summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/third_party/blink/renderer
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer')
-rw-r--r--chromium/third_party/blink/renderer/.style.yapf2
-rw-r--r--chromium/third_party/blink/renderer/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/DEPS15
-rw-r--r--chromium/third_party/blink/renderer/bindings/BUILD.gn12
-rw-r--r--chromium/third_party/blink/renderer/bindings/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md17
-rw-r--r--chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt1
-rw-r--r--chromium/third_party/blink/renderer/bindings/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/bindings/bindings.gni7
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module.h5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom/DEPS5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_dev_tools_host_custom.cc21
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/generated.gni4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc9
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/idl_types.h57
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc7
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc32
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.h6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/module_record.cc116
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/module_record.h22
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/module_record_test.cc93
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/module_request.cc19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/module_request.h30
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h218
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc9
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h9
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc70
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc115
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h43
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc62
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_function.h76
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc7
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h10
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc181
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.cc1
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.cc27
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.h23
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.cc127
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.h13
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.cc258
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.h64
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h24
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc97
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc39
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc106
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/source_location.cc43
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/source_location.h12
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h4
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h649
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits_test.cc520
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc16
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc415
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h98
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc5
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.cc3
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc19
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc148
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc35
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc27
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc8
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc207
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h31
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.cc248
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h89
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc90
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc9
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h21
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc49
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h21
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc48
-rw-r--r--chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h17
-rw-r--r--chromium/third_party/blink/renderer/bindings/generated_in_core.gni66
-rw-r--r--chromium/third_party/blink/renderer/bindings/generated_in_modules.gni250
-rw-r--r--chromium/third_party/blink/renderer/bindings/idl_in_core.gni28
-rw-r--r--chromium/third_party/blink/renderer/bindings/idl_in_modules.gni119
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn52
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni20
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc51
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h4
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc49
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.h12
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc6
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf4
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py214
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_function.py34
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py9
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py10
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py15
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py3
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py3
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py2
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py189
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py2
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py10
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py9
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/task_queue.py3
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py595
-rwxr-xr-xchromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py4
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py8
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py4
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/idl_types.py2
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/scripts.gni17
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/utilities.py35
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py6
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py9
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py9
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py2
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf4
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py1
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py12
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py2
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py5
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py28
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py17
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py16
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py45
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py29
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py8
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py12
-rw-r--r--chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py25
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl4
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl17
-rw-r--r--chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl4
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/PRESUBMIT.py19
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py1
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/css_properties.py33
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py4
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py23
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py4
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl36
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.h.tmpl17
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl6
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl12
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.cc.tmpl6
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl83
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/gperf.py2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/in_file.py2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/in_generator.py5
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/make_document_policy_features_tests.py27
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/make_policy_helper.py7
-rwxr-xr-xchromium/third_party/blink/renderer/build/scripts/make_runtime_features.py2
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/name_utilities.py4
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/scripts.gni5
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/document_policy_features.cc.tmpl37
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl38
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/macros.tmpl10
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl7
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/policy_helper.cc.tmpl29
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl11
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/templates/settings_macros.h.tmpl20
-rw-r--r--chromium/third_party/blink/renderer/build/scripts/writer_test_util.py111
-rw-r--r--chromium/third_party/blink/renderer/controller/BUILD.gn7
-rw-r--r--chromium/third_party/blink/renderer/controller/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/controller/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/controller/blink_initializer.cc4
-rw-r--r--chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc10
-rw-r--r--chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.h14
-rw-r--r--chromium/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc2
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.cc126
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl_test.cc272
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.cc38
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc82
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h19
-rw-r--r--chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/BUILD.gn113
-rw-r--r--chromium/third_party/blink/renderer/core/DEPS12
-rw-r--r--chromium/third_party/blink/renderer/core/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/OWNERS18
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h10
-rw-r--r--chromium/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animatable.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.cc391
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.h89
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect.h12
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_test.cc723
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_time_delta.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_timeline.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_timeline.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animation.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animation.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animations.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc164
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h53
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h3
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations.h21
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_animations_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline.h16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/element_animations.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/animation/element_animations.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/inert_effect.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/inert_effect.h4
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h62
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_length.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/animation/interpolable_value.h1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/animation/length_property_functions.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/pending_animations.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/animation/pending_animations.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.h10
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/animation/string_keyframe.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_calculations.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation/timing_input_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/transition_keyframe.h2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/animation_frame/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/animation_frame/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/aom/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/aom/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/aom/accessible_node.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/aom/accessible_node.h6
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_object.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_object.h4
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_object_item.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_object_item.h14
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc114
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/data_transfer.h36
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h3
-rw-r--r--chromium/third_party/blink/renderer/core/content_capture/content_capture_task.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/content_capture/content_capture_task.h3
-rw-r--r--chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h12
-rw-r--r--chromium/third_party/blink/renderer/core/core_idl_files.gni34
-rw-r--r--chromium/third_party/blink/renderer/core/core_initializer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/css/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/css/abstract_property_set_css_style_declaration.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/active_style_sheets.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/css/active_style_sheets.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/active_style_sheets_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.h47
-rw-r--r--chromium/third_party/blink/renderer/core/css/build.gni26
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query.h37
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query_evaluator.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query_evaluator.h65
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query_evaluator_test.cc248
-rw-r--r--chromium/third_party/blink/renderer/core/css/container_query_test.cc198
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style.cc686
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style.h169
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style_map.cc296
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style_map.h66
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style_map_test.cc204
-rw-r--r--chromium/third_party/blink/renderer/core/css/counter_style_test.cc627
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_container_rule.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_container_rule.h37
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_container_rule.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_counter_style_rule.cc188
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_counter_style_rule.h28
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_counter_style_rule.idl22
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_counter_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_counter_value.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc90
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_selector.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_font_selector.h19
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_global_rule_set.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_gradient_value.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_grouping_rule.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_image_set_value.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_image_set_value.h19
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_image_value.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_initial_color_value.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_math_expression_node.cc132
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_math_expression_node.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_math_function_value.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_numeric_literal_value.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_page_rule_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_path_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_path_value.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_primitive_value.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_primitive_value.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_primitive_value_mappings.h415
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_primitive_value_test.cc51
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_properties.json51029
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_equality.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_id_templates.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_name.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_value_set.cc51
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_property_value_set.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_revert_value.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_rule.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector.cc112
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector.h75
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector_list.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector_list.h14
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector_watch.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_selector_watch.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_declaration.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_style_sheet.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_test_helpers.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_test_helpers.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_unset_value.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value.h15
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.h25
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_clamping_utils_test.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_id_mappings.h12
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_keywords.json549
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_pair.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_pool.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/css_value_pool.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_style_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h11
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/dom_window_css.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/element_rule_collector.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/css/element_rule_collector.h39
-rw-r--r--chromium/third_party/blink/renderer/core/css/element_rule_collector_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_cache.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_document.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_face_set_document.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/font_update_invalidation_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_feature_names.json51
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc86
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_evaluator.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_evaluator_test.cc138
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_exp.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_exp.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_query_set_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values.h14
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_cached.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_cached.h11
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_dynamic.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.h22
-rw-r--r--chromium/third_party/blink/renderer/core/css/media_values_initial_viewport_test.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/css/native_paint_image_generator.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/css/native_paint_image_generator.h18
-rw-r--r--chromium/third_party/blink/renderer/core/css/offscreen_font_selector.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/offscreen_font_selector.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc238
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/at_rule_names.json53
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css.proto89
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.h1
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h14
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths_fuzzer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_property_parser.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc82
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc88
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/css/parser/sizes_math_function_parser_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/predefined_counter_styles.css435
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_bitset.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_bitset_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc298
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h158
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property.h28
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property_methods.json52
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property_ref.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property_ref.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_property_test.cc170
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/css_unresolved_property.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc1197
-rw-r--r--chromium/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/cascade_expansion.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/cascade_map.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/cascade_map.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h4
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc160
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.h16
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/font_builder.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/font_builder.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/match_result.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/match_result.h5
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h17
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc492
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc207
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h49
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_adjuster_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_builder.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.h13
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_cascade.cc141
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_cascade.h14
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc317
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h19
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.h63
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state_test.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc247
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc93
-rw-r--r--chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h12
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_feature_set.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_set.cc187
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_set.h99
-rw-r--r--chromium/third_party/blink/renderer/core/css/rule_set_test.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_checker.cc261
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_checker.h11
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_filter.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_query.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_query.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/selector_query_test.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_change_reason.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_change_reason.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_color.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_color.h10
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine.cc313
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine.h68
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_engine_test.cc652
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_environment_variables.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_environment_variables.h10
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_invalidation_root.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_invalidation_root.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_property_serializer.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_property_serializer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_recalc.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_recalc.h63
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_recalc_root.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_recalc_root.h3
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule.h98
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule_counter_style.cc144
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule_counter_style.h86
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_rule_import.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_collection.h6
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_sheet_contents.h10
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_traversal_root.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_traversal_root.h25
-rw-r--r--chromium/third_party/blink/renderer/core/css/style_traversal_root_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/css/svg.css4
-rw-r--r--chromium/third_party/blink/renderer/core/css/tree_scope_style_sheet_collection.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/css/view-source.css29
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc115
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h27
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.h8
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/README.md35
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/build.gni10
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition.cc170
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition.h76
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition.idl23
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition_init.idl23
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.h41
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/document_transition/document_transition_test.cc259
-rw-r--r--chromium/third_party/blink/renderer/core/dom/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/abstract_range.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/abstract_range.h31
-rw-r--r--chromium/third_party/blink/renderer/core/dom/abstract_range.idl15
-rw-r--r--chromium/third_party/blink/renderer/core/dom/aria_attributes.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/attr.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/build.gni40
-rw-r--r--chromium/third_party/blink/renderer/core/dom/character_data.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/child_node.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/container_node.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/dom/container_node.h19
-rw-r--r--chromium/third_party/blink/renderer/core/dom/create_element_flags.h27
-rw-r--r--chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc74
-rw-r--r--chromium/third_party/blink/renderer/core/dom/distributed_nodes.h76
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.cc667
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.h145
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.idl44
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_data.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_fragment.h9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_init.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_init.h11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h14
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_exception.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_implementation.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_token_list.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_token_list.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/dom_token_list.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element-hot.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.cc730
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.h111
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element.idl29
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_data.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_rare_data.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_rare_data.h24
-rw-r--r--chromium/third_party/blink/renderer/core/dom/element_test.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_path.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/event_target.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/simulated_click_options.h10
-rw-r--r--chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc111
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h57
-rw-r--r--chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc145
-rw-r--r--chromium/third_party/blink/renderer/core/dom/focus_params.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/interest_cohort.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h24
-rw-r--r--chromium/third_party/blink/renderer/core/dom/named_node_map.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node.cc344
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node.h170
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node.idl16
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_computed_style.h4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_list.h11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_rare_data.h11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_test.cc74
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_traversal.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/node_traversal.h9
-rw-r--r--chromium/third_party/blink/renderer/core/dom/parent_node.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/processing_instruction.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/dom/pseudo_element.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/pseudo_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.h13
-rw-r--r--chromium/third_party/blink/renderer/core/dom/range.idl19
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/dom/set_inner_html_options.idl7
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_dom_v0_test.cc192
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root.h68
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root.idl7
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root_v0.cc251
-rw-r--r--chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h136
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment.cc183
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment.h5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/slot_assignment_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range.h17
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range.idl13
-rw-r--r--chromium/third_party/blink/renderer/core/dom/static_range_init.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text_link_colors.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text_link_colors.h12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/text_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h12
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_ordered_map_test.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope.h3
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope_adopter_test.cc102
-rw-r--r--chromium/third_party/blink/renderer/core/dom/tree_scope_test.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc302
-rw-r--r--chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h139
-rw-r--r--chromium/third_party/blink/renderer/core/dom/whitespace_attacher.h1
-rw-r--r--chromium/third_party/blink/renderer/core/dom/whitespace_attacher_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/build.gni8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/editing/caret_display_item_client.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc107
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/insert_commands.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/insert_list_command.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/insert_node_before_command.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/insert_text_command.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/insert_text_command_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/move_commands_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/remove_css_property_command.h3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.h6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/typing_command.cc168
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/typing_command.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/undo_step.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/commands/undo_step.h6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_behavior.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_strategy.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_strategy_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_style.cc131
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_style.h7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_style_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_utilities.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_utilities.h20
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editing_utilities_test.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editor.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editor.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/editor_key_bindings.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/editing/element_inner_text.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ephemeral_range.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ephemeral_range_test.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.h52
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc145
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h15
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer_runner.h30
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.h31
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/text_finder.h7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_caret.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_caret.h3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_selection.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_selection.h7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/frame_selection_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/edit_context.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/edit_context.h14
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.h9
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_position.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_position.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.h5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/layout_selection.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/editing/layout_selection.h24
-rw-r--r--chromium/third_party/blink/renderer/core/editing/layout_selection_test.cc172
-rw-r--r--chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/editing/local_caret_rect_test.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/editing/markers/text_match_marker_list_impl.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h5
-rw-r--r--chromium/third_party/blink/renderer/core/editing/position.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/editing/position.h7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/position_test.cc73
-rw-r--r--chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.h45
-rw-r--r--chromium/third_party/blink/renderer/core/editing/relocatable_position.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/editing/relocatable_position.h13
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_adjuster.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_adjuster_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_controller.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_controller_test.cc110
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_editor.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier.cc372
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier.h71
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier_line.cc230
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc164
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_template.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_template.h4
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_template_test.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/editing/selection_type.h35
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/serialization.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/serialization.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/serialization_test.cc74
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/substring_util.h6
-rw-r--r--chromium/third_party/blink/renderer/core/editing/substring_util.mm11
-rw-r--r--chromium/third_party/blink/renderer/core/editing/substring_util_test.mm10
-rw-r--r--chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.h1
-rw-r--r--chromium/third_party/blink/renderer/core/editing/testing/selection_sample.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/editing/testing/selection_sample_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/editing/text_offset_mapping.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/editing/text_offset_mapping_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_position.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_position_test.cc178
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_selection.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_selection.h21
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_selection_test.cc113
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units.cc308
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units.h54
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_line.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_line_test.cc295
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_paragraph.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_paragraph_test.cc109
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_sentence.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_sentence_test.cc128
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_test.cc263
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_word.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/editing/visible_units_word_test.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/events/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/events/current_input_event.h2
-rw-r--r--chromium/third_party/blink/renderer/core/events/event_target_names.json51
-rw-r--r--chromium/third_party/blink/renderer/core/events/event_type_names.json511
-rw-r--r--chromium/third_party/blink/renderer/core/events/event_util.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/events/hash_change_event.h1
-rw-r--r--chromium/third_party/blink/renderer/core/events/message_event.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/events/message_event.h13
-rw-r--r--chromium/third_party/blink/renderer/core/events/mouse_event.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/events/mouse_event.h38
-rw-r--r--chromium/third_party/blink/renderer/core/events/mouse_event_test.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event.h48
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event_init.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/events/pointer_event_util.h4
-rw-r--r--chromium/third_party/blink/renderer/core/events/promise_rejection_event.h3
-rw-r--r--chromium/third_party/blink/renderer/core/events/simulated_event_util.cc207
-rw-r--r--chromium/third_party/blink/renderer/core/events/simulated_event_util.h28
-rw-r--r--chromium/third_party/blink/renderer/core/events/wheel_event.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/DEPS7
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/agent.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/agent.h30
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.cc179
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.h88
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector_test.cc181
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/build.gni3
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/execution_context.cc160
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/execution_context.h81
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/navigator_base.h78
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/remote_security_context.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/remote_security_context.h13
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context.h5
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context_init.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/security_context_init.h14
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.h15
-rw-r--r--chromium/third_party/blink/renderer/core/exported/BUILD.gn16
-rw-r--r--chromium/third_party/blink/renderer/core/exported/test_web_frame_content_dumper.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_content_holder.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h1
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h7
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_dom_message_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_element.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_element_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h4
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc140
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_heap.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_isolated_world_info.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_node.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc154
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h20
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_performance.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.h8
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc152
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_security_policy.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_settings_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h9
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_impl.cc444
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_impl.h117
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_observer.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/exported/web_view_test.cc386
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/README.md18
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/document_policy.dict3
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/document_policy_features.json566
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/document_policy_sim_test.cc457
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy.dict1
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h40
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support_test.cc297
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_features.json570
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_parser.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/feature_policy/policy_helper.h9
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.h19
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc158
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_header_list.h2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc318
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h15
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/place_holder_bytes_consumer_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h1
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/request.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/blob.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file_reader.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/DEPS13
-rw-r--r--chromium/third_party/blink/renderer/core/frame/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/ad_tracker.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/frame/ad_tracker.h16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc234
-rw-r--r--chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/frame/build.gni19
-rw-r--r--chromium/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/DEPS5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc903
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h198
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc796
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/conversion_util.cc191
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/conversion_util.h37
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/conversion_util_fuzzer.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/conversion_util_test.cc165
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive.h41
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc1982
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h467
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc792
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc364
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source.h110
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc1261
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.cc125
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.h46
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h22
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc933
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.h171
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc1478
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.h41
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/string_list_directive_test.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.h28
-rw-r--r--chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive_test.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/frame/deprecation.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/frame/deprecation.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_window.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/frame/dom_window.h6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/find_in_page.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/frame/find_in_page.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame.cc157
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame.h99
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_console.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_content_as_text.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_content_as_text.h25
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_content_as_text_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.h1
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_owner.h6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_serializer.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_serializer.h3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc533
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h271
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_view.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_view.h12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/frame/fullscreen_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/history.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/impression_params.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/frame/intervention.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/intervention.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_dom_window.cc213
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_dom_window.h44
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_dom_window_test.cc128
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame.cc433
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame.h124
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_client.h40
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.cc244
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.h29
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc187
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h42
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc198
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.cc664
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.h44
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/frame/mhtml_archive_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigation_rate_limiter.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator.h27
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_automation_information.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_id.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/frame/navigator_window_controls_overlay.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/policy_container.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/frame/policy_container.h19
-rw-r--r--chromium/third_party/blink/renderer/core/frame/policy_container_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame.cc361
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame.h77
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client.h59
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h39
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_owner.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_owner.h9
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/frame/remote_frame_view.h4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/reporting_context.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/reporting_context_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/frame/sandbox_flags.h61
-rw-r--r--chromium/third_party/blink/renderer/core/frame/savable_resources.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen.h17
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.h16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings.h18
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings.json5129
-rw-r--r--chromium/third_party/blink/renderer/core/frame/settings_delegate.h47
-rw-r--r--chromium/third_party/blink/renderer/core/frame/sticky_ad_detector.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/use_counter_helper.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/use_counter_helper_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.cc127
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_serializer_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_test.cc1940
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc2954
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h824
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc4301
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h1050
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_frame_widget_test.cc164
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_local_frame_client_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc533
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h126
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc121
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.h44
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc764
-rw-r--r--chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h227
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window.idl19
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_controls_overlay.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_controls_overlay.h44
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_controls_overlay.idl13
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h24
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl16
-rw-r--r--chromium/third_party/blink/renderer/core/frame/window_post_message_options.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/fullscreen/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/fullscreen/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/fullscreen/fullscreen.h6
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_matrix.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_quad.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/geometry/dom_rect.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/html/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/html/aria_properties.json56
-rw-r--r--chromium/third_party/blink/renderer/core/html/battery_savings.h24
-rw-r--r--chromium/third_party/blink/renderer/core/html/build.gni57
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h19
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc124
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h11
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.cc835
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.h205
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data_color_settings.idl22
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl22
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data_test.cc495
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc148
-rw-r--r--chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.h35
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc80
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h9
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_element_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_state_set.cc123
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_state_set.h47
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/custom_state_set.idl13
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/element_internals.idl5
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.cc150
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.h73
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h51
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h69
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h80
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h59
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h93
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h82
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h67
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h76
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h46
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc88
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h76
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h41
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h67
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h40
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h60
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h62
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h109
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h55
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc186
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h85
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc149
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h88
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc169
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h79
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h25
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h74
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/email_input_type.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/email_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/email_input_type_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_button_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl28
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_label_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_option_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_option_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc348
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.h107
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/image_input_type.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/input_type_view.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/range_input_type.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.css8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.js23
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/resources/validation_bubble.css1
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/search_input_type.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/search_input_type.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/select_type.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_control_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_control_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_anchor_element.cc120
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_anchor_element.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_area_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_attribute_names.json52
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element.cc127
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element.h99
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element.idl34
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_content_element_test.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_details_element.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_dialog_element.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_dialog_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_document.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element.cc368
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element.h21
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element.idl8
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_element_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_embed_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h7
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element.h11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_iframe_element_test.cc101
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_image_element.h14
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_li_element.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.h13
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_link_element.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meta_element.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meta_element_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_meter_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_no_embed_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_object_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_object_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_olist_element.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_or_foreign_element.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_picture_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_picture_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_plugin_element.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_plugin_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_popup_element.cc148
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_popup_element.h48
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_popup_element.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_progress_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_script_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_shadow_element.cc51
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_shadow_element.h49
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_shadow_element.idl37
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_slot_element.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_slot_element.h9
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_source_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_source_element.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_source_element.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_style_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_summary_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_col_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_table_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_tag_names.json519
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_ulist_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_view_source_document.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/html/html_view_source_document_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_child.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_style.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_style.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_web_bundle.cc184
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_web_bundle.h12
-rw-r--r--chromium/third_party/blink/renderer/core/html/link_web_bundle_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/html/list_item_ordinal.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/DEPS10
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.h34
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element.cc212
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element.h103
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc257
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element.cc197
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element.h93
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h2
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_frame_callback_requester.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.h10
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc203
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h23
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc158
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h17
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h6
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/preload_request.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/preload_request.h33
-rw-r--r--chromium/third_party/blink/renderer/core/html/parser/text_document_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/html/plugin_document.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h8
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/portal_host.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/portal_host.h9
-rw-r--r--chromium/third_party/blink/renderer/core/html/portal/portal_host.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/html/rel_list.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/android.css2
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/controls_refresh.css41
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/forced_colors.css103
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/html.css109
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/images/time_icon.svg2
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/input_multiple_fields.css3
-rw-r--r--chromium/third_party/blink/renderer/core/html/resources/mac.css2
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/shadow_element_names.json56
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.h1
-rw-r--r--chromium/third_party/blink/renderer/core/html/subresource_redirect_test.cc211
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/cue_timeline.h10
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/html_track_element.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/html_track_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/track_base.h4
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h2
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc223
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h29
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc377
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h162
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/input/boundary_event_dispatcher.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler.h10
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handler_test.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/input/event_handling_util.h4
-rw-r--r--chromium/third_party/blink/renderer/core/input/gesture_manager.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h1
-rw-r--r--chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/input/mouse_event_manager.h5
-rw-r--r--chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/input/scroll_manager.cc248
-rw-r--r--chromium/third_party/blink/renderer/core/input/scroll_manager.h28
-rw-r--r--chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/input/touch_action_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/DEPS6
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/build.gni5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h20
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/devtools_session.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/dom_traversal_utils.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspect_tools.cc132
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspect_tools.h44
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.h11
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_contrast.cc406
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_contrast.h65
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_contrast_test.cc212
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc235
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h6
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent_test.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc349
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h58
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_io_agent.h3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.h2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc124
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.h38
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl_unittest.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc105
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h12
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc308
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h24
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h8
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc218
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h55
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json3
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_session_state.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc88
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h23
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/node_content_visibility_state.h16
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/thread_debugger.h1
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc82
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h9
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.h4
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h9
-rw-r--r--chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc117
-rw-r--r--chromium/third_party/blink/renderer/core/layout/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/api/line_layout_item.h24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/box_layout_extra_input.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/build.gni13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/floating_objects.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/axis.h78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/axis_test.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/logical_size.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.h26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_testing_test.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout-shift-tracker-old-paint-offset.md76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.cc111
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.cc372
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.h60
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc148
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_test.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_br.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_counter.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_counter.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_details_marker.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_details_marker.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame_set.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.cc130
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.h18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.cc434
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.h207
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_factory.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_test.cc143
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.cc80
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc255
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc226
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_col.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_col.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_col_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row_test.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_test.cc151
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.cc217
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.h27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_android.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_android.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video_test.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.h31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view_test.cc428
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_box.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_iterator.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/line_box_list.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/list_marker.cc145
-rw-r--r--chromium/third_party/blink/renderer/core/layout/list_marker.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/list_marker_test.cc312
-rw-r--r--chromium/third_party/blink/renderer/core/layout/list_marker_text.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc430
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc2423
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h394
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc535
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc461
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h132
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc376
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h133
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection_test.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/README.md2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc88
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc169
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc892
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h167
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc195
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc124
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc244
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h142
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc320
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_padded_layout_algorithm.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_radical_layout_algorithm.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_under_over_layout_algorithm.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc152
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc234
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc176
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc191
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h121
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc141
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h43
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc86
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc242
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc160
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc665
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h194
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc451
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc308
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc323
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h74
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc105
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc141
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment_test.cc185
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.h33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.cc97
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h51
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h93
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc470
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc166
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc139
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h40
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/overflow_model.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc111
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h52
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc80
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_content_container.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_hit_test_perftest.cc132
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc225
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc707
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h180
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc140
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h88
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h79
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/web_font_rendering_win.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/loader/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/address_space_feature.cc219
-rw-r--r--chromium/third_party/blink/renderer/core/loader/address_space_feature.h30
-rw-r--r--chromium/third_party/blink/renderer/core/loader/address_space_feature_test.cc156
-rw-r--r--chromium/third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.h3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h36
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc319
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context.h50
-rw-r--r--chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/loader/build.gni20
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_load_timing.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_load_timing.h17
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_loader.cc620
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_loader.h70
-rw-r--r--chromium/third_party/blink/renderer/core/loader/document_loader_test.cc481
-rw-r--r--chromium/third_party/blink/renderer/core/loader/empty_clients.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/loader/empty_clients.h70
-rw-r--r--chromium/third_party/blink/renderer/core/loader/font_preload_manager.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/font_preload_manager.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/form_submission.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/loader/form_submission.h44
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h31
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc324
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc134
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_load_request.h40
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.cc264
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.h29
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader_types.h5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/http_equiv.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/loader/idleness_detector.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/idleness_detector.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/image_loader.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/loader/interactive_detector.cc81
-rw-r--r--chromium/third_party/blink/renderer/core/loader/interactive_detector.h24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/interactive_detector_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/loader/lazy_image_helper.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/lazy_image_helper.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader.h13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader_client.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/link_loader_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.h11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc121
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h14
-rw-r--r--chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h111
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h16
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc125
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h10
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.h67
-rw-r--r--chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/loader/preload_helper.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prerender_handle.cc125
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prerender_handle.h94
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prerender_test.cc250
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prerenderer_client.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/loader/prerenderer_client.h67
-rw-r--r--chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc194
-rw-r--r--chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h90
-rw-r--r--chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc398
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h31
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/prerender_client.h54
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/prerender_handle.cc139
-rw-r--r--chromium/third_party/blink/renderer/core/loader/private/prerender_handle.h108
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/font_resource.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/font_resource.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h29
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/script_resource.h43
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/script_resource_test.cc92
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.h7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.h46
-rw-r--r--chromium/third_party/blink/renderer/core/loader/text_track_loader.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/loader/text_track_loader.h2
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader.h4
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h3
-rw-r--r--chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h6
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.h8
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.h2
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.h5
-rw-r--r--chromium/third_party/blink/renderer/core/messaging/message_port_descriptor_mojom_traits_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h19
-rw-r--r--chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc264
-rw-r--r--chromium/third_party/blink/renderer/core/mobile_metrics/mobile_metrics_test_helpers.h30
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/BUILD.gn38
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/mojo.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/mojo_handle.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/mojo_watcher.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/mojo_watcher.h6
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h2
-rw-r--r--chromium/third_party/blink/renderer/core/mojo/tests/js_to_cpp.mojom61
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller.h9
-rw-r--r--chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client.h34
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc86
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl.h24
-rw-r--r--chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_controller.cc364
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_controller.h52
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_controller_test.cc1000
-rw-r--r--chromium/third_party/blink/renderer/core/page/context_menu_provider.h4
-rw-r--r--chromium/third_party/blink/renderer/core/page/create_window.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_controller.cc184
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_controller.h16
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_controller_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_data.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_data.h6
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_image.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/drag_image_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/page/focus_controller.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/page/link_highlight.h7
-rw-r--r--chromium/third_party/blink/renderer/core/page/page.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/page/page.h30
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_animator.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_animator.h4
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_popup_client.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_widget_delegate.h8
-rw-r--r--chromium/third_party/blink/renderer/core/page/plugin_data_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/page/print_context_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h1
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h1
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc90
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h1
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc265
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc514
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h105
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc342
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h49
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc619
-rw-r--r--chromium/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h4
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/page/viewport_test.cc435
-rw-r--r--chromium/third_party/blink/renderer/core/paint/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.cc220
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/build.gni12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc215
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc737
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc114
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc362
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/paint/cull_rect_updater.cc287
-rw-r--r--chromium/third_party/blink/renderer/core/paint/cull_rect_updater.h75
-rw-r--r--chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/details_marker_painter.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/details_marker_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/document_marker_painter.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/element_timing_utils.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/paint/filter_effect_builder.h16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc184
-rw-r--r--chromium/third_party/blink/renderer/core/paint/fragment_data.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/fragment_data.h19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/frame_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/highlight_painting_utils.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/paint/highlight_painting_utils_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.h19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h43
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc119
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_painter.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc120
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_text_box_painter_test.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/paint/list_marker_painter.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc539
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h95
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc355
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h125
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc133
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h92
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc992
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h371
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc685
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc278
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h202
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc225
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.h33
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.h13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc557
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h43
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.h12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc230
-rw-r--r--chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc149
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_painter_base.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_info.h18
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc146
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.cc376
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.h78
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc276
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h22
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc162
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc868
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_phase.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc532
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h37
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc115
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.cc163
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.h122
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h36
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_test_helper.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc230
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h42
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/paint/replaced_painter.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc155
-rw-r--r--chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.h50
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_object_painter.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_painter_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_decoration_info.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h44
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc218
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_painter_base.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_painter_base.h13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_painter_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/paint/theme_painter.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/paint/theme_painter_default.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.h1
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.json512
-rw-r--r--chromium/third_party/blink/renderer/core/probe/core_probes.pidl11
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc80
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc524
-rw-r--r--chromium/third_party/blink/renderer/core/scheduler_integration_tests/throttling_test.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/script/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/script/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_pending_script.cc115
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_pending_script.h4
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_script.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/script/classic_script.h24
-rw-r--r--chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/script/document_modulator_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/script/import_map.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/script/js_module_script.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/script/js_module_script.h15
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator.h35
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/script/modulator_impl_base.h26
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map.h6
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_map_test.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_record_resolver.h2
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_script.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/script/module_script_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_loader.cc370
-rw-r--r--chromium/third_party/blink/renderer/core/script/script_loader.h22
-rw-r--r--chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h12
-rw-r--r--chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/script/worker_modulator_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/core/script/xml_parser_script_runner.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h4
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator.h5
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_base.h4
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h7
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm64
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scroll_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollable_area.h14
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar.h2
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h6
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar_theme.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/streams/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/count_queuing_strategy.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.h23
-rw-r--r--chromium/third_party/blink/renderer/core/streams/queue_with_sizes.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/queue_with_sizes.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc1396
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h229
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl9
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream.cc307
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream.h80
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc175
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h52
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.h15
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_controller.h5
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.h11
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h6
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.h21
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h5
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_test.cc136
-rw-r--r--chromium/third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/stream_algorithms.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.h3
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transferable_streams.cc240
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transferable_streams.h31
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transferable_streams_test.cc494
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream.h5
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.h6
-rw-r--r--chromium/third_party/blink/renderer/core/streams/transform_stream_transformer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source.idl13
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source_base.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl7
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl7
-rw-r--r--chromium/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl7
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream.h20
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h2
-rw-r--r--chromium/third_party/blink/renderer/core/style/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/style/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/style/build.gni13
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style.cc169
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style.h264
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_constants.h98
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json544
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json587
-rw-r--r--chromium/third_party/blink/renderer/core/style/computed_style_test.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/style/content_data.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/style/content_data.h46
-rw-r--r--chromium/third_party/blink/renderer/core/style/counter_content.h62
-rw-r--r--chromium/third_party/blink/renderer/core/style/data_equivalency.h6
-rw-r--r--chromium/third_party/blink/renderer/core/style/fill_layer.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_area.h13
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_track_list.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/style/grid_track_list.h4
-rw-r--r--chromium/third_party/blink/renderer/core/style/list_style_type_data.cc110
-rw-r--r--chromium/third_party/blink/renderer/core/style/list_style_type_data.h80
-rw-r--r--chromium/third_party/blink/renderer/core/style/shadow_list.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/style/shadow_list.h5
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_aspect_ratio.h2
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_fetched_image.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_fetched_image.h3
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_fetched_image_set.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_fetched_image_set.h3
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_image.h7
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_pending_image.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/style/style_pending_image.h18
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style.cc313
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style.h485
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc190
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h365
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_computed_style_test.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_dash_array.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_dash_array.h44
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_paint.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/style/svg_paint.h81
-rw-r--r--chromium/third_party/blink/renderer/core/style/unzoomed_length.h61
-rw-r--r--chromium/third_party/blink/renderer/core/svg/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/smil_time_container_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/build.gni4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc400
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h105
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h14
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_a_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_a_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_element.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_animated_path.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_circle_element.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_circle_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_document_extensions.h4
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_element.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_element.h23
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_element_rare_data.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.cc137
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.h85
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_external_document_cache_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_filter_element.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_filter_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_geometry_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_geometry_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_gradient_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_gradient_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_graphics_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_graphics_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_image_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_image_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_length.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_length.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_length_context.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_line_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_line_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_marker_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_marker_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mask_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mask_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mpath_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_parser_utilities.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_path.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_path.h6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_path_element.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_path_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_pattern_element.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_point.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_point.h8
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_point_tear_off.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_poly_element.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_poly_element.h3
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_rect_element.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_rect_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource.cc162
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource.h53
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource_client.h23
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.cc158
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.h67
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_resource_document_content_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_script_element.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_script_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_stop_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_svg_element.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_svg_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_symbol_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_content_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_content_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_path_element.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.h2
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_use_element.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/svg/svg_use_element.h12
-rw-r--r--chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/testing/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.h4
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-main.html2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-subframe.html6
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_basic_rtl.html24
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_lr_rtl.html25
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_rl_rtl.html25
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/display_none_frame.html5
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html37
-rw-r--r--chromium/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html25
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dictionary_test.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dictionary_test.h7
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_modulator.h13
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/testing/dummy_page_holder.h1
-rw-r--r--chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.h33
-rw-r--r--chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.h17
-rw-r--r--chromium/third_party/blink/renderer/core/testing/fake_web_plugin.h8
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internal_settings.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.cc555
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.h19
-rw-r--r--chromium/third_party/blink/renderer/core/testing/internals.idl15
-rw-r--r--chromium/third_party/blink/renderer/core/testing/intersection_observer_test_helper.h61
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.h2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_function_scope.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_function_scope.h46
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.h14
-rw-r--r--chromium/third_party/blink/renderer/core/testing/module_test_base.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/testing/module_test_base.h18
-rw-r--r--chromium/third_party/blink/renderer/core/testing/null_execution_context.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/testing/null_execution_context.h2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/page_test_base.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h42
-rw-r--r--chromium/third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h2
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h17
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h31
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc73
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_test.h40
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h30
-rw-r--r--chromium/third_party/blink/renderer/core/testing/wait_for_event.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/timing/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/event_timing.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/timing/largest_contentful_paint.h9
-rw-r--r--chromium/third_party/blink/renderer/core/timing/layout_shift.h10
-rw-r--r--chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.h4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc288
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h39
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc286
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h42
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl12
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.h15
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_entry.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_entry.h3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_event_timing.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_event_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.h15
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_mark.h3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_measure.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.h16
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_group.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_group.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_group_test.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/timing/task_attribution_timing.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/task_attribution_timing.h6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.cc74
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.h23
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.h1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.h1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h1
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h4
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h1
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h5
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h11
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_array_piece.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.h1
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h1
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h1
-rw-r--r--chromium/third_party/blink/renderer/core/url/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/url/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/web_test/BUILD.gn44
-rw-r--r--chromium/third_party/blink/renderer/core/web_test/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/core/web_test/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc274
-rw-r--r--chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h112
-rw-r--r--chromium/third_party/blink/renderer/core/workers/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/README.md1
-rw-r--r--chromium/third_party/blink/renderer/core/workers/build.gni2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.h31
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker.h10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h30
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h9
-rw-r--r--chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h20
-rw-r--r--chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h1
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h17
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_thread.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/shared_worker_thread.h5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_object_proxy_base.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_global_scope.h24
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_navigator.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_navigator.h44
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h23
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread.h2
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h24
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.h5
-rw-r--r--chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/xml/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/core/xml/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/core/xml/dom_parser.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/xml/dom_parser.h3
-rw-r--r--chromium/third_party/blink/renderer/core/xml/parse_from_string_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_grammar.y2
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.cc1137
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.h706
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xslt_processor.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/xml/xslt_processor.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/DIR_METADATA5
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc79
-rw-r--r--chromium/third_party/blink/renderer/modules/BUILD.gn85
-rw-r--r--chromium/third_party/blink/renderer/modules/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/modules/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc99
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc90
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc1375
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h50
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc61
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_list.h57
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_media_element.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc79
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc134
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc1595
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h93
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc1498
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.h203
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc1407
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h126
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc61
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc132
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.h51
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc163
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc329
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h51
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h58
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc31
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc220
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt3
-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/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/audio_output_devices/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/audio_output_devices/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.h15
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/background_sync/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/background_sync/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/badging/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/badging/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_manager.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/battery_manager.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/navigator_battery.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/beacon/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/beacon/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/broadcastchannel/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/DEPS5
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/idls.gni15
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/navigator_storage_buckets.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket.cc206
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket.h75
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.cc169
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/storage_bucket_options.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/buckets/worker_navigator_storage_buckets.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_utils.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/BUILD.gn13
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc786
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h103
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc187
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h129
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl24
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc34
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h50
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc82
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc101
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h46
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl29
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/idls.gni4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc384
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h213
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl24
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl21
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h77
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/deflate_transformer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/deflate_transformer.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/inflate_transformer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/compression/inflate_transformer.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/contacts_picker/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/content_index/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/content_index/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event_init.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_delete_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc85
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc305
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/crypto.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn9
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/README.md85
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.cc55
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h46
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.cc288
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h56
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet_test.cc272
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.cc37
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.cc57
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.h44
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc13
-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/csspaint/paint_worklet_id_generator.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/device/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/device/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/device/device_service.cc219
-rw-r--r--chromium/third_party/blink/renderer/modules/device/device_service.h96
-rw-r--r--chromium/third_party/blink/renderer/modules/device/device_service.idl21
-rw-r--r--chromium/third_party/blink/renderer/modules/device/idls.gni7
-rw-r--r--chromium/third_party/blink/renderer/modules/device/navigator_device.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump_unittest.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn30
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc252
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h114
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper_unittest.cc209
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.cc126
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket_unittest.cc171
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc372
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h151
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper_unittest.cc256
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/udp_socket.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/document_metadata/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/document_metadata/OWNERS5
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/event_target_modules_names.json54
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/event_source.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/eventsource/event_source.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc277
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_testing_support.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/OWNERS1
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/eyedropper/idls.gni10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn42
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc83
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc83
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.cc69
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writable_options.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc270
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h77
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.cc110
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc151
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc119
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.h70
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc483
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc117
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h45
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.cc452
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access_test.cc233
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc314
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc234
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/idls.gni10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc274
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h77
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc111
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc69
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc152
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc121
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h72
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc271
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h69
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc130
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h46
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc122
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h29
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc122
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h29
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/window_file_system_access.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl21
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/html_input_element_file_system.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc140
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.h56
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator_entry.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_manager.cc172
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_manager.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_manager.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_metadata.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_metadata.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_metadata.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/idls.gni6
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/navigator_fonts.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/query_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/geolocation/geolocation.h40
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/BUILD.gn20
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.cc115
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.h55
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing_segment.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query_result.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_hints.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_model_constraint.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_point.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_prediction.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.cc165
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.h67
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.cc78
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h62
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_segment.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.h43
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.cc204
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h113
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters_unittest.cc246
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/idls.gni23
-rw-r--r--chromium/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl26
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/DIR_METADATA1
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_detector.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc195
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_any.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_any.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc90
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h55
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.cc109
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.h48
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_init.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h23
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idls.gni4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc41
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json56
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc78
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/OWNERS5
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h4
-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.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/launch_params.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/launch_queue.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/launch_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock_manager.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock_manager.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc75
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/navigator_locks.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/navigator_locks.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_manager.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_manager.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc94
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_parser.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc179
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/media/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/media/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/web_audio_device_factory.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media/webmediaplayer_util_unittest.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_fuzzer.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc133
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_dark.svg5
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_white.svg5
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/ic_pause_dark.svg4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/ic_play_arrow_dark.svg4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css43
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls_Android.css1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc55
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source_unittest.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc74
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc73
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc54
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_options.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc149
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder_unittest.cc239
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/vpx_encoder.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_metadata.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/media_session_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn7
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/DEPS10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/idls.gni2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.cc305
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc436
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer_config.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/track_default_list.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/track_default_list.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/idls.gni3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm_unittest.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc138
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.cc78
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h44
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink_test.cc188
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc170
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h83
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source_test.cc245
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h33
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.cc210
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_test.cc144
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc199
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc305
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_signal.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_test.cc75
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc61
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc114
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h42
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc139
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h26
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc22
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc103
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h72
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc211
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.h49
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc129
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter_unittest.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.cc106
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h44
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc244
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.cc162
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h80
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source_test.cc191
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc429
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc120
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc95
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/BUILD.gn12
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/idls.gni5
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc125
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h84
-rw-r--r--chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_idl_files.gni6
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_initializer.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/README.md5
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/global_native_io.cc37
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/global_native_io.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/idls.gni2
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h48
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_error.cc95
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_error.h45
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file.cc384
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file.h67
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.cc755
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.h136
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.idl44
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.cc270
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.h22
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc331
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_manager.h68
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/native_io_manager.idl33
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/window_native_io.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.h40
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/network_information.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/network_information.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc64
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.h44
-rw-r--r--chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/idls.gni1
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_message.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc337
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_reader.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_reader.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_record.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_writer.cc197
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_writer.h74
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_writer.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_utils.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_utils.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/notification.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/notification.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/OWNERS4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/abort_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/complete_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_handler_utils.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_test.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_test_helper.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payments_validators.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn10
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/sctp_transport_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc118
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc165
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h69
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc72
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc58
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_sink_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc42
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc354
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h32
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc126
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h76
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc265
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc85
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permission_utils.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permissions.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/permissions.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/dom_mime_type.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection_available_event.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc51
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_provider.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/storage_manager.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/storage_manager.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc85
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/remote_objects/remote_object.cc143
-rw-r--r--chromium/third_party/blink/renderer/modules/remote_objects/remote_object.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/BUILD.gn77
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/OWNERS2
-rwxr-xr-xchromium/third_party/blink/renderer/modules/sanitizer_api/build_corpus.py68
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config1.txt17
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config2.txt9
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/default.txt0
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium1.html1000
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium2.html1000
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium3.html1000
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple1.html1
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple2.html3
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple3.html1
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc244
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h174
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api.dict435
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc121
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto20
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/dom_task.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/dom_task.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/scheduler.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_enumeration/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_enumeration/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.cc41
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.h30
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/idls.gni1
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/orientation_sensor.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_reading_remapper.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/idls.gni2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/navigator_serial.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_connection_event.cc37
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_connection_event.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_connection_event.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_connection_event_init.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc69
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc71
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h37
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/DEPS3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/face_detector.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/text_detector.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/srcobject/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/srcobject/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/README.md9
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/BUILD.gn17
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/DEPS9
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/idls.gni13
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.cc778
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.h92
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/vibration/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/vibration/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/vibration/vibration_controller.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/vibration/vibration_controller.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc52
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h2
-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/wake_lock/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/README.md2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h37
-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.cc48
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.cc57
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc57
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc22
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/oscillator_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/wave_shaper_node.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn19
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/DEPS9
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/DIR_METADATA11
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc147
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl23
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc62
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_support.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc269
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.h98
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl50
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.cc85
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h49
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc158
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.h80
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/color_space_primary_id.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/color_space_range_id.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/color_space_transfer_id.idl23
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc131
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h30
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_config.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.cc331
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.h136
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto62
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/generate_image_corpus.py81
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_h264.textproto76
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_vp8.textproto76
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/idls.gni27
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_base.textproto27
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc176
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/plane.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_color_space.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.cc432
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.h32
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc84
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc123
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_fuzzer.cc60
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_support.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc628
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h176
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc853
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame.h65
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc80
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h57
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.cc103
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.h83
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame_test.cc189
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl (renamed from chromium/third_party/blink/renderer/modules/webcodecs/web_codecs_error_callback.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database_context.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/DEPS6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/idls.gni3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc3
-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.cc317
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h64
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc968
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h112
-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_texture.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc74
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_texture_info.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.cc495
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h69
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.idl22
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame_handle.idl43
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc109
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc64
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h141
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc105
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.h22
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc84
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.idl35
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl35
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_binding_layout.idl17
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_copy_view.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc84
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h26
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc9
-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.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc189
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl17
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_image_bitmap_copy_view.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_buffer.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_image_bitmap.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_image_data_layout.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_object_base.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_base.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage_descriptor.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc125
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h32
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.idl17
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_descriptor.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc215
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_binding_layout.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_face_state.idl24
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_state_face_descriptor.idl24
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl16
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.cc174
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.h18
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_binding_layout.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_copy_view.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_data_layout.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/idls.gni24
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc49
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/navigator_web_id.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/navigator_web_id.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/navigator_web_id.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/web_id.cc137
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/web_id.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/web_id.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webid/web_id_request_options.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_message_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/webrtc/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/webrtc/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_stream.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_stream.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc71
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport_options.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport_test.cc105
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/send_stream.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/send_stream.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/test_utils.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/web_transport.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/navigator_usb.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/navigator_usb.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/navigator_usb.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb_device.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.cc64
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.h40
-rw-r--r--chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/BUILD.gn22
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/document_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/element_xr.h21
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/element_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/global_event_handlers_xr.h25
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/html_element_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/idls.gni15
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/mathml_element_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/svg_element_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/window_xr.idl12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc145
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h54
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc95
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h37
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.cc136
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.h67
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_state_init.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.cc174
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.h40
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_hand.cc61
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_hand.h71
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_hand.idl44
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_image_tracking_result.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.h30
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_space.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_space.h54
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_joint_space.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h28
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.cc93
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.h41
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.cc144
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.h52
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_system.cc204
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_system.h23
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.cc116
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_utils.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc58
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.h24
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc96
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_information.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl15
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h34
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl15
-rw-r--r--chromium/third_party/blink/renderer/platform/BUILD.gn66
-rw-r--r--chromium/third_party/blink/renderer/platform/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/platform/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_animation.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_animation.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_animation_curve.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_animation_delegate.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_keyframe.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc79
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h22
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/timing_function.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/animation/timing_function.h30
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_bus.cc28
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_bus.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_channel.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/audio_utilities.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/biquad.cc65
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/distance_effect.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/down_sampler.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc22
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/equal_power_panner.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/fft_frame.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/hrtf_panner.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/iir_filter.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/panner.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/push_pull_fifo.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/reverb.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/sinc_resampler.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/stereo_panner.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/audio/up_sampler.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/back_forward_cache_utils.cc38
-rw-r--r--chromium/third_party/blink/renderer/platform/back_forward_cache_utils.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/dictionary_base.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/exception_context.h135
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/exception_messages.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/exception_messages.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/exception_state.cc133
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/exception_state.h147
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/idl_member_installer.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc52
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/scoped_persistent.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/script_state.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/script_state.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/script_wrappable.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/script_wrappable.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/to_v8.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h51
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/union_base.cc33
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/union_base.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.cc47
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h56
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc35
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h46
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc58
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.h42
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/wrapper_type_info.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.cc44
-rw-r--r--chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/context_lifecycle_observer.cc25
-rw-r--r--chromium/third_party/blink/renderer/platform/context_lifecycle_observer.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/disk_data_allocator.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/disk_data_allocator.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/disk_data_metadata.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/file_path_conversion.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/impression_conversions.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/mediastream/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/platform.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/sync_load_response.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/url_conversion.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_back_forward_cache_loader_helper.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_font.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_memory_pressure_listener.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_mixed_content.cc99
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc56
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_security_origin.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_string.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_string_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_request.cc22
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_response.cc33
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/file_metadata.cc51
-rw-r--r--chromium/third_party/blink/renderer/platform/file_metadata.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font.cc83
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_cache.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_cache.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_description.cc66
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_description.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc81
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h32
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/font_metrics_override.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm8
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm75
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm16
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac_test.mm19
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc48
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.cc227
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.h47
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc122
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc280
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc159
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h63
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc41
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc41
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc39
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc57
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc19
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/calculation_value.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/layout_unit.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/length_functions.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/geometry/length_functions_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/DEPS14
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/OWNERS6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc47
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc59
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc85
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc190
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.h62
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc131
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource.h73
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc62
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc51
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.cc149
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.h76
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc213
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc157
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc96
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc71
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc76
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/contiguous_container.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc79
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test_wo_platform.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_blend.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_box_reflect.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_color_matrix.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_composite.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_convolve_matrix.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_displacement_map.cc25
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_drop_shadow.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_flood.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_gaussian_blur.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_lighting.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_merge.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_morphology.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_offset.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_tile.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/fe_turbulence.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_effect.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/filters/source_alpha.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc74
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc51
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h26
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc81
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc93
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h63
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc203
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_context.h104
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_context_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc59
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/graphics_types.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image.cc22
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image_data_buffer.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/image_frame_generator.cc74
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h56
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc64
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc300
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc402
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h29
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc65
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h13
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc34
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h32
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/painted_selection_bound.h29
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/parkable_image.cc269
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/parkable_image.h120
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.cc223
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.h122
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/parkable_image_test.cc668
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/path.cc63
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/path.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/path_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/placeholder_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc23
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/resource_id_traits.h55
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/rw_buffer.cc278
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/rw_buffer.h121
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/rw_buffer_test.cc182
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc56
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h13
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image_test.cc35
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc231
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.h86
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc313
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/BUILD.gn114
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/blink_gc.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_deque.h58
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h61
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h67
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h45
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h320
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h42
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_list_hash_set.h125
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector.h148
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h207
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/custom_spaces.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h60
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/garbage_collected.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h81
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/handle.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_allocator.h17
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_allocator_impl.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h210
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/heap_traits.h38
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_hash_table_backing.h283
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_vector_backing.h213
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h53
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h90
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap.h42
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc139
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h909
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.cc139
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h178
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc116
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.cc (renamed from chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc)0
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.h225
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h40
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h95
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/member.h59
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/persistent.h151
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc19
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc181
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h65
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h46
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h253
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/member.h131
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/persistent.h174
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/process_heap.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/self_keep_alive.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/thread_state.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/trace_traits.h129
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h26
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc137
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h36
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h275
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h214
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc21
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h45
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h27
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h29
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h245
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h54
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h26
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h59
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc143
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h149
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h55
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h42
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/heap/visitor.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc237
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc161
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.h27
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test.cc57
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.cc50
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.cc34
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/BUILD.gn7
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/histogram.cc26
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/histogram.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider_test.cc52
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc17
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/json/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/json/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/link_hash.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/BUILD.gn31
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc16
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc69
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors.cc247
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors.h64
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc82
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h43
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler_test.cc135
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer_test.cc96
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc154
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h22
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc33
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h13
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc88
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource.h51
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_error.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc293
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h39
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc285
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc182
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h28
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc359
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc52
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h59
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h36
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc170
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h18
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc132
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/DEPS31
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc594
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h128
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client_unittest.cc898
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc102
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.cc335
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h155
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context_unittest.cc219
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h60
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.cc459
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h39
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader_test.cc336
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc630
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender_unittest.cc561
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc1172
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_factory.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc715
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc23
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/mixed_content.cc102
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/mixed_content.h52
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h33
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc53
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h31
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/test_loader_factory.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/web_url_request_util.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/mediastream/webaudio_media_stream_source.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/big_string_mojom_traits_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc32
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h119
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set_test.cc214
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc39
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc50
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set.h123
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set_test.cc205
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/mojo_binding_context.h35
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/mojo/string16_mojom_traits_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/network/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc51
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/network/http_names.json51
-rw-r--r--chromium/third_party/blink/renderer/platform/network/http_parsers.cc43
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_log.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_state_notifier_test.cc47
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_utils.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/network/network_utils.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/p2p/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/p2p/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/DEPS5
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink_proxy.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h24
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc37
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc57
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc805
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h199
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc409
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc58
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc156
-rw-r--r--chromium/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/privacy_budget/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5466
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc83
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/features.h15
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/thread.cc19
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.cc41
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc40
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc367
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc30
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc55
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc108
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h14
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc190
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc21
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc29
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc92
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc18
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc412
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h58
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc78
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc72
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h88
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc58
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc113
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc31
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/public/thread.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc21
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc1
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.h23
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/supplementable.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/data/colrv0_test.ttfbin0 -> 976 bytes
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/data/colrv1_test.ttfbin0 -> 1128 bytes
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h22
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h66
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/testing_platform_support.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/unit_test_helpers.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/video_frame_utils.cc54
-rw-r--r--chromium/third_party/blink/renderer/platform/testing/video_frame_utils.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc85
-rw-r--r--chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/text/hyphenation_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/platform/text/locale_to_script_mapping.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/text/platform_locale.cc20
-rw-r--r--chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/timer.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/timer.h81
-rw-r--r--chromium/third_party/blink/renderer/platform/timer_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/scale_transform_operation.h3
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operation.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operations.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/transforms/translate_transform_operation.h1
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/local_video_capturer_source.cc6
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc610
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.h77
-rw-r--r--chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc314
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl.cc116
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc171
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.cc77
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.h19
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc128
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin.h25
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin_fuzzer.cc22
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc309
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_policy.cc62
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_policy.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/weborigin/security_policy_test.cc71
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/DEPS10
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/DIR_METADATA3
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/OWNERS2
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc503
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h76
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc260
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h5
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/DEPS13
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc38
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc15
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc28
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h20
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/render_frame_metadata_observer_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/frame_widget.h49
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/OWNERS5
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.cc24
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.cc254
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc193
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc186
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/input_metrics.cc48
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/input_metrics.h21
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc9
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.h4
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc92
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc13
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc42
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc14
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc57
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h13
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/widget_base.cc175
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/widget_base.h70
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/widget_base_client.h32
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/allocator.h88
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.cc113
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.h6
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/allocator/partitions_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/assertions.h77
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/container_annotations.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/cross_thread_copier.h17
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/deque.h30
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/deque_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/functional.h64
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/hash_iterators.h108
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc72
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/hash_table.h55
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/leak_annotations.h59
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/list_hash_set.h430
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/std_lib_extras.h9
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/DIR_METADATA4
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h45
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.cc5
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.h10
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/character_names.h8
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_builder.cc11
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_impl.cc59
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_impl.h57
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_mac.mm3
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/string_view.h11
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.cc12
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.h16
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/threading.cc2
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/threading.h7
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/type_traits.h41
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/vector.h10
5152 files changed, 164543 insertions, 102495 deletions
diff --git a/chromium/third_party/blink/renderer/.style.yapf b/chromium/third_party/blink/renderer/.style.yapf
deleted file mode 100644
index 557fa7bf84c..00000000000
--- a/chromium/third_party/blink/renderer/.style.yapf
+++ /dev/null
@@ -1,2 +0,0 @@
-[style]
-based_on_style = pep8
diff --git a/chromium/third_party/blink/renderer/BUILD.gn b/chromium/third_party/blink/renderer/BUILD.gn
index e70d561c630..02ee0bfd103 100644
--- a/chromium/third_party/blink/renderer/BUILD.gn
+++ b/chromium/third_party/blink/renderer/BUILD.gn
@@ -50,7 +50,8 @@ config("inside_blink") {
"-Wno-implicit-int-conversion",
]
- if (!is_ash || default_toolchain != "//build/toolchain/cros:target") {
+ if (!is_chromeos_ash ||
+ default_toolchain != "//build/toolchain/cros:target") {
cflags += [ "-Wno-enum-float-conversion" ]
}
}
diff --git a/chromium/third_party/blink/renderer/DEPS b/chromium/third_party/blink/renderer/DEPS
index bcc9717108c..8ea205527f7 100644
--- a/chromium/third_party/blink/renderer/DEPS
+++ b/chromium/third_party/blink/renderer/DEPS
@@ -1,14 +1,15 @@
include_rules = [
- "+base/allocator/partition_allocator/partition_alloc.h",
"+base/allocator/partition_allocator/oom.h",
+ "+base/allocator/partition_allocator/partition_alloc.h",
"+base/auto_reset.h",
"+base/bind.h",
- "+base/callback_helpers.h",
"+base/bit_cast.h",
+ "+base/bits.h",
"+base/check.h",
"+base/check_op.h",
"+base/compiler_specific.h",
"+base/containers/adapters.h",
+ "+base/containers/contains.h",
"+base/containers/span.h",
"+base/debug",
"+base/feature_list.h",
@@ -18,7 +19,6 @@ include_rules = [
"+base/i18n/rtl.h",
"+base/location.h",
"+base/logging.h",
- "+base/notreached.h",
"+base/macros.h",
"+base/memory/checked_ptr.h",
"+base/memory/ptr_util.h",
@@ -28,12 +28,14 @@ include_rules = [
"+base/metrics/histogram_functions.h",
"+base/metrics/histogram_macros.h",
"+base/metrics/single_sample_metrics.h",
+ "+base/notreached.h",
"+base/numerics/checked_math.h",
"+base/numerics/clamped_math.h",
"+base/numerics/ranges.h",
"+base/numerics/safe_conversions.h",
"+base/optional.h",
"+base/rand_util.h",
+ "+base/ranges",
"+base/sequence_checker.h",
"+base/sequenced_task_runner.h",
"+base/single_thread_task_runner.h",
@@ -57,10 +59,11 @@ include_rules = [
"+base/timer/elapsed_timer.h",
"+base/timer/timer.h",
"+base/trace_event",
- "+base/util/type_safety/pass_key.h",
- "+base/util/type_safety/strong_alias.h",
+ "+base/types/pass_key.h",
+ "+base/types/strong_alias.h",
"+build",
"+components/crash/core/common/crash_key.h",
+ "+components/power_scheduler",
"+net/cookies",
"+net/http/structured_headers.h",
"+services/network/public/mojom",
@@ -76,7 +79,7 @@ include_rules = [
"+ui/base/cursor/mojom/cursor.mojom-blink.h",
"+ui/base/cursor/mojom/cursor_type.mojom-blink.h",
- "+ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h",
+ "+ui/base/dragdrop/mojom",
"+ui/events/keycodes/dom",
"+v8",
]
diff --git a/chromium/third_party/blink/renderer/bindings/BUILD.gn b/chromium/third_party/blink/renderer/bindings/BUILD.gn
index dd6c7397b20..61c9e7f59da 100644
--- a/chromium/third_party/blink/renderer/bindings/BUILD.gn
+++ b/chromium/third_party/blink/renderer/bindings/BUILD.gn
@@ -17,8 +17,7 @@ import("//third_party/blink/renderer/modules/modules_idl_files.gni")
visibility = [ "//third_party/blink/renderer/*" ]
-# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
-python2_action("interfaces_info") {
+action("interfaces_info") {
script = "$bindings_scripts_dir/compute_interfaces_info_overall.py"
inputs = [
@@ -66,9 +65,6 @@ if (use_blink_v8_binding_new_idl_interface) {
template("collect_idl_files") {
action_with_pydeps(target_name) {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- run_under_python2 = true
-
script = "${bindings_scripts_dir}/collect_idl_files.py"
inputs = invoker.inputs
@@ -141,9 +137,6 @@ collect_idl_files("web_idl_in_modules_for_testing") {
action_with_pydeps("web_idl_database") {
visibility += [ "//tools/privacy_budget/blink_apis:*" ]
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- run_under_python2 = true
-
script = "${bindings_scripts_dir}/build_web_idl_database.py"
input_data_files = get_target_outputs(":web_idl_in_core") +
@@ -172,9 +165,6 @@ action_with_pydeps("web_idl_database") {
template("generate_bindings") {
action_with_pydeps(target_name) {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- run_under_python2 = true
-
script = "${bindings_scripts_dir}/generate_bindings.py"
if (defined(invoker.pool)) {
diff --git a/chromium/third_party/blink/renderer/bindings/DIR_METADATA b/chromium/third_party/blink/renderer/bindings/DIR_METADATA
new file mode 100644
index 00000000000..9eb47abdbd1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Bindings"
+}
+
+team_email: "blink-reviews-bindings@chromium.org"
diff --git a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
index 7835be1c7a8..84544f468fc 100644
--- a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+++ b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -957,23 +957,6 @@ v8::Local<v8::Value> V8XXX::CallAsFunctionCallback(const v8::Arguments& args) {
}
```
-### [CustomElementCallbacks] _(m, a)_
-
-Summary: Wraps the method/accessor with a Custom Elements "callback delivery scope" which will dispatch Custom Element callbacks (createdCallback, attributeChangedCallback, etc.) before returning to script.
-
-*** note
-This attribute is only for Custom Elements V0,
-and is superceded by `[CEReactions]` for V1.
-***
-
-If the method/accessor creates elements or modifies DOM nodes in any way, it should be tagged with this extended attribute. Even if you're not a Node, this may apply to you! For example [DOMTokenList.toggle](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/blink/renderer/core/dom/dom_token_list.idl&l=34) can be reflected in the attribute of its associated element, so it needs to be tagged with CustomElementCallbacks. If the method/accessor only calls something that may modify the DOM (for example, it runs user script as a callback) you don't need to tag your method with `[CustomElementCallbacks]`; that is the responsibility of the binding that actually modifies the DOM. In general over-applying this extended attribute is safe, with one caveat:
-
-* This extended attribute MUST NOT be used on members that operate on non-main threads, because the callback delivery scope accesses statics.
-* Basically: Don't apply this extended attribute to anything that can be called from a worker.
-* This criterion (accessible by workers) depends on implementation and cannot easily be checked from the IDL or C++ headers (it includes obvious cases like `[Exposed=Worker]`, where there is a constructor on the (JS) global object, but also cases where the C++ creates or accesses methods internally), so please be careful.
-
-Usage: `[CustomElementCallbacks]` takes no arguments.
-
### [HighEntropy] _(m, a, c)_
Summary: Denotes an API that exposes data that folks on the internet find useful for fingerprinting.
diff --git a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
index 1d8daf39c58..2433667658f 100644
--- a/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
+++ b/chromium/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -49,7 +49,6 @@ ContextEnabled=*
CrossOrigin=|Getter|Setter
Custom=|Getter|Setter|LegacyCallAsFunction|PropertyGetter|PropertyEnumerator|PropertyQuery
CustomConstructor
-CustomElementCallbacks
DefaultValue=Undefined
DeprecateAs=*
DoNotCheckConstants
diff --git a/chromium/third_party/blink/renderer/bindings/OWNERS b/chromium/third_party/blink/renderer/bindings/OWNERS
index 7458e2d7d38..c86b5f21f29 100644
--- a/chromium/third_party/blink/renderer/bindings/OWNERS
+++ b/chromium/third_party/blink/renderer/bindings/OWNERS
@@ -18,6 +18,3 @@ per-file generated_in_core.gni=*
per-file generated_in_modules.gni=*
per-file idl_in_core.gni=*
per-file idl_in_modules.gni=*
-
-# TEAM: blink-reviews-bindings@chromium.org
-# COMPONENT: Blink>Bindings
diff --git a/chromium/third_party/blink/renderer/bindings/bindings.gni b/chromium/third_party/blink/renderer/bindings/bindings.gni
index f942dd02d82..d05f6b67f90 100644
--- a/chromium/third_party/blink/renderer/bindings/bindings.gni
+++ b/chromium/third_party/blink/renderer/bindings/bindings.gni
@@ -54,6 +54,7 @@ bindings_core_v8_files =
"core/v8/maplike.h",
"core/v8/module_record.cc",
"core/v8/module_record.h",
+ "core/v8/module_request.cc",
"core/v8/module_request.h",
"core/v8/native_value_traits.h",
"core/v8/native_value_traits_impl.cc",
@@ -117,10 +118,9 @@ bindings_core_v8_files =
"core/v8/source_location.cc",
"core/v8/source_location.h",
"core/v8/to_v8_for_core.h",
+ "core/v8/to_v8_traits.h",
"core/v8/use_counter_callback.cc",
"core/v8/use_counter_callback.h",
- "core/v8/v0_custom_element_constructor_builder.cc",
- "core/v8/v0_custom_element_constructor_builder.h",
"core/v8/v8_binding_for_core.cc",
"core/v8/v8_binding_for_core.h",
"core/v8/v8_code_cache.cc",
@@ -159,8 +159,6 @@ bindings_core_v8_files =
"core/v8/v8_string_resource.h",
"core/v8/v8_throw_dom_exception.cc",
"core/v8/v8_throw_dom_exception.h",
- "core/v8/v8_v0_custom_element_lifecycle_callbacks.cc",
- "core/v8/v8_v0_custom_element_lifecycle_callbacks.h",
"core/v8/v8_wasm_response_extensions.cc",
"core/v8/v8_wasm_response_extensions.h",
"core/v8/window_proxy.cc",
@@ -199,6 +197,7 @@ bindings_unittest_files =
"core/v8/script_streamer_test.cc",
"core/v8/script_wrappable_v8_gc_integration_test.cc",
"core/v8/to_v8_test.cc",
+ "core/v8/to_v8_traits_test.cc",
"core/v8/trace_wrapper_v8_reference_test.cc",
"core/v8/v8_binding_for_testing.cc",
"core/v8/v8_binding_for_testing.h",
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/DIR_METADATA b/chromium/third_party/blink/renderer/bindings/core/v8/DIR_METADATA
new file mode 100644
index 00000000000..9eb47abdbd1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Bindings"
+}
+
+team_email: "blink-reviews-bindings@chromium.org"
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS b/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS
index daa4941ea82..09bbb23429b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/OWNERS
@@ -1,6 +1,3 @@
per-file script_source_.*=leszeks@chromium.org
per-file script_streamer.*=leszeks@chromium.org
per-file v8_wasm_response_extensions.*=ahaas@chromium.org
-
-# TEAM: blink-reviews-bindings@chromium.org
-# COMPONENT: Blink>Bindings
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
index c88962aa7f5..9339a01ec81 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_location.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_window.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/execution_context/agent.h"
#include "third_party/blink/renderer/core/frame/dom_window.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -151,9 +152,12 @@ bool CanAccessWindowInternal(
if (detail == SecurityOrigin::AccessResultDomainDetail::
kDomainNotRelevantAgentClusterMismatch) {
// Assert that because the agent clusters are different than the
- // WindowAgentFactories must also be different.
+ // WindowAgentFactories must also be different unless they differ in
+ // being explicitly origin keyed.
SECURITY_CHECK(
!IsSameWindowAgentFactory(accessing_window, local_target_window) ||
+ (accessing_window->GetAgent()->IsExplicitlyOriginKeyed() !=
+ local_target_window->GetAgent()->IsExplicitlyOriginKeyed()) ||
(WebTestSupport::IsRunningWebTest() &&
local_target_window->GetFrame()->PagePopupOwner()));
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module.h b/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module.h
index d53d8230d90..52e3d6d46a2 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "v8/include/v8.h"
@@ -50,9 +51,9 @@ struct BoxedV8ModuleHash {
static bool Equal(const Member<BoxedV8Module>& a,
const Member<BoxedV8Module>& b) {
- if (a.IsHashTableDeletedValue() && b.IsHashTableDeletedValue())
+ if (IsHashTableDeletedValue(a) && IsHashTableDeletedValue(b))
return true;
- if (a.IsHashTableDeletedValue() || b.IsHashTableDeletedValue())
+ if (IsHashTableDeletedValue(a) || IsHashTableDeletedValue(b))
return false;
if (!a && !b)
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module_test.cc
index 99bfffada18..a08b2d354fe 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/boxed_v8_module_test.cc
@@ -8,6 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/core/testing/module_test_base.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
@@ -23,18 +24,14 @@ TEST(BoxedV8ModuleTest, equalAndHash) {
const KURL js_url_b("https://example.com/b.js");
Member<BoxedV8Module> module_empty = nullptr;
- Member<BoxedV8Module> module_deleted(WTF::kHashTableDeletedValue);
+ Member<BoxedV8Module> module_deleted(kMemberDeletedValue);
- v8::Local<v8::Module> local_module_a = ModuleRecord::Compile(
- scope.GetIsolate(), "export const a = 'a';", js_url_a, js_url_a,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> local_module_a = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const a = 'a';", js_url_a);
Member<BoxedV8Module> module_a =
MakeGarbageCollected<BoxedV8Module>(scope.GetIsolate(), local_module_a);
- v8::Local<v8::Module> local_module_b = ModuleRecord::Compile(
- scope.GetIsolate(), "export const b = 'b';", js_url_b, js_url_b,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> local_module_b = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const b = 'b';", js_url_b);
Member<BoxedV8Module> module_b =
MakeGarbageCollected<BoxedV8Module>(scope.GetIsolate(), local_module_b);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom/DEPS b/chromium/third_party/blink/renderer/bindings/core/v8/custom/DEPS
new file mode 100644
index 00000000000..4cb839d6518
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+ "v8_dev_tools_host_custom.cc": [
+ "+base/strings/utf_string_conversions.h",
+ ],
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_dev_tools_host_custom.cc b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_dev_tools_host_custom.cc
index aa3e1ce4156..0f9c10419cd 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_dev_tools_host_custom.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/custom/v8_dev_tools_host_custom.cc
@@ -30,9 +30,10 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_dev_tools_host.h"
+#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "third_party/blink/public/common/context_menu_data/menu_item_info.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/web_menu_item_info.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_html_document.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_mouse_event.h"
@@ -58,7 +59,7 @@ void V8DevToolsHost::PlatformMethodCustom(
static bool PopulateContextMenuItems(v8::Isolate* isolate,
const v8::Local<v8::Array>& item_array,
- WebVector<WebMenuItemInfo>& items) {
+ std::vector<MenuItemInfo>& items) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
for (uint32_t i = 0; i < item_array->Length(); ++i) {
v8::Local<v8::Object> item =
@@ -84,13 +85,13 @@ static bool PopulateContextMenuItems(v8::Isolate* isolate,
String type_string = ToCoreStringWithNullCheck(type.As<v8::String>());
items.reserve(items.size() + 1);
items.emplace_back();
- WebMenuItemInfo& item_info = items[items.size() - 1];
+ MenuItemInfo& item_info = items[items.size() - 1];
if (type_string == "separator") {
- item_info.type = WebMenuItemInfo::kSeparator;
+ item_info.type = MenuItemInfo::kSeparator;
item_info.enabled = true;
item_info.action = DevToolsHost::kMaxContextMenuAction;
} else if (type_string == "subMenu" && sub_items->IsArray()) {
- item_info.type = WebMenuItemInfo::kSubMenu;
+ item_info.type = MenuItemInfo::kSubMenu;
item_info.enabled = true;
item_info.action = DevToolsHost::kMaxContextMenuAction;
v8::Local<v8::Array> sub_items_array =
@@ -100,7 +101,7 @@ static bool PopulateContextMenuItems(v8::Isolate* isolate,
return false;
TOSTRING_DEFAULT(V8StringResource<kTreatNullAsNullString>, label_string,
label, false);
- item_info.label = String(label_string);
+ item_info.label = base::UTF8ToUTF16(String(label_string).Utf8());
} else {
int32_t int32_id;
if (!id->Int32Value(context).To(&int32_id) || int32_id < 0 ||
@@ -109,10 +110,10 @@ static bool PopulateContextMenuItems(v8::Isolate* isolate,
TOSTRING_DEFAULT(V8StringResource<kTreatNullAsNullString>, label_string,
label, false);
if (type_string == "checkbox")
- item_info.type = WebMenuItemInfo::kCheckableOption;
+ item_info.type = MenuItemInfo::kCheckableOption;
else
- item_info.type = WebMenuItemInfo::kOption;
- item_info.label = String(label_string);
+ item_info.type = MenuItemInfo::kOption;
+ item_info.label = base::UTF8ToUTF16(String(label_string).Utf8());
item_info.enabled = true;
item_info.action = int32_id;
if (checked->IsBoolean())
@@ -144,7 +145,7 @@ void V8DevToolsHost::ShowContextMenuAtPointMethodCustom(
v8::Local<v8::Value> array = info[2];
if (!array->IsArray())
return;
- WebVector<WebMenuItemInfo> items;
+ std::vector<MenuItemInfo> items;
if (!PopulateContextMenuItems(isolate, v8::Local<v8::Array>::Cast(array),
items))
return;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/generated.gni b/chromium/third_party/blink/renderer/bindings/core/v8/generated.gni
index 3cffd6d6de2..a53634140ba 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/generated.gni
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/generated.gni
@@ -64,8 +64,6 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/html_option_element_or_html_opt_group_element.h",
"$bindings_core_v8_output_dir/html_script_element_or_svg_script_element.cc",
"$bindings_core_v8_output_dir/html_script_element_or_svg_script_element.h",
- "$bindings_core_v8_output_dir/image_bitmap_source.cc",
- "$bindings_core_v8_output_dir/image_bitmap_source.h",
"$bindings_core_v8_output_dir/internal_enum_or_internal_enum_sequence.cc",
"$bindings_core_v8_output_dir/internal_enum_or_internal_enum_sequence.h",
"$bindings_core_v8_output_dir/media_list_or_string.cc",
@@ -76,6 +74,8 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/node_or_string_or_trusted_script.h",
"$bindings_core_v8_output_dir/radio_node_list_or_element.cc",
"$bindings_core_v8_output_dir/radio_node_list_or_element.h",
+ "$bindings_core_v8_output_dir/readable_stream_default_controller_or_readable_byte_stream_controller.cc",
+ "$bindings_core_v8_output_dir/readable_stream_default_controller_or_readable_byte_stream_controller.h",
"$bindings_core_v8_output_dir/readable_stream_default_reader_or_readable_stream_byob_reader.cc",
"$bindings_core_v8_output_dir/readable_stream_default_reader_or_readable_stream_byob_reader.h",
"$bindings_core_v8_output_dir/request_or_usv_string.cc",
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index fb3b0e8f9d3..5ea6550e116 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -14,7 +14,6 @@
#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/html/custom/ce_reactions_scope.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/xml/dom_parser.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -112,7 +111,6 @@ void V8SetReflectedBooleanAttribute(
v8::Isolate* isolate = info.GetIsolate();
Element* impl = V8Element::ToImpl(info.Holder());
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
ExceptionState exception_state(isolate, ExceptionState::kSetterContext,
interface_name, idl_attribute_name);
CEReactionsScope ce_reactions_scope;
@@ -131,7 +129,6 @@ void V8SetReflectedDOMStringAttribute(
const QualifiedName& content_attr) {
Element* impl = V8Element::ToImpl(info.Holder());
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
CEReactionsScope ce_reactions_scope;
// Prepare the value to be set.
@@ -147,7 +144,6 @@ void V8SetReflectedNullableDOMStringAttribute(
const QualifiedName& content_attr) {
Element* impl = V8Element::ToImpl(info.Holder());
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
CEReactionsScope ce_reactions_scope;
// Prepare the value to be set.
@@ -413,8 +409,6 @@ void InstallCSSPropertyAttributes(
v8::Local<v8::FunctionTemplate> set_func = v8::FunctionTemplate::New(
isolate, CSSPropertyAttributeSet, v8_property_name, signature, 1,
v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect);
- get_func->RemovePrototype();
- set_func->RemovePrototype();
get_func->SetAcceptAnyReceiver(false);
set_func->SetAcceptAnyReceiver(false);
get_func->SetClassName(
@@ -485,9 +479,6 @@ void PerformAttributeSetCEReactionsReflect(
return;
}
- // [Reflect]
- V0CustomElementProcessingStack::CallbackDeliveryScope v0_custom_element_scope;
- // [CEReactions]
CEReactionsScope ce_reactions_scope;
Element* blink_receiver = V8Element::ToWrappableUnsafe(info.This());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h b/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
index a0582c93610..609c7d5a9cf 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
@@ -78,9 +78,9 @@ using InstallTemplateFunction =
using InstallRuntimeEnabledFeaturesFunction =
void (*)(v8::Isolate*,
const DOMWrapperWorld&,
- v8::Local<v8::Object> instance,
- v8::Local<v8::Object> prototype,
- v8::Local<v8::Function> interface);
+ v8::Local<v8::Object> instance_object,
+ v8::Local<v8::Object> prototype_object,
+ v8::Local<v8::Function> interface_object);
using InstallRuntimeEnabledFeaturesOnTemplateFunction = InstallTemplateFunction;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/idl_types.h b/chromium/third_party/blink/renderer/bindings/core/v8/idl_types.h
index 2b89fa0c356..daac58e5875 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/idl_types.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/idl_types.h
@@ -95,13 +95,33 @@ using IDLLongLongEnforceRange =
using IDLUnsignedLongLongEnforceRange =
IDLIntegerTypeBase<uint64_t, bindings::IDLIntegerConvMode::kEnforceRange>;
+// Floating point number types
+
+namespace bindings {
+
+enum class IDLFloatingPointNumberConvMode {
+ kDefault,
+ kUnrestricted,
+};
+
+} // namespace bindings
+
+template <typename T,
+ bindings::IDLFloatingPointNumberConvMode mode =
+ bindings::IDLFloatingPointNumberConvMode::kDefault>
+struct IDLFloatingPointNumberTypeBase final : public IDLBaseHelper<T> {};
+
// float
-struct IDLFloat final : public IDLBaseHelper<float> {};
-struct IDLUnrestrictedFloat final : public IDLBaseHelper<float> {};
+using IDLFloat = IDLFloatingPointNumberTypeBase<float>;
+using IDLUnrestrictedFloat = IDLFloatingPointNumberTypeBase<
+ float,
+ bindings::IDLFloatingPointNumberConvMode::kUnrestricted>;
// double
-struct IDLDouble final : public IDLBaseHelper<double> {};
-struct IDLUnrestrictedDouble final : public IDLBaseHelper<double> {};
+using IDLDouble = IDLFloatingPointNumberTypeBase<double>;
+using IDLUnrestrictedDouble = IDLFloatingPointNumberTypeBase<
+ double,
+ bindings::IDLFloatingPointNumberConvMode::kUnrestricted>;
// Strings
// The "Base" classes are always templatized and require users to specify how JS
@@ -179,29 +199,32 @@ enum class IDLStringConvMode {
} // namespace bindings
+// Base class for IDL string types (except for enumeration types)
+struct IDLStringTypeBase : public IDLBaseHelper<String> {};
+
// ByteString
template <bindings::IDLStringConvMode mode>
-struct IDLByteStringBaseV2 final : public IDLBaseHelper<String> {};
+struct IDLByteStringBaseV2 final : public IDLStringTypeBase {};
using IDLByteStringV2 =
IDLByteStringBaseV2<bindings::IDLStringConvMode::kDefault>;
// DOMString
template <bindings::IDLStringConvMode mode>
-struct IDLStringBaseV2 final : public IDLBaseHelper<String> {};
+struct IDLStringBaseV2 final : public IDLStringTypeBase {};
using IDLStringV2 = IDLStringBaseV2<bindings::IDLStringConvMode::kDefault>;
using IDLStringTreatNullAsEmptyStringV2 =
IDLStringBaseV2<bindings::IDLStringConvMode::kTreatNullAsEmptyString>;
// USVString
template <bindings::IDLStringConvMode mode>
-struct IDLUSVStringBaseV2 final : public IDLBaseHelper<String> {};
+struct IDLUSVStringBaseV2 final : public IDLStringTypeBase {};
using IDLUSVStringV2 =
IDLUSVStringBaseV2<bindings::IDLStringConvMode::kDefault>;
// [StringContext=TrustedHTML] DOMString
template <bindings::IDLStringConvMode mode>
struct IDLStringStringContextTrustedHTMLBaseV2 final
- : public IDLBaseHelper<String> {};
+ : public IDLStringTypeBase {};
using IDLStringStringContextTrustedHTMLV2 =
IDLStringStringContextTrustedHTMLBaseV2<
bindings::IDLStringConvMode::kDefault>;
@@ -212,7 +235,7 @@ using IDLStringStringContextTrustedHTMLTreatNullAsEmptyStringV2 =
// [StringContext=TrustedScript] DOMString
template <bindings::IDLStringConvMode mode>
struct IDLStringStringContextTrustedScriptBaseV2 final
- : public IDLBaseHelper<String> {};
+ : public IDLStringTypeBase {};
using IDLStringStringContextTrustedScriptV2 =
IDLStringStringContextTrustedScriptBaseV2<
bindings::IDLStringConvMode::kDefault>;
@@ -223,7 +246,7 @@ using IDLStringStringContextTrustedScriptTreatNullAsEmptyStringV2 =
// [StringContext=TrustedScriptURL] USVString
template <bindings::IDLStringConvMode mode>
struct IDLUSVStringStringContextTrustedScriptURLBaseV2 final
- : public IDLBaseHelper<String> {};
+ : public IDLStringTypeBase {};
using IDLUSVStringStringContextTrustedScriptURLV2 =
IDLUSVStringStringContextTrustedScriptURLBaseV2<
bindings::IDLStringConvMode::kDefault>;
@@ -298,6 +321,20 @@ struct IDLOnBeforeUnloadEventHandler final
: public IDLBaseHelper<EventListener*> {};
struct IDLOnErrorEventHandler final : public IDLBaseHelper<EventListener*> {};
+// IDL optional types
+//
+// IDLOptional represents an optional argument and supports a conversion from
+// ES undefined to "missing" special value. The "missing" value might be
+// represented in Blink as base::nullopt, nullptr, 0, etc. depending on a Blink
+// type.
+//
+// Note that IDLOptional is not meant to represent an optional dictionary
+// member.
+template <typename T>
+struct IDLOptional final : public IDLBase {
+ using ImplType = void;
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_IDL_TYPES_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
index f7099162b6e..3b83f26aced 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -182,12 +182,12 @@ ContentSecurityPolicy* IsolatedWorldCSP::CreateIsolatedWorldCSP(
IsolatedWorldCSPDelegate* delegate =
MakeGarbageCollected<IsolatedWorldCSPDelegate>(
- window, std::move(self_origin), world_id,
+ window, self_origin, world_id,
policy.IsEmpty() ? CSPType::kEmpty : CSPType::kNonEmpty);
csp->BindToDelegate(*delegate);
- csp->AddPolicyFromHeaderValue(
- policy, network::mojom::ContentSecurityPolicyType::kEnforce,
- network::mojom::ContentSecurityPolicySource::kHTTP);
+ csp->DidReceiveHeader(policy, *self_origin,
+ network::mojom::ContentSecurityPolicyType::kEnforce,
+ network::mojom::ContentSecurityPolicySource::kHTTP);
return csp;
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
index 412bad667ca..5931ae96436 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_based_event_listener.cc
@@ -132,10 +132,10 @@ void JSBasedEventListener::Invoke(
current_event = window->CurrentEvent();
// Step 8-2: If |struct|’s invocation-target-in-shadow-tree is false (i.e.,
- // event's target is in a V1 shadow tree), then set |global|’s current
+ // event's target is in a shadow tree), then set |global|’s current
// event to event.
Node* target_node = event->target()->ToNode();
- if (!(target_node && target_node->IsInV1ShadowTree()))
+ if (!(target_node && target_node->IsInShadowTree()))
window->SetCurrentEvent(event);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
index 77d95d30e80..a22d5d790f8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
@@ -203,10 +203,9 @@ v8::Local<v8::Value> JSEventHandlerForContentAttribute::GetCompiledHandler(
DCHECK_LE(scopes_size, base::size(scopes));
v8::ScriptOrigin origin(
- V8String(isolate, source_url_),
- v8::Integer::New(isolate, position_.line_.ZeroBasedInt()),
- v8::Integer::New(isolate, position_.column_.ZeroBasedInt()),
- v8::True(isolate)); // True as |SanitizeScriptErrors::kDoNotSanitize|
+ V8String(isolate, source_url_), position_.line_.ZeroBasedInt(),
+ position_.column_.ZeroBasedInt(),
+ true); // true as |SanitizeScriptErrors::kDoNotSanitize|
v8::ScriptCompiler::Source source(V8String(isolate, script_body_), origin);
v8::Local<v8::Function> compiled_function;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index 16d2cc458b3..be5cf4457cd 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -69,12 +69,6 @@
namespace blink {
-namespace {
-
-constexpr char kGlobalProxyLabel[] = "WindowProxy::global_proxy_";
-
-} // namespace
-
void LocalWindowProxy::Trace(Visitor* visitor) const {
visitor->Trace(script_state_);
WindowProxy::Trace(visitor);
@@ -94,8 +88,6 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
if (lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged) {
DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged);
- if (next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged)
- global_proxy_.SetPhantom();
lifecycle_ = next_status;
return;
}
@@ -114,7 +106,7 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
next_status == Lifecycle::kGlobalObjectIsDetached) {
// Clean up state on the global proxy, which will be reused.
if (!global_proxy_.IsEmpty()) {
- CHECK(global_proxy_ == context->Global());
+ CHECK(global_proxy_.Get() == context->Global());
CHECK_EQ(ToScriptWrappable(context->Global()),
ToScriptWrappable(
context->Global()->GetPrototype().As<v8::Object>()));
@@ -135,12 +127,6 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
V8GCForContextDispose::Instance().NotifyContextDisposed(
GetFrame()->IsMainFrame(), frame_reuse_status);
- if (next_status == Lifecycle::kFrameIsDetached) {
- // The context's frame is detached from the DOM, so there shouldn't be a
- // strong reference to the context.
- global_proxy_.SetPhantom();
- }
-
DCHECK_EQ(lifecycle_, Lifecycle::kContextIsInitialized);
lifecycle_ = next_status;
}
@@ -159,7 +145,6 @@ void LocalWindowProxy::Initialize() {
v8::Local<v8::Context> context = script_state_->GetContext();
if (global_proxy_.IsEmpty()) {
global_proxy_.Set(GetIsolate(), context->Global());
- global_proxy_.Get().AnnotateStrongRetainer(kGlobalProxyLabel);
CHECK(!global_proxy_.IsEmpty());
}
@@ -184,8 +169,8 @@ void LocalWindowProxy::Initialize() {
scoped_refptr<const SecurityOrigin> origin;
if (world_->IsMainWorld()) {
- // ActivityLogger for main world is updated within updateDocumentInternal().
- UpdateDocumentInternal();
+ // This also updates the ActivityLogger for the main world.
+ UpdateDocumentForMainWorld();
origin = GetFrame()->DomWindow()->GetSecurityOrigin();
} else {
UpdateActivityLogger();
@@ -319,7 +304,7 @@ void LocalWindowProxy::SetupWindowPrototypeChain() {
// The global proxy object. Note this is not the global object.
v8::Local<v8::Object> global_proxy = context->Global();
- CHECK(global_proxy_ == global_proxy);
+ CHECK(global_proxy_.Get() == global_proxy);
V8DOMWrapper::SetNativeInfo(GetIsolate(), global_proxy, wrapper_type_info,
window);
// Mark the handle to be traced by Oilpan, since the global proxy has a
@@ -448,7 +433,6 @@ void LocalWindowProxy::SetSecurityToken(const SecurityOrigin* origin) {
}
void LocalWindowProxy::UpdateDocument() {
- DCHECK(world_->IsMainWorld());
// For an uninitialized main window proxy, there's nothing we need
// to update. The update is done when the window proxy gets initialized later.
if (lifecycle_ == Lifecycle::kContextIsUninitialized)
@@ -464,10 +448,14 @@ void LocalWindowProxy::UpdateDocument() {
return;
}
- UpdateDocumentInternal();
+ if (!world_->IsMainWorld())
+ return;
+
+ UpdateDocumentForMainWorld();
}
-void LocalWindowProxy::UpdateDocumentInternal() {
+void LocalWindowProxy::UpdateDocumentForMainWorld() {
+ DCHECK(world_->IsMainWorld());
UpdateActivityLogger();
UpdateDocumentProperty();
UpdateSecurityOrigin(GetFrame()->DomWindow()->GetSecurityOrigin());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.h b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.h
index 5fa12678f86..27f175f3b61 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/local_window_proxy.h
@@ -71,6 +71,7 @@ class LocalWindowProxy final : public WindowProxy {
v8::Context::AbortScriptExecutionCallback callback);
private:
+ // LocalWindowProxy overrides:
bool IsLocal() const override { return true; }
void Initialize() override;
void DisposeContext(Lifecycle next_status, FrameReuseStatus) override;
@@ -92,9 +93,10 @@ class LocalWindowProxy final : public WindowProxy {
// Triggers updates of objects that are associated with a Document:
// - the activity logger
- // - the document DOM wrapper
+ // - the document DOM wrapper (performance optimization for accessing
+ // window.document in the main world)
// - the security origin
- void UpdateDocumentInternal();
+ void UpdateDocumentForMainWorld();
// The JavaScript wrapper for the document object is cached on the global
// object for fast access. UpdateDocumentProperty sets the wrapper
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/module_record.cc b/chromium/third_party/blink/renderer/bindings/core/v8/module_record.cc
index ef6715fe6a9..6dd4e486d90 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/module_record.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/module_record.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_record_resolver.h"
@@ -17,6 +18,8 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
+#include "third_party/blink/renderer/platform/wtf/wtf.h"
namespace blink {
@@ -46,15 +49,11 @@ void ModuleRecordProduceCacheData::Trace(Visitor* visitor) const {
v8::Local<v8::Module> ModuleRecord::Compile(
v8::Isolate* isolate,
- const String& source,
- const KURL& source_url,
- const KURL& base_url,
+ const ModuleScriptCreationParams& params,
const ScriptFetchOptions& options,
const TextPosition& text_position,
ExceptionState& exception_state,
mojom::blink::V8CacheOptions v8_cache_options,
- SingleCachedMetadataHandler* cache_handler,
- ScriptSourceLocationType source_location_type,
ModuleRecordProduceCacheData** out_produce_cache_data) {
v8::TryCatch try_catch(isolate);
v8::Local<v8::Module> module;
@@ -71,13 +70,13 @@ v8::Local<v8::Module> ModuleRecord::Compile(
V8CodeCache::ProduceCacheOptions produce_cache_options;
v8::ScriptCompiler::NoCacheReason no_cache_reason;
std::tie(compile_options, produce_cache_options, no_cache_reason) =
- V8CodeCache::GetCompileOptions(v8_cache_options, cache_handler,
- source.length(), source_location_type);
+ V8CodeCache::GetCompileOptions(v8_cache_options, params.CacheHandler(),
+ params.GetSourceText().length(),
+ params.SourceLocationType());
if (!V8ScriptRunner::CompileModule(
- isolate, source, cache_handler, source_url, text_position,
- compile_options, no_cache_reason,
- ReferrerScriptInfo(base_url, options,
+ isolate, params, text_position, compile_options, no_cache_reason,
+ ReferrerScriptInfo(params.BaseURL(), options,
ReferrerScriptInfo::BaseUrlSource::kOther))
.ToLocal(&module)) {
DCHECK(try_catch.HasCaught());
@@ -89,7 +88,7 @@ v8::Local<v8::Module> ModuleRecord::Compile(
if (out_produce_cache_data) {
*out_produce_cache_data =
MakeGarbageCollected<ModuleRecordProduceCacheData>(
- isolate, cache_handler, produce_cache_options, module);
+ isolate, params.CacheHandler(), produce_cache_options, module);
}
return module;
@@ -134,18 +133,43 @@ Vector<ModuleRequest> ModuleRecord::ModuleRequests(
if (record.IsEmpty())
return Vector<ModuleRequest>();
+ v8::Local<v8::FixedArray> v8_module_requests = record->GetModuleRequests();
+ int length = v8_module_requests->Length();
Vector<ModuleRequest> requests;
- int length = record->GetModuleRequestsLength();
requests.ReserveInitialCapacity(length);
+ bool needs_text_position =
+ !WTF::IsMainThread() ||
+ probe::ToCoreProbeSink(ExecutionContext::From(script_state))
+ ->HasDevToolsSessions();
for (int i = 0; i < length; ++i) {
- v8::Local<v8::String> v8_name = record->GetModuleRequest(i);
- v8::Location v8_loc = record->GetModuleRequestLocation(i);
- TextPosition position(
- OrdinalNumber::FromZeroBasedInt(v8_loc.GetLineNumber()),
- OrdinalNumber::FromZeroBasedInt(v8_loc.GetColumnNumber()));
- requests.emplace_back(ToCoreString(v8_name), position);
+ v8::Local<v8::ModuleRequest> v8_module_request =
+ v8_module_requests->Get(script_state->GetContext(), i)
+ .As<v8::ModuleRequest>();
+ v8::Local<v8::String> v8_specifier = v8_module_request->GetSpecifier();
+ TextPosition position = TextPosition::MinimumPosition();
+ if (needs_text_position) {
+ // The source position is only used by DevTools for module requests and
+ // only visible if devtools is open when the request is initiated.
+ // Calculating the source position is not free and V8 has to initialize
+ // the line end information for the complete module, thus we try to
+ // avoid this additional work here if DevTools is closed.
+ int source_offset = v8_module_request->GetSourceOffset();
+ v8::Location v8_loc = record->SourceOffsetToLocation(source_offset);
+ position = TextPosition(
+ OrdinalNumber::FromZeroBasedInt(v8_loc.GetLineNumber()),
+ OrdinalNumber::FromZeroBasedInt(v8_loc.GetColumnNumber()));
+ }
+ Vector<ImportAssertion> import_assertions =
+ ModuleRecord::ToBlinkImportAssertions(
+ script_state->GetContext(), record,
+ v8_module_request->GetImportAssertions(),
+ /*v8_import_assertions_has_positions=*/true);
+
+ requests.emplace_back(ToCoreString(v8_specifier), position,
+ import_assertions);
}
+
return requests;
}
@@ -157,19 +181,71 @@ v8::Local<v8::Value> ModuleRecord::V8Namespace(v8::Local<v8::Module> record) {
v8::MaybeLocal<v8::Module> ModuleRecord::ResolveModuleCallback(
v8::Local<v8::Context> context,
v8::Local<v8::String> specifier,
+ v8::Local<v8::FixedArray> import_assertions,
v8::Local<v8::Module> referrer) {
v8::Isolate* isolate = context->GetIsolate();
Modulator* modulator = Modulator::From(ScriptState::From(context));
DCHECK(modulator);
+ ModuleRequest module_request(
+ ToCoreStringWithNullCheck(specifier), TextPosition(),
+ ModuleRecord::ToBlinkImportAssertions(
+ context, referrer, import_assertions,
+ /*v8_import_assertions_has_positions=*/true));
+
ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
"ModuleRecord", "resolveModuleCallback");
v8::Local<v8::Module> resolved =
- modulator->GetModuleRecordResolver()->Resolve(
- ToCoreStringWithNullCheck(specifier), referrer, exception_state);
+ modulator->GetModuleRecordResolver()->Resolve(module_request, referrer,
+ exception_state);
DCHECK(!resolved.IsEmpty());
DCHECK(!exception_state.HadException());
+
return resolved;
}
+Vector<ImportAssertion> ModuleRecord::ToBlinkImportAssertions(
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Module> record,
+ v8::Local<v8::FixedArray> v8_import_assertions,
+ bool v8_import_assertions_has_positions) {
+ // If v8_import_assertions_has_positions == true then v8_import_assertions has
+ // source position information and is given in the form [key1, value1,
+ // source_offset1, key2, value2, source_offset2, ...]. Otherwise if
+ // v8_import_assertions_has_positions == false, then v8_import_assertions is
+ // in the form [key1, value1, key2, value2, ...].
+ const int kV8AssertionEntrySize = v8_import_assertions_has_positions ? 3 : 2;
+
+ Vector<ImportAssertion> import_assertions;
+ int number_of_import_assertions =
+ v8_import_assertions->Length() / kV8AssertionEntrySize;
+ import_assertions.ReserveInitialCapacity(number_of_import_assertions);
+ for (int i = 0; i < number_of_import_assertions; ++i) {
+ v8::Local<v8::String> v8_assertion_key =
+ v8_import_assertions->Get(context, i * kV8AssertionEntrySize)
+ .As<v8::String>();
+ v8::Local<v8::String> v8_assertion_value =
+ v8_import_assertions->Get(context, (i * kV8AssertionEntrySize) + 1)
+ .As<v8::String>();
+ TextPosition assertion_position;
+ if (v8_import_assertions_has_positions) {
+ int32_t v8_assertion_source_offset =
+ v8_import_assertions->Get(context, (i * kV8AssertionEntrySize) + 2)
+ .As<v8::Int32>()
+ ->Value();
+ v8::Location v8_assertion_loc =
+ record->SourceOffsetToLocation(v8_assertion_source_offset);
+ assertion_position = TextPosition(
+ OrdinalNumber::FromZeroBasedInt(v8_assertion_loc.GetLineNumber()),
+ OrdinalNumber::FromZeroBasedInt(v8_assertion_loc.GetColumnNumber()));
+ }
+
+ import_assertions.emplace_back(ToCoreString(v8_assertion_key),
+ ToCoreString(v8_assertion_value),
+ assertion_position);
+ }
+
+ return import_assertions;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/module_record.h b/chromium/third_party/blink/renderer/bindings/core/v8/module_record.h
index 289213fe508..c4c02d9b10b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/module_record.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/module_record.h
@@ -22,6 +22,7 @@ namespace blink {
class ExceptionState;
class KURL;
+class ModuleScriptCreationParams;
class ScriptFetchOptions;
class ScriptState;
class ScriptValue;
@@ -63,16 +64,11 @@ class CORE_EXPORT ModuleRecord final {
public:
static v8::Local<v8::Module> Compile(
v8::Isolate*,
- const String& source,
- const KURL& source_url,
- const KURL& base_url,
+ const ModuleScriptCreationParams& params,
const ScriptFetchOptions&,
const TextPosition&,
ExceptionState&,
mojom::blink::V8CacheOptions = mojom::blink::V8CacheOptions::kDefault,
- SingleCachedMetadataHandler* = nullptr,
- ScriptSourceLocationType source_location_type =
- ScriptSourceLocationType::kInternal,
ModuleRecordProduceCacheData** out_produce_cache_data = nullptr);
// Returns exception, if any.
@@ -87,10 +83,24 @@ class CORE_EXPORT ModuleRecord final {
static v8::Local<v8::Value> V8Namespace(v8::Local<v8::Module> record);
+ // ToBlinkImportAssertions deserializes v8::FixedArray encoded import
+ // assertions to blink::ImportAssertion. When
+ // |v8_import_assertions_has_positions| is set to true, it expects [key1,
+ // value1, position1, key2, value2, position2, ...] encoding used in
+ // v8::ModuleRequest::GetImportAssertions(). When it is set to false, it
+ // expects [key1, value1, key2, value2, ...] encoding used in the
+ // |HostImportModuleDynamically| callback.
+ static Vector<ImportAssertion> ToBlinkImportAssertions(
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Module> record,
+ v8::Local<v8::FixedArray> v8_import_assertions,
+ bool v8_import_assertions_has_positions);
+
private:
static v8::MaybeLocal<v8::Module> ResolveModuleCallback(
v8::Local<v8::Context>,
v8::Local<v8::String> specifier,
+ v8::Local<v8::FixedArray> import_assertions,
v8::Local<v8::Module> referrer);
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/module_record_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
index 3b5813b3c9a..39d0164390b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
@@ -29,7 +29,7 @@ namespace {
class TestModuleRecordResolver final : public ModuleRecordResolver {
public:
- TestModuleRecordResolver(v8::Isolate* isolate) : isolate_(isolate) {}
+ explicit TestModuleRecordResolver(v8::Isolate* isolate) : isolate_(isolate) {}
~TestModuleRecordResolver() override = default;
size_t ResolveCount() const { return specifiers_.size(); }
@@ -56,10 +56,10 @@ class TestModuleRecordResolver final : public ModuleRecordResolver {
return nullptr;
}
- v8::Local<v8::Module> Resolve(const String& specifier,
+ v8::Local<v8::Module> Resolve(const ModuleRequest& module_request,
v8::Local<v8::Module> module,
ExceptionState&) override {
- specifiers_.push_back(specifier);
+ specifiers_.push_back(module_request.specifier);
return module_records_.TakeFirst()->NewLocal(isolate_);
}
@@ -114,19 +114,16 @@ class ModuleRecordTest : public ::testing::Test, public ParametrizedModuleTest {
TEST_P(ModuleRecordTest, compileSuccess) {
V8TestingScope scope;
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- scope.GetIsolate(), "export const a = 42;", js_url, js_url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const a = 42;", js_url);
ASSERT_FALSE(module.IsEmpty());
}
TEST_P(ModuleRecordTest, compileFail) {
V8TestingScope scope;
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- scope.GetIsolate(), "123 = 456", js_url, js_url, ScriptFetchOptions(),
- TextPosition::MinimumPosition(), scope.GetExceptionState());
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "123 = 456", js_url, scope.GetExceptionState());
ASSERT_TRUE(module.IsEmpty());
EXPECT_TRUE(scope.GetExceptionState().HadException());
}
@@ -134,16 +131,43 @@ TEST_P(ModuleRecordTest, compileFail) {
TEST_P(ModuleRecordTest, moduleRequests) {
V8TestingScope scope;
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
scope.GetIsolate(), "import 'a'; import 'b'; export const c = 'c';",
- js_url, js_url, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ js_url);
ASSERT_FALSE(module.IsEmpty());
auto requests = ModuleRecord::ModuleRequests(scope.GetScriptState(), module);
EXPECT_EQ(2u, requests.size());
EXPECT_EQ("a", requests[0].specifier);
+ EXPECT_EQ(0u, requests[0].import_assertions.size());
EXPECT_EQ("b", requests[1].specifier);
+ EXPECT_EQ(0u, requests[1].import_assertions.size());
+}
+
+TEST_P(ModuleRecordTest, moduleRequestsWithImportAssertions) {
+ V8TestingScope scope;
+ v8::V8::SetFlagsFromString("--harmony-import-assertions");
+ const KURL js_url("https://example.com/foo.js");
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ scope.GetIsolate(),
+ "import 'a' assert { };"
+ "import 'b' assert { type: 'x'};"
+ "import 'c' assert { foo: 'y', type: 'z' };",
+ js_url);
+ ASSERT_FALSE(module.IsEmpty());
+
+ auto requests = ModuleRecord::ModuleRequests(scope.GetScriptState(), module);
+ EXPECT_EQ(3u, requests.size());
+ EXPECT_EQ("a", requests[0].specifier);
+ EXPECT_EQ(0u, requests[0].import_assertions.size());
+ EXPECT_EQ(String(), requests[0].GetModuleTypeString());
+
+ EXPECT_EQ("b", requests[1].specifier);
+ EXPECT_EQ(1u, requests[1].import_assertions.size());
+ EXPECT_EQ("x", requests[1].GetModuleTypeString());
+
+ EXPECT_EQ("c", requests[2].specifier);
+ EXPECT_EQ("z", requests[2].GetModuleTypeString());
}
TEST_P(ModuleRecordTest, instantiateNoDeps) {
@@ -154,10 +178,8 @@ TEST_P(ModuleRecordTest, instantiateNoDeps) {
auto* resolver = modulator->GetTestModuleRecordResolver();
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- scope.GetIsolate(), "export const a = 42;", js_url, js_url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const a = 42;", js_url);
ASSERT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url);
@@ -174,26 +196,21 @@ TEST_P(ModuleRecordTest, instantiateWithDeps) {
auto* resolver = modulator->GetTestModuleRecordResolver();
const KURL js_url_a("https://example.com/a.js");
- v8::Local<v8::Module> module_a = ModuleRecord::Compile(
- scope.GetIsolate(), "export const a = 'a';", js_url_a, js_url_a,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module_a = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const a = 'a';", js_url_a);
ASSERT_FALSE(module_a.IsEmpty());
resolver->PrepareMockResolveResult(module_a);
const KURL js_url_b("https://example.com/b.js");
- v8::Local<v8::Module> module_b = ModuleRecord::Compile(
- scope.GetIsolate(), "export const b = 'b';", js_url_b, js_url_b,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module_b = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const b = 'b';", js_url_b);
ASSERT_FALSE(module_b.IsEmpty());
resolver->PrepareMockResolveResult(module_b);
const KURL js_url_c("https://example.com/c.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
scope.GetIsolate(), "import 'a'; import 'b'; export const c = 123;",
- js_url_c, js_url_c, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ js_url_c);
ASSERT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url_c);
@@ -212,10 +229,8 @@ TEST_P(ModuleRecordTest, EvaluationErrorIsRemembered) {
auto* resolver = modulator->GetTestModuleRecordResolver();
const KURL js_url_f("https://example.com/failure.js");
- v8::Local<v8::Module> module_failure = ModuleRecord::Compile(
- scope.GetIsolate(), "nonexistent_function()", js_url_f, js_url_f,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module_failure = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "nonexistent_function()", js_url_f);
ASSERT_FALSE(module_failure.IsEmpty());
ASSERT_TRUE(
ModuleRecord::Instantiate(state, module_failure, js_url_f).IsEmpty());
@@ -226,9 +241,8 @@ TEST_P(ModuleRecordTest, EvaluationErrorIsRemembered) {
resolver->PrepareMockResolveResult(module_failure);
const KURL js_url_c("https://example.com/c.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
scope.GetIsolate(), "import 'failure'; export const c = 123;", js_url_c,
- js_url_c, ScriptFetchOptions(), TextPosition::MinimumPosition(),
scope.GetExceptionState());
ASSERT_FALSE(module.IsEmpty());
ASSERT_TRUE(ModuleRecord::Instantiate(state, module, js_url_c).IsEmpty());
@@ -253,10 +267,8 @@ TEST_P(ModuleRecordTest, Evaluate) {
MakeGarbageCollected<ModuleRecordTestModulator>(scope.GetScriptState());
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- scope.GetIsolate(), "export const a = 42; window.foo = 'bar';", js_url,
- js_url, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const a = 42; window.foo = 'bar';", js_url);
ASSERT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url);
@@ -289,9 +301,8 @@ TEST_P(ModuleRecordTest, EvaluateCaptureError) {
MakeGarbageCollected<ModuleRecordTestModulator>(scope.GetScriptState());
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- scope.GetIsolate(), "throw 'bar';", js_url, js_url, ScriptFetchOptions(),
- TextPosition::MinimumPosition(), ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module =
+ ModuleTestBase::CompileModule(scope.GetIsolate(), "throw 'bar';", js_url);
ASSERT_FALSE(module.IsEmpty());
ScriptValue instantiation_exception =
ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/module_request.cc b/chromium/third_party/blink/renderer/bindings/core/v8/module_request.cc
new file mode 100644
index 00000000000..f915e6e6e02
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/module_request.cc
@@ -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.
+
+#include "third_party/blink/renderer/bindings/core/v8/module_request.h"
+
+namespace blink {
+
+String ModuleRequest::GetModuleTypeString() const {
+ for (const ImportAssertion& import_assertion : import_assertions) {
+ if (import_assertion.key == "type") {
+ DCHECK(!import_assertion.value.IsNull());
+ return import_assertion.value;
+ }
+ }
+ return String();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/module_request.h b/chromium/third_party/blink/renderer/bindings/core/v8/module_request.h
index 29d6c2beed7..9710252bb7e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/module_request.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/module_request.h
@@ -5,16 +5,40 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_MODULE_REQUEST_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_MODULE_REQUEST_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-struct ModuleRequest {
+// An import assertion key/value pair per spec:
+// https://tc39.es/proposal-import-assertions/
+struct ImportAssertion {
+ String key;
+ String value;
+ TextPosition position;
+ ImportAssertion(const String& key,
+ const String& value,
+ const TextPosition& position)
+ : key(key), value(value), position(position) {}
+};
+
+// An instance of a ModuleRequest record:
+// https://tc39.es/proposal-import-assertions/#sec-modulerequest-record
+// Represents a module script's request to import a module given a specifier and
+// list of import assertions.
+struct CORE_EXPORT ModuleRequest {
String specifier;
TextPosition position;
- ModuleRequest(const String& specifier, const TextPosition& position)
- : specifier(specifier), position(position) {}
+ Vector<ImportAssertion> import_assertions;
+ ModuleRequest(const String& specifier,
+ const TextPosition& position,
+ const Vector<ImportAssertion>& import_assertions)
+ : specifier(specifier),
+ position(position),
+ import_assertions(import_assertions) {}
+
+ String GetModuleTypeString() const;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
index ccc3625f634..5a39f8ae2fd 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
@@ -36,6 +36,7 @@ namespace bindings {
class DictionaryBase;
class EnumerationBase;
+class UnionBase;
CORE_EXPORT void NativeValueTraitsInterfaceNotOfType(
const WrapperTypeInfo* wrapper_type_info,
@@ -58,10 +59,21 @@ struct CORE_EXPORT NativeValueTraits<IDLAny>
return ScriptValue(isolate, value);
}
};
+
// IDLNullable<IDLAny> must not be used.
template <>
struct NativeValueTraits<IDLNullable<IDLAny>>;
+template <>
+struct CORE_EXPORT NativeValueTraits<IDLOptional<IDLAny>>
+ : public NativeValueTraitsBase<IDLAny> {
+ static ScriptValue NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return ScriptValue(isolate, value);
+ }
+};
+
// boolean
template <>
struct CORE_EXPORT NativeValueTraits<IDLBoolean>
@@ -73,6 +85,16 @@ struct CORE_EXPORT NativeValueTraits<IDLBoolean>
}
};
+template <>
+struct CORE_EXPORT NativeValueTraits<IDLOptional<IDLBoolean>>
+ : public NativeValueTraitsBase<IDLBoolean> {
+ static bool NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return ToBoolean(isolate, value, exception_state);
+ }
+};
+
// Integer types
#define DEFINE_NATIVE_VALUE_TRAITS_INTEGER_TYPE(T, Func) \
template <bindings::IDLIntegerConvMode mode> \
@@ -387,6 +409,19 @@ struct CORE_EXPORT NativeValueTraits<IDLNullable<IDLByteStringV2>>
}
};
+template <>
+struct CORE_EXPORT NativeValueTraits<IDLOptional<IDLByteStringV2>>
+ : public NativeValueTraitsBase<IDLByteStringV2> {
+ static decltype(auto) NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return bindings::NativeValueTraitsStringAdapter();
+ return NativeValueTraits<IDLByteStringV2>::NativeValue(isolate, value,
+ exception_state);
+ }
+};
+
template <bindings::IDLStringConvMode mode>
struct NativeValueTraits<IDLStringBaseV2<mode>>
: public NativeValueTraitsBase<IDLStringBaseV2<mode>> {
@@ -433,6 +468,19 @@ struct CORE_EXPORT NativeValueTraits<IDLNullable<IDLStringV2>>
}
};
+template <>
+struct CORE_EXPORT NativeValueTraits<IDLOptional<IDLStringV2>>
+ : public NativeValueTraitsBase<IDLStringV2> {
+ static decltype(auto) NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return bindings::NativeValueTraitsStringAdapter();
+ return NativeValueTraits<IDLStringV2>::NativeValue(isolate, value,
+ exception_state);
+ }
+};
+
template <bindings::IDLStringConvMode mode>
struct NativeValueTraits<IDLUSVStringBaseV2<mode>>
: public NativeValueTraitsBase<IDLUSVStringBaseV2<mode>> {
@@ -463,6 +511,19 @@ struct CORE_EXPORT NativeValueTraits<IDLNullable<IDLUSVStringV2>>
}
};
+template <>
+struct CORE_EXPORT NativeValueTraits<IDLOptional<IDLUSVStringV2>>
+ : public NativeValueTraitsBase<IDLUSVStringV2> {
+ static decltype(auto) NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return bindings::NativeValueTraitsStringAdapter();
+ return NativeValueTraits<IDLUSVStringV2>::NativeValue(isolate, value,
+ exception_state);
+ }
+};
+
template <bindings::IDLStringConvMode mode>
struct NativeValueTraits<IDLStringStringContextTrustedHTMLBaseV2<mode>>
: public NativeValueTraitsBase<
@@ -586,6 +647,7 @@ struct CORE_EXPORT NativeValueTraits<DOMArrayBuffer>
v8::Local<v8::Value> value,
ExceptionState& exception_state);
};
+
template <>
struct CORE_EXPORT NativeValueTraits<IDLNullable<DOMArrayBuffer>>
: public NativeValueTraitsBase<DOMArrayBuffer*> {
@@ -613,6 +675,7 @@ struct NativeValueTraits<
v8::Local<v8::Value> value,
ExceptionState& exception_state);
};
+
template <typename T>
struct NativeValueTraits<
IDLNullable<NotShared<T>>,
@@ -642,6 +705,7 @@ struct NativeValueTraits<
v8::Local<v8::Value> value,
ExceptionState& exception_state);
};
+
template <typename T>
struct NativeValueTraits<
IDLNullable<MaybeShared<T>>,
@@ -673,6 +737,7 @@ struct NativeValueTraits<
v8::Local<v8::Value> value,
ExceptionState& exception_state);
};
+
template <typename T>
struct NativeValueTraits<
IDLNullable<T>,
@@ -756,6 +821,7 @@ struct CORE_EXPORT NativeValueTraits<IDLPromise>
value);
}
};
+
// IDLNullable<IDLPromise> must not be used.
template <>
struct NativeValueTraits<IDLNullable<IDLPromise>>;
@@ -888,6 +954,20 @@ struct NativeValueTraits<IDLSequence<T>>
}
};
+template <typename T>
+struct NativeValueTraits<IDLOptional<IDLSequence<T>>>
+ : public NativeValueTraitsBase<IDLSequence<T>> {
+ static typename NativeValueTraits<IDLSequence<T>>::ImplType NativeValue(
+ v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return {};
+ return NativeValueTraits<IDLSequence<T>>::NativeValue(isolate, value,
+ exception_state);
+ }
+};
+
// Record types
template <typename K, typename V>
struct NativeValueTraits<IDLRecord<K, V>>
@@ -1140,35 +1220,20 @@ struct NativeValueTraits<
}
};
+// We don't support nullable dictionary types for the time being since it's
+// quite confusing.
template <typename T>
struct NativeValueTraits<
IDLNullable<T>,
- typename std::enable_if_t<std::is_base_of<IDLDictionaryBase, T>::value>>
- : public NativeValueTraitsBase<IDLNullable<T>> {
- static T* NativeValue(v8::Isolate* isolate,
- v8::Local<v8::Value> value,
- ExceptionState& exception_state) {
- if (value->IsObject())
- return NativeValueTraits<T>::NativeValue(isolate, value, exception_state);
- if (value->IsNullOrUndefined())
- return nullptr;
- exception_state.ThrowTypeError("The given value is not an object.");
- return nullptr;
- }
+ typename std::enable_if_t<
+ std::is_base_of<bindings::DictionaryBase, T>::value>>;
- static T* ArgumentValue(v8::Isolate* isolate,
- int argument_index,
- v8::Local<v8::Value> value,
- ExceptionState& exception_state) {
- if (value->IsObject())
- return NativeValueTraits<T>::NativeValue(isolate, value, exception_state);
- if (value->IsNullOrUndefined())
- return nullptr;
- exception_state.ThrowTypeError(
- ExceptionMessages::ArgumentNotOfType(argument_index, "Object"));
- return nullptr;
- }
-};
+// Migration Adapters: Nullable dictionary types generated by the old bindings
+// generator.
+template <typename T>
+struct NativeValueTraits<
+ IDLNullable<T>,
+ typename std::enable_if_t<std::is_base_of<IDLDictionaryBase, T>::value>>;
// Enumeration types
template <typename T>
@@ -1253,6 +1318,18 @@ struct NativeValueTraits<
}
};
+template <typename T>
+struct NativeValueTraits<
+ T,
+ typename std::enable_if_t<std::is_base_of<bindings::UnionBase, T>::value>>
+ : public NativeValueTraitsBase<T*> {
+ static T* NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return T::Create(isolate, value, exception_state);
+ }
+};
+
// Migration Adapters: union types generated by the old bindings generator.
template <typename T>
struct NativeValueTraits<IDLUnionNotINT<T>> : public NativeValueTraitsBase<T> {
@@ -1318,6 +1395,44 @@ struct NativeValueTraits<IDLNullable<IDLUnionNotINT<T>>>
template <typename T>
struct NativeValueTraits<IDLNullable<IDLUnionINT<T>>>;
+template <typename T>
+struct NativeValueTraits<IDLOptional<IDLUnionNotINT<T>>>
+ : public NativeValueTraitsBase<T> {
+ static T NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return T();
+ return NativeValueTraits<IDLUnionNotINT<T>>::NativeValue(isolate, value,
+ exception_state);
+ }
+
+ static T ArgumentValue(v8::Isolate* isolate,
+ int argument_index,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return NativeValue(isolate, value, exception_state);
+ }
+};
+
+template <typename T>
+struct NativeValueTraits<IDLOptional<IDLUnionINT<T>>>
+ : public NativeValueTraitsBase<T> {
+ static T NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return NativeValueTraits<IDLUnionINT<T>>::NativeValue(isolate, value,
+ exception_state);
+ }
+
+ static T ArgumentValue(v8::Isolate* isolate,
+ int argument_index,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ return NativeValue(isolate, value, exception_state);
+ }
+};
+
// Nullable types
template <typename InnerType>
struct NativeValueTraits<
@@ -1347,10 +1462,62 @@ struct NativeValueTraits<
value, exception_state);
}
};
+
// IDLNullable<IDLNullable<T>> must not be used.
template <typename T>
struct NativeValueTraits<IDLNullable<IDLNullable<T>>>;
+// Optional types
+template <typename T>
+struct NativeValueTraits<IDLOptional<T>,
+ typename std::enable_if_t<std::is_arithmetic<
+ typename NativeValueTraits<T>::ImplType>::value>>
+ : public NativeValueTraitsBase<typename NativeValueTraits<T>::ImplType> {
+ using ImplType = typename NativeValueTraits<T>::ImplType;
+
+ static ImplType NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ // Just let ES undefined to be converted into 0.
+ return NativeValueTraits<T>::NativeValue(isolate, value, exception_state);
+ }
+
+ static ImplType ArgumentValue(v8::Isolate* isolate,
+ int argument_index,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ // Just let ES undefined to be converted into 0.
+ return NativeValueTraits<T>::ArgumentValue(isolate, argument_index, value,
+ exception_state);
+ }
+};
+
+template <typename T>
+struct NativeValueTraits<IDLOptional<T>,
+ typename std::enable_if_t<std::is_pointer<
+ typename NativeValueTraits<T>::ImplType>::value>>
+ : public NativeValueTraitsBase<typename NativeValueTraits<T>::ImplType> {
+ using ImplType = typename NativeValueTraits<T>::ImplType;
+
+ static ImplType NativeValue(v8::Isolate* isolate,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return nullptr;
+ return NativeValueTraits<T>::NativeValue(isolate, value, exception_state);
+ }
+
+ static ImplType ArgumentValue(v8::Isolate* isolate,
+ int argument_index,
+ v8::Local<v8::Value> value,
+ ExceptionState& exception_state) {
+ if (value->IsUndefined())
+ return nullptr;
+ return NativeValueTraits<T>::ArgumentValue(isolate, argument_index, value,
+ exception_state);
+ }
+};
+
// Date
template <>
struct CORE_EXPORT NativeValueTraits<IDLDate>
@@ -1420,6 +1587,7 @@ struct CORE_EXPORT NativeValueTraits<XPathNSResolver>
v8::Local<v8::Value> value,
ExceptionState& exception_state);
};
+
template <>
struct CORE_EXPORT NativeValueTraits<IDLNullable<XPathNSResolver>>
: public NativeValueTraitsBase<IDLNullable<XPathNSResolver>> {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc b/chromium/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc
index 88a639c6697..7728ca77e8f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h"
#include <memory>
+#include <utility>
#include "base/memory/ptr_util.h"
#include "third_party/blink/public/platform/platform.h"
@@ -214,7 +215,7 @@ void RejectedPromises::HandlerAdded(v8::PromiseRejectMessage data) {
context->GetTaskRunner(TaskType::kDOMManipulation)
->PostTask(FROM_HERE, WTF::Bind(&RejectedPromises::RevokeNow,
scoped_refptr<RejectedPromises>(this),
- WTF::Passed(std::move(message))));
+ std::move(message)));
reported_as_errors_.EraseAt(i);
return;
}
@@ -244,7 +245,7 @@ void RejectedPromises::ProcessQueue() {
kv.key->GetTaskRunner(blink::TaskType::kDOMManipulation)
->PostTask(FROM_HERE, WTF::Bind(&RejectedPromises::ProcessQueueNow,
scoped_refptr<RejectedPromises>(this),
- WTF::Passed(std::move(kv.value))));
+ std::move(kv.value)));
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
index ab2c20f80a0..a4fa41cf291 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
@@ -62,8 +62,6 @@ void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
if (lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged) {
DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged);
- if (next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged)
- global_proxy_.SetPhantom();
lifecycle_ = next_status;
return;
}
@@ -74,6 +72,7 @@ void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
if ((next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
next_status == Lifecycle::kGlobalObjectIsDetached) &&
!global_proxy_.IsEmpty()) {
+ v8::HandleScope handle_scope(GetIsolate());
global_proxy_.Get().SetWrapperClassId(0);
V8DOMWrapper::ClearNativeInfo(GetIsolate(),
global_proxy_.NewLocal(GetIsolate()));
@@ -82,12 +81,6 @@ void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
#endif
}
- if (next_status == Lifecycle::kFrameIsDetached) {
- // The context's frame is detached from the DOM, so there shouldn't be a
- // strong reference to the context.
- global_proxy_.SetPhantom();
- }
-
DCHECK_EQ(lifecycle_, Lifecycle::kContextIsInitialized);
lifecycle_ = next_status;
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h
index 0841c421bef..22596bda400 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h
@@ -40,14 +40,12 @@
namespace blink {
// Subclass of WindowProxy that only handles RemoteFrame.
-// TODO(dcheng): This class temporarily contains code duplicated from
-// LocalWindowProxy. It will be removed once the global proxy is instantiated
-// using v8::Context::NewRemoteContext().
class RemoteWindowProxy final : public WindowProxy {
public:
RemoteWindowProxy(v8::Isolate*, RemoteFrame&, scoped_refptr<DOMWrapperWorld>);
private:
+ // WindowProxy overrides:
void Initialize() override;
void DisposeContext(Lifecycle next_status, FrameReuseStatus) override;
@@ -62,6 +60,11 @@ class RemoteWindowProxy final : public WindowProxy {
void SetupWindowPrototypeChain();
};
+template <>
+struct DowncastTraits<RemoteWindowProxy> {
+ static bool AllowFrom(const WindowProxy& proxy) { return !proxy.IsLocal(); }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_REMOTE_WINDOW_PROXY_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
index b54f028e092..40591a51f7d 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/scheduled_action.cc
@@ -31,19 +31,16 @@
#include "third_party/blink/renderer/bindings/core/v8/scheduled_action.h"
#include "third_party/blink/renderer/bindings/core/v8/binding_security.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.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/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/core/script/classic_script.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/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -115,40 +112,45 @@ void ScheduledAction::Execute(ExecutionContext* context) {
DVLOG(1) << "ScheduledAction::execute " << this << ": context is empty";
return;
}
- // ExecutionContext::CanExecuteScripts() relies on the current context to
- // determine if it is allowed. Enter the scope here.
- ScriptState::Scope scope(script_state_->Get());
- if (!context->CanExecuteScripts(kAboutToExecuteScript)) {
- DVLOG(1) << "ScheduledAction::execute " << this
- << ": window can not execute scripts";
- return;
- }
- // https://html.spec.whatwg.org/C/#timer-initialisation-steps
- if (function_) {
- DVLOG(1) << "ScheduledAction::execute " << this << ": have function";
- function_->InvokeAndReportException(context->ToScriptWrappable(),
- arguments_);
- return;
+ {
+ // ExecutionContext::CanExecuteScripts() relies on the current context to
+ // determine if it is allowed. Enter the scope here.
+ // TODO(crbug.com/1151165): Consider merging CanExecuteScripts() calls,
+ // because once crbug.com/1111134 is done, CanExecuteScripts() will be
+ // always called below inside
+ // - InvokeAndReportException() => V8Function::Invoke() =>
+ // IsCallbackFunctionRunnable() and
+ // - V8ScriptRunner::CompileAndRunScript().
+ ScriptState::Scope scope(script_state_->Get());
+ if (!context->CanExecuteScripts(kAboutToExecuteScript)) {
+ DVLOG(1) << "ScheduledAction::execute " << this
+ << ": window can not execute scripts";
+ return;
+ }
+
+ // https://html.spec.whatwg.org/C/#timer-initialisation-steps
+ if (function_) {
+ DVLOG(1) << "ScheduledAction::execute " << this << ": have function";
+ function_->InvokeAndReportException(context->ToScriptWrappable(),
+ arguments_);
+ return;
+ }
+
+ // We exit the scope here, because we enter v8::Context during the main
+ // evaluation below.
}
// We use |SanitizeScriptErrors::kDoNotSanitize| because muted errors flag is
// not set in https://html.spec.whatwg.org/C/#timer-initialisation-steps
+ // TODO(crbug.com/1133238): Plumb base URL etc. from the initializing script.
DVLOG(1) << "ScheduledAction::execute " << this << ": executing from source";
- if (LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(context)) {
- window->GetScriptController().ExecuteScriptAndReturnValue(
- script_state_->GetContext(),
- ScriptSourceCode(code_,
- ScriptSourceLocationType::kEvalForScheduledAction),
- KURL(), SanitizeScriptErrors::kDoNotSanitize);
- } else {
- WorkerGlobalScope* worker = To<WorkerGlobalScope>(context);
- DCHECK(worker->GetThread()->IsCurrentThread());
- worker->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode(code_,
- ScriptSourceLocationType::kEvalForScheduledAction),
- SanitizeScriptErrors::kDoNotSanitize);
- }
+ v8::HandleScope scope(script_state_->GetIsolate());
+ ClassicScript* script = MakeGarbageCollected<ClassicScript>(
+ ScriptSourceCode(code_,
+ ScriptSourceLocationType::kEvalForScheduledAction),
+ KURL(), ScriptFetchOptions(), SanitizeScriptErrors::kDoNotSanitize);
+ script->RunScriptOnScriptStateAndReturnValue(script_state_->Get());
}
void ScheduledAction::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
index b572c7f7b9a..97c22f59811 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.cc
@@ -36,9 +36,6 @@
#include <utility>
#include "base/callback_helpers.h"
-#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
-#include "third_party/blink/public/web/web_settings.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.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_gc_controller.h"
@@ -51,7 +48,6 @@
#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/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
@@ -83,31 +79,6 @@ void ScriptController::UpdateSecurityOrigin(
window_proxy_manager_->UpdateSecurityOrigin(security_origin);
}
-// TODO(crbug/1129743): Use ScriptEvaluationResult instead of
-// v8::Local<v8::Value> as the return type.
-v8::Local<v8::Value> ScriptController::ExecuteScriptAndReturnValue(
- v8::Local<v8::Context> context,
- const ScriptSourceCode& source,
- const KURL& base_url,
- SanitizeScriptErrors sanitize_script_errors,
- const ScriptFetchOptions& fetch_options) {
- mojom::blink::V8CacheOptions v8_cache_options =
- mojom::blink::V8CacheOptions::kDefault;
- if (const Settings* settings = window_->GetFrame()->GetSettings())
- v8_cache_options = settings->GetV8CacheOptions();
-
- ScriptEvaluationResult result = V8ScriptRunner::CompileAndRunScript(
- GetIsolate(), ScriptState::From(context), window_.Get(), source,
- base_url, sanitize_script_errors, fetch_options,
- std::move(v8_cache_options),
- V8ScriptRunner::RethrowErrorsOption::DoNotRethrow());
-
- if (result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess)
- return result.GetSuccessValue();
-
- return v8::Local<v8::Value>();
-}
-
TextPosition ScriptController::EventHandlerPosition() const {
ScriptableDocumentParser* parser =
window_->document()->GetScriptableDocumentParser();
@@ -185,7 +156,7 @@ v8::ExtensionConfiguration ScriptController::ExtensionsFor(
}
void ScriptController::UpdateDocument() {
- window_proxy_manager_->MainWorldProxyMaybeUninitialized()->UpdateDocument();
+ window_proxy_manager_->UpdateDocument();
}
void ScriptController::ExecuteJavaScriptURL(
@@ -264,12 +235,12 @@ void ScriptController::ExecuteJavaScriptURL(
UseCounter::Count(window_.Get(),
WebFeature::kReplaceDocumentViaJavaScriptURL);
- auto params = std::make_unique<WebNavigationParams>();
- params->url = window_->Url();
- if (auto* owner = window_->GetFrame()->Owner())
- params->frame_policy = owner->GetFramePolicy();
- params->origin_to_commit = window_->GetSecurityOrigin();
+ auto* previous_document_loader =
+ window_->GetFrame()->Loader().GetDocumentLoader();
+ DCHECK(previous_document_loader);
+ auto params =
+ previous_document_loader->CreateWebNavigationParamsToCloneDocument();
String result = ToCoreString(v8::Local<v8::String>::Cast(v8_result));
WebNavigationParams::FillStaticResponse(params.get(), "text/html", "UTF-8",
StringUTF8Adaptor(result));
@@ -277,54 +248,31 @@ void ScriptController::ExecuteJavaScriptURL(
CommitReason::kJavascriptUrl);
}
-v8::Local<v8::Value> ScriptController::EvaluateScriptInMainWorld(
- const ScriptSourceCode& source_code,
- const KURL& base_url,
- SanitizeScriptErrors sanitize_script_errors,
- const ScriptFetchOptions& fetch_options,
- ExecuteScriptPolicy policy) {
- if (!CanExecuteScript(policy)) {
- return v8::Local<v8::Value>();
- }
-
- // |context| should be initialized already due to the
- // MainWorldProxy() call.
- v8::Local<v8::Context> context =
- window_proxy_manager_->MainWorldProxy()->ContextIfInitialized();
- v8::Context::Scope scope(context);
- v8::EscapableHandleScope handle_scope(GetIsolate());
-
- v8::Local<v8::Value> object = ExecuteScriptAndReturnValue(
- context, source_code, base_url, sanitize_script_errors, fetch_options);
-
- if (object.IsEmpty())
- return v8::Local<v8::Value>();
-
- return handle_scope.Escape(object);
-}
-
v8::Local<v8::Value> ScriptController::EvaluateMethodInMainWorld(
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
- v8::Local<v8::Value> argv[],
- ExecuteScriptPolicy policy) {
- if (!CanExecuteScript(policy)) {
+ v8::Local<v8::Value> argv[]) {
+ if (!CanExecuteScript(
+ ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled)) {
+ return v8::Local<v8::Value>();
+ }
+
+ // |script_state->GetContext()| should be initialized already due to the
+ // WindowProxy() call inside ToScriptStateForMainWorld().
+ ScriptState* script_state = ToScriptStateForMainWorld(window_->GetFrame());
+ if (!script_state) {
return v8::Local<v8::Value>();
}
+ DCHECK_EQ(script_state->GetIsolate(), GetIsolate());
- // |context| should be initialized already due to the
- // MainWorldProxy() call.
- v8::Local<v8::Context> context =
- window_proxy_manager_->MainWorldProxy()->ContextIfInitialized();
- v8::Context::Scope scope(context);
+ v8::Context::Scope scope(script_state->GetContext());
v8::EscapableHandleScope handle_scope(GetIsolate());
v8::TryCatch try_catch(GetIsolate());
try_catch.SetVerbose(true);
- ExecutionContext* executionContext =
- ExecutionContext::From(ScriptState::From(context));
+ ExecutionContext* executionContext = ExecutionContext::From(script_state);
v8::MaybeLocal<v8::Value> resultObj = V8ScriptRunner::CallFunction(
function, executionContext, receiver, argc,
@@ -337,7 +285,7 @@ v8::Local<v8::Value> ScriptController::EvaluateMethodInMainWorld(
}
bool ScriptController::CanExecuteScript(ExecuteScriptPolicy policy) {
- if (policy == kDoNotExecuteScriptWhenScriptsDisabled &&
+ if (policy == ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled &&
!window_->CanExecuteScripts(kAboutToExecuteScript))
return false;
@@ -347,29 +295,6 @@ bool ScriptController::CanExecuteScript(ExecuteScriptPolicy policy) {
return true;
}
-v8::Local<v8::Value> ScriptController::ExecuteScriptInIsolatedWorld(
- int32_t world_id,
- const ScriptSourceCode& source,
- const KURL& base_url,
- SanitizeScriptErrors sanitize_script_errors) {
- DCHECK_GT(world_id, 0);
-
- scoped_refptr<DOMWrapperWorld> world =
- DOMWrapperWorld::EnsureIsolatedWorld(GetIsolate(), world_id);
- LocalWindowProxy* isolated_world_window_proxy = WindowProxy(*world);
- // TODO(dcheng): Context must always be initialized here, due to the call to
- // windowProxy() on the previous line. Add a helper which makes that obvious?
- v8::Local<v8::Context> context =
- isolated_world_window_proxy->ContextIfInitialized();
- v8::Context::Scope scope(context);
-
- v8::Local<v8::Value> evaluation_result = ExecuteScriptAndReturnValue(
- context, source, base_url, sanitize_script_errors);
- if (!evaluation_result.IsEmpty())
- return evaluation_result;
- return v8::Local<v8::Value>::New(GetIsolate(), v8::Undefined(GetIsolate()));
-}
-
scoped_refptr<DOMWrapperWorld>
ScriptController::CreateNewInspectorIsolatedWorld(const String& world_name) {
scoped_refptr<DOMWrapperWorld> world = DOMWrapperWorld::Create(
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
index 992b5ec1227..d81f02ca6e6 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_controller.h
@@ -34,14 +34,10 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
#include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
-#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8/include/v8.h"
@@ -49,23 +45,18 @@
namespace blink {
class DOMWrapperWorld;
-class ExecutionContext;
class KURL;
class LocalDOMWindow;
-class ScriptSourceCode;
class SecurityOrigin;
+enum class ExecuteScriptPolicy;
+
// This class exposes methods to run script in a frame (in the main world and
// in isolated worlds). An instance can be obtained by using
// LocalDOMWindow::GetScriptController().
class CORE_EXPORT ScriptController final
: public GarbageCollected<ScriptController> {
public:
- enum ExecuteScriptPolicy {
- kExecuteScriptWhenScriptsDisabled,
- kDoNotExecuteScriptWhenScriptsDisabled
- };
-
ScriptController(LocalDOMWindow& window,
LocalWindowProxyManager& window_proxy_manager)
: window_(&window), window_proxy_manager_(&window_proxy_manager) {}
@@ -77,39 +68,11 @@ class CORE_EXPORT ScriptController final
return window_proxy_manager_->WindowProxy(world);
}
- v8::Local<v8::Value> ExecuteScriptAndReturnValue(
- v8::Local<v8::Context>,
- const ScriptSourceCode&,
- const KURL& base_url,
- SanitizeScriptErrors,
- const ScriptFetchOptions& = ScriptFetchOptions());
-
v8::Local<v8::Value> EvaluateMethodInMainWorld(
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
- v8::Local<v8::Value> argv[],
- ScriptController::ExecuteScriptPolicy = ScriptController::
- ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled);
-
- // Evaluate JavaScript in the main world.
- v8::Local<v8::Value> EvaluateScriptInMainWorld(const ScriptSourceCode&,
- const KURL& base_url,
- SanitizeScriptErrors,
- const ScriptFetchOptions&,
- ExecuteScriptPolicy);
-
- // Executes JavaScript in an isolated world. The script gets its own global
- // scope, its own prototypes for intrinsic JavaScript objects (String, Array,
- // and so-on), and its own wrappers for all DOM nodes and DOM constructors.
- //
- // If an isolated world with the specified ID already exists, it is reused.
- // Otherwise, a new world is created.
- v8::Local<v8::Value> ExecuteScriptInIsolatedWorld(
- int32_t world_id,
- const ScriptSourceCode&,
- const KURL& base_url,
- SanitizeScriptErrors sanitize_script_errors);
+ v8::Local<v8::Value> argv[]);
// Executes a javascript url in the main world. |world_for_csp| denotes the
// javascript world in which this navigation initiated and which should be
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
index b9241cbee94..51a42db62c8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
@@ -81,12 +81,6 @@ ScriptEvaluationResult ScriptEvaluationResult::FromModuleAborted() {
ResultType::kAborted, {});
}
-ScriptEvaluationResult& ScriptEvaluationResult::Escape(
- ScriptState::EscapableScope* scope) {
- value_ = scope->Escape(value_);
- return *this;
-}
-
v8::Local<v8::Value> ScriptEvaluationResult::GetSuccessValue() const {
DCHECK_EQ(result_type_, ResultType::kSuccess);
DCHECK(!value_.IsEmpty());
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
index f31b03eba76..9bc596456e8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
@@ -96,8 +96,6 @@ class CORE_EXPORT ScriptEvaluationResult final {
v8::Local<v8::Value> exception);
static ScriptEvaluationResult FromModuleAborted();
- ScriptEvaluationResult& Escape(ScriptState::EscapableScope* scope);
-
ResultType GetResultType() const { return result_type_; }
// Can be called only when GetResultType() == kSuccess.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
index 5d84c120ac4..5eef41c8c24 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.cc
@@ -9,6 +9,28 @@
namespace blink {
+namespace {
+
+class CallableHolder final : public CustomWrappableAdapter {
+ public:
+ explicit CallableHolder(NewScriptFunction::Callable* callable)
+ : callable_(callable) {}
+ const char* NameInHeapSnapshot() const final {
+ return "ScriptFunction::Callable";
+ }
+ NewScriptFunction::Callable* GetCallable() { return callable_; }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(callable_);
+ CustomWrappableAdapter::Trace(visitor);
+ }
+
+ private:
+ const Member<NewScriptFunction::Callable> callable_;
+};
+
+} // namespace
+
void ScriptFunction::Trace(Visitor* visitor) const {
visitor->Trace(script_state_);
CustomWrappableAdapter::Trace(visitor);
@@ -48,4 +70,44 @@ void ScriptFunction::CallCallback(
script_function->CallRaw(args);
}
+ScriptValue NewScriptFunction::Callable::Call(ScriptState*, ScriptValue) {
+ NOTREACHED();
+ return ScriptValue();
+}
+
+void NewScriptFunction::Callable::CallRaw(
+ ScriptState* script_state,
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ ScriptValue result =
+ Call(script_state, ScriptValue(script_state->GetIsolate(), args[0]));
+ V8SetReturnValue(args, result.V8Value());
+}
+
+v8::Local<v8::Function> NewScriptFunction::BindToV8Function(
+ ScriptState* script_state,
+ Callable* callable) {
+ DCHECK(callable);
+ v8::Local<v8::Object> wrapper =
+ MakeGarbageCollected<CallableHolder>(callable)
+ ->CreateAndInitializeWrapper(script_state);
+
+ // The wrapper is held alive by the CallHandlerInfo internally in V8 as long
+ // as the function is alive.
+ return v8::Function::New(script_state->GetContext(), CallCallback, wrapper,
+ callable->Length(), v8::ConstructorBehavior::kThrow)
+ .ToLocalChecked();
+}
+
+void NewScriptFunction::CallCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(args.GetIsolate(),
+ "Blink_CallCallback");
+ v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(args.Data());
+ auto* holder = static_cast<CallableHolder*>(ToCustomWrappable(data));
+ ScriptState* script_state =
+ ScriptState::From(args.GetIsolate()->GetCurrentContext());
+
+ holder->GetCallable()->CallRaw(script_state, args);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
index 2e80f0b9f84..595ee8f8499 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_function.h
@@ -34,22 +34,14 @@
#include "third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "v8/include/v8.h"
namespace blink {
-// A common way of using ScriptFunction is as follows:
-//
-// class DerivedFunction : public ScriptFunction {
-// // This returns a V8 function which the DerivedFunction is bound to.
-// // The DerivedFunction is destroyed when the V8 function is
-// // garbage-collected.
-// static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
-// DerivedFunction* self = new DerivedFunction(script_state);
-// return self->BindToV8Function();
-// }
-// };
+// DEPRECATED: Use NewScriptFunction.
class CORE_EXPORT ScriptFunction : public CustomWrappableAdapter {
public:
~ScriptFunction() override = default;
@@ -86,6 +78,68 @@ class CORE_EXPORT ScriptFunction : public CustomWrappableAdapter {
#endif
};
+// A `NewScriptFunction` represents a function that can be called from scripts.
+// You can define a subclass of `Callable` and put arbitrary logic by
+// overriding `Call` or `CallRaw` methods.
+class CORE_EXPORT NewScriptFunction final
+ : public GarbageCollected<NewScriptFunction> {
+ public:
+ class CORE_EXPORT Callable : public GarbageCollected<Callable> {
+ public:
+ virtual ~Callable() = default;
+
+ // Subclasses should implement one of Call() or CallRaw(). Most will
+ // implement Call().
+ virtual ScriptValue Call(ScriptState*, ScriptValue);
+
+ // To support more than one argument, or for low-level access to the V8 API,
+ // implement CallRaw(). The default implementation delegates to Call().
+ virtual void CallRaw(ScriptState*,
+ const v8::FunctionCallbackInfo<v8::Value>&);
+
+ // The length of the aosociated JavaScript function. Implement this only
+ // when the function is exposed to scripts.
+ virtual int Length() const { return 0; }
+
+ virtual void Trace(Visitor* visitor) const {}
+ };
+
+ // Represents a function that returns a value given to the constructor.
+ class Constant final : public Callable {
+ public:
+ explicit Constant(ScriptValue value) : value_(value) {}
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(value_);
+ Callable::Trace(visitor);
+ }
+ ScriptValue Call(ScriptState*, ScriptValue) override { return value_; }
+
+ private:
+ const ScriptValue value_;
+ };
+
+ NewScriptFunction(ScriptState* script_state, Callable* callable)
+ : script_state_(script_state),
+ function_(script_state->GetIsolate(),
+ BindToV8Function(script_state, callable)) {}
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(script_state_);
+ visitor->Trace(function_);
+ }
+
+ v8::Local<v8::Function> V8Function() {
+ return function_.NewLocal(script_state_->GetIsolate());
+ }
+
+ private:
+ static v8::Local<v8::Function> BindToV8Function(ScriptState*, Callable*);
+ static void CallCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+
+ Member<ScriptState> script_state_;
+ TraceWrapperV8Reference<v8::Function> function_;
+};
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
index 4bc39c11009..3c98f9018da 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.cc
@@ -266,6 +266,13 @@ ScriptPromise ScriptPromise::Then(v8::Local<v8::Function> on_fulfilled,
return ScriptPromise(script_state_, result_promise);
}
+ScriptPromise ScriptPromise::Then(NewScriptFunction* on_fulfilled,
+ NewScriptFunction* on_rejected) {
+ const v8::Local<v8::Function> empty;
+ return Then(on_fulfilled ? on_fulfilled->V8Function() : empty,
+ on_rejected ? on_rejected->V8Function() : empty);
+}
+
ScriptPromise ScriptPromise::CastUndefined(ScriptState* script_state) {
return ScriptPromise::Cast(script_state,
v8::Undefined(script_state->GetIsolate()));
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
index 37385c2267a..3b7d6d5cf05 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise.h
@@ -43,6 +43,7 @@ namespace blink {
class DOMException;
class ExceptionState;
+class NewScriptFunction;
// ScriptPromise is the class for representing Promise values in C++ world.
// ScriptPromise holds a Promise.
@@ -69,6 +70,8 @@ class CORE_EXPORT ScriptPromise final {
ScriptPromise Then(v8::Local<v8::Function> on_fulfilled,
v8::Local<v8::Function> on_rejected = {});
+ ScriptPromise Then(NewScriptFunction* on_fulfilled,
+ NewScriptFunction* on_rejected = nullptr);
bool IsObject() const { return promise_.IsObject(); }
@@ -78,9 +81,14 @@ class CORE_EXPORT ScriptPromise final {
return promise_.IsUndefined() || promise_.IsNull();
}
- ScriptValue GetScriptValue() const { return promise_; }
+ ScriptValue AsScriptValue() const { return promise_; }
v8::Local<v8::Value> V8Value() const { return promise_.V8Value(); }
+ v8::Local<v8::Promise> V8Promise() const {
+ // This is safe because `promise_` always stores a promise value as long
+ // as it's non-empty.
+ return V8Value().As<v8::Promise>();
+ }
v8::Isolate* GetIsolate() const { return script_state_->GetIsolate(); }
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
index b4efa922faa..4d3ba4bb7d6 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
@@ -510,7 +510,7 @@ TEST_F(ScriptPromisePropertyGarbageCollectedTest, MarkAsHandled) {
GarbageCollectedScriptWrappable* reason =
MakeGarbageCollected<GarbageCollectedScriptWrappable>("reason");
GetProperty()->Reject(reason);
- EXPECT_FALSE(promise.V8Value().As<v8::Promise>()->HasHandler());
+ EXPECT_FALSE(promise.V8Promise()->HasHandler());
}
GetProperty()->Reset();
@@ -524,7 +524,7 @@ TEST_F(ScriptPromisePropertyGarbageCollectedTest, MarkAsHandled) {
GarbageCollectedScriptWrappable* reason =
MakeGarbageCollected<GarbageCollectedScriptWrappable>("reason");
GetProperty()->Reject(reason);
- EXPECT_TRUE(promise.V8Value().As<v8::Promise>()->HasHandler());
+ EXPECT_TRUE(promise.V8Promise()->HasHandler());
}
GetProperty()->Reset();
@@ -538,7 +538,7 @@ TEST_F(ScriptPromisePropertyGarbageCollectedTest, MarkAsHandled) {
GarbageCollectedScriptWrappable* reason =
MakeGarbageCollected<GarbageCollectedScriptWrappable>("reason");
GetProperty()->Reject(reason);
- EXPECT_TRUE(promise.V8Value().As<v8::Promise>()->HasHandler());
+ EXPECT_TRUE(promise.V8Promise()->HasHandler());
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
index 13d4fea03a3..69231d62d79 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h
@@ -42,7 +42,7 @@ class CORE_EXPORT ScriptPromiseResolver
public:
explicit ScriptPromiseResolver(ScriptState*);
- virtual ~ScriptPromiseResolver();
+ ~ScriptPromiseResolver() override;
void Dispose();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
index 0e4aa4195a8..ef38dc01fc0 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_test.cc
@@ -48,6 +48,12 @@ namespace {
typedef ScriptPromise::InternalResolver Resolver;
+template <typename T, typename... Args>
+NewScriptFunction* CreateFunction(ScriptState* script_state, Args&&... args) {
+ return MakeGarbageCollected<NewScriptFunction>(
+ script_state, MakeGarbageCollected<T>(std::forward<Args>(args)...));
+}
+
class FunctionForScriptPromiseTest : public ScriptFunction {
public:
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
@@ -88,6 +94,49 @@ class ThrowingFunction : public ScriptFunction {
}
};
+class ThrowingCallable : public NewScriptFunction::Callable {
+ public:
+ private:
+ ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
+ v8::Isolate* isolate = script_state->GetIsolate();
+ isolate->ThrowException(v8::Undefined(isolate));
+ return ScriptValue();
+ }
+};
+
+class NotReached : public NewScriptFunction::Callable {
+ ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
+ ADD_FAILURE() << "This function should not be called.";
+ return ScriptValue();
+ }
+};
+
+class ScriptValueHolder final : public GarbageCollected<ScriptValueHolder> {
+ public:
+ const ScriptValue& Value() const { return value_; }
+ void SetValue(const ScriptValue& value) { value_ = value; }
+ void Trace(Visitor* visitor) const { visitor->Trace(value_); }
+
+ private:
+ ScriptValue value_;
+};
+
+class CapturingCallable final : public NewScriptFunction::Callable {
+ public:
+ explicit CapturingCallable(ScriptValueHolder* holder) : holder_(holder) {}
+ ScriptValue Call(ScriptState*, ScriptValue value) override {
+ holder_->SetValue(value);
+ return value;
+ }
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(holder_);
+ Callable::Trace(visitor);
+ }
+
+ private:
+ Member<ScriptValueHolder> holder_;
+};
+
String ToString(v8::Local<v8::Context> context, const ScriptValue& value) {
return ToCoreString(value.V8Value()->ToString(context).ToLocalChecked());
}
@@ -133,6 +182,28 @@ TEST(ScriptPromiseTest, ThenResolve) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
+TEST(ScriptPromiseTest, ThenResolveScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_fulfilled = MakeGarbageCollected<ScriptValueHolder>();
+ promise.Then(
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_fulfilled),
+ CreateFunction<NotReached>(scope.GetScriptState()));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_fulfilled->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Resolve(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_fulfilled->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_EQ("hello", ToString(scope.GetContext(), on_fulfilled->Value()));
+}
+
TEST(ScriptPromiseTest, ResolveThen) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
@@ -154,6 +225,24 @@ TEST(ScriptPromiseTest, ResolveThen) {
EXPECT_TRUE(on_rejected.IsEmpty());
}
+TEST(ScriptPromiseTest, ResolveThenScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_fulfilled = MakeGarbageCollected<ScriptValueHolder>();
+ resolver.Resolve(V8String(scope.GetIsolate(), "hello"));
+ promise.Then(
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_fulfilled),
+ CreateFunction<NotReached>(scope.GetScriptState()));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_fulfilled->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_EQ("hello", ToString(scope.GetContext(), on_fulfilled->Value()));
+}
+
TEST(ScriptPromiseTest, ThenReject) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
@@ -180,6 +269,28 @@ TEST(ScriptPromiseTest, ThenReject) {
EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected));
}
+TEST(ScriptPromiseTest, ThenRejectScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_rejected = MakeGarbageCollected<ScriptValueHolder>();
+ promise.Then(
+ CreateFunction<NotReached>(scope.GetScriptState()),
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_rejected));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Reject(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected->Value()));
+}
+
TEST(ScriptPromiseTest, ThrowingOnFulfilled) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
@@ -214,6 +325,32 @@ TEST(ScriptPromiseTest, ThrowingOnFulfilled) {
EXPECT_FALSE(on_rejected2.IsEmpty());
}
+TEST(ScriptPromiseTest, ThrowingOnFulfilledScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_rejected = MakeGarbageCollected<ScriptValueHolder>();
+
+ promise =
+ promise.Then(CreateFunction<ThrowingCallable>(scope.GetScriptState()),
+ CreateFunction<NotReached>(scope.GetScriptState()));
+ promise.Then(
+ CreateFunction<NotReached>(scope.GetScriptState()),
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_rejected));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Resolve(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_FALSE(on_rejected->Value().IsEmpty());
+}
+
TEST(ScriptPromiseTest, ThrowingOnRejected) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
@@ -248,6 +385,32 @@ TEST(ScriptPromiseTest, ThrowingOnRejected) {
EXPECT_FALSE(on_rejected2.IsEmpty());
}
+TEST(ScriptPromiseTest, ThrowingOnRejectedScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_rejected = MakeGarbageCollected<ScriptValueHolder>();
+
+ promise =
+ promise.Then(CreateFunction<NotReached>(scope.GetScriptState()),
+ CreateFunction<ThrowingCallable>(scope.GetScriptState()));
+ promise.Then(
+ CreateFunction<NotReached>(scope.GetScriptState()),
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_rejected));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ resolver.Reject(V8String(scope.GetIsolate(), "hello"));
+
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_FALSE(on_rejected->Value().IsEmpty());
+}
+
TEST(ScriptPromiseTest, RejectThen) {
V8TestingScope scope;
Resolver resolver(scope.GetScriptState());
@@ -269,6 +432,24 @@ TEST(ScriptPromiseTest, RejectThen) {
EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected));
}
+TEST(ScriptPromiseTest, RejectThenScriptFunction) {
+ V8TestingScope scope;
+ Resolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ auto* const on_rejected = MakeGarbageCollected<ScriptValueHolder>();
+ resolver.Reject(V8String(scope.GetIsolate(), "hello"));
+ promise.Then(
+ CreateFunction<NotReached>(scope.GetScriptState()),
+ CreateFunction<CapturingCallable>(scope.GetScriptState(), on_rejected));
+
+ ASSERT_FALSE(promise.IsEmpty());
+ EXPECT_TRUE(on_rejected->Value().IsEmpty());
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ EXPECT_EQ("hello", ToString(scope.GetContext(), on_rejected->Value()));
+}
+
TEST(ScriptPromiseTest, CastPromise) {
V8TestingScope scope;
ScriptPromise promise = Resolver(scope.GetScriptState()).Promise();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.cc
index 41600d39f94..b7e053a18db 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.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/visitor.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "v8/include/v8.h"
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.h
index ee5315a0ae8..8419792d413 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_promise_tester.h
@@ -7,13 +7,13 @@
#include "base/memory/weak_ptr.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
class ScriptState;
class ScriptPromise;
-class Visitor;
// Utility for writing unit tests involving promises.
// Typical usage:
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.cc
index dc0523f9f09..23fe9bbb3f2 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/bindings/string_resource.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
namespace blink {
@@ -70,9 +71,10 @@ ScriptRegexp::ScriptRegexp(const String& pattern,
ToCoreStringWithUndefinedOrNullCheck(try_catch.Message()->Get());
}
-int ScriptRegexp::Match(const String& string,
+int ScriptRegexp::Match(StringView string,
int start_from,
- int* match_length) const {
+ int* match_length,
+ WTF::Vector<String>* group_list) const {
if (match_length)
*match_length = 0;
@@ -94,7 +96,7 @@ int ScriptRegexp::Match(const String& string,
v8::Local<v8::RegExp> regex = regex_.NewLocal(isolate);
v8::Local<v8::String> subject =
- V8String(isolate, string.Substring(start_from));
+ V8String(isolate, StringView(string, start_from));
v8::Local<v8::Value> return_value;
if (!regex->Exec(context, subject).ToLocal(&return_value))
return -1;
@@ -122,7 +124,26 @@ int ScriptRegexp::Match(const String& string,
*match_length = match.As<v8::String>()->Length();
}
+ if (group_list) {
+ DCHECK(group_list->IsEmpty());
+ for (uint32_t i = 1; i < result->Length(); ++i) {
+ v8::Local<v8::Value> group;
+ if (!result->Get(context, i).ToLocal(&group))
+ return -1;
+ String group_string;
+ if (group->IsString()) {
+ group_string =
+ ToBlinkString<String>(group.As<v8::String>(), kExternalize);
+ }
+ group_list->push_back(group_string);
+ }
+ }
+
return match_offset.As<v8::Int32>()->Value() + start_from;
}
+void ScriptRegexp::Trace(Visitor* visitor) const {
+ visitor->Trace(regex_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.h
index 58df59bfb3f..315aef9ac2a 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_regexp.h
@@ -29,7 +29,8 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "v8/include/v8.h"
@@ -37,9 +38,7 @@ namespace blink {
enum MultilineMode { kMultilineDisabled, kMultilineEnabled };
-class CORE_EXPORT ScriptRegexp {
- USING_FAST_MALLOC(ScriptRegexp);
-
+class CORE_EXPORT ScriptRegexp final : public GarbageCollected<ScriptRegexp> {
public:
enum CharacterMode {
BMP, // NOLINT
@@ -53,16 +52,26 @@ class CORE_EXPORT ScriptRegexp {
MultilineMode = kMultilineDisabled,
CharacterMode = BMP);
- int Match(const String&,
+ // Attempt to match the given input string against the regexp. Returns the
+ // index of the match within the input string on success and -1 otherwise.
+ // If |match_length| is provided, then its populated with the length of the
+ // match on success. If |group_list| is provided its populated with the
+ // matched groups within the regexp. These are the values normally starting
+ // at index 1 within the array returned from Regexp.exec(). |group_list|
+ // must be empty if it is provided.
+ int Match(StringView,
int start_from = 0,
- int* match_length = nullptr) const;
+ int* match_length = nullptr,
+ WTF::Vector<String>* group_list = nullptr) const;
bool IsValid() const { return !regex_.IsEmpty(); }
// exceptionMessage is available only if !isValid().
String ExceptionMessage() const { return exception_message_; }
+ void Trace(Visitor* visitor) const;
+
private:
- ScopedPersistent<v8::RegExp> regex_;
+ TraceWrapperV8Reference<v8::RegExp> regex_;
String exception_message_;
DISALLOW_COPY_AND_ASSIGN(ScriptRegexp);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
index 0fb1c19eacb..02e2081d4d1 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -19,10 +20,12 @@
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/response_body_loader.h"
+#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
@@ -100,9 +103,9 @@ class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
memcpy(copy_for_resource.get(), buffer, num_bytes);
PostCrossThreadTask(
*loading_task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- NotifyClientDidReceiveData, response_body_loader_client_,
- WTF::Passed(std::move(copy_for_resource)), num_bytes));
+ CrossThreadBindOnce(NotifyClientDidReceiveData,
+ response_body_loader_client_,
+ std::move(copy_for_resource), num_bytes));
result = data_pipe_->EndReadData(num_bytes);
CHECK_EQ(result, MOJO_RESULT_OK);
@@ -266,6 +269,100 @@ class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
size_t ScriptStreamer::small_script_threshold_ = 30 * 1024;
+std::tuple<ScriptStreamer*, ScriptStreamer::NotStreamingReason>
+ScriptStreamer::TakeFrom(ScriptResource* script_resource) {
+ ScriptStreamer::NotStreamingReason not_streamed_reason =
+ script_resource->NoStreamerReason();
+ ScriptStreamer* streamer = script_resource->TakeStreamer();
+ if (streamer) {
+ if (streamer->IsStreamingSuppressed()) {
+ not_streamed_reason = streamer->StreamingSuppressedReason();
+ streamer = nullptr;
+ } else {
+ DCHECK_EQ(not_streamed_reason,
+ ScriptStreamer::NotStreamingReason::kInvalid);
+ }
+ }
+ return std::make_tuple(streamer, not_streamed_reason);
+}
+
+namespace {
+
+enum class StreamedBoolean {
+ // Must match BooleanStreamed in enums.xml.
+ kNotStreamed = 0,
+ kStreamed = 1,
+ kMaxValue = kStreamed
+};
+
+void RecordStartedStreamingHistogram(ScriptSchedulingType type,
+ bool did_use_streamer) {
+ StreamedBoolean streamed = did_use_streamer ? StreamedBoolean::kStreamed
+ : StreamedBoolean::kNotStreamed;
+ switch (type) {
+ case ScriptSchedulingType::kParserBlocking: {
+ UMA_HISTOGRAM_ENUMERATION(
+ "WebCore.Scripts.ParsingBlocking.StartedStreaming", streamed);
+ break;
+ }
+ case ScriptSchedulingType::kDefer: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Deferred.StartedStreaming",
+ streamed);
+ break;
+ }
+ case ScriptSchedulingType::kAsync: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Async.StartedStreaming",
+ streamed);
+ break;
+ }
+ default: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Other.StartedStreaming",
+ streamed);
+ break;
+ }
+ }
+}
+
+void RecordNotStreamingReasonHistogram(
+ ScriptSchedulingType type,
+ ScriptStreamer::NotStreamingReason reason) {
+ switch (type) {
+ case ScriptSchedulingType::kParserBlocking: {
+ UMA_HISTOGRAM_ENUMERATION(
+ "WebCore.Scripts.ParsingBlocking.NotStreamingReason", reason);
+ break;
+ }
+ case ScriptSchedulingType::kDefer: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Deferred.NotStreamingReason",
+ reason);
+ break;
+ }
+ case ScriptSchedulingType::kAsync: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Async.NotStreamingReason",
+ reason);
+ break;
+ }
+ default: {
+ UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Other.NotStreamingReason",
+ reason);
+ break;
+ }
+ }
+}
+
+} // namespace
+
+void ScriptStreamer::RecordStreamingHistogram(
+ ScriptSchedulingType type,
+ bool can_use_streamer,
+ ScriptStreamer::NotStreamingReason reason) {
+ RecordStartedStreamingHistogram(type, can_use_streamer);
+ if (!can_use_streamer) {
+ DCHECK_NE(ScriptStreamer::NotStreamingReason::kInvalid, reason);
+ RecordNotStreamingReasonHistogram(type, reason);
+ }
+}
+
bool ScriptStreamer::ConvertEncoding(
const char* encoding_name,
v8::ScriptCompiler::StreamedSource::Encoding* encoding) {
@@ -429,6 +526,16 @@ bool ScriptStreamer::TryStartStreamingTask() {
if (!CanStartStreaming())
return false;
+ // Skip non-JS modules based on the mime-type.
+ // TODO(crbug/1132413),TODO(crbug/1061857): Disable streaming for non-JS
+ // based the specific import statements.
+ if (script_resource_->GetScriptType() == mojom::blink::ScriptType::kModule &&
+ !MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
+ script_resource_->GetResponse().HttpContentType())) {
+ SuppressStreaming(NotStreamingReason::kNonJavascriptModule);
+ return false;
+ }
+
// Even if the first data chunk is small, the script can still be big enough -
// wait until the next data chunk comes before deciding whether to start the
// streaming.
@@ -486,10 +593,14 @@ bool ScriptStreamer::TryStartStreamingTask() {
std::move(stream_ptr), encoding_);
std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask>
- script_streaming_task(
- base::WrapUnique(v8::ScriptCompiler::StartStreamingScript(
+ script_streaming_task =
+ base::WrapUnique(v8::ScriptCompiler::StartStreaming(
V8PerIsolateData::MainThreadIsolate(), source_.get(),
- compile_options_)));
+ script_resource_->GetScriptType() ==
+ mojom::blink::ScriptType::kClassic
+ ? v8::ScriptType::kClassic
+ : v8::ScriptType::kModule));
+
if (!script_streaming_task) {
// V8 cannot stream the script.
stream_ = nullptr;
@@ -518,7 +629,7 @@ bool ScriptStreamer::TryStartStreamingTask() {
worker_pool::PostTask(
FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
CrossThreadBindOnce(RunScriptStreamingTask,
- WTF::Passed(std::move(script_streaming_task)),
+ std::move(script_streaming_task),
WrapCrossThreadPersistent(this),
WTF::CrossThreadUnretained(stream_)));
@@ -529,12 +640,10 @@ ScriptStreamer::ScriptStreamer(
ScriptResource* script_resource,
mojo::ScopedDataPipeConsumerHandle data_pipe,
ResponseBodyLoaderClient* response_body_loader_client,
- v8::ScriptCompiler::CompileOptions compile_options,
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner)
: script_resource_(script_resource),
response_body_loader_client_(response_body_loader_client),
data_pipe_(std::move(data_pipe)),
- compile_options_(compile_options),
script_url_string_(script_resource->Url().Copy().GetString()),
script_resource_identifier_(script_resource->InspectorId()),
// Unfortunately there's no dummy encoding value in the enum; let's use
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.h b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.h
index bf042780c45..714c66ae3aa 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer.h
@@ -6,11 +6,13 @@
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_STREAMER_H_
#include <memory>
+#include <tuple>
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/script/script_scheduling_type.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "v8/include/v8.h"
@@ -58,6 +60,7 @@ class CORE_EXPORT ScriptStreamer final
kModuleScript,
kNoDataPipe,
kLoadingCancelled,
+ kNonJavascriptModule,
kDisabledByFeatureList,
// Pseudo values that should never be seen in reported metrics
@@ -69,11 +72,16 @@ class CORE_EXPORT ScriptStreamer final
ScriptResource* resource,
mojo::ScopedDataPipeConsumerHandle data_pipe,
ResponseBodyLoaderClient* response_body_loader_client,
- v8::ScriptCompiler::CompileOptions compile_options,
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner);
~ScriptStreamer();
void Trace(Visitor*) const;
+ static std::tuple<ScriptStreamer*, NotStreamingReason> TakeFrom(
+ ScriptResource*);
+ static void RecordStreamingHistogram(ScriptSchedulingType type,
+ bool can_use_streamer,
+ ScriptStreamer::NotStreamingReason);
+
// Returns false if we cannot stream the given encoding.
static bool ConvertEncoding(const char* encoding_name,
v8::ScriptCompiler::StreamedSource::Encoding*);
@@ -201,9 +209,6 @@ class CORE_EXPORT ScriptStreamer final
// The reason that streaming is disabled
NotStreamingReason suppressed_reason_ = NotStreamingReason::kInvalid;
- // What kind of cached data V8 produces during streaming.
- v8::ScriptCompiler::CompileOptions compile_options_;
-
// Keep the script URL string for event tracing.
const String script_url_string_;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
index c7cf683f19b..9cf829f3b16 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/platform/web_url_request_extra_data.h"
@@ -72,7 +73,8 @@ class NoopLoaderFactory final : public ResourceFetcher::LoaderFactory {
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner>,
- scoped_refptr<base::SingleThreadTaskRunner>) override {
+ scoped_refptr<base::SingleThreadTaskRunner>,
+ WebBackForwardCacheLoaderHelper) override {
return std::make_unique<NoopWebURLLoader>();
}
std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override {
@@ -130,7 +132,11 @@ class ScriptStreamingTest : public testing::Test {
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
properties->MakeDetachable(), context, freezable_task_runner_,
unfreezable_task_runner_, MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
+
+ EXPECT_EQ(mojo::CreateDataPipe(nullptr, producer_handle_, consumer_handle_),
+ MOJO_RESULT_OK);
ResourceRequest request(url_);
request.SetRequestContext(mojom::blink::RequestContextType::SCRIPT);
@@ -149,7 +155,7 @@ class ScriptStreamingTest : public testing::Test {
resource_->Loader()->DidReceiveResponse(WrappedResourceResponse(response));
resource_->Loader()->DidStartLoadingResponseBody(
- std::move(data_pipe_.consumer_handle));
+ std::move(consumer_handle_));
}
ScriptSourceCode GetScriptSourceCode() const {
@@ -172,7 +178,7 @@ class ScriptStreamingTest : public testing::Test {
protected:
void AppendData(const char* data) {
uint32_t data_len = strlen(data);
- MojoResult result = data_pipe_.producer_handle->WriteData(
+ MojoResult result = producer_handle_->WriteData(
data, &data_len, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
EXPECT_EQ(result, MOJO_RESULT_OK);
@@ -195,7 +201,7 @@ class ScriptStreamingTest : public testing::Test {
void Finish() {
resource_->Loader()->DidFinishLoading(base::TimeTicks(), 0, 0, 0, false);
- data_pipe_.producer_handle.reset();
+ producer_handle_.reset();
resource_->SetStatus(ResourceStatus::kCached);
}
@@ -210,7 +216,8 @@ class ScriptStreamingTest : public testing::Test {
Persistent<TestResourceClient> resource_client_;
Persistent<ScriptResource> resource_;
- mojo::DataPipe data_pipe_;
+ mojo::ScopedDataPipeProducerHandle producer_handle_;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle_;
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
index d1736184493..1eb157a30b0 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
@@ -43,16 +43,15 @@ enum SerializationTag {
// transferred MojoHandle.
kBlobTag = 'b', // uuid:WebCoreString, type:WebCoreString, size:uint64_t ->
// Blob (ref)
- kBlobIndexTag = 'i', // index:int32_t -> Blob (ref)
- kFileTag = 'f', // file:RawFile -> File (ref)
- kFileIndexTag = 'e', // index:int32_t -> File (ref)
- kDOMFileSystemTag = 'd', // type:int32_t, name:WebCoreString,
- // uuid:WebCoreString -> FileSystem (ref)
- kNativeFileSystemFileHandleTag = 'n', // name:WebCoreString, index:uint32_t
- // -> NativeFileSystemFileHandle (ref)
- kNativeFileSystemDirectoryHandleTag =
- 'N', // name:WebCoreString, index:uint32_t ->
- // NativeFileSystemDirectoryHandle (ref)
+ kBlobIndexTag = 'i', // index:int32_t -> Blob (ref)
+ kFileTag = 'f', // file:RawFile -> File (ref)
+ kFileIndexTag = 'e', // index:int32_t -> File (ref)
+ kDOMFileSystemTag = 'd', // type:int32_t, name:WebCoreString,
+ // uuid:WebCoreString -> FileSystem (ref)
+ kFileSystemFileHandleTag = 'n', // name:WebCoreString, index:uint32_t
+ // -> FileSystemFileHandle (ref)
+ kFileSystemDirectoryHandleTag = 'N', // name:WebCoreString, index:uint32_t ->
+ // FileSystemDirectoryHandle (ref)
kFileListTag =
'l', // length:uint32_t, files:RawFile[length] -> FileList (ref)
kFileListIndexTag =
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.cc
index 2eacec18fa6..1732c2b027b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.cc
@@ -8,47 +8,45 @@
namespace blink {
-SerializedColorParams::SerializedColorParams()
- : color_space_(SerializedColorSpace::kSRGB),
- pixel_format_(SerializedPixelFormat::kRGBA8),
- opacity_mode_(SerializedOpacityMode::kNonOpaque),
- storage_format_(SerializedImageDataStorageFormat::kUint8Clamped) {}
-
-SerializedColorParams::SerializedColorParams(CanvasColorParams color_params) {
- switch (color_params.ColorSpace()) {
+namespace {
+
+SerializedColorSpace SerializeColorSpace(CanvasColorSpace color_space) {
+ switch (color_space) {
case CanvasColorSpace::kSRGB:
- color_space_ = SerializedColorSpace::kSRGB;
- break;
+ return SerializedColorSpace::kSRGB;
case CanvasColorSpace::kRec2020:
- color_space_ = SerializedColorSpace::kRec2020;
- break;
+ return SerializedColorSpace::kRec2020;
case CanvasColorSpace::kP3:
- color_space_ = SerializedColorSpace::kP3;
- break;
+ return SerializedColorSpace::kP3;
}
+ NOTREACHED();
+ return SerializedColorSpace::kSRGB;
+}
- switch (color_params.PixelFormat()) {
- case CanvasPixelFormat::kRGBA8:
- pixel_format_ = SerializedPixelFormat::kRGBA8;
- break;
- case CanvasPixelFormat::kBGRA8:
- pixel_format_ = SerializedPixelFormat::kBGRA8;
- break;
- case CanvasPixelFormat::kF16:
- pixel_format_ = SerializedPixelFormat::kF16;
- break;
+CanvasColorSpace DeserializeColorSpace(
+ SerializedColorSpace serialized_color_space) {
+ switch (serialized_color_space) {
+ case SerializedColorSpace::kLegacyObsolete:
+ case SerializedColorSpace::kSRGB:
+ return CanvasColorSpace::kSRGB;
+ case SerializedColorSpace::kRec2020:
+ return CanvasColorSpace::kRec2020;
+ case SerializedColorSpace::kP3:
+ return CanvasColorSpace::kP3;
}
-
- opacity_mode_ = SerializedOpacityMode::kNonOpaque;
- if (color_params.GetOpacityMode() == blink::kOpaque)
- opacity_mode_ = SerializedOpacityMode::kOpaque;
- storage_format_ = SerializedImageDataStorageFormat::kUint8Clamped;
+ NOTREACHED();
+ return CanvasColorSpace::kSRGB;
}
-SerializedColorParams::SerializedColorParams(
- CanvasColorParams color_params,
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// SerializedImageDataSettings
+
+SerializedImageDataSettings::SerializedImageDataSettings(
+ CanvasColorSpace color_space,
ImageDataStorageFormat storage_format)
- : SerializedColorParams(color_params) {
+ : color_space_(SerializeColorSpace(color_space)) {
switch (storage_format) {
case kUint8ClampedArrayStorageFormat:
storage_format_ = SerializedImageDataStorageFormat::kUint8Clamped;
@@ -62,64 +60,16 @@ SerializedColorParams::SerializedColorParams(
}
}
-SerializedColorParams::SerializedColorParams(
+SerializedImageDataSettings::SerializedImageDataSettings(
SerializedColorSpace color_space,
- SerializedPixelFormat pixel_format,
- SerializedOpacityMode opacity_mode,
- SerializedImageDataStorageFormat storage_format) {
- SetSerializedColorSpace(color_space);
- SetSerializedPixelFormat(pixel_format);
- SetSerializedOpacityMode(opacity_mode);
- SetSerializedImageDataStorageFormat(storage_format);
-}
+ SerializedImageDataStorageFormat storage_format)
+ : color_space_(color_space), storage_format_(storage_format) {}
-CanvasColorParams SerializedColorParams::GetCanvasColorParams() const {
- CanvasColorSpace color_space = CanvasColorSpace::kSRGB;
- switch (color_space_) {
- case SerializedColorSpace::kLegacyObsolete:
- case SerializedColorSpace::kSRGB:
- color_space = CanvasColorSpace::kSRGB;
- break;
- case SerializedColorSpace::kRec2020:
- color_space = CanvasColorSpace::kRec2020;
- break;
- case SerializedColorSpace::kP3:
- color_space = CanvasColorSpace::kP3;
- break;
- }
-
- CanvasPixelFormat pixel_format = CanvasPixelFormat::kRGBA8;
- switch (pixel_format_) {
- case SerializedPixelFormat::kNative8_LegacyObsolete:
-#if defined(OS_ANDROID)
- pixel_format = CanvasPixelFormat::kRGBA8;
-#else
- pixel_format = CanvasPixelFormat::kBGRA8;
-#endif
- break;
- case SerializedPixelFormat::kRGBA8:
- pixel_format = CanvasPixelFormat::kRGBA8;
- break;
- case SerializedPixelFormat::kBGRA8:
- pixel_format = CanvasPixelFormat::kBGRA8;
- break;
- case SerializedPixelFormat::kF16:
- pixel_format = CanvasPixelFormat::kF16;
- break;
- }
-
- blink::OpacityMode opacity_mode = blink::kNonOpaque;
- if (opacity_mode_ == SerializedOpacityMode::kOpaque)
- opacity_mode = blink::kOpaque;
-
- return CanvasColorParams(color_space, pixel_format, opacity_mode);
-}
-
-CanvasColorSpace SerializedColorParams::GetColorSpace() const {
- return GetCanvasColorParams().ColorSpace();
+CanvasColorSpace SerializedImageDataSettings::GetColorSpace() const {
+ return DeserializeColorSpace(color_space_);
}
-ImageDataStorageFormat SerializedColorParams::GetStorageFormat() const {
+ImageDataStorageFormat SerializedImageDataSettings::GetStorageFormat() const {
switch (storage_format_) {
case SerializedImageDataStorageFormat::kUint8Clamped:
return kUint8ClampedArrayStorageFormat;
@@ -132,41 +82,125 @@ ImageDataStorageFormat SerializedColorParams::GetStorageFormat() const {
return kUint8ClampedArrayStorageFormat;
}
-void SerializedColorParams::SetSerializedColorSpace(
- SerializedColorSpace color_space) {
- color_space_ = color_space;
+ImageDataSettings* SerializedImageDataSettings::GetImageDataSettings() const {
+ ImageDataSettings* settings = ImageDataSettings::Create();
+ switch (DeserializeColorSpace(color_space_)) {
+ case CanvasColorSpace::kSRGB:
+ settings->setColorSpace(kSRGBCanvasColorSpaceName);
+ break;
+ case CanvasColorSpace::kRec2020:
+ settings->setColorSpace(kRec2020CanvasColorSpaceName);
+ break;
+ case CanvasColorSpace::kP3:
+ settings->setColorSpace(kP3CanvasColorSpaceName);
+ break;
+ }
+ switch (storage_format_) {
+ case SerializedImageDataStorageFormat::kUint8Clamped:
+ settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ break;
+ case SerializedImageDataStorageFormat::kUint16:
+ settings->setStorageFormat(kUint16ArrayStorageFormatName);
+ break;
+ case SerializedImageDataStorageFormat::kFloat32:
+ settings->setStorageFormat(kFloat32ArrayStorageFormatName);
+ break;
+ }
+ return settings;
}
-void SerializedColorParams::SetSerializedPixelFormat(
- SerializedPixelFormat pixel_format) {
- pixel_format_ = pixel_format;
-}
+////////////////////////////////////////////////////////////////////////////////
+// SerializedImageBitmapSettings
-void SerializedColorParams::SetSerializedOpacityMode(
- SerializedOpacityMode opacity_mode) {
- opacity_mode_ = opacity_mode;
-}
+SerializedImageBitmapSettings::SerializedImageBitmapSettings() = default;
-void SerializedColorParams::SetSerializedImageDataStorageFormat(
- SerializedImageDataStorageFormat storage_format) {
- storage_format_ = storage_format;
-}
+SerializedImageBitmapSettings::SerializedImageBitmapSettings(SkImageInfo info) {
+ color_space_ =
+ SerializeColorSpace(CanvasColorSpaceFromSkColorSpace(info.colorSpace()));
-SerializedColorSpace SerializedColorParams::GetSerializedColorSpace() const {
- return color_space_;
-}
+ switch (info.colorType()) {
+ default:
+ case kRGBA_8888_SkColorType:
+ pixel_format_ = SerializedPixelFormat::kRGBA8;
+ break;
+ case kBGRA_8888_SkColorType:
+ pixel_format_ = SerializedPixelFormat::kBGRA8;
+ break;
+ case kRGB_888x_SkColorType:
+ pixel_format_ = SerializedPixelFormat::kRGBX8;
+ break;
+ case kRGBA_F16_SkColorType:
+ pixel_format_ = SerializedPixelFormat::kF16;
+ break;
+ }
-SerializedPixelFormat SerializedColorParams::GetSerializedPixelFormat() const {
- return pixel_format_;
+ switch (info.alphaType()) {
+ case kUnknown_SkAlphaType:
+ case kPremul_SkAlphaType:
+ opacity_mode_ = SerializedOpacityMode::kNonOpaque;
+ is_premultiplied_ = true;
+ break;
+ case kUnpremul_SkAlphaType:
+ opacity_mode_ = SerializedOpacityMode::kNonOpaque;
+ is_premultiplied_ = false;
+ break;
+ case kOpaque_SkAlphaType:
+ opacity_mode_ = SerializedOpacityMode::kOpaque;
+ is_premultiplied_ = true;
+ break;
+ }
}
-SerializedOpacityMode SerializedColorParams::GetSerializedOpacityMode() const {
- return opacity_mode_;
-}
+SerializedImageBitmapSettings::SerializedImageBitmapSettings(
+ SerializedColorSpace color_space,
+ SerializedPixelFormat pixel_format,
+ SerializedOpacityMode opacity_mode,
+ uint32_t is_premultiplied)
+ : color_space_(color_space),
+ pixel_format_(pixel_format),
+ opacity_mode_(opacity_mode),
+ is_premultiplied_(is_premultiplied) {}
+
+SkImageInfo SerializedImageBitmapSettings::GetSkImageInfo(
+ uint32_t width,
+ uint32_t height) const {
+ sk_sp<SkColorSpace> sk_color_space =
+ CanvasColorSpaceToSkColorSpace(DeserializeColorSpace(color_space_));
+
+ SkColorType sk_color_type = kRGBA_8888_SkColorType;
+ switch (pixel_format_) {
+ case SerializedPixelFormat::kNative8_LegacyObsolete:
+ sk_color_type = kN32_SkColorType;
+ break;
+ case SerializedPixelFormat::kRGBA8:
+ sk_color_type = kRGBA_8888_SkColorType;
+ break;
+ case SerializedPixelFormat::kBGRA8:
+ sk_color_type = kBGRA_8888_SkColorType;
+ break;
+ case SerializedPixelFormat::kRGBX8:
+ sk_color_type = kRGB_888x_SkColorType;
+ break;
+ case SerializedPixelFormat::kF16:
+ sk_color_type = kRGBA_F16_SkColorType;
+ break;
+ }
+
+ SkAlphaType sk_alpha_type = kPremul_SkAlphaType;
+ if (opacity_mode_ == SerializedOpacityMode::kOpaque) {
+ sk_alpha_type = kOpaque_SkAlphaType;
+ } else if (is_premultiplied_) {
+ sk_alpha_type = kPremul_SkAlphaType;
+ } else {
+ sk_alpha_type = kUnpremul_SkAlphaType;
+ }
+
+ blink::OpacityMode opacity_mode = blink::kNonOpaque;
+ if (opacity_mode_ == SerializedOpacityMode::kOpaque)
+ opacity_mode = blink::kOpaque;
-SerializedImageDataStorageFormat
-SerializedColorParams::GetSerializedImageDataStorageFormat() const {
- return storage_format_;
+ return SkImageInfo::Make(width, height, sk_color_type, sk_alpha_type,
+ std::move(sk_color_space));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.h
index 512df80ae8e..0d87169a169 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_color_params.h
@@ -53,7 +53,8 @@ enum class SerializedPixelFormat : uint32_t {
kF16 = 1,
kRGBA8 = 2,
kBGRA8 = 3,
- kLast = kBGRA8,
+ kRGBX8 = 4,
+ kLast = kRGBX8,
};
// This enumeration specifies the values used to serialize
@@ -71,35 +72,52 @@ enum class SerializedOpacityMode : uint32_t {
kLast = kOpaque,
};
-class SerializedColorParams {
+class SerializedImageDataSettings {
public:
- SerializedColorParams();
- SerializedColorParams(CanvasColorParams);
- SerializedColorParams(CanvasColorParams, ImageDataStorageFormat);
- SerializedColorParams(SerializedColorSpace,
- SerializedPixelFormat,
- SerializedOpacityMode,
- SerializedImageDataStorageFormat);
-
- CanvasColorParams GetCanvasColorParams() const;
+ SerializedImageDataSettings(CanvasColorSpace, ImageDataStorageFormat);
+ SerializedImageDataSettings(SerializedColorSpace,
+ SerializedImageDataStorageFormat);
+
CanvasColorSpace GetColorSpace() const;
ImageDataStorageFormat GetStorageFormat() const;
+ ImageDataSettings* GetImageDataSettings() const;
- void SetSerializedColorSpace(SerializedColorSpace);
- void SetSerializedPixelFormat(SerializedPixelFormat);
- void SetSerializedOpacityMode(SerializedOpacityMode);
- void SetSerializedImageDataStorageFormat(SerializedImageDataStorageFormat);
+ SerializedColorSpace GetSerializedColorSpace() const { return color_space_; }
+ SerializedImageDataStorageFormat GetSerializedImageDataStorageFormat() const {
+ return storage_format_;
+ }
- SerializedColorSpace GetSerializedColorSpace() const;
- SerializedPixelFormat GetSerializedPixelFormat() const;
- SerializedImageDataStorageFormat GetSerializedImageDataStorageFormat() const;
- SerializedOpacityMode GetSerializedOpacityMode() const;
+ private:
+ SerializedColorSpace color_space_ = SerializedColorSpace::kSRGB;
+ SerializedImageDataStorageFormat storage_format_ =
+ SerializedImageDataStorageFormat::kUint8Clamped;
+};
+
+class SerializedImageBitmapSettings {
+ public:
+ SerializedImageBitmapSettings();
+ explicit SerializedImageBitmapSettings(SkImageInfo);
+ SerializedImageBitmapSettings(SerializedColorSpace,
+ SerializedPixelFormat,
+ SerializedOpacityMode,
+ uint32_t is_premultiplied);
+
+ SkImageInfo GetSkImageInfo(uint32_t width, uint32_t height) const;
+
+ SerializedColorSpace GetSerializedColorSpace() const { return color_space_; }
+ SerializedPixelFormat GetSerializedPixelFormat() const {
+ return pixel_format_;
+ }
+ SerializedOpacityMode GetSerializedOpacityMode() const {
+ return opacity_mode_;
+ }
+ uint32_t IsPremultiplied() const { return is_premultiplied_; }
private:
- SerializedColorSpace color_space_;
- SerializedPixelFormat pixel_format_;
- SerializedOpacityMode opacity_mode_;
- SerializedImageDataStorageFormat storage_format_;
+ SerializedColorSpace color_space_ = SerializedColorSpace::kSRGB;
+ SerializedPixelFormat pixel_format_ = SerializedPixelFormat::kRGBA8;
+ SerializedOpacityMode opacity_mode_ = SerializedOpacityMode::kNonOpaque;
+ bool is_premultiplied_ = true;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
index dea409f2322..766e3328a1b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
@@ -409,6 +409,9 @@ void SerializedScriptValue::TransferReadableStream(
readable_stream->Serialize(script_state, local_port, exception_state);
if (exception_state.HadException())
return;
+ // The last element is added by the above `AddStreamChannel()` call.
+ streams_.back().readable_optimizer =
+ readable_stream->TakeTransferringOptimizer();
}
void SerializedScriptValue::TransferWritableStreams(
@@ -433,6 +436,9 @@ void SerializedScriptValue::TransferWritableStream(
writable_stream->Serialize(script_state, local_port, exception_state);
if (exception_state.HadException())
return;
+ // The last element is added by the above `AddStreamChannel()` call.
+ streams_.back().writable_optimizer =
+ writable_stream->TakeTransferringOptimizer();
}
void SerializedScriptValue::TransferTransformStreams(
@@ -790,7 +796,7 @@ static_assert(kSerializedScriptValueVersion ==
"Update WebSerializedScriptValueVersion.h.");
bool SerializedScriptValue::IsOriginCheckRequired() const {
- return native_file_system_tokens_.size() > 0;
+ return file_system_access_tokens_.size() > 0;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
index c057291fab8..7898c521db4 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
@@ -38,7 +38,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/common/messaging/message_port_channel.h"
#include "third_party/blink/public/common/messaging/message_port_descriptor.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/file_system_access/file_system_access_transfer_token.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/transferables.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -102,8 +103,8 @@ class CORE_EXPORT SerializedScriptValue
using TransferredWasmModulesArray = WTF::Vector<v8::CompiledWasmModule>;
using MessagePortChannelArray = Vector<MessagePortChannel>;
using StreamArray = Vector<Stream>;
- using NativeFileSystemTokensArray =
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>>;
+ using FileSystemAccessTokensArray =
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>;
// Increment this for each incompatible change to the wire format.
// Version 2: Added StringUCharTag for UChar v8 strings.
@@ -271,12 +272,19 @@ class CORE_EXPORT SerializedScriptValue
size_t DataLengthInBytes() const { return data_buffer_size_; }
TransferredWasmModulesArray& WasmModules() { return wasm_modules_; }
+
+ const SecurityOrigin* origin() { return origin_.get(); }
+
+ void set_origin(const SecurityOrigin* origin) {
+ origin_ = origin->IsolatedCopy();
+ }
+
SharedArrayBufferContentsArray& SharedArrayBuffersContents() {
return shared_array_buffers_contents_;
}
BlobDataHandleMap& BlobDataHandles() { return blob_data_handles_; }
- NativeFileSystemTokensArray& NativeFileSystemTokens() {
- return native_file_system_tokens_;
+ FileSystemAccessTokensArray& FileSystemAccessTokens() {
+ return file_system_access_tokens_;
}
MojoScopedHandleArray& MojoHandles() { return mojo_handles_; }
ArrayBufferContentsArray& GetArrayBufferContentsArray() {
@@ -393,10 +401,14 @@ class CORE_EXPORT SerializedScriptValue
// These do not have one-use transferred contents, like the above.
TransferredWasmModulesArray wasm_modules_;
+ // To count how often WebAssembly modules get transferred cross-origin, we
+ // allow to store the |SecurityOrigin| in the |V8SerializedScriptValue|. The
+ // |SecurityOrigin| has to be set explicitly with |set_origin()|.
+ scoped_refptr<SecurityOrigin> origin_;
BlobDataHandleMap blob_data_handles_;
MojoScopedHandleArray mojo_handles_;
SharedArrayBufferContentsArray shared_array_buffers_contents_;
- NativeFileSystemTokensArray native_file_system_tokens_;
+ FileSystemAccessTokensArray file_system_access_tokens_;
HashMap<const void* const*, std::unique_ptr<Attachment>> attachments_;
bool has_registered_external_allocation_;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
index 697b1fe0ce9..e4f056150e2 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/mojo/mojo_handle.h"
#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -95,6 +96,14 @@ size_t ReadVersionEnvelope(SerializedScriptValue* serialized_script_value,
return i;
}
+MessagePort* CreateEntangledPort(ScriptState* script_state,
+ const MessagePortChannel& channel) {
+ MessagePort* const port =
+ MakeGarbageCollected<MessagePort>(*ExecutionContext::From(script_state));
+ port->Entangle(channel);
+ return port;
+}
+
} // namespace
V8ScriptValueDeserializer::V8ScriptValueDeserializer(
@@ -183,12 +192,7 @@ void V8ScriptValueDeserializer::Transfer() {
// TODO(ricea): Make ExtendableMessageEvent store an
// UnpackedSerializedScriptValue like MessageEvent does, and then this
// special case won't be necessary.
- Vector<MessagePortChannel> channels;
- for (auto& stream : serialized_script_value_->GetStreams()) {
- channels.push_back(stream.channel);
- }
- transferred_stream_ports_ = MessagePort::EntanglePorts(
- *ExecutionContext::From(script_state_), channels);
+ streams_ = std::move(serialized_script_value_->GetStreams());
}
// There's nothing else to transfer if the deserializer was not given an
@@ -354,14 +358,12 @@ ScriptWrappable* V8ScriptValueDeserializer::ReadDOMObject(
if (!ReadUint32(&width) || !ReadUint32(&height) ||
!ReadUint32(&byte_length) || !ReadRawBytes(byte_length, &pixels))
return nullptr;
- CanvasColorParams color_params =
- SerializedColorParams(canvas_color_space, canvas_pixel_format,
- canvas_opacity_mode,
- SerializedImageDataStorageFormat::kUint8Clamped)
- .GetCanvasColorParams();
- base::CheckedNumeric<uint32_t> computed_byte_length = width;
- computed_byte_length *= height;
- computed_byte_length *= color_params.BytesPerPixel();
+ SkImageInfo info =
+ SerializedImageBitmapSettings(canvas_color_space, canvas_pixel_format,
+ canvas_opacity_mode, is_premultiplied)
+ .GetSkImageInfo(width, height);
+ base::CheckedNumeric<uint32_t> computed_byte_length =
+ info.computeMinByteSize();
if (!computed_byte_length.IsValid() ||
computed_byte_length.ValueOrDie() != byte_length)
return nullptr;
@@ -370,8 +372,8 @@ ScriptWrappable* V8ScriptValueDeserializer::ReadDOMObject(
// been deprecated.
return nullptr;
}
- return MakeGarbageCollected<ImageBitmap>(
- pixels, width, height, is_premultiplied, origin_clean, color_params);
+ SkPixmap pixmap(info, pixels, info.minRowBytes());
+ return MakeGarbageCollected<ImageBitmap>(pixmap, origin_clean);
}
case kImageBitmapTransferTag: {
uint32_t index = 0;
@@ -426,24 +428,23 @@ ScriptWrappable* V8ScriptValueDeserializer::ReadDOMObject(
return nullptr;
}
- SerializedColorParams color_params(
- canvas_color_space, SerializedPixelFormat::kNative8_LegacyObsolete,
- SerializedOpacityMode::kNonOpaque, image_data_storage_format);
- ImageDataStorageFormat storage_format = color_params.GetStorageFormat();
+ SerializedImageDataSettings settings(canvas_color_space,
+ image_data_storage_format);
base::CheckedNumeric<size_t> computed_byte_length = width;
computed_byte_length *= height;
computed_byte_length *=
- ImageData::StorageFormatBytesPerPixel(storage_format);
+ ImageData::StorageFormatBytesPerPixel(settings.GetStorageFormat());
if (!computed_byte_length.IsValid() ||
computed_byte_length.ValueOrDie() != byte_length)
return nullptr;
- ImageData* image_data = ImageData::Create(
- IntSize(width, height), color_params.GetColorSpace(), storage_format);
+ ImageData* image_data = ImageData::ValidateAndCreate(
+ width, height, base::nullopt, settings.GetImageDataSettings(),
+ exception_state);
if (!image_data)
return nullptr;
- DOMArrayBufferBase* pixel_buffer = image_data->BufferBase();
- DCHECK_EQ(pixel_buffer->ByteLength(), byte_length);
- memcpy(pixel_buffer->Data(), pixels, byte_length);
+ SkPixmap image_data_pixmap = image_data->GetSkPixmap();
+ DCHECK_EQ(image_data_pixmap.computeByteSize(), byte_length);
+ memcpy(image_data_pixmap.writable_addr(), pixels, byte_length);
return image_data;
}
case kDOMPointTag: {
@@ -558,52 +559,56 @@ ScriptWrappable* V8ScriptValueDeserializer::ReadDOMObject(
if (!TransferableStreamsEnabled())
return nullptr;
uint32_t index = 0;
- if (!ReadUint32(&index) || !transferred_stream_ports_ ||
- index >= transferred_stream_ports_->size()) {
+ if (!ReadUint32(&index) || index >= streams_.size()) {
return nullptr;
}
return ReadableStream::Deserialize(
- script_state_, (*transferred_stream_ports_)[index].Get(),
- exception_state);
+ script_state_,
+ CreateEntangledPort(GetScriptState(), streams_[index].channel),
+ std::move(streams_[index].readable_optimizer), exception_state);
}
case kWritableStreamTransferTag: {
if (!TransferableStreamsEnabled())
return nullptr;
uint32_t index = 0;
- if (!ReadUint32(&index) || !transferred_stream_ports_ ||
- index >= transferred_stream_ports_->size()) {
+ if (!ReadUint32(&index) || index >= streams_.size()) {
return nullptr;
}
return WritableStream::Deserialize(
- script_state_, (*transferred_stream_ports_)[index].Get(),
- exception_state);
+ script_state_,
+ CreateEntangledPort(GetScriptState(), streams_[index].channel),
+ std::move(streams_[index].writable_optimizer), exception_state);
}
case kTransformStreamTransferTag: {
if (!TransferableStreamsEnabled())
return nullptr;
uint32_t index = 0;
- if (!ReadUint32(&index) || !transferred_stream_ports_ ||
+ if (!ReadUint32(&index) ||
index == std::numeric_limits<decltype(index)>::max() ||
- index + 1 >= transferred_stream_ports_->size()) {
+ index + 1 >= streams_.size()) {
return nullptr;
}
+ MessagePort* const port_for_readable =
+ CreateEntangledPort(GetScriptState(), streams_[index].channel);
+ MessagePort* const port_for_writable =
+ CreateEntangledPort(GetScriptState(), streams_[index + 1].channel);
// https://streams.spec.whatwg.org/#ts-transfer
// 1. Let readableRecord be !
// StructuredDeserializeWithTransfer(dataHolder.[[readable]], the
// current Realm).
- ReadableStream* readable = ReadableStream::Deserialize(
- script_state_, (*transferred_stream_ports_)[index].Get(),
- exception_state);
+ ReadableStream* readable =
+ ReadableStream::Deserialize(script_state_, port_for_readable,
+ /*optimizer=*/nullptr, exception_state);
if (!readable)
return nullptr;
// 2. Let writableRecord be !
// StructuredDeserializeWithTransfer(dataHolder.[[writable]], the
// current Realm).
- WritableStream* writable = WritableStream::Deserialize(
- script_state_, (*transferred_stream_ports_)[index + 1].Get(),
- exception_state);
+ WritableStream* writable =
+ WritableStream::Deserialize(script_state_, port_for_writable,
+ /*optimizer=*/nullptr, exception_state);
if (!writable)
return nullptr;
@@ -746,6 +751,14 @@ v8::MaybeLocal<v8::WasmModuleObject>
V8ScriptValueDeserializer::GetWasmModuleFromId(v8::Isolate* isolate,
uint32_t id) {
if (id < serialized_script_value_->WasmModules().size()) {
+ ExecutionContext* execution_context = ExecutionContext::From(script_state_);
+ DCHECK(serialized_script_value_->origin());
+ UseCounter::Count(execution_context, WebFeature::kWasmModuleSharing);
+ if (!serialized_script_value_->origin()->IsSameOriginWith(
+ execution_context->GetSecurityOrigin())) {
+ UseCounter::Count(execution_context,
+ WebFeature::kCrossOriginWasmModuleSharing);
+ }
return v8::WasmModuleObject::FromCompiledModule(
isolate, serialized_script_value_->WasmModules()[id]);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
index cf8af825cb8..b8e3309eda8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h
@@ -119,7 +119,7 @@ class CORE_EXPORT V8ScriptValueDeserializer
// Message ports which were transferred in.
const MessagePortArray* transferred_message_ports_ = nullptr;
- MessagePortArray* transferred_stream_ports_ = nullptr;
+ Vector<SerializedScriptValue::Stream> streams_;
// Blob info for blobs stored by index.
const WebBlobInfoArray* blob_info_array_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
index 25d53ad41b5..517d4f5f8ec 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
@@ -118,7 +118,7 @@ scoped_refptr<SerializedScriptValue> V8ScriptValueSerializer::Serialize(
if (shared_array_buffers_.size()) {
auto* execution_context = ExecutionContext::From(script_state_);
- if (!execution_context->SharedArrayBufferTransferAllowed()) {
+ if (!execution_context->CheckSharedArrayBufferTransferAllowedAndReport()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kDataCloneError,
"SharedArrayBuffer transfer requires self.crossOriginIsolated.");
@@ -304,7 +304,8 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
return false;
}
WriteTag(kImageBitmapTag);
- SerializedColorParams color_params(image_bitmap->GetCanvasColorParams());
+ SkImageInfo info = image_bitmap->GetBitmapSkImageInfo();
+ SerializedImageBitmapSettings color_params(info);
WriteUint32Enum(ImageSerializationTag::kCanvasColorSpaceTag);
WriteUint32Enum(color_params.GetSerializedColorSpace());
WriteUint32Enum(ImageSerializationTag::kCanvasPixelFormatTag);
@@ -314,11 +315,11 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
WriteUint32Enum(ImageSerializationTag::kOriginCleanTag);
WriteUint32(image_bitmap->OriginClean());
WriteUint32Enum(ImageSerializationTag::kIsPremultipliedTag);
- WriteUint32(image_bitmap->IsPremultiplied());
+ WriteUint32(color_params.IsPremultiplied());
WriteUint32Enum(ImageSerializationTag::kEndTag);
WriteUint32(image_bitmap->width());
WriteUint32(image_bitmap->height());
- Vector<uint8_t> pixels = image_bitmap->CopyBitmapData();
+ Vector<uint8_t> pixels = image_bitmap->CopyBitmapData(info, false);
// Check if we succeeded to copy the BitmapData.
if (image_bitmap->width() != 0 && image_bitmap->height() != 0 &&
pixels.size() == 0) {
@@ -334,19 +335,24 @@ bool V8ScriptValueSerializer::WriteDOMObject(ScriptWrappable* wrappable,
if (wrapper_type_info == V8ImageData::GetWrapperTypeInfo()) {
ImageData* image_data = wrappable->ToImpl<ImageData>();
WriteTag(kImageDataTag);
- SerializedColorParams color_params(image_data->GetCanvasColorParams(),
- image_data->GetImageDataStorageFormat());
+ SerializedImageDataSettings settings(
+ image_data->GetCanvasColorSpace(),
+ image_data->GetImageDataStorageFormat());
WriteUint32Enum(ImageSerializationTag::kCanvasColorSpaceTag);
- WriteUint32Enum(color_params.GetSerializedColorSpace());
+ WriteUint32Enum(settings.GetSerializedColorSpace());
WriteUint32Enum(ImageSerializationTag::kImageDataStorageFormatTag);
- WriteUint32Enum(color_params.GetSerializedImageDataStorageFormat());
+ WriteUint32Enum(settings.GetSerializedImageDataStorageFormat());
WriteUint32Enum(ImageSerializationTag::kEndTag);
WriteUint32(image_data->width());
WriteUint32(image_data->height());
- DOMArrayBufferBase* pixel_buffer = image_data->BufferBase();
- size_t pixel_buffer_length = pixel_buffer->ByteLength();
- WriteUint64(base::strict_cast<uint64_t>(pixel_buffer_length));
- WriteRawBytes(pixel_buffer->Data(), pixel_buffer_length);
+ if (image_data->IsBufferBaseDetached()) {
+ WriteUint64(0u);
+ } else {
+ SkPixmap image_data_pixmap = image_data->GetSkPixmap();
+ size_t pixel_buffer_length = image_data_pixmap.computeByteSize();
+ WriteUint64(base::strict_cast<uint64_t>(pixel_buffer_length));
+ WriteRawBytes(image_data_pixmap.addr(), pixel_buffer_length);
+ }
return true;
}
if (wrapper_type_info == V8DOMPoint::GetWrapperTypeInfo()) {
@@ -762,6 +768,13 @@ v8::Maybe<uint32_t> V8ScriptValueSerializer::GetWasmModuleTransferId(
// simple and should perform sufficiently well under these expectations.
serialized_script_value_->WasmModules().push_back(
module->GetCompiledModule());
+ if (!serialized_script_value_->origin()) {
+ // Store the |SecurityOrigin| of the current |ExecutionContext| to count
+ // during deserialization if the WebAssembly module got transferred
+ // cross-origin.
+ serialized_script_value_->set_origin(
+ ExecutionContext::From(script_state_)->GetSecurityOrigin());
+ }
uint32_t size =
static_cast<uint32_t>(serialized_script_value_->WasmModules().size());
DCHECK_GE(size, 1u);
@@ -777,7 +790,7 @@ v8::Maybe<uint32_t> V8ScriptValueSerializer::GetWasmModuleTransferId(
void* V8ScriptValueSerializer::ReallocateBufferMemory(void* old_buffer,
size_t size,
size_t* actual_size) {
- *actual_size = WTF::Partitions::BufferActualSize(size);
+ *actual_size = WTF::Partitions::BufferPotentialCapacity(size);
return WTF::Partitions::BufferTryRealloc(old_buffer, *actual_size,
"SerializedScriptValue buffer");
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index d7195549a41..f8e1a441fa8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -759,8 +759,11 @@ TEST(V8ScriptValueSerializerTest, DecodeDOMMatrixReadOnly) {
TEST(V8ScriptValueSerializerTest, RoundTripImageData) {
// ImageData objects should serialize and deserialize correctly.
V8TestingScope scope;
- ImageData* image_data = ImageData::Create(2, 1, ASSERT_NO_EXCEPTION);
- image_data->data().GetAsUint8ClampedArray()->Data()[0] = 200;
+ ImageData* image_data = ImageData::ValidateAndCreate(
+ 2, 1, base::nullopt, nullptr, ASSERT_NO_EXCEPTION);
+ SkPixmap pm = image_data->GetSkPixmap();
+ pm.writable_addr32(0, 0)[0] = 200u;
+ pm.writable_addr32(1, 0)[0] = 100u;
v8::Local<v8::Value> wrapper =
ToV8(image_data, scope.GetContext()->Global(), scope.GetIsolate());
v8::Local<v8::Value> result = RoundTrip(wrapper, scope);
@@ -768,21 +771,40 @@ TEST(V8ScriptValueSerializerTest, RoundTripImageData) {
ImageData* new_image_data = V8ImageData::ToImpl(result.As<v8::Object>());
EXPECT_NE(image_data, new_image_data);
EXPECT_EQ(image_data->Size(), new_image_data->Size());
- EXPECT_EQ(image_data->data().GetAsUint8ClampedArray()->length(),
- new_image_data->data().GetAsUint8ClampedArray()->length());
- EXPECT_EQ(200, new_image_data->data().GetAsUint8ClampedArray()->Data()[0]);
+ SkPixmap new_pm = new_image_data->GetSkPixmap();
+ EXPECT_EQ(200u, new_pm.addr32(0, 0)[0]);
+ EXPECT_EQ(100u, new_pm.addr32(1, 0)[0]);
+}
+
+TEST(V8ScriptValueSerializerTest, RoundTripDetachedImageData) {
+ // If an ImageData is detached, it can be serialized, but will fail when being
+ // deserialized.
+ V8TestingScope scope;
+ ImageData* image_data = ImageData::ValidateAndCreate(
+ 2, 1, base::nullopt, nullptr, ASSERT_NO_EXCEPTION);
+ SkPixmap pm = image_data->GetSkPixmap();
+ pm.writable_addr32(0, 0)[0] = 200u;
+ image_data->data().GetAsUint8ClampedArray()->BufferBase()->Detach();
+
+ v8::Local<v8::Value> wrapper =
+ ToV8(image_data, scope.GetContext()->Global(), scope.GetIsolate());
+ v8::Local<v8::Value> result = RoundTrip(wrapper, scope);
+ EXPECT_FALSE(V8ImageData::HasInstance(result, scope.GetIsolate()));
}
TEST(V8ScriptValueSerializerTest, RoundTripImageDataWithColorSpaceInfo) {
// ImageData objects with color space information should serialize and
// deserialize correctly.
V8TestingScope scope;
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- color_settings->setColorSpace("p3");
- color_settings->setStorageFormat("float32");
- ImageData* image_data =
- ImageData::CreateImageData(2, 1, color_settings, ASSERT_NO_EXCEPTION);
- static_cast<unsigned char*>(image_data->BufferBase()->Data())[0] = 200;
+ ImageDataSettings* image_data_settings = ImageDataSettings::Create();
+ image_data_settings->setColorSpace("display-p3");
+ image_data_settings->setStorageFormat("float32");
+ ImageData* image_data = ImageData::ValidateAndCreate(
+ 2, 1, base::nullopt, image_data_settings, ASSERT_NO_EXCEPTION);
+ SkPixmap pm = image_data->GetSkPixmap();
+ EXPECT_EQ(kRGBA_F32_SkColorType, pm.info().colorType());
+ static_cast<float*>(pm.writable_addr(0, 0))[0] = 200.f;
+
v8::Local<v8::Value> wrapper =
ToV8(image_data, scope.GetContext()->Global(), scope.GetIsolate());
v8::Local<v8::Value> result = RoundTrip(wrapper, scope);
@@ -790,14 +812,12 @@ TEST(V8ScriptValueSerializerTest, RoundTripImageDataWithColorSpaceInfo) {
ImageData* new_image_data = V8ImageData::ToImpl(result.As<v8::Object>());
EXPECT_NE(image_data, new_image_data);
EXPECT_EQ(image_data->Size(), new_image_data->Size());
- ImageDataColorSettings* new_color_settings =
- new_image_data->getColorSettings();
- EXPECT_EQ("p3", new_color_settings->colorSpace());
- EXPECT_EQ("float32", new_color_settings->storageFormat());
- EXPECT_EQ(image_data->BufferBase()->ByteLength(),
- new_image_data->BufferBase()->ByteLength());
- EXPECT_EQ(200, static_cast<unsigned char*>(
- new_image_data->BufferBase()->Data())[0]);
+ ImageDataSettings* new_image_data_settings = new_image_data->getSettings();
+ EXPECT_EQ("display-p3", new_image_data_settings->colorSpace());
+ EXPECT_EQ("float32", new_image_data_settings->storageFormat());
+ SkPixmap new_pm = new_image_data->GetSkPixmap();
+ EXPECT_EQ(kRGBA_F32_SkColorType, new_pm.info().colorType());
+ EXPECT_EQ(200.f, reinterpret_cast<const float*>(new_pm.addr(0, 0))[0]);
}
TEST(V8ScriptValueSerializerTest, DecodeImageDataV9) {
@@ -814,8 +834,9 @@ TEST(V8ScriptValueSerializerTest, DecodeImageDataV9) {
ASSERT_TRUE(V8ImageData::HasInstance(result, scope.GetIsolate()));
ImageData* new_image_data = V8ImageData::ToImpl(result.As<v8::Object>());
EXPECT_EQ(IntSize(2, 1), new_image_data->Size());
- EXPECT_EQ(8u, new_image_data->data().GetAsUint8ClampedArray()->length());
- EXPECT_EQ(200, new_image_data->data().GetAsUint8ClampedArray()->Data()[0]);
+ SkPixmap new_pm = new_image_data->GetSkPixmap();
+ EXPECT_EQ(8u, new_pm.computeByteSize());
+ EXPECT_EQ(200u, new_pm.addr32()[0]);
}
TEST(V8ScriptValueSerializerTest, DecodeImageDataV16) {
@@ -829,8 +850,10 @@ TEST(V8ScriptValueSerializerTest, DecodeImageDataV16) {
ASSERT_TRUE(V8ImageData::HasInstance(result, scope.GetIsolate()));
ImageData* new_image_data = V8ImageData::ToImpl(result.As<v8::Object>());
EXPECT_EQ(IntSize(2, 1), new_image_data->Size());
- EXPECT_EQ(8u, new_image_data->data().GetAsUint8ClampedArray()->length());
- EXPECT_EQ(200, new_image_data->data().GetAsUint8ClampedArray()->Data()[0]);
+ SkPixmap new_pm = new_image_data->GetSkPixmap();
+ EXPECT_EQ(kRGBA_8888_SkColorType, new_pm.info().colorType());
+ EXPECT_EQ(8u, new_pm.computeByteSize());
+ EXPECT_EQ(200u, new_pm.addr32()[0]);
}
TEST(V8ScriptValueSerializerTest, DecodeImageDataV18) {
@@ -846,13 +869,12 @@ TEST(V8ScriptValueSerializerTest, DecodeImageDataV18) {
ASSERT_TRUE(V8ImageData::HasInstance(result, scope.GetIsolate()));
ImageData* new_image_data = V8ImageData::ToImpl(result.As<v8::Object>());
EXPECT_EQ(IntSize(2, 1), new_image_data->Size());
- ImageDataColorSettings* new_color_settings =
- new_image_data->getColorSettings();
- EXPECT_EQ("p3", new_color_settings->colorSpace());
- EXPECT_EQ("float32", new_color_settings->storageFormat());
- EXPECT_EQ(32u, new_image_data->BufferBase()->ByteLength());
- EXPECT_EQ(200, static_cast<unsigned char*>(
- new_image_data->BufferBase()->Data())[0]);
+ ImageDataSettings* new_image_data_settings = new_image_data->getSettings();
+ EXPECT_EQ("display-p3", new_image_data_settings->colorSpace());
+ EXPECT_EQ("float32", new_image_data_settings->storageFormat());
+ SkPixmap new_pm = new_image_data->GetSkPixmap();
+ EXPECT_EQ(kRGBA_F32_SkColorType, new_pm.info().colorType());
+ EXPECT_EQ(200u, static_cast<const uint8_t*>(new_pm.addr(0, 0))[0]);
}
TEST(V8ScriptValueSerializerTest, InvalidImageDataDecodeV18) {
@@ -1037,12 +1059,12 @@ TEST(V8ScriptValueSerializerTest, RoundTripImageBitmap) {
}
TEST(V8ScriptValueSerializerTest, RoundTripImageBitmapWithColorSpaceInfo) {
+ sk_sp<SkColorSpace> p3 =
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
V8TestingScope scope;
// Make a 10x7 red ImageBitmap in P3 color space.
SkImageInfo info =
- SkImageInfo::Make(10, 7, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
- SkNamedGamut::kDisplayP3));
+ SkImageInfo::Make(10, 7, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3);
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
surface->getCanvas()->clear(SK_ColorRED);
auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(
@@ -1059,9 +1081,9 @@ TEST(V8ScriptValueSerializerTest, RoundTripImageBitmapWithColorSpaceInfo) {
ASSERT_EQ(IntSize(10, 7), new_image_bitmap->Size());
// Check the color settings.
- CanvasColorParams color_params = new_image_bitmap->GetCanvasColorParams();
- EXPECT_EQ(CanvasColorSpace::kP3, color_params.ColorSpace());
- EXPECT_EQ(CanvasPixelFormat::kF16, color_params.PixelFormat());
+ SkImageInfo bitmap_info = new_image_bitmap->GetBitmapSkImageInfo();
+ EXPECT_EQ(kRGBA_F16_SkColorType, bitmap_info.colorType());
+ EXPECT_TRUE(SkColorSpace::Equals(p3.get(), bitmap_info.colorSpace()));
// Check that the pixel at (3, 3) is red. We expect red in P3 to be
// {0x57, 0x3B, 0x68, 0x32, 0x6E, 0x30, 0x00, 0x3C} when each color
@@ -1128,6 +1150,8 @@ TEST(V8ScriptValueSerializerTest, DecodeImageBitmapV18) {
{0xff, 0x12, 0xff, 0x0d, 0x5c, 0x67, 0x01, 0x03, 0x02, 0x01, 0x04, 0x01,
0x05, 0x01, 0x00, 0x02, 0x01, 0x10, 0x94, 0x3a, 0x3f, 0x28, 0x5f, 0x24,
0x00, 0x3c, 0x94, 0x3a, 0x3f, 0x28, 0x5f, 0x24, 0x00, 0x3c});
+ sk_sp<SkColorSpace> p3 =
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
v8::Local<v8::Value> result =
V8ScriptValueDeserializer(script_state, input).Deserialize();
@@ -1137,16 +1161,14 @@ TEST(V8ScriptValueSerializerTest, DecodeImageBitmapV18) {
ASSERT_EQ(IntSize(2, 1), new_image_bitmap->Size());
// Check the color settings.
- CanvasColorParams color_params = new_image_bitmap->GetCanvasColorParams();
- EXPECT_EQ(CanvasColorSpace::kP3, color_params.ColorSpace());
- EXPECT_EQ(CanvasPixelFormat::kF16, color_params.PixelFormat());
+ SkImageInfo bitmap_info = new_image_bitmap->GetBitmapSkImageInfo();
+ EXPECT_EQ(kRGBA_F16_SkColorType, bitmap_info.colorType());
+ EXPECT_TRUE(SkColorSpace::Equals(p3.get(), bitmap_info.colorSpace()));
// Check that the pixel at (1, 0) is red.
uint8_t pixel[8] = {};
SkImageInfo info =
- SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
- SkNamedGamut::kDisplayP3));
+ SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3);
ASSERT_TRUE(
new_image_bitmap->BitmapImage()->PaintImageForCurrentFrame().readPixels(
info, &pixel, 8, 1, 0));
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/source_location.cc b/chromium/third_party/blink/renderer/bindings/core/v8/source_location.cc
index a7dada1068f..28938bcb177 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/source_location.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/source_location.cc
@@ -41,9 +41,10 @@ std::unique_ptr<SourceLocation> SourceLocation::Capture(
unsigned column_number) {
std::unique_ptr<v8_inspector::V8StackTrace> stack_trace =
CaptureStackTrace(false);
- if (stack_trace && !stack_trace->isEmpty())
+ if (stack_trace && !stack_trace->isEmpty()) {
return SourceLocation::CreateFromNonEmptyV8StackTrace(
- std::move(stack_trace), 0);
+ std::move(stack_trace));
+ }
return std::make_unique<SourceLocation>(url, line_number, column_number,
std::move(stack_trace));
}
@@ -53,9 +54,10 @@ std::unique_ptr<SourceLocation> SourceLocation::Capture(
ExecutionContext* execution_context) {
std::unique_ptr<v8_inspector::V8StackTrace> stack_trace =
CaptureStackTrace(false);
- if (stack_trace && !stack_trace->isEmpty())
+ if (stack_trace && !stack_trace->isEmpty()) {
return SourceLocation::CreateFromNonEmptyV8StackTrace(
- std::move(stack_trace), 0);
+ std::move(stack_trace));
+ }
if (LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(execution_context)) {
Document* document = window->document();
@@ -86,8 +88,7 @@ std::unique_ptr<SourceLocation> SourceLocation::FromMessage(
if (debugger)
stack_trace = debugger->GetV8Inspector()->createStackTrace(stack);
- int script_id =
- static_cast<int>(message->GetScriptOrigin().ScriptID()->Value());
+ int script_id = message->GetScriptOrigin().ScriptId();
if (!stack.IsEmpty() && stack->GetFrameCount() > 0) {
int top_script_id = stack->GetFrame(isolate, 0)->GetScriptId();
if (top_script_id == script_id)
@@ -100,9 +101,10 @@ std::unique_ptr<SourceLocation> SourceLocation::FromMessage(
message->GetStartColumn(isolate->GetCurrentContext()).To(&column_number))
++column_number;
- if ((!script_id || !line_number) && stack_trace && !stack_trace->isEmpty())
+ if ((!script_id || !line_number) && stack_trace && !stack_trace->isEmpty()) {
return SourceLocation::CreateFromNonEmptyV8StackTrace(
- std::move(stack_trace), 0);
+ std::move(stack_trace));
+ }
String url = ToCoreStringWithUndefinedOrNullCheck(
message->GetScriptOrigin().ResourceName());
@@ -114,12 +116,12 @@ std::unique_ptr<SourceLocation> SourceLocation::FromMessage(
// static
std::unique_ptr<SourceLocation> SourceLocation::CreateFromNonEmptyV8StackTrace(
- std::unique_ptr<v8_inspector::V8StackTrace> stack_trace,
- int script_id) {
+ std::unique_ptr<v8_inspector::V8StackTrace> stack_trace) {
// Retrieve the data before passing the ownership to SourceLocation.
String url = ToCoreString(stack_trace->topSourceURL());
unsigned line_number = stack_trace->topLineNumber();
unsigned column_number = stack_trace->topColumnNumber();
+ int script_id = stack_trace->topScriptIdAsInteger();
return base::WrapUnique(new SourceLocation(
url, line_number, column_number, std::move(stack_trace), script_id));
}
@@ -140,9 +142,10 @@ std::unique_ptr<SourceLocation> SourceLocation::FromFunction(
std::unique_ptr<SourceLocation> SourceLocation::CaptureWithFullStackTrace() {
std::unique_ptr<v8_inspector::V8StackTrace> stack_trace =
CaptureStackTrace(true);
- if (stack_trace && !stack_trace->isEmpty())
+ if (stack_trace && !stack_trace->isEmpty()) {
return SourceLocation::CreateFromNonEmptyV8StackTrace(
- std::move(stack_trace), 0);
+ std::move(stack_trace));
+ }
return std::make_unique<SourceLocation>(String(), 0, 0, nullptr, 0);
}
@@ -167,7 +170,7 @@ void SourceLocation::ToTracedValue(TracedValue* value, const char* name) const {
value->BeginDictionary();
value->SetString("functionName",
ToCoreString(stack_trace_->topFunctionName()));
- value->SetString("scriptId", ToCoreString(stack_trace_->topScriptId()));
+ value->SetInteger("scriptId", stack_trace_->topScriptIdAsInteger());
value->SetString("url", ToCoreString(stack_trace_->topSourceURL()));
value->SetInteger("lineNumber", stack_trace_->topLineNumber());
value->SetInteger("columnNumber", stack_trace_->topColumnNumber());
@@ -175,6 +178,20 @@ void SourceLocation::ToTracedValue(TracedValue* value, const char* name) const {
value->EndArray();
}
+void SourceLocation::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ // TODO(altimin): Consider replacing nested dict-inside-array with just an
+ // array here.
+ auto array = std::move(context).WriteArray();
+ auto dict = array.AppendDictionary();
+ // TODO(altimin): Add TracedValue support to v8::StringView and remove
+ // ToCoreString calls.
+ dict.Add("functionName", ToCoreString(stack_trace_->topFunctionName()));
+ dict.Add("scriptId", stack_trace_->topScriptIdAsInteger());
+ dict.Add("url", ToCoreString(stack_trace_->topSourceURL()));
+ dict.Add("lineNumber", stack_trace_->topLineNumber());
+ dict.Add("columnNumber", stack_trace_->topColumnNumber());
+}
+
std::unique_ptr<SourceLocation> SourceLocation::Clone() const {
return base::WrapUnique(new SourceLocation(
url_.IsolatedCopy(), line_number_, column_number_,
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/source_location.h b/chromium/third_party/blink/renderer/bindings/core/v8/source_location.h
index 3126e04984e..08f41febdf8 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/source_location.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/source_location.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace blink {
@@ -58,10 +59,18 @@ class CORE_EXPORT SourceLocation {
return std::move(stack_trace_);
}
+ bool HasStackTrace() const {
+ return stack_trace_ && !stack_trace_->isEmpty();
+ }
+
// Safe to pass between threads, drops async chain in stack trace.
std::unique_ptr<SourceLocation> Clone() const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
// No-op when stack trace is unknown.
+ // TODO(altimin): Replace all usages of `ToTracedValue` with
+ // `WriteIntoTracedValue` and remove this method.
void ToTracedValue(TracedValue*, const char* name) const;
// Could be null string when stack trace is unknown.
@@ -76,8 +85,7 @@ class CORE_EXPORT SourceLocation {
private:
static std::unique_ptr<SourceLocation> CreateFromNonEmptyV8StackTrace(
- std::unique_ptr<v8_inspector::V8StackTrace>,
- int script_id);
+ std::unique_ptr<v8_inspector::V8StackTrace>);
String url_;
unsigned line_number_;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h
index 40ae6d6650b..60276298c88 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h
@@ -31,14 +31,14 @@ template <typename T>
inline v8::Local<v8::Value> ToV8(NotShared<T> value,
v8::Local<v8::Object> creation_context,
v8::Isolate* isolate) {
- return ToV8(value.View(), creation_context, isolate);
+ return ToV8(value.Get(), creation_context, isolate);
}
template <typename T>
inline v8::Local<v8::Value> ToV8(MaybeShared<T> value,
v8::Local<v8::Object> creation_context,
v8::Isolate* isolate) {
- return ToV8(value.View(), creation_context, isolate);
+ return ToV8(value.Get(), creation_context, isolate);
}
// Dictionary
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h
new file mode 100644
index 00000000000..2233edae858
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h
@@ -0,0 +1,649 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_TO_V8_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_TO_V8_TRAITS_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/idl_dictionary_base.h"
+#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
+#include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
+#include "third_party/blink/renderer/platform/bindings/dictionary_base.h"
+#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
+#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+// ToV8Traits provides C++ -> V8 conversion.
+// Currently, you can use ToV8() which is defined in to_v8.h for this
+// conversion, but it cannot throw an exception when an error occurs.
+// We will solve this problem and replace ToV8() in to_v8.h with
+// ToV8Traits::ToV8().
+// TODO(canonmukai): Replace existing ToV8() with ToV8Traits<>.
+
+// Primary template for ToV8Traits.
+template <typename T, typename SFINAEHelper = void>
+struct ToV8Traits;
+
+// Any
+template <>
+struct ToV8Traits<IDLAny> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const ScriptValue& script_value)
+ WARN_UNUSED_RESULT {
+ DCHECK(!script_value.IsEmpty());
+ return script_value.V8Value();
+ }
+};
+
+// Boolean
+template <>
+struct ToV8Traits<IDLBoolean> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ bool value) WARN_UNUSED_RESULT {
+ return v8::Boolean::New(script_state->GetIsolate(), value);
+ }
+};
+
+// Integer
+// int8_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<int8_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ int8_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::New(script_state->GetIsolate(), value);
+ }
+};
+
+// int16_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<int16_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ int16_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::New(script_state->GetIsolate(), value);
+ }
+};
+
+// int32_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<int32_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ int32_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::New(script_state->GetIsolate(), value);
+ }
+};
+
+// int64_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<int64_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ int64_t value) WARN_UNUSED_RESULT {
+ int32_t value_in_32bit = static_cast<int32_t>(value);
+ if (value_in_32bit == value)
+ return v8::Integer::New(script_state->GetIsolate(), value_in_32bit);
+ // v8::Integer cannot represent 64-bit integers.
+ return v8::Number::New(script_state->GetIsolate(), value);
+ }
+};
+
+// uint8_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<uint8_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ uint8_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::NewFromUnsigned(script_state->GetIsolate(), value);
+ }
+};
+
+// uint16_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<uint16_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ uint16_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::NewFromUnsigned(script_state->GetIsolate(), value);
+ }
+};
+
+// uint32_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<uint32_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ uint32_t value) WARN_UNUSED_RESULT {
+ return v8::Integer::NewFromUnsigned(script_state->GetIsolate(), value);
+ }
+};
+
+// uint64_t
+template <bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLIntegerTypeBase<uint64_t, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ uint64_t value) WARN_UNUSED_RESULT {
+ uint32_t value_in_32bit = static_cast<uint32_t>(value);
+ if (value_in_32bit == value) {
+ return v8::Integer::NewFromUnsigned(script_state->GetIsolate(),
+ value_in_32bit);
+ }
+ // v8::Integer cannot represent 64-bit integers.
+ return v8::Number::New(script_state->GetIsolate(), value);
+ }
+};
+
+// Floating Point Number
+template <typename T, bindings::IDLFloatingPointNumberConvMode mode>
+struct ToV8Traits<IDLFloatingPointNumberTypeBase<T, mode>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T value) WARN_UNUSED_RESULT {
+ return v8::Number::New(script_state->GetIsolate(), value);
+ }
+};
+
+// String
+template <typename T>
+struct ToV8Traits<
+ T,
+ typename std::enable_if_t<std::is_base_of<IDLStringTypeBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const String& value)
+ WARN_UNUSED_RESULT {
+ // if |value| is a null string, V8String() returns an empty string.
+ return V8String(script_state->GetIsolate(), value);
+ }
+};
+
+// Object
+template <>
+struct ToV8Traits<IDLObject> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const ScriptValue& script_value)
+ WARN_UNUSED_RESULT {
+ DCHECK(!script_value.IsEmpty());
+ v8::Local<v8::Value> v8_value = script_value.V8Value();
+ DCHECK(v8_value->IsObject());
+ return v8_value;
+ }
+};
+
+// Promise
+template <>
+struct ToV8Traits<IDLPromise> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const ScriptPromise& script_promise)
+ WARN_UNUSED_RESULT {
+ DCHECK(!script_promise.IsEmpty());
+ return script_promise.V8Value();
+ }
+};
+
+// ScriptWrappable
+
+namespace bindings {
+
+// Helper function for ScriptWrappable
+inline v8::MaybeLocal<v8::Value> ToV8HelperScriptWrappable(
+ ScriptState* script_state,
+ ScriptWrappable* script_wrappable) {
+ CHECK(script_wrappable);
+ v8::Local<v8::Value> wrapper =
+ DOMDataStore::GetWrapper(script_wrappable, script_state->GetIsolate());
+ if (!wrapper.IsEmpty()) {
+ return wrapper;
+ }
+
+ if (!script_wrappable->WrapV2(script_state).ToLocal(&wrapper)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ return wrapper;
+}
+
+// For optimization
+inline v8::MaybeLocal<v8::Value> ToV8HelperScriptWrappable(
+ v8::Isolate* isolate,
+ ScriptWrappable* script_wrappable,
+ v8::Local<v8::Object> creation_context_object) {
+ CHECK(script_wrappable);
+ v8::Local<v8::Value> wrapper =
+ DOMDataStore::GetWrapper(script_wrappable, isolate);
+ if (!wrapper.IsEmpty()) {
+ return wrapper;
+ }
+
+ CHECK(!creation_context_object.IsEmpty());
+ ScriptState* script_state =
+ ScriptState::From(creation_context_object->CreationContext());
+ if (!script_wrappable->WrapV2(script_state).ToLocal(&wrapper)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ return wrapper;
+}
+
+} // namespace bindings
+
+template <typename T>
+struct ToV8Traits<
+ T,
+ typename std::enable_if_t<std::is_base_of<ScriptWrappable, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* script_wrappable)
+ WARN_UNUSED_RESULT {
+ return bindings::ToV8HelperScriptWrappable(script_state, script_wrappable);
+ }
+
+ // This overload is used for the case when a ToV8 caller does not have
+ // |script_state| but has a receiver object (a creation context object)
+ // which is needed to create a wrapper. If a wrapper object corresponding to
+ // the receiver object exists, ToV8 can return it without a call to
+ // CreationContext() which is slow.
+ static v8::MaybeLocal<v8::Value> ToV8(
+ v8::Isolate* isolate,
+ T* script_wrappable,
+ v8::Local<v8::Object> creation_context_object) WARN_UNUSED_RESULT {
+ return bindings::ToV8HelperScriptWrappable(isolate, script_wrappable,
+ creation_context_object);
+ }
+};
+
+// Dictionary
+template <typename T>
+struct ToV8Traits<T,
+ typename std::enable_if_t<
+ std::is_base_of<bindings::DictionaryBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T* dictionary)
+ WARN_UNUSED_RESULT {
+ DCHECK(dictionary);
+ v8::Local<v8::Value> v8_value = dictionary->CreateV8Object(
+ script_state->GetIsolate(), script_state->GetContext()->Global());
+ DCHECK(!v8_value.IsEmpty());
+ return v8_value;
+ }
+};
+
+// Old implementation of Dictionary
+template <typename T>
+struct ToV8Traits<
+ T,
+ typename std::enable_if_t<std::is_base_of<IDLDictionaryBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T* dictionary)
+ WARN_UNUSED_RESULT {
+ DCHECK(dictionary);
+ return dictionary->ToV8Impl(script_state->GetContext()->Global(),
+ script_state->GetIsolate());
+ }
+};
+
+// Callback function
+template <typename T>
+struct ToV8Traits<T,
+ typename std::enable_if_t<
+ std::is_base_of<CallbackFunctionBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* callback) WARN_UNUSED_RESULT {
+ // creation_context (|script_state->GetContext()|) is intentionally ignored.
+ // Callback functions are not wrappers nor clonable. ToV8 on a callback
+ // function must be used only when it's in the same world.
+ DCHECK(callback);
+ DCHECK(&callback->GetWorld() == &script_state->World());
+ return callback->CallbackObject().template As<v8::Value>();
+ }
+};
+
+// Callback interface
+template <typename T>
+struct ToV8Traits<T,
+ typename std::enable_if_t<
+ std::is_base_of<CallbackInterfaceBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* callback) WARN_UNUSED_RESULT {
+ // creation_context (|script_state->GetContext()|) is intentionally ignored.
+ // Callback Interfaces are not wrappers nor clonable. ToV8 on a callback
+ // interface must be used only when it's in the same world.
+ DCHECK(callback);
+ DCHECK(&callback->GetWorld() == &script_state->World());
+ return callback->CallbackObject().template As<v8::Value>();
+ }
+};
+
+// Enumeration
+template <typename T>
+struct ToV8Traits<T,
+ typename std::enable_if_t<
+ std::is_base_of<bindings::EnumerationBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T& enumeration)
+ WARN_UNUSED_RESULT {
+ return V8String(script_state->GetIsolate(), enumeration.AsCStr());
+ }
+};
+
+// NotShared
+template <typename T>
+struct ToV8Traits<NotShared<T>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ NotShared<T> value) WARN_UNUSED_RESULT {
+ return ToV8Traits<T>::ToV8(script_state, value.Get());
+ }
+};
+
+// MaybeShared
+template <typename T>
+struct ToV8Traits<MaybeShared<T>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ MaybeShared<T> value)
+ WARN_UNUSED_RESULT {
+ return ToV8Traits<T>::ToV8(script_state, value.Get());
+ }
+};
+
+// Array
+
+namespace bindings {
+
+// Helper function for IDLSequence
+template <typename ElementIDLType, typename VectorType>
+inline v8::MaybeLocal<v8::Value> ToV8HelperSequence(ScriptState* script_state,
+ const VectorType& vector) {
+ v8::Isolate* isolate = script_state->GetIsolate();
+ v8::Local<v8::Array> array;
+ {
+ v8::Context::Scope context_scope(script_state->GetContext());
+ array = v8::Array::New(isolate, SafeCast<int>(vector.size()));
+ }
+ v8::Local<v8::Context> context = script_state->GetContext();
+ uint32_t index = 0;
+ typename VectorType::const_iterator end = vector.end();
+ for (typename VectorType::const_iterator iter = vector.begin(); iter != end;
+ ++iter) {
+ v8::Local<v8::Value> v8_value;
+ if (!ToV8Traits<ElementIDLType>::ToV8(script_state, *iter)
+ .ToLocal(&v8_value)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ bool is_property_created;
+ if (!array->CreateDataProperty(context, index++, v8_value)
+ .To(&is_property_created) ||
+ !is_property_created) {
+ return v8::Local<v8::Value>();
+ }
+ }
+ return array;
+}
+
+// Helper function for IDLRecord
+template <typename ValueIDLType, typename VectorType>
+inline v8::MaybeLocal<v8::Value> ToV8HelperRecord(ScriptState* script_state,
+ const VectorType& vector) {
+ v8::Isolate* isolate = script_state->GetIsolate();
+ v8::Local<v8::Object> object;
+ {
+ v8::Context::Scope context_scope(script_state->GetContext());
+ object = v8::Object::New(isolate);
+ }
+ v8::Local<v8::Context> context = script_state->GetContext();
+ typename VectorType::const_iterator end = vector.end();
+ for (typename VectorType::const_iterator iter = vector.begin(); iter != end;
+ ++iter) {
+ v8::Local<v8::Value> v8_value;
+ if (!ToV8Traits<ValueIDLType>::ToV8(script_state, iter->second)
+ .ToLocal(&v8_value)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ bool is_property_created;
+ if (!object
+ ->CreateDataProperty(context, V8AtomicString(isolate, iter->first),
+ v8_value)
+ .To(&is_property_created) ||
+ !is_property_created) {
+ return v8::Local<v8::Value>();
+ }
+ }
+ return object;
+}
+
+} // namespace bindings
+
+// IDLSequence
+template <typename T>
+struct ToV8Traits<IDLSequence<T>> {
+ static v8::MaybeLocal<v8::Value> ToV8(
+ ScriptState* script_state,
+ const typename IDLSequence<T>::ImplType& value) {
+ return bindings::ToV8HelperSequence<T>(script_state, value);
+ }
+
+ static v8::MaybeLocal<v8::Value> ToV8(
+ ScriptState* script_state,
+ const typename IDLSequence<T>::ImplType* value) {
+ return bindings::ToV8HelperSequence<T>(script_state, *value);
+ }
+};
+
+// IDLRecord
+// K must be based of IDL String types.
+template <typename K, typename V>
+struct ToV8Traits<IDLRecord<K, V>> {
+ static v8::MaybeLocal<v8::Value> ToV8(
+ ScriptState* script_state,
+ const typename IDLRecord<K, V>::ImplType& value) {
+ return bindings::ToV8HelperRecord<V>(script_state, value);
+ }
+
+ static v8::MaybeLocal<v8::Value> ToV8(
+ ScriptState* script_state,
+ const typename IDLRecord<K, V>::ImplType* value) {
+ return bindings::ToV8HelperRecord<V>(script_state, *value);
+ }
+};
+
+// Nullable
+
+// IDLNullable<IDLNullable<T>> must not be used.
+template <typename T>
+struct ToV8Traits<IDLNullable<IDLNullable<T>>>;
+
+// Nullable Boolean
+template <>
+struct ToV8Traits<IDLNullable<IDLBoolean>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const base::Optional<bool>& value)
+ WARN_UNUSED_RESULT {
+ if (!value)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<IDLBoolean>::ToV8(script_state, *value);
+ }
+};
+
+// Nullable Integers
+template <typename T, bindings::IDLIntegerConvMode mode>
+struct ToV8Traits<IDLNullable<IDLIntegerTypeBase<T, mode>>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const base::Optional<T>& value)
+ WARN_UNUSED_RESULT {
+ if (!value)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<IDLIntegerTypeBase<T, mode>>::ToV8(script_state, *value);
+ }
+};
+
+// Nullable Floating Point Number
+template <typename T, bindings::IDLFloatingPointNumberConvMode mode>
+struct ToV8Traits<IDLNullable<IDLFloatingPointNumberTypeBase<T, mode>>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const base::Optional<T>& value)
+ WARN_UNUSED_RESULT {
+ if (!value)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<IDLFloatingPointNumberTypeBase<T, mode>>::ToV8(
+ script_state, *value);
+ }
+};
+
+// Nullable Strings
+template <typename T>
+struct ToV8Traits<
+ IDLNullable<T>,
+ typename std::enable_if_t<std::is_base_of<IDLStringTypeBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const String& value)
+ WARN_UNUSED_RESULT {
+ if (!value)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, value);
+ }
+};
+
+// Nullable ScriptWrappable
+template <typename T>
+struct ToV8Traits<
+ IDLNullable<T>,
+ typename std::enable_if_t<std::is_base_of<ScriptWrappable, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* script_wrappable)
+ WARN_UNUSED_RESULT {
+ if (!script_wrappable)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, script_wrappable);
+ }
+
+ static v8::MaybeLocal<v8::Value> ToV8(v8::Isolate* isolate,
+ ScriptWrappable* script_wrappable,
+ v8::Local<v8::Object> creation_context)
+ WARN_UNUSED_RESULT {
+ if (!script_wrappable)
+ return v8::Null(isolate);
+ return ToV8Traits<T>::ToV8(isolate, script_wrappable, creation_context);
+ }
+};
+
+// Nullable Dictionary
+template <typename T>
+struct ToV8Traits<IDLNullable<T>,
+ typename std::enable_if_t<
+ std::is_base_of<bindings::DictionaryBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T* dictionary)
+ WARN_UNUSED_RESULT {
+ if (!dictionary)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, dictionary);
+ }
+};
+
+// Nullable Dictionary (Old implementation)
+template <typename T>
+struct ToV8Traits<
+ IDLNullable<T>,
+ typename std::enable_if_t<std::is_base_of<IDLDictionaryBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T* dictionary)
+ WARN_UNUSED_RESULT {
+ if (!dictionary)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, dictionary);
+ }
+};
+
+// Nullable Callback function
+template <typename T>
+struct ToV8Traits<IDLNullable<T>,
+ typename std::enable_if_t<
+ std::is_base_of<CallbackFunctionBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* callback) WARN_UNUSED_RESULT {
+ if (!callback)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, callback);
+ }
+};
+
+// Nullable Callback interface
+template <typename T>
+struct ToV8Traits<IDLNullable<T>,
+ typename std::enable_if_t<
+ std::is_base_of<CallbackInterfaceBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ T* callback) WARN_UNUSED_RESULT {
+ if (!callback)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, callback);
+ }
+};
+
+// Nullable Enumeration
+template <typename T>
+struct ToV8Traits<IDLNullable<T>,
+ typename std::enable_if_t<
+ std::is_base_of<bindings::EnumerationBase, T>::value>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const base::Optional<T>& enumeration)
+ WARN_UNUSED_RESULT {
+ if (!enumeration)
+ return v8::Null(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, *enumeration);
+ }
+};
+
+// Nullable Date
+// IDLDate must be used as IDLNullable<IDLDate>.
+template <>
+struct ToV8Traits<IDLNullable<IDLDate>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const base::Optional<base::Time> date)
+ WARN_UNUSED_RESULT {
+ if (!date)
+ return v8::Null(script_state->GetIsolate());
+ return v8::Date::New(script_state->GetContext(),
+ date->ToJsTimeIgnoringNull())
+ .ToLocalChecked();
+ }
+};
+
+// Union types
+
+namespace bindings {
+
+// Helper function for Union
+template <typename T>
+inline v8::MaybeLocal<v8::Value> ToV8HelperUnion(ScriptState* script_state,
+ const T& value) {
+ return ToV8(value, script_state->GetContext()->Global(),
+ script_state->GetIsolate());
+}
+
+} // namespace bindings
+
+template <typename T>
+struct ToV8Traits<IDLUnionNotINT<T>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T& value) WARN_UNUSED_RESULT {
+ return bindings::ToV8HelperUnion(script_state, value);
+ }
+};
+
+// Optional
+template <typename T>
+struct ToV8Traits<IDLOptional<T>> {
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const T* value) WARN_UNUSED_RESULT {
+ if (!value)
+ return v8::Undefined(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, value);
+ }
+
+ static v8::MaybeLocal<v8::Value> ToV8(ScriptState* script_state,
+ const ScriptValue& value)
+ WARN_UNUSED_RESULT {
+ if (value.IsEmpty())
+ return v8::Undefined(script_state->GetIsolate());
+ return ToV8Traits<T>::ToV8(script_state, value);
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_TO_V8_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits_test.cc
new file mode 100644
index 00000000000..f30f06a51df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/to_v8_traits_test.cc
@@ -0,0 +1,520 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/file_or_usv_string_or_form_data.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_address_space.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_create_html_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/core/testing/garbage_collected_script_wrappable.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/platform/bindings/dictionary_base.h"
+
+namespace blink {
+
+namespace {
+
+#define TEST_TOV8_TRAITS(scope, IDLType, expected, value) \
+ TestToV8Traits<IDLType>(scope, expected, value, __FILE__, __LINE__)
+
+template <typename IDLType, typename T>
+void TestToV8Traits(const V8TestingScope& scope,
+ const String& expected,
+ T value,
+ const char* path,
+ int line_number) {
+ v8::Local<v8::Value> actual;
+ if (!ToV8Traits<IDLType>::ToV8(scope.GetScriptState(), value)
+ .ToLocal(&actual)) {
+ ADD_FAILURE_AT(path, line_number) << "ToV8 throws an exception.";
+ return;
+ }
+ String actual_string =
+ ToCoreString(actual->ToString(scope.GetContext()).ToLocalChecked());
+ if (expected != actual_string) {
+ ADD_FAILURE_AT(path, line_number)
+ << "ToV8 returns an incorrect value.\n Actual: "
+ << actual_string.Utf8() << "\nExpected: " << expected;
+ return;
+ }
+}
+
+TEST(ToV8TraitsTest, Any) {
+ const V8TestingScope scope;
+ ScriptValue value(scope.GetIsolate(),
+ v8::Number::New(scope.GetIsolate(), 1234.0));
+ v8::Local<v8::Value> actual1;
+ ASSERT_TRUE(ToV8Traits<IDLAny>::ToV8(scope.GetScriptState(), value)
+ .ToLocal(&actual1));
+ EXPECT_FALSE(actual1.IsEmpty());
+ double actual_as_number1 = actual1.As<v8::Number>()->Value();
+ EXPECT_EQ(1234.0, actual_as_number1);
+}
+
+TEST(ToV8TraitsTest, Boolean) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLBoolean, "true", true);
+ TEST_TOV8_TRAITS(scope, IDLBoolean, "false", false);
+}
+
+TEST(ToV8TraitsTest, Integer) {
+ const V8TestingScope scope;
+ // Test type matching
+ // Integer
+ TEST_TOV8_TRAITS(scope, IDLByte, "0", static_cast<int8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLByte, "1", static_cast<int8_t>(1));
+ TEST_TOV8_TRAITS(scope, IDLByte, "-2", static_cast<int8_t>(-2));
+ TEST_TOV8_TRAITS(scope, IDLShort, "0", static_cast<int16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLong, "0", static_cast<int32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLongLong, "0", static_cast<int64_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLOctet, "0", static_cast<uint8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedShort, "0", static_cast<uint16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLong, "0", static_cast<uint32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongLong, "0", static_cast<uint64_t>(0));
+ // [Clamp] Integer
+ TEST_TOV8_TRAITS(scope, IDLByteClamp, "0", static_cast<int8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLShortClamp, "0", static_cast<int16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLongClamp, "0", static_cast<int32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLongLongClamp, "0", static_cast<int64_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLOctetClamp, "0", static_cast<uint8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedShortClamp, "0", static_cast<uint16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongClamp, "0", static_cast<uint32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongLongClamp, "0",
+ static_cast<uint64_t>(0));
+ // [EnforceRange] Integer
+ TEST_TOV8_TRAITS(scope, IDLByteEnforceRange, "0", static_cast<int8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLShortEnforceRange, "0", static_cast<int16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLongEnforceRange, "0", static_cast<int32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLLongLongEnforceRange, "0",
+ static_cast<int64_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLOctetEnforceRange, "0", static_cast<uint8_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedShortEnforceRange, "0",
+ static_cast<uint16_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongEnforceRange, "0",
+ static_cast<uint32_t>(0));
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongLongEnforceRange, "0",
+ static_cast<uint64_t>(0));
+
+ // Test the maximum and the minimum integer in the range
+ TEST_TOV8_TRAITS(scope, IDLLong, "-2147483648",
+ std::numeric_limits<int32_t>::min());
+ TEST_TOV8_TRAITS(scope, IDLLong, "2147483647",
+ std::numeric_limits<int32_t>::max());
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLong, "4294967295",
+ std::numeric_limits<uint32_t>::max());
+
+ // v8::Number can represent exact numbers in [-(2^53-1), 2^53-1].
+ TEST_TOV8_TRAITS(scope, IDLLongLong, "-9007199254740991",
+ static_cast<int64_t>(-9007199254740991)); // -(2^53-1)
+ TEST_TOV8_TRAITS(scope, IDLLongLong, "9007199254740991",
+ static_cast<int64_t>(9007199254740991)); // 2^53-1
+ TEST_TOV8_TRAITS(scope, IDLUnsignedLongLong, "9007199254740991",
+ static_cast<uint64_t>(9007199254740991)); // 2^53-1
+}
+
+TEST(ToV8TraitsTest, FloatAndDouble) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLFloat, "0.5", static_cast<float>(0.5));
+ TEST_TOV8_TRAITS(scope, IDLUnrestrictedFloat, "-0.5",
+ static_cast<float>(-0.5));
+ TEST_TOV8_TRAITS(scope, IDLDouble, "0.5", static_cast<double>(0.5));
+ TEST_TOV8_TRAITS(scope, IDLUnrestrictedDouble, "-0.5",
+ static_cast<double>(-0.5));
+ TEST_TOV8_TRAITS(scope, IDLUnrestrictedDouble, "NaN",
+ std::numeric_limits<double>::quiet_NaN());
+ TEST_TOV8_TRAITS(scope, IDLUnrestrictedDouble, "Infinity",
+ std::numeric_limits<double>::infinity());
+ TEST_TOV8_TRAITS(scope, IDLUnrestrictedDouble, "-Infinity",
+ -std::numeric_limits<double>::infinity());
+}
+
+TEST(ToV8TraitsTest, String) {
+ const V8TestingScope scope;
+ const String string("string");
+ const char* const charptr_string = "charptrString";
+ // ByteString
+ TEST_TOV8_TRAITS(scope, IDLByteStringV2, "string", string);
+ TEST_TOV8_TRAITS(scope, IDLByteStringV2, "charptrString", charptr_string);
+ // DOMString
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "string", string);
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "charptrString", charptr_string);
+ TEST_TOV8_TRAITS(scope, IDLStringTreatNullAsEmptyStringV2, "string", string);
+ TEST_TOV8_TRAITS(scope, IDLStringTreatNullAsEmptyStringV2, "charptrString",
+ charptr_string);
+ // USVString
+ TEST_TOV8_TRAITS(scope, IDLUSVStringV2, "string", string);
+ TEST_TOV8_TRAITS(scope, IDLUSVStringV2, "charptrString", charptr_string);
+ // [StringContext=TrustedHTML] DOMString
+ TEST_TOV8_TRAITS(scope, IDLStringStringContextTrustedHTMLV2, "string",
+ string);
+ TEST_TOV8_TRAITS(scope, IDLStringStringContextTrustedHTMLV2, "charptrString",
+ charptr_string);
+ TEST_TOV8_TRAITS(scope,
+ IDLStringStringContextTrustedHTMLTreatNullAsEmptyStringV2,
+ "string", string);
+ TEST_TOV8_TRAITS(scope,
+ IDLStringStringContextTrustedHTMLTreatNullAsEmptyStringV2,
+ "charptrString", charptr_string);
+ // [StringContext=TrustedScript] DOMString
+ TEST_TOV8_TRAITS(scope, IDLStringStringContextTrustedScriptV2, "string",
+ string);
+ TEST_TOV8_TRAITS(scope, IDLStringStringContextTrustedScriptV2,
+ "charptrString", charptr_string);
+ TEST_TOV8_TRAITS(scope,
+ IDLStringStringContextTrustedScriptTreatNullAsEmptyStringV2,
+ "string", string);
+ TEST_TOV8_TRAITS(scope,
+ IDLStringStringContextTrustedScriptTreatNullAsEmptyStringV2,
+ "charptrString", charptr_string);
+ // [StringContext=TrustedScriptURL] USVString
+ TEST_TOV8_TRAITS(scope, IDLUSVStringStringContextTrustedScriptURLV2, "string",
+ string);
+ TEST_TOV8_TRAITS(scope, IDLUSVStringStringContextTrustedScriptURLV2,
+ "charptrString", charptr_string);
+}
+
+TEST(ToV8TraitsTest, EmptyString) {
+ const V8TestingScope scope;
+ const String empty_string("");
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "", empty_string);
+ const char* const empty = "";
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "", empty);
+}
+
+TEST(ToV8TraitsTest, Object) {
+ const V8TestingScope scope;
+ Vector<String> string_vector;
+ string_vector.push_back("hello");
+ string_vector.push_back("world");
+ ScriptValue value(scope.GetIsolate(),
+ ToV8Traits<IDLSequence<IDLStringV2>>::ToV8(
+ scope.GetScriptState(), string_vector));
+ TEST_TOV8_TRAITS(scope, IDLObject, "hello,world", value);
+ v8::Local<v8::Value> actual;
+ ASSERT_TRUE(ToV8Traits<IDLObject>::ToV8(scope.GetScriptState(), value)
+ .ToLocal(&actual));
+ EXPECT_TRUE(actual->IsObject());
+}
+
+TEST(ToV8TraitsTest, Promise) {
+ const V8TestingScope scope;
+ ScriptPromise::InternalResolver resolver(scope.GetScriptState());
+ ScriptPromise promise = resolver.Promise();
+ TEST_TOV8_TRAITS(scope, IDLPromise, "[object Promise]", promise);
+}
+
+TEST(ToV8TraitsTest, NotShared) {
+ const V8TestingScope scope;
+ auto not_shared = NotShared<DOMUint8Array>(DOMUint8Array::Create(2));
+ not_shared->Data()[0] = static_cast<uint8_t>(0);
+ not_shared->Data()[1] = static_cast<uint8_t>(255);
+ TEST_TOV8_TRAITS(scope, NotShared<DOMUint8Array>, "0,255", not_shared);
+}
+
+TEST(ToV8TraitsTest, MaybeShared) {
+ const V8TestingScope scope;
+ auto maybe_shared = MaybeShared<DOMInt8Array>(DOMInt8Array::Create(3));
+ maybe_shared->Data()[0] = static_cast<int8_t>(-128);
+ maybe_shared->Data()[1] = static_cast<int8_t>(0);
+ maybe_shared->Data()[2] = static_cast<int8_t>(127);
+ TEST_TOV8_TRAITS(scope, MaybeShared<DOMInt8Array>, "-128,0,127",
+ maybe_shared);
+}
+
+TEST(ToV8TraitsTest, Vector) {
+ const V8TestingScope scope;
+ Vector<String> string_vector;
+ string_vector.push_back("foo");
+ string_vector.push_back("bar");
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLStringV2>, "foo,bar", string_vector);
+}
+
+TEST(ToV8TraitsTest, HeapVector) {
+ const V8TestingScope scope;
+ HeapVector<Member<GarbageCollectedScriptWrappable>> heap_vector;
+ heap_vector.push_back(
+ MakeGarbageCollected<GarbageCollectedScriptWrappable>("hoge"));
+ heap_vector.push_back(
+ MakeGarbageCollected<GarbageCollectedScriptWrappable>("fuga"));
+ TEST_TOV8_TRAITS(scope, IDLSequence<GarbageCollectedScriptWrappable>,
+ "hoge,fuga", heap_vector);
+
+ HeapVector<Member<GarbageCollectedScriptWrappable>>*
+ garbage_collected_heap_vector = &heap_vector;
+ TEST_TOV8_TRAITS(scope, IDLSequence<GarbageCollectedScriptWrappable>,
+ "hoge,fuga", garbage_collected_heap_vector);
+}
+
+TEST(ToV8TraitsTest, BasicIDLTypeVectors) {
+ const V8TestingScope scope;
+
+ Vector<int32_t> int32_vector;
+ int32_vector.push_back(42);
+ int32_vector.push_back(23);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLLong>, "42,23", int32_vector);
+
+ Vector<int64_t> int64_vector;
+ int64_vector.push_back(31773);
+ int64_vector.push_back(404);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLLongLong>, "31773,404", int64_vector);
+
+ Vector<uint32_t> uint32_vector;
+ uint32_vector.push_back(1);
+ uint32_vector.push_back(2);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLUnsignedLong>, "1,2", uint32_vector);
+
+ Vector<uint64_t> uint64_vector;
+ uint64_vector.push_back(1001);
+ uint64_vector.push_back(2002);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLUnsignedLongLong>, "1001,2002",
+ uint64_vector);
+
+ Vector<float> float_vector;
+ float_vector.push_back(0.125);
+ float_vector.push_back(1.);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLFloat>, "0.125,1", float_vector);
+
+ Vector<double> double_vector;
+ double_vector.push_back(2.3);
+ double_vector.push_back(4.2);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLDouble>, "2.3,4.2", double_vector);
+
+ Vector<bool> bool_vector;
+ bool_vector.push_back(true);
+ bool_vector.push_back(true);
+ bool_vector.push_back(false);
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLBoolean>, "true,true,false",
+ bool_vector);
+}
+
+TEST(ToV8TraitsTest, StringVectorVector) {
+ const V8TestingScope scope;
+
+ Vector<String> string_vector1;
+ string_vector1.push_back("foo");
+ string_vector1.push_back("bar");
+ Vector<String> string_vector2;
+ string_vector2.push_back("quux");
+
+ Vector<Vector<String>> compound_vector;
+ compound_vector.push_back(string_vector1);
+ compound_vector.push_back(string_vector2);
+
+ EXPECT_EQ(2U, compound_vector.size());
+ TEST_TOV8_TRAITS(scope, IDLSequence<IDLSequence<IDLStringV2>>, "foo,bar,quux",
+ compound_vector);
+
+ v8::Local<v8::Value> actual;
+ ASSERT_TRUE(ToV8Traits<IDLSequence<IDLSequence<IDLStringV2>>>::ToV8(
+ scope.GetScriptState(), compound_vector)
+ .ToLocal(&actual))
+ << "ToV8 throws an exception.";
+ v8::Local<v8::Object> result =
+ actual->ToObject(scope.GetContext()).ToLocalChecked();
+ v8::Local<v8::Value> vector1 =
+ result->Get(scope.GetContext(), 0).ToLocalChecked();
+ EXPECT_TRUE(vector1->IsArray());
+ EXPECT_EQ(2U, vector1.As<v8::Array>()->Length());
+ v8::Local<v8::Value> vector2 =
+ result->Get(scope.GetContext(), 1).ToLocalChecked();
+ EXPECT_TRUE(vector2->IsArray());
+ EXPECT_EQ(1U, vector2.As<v8::Array>()->Length());
+}
+
+TEST(ToV8TraitsTest, PairVector) {
+ const V8TestingScope scope;
+ Vector<std::pair<String, int8_t>> pair_vector;
+ pair_vector.push_back(std::make_pair("one", 1));
+ pair_vector.push_back(std::make_pair("two", 2));
+ using ByteRecord = IDLRecord<IDLStringV2, IDLByte>;
+ TEST_TOV8_TRAITS(scope, ByteRecord, "[object Object]", pair_vector);
+ v8::Local<v8::Value> actual;
+ ASSERT_TRUE(ToV8Traits<ByteRecord>::ToV8(scope.GetScriptState(), pair_vector)
+ .ToLocal(&actual))
+ << "ToV8 throws an exception.";
+ v8::Local<v8::Object> result =
+ actual->ToObject(scope.GetContext()).ToLocalChecked();
+ v8::Local<v8::Value> one =
+ result->Get(scope.GetContext(), V8String(scope.GetIsolate(), "one"))
+ .ToLocalChecked();
+ EXPECT_EQ(1, one->NumberValue(scope.GetContext()).FromJust());
+ v8::Local<v8::Value> two =
+ result->Get(scope.GetContext(), V8String(scope.GetIsolate(), "two"))
+ .ToLocalChecked();
+ EXPECT_EQ(2, two->NumberValue(scope.GetContext()).FromJust());
+}
+
+TEST(ToV8TraitsTest, PairHeapVector) {
+ const V8TestingScope scope;
+ HeapVector<std::pair<String, Member<GarbageCollectedScriptWrappable>>>
+ pair_heap_vector;
+ pair_heap_vector.push_back(std::make_pair(
+ "one", MakeGarbageCollected<GarbageCollectedScriptWrappable>("foo")));
+ pair_heap_vector.push_back(std::make_pair(
+ "two", MakeGarbageCollected<GarbageCollectedScriptWrappable>("bar")));
+ using HeapRecord = IDLRecord<IDLStringV2, GarbageCollectedScriptWrappable>;
+ TEST_TOV8_TRAITS(scope, HeapRecord, "[object Object]", pair_heap_vector);
+ v8::Local<v8::Value> actual;
+ ASSERT_TRUE(
+ ToV8Traits<HeapRecord>::ToV8(scope.GetScriptState(), pair_heap_vector)
+ .ToLocal(&actual))
+ << "ToV8 throws an exception.";
+ v8::Local<v8::Object> result =
+ actual->ToObject(scope.GetContext()).ToLocalChecked();
+ v8::Local<v8::Value> one =
+ result->Get(scope.GetContext(), V8String(scope.GetIsolate(), "one"))
+ .ToLocalChecked();
+ EXPECT_TRUE(one->IsObject());
+ EXPECT_EQ(String("foo"),
+ ToCoreString(one->ToString(scope.GetContext()).ToLocalChecked()));
+ v8::Local<v8::Value> two =
+ result->Get(scope.GetContext(), V8String(scope.GetIsolate(), "two"))
+ .ToLocalChecked();
+ EXPECT_TRUE(two->IsObject());
+ EXPECT_EQ(String("bar"),
+ ToCoreString(two->ToString(scope.GetContext()).ToLocalChecked()));
+
+ HeapVector<std::pair<String, Member<GarbageCollectedScriptWrappable>>>*
+ garbage_collected_pair_heap_vector = &pair_heap_vector;
+ TEST_TOV8_TRAITS(scope, HeapRecord, "[object Object]",
+ garbage_collected_pair_heap_vector);
+}
+
+TEST(ToV8TraitsTest, NullStringInputForNoneNullableType) {
+ const V8TestingScope scope;
+ const String null_string;
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "", null_string);
+ const char* const null = nullptr;
+ TEST_TOV8_TRAITS(scope, IDLStringV2, "", null);
+}
+
+TEST(ToV8TraitsTest, Nullable) {
+ const V8TestingScope scope;
+ // Nullable Boolean
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLBoolean>, "null", base::nullopt);
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLBoolean>, "true", true);
+ // Nullable Integer
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLByte>, "null", base::nullopt);
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLUnsignedLong>, "0",
+ base::Optional<uint32_t>(0));
+ // Nullable Float
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLFloat>, "null", base::nullopt);
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLFloat>, "0.5",
+ base::Optional<float>(0.5));
+ // Nullable Double
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLDouble>, "null", base::nullopt);
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLDouble>, "3.14",
+ base::Optional<double>(3.14));
+}
+
+TEST(ToV8TraitsTest, NullableString) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "null", String());
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "string", String("string"));
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "", String(""));
+ const char* const null = nullptr;
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "null", null);
+ const char* const charptr_string = "charptrString";
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "charptrString",
+ charptr_string);
+ const char* const charptr_empty_string = "";
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLStringV2>, "", charptr_empty_string);
+}
+
+TEST(ToV8TraitsTest, NullableScriptWrappable) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<EventTarget>, "null", nullptr);
+ EventTarget* event_target = EventTarget::Create(scope.GetScriptState());
+ TEST_TOV8_TRAITS(scope, IDLNullable<EventTarget>, "[object EventTarget]",
+ event_target);
+}
+
+TEST(ToV8TraitsTest, NullableDictionary) {
+ const V8TestingScope scope;
+ // bindings::DictionaryBase
+ TEST_TOV8_TRAITS(scope, IDLNullable<bindings::DictionaryBase>, "null",
+ nullptr);
+ // IDLDictionaryBase
+ DOMPointInit* dom_point_init = DOMPointInit::Create();
+ TEST_TOV8_TRAITS(scope, IDLNullable<DOMPointInit>, "null", nullptr);
+ TEST_TOV8_TRAITS(scope, IDLNullable<DOMPointInit>, "[object Object]",
+ dom_point_init);
+}
+
+TEST(ToV8TraitsTest, NullableCallbackFunction) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8CreateHTMLCallback>, "null", nullptr);
+ V8CreateHTMLCallback* v8_create_html_callback =
+ V8CreateHTMLCallback::Create(scope.GetContext()->Global());
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8CreateHTMLCallback>, "[object Window]",
+ v8_create_html_callback);
+}
+
+TEST(ToV8TraitsTest, NullableCallbackInterface) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8CreateHTMLCallback>, "null", nullptr);
+ V8EventListener* v8_event_listener =
+ V8EventListener::Create(scope.GetContext()->Global());
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8EventListener>, "[object Window]",
+ v8_event_listener);
+}
+
+TEST(ToV8TraitsTest, NullableEnumeration) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8AddressSpace>, "null", base::nullopt);
+ const base::Optional<V8AddressSpace> v8_address_space =
+ V8AddressSpace::Create("public");
+ TEST_TOV8_TRAITS(scope, IDLNullable<V8AddressSpace>, "public",
+ v8_address_space);
+}
+
+TEST(ToV8TraitsTest, NullableDate) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLNullable<IDLDate>, "null", base::nullopt);
+
+ base::Time expected_date;
+ EXPECT_TRUE(
+ base::Time::FromString("Fri, 01 Jan 2021 00:00:00 GMT", &expected_date));
+ v8::Local<v8::Value> result;
+ ASSERT_TRUE(
+ ToV8Traits<IDLNullable<IDLDate>>::ToV8(
+ scope.GetScriptState(), base::Optional<base::Time>(expected_date))
+ .ToLocal(&result));
+ String actual_string =
+ ToCoreString(result->ToString(scope.GetContext()).ToLocalChecked());
+ base::Time actual_date;
+ EXPECT_TRUE(
+ base::Time::FromString(actual_string.Ascii().c_str(), &actual_date));
+ EXPECT_EQ(expected_date, actual_date);
+}
+
+TEST(ToV8TraitsTest, Union) {
+ const V8TestingScope scope;
+ const FileOrUSVStringOrFormData usv_string =
+ FileOrUSVStringOrFormData::FromUSVString("https://example.com/");
+ TEST_TOV8_TRAITS(scope, IDLUnionNotINT<FileOrUSVStringOrFormData>,
+ "https://example.com/", usv_string);
+}
+
+TEST(ToV8TraitsTest, Optional) {
+ const V8TestingScope scope;
+ TEST_TOV8_TRAITS(scope, IDLOptional<DOMPointInit>, "undefined", nullptr);
+ DOMPointInit* dom_point_init = DOMPointInit::Create();
+ TEST_TOV8_TRAITS(scope, IDLOptional<DOMPointInit>, "[object Object]",
+ dom_point_init);
+
+ TEST_TOV8_TRAITS(scope, IDLOptional<IDLAny>, "undefined", ScriptValue());
+ ScriptValue value(scope.GetIsolate(),
+ v8::Number::New(scope.GetIsolate(), 3.14));
+ TEST_TOV8_TRAITS(scope, IDLOptional<IDLAny>, "3.14", value);
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc b/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
index 598bbba548e..375225e2929 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
@@ -236,14 +236,23 @@ void UseCounterCallback(v8::Isolate* isolate,
case v8::Isolate::kRegExpReplaceCalledOnSlowRegExp:
blink_feature = WebFeature::kV8RegExpReplaceCalledOnSlowRegExp;
break;
- case v8::Isolate::kSharedArrayBufferConstructed:
- if (!CurrentExecutionContext(isolate)->CrossOriginIsolatedCapability()) {
+ case v8::Isolate::kSharedArrayBufferConstructed: {
+ ExecutionContext* current_execution_context =
+ CurrentExecutionContext(isolate);
+ if (!current_execution_context->CrossOriginIsolatedCapability()) {
+ // It is performance critical to only file the issue once per context.
+ if (!current_execution_context
+ ->has_filed_shared_array_buffer_creation_issue()) {
+ current_execution_context->FileSharedArrayBufferCreationIssue();
+ }
blink_feature =
WebFeature::kV8SharedArrayBufferConstructedWithoutIsolation;
+ deprecated = true;
} else {
blink_feature = WebFeature::kV8SharedArrayBufferConstructed;
}
break;
+ }
case v8::Isolate::kArrayPrototypeHasElements:
blink_feature = WebFeature::kV8ArrayPrototypeHasElements;
break;
@@ -337,6 +346,9 @@ void UseCounterCallback(v8::Isolate* isolate,
case v8::Isolate::kWasmMultiValue:
blink_feature = WebFeature::kV8WasmMultiValue;
break;
+ case v8::Isolate::kWasmExceptionHandling:
+ blink_feature = WebFeature::kV8WasmExceptionHandling;
+ break;
default:
// This can happen if V8 has added counters that this version of Blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
deleted file mode 100644
index 17ca699336f..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/string_or_element_creation_options.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_document.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_element_registration_options.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_html_element.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_svg_element.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/svg_names.h"
-#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h"
-#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
-#include "third_party/blink/renderer/platform/bindings/v8_private_property.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/wtf/assertions.h"
-
-namespace blink {
-
-const V8PrivateProperty::SymbolKey kPrivatePropertyDocument;
-const V8PrivateProperty::SymbolKey kPrivatePropertyIsInterfacePrototypeObject;
-const V8PrivateProperty::SymbolKey kPrivatePropertyNamespaceURI;
-const V8PrivateProperty::SymbolKey kPrivatePropertyTagName;
-const V8PrivateProperty::SymbolKey kPrivatePropertyType;
-
-static void ConstructCustomElement(const v8::FunctionCallbackInfo<v8::Value>&);
-
-V0CustomElementConstructorBuilder::V0CustomElementConstructorBuilder(
- ScriptState* script_state,
- const ElementRegistrationOptions* options)
- : script_state_(script_state), options_(options), callbacks_(nullptr) {
- DCHECK(script_state_->GetContext() ==
- script_state_->GetIsolate()->GetCurrentContext());
-}
-
-bool V0CustomElementConstructorBuilder::IsFeatureAllowed() const {
- return script_state_->World().IsMainWorld();
-}
-
-bool V0CustomElementConstructorBuilder::ValidateOptions(
- const AtomicString& type,
- QualifiedName& tag_name,
- ExceptionState& exception_state) {
- DCHECK(prototype_.IsEmpty());
-
- v8::TryCatch try_catch(script_state_->GetIsolate());
-
- if (!script_state_->PerContextData()) {
- // FIXME: This should generate an InvalidContext exception at a later point.
- V0CustomElementException::ThrowException(
- V0CustomElementException::kContextDestroyedCheckingPrototype, type,
- exception_state);
- try_catch.ReThrow();
- return false;
- }
-
- // TODO(crbug.com/1070871): ElementRegistrationOptions.prototype has a default
- // value, but we check |hasPrototype()| here for backward compatibility.
- if (options_->hasPrototype() && !options_->prototype().IsNull()) {
- DCHECK(options_->prototype().IsObject());
- prototype_ = options_->prototype().V8Value().As<v8::Object>();
- } else {
- prototype_ = v8::Object::New(script_state_->GetIsolate());
- v8::Local<v8::Object> base_prototype =
- script_state_->PerContextData()->PrototypeForType(
- V8HTMLElement::GetWrapperTypeInfo());
- if (!base_prototype.IsEmpty()) {
- bool set_prototype;
- if (!prototype_->SetPrototype(script_state_->GetContext(), base_prototype)
- .To(&set_prototype) ||
- !set_prototype) {
- return false;
- }
- }
- }
-
- AtomicString namespace_uri = html_names::xhtmlNamespaceURI;
- if (HasValidPrototypeChainFor(V8SVGElement::GetWrapperTypeInfo()))
- namespace_uri = svg_names::kNamespaceURI;
-
- DCHECK(!try_catch.HasCaught());
-
- AtomicString local_name;
-
- if (!options_->extends().IsNull()) {
- local_name = AtomicString(options_->extends().DeprecatedLower());
-
- if (!Document::IsValidName(local_name)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kExtendsIsInvalidName, type,
- exception_state);
- try_catch.ReThrow();
- return false;
- }
- if (V0CustomElement::IsValidName(local_name)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kExtendsIsCustomElementName, type,
- exception_state);
- try_catch.ReThrow();
- return false;
- }
- } else {
- if (namespace_uri == svg_names::kNamespaceURI) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kExtendsIsInvalidName, type,
- exception_state);
- try_catch.ReThrow();
- return false;
- }
- local_name = type;
- }
-
- DCHECK(!try_catch.HasCaught());
- tag_name = QualifiedName(g_null_atom, local_name, namespace_uri);
- return true;
-}
-
-V0CustomElementLifecycleCallbacks*
-V0CustomElementConstructorBuilder::CreateCallbacks() {
- DCHECK(!prototype_.IsEmpty());
-
- v8::TryCatch exception_catcher(script_state_->GetIsolate());
- exception_catcher.SetVerbose(true);
-
- v8::MaybeLocal<v8::Function> created = RetrieveCallback("createdCallback");
- v8::MaybeLocal<v8::Function> attached = RetrieveCallback("attachedCallback");
- v8::MaybeLocal<v8::Function> detached = RetrieveCallback("detachedCallback");
- v8::MaybeLocal<v8::Function> attribute_changed =
- RetrieveCallback("attributeChangedCallback");
-
- callbacks_ = MakeGarbageCollected<V8V0CustomElementLifecycleCallbacks>(
- script_state_, prototype_, created, attached, detached,
- attribute_changed);
- return callbacks_;
-}
-
-v8::MaybeLocal<v8::Function>
-V0CustomElementConstructorBuilder::RetrieveCallback(const char* name) {
- v8::Local<v8::Value> value;
- if (!prototype_
- ->Get(script_state_->GetContext(),
- V8AtomicString(script_state_->GetIsolate(), name))
- .ToLocal(&value) ||
- !value->IsFunction())
- return v8::MaybeLocal<v8::Function>();
- return v8::MaybeLocal<v8::Function>(value.As<v8::Function>());
-}
-
-bool V0CustomElementConstructorBuilder::CreateConstructor(
- Document* document,
- V0CustomElementDefinition* definition,
- ExceptionState& exception_state) {
- DCHECK(!prototype_.IsEmpty());
- DCHECK(constructor_.IsEmpty());
- DCHECK(document);
-
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::Context> context = script_state_->GetContext();
-
- if (!PrototypeIsValid(definition->Descriptor().GetType(), exception_state))
- return false;
-
- const V0CustomElementDescriptor& descriptor = definition->Descriptor();
-
- v8::Local<v8::String> v8_tag_name = V8String(isolate, descriptor.LocalName());
- v8::Local<v8::Value> v8_type;
- if (descriptor.IsTypeExtension())
- v8_type = V8String(isolate, descriptor.GetType());
- else
- v8_type = v8::Null(isolate);
-
- v8::Local<v8::Object> data = v8::Object::New(isolate);
- V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyDocument)
- .Set(data, ToV8(document, context->Global(), isolate));
- V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyNamespaceURI)
- .Set(data, V8String(isolate, descriptor.NamespaceURI()));
- V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyTagName)
- .Set(data, v8_tag_name);
- V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyType)
- .Set(data, v8_type);
-
- v8::Local<v8::FunctionTemplate> constructor_template =
- v8::FunctionTemplate::New(isolate);
- constructor_template->SetCallHandler(ConstructCustomElement, data);
- if (!constructor_template->GetFunction(context).ToLocal(&constructor_)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kContextDestroyedRegisteringDefinition,
- definition->Descriptor().GetType(), exception_state);
- return false;
- }
-
- constructor_->SetName(v8_type->IsNull() ? v8_tag_name
- : v8_type.As<v8::String>());
-
- v8::Local<v8::String> prototype_key = V8AtomicString(isolate, "prototype");
- bool has_own_property;
- if (!constructor_->HasOwnProperty(context, prototype_key)
- .To(&has_own_property) ||
- !has_own_property) {
- return false;
- }
-
- // This sets the property *value*; calling Set is safe because
- // "prototype" is a non-configurable data property so there can be
- // no side effects.
- bool set_prototype_key;
- if (!constructor_->Set(context, prototype_key, prototype_)
- .To(&set_prototype_key) ||
- !set_prototype_key) {
- return false;
- }
-
- // This *configures* the property. DefineOwnProperty of a function's
- // "prototype" does not affect the value, but can reconfigure the
- // property.
- bool configured_prototype;
- if (!constructor_
- ->DefineOwnProperty(
- context, prototype_key, prototype_,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontEnum |
- v8::DontDelete))
- .To(&configured_prototype) ||
- !configured_prototype) {
- return false;
- }
-
- v8::Local<v8::String> constructor_key =
- V8AtomicString(isolate, "constructor");
- v8::Local<v8::Value> constructor_prototype;
- if (!prototype_->Get(context, constructor_key)
- .ToLocal(&constructor_prototype)) {
- return false;
- }
-
- bool set_prototype;
- if (!constructor_->SetPrototype(context, constructor_prototype)
- .To(&set_prototype) ||
- !set_prototype) {
- return false;
- }
-
- V8PrivateProperty::GetSymbol(isolate,
- kPrivatePropertyIsInterfacePrototypeObject)
- .Set(prototype_, v8::True(isolate));
-
- bool configured_constructor;
- if (!prototype_
- ->DefineOwnProperty(context, constructor_key, constructor_,
- v8::DontEnum)
- .To(&configured_constructor) ||
- !configured_constructor) {
- return false;
- }
-
- return true;
-}
-
-bool V0CustomElementConstructorBuilder::PrototypeIsValid(
- const AtomicString& type,
- ExceptionState& exception_state) const {
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::Context> context = script_state_->GetContext();
-
- if (prototype_->InternalFieldCount() ||
- V8PrivateProperty::GetSymbol(isolate,
- kPrivatePropertyIsInterfacePrototypeObject)
- .HasValue(prototype_)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kPrototypeInUse, type, exception_state);
- return false;
- }
-
- v8::PropertyAttribute property_attribute;
- if (!prototype_
- ->GetPropertyAttributes(context,
- V8AtomicString(isolate, "constructor"))
- .To(&property_attribute) ||
- (property_attribute & v8::DontDelete)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kConstructorPropertyNotConfigurable, type,
- exception_state);
- return false;
- }
-
- return true;
-}
-
-bool V0CustomElementConstructorBuilder::DidRegisterDefinition() const {
- DCHECK(!constructor_.IsEmpty());
-
- return callbacks_->SetBinding(std::make_unique<V0CustomElementBinding>(
- script_state_->GetIsolate(), prototype_));
-}
-
-ScriptValue V0CustomElementConstructorBuilder::BindingsReturnValue() const {
- return ScriptValue(script_state_->GetIsolate(), constructor_);
-}
-
-bool V0CustomElementConstructorBuilder::HasValidPrototypeChainFor(
- const WrapperTypeInfo* type) const {
- v8::Local<v8::Object> element_prototype =
- script_state_->PerContextData()->PrototypeForType(type);
- if (element_prototype.IsEmpty())
- return false;
-
- v8::Local<v8::Value> chain = prototype_;
- while (!chain.IsEmpty() && chain->IsObject()) {
- if (chain == element_prototype)
- return true;
- chain = chain.As<v8::Object>()->GetPrototype();
- }
-
- return false;
-}
-
-static void ConstructCustomElement(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- v8::Isolate* isolate = info.GetIsolate();
-
- if (!info.IsConstructCall()) {
- V8ThrowException::ThrowTypeError(
- isolate, "DOM object constructor cannot be called as a function.");
- return;
- }
-
- if (info.Length() > 0) {
- V8ThrowException::ThrowTypeError(
- isolate, "This constructor should be called without arguments.");
- return;
- }
-
- v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(info.Data());
- v8::Local<v8::Value> document_value;
- if (!V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyDocument)
- .GetOrUndefined(data)
- .ToLocal(&document_value)) {
- return;
- }
- Document* document = V8Document::ToImpl(document_value.As<v8::Object>());
- v8::Local<v8::Value> namespace_uri_value;
- if (!V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyNamespaceURI)
- .GetOrUndefined(data)
- .ToLocal(&namespace_uri_value) ||
- namespace_uri_value->IsUndefined()) {
- return;
- }
- TOSTRING_VOID(V8StringResource<>, namespace_uri, namespace_uri_value);
- v8::Local<v8::Value> tag_name_value;
- if (!V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyTagName)
- .GetOrUndefined(data)
- .ToLocal(&tag_name_value) ||
- tag_name_value->IsUndefined()) {
- return;
- }
- TOSTRING_VOID(V8StringResource<>, tag_name, tag_name_value);
- v8::Local<v8::Value> maybe_type;
- if (!V8PrivateProperty::GetSymbol(isolate, kPrivatePropertyType)
- .GetOrUndefined(data)
- .ToLocal(&maybe_type) ||
- maybe_type->IsUndefined()) {
- return;
- }
- TOSTRING_VOID(V8StringResource<kTreatNullAsNullString>, type, maybe_type);
-
- ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
- "CustomElement");
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
- Element* element = document->createElementNS(
- namespace_uri, tag_name, StringOrElementCreationOptions::FromString(type),
- exception_state);
- if (element) {
- UseCounter::Count(document, WebFeature::kV0CustomElementsConstruct);
- }
- V8SetReturnValueFast(info, element, document);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h b/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h
deleted file mode 100644
index 7e02e872243..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V0_CUSTOM_ELEMENT_CONSTRUCTOR_BUILDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V0_CUSTOM_ELEMENT_CONSTRUCTOR_BUILDER_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/core/dom/qualified_name.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class V0CustomElementDefinition;
-class Document;
-class ElementRegistrationOptions;
-class ExceptionState;
-class QualifiedName;
-struct WrapperTypeInfo;
-
-// Handles the scripting-specific parts of the Custom Elements element
-// registration algorithm and constructor generation algorithm. It is
-// used in the implementation of those algorithms in
-// Document::registerElement.
-class V0CustomElementConstructorBuilder {
- STACK_ALLOCATED();
-
- public:
- V0CustomElementConstructorBuilder(ScriptState*,
- const ElementRegistrationOptions*);
-
- // The builder accumulates state and may run script at specific
- // points. These methods must be called in order. When one fails
- // (returns false), the calls must stop.
-
- bool IsFeatureAllowed() const;
- bool ValidateOptions(const AtomicString& type,
- QualifiedName& tag_name,
- ExceptionState&);
- V0CustomElementLifecycleCallbacks* CreateCallbacks();
- bool CreateConstructor(Document*,
- V0CustomElementDefinition*,
- ExceptionState&);
- bool DidRegisterDefinition() const;
-
- // This method collects a return value for the bindings. It is
- // safe to call this method even if the builder failed; it will
- // return an empty value.
- ScriptValue BindingsReturnValue() const;
-
- private:
- bool HasValidPrototypeChainFor(const WrapperTypeInfo*) const;
- bool PrototypeIsValid(const AtomicString& type, ExceptionState&) const;
- v8::MaybeLocal<v8::Function> RetrieveCallback(const char* name);
-
- ScriptState* script_state_;
- const ElementRegistrationOptions* options_;
- v8::Local<v8::Object> prototype_;
- v8::Local<v8::Function> constructor_;
- V8V0CustomElementLifecycleCallbacks* callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementConstructorBuilder);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V0_CUSTOM_ELEMENT_CONSTRUCTOR_BUILDER_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index 8327721aed9..8dd0021d59e 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "base/debug/dump_without_crashing.h"
#include "third_party/blink/renderer/bindings/core/v8/custom/v8_custom_xpath_ns_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
@@ -768,8 +769,10 @@ v8::Local<v8::Context> ToV8ContextEvenIfDetached(LocalFrame* frame,
// TODO(crbug.com/1046282): The following bailout is a temporary fix
// introduced due to crbug.com/1037985 . Remove this temporary fix once
// the root cause is fixed.
- if (frame->IsProvisional())
+ if (frame->IsProvisional()) {
+ base::debug::DumpWithoutCrashing();
return v8::Local<v8::Context>();
+ }
return frame->WindowProxy(world)->ContextIfInitialized();
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.cc
index 6f3c53ccbb6..e63324ce04c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.cc
@@ -18,7 +18,8 @@ std::unique_ptr<DummyPageHolder> V8TestingScope::CreateDummyPageHolder(
std::unique_ptr<DummyPageHolder> holder = std::make_unique<DummyPageHolder>();
if (url.IsValid()) {
holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h
index 77087972d7c..04984552064 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h
@@ -77,10 +77,12 @@ class BindingTestSupportingGC : public testing::Test {
v8::Isolate::GarbageCollectionType::kMinorGarbageCollection);
}
- void RunV8FullGC(v8::EmbedderHeapTracer::EmbedderStackState stack_state =
- v8::EmbedderHeapTracer::EmbedderStackState::kEmpty) {
+ void RunV8FullGC(
+ v8::EmbedderHeapTracer::EmbedderStackState stack_state =
+ v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers) {
ThreadState::Current()->CollectAllGarbageForTesting(
- stack_state == v8::EmbedderHeapTracer::EmbedderStackState::kEmpty
+ stack_state ==
+ v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers
? BlinkGC::kNoHeapPointersOnStack
: BlinkGC::kHeapPointersOnStack);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
index 44c11826e21..0f9959905b6 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_code_cache.cc
@@ -321,17 +321,14 @@ scoped_refptr<CachedMetadata> V8CodeCache::GenerateFullCodeCache(
ReferrerScriptInfo referrer_info;
v8::ScriptOrigin origin(
V8String(isolate, file_name),
- v8::Integer::New(isolate, 0), // line_offset
- v8::Integer::New(isolate, 0), // column_offset
- v8::Boolean::New(
- isolate,
- opaque_mode == OpaqueMode::kNotOpaque), // is_shared_cross_origin
- v8::Local<v8::Integer>(), // script_id
- V8String(isolate, String("")), // source_map_url
- v8::Boolean::New(isolate,
- opaque_mode == OpaqueMode::kOpaque), // is_opaque
- v8::False(isolate), // is_wasm
- v8::False(isolate), // is_module
+ 0, // line_offset
+ 0, // column_offset
+ opaque_mode == OpaqueMode::kNotOpaque, // is_shared_cross_origin
+ -1, // script_id
+ V8String(isolate, String("")), // source_map_url
+ opaque_mode == OpaqueMode::kOpaque, // is_opaque
+ false, // is_wasm
+ false, // is_module
referrer_info.ToV8HostDefinedOptions(isolate));
v8::Local<v8::String> code(V8String(isolate, script_string));
v8::ScriptCompiler::Source source(code, origin);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
index 39f20c54149..54ed4ad1b4a 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.cc
@@ -205,11 +205,10 @@ CreateAccessorFunctionOrTemplate<v8::FunctionTemplate>(
} else {
function_template = v8::FunctionTemplate::New(
isolate, callback, data, signature, length,
- v8::ConstructorBehavior::kAllow, side_effect_type);
+ v8::ConstructorBehavior::kThrow, side_effect_type);
}
if (!function_template.IsEmpty()) {
- function_template->RemovePrototype();
function_template->SetAcceptAnyReceiver(
access_check_configuration == V8DOMConfiguration::kDoNotCheckAccess);
@@ -485,12 +484,10 @@ void InstallMethodInternal(v8::Isolate* isolate,
: v8::SideEffectType::kHasSideEffect;
if (method.property_location_configuration &
(V8DOMConfiguration::kOnInstance | V8DOMConfiguration::kOnPrototype)) {
- // TODO(luoe): use ConstructorBehavior::kThrow for non-constructor methods.
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(
isolate, callback, v8::Local<v8::Value>(), signature, method.length,
- v8::ConstructorBehavior::kAllow, side_effect_type, v8_c_function);
- function_template->RemovePrototype();
+ v8::ConstructorBehavior::kThrow, side_effect_type, v8_c_function);
function_template->SetAcceptAnyReceiver(
method.access_check_configuration ==
V8DOMConfiguration::kDoNotCheckAccess);
@@ -510,13 +507,11 @@ void InstallMethodInternal(v8::Isolate* isolate,
// Operations installed on the interface object must be static methods, so
// no need to specify a signature, i.e. no need to do type check against a
// holder.
- // TODO(luoe): use ConstructorBehavior::kThrow for non-constructor methods.
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(isolate, callback, v8::Local<v8::Value>(),
v8::Local<v8::Signature>(), method.length,
- v8::ConstructorBehavior::kAllow,
+ v8::ConstructorBehavior::kThrow,
side_effect_type);
- function_template->RemovePrototype();
// Similarly, there is no need to do an access check for static methods, as
// there is no holder to check against.
AddMethodToTemplate(isolate, interface_template, function_template, method);
@@ -554,12 +549,10 @@ void InstallMethodInternal(
DCHECK(location);
if (location &
(V8DOMConfiguration::kOnInstance | V8DOMConfiguration::kOnPrototype)) {
- // TODO(luoe): use ConstructorBehavior::kThrow for non-constructor methods.
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(
isolate, callback, v8::Local<v8::Value>(), signature, config.length,
- v8::ConstructorBehavior::kAllow, side_effect_type);
- function_template->RemovePrototype();
+ v8::ConstructorBehavior::kThrow, side_effect_type);
function_template->SetAcceptAnyReceiver(
config.access_check_configuration ==
V8DOMConfiguration::kDoNotCheckAccess);
@@ -586,13 +579,11 @@ void InstallMethodInternal(
// Operations installed on the interface object must be static
// operations, so no need to specify a signature, i.e. no need to do
// type check against a holder.
- // TODO(luoe): use ConstructorBehavior::kThrow for non-constructor methods.
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(isolate, callback, v8::Local<v8::Value>(),
v8::Local<v8::Signature>(), config.length,
- v8::ConstructorBehavior::kAllow,
+ v8::ConstructorBehavior::kThrow,
side_effect_type);
- function_template->RemovePrototype();
v8::Local<v8::Function> function =
function_template->GetFunction(isolate->GetCurrentContext())
.ToLocalChecked();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
index 86780b6d16f..94a956b339b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.h"
#include <memory>
+#include <sstream>
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
@@ -16,6 +17,17 @@
#include "third_party/blink/renderer/platform/heap/unified_heap_controller.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+
+#if BUILDFLAG(USE_V8_OILPAN)
+
+namespace blink {
+void EmbedderGraphBuilder::BuildEmbedderGraphCallback(v8::Isolate* isolate,
+ v8::EmbedderGraph* graph,
+ void*) {}
+} // namespace blink
+
+#else // !USE_V8_OILPAN
namespace blink {
@@ -65,10 +77,19 @@ class EmbedderNode : public Graph::Node {
Graph::Node* WrapperNode() override { return wrapper_; }
Detachedness GetDetachedness() override { return detachedness_; }
+ void AddEdgeName(std::unique_ptr<char[]> edge_name) {
+ edge_names_.push_back(std::move(edge_name));
+ }
+
private:
const char* name_;
Graph::Node* wrapper_;
const Detachedness detachedness_;
+ // V8's API uses raw strings for edge names and expect the underlying memory
+ // to be retained until the end of graph building where strings are copied
+ // into its internal storage. The following vector retains those edge names
+ // until a node is freed which is at the end of graph building.
+ Vector<std::unique_ptr<char[]>> edge_names_;
};
class EmbedderRootNode : public EmbedderNode {
@@ -77,14 +98,6 @@ class EmbedderRootNode : public EmbedderNode {
: EmbedderNode(name, nullptr, Detachedness::kUnknown) {}
// Graph::Node override.
bool IsRootNode() override { return true; }
-
- void AddEdgeName(std::unique_ptr<const char> edge_name) {
- edge_names_.insert(std::move(edge_name));
- }
-
- private:
- // Storage to hold edge names until they have been internalized by V8.
- HashSet<std::unique_ptr<const char>> edge_names_;
};
class NodeBuilder final {
@@ -183,13 +196,17 @@ class GC_PLUGIN_IGNORE(
public:
ParentScope(V8EmbedderGraphBuilder* visitor, Traceable traceable)
- : visitor_(visitor) {
+ : visitor_(visitor), old_parent_(visitor->current_parent_) {
visitor->current_parent_ = traceable;
}
- ~ParentScope() { visitor_->current_parent_ = nullptr; }
+ ~ParentScope() { visitor_->current_parent_ = old_parent_; }
+
+ ParentScope(const ParentScope&) = delete;
+ ParentScope& operator=(const ParentScope&) = delete;
private:
V8EmbedderGraphBuilder* const visitor_;
+ Traceable old_parent_;
};
class State final {
@@ -217,12 +234,12 @@ class GC_PLUGIN_IGNORE(
return node_;
}
- void AddEdge(State* destination, std::string edge_name) {
+ void AddEdgeName(State* destination, std::string edge_name) {
auto result = named_edges_.insert(destination, std::move(edge_name));
DCHECK(result.is_new_entry);
}
- void AddRootEdge(State* destination, std::string edge_name) {
+ void AddRootEdgeName(State* destination, std::string edge_name) {
// State may represent root groups in which case there may exist multiple
// references to the same |destination|.
named_edges_.insert(destination, std::move(edge_name));
@@ -307,10 +324,12 @@ class GC_PLUGIN_IGNORE(
class EphemeronItem final {
public:
- EphemeronItem(Traceable key,
+ EphemeronItem(Traceable backing,
+ Traceable key,
Traceable value,
TraceCallback value_tracing_callback)
- : key_(key),
+ : backing_(backing),
+ key_(key),
value_(value),
value_tracing_callback_(value_tracing_callback) {}
@@ -322,13 +341,16 @@ class GC_PLUGIN_IGNORE(
if (!builder->StateExists(key_))
return false;
{
- TraceValuesScope scope(builder, key_);
+ ParentScope scope(builder, key_);
+ builder->current_ephemeron_backing_ = backing_;
value_tracing_callback_(builder, const_cast<void*>(value_));
+ builder->current_ephemeron_backing_ = nullptr;
}
return true;
}
private:
+ Traceable backing_;
Traceable key_;
Traceable value_;
TraceCallback value_tracing_callback_;
@@ -365,6 +387,7 @@ class GC_PLUGIN_IGNORE(
}
void AddEdge(State*, State*);
+ void AddEphemeronEdgeName(Traceable backing, State* parent, State* current);
void VisitPersistentHandleInternal(v8::Local<v8::Object>, uint16_t);
void VisitPendingActivities();
@@ -390,27 +413,12 @@ class GC_PLUGIN_IGNORE(
}
}
- class TraceValuesScope final {
- STACK_ALLOCATED();
- DISALLOW_COPY_AND_ASSIGN(TraceValuesScope);
-
- public:
- explicit TraceValuesScope(V8EmbedderGraphBuilder* graph_builder,
- Traceable key)
- : graph_builder_(graph_builder) {
- graph_builder_->current_parent_ = key;
- }
- ~TraceValuesScope() { graph_builder_->current_parent_ = nullptr; }
-
- private:
- V8EmbedderGraphBuilder* const graph_builder_;
- };
-
v8::Isolate* const isolate_;
Graph* const graph_;
NodeBuilder* const node_builder_;
Traceable current_parent_ = nullptr;
+ Traceable current_ephemeron_backing_ = nullptr;
HashMap<Traceable, State*> states_;
// Worklist that is used to visit transitive closure.
Deque<std::unique_ptr<WorklistItemBase>> worklist_;
@@ -519,11 +527,42 @@ void V8EmbedderGraphBuilder::VisitRoot(const void* object,
State* const current = GetOrCreateState(
traceable, HeapObjectHeader::FromPayload(traceable)->Name(),
Detachedness::kUnknown);
- parent->AddRootEdge(current, location.ToString());
+ parent->AddRootEdgeName(current, location.ToString());
}
Visit(object, wrapper_descriptor);
}
+void V8EmbedderGraphBuilder::AddEphemeronEdgeName(Traceable backing,
+ State* parent,
+ State* current) {
+ const GCInfo& backing_info = GCInfo::From(
+ HeapObjectHeader::FromPayload(current_ephemeron_backing_)->GcInfoIndex());
+ HeapObjectName backing_name = backing_info.name(current_ephemeron_backing_);
+ std::stringstream ss;
+ ss << "part of key -> value pair in ephemeron table";
+ if (!backing_name.name_is_hidden) {
+ const std::string backing_name_str(backing_name.value);
+ const auto kvp_pos = backing_name_str.find("WTF::KeyValuePair");
+ // Ephemerons are defined through WTF::KeyValuePair.
+ CHECK_NE(std::string::npos, kvp_pos);
+ // Extracting the pair TYPE from for WTF::KeyValuePair<TYPE>.
+ ss << " (<";
+ size_t current_pos = kvp_pos + sizeof("WTF::KeyValuePair");
+ CHECK_EQ('<', backing_name_str[current_pos - 1]);
+ size_t nesting = 0;
+ while (backing_name_str[current_pos] != '>' || (nesting > 0)) {
+ if (backing_name_str[current_pos] == '<')
+ nesting++;
+ if (backing_name_str[current_pos] == '>')
+ nesting--;
+ ss << backing_name_str[current_pos];
+ current_pos++;
+ }
+ ss << ">)";
+ }
+ parent->AddEdgeName(current, ss.str());
+}
+
void V8EmbedderGraphBuilder::Visit(const void* object,
TraceDescriptor wrapper_descriptor) {
const void* traceable = wrapper_descriptor.base_object_payload;
@@ -534,6 +573,10 @@ void V8EmbedderGraphBuilder::Visit(const void* object,
State* const parent = GetStateNotNull(current_parent_);
State* const current =
GetOrCreateState(traceable, name.value, Detachedness::kUnknown);
+ if (current_ephemeron_backing_) {
+ // Just records an edge name in case the state gets later on materialized.
+ AddEphemeronEdgeName(current_ephemeron_backing_, parent, current);
+ }
if (current->IsPending()) {
if (parent->HasNode()) {
// Backedge in currently processed graph.
@@ -561,21 +604,17 @@ void V8EmbedderGraphBuilder::Visit(const void* object,
void V8EmbedderGraphBuilder::AddEdge(State* parent, State* current) {
EmbedderNode* parent_node = parent->GetOrCreateNode(node_builder_);
EmbedderNode* current_node = current->GetOrCreateNode(node_builder_);
- if (parent_node->IsRootNode()) {
- const std::string edge_name = parent->EdgeName(current);
- if (!edge_name.empty()) {
- // V8's API is based on raw C strings. Allocate and temporarily keep the
- // edge name alive from the corresponding node.
- const size_t len = edge_name.length();
- char* raw_location_string = new char[len + 1];
- strncpy(raw_location_string, edge_name.c_str(), len);
- raw_location_string[len] = 0;
- std::unique_ptr<const char> holder(raw_location_string);
- graph_->AddEdge(parent_node, current_node, holder.get());
- static_cast<EmbedderRootNode*>(parent_node)
- ->AddEdgeName(std::move(holder));
- return;
- }
+ if (!parent->EdgeName(current).empty()) {
+ std::string edge_name = parent->EdgeName(current);
+ // V8's API is based on raw C strings. Allocate and temporarily keep the
+ // edge name alive from the corresponding node.
+ const size_t len = edge_name.length();
+ auto holder = std::make_unique<char[]>(len + 1);
+ strncpy(holder.get(), edge_name.c_str(), len);
+ holder[len] = 0;
+ graph_->AddEdge(parent_node, current_node, holder.get());
+ parent_node->AddEdgeName(std::move(holder));
+ return;
}
graph_->AddEdge(parent_node, current_node);
}
@@ -590,9 +629,14 @@ void V8EmbedderGraphBuilder::VisitWeakContainer(
// Only ephemerons have weak callbacks.
if (ephemeron_iteration.callback) {
// Heap snapshot is always run after a GC so we know there are no dead
- // entries in the backing store, thus it safe to trace it strongly.
+ // entries in the backing store. Using the weak descriptor here ensures that
+ // the key is not held alive from the backing store but rather from the
+ // object. A named edge ensures that we make the fact that value was held
+ // alive via ephemeron visible.
if (object) {
- Visit(object, strong_desc);
+ ParentScope parent(this, ephemeron_iteration.base_object_payload);
+ ephemeron_iteration.callback(this,
+ ephemeron_iteration.base_object_payload);
}
}
}
@@ -600,8 +644,10 @@ void V8EmbedderGraphBuilder::VisitWeakContainer(
void V8EmbedderGraphBuilder::VisitEphemeron(
const void* key,
TraceDescriptor value_trace_descriptor) {
+ // During regular visitation of ephemerons, current_parent_ refers to the
+ // backing store.
ephemeron_worklist_.push_back(std::make_unique<EphemeronItem>(
- key, value_trace_descriptor.base_object_payload,
+ current_parent_, key, value_trace_descriptor.base_object_payload,
value_trace_descriptor.callback));
}
@@ -687,3 +733,5 @@ void EmbedderGraphBuilder::BuildEmbedderGraphCallback(v8::Isolate* isolate,
}
} // namespace blink
+
+#endif // !USE_V8_OILPAN
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index d36cb64149c..576f82e2406 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -53,6 +53,7 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -75,23 +76,29 @@ Node* V8GCController::OpaqueRootForGC(v8::Isolate*, Node* node) {
return node;
}
+#if !BUILDFLAG(USE_V8_OILPAN)
namespace {
-
bool IsNestedInV8GC(ThreadState* thread_state, v8::GCType type) {
return thread_state && (type == v8::kGCTypeMarkSweepCompact ||
type == v8::kGCTypeIncrementalMarking);
}
-
} // namespace
+#endif // !USE_V8_OILPAN
void V8GCController::GcPrologue(v8::Isolate* isolate,
v8::GCType type,
v8::GCCallbackFlags flags) {
RUNTIME_CALL_TIMER_SCOPE(isolate, RuntimeCallStats::CounterId::kGcPrologue);
+#if !BUILDFLAG(USE_V8_OILPAN)
ThreadHeapStatsCollector::BlinkGCInV8Scope nested_scope(
IsNestedInV8GC(ThreadState::Current(), type)
? ThreadState::Current()->Heap().stats_collector()
: nullptr);
+#endif // !USE_V8_OILPAN
+
+ auto* per_isolate_data = V8PerIsolateData::From(isolate);
+ per_isolate_data->EnterGC();
+
ScriptForbiddenScope::Enter();
// Attribute garbage collection to the all frames instead of a specific
@@ -105,14 +112,12 @@ void V8GCController::GcPrologue(v8::Isolate* isolate,
case v8::kGCTypeIncrementalMarking:
// Recomputing ASWs is opportunistic during incremental marking as they
// only need to be recomputing during the atomic pause for corectness.
- V8PerIsolateData::From(isolate)
- ->GetActiveScriptWrappableManager()
+ per_isolate_data->GetActiveScriptWrappableManager()
->RecomputeActiveScriptWrappables(
ActiveScriptWrappableManager::RecomputeMode::kOpportunistic);
break;
case v8::kGCTypeMarkSweepCompact:
- V8PerIsolateData::From(isolate)
- ->GetActiveScriptWrappableManager()
+ per_isolate_data->GetActiveScriptWrappableManager()
->RecomputeActiveScriptWrappables(
ActiveScriptWrappableManager::RecomputeMode::kRequired);
break;
@@ -125,10 +130,15 @@ void V8GCController::GcEpilogue(v8::Isolate* isolate,
v8::GCType type,
v8::GCCallbackFlags flags) {
RUNTIME_CALL_TIMER_SCOPE(isolate, RuntimeCallStats::CounterId::kGcEpilogue);
+#if !BUILDFLAG(USE_V8_OILPAN)
ThreadHeapStatsCollector::BlinkGCInV8Scope nested_scope(
IsNestedInV8GC(ThreadState::Current(), type)
? ThreadState::Current()->Heap().stats_collector()
: nullptr);
+#endif // !USE_V8_OILPAN
+
+ V8PerIsolateData::From(isolate)->LeaveGC();
+
ScriptForbiddenScope::Exit();
if (BlameContext* blame_context =
@@ -136,17 +146,8 @@ void V8GCController::GcEpilogue(v8::Isolate* isolate,
blame_context->Leave();
ThreadState* current_thread_state = ThreadState::Current();
- if (current_thread_state && !current_thread_state->IsGCForbidden()) {
- if (flags & v8::kGCCallbackFlagForced) {
- // Forces a precise GC at the end of the current event loop. This is
- // required for testing code that cannot use GC internals but rather has
- // to rely on window.gc(). Only schedule additional GCs if the last GC was
- // using conservative stack scanning.
- if (type == v8::kGCTypeScavenge ||
- current_thread_state->RequiresForcedGCForTesting()) {
- current_thread_state->ScheduleForcedGCForTesting();
- }
- }
+ if (current_thread_state) {
+ current_thread_state->NotifyGarbageCollection(type, flags);
}
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
index 0b6066eeb15..a64019b606c 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
@@ -49,7 +49,7 @@ static size_t GetMemoryUsage() {
v8::HeapStatistics v8_heap_statistics;
blink::V8PerIsolateData::MainThreadIsolate()->GetHeapStatistics(
&v8_heap_statistics);
- usage = v8_heap_statistics.total_heap_size();
+ usage += v8_heap_statistics.total_heap_size();
return usage;
}
#endif // defined(OS_ANDROID)
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 3252caf9364..e0f8d19545f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -92,8 +92,7 @@ namespace blink {
static void ReportFatalErrorInMainThread(const char* location,
const char* message) {
- DVLOG(1) << "V8 error: " << message << " (" << location << ").";
- LOG(FATAL);
+ LOG(FATAL) << "V8 error: " << message << " (" << location << ").";
}
static void ReportOOMErrorInMainThread(const char* location, bool is_js_heap) {
@@ -477,20 +476,21 @@ static bool WasmCodeGenerationCheckCallbackInMainThread(
return false;
}
-static bool WasmSimdEnabledCallback(v8::Local<v8::Context> context) {
+static bool WasmExceptionsEnabledCallback(v8::Local<v8::Context> context) {
ExecutionContext* execution_context = ToExecutionContext(context);
if (!execution_context)
return false;
- return RuntimeEnabledFeatures::WebAssemblySimdEnabled(execution_context);
+ return RuntimeEnabledFeatures::WebAssemblyExceptionsEnabled(
+ execution_context);
}
-static bool WasmThreadsEnabledCallback(v8::Local<v8::Context> context) {
+static bool WasmSimdEnabledCallback(v8::Local<v8::Context> context) {
ExecutionContext* execution_context = ToExecutionContext(context);
if (!execution_context)
return false;
- return RuntimeEnabledFeatures::WebAssemblyThreadsEnabled(execution_context);
+ return RuntimeEnabledFeatures::WebAssemblySimdEnabled(execution_context);
}
v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
@@ -554,7 +554,8 @@ static bool WasmInstanceOverride(
static v8::MaybeLocal<v8::Promise> HostImportModuleDynamically(
v8::Local<v8::Context> context,
v8::Local<v8::ScriptOrModule> v8_referrer,
- v8::Local<v8::String> v8_specifier) {
+ v8::Local<v8::String> v8_specifier,
+ v8::Local<v8::FixedArray> v8_import_assertions) {
ScriptState* script_state = ScriptState::From(context);
Modulator* modulator = Modulator::From(script_state);
@@ -599,14 +600,20 @@ static v8::MaybeLocal<v8::Promise> HostImportModuleDynamically(
referrer_resource_url = KURL(NullURL(), referrer_resource_url_str);
}
+ ModuleRequest module_request(
+ specifier, TextPosition(),
+ ModuleRecord::ToBlinkImportAssertions(
+ script_state->GetContext(), v8::Local<v8::Module>(),
+ v8_import_assertions, /*v8_import_assertions_has_positions=*/false));
+
ReferrerScriptInfo referrer_info =
ReferrerScriptInfo::FromV8HostDefinedOptions(
context, v8_referrer->GetHostDefinedOptions());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
- modulator->ResolveDynamically(specifier, referrer_resource_url, referrer_info,
- resolver);
+ modulator->ResolveDynamically(module_request, referrer_resource_url,
+ referrer_info, resolver);
return v8::Local<v8::Promise>::Cast(promise.V8Value());
}
@@ -644,8 +651,8 @@ static void InitializeV8Common(v8::Isolate* isolate) {
isolate->SetUseCounterCallback(&UseCounterCallback);
isolate->SetWasmModuleCallback(WasmModuleOverride);
isolate->SetWasmInstanceCallback(WasmInstanceOverride);
+ isolate->SetWasmExceptionsEnabledCallback(WasmExceptionsEnabledCallback);
isolate->SetWasmSimdEnabledCallback(WasmSimdEnabledCallback);
- isolate->SetWasmThreadsEnabledCallback(WasmThreadsEnabledCallback);
isolate->SetHostImportModuleDynamicallyCallback(HostImportModuleDynamically);
isolate->SetHostInitializeImportMetaObjectCallback(
HostGetImportMetaProperties);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc
index 2fe305a01a9..acbade0fe67 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_metrics.cc
@@ -26,7 +26,7 @@ void V8MetricsRecorder::AddMainThreadEvent(
.SetModuleSize(
ukm::GetExponentialBucketMinForBytes(event.module_size_in_bytes))
.SetFunctionCount(event.function_count)
- .SetWallClockTime(event.wall_clock_time_in_us)
+ .SetWallClockDuration(event.wall_clock_duration_in_us)
.Record(ukm->recorder);
}
@@ -46,7 +46,7 @@ void V8MetricsRecorder::AddMainThreadEvent(
.SetCodeSize(
ukm::GetExponentialBucketMinForBytes(event.code_size_in_bytes))
.SetLiftoffBailoutCount(event.liftoff_bailout_count)
- .SetWallClockTime(event.wall_clock_time_in_us)
+ .SetWallClockDuration(event.wall_clock_duration_in_us)
.Record(ukm->recorder);
}
@@ -59,7 +59,7 @@ void V8MetricsRecorder::AddMainThreadEvent(
ukm::builders::V8_Wasm_ModuleInstantiated(ukm->source_id)
.SetSuccess(event.success ? 1 : 0)
.SetImportedFunctionCount(event.imported_function_count)
- .SetWallClockTime(event.wall_clock_time_in_us)
+ .SetWallClockDuration(event.wall_clock_duration_in_us)
.Record(ukm->recorder);
}
@@ -73,7 +73,7 @@ void V8MetricsRecorder::AddMainThreadEvent(
.SetLazy(event.lazy ? 1 : 0)
.SetCodeSize(
ukm::GetExponentialBucketMinForBytes(event.code_size_in_bytes))
- .SetWallClockTime(event.wall_clock_time_in_us)
+ .SetWallClockDuration(event.wall_clock_duration_in_us)
.Record(ukm->recorder);
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
index cb2fe11556e..9e23d8cbaae 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_object_parser.cc
@@ -38,7 +38,7 @@ bool V8ObjectParser::ParseCSSPropertyList(
return false;
for (const auto& property : properties) {
- CSSPropertyID property_id = cssPropertyID(execution_context, property);
+ CSSPropertyID property_id = CssPropertyID(execution_context, property);
if (property_id == CSSPropertyID::kVariable) {
custom_properties->push_back(std::move(property));
} else if (property_id != CSSPropertyID::kInvalid) {
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
index f6dac9b6d13..29f65c22b3b 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -39,14 +39,18 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_initializer.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/core/execution_context/agent.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/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/script/classic_script.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_script.h"
+#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
@@ -220,16 +224,13 @@ v8::MaybeLocal<v8::Script> V8ScriptRunner::CompileScript(
// NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
// 1, whereas v8 starts at 0.
v8::ScriptOrigin origin(
- V8String(isolate, file_name),
- v8::Integer::New(isolate, script_start_position.line_.ZeroBasedInt()),
- v8::Integer::New(isolate, script_start_position.column_.ZeroBasedInt()),
- v8::Boolean::New(isolate, sanitize_script_errors ==
- SanitizeScriptErrors::kDoNotSanitize),
- v8::Local<v8::Integer>(), V8String(isolate, source.SourceMapUrl()),
- v8::Boolean::New(
- isolate, sanitize_script_errors == SanitizeScriptErrors::kSanitize),
- v8::False(isolate), // is_wasm
- v8::False(isolate), // is_module
+ V8String(isolate, file_name), script_start_position.line_.ZeroBasedInt(),
+ script_start_position.column_.ZeroBasedInt(),
+ sanitize_script_errors == SanitizeScriptErrors::kDoNotSanitize, -1,
+ V8String(isolate, source.SourceMapUrl()),
+ sanitize_script_errors == SanitizeScriptErrors::kSanitize,
+ false, // is_wasm
+ false, // is_module
referrer_info.ToV8HostDefinedOptions(isolate));
if (!*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(kTraceEventCategoryGroup)) {
@@ -250,74 +251,82 @@ v8::MaybeLocal<v8::Script> V8ScriptRunner::CompileScript(
v8::MaybeLocal<v8::Module> V8ScriptRunner::CompileModule(
v8::Isolate* isolate,
- const String& source_text,
- SingleCachedMetadataHandler* cache_handler,
- const String& file_name,
+ const ModuleScriptCreationParams& params,
const TextPosition& start_position,
v8::ScriptCompiler::CompileOptions compile_options,
v8::ScriptCompiler::NoCacheReason no_cache_reason,
const ReferrerScriptInfo& referrer_info) {
+ const String file_name = params.SourceURL();
constexpr const char* kTraceEventCategoryGroup = "v8,devtools.timeline";
TRACE_EVENT_BEGIN1(kTraceEventCategoryGroup, "v8.compileModule", "fileName",
file_name.Utf8());
// |resource_is_shared_cross_origin| is always true and |resource_is_opaque|
// is always false because CORS is enforced to module scripts.
- v8::ScriptOrigin origin(
- V8String(isolate, file_name),
- v8::Integer::New(isolate, start_position.line_.ZeroBasedInt()),
- v8::Integer::New(isolate, start_position.column_.ZeroBasedInt()),
- v8::Boolean::New(isolate, true), // resource_is_shared_cross_origin
- v8::Local<v8::Integer>(), // script id
- v8::String::Empty(isolate), // source_map_url
- v8::Boolean::New(isolate, false), // resource_is_opaque
- v8::False(isolate), // is_wasm
- v8::True(isolate), // is_module
- referrer_info.ToV8HostDefinedOptions(isolate));
-
- v8::Local<v8::String> code = V8String(isolate, source_text);
-
- v8::MaybeLocal<v8::Module> script;
+ v8::ScriptOrigin origin(V8String(isolate, file_name),
+ start_position.line_.ZeroBasedInt(),
+ start_position.column_.ZeroBasedInt(),
+ true, // resource_is_shared_cross_origin
+ -1, // script id
+ v8::String::Empty(isolate), // source_map_url
+ false, // resource_is_opaque
+ false, // is_wasm
+ true, // is_module
+ referrer_info.ToV8HostDefinedOptions(isolate));
+
+ v8::Local<v8::String> code = V8String(isolate, params.GetSourceText());
inspector_compile_script_event::V8CacheResult cache_result;
+ v8::MaybeLocal<v8::Module> script;
+ ScriptStreamer* streamer = params.GetScriptStreamer();
+ if (streamer) {
+ // Final compile call for a streamed compilation.
+ // Streaming compilation may involve use of code cache.
+ // TODO(leszeks): Add compile timer to streaming compilation.
+ DCHECK(streamer->IsFinished());
+ DCHECK(!streamer->IsStreamingSuppressed());
+ script = v8::ScriptCompiler::CompileModule(
+ isolate->GetCurrentContext(), streamer->Source(), code, origin);
+ } else {
+ switch (compile_options) {
+ case v8::ScriptCompiler::kNoCompileOptions:
+ case v8::ScriptCompiler::kEagerCompile: {
+ v8::ScriptCompiler::Source source(code, origin);
+ script = v8::ScriptCompiler::CompileModule(
+ isolate, &source, compile_options, no_cache_reason);
+ break;
+ }
- switch (compile_options) {
- case v8::ScriptCompiler::kNoCompileOptions:
- case v8::ScriptCompiler::kEagerCompile: {
- v8::ScriptCompiler::Source source(code, origin);
- script = v8::ScriptCompiler::CompileModule(
- isolate, &source, compile_options, no_cache_reason);
- break;
- }
-
- case v8::ScriptCompiler::kConsumeCodeCache: {
- // Compile a script, and consume a V8 cache that was generated previously.
- DCHECK(cache_handler);
- v8::ScriptCompiler::CachedData* cached_data =
- V8CodeCache::CreateCachedData(cache_handler);
- v8::ScriptCompiler::Source source(code, origin, cached_data);
- script = v8::ScriptCompiler::CompileModule(
- isolate, &source, compile_options, no_cache_reason);
- if (cached_data->rejected) {
- cache_handler->ClearCachedMetadata(
- CachedMetadataHandler::kClearPersistentStorage);
- } else if (InDiscardExperiment()) {
- // Experimentally free code cache from memory after first use. See
- // http://crbug.com/1045052.
- cache_handler->ClearCachedMetadata(
- CachedMetadataHandler::kDiscardLocally);
+ case v8::ScriptCompiler::kConsumeCodeCache: {
+ // Compile a script, and consume a V8 cache that was generated
+ // previously.
+ SingleCachedMetadataHandler* cache_handler = params.CacheHandler();
+ DCHECK(cache_handler);
+ v8::ScriptCompiler::CachedData* cached_data =
+ V8CodeCache::CreateCachedData(cache_handler);
+ v8::ScriptCompiler::Source source(code, origin, cached_data);
+ script = v8::ScriptCompiler::CompileModule(
+ isolate, &source, compile_options, no_cache_reason);
+ if (cached_data->rejected) {
+ cache_handler->ClearCachedMetadata(
+ CachedMetadataHandler::kClearPersistentStorage);
+ } else if (InDiscardExperiment()) {
+ // Experimentally free code cache from memory after first use. See
+ // http://crbug.com/1045052.
+ cache_handler->ClearCachedMetadata(
+ CachedMetadataHandler::kDiscardLocally);
+ }
+ cache_result.consume_result = base::make_optional(
+ inspector_compile_script_event::V8CacheResult::ConsumeResult(
+ compile_options, cached_data->length, cached_data->rejected));
+ break;
}
- cache_result.consume_result = base::make_optional(
- inspector_compile_script_event::V8CacheResult::ConsumeResult(
- compile_options, cached_data->length, cached_data->rejected));
- break;
}
}
TRACE_EVENT_END1(kTraceEventCategoryGroup, "v8.compileModule", "data",
inspector_compile_script_event::Data(
- file_name, start_position, cache_result, false,
- ScriptStreamer::NotStreamingReason::kModuleScript));
-
+ file_name, start_position, cache_result, streamer,
+ params.NotStreamingReason()));
return script;
}
@@ -370,19 +379,49 @@ v8::MaybeLocal<v8::Value> V8ScriptRunner::RunCompiledScript(
}
ScriptEvaluationResult V8ScriptRunner::CompileAndRunScript(
- v8::Isolate* isolate,
ScriptState* script_state,
- ExecutionContext* execution_context,
- const ScriptSourceCode& source,
- const KURL& base_url,
- SanitizeScriptErrors sanitize_script_errors,
- const ScriptFetchOptions& fetch_options,
- mojom::blink::V8CacheOptions v8_cache_options,
+ ClassicScript* classic_script,
+ ExecuteScriptPolicy policy,
RethrowErrorsOption rethrow_errors) {
- DCHECK_EQ(isolate, script_state->GetIsolate());
+ if (!script_state)
+ return ScriptEvaluationResult::FromClassicNotRun();
+
+ // |script_state->GetContext()| must be initialized here already, typically
+ // due to a WindowProxy() call inside ToScriptState*() that is used to get the
+ // ScriptState.
+
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ DCHECK(execution_context->IsContextThread());
+
+ if (policy == ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled &&
+ !execution_context->CanExecuteScripts(kAboutToExecuteScript)) {
+ return ScriptEvaluationResult::FromClassicNotRun();
+ }
+
+ v8::Isolate* isolate = script_state->GetIsolate();
+ const ScriptSourceCode& source = classic_script->GetScriptSourceCode();
+ const SanitizeScriptErrors sanitize_script_errors =
+ classic_script->GetSanitizeScriptErrors();
LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(execution_context);
+ WorkerOrWorkletGlobalScope* worker_or_worklet_global_scope =
+ DynamicTo<WorkerOrWorkletGlobalScope>(execution_context);
LocalFrame* frame = window ? window->GetFrame() : nullptr;
+
+ if (window && window->document()->IsInitialEmptyDocument()) {
+ window->GetFrame()->Loader().DidAccessInitialDocument();
+ } else if (worker_or_worklet_global_scope) {
+ DCHECK_EQ(
+ script_state,
+ worker_or_worklet_global_scope->ScriptController()->GetScriptState());
+ DCHECK(worker_or_worklet_global_scope->ScriptController()
+ ->IsContextInitialized());
+ DCHECK(worker_or_worklet_global_scope->ScriptController()
+ ->IsReadyToEvaluate());
+ }
+
+ v8::Context::Scope scope(script_state->GetContext());
+
TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
inspector_evaluate_script_event::Data(
frame, source.Url().GetString(), source.StartPosition()));
@@ -403,6 +442,7 @@ ScriptEvaluationResult V8ScriptRunner::CompileAndRunScript(
// Omit storing base URL if it is same as source URL.
// Note: This improves chance of getting into a fast path in
// ReferrerScriptInfo::ToV8HostDefinedOptions.
+ const KURL base_url = classic_script->BaseURL();
KURL stored_base_url = (base_url == source.Url()) ? KURL() : base_url;
// TODO(hiroshige): Remove this code and related use counters once the
@@ -423,8 +463,8 @@ ScriptEvaluationResult V8ScriptRunner::CompileAndRunScript(
break;
}
}
- const ReferrerScriptInfo referrer_info(stored_base_url, fetch_options,
- base_url_source);
+ const ReferrerScriptInfo referrer_info(
+ stored_base_url, classic_script->FetchOptions(), base_url_source);
v8::Local<v8::Script> script;
@@ -432,7 +472,8 @@ ScriptEvaluationResult V8ScriptRunner::CompileAndRunScript(
V8CodeCache::ProduceCacheOptions produce_cache_options;
v8::ScriptCompiler::NoCacheReason no_cache_reason;
std::tie(compile_options, produce_cache_options, no_cache_reason) =
- V8CodeCache::GetCompileOptions(v8_cache_options, source);
+ V8CodeCache::GetCompileOptions(execution_context->GetV8CacheOptions(),
+ source);
v8::MaybeLocal<v8::Value> maybe_result;
if (V8ScriptRunner::CompileScript(script_state, source,
@@ -449,6 +490,8 @@ ScriptEvaluationResult V8ScriptRunner::CompileAndRunScript(
// TODO(crbug/1114601): Investigate whether to check CanContinue() in other
// script evaluation code paths.
if (!try_catch.CanContinue()) {
+ if (worker_or_worklet_global_scope)
+ worker_or_worklet_global_scope->ScriptController()->ForbidExecution();
return ScriptEvaluationResult::FromClassicAborted();
}
@@ -671,6 +714,10 @@ ScriptEvaluationResult V8ScriptRunner::EvaluateModule(
ExecutionContext* execution_context = ExecutionContext::From(script_state);
v8::Isolate* isolate = script_state->GetIsolate();
+ // TODO(crbug.com/1151165): Ideally v8::Context should be entered before
+ // CanExecuteScripts().
+ v8::Context::Scope scope(script_state->GetContext());
+
// <spec step="3">Check if we can run script with settings. If this returns
// "do not run" then return NormalCompletion(empty).</spec>
if (!execution_context->CanExecuteScripts(kAboutToExecuteScript)) {
@@ -683,7 +730,6 @@ ScriptEvaluationResult V8ScriptRunner::EvaluateModule(
v8::MicrotasksScope microtasks_scope(isolate,
ToMicrotaskQueue(execution_context),
v8::MicrotasksScope::kRunMicrotasks);
- ScriptState::EscapableScope scope(script_state);
// Without TLA: <spec step="5">Let evaluationStatus be null.</spec>
ScriptEvaluationResult result = ScriptEvaluationResult::FromModuleNotRun();
@@ -727,11 +773,20 @@ ScriptEvaluationResult V8ScriptRunner::EvaluateModule(
// Do not perform a microtask checkpoint here. A checkpoint is performed
// only after module error handling to ensure proper timing with and
// without top-level await.
+
+ v8::MaybeLocal<v8::Value> maybe_result =
+ record->Evaluate(script_state->GetContext());
+
+ if (!try_catch.CanContinue())
+ return ScriptEvaluationResult::FromModuleAborted();
+
v8::Local<v8::Value> v8_result;
- if (!record->Evaluate(script_state->GetContext()).ToLocal(&v8_result)) {
+ if (!maybe_result.ToLocal(&v8_result)) {
+ DCHECK(try_catch.HasCaught());
result =
ScriptEvaluationResult::FromModuleException(try_catch.Exception());
} else {
+ DCHECK(!try_catch.HasCaught());
result = ScriptEvaluationResult::FromModuleSuccess(v8_result);
}
@@ -775,9 +830,9 @@ ScriptEvaluationResult V8ScriptRunner::EvaluateModule(
}
// <spec step="8">Clean up after running script with settings.</spec>
- // - Partially implement in MicrotaskScope destructor and the
- // - ScriptState::EscapableScope destructor.
- return result.Escape(&scope);
+ // Partially implemented in MicrotaskScope destructor and the
+ // v8::Context::Scope destructor.
+ return result;
}
void V8ScriptRunner::ReportException(v8::Isolate* isolate,
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
index 65b88676e1b..1bf869adf64 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
@@ -26,7 +26,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_SCRIPT_RUNNER_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_SCRIPT_RUNNER_H_
-#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -40,15 +39,19 @@ class TextPosition;
namespace blink {
-class ScriptEvaluationResult;
+class ClassicScript;
class ExecutionContext;
-class KURL;
class ModuleScript;
+class ModuleScriptCreationParams;
class ReferrerScriptInfo;
-class ScriptFetchOptions;
+class ScriptEvaluationResult;
class ScriptSourceCode;
class ScriptState;
-class SingleCachedMetadataHandler;
+
+enum class ExecuteScriptPolicy {
+ kExecuteScriptWhenScriptsDisabled,
+ kDoNotExecuteScriptWhenScriptsDisabled
+};
class CORE_EXPORT V8ScriptRunner final {
STATIC_ONLY(V8ScriptRunner);
@@ -114,23 +117,15 @@ class CORE_EXPORT V8ScriptRunner final {
const ReferrerScriptInfo&);
static v8::MaybeLocal<v8::Module> CompileModule(
v8::Isolate*,
- const String& source,
- SingleCachedMetadataHandler*,
- const String& file_name,
+ const ModuleScriptCreationParams&,
const WTF::TextPosition&,
v8::ScriptCompiler::CompileOptions,
v8::ScriptCompiler::NoCacheReason,
const ReferrerScriptInfo&);
- static ScriptEvaluationResult CompileAndRunScript(
- v8::Isolate*,
- ScriptState*,
- ExecutionContext*,
- const ScriptSourceCode&,
- const KURL&,
- SanitizeScriptErrors,
- const ScriptFetchOptions&,
- mojom::blink::V8CacheOptions,
- RethrowErrorsOption);
+ static ScriptEvaluationResult CompileAndRunScript(ScriptState*,
+ ClassicScript*,
+ ExecuteScriptPolicy,
+ RethrowErrorsOption);
static v8::MaybeLocal<v8::Value> CompileAndRunInternalScript(
v8::Isolate*,
ScriptState*,
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc
index d9d550eed55..53e97a49e2f 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_script_runner_test.cc
@@ -106,7 +106,7 @@ class V8ScriptRunnerTest : public testing::Test {
String code = Code();
ResourceResponse response(Url());
response.SetHttpStatusCode(200);
- resource->SetResponse(response);
+ resource->ResponseReceived(response);
StringUTF8Adaptor code_utf8(code);
resource->AppendData(code_utf8.data(), code_utf8.size());
resource->FinishForTest();
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.cc
deleted file mode 100644
index fb9ec7b35ca..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h"
-
-#include <memory>
-#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_element.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
-#include "third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h"
-#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
-#include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
-
-namespace blink {
-
-#define CALLBACK_LIST(V) \
- V(created, CreatedCallback) \
- V(attached, AttachedCallback) \
- V(detached, DetachedCallback) \
- V(attribute_changed, AttributeChangedCallback)
-
-static V0CustomElementLifecycleCallbacks::CallbackType FlagSet(
- v8::MaybeLocal<v8::Function> attached,
- v8::MaybeLocal<v8::Function> detached,
- v8::MaybeLocal<v8::Function> attribute_changed) {
- // V8 Custom Elements always run created to swizzle prototypes.
- int flags = V0CustomElementLifecycleCallbacks::kCreatedCallback;
-
- if (!attached.IsEmpty())
- flags |= V0CustomElementLifecycleCallbacks::kAttachedCallback;
-
- if (!detached.IsEmpty())
- flags |= V0CustomElementLifecycleCallbacks::kDetachedCallback;
-
- if (!attribute_changed.IsEmpty())
- flags |= V0CustomElementLifecycleCallbacks::kAttributeChangedCallback;
-
- return V0CustomElementLifecycleCallbacks::CallbackType(flags);
-}
-
-V8V0CustomElementLifecycleCallbacks::V8V0CustomElementLifecycleCallbacks(
- ScriptState* script_state,
- v8::Local<v8::Object> prototype,
- v8::MaybeLocal<v8::Function> created,
- v8::MaybeLocal<v8::Function> attached,
- v8::MaybeLocal<v8::Function> detached,
- v8::MaybeLocal<v8::Function> attribute_changed)
- : V0CustomElementLifecycleCallbacks(
- FlagSet(attached, detached, attribute_changed)),
- script_state_(script_state),
- prototype_(script_state->GetIsolate(), prototype){
- v8::Isolate* isolate = script_state->GetIsolate();
- v8::Local<v8::Function> function;
-
-// A given object can only be used as a Custom Element prototype
-// once; see customElementIsInterfacePrototypeObject
-#define SET_PRIVATE_PROPERTY(Maybe, Name) \
- static const V8PrivateProperty::SymbolKey kPrivateProperty##Name; \
- V8PrivateProperty::Symbol symbol##Name = \
- V8PrivateProperty::GetSymbol(isolate, kPrivateProperty##Name); \
- DCHECK(!symbol##Name.HasValue(prototype)); \
- { \
- if (Maybe.ToLocal(&function)) \
- symbol##Name.Set(prototype, function); \
- }
-
- CALLBACK_LIST(SET_PRIVATE_PROPERTY)
-#undef SET_PRIVATE_PROPERTY
-
-#define SET_FIELD(maybe, ignored) \
- if (maybe.ToLocal(&function)) \
- maybe##_.Set(isolate, function);
-
- CALLBACK_LIST(SET_FIELD)
-#undef SET_FIELD
-}
-
-V8PerContextData* V8V0CustomElementLifecycleCallbacks::CreationContextData() {
- if (!script_state_->ContextIsValid())
- return nullptr;
-
- v8::Local<v8::Context> context = script_state_->GetContext();
- if (context.IsEmpty())
- return nullptr;
-
- return V8PerContextData::From(context);
-}
-
-V8V0CustomElementLifecycleCallbacks::~V8V0CustomElementLifecycleCallbacks() =
- default;
-
-bool V8V0CustomElementLifecycleCallbacks::SetBinding(
- std::unique_ptr<V0CustomElementBinding> binding) {
- V8PerContextData* per_context_data = CreationContextData();
- if (!per_context_data)
- return false;
-
- // The context is responsible for keeping the prototype
- // alive. This in turn keeps callbacks alive through hidden
- // references; see CALLBACK_LIST(SET_HIDDEN_VALUE).
- per_context_data->AddCustomElementBinding(std::move(binding));
- return true;
-}
-
-void V8V0CustomElementLifecycleCallbacks::Created(Element* element) {
- // FIXME: callbacks while paused should be queued up for execution to
- // continue then be delivered in order rather than delivered immediately.
- // Bug 329665 tracks similar behavior for other synchronous events.
- if (!script_state_->ContextIsValid())
- return;
-
- element->SetV0CustomElementState(Element::kV0Upgraded);
-
- ScriptState::Scope scope(script_state_);
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::Context> context = script_state_->GetContext();
- v8::Local<v8::Value> receiver_value =
- ToV8(element, context->Global(), isolate);
- if (receiver_value.IsEmpty())
- return;
- v8::Local<v8::Object> receiver = receiver_value.As<v8::Object>();
-
- // Swizzle the prototype of the wrapper.
- v8::Local<v8::Object> prototype = prototype_.NewLocal(isolate);
- bool set_prototype;
- if (prototype.IsEmpty() ||
- !receiver->SetPrototype(context, prototype).To(&set_prototype) ||
- !set_prototype) {
- return;
- }
-
- v8::Local<v8::Function> callback = created_.NewLocal(isolate);
- if (callback.IsEmpty())
- return;
-
- v8::TryCatch exception_catcher(isolate);
- exception_catcher.SetVerbose(true);
- V8ScriptRunner::CallFunction(callback, ExecutionContext::From(script_state_),
- receiver, 0, nullptr, isolate);
-}
-
-void V8V0CustomElementLifecycleCallbacks::Attached(Element* element) {
- Call(attached_, element);
-}
-
-void V8V0CustomElementLifecycleCallbacks::Detached(Element* element) {
- Call(detached_, element);
-}
-
-void V8V0CustomElementLifecycleCallbacks::AttributeChanged(
- Element* element,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) {
- // FIXME: callbacks while paused should be queued up for execution to
- // continue then be delivered in order rather than delivered immediately.
- // Bug 329665 tracks similar behavior for other synchronous events.
- if (!script_state_->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state_);
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::Context> context = script_state_->GetContext();
- v8::Local<v8::Value> receiver = ToV8(element, context->Global(), isolate);
- if (receiver.IsEmpty())
- return;
-
- v8::Local<v8::Function> callback = attribute_changed_.NewLocal(isolate);
- if (callback.IsEmpty())
- return;
-
- v8::Local<v8::Value> argv[] = {
- V8String(isolate, name),
- old_value.IsNull() ? v8::Local<v8::Value>(v8::Null(isolate))
- : v8::Local<v8::Value>(V8String(isolate, old_value)),
- new_value.IsNull() ? v8::Local<v8::Value>(v8::Null(isolate))
- : v8::Local<v8::Value>(V8String(isolate, new_value))};
-
- v8::TryCatch exception_catcher(isolate);
- exception_catcher.SetVerbose(true);
- V8ScriptRunner::CallFunction(callback, ExecutionContext::From(script_state_),
- receiver, base::size(argv), argv, isolate);
-}
-
-void V8V0CustomElementLifecycleCallbacks::Call(
- const TraceWrapperV8Reference<v8::Function>& callback_reference,
- Element* element) {
- // FIXME: callbacks while paused should be queued up for execution to
- // continue then be delivered in order rather than delivered immediately.
- // Bug 329665 tracks similar behavior for other synchronous events.
- if (!script_state_->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state_);
- v8::Isolate* isolate = script_state_->GetIsolate();
- v8::Local<v8::Context> context = script_state_->GetContext();
- v8::Local<v8::Function> callback = callback_reference.NewLocal(isolate);
- if (callback.IsEmpty())
- return;
-
- v8::Local<v8::Value> receiver = ToV8(element, context->Global(), isolate);
- if (receiver.IsEmpty())
- return;
-
- v8::TryCatch exception_catcher(isolate);
- exception_catcher.SetVerbose(true);
- V8ScriptRunner::CallFunction(callback, ExecutionContext::From(script_state_),
- receiver, 0, nullptr, isolate);
-}
-
-void V8V0CustomElementLifecycleCallbacks::Trace(Visitor* visitor) const {
- visitor->Trace(script_state_);
- visitor->Trace(prototype_);
- visitor->Trace(created_);
- visitor->Trace(attached_);
- visitor->Trace(detached_);
- visitor->Trace(attribute_changed_);
- V0CustomElementLifecycleCallbacks::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h b/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h
deleted file mode 100644
index 3376747456a..00000000000
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
-
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class V0CustomElementBinding;
-class V0CustomElementLifecycleCallbacks;
-class Element;
-class V8PerContextData;
-
-class V8V0CustomElementLifecycleCallbacks final
- : public V0CustomElementLifecycleCallbacks {
- public:
- V8V0CustomElementLifecycleCallbacks(
- ScriptState*,
- v8::Local<v8::Object> prototype,
- v8::MaybeLocal<v8::Function> created,
- v8::MaybeLocal<v8::Function> attached,
- v8::MaybeLocal<v8::Function> detached,
- v8::MaybeLocal<v8::Function> attribute_changed);
- ~V8V0CustomElementLifecycleCallbacks() override;
-
- bool SetBinding(std::unique_ptr<V0CustomElementBinding>);
-
- void Trace(Visitor*) const override;
-
- private:
- void Created(Element*) override;
- void Attached(Element*) override;
- void Detached(Element*) override;
- void AttributeChanged(Element*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) override;
-
- void Call(const TraceWrapperV8Reference<v8::Function>& callback_reference,
- Element*);
-
- V8PerContextData* CreationContextData();
-
- Member<ScriptState> script_state_;
- TraceWrapperV8Reference<v8::Object> prototype_;
- TraceWrapperV8Reference<v8::Function> created_;
- TraceWrapperV8Reference<v8::Function> attached_;
- TraceWrapperV8Reference<v8::Function> detached_;
- TraceWrapperV8Reference<v8::Function> attribute_changed_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
index 5ba2f110ca8..eda5ba6c23d 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
@@ -23,8 +23,6 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
-#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -207,39 +205,6 @@ class ExceptionToAbortStreamingScope {
DISALLOW_COPY_AND_ASSIGN(ExceptionToAbortStreamingScope);
};
-RawResource* GetRawResource(ScriptState* script_state,
- const String& url_string,
- Response* response) {
- ExecutionContext* execution_context = ExecutionContext::From(script_state);
- if (!execution_context)
- return nullptr;
- ResourceFetcher* fetcher = execution_context->Fetcher();
- if (!fetcher)
- return nullptr;
- KURL url(url_string);
- if (!url.IsValid())
- return nullptr;
- Resource* resource = fetcher->CachedResource(url);
- if (!resource)
- return nullptr;
-
- // Make sure the resource matches the |response|. To check that, we make sure
- // the response times match, and the response sources match.
- const ResourceResponse& resource_response = resource->GetResponse();
- const FetchResponseData* fetch_response_data =
- response->GetResponse()->InternalResponse();
- if (resource_response.ResponseTime() != fetch_response_data->ResponseTime())
- return nullptr;
- bool from_service_worker = fetch_response_data->ResponseSource() ==
- network::mojom::FetchResponseSource::kUnspecified;
- if (resource_response.WasFetchedViaServiceWorker() != from_service_worker)
- return nullptr;
-
- // Wasm modules should be fetched as raw resources.
- DCHECK_EQ(ResourceType::kRaw, resource->GetType());
- return ToRawResource(resource);
-}
-
class WasmStreamingClient : public v8::WasmStreaming::Client {
public:
WasmStreamingClient(const String& response_url,
@@ -362,35 +327,32 @@ void StreamFromResponseCallback(
String url = response->url();
const std::string& url_utf8 = url.Utf8();
streaming->SetUrl(url_utf8.c_str(), url_utf8.size());
- RawResource* resource = GetRawResource(script_state, url, response);
- if (resource) {
- SingleCachedMetadataHandler* cache_handler = resource->ScriptCacheHandler();
- if (cache_handler) {
- auto client = std::make_shared<WasmStreamingClient>(
- url, resource->GetResponse().ResponseTime());
- streaming->SetClient(client);
- scoped_refptr<CachedMetadata> cached_module =
- cache_handler->GetCachedMetadata(kWasmModuleTag);
- if (cached_module) {
- TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
- "v8.wasm.moduleCacheHit", TRACE_EVENT_SCOPE_THREAD,
- "url", url.Utf8(), "consumedCacheSize",
- cached_module->size());
- bool is_valid = streaming->SetCompiledModuleBytes(
- reinterpret_cast<const uint8_t*>(cached_module->Data()),
- cached_module->size());
- if (is_valid) {
- // Keep the buffer alive until V8 is ready to deserialize it.
- // TODO(bbudge) V8 should notify us if deserialization fails, so we
- // can release the data and reset the cache.
- client->SetBuffer(cached_module);
- } else {
- TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
- "v8.wasm.moduleCacheInvalid",
- TRACE_EVENT_SCOPE_THREAD);
- cache_handler->ClearCachedMetadata(
- CachedMetadataHandler::kClearPersistentStorage);
- }
+ if (auto* cache_handler =
+ response->BodyBuffer()->GetCachedMetadataHandler()) {
+ auto client = std::make_shared<WasmStreamingClient>(
+ url, response->GetResponse()->InternalResponse()->ResponseTime());
+ streaming->SetClient(client);
+ scoped_refptr<CachedMetadata> cached_module =
+ cache_handler->GetCachedMetadata(kWasmModuleTag);
+ if (cached_module) {
+ TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "v8.wasm.moduleCacheHit", TRACE_EVENT_SCOPE_THREAD,
+ "url", url.Utf8(), "consumedCacheSize",
+ cached_module->size());
+ bool is_valid = streaming->SetCompiledModuleBytes(
+ reinterpret_cast<const uint8_t*>(cached_module->Data()),
+ cached_module->size());
+ if (is_valid) {
+ // Keep the buffer alive until V8 is ready to deserialize it.
+ // TODO(bbudge) V8 should notify us if deserialization fails, so we
+ // can release the data and reset the cache.
+ client->SetBuffer(cached_module);
+ } else {
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "v8.wasm.moduleCacheInvalid",
+ TRACE_EVENT_SCOPE_THREAD);
+ cache_handler->ClearCachedMetadata(
+ CachedMetadataHandler::kClearPersistentStorage);
}
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
index b57941ba35e..8e590ffed40 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
@@ -50,6 +50,7 @@ WindowProxy::~WindowProxy() {
void WindowProxy::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
+ visitor->Trace(global_proxy_);
}
WindowProxy::WindowProxy(v8::Isolate* isolate,
@@ -94,9 +95,9 @@ v8::Local<v8::Object> WindowProxy::ReleaseGlobalProxy() {
lifecycle_ == Lifecycle::kGlobalObjectIsDetached);
// Make sure the global object was detached from the proxy by calling
- // clearForNavigation().
+ // ClearForSwap().
DLOG_IF(FATAL, is_global_object_attached_)
- << "Context not detached by calling clearForNavigation()";
+ << "Context not detached by calling ClearForSwap()";
v8::Local<v8::Object> global_proxy = global_proxy_.NewLocal(isolate_);
global_proxy_.Clear();
@@ -108,6 +109,10 @@ void WindowProxy::SetGlobalProxy(v8::Local<v8::Object> global_proxy) {
CHECK(global_proxy_.IsEmpty());
global_proxy_.Set(isolate_, global_proxy);
+ // The global proxy was transferred from a previous WindowProxy, so the state
+ // should be detached, not uninitialized. This ensures that it will be
+ // properly reinitialized when needed, e.g. by `UpdateDocument()`.
+ lifecycle_ = Lifecycle::kGlobalObjectIsDetached;
}
// Create a new environment and setup the global object.
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
index 4323a5c7f20..56f808fe995 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy.h
@@ -34,7 +34,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "v8/include/v8.h"
@@ -277,11 +277,20 @@ class WindowProxy : public GarbageCollected<WindowProxy> {
protected:
// TODO(dcheng): Consider making these private and using getters.
const scoped_refptr<DOMWrapperWorld> world_;
- // |global_proxy_| is the root reference from Blink to v8::Context (a strong
- // reference to the global proxy makes the entire context alive). In order to
- // discard the v8::Context, |global_proxy_| needs to be a weak reference or
- // to be destroyed.
- ScopedPersistent<v8::Object> global_proxy_;
+ // Note: this used to be a ScopedPersistent, making `global_proxy_` a strong
+ // GC root from Blink to v8::Context. When the context was disposed (e.g. when
+ // detaching the frame or purging v8), it was important to call `SetPhantom()`
+ // to convert `global_proxy_` to a weak GC root. Otherwise, even if
+ // `WindowProxy` was no longer reachable via Blink GC, the strong reference
+ // could create a reference cycle preventing GC of both Blink and v8 objects:
+ //
+ // WindowProxy -> global_proxy_ -> v8::Context -> JS object
+ // -> chain of Blink C++ objects -> WindowProxy
+ //
+ // With unified tracing, `global_proxy_` can simply be a traced v8 reference.
+ // Once `WindowProxy` is no longer reachable from a GC root, `global_proxy_`
+ // will also become collectible with no need to explicitly break a cycle.
+ TraceWrapperV8Reference<v8::Object> global_proxy_;
Lifecycle lifecycle_;
};
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
index 66bc944696b..9fea377d4db 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
@@ -4,8 +4,12 @@
#include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h"
+#include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h"
+#include "third_party/blink/renderer/bindings/core/v8/remote_window_proxy.h"
+#include "third_party/blink/renderer/core/frame/remote_frame.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -58,14 +62,28 @@ void WindowProxyManager::SetGlobalProxies(
for (const auto& entry : global_proxies)
WindowProxyMaybeUninitialized(*entry.first)->SetGlobalProxy(entry.second);
- // Initialize the window proxies now, to re-establish the connection between
- // the global object and the v8::Context. This is really only needed for a
- // RemoteDOMWindow, since it has no scripting environment of its own.
- // Without this, existing script references to a swapped in RemoteDOMWindow
- // would be broken until that RemoteDOMWindow was vended again through an
- // interface like window.frames.
- for (const auto& entry : global_proxies)
+ // Any transferred global proxies must now be reinitialized to ensure any
+ // preexisting JS references to global proxies don't break.
+
+ // For local frames, the global proxies cannot be reinitialized yet. Blink is
+ // in the midst of committing a navigation and swapping in the new frame.
+ // Instead, the global proxies will be reinitialized after this via a call to
+ // `UpdateDocument()` when the new `Document` is installed: this will happen
+ // before committing the navigation completes and yields back to the event
+ // loop.
+ if (frame_type_ == FrameType::kLocal)
+ return;
+
+ for (const auto& entry : global_proxies) {
WindowProxyMaybeUninitialized(*entry.first)->InitializeIfNeeded();
+ }
+}
+
+void WindowProxyManager::ResetIsolatedWorldsForTesting() {
+ for (auto& world_info : isolated_worlds_) {
+ world_info.value->ClearForClose();
+ }
+ isolated_worlds_.clear();
}
WindowProxyManager::WindowProxyManager(Frame& frame, FrameType frame_type)
@@ -114,14 +132,21 @@ WindowProxy* WindowProxyManager::WindowProxyMaybeUninitialized(
return window_proxy;
}
+void LocalWindowProxyManager::UpdateDocument() {
+ MainWorldProxyMaybeUninitialized()->UpdateDocument();
+
+ for (auto& entry : isolated_worlds_) {
+ To<LocalWindowProxy>(entry.value.Get())->UpdateDocument();
+ }
+}
+
void LocalWindowProxyManager::UpdateSecurityOrigin(
const SecurityOrigin* security_origin) {
- static_cast<LocalWindowProxy*>(window_proxy_.Get())
+ To<LocalWindowProxy>(window_proxy_.Get())
->UpdateSecurityOrigin(security_origin);
for (auto& entry : isolated_worlds_) {
- auto* isolated_window_proxy =
- static_cast<LocalWindowProxy*>(entry.value.Get());
+ auto* isolated_window_proxy = To<LocalWindowProxy>(entry.value.Get());
scoped_refptr<SecurityOrigin> isolated_security_origin =
isolated_window_proxy->World().IsolatedWorldSecurityOrigin(
security_origin->AgentClusterId());
@@ -137,9 +162,7 @@ void LocalWindowProxyManager::SetAbortScriptExecution(
->SetAbortScriptExecution(callback);
for (auto& entry : isolated_worlds_) {
- auto* isolated_window_proxy =
- static_cast<LocalWindowProxy*>(entry.value.Get());
- isolated_window_proxy->SetAbortScriptExecution(callback);
+ To<LocalWindowProxy>(entry.value.Get())->SetAbortScriptExecution(callback);
}
}
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
index ea9dd330ec4..eb810cf9b51 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
@@ -27,29 +27,27 @@ class WindowProxyManager : public GarbageCollected<WindowProxyManager> {
v8::Isolate* GetIsolate() const { return isolate_; }
void ClearForClose();
- void CORE_EXPORT ClearForNavigation();
+ CORE_EXPORT void ClearForNavigation();
void ClearForSwap();
void ClearForV8MemoryPurge();
- // Global proxies are passed in a vector to maintain their order: global proxy
- // object for the main world is always first. This is needed to prevent bugs
- // like https://crbug.com/700077 .
+ // Helpers used to transfer global proxies from the previous frame to the new
+ // frame when swapping frames. Global proxies are passed in a vector to ensure
+ // the main world is always processed first. This is needed to prevent bugs
+ // like https://crbug.com/700077.
using GlobalProxyVector =
Vector<std::pair<DOMWrapperWorld*, v8::Local<v8::Object>>>;
void CORE_EXPORT ReleaseGlobalProxies(GlobalProxyVector&);
void CORE_EXPORT SetGlobalProxies(const GlobalProxyVector&);
- WindowProxy* MainWorldProxy() {
- window_proxy_->InitializeIfNeeded();
- return window_proxy_;
- }
-
WindowProxy* GetWindowProxy(DOMWrapperWorld& world) {
WindowProxy* window_proxy = WindowProxyMaybeUninitialized(world);
window_proxy->InitializeIfNeeded();
return window_proxy;
}
+ CORE_EXPORT void ResetIsolatedWorldsForTesting();
+
protected:
using IsolatedWorldMap = HeapHashMap<int, Member<WindowProxy>>;
enum class FrameType { kLocal, kRemote };
@@ -76,9 +74,6 @@ class WindowProxyManagerImplHelper : public WindowProxyManager {
using Base = WindowProxyManager;
public:
- ProxyType* MainWorldProxy() {
- return static_cast<ProxyType*>(Base::MainWorldProxy());
- }
ProxyType* WindowProxy(DOMWrapperWorld& world) {
return static_cast<ProxyType*>(Base::GetWindowProxy(world));
}
@@ -101,6 +96,8 @@ class LocalWindowProxyManager
return static_cast<LocalWindowProxy*>(window_proxy_.Get());
}
+ void UpdateDocument();
+
// Sets the given security origin to the main world's context. Also updates
// the security origin of the context for each isolated world.
void UpdateSecurityOrigin(const SecurityOrigin*);
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc
index 6faf1d5d800..ca16c31ce9d 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -49,4 +50,46 @@ TEST_F(WindowProxyTest, ReinitializedAfterNavigation) {
ASSERT_GT(ConsoleMessages().size(), 0U);
EXPECT_EQ("PASSED", ConsoleMessages()[0]);
}
+
+TEST_F(WindowProxyTest, IsolatedWorldReinitializedAfterNavigation) {
+ SimRequest main_resource("https://example.com/index.html", "text/html");
+ LoadURL("https://example.com/index.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <html><body><iframe></iframe></body></html>
+ )HTML");
+
+ ASSERT_TRUE(MainFrame().FirstChild());
+
+ v8::HandleScope scope(v8::Isolate::GetCurrent());
+
+ const int32_t kIsolatedWorldId = 42;
+
+ // Save a reference to the top `window` in the isolated world.
+ v8::Local<v8::Value> window_top =
+ MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue(
+ kIsolatedWorldId, WebScriptSource("window"));
+ ASSERT_TRUE(window_top->IsObject());
+
+ // Save a reference to the child frame's window proxy in the isolated world.
+ v8::Local<v8::Value> saved_child_window =
+ MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue(
+ kIsolatedWorldId, WebScriptSource("saved = window[0]"));
+ ASSERT_TRUE(saved_child_window->IsObject());
+
+ frame_test_helpers::LoadFrame(MainFrame().FirstChild()->ToWebLocalFrame(),
+ "data:text/html,<body><p>Hello</p></body>");
+ ASSERT_TRUE(MainFrame().FirstChild());
+
+ // Test if the window proxy of the navigated frame was reinitialized. The
+ // `top` attribute of the saved child frame's window proxy reference should
+ // refer to the same object as the top-level window proxy reference that was
+ // cached earlier.
+ v8::Local<v8::Value> top_via_saved =
+ MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue(
+ kIsolatedWorldId, WebScriptSource("saved.top"));
+ EXPECT_TRUE(top_via_saved->IsObject());
+ EXPECT_TRUE(window_top->StrictEquals(top_via_saved));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index 4f3b691b633..59430d092be 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -33,29 +33,13 @@
#include <memory>
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-#include "third_party/blink/renderer/core/events/error_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/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
-#include "third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h"
-#include "third_party/blink/renderer/core/workers/shared_worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
-#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
@@ -312,38 +296,6 @@ void WorkerOrWorkletScriptController::DisableEvalInternal(
V8String(isolate_, error_message));
}
-// https://html.spec.whatwg.org/C/#run-a-classic-script
-ScriptEvaluationResult WorkerOrWorkletScriptController::EvaluateAndReturnValue(
- const ScriptSourceCode& source_code,
- SanitizeScriptErrors sanitize_script_errors,
- mojom::blink::V8CacheOptions v8_cache_options,
- V8ScriptRunner::RethrowErrorsOption rethrow_errors) {
- if (IsExecutionForbidden())
- return ScriptEvaluationResult::FromClassicNotRun();
-
- DCHECK(IsContextInitialized());
- DCHECK(is_ready_to_evaluate_);
-
- // TODO(crbug/1114994): Plumb this from ClassicScript.
- const KURL base_url = source_code.Url();
-
- // Use default ReferrerScriptInfo here, as
- // - A work{er,let} script doesn't have a nonce, and
- // - a work{er,let} script is always "not parser inserted".
- // TODO(crbug/1114989): Plumb ScriptFetchOptions from ClassicScript.
- ScriptEvaluationResult result = V8ScriptRunner::CompileAndRunScript(
- isolate_, script_state_, global_scope_, source_code, base_url,
- sanitize_script_errors, ScriptFetchOptions(), v8_cache_options,
- std::move(rethrow_errors));
-
- if (result.GetResultType() == ScriptEvaluationResult::ResultType::kAborted)
- ForbidExecution();
- else
- CHECK(!IsExecutionForbidden());
-
- return result;
-}
-
void WorkerOrWorkletScriptController::ForbidExecution() {
DCHECK(global_scope_->IsContextThread());
execution_forbidden_ = true;
diff --git a/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
index 24286a79c19..50054a0065a 100644
--- a/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
+++ b/chromium/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -32,20 +32,14 @@
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORKER_OR_WORKLET_SCRIPT_CONTROLLER_H_
#include "base/macros.h"
-#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h"
-#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
#include "v8/include/v8.h"
namespace blink {
-class ScriptSourceCode;
class WorkerOrWorkletGlobalScope;
class CORE_EXPORT WorkerOrWorkletScriptController final
@@ -57,15 +51,6 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
bool IsExecutionForbidden() const;
- // https://html.spec.whatwg.org/C/#run-a-classic-script
- // Callers should enter ScriptState::Scope before calling this.
- ScriptEvaluationResult EvaluateAndReturnValue(
- const ScriptSourceCode&,
- SanitizeScriptErrors sanitize_script_errors,
- mojom::blink::V8CacheOptions = mojom::blink::V8CacheOptions::kDefault,
- V8ScriptRunner::RethrowErrorsOption =
- V8ScriptRunner::RethrowErrorsOption::DoNotRethrow());
-
// Prevents future JavaScript execution.
void ForbidExecution();
@@ -84,7 +69,6 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
// Disables `eval()` on JavaScript. This must be called before Evaluate().
void DisableEval(const String&);
- // Used by Inspector agents:
ScriptState* GetScriptState() { return script_state_; }
// Used by V8 bindings:
@@ -102,6 +86,7 @@ class CORE_EXPORT WorkerOrWorkletScriptController final
bool IsContextInitialized() const {
return script_state_ && !!script_state_->PerContextData();
}
+ bool IsReadyToEvaluate() const { return is_ready_to_evaluate_; }
private:
void DisableEvalInternal(const String& error_message);
diff --git a/chromium/third_party/blink/renderer/bindings/generated_in_core.gni b/chromium/third_party/blink/renderer/bindings/generated_in_core.gni
index dbdf05c6664..f60e846297e 100644
--- a/chromium/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/chromium/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -57,6 +57,12 @@ generated_callback_function_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_resize_observer_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_state_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_state_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_cancel_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_cancel_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_pull_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_pull_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_start_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_start_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_void_function.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_void_function.h",
]
@@ -107,12 +113,12 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_layout_constraints_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_2d_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_2d_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_init.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_parser_init.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_parser_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_point_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_quad_init.cc",
@@ -165,12 +171,16 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_hash_change_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_idle_request_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_idle_request_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_interest_cohort.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_interest_cohort.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_data_color_settings.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_data_color_settings.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_data_settings.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_data_settings.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_encode_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_encode_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_impression_params.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_impression_params.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_device_capabilities_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_device_capabilities_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_input_event_init.cc",
@@ -187,12 +197,16 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_keyframe_animation_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_keyframe_effect_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_keyframe_effect_options.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_measure_memory.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_measure_memory.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_media_query_list_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_media_query_list_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_attribution_container.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_attribution_container.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_message_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_message_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_mojo_create_data_pipe_options.cc",
@@ -237,6 +251,8 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_overscroll_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_page_transition_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_page_transition_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_parse_from_string_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_parse_from_string_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_performance_mark_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_performance_mark_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_performance_measure_options.cc",
@@ -301,12 +317,12 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_to_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_security_policy_violation_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_security_policy_violation_event_init.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_static_range_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_static_range_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_submit_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_submit_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_text_format_update_event_init.cc",
@@ -329,6 +345,8 @@ generated_dictionary_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ua_data_values.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ui_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ui_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_validity_state_flags.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_validity_state_flags.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_wheel_event_init.cc",
@@ -388,8 +406,6 @@ generated_enumeration_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_form_state_restore_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_fullscreen_navigation_ui.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_fullscreen_navigation_ui.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_pixel_format.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_pixel_format.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_color_space.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_color_space.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_data_storage_format.cc",
@@ -410,6 +426,10 @@ generated_enumeration_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_playback_direction.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_premultiply_alpha.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_premultiply_alpha.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_reader_mode.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_reader_mode.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_referrer_policy.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_referrer_policy.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_refresh_policy.cc",
@@ -434,6 +454,8 @@ generated_enumeration_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_resize_quality.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_response_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_response_type.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_root_transition_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_root_transition_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_behavior.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_behavior.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_direction.cc",
@@ -475,6 +497,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_abort_controller.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_abort_signal.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_abort_signal.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_abstract_range.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_abstract_range.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_accessible_node.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_accessible_node.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_accessible_node_list.cc",
@@ -533,6 +557,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_animation.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_condition_rule.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_condition_rule.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_container_rule.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_container_rule.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_counter_style_rule.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_counter_style_rule.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_font_face_rule.cc",
@@ -625,6 +651,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_element_registry.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_event.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_state_set.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_state_set.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_data_transfer.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_data_transfer.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_data_transfer_item.cc",
@@ -645,6 +673,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_policy_violation_report_body.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_exception.cc",
@@ -745,8 +775,6 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_canvas_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_collection.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_collection.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_content_element.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_content_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_data_element.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_data_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_data_list_element.cc",
@@ -833,6 +861,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_param_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_picture_element.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_picture_element.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_popup_element.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_popup_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_portal_element.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_portal_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_pre_element.cc",
@@ -845,8 +875,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_script_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_select_element.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_select_element.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_shadow_element.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_shadow_element.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_select_menu_element.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_select_menu_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_slot_element.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_slot_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_html_source_element.cc",
@@ -1369,6 +1399,8 @@ generated_interface_sources_in_core = [
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_wheel_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_window.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_window.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_window_controls_overlay.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_window_controls_overlay.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_worker.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_worker.h",
"$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_worker_global_scope.cc",
diff --git a/chromium/third_party/blink/renderer/bindings/generated_in_modules.gni b/chromium/third_party/blink/renderer/bindings/generated_in_modules.gni
index 60700b63fc7..46763abf469 100644
--- a/chromium/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/chromium/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -23,14 +23,16 @@ generated_callback_function_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_decode_error_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_granted_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_granted_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session_action_handler.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session_action_handler.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_modal_close_watcher.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_modal_close_watcher.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigator_user_media_error_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigator_user_media_error_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigator_user_media_success_callback.cc",
@@ -51,6 +53,8 @@ generated_callback_function_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_session_description_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_stats_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_stats_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_state_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_state_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_error_callback.cc",
@@ -65,8 +69,8 @@ generated_callback_function_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_request_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_request_callback.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h",
]
@@ -115,8 +119,16 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_configuration.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_support.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_support.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.cc",
@@ -139,6 +151,10 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_large_blob_outputs.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_authenticator_selection_criteria.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_authenticator_selection_criteria.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_avc_bitstream_format.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_avc_bitstream_format.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_avc_encoder_config.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_avc_encoder_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_options.cc",
@@ -177,6 +193,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_can_make_payment_response.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_context_creation_attributes_module.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_context_creation_attributes_module.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text_run.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text_run.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_channel_merger_options.cc",
@@ -193,6 +211,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_constant_source_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_constant_source_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_constrain_boolean_parameters.cc",
@@ -259,8 +279,6 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_dynamics_compressor_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_event_source_init.cc",
@@ -283,8 +301,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_picker_accept_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_picker_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_picker_options.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writer_options.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writer_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writable_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writable_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_flags.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_flags.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_get_directory_options.cc",
@@ -295,8 +313,6 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_handle_permission_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_remove_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_remove_options.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_iterator_entry.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_iterator_entry.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gain_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gain_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gamepad_axis_event_init.cc",
@@ -317,18 +333,18 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_entry.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_entry.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_descriptor.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_copy_view.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_copy_view.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_layout.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_layout.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_dict.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_dict.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_buffer_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_buffer_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_encoder_descriptor.cc",
@@ -337,16 +353,22 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pass_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_extent_3d_dict.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_extent_3d_dict.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_fence_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_fence_descriptor.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_bitmap_copy_view.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_bitmap_copy_view.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_buffer.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_buffer.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_image_bitmap.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_image_bitmap.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_texture.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_texture.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_data_layout.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_data_layout.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_limits.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_limits.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_object_descriptor_base.cc",
@@ -359,8 +381,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_descriptor_base.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_layout_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_layout_descriptor.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage_descriptor.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_query_set_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_query_set_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_rasterization_state_descriptor.cc",
@@ -379,18 +401,20 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_request_adapter_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_request_adapter_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_layout.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_layout.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_module_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_module_descriptor.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_state_face_descriptor.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_state_face_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_face_state.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_face_state.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_storage_texture_binding_layout.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_storage_texture_binding_layout.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_swap_chain_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_swap_chain_descriptor.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_copy_view.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_copy_view.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_data_layout.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_data_layout.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_binding_layout.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_binding_layout.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.cc",
@@ -403,6 +427,20 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_model_constraint.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_model_constraint.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_point.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_point.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_segment.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_segment.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_collection_info.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_collection_info.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_connection_event_init.cc",
@@ -423,8 +461,6 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_index_parameters.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_object_store_parameters.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_object_store_parameters.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_init.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_transaction_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_transaction_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_version_change_event_init.cc",
@@ -433,6 +469,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idle_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_iir_filter_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_iir_filter_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_decode_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_decode_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_frame.cc",
@@ -507,6 +545,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_track_capabilities.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_track_capabilities.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_track_constraint_set.cc",
@@ -617,6 +657,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_plane_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_plane_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_point_2d.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_point_2d.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_position_options.cc",
@@ -639,6 +681,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_rp_entity.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_user_entity.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_user_entity.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_details.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_details.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_permission_descriptor.cc",
@@ -647,6 +691,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_subscription_change_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_subscription_options_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_subscription_options_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_query_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_query_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_quic_transport_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_quic_transport_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_registration_options.cc",
@@ -745,6 +791,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_source_buffer_config.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_source_buffer_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_recognition_error_event_init.cc",
@@ -757,6 +805,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_synthesis_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_stereo_panner_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_stereo_panner_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_estimate.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_estimate.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_event_init.cc",
@@ -773,6 +823,12 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_text_decoder_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_text_encoder_encode_into_result.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_text_encoder_encode_into_result.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_component_result.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_component_result.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_connection_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_connection_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_control_transfer_parameters.cc",
@@ -781,12 +837,16 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_device_filter.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_device_request_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_device_request_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_color_space.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_color_space.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_configuration.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_configuration.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_support.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_support.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_encode_options.cc",
@@ -799,18 +859,22 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_metadata.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_virtual_keyboard_geometry_change_event_init.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_virtual_keyboard_geometry_change_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_watch_advertisements_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_watch_advertisements_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wave_shaper_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wave_shaper_options.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id_request_options.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id_request_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_transport_close_info.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_transport_close_info.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_context_attributes.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_context_attributes.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_context_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_context_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_texture_info.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_texture_info.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_video_frame_handle.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_video_frame_handle.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket_close_info.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket_close_info.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket_connection.cc",
@@ -819,6 +883,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket_stream_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_write_params.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_write_params.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_state_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_state_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hit_test_options_init.cc",
@@ -827,6 +893,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_source_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_sources_change_event_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_sources_change_event_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_light_probe_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_light_probe_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_ray_direction_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_ray_direction_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_reference_space_event_init.cc",
@@ -837,6 +905,8 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_session_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_session_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_session_init.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_tracked_image_init.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_tracked_image_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_transient_input_hit_test_options_init.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_transient_input_hit_test_options_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_layer_init.cc",
@@ -868,6 +938,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_binary_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_biquad_filter_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_biquad_filter_type.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bitrate_mode.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_bitrate_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_fill_rule.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_fill_rule.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_pixel_format.cc",
@@ -888,6 +960,14 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_codec_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_gamut.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_gamut.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_matrix_id.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_matrix_id.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_primary_id.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_primary_id.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_range_id.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_range_id.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_transfer_id.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_space_transfer_id.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_connection_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_connection_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_contact_property.cc",
@@ -930,14 +1010,16 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_factor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_operation.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_operation.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compare_function.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compare_function.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_cull_mode.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_cull_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_error_filter.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_error_filter.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_extension_name.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_extension_name.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_feature_name.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_feature_name.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_filter_mode.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_filter_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_front_face.cc",
@@ -958,6 +1040,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_query_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_operation.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_operation.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_storage_texture_access.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_storage_texture_access.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_store_op.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_store_op.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_aspect.cc",
@@ -968,6 +1052,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_dimension.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_format.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_format.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_sample_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_sample_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_dimension.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_dimension.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_format.cc",
@@ -980,8 +1066,6 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_cursor_direction.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_data_loss_amount.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_data_loss_amount.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observation_type.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observation_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_request_ready_state.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_request_ready_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_transaction_durability.cc",
@@ -1014,6 +1098,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session_action.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session_playback_state.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session_playback_state.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_state.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_metering_mode.cc",
@@ -1062,6 +1148,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presenter_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_type.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_state.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_push_encryption_key_name.cc",
@@ -1128,6 +1216,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_update_via_cache.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_synthesis_error_code.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_synthesis_error_code.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_durability.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_durability.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_task_priority.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_task_priority.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_track_default_type.cc",
@@ -1148,22 +1238,28 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_user_idle_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_user_verification_requirement.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_user_verification_requirement.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_acceleration_preference.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_acceleration_preference.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_pixel_format.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_pixel_format.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wake_lock_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wake_lock_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_power_preference.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_power_preference.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_well_known_directory.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_well_known_directory.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_write_command_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_write_command_type.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_data_format.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_data_format.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_usage.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_usage.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_environment_blend_mode.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_environment_blend_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_eye.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_eye.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hand_joint.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hand_joint.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_handedness.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_handedness.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hit_test_trackable_type.cc",
@@ -1172,6 +1268,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_orientation.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_reference_space_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_reference_space_type.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_reflection_format.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_reflection_format.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_session_mode.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_session_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_target_ray_mode.cc",
@@ -1205,6 +1303,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_destination_node.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_destination_node.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_listener.cc",
@@ -1293,6 +1393,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_can_make_payment_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_capture_media_stream_track.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_capture_media_stream_track.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text_run.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_gradient.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_gradient.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_canvas_pattern.cc",
@@ -1313,6 +1415,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_clipboard_item.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compression_stream.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compression_stream.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_constant_source_node.cc",
@@ -1369,6 +1473,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_device_motion_event_rotation_rate.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_device_orientation_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_device_orientation_event.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_device_service.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_device_service.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_digital_goods_service.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_digital_goods_service.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_directory_entry.cc",
@@ -1389,8 +1495,6 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_dom_file_system_sync.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_dynamics_compressor_node.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_dynamics_compressor_node.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_element.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.cc",
@@ -1433,6 +1537,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_extendable_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_extendable_message_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_extendable_message_event.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_eye_dropper.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_eye_dropper.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_face_detector.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_face_detector.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_federated_credential.cc",
@@ -1445,6 +1551,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_entry_sync.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_handle.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_handle.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_iterator.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_iterator.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_file_handle.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_file_handle.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_system_handle.cc",
@@ -1455,8 +1563,6 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_writer.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_writer_sync.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_file_writer_sync.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_iterator.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_iterator.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_manager.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_font_metadata.cc",
@@ -1537,6 +1643,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_type.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_module.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_module.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_stage.cc",
@@ -1553,8 +1661,16 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_uncaptured_error_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_validation_error.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_validation_error.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gravity_sensor.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gravity_sensor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gyroscope.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gyroscope.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_recognizer.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_recognizer.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_stroke.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_stroke.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_hid_connection_event.cc",
@@ -1589,12 +1705,6 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_key_range.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_object_store.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_object_store.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observation.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observation.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_changes.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_changes.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_open_db_request.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_open_db_request.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_request.cc",
@@ -1637,6 +1747,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_magnetometer.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_magnetometer.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_mathml_element.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_mathml_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_capabilities.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_capabilities.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_device_info.cc",
@@ -1705,14 +1817,12 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_mime_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_mime_type_array.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_mime_type_array.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_file_system_directory_iterator.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_file_system_directory_iterator.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file_manager.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file_sync.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_file_sync.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_manager.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_native_io_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigation_preload_manager.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigation_preload_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_navigator.cc",
@@ -1725,8 +1835,6 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_reading_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_record.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_record.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_writer.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ndef_writer.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_network_information.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_network_information.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_notification.cc",
@@ -1975,12 +2083,18 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_stereo_panner_node.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_manager.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_bucket_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_manager.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_manager.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_subtle_crypto.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_subtle_crypto.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_svg_element.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_svg_element.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sync_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sync_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sync_manager.cc",
@@ -2007,6 +2121,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_track_default_list.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_url_pattern.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_usb_alternate_interface.cc",
@@ -2055,6 +2171,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wake_lock_sentinel.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wave_shaper_node.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wave_shaper_node.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_transport.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_transport.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl2_rendering_context.cc",
@@ -2127,8 +2245,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_vertex_array_object_oes.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_video_texture.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_video_texture.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_id.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_video_frame.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_video_frame.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_websocket_stream.cc",
@@ -2153,12 +2271,16 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_anchor_set.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_bounded_reference_space.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_bounded_reference_space.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_cpu_depth_information.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_cpu_depth_information.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_information.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_information.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_state.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_dom_overlay_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_frame.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_frame.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hand.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hand.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hit_test_result.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hit_test_result.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_hit_test_source.cc",
@@ -2173,6 +2295,10 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_source_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_sources_change_event.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_input_sources_change_event.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_joint_pose.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_joint_pose.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_joint_space.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_joint_space.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_layer.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_layer.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_light_estimate.cc",
@@ -2181,8 +2307,6 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_light_probe.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_detection_state.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_detection_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_set.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_plane_set.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_pose.cc",
@@ -2217,12 +2341,10 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_viewport.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_binding.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_binding.h",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_depth_information.cc",
+ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_depth_information.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_layer.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_layer.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_information.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_information.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state.h",
]
generated_namespace_sources_in_modules = []
@@ -2244,8 +2366,6 @@ if (!is_android) {
# Serial
if (!is_android) {
generated_dictionary_sources_in_modules += [
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event_init.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event_init.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_input_signals.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_input_signals.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_options.cc",
@@ -2268,8 +2388,6 @@ if (!is_android) {
generated_interface_sources_in_modules += [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial.h",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event.cc",
- "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.h",
]
diff --git a/chromium/third_party/blink/renderer/bindings/idl_in_core.gni b/chromium/third_party/blink/renderer/bindings/idl_in_core.gni
index 9a546b39ac9..16d8c5ebee3 100644
--- a/chromium/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/chromium/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -39,6 +39,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/clipboard/data_transfer_item_list.idl",
"//third_party/blink/renderer/core/css/css.idl",
"//third_party/blink/renderer/core/css/css_condition_rule.idl",
+ "//third_party/blink/renderer/core/css/css_container_rule.idl",
"//third_party/blink/renderer/core/css/css_counter_style_rule.idl",
"//third_party/blink/renderer/core/css/css_font_face_rule.idl",
"//third_party/blink/renderer/core/css/css_grouping_rule.idl",
@@ -105,8 +106,12 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/css/style_media.idl",
"//third_party/blink/renderer/core/css/style_sheet.idl",
"//third_party/blink/renderer/core/css/style_sheet_list.idl",
+ "//third_party/blink/renderer/core/document_transition/document_transition.idl",
+ "//third_party/blink/renderer/core/document_transition/document_transition_init.idl",
+ "//third_party/blink/renderer/core/document_transition/document_transition_supplement.idl",
"//third_party/blink/renderer/core/dom/abort_controller.idl",
"//third_party/blink/renderer/core/dom/abort_signal.idl",
+ "//third_party/blink/renderer/core/dom/abstract_range.idl",
"//third_party/blink/renderer/core/dom/accessibility_role.idl",
"//third_party/blink/renderer/core/dom/aria_attributes.idl",
"//third_party/blink/renderer/core/dom/aria_relationship_attributes.idl",
@@ -147,6 +152,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/dom/idle_deadline.idl",
"//third_party/blink/renderer/core/dom/idle_request_callback.idl",
"//third_party/blink/renderer/core/dom/idle_request_options.idl",
+ "//third_party/blink/renderer/core/dom/interest_cohort.idl",
"//third_party/blink/renderer/core/dom/iterator.idl",
"//third_party/blink/renderer/core/dom/mutation_observer.idl",
"//third_party/blink/renderer/core/dom/mutation_observer_init.idl",
@@ -162,10 +168,10 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/dom/pointer_lock_options.idl",
"//third_party/blink/renderer/core/dom/processing_instruction.idl",
"//third_party/blink/renderer/core/dom/range.idl",
- "//third_party/blink/renderer/core/dom/set_inner_html_options.idl",
"//third_party/blink/renderer/core/dom/shadow_root.idl",
"//third_party/blink/renderer/core/dom/shadow_root_init.idl",
"//third_party/blink/renderer/core/dom/static_range.idl",
+ "//third_party/blink/renderer/core/dom/static_range_init.idl",
"//third_party/blink/renderer/core/dom/text.idl",
"//third_party/blink/renderer/core/dom/tree_walker.idl",
"//third_party/blink/renderer/core/dom/void_function.idl",
@@ -258,6 +264,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/frame/feature_policy_violation_report_body.idl",
"//third_party/blink/renderer/core/frame/fragment_directive.idl",
"//third_party/blink/renderer/core/frame/history.idl",
+ "//third_party/blink/renderer/core/frame/impression_params.idl",
"//third_party/blink/renderer/core/frame/intervention_report_body.idl",
"//third_party/blink/renderer/core/frame/is_input_pending_options.idl",
"//third_party/blink/renderer/core/frame/location.idl",
@@ -274,6 +281,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/frame/navigator_ua_brand_version.idl",
"//third_party/blink/renderer/core/frame/navigator_ua_data.idl",
"//third_party/blink/renderer/core/frame/navigator_user_activation.idl",
+ "//third_party/blink/renderer/core/frame/navigator_window_controls_overlay.idl",
"//third_party/blink/renderer/core/frame/report.idl",
"//third_party/blink/renderer/core/frame/report_body.idl",
"//third_party/blink/renderer/core/frame/reporting_observer.idl",
@@ -288,6 +296,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/frame/user_activation.idl",
"//third_party/blink/renderer/core/frame/visual_viewport.idl",
"//third_party/blink/renderer/core/frame/window.idl",
+ "//third_party/blink/renderer/core/frame/window_controls_overlay.idl",
"//third_party/blink/renderer/core/frame/window_event_handlers.idl",
"//third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl",
"//third_party/blink/renderer/core/frame/window_post_message_options.idl",
@@ -311,10 +320,11 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/html/canvas/baselines.idl",
"//third_party/blink/renderer/core/html/canvas/html_canvas_element.idl",
"//third_party/blink/renderer/core/html/canvas/image_data.idl",
- "//third_party/blink/renderer/core/html/canvas/image_data_color_settings.idl",
+ "//third_party/blink/renderer/core/html/canvas/image_data_settings.idl",
"//third_party/blink/renderer/core/html/canvas/image_encode_options.idl",
"//third_party/blink/renderer/core/html/canvas/text_metrics.idl",
"//third_party/blink/renderer/core/html/custom/custom_element_registry.idl",
+ "//third_party/blink/renderer/core/html/custom/custom_state_set.idl",
"//third_party/blink/renderer/core/html/custom/element_internals.idl",
"//third_party/blink/renderer/core/html/custom/validity_state_flags.idl",
"//third_party/blink/renderer/core/html/event_handler.idl",
@@ -335,6 +345,7 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/html/forms/html_options_collection.idl",
"//third_party/blink/renderer/core/html/forms/html_output_element.idl",
"//third_party/blink/renderer/core/html/forms/html_select_element.idl",
+ "//third_party/blink/renderer/core/html/forms/html_select_menu_element.idl",
"//third_party/blink/renderer/core/html/forms/html_text_area_element.idl",
"//third_party/blink/renderer/core/html/forms/radio_node_list.idl",
"//third_party/blink/renderer/core/html/forms/submit_event.idl",
@@ -347,7 +358,6 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/html/html_body_element.idl",
"//third_party/blink/renderer/core/html/html_br_element.idl",
"//third_party/blink/renderer/core/html/html_collection.idl",
- "//third_party/blink/renderer/core/html/html_content_element.idl",
"//third_party/blink/renderer/core/html/html_data_element.idl",
"//third_party/blink/renderer/core/html/html_details_element.idl",
"//third_party/blink/renderer/core/html/html_dialog_element.idl",
@@ -381,11 +391,11 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/html/html_paragraph_element.idl",
"//third_party/blink/renderer/core/html/html_param_element.idl",
"//third_party/blink/renderer/core/html/html_picture_element.idl",
+ "//third_party/blink/renderer/core/html/html_popup_element.idl",
"//third_party/blink/renderer/core/html/html_pre_element.idl",
"//third_party/blink/renderer/core/html/html_progress_element.idl",
"//third_party/blink/renderer/core/html/html_quote_element.idl",
"//third_party/blink/renderer/core/html/html_script_element.idl",
- "//third_party/blink/renderer/core/html/html_shadow_element.idl",
"//third_party/blink/renderer/core/html/html_slot_element.idl",
"//third_party/blink/renderer/core/html/html_source_element.idl",
"//third_party/blink/renderer/core/html/html_span_element.idl",
@@ -498,7 +508,11 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/streams/transform_stream.idl",
"//third_party/blink/renderer/core/streams/transform_stream_default_controller.idl",
"//third_party/blink/renderer/core/streams/underlying_sink_base.idl",
+ "//third_party/blink/renderer/core/streams/underlying_source.idl",
"//third_party/blink/renderer/core/streams/underlying_source_base.idl",
+ "//third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl",
+ "//third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl",
+ "//third_party/blink/renderer/core/streams/underlying_source_start_callback.idl",
"//third_party/blink/renderer/core/streams/writable_stream.idl",
"//third_party/blink/renderer/core/streams/writable_stream_default_controller.idl",
"//third_party/blink/renderer/core/streams/writable_stream_default_writer.idl",
@@ -611,8 +625,10 @@ static_idl_files_in_core = get_path_info(
"//third_party/blink/renderer/core/timing/largest_contentful_paint.idl",
"//third_party/blink/renderer/core/timing/layout_shift.idl",
"//third_party/blink/renderer/core/timing/layout_shift_attribution.idl",
- "//third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl",
- "//third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl",
+ "//third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl",
+ "//third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl",
+ "//third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl",
+ "//third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl",
"//third_party/blink/renderer/core/timing/memory_info.idl",
"//third_party/blink/renderer/core/timing/performance.idl",
"//third_party/blink/renderer/core/timing/performance_element_timing.idl",
diff --git a/chromium/third_party/blink/renderer/bindings/idl_in_modules.gni b/chromium/third_party/blink/renderer/bindings/idl_in_modules.gni
index de4b5adab47..a5cd50fec1c 100644
--- a/chromium/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/chromium/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -65,12 +65,19 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/bluetooth/request_device_options.idl",
"//third_party/blink/renderer/modules/bluetooth/watch_advertisements_options.idl",
"//third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.idl",
+ "//third_party/blink/renderer/modules/buckets/navigator_storage_buckets.idl",
+ "//third_party/blink/renderer/modules/buckets/storage_bucket.idl",
+ "//third_party/blink/renderer/modules/buckets/storage_bucket_manager.idl",
+ "//third_party/blink/renderer/modules/buckets/storage_bucket_options.idl",
+ "//third_party/blink/renderer/modules/buckets/worker_navigator_storage_buckets.idl",
"//third_party/blink/renderer/modules/cache_storage/cache.idl",
"//third_party/blink/renderer/modules/cache_storage/cache_query_options.idl",
"//third_party/blink/renderer/modules/cache_storage/cache_storage.idl",
"//third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.idl",
"//third_party/blink/renderer/modules/cache_storage/window_cache_storage.idl",
"//third_party/blink/renderer/modules/cache_storage/worker_cache_storage.idl",
+ "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl",
+ "//third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl",
"//third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl",
"//third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl",
"//third_party/blink/renderer/modules/canvas/canvas2d/canvas_pattern.idl",
@@ -81,6 +88,8 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl",
"//third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl",
"//third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.idl",
+ "//third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl",
+ "//third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl",
"//third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_module.idl",
"//third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl",
"//third_party/blink/renderer/modules/clipboard/clipboard.idl",
@@ -167,6 +176,8 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/delegated_ink/ink.idl",
"//third_party/blink/renderer/modules/delegated_ink/ink_trail_style.idl",
"//third_party/blink/renderer/modules/delegated_ink/navigator_ink.idl",
+ "//third_party/blink/renderer/modules/device/device_service.idl",
+ "//third_party/blink/renderer/modules/device/navigator_device.idl",
"//third_party/blink/renderer/modules/device_orientation/device_motion_event.idl",
"//third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration.idl",
"//third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration_init.idl",
@@ -201,11 +212,14 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.idl",
"//third_party/blink/renderer/modules/eventsource/event_source.idl",
"//third_party/blink/renderer/modules/eventsource/event_source_init.idl",
- "//third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl",
+ "//third_party/blink/renderer/modules/eyedropper/color_select_event.idl",
+ "//third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl",
+ "//third_party/blink/renderer/modules/eyedropper/eye_dropper.idl",
+ "//third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl",
"//third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl",
"//third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl",
"//third_party/blink/renderer/modules/file_system_access/file_picker_options.idl",
- "//third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl",
+ "//third_party/blink/renderer/modules/file_system_access/file_system_create_writable_options.idl",
"//third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl",
"//third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl",
"//third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl",
@@ -214,11 +228,11 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl",
"//third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl",
"//third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl",
- "//third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl",
+ "//third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.idl",
"//third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl",
"//third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl",
- "//third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl",
- "//third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl",
+ "//third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.idl",
+ "//third_party/blink/renderer/modules/file_system_access/window_file_system_access.idl",
"//third_party/blink/renderer/modules/file_system_access/write_params.idl",
"//third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.idl",
"//third_party/blink/renderer/modules/filesystem/dedicated_worker_global_scope_file_system.idl",
@@ -247,8 +261,6 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/filesystem/metadata_callback.idl",
"//third_party/blink/renderer/modules/filesystem/shared_worker_global_scope_file_system.idl",
"//third_party/blink/renderer/modules/filesystem/window_file_system.idl",
- "//third_party/blink/renderer/modules/font_access/font_iterator.idl",
- "//third_party/blink/renderer/modules/font_access/font_iterator_entry.idl",
"//third_party/blink/renderer/modules/font_access/font_manager.idl",
"//third_party/blink/renderer/modules/font_access/font_metadata.idl",
"//third_party/blink/renderer/modules/font_access/font_table_map.idl",
@@ -272,6 +284,18 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/geolocation/geolocation_position_error.idl",
"//third_party/blink/renderer/modules/geolocation/navigator_geolocation.idl",
"//third_party/blink/renderer/modules/geolocation/position_options.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_drawing_segment.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_feature_query.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_feature_query_result.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_hints.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_model_constraint.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_point.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_prediction.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_segment.idl",
+ "//third_party/blink/renderer/modules/handwriting/handwriting_stroke.idl",
+ "//third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl",
"//third_party/blink/renderer/modules/hid/hid.idl",
"//third_party/blink/renderer/modules/hid/hid_collection_info.idl",
"//third_party/blink/renderer/modules/hid/hid_connection_event.idl",
@@ -301,10 +325,6 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/indexeddb/idb_key_range.idl",
"//third_party/blink/renderer/modules/indexeddb/idb_object_store.idl",
"//third_party/blink/renderer/modules/indexeddb/idb_object_store_parameters.idl",
- "//third_party/blink/renderer/modules/indexeddb/idb_observation.idl",
- "//third_party/blink/renderer/modules/indexeddb/idb_observer.idl",
- "//third_party/blink/renderer/modules/indexeddb/idb_observer_changes.idl",
- "//third_party/blink/renderer/modules/indexeddb/idb_observer_init.idl",
"//third_party/blink/renderer/modules/indexeddb/idb_open_db_request.idl",
"//third_party/blink/renderer/modules/indexeddb/idb_request.idl",
"//third_party/blink/renderer/modules/indexeddb/idb_transaction.idl",
@@ -360,6 +380,7 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/mediasource/html_video_element_media_source.idl",
"//third_party/blink/renderer/modules/mediasource/media_source.idl",
"//third_party/blink/renderer/modules/mediasource/source_buffer.idl",
+ "//third_party/blink/renderer/modules/mediasource/source_buffer_config.idl",
"//third_party/blink/renderer/modules/mediasource/source_buffer_list.idl",
"//third_party/blink/renderer/modules/mediasource/track_default.idl",
"//third_party/blink/renderer/modules/mediasource/track_default_list.idl",
@@ -384,7 +405,10 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/mediastream/media_stream_track_event.idl",
"//third_party/blink/renderer/modules/mediastream/media_stream_track_event_init.idl",
"//third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl",
+ "//third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.idl",
"//third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl",
+ "//third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.idl",
+ "//third_party/blink/renderer/modules/mediastream/media_stream_track_signal.idl",
"//third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl",
"//third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl",
"//third_party/blink/renderer/modules/mediastream/media_track_constraints.idl",
@@ -393,9 +417,10 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/mediastream/navigator_media_stream.idl",
"//third_party/blink/renderer/modules/mediastream/navigator_user_media.idl",
"//third_party/blink/renderer/modules/mediastream/overconstrained_error.idl",
+ "//third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.idl",
"//third_party/blink/renderer/modules/native_io/native_io_file.idl",
+ "//third_party/blink/renderer/modules/native_io/native_io_file_manager.idl",
"//third_party/blink/renderer/modules/native_io/native_io_file_sync.idl",
- "//third_party/blink/renderer/modules/native_io/native_io_manager.idl",
"//third_party/blink/renderer/modules/native_io/window_native_io.idl",
"//third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl",
"//third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.idl",
@@ -411,7 +436,6 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/nfc/ndef_record_init.idl",
"//third_party/blink/renderer/modules/nfc/ndef_scan_options.idl",
"//third_party/blink/renderer/modules/nfc/ndef_write_options.idl",
- "//third_party/blink/renderer/modules/nfc/ndef_writer.idl",
"//third_party/blink/renderer/modules/notifications/get_notification_options.idl",
"//third_party/blink/renderer/modules/notifications/notification.idl",
"//third_party/blink/renderer/modules/notifications/notification_action.idl",
@@ -585,6 +609,7 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl",
"//third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl",
"//third_party/blink/renderer/modules/scheduler/scheduler.idl",
+ "//third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl",
"//third_party/blink/renderer/modules/scheduler/scheduler_post_task_options.idl",
"//third_party/blink/renderer/modules/scheduler/task_controller.idl",
"//third_party/blink/renderer/modules/scheduler/task_signal.idl",
@@ -595,6 +620,7 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.idl",
"//third_party/blink/renderer/modules/sensor/accelerometer.idl",
"//third_party/blink/renderer/modules/sensor/ambient_light_sensor.idl",
+ "//third_party/blink/renderer/modules/sensor/gravity_sensor.idl",
"//third_party/blink/renderer/modules/sensor/gyroscope.idl",
"//third_party/blink/renderer/modules/sensor/linear_acceleration_sensor.idl",
"//third_party/blink/renderer/modules/sensor/magnetometer.idl",
@@ -656,6 +682,10 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/storage/storage_event.idl",
"//third_party/blink/renderer/modules/storage/storage_event_init.idl",
"//third_party/blink/renderer/modules/storage/window_storage.idl",
+ "//third_party/blink/renderer/modules/url_pattern/url_pattern.idl",
+ "//third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.idl",
+ "//third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl",
+ "//third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl",
"//third_party/blink/renderer/modules/vibration/navigator_vibration.idl",
"//third_party/blink/renderer/modules/video_rvfc/html_video_element_request_video_frame_callback.idl",
"//third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl",
@@ -732,25 +762,39 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webaudio/wave_shaper_node.idl",
"//third_party/blink/renderer/modules/webaudio/wave_shaper_options.idl",
"//third_party/blink/renderer/modules/webcodecs/audio_decoder.idl",
+ "//third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl",
"//third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl",
+ "//third_party/blink/renderer/modules/webcodecs/audio_decoder_support.idl",
+ "//third_party/blink/renderer/modules/webcodecs/audio_encoder.idl",
+ "//third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl",
+ "//third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl",
"//third_party/blink/renderer/modules/webcodecs/audio_frame.idl",
"//third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl",
"//third_party/blink/renderer/modules/webcodecs/audio_frame_output_callback.idl",
+ "//third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl",
"//third_party/blink/renderer/modules/webcodecs/codec_state.idl",
"//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.idl",
+ "//third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl",
+ "//third_party/blink/renderer/modules/webcodecs/color_space_primary_id.idl",
+ "//third_party/blink/renderer/modules/webcodecs/color_space_range_id.idl",
+ "//third_party/blink/renderer/modules/webcodecs/color_space_transfer_id.idl",
"//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl",
- "//third_party/blink/renderer/modules/webcodecs/encoded_audio_config.idl",
"//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl",
"//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl",
+ "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl",
+ "//third_party/blink/renderer/modules/webcodecs/hardware_preference.idl",
"//third_party/blink/renderer/modules/webcodecs/image_decoder.idl",
"//third_party/blink/renderer/modules/webcodecs/image_decoder_init.idl",
+ "//third_party/blink/renderer/modules/webcodecs/image_decode_options.idl",
"//third_party/blink/renderer/modules/webcodecs/image_frame.idl",
"//third_party/blink/renderer/modules/webcodecs/image_track.idl",
"//third_party/blink/renderer/modules/webcodecs/plane.idl",
"//third_party/blink/renderer/modules/webcodecs/plane_init.idl",
+ "//third_party/blink/renderer/modules/webcodecs/video_color_space.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder_init.idl",
+ "//third_party/blink/renderer/modules/webcodecs/video_decoder_support.idl",
"//third_party/blink/renderer/modules/webcodecs/video_encoder.idl",
"//third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl",
"//third_party/blink/renderer/modules/webcodecs/video_encoder_encode_options.idl",
@@ -759,10 +803,11 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webcodecs/video_frame.idl",
"//third_party/blink/renderer/modules/webcodecs/video_frame_init.idl",
"//third_party/blink/renderer/modules/webcodecs/video_frame_output_callback.idl",
+ "//third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl",
"//third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl",
"//third_party/blink/renderer/modules/webcodecs/video_track_reader.idl",
"//third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl",
- "//third_party/blink/renderer/modules/webcodecs/web_codecs_error_callback.idl",
+ "//third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl",
"//third_party/blink/renderer/modules/webdatabase/database.idl",
"//third_party/blink/renderer/modules/webdatabase/sql_error.idl",
"//third_party/blink/renderer/modules/webdatabase/sql_result_set.idl",
@@ -837,6 +882,9 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.idl",
"//third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl",
"//third_party/blink/renderer/modules/webgl/webgl_video_texture.idl",
+ "//third_party/blink/renderer/modules/webgl/webgl_webcodecs_texture_info.idl",
+ "//third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.idl",
+ "//third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame_handle.idl",
"//third_party/blink/renderer/modules/webgpu/gpu.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_adapter.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl",
@@ -845,15 +893,15 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_buffer.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_buffer_binding.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_buffer_copy_view.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_buffer_binding_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_buffer_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_color_dict.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_color_write.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_command_buffer_descriptor.idl",
@@ -863,25 +911,30 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_device.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_device_lost_info.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_fence.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_fence_descriptor.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_image_bitmap_copy_view.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_image_copy_buffer.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_image_copy_image_bitmap.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_image_data_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_limits.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_map_mode.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_object_base.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_object_descriptor_base.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_origin_2d_dict.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_origin_3d_dict.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_pipeline_base.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_pipeline_descriptor_base.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_programmable_stage_descriptor.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_programmable_stage.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_query_set.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_query_set_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_queue.idl",
@@ -899,16 +952,17 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_sampler.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_sampler_binding_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_shader_module_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_stencil_state_face_descriptor.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_stencil_face_state.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_swap_chain_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_texture.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_texture_copy_view.idl",
- "//third_party/blink/renderer/modules/webgpu/gpu_texture_data_layout.idl",
+ "//third_party/blink/renderer/modules/webgpu/gpu_texture_binding_layout.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl",
"//third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl",
@@ -972,16 +1026,25 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_result.idl",
"//third_party/blink/renderer/modules/webusb/usb_out_transfer_result.idl",
"//third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl",
- "//third_party/blink/renderer/modules/xr/element_xr.idl",
+ "//third_party/blink/renderer/modules/xr/document_xr.idl",
+ "//third_party/blink/renderer/modules/xr/html_element_xr.idl",
+ "//third_party/blink/renderer/modules/xr/mathml_element_xr.idl",
"//third_party/blink/renderer/modules/xr/navigator_xr.idl",
+ "//third_party/blink/renderer/modules/xr/svg_element_xr.idl",
+ "//third_party/blink/renderer/modules/xr/window_xr.idl",
"//third_party/blink/renderer/modules/xr/xr_anchor.idl",
"//third_party/blink/renderer/modules/xr/xr_anchor_set.idl",
"//third_party/blink/renderer/modules/xr/xr_bounded_reference_space.idl",
+ "//third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl",
"//third_party/blink/renderer/modules/xr/xr_depth_information.idl",
+ "//third_party/blink/renderer/modules/xr/xr_depth_state_init.idl",
"//third_party/blink/renderer/modules/xr/xr_dom_overlay_init.idl",
"//third_party/blink/renderer/modules/xr/xr_dom_overlay_state.idl",
"//third_party/blink/renderer/modules/xr/xr_frame.idl",
"//third_party/blink/renderer/modules/xr/xr_frame_request_callback.idl",
+ "//third_party/blink/renderer/modules/xr/xr_hand.idl",
+ "//third_party/blink/renderer/modules/xr/xr_joint_pose.idl",
+ "//third_party/blink/renderer/modules/xr/xr_joint_space.idl",
"//third_party/blink/renderer/modules/xr/xr_hit_test_options_init.idl",
"//third_party/blink/renderer/modules/xr/xr_hit_test_result.idl",
"//third_party/blink/renderer/modules/xr/xr_hit_test_source.idl",
@@ -997,7 +1060,6 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/xr/xr_light_probe.idl",
"//third_party/blink/renderer/modules/xr/xr_light_probe_init.idl",
"//third_party/blink/renderer/modules/xr/xr_plane.idl",
- "//third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl",
"//third_party/blink/renderer/modules/xr/xr_plane_set.idl",
"//third_party/blink/renderer/modules/xr/xr_pose.idl",
"//third_party/blink/renderer/modules/xr/xr_ray.idl",
@@ -1023,10 +1085,9 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/xr/xr_viewport.idl",
"//third_party/blink/renderer/modules/xr/xr_webgl_binding.idl",
"//third_party/blink/renderer/modules/xr/xr_webgl_context.idl",
+ "//third_party/blink/renderer/modules/xr/xr_webgl_depth_information.idl",
"//third_party/blink/renderer/modules/xr/xr_webgl_layer.idl",
"//third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl",
- "//third_party/blink/renderer/modules/xr/xr_world_information.idl",
- "//third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl",
],
"abspath")
@@ -1048,8 +1109,6 @@ if (!is_android) {
[
"//third_party/blink/renderer/modules/serial/navigator_serial.idl",
"//third_party/blink/renderer/modules/serial/serial.idl",
- "//third_party/blink/renderer/modules/serial/serial_connection_event.idl",
- "//third_party/blink/renderer/modules/serial/serial_connection_event_init.idl",
"//third_party/blink/renderer/modules/serial/serial_input_signals.idl",
"//third_party/blink/renderer/modules/serial/serial_options.idl",
"//third_party/blink/renderer/modules/serial/serial_output_signals.idl",
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn b/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
index 28cfe126f64..fd8e73febf2 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/BUILD.gn
@@ -97,29 +97,27 @@ group("bindings_modules_v8_generated") {
]
}
-idl_compiler("generate_bindings_modules_v8_interfaces") {
- if (use_blink_v8_binding_new_idl_interface) {
- modules_interface_idl_files =
- filter_exclude(modules_idl_files, [ "*_callback.idl" ])
- }
- if (use_blink_v8_binding_new_idl_callback_interface) {
- modules_callback_interface_idl_files =
- filter_include(modules_idl_files, [ "*_callback.idl" ])
- }
-
- sources = modules_definition_idl_files
- if (use_blink_v8_binding_new_idl_callback_interface) {
- sources -= modules_callback_interface_idl_files
- }
- if (use_blink_v8_binding_new_idl_dictionary) {
- sources -= modules_dictionary_idl_files
+if (!use_blink_v8_binding_new_idl_callback_interface ||
+ !use_blink_v8_binding_new_idl_dictionary ||
+ !use_blink_v8_binding_new_idl_interface) {
+ idl_compiler("generate_bindings_modules_v8_interfaces") {
+ sources = []
+ if (!use_blink_v8_binding_new_idl_callback_interface) {
+ sources += filter_include(modules_idl_files, [ "*_callback.idl" ])
+ }
+ if (!use_blink_v8_binding_new_idl_dictionary) {
+ sources += modules_dictionary_idl_files
+ }
+ if (!use_blink_v8_binding_new_idl_interface) {
+ sources += filter_exclude(modules_idl_files, [ "*_callback.idl" ])
+ }
+ output_dir = bindings_modules_v8_output_dir
+ output_name_suffix = ""
+ target_component = "modules"
}
- if (use_blink_v8_binding_new_idl_interface) {
- sources -= modules_interface_idl_files
+} else {
+ group("generate_bindings_modules_v8_interfaces") {
}
- output_dir = bindings_modules_v8_output_dir
- output_name_suffix = ""
- target_component = "modules"
}
idl_impl("bindings_modules_impl_generated") {
@@ -229,8 +227,13 @@ group("generate_mojo_bindings") {
blink_modules_sources("bindings_modules_impl") {
# ":generate_bindings_modules_v8_partial_interfaces_for_testing" is not
# included here.
- sources = get_target_outputs(":generate_bindings_modules_v8_interfaces") +
- get_target_outputs(":bindings_modules_impl_generated")
+ sources = get_target_outputs(":bindings_modules_impl_generated")
+
+ if (!use_blink_v8_binding_new_idl_callback_interface ||
+ !use_blink_v8_binding_new_idl_dictionary ||
+ !use_blink_v8_binding_new_idl_interface) {
+ sources += get_target_outputs(":generate_bindings_modules_v8_interfaces")
+ }
if (!use_blink_v8_binding_new_idl_interface) {
sources +=
get_target_outputs(":generate_bindings_modules_v8_partial_interfaces") +
@@ -248,8 +251,7 @@ blink_modules_sources("bindings_modules_impl") {
]
}
-# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
-python2_action("generate_v8_context_snapshot_external_references") {
+action("generate_v8_context_snapshot_external_references") {
script = "$bindings_scripts_dir/generate_v8_context_snapshot_external_references.py"
idl_files =
core_interface_idl_files_core_only +
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni b/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
index 1641dbd99ad..153a73bccda 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -49,6 +49,10 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/double_or_dom_point.cc",
"$bindings_modules_v8_output_dir/double_sequence_or_gpu_color_dict.cc",
"$bindings_modules_v8_output_dir/double_sequence_or_gpu_color_dict.h",
+ "$bindings_modules_v8_output_dir/encoded_audio_chunk_or_encoded_video_chunk.cc",
+ "$bindings_modules_v8_output_dir/encoded_audio_chunk_or_encoded_video_chunk.h",
+ "$bindings_modules_v8_output_dir/encoded_av_chunk_sequence_or_encoded_av_chunk.cc",
+ "$bindings_modules_v8_output_dir/encoded_av_chunk_sequence_or_encoded_av_chunk.h",
"$bindings_modules_v8_output_dir/float32_array_or_float64_array_or_dom_matrix.cc",
"$bindings_modules_v8_output_dir/float32_array_or_float64_array_or_dom_matrix.h",
"$bindings_modules_v8_output_dir/gpu_buffer_or_array_buffer.cc",
@@ -69,6 +73,8 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index.h",
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index_or_idb_cursor.cc",
"$bindings_modules_v8_output_dir/idb_object_store_or_idb_index_or_idb_cursor.h",
+ "$bindings_modules_v8_output_dir/image_bitmap_source.cc",
+ "$bindings_modules_v8_output_dir/image_bitmap_source.h",
"$bindings_modules_v8_output_dir/int32_array_or_long_sequence.cc",
"$bindings_modules_v8_output_dir/int32_array_or_long_sequence.h",
"$bindings_modules_v8_output_dir/long_or_constrain_long_range.cc",
@@ -91,8 +97,6 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/rendering_context.h",
"$bindings_modules_v8_output_dir/request_or_usv_string_or_request_or_usv_string_sequence.cc",
"$bindings_modules_v8_output_dir/request_or_usv_string_or_request_or_usv_string_sequence.h",
- "$bindings_modules_v8_output_dir/rtc_ice_candidate_init_or_rtc_ice_candidate.cc",
- "$bindings_modules_v8_output_dir/rtc_ice_candidate_init_or_rtc_ice_candidate.h",
"$bindings_modules_v8_output_dir/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.cc",
"$bindings_modules_v8_output_dir/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h",
"$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.cc",
@@ -117,10 +121,14 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/unsigned_long_enforce_range_sequence_or_gpu_origin_3d_dict.h",
"$bindings_modules_v8_output_dir/usv_string_or_uint32_array.cc",
"$bindings_modules_v8_output_dir/usv_string_or_uint32_array.h",
+ "$bindings_modules_v8_output_dir/usv_string_or_url_pattern_init.cc",
+ "$bindings_modules_v8_output_dir/usv_string_or_url_pattern_init.h",
"$bindings_modules_v8_output_dir/usv_string_or_usv_string_sequence.cc",
"$bindings_modules_v8_output_dir/usv_string_or_usv_string_sequence.h",
"$bindings_modules_v8_output_dir/webgl_rendering_context_or_webgl2_rendering_context.cc",
"$bindings_modules_v8_output_dir/webgl_rendering_context_or_webgl2_rendering_context.h",
+ "$bindings_modules_v8_output_dir/well_known_directory_or_file_system_handle.cc",
+ "$bindings_modules_v8_output_dir/well_known_directory_or_file_system_handle.h",
"$bindings_modules_v8_output_dir/worklet_animation_effect_or_worklet_group_effect.cc",
"$bindings_modules_v8_output_dir/worklet_animation_effect_or_worklet_group_effect.h",
]
@@ -142,8 +150,8 @@ generated_modules_callback_function_files = [
"$bindings_modules_v8_output_dir/v8_decode_error_callback.h",
"$bindings_modules_v8_output_dir/v8_decode_success_callback.cc",
"$bindings_modules_v8_output_dir/v8_decode_success_callback.h",
- "$bindings_modules_v8_output_dir/v8_idb_observer_callback.cc",
- "$bindings_modules_v8_output_dir/v8_idb_observer_callback.h",
+ "$bindings_modules_v8_output_dir/v8_encoded_audio_chunk_output_callback.cc",
+ "$bindings_modules_v8_output_dir/v8_encoded_audio_chunk_output_callback.h",
"$bindings_modules_v8_output_dir/v8_launch_consumer.cc",
"$bindings_modules_v8_output_dir/v8_launch_consumer.h",
"$bindings_modules_v8_output_dir/v8_lock_granted_callback.cc",
@@ -184,8 +192,8 @@ generated_modules_callback_function_files = [
"$bindings_modules_v8_output_dir/v8_video_frame_output_callback.h",
"$bindings_modules_v8_output_dir/v8_video_frame_request_callback.cc",
"$bindings_modules_v8_output_dir/v8_video_frame_request_callback.h",
- "$bindings_modules_v8_output_dir/v8_web_codecs_error_callback.cc",
- "$bindings_modules_v8_output_dir/v8_web_codecs_error_callback.h",
+ "$bindings_modules_v8_output_dir/v8_webcodecs_error_callback.cc",
+ "$bindings_modules_v8_output_dir/v8_webcodecs_error_callback.h",
"$bindings_modules_v8_output_dir/v8_xr_frame_request_callback.cc",
"$bindings_modules_v8_output_dir/v8_xr_frame_request_callback.h",
]
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
index 41d0fc1cf41..327c0e8afe1 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.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/file_system_access_manager.mojom-blink.h"
#include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_crypto.h"
@@ -13,8 +13,8 @@
#include "third_party/blink/renderer/bindings/modules/v8/serialization/web_crypto_sub_tags.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/crypto/crypto_key.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_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h"
#include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_certificate_generator.h"
@@ -52,9 +52,9 @@ ScriptWrappable* V8ScriptValueDeserializerForModules::ReadDOMObject(
ExecutionContext::From(GetScriptState()), name,
static_cast<mojom::blink::FileSystemType>(raw_type), KURL(root_url));
}
- case kNativeFileSystemFileHandleTag:
- case kNativeFileSystemDirectoryHandleTag:
- return ReadNativeFileSystemHandle(tag);
+ case kFileSystemFileHandleTag:
+ case kFileSystemDirectoryHandleTag:
+ return ReadFileSystemHandle(tag);
case kRTCCertificateTag: {
String pem_private_key;
String pem_certificate;
@@ -311,10 +311,9 @@ CryptoKey* V8ScriptValueDeserializerForModules::ReadCryptoKey() {
return MakeGarbageCollected<CryptoKey>(key);
}
-NativeFileSystemHandle*
-V8ScriptValueDeserializerForModules::ReadNativeFileSystemHandle(
+FileSystemHandle* V8ScriptValueDeserializerForModules::ReadFileSystemHandle(
SerializationTag tag) {
- if (!RuntimeEnabledFeatures::NativeFileSystemEnabled(
+ if (!RuntimeEnabledFeatures::FileSystemAccessEnabled(
ExecutionContext::From(GetScriptState()))) {
return nullptr;
}
@@ -326,52 +325,52 @@ V8ScriptValueDeserializerForModules::ReadNativeFileSystemHandle(
}
// Find the FileSystemHandle's token.
- SerializedScriptValue::NativeFileSystemTokensArray& tokens_array =
- GetSerializedScriptValue()->NativeFileSystemTokens();
+ SerializedScriptValue::FileSystemAccessTokensArray& tokens_array =
+ GetSerializedScriptValue()->FileSystemAccessTokens();
if (token_index >= tokens_array.size()) {
return nullptr;
}
// IndexedDB code assumes that deserializing a SSV is non-destructive. So
// rather than consuming the token here instead we clone it.
- mojo::Remote<mojom::blink::NativeFileSystemTransferToken> token(
+ mojo::Remote<mojom::blink::FileSystemAccessTransferToken> token(
std::move(tokens_array[token_index]));
if (!token) {
return nullptr;
}
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> token_clone;
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> token_clone;
token->Clone(token_clone.InitWithNewPipeAndPassReceiver());
tokens_array[token_index] = std::move(token_clone);
- // Use the NativeFileSystemManager to redeem the token to clone the
+ // Use the FileSystemAccessManager to redeem the token to clone the
// FileSystemHandle.
ExecutionContext* execution_context =
ExecutionContext::From(GetScriptState());
- mojo::Remote<mojom::blink::NativeFileSystemManager>
- native_file_system_manager;
+ mojo::Remote<mojom::blink::FileSystemAccessManager>
+ file_system_access_manager;
execution_context->GetBrowserInterfaceBroker().GetInterface(
- native_file_system_manager.BindNewPipeAndPassReceiver());
+ file_system_access_manager.BindNewPipeAndPassReceiver());
// Clone the FileSystemHandle object.
switch (tag) {
- case kNativeFileSystemFileHandleTag: {
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle> file_handle;
+ case kFileSystemFileHandleTag: {
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileHandle> file_handle;
- native_file_system_manager->GetFileHandleFromToken(
+ file_system_access_manager->GetFileHandleFromToken(
token.Unbind(), file_handle.InitWithNewPipeAndPassReceiver());
- return MakeGarbageCollected<NativeFileSystemFileHandle>(
- execution_context, name, std::move(file_handle));
+ return MakeGarbageCollected<FileSystemFileHandle>(execution_context, name,
+ std::move(file_handle));
}
- case kNativeFileSystemDirectoryHandleTag: {
- mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle>
+ case kFileSystemDirectoryHandleTag: {
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDirectoryHandle>
directory_handle;
- native_file_system_manager->GetDirectoryHandleFromToken(
+ file_system_access_manager->GetDirectoryHandleFromToken(
token.Unbind(), directory_handle.InitWithNewPipeAndPassReceiver());
- return MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
+ return MakeGarbageCollected<FileSystemDirectoryHandle>(
execution_context, name, std::move(directory_handle));
}
default: {
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
index ccc7f4edec2..90408ee5f1d 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
@@ -11,7 +11,7 @@
namespace blink {
class CryptoKey;
-class NativeFileSystemHandle;
+class FileSystemHandle;
class RTCEncodedAudioFrame;
class RTCEncodedVideoFrame;
class VideoFrame;
@@ -46,7 +46,7 @@ class MODULES_EXPORT V8ScriptValueDeserializerForModules final
return true;
}
CryptoKey* ReadCryptoKey();
- NativeFileSystemHandle* ReadNativeFileSystemHandle(SerializationTag tag);
+ FileSystemHandle* ReadFileSystemHandle(SerializationTag tag);
RTCEncodedAudioFrame* ReadRTCEncodedAudioFrame();
RTCEncodedVideoFrame* ReadRTCEncodedVideoFrame();
VideoFrame* ReadVideoFrame();
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
index 30254b40031..c60809ee7b1 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
@@ -62,18 +62,16 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
return true;
}
if (wrapper_type_info == V8FileSystemFileHandle::GetWrapperTypeInfo() &&
- RuntimeEnabledFeatures::NativeFileSystemEnabled(
+ RuntimeEnabledFeatures::FileSystemAccessEnabled(
ExecutionContext::From(GetScriptState()))) {
- return WriteNativeFileSystemHandle(
- kNativeFileSystemFileHandleTag,
- wrappable->ToImpl<NativeFileSystemHandle>());
+ return WriteFileSystemHandle(kFileSystemFileHandleTag,
+ wrappable->ToImpl<FileSystemHandle>());
}
if (wrapper_type_info == V8FileSystemDirectoryHandle::GetWrapperTypeInfo() &&
- RuntimeEnabledFeatures::NativeFileSystemEnabled(
+ RuntimeEnabledFeatures::FileSystemAccessEnabled(
ExecutionContext::From(GetScriptState()))) {
- return WriteNativeFileSystemHandle(
- kNativeFileSystemDirectoryHandleTag,
- wrappable->ToImpl<NativeFileSystemHandle>());
+ return WriteFileSystemHandle(kFileSystemDirectoryHandleTag,
+ wrappable->ToImpl<FileSystemHandle>());
}
if (wrapper_type_info == V8RTCCertificate::GetWrapperTypeInfo()) {
RTCCertificate* certificate = wrappable->ToImpl<RTCCertificate>();
@@ -110,16 +108,15 @@ bool V8ScriptValueSerializerForModules::WriteDOMObject(
"storage.");
return false;
}
- auto* video_frame = wrappable->ToImpl<VideoFrame>();
-
- if (!video_frame->frame()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kDataCloneError,
- "Cannot serialize destroyed VideoFrame.");
+ scoped_refptr<VideoFrameHandle> handle =
+ wrappable->ToImpl<VideoFrame>()->handle()->Clone();
+ if (!handle) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kDataCloneError,
+ "A VideoFrame could not be cloned "
+ "because it was closed.");
return false;
}
-
- return WriteVideoFrame(video_frame);
+ return WriteVideoFrameHandle(std::move(handle));
}
return false;
}
@@ -301,20 +298,20 @@ bool V8ScriptValueSerializerForModules::WriteCryptoKey(
return true;
}
-bool V8ScriptValueSerializerForModules::WriteNativeFileSystemHandle(
+bool V8ScriptValueSerializerForModules::WriteFileSystemHandle(
SerializationTag tag,
- NativeFileSystemHandle* native_file_system_handle) {
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> token =
- native_file_system_handle->Transfer();
+ FileSystemHandle* file_system_handle) {
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> token =
+ file_system_handle->Transfer();
- SerializedScriptValue::NativeFileSystemTokensArray& tokens_array =
- GetSerializedScriptValue()->NativeFileSystemTokens();
+ SerializedScriptValue::FileSystemAccessTokensArray& tokens_array =
+ GetSerializedScriptValue()->FileSystemAccessTokens();
tokens_array.push_back(std::move(token));
const uint32_t token_index = static_cast<uint32_t>(tokens_array.size() - 1);
WriteTag(tag);
- WriteUTF8String(native_file_system_handle->name());
+ WriteUTF8String(file_system_handle->name());
WriteUint32(token_index);
return true;
}
@@ -347,12 +344,12 @@ bool V8ScriptValueSerializerForModules::WriteRTCEncodedVideoFrame(
return true;
}
-bool V8ScriptValueSerializerForModules::WriteVideoFrame(
- VideoFrame* video_frame) {
+bool V8ScriptValueSerializerForModules::WriteVideoFrameHandle(
+ scoped_refptr<VideoFrameHandle> handle) {
auto* attachment =
GetSerializedScriptValue()->GetOrCreateAttachment<VideoFrameAttachment>();
auto& frames = attachment->Handles();
- frames.push_back(video_frame->handle());
+ frames.push_back(std::move(handle));
const uint32_t index = static_cast<uint32_t>(frames.size() - 1);
WriteTag(kVideoFrameTag);
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.h b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.h
index d15725e12af..3ea3283c636 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.h
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.h
@@ -5,16 +5,17 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_MODULES_V8_SERIALIZATION_V8_SCRIPT_VALUE_SERIALIZER_FOR_MODULES_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_MODULES_V8_SERIALIZATION_V8_SCRIPT_VALUE_SERIALIZER_FOR_MODULES_H_
+#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/platform/web_crypto_algorithm.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
-class NativeFileSystemHandle;
+class FileSystemHandle;
class RTCEncodedAudioFrame;
class RTCEncodedVideoFrame;
-class VideoFrame;
+class VideoFrameHandle;
class WebCryptoKey;
// Extends V8ScriptValueSerializer with support for modules/ types.
@@ -32,12 +33,11 @@ class MODULES_EXPORT V8ScriptValueSerializerForModules final
private:
void WriteOneByte(uint8_t byte) { WriteRawBytes(&byte, 1); }
bool WriteCryptoKey(const WebCryptoKey&, ExceptionState&);
- bool WriteNativeFileSystemHandle(
- SerializationTag tag,
- NativeFileSystemHandle* native_file_system_handle);
+ bool WriteFileSystemHandle(SerializationTag tag,
+ FileSystemHandle* file_system_handle);
bool WriteRTCEncodedAudioFrame(RTCEncodedAudioFrame*);
bool WriteRTCEncodedVideoFrame(RTCEncodedVideoFrame*);
- bool WriteVideoFrame(VideoFrame*);
+ bool WriteVideoFrameHandle(scoped_refptr<VideoFrameHandle>);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
index 78bb2480df3..170fa8abcf1 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -989,8 +989,8 @@ TEST(V8ScriptValueSerializerForModulesTest, RoundTripVideoFrame) {
scoped_refptr<media::VideoFrame> media_frame =
media::VideoFrame::CreateBlackFrame(kFrameSize);
- // Pass a copy the reference to the video frame.
- auto* blink_frame = MakeGarbageCollected<VideoFrame>(media_frame);
+ auto* blink_frame = MakeGarbageCollected<VideoFrame>(
+ media_frame, scope.GetExecutionContext());
// Round trip the frame and make sure the size is the same.
v8::Local<v8::Value> wrapper = ToV8(blink_frame, scope.GetScriptState());
@@ -1003,13 +1003,16 @@ TEST(V8ScriptValueSerializerForModulesTest, RoundTripVideoFrame) {
EXPECT_FALSE(media_frame->HasOneRef());
- // Destroying either |blink_frame| or |new_frame| should remove all references
+ // Closing |blink_frame| and |new_frame| should remove all references
// to |media_frame|.
- blink_frame->destroy();
+ blink_frame->close();
+ EXPECT_FALSE(media_frame->HasOneRef());
+
+ new_frame->close();
EXPECT_TRUE(media_frame->HasOneRef());
}
-TEST(V8ScriptValueSerializerForModulesTest, DestroyedVideoFrameThrows) {
+TEST(V8ScriptValueSerializerForModulesTest, ClosedVideoFrameThrows) {
V8TestingScope scope;
ExceptionState exception_state(scope.GetIsolate(),
ExceptionState::kExecutionContext, "Window",
@@ -1020,10 +1023,11 @@ TEST(V8ScriptValueSerializerForModulesTest, DestroyedVideoFrameThrows) {
media::VideoFrame::CreateBlackFrame(kFrameSize);
// Create and destroy the frame.
- auto* blink_frame = MakeGarbageCollected<VideoFrame>(media_frame);
- blink_frame->destroy();
+ auto* blink_frame = MakeGarbageCollected<VideoFrame>(
+ media_frame, scope.GetExecutionContext());
+ blink_frame->close();
- // Serializing the destroyed frame should throw an error.
+ // Serializing the closed frame should throw an error.
v8::Local<v8::Value> wrapper = ToV8(blink_frame, scope.GetScriptState());
EXPECT_FALSE(V8ScriptValueSerializer(scope.GetScriptState())
.Serialize(wrapper, exception_state));
diff --git a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
index fd4130e6fe4..1ec45264e7f 100644
--- a/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
+++ b/chromium/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
@@ -145,8 +145,6 @@ v8::Local<v8::Value> ToV8(const IDBAny* impl,
return v8::Undefined(isolate);
case IDBAny::kNullType:
return v8::Null(isolate);
- case IDBAny::kDOMStringListType:
- return ToV8(impl->DomStringList(), creation_context, isolate);
case IDBAny::kIDBCursorType:
return ToV8(impl->IdbCursor(), creation_context, isolate);
case IDBAny::kIDBCursorWithValueType:
@@ -544,8 +542,8 @@ static v8::Local<v8::Value> DeserializeIDBValueData(v8::Isolate* isolate,
scoped_refptr<SerializedScriptValue> serialized_value =
value->CreateSerializedValue();
- serialized_value->NativeFileSystemTokens() =
- std::move(const_cast<IDBValue*>(value)->NativeFileSystemTokens());
+ serialized_value->FileSystemAccessTokens() =
+ std::move(const_cast<IDBValue*>(value)->FileSystemAccessTokens());
SerializedScriptValue::DeserializeOptions options;
options.blob_info = &value->BlobInfo();
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn b/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn
index a6cc71426b1..ced07798d66 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn
+++ b/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn
@@ -18,10 +18,7 @@ action("cached_lex_yacc_tables") {
script = "blink_idl_parser.py"
inputs = idl_lexer_parser_files
- outputs = [
- "$bindings_scripts_output_dir/lextab.py",
- "$bindings_scripts_output_dir/parsetab.pickle",
- ]
+ outputs = [ "$bindings_scripts_output_dir/parsetab.pickle" ]
args = [ rebase_path(bindings_scripts_output_dir, root_build_dir) ]
}
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf
deleted file mode 100644
index 2ae9158e446..00000000000
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf
+++ /dev/null
@@ -1,4 +0,0 @@
-[style]
-# https://www.chromium.org/blink/coding-style
-based_on_style = pep8
-column_limit = 79
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
index e190f7134b8..5496853c9bf 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
@@ -29,8 +29,15 @@ def blink_class_name(idl_definition):
# is implemented as |class EXTsRGB|, not as |ExtSRgb| nor |ExtsRgb|.
if isinstance(idl_definition,
(web_idl.CallbackFunction, web_idl.CallbackInterface,
- web_idl.Enumeration, web_idl.NewUnion)):
+ web_idl.Enumeration)):
return "V8{}".format(idl_definition.identifier)
+ elif isinstance(idl_definition, web_idl.NewUnion):
+ # Technically this name is not guaranteed to be unique because
+ # (X or sequence<Y or Z>) and (X or Y or sequence<Z>) have the same
+ # name, but it's highly unlikely to cause a conflict in the actual use
+ # cases. Plus, we prefer a simple naming rule conformant to the
+ # Chromium coding style. So, we go with this way.
+ return "V8Union{}".format("Or".join(idl_definition.member_tokens))
else:
return idl_definition.identifier
@@ -49,17 +56,19 @@ def v8_bridge_class_name(idl_definition):
return "V8{}".format(idl_definition.identifier)
-def blink_type_info(idl_type):
+def blink_type_info(idl_type, use_new_union=False):
"""
Returns the types of Blink implementation corresponding to the given IDL
type. The returned object has the following attributes.
- member_t: The type of a member variable. E.g. T => Member<T>
ref_t: The type of a local variable that references to an already-existing
value. E.g. String => String&
const_ref_t: A const-qualified reference type.
value_t: The type of a variable that behaves as a value. E.g. String =>
String
+ member_t: The type of a member variable. E.g. T => Member<T>
+ member_ref_t: The type used for input to and output from a member
+ variable. E.g. T* for Member<T> and const String& for String.
has_null_value: True if the Blink implementation type can represent IDL
null value by itself without use of base::Optional<T>.
"""
@@ -72,28 +81,38 @@ def blink_type_info(idl_type):
ref_fmt="{}",
const_ref_fmt="const {}",
value_fmt="{}",
- has_null_value=False):
+ has_null_value=False,
+ clear_member_var_fmt="{}.Clear()"):
self.typename = typename
- self.member_t = member_fmt.format(typename)
+ self.is_gc_type = is_gc_type(idl_type)
self.ref_t = ref_fmt.format(typename)
self.const_ref_t = const_ref_fmt.format(typename)
self.value_t = value_fmt.format(typename)
- # Whether Blink impl type can represent IDL null or not.
+ self.member_t = member_fmt.format(typename)
+ self.member_ref_t = (self.ref_t
+ if self.is_gc_type else self.const_ref_t)
self.has_null_value = has_null_value
+ self._clear_member_var_fmt = clear_member_var_fmt
+
+ def clear_member_var_expr(self, var_name):
+ """Returns an expression to reset the given member variable."""
+ return self._clear_member_var_fmt.format(var_name)
def is_gc_type(idl_type):
idl_type = idl_type.unwrap()
- return bool(idl_type.type_definition_object
- and not idl_type.is_enumeration)
+ return bool(
+ idl_type.is_buffer_source_type or
+ (idl_type.type_definition_object and not idl_type.is_enumeration)
+ or (idl_type.new_union_definition_object and use_new_union))
def vector_element_type(idl_type):
- # Add |Member<T>| explicitly so that the complete type definition of
+ # Use |Member<T>| explicitly so that the complete type definition of
# |T| will not be required.
- typename = blink_type_info(idl_type).typename
- if is_gc_type(idl_type):
- return "Member<{}>".format(typename)
+ type_info = blink_type_info(idl_type)
+ if type_info.is_gc_type:
+ return type_info.member_t
else:
- return typename
+ return type_info.typename
real_type = idl_type.unwrap(typedef=True)
@@ -113,15 +132,16 @@ def blink_type_info(idl_type):
"double": "double",
"unrestricted double": "double",
}
- return TypeInfo(
- cxx_type[real_type.keyword_typename], const_ref_fmt="{}")
+ return TypeInfo(cxx_type[real_type.keyword_typename],
+ const_ref_fmt="{}",
+ clear_member_var_fmt="{} = 0")
if real_type.is_string:
- return TypeInfo(
- "String",
- ref_fmt="{}&",
- const_ref_fmt="const {}&",
- has_null_value=True)
+ return TypeInfo("String",
+ ref_fmt="{}&",
+ const_ref_fmt="const {}&",
+ has_null_value=True,
+ clear_member_var_fmt="{} = String()")
if real_type.is_array_buffer:
assert "AllowShared" not in real_type.extended_attributes
@@ -168,7 +188,7 @@ def blink_type_info(idl_type):
if real_type.type_definition_object:
blink_impl_type = blink_class_name(real_type.type_definition_object)
if real_type.is_enumeration:
- return TypeInfo(blink_impl_type)
+ return TypeInfo(blink_impl_type, clear_member_var_fmt="")
return TypeInfo(
blink_impl_type,
member_fmt="Member<{}>",
@@ -181,18 +201,34 @@ def blink_type_info(idl_type):
or real_type.is_variadic):
typename = "VectorOf<{}>".format(
vector_element_type(real_type.element_type))
- return TypeInfo(typename, ref_fmt="{}&", const_ref_fmt="const {}&")
+ return TypeInfo(typename,
+ ref_fmt="{}&",
+ const_ref_fmt="const {}&",
+ clear_member_var_fmt="{}.clear()")
if real_type.is_record:
typename = "VectorOfPairs<{}, {}>".format(
vector_element_type(real_type.key_type),
vector_element_type(real_type.value_type))
- return TypeInfo(typename, ref_fmt="{}&", const_ref_fmt="const {}&")
+ return TypeInfo(typename,
+ ref_fmt="{}&",
+ const_ref_fmt="const {}&",
+ clear_member_var_fmt="{}.clear()")
if real_type.is_promise:
return TypeInfo(
"ScriptPromise", ref_fmt="{}&", const_ref_fmt="const {}&")
+ if real_type.is_union and use_new_union:
+ blink_impl_type = blink_class_name(
+ real_type.new_union_definition_object)
+ return TypeInfo(blink_impl_type,
+ member_fmt="Member<{}>",
+ ref_fmt="{}*",
+ const_ref_fmt="const {}*",
+ value_fmt="{}*",
+ has_null_value=False)
+
if real_type.is_union:
blink_impl_type = blink_class_name(real_type.union_definition_object)
return TypeInfo(
@@ -205,15 +241,29 @@ def blink_type_info(idl_type):
inner_type = blink_type_info(real_type.inner_type)
if inner_type.has_null_value:
return inner_type
- return TypeInfo(
- "base::Optional<{}>".format(inner_type.value_t),
- ref_fmt="{}&",
- const_ref_fmt="const {}&")
+ return TypeInfo("base::Optional<{}>".format(inner_type.value_t),
+ ref_fmt="{}&",
+ const_ref_fmt="const {}&",
+ clear_member_var_fmt="{}.reset()")
assert False, "Unknown type: {}".format(idl_type.syntactic_form)
-def native_value_tag(idl_type):
+def native_value_tag(idl_type, argument=None, apply_optional_to_last_arg=True):
+ """Returns the tag type of NativeValueTraits."""
+ assert isinstance(idl_type, web_idl.IdlType)
+ assert argument is None or isinstance(argument, web_idl.Argument)
+
+ if (idl_type.is_optional and argument
+ and not (idl_type.is_nullable or argument.default_value)
+ and (apply_optional_to_last_arg
+ or argument != argument.owner.arguments[-1])):
+ return "IDLOptional<{}>".format(_native_value_tag_impl(idl_type))
+
+ return _native_value_tag_impl(idl_type)
+
+
+def _native_value_tag_impl(idl_type):
"""Returns the tag type of NativeValueTraits."""
assert isinstance(idl_type, web_idl.IdlType)
@@ -251,15 +301,16 @@ def native_value_tag(idl_type):
if real_type.is_sequence:
return "IDLSequence<{}>".format(
- native_value_tag(real_type.element_type))
+ _native_value_tag_impl(real_type.element_type))
if real_type.is_frozen_array:
- return "IDLArray<{}>".format(native_value_tag(real_type.element_type))
+ return "IDLArray<{}>".format(
+ _native_value_tag_impl(real_type.element_type))
if real_type.is_record:
return "IDLRecord<{}, {}>".format(
- native_value_tag(real_type.key_type),
- native_value_tag(real_type.value_type))
+ _native_value_tag_impl(real_type.key_type),
+ _native_value_tag_impl(real_type.value_type))
if real_type.is_promise:
return "IDLPromise"
@@ -271,40 +322,48 @@ def native_value_tag(idl_type):
return "IDLUnionNotINT<{}>".format(class_name)
if real_type.is_nullable:
- return "IDLNullable<{}>".format(native_value_tag(real_type.inner_type))
+ return "IDLNullable<{}>".format(
+ _native_value_tag_impl(real_type.inner_type))
assert False, "Unknown type: {}".format(idl_type.syntactic_form)
-def make_blink_to_v8_value(v8_var_name, blink_value_expr, idl_type,
- v8_creation_context):
+def make_blink_to_v8_value(
+ v8_var_name,
+ blink_value_expr,
+ idl_type,
+ argument=None,
+ error_exit_return_statement="return v8::MaybeLocal<v8::Value>();",
+ creation_context_script_state="${script_state}"):
"""
Returns a SymbolNode whose definition converts a Blink value to a v8::Value.
"""
assert isinstance(v8_var_name, str)
assert isinstance(blink_value_expr, str)
assert isinstance(idl_type, web_idl.IdlType)
- assert isinstance(v8_creation_context, str)
+ assert argument is None or isinstance(argument, web_idl.Argument)
+ assert isinstance(error_exit_return_statement, str)
+ assert isinstance(creation_context_script_state, str)
+
+ T = TextNode
+ F = lambda *args, **kwargs: T(_format(*args, **kwargs))
def create_definition(symbol_node):
- if (idl_type.unwrap(typedef=True).is_nullable
- and idl_type.unwrap().is_string):
- pattern = ("v8::Local<v8::Value> {v8_var_name} = "
- "{blink_value_expr}.IsNull() "
- "? v8::Null(${isolate}).As<v8::Value>() "
- ": ToV8("
- "{blink_value_expr}, {v8_creation_context}, ${isolate})"
- ".As<v8::Value>();")
- else:
- pattern = (
- "auto&& {v8_var_name} = ToV8("
- "{blink_value_expr}, {v8_creation_context}, ${isolate});")
- node = TextNode(
- _format(pattern,
- v8_var_name=v8_var_name,
- blink_value_expr=blink_value_expr,
- v8_creation_context=v8_creation_context))
- return SymbolDefinitionNode(symbol_node, [node])
+ binds = {
+ "blink_value_expr": blink_value_expr,
+ "creation_context_script_state": creation_context_script_state,
+ "native_value_tag": native_value_tag(idl_type, argument=argument),
+ "v8_var_name": v8_var_name,
+ }
+ pattern = ("!ToV8Traits<{native_value_tag}>::ToV8("
+ "{creation_context_script_state}, {blink_value_expr})"
+ ".ToLocal(&{v8_var_name})")
+ nodes = [
+ F("v8::Local<v8::Value> {v8_var_name};", **binds),
+ CxxUnlikelyIfNode(cond=F(pattern, **binds),
+ body=T(error_exit_return_statement)),
+ ]
+ return SymbolDefinitionNode(symbol_node, nodes)
return SymbolNode(v8_var_name, definition_constructor=create_definition)
@@ -340,9 +399,12 @@ def make_default_value_expr(idl_type, default_value):
else
var = ${assignment_value};
"""
+ assert isinstance(idl_type, web_idl.IdlType)
+ assert (default_value is None
+ or isinstance(default_value, web_idl.LiteralConstant))
assert default_value.is_type_compatible_with(idl_type)
- class DefaultValueExpr:
+ class DefaultValueExpr(object):
_ALLOWED_SYMBOLS_IN_DEPS = ("isolate")
def __init__(self, initializer_expr, initializer_deps,
@@ -491,8 +553,8 @@ def make_default_value_expr(idl_type, default_value):
def make_v8_to_blink_value(blink_var_name,
v8_value_expr,
idl_type,
- argument_index=None,
- default_value=None,
+ argument=None,
+ error_exit_return_statement="return;",
cg_context=None):
"""
Returns a SymbolNode whose definition converts a v8::Value to a Blink value.
@@ -500,9 +562,8 @@ def make_v8_to_blink_value(blink_var_name,
assert isinstance(blink_var_name, str)
assert isinstance(v8_value_expr, str)
assert isinstance(idl_type, web_idl.IdlType)
- assert (argument_index is None or isinstance(argument_index, (int, long)))
- assert (default_value is None
- or isinstance(default_value, web_idl.LiteralConstant))
+ assert argument is None or isinstance(argument, web_idl.Argument)
+ assert isinstance(error_exit_return_statement, str)
T = TextNode
F = lambda *args, **kwargs: T(_format(*args, **kwargs))
@@ -536,28 +597,34 @@ def make_v8_to_blink_value(blink_var_name,
v8_value_expr)
def create_definition(symbol_node):
- if argument_index is None:
+ if argument is None:
func_name = "NativeValue"
arguments = ["${isolate}", v8_value_expr, "${exception_state}"]
else:
func_name = "ArgumentValue"
arguments = [
"${isolate}",
- str(argument_index),
+ str(argument.index),
v8_value_expr,
"${exception_state}",
]
if "StringContext" in idl_type.effective_annotations:
arguments.append("${execution_context_of_document_tree}")
- blink_value_expr = _format(
- "NativeValueTraits<{_1}>::{_2}({_3})",
- _1=native_value_tag(idl_type),
- _2=func_name,
- _3=", ".join(arguments))
- default_expr = (make_default_value_expr(idl_type, default_value)
- if default_value else None)
+ blink_value_expr = _format("NativeValueTraits<{_1}>::{_2}({_3})",
+ _1=native_value_tag(
+ idl_type,
+ argument=argument,
+ apply_optional_to_last_arg=False),
+ _2=func_name,
+ _3=", ".join(arguments))
+ if argument and argument.default_value:
+ default_expr = make_default_value_expr(idl_type,
+ argument.default_value)
+ else:
+ default_expr = None
exception_exit_node = CxxUnlikelyIfNode(
- cond="${exception_state}.HadException()", body=T("return;"))
+ cond="${exception_state}.HadException()",
+ body=T(error_exit_return_statement))
if not (default_expr or fast_path_cond):
return SymbolDefinitionNode(symbol_node, [
@@ -569,7 +636,10 @@ def make_v8_to_blink_value(blink_var_name,
"decltype(NativeValueTraits<{}>::NativeValue("
"std::declval<v8::Isolate*>(), "
"std::declval<v8::Local<v8::Value>>(), "
- "std::declval<ExceptionState&>()))", native_value_tag(idl_type))
+ "std::declval<ExceptionState&>()))",
+ native_value_tag(idl_type,
+ argument=argument,
+ apply_optional_to_last_arg=False))
if default_expr and default_expr.is_initialization_lightweight:
pattern = "{} ${{{}}}{{{}}};"
args = [
@@ -620,7 +690,7 @@ def make_v8_to_blink_value_variadic(blink_var_name, v8_array,
"""
assert isinstance(blink_var_name, str)
assert isinstance(v8_array, str)
- assert isinstance(v8_array_start_index, (int, long))
+ assert isinstance(v8_array_start_index, int)
assert isinstance(idl_type, web_idl.IdlType)
pattern = ("auto&& ${{{_1}}} = "
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_function.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_function.py
index ff68193e392..f15a7edcb49 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_function.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_function.py
@@ -49,13 +49,12 @@ def bind_local_vars(code_node, cg_context, is_construct_call=False):
local_vars = []
local_vars.extend([
- S("argument_creation_context",
- ("v8::Local<v8::Object> ${argument_creation_context} = "
- "CallbackRelevantScriptState()->GetContext()->Global();")),
S("exception_state", ("ExceptionState ${exception_state}("
"${isolate}, ExceptionState::kExecutionContext,"
"${class_like_name}, ${property_name});")),
S("isolate", "v8::Isolate* ${isolate} = GetIsolate();"),
+ S("script_state",
+ "ScriptState* ${script_state} = CallbackRelevantScriptState();"),
])
if cg_context.callback_function:
@@ -311,9 +310,13 @@ bindings::CallbackInvokeHelper<{template_params}> helper(
v8_arg_name = name_style.local_var_f("v8_arg{}_{}", index + 1,
arguments[index].identifier)
body.register_code_symbol(
- make_blink_to_v8_value(v8_arg_name, arg_name,
- arguments[index].idl_type,
- "${argument_creation_context}"))
+ make_blink_to_v8_value(
+ v8_arg_name,
+ arg_name,
+ arguments[index].idl_type,
+ argument=arguments[index],
+ error_exit_return_statement=(
+ "return ${return_value_on_failure};")))
body.append(
F("argv[{index}] = ${{{v8_arg}}};",
index=index,
@@ -322,10 +325,13 @@ bindings::CallbackInvokeHelper<{template_params}> helper(
v8_arg_name = name_style.local_var_f("v8_arg{}_{}", len(arguments),
arguments[-1].identifier)
body.register_code_symbol(
- make_blink_to_v8_value(v8_arg_name,
- "{}[i]".format(variadic_arg_name),
- arguments[-1].idl_type,
- "${argument_creation_context}"))
+ make_blink_to_v8_value(
+ v8_arg_name,
+ "{}[i]".format(variadic_arg_name),
+ arguments[-1].idl_type.unwrap(variadic=True),
+ argument=arguments[-1],
+ error_exit_return_statement=(
+ "return ${return_value_on_failure};")))
body.append(
CxxForLoopNode(
cond=F("wtf_size_t i = 0; i < {var_arg}.size(); ++i",
@@ -335,7 +341,7 @@ bindings::CallbackInvokeHelper<{template_params}> helper(
non_var_arg_size=len(arguments) - 1,
v8_arg=v8_arg_name),
],
- weak_dep_syms=["argument_creation_context", "isolate"]))
+ weak_dep_syms=["isolate", "script_state"]))
body.extend([
CxxUnlikelyIfNode(cond="!helper.Call(argc, argv)",
@@ -589,11 +595,13 @@ def generate_callback_function(callback_function_identifier):
source_node.accumulator.add_include_headers([
"third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.h",
"third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
+ "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h",
])
(header_forward_decls, header_include_headers, source_forward_decls,
source_include_headers) = collect_forward_decls_and_include_headers(
- [callback_function.return_type] +
- map(lambda argument: argument.idl_type, callback_function.arguments))
+ [callback_function.return_type] + list(
+ map(lambda argument: argument.idl_type,
+ callback_function.arguments)))
header_node.accumulator.add_class_decls(header_forward_decls)
header_node.accumulator.add_include_headers(header_include_headers)
source_node.accumulator.add_class_decls(source_forward_decls)
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
index f64cef88c48..45bc422d5b2 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
@@ -177,7 +177,7 @@ def generate_callback_interface(callback_interface_identifier):
prop_install_mode=PropInstallMode.UNCONDITIONAL,
trampoline_var_name=None,
attribute_entries=[],
- constant_entries=filter(is_unconditional, constant_entries),
+ constant_entries=list(filter(is_unconditional, constant_entries)),
exposed_construct_entries=[],
operation_entries=[])
(install_interface_template_decl, install_interface_template_def,
@@ -286,12 +286,13 @@ def generate_callback_interface(callback_interface_identifier):
source_node.accumulator.add_include_headers([
"third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.h",
"third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
+ "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h",
])
(header_forward_decls, header_include_headers, source_forward_decls,
source_include_headers) = collect_forward_decls_and_include_headers(
- [callback_interface.operation_groups[0][0].return_type] +
- map(lambda argument: argument.idl_type,
- callback_interface.operation_groups[0][0].arguments))
+ [callback_interface.operation_groups[0][0].return_type] + list(
+ map(lambda argument: argument.idl_type,
+ callback_interface.operation_groups[0][0].arguments)))
header_node.accumulator.add_class_decls(header_forward_decls)
header_node.accumulator.add_include_headers(header_include_headers)
source_node.accumulator.add_class_decls(source_forward_decls)
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
index 52972fefe20..e5ae9d9629e 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
@@ -503,13 +503,13 @@ class CompositeNode(CodeNode):
gensym_kwargs = {}
template_vars = {}
for arg in args:
- assert isinstance(arg, (CodeNode, int, long, str))
+ assert isinstance(arg, (CodeNode, int, str))
gensym = CodeNode.gensym()
gensym_args.append("${{{}}}".format(gensym))
template_vars[gensym] = arg
for key, value in kwargs.items():
- assert isinstance(key, (int, long, str))
- assert isinstance(value, (CodeNode, int, long, str))
+ assert isinstance(key, (int, str))
+ assert isinstance(value, (CodeNode, int, str))
gensym = CodeNode.gensym()
gensym_kwargs[key] = "${{{}}}".format(gensym)
template_vars[gensym] = value
@@ -602,7 +602,7 @@ class ListNode(CodeNode):
def insert(self, index, node):
if node is None:
return
- assert isinstance(index, (int, long))
+ assert isinstance(index, int)
assert isinstance(node, CodeNode)
assert node.outer is None and node.prev is None
@@ -721,7 +721,7 @@ class SymbolScopeNode(SequenceNode):
if not scope_chains:
return counts
- self_index = iter(scope_chains).next().index(self)
+ self_index = next(iter(scope_chains)).index(self)
scope_chains = map(
lambda scope_chain: scope_chain[self_index + 1:], scope_chains)
scope_to_likeliness = {}
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
index a229a6c71c9..5fa288dabf2 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
@@ -109,7 +109,7 @@ def expr_and(terms):
if any(term.is_always_false for term in terms):
return _Expr(False)
- terms = filter(lambda x: not x.is_always_true, terms)
+ terms = list(filter(lambda x: not x.is_always_true, terms))
if not terms:
return _Expr(True)
if len(terms) == 1:
@@ -124,7 +124,7 @@ def expr_or(terms):
if any(term.is_always_true for term in terms):
return _Expr(True)
- terms = filter(lambda x: not x.is_always_false, terms)
+ terms = list(filter(lambda x: not x.is_always_false, terms))
if not terms:
return _Expr(False)
if len(terms) == 1:
@@ -222,7 +222,7 @@ def expr_from_exposure(exposure,
elif exposure.only_in_secure_contexts is False:
secure_context_term = _Expr(True)
else:
- terms = map(ref_enabled, exposure.only_in_secure_contexts)
+ terms = list(map(ref_enabled, exposure.only_in_secure_contexts))
secure_context_term = expr_or(
[_Expr("${is_in_secure_context}"),
expr_not(expr_and(terms))])
@@ -275,10 +275,11 @@ def expr_from_exposure(exposure,
# [ContextEnabled]
if exposure.context_enabled_features:
- terms = map(
- lambda feature: _Expr(
- "${{context_feature_settings}}->is{}Enabled()".format(
- feature)), exposure.context_enabled_features)
+ terms = list(
+ map(
+ lambda feature: _Expr(
+ "${{context_feature_settings}}->is{}Enabled()".format(
+ feature)), exposure.context_enabled_features))
context_enabled_terms.append(
expr_and([_Expr("${context_feature_settings}"),
expr_or(terms)]))
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py
index 87d26eec3ca..d88fac3a228 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py
@@ -23,10 +23,11 @@ class _TemplateFormatter(string.Formatter):
self._template_formatter_indexing_count_ = 0
def get_value(self, key, args, kwargs):
- if isinstance(key, (int, long)):
+ if isinstance(key, int):
return args[key]
assert isinstance(key, str)
if not key:
+ # TODO(crbug.com/1174969):
# Prior to Python 3.1, when a positional argument specifier is
# omitted, |format_string="{}"| produces |key=""|. Should be
# removed once Python2 gets retired.
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
index 1f808e310d0..e24764c13bd 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -179,4 +179,5 @@ def write_code_node_to_file(code_node, filepath):
filename=format_result.filename,
stderr=format_result.error_message))
- web_idl.file_io.write_to_file_if_changed(filepath, format_result.contents)
+ web_idl.file_io.write_to_file_if_changed(
+ filepath, format_result.contents.encode('utf-8'))
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
index bee4581d5f9..52b72f61554 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
@@ -886,7 +886,7 @@ def make_dict_trace_func(cg_context):
_2 = _blink_member_name(member).value_var
return TextNode(_format(pattern, _1=_1, _2=_2))
- body.extend(map(make_trace_member_node, own_members))
+ body.extend(list(map(make_trace_member_node, own_members)))
body.append(TextNode("BaseClass::Trace(visitor);"))
return func_decl, func_def
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 5a6c82c1b8f..e09a559c389 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -244,11 +244,13 @@ const auto ${arg1_value} = arg1_value_maybe_enum.value();
cg_context.attribute.idl_type))
return
- for index, argument in enumerate(cg_context.function_like.arguments):
- name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier)
+ for argument in cg_context.function_like.arguments:
+ name = name_style.arg_f("arg{}_{}", argument.index + 1,
+ argument.identifier)
if argument.is_variadic:
code_node.register_code_symbol(
- make_v8_to_blink_value_variadic(name, "${info}", index,
+ make_v8_to_blink_value_variadic(name, "${info}",
+ argument.index,
argument.idl_type))
else:
v8_value = "${{info}}[{}]".format(argument.index)
@@ -256,8 +258,7 @@ const auto ${arg1_value} = arg1_value_maybe_enum.value();
make_v8_to_blink_value(name,
v8_value,
argument.idl_type,
- argument_index=index,
- default_value=argument.default_value,
+ argument=argument,
cg_context=cg_context))
@@ -582,7 +583,7 @@ def _make_blink_api_call(code_node,
overriding_args=None):
assert isinstance(code_node, SymbolScopeNode)
assert isinstance(cg_context, CodeGenContext)
- assert num_of_args is None or isinstance(num_of_args, (int, long))
+ assert num_of_args is None or isinstance(num_of_args, int)
assert (overriding_args is None
or (isinstance(overriding_args, (list, tuple))
and all(isinstance(arg, str) for arg in overriding_args)))
@@ -1060,8 +1061,9 @@ def _make_overload_dispatcher_per_arg_size(cg_context, items):
# 12.4. if V is a platform object, ...
def inheritance_length(func_and_type):
- return len(func_and_type[1].type_definition_object.
- inclusive_inherited_interfaces)
+ return (len(func_and_type[1].type_definition_object.
+ inclusive_inherited_interfaces),
+ func_and_type[1].type_definition_object.identifier)
# Attempt to match from most derived to least derived.
for func_like, idl_type in sorted(
@@ -1118,16 +1120,12 @@ def _make_overload_dispatcher_per_arg_size(cg_context, items):
"bindings::IsEsIterableObject"
"(${isolate}, {value}, ${exception_state})")
dispatcher_nodes.append(
- TextNode("if (${exception_state}.HadException()) {\n"
- " return;\n"
- "}"))
+ CxxUnlikelyIfNode(cond="${exception_state}.HadException()",
+ body=TextNode("return;")))
# 12.10. if Type(V) is Object and ...
- def is_es_object_type(t, u):
- return (u.is_callback_interface or u.is_dictionary or u.is_record
- or u.is_object)
-
- func_like = find(is_es_object_type)
+ func_like = find(lambda t, u: u.is_callback_interface or u.is_dictionary or
+ u.is_record or u.is_object)
if func_like:
dispatch_if("{value}->IsObject()")
@@ -1196,8 +1194,10 @@ def make_overload_dispatcher(cg_context):
did_use_break = did_use_break or can_fail
conditional = expr_or(
- map(lambda item: expr_from_exposure(item.function_like.exposure),
- items))
+ list(
+ map(
+ lambda item: expr_from_exposure(item.function_like.exposure
+ ), items)))
if not conditional.is_always_true:
node = CxxUnlikelyIfNode(cond=conditional, body=node)
@@ -1442,34 +1442,18 @@ def make_steps_of_ce_reactions(cg_context):
or cg_context.named_property_setter
or cg_context.named_property_deleter)
- T = TextNode
-
- nodes = []
-
- ext_attrs = cg_context.member_like.extended_attributes
- if "CustomElementCallbacks" in ext_attrs or "Reflect" in ext_attrs:
- if "CustomElementCallbacks" in ext_attrs:
- nodes.append(T("// [CustomElementCallbacks]"))
- elif "Reflect" in ext_attrs:
- nodes.append(T("// [Reflect]"))
- nodes.append(
- T("V0CustomElementProcessingStack::CallbackDeliveryScope "
- "v0_custom_element_scope;"))
- nodes[-1].accumulate(
- CodeGenAccumulator.require_include_headers([
- "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
- ]))
+ if "CEReactions" not in cg_context.member_like.extended_attributes:
+ return None
- if "CEReactions" in ext_attrs:
- nodes.append(T("// [CEReactions]"))
- nodes.append(T("CEReactionsScope ce_reactions_scope;"))
- nodes[-1].accumulate(
- CodeGenAccumulator.require_include_headers([
- "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
- ]))
+ nodes = [
+ TextNode("// [CEReactions]"),
+ TextNode("CEReactionsScope ce_reactions_scope;"),
+ ]
- if not nodes:
- return None
+ nodes[-1].accumulate(
+ CodeGenAccumulator.require_include_headers([
+ "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
+ ]))
# CEReactions scope is not tolerant of V8 exception, so it's necessary to
# invoke custom element reactions before throwing an exception. Thus, put
@@ -1812,12 +1796,12 @@ EventListener* event_handler = JSEventHandler::CreateOrNull(
has_cereactions = True
elif key == "Reflect":
has_reflect = True
- elif key in ("Affects", "CustomElementCallbacks", "DeprecateAs",
- "Exposed", "LogActivity", "LogAllWorlds", "Measure",
- "MeasureAs", "ReflectEmpty", "ReflectInvalid",
- "ReflectMissing", "ReflectOnly",
- "RuntimeCallStatsCounter", "RuntimeEnabled",
- "SecureContext", "URL", "Unscopable"):
+ elif key in ("Affects", "DeprecateAs", "Exposed", "LogActivity",
+ "LogAllWorlds", "Measure", "MeasureAs",
+ "ReflectEmpty", "ReflectInvalid", "ReflectMissing",
+ "ReflectOnly", "RuntimeCallStatsCounter",
+ "RuntimeEnabled", "SecureContext", "URL",
+ "Unscopable"):
pass
else:
return None
@@ -2435,7 +2419,7 @@ if (${info}.ShouldThrowOnError()) {
"blink_property_value",
"${v8_property_value}",
cg_context.indexed_property_setter.arguments[1].idl_type,
- argument_index=2))
+ argument=cg_context.indexed_property_setter.arguments[1]))
body.extend([
TextNode("""\
@@ -2797,7 +2781,7 @@ if (!is_creating) {
"blink_property_value",
"${v8_property_value}",
cg_context.named_property_setter.arguments[1].idl_type,
- argument_index=2))
+ argument=cg_context.named_property_setter.arguments[1]))
if "Custom" in cg_context.named_property_setter.extended_attributes:
text = _format(
@@ -4652,7 +4636,7 @@ class _PropEntryConstructorGroup(_PropEntryBase):
def __init__(self, is_context_dependent, exposure_conditional, world,
constructor_group, ctor_callback_name, ctor_func_length):
assert isinstance(ctor_callback_name, str)
- assert isinstance(ctor_func_length, (int, long))
+ assert isinstance(ctor_func_length, int)
_PropEntryBase.__init__(self, is_context_dependent,
exposure_conditional, world, constructor_group)
@@ -4680,7 +4664,7 @@ class _PropEntryOperationGroup(_PropEntryBase):
op_func_length,
no_alloc_direct_callback_name=None):
assert isinstance(op_callback_name, str)
- assert isinstance(op_func_length, (int, long))
+ assert isinstance(op_func_length, int)
_PropEntryBase.__init__(self, is_context_dependent,
exposure_conditional, world, operation_group)
@@ -5199,9 +5183,9 @@ def make_install_interface_template(cg_context, function_name, class_name,
])
if class_like.identifier == "CSSStyleDeclaration":
- css_properties = filter(
- lambda attr: "CSSProperty" in attr.extended_attributes,
- class_like.attributes)
+ css_properties = list(
+ filter(lambda attr: "CSSProperty" in attr.extended_attributes,
+ class_like.attributes))
if css_properties:
prop_name_list = "".join(
map(lambda attr: "\"{}\", ".format(attr.identifier),
@@ -5228,8 +5212,9 @@ def make_install_interface_template(cg_context, function_name, class_name,
// https://heycam.github.io/webidl/#es-DOMException-specialness
{
v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template =
- v8::FunctionTemplate::New(${isolate});
- intrinsic_error_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(${isolate}, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(${isolate}, "prototype"), v8::kErrorPrototype);
${interface_function_template}->Inherit(
@@ -5237,7 +5222,7 @@ def make_install_interface_template(cg_context, function_name, class_name,
}
"""))
- if class_like.identifier == "NativeFileSystemDirectoryIterator":
+ if class_like.identifier == "FileSystemDirectoryIterator":
body.append(
T("""\
// Temporary @@asyncIterator support for FileSystemDirectoryHandle
@@ -5245,8 +5230,9 @@ def make_install_interface_template(cg_context, function_name, class_name,
{
v8::Local<v8::FunctionTemplate>
intrinsic_iterator_prototype_interface_template =
- v8::FunctionTemplate::New(${isolate});
- intrinsic_iterator_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(${isolate}, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(${isolate}, "prototype"), v8::kAsyncIteratorPrototype);
${interface_function_template}->Inherit(
@@ -5272,8 +5258,9 @@ ${instance_object_template}->MarkAsUndetectable();
{
v8::Local<v8::FunctionTemplate>
intrinsic_iterator_prototype_interface_template =
- v8::FunctionTemplate::New(${isolate});
- intrinsic_iterator_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(${isolate}, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(${isolate}, "prototype"), v8::kIteratorPrototype);
${interface_function_template}->Inherit(
@@ -5606,8 +5593,8 @@ ${instance_object} = ${v8_context}->Global()->GetPrototype().As<v8::Object>();\
pattern,
install_func="IDLMemberInstaller::InstallConstants",
table_name=table_name)
- constant_callback_entries = filter(lambda entry: entry.const_callback_name,
- constant_entries)
+ constant_callback_entries = list(
+ filter(lambda entry: entry.const_callback_name, constant_entries))
install_properties(table_name, constant_callback_entries,
_make_constant_callback_registration_table,
installer_call_text)
@@ -5617,8 +5604,8 @@ ${instance_object} = ${v8_context}->Global()->GetPrototype().As<v8::Object>();\
pattern,
install_func="IDLMemberInstaller::InstallConstants",
table_name=table_name)
- constant_value_entries = filter(
- lambda entry: not entry.const_callback_name, constant_entries)
+ constant_value_entries = list(
+ filter(lambda entry: not entry.const_callback_name, constant_entries))
install_properties(table_name, constant_value_entries,
_make_constant_value_registration_table,
installer_call_text)
@@ -5637,12 +5624,14 @@ ${instance_object} = ${v8_context}->Global()->GetPrototype().As<v8::Object>();\
pattern,
install_func="IDLMemberInstaller::InstallOperations",
table_name=table_name)
- entries = filter(lambda entry: not entry.no_alloc_direct_callback_name,
- operation_entries)
+ entries = list(
+ filter(lambda entry: not entry.no_alloc_direct_callback_name,
+ operation_entries))
install_properties(table_name, entries, _make_operation_registration_table,
installer_call_text)
- entries = filter(lambda entry: entry.no_alloc_direct_callback_name,
- operation_entries)
+ entries = list(
+ filter(lambda entry: entry.no_alloc_direct_callback_name,
+ operation_entries))
install_properties(table_name, entries, _make_operation_registration_table,
installer_call_text)
@@ -6324,8 +6313,8 @@ def make_v8_context_snapshot_api(cg_context, component, attribute_entries,
return None, None
derived_interfaces = cg_context.interface.deriveds
- derived_names = map(lambda interface: interface.identifier,
- derived_interfaces)
+ derived_names = list(
+ map(lambda interface: interface.identifier, derived_interfaces))
derived_names.append(cg_context.interface.identifier)
if not ("Window" in derived_names or "HTMLDocument" in derived_names):
return None, None
@@ -6399,9 +6388,11 @@ def _make_v8_context_snapshot_get_reference_table_function(
collect_callbacks(named_properties_object_callback_defs)
collect_callbacks(cross_origin_property_callback_defs)
- entry_nodes = map(
- lambda name: TextNode("reinterpret_cast<intptr_t>({}),".format(name)),
- filter(None, callback_names))
+ entry_nodes = list(
+ map(
+ lambda name: TextNode("reinterpret_cast<intptr_t>({}),".format(name
+ )),
+ filter(None, callback_names)))
table_node = ListNode([
TextNode("static const intptr_t kReferenceTable[] = {"),
ListNode(entry_nodes),
@@ -6438,10 +6429,11 @@ def _make_v8_context_snapshot_install_props_per_context_function(
class_name=None,
prop_install_mode=PropInstallMode.V8_CONTEXT_SNAPSHOT,
trampoline_var_name=None,
- attribute_entries=filter(selector, attribute_entries),
- constant_entries=filter(selector, constant_entries),
- exposed_construct_entries=filter(selector, exposed_construct_entries),
- operation_entries=filter(selector, operation_entries))
+ attribute_entries=list(filter(selector, attribute_entries)),
+ constant_entries=list(filter(selector, constant_entries)),
+ exposed_construct_entries=list(
+ filter(selector, exposed_construct_entries)),
+ operation_entries=list(filter(selector, operation_entries)))
return func_decl, func_def
@@ -6804,11 +6796,11 @@ def generate_class_like(class_like):
class_name=impl_class_name,
prop_install_mode=PropInstallMode.UNCONDITIONAL,
trampoline_var_name=tp_install_unconditional_props,
- attribute_entries=filter(is_unconditional, attribute_entries),
- constant_entries=filter(is_unconditional, constant_entries),
- exposed_construct_entries=filter(is_unconditional,
- exposed_construct_entries),
- operation_entries=filter(is_unconditional, operation_entries))
+ attribute_entries=list(filter(is_unconditional, attribute_entries)),
+ constant_entries=list(filter(is_unconditional, constant_entries)),
+ exposed_construct_entries=list(
+ filter(is_unconditional, exposed_construct_entries)),
+ operation_entries=list(filter(is_unconditional, operation_entries)))
(install_context_independent_props_decl,
install_context_independent_props_def,
install_context_independent_props_trampoline) = make_install_properties(
@@ -6817,11 +6809,14 @@ def generate_class_like(class_like):
class_name=impl_class_name,
prop_install_mode=PropInstallMode.CONTEXT_INDEPENDENT,
trampoline_var_name=tp_install_context_independent_props,
- attribute_entries=filter(is_context_independent, attribute_entries),
- constant_entries=filter(is_context_independent, constant_entries),
- exposed_construct_entries=filter(is_context_independent,
- exposed_construct_entries),
- operation_entries=filter(is_context_independent, operation_entries))
+ attribute_entries=list(
+ filter(is_context_independent, attribute_entries)),
+ constant_entries=list(filter(is_context_independent,
+ constant_entries)),
+ exposed_construct_entries=list(
+ filter(is_context_independent, exposed_construct_entries)),
+ operation_entries=list(
+ filter(is_context_independent, operation_entries)))
(install_context_dependent_props_decl, install_context_dependent_props_def,
install_context_dependent_props_trampoline) = make_install_properties(
cg_context,
@@ -6829,11 +6824,13 @@ def generate_class_like(class_like):
class_name=impl_class_name,
prop_install_mode=PropInstallMode.CONTEXT_DEPENDENT,
trampoline_var_name=tp_install_context_dependent_props,
- attribute_entries=filter(is_context_dependent, attribute_entries),
- constant_entries=filter(is_context_dependent, constant_entries),
- exposed_construct_entries=filter(is_context_dependent,
- exposed_construct_entries),
- operation_entries=filter(is_context_dependent, operation_entries))
+ attribute_entries=list(filter(is_context_dependent,
+ attribute_entries)),
+ constant_entries=list(filter(is_context_dependent, constant_entries)),
+ exposed_construct_entries=list(
+ filter(is_context_dependent, exposed_construct_entries)),
+ operation_entries=list(filter(is_context_dependent,
+ operation_entries)))
(install_interface_template_decl, install_interface_template_def,
install_interface_template_trampoline) = make_install_interface_template(
cg_context,
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py
index b4c70553863..f3a2fcd772d 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py
@@ -105,7 +105,7 @@ class MakoRenderer(object):
on_error = self._caller_stack_on_error
if (len(current) <= len(on_error)
and all(current[i] == on_error[i]
- for i in xrange(len(current)))):
+ for i in range(len(current)))):
pass # Error happened in a deeper caller.
else:
self._caller_stack_on_error = list(self._caller_stack)
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
index 931347f0849..f74776cc373 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
@@ -135,7 +135,8 @@ class PathManager(object):
#
# Avoid name_style.file not to make "Int32Array" into
# "int_32_array".
- filename = "V8_{}".format(idl_definition.identifier).lower()
+ filename = "v8_union_{}".format("_".join(
+ idl_definition.member_tokens)).lower()
self._api_basename = filename
self._impl_basename = filename
elif isinstance(idl_definition, web_idl.Union):
@@ -210,13 +211,13 @@ class PathManager(object):
# //third_party/blink/renderer/bindings/scripts/utilities.py
_BACKWARD_COMPATIBLE_UNION_FILEPATHS = {
# modules/canvas2d/CanvasRenderingContext2D.idl
- "CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas":
+ "CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame":
"CanvasImageSource",
# modules/canvas/htmlcanvas/html_canvas_element_module.idl
"CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext":
"RenderingContext",
# core/frame/window_or_worker_global_scope.idl
- "HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas":
+ "HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvasOrVideoFrame":
"ImageBitmapSource",
# bindings/tests/idls/core/TestTypedefs.idl
"NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord":
@@ -230,4 +231,7 @@ _BACKWARD_COMPATIBLE_UNION_FILEPATHS = {
# modules/beacon/navigator_beacon.idl
'ReadableStreamOrBlobOrArrayBufferOrArrayBufferViewOrFormDataOrURLSearchParamsOrUSVString':
'ReadableStreamOrXMLHttpRequestBodyInit',
+ # modules/mediasource/source_buffer.idl
+ 'EncodedAudioChunkOrEncodedVideoChunkSequenceOrEncodedAudioChunkOrEncodedVideoChunk':
+ 'EncodedAVChunkSequenceOrEncodedAVChunk',
}
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py
index dc3493cc394..017d3d47bb3 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py
@@ -70,8 +70,13 @@ def gn_format(contents, filename=None):
def _invoke_format_command(command_line, filename, contents):
- proc = subprocess.Popen(
- command_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ kwargs = {}
+ if sys.version_info.major != 2:
+ kwargs['encoding'] = 'utf-8'
+ proc = subprocess.Popen(command_line,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ **kwargs)
stdout_output, stderr_output = proc.communicate(input=contents)
exit_code = proc.wait()
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/task_queue.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/task_queue.py
index 0fab5c2813b..ab569ee28ec 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/task_queue.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/task_queue.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import functools
import multiprocessing
from .package_initializer import package_initializer
@@ -77,7 +78,7 @@ class TaskQueue(object):
def report_worker_task_progress():
if not report_progress:
return
- done_count = reduce(
+ done_count = functools.reduce(
lambda count, worker_task: count + bool(worker_task.ready()),
self._worker_tasks, 0)
report_progress(len(self._worker_tasks), done_count)
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
index db135ca9796..d55debdb474 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
@@ -7,13 +7,21 @@ import web_idl
from . import name_style
from .blink_v8_bridge import blink_class_name
from .blink_v8_bridge import blink_type_info
+from .blink_v8_bridge import make_v8_to_blink_value
+from .blink_v8_bridge import native_value_tag
+from .blink_v8_bridge import v8_bridge_class_name
from .code_node import EmptyNode
from .code_node import ListNode
+from .code_node import SymbolNode
+from .code_node import SymbolScopeNode
from .code_node import TextNode
+from .code_node_cxx import CxxBlockNode
from .code_node_cxx import CxxClassDefNode
from .code_node_cxx import CxxFuncDeclNode
from .code_node_cxx import CxxFuncDefNode
from .code_node_cxx import CxxNamespaceNode
+from .code_node_cxx import CxxSwitchNode
+from .code_node_cxx import CxxUnlikelyIfNode
from .codegen_accumulator import CodeGenAccumulator
from .codegen_context import CodeGenContext
from .codegen_format import format_template as _format
@@ -43,8 +51,9 @@ class _UnionMember(object):
self._api_pred = "Is{}".format(self._base_name)
self._api_get = "GetAs{}".format(self._base_name)
self._api_set = "Set"
- self._member_var = name_style.member_var("member", self._base_name)
- self._member_type = None
+ self._var_name = name_style.member_var("member", self._base_name)
+ self._idl_type = None
+ self._type_info = None
self._typedef_aliases = ()
@property
@@ -70,12 +79,16 @@ class _UnionMember(object):
return self._api_set
@property
- def member_var(self):
- return self._member_var
+ def var_name(self):
+ return self._var_name
@property
- def member_type(self):
- return self._member_type
+ def idl_type(self):
+ return self._idl_type
+
+ @property
+ def type_info(self):
+ return self._type_info
@property
def typedef_aliases(self):
@@ -95,7 +108,8 @@ class _UnionMemberImpl(_UnionMember):
_UnionMember.__init__(self, base_name=base_name)
self._is_null = idl_type is None
if not self._is_null:
- self._member_type = blink_type_info(idl_type)
+ self._idl_type = idl_type
+ self._type_info = blink_type_info(idl_type)
self._typedef_aliases = tuple([
_UnionMemberAlias(impl=self, typedef=typedef)
for typedef in union.typedef_members
@@ -103,13 +117,43 @@ class _UnionMemberImpl(_UnionMember):
])
+class _UnionMemberSubunion(_UnionMember):
+ def __init__(self, union, subunion):
+ assert isinstance(union, web_idl.NewUnion)
+ assert isinstance(subunion, web_idl.NewUnion)
+
+ _UnionMember.__init__(self, base_name=blink_class_name(subunion))
+ self._type_info = blink_type_info(subunion.idl_types[0],
+ use_new_union=True)
+ self._typedef_aliases = tuple(
+ map(lambda typedef: _UnionMemberAlias(impl=self, typedef=typedef),
+ subunion.aliasing_typedefs))
+ self._blink_class_name = blink_class_name(subunion)
+
+ @property
+ def blink_class_name(self):
+ return self._blink_class_name
+
+
class _UnionMemberAlias(_UnionMember):
def __init__(self, impl, typedef):
- assert isinstance(impl, _UnionMemberImpl)
+ assert isinstance(impl, (_UnionMemberImpl, _UnionMemberSubunion))
assert isinstance(typedef, web_idl.Typedef)
_UnionMember.__init__(self, base_name=typedef.identifier)
- self._member_var = impl.member_var
+ self._var_name = impl.var_name
+ self._type_info = impl.type_info
+
+
+def create_union_members(union):
+ assert isinstance(union, web_idl.NewUnion)
+
+ union_members = map(
+ lambda member_type: _UnionMemberImpl(union, member_type),
+ union.flattened_member_types)
+ if union.does_include_nullable_type:
+ union_members.append(_UnionMemberImpl(union, idl_type=None))
+ return tuple(union_members)
def make_content_type_enum_class_def(cg_context):
@@ -124,12 +168,424 @@ def make_content_type_enum_class_def(cg_context):
member.content_type(with_enum_name=False)))
return ListNode([
+ TextNode("// The type of the content value of this IDL union."),
TextNode("enum class ContentType {"),
ListNode(map(TextNode, entries), separator=", "),
TextNode("};"),
])
+def make_factory_methods(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ S = SymbolNode
+ T = TextNode
+
+ func_decl = CxxFuncDeclNode(name="Create",
+ arg_decls=[
+ "v8::Isolate* isolate",
+ "v8::Local<v8::Value> v8_value",
+ "ExceptionState& exception_state",
+ ],
+ return_type="${class_name}*",
+ static=True)
+
+ func_def = CxxFuncDefNode(name="Create",
+ arg_decls=[
+ "v8::Isolate* isolate",
+ "v8::Local<v8::Value> v8_value",
+ "ExceptionState& exception_state",
+ ],
+ return_type="${class_name}*",
+ class_name="${class_name}")
+ func_def.set_base_template_vars(cg_context.template_bindings())
+
+ body = func_def.body
+ body.add_template_vars({
+ "isolate": "isolate",
+ "v8_value": "v8_value",
+ "exception_state": "exception_state",
+ })
+
+ # Create an instance from v8::Value based on the overload resolution
+ # algorithm.
+ # https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
+
+ union_members = cg_context.union_members
+ member = None # Will be a found member in union_members.
+
+ def find_by_member(test):
+ for member in union_members:
+ if test(member):
+ return member
+ return None
+
+ def find_by_type(test):
+ for member in union_members:
+ if member.idl_type and test(member.idl_type):
+ return member
+ return None
+
+ def dispatch_if(cond_text, value_symbol=None):
+ scope_node = SymbolScopeNode(
+ [T("return MakeGarbageCollected<${class_name}>(${blink_value});")])
+ if not value_symbol:
+ value_symbol = make_v8_to_blink_value(
+ "blink_value",
+ "${v8_value}",
+ member.idl_type,
+ error_exit_return_statement="return nullptr;")
+ scope_node.register_code_symbol(value_symbol)
+ if cond_text is True:
+ body.append(CxxBlockNode(body=scope_node))
+ else:
+ body.append(CxxUnlikelyIfNode(cond=cond_text, body=scope_node))
+
+ # 12.3. if V is null or undefined, ...
+ member = find_by_member(lambda m: m.is_null)
+ if member:
+ dispatch_if("${v8_value}->IsNullOrUndefined()",
+ S("blink_value", "auto&& ${blink_value} = nullptr;"))
+
+ # 12.4. if V is a platform object, ...
+ interface_members = filter(
+ lambda member: member.idl_type and member.idl_type.is_interface,
+ union_members)
+ interface_members = sorted(
+ interface_members,
+ key=lambda member: (len(member.idl_type.type_definition_object.
+ inclusive_inherited_interfaces), member.
+ idl_type.type_definition_object.identifier),
+ reverse=True)
+ # Attempt to match from most derived to least derived.
+ for member in interface_members:
+ v8_bridge_name = v8_bridge_class_name(
+ member.idl_type.type_definition_object)
+ dispatch_if(
+ _format("{}::HasInstance(${isolate}, ${v8_value})",
+ v8_bridge_name))
+
+ # 12.5. if Type(V) is Object, V has an [[ArrayBufferData]] internal
+ # slot, ...
+ member = find_by_type(lambda t: t.is_array_buffer)
+ if member:
+ dispatch_if("${v8_value}->IsArrayBuffer() || "
+ "${v8_value}->IsSharedArrayBuffer()")
+
+ # V8 specific optimization: ArrayBufferView
+ member = find_by_type(lambda t: t.is_array_buffer_view)
+ if member:
+ dispatch_if("${v8_value}->IsArrayBufferView()")
+
+ # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ...
+ member = find_by_type(lambda t: t.is_data_view)
+ if member:
+ dispatch_if("${v8_value}->IsDataView()")
+
+ # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, ...
+ typed_array_types = ("Int8Array", "Int16Array", "Int32Array", "Uint8Array",
+ "Uint16Array", "Uint32Array", "Uint8ClampedArray",
+ "Float32Array", "Float64Array")
+ for typed_array_type in typed_array_types:
+ member = find_by_type(lambda t: t.keyword_typename == typed_array_type)
+ if member:
+ dispatch_if(_format("${v8_value}->Is{}()", typed_array_type))
+
+ # 12.8. if IsCallable(V) is true, ...
+ member = find_by_type(lambda t: t.is_callback_function)
+ if member:
+ dispatch_if("${v8_value}->IsFunction()")
+
+ # 12.9. if Type(V) is Object and ... @@iterator ...
+ member = find_by_type(lambda t: t.is_sequence or t.is_frozen_array)
+ if member:
+ dispatch_if("${v8_value}->IsArray() || " # Excessive optimization
+ "bindings::IsEsIterableObject"
+ "(${isolate}, ${v8_value}, ${exception_state})")
+ body.append(
+ CxxUnlikelyIfNode(cond="${exception_state}.HadException()",
+ body=T("return nullptr;")))
+
+ # 12.10. if Type(V) is Object and ...
+ member = find_by_type(lambda t: t.is_callback_interface or t.is_dictionary
+ or t.is_record or t.is_object)
+ if member:
+ dispatch_if("${v8_value}->IsObject()")
+
+ # 12.11. if Type(V) is Boolean and ...
+ member = find_by_type(lambda t: t.is_boolean)
+ if member:
+ dispatch_if("${v8_value}->IsBoolean()")
+
+ # 12.12. if Type(V) is Number and ...
+ member = find_by_type(lambda t: t.is_numeric)
+ if member:
+ dispatch_if("${v8_value}->IsNumber()")
+
+ # 12.13. if there is an entry in S that has ... a string type ...
+ # 12.14. if there is an entry in S that has ... a numeric type ...
+ # 12.15. if there is an entry in S that has ... boolean ...
+ member = find_by_type(lambda t: t.is_enumeration or t.is_string or t.
+ is_numeric or t.is_boolean)
+ if member:
+ dispatch_if(True)
+ else:
+ body.append(
+ T("${exception_state}.ThrowTypeError("
+ "ExceptionMessages::ValueNotOfType("
+ "UnionNameInIDL().Ascii().c_str()));"))
+ body.append(T("return nullptr;"))
+
+ return func_decl, func_def
+
+
+def make_constructors(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ decls = ListNode()
+
+ for member in cg_context.union_members:
+ if member.is_null:
+ func_def = CxxFuncDefNode(name=cg_context.class_name,
+ arg_decls=["std::nullptr_t"],
+ return_type="",
+ explicit=True,
+ member_initializer_list=[
+ "content_type_({})".format(
+ member.content_type()),
+ ])
+ else:
+ func_def = CxxFuncDefNode(
+ name=cg_context.class_name,
+ arg_decls=["{} value".format(member.type_info.member_ref_t)],
+ return_type="",
+ explicit=True,
+ member_initializer_list=[
+ "content_type_({})".format(member.content_type()),
+ "{}(value)".format(member.var_name),
+ ])
+ decls.append(func_def)
+
+ return decls, None
+
+
+def make_accessor_functions(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ T = TextNode
+ F = lambda *args, **kwargs: T(_format(*args, **kwargs))
+
+ decls = ListNode()
+ defs = ListNode()
+
+ func_def = CxxFuncDefNode(name="GetContentType",
+ arg_decls=[],
+ return_type="ContentType",
+ const=True)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ func_def.body.append(T("return content_type_;"))
+ decls.extend([
+ T("// Returns the type of the content value."),
+ func_def,
+ EmptyNode(),
+ ])
+
+ def make_api_pred(member):
+ func_def = CxxFuncDefNode(name=member.api_pred,
+ arg_decls=[],
+ return_type="bool",
+ const=True)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ func_def.body.append(
+ F("return content_type_ == {};", member.content_type()))
+ return func_def
+
+ def make_api_get(member):
+ func_def = CxxFuncDefNode(name=member.api_get,
+ arg_decls=[],
+ return_type=member.type_info.member_ref_t,
+ const=True)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ func_def.body.extend([
+ F("DCHECK_EQ(content_type_, {});", member.content_type()),
+ F("return {};", member.var_name),
+ ])
+ return func_def
+
+ def make_api_set(member):
+ func_def = CxxFuncDefNode(
+ name=member.api_set,
+ arg_decls=["{} value".format(member.type_info.member_ref_t)],
+ return_type="void")
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ func_def.body.extend([
+ T("Clear();"),
+ F("{} = value;", member.var_name),
+ F("content_type_ = {};", member.content_type()),
+ ])
+ return func_def
+
+ def make_api_set_null(member):
+ func_def = CxxFuncDefNode(name=member.api_set,
+ arg_decls=["std::nullptr_t"],
+ return_type="void")
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ func_def.body.extend([
+ T("Clear();"),
+ F("content_type_ = {};", member.content_type()),
+ ])
+ return func_def
+
+ for member in cg_context.union_members:
+ if member.is_null:
+ decls.append(make_api_pred(member))
+ decls.append(make_api_set_null(member))
+ else:
+ decls.append(make_api_pred(member))
+ for alias in member.typedef_aliases:
+ decls.append(make_api_pred(alias))
+ decls.append(make_api_get(member))
+ for alias in member.typedef_aliases:
+ decls.append(make_api_get(alias))
+ decls.append(make_api_set(member))
+ decls.append(EmptyNode())
+
+ def make_api_subunion_pred(subunion, subunion_members):
+ func_def = CxxFuncDefNode(name=subunion.api_pred,
+ arg_decls=[],
+ return_type="bool",
+ const=True)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ expr = " || ".join(
+ map(
+ lambda member: "content_type_ == {}".format(
+ member.content_type()), subunion_members))
+ func_def.body.append(F("return {};", expr))
+ return func_def, None
+
+ def make_api_subunion_get(subunion, subunion_members):
+ func_decl = CxxFuncDeclNode(name=subunion.api_get,
+ arg_decls=[],
+ return_type=subunion.type_info.value_t,
+ const=True)
+ func_def = CxxFuncDefNode(name=subunion.api_get,
+ arg_decls=[],
+ return_type=subunion.type_info.value_t,
+ const=True,
+ class_name=cg_context.class_name)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ node = CxxSwitchNode(cond="content_type_")
+ node.append(case=None,
+ body=[T("NOTREACHED();"),
+ T("return nullptr;")],
+ should_add_break=False)
+ for member in subunion_members:
+ node.append(case=member.content_type(),
+ body=F("return MakeGarbageCollected<{}>({}());",
+ subunion.blink_class_name, member.api_get),
+ should_add_break=False)
+ func_def.body.append(node)
+ return func_decl, func_def
+
+ def make_api_subunion_set(subunion, subunion_members):
+ func_decl = CxxFuncDeclNode(
+ name=subunion.api_set,
+ arg_decls=["{} value".format(subunion.type_info.const_ref_t)],
+ return_type="void")
+ func_def = CxxFuncDefNode(
+ name=subunion.api_set,
+ arg_decls=["{} value".format(subunion.type_info.const_ref_t)],
+ return_type="void",
+ class_name=cg_context.class_name)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ node = CxxSwitchNode(cond="value->GetContentType()")
+ for member in subunion_members:
+ node.append(case=F("{}::{}", subunion.blink_class_name,
+ member.content_type()),
+ body=F("Set(value->{}());", member.api_get))
+ func_def.body.append(node)
+ return func_decl, func_def
+
+ for subunion in cg_context.union.union_members:
+ subunion_members = create_union_members(subunion)
+ subunion = _UnionMemberSubunion(cg_context.union, subunion)
+ func_decl, func_def = make_api_subunion_pred(subunion,
+ subunion_members)
+ decls.append(func_decl)
+ defs.append(func_def)
+ defs.append(EmptyNode())
+ func_decl, func_def = make_api_subunion_get(subunion, subunion_members)
+ decls.append(func_decl)
+ defs.append(func_def)
+ defs.append(EmptyNode())
+ func_decl, func_def = make_api_subunion_set(subunion, subunion_members)
+ decls.append(func_decl)
+ defs.append(func_def)
+ defs.append(EmptyNode())
+ decls.append(EmptyNode())
+
+ return decls, defs
+
+
+def make_clear_function(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ func_decl = CxxFuncDeclNode(name="Clear", arg_decls=[], return_type="void")
+
+ func_def = CxxFuncDefNode(name="Clear",
+ arg_decls=[],
+ return_type="void",
+ class_name=cg_context.class_name)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ body = func_def.body
+
+ for member in cg_context.union_members:
+ if member.is_null:
+ continue
+ clear_expr = member.type_info.clear_member_var_expr(member.var_name)
+ if clear_expr:
+ body.append(TextNode("{};".format(clear_expr)))
+
+ return func_decl, func_def
+
+
+def make_tov8value_function(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ func_decl = CxxFuncDeclNode(name="ToV8Value",
+ arg_decls=["ScriptState* script_state"],
+ return_type="v8::MaybeLocal<v8::Value>",
+ override=True)
+
+ func_def = CxxFuncDefNode(name="ToV8Value",
+ arg_decls=["ScriptState* script_state"],
+ return_type="v8::MaybeLocal<v8::Value>",
+ class_name=cg_context.class_name)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ body = func_def.body
+ body.add_template_vars({"script_state": "script_state"})
+
+ branches = CxxSwitchNode(cond="content_type_")
+ for member in cg_context.union_members:
+ if member.is_null:
+ text = "return v8::Null(${script_state}->GetIsolate());"
+ else:
+ text = _format("return ToV8Traits<{}>::ToV8(${script_state}, {});",
+ native_value_tag(member.idl_type), member.var_name)
+ branches.append(case=member.content_type(),
+ body=TextNode(text),
+ should_add_break=False)
+
+ body.extend([
+ branches,
+ EmptyNode(),
+ TextNode("NOTREACHED();"),
+ TextNode("return v8::MaybeLocal<v8::Value>();"),
+ ])
+
+ return func_decl, func_def
+
+
def make_trace_function(cg_context):
assert isinstance(cg_context, CodeGenContext)
@@ -152,20 +608,54 @@ def make_trace_function(cg_context):
continue
body.append(
TextNode("TraceIfNeeded<{}>::Trace(visitor, {});".format(
- member.member_type.member_t, member.member_var)))
+ member.type_info.member_t, member.var_name)))
body.append(TextNode("${base_class_name}::Trace(visitor);"))
return func_decl, func_def
+def make_name_function(cg_context):
+ assert isinstance(cg_context, CodeGenContext)
+
+ func_def = CxxFuncDefNode(name="UnionNameInIDL",
+ arg_decls=[],
+ return_type="String",
+ static=True)
+ func_def.set_base_template_vars(cg_context.template_bindings())
+ body = func_def.body
+
+ body.extend([
+ TextNode("static constexpr const char* const member_names[] = {"),
+ ListNode(list(
+ map(
+ lambda name: TextNode("\"{}\"".format(name)),
+ sorted(
+ map(lambda idl_type: idl_type.syntactic_form,
+ cg_context.union.flattened_member_types)))),
+ separator=", "),
+ TextNode("};"),
+ TextNode("return ProduceUnionNameInIDL(member_names);"),
+ ])
+
+ return func_def, None
+
+
def make_member_vars_def(cg_context):
assert isinstance(cg_context, CodeGenContext)
+ member_vars_def = ListNode()
+ member_vars_def.extend([
+ TextNode("ContentType content_type_;"),
+ EmptyNode(),
+ ])
+
entries = [
- "{} {};".format(member.member_type.member_t, member.member_var)
+ "{} {};".format(member.type_info.member_t, member.var_name)
for member in cg_context.union_members if not member.is_null
]
- return ListNode(map(TextNode, entries))
+ member_vars_def.extend(map(TextNode, entries))
+
+ return member_vars_def
def generate_union(union_identifier):
@@ -182,13 +672,8 @@ def generate_union(union_identifier):
# Class names
class_name = blink_class_name(union)
- union_members = map(
- lambda member_type: _UnionMemberImpl(union=union, idl_type=member_type
- ), union.flattened_member_types)
- if union.does_include_nullable_type:
- union_members.append(_UnionMemberImpl(union=union, idl_type=None))
cg_context = CodeGenContext(union=union,
- union_members=tuple(union_members),
+ union_members=create_union_members(union),
class_name=class_name,
base_class_name="bindings::UnionBase")
@@ -218,7 +703,14 @@ def generate_union(union_identifier):
# Implementation parts
content_type_enum_class_def = make_content_type_enum_class_def(cg_context)
- trace_decls, trace_defs = make_trace_function(cg_context)
+ factory_decls, factory_defs = make_factory_methods(cg_context)
+ ctor_decls, ctor_defs = make_constructors(cg_context)
+ accessor_decls, accessor_defs = make_accessor_functions(cg_context)
+ clear_func_decls, clear_func_defs = make_clear_function(cg_context)
+ tov8value_func_decls, tov8value_func_defs = make_tov8value_function(
+ cg_context)
+ trace_func_decls, trace_func_defs = make_trace_function(cg_context)
+ name_func_decls, name_func_defs = make_name_function(cg_context)
member_vars_def = make_member_vars_def(cg_context)
# Header part (copyright, include directives, and forward declarations)
@@ -251,10 +743,28 @@ def generate_union(union_identifier):
])
# Assemble the parts.
+ header_node.accumulator.add_class_decls([
+ "ExceptionState",
+ ])
header_node.accumulator.add_include_headers([
component_export_header(api_component, for_testing),
"third_party/blink/renderer/platform/bindings/union_base.h",
])
+ source_node.accumulator.add_include_headers([
+ "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
+ "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h",
+ "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h",
+ "third_party/blink/renderer/platform/bindings/exception_state.h",
+ ])
+ header_node.accumulator.add_class_decls(
+ map(blink_class_name, union.union_members))
+ source_node.accumulator.add_include_headers(
+ map(lambda subunion: PathManager(subunion).api_path(ext="h"),
+ union.union_members))
+ source_node.accumulator.add_include_headers([
+ PathManager(idl_type.type_definition_object).api_path(ext="h")
+ for idl_type in union.flattened_member_types if idl_type.is_interface
+ ])
(header_forward_decls, header_include_headers, source_forward_decls,
source_include_headers) = collect_forward_decls_and_include_headers(
union.flattened_member_types)
@@ -266,16 +776,43 @@ def generate_union(union_identifier):
header_blink_ns.body.append(class_def)
header_blink_ns.body.append(EmptyNode())
- class_def.public_section.extend([
- content_type_enum_class_def,
- EmptyNode(),
- trace_decls,
- EmptyNode(),
- ])
- source_blink_ns.body.extend([
- trace_defs,
- EmptyNode(),
- ])
+ class_def.public_section.append(content_type_enum_class_def)
+ class_def.public_section.append(EmptyNode())
+
+ class_def.public_section.append(factory_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(factory_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.public_section.append(ctor_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(ctor_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.public_section.append(accessor_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(accessor_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.public_section.append(clear_func_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(clear_func_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.public_section.append(tov8value_func_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(tov8value_func_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.public_section.append(trace_func_decls)
+ class_def.public_section.append(EmptyNode())
+ source_blink_ns.body.append(trace_func_defs)
+ source_blink_ns.body.append(EmptyNode())
+
+ class_def.private_section.append(name_func_decls)
+ class_def.private_section.append(EmptyNode())
+ source_blink_ns.body.append(name_func_defs)
+ source_blink_ns.body.append(EmptyNode())
class_def.private_section.append(member_vars_def)
class_def.private_section.append(EmptyNode())
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
index 130004eae83..04c0fabcef2 100755
--- a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
@@ -80,7 +80,7 @@ def read_idl_file(reader, idl_filename):
assert len(interfaces) == 1, (
"Expected one interface in file %r, found %d" %
(idl_filename, len(interfaces)))
- return (interfaces.values()[0], includes)
+ return (list(interfaces.values())[0], includes)
def interface_is_global(interface):
@@ -281,7 +281,7 @@ def main():
info_provider = create_component_info_provider(
os.path.normpath(options.info_dir), options.target_component)
- idl_filenames = map(str.strip, open(options.idl_files_list))
+ idl_filenames = list(map(str.strip, open(options.idl_files_list)))
generate_origin_trial_features(info_provider, options, idl_filenames)
return 0
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
index 0fc86d4a24c..3db6074896b 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py
@@ -394,7 +394,8 @@ class IdlInterface(object):
else:
raise ValueError('Unrecognized node class: %s' % child_class)
- if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1:
+ if len(list(filter(None,
+ [self.iterable, self.maplike, self.setlike]))) > 1:
raise ValueError(
'Interface can only have one of iterable<>, maplike<> and setlike<>.'
)
@@ -512,6 +513,9 @@ class IdlAttribute(TypedObject):
def accept(self, visitor):
visitor.visit_attribute(self)
+ def __lt__(self, other):
+ return self.name < other.name
+
################################################################################
# Constants
@@ -852,7 +856,7 @@ class IdlIncludes(object):
################################################################################
-class Exposure:
+class Exposure(object):
"""An Exposure holds one Exposed or RuntimeEnabled condition.
Each exposure has two properties: exposed and runtime_enabled.
Exposure(e, r) corresponds to [Exposed(e r)]. Exposure(e) corresponds to
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py
index 8d72865a6ca..b80eebdcd61 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py
@@ -55,8 +55,8 @@ def validate_blink_idl_definitions(idl_filename, idl_file_basename,
definitions. There is no filename convention in this case.
- Otherwise, an IDL file is invalid.
"""
- targets = (
- definitions.interfaces.values() + definitions.dictionaries.values())
+ targets = (list(definitions.interfaces.values()) +
+ list(definitions.dictionaries.values()))
number_of_targets = len(targets)
if number_of_targets > 1:
raise Exception(
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py
index cd4f0c3513b..ab95e9c0b08 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py
@@ -349,7 +349,7 @@ class IdlUnionType(IdlTypeBase):
return True
def single_matching_member_type(self, predicate):
- matching_types = filter(predicate, self.flattened_member_types)
+ matching_types = list(filter(predicate, self.flattened_member_types))
if len(matching_types) > 1:
raise ValueError('%s is ambiguous.' % self.name)
return matching_types[0] if matching_types else None
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni b/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni
index af34ef234a9..eb796d6ba09 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni
+++ b/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni
@@ -66,8 +66,7 @@ idl_compiler_files = get_path_info(
# component_info_file = output pickle file for component wide info.
# deps = dependencies
template("compute_interfaces_info") {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
script = "$bindings_scripts_dir/compute_interfaces_info_individual.py"
if (defined(invoker.visibility)) {
visibility = invoker.visibility
@@ -114,8 +113,7 @@ template("compute_interfaces_info") {
# output_file = The .in file to write, relative to the blink_gen_dir.
# suffix = (Optional) String to be passed to script via --suffix
template("generate_event_interfaces") {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
# Write the file list to a unique temp file to avoid blowing out the
# command line length limit.
idl_files_list = "$target_gen_dir/${target_name}_file_list.tmp"
@@ -166,7 +164,6 @@ template("idl_compiler") {
idl_lexer_parser_files + idl_compiler_files # to be explicit (covered by
# parsetab)
_inputs += [
- "$bindings_scripts_output_dir/lextab.py",
"$bindings_scripts_output_dir/parsetab.pickle",
"$bindings_scripts_output_dir/cached_jinja_templates.stamp",
"$bindings_dir/IDLExtendedAttributes.txt",
@@ -199,8 +196,7 @@ template("idl_compiler") {
# Spawning a python process per IDL file is slow. Use a single action
# instead (crbug.com/821256).
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
script = _script
inputs = _inputs
public_deps = _public_deps
@@ -249,8 +245,7 @@ template("idl_compiler") {
template("idl_impl") {
dictionary_impl_output_dir = "$root_gen_dir/third_party/blink/renderer/"
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
script = "//third_party/blink/renderer/bindings/scripts/idl_compiler.py"
idl_files_list = "$target_gen_dir/${target_name}_file_list.tmp"
write_file(idl_files_list, rebase_path(invoker.dict_idls, root_build_dir))
@@ -259,7 +254,6 @@ template("idl_impl") {
idl_lexer_parser_files + idl_compiler_files # to be explicit (covered
# by parsetab)
inputs += [
- "$bindings_scripts_output_dir/lextab.py",
"$bindings_scripts_output_dir/parsetab.pickle",
"$bindings_scripts_output_dir/cached_jinja_templates.stamp",
"$bindings_dir/IDLExtendedAttributes.txt",
@@ -444,8 +438,7 @@ template("generate_global_constructors") {
# deps = dependencies
#
template("generate_origin_trial_features") {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
script = "//third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py"
# Write the file list to a unique temp file to avoid blowing out the
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/utilities.py b/chromium/third_party/blink/renderer/bindings/scripts/utilities.py
index af664e0f239..954c5ad02c5 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/utilities.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/utilities.py
@@ -196,8 +196,9 @@ class ComponentInfoProviderModules(ComponentInfoProvider):
@property
def callback_functions(self):
- return dict(self._component_info_core['callback_functions'].items() +
- self._component_info_modules['callback_functions'].items())
+ return dict(
+ list(self._component_info_core['callback_functions'].items()) +
+ list(self._component_info_modules['callback_functions'].items()))
@property
def specifier_for_export(self):
@@ -209,8 +210,8 @@ class ComponentInfoProviderModules(ComponentInfoProvider):
def load_interfaces_info_overall_pickle(info_dir):
- with open(os.path.join(info_dir,
- 'interfaces_info.pickle')) as interface_info_file:
+ with open(os.path.join(info_dir, 'interfaces_info.pickle'),
+ mode='rb') as interface_info_file:
return pickle.load(interface_info_file)
@@ -236,23 +237,20 @@ def merge_dict_recursively(target, diff):
def create_component_info_provider_core(info_dir):
interfaces_info = load_interfaces_info_overall_pickle(info_dir)
- with open(
- os.path.join(info_dir, 'core',
- 'component_info_core.pickle')) as component_info_file:
+ with open(os.path.join(info_dir, 'core', 'component_info_core.pickle'),
+ mode='rb') as component_info_file:
component_info = pickle.load(component_info_file)
return ComponentInfoProviderCore(interfaces_info, component_info)
def create_component_info_provider_modules(info_dir):
interfaces_info = load_interfaces_info_overall_pickle(info_dir)
- with open(
- os.path.join(info_dir, 'core',
- 'component_info_core.pickle')) as component_info_file:
+ with open(os.path.join(info_dir, 'core', 'component_info_core.pickle'),
+ mode='rb') as component_info_file:
component_info_core = pickle.load(component_info_file)
- with open(
- os.path.join(
- info_dir, 'modules',
- 'component_info_modules.pickle')) as component_info_file:
+ with open(os.path.join(info_dir, 'modules',
+ 'component_info_modules.pickle'),
+ mode='rb') as component_info_file:
component_info_modules = pickle.load(component_info_file)
return ComponentInfoProviderModules(interfaces_info, component_info_core,
component_info_modules)
@@ -347,7 +345,7 @@ def write_file(new_text, destination_filename):
def write_pickle_file(pickle_filename, data):
# If |data| is same with the file content, we skip updating.
if os.path.isfile(pickle_filename):
- with open(pickle_filename) as pickle_file:
+ with open(pickle_filename, 'rb') as pickle_file:
try:
if pickle.load(pickle_file) == data:
return
@@ -477,13 +475,13 @@ def get_first_interface_name_from_idl(file_contents):
def shorten_union_name(union_type):
aliases = {
# modules/canvas2d/CanvasRenderingContext2D.idl
- 'CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas':
+ 'CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame':
'CanvasImageSource',
# modules/canvas/htmlcanvas/html_canvas_element_module.idl
'CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext':
'RenderingContext',
# core/frame/window_or_worker_global_scope.idl
- 'HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas':
+ 'HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvasOrVideoFrame':
'ImageBitmapSource',
# bindings/tests/idls/core/TestTypedefs.idl
'NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord':
@@ -497,6 +495,9 @@ def shorten_union_name(union_type):
# modules/beacon/navigator_beacon.idl
'ReadableStreamOrBlobOrArrayBufferOrArrayBufferViewOrFormDataOrURLSearchParamsOrUSVString':
'ReadableStreamOrXMLHttpRequestBodyInit',
+ # modules/mediasource/source_buffer.idl
+ 'EncodedAudioChunkOrEncodedVideoChunkSequenceOrEncodedAudioChunkOrEncodedVideoChunk':
+ 'EncodedAVChunkSequenceOrEncodedAVChunk',
}
idl_type = union_type
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
index 45aba557fc5..c3ba34281dd 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py
@@ -104,8 +104,7 @@ def attribute_context(interface, attribute, interfaces, component_info):
is_ce_reactions = 'CEReactions' in extended_attributes
if is_ce_reactions:
includes.add('core/html/custom/ce_reactions_scope.h')
- # [CustomElementCallbacks], [Reflect]
- is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes
+ # [Reflect]
is_reflect = 'Reflect' in extended_attributes
# [ReflectOnly]
reflect_only = extended_attribute_value_as_list(attribute, 'ReflectOnly')
@@ -113,8 +112,6 @@ def attribute_context(interface, attribute, interfaces, component_info):
reflect_only = map(
lambda v: cpp_content_attribute_value_name(interface, v),
reflect_only)
- if is_custom_element_callbacks or is_reflect:
- includes.add('core/html/custom/v0_custom_element_processing_stack.h')
# [PerWorldBindings]
if 'PerWorldBindings' in extended_attributes:
assert idl_type.is_wrapper_type or 'LogActivity' in \
@@ -238,7 +235,6 @@ def attribute_context(interface, attribute, interfaces, component_info):
'is_check_security_for_receiver': is_check_security_for_receiver,
'is_check_security_for_return_value':
is_check_security_for_return_value,
- 'is_custom_element_callbacks': is_custom_element_callbacks,
# TODO(yukishiino): Make all DOM attributes accessor-type properties.
'is_data_type_property': is_data_type_property(interface, attribute),
'is_getter_raises_exception': # [RaisesException]
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
index a43260414db..a85b03abe75 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py
@@ -189,7 +189,7 @@ def context_enabled_features(attributes):
return sorted([
member for member in members
if member.get(KEY) and not member.get('exposed_test')
- ])
+ ], key=lambda item: item['name'])
def member_filter_by_name(members, name):
return [member for member in members if member[KEY] == name]
@@ -612,7 +612,8 @@ def interface_context(interface, interfaces, component_info):
sorted(
origin_trial_features(interface, context['constants'],
context['attributes'], context['methods']) +
- context_enabled_features(context['attributes'])),
+ context_enabled_features(context['attributes']),
+ key=lambda item: item['name']),
})
if context['optional_features']:
includes.add('platform/bindings/v8_per_context_data.h')
@@ -1356,9 +1357,9 @@ def resolution_tests_methods(effective_overloads):
# Extract argument and IDL type to simplify accessing these in each loop.
arguments = [method['arguments'][index] for method in methods]
- arguments_methods = zip(arguments, methods)
+ arguments_methods = list(zip(arguments, methods))
idl_types = [argument['idl_type_object'] for argument in arguments]
- idl_types_methods = zip(idl_types, methods)
+ idl_types_methods = list(zip(idl_types, methods))
# We can’t do a single loop through all methods or simply sort them, because
# a method may be listed in multiple steps of the resolution algorithm, and
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
index 5f1f89a3def..4548c9db43c 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py
@@ -46,6 +46,10 @@ import v8_types
import v8_utilities
from v8_utilities import (has_extended_attribute_value, is_unforgeable)
+# TODO(crbug.com/1174969): Remove this once Python2 is obsoleted.
+if sys.version_info.major != 2:
+ basestring = str
+
def method_is_visible(method, interface_is_partial):
if 'overloads' in method:
@@ -183,9 +187,6 @@ def method_context(interface, method, component_info, is_visible=True):
is_ce_reactions = 'CEReactions' in extended_attributes
if is_ce_reactions:
includes.add('core/html/custom/ce_reactions_scope.h')
- is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes
- if is_custom_element_callbacks:
- includes.add('core/html/custom/v0_custom_element_processing_stack.h')
is_raises_exception = 'RaisesException' in extended_attributes
@@ -257,8 +258,6 @@ def method_context(interface, method, component_info, is_visible=True):
'CrossOrigin' in extended_attributes,
'is_custom':
'Custom' in extended_attributes,
- 'is_custom_element_callbacks':
- is_custom_element_callbacks,
'is_explicit_nullable':
idl_type.is_explicit_nullable,
'is_new_object':
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
index 2ecd6923320..fcfc48371b1 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py
@@ -271,7 +271,7 @@ EXPOSED_WORKERS = set([
])
-class ExposureSet:
+class ExposureSet(object):
"""An ExposureSet is a collection of Exposure instructions."""
def __init__(self, exposures=None):
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf
deleted file mode 100644
index 2ae9158e446..00000000000
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf
+++ /dev/null
@@ -1,4 +0,0 @@
-[style]
-# https://www.chromium.org/blink/coding-style
-based_on_style = pep8
-column_limit = 79
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
index 7cf7f010d57..a2d17cc577d 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
@@ -35,6 +35,7 @@ def _setup_sys_path():
_setup_sys_path()
from . import file_io
+from .argument import Argument
from .ast_group import AstGroup
from .attribute import Attribute
from .callback_function import CallbackFunction
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py
index 13fb7c7068d..b73b7710687 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py
@@ -91,11 +91,13 @@ class CallbackInterface(UserDefinedType, WithExtendedAttributes,
for operation_ir in ir.operations
])
self._operation_groups = tuple([
- OperationGroup(
- operation_group_ir,
- filter(lambda x: x.identifier == operation_group_ir.identifier,
- self._operations),
- owner=self) for operation_group_ir in ir.operation_groups
+ OperationGroup(operation_group_ir,
+ list(
+ filter(
+ lambda x: x.identifier == operation_group_ir
+ .identifier, self._operations)),
+ owner=self)
+ for operation_group_ir in ir.operation_groups
])
@property
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py
index eafd940eba3..3a0c68bc162 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py
@@ -166,4 +166,4 @@ class Database(object):
return self._view_by_kind(Database._Kind.NEW_UNION)
def _view_by_kind(self, kind):
- return self._impl.find_by_kind(kind).values()
+ return list(self._impl.find_by_kind(kind).values())
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py
index abaeef39c30..e36cf7439ae 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py
@@ -8,8 +8,11 @@ from .runtime_enabled_features import RuntimeEnabledFeatures
class _Feature(str):
"""Represents a runtime-enabled feature."""
+ def __new__(cls, value):
+ return str.__new__(cls, value)
+
def __init__(self, value):
- str.__init__(self, value)
+ str.__init__(self)
self._is_context_dependent = (
RuntimeEnabledFeatures.is_context_dependent(self))
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
index 648c70d803d..1712f19c672 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
@@ -71,8 +71,9 @@ class FunctionLike(WithIdentifier):
def num_of_required_arguments(self):
"""Returns the number of required arguments."""
return len(
- filter(lambda arg: not (arg.is_optional or arg.is_variadic),
- self.arguments))
+ list(
+ filter(lambda arg: not (arg.is_optional or arg.is_variadic),
+ self.arguments)))
class OverloadGroup(WithIdentifier):
@@ -171,8 +172,7 @@ class OverloadGroup(WithIdentifier):
Returns the effective overload set.
https://heycam.github.io/webidl/#compute-the-effective-overload-set
"""
- assert argument_count is None or isinstance(argument_count,
- (int, long))
+ assert argument_count is None or isinstance(argument_count, int)
N = argument_count
S = []
@@ -188,21 +188,21 @@ class OverloadGroup(WithIdentifier):
S.append(
OverloadGroup.EffectiveOverloadItem(
- X, map(lambda arg: arg.idl_type, X.arguments),
- map(lambda arg: arg.optionality, X.arguments)))
+ X, list(map(lambda arg: arg.idl_type, X.arguments)),
+ list(map(lambda arg: arg.optionality, X.arguments))))
if X.is_variadic:
- for i in xrange(n, max(maxarg, N)):
- t = map(lambda arg: arg.idl_type, X.arguments)
- o = map(lambda arg: arg.optionality, X.arguments)
- for _ in xrange(n, i + 1):
+ for i in range(n, max(maxarg, N)):
+ t = list(map(lambda arg: arg.idl_type, X.arguments))
+ o = list(map(lambda arg: arg.optionality, X.arguments))
+ for _ in range(n, i + 1):
t.append(X.arguments[-1].idl_type)
o.append(X.arguments[-1].optionality)
S.append(OverloadGroup.EffectiveOverloadItem(X, t, o))
- t = map(lambda arg: arg.idl_type, X.arguments)
- o = map(lambda arg: arg.optionality, X.arguments)
- for i in xrange(n - 1, -1, -1):
+ t = list(map(lambda arg: arg.idl_type, X.arguments))
+ o = list(map(lambda arg: arg.optionality, X.arguments))
+ for i in range(n - 1, -1, -1):
if X.arguments[i].optionality == IdlType.Optionality.REQUIRED:
break
S.append(OverloadGroup.EffectiveOverloadItem(X, t[:i], o[:i]))
@@ -222,7 +222,7 @@ class OverloadGroup(WithIdentifier):
for item in items)
assert len(items) > 1
- for index in xrange(len(items[0].type_list)):
+ for index in range(len(items[0].type_list)):
# Assume that the given items are valid, and we only need to test
# the two types.
if OverloadGroup.are_distinguishable_types(
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
index 8c1a717b758..c540cd1c7ef 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -211,7 +211,7 @@ class IdlCompiler(object):
only_to_members_of_partial_or_mixin=False)
propagate_to_exposure(propagate)
- map(process_member_like, ir.iter_all_members())
+ list(map(process_member_like, ir.iter_all_members()))
def process_member_like(ir):
propagate = functools.partial(propagate_extattr, ir=ir)
@@ -237,7 +237,7 @@ class IdlCompiler(object):
self._ir_map.move_to_new_phase()
- map(process_interface_like, old_irs)
+ list(map(process_interface_like, old_irs))
def _determine_blink_headers(self):
irs = self._ir_map.irs_of_kinds(
@@ -425,9 +425,9 @@ class IdlCompiler(object):
assert not new_interface.deriveds
derived_set = identifier_to_derived_set.get(
new_interface.identifier, set())
- new_interface.deriveds = map(
- lambda id_: self._ref_to_idl_def_factory.create(id_),
- sorted(derived_set))
+ new_interface.deriveds = list(
+ map(lambda id_: self._ref_to_idl_def_factory.create(id_),
+ sorted(derived_set)))
def _supplement_missing_html_constructor_operation(self):
# Temporary mitigation of misuse of [HTMLConstructor]
@@ -556,7 +556,8 @@ class IdlCompiler(object):
self._ir_map.add(new_ir)
for group in new_ir.iter_all_overload_groups():
- exposures = map(lambda overload: overload.exposure, group)
+ exposures = list(map(lambda overload: overload.exposure,
+ group))
# [Exposed]
if any(not exposure.global_names_and_features
@@ -656,8 +657,8 @@ class IdlCompiler(object):
constructs = set()
for global_name in global_names:
constructs.update(exposed_map.get(global_name, []))
- new_ir.exposed_constructs = map(
- self._ref_to_idl_def_factory.create, sorted(constructs))
+ new_ir.exposed_constructs = list(
+ map(self._ref_to_idl_def_factory.create, sorted(constructs)))
assert not new_ir.legacy_window_aliases
if new_ir.identifier != 'Window':
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py
index 5776c2c18d9..a11a473b08f 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py
@@ -562,6 +562,10 @@ class IdlType(WithExtendedAttributes, WithDebugInfo):
return None
@property
+ def new_union_definition_object(self):
+ return None
+
+ @property
def union_definition_object(self):
"""
Returns an object that represents an union or None.
@@ -1149,6 +1153,7 @@ class UnionType(IdlType):
debug_info=debug_info,
pass_key=pass_key)
self._member_types = tuple(member_types)
+ self._new_union_definition_object = None
self._union_definition_object = None
def __eq__(self, other):
@@ -1223,6 +1228,17 @@ class UnionType(IdlType):
return set(flatten(self))
@property
+ def new_union_definition_object(self):
+ return self._new_union_definition_object
+
+ def set_new_union_definition_object(self, union_definition_object):
+ # In Python2, we need to avoid circular imports.
+ from .union import NewUnion
+ assert isinstance(union_definition_object, NewUnion)
+ assert self._new_union_definition_object is None
+ self._new_union_definition_object = union_definition_object
+
+ @property
def union_definition_object(self):
return self._union_definition_object
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
index 65d24e529d1..067ef2eb0b2 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
@@ -180,8 +180,9 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo,
self._constructor_groups = tuple([
ConstructorGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._constructors),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._constructors)),
owner=self) for group_ir in ir.constructor_groups
])
assert len(self._constructor_groups) <= 1
@@ -192,8 +193,9 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo,
self._named_constructor_groups = tuple([
ConstructorGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._named_constructors),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._named_constructors)),
owner=self) for group_ir in ir.named_constructor_groups
])
self._operations = tuple([
@@ -203,22 +205,23 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo,
self._operation_groups = tuple([
OperationGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._operations),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._operations)),
owner=self) for group_ir in ir.operation_groups
])
self._exposed_constructs = tuple(ir.exposed_constructs)
self._legacy_window_aliases = tuple(ir.legacy_window_aliases)
self._indexed_and_named_properties = None
- indexed_and_named_property_operations = filter(
- lambda x: x.is_indexed_or_named_property_operation,
- self._operations)
+ indexed_and_named_property_operations = list(
+ filter(lambda x: x.is_indexed_or_named_property_operation,
+ self._operations))
if indexed_and_named_property_operations:
self._indexed_and_named_properties = IndexedAndNamedProperties(
indexed_and_named_property_operations, owner=self)
self._stringifier = None
- stringifier_operation_irs = filter(lambda x: x.is_stringifier,
- ir.operations)
+ stringifier_operation_irs = list(
+ filter(lambda x: x.is_stringifier, ir.operations))
if stringifier_operation_irs:
assert len(stringifier_operation_irs) == 1
op_ir = make_copy(stringifier_operation_irs[0])
@@ -231,8 +234,9 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo,
attribute = None
if operation.stringifier_attribute:
attr_id = operation.stringifier_attribute
- attributes = filter(lambda x: x.identifier == attr_id,
- self._attributes)
+ attributes = list(
+ filter(lambda x: x.identifier == attr_id,
+ self._attributes))
assert len(attributes) == 1
attribute = attributes[0]
self._stringifier = Stringifier(operation, attribute, owner=self)
@@ -578,8 +582,9 @@ class Iterable(WithDebugInfo):
self._operation_groups = tuple([
OperationGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._operations),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._operations)),
owner=owner) for group_ir in ir.operation_groups
])
@@ -666,8 +671,9 @@ class Maplike(WithDebugInfo):
self._operation_groups = tuple([
OperationGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._operations),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._operations)),
owner=owner) for group_ir in ir.operation_groups
])
@@ -755,8 +761,9 @@ class Setlike(WithDebugInfo):
self._operation_groups = tuple([
OperationGroup(
group_ir,
- filter(lambda x: x.identifier == group_ir.identifier,
- self._operations),
+ list(
+ filter(lambda x: x.identifier == group_ir.identifier,
+ self._operations)),
owner=owner) for group_ir in ir.operation_groups
])
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
index e9aeff4ab82..f306f890ca2 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import sys
+
from .argument import Argument
from .ast_group import AstGroup
from .attribute import Attribute
@@ -30,6 +32,11 @@ from .operation import Operation
from .typedef import Typedef
+# TODO(crbug.com/1174969): Remove this once Python2 is obsoleted.
+if sys.version_info.major != 2:
+ long = int
+
+
def load_and_register_idl_definitions(filepaths, register_ir,
create_ref_to_idl_def, idl_type_factory):
"""
@@ -160,7 +167,7 @@ class _IRBuilder(object):
child_nodes = list(node.GetChildren())
extended_attributes = self._take_extended_attributes(child_nodes)
- members = map(self._build_interface_member, child_nodes)
+ members = list(map(self._build_interface_member, child_nodes))
attributes = []
constants = []
operations = []
@@ -302,7 +309,7 @@ class _IRBuilder(object):
child_nodes = list(node.GetChildren())
inherited = self._take_inheritance(child_nodes)
extended_attributes = self._take_extended_attributes(child_nodes)
- own_members = map(self._build_dictionary_member, child_nodes)
+ own_members = list(map(self._build_dictionary_member, child_nodes))
return Dictionary.IR(
identifier=Identifier(node.GetName()),
@@ -336,7 +343,7 @@ class _IRBuilder(object):
child_nodes = list(node.GetChildren())
extended_attributes = self._take_extended_attributes(child_nodes)
- members = map(self._build_interface_member, child_nodes)
+ members = list(map(self._build_interface_member, child_nodes))
constants = []
operations = []
for member in members:
@@ -456,8 +463,8 @@ class _IRBuilder(object):
assert len(child_nodes) == 1
child = child_nodes[0]
if child.GetClass() == 'Arguments':
- arguments = map(build_extattr_argument,
- child.GetChildren())
+ arguments = list(
+ map(build_extattr_argument, child.GetChildren()))
elif child.GetClass() == 'Call':
assert len(child.GetChildren()) == 1
grand_child = child.GetChildren()[0]
@@ -486,7 +493,9 @@ class _IRBuilder(object):
assert node.GetClass() == 'ExtAttributes'
return ExtendedAttributes(
- filter(None, map(build_extended_attribute, node.GetChildren())))
+ list(
+ filter(None, map(build_extended_attribute,
+ node.GetChildren()))))
def _build_inheritance(self, node):
assert node.GetClass() == 'Inherit'
@@ -506,7 +515,7 @@ class _IRBuilder(object):
def _build_iterable(self, node):
assert node.GetClass() == 'Iterable'
- types = map(self._build_type, node.GetChildren())
+ types = list(map(self._build_type, node.GetChildren()))
assert len(types) == 1 or len(types) == 2
if len(types) == 1: # value iterator
key_type, value_type = (None, types[0])
@@ -584,7 +593,7 @@ class _IRBuilder(object):
def _build_maplike(self, node, interface_identifier):
assert node.GetClass() == 'Maplike'
assert isinstance(interface_identifier, Identifier)
- types = map(self._build_type, node.GetChildren())
+ types = list(map(self._build_type, node.GetChildren()))
assert len(types) == 2
key_type, value_type = types
is_readonly = bool(node.GetProperty('READONLY'))
@@ -676,7 +685,7 @@ class _IRBuilder(object):
def _build_setlike(self, node, interface_identifier):
assert node.GetClass() == 'Setlike'
assert isinstance(interface_identifier, Identifier)
- types = map(self._build_type, node.GetChildren())
+ types = list(map(self._build_type, node.GetChildren()))
assert len(types) == 1
value_type = types[0]
is_readonly = bool(node.GetProperty('READONLY'))
@@ -838,7 +847,7 @@ class _IRBuilder(object):
def build_union_type(node, extended_attributes):
return self._idl_type_factory.union_type(
- member_types=map(self._build_type, node.GetChildren()),
+ member_types=list(map(self._build_type, node.GetChildren())),
is_optional=is_optional,
extended_attributes=extended_attributes,
debug_info=self._build_debug_info(node))
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py
index a7a2b11f3f0..a5b94872808 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py
@@ -3,6 +3,14 @@
# found in the LICENSE file.
+import sys
+
+# TODO(crbug.com/1174969): Remove this once Python2 is obsoleted.
+if sys.version_info.major != 2:
+ long = int
+ basestring = str
+
+
def make_copy(obj, memo=None):
"""
Creates a copy of the given object, which should be an IR or part of IR.
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
index 8ecef23326a..18c8f8f6588 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
@@ -107,11 +107,13 @@ class Namespace(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo,
for operation_ir in ir.operations
])
self._operation_groups = tuple([
- OperationGroup(
- operation_group_ir,
- filter(lambda x: x.identifier == operation_group_ir.identifier,
- self._operations),
- owner=self) for operation_group_ir in ir.operation_groups
+ OperationGroup(operation_group_ir,
+ list(
+ filter(
+ lambda x: x.identifier == operation_group_ir
+ .identifier, self._operations)),
+ owner=self)
+ for operation_group_ir in ir.operation_groups
])
@property
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py
index 0d0b4ea653a..bc2aab7fef7 100644
--- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py
+++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py
@@ -114,7 +114,7 @@ class NewUnion(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
union_members.add(sub_union_ir.public_object)
components = set()
- for_testing = False
+ for_testing = [False]
def collect_primary_component(idl_type):
type_definition_object = idl_type.type_definition_object
@@ -122,12 +122,12 @@ class NewUnion(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
components.add(type_definition_object.components[0])
if (type_definition_object and
type_definition_object.code_generator_info.for_testing):
- for_testing = True
+ for_testing[0] = True
for idl_type in flattened_member_types:
idl_type.apply_to_all_composing_elements(collect_primary_component)
code_generator_info = CodeGeneratorInfoMutable()
- code_generator_info.set_for_testing(for_testing)
+ code_generator_info.set_for_testing(for_testing[0])
WithIdentifier.__init__(self, identifier)
WithCodeGeneratorInfo.__init__(self,
@@ -140,7 +140,8 @@ class NewUnion(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
idl_type.type_name_with_extended_attribute_key_values)
sort_key_identifier = lambda x: x.identifier
- self._union_types = tuple(ir.union_types)
+ self._idl_types = tuple(ir.union_types)
+ self._member_tokens = ir.token
self._flattened_member_types = tuple(
sorted(flattened_member_types, key=sort_key_typename))
self._does_include_nullable_type = does_include_nullable_type
@@ -153,9 +154,19 @@ class NewUnion(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
sorted(ir.typedefs, key=sort_key_identifier))
ir.public_object = self
- # TODO(yukishiino): Replace BackwardCompatibleUnion with NewUnion
- # for union_type in self._union_types:
- # union_type.set_union_definition_object(self)
+
+ for idl_type in self._idl_types:
+ idl_type.set_new_union_definition_object(self)
+
+ @property
+ def idl_types(self):
+ """Returns a list of IdlTypes which this object represents."""
+ return self._idl_types
+
+ @property
+ def member_tokens(self):
+ """Returns a list of unique names of union member types."""
+ return self._member_tokens
@property
def flattened_member_types(self):
diff --git a/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
index 91bd1051309..c313e1d036e 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/attributes.cc.tmpl
@@ -409,10 +409,6 @@ static void {{attribute.camel_case_name}}AttributeSetter{{world_suffix}}(
if (!result)
return;
{% else %}{# attribute.is_put_forwards #}
- {% if attribute.is_custom_element_callbacks or attribute.is_reflect %}
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
- {% endif %}
-
{% if attribute.has_setter_exception_state %}
{{define_exception_state}}
{% endif %}
diff --git a/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
index 8473ac96dab..e4bc040f22a 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
@@ -579,19 +579,21 @@ static void Install{{v8_class}}Template(
// so there is no need to reuse this FunctionTemplate and register it in
// V8PerIsolateData.
v8::Local<v8::FunctionTemplate> intrinsic_iterator_prototype_interface_template =
- v8::FunctionTemplate::New(isolate);
- intrinsic_iterator_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(isolate, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(isolate, "prototype"), v8::kIteratorPrototype);
interface_template->Inherit(intrinsic_iterator_prototype_interface_template);
{% endif %}
- {% if interface_name == 'NativeFileSystemDirectoryIterator' %}
+ {% if interface_name == 'FileSystemDirectoryIterator' %}
// Temporary @@asyncIterator support for FileSystemDirectoryHandle
// TODO(https://crbug.com/1087157): Replace with proper bindings support.
v8::Local<v8::FunctionTemplate> intrinsic_iterator_prototype_interface_template =
- v8::FunctionTemplate::New(isolate);
- intrinsic_iterator_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(isolate, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(isolate, "prototype"), v8::kAsyncIteratorPrototype);
interface_template->Inherit(intrinsic_iterator_prototype_interface_template);
@@ -614,8 +616,9 @@ static void Install{{v8_class}}Template(
// |interface_template| is instantiated, its prototype.__proto__ will point to
// |intrinsic_error_prototype_interface_template|'s "prototype" property.
v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template =
- v8::FunctionTemplate::New(isolate);
- intrinsic_error_prototype_interface_template->RemovePrototype();
+ v8::FunctionTemplate::New(isolate, nullptr, v8::Local<v8::Value>(),
+ v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
V8AtomicString(isolate, "prototype"), v8::kErrorPrototype);
interface_template->Inherit(intrinsic_error_prototype_interface_template);
diff --git a/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
index 918ea13c32e..b1317339a0b 100644
--- a/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
+++ b/chromium/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
@@ -79,10 +79,6 @@ static void {{method.camel_case_name}}{{method.overload_index}}Method{{world_suf
{% endif %}
{% endif %}
- {% if method.is_custom_element_callbacks %}
- V0CustomElementProcessingStack::CallbackDeliveryScope delivery_scope;
- {% endif %}
-
{{function_call | trim | indent(2)}}
}
{% endfilter %}
diff --git a/chromium/third_party/blink/renderer/build/scripts/PRESUBMIT.py b/chromium/third_party/blink/renderer/build/scripts/PRESUBMIT.py
index 3578fcbf05f..4cc2799ee46 100644
--- a/chromium/third_party/blink/renderer/build/scripts/PRESUBMIT.py
+++ b/chromium/third_party/blink/renderer/build/scripts/PRESUBMIT.py
@@ -41,15 +41,16 @@ def _RunTests(input_api, output_api):
tests = [{
'file_name': 'json5_generator_unittest.py',
'affected_list': [r'.*json5_generator.*', r'.*\btests[\\\/].*']
- },
- {
- 'file_name': 'make_runtime_features_utilities_unittest.py',
- 'affected_list': [r'.*make_runtime_features_utilities.*']
- },
- {
- 'file_name': 'make_document_policy_features_unittest.py',
- 'affected_list': [r'.*make_document_policy_features.*']
- }]
+ }, {
+ 'file_name': 'make_runtime_features_utilities_unittest.py',
+ 'affected_list': [r'.*make_runtime_features_utilities.*']
+ }, {
+ 'file_name': 'make_document_policy_features_unittest.py',
+ 'affected_list': [r'.*make_document_policy_features.*']
+ }, {
+ 'file_name': 'make_document_policy_features_tests.py',
+ 'affected_list': [r'.*make_document_policy_features.*']
+ }]
test_commands = []
for test in tests:
test_commands.append(
diff --git a/chromium/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py b/chromium/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
index dd1978df233..db8096c4a89 100644
--- a/chromium/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
+++ b/chromium/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
@@ -9,6 +9,7 @@ import re
SPECIAL_TOKENS = [
# This list should be sorted by length.
+ 'WebCodecs',
'WebSocket',
'String16',
'Float32',
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/css_properties.py b/chromium/third_party/blink/renderer/build/scripts/core/css/css_properties.py
index 831136285e2..b779e079244 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/css_properties.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/css_properties.py
@@ -67,6 +67,7 @@ class CSSProperties(object):
# in the various generators for ComputedStyle.
self._field_alias_expander = FieldAliasExpander(file_paths[1])
+ # _alias_offset must be a power of 2.
self._alias_offset = 1024
# 0: CSSPropertyID::kInvalid
# 1: CSSPropertyID::kVariable
@@ -224,7 +225,7 @@ class CSSProperties(object):
updated_alias['enum_key'] = enum_key_for_css_property_alias(
alias['name'])
updated_alias['enum_value'] = aliased_property['enum_value'] + \
- self._alias_offset
+ self._alias_offset * len(aliased_property['aliases'])
updated_alias['superclass'] = 'CSSUnresolvedProperty'
updated_alias['namespace_group'] = \
'Shorthand' if aliased_property['longhands'] else 'Longhand'
@@ -320,15 +321,29 @@ class CSSProperties(object):
set_if_none(property_, 'custom_compare', False)
set_if_none(property_, 'mutable', False)
- if property_['direction_aware_options']:
- if not property_['style_builder_template']:
+ if property_['logical_property_group']:
+ group = property_['logical_property_group']
+ assert 'name' in group, 'name option is required'
+ assert 'resolver' in group, 'resolver option is required'
+ logicals = {
+ 'block', 'inline', 'block-start', 'block-end', 'inline-start',
+ 'inline-end', 'start-start', 'start-end', 'end-start',
+ 'end-end'
+ }
+ physicals = {
+ 'vertical', 'horizontal', 'top', 'bottom', 'left', 'right',
+ 'top-left', 'top-right', 'bottom-right', 'bottom-left'
+ }
+ if group['resolver'] in logicals:
+ group['is_logical'] = True
+ elif group['resolver'] in physicals:
+ group['is_logical'] = False
+ else:
+ assert 0, 'invalid resolver option'
+ group['name'] = NameStyleConverter(group['name'])
+ group['resolver_name'] = NameStyleConverter(group['resolver'])
+ if not property_['style_builder_template'] and group['is_logical']:
property_['style_builder_template'] = 'direction_aware'
- options = property_['direction_aware_options']
- assert 'resolver' in options, 'resolver option is required'
- assert 'physical_group' in options, 'physical_group option is required'
- options['resolver_name'] = NameStyleConverter(options['resolver'])
- options['physical_group_name'] = NameStyleConverter(
- options['physical_group'])
@property
def default_parameters(self):
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
index bc7c717cf1e..c6044f4971d 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
@@ -29,8 +29,8 @@ class CSSPropertyNamesWriter(json5_generator.Writer):
'core/css/templates/css_property_names.h.tmpl')
def generate_header(self):
return {
- 'alias_offset':
- self._css_properties.alias_offset,
+ 'alias_mask':
+ hex(0xffffffff - self._css_properties.alias_offset + 1),
'class_name':
self.class_name,
'property_enums':
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py b/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
index 1799cd5a153..5f43ffabc26 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
@@ -71,7 +71,7 @@ class Expansion(object):
def enabled_longhands(self):
include = lambda longhand: not longhand[
'runtime_flag'] or self.is_enabled(longhand['runtime_flag'])
- return filter(include, self._longhands)
+ return list(filter(include, self._longhands))
@property
def index(self):
@@ -87,8 +87,9 @@ class Expansion(object):
def create_expansions(longhands):
flags = collect_runtime_flags(longhands)
- expansions = map(lambda mask: Expansion(longhands, flags, mask),
- range(1 << len(flags)))
+ expansions = list(
+ map(lambda mask: Expansion(longhands, flags, mask),
+ range(1 << len(flags))))
assert len(expansions) > 0
# We generate 2^N expansions for N flags, so enforce some limit.
assert len(flags) <= 4, 'Too many runtime flags for a single shorthand'
@@ -114,14 +115,14 @@ class StylePropertyShorthandWriter(json5_generator.Writer):
self._longhand_dictionary = defaultdict(list)
for property_ in json5_properties.shorthands:
- property_['longhand_enum_keys'] = map(enum_key_for_css_property,
- property_['longhands'])
- property_['longhand_property_ids'] = map(id_for_css_property,
- property_['longhands'])
-
- longhands = map(
- lambda name: json5_properties.properties_by_name[name],
- property_['longhands'])
+ property_['longhand_enum_keys'] = list(
+ map(enum_key_for_css_property, property_['longhands']))
+ property_['longhand_property_ids'] = list(
+ map(id_for_css_property, property_['longhands']))
+
+ longhands = list(
+ map(lambda name: json5_properties.properties_by_name[name],
+ property_['longhands']))
property_['expansions'] = create_expansions(longhands)
for longhand_enum_key in property_['longhand_enum_keys']:
self._longhand_dictionary[longhand_enum_key].append(property_)
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
index 75030ac577e..f72aadee17d 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
@@ -42,8 +42,8 @@ class CSSPropertyInstancesWriter(json5_generator.Writer):
aliases = self._css_properties.aliases
# Lists of PropertyClassData.
- self._property_classes_by_id = map(self.get_class, properties)
- self._alias_classes_by_id = map(self.get_class, aliases)
+ self._property_classes_by_id = list(map(self.get_class, properties))
+ self._alias_classes_by_id = list(map(self.get_class, aliases))
# Sort by enum value.
self._property_classes_by_id.sort(key=lambda t: t.enum_value)
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl
index 5ad18b5c21b..35137c4e1ba 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
@@ -88,23 +87,11 @@ const CSSProperty* {{class_name}}::SurrogateFor(TextDirection direction,
return &GetCSSProperty{{property.surrogate_for.name.to_upper_camel_case()}}();
}
{% endif %}
- {% if property.computed_value_comparable %}
-bool {{class_name}}::ComputedValuesEqual(const ComputedStyle& a, const ComputedStyle& b) const {
- {% if property.computed_value_compare_fields %}
- {% for field in property.computed_value_compare_fields %}
- if (!(a.{{field}}() == b.{{field}}()))
- return false;
- {% endfor %}
- return true;
- {% else %}
- return a.{{property.getter}}() == b.{{property.getter}}();
- {% endif %}
-}
- {% endif %}
- {% if property.direction_aware_options %}
- {% set options = property.direction_aware_options %}
- {% set resolver_name = options.resolver_name.to_upper_camel_case() %}
- {% set physical_group_name = options.physical_group_name.to_upper_camel_case() %}
+ {% if property.logical_property_group %}
+ {% set group = property.logical_property_group %}
+ {% set group_name = group.name.to_upper_camel_case() %}
+ {% set resolver_name = group.resolver_name.to_upper_camel_case() %}
+ {% if group.is_logical %}
const CSSProperty* {{class_name}}::SurrogateFor(TextDirection direction,
blink::WritingMode writing_mode) const {
return &ResolveDirectionAwareProperty(direction, writing_mode);
@@ -114,8 +101,19 @@ const CSSProperty& {{class_name}}::ResolveDirectionAwareProperty(
TextDirection direction,
blink::WritingMode writing_mode) const {
return CSSDirectionAwareResolver::Resolve{{resolver_name}}(direction, writing_mode,
- CSSDirectionAwareResolver::{{physical_group_name}}Group());
+ CSSDirectionAwareResolver::Physical{{group_name}}Mapping());
}
+
+bool {{class_name}}::IsInSameLogicalPropertyGroupWithDifferentMappingLogic(
+ CSSPropertyID id) const {
+ return CSSDirectionAwareResolver::Physical{{group_name}}Mapping().Contains(id);
+}
+ {% else %}
+bool {{class_name}}::IsInSameLogicalPropertyGroupWithDifferentMappingLogic(
+ CSSPropertyID id) const {
+ return CSSDirectionAwareResolver::Logical{{group_name}}Mapping().Contains(id);
+}
+ {% endif %}
{% endif %}
{{style_builder_functions(property)}}
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.h.tmpl
index f0c48563ef7..f954b7bd400 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.h.tmpl
@@ -22,14 +22,14 @@ class CSSParserLocalContext;
class CSSValue;
class LayoutObject;
class Node;
-class SVGComputedStyle;
namespace {{namespace}} {
{% for property in properties %}
{% set class_name = property.name.to_upper_camel_case() %}
{% set is_alias = property.alias_for %}
-{% set is_surrogate = property.surrogate_for or property.direction_aware_options %}
+{% set is_surrogate = property.surrogate_for or
+ (property.logical_property_group and property.logical_property_group.is_logical) %}
{% set property_id = 'CSSPropertyID::' + property.enum_key %}
{% set separator = '\'' + (property.separator or '\\0') + '\'' %}
{% set flags = [
@@ -48,9 +48,9 @@ namespace {{namespace}} {
(property.font and 'kAffectsFont' or ''),
(property.is_background and 'kBackground' or ''),
(property.is_border and 'kBorder' or ''),
- (property.computed_value_comparable and 'kComputedValueComparable' or ''),
(property.tree_scoped_value and 'kTreeScopedValue' or ''),
(property.valid_for_highlight and 'kValidForHighlight' or ''),
+ (property.logical_property_group and 'kInLogicalPropertyGroup' or ''),
] | reject('==', '') | join(' | ') %}
{% set ctor_args = (not is_alias and [property_id, flags, separator] or []) %}
// {{property.name}}
@@ -80,20 +80,18 @@ class {{class_name}} final : public {{property.superclass}} {
{% if property.unvisited_property %}
const CSSProperty* GetUnvisitedProperty() const override;
{% endif %}
- {% if property.surrogate_for or property.direction_aware_options %}
+ {% if is_surrogate %}
const CSSProperty* SurrogateFor(TextDirection, blink::WritingMode) const override;
{% endif %}
{% for property_method in property.property_methods %}
{{property_method.return_type}} {{property_method.name}}{{property_method.parameters}} const override;
{% endfor %}
- {% if property.computed_value_comparable %}
- bool ComputedValuesEqual(const ComputedStyle& a, const ComputedStyle& b) const override;
- {% endif %}
- {% if property.direction_aware_options %}
+ {% if property.logical_property_group %}
+ bool IsInSameLogicalPropertyGroupWithDifferentMappingLogic(CSSPropertyID) const override;
+ {% if property.logical_property_group.is_logical %}
const CSSProperty& ResolveDirectionAwareProperty(TextDirection, blink::WritingMode) const override;
const CSSValue* CSSValueFromComputedStyleInternal(
const ComputedStyle&,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const override {
// Directional properties are resolved by CSSDirectionAwareResolver
@@ -101,6 +99,7 @@ class {{class_name}} final : public {{property.superclass}} {
NOTREACHED();
return nullptr;
}
+ {% endif %}
{% endif %}
{% if property.style_builder_declare %}
void ApplyInitial(StyleResolverState&) const override;
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
index b44bb8f47e7..1ddbddbb76e 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
@@ -31,8 +31,8 @@ const CSSProperty& Get{{property_class_data.property_id}}() {
{% endfor %}
const CSSUnresolvedProperty* GetAliasPropertyInternal(CSSPropertyID id) {
- DCHECK_GT(id, lastCSSProperty); // last property id
- DCHECK_LE(id, lastUnresolvedCSSProperty); // last unresolved property id
+ DCHECK_GT(id, kLastCSSProperty); // last property id
+ DCHECK_LE(id, kLastUnresolvedCSSProperty); // last unresolved property id
switch (id) {
{% for property_class_data in alias_classes_by_property_id %}
case CSSPropertyID::{{property_class_data.enum_key}}:
@@ -47,7 +47,7 @@ const CSSUnresolvedProperty* GetAliasPropertyInternal(CSSPropertyID id) {
const CSSUnresolvedProperty& GetNonAliasPropertyInternal(CSSPropertyID id) {
DCHECK_NE(id, CSSPropertyID::kInvalid);
DCHECK_NE(id, CSSPropertyID::kVariable);
- DCHECK_LE(id, lastCSSProperty); // last property id
+ DCHECK_LE(id, kLastCSSProperty); // last property id
static constexpr const CSSUnresolvedProperty* const property_classes[] = {
{% for property_class_data in property_classes_by_property_id %}
&property_{{property_class_data.property_id.lower()}}, // {{property_class_data.property_id}}
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
index 2b57b4c969f..6e885ec4682 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
@@ -33,9 +33,7 @@ void {{class_name}}::ApplyValue(StyleResolverState& state, const CSSValue& value
{% endmacro %}
{% macro set_value(property) %}
- {% if property.svg %}
-state.Style()->AccessSVGStyle().{{property.setter}}
- {%- elif property.font %}
+ {%- if property.font %}
state.GetFontBuilder().{{property.setter}}
{%- else %}
state.Style()->{{property.setter}}
@@ -63,9 +61,7 @@ To<Longhand>(resolved_property).{{apply_call}};
{% macro style_builder_functions(property) %}
{% if not property.style_builder_template %}
{% call(property) apply_initial(property) %}
- {% if property.svg %}
- {{set_value(property)}}(SVGComputedStyle::{{property.initial}}());
- {% elif property.font %}
+ {% if property.font %}
{{set_value(property)}}(FontBuilder::{{property.initial}}());
{% else %}
{{set_value(property)}}(ComputedStyleInitialValues::{{property.initial}}());
@@ -75,9 +71,7 @@ To<Longhand>(resolved_property).{{apply_call}};
{% endif %}
{% endcall %}
{% call(property) apply_inherit(property) %}
- {% if property.svg %}
- {{set_value(property)}}(state.ParentStyle()->SvgStyle().{{property.getter}}());
- {% elif property.font %}
+ {% if property.font %}
{{set_value(property)}}(state.ParentFontDescription().{{property.getter}}());
{% else %}
{{set_value(property)}}(state.ParentStyle()->{{property.getter}}());
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.cc.tmpl
index 2d39cfdb6e0..8ad1fadc24f 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.cc.tmpl
@@ -41,9 +41,11 @@ const Property* FindProperty(const char* str, unsigned int len) {
return {{class_name}}Hash::findPropertyImpl(str, len);
}
-CSSPropertyID cssPropertyID(const ExecutionContext* execution_context, const String& string)
+CSSPropertyID CssPropertyID(const ExecutionContext* execution_context,
+ const String& string)
{
- return resolveCSSPropertyID(unresolvedCSSPropertyID(execution_context, string));
+ return ResolveCSSPropertyID(UnresolvedCSSPropertyID(execution_context,
+ string));
}
mojom::blink::CSSSampleId GetCSSSampleId(CSSPropertyID id) {
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
index 159f1785f06..575fdb77146 100644
--- a/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
@@ -13,7 +13,7 @@
namespace WTF {
class AtomicString;
class String;
-}
+} // namespace WTF
namespace blink {
@@ -29,20 +29,34 @@ const CSSPropertyID kCSSPropertyAliasList[] = {
{{property_aliases}}
};
+// The lowest CSSPropertyID excluding kInvalid and kVariable.
const int kIntFirstCSSProperty = {{first_property_id}};
-const CSSPropertyID firstCSSProperty = static_cast<CSSPropertyID>(kIntFirstCSSProperty);
-const int numCSSProperties = {{properties_count}};
+const CSSPropertyID kFirstCSSProperty =
+ static_cast<CSSPropertyID>(kIntFirstCSSProperty);
+
+// The number of unresolved CSS properties excluding kInvalid and kVariable.
+const int kNumCSSProperties = {{properties_count}};
+
+// The highest resolved CSSPropertyID.
const int kIntLastCSSProperty = {{last_property_id}};
-const CSSPropertyID lastCSSProperty = static_cast<CSSPropertyID>(kIntLastCSSProperty);
-const CSSPropertyID lastUnresolvedCSSProperty = static_cast<CSSPropertyID>({{last_unresolved_property_id}});
-const CSSPropertyID kFirstHighPriorityCSSProperty = firstCSSProperty;
+const CSSPropertyID kLastCSSProperty =
+ static_cast<CSSPropertyID>(kIntLastCSSProperty);
+
+// The highest unresolved CSSPropertyID.
+const CSSPropertyID kLastUnresolvedCSSProperty =
+ static_cast<CSSPropertyID>({{last_unresolved_property_id}});
+
+const CSSPropertyID kFirstHighPriorityCSSProperty = kFirstCSSProperty;
const CSSPropertyID kLastHighPriorityCSSProperty = CSSPropertyID::{{last_high_priority_property_id}};
-const int numCSSPropertyIDs = static_cast<int>(lastUnresolvedCSSProperty) + 1;
-const size_t maxCSSPropertyNameLength = {{max_name_length}};
+
+// 1 + <The highest unresolved CSSPropertyID>.
+const int kNumCSSPropertyIDs = static_cast<int>(kLastUnresolvedCSSProperty) + 1;
+
+const size_t kMaxCSSPropertyNameLength = {{max_name_length}};
constexpr size_t kCSSPropertyIDBitLength = {{property_id_bit_length}};
static_assert((static_cast<size_t>(1) << kCSSPropertyIDBitLength) >
- static_cast<size_t>(lastUnresolvedCSSProperty),
+ static_cast<size_t>(kLastUnresolvedCSSProperty),
"kCSSPropertyIDBitLength has enough bits");
static_assert(CSSPropertyID::kColor == kFirstHighPriorityCSSProperty,
@@ -54,8 +68,8 @@ static_assert((static_cast<int>(kLastHighPriorityCSSProperty) -
"There should a low number of high-priority properties");
inline int GetCSSPropertyIDIndex(CSSPropertyID id) {
- DCHECK_GE(id, firstCSSProperty);
- DCHECK_LE(id, lastCSSProperty);
+ DCHECK_GE(id, kFirstCSSProperty);
+ DCHECK_LE(id, kLastCSSProperty);
return static_cast<int>(id) - kIntFirstCSSProperty;
}
@@ -64,47 +78,56 @@ constexpr bool IsHighPriority(CSSPropertyID id) {
id <= kLastHighPriorityCSSProperty;
}
-inline bool isCSSPropertyIDWithName(CSSPropertyID id)
+inline bool IsCSSPropertyIDWithName(CSSPropertyID id)
{
- return id >= firstCSSProperty && id <= lastUnresolvedCSSProperty;
+ return id >= kFirstCSSProperty && id <= kLastUnresolvedCSSProperty;
}
-inline bool isValidCSSPropertyID(CSSPropertyID id)
+inline bool IsValidCSSPropertyID(CSSPropertyID id)
{
return id != CSSPropertyID::kInvalid;
}
-inline CSSPropertyID convertToCSSPropertyID(int value)
+inline CSSPropertyID ConvertToCSSPropertyID(int value)
{
DCHECK_GE(value, static_cast<int>(CSSPropertyID::kInvalid));
DCHECK_LE(value, kIntLastCSSProperty);
return static_cast<CSSPropertyID>(value);
}
-inline CSSPropertyID resolveCSSPropertyID(CSSPropertyID id)
+inline CSSPropertyID ResolveCSSPropertyID(CSSPropertyID id)
{
- return convertToCSSPropertyID(static_cast<int>(id) & ~{{alias_offset}});
+ return ConvertToCSSPropertyID(static_cast<int>(id) & ~{{alias_mask}});
}
-inline bool isPropertyAlias(CSSPropertyID id) { return static_cast<int>(id) & {{alias_offset}}; }
+inline bool IsPropertyAlias(CSSPropertyID id) {
+ return static_cast<int>(id) & {{alias_mask}};
+}
-CSSPropertyID CORE_EXPORT unresolvedCSSPropertyID(const ExecutionContext*, const WTF::String&);
+CSSPropertyID CORE_EXPORT UnresolvedCSSPropertyID(const ExecutionContext*,
+ const WTF::String&);
-CSSPropertyID CORE_EXPORT cssPropertyID(const ExecutionContext*, const WTF::String&);
+CSSPropertyID CORE_EXPORT CssPropertyID(const ExecutionContext*,
+ const WTF::String&);
class CSSPropertyIDList {
STACK_ALLOCATED();
+
public:
- class Iterator {
- STACK_ALLOCATED();
- public:
- Iterator(int id) : id_(id) {}
- CSSPropertyID operator*() const { return convertToCSSPropertyID(id_); }
- Iterator& operator++() { id_++; return *this; }
- bool operator!=(const Iterator& i) const { return id_ != i.id_; }
- private:
- int id_;
- };
+ class Iterator {
+ STACK_ALLOCATED();
+ public:
+ Iterator(int id) : id_(id) {}
+ CSSPropertyID operator*() const { return ConvertToCSSPropertyID(id_); }
+ Iterator& operator++() {
+ id_++;
+ return *this;
+ }
+ bool operator!=(const Iterator& i) const { return id_ != i.id_; }
+
+ private:
+ int id_;
+ };
Iterator begin() const { return Iterator(kIntFirstCSSProperty); }
Iterator end() const { return Iterator(kIntLastCSSProperty + 1); }
};
diff --git a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
index 731f354bc94..8956cc69075 100755
--- a/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
+++ b/chromium/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
@@ -49,6 +49,7 @@ ALIGNMENT_ORDER = [
'Font',
'FillLayer',
'NinePieceImage',
+ 'SVGPaint',
'IntrinsicLength',
'TextDecorationThickness',
'StyleAspectRatio',
@@ -63,6 +64,7 @@ ALIGNMENT_ORDER = [
'FloatSize',
'LengthPoint',
'Length',
+ 'UnzoomedLength',
'TextSizeAdjust',
'TabSize',
'float',
diff --git a/chromium/third_party/blink/renderer/build/scripts/gperf.py b/chromium/third_party/blink/renderer/build/scripts/gperf.py
index 5ee49056be4..db72660d471 100644
--- a/chromium/third_party/blink/renderer/build/scripts/gperf.py
+++ b/chromium/third_party/blink/renderer/build/scripts/gperf.py
@@ -95,7 +95,7 @@ def main():
open(args.output_file, 'wb').write(
generate_gperf(gperf_path,
- open(infile).read(), gperf_args))
+ open(infile).read(), gperf_args).encode('utf-8'))
if __name__ == '__main__':
diff --git a/chromium/third_party/blink/renderer/build/scripts/in_file.py b/chromium/third_party/blink/renderer/build/scripts/in_file.py
index 28adc050f1e..58113483e57 100644
--- a/chromium/third_party/blink/renderer/build/scripts/in_file.py
+++ b/chromium/third_party/blink/renderer/build/scripts/in_file.py
@@ -66,7 +66,7 @@ class InFile(object):
self._defaults = defaults
self._valid_values = copy.deepcopy(
valid_values if valid_values else {})
- self._parse(map(str.strip, lines))
+ self._parse(list(map(str.strip, lines)))
@classmethod
def load_from_files(self, file_paths, defaults, valid_values,
diff --git a/chromium/third_party/blink/renderer/build/scripts/in_generator.py b/chromium/third_party/blink/renderer/build/scripts/in_generator.py
index e46740a2e85..e8450b734e8 100644
--- a/chromium/third_party/blink/renderer/build/scripts/in_generator.py
+++ b/chromium/third_party/blink/renderer/build/scripts/in_generator.py
@@ -32,10 +32,15 @@ import os
import os.path
import shlex
import shutil
+import sys
import optparse
from in_file import InFile
+# TODO(crbug.com/1174969): Remove this once Python2 is obsoleted.
+if sys.version_info.major != 2:
+ basestring = str
+
#########################################################
# This is now deprecated - use json5_generator.py instead
diff --git a/chromium/third_party/blink/renderer/build/scripts/make_document_policy_features_tests.py b/chromium/third_party/blink/renderer/build/scripts/make_document_policy_features_tests.py
new file mode 100644
index 00000000000..b20267ef340
--- /dev/null
+++ b/chromium/third_party/blink/renderer/build/scripts/make_document_policy_features_tests.py
@@ -0,0 +1,27 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Note(crbug.com/1167597): Do NOT change the file name to end with
+# '_test.py' or '_unittest.py' as these files will be recognized by
+# 'run_blinkpy_tests.py' task, where jinja2 module is not available.
+
+import unittest
+import os
+from make_document_policy_features import DocumentPolicyFeatureWriter
+from writer_test_util import path_to_test_file, WriterTest
+
+
+class MakeDocumentPolicyFeaturesTest(WriterTest):
+ def test_default_value_control(self):
+ self._test_writer(
+ DocumentPolicyFeatureWriter, [
+ path_to_test_file('document_policy_default_value_control',
+ 'input', 'document_policy_features.json5')
+ ],
+ path_to_test_file('document_policy_default_value_control',
+ 'output'))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/chromium/third_party/blink/renderer/build/scripts/make_policy_helper.py b/chromium/third_party/blink/renderer/build/scripts/make_policy_helper.py
index 854c7394b8a..cfcb13239c6 100644
--- a/chromium/third_party/blink/renderer/build/scripts/make_policy_helper.py
+++ b/chromium/third_party/blink/renderer/build/scripts/make_policy_helper.py
@@ -23,8 +23,15 @@ class FeaturePolicyFeatureWriter(json5_generator.Writer):
# might be different.
document_policy_features = []
+ def to_devtools_enum_format(feature_policy_name):
+ """ Convert '-' separated feature_policy_name to cammel case devtool enum name """
+ return ''.join(
+ [name.capitalize() for name in feature_policy_name.split('-')])
+
for feature in self.json5_file.name_dictionaries:
if feature['feature_policy_name']:
+ feature['devtools_enum_name'] = to_devtools_enum_format(
+ feature['feature_policy_name'])
feature_policy_features.append(feature)
elif feature['document_policy_name']:
document_policy_features.append(feature)
diff --git a/chromium/third_party/blink/renderer/build/scripts/make_runtime_features.py b/chromium/third_party/blink/renderer/build/scripts/make_runtime_features.py
index cafe8d94a8e..6925a4fa580 100755
--- a/chromium/third_party/blink/renderer/build/scripts/make_runtime_features.py
+++ b/chromium/third_party/blink/renderer/build/scripts/make_runtime_features.py
@@ -138,7 +138,7 @@ class RuntimeFeatureWriter(BaseRuntimeFeatureWriter):
except Exception:
# If trouble unpickling, overwrite
pass
- with open(os.path.abspath(file_name), 'w') as pickle_file:
+ with open(os.path.abspath(file_name), 'wb') as pickle_file:
pickle.dump(features_map, pickle_file)
def _template_inputs(self):
diff --git a/chromium/third_party/blink/renderer/build/scripts/name_utilities.py b/chromium/third_party/blink/renderer/build/scripts/name_utilities.py
index b476f328d4d..374fa2f25c6 100644
--- a/chromium/third_party/blink/renderer/build/scripts/name_utilities.py
+++ b/chromium/third_party/blink/renderer/build/scripts/name_utilities.py
@@ -44,6 +44,10 @@ def cpp_name(entry):
def enum_key_for_css_keyword(keyword):
+ # To make sure different enum keys are generated for infinity and -infinity.
+ # Design doc : https://bit.ly/349gXjq
+ if (not isinstance(keyword, str)) and keyword.original == '-infinity':
+ return 'kNegative' + _upper_camel_case(keyword)
return 'k' + _upper_camel_case(keyword)
diff --git a/chromium/third_party/blink/renderer/build/scripts/scripts.gni b/chromium/third_party/blink/renderer/build/scripts/scripts.gni
index c82106642db..be6bab77d40 100644
--- a/chromium/third_party/blink/renderer/build/scripts/scripts.gni
+++ b/chromium/third_party/blink/renderer/build/scripts/scripts.gni
@@ -72,7 +72,7 @@ make_trie_helpers_files =
# on Posix we want to run the system one on the path.
if (host_os == "win") {
gperf_exe = rebase_path("//third_party/gperf/bin/gperf.exe", root_build_dir)
-} else if (is_mac) {
+} else if (host_os == "mac") {
gperf_exe = mac_bin_path + "gperf"
} else {
gperf_exe = "gperf"
@@ -92,8 +92,7 @@ make_core_generated_deps = [
# - //third_party/blink/renderer/build/scripts
# - //third_party
template("blink_python_runner") {
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- python2_action(target_name) {
+ action(target_name) {
script = "$_scripts_dir/run_with_pythonpath.py"
sources = [ invoker.script ]
if (defined(invoker.sources)) {
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/document_policy_features.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/document_policy_features.cc.tmpl
index bf9f9115cef..b309b866ea7 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/document_policy_features.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/document_policy_features.cc.tmpl
@@ -1,9 +1,10 @@
{% from 'templates/macros.tmpl' import license, source_files_for_generated_file %}
{{license()}}
-{{ source_files_for_generated_file(template_file, input_files) }}
#include "base/no_destructor.h"
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
#include "third_party/blink/public/common/feature_policy/policy_value.h"
#include "third_party/blink/public/mojom/feature_policy/policy_value.mojom.h"
@@ -13,17 +14,33 @@
namespace blink {
const DocumentPolicyFeatureInfoMap& GetDocumentPolicyFeatureInfoMap() {
- static const base::NoDestructor<DocumentPolicyFeatureInfoMap> feature_info_map({
- {%- for feature in features %}
- {
- mojom::DocumentPolicyFeature::k{{feature.name}},
+ static const base::NoDestructor<DocumentPolicyFeatureInfoMap> feature_info_map([] {
+ DocumentPolicyFeatureInfoMap map({
+ {%- for feature in features %}
{
- "{{feature.document_policy_name}}",
- {{parse_default_value(feature.default_value, feature.value_type)}}
+ mojom::DocumentPolicyFeature::k{{feature.name}},
+ {
+ "{{feature.document_policy_name}}",
+ {{parse_default_value(feature.default_value, feature.value_type)}}
+ }
+ },
+ {%- endfor %}
+ });
+
+ {%- for feature in features %}
+ {%- if feature.default_value_behind_flag %}
+ {%- for flag, default_value in feature.default_value_behind_flag %}
+ {%- if not loop.first %} else {% endif %}
+ if (base::FeatureList::IsEnabled(features::k{{flag}})) {
+ map.find(mojom::DocumentPolicyFeature::k{{feature.name}})->second.default_value =
+ {{parse_default_value(default_value, feature.value_type)}};
}
- },
+ {%- endfor %}
+ {%- endif %}
{%- endfor %}
- });
+
+ return map;
+ }());
return *feature_info_map;
}
@@ -38,5 +55,3 @@ const DocumentPolicyNameFeatureMap& GetDocumentPolicyNameFeatureMap() {
}
} // namespace blink
-
-
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
index 91712d1b263..2e46f6e80e4 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
@@ -61,6 +61,12 @@ const {{field.type_name}}&
{%- endfor -%}
{% endmacro %}
+{% macro group_setter_expression(group) %}
+{% for group in group.path_without_root() -%}
+{{group.member_name}}{{print_if(not loop.last, ".Access()->")}}
+{%- endfor -%}
+{% endmacro %}
+
{% macro declare_storage(field) %}
{% if field.is_bit_field %}
{{print_if(field.mutable, "mutable ")}}unsigned {{field.name}} : {{field.size}}; // {{field.type_name}}
@@ -87,12 +93,15 @@ const {{field.type_name}}&
{% for subgroup in group.subgroups %}
{# If every field in this subgroup is to be compared, we can compare the
group pointer instead. #}
+ {% set group_expression = group_getter_expression(subgroup) %}
{% if subgroup.all_fields|rejectattr("custom_compare")|reject("in", fields_to_compare)|list|length == 0 -%}
- {{boolean_and()}}{{subgroup.member_name}} == o.{{subgroup.member_name}}
+ {{boolean_and()}}{{group_expression}} == o.{{group_expression}}
{# Otherwise, we would have to recursively generate comparison operations
- on fields in the subgroup. #}
+ on fields in the subgroup. If the objects are the same, we can skip the
+ per-field comparisons. #}
{% elif subgroup.all_fields|rejectattr("custom_compare")|select("in", fields_to_compare)|list|length > 0 -%}
- {{fieldwise_compare(subgroup, fields_to_compare, boolean_and)}}
+ {{boolean_and()}}({{group_expression}}.Get() == o.{{group_expression}}.Get()
+|| ({{fieldwise_compare(subgroup, fields_to_compare)}}))
{% endif %}
{% endfor %}
{% for field in group.fields|rejectattr("custom_compare")|select("in", fields_to_compare) -%}
@@ -102,10 +111,13 @@ const {{field.type_name}}&
{% macro fieldwise_copy(group, fields_to_copy) %}
{% for subgroup in group.subgroups %}
+ {% set group_expression = group_getter_expression(subgroup) %}
{% if subgroup.all_fields|rejectattr("custom_copy")|reject("in", fields_to_copy)|list|length == 0 -%}
- {{subgroup.member_name}} = other.{{subgroup.member_name}};
+ {{group_setter_expression(subgroup)}} = other.{{group_expression}};
{% elif subgroup.all_fields|rejectattr("custom_copy")|select("in", fields_to_copy)|list|length > 0 -%}
- {{fieldwise_copy(subgroup, fields_to_copy)}}
+if ({{group_expression}}.Get() != other.{{group_expression}}.Get()) {
+{{fieldwise_copy(subgroup, fields_to_copy)|indent(2, true)}}
+}
{% endif %}
{% endfor %}
{% for field in group.fields|rejectattr("custom_copy")|select("in", fields_to_copy) -%}
@@ -118,12 +130,14 @@ const {{field.type_name}}&
{% for subgroup in group.subgroups %}
{# If every field in this subgroup is inherited, we directly compare the
group pointer instead. #}
+ {% set group_expression = group_getter_expression(subgroup) %}
{% if subgroup.all_fields|rejectattr("is_inherited")|list|length == 0 -%}
- {{boolean_and()}}{{subgroup.member_name}}.Get() == o.{{subgroup.member_name}}.Get()
+ {{boolean_and()}}{{group_expression}}.Get() == o.{{group_expression}}.Get()
{# Otherwise, we would have to recursively generate comparison operations
on fields in the subgroup. #}
{% elif subgroup.all_fields|selectattr("is_inherited")|list|length > 0 -%}
- {{fieldwise_pointer_compare_inherited(subgroup, boolean_and)}}
+ {{boolean_and()}}({{group_expression}}.Get() == o.{{group_expression}}.Get()
+|| ({{fieldwise_pointer_compare_inherited(subgroup)}}))
{% endif %}
{% endfor %}
{% for field in group.fields if field.is_inherited -%}
@@ -131,6 +145,14 @@ const {{field.type_name}}&
{% endfor %}
{% endmacro %}
+{% macro diff_field(is_pointer_type, expr) %}
+{% if is_pointer_type -%}
+!DataEquivalent(a.{{expr}}, b.{{expr}})
+{%- else -%}
+a.{{expr}} != b.{{expr}}
+{%- endif %}
+{% endmacro %}
+
{% macro fieldwise_diff(group_to_diff) %}
{% for diff_group in group_to_diff.subgroups %}
if (a.{{group_getter_expression(diff_group.group)}}.Get() != b.{{group_getter_expression(diff_group.group)}}.Get()) {
@@ -138,7 +160,7 @@ if (a.{{group_getter_expression(diff_group.group)}}.Get() != b.{{group_getter_ex
}
{% endfor %}
{% for field in group_to_diff.fields %}
-if (a.{{getter_expression(field)}} != b.{{getter_expression(field)}})
+if ({{diff_field(field.wrapper_pointer_name, getter_expression(field))}})
return true;
{% endfor %}
{% for expression in group_to_diff.expressions %}
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/macros.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/macros.tmpl
index dcdbb02a56c..d446c30767b 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/macros.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/macros.tmpl
@@ -76,3 +76,13 @@ case {{ length }}:
{% macro print_if(predicate, str) -%}
{% if predicate %}{{str}}{% endif %}
{%- endmacro %}
+
+
+{# See //docs/lacros.md for details on these Chrome OS defines. #}
+{%- macro platform_define(platform) -%}
+{%- if platform|lower == 'chromeos' -%}
+(BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS))
+{%- else -%}
+defined(OS_{{platform | upper}})
+{%- endif -%}
+{%- endmacro -%}
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
index fea0690b3f9..6cbd0173460 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
@@ -1,4 +1,4 @@
-{% from 'templates/macros.tmpl' import license, source_files_for_generated_file %}
+{% from 'templates/macros.tmpl' import license, source_files_for_generated_file, platform_define %}
{{license()}}
{{source_files_for_generated_file(template_file, input_files)}}
@@ -8,7 +8,8 @@
#include <algorithm>
#include <array>
#include <iterator>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -100,7 +101,7 @@ bool origin_trials::FeatureEnabledForOS(OriginTrialFeature feature) {
#if
{%- for os in feature.origin_trial_os %}
{%- if not loop.first %} ||{% endif %}
- defined(OS_{{os | upper}})
+ {{platform_define(os)}}
{%- endfor %}
return true;
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/policy_helper.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/policy_helper.cc.tmpl
index b18e356c226..928c17a96a8 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/policy_helper.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/policy_helper.cc.tmpl
@@ -6,13 +6,14 @@
#include "third_party/blink/renderer/core/feature_policy/policy_helper.h"
#include "third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom-blink.h"
+#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
+#include "third_party/blink/renderer/core/inspector/protocol/Page.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
-
namespace {
{% for feature in feature_policy_features %}
@@ -50,8 +51,20 @@ const FeatureNameMap& GetDefaultFeatureNameMap() {
return default_feature_name_map;
}
-const DocumentPolicyFeatureSet& GetAvailableDocumentPolicyFeatures() {
+
+DocumentPolicyFeatureSet& GetAvailableDocumentPolicyFeaturesInternal() {
DEFINE_STATIC_LOCAL(DocumentPolicyFeatureSet, features, ());
+ return features;
+}
+
+
+void ResetAvailableDocumentPolicyFeaturesForTest() {
+ GetAvailableDocumentPolicyFeaturesInternal().clear();
+}
+
+
+const DocumentPolicyFeatureSet& GetAvailableDocumentPolicyFeatures() {
+ DocumentPolicyFeatureSet& features = GetAvailableDocumentPolicyFeaturesInternal();
if (features.IsEmpty()) {
{% for feature in document_policy_features %}
{% if not feature.depends_on or feature.name in dp_origin_trial_dependency_map %}
@@ -99,4 +112,16 @@ bool DisabledByOriginTrial(mojom::blink::DocumentPolicyFeature feature,
return false;
}
+String PermissionsPolicyFeatureToProtocol(mojom::blink::FeaturePolicyFeature feature) {
+ switch (feature) {
+ {% for feature in feature_policy_features %}
+ case mojom::blink::FeaturePolicyFeature::k{{feature.name}}:
+ return protocol::Page::PermissionsPolicyFeatureEnum::{{feature.devtools_enum_name}};
+ {% endfor %}
+ case mojom::blink::FeaturePolicyFeature::kNotFound:
+ NOTREACHED();
+ return "";
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
index ca5cbd86227..2b5eeb4e371 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
@@ -1,9 +1,10 @@
-{% from 'templates/macros.tmpl' import license, source_files_for_generated_file %}
+{% from 'templates/macros.tmpl' import license, source_files_for_generated_file, platform_define %}
{{license()}}
{{source_files_for_generated_file(template_file, input_files)}}
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -33,7 +34,7 @@ void RuntimeEnabledFeatures::Set{{feature_set|capitalize}}FeaturesEnabled(bool e
// Platform-dependent features
{% for platform in platforms %}
-#if defined(OS_{{platform | upper}})
+#if {{platform_define(platform)}}
{% for feature in features if feature.status_type == 'dict' and feature.status[platform] == feature_set %}
Set{{feature.name}}Enabled(enable);
{% endfor %}
@@ -44,7 +45,7 @@ void RuntimeEnabledFeatures::Set{{feature_set|capitalize}}FeaturesEnabled(bool e
#if
{%- for platform in platforms %}
{%- if not loop.first %} &&{% endif %}
- !defined(OS_{{platform | upper}})
+ !{{platform_define(platform)}}
{%- endfor %}
{% for feature in features if feature.status_type == 'dict' and feature.status['default'] == feature_set %}
@@ -112,7 +113,7 @@ bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.
// Platform-dependent features
{% for platform in platforms %}
-#if defined(OS_{{platform | upper}})
+#if {{platform_define(platform)}}
{% for feature in features %}
{% if feature.status_type == 'dict' %}
bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.status[platform] == 'stable' else 'false'}};
@@ -125,7 +126,7 @@ bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.
#if
{%- for platform in platforms %}
{%- if not loop.first %} &&{% endif %}
- !defined(OS_{{platform | upper}})
+ !{{platform_define(platform)}}
{%- endfor %}
{% for feature in features %}
diff --git a/chromium/third_party/blink/renderer/build/scripts/templates/settings_macros.h.tmpl b/chromium/third_party/blink/renderer/build/scripts/templates/settings_macros.h.tmpl
index 6f917df98a7..327431d6054 100644
--- a/chromium/third_party/blink/renderer/build/scripts/templates/settings_macros.h.tmpl
+++ b/chromium/third_party/blink/renderer/build/scripts/templates/settings_macros.h.tmpl
@@ -39,28 +39,16 @@ void Settings::Set{{setting.name.to_upper_camel_case()}}({{setting.type|to_passi
return; \
{{setting.name.to_class_data_member()}} = {{setting.name.to_snake_case()}}; \
{% if setting.invalidate %}
- Invalidate(SettingsDelegate::k{{setting.invalidate}}Change); \
+ {% for type in setting.invalidate %}
+ Invalidate(SettingsDelegate::ChangeType::k{{type}}); \
+ {% endfor %}
{% endif %}
} \
{% endfor %}
void Settings::SetFromStrings(const String& name, const String& value) { \
{% for setting in settings %}
if (name == "{{setting.name}}") { \
- Set{{setting.name.to_upper_camel_case()}}( \
- {% if setting.type == 'String' %}
- value \
- {% elif setting.type == 'bool' %}
- value.IsEmpty() || value == "true" \
- {% elif setting.type == 'int' %}
- value.ToInt() \
- {% elif setting.type == 'float' %}
- value.ToFloat() \
- {% elif setting.type == 'double' %}
- value.ToDouble() \
- {% else %}
- static_cast<{{setting.type}}>(value.ToInt()) \
- {% endif %}
- ); \
+ Set{{setting.name.to_upper_camel_case()}}(FromString<{{setting.type}}>()(value)); \
return; \
} \
{% endfor %}
diff --git a/chromium/third_party/blink/renderer/build/scripts/writer_test_util.py b/chromium/third_party/blink/renderer/build/scripts/writer_test_util.py
new file mode 100644
index 00000000000..f991dcaac2f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/build/scripts/writer_test_util.py
@@ -0,0 +1,111 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import contextlib
+import difflib
+import filecmp
+import os
+import shutil
+import tempfile
+import unittest
+
+from json5_generator import Json5File, Writer
+
+
+@contextlib.contextmanager
+def tmp_dir():
+ tmp = tempfile.mkdtemp()
+ try:
+ yield tmp
+ finally:
+ shutil.rmtree(tmp)
+
+
+def path_to_test_file(*path):
+ return os.path.join(os.path.dirname(__file__), 'tests', *path)
+
+
+def diff(filename1, filename2):
+ with open(filename1) as file1:
+ file1_lines = file1.readlines()
+ with open(filename2) as file2:
+ file2_lines = file2.readlines()
+
+ # Use Python's difflib module so that diffing works across platforms
+ return ''.join(difflib.context_diff(file1_lines, file2_lines))
+
+
+def is_identical_file(reference_filename, output_filename):
+ reference_basename = os.path.basename(reference_filename)
+
+ if not os.path.isfile(reference_filename):
+ print 'Missing reference file!'
+ print '(if adding new test, update reference files)'
+ print reference_basename
+ print
+ return False
+
+ if not filecmp.cmp(reference_filename, output_filename):
+ # cmp is much faster than diff, and usual case is "no difference",
+ # so only run diff if cmp detects a difference
+ print 'FAIL: %s' % reference_basename
+ print diff(reference_filename, output_filename)
+ return False
+
+ return True
+
+
+def compare_output_dir(reference_dir, output_dir):
+ """
+ Compares output files in both reference_dir and output_dir.
+
+ Note: this function ignores subdirectory content in both reference
+ dir and output_dir.
+
+ Note: reference_dir should have all ref files ending with .ref suffix.
+ '.ref' suffix is added to bypass code formatter on reference files.
+
+ :returns {bool}: Whether files in output dir matches files in ref dir
+ """
+ ref_content = {
+ f[:-4]
+ for f in os.listdir(reference_dir) if f.endswith('.ref')
+ }
+ output_content = set(os.listdir(output_dir))
+
+ if ref_content != output_content:
+ print 'Output files does not match.'
+ print 'Following files are extra: {}'.format(output_content -
+ ref_content)
+ print 'Following files are missing: {}'.format(ref_content -
+ output_content)
+ return False
+
+ for file_name in ref_content:
+ ref_file = os.path.join(reference_dir, file_name) + '.ref'
+ output_file = os.path.join(output_dir, file_name)
+
+ if os.path.isdir(ref_file) and os.path.isdir(output_file):
+ continue
+ elif os.path.isdir(ref_file) or os.path.isdir(output_file):
+ return False
+ elif not is_identical_file(ref_file, output_file):
+ return False
+
+ return True
+
+
+class WriterTest(unittest.TestCase):
+ def _test_writer(self, writer_class, json5_files, reference_dir):
+ """
+ :param writer_class {Writer}: a subclass to Writer
+ :param json5_files {List[str]}: json5 test input files
+ :param reference_dir {str}: directory to expected output files
+ """
+ with tmp_dir() as tmp:
+ writer = writer_class(json5_files, tmp)
+ writer.write_files(tmp)
+ writer.cleanup_files(tmp)
+
+ self.assertTrue(compare_output_dir(reference_dir, tmp))
diff --git a/chromium/third_party/blink/renderer/controller/BUILD.gn b/chromium/third_party/blink/renderer/controller/BUILD.gn
index c5647d2dc50..8ca39927416 100644
--- a/chromium/third_party/blink/renderer/controller/BUILD.gn
+++ b/chromium/third_party/blink/renderer/controller/BUILD.gn
@@ -9,7 +9,10 @@ import("//third_party/blink/renderer/config.gni")
import("//third_party/blink/renderer/core/core.gni")
import("//third_party/blink/renderer/modules/modules.gni")
-visibility = [ "//third_party/blink/*" ]
+visibility = [
+ "//:gn_all",
+ "//third_party/blink/*",
+]
component("controller") {
output_name = "blink_controller"
@@ -195,6 +198,7 @@ source_set("blink_unittests_sources") {
testonly = true
sources = [
+ "performance_manager/renderer_resource_coordinator_impl_test.cc",
"performance_manager/v8_detailed_memory_reporter_impl_test.cc",
"performance_manager/v8_worker_memory_reporter_test.cc",
"tests/run_all_tests.cc",
@@ -224,6 +228,7 @@ source_set("blink_unittests_sources") {
"//base:i18n",
"//base/test:test_support",
"//components/payments/mojom:mojom_blink",
+ "//components/performance_manager/public/mojom:mojom_blink",
"//content/test:test_support",
"//gpu:test_support",
"//testing/gmock",
diff --git a/chromium/third_party/blink/renderer/controller/DIR_METADATA b/chromium/third_party/blink/renderer/controller/DIR_METADATA
new file mode 100644
index 00000000000..90b2e9cf1bc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Internals>Modularization"
+}
+
+team_email: "platform-architecture-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/controller/OWNERS b/chromium/third_party/blink/renderer/controller/OWNERS
index c4622a1fe9e..00ade91cf4e 100644
--- a/chromium/third_party/blink/renderer/controller/OWNERS
+++ b/chromium/third_party/blink/renderer/controller/OWNERS
@@ -4,6 +4,3 @@ nverne@chromium.org
slangley@chromium.org
tkent@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>Modularization
diff --git a/chromium/third_party/blink/renderer/controller/blink_initializer.cc b/chromium/third_party/blink/renderer/controller/blink_initializer.cc
index c6b95e1854b..b71000750cf 100644
--- a/chromium/third_party/blink/renderer/controller/blink_initializer.cc
+++ b/chromium/third_party/blink/renderer/controller/blink_initializer.cc
@@ -38,7 +38,7 @@
#include "mojo/public/cpp/bindings/binder_map.h"
#include "third_party/blink/public/common/experiments/memory_ablation_experiment.h"
#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h"
+#include "third_party/blink/public/mojom/optimization_guide/optimization_guide.mojom-blink.h"
#include "third_party/blink/public/platform/interface_registry.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/web/blink.h"
@@ -47,7 +47,6 @@
#include "third_party/blink/renderer/controller/dev_tools_frontend_impl.h"
#include "third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h"
#include "third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.h"
-#include "third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h"
#include "third_party/blink/renderer/core/animation/animation_clock.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/agent.h"
@@ -167,7 +166,6 @@ void InitializeCommon(Platform* platform, mojo::BinderMap* binders) {
// Initialize performance manager.
RendererResourceCoordinatorImpl::MaybeInitialize();
- V8WorkerMemoryReporter::RegisterWebMemoryReporter();
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc b/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc
index 7c15b9ea0e5..671189a4926 100644
--- a/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc
+++ b/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/inspector/dev_tools_host.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -65,9 +66,7 @@ const char DevToolsFrontendImpl::kSupplementName[] = "DevToolsFrontendImpl";
DevToolsFrontendImpl::DevToolsFrontendImpl(
LocalFrame& frame,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsFrontend> receiver)
- : Supplement<LocalFrame>(frame),
- host_(frame.DomWindow()),
- receiver_(this, frame.DomWindow()) {
+ : Supplement<LocalFrame>(frame) {
receiver_.Bind(std::move(receiver),
frame.GetTaskRunner(TaskType::kMiscPlatformAPI));
}
@@ -106,7 +105,10 @@ void DevToolsFrontendImpl::DidClearWindowObject() {
void DevToolsFrontendImpl::SetupDevToolsFrontend(
const String& api_script,
mojo::PendingAssociatedRemote<mojom::blink::DevToolsFrontendHost> host) {
- DCHECK(GetSupplementable()->IsMainFrame());
+ LocalFrame* frame = GetSupplementable();
+ DCHECK(frame->IsMainFrame());
+ frame->GetWidgetForLocalRoot()->SetLayerTreeDebugState(
+ cc::LayerTreeDebugState());
api_script_ = api_script;
host_.Bind(std::move(host),
GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI));
diff --git a/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.h b/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.h
index a36f7842f13..7e7eadb9011 100644
--- a/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.h
+++ b/chromium/third_party/blink/renderer/controller/dev_tools_frontend_impl.h
@@ -37,7 +37,6 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -84,13 +83,14 @@ class DevToolsFrontendImpl final
Member<DevToolsHost> devtools_host_;
String api_script_;
- HeapMojoAssociatedRemote<mojom::blink::DevToolsFrontendHost,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- host_;
+ // The host_ must outlive the ExecutionContext of LocalFrame, so it should not
+ // be associated with the ExecutionContext of LocalFrame.
+ HeapMojoAssociatedRemote<mojom::blink::DevToolsFrontendHost> host_{nullptr};
+ // The receiver_ must outlive the ExecutionContext of LocalFrame, so it should
+ // not be associated with the ExecutionContext of LocalFrame.
HeapMojoAssociatedReceiver<mojom::blink::DevToolsFrontend,
- DevToolsFrontendImpl,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- receiver_;
+ DevToolsFrontendImpl>
+ receiver_{this, nullptr};
DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendImpl);
};
diff --git a/chromium/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc b/chromium/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
index 9aa0387d653..8ae8a7b1054 100644
--- a/chromium/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
+++ b/chromium/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
@@ -11,6 +11,8 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
@@ -70,7 +72,9 @@ class MockMemoryUsageMonitor : public MemoryUsageMonitor {
MockMemoryUsageMonitor(
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_for_testing,
const base::TickClock* clock)
- : MemoryUsageMonitor(task_runner_for_testing, clock) {
+ : MemoryUsageMonitor(task_runner_for_testing, clock),
+ agent_group_scheduler_(
+ Thread::MainThread()->Scheduler()->CreateAgentGroupScheduler()) {
memset(&mock_memory_usage_, 0, sizeof(mock_memory_usage_));
}
~MockMemoryUsageMonitor() override = default;
@@ -115,11 +119,12 @@ class MockMemoryUsageMonitor : public MemoryUsageMonitor {
Page* CreateDummyPage() {
Page::PageClients page_clients;
FillWithEmptyClients(page_clients);
- return Page::CreateNonOrdinary(page_clients);
+ return Page::CreateNonOrdinary(page_clients, *agent_group_scheduler_);
}
MemoryUsage mock_memory_usage_;
std::vector<Persistent<Page>> dummy_pages_;
+ std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler_;
};
class HighestPmfReporterTest : public PageTestBase {
diff --git a/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc
index 29693644b89..d78fba9a480 100644
--- a/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc
+++ b/chromium/third_party/blink/renderer/controller/memory_usage_monitor.cc
@@ -79,7 +79,7 @@ void MemoryUsageMonitor::TimerFired() {
MemoryUsage usage = GetCurrentMemoryUsage();
for (auto& observer : observers_)
observer.OnMemoryPing(usage);
- if (!observers_.might_have_observers())
+ if (observers_.empty())
StopMonitoring();
}
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.cc b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.cc
index 090d4048a44..67c85abefc4 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.cc
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.cc
@@ -4,13 +4,20 @@
#include "third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h"
+#include <utility>
+
#include "base/bind.h"
+#include "base/check.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/frame.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/remote_frame.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
@@ -18,24 +25,30 @@
#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/thread.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+using performance_manager::mojom::blink::IframeAttributionData;
+using performance_manager::mojom::blink::IframeAttributionDataPtr;
+using performance_manager::mojom::blink::ProcessCoordinationUnit;
+using performance_manager::mojom::blink::V8ContextDescription;
+using performance_manager::mojom::blink::V8ContextDescriptionPtr;
+using performance_manager::mojom::blink::V8ContextWorldType;
+
namespace WTF {
// Copies the data by move.
template <>
-struct CrossThreadCopier<
- performance_manager::mojom::blink::V8ContextDescriptionPtr>
- : public WTF::CrossThreadCopierByValuePassThrough<
- performance_manager::mojom::blink::V8ContextDescriptionPtr> {};
+struct CrossThreadCopier<V8ContextDescriptionPtr>
+ : public WTF::CrossThreadCopierByValuePassThrough<V8ContextDescriptionPtr> {
+};
// Copies the data by move.
template <>
-struct CrossThreadCopier<
- performance_manager::mojom::blink::IframeAttributionDataPtr>
+struct CrossThreadCopier<IframeAttributionDataPtr>
: public WTF::CrossThreadCopierByValuePassThrough<
- performance_manager::mojom::blink::IframeAttributionDataPtr> {};
+ IframeAttributionDataPtr> {};
// Copies the data using the copy constructor.
template <>
@@ -46,9 +59,9 @@ struct CrossThreadCopier<blink::V8ContextToken>
namespace blink {
-namespace {
+using mojom::blink::FrameOwnerElementType;
-using performance_manager::mojom::blink::V8ContextWorldType;
+namespace {
// Determines if the given stable world ID is an extension world ID.
// Extensions IDs are 32-character strings containing characters in the range of
@@ -67,6 +80,33 @@ bool IsExtensionStableWorldId(const String& stable_world_id) {
return true;
}
+// Returns true if |owner| is an iframe, false otherwise.
+// This will also return true for custom elements built on iframe, like
+// <webview> and <guestview>. Since the renderer has no knowledge of these they
+// must be filtered out on the browser side.
+bool ShouldSendIframeNotificationsFor(const HTMLFrameOwnerElement& owner) {
+ return owner.OwnerType() == FrameOwnerElementType::kIframe;
+}
+
+// If |frame| is a RemoteFrame with a local parent, returns the parent.
+// Otherwise returns nullptr.
+LocalFrame* GetLocalParentOfRemoteFrame(const Frame& frame) {
+ if (IsA<RemoteFrame>(frame)) {
+ if (Frame* parent = frame.Tree().Parent()) {
+ return DynamicTo<LocalFrame>(parent);
+ }
+ }
+ return nullptr;
+}
+
+IframeAttributionDataPtr AttributionDataForOwner(
+ const HTMLFrameOwnerElement& owner) {
+ auto attribution_data = IframeAttributionData::New();
+ attribution_data->id = owner.FastGetAttribute(html_names::kIdAttr);
+ attribution_data->src = owner.FastGetAttribute(html_names::kSrcAttr);
+ return attribution_data;
+}
+
} // namespace
RendererResourceCoordinatorImpl::~RendererResourceCoordinatorImpl() = default;
@@ -80,9 +120,7 @@ void RendererResourceCoordinatorImpl::MaybeInitialize() {
DCHECK(IsMainThread());
DCHECK(platform);
- mojo::PendingRemote<
- performance_manager::mojom::blink::ProcessCoordinationUnit>
- remote;
+ mojo::PendingRemote<ProcessCoordinationUnit> remote;
platform->GetBrowserInterfaceBroker()->GetInterface(
remote.InitWithNewPipeAndPassReceiver());
RendererResourceCoordinator::Set(
@@ -91,8 +129,7 @@ void RendererResourceCoordinatorImpl::MaybeInitialize() {
void RendererResourceCoordinatorImpl::SetMainThreadTaskLoadIsLow(
bool main_thread_task_load_is_low) {
- if (!service_)
- return;
+ DCHECK(service_);
service_->SetMainThreadTaskLoadIsLow(main_thread_task_load_is_low);
}
@@ -100,14 +137,12 @@ void RendererResourceCoordinatorImpl::OnScriptStateCreated(
ScriptState* script_state,
ExecutionContext* execution_context) {
DCHECK(script_state);
- if (!service_)
- return;
+ DCHECK(service_);
- auto v8_desc = performance_manager::mojom::blink::V8ContextDescription::New();
+ auto v8_desc = V8ContextDescription::New();
v8_desc->token = script_state->GetToken();
- performance_manager::mojom::blink::IframeAttributionDataPtr
- iframe_attribution_data;
+ IframeAttributionDataPtr iframe_attribution_data;
// Default the world name to being empty.
@@ -162,12 +197,7 @@ void RendererResourceCoordinatorImpl::OnScriptStateCreated(
// frame.
auto* owner = To<HTMLFrameOwnerElement>(local_frame->Owner());
DCHECK(owner);
- iframe_attribution_data =
- performance_manager::mojom::blink::IframeAttributionData::New();
- iframe_attribution_data->id =
- owner->FastGetAttribute(html_names::kIdAttr);
- iframe_attribution_data->src =
- owner->FastGetAttribute(html_names::kSrcAttr);
+ iframe_attribution_data = AttributionDataForOwner(*owner);
}
}
}
@@ -189,18 +219,44 @@ void RendererResourceCoordinatorImpl::OnScriptStateDestroyed(
DispatchOnV8ContextDestroyed(script_state->GetToken());
}
+void RendererResourceCoordinatorImpl::OnBeforeContentFrameAttached(
+ const Frame& frame,
+ const HTMLFrameOwnerElement& owner) {
+ DCHECK(service_);
+ if (!ShouldSendIframeNotificationsFor(owner))
+ return;
+ LocalFrame* parent = GetLocalParentOfRemoteFrame(frame);
+ if (!parent)
+ return;
+ service_->OnRemoteIframeAttached(
+ parent->GetLocalFrameToken(),
+ frame.GetFrameToken().GetAs<RemoteFrameToken>(),
+ AttributionDataForOwner(owner));
+}
+
+void RendererResourceCoordinatorImpl::OnBeforeContentFrameDetached(
+ const Frame& frame,
+ const HTMLFrameOwnerElement& owner) {
+ DCHECK(service_);
+ if (!ShouldSendIframeNotificationsFor(owner))
+ return;
+ LocalFrame* parent = GetLocalParentOfRemoteFrame(frame);
+ if (!parent)
+ return;
+ service_->OnRemoteIframeDetached(
+ parent->GetLocalFrameToken(),
+ frame.GetFrameToken().GetAs<RemoteFrameToken>());
+}
+
RendererResourceCoordinatorImpl::RendererResourceCoordinatorImpl(
- mojo::PendingRemote<
- performance_manager::mojom::blink::ProcessCoordinationUnit> remote) {
+ mojo::PendingRemote<ProcessCoordinationUnit> remote) {
service_.Bind(std::move(remote));
}
void RendererResourceCoordinatorImpl::DispatchOnV8ContextCreated(
- performance_manager::mojom::blink::V8ContextDescriptionPtr v8_desc,
- performance_manager::mojom::blink::IframeAttributionDataPtr
- iframe_attribution_data) {
- if (!service_)
- return;
+ V8ContextDescriptionPtr v8_desc,
+ IframeAttributionDataPtr iframe_attribution_data) {
+ DCHECK(service_);
// Calls to this can arrive on any thread (due to workers, etc), but the
// interface itself is bound to the main thread. In this case, once we've
// collated the necessary data we bounce over to the main thread. Note that
@@ -221,8 +277,7 @@ void RendererResourceCoordinatorImpl::DispatchOnV8ContextCreated(
void RendererResourceCoordinatorImpl::DispatchOnV8ContextDetached(
const blink::V8ContextToken& token) {
- if (!service_)
- return;
+ DCHECK(service_);
// See DispatchOnV8ContextCreated for why this is both needed and safe.
if (!IsMainThread()) {
blink::PostCrossThreadTask(
@@ -236,8 +291,7 @@ void RendererResourceCoordinatorImpl::DispatchOnV8ContextDetached(
}
void RendererResourceCoordinatorImpl::DispatchOnV8ContextDestroyed(
const blink::V8ContextToken& token) {
- if (!service_)
- return;
+ DCHECK(service_);
// See DispatchOnV8ContextCreated for why this is both needed and safe.
if (!IsMainThread()) {
blink::PostCrossThreadTask(
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h
index e02fd5b2dcb..a908f8076d8 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h
@@ -37,8 +37,14 @@ class CONTROLLER_EXPORT RendererResourceCoordinatorImpl final
ExecutionContext* execution_context) final;
void OnScriptStateDetached(ScriptState* script_state) final;
void OnScriptStateDestroyed(ScriptState* script_state) final;
+ void OnBeforeContentFrameAttached(const Frame& frame,
+ const HTMLFrameOwnerElement& owner) final;
+ void OnBeforeContentFrameDetached(const Frame& frame,
+ const HTMLFrameOwnerElement& owner) final;
private:
+ friend class RendererResourceCoordinatorImplTest;
+
explicit RendererResourceCoordinatorImpl(
mojo::PendingRemote<
performance_manager::mojom::blink::ProcessCoordinationUnit> remote);
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl_test.cc b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl_test.cc
new file mode 100644
index 00000000000..92185a64a31
--- /dev/null
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl_test.cc
@@ -0,0 +1,272 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/controller/performance_manager/renderer_resource_coordinator_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/check.h"
+#include "base/memory/ptr_util.h"
+#include "components/performance_manager/public/mojom/coordination_unit.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 "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+namespace {
+
+using performance_manager::mojom::blink::IframeAttributionData;
+using performance_manager::mojom::blink::IframeAttributionDataPtr;
+using performance_manager::mojom::blink::ProcessCoordinationUnit;
+using performance_manager::mojom::blink::V8ContextDescription;
+using performance_manager::mojom::blink::V8ContextDescriptionPtr;
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::Field;
+using ::testing::InSequence;
+using ::testing::Mock;
+using ::testing::Pointee;
+
+class MockProcessCoordinationUnit : public ProcessCoordinationUnit {
+ public:
+ explicit MockProcessCoordinationUnit(
+ mojo::PendingReceiver<ProcessCoordinationUnit> receiver)
+ : receiver_(this, std::move(receiver)) {}
+
+ // Don't mock uninteresting property signals.
+ void SetMainThreadTaskLoadIsLow(bool main_thread_task_load_is_low) final {}
+
+ MOCK_METHOD(void,
+ OnV8ContextCreated,
+ (V8ContextDescriptionPtr description,
+ IframeAttributionDataPtr attribution),
+ (override));
+ MOCK_METHOD(void,
+ OnV8ContextDetached,
+ (const blink::V8ContextToken& token),
+ (override));
+ MOCK_METHOD(void,
+ OnV8ContextDestroyed,
+ (const blink::V8ContextToken& token),
+ (override));
+ MOCK_METHOD(void,
+ OnRemoteIframeAttached,
+ (const blink::LocalFrameToken& parent_frame_token,
+ const blink::RemoteFrameToken& remote_frame_token,
+ IframeAttributionDataPtr attribution),
+ (override));
+ MOCK_METHOD(void,
+ OnRemoteIframeDetached,
+ (const blink::LocalFrameToken& parent_frame_token,
+ const blink::RemoteFrameToken& remote_frame_token),
+ (override));
+
+ void VerifyExpectations() {
+ // Ensure that any pending Mojo messages are processed.
+ receiver_.FlushForTesting();
+ Mock::VerifyAndClearExpectations(this);
+ }
+
+ private:
+ mojo::Receiver<ProcessCoordinationUnit> receiver_;
+};
+
+MATCHER_P(MatchV8ContextDescription,
+ execution_context_token,
+ "V8ContextDescription::execution_context_token matches") {
+ return arg->execution_context_token ==
+ blink::ExecutionContextToken(execution_context_token);
+}
+
+MATCHER_P2(MatchAndSaveV8ContextDescription,
+ execution_context_token,
+ output_token,
+ "V8ContextDescription::execution_context_token matches") {
+ DCHECK(output_token);
+ *output_token = arg->token;
+ return arg->execution_context_token ==
+ blink::ExecutionContextToken(execution_context_token);
+}
+
+} // namespace
+
+class RendererResourceCoordinatorImplTest : public ::testing::Test {
+ protected:
+ void TearDown() override {
+ // Uninstall any RendererResourceCoordinator that was set by
+ // InitializeMockProcessCoordinationUnit.
+ RendererResourceCoordinator::Set(nullptr);
+ }
+
+ template <typename MockType>
+ void InitializeMockProcessCoordinationUnit() {
+ DCHECK(!mock_process_coordination_unit_);
+ DCHECK(!resource_coordinator_);
+
+ mojo::PendingRemote<ProcessCoordinationUnit> pending_remote;
+ mock_process_coordination_unit_ = std::make_unique<MockType>(
+ pending_remote.InitWithNewPipeAndPassReceiver());
+
+ // Create a RendererResourceCoordinator bound to the other end of the
+ // MockProcessCoordinationUnit's remote.
+ // Can't use make_unique with a private constructor.
+ resource_coordinator_ = base::WrapUnique(
+ new RendererResourceCoordinatorImpl(std::move(pending_remote)));
+ RendererResourceCoordinator::Set(resource_coordinator_.get());
+ }
+
+ std::unique_ptr<MockProcessCoordinationUnit> mock_process_coordination_unit_;
+ std::unique_ptr<RendererResourceCoordinatorImpl> resource_coordinator_;
+};
+
+TEST_F(RendererResourceCoordinatorImplTest, IframeNotifications) {
+ InitializeMockProcessCoordinationUnit<
+ ::testing::StrictMock<MockProcessCoordinationUnit>>();
+
+ frame_test_helpers::WebViewHelper helper;
+ helper.InitializeAndLoad("about:blank");
+
+ // The <iframe> tag will have a fixed id attribute and no src attribute.
+ auto iframe_attribution_matcher =
+ Pointee(AllOf(Field(&IframeAttributionData::id, "iframe-id"),
+ Field(&IframeAttributionData::src, WTF::String())));
+
+ // Create an empty frame. This will send a notification as the main frame's
+ // context is created.
+ WebLocalFrameImpl* main_frame = helper.GetWebView()->MainFrameImpl();
+ EXPECT_CALL(
+ *mock_process_coordination_unit_,
+ OnV8ContextCreated(
+ MatchV8ContextDescription(main_frame->GetLocalFrameToken()), _));
+ frame_test_helpers::LoadHTMLString(
+ main_frame,
+ "<!DOCTYPE html>"
+ "<iframe id='iframe-id'></iframe>",
+ url_test_helpers::ToKURL("https://example.com/subframe.html"));
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Swap for a remote frame.
+ WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnRemoteIframeAttached(main_frame->GetLocalFrameToken(),
+ remote_frame->GetRemoteFrameToken(),
+ iframe_attribution_matcher));
+ main_frame->FirstChild()->Swap(remote_frame);
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Create another remote frame, this time with a remote parent. No
+ // notification should be received.
+ frame_test_helpers::CreateRemoteChild(*remote_frame);
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Test frame swaps. Each one should send a detach notification for the
+ // current frame and an attach notification for the new frame.
+
+ // Save the V8ContextToken reported in OnV8ContextCreated so it can be
+ // compared with the token in the matching OnV8ContextDetached.
+ blink::V8ContextToken current_v8_context_token;
+
+ // Remote -> Remote
+ WebRemoteFrameImpl* new_remote_frame = frame_test_helpers::CreateRemote();
+ {
+ InSequence seq;
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnRemoteIframeDetached(main_frame->GetLocalFrameToken(),
+ remote_frame->GetRemoteFrameToken()));
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnRemoteIframeAttached(main_frame->GetLocalFrameToken(),
+ new_remote_frame->GetRemoteFrameToken(),
+ iframe_attribution_matcher));
+ }
+ main_frame->FirstChild()->Swap(new_remote_frame);
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Remote -> Local
+ WebLocalFrameImpl* local_frame = helper.CreateProvisional(*new_remote_frame);
+ {
+ InSequence seq;
+ EXPECT_CALL(
+ *mock_process_coordination_unit_,
+ OnRemoteIframeDetached(main_frame->GetLocalFrameToken(),
+ new_remote_frame->GetRemoteFrameToken()));
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnV8ContextCreated(MatchAndSaveV8ContextDescription(
+ local_frame->GetLocalFrameToken(),
+ &current_v8_context_token),
+ iframe_attribution_matcher));
+ }
+ // Committing a navigation in the provisional frame swaps it in.
+ frame_test_helpers::LoadFrame(local_frame, "data:text/html,");
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Local -> Local
+ WebLocalFrameImpl* new_local_frame = helper.CreateProvisional(*local_frame);
+ {
+ InSequence seq;
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnV8ContextDetached(current_v8_context_token));
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnV8ContextCreated(MatchAndSaveV8ContextDescription(
+ new_local_frame->GetLocalFrameToken(),
+ &current_v8_context_token),
+ iframe_attribution_matcher));
+ }
+ // Committing a navigation in the provisional frame swaps it in.
+ frame_test_helpers::LoadFrame(new_local_frame, "data:text/html,");
+ mock_process_coordination_unit_->VerifyExpectations();
+
+ // Local -> Remote
+ remote_frame = frame_test_helpers::CreateRemote();
+ {
+ InSequence seq;
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnV8ContextDetached(current_v8_context_token));
+ EXPECT_CALL(*mock_process_coordination_unit_,
+ OnRemoteIframeAttached(main_frame->GetLocalFrameToken(),
+ remote_frame->GetRemoteFrameToken(),
+ iframe_attribution_matcher));
+ }
+ main_frame->FirstChild()->Swap(remote_frame);
+ mock_process_coordination_unit_->VerifyExpectations();
+}
+
+TEST_F(RendererResourceCoordinatorImplTest, NonIframeNotifications) {
+ // Don't care about mocked methods except for OnRemoteIframeAttached.
+ InitializeMockProcessCoordinationUnit<
+ ::testing::NiceMock<MockProcessCoordinationUnit>>();
+
+ frame_test_helpers::WebViewHelper helper;
+ helper.InitializeAndLoad("about:blank");
+
+ // Create an empty frame.
+ WebLocalFrameImpl* main_frame = helper.GetWebView()->MainFrameImpl();
+ frame_test_helpers::LoadHTMLString(
+ main_frame,
+ "<!DOCTYPE html>"
+ "<object type=\"text/html\"></object>",
+ url_test_helpers::ToKURL("https://example.com/subframe.html"));
+
+ // Swap for a remote frame. Since this is not an iframe, there should be no
+ // notification.
+ WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
+ EXPECT_CALL(*mock_process_coordination_unit_, OnRemoteIframeAttached(_, _, _))
+ .Times(0);
+ main_frame->FirstChild()->Swap(remote_frame);
+ mock_process_coordination_unit_->VerifyExpectations();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.cc b/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.cc
index 28935fda495..da92fe51e65 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.cc
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.cc
@@ -19,6 +19,7 @@
#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/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
#include "v8/include/v8.h"
@@ -51,6 +52,7 @@ class FrameAssociatedMeasurementDelegate : public v8::MeasureMemoryDelegate {
const std::vector<std::pair<v8::Local<v8::Context>, size_t>>&
context_sizes_in_bytes,
size_t unattributed_size_in_bytes) override {
+ DCHECK(IsMainThread());
mojom::blink::PerIsolateV8MemoryUsagePtr isolate_memory_usage =
mojom::blink::PerIsolateV8MemoryUsage::New();
for (const auto& context_and_size : context_sizes_in_bytes) {
@@ -63,8 +65,8 @@ class FrameAssociatedMeasurementDelegate : public v8::MeasureMemoryDelegate {
// TODO(crbug.com/1080672): It would be prefereable to count the
// V8SchemaRegistry context's overhead with unassociated_bytes, but at
// present there isn't a public API that allows this distinction.
- ++(isolate_memory_usage->num_unassociated_contexts);
- isolate_memory_usage->unassociated_context_bytes_used += size;
+ ++(isolate_memory_usage->num_detached_contexts);
+ isolate_memory_usage->detached_bytes_used += size;
continue;
}
if (DOMWrapperWorld::World(context).GetWorldId() !=
@@ -85,7 +87,7 @@ class FrameAssociatedMeasurementDelegate : public v8::MeasureMemoryDelegate {
#endif
isolate_memory_usage->contexts.push_back(std::move(context_memory_usage));
}
- isolate_memory_usage->unassociated_bytes_used = unattributed_size_in_bytes;
+ isolate_memory_usage->shared_bytes_used = unattributed_size_in_bytes;
std::move(callback_).Run(std::move(isolate_memory_usage));
}
@@ -128,6 +130,7 @@ class V8ProcessMemoryReporter : public RefCounted<V8ProcessMemoryReporter> {
result_(mojom::blink::PerProcessV8MemoryUsage::New()) {}
void StartMeasurements(V8DetailedMemoryReporterImpl::Mode mode) {
+ DCHECK(IsMainThread());
v8::Isolate* isolate = v8::Isolate::GetCurrent();
// 1. Start measurement of the main V8 isolate.
if (!isolate) {
@@ -136,7 +139,7 @@ class V8ProcessMemoryReporter : public RefCounted<V8ProcessMemoryReporter> {
MainMeasurementComplete(mojom::blink::PerIsolateV8MemoryUsage::New());
} else {
auto delegate = std::make_unique<FrameAssociatedMeasurementDelegate>(
- WTF::Bind(&V8ProcessMemoryReporter::MainMeasurementComplete,
+ WTF::Bind(&V8ProcessMemoryReporter::MainV8MeasurementComplete,
scoped_refptr<V8ProcessMemoryReporter>(this)));
isolate->MeasureMemory(std::move(delegate),
@@ -150,6 +153,30 @@ class V8ProcessMemoryReporter : public RefCounted<V8ProcessMemoryReporter> {
}
private:
+ void MainV8MeasurementComplete(
+ mojom::blink::PerIsolateV8MemoryUsagePtr isolate_memory_usage) {
+ // At this point measurement of the main V8 isolate is done and we
+ // can measure the corresponding Blink memory. Note that the order
+ // of the measurements is important because the V8 measurement does
+ // a GC and we want to get the Blink memory after the GC.
+ // This function and V8ProcessMemoryReporter::StartMeasurements both
+ // run on the main thread of the renderer. This means that the Blink
+ // heap given by ThreadState::Current() is attached to the main V8
+ // isolate given by v8::Isolate::GetCurrent().
+ ThreadState::Current()->CollectNodeAndCssStatistics(
+ WTF::Bind(&V8ProcessMemoryReporter::MainBlinkMeasurementComplete,
+ scoped_refptr<V8ProcessMemoryReporter>(this),
+ std::move(isolate_memory_usage)));
+ }
+
+ void MainBlinkMeasurementComplete(
+ mojom::blink::PerIsolateV8MemoryUsagePtr isolate_memory_usage,
+ size_t node_bytes,
+ size_t css_bytes) {
+ isolate_memory_usage->blink_bytes_used = node_bytes + css_bytes;
+ MainMeasurementComplete(std::move(isolate_memory_usage));
+ }
+
void MainMeasurementComplete(
mojom::blink::PerIsolateV8MemoryUsagePtr isolate_memory_usage) {
result_->isolates.push_back(std::move(isolate_memory_usage));
@@ -163,6 +190,9 @@ class V8ProcessMemoryReporter : public RefCounted<V8ProcessMemoryReporter> {
auto context_memory_usage = mojom::blink::PerContextV8MemoryUsage::New();
context_memory_usage->token = ToExecutionContextToken(worker.token);
context_memory_usage->bytes_used = worker.bytes;
+ if (!worker.url.IsNull()) {
+ context_memory_usage->url = worker.url.GetString();
+ }
worker_memory_usage->contexts.push_back(std::move(context_memory_usage));
result_->isolates.push_back(std::move(worker_memory_usage));
}
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl_test.cc b/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl_test.cc
index 089baf0ccac..f075c9ea5c2 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl_test.cc
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl_test.cc
@@ -39,6 +39,11 @@ class MemoryUsageChecker {
// only check the lower bound.
EXPECT_LE(1000000u, entry->bytes_used);
++actual_context_count;
+ if (entry->token.Is<DedicatedWorkerToken>()) {
+ EXPECT_EQ(String("http://fake.url/"), entry->url);
+ } else {
+ EXPECT_FALSE(entry->url);
+ }
}
}
EXPECT_EQ(expected_context_count_, actual_context_count);
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
index c363490451e..b9bf705966f 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
@@ -9,7 +9,6 @@
#include "base/check.h"
#include "base/time/time.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h"
#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
@@ -40,6 +39,14 @@ const base::TimeDelta V8WorkerMemoryReporter::kTimeout =
base::TimeDelta::FromSeconds(60);
namespace {
+
+// TODO(906991): Remove this once PlzDedicatedWorker ships. Until then
+// the browser does not know URLs of dedicated workers, so we pass them
+// together with the measurement result. We limit the max length of the
+// URLs to reduce memory allocations and the traffic between the renderer
+// and the browser processes.
+constexpr size_t kMaxReportedUrlLength = 2000;
+
// This delegate is provided to v8::Isolate::MeasureMemory API.
// V8 calls MeasurementComplete with the measurement result.
//
@@ -65,7 +72,7 @@ class WorkerMeasurementDelegate : public v8::MeasureMemoryDelegate {
private:
void NotifyMeasurementSuccess(
- V8WorkerMemoryReporter::WorkerMemoryUsage memory_usage);
+ std::unique_ptr<V8WorkerMemoryReporter::WorkerMemoryUsage> memory_usage);
void NotifyMeasurementFailure();
base::WeakPtr<V8WorkerMemoryReporter> worker_memory_reporter_;
WorkerThread* worker_thread_;
@@ -92,8 +99,17 @@ void WorkerMeasurementDelegate::MeasurementComplete(
for (auto& context_size : context_sizes) {
bytes += context_size.second;
}
- NotifyMeasurementSuccess(V8WorkerMemoryReporter::WorkerMemoryUsage{
- To<WorkerGlobalScope>(global_scope)->GetWorkerToken(), bytes});
+ auto* worker_global_scope = To<WorkerGlobalScope>(global_scope);
+ auto memory_usage =
+ std::make_unique<V8WorkerMemoryReporter::WorkerMemoryUsage>();
+ memory_usage->token = worker_global_scope->GetWorkerToken();
+ memory_usage->bytes = bytes;
+ if (worker_global_scope->IsUrlValid() &&
+ worker_global_scope->Url().GetString().length() < kMaxReportedUrlLength) {
+ // Copy the URL to send it over to the main thread.
+ memory_usage->url = worker_global_scope->Url().Copy();
+ }
+ NotifyMeasurementSuccess(std::move(memory_usage));
}
void WorkerMeasurementDelegate::NotifyMeasurementFailure() {
@@ -105,11 +121,11 @@ void WorkerMeasurementDelegate::NotifyMeasurementFailure() {
}
void WorkerMeasurementDelegate::NotifyMeasurementSuccess(
- V8WorkerMemoryReporter::WorkerMemoryUsage memory_usage) {
+ std::unique_ptr<V8WorkerMemoryReporter::WorkerMemoryUsage> memory_usage) {
DCHECK(worker_thread_->IsCurrentThread());
DCHECK(!did_notify_);
V8WorkerMemoryReporter::NotifyMeasurementSuccess(
- worker_thread_, worker_memory_reporter_, memory_usage);
+ worker_thread_, worker_memory_reporter_, std::move(memory_usage));
did_notify_ = true;
}
@@ -170,12 +186,12 @@ void V8WorkerMemoryReporter::StartMeasurement(
void V8WorkerMemoryReporter::NotifyMeasurementSuccess(
WorkerThread* worker_thread,
base::WeakPtr<V8WorkerMemoryReporter> worker_memory_reporter,
- WorkerMemoryUsage memory_usage) {
+ std::unique_ptr<WorkerMemoryUsage> memory_usage) {
DCHECK(worker_thread->IsCurrentThread());
PostCrossThreadTask(
*Thread::MainThread()->GetTaskRunner(), FROM_HERE,
CrossThreadBindOnce(&V8WorkerMemoryReporter::OnMeasurementSuccess,
- worker_memory_reporter, memory_usage));
+ worker_memory_reporter, std::move(memory_usage)));
}
// static
@@ -201,11 +217,11 @@ void V8WorkerMemoryReporter::OnMeasurementFailure() {
}
void V8WorkerMemoryReporter::OnMeasurementSuccess(
- WorkerMemoryUsage memory_usage) {
+ std::unique_ptr<WorkerMemoryUsage> memory_usage) {
DCHECK(IsMainThread());
if (state_ == State::kDone)
return;
- result_.workers.emplace_back(memory_usage);
+ result_.workers.emplace_back(*memory_usage);
++success_count_;
if (success_count_ + failure_count_ == worker_count_) {
InvokeCallback();
@@ -234,50 +250,4 @@ void V8WorkerMemoryReporter::InvokeCallback() {
state_ = State::kDone;
}
-namespace {
-
-// Used by the performance.measureMemory Web API. It forwards the incoming
-// memory measurement request to V8WorkerMemoryReporter and adapts the result
-// to match the format of the Web API.
-//
-// It will be removed in the future when performance.measureMemory switches
-// to a mojo-based implementation that queries PerformanceManager in the
-// browser process.
-class WebMemoryReporter : public MeasureMemoryController::V8MemoryReporter {
- void GetMemoryUsage(MeasureMemoryController::ResultCallback callback,
- v8::MeasureMemoryExecution execution) override {
- V8WorkerMemoryReporter::GetMemoryUsage(
- WTF::Bind(&WebMemoryReporter::ForwardResults, std::move(callback)),
- execution);
- }
-
- // Adapts the result to match the format expected by MeasureMemoryController.
- static void ForwardResults(MeasureMemoryController::ResultCallback callback,
- const V8WorkerMemoryReporter::Result& result) {
- HeapVector<Member<MeasureMemoryBreakdown>> new_result;
- const String kDedicatedWorkerGlobalScope("DedicatedWorkerGlobalScope");
- const String kJS("JS");
- const Vector<String> kWorkerMemoryTypes = {kDedicatedWorkerGlobalScope,
- kJS};
- const Vector<String> kEmptyAttribution = {};
- for (const auto& worker : result.workers) {
- if (worker.token.Is<DedicatedWorkerToken>()) {
- MeasureMemoryBreakdown* entry = MeasureMemoryBreakdown::Create();
- entry->setBytes(worker.bytes);
- entry->setUserAgentSpecificTypes(kWorkerMemoryTypes);
- entry->setAttribution(kEmptyAttribution);
- new_result.push_back(entry);
- }
- }
- std::move(callback).Run(new_result);
- }
-};
-
-} // anonymous namespace
-
-void V8WorkerMemoryReporter::RegisterWebMemoryReporter() {
- MeasureMemoryController::SetDedicatedWorkerMemoryReporter(
- new WebMemoryReporter());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h
index e60db41b63d..484b3314c85 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.h
@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/controller/controller_export.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8/include/v8.h"
@@ -40,6 +41,12 @@ class CONTROLLER_EXPORT V8WorkerMemoryReporter {
struct WorkerMemoryUsage {
WorkerToken token;
size_t bytes;
+ // TODO(906991): Remove this once PlzDedicatedWorker ships. Until then
+ // the browser does not know URLs of dedicated workers, so we pass them
+ // together with the measurement result.
+ // URLs longer than kMaxReportedUrlLength are skipped. In such a case
+ // url.IsNull() returns true.
+ KURL url;
};
struct Result {
@@ -54,15 +61,13 @@ class CONTROLLER_EXPORT V8WorkerMemoryReporter {
v8::MeasureMemoryExecution mode);
// These functions are called by WorkerMeasurementDelegate on a worker thread.
- static void NotifyMeasurementSuccess(WorkerThread*,
- base::WeakPtr<V8WorkerMemoryReporter>,
- WorkerMemoryUsage memory_usage);
+ static void NotifyMeasurementSuccess(
+ WorkerThread*,
+ base::WeakPtr<V8WorkerMemoryReporter>,
+ std::unique_ptr<WorkerMemoryUsage> memory_usage);
static void NotifyMeasurementFailure(WorkerThread*,
base::WeakPtr<V8WorkerMemoryReporter>);
- // Injects the implementation for the performance.measureMemory Web API.
- static void RegisterWebMemoryReporter();
-
private:
// The initial state is kWaiting.
// Transition from kWaiting to kDone happens on two events:
@@ -86,7 +91,7 @@ class CONTROLLER_EXPORT V8WorkerMemoryReporter {
// Functions that run on the main thread.
void OnTimeout();
void OnMeasurementFailure();
- void OnMeasurementSuccess(WorkerMemoryUsage memory_usage);
+ void OnMeasurementSuccess(std::unique_ptr<WorkerMemoryUsage> memory_usage);
void InvokeCallback();
base::WeakPtr<V8WorkerMemoryReporter> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
diff --git a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter_test.cc b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter_test.cc
index 8bf9115b080..100d2eebb28 100644
--- a/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter_test.cc
+++ b/chromium/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter_test.cc
@@ -68,6 +68,7 @@ class MemoryUsageChecker {
EXPECT_THAT(expected_counts, testing::Contains(worker_count_));
if (worker_count_ == 1) {
EXPECT_LE(bytes_per_worker_lower_bound_, result.workers[0].bytes);
+ EXPECT_EQ(KURL("http://fake.url/"), result.workers[0].url);
}
called_ = true;
if (callback_action_ == CallbackAction::kExitRunLoop) {
@@ -98,7 +99,7 @@ TEST_F(V8WorkerMemoryReporterTest, OnMeasurementSuccess) {
EXPECT_CALL(mock_callback, Callback(result)).Times(1);
for (auto& worker : result.workers) {
- reporter.OnMeasurementSuccess(worker);
+ reporter.OnMeasurementSuccess(std::make_unique<WorkerMemoryUsage>(worker));
}
}
@@ -112,9 +113,11 @@ TEST_F(V8WorkerMemoryReporterTest, OnMeasurementFailure) {
WorkerMemoryUsage{WorkerToken(DedicatedWorkerToken()), 2}})};
EXPECT_CALL(mock_callback, Callback(result)).Times(1);
- reporter.OnMeasurementSuccess(result.workers[0]);
+ reporter.OnMeasurementSuccess(
+ std::make_unique<WorkerMemoryUsage>(result.workers[0]));
reporter.OnMeasurementFailure();
- reporter.OnMeasurementSuccess(result.workers[1]);
+ reporter.OnMeasurementSuccess(
+ std::make_unique<WorkerMemoryUsage>(result.workers[1]));
}
TEST_F(V8WorkerMemoryReporterTest, OnTimeout) {
@@ -128,11 +131,13 @@ TEST_F(V8WorkerMemoryReporterTest, OnTimeout) {
EXPECT_CALL(mock_callback, Callback(result)).Times(1);
- reporter.OnMeasurementSuccess(result.workers[0]);
- reporter.OnMeasurementSuccess(result.workers[1]);
- reporter.OnTimeout();
reporter.OnMeasurementSuccess(
- WorkerMemoryUsage{WorkerToken(SharedWorkerToken()), 2});
+ std::make_unique<WorkerMemoryUsage>(result.workers[0]));
+ reporter.OnMeasurementSuccess(
+ std::make_unique<WorkerMemoryUsage>(result.workers[1]));
+ reporter.OnTimeout();
+ reporter.OnMeasurementSuccess(std::make_unique<WorkerMemoryUsage>(
+ WorkerMemoryUsage{WorkerToken(SharedWorkerToken()), 2}));
reporter.OnMeasurementFailure();
}
@@ -146,8 +151,10 @@ TEST_F(V8WorkerMemoryReporterTest, OnTimeoutNoop) {
WorkerMemoryUsage{WorkerToken(DedicatedWorkerToken()), 2}})};
EXPECT_CALL(mock_callback, Callback(result)).Times(1);
- reporter.OnMeasurementSuccess(result.workers[0]);
- reporter.OnMeasurementSuccess(result.workers[1]);
+ reporter.OnMeasurementSuccess(
+ std::make_unique<WorkerMemoryUsage>(result.workers[0]));
+ reporter.OnMeasurementSuccess(
+ std::make_unique<WorkerMemoryUsage>(result.workers[1]));
reporter.OnTimeout();
}
diff --git a/chromium/third_party/blink/renderer/core/BUILD.gn b/chromium/third_party/blink/renderer/core/BUILD.gn
index 991cd09342e..fef22a645f6 100644
--- a/chromium/third_party/blink/renderer/core/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/BUILD.gn
@@ -24,6 +24,7 @@ import("//third_party/blink/renderer/core/context_features/build.gni")
import("//third_party/blink/renderer/core/core.gni")
import("//third_party/blink/renderer/core/css/build.gni")
import("//third_party/blink/renderer/core/display_lock/build.gni")
+import("//third_party/blink/renderer/core/document_transition/build.gni")
import("//third_party/blink/renderer/core/dom/build.gni")
import("//third_party/blink/renderer/core/editing/build.gni")
import("//third_party/blink/renderer/core/events/build.gni")
@@ -193,6 +194,9 @@ component("core") {
rebase_path(blink_core_sources_context_features, "", "context_features")
sources += rebase_path(blink_core_sources_css, "", "css")
sources += rebase_path(blink_core_sources_display_lock, "", "display_lock")
+ sources += rebase_path(blink_core_sources_document_transition,
+ "",
+ "document_transition")
sources += rebase_path(blink_core_sources_dom, "", "dom")
sources += rebase_path(blink_core_sources_editing, "", "editing")
sources += rebase_path(blink_core_sources_events, "", "events")
@@ -255,14 +259,21 @@ component("core") {
"//third_party/blink/renderer/core/exported",
"//third_party/blink/renderer/core/probe",
"//third_party/blink/renderer/core/typed_arrays",
+ "//third_party/blink/renderer/core/xml:xpath_generated",
"//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform/wtf",
+ "//ui/accessibility:ax_base",
"//ui/base/cursor:cursor_base",
+ "//ui/base/dragdrop/mojom:mojom_blink_headers",
+ "//ui/base/dragdrop/mojom:mojom_shared",
"//url",
"//v8",
]
+
deps = [
"//build:chromeos_buildflags",
"//components/paint_preview/common",
+ "//components/performance_manager/public/mojom:mojom_blink",
"//components/shared_highlighting/core/common",
"//gpu/config",
"//mojo/public/cpp/bindings:bindings",
@@ -274,16 +285,13 @@ component("core") {
"//services/service_manager/public/cpp",
"//skia",
"//skia:skcms",
+ "//storage/common",
"//third_party/blink/public:buildflags",
"//third_party/blink/public:image_resources_grit",
"//third_party/blink/public:resources",
"//third_party/blink/public/common",
"//third_party/blink/public/strings",
"//third_party/blink/renderer/core/typed_arrays:typed_arrays",
- "//third_party/blink/renderer/core/xml:xpath_generated",
- "//third_party/blink/renderer/platform",
- "//third_party/blink/renderer/platform/wtf",
- "//ui/accessibility:ax_base",
"//ui/base/cursor:cursor_base",
"//ui/base/cursor/mojom:cursor_type_blink",
"//ui/base/dragdrop/mojom:mojom_blink",
@@ -400,8 +408,11 @@ source_set("testing") {
"testing/internal_settings.h",
"testing/internals.cc",
"testing/internals.h",
+ "testing/intersection_observer_test_helper.h",
"testing/mock_clipboard_host.cc",
"testing/mock_clipboard_host.h",
+ "testing/mock_function_scope.cc",
+ "testing/mock_function_scope.h",
"testing/mock_hyphenation.cc",
"testing/mock_hyphenation.h",
"testing/mock_policy_container_host.cc",
@@ -413,6 +424,8 @@ source_set("testing") {
"testing/origin_trials_test_partial.h",
"testing/record_test.cc",
"testing/record_test.h",
+ "testing/scoped_fake_ukm_recorder.cc",
+ "testing/scoped_fake_ukm_recorder.h",
"testing/scoped_mock_overlay_scrollbars.h",
"testing/sequence_test.cc",
"testing/sequence_test.h",
@@ -923,22 +936,16 @@ blink_python_runner("make_core_generated_css_tokenizer_codepoints") {
blink_python_runner("make_core_generated_css_primitive_value_unit_trie") {
visibility = [] # Allow re-assignment of list.
visibility = [ ":*" ]
-
- # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
- script = "//build/util/python2_action.py"
+ script = "../build/scripts/core/css/make_css_primitive_value_unit_trie.py"
input_file = "css/css_primitive_value_units.json5"
inputs = make_trie_helpers_files + [
input_file,
- "../build/scripts/core/css/make_css_primitive_value_unit_trie.py",
"../build/scripts/core/css/templates/css_primitive_value_unit_trie.cc.tmpl",
]
outputs = [ "$blink_core_output_dir/css/css_primitive_value_unit_trie.cc" ]
args = [
- rebase_path(
- "../build/scripts/core/css/make_css_primitive_value_unit_trie.py",
- root_build_dir),
rebase_path(input_file, root_build_dir),
"--output_dir",
"$rel_blink_core_gen_dir/css",
@@ -1186,45 +1193,17 @@ source_set("unit_tests") {
"css/mock_css_paint_image_generator.h",
"display_lock/display_lock_context_test.cc",
"display_lock/display_lock_utilities_test.cc",
- "dom/attr_test.cc",
- "dom/document_statistics_collector_test.cc",
- "dom/document_test.cc",
- "dom/dom_node_ids_test.cc",
- "dom/element_test.cc",
- "dom/events/event_path_test.cc",
- "dom/events/event_target_test.cc",
- "dom/events/listener_leak_test.cc",
- "dom/first_letter_pseudo_element_test.cc",
- "dom/flat_tree_traversal_test.cc",
- "dom/idle_deadline_test.cc",
- "dom/layout_tree_builder_traversal_test.cc",
- "dom/live_node_list_registry_test.cc",
- "dom/mutation_observer_test.cc",
- "dom/names_map_test.cc",
- "dom/node_test.cc",
- "dom/nth_index_cache_test.cc",
- "dom/range_test.cc",
- "dom/scripted_animation_controller_test.cc",
- "dom/scripted_idle_task_controller_test.cc",
- "dom/shadow_dom_v0_test.cc",
- "dom/slot_assignment_test.cc",
- "dom/space_split_string_test.cc",
- "dom/static_range_test.cc",
- "dom/text_test.cc",
- "dom/tree_scope_adopter_test.cc",
- "dom/tree_scope_test.cc",
- "dom/weak_identifier_map_test.cc",
- "dom/whitespace_attacher_test.cc",
+ "document_transition/document_transition_test.cc",
"editing/caret_display_item_client_test.cc",
"editing/finder/text_finder_test.cc",
"editing/keyboard_test.cc",
"editing/link_selection_test.cc",
"events/message_event_test.cc",
+ "events/mouse_event_test.cc",
"events/pointer_event_factory_test.cc",
"events/pointer_event_util_test.cc",
"events/touch_event_test.cc",
"events/web_input_event_conversion_test.cc",
- "execution_context/agent_metrics_collector_test.cc",
"execution_context/execution_context_lifecycle_state_observer_test.cc",
"exported/web_document_subresource_filter_test.cc",
"exported/web_document_test.cc",
@@ -1245,6 +1224,8 @@ source_set("unit_tests") {
"exported/web_selector_test.cc",
"exported/web_view_test.cc",
"feature_policy/document_policy_parser_test.cc",
+ "feature_policy/document_policy_sim_test.cc",
+ "feature_policy/feature_policy_devtools_support_test.cc",
"feature_policy/feature_policy_test.cc",
"feature_policy/policy_test.cc",
"fetch/blob_bytes_consumer_test.cc",
@@ -1266,17 +1247,18 @@ source_set("unit_tests") {
"frame/ad_tracker_test.cc",
"frame/browser_controls_test.cc",
"frame/csp/content_security_policy_test.cc",
+ "frame/csp/conversion_util_test.cc",
"frame/csp/csp_directive_list_test.cc",
"frame/csp/csp_source_test.cc",
- "frame/csp/media_list_directive_test.cc",
"frame/csp/require_trusted_types_for_directive_test.cc",
"frame/csp/source_list_directive_test.cc",
- "frame/csp/string_list_directive_test.cc",
+ "frame/csp/trusted_types_directive_test.cc",
"frame/deprecation_report_body_test.cc",
"frame/document_loading_rendering_test.cc",
"frame/document_policy_violation_report_body_test.cc",
"frame/dom_timer_test.cc",
"frame/find_in_page_test.cc",
+ "frame/frame_content_as_text_test.cc",
"frame/frame_overlay_test.cc",
"frame/frame_serializer_test.cc",
"frame/frame_test.cc",
@@ -1311,8 +1293,10 @@ source_set("unit_tests") {
"input/scroll_snap_test.cc",
"input/touch_action_test.cc",
"input/touch_event_manager_test.cc",
+ "inspector/inspector_contrast_test.cc",
"inspector/inspector_emulation_agent_test.cc",
"inspector/inspector_history_test.cc",
+ "inspector/inspector_media_context_impl_unittest.cc",
"inspector/inspector_session_state_test.cc",
"inspector/inspector_style_resolver_test.cc",
"inspector/main_thread_debugger_test.cc",
@@ -1322,6 +1306,7 @@ source_set("unit_tests") {
"layout/api/selection_state_test.cc",
"layout/collapsed_border_value_test.cc",
"layout/force_legacy_layout_test.cc",
+ "layout/geometry/axis_test.cc",
"layout/geometry/logical_rect_test.cc",
"layout/geometry/physical_rect_test.cc",
"layout/geometry/physical_size_test.cc",
@@ -1337,6 +1322,7 @@ source_set("unit_tests") {
"layout/layout_grid_test.cc",
"layout/layout_image_test.cc",
"layout/layout_inline_test.cc",
+ "layout/layout_list_marker_test.cc",
"layout/layout_media_test.cc",
"layout/layout_multi_column_flow_thread_test.cc",
"layout/layout_object_test.cc",
@@ -1359,6 +1345,7 @@ source_set("unit_tests") {
"layout/line/abstract_inline_text_box_test.cc",
"layout/line/inline_text_box_test.cc",
"layout/line/line_orientation_utils_test.cc",
+ "layout/list_marker_test.cc",
"layout/map_coordinates_test.cc",
"layout/min_max_size_test.cc",
"layout/multi_column_fragmentainer_group_test.cc",
@@ -1376,14 +1363,12 @@ source_set("unit_tests") {
"layout/ng/inline/ng_fragment_items_builder_test.cc",
"layout/ng/inline/ng_fragment_items_test.cc",
"layout/ng/inline/ng_inline_cursor_test.cc",
- "layout/ng/inline/ng_inline_fragment_traversal_test.cc",
"layout/ng/inline/ng_inline_items_builder_test.cc",
"layout/ng/inline/ng_inline_layout_algorithm_test.cc",
"layout/ng/inline/ng_inline_node_test.cc",
"layout/ng/inline/ng_line_breaker_test.cc",
"layout/ng/inline/ng_offset_mapping_test.cc",
"layout/ng/inline/ng_physical_line_box_fragment_test.cc",
- "layout/ng/inline/ng_physical_text_fragment_test.cc",
"layout/ng/list/layout_ng_list_item_test.cc",
"layout/ng/ng_absolute_utils_test.cc",
"layout/ng/ng_base_layout_algorithm_test.cc",
@@ -1404,7 +1389,9 @@ source_set("unit_tests") {
"layout/ng/ng_length_utils_test.cc",
"layout/ng/ng_out_of_flow_layout_part_test.cc",
"layout/ng/ng_physical_box_fragment_test.cc",
+ "layout/ng/ng_physical_fragment_test.cc",
"layout/ng/ng_relative_utils_test.cc",
+ "layout/ng/table/ng_table_layout_algorithm_helpers_test.cc",
"layout/overflow_model_test.cc",
"layout/paint_containment_test.cc",
"layout/scroll_anchor_test.cc",
@@ -1438,7 +1425,6 @@ source_set("unit_tests") {
"loader/navigation_policy_test.cc",
"loader/ping_loader_test.cc",
"loader/prerender_test.cc",
- "loader/previews_resource_loading_hints_test.cc",
"loader/programmatic_scroll_test.cc",
"loader/progress_tracker_test.cc",
"loader/resource/css_style_sheet_resource_test.cc",
@@ -1449,6 +1435,7 @@ source_set("unit_tests") {
"loader/resource/mock_image_resource_observer.cc",
"loader/resource/mock_image_resource_observer.h",
"loader/resource/multipart_image_resource_parser_test.cc",
+ "loader/resource/script_resource_test.cc",
"loader/resource_load_observer_for_frame_test.cc",
"loader/threadable_loader_test.cc",
"loader/threaded_icon_loader_test.cc",
@@ -1479,6 +1466,7 @@ source_set("unit_tests") {
"page/scrolling/snap_coordinator_test.cc",
"page/scrolling/text_fragment_anchor_metrics_test.cc",
"page/scrolling/text_fragment_anchor_test.cc",
+ "page/scrolling/text_fragment_finder_test.cc",
"page/scrolling/text_fragment_selector_generator_test.cc",
"page/scrolling/text_fragment_selector_test.cc",
"page/slot_scoped_traversal_test.cc",
@@ -1511,8 +1499,6 @@ source_set("unit_tests") {
"paint/largest_contentful_paint_calculator_test.cc",
"paint/link_highlight_impl_test.cc",
"paint/ng/ng_box_fragment_painter_test.cc",
- "paint/ng/ng_paint_fragment_test.cc",
- "paint/ng/ng_paint_fragment_traversal_test.cc",
"paint/ng/ng_text_fragment_painter_test.cc",
"paint/nine_piece_image_grid_test.cc",
"paint/object_paint_invalidator_test.cc",
@@ -1564,10 +1550,10 @@ source_set("unit_tests") {
"svg/animation/smil_time_container_test.cc",
"svg/animation/svg_smil_element_test.cc",
"svg/graphics/svg_image_test.cc",
- "svg/svg_external_document_cache_test.cc",
"svg/svg_foreign_object_element_test.cc",
"svg/svg_path_parser_test.cc",
"svg/svg_path_query_test.cc",
+ "svg/svg_resource_document_content_test.cc",
"svg/svg_text_content_element_test.cc",
"svg/svg_use_element_test.cc",
"svg/unsafe_svg_attribute_sanitization_test.cc",
@@ -1595,13 +1581,14 @@ source_set("unit_tests") {
"xml/xpath_functions_test.cc",
]
- # If you create a new subdirectory 'foo' that contains unit tets, list them in
+ # If you create a new subdirectory 'foo' that contains unit tests, list them in
# 'foo/build.gni' to define blink_core_tests_foo, and add any dependencies in
# the deps section below.
sources += rebase_path(blink_core_tests_accessibility, "", "accessibility")
sources += rebase_path(blink_core_tests_animation, "", "animation")
sources += rebase_path(blink_core_tests_clipboard, "", "clipboard")
sources += rebase_path(blink_core_tests_css, "", "css")
+ sources += rebase_path(blink_core_tests_dom, "", "dom")
sources += rebase_path(blink_core_tests_editing, "", "editing")
sources += rebase_path(blink_core_tests_fileapi, "", "fileapi")
sources += rebase_path(blink_core_tests_html, "", "html")
@@ -1643,16 +1630,11 @@ source_set("unit_tests") {
"//ui/accessibility:ax_base",
"//ui/base/cursor:cursor_base",
"//ui/base/cursor/mojom:cursor_type_blink",
+ "//ui/base/dragdrop/mojom:mojom_blink",
]
data_deps = [ ":unit_tests_data" ]
- # FIXME: Enable mojo unittests on Android after fixing data dependency.
- # crbug.com/741925
- if (!is_android) {
- deps += [ "//third_party/blink/renderer/core/mojo:unit_tests" ]
- }
-
if (!is_mac) {
sources += [
"scroll/scroll_animator_test.cc",
@@ -1691,7 +1673,10 @@ group("js_files_for_form_controls_web_tests") {
source_set("perf_tests") {
testonly = true
- sources = [ "layout/visual_rect_mapping_perftest.cc" ]
+ sources = [
+ "layout/svg/svg_hit_test_perftest.cc",
+ "layout/visual_rect_mapping_perftest.cc",
+ ]
configs += [
":blink_core_pch",
@@ -1716,6 +1701,7 @@ source_set("unit_test_support") {
"frame/frame_test_helpers.h",
"html/media/html_media_test_helper.cc",
"html/media/html_media_test_helper.h",
+ "mobile_metrics/mobile_metrics_test_helpers.h",
"script/mock_script_element_base.h",
"testing/core_unit_test_helper.cc",
"testing/core_unit_test_helper.h",
@@ -1739,6 +1725,8 @@ source_set("unit_test_support") {
"testing/sim/sim_request.h",
"testing/sim/sim_test.cc",
"testing/sim/sim_test.h",
+ "testing/sim/sim_web_frame_widget.cc",
+ "testing/sim/sim_web_frame_widget.h",
"workers/worker_thread_test_helper.h",
]
@@ -1806,6 +1794,17 @@ fuzzer_test("content_security_policy_fuzzer") {
seed_corpus = "//testing/libfuzzer/fuzzers/content_security_policy_corpus"
}
+fuzzer_test("content_security_policy_conversion_util_fuzzer") {
+ sources = [ "frame/csp/conversion_util_fuzzer.cc" ]
+ deps = [
+ ":core",
+ "//third_party/blink/renderer/core:testing",
+ "//third_party/blink/renderer/platform:blink_fuzzer_test_support",
+ ]
+ dict = "//testing/libfuzzer/fuzzers/dicts/content_security_policy.dict"
+ seed_corpus = "//testing/libfuzzer/fuzzers/content_security_policy_corpus"
+}
+
fuzzer_test("css_parser_proto_fuzzer") {
sources = [
"css/parser/css_parser_proto_fuzzer.cc",
diff --git a/chromium/third_party/blink/renderer/core/DEPS b/chromium/third_party/blink/renderer/core/DEPS
index c1d86ea88d1..c1ed3d8ea87 100644
--- a/chromium/third_party/blink/renderer/core/DEPS
+++ b/chromium/third_party/blink/renderer/core/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"+base/bits.h",
"+base/cancelable_callback.h",
"+base/files/file.h",
+ "+base/i18n/uchar.h",
"+base/mac/foundation_util.h",
"+base/mac/mac_util.h",
"+base/mac/scoped_cftyperef.h",
@@ -23,7 +24,7 @@ include_rules = [
"+base/unguessable_token.h",
"+build/mac",
"+build/win",
- "+cc/animation/animation_curve.h",
+ "+ui/gfx/animation/keyframe/animation_curve.h",
"+cc/animation/animation_host.h",
"+cc/animation/scroll_offset_animations.h",
"+cc/animation/scroll_offset_animation_curve.h",
@@ -76,6 +77,7 @@ include_rules = [
"+services/network/public/cpp/cors/cors_error_status.h",
"+services/network/public/cpp/features.h",
"+services/network/public/cpp/ip_address_space_util.h",
+ "+services/network/public/cpp/is_potentially_trustworthy.h",
"+services/network/public/cpp/request_destination.h",
"+services/network/public/cpp/request_mode.h",
"+services/network/public/cpp/web_sandbox_flags.h",
@@ -85,6 +87,7 @@ include_rules = [
"+skia/public/mojom",
"+skia/ext/image_operations.h",
"+skia/ext/legacy_display_globals.h",
+ "+skia/ext/skia_utils_base.h",
"+skia/ext/skia_utils_mac.h",
"+third_party/blink/public/common",
"+third_party/blink/public/mojom",
@@ -126,6 +129,7 @@ include_rules = [
specific_include_rules = {
# Additional allowed includes for tests.
".*_test(_.*)?\.(cc|h|mm)" : [
+ "+base/timer/lap_timer.h",
"+base/message_loop/message_loop.h",
"+base/test/test_mock_time_task_runner.h",
# Test harness may use cc directly instead of going through WebViewImpl etc.
@@ -136,6 +140,7 @@ specific_include_rules = {
# that the Web abstraction can go away.
"+content/renderer/compositor",
"+content/test",
+ "+testing/perf/perf_result_reporter.h",
"+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
"+third_party/blink/renderer/core/frame/web_remote_frame_impl.h",
"+gin",
@@ -143,6 +148,7 @@ specific_include_rules = {
],
"data_object_item.cc" : [ "+ui/gfx/codec" ],
"chrome_client.h" : [
+ "+components/viz/common/delegated_ink_metadata.h",
"+components/viz/common/surfaces/frame_sink_id.h",
],
"clipboard_utilities.cc" : [ "+net/base/escape.h" ],
@@ -152,10 +158,6 @@ specific_include_rules = {
"find_task_controller.cc" : [
"+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
],
- # TODO(darin): Remove once onion-souping is complete for prerendering.
- "prerenderer_client.cc" : [
- "+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
- ],
"html_media_element_test.cc": [
"+base/test/gtest_util.h",
],
diff --git a/chromium/third_party/blink/renderer/core/DIR_METADATA b/chromium/third_party/blink/renderer/core/DIR_METADATA
new file mode 100644
index 00000000000..fca4a1fc814
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink"
+}
+
+team_email: "blink-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/OWNERS b/chromium/third_party/blink/renderer/core/OWNERS
index b3dab08db5b..393b9d2952c 100644
--- a/chromium/third_party/blink/renderer/core/OWNERS
+++ b/chromium/third_party/blink/renderer/core/OWNERS
@@ -1,6 +1,11 @@
# Please prefer to use more specific OWNERS if possible.
# For example, core/rendering/OWNERS for rendering changes.
+# New owners should be proposed by email to blink-core-owners-discuss@chromium.org,
+# similar to the committer nomination process.
+# Once accepted, new owners should also be added to blink-core-owners-discuss@chromium.org.
+# https://groups.google.com/a/chromium.org/g/blink-core-owners-discuss
+
# Reviewers (comments indicate areas of expertise):
alexis.menard@intel.com
# bokan reviews changes around viewport behavior, scrolling, cc/blink interaction, co-ordinate spaces and input events
@@ -9,13 +14,13 @@ cbiesinger@chromium.org
chrishtr@chromium.org
clamy@chromium.org
dcheng@chromium.org
-# dtapuska reviews input-related changes
-dtapuska@chromium.org
dgozman@chromium.org
# drott reviews font specific changes.
drott@chromium.org
dsinclair@chromium.org
dstockwell@chromium.org
+# dtapuska reviews input-related changes
+dtapuska@chromium.org
enne@chromium.org
# flackr reviews animation- and scrolling-related changes.
flackr@chromium.org
@@ -25,12 +30,14 @@ foolip@chromium.org
fs@opera.com
fserb@chromium.org
futhark@chromium.org
+fwang@igalia.com
haraken@chromium.org
hayato@chromium.org
hiroshige@chromium.org
ikilpatrick@chromium.org
inferno@chromium.org
japhet@chromium.org
+jarhar@chromium.org
jbroman@chromium.org
jfernandez@igalia.com
jianli@chromium.org
@@ -44,9 +51,6 @@ kouhei@chromium.org
masonfreed@chromium.org
mkwst@chromium.org
mstensho@chromium.org
-# nainar reviews changes in core/css,core/style
-# and related code in core/dom and core/layout.
-nainar@chromium.org
nhiroki@chromium.org
obrufau@igalia.com
# pdr reviews many svg and text autosizing patches.
@@ -65,13 +69,9 @@ szager@chromium.org
thakis@chromium.org
timloh@chromium.org
tkent@chromium.org
-tonyg@chromium.org
vmpstr@chromium.org
vollick@chromium.org
wangxianzhu@chromium.org
yhirano@chromium.org
yoavweiss@chromium.org
yutak@chromium.org
-
-# TEAM: blink-dev@chromium.org
-# COMPONENT: Blink
diff --git a/chromium/third_party/blink/renderer/core/accessibility/DIR_METADATA b/chromium/third_party/blink/renderer/core/accessibility/DIR_METADATA
new file mode 100644
index 00000000000..7a89266091b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/accessibility/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Accessibility"
+}
+
+team_email: "chromium-accessibility@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/accessibility/OWNERS b/chromium/third_party/blink/renderer/core/accessibility/OWNERS
index 5eed66eb588..4e6cc130180 100644
--- a/chromium/third_party/blink/renderer/core/accessibility/OWNERS
+++ b/chromium/third_party/blink/renderer/core/accessibility/OWNERS
@@ -1,4 +1 @@
file://third_party/blink/renderer/modules/accessibility/OWNERS
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: Blink>Accessibility
diff --git a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
index f3e09384d83..c67098b16b4 100644
--- a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
+++ b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache.h
@@ -45,7 +45,6 @@ class HTMLFrameOwnerElement;
class HTMLSelectElement;
class IntPoint;
class LayoutRect;
-class LineLayoutItem;
class LocalFrameView;
class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
@@ -63,6 +62,12 @@ class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
virtual void Dispose() = 0;
+ // A Freeze() occurs during a serialization run.
+ // Used here as a hint for DCHECKS to enforce the following behavior:
+ // objects in the ax hierarchy should not be destroyed during serialization.
+ virtual void Freeze() = 0;
+ virtual void Thaw() = 0;
+
// Register/remove popups
virtual void InitializePopup(Document* document) = 0;
virtual void DisposePopup(Document* document) = 0;
@@ -76,7 +81,6 @@ class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
virtual void ListboxSelectedChildrenChanged(HTMLSelectElement*) = 0;
virtual void ListboxActiveIndexChanged(HTMLSelectElement*) = 0;
virtual void LocationChanged(const LayoutObject*) = 0;
- virtual void RadiobuttonRemovedFromGroup(HTMLInputElement*) = 0;
virtual void ImageLoaded(const LayoutObject*) = 0;
virtual void Remove(AccessibleNode*) = 0;
@@ -139,7 +143,7 @@ class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
Element*,
const LayoutRect&) = 0;
- virtual void InlineTextBoxesUpdated(LineLayoutItem) = 0;
+ virtual void InlineTextBoxesUpdated(LayoutObject*) = 0;
// Called when the scroll offset changes.
virtual void HandleScrollPositionChanged(LocalFrameView*) = 0;
diff --git a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h
index d3290f14ed1..1ea08910d80 100644
--- a/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h
+++ b/chromium/third_party/blink/renderer/core/accessibility/ax_object_cache_base.h
@@ -28,7 +28,8 @@ class CORE_EXPORT AXObjectCacheBase : public AXObjectCache {
~AXObjectCacheBase() override = default;
virtual AXObject* Get(const Node*) = 0;
- virtual AXObject* GetOrCreate(LayoutObject*) = 0;
+ virtual AXObject* GetOrCreate(LayoutObject*,
+ AXObject* parent_if_known = nullptr) = 0;
protected:
AXObjectCacheBase() = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/BUILD.gn b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
index a690dc32877..efc1cfc7c81 100644
--- a/chromium/third_party/blink/renderer/core/animation/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/animation/BUILD.gn
@@ -72,6 +72,8 @@ blink_core_sources("animation") {
"css/css_transition_data.h",
"css_angle_interpolation_type.cc",
"css_angle_interpolation_type.h",
+ "css_aspect_ratio_interpolation_type.cc",
+ "css_aspect_ratio_interpolation_type.h",
"css_basic_shape_interpolation_type.cc",
"css_basic_shape_interpolation_type.h",
"css_border_image_length_box_interpolation_type.cc",
@@ -168,6 +170,8 @@ blink_core_sources("animation") {
"image_slice_property_functions.h",
"inert_effect.cc",
"inert_effect.h",
+ "interpolable_aspect_ratio.cc",
+ "interpolable_aspect_ratio.h",
"interpolable_filter.cc",
"interpolable_filter.h",
"interpolable_length.cc",
diff --git a/chromium/third_party/blink/renderer/core/animation/DIR_METADATA b/chromium/third_party/blink/renderer/core/animation/DIR_METADATA
new file mode 100644
index 00000000000..072e8c98258
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Animation"
+}
+
+team_email: "animations-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/animation/OWNERS b/chromium/third_party/blink/renderer/core/animation/OWNERS
index ef3593179c5..e7571208635 100644
--- a/chromium/third_party/blink/renderer/core/animation/OWNERS
+++ b/chromium/third_party/blink/renderer/core/animation/OWNERS
@@ -8,6 +8,3 @@ alancutter@chromium.org
ericwilligers@chromium.org
per-file compositor_*=loyso@chromium.org
-
-# TEAM: animations-dev@chromium.org
-# COMPONENT: Blink>Animation
diff --git a/chromium/third_party/blink/renderer/core/animation/animatable.cc b/chromium/third_party/blink/renderer/core/animation/animatable.cc
index 01fee49eac1..bb64f4e2334 100644
--- a/chromium/third_party/blink/renderer/core/animation/animatable.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animatable.cc
@@ -73,6 +73,11 @@ Animation* Animatable::animate(
if (exception_state.HadException())
return nullptr;
+ // Creation of the keyframe effect parses JavaScript, which could result
+ // in destruction of the execution context. Recheck that it is still valid.
+ if (!element->GetExecutionContext())
+ return nullptr;
+
ReportFeaturePolicyViolationsIfNecessary(*element->GetExecutionContext(),
*effect->Model());
if (!options.IsKeyframeAnimationOptions())
@@ -90,6 +95,9 @@ Animation* Animatable::animate(
nullptr, exception_state);
}
+ if (!animation)
+ return nullptr;
+
animation->setId(options_dict->id());
return animation;
}
@@ -107,6 +115,11 @@ Animation* Animatable::animate(ScriptState* script_state,
if (exception_state.HadException())
return nullptr;
+ // Creation of the keyframe effect parses JavaScript, which could result
+ // in destruction of the execution context. Recheck that it is still valid.
+ if (!element->GetExecutionContext())
+ return nullptr;
+
ReportFeaturePolicyViolationsIfNecessary(*element->GetExecutionContext(),
*effect->Model());
return element->GetDocument().Timeline().Play(effect);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.cc b/chromium/third_party/blink/renderer/core/animation/animation.cc
index 3cd250acb32..5bededa4316 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation.cc
@@ -53,6 +53,8 @@
#include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/events/animation_playback_event.h"
@@ -83,26 +85,6 @@ unsigned NextSequenceNumber() {
return ++next;
}
-double SecondsToMilliseconds(double seconds) {
- return seconds * 1000;
-}
-
-double MillisecondsToSeconds(double milliseconds) {
- return milliseconds / 1000;
-}
-
-double Max(base::Optional<double> a, double b) {
- if (a.has_value())
- return std::max(a.value(), b);
- return b;
-}
-
-double Min(base::Optional<double> a, double b) {
- if (a.has_value())
- return std::min(a.value(), b);
- return b;
-}
-
PseudoPriority ConvertPseudoIdtoPriority(const PseudoId& pseudo) {
if (pseudo == kPseudoIdNone)
return PseudoPriority::kNone;
@@ -180,6 +162,16 @@ AtomicString GetCSSTransitionCSSPropertyName(const Animation* animation) {
->TransitionCSSPropertyName()
.ToAtomicString();
}
+
+bool GreaterThanOrEqualWithinTimeTolerance(const AnimationTimeDelta& a,
+ const AnimationTimeDelta& b) {
+ double a_ms = a.InMillisecondsF();
+ double b_ms = b.InMillisecondsF();
+ if (std::abs(a_ms - b_ms) < Animation::kTimeToleranceMs)
+ return true;
+
+ return a_ms > b_ms;
+}
} // namespace
Animation* Animation::Create(AnimationEffect* effect,
@@ -294,13 +286,21 @@ void Animation::Dispose() {
DCHECK(!compositor_animation_);
}
-double Animation::EffectEnd() const {
- return content_ ? content_->SpecifiedTiming().EndTimeInternal() : 0;
+AnimationTimeDelta Animation::EffectEnd() const {
+ return content_ ? AnimationTimeDelta::FromSecondsD(
+ content_->SpecifiedTiming().EndTimeInternal())
+ : AnimationTimeDelta();
}
-bool Animation::Limited(base::Optional<double> current_time) const {
- return (EffectivePlaybackRate() < 0 && current_time <= 0) ||
- (EffectivePlaybackRate() > 0 && current_time >= EffectEnd());
+bool Animation::Limited(base::Optional<AnimationTimeDelta> current_time) const {
+ if (!current_time)
+ return false;
+
+ return (EffectivePlaybackRate() < 0 &&
+ current_time <= AnimationTimeDelta()) ||
+ (EffectivePlaybackRate() > 0 &&
+ GreaterThanOrEqualWithinTimeTolerance(current_time.value(),
+ EffectEnd()));
}
Document* Animation::GetDocument() const {
@@ -312,9 +312,9 @@ base::Optional<double> Animation::TimelineTime() const {
}
// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation.
-void Animation::setCurrentTime(base::Optional<double> new_current_time,
+void Animation::setCurrentTime(CSSNumberish current_time,
ExceptionState& exception_state) {
- if (!new_current_time) {
+ if (current_time.IsNull()) {
// If the current time is resolved, then throw a TypeError.
if (CurrentTimeInternal()) {
exception_state.ThrowTypeError(
@@ -323,12 +323,25 @@ void Animation::setCurrentTime(base::Optional<double> new_current_time,
return;
}
- SetCurrentTimeInternal(MillisecondsToSeconds(new_current_time.value()));
+ if (current_time.IsCSSNumericValue()) {
+ // Throw exception for CSSNumberish that is a CSSNumericValue
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Invalid startTime. CSSNumericValue not yet supported.");
+ return;
+ }
+
+ DCHECK(current_time.IsDouble());
+ // Convert from double to AnimationTimeDelta for internal use.
+ base::Optional<AnimationTimeDelta> new_current_time =
+ AnimationTimeDelta::FromMillisecondsD(current_time.GetAsDouble());
+
+ DCHECK(new_current_time);
+ SetCurrentTimeInternal(new_current_time.value());
// Synchronously resolve pending pause task.
if (pending_pause_) {
- SetHoldTimeAndPhase(MillisecondsToSeconds(new_current_time.value()),
- TimelinePhase::kActive);
+ SetHoldTimeAndPhase(new_current_time, TimelinePhase::kActive);
ApplyPendingPlaybackRate();
start_time_ = base::nullopt;
pending_pause_ = false;
@@ -345,19 +358,17 @@ void Animation::setCurrentTime(base::Optional<double> new_current_time,
NotifyProbe();
}
-void Animation::setCurrentTime(base::Optional<double> new_current_time) {
+void Animation::setCurrentTime(CSSNumberish current_time) {
NonThrowableExceptionState exception_state;
- setCurrentTime(new_current_time, exception_state);
+ setCurrentTime(current_time, exception_state);
}
// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation
// See steps for silently setting the current time. The preliminary step of
// handling an unresolved time are to be handled by the caller.
-void Animation::SetCurrentTimeInternal(double new_current_time) {
- DCHECK(std::isfinite(new_current_time));
-
- base::Optional<double> previous_start_time = start_time_;
- base::Optional<double> previous_hold_time = hold_time_;
+void Animation::SetCurrentTimeInternal(AnimationTimeDelta new_current_time) {
+ base::Optional<AnimationTimeDelta> previous_start_time = start_time_;
+ base::Optional<AnimationTimeDelta> previous_hold_time = hold_time_;
base::Optional<TimelinePhase> previous_hold_phase = hold_phase_;
// Update either the hold time or the start time.
@@ -383,11 +394,8 @@ void Animation::SetCurrentTimeInternal(double new_current_time) {
}
void Animation::SetHoldTimeAndPhase(
- base::Optional<double> new_hold_time /* in seconds */,
+ base::Optional<AnimationTimeDelta> new_hold_time,
TimelinePhase new_hold_phase) {
- // new_hold_time must be valid, unless new_hold_phase is inactive.
- DCHECK(new_hold_time ||
- (!new_hold_time && new_hold_phase == TimelinePhase::kInactive));
hold_time_ = new_hold_time;
hold_phase_ = new_hold_phase;
}
@@ -397,18 +405,22 @@ void Animation::ResetHoldTimeAndPhase() {
hold_phase_ = base::nullopt;
}
-base::Optional<double> Animation::startTime() const {
- return start_time_
- ? base::make_optional(SecondsToMilliseconds(start_time_.value()))
- : base::nullopt;
+void Animation::startTime(CSSNumberish& startTime) const {
+ startTime =
+ start_time_
+ ? CSSNumberish::FromDouble(start_time_.value().InMillisecondsF())
+ : CSSNumberish();
}
// https://drafts.csswg.org/web-animations/#the-current-time-of-an-animation
-base::Optional<double> Animation::currentTime() const {
+void Animation::currentTime(CSSNumberish& currentTime) const {
// 1. If the animation’s hold time is resolved,
// The current time is the animation’s hold time.
- if (hold_time_.has_value())
- return SecondsToMilliseconds(hold_time_.value());
+ if (hold_time_.has_value()) {
+ currentTime =
+ CSSNumberish::FromDouble(hold_time_.value().InMillisecondsF());
+ return;
+ }
// 2. If any of the following are true:
// * the animation has no associated timeline, or
@@ -416,28 +428,30 @@ base::Optional<double> Animation::currentTime() const {
// * the animation’s start time is unresolved.
// The current time is an unresolved time value.
if (!timeline_ || !timeline_->IsActive() || !start_time_)
- return base::nullopt;
+ return;
// 3. Otherwise,
// current time = (timeline time - start time) × playback rate
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
// An active timeline should always have a value, and since inactive timeline
// is handled in step 2 above, make sure that timeline_time has a value.
DCHECK(timeline_time.has_value());
- double current_time =
+ AnimationTimeDelta calculated_current_time =
(timeline_time.value() - start_time_.value()) * playback_rate_;
- return SecondsToMilliseconds(current_time);
+
+ currentTime =
+ CSSNumberish::FromDouble(calculated_current_time.InMillisecondsF());
}
bool Animation::ValidateHoldTimeAndPhase() const {
- return (hold_phase_ && hold_time_) ||
+ return hold_phase_ ||
((!hold_phase_ || hold_phase_ == TimelinePhase::kInactive) &&
!hold_time_);
}
-base::Optional<double> Animation::CurrentTimeInternal() const {
+base::Optional<AnimationTimeDelta> Animation::CurrentTimeInternal() const {
DCHECK(ValidateHoldTimeAndPhase());
return hold_time_ ? hold_time_ : CalculateCurrentTime();
}
@@ -447,7 +461,7 @@ TimelinePhase Animation::CurrentPhaseInternal() const {
return hold_phase_ ? hold_phase_.value() : CalculateCurrentPhase();
}
-base::Optional<double> Animation::UnlimitedCurrentTime() const {
+base::Optional<AnimationTimeDelta> Animation::UnlimitedCurrentTime() const {
return CalculateAnimationPlayState() == kPaused || !start_time_
? CurrentTimeInternal()
: CalculateCurrentTime();
@@ -466,9 +480,11 @@ bool Animation::PreCommit(
compositor_state_ &&
(Paused() || compositor_state_->playback_rate != EffectivePlaybackRate());
bool hard_change =
- compositor_state_ && (compositor_state_->effect_changed ||
- compositor_state_->start_time != start_time_ ||
- !compositor_state_->start_time || !start_time_);
+ compositor_state_ &&
+ (compositor_state_->effect_changed || !compositor_state_->start_time ||
+ !start_time_ ||
+ !IsWithinAnimationTimeEpsilon(compositor_state_->start_time.value(),
+ start_time_.value().InSecondsF()));
// FIXME: softChange && !hardChange should generate a Pause/ThenStart,
// not a Cancel, but we can't communicate these to the compositor yet.
@@ -526,7 +542,8 @@ void Animation::PostCommit() {
DCHECK_EQ(kStart, compositor_state_->pending_action);
if (compositor_state_->start_time) {
- DCHECK_EQ(start_time_.value(), compositor_state_->start_time.value());
+ DCHECK(IsWithinAnimationTimeEpsilon(start_time_.value().InSecondsF(),
+ compositor_state_->start_time.value()));
compositor_state_->pending_action = kNone;
}
}
@@ -621,7 +638,7 @@ bool Animation::HasLowerCompositeOrdering(
return animation1->SequenceNumber() < animation2->SequenceNumber();
}
-void Animation::NotifyReady(double ready_time) {
+void Animation::NotifyReady(AnimationTimeDelta ready_time) {
// Complete the pending updates prior to updating the compositor state in
// order to ensure a correct start time for the compositor state without the
// need to duplicate the calculations.
@@ -633,7 +650,9 @@ void Animation::NotifyReady(double ready_time) {
if (compositor_state_ && compositor_state_->pending_action == kStart) {
DCHECK(!compositor_state_->start_time);
compositor_state_->pending_action = kNone;
- compositor_state_->start_time = start_time_;
+ compositor_state_->start_time =
+ start_time_ ? base::make_optional(start_time_.value().InSecondsF())
+ : base::nullopt;
}
// Notify of change to play state.
@@ -643,8 +662,7 @@ void Animation::NotifyReady(double ready_time) {
// Microtask for playing an animation.
// Refer to Step 8.3 'pending play task' in
// https://drafts.csswg.org/web-animations/#playing-an-animation-section.
-void Animation::CommitPendingPlay(double ready_time) {
- DCHECK(std::isfinite(ready_time));
+void Animation::CommitPendingPlay(AnimationTimeDelta ready_time) {
DCHECK(start_time_ || hold_time_);
DCHECK(pending_play_);
pending_play_ = false;
@@ -680,7 +698,7 @@ void Animation::CommitPendingPlay(double ready_time) {
// If the playback rate is zero, let new start time be simply ready
// time.
// B.5 Set the start time of animation to new start time.
- double current_time_to_match =
+ AnimationTimeDelta current_time_to_match =
(ready_time - start_time_.value()) * playback_rate_;
ApplyPendingPlaybackRate();
if (playback_rate_ == 0) {
@@ -705,7 +723,7 @@ void Animation::CommitPendingPlay(double ready_time) {
// Microtask for pausing an animation.
// Refer to step 7 'pending pause task' in
// https://drafts.csswg.org/web-animations-1/#pausing-an-animation-section
-void Animation::CommitPendingPause(double ready_time) {
+void Animation::CommitPendingPause(AnimationTimeDelta ready_time) {
DCHECK(pending_pause_);
pending_pause_ = false;
@@ -769,7 +787,7 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
UpdateIfNecessary();
AnimationPlayState old_play_state = CalculateAnimationPlayState();
- base::Optional<double> old_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> old_current_time = CurrentTimeInternal();
CancelAnimationOnCompositor();
@@ -795,7 +813,8 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
if (timeline) {
if (!timeline->IsMonotonicallyIncreasing()) {
ApplyPendingPlaybackRate();
- double boundary_time = (playback_rate_ > 0) ? 0 : EffectEnd();
+ AnimationTimeDelta boundary_time =
+ (playback_rate_ > 0) ? AnimationTimeDelta() : EffectEnd();
switch (old_play_state) {
case kIdle:
break;
@@ -851,11 +870,11 @@ void Animation::setTimeline(AnimationTimeline* timeline) {
NotifyProbe();
}
-base::Optional<double> Animation::CalculateStartTime(
- double current_time) const {
- base::Optional<double> start_time;
+base::Optional<AnimationTimeDelta> Animation::CalculateStartTime(
+ AnimationTimeDelta current_time) const {
+ base::Optional<AnimationTimeDelta> start_time;
if (timeline_) {
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
if (timeline_time)
start_time = timeline_time.value() - current_time / playback_rate_;
// TODO(crbug.com/916117): Handle NaN time for scroll-linked animations.
@@ -864,16 +883,13 @@ base::Optional<double> Animation::CalculateStartTime(
return start_time;
}
-base::Optional<double> Animation::CalculateCurrentTime() const {
+base::Optional<AnimationTimeDelta> Animation::CalculateCurrentTime() const {
if (!start_time_ || !timeline_ || !timeline_->IsActive())
return base::nullopt;
- base::Optional<double> timeline_time = timeline_->CurrentTimeSeconds();
- if (!timeline_time) {
- // timeline_time can be null only when the timeline is inactive
- DCHECK(!timeline_->IsActive());
- return base::nullopt;
- }
+ base::Optional<AnimationTimeDelta> timeline_time = timeline_->CurrentTime();
+ // timeline_ must be active here, make sure it is returning a current_time.
+ DCHECK(timeline_time);
return (timeline_time.value() - start_time_.value()) * playback_rate_;
}
@@ -885,42 +901,56 @@ TimelinePhase Animation::CalculateCurrentPhase() const {
}
// https://drafts.csswg.org/web-animations/#setting-the-start-time-of-an-animation
-void Animation::setStartTime(base::Optional<double> start_time_ms,
+void Animation::setStartTime(CSSNumberish start_time,
ExceptionState& exception_state) {
+ if (!start_time.IsNull() && start_time.IsCSSNumericValue()) {
+ // Throw exception for CSSNumberish that is a CSSNumericValue
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Invalid startTime. CSSNumericValue not yet supported.");
+ return;
+ }
+
+ base::Optional<AnimationTimeDelta> new_start_time =
+ !start_time.IsNull()
+ ? base::make_optional(
+ AnimationTimeDelta::FromMillisecondsD(start_time.GetAsDouble()))
+ : base::nullopt;
+
bool had_start_time = start_time_.has_value();
// 1. Let timeline time be the current time value of the timeline that
// animation is associated with. If there is no timeline associated with
// animation or the associated timeline is inactive, let the timeline time
// be unresolved.
- base::Optional<double> timeline_time = timeline_ && timeline_->IsActive()
- ? timeline_->CurrentTimeSeconds()
- : base::nullopt;
+ base::Optional<AnimationTimeDelta> timeline_time =
+ timeline_ && timeline_->IsActive() ? timeline_->CurrentTime()
+ : base::nullopt;
// 2. If timeline time is unresolved and new start time is resolved, make
// animation’s hold time unresolved.
// This preserves the invariant that when we don’t have an active timeline it
// is only possible to set either the start time or the animation’s current
// time.
- if (!timeline_time && start_time_ms) {
+ if (!timeline_time && new_start_time) {
ResetHoldTimeAndPhase();
}
// 3. Let previous current time be animation’s current time.
- base::Optional<double> previous_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> previous_current_time =
+ CurrentTimeInternal();
TimelinePhase previous_current_phase = CurrentPhaseInternal();
// 4. Apply any pending playback rate on animation.
ApplyPendingPlaybackRate();
// 5. Set animation’s start time to new start time.
- base::Optional<double> new_start_time;
- if (start_time_ms) {
- new_start_time = MillisecondsToSeconds(start_time_ms.value());
+ if (new_start_time) {
// Snap to timeline time if within floating point tolerance to ensure
// deterministic behavior in phase transitions.
- if (timeline_time && IsWithinAnimationTimeEpsilon(timeline_time.value(),
- new_start_time.value())) {
+ if (timeline_time &&
+ IsWithinAnimationTimeEpsilon(timeline_time.value().InSecondsF(),
+ new_start_time.value().InSecondsF())) {
new_start_time = timeline_time.value();
}
}
@@ -959,7 +989,7 @@ void Animation::setStartTime(base::Optional<double> start_time_ms,
UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kAsync);
// Update user agent.
- base::Optional<double> new_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> new_current_time = CurrentTimeInternal();
// Even when the animation is not outdated,call SetOutdated to ensure
// the animation is tracked by its timeline for future timing
// updates.
@@ -972,9 +1002,9 @@ void Animation::setStartTime(base::Optional<double> start_time_ms,
NotifyProbe();
}
-void Animation::setStartTime(base::Optional<double> start_time_ms) {
+void Animation::setStartTime(CSSNumberish start_time) {
NonThrowableExceptionState exception_state;
- setStartTime(start_time_ms, exception_state);
+ setStartTime(start_time, exception_state);
}
// https://drafts.csswg.org/web-animations-1/#setting-the-associated-effect
@@ -1049,11 +1079,11 @@ void Animation::setEffect(AnimationEffect* new_effect) {
// The timing phase is ‘before’.
// Otherwise,
// The timing phase is ‘after’.
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
Timing::Phase phase;
if (!current_time)
phase = Timing::kPhaseNone;
- else if (current_time < 0)
+ else if (current_time < AnimationTimeDelta())
phase = Timing::kPhaseBefore;
else
phase = Timing::kPhaseAfter;
@@ -1177,7 +1207,7 @@ void Animation::pause(ExceptionState& exception_state) {
return;
// 3. Let seek time be a time value that is initially unresolved.
- base::Optional<double> seek_time;
+ base::Optional<AnimationTimeDelta> seek_time;
// 4. Let has finite timeline be true if animation has an associated timeline
// that is not monotonically increasing.
@@ -1194,12 +1224,11 @@ void Animation::pause(ExceptionState& exception_state) {
// steps.
// Otherwise,
// Set seek time to animation's associated effect end.
- base::Optional<double> current_time = CurrentTimeInternal();
- if (!current_time) {
+ if (!CurrentTimeInternal()) {
if (playback_rate_ >= 0) {
- seek_time = 0;
+ seek_time = AnimationTimeDelta();
} else {
- if (EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot play reversed Animation with infinite target effect end.");
@@ -1283,7 +1312,7 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
bool enable_seek =
auto_rewind == AutoRewind::kEnabled || reset_current_time_on_resume_;
bool has_pending_ready_promise = false;
- base::Optional<double> seek_time;
+ base::Optional<AnimationTimeDelta> seek_time;
bool has_finite_timeline =
timeline_ && !timeline_->IsMonotonicallyIncreasing();
@@ -1311,21 +1340,23 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
// is unresolved,
// 5c1. Set seek time to zero.
double effective_playback_rate = EffectivePlaybackRate();
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
if (reset_current_time_on_resume_) {
current_time = base::nullopt;
reset_current_time_on_resume_ = false;
}
+ base::Optional<AnimationTimeDelta> effect_end = EffectEnd();
if (effective_playback_rate > 0 && enable_seek &&
- (!current_time || current_time < 0 || current_time >= EffectEnd())) {
- seek_time = 0;
+ (!current_time || current_time < AnimationTimeDelta() ||
+ current_time >= effect_end)) {
+ seek_time = AnimationTimeDelta();
} else if (effective_playback_rate < 0 && enable_seek &&
- (!current_time || current_time <= 0 ||
+ (!current_time || current_time <= AnimationTimeDelta() ||
current_time > EffectEnd())) {
- if (EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot play reversed Animation with infinite target effect end.");
@@ -1333,7 +1364,7 @@ void Animation::PlayInternal(AutoRewind auto_rewind,
}
seek_time = EffectEnd();
} else if (effective_playback_rate == 0 && !current_time) {
- seek_time = 0;
+ seek_time = AnimationTimeDelta();
}
// 6. If seek time is resolved,
@@ -1441,8 +1472,7 @@ void Animation::finish(ExceptionState& exception_state) {
"Cannot finish Animation with a playbackRate of 0.");
return;
}
- if (EffectivePlaybackRate() > 0 &&
- EffectEnd() == std::numeric_limits<double>::infinity()) {
+ if (EffectivePlaybackRate() > 0 && EffectEnd().is_inf()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot finish Animation with an infinite target effect end.");
@@ -1451,7 +1481,8 @@ void Animation::finish(ExceptionState& exception_state) {
ApplyPendingPlaybackRate();
- double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
+ AnimationTimeDelta new_current_time =
+ playback_rate_ < 0 ? AnimationTimeDelta() : EffectEnd();
SetCurrentTimeInternal(new_current_time);
if (!start_time_ && timeline_ && timeline_->IsActive())
@@ -1483,7 +1514,7 @@ void Animation::UpdateFinishedState(UpdateType update_type,
// required to accommodate timelines that may change direction. Without this
// distinction, a once-finished animation would remain finished even when its
// timeline progresses in the opposite direction.
- base::Optional<double> unconstrained_current_time =
+ base::Optional<AnimationTimeDelta> unconstrained_current_time =
did_seek ? CurrentTimeInternal() : CalculateCurrentTime();
// 2. Conditionally update the hold time.
@@ -1497,22 +1528,42 @@ void Animation::UpdateFinishedState(UpdateType update_type,
// boundary. The value of previous current time is used to retain this
// value.
double playback_rate = EffectivePlaybackRate();
- base::Optional<double> hold_time;
+ base::Optional<AnimationTimeDelta> hold_time;
TimelinePhase hold_phase;
- if (playback_rate > 0 && unconstrained_current_time >= EffectEnd()) {
- hold_time = did_seek ? unconstrained_current_time
- : Max(previous_current_time_, EffectEnd());
+
+ if (playback_rate > 0 &&
+ GreaterThanOrEqualWithinTimeTolerance(
+ unconstrained_current_time.value(), EffectEnd())) {
+ if (did_seek) {
+ hold_time = unconstrained_current_time;
+ } else {
+ if (previous_current_time_ > EffectEnd()) {
+ hold_time = previous_current_time_;
+ } else {
+ hold_time = EffectEnd();
+ }
+ }
hold_phase = did_seek ? TimelinePhase::kActive : CalculateCurrentPhase();
SetHoldTimeAndPhase(hold_time, hold_phase);
- } else if (playback_rate < 0 && unconstrained_current_time <= 0) {
- hold_time = did_seek ? unconstrained_current_time
- : Min(previous_current_time_, 0);
+ } else if (playback_rate < 0 &&
+ unconstrained_current_time.value() <= AnimationTimeDelta()) {
+ if (did_seek) {
+ hold_time = unconstrained_current_time;
+ } else {
+ if (previous_current_time_ <= AnimationTimeDelta()) {
+ hold_time = previous_current_time_;
+ } else {
+ hold_time = AnimationTimeDelta();
+ }
+ }
hold_phase = did_seek ? TimelinePhase::kActive : CalculateCurrentPhase();
// Hack for resolving precision issue at zero.
- if (hold_time.value() == -0)
- hold_time = 0;
+ if (hold_time.has_value() &&
+ IsWithinAnimationTimeEpsilon(hold_time.value().InSecondsF(), -0)) {
+ hold_time = AnimationTimeDelta();
+ }
SetHoldTimeAndPhase(hold_time, hold_phase);
} else if (playback_rate != 0) {
@@ -1573,7 +1624,7 @@ void Animation::AsyncFinishMicrotask() {
if (pending_finish_notification_) {
// A pending play or pause must resolve before the finish promise.
if (PendingInternal() && timeline_)
- NotifyReady(timeline_->CurrentTimeSeconds().value_or(0));
+ NotifyReady(timeline_->CurrentTime().value_or(AnimationTimeDelta()));
CommitFinishNotification();
}
@@ -1645,14 +1696,14 @@ void Animation::updatePlaybackRate(double playback_rate,
// animation with the did seek flag set to false, and the
// synchronously notify flag set to false.
case kFinished: {
- base::Optional<double> unconstrained_current_time =
+ base::Optional<AnimationTimeDelta> unconstrained_current_time =
CalculateCurrentTime();
- base::Optional<double> timeline_time =
- timeline_ ? timeline_->CurrentTimeSeconds() : base::nullopt;
+ base::Optional<AnimationTimeDelta> timeline_time =
+ timeline_ ? timeline_->CurrentTime() : base::nullopt;
if (playback_rate) {
if (timeline_time) {
start_time_ = (timeline_time && unconstrained_current_time)
- ? base::make_optional<double>(
+ ? base::make_optional<AnimationTimeDelta>(
(timeline_time.value() -
unconstrained_current_time.value()) /
playback_rate)
@@ -1768,7 +1819,7 @@ void Animation::ApplyPendingPlaybackRate() {
void Animation::setPlaybackRate(double playback_rate,
ExceptionState& exception_state) {
- base::Optional<double> start_time_before = start_time_;
+ base::Optional<AnimationTimeDelta> start_time_before = start_time_;
// 1. Clear any pending playback rate on animation.
// 2. Let previous time be the value of the current time of animation before
@@ -1777,9 +1828,10 @@ void Animation::setPlaybackRate(double playback_rate,
// 4. If previous time is resolved, set the current time of animation to
// previous time
pending_playback_rate_ = base::nullopt;
- base::Optional<double> previous_current_time = currentTime();
+ CSSNumberish previous_current_time;
+ currentTime(previous_current_time);
playback_rate_ = playback_rate;
- if (previous_current_time.has_value()) {
+ if (!previous_current_time.IsNull()) {
setCurrentTime(previous_current_time, exception_state);
}
@@ -1855,7 +1907,7 @@ Animation::CheckCanStartAnimationOnCompositorInternal() const {
// enable compositing provided the iteration duration is finite. Having an
// infinite number of iterations in the animation should not impede the
// ability to composite the animation.
- if (std::isinf(EffectEnd()) && EffectivePlaybackRate() < 0)
+ if (EffectEnd().is_inf() && EffectivePlaybackRate() < 0)
reasons |= CompositorAnimations::kInvalidAnimationOrEffect;
// An Animation without a timeline effectively isn't playing, so there is no
@@ -1893,10 +1945,13 @@ void Animation::StartAnimationOnCompositor(
CheckCanStartAnimationOnCompositor(paint_artifact_compositor, nullptr),
CompositorAnimations::kNoFailure);
+ // If PlaybackRate is 0, then we will run into divide by 0 issues.
+ DCHECK(!IsWithinAnimationTimeEpsilon(0, EffectivePlaybackRate()));
+
bool reversed = EffectivePlaybackRate() < 0;
- base::Optional<double> start_time = base::nullopt;
- double time_offset = 0;
+ base::Optional<AnimationTimeDelta> start_time;
+ AnimationTimeDelta time_offset = AnimationTimeDelta();
// Start the animation on the compositor with either a start time or time
// offset. The start time is used for synchronous updates where the
// compositor start time must be in precise alignment with the specified time
@@ -1905,27 +1960,30 @@ void Animation::StartAnimationOnCompositor(
// Asynchronous updates have an associated pending play or pending pause
// task associated with them.
if (start_time_ && !PendingInternal()) {
- start_time = timeline_->ZeroTimeInSeconds() + start_time_.value();
+ start_time = timeline_->ZeroTime() + start_time_.value();
if (reversed) {
start_time =
start_time.value() - (EffectEnd() / fabs(EffectivePlaybackRate()));
}
- DCHECK(std::isfinite(start_time.value()));
} else {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
time_offset =
reversed ? EffectEnd() - current_time.value() : current_time.value();
time_offset = time_offset / fabs(EffectivePlaybackRate());
- DCHECK(std::isfinite(time_offset));
}
DCHECK_NE(compositor_group_, 0);
DCHECK(To<KeyframeEffect>(content_.Get()));
+ base::Optional<double> start_time_s;
+ if (start_time) {
+ start_time_s = start_time.value().InSecondsF();
+ }
To<KeyframeEffect>(content_.Get())
- ->StartAnimationOnCompositor(compositor_group_, start_time,
- base::TimeDelta::FromSecondsD(time_offset),
- EffectivePlaybackRate());
+ ->StartAnimationOnCompositor(
+ compositor_group_, start_time_s,
+ base::TimeDelta::FromSecondsD(time_offset.InSecondsF()),
+ EffectivePlaybackRate());
}
// TODO(crbug.com/960944): Rename to SetPendingCommit. This method handles both
@@ -1952,7 +2010,10 @@ void Animation::SetCompositorPending(bool effect_changed) {
if (PendingInternal() || !compositor_state_ ||
compositor_state_->effect_changed ||
compositor_state_->playback_rate != EffectivePlaybackRate() ||
- compositor_state_->start_time != start_time_ ||
+ compositor_state_->start_time.has_value() != start_time_.has_value() ||
+ (compositor_state_->start_time && start_time_ &&
+ !IsWithinAnimationTimeEpsilon(compositor_state_->start_time.value(),
+ start_time_.value().InSecondsF())) ||
!compositor_state_->start_time || !start_time_) {
compositor_pending_ = true;
document_->GetPendingAnimations().Add(this);
@@ -2002,14 +2063,14 @@ bool Animation::Update(TimingUpdateReason reason) {
UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync);
if (content_) {
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
TimelinePhase inherited_phase = TimelinePhase::kInactive;
if (!idle) {
inherited_time = CurrentTimeInternal();
// Special case for end-exclusivity when playing backwards.
- if (inherited_time == 0 && EffectivePlaybackRate() < 0)
- inherited_time = -1;
+ if (inherited_time == AnimationTimeDelta() && EffectivePlaybackRate() < 0)
+ inherited_time = AnimationTimeDelta::FromSecondsD(-1);
inherited_phase = CurrentPhaseInternal();
}
@@ -2049,12 +2110,14 @@ bool Animation::Update(TimingUpdateReason reason) {
void Animation::QueueFinishedEvent() {
const AtomicString& event_type = event_type_names::kFinish;
if (GetExecutionContext() && HasEventListeners(event_type)) {
- base::Optional<double> event_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> event_current_time =
+ CurrentTimeInternal();
+ base::Optional<double> event_current_time_ms;
if (event_current_time)
- event_current_time = SecondsToMilliseconds(event_current_time.value());
+ event_current_time_ms = event_current_time.value().InMillisecondsF();
// TODO(crbug.com/916117): Handle NaN values for scroll-linked animations.
pending_finished_event_ = MakeGarbageCollected<AnimationPlaybackEvent>(
- event_type, event_current_time, TimelineTime());
+ event_type, event_current_time_ms, TimelineTime());
pending_finished_event_->SetTarget(this);
pending_finished_event_->SetCurrentTarget(this);
document_->EnqueueAnimationFrameEvent(pending_finished_event_);
@@ -2084,10 +2147,9 @@ base::Optional<AnimationTimeDelta> Animation::TimeToEffectChange() {
return base::nullopt;
if (!content_) {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
- return AnimationTimeDelta::FromSecondsD(-current_time.value() /
- playback_rate_);
+ return -current_time.value() / playback_rate_;
}
if (!HasActiveAnimationsOnCompositor() &&
@@ -2100,7 +2162,8 @@ base::Optional<AnimationTimeDelta> Animation::TimeToEffectChange() {
}
void Animation::cancel() {
- double current_time_before_cancel = CurrentTimeInternal().value_or(0);
+ AnimationTimeDelta current_time_before_cancel =
+ CurrentTimeInternal().value_or(AnimationTimeDelta());
AnimationPlayState initial_play_state = CalculateAnimationPlayState();
if (initial_play_state != kIdle) {
ResetPendingTasks();
@@ -2223,7 +2286,7 @@ void Animation::AddedEventListener(
UseCounter::Count(GetExecutionContext(), WebFeature::kAnimationFinishEvent);
}
-void Animation::PauseForTesting(double pause_time) {
+void Animation::PauseForTesting(AnimationTimeDelta pause_time) {
// Do not restart a canceled animation.
if (CalculateAnimationPlayState() == kIdle)
return;
@@ -2232,11 +2295,11 @@ void Animation::PauseForTesting(double pause_time) {
// animation.
SetCurrentTimeInternal(pause_time);
if (HasActiveAnimationsOnCompositor()) {
- base::Optional<double> current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> current_time = CurrentTimeInternal();
DCHECK(current_time);
To<KeyframeEffect>(content_.Get())
->PauseAnimationForTestingOnCompositor(
- base::TimeDelta::FromSecondsD(current_time.value()));
+ base::TimeDelta::FromSecondsD(current_time.value().InSecondsF()));
}
// Do not wait for animation ready to lock in the hold time. Otherwise,
@@ -2420,11 +2483,13 @@ void Animation::RemoveReplacedAnimation() {
replace_state_ = kRemoved;
const AtomicString& event_type = event_type_names::kRemove;
if (GetExecutionContext() && HasEventListeners(event_type)) {
- base::Optional<double> event_current_time = CurrentTimeInternal();
+ base::Optional<AnimationTimeDelta> event_current_time =
+ CurrentTimeInternal();
+ base::Optional<double> event_current_time_ms;
if (event_current_time)
- event_current_time = SecondsToMilliseconds(event_current_time.value());
+ event_current_time_ms = event_current_time.value().InMillisecondsF();
pending_remove_event_ = MakeGarbageCollected<AnimationPlaybackEvent>(
- event_type, event_current_time, TimelineTime());
+ event_type, event_current_time_ms, TimelineTime());
pending_remove_event_->SetTarget(this);
pending_remove_event_->SetCurrentTarget(this);
document_->EnqueueAnimationFrameEvent(pending_remove_event_);
@@ -2533,6 +2598,24 @@ void Animation::commitStyles(ExceptionState& exception_state) {
WrapWeakPersistent(inline_style), WrapWeakPersistent(target)));
}
+bool Animation::IsInDisplayLockedSubtree() {
+ Element* owning_element = OwningElement();
+ if (!owning_element || !GetDocument())
+ return false;
+
+ base::TimeTicks display_lock_update_timestamp =
+ GetDocument()->GetDisplayLockDocumentState().GetLockUpdateTimestamp();
+
+ if (last_display_lock_update_time_ < display_lock_update_timestamp) {
+ const Element* element =
+ DisplayLockUtilities::NearestLockedExclusiveAncestor(*owning_element);
+ is_in_display_locked_subtree_ = !!element;
+ last_display_lock_update_time_ = display_lock_update_timestamp;
+ }
+
+ return is_in_display_locked_subtree_;
+}
+
void Animation::Trace(Visitor* visitor) const {
visitor->Trace(content_);
visitor->Trace(document_);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.h b/chromium/third_party/blink/renderer/core/animation/animation.h
index caeacc7cf95..1a512b861d3 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation.h
@@ -36,6 +36,7 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
+#include "base/time/time.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/bindings/core/v8/script_promise_property.h"
@@ -44,6 +45,7 @@
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
+#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/dom/dom_exception.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"
@@ -99,6 +101,10 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// relative position.
enum CompareAnimationsOrdering { kTreeOrder, kPointerOrder };
+ // Only expect timing accuracy to within 1 microsecond.
+ // drafts.csswg.org/web-animations/#precision-of-time-values.
+ static constexpr double kTimeToleranceMs = 0.001;
+
static Animation* Create(AnimationEffect*,
AnimationTimeline*,
ExceptionState& = ASSERT_NO_EXCEPTION);
@@ -141,12 +147,13 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
void cancel();
- base::Optional<double> currentTime() const;
- void setCurrentTime(base::Optional<double> new_current_time,
- ExceptionState& exception_state);
- void setCurrentTime(base::Optional<double> new_current_time);
+ void currentTime(CSSNumberish&) const;
+ base::Optional<AnimationTimeDelta> CurrentTimeInternal() const;
+ void setCurrentTime(CSSNumberish, ExceptionState& exception_state);
+ void setCurrentTime(CSSNumberish);
+ void SetCurrentTimeInternal(AnimationTimeDelta);
- base::Optional<double> UnlimitedCurrentTime() const;
+ base::Optional<AnimationTimeDelta> UnlimitedCurrentTime() const;
// https://drafts.csswg.org/web-animations/#play-states
String PlayStateString() const;
@@ -202,10 +209,12 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
virtual void setTimeline(AnimationTimeline* timeline);
Document* GetDocument() const;
- base::Optional<double> startTime() const;
- base::Optional<double> StartTimeInternal() const { return start_time_; }
- virtual void setStartTime(base::Optional<double>, ExceptionState&);
- void setStartTime(base::Optional<double>);
+ void startTime(CSSNumberish&) const;
+ base::Optional<AnimationTimeDelta> StartTimeInternal() const {
+ return start_time_;
+ }
+ virtual void setStartTime(CSSNumberish, ExceptionState&);
+ void setStartTime(CSSNumberish);
const AnimationEffect* effect() const { return content_.Get(); }
AnimationEffect* effect() { return content_.Get(); }
@@ -216,7 +225,7 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// Pausing via this method is not reflected in the value returned by
// paused() and must never overlap with pausing via pause().
- void PauseForTesting(double pause_time);
+ void PauseForTesting(AnimationTimeDelta pause_time);
void DisableCompositedAnimationForTesting();
// This should only be used for CSS
@@ -238,9 +247,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
void CancelIncompatibleAnimationsOnCompositor();
bool HasActiveAnimationsOnCompositor();
void SetCompositorPending(bool effect_changed = false);
- void NotifyReady(double ready_time);
- void CommitPendingPlay(double ready_time);
- void CommitPendingPause(double ready_time);
+ void NotifyReady(AnimationTimeDelta ready_time);
+ void CommitPendingPlay(AnimationTimeDelta ready_time);
+ void CommitPendingPause(AnimationTimeDelta ready_time);
// CompositorAnimationClient implementation.
CompositorAnimation* GetCompositorAnimation() const override {
return compositor_animation_ ? compositor_animation_->GetAnimation()
@@ -291,11 +300,16 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// depends on computed values.
virtual void FlushPendingUpdates() const {}
+ bool IsInDisplayLockedSubtree();
+
+ void SetCanCompositeBGColorAnim() { can_composite_bgcolor_anim_ = true; }
+ void ResetCanCompositeBGColorAnim() { can_composite_bgcolor_anim_ = false; }
+ bool CanCompositeBGColorAnim() const { return can_composite_bgcolor_anim_; }
+
protected:
DispatchEventResult DispatchEventInternal(Event&) override;
void AddedEventListener(const AtomicString& event_type,
RegisteredEventListener&) override;
- base::Optional<double> CurrentTimeInternal() const;
TimelinePhase CurrentPhaseInternal() const;
virtual AnimationEffect::EventDelegate* CreateEventDelegate(
Element* target,
@@ -304,18 +318,16 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
}
private:
- void SetCurrentTimeInternal(double new_current_time);
- void SetHoldTimeAndPhase(
- base::Optional<double> new_hold_time /* in seconds */,
- TimelinePhase new_hold_phase);
+ void SetHoldTimeAndPhase(base::Optional<AnimationTimeDelta> new_hold_time,
+ TimelinePhase new_hold_phase);
void ResetHoldTimeAndPhase();
bool ValidateHoldTimeAndPhase() const;
void ClearOutdated();
void ForceServiceOnNextFrame();
- double EffectEnd() const;
- bool Limited(base::Optional<double> current_time) const;
+ AnimationTimeDelta EffectEnd() const;
+ bool Limited(base::Optional<AnimationTimeDelta> current_time) const;
// Playback rate that will take effect once any pending tasks are resolved.
// If there are no pending tasks, then the effective playback rate equals the
@@ -323,8 +335,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
double EffectivePlaybackRate() const;
void ApplyPendingPlaybackRate();
- base::Optional<double> CalculateStartTime(double current_time) const;
- base::Optional<double> CalculateCurrentTime() const;
+ base::Optional<AnimationTimeDelta> CalculateStartTime(
+ AnimationTimeDelta current_time) const;
+ base::Optional<AnimationTimeDelta> CalculateCurrentTime() const;
TimelinePhase CalculateCurrentPhase() const;
void BeginUpdatingState();
@@ -387,10 +400,10 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// effect when running a scheduled task in response to the animation being
// ready.
base::Optional<double> pending_playback_rate_;
- base::Optional<double> start_time_;
- base::Optional<double> hold_time_;
+ base::Optional<AnimationTimeDelta> start_time_;
+ base::Optional<AnimationTimeDelta> hold_time_;
base::Optional<TimelinePhase> hold_phase_;
- base::Optional<double> previous_current_time_;
+ base::Optional<AnimationTimeDelta> previous_current_time_;
bool reset_current_time_on_resume_ = false;
unsigned sequence_number_;
@@ -445,9 +458,17 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
USING_FAST_MALLOC(CompositorState);
public:
+ // TODO(https://crbug.com/1166397): Convert composited animations to use
+ // AnimationTimeDelta for start_time_ and hold_time_.
explicit CompositorState(Animation& animation)
- : start_time(animation.start_time_),
- hold_time(animation.hold_time_),
+ : start_time(animation.start_time_
+ ? base::make_optional(
+ animation.start_time_.value().InSecondsF())
+ : base::nullopt),
+ hold_time(animation.hold_time_
+ ? base::make_optional(
+ animation.hold_time_.value().InSecondsF())
+ : base::nullopt),
playback_rate(animation.EffectivePlaybackRate()),
effect_changed(false),
pending_action(animation.start_time_ ? kNone : kStart) {}
@@ -503,6 +524,20 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
bool effect_suppressed_;
+ // True if the background color animation can be composited. Set by the
+ // BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams. We keep it here
+ // instead of ElementAnimations such that when we create a compositor
+ // animation, we know which animation should fall back. Note that when we
+ // extend the native paint worklet to composite other types of animations in
+ // the future, we might need to extend this to be a fall back reasons.
+ bool can_composite_bgcolor_anim_ = false;
+
+ // Animations with an owning element stop ticking if there is an active
+ // display lock on an ancestor element. Cache the status to minimize the
+ // number of tree walks.
+ base::TimeTicks last_display_lock_update_time_ = base::TimeTicks();
+ bool is_in_display_locked_subtree_ = false;
+
FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestCompositeAfterPaint,
NoCompositeWithoutCompositedElementId);
FRIEND_TEST_ALL_PREFIXES(AnimationAnimationTestNoCompositing,
diff --git a/chromium/third_party/blink/renderer/core/animation/animation.idl b/chromium/third_party/blink/renderer/core/animation/animation.idl
index ee01f455ec1..0bdb34f11c0 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation.idl
+++ b/chromium/third_party/blink/renderer/core/animation/animation.idl
@@ -41,8 +41,8 @@ enum ReplaceState { "active", "removed", "persisted" };
[CallWith=ExecutionContext, RaisesException] constructor(optional AnimationEffect? effect = null, optional AnimationTimeline? timeline);
[Measure] attribute AnimationEffect? effect;
[RuntimeEnabled=WebAnimationsAPI] attribute AnimationTimeline? timeline;
- [Measure, RaisesException=Setter] attribute double? startTime;
- [Measure, RaisesException=Setter] attribute double? currentTime;
+ [Measure, RaisesException=Setter] attribute CSSNumberish? startTime;
+ [Measure, RaisesException=Setter] attribute CSSNumberish? currentTime;
[Measure, RaisesException=Setter] attribute double playbackRate;
[Measure] readonly attribute AnimationPlayState playState;
[RuntimeEnabled=WebAnimationsAPI, Measure] readonly attribute ReplaceState replaceState;
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
index 286f2d33216..6cdacfffe51 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.cc
@@ -47,7 +47,7 @@ AnimationEffect::AnimationEffect(const Timing& timing,
timing_(timing),
event_delegate_(event_delegate),
needs_update_(true),
- cancel_time_(0) {
+ cancel_time_(AnimationTimeDelta()) {
timing_.AssertValid();
}
@@ -131,7 +131,7 @@ base::Optional<Timing::Phase> TimelinePhaseToTimingPhase(
}
void AnimationEffect::UpdateInheritedTime(
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_timeline_phase,
TimingUpdateReason reason) const {
base::Optional<double> playback_rate = base::nullopt;
@@ -152,7 +152,9 @@ void AnimationEffect::UpdateInheritedTime(
last_update_time_ = inherited_time;
last_update_phase_ = timeline_phase;
- const base::Optional<double> local_time = inherited_time;
+ const base::Optional<double> local_time =
+ inherited_time ? base::make_optional(inherited_time.value().InSecondsF())
+ : base::nullopt;
if (needs_update) {
Timing::CalculatedTiming calculated = SpecifiedTiming().CalculateTimings(
local_time, timeline_phase, direction, IsA<KeyframeEffect>(this),
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect.h b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
index a2373d4f7de..c876426d7e9 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect.h
@@ -114,8 +114,10 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
ComputedEffectTiming* getComputedTiming() const;
void updateTiming(OptionalEffectTiming*,
ExceptionState& = ASSERT_NO_EXCEPTION);
- double GetCancelTime() const { return cancel_time_; }
- void SetCancelTime(double cancel_time) { cancel_time_ = cancel_time; }
+ AnimationTimeDelta GetCancelTime() const { return cancel_time_; }
+ void SetCancelTime(AnimationTimeDelta cancel_time) {
+ cancel_time_ = cancel_time;
+ }
// Attach/Detach the AnimationEffect from its owning animation.
virtual void Attach(AnimationEffectOwner* owner) { owner_ = owner; }
@@ -134,7 +136,7 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
// When AnimationEffect receives a new inherited time via updateInheritedTime
// it will (if necessary) recalculate timings and (if necessary) call
// updateChildrenAndEffects.
- void UpdateInheritedTime(base::Optional<double> inherited_time,
+ void UpdateInheritedTime(base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase,
TimingUpdateReason) const;
void Invalidate() const { needs_update_ = true; }
@@ -168,9 +170,9 @@ class CORE_EXPORT AnimationEffect : public ScriptWrappable {
mutable Timing::CalculatedTiming calculated_;
mutable bool needs_update_;
- mutable base::Optional<double> last_update_time_;
+ mutable base::Optional<AnimationTimeDelta> last_update_time_;
mutable base::Optional<Timing::Phase> last_update_phase_;
- double cancel_time_;
+ AnimationTimeDelta cancel_time_;
const Timing::CalculatedTiming& EnsureCalculated() const;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc b/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
index bacd7956bf9..9a810175445 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_effect_test.cc
@@ -84,8 +84,9 @@ class TestAnimationEffect : public AnimationEffect {
void UpdateInheritedTime(double time, TimingUpdateReason reason) {
event_delegate_->Reset();
- AnimationEffect::UpdateInheritedTime(
- time, /*inherited_phase*/ base::nullopt, reason);
+ AnimationEffect::UpdateInheritedTime(AnimationTimeDelta::FromSecondsD(time),
+ /*inherited_phase*/ base::nullopt,
+ reason);
}
void UpdateChildrenAndEffects() const override {}
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
index fd95d13cd49..86a7a8b13d0 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_input_helpers.cc
@@ -79,7 +79,7 @@ CSSPropertyID AnimationInputHelpers::KeyframeAttributeToCSSProperty(
builder.Append('-');
builder.Append(property[i]);
}
- return cssPropertyID(document.GetExecutionContext(), builder.ToString());
+ return CssPropertyID(document.GetExecutionContext(), builder.ToString());
}
CSSPropertyID AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(
@@ -92,7 +92,7 @@ CSSPropertyID AnimationInputHelpers::KeyframeAttributeToPresentationAttribute(
String unprefixed_property = RemoveSVGPrefix(property);
if (SVGElement::IsAnimatableCSSProperty(QualifiedName(
g_null_atom, AtomicString(unprefixed_property), g_null_atom))) {
- return cssPropertyID(element->GetExecutionContext(), unprefixed_property);
+ return CssPropertyID(element->GetExecutionContext(), unprefixed_property);
}
return CSSPropertyID::kInvalid;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_test.cc b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
index 151f3417187..5916636297d 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_test.cc
@@ -68,14 +68,6 @@
namespace blink {
-namespace {
-
-double MillisecondsToSeconds(double milliseconds) {
- return milliseconds / 1000;
-}
-
-} // namespace
-
void ExpectRelativeErrorWithinEpsilon(double expected, double observed) {
EXPECT_NEAR(1.0, observed / expected, std::numeric_limits<double>::epsilon());
}
@@ -97,7 +89,7 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
timeline = GetDocument().Timeline();
timeline->ResetForTesting();
animation = timeline->Play(nullptr);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
animation->setEffect(MakeAnimation());
}
@@ -193,8 +185,10 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
}
bool SimulateFrame(double time_ms) {
- if (animation->pending())
- animation->NotifyReady(MillisecondsToSeconds(last_frame_time));
+ if (animation->pending()) {
+ animation->NotifyReady(
+ AnimationTimeDelta::FromMillisecondsD(last_frame_time));
+ }
SimulateMicrotask();
last_frame_time = time_ms;
@@ -222,6 +216,33 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
GetPage().Animator().ServiceScriptedAnimations(new_time);
}
+ bool StartTimeIsSet(Persistent<blink::Animation> animation) {
+ CSSNumberish start_time;
+ animation->startTime(start_time);
+ return !start_time.IsNull();
+ }
+
+ bool CurrentTimeIsSet(Persistent<blink::Animation> animation) {
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ return !current_time.IsNull();
+ }
+
+ double GetStartTimeMs(Persistent<blink::Animation> animation) {
+ CSSNumberish start_time;
+ animation->startTime(start_time);
+ return start_time.GetAsDouble();
+ }
+
+ double GetCurrentTimeMs(Persistent<blink::Animation> animation) {
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ return current_time.GetAsDouble();
+ }
+
+#define EXPECT_TIME(expected, observed) \
+ EXPECT_NEAR(expected, observed, Animation::kTimeToleranceMs)
+
Persistent<DocumentTimeline> timeline;
Persistent<Animation> animation;
@@ -231,6 +252,38 @@ class AnimationAnimationTestNoCompositing : public RenderingTest {
class AnimationAnimationTestCompositing
: public AnimationAnimationTestNoCompositing {
+ public:
+ Animation* CreateAnimation(CSSPropertyID property_id,
+ String from,
+ String to) {
+ Timing timing;
+ timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
+
+ Persistent<StringKeyframe> start_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ start_keyframe->SetCSSPropertyValue(
+ property_id, from, SecureContextMode::kInsecureContext, nullptr);
+ Persistent<StringKeyframe> end_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ end_keyframe->SetCSSPropertyValue(
+ property_id, to, SecureContextMode::kInsecureContext, nullptr);
+
+ StringKeyframeVector keyframes;
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+
+ Element* element = GetElementById("target");
+ auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+
+ NonThrowableExceptionState exception_state;
+ DocumentTimeline* timeline =
+ MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+ return Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
+ exception_state);
+ }
+
+ private:
void SetUp() override {
EnableCompositing();
AnimationAnimationTestNoCompositing::SetUp();
@@ -250,155 +303,158 @@ class AnimationAnimationTestCompositeAfterPaint
TEST_F(AnimationAnimationTestNoCompositing, InitialState) {
SetUpWithoutStartingTimeline();
animation = timeline->Play(nullptr);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->pending());
EXPECT_FALSE(animation->Paused());
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
StartTimeline();
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(0, timeline->CurrentTimeMilliseconds());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, timeline->CurrentTimeMilliseconds().value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
EXPECT_FALSE(animation->pending());
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(0, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, CurrentTimeDoesNotSetOutdated) {
EXPECT_FALSE(animation->Outdated());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Outdated());
// FIXME: We should split simulateFrame into a version that doesn't update
// the animation and one that does, as most of the tests don't require
// update() to be called.
GetDocument().GetAnimationClock().UpdateTime(
base::TimeTicks() + base::TimeDelta::FromMilliseconds(10000));
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Outdated());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTime) {
EXPECT_EQ("running", animation->playState());
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeNegative) {
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-2);
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
// A seek can set current time outside the range [0, EffectEnd()].
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
SimulateFrame(40000);
// Hold current time even though outside normal range for the animation.
EXPECT_FALSE(animation->pending());
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
SetCurrentTimeNegativeWithoutSimultaneousPlaybackRateChange) {
SimulateFrame(20000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
// Reversing the direction preserves current time.
animation->setPlaybackRate(-1);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(30000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimePastContentEnd) {
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
// Reversing the play direction changes the play state from finished to
// running.
animation->setPlaybackRate(-2);
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(40000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeMax) {
double limit = std::numeric_limits<double>::max();
- animation->setCurrentTime(limit);
- ExpectRelativeErrorWithinEpsilon(limit, animation->currentTime().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(limit));
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ ExpectRelativeErrorWithinEpsilon(limit, current_time.GetAsDouble());
SimulateFrame(100000);
- ExpectRelativeErrorWithinEpsilon(limit, animation->currentTime().value());
+ animation->currentTime(current_time);
+ ExpectRelativeErrorWithinEpsilon(limit, current_time.GetAsDouble());
}
TEST_F(AnimationAnimationTestNoCompositing, SetCurrentTimeSetsStartTime) {
- EXPECT_EQ(0, animation->startTime());
- animation->setCurrentTime(1000);
- EXPECT_EQ(-1000, animation->startTime());
+ EXPECT_TIME(0, GetStartTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(1000));
+ EXPECT_TIME(-1000, GetStartTimeMs(animation));
SimulateFrame(1000);
- EXPECT_EQ(-1000, animation->startTime());
- EXPECT_EQ(2000, animation->currentTime());
+ EXPECT_TIME(-1000, GetStartTimeMs(animation));
+ EXPECT_TIME(2000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetStartTime) {
SimulateFrame(20000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(0, animation->startTime());
- EXPECT_EQ(20000, animation->currentTime());
- animation->setStartTime(10000);
+ EXPECT_TIME(0, GetStartTimeMs(animation));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(10000));
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->startTime());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetStartTimeMs(animation));
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(30000);
- EXPECT_EQ(10000, animation->startTime());
- EXPECT_EQ(20000, animation->currentTime());
- animation->setStartTime(-20000);
+ EXPECT_TIME(10000, GetStartTimeMs(animation));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(-20000));
EXPECT_EQ("finished", animation->playState());
}
TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeLimitsAnimation) {
// Setting the start time is a seek operation, which is not constrained by the
// normal limits on the animation.
- animation->setStartTime(-50000);
+ animation->setStartTime(CSSNumberish::FromDouble(-50000));
EXPECT_EQ("finished", animation->playState());
EXPECT_TRUE(animation->Limited());
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-1);
EXPECT_EQ("running", animation->playState());
- animation->setStartTime(-100000);
+ animation->setStartTime(CSSNumberish::FromDouble(-100000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(-100000, animation->currentTime());
+ EXPECT_TIME(-100000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
}
@@ -406,15 +462,15 @@ TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeOnLimitedAnimation) {
// The setStartTime method is a seek and thus not constrained by the normal
// limits on the animation.
SimulateFrame(30000);
- animation->setStartTime(-10000);
+ animation->setStartTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
- animation->setCurrentTime(50000);
- EXPECT_EQ(50000, animation->currentTime());
- animation->setStartTime(-40000);
- EXPECT_EQ(70000, animation->currentTime());
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
+ animation->setStartTime(CSSNumberish::FromDouble(-40000));
+ EXPECT_TIME(70000, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
EXPECT_TRUE(animation->Limited());
}
@@ -426,11 +482,11 @@ TEST_F(AnimationAnimationTestNoCompositing, StartTimePauseFinish) {
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->finish(exception_state);
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishWhenPaused) {
@@ -449,24 +505,24 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishWhenPaused) {
TEST_F(AnimationAnimationTestNoCompositing, StartTimeFinishPause) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, StartTimeWithZeroPlaybackRate) {
animation->setPlaybackRate(0);
EXPECT_EQ("running", animation->playState());
SimulateAwaitReady();
- EXPECT_TRUE(animation->startTime().has_value());
+ EXPECT_TRUE(StartTimeIsSet(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
@@ -475,13 +531,13 @@ TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
// Resume playing the animation at the 20s mark.
SimulateFrame(20000);
EXPECT_EQ("paused", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -490,19 +546,19 @@ TEST_F(AnimationAnimationTestNoCompositing, PausePlay) {
// Advance another 10s.
SimulateFrame(30000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToStart) {
// Auto-replay when starting from limit.
- animation->setCurrentTime(30000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(30000));
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
// Auto-replay when starting past the upper bound.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -510,11 +566,11 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToStart) {
// from a negative value of current time.
SimulateFrame(10000);
EXPECT_FALSE(animation->pending());
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
EXPECT_EQ("running", animation->playState());
EXPECT_FALSE(animation->pending());
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
SimulateAwaitReady();
@@ -526,14 +582,14 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToEnd) {
// Snap to end when playing a reversed animation from the start.
animation->setPlaybackRate(-1);
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Snap to end if playing a reversed animation starting past the upper limit.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->pending());
SimulateFrame(10000);
@@ -542,9 +598,9 @@ TEST_F(AnimationAnimationTestNoCompositing, PlayRewindsToEnd) {
// Snap to the end if playing a reversed animation starting with a negative
// value for current time.
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->play();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
@@ -559,15 +615,15 @@ TEST_F(AnimationAnimationTestNoCompositing,
// becomes the hold time.
animation->setPlaybackRate(0);
animation->play();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->play();
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->play();
- EXPECT_EQ(-10000, animation->currentTime());
+ EXPECT_TIME(-10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
@@ -583,76 +639,76 @@ TEST_F(AnimationAnimationTestNoCompositing,
}
TEST_F(AnimationAnimationTestNoCompositing, Reverse) {
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->pause();
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
// Effective playback rate does not kick in until the animation is ready.
EXPECT_EQ(1, animation->playbackRate());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
EXPECT_EQ(-1, animation->playbackRate());
// Updating the playback rate does not change current time.
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
ReverseHoldsCurrentTimeWithPlaybackRateZero) {
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->setPlaybackRate(0);
animation->pause();
animation->reverse();
SimulateAwaitReady();
EXPECT_EQ("running", animation->playState());
EXPECT_EQ(0, animation->playbackRate());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseSeeksToStart) {
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->setPlaybackRate(-1);
animation->reverse();
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseSeeksToEnd) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->reverse();
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseBeyondLimit) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->setPlaybackRate(-1);
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, Finish) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
// Finished snaps to the end of the animation.
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
// Finished is a synchronous operation.
EXPECT_FALSE(animation->pending());
animation->setPlaybackRate(-1);
animation->finish(exception_state);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->pending());
}
@@ -660,28 +716,28 @@ TEST_F(AnimationAnimationTestNoCompositing, Finish) {
TEST_F(AnimationAnimationTestNoCompositing, FinishAfterEffectEnd) {
NonThrowableExceptionState exception_state;
// OK to set current time out of bounds.
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->finish(exception_state);
// The finish method triggers a snap to the upper boundary.
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishBeforeStart) {
NonThrowableExceptionState exception_state;
- animation->setCurrentTime(-10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(-10000));
animation->setPlaybackRate(-1);
animation->finish(exception_state);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing,
FinishDoesNothingWithPlaybackRateZero) {
// Cannot finish an animation that has a playback rate of zero.
DummyExceptionStateForTesting exception_state;
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
animation->setPlaybackRate(0);
animation->finish(exception_state);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_TRUE(exception_state.HadException());
}
@@ -693,11 +749,11 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishRaisesException) {
timing.iteration_count = std::numeric_limits<double>::infinity();
animation->setEffect(MakeGarbageCollected<KeyframeEffect>(
nullptr, MakeEmptyEffectModel(), timing));
- animation->setCurrentTime(10000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(10000));
DummyExceptionStateForTesting exception_state;
animation->finish(exception_state);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
EXPECT_TRUE(exception_state.HadException());
EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
exception_state.CodeAs<DOMExceptionCode>());
@@ -705,12 +761,12 @@ TEST_F(AnimationAnimationTestNoCompositing, FinishRaisesException) {
TEST_F(AnimationAnimationTestNoCompositing, LimitingAtEffectEnd) {
SimulateFrame(30000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
// Cannot run past the end of the animation without a seek.
SimulateFrame(40000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
}
@@ -720,11 +776,11 @@ TEST_F(AnimationAnimationTestNoCompositing, LimitingAtStart) {
SimulateAwaitReady();
SimulateFrame(45000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
SimulateFrame(60000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
EXPECT_FALSE(animation->Paused());
}
@@ -732,75 +788,75 @@ TEST_F(AnimationAnimationTestNoCompositing, LimitingWithNoEffect) {
animation->setEffect(nullptr);
EXPECT_TRUE(animation->Limited());
SimulateFrame(30000);
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRate) {
animation->setPlaybackRate(2);
SimulateAwaitReady();
EXPECT_EQ(2, animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateWhilePaused) {
SimulateFrame(10000);
animation->pause();
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(2);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(20000);
animation->play();
// Change to playback rate does not alter current time.
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(25000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateWhileLimited) {
// Animation plays until it hits the upper bound.
SimulateFrame(40000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
animation->setPlaybackRate(2);
SimulateAwaitReady();
// Already at the end of the animation.
SimulateFrame(50000);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
animation->setPlaybackRate(-2);
SimulateAwaitReady();
SimulateFrame(60000);
EXPECT_FALSE(animation->Limited());
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateZero) {
SimulateFrame(10000);
animation->setPlaybackRate(0);
- EXPECT_EQ(10000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
SimulateFrame(20000);
- EXPECT_EQ(10000, animation->currentTime());
- animation->setCurrentTime(20000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(20000));
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateMax) {
animation->setPlaybackRate(std::numeric_limits<double>::max());
EXPECT_EQ(std::numeric_limits<double>::max(), animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateAwaitReady();
SimulateFrame(1);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRate) {
@@ -808,10 +864,10 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRate) {
EXPECT_EQ(1, animation->playbackRate());
SimulateAwaitReady();
EXPECT_EQ(2, animation->playbackRate());
- EXPECT_EQ(0, animation->currentTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhilePaused) {
@@ -836,11 +892,11 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhilePaused) {
TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhileLimited) {
NonThrowableExceptionState exception_state;
animation->finish(exception_state);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Updating playback rate does not affect current time.
animation->updatePlaybackRate(2);
- EXPECT_EQ(30000, animation->currentTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
// Updating payback rate is resolved immediately for an animation in the
// finished state.
@@ -863,36 +919,36 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateWhileRunning) {
TEST_F(AnimationAnimationTestNoCompositing, SetEffect) {
animation = timeline->Play(nullptr);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
AnimationEffect* effect1 = MakeAnimation();
AnimationEffect* effect2 = MakeAnimation();
animation->setEffect(effect1);
EXPECT_EQ(effect1, animation->effect());
- EXPECT_EQ(0, animation->currentTime());
- animation->setCurrentTime(15000);
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ animation->setCurrentTime(CSSNumberish::FromDouble(15000));
animation->setEffect(effect2);
- EXPECT_EQ(15000, animation->currentTime());
+ EXPECT_TIME(15000, GetCurrentTimeMs(animation));
EXPECT_EQ(nullptr, effect1->GetAnimationForTesting());
EXPECT_EQ(animation, effect2->GetAnimationForTesting());
EXPECT_EQ(effect2, animation->effect());
}
TEST_F(AnimationAnimationTestNoCompositing, SetEffectLimitsAnimation) {
- animation->setCurrentTime(20000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(20000));
animation->setEffect(MakeAnimation(10));
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
EXPECT_TRUE(animation->Limited());
SimulateFrame(10000);
- EXPECT_EQ(20000, animation->currentTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, SetEffectUnlimitsAnimation) {
- animation->setCurrentTime(40000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(40000));
animation->setEffect(MakeAnimation(60));
EXPECT_FALSE(animation->Limited());
- EXPECT_EQ(40000, animation->currentTime());
+ EXPECT_TIME(40000, GetCurrentTimeMs(animation));
SimulateFrame(10000);
- EXPECT_EQ(50000, animation->currentTime());
+ EXPECT_TIME(50000, GetCurrentTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, EmptyAnimationsDontUpdateEffects) {
@@ -912,6 +968,10 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsDisassociateFromEffect) {
EXPECT_EQ(nullptr, animation2->effect());
}
+#define EXPECT_TIMEDELTA(expected, observed) \
+ EXPECT_NEAR(expected.InMillisecondsF(), observed.InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
+
TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
Timing timing;
timing.start_delay = 1;
@@ -920,46 +980,48 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
auto* keyframe_effect = MakeGarbageCollected<KeyframeEffect>(
nullptr, MakeEmptyEffectModel(), timing);
animation = timeline->Play(keyframe_effect);
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
// Next effect change at end of start delay.
SimulateFrame(0);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Next effect change at end of start delay.
SimulateFrame(500);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
// Start of active phase.
SimulateFrame(1000);
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
// Still in active phase.
SimulateFrame(1500);
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
// Start of the after phase. Next effect change at end of after phase.
SimulateFrame(2000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Still in effect if fillmode = forward|both.
SimulateFrame(3000);
EXPECT_EQ(base::nullopt, animation->TimeToEffectChange());
// Reset to start of animation. Next effect at the end of the start delay.
- animation->setCurrentTime(0);
+ animation->setCurrentTime(CSSNumberish::FromDouble(0));
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// Start delay is scaled by playback rate.
animation->setPlaybackRate(2);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
// Effectively a paused animation.
animation->setPlaybackRate(0);
@@ -967,23 +1029,24 @@ TEST_F(AnimationAnimationTestNoCompositing, AnimationsReturnTimeToNextEffect) {
EXPECT_EQ(base::nullopt, animation->TimeToEffectChange());
// Reversed animation from end time. Next effect after end delay.
- animation->setCurrentTime(3000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(3000));
animation->setPlaybackRate(-1);
animation->Update(kTimingUpdateOnDemand);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ animation->TimeToEffectChange().value());
// End delay is scaled by playback rate.
animation->setPlaybackRate(-2);
animation->Update(kTimingUpdateOnDemand);
SimulateFrame(3000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(0.5),
- animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(0.5),
+ animation->TimeToEffectChange().value());
}
TEST_F(AnimationAnimationTestNoCompositing, TimeToNextEffectWhenPaused) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
animation->pause();
EXPECT_TRUE(animation->pending());
EXPECT_EQ("paused", animation->playState());
@@ -995,8 +1058,9 @@ TEST_F(AnimationAnimationTestNoCompositing, TimeToNextEffectWhenPaused) {
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectWhenCancelledBeforeStart) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
- animation->setCurrentTime(-8000);
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(-8000));
animation->setPlaybackRate(2);
EXPECT_EQ("running", animation->playState());
animation->cancel();
@@ -1010,8 +1074,9 @@ TEST_F(AnimationAnimationTestNoCompositing,
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectWhenCancelledBeforeStartReverse) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
- animation->setCurrentTime(9000);
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
+ animation->setCurrentTime(CSSNumberish::FromDouble(9000));
animation->setPlaybackRate(-3);
EXPECT_EQ("running", animation->playState());
animation->cancel();
@@ -1023,7 +1088,8 @@ TEST_F(AnimationAnimationTestNoCompositing,
TEST_F(AnimationAnimationTestNoCompositing,
TimeToNextEffectSimpleCancelledBeforeStart) {
- EXPECT_EQ(AnimationTimeDelta(), animation->TimeToEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_EQ("running", animation->playState());
animation->cancel();
EXPECT_EQ("idle", animation->playState());
@@ -1059,99 +1125,99 @@ TEST_F(AnimationAnimationTestNoCompositing, HasLowerCompositeOrdering) {
TEST_F(AnimationAnimationTestNoCompositing, PlayAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_TIME(0, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(10000, animation->currentTime());
- EXPECT_EQ(0, animation->startTime());
+ EXPECT_TIME(10000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(0, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PlayBackwardsAfterCancel) {
animation->setPlaybackRate(-1);
- animation->setCurrentTime(15000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(15000));
animation->cancel();
EXPECT_EQ("idle", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
// Snap to the end of the animation.
animation->play();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, ReverseAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
EXPECT_FALSE(animation->pending());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
// Reverse snaps to the end of the animation.
animation->reverse();
EXPECT_EQ("running", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
SimulateFrame(10000);
EXPECT_EQ("running", animation->playState());
- EXPECT_EQ(20000, animation->currentTime());
- EXPECT_EQ(30000, animation->startTime());
+ EXPECT_TIME(20000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, FinishAfterCancel) {
NonThrowableExceptionState exception_state;
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->finish(exception_state);
EXPECT_EQ("finished", animation->playState());
- EXPECT_EQ(30000, animation->currentTime());
- EXPECT_EQ(-30000, animation->startTime());
+ EXPECT_TIME(30000, GetCurrentTimeMs(animation));
+ EXPECT_TIME(-30000, GetStartTimeMs(animation));
}
TEST_F(AnimationAnimationTestNoCompositing, PauseAfterCancel) {
animation->cancel();
EXPECT_EQ("idle", animation->playState());
- EXPECT_FALSE(animation->currentTime().has_value());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_FALSE(CurrentTimeIsSet(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
animation->pause();
EXPECT_EQ("paused", animation->playState());
EXPECT_TRUE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
SimulateAwaitReady();
EXPECT_FALSE(animation->pending());
- EXPECT_EQ(0, animation->currentTime());
- EXPECT_FALSE(animation->startTime().has_value());
+ EXPECT_TIME(0, GetCurrentTimeMs(animation));
+ EXPECT_FALSE(StartTimeIsSet(animation));
}
// crbug.com/1052217
@@ -1169,7 +1235,8 @@ TEST_F(AnimationAnimationTestNoCompositing, SetPlaybackRateAfterFinish) {
EXPECT_EQ(animation->playbackRate(), -1);
EXPECT_TRUE(animation->Outdated());
animation->Update(kTimingUpdateOnDemand);
- EXPECT_EQ(0, animation->TimeToEffectChange()->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_FALSE(animation->Outdated());
}
@@ -1189,7 +1256,8 @@ TEST_F(AnimationAnimationTestNoCompositing, UpdatePlaybackRateAfterFinish) {
EXPECT_EQ(animation->playbackRate(), -1);
EXPECT_TRUE(animation->Outdated());
animation->Update(kTimingUpdateOnDemand);
- EXPECT_EQ(0, animation->TimeToEffectChange()->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ animation->TimeToEffectChange().value());
EXPECT_FALSE(animation->Outdated());
}
@@ -1302,7 +1370,7 @@ TEST_F(AnimationAnimationTestCompositing, PreCommitRecordsHistograms) {
// Now make the playback rate 0. This trips both the invalid animation and
// unsupported timing parameter reasons.
animation->setPlaybackRate(0);
- animation->NotifyReady(100);
+ animation->NotifyReady(AnimationTimeDelta::FromSecondsD(100));
{
HistogramTester histogram;
ASSERT_TRUE(animation->PreCommit(0, nullptr, true));
@@ -1403,6 +1471,163 @@ TEST_F(AnimationAnimationTestCompositing, InfiniteDurationAnimation) {
animation->CheckCanStartAnimationOnCompositor(nullptr));
}
+// This test ensures that a background-color animation can start on compositor.
+TEST_F(AnimationAnimationTestCompositing, BackgroundColorComposited) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+
+ Animation* animation =
+ CreateAnimation(CSSPropertyID::kBackgroundColor, "red", "green");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ // A basic condition for an animation to be compositable is that it is set so
+ // by BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams.
+ animation->SetCanCompositeBGColorAnim();
+ EXPECT_EQ(animation->CheckCanStartAnimationOnCompositor(nullptr),
+ CompositorAnimations::kNoFailure);
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transform depends
+// on the width and height of the box and a change to either triggers a restart
+// of the animation if running.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnSizeChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ Animation* animation = CreateAnimation(
+ CSSPropertyID::kTransform, "translate(100%, 100%)", "translate(0%, 0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ EXPECT_EQ(animation->CheckCanStartAnimationOnCompositor(nullptr),
+ CompositorAnimations::kNoFailure);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Kick the animation out of the play-pending state.
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // No size change and animation does not require a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Restart animation on a width change.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 200));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Restart animation on a height change.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 300));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transform only
+// depends on width and a change to the height does not trigger a restart.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnWidthChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ animation = CreateAnimation(CSSPropertyID::kTransform, "translateX(100%)",
+ "translateX(0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // Transform is not height dependent and a change to the height does not force
+ // an animation restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 300));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Width change forces a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(200, 300));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
+// crbug.com/1149012
+// Regression test to ensure proper restart logic for composited animations on
+// relative transforms after a size change. In this test, the transition only
+// affects height and a change to the width does not trigger a restart.
+TEST_F(AnimationAnimationTestCompositing,
+ RestartCompositedAnimationOnHeightChange) {
+ // TODO(crbug.com/389359): Remove forced feature enabling once on by
+ // default.
+ ScopedCompositeRelativeKeyframesForTest composite_relative_keyframes(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target"
+ style="width: 100px; height: 200px; will-change: transform">
+ </div>
+ )HTML");
+
+ animation = CreateAnimation(CSSPropertyID::kTransform, "translateY(100%)",
+ "translateY(0%)");
+
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ KeyframeEffect* keyframe_effect =
+ DynamicTo<KeyframeEffect>(animation->effect());
+ ASSERT_TRUE(keyframe_effect);
+
+ GetDocument().GetPendingAnimations().Update(nullptr, true);
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(100, 200));
+ animation->setStartTime(CSSNumberish::FromDouble(0));
+
+ // Transform is not width dependent and a change to the width does not force
+ // an animation restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(300, 200));
+ EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
+
+ // Height change forces a restart.
+ keyframe_effect->UpdateBoxSizeAndCheckTransformAxisAlignment(
+ FloatSize(300, 400));
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+}
+
TEST_F(AnimationAnimationTestCompositing,
ScrollLinkedAnimationCanBeComposited) {
ResetWithCompositedAnimation();
@@ -1533,7 +1758,7 @@ TEST_F(AnimationAnimationTestCompositing,
UpdateAllLifecyclePhasesForTest();
const double TEST_START_TIME = 10;
- scroll_animation->setStartTime(TEST_START_TIME);
+ scroll_animation->setStartTime(CSSNumberish::FromDouble(TEST_START_TIME));
scroll_animation->play();
EXPECT_EQ(scroll_animation->CheckCanStartAnimationOnCompositor(nullptr),
CompositorAnimations::kNoFailure);
@@ -1581,25 +1806,25 @@ TEST_F(AnimationAnimationTestNoCompositing, ScrollLinkedAnimationCreation) {
Animation::Create(MakeAnimation(), scroll_timeline, exception_state);
// Verify start and current times in Idle state.
- EXPECT_FALSE(scroll_animation->startTime().has_value());
- EXPECT_FALSE(scroll_animation->currentTime().has_value());
+ EXPECT_FALSE(StartTimeIsSet(scroll_animation));
+ EXPECT_FALSE(CurrentTimeIsSet(scroll_animation));
scroll_animation->play();
// Verify start and current times in Pending state.
- EXPECT_EQ(0, scroll_animation->startTime());
- EXPECT_EQ(20, scroll_animation->currentTime());
+ EXPECT_TIME(0, GetStartTimeMs(scroll_animation));
+ EXPECT_TIME(20, GetCurrentTimeMs(scroll_animation));
UpdateAllLifecyclePhasesForTest();
// Verify start and current times in Playing state.
- EXPECT_EQ(0, scroll_animation->startTime());
- EXPECT_EQ(20, scroll_animation->currentTime());
+ EXPECT_TIME(0, GetStartTimeMs(scroll_animation));
+ EXPECT_TIME(20, GetCurrentTimeMs(scroll_animation));
// Verify current time after scroll.
scrollable_area->SetScrollOffset(ScrollOffset(0, 40),
mojom::blink::ScrollType::kProgrammatic);
SimulateFrameForScrollAnimations();
- EXPECT_EQ(40, scroll_animation->currentTime());
+ EXPECT_TIME(40, GetCurrentTimeMs(scroll_animation));
}
// Verifies that finished composited scroll-linked animations restart on
@@ -1671,14 +1896,14 @@ TEST_F(AnimationAnimationTestCompositing,
// Advances the animation to "finished" state. The composited animation will
// be destroyed accordingly.
- scroll_animation->setCurrentTime(50000);
+ scroll_animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ(scroll_animation->playState(), "finished");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
GetDocument().GetPendingAnimations().Update(nullptr, true);
EXPECT_FALSE(scroll_animation->HasActiveAnimationsOnCompositor());
// Restarting the animation should create a new compositor animation.
- scroll_animation->setCurrentTime(100);
+ scroll_animation->setCurrentTime(CSSNumberish::FromDouble(100));
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(scroll_animation->playState(), "running");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
@@ -1715,7 +1940,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->Update(kTimingUpdateForAnimationFrame));
// Asynchronous completion.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
}
@@ -1735,7 +1960,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->HasPendingActivity());
// Resolving the finished promise clears the pending activity.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
SimulateMicrotask();
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
@@ -1786,7 +2011,7 @@ TEST_F(AnimationAnimationTestNoCompositing,
EXPECT_TRUE(animation->HasPendingActivity());
// Finishing the animation asynchronously clears the pending activity.
- animation->setCurrentTime(50000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(50000));
EXPECT_EQ("finished", animation->playState());
SimulateMicrotask();
EXPECT_FALSE(animation->Update(kTimingUpdateForAnimationFrame));
@@ -2012,4 +2237,62 @@ TEST_F(AnimationAnimationTestCompositing,
CompositorAnimations::kTimelineSourceHasInvalidCompositingState);
}
+TEST_F(AnimationAnimationTestCompositing, ContentVisibleDisplayLockTest) {
+ animation->cancel();
+ RunDocumentLifecycle();
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .container {
+ content-visibility: auto;
+ }
+ @keyframes anim {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+ #target {
+ background-color: blue;
+ width: 50px;
+ height: 50px;
+ animation: anim 1s linear alternate infinite;
+ }
+ </style>
+ <div id="outer" class="container">
+ <div id="inner" class="container">
+ <div id ="target">
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ RunDocumentLifecycle();
+
+ Element* outer = GetElementById("outer");
+ Element* inner = GetElementById("inner");
+ Element* target = GetElementById("target");
+
+ ElementAnimations* element_animations = target->GetElementAnimations();
+ EXPECT_EQ(1u, element_animations->Animations().size());
+
+ Animation* animation = element_animations->Animations().begin()->key;
+ ASSERT_TRUE(!!animation);
+ EXPECT_FALSE(animation->IsInDisplayLockedSubtree());
+
+ inner->setAttribute(html_names::kStyleAttr, "content-visibility: hidden");
+ RunDocumentLifecycle();
+ EXPECT_TRUE(animation->IsInDisplayLockedSubtree());
+
+ inner->setAttribute(html_names::kStyleAttr, "content-visibility: visible");
+ RunDocumentLifecycle();
+ EXPECT_FALSE(animation->IsInDisplayLockedSubtree());
+
+ outer->setAttribute(html_names::kStyleAttr, "content-visibility: hidden");
+ RunDocumentLifecycle();
+ EXPECT_TRUE(animation->IsInDisplayLockedSubtree());
+
+ // Ensure that the animation has not been canceled even though display locked.
+ EXPECT_EQ(1u, target->GetElementAnimations()->Animations().size());
+ EXPECT_EQ(animation->playState(), "running");
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h b/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
index 9c330f3443b..b7ab9757fcd 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_time_delta.h
@@ -41,6 +41,8 @@ class CORE_EXPORT AnimationTimeDelta {
public:
constexpr AnimationTimeDelta() : delta_(0) {}
+ constexpr explicit AnimationTimeDelta(base::TimeDelta time_delta)
+ : delta_(time_delta.InSecondsF()) {}
static AnimationTimeDelta FromSecondsD(double time_s) {
DCHECK(!std::isnan(time_s));
@@ -61,6 +63,9 @@ class CORE_EXPORT AnimationTimeDelta {
bool is_max() const {
return delta_ == std::numeric_limits<double>::infinity();
}
+
+ bool is_inf() const { return std::isinf(delta_); }
+
bool is_zero() const { return delta_ == 0; }
AnimationTimeDelta operator+(AnimationTimeDelta other) const {
@@ -72,6 +77,7 @@ class CORE_EXPORT AnimationTimeDelta {
AnimationTimeDelta operator-(AnimationTimeDelta other) const {
return AnimationTimeDelta(delta_ - other.delta_);
}
+ AnimationTimeDelta operator-() { return AnimationTimeDelta(-delta_); }
template <typename T>
AnimationTimeDelta operator*(T a) const {
return AnimationTimeDelta(delta_ * a);
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc b/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
index 3a3859f3f1c..e6a822b50c8 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_timeline.cc
@@ -46,6 +46,12 @@ void AnimationTimeline::currentTime(CSSNumberish& currentTime) {
: CSSNumberish();
}
+base::Optional<AnimationTimeDelta> AnimationTimeline::CurrentTime() {
+ base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
+ return result ? base::make_optional(AnimationTimeDelta(result.value()))
+ : base::nullopt;
+}
+
base::Optional<double> AnimationTimeline::CurrentTimeMilliseconds() {
base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
return result ? base::make_optional(result->InMillisecondsF())
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_timeline.h b/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
index 6c16a91fd4e..8cc0a6252e8 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_timeline.h
@@ -36,6 +36,7 @@ class CORE_EXPORT AnimationTimeline : public ScriptWrappable {
~AnimationTimeline() override = default;
virtual void currentTime(CSSNumberish&);
+ base::Optional<AnimationTimeDelta> CurrentTime();
base::Optional<double> CurrentTimeMilliseconds();
base::Optional<double> CurrentTimeSeconds();
@@ -48,7 +49,7 @@ class CORE_EXPORT AnimationTimeline : public ScriptWrappable {
virtual bool IsScrollTimeline() const { return false; }
virtual bool IsCSSScrollTimeline() const { return false; }
virtual bool IsActive() const = 0;
- virtual double ZeroTimeInSeconds() = 0;
+ virtual AnimationTimeDelta ZeroTime() = 0;
// https://drafts.csswg.org/web-animations/#monotonically-increasing-timeline
// A timeline is monotonically increasing if its reported current time is
// always greater than or equal than its previously reported current time.
diff --git a/chromium/third_party/blink/renderer/core/animation/build.gni b/chromium/third_party/blink/renderer/core/animation/build.gni
index 65558126ec5..acf6f02e997 100644
--- a/chromium/third_party/blink/renderer/core/animation/build.gni
+++ b/chromium/third_party/blink/renderer/core/animation/build.gni
@@ -15,6 +15,8 @@ blink_core_tests_animation = [
"css/css_animations_test.cc",
"css/css_scroll_timeline_test.cc",
"css/css_transition_data_test.cc",
+ "css_color_interpolation_type_test.cc",
+ "css_interpolation_types_map_test.cc",
"document_animations_test.cc",
"document_timeline_test.cc",
"effect_input_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
index 51fb92a1f8c..204c414357d 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -153,6 +153,16 @@ bool HasIncompatibleAnimations(const Element& target_element,
return false;
}
+void DefaultToUnsupportedProperty(
+ PropertyHandleSet* unsupported_properties,
+ const PropertyHandle& property,
+ CompositorAnimations::FailureReasons* reasons) {
+ (*reasons) |= CompositorAnimations::kUnsupportedCSSProperty;
+ if (unsupported_properties) {
+ unsupported_properties->insert(property);
+ }
+}
+
} // namespace
CompositorElementIdNamespace
@@ -169,10 +179,11 @@ CompositorAnimations::CompositorElementNamespaceForProperty(
return CompositorElementIdNamespace::kPrimaryTransform;
case CSSPropertyID::kFilter:
return CompositorElementIdNamespace::kEffectFilter;
+ case CSSPropertyID::kBackgroundColor:
case CSSPropertyID::kVariable:
- // TODO(crbug.com/883721): Variables should not require the target
- // element to have any composited property tree nodes - i.e. should
- // not need to check for existence of a property tree node.
+ // TODO(crbug.com/883721): Variables and background color should not
+ // require the target element to have any composited property tree nodes -
+ // i.e. should not need to check for existence of a property tree node.
// For now, variable animations target the primary animation target
// node - the effect namespace.
return CompositorElementIdNamespace::kPrimaryEffect;
@@ -272,6 +283,13 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
// Backdrop-filter pixel moving filters do not change the layer bounds
// like regular filters do, so they can still be composited.
break;
+ case CSSPropertyID::kBackgroundColor:
+ if (!RuntimeEnabledFeatures::CompositeBGColorAnimationEnabled() ||
+ !animation_to_add->CanCompositeBGColorAnim()) {
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
+ }
+ break;
case CSSPropertyID::kVariable: {
// Custom properties are supported only in the case of
// OffMainThreadCSSPaintEnabled, and even then only for some specific
@@ -287,10 +305,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
!layout_object->Style()->HasCSSPaintImagesUsingCustomProperty(
property.CustomPropertyName(),
layout_object->GetDocument())) {
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
}
// TODO: Add support for keyframes containing different types
if (!keyframes.front() ||
@@ -302,10 +318,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
} else {
// We skip the rest of the loop in this case for the same reason as
// unsupported CSS properties - see below.
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
continue;
}
break;
@@ -316,10 +330,8 @@ CompositorAnimations::CheckCanStartEffectOnCompositor(
// an unsupported property.
// ii. GetCompositorKeyframeValue() will be false so we will
// accidentally count this as kInvalidAnimationOrEffect as well.
- if (unsupported_properties) {
- unsupported_properties->insert(property);
- }
- reasons |= kUnsupportedCSSProperty;
+ DefaultToUnsupportedProperty(unsupported_properties, property,
+ &reasons);
continue;
}
@@ -406,7 +418,7 @@ CompositorAnimations::CheckCanStartElementOnCompositor(
(effect && effect->HasDirectCompositingReasons());
}
if (!has_direct_compositing_reasons &&
- To<KeyframeEffectModelBase>(model).HasNonVariableProperty()) {
+ To<KeyframeEffectModelBase>(model).RequiresPropertyNode()) {
reasons |= kTargetHasInvalidCompositingState;
}
} else {
@@ -696,6 +708,8 @@ void CompositorAnimations::GetAnimationOnCompositor(
DCHECK(!properties.IsEmpty());
for (const auto& property : properties) {
AtomicString custom_property_name = "";
+ CompositorPaintWorkletInput::NativePropertyType native_property_type =
+ CompositorPaintWorkletInput::NativePropertyType::kInvalid;
// If the animation duration is infinite, it doesn't make sense to scale
// the keyframe offset, so use a scale of 1.0. This is connected to
// the known issue of how the Web Animations spec handles infinite
@@ -749,6 +763,17 @@ void CompositorAnimations::GetAnimationOnCompositor(
curve = std::move(transform_curve);
break;
}
+ case CSSPropertyID::kBackgroundColor: {
+ native_property_type =
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor;
+ auto float_curve = std::make_unique<CompositorFloatAnimationCurve>();
+ target_property = compositor_target_property::NATIVE_PROPERTY;
+ AddKeyframesToCurve(*float_curve, values);
+ float_curve->SetTimingFunction(*timing.timing_function);
+ float_curve->SetScaledDuration(scale);
+ curve = std::move(float_curve);
+ break;
+ }
case CSSPropertyID::kVariable: {
DCHECK(RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled());
custom_property_name = property.CustomPropertyName();
@@ -776,8 +801,18 @@ void CompositorAnimations::GetAnimationOnCompositor(
}
DCHECK(curve.get());
- auto keyframe_model = std::make_unique<CompositorKeyframeModel>(
- *curve, target_property, 0, group, std::move(custom_property_name));
+ std::unique_ptr<CompositorKeyframeModel> keyframe_model;
+ if (!custom_property_name.IsEmpty()) {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group, std::move(custom_property_name));
+ } else if (native_property_type !=
+ CompositorPaintWorkletInput::NativePropertyType::kInvalid) {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group, native_property_type);
+ } else {
+ keyframe_model = std::make_unique<CompositorKeyframeModel>(
+ *curve, target_property, 0, group);
+ }
if (start_time)
keyframe_model->SetStartTime(start_time.value());
@@ -834,8 +869,9 @@ CompositorAnimations::CheckCanStartTransformAnimationOnCompositorForSVG(
if (layout_object->IsSVGViewportContainer()) {
// Nested SVG doesn't support transforms for now.
reasons |= kTransformRelatedPropertyCannotBeAcceleratedOnTarget;
- } else if (layout_object->IsSVGForeignObject() &&
- layout_object->StyleRef().EffectiveZoom() != 1) {
+ } else if (layout_object->StyleRef().EffectiveZoom() != 1) {
+ // TODO(crbug.com/1186312): Composited transform animation with non-1
+ // effective zoom is incorrectly scaled for now.
// TODO(crbug.com/1134775): If a foreignObject's effect zoom is not 1,
// its transform node contains an additional scale which would be removed
// by composited animation.
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
index ad0abb2462b..c107d8b8fed 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -47,6 +47,7 @@ class Animation;
class CompositorAnimation;
class Element;
class KeyframeEffectModelBase;
+class Node;
class PaintArtifactCompositor;
class SVGElement;
diff --git a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 69121bf03e4..63147572614 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -56,7 +56,6 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
@@ -183,7 +182,8 @@ class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
const Timing& timing,
const KeyframeEffectModelBase& effect) {
// TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
nullptr);
return CheckCanStartEffectOnCompositor(timing, *element_.Get(), nullptr,
@@ -455,7 +455,8 @@ class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
// As the compositor code only understands CompositorKeyframeValues, we must
// snapshot the effect to make those available.
// TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
nullptr);
@@ -635,7 +636,8 @@ TEST_P(AnimationCompositorAnimationsTest,
SetCustomProperty("--x", "5");
UpdateAllLifecyclePhasesForTest();
- auto style = GetDocument().GetStyleResolver().StyleForElement(element_);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element_, StyleRecalcContext());
EXPECT_TRUE(style->NonInheritedVariables());
EXPECT_TRUE(style->NonInheritedVariables()
->GetData(AtomicString("--foo"))
@@ -1334,7 +1336,7 @@ TEST_P(AnimationCompositorAnimationsTest, CanStartEffectOnCompositorBasic) {
MakeGarbageCollected<StringKeyframeEffectModel>(non_css_frames_vector);
EXPECT_TRUE(CanStartEffectOnCompositor(timing_, *non_css_frames) &
CompositorAnimations::kAnimationAffectsNonCSSProperties);
- EXPECT_TRUE(non_css_frames->HasNonVariableProperty());
+ EXPECT_TRUE(non_css_frames->RequiresPropertyNode());
// NB: Important that non_css_frames_vector goes away and cleans up
// before fake_name.
}
@@ -1737,7 +1739,7 @@ TEST_P(AnimationCompositorAnimationsTest,
keyframe_model->TargetProperty());
EXPECT_EQ(keyframe_model->GetCustomPropertyNameForTesting(),
property_name.Utf8().data());
- EXPECT_FALSE(effect->HasNonVariableProperty());
+ EXPECT_FALSE(effect->RequiresPropertyNode());
}
TEST_P(AnimationCompositorAnimationsTest,
@@ -2065,8 +2067,7 @@ TEST_P(AnimationCompositorAnimationsTest, CompositedTransformAnimation) {
ASSERT_NE(nullptr, cc_transform);
EXPECT_TRUE(cc_transform->has_potential_animation);
EXPECT_TRUE(cc_transform->is_currently_animating);
- EXPECT_EQ(cc::kNotScaled, cc_transform->starting_animation_scale);
- EXPECT_EQ(cc::kNotScaled, cc_transform->maximum_animation_scale);
+ EXPECT_EQ(1.f, cc_transform->maximum_animation_scale);
// Make sure the animation is started on the compositor.
EXPECT_EQ(
@@ -2100,7 +2101,6 @@ TEST_P(AnimationCompositorAnimationsTest, CompositedScaleAnimation) {
ASSERT_NE(nullptr, cc_transform);
EXPECT_TRUE(cc_transform->has_potential_animation);
EXPECT_TRUE(cc_transform->is_currently_animating);
- EXPECT_EQ(2.f, cc_transform->starting_animation_scale);
EXPECT_EQ(5.f, cc_transform->maximum_animation_scale);
// Make sure the animation is started on the compositor.
@@ -2242,6 +2242,9 @@ TEST_P(AnimationCompositorAnimationsTest,
<use id="use" href="#rect-useref" class="animate"/>
<use id="use-offset" href="#rect-useref" x="10" class="animate"/>
</svg>
+ <svg id="svg-zoomed" class="animate" style="zoom: 1.5">
+ <rect id="rect-zoomed" class="animate"/>
+ </svg>
)HTML");
auto CanStartAnimation = [&](const char* id) -> bool {
@@ -2261,6 +2264,9 @@ TEST_P(AnimationCompositorAnimationsTest,
EXPECT_TRUE(CanStartAnimation("use"));
EXPECT_FALSE(CanStartAnimation("use-offset"));
+ EXPECT_FALSE(CanStartAnimation("svg-zoomed"));
+ EXPECT_FALSE(CanStartAnimation("rect-zoomed"));
+
To<SVGElement>(GetDocument().getElementById("rect"))
->SetWebAnimatedAttribute(
svg_names::kXAttr,
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
index 83be42ab243..7bd0c3fd1b7 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/animation/css/compositor_keyframe_value.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
index d84627765c8..cede2395cd2 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.cc
@@ -34,7 +34,8 @@ static CompositorKeyframeValue* CreateFromTransformProperties(
CompositorKeyframeValue* CompositorKeyframeValueFactory::Create(
const PropertyHandle& property,
- const ComputedStyle& style) {
+ const ComputedStyle& style,
+ double offset) {
const CSSProperty& css_property = property.GetCSSProperty();
#if DCHECK_IS_ON()
// Variables are conditionally interpolable and compositable.
@@ -67,6 +68,9 @@ CompositorKeyframeValue* CompositorKeyframeValueFactory::Create(
return CreateFromTransformProperties(style.Scale(), style.EffectiveZoom(),
nullptr);
}
+ case CSSPropertyID::kBackgroundColor: {
+ return MakeGarbageCollected<CompositorKeyframeDouble>(offset);
+ }
case CSSPropertyID::kVariable: {
if (!RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled()) {
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
index d4e55a9a6b1..17115618768 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h
@@ -18,7 +18,8 @@ class CompositorKeyframeValueFactory {
public:
static CompositorKeyframeValue* Create(const PropertyHandle&,
- const ComputedStyle&);
+ const ComputedStyle&,
+ double offset);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
index e2e7beb7993..9e637788e15 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animation.cc
@@ -60,7 +60,7 @@ void CSSAnimation::setTimeline(AnimationTimeline* timeline) {
ignore_css_timeline_ = true;
}
-void CSSAnimation::setStartTime(base::Optional<double> start_time_ms,
+void CSSAnimation::setStartTime(CSSNumberish start_time_ms,
ExceptionState& exception_state) {
PlayStateTransitionScope scope(*this);
Animation::setStartTime(start_time_ms, exception_state);
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animation.h b/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
index 745f14f4876..32bfc8a162c 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animation.h
@@ -51,7 +51,7 @@ class CORE_EXPORT CSSAnimation : public Animation {
void play(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void reverse(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void setTimeline(AnimationTimeline*) override;
- void setStartTime(base::Optional<double>, ExceptionState&) override;
+ void setStartTime(CSSNumberish, ExceptionState&) override;
// When set, subsequent changes to animation-play-state no longer affect the
// play state.
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
index 601832605c7..18dcabd7910 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -434,11 +434,11 @@ AnimationTimeDelta IterationElapsedTime(const AnimationEffect& effect,
CSSScrollTimeline* CreateCSSScrollTimeline(
Element* element,
- const CSSScrollTimeline::Options& options) {
+ CSSScrollTimeline::Options&& options) {
if (!options.IsValid())
return nullptr;
- auto* scroll_timeline =
- MakeGarbageCollected<CSSScrollTimeline>(&element->GetDocument(), options);
+ auto* scroll_timeline = MakeGarbageCollected<CSSScrollTimeline>(
+ &element->GetDocument(), std::move(options));
// It's is not allowed for a style resolve to create timelines that
// needs timing updates (i.e. AnimationTimeline::NeedsAnimationTimingUpdate()
// must return false). Servicing animations after creation preserves this
@@ -486,7 +486,7 @@ AnimationTimeline* ComputeTimeline(Element* element,
if (timeline->Matches(options))
return existing_timeline;
}
- if (auto* timeline = CreateCSSScrollTimeline(element, options))
+ if (auto* timeline = CreateCSSScrollTimeline(element, std::move(options)))
return timeline;
}
return nullptr;
@@ -760,7 +760,7 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
DCHECK(!is_animation_style_change);
base::Optional<TimelinePhase> inherited_phase;
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
if (timeline) {
inherited_phase = base::make_optional(timeline->Phase());
@@ -770,7 +770,7 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
((timeline != existing_animation->Timeline()) ||
animation->ResetsCurrentTimeOnResume())) {
if (!timeline->IsMonotonicallyIncreasing())
- inherited_time = timeline->CurrentTimeSeconds();
+ inherited_time = timeline->CurrentTime();
}
}
@@ -792,13 +792,13 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
ComputeTimeline(&element, timeline_name, scroll_timeline_rule,
nullptr /* existing_timeline */);
base::Optional<TimelinePhase> inherited_phase;
- base::Optional<double> inherited_time;
+ base::Optional<AnimationTimeDelta> inherited_time;
if (timeline) {
if (timeline->IsMonotonicallyIncreasing()) {
- inherited_time = 0;
+ inherited_time = AnimationTimeDelta();
} else {
inherited_phase = base::make_optional(timeline->Phase());
- inherited_time = timeline->CurrentTimeSeconds();
+ inherited_time = timeline->CurrentTime();
}
}
update.StartAnimation(
@@ -1039,8 +1039,9 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
// Set the current time as the start time for retargeted transitions
if (retargeted_compositor_transitions.Contains(property)) {
- animation->setStartTime(
- element->GetDocument().Timeline().CurrentTimeMilliseconds());
+ CSSNumberish current_time;
+ element->GetDocument().Timeline().currentTime(current_time);
+ animation->setStartTime(current_time);
}
animation->Update(kTimingUpdateOnDemand);
running_transition->animation = animation;
@@ -1239,9 +1240,9 @@ void CSSAnimations::CalculateTransitionUpdateForProperty(
if (property.GetCSSProperty().IsCompositableProperty()) {
CompositorKeyframeValue* from = CompositorKeyframeValueFactory::Create(
- property, *state.before_change_style);
- CompositorKeyframeValue* to =
- CompositorKeyframeValueFactory::Create(property, state.style);
+ property, *state.before_change_style, start_keyframe->Offset().value());
+ CompositorKeyframeValue* to = CompositorKeyframeValueFactory::Create(
+ property, state.style, end_keyframe->Offset().value());
start_keyframe->SetCompositorValue(from);
end_keyframe->SetCompositorValue(to);
}
@@ -1253,8 +1254,8 @@ void CSSAnimations::CalculateTransitionUpdateForProperty(
state.update.StartTransition(
property, state.before_change_style, state.cloned_style,
reversing_adjusted_start_value, reversing_shortening_factor,
- *MakeGarbageCollected<InertEffect>(model, timing, false, 0,
- base::nullopt));
+ *MakeGarbageCollected<InertEffect>(model, timing, false,
+ AnimationTimeDelta(), base::nullopt));
DCHECK(!state.animating_element->GetElementAnimations() ||
!state.animating_element->GetElementAnimations()
->IsAnimationStyleChange());
@@ -1288,7 +1289,7 @@ void CSSAnimations::CalculateTransitionUpdateForStandardProperty(
}
CSSPropertyID resolved_id =
- resolveCSSPropertyID(transition_property.unresolved_property);
+ ResolveCSSPropertyID(transition_property.unresolved_property);
bool animate_all = resolved_id == CSSPropertyID::kAll;
const StylePropertyShorthand& property_list =
animate_all ? PropertiesForTransitionAll()
@@ -1299,7 +1300,7 @@ void CSSAnimations::CalculateTransitionUpdateForStandardProperty(
CSSPropertyID longhand_id =
property_list.length() ? property_list.properties()[i]->PropertyID()
: resolved_id;
- DCHECK_GE(longhand_id, firstCSSProperty);
+ DCHECK_GE(longhand_id, kFirstCSSProperty);
const CSSProperty& property =
CSSProperty::Get(longhand_id)
.ResolveDirectionAwareProperty(style.Direction(),
@@ -1425,19 +1426,27 @@ scoped_refptr<const ComputedStyle> CSSAnimations::CalculateBeforeChangeStyle(
a, b, Animation::CompareAnimationsOrdering::kPointerOrder);
});
- // Sample animations and add to the interpolations map.
+ // Sample animations and add to the interpolatzions map.
for (Animation* animation : animations) {
- base::Optional<double> current_time = animation->currentTime();
- if (!current_time)
+ CSSNumberish current_time_numberish;
+ animation->currentTime(current_time_numberish);
+ if (current_time_numberish.IsNull())
continue;
+ // CSSNumericValue is not yet supported, verify that it is not used
+ DCHECK(!current_time_numberish.IsCSSNumericValue());
+
+ base::Optional<AnimationTimeDelta> current_time =
+ AnimationTimeDelta::FromMillisecondsD(
+ current_time_numberish.GetAsDouble());
+
auto* effect = DynamicTo<KeyframeEffect>(animation->effect());
if (!effect)
continue;
auto* inert_animation_for_sampling = MakeGarbageCollected<InertEffect>(
- effect->Model(), effect->SpecifiedTiming(), false,
- current_time.value() / 1000, base::nullopt);
+ effect->Model(), effect->SpecifiedTiming(), false, current_time,
+ base::nullopt);
HeapVector<Member<Interpolation>> sample;
inert_animation_for_sampling->Sample(sample);
@@ -1692,10 +1701,9 @@ void CSSAnimations::AnimationEventDelegate::OnEventCondition(
previous_phase_ != Timing::kPhaseAfter) {
// TODO(crbug.com/1059968): Determine if animation direction or playback
// rate factor into the calculation of the elapsed time.
- double cancel_time = animation_node.GetCancelTime();
+ AnimationTimeDelta cancel_time = animation_node.GetCancelTime();
MaybeDispatch(Document::kAnimationCancelListener,
- event_type_names::kAnimationcancel,
- AnimationTimeDelta::FromSecondsD(cancel_time));
+ event_type_names::kAnimationcancel, cancel_time);
}
if (!phase_change && current_phase == Timing::kPhaseActive &&
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
index 0857a0e4daa..9982f48ab31 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_animations_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/animation/animation.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
#include "third_party/blink/renderer/core/animation/element_animations.h"
+#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -38,7 +39,7 @@ class CSSAnimationsTest : public RenderingTest {
SetUpAnimationClockForTesting();
// Advance timer to document time.
platform()->AdvanceClockSeconds(
- GetDocument().Timeline().ZeroTime().since_origin().InSecondsF());
+ GetDocument().Timeline().ZeroTime().InSecondsF());
}
void TearDown() override {
@@ -263,8 +264,9 @@ class CSSAnimationsCompositorSyncTest : public CSSAnimationsTest {
void VerifyCompositorOpacity(double expected_value) {
cc::KeyframeModel* keyframe_model = GetCompositorKeyframeForOpacity();
base::TimeDelta iteration_time = CompositorIterationTime();
- const cc::FloatAnimationCurve* opacity_curve =
- keyframe_model->curve()->ToFloatAnimationCurve();
+ const gfx::FloatAnimationCurve* opacity_curve =
+ gfx::FloatAnimationCurve::ToFloatAnimationCurve(
+ keyframe_model->curve());
EXPECT_NEAR(expected_value, opacity_curve->GetValue(iteration_time),
kTolerance);
}
@@ -347,15 +349,21 @@ TEST_F(CSSAnimationsCompositorSyncTest, SetStartTime) {
Animation* animation = GetAnimation();
int compositor_group = animation->CompositorGroup();
+ CSSNumberish start_time, current_time;
+ animation->startTime(start_time);
+ animation->currentTime(current_time);
+
// Partially rewind the animation via setStartTime.
- double new_start_time =
- animation->startTime().value() + animation->currentTime().value() / 2;
+ CSSNumberish new_start_time = CSSNumberish::FromDouble(
+ start_time.GetAsDouble() + (current_time.GetAsDouble() / 2));
+
animation->setStartTime(new_start_time, ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhasesForTest();
// Verify blink updates.
- EXPECT_NEAR(250, animation->currentTime().value(),
- kTimeToleranceMilliseconds);
+ animation->currentTime(current_time);
+ EXPECT_TRUE(current_time.IsDouble());
+ EXPECT_NEAR(250, current_time.GetAsDouble(), kTimeToleranceMilliseconds);
EXPECT_NEAR(0.75, element_->GetComputedStyle()->Opacity(), kTolerance);
// Compositor animation needs to restart and will have a new compositor group.
@@ -386,12 +394,14 @@ TEST_F(CSSAnimationsCompositorSyncTest, SetCurrentTime) {
int compositor_group = animation->CompositorGroup();
// Advance current time.
- animation->setCurrentTime(750, ASSERT_NO_EXCEPTION);
+ animation->setCurrentTime(CSSNumberish::FromDouble(750), ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhasesForTest();
// Verify blink updates.
- EXPECT_NEAR(750, animation->currentTime().value(),
- kTimeToleranceMilliseconds);
+ CSSNumberish current_time;
+ animation->currentTime(current_time);
+ EXPECT_TRUE(current_time.IsDouble());
+ EXPECT_NEAR(750, current_time.GetAsDouble(), kTimeToleranceMilliseconds);
EXPECT_NEAR(0.25, element_->GetComputedStyle()->Opacity(), kTolerance);
// Compositor animation needs to restart and will have a new compositor group.
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
index 179646a550c..d63409c1c28 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
@@ -82,8 +82,10 @@ double ComputeElementOffsetThreshold(const CSSValue* value) {
ScrollTimelineElementBasedOffset* ComputeElementBasedOffset(
Document& document,
const cssvalue::CSSElementOffsetValue* value) {
- auto* offset = MakeGarbageCollected<ScrollTimelineElementBasedOffset>();
- offset->setTarget(ComputeElementOffsetTarget(document, value->Target()));
+ auto* offset = ScrollTimelineElementBasedOffset::Create();
+ Element* target = ComputeElementOffsetTarget(document, value->Target());
+ if (target)
+ offset->setTarget(target);
offset->setEdge(ComputeElementOffsetEdge(value->Edge()));
offset->setThreshold(ComputeElementOffsetThreshold(value->Threshold()));
return offset;
@@ -121,23 +123,22 @@ ScrollTimelineOffset* ComputeScrollOffset(Document& document,
return MakeGarbageCollected<ScrollTimelineOffset>();
}
-HeapVector<Member<ScrollTimelineOffset>>* ComputeScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> ComputeScrollOffsets(
Document& document,
const CSSValue* start,
const CSSValue* end) {
- auto* offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
+ HeapVector<Member<ScrollTimelineOffset>> offsets;
- bool start_is_auto = IsAuto(start) || !start;
- bool end_is_auto = IsAuto(end) || !end;
+ const bool start_is_auto = !start || IsAuto(start);
+ const bool end_is_auto = !end || IsAuto(end);
// TODO(crbug.com/1094014): scroll_offsets will replace start and end
// offsets once spec decision on multiple scroll offsets is finalized.
// https://github.com/w3c/csswg-drafts/issues/4912
if (!start_is_auto)
- offsets->push_back(ComputeScrollOffset(document, start));
+ offsets.push_back(ComputeScrollOffset(document, start));
if (!end_is_auto || !start_is_auto)
- offsets->push_back(ComputeScrollOffset(document, end));
+ offsets.push_back(ComputeScrollOffset(document, end));
return offsets;
}
@@ -212,11 +213,11 @@ CSSScrollTimeline::Options::Options(Element* element,
time_range_(ComputeTimeRange(rule.GetTimeRange())),
rule_(&rule) {}
-CSSScrollTimeline::CSSScrollTimeline(Document* document, const Options& options)
+CSSScrollTimeline::CSSScrollTimeline(Document* document, Options&& options)
: ScrollTimeline(document,
options.source_,
options.direction_,
- options.offsets_,
+ std::move(options.offsets_),
*options.time_range_),
rule_(options.rule_) {
DCHECK(options.IsValid());
@@ -229,10 +230,9 @@ const AtomicString& CSSScrollTimeline::Name() const {
}
bool CSSScrollTimeline::Matches(const Options& options) const {
- DCHECK(options.offsets_);
return (scrollSource() == options.source_) &&
(GetOrientation() == options.direction_) &&
- (ScrollOffsetsEqual(*options.offsets_)) &&
+ (ScrollOffsetsEqual(options.offsets_)) &&
(GetTimeRange() == options.time_range_) && (rule_ == options.rule_);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
index c06419f378e..ef6811a5c33 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline.h
@@ -33,12 +33,12 @@ class CORE_EXPORT CSSScrollTimeline : public ScrollTimeline {
Element* source_;
ScrollTimeline::ScrollDirection direction_;
- HeapVector<Member<ScrollTimelineOffset>>* offsets_;
+ HeapVector<Member<ScrollTimelineOffset>> offsets_;
base::Optional<double> time_range_;
StyleRuleScrollTimeline* rule_;
};
- CSSScrollTimeline(Document*, const Options&);
+ CSSScrollTimeline(Document*, Options&&);
const AtomicString& Name() const;
diff --git a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
index a693940dd30..3e6b652a202 100644
--- a/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
@@ -4,10 +4,16 @@
#include "third_party/blink/renderer/core/animation/css/css_scroll_timeline.h"
+#include "third_party/blink/renderer/core/animation/document_animations.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/id_target_observer_registry.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_style_element.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -22,6 +28,10 @@ class CSSScrollTimelineTest : public PageTestBase,
bool HasObservers(const AtomicString& id) {
return GetDocument().GetIdTargetObserverRegistry().HasObservers(id);
}
+
+ DocumentAnimations& GetDocumentAnimations() const {
+ return GetDocument().GetDocumentAnimations();
+ }
};
TEST_F(CSSScrollTimelineTest, IdObserverElementRemoval) {
@@ -217,4 +227,130 @@ TEST_F(CSSScrollTimelineTest, SharedTimelines) {
EXPECT_NE(animations2[2]->timeline(), animations1[1]->timeline());
}
+TEST_F(CSSScrollTimelineTest, MultipleLifecyclePasses) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ @keyframes anim {
+ from { color: green; }
+ to { color: green; }
+ }
+ @scroll-timeline timeline {
+ source: selector(#scroller);
+ time-range: 10s;
+ start: auto;
+ end: auto;
+ }
+ #scroller {
+ height: 100px;
+ overflow: scroll;
+ }
+ #scroller > div {
+ height: 200px;
+ }
+ #element {
+ color: red;
+ animation: anim 10s timeline;
+ }
+ </style>
+ <div id=element></div>
+ <div id=scroller>
+ <div id=contents></div>
+ </div>
+ )HTML");
+
+ Element* element = GetDocument().getElementById("element");
+ ASSERT_TRUE(element);
+
+ // According to the rules of the spec [1], the timeline is now inactive,
+ // because #scroller did not have a layout box at the time style recalc
+ // for #element happened.
+ //
+ // However, we do an additional style/layout pass if we detect new
+ // CSSScrollTimelines in this situation, hence we ultimately do expect
+ // the animation to apply [2].
+ //
+ // See also DocumentAnimations::ValidateTimelines.
+ //
+ // [1] https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
+ // [2] https://github.com/w3c/csswg-drafts/issues/5261
+ EXPECT_EQ(MakeRGB(0, 128, 0),
+ element->GetComputedStyle()->VisitedDependentColor(
+ GetCSSPropertyColor()));
+}
+
+namespace {
+
+class AnimationTriggeringDelegate : public ResizeObserver::Delegate {
+ public:
+ explicit AnimationTriggeringDelegate(Element* element) : element_(element) {}
+
+ void OnResize(
+ const HeapVector<Member<ResizeObserverEntry>>& entries) override {
+ element_->setAttribute(blink::html_names::kClassAttr, "animate");
+ }
+
+ void Trace(Visitor* visitor) const override {
+ ResizeObserver::Delegate::Trace(visitor);
+ visitor->Trace(element_);
+ }
+
+ private:
+ Member<Element> element_;
+};
+
+} // namespace
+
+TEST_F(CSSScrollTimelineTest, ResizeObserverTriggeredTimelines) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ @keyframes anim {
+ from { width: 100px; }
+ to { width: 100px; }
+ }
+ @scroll-timeline timeline {
+ source: selector(#scroller);
+ time-range: 10s;
+ }
+ #scroller {
+ height: 100px;
+ overflow: scroll;
+ }
+ #scroller > div {
+ height: 200px;
+ }
+ #element {
+ width: 1px;
+ }
+ #element.animate {
+ animation: anim 10s timeline;
+ }
+ </style>
+ <div id=main></div>
+ )HTML");
+
+ ASSERT_TRUE(
+ GetDocumentAnimations().GetUnvalidatedTimelinesForTesting().IsEmpty());
+
+ Element* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+ element->setAttribute(blink::html_names::kIdAttr, "element");
+
+ Element* scroller = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+ scroller->setAttribute(blink::html_names::kIdAttr, "scroller");
+ scroller->AppendChild(MakeGarbageCollected<HTMLDivElement>(GetDocument()));
+
+ Element* main = GetDocument().getElementById("main");
+ ASSERT_TRUE(main);
+ main->AppendChild(element);
+ main->AppendChild(scroller);
+
+ auto* delegate = MakeGarbageCollected<AnimationTriggeringDelegate>(element);
+ ResizeObserver* observer =
+ ResizeObserver::Create(GetDocument().domWindow(), delegate);
+ observer->observe(element);
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(1u,
+ GetDocumentAnimations().GetUnvalidatedTimelinesForTesting().size());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc
new file mode 100644
index 00000000000..d0552b1a8d7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.cc
@@ -0,0 +1,164 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h"
+#include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+
+namespace blink {
+
+class CSSAspectRatioNonInterpolableValue final : public NonInterpolableValue {
+ public:
+ ~CSSAspectRatioNonInterpolableValue() final = default;
+
+ static scoped_refptr<CSSAspectRatioNonInterpolableValue> Create(
+ StyleAspectRatio aspect_ratio) {
+ return base::AdoptRef(
+ new CSSAspectRatioNonInterpolableValue(aspect_ratio.GetType()));
+ }
+
+ EAspectRatioType GetAspectRatioType() const { return type_; }
+
+ bool IsCompatibleWith(const CSSAspectRatioNonInterpolableValue& other) const {
+ if (GetAspectRatioType() == EAspectRatioType::kAuto ||
+ GetAspectRatioType() != other.GetAspectRatioType())
+ return false;
+ return true;
+ }
+
+ DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
+
+ private:
+ explicit CSSAspectRatioNonInterpolableValue(EAspectRatioType type)
+ : type_(type) {}
+
+ EAspectRatioType type_;
+};
+
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSAspectRatioNonInterpolableValue);
+template <>
+struct DowncastTraits<CSSAspectRatioNonInterpolableValue> {
+ static bool AllowFrom(const NonInterpolableValue* value) {
+ return value && AllowFrom(*value);
+ }
+ static bool AllowFrom(const NonInterpolableValue& value) {
+ return value.GetType() == CSSAspectRatioNonInterpolableValue::static_type_;
+ }
+};
+
+class InheritedAspectRatioChecker
+ : public CSSInterpolationType::CSSConversionChecker {
+ public:
+ explicit InheritedAspectRatioChecker(StyleAspectRatio aspect_ratio)
+ : aspect_ratio_(aspect_ratio) {}
+
+ private:
+ bool IsValid(const StyleResolverState& state,
+ const InterpolationValue& underlying) const final {
+ return state.ParentStyle()->AspectRatio() == aspect_ratio_;
+ }
+
+ const StyleAspectRatio aspect_ratio_;
+};
+
+std::unique_ptr<InterpolableValue>
+CSSAspectRatioInterpolationType::CreateInterpolableAspectRatio(
+ const StyleAspectRatio& aspect_ratio) {
+ std::unique_ptr<InterpolableAspectRatio> result =
+ InterpolableAspectRatio::MaybeCreate(aspect_ratio);
+ return std::move(result);
+}
+
+PairwiseInterpolationValue CSSAspectRatioInterpolationType::MaybeMergeSingles(
+ InterpolationValue&& start,
+ InterpolationValue&& end) const {
+ if (!To<CSSAspectRatioNonInterpolableValue>(*start.non_interpolable_value)
+ .IsCompatibleWith(To<CSSAspectRatioNonInterpolableValue>(
+ *end.non_interpolable_value))) {
+ return nullptr;
+ }
+ return PairwiseInterpolationValue(std::move(start.interpolable_value),
+ std::move(end.interpolable_value),
+ std::move(start.non_interpolable_value));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertNeutral(
+ const InterpolationValue& underlying,
+ ConversionCheckers& conversion_checkers) const {
+ return InterpolationValue(underlying.interpolable_value->CloneAndZero(),
+ underlying.non_interpolable_value);
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInitial(
+ const StyleResolverState&,
+ ConversionCheckers& conversion_checkers) const {
+ StyleAspectRatio initial_ratio = ComputedStyle::InitialStyle().AspectRatio();
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(initial_ratio),
+ CSSAspectRatioNonInterpolableValue::Create(initial_ratio));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInherit(
+ const StyleResolverState& state,
+ ConversionCheckers& conversion_checkers) const {
+ if (!state.ParentStyle())
+ return nullptr;
+
+ StyleAspectRatio inherited_aspect_ratio = state.ParentStyle()->AspectRatio();
+ conversion_checkers.push_back(
+ std::make_unique<InheritedAspectRatioChecker>(inherited_aspect_ratio));
+ if (inherited_aspect_ratio.IsAuto())
+ return nullptr;
+
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(inherited_aspect_ratio),
+ CSSAspectRatioNonInterpolableValue::Create(inherited_aspect_ratio));
+}
+
+InterpolationValue
+CSSAspectRatioInterpolationType::MaybeConvertStandardPropertyUnderlyingValue(
+ const ComputedStyle& style) const {
+ return InterpolationValue(
+ CreateInterpolableAspectRatio(style.AspectRatio()),
+ CSSAspectRatioNonInterpolableValue::Create(style.AspectRatio()));
+}
+
+InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertValue(
+ const CSSValue& value,
+ const StyleResolverState* state,
+ ConversionCheckers&) const {
+ StyleAspectRatio ratio =
+ StyleBuilderConverter::ConvertAspectRatio(*state, value);
+ return InterpolationValue(CreateInterpolableAspectRatio(ratio),
+ CSSAspectRatioNonInterpolableValue::Create(ratio));
+}
+
+void CSSAspectRatioInterpolationType::ApplyStandardPropertyValue(
+ const InterpolableValue& interpolable_value,
+ const NonInterpolableValue* non_interpolable_value,
+ StyleResolverState& state) const {
+ const auto& aspect_ratio = To<InterpolableAspectRatio>(interpolable_value);
+ state.Style()->SetAspectRatio(StyleAspectRatio(
+ To<CSSAspectRatioNonInterpolableValue>(non_interpolable_value)
+ ->GetAspectRatioType(),
+ aspect_ratio.GetRatio()));
+}
+void CSSAspectRatioInterpolationType::Composite(
+ UnderlyingValueOwner& underlying_value_owner,
+ double underlying_fraction,
+ const InterpolationValue& value,
+ double interpolation_fraction) const {
+ underlying_value_owner.MutableValue().interpolable_value->ScaleAndAdd(
+ underlying_fraction, *value.interpolable_value);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h
new file mode 100644
index 00000000000..93d854058f7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h
@@ -0,0 +1,53 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
+
+#include "third_party/blink/renderer/core/animation/css_interpolation_type.h"
+#include "third_party/blink/renderer/core/css_value_keywords.h"
+
+namespace blink {
+
+class StyleAspectRatio;
+
+class CSSAspectRatioInterpolationType : public CSSInterpolationType {
+ public:
+ explicit CSSAspectRatioInterpolationType(PropertyHandle property)
+ : CSSInterpolationType(property) {
+ DCHECK_EQ(CSSPropertyID::kAspectRatio,
+ property.GetCSSProperty().PropertyID());
+ }
+
+ InterpolationValue MaybeConvertStandardPropertyUnderlyingValue(
+ const ComputedStyle&) const final;
+ PairwiseInterpolationValue MaybeMergeSingles(
+ InterpolationValue&& start,
+ InterpolationValue&& end) const final;
+ void ApplyStandardPropertyValue(const InterpolableValue&,
+ const NonInterpolableValue*,
+ StyleResolverState&) const final;
+ void Composite(UnderlyingValueOwner&,
+ double underlying_fraction,
+ const InterpolationValue&,
+ double interpolation_fraction) const final;
+
+ static std::unique_ptr<InterpolableValue> CreateInterpolableAspectRatio(
+ const StyleAspectRatio&);
+
+ private:
+ InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertInitial(const StyleResolverState&,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertInherit(const StyleResolverState&,
+ ConversionCheckers&) const final;
+ InterpolationValue MaybeConvertValue(const CSSValue&,
+ const StyleResolverState*,
+ ConversionCheckers&) const final;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_ASPECT_RATIO_INTERPOLATION_TYPE_H_
diff --git a/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
index 1bb38aa0905..57b3fe7781d 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
@@ -34,8 +34,6 @@ const BasicShape* GetBasicShape(const CSSProperty& property,
return nullptr;
return style.ShapeOutside()->Shape();
case CSSPropertyID::kClipPath: {
- if (!style.ClipPath())
- return nullptr;
auto* clip_path_operation =
DynamicTo<ShapeClipPathOperation>(style.ClipPath());
if (!clip_path_operation)
diff --git a/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
index 1a816361073..09adb2a97fb 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_clip_interpolation_type.cc
@@ -88,7 +88,7 @@ class InheritedClipChecker : public CSSInterpolationType::CSSConversionChecker {
const Vector<Length> inherited_length_list_;
};
-class CSSClipNonInterpolableValue : public NonInterpolableValue {
+class CSSClipNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSClipNonInterpolableValue() final = default;
@@ -121,7 +121,7 @@ struct DowncastTraits<CSSClipNonInterpolableValue> {
}
};
-class UnderlyingAutosChecker
+class UnderlyingAutosChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingAutosChecker(const ClipAutos& underlying_autos)
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
index 7276cf1c59f..5f2a4f6b362 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.cc
@@ -68,7 +68,9 @@ CSSColorInterpolationType::CreateInterpolableColor(CSSValueID keyword) {
case CSSValueID::kInternalQuirkInherit:
return CreateInterpolableColorForIndex(kQuirkInherit);
case CSSValueID::kWebkitFocusRingColor:
- return CreateInterpolableColor(LayoutTheme::GetTheme().FocusRingColor());
+ // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
+ return CreateInterpolableColor(LayoutTheme::GetTheme().FocusRingColor(
+ ComputedStyle::InitialStyle().UsedColorScheme()));
default:
DCHECK(StyleColor::IsColorKeyword(keyword));
// TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
@@ -96,6 +98,20 @@ CSSColorInterpolationType::MaybeCreateInterpolableColor(const CSSValue& value) {
return CreateInterpolableColor(identifier_value->GetValueID());
}
+Color CSSColorInterpolationType::GetRGBA(const InterpolableValue& value) {
+ const InterpolableList& list = To<InterpolableList>(value);
+ DCHECK_GE(list.length(), kAlpha);
+ double color[kAlpha + 1];
+ for (unsigned i = kRed; i <= kAlpha; i++) {
+ const InterpolableValue& current_value = *(list.Get(i));
+ color[i] = To<InterpolableNumber>(current_value).Value();
+ }
+ return Color(MakeRGBA(std::round(color[kRed] / color[kAlpha]),
+ std::round(color[kGreen] / color[kAlpha]),
+ std::round(color[kBlue] / color[kAlpha]),
+ color[kAlpha]));
+}
+
static void AddPremultipliedColor(double& red,
double& green,
double& blue,
@@ -141,8 +157,9 @@ Color CSSColorInterpolationType::ResolveInterpolableColor(
*state.Style())
.Access();
}
- AddPremultipliedColor(red, green, blue, alpha, currentcolor_fraction,
- current_style_color.GetColor());
+ AddPremultipliedColor(
+ red, green, blue, alpha, currentcolor_fraction,
+ current_style_color.Resolve(Color(), state.Style()->UsedColorScheme()));
}
const TextLinkColors& colors = state.GetDocument().GetTextLinkColors();
if (double webkit_activelink_fraction =
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
index 7708b1d428b..538e1d9171e 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type.h
@@ -15,7 +15,7 @@ namespace blink {
class StyleColor;
struct OptionalStyleColor;
-class CSSColorInterpolationType : public CSSInterpolationType {
+class CORE_EXPORT CSSColorInterpolationType : public CSSInterpolationType {
public:
CSSColorInterpolationType(PropertyHandle property,
const PropertyRegistration* registration = nullptr)
@@ -44,6 +44,10 @@ class CSSColorInterpolationType : public CSSInterpolationType {
bool is_visited = false,
bool is_text_decoration = false);
+ // Extract color info from a InterpolableValue-result, the input value must be
+ // a InterpolableList.
+ static Color GetRGBA(const InterpolableValue&);
+
private:
InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
ConversionCheckers&) const final;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc
new file mode 100644
index 00000000000..3cc0c4ee5f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_color_interpolation_type_test.cc
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_color_interpolation_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+
+namespace blink {
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA1) {
+ Color color(230, 120, 0, 255);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA2) {
+ Color color(100, 190, 0, 1);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+TEST(CSSColorInterpolationTypeTest, GetRGBA3) {
+ Color color(35, 140, 10, 10);
+ EXPECT_EQ(color,
+ CSSColorInterpolationType::GetRGBA(
+ *CSSColorInterpolationType::CreateInterpolableColor(color)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h b/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
index 501fc9c4f09..ccd7a7045d0 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
+++ b/chromium/third_party/blink/renderer/core/animation/css_default_interpolation_type.h
@@ -11,7 +11,8 @@
namespace blink {
-class CORE_EXPORT CSSDefaultNonInterpolableValue : public NonInterpolableValue {
+class CORE_EXPORT CSSDefaultNonInterpolableValue final
+ : public NonInterpolableValue {
public:
~CSSDefaultNonInterpolableValue() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
index bee89cee486..c5d8b93ccfd 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.cc
@@ -16,7 +16,7 @@
namespace blink {
-class CSSFontVariationSettingsNonInterpolableValue
+class CSSFontVariationSettingsNonInterpolableValue final
: public NonInterpolableValue {
public:
~CSSFontVariationSettingsNonInterpolableValue() final = default;
@@ -65,7 +65,8 @@ static bool TagsMatch(const NonInterpolableValue& a,
return GetTags(a) == GetTags(b);
}
-class UnderlyingTagsChecker : public InterpolationType::ConversionChecker {
+class UnderlyingTagsChecker final
+ : public InterpolationType::ConversionChecker {
public:
explicit UnderlyingTagsChecker(const Vector<uint32_t>& tags) : tags_(tags) {}
~UnderlyingTagsChecker() final = default;
@@ -79,7 +80,7 @@ class UnderlyingTagsChecker : public InterpolationType::ConversionChecker {
const Vector<uint32_t> tags_;
};
-class InheritedFontVariationSettingsChecker
+class InheritedFontVariationSettingsChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit InheritedFontVariationSettingsChecker(
diff --git a/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
index b7d1d7c02f0..d52bbbf5a33 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_image_interpolation_type.cc
@@ -34,7 +34,7 @@ const StyleImage* GetStyleImage(const CSSProperty& property,
}
} // namespace
-class CSSImageNonInterpolableValue : public NonInterpolableValue {
+class CSSImageNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSImageNonInterpolableValue() final = default;
@@ -165,7 +165,7 @@ bool CSSImageInterpolationType::EqualNonInterpolableValues(
To<CSSImageNonInterpolableValue>(*b));
}
-class UnderlyingImageChecker
+class UnderlyingImageChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
UnderlyingImageChecker(const InterpolationValue& underlying)
@@ -203,7 +203,7 @@ InterpolationValue CSSImageInterpolationType::MaybeConvertInitial(
return nullptr;
}
-class InheritedImageChecker
+class InheritedImageChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedImageChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
index 52fc77278e9..e3090ccf7fd 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_image_list_interpolation_type.cc
@@ -18,7 +18,7 @@
namespace blink {
-class UnderlyingImageListChecker
+class UnderlyingImageListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingImageListChecker(const InterpolationValue& underlying)
@@ -65,7 +65,7 @@ InterpolationValue CSSImageListInterpolationType::MaybeConvertStyleImageList(
});
}
-class InheritedImageListChecker
+class InheritedImageListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedImageListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index 71ea57ec1e4..27982868f56 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/animation/css_angle_interpolation_type.h"
+#include "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_border_image_length_box_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_clip_interpolation_type.h"
@@ -83,28 +84,22 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
DEFINE_STATIC_LOCAL(ApplicableTypesMap, all_applicable_types_map, ());
DEFINE_STATIC_LOCAL(ApplicableTypesMap, composited_applicable_types_map, ());
- ApplicableTypesMap& applicable_types_map =
- allow_all_animations_ ? all_applicable_types_map
- : composited_applicable_types_map;
-
- auto entry = applicable_types_map.find(property);
- bool found_entry = entry != applicable_types_map.end();
-
// Custom property interpolation types may change over time so don't trust the
- // applicableTypesMap without checking the registry.
+ // applicable_types_map without checking the registry. Also since the static
+ // map is shared between documents, the registered type may be different in
+ // the different documents.
if (registry_ && property.IsCSSCustomProperty()) {
- const auto* registration = GetRegistration(registry_, property);
- if (registration) {
- if (found_entry) {
- applicable_types_map.erase(entry);
- }
+ if (const auto* registration = GetRegistration(registry_, property))
return registration->GetInterpolationTypes();
- }
}
- if (found_entry) {
+ ApplicableTypesMap& applicable_types_map =
+ allow_all_animations_ ? all_applicable_types_map
+ : composited_applicable_types_map;
+
+ auto entry = applicable_types_map.find(property);
+ if (entry != applicable_types_map.end())
return *entry->value;
- }
std::unique_ptr<InterpolationTypes> applicable_types =
std::make_unique<InterpolationTypes>();
@@ -179,6 +174,10 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
applicable_types->push_back(
std::make_unique<CSSLengthInterpolationType>(used_property));
break;
+ case CSSPropertyID::kAspectRatio:
+ applicable_types->push_back(
+ std::make_unique<CSSAspectRatioInterpolationType>(used_property));
+ break;
case CSSPropertyID::kFlexGrow:
case CSSPropertyID::kFlexShrink:
case CSSPropertyID::kFillOpacity:
diff --git a/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc
new file mode 100644
index 00000000000..8811ad19b65
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/css_interpolation_types_map_test.cc
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/css_interpolation_types_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/feature_policy/document_policy.h"
+#include "third_party/blink/renderer/core/css/css_test_helpers.h"
+#include "third_party/blink/renderer/core/css/property_registry.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/document_init.h"
+#include "third_party/blink/renderer/core/testing/null_execution_context.h"
+
+namespace blink {
+
+TEST(CSSInterpolationTypesMapTest, RegisteredCustomProperty) {
+ auto* execution_context = MakeGarbageCollected<NullExecutionContext>();
+ execution_context->SetUpSecurityContextForTesting();
+ execution_context->GetSecurityContext().SetDocumentPolicy(
+ DocumentPolicy::CreateWithHeaderPolicy({}));
+
+ DocumentInit init =
+ DocumentInit::Create().WithExecutionContext(execution_context);
+ auto* document1 = MakeGarbageCollected<Document>(init);
+ auto* document2 = MakeGarbageCollected<Document>(init);
+
+ AtomicString property_name("--x");
+ PropertyRegistration* registration =
+ css_test_helpers::CreateLengthRegistration(property_name, 0);
+ PropertyRegistry* registry = MakeGarbageCollected<PropertyRegistry>();
+ registry->RegisterProperty(property_name, *registration);
+
+ CSSInterpolationTypesMap map1(nullptr, *document1);
+ CSSInterpolationTypesMap map2(registry, *document2);
+
+ PropertyHandle handle(property_name);
+ auto& types1 = map1.Get(handle);
+ auto& types2 = map2.Get(handle);
+ EXPECT_NE(&types1, &types2);
+ EXPECT_EQ(types1.size(), 1u);
+
+ auto& types1_1 = map1.Get(handle);
+ EXPECT_EQ(&types1, &types1_1);
+
+ execution_context->NotifyContextDestroyed();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
index 12c18f32300..936b3fbf773 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
@@ -155,12 +155,14 @@ void CSSLengthInterpolationType::ApplyStandardPropertyValue(
const float kSlack = 1e-6;
const float before_length = FloatValueForLength(before, 100);
const float after_length = FloatValueForLength(after, 100);
- // Test relative difference for large values to avoid floating point
- // inaccuracies tripping the check.
- const float delta = std::abs(before_length) < kSlack
- ? after_length - before_length
- : (after_length - before_length) / before_length;
- DCHECK_LT(std::abs(delta), kSlack);
+ if (std::isfinite(before_length) && std::isfinite(after_length)) {
+ // Test relative difference for large values to avoid floating point
+ // inaccuracies tripping the check.
+ const float delta = std::abs(before_length) < kSlack
+ ? after_length - before_length
+ : (after_length - before_length) / before_length;
+ DCHECK_LT(std::abs(delta), kSlack);
+ }
#endif
return;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
index d05ce01f00f..93c37aa00ea 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_length_list_interpolation_type.cc
@@ -65,7 +65,7 @@ InterpolationValue CSSLengthListInterpolationType::MaybeConvertInitial(
return MaybeConvertLengthList(initial_length_list, 1);
}
-class InheritedLengthListChecker
+class InheritedLengthListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedLengthListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
index 61fdbd23305..8e14fe549c4 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
@@ -30,9 +30,9 @@ bool GetColor(const CSSProperty& property,
StyleColor& result) {
switch (property.PropertyID()) {
case CSSPropertyID::kFill:
- return GetColorFromPaint(style.SvgStyle().FillPaint(), result);
+ return GetColorFromPaint(style.FillPaint(), result);
case CSSPropertyID::kStroke:
- return GetColorFromPaint(style.SvgStyle().StrokePaint(), result);
+ return GetColorFromPaint(style.StrokePaint(), result);
default:
NOTREACHED();
return false;
@@ -126,15 +126,14 @@ void CSSPaintInterpolationType::ApplyStandardPropertyValue(
StyleResolverState& state) const {
Color color = CSSColorInterpolationType::ResolveInterpolableColor(
interpolable_color, state);
- SVGComputedStyle& mutable_svg_style = state.Style()->AccessSVGStyle();
switch (CssProperty().PropertyID()) {
case CSSPropertyID::kFill:
- mutable_svg_style.SetFillPaint(SVGPaint(color));
- mutable_svg_style.SetInternalVisitedFillPaint(SVGPaint(color));
+ state.Style()->SetFillPaint(SVGPaint(color));
+ state.Style()->SetInternalVisitedFillPaint(SVGPaint(color));
break;
case CSSPropertyID::kStroke:
- mutable_svg_style.SetStrokePaint(SVGPaint(color));
- mutable_svg_style.SetInternalVisitedStrokePaint(SVGPaint(color));
+ state.Style()->SetStrokePaint(SVGPaint(color));
+ state.Style()->SetInternalVisitedStrokePaint(SVGPaint(color));
break;
default:
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
index d60b39522ee..aa9fbc19052 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
@@ -24,7 +24,7 @@ const StylePath* GetPath(const CSSProperty& property,
const ComputedStyle& style) {
switch (property.PropertyID()) {
case CSSPropertyID::kD:
- return style.SvgStyle().D();
+ return style.D();
case CSSPropertyID::kOffsetPath:
return DynamicTo<StylePath>(style.OffsetPath());
case CSSPropertyID::kClipPath: {
diff --git a/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
index 9da7670ecb9..a61bdf0b566 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_scale_interpolation_type.cc
@@ -81,7 +81,7 @@ class InheritedScaleChecker
} // namespace
-class CSSScaleNonInterpolableValue : public NonInterpolableValue {
+class CSSScaleNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSScaleNonInterpolableValue() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
index 829c2921e6e..cb79a29792b 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_size_list_interpolation_type.cc
@@ -18,7 +18,7 @@
namespace blink {
-class UnderlyingSizeListChecker
+class UnderlyingSizeListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingSizeListChecker(const NonInterpolableList& underlying_list)
@@ -47,7 +47,7 @@ class UnderlyingSizeListChecker
scoped_refptr<const NonInterpolableList> underlying_list_;
};
-class InheritedSizeListChecker
+class InheritedSizeListChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
InheritedSizeListChecker(const CSSProperty& property,
diff --git a/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
index f3156672400..711c61fa9d2 100644
--- a/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/css_visibility_interpolation_type.cc
@@ -13,7 +13,7 @@
namespace blink {
-class CSSVisibilityNonInterpolableValue : public NonInterpolableValue {
+class CSSVisibilityNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSVisibilityNonInterpolableValue() final = default;
@@ -59,7 +59,7 @@ struct DowncastTraits<CSSVisibilityNonInterpolableValue> {
}
};
-class UnderlyingVisibilityChecker
+class UnderlyingVisibilityChecker final
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit UnderlyingVisibilityChecker(EVisibility visibility)
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations.cc b/chromium/third_party/blink/renderer/core/animation/document_animations.cc
index 74629dfc276..c7ed01c694e 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations.cc
@@ -71,6 +71,7 @@ DocumentAnimations::DocumentAnimations(Document* document)
void DocumentAnimations::AddTimeline(AnimationTimeline& timeline) {
timelines_.insert(&timeline);
+ unvalidated_timelines_.insert(&timeline);
}
void DocumentAnimations::UpdateAnimationTimingForAnimationFrame() {
@@ -159,6 +160,15 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations(
return animations;
}
+void DocumentAnimations::ValidateTimelines() {
+ for (auto& timeline : unvalidated_timelines_) {
+ if (auto* scroll_timeline = DynamicTo<CSSScrollTimeline>(timeline.Get()))
+ scroll_timeline->ValidateState();
+ }
+
+ unvalidated_timelines_.clear();
+}
+
void DocumentAnimations::CacheCSSScrollTimeline(CSSScrollTimeline& timeline) {
// We cache the least seen CSSScrollTimeline for a given name.
cached_css_timelines_.Set(timeline.Name(), &timeline);
@@ -172,6 +182,7 @@ CSSScrollTimeline* DocumentAnimations::FindCachedCSSScrollTimeline(
void DocumentAnimations::Trace(Visitor* visitor) const {
visitor->Trace(document_);
visitor->Trace(timelines_);
+ visitor->Trace(unvalidated_timelines_);
visitor->Trace(cached_css_timelines_);
}
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations.h b/chromium/third_party/blink/renderer/core/animation/document_animations.h
index f5e30f0a731..759d9f34600 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations.h
@@ -72,6 +72,22 @@ class CORE_EXPORT DocumentAnimations final
HeapVector<Member<Animation>> getAnimations(const TreeScope&);
+ // All newly created AnimationTimelines are considered "unvalidated". This
+ // means that the internal state of the timeline is considered tentative,
+ // and that computing the actual state may require an additional style/layout
+ // pass.
+ //
+ // The lifecycle update will call this function after style and layout has
+ // completed. The function will then go though all unvalidated timelines,
+ // and compare the current state snapshot to a fresh state snapshot. If they
+ // are equal, then the tentative state turned out to be correct, and no
+ // further action is needed. Otherwise, all effects targets associated with
+ // the timeline are marked for recalc, which causes the style/layout phase
+ // to run again.
+ //
+ // https://github.com/w3c/csswg-drafts/issues/5261
+ void ValidateTimelines();
+
void CacheCSSScrollTimeline(CSSScrollTimeline&);
CSSScrollTimeline* FindCachedCSSScrollTimeline(const AtomicString&);
@@ -79,6 +95,10 @@ class CORE_EXPORT DocumentAnimations final
const {
return timelines_;
}
+ const HeapHashSet<WeakMember<AnimationTimeline>>&
+ GetUnvalidatedTimelinesForTesting() const {
+ return unvalidated_timelines_;
+ }
uint64_t current_transition_generation_;
void Trace(Visitor*) const;
@@ -90,6 +110,7 @@ class CORE_EXPORT DocumentAnimations final
private:
Member<Document> document_;
HeapHashSet<WeakMember<AnimationTimeline>> timelines_;
+ HeapHashSet<WeakMember<AnimationTimeline>> unvalidated_timelines_;
// We cache CSSScrollTimelines by name, such that multiple animations using
// the same timeline can use the same CSSScrollTimeline instance.
diff --git a/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc b/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
index 9e8ec4d63ba..75ab69b5cea 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_animations_test.cc
@@ -24,7 +24,7 @@ class MockAnimationTimeline : public AnimationTimeline {
MOCK_METHOD0(Phase, TimelinePhase());
MOCK_CONST_METHOD0(IsActive, bool());
- MOCK_METHOD0(ZeroTimeInSeconds, double());
+ MOCK_METHOD0(ZeroTime, AnimationTimeDelta());
MOCK_METHOD0(InitialStartTimeForAnimations,
base::Optional<base::TimeDelta>());
MOCK_METHOD0(NeedsAnimationTimingUpdate, bool());
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline.cc b/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
index c05b1f14b81..6abfb137535 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -44,10 +44,11 @@ namespace {
// Returns the current animation time for a given |document|. This is
// the animation clock time capped to be at least this document's
-// ZeroTime() such that the animation time is never negative when converted.
+// CalculateZeroTime() such that the animation time is never negative when
+// converted.
base::TimeTicks CurrentAnimationTime(Document* document) {
base::TimeTicks animation_time = document->GetAnimationClock().CurrentTime();
- base::TimeTicks document_zero_time = document->Timeline().ZeroTime();
+ base::TimeTicks document_zero_time = document->Timeline().CalculateZeroTime();
// The AnimationClock time may be null or less than the local document's
// zero time if we have not generated any frames for this document yet. If
@@ -142,10 +143,11 @@ void DocumentTimeline::DocumentTimelineTiming::WakeAfter(
void DocumentTimeline::DocumentTimelineTiming::Trace(Visitor* visitor) const {
visitor->Trace(timeline_);
+ visitor->Trace(timer_);
DocumentTimeline::PlatformTiming::Trace(visitor);
}
-base::TimeTicks DocumentTimeline::ZeroTime() {
+base::TimeTicks DocumentTimeline::CalculateZeroTime() {
if (!zero_time_initialized_ && document_->Loader()) {
zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime() +
origin_time_;
@@ -172,12 +174,14 @@ AnimationTimeline::PhaseAndTime DocumentTimeline::CurrentPhaseAndTime() {
base::Optional<base::TimeDelta> result =
playback_rate_ == 0
- ? ZeroTime().since_origin()
- : (CurrentAnimationTime(GetDocument()) - ZeroTime()) * playback_rate_;
+ ? CalculateZeroTime().since_origin()
+ : (CurrentAnimationTime(GetDocument()) - CalculateZeroTime()) *
+ playback_rate_;
return {TimelinePhase::kActive, result};
}
-void DocumentTimeline::PauseAnimationsForTesting(double pause_time) {
+void DocumentTimeline::PauseAnimationsForTesting(
+ AnimationTimeDelta pause_time) {
for (const auto& animation : animations_needing_update_)
animation->PauseForTesting(pause_time);
ServiceAnimations(kTimingUpdateOnDemand);
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline.h b/chromium/third_party/blink/renderer/core/animation/document_timeline.h
index a1392ecdb62..87ae16853da 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline.h
@@ -78,12 +78,14 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
// The zero time of DocumentTimeline is computed by adding a separate
// |origin_time_| from DocumentTimelineOptions.
// https://drafts.csswg.org/web-animations/#origin-time
- base::TimeTicks ZeroTime();
- double ZeroTimeInSeconds() override {
- return ZeroTime().since_origin().InSecondsF();
+ // TODO(crbug.com/1162960) Convert DocumentTimeline::zero_time_ from
+ // base::TimeTicks to AnimationTimeDelta
+ base::TimeTicks CalculateZeroTime();
+ AnimationTimeDelta ZeroTime() override {
+ return AnimationTimeDelta(CalculateZeroTime().since_origin());
}
- void PauseAnimationsForTesting(double);
+ void PauseAnimationsForTesting(AnimationTimeDelta);
void InvalidateKeyframeEffects(const TreeScope&);
@@ -107,6 +109,8 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
base::TimeDelta origin_time_;
// The origin time. This is computed by adding |origin_time_| to the time
// origin of the document.
+ // TODO(crbug.com/1162960) Convert DocumentTimeline::zero_time_ from
+ // base::TimeTicks to AnimationTimeDelta
base::TimeTicks zero_time_;
bool zero_time_initialized_;
@@ -119,7 +123,7 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
class DocumentTimelineTiming final : public PlatformTiming {
public:
- DocumentTimelineTiming(DocumentTimeline* timeline)
+ explicit DocumentTimelineTiming(DocumentTimeline* timeline)
: timeline_(timeline),
timer_(timeline->GetDocument()->GetTaskRunner(
TaskType::kInternalDefault),
@@ -136,7 +140,7 @@ class CORE_EXPORT DocumentTimeline : public AnimationTimeline {
private:
Member<DocumentTimeline> timeline_;
- TaskRunnerTimer<DocumentTimelineTiming> timer_;
+ HeapTaskRunnerTimer<DocumentTimelineTiming> timer_;
};
friend class AnimationDocumentTimelineTest;
diff --git a/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
index f165b142f00..6df9206afa0 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/pending_animations.h"
+#include "third_party/blink/renderer/core/animation/timing_calculations.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/qualified_name.h"
@@ -53,6 +54,10 @@ namespace {
base::TimeTicks TimeTicksFromMillisecondsD(double seconds) {
return base::TimeTicks() + base::TimeDelta::FromMillisecondsD(seconds);
}
+
+#define EXPECT_TIME_NEAR(expected, value) \
+ EXPECT_NEAR((expected).InMillisecondsF(), (value).InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
} // namespace
namespace blink {
@@ -209,16 +214,16 @@ TEST_F(AnimationDocumentTimelineTest, CurrentTimeSeconds) {
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormal) {
- base::TimeTicks zero_time = timeline->ZeroTime();
+ base::TimeTicks zero_time = timeline->CalculateZeroTime();
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(zero_time, timeline->ZeroTime());
+ EXPECT_EQ(zero_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
- EXPECT_EQ(zero_time, timeline->ZeroTime());
+ EXPECT_EQ(zero_time, timeline->CalculateZeroTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
}
@@ -229,33 +234,33 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormalWithOriginTime) {
timeline->ResetForTesting();
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1200, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRatePause) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}
@@ -265,61 +270,61 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRatePauseWithOriginTime) {
document.Get(), origin_time, platform_timing);
timeline->ResetForTesting();
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
- EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks() + origin_time, timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1100), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1100), timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->CalculateZeroTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->CalculateZeroTime());
EXPECT_EQ(1300, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateSlow) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(0.5);
EXPECT_EQ(0.5, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1000), timeline->CalculateZeroTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->CalculateZeroTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PlaybackRateFast) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
- EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
+ EXPECT_EQ(base::TimeTicks(), timeline->CalculateZeroTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(500), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(500), timeline->CalculateZeroTime());
EXPECT_EQ(5000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-2000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-2000), timeline->CalculateZeroTime());
EXPECT_EQ(6000, timeline->CurrentTimeMilliseconds());
}
@@ -329,30 +334,33 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateFastWithOriginTime) {
timeline->ResetForTesting();
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1000000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1000000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->CalculateZeroTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(300000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->CalculateZeroTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());
timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400000));
- EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
+ EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000),
+ timeline->CalculateZeroTime());
EXPECT_EQ(1600000, timeline->CurrentTimeMilliseconds());
}
TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
- float seek_time = 1;
+ AnimationTimeDelta seek_time = AnimationTimeDelta::FromSecondsD(1);
timing.fill_mode = Timing::FillMode::FORWARDS;
auto* anim1 = MakeGarbageCollected<KeyframeEffect>(
element.Get(), CreateEmptyEffectModel(), timing);
@@ -362,8 +370,13 @@ TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
Animation* animation2 = timeline->Play(anim2);
timeline->PauseAnimationsForTesting(seek_time);
- EXPECT_FLOAT_EQ(seek_time * 1000, animation1->currentTime().value());
- EXPECT_FLOAT_EQ(seek_time * 1000, animation2->currentTime().value());
+ CSSNumberish current_time;
+ animation1->currentTime(current_time);
+ EXPECT_NEAR(seek_time.InMillisecondsF(), current_time.GetAsDouble(),
+ Animation::kTimeToleranceMs);
+ animation2->currentTime(current_time);
+ EXPECT_NEAR(seek_time.InMillisecondsF(), current_time.GetAsDouble(),
+ Animation::kTimeToleranceMs);
}
TEST_F(AnimationDocumentTimelineTest, DelayBeforeAnimationStart) {
@@ -397,7 +410,7 @@ TEST_F(AnimationDocumentTimelineTest, UseAnimationAfterTimelineDeref) {
Animation* animation = timeline->Play(nullptr);
timeline.Clear();
// Test passes if this does not crash.
- animation->setStartTime(0);
+ animation->setStartTime(CSSNumberish::FromDouble(0));
}
TEST_F(AnimationDocumentTimelineTest, PlayAfterDocumentDeref) {
@@ -459,8 +472,9 @@ TEST_F(AnimationDocumentTimelineRealTimeTest,
DocumentTimeline* timeline =
MakeGarbageCollected<DocumentTimeline>(document.Get(), origin_time);
timeline->SetPlaybackRate(0.5);
- EXPECT_EQ(origin_time * 2,
- timeline->ZeroTime() - document->Timeline().ZeroTime());
+
+ EXPECT_TIME_NEAR(AnimationTimeDelta(origin_time) * 2,
+ timeline->ZeroTime() - document->Timeline().ZeroTime());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc b/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
index 8f4ea26b32f..bf4f93ecf76 100644
--- a/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/effect_stack_test.cc
@@ -34,14 +34,14 @@ class AnimationEffectStackTest : public PageTestBase {
Animation* Play(KeyframeEffect* effect, double start_time) {
Animation* animation = timeline->Play(effect);
- animation->setStartTime(start_time * 1000);
+ animation->setStartTime(CSSNumberish::FromDouble(start_time * 1000));
animation->Update(kTimingUpdateOnDemand);
return animation;
}
void UpdateTimeline(base::TimeDelta time) {
GetDocument().GetAnimationClock().UpdateTime(
- GetDocument().Timeline().ZeroTime() + time);
+ GetDocument().Timeline().CalculateZeroTime() + time);
timeline->ServiceAnimations(kTimingUpdateForAnimationFrame);
}
@@ -68,8 +68,8 @@ class AnimationEffectStackTest : public PageTestBase {
InertEffect* MakeInertEffect(KeyframeEffectModelBase* effect) {
Timing timing;
timing.fill_mode = Timing::FillMode::BOTH;
- return MakeGarbageCollected<InertEffect>(effect, timing, false, 0,
- base::nullopt);
+ return MakeGarbageCollected<InertEffect>(
+ effect, timing, false, AnimationTimeDelta(), base::nullopt);
}
KeyframeEffect* MakeKeyframeEffect(KeyframeEffectModelBase* effect,
diff --git a/chromium/third_party/blink/renderer/core/animation/element_animations.cc b/chromium/third_party/blink/renderer/core/animation/element_animations.cc
index 705df935c98..afad6b763cf 100644
--- a/chromium/third_party/blink/renderer/core/animation/element_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/element_animations.cc
@@ -51,6 +51,8 @@ void UpdateAnimationFlagsForEffect(const KeyframeEffect& effect,
style.SetHasCurrentFilterAnimation(true);
if (effect.Affects(PropertyHandle(GetCSSPropertyBackdropFilter())))
style.SetHasCurrentBackdropFilterAnimation(true);
+ if (effect.Affects(PropertyHandle(GetCSSPropertyBackgroundColor())))
+ style.SetHasCurrentBackgroundColorAnimation(true);
}
} // namespace
@@ -151,4 +153,16 @@ bool ElementAnimations::UpdateBoxSizeAndCheckTransformAxisAlignment(
return preserves_axis_alignment;
}
+bool ElementAnimations::IsIdentityOrTranslation() const {
+ for (auto& entry : animations_) {
+ if (auto* effect = DynamicTo<KeyframeEffect>(entry.key->effect())) {
+ if (!effect->IsCurrent() && !effect->IsInEffect())
+ continue;
+ if (!effect->IsIdentityOrTranslation())
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/element_animations.h b/chromium/third_party/blink/renderer/core/animation/element_animations.h
index a0277a0724a..babb8cbff4c 100644
--- a/chromium/third_party/blink/renderer/core/animation/element_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/element_animations.h
@@ -89,6 +89,7 @@ class CORE_EXPORT ElementAnimations final
void ClearBaseComputedStyle();
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
+ bool IsIdentityOrTranslation() const;
void Trace(Visitor*) const;
diff --git a/chromium/third_party/blink/renderer/core/animation/inert_effect.cc b/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
index 7599fe76593..210a2dfced5 100644
--- a/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/inert_effect.cc
@@ -37,7 +37,7 @@ namespace blink {
InertEffect::InertEffect(KeyframeEffectModelBase* model,
const Timing& timing,
bool paused,
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase)
: AnimationEffect(timing),
model_(model),
diff --git a/chromium/third_party/blink/renderer/core/animation/inert_effect.h b/chromium/third_party/blink/renderer/core/animation/inert_effect.h
index 157b1207093..76e785839a5 100644
--- a/chromium/third_party/blink/renderer/core/animation/inert_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/inert_effect.h
@@ -45,7 +45,7 @@ class CORE_EXPORT InertEffect final : public AnimationEffect {
InertEffect(KeyframeEffectModelBase*,
const Timing&,
bool paused,
- base::Optional<double> inherited_time,
+ base::Optional<AnimationTimeDelta> inherited_time,
base::Optional<TimelinePhase> inherited_phase);
void Sample(HeapVector<Member<Interpolation>>&) const;
@@ -66,7 +66,7 @@ class CORE_EXPORT InertEffect final : public AnimationEffect {
private:
Member<KeyframeEffectModelBase> model_;
bool paused_;
- base::Optional<double> inherited_time_;
+ base::Optional<AnimationTimeDelta> inherited_time_;
base::Optional<TimelinePhase> inherited_phase_;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc
new file mode 100644
index 00000000000..cfcbc5408f0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.cc
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h"
+#include "third_party/blink/renderer/core/animation/interpolable_value.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+// static
+std::unique_ptr<InterpolableAspectRatio> InterpolableAspectRatio::MaybeCreate(
+ const StyleAspectRatio& aspect_ratio) {
+ if (!RuntimeEnabledFeatures::CSSAspectRatioInterpolationEnabled())
+ return nullptr;
+
+ // Auto aspect ratio cannot be interpolated to / from.
+ if (aspect_ratio.IsAuto())
+ return nullptr;
+ return std::make_unique<InterpolableAspectRatio>(aspect_ratio.GetRatio());
+}
+
+InterpolableAspectRatio::InterpolableAspectRatio(
+ const FloatSize& aspect_ratio) {
+ // The StyleAspectRatio::IsAuto check in MaybeCreate should return true if we
+ // have a degenerate aspect ratio.
+ DCHECK(aspect_ratio.Height() > 0 && aspect_ratio.Width() > 0);
+
+ value_ = std::make_unique<InterpolableNumber>(
+ log(aspect_ratio.Width() / aspect_ratio.Height()));
+}
+
+FloatSize InterpolableAspectRatio::GetRatio() const {
+ return FloatSize(exp(To<InterpolableNumber>(*value_).Value()), 1);
+}
+
+void InterpolableAspectRatio::Scale(double scale) {
+ value_->Scale(scale);
+}
+
+void InterpolableAspectRatio::Add(const InterpolableValue& other) {
+ value_->Add(*To<InterpolableAspectRatio>(other).value_);
+}
+
+void InterpolableAspectRatio::AssertCanInterpolateWith(
+ const InterpolableValue& other) const {
+ const InterpolableAspectRatio& other_aspect_ratio =
+ To<InterpolableAspectRatio>(other);
+ value_->AssertCanInterpolateWith(*other_aspect_ratio.value_);
+}
+
+void InterpolableAspectRatio::Interpolate(const InterpolableValue& to,
+ const double progress,
+ InterpolableValue& result) const {
+ const InterpolableAspectRatio& aspect_ratio_to =
+ To<InterpolableAspectRatio>(to);
+ InterpolableAspectRatio& aspect_ratio_result =
+ To<InterpolableAspectRatio>(result);
+ value_->Interpolate(*aspect_ratio_to.value_, progress,
+ *aspect_ratio_result.value_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h
new file mode 100644
index 00000000000..36d29a1d8df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h
@@ -0,0 +1,62 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
+
+#include <memory>
+#include "third_party/blink/renderer/core/animation/interpolable_value.h"
+#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
+
+namespace blink {
+
+// Represents a blink::StyleAspectRatio, converted into its logarithm for
+// interpolation.
+class CORE_EXPORT InterpolableAspectRatio final : public InterpolableValue {
+ public:
+ explicit InterpolableAspectRatio(const FloatSize& ratio);
+ explicit InterpolableAspectRatio(std::unique_ptr<InterpolableValue> value)
+ : value_(std::move(value)) {}
+
+ static std::unique_ptr<InterpolableAspectRatio> MaybeCreate(
+ const StyleAspectRatio&);
+
+ FloatSize GetRatio() const;
+
+ // InterpolableValue implementation:
+ void Interpolate(const InterpolableValue& to,
+ const double progress,
+ InterpolableValue& result) const final;
+ bool IsAspectRatio() const final { return true; }
+ bool Equals(const InterpolableValue& other) const final {
+ NOTREACHED();
+ return false;
+ }
+ void Scale(double scale) final;
+ void Add(const InterpolableValue& other) final;
+ void AssertCanInterpolateWith(const InterpolableValue& other) const final;
+
+ private:
+ InterpolableAspectRatio* RawClone() const final {
+ return new InterpolableAspectRatio(value_->Clone());
+ }
+ InterpolableAspectRatio* RawCloneAndZero() const final {
+ return new InterpolableAspectRatio(value_->CloneAndZero());
+ }
+
+ // Interpolable aspect ratio value is stored and interpolated as the log of
+ // the real aspect ratio.
+ std::unique_ptr<InterpolableValue> value_;
+};
+
+template <>
+struct DowncastTraits<InterpolableAspectRatio> {
+ static bool AllowFrom(const InterpolableValue& interpolable_value) {
+ return interpolable_value.IsAspectRatio();
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_ASPECT_RATIO_H_
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc b/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
index 08e6cc60d5a..4e958c4de06 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_length.cc
@@ -204,8 +204,11 @@ static UnitType IndexToUnitType(wtf_size_t index) {
Length InterpolableLength::CreateLength(
const CSSToLengthConversionData& conversion_data,
ValueRange range) const {
+ // Passing true for ToCalcValue is a dirty hack to ensure that we don't create
+ // a degenerate value when animating 'background-position', while we know it
+ // may cause some minor animation glitches for the other properties.
if (IsExpression())
- return Length(expression_->ToCalcValue(conversion_data, range));
+ return Length(expression_->ToCalcValue(conversion_data, range, true));
bool has_percentage = HasPercentage();
double pixels = 0;
diff --git a/chromium/third_party/blink/renderer/core/animation/interpolable_value.h b/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
index 0a846d2f464..21428f41228 100644
--- a/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
+++ b/chromium/third_party/blink/renderer/core/animation/interpolable_value.h
@@ -39,6 +39,7 @@ class CORE_EXPORT InterpolableValue {
virtual bool IsBool() const { return false; }
virtual bool IsList() const { return false; }
virtual bool IsLength() const { return false; }
+ virtual bool IsAspectRatio() const { return false; }
virtual bool IsShadow() const { return false; }
virtual bool IsFilter() const { return false; }
virtual bool IsTransformList() const { return false; }
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
index 082b5a3ee9f..3cc8831033b 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -432,7 +432,7 @@ void KeyframeEffect::AttachCompositedLayers() {
// very special element id for this animation so that the compositor animation
// system recognize it. We do not use 0 as the element id because 0 is
// kInvalidElementId.
- if (compositor_animation && !Model()->HasNonVariableProperty()) {
+ if (compositor_animation && !Model()->RequiresPropertyNode()) {
compositor_animation->AttachNoElement();
return;
}
@@ -503,12 +503,10 @@ bool KeyframeEffect::UpdateBoxSizeAndCheckTransformAxisAlignment(
if (effect_target_size_) {
if ((size_dependencies & TransformOperation::kDependsWidth) &&
(effect_target_size_->Width() != box_size.Width()))
- GetAnimation()->RestartAnimationOnCompositor();
+ RestartRunningAnimationOnCompositor();
else if ((size_dependencies & TransformOperation::kDependsHeight) &&
- (effect_target_size_->Width() != box_size.Height()))
- GetAnimation()->RestartAnimationOnCompositor();
- } else if (size_dependencies) {
- GetAnimation()->RestartAnimationOnCompositor();
+ (effect_target_size_->Height() != box_size.Height()))
+ RestartRunningAnimationOnCompositor();
}
}
@@ -517,6 +515,40 @@ bool KeyframeEffect::UpdateBoxSizeAndCheckTransformAxisAlignment(
return preserves_axis_alignment;
}
+void KeyframeEffect::RestartRunningAnimationOnCompositor() {
+ Animation* animation = GetAnimation();
+ if (!animation)
+ return;
+
+ // No need to to restart an animation that is in the process of starting up,
+ // paused or idle.
+ if (!animation->StartTimeInternal())
+ return;
+
+ animation->RestartAnimationOnCompositor();
+}
+
+bool KeyframeEffect::IsIdentityOrTranslation() const {
+ static const auto** properties = TransformProperties();
+ for (size_t i = 0; i < num_transform_properties; i++) {
+ const auto* keyframes =
+ Model()->GetPropertySpecificKeyframes(PropertyHandle(*properties[i]));
+ if (!keyframes)
+ continue;
+
+ for (const auto& keyframe : *keyframes) {
+ if (const auto* value = keyframe->GetCompositorKeyframeValue()) {
+ if (!To<CompositorKeyframeTransform>(value)
+ ->GetTransformOperations()
+ .IsIdentityOrTranslation()) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
EffectModel::CompositeOperation KeyframeEffect::CompositeInternal() const {
return model_->Composite();
}
@@ -744,7 +776,7 @@ void KeyframeEffect::CountAnimatedProperties() const {
Document& document = target_element_->GetDocument();
for (const auto& property : model_->Properties()) {
if (property.IsCSSProperty()) {
- DCHECK(isValidCSSPropertyID(property.GetCSSProperty().PropertyID()));
+ DCHECK(IsValidCSSPropertyID(property.GetCSSProperty().PropertyID()));
document.CountAnimatedProperty(property.GetCSSProperty().PropertyID());
}
}
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
index e0e72423223..7e880f50f65 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect.h
@@ -136,6 +136,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
void Trace(Visitor*) const override;
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
+ bool IsIdentityOrTranslation() const;
ActiveInterpolationsMap InterpolationsForCommitStyles();
@@ -165,6 +166,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
AnimationTimeDelta time_to_next_iteration) const override;
bool HasIncompatibleStyle() const;
bool HasMultipleTransformProperties() const;
+ void RestartRunningAnimationOnCompositor();
Member<Element> effect_target_;
Member<Element> target_element_;
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index db13009db28..5eea620d145 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -96,15 +96,15 @@ bool KeyframeEffectModelBase::Sample(
namespace {
-static const size_t num_compositable_properties = 7;
+static const size_t num_compositable_properties = 8;
const CSSProperty** CompositableProperties() {
static const CSSProperty*
kCompositableProperties[num_compositable_properties] = {
- &GetCSSPropertyOpacity(), &GetCSSPropertyRotate(),
- &GetCSSPropertyScale(), &GetCSSPropertyTransform(),
- &GetCSSPropertyTranslate(), &GetCSSPropertyFilter(),
- &GetCSSPropertyBackdropFilter()};
+ &GetCSSPropertyOpacity(), &GetCSSPropertyRotate(),
+ &GetCSSPropertyScale(), &GetCSSPropertyTransform(),
+ &GetCSSPropertyTranslate(), &GetCSSPropertyFilter(),
+ &GetCSSPropertyBackdropFilter(), &GetCSSPropertyBackgroundColor()};
return kCompositableProperties;
}
@@ -351,11 +351,13 @@ void KeyframeEffectModelBase::EnsureKeyframeGroups() const {
}
}
-bool KeyframeEffectModelBase::HasNonVariableProperty() const {
+bool KeyframeEffectModelBase::RequiresPropertyNode() const {
for (const auto& keyframe : keyframes_) {
for (const auto& property : keyframe->Properties()) {
if (!property.IsCSSProperty() ||
- property.GetCSSProperty().PropertyID() != CSSPropertyID::kVariable)
+ (property.GetCSSProperty().PropertyID() != CSSPropertyID::kVariable &&
+ property.GetCSSProperty().PropertyID() !=
+ CSSPropertyID::kBackgroundColor))
return true;
}
}
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
index 4331383890e..61ae955cf4d 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -157,7 +157,7 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel {
return has_revert_;
}
- bool HasNonVariableProperty() const;
+ bool RequiresPropertyNode() const;
bool IsTransformRelatedEffect() const override;
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
index 681cc986ef0..4a75261a456 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
@@ -160,7 +160,8 @@ const PropertySpecificKeyframeVector& ConstructEffectAndGetKeyframes(
auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
- auto style = document->GetStyleResolver().StyleForElement(element);
+ auto style = document->GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
// Snapshot should update first time after construction
EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
@@ -634,7 +635,8 @@ TEST_F(AnimationKeyframeEffectModel, CompositorSnapshotUpdateBasic) {
KeyframesAtZeroAndOne(CSSPropertyID::kOpacity, "0", "1");
auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
- auto style = GetDocument().GetStyleResolver().StyleForElement(element);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
const CompositorKeyframeValue* value;
@@ -670,7 +672,8 @@ TEST_F(AnimationKeyframeEffectModel,
auto* effect =
MakeGarbageCollected<StringKeyframeEffectModel>(opacity_keyframes);
- auto style = GetDocument().GetStyleResolver().StyleForElement(element);
+ auto style = GetDocument().GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
*element, *style, nullptr));
diff --git a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
index 8a17f8569f7..c7d170c625a 100644
--- a/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_effect_timing.h"
@@ -29,6 +30,10 @@
namespace blink {
+#define EXPECT_TIMEDELTA(expected, observed) \
+ EXPECT_NEAR(expected.InMillisecondsF(), observed.InMillisecondsF(), \
+ Animation::kTimeToleranceMs)
+
using animation_test_helpers::SetV8ObjectPropertyAsNumber;
using animation_test_helpers::SetV8ObjectPropertyAsString;
@@ -227,8 +232,8 @@ TEST_F(AnimationKeyframeEffectV8Test, CanSetDuration) {
KeyframeEffect* animation = CreateAnimationFromTiming(
script_state, element.Get(), js_keyframes, duration);
- EXPECT_EQ(duration / 1000,
- animation->SpecifiedTiming().iteration_duration->InSecondsF());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromMillisecondsD(duration),
+ animation->SpecifiedTiming().iteration_duration.value());
}
TEST_F(AnimationKeyframeEffectV8Test, CanOmitSpecifiedDuration) {
@@ -367,35 +372,38 @@ TEST_F(KeyframeEffectTest, TimeToEffectChange) {
Animation* animation = GetDocument().Timeline().Play(keyframe_effect);
// Beginning of the animation.
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
EXPECT_EQ(AnimationTimeDelta::Max(),
keyframe_effect->TimeToReverseEffectChange());
// End of the before phase.
- animation->setCurrentTime(100000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(100000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// Nearing the end of the active phase.
- animation->setCurrentTime(199000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(1),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(199000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(1),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// End of the active phase.
- animation->setCurrentTime(200000);
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta(), keyframe_effect->TimeToReverseEffectChange());
+ animation->setCurrentTime(CSSNumberish::FromDouble(200000));
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToForwardsEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta(),
+ keyframe_effect->TimeToReverseEffectChange());
// End of the animation.
- animation->setCurrentTime(300000);
+ animation->setCurrentTime(CSSNumberish::FromDouble(300000));
EXPECT_EQ(AnimationTimeDelta::Max(),
keyframe_effect->TimeToForwardsEffectChange());
- EXPECT_EQ(AnimationTimeDelta::FromSecondsD(100),
- keyframe_effect->TimeToReverseEffectChange());
+ EXPECT_TIMEDELTA(AnimationTimeDelta::FromSecondsD(100),
+ keyframe_effect->TimeToReverseEffectChange());
}
TEST_F(KeyframeEffectTest, CheckCanStartAnimationOnCompositorNoKeyframes) {
diff --git a/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc b/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
index de2cc0c91df..2b78a53fb3f 100644
--- a/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
+++ b/chromium/third_party/blink/renderer/core/animation/length_property_functions.cc
@@ -130,10 +130,10 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.Bottom();
return true;
case CSSPropertyID::kCx:
- result = style.SvgStyle().Cx();
+ result = style.Cx();
return true;
case CSSPropertyID::kCy:
- result = style.SvgStyle().Cy();
+ result = style.Cy();
return true;
case CSSPropertyID::kFlexBasis:
result = style.FlexBasis();
@@ -184,16 +184,16 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.PaddingTop();
return true;
case CSSPropertyID::kR:
- result = style.SvgStyle().R();
+ result = style.R();
return true;
case CSSPropertyID::kRight:
result = style.Right();
return true;
case CSSPropertyID::kRx:
- result = style.SvgStyle().Rx();
+ result = style.Rx();
return true;
case CSSPropertyID::kRy:
- result = style.SvgStyle().Ry();
+ result = style.Ry();
return true;
case CSSPropertyID::kShapeMargin:
result = style.ShapeMargin();
@@ -223,10 +223,10 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
result = style.Width();
return true;
case CSSPropertyID::kX:
- result = style.SvgStyle().X();
+ result = style.X();
return true;
case CSSPropertyID::kY:
- result = style.SvgStyle().Y();
+ result = style.Y();
return true;
case CSSPropertyID::kBorderBottomWidth:
@@ -277,9 +277,9 @@ bool LengthPropertyFunctions::GetLength(const CSSProperty& property,
return true;
case CSSPropertyID::kBaselineShift:
- if (style.BaselineShift() != BS_LENGTH)
+ if (style.BaselineShiftType() != EBaselineShiftType::kLength)
return false;
- result = style.BaselineShiftValue();
+ result = style.BaselineShift();
return true;
case CSSPropertyID::kLineHeight:
// Percent Lengths are used to represent numbers on line-height.
@@ -322,7 +322,8 @@ bool LengthPropertyFunctions::SetLength(const CSSProperty& property,
switch (property.PropertyID()) {
// Setters that take a Length value.
case CSSPropertyID::kBaselineShift:
- style.SetBaselineShiftValue(value);
+ style.SetBaselineShiftType(EBaselineShiftType::kLength);
+ style.SetBaselineShift(value);
return true;
case CSSPropertyID::kBottom:
style.SetBottom(value);
diff --git a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
index 82d035e4a71..80ead64fe8e 100644
--- a/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
+++ b/chromium/third_party/blink/renderer/core/animation/list_interpolation_functions.h
@@ -81,7 +81,7 @@ class CORE_EXPORT ListInterpolationFunctions {
const NonInterpolableValue* b);
};
-class CORE_EXPORT NonInterpolableList : public NonInterpolableValue {
+class CORE_EXPORT NonInterpolableList final : public NonInterpolableValue {
public:
~NonInterpolableList() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc b/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
index f3d696942e3..a4596e6a2f9 100644
--- a/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
+++ b/chromium/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
@@ -100,7 +100,7 @@ InterpolationValue PathInterpolationFunctions::ConvertValue(
path_seg_types, style_path->GetWindRule()));
}
-class UnderlyingPathSegTypesChecker
+class UnderlyingPathSegTypesChecker final
: public InterpolationType::ConversionChecker {
public:
~UnderlyingPathSegTypesChecker() final = default;
diff --git a/chromium/third_party/blink/renderer/core/animation/pending_animations.cc b/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
index 8b96385792b..0377a3a87be 100644
--- a/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/pending_animations.cc
@@ -72,27 +72,27 @@ bool PendingAnimations::Update(
animation->HasActiveAnimationsOnCompositor();
// Animations with a start time do not participate in compositor start-time
// grouping.
- if (animation->PreCommit(animation->startTime() ? 1 : compositor_group,
- paint_artifact_compositor, start_on_compositor)) {
+ if (animation->PreCommit(
+ animation->StartTimeInternal() ? 1 : compositor_group,
+ paint_artifact_compositor, start_on_compositor)) {
if (animation->HasActiveAnimationsOnCompositor() &&
- !had_compositor_animation && !animation->startTime()) {
+ !had_compositor_animation && !animation->StartTimeInternal()) {
started_synchronized_on_compositor = true;
}
if (!animation->timeline() || !animation->timeline()->IsActive())
continue;
- if (animation->Playing() && !animation->startTime()) {
+ if (animation->Playing() && !animation->StartTimeInternal()) {
waiting_for_start_time.push_back(animation.Get());
} else if (animation->PendingInternal()) {
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
+ animation->timeline()->CurrentTime());
// A pending animation that is not waiting on a start time does not need
// to be synchronized with animations that are starting up. Nonetheless,
// it needs to notify the animation to resolve the ready promise and
// commit the pending state.
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
} else {
deferred.push_back(animation);
@@ -108,11 +108,10 @@ bool PendingAnimations::Update(
waiting_for_start_time);
} else {
for (auto& animation : waiting_for_start_time) {
- DCHECK(!animation->startTime());
+ DCHECK(!animation->StartTimeInternal());
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime());
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
}
@@ -155,7 +154,7 @@ void PendingAnimations::NotifyCompositorAnimationStarted(
animations.swap(waiting_for_compositor_animation_start_);
for (auto animation : animations) {
- if (animation->startTime() || !animation->PendingInternal() ||
+ if (animation->StartTimeInternal() || !animation->PendingInternal() ||
!animation->timeline() || !animation->timeline()->IsActive()) {
// Already started or no longer relevant.
continue;
@@ -168,10 +167,11 @@ void PendingAnimations::NotifyCompositorAnimationStarted(
if (animation->timeline() &&
!animation->timeline()->IsMonotonicallyIncreasing()) {
animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime().value_or(AnimationTimeDelta()));
} else {
- animation->NotifyReady(monotonic_animation_start_time -
- animation->timeline()->ZeroTimeInSeconds());
+ animation->NotifyReady(
+ AnimationTimeDelta::FromSecondsD(monotonic_animation_start_time) -
+ animation->timeline()->ZeroTime());
}
}
}
@@ -192,7 +192,7 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
return;
// Start any main thread animations that were scheduled to wait on
- // compositor synchronization from a previous frame. Otherwise, an
+ // compositor synchronization from a previous frame. Otherwise, a
// continuous influx of new composited animations could delay the start
// of non-composited animations indefinitely (crbug.com/666710).
HeapVector<Member<Animation>> animations;
@@ -202,9 +202,8 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
waiting_for_compositor_animation_start_.push_back(animation);
} else {
DCHECK(animation->timeline()->IsActive() &&
- animation->timeline()->CurrentTimeSeconds());
- animation->NotifyReady(
- animation->timeline()->CurrentTimeSeconds().value_or(0));
+ animation->timeline()->CurrentTime());
+ animation->NotifyReady(animation->timeline()->CurrentTime().value());
}
}
}
@@ -212,6 +211,7 @@ void PendingAnimations::FlushWaitingNonCompositedAnimations() {
void PendingAnimations::Trace(Visitor* visitor) const {
visitor->Trace(pending_);
visitor->Trace(waiting_for_compositor_animation_start_);
+ visitor->Trace(timer_);
}
void PendingAnimations::TimerFired(TimerBase*) {
diff --git a/chromium/third_party/blink/renderer/core/animation/pending_animations.h b/chromium/third_party/blink/renderer/core/animation/pending_animations.h
index bc700e8b808..5a7c0f7deda 100644
--- a/chromium/third_party/blink/renderer/core/animation/pending_animations.h
+++ b/chromium/third_party/blink/renderer/core/animation/pending_animations.h
@@ -103,7 +103,7 @@ class CORE_EXPORT PendingAnimations final
HeapVector<Member<Animation>> pending_;
HeapVector<Member<Animation>> waiting_for_compositor_animation_start_;
- TaskRunnerTimer<PendingAnimations> timer_;
+ HeapTaskRunnerTimer<PendingAnimations> timer_;
int compositor_group_;
bool inside_timer_fired_;
};
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
index b260ad37970..259917a785b 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -138,17 +138,16 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
return nullptr;
}
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
if (options->scrollOffsets().IsEmpty()) {
// TODO(crbug.com/1094014): scroll_offsets will replace start and end
// offsets once spec decision on multiple scroll offsets is finalized.
// https://github.com/w3c/csswg-drafts/issues/4912
if (!start_scroll_offset->IsDefaultValue())
- scroll_offsets->push_back(start_scroll_offset);
+ scroll_offsets.push_back(start_scroll_offset);
if (!end_scroll_offset->IsDefaultValue() ||
!start_scroll_offset->IsDefaultValue())
- scroll_offsets->push_back(end_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
} else {
for (auto& offset : options->scrollOffsets()) {
ScrollTimelineOffset* scroll_offset =
@@ -159,13 +158,13 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
}
if (scroll_offset->IsDefaultValue() &&
(options->scrollOffsets().size() == 1 ||
- (scroll_offsets->size() + 1) < options->scrollOffsets().size())) {
+ (scroll_offsets.size() + 1) < options->scrollOffsets().size())) {
exception_state.ThrowTypeError(
"Invalid scrollOffsets: 'auto' can only be set as an end "
"offset when start offset presents.");
return nullptr;
}
- scroll_offsets->push_back(scroll_offset);
+ scroll_offsets.push_back(scroll_offset);
}
}
@@ -182,15 +181,14 @@ ScrollTimeline::ScrollTimeline(
Document* document,
Element* scroll_source,
ScrollDirection orientation,
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets,
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets,
base::Optional<double> time_range)
: AnimationTimeline(document),
scroll_source_(scroll_source),
resolved_scroll_source_(ResolveScrollSource(scroll_source_)),
orientation_(orientation),
- scroll_offsets_(scroll_offsets),
+ scroll_offsets_(std::move(scroll_offsets)),
time_range_(time_range) {
- DCHECK(scroll_offsets_);
if (resolved_scroll_source_) {
ScrollTimelineSet& set = GetScrollTimelineSet();
if (!set.Contains(resolved_scroll_source_)) {
@@ -222,14 +220,12 @@ bool ScrollTimeline::ComputeIsActive() const {
ScrollTimelineOffset* ScrollTimeline::StartScrollOffset() const {
// Single entry offset in scrollOffsets is considered as 'end'. Thus,
// resolving start offset only if there is at least 2 offsets.
- return scroll_offsets_ && scroll_offsets_->size() >= 2
- ? scroll_offsets_->at(0)
- : nullptr;
+ return scroll_offsets_.size() >= 2 ? scroll_offsets_.at(0) : nullptr;
}
ScrollTimelineOffset* ScrollTimeline::EndScrollOffset() const {
// End offset is always the last offset in scrollOffsets if exists.
- return scroll_offsets_ && scroll_offsets_->size() >= 1
- ? scroll_offsets_->at(scroll_offsets_->size() - 1)
+ return scroll_offsets_.size() >= 1
+ ? scroll_offsets_.at(scroll_offsets_.size() - 1)
: nullptr;
}
@@ -255,16 +251,16 @@ bool ScrollTimeline::ResolveScrollOffsets(
auto orientation = ToPhysicalScrollOrientation(orientation_, *layout_box);
- if (scroll_offsets_->size() == 0) {
+ if (scroll_offsets_.size() == 0) {
// Start and end offsets resolve to 'auto'.
resolved_offsets.push_back(0);
resolved_offsets.push_back(max_offset);
return true;
}
// Single entry offset in scrollOffsets is considered as 'end'.
- if (scroll_offsets_->size() == 1)
+ if (scroll_offsets_.size() == 1)
resolved_offsets.push_back(0);
- for (auto& offset : *scroll_offsets_) {
+ for (auto& offset : scroll_offsets_) {
auto resolved_offset = offset->ResolveOffset(
resolved_scroll_source_, orientation, max_offset, max_offset);
if (!resolved_offset) {
@@ -274,7 +270,6 @@ bool ScrollTimeline::ResolveScrollOffsets(
}
resolved_offsets.push_back(resolved_offset.value());
}
- // TODO(crbug.com/1094014): Implement clamping for overlapping offsets.
DCHECK_GE(resolved_offsets.size(), 2u);
return true;
}
@@ -286,12 +281,11 @@ AnimationTimeline::PhaseAndTime ScrollTimeline::CurrentPhaseAndTime() {
bool ScrollTimeline::ScrollOffsetsEqual(
const HeapVector<Member<ScrollTimelineOffset>>& other) const {
- DCHECK(scroll_offsets_);
- if (scroll_offsets_->size() != other.size())
+ if (scroll_offsets_.size() != other.size())
return false;
- size_t size = scroll_offsets_->size();
+ size_t size = scroll_offsets_.size();
for (size_t i = 0; i < size; ++i) {
- if (!DataEquivalent(scroll_offsets_->at(i), other.at(i)))
+ if (!DataEquivalent(scroll_offsets_.at(i), other.at(i)))
return false;
}
return true;
@@ -477,11 +471,7 @@ void ScrollTimeline::endScrollOffset(ScrollTimelineOffsetValue& out) const {
const HeapVector<ScrollTimelineOffsetValue> ScrollTimeline::scrollOffsets()
const {
HeapVector<ScrollTimelineOffsetValue> scroll_offsets;
-
- if (!scroll_offsets_)
- return scroll_offsets;
-
- for (auto& offset : *scroll_offsets_) {
+ for (auto& offset : scroll_offsets_) {
scroll_offsets.push_back(offset->ToScrollTimelineOffsetValue());
// 'auto' can only be the end offset.
DCHECK(!offset->IsDefaultValue() || scroll_offsets.size() == 2);
@@ -614,6 +604,14 @@ void ScrollTimeline::InvalidateEffectTargetStyle() {
animation->InvalidateEffectTargetStyle();
}
+void ScrollTimeline::ValidateState() {
+ auto state = ComputeTimelineState();
+ if (timeline_state_snapshotted_ == state)
+ return;
+ timeline_state_snapshotted_ = state;
+ InvalidateEffectTargetStyle();
+}
+
CompositorAnimationTimeline* ScrollTimeline::EnsureCompositorTimeline() {
if (compositor_timeline_)
return compositor_timeline_.get();
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
index 019885d471d..445af19f636 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -44,7 +44,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
ScrollTimeline(Document*,
Element*,
ScrollDirection,
- HeapVector<Member<ScrollTimelineOffset>>*,
+ HeapVector<Member<ScrollTimelineOffset>>,
base::Optional<double>);
bool IsScrollTimeline() const override { return true; }
@@ -53,7 +53,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
// https://github.com/WICG/scroll-animations/issues/31
bool IsActive() const override;
base::Optional<base::TimeDelta> InitialStartTimeForAnimations() override;
- double ZeroTimeInSeconds() override { return 0; }
+ AnimationTimeDelta ZeroTime() override { return AnimationTimeDelta(); }
void ServiceAnimations(TimingUpdateReason) override;
void ScheduleNextService() override;
@@ -95,6 +95,9 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
// for style recalc.
void InvalidateEffectTargetStyle();
+ // See DocumentAnimations::ValidateTimelines
+ void ValidateState();
+
CompositorAnimationTimeline* EnsureCompositorTimeline() override;
void UpdateCompositorTimeline() override;
@@ -126,6 +129,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
size_t AttachedAnimationsCount() const { return scroll_animations_.size(); }
private:
+ FRIEND_TEST_ALL_PREFIXES(ScrollTimelineTest, MultipleScrollOffsetsClamping);
// https://wicg.github.io/scroll-animations/#avoiding-cycles
// Snapshots scroll timeline current time and phase.
// Called once per animation frame.
@@ -166,7 +170,7 @@ class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
Member<Element> scroll_source_;
Member<Node> resolved_scroll_source_;
ScrollDirection orientation_;
- Member<HeapVector<Member<ScrollTimelineOffset>>> scroll_offsets_;
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets_;
base::Optional<double> time_range_;
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
index 7555b92eca1..6631be00e8e 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_offset.cc
@@ -58,8 +58,11 @@ bool ElementBasedOffsetsEqual(ScrollTimelineElementBasedOffset* o1,
return true;
if (!o1 || !o2)
return false;
- return (o1->edge() == o2->edge()) && (o1->target() == o2->target()) &&
- (o1->threshold() == o2->threshold());
+ // TODO(crbug.com/1070871): Use targetOr(nullptr) after migration is done.
+ Element* target_or_null1 = o1->hasTarget() ? o1->target() : nullptr;
+ Element* target_or_null2 = o2->hasTarget() ? o2->target() : nullptr;
+ return target_or_null1 == target_or_null2 && o1->edge() == o2->edge() &&
+ o1->threshold() == o2->threshold();
}
CSSKeywordValue* GetCSSKeywordValue(const ScrollTimelineOffsetValue& offset) {
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
index 5321591f55a..ac3d1cd6811 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
@@ -30,7 +30,7 @@ static constexpr double time_error_ms = 0.001 + 1e-13;
#define EXPECT_TIME_NEAR(expected, value) \
EXPECT_NEAR(expected, value, time_error_ms)
-HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> CreateScrollOffsets(
ScrollTimelineOffset* start_scroll_offset =
MakeGarbageCollected<ScrollTimelineOffset>(
CSSNumericLiteralValue::Create(
@@ -41,10 +41,9 @@ HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
CSSNumericLiteralValue::Create(
90.0,
CSSPrimitiveValue::UnitType::kPixels))) {
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
- scroll_offsets->push_back(start_scroll_offset);
- scroll_offsets->push_back(end_scroll_offset);
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
+ scroll_offsets.push_back(start_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
return scroll_offsets;
}
@@ -82,12 +81,12 @@ class TestScrollTimeline : public ScrollTimeline {
public:
TestScrollTimeline(Document* document,
Element* scroll_source,
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets =
CreateScrollOffsets())
: ScrollTimeline(document,
scroll_source,
ScrollTimeline::Vertical,
- scroll_offsets,
+ std::move(scroll_offsets),
100.0),
next_service_scheduled_(false) {}
@@ -801,7 +800,7 @@ TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
auto* scroller =
To<LayoutBoxModelObject>(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasNonVisibleOverflow());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
double time_range = 100.0;
@@ -879,4 +878,68 @@ TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
EXPECT_EQ(100, scroll_timeline->CurrentTimeMilliseconds().value());
}
+TEST_F(ScrollTimelineTest, OverlappingScrollOffsets) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller { overflow: scroll; width: 100px; height: 100px; }
+ #spacer { height: 1000px; }
+ </style>
+ <div id='scroller'>
+ <div id ='spacer'></div>
+ </div>
+ )HTML");
+
+ auto* scroller =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("scroller"));
+ ASSERT_TRUE(scroller);
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ ASSERT_TRUE(scrollable_area);
+ double time_range = 100.0;
+ ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
+ options->setTimeRange(
+ DoubleOrScrollTimelineAutoKeyword::FromDouble(time_range));
+ options->setScrollSource(GetElementById("scroller"));
+ HeapVector<ScrollTimelineOffsetValue> scroll_offsets = {
+ OffsetFromString("90px"), OffsetFromString("40px"),
+ OffsetFromString("10px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ ScrollTimeline* scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 80),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(0, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 95),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(100, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scroll_offsets = {OffsetFromString("0px"), OffsetFromString("100px"),
+ OffsetFromString("50px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 40),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(20, scroll_timeline->CurrentTimeMilliseconds().value());
+
+ scroll_offsets = {OffsetFromString("50px"), OffsetFromString("0px"),
+ OffsetFromString("100px")};
+ options->setScrollOffsets(scroll_offsets);
+
+ scroll_timeline =
+ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
+
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 60),
+ mojom::blink::ScrollType::kProgrammatic);
+ SimulateFrame();
+ EXPECT_EQ(80, scroll_timeline->CurrentTimeMilliseconds().value());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
index 9fe7b941f90..3e3a139d403 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
@@ -16,13 +16,12 @@ namespace blink {
namespace {
-HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> CreateScrollOffsets(
ScrollTimelineOffset* start_scroll_offset,
ScrollTimelineOffset* end_scroll_offset) {
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
- scroll_offsets->push_back(start_scroll_offset);
- scroll_offsets->push_back(end_scroll_offset);
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
+ scroll_offsets.push_back(start_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
return scroll_offsets;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
index 0b2840a787d..4503d3bb652 100644
--- a/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
+++ b/chromium/third_party/blink/renderer/core/animation/string_keyframe.cc
@@ -340,7 +340,7 @@ bool StringKeyframe::CSSPropertySpecificKeyframe::
const ComputedStyle* parent_style) const {
compositor_keyframe_value_cache_ =
StyleResolver::CreateCompositorKeyframeValueSnapshot(
- element, base_style, parent_style, property, value_.Get());
+ element, base_style, parent_style, property, value_.Get(), offset_);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc b/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
index 9c256e7127d..2162168aa4d 100644
--- a/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
+++ b/chromium/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
@@ -47,7 +47,7 @@ SVGPropertyBase* SVGPathInterpolationType::AppliedSVGValue(
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) const {
return MakeGarbageCollected<SVGPath>(
- MakeGarbageCollected<cssvalue::CSSPathValue>(
+ *MakeGarbageCollected<cssvalue::CSSPathValue>(
PathInterpolationFunctions::AppliedValue(interpolable_value,
non_interpolable_value)));
}
diff --git a/chromium/third_party/blink/renderer/core/animation/timing.cc b/chromium/third_party/blink/renderer/core/animation/timing.cc
index 5a6d39467f4..8d57548ca6c 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing.cc
+++ b/chromium/third_party/blink/renderer/core/animation/timing.cc
@@ -121,7 +121,7 @@ ComputedEffectTiming* Timing::getComputedTiming(
computed_timing->setLocalTime(
CSSNumberish::FromDouble(calculated_timing.local_time.value() * 1000));
} else {
- computed_timing->setLocalTimeToNull();
+ computed_timing->setLocalTime(CSSNumberish());
}
if (calculated_timing.is_in_effect) {
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
index b1ca293f721..2173cc75e7a 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
+++ b/chromium/third_party/blink/renderer/core/animation/timing_calculations.h
@@ -56,10 +56,14 @@ static inline bool IsWithinAnimationTimeEpsilon(double a, double b) {
return std::abs(a - b) <= TimingCalculationEpsilon();
}
-inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
+static inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
return a <= b + TimingCalculationEpsilon();
}
+static inline bool GreaterThanOrEqualToWithinEpsilon(double a, double b) {
+ return a >= b - TimingCalculationEpsilon();
+}
+
static inline double MultiplyZeroAlwaysGivesZero(double x, double y) {
DCHECK(!std::isnan(x));
DCHECK(!std::isnan(y));
diff --git a/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc b/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
index f5b7c8f7498..98834571a87 100644
--- a/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
+++ b/chromium/third_party/blink/renderer/core/animation/timing_input_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/animation/timing_input.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_animation_options.h"
#include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
diff --git a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
index e8c75ae0538..a5b39a1c6a0 100644
--- a/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
+++ b/chromium/third_party/blink/renderer/core/animation/transition_keyframe.h
@@ -78,6 +78,8 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
bool IsTransitionPropertySpecificKeyframe() const final { return true; }
+ const TypedInterpolationValue* GetValue() const { return value_.get(); }
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
index fd899c25b55..0ab3b9a41db 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.cc
@@ -94,19 +94,17 @@ void WorkletAnimationController::ScrollSourceCompositingStateChanged(
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
WorkletAnimationController::EnsureMainThreadMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner) {
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher;
- if (!mutator_task_runner_) {
+ if (!main_thread_mutator_client_) {
main_thread_mutator_client_ =
AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
- &mutator_dispatcher, &mutator_task_runner_);
+ mutator_dispatcher, std::move(mutator_task_runner));
main_thread_mutator_client_->SetDelegate(this);
}
DCHECK(main_thread_mutator_client_);
- DCHECK(mutator_task_runner_);
DCHECK(mutator_dispatcher);
- *mutator_task_runner = mutator_task_runner_;
return mutator_dispatcher;
}
diff --git a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
index b9f5cad9e1d..b365819b6da 100644
--- a/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
+++ b/chromium/third_party/blink/renderer/core/animation/worklet_animation_controller.h
@@ -20,6 +20,7 @@ namespace blink {
class AnimationWorkletMutatorDispatcherImpl;
class Document;
class MainThreadMutatorClient;
+class Node;
class WorkletAnimationBase;
// Handles AnimationWorklet animations on the main-thread.
@@ -36,7 +37,7 @@ class CORE_EXPORT WorkletAnimationController
: public GarbageCollected<WorkletAnimationController>,
public MutatorClient {
public:
- WorkletAnimationController(Document*);
+ explicit WorkletAnimationController(Document*);
~WorkletAnimationController() override;
void AttachAnimation(WorkletAnimationBase&);
@@ -54,7 +55,7 @@ class CORE_EXPORT WorkletAnimationController
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
EnsureMainThreadMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner);
void SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output) override;
@@ -79,7 +80,6 @@ class CORE_EXPORT WorkletAnimationController
// TODO(crbug.com/1090515): The following proxy is needed for platform/ to
// access this class. We should bypass it eventually.
std::unique_ptr<MainThreadMutatorClient> main_thread_mutator_client_;
- scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner_;
Member<Document> document_;
};
diff --git a/chromium/third_party/blink/renderer/core/animation_frame/DIR_METADATA b/chromium/third_party/blink/renderer/core/animation_frame/DIR_METADATA
new file mode 100644
index 00000000000..4ae95d48d73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/animation_frame/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Canvas"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/animation_frame/OWNERS b/chromium/third_party/blink/renderer/core/animation_frame/OWNERS
index 5ef87b1aa3f..1e563633b29 100644
--- a/chromium/third_party/blink/renderer/core/animation_frame/OWNERS
+++ b/chromium/third_party/blink/renderer/core/animation_frame/OWNERS
@@ -1,4 +1 @@
fserb@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
diff --git a/chromium/third_party/blink/renderer/core/aom/DIR_METADATA b/chromium/third_party/blink/renderer/core/aom/DIR_METADATA
new file mode 100644
index 00000000000..7a89266091b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/aom/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Accessibility"
+}
+
+team_email: "chromium-accessibility@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/aom/OWNERS b/chromium/third_party/blink/renderer/core/aom/OWNERS
index 5eed66eb588..4e6cc130180 100644
--- a/chromium/third_party/blink/renderer/core/aom/OWNERS
+++ b/chromium/third_party/blink/renderer/core/aom/OWNERS
@@ -1,4 +1 @@
file://third_party/blink/renderer/modules/accessibility/OWNERS
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: Blink>Accessibility
diff --git a/chromium/third_party/blink/renderer/core/aom/accessible_node.cc b/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
index 62252d26747..78a92e61b9a 100644
--- a/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
+++ b/chromium/third_party/blink/renderer/core/aom/accessible_node.cc
@@ -55,6 +55,8 @@ QualifiedName GetCorrespondingARIAAttribute(AOMStringProperty property) {
return html_names::kAriaSortAttr;
case AOMStringProperty::kValueText:
return html_names::kAriaValuetextAttr;
+ case AOMStringProperty::kVirtualContent:
+ return html_names::kAriaVirtualcontentAttr;
}
NOTREACHED();
@@ -910,6 +912,15 @@ void AccessibleNode::setValueText(const AtomicString& value_text) {
NotifyAttributeChanged(html_names::kAriaValuetextAttr);
}
+AtomicString AccessibleNode::virtualContent() const {
+ return GetProperty(AOMStringProperty::kVirtualContent);
+}
+
+void AccessibleNode::setVirtualContent(const AtomicString& virtual_content) {
+ SetStringProperty(AOMStringProperty::kVirtualContent, virtual_content);
+ NotifyAttributeChanged(html_names::kAriaVirtualcontentAttr);
+}
+
AccessibleNodeList* AccessibleNode::childNodes() {
return AccessibleNodeList::Create(children_);
}
@@ -991,6 +1002,7 @@ bool AccessibleNode::IsStringTokenProperty(AOMStringProperty property) {
// supported.
case AOMStringProperty::kRoleDescription:
case AOMStringProperty::kValueText:
+ case AOMStringProperty::kVirtualContent:
break;
}
return false;
diff --git a/chromium/third_party/blink/renderer/core/aom/accessible_node.h b/chromium/third_party/blink/renderer/core/aom/accessible_node.h
index 65d019df381..5858559030f 100644
--- a/chromium/third_party/blink/renderer/core/aom/accessible_node.h
+++ b/chromium/third_party/blink/renderer/core/aom/accessible_node.h
@@ -40,7 +40,8 @@ enum class AOMStringProperty {
kRole,
kRoleDescription,
kSort,
- kValueText
+ kValueText,
+ kVirtualContent
};
// All of the properties of AccessibleNode that have type "boolean".
@@ -337,6 +338,9 @@ class CORE_EXPORT AccessibleNode : public EventTargetWithInlineData {
AtomicString valueText() const;
void setValueText(const AtomicString&);
+ AtomicString virtualContent() const;
+ void setVirtualContent(const AtomicString&);
+
AccessibleNodeList* childNodes();
void appendChild(AccessibleNode*, ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/clipboard/DIR_METADATA b/chromium/third_party/blink/renderer/core/clipboard/DIR_METADATA
new file mode 100644
index 00000000000..ae781d07399
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/clipboard/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>DataTransfer"
+}
+
+team_email: "storage-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/clipboard/OWNERS b/chromium/third_party/blink/renderer/core/clipboard/OWNERS
index ddb3f8e0cbc..9d11d8bcf13 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/OWNERS
+++ b/chromium/third_party/blink/renderer/core/clipboard/OWNERS
@@ -4,6 +4,3 @@ huangdarwin@chromium.org
# Secondary:
dcheng@chromium.org
pwnall@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>DataTransfer
diff --git a/chromium/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc b/chromium/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
index 45e0b1b4327..5234fc5c8bb 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
+#include "base/i18n/uchar.h"
#include "net/base/escape.h"
#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -75,8 +76,9 @@ static String EscapeForHTML(const String& str) {
{reinterpret_cast<const char*>(str.Characters8()), str.length()});
return String(result.data(), result.size());
}
- auto result = net::EscapeForHTML({str.Characters16(), str.length()});
- return String(result.data(), result.size());
+ auto result = net::EscapeForHTML(
+ {base::i18n::ToChar16Ptr(str.Characters16()), str.length()});
+ return String(base::i18n::ToUCharPtr(result.data()), result.size());
}
String URLToImageMarkup(const KURL& url, const String& title) {
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_object.cc b/chromium/third_party/blink/renderer/core/clipboard/data_object.cc
index 763ca4421e9..58d1c47df2c 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_object.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -30,7 +30,9 @@
#include "third_party/blink/renderer/core/clipboard/data_object.h"
+#include "base/feature_list.h"
#include "base/notreached.h"
+#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_drag_data.h"
#include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
@@ -40,6 +42,7 @@
#include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
#include "third_party/blink/renderer/platform/file_metadata.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "ui/base/ui_base_features.h"
namespace blink {
@@ -54,8 +57,28 @@ DataObject* DataObject::CreateFromClipboard(SystemClipboard* system_clipboard,
for (const String& type : system_clipboard->ReadAvailableTypes()) {
if (paste_mode == PasteMode::kPlainTextOnly && type != kMimeTypeTextPlain)
continue;
- data_object->item_list_.push_back(DataObjectItem::CreateFromClipboard(
- system_clipboard, type, sequence_number));
+ mojom::blink::ClipboardFilesPtr files;
+ if (type == kMimeTypeTextURIList &&
+ base::FeatureList::IsEnabled(features::kClipboardFilenames)) {
+ files = system_clipboard->ReadFiles();
+ // Ignore ReadFiles() result if clipboard sequence number has changed.
+ if (system_clipboard->SequenceNumber() != sequence_number) {
+ files->files.clear();
+ }
+ for (const mojom::blink::DataTransferFilePtr& file : files->files) {
+ data_object->AddFilename(
+ FilePathToString(file->path), FilePathToString(file->display_name),
+ files->file_system_id,
+ base::MakeRefCounted<FileSystemAccessDropData>(
+ std::move(file->file_system_access_token)));
+ }
+ }
+ if (files && !files->files.IsEmpty()) {
+ DraggedIsolatedFileSystem::PrepareForDataObject(data_object);
+ } else {
+ data_object->item_list_.push_back(DataObjectItem::CreateFromClipboard(
+ system_clipboard, type, sequence_number));
+ }
#if DCHECK_IS_ON()
DCHECK(types_seen.insert(type).is_new_entry);
#endif
@@ -230,10 +253,10 @@ void DataObject::AddFilename(
const String& filename,
const String& display_name,
const String& file_system_id,
- scoped_refptr<NativeFileSystemDropData> native_file_system_entry) {
+ scoped_refptr<FileSystemAccessDropData> file_system_access_entry) {
InternalAddFileItem(DataObjectItem::CreateFromFileWithFileSystemId(
File::CreateForUserProvidedFile(filename, display_name), file_system_id,
- std::move(native_file_system_entry)));
+ std::move(file_system_access_entry)));
}
void DataObject::AddSharedBuffer(scoped_refptr<SharedBuffer> buffer,
@@ -308,7 +331,7 @@ DataObject* DataObject::Create(WebDragData data) {
has_file_system = true;
data_object->AddFilename(item.filename_data, item.display_name_data,
data.FilesystemId(),
- item.native_file_system_entry);
+ item.file_system_access_entry);
break;
case WebDragData::Item::kStorageTypeBinaryData:
// This should never happen when dragging in.
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_object.h b/chromium/third_party/blink/renderer/core/clipboard/data_object.h
index b621b8e4fe0..d7982fb7c19 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_object.h
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_object.h
@@ -99,8 +99,8 @@ class CORE_EXPORT DataObject : public GarbageCollected<DataObject>,
void AddFilename(const String& filename,
const String& display_name,
const String& file_system_id,
- scoped_refptr<NativeFileSystemDropData>
- native_file_system_entry = nullptr);
+ scoped_refptr<FileSystemAccessDropData>
+ file_system_access_entry = nullptr);
// Used for dragging in filesystem from the desktop.
void SetFilesystemId(const String& file_system_id) {
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_object_item.cc b/chromium/third_party/blink/renderer/core/clipboard/data_object_item.cc
index 800ce7d6c43..c0546a3cbba 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_object_item.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_object_item.cc
@@ -31,7 +31,7 @@
#include "third_party/blink/renderer/core/clipboard/data_object_item.h"
#include "base/time/time.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/file_system_access_data_transfer_token.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
#include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
@@ -63,12 +63,12 @@ DataObjectItem* DataObjectItem::CreateFromFile(File* file) {
DataObjectItem* DataObjectItem::CreateFromFileWithFileSystemId(
File* file,
const String& file_system_id,
- scoped_refptr<NativeFileSystemDropData> native_file_entry) {
+ scoped_refptr<FileSystemAccessDropData> file_system_access_entry) {
DataObjectItem* item =
MakeGarbageCollected<DataObjectItem>(kFileKind, file->type());
item->file_ = file;
item->file_system_id_ = file_system_id;
- item->native_file_system_entry_ = native_file_entry;
+ item->file_system_access_entry_ = file_system_access_entry;
return item;
}
@@ -225,18 +225,19 @@ String DataObjectItem::FileSystemId() const {
return file_system_id_;
}
-bool DataObjectItem::HasNativeFileSystemEntry() const {
- return static_cast<bool>(native_file_system_entry_);
+bool DataObjectItem::HasFileSystemAccessEntry() const {
+ return static_cast<bool>(file_system_access_entry_);
}
-mojo::PendingRemote<mojom::blink::NativeFileSystemDragDropToken>
-DataObjectItem::CloneNativeFileSystemEntryToken() const {
- DCHECK(HasNativeFileSystemEntry());
- mojo::Remote<mojom::blink::NativeFileSystemDragDropToken> token_cloner(
- std::move(native_file_system_entry_->data));
- mojo::PendingRemote<mojom::blink::NativeFileSystemDragDropToken> token_clone;
+mojo::PendingRemote<mojom::blink::FileSystemAccessDataTransferToken>
+DataObjectItem::CloneFileSystemAccessEntryToken() const {
+ DCHECK(HasFileSystemAccessEntry());
+ mojo::Remote<mojom::blink::FileSystemAccessDataTransferToken> token_cloner(
+ std::move(file_system_access_entry_->data));
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDataTransferToken>
+ token_clone;
token_cloner->Clone(token_clone.InitWithNewPipeAndPassReceiver());
- native_file_system_entry_->data = token_cloner.Unbind();
+ file_system_access_entry_->data = token_cloner.Unbind();
return token_clone;
}
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_object_item.h b/chromium/third_party/blink/renderer/core/clipboard/data_object_item.h
index 5a9c4c137d9..f79f3e1d5f9 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_object_item.h
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_object_item.h
@@ -33,8 +33,7 @@
#include "base/optional.h"
#include "mojo/public/cpp/bindings/remote.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_transfer_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_data_transfer_token.mojom-blink.h"
#include "third_party/blink/public/platform/web_drag_data.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/fileapi/file.h"
@@ -60,7 +59,8 @@ class CORE_EXPORT DataObjectItem final
static DataObjectItem* CreateFromFileWithFileSystemId(
File*,
const String& file_system_id,
- scoped_refptr<NativeFileSystemDropData> native_file_entry = nullptr);
+ scoped_refptr<FileSystemAccessDropData> file_system_access_entry =
+ nullptr);
static DataObjectItem* CreateFromURL(const String& url, const String& title);
static DataObjectItem* CreateFromHTML(const String& html,
const KURL& base_url);
@@ -95,9 +95,9 @@ class CORE_EXPORT DataObjectItem final
bool HasFileSystemId() const;
String FileSystemId() const;
- bool HasNativeFileSystemEntry() const;
- mojo::PendingRemote<mojom::blink::NativeFileSystemDragDropToken>
- CloneNativeFileSystemEntryToken() const;
+ bool HasFileSystemAccessEntry() const;
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDataTransferToken>
+ CloneFileSystemAccessEntryToken() const;
void Trace(Visitor*) const;
@@ -107,7 +107,7 @@ class CORE_EXPORT DataObjectItem final
kInternalSource,
};
- scoped_refptr<NativeFileSystemDropData> native_file_system_entry_;
+ scoped_refptr<FileSystemAccessDropData> file_system_access_entry_;
DataSource source_;
ItemKind kind_;
String type_;
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
index ecc7cf0845d..1bc41417bbf 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -60,6 +60,7 @@
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
namespace blink {
@@ -147,7 +148,6 @@ class DraggedNodeImageBuilder {
return DataTransfer::CreateDragImageForFrame(
*local_frame_, 1.0f,
- LayoutObject::ShouldRespectImageOrientation(dragged_layout_object),
bounding_box.Size(), paint_offset, builder, border_box_properties);
}
@@ -159,10 +159,8 @@ class DraggedNodeImageBuilder {
#endif
};
-} // namespace
-
-static base::Optional<DragOperation> ConvertEffectAllowedToDragOperation(
- const String& op) {
+base::Optional<DragOperationsMask> ConvertEffectAllowedToDragOperationsMask(
+ const AtomicString& op) {
// Values specified in
// https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-effectallowed
if (op == "uninitialized")
@@ -175,18 +173,24 @@ static base::Optional<DragOperation> ConvertEffectAllowedToDragOperation(
return kDragOperationLink;
if (op == "move")
return kDragOperationMove;
- if (op == "copyLink")
- return static_cast<DragOperation>(kDragOperationCopy | kDragOperationLink);
- if (op == "copyMove")
- return static_cast<DragOperation>(kDragOperationCopy | kDragOperationMove);
- if (op == "linkMove")
- return static_cast<DragOperation>(kDragOperationLink | kDragOperationMove);
+ if (op == "copyLink") {
+ return static_cast<DragOperationsMask>(kDragOperationCopy |
+ kDragOperationLink);
+ }
+ if (op == "copyMove") {
+ return static_cast<DragOperationsMask>(kDragOperationCopy |
+ kDragOperationMove);
+ }
+ if (op == "linkMove") {
+ return static_cast<DragOperationsMask>(kDragOperationLink |
+ kDragOperationMove);
+ }
if (op == "all")
return kDragOperationEvery;
return base::nullopt;
}
-static String ConvertDragOperationToEffectAllowed(DragOperation op) {
+AtomicString ConvertDragOperationsMaskToEffectAllowed(DragOperationsMask op) {
if (((op & kDragOperationMove) && (op & kDragOperationCopy) &&
(op & kDragOperationLink)) ||
(op == kDragOperationEvery))
@@ -209,8 +213,7 @@ static String ConvertDragOperationToEffectAllowed(DragOperation op) {
// We provide the IE clipboard types (URL and Text), and the clipboard types
// specified in the HTML spec. See
// https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface
-static String NormalizeType(const String& type,
- bool* convert_to_url = nullptr) {
+String NormalizeType(const String& type, bool* convert_to_url = nullptr) {
String clean_type = type.StripWhiteSpace().LowerASCII();
if (clean_type == kMimeTypeText ||
clean_type.StartsWith(kMimeTypeTextPlainEtc))
@@ -223,6 +226,8 @@ static String NormalizeType(const String& type,
return clean_type;
}
+} // namespace
+
// static
DataTransfer* DataTransfer::Create() {
DataTransfer* data = Create(
@@ -241,7 +246,7 @@ DataTransfer* DataTransfer::Create(DataTransferType type,
DataTransfer::~DataTransfer() = default;
-void DataTransfer::setDropEffect(const String& effect) {
+void DataTransfer::setDropEffect(const AtomicString& effect) {
if (!IsForDragAndDrop())
return;
@@ -253,18 +258,14 @@ void DataTransfer::setDropEffect(const String& effect) {
// The specification states that dropEffect can be changed at all times, even
// if the DataTransfer instance is protected or neutered.
- //
- // Allowing these changes seems inconsequential, but findDropZone() in
- // EventHandler.cpp relies on being able to call setDropEffect during
- // dragenter, when the DataTransfer policy is DataTransferTypesReadable.
drop_effect_ = effect;
}
-void DataTransfer::setEffectAllowed(const String& effect) {
+void DataTransfer::setEffectAllowed(const AtomicString& effect) {
if (!IsForDragAndDrop())
return;
- if (!ConvertEffectAllowedToDragOperation(effect)) {
+ if (!ConvertEffectAllowedToDragOperationsMask(effect)) {
// This means that there was no conversion, and the effectAllowed that
// we are passed isn't a valid effectAllowed, so we should ignore it,
// and not set |effect_allowed_|.
@@ -392,7 +393,6 @@ FloatSize DataTransfer::DeviceSpaceSize(const FloatSize& css_size,
std::unique_ptr<DragImage> DataTransfer::CreateDragImageForFrame(
LocalFrame& frame,
float opacity,
- RespectImageOrientationEnum image_orientation,
const FloatSize& css_size,
const FloatPoint& paint_offset,
PaintRecordBuilder& builder,
@@ -425,7 +425,10 @@ std::unique_ptr<DragImage> DataTransfer::CreateDragImageForFrame(
float screen_device_scale_factor =
chrome_client.GetScreenInfo(frame).device_scale_factor;
- return DragImage::Create(image.get(), image_orientation,
+ // There is no orientation information in the image, so pass
+ // kDoNotRespectImageOrientation in order to avoid wasted work looking
+ // at orientation.
+ return DragImage::Create(image.get(), kDoNotRespectImageOrientation,
screen_device_scale_factor, kInterpolationDefault,
opacity);
}
@@ -559,41 +562,27 @@ bool DataTransfer::CanSetDragImage() const {
policy_ == DataTransferAccessPolicy::kWritable;
}
-DragOperation DataTransfer::SourceOperation() const {
- base::Optional<DragOperation> op =
- ConvertEffectAllowedToDragOperation(effect_allowed_);
+DragOperationsMask DataTransfer::SourceOperation() const {
+ base::Optional<DragOperationsMask> op =
+ ConvertEffectAllowedToDragOperationsMask(effect_allowed_);
DCHECK(op);
return *op;
}
-DragOperation DataTransfer::DestinationOperation() const {
- base::Optional<DragOperation> op =
- ConvertEffectAllowedToDragOperation(drop_effect_);
- DCHECK(op == kDragOperationCopy || op == kDragOperationNone ||
- op == kDragOperationLink || op == kDragOperationMove ||
- op == kDragOperationEvery);
- return *op;
+ui::mojom::blink::DragOperation DataTransfer::DestinationOperation() const {
+ DCHECK(DropEffectIsInitialized());
+ base::Optional<DragOperationsMask> op =
+ ConvertEffectAllowedToDragOperationsMask(drop_effect_);
+ return static_cast<ui::mojom::blink::DragOperation>(*op);
}
-void DataTransfer::SetSourceOperation(DragOperation op) {
- DCHECK_NE(op, kDragOperationPrivate);
- effect_allowed_ = ConvertDragOperationToEffectAllowed(op);
+void DataTransfer::SetSourceOperation(DragOperationsMask op) {
+ effect_allowed_ = ConvertDragOperationsMaskToEffectAllowed(op);
}
-void DataTransfer::SetDestinationOperation(DragOperation op) {
- DCHECK(op == kDragOperationCopy || op == kDragOperationNone ||
- op == kDragOperationLink || op == kDragOperationMove);
- drop_effect_ = ConvertDragOperationToEffectAllowed(op);
-}
-
-bool DataTransfer::HasDropZoneType(const String& keyword) {
- if (keyword.StartsWith("file:"))
- return HasFileOfType(keyword.Substring(5));
-
- if (keyword.StartsWith("string:"))
- return HasStringOfType(keyword.Substring(7));
-
- return false;
+void DataTransfer::SetDestinationOperation(ui::mojom::blink::DragOperation op) {
+ drop_effect_ = ConvertDragOperationsMaskToEffectAllowed(
+ static_cast<DragOperationsMask>(op));
}
DataTransferItemList* DataTransfer::items() {
@@ -612,7 +601,6 @@ DataTransfer::DataTransfer(DataTransferType type,
DataTransferAccessPolicy policy,
DataObject* data_object)
: policy_(policy),
- drop_effect_("uninitialized"),
effect_allowed_("uninitialized"),
transfer_type_(type),
data_object_(data_object),
@@ -653,30 +641,6 @@ bool DataTransfer::HasStringOfType(const String& type) const {
return data_object_->Types().Contains(type);
}
-DragOperation ConvertDropZoneOperationToDragOperation(
- const String& drag_operation) {
- if (drag_operation == "copy")
- return kDragOperationCopy;
- if (drag_operation == "move")
- return kDragOperationMove;
- if (drag_operation == "link")
- return kDragOperationLink;
- return kDragOperationNone;
-}
-
-String ConvertDragOperationToDropZoneOperation(DragOperation operation) {
- switch (operation) {
- case kDragOperationCopy:
- return String("copy");
- case kDragOperationMove:
- return String("move");
- case kDragOperationLink:
- return String("link");
- default:
- return String("copy");
- }
-}
-
void DataTransfer::Trace(Visitor* visitor) const {
visitor->Trace(data_object_);
visitor->Trace(drag_image_);
diff --git a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.h b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.h
index 5887f8abead..8884592ff33 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/data_transfer.h
+++ b/chromium/third_party/blink/renderer/core/clipboard/data_transfer.h
@@ -25,6 +25,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CLIPBOARD_DATA_TRANSFER_H_
#include <memory>
+
#include "third_party/blink/public/common/page/drag_operation.h"
#include "third_party/blink/renderer/core/clipboard/data_object.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -33,6 +34,8 @@
#include "third_party/blink/renderer/platform/geometry/int_point.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h"
namespace blink {
@@ -77,15 +80,13 @@ class CORE_EXPORT DataTransfer final : public ScriptWrappable,
bool IsForCopyAndPaste() const { return transfer_type_ == kCopyAndPaste; }
bool IsForDragAndDrop() const { return transfer_type_ == kDragAndDrop; }
- String dropEffect() const {
- return DropEffectIsUninitialized() ? "none" : drop_effect_;
- }
- void setDropEffect(const String&);
- bool DropEffectIsUninitialized() const {
- return drop_effect_ == "uninitialized";
+ AtomicString dropEffect() const {
+ return DropEffectIsInitialized() ? drop_effect_ : "none";
}
- String effectAllowed() const { return effect_allowed_; }
- void setEffectAllowed(const String&);
+ void setDropEffect(const AtomicString&);
+ bool DropEffectIsInitialized() const { return !drop_effect_.IsNull(); }
+ AtomicString effectAllowed() const { return effect_allowed_; }
+ void setEffectAllowed(const AtomicString&);
void clearData(const String& type = String());
String getData(const String& type) const;
@@ -123,12 +124,10 @@ class CORE_EXPORT DataTransfer final : public ScriptWrappable,
// anyway.
bool CanSetDragImage() const;
- DragOperation SourceOperation() const;
- DragOperation DestinationOperation() const;
- void SetSourceOperation(DragOperation);
- void SetDestinationOperation(DragOperation);
-
- bool HasDropZoneType(const String&);
+ DragOperationsMask SourceOperation() const;
+ ui::mojom::blink::DragOperation DestinationOperation() const;
+ void SetSourceOperation(DragOperationsMask);
+ void SetDestinationOperation(ui::mojom::blink::DragOperation);
DataTransferItemList* items();
@@ -148,7 +147,6 @@ class CORE_EXPORT DataTransfer final : public ScriptWrappable,
static std::unique_ptr<DragImage> CreateDragImageForFrame(
LocalFrame&,
float,
- RespectImageOrientationEnum,
const FloatSize& css_size,
const FloatPoint& paint_offset,
PaintRecordBuilder&,
@@ -169,8 +167,8 @@ class CORE_EXPORT DataTransfer final : public ScriptWrappable,
// Instead of using this member directly, prefer to use the can*() methods
// above.
DataTransferAccessPolicy policy_;
- String drop_effect_;
- String effect_allowed_;
+ AtomicString drop_effect_;
+ AtomicString effect_allowed_;
DataTransferType transfer_type_;
Member<DataObject> data_object_;
@@ -181,10 +179,6 @@ class CORE_EXPORT DataTransfer final : public ScriptWrappable,
Member<Node> drag_image_element_;
};
-DragOperation ConvertDropZoneOperationToDragOperation(
- const String& drag_operation);
-String ConvertDragOperationToDropZoneOperation(DragOperation);
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CLIPBOARD_DATA_TRANSFER_H_
diff --git a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
index 3a11329c7ed..63a692a642a 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
+++ b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -8,6 +8,7 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "mojo/public/cpp/system/platform_handle.h"
+#include "skia/ext/skia_utils_base.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"
@@ -42,10 +43,10 @@ SystemClipboard::SystemClipboard(LocalFrame* frame)
frame->GetBrowserInterfaceBroker().GetInterface(
clipboard_.BindNewPipeAndPassReceiver(
frame->GetTaskRunner(TaskType::kUserInteraction)));
-#if defined(OS_LINUX) || BUILDFLAG(IS_LACROS)
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
is_selection_buffer_available_ =
frame->GetSettings()->GetSelectionClipboardBufferAvailable();
-#endif // defined(OS_LINUX) || BUILDFLAG(IS_LACROS)
+#endif // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
}
bool SystemClipboard::IsSelectionMode() const {
@@ -183,7 +184,15 @@ void SystemClipboard::WriteImageWithTag(Image* image,
SkBitmap bitmap;
if (sk_sp<SkImage> sk_image = paint_image.GetSwSkImage())
sk_image->asLegacyBitmap(&bitmap);
- clipboard_->WriteImage(bitmap);
+ // The bitmap backing a canvas can be in non-native skia pixel order (aka
+ // RGBA when kN32_SkColorType is BGRA-ordered, or higher bit-depth color-types
+ // like F16. The IPC to the browser requires the bitmap to be in N32 format
+ // so we convert it here if needed.
+ SkBitmap n32_bitmap;
+ if (skia::SkBitmapToN32OpaqueOrPremul(bitmap, &n32_bitmap))
+ clipboard_->WriteImage(n32_bitmap);
+ else
+ clipboard_->WriteImage(SkBitmap());
if (url.IsValid() && !url.IsEmpty()) {
#if !defined(OS_MAC)
@@ -206,6 +215,14 @@ void SystemClipboard::WriteImage(const SkBitmap& bitmap) {
clipboard_->WriteImage(bitmap);
}
+mojom::blink::ClipboardFilesPtr SystemClipboard::ReadFiles() {
+ mojom::blink::ClipboardFilesPtr files;
+ if (!IsValidBufferType(buffer_) || !clipboard_.is_bound())
+ return files;
+ clipboard_->ReadFiles(buffer_, &files);
+ return files;
+}
+
String SystemClipboard::ReadCustomData(const String& type) {
if (!IsValidBufferType(buffer_) || !clipboard_.is_bound())
return String();
diff --git a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
index ff393ac412f..52420eb13a4 100644
--- a/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
+++ b/chromium/third_party/blink/renderer/core/clipboard/system_clipboard.h
@@ -70,6 +70,9 @@ class CORE_EXPORT SystemClipboard final
// Write the image only.
void WriteImage(const SkBitmap&);
+ // Read files.
+ mojom::blink::ClipboardFilesPtr ReadFiles();
+
String ReadCustomData(const String& type);
void WriteDataObject(DataObject*);
diff --git a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.cc b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.cc
index 21f46317590..5c9dd3d0f4f 100644
--- a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.cc
+++ b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.cc
@@ -46,7 +46,12 @@ void ContentCaptureTask::TaskDelay::IncreaseDelayExponent() {
ContentCaptureTask::ContentCaptureTask(LocalFrame& local_frame_root,
TaskSession& task_session)
- : local_frame_root_(&local_frame_root), task_session_(&task_session) {
+ : local_frame_root_(&local_frame_root),
+ task_session_(&task_session),
+ delay_task_(
+ local_frame_root_->GetTaskRunner(TaskType::kInternalContentCapture),
+ this,
+ &ContentCaptureTask::Run) {
base::TimeDelta task_short_delay;
base::TimeDelta task_long_delay;
@@ -268,22 +273,14 @@ void ContentCaptureTask::ScheduleInternal(ScheduleReason reason) {
base::TimeDelta delay = GetAndAdjustDelay(reason);
// Return if the current task is about to run soon.
- if (delay_task_ && delay_task_->IsActive() &&
- delay_task_->NextFireInterval() < delay) {
+ if (delay_task_.IsActive() && delay_task_.NextFireInterval() < delay) {
return;
}
- if (!delay_task_) {
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- local_frame_root_->GetTaskRunner(TaskType::kInternalContentCapture);
- delay_task_ = std::make_unique<TaskRunnerTimer<ContentCaptureTask>>(
- task_runner, this, &ContentCaptureTask::Run);
- }
-
- if (delay_task_->IsActive())
- delay_task_->Stop();
+ if (delay_task_.IsActive())
+ delay_task_.Stop();
- delay_task_->StartOneShot(delay, FROM_HERE);
+ delay_task_.StartOneShot(delay, FROM_HERE);
TRACE_EVENT_INSTANT1("content_capture", "ScheduleTask",
TRACE_EVENT_SCOPE_THREAD, "reason", reason);
if (histogram_reporter_) {
@@ -308,17 +305,16 @@ bool ContentCaptureTask::ShouldPause() {
}
void ContentCaptureTask::CancelTask() {
- if (delay_task_ && delay_task_->IsActive())
- delay_task_->Stop();
+ if (delay_task_.IsActive())
+ delay_task_.Stop();
}
void ContentCaptureTask::ClearDocumentSessionsForTesting() {
task_session_->ClearDocumentSessionsForTesting();
}
base::TimeDelta ContentCaptureTask::GetTaskNextFireIntervalForTesting() const {
- return delay_task_ && delay_task_->IsActive()
- ? delay_task_->NextFireInterval()
- : base::TimeDelta();
+ return delay_task_.IsActive() ? delay_task_.NextFireInterval()
+ : base::TimeDelta();
}
void ContentCaptureTask::CancelTaskForTesting() {
@@ -328,6 +324,7 @@ void ContentCaptureTask::CancelTaskForTesting() {
void ContentCaptureTask::Trace(Visitor* visitor) const {
visitor->Trace(local_frame_root_);
visitor->Trace(task_session_);
+ visitor->Trace(delay_task_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.h b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.h
index aa426d98f80..77cfabacc82 100644
--- a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.h
+++ b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h"
#include "third_party/blink/renderer/core/content_capture/task_session.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -142,7 +143,7 @@ class CORE_EXPORT ContentCaptureTask
Member<LocalFrame> local_frame_root_;
Member<TaskSession> task_session_;
- std::unique_ptr<TaskRunnerTimer<ContentCaptureTask>> delay_task_;
+ HeapTaskRunnerTimer<ContentCaptureTask> delay_task_;
TaskState task_state_ = TaskState::kStop;
std::unique_ptr<TaskDelay> task_delay_;
diff --git a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
index 1cb90c88f41..b533148b1df 100644
--- a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
+++ b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.cc
@@ -4,6 +4,7 @@
#include <utility>
+#include "base/metrics/histogram_functions.h"
#include "third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h"
namespace blink {
@@ -17,14 +18,8 @@ constexpr char ContentCaptureTaskHistogramReporter::kTaskDelayInMs[];
constexpr char ContentCaptureTaskHistogramReporter::kTaskRunsPerCapture[];
ContentCaptureTaskHistogramReporter::ContentCaptureTaskHistogramReporter()
- : capture_content_delay_time_histogram_(kCaptureContentDelayTime,
- 500,
- 30000,
- 50),
- capture_content_time_histogram_(kCaptureContentTime, 0, 50000, 50),
+ : capture_content_time_histogram_(kCaptureContentTime, 0, 50000, 50),
send_content_time_histogram_(kSendContentTime, 0, 50000, 50),
- sent_content_count_histogram_(kSentContentCount, 0, 10000, 50),
- task_delay_time_in_ms_histogram_(kTaskDelayInMs, 1, 128000, 100),
task_runs_per_capture_histogram_(kTaskRunsPerCapture, 0, 100, 50) {}
ContentCaptureTaskHistogramReporter::~ContentCaptureTaskHistogramReporter() =
@@ -45,9 +40,10 @@ void ContentCaptureTaskHistogramReporter::OnTaskScheduled(
void ContentCaptureTaskHistogramReporter::OnTaskRun() {
if (!task_scheduled_time_.is_null()) {
- task_delay_time_in_ms_histogram_.CountMilliseconds(base::TimeTicks::Now() -
- task_scheduled_time_);
- task_scheduled_time_ = base::TimeTicks();
+ base::UmaHistogramCustomTimes(kTaskDelayInMs,
+ base::TimeTicks::Now() - task_scheduled_time_,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(128), 100);
}
task_runs_per_capture_++;
}
@@ -81,8 +77,10 @@ void ContentCaptureTaskHistogramReporter::OnSendContentEnded(
if (captured_content_change_time_) {
base::TimeTicks content_change_time = captured_content_change_time_.value();
captured_content_change_time_.reset();
- capture_content_delay_time_histogram_.CountMilliseconds(
- now - content_change_time);
+ base::UmaHistogramCustomTimes(kCaptureContentDelayTime,
+ now - content_change_time,
+ base::TimeDelta::FromMilliseconds(500),
+ base::TimeDelta::FromSeconds(30), 50);
}
if (!sent_content_count)
return;
@@ -97,7 +95,7 @@ void ContentCaptureTaskHistogramReporter::OnAllCapturedContentSent() {
void ContentCaptureTaskHistogramReporter::RecordsSentContentCountPerDocument(
size_t sent_content_count) {
- sent_content_count_histogram_.Count(sent_content_count);
+ base::UmaHistogramCounts10000(kSentContentCount, sent_content_count);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
index 388633de4c2..4201456d224 100644
--- a/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
+++ b/chromium/third_party/blink/renderer/core/content_capture/content_capture_task_histogram_reporter.h
@@ -22,7 +22,8 @@ class CORE_EXPORT ContentCaptureTaskHistogramReporter
static constexpr char kCaptureContentTime[] =
"ContentCapture.CaptureContentTime2";
static constexpr char kSendContentTime[] = "ContentCapture.SendContentTime";
- static constexpr char kSentContentCount[] = "ContentCapture.SentContentCount";
+ static constexpr char kSentContentCount[] =
+ "ContentCapture.SentContentCount2";
static constexpr char kTaskDelayInMs[] = "ContentCapture.TaskDelayTimeInMs";
static constexpr char kTaskRunsPerCapture[] =
"ContentCapture.TaskRunsPerCapture";
@@ -66,21 +67,12 @@ class CORE_EXPORT ContentCaptureTaskHistogramReporter
// and sending the content.
size_t task_runs_per_capture_ = 0;
- // Records time from first content change to content that has been sent, its
- // range is 500ms from to 30s.
- CustomCountHistogram capture_content_delay_time_histogram_;
// Records time to capture the content, its range is from 0 to 50,000
// microseconds.
CustomCountHistogram capture_content_time_histogram_;
// Records time to send the content, its range is from 0 to 50,000
// microseconds.
CustomCountHistogram send_content_time_histogram_;
- // Records total count has been sent, its range is from 0 to 10,000.
- LinearHistogram sent_content_count_histogram_;
- // Records time taken for the task to start after it is schedule, its range is
- // 1ms to 128s. The time of task that was scheduled for the retry wasn't
- // measured because it is always 500ms.
- CustomCountHistogram task_delay_time_in_ms_histogram_;
// Records the number of times ContentCapture task run to complete a capture
// which includes capturing and sending the content.
CustomCountHistogram task_runs_per_capture_histogram_;
diff --git a/chromium/third_party/blink/renderer/core/core_idl_files.gni b/chromium/third_party/blink/renderer/core/core_idl_files.gni
index eec15ef4af6..96315711f9c 100644
--- a/chromium/third_party/blink/renderer/core/core_idl_files.gni
+++ b/chromium/third_party/blink/renderer/core/core_idl_files.gni
@@ -56,6 +56,7 @@ core_interface_idl_files_core_only =
"clipboard/data_transfer.idl",
"clipboard/data_transfer_item_list.idl",
"css/css_condition_rule.idl",
+ "css/css_container_rule.idl",
"css/css_counter_style_rule.idl",
"css/css_font_face_rule.idl",
"css/css_grouping_rule.idl",
@@ -110,8 +111,10 @@ core_interface_idl_files_core_only =
"css/style_media.idl",
"css/style_sheet.idl",
"css/style_sheet_list.idl",
+ "document_transition/document_transition.idl",
"dom/abort_controller.idl",
"dom/abort_signal.idl",
+ "dom/abstract_range.idl",
"dom/attr.idl",
"dom/cdata_section.idl",
"dom/character_data.idl",
@@ -123,6 +126,7 @@ core_interface_idl_files_core_only =
"dom/dom_string_list.idl",
"dom/dom_string_map.idl",
"dom/dom_token_list.idl",
+ "dom/element.idl",
"dom/events/custom_event.idl",
"dom/events/event.idl",
"dom/events/event_target.idl",
@@ -201,6 +205,7 @@ core_interface_idl_files_core_only =
"frame/test_report_body.idl",
"frame/user_activation.idl",
"frame/visual_viewport.idl",
+ "frame/window_controls_overlay.idl",
"geometry/dom_matrix.idl",
"geometry/dom_matrix_read_only.idl",
"geometry/dom_point.idl",
@@ -212,6 +217,7 @@ core_interface_idl_files_core_only =
"html/canvas/image_data.idl",
"html/canvas/text_metrics.idl",
"html/custom/custom_element_registry.idl",
+ "html/custom/custom_state_set.idl",
"html/custom/element_internals.idl",
"html/forms/form_data.idl",
"html/forms/form_data_event.idl",
@@ -227,6 +233,7 @@ core_interface_idl_files_core_only =
"html/forms/html_options_collection.idl",
"html/forms/html_output_element.idl",
"html/forms/html_select_element.idl",
+ "html/forms/html_select_menu_element.idl",
"html/forms/html_text_area_element.idl",
"html/forms/radio_node_list.idl",
"html/forms/submit_event.idl",
@@ -238,7 +245,6 @@ core_interface_idl_files_core_only =
"html/html_body_element.idl",
"html/html_br_element.idl",
"html/html_collection.idl",
- "html/html_content_element.idl",
"html/html_data_element.idl",
"html/html_details_element.idl",
"html/html_dialog_element.idl",
@@ -268,11 +274,11 @@ core_interface_idl_files_core_only =
"html/html_paragraph_element.idl",
"html/html_param_element.idl",
"html/html_picture_element.idl",
+ "html/html_popup_element.idl",
"html/html_pre_element.idl",
"html/html_progress_element.idl",
"html/html_quote_element.idl",
"html/html_script_element.idl",
- "html/html_shadow_element.idl",
"html/html_slot_element.idl",
"html/html_source_element.idl",
"html/html_span_element.idl",
@@ -318,7 +324,6 @@ core_interface_idl_files_core_only =
"layout/ng/custom/layout_fragment.idl",
"layout/ng/custom/layout_worklet_global_scope.idl",
"loader/appcache/application_cache.idl",
- "mathml/mathml_element.idl",
"messaging/message_channel.idl",
"messaging/message_port.idl",
"mojo/mojo.idl",
@@ -370,7 +375,6 @@ core_interface_idl_files_core_only =
"svg/svg_component_transfer_function_element.idl",
"svg/svg_defs_element.idl",
"svg/svg_desc_element.idl",
- "svg/svg_element.idl",
"svg/svg_ellipse_element.idl",
"svg/svg_fe_blend_element.idl",
"svg/svg_fe_color_matrix_element.idl",
@@ -498,7 +502,6 @@ core_interface_idl_files_modules_dependent =
"clipboard/data_transfer_item.idl",
"css/css.idl",
"dom/document.idl",
- "dom/element.idl",
"dom/shadow_root.idl",
"frame/navigator.idl",
"frame/screen.idl",
@@ -512,7 +515,9 @@ core_interface_idl_files_modules_dependent =
"html/track/audio_track.idl",
"html/track/video_track.idl",
"inspector/dev_tools_host.idl",
+ "mathml/mathml_element.idl",
"offscreencanvas/offscreen_canvas.idl",
+ "svg/svg_element.idl",
"url/url.idl",
"workers/dedicated_worker_global_scope.idl",
"workers/shared_worker_global_scope.idl",
@@ -530,6 +535,7 @@ core_partial_definition_idl_files =
"css/cssom/element_computed_style_map.idl",
"css/font_face_source.idl",
"css/property_registration.idl",
+ "document_transition/document_transition_supplement.idl",
"dom/accessibility_role.idl",
"dom/aria_attributes.idl",
"dom/aria_relationship_attributes.idl",
@@ -555,6 +561,7 @@ core_partial_definition_idl_files =
"frame/navigator_scheduling.idl",
"frame/navigator_ua.idl",
"frame/navigator_user_activation.idl",
+ "frame/navigator_window_controls_overlay.idl",
"frame/window_event_handlers.idl",
"frame/window_or_worker_global_scope.idl",
"fullscreen/document_fullscreen.idl",
@@ -613,6 +620,9 @@ core_callback_function_idl_files =
"dom/function_string_callback.idl",
"dom/idle_request_callback.idl",
"dom/void_function.idl",
+ "streams/underlying_source_cancel_callback.idl",
+ "streams/underlying_source_pull_callback.idl",
+ "streams/underlying_source_start_callback.idl",
],
"abspath")
@@ -644,16 +654,18 @@ core_dictionary_idl_files =
"css/property_definition.idl",
"css/cssom/css_matrix_component_options.idl",
"css/cssom/css_numeric_type.idl",
+ "document_transition/document_transition_init.idl",
"dom/element_creation_options.idl",
"dom/element_definition_options.idl",
"dom/element_registration_options.idl",
"dom/get_inner_html_options.idl",
"dom/get_root_node_options.idl",
"dom/idle_request_options.idl",
+ "dom/interest_cohort.idl",
"dom/mutation_observer_init.idl",
"dom/pointer_lock_options.idl",
- "dom/set_inner_html_options.idl",
"dom/shadow_root_init.idl",
+ "dom/static_range_init.idl",
"dom/events/add_event_listener_options.idl",
"dom/events/custom_event_init.idl",
"dom/events/event_init.idl",
@@ -691,6 +703,7 @@ core_dictionary_idl_files =
"fetch/trust_token.idl",
"fileapi/blob_property_bag.idl",
"fileapi/file_property_bag.idl",
+ "frame/impression_params.idl",
"frame/is_input_pending_options.idl",
"frame/navigator_ua_brand_version.idl",
"frame/reporting_observer_options.idl",
@@ -707,7 +720,7 @@ core_dictionary_idl_files =
"html/focus_options.idl",
"html/assigned_nodes_options.idl",
"html/canvas/baselines.idl",
- "html/canvas/image_data_color_settings.idl",
+ "html/canvas/image_data_settings.idl",
"html/canvas/image_encode_options.idl",
"html/custom/validity_state_flags.idl",
"html/forms/form_data_event_init.idl",
@@ -745,9 +758,12 @@ core_dictionary_idl_files =
"streams/readable_stream_get_reader_options.idl",
"streams/readable_writable_pair.idl",
"streams/stream_pipe_options.idl",
+ "streams/underlying_source.idl",
"streams/queuing_strategy_init.idl",
- "timing/measure_memory/measure_memory.idl",
- "timing/measure_memory/measure_memory_breakdown.idl",
+ "timing/measure_memory/memory_measurement.idl",
+ "timing/measure_memory/memory_breakdown_entry.idl",
+ "timing/measure_memory/memory_attribution.idl",
+ "timing/measure_memory/memory_attribution_container.idl",
"timing/performance_mark_options.idl",
"timing/performance_measure_options.idl",
"timing/performance_observer_init.idl",
diff --git a/chromium/third_party/blink/renderer/core/core_initializer.cc b/chromium/third_party/blink/renderer/core/core_initializer.cc
index c35f041759f..7198057dd28 100644
--- a/chromium/third_party/blink/renderer/core/core_initializer.cc
+++ b/chromium/third_party/blink/renderer/core/core_initializer.cc
@@ -142,8 +142,6 @@ void CoreInitializer::Initialize() {
style_change_extra_data::Init();
- SecurityPolicy::Init();
-
RegisterEventFactory();
StringImpl::FreezeStaticStrings();
diff --git a/chromium/third_party/blink/renderer/core/css/DIR_METADATA b/chromium/third_party/blink/renderer/core/css/DIR_METADATA
new file mode 100644
index 00000000000..1876fb375cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>CSS"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/css/OWNERS b/chromium/third_party/blink/renderer/core/css/OWNERS
index a007a39a025..7c1cab453b7 100644
--- a/chromium/third_party/blink/renderer/core/css/OWNERS
+++ b/chromium/third_party/blink/renderer/core/css/OWNERS
@@ -3,6 +3,3 @@ andruud@chromium.org
ericwilligers@chromium.org
futhark@chromium.org
xiaochengh@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/chromium/third_party/blink/renderer/core/css/abstract_property_set_css_style_declaration.cc b/chromium/third_party/blink/renderer/core/css/abstract_property_set_css_style_declaration.cc
index a252ce58d37..060346478e7 100644
--- a/chromium/third_party/blink/renderer/core/css/abstract_property_set_css_style_declaration.cc
+++ b/chromium/third_party/blink/renderer/core/css/abstract_property_set_css_style_declaration.cc
@@ -68,8 +68,8 @@ void AbstractPropertySetCSSStyleDeclaration::setCSSText(
String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(
const String& property_name) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
- if (!isValidCSSPropertyID(property_id))
+ CssPropertyID(GetExecutionContext(), property_name);
+ if (!IsValidCSSPropertyID(property_id))
return String();
if (property_id == CSSPropertyID::kVariable)
return PropertySet().GetPropertyValue(AtomicString(property_name));
@@ -79,8 +79,8 @@ String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(
String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(
const String& property_name) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
- if (!isValidCSSPropertyID(property_id))
+ CssPropertyID(GetExecutionContext(), property_name);
+ if (!IsValidCSSPropertyID(property_id))
return String();
bool important = false;
@@ -94,14 +94,14 @@ String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(
String AbstractPropertySetCSSStyleDeclaration::GetPropertyShorthand(
const String& property_name) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
+ CssPropertyID(GetExecutionContext(), property_name);
// Custom properties don't have shorthands, so we can ignore them here.
- if (!isValidCSSPropertyID(property_id) ||
+ if (!IsValidCSSPropertyID(property_id) ||
!CSSProperty::Get(property_id).IsLonghand())
return String();
CSSPropertyID shorthand_id = PropertySet().GetPropertyShorthand(property_id);
- if (!isValidCSSPropertyID(shorthand_id))
+ if (!IsValidCSSPropertyID(shorthand_id))
return String();
return CSSProperty::Get(shorthand_id).GetPropertyNameString();
}
@@ -109,10 +109,10 @@ String AbstractPropertySetCSSStyleDeclaration::GetPropertyShorthand(
bool AbstractPropertySetCSSStyleDeclaration::IsPropertyImplicit(
const String& property_name) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
+ CssPropertyID(GetExecutionContext(), property_name);
// Custom properties don't have shorthands, so we can ignore them here.
- if (property_id < firstCSSProperty)
+ if (property_id < kFirstCSSProperty)
return false;
return PropertySet().IsPropertyImplicit(property_id);
}
@@ -124,8 +124,8 @@ void AbstractPropertySetCSSStyleDeclaration::setProperty(
const String& priority,
ExceptionState& exception_state) {
CSSPropertyID property_id =
- unresolvedCSSPropertyID(execution_context, property_name);
- if (!isValidCSSPropertyID(property_id))
+ UnresolvedCSSPropertyID(execution_context, property_name);
+ if (!IsValidCSSPropertyID(property_id))
return;
bool important = EqualIgnoringASCIICase(priority, "important");
@@ -143,8 +143,8 @@ String AbstractPropertySetCSSStyleDeclaration::removeProperty(
const String& property_name,
ExceptionState& exception_state) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
- if (!isValidCSSPropertyID(property_id))
+ CssPropertyID(GetExecutionContext(), property_name);
+ if (!IsValidCSSPropertyID(property_id))
return String();
StyleAttributeMutationScope mutation_scope(this);
@@ -176,7 +176,7 @@ const CSSValue*
AbstractPropertySetCSSStyleDeclaration::GetPropertyCSSValueInternal(
AtomicString custom_property_name) {
DCHECK_EQ(CSSPropertyID::kVariable,
- cssPropertyID(GetExecutionContext(), custom_property_name));
+ CssPropertyID(GetExecutionContext(), custom_property_name));
return PropertySet().GetPropertyCSSValue(custom_property_name);
}
diff --git a/chromium/third_party/blink/renderer/core/css/active_style_sheets.cc b/chromium/third_party/blink/renderer/core/css/active_style_sheets.cc
index 3c9209e0847..b2b05ae2bab 100644
--- a/chromium/third_party/blink/renderer/core/css/active_style_sheets.cc
+++ b/chromium/third_party/blink/renderer/core/css/active_style_sheets.cc
@@ -124,4 +124,45 @@ ActiveSheetsChange CompareActiveStyleSheets(
: kActiveSheetsChanged;
}
+namespace {
+
+bool HasMediaQueries(const ActiveStyleSheetVector& active_style_sheets) {
+ for (const auto& active_sheet : active_style_sheets) {
+ if (const MediaQuerySet* media_queries =
+ active_sheet.first->MediaQueries()) {
+ if (!media_queries->QueryVector().IsEmpty())
+ return true;
+ }
+ StyleSheetContents* contents = active_sheet.first->Contents();
+ if (contents->HasMediaQueries())
+ return true;
+ }
+ return false;
+}
+
+bool HasSizeDependentMediaQueries(
+ const ActiveStyleSheetVector& active_style_sheets) {
+ for (const auto& active_sheet : active_style_sheets) {
+ if (active_sheet.first->HasMediaQueryResults())
+ return true;
+ StyleSheetContents* contents = active_sheet.first->Contents();
+ if (!contents->HasRuleSet())
+ continue;
+ if (contents->GetRuleSet().Features().HasMediaQueryResults())
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+bool AffectedByMediaValueChange(const ActiveStyleSheetVector& active_sheets,
+ MediaValueChange change) {
+ if (change == MediaValueChange::kSize)
+ return HasSizeDependentMediaQueries(active_sheets);
+
+ DCHECK(change == MediaValueChange::kOther);
+ return HasMediaQueries(active_sheets);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/active_style_sheets.h b/chromium/third_party/blink/renderer/core/css/active_style_sheets.h
index 47f3ae5d58c..ce4d711c29c 100644
--- a/chromium/third_party/blink/renderer/core/css/active_style_sheets.h
+++ b/chromium/third_party/blink/renderer/core/css/active_style_sheets.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_ACTIVE_STYLE_SHEETS_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/media_value_change.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
@@ -27,6 +28,9 @@ CompareActiveStyleSheets(const ActiveStyleSheetVector& old_style_sheets,
const ActiveStyleSheetVector& new_style_sheets,
HeapHashSet<Member<RuleSet>>& changed_rule_sets);
+bool AffectedByMediaValueChange(const ActiveStyleSheetVector& active_sheets,
+ MediaValueChange change);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_ACTIVE_STYLE_SHEETS_H_
diff --git a/chromium/third_party/blink/renderer/core/css/active_style_sheets_test.cc b/chromium/third_party/blink/renderer/core/css/active_style_sheets_test.cc
index f01a512e45f..d23055dc0df 100644
--- a/chromium/third_party/blink/renderer/core/css/active_style_sheets_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/active_style_sheets_test.cc
@@ -510,7 +510,6 @@ TEST_F(ApplyRulesetsTest, RemoveSheetFromShadowTree) {
shadow_root.setInnerHTML("<style>::slotted(#dummy){color:pink}</style>");
UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(GetStyleEngine().TreeBoundaryCrossingScopes().IsEmpty());
ASSERT_EQ(1u, shadow_root.StyleSheets().length());
StyleSheet* sheet = shadow_root.StyleSheets().item(0);
@@ -523,8 +522,6 @@ TEST_F(ApplyRulesetsTest, RemoveSheetFromShadowTree) {
std::make_pair(css_sheet, &css_sheet->Contents()->GetRuleSet()));
GetStyleEngine().ApplyRuleSetChanges(shadow_root, old_style_sheets,
ActiveStyleSheetVector());
-
- EXPECT_TRUE(GetStyleEngine().TreeBoundaryCrossingScopes().IsEmpty());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.cc b/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.cc
new file mode 100644
index 00000000000..61e1b6a0672
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.cc
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/background_color_paint_image_generator.h"
+
+namespace blink {
+
+namespace {
+
+BackgroundColorPaintImageGenerator::
+ BackgroundColorPaintImageGeneratorCreateFunction g_create_function =
+ nullptr;
+
+} // namespace
+
+// static
+void BackgroundColorPaintImageGenerator::Init(
+ BackgroundColorPaintImageGeneratorCreateFunction create_function) {
+ DCHECK(!g_create_function);
+ g_create_function = create_function;
+}
+
+BackgroundColorPaintImageGenerator* BackgroundColorPaintImageGenerator::Create(
+ LocalFrame& local_root) {
+ DCHECK(g_create_function);
+ return g_create_function(local_root);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.h b/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.h
new file mode 100644
index 00000000000..08a77b9f1ec
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/background_color_paint_image_generator.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_CORE_CSS_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/native_paint_image_generator.h"
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace blink {
+
+class Image;
+class LocalFrame;
+class Node;
+
+class CORE_EXPORT BackgroundColorPaintImageGenerator
+ : public NativePaintImageGenerator {
+ public:
+ static BackgroundColorPaintImageGenerator* Create(LocalFrame&);
+
+ ~BackgroundColorPaintImageGenerator() override = default;
+
+ typedef BackgroundColorPaintImageGenerator* (
+ *BackgroundColorPaintImageGeneratorCreateFunction)(LocalFrame&);
+ static void Init(
+ BackgroundColorPaintImageGeneratorCreateFunction create_function);
+
+ virtual scoped_refptr<Image> Paint(const FloatSize& container_size,
+ const Node*,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets) = 0;
+
+ // Get the animated colors and offsets from the animation keyframes.
+ // Returning false meaning that we need to fall back to the main thread for
+ // the animation.
+ virtual bool GetBGColorPaintWorkletParams(Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/css/build.gni b/chromium/third_party/blink/renderer/core/css/build.gni
index fc0c8c1d548..0b3d30b94dd 100644
--- a/chromium/third_party/blink/renderer/core/css/build.gni
+++ b/chromium/third_party/blink/renderer/core/css/build.gni
@@ -7,12 +7,22 @@ blink_core_sources_css = [
"abstract_property_set_css_style_declaration.h",
"active_style_sheets.cc",
"active_style_sheets.h",
+ "background_color_paint_image_generator.cc",
+ "background_color_paint_image_generator.h",
"basic_shape_functions.cc",
"basic_shape_functions.h",
"binary_data_font_face_source.cc",
"binary_data_font_face_source.h",
"computed_style_css_value_mapping.cc",
"computed_style_css_value_mapping.h",
+ "counter_style.cc",
+ "counter_style.h",
+ "counter_style_map.cc",
+ "counter_style_map.h",
+ "container_query.cc",
+ "container_query.h",
+ "container_query_evaluator.cc",
+ "container_query_evaluator.h",
"css_axis_value.cc",
"css_axis_value.h",
"css_basic_shape_values.cc",
@@ -27,6 +37,8 @@ blink_core_sources_css = [
"css_computed_style_declaration.h",
"css_condition_rule.cc",
"css_condition_rule.h",
+ "css_container_rule.cc",
+ "css_container_rule.h",
"css_content_distribution_value.cc",
"css_content_distribution_value.h",
"css_counter_style_rule.cc",
@@ -204,6 +216,8 @@ blink_core_sources_css = [
"css_uri_value.h",
"css_value.cc",
"css_value.h",
+ "css_value_clamping_utils.h",
+ "css_value_clamping_utils.cc",
"css_value_id_mappings.h",
"css_value_list.cc",
"css_value_list.h",
@@ -381,9 +395,6 @@ blink_core_sources_css = [
"media_values_cached.h",
"media_values_dynamic.cc",
"media_values_dynamic.h",
- "media_values_initial_viewport.cc",
- "media_values_initial_viewport.h",
- "native_paint_image_generator.cc",
"native_paint_image_generator.h",
"offscreen_font_selector.cc",
"offscreen_font_selector.h",
@@ -573,6 +584,8 @@ blink_core_sources_css = [
"style_recalc_root.h",
"style_rule.cc",
"style_rule.h",
+ "style_rule_counter_style.cc",
+ "style_rule_counter_style.h",
"style_rule_css_style_declaration.cc",
"style_rule_css_style_declaration.h",
"style_rule_import.cc",
@@ -603,6 +616,8 @@ blink_core_tests_css = [
"active_style_sheets_test.cc",
"affected_by_pseudo_test.cc",
"computed_style_css_value_mapping_test.cc",
+ "container_query_test.cc",
+ "container_query_evaluator_test.cc",
"css_computed_style_declaration_test.cc",
"css_element_offset_value_test.cc",
"css_font_face_source_test.cc",
@@ -621,6 +636,9 @@ blink_core_tests_css = [
"css_style_declaration_test.cc",
"css_style_sheet_test.cc",
"css_syntax_string_parser_test.cc",
+ "css_value_clamping_utils_test.cc",
+ "counter_style_map_test.cc",
+ "counter_style_test.cc",
"cssom/computed_style_property_map_test.cc",
"cssom/cross_thread_style_value_test.cc",
"cssom/css_math_invert_test.cc",
@@ -647,7 +665,6 @@ blink_core_tests_css = [
"media_query_list_test.cc",
"media_query_matcher_test.cc",
"media_query_set_test.cc",
- "media_values_initial_viewport_test.cc",
"media_values_test.cc",
"parser/css_lazy_parsing_test.cc",
"parser/css_parser_fast_paths_test.cc",
@@ -684,7 +701,6 @@ blink_core_tests_css = [
"resolver/style_adjuster_test.cc",
"resolver/style_builder_test.cc",
"resolver/style_cascade_test.cc",
- "resolver/style_resolver_state_test.cc",
"resolver/style_resolver_test.cc",
"rule_feature_set_test.cc",
"rule_set_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/css/container_query.cc b/chromium/third_party/blink/renderer/core/css/container_query.cc
new file mode 100644
index 00000000000..6b75aa2459c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/container_query.h"
+#include "third_party/blink/renderer/core/css/media_query_exp.h"
+
+namespace blink {
+
+namespace {
+
+PhysicalAxes ComputeQueriedAxes(const MediaQuerySet& media_queries) {
+ PhysicalAxes axes(kPhysicalAxisNone);
+
+ for (const auto& media_query : media_queries.QueryVector()) {
+ for (const auto& expression : media_query->Expressions()) {
+ if (expression.IsWidthDependent())
+ axes |= PhysicalAxes(kPhysicalAxisHorizontal);
+ if (expression.IsHeightDependent())
+ axes |= PhysicalAxes(kPhysicalAxisVertical);
+ }
+ }
+
+ return axes;
+}
+
+} // namespace
+
+ContainerQuery::ContainerQuery(scoped_refptr<MediaQuerySet> media_queries)
+ : media_queries_(media_queries),
+ queried_axes_(ComputeQueriedAxes(*media_queries)) {}
+
+ContainerQuery::ContainerQuery(const ContainerQuery& other)
+ : media_queries_(other.media_queries_->Copy()),
+ queried_axes_(other.queried_axes_) {}
+
+String ContainerQuery::ToString() const {
+ return media_queries_->MediaText();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/container_query.h b/chromium/third_party/blink/renderer/core/css/container_query.h
new file mode 100644
index 00000000000..1257645c088
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/media_list.h"
+#include "third_party/blink/renderer/core/layout/geometry/axis.h"
+
+namespace blink {
+
+class CORE_EXPORT ContainerQuery final
+ : public GarbageCollected<ContainerQuery> {
+ public:
+ explicit ContainerQuery(scoped_refptr<MediaQuerySet>);
+ ContainerQuery(const ContainerQuery&);
+
+ PhysicalAxes QueriedAxes() const { return queried_axes_; }
+
+ String ToString() const;
+
+ void Trace(Visitor*) const {}
+
+ private:
+ friend class ContainerQueryTest;
+ friend class ContainerQueryEvaluator;
+
+ // TODO(crbug.com/1145970): Refactor to avoid internal MediaQuerySet.
+ scoped_refptr<MediaQuerySet> media_queries_;
+ PhysicalAxes queried_axes_{kPhysicalAxisNone};
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_H_
diff --git a/chromium/third_party/blink/renderer/core/css/container_query_evaluator.cc b/chromium/third_party/blink/renderer/core/css/container_query_evaluator.cc
new file mode 100644
index 00000000000..aee25f87272
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query_evaluator.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/container_query_evaluator.h"
+#include "third_party/blink/renderer/core/css/container_query.h"
+
+#include "third_party/blink/renderer/core/css/media_values_cached.h"
+
+namespace blink {
+
+namespace {
+
+bool IsSufficientlyContained(PhysicalAxes contained_axes,
+ PhysicalAxes queried_axes) {
+ return (contained_axes & queried_axes) == queried_axes;
+}
+
+} // namespace
+
+ContainerQueryEvaluator::ContainerQueryEvaluator(PhysicalSize size,
+ PhysicalAxes contained_axes) {
+ SetData(size, contained_axes);
+}
+
+bool ContainerQueryEvaluator::Eval(
+ const ContainerQuery& container_query) const {
+ if (!IsSufficientlyContained(contained_axes_, container_query.QueriedAxes()))
+ return false;
+ return media_query_evaluator_->Eval(*container_query.media_queries_);
+}
+
+void ContainerQueryEvaluator::Add(const ContainerQuery& query, bool result) {
+ results_.Set(&query, result);
+}
+
+bool ContainerQueryEvaluator::ContainerChanged(PhysicalSize size,
+ PhysicalAxes contained_axes) {
+ if (size_ == size && contained_axes_ == contained_axes)
+ return false;
+
+ SetData(size, contained_axes);
+
+ if (!ResultsChanged())
+ return false;
+
+ // We can clear the results here because we will always recaculate the style
+ // of all descendants which depend on this evaluator whenever we return
+ // 'true' from this function, so the results will always be repopulated.
+ results_.clear();
+
+ return true;
+}
+
+void ContainerQueryEvaluator::Trace(Visitor* visitor) const {
+ visitor->Trace(media_query_evaluator_);
+ visitor->Trace(results_);
+}
+
+void ContainerQueryEvaluator::SetData(PhysicalSize size,
+ PhysicalAxes contained_axes) {
+ size_ = size;
+ contained_axes_ = contained_axes;
+
+ auto* cached_values = MakeGarbageCollected<MediaValuesCached>();
+ cached_values->OverrideViewportDimensions(size_.width, size_.height);
+ media_query_evaluator_ =
+ MakeGarbageCollected<MediaQueryEvaluator>(*cached_values);
+}
+
+bool ContainerQueryEvaluator::ResultsChanged() const {
+ for (const auto& result : results_) {
+ if (Eval(*result.key) != result.value)
+ return true;
+ }
+ return false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/container_query_evaluator.h b/chromium/third_party/blink/renderer/core/css/container_query_evaluator.h
new file mode 100644
index 00000000000..939d0488b3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query_evaluator.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_EVALUATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_EVALUATOR_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
+#include "third_party/blink/renderer/core/layout/geometry/axis.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class ContainerQuery;
+
+class CORE_EXPORT ContainerQueryEvaluator final
+ : public GarbageCollected<ContainerQueryEvaluator> {
+ public:
+ ContainerQueryEvaluator(PhysicalSize, PhysicalAxes contained_axes);
+
+ bool Eval(const ContainerQuery&) const;
+
+ // Add a dependent query to this evaluator. During calls to ContainerChanged,
+ // all dependent queries are checked to see if the new size/axis information
+ // causes a change in the evaluation result.
+ void Add(const ContainerQuery&, bool result);
+
+ bool EvalAndAdd(const ContainerQuery& query) {
+ bool result = Eval(query);
+ Add(query, result);
+ return result;
+ }
+
+ // Update the size/axis information of the evaluator.
+ //
+ // A return value of 'false' means that the update has no effect on the
+ // evaluation of queries associated with this evaluator, and therefore we do
+ // not need to perform style recalc of any elements which depend on this
+ // evaluator.
+ //
+ // A return value of 'true' means that the update *may* have an effect, and
+ // therefore elements that depends on this evaluator need style recalc.
+ //
+ // Dependent queries are cleared when 'true' is returned (and left unchanged
+ // otherwise).
+ bool ContainerChanged(PhysicalSize, PhysicalAxes contained_axes);
+
+ void Trace(Visitor*) const;
+
+ private:
+ void SetData(PhysicalSize, PhysicalAxes contained_axes);
+ bool ResultsChanged() const;
+
+ // TODO(crbug.com/1145970): Don't lean on MediaQueryEvaluator.
+ Member<MediaQueryEvaluator> media_query_evaluator_;
+ PhysicalSize size_;
+ PhysicalAxes contained_axes_;
+ HeapHashMap<Member<const ContainerQuery>, bool> results_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_QUERY_EVALUATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/css/container_query_evaluator_test.cc b/chromium/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
new file mode 100644
index 00000000000..60d2e5c45d2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
@@ -0,0 +1,248 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/container_query_evaluator.h"
+
+#include "third_party/blink/renderer/core/css/container_query.h"
+#include "third_party/blink/renderer/core/css/css_container_rule.h"
+#include "third_party/blink/renderer/core/css/css_test_helpers.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class ContainerQueryEvaluatorTest : public PageTestBase,
+ private ScopedCSSContainerQueriesForTest {
+ public:
+ ContainerQueryEvaluatorTest() : ScopedCSSContainerQueriesForTest(true) {}
+
+ ContainerQuery* ParseContainer(String query) {
+ String rule = "@container " + query + " {}";
+ auto* style_rule = DynamicTo<StyleRuleContainer>(
+ css_test_helpers::ParseRule(GetDocument(), rule));
+ if (!style_rule)
+ return nullptr;
+ return &style_rule->GetContainerQuery();
+ }
+
+ bool Eval(String query,
+ double width,
+ double height,
+ PhysicalAxes contained_axes) {
+ ContainerQuery* container_query = ParseContainer(query);
+ DCHECK(container_query);
+ auto* evaluator = MakeGarbageCollected<ContainerQueryEvaluator>(
+ PhysicalSize(LayoutUnit(width), LayoutUnit(height)), contained_axes);
+ return evaluator->Eval(*container_query);
+ }
+
+ const PhysicalAxes none{kPhysicalAxisNone};
+ const PhysicalAxes both{kPhysicalAxisBoth};
+ const PhysicalAxes horizontal{kPhysicalAxisHorizontal};
+ const PhysicalAxes vertical{kPhysicalAxisVertical};
+};
+
+TEST_F(ContainerQueryEvaluatorTest, ContainmentMatch) {
+ {
+ String query = "(min-width: 100px)";
+ EXPECT_TRUE(Eval(query, 100.0, 100.0, horizontal));
+ EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, vertical));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, none));
+ EXPECT_FALSE(Eval(query, 99.0, 100.0, horizontal));
+ }
+
+ {
+ String query = "(min-height: 100px)";
+ EXPECT_TRUE(Eval(query, 100.0, 100.0, vertical));
+ EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, horizontal));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, none));
+ EXPECT_FALSE(Eval(query, 100.0, 99.0, vertical));
+ }
+
+ {
+ String query = "(min-width: 100px) and (min-height: 100px)";
+ EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, vertical));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, horizontal));
+ EXPECT_FALSE(Eval(query, 100.0, 100.0, none));
+ EXPECT_FALSE(Eval(query, 100.0, 99.0, both));
+ EXPECT_FALSE(Eval(query, 99.0, 100.0, both));
+ }
+}
+
+TEST_F(ContainerQueryEvaluatorTest, ContainerChanged) {
+ PhysicalSize size_100(LayoutUnit(100), LayoutUnit(100));
+ PhysicalSize size_200(LayoutUnit(200), LayoutUnit(200));
+
+ ContainerQuery* container_query_100 = ParseContainer("(min-width: 100px)");
+ ContainerQuery* container_query_200 = ParseContainer("(min-width: 200px)");
+ ASSERT_TRUE(container_query_100);
+ ASSERT_TRUE(container_query_200);
+
+ auto* evaluator =
+ MakeGarbageCollected<ContainerQueryEvaluator>(size_100, horizontal);
+ ASSERT_TRUE(evaluator);
+
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_100));
+ EXPECT_FALSE(evaluator->EvalAndAdd(*container_query_200));
+
+ EXPECT_FALSE(evaluator->ContainerChanged(size_100, horizontal));
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_100));
+ EXPECT_FALSE(evaluator->EvalAndAdd(*container_query_200));
+
+ EXPECT_TRUE(evaluator->ContainerChanged(size_200, horizontal));
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_100));
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_200));
+
+ EXPECT_FALSE(evaluator->ContainerChanged(size_200, horizontal));
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_100));
+ EXPECT_TRUE(evaluator->EvalAndAdd(*container_query_200));
+
+ EXPECT_TRUE(evaluator->ContainerChanged(size_200, vertical));
+ EXPECT_FALSE(evaluator->EvalAndAdd(*container_query_100));
+ EXPECT_FALSE(evaluator->EvalAndAdd(*container_query_200));
+}
+
+TEST_F(ContainerQueryEvaluatorTest, SizeInvalidation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #container {
+ contain: size layout;
+ width: 500px;
+ height: 500px;
+ }
+ @container (min-width: 500px) {
+ div { z-index:1; }
+ }
+ </style>
+ <div id=container>
+ <div id=div></div>
+ <div id=div></div>
+ <div id=div></div>
+ <div id=div></div>
+ <div id=div></div>
+ <div id=div></div>
+ </div>
+ )HTML");
+
+ Element* container = GetDocument().getElementById("container");
+ ASSERT_TRUE(container);
+ ASSERT_TRUE(container->GetContainerQueryEvaluator());
+
+ {
+ // Causes re-layout, but the size does not change
+ container->SetInlineStyleProperty(CSSPropertyID::kFloat, "left");
+
+ unsigned before_count = GetStyleEngine().StyleForElementCount();
+
+ UpdateAllLifecyclePhasesForTest();
+
+ unsigned after_count = GetStyleEngine().StyleForElementCount();
+
+ // Only #container should be affected. In particular, we should not
+ // recalc any style for <div> children of #container.
+ EXPECT_EQ(1u, after_count - before_count);
+ }
+
+ {
+ // The size of the container changes, but it does not matter for
+ // the result of the query (min-width: 500px).
+ container->SetInlineStyleProperty(CSSPropertyID::kWidth, "600px");
+
+ unsigned before_count = GetStyleEngine().StyleForElementCount();
+
+ UpdateAllLifecyclePhasesForTest();
+
+ unsigned after_count = GetStyleEngine().StyleForElementCount();
+
+ // Only #container should be affected. In particular, we should not
+ // recalc any style for <div> children of #container.
+ EXPECT_EQ(1u, after_count - before_count);
+ }
+}
+
+TEST_F(ContainerQueryEvaluatorTest, DependentQueries) {
+ PhysicalSize size_100(LayoutUnit(100), LayoutUnit(100));
+ PhysicalSize size_150(LayoutUnit(150), LayoutUnit(150));
+ PhysicalSize size_200(LayoutUnit(200), LayoutUnit(200));
+ PhysicalSize size_300(LayoutUnit(300), LayoutUnit(300));
+ PhysicalSize size_400(LayoutUnit(400), LayoutUnit(400));
+
+ ContainerQuery* query_min_200px = ParseContainer("(min-width: 200px)");
+ ContainerQuery* query_max_300px = ParseContainer("(max-width: 300px)");
+ ASSERT_TRUE(query_min_200px);
+
+ auto* evaluator =
+ MakeGarbageCollected<ContainerQueryEvaluator>(size_100, horizontal);
+
+ evaluator->EvalAndAdd(*query_min_200px);
+ evaluator->EvalAndAdd(*query_max_300px);
+ // Updating with the same size as we initially had should not invalidate
+ // any query results.
+ EXPECT_FALSE(evaluator->ContainerChanged(size_100, horizontal));
+
+ // Makes no difference for either of (min-width: 200px), (max-width: 300px):
+ EXPECT_FALSE(evaluator->ContainerChanged(size_150, horizontal));
+
+ // (min-width: 200px) becomes true:
+ EXPECT_TRUE(evaluator->ContainerChanged(size_200, horizontal));
+
+ evaluator->EvalAndAdd(*query_min_200px);
+ evaluator->EvalAndAdd(*query_max_300px);
+ EXPECT_FALSE(evaluator->ContainerChanged(size_200, horizontal));
+
+ // Makes no difference for either of (min-width: 200px), (max-width: 300px):
+ EXPECT_FALSE(evaluator->ContainerChanged(size_300, horizontal));
+
+ // (max-width: 300px) becomes false:
+ EXPECT_TRUE(evaluator->ContainerChanged(size_400, horizontal));
+}
+
+TEST_F(ContainerQueryEvaluatorTest, EvaluatorOnDetachLayoutTree) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ main {
+ display: block;
+ contain: size layout;
+ width: 500px;
+ height: 500px;
+ }
+ @container (min-width: 500px) {
+ div { --x:test; }
+ }
+ </style>
+ <main id=container1>
+ <div></div>
+ </main>
+ <main id=container2>
+ <div></div>
+ </main>
+ )HTML");
+
+ Element* container1 = GetDocument().getElementById("container1");
+ ASSERT_TRUE(container1);
+ ASSERT_TRUE(container1->GetContainerQueryEvaluator());
+
+ // DetachLayoutTree with performing_reattach=false:
+ container1->remove();
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(container1->GetContainerQueryEvaluator())
+ << "ContainerQueryEvaluator should be removed";
+
+ // DetachLayoutTree with performing_reattach=true:
+ Element* container2 = GetDocument().getElementById("container2");
+ ASSERT_TRUE(container2);
+ ASSERT_TRUE(container2->GetContainerQueryEvaluator());
+ container2->SetInlineStyleProperty(CSSPropertyID::kDisplay, "none");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(container2->GetContainerQueryEvaluator())
+ << "ContainerQueryEvaluator should persist";
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/container_query_test.cc b/chromium/third_party/blink/renderer/core/css/container_query_test.cc
new file mode 100644
index 00000000000..57f1d190e94
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/container_query_test.cc
@@ -0,0 +1,198 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/container_query.h"
+
+#include "third_party/blink/renderer/core/css/css_container_rule.h"
+#include "third_party/blink/renderer/core/css/css_test_helpers.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class ContainerQueryTest : public PageTestBase,
+ private ScopedCSSContainerQueriesForTest {
+ public:
+ ContainerQueryTest() : ScopedCSSContainerQueriesForTest(true) {}
+
+ StyleRuleContainer* ParseAtContainer(String rule_string) {
+ return DynamicTo<StyleRuleContainer>(
+ css_test_helpers::ParseRule(GetDocument(), rule_string));
+ }
+
+ ContainerQuery* ParseContainerQuery(String query) {
+ String rule = "@container " + query + " {}";
+ StyleRuleContainer* container = ParseAtContainer(rule);
+ if (!container)
+ return nullptr;
+ return &container->GetContainerQuery();
+ }
+
+ PhysicalAxes QueriedAxes(String query) {
+ ContainerQuery* container_query = ParseContainerQuery(query);
+ DCHECK(container_query);
+ return container_query->QueriedAxes();
+ }
+
+ String SerializeCondition(StyleRuleContainer* container) {
+ if (!container)
+ return "";
+ return container->GetContainerQuery().ToString();
+ }
+
+ // TODO(crbug.com/1145970): Remove this when ContainerQuery no longer
+ // relies on MediaQuerySet.
+ MediaQuerySet& GetMediaQuerySet(ContainerQuery& container_query) {
+ return *container_query.media_queries_;
+ }
+};
+
+TEST_F(ContainerQueryTest, PreludeParsing) {
+ // Valid:
+ EXPECT_EQ(
+ "(min-width: 300px)",
+ SerializeCondition(ParseAtContainer("@container (min-width: 300px) {}")));
+ EXPECT_EQ(
+ "(max-width: 500px)",
+ SerializeCondition(ParseAtContainer("@container (max-width: 500px) {}")));
+
+ // TODO(crbug.com/1145970): The MediaQuery parser emits a "not all"
+ // MediaQuery for parse failures. When ContainerQuery has its own parser,
+ // it should probably return nullptr instead.
+
+ // Invalid:
+ EXPECT_EQ("not all",
+ SerializeCondition(ParseAtContainer("@container 100px {}")));
+ EXPECT_EQ("not all",
+ SerializeCondition(ParseAtContainer("@container calc(1) {}")));
+}
+
+TEST_F(ContainerQueryTest, RuleParsing) {
+ StyleRuleContainer* container = ParseAtContainer(R"CSS(
+ @container (min-width: 100px) {
+ div { width: 100px; }
+ span { height: 100px; }
+ }
+ )CSS");
+ ASSERT_TRUE(container);
+
+ CSSStyleSheet* sheet = css_test_helpers::CreateStyleSheet(GetDocument());
+ auto* rule =
+ DynamicTo<CSSContainerRule>(container->CreateCSSOMWrapper(sheet));
+ ASSERT_TRUE(rule);
+ ASSERT_EQ(2u, rule->length());
+
+ auto* div_rule = rule->Item(0);
+ ASSERT_TRUE(div_rule);
+ EXPECT_EQ("div { width: 100px; }", div_rule->cssText());
+
+ auto* span_rule = rule->Item(1);
+ ASSERT_TRUE(span_rule);
+ EXPECT_EQ("span { height: 100px; }", span_rule->cssText());
+}
+
+TEST_F(ContainerQueryTest, RuleCopy) {
+ StyleRuleContainer* container = ParseAtContainer(R"CSS(
+ @container (min-width: 100px) {
+ div { width: 100px; }
+ }
+ )CSS");
+ ASSERT_TRUE(container);
+
+ // Copy via StyleRuleBase to test switch dispatch.
+ auto* copy_base = static_cast<StyleRuleBase*>(container)->Copy();
+ auto* copy = DynamicTo<StyleRuleContainer>(copy_base);
+ ASSERT_TRUE(copy);
+
+ // The StyleRuleContainer object should be copied.
+ EXPECT_NE(container, copy);
+
+ // The rules should be copied.
+ auto rules = container->ChildRules();
+ auto rules_copy = copy->ChildRules();
+ ASSERT_EQ(1u, rules.size());
+ ASSERT_EQ(1u, rules_copy.size());
+ EXPECT_NE(rules[0], rules_copy[0]);
+
+ // The ContainerQuery should be copied.
+ EXPECT_NE(&container->GetContainerQuery(), &copy->GetContainerQuery());
+
+ // The inner MediaQuerySet should be copied.
+ EXPECT_NE(&GetMediaQuerySet(container->GetContainerQuery()),
+ &GetMediaQuerySet(copy->GetContainerQuery()));
+}
+
+TEST_F(ContainerQueryTest, ContainerQueryEvaluation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #container {
+ contain: size layout;
+ width: 500px;
+ height: 500px;
+ }
+ #container.adjust {
+ width: 600px;
+ }
+
+ div { z-index:1; }
+ /* Should apply: */
+ @container (min-width: 500px) {
+ div { z-index:2; }
+ }
+ /* Should initially not apply: */
+ @container (min-width: 600px) {
+ div { z-index:3; }
+ }
+ </style>
+ <div id=container>
+ <div id=div></div>
+ </div>
+ )HTML");
+ Element* div = GetDocument().getElementById("div");
+ ASSERT_TRUE(div);
+ EXPECT_EQ(2, div->ComputedStyleRef().ZIndex());
+
+ // Check that dependent elements are responsive to changes:
+ Element* container = GetDocument().getElementById("container");
+ ASSERT_TRUE(container);
+ container->setAttribute(html_names::kClassAttr, "adjust");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(3, div->ComputedStyleRef().ZIndex());
+
+ container->setAttribute(html_names::kClassAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(2, div->ComputedStyleRef().ZIndex());
+}
+
+TEST_F(ContainerQueryTest, QueriedAxes) {
+ auto horizontal = PhysicalAxes(kPhysicalAxisHorizontal);
+ auto vertical = PhysicalAxes(kPhysicalAxisVertical);
+ auto both = PhysicalAxes(kPhysicalAxisBoth);
+ auto none = PhysicalAxes(kPhysicalAxisNone);
+
+ EXPECT_EQ(horizontal, QueriedAxes("(min-width: 1px)"));
+ EXPECT_EQ(horizontal, QueriedAxes("(max-width: 1px)"));
+ EXPECT_EQ(horizontal, QueriedAxes("(width: 1px)"));
+
+ EXPECT_EQ(vertical, QueriedAxes("(min-height: 1px)"));
+ EXPECT_EQ(vertical, QueriedAxes("(max-height: 1px)"));
+ EXPECT_EQ(vertical, QueriedAxes("(height: 1px)"));
+
+ EXPECT_EQ(both, QueriedAxes("(width: 1px) and (height: 1px)"));
+ EXPECT_EQ(both, QueriedAxes("(min-width: 1px) and (max-height: 1px)"));
+
+ // TODO(crbug.com/1145970): We want to test the case where no axes are
+ // queried (kPhysicalAxisNone). This can (for now) be achieved by using
+ // some media query feature (e.g. "resolution"). Ultimately, using
+ // "resolution" will not be allowed in @container: we will then need to find
+ // another way to author a container query that queries no axes (or make it
+ // illegal altogether).
+ EXPECT_EQ(none, QueriedAxes("(resolution: 150dpi)"));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style.cc b/chromium/third_party/blink/renderer/core/css/counter_style.cc
new file mode 100644
index 00000000000..b49e0fc43eb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style.cc
@@ -0,0 +1,686 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/counter_style.h"
+
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
+#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_string_value.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css/css_value_pair.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
+#include "third_party/blink/renderer/core/css_value_keywords.h"
+#include "third_party/blink/renderer/core/layout/list_marker_text.h"
+#include "third_party/blink/renderer/platform/text/text_break_iterator.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+namespace {
+
+// User agents must support representations at least 60 Unicode codepoints long,
+// but they may choose to instead use the fallback style for representations
+// that would be longer than 60 codepoints. Since WTF::String may use UTF-16, we
+// limit string length at 120.
+const wtf_size_t kCounterLengthLimit = 120;
+
+bool HasSymbols(CounterStyleSystem system) {
+ switch (system) {
+ case CounterStyleSystem::kCyclic:
+ case CounterStyleSystem::kFixed:
+ case CounterStyleSystem::kSymbolic:
+ case CounterStyleSystem::kAlphabetic:
+ case CounterStyleSystem::kNumeric:
+ case CounterStyleSystem::kAdditive:
+ return true;
+ case CounterStyleSystem::kUnresolvedExtends:
+ case CounterStyleSystem::kHebrew:
+ case CounterStyleSystem::kSimpChineseInformal:
+ case CounterStyleSystem::kSimpChineseFormal:
+ case CounterStyleSystem::kTradChineseInformal:
+ case CounterStyleSystem::kTradChineseFormal:
+ case CounterStyleSystem::kKoreanHangulFormal:
+ case CounterStyleSystem::kKoreanHanjaInformal:
+ case CounterStyleSystem::kKoreanHanjaFormal:
+ case CounterStyleSystem::kLowerArmenian:
+ case CounterStyleSystem::kUpperArmenian:
+ case CounterStyleSystem::kEthiopicNumeric:
+ return false;
+ }
+}
+
+String SymbolToString(const CSSValue& value) {
+ if (const CSSStringValue* string = DynamicTo<CSSStringValue>(value))
+ return string->Value();
+ return To<CSSCustomIdentValue>(value).Value();
+}
+
+std::pair<int, int> BoundsToIntegerPair(const CSSValuePair& bounds) {
+ int lower_bound, upper_bound;
+ if (bounds.First().IsIdentifierValue()) {
+ DCHECK_EQ(CSSValueID::kInfinite,
+ To<CSSIdentifierValue>(bounds.First()).GetValueID());
+ lower_bound = std::numeric_limits<int>::min();
+ } else {
+ DCHECK(bounds.First().IsPrimitiveValue());
+ lower_bound = To<CSSPrimitiveValue>(bounds.First()).GetIntValue();
+ }
+ if (bounds.Second().IsIdentifierValue()) {
+ DCHECK_EQ(CSSValueID::kInfinite,
+ To<CSSIdentifierValue>(bounds.Second()).GetValueID());
+ upper_bound = std::numeric_limits<int>::max();
+ } else {
+ DCHECK(bounds.Second().IsPrimitiveValue());
+ upper_bound = To<CSSPrimitiveValue>(bounds.Second()).GetIntValue();
+ }
+ return std::make_pair(lower_bound, upper_bound);
+}
+
+// https://drafts.csswg.org/css-counter-styles/#cyclic-system
+Vector<wtf_size_t> CyclicAlgorithm(int value, wtf_size_t num_symbols) {
+ DCHECK(num_symbols);
+ value %= static_cast<int>(num_symbols);
+ value -= 1;
+ if (value < 0)
+ value += num_symbols;
+ return {value};
+}
+
+// https://drafts.csswg.org/css-counter-styles/#fixed-system
+Vector<wtf_size_t> FixedAlgorithm(int value,
+ int first_symbol_value,
+ wtf_size_t num_symbols) {
+ if (value < first_symbol_value ||
+ static_cast<unsigned>(value - first_symbol_value) >= num_symbols)
+ return Vector<wtf_size_t>();
+ return {value - first_symbol_value};
+}
+
+// https://drafts.csswg.org/css-counter-styles/#symbolic-system
+Vector<wtf_size_t> SymbolicAlgorithm(unsigned value, wtf_size_t num_symbols) {
+ DCHECK(num_symbols);
+ if (!value)
+ return Vector<wtf_size_t>();
+ wtf_size_t index = (value - 1) % num_symbols;
+ wtf_size_t repetitions = (value + num_symbols - 1) / num_symbols;
+ if (repetitions > kCounterLengthLimit)
+ return Vector<wtf_size_t>();
+ return Vector<wtf_size_t>(repetitions, index);
+}
+
+// https://drafts.csswg.org/css-counter-styles/#alphabetic-system
+Vector<wtf_size_t> AlphabeticAlgorithm(unsigned value, wtf_size_t num_symbols) {
+ DCHECK(num_symbols);
+ if (!value)
+ return Vector<wtf_size_t>();
+ Vector<wtf_size_t> result;
+ while (value) {
+ value -= 1;
+ result.push_back(value % num_symbols);
+ value /= num_symbols;
+
+ // Since length is logarithmic to value, we won't exceed the length limit.
+ DCHECK_LE(result.size(), kCounterLengthLimit);
+ }
+ std::reverse(result.begin(), result.end());
+ return result;
+}
+
+// https://drafts.csswg.org/css-counter-styles/#numeric-system
+Vector<wtf_size_t> NumericAlgorithm(unsigned value, wtf_size_t num_symbols) {
+ DCHECK_GT(num_symbols, 1u);
+ if (!value)
+ return {0};
+
+ Vector<wtf_size_t> result;
+ while (value) {
+ result.push_back(value % num_symbols);
+ value /= num_symbols;
+
+ // Since length is logarithmic to value, we won't exceed the length limit.
+ DCHECK_LE(result.size(), kCounterLengthLimit);
+ }
+ std::reverse(result.begin(), result.end());
+ return result;
+}
+
+// https://drafts.csswg.org/css-counter-styles/#additive-system
+Vector<wtf_size_t> AdditiveAlgorithm(unsigned value,
+ const Vector<unsigned>& weights) {
+ DCHECK(weights.size());
+ if (!value) {
+ if (weights.back() == 0u)
+ return {weights.size() - 1};
+ return Vector<wtf_size_t>();
+ }
+
+ Vector<wtf_size_t> result;
+ for (wtf_size_t index = 0; value && index < weights.size() && weights[index];
+ ++index) {
+ wtf_size_t repetitions = value / weights[index];
+ if (repetitions) {
+ if (result.size() + repetitions > kCounterLengthLimit)
+ return Vector<wtf_size_t>();
+ result.AppendVector(Vector<wtf_size_t>(repetitions, index));
+ }
+ value %= weights[index];
+ }
+ if (value)
+ return Vector<wtf_size_t>();
+ return result;
+}
+
+// TODO(crbug.com/687225): After @counter-style is shipped and the legacy
+// code paths are removed, remove everything else of list_marker_text and move
+// the implementation of the special algorithms here.
+
+String HebrewAlgorithm(unsigned value) {
+ if (value > 999999)
+ return String();
+ return list_marker_text::GetText(EListStyleType::kHebrew, value);
+}
+
+int AbsoluteValueForLegacyCJKAlgorithms(int value) {
+ // @counter-style algorithm works on absolute value, but the legacy
+ // implementation works on the original value (and handles negative sign on
+ // its own). Clamp to the signed int range before proceeding.
+ if (UNLIKELY(value == std::numeric_limits<int>::min()))
+ return std::numeric_limits<int>::max();
+ else
+ return std::abs(value);
+}
+
+String SimpChineseInformalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kSimpChineseInformal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String SimpChineseFormalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kSimpChineseFormal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String TradChineseInformalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kTradChineseInformal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String TradChineseFormalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kTradChineseFormal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String KoreanHangulFormalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kKoreanHangulFormal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String KoreanHanjaInformalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kKoreanHanjaInformal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String KoreanHanjaFormalAlgorithm(int value) {
+ return list_marker_text::GetText(EListStyleType::kKoreanHanjaFormal,
+ AbsoluteValueForLegacyCJKAlgorithms(value));
+}
+
+String LowerArmenianAlgorithm(unsigned value) {
+ if (value > 99999999)
+ return String();
+ return list_marker_text::GetText(EListStyleType::kLowerArmenian, value);
+}
+
+String UpperArmenianAlgorithm(unsigned value) {
+ if (value > 99999999)
+ return String();
+ return list_marker_text::GetText(EListStyleType::kUpperArmenian, value);
+}
+
+// https://drafts.csswg.org/css-counter-styles-3/#ethiopic-numeric-counter-style
+String EthiopicNumericAlgorithm(unsigned value) {
+ // Ethiopic characters for 1-9
+ static const UChar units[9] = {0x1369, 0x136A, 0x136B, 0x136C, 0x136D,
+ 0x136E, 0x136F, 0x1370, 0x1371};
+ // Ethiopic characters for 10, 20, ..., 90
+ static const UChar tens[9] = {0x1372, 0x1373, 0x1374, 0x1375, 0x1376,
+ 0x1377, 0x1378, 0x1379, 0x137A};
+ if (!value)
+ return String();
+ if (value < 10u)
+ return String(&units[value - 1], 1);
+
+ // Generate characters in the reversed ordering
+ Vector<UChar> result;
+ for (bool odd_group = false; value; odd_group = !odd_group) {
+ unsigned group_value = value % 100;
+ value /= 100;
+ if (!odd_group) {
+ // This adds an extra character for group 0. We'll remove it in the end.
+ result.push_back(kEthiopicNumberTenThousandCharacter);
+ } else {
+ if (group_value)
+ result.push_back(kEthiopicNumberHundredCharacter);
+ }
+ bool most_significant_group = !value;
+ bool remove_digits = !group_value ||
+ (group_value == 1 && most_significant_group) ||
+ (group_value == 1 && odd_group);
+ if (!remove_digits) {
+ if (unsigned unit = group_value % 10)
+ result.push_back(units[unit - 1]);
+ if (unsigned ten = group_value / 10)
+ result.push_back(tens[ten - 1]);
+ }
+ }
+
+ std::reverse(result.begin(), result.end());
+ // Remove the extra character from group 0
+ result.pop_back();
+ return String(result.data(), result.size());
+}
+
+} // namespace
+
+// static
+CounterStyle& CounterStyle::GetDecimal() {
+ DEFINE_STATIC_LOCAL(
+ Persistent<CounterStyle>, decimal,
+ (CounterStyleMap::GetUACounterStyleMap()->FindCounterStyleAcrossScopes(
+ "decimal")));
+ DCHECK(decimal);
+ return *decimal;
+}
+
+// static
+CounterStyleSystem CounterStyle::ToCounterStyleSystemEnum(
+ const CSSValue* value) {
+ if (!value)
+ return CounterStyleSystem::kSymbolic;
+
+ CSSValueID system_keyword;
+ if (const auto* id = DynamicTo<CSSIdentifierValue>(value)) {
+ system_keyword = id->GetValueID();
+ } else {
+ // Either fixed or extends.
+ DCHECK(value->IsValuePair());
+ const CSSValuePair* pair = To<CSSValuePair>(value);
+ DCHECK(pair->First().IsIdentifierValue());
+ system_keyword = To<CSSIdentifierValue>(pair->First()).GetValueID();
+ }
+
+ switch (system_keyword) {
+ case CSSValueID::kCyclic:
+ return CounterStyleSystem::kCyclic;
+ case CSSValueID::kFixed:
+ return CounterStyleSystem::kFixed;
+ case CSSValueID::kSymbolic:
+ return CounterStyleSystem::kSymbolic;
+ case CSSValueID::kAlphabetic:
+ return CounterStyleSystem::kAlphabetic;
+ case CSSValueID::kNumeric:
+ return CounterStyleSystem::kNumeric;
+ case CSSValueID::kAdditive:
+ return CounterStyleSystem::kAdditive;
+ case CSSValueID::kInternalHebrew:
+ return CounterStyleSystem::kHebrew;
+ case CSSValueID::kInternalSimpChineseInformal:
+ return CounterStyleSystem::kSimpChineseInformal;
+ case CSSValueID::kInternalSimpChineseFormal:
+ return CounterStyleSystem::kSimpChineseFormal;
+ case CSSValueID::kInternalTradChineseInformal:
+ return CounterStyleSystem::kTradChineseInformal;
+ case CSSValueID::kInternalTradChineseFormal:
+ return CounterStyleSystem::kTradChineseFormal;
+ case CSSValueID::kInternalKoreanHangulFormal:
+ return CounterStyleSystem::kKoreanHangulFormal;
+ case CSSValueID::kInternalKoreanHanjaInformal:
+ return CounterStyleSystem::kKoreanHanjaInformal;
+ case CSSValueID::kInternalKoreanHanjaFormal:
+ return CounterStyleSystem::kKoreanHanjaFormal;
+ case CSSValueID::kInternalLowerArmenian:
+ return CounterStyleSystem::kLowerArmenian;
+ case CSSValueID::kInternalUpperArmenian:
+ return CounterStyleSystem::kUpperArmenian;
+ case CSSValueID::kInternalEthiopicNumeric:
+ return CounterStyleSystem::kEthiopicNumeric;
+ case CSSValueID::kExtends:
+ return CounterStyleSystem::kUnresolvedExtends;
+ default:
+ NOTREACHED();
+ return CounterStyleSystem::kSymbolic;
+ }
+}
+
+CounterStyle::~CounterStyle() = default;
+
+AtomicString CounterStyle::GetName() const {
+ return style_rule_->GetName();
+}
+
+// static
+CounterStyle* CounterStyle::Create(const StyleRuleCounterStyle& rule) {
+ if (!rule.HasValidSymbols())
+ return nullptr;
+
+ return MakeGarbageCollected<CounterStyle>(rule);
+}
+
+CounterStyle::CounterStyle(const StyleRuleCounterStyle& rule)
+ : style_rule_(rule), style_rule_version_(rule.GetVersion()) {
+ if (const CSSValue* system = rule.GetSystem()) {
+ system_ = ToCounterStyleSystemEnum(system);
+
+ if (system_ == CounterStyleSystem::kUnresolvedExtends) {
+ const auto& second = To<CSSValuePair>(system)->Second();
+ extends_name_ = To<CSSCustomIdentValue>(second).Value();
+ } else if (system_ == CounterStyleSystem::kFixed && system->IsValuePair()) {
+ const auto& second = To<CSSValuePair>(system)->Second();
+ first_symbol_value_ = To<CSSPrimitiveValue>(second).GetIntValue();
+ }
+ }
+
+ if (const CSSValue* fallback = rule.GetFallback())
+ fallback_name_ = To<CSSCustomIdentValue>(fallback)->Value();
+
+ if (HasSymbols(system_)) {
+ if (system_ == CounterStyleSystem::kAdditive) {
+ for (const CSSValue* symbol :
+ To<CSSValueList>(*rule.GetAdditiveSymbols())) {
+ const auto& pair = To<CSSValuePair>(*symbol);
+ additive_weights_.push_back(
+ To<CSSPrimitiveValue>(pair.First()).GetIntValue());
+ symbols_.push_back(SymbolToString(pair.Second()));
+ }
+ } else {
+ for (const CSSValue* symbol : To<CSSValueList>(*rule.GetSymbols()))
+ symbols_.push_back(SymbolToString(*symbol));
+ }
+ }
+
+ if (const CSSValue* negative = rule.GetNegative()) {
+ if (const CSSValuePair* pair = DynamicTo<CSSValuePair>(negative)) {
+ negative_prefix_ = SymbolToString(pair->First());
+ negative_suffix_ = SymbolToString(pair->Second());
+ } else {
+ negative_prefix_ = SymbolToString(*negative);
+ }
+ }
+
+ if (const CSSValue* pad = rule.GetPad()) {
+ const CSSValuePair& pair = To<CSSValuePair>(*pad);
+ pad_length_ = To<CSSPrimitiveValue>(pair.First()).GetIntValue();
+ pad_symbol_ = SymbolToString(pair.Second());
+ }
+
+ if (const CSSValue* range = rule.GetRange()) {
+ if (range->IsIdentifierValue()) {
+ DCHECK_EQ(CSSValueID::kAuto, To<CSSIdentifierValue>(range)->GetValueID());
+ // Empty |range_| already means 'auto'.
+ } else {
+ for (const CSSValue* bounds : To<CSSValueList>(*range))
+ range_.push_back(BoundsToIntegerPair(To<CSSValuePair>(*bounds)));
+ }
+ }
+
+ if (const CSSValue* prefix = rule.GetPrefix())
+ prefix_ = SymbolToString(*prefix);
+ if (const CSSValue* suffix = rule.GetSuffix())
+ suffix_ = SymbolToString(*suffix);
+
+ // TODO(crbug.com/1166766): Implement 'speak-as'.
+}
+
+void CounterStyle::ResolveExtends(CounterStyle& extended) {
+ DCHECK_NE(extended.system_, CounterStyleSystem::kUnresolvedExtends);
+ extended_style_ = extended;
+
+ system_ = extended.system_;
+
+ if (system_ == CounterStyleSystem::kFixed)
+ first_symbol_value_ = extended.first_symbol_value_;
+
+ if (!style_rule_->GetFallback()) {
+ fallback_name_ = extended.fallback_name_;
+ fallback_style_ = nullptr;
+ }
+
+ symbols_ = extended.symbols_;
+ if (system_ == CounterStyleSystem::kAdditive)
+ additive_weights_ = extended.additive_weights_;
+
+ if (!style_rule_->GetNegative()) {
+ negative_prefix_ = extended.negative_prefix_;
+ negative_suffix_ = extended.negative_suffix_;
+ }
+
+ if (!style_rule_->GetPad()) {
+ pad_length_ = extended.pad_length_;
+ pad_symbol_ = extended.pad_symbol_;
+ }
+
+ if (!style_rule_->GetRange())
+ range_ = extended.range_;
+
+ if (!style_rule_->GetPrefix())
+ prefix_ = extended.prefix_;
+ if (!style_rule_->GetSuffix())
+ suffix_ = extended.suffix_;
+
+ // TODO(crbug.com/1166766): Implement 'speak-as'.
+}
+
+bool CounterStyle::RangeContains(int value) const {
+ if (range_.size()) {
+ for (const auto& bounds : range_) {
+ if (value >= bounds.first && value <= bounds.second)
+ return true;
+ }
+ return false;
+ }
+
+ // 'range' value is auto
+ switch (system_) {
+ case CounterStyleSystem::kCyclic:
+ case CounterStyleSystem::kNumeric:
+ case CounterStyleSystem::kFixed:
+ case CounterStyleSystem::kSimpChineseInformal:
+ case CounterStyleSystem::kSimpChineseFormal:
+ case CounterStyleSystem::kTradChineseInformal:
+ case CounterStyleSystem::kTradChineseFormal:
+ case CounterStyleSystem::kKoreanHangulFormal:
+ case CounterStyleSystem::kKoreanHanjaInformal:
+ case CounterStyleSystem::kKoreanHanjaFormal:
+ return true;
+ case CounterStyleSystem::kSymbolic:
+ case CounterStyleSystem::kAlphabetic:
+ case CounterStyleSystem::kEthiopicNumeric:
+ return value >= 1;
+ case CounterStyleSystem::kAdditive:
+ return value >= 0;
+ case CounterStyleSystem::kHebrew:
+ return value >= 0 && value <= 999999;
+ case CounterStyleSystem::kLowerArmenian:
+ case CounterStyleSystem::kUpperArmenian:
+ return value >= 0 && value <= 99999999;
+ case CounterStyleSystem::kUnresolvedExtends:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool CounterStyle::NeedsNegativeSign(int value) const {
+ if (value >= 0)
+ return false;
+ switch (system_) {
+ case CounterStyleSystem::kSymbolic:
+ case CounterStyleSystem::kAlphabetic:
+ case CounterStyleSystem::kNumeric:
+ case CounterStyleSystem::kAdditive:
+ case CounterStyleSystem::kHebrew:
+ case CounterStyleSystem::kSimpChineseInformal:
+ case CounterStyleSystem::kSimpChineseFormal:
+ case CounterStyleSystem::kTradChineseInformal:
+ case CounterStyleSystem::kTradChineseFormal:
+ case CounterStyleSystem::kKoreanHangulFormal:
+ case CounterStyleSystem::kKoreanHanjaInformal:
+ case CounterStyleSystem::kKoreanHanjaFormal:
+ case CounterStyleSystem::kLowerArmenian:
+ case CounterStyleSystem::kUpperArmenian:
+ case CounterStyleSystem::kEthiopicNumeric:
+ return true;
+ case CounterStyleSystem::kCyclic:
+ case CounterStyleSystem::kFixed:
+ return false;
+ case CounterStyleSystem::kUnresolvedExtends:
+ NOTREACHED();
+ return false;
+ }
+}
+
+String CounterStyle::GenerateFallbackRepresentation(int value) const {
+ if (is_in_fallback_) {
+ // We are in a fallback cycle. Use decimal instead.
+ return GetDecimal().GenerateRepresentation(value);
+ }
+
+ base::AutoReset<bool> in_fallback_scope(&is_in_fallback_, true);
+ return fallback_style_->GenerateRepresentation(value);
+}
+
+String CounterStyle::GenerateRepresentation(int value) const {
+ DCHECK(!IsDirty());
+
+ if (pad_length_ > kCounterLengthLimit)
+ return GenerateFallbackRepresentation(value);
+
+ String initial_representation = GenerateInitialRepresentation(value);
+ if (initial_representation.IsNull())
+ return GenerateFallbackRepresentation(value);
+
+ wtf_size_t initial_length = NumGraphemeClusters(initial_representation);
+
+ // TODO(crbug.com/687225): Spec requires us to further increment
+ // |initial_length| by the length of the negative sign, but no current
+ // implementation is doing that. For backward compatibility, we don't do that
+ // for now. See https://github.com/w3c/csswg-drafts/issues/5906 for details.
+ //
+ // if (NeedsNegativeSign(value)) {
+ // initial_length += NumGraphemeClusters(negative_prefix_);
+ // initial_length += NumGraphemeClusters(negative_suffix_);
+ // }
+
+ wtf_size_t pad_copies =
+ pad_length_ > initial_length ? pad_length_ - initial_length : 0;
+
+ StringBuilder result;
+ if (NeedsNegativeSign(value))
+ result.Append(negative_prefix_);
+ for (wtf_size_t i = 0; i < pad_copies; ++i)
+ result.Append(pad_symbol_);
+ result.Append(initial_representation);
+ if (NeedsNegativeSign(value))
+ result.Append(negative_suffix_);
+ return result.ToString();
+}
+
+String CounterStyle::GenerateInitialRepresentation(int value) const {
+ if (!RangeContains(value))
+ return String();
+
+ unsigned abs_value =
+ value == std::numeric_limits<int>::min()
+ ? static_cast<unsigned>(std::numeric_limits<int>::max()) + 1u
+ : std::abs(value);
+
+ switch (system_) {
+ case CounterStyleSystem::kCyclic:
+ return IndexesToString(CyclicAlgorithm(value, symbols_.size()));
+ case CounterStyleSystem::kFixed:
+ return IndexesToString(
+ FixedAlgorithm(value, first_symbol_value_, symbols_.size()));
+ case CounterStyleSystem::kNumeric:
+ return IndexesToString(NumericAlgorithm(abs_value, symbols_.size()));
+ case CounterStyleSystem::kSymbolic:
+ return IndexesToString(SymbolicAlgorithm(abs_value, symbols_.size()));
+ case CounterStyleSystem::kAlphabetic:
+ return IndexesToString(AlphabeticAlgorithm(abs_value, symbols_.size()));
+ case CounterStyleSystem::kAdditive:
+ return IndexesToString(AdditiveAlgorithm(abs_value, additive_weights_));
+ case CounterStyleSystem::kHebrew:
+ return HebrewAlgorithm(abs_value);
+ case CounterStyleSystem::kSimpChineseInformal:
+ return SimpChineseInformalAlgorithm(value);
+ case CounterStyleSystem::kSimpChineseFormal:
+ return SimpChineseFormalAlgorithm(value);
+ case CounterStyleSystem::kTradChineseInformal:
+ return TradChineseInformalAlgorithm(value);
+ case CounterStyleSystem::kTradChineseFormal:
+ return TradChineseFormalAlgorithm(value);
+ case CounterStyleSystem::kKoreanHangulFormal:
+ return KoreanHangulFormalAlgorithm(value);
+ case CounterStyleSystem::kKoreanHanjaInformal:
+ return KoreanHanjaInformalAlgorithm(value);
+ case CounterStyleSystem::kKoreanHanjaFormal:
+ return KoreanHanjaFormalAlgorithm(value);
+ case CounterStyleSystem::kLowerArmenian:
+ return LowerArmenianAlgorithm(abs_value);
+ case CounterStyleSystem::kUpperArmenian:
+ return UpperArmenianAlgorithm(abs_value);
+ case CounterStyleSystem::kEthiopicNumeric:
+ return EthiopicNumericAlgorithm(abs_value);
+ case CounterStyleSystem::kUnresolvedExtends:
+ NOTREACHED();
+ return String();
+ }
+}
+
+String CounterStyle::IndexesToString(
+ const Vector<wtf_size_t>& symbol_indexes) const {
+ if (symbol_indexes.IsEmpty())
+ return String();
+
+ StringBuilder result;
+ for (wtf_size_t index : symbol_indexes)
+ result.Append(symbols_[index]);
+ return result.ToString();
+}
+
+void CounterStyle::TraverseAndMarkDirtyIfNeeded(
+ HeapHashSet<Member<CounterStyle>>& visited_counter_styles) {
+ if (IsPredefined() || visited_counter_styles.Contains(this))
+ return;
+ visited_counter_styles.insert(this);
+
+ if (has_inexistent_references_ ||
+ style_rule_version_ != style_rule_->GetVersion()) {
+ SetIsDirty();
+ return;
+ }
+
+ if (extended_style_) {
+ extended_style_->TraverseAndMarkDirtyIfNeeded(visited_counter_styles);
+ if (extended_style_->IsDirty()) {
+ SetIsDirty();
+ return;
+ }
+ }
+
+ if (fallback_style_) {
+ fallback_style_->TraverseAndMarkDirtyIfNeeded(visited_counter_styles);
+ if (fallback_style_->IsDirty()) {
+ SetIsDirty();
+ return;
+ }
+ }
+}
+
+void CounterStyle::Trace(Visitor* visitor) const {
+ visitor->Trace(style_rule_);
+ visitor->Trace(extended_style_);
+ visitor->Trace(fallback_style_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style.h b/chromium/third_party/blink/renderer/core/css/counter_style.h
new file mode 100644
index 00000000000..7dc26c957f8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style.h
@@ -0,0 +1,169 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink {
+
+class StyleRuleCounterStyle;
+class CSSValue;
+
+enum class CounterStyleSystem {
+ kCyclic,
+ kFixed,
+ kSymbolic,
+ kAlphabetic,
+ kNumeric,
+ kAdditive,
+ kHebrew,
+ kSimpChineseInformal,
+ kSimpChineseFormal,
+ kTradChineseInformal,
+ kTradChineseFormal,
+ kKoreanHangulFormal,
+ kKoreanHanjaInformal,
+ kKoreanHanjaFormal,
+ kLowerArmenian,
+ kUpperArmenian,
+ kEthiopicNumeric,
+ kUnresolvedExtends,
+};
+
+// Represents a valid counter style defined in a tree scope.
+class CORE_EXPORT CounterStyle final : public GarbageCollected<CounterStyle> {
+ public:
+ static CounterStyle& GetDecimal();
+
+ static CounterStyleSystem ToCounterStyleSystemEnum(const CSSValue* value);
+
+ // Returns nullptr if the @counter-style rule is invalid.
+ static CounterStyle* Create(const StyleRuleCounterStyle&);
+
+ const StyleRuleCounterStyle& GetStyleRule() const { return *style_rule_; }
+
+ AtomicString GetName() const;
+ CounterStyleSystem GetSystem() const { return system_; }
+
+ bool IsPredefined() const { return is_predefined_; }
+ void SetIsPredefined() { is_predefined_ = true; }
+
+ // Returns true for the predefined symbolic counter styles 'disc', 'circle',
+ // 'square', 'disclosure-open' and 'disclosure-closed'.
+ bool IsPredefinedSymbolMarker() const { return is_predefined_symbol_marker_; }
+ void SetIsPredefinedSymbolMarker() { is_predefined_symbol_marker_ = true; }
+
+ // A CounterStyle object is dirtied when the information it holds becomes
+ // stale, e.g., when the style rule mutated or the 'extends' or 'fallback'
+ // counter styles mutated, etc. Once dirtied, it will never be reused, and
+ // will be removed or replaced by a newly created clean CounterStyle.
+ // Elements using dirty CounterStyles should update style and layout.
+ bool IsDirty() const { return is_dirty_; }
+ void SetIsDirty() { is_dirty_ = true; }
+
+ void TraverseAndMarkDirtyIfNeeded(HeapHashSet<Member<CounterStyle>>& visited);
+
+ // Set to true when there's no counter style matching 'extends' or 'fallback',
+ // and therefore we are resorting to 'decimal'.
+ void SetHasInexistentReferences() { has_inexistent_references_ = true; }
+
+ // https://drafts.csswg.org/css-counter-styles/#generate-a-counter
+ String GenerateRepresentation(int value) const;
+
+ String GetPrefix() const { return prefix_; }
+ String GetSuffix() const { return suffix_; }
+
+ AtomicString GetExtendsName() const { return extends_name_; }
+ const CounterStyle& GetExtendedStyle() const { return *extended_style_; }
+ bool HasUnresolvedExtends() const {
+ return system_ == CounterStyleSystem::kUnresolvedExtends;
+ }
+ void ResolveExtends(CounterStyle& extended);
+
+ AtomicString GetFallbackName() const { return fallback_name_; }
+ const CounterStyle& GetFallbackStyle() const { return *fallback_style_; }
+ bool HasUnresolvedFallback() const { return !fallback_style_; }
+ void ResolveFallback(CounterStyle& fallback) { fallback_style_ = &fallback; }
+
+ void Trace(Visitor*) const;
+
+ explicit CounterStyle(const StyleRuleCounterStyle& rule);
+ ~CounterStyle();
+
+ private:
+ // https://drafts.csswg.org/css-counter-styles/#counter-style-range
+ bool RangeContains(int value) const;
+
+ // Returns true if a negative sign is needed for the value.
+ // https://drafts.csswg.org/css-counter-styles/#counter-style-negative
+ bool NeedsNegativeSign(int value) const;
+
+ // https://drafts.csswg.org/css-counter-styles/#initial-representation-for-the-counter-value
+ // Returns nullptr if the counter value cannot be represented with the given
+ // 'system', 'range' and 'symbols'/'additive-symbols' descriptor values.
+ String GenerateInitialRepresentation(int value) const;
+
+ // Uses the fallback counter style to generate a representation for the value.
+ // It may recurse, and if it enters a loop, it uses 'decimal' instead.
+ String GenerateFallbackRepresentation(int value) const;
+
+ String IndexesToString(const Vector<wtf_size_t>& symbol_indexes) const;
+
+ // The corresponding style rule in CSS.
+ Member<const StyleRuleCounterStyle> style_rule_;
+
+ // Tracks mutations of |style_rule_|.
+ int style_rule_version_;
+
+ // The actual system of the counter style with 'extends' resolved. The value
+ // is kUnresolvedExtends temporarily before the resolution.
+ CounterStyleSystem system_ = CounterStyleSystem::kSymbolic;
+
+ AtomicString extends_name_;
+ Member<CounterStyle> extended_style_;
+
+ AtomicString fallback_name_ = "decimal";
+ Member<CounterStyle> fallback_style_;
+
+ // True if we are looking for a fallback counter style to generate a counter
+ // value. Supports cycle detection in fallback.
+ mutable bool is_in_fallback_ = false;
+
+ // Value of 'symbols' for non-additive systems; Or symbol values in
+ // 'additive-symbols' for the 'additive' system.
+ Vector<String> symbols_;
+
+ // Additive weights, for the 'additive' system only.
+ Vector<unsigned> additive_weights_;
+
+ // Value of 'range' descriptor. Empty vector means 'auto'.
+ Vector<std::pair<int, int>> range_;
+
+ String prefix_;
+ String suffix_ = ". ";
+
+ String negative_prefix_ = "-";
+ String negative_suffix_;
+
+ String pad_symbol_;
+ wtf_size_t pad_length_ = 0;
+
+ // First symbol value, for 'fixed' system only.
+ wtf_size_t first_symbol_value_ = 1;
+
+ bool is_predefined_ = false;
+ bool is_predefined_symbol_marker_ = false;
+ bool has_inexistent_references_ = false;
+ bool is_dirty_ = false;
+
+ friend class CounterStyleMapTest;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_H_
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style_map.cc b/chromium/third_party/blink/renderer/core/css/counter_style_map.cc
new file mode 100644
index 00000000000..e1feebc435c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style_map.cc
@@ -0,0 +1,296 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
+
+#include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
+#include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
+#include "third_party/blink/renderer/core/css/rule_set.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+
+namespace blink {
+
+namespace {
+
+const char* predefined_symbol_markers[] = {
+ "disc", "square", "circle", "disclosure-open", "disclosure-closed"};
+
+CounterStyleMap* CreateUACounterStyleMap() {
+ CounterStyleMap* map =
+ MakeGarbageCollected<CounterStyleMap>(nullptr, nullptr);
+ map->AddCounterStyles(*CSSDefaultStyleSheets::Instance().DefaultStyle());
+ map->SetIsPredefined();
+ for (const char* symbol_marker : predefined_symbol_markers) {
+ map->FindCounterStyleAcrossScopes(symbol_marker)
+ ->SetIsPredefinedSymbolMarker();
+ }
+ HeapHashSet<Member<CounterStyleMap>> dummy_visited;
+ map->ResolveReferences(dummy_visited);
+ return map;
+}
+
+} // namespace
+
+void CounterStyleMap::SetIsPredefined() {
+ for (CounterStyle* counter_style : counter_styles_.Values())
+ counter_style->SetIsPredefined();
+}
+
+// static
+CounterStyleMap* CounterStyleMap::GetUACounterStyleMap() {
+ DEFINE_STATIC_LOCAL(Persistent<CounterStyleMap>, ua_counter_style_map,
+ (CreateUACounterStyleMap()));
+ return ua_counter_style_map;
+}
+
+// static
+CounterStyleMap* CounterStyleMap::GetUserCounterStyleMap(Document& document) {
+ return document.GetStyleEngine().GetUserCounterStyleMap();
+}
+
+// static
+CounterStyleMap* CounterStyleMap::GetAuthorCounterStyleMap(
+ const TreeScope& scope) {
+ if (!scope.GetScopedStyleResolver())
+ return nullptr;
+ return scope.GetScopedStyleResolver()->GetCounterStyleMap();
+}
+
+// static
+CounterStyleMap* CounterStyleMap::CreateUserCounterStyleMap(
+ Document& document) {
+ return MakeGarbageCollected<CounterStyleMap>(&document, nullptr);
+}
+
+// static
+CounterStyleMap* CounterStyleMap::CreateAuthorCounterStyleMap(
+ TreeScope& tree_scope) {
+ return MakeGarbageCollected<CounterStyleMap>(&tree_scope.GetDocument(),
+ &tree_scope);
+}
+
+CounterStyleMap::CounterStyleMap(Document* document, TreeScope* tree_scope)
+ : owner_document_(document), tree_scope_(tree_scope) {
+#if DCHECK_IS_ON()
+ if (tree_scope)
+ DCHECK_EQ(document, &tree_scope->GetDocument());
+#endif
+}
+
+void CounterStyleMap::AddCounterStyles(const RuleSet& rule_set) {
+ if (!rule_set.CounterStyleRules().size())
+ return;
+
+ for (StyleRuleCounterStyle* rule : rule_set.CounterStyleRules()) {
+ CounterStyle* counter_style = CounterStyle::Create(*rule);
+ if (!counter_style) {
+ DCHECK(owner_document_) << "Predefined counter style " << rule->GetName()
+ << " has invalid symbols";
+ continue;
+ }
+ AtomicString name = rule->GetName();
+ if (CounterStyle* replaced = counter_styles_.at(name))
+ replaced->SetIsDirty();
+ counter_styles_.Set(rule->GetName(), counter_style);
+ }
+
+ if (owner_document_)
+ owner_document_->GetStyleEngine().MarkCounterStylesNeedUpdate();
+}
+
+CounterStyleMap* CounterStyleMap::GetAncestorMap() const {
+ if (tree_scope_) {
+ // Resursively walk up to parent scope to find an author CounterStyleMap.
+ for (TreeScope* scope = tree_scope_->ParentTreeScope(); scope;
+ scope = scope->ParentTreeScope()) {
+ if (CounterStyleMap* map = GetAuthorCounterStyleMap(*scope))
+ return map;
+ }
+
+ // Fallback to user counter style map
+ if (CounterStyleMap* user_map = GetUserCounterStyleMap(*owner_document_))
+ return user_map;
+ }
+
+ // Author and user counter style maps fall back to UA
+ if (owner_document_)
+ return GetUACounterStyleMap();
+
+ // UA counter style map doesn't have any fallback
+ return nullptr;
+}
+
+CounterStyle* CounterStyleMap::FindCounterStyleAcrossScopes(
+ const AtomicString& name) const {
+ if (CounterStyle* style = counter_styles_.at(name))
+ return style;
+
+ if (CounterStyleMap* ancestor_map = GetAncestorMap())
+ return ancestor_map->FindCounterStyleAcrossScopes(name);
+
+ return nullptr;
+}
+
+void CounterStyleMap::ResolveExtendsFor(CounterStyle& counter_style) {
+ DCHECK(counter_style.HasUnresolvedExtends());
+
+ HeapVector<Member<CounterStyle>, 2> extends_chain;
+ HeapHashSet<Member<CounterStyle>> unresolved_styles;
+ extends_chain.push_back(&counter_style);
+ do {
+ unresolved_styles.insert(extends_chain.back());
+ AtomicString extends_name = extends_chain.back()->GetExtendsName();
+ extends_chain.push_back(FindCounterStyleAcrossScopes(extends_name));
+ } while (extends_chain.back() &&
+ extends_chain.back()->HasUnresolvedExtends() &&
+ !unresolved_styles.Contains(extends_chain.back()));
+
+ // If one or more @counter-style rules form a cycle with their extends values,
+ // all of the counter styles participating in the cycle must be treated as if
+ // they were extending the 'decimal' counter style instead.
+ if (extends_chain.back() && extends_chain.back()->HasUnresolvedExtends()) {
+ CounterStyle* cycle_start = extends_chain.back();
+ do {
+ extends_chain.back()->ResolveExtends(CounterStyle::GetDecimal());
+ extends_chain.pop_back();
+ } while (extends_chain.back() != cycle_start);
+ }
+
+ CounterStyle* next = extends_chain.back();
+ while (extends_chain.size() > 1u) {
+ extends_chain.pop_back();
+ if (next) {
+ extends_chain.back()->ResolveExtends(*next);
+ } else {
+ extends_chain.back()->ResolveExtends(CounterStyle::GetDecimal());
+ extends_chain.back()->SetHasInexistentReferences();
+ }
+
+ next = extends_chain.back();
+ }
+}
+
+void CounterStyleMap::ResolveFallbackFor(CounterStyle& counter_style) {
+ DCHECK(counter_style.HasUnresolvedFallback());
+ AtomicString fallback_name = counter_style.GetFallbackName();
+ CounterStyle* fallback_style = FindCounterStyleAcrossScopes(fallback_name);
+ if (fallback_style) {
+ counter_style.ResolveFallback(*fallback_style);
+ } else {
+ counter_style.ResolveFallback(CounterStyle::GetDecimal());
+ counter_style.SetHasInexistentReferences();
+ }
+}
+
+void CounterStyleMap::ResolveReferences(
+ HeapHashSet<Member<CounterStyleMap>>& visited_maps) {
+ if (visited_maps.Contains(this))
+ return;
+ visited_maps.insert(this);
+
+ // References in ancestor scopes must be resolved first.
+ if (CounterStyleMap* ancestor_map = GetAncestorMap())
+ ancestor_map->ResolveReferences(visited_maps);
+
+ for (CounterStyle* counter_style : counter_styles_.Values()) {
+ if (counter_style->HasUnresolvedExtends())
+ ResolveExtendsFor(*counter_style);
+ if (counter_style->HasUnresolvedFallback())
+ ResolveFallbackFor(*counter_style);
+ }
+}
+
+void CounterStyleMap::MarkDirtyCounterStyles(
+ HeapHashSet<Member<CounterStyle>>& visited_counter_styles) {
+ for (CounterStyle* counter_style : counter_styles_.Values())
+ counter_style->TraverseAndMarkDirtyIfNeeded(visited_counter_styles);
+
+ // Replace dirty CounterStyles by clean ones with unresolved references.
+ for (Member<CounterStyle>& counter_style_ref : counter_styles_.Values()) {
+ if (counter_style_ref->IsDirty()) {
+ CounterStyle* clean_style =
+ MakeGarbageCollected<CounterStyle>(counter_style_ref->GetStyleRule());
+ counter_style_ref = clean_style;
+ }
+ }
+}
+
+// static
+void CounterStyleMap::MarkAllDirtyCounterStyles(
+ Document& document,
+ const HeapHashSet<Member<TreeScope>>& active_tree_scopes) {
+ // Traverse all CounterStyle objects in the document to mark dirtiness.
+ // We assume that there are not too many CounterStyle objects, so this won't
+ // be a performance bottleneck.
+ TRACE_EVENT0("blink", "CounterStyleMap::MarkAllDirtyCounterStyles");
+
+ HeapHashSet<Member<CounterStyle>> visited_counter_styles;
+
+ if (CounterStyleMap* user_map = GetUserCounterStyleMap(document))
+ user_map->MarkDirtyCounterStyles(visited_counter_styles);
+
+ if (CounterStyleMap* document_map = GetAuthorCounterStyleMap(document))
+ document_map->MarkDirtyCounterStyles(visited_counter_styles);
+
+ for (const TreeScope* scope : active_tree_scopes) {
+ if (CounterStyleMap* scoped_map = GetAuthorCounterStyleMap(*scope))
+ scoped_map->MarkDirtyCounterStyles(visited_counter_styles);
+ }
+}
+
+// static
+void CounterStyleMap::ResolveAllReferences(
+ Document& document,
+ const HeapHashSet<Member<TreeScope>>& active_tree_scopes) {
+ // Traverse all counter style maps to find and update CounterStyles that are
+ // dirty or have unresolved references. We assume there are not too many
+ // CounterStyles, so that this won't be a performance bottleneck.
+ TRACE_EVENT0("blink", "CounterStyleMap::ResolveAllReferences");
+
+ HeapHashSet<Member<CounterStyleMap>> visited_maps;
+ visited_maps.insert(GetUACounterStyleMap());
+
+ if (CounterStyleMap* user_map = GetUserCounterStyleMap(document))
+ user_map->ResolveReferences(visited_maps);
+
+ if (CounterStyleMap* document_map = GetAuthorCounterStyleMap(document))
+ document_map->ResolveReferences(visited_maps);
+
+ for (const TreeScope* scope : active_tree_scopes) {
+ if (CounterStyleMap* scoped_map = GetAuthorCounterStyleMap(*scope)) {
+ scoped_map->ResolveReferences(visited_maps);
+
+#if DCHECK_IS_ON()
+ for (CounterStyle* counter_style : scoped_map->counter_styles_.Values()) {
+ DCHECK(!counter_style->IsDirty());
+ DCHECK(!counter_style->HasUnresolvedExtends());
+ DCHECK(!counter_style->HasUnresolvedFallback());
+ }
+#endif
+ }
+ }
+}
+
+void CounterStyleMap::Dispose() {
+ if (!counter_styles_.size())
+ return;
+
+ for (CounterStyle* counter_style : counter_styles_.Values())
+ counter_style->SetIsDirty();
+ counter_styles_.clear();
+
+ if (owner_document_)
+ owner_document_->GetStyleEngine().MarkCounterStylesNeedUpdate();
+}
+
+void CounterStyleMap::Trace(Visitor* visitor) const {
+ visitor->Trace(owner_document_);
+ visitor->Trace(tree_scope_);
+ visitor->Trace(counter_styles_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style_map.h b/chromium/third_party/blink/renderer/core/css/counter_style_map.h
new file mode 100644
index 00000000000..f87ef85775e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style_map.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_MAP_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/counter_style.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
+
+namespace blink {
+
+class Document;
+class TreeScope;
+class CounterStyle;
+class RuleSet;
+
+class CORE_EXPORT CounterStyleMap : public GarbageCollected<CounterStyleMap> {
+ public:
+ static CounterStyleMap* GetUACounterStyleMap();
+ static CounterStyleMap* GetUserCounterStyleMap(Document&);
+ static CounterStyleMap* GetAuthorCounterStyleMap(const TreeScope&);
+
+ static CounterStyleMap* CreateUserCounterStyleMap(Document&);
+ static CounterStyleMap* CreateAuthorCounterStyleMap(TreeScope&);
+
+ CounterStyle* FindCounterStyleAcrossScopes(const AtomicString& name) const;
+
+ void AddCounterStyles(const RuleSet&);
+ void SetIsPredefined();
+
+ void ResolveReferences(HeapHashSet<Member<CounterStyleMap>>& resolved_maps);
+ static void ResolveAllReferences(Document&,
+ const HeapHashSet<Member<TreeScope>>&);
+
+ void MarkDirtyCounterStyles(HeapHashSet<Member<CounterStyle>>& visited);
+ static void MarkAllDirtyCounterStyles(Document&,
+ const HeapHashSet<Member<TreeScope>>&);
+
+ void Dispose();
+
+ CounterStyleMap(Document* document, TreeScope* tree_scope);
+ void Trace(Visitor*) const;
+
+ private:
+ CounterStyleMap* GetAncestorMap() const;
+
+ void ResolveExtendsFor(CounterStyle&);
+ void ResolveFallbackFor(CounterStyle&);
+
+ // Null means these are user-agent rules.
+ Member<Document> owner_document_;
+
+ // Null tree scope and non-null document means these are user rules.
+ Member<TreeScope> tree_scope_;
+
+ HeapHashMap<AtomicString, Member<CounterStyle>> counter_styles_;
+
+ friend class CounterStyleMapTest;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_COUNTER_STYLE_MAP_H_
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style_map_test.cc b/chromium/third_party/blink/renderer/core/css/counter_style_map_test.cc
new file mode 100644
index 00000000000..fce0ed27fe0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style_map_test.cc
@@ -0,0 +1,204 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
+
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class CounterStyleMapTest : public PageTestBase,
+ private ScopedCSSAtRuleCounterStyleForTest {
+ public:
+ CounterStyleMapTest() : ScopedCSSAtRuleCounterStyleForTest(true) {}
+
+ ShadowRoot& AttachShadowTo(const char* host_id) {
+ Element* host = GetElementById(host_id);
+ return host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ }
+
+ const CounterStyle& GetCounterStyle(const TreeScope& scope,
+ const AtomicString& name) {
+ return *CounterStyleMap::GetAuthorCounterStyleMap(scope)
+ ->counter_styles_.at(name);
+ }
+};
+
+TEST_F(CounterStyleMapTest, ExtendsUAStyle) {
+ SetHtmlInnerHTML(R"HTML(
+ <style> @counter-style foo { system: extends disc; } </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("disc", foo.GetExtendedStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, ExtendsAuthorStyle) {
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: 'X'; }
+ @counter-style bar { system: extends foo; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("foo", bar.GetExtendedStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, ExtendsParentScopeStyle) {
+ SetHtmlInnerHTML(R"HTML(
+ <style> @counter-style foo { symbols: 'X'; } </style>
+ <div id=host></div>
+ )HTML");
+ ShadowRoot& shadow = AttachShadowTo("host");
+ shadow.setInnerHTML(
+ "<style>@counter-style bar { system: extends foo; }</style>");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& bar = GetCounterStyle(shadow, "bar");
+ EXPECT_EQ("foo", bar.GetExtendedStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, ExtendsCyclic) {
+ // Cyclic extends resolve to 'decimal'.
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { system: extends bar; }
+ @counter-style bar { system: extends baz; }
+ @counter-style baz { system: extends bar; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("bar", foo.GetExtendedStyle().GetName());
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("decimal", bar.GetExtendedStyle().GetName());
+
+ const CounterStyle& baz = GetCounterStyle(GetDocument(), "baz");
+ EXPECT_EQ("decimal", baz.GetExtendedStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, ExtendsNonexistentStyle) {
+ // Extending non-existent style resolves to 'decimal'.
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { system: extends bar; }
+ @counter-style bar { system: extends baz; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("bar", foo.GetExtendedStyle().GetName());
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("decimal", bar.GetExtendedStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, FallbackToUAStyle) {
+ SetHtmlInnerHTML(R"HTML(
+ <style> @counter-style foo { symbols: 'X'; fallback: disc; } </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("disc", foo.GetFallbackStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, FallbackToAuthorStyle) {
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: 'X'; }
+ @counter-style bar { symbols: 'Y'; fallback: foo; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("foo", bar.GetFallbackStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, FallbackOnExtends) {
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: 'X'; fallback: disc; }
+ @counter-style bar { system: extends foo; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("disc", bar.GetFallbackStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, FallbackCyclic) {
+ // Cyclic fallbacks are allowed. We break cycles when generating counter text.
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: 'X'; fallback: bar; }
+ @counter-style bar { symbols: 'X'; fallback: foo; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("bar", foo.GetFallbackStyle().GetName());
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("foo", bar.GetFallbackStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, FallbackToNonexistentStyle) {
+ // Fallback to non-existent style resolves to 'decimal'.
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: 'X'; fallback: bar; }
+ @counter-style bar { symbols: 'X'; fallback: baz; }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ EXPECT_EQ("bar", foo.GetFallbackStyle().GetName());
+
+ const CounterStyle& bar = GetCounterStyle(GetDocument(), "bar");
+ EXPECT_EQ("decimal", bar.GetFallbackStyle().GetName());
+}
+
+TEST_F(CounterStyleMapTest, UpdateReferencesInChildScope) {
+ SetHtmlInnerHTML(R"HTML(
+ <style> @counter-style foo { symbols: 'X'; } </style>
+ <div id=host></div>
+ )HTML");
+ ShadowRoot& shadow = AttachShadowTo("host");
+ shadow.setInnerHTML(
+ "<style>@counter-style bar { system: extends foo; }</style>");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle(GetDocument(), "foo");
+ const CounterStyle& bar = GetCounterStyle(shadow, "bar");
+ EXPECT_EQ(&foo, &bar.GetExtendedStyle());
+
+ GetDocument().QuerySelector("style")->remove();
+ UpdateAllLifecyclePhasesForTest();
+
+ // After counter style rule changes in the parent scope, the original
+ // CounterStyle for 'bar' in child scopes will be dirtied, and will be
+ // replaced by a new CounterStyle object.
+ EXPECT_TRUE(foo.IsDirty());
+ EXPECT_TRUE(bar.IsDirty());
+
+ const CounterStyle& new_bar = GetCounterStyle(shadow, "bar");
+ EXPECT_NE(&bar, &new_bar);
+ EXPECT_EQ("decimal", new_bar.GetExtendedStyle().GetName());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/counter_style_test.cc b/chromium/third_party/blink/renderer/core/css/counter_style_test.cc
new file mode 100644
index 00000000000..a7606551b2a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/counter_style_test.cc
@@ -0,0 +1,627 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/counter_style.h"
+
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class CounterStyleTest : public PageTestBase,
+ private ScopedCSSAtRuleCounterStyleForTest {
+ public:
+ CounterStyleTest() : ScopedCSSAtRuleCounterStyleForTest(true) {}
+
+ protected:
+ const CounterStyle& GetCounterStyle(const AtomicString& name) {
+ if (const CounterStyleMap* document_map =
+ CounterStyleMap::GetAuthorCounterStyleMap(GetDocument()))
+ return *document_map->FindCounterStyleAcrossScopes(name);
+ return *CounterStyleMap::GetUACounterStyleMap()
+ ->FindCounterStyleAcrossScopes(name);
+ }
+
+ const CounterStyle AddCounterStyle(const AtomicString& name,
+ const String& descriptors) {
+ StringBuilder declaration;
+ declaration.Append("@counter-style ");
+ declaration.Append(name);
+ declaration.Append("{");
+ declaration.Append(descriptors);
+ declaration.Append("}");
+ InsertStyleElement(declaration.ToString().Utf8());
+ UpdateAllLifecyclePhasesForTest();
+ return GetCounterStyle(name);
+ }
+};
+
+TEST_F(CounterStyleTest, NumericAlgorithm) {
+ const CounterStyle& decimal = GetCounterStyle("decimal");
+ EXPECT_EQ("-123", decimal.GenerateRepresentation(-123));
+ EXPECT_EQ("0", decimal.GenerateRepresentation(0));
+ EXPECT_EQ("456", decimal.GenerateRepresentation(456));
+}
+
+TEST_F(CounterStyleTest, AdditiveAlgorithm) {
+ const CounterStyle& upper_roman = GetCounterStyle("upper-roman");
+ EXPECT_EQ("I", upper_roman.GenerateRepresentation(1));
+ EXPECT_EQ("CDXLIV", upper_roman.GenerateRepresentation(444));
+ EXPECT_EQ("MMMCMXCIX", upper_roman.GenerateRepresentation(3999));
+
+ // Can't represent 0. Fallback to 'decimal'.
+ EXPECT_EQ("0", upper_roman.GenerateRepresentation(0));
+}
+
+TEST_F(CounterStyleTest, ExtendsAdditive) {
+ InsertStyleElement("@counter-style foo { system: extends upper-roman; }");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle("foo");
+ EXPECT_EQ("I", foo.GenerateRepresentation(1));
+ EXPECT_EQ("CDXLIV", foo.GenerateRepresentation(444));
+ EXPECT_EQ("MMMCMXCIX", foo.GenerateRepresentation(3999));
+
+ // Can't represent 0. Fallback to 'decimal'.
+ EXPECT_EQ("0", foo.GenerateRepresentation(0));
+}
+
+TEST_F(CounterStyleTest, AdditiveLengthLimit) {
+ InsertStyleElement(
+ "@counter-style foo { system: additive; additive-symbols: 1 I; }");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle("foo");
+ EXPECT_EQ("I", foo.GenerateRepresentation(1));
+ EXPECT_EQ("II", foo.GenerateRepresentation(2));
+ EXPECT_EQ("III", foo.GenerateRepresentation(3));
+
+ // Length limit exceeded. Fallback to 'decimal'.
+ EXPECT_EQ("1000000", foo.GenerateRepresentation(1000000));
+}
+
+TEST_F(CounterStyleTest, AdditiveWithZero) {
+ InsertStyleElement(
+ "@counter-style foo { system: additive; additive-symbols: 1 I, 0 O; }");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle("foo");
+ EXPECT_EQ("O", foo.GenerateRepresentation(0));
+ EXPECT_EQ("I", foo.GenerateRepresentation(1));
+ EXPECT_EQ("II", foo.GenerateRepresentation(2));
+ EXPECT_EQ("III", foo.GenerateRepresentation(3));
+}
+
+TEST_F(CounterStyleTest, AlphabeticAlgorithm) {
+ const CounterStyle& lower_alpha = GetCounterStyle("lower-alpha");
+ EXPECT_EQ("a", lower_alpha.GenerateRepresentation(1));
+ EXPECT_EQ("ab", lower_alpha.GenerateRepresentation(28));
+ EXPECT_EQ("cab", lower_alpha.GenerateRepresentation(26 + 26 * 26 * 3 + 2));
+}
+
+TEST_F(CounterStyleTest, CyclicAlgorithm) {
+ InsertStyleElement("@counter-style foo { system: cyclic; symbols: A B C; }");
+ UpdateAllLifecyclePhasesForTest();
+
+ const CounterStyle& foo = GetCounterStyle("foo");
+ EXPECT_EQ(String("B"), foo.GenerateRepresentation(-100));
+ EXPECT_EQ(String("B"), foo.GenerateRepresentation(-1));
+ EXPECT_EQ(String("C"), foo.GenerateRepresentation(0));
+ EXPECT_EQ(String("A"), foo.GenerateRepresentation(1));
+ EXPECT_EQ(String("B"), foo.GenerateRepresentation(2));
+ EXPECT_EQ(String("C"), foo.GenerateRepresentation(3));
+ EXPECT_EQ(String("A"), foo.GenerateRepresentation(4));
+ EXPECT_EQ(String("A"), foo.GenerateRepresentation(100));
+}
+
+TEST_F(CounterStyleTest, FixedAlgorithm) {
+ const CounterStyle& eb = GetCounterStyle("cjk-earthly-branch");
+ EXPECT_EQ(String(u"\u5B50"), eb.GenerateRepresentation(1));
+ EXPECT_EQ(String(u"\u4EA5"), eb.GenerateRepresentation(12));
+
+ // Fallback to decimal
+ EXPECT_EQ("-1", eb.GenerateRepresentation(-1));
+ EXPECT_EQ("0", eb.GenerateRepresentation(0));
+}
+
+TEST_F(CounterStyleTest, SymbolicAlgorithm) {
+ InsertStyleElement(R"HTML(
+ @counter-style upper-alpha-legal {
+ system: symbolic;
+ symbols: A B C D E F G H I J K L M
+ N O P Q R S T U V W X Y Z;
+ }
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ const CounterStyle& legal = GetCounterStyle("upper-alpha-legal");
+
+ EXPECT_EQ("A", legal.GenerateRepresentation(1));
+ EXPECT_EQ("BB", legal.GenerateRepresentation(28));
+ EXPECT_EQ("CCC", legal.GenerateRepresentation(55));
+
+ // Length limit exceeded. Fallback to 'decimal'.
+ EXPECT_EQ("1000000", legal.GenerateRepresentation(1000000));
+}
+
+TEST_F(CounterStyleTest, CyclicFallback) {
+ InsertStyleElement(R"HTML(
+ @counter-style foo {
+ system: fixed;
+ symbols: A B;
+ fallback: bar;
+ }
+
+ @counter-style bar {
+ system: fixed;
+ symbols: C D E F;
+ fallback: baz;
+ }
+
+ @counter-style baz {
+ system: additive;
+ additive-symbols: 5 V;
+ fallback: foo;
+ }
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+ const CounterStyle& foo = GetCounterStyle("foo");
+ const CounterStyle& bar = GetCounterStyle("bar");
+ const CounterStyle& baz = GetCounterStyle("baz");
+
+ // foo -> bar
+ EXPECT_EQ("E", foo.GenerateRepresentation(3));
+
+ // bar -> baz
+ EXPECT_EQ("V", bar.GenerateRepresentation(5));
+
+ // baz -> foo
+ EXPECT_EQ("A", baz.GenerateRepresentation(1));
+
+ // baz -> foo -> bar
+ EXPECT_EQ("F", baz.GenerateRepresentation(4));
+
+ // foo -> bar -> baz -> foo. Break fallback cycle with 'decimal'.
+ EXPECT_EQ("6", foo.GenerateRepresentation(6));
+}
+
+TEST_F(CounterStyleTest, CustomNegative) {
+ InsertStyleElement(R"CSS(
+ @counter-style financial-decimal {
+ system: extends decimal;
+ negative: '(' ')';
+ }
+
+ @counter-style extended {
+ system: extends financial-decimal;
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Getting custom 'negative' directly from descriptor value.
+ const CounterStyle& financial_decimal = GetCounterStyle("financial-decimal");
+ EXPECT_EQ("(999)", financial_decimal.GenerateRepresentation(-999));
+ EXPECT_EQ("(1)", financial_decimal.GenerateRepresentation(-1));
+ EXPECT_EQ("0", financial_decimal.GenerateRepresentation(0));
+ EXPECT_EQ("1", financial_decimal.GenerateRepresentation(1));
+ EXPECT_EQ("99", financial_decimal.GenerateRepresentation(99));
+
+ // Getting custom 'negative' indirectly by extending a counter style.
+ const CounterStyle& extended = GetCounterStyle("extended");
+ EXPECT_EQ("(999)", extended.GenerateRepresentation(-999));
+ EXPECT_EQ("(1)", extended.GenerateRepresentation(-1));
+ EXPECT_EQ("0", extended.GenerateRepresentation(0));
+ EXPECT_EQ("1", extended.GenerateRepresentation(1));
+ EXPECT_EQ("99", extended.GenerateRepresentation(99));
+}
+
+TEST_F(CounterStyleTest, CustomPad) {
+ InsertStyleElement(R"CSS(
+ @counter-style financial-decimal-pad {
+ system: extends decimal;
+ negative: '(' ')';
+ pad: 4 '0';
+ }
+
+ @counter-style extended {
+ system: extends financial-decimal-pad;
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Getting custom 'pad' directly from descriptor value.
+ const CounterStyle& financial_decimal_pad =
+ GetCounterStyle("financial-decimal-pad");
+ EXPECT_EQ("(0099)", financial_decimal_pad.GenerateRepresentation(-99));
+ EXPECT_EQ("(0001)", financial_decimal_pad.GenerateRepresentation(-1));
+ EXPECT_EQ("0000", financial_decimal_pad.GenerateRepresentation(0));
+ EXPECT_EQ("0001", financial_decimal_pad.GenerateRepresentation(1));
+ EXPECT_EQ("0099", financial_decimal_pad.GenerateRepresentation(99));
+
+ // Getting custom 'pad' indirectly by extending a counter style.
+ const CounterStyle& extended = GetCounterStyle("extended");
+ EXPECT_EQ("(0099)", extended.GenerateRepresentation(-99));
+ EXPECT_EQ("(0001)", extended.GenerateRepresentation(-1));
+ EXPECT_EQ("0000", extended.GenerateRepresentation(0));
+ EXPECT_EQ("0001", extended.GenerateRepresentation(1));
+ EXPECT_EQ("0099", extended.GenerateRepresentation(99));
+}
+
+TEST_F(CounterStyleTest, PadLengthLimit) {
+ InsertStyleElement(R"CSS(
+ @counter-style foo {
+ system: extends decimal;
+ pad: 1000 '0';
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Pad length is too long. Fallback to 'decimal'.
+ const CounterStyle& foo = GetCounterStyle("foo");
+ EXPECT_EQ("0", foo.GenerateRepresentation(0));
+}
+
+TEST_F(CounterStyleTest, SymbolicWithExtendedRange) {
+ InsertStyleElement(R"CSS(
+ @counter-style base {
+ system: symbolic;
+ symbols: A B;
+ }
+
+ @counter-style custom {
+ system: extends base;
+ range: infinite -2, 0 infinite;
+ }
+
+ @counter-style extended {
+ system: extends custom;
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Getting custom 'range' directly from descriptor value.
+ const CounterStyle& custom = GetCounterStyle("custom");
+ EXPECT_EQ("-AA", custom.GenerateRepresentation(-3));
+ EXPECT_EQ("-B", custom.GenerateRepresentation(-2));
+ // -1 is out of 'range' value. Fallback to 'decimal'
+ EXPECT_EQ("-1", custom.GenerateRepresentation(-1));
+ // 0 is within 'range' but not representable. Fallback to 'decimal'.
+ EXPECT_EQ("0", custom.GenerateRepresentation(0));
+ EXPECT_EQ("A", custom.GenerateRepresentation(1));
+
+ // Getting custom 'range' indirectly by extending a counter style.
+ const CounterStyle& extended = GetCounterStyle("extended");
+ EXPECT_EQ("-AA", extended.GenerateRepresentation(-3));
+ EXPECT_EQ("-B", extended.GenerateRepresentation(-2));
+ EXPECT_EQ("-1", extended.GenerateRepresentation(-1));
+ EXPECT_EQ("0", extended.GenerateRepresentation(0));
+ EXPECT_EQ("A", extended.GenerateRepresentation(1));
+}
+
+TEST_F(CounterStyleTest, AdditiveWithExtendedRange) {
+ InsertStyleElement(R"CSS(
+ @counter-style base {
+ system: additive;
+ additive-symbols: 2 B, 1 A;
+ }
+
+ @counter-style custom {
+ system: extends base;
+ range: infinite -2, 0 infinite;
+ }
+
+ @counter-style extended {
+ system: extends custom;
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Getting custom 'range' directly from descriptor value.
+ const CounterStyle& custom = GetCounterStyle("custom");
+ EXPECT_EQ("-BA", custom.GenerateRepresentation(-3));
+ EXPECT_EQ("-B", custom.GenerateRepresentation(-2));
+ // -1 is out of 'range' value. Fallback to 'decimal'.
+ EXPECT_EQ("-1", custom.GenerateRepresentation(-1));
+ // 0 is within 'range' but not representable. Fallback to 'decimal'.
+ EXPECT_EQ("0", custom.GenerateRepresentation(0));
+ EXPECT_EQ("A", custom.GenerateRepresentation(1));
+
+ // Getting custom 'range' indirectly by extending a counter style.
+ const CounterStyle& extended = GetCounterStyle("extended");
+ EXPECT_EQ("-BA", extended.GenerateRepresentation(-3));
+ EXPECT_EQ("-B", extended.GenerateRepresentation(-2));
+ EXPECT_EQ("-1", extended.GenerateRepresentation(-1));
+ EXPECT_EQ("0", extended.GenerateRepresentation(0));
+ EXPECT_EQ("A", extended.GenerateRepresentation(1));
+}
+
+TEST_F(CounterStyleTest, CustomFirstSymbolValue) {
+ InsertStyleElement(R"CSS(
+ @counter-style base {
+ system: fixed 2;
+ symbols: A B C;
+ }
+
+ @counter-style extended {
+ system: extends base;
+ }
+ )CSS");
+ UpdateAllLifecyclePhasesForTest();
+
+ // Getting custom first symbol value directly from descriptor value.
+ const CounterStyle& base = GetCounterStyle("base");
+ EXPECT_EQ("1", base.GenerateRepresentation(1));
+ EXPECT_EQ("A", base.GenerateRepresentation(2));
+ EXPECT_EQ("B", base.GenerateRepresentation(3));
+ EXPECT_EQ("C", base.GenerateRepresentation(4));
+ EXPECT_EQ("5", base.GenerateRepresentation(5));
+
+ // Getting custom first symbol value indirectly using 'extends'.
+ const CounterStyle& extended = GetCounterStyle("extended");
+ EXPECT_EQ("1", extended.GenerateRepresentation(1));
+ EXPECT_EQ("A", extended.GenerateRepresentation(2));
+ EXPECT_EQ("B", extended.GenerateRepresentation(3));
+ EXPECT_EQ("C", extended.GenerateRepresentation(4));
+ EXPECT_EQ("5", extended.GenerateRepresentation(5));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesCyclic) {
+ const CounterStyle& cyclic =
+ AddCounterStyle("cyclic", "system: cyclic; symbols: A B C;");
+ EXPECT_EQ("A",
+ cyclic.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("A",
+ cyclic.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesNumeric) {
+ const CounterStyle& numeric =
+ AddCounterStyle("numeric",
+ "system: numeric; symbols: '0' '1' '2' '3' '4' '5' '6' "
+ "'7' '8' '9' A B C D E F");
+ EXPECT_EQ("-80000000",
+ numeric.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("7FFFFFFF",
+ numeric.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesAlphabetic) {
+ const CounterStyle& alphabetic = AddCounterStyle(
+ "alphabetic",
+ "system: alphabetic; symbols: A B C; range: infinite infinite;");
+ EXPECT_EQ("-ABAABABBBAACCCACACCB",
+ alphabetic.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("ABAABABBBAACCCACACCA",
+ alphabetic.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesAdditive) {
+ const CounterStyle& additive =
+ AddCounterStyle("additive",
+ "system: additive; range: infinite infinite;"
+ "additive-symbols: 2000000000 '2B',"
+ " 100000000 '1CM',"
+ " 40000000 '4DM',"
+ " 7000000 '7M',"
+ " 400000 '4CK',"
+ " 80000 '8DK',"
+ " 3000 '3K',"
+ " 600 '6C',"
+ " 40 '4D',"
+ " 8 '8I',"
+ " 7 '7I';");
+ EXPECT_EQ("-2B1CM4DM7M4CK8DK3K6C4D8I",
+ additive.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("2B1CM4DM7M4CK8DK3K6C4D7I",
+ additive.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesSymbolic) {
+ // No symbolic counter style can possibly represent such large values without
+ // exceeding the length limit. Always fallbacks to 'decimal'.
+ const CounterStyle& symbolic = AddCounterStyle(
+ "symbolic",
+ "system: symbolic; symbols: A B C; range: infinite infinite;");
+ EXPECT_EQ("-2147483648",
+ symbolic.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("2147483647",
+ symbolic.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, ExtremeValuesFixed) {
+ const CounterStyle& fixed =
+ AddCounterStyle("fixed", "system: fixed 2147483646; symbols: A B C D;");
+ // An int subtraction would overflow and return 2 as the result.
+ EXPECT_EQ("-2147483648",
+ fixed.GenerateRepresentation(std::numeric_limits<int>::min()));
+ EXPECT_EQ("B", fixed.GenerateRepresentation(std::numeric_limits<int>::max()));
+}
+
+TEST_F(CounterStyleTest, PrefixAndSuffix) {
+ const CounterStyle& base = AddCounterStyle(
+ "base", "system: symbolic; symbols: A; prefix: X; suffix: Y;");
+ EXPECT_EQ("X", base.GetPrefix());
+ EXPECT_EQ("Y", base.GetSuffix());
+
+ const CounterStyle& extended =
+ AddCounterStyle("extended", "system: extends base");
+ EXPECT_EQ("X", extended.GetPrefix());
+ EXPECT_EQ("Y", extended.GetSuffix());
+}
+
+TEST_F(CounterStyleTest, Hebrew) {
+ // Verifies that our 'hebrew' implementation matches the spec in the
+ // officially specified range 1-10999.
+ // https://drafts.csswg.org/css-counter-styles-3/#hebrew
+ const CounterStyle& hebrew_as_specced =
+ AddCounterStyle("hebrew-as-specced", R"CSS(
+ system: additive;
+ range: 1 10999;
+ additive-symbols: 10000 \5D9\5F3, 9000 \5D8\5F3, 8000 \5D7\5F3, 7000 \5D6\5F3, 6000 \5D5\5F3, 5000 \5D4\5F3, 4000 \5D3\5F3, 3000 \5D2\5F3, 2000 \5D1\5F3, 1000 \5D0\5F3, 400 \5EA, 300 \5E9, 200 \5E8, 100 \5E7, 90 \5E6, 80 \5E4, 70 \5E2, 60 \5E1, 50 \5E0, 40 \5DE, 30 \5DC, 20 \5DB, 19 \5D9\5D8, 18 \5D9\5D7, 17 \5D9\5D6, 16 \5D8\5D6, 15 \5D8\5D5, 10 \5D9, 9 \5D8, 8 \5D7, 7 \5D6, 6 \5D5, 5 \5D4, 4 \5D3, 3 \5D2, 2 \5D1, 1 \5D0;
+ )CSS");
+ const CounterStyle& hebrew_as_implemented = GetCounterStyle("hebrew");
+ for (int value = 1; value <= 10999; ++value) {
+ String expected = hebrew_as_specced.GenerateRepresentation(value);
+ String actual = hebrew_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, LowerArmenian) {
+ // Verifies that our 'lower-armenian' implementation matches the spec in the
+ // officially specified range 1-9999.
+ // https://drafts.csswg.org/css-counter-styles-3/#valdef-counter-style-name-lower-armenian
+ const CounterStyle& lower_armenian_as_specced =
+ AddCounterStyle("lower-armenian-as-specced", R"CSS(
+ system: additive;
+ range: 1 9999;
+ additive-symbols: 9000 "\584", 8000 "\583", 7000 "\582", 6000 "\581", 5000 "\580", 4000 "\57F", 3000 "\57E", 2000 "\57D", 1000 "\57C", 900 "\57B", 800 "\57A", 700 "\579", 600 "\578", 500 "\577", 400 "\576", 300 "\575", 200 "\574", 100 "\573", 90 "\572", 80 "\571", 70 "\570", 60 "\56F", 50 "\56E", 40 "\56D", 30 "\56C", 20 "\56B", 10 "\56A", 9 "\569", 8 "\568", 7 "\567", 6 "\566", 5 "\565", 4 "\564", 3 "\563", 2 "\562", 1 "\561";
+ )CSS");
+ const CounterStyle& lower_armenian_as_implemented =
+ GetCounterStyle("lower-armenian");
+ for (int value = 1; value <= 9999; ++value) {
+ String expected = lower_armenian_as_specced.GenerateRepresentation(value);
+ String actual = lower_armenian_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, UpperArmenian) {
+ // Verifies that our 'upper-armenian' implementation matches the spec in the
+ // officially specified range 1-9999.
+ // https://drafts.csswg.org/css-counter-styles-3/#valdef-counter-style-name-upper-armenian
+ const CounterStyle& upper_armenian_as_specced =
+ AddCounterStyle("upper-armenian-as-specced", R"CSS(
+ system: additive;
+ range: 1 9999;
+ additive-symbols: 9000 \554, 8000 \553, 7000 \552, 6000 \551, 5000 \550, 4000 \54F, 3000 \54E, 2000 \54D, 1000 \54C, 900 \54B, 800 \54A, 700 \549, 600 \548, 500 \547, 400 \546, 300 \545, 200 \544, 100 \543, 90 \542, 80 \541, 70 \540, 60 \53F, 50 \53E, 40 \53D, 30 \53C, 20 \53B, 10 \53A, 9 \539, 8 \538, 7 \537, 6 \536, 5 \535, 4 \534, 3 \533, 2 \532, 1 \531;
+ )CSS");
+ const CounterStyle& upper_armenian_as_implemented =
+ GetCounterStyle("upper-armenian");
+ for (int value = 1; value <= 9999; ++value) {
+ String expected = upper_armenian_as_specced.GenerateRepresentation(value);
+ String actual = upper_armenian_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, KoreanHangulFormal) {
+ // Verifies that our 'korean-hangul-formal' implementation matches the spec in
+ // the officially specified range 1-9999.
+ // https://drafts.csswg.org/css-counter-styles-3/#korean-hangul-formal
+ const CounterStyle& korean_hangul_formal_as_specced =
+ AddCounterStyle("korean-hangul-formal-as-specced", R"CSS(
+ system: additive;
+ range: -9999 9999;
+ additive-symbols: 9000 \AD6C\CC9C, 8000 \D314\CC9C, 7000 \CE60\CC9C, 6000 \C721\CC9C, 5000 \C624\CC9C, 4000 \C0AC\CC9C, 3000 \C0BC\CC9C, 2000 \C774\CC9C, 1000 \C77C\CC9C, 900 \AD6C\BC31, 800 \D314\BC31, 700 \CE60\BC31, 600 \C721\BC31, 500 \C624\BC31, 400 \C0AC\BC31, 300 \C0BC\BC31, 200 \C774\BC31, 100 \C77C\BC31, 90 \AD6C\C2ED, 80 \D314\C2ED, 70 \CE60\C2ED, 60 \C721\C2ED, 50 \C624\C2ED, 40 \C0AC\C2ED, 30 \C0BC\C2ED, 20 \C774\C2ED, 10 \C77C\C2ED, 9 \AD6C, 8 \D314, 7 \CE60, 6 \C721, 5 \C624, 4 \C0AC, 3 \C0BC, 2 \C774, 1 \C77C, 0 \C601;
+ negative: "\B9C8\C774\B108\C2A4 ";
+ )CSS");
+ const CounterStyle& korean_hangul_formal_as_implemented =
+ GetCounterStyle("korean-hangul-formal");
+ for (int value = -9999; value <= 9999; ++value) {
+ String expected =
+ korean_hangul_formal_as_specced.GenerateRepresentation(value);
+ String actual =
+ korean_hangul_formal_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, KoreanHanjaFormal) {
+ // Verifies that our 'korean-hanja-formal' implementation matches the spec in
+ // the officially specified range 1-9999.
+ // https://drafts.csswg.org/css-counter-styles-3/#korean-hanja-formal
+ const CounterStyle& korean_hanja_formal_as_specced =
+ AddCounterStyle("korean-hanja-formal-as-specced", R"CSS(
+ system: additive;
+ range: -9999 9999;
+ additive-symbols: 9000 \4E5D\4EDF, 8000 \516B\4EDF, 7000 \4E03\4EDF, 6000 \516D\4EDF, 5000 \4E94\4EDF, 4000 \56DB\4EDF, 3000 \53C3\4EDF, 2000 \8CB3\4EDF, 1000 \58F9\4EDF, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \53C3\767E, 200 \8CB3\767E, 100 \58F9\767E, 90 \4E5D\62FE, 80 \516B\62FE, 70 \4E03\62FE, 60 \516D\62FE, 50 \4E94\62FE, 40 \56DB\62FE, 30 \53C3\62FE, 20 \8CB3\62FE, 10 \58F9\62FE, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \53C3, 2 \8CB3, 1 \58F9, 0 \96F6;
+ negative: "\B9C8\C774\B108\C2A4 ";
+ )CSS");
+ const CounterStyle& korean_hanja_formal_as_implemented =
+ GetCounterStyle("korean-hanja-formal");
+ for (int value = -9999; value <= 9999; ++value) {
+ String expected =
+ korean_hanja_formal_as_specced.GenerateRepresentation(value);
+ String actual =
+ korean_hanja_formal_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, KoreanHanjaInformal) {
+ // Verifies that our 'korean-hanja-informal' implementation matches the spec
+ // in the officially specified range 1-9999.
+ // https://drafts.csswg.org/css-counter-styles-3/#korean-hanja-informal
+ const CounterStyle& korean_hanja_informal_as_specced =
+ AddCounterStyle("korean-hanja-informal-as-specced", R"CSS(
+ system: additive;
+ range: -9999 9999;
+ additive-symbols: 9000 \4E5D\5343, 8000 \516B\5343, 7000 \4E03\5343, 6000 \516D\5343, 5000 \4E94\5343, 4000 \56DB\5343, 3000 \4E09\5343, 2000 \4E8C\5343, 1000 \5343, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \4E09\767E, 200 \4E8C\767E, 100 \767E, 90 \4E5D\5341, 80 \516B\5341, 70 \4E03\5341, 60 \516D\5341, 50 \4E94\5341, 40 \56DB\5341, 30 \4E09\5341, 20 \4E8C\5341, 10 \5341, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \4E09, 2 \4E8C, 1 \4E00, 0 \96F6;
+ negative: "\B9C8\C774\B108\C2A4 ";
+ )CSS");
+ const CounterStyle& korean_hanja_informal_as_implemented =
+ GetCounterStyle("korean-hanja-informal");
+ for (int value = -9999; value <= 9999; ++value) {
+ String expected =
+ korean_hanja_informal_as_specced.GenerateRepresentation(value);
+ String actual =
+ korean_hanja_informal_as_implemented.GenerateRepresentation(value);
+ EXPECT_EQ(expected, actual);
+ }
+}
+
+TEST_F(CounterStyleTest, EthiopicNumeric) {
+ const CounterStyle& style = GetCounterStyle("ethiopic-numeric");
+ EXPECT_EQ(String(u"\u1369"), style.GenerateRepresentation(1));
+ EXPECT_EQ(String(u"\u136A"), style.GenerateRepresentation(2));
+ EXPECT_EQ(String(u"\u136B"), style.GenerateRepresentation(3));
+ EXPECT_EQ(String(u"\u136C"), style.GenerateRepresentation(4));
+ EXPECT_EQ(String(u"\u136D"), style.GenerateRepresentation(5));
+ EXPECT_EQ(String(u"\u136E"), style.GenerateRepresentation(6));
+ EXPECT_EQ(String(u"\u136F"), style.GenerateRepresentation(7));
+ EXPECT_EQ(String(u"\u1370"), style.GenerateRepresentation(8));
+ EXPECT_EQ(String(u"\u1371"), style.GenerateRepresentation(9));
+ EXPECT_EQ(String(u"\u1372"), style.GenerateRepresentation(10));
+ EXPECT_EQ(String(u"\u1372\u1369"), style.GenerateRepresentation(11));
+ EXPECT_EQ(String(u"\u1372\u136A"), style.GenerateRepresentation(12));
+ EXPECT_EQ(String(u"\u1375\u136B"), style.GenerateRepresentation(43));
+ EXPECT_EQ(String(u"\u1378\u136F"), style.GenerateRepresentation(77));
+ EXPECT_EQ(String(u"\u1379"), style.GenerateRepresentation(80));
+ EXPECT_EQ(String(u"\u137A\u1371"), style.GenerateRepresentation(99));
+ EXPECT_EQ(String(u"\u137B"), style.GenerateRepresentation(100));
+ EXPECT_EQ(String(u"\u137B\u1369"), style.GenerateRepresentation(101));
+ EXPECT_EQ(String(u"\u136A\u137B\u1373\u136A"),
+ style.GenerateRepresentation(222));
+ EXPECT_EQ(String(u"\u136D\u137B\u1375"), style.GenerateRepresentation(540));
+ EXPECT_EQ(String(u"\u1371\u137B\u137A\u1371"),
+ style.GenerateRepresentation(999));
+ EXPECT_EQ(String(u"\u1372\u137B"), style.GenerateRepresentation(1000));
+ EXPECT_EQ(String(u"\u1372\u137B\u136D"), style.GenerateRepresentation(1005));
+ EXPECT_EQ(String(u"\u1372\u137B\u1377"), style.GenerateRepresentation(1060));
+ EXPECT_EQ(String(u"\u1372\u137B\u1377\u136D"),
+ style.GenerateRepresentation(1065));
+ EXPECT_EQ(String(u"\u1372\u1370\u137B"), style.GenerateRepresentation(1800));
+ EXPECT_EQ(String(u"\u1372\u1370\u137B\u1377"),
+ style.GenerateRepresentation(1860));
+ EXPECT_EQ(String(u"\u1372\u1370\u137B\u1377\u136D"),
+ style.GenerateRepresentation(1865));
+ EXPECT_EQ(String(u"\u1376\u1370\u137B\u1377\u136D"),
+ style.GenerateRepresentation(5865));
+ EXPECT_EQ(String(u"\u1378\u137B\u136D"), style.GenerateRepresentation(7005));
+ EXPECT_EQ(String(u"\u1378\u1370\u137B"), style.GenerateRepresentation(7800));
+ EXPECT_EQ(String(u"\u1378\u1370\u137B\u1377\u136C"),
+ style.GenerateRepresentation(7864));
+ EXPECT_EQ(String(u"\u137A\u1371\u137B\u137A\u1371"),
+ style.GenerateRepresentation(9999));
+ EXPECT_EQ(String(u"\u137C"), style.GenerateRepresentation(10000));
+ EXPECT_EQ(String(u"\u1378\u1370\u137B\u1369\u137C\u137A\u136A"),
+ style.GenerateRepresentation(78010092));
+ EXPECT_EQ(String(u"\u137B\u137C\u1369"),
+ style.GenerateRepresentation(1000001));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc b/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
index a76ffa78c50..f2dfadd8e85 100644
--- a/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_computed_style_declaration.cc
@@ -38,6 +38,8 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css/zoom_adjusted_pixel_value.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
@@ -46,6 +48,7 @@
#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/wtf/text/string_builder.h"
namespace blink {
@@ -78,6 +81,7 @@ const CSSPropertyID kComputedPropertyArray[] = {
CSSPropertyID::kBorderBottomLeftRadius,
CSSPropertyID::kBorderBottomRightRadius, CSSPropertyID::kBorderBottomStyle,
CSSPropertyID::kBorderBottomWidth, CSSPropertyID::kBorderCollapse,
+ CSSPropertyID::kBorderEndEndRadius, CSSPropertyID::kBorderEndStartRadius,
CSSPropertyID::kBorderImageOutset, CSSPropertyID::kBorderImageRepeat,
CSSPropertyID::kBorderImageSlice, CSSPropertyID::kBorderImageSource,
CSSPropertyID::kBorderImageWidth, CSSPropertyID::kBorderInlineEndColor,
@@ -87,7 +91,8 @@ const CSSPropertyID kComputedPropertyArray[] = {
CSSPropertyID::kBorderInlineStartWidth, CSSPropertyID::kBorderLeftColor,
CSSPropertyID::kBorderLeftStyle, CSSPropertyID::kBorderLeftWidth,
CSSPropertyID::kBorderRightColor, CSSPropertyID::kBorderRightStyle,
- CSSPropertyID::kBorderRightWidth, CSSPropertyID::kBorderTopColor,
+ CSSPropertyID::kBorderRightWidth, CSSPropertyID::kBorderStartEndRadius,
+ CSSPropertyID::kBorderStartStartRadius, CSSPropertyID::kBorderTopColor,
CSSPropertyID::kBorderTopLeftRadius, CSSPropertyID::kBorderTopRightRadius,
CSSPropertyID::kBorderTopStyle, CSSPropertyID::kBorderTopWidth,
CSSPropertyID::kBottom, CSSPropertyID::kBoxShadow,
@@ -251,6 +256,21 @@ void LogUnimplementedPropertyID(const CSSProperty& property) {
<< property.GetPropertyName() << "'.";
}
+// TODO(crbug.com/1167696): We probably want to avoid doing this for
+// performance reasons.
+bool InclusiveAncestorMayDependOnContainerQueries(Node* node) {
+ if (!RuntimeEnabledFeatures::CSSContainerQueriesEnabled())
+ return false;
+ for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(*node)) {
+ const ComputedStyle* style = ancestor.GetComputedStyle();
+ // Since DependsOnContainerQueries is stored on ComputedStyle, we have to
+ // behave as if the flag is set for nullptr-styles (display:none).
+ if (!style || style->DependsOnContainerQueries())
+ return true;
+ }
+ return false;
+}
+
} // namespace
const Vector<const CSSProperty*>&
@@ -278,20 +298,8 @@ CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(
CSSComputedStyleDeclaration::~CSSComputedStyleDeclaration() = default;
String CSSComputedStyleDeclaration::cssText() const {
- StringBuilder result;
- static const Vector<const CSSProperty*>& properties =
- ComputableProperties(GetExecutionContext());
-
- for (unsigned i = 0; i < properties.size(); i++) {
- if (i)
- result.Append(' ');
- result.Append(properties[i]->GetPropertyName());
- result.Append(": ");
- result.Append(GetPropertyValue(properties[i]->PropertyID()));
- result.Append(';');
- }
-
- return result.ToString();
+ // CSSStyleDeclaration.cssText should return empty string for computed style.
+ return String();
}
void CSSComputedStyleDeclaration::setCSSText(const ExecutionContext*,
@@ -438,7 +446,8 @@ const CSSValue* CSSComputedStyleDeclaration::GetPropertyCSSValue(
LayoutObject* layout_object = StyledLayoutObject();
const ComputedStyle* style = ComputeComputedStyle();
- if (property_class.IsLayoutDependent(style, layout_object)) {
+ if (property_class.IsLayoutDependent(style, layout_object) ||
+ InclusiveAncestorMayDependOnContainerQueries(styled_node)) {
document.UpdateStyleAndLayoutForNode(styled_node,
DocumentUpdateReason::kJavaScript);
styled_node = StyledNode();
@@ -535,8 +544,8 @@ CSSRule* CSSComputedStyleDeclaration::parentRule() const {
String CSSComputedStyleDeclaration::getPropertyValue(
const String& property_name) {
CSSPropertyID property_id =
- cssPropertyID(GetExecutionContext(), property_name);
- if (!isValidCSSPropertyID(property_id))
+ CssPropertyID(GetExecutionContext(), property_name);
+ if (!IsValidCSSPropertyID(property_id))
return String();
if (property_id == CSSPropertyID::kVariable) {
const CSSValue* value = GetPropertyCSSValue(AtomicString(property_name));
@@ -596,7 +605,7 @@ const CSSValue* CSSComputedStyleDeclaration::GetPropertyCSSValueInternal(
const CSSValue* CSSComputedStyleDeclaration::GetPropertyCSSValueInternal(
AtomicString custom_property_name) {
DCHECK_EQ(CSSPropertyID::kVariable,
- cssPropertyID(GetExecutionContext(), custom_property_name));
+ CssPropertyID(GetExecutionContext(), custom_property_name));
return GetPropertyCSSValue(custom_property_name);
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_container_rule.cc b/chromium/third_party/blink/renderer/core/css/css_container_rule.cc
new file mode 100644
index 00000000000..1dd370f41dc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_container_rule.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/css_container_rule.h"
+
+#include "third_party/blink/renderer/core/css/style_rule.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+CSSContainerRule::CSSContainerRule(StyleRuleContainer* container_rule,
+ CSSStyleSheet* parent)
+ : CSSConditionRule(container_rule, parent) {}
+
+CSSContainerRule::~CSSContainerRule() = default;
+
+String CSSContainerRule::cssText() const {
+ // TODO(crbug.com/1145970): Spec and implement serialization.
+ NOTIMPLEMENTED();
+ return "";
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_container_rule.h b/chromium/third_party/blink/renderer/core/css/css_container_rule.h
new file mode 100644
index 00000000000..dba352576e7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_container_rule.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_CONTAINER_RULE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_CONTAINER_RULE_H_
+
+#include "third_party/blink/renderer/core/css/css_condition_rule.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+
+namespace blink {
+
+class StyleRuleContainer;
+
+class CSSContainerRule final : public CSSConditionRule {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ CSSContainerRule(StyleRuleContainer*, CSSStyleSheet*);
+ ~CSSContainerRule() override;
+
+ String cssText() const override;
+
+ private:
+ CSSRule::Type GetType() const override { return kContainerRule; }
+};
+
+template <>
+struct DowncastTraits<CSSContainerRule> {
+ static bool AllowFrom(const CSSRule& rule) {
+ return rule.GetType() == CSSRule::kContainerRule;
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_CONTAINER_RULE_H_
diff --git a/chromium/third_party/blink/renderer/core/css/css_container_rule.idl b/chromium/third_party/blink/renderer/core/css/css_container_rule.idl
new file mode 100644
index 00000000000..709dbcf83ce
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_container_rule.idl
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ Exposed=Window,
+ RuntimeEnabled=CSSContainerQueries
+] interface CSSContainerRule : CSSConditionRule {
+ // TODO(crbug.com/1145970): Spec and implement.
+};
diff --git a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.cc b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.cc
index e6155be6da3..c6c4a622a2e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.cc
@@ -3,7 +3,15 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/css_counter_style_rule.h"
-#include "third_party/blink/renderer/core/css/style_rule.h"
+#include "third_party/blink/renderer/core/css/css_style_sheet.h"
+#include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
+#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -15,7 +23,84 @@ CSSCounterStyleRule::CSSCounterStyleRule(
CSSCounterStyleRule::~CSSCounterStyleRule() = default;
String CSSCounterStyleRule::cssText() const {
- return String();
+ StringBuilder result;
+ result.Append("@counter-style ");
+ result.Append(name());
+ result.Append(" {");
+
+ // Note: The exact serialization isn't well specified.
+ String system_text = system();
+ if (system_text.length()) {
+ result.Append(" system: ");
+ result.Append(system_text);
+ result.Append(";");
+ }
+
+ String symbols_text = symbols();
+ if (symbols_text.length()) {
+ result.Append(" symbols: ");
+ result.Append(symbols_text);
+ result.Append(";");
+ }
+
+ String additive_symbols_text = additiveSymbols();
+ if (additive_symbols_text.length()) {
+ result.Append(" additive-symbols: ");
+ result.Append(additive_symbols_text);
+ result.Append(";");
+ }
+
+ String negative_text = negative();
+ if (negative_text.length()) {
+ result.Append(" negative: ");
+ result.Append(negative_text);
+ result.Append(";");
+ }
+
+ String prefix_text = prefix();
+ if (prefix_text.length()) {
+ result.Append(" prefix: ");
+ result.Append(prefix_text);
+ result.Append(";");
+ }
+
+ String suffix_text = suffix();
+ if (suffix_text.length()) {
+ result.Append(" suffix: ");
+ result.Append(suffix_text);
+ result.Append(";");
+ }
+
+ String pad_text = pad();
+ if (pad_text.length()) {
+ result.Append(" pad: ");
+ result.Append(pad_text);
+ result.Append(";");
+ }
+
+ String range_text = range();
+ if (range_text.length()) {
+ result.Append(" range: ");
+ result.Append(range_text);
+ result.Append(";");
+ }
+
+ String fallback_text = fallback();
+ if (fallback_text.length()) {
+ result.Append(" fallback: ");
+ result.Append(fallback_text);
+ result.Append(";");
+ }
+
+ String speak_as_text = speakAs();
+ if (speak_as_text.length()) {
+ result.Append(" speak-as: ");
+ result.Append(speak_as_text);
+ result.Append(";");
+ }
+
+ result.Append(" }");
+ return result.ToString();
}
void CSSCounterStyleRule::Reattach(StyleRuleBase* rule) {
@@ -87,48 +172,103 @@ String CSSCounterStyleRule::fallback() const {
return String();
}
-void CSSCounterStyleRule::setName(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::SetterInternal(
+ const ExecutionContext* execution_context,
+ AtRuleDescriptorID descriptor_id,
+ const String& text) {
+ CSSStyleSheet* style_sheet = parentStyleSheet();
+ auto& context = *MakeGarbageCollected<CSSParserContext>(
+ ParserContext(execution_context->GetSecureContextMode()), style_sheet);
+ CSSTokenizer tokenizer(text);
+ auto tokens = tokenizer.TokenizeToEOF();
+ CSSParserTokenRange token_range(tokens);
+ CSSValue* new_value = AtRuleDescriptorParser::ParseAtCounterStyleDescriptor(
+ descriptor_id, token_range, context);
+ if (!new_value ||
+ !counter_style_rule_->NewValueInvalidOrEqual(descriptor_id, new_value))
+ return;
+
+ // TODO(xiaochengh): RuleMutationScope causes all rules of the tree scope to
+ // be re-collected and the entire CounterStyleMap rebuilt, while we only need
+ // to dirty one CounterStyle. Try to improve.
+ CSSStyleSheet::RuleMutationScope rule_mutation_scope(this);
+
+ counter_style_rule_->SetDescriptorValue(descriptor_id, new_value);
+ if (Document* document = style_sheet->OwnerDocument())
+ document->GetStyleEngine().MarkCounterStylesNeedUpdate();
+}
+
+void CSSCounterStyleRule::setName(const ExecutionContext* execution_context,
+ const String& text) {
+ CSSStyleSheet* style_sheet = parentStyleSheet();
+ auto& context = *MakeGarbageCollected<CSSParserContext>(
+ ParserContext(execution_context->GetSecureContextMode()), style_sheet);
+ CSSTokenizer tokenizer(text);
+ auto tokens = tokenizer.TokenizeToEOF();
+ CSSParserTokenRange token_range(tokens);
+ AtomicString name =
+ css_parsing_utils::ConsumeCounterStyleNameInPrelude(token_range, context);
+ if (!name || name == counter_style_rule_->GetName())
+ return;
+
+ // Changing name may affect cascade result, which requires re-collecting all
+ // the rules and re-constructing the CounterStyleMap to handle.
+ CSSStyleSheet::RuleMutationScope rule_mutation_scope(this);
+
+ counter_style_rule_->SetName(name);
+ if (Document* document = style_sheet->OwnerDocument())
+ document->GetStyleEngine().MarkCounterStylesNeedUpdate();
}
-void CSSCounterStyleRule::setSystem(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setSystem(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::System, text);
}
-void CSSCounterStyleRule::setSymbols(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setSymbols(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Symbols, text);
}
-void CSSCounterStyleRule::setAdditiveSymbols(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setAdditiveSymbols(
+ const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::AdditiveSymbols, text);
}
-void CSSCounterStyleRule::setNegative(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setNegative(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Negative, text);
}
-void CSSCounterStyleRule::setPrefix(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setPrefix(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Prefix, text);
}
-void CSSCounterStyleRule::setSuffix(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setSuffix(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Suffix, text);
}
-void CSSCounterStyleRule::setRange(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setRange(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Range, text);
}
-void CSSCounterStyleRule::setPad(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setPad(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Pad, text);
}
-void CSSCounterStyleRule::setSpeakAs(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setSpeakAs(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::SpeakAs, text);
}
-void CSSCounterStyleRule::setFallback(const String&) {
- // TODO(crbug.com/687225): Implement
+void CSSCounterStyleRule::setFallback(const ExecutionContext* execution_context,
+ const String& text) {
+ SetterInternal(execution_context, AtRuleDescriptorID::Fallback, text);
}
void CSSCounterStyleRule::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.h b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.h
index 7581cb9ccde..6e8620d9d28 100644
--- a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.h
@@ -6,10 +6,12 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_COUNTER_STYLE_RULE_H_
#include "third_party/blink/renderer/core/css/css_rule.h"
+#include "third_party/blink/renderer/core/css/parser/at_rule_descriptors.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
+class ExecutionContext;
class StyleRuleCounterStyle;
class CSSCounterStyleRule final : public CSSRule {
@@ -34,23 +36,27 @@ class CSSCounterStyleRule final : public CSSRule {
String speakAs() const;
String fallback() const;
- void setName(const String&);
- void setSystem(const String&);
- void setSymbols(const String&);
- void setAdditiveSymbols(const String&);
- void setNegative(const String&);
- void setPrefix(const String&);
- void setSuffix(const String&);
- void setRange(const String&);
- void setPad(const String&);
- void setSpeakAs(const String&);
- void setFallback(const String&);
+ void setName(const ExecutionContext*, const String&);
+ void setSystem(const ExecutionContext*, const String&);
+ void setSymbols(const ExecutionContext*, const String&);
+ void setAdditiveSymbols(const ExecutionContext*, const String&);
+ void setNegative(const ExecutionContext*, const String&);
+ void setPrefix(const ExecutionContext*, const String&);
+ void setSuffix(const ExecutionContext*, const String&);
+ void setRange(const ExecutionContext*, const String&);
+ void setPad(const ExecutionContext*, const String&);
+ void setSpeakAs(const ExecutionContext*, const String&);
+ void setFallback(const ExecutionContext*, const String&);
void Trace(Visitor*) const override;
private:
CSSRule::Type GetType() const override { return kCounterStyleRule; }
+ void SetterInternal(const ExecutionContext*,
+ AtRuleDescriptorID,
+ const String&);
+
Member<StyleRuleCounterStyle> counter_style_rule_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.idl b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.idl
index 4b1f8ef776a..88fcfc1fcbe 100644
--- a/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.idl
+++ b/chromium/third_party/blink/renderer/core/css/css_counter_style_rule.idl
@@ -5,15 +5,15 @@
// https://drafts.csswg.org/css-counter-styles-3/#the-csscounterstylerule-interface
[Exposed=Window, RuntimeEnabled=CSSAtRuleCounterStyle]
interface CSSCounterStyleRule : CSSRule {
- attribute CSSOMString name;
- attribute CSSOMString system;
- attribute CSSOMString symbols;
- attribute CSSOMString additiveSymbols;
- attribute CSSOMString negative;
- attribute CSSOMString prefix;
- attribute CSSOMString suffix;
- attribute CSSOMString range;
- attribute CSSOMString pad;
- attribute CSSOMString speakAs;
- attribute CSSOMString fallback;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString name;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString system;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString symbols;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString additiveSymbols;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString negative;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString prefix;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString suffix;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString range;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString pad;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString speakAs;
+ [SetterCallWith=ExecutionContext] attribute CSSOMString fallback;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_counter_value.cc b/chromium/third_party/blink/renderer/core/css/css_counter_value.cc
index 34f1f796232..40de5d47af3 100644
--- a/chromium/third_party/blink/renderer/core/css/css_counter_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_counter_value.cc
@@ -23,7 +23,7 @@ String CSSCounterValue::CustomCSSText() const {
result.Append(", ");
result.Append(separator_->CssText());
}
- bool is_default_list_style = ListStyle() == CSSValueID::kDecimal;
+ bool is_default_list_style = ListStyle() == "decimal";
if (!is_default_list_style) {
result.Append(", ");
result.Append(list_style_->CssText());
diff --git a/chromium/third_party/blink/renderer/core/css/css_counter_value.h b/chromium/third_party/blink/renderer/core/css/css_counter_value.h
index 004b56844de..36458e232e6 100644
--- a/chromium/third_party/blink/renderer/core/css/css_counter_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_counter_value.h
@@ -34,7 +34,7 @@ namespace cssvalue {
class CSSCounterValue : public CSSValue {
public:
CSSCounterValue(CSSCustomIdentValue* identifier,
- CSSIdentifierValue* list_style,
+ CSSCustomIdentValue* list_style,
CSSStringValue* separator)
: CSSValue(kCounterClass),
identifier_(identifier),
@@ -42,7 +42,7 @@ class CSSCounterValue : public CSSValue {
separator_(separator) {}
String Identifier() const { return identifier_->Value(); }
- CSSValueID ListStyle() const { return list_style_->GetValueID(); }
+ AtomicString ListStyle() const { return list_style_->Value(); }
String Separator() const { return separator_->Value(); }
bool Equals(const CSSCounterValue& other) const {
@@ -56,7 +56,7 @@ class CSSCounterValue : public CSSValue {
private:
Member<CSSCustomIdentValue> identifier_; // string
- Member<CSSIdentifierValue> list_style_; // ident
+ Member<CSSCustomIdentValue> list_style_; // ident
Member<CSSStringValue> separator_; // string
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
index 285d47e683c..47ee7c070c1 100644
--- a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.cc
@@ -89,14 +89,16 @@ static StyleSheetContents* ParseUASheet(const String& str) {
CSSDefaultStyleSheets::CSSDefaultStyleSheets()
: media_controls_style_sheet_loader_(nullptr) {
- // Strict-mode rules.
- String forced_colors_style_sheet =
- RuntimeEnabledFeatures::ForcedColorsEnabled()
- ? UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_FORCED_COLORS_CSS)
+ // Predefined @counter-style rules
+ String predefined_counter_styles_sheet =
+ RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()
+ ? UncompressResourceAsASCIIString(
+ IDR_UASTYLE_PREDEFINED_COUNTER_STYLES_CSS)
: String();
+ // Strict-mode rules.
String default_rules = UncompressResourceAsASCIIString(IDR_UASTYLE_HTML_CSS) +
LayoutTheme::GetTheme().ExtraDefaultStyleSheet() +
- forced_colors_style_sheet;
+ predefined_counter_styles_sheet;
default_style_sheet_ = ParseUASheet(default_rules);
@@ -114,13 +116,11 @@ CSSDefaultStyleSheets::CSSDefaultStyleSheets()
default_svg_style_->CompactRulesIfNeeded();
default_quirks_style_->CompactRulesIfNeeded();
default_print_style_->CompactRulesIfNeeded();
- default_forced_color_style_->CompactRulesIfNeeded();
DCHECK(default_style_->UniversalRules()->IsEmpty());
DCHECK(default_mathml_style_->UniversalRules()->IsEmpty());
DCHECK(default_svg_style_->UniversalRules()->IsEmpty());
DCHECK(default_quirks_style_->UniversalRules()->IsEmpty());
DCHECK(default_print_style_->UniversalRules()->IsEmpty());
- DCHECK(default_forced_color_style_->UniversalRules()->IsEmpty());
#endif
}
@@ -133,6 +133,7 @@ void CSSDefaultStyleSheets::PrepareForLeakDetection() {
mathml_style_sheet_.Clear();
media_controls_style_sheet_.Clear();
text_track_style_sheet_.Clear();
+ forced_colors_style_sheet_.Clear();
fullscreen_style_sheet_.Clear();
webxr_overlay_style_sheet_.Clear();
marker_style_sheet_.Clear();
@@ -153,14 +154,13 @@ void CSSDefaultStyleSheets::InitializeDefaultStyles() {
default_svg_style_ = MakeGarbageCollected<RuleSet>();
default_quirks_style_ = MakeGarbageCollected<RuleSet>();
default_print_style_ = MakeGarbageCollected<RuleSet>();
- default_forced_color_style_ = MakeGarbageCollected<RuleSet>();
+ default_media_controls_style_ = MakeGarbageCollected<RuleSet>();
+ default_forced_color_style_.Clear();
default_pseudo_element_style_.Clear();
default_style_->AddRulesFromSheet(DefaultStyleSheet(), ScreenEval());
default_quirks_style_->AddRulesFromSheet(QuirksStyleSheet(), ScreenEval());
default_print_style_->AddRulesFromSheet(DefaultStyleSheet(), PrintEval());
- default_forced_color_style_->AddRulesFromSheet(DefaultStyleSheet(),
- ForcedColorsEval());
}
RuleSet* CSSDefaultStyleSheets::DefaultViewSourceStyle() {
@@ -218,8 +218,10 @@ bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForElement(
ParseUASheet(UncompressResourceAsASCIIString(IDR_UASTYLE_SVG_CSS));
default_svg_style_->AddRulesFromSheet(SvgStyleSheet(), ScreenEval());
default_print_style_->AddRulesFromSheet(SvgStyleSheet(), PrintEval());
- default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(),
- ForcedColorsEval());
+ if (default_forced_color_style_) {
+ default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(),
+ ForcedColorsEval());
+ }
changed_default_style = true;
}
@@ -241,11 +243,14 @@ bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForElement(
// and <audio>.
media_controls_style_sheet_ =
ParseUASheet(media_controls_style_sheet_loader_->GetUAStyleSheet());
- default_style_->AddRulesFromSheet(MediaControlsStyleSheet(), ScreenEval());
+ default_media_controls_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
+ ScreenEval());
default_print_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
PrintEval());
- default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
- ForcedColorsEval());
+ if (default_forced_color_style_) {
+ default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
+ ForcedColorsEval());
+ }
changed_default_style = true;
}
@@ -277,7 +282,8 @@ bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForElement(
settings->GetTextTrackTextSize());
builder.Append(" } ");
text_track_style_sheet_ = ParseUASheet(builder.ToString());
- default_style_->AddRulesFromSheet(text_track_style_sheet_, ScreenEval());
+ default_media_controls_style_->AddRulesFromSheet(text_track_style_sheet_,
+ ScreenEval());
default_print_style_->AddRulesFromSheet(text_track_style_sheet_,
PrintEval());
changed_default_style = true;
@@ -321,8 +327,10 @@ bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetForXrOverlay() {
default_style_->AddRulesFromSheet(webxr_overlay_style_sheet_, ScreenEval());
default_print_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
PrintEval());
- default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
- ForcedColorsEval());
+ if (default_forced_color_style_) {
+ default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
+ ForcedColorsEval());
+ }
return true;
}
@@ -339,6 +347,50 @@ void CSSDefaultStyleSheets::EnsureDefaultStyleSheetForFullscreen() {
ScreenEval());
}
+bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetForForcedColors() {
+ if (forced_colors_style_sheet_)
+ return false;
+
+ String forced_colors_rules =
+ RuntimeEnabledFeatures::ForcedColorsEnabled()
+ ? UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_FORCED_COLORS_CSS)
+ : String();
+ forced_colors_style_sheet_ = ParseUASheet(forced_colors_rules);
+
+ if (!default_forced_color_style_)
+ default_forced_color_style_ = MakeGarbageCollected<RuleSet>();
+ default_forced_color_style_->AddRulesFromSheet(DefaultStyleSheet(),
+ ForcedColorsEval());
+ default_forced_color_style_->AddRulesFromSheet(ForcedColorsStyleSheet(),
+ ForcedColorsEval());
+ if (svg_style_sheet_) {
+ default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(),
+ ForcedColorsEval());
+ }
+ if (media_controls_style_sheet_) {
+ default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
+ ForcedColorsEval());
+ }
+ if (webxr_overlay_style_sheet_) {
+ default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
+ ForcedColorsEval());
+ }
+
+ return true;
+}
+
+void CSSDefaultStyleSheets::CollectFeaturesTo(const Document& document,
+ RuleFeatureSet& features) {
+ if (DefaultStyle())
+ features.Add(DefaultStyle()->Features());
+ if (DefaultMediaControlsStyle())
+ features.Add(DefaultMediaControlsStyle()->Features());
+ if (DefaultMathMLStyle())
+ features.Add(DefaultMathMLStyle()->Features());
+ if (document.IsViewSource() && DefaultViewSourceStyle())
+ features.Add(DefaultViewSourceStyle()->Features());
+}
+
void CSSDefaultStyleSheets::Trace(Visitor* visitor) const {
visitor->Trace(default_style_);
visitor->Trace(default_mathml_style_);
@@ -347,6 +399,7 @@ void CSSDefaultStyleSheets::Trace(Visitor* visitor) const {
visitor->Trace(default_print_style_);
visitor->Trace(default_view_source_style_);
visitor->Trace(default_forced_color_style_);
+ visitor->Trace(default_media_controls_style_);
visitor->Trace(default_style_sheet_);
visitor->Trace(default_pseudo_element_style_);
visitor->Trace(mobile_viewport_style_sheet_);
@@ -357,6 +410,7 @@ void CSSDefaultStyleSheets::Trace(Visitor* visitor) const {
visitor->Trace(mathml_style_sheet_);
visitor->Trace(media_controls_style_sheet_);
visitor->Trace(text_track_style_sheet_);
+ visitor->Trace(forced_colors_style_sheet_);
visitor->Trace(fullscreen_style_sheet_);
visitor->Trace(webxr_overlay_style_sheet_);
visitor->Trace(marker_style_sheet_);
diff --git a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
index bfab04b00f0..68d9c2d27c3 100644
--- a/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
+++ b/chromium/third_party/blink/renderer/core/css/css_default_style_sheets.h
@@ -32,7 +32,9 @@
namespace blink {
+class Document;
class Element;
+class RuleFeatureSet;
class RuleSet;
class StyleSheetContents;
@@ -49,6 +51,7 @@ class CSSDefaultStyleSheets final
bool EnsureDefaultStyleSheetsForPseudoElement(PseudoId);
bool EnsureDefaultStyleSheetForXrOverlay();
void EnsureDefaultStyleSheetForFullscreen();
+ bool EnsureDefaultStyleSheetForForcedColors();
RuleSet* DefaultStyle() { return default_style_.Get(); }
RuleSet* DefaultMathMLStyle() { return default_mathml_style_.Get(); }
@@ -62,6 +65,9 @@ class CSSDefaultStyleSheets final
RuleSet* DefaultPseudoElementStyleOrNull() {
return default_pseudo_element_style_.Get();
}
+ RuleSet* DefaultMediaControlsStyle() {
+ return default_media_controls_style_.Get();
+ }
StyleSheetContents* EnsureMobileViewportStyleSheet();
StyleSheetContents* EnsureTelevisionViewportStyleSheet();
@@ -78,6 +84,9 @@ class CSSDefaultStyleSheets final
return fullscreen_style_sheet_.Get();
}
StyleSheetContents* MarkerStyleSheet() { return marker_style_sheet_.Get(); }
+ StyleSheetContents* ForcedColorsStyleSheet() {
+ return forced_colors_style_sheet_.Get();
+ }
CORE_EXPORT void PrepareForLeakDetection();
@@ -97,6 +106,8 @@ class CSSDefaultStyleSheets final
return media_controls_style_sheet_loader_.get();
}
+ void CollectFeaturesTo(const Document&, RuleFeatureSet&);
+
void Trace(Visitor*) const;
private:
@@ -110,6 +121,7 @@ class CSSDefaultStyleSheets final
Member<RuleSet> default_view_source_style_;
Member<RuleSet> default_forced_color_style_;
Member<RuleSet> default_pseudo_element_style_;
+ Member<RuleSet> default_media_controls_style_;
Member<StyleSheetContents> default_style_sheet_;
Member<StyleSheetContents> mobile_viewport_style_sheet_;
@@ -123,6 +135,7 @@ class CSSDefaultStyleSheets final
Member<StyleSheetContents> fullscreen_style_sheet_;
Member<StyleSheetContents> webxr_overlay_style_sheet_;
Member<StyleSheetContents> marker_style_sheet_;
+ Member<StyleSheetContents> forced_colors_style_sheet_;
std::unique_ptr<UAStyleSheetLoader> media_controls_style_sheet_loader_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc b/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
index 89699d77da4..3c91fe87f6f 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_face_src_value.cc
@@ -127,7 +127,7 @@ FontResource& CSSFontFaceSrcValue::Fetch(ExecutionContext* context,
context->GetTaskRunner(TaskType::kInternalLoading).get());
}
}
- return *ToFontResource(fetched_->GetResource());
+ return *To<FontResource>(fetched_->GetResource());
}
void CSSFontFaceSrcValue::RestoreCachedResourceIfNeeded(
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_selector.cc b/chromium/third_party/blink/renderer/core/css/css_font_selector.cc
index 3269f58eb3d..7cbff5a8da9 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_selector.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_font_selector.cc
@@ -46,18 +46,19 @@
namespace blink {
-CSSFontSelector::CSSFontSelector(Document* document)
- : document_(document),
- generic_font_family_settings_(
- document->GetFrame()->GetSettings()->GetGenericFontFamilySettings()) {
- // FIXME: An old comment used to say there was no need to hold a reference to
- // document_ because "we are guaranteed to be destroyed before the document".
- // But there does not seem to be any such guarantee.
- DCHECK(document_);
- DCHECK(document_->GetFrame());
+CSSFontSelector::CSSFontSelector(const TreeScope& tree_scope)
+ : tree_scope_(&tree_scope),
+ generic_font_family_settings_(tree_scope.GetDocument()
+ .GetFrame()
+ ->GetSettings()
+ ->GetGenericFontFamilySettings()) {
+ DCHECK(tree_scope.GetDocument().GetFrame());
FontCache::GetFontCache()->AddClient(this);
- FontFaceSetDocument::From(*document)->AddFontFacesToFontFaceCache(
- &font_face_cache_);
+ if (tree_scope.RootNode().IsDocumentNode()) {
+ font_face_cache_ = MakeGarbageCollected<FontFaceCache>();
+ FontFaceSetDocument::From(tree_scope.GetDocument())
+ ->AddFontFacesToFontFaceCache(font_face_cache_);
+ }
}
CSSFontSelector::~CSSFontSelector() = default;
@@ -75,7 +76,7 @@ void CSSFontSelector::UnregisterForInvalidationCallbacks(
void CSSFontSelector::DispatchInvalidationCallbacks(
FontInvalidationReason reason) {
- font_face_cache_.IncrementVersion();
+ font_face_cache_->IncrementVersion();
HeapVector<Member<FontSelectorClient>> clients;
CopyToVector(clients_, clients);
@@ -97,13 +98,14 @@ void CSSFontSelector::FontCacheInvalidated() {
scoped_refptr<FontData> CSSFontSelector::GetFontData(
const FontDescription& font_description,
const AtomicString& family_name) {
+ Document& document = GetTreeScope()->GetDocument();
if (CSSSegmentedFontFace* face =
- font_face_cache_.Get(font_description, family_name)) {
- document_->GetFontMatchingMetrics()->ReportWebFontFamily(family_name);
+ font_face_cache_->Get(font_description, family_name)) {
+ document.GetFontMatchingMetrics()->ReportWebFontFamily(family_name);
return face->GetFontData(font_description);
}
- document_->GetFontMatchingMetrics()->ReportSystemFontFamily(family_name);
+ document.GetFontMatchingMetrics()->ReportSystemFontFamily(family_name);
// Try to return the correct font based off our settings, in case we were
// handed the generic font family name.
@@ -112,7 +114,7 @@ scoped_refptr<FontData> CSSFontSelector::GetFontData(
if (settings_family_name.IsEmpty())
return nullptr;
- document_->GetFontMatchingMetrics()->ReportFontFamilyLookupByGenericFamily(
+ document.GetFontMatchingMetrics()->ReportFontFamilyLookupByGenericFamily(
family_name, font_description.GetScript(),
font_description.GenericFamily(), settings_family_name);
@@ -120,7 +122,7 @@ scoped_refptr<FontData> CSSFontSelector::GetFontData(
FontCache::GetFontCache()->GetFontData(font_description,
settings_family_name);
- document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
+ document.GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
settings_family_name, font_description, font_data.get());
return font_data;
@@ -129,7 +131,7 @@ scoped_refptr<FontData> CSSFontSelector::GetFontData(
void CSSFontSelector::WillUseFontData(const FontDescription& font_description,
const AtomicString& family,
const String& text) {
- CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
+ CSSSegmentedFontFace* face = font_face_cache_->Get(font_description, family);
if (face)
face->WillUseFontData(font_description, text);
}
@@ -137,7 +139,7 @@ void CSSFontSelector::WillUseFontData(const FontDescription& font_description,
void CSSFontSelector::WillUseRange(const FontDescription& font_description,
const AtomicString& family,
const FontDataForRangeSet& range_set) {
- CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
+ CSSSegmentedFontFace* face = font_face_cache_->Get(font_description, family);
if (face)
face->WillUseRange(font_description, range_set);
}
@@ -162,43 +164,37 @@ void CSSFontSelector::UpdateGenericFontFamilySettings(Document& document) {
}
void CSSFontSelector::ReportNotDefGlyph() const {
- DCHECK(document_);
- UseCounter::Count(document_, WebFeature::kFontShapingNotDefGlyphObserved);
+ UseCounter::Count(GetDocument(), WebFeature::kFontShapingNotDefGlyphObserved);
}
void CSSFontSelector::ReportSuccessfulFontFamilyMatch(
const AtomicString& font_family_name) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportSuccessfulFontFamilyMatch(
+ GetDocument().GetFontMatchingMetrics()->ReportSuccessfulFontFamilyMatch(
font_family_name);
}
void CSSFontSelector::ReportFailedFontFamilyMatch(
const AtomicString& font_family_name) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportFailedFontFamilyMatch(
+ GetDocument().GetFontMatchingMetrics()->ReportFailedFontFamilyMatch(
font_family_name);
}
void CSSFontSelector::ReportSuccessfulLocalFontMatch(
const AtomicString& font_name) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportSuccessfulLocalFontMatch(
+ GetDocument().GetFontMatchingMetrics()->ReportSuccessfulLocalFontMatch(
font_name);
}
void CSSFontSelector::ReportFailedLocalFontMatch(
const AtomicString& font_name) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportFailedLocalFontMatch(font_name);
+ GetDocument().GetFontMatchingMetrics()->ReportFailedLocalFontMatch(font_name);
}
void CSSFontSelector::ReportFontLookupByUniqueOrFamilyName(
const AtomicString& name,
const FontDescription& font_description,
SimpleFontData* resulting_font_data) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
+ GetDocument().GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
name, font_description, resulting_font_data);
}
@@ -207,8 +203,7 @@ void CSSFontSelector::ReportFontLookupByUniqueNameOnly(
const FontDescription& font_description,
SimpleFontData* resulting_font_data,
bool is_loading_fallback) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueNameOnly(
+ GetDocument().GetFontMatchingMetrics()->ReportFontLookupByUniqueNameOnly(
name, font_description, resulting_font_data, is_loading_fallback);
}
@@ -217,8 +212,7 @@ void CSSFontSelector::ReportFontLookupByFallbackCharacter(
FontFallbackPriority fallback_priority,
const FontDescription& font_description,
SimpleFontData* resulting_font_data) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportFontLookupByFallbackCharacter(
+ GetDocument().GetFontMatchingMetrics()->ReportFontLookupByFallbackCharacter(
fallback_character, fallback_priority, font_description,
resulting_font_data);
}
@@ -226,13 +220,12 @@ void CSSFontSelector::ReportFontLookupByFallbackCharacter(
void CSSFontSelector::ReportLastResortFallbackFontLookup(
const FontDescription& font_description,
SimpleFontData* resulting_font_data) {
- DCHECK(document_);
- document_->GetFontMatchingMetrics()->ReportLastResortFallbackFontLookup(
+ GetDocument().GetFontMatchingMetrics()->ReportLastResortFallbackFontLookup(
font_description, resulting_font_data);
}
void CSSFontSelector::Trace(Visitor* visitor) const {
- visitor->Trace(document_);
+ visitor->Trace(tree_scope_);
visitor->Trace(font_face_cache_);
visitor->Trace(clients_);
FontSelector::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/css/css_font_selector.h b/chromium/third_party/blink/renderer/core/css/css_font_selector.h
index 4d0e8dd21be..dfe75a67da7 100644
--- a/chromium/third_party/blink/renderer/core/css/css_font_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/css_font_selector.h
@@ -42,10 +42,10 @@ class FontDescription;
class CORE_EXPORT CSSFontSelector : public FontSelector {
public:
- explicit CSSFontSelector(Document*);
+ explicit CSSFontSelector(const TreeScope&);
~CSSFontSelector() override;
- unsigned Version() const override { return font_face_cache_.Version(); }
+ unsigned Version() const override { return font_face_cache_->Version(); }
void ReportNotDefGlyph() const override;
@@ -100,15 +100,21 @@ class CORE_EXPORT CSSFontSelector : public FontSelector {
void UnregisterForInvalidationCallbacks(FontSelectorClient*) override;
ExecutionContext* GetExecutionContext() const override {
- return document_ ? document_->GetExecutionContext() : nullptr;
+ return tree_scope_ ? GetDocument().GetExecutionContext() : nullptr;
}
- FontFaceCache* GetFontFaceCache() override { return &font_face_cache_; }
+ FontFaceCache* GetFontFaceCache() override { return font_face_cache_; }
const GenericFontFamilySettings& GetGenericFontFamilySettings() const {
return generic_font_family_settings_;
}
void UpdateGenericFontFamilySettings(Document&);
+ const TreeScope* GetTreeScope() const { return tree_scope_; }
+ Document& GetDocument() const {
+ DCHECK(tree_scope_);
+ return tree_scope_->GetDocument();
+ }
+
void Trace(Visitor*) const override;
protected:
@@ -118,9 +124,8 @@ class CORE_EXPORT CSSFontSelector : public FontSelector {
// TODO(Oilpan): Ideally this should just be a traced Member but that will
// currently leak because ComputedStyle and its data are not on the heap.
// See crbug.com/383860 for details.
- WeakMember<Document> document_;
- // FIXME: Move to Document or StyleEngine.
- FontFaceCache font_face_cache_;
+ WeakMember<const TreeScope> tree_scope_;
+ Member<FontFaceCache> font_face_cache_;
HeapHashSet<WeakMember<FontSelectorClient>> clients_;
GenericFontFamilySettings generic_font_family_settings_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_global_rule_set.cc b/chromium/third_party/blink/renderer/core/css/css_global_rule_set.cc
index 0c3c15ed944..995afcad348 100644
--- a/chromium/third_party/blink/renderer/core/css/css_global_rule_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_global_rule_set.cc
@@ -35,17 +35,13 @@ void CSSGlobalRuleSet::Update(Document& document) {
is_dirty_ = false;
features_.Clear();
- has_fullscreen_ua_style_ = false;
CSSDefaultStyleSheets& default_style_sheets =
CSSDefaultStyleSheets::Instance();
- if (default_style_sheets.DefaultStyle()) {
- features_.Add(default_style_sheets.DefaultStyle()->Features());
- has_fullscreen_ua_style_ = default_style_sheets.FullscreenStyleSheet();
- }
- if (document.IsViewSource())
- features_.Add(default_style_sheets.DefaultViewSourceStyle()->Features());
+ has_fullscreen_ua_style_ = default_style_sheets.FullscreenStyleSheet();
+
+ default_style_sheets.CollectFeaturesTo(document, features_);
if (watched_selectors_rule_set_)
features_.Add(watched_selectors_rule_set_->Features());
diff --git a/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc b/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
index 5bba1337a4b..27aea6ae005 100644
--- a/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_gradient_value.cc
@@ -390,8 +390,8 @@ bool NormalizeAndAddStops(const Vector<GradientStop>& stops,
const float first_offset = stops.front().offset;
const float last_offset = stops.back().offset;
- const float span =
- std::min(last_offset - first_offset, std::numeric_limits<float>::max());
+ const float span = std::min(std::max(last_offset - first_offset, 0.f),
+ std::numeric_limits<float>::max());
if (fabs(span) < std::numeric_limits<float>::epsilon()) {
// All stops are coincident -> use a single clamped offset value.
@@ -418,8 +418,7 @@ bool NormalizeAndAddStops(const Vector<GradientStop>& stops,
// stop offsets should be monotonically increasing in [0 , 1]
DCHECK_GE(normalized_offset, 0);
DCHECK_LE(normalized_offset, 1);
- DCHECK(i == 0 ||
- normalized_offset >= (stops[i - 1].offset - first_offset) / span);
+ DCHECK(i == 0 || normalized_offset >= desc.stops.back().stop);
desc.stops.emplace_back(normalized_offset, stops[i].color);
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_grouping_rule.h b/chromium/third_party/blink/renderer/core/css/css_grouping_rule.h
index d8b7dc46788..4d201b28e3d 100644
--- a/chromium/third_party/blink/renderer/core/css/css_grouping_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_grouping_rule.h
@@ -32,7 +32,7 @@ namespace blink {
class ExceptionState;
class CSSRuleList;
-class CSSGroupingRule : public CSSRule {
+class CORE_EXPORT CSSGroupingRule : public CSSRule {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/css/css_image_set_value.cc b/chromium/third_party/blink/renderer/core/css/css_image_set_value.cc
index 89ac0c76073..bd14a2d5250 100644
--- a/chromium/third_party/blink/renderer/core/css/css_image_set_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_image_set_value.cc
@@ -39,14 +39,13 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/referrer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
-CSSImageSetValue::CSSImageSetValue(CSSParserMode parser_mode)
- : CSSValueList(kImageSetClass, kCommaSeparator),
- cached_scale_factor_(1),
- parser_mode_(parser_mode) {}
+CSSImageSetValue::CSSImageSetValue()
+ : CSSValueList(kImageSetClass, kCommaSeparator), cached_scale_factor_(1) {}
CSSImageSetValue::~CSSImageSetValue() = default;
@@ -54,27 +53,14 @@ void CSSImageSetValue::FillImageSet() {
wtf_size_t length = this->length();
wtf_size_t i = 0;
while (i < length) {
- const auto& image_value = To<CSSImageValue>(Item(i));
- String image_url = image_value.Url();
+ wtf_size_t image_index = i;
++i;
SECURITY_DCHECK(i < length);
- const CSSValue& scale_factor_value = Item(i);
- float scale_factor =
- To<CSSPrimitiveValue>(scale_factor_value).GetFloatValue();
-
- ImageWithScale image;
- image.image_url = image_url;
- image.referrer.referrer = image_value.GetReferrer().referrer;
- image.referrer.referrer_policy = image_value.GetReferrer().referrer_policy;
- image.scale_factor = scale_factor;
-
- // Only set for the first image as all images in a set should have identical
- // is_ad_related bits.
- if (!images_in_set_.size())
- is_ad_related_ = image_value.GetIsAdRelated();
- DCHECK_EQ(is_ad_related_, image_value.GetIsAdRelated());
- images_in_set_.push_back(image);
+ const auto& scale_factor_value = To<CSSPrimitiveValue>(Item(i));
+
+ images_in_set_.push_back(
+ ImageWithScale{image_index, scale_factor_value.GetFloatValue()});
++i;
}
@@ -119,19 +105,21 @@ StyleImage* CSSImageSetValue::CacheImage(
// Page::PageScaleFactor(), LocalFrame::PageZoomFactor(), and any CSS
// transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
ImageWithScale image = BestImageForScaleFactor(device_scale_factor);
- ResourceRequest resource_request(document.CompleteURL(image.image_url));
+ const auto& image_value = To<CSSImageValue>(Item(image.index));
+ ResourceRequest resource_request(image_value.Url());
resource_request.SetReferrerPolicy(
ReferrerUtils::MojoReferrerPolicyResolveDefault(
- image.referrer.referrer_policy));
- resource_request.SetReferrerString(image.referrer.referrer);
- if (is_ad_related_)
+ image_value.GetReferrer().referrer_policy));
+ resource_request.SetReferrerString(image_value.GetReferrer().referrer);
+ if (image_value.GetIsAdRelated())
resource_request.SetIsAdResource();
ResourceLoaderOptions options(
document.GetExecutionContext()->GetCurrentWorld());
- options.initiator_info.name = parser_mode_ == kUASheetMode
- ? fetch_initiator_type_names::kUacss
- : fetch_initiator_type_names::kCSS;
- options.initiator_info.referrer = image.referrer.referrer;
+ const AtomicString& initiator_name = image_value.GetInitiator();
+ options.initiator_info.name = initiator_name.IsEmpty()
+ ? fetch_initiator_type_names::kCSS
+ : initiator_name;
+ options.initiator_info.referrer = image_value.GetReferrer().referrer;
FetchParameters params(std::move(resource_request), options);
if (cross_origin != kCrossOriginAttributeNotSet) {
@@ -192,7 +180,7 @@ void CSSImageSetValue::TraceAfterDispatch(blink::Visitor* visitor) const {
}
CSSImageSetValue* CSSImageSetValue::ValueWithURLsMadeAbsolute() {
- auto* value = MakeGarbageCollected<CSSImageSetValue>(parser_mode_);
+ auto* value = MakeGarbageCollected<CSSImageSetValue>();
for (auto& item : *this) {
auto* image_value = DynamicTo<CSSImageValue>(item.Get());
image_value ? value->Append(*image_value->ValueWithURLMadeAbsolute())
diff --git a/chromium/third_party/blink/renderer/core/css/css_image_set_value.h b/chromium/third_party/blink/renderer/core/css/css_image_set_value.h
index 0b474dc65c7..980533cd662 100644
--- a/chromium/third_party/blink/renderer/core/css/css_image_set_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_image_set_value.h
@@ -27,10 +27,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_IMAGE_SET_VALUE_H_
#include "third_party/blink/renderer/core/css/css_value_list.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
#include "third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
-#include "third_party/blink/renderer/platform/weborigin/referrer.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -41,7 +39,7 @@ class StyleImage;
class CSSImageSetValue : public CSSValueList {
public:
- explicit CSSImageSetValue(CSSParserMode);
+ explicit CSSImageSetValue();
~CSSImageSetValue();
bool IsCachePending(float device_scale_factor) const;
@@ -54,13 +52,6 @@ class CSSImageSetValue : public CSSValueList {
String CustomCSSText() const;
- struct ImageWithScale {
- DISALLOW_NEW();
- String image_url;
- Referrer referrer;
- float scale_factor;
- };
-
CSSImageSetValue* ValueWithURLsMadeAbsolute();
bool HasFailedOrCanceledSubresources() const;
@@ -68,6 +59,12 @@ class CSSImageSetValue : public CSSValueList {
void TraceAfterDispatch(blink::Visitor*) const;
protected:
+ struct ImageWithScale {
+ DISALLOW_NEW();
+ wtf_size_t index;
+ float scale_factor;
+ };
+
ImageWithScale BestImageForScaleFactor(float scale_factor);
private:
@@ -80,8 +77,6 @@ class CSSImageSetValue : public CSSValueList {
Member<StyleImage> cached_image_;
float cached_scale_factor_;
- bool is_ad_related_ = false;
- CSSParserMode parser_mode_;
Vector<ImageWithScale> images_in_set_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/css_image_value.h b/chromium/third_party/blink/renderer/core/css/css_image_value.h
index ed57fce9a75..167e4fc54dc 100644
--- a/chromium/third_party/blink/renderer/core/css/css_image_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_image_value.h
@@ -61,6 +61,7 @@ class CORE_EXPORT CSSImageValue : public CSSValue {
const String& RelativeUrl() const { return relative_url_; }
const Referrer& GetReferrer() const { return referrer_; }
+ const AtomicString& GetInitiator() const { return initiator_name_; }
bool GetIsAdRelated() const { return is_ad_related_; }
void ReResolveURL(const Document&) const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_initial_color_value.h b/chromium/third_party/blink/renderer/core/css/css_initial_color_value.h
index e7ac1b064be..381ad6e7353 100644
--- a/chromium/third_party/blink/renderer/core/css/css_initial_color_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_initial_color_value.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_INITIAL_COLOR_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_INITIAL_COLOR_VALUE_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -19,7 +19,7 @@ class CORE_EXPORT CSSInitialColorValue : public CSSValue {
public:
static CSSInitialColorValue* Create();
- explicit CSSInitialColorValue(util::PassKey<CSSValuePool>)
+ explicit CSSInitialColorValue(base::PassKey<CSSValuePool>)
: CSSValue(kInitialColorValueClass) {}
String CustomCSSText() const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_math_expression_node.cc b/chromium/third_party/blink/renderer/core/css/css_math_expression_node.cc
index e74f5b731d0..53fc5910743 100644
--- a/chromium/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
+#include "third_party/blink/renderer/core/css/css_value_clamping_utils.h"
#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
@@ -123,6 +124,39 @@ static bool HasDoubleValue(CSSPrimitiveValue::UnitType type) {
}
}
+namespace {
+
+const PixelsAndPercent CreateClampedSamePixelsAndPercent(float value) {
+ return PixelsAndPercent(CSSValueClampingUtils::ClampLength(value),
+ CSSValueClampingUtils::ClampLength(value));
+}
+
+bool IsNaN(PixelsAndPercent value, bool allows_negative_percentage_reference) {
+ if (std::isnan(value.pixels + value.percent) ||
+ (allows_negative_percentage_reference && std::isinf(value.percent))) {
+ return true;
+ }
+ return false;
+}
+
+base::Optional<PixelsAndPercent> EvaluateValueIfNaNorInfinity(
+ scoped_refptr<const blink::CalculationExpressionNode> value,
+ bool allows_negative_percentage_reference) {
+ float evaluated_value = value->Evaluate(1);
+ if (std::isnan(evaluated_value) || std::isinf(evaluated_value)) {
+ return CreateClampedSamePixelsAndPercent(evaluated_value);
+ }
+ if (allows_negative_percentage_reference) {
+ evaluated_value = value->Evaluate(-1);
+ if (std::isnan(evaluated_value) || std::isinf(evaluated_value)) {
+ return CreateClampedSamePixelsAndPercent(evaluated_value);
+ }
+ }
+ return base::nullopt;
+}
+
+} // namespace
+
// ------ Start of CSSMathExpressionNumericLiteral member functions ------
// static
@@ -138,7 +172,8 @@ CSSMathExpressionNumericLiteral* CSSMathExpressionNumericLiteral::Create(
double value,
CSSPrimitiveValue::UnitType type,
bool is_integer) {
- if (std::isnan(value) || std::isinf(value))
+ if (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
+ (std::isnan(value) || std::isinf(value)))
return nullptr;
return MakeGarbageCollected<CSSMathExpressionNumericLiteral>(
CSSNumericLiteralValue::Create(value, type), is_integer);
@@ -166,11 +201,23 @@ CSSMathExpressionNumericLiteral::ToPixelsAndPercent(
PixelsAndPercent value(0, 0);
switch (category_) {
case kCalcLength:
- value.pixels = value_->ComputeLength<float>(conversion_data);
+ // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
+ // PixelsAndPercent. Therefore, we need to use a function that doesn't
+ // internally clamp the result to the float range.
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ value.pixels = value_->ComputeLengthPx(conversion_data);
+ else
+ value.pixels = value_->ComputeLength<float>(conversion_data);
break;
case kCalcPercent:
DCHECK(value_->IsPercentage());
- value.percent = value_->GetFloatValue();
+ // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
+ // PixelsAndPercent. Therefore, we need to use a function that doesn't
+ // internally clamp the result to the float range.
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ value.percent = value_->GetDoubleValue();
+ else
+ value.percent = value_->GetFloatValue();
break;
case kCalcNumber:
// TODO(alancutter): Stop treating numbers like pixels unconditionally
@@ -223,6 +270,11 @@ double CSSMathExpressionNumericLiteral::ComputeLengthPx(
const CSSToLengthConversionData& conversion_data) const {
switch (category_) {
case kCalcLength:
+ // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
+ // PixelsAndPercent. Therefore, we need to use a function that doesn't
+ // internally clamp the result to the float range.
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ return value_->ComputeLengthPx(conversion_data);
return value_->ComputeLength<double>(conversion_data);
case kCalcNumber:
case kCalcPercent:
@@ -434,10 +486,13 @@ CSSMathExpressionNode* CSSMathExpressionBinaryOperation::CreateSimplified(
left_side == number_side ? right_side : left_side;
double number = number_side->DoubleValue();
- if (std::isnan(number) || std::isinf(number))
- return nullptr;
- if (op == CSSMathOperator::kDivide && !number)
- return nullptr;
+
+ if (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ if (std::isnan(number) || std::isinf(number))
+ return nullptr;
+ if (op == CSSMathOperator::kDivide && !number)
+ return nullptr;
+ }
CSSPrimitiveValue::UnitType other_type = other_side->ResolvedUnitType();
if (HasDoubleValue(other_type)) {
@@ -737,14 +792,23 @@ const CSSMathExpressionNode* CSSMathExpressionBinaryOperation::GetNumberSide(
double CSSMathExpressionBinaryOperation::EvaluateOperator(double left_value,
double right_value,
CSSMathOperator op) {
+ // Design doc for infinity and NaN: https://bit.ly/349gXjq
switch (op) {
case CSSMathOperator::kAdd:
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ return left_value + right_value;
return clampTo<double>(left_value + right_value);
case CSSMathOperator::kSubtract:
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ return left_value - right_value;
return clampTo<double>(left_value - right_value);
case CSSMathOperator::kMultiply:
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ return left_value * right_value;
return clampTo<double>(left_value * right_value);
case CSSMathOperator::kDivide:
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
+ return left_value / right_value;
if (right_value)
return clampTo<double>(left_value / right_value);
return std::numeric_limits<double>::quiet_NaN();
@@ -815,6 +879,9 @@ bool CSSMathExpressionVariadicOperation::IsZero() const {
double CSSMathExpressionVariadicOperation::EvaluateBinary(double lhs,
double rhs) const {
+ if (std::isnan(lhs) || std::isnan(rhs))
+ return std::numeric_limits<double>::quiet_NaN();
+
switch (operator_) {
case CSSMathOperator::kMin:
return std::min(lhs, rhs);
@@ -1084,6 +1151,23 @@ class CSSMathExpressionNodeParser {
private:
CSSMathExpressionNode* ParseValue(CSSParserTokenRange& tokens) {
CSSParserToken token = tokens.ConsumeIncludingWhitespace();
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ if (token.Id() == CSSValueID::kInfinity) {
+ return CSSMathExpressionNumericLiteral::Create(
+ std::numeric_limits<double>::infinity(),
+ CSSPrimitiveValue::UnitType::kNumber, false);
+ }
+ if (token.Id() == CSSValueID::kNegativeInfinity) {
+ return CSSMathExpressionNumericLiteral::Create(
+ -std::numeric_limits<double>::infinity(),
+ CSSPrimitiveValue::UnitType::kNumber, false);
+ }
+ if (token.Id() == CSSValueID::kNan) {
+ return CSSMathExpressionNumericLiteral::Create(
+ std::numeric_limits<double>::quiet_NaN(),
+ CSSPrimitiveValue::UnitType::kNumber, false);
+ }
+ }
if (!(token.GetType() == kNumberToken ||
token.GetType() == kPercentageToken ||
token.GetType() == kDimensionToken))
@@ -1212,11 +1296,37 @@ class CSSMathExpressionNodeParser {
scoped_refptr<CalculationValue> CSSMathExpressionNode::ToCalcValue(
const CSSToLengthConversionData& conversion_data,
- ValueRange range) const {
- if (auto maybe_pixels_and_percent = ToPixelsAndPercent(conversion_data))
+ ValueRange range,
+ bool allows_negative_percentage_reference) const {
+ if (auto maybe_pixels_and_percent = ToPixelsAndPercent(conversion_data)) {
+ // Clamping if pixels + percent could result in NaN. In special case,
+ // inf px + inf % could evaluate to nan when
+ // allows_negative_percentage_reference is true.
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ if (IsNaN(*maybe_pixels_and_percent,
+ allows_negative_percentage_reference)) {
+ maybe_pixels_and_percent = CreateClampedSamePixelsAndPercent(
+ std::numeric_limits<float>::quiet_NaN());
+ } else {
+ maybe_pixels_and_percent->pixels = CSSValueClampingUtils::ClampLength(
+ maybe_pixels_and_percent->pixels);
+ maybe_pixels_and_percent->percent = CSSValueClampingUtils::ClampLength(
+ maybe_pixels_and_percent->percent);
+ }
+ }
return CalculationValue::Create(*maybe_pixels_and_percent, range);
- return CalculationValue::CreateSimplified(
- ToCalculationExpression(conversion_data), range);
+ }
+
+ auto value = ToCalculationExpression(conversion_data);
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ base::Optional<PixelsAndPercent> evaluated_value =
+ EvaluateValueIfNaNorInfinity(value,
+ allows_negative_percentage_reference);
+ if (evaluated_value.has_value()) {
+ return CalculationValue::Create(evaluated_value.value(), range);
+ }
+ }
+ return CalculationValue::CreateSimplified(value, range);
}
// static
diff --git a/chromium/third_party/blink/renderer/core/css/css_math_expression_node.h b/chromium/third_party/blink/renderer/core/css/css_math_expression_node.h
index f7012a2c342..72ea6d1f5e2 100644
--- a/chromium/third_party/blink/renderer/core/css/css_math_expression_node.h
+++ b/chromium/third_party/blink/renderer/core/css/css_math_expression_node.h
@@ -95,7 +95,8 @@ class CORE_EXPORT CSSMathExpressionNode
scoped_refptr<CalculationValue> ToCalcValue(
const CSSToLengthConversionData& conversion_data,
- ValueRange range) const;
+ ValueRange range,
+ bool allows_negative_percentage_reference) const;
// Evaluates the expression with type conversion (e.g., cm -> px) handled, and
// returns the result value in the canonical unit of the corresponding
diff --git a/chromium/third_party/blink/renderer/core/css/css_math_function_value.cc b/chromium/third_party/blink/renderer/core/css/css_math_function_value.cc
index 7df858df8df..195407bf214 100644
--- a/chromium/third_party/blink/renderer/core/css/css_math_function_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_math_function_value.cc
@@ -5,8 +5,10 @@
#include "third_party/blink/renderer/core/css/css_math_function_value.h"
#include "third_party/blink/renderer/core/css/css_math_expression_node.h"
+#include "third_party/blink/renderer/core/css/css_value_clamping_utils.h"
#include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -139,7 +141,8 @@ bool CSSMathFunctionValue::IsComputationallyIndependent() const {
scoped_refptr<CalculationValue> CSSMathFunctionValue::ToCalcValue(
const CSSToLengthConversionData& conversion_data) const {
- return expression_->ToCalcValue(conversion_data, PermittedValueRange());
+ return expression_->ToCalcValue(conversion_data, PermittedValueRange(),
+ AllowsNegativePercentageReference());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/chromium/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
index 41e34deda2e..27e722894df 100644
--- a/chromium/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -7,6 +7,7 @@
#include "build/build_config.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
#include "third_party/blink/renderer/core/css/css_value_pool.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -23,7 +24,8 @@ void CSSNumericLiteralValue::TraceAfterDispatch(blink::Visitor* visitor) const {
CSSNumericLiteralValue::CSSNumericLiteralValue(double num, UnitType type)
: CSSPrimitiveValue(kNumericLiteralClass), num_(num) {
- DCHECK(std::isfinite(num));
+ DCHECK(RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() ||
+ std::isfinite(num));
DCHECK_NE(UnitType::kUnknown, type);
numeric_literal_unit_type_ = static_cast<unsigned>(type);
}
@@ -31,13 +33,19 @@ CSSNumericLiteralValue::CSSNumericLiteralValue(double num, UnitType type)
// static
CSSNumericLiteralValue* CSSNumericLiteralValue::Create(double value,
UnitType type) {
- // TODO(timloh): This looks wrong.
- if (std::isinf(value))
- value = 0;
-
if (value < 0 || value > CSSValuePool::kMaximumCacheableIntegerValue)
return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ // Value can be NaN.
+ if (std::isnan(value))
+ return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
+ } else {
+ // TODO(timloh): This looks wrong.
+ if (std::isinf(value))
+ value = 0;
+ }
+
int int_value = clampTo<int>(value);
if (value != int_value)
return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
@@ -155,6 +163,24 @@ static String FormatNumber(double number, const char* suffix) {
return result;
}
+static String FormatInfinityOrNaN(double number, const char* suffix) {
+ String result;
+ if (std::isinf(number)) {
+ if (number > 0)
+ result = "infinity";
+ else
+ result = "-infinity";
+
+ } else {
+ DCHECK(std::isnan(number));
+ result = "NaN";
+ }
+
+ if (strlen(suffix) > 0)
+ result = result + String::Format(" * 1%s", suffix);
+ return result;
+}
+
String CSSNumericLiteralValue::CustomCSSText() const {
String text;
switch (GetType()) {
@@ -203,7 +229,13 @@ String CSSNumericLiteralValue::CustomCSSText() const {
// If the value is small integer, go the fast path.
if (value < kMinInteger || value > kMaxInteger ||
std::trunc(value) != value) {
- text = FormatNumber(value, UnitTypeToString(GetType()));
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
+ (std::isinf(value) || std::isnan(value))) {
+ text = FormatInfinityOrNaN(value, UnitTypeToString(GetType()));
+ } else {
+ text = FormatNumber(value, UnitTypeToString(GetType()));
+ }
+
} else {
StringBuilder builder;
int int_value = value;
diff --git a/chromium/third_party/blink/renderer/core/css/css_page_rule_test.cc b/chromium/third_party/blink/renderer/core/css/css_page_rule_test.cc
index a9bcbd44e76..aaf2277721f 100644
--- a/chromium/third_party/blink/renderer/core/css/css_page_rule_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_page_rule_test.cc
@@ -53,6 +53,8 @@ TEST(CSSPageRule, selectorText) {
// set page type selector.
page_rule->setSelectorText(context, "namedpage");
EXPECT_EQ("namedpage", page_rule->selectorText());
+
+ context->NotifyContextDestroyed();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_path_value.cc b/chromium/third_party/blink/renderer/core/css/css_path_value.cc
index d4f7425f907..83d50df9f08 100644
--- a/chromium/third_party/blink/renderer/core/css/css_path_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_path_value.cc
@@ -41,7 +41,7 @@ CSSPathValue* CreatePathValue() {
} // namespace
-CSSPathValue& CSSPathValue::EmptyPathValue() {
+const CSSPathValue& CSSPathValue::EmptyPathValue() {
DEFINE_STATIC_LOCAL(Persistent<CSSPathValue>, empty, (CreatePathValue()));
return *empty;
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_path_value.h b/chromium/third_party/blink/renderer/core/css/css_path_value.h
index 2642b3107fb..493b56e8d9a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_path_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_path_value.h
@@ -21,7 +21,7 @@ namespace cssvalue {
class CSSPathValue : public CSSValue {
public:
- static CSSPathValue& EmptyPathValue();
+ static const CSSPathValue& EmptyPathValue();
explicit CSSPathValue(scoped_refptr<StylePath>,
PathSerializationFormat = kNoTransformation);
diff --git a/chromium/third_party/blink/renderer/core/css/css_primitive_value.cc b/chromium/third_party/blink/renderer/core/css/css_primitive_value.cc
index 0c6378150cd..411928c3a1e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_primitive_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
+#include "third_party/blink/renderer/core/css/css_value_clamping_utils.h"
#include "third_party/blink/renderer/core/css/css_value_pool.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -55,6 +56,12 @@ struct SameSizeAsCSSPrimitiveValue : CSSValue {
ASSERT_SIZE(CSSPrimitiveValue, SameSizeAsCSSPrimitiveValue);
float CSSPrimitiveValue::ClampToCSSLengthRange(double value) {
+ // TODO(crbug.com/1133390): clampTo function could occur the DECHECK failure
+ // for NaN value. Therefore, infinity and NaN values should not be clamped
+ // here.
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ value = CSSValueClampingUtils::ClampLength(value);
+ }
return clampTo<float>(value, kMinValueForCssLength, kMaxValueForCssLength);
}
@@ -261,13 +268,24 @@ uint8_t CSSPrimitiveValue::ComputeLength(
template <>
float CSSPrimitiveValue::ComputeLength(
const CSSToLengthConversionData& conversion_data) const {
- return clampTo<float>(ComputeLengthDouble(conversion_data));
+ // TODO(crbug.com/1133390): clampTo function could occur the DECHECK failure
+ // for NaN value. Therefore, infinity and NaN values should not be clamped
+ // here.
+ float value = ComputeLengthDouble(conversion_data);
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ return CSSValueClampingUtils::ClampLength(value);
+ }
+ return value;
}
template <>
double CSSPrimitiveValue::ComputeLength(
const CSSToLengthConversionData& conversion_data) const {
- return ComputeLengthDouble(conversion_data);
+ double value = ComputeLengthDouble(conversion_data);
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ return CSSValueClampingUtils::ClampLength(value);
+ }
+ return value;
}
double CSSPrimitiveValue::ComputeLengthDouble(
@@ -359,7 +377,11 @@ Length CSSPrimitiveValue::ConvertToLength(
if (IsPercentage()) {
if (IsNumericLiteralValue() ||
!To<CSSMathFunctionValue>(this)->AllowsNegativePercentageReference()) {
- return Length::Percent(GetDoubleValue());
+ double value = GetDoubleValue();
+ if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
+ value = CSSValueClampingUtils::ClampLength(value);
+ }
+ return Length::Percent(value);
}
}
DCHECK(IsCalculated());
diff --git a/chromium/third_party/blink/renderer/core/css/css_primitive_value.h b/chromium/third_party/blink/renderer/core/css/css_primitive_value.h
index 2cfe667e733..8b361a06276 100644
--- a/chromium/third_party/blink/renderer/core/css/css_primitive_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_primitive_value.h
@@ -296,7 +296,8 @@ CORE_EXPORT float CSSPrimitiveValue::ComputeLength(
const CSSToLengthConversionData&) const;
template <>
-double CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
+CORE_EXPORT double CSSPrimitiveValue::ComputeLength(
+ const CSSToLengthConversionData&) const;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
diff --git a/chromium/third_party/blink/renderer/core/css/css_primitive_value_mappings.h b/chromium/third_party/blink/renderer/core/css/css_primitive_value_mappings.h
index da176f1ec5c..19fcafdbb5f 100644
--- a/chromium/third_party/blink/renderer/core/css/css_primitive_value_mappings.h
+++ b/chromium/third_party/blink/renderer/core/css/css_primitive_value_mappings.h
@@ -40,7 +40,6 @@
#include "third_party/blink/renderer/core/scroll/scroll_customization.h"
#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_smoothing_mode.h"
#include "third_party/blink/renderer/platform/fonts/text_rendering_mode.h"
@@ -1008,360 +1007,6 @@ inline WindRule CSSIdentifierValue::ConvertTo() const {
}
template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EAlignmentBaseline e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case AB_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case AB_BASELINE:
- value_id_ = CSSValueID::kBaseline;
- break;
- case AB_BEFORE_EDGE:
- value_id_ = CSSValueID::kBeforeEdge;
- break;
- case AB_TEXT_BEFORE_EDGE:
- value_id_ = CSSValueID::kTextBeforeEdge;
- break;
- case AB_MIDDLE:
- value_id_ = CSSValueID::kMiddle;
- break;
- case AB_CENTRAL:
- value_id_ = CSSValueID::kCentral;
- break;
- case AB_AFTER_EDGE:
- value_id_ = CSSValueID::kAfterEdge;
- break;
- case AB_TEXT_AFTER_EDGE:
- value_id_ = CSSValueID::kTextAfterEdge;
- break;
- case AB_IDEOGRAPHIC:
- value_id_ = CSSValueID::kIdeographic;
- break;
- case AB_ALPHABETIC:
- value_id_ = CSSValueID::kAlphabetic;
- break;
- case AB_HANGING:
- value_id_ = CSSValueID::kHanging;
- break;
- case AB_MATHEMATICAL:
- value_id_ = CSSValueID::kMathematical;
- break;
- }
-}
-
-template <>
-inline EAlignmentBaseline CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kAuto:
- return AB_AUTO;
- case CSSValueID::kBaseline:
- return AB_BASELINE;
- case CSSValueID::kBeforeEdge:
- return AB_BEFORE_EDGE;
- case CSSValueID::kTextBeforeEdge:
- return AB_TEXT_BEFORE_EDGE;
- case CSSValueID::kMiddle:
- return AB_MIDDLE;
- case CSSValueID::kCentral:
- return AB_CENTRAL;
- case CSSValueID::kAfterEdge:
- return AB_AFTER_EDGE;
- case CSSValueID::kTextAfterEdge:
- return AB_TEXT_AFTER_EDGE;
- case CSSValueID::kIdeographic:
- return AB_IDEOGRAPHIC;
- case CSSValueID::kAlphabetic:
- return AB_ALPHABETIC;
- case CSSValueID::kHanging:
- return AB_HANGING;
- case CSSValueID::kMathematical:
- return AB_MATHEMATICAL;
- default:
- break;
- }
-
- NOTREACHED();
- return AB_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EBufferedRendering e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case BR_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case BR_DYNAMIC:
- value_id_ = CSSValueID::kDynamic;
- break;
- case BR_STATIC:
- value_id_ = CSSValueID::kStatic;
- break;
- }
-}
-
-template <>
-inline EBufferedRendering CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kAuto:
- return BR_AUTO;
- case CSSValueID::kDynamic:
- return BR_DYNAMIC;
- case CSSValueID::kStatic:
- return BR_STATIC;
- default:
- break;
- }
-
- NOTREACHED();
- return BR_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EColorInterpolation e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case CI_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case CI_SRGB:
- value_id_ = CSSValueID::kSRGB;
- break;
- case CI_LINEARRGB:
- value_id_ = CSSValueID::kLinearrgb;
- break;
- }
-}
-
-template <>
-inline EColorInterpolation CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kSRGB:
- return CI_SRGB;
- case CSSValueID::kLinearrgb:
- return CI_LINEARRGB;
- case CSSValueID::kAuto:
- return CI_AUTO;
- default:
- break;
- }
-
- NOTREACHED();
- return CI_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EColorRendering e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case CR_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case CR_OPTIMIZESPEED:
- value_id_ = CSSValueID::kOptimizespeed;
- break;
- case CR_OPTIMIZEQUALITY:
- value_id_ = CSSValueID::kOptimizequality;
- break;
- }
-}
-
-template <>
-inline EColorRendering CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kOptimizespeed:
- return CR_OPTIMIZESPEED;
- case CSSValueID::kOptimizequality:
- return CR_OPTIMIZEQUALITY;
- case CSSValueID::kAuto:
- return CR_AUTO;
- default:
- break;
- }
-
- NOTREACHED();
- return CR_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EDominantBaseline e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case DB_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case DB_USE_SCRIPT:
- value_id_ = CSSValueID::kUseScript;
- break;
- case DB_NO_CHANGE:
- value_id_ = CSSValueID::kNoChange;
- break;
- case DB_RESET_SIZE:
- value_id_ = CSSValueID::kResetSize;
- break;
- case DB_CENTRAL:
- value_id_ = CSSValueID::kCentral;
- break;
- case DB_MIDDLE:
- value_id_ = CSSValueID::kMiddle;
- break;
- case DB_TEXT_BEFORE_EDGE:
- value_id_ = CSSValueID::kTextBeforeEdge;
- break;
- case DB_TEXT_AFTER_EDGE:
- value_id_ = CSSValueID::kTextAfterEdge;
- break;
- case DB_IDEOGRAPHIC:
- value_id_ = CSSValueID::kIdeographic;
- break;
- case DB_ALPHABETIC:
- value_id_ = CSSValueID::kAlphabetic;
- break;
- case DB_HANGING:
- value_id_ = CSSValueID::kHanging;
- break;
- case DB_MATHEMATICAL:
- value_id_ = CSSValueID::kMathematical;
- break;
- }
-}
-
-template <>
-inline EDominantBaseline CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kAuto:
- return DB_AUTO;
- case CSSValueID::kUseScript:
- return DB_USE_SCRIPT;
- case CSSValueID::kNoChange:
- return DB_NO_CHANGE;
- case CSSValueID::kResetSize:
- return DB_RESET_SIZE;
- case CSSValueID::kIdeographic:
- return DB_IDEOGRAPHIC;
- case CSSValueID::kAlphabetic:
- return DB_ALPHABETIC;
- case CSSValueID::kHanging:
- return DB_HANGING;
- case CSSValueID::kMathematical:
- return DB_MATHEMATICAL;
- case CSSValueID::kCentral:
- return DB_CENTRAL;
- case CSSValueID::kMiddle:
- return DB_MIDDLE;
- case CSSValueID::kTextAfterEdge:
- return DB_TEXT_AFTER_EDGE;
- case CSSValueID::kTextBeforeEdge:
- return DB_TEXT_BEFORE_EDGE;
- default:
- break;
- }
-
- NOTREACHED();
- return DB_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EShapeRendering e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case SR_AUTO:
- value_id_ = CSSValueID::kAuto;
- break;
- case SR_OPTIMIZESPEED:
- value_id_ = CSSValueID::kOptimizespeed;
- break;
- case SR_CRISPEDGES:
- value_id_ = CSSValueID::kCrispedges;
- break;
- case SR_GEOMETRICPRECISION:
- value_id_ = CSSValueID::kGeometricprecision;
- break;
- }
-}
-
-template <>
-inline EShapeRendering CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kAuto:
- return SR_AUTO;
- case CSSValueID::kOptimizespeed:
- return SR_OPTIMIZESPEED;
- case CSSValueID::kCrispedges:
- return SR_CRISPEDGES;
- case CSSValueID::kGeometricprecision:
- return SR_GEOMETRICPRECISION;
- default:
- break;
- }
-
- NOTREACHED();
- return SR_AUTO;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(ETextAnchor e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case TA_START:
- value_id_ = CSSValueID::kStart;
- break;
- case TA_MIDDLE:
- value_id_ = CSSValueID::kMiddle;
- break;
- case TA_END:
- value_id_ = CSSValueID::kEnd;
- break;
- }
-}
-
-template <>
-inline ETextAnchor CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kStart:
- return TA_START;
- case CSSValueID::kMiddle:
- return TA_MIDDLE;
- case CSSValueID::kEnd:
- return TA_END;
- default:
- break;
- }
-
- NOTREACHED();
- return TA_START;
-}
-
-template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EVectorEffect e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case VE_NONE:
- value_id_ = CSSValueID::kNone;
- break;
- case VE_NON_SCALING_STROKE:
- value_id_ = CSSValueID::kNonScalingStroke;
- break;
- }
-}
-
-template <>
-inline EVectorEffect CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kNone:
- return VE_NONE;
- case CSSValueID::kNonScalingStroke:
- return VE_NON_SCALING_STROKE;
- default:
- break;
- }
-
- NOTREACHED();
- return VE_NONE;
-}
-
-template <>
inline CSSIdentifierValue::CSSIdentifierValue(EPaintOrderType e)
: CSSValue(kIdentifierClass) {
switch (e) {
@@ -1399,34 +1044,6 @@ inline EPaintOrderType CSSIdentifierValue::ConvertTo() const {
}
template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EMaskType e)
- : CSSValue(kIdentifierClass) {
- switch (e) {
- case MT_LUMINANCE:
- value_id_ = CSSValueID::kLuminance;
- break;
- case MT_ALPHA:
- value_id_ = CSSValueID::kAlpha;
- break;
- }
-}
-
-template <>
-inline EMaskType CSSIdentifierValue::ConvertTo() const {
- switch (value_id_) {
- case CSSValueID::kLuminance:
- return MT_LUMINANCE;
- case CSSValueID::kAlpha:
- return MT_ALPHA;
- default:
- break;
- }
-
- NOTREACHED();
- return MT_LUMINANCE;
-}
-
-template <>
inline TouchAction CSSIdentifierValue::ConvertTo() const {
switch (value_id_) {
case CSSValueID::kNone:
@@ -1899,34 +1516,6 @@ inline cc::SnapAlignment CSSIdentifierValue::ConvertTo() const {
}
template <>
-inline CSSIdentifierValue::CSSIdentifierValue(Containment snap_type)
- : CSSValue(kIdentifierClass) {
- switch (snap_type) {
- case kContainsNone:
- value_id_ = CSSValueID::kNone;
- break;
- case kContainsStrict:
- value_id_ = CSSValueID::kStrict;
- break;
- case kContainsContent:
- value_id_ = CSSValueID::kContent;
- break;
- case kContainsPaint:
- value_id_ = CSSValueID::kPaint;
- break;
- case kContainsStyle:
- value_id_ = CSSValueID::kStyle;
- break;
- case kContainsLayout:
- value_id_ = CSSValueID::kLayout;
- break;
- case kContainsSize:
- value_id_ = CSSValueID::kSize;
- break;
- }
-}
-
-template <>
inline Containment CSSIdentifierValue::ConvertTo() const {
switch (GetValueID()) {
case CSSValueID::kNone:
@@ -1943,6 +1532,10 @@ inline Containment CSSIdentifierValue::ConvertTo() const {
return kContainsLayout;
case CSSValueID::kSize:
return kContainsSize;
+ case CSSValueID::kInlineSize:
+ return kContainsInlineSize;
+ case CSSValueID::kBlockSize:
+ return kContainsBlockSize;
default:
break;
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_primitive_value_test.cc b/chromium/third_party/blink/renderer/core/css/css_primitive_value_test.cc
index e3c7a958cfe..fb08b73188c 100644
--- a/chromium/third_party/blink/renderer/core/css/css_primitive_value_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_primitive_value_test.cc
@@ -102,5 +102,56 @@ TEST(CSSPrimitiveValueTest, Zooming) {
EXPECT_EQ("calc(10% + 100px)", converted->CustomCSSText());
}
+TEST(CSSPrimitiveValueTest, PositiveInfinityLengthClamp) {
+ UnitValue a = {std::numeric_limits<double>::infinity(), UnitType::kPixels};
+ UnitValue b = {1, UnitType::kPixels};
+ CSSPrimitiveValue* value = CreateAddition(a, b);
+ CSSToLengthConversionData conversion_data;
+ EXPECT_EQ(std::numeric_limits<double>::max(),
+ value->ComputeLength<double>(conversion_data));
+}
+
+TEST(CSSPrimitiveValueTest, NegativeInfinityLengthClamp) {
+ UnitValue a = {-std::numeric_limits<double>::infinity(), UnitType::kPixels};
+ UnitValue b = {1, UnitType::kPixels};
+ CSSPrimitiveValue* value = CreateAddition(a, b);
+ CSSToLengthConversionData conversion_data;
+ EXPECT_EQ(std::numeric_limits<double>::lowest(),
+ value->ComputeLength<double>(conversion_data));
+}
+
+TEST(CSSPrimitiveValueTest, NaNLengthClamp) {
+ UnitValue a = {-std::numeric_limits<double>::quiet_NaN(), UnitType::kPixels};
+ UnitValue b = {1, UnitType::kPixels};
+ CSSPrimitiveValue* value = CreateAddition(a, b);
+ CSSToLengthConversionData conversion_data;
+ EXPECT_EQ(std::numeric_limits<double>::max(),
+ value->ComputeLength<double>(conversion_data));
+}
+
+TEST(CSSPrimitiveValueTest, PositiveInfinityPercentLengthClamp) {
+ CSSPrimitiveValue* value =
+ Create({std::numeric_limits<double>::infinity(), UnitType::kPercentage});
+ CSSToLengthConversionData conversion_data;
+ Length length = value->ConvertToLength(conversion_data);
+ EXPECT_EQ(std::numeric_limits<float>::max(), length.Percent());
+}
+
+TEST(CSSPrimitiveValueTest, NegativeInfinityPercentLengthClamp) {
+ CSSPrimitiveValue* value =
+ Create({-std::numeric_limits<double>::infinity(), UnitType::kPercentage});
+ CSSToLengthConversionData conversion_data;
+ Length length = value->ConvertToLength(conversion_data);
+ EXPECT_EQ(std::numeric_limits<float>::lowest(), length.Percent());
+}
+
+TEST(CSSPrimitiveValueTest, NaNPercentLengthClamp) {
+ CSSPrimitiveValue* value = Create(
+ {-std::numeric_limits<double>::quiet_NaN(), UnitType::kPercentage});
+ CSSToLengthConversionData conversion_data;
+ Length length = value->ConvertToLength(conversion_data);
+ EXPECT_EQ(std::numeric_limits<float>::max(), length.Percent());
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_properties.json5 b/chromium/third_party/blink/renderer/core/css/css_properties.json5
index 2c6d694897e..b3a7cfb44c0 100644
--- a/chromium/third_party/blink/renderer/core/css/css_properties.json5
+++ b/chromium/third_party/blink/renderer/core/css/css_properties.json5
@@ -155,28 +155,6 @@
valid_type: "bool",
},
- // - computed_value_comparable
- //
- // If true, a CSSProperty::ComputedValuesEqual function is generated.
- computed_value_comparable: {
- default: false,
- valid_type: "bool",
- },
-
- // - computed_value_compare_fields
- //
- // If present, the ComputedStyle fields listed will be used in the
- // generated ComputedvaluesEqual function. This is useful if the value
- // of a property is stored in multiple fields. For example, for
- // vertical-align:
- //
- // computed_value_compare_fields: ['VerticalAlign', 'GetVerticalAlignLength']
- //
- // Has no effect unless computed_value_comparable is true.
- computed_value_compare_fields: {
- default: [],
- },
-
// - runtime_flag
// The name of the flag on RuntimeEnabledFeatures
// (e.g. "CSSOverscrollBehavior") that conditionally enables the
@@ -309,24 +287,18 @@
// - font
// The default property handlers call into the FontBuilder instead of
// setting values directly onto the ComputedStyle
- // - svg
- // The default property handlers access the SVGComputedStyle
font: {
default: false,
valid_type: "bool",
},
- svg: {
- default: false,
- valid_type: "bool",
- },
// - name_for_methods: "BlendMode"
// Tweaks how we choose defaults for getter, setter, initial and type_name.
// For example, setting this to BlendMode will make us use a setter of
// setBlendMode
// - initial
- // The static function to invoke on ComputedStyleInitialValues,
- // SVGComputedStyle, or FontBuilder to retrieve the initial value.
+ // The static function to invoke on ComputedStyleInitialValues
+ // or FontBuilder to retrieve the initial value.
// Defaults to e.g. InitialBorderBottomLeft.
// - getter
// The ComputedStyle getter, defaults to e.g. BorderBottomLeft
@@ -362,34 +334,48 @@
converter: {
},
- // Options used for properties that depend on writing-mode and/or
- // text-direction (e.g. css-logical).
- direction_aware_options: {
- // The name of the mapping function used to convert from a logical
- // property to a physical property. Corresponds to a function in
- // CSSDirectionAwareResolver. E.g. a value of "baz" corresponds to
- // CSSDirectionAwareResolver::ResolveBaz(...).
- resolver: {
+ // - logical_property_group: used for properties that depend on writing-mode
+ // and/or text-direction (e.g. css-logical), and for their physical counterparts.
+ // Represents the "logical property group" described by css-logical
+ // (https://drafts.csswg.org/css-logical/#logical-property-group).
+ logical_property_group: {
+ // A name identifying the logical property group. All logical and physical
+ // properties in the same group should have the same name.
+ //
+ // In terms of code generation, each value corresponds to 2 functions in
+ // CSSDirectionAwareResolver. E.g. a value of "foo-bar" would correspond to:
+ // - CSSDirectionAwareResolver::LogicalFooBarMapping(), containing the
+ // properties of the group with a flow-relative mapping logic.
+ // - CSSDirectionAwareResolver::PhysicalFooBarMapping(), containing the
+ // properties of the group with a physical mapping logic.
+ name: {
valid_type: "str",
- valid_values: ["inline-start", "inline-end", "block-start", "block-end",
- "inline", "block"],
+ valid_values: ["border", "border-color", "border-radius",
+ "border-style", "border-width", "inset",
+ "margin", "max-size", "min-size", "overflow", "padding",
+ "scroll-margin", "scroll-padding", "size",
+ "visited-border-color"],
},
- // The name of the physical property group to pass to the resolver.
- // The group represents the physical part of the "logical property group"
- // described by css-logical [1].
+ // The name of the mapping function used to convert between equivalent
+ // logical and physical properties within the same group. Corresponds to
+ // a function in CSSDirectionAwareResolver. E.g. a value of "baz"
+ // corresponds to CSSDirectionAwareResolver::ResolveBaz(...).
//
- // In terms of code generation, each value corresponds to a function in
- // CSSDirectionAwareResolver. E.g. a value of "foo-bar" would correspond
- // to CSSDirectionAwareResolver::FooBarGroup().
- //
- // [1] https://drafts.csswg.org/css-logical/#logical-property-group
- physical_group: {
+ // Also identifies the mapping logic of the group
+ // (https://drafts.csswg.org/css-logical-1/#mapping-logic)
+ resolver: {
valid_type: "str",
- valid_values: ["border", "border-color", "border-style", "border-width",
- "inset", "margin", "max-size",
- "min-size", "overflow", "padding", "scroll-margin",
- "scroll-padding", "size", "visited-border-color"],
- }
+ valid_values: [
+ // Mapping logic: flow-relative (logical)
+ "block", "inline",
+ "block-start", "block-end", "inline-start", "inline-end",
+ "start-start", "start-end", "end-start", "end-end",
+ // Mapping logic: physical
+ "vertical", "horizontal",
+ "top", "bottom", "left", "right",
+ "top-left", "top-right", "bottom-right", "bottom-left",
+ ],
+ },
},
// - surrogate_for: "other-property"
@@ -405,7 +391,7 @@
// * inline-size (surrogate for width, or height)
// * All css-logical propeties in general
//
- // Note that for properties that use direction_aware_options,
+ // Note that for properties that use logical_property_group,
// 'surrogate_for' should not be set, as the mapping is determined at
// run-time (depending og e.g. 'direction').
surrogate_for: {
@@ -728,7 +714,6 @@
style_builder_custom_functions: ["value"],
priority: "High",
valid_for_marker: true,
- computed_value_comparable: true,
},
{
name: "font-family",
@@ -738,6 +723,7 @@
font: true,
name_for_methods: "FamilyDescription",
type_name: "FontDescription::FamilyDescription",
+ style_builder_custom_functions: ["initial", "inherit"],
converter: "ConvertFontFamily",
priority: "High",
valid_for_first_letter: true,
@@ -1024,7 +1010,6 @@
type_name: "WritingMode",
style_builder_custom_functions: ["initial", "inherit", "value"],
priority: "High",
- computed_value_comparable: true,
},
{
name: "-webkit-writing-mode",
@@ -1034,7 +1019,6 @@
style_builder_custom_functions: ["initial", "inherit", "value"],
priority: "High",
surrogate_for: "writing-mode",
- computed_value_comparable: true,
},
{
name: "text-rendering",
@@ -1066,7 +1050,6 @@
default_value: "StyleContentAlignmentData(ContentPosition::kNormal, ContentDistributionType::kDefault, OverflowAlignment::kDefault)",
type_name: "StyleContentAlignmentData",
converter: "ConvertContentAlignmentData",
- computed_value_comparable: true,
},
{
name: "align-items",
@@ -1077,14 +1060,17 @@
default_value: "StyleSelfAlignmentData(ItemPosition::kNormal, OverflowAlignment::kDefault)",
type_name: "StyleSelfAlignmentData",
converter: "ConvertSelfOrDefaultAlignmentData",
- computed_value_comparable: true,
},
{
name: "alignment-baseline",
property_methods: ["CSSValueFromComputedStyleInternal"],
- svg: true,
- keywords: ["baseline", "alphabetic", "ideographic", "middle", "central", "mathematical"],
- typedom_types: ["Keyword"]
+ field_group: "svg",
+ field_template: "keyword",
+ keywords: ["auto", "baseline", "alphabetic", "ideographic", "middle",
+ "central", "mathematical", "before-edge", "text-before-edge",
+ "after-edge", "text-after-edge", "hanging"],
+ typedom_types: ["Keyword"],
+ default_value: "auto",
},
{
name: "align-self",
@@ -1095,12 +1081,11 @@
default_value: "StyleSelfAlignmentData(ItemPosition::kAuto, OverflowAlignment::kDefault)",
type_name: "StyleSelfAlignmentData",
converter: "ConvertSelfOrDefaultAlignmentData",
- computed_value_comparable: true,
},
{
name: "aspect-ratio",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
- interpolable: false,
+ interpolable: true,
field_group: "box",
field_template: "external",
keywords: ["auto"],
@@ -1122,7 +1107,7 @@
default_value: "MakeGarbageCollected<StyleFilterData>()",
type_name: "StyleFilterData",
computed_style_custom_functions: ["initial", "getter","setter"],
- converter: "ConvertFilterOperations",
+ style_builder_custom_functions: ["value"],
keywords: ["none"],
typedom_types: ["Keyword"],
},
@@ -1185,6 +1170,7 @@
name: "background-color",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
+ compositable: true,
field_group: "background",
field_template: "external",
include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
@@ -1294,9 +1280,12 @@
name: "baseline-shift",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->misc",
+ field_template: "external",
+ type_name: "Length",
+ default_value: "Length::Fixed()",
style_builder_custom_functions: ["inherit", "value"],
- keywords: ["sub", "super"],
+ keywords: ["baseline", "sub", "super"],
typedom_types: ["Keyword", "Percentage", "Length"]
},
{
@@ -1315,7 +1304,10 @@
style_builder_template: "color",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-color",
+ resolver: "bottom",
+ },
},
{
name: "border-bottom-left-radius",
@@ -1330,7 +1322,10 @@
typedom_types: ["Length", "Percentage"],
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "bottom-left",
+ },
},
{
name: "border-bottom-right-radius",
@@ -1345,7 +1340,10 @@
typedom_types: ["Length", "Percentage"],
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "bottom-right",
+ },
},
{
name: "border-bottom-style",
@@ -1361,7 +1359,10 @@
type_name: "EBorderStyle",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-style",
+ resolver: "bottom",
+ },
},
{
name: "border-bottom-width",
@@ -1378,7 +1379,10 @@
converter: "ConvertBorderWidth",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-width",
+ resolver: "bottom",
+ },
},
{
name: "border-collapse",
@@ -1465,7 +1469,10 @@
style_builder_template: "color",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-color",
+ resolver: "left",
+ },
},
{
name: "border-left-style",
@@ -1481,7 +1488,10 @@
type_name: "EBorderStyle",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-style",
+ resolver: "left",
+ },
},
{
name: "border-left-width",
@@ -1498,7 +1508,10 @@
converter: "ConvertBorderWidth",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-width",
+ resolver: "left",
+ },
},
{
name: "border-right-color",
@@ -1516,7 +1529,10 @@
style_builder_template: "color",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-color",
+ resolver: "right",
+ },
},
{
name: "border-right-style",
@@ -1532,7 +1548,10 @@
type_name: "EBorderStyle",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-style",
+ resolver: "right",
+ },
},
{
name: "border-right-width",
@@ -1549,7 +1568,10 @@
converter: "ConvertBorderWidth",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-width",
+ resolver: "right",
+ },
},
{
name: "border-top-color",
@@ -1567,7 +1589,10 @@
style_builder_template: "color",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-color",
+ resolver: "top",
+ },
},
{
name: "border-top-left-radius",
@@ -1582,7 +1607,10 @@
typedom_types: ["Length", "Percentage"],
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "top-left",
+ },
},
{
name: "border-top-right-radius",
@@ -1597,7 +1625,10 @@
typedom_types: ["Length", "Percentage"],
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "top-right",
+ },
},
{
name: "border-top-style",
@@ -1613,7 +1644,10 @@
type_name: "EBorderStyle",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-style",
+ resolver: "top",
+ },
},
{
name: "border-top-width",
@@ -1630,7 +1664,10 @@
converter: "ConvertBorderWidth",
valid_for_first_letter: true,
is_border: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "border-width",
+ resolver: "top",
+ },
},
{
name: "bottom",
@@ -1643,7 +1680,10 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "inset",
+ resolver: "bottom",
+ },
},
{
name: "box-shadow",
@@ -1710,7 +1750,10 @@
{
name: "buffered-rendering",
property_methods: ["CSSValueFromComputedStyleInternal"],
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
+ keywords: ["auto", "dynamic", "static"],
+ default_value: "auto",
},
{
name: "caption-side",
@@ -1767,11 +1810,12 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
field_group: "*",
- field_template: "pointer",
+ field_template: "external",
include_paths: ["third_party/blink/renderer/core/style/clip_path_operation.h"],
wrapper_pointer_name: "scoped_refptr",
default_value: "nullptr",
type_name: "ClipPathOperation",
+ computed_style_custom_functions: ["getter", "setter"],
converter: "ConvertClipPath",
keywords: ["none"],
typedom_types: ["Keyword"]
@@ -1780,32 +1824,46 @@
name: "clip-rule",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ // TODO(fs): Convert this to a keyword (requires enum massage).
+ field_template: "primitive",
+ field_size: 1,
+ include_paths: ["third_party/blink/renderer/platform/graphics/graphics_types.h"],
type_name: "WindRule",
keywords: ["nonzero", "evenodd"],
+ default_value: "RULE_NONZERO",
typedom_types: ["Keyword"]
},
{
name: "color-interpolation",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
+ type_name: "EColorInterpolation",
keywords: ["auto", "srgb", "linearrgb"],
+ default_value: "srgb",
typedom_types: ["Keyword"],
},
{
name: "color-interpolation-filters",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
type_name: "EColorInterpolation",
+ keywords: ["auto", "srgb", "linearrgb"],
+ default_value: "linearrgb",
+ typedom_types: ["Keyword"],
},
{
name: "color-rendering",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
keywords: ["auto", "optimizespeed", "optimizequality"],
+ default_value: "auto",
typedom_types: ["Keyword"],
},
{
@@ -1834,13 +1892,13 @@
name: "contain",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
field_group: "*",
- field_size: 4,
+ field_size: 5,
field_template: "primitive",
default_value: "kContainsNone",
name_for_methods: "Contain",
type_name: "unsigned",
converter: "ConvertFlags<Containment>",
- keywords: ["none", "strict", "content", "size", "layout", "style", "paint"],
+ keywords: ["none", "strict", "content", "size", "layout", "style", "paint", "inline-size", "block-size"],
typedom_types: ["Keyword"],
},
{
@@ -1868,6 +1926,7 @@
computed_style_custom_functions: ["getter", "setter"],
style_builder_custom_functions: ["initial", "inherit", "value"],
valid_for_marker: true,
+ tree_scoped_value: true,
},
{
name: "counter-increment",
@@ -1922,7 +1981,9 @@
name: "cx",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Fixed()",
typedom_types: ["Length", "Percentage"],
converter: "ConvertLength",
},
@@ -1930,7 +1991,9 @@
name: "cy",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Fixed()",
typedom_types: ["Length", "Percentage"],
converter: "ConvertLength",
},
@@ -1938,7 +2001,12 @@
name: "d",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "pointer",
+ include_paths: ["third_party/blink/renderer/core/style/style_path.h"],
+ wrapper_pointer_name: "scoped_refptr",
+ type_name: "StylePath",
+ default_value: "nullptr",
converter: "ConvertPathOrNone",
keywords: ["none"],
typedom_types: ["Keyword"],
@@ -1960,8 +2028,11 @@
name: "dominant-baseline",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
- keywords: ["auto", "alphabetic", "ideographic", "middle", "central", "mathematical", "hanging"],
+ field_group: "svg",
+ field_template: "keyword",
+ keywords: ["auto", "alphabetic", "ideographic", "middle", "central", "mathematical", "hanging",
+ "use-script", "no-change", "reset-size", "text-after-edge", "text-before-edge"],
+ default_value: "auto",
typedom_types: ["Keyword"]
},
{
@@ -1976,14 +2047,20 @@
},
{
name: "fill",
- property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
inherited: true,
- svg: true,
- initial: "InitialFillPaint",
- setter: "SetFillPaint",
- getter: "FillPaint",
+ field_group: "svg->fill",
+ field_template: "external",
+ type_name: "SVGPaint",
+ include_paths: ["third_party/blink/renderer/core/style/svg_paint.h"],
+ default_value: "SVGPaint(Color::kBlack)",
+ name_for_methods: "FillPaint",
converter: "ConvertSVGPaint",
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialFillPaint",
+ },
valid_for_highlight: true,
},
{
@@ -1991,7 +2068,10 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
+ field_group: "svg->fill",
+ field_template: "primitive",
+ type_name: "float",
+ default_value: "1",
converter: "ConvertAlpha",
typedom_types: ["Number"],
},
@@ -1999,9 +2079,14 @@
name: "fill-rule",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ // TODO(fs): Convert this to a keyword (requires enum massage).
+ field_template: "primitive",
+ field_size: 1,
+ include_paths: ["third_party/blink/renderer/platform/graphics/graphics_types.h"],
type_name: "WindRule",
keywords: ["nonzero", "evenodd"],
+ default_value: "RULE_NONZERO",
typedom_types: ["Keyword"]
},
{
@@ -2016,7 +2101,7 @@
default_value: "MakeGarbageCollected<StyleFilterData>()",
type_name: "StyleFilterData",
computed_style_custom_functions: ["initial", "getter", "setter"],
- converter: "ConvertFilterOperations",
+ style_builder_custom_functions: ["value"],
keywords: ["none"],
typedom_types: ["Keyword"],
},
@@ -2030,7 +2115,6 @@
converter: "ConvertLengthOrAuto",
typedom_types: ["Keyword", "Length", "Percentage"],
keywords: ["auto"],
- computed_value_comparable: true,
},
{
name: "flex-direction",
@@ -2040,7 +2124,6 @@
typedom_types: ["Keyword"],
keywords: ["row", "row-reverse", "column", "column-reverse"],
default_value: "row",
- computed_value_comparable: true,
},
{
name: "flex-grow",
@@ -2051,7 +2134,6 @@
default_value: "0.0f",
type_name: "float",
typedom_types: ["Number"],
- computed_value_comparable: true,
},
{
name: "flex-shrink",
@@ -2062,7 +2144,6 @@
default_value: "1.0f",
type_name: "float",
typedom_types: ["Number"],
- computed_value_comparable: true,
},
{
name: "flex-wrap",
@@ -2072,7 +2153,6 @@
typedom_types: ["Keyword"],
keywords: ["nowrap", "wrap", "wrap-reverse"],
default_value: "nowrap",
- computed_value_comparable: true,
},
{
name: "float",
@@ -2090,7 +2170,15 @@
name: "flood-color",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
- svg: true,
+ field_group: "svg->misc",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+ default_value: "StyleColor(Color::kBlack)",
+ type_name: "StyleColor",
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialFloodColor",
+ },
converter: "ConvertStyleColor",
keywords: ["currentcolor"],
typedom_types: ["Keyword"],
@@ -2099,7 +2187,10 @@
name: "flood-opacity",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->misc",
+ field_template: "primitive",
+ type_name: "float",
+ default_value: "1",
converter: "ConvertAlpha",
typedom_types: ["Number"]
},
@@ -2241,7 +2332,10 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthSizing",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "size",
+ resolver: "vertical",
+ },
},
{
name: "hyphens",
@@ -2272,7 +2366,6 @@
name: "image-orientation",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
- runtime_flag: "ImageOrientation",
field_group: "*",
field_template: "primitive",
default_value: "true",
@@ -2298,7 +2391,6 @@
default_value: "StyleContentAlignmentData(ContentPosition::kNormal, ContentDistributionType::kDefault, OverflowAlignment::kDefault)",
type_name: "StyleContentAlignmentData",
converter: "ConvertContentAlignmentData",
- computed_value_comparable: true,
},
{
name: "justify-items",
@@ -2309,7 +2401,6 @@
default_value: "StyleSelfAlignmentData(ItemPosition::kLegacy, OverflowAlignment::kDefault)",
type_name: "StyleSelfAlignmentData",
converter: "ConvertSelfOrDefaultAlignmentData",
- computed_value_comparable: true,
},
{
name: "justify-self",
@@ -2320,7 +2411,6 @@
default_value: "StyleSelfAlignmentData(ItemPosition::kAuto, OverflowAlignment::kDefault)",
type_name: "StyleSelfAlignmentData",
converter: "ConvertSelfOrDefaultAlignmentData",
- computed_value_comparable: true,
},
{
name: "left",
@@ -2333,7 +2423,10 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "inset",
+ resolver: "left",
+ },
},
{
name: "letter-spacing",
@@ -2350,7 +2443,15 @@
name: "lighting-color",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
- svg: true,
+ field_group: "svg->misc",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+ default_value: "StyleColor(Color::kWhite)",
+ type_name: "StyleColor",
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialLightingColor",
+ },
converter: "ConvertStyleColor",
keywords: ["currentcolor"],
typedom_types: ["Keyword"],
@@ -2414,8 +2515,15 @@
name: "list-style-type",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/style/list_style_type_data.h"],
+ wrapper_pointer_name: "Persistent",
+ default_value: "ListStyleTypeData::CreateCounterStyle(\"disc\", nullptr)",
+ type_name: "ListStyleTypeData",
keywords: [
- "disc", "circle", "square", "decimal", "decimal-leading-zero",
+ "disc", "circle", "square", "disclosure-open", "disclosure-closed",
+ "decimal", "decimal-leading-zero",
"arabic-indic", "bengali", "cambodian", "khmer", "devanagari",
"gujarati", "gurmukhi", "kannada", "lao", "malayalam", "mongolian",
"myanmar", "oriya", "persian", "urdu", "telugu", "tibetan", "thai",
@@ -2429,7 +2537,9 @@
"simp-chinese-informal", "trad-chinese-formal", "trad-chinese-informal",
"hiragana", "katakana", "hiragana-iroha", "katakana-iroha", "none"
],
+ computed_style_custom_functions: ["getter"],
style_builder_custom_functions: ["initial", "inherit", "value"],
+ tree_scoped_value: true,
},
{
name: "margin-bottom",
@@ -2444,7 +2554,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "margin",
+ resolver: "bottom",
+ },
},
{
name: "margin-left",
@@ -2459,7 +2572,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "margin",
+ resolver: "left",
+ },
},
{
name: "margin-right",
@@ -2474,7 +2590,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "margin",
+ resolver: "right",
+ },
},
{
name: "margin-top",
@@ -2489,13 +2608,20 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "margin",
+ resolver: "top",
+ },
},
{
name: "marker-end",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg->inherited_resources",
+ field_template: "pointer",
+ type_name: "StyleSVGResource",
+ wrapper_pointer_name: "scoped_refptr",
+ default_value: "nullptr",
name_for_methods: "MarkerEndResource",
converter: "ConvertElementReference",
keywords: ["none"],
@@ -2505,7 +2631,11 @@
name: "marker-mid",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg->inherited_resources",
+ field_template: "pointer",
+ type_name: "StyleSVGResource",
+ wrapper_pointer_name: "scoped_refptr",
+ default_value: "nullptr",
name_for_methods: "MarkerMidResource",
converter: "ConvertElementReference",
keywords: ["none"],
@@ -2515,7 +2645,11 @@
name: "marker-start",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg->inherited_resources",
+ field_template: "pointer",
+ type_name: "StyleSVGResource",
+ wrapper_pointer_name: "scoped_refptr",
+ default_value: "nullptr",
name_for_methods: "MarkerStartResource",
converter: "ConvertElementReference",
keywords: ["none"],
@@ -2524,16 +2658,23 @@
{
name: "mask",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
- svg: true,
+ field_group: "svg",
+ field_template: "pointer",
+ type_name: "StyleSVGResource",
+ include_paths: ["third_party/blink/renderer/core/style/style_svg_resource.h"],
+ wrapper_pointer_name: "scoped_refptr",
+ default_value: "nullptr",
name_for_methods: "MaskerResource",
converter: "ConvertElementReference",
},
{
name: "mask-type",
property_methods: ["CSSValueFromComputedStyleInternal"],
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
keywords: ["luminance", "alpha"],
- typedom_types: ["Keyword"]
+ typedom_types: ["Keyword"],
+ default_value: "luminance",
},
{
name: "math-shift",
@@ -2566,7 +2707,10 @@
converter: "ConvertLengthMaxSizing",
keywords: ["none"],
typedom_types: ["Keyword", "Length", "Percentage"],
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "max-size",
+ resolver: "vertical",
+ },
},
{
name: "max-width",
@@ -2579,7 +2723,10 @@
converter: "ConvertLengthMaxSizing",
keywords: ["none"],
typedom_types: ["Keyword", "Length", "Percentage"],
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "max-size",
+ resolver: "horizontal",
+ },
},
{
name: "min-height",
@@ -2591,7 +2738,10 @@
default_value: "Length()",
converter: "ConvertLengthSizing",
typedom_types: ["Length", "Percentage"],
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "min-size",
+ resolver: "vertical",
+ },
},
{
name: "min-width",
@@ -2603,7 +2753,10 @@
default_value: "Length()",
converter: "ConvertLengthSizing",
typedom_types: ["Length", "Percentage"],
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "min-size",
+ resolver: "horizontal",
+ },
},
{
name: "mix-blend-mode",
@@ -2839,17 +2992,17 @@
},
{
name: "overflow-inline",
- direction_aware_options: {
+ logical_property_group: {
+ name: "overflow",
resolver: "inline",
- physical_group: "overflow",
},
runtime_flag: "CSSLogicalOverflow",
},
{
name: "overflow-block",
- direction_aware_options: {
+ logical_property_group: {
+ name: "overflow",
resolver: "block",
- physical_group: "overflow",
},
runtime_flag: "CSSLogicalOverflow",
},
@@ -2874,6 +3027,10 @@
typedom_types: ["Keyword"],
default_value: "visible",
type_name: "EOverflow",
+ logical_property_group: {
+ name: "overflow",
+ resolver: "horizontal",
+ },
},
{
name: "overflow-y",
@@ -2885,19 +3042,23 @@
typedom_types: ["Keyword"],
default_value: "visible",
type_name: "EOverflow",
+ logical_property_group: {
+ name: "overflow",
+ resolver: "vertical",
+ },
},
{
name: "overscroll-behavior-inline",
- direction_aware_options: {
+ logical_property_group: {
+ name: "overscroll-behavior",
resolver: "inline",
- physical_group: "overscroll-behavior",
},
},
{
name: "overscroll-behavior-block",
- direction_aware_options: {
+ logical_property_group: {
+ name: "overscroll-behavior",
resolver: "block",
- physical_group: "overscroll-behavior",
},
},
{
@@ -2907,7 +3068,11 @@
keywords: ["auto", "contain", "none"],
default_value: "auto",
type_name: "EOverscrollBehavior",
- typedom_types: ["Keyword"]
+ typedom_types: ["Keyword"],
+ logical_property_group: {
+ name: "overscroll-behavior",
+ resolver: "horizontal",
+ },
},
{
name: "overscroll-behavior-y",
@@ -2916,7 +3081,11 @@
keywords: ["auto", "contain", "none"],
default_value: "auto",
type_name: "EOverscrollBehavior",
- typedom_types: ["Keyword"]
+ typedom_types: ["Keyword"],
+ logical_property_group: {
+ name: "overscroll-behavior",
+ resolver: "vertical",
+ },
},
{
name: "padding-bottom",
@@ -2930,7 +3099,10 @@
computed_style_custom_functions: ["setter"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "padding",
+ resolver: "bottom",
+ },
},
{
name: "padding-left",
@@ -2944,7 +3116,10 @@
computed_style_custom_functions: ["setter"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "padding",
+ resolver: "left",
+ },
},
{
name: "padding-right",
@@ -2958,7 +3133,10 @@
computed_style_custom_functions: ["setter"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "padding",
+ resolver: "right",
+ },
},
{
name: "padding-top",
@@ -2972,7 +3150,10 @@
computed_style_custom_functions: ["setter"],
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "padding",
+ resolver: "top",
+ },
},
{
name: "page",
@@ -3001,7 +3182,11 @@
name: "paint-order",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "primitive",
+ field_size: 3,
+ type_name: "EPaintOrder",
+ default_value: "kPaintOrderNormal",
converter: "ConvertPaintOrder",
keywords: ["normal", "fill", "stroke", "markers"],
typedom_types: ["Keyword"]
@@ -3101,13 +3286,18 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "inset",
+ resolver: "right",
+ },
},
{
name: "r",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Fixed()",
typedom_types: ["Length", "Percentage"],
converter: "ConvertLength",
},
@@ -3115,7 +3305,9 @@
name: "rx",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Auto()",
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
@@ -3124,7 +3316,9 @@
name: "ry",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Auto()",
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
@@ -3170,9 +3364,9 @@
{
name: "scroll-margin-block-end",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-margin",
resolver: "block-end",
- physical_group: "scroll-margin",
},
typedom_types: ["Keyword", "Length"]
},
@@ -3191,9 +3385,9 @@
{
name: "scroll-margin-block-start",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-margin",
resolver: "block-start",
- physical_group: "scroll-margin",
},
typedom_types: ["Keyword", "Length"]
},
@@ -3205,23 +3399,27 @@
default_value: "0.0f",
type_name: "float",
converter: "ConvertComputedLength<float>",
- typedom_types: ["Keyword", "Length"]
+ typedom_types: ["Keyword", "Length"],
+ logical_property_group: {
+ name: "scroll-margin",
+ resolver: "bottom",
+ },
},
{
name: "scroll-margin-inline-end",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-margin",
resolver: "inline-end",
- physical_group: "scroll-margin",
},
typedom_types: ["Keyword", "Length"]
},
{
name: "scroll-margin-inline-start",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-margin",
resolver: "inline-start",
- physical_group: "scroll-margin",
},
typedom_types: ["Keyword", "Length"]
},
@@ -3233,7 +3431,11 @@
default_value: "0.0f",
type_name: "float",
converter: "ConvertComputedLength<float>",
- typedom_types: ["Keyword", "Length"]
+ typedom_types: ["Keyword", "Length"],
+ logical_property_group: {
+ name: "scroll-margin",
+ resolver: "left",
+ },
},
{
name: "scroll-margin-right",
@@ -3243,7 +3445,11 @@
default_value: "0.0f",
type_name: "float",
converter: "ConvertComputedLength<float>",
- typedom_types: ["Keyword", "Length"]
+ typedom_types: ["Keyword", "Length"],
+ logical_property_group: {
+ name: "scroll-margin",
+ resolver: "right",
+ },
},
{
name: "scroll-margin-top",
@@ -3253,7 +3459,11 @@
default_value: "0.0f",
type_name: "float",
converter: "ConvertComputedLength<float>",
- typedom_types: ["Keyword", "Length"]
+ typedom_types: ["Keyword", "Length"],
+ logical_property_group: {
+ name: "scroll-margin",
+ resolver: "top",
+ },
},
{
name: "scroll-padding-block-end",
@@ -3263,9 +3473,9 @@
typedom_types: ["Keyword", "Length", "Percentage"],
type_name: "Length",
converter: "ConvertLengthOrAuto",
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-padding",
resolver: "block-end",
- physical_group: "scroll-padding",
},
},
{
@@ -3276,9 +3486,9 @@
typedom_types: ["Keyword", "Length", "Percentage"],
type_name: "Length",
converter: "ConvertLengthOrAuto",
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-padding",
resolver: "block-start",
- physical_group: "scroll-padding",
},
},
{
@@ -3290,6 +3500,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
+ logical_property_group: {
+ name: "scroll-padding",
+ resolver: "bottom",
+ },
},
{
name: "scroll-padding-inline-end",
@@ -3299,9 +3513,9 @@
typedom_types: ["Keyword", "Length", "Percentage"],
type_name: "Length",
converter: "ConvertLengthOrAuto",
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-padding",
resolver: "inline-end",
- physical_group: "scroll-padding",
},
},
{
@@ -3312,9 +3526,9 @@
typedom_types: ["Keyword", "Length", "Percentage"],
type_name: "Length",
converter: "ConvertLengthOrAuto",
- direction_aware_options: {
+ logical_property_group: {
+ name: "scroll-padding",
resolver: "inline-start",
- physical_group: "scroll-padding",
},
},
{
@@ -3326,6 +3540,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
+ logical_property_group: {
+ name: "scroll-padding",
+ resolver: "left",
+ },
},
{
name: "scroll-padding-right",
@@ -3336,6 +3554,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
+ logical_property_group: {
+ name: "scroll-padding",
+ resolver: "right",
+ },
},
{
name: "scroll-padding-top",
@@ -3346,6 +3568,10 @@
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
+ logical_property_group: {
+ name: "scroll-padding",
+ resolver: "top",
+ },
},
{
name: "scroll-snap-align",
@@ -3422,8 +3648,10 @@
name: "shape-rendering",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
keywords: ["auto", "optimizespeed", "crispedges", "geometricprecision"],
+ default_value: "auto",
typedom_types: ["Keyword"],
},
{
@@ -3447,7 +3675,16 @@
name: "stop-color",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
- svg: true,
+ field_group: "svg->stop",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+ default_value: "StyleColor(Color::kBlack)",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter"],
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialStopColor",
+ },
converter: "ConvertStyleColor",
keywords: ["currentcolor"],
typedom_types: ["Keyword"],
@@ -3456,20 +3693,29 @@
name: "stop-opacity",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->stop",
+ field_template: "primitive",
+ type_name: "float",
+ default_value: "1",
converter: "ConvertAlpha",
typedom_types: ["Number"]
},
{
name: "stroke",
- property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
interpolable: true,
inherited: true,
- svg: true,
- initial: "InitialStrokePaint",
- setter: "SetStrokePaint",
- getter: "StrokePaint",
+ field_group: "svg->stroke",
+ field_template: "external",
+ type_name: "SVGPaint",
+ include_paths: ["third_party/blink/renderer/core/style/svg_paint.h"],
+ default_value: "SVGPaint()",
+ name_for_methods: "StrokePaint",
converter: "ConvertSVGPaint",
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialStrokePaint",
+ },
valid_for_highlight: true,
},
{
@@ -3477,7 +3723,12 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
+ field_group: "svg->stroke",
+ field_template: "pointer",
+ type_name: "SVGDashArray",
+ include_paths: ["third_party/blink/renderer/core/style/svg_dash_array.h"],
+ wrapper_pointer_name: "scoped_refptr",
+ default_value: "EmptyDashArray()",
name_for_methods: "StrokeDashArray",
converter: "ConvertStrokeDasharray",
keywords: ["none"],
@@ -3488,7 +3739,10 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
+ field_group: "svg->stroke",
+ field_template: "external",
+ type_name: "Length",
+ default_value: "Length::Fixed()",
name_for_methods: "StrokeDashOffset",
converter: "ConvertLength",
typedom_types: ["Length", "Percentage"]
@@ -3497,9 +3751,12 @@
name: "stroke-linecap",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
- name_for_methods: "CapStyle",
+ field_group: "svg->stroke",
+ field_template: "primitive",
+ field_size: 2,
type_name: "LineCap",
+ default_value: "kButtCap",
+ name_for_methods: "CapStyle",
keywords: ["butt", "round", "square"],
typedom_types: ["Keyword"]
},
@@ -3507,9 +3764,12 @@
name: "stroke-linejoin",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
- name_for_methods: "JoinStyle",
+ field_group: "svg->stroke",
+ field_template: "primitive",
+ field_size: 2,
type_name: "LineJoin",
+ default_value: "kMiterJoin",
+ name_for_methods: "JoinStyle",
keywords: ["miter", "bevel", "round"],
typedom_types: ["Keyword"]
},
@@ -3518,9 +3778,11 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
- name_for_methods: "StrokeMiterLimit",
+ field_group: "svg->stroke",
+ field_template: "primitive",
type_name: "float",
+ default_value: "4",
+ name_for_methods: "StrokeMiterLimit",
typedom_types: ["Number"]
},
{
@@ -3528,7 +3790,10 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
+ field_group: "svg->stroke",
+ field_template: "primitive",
+ type_name: "float",
+ default_value: "1",
converter: "ConvertAlpha",
typedom_types: ["Number"]
},
@@ -3537,7 +3802,11 @@
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
inherited: true,
- svg: true,
+ field_group: "svg->stroke",
+ field_template: "external",
+ type_name: "UnzoomedLength",
+ include_paths: ["third_party/blink/renderer/core/style/unzoomed_length.h"],
+ default_value: "UnzoomedLength(Length::Fixed(1))",
converter: "ConvertUnzoomedLength",
typedom_types: ["Length", "Percentage"],
valid_for_highlight: true,
@@ -3597,9 +3866,11 @@
name: "text-anchor",
property_methods: ["CSSValueFromComputedStyleInternal"],
inherited: true,
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
keywords: ["start", "middle", "end"],
- typedom_types: ["Keyword"]
+ default_value: "start",
+ typedom_types: ["Keyword"],
},
{
name: "text-combine-upright",
@@ -3630,7 +3901,6 @@
valid_for_first_letter: true,
valid_for_cue: true,
valid_for_highlight: true,
- computed_value_comparable: true,
},
{
name: "text-decoration-line",
@@ -3646,7 +3916,6 @@
valid_for_first_letter: true,
valid_for_cue: true,
valid_for_highlight: true,
- computed_value_comparable: true,
},
{
name: "text-decoration-skip-ink",
@@ -3661,7 +3930,6 @@
valid_for_cue: true,
valid_for_marker: true,
valid_for_highlight: true,
- computed_value_comparable: true,
},
{
name: "text-decoration-style",
@@ -3674,7 +3942,6 @@
valid_for_first_letter: true,
valid_for_cue: true,
valid_for_highlight: true,
- computed_value_comparable: true,
},
{
name: "text-decoration-thickness",
@@ -3691,7 +3958,6 @@
typedom_types: ["Keyword", "Length", "Percentage"],
valid_for_first_letter: true,
valid_for_highlight: true,
- computed_value_comparable: true,
},
{
name: "text-indent",
@@ -3814,7 +4080,10 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthOrAuto",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "inset",
+ resolver: "top",
+ },
},
{
name: "touch-action",
@@ -3936,9 +4205,11 @@
{
name: "vector-effect",
property_methods: ["CSSValueFromComputedStyleInternal"],
- svg: true,
+ field_group: "svg",
+ field_template: "keyword",
keywords: ["none", "non-scaling-stroke"],
- typedom_types: ["Keyword"]
+ typedom_types: ["Keyword"],
+ default_value: "none",
},
{
name: "vertical-align",
@@ -3948,8 +4219,6 @@
typedom_types: ["Keyword", "Length", "Percentage"],
keywords: ["baseline", "sub", "super", "text-top", "text-bottom", "middle"],
valid_for_first_letter: true,
- computed_value_comparable: true,
- computed_value_compare_fields: ['VerticalAlign', 'GetVerticalAlignLength']
},
{
name: "visibility",
@@ -3968,7 +4237,9 @@
name: "x",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Fixed()",
typedom_types: ["Length", "Percentage"],
converter: "ConvertLength",
},
@@ -3976,7 +4247,9 @@
name: "y",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
interpolable: true,
- svg: true,
+ field_group: "svg->geometry",
+ field_template: "<length>",
+ default_value: "Length::Fixed()",
typedom_types: ["Length", "Percentage"],
converter: "ConvertLength",
},
@@ -4613,7 +4886,10 @@
default_value: "Length()",
typedom_types: ["Keyword", "Length", "Percentage"],
converter: "ConvertLengthSizing",
- computed_value_comparable: true,
+ logical_property_group: {
+ name: "size",
+ resolver: "horizontal",
+ },
},
{
name: "will-change",
@@ -4665,9 +4941,9 @@
name: "inline-size",
property_methods: ["ParseSingleValue"],
layout_dependent: true,
- direction_aware_options: {
+ logical_property_group: {
+ name: "size",
resolver: "inline",
- physical_group: "size",
},
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4676,9 +4952,9 @@
name: "block-size",
property_methods: ["ParseSingleValue"],
layout_dependent: true,
- direction_aware_options: {
+ logical_property_group: {
+ name: "size",
resolver: "block",
- physical_group: "size",
},
keywords: ["auto"],
typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4686,27 +4962,27 @@
{
name: "min-inline-size",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "min-size",
resolver: "inline",
- physical_group: "min-size",
},
typedom_types: ["Length", "Percentage"],
},
{
name: "min-block-size",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "min-size",
resolver: "block",
- physical_group: "min-size",
},
typedom_types: ["Length", "Percentage"],
},
{
name: "max-inline-size",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "max-size",
resolver: "inline",
- physical_group: "max-size",
},
keywords: ["none"],
typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4714,9 +4990,9 @@
{
name: "max-block-size",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "max-size",
resolver: "block",
- physical_group: "max-size",
},
keywords: ["none"],
typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4725,9 +5001,9 @@
name: "margin-inline-start",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "margin",
resolver: "inline-start",
- physical_group: "margin",
},
typedom_types: ["Length", "Percentage"],
keywords: ["auto"],
@@ -4737,9 +5013,9 @@
name: "margin-inline-end",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "margin",
resolver: "inline-end",
- physical_group: "margin",
},
typedom_types: ["Length", "Percentage"],
keywords: ["auto"],
@@ -4749,9 +5025,9 @@
name: "margin-block-start",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "margin",
resolver: "block-start",
- physical_group: "margin",
},
typedom_types: ["Length", "Percentage"],
keywords: ["auto"],
@@ -4761,9 +5037,9 @@
name: "margin-block-end",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "margin",
resolver: "block-end",
- physical_group: "margin",
},
typedom_types: ["Length", "Percentage"],
keywords: ["auto"],
@@ -4773,9 +5049,9 @@
name: "padding-inline-start",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "padding",
resolver: "inline-start",
- physical_group: "padding",
},
typedom_types: ["Length", "Percentage"]
},
@@ -4783,9 +5059,9 @@
name: "padding-inline-end",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "padding",
resolver: "inline-end",
- physical_group: "padding",
},
typedom_types: ["Length", "Percentage"]
},
@@ -4793,9 +5069,9 @@
name: "padding-block-start",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "padding",
resolver: "block-start",
- physical_group: "padding",
},
typedom_types: ["Length", "Percentage"]
},
@@ -4803,152 +5079,192 @@
name: "padding-block-end",
layout_dependent: true,
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "padding",
resolver: "block-end",
- physical_group: "padding",
},
typedom_types: ["Length", "Percentage"]
},
{
name: "border-inline-start-width",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-width",
resolver: "inline-start",
- physical_group: "border-width",
},
valid_for_first_letter: true,
},
{
name: "border-inline-start-style",
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-style",
resolver: "inline-start",
- physical_group: "border-style",
},
valid_for_first_letter: true,
},
{
name: "border-inline-start-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-color",
resolver: "inline-start",
- physical_group: "border-color",
},
valid_for_first_letter: true,
},
{
name: "border-inline-end-width",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-width",
resolver: "inline-end",
- physical_group: "border-width",
},
valid_for_first_letter: true,
},
{
name: "border-inline-end-style",
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-style",
resolver: "inline-end",
- physical_group: "border-style",
},
valid_for_first_letter: true,
},
{
name: "border-inline-end-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-color",
resolver: "inline-end",
- physical_group: "border-color",
},
valid_for_first_letter: true,
},
{
name: "border-block-start-width",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-width",
resolver: "block-start",
- physical_group: "border-width",
},
valid_for_first_letter: true,
},
{
name: "border-block-start-style",
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-style",
resolver: "block-start",
- physical_group: "border-style",
},
valid_for_first_letter: true,
},
{
name: "border-block-start-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-color",
resolver: "block-start",
- physical_group: "border-color",
},
valid_for_first_letter: true,
},
{
name: "border-block-end-width",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-width",
resolver: "block-end",
- physical_group: "border-width",
},
valid_for_first_letter: true,
},
{
name: "border-block-end-style",
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-style",
resolver: "block-end",
- physical_group: "border-style",
},
valid_for_first_letter: true,
},
{
name: "border-block-end-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border-color",
resolver: "block-end",
- physical_group: "border-color",
},
valid_for_first_letter: true,
},
{
name: "inset-inline-start",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "inset",
resolver: "inline-start",
- physical_group: "inset",
},
typedom_types: ["Length", "Percentage"]
},
{
name: "inset-inline-end",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "inset",
resolver: "inline-end",
- physical_group: "inset",
},
typedom_types: ["Length", "Percentage"]
},
{
name: "inset-block-start",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "inset",
resolver: "block-start",
- physical_group: "inset",
},
typedom_types: ["Length", "Percentage"]
},
{
name: "inset-block-end",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "inset",
resolver: "block-end",
- physical_group: "inset",
},
typedom_types: ["Length", "Percentage"]
},
+ {
+ name: "border-start-start-radius",
+ property_methods: ["ParseSingleValue"],
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "start-start",
+ },
+ typedom_types: ["Length", "Percentage"],
+ valid_for_first_letter: true,
+ },
+ {
+ name: "border-start-end-radius",
+ property_methods: ["ParseSingleValue"],
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "start-end",
+ },
+ typedom_types: ["Length", "Percentage"],
+ valid_for_first_letter: true,
+ },
+ {
+ name: "border-end-start-radius",
+ property_methods: ["ParseSingleValue"],
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "end-start",
+ },
+ typedom_types: ["Length", "Percentage"],
+ valid_for_first_letter: true,
+ },
+ {
+ name: "border-end-end-radius",
+ property_methods: ["ParseSingleValue"],
+ logical_property_group: {
+ name: "border-radius",
+ resolver: "end-end",
+ },
+ typedom_types: ["Length", "Percentage"],
+ valid_for_first_letter: true,
+ },
// Non-standard direction aware properties
@@ -5182,12 +5498,6 @@
runtime_flag: "CSSFontFaceAdvanceOverride",
},
{
- name: "advance-proportional-override",
- is_descriptor: true,
- is_property: false,
- runtime_flag: "CSSFontFaceAdvanceProportionalOverride",
- },
- {
name: "line-gap-override",
is_descriptor: true,
is_property: false,
@@ -5317,9 +5627,9 @@
"border-block-end-color"
],
property_methods: ["ParseShorthand"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border",
resolver: "block-end",
- physical_group: "border",
},
},
{
@@ -5329,9 +5639,9 @@
"border-block-start-color"
],
property_methods: ["ParseShorthand"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border",
resolver: "block-start",
- physical_group: "border",
},
},
{
@@ -5350,6 +5660,10 @@
"border-bottom-width", "border-bottom-style", "border-bottom-color"
],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
+ logical_property_group: {
+ name: "border",
+ resolver: "bottom",
+ },
},
{
name: "border-color",
@@ -5387,9 +5701,9 @@
"border-inline-end-color"
],
property_methods: ["ParseShorthand"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border",
resolver: "inline-end",
- physical_group: "border",
},
},
{
@@ -5399,9 +5713,9 @@
"border-inline-start-color"
],
property_methods: ["ParseShorthand"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "border",
resolver: "inline-start",
- physical_group: "border",
},
},
{
@@ -5420,6 +5734,10 @@
"border-left-width", "border-left-style", "border-left-color"
],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
+ logical_property_group: {
+ name: "border",
+ resolver: "left",
+ },
},
{
name: "border-radius",
@@ -5435,6 +5753,10 @@
"border-right-width", "border-right-style", "border-right-color"
],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
+ logical_property_group: {
+ name: "border",
+ resolver: "right",
+ },
},
{
name: "border-spacing",
@@ -5456,6 +5778,10 @@
name: "border-top",
longhands: ["border-top-width", "border-top-style", "border-top-color"],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
+ logical_property_group: {
+ name: "border",
+ resolver: "top",
+ },
},
{
name: "border-width",
@@ -5603,7 +5929,6 @@
name: "marker",
longhands: ["marker-start", "marker-mid", "marker-end"],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
- svg: true,
},
{
name: "offset",
@@ -5871,6 +6196,10 @@
converter: "ConvertStyleColor",
style_builder_template: "visited_color",
valid_for_first_letter: true,
+ logical_property_group: {
+ name: "visited-border-color",
+ resolver: "left",
+ },
},
{
name: "-internal-visited-border-right-color",
@@ -5885,6 +6214,10 @@
converter: "ConvertStyleColor",
style_builder_template: "visited_color",
valid_for_first_letter: true,
+ logical_property_group: {
+ name: "visited-border-color",
+ resolver: "right",
+ },
},
{
name: "-internal-visited-border-top-color",
@@ -5899,6 +6232,10 @@
converter: "ConvertStyleColor",
style_builder_template: "visited_color",
valid_for_first_letter: true,
+ logical_property_group: {
+ name: "visited-border-color",
+ resolver: "top",
+ },
},
{
name: "-internal-visited-border-bottom-color",
@@ -5913,14 +6250,18 @@
converter: "ConvertStyleColor",
style_builder_template: "visited_color",
valid_for_first_letter: true,
+ logical_property_group: {
+ name: "visited-border-color",
+ resolver: "bottom",
+ },
},
{
name: "-internal-visited-border-inline-start-color",
visited_property_for: "border-inline-start-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "visited-border-color",
resolver: "inline-start",
- physical_group: "visited-border-color",
},
valid_for_first_letter: true,
},
@@ -5928,9 +6269,9 @@
name: "-internal-visited-border-inline-end-color",
visited_property_for: "border-inline-end-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "visited-border-color",
resolver: "inline-end",
- physical_group: "visited-border-color",
},
valid_for_first_letter: true,
},
@@ -5938,9 +6279,9 @@
name: "-internal-visited-border-block-start-color",
visited_property_for: "border-block-start-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "visited-border-color",
resolver: "block-start",
- physical_group: "visited-border-color",
},
valid_for_first_letter: true,
},
@@ -5948,22 +6289,28 @@
name: "-internal-visited-border-block-end-color",
visited_property_for: "border-block-end-color",
property_methods: ["ParseSingleValue"],
- direction_aware_options: {
+ logical_property_group: {
+ name: "visited-border-color",
resolver: "block-end",
- physical_group: "visited-border-color",
},
valid_for_first_letter: true,
},
{
name: "-internal-visited-fill",
visited_property_for: "fill",
- property_methods: ["ParseSingleValue"],
+ property_methods: ["ParseSingleValue", "ColorIncludingFallback"],
inherited: true,
- svg: true,
- initial: "InitialFillPaint",
- setter: "SetInternalVisitedFillPaint",
- getter: "FillPaint",
+ field_group: "svg->fill",
+ field_template: "external",
+ type_name: "SVGPaint",
+ include_paths: ["third_party/blink/renderer/core/style/svg_paint.h"],
+ default_value: "SVGPaint(Color::kBlack)",
+ name_for_methods: "InternalVisitedFillPaint",
converter: "ConvertSVGPaint",
+ style_builder_template: "visited_color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialFillPaint",
+ },
valid_for_highlight: true,
},
{
@@ -5983,13 +6330,19 @@
{
name: "-internal-visited-stroke",
visited_property_for: "stroke",
- property_methods: ["ParseSingleValue"],
+ property_methods: ["ParseSingleValue", "ColorIncludingFallback"],
inherited: true,
- svg: true,
- initial: "InitialStrokePaint",
- setter: "SetInternalVisitedStrokePaint",
- getter: "StrokePaint",
+ field_group: "svg->stroke",
+ field_template: "external",
+ type_name: "SVGPaint",
+ include_paths: ["third_party/blink/renderer/core/style/svg_paint.h"],
+ default_value: "SVGPaint()",
+ name_for_methods: "InternalVisitedStrokePaint",
converter: "ConvertSVGPaint",
+ style_builder_template: "visited_color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialStrokePaint",
+ },
valid_for_highlight: true,
},
{
@@ -6054,6 +6407,82 @@
valid_for_highlight: true,
},
+ // Forced colors properties.
+ {
+ name: "-internal-forced-background-color",
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/layout/layout_theme.h"],
+ default_value: "StyleColor(CSSValueID::kCanvas)",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter"],
+ converter: "ConvertStyleColor",
+ style_builder_template: "color",
+ style_builder_template_args: {
+ initial_color: "ComputedStyleInitialValues::InitialInternalForcedBackgroundColor",
+ },
+ valid_for_first_letter: true,
+ valid_for_cue: true,
+ },
+ {
+ name: "-internal-forced-border-color",
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+ default_value: "StyleColor::CurrentColor()",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter"],
+ converter: "ConvertStyleColor",
+ style_builder_template: "color",
+ valid_for_first_letter: true,
+ },
+ {
+ name: "-internal-forced-color",
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
+ inherited: true,
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/layout/layout_theme.h"],
+ default_value: "StyleColor(CSSValueID::kCanvastext)",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter"],
+ style_builder_custom_functions: ["initial", "inherit", "value"],
+ valid_for_first_letter: true,
+ valid_for_cue: true,
+ valid_for_marker: true,
+ },
+ {
+ name: "-internal-forced-outline-color",
+ property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "ColorIncludingFallback"],
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+ default_value: "StyleColor::CurrentColor()",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter"],
+ converter: "ConvertStyleColor",
+ style_builder_template: "color",
+ valid_for_cue: true,
+ },
+ {
+ name: "-internal-forced-visited-color",
+ visited_property_for: "-internal-forced-color",
+ property_methods: ["ParseSingleValue", "ColorIncludingFallback"],
+ inherited: true,
+ field_group: "*",
+ field_template: "external",
+ include_paths: ["third_party/blink/renderer/core/layout/layout_theme.h"],
+ default_value: "StyleColor(CSSValueID::kCanvastext)",
+ type_name: "StyleColor",
+ computed_style_custom_functions: ["getter", "setter"],
+ style_builder_custom_functions: ["initial", "inherit", "value"],
+ valid_for_first_letter: true,
+ valid_for_cue: true,
+ valid_for_marker: true,
+ },
+
// Name: -internal-empty-line-height:
// Value: none | fabricated
// If the element is inline or contains visible text, this property has
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_equality.cc b/chromium/third_party/blink/renderer/core/css/css_property_equality.cc
index 193e125f8f0..7cd98e62a28 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_equality.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -85,7 +85,7 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
return FillLayersEqual<CSSPropertyID::kBackgroundSize>(
a.BackgroundLayers(), b.BackgroundLayers());
case CSSPropertyID::kBaselineShift:
- return a.BaselineShiftValue() == b.BaselineShiftValue();
+ return a.BaselineShift() == b.BaselineShift();
case CSSPropertyID::kBorderBottomColor:
return a.BorderBottomColor() == b.BorderBottomColor() &&
a.InternalVisitedBorderBottomColor() ==
@@ -138,13 +138,10 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
case CSSPropertyID::kColor:
return a.GetColor() == b.GetColor() &&
a.InternalVisitedColor() == b.InternalVisitedColor();
- case CSSPropertyID::kFill: {
- const SVGComputedStyle& a_svg = a.SvgStyle();
- const SVGComputedStyle& b_svg = b.SvgStyle();
- return a_svg.FillPaint().EqualTypeOrColor(b_svg.FillPaint()) &&
- a_svg.InternalVisitedFillPaint().EqualTypeOrColor(
- b_svg.InternalVisitedFillPaint());
- }
+ case CSSPropertyID::kFill:
+ return a.FillPaint().EqualTypeOrColor(b.FillPaint()) &&
+ a.InternalVisitedFillPaint().EqualTypeOrColor(
+ b.InternalVisitedFillPaint());
case CSSPropertyID::kFillOpacity:
return a.FillOpacity() == b.FillOpacity();
case CSSPropertyID::kFlexBasis:
@@ -249,13 +246,10 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
return a.StopColor() == b.StopColor();
case CSSPropertyID::kStopOpacity:
return a.StopOpacity() == b.StopOpacity();
- case CSSPropertyID::kStroke: {
- const SVGComputedStyle& a_svg = a.SvgStyle();
- const SVGComputedStyle& b_svg = b.SvgStyle();
- return a_svg.StrokePaint().EqualTypeOrColor(b_svg.StrokePaint()) &&
- a_svg.InternalVisitedStrokePaint().EqualTypeOrColor(
- b_svg.InternalVisitedStrokePaint());
- }
+ case CSSPropertyID::kStroke:
+ return a.StrokePaint().EqualTypeOrColor(b.StrokePaint()) &&
+ a.InternalVisitedStrokePaint().EqualTypeOrColor(
+ b.InternalVisitedStrokePaint());
case CSSPropertyID::kStrokeDasharray:
return a.StrokeDashArray() == b.StrokeDashArray();
case CSSPropertyID::kStrokeDashoffset:
@@ -367,21 +361,21 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
case CSSPropertyID::kWordSpacing:
return a.WordSpacing() == b.WordSpacing();
case CSSPropertyID::kD:
- return DataEquivalent(a.SvgStyle().D(), b.SvgStyle().D());
+ return DataEquivalent(a.D(), b.D());
case CSSPropertyID::kCx:
- return a.SvgStyle().Cx() == b.SvgStyle().Cx();
+ return a.Cx() == b.Cx();
case CSSPropertyID::kCy:
- return a.SvgStyle().Cy() == b.SvgStyle().Cy();
+ return a.Cy() == b.Cy();
case CSSPropertyID::kX:
- return a.SvgStyle().X() == b.SvgStyle().X();
+ return a.X() == b.X();
case CSSPropertyID::kY:
- return a.SvgStyle().Y() == b.SvgStyle().Y();
+ return a.Y() == b.Y();
case CSSPropertyID::kR:
- return a.SvgStyle().R() == b.SvgStyle().R();
+ return a.R() == b.R();
case CSSPropertyID::kRx:
- return a.SvgStyle().Rx() == b.SvgStyle().Rx();
+ return a.Rx() == b.Rx();
case CSSPropertyID::kRy:
- return a.SvgStyle().Ry() == b.SvgStyle().Ry();
+ return a.Ry() == b.Ry();
case CSSPropertyID::kZIndex:
return a.HasAutoZIndex() == b.HasAutoZIndex() &&
(a.HasAutoZIndex() || a.ZIndex() == b.ZIndex());
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_id_templates.h b/chromium/third_party/blink/renderer/core/css/css_property_id_templates.h
index a510c18fb61..f754d70792e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_id_templates.h
+++ b/chromium/third_party/blink/renderer/core/css/css_property_id_templates.h
@@ -15,10 +15,10 @@ struct HashTraits<blink::CSSPropertyID>
: GenericHashTraits<blink::CSSPropertyID> {
static const bool kEmptyValueIsZero = true;
static void ConstructDeletedValue(blink::CSSPropertyID& slot, bool) {
- slot = static_cast<blink::CSSPropertyID>(blink::numCSSPropertyIDs);
+ slot = static_cast<blink::CSSPropertyID>(blink::kNumCSSPropertyIDs);
}
static bool IsDeletedValue(blink::CSSPropertyID value) {
- return static_cast<int>(value) == blink::numCSSPropertyIDs;
+ return static_cast<int>(value) == blink::kNumCSSPropertyIDs;
}
};
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_name.h b/chromium/third_party/blink/renderer/core/css/css_property_name.h
index e8f7a46a250..d902dc6f7fc 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_name.h
+++ b/chromium/third_party/blink/renderer/core/css/css_property_name.h
@@ -34,7 +34,7 @@ class CORE_EXPORT CSSPropertyName {
static base::Optional<CSSPropertyName> From(
const ExecutionContext* execution_context,
const String& value) {
- const CSSPropertyID property_id = cssPropertyID(execution_context, value);
+ const CSSPropertyID property_id = CssPropertyID(execution_context, value);
if (property_id == CSSPropertyID::kInvalid)
return base::nullopt;
if (property_id == CSSPropertyID::kVariable)
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_value.cc b/chromium/third_party/blink/renderer/core/css/css_property_value.cc
index d27353e4463..bb4c818dcdb 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_property_value.cc
@@ -64,7 +64,7 @@ CSSPropertyID CSSPropertyValueMetadata::ShorthandID() const {
}
CSSPropertyID CSSPropertyValueMetadata::PropertyID() const {
- return convertToCSSPropertyID(property_id_);
+ return ConvertToCSSPropertyID(property_id_);
}
CSSPropertyName CSSPropertyValueMetadata::Name() const {
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_value_set.cc b/chromium/third_party/blink/renderer/core/css/css_property_value_set.cc
index ee5fccddafd..7141f4ef739 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_value_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_property_value_set.cc
@@ -81,8 +81,14 @@ MutableCSSPropertyValueSet::MutableCSSPropertyValueSet(
unsigned length)
: CSSPropertyValueSet(kHTMLStandardMode) {
property_vector_.ReserveInitialCapacity(length);
- for (unsigned i = 0; i < length; ++i)
+ for (unsigned i = 0; i < length; ++i) {
property_vector_.UncheckedAppend(properties[i]);
+ if (!may_have_logical_properties_) {
+ const CSSProperty& prop = CSSProperty::Get(properties[i].Id());
+ may_have_logical_properties_ =
+ prop.IsInLogicalPropertyGroup() && prop.IsSurrogate();
+ }
+ }
}
ImmutableCSSPropertyValueSet::ImmutableCSSPropertyValueSet(
@@ -126,7 +132,7 @@ static bool IsPropertyMatch(const CSSPropertyValueMetadata& metadata,
// TODO(hjkim3323@gmail.com): Remove kInternalFontSizeDelta bypassing hack
#if DCHECK_IS_ON()
DCHECK(!result || property_id == CSSPropertyID::kInternalFontSizeDelta ||
- CSSProperty::Get(resolveCSSPropertyID(property_id)).IsWebExposed());
+ CSSProperty::Get(ResolveCSSPropertyID(property_id)).IsWebExposed());
#endif
return result;
}
@@ -180,12 +186,19 @@ MutableCSSPropertyValueSet::MutableCSSPropertyValueSet(
if (auto* other_mutable_property_set =
DynamicTo<MutableCSSPropertyValueSet>(other)) {
property_vector_ = other_mutable_property_set->property_vector_;
+ may_have_logical_properties_ =
+ other_mutable_property_set->may_have_logical_properties_;
} else {
property_vector_.ReserveInitialCapacity(other.PropertyCount());
for (unsigned i = 0; i < other.PropertyCount(); ++i) {
PropertyReference property = other.PropertyAt(i);
property_vector_.UncheckedAppend(
CSSPropertyValue(property.PropertyMetadata(), property.Value()));
+ if (!may_have_logical_properties_) {
+ const CSSProperty& prop = CSSProperty::Get(property.Id());
+ may_have_logical_properties_ =
+ prop.IsInLogicalPropertyGroup() && prop.IsSurrogate();
+ }
}
}
}
@@ -356,14 +369,14 @@ MutableCSSPropertyValueSet::SetResult MutableCSSPropertyValueSet::SetProperty(
bool important,
SecureContextMode secure_context_mode,
StyleSheetContents* context_style_sheet) {
- DCHECK_GE(unresolved_property, firstCSSProperty);
+ DCHECK_GE(unresolved_property, kFirstCSSProperty);
// Setting the value to an empty string just removes the property in both IE
// and Gecko. Setting it to null seems to produce less consistent results, but
// we treat it just the same.
if (value.IsEmpty()) {
bool did_parse = true;
- bool did_change = RemoveProperty(resolveCSSPropertyID(unresolved_property));
+ bool did_change = RemoveProperty(ResolveCSSPropertyID(unresolved_property));
return SetResult{did_parse, did_change};
}
@@ -417,11 +430,32 @@ bool MutableCSSPropertyValueSet::SetProperty(const CSSPropertyValue& property,
CSSPropertyValue* slot) {
CSSPropertyValue* to_replace =
slot ? slot : FindCSSPropertyWithName(property.Name());
- if (to_replace && *to_replace == property)
- return false;
if (to_replace) {
- *to_replace = property;
- return true;
+ if (may_have_logical_properties_) {
+ const CSSProperty& prop = CSSProperty::Get(property.Id());
+ if (prop.IsInLogicalPropertyGroup()) {
+ DCHECK(property_vector_.Contains(*to_replace));
+ int to_replace_index = to_replace - property_vector_.begin();
+ for (int n = property_vector_.size() - 1; n > to_replace_index; --n) {
+ if (prop.IsInSameLogicalPropertyGroupWithDifferentMappingLogic(
+ PropertyAt(n).Id())) {
+ RemovePropertyAtIndex(to_replace_index, nullptr);
+ to_replace = nullptr;
+ break;
+ }
+ }
+ }
+ }
+ if (to_replace) {
+ if (*to_replace == property)
+ return false;
+ *to_replace = property;
+ return true;
+ }
+ } else if (!may_have_logical_properties_) {
+ const CSSProperty& prop = CSSProperty::Get(property.Id());
+ may_have_logical_properties_ =
+ prop.IsInLogicalPropertyGroup() && prop.IsSurrogate();
}
property_vector_.push_back(property);
return true;
@@ -503,6 +537,7 @@ bool CSSPropertyValueSet::HasFailedOrCanceledSubresources() const {
void MutableCSSPropertyValueSet::Clear() {
property_vector_.clear();
+ may_have_logical_properties_ = false;
}
inline bool ContainsId(const CSSProperty* const set[],
diff --git a/chromium/third_party/blink/renderer/core/css/css_property_value_set.h b/chromium/third_party/blink/renderer/core/css/css_property_value_set.h
index 07aa92cfa3e..701682d8db5 100644
--- a/chromium/third_party/blink/renderer/core/css/css_property_value_set.h
+++ b/chromium/third_party/blink/renderer/core/css/css_property_value_set.h
@@ -298,6 +298,7 @@ class CORE_EXPORT MutableCSSPropertyValueSet : public CSSPropertyValueSet {
friend class CSSPropertyValueSet;
HeapVector<CSSPropertyValue, 4> property_vector_;
+ bool may_have_logical_properties_{false};
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/css/css_revert_value.h b/chromium/third_party/blink/renderer/core/css/css_revert_value.h
index b3dd5a8f721..0fadc4f714e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_revert_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_revert_value.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_REVERT_VALUE_H_
#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -20,7 +20,7 @@ class CORE_EXPORT CSSRevertValue : public CSSValue {
public:
static CSSRevertValue* Create();
- explicit CSSRevertValue(util::PassKey<CSSValuePool>)
+ explicit CSSRevertValue(base::PassKey<CSSValuePool>)
: CSSValue(kRevertClass) {}
String CustomCSSText() const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_rule.h b/chromium/third_party/blink/renderer/core/css/css_rule.h
index 7c7d76c19ec..5b274b1f48a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/css_rule.h
@@ -64,6 +64,7 @@ class CORE_EXPORT CSSRule : public ScriptWrappable {
// Values for internal use, not web-exposed:
kPropertyRule = 16,
kScrollTimelineRule = 17,
+ kContainerRule = 18,
};
virtual Type GetType() const = 0;
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector.cc b/chromium/third_party/blink/renderer/core/css/css_selector.cc
index eae5a8d14be..d760031781d 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_selector.cc
@@ -245,6 +245,10 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
return kPseudoIdResizer;
case kPseudoTargetText:
return kPseudoIdTargetText;
+ case kPseudoSpellingError:
+ return kPseudoIdSpellingError;
+ case kPseudoGrammarError:
+ return kPseudoIdGrammarError;
case kPseudoUnknown:
case kPseudoEmpty:
case kPseudoFirstChild:
@@ -281,6 +285,7 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
case kPseudoOptional:
case kPseudoPlaceholder:
case kPseudoPlaceholderShown:
+ case kPseudoFileSelectorButton:
case kPseudoRequired:
case kPseudoReadOnly:
case kPseudoReadWrite:
@@ -289,6 +294,7 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
case kPseudoIndeterminate:
case kPseudoTarget:
case kPseudoLang:
+ case kPseudoDir:
case kPseudoNot:
case kPseudoRoot:
case kPseudoScope:
@@ -313,14 +319,11 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
case kPseudoCue:
case kPseudoFutureCue:
case kPseudoPastCue:
- case kPseudoUnresolved:
case kPseudoDefined:
- case kPseudoContent:
case kPseudoHost:
case kPseudoHostContext:
case kPseudoPart:
case kPseudoState:
- case kPseudoShadow:
case kPseudoFullScreen:
case kPseudoFullScreenAncestor:
case kPseudoFullscreen:
@@ -332,6 +335,7 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
case kPseudoListBox:
case kPseudoMultiSelectFocus:
case kPseudoHostHasAppearance:
+ case kPseudoPopupOpen:
case kPseudoSlotted:
case kPseudoVideoPersistent:
case kPseudoVideoPersistentAncestor:
@@ -363,6 +367,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
CSSSelector::kPseudoWebKitCustomElement},
{"-internal-modal", CSSSelector::kPseudoModal},
{"-internal-multi-select-focus", CSSSelector::kPseudoMultiSelectFocus},
+ {"-internal-popup-open", CSSSelector::kPseudoPopupOpen},
{"-internal-shadow-host-has-appearance",
CSSSelector::kPseudoHostHasAppearance},
{"-internal-spatial-navigation-focus",
@@ -391,7 +396,6 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"backdrop", CSSSelector::kPseudoBackdrop},
{"before", CSSSelector::kPseudoBefore},
{"checked", CSSSelector::kPseudoChecked},
- {"content", CSSSelector::kPseudoContent},
{"corner-present", CSSSelector::kPseudoCornerPresent},
{"cue", CSSSelector::kPseudoWebKitCustomElement},
{"decrement", CSSSelector::kPseudoDecrement},
@@ -402,6 +406,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"empty", CSSSelector::kPseudoEmpty},
{"enabled", CSSSelector::kPseudoEnabled},
{"end", CSSSelector::kPseudoEnd},
+ {"file-selector-button", CSSSelector::kPseudoFileSelectorButton},
{"first", CSSSelector::kPseudoFirstPage},
{"first-child", CSSSelector::kPseudoFirstChild},
{"first-letter", CSSSelector::kPseudoFirstLetter},
@@ -412,6 +417,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"focus-within", CSSSelector::kPseudoFocusWithin},
{"fullscreen", CSSSelector::kPseudoFullscreen},
{"future", CSSSelector::kPseudoFutureCue},
+ {"grammar-error", CSSSelector::kPseudoGrammarError},
{"horizontal", CSSSelector::kPseudoHorizontal},
{"host", CSSSelector::kPseudoHost},
{"hover", CSSSelector::kPseudoHover},
@@ -440,12 +446,11 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"root", CSSSelector::kPseudoRoot},
{"scope", CSSSelector::kPseudoScope},
{"selection", CSSSelector::kPseudoSelection},
- {"shadow", CSSSelector::kPseudoShadow},
{"single-button", CSSSelector::kPseudoSingleButton},
+ {"spelling-error", CSSSelector::kPseudoSpellingError},
{"start", CSSSelector::kPseudoStart},
{"target", CSSSelector::kPseudoTarget},
{"target-text", CSSSelector::kPseudoTargetText},
- {"unresolved", CSSSelector::kPseudoUnresolved},
{"valid", CSSSelector::kPseudoValid},
{"vertical", CSSSelector::kPseudoVertical},
{"visited", CSSSelector::kPseudoVisited},
@@ -456,6 +461,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
const static NameToPseudoStruct kPseudoTypeWithArgumentsMap[] = {
{"-webkit-any", CSSSelector::kPseudoAny},
{"cue", CSSSelector::kPseudoCue},
+ {"dir", CSSSelector::kPseudoDir},
{"host", CSSSelector::kPseudoHost},
{"host-context", CSSSelector::kPseudoHostContext},
{"is", CSSSelector::kPseudoIs},
@@ -467,7 +473,6 @@ const static NameToPseudoStruct kPseudoTypeWithArgumentsMap[] = {
{"nth-of-type", CSSSelector::kPseudoNthOfType},
{"part", CSSSelector::kPseudoPart},
{"slotted", CSSSelector::kPseudoSlotted},
- {"state", CSSSelector::kPseudoState},
{"where", CSSSelector::kPseudoWhere},
};
@@ -501,6 +506,10 @@ static CSSSelector::PseudoType NameToPseudoType(const AtomicString& name,
if (match == pseudo_type_map_end || match->string != name.GetString())
return CSSSelector::kPseudoUnknown;
+ if (match->type == CSSSelector::kPseudoDir &&
+ !RuntimeEnabledFeatures::CSSPseudoDirEnabled())
+ return CSSSelector::kPseudoUnknown;
+
if (match->type == CSSSelector::kPseudoFocusVisible &&
!RuntimeEnabledFeatures::CSSFocusVisibleEnabled())
return CSSSelector::kPseudoUnknown;
@@ -509,13 +518,14 @@ static CSSSelector::PseudoType NameToPseudoType(const AtomicString& name,
!RuntimeEnabledFeatures::CSSPictureInPictureEnabled())
return CSSSelector::kPseudoUnknown;
- if (match->type == CSSSelector::kPseudoState &&
- !RuntimeEnabledFeatures::CustomStatePseudoClassEnabled()) {
+ if (match->type == CSSSelector::kPseudoTargetText &&
+ !RuntimeEnabledFeatures::CSSTargetTextPseudoElementEnabled()) {
return CSSSelector::kPseudoUnknown;
}
- if (match->type == CSSSelector::kPseudoTargetText &&
- !RuntimeEnabledFeatures::CSSTargetTextPseudoElementEnabled()) {
+ if ((match->type == CSSSelector::kPseudoSpellingError ||
+ match->type == CSSSelector::kPseudoGrammarError) &&
+ !RuntimeEnabledFeatures::CSSSpellingGrammarErrorsEnabled()) {
return CSSSelector::kPseudoUnknown;
}
@@ -566,6 +576,9 @@ CSSSelector::PseudoType CSSSelector::ParsePseudoType(const AtomicString& name,
return kPseudoWebKitCustomElement;
if (name.StartsWith("-internal-"))
return kPseudoBlinkInternalElement;
+ if (RuntimeEnabledFeatures::CustomStatePseudoClassEnabled() &&
+ name.StartsWith("--"))
+ return kPseudoState;
return kPseudoUnknown;
}
@@ -596,8 +609,10 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
bool has_arguments,
CSSParserMode mode) {
DCHECK(match_ == kPseudoClass || match_ == kPseudoElement);
- SetValue(value);
- SetPseudoType(ParsePseudoType(value, has_arguments));
+ AtomicString lower_value = value.LowerASCII();
+ PseudoType pseudo_type = ParsePseudoType(lower_value, has_arguments);
+ SetPseudoType(pseudo_type);
+ SetValue(pseudo_type == kPseudoState ? value : lower_value);
switch (GetPseudoType()) {
case kPseudoAfter:
@@ -616,6 +631,7 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoMarker:
case kPseudoPart:
case kPseudoPlaceholder:
+ case kPseudoFileSelectorButton:
case kPseudoResizer:
case kPseudoScrollbar:
case kPseudoScrollbarCorner:
@@ -625,16 +641,13 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoScrollbarTrackPiece:
case kPseudoSelection:
case kPseudoWebKitCustomElement:
- case kPseudoContent:
case kPseudoSlotted:
case kPseudoTargetText:
+ case kPseudoSpellingError:
+ case kPseudoGrammarError:
if (match_ != kPseudoElement)
pseudo_type_ = kPseudoUnknown;
break;
- case kPseudoShadow:
- if (match_ != kPseudoElement || context.IsLiveProfile())
- pseudo_type_ = kPseudoUnknown;
- break;
case kPseudoBlinkInternalElement:
if (match_ != kPseudoElement || mode != kUASheetMode)
pseudo_type_ = kPseudoUnknown;
@@ -645,6 +658,7 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoListBox:
case kPseudoModal:
case kPseudoMultiSelectFocus:
+ case kPseudoPopupOpen:
case kPseudoSpatialNavigationFocus:
case kPseudoSpatialNavigationInterest:
case kPseudoVideoPersistent:
@@ -667,6 +681,7 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoDefault:
case kPseudoDefined:
case kPseudoDisabled:
+ case kPseudoDir:
case kPseudoDoubleButton:
case kPseudoDrag:
case kPseudoEmpty:
@@ -733,10 +748,6 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoRightPage:
pseudo_type_ = kPseudoUnknown;
break;
- case kPseudoUnresolved:
- if (match_ != kPseudoClass || !context.CustomElementsV0Enabled())
- pseudo_type_ = kPseudoUnknown;
- break;
}
}
@@ -804,8 +815,10 @@ const CSSSelector* CSSSelector::SerializeCompound(
SerializeIdentifier(simple_selector->SerializingValue(), builder);
} else if (simple_selector->match_ == kPseudoClass ||
simple_selector->match_ == kPagePseudoClass) {
- builder.Append(':');
- builder.Append(simple_selector->SerializingValue());
+ if (simple_selector->GetPseudoType() != kPseudoState) {
+ builder.Append(':');
+ builder.Append(simple_selector->SerializingValue());
+ }
switch (simple_selector->GetPseudoType()) {
case kPseudoNthChild:
@@ -836,8 +849,8 @@ const CSSSelector* CSSSelector::SerializeCompound(
builder.Append(')');
break;
}
+ case kPseudoDir:
case kPseudoLang:
- case kPseudoState:
builder.Append('(');
SerializeIdentifier(simple_selector->Argument(), builder);
builder.Append(')');
@@ -845,6 +858,10 @@ const CSSSelector* CSSSelector::SerializeCompound(
case kPseudoNot:
DCHECK(simple_selector->SelectorList());
break;
+ case kPseudoState:
+ builder.Append(':');
+ SerializeIdentifier(simple_selector->SerializingValue(), builder);
+ break;
case kPseudoHost:
case kPseudoHostContext:
case kPseudoAny:
@@ -907,8 +924,13 @@ const CSSSelector* CSSSelector::SerializeCompound(
if (simple_selector->match_ != kAttributeSet) {
SerializeString(simple_selector->SerializingValue(), builder);
if (simple_selector->AttributeMatch() ==
- AttributeMatchType::kCaseInsensitive)
+ AttributeMatchType::kCaseInsensitive) {
builder.Append(" i");
+ } else if (simple_selector->AttributeMatch() ==
+ AttributeMatchType::kCaseSensitiveAlways) {
+ DCHECK(RuntimeEnabledFeatures::CSSCaseSensitiveSelectorEnabled());
+ builder.Append(" s");
+ }
builder.Append(']');
}
}
@@ -949,10 +971,6 @@ String CSSSelector::SelectorText() const {
case kChild:
result = " > " + builder.ToString() + result;
break;
- case kShadowDeep:
- case kShadowDeepAsDescendant:
- result = " /deep/ " + builder.ToString() + result;
- break;
case kDirectAdjacent:
result = " + " + builder.ToString() + result;
break;
@@ -963,7 +981,7 @@ String CSSSelector::SelectorText() const {
NOTREACHED();
break;
case kShadowPart:
- case kShadowPseudo:
+ case kUAShadow:
case kShadowSlot:
result = builder.ToString() + result;
break;
@@ -1110,7 +1128,8 @@ bool CSSSelector::IsTreeAbidingPseudoElement() const {
return Match() == CSSSelector::kPseudoElement &&
(GetPseudoType() == kPseudoBefore || GetPseudoType() == kPseudoAfter ||
GetPseudoType() == kPseudoMarker ||
- GetPseudoType() == kPseudoPlaceholder);
+ GetPseudoType() == kPseudoPlaceholder ||
+ GetPseudoType() == kPseudoFileSelectorButton);
}
bool CSSSelector::IsAllowedAfterPart() const {
@@ -1123,10 +1142,13 @@ bool CSSSelector::IsAllowedAfterPart() const {
case kPseudoBefore:
case kPseudoAfter:
case kPseudoPlaceholder:
+ case kPseudoFileSelectorButton:
case kPseudoFirstLine:
case kPseudoFirstLetter:
case kPseudoSelection:
case kPseudoTargetText:
+ case kPseudoSpellingError:
+ case kPseudoGrammarError:
return true;
default:
return false;
@@ -1152,14 +1174,6 @@ static bool ForAnyInTagHistory(const Functor& functor,
return false;
}
-bool CSSSelector::HasContentPseudo() const {
- return ForAnyInTagHistory(
- [](const CSSSelector& selector) -> bool {
- return selector.RelationIsAffectedByPseudoContent();
- },
- *this);
-}
-
bool CSSSelector::HasSlottedPseudo() const {
return ForAnyInTagHistory(
[](const CSSSelector& selector) -> bool {
@@ -1168,15 +1182,6 @@ bool CSSSelector::HasSlottedPseudo() const {
*this);
}
-bool CSSSelector::HasDeepCombinatorOrShadowPseudo() const {
- return ForAnyInTagHistory(
- [](const CSSSelector& selector) -> bool {
- return selector.Relation() == CSSSelector::kShadowDeep ||
- selector.GetPseudoType() == CSSSelector::kPseudoShadow;
- },
- *this);
-}
-
bool CSSSelector::FollowsPart() const {
const CSSSelector* previous = TagHistory();
if (!previous)
@@ -1184,15 +1189,6 @@ bool CSSSelector::FollowsPart() const {
return previous->GetPseudoType() == kPseudoPart;
}
-bool CSSSelector::NeedsUpdatedDistribution() const {
- return ForAnyInTagHistory(
- [](const CSSSelector& selector) -> bool {
- return selector.RelationIsAffectedByPseudoContent() ||
- selector.GetPseudoType() == CSSSelector::kPseudoHostContext;
- },
- *this);
-}
-
String CSSSelector::FormatPseudoTypeForDebugging(PseudoType type) {
for (const auto& s : kPseudoTypeWithoutArgumentsMap) {
if (s.type == type)
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector.h b/chromium/third_party/blink/renderer/core/css/css_selector.h
index f92f728b10f..fdb0de38d7b 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/css_selector.h
@@ -62,10 +62,8 @@ class Node;
// (http://www.w3.org/TR/css3-selectors/#combinators), such as descendant,
// sibling, etc., are parsed right-to-left (in the example above, this is why
// #c is earlier in the tagHistory() chain than .a.b).
-// * SubSelector relations are parsed left-to-right in most cases (such as the
-// .a.b example above); a counter-example is the
-// ::content pseudo-element. Most (all?) other pseudo elements and pseudo
-// classes are parsed left-to-right.
+// * SubSelector relations are parsed left-to-right, such as the .a.b example
+// above.
// * ShadowPseudo relations are parsed right-to-left. Example:
// summary::-webkit-details-marker is parsed as: selectorText():
// summary::-webkit-details-marker --> (relation == ShadowPseudo)
@@ -146,17 +144,33 @@ class CORE_EXPORT CSSSelector {
};
enum RelationType {
- kSubSelector, // No combinator
- kDescendant, // "Space" combinator
- kChild, // > combinator
- kDirectAdjacent, // + combinator
- kIndirectAdjacent, // ~ combinator
- // Special cases for shadow DOM related selectors.
- kShadowDeep, // /deep/ combinator
- kShadowDeepAsDescendant, // /deep/ as an alias for descendant
- kShadowPseudo, // ::shadow pseudo element
- kShadowSlot, // ::slotted() pseudo element
- kShadowPart, // ::part() pseudo element
+ // No combinator. Used between simple selectors within the same compound.
+ kSubSelector,
+ // "Space" combinator
+ kDescendant,
+ // > combinator
+ kChild,
+ // + combinator
+ kDirectAdjacent,
+ // ~ combinator
+ kIndirectAdjacent,
+ // The relation types below are implicit combinators inserted at parse time
+ // before pseudo elements which match another flat tree element than the
+ // rest of the compound.
+ //
+ // Implicit combinator inserted before pseudo elements matching an element
+ // inside a UA shadow tree. This combinator allows the selector matching to
+ // cross a shadow root.
+ //
+ // Examples:
+ // input::placeholder, video::cue(i), video::--webkit-media-controls-panel
+ kUAShadow,
+ // Implicit combinator inserted before ::slotted() selectors.
+ kShadowSlot,
+ // Implicit combinator inserted before ::part() selectors which allows
+ // matching a ::part in shadow-including descendant tree for #host in
+ // "#host::part(button)".
+ kShadowPart,
};
enum PseudoType {
@@ -214,6 +228,7 @@ class CORE_EXPORT CSSSelector {
kPseudoLang,
kPseudoNot,
kPseudoPlaceholder,
+ kPseudoFileSelectorButton,
kPseudoResizer,
kPseudoRoot,
kPseudoScope,
@@ -255,28 +270,30 @@ class CORE_EXPORT CSSSelector {
kPseudoCue,
kPseudoFutureCue,
kPseudoPastCue,
- kPseudoUnresolved,
kPseudoDefined,
- kPseudoContent,
kPseudoHasDatalist,
kPseudoHost,
kPseudoHostContext,
- kPseudoShadow,
kPseudoSpatialNavigationFocus,
kPseudoSpatialNavigationInterest,
kPseudoIsHtml,
kPseudoListBox,
kPseudoMultiSelectFocus,
kPseudoHostHasAppearance,
+ kPseudoPopupOpen,
kPseudoSlotted,
kPseudoVideoPersistent,
kPseudoVideoPersistentAncestor,
kPseudoTargetText,
+ kPseudoDir,
+ kPseudoSpellingError,
+ kPseudoGrammarError,
};
enum class AttributeMatchType {
kCaseSensitive,
kCaseInsensitive,
+ kCaseSensitiveAlways,
};
PseudoType GetPseudoType() const {
@@ -343,9 +360,7 @@ class CORE_EXPORT CSSSelector {
bool IsAdjacentSelector() const {
return relation_ == kDirectAdjacent || relation_ == kIndirectAdjacent;
}
- bool IsShadowSelector() const {
- return relation_ == kShadowPseudo || relation_ == kShadowDeep;
- }
+ bool IsUAShadowSelector() const { return relation_ == kUAShadow; }
bool IsAttributeSelector() const {
return match_ >= kFirstAttributeSelectorMatch;
}
@@ -353,9 +368,6 @@ class CORE_EXPORT CSSSelector {
return pseudo_type_ == kPseudoHost || pseudo_type_ == kPseudoHostContext;
}
bool IsUserActionPseudoClass() const;
- bool IsV0InsertionPointCrossing() const {
- return pseudo_type_ == kPseudoHostContext || pseudo_type_ == kPseudoContent;
- }
bool IsIdClassOrAttributeSelector() const;
RelationType Relation() const { return static_cast<RelationType>(relation_); }
@@ -400,23 +412,13 @@ class CORE_EXPORT CSSSelector {
bool IsForPage() const { return is_for_page_; }
void SetForPage() { is_for_page_ = true; }
- bool RelationIsAffectedByPseudoContent() const {
- return relation_is_affected_by_pseudo_content_;
- }
- void SetRelationIsAffectedByPseudoContent() {
- relation_is_affected_by_pseudo_content_ = true;
- }
-
bool MatchesPseudoElement() const;
bool IsTreeAbidingPseudoElement() const;
bool IsAllowedAfterPart() const;
- bool HasContentPseudo() const;
bool HasSlottedPseudo() const;
- bool HasDeepCombinatorOrShadowPseudo() const;
// Returns true if the immediately preceeding simple selector is ::part.
bool FollowsPart() const;
- bool NeedsUpdatedDistribution() const;
static String FormatPseudoTypeForDebugging(PseudoType);
@@ -429,7 +431,6 @@ class CORE_EXPORT CSSSelector {
unsigned has_rare_data_ : 1;
unsigned is_for_page_ : 1;
unsigned tag_is_implicit_ : 1;
- unsigned relation_is_affected_by_pseudo_content_ : 1;
unsigned is_last_in_original_list_ : 1;
void SetPseudoType(PseudoType pseudo_type) {
@@ -556,7 +557,6 @@ inline CSSSelector::CSSSelector()
has_rare_data_(false),
is_for_page_(false),
tag_is_implicit_(false),
- relation_is_affected_by_pseudo_content_(false),
is_last_in_original_list_(false),
data_(DataUnion::kConstructEmptyValue) {}
@@ -570,7 +570,6 @@ inline CSSSelector::CSSSelector(const QualifiedName& tag_q_name,
has_rare_data_(false),
is_for_page_(false),
tag_is_implicit_(tag_is_implicit),
- relation_is_affected_by_pseudo_content_(false),
is_last_in_original_list_(false),
data_(tag_q_name) {}
@@ -583,8 +582,6 @@ inline CSSSelector::CSSSelector(const CSSSelector& o)
has_rare_data_(o.has_rare_data_),
is_for_page_(o.is_for_page_),
tag_is_implicit_(o.tag_is_implicit_),
- relation_is_affected_by_pseudo_content_(
- o.relation_is_affected_by_pseudo_content_),
is_last_in_original_list_(o.is_last_in_original_list_),
data_(DataUnion::kConstructUninitialized) {
if (o.match_ == kTag) {
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector_list.cc b/chromium/third_party/blink/renderer/core/css/css_selector_list.cc
index e0f60be8309..df2c8e7466e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector_list.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_selector_list.cc
@@ -42,48 +42,6 @@ namespace {
// in official builds.
const char kCSSSelectorTypeName[] = "blink::CSSSelector";
-// See CSSSelectorList::TreatAsNonComplexArgumentToNot.
-//
-// Note that there is no need to keep this function up to date (e.g. add new
-// pseudo-classes etc), as this is only used to determine if ShadowDOM v0
-// features should be allowed in combination with :not(), and new selector
-// features should generally _not_ be allowed to work with ShadowDOM v0.
-//
-// TODO(crbug.com/937746): Remove this when ShadowDOM v0 is removed.
-bool TreatAsNonComplexArgumentToNot(const CSSSelector* selector) {
- if (!selector)
- return false;
-
- if (selector->SelectorList()) {
- switch (selector->GetPseudoType()) {
- case CSSSelector::kPseudoIs:
- case CSSSelector::kPseudoWhere:
- break;
- default:
- return false;
- }
- }
-
- if (selector->Match() == CSSSelector::kPseudoElement)
- return false;
-
- if (!selector->TagHistory())
- return true;
-
- if (selector->Match() == CSSSelector::kTag) {
- // We can't check against anyQName() here because namespace may not be
- // g_null_atom.
- // Example:
- // @namespace "http://www.w3.org/2000/svg";
- // svg:not(:root) { ...
- if (selector->TagQName().LocalName() ==
- CSSSelector::UniversalSelectorAtom())
- return TreatAsNonComplexArgumentToNot(selector->TagHistory());
- }
-
- return false;
-}
-
} // namespace
CSSSelectorList CSSSelectorList::Copy() const {
@@ -162,10 +120,6 @@ unsigned CSSSelectorList::ComputeLength() const {
return static_cast<unsigned>(current - selector_array_) + 1;
}
-bool CSSSelectorList::TreatAsNonComplexArgumentToNot() const {
- return blink::TreatAsNonComplexArgumentToNot(First()) && !Next(*First());
-}
-
void CSSSelectorList::DeleteSelectors() {
DCHECK(selector_array_);
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector_list.h b/chromium/third_party/blink/renderer/core/css/css_selector_list.h
index 91119ceac0d..26d3347883a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector_list.h
+++ b/chromium/third_party/blink/renderer/core/css/css_selector_list.h
@@ -117,20 +117,6 @@ class CORE_EXPORT CSSSelectorList {
// avoided when possible. Instead iterate from first() and using next().
unsigned ComputeLength() const;
- // To reduce complexity, we generally do not support ShadowDOM v0 features
- // and the :not() pseudo class in the same selector. However, for backwards
- // compatibility, we support this anyway when :not()'s argument is a single
- // selector that's "sufficiently simple".
- //
- // This function returns true when the selector list is "sufficiently simple",
- // in which case ShadowDOM v0 features will be allowed.
- //
- // See SelectorCheckingContext.in_nested_complex_selector (and how it's
- // used) for more information.
- //
- // TODO(crbug.com/937746): Remove this when ShadowDOM v0 is removed.
- bool TreatAsNonComplexArgumentToNot() const;
-
private:
void DeleteSelectorsIfNeeded() {
if (selector_array_)
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector_test.cc b/chromium/third_party/blink/renderer/core/css/css_selector_test.cc
index 21e8a9bda28..777fabc120b 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_selector_test.cc
@@ -45,7 +45,6 @@ TEST(CSSSelector, Representations) {
"#id.class { }"
"[attr]#id { }"
"div[attr]#id { }"
- "div::content { }"
"div::first-line { }"
".a.b.c { }"
"div:not(.a) { }" // without class a
@@ -67,7 +66,7 @@ TEST(CSSSelector, Representations) {
".a.b .c {}";
sheet.AddCSSRules(css_rules);
- EXPECT_EQ(30u,
+ EXPECT_EQ(29u,
sheet.GetRuleSet().RuleCount()); // .a, .b counts as two rules.
#ifndef NDEBUG
sheet.GetRuleSet().Show();
@@ -166,4 +165,25 @@ TEST(CSSSelector, HasLinkOrVisited) {
EXPECT_TRUE(HasLinkOrVisited(":host-context(:link)"));
}
+TEST(CSSSelector, CueDefaultNamespace) {
+ css_test_helpers::TestStyleSheet sheet;
+
+ sheet.AddCSSRules(R"HTML(
+ @namespace "http://www.w3.org/1999/xhtml";
+ video::cue(b) {}
+ )HTML");
+
+ const CSSSelector& cue_selector =
+ (*sheet.GetRuleSet().CuePseudoRules())[0]->Selector();
+ EXPECT_EQ(cue_selector.GetPseudoType(), CSSSelector::kPseudoCue);
+
+ const CSSSelectorList* cue_arguments = cue_selector.SelectorList();
+ ASSERT_TRUE(cue_arguments);
+ const CSSSelector* vtt_type_selector = cue_arguments->First();
+ ASSERT_TRUE(vtt_type_selector);
+ EXPECT_EQ(vtt_type_selector->TagQName().LocalName(), "b");
+ // Default namespace should not affect VTT node type selector.
+ EXPECT_EQ(vtt_type_selector->TagQName().NamespaceURI(), g_star_atom);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector_watch.cc b/chromium/third_party/blink/renderer/core/css/css_selector_watch.cc
index efb35dcaad3..ef245aba8e4 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector_watch.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_selector_watch.cc
@@ -173,6 +173,7 @@ void CSSSelectorWatch::WatchCSSSelectors(const Vector<String>& selectors) {
void CSSSelectorWatch::Trace(Visitor* visitor) const {
visitor->Trace(watched_callback_selectors_);
+ visitor->Trace(callback_selector_change_timer_);
Supplement<Document>::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_selector_watch.h b/chromium/third_party/blink/renderer/core/css/css_selector_watch.h
index 484d82717f5..df66e8db24e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_selector_watch.h
+++ b/chromium/third_party/blink/renderer/core/css/css_selector_watch.h
@@ -77,7 +77,7 @@ class CORE_EXPORT CSSSelectorWatch final
HashSet<String> added_selectors_;
HashSet<String> removed_selectors_;
- TaskRunnerTimer<CSSSelectorWatch> callback_selector_change_timer_;
+ HeapTaskRunnerTimer<CSSSelectorWatch> callback_selector_change_timer_;
// When an element is reparented, the new location's style is evaluated after
// the expriation of the relayout timer. We don't want to send redundant
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_declaration.cc b/chromium/third_party/blink/renderer/core/css/css_style_declaration.cc
index 4d7b07c12cd..a03d278e36a 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_declaration.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_style_declaration.cc
@@ -118,7 +118,7 @@ CSSPropertyID ParseCSSPropertyID(const ExecutionContext* execution_context,
return CSSPropertyID::kInvalid;
String prop_name = builder.ToString();
- return unresolvedCSSPropertyID(execution_context, prop_name);
+ return UnresolvedCSSPropertyID(execution_context, prop_name);
}
// When getting properties on CSSStyleDeclarations, the name used from
@@ -143,8 +143,8 @@ CSSPropertyID CssPropertyInfo(const ExecutionContext* execution_context,
if (unresolved_property == CSSPropertyID::kVariable)
unresolved_property = CSSPropertyID::kInvalid;
map.insert(name, unresolved_property);
- DCHECK(!isValidCSSPropertyID(unresolved_property) ||
- CSSProperty::Get(resolveCSSPropertyID(unresolved_property))
+ DCHECK(!IsValidCSSPropertyID(unresolved_property) ||
+ CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
.IsWebExposed(execution_context));
return unresolved_property;
}
@@ -162,10 +162,10 @@ String CSSStyleDeclaration::AnonymousNamedGetter(const AtomicString& name) {
CssPropertyInfo(GetExecutionContext(), name);
// Do not handle non-property names.
- if (!isValidCSSPropertyID(unresolved_property))
+ if (!IsValidCSSPropertyID(unresolved_property))
return String();
- return GetPropertyValueInternal(resolveCSSPropertyID(unresolved_property));
+ return GetPropertyValueInternal(ResolveCSSPropertyID(unresolved_property));
}
NamedPropertySetterResult CSSStyleDeclaration::AnonymousNamedSetter(
@@ -177,7 +177,7 @@ NamedPropertySetterResult CSSStyleDeclaration::AnonymousNamedSetter(
if (!execution_context)
return NamedPropertySetterResult::kDidNotIntercept;
CSSPropertyID unresolved_property = CssPropertyInfo(execution_context, name);
- if (!isValidCSSPropertyID(unresolved_property))
+ if (!IsValidCSSPropertyID(unresolved_property))
return NamedPropertySetterResult::kDidNotIntercept;
// We create the ExceptionState manually due to performance issues: adding
// [RaisesException] to the IDL causes the bindings layer to expensively
@@ -186,7 +186,7 @@ NamedPropertySetterResult CSSStyleDeclaration::AnonymousNamedSetter(
ExceptionState exception_state(
script_state->GetIsolate(), ExceptionState::kSetterContext,
"CSSStyleDeclaration",
- CSSProperty::Get(resolveCSSPropertyID(unresolved_property))
+ CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
.GetPropertyName());
SetPropertyInternal(unresolved_property, String(), value, false,
execution_context->GetSecureContextMode(),
@@ -205,7 +205,7 @@ NamedPropertyDeleterResult CSSStyleDeclaration::AnonymousNamedDeleter(
void CSSStyleDeclaration::NamedPropertyEnumerator(Vector<String>& names,
ExceptionState&) {
- typedef Vector<String, numCSSProperties - 1> PreAllocatedPropertyVector;
+ typedef Vector<String, kNumCSSProperties - 1> PreAllocatedPropertyVector;
DEFINE_STATIC_LOCAL(PreAllocatedPropertyVector, property_names, ());
const ExecutionContext* execution_context = GetExecutionContext();
@@ -213,7 +213,7 @@ void CSSStyleDeclaration::NamedPropertyEnumerator(Vector<String>& names,
if (property_names.IsEmpty()) {
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property_class =
- CSSProperty::Get(resolveCSSPropertyID(property_id));
+ CSSProperty::Get(ResolveCSSPropertyID(property_id));
if (property_class.IsWebExposed(execution_context))
property_names.push_back(property_class.GetJSPropertyName());
}
@@ -231,7 +231,7 @@ void CSSStyleDeclaration::NamedPropertyEnumerator(Vector<String>& names,
bool CSSStyleDeclaration::NamedPropertyQuery(const AtomicString& name,
ExceptionState&) {
- return isValidCSSPropertyID(CssPropertyInfo(GetExecutionContext(), name));
+ return IsValidCSSPropertyID(CssPropertyInfo(GetExecutionContext(), name));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc b/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
index bdf00ae71b6..6fe597879f3 100644
--- a/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/html/html_style_element.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -137,9 +138,15 @@ CSSStyleSheet* CSSStyleSheet::CreateInline(Node& owner_node,
const KURL& base_url,
const TextPosition& start_position,
const WTF::TextEncoding& encoding) {
+ Document& owner_node_document = owner_node.GetDocument();
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
- owner_node.GetDocument(), owner_node.GetDocument().BaseURL(),
- true /* origin_clean */, owner_node.GetDocument().GetReferrerPolicy(),
+ owner_node_document, owner_node_document.BaseURL(),
+ true /* origin_clean */,
+ Referrer(
+ owner_node_document.GetExecutionContext()
+ ? owner_node_document.GetExecutionContext()->OutgoingReferrer()
+ : String(), // GetExecutionContext() only returns null in tests.
+ owner_node.GetDocument().GetReferrerPolicy()),
encoding);
if (AdTracker::IsAdScriptExecutingInDocument(&owner_node.GetDocument()))
parser_context->SetIsAdRelated();
diff --git a/chromium/third_party/blink/renderer/core/css/css_test_helpers.cc b/chromium/third_party/blink/renderer/core/css/css_test_helpers.cc
index 0cc4af0386a..46d5bba0855 100644
--- a/chromium/third_party/blink/renderer/core/css/css_test_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_test_helpers.cc
@@ -38,9 +38,7 @@ TestStyleSheet::~TestStyleSheet() = default;
TestStyleSheet::TestStyleSheet() {
document_ = Document::CreateForTest();
- TextPosition position;
- style_sheet_ = CSSStyleSheet::CreateInline(*document_, NullURL(), position,
- UTF8Encoding());
+ style_sheet_ = CreateStyleSheet(*document_);
}
CSSRuleList* TestStyleSheet::CssRules() {
@@ -67,6 +65,12 @@ void TestStyleSheet::AddCSSRules(const String& css_text, bool is_empty_sheet) {
ASSERT_EQ(style_sheet_->length(), sheet_length);
}
+CSSStyleSheet* CreateStyleSheet(Document& document) {
+ TextPosition position;
+ return CSSStyleSheet::CreateInline(document, NullURL(), position,
+ UTF8Encoding());
+}
+
PropertyRegistration* CreatePropertyRegistration(const String& name) {
auto syntax_definition = CSSSyntaxStringParser("*").Parse();
DCHECK(syntax_definition);
diff --git a/chromium/third_party/blink/renderer/core/css/css_test_helpers.h b/chromium/third_party/blink/renderer/core/css/css_test_helpers.h
index c50b4514df6..fac98f438c7 100644
--- a/chromium/third_party/blink/renderer/core/css/css_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/css/css_test_helpers.h
@@ -45,6 +45,8 @@ class TestStyleSheet {
Persistent<CSSStyleSheet> style_sheet_;
};
+CSSStyleSheet* CreateStyleSheet(Document& document);
+
// Create a PropertyRegistration for the given name. The syntax, initial value,
// and inherited status are all undefined.
PropertyRegistration* CreatePropertyRegistration(const String& name);
diff --git a/chromium/third_party/blink/renderer/core/css/css_unset_value.h b/chromium/third_party/blink/renderer/core/css/css_unset_value.h
index dfbf7a8fd84..517b50e6c7e 100644
--- a/chromium/third_party/blink/renderer/core/css/css_unset_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_unset_value.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_UNSET_VALUE_H_
#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -20,7 +20,7 @@ class CORE_EXPORT CSSUnsetValue : public CSSValue {
public:
static CSSUnsetValue* Create();
- explicit CSSUnsetValue(util::PassKey<CSSValuePool>) : CSSValue(kUnsetClass) {}
+ explicit CSSUnsetValue(base::PassKey<CSSValuePool>) : CSSValue(kUnsetClass) {}
String CustomCSSText() const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_value.h b/chromium/third_party/blink/renderer/core/css/css_value.h
index 03dba55ee92..4867a7438da 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value.h
+++ b/chromium/third_party/blink/renderer/core/css/css_value.h
@@ -24,6 +24,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/style/data_equivalency.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
@@ -33,6 +34,7 @@ class Length;
class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> {
public:
+#if !BUILDFLAG(USE_V8_OILPAN)
template <typename T>
static void* AllocateObject(size_t size) {
ThreadState* state =
@@ -42,6 +44,7 @@ class CORE_EXPORT CSSValue : public GarbageCollected<CSSValue> {
state, size, BlinkGC::kCSSValueArenaIndex,
GCInfoTrait<GCInfoFoldedType<CSSValue>>::Index(), type_name);
}
+#endif // !USE_V8_OILPAN
// TODO(sashab): Remove this method and move logic to the caller.
static CSSValue* Create(const Length& value, float zoom);
@@ -340,4 +343,16 @@ inline bool CompareCSSValueVector(
} // namespace blink
+#if BUILDFLAG(USE_V8_OILPAN)
+namespace cppgc {
+// Assign CSSValue to be allocated on custom CSSValueSpace.
+template <typename T>
+struct SpaceTrait<
+ T,
+ std::enable_if_t<std::is_base_of<blink::CSSValue, T>::value>> {
+ using Space = blink::CSSValueSpace;
+};
+} // namespace cppgc
+#endif // !USE_V8_OILPAN
+
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VALUE_H_
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.cc b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.cc
new file mode 100644
index 00000000000..e479bfd26df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.cc
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/css_value_clamping_utils.h"
+#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+
+namespace blink {
+
+double CSSValueClampingUtils::ClampLength(double value) {
+ if (std::isnan(value))
+ value = std::numeric_limits<double>::max();
+ return clampTo<double>(value);
+}
+
+float CSSValueClampingUtils::ClampLength(float value) {
+ if (std::isnan(value))
+ value = std::numeric_limits<float>::max();
+ return clampTo<float>(value);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.h b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.h
new file mode 100644
index 00000000000..9bfa6bb8910
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils.h
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VALUE_CLAMPING_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VALUE_CLAMPING_UTILS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class CORE_EXPORT CSSValueClampingUtils {
+ STATIC_ONLY(CSSValueClampingUtils);
+
+ public:
+ static double ClampLength(double value);
+ static float ClampLength(float value);
+ // TODO(crbug.com/1133390): The clamping functions for specific properties
+ // (i.e. <time>, <angle> .. ) will be added.
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VALUE_CLAMPING_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils_test.cc b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils_test.cc
new file mode 100644
index 00000000000..74e18c96d46
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/css_value_clamping_utils_test.cc
@@ -0,0 +1,38 @@
+#include "third_party/blink/renderer/core/css/css_value_clamping_utils.h"
+
+#include <limits>
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(CSSValueClampingTest, IsLengthNotClampedZeroValue) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(0.0), 0.0);
+}
+
+TEST(CSSValueClampingTest, IsLengthNotClampedPositiveFiniteValue) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(10.0), 10.0);
+}
+
+TEST(CSSValueClampingTest, IsLengthNotClampediNegativeFiniteValue) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(-10.0), -10.0);
+}
+
+TEST(CSSValueClampingTest, IsLengthClampedPositiveInfinity) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(
+ std::numeric_limits<double>::infinity()),
+ std::numeric_limits<double>::max());
+}
+
+TEST(CSSValueClampingTest, IsLengthClampedNaN) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(
+ std::numeric_limits<double>::quiet_NaN()),
+ std::numeric_limits<double>::max());
+}
+
+TEST(CSSValueClampingTest, IsLengthClampedNegativeInfinity) {
+ EXPECT_EQ(CSSValueClampingUtils::ClampLength(
+ -std::numeric_limits<double>::infinity()),
+ std::numeric_limits<double>::lowest());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_id_mappings.h b/chromium/third_party/blink/renderer/core/css/css_value_id_mappings.h
index 1b5e8c6c194..7af488e789b 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_id_mappings.h
+++ b/chromium/third_party/blink/renderer/core/css/css_value_id_mappings.h
@@ -185,6 +185,10 @@ inline EListStyleType CssValueIDToPlatformEnum(CSSValueID v) {
return EListStyleType::kCircle;
case CSSValueID::kSquare:
return EListStyleType::kSquare;
+ case CSSValueID::kDisclosureOpen:
+ return EListStyleType::kDisclosureOpen;
+ case CSSValueID::kDisclosureClosed:
+ return EListStyleType::kDisclosureClosed;
case CSSValueID::kDecimal:
return EListStyleType::kDecimal;
case CSSValueID::kDecimalLeadingZero:
@@ -292,12 +296,10 @@ inline EListStyleType CssValueIDToPlatformEnum(CSSValueID v) {
case CSSValueID::kNone:
return EListStyleType::kNone;
default:
- NOTREACHED();
break;
}
- NOTREACHED();
- return EListStyleType::kDisc;
+ return EListStyleType::kNone;
}
template <>
@@ -371,6 +373,10 @@ inline CSSValueID PlatformEnumToCSSValueID(EListStyleType v) {
return CSSValueID::kCircle;
case EListStyleType::kSquare:
return CSSValueID::kSquare;
+ case EListStyleType::kDisclosureOpen:
+ return CSSValueID::kDisclosureOpen;
+ case EListStyleType::kDisclosureClosed:
+ return CSSValueID::kDisclosureClosed;
case EListStyleType::kDecimal:
return CSSValueID::kDecimal;
case EListStyleType::kDecimalLeadingZero:
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5 b/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
index dba0e26678b..e99da16e617 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/chromium/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -435,6 +435,8 @@
"disc",
"circle",
"square",
+ "disclosure-open",
+ "disclosure-closed",
"decimal",
"decimal-leading-zero",
"arabic-indic",
@@ -1327,6 +1329,12 @@
"max",
"clamp",
+ //<calc-constant>
+ //https://drafts.csswg.org/css-values/#calc-syntax
+ "infinity",
+ "-infinity",
+ "nan",
+
// scroll-snap-type
// none
// x
@@ -1353,6 +1361,8 @@
"style",
// layout
"size",
+ "block-size",
+ "inline-size",
// grid auto-repeat
"auto-fill",
@@ -1435,6 +1445,14 @@
"single-fold-vertical",
"single-fold-horizontal",
+ // (screen-fold-posture) media feature
+ "no-fold",
+ "laptop",
+ // flat,
+ "tent",
+ "tablet",
+ "book",
+
// scrollbar-gutter
// auto
"stable",
@@ -1447,5 +1465,36 @@
"more",
"less",
"forced",
+
+ // @counter-style system
+ "cyclic",
+ // fixed,
+ "symbolic",
+ // alphabetic,
+ "numeric",
+ "additive",
+ "extends",
+ // Predefined counter styles that don't use the above systems
+ "-internal-simp-chinese-informal",
+ "-internal-simp-chinese-formal",
+ "-internal-trad-chinese-informal",
+ "-internal-trad-chinese-formal",
+ "-internal-korean-hangul-formal",
+ "-internal-korean-hanja-informal",
+ "-internal-korean-hanja-formal",
+ "-internal-hebrew",
+ "-internal-lower-armenian",
+ "-internal-upper-armenian",
+ "-internal-ethiopic-numeric",
+
+ // @counter-style range
+ // infinite,
+
+ // @counter-style speak-as
+ // auto
+ "bullets",
+ "numbers",
+ "words",
+ // spell-out,
],
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_pair.h b/chromium/third_party/blink/renderer/core/css/css_value_pair.h
index db0081bff0e..faa859c5e49 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_pair.h
+++ b/chromium/third_party/blink/renderer/core/css/css_value_pair.h
@@ -59,9 +59,9 @@ class CORE_EXPORT CSSValuePair : public CSSValue {
}
bool Equals(const CSSValuePair& other) const {
- DCHECK_EQ(identical_values_policy_, other.identical_values_policy_);
return DataEquivalent(first_, other.first_) &&
- DataEquivalent(second_, other.second_);
+ DataEquivalent(second_, other.second_) &&
+ identical_values_policy_ == other.identical_values_policy_;
}
void TraceAfterDispatch(blink::Visitor*) const;
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_pool.cc b/chromium/third_party/blink/renderer/core/css/css_value_pool.cc
index 7fdee1b81d8..1935fed55a8 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_pool.cc
+++ b/chromium/third_party/blink/renderer/core/css/css_value_pool.cc
@@ -36,7 +36,7 @@ CSSValuePool& CssValuePool() {
Persistent<CSSValuePool>& pool_handle = *thread_specific_pool;
if (!pool_handle) {
pool_handle = MakeGarbageCollected<CSSValuePool>();
- pool_handle.RegisterAsStaticReference();
+ LEAK_SANITIZER_IGNORE_OBJECT(&pool_handle);
}
return *pool_handle;
}
diff --git a/chromium/third_party/blink/renderer/core/css/css_value_pool.h b/chromium/third_party/blink/renderer/core/css/css_value_pool.h
index 4d3431fa852..304688ad657 100644
--- a/chromium/third_party/blink/renderer/core/css/css_value_pool.h
+++ b/chromium/third_party/blink/renderer/core/css/css_value_pool.h
@@ -27,7 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_VALUE_POOL_H_
#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_color_value.h"
#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
@@ -50,7 +50,7 @@ namespace blink {
class CORE_EXPORT CSSValuePool final : public GarbageCollected<CSSValuePool> {
public:
- using PassKey = util::PassKey<CSSValuePool>;
+ using PassKey = base::PassKey<CSSValuePool>;
// TODO(sashab): Make all the value pools store const CSSValues.
static const int kMaximumCacheableIntegerValue = 255;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc
index f7fa3052dd6..a12889e3d04 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/cross_thread_style_value_test.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
#include <memory>
+#include <utility>
+
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -103,7 +105,7 @@ TEST_F(CrossThreadStyleValueTest, PassUnsupportedValueCrossThread) {
CrossThreadBindOnce(&CrossThreadStyleValueTest::CheckUnsupportedValue,
CrossThreadUnretained(this),
CrossThreadUnretained(&waitable_event),
- WTF::Passed(std::move(value))));
+ std::move(value)));
waitable_event.Wait();
ShutDownThread();
@@ -134,7 +136,7 @@ TEST_F(CrossThreadStyleValueTest, PassUnparsedValueCrossThread) {
CrossThreadBindOnce(&CrossThreadStyleValueTest::CheckUnparsedValue,
CrossThreadUnretained(this),
CrossThreadUnretained(&waitable_event),
- WTF::Passed(std::move(value))));
+ std::move(value)));
waitable_event.Wait();
ShutDownThread();
@@ -166,7 +168,7 @@ TEST_F(CrossThreadStyleValueTest, PassKeywordValueCrossThread) {
CrossThreadBindOnce(&CrossThreadStyleValueTest::CheckKeywordValue,
CrossThreadUnretained(this),
CrossThreadUnretained(&waitable_event),
- WTF::Passed(std::move(value))));
+ std::move(value)));
waitable_event.Wait();
ShutDownThread();
@@ -198,7 +200,7 @@ TEST_F(CrossThreadStyleValueTest, PassUnitValueCrossThread) {
CrossThreadBindOnce(&CrossThreadStyleValueTest::CheckUnitValue,
CrossThreadUnretained(this),
CrossThreadUnretained(&waitable_event),
- WTF::Passed(std::move(value))));
+ std::move(value)));
waitable_event.Wait();
ShutDownThread();
@@ -230,7 +232,7 @@ TEST_F(CrossThreadStyleValueTest, PassColorValueCrossThread) {
CrossThreadBindOnce(&CrossThreadStyleValueTest::CheckColorValue,
CrossThreadUnretained(this),
CrossThreadUnretained(&waitable_event),
- WTF::Passed(std::move(value))));
+ std::move(value)));
waitable_event.Wait();
ShutDownThread();
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.cc b/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.cc
index 5e26e4e55f9..ad1b2c7a890 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_style_value.cc
@@ -25,7 +25,7 @@ CSSStyleValueVector ParseCSSStyleValue(
const String& value,
ExceptionState& exception_state) {
const CSSPropertyID property_id =
- cssPropertyID(execution_context, property_name);
+ CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid property name");
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc b/chromium/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc
index 049dfc28085..119929b984d 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc
@@ -119,18 +119,19 @@ IndexedPropertySetterResult CSSUnparsedValue::AnonymousIndexedSetter(
}
const CSSValue* CSSUnparsedValue::ToCSSValue() const {
- if (tokens_.IsEmpty()) {
+ CSSTokenizer tokenizer(ToString());
+ const auto tokens = tokenizer.TokenizeToEOF();
+ CSSParserTokenRange range(tokens);
+
+ if (range.AtEnd()) {
return MakeGarbageCollected<CSSVariableReferenceValue>(
CSSVariableData::Create());
}
- CSSTokenizer tokenizer(ToString());
- const auto tokens = tokenizer.TokenizeToEOF();
return MakeGarbageCollected<CSSVariableReferenceValue>(
- CSSVariableData::Create({CSSParserTokenRange(tokens), StringView()},
- false /* is_animation_tainted */,
- false /* needs_variable_resolution */, KURL(),
- WTF::TextEncoding()));
+ CSSVariableData::Create(
+ {range, StringView()}, false /* is_animation_tainted */,
+ false /* needs_variable_resolution */, KURL(), WTF::TextEncoding()));
}
String CSSUnparsedValue::ToString() const {
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.cc b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.cc
index 35a58b2dcd2..62b78885b2a 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.cc
@@ -18,10 +18,11 @@ namespace {
void DrawInternal(cc::PaintCanvas* canvas,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
const PaintFlags& flags,
Image::ImageClampingMode clamping_mode,
const PaintImage& image) {
- canvas->drawImageRect(image, src_rect, dest_rect, &flags,
+ canvas->drawImageRect(image, src_rect, dest_rect, sampling, &flags,
WebCoreClampingModeToSkiaRectConstraint(clamping_mode));
}
} // namespace
@@ -30,16 +31,19 @@ void PaintWorkletDeferredImage::Draw(cc::PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum,
ImageClampingMode clamping_mode,
ImageDecodingMode) {
- DrawInternal(canvas, dest_rect, src_rect, flags, clamping_mode, image_);
+ DrawInternal(canvas, dest_rect, src_rect, sampling, flags, clamping_mode,
+ image_);
}
void PaintWorkletDeferredImage::DrawTile(GraphicsContext& context,
const FloatRect& src_rect,
RespectImageOrientationEnum) {
- DrawInternal(context.Canvas(), FloatRect(), src_rect, context.FillFlags(),
+ DrawInternal(context.Canvas(), FloatRect(), src_rect,
+ context.ImageSamplingOptions(), context.FillFlags(),
kClampImageToSourceRect, image_);
}
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h
index d82c56208fe..ecccd20e76c 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h
@@ -35,6 +35,7 @@ class CORE_EXPORT PaintWorkletDeferredImage : public GeneratedImage {
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
index 6dde8129649..32a1c56bc07 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
@@ -31,6 +31,8 @@ class CORE_EXPORT PaintWorkletInput : public cc::PaintWorkletInput {
const FloatSize& ContainerSize() const { return container_size_; }
protected:
+ PaintWorkletInput(const FloatSize& container_size, int worklet_id)
+ : container_size_(container_size), worklet_id_(worklet_id) {}
PaintWorkletInput(const FloatSize& container_size,
int worklet_id,
cc::PaintWorkletInput::PropertyKeys property_keys)
@@ -46,14 +48,7 @@ class CORE_EXPORT PaintWorkletInput : public cc::PaintWorkletInput {
// List of properties associated with this PaintWorkletInput.
// Kept and initialized here, but used in CC, so using C++ std library types.
- // TODO(xidachen): make this structure account for native property.
- // Instead of pair<string, CompositorElementId>, define
- // struct PropertyKey {
- // std::string custom_property_name;
- // enum native_property_type;
- // CompositorElementId element_id;
- // }
- // PropId uniquely identifies a property value, potentially being animated by
+ // PropertyKey uniquely identifies a property, potentially being animated by
// the compositor, used by this PaintWorklet as an input at paint time. The
// worklet provides a list of the properties that it uses as inputs.
cc::PaintWorkletInput::PropertyKeys property_keys_;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc
index fd973714f46..ed04bc1bf55 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.cc
@@ -172,13 +172,13 @@ CSSStyleValueVector PaintWorkletStylePropertyMap::getAll(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) const {
- CSSPropertyID property_id = cssPropertyID(execution_context, property_name);
+ CSSPropertyID property_id = CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
return CSSStyleValueVector();
}
- DCHECK(isValidCSSPropertyID(property_id));
+ DCHECK(IsValidCSSPropertyID(property_id));
CSSStyleValueVector values;
auto value = data_.find(property_name);
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
index d69a8b53e21..26f04ede8d8 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
index c76f2b79ed8..583f9a8ae8a 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
@@ -66,7 +66,11 @@ const CSSValue* StyleValueToCSSValue(
case CSSPropertyID::kBorderBottomLeftRadius:
case CSSPropertyID::kBorderBottomRightRadius:
case CSSPropertyID::kBorderTopLeftRadius:
- case CSSPropertyID::kBorderTopRightRadius: {
+ case CSSPropertyID::kBorderTopRightRadius:
+ case CSSPropertyID::kBorderEndEndRadius:
+ case CSSPropertyID::kBorderEndStartRadius:
+ case CSSPropertyID::kBorderStartEndRadius:
+ case CSSPropertyID::kBorderStartStartRadius: {
// level 1 only accept single <length-percentages>, but border-radius-*
// expects pairs.
const auto* value = style_value.ToCSSValue();
@@ -267,13 +271,13 @@ void StylePropertyMap::set(const ExecutionContext* execution_context,
const HeapVector<CSSStyleValueOrString>& values,
ExceptionState& exception_state) {
const CSSPropertyID property_id =
- cssPropertyID(execution_context, property_name);
+ CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
return;
}
- DCHECK(isValidCSSPropertyID(property_id));
+ DCHECK(IsValidCSSPropertyID(property_id));
const CSSProperty& property = CSSProperty::Get(property_id);
if (property.IsShorthand()) {
if (values.size() != 1) {
@@ -332,7 +336,7 @@ void StylePropertyMap::append(const ExecutionContext* execution_context,
return;
const CSSPropertyID property_id =
- cssPropertyID(execution_context, property_name);
+ CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
@@ -377,7 +381,7 @@ void StylePropertyMap::append(const ExecutionContext* execution_context,
void StylePropertyMap::remove(const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) {
- CSSPropertyID property_id = cssPropertyID(execution_context, property_name);
+ CSSPropertyID property_id = CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid property name: " + property_name);
return;
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
index 872cf6184fb..e1972e99982 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
@@ -70,7 +70,11 @@ CSSStyleValue* CreateStyleValueWithPropertyInternal(CSSPropertyID property_id,
case CSSPropertyID::kBorderBottomLeftRadius:
case CSSPropertyID::kBorderBottomRightRadius:
case CSSPropertyID::kBorderTopLeftRadius:
- case CSSPropertyID::kBorderTopRightRadius: {
+ case CSSPropertyID::kBorderTopRightRadius:
+ case CSSPropertyID::kBorderEndEndRadius:
+ case CSSPropertyID::kBorderEndStartRadius:
+ case CSSPropertyID::kBorderStartEndRadius:
+ case CSSPropertyID::kBorderStartStartRadius: {
// border-radius-* are always stored as pairs, but when both values are
// the same, we should reify as a single value.
if (const auto* pair = DynamicTo<CSSValuePair>(value)) {
diff --git a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
index ab9f78db42d..98b0e75279b 100644
--- a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
@@ -30,7 +30,6 @@
#include "third_party/blink/renderer/core/css/document_style_sheet_collector.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
-#include "third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css/style_sheet_candidate.h"
@@ -50,9 +49,7 @@ DocumentStyleSheetCollection::DocumentStyleSheetCollection(
void DocumentStyleSheetCollection::CollectStyleSheetsFromCandidates(
StyleEngine& engine,
DocumentStyleSheetCollector& collector) {
- CHECK(ThreadState::Current()->IsOnThreadHeap(this));
for (Node* n : style_sheet_candidate_nodes_) {
- CHECK(ThreadState::Current()->IsOnThreadHeap(n));
StyleSheetCandidate candidate(*n);
DCHECK(!candidate.IsXSL());
@@ -127,22 +124,4 @@ void DocumentStyleSheetCollection::UpdateActiveStyleSheets(
ApplyActiveStyleSheetChanges(*collection);
}
-void DocumentStyleSheetCollection::CollectViewportRules(
- ViewportStyleResolver& viewport_resolver) {
- for (Node* node : style_sheet_candidate_nodes_) {
- StyleSheetCandidate candidate(*node);
-
- if (candidate.IsImport())
- continue;
- StyleSheet* sheet = candidate.Sheet();
- if (!sheet)
- continue;
- if (!candidate.CanBeActivated(
- GetDocument().GetStyleEngine().PreferredStylesheetSetName()))
- continue;
- viewport_resolver.CollectViewportRulesFromAuthorSheet(
- To<CSSStyleSheet>(*sheet));
- }
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.h b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.h
index 6abcc0412bb..d234c2c813f 100644
--- a/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.h
+++ b/chromium/third_party/blink/renderer/core/css/document_style_sheet_collection.h
@@ -37,7 +37,6 @@ namespace blink {
class DocumentStyleSheetCollector;
class StyleEngine;
class TreeScope;
-class ViewportStyleResolver;
class DocumentStyleSheetCollection final
: public TreeScopeStyleSheetCollection {
@@ -49,7 +48,6 @@ class DocumentStyleSheetCollection final
void UpdateActiveStyleSheets(StyleEngine&);
void CollectStyleSheets(StyleEngine&, DocumentStyleSheetCollector&);
- void CollectViewportRules(ViewportStyleResolver&);
void Trace(Visitor* visitor) const override {
TreeScopeStyleSheetCollection::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/css/dom_window_css.cc b/chromium/third_party/blink/renderer/core/css/dom_window_css.cc
index 58eefab5dc5..0e61e40c701 100644
--- a/chromium/third_party/blink/renderer/core/css/dom_window_css.cc
+++ b/chromium/third_party/blink/renderer/core/css/dom_window_css.cc
@@ -44,7 +44,7 @@ bool DOMWindowCSS::supports(const ExecutionContext* execution_context,
const String& property,
const String& value) {
CSSPropertyID unresolved_property =
- unresolvedCSSPropertyID(execution_context, property);
+ UnresolvedCSSPropertyID(execution_context, property);
if (unresolved_property == CSSPropertyID::kInvalid)
return false;
if (unresolved_property == CSSPropertyID::kVariable) {
@@ -59,7 +59,7 @@ bool DOMWindowCSS::supports(const ExecutionContext* execution_context,
}
#if DCHECK_IS_ON()
- DCHECK(CSSProperty::Get(resolveCSSPropertyID(unresolved_property))
+ DCHECK(CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
.IsWebExposed(execution_context));
#endif
diff --git a/chromium/third_party/blink/renderer/core/css/element_rule_collector.cc b/chromium/third_party/blink/renderer/core/css/element_rule_collector.cc
index 263363b3bbc..f431f80add0 100644
--- a/chromium/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/chromium/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/css/element_rule_collector.h"
+#include "third_party/blink/renderer/core/css/container_query_evaluator.h"
#include "third_party/blink/renderer/core/css/css_import_rule.h"
#include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
#include "third_party/blink/renderer/core/css/css_media_rule.h"
@@ -59,12 +60,15 @@ unsigned AdjustLinkMatchType(EInsideLink inside_link,
} // namespace
-ElementRuleCollector::ElementRuleCollector(const ElementResolveContext& context,
- const SelectorFilter& filter,
- MatchResult& result,
- ComputedStyle* style,
- EInsideLink inside_link)
+ElementRuleCollector::ElementRuleCollector(
+ const ElementResolveContext& context,
+ const StyleRecalcContext& style_recalc_context,
+ const SelectorFilter& filter,
+ MatchResult& result,
+ ComputedStyle* style,
+ EInsideLink inside_link)
: context_(context),
+ style_recalc_context_(style_recalc_context),
selector_filter_(filter),
style_(style),
pseudo_style_request_(kPseudoIdNone),
@@ -132,9 +136,8 @@ static bool RulesApplicableInCurrentTreeScope(
template <typename RuleDataListType>
void ElementRuleCollector::CollectMatchingRulesForList(
const RuleDataListType* rules,
- ShadowV0CascadeOrder cascade_order,
const MatchRequest& match_request,
- PartNames* part_names) {
+ PartRequest* part_request) {
if (!rules)
return;
@@ -144,7 +147,7 @@ void ElementRuleCollector::CollectMatchingRulesForList(
init.element_style = style_.get();
init.scrollbar = pseudo_style_request_.scrollbar;
init.scrollbar_part = pseudo_style_request_.scrollbar_part;
- init.part_names = part_names;
+ init.part_names = part_request ? &part_request->part_names : nullptr;
SelectorChecker checker(init);
SelectorChecker::SelectorCheckingContext context(&context_.GetElement());
context.scope = match_request.scope;
@@ -175,12 +178,22 @@ void ElementRuleCollector::CollectMatchingRulesForList(
if (!rule->ShouldConsiderForMatchingRules(include_empty_rules_))
continue;
+ const auto& selector = rule_data->Selector();
+ if (UNLIKELY(part_request && part_request->for_shadow_pseudo)) {
+ if (!selector.IsAllowedAfterPart()) {
+ DCHECK_EQ(selector.GetPseudoType(), CSSSelector::kPseudoPart);
+ rejected++;
+ continue;
+ }
+ DCHECK_EQ(selector.Relation(), CSSSelector::kUAShadow);
+ }
+
SelectorChecker::MatchResult result;
- context.selector = &rule_data->Selector();
+ context.selector = &selector;
context.is_inside_visited_link =
rule_data->LinkMatchType() == CSSSelector::kMatchVisited;
DCHECK(!context.is_inside_visited_link ||
- (inside_link_ == EInsideLink::kInsideVisitedLink));
+ inside_link_ == EInsideLink::kInsideVisitedLink);
if (!checker.Match(context, result)) {
rejected++;
continue;
@@ -190,9 +203,19 @@ void ElementRuleCollector::CollectMatchingRulesForList(
rejected++;
continue;
}
+ if (auto* container_query = rule_data->GetContainerQuery()) {
+ result_.SetDependsOnContainerQueries();
+
+ auto* evaluator = style_recalc_context_.cq_evaluator;
+
+ if (!evaluator || !evaluator->EvalAndAdd(*container_query)) {
+ rejected++;
+ continue;
+ }
+ }
matched++;
- DidMatchRule(rule_data, result, cascade_order, match_request);
+ DidMatchRule(rule_data, result, match_request);
}
StyleEngine& style_engine =
@@ -209,7 +232,6 @@ void ElementRuleCollector::CollectMatchingRulesForList(
DISABLE_CFI_PERF
void ElementRuleCollector::CollectMatchingRules(
const MatchRequest& match_request,
- ShadowV0CascadeOrder cascade_order,
bool matching_tree_boundary_rules) {
DCHECK(match_request.rule_set);
@@ -218,13 +240,14 @@ void ElementRuleCollector::CollectMatchingRules(
if (!pseudo_id.IsEmpty()) {
DCHECK(element.IsStyledElement());
CollectMatchingRulesForList(
- match_request.rule_set->ShadowPseudoElementRules(pseudo_id),
- cascade_order, match_request);
+ match_request.rule_set->UAShadowPseudoElementRules(pseudo_id),
+ match_request);
}
- if (element.IsVTTElement())
+ if (element.IsVTTElement()) {
CollectMatchingRulesForList(match_request.rule_set->CuePseudoRules(),
- cascade_order, match_request);
+ match_request);
+ }
// Check whether other types of rules are applicable in the current tree
// scope. Criteria for this:
// a) the rules are UA rules.
@@ -238,54 +261,62 @@ void ElementRuleCollector::CollectMatchingRules(
// We need to collect the rules for id, class, tag, and everything else into a
// buffer and then sort the buffer.
- if (element.HasID())
+ if (element.HasID()) {
CollectMatchingRulesForList(
match_request.rule_set->IdRules(element.IdForStyleResolution()),
- cascade_order, match_request);
+ match_request);
+ }
if (element.IsStyledElement() && element.HasClass()) {
- for (wtf_size_t i = 0; i < element.ClassNames().size(); ++i)
+ for (wtf_size_t i = 0; i < element.ClassNames().size(); ++i) {
CollectMatchingRulesForList(
match_request.rule_set->ClassRules(element.ClassNames()[i]),
- cascade_order, match_request);
+ match_request);
+ }
}
- if (element.IsLink())
+ if (element.IsLink()) {
CollectMatchingRulesForList(match_request.rule_set->LinkPseudoClassRules(),
- cascade_order, match_request);
+ match_request);
+ }
if (inside_link_ == EInsideLink::kInsideVisitedLink) {
CollectMatchingRulesForList(match_request.rule_set->VisitedDependentRules(),
- cascade_order, match_request);
+ match_request);
}
- if (SelectorChecker::MatchesFocusPseudoClass(element))
+ if (SelectorChecker::MatchesFocusPseudoClass(element)) {
CollectMatchingRulesForList(match_request.rule_set->FocusPseudoClassRules(),
- cascade_order, match_request);
+ match_request);
+ }
+ if (SelectorChecker::MatchesFocusVisiblePseudoClass(element)) {
+ CollectMatchingRulesForList(
+ match_request.rule_set->FocusVisiblePseudoClassRules(), match_request);
+ }
if (SelectorChecker::MatchesSpatialNavigationInterestPseudoClass(element)) {
CollectMatchingRulesForList(
match_request.rule_set->SpatialNavigationInterestPseudoClassRules(),
- cascade_order, match_request);
+ match_request);
}
AtomicString element_name = matching_ua_rules_
? element.localName()
: element.LocalNameForSelectorMatching();
CollectMatchingRulesForList(match_request.rule_set->TagRules(element_name),
- cascade_order, match_request);
+ match_request);
CollectMatchingRulesForList(match_request.rule_set->UniversalRules(),
- cascade_order, match_request);
+ match_request);
}
void ElementRuleCollector::CollectMatchingShadowHostRules(
- const MatchRequest& match_request,
- ShadowV0CascadeOrder cascade_order) {
+ const MatchRequest& match_request) {
CollectMatchingRulesForList(match_request.rule_set->ShadowHostRules(),
- cascade_order, match_request);
+ match_request);
}
void ElementRuleCollector::CollectMatchingPartPseudoRules(
const MatchRequest& match_request,
PartNames& part_names,
- ShadowV0CascadeOrder cascade_order) {
+ bool for_shadow_pseudo) {
+ PartRequest request{part_names, for_shadow_pseudo};
CollectMatchingRulesForList(match_request.rule_set->PartPseudoRules(),
- cascade_order, match_request, &part_names);
+ match_request, &request);
}
template <class CSSRuleCollection>
@@ -360,7 +391,6 @@ void ElementRuleCollector::SortAndTransferMatchedRules() {
void ElementRuleCollector::DidMatchRule(
const RuleData* rule_data,
const SelectorChecker::MatchResult& result,
- ShadowV0CascadeOrder cascade_order,
const MatchRequest& match_request) {
PseudoId dynamic_pseudo = result.dynamic_pseudo;
// If we're matching normal rules, set a pseudo bit if we really just matched
@@ -380,9 +410,9 @@ void ElementRuleCollector::DidMatchRule(
if (!rule_data->Rule()->Properties().IsEmpty())
style_->SetHasPseudoElementStyle(dynamic_pseudo);
} else {
- matched_rules_.push_back(MatchedRule(
- rule_data, result.specificity, cascade_order,
- match_request.style_sheet_index, match_request.style_sheet));
+ matched_rules_.push_back(MatchedRule(rule_data, result.specificity,
+ match_request.style_sheet_index,
+ match_request.style_sheet));
}
}
diff --git a/chromium/third_party/blink/renderer/core/css/element_rule_collector.h b/chromium/third_party/blink/renderer/core/css/element_rule_collector.h
index 8e69c0035a4..170baa15765 100644
--- a/chromium/third_party/blink/renderer/core/css/element_rule_collector.h
+++ b/chromium/third_party/blink/renderer/core/css/element_rule_collector.h
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/css/resolver/match_request.h"
#include "third_party/blink/renderer/core/css/resolver/match_result.h"
#include "third_party/blink/renderer/core/css/selector_checker.h"
+#include "third_party/blink/renderer/core/css/style_recalc.h"
#include "third_party/blink/renderer/core/style/computed_style_base_constants.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -42,19 +43,12 @@ class RuleData;
class SelectorFilter;
class StyleRuleUsageTracker;
-// TODO(kochi): ShadowV0CascadeOrder is used only for Shadow DOM V0
-// bug-compatible cascading order. Once Shadow DOM V0 implementation is gone,
-// remove this completely.
-using ShadowV0CascadeOrder = unsigned;
-const ShadowV0CascadeOrder kIgnoreCascadeOrder = 0;
-
class MatchedRule {
DISALLOW_NEW();
public:
MatchedRule(const RuleData* rule_data,
unsigned specificity,
- ShadowV0CascadeOrder cascade_order,
unsigned style_sheet_index,
const CSSStyleSheet* parent_style_sheet)
: rule_data_(rule_data),
@@ -62,10 +56,8 @@ class MatchedRule {
parent_style_sheet_(parent_style_sheet) {
DCHECK(rule_data_);
static const unsigned kBitsForPositionInRuleData = 18;
- static const unsigned kBitsForStyleSheetIndex = 32;
- position_ = ((uint64_t)cascade_order
- << (kBitsForStyleSheetIndex + kBitsForPositionInRuleData)) +
- ((uint64_t)style_sheet_index << kBitsForPositionInRuleData) +
+ position_ = (static_cast<uint64_t>(style_sheet_index)
+ << kBitsForPositionInRuleData) +
rule_data_->GetPosition();
}
@@ -108,6 +100,7 @@ class CORE_EXPORT ElementRuleCollector {
public:
ElementRuleCollector(const ElementResolveContext&,
+ const StyleRecalcContext&,
const SelectorFilter&,
MatchResult&,
ComputedStyle*,
@@ -131,15 +124,11 @@ class CORE_EXPORT ElementRuleCollector {
RuleIndexList* MatchedCSSRuleList();
void CollectMatchingRules(const MatchRequest&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder,
bool matching_tree_boundary_rules = false);
- void CollectMatchingShadowHostRules(
- const MatchRequest&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
- void CollectMatchingPartPseudoRules(
- const MatchRequest&,
- PartNames&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
+ void CollectMatchingShadowHostRules(const MatchRequest&);
+ void CollectMatchingPartPseudoRules(const MatchRequest&,
+ PartNames&,
+ bool for_shadow_pseudo);
void SortAndTransferMatchedRules();
void ClearMatchedRules();
void AddElementStyleProperties(const CSSPropertyValueSet*,
@@ -160,18 +149,23 @@ class CORE_EXPORT ElementRuleCollector {
void AddMatchedRulesToTracker(StyleRuleUsageTracker*) const;
private:
+ struct PartRequest {
+ PartNames& part_names;
+ // If this is true, we're matching for a pseudo-element of the part, such as
+ // ::placeholder.
+ bool for_shadow_pseudo = false;
+ };
+
template <typename RuleDataListType>
void CollectMatchingRulesForList(const RuleDataListType*,
- ShadowV0CascadeOrder,
const MatchRequest&,
- PartNames* = nullptr);
+ PartRequest* = nullptr);
bool Match(SelectorChecker&,
const SelectorChecker::SelectorCheckingContext&,
MatchResult&);
void DidMatchRule(const RuleData*,
const SelectorChecker::MatchResult&,
- ShadowV0CascadeOrder,
const MatchRequest&);
template <class CSSRuleCollection>
@@ -185,6 +179,7 @@ class CORE_EXPORT ElementRuleCollector {
private:
const ElementResolveContext& context_;
+ StyleRecalcContext style_recalc_context_;
const SelectorFilter& selector_filter_;
scoped_refptr<ComputedStyle>
style_; // FIXME: This can be mutated during matching!
diff --git a/chromium/third_party/blink/renderer/core/css/element_rule_collector_test.cc b/chromium/third_party/blink/renderer/core/css/element_rule_collector_test.cc
index 491e413936e..f16340e40f8 100644
--- a/chromium/third_party/blink/renderer/core/css/element_rule_collector_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/element_rule_collector_test.cc
@@ -39,8 +39,8 @@ class ElementRuleCollectorTest : public PageTestBase {
SelectorFilter filter;
MatchResult result;
auto style = ComputedStyle::Create();
- ElementRuleCollector collector(context, filter, result, style.get(),
- InsideLink(element));
+ ElementRuleCollector collector(context, StyleRecalcContext(), filter,
+ result, style.get(), InsideLink(element));
String rule = selector + " { color: green }";
auto* style_rule =
diff --git a/chromium/third_party/blink/renderer/core/css/font_face.cc b/chromium/third_party/blink/renderer/core/css/font_face.cc
index b5c85ed576f..cdf238e471c 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face.cc
@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_unicode_range_value.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/local_font_face_source.h"
#include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
#include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h"
@@ -121,7 +122,7 @@ FontFace* FontFace::Create(ExecutionContext* context,
if (source.IsArrayBuffer())
return Create(context, family, source.GetAsArrayBuffer(), descriptors);
if (source.IsArrayBufferView()) {
- return Create(context, family, source.GetAsArrayBufferView().View(),
+ return Create(context, family, source.GetAsArrayBufferView().Get(),
descriptors);
}
NOTREACHED();
@@ -209,8 +210,6 @@ FontFace* FontFace::Create(Document* document,
AtRuleDescriptorID::LineGapOverride) &&
font_face->SetPropertyFromStyle(properties,
AtRuleDescriptorID::AdvanceOverride) &&
- font_face->SetPropertyFromStyle(
- properties, AtRuleDescriptorID::AdvanceProportionalOverride) &&
font_face->GetFontSelectionCapabilities().IsValid() &&
!font_face->family().IsEmpty()) {
font_face->InitCSSFontFace(document->GetExecutionContext(), *src);
@@ -423,10 +422,7 @@ bool FontFace::SetPropertyValue(const CSSValue* value,
line_gap_override_ = ConvertFontMetricOverrideValue(value);
break;
case AtRuleDescriptorID::AdvanceOverride:
- advance_override_ = value;
- break;
- case AtRuleDescriptorID::AdvanceProportionalOverride:
- advance_proportional_override_ = ConvertFontMetricOverrideValue(value);
+ advance_override_ = ConvertFontMetricOverrideValue(value);
break;
default:
NOTREACHED();
@@ -871,7 +867,6 @@ void FontFace::Trace(Visitor* visitor) const {
visitor->Trace(descent_override_);
visitor->Trace(line_gap_override_);
visitor->Trace(advance_override_);
- visitor->Trace(advance_proportional_override_);
visitor->Trace(error_);
visitor->Trace(loaded_property_);
visitor->Trace(css_font_face_);
@@ -914,13 +909,11 @@ FontMetricsOverride FontFace::GetFontMetricsOverride() const {
To<CSSPrimitiveValue>(*line_gap_override_).GetFloatValue() / 100;
}
if (advance_override_) {
+ const CSSValuePair& pair = To<CSSValuePair>(*advance_override_);
result.advance_override =
- To<CSSPrimitiveValue>(*advance_override_).GetFloatValue();
- }
- if (advance_proportional_override_) {
- result.advance_proportional_override =
- To<CSSPrimitiveValue>(*advance_proportional_override_).GetFloatValue() /
- 100;
+ To<CSSPrimitiveValue>(pair.First()).GetFloatValue() / 100;
+ result.advance_override_vertical_upright =
+ To<CSSPrimitiveValue>(pair.Second()).GetFloatValue() / 100;
}
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/css/font_face.h b/chromium/third_party/blink/renderer/core/css/font_face.h
index e8d606167ab..39194852be9 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face.h
@@ -143,7 +143,7 @@ class CORE_EXPORT FontFace : public ScriptWrappable,
bool HasFontMetricsOverride() const {
return ascent_override_ || descent_override_ || line_gap_override_ ||
- advance_override_ || advance_proportional_override_;
+ advance_override_;
}
FontMetricsOverride GetFontMetricsOverride() const;
@@ -189,7 +189,6 @@ class CORE_EXPORT FontFace : public ScriptWrappable,
Member<const CSSValue> descent_override_;
Member<const CSSValue> line_gap_override_;
Member<const CSSValue> advance_override_;
- Member<const CSSValue> advance_proportional_override_;
LoadStatusType status_;
Member<DOMException> error_;
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_cache.h b/chromium/third_party/blink/renderer/core/css/font_face_cache.h
index f0551fe0809..212dc3132ac 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_cache.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face_cache.h
@@ -42,9 +42,7 @@ namespace blink {
class FontDescription;
-class CORE_EXPORT FontFaceCache final {
- DISALLOW_NEW();
-
+class CORE_EXPORT FontFaceCache final : public GarbageCollected<FontFaceCache> {
public:
FontFaceCache();
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc b/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc
index 98e6ca440b3..26ca0030ab5 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_cache_test.cc
@@ -41,9 +41,7 @@ class FontFaceCacheTest : public PageTestBase {
FontSelectionValue style,
FontSelectionValue weight);
- FontFaceCache cache_;
-
- void Trace(Visitor*) const;
+ Persistent<FontFaceCache> cache_;
protected:
const AtomicString kFontNameForTesting{"Arial"};
@@ -51,11 +49,12 @@ class FontFaceCacheTest : public PageTestBase {
void FontFaceCacheTest::SetUp() {
PageTestBase::SetUp();
+ cache_ = MakeGarbageCollected<FontFaceCache>();
ClearCache();
}
void FontFaceCacheTest::ClearCache() {
- cache_.ClearAll();
+ cache_->ClearAll();
}
void FontFaceCacheTest::AppendTestFaceForCapabilities(const CSSValue& stretch,
@@ -83,7 +82,7 @@ void FontFaceCacheTest::AppendTestFaceForCapabilities(const CSSValue& stretch,
MakeGarbageCollected<StyleRuleFontFace>(font_face_descriptor);
FontFace* font_face = FontFace::Create(&GetDocument(), style_rule_font_face);
CHECK(font_face);
- cache_.Add(style_rule_font_face, font_face);
+ cache_->Add(style_rule_font_face, font_face);
}
void FontFaceCacheTest::AppendTestFaceForCapabilities(
@@ -125,7 +124,7 @@ TEST_F(FontFaceCacheTest, Instantiate) {
*weight_value);
AppendTestFaceForCapabilities(*stretch_value_condensed, *style_value,
*weight_value);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
}
TEST_F(FontFaceCacheTest, SimpleWidthMatch) {
@@ -141,12 +140,12 @@ TEST_F(FontFaceCacheTest, SimpleWidthMatch) {
*weight_value);
AppendTestFaceForCapabilities(*stretch_value_condensed, *style_value,
*weight_value);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
const FontDescription& description_condensed = FontDescriptionForRequest(
CondensedWidthValue(), NormalSlopeValue(), NormalWeightValue());
CSSSegmentedFontFace* result =
- cache_.Get(description_condensed, kFontNameForTesting);
+ cache_->Get(description_condensed, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
@@ -172,12 +171,12 @@ TEST_F(FontFaceCacheTest, SimpleWeightMatch) {
CSSNumericLiteralValue::Create(100, CSSPrimitiveValue::UnitType::kNumber);
AppendTestFaceForCapabilities(*stretch_value, *style_value,
*weight_value_thin);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
const FontDescription& description_bold = FontDescriptionForRequest(
NormalWidthValue(), NormalSlopeValue(), BoldWeightValue());
CSSSegmentedFontFace* result =
- cache_.Get(description_bold, kFontNameForTesting);
+ cache_->Get(description_bold, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
result->GetFontSelectionCapabilities();
@@ -272,7 +271,7 @@ TEST_F(FontFaceCacheTest, DISABLED_MatchCombinations) {
}
for (FontDescription& test_description : test_descriptions) {
CSSSegmentedFontFace* result =
- cache_.Get(test_description, kFontNameForTesting);
+ cache_->Get(test_description, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
result->GetFontSelectionCapabilities();
@@ -315,12 +314,12 @@ TEST_F(FontFaceCacheTest, WidthRangeMatching) {
AppendTestFaceForCapabilities(*stretch_value, *style_value,
*second_weight_list);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
const FontDescription& description_bold = FontDescriptionForRequest(
NormalWidthValue(), NormalSlopeValue(), BoldWeightValue());
CSSSegmentedFontFace* result =
- cache_.Get(description_bold, kFontNameForTesting);
+ cache_->Get(description_bold, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
result->GetFontSelectionCapabilities();
@@ -365,14 +364,14 @@ TEST_F(FontFaceCacheTest, WidthRangeMatchingBetween400500) {
*(weight_values_lower[0]),
*(weight_values_upper[0]));
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 1ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 1ul);
FontSelectionValue test_weight(450);
const FontDescription& description_expanded = FontDescriptionForRequest(
NormalWidthValue(), NormalSlopeValue(), test_weight);
CSSSegmentedFontFace* result =
- cache_.Get(description_expanded, kFontNameForTesting);
+ cache_->Get(description_expanded, kFontNameForTesting);
ASSERT_TRUE(result);
ASSERT_EQ(result->GetFontSelectionCapabilities().weight.minimum,
FontSelectionValue(600));
@@ -380,9 +379,9 @@ TEST_F(FontFaceCacheTest, WidthRangeMatchingBetween400500) {
AppendTestFaceForCapabilities(*stretch_value, *style_value,
*(weight_values_lower[1]),
*(weight_values_upper[1]));
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
- result = cache_.Get(description_expanded, kFontNameForTesting);
+ result = cache_->Get(description_expanded, kFontNameForTesting);
ASSERT_TRUE(result);
ASSERT_EQ(result->GetFontSelectionCapabilities().weight.minimum,
FontSelectionValue(415));
@@ -390,9 +389,9 @@ TEST_F(FontFaceCacheTest, WidthRangeMatchingBetween400500) {
AppendTestFaceForCapabilities(*stretch_value, *style_value,
*(weight_values_lower[2]),
*(weight_values_upper[2]));
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 3ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 3ul);
- result = cache_.Get(description_expanded, kFontNameForTesting);
+ result = cache_->Get(description_expanded, kFontNameForTesting);
ASSERT_TRUE(result);
ASSERT_EQ(result->GetFontSelectionCapabilities().weight.minimum,
FontSelectionValue(475));
@@ -424,12 +423,12 @@ TEST_F(FontFaceCacheTest, StretchRangeMatching) {
AppendTestFaceForCapabilities(*second_stretch_list, *style_value,
*weight_value);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
const FontDescription& description_expanded = FontDescriptionForRequest(
FontSelectionValue(105), NormalSlopeValue(), NormalWeightValue());
CSSSegmentedFontFace* result =
- cache_.Get(description_expanded, kFontNameForTesting);
+ cache_->Get(description_expanded, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
result->GetFontSelectionCapabilities();
@@ -477,12 +476,12 @@ TEST_F(FontFaceCacheTest, ObliqueRangeMatching) {
AppendTestFaceForCapabilities(*stretch_value, *oblique_value_second,
*weight_value);
- ASSERT_EQ(cache_.GetNumSegmentedFacesForTesting(), 2ul);
+ ASSERT_EQ(cache_->GetNumSegmentedFacesForTesting(), 2ul);
const FontDescription& description_italic = FontDescriptionForRequest(
NormalWidthValue(), ItalicSlopeValue(), NormalWeightValue());
CSSSegmentedFontFace* result =
- cache_.Get(description_italic, kFontNameForTesting);
+ cache_->Get(description_italic, kFontNameForTesting);
ASSERT_TRUE(result);
FontSelectionCapabilities result_capabilities =
result->GetFontSelectionCapabilities();
@@ -495,8 +494,4 @@ TEST_F(FontFaceCacheTest, ObliqueRangeMatching) {
FontSelectionRange({FontSelectionValue(30), FontSelectionValue(35)}));
}
-void FontFaceCacheTest::Trace(Visitor* visitor) const {
- visitor->Trace(cache_);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc b/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
index 1d1b35ab67c..c94cd0ccc93 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -265,6 +265,7 @@ void FontFaceSetDocument::LCPLimitReached(TimerBase*) {
}
void FontFaceSetDocument::Trace(Visitor* visitor) const {
+ visitor->Trace(lcp_limit_timer_);
Supplement<Document>::Trace(visitor);
FontFaceSet::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/css/font_face_set_document.h b/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
index 680c926f238..f00f129a016 100644
--- a/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
+++ b/chromium/third_party/blink/renderer/core/css/font_face_set_document.h
@@ -81,8 +81,7 @@ class CORE_EXPORT FontFaceSetDocument final : public FontFaceSet,
protected:
bool InActiveContext() const override;
FontSelector* GetFontSelector() const override {
- // TODO(Fserb): tracking down crbug.com/988125, can be DCHECK later.
- CHECK(IsMainThread());
+ DCHECK(IsMainThread());
return GetDocument()->GetStyleEngine().GetFontSelector();
}
@@ -128,7 +127,7 @@ class CORE_EXPORT FontFaceSetDocument final : public FontFaceSet,
};
FontDisplayAutoAlignHistogram font_display_auto_align_histogram_;
- TaskRunnerTimer<FontFaceSetDocument> lcp_limit_timer_;
+ HeapTaskRunnerTimer<FontFaceSetDocument> lcp_limit_timer_;
bool has_reached_lcp_limit_ = false;
};
diff --git a/chromium/third_party/blink/renderer/core/css/font_update_invalidation_test.cc b/chromium/third_party/blink/renderer/core/css/font_update_invalidation_test.cc
index 1a656b05dd2..506a0d035be 100644
--- a/chromium/third_party/blink/renderer/core/css/font_update_invalidation_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/font_update_invalidation_test.cc
@@ -17,12 +17,9 @@ namespace blink {
// This test suite verifies that after font changes (e.g., font loaded), we do
// not invalidate the full document's style or layout, but for affected elements
// only.
-class FontUpdateInvalidationTest
- : private ScopedCSSReducedFontLoadingLayoutInvalidationsForTest,
- public SimTest {
+class FontUpdateInvalidationTest : public SimTest {
public:
- FontUpdateInvalidationTest()
- : ScopedCSSReducedFontLoadingLayoutInvalidationsForTest(true) {}
+ FontUpdateInvalidationTest() = default;
protected:
static Vector<char> ReadAhemWoff2() {
diff --git a/chromium/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc b/chromium/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
index 05434171788..3c250fd995b 100644
--- a/chromium/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
@@ -94,10 +94,6 @@ ALWAYS_INLINE bool StyleInvalidator::MatchesCurrentInvalidationSets(
return true;
}
- if (invalidation_flags_.InsertionPointCrossing() &&
- element.IsV0InsertionPoint())
- return true;
-
for (auto* const invalidation_set : invalidation_sets_) {
if (invalidation_set->InvalidatesElement(element))
return true;
@@ -308,12 +304,6 @@ void StyleInvalidator::Invalidate(Element& element, SiblingData& sibling_data) {
auto* html_slot_element = DynamicTo<HTMLSlotElement>(element);
if (html_slot_element && InvalidatesSlotted())
InvalidateSlotDistributedElements(*html_slot_element);
-
- if (InsertionPointCrossing() && element.IsV0InsertionPoint()) {
- element.SetNeedsStyleRecalc(kSubtreeStyleChange,
- StyleChangeReasonForTracing::Create(
- style_change_reason::kStyleInvalidator));
- }
}
// We need to recurse into children if:
diff --git a/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc b/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
index 6b4cc619728..b16aea1043d 100644
--- a/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
+++ b/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
@@ -38,16 +38,34 @@ Element& LayoutTreeRebuildRoot::RootElement() const {
ContainerNode* LayoutTreeRebuildRoot::Parent(const Node& node) const {
return node.GetReattachParent();
}
+
+bool LayoutTreeRebuildRoot::IsChildDirty(const Node& node) const {
+ return node.ChildNeedsReattachLayoutTree();
+}
#endif // DCHECK_IS_ON()
bool LayoutTreeRebuildRoot::IsDirty(const Node& node) const {
return node.NeedsReattachLayoutTree();
}
-void LayoutTreeRebuildRoot::RootRemoved(ContainerNode& parent) {
+void LayoutTreeRebuildRoot::SubtreeModified(ContainerNode& parent) {
+ if (!GetRootNode())
+ return;
+ if (GetRootNode()->isConnected())
+ return;
+ // LayoutTreeRebuildRoot is only used for marking for layout tree rebuild
+ // during style recalc. We do not allow DOM modifications during style recalc
+ // or the layout tree rebuild that happens right after. The only time we
+ // should end up here is when we find out that we need to remove generated
+ // pseudo elements like ::first-letter or ::marker during layout tree rebuild.
+ DCHECK(parent.isConnected());
+ DCHECK(GetRootNode()->IsPseudoElement());
Element* ancestor = DynamicTo<Element>(parent);
- if (!ancestor)
+ if (!ancestor) {
+ // The parent should be the pseudo element's originating element.
+ NOTREACHED();
ancestor = parent.ParentOrShadowHostElement();
+ }
for (; ancestor; ancestor = ancestor->GetReattachParent()) {
DCHECK(ancestor->ChildNeedsReattachLayoutTree());
DCHECK(!ancestor->NeedsReattachLayoutTree());
diff --git a/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.h b/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.h
index 25657e73dc5..f7d20829c20 100644
--- a/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.h
+++ b/chromium/third_party/blink/renderer/core/css/layout_tree_rebuild_root.h
@@ -14,13 +14,14 @@ class CORE_EXPORT LayoutTreeRebuildRoot : public StyleTraversalRoot {
public:
Element& RootElement() const;
+ void SubtreeModified(ContainerNode& parent) final;
private:
#if DCHECK_IS_ON()
ContainerNode* Parent(const Node& node) const final;
+ bool IsChildDirty(const Node& node) const final;
#endif // DCHECK_IS_ON()
bool IsDirty(const Node& node) const final;
- void RootRemoved(ContainerNode& parent) final;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_feature_names.json5 b/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
index 464d2a23663..babc3d594af 100644
--- a/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
+++ b/chromium/third_party/blink/renderer/core/css/media_feature_names.json5
@@ -59,6 +59,7 @@
"resolution",
"-webkit-transform-3d",
"scan",
+ "screen-fold-posture",
"screen-spanning",
],
}
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
index 2286a3bf90d..f02ca798826 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -31,13 +31,14 @@
#include "third_party/blink/public/common/css/forced_colors.h"
#include "third_party/blink/public/common/css/navigation_controls.h"
-#include "third_party/blink/public/common/css/screen_spanning.h"
+#include "third_party/blink/renderer/core/css/media_values.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/mojom/manifest/display_mode.mojom-shared.h"
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
@@ -46,7 +47,6 @@
#include "third_party/blink/renderer/core/css/media_list.h"
#include "third_party/blink/renderer/core/css/media_query.h"
#include "third_party/blink/renderer/core/css/media_values_dynamic.h"
-#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
#include "third_party/blink/renderer/core/css/resolver/media_query_result.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -60,10 +60,12 @@
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "ui/base/pointer/pointer_device.h"
namespace blink {
+using mojom::blink::HoverType;
+using mojom::blink::PointerType;
+
namespace {
void RecordMediaQueryResult(Document* doc,
@@ -100,12 +102,6 @@ MediaQueryEvaluator::MediaQueryEvaluator(LocalFrame* frame)
MediaQueryEvaluator::MediaQueryEvaluator(const MediaValues& media_values)
: media_values_(media_values.Copy()) {}
-MediaQueryEvaluator::MediaQueryEvaluator(
- MediaValuesInitialViewport* media_values)
- : media_values_(media_values) {
- DCHECK(media_values);
-}
-
MediaQueryEvaluator::~MediaQueryEvaluator() = default;
void MediaQueryEvaluator::Trace(Visitor* visitor) const {
@@ -696,16 +692,17 @@ static bool ImmersiveMediaFeatureEval(const MediaQueryExpValue& value,
static bool HoverMediaFeatureEval(const MediaQueryExpValue& value,
MediaFeaturePrefix,
const MediaValues& media_values) {
- ui::HoverType hover = media_values.PrimaryHoverType();
+ HoverType hover = media_values.PrimaryHoverType();
if (!value.IsValid())
- return hover != ui::HOVER_TYPE_NONE;
+ return hover != HoverType::kHoverNone;
if (!value.is_id)
return false;
- return (hover == ui::HOVER_TYPE_NONE && value.id == CSSValueID::kNone) ||
- (hover == ui::HOVER_TYPE_HOVER && value.id == CSSValueID::kHover);
+ return (hover == HoverType::kHoverNone && value.id == CSSValueID::kNone) ||
+ (hover == HoverType::kHoverHoverType &&
+ value.id == CSSValueID::kHover);
}
static bool AnyHoverMediaFeatureEval(const MediaQueryExpValue& value,
@@ -714,16 +711,17 @@ static bool AnyHoverMediaFeatureEval(const MediaQueryExpValue& value,
int available_hover_types = media_values.AvailableHoverTypes();
if (!value.IsValid())
- return available_hover_types & ~ui::HOVER_TYPE_NONE;
+ return available_hover_types & ~static_cast<int>(HoverType::kHoverNone);
if (!value.is_id)
return false;
switch (value.id) {
case CSSValueID::kNone:
- return available_hover_types & ui::HOVER_TYPE_NONE;
+ return available_hover_types & static_cast<int>(HoverType::kHoverNone);
case CSSValueID::kHover:
- return available_hover_types & ui::HOVER_TYPE_HOVER;
+ return available_hover_types &
+ static_cast<int>(HoverType::kHoverHoverType);
default:
NOTREACHED();
return false;
@@ -742,18 +740,20 @@ static bool OriginTrialTestMediaFeatureEval(const MediaQueryExpValue& value,
static bool PointerMediaFeatureEval(const MediaQueryExpValue& value,
MediaFeaturePrefix,
const MediaValues& media_values) {
- ui::PointerType pointer = media_values.PrimaryPointerType();
+ PointerType pointer = media_values.PrimaryPointerType();
if (!value.IsValid())
- return pointer != ui::POINTER_TYPE_NONE;
+ return pointer != PointerType::kPointerNone;
if (!value.is_id)
return false;
- return (pointer == ui::POINTER_TYPE_NONE && value.id == CSSValueID::kNone) ||
- (pointer == ui::POINTER_TYPE_COARSE &&
+ return (pointer == PointerType::kPointerNone &&
+ value.id == CSSValueID::kNone) ||
+ (pointer == PointerType::kPointerCoarseType &&
value.id == CSSValueID::kCoarse) ||
- (pointer == ui::POINTER_TYPE_FINE && value.id == CSSValueID::kFine);
+ (pointer == PointerType::kPointerFineType &&
+ value.id == CSSValueID::kFine);
}
static bool PrefersReducedMotionMediaFeatureEval(
@@ -791,19 +791,22 @@ static bool AnyPointerMediaFeatureEval(const MediaQueryExpValue& value,
const MediaValues& media_values) {
int available_pointers = media_values.AvailablePointerTypes();
- if (!value.IsValid())
- return available_pointers & ~ui::POINTER_TYPE_NONE;
+ if (!value.IsValid()) {
+ return available_pointers & ~static_cast<int>(PointerType::kPointerNone);
+ }
if (!value.is_id)
return false;
switch (value.id) {
case CSSValueID::kCoarse:
- return available_pointers & ui::POINTER_TYPE_COARSE;
+ return available_pointers &
+ static_cast<int>(PointerType::kPointerCoarseType);
case CSSValueID::kFine:
- return available_pointers & ui::POINTER_TYPE_FINE;
+ return available_pointers &
+ static_cast<int>(PointerType::kPointerFineType);
case CSSValueID::kNone:
- return available_pointers & ui::POINTER_TYPE_NONE;
+ return available_pointers & static_cast<int>(PointerType::kPointerNone);
default:
NOTREACHED();
return false;
@@ -977,6 +980,37 @@ static bool ScreenSpanningMediaFeatureEval(const MediaQueryExpValue& value,
value.id == CSSValueID::kSingleFoldHorizontal);
}
+static bool ScreenFoldPostureMediaFeatureEval(const MediaQueryExpValue& value,
+ MediaFeaturePrefix,
+ const MediaValues& media_values) {
+ // isValid() is false if there is no parameter. Without parameter we should
+ // return true to indicate that screenFoldPosture is enabled in the
+ // browser.
+ if (!value.IsValid())
+ return true;
+
+ DCHECK(value.is_id);
+
+ ScreenFoldPosture screen_fold_posture = media_values.GetScreenFoldPosture();
+ switch (value.id) {
+ case CSSValueID::kNoFold:
+ return screen_fold_posture == ScreenFoldPosture::kNoFold;
+ case CSSValueID::kLaptop:
+ return screen_fold_posture == ScreenFoldPosture::kLaptop;
+ case CSSValueID::kFlat:
+ return screen_fold_posture == ScreenFoldPosture::kFlat;
+ case CSSValueID::kTent:
+ return screen_fold_posture == ScreenFoldPosture::kTent;
+ case CSSValueID::kTablet:
+ return screen_fold_posture == ScreenFoldPosture::kTablet;
+ case CSSValueID::kBook:
+ return screen_fold_posture == ScreenFoldPosture::kBook;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
void MediaQueryEvaluator::Init() {
// Create the table.
g_function_map = new FunctionMap;
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.h b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.h
index 3a2f09df7ce..c3ed951f03c 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_evaluator.h
+++ b/chromium/third_party/blink/renderer/core/css/media_query_evaluator.h
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
+
class LocalFrame;
class MediaQuery;
class MediaQueryExp;
@@ -40,7 +41,6 @@ class MediaQueryResult;
class MediaQuerySet;
class MediaQuerySetResult;
class MediaValues;
-class MediaValuesInitialViewport;
using MediaQueryResultList = Vector<MediaQueryResult>;
@@ -74,7 +74,6 @@ class CORE_EXPORT MediaQueryEvaluator final
// values.
explicit MediaQueryEvaluator(const MediaValues&);
- explicit MediaQueryEvaluator(MediaValuesInitialViewport*);
MediaQueryEvaluator(const MediaQueryEvaluator&) = delete;
MediaQueryEvaluator& operator=(const MediaQueryEvaluator&) = delete;
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_evaluator_test.cc b/chromium/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
index a9140bdbb4b..54654c0c48e 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
@@ -7,10 +7,9 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/css/forced_colors.h"
-#include "third_party/blink/public/common/css/screen_spanning.h"
#include "third_party/blink/renderer/core/css/media_list.h"
+#include "third_party/blink/renderer/core/css/media_values.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
-#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/css/parser/media_query_parser.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -279,6 +278,75 @@ MediaQueryEvaluatorTestCase g_screen_spanning_single_fold_horizontal_cases[] = {
{nullptr, 0} // Do not remove the terminator line.
};
+MediaQueryEvaluatorTestCase g_screen_fold_posture_none_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 0},
+ {"(screen-fold-posture: flat)", 0},
+ {"(screen-fold-posture: tent)", 0},
+ {"(screen-fold-posture: tablet)", 0},
+ {"(screen-fold-posture: book)", 0},
+ {"(screen-fold-posture: no-fold)", 1},
+ {"(screen-fold-posture: 15)", 0},
+ {"(screen-fold-posture: 2px)", 0},
+ {"(screen-fold-posture: 16/9)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_laptop_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 1},
+ {"(screen-fold-posture: flat)", 0},
+ {"(screen-fold-posture: tent)", 0},
+ {"(screen-fold-posture: tablet)", 0},
+ {"(screen-fold-posture: book)", 0},
+ {"(screen-fold-posture: no-fold)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_flat_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 0},
+ {"(screen-fold-posture: flat)", 1},
+ {"(screen-fold-posture: tent)", 0},
+ {"(screen-fold-posture: tablet)", 0},
+ {"(screen-fold-posture: book)", 0},
+ {"(screen-fold-posture: no-fold)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_tent_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 0},
+ {"(screen-fold-posture: flat)", 0},
+ {"(screen-fold-posture: tent)", 1},
+ {"(screen-fold-posture: tablet)", 0},
+ {"(screen-fold-posture: book)", 0},
+ {"(screen-fold-posture: no-fold)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_tablet_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 0},
+ {"(screen-fold-posture: flat)", 0},
+ {"(screen-fold-posture: tent)", 0},
+ {"(screen-fold-posture: tablet)", 1},
+ {"(screen-fold-posture: book)", 0},
+ {"(screen-fold-posture: no-fold)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_book_cases[] = {
+ {"(screen-fold-posture)", 1},
+ {"(screen-fold-posture: laptop)", 0},
+ {"(screen-fold-posture: flat)", 0},
+ {"(screen-fold-posture: tent)", 0},
+ {"(screen-fold-posture: tablet)", 0},
+ {"(screen-fold-posture: book)", 1},
+ {"(screen-fold-posture: no-fold)", 0},
+ {nullptr, 0} // Do not remove the terminator line.
+};
+
void TestMQEvaluator(MediaQueryEvaluatorTestCase* test_cases,
const MediaQueryEvaluator& media_query_evaluator,
CSSParserMode mode) {
@@ -311,8 +379,8 @@ TEST(MediaQueryEvaluatorTest, Cached) {
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
- data.primary_pointer_type = ui::POINTER_TYPE_FINE;
- data.primary_hover_type = ui::HOVER_TYPE_HOVER;
+ data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
+ data.primary_hover_type = mojom::blink::HoverType::kHoverHoverType;
data.default_font_size = 16;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
@@ -405,20 +473,6 @@ TEST(MediaQueryEvaluatorTest, CachedFloatViewportNonFloatFriendly) {
media_query_evaluator);
}
-TEST(MediaQueryEvaluatorTest, InitialViewport) {
- auto page_holder = std::make_unique<DummyPageHolder>(IntSize(500, 500));
- page_holder->GetFrameView().SetMediaType(media_type_names::kScreen);
- page_holder->GetFrameView().SetLayoutSizeFixedToFrameSize(false);
- page_holder->GetFrameView().SetInitialViewportSize(IntSize(500, 500));
- page_holder->GetFrameView().SetLayoutSize(IntSize(800, 800));
- page_holder->GetFrameView().SetFrameRect(IntRect(0, 0, 800, 800));
-
- MediaQueryEvaluator media_query_evaluator(
- MakeGarbageCollected<MediaValuesInitialViewport>(
- page_holder->GetFrame()));
- TestMQEvaluator(g_viewport_test_cases, media_query_evaluator);
-}
-
TEST(MediaQueryEvaluatorTest, DynamicImmersive) {
auto page_holder = std::make_unique<DummyPageHolder>(IntSize(500, 500));
page_holder->GetFrameView().SetMediaType(media_type_names::kScreen);
@@ -536,4 +590,52 @@ TEST(MediaQueryEvaluatorTest, CachedScreenSpanning) {
}
}
+TEST(MediaQueryEvaluatorTest, CachedScreenFoldPosture) {
+ ScopedScreenFoldForTest scoped_feature(true);
+
+ MediaValuesCached::MediaValuesCachedData data;
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kNoFold;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_none_cases, media_query_evaluator);
+ }
+
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kLaptop;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_laptop_cases, media_query_evaluator);
+ }
+
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kFlat;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_flat_cases, media_query_evaluator);
+ }
+
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kTent;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_tent_cases, media_query_evaluator);
+ }
+
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kTablet;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_tablet_cases, media_query_evaluator);
+ }
+
+ {
+ data.screen_fold_posture = ScreenFoldPosture::kBook;
+ MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+ MediaQueryEvaluator media_query_evaluator(*media_values);
+ TestMQEvaluator(g_screen_fold_posture_book_cases, media_query_evaluator);
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_exp.cc b/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
index 60177fab7a8..31adc9de623 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -114,6 +114,14 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
}
}
+ if (RuntimeEnabledFeatures::ScreenFoldEnabled()) {
+ if (media_feature == media_feature_names::kScreenFoldPostureMediaFeature) {
+ return ident == CSSValueID::kNoFold || ident == CSSValueID::kLaptop ||
+ ident == CSSValueID::kFlat || ident == CSSValueID::kTent ||
+ ident == CSSValueID::kTablet || ident == CSSValueID::kBook;
+ }
+ }
+
return false;
}
@@ -242,7 +250,10 @@ static inline bool FeatureWithoutValue(
RuntimeEnabledFeatures::OriginTrialsSampleAPIEnabled(
execution_context)) ||
(media_feature == media_feature_names::kScreenSpanningMediaFeature &&
- RuntimeEnabledFeatures::CSSFoldablesEnabled());
+ RuntimeEnabledFeatures::CSSFoldablesEnabled()) ||
+ (media_feature ==
+ media_feature_names::kScreenFoldPostureMediaFeature &&
+ RuntimeEnabledFeatures::ScreenFoldEnabled());
}
bool MediaQueryExp::IsViewportDependent() const {
@@ -276,6 +287,18 @@ bool MediaQueryExp::IsDeviceDependent() const {
media_feature_ == media_feature_names::kMaxDeviceHeightMediaFeature;
}
+bool MediaQueryExp::IsWidthDependent() const {
+ return media_feature_ == media_feature_names::kWidthMediaFeature ||
+ media_feature_ == media_feature_names::kMinWidthMediaFeature ||
+ media_feature_ == media_feature_names::kMaxWidthMediaFeature;
+}
+
+bool MediaQueryExp::IsHeightDependent() const {
+ return media_feature_ == media_feature_names::kHeightMediaFeature ||
+ media_feature_ == media_feature_names::kMinHeightMediaFeature ||
+ media_feature_ == media_feature_names::kMaxHeightMediaFeature;
+}
+
MediaQueryExp::MediaQueryExp(const MediaQueryExp& other)
: media_feature_(other.MediaFeature()), exp_value_(other.ExpValue()) {}
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_exp.h b/chromium/third_party/blink/renderer/core/css/media_query_exp.h
index f579b0204e7..05353333ae9 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_exp.h
+++ b/chromium/third_party/blink/renderer/core/css/media_query_exp.h
@@ -106,6 +106,10 @@ class CORE_EXPORT MediaQueryExp {
bool IsDeviceDependent() const;
+ bool IsWidthDependent() const;
+
+ bool IsHeightDependent() const;
+
String Serialize() const;
private:
diff --git a/chromium/third_party/blink/renderer/core/css/media_query_set_test.cc b/chromium/third_party/blink/renderer/core/css/media_query_set_test.cc
index 6573f3ed375..69f675b7ebb 100644
--- a/chromium/third_party/blink/renderer/core/css/media_query_set_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_query_set_test.cc
@@ -193,6 +193,7 @@ TEST(MediaQuerySetTest, BehindRuntimeFlag) {
ScopedForcedColorsForTest forced_colors_flag(false);
ScopedMediaQueryNavigationControlsForTest navigation_controls_flag(false);
ScopedCSSFoldablesForTest foldables_flag(false);
+ ScopedScreenFoldForTest screen_fold_flag(false);
// The first string represents the input string, the second string represents
// the output string.
@@ -200,10 +201,12 @@ TEST(MediaQuerySetTest, BehindRuntimeFlag) {
{"(forced-colors)", "not all"},
{"(navigation-controls)", "not all"},
{"(screen-spanning)", "not all"},
+ {"(screen-fold-posture)", "not all"},
{"(shape: rect)", "not all"},
{"(forced-colors: none)", "not all"},
{"(navigation-controls: none)", "not all"},
{"(screen-spanning:none)", "not all"},
+ {"(screen-fold-posture:none)", "not all"},
{nullptr, nullptr} // Do not remove the terminator line.
};
diff --git a/chromium/third_party/blink/renderer/core/css/media_values.cc b/chromium/third_party/blink/renderer/core/css/media_values.cc
index f6a48097aee..61e0ef7e3a4 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values.cc
@@ -4,14 +4,15 @@
#include "third_party/blink/renderer/core/css/media_values.h"
-#include "third_party/blink/public/common/css/screen_spanning.h"
#include "third_party/blink/public/common/widget/screen_info.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/css/media_feature_overrides.h"
+#include "third_party/blink/renderer/core/css/media_values.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
#include "third_party/blink/renderer/core/css/media_values_dynamic.h"
+#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -62,7 +63,7 @@ double MediaValues::CalculateViewportHeight(LocalFrame* frame) {
int MediaValues::CalculateDeviceWidth(LocalFrame* frame) {
DCHECK(frame && frame->View() && frame->GetSettings() && frame->GetPage());
- blink::ScreenInfo screen_info =
+ const ScreenInfo& screen_info =
frame->GetPage()->GetChromeClient().GetScreenInfo(*frame);
int device_width = screen_info.rect.width();
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
@@ -74,7 +75,7 @@ int MediaValues::CalculateDeviceWidth(LocalFrame* frame) {
int MediaValues::CalculateDeviceHeight(LocalFrame* frame) {
DCHECK(frame && frame->View() && frame->GetSettings() && frame->GetPage());
- blink::ScreenInfo screen_info =
+ const ScreenInfo& screen_info =
frame->GetPage()->GetChromeClient().GetScreenInfo(*frame);
int device_height = screen_info.rect.height();
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
@@ -97,7 +98,7 @@ float MediaValues::CalculateDevicePixelRatio(LocalFrame* frame) {
int MediaValues::CalculateColorBitsPerComponent(LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetPage());
- ScreenInfo screen_info =
+ const ScreenInfo& screen_info =
frame->GetPage()->GetChromeClient().GetScreenInfo(*frame);
if (screen_info.is_monochrome)
return 0;
@@ -107,7 +108,7 @@ int MediaValues::CalculateColorBitsPerComponent(LocalFrame* frame) {
int MediaValues::CalculateMonochromeBitsPerComponent(LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetPage());
- ScreenInfo screen_info =
+ const ScreenInfo& screen_info =
frame->GetPage()->GetChromeClient().GetScreenInfo(*frame);
if (!screen_info.is_monochrome)
return 0;
@@ -150,7 +151,8 @@ bool MediaValues::CalculateInImmersiveMode(LocalFrame* frame) {
return frame->GetSettings()->GetImmersiveModeEnabled();
}
-ui::PointerType MediaValues::CalculatePrimaryPointerType(LocalFrame* frame) {
+mojom::blink::PointerType MediaValues::CalculatePrimaryPointerType(
+ LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetSettings());
return frame->GetSettings()->GetPrimaryPointerType();
@@ -162,7 +164,8 @@ int MediaValues::CalculateAvailablePointerTypes(LocalFrame* frame) {
return frame->GetSettings()->GetAvailablePointerTypes();
}
-ui::HoverType MediaValues::CalculatePrimaryHoverType(LocalFrame* frame) {
+mojom::blink::HoverType MediaValues::CalculatePrimaryHoverType(
+ LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetSettings());
return frame->GetSettings()->GetPrimaryHoverType();
@@ -177,6 +180,19 @@ int MediaValues::CalculateAvailableHoverTypes(LocalFrame* frame) {
ColorSpaceGamut MediaValues::CalculateColorGamut(LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetPage());
+ if (const auto* overrides = frame->GetPage()->GetMediaFeatureOverrides()) {
+ MediaQueryExpValue value = overrides->GetOverride("color-gamut");
+ if (value.IsValid()) {
+ if (value.id == CSSValueID::kSRGB)
+ return ColorSpaceGamut::SRGB;
+ if (value.id == CSSValueID::kP3)
+ return ColorSpaceGamut::P3;
+ // Rec. 2020 is also known as ITU-R-Empfehlung BT.2020.
+ if (value.id == CSSValueID::kRec2020)
+ return ColorSpaceGamut::BT2020;
+ NOTREACHED();
+ }
+ }
return color_space_utilities::GetColorSpaceGamut(
frame->GetPage()->GetChromeClient().GetScreenInfo(*frame));
}
@@ -242,25 +258,30 @@ ScreenSpanning MediaValues::CalculateScreenSpanning(LocalFrame* frame) {
if (!frame->GetWidgetForLocalRoot())
return ScreenSpanning::kNone;
- WebVector<WebRect> window_segments =
+ WebVector<gfx::Rect> window_segments =
frame->GetWidgetForLocalRoot()->WindowSegments();
if (window_segments.size() == 2) {
// If there are two segments and the y value of the segments is the same,
// we have side-by-side segments which are represented as a single vertical
// fold.
- if (window_segments[0].y == window_segments[1].y)
+ if (window_segments[0].y() == window_segments[1].y())
return ScreenSpanning::kSingleFoldVertical;
// If the x value of the segments is the same, we have stacked segments
// which are represented as a single horizontal fold.
- if (window_segments[0].x == window_segments[1].x)
+ if (window_segments[0].x() == window_segments[1].x())
return ScreenSpanning::kSingleFoldHorizontal;
}
return ScreenSpanning::kNone;
}
+ScreenFoldPosture MediaValues::CalculateScreenFoldPosture(LocalFrame* frame) {
+ // TODO(darktears): Retrieve information from the host.
+ return ScreenFoldPosture::kNoFold;
+}
+
bool MediaValues::ComputeLengthImpl(double value,
CSSPrimitiveValue::UnitType type,
unsigned default_font_size,
diff --git a/chromium/third_party/blink/renderer/core/css/media_values.h b/chromium/third_party/blink/renderer/core/css/media_values.h
index a631a5f3711..babd2eb8caa 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values.h
@@ -8,6 +8,7 @@
#include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/css/preferred_contrast.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -22,7 +23,8 @@ enum class CSSValueID;
enum class ColorSpaceGamut;
enum class ForcedColors;
enum class NavigationControls;
-enum class ScreenSpanning;
+enum class ScreenSpanning { kNone, kSingleFoldHorizontal, kSingleFoldVertical };
+enum class ScreenFoldPosture { kNoFold, kLaptop, kFlat, kTent, kTablet, kBook };
mojom::blink::PreferredColorScheme CSSValueIDToPreferredColorScheme(
CSSValueID id);
@@ -69,9 +71,9 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
virtual float DevicePixelRatio() const = 0;
virtual int ColorBitsPerComponent() const = 0;
virtual int MonochromeBitsPerComponent() const = 0;
- virtual ui::PointerType PrimaryPointerType() const = 0;
+ virtual mojom::blink::PointerType PrimaryPointerType() const = 0;
virtual int AvailablePointerTypes() const = 0;
- virtual ui::HoverType PrimaryHoverType() const = 0;
+ virtual mojom::blink::HoverType PrimaryHoverType() const = 0;
virtual int AvailableHoverTypes() const = 0;
virtual bool ThreeDEnabled() const = 0;
virtual bool InImmersiveMode() const = 0;
@@ -91,6 +93,7 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
virtual ForcedColors GetForcedColors() const = 0;
virtual NavigationControls GetNavigationControls() const = 0;
virtual ScreenSpanning GetScreenSpanning() const = 0;
+ virtual ScreenFoldPosture GetScreenFoldPosture() const = 0;
protected:
static double CalculateViewportWidth(LocalFrame*);
@@ -106,9 +109,9 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
static blink::mojom::DisplayMode CalculateDisplayMode(LocalFrame*);
static bool CalculateThreeDEnabled(LocalFrame*);
static bool CalculateInImmersiveMode(LocalFrame*);
- static ui::PointerType CalculatePrimaryPointerType(LocalFrame*);
+ static mojom::blink::PointerType CalculatePrimaryPointerType(LocalFrame*);
static int CalculateAvailablePointerTypes(LocalFrame*);
- static ui::HoverType CalculatePrimaryHoverType(LocalFrame*);
+ static mojom::blink::HoverType CalculatePrimaryHoverType(LocalFrame*);
static int CalculateAvailableHoverTypes(LocalFrame*);
static ColorSpaceGamut CalculateColorGamut(LocalFrame*);
static mojom::blink::PreferredColorScheme CalculatePreferredColorScheme(
@@ -120,6 +123,7 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
static ForcedColors CalculateForcedColors();
static NavigationControls CalculateNavigationControls(LocalFrame*);
static ScreenSpanning CalculateScreenSpanning(LocalFrame*);
+ static ScreenFoldPosture CalculateScreenFoldPosture(LocalFrame*);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_cached.cc b/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
index 6fe6bf123a3..44d8d0b036c 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values_cached.cc
@@ -6,10 +6,10 @@
#include "third_party/blink/public/common/css/forced_colors.h"
#include "third_party/blink/public/common/css/navigation_controls.h"
-#include "third_party/blink/public/common/css/screen_spanning.h"
#include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-blink.h"
#include "third_party/blink/public/mojom/css/preferred_contrast.mojom-blink.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
+#include "third_party/blink/renderer/core/css/media_values.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -25,9 +25,9 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData()
device_pixel_ratio(1.0),
color_bits_per_component(24),
monochrome_bits_per_component(0),
- primary_pointer_type(ui::POINTER_TYPE_NONE),
+ primary_pointer_type(mojom::blink::PointerType::kPointerNone),
available_pointer_types(ui::POINTER_TYPE_NONE),
- primary_hover_type(ui::HOVER_TYPE_NONE),
+ primary_hover_type(mojom::blink::HoverType::kHoverNone),
available_hover_types(ui::HOVER_TYPE_NONE),
default_font_size(16),
three_d_enabled(false),
@@ -40,7 +40,8 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData()
prefers_reduced_motion(false),
forced_colors(ForcedColors::kNone),
navigation_controls(NavigationControls::kNone),
- screen_spanning(ScreenSpanning::kNone) {}
+ screen_spanning(ScreenSpanning::kNone),
+ screen_fold_posture(ScreenFoldPosture::kNoFold) {}
MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
Document& document)
@@ -85,6 +86,7 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
forced_colors = MediaValues::CalculateForcedColors();
navigation_controls = MediaValues::CalculateNavigationControls(frame);
screen_spanning = MediaValues::CalculateScreenSpanning(frame);
+ screen_fold_posture = MediaValues::CalculateScreenFoldPosture(frame);
}
}
@@ -141,7 +143,7 @@ int MediaValuesCached::MonochromeBitsPerComponent() const {
return data_.monochrome_bits_per_component;
}
-ui::PointerType MediaValuesCached::PrimaryPointerType() const {
+mojom::blink::PointerType MediaValuesCached::PrimaryPointerType() const {
return data_.primary_pointer_type;
}
@@ -149,7 +151,7 @@ int MediaValuesCached::AvailablePointerTypes() const {
return data_.available_pointer_types;
}
-ui::HoverType MediaValuesCached::PrimaryHoverType() const {
+mojom::blink::HoverType MediaValuesCached::PrimaryHoverType() const {
return data_.primary_hover_type;
}
@@ -225,4 +227,8 @@ ScreenSpanning MediaValuesCached::GetScreenSpanning() const {
return data_.screen_spanning;
}
+ScreenFoldPosture MediaValuesCached::GetScreenFoldPosture() const {
+ return data_.screen_fold_posture;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_cached.h b/chromium/third_party/blink/renderer/core/css/media_values_cached.h
index 92f44ef07ff..76439c8def4 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_cached.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values_cached.h
@@ -24,9 +24,9 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
float device_pixel_ratio;
int color_bits_per_component;
int monochrome_bits_per_component;
- ui::PointerType primary_pointer_type;
+ mojom::blink::PointerType primary_pointer_type;
int available_pointer_types;
- ui::HoverType primary_hover_type;
+ mojom::blink::HoverType primary_hover_type;
int available_hover_types;
int default_font_size;
bool three_d_enabled;
@@ -42,6 +42,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
ForcedColors forced_colors;
NavigationControls navigation_controls;
ScreenSpanning screen_spanning;
+ ScreenFoldPosture screen_fold_posture;
MediaValuesCachedData();
explicit MediaValuesCachedData(Document&);
@@ -73,6 +74,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
data.forced_colors = forced_colors;
data.navigation_controls = navigation_controls;
data.screen_spanning = screen_spanning;
+ data.screen_fold_posture = screen_fold_posture;
return data;
}
};
@@ -96,9 +98,9 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
float DevicePixelRatio() const override;
int ColorBitsPerComponent() const override;
int MonochromeBitsPerComponent() const override;
- ui::PointerType PrimaryPointerType() const override;
+ mojom::blink::PointerType PrimaryPointerType() const override;
int AvailablePointerTypes() const override;
- ui::HoverType PrimaryHoverType() const override;
+ mojom::blink::HoverType PrimaryHoverType() const override;
int AvailableHoverTypes() const override;
bool ThreeDEnabled() const override;
bool InImmersiveMode() const override;
@@ -115,6 +117,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
ForcedColors GetForcedColors() const override;
NavigationControls GetNavigationControls() const override;
ScreenSpanning GetScreenSpanning() const override;
+ ScreenFoldPosture GetScreenFoldPosture() const override;
void OverrideViewportDimensions(double width, double height) override;
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
index df1f7b9dfca..b75305eb963 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
+++ b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.cc
@@ -99,7 +99,7 @@ int MediaValuesDynamic::MonochromeBitsPerComponent() const {
return CalculateMonochromeBitsPerComponent(frame_);
}
-ui::PointerType MediaValuesDynamic::PrimaryPointerType() const {
+mojom::blink::PointerType MediaValuesDynamic::PrimaryPointerType() const {
return CalculatePrimaryPointerType(frame_);
}
@@ -107,7 +107,7 @@ int MediaValuesDynamic::AvailablePointerTypes() const {
return CalculateAvailablePointerTypes(frame_);
}
-ui::HoverType MediaValuesDynamic::PrimaryHoverType() const {
+mojom::blink::HoverType MediaValuesDynamic::PrimaryHoverType() const {
return CalculatePrimaryHoverType(frame_);
}
@@ -169,6 +169,10 @@ ScreenSpanning MediaValuesDynamic::GetScreenSpanning() const {
return CalculateScreenSpanning(frame_);
}
+ScreenFoldPosture MediaValuesDynamic::GetScreenFoldPosture() const {
+ return CalculateScreenFoldPosture(frame_);
+}
+
Document* MediaValuesDynamic::GetDocument() const {
return frame_->GetDocument();
}
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
index 6a02488acd3..b78c855f491 100644
--- a/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
+++ b/chromium/third_party/blink/renderer/core/css/media_values_dynamic.h
@@ -37,9 +37,9 @@ class CORE_EXPORT MediaValuesDynamic : public MediaValues {
float DevicePixelRatio() const override;
int ColorBitsPerComponent() const override;
int MonochromeBitsPerComponent() const override;
- ui::PointerType PrimaryPointerType() const override;
+ mojom::blink::PointerType PrimaryPointerType() const override;
int AvailablePointerTypes() const override;
- ui::HoverType PrimaryHoverType() const override;
+ mojom::blink::HoverType PrimaryHoverType() const override;
int AvailableHoverTypes() const override;
bool ThreeDEnabled() const override;
bool InImmersiveMode() const override;
@@ -54,6 +54,7 @@ class CORE_EXPORT MediaValuesDynamic : public MediaValues {
ForcedColors GetForcedColors() const override;
NavigationControls GetNavigationControls() const override;
ScreenSpanning GetScreenSpanning() const override;
+ ScreenFoldPosture GetScreenFoldPosture() const override;
Document* GetDocument() const override;
bool HasValues() const override;
void OverrideViewportDimensions(double width, double height) override;
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.cc b/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.cc
deleted file mode 100644
index e81c5cc7b5c..00000000000
--- a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-
-namespace blink {
-
-MediaValuesInitialViewport::MediaValuesInitialViewport(LocalFrame& frame)
- : MediaValuesDynamic(&frame) {}
-
-double MediaValuesInitialViewport::ViewportWidth() const {
- DCHECK(frame_->View());
- return frame_->View()->InitialViewportWidth();
-}
-
-double MediaValuesInitialViewport::ViewportHeight() const {
- DCHECK(frame_->View());
- return frame_->View()->InitialViewportHeight();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.h b/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.h
deleted file mode 100644
index 3aed1d54cdf..00000000000
--- a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_VALUES_INITIAL_VIEWPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_VALUES_INITIAL_VIEWPORT_H_
-
-#include "third_party/blink/renderer/core/css/media_values_dynamic.h"
-
-namespace blink {
-
-class CORE_EXPORT MediaValuesInitialViewport final : public MediaValuesDynamic {
- public:
- explicit MediaValuesInitialViewport(LocalFrame&);
-
- double ViewportWidth() const override;
- double ViewportHeight() const override;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_MEDIA_VALUES_INITIAL_VIEWPORT_H_
diff --git a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport_test.cc b/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport_test.cc
deleted file mode 100644
index 6b68f43fd56..00000000000
--- a/chromium/third_party/blink/renderer/core/css/media_values_initial_viewport_test.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-
-namespace blink {
-
-class MediaValuesInitialViewportTest : public PageTestBase {
- private:
- void SetUp() override {
- PageTestBase::SetUp(IntSize(320, 480));
- GetDocument().View()->SetInitialViewportSize(IntSize(320, 480));
- }
-};
-
-TEST_F(MediaValuesInitialViewportTest, InitialViewportSize) {
- LocalFrameView* view = GetDocument().View();
- ASSERT_TRUE(view);
- EXPECT_TRUE(view->LayoutSizeFixedToFrameSize());
-
- auto* media_values = MakeGarbageCollected<MediaValuesInitialViewport>(
- *GetDocument().GetFrame());
- EXPECT_EQ(320, media_values->ViewportWidth());
- EXPECT_EQ(480, media_values->ViewportHeight());
-
- view->SetLayoutSizeFixedToFrameSize(false);
- view->SetLayoutSize(IntSize(800, 600));
- EXPECT_EQ(320, media_values->ViewportWidth());
- EXPECT_EQ(480, media_values->ViewportHeight());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.cc b/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.cc
deleted file mode 100644
index 3390228bfbe..00000000000
--- a/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.cc
+++ /dev/null
@@ -1,31 +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/core/css/native_paint_image_generator.h"
-
-namespace blink {
-
-namespace {
-
-NativePaintImageGenerator::NativePaintImageGeneratorCreateFunction
- g_create_function = nullptr;
-
-} // namespace
-
-// static
-void NativePaintImageGenerator::Init(
- NativePaintImageGeneratorCreateFunction create_function) {
- DCHECK(!g_create_function);
- g_create_function = create_function;
-}
-
-// static
-std::unique_ptr<NativePaintImageGenerator> NativePaintImageGenerator::Create() {
- DCHECK(g_create_function);
- return g_create_function();
-}
-
-NativePaintImageGenerator::~NativePaintImageGenerator() = default;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.h b/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.h
index 465f0549529..eca4dbc444f 100644
--- a/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.h
+++ b/chromium/third_party/blink/renderer/core/css/native_paint_image_generator.h
@@ -6,24 +6,18 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_NATIVE_PAINT_IMAGE_GENERATOR_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/geometry/float_size.h"
-#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
-class Image;
-
-class CORE_EXPORT NativePaintImageGenerator {
+class CORE_EXPORT NativePaintImageGenerator
+ : public GarbageCollected<NativePaintImageGenerator> {
public:
- static std::unique_ptr<NativePaintImageGenerator> Create();
- virtual ~NativePaintImageGenerator();
+ virtual ~NativePaintImageGenerator() = default;
- typedef std::unique_ptr<NativePaintImageGenerator> (
- *NativePaintImageGeneratorCreateFunction)();
- static void Init(NativePaintImageGeneratorCreateFunction);
+ virtual void Shutdown() = 0;
- virtual scoped_refptr<Image> Paint(const FloatSize& container_size,
- SkColor color) = 0;
+ virtual void Trace(Visitor* visitor) const {}
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.cc b/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.cc
index e35b6e1cc66..20391b979d3 100644
--- a/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.cc
+++ b/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.cc
@@ -21,7 +21,7 @@
namespace blink {
OffscreenFontSelector::OffscreenFontSelector(WorkerGlobalScope* worker)
- : worker_(worker) {
+ : font_face_cache_(MakeGarbageCollected<FontFaceCache>()), worker_(worker) {
DCHECK(worker);
FontCache::GetFontCache()->AddClient(this);
}
@@ -43,7 +43,7 @@ scoped_refptr<FontData> OffscreenFontSelector::GetFontData(
const FontDescription& font_description,
const AtomicString& family_name) {
if (CSSSegmentedFontFace* face =
- font_face_cache_.Get(font_description, family_name)) {
+ font_face_cache_->Get(font_description, family_name)) {
worker_->GetFontMatchingMetrics()->ReportWebFontFamily(family_name);
return face->GetFontData(font_description);
}
@@ -74,7 +74,7 @@ void OffscreenFontSelector::WillUseFontData(
const FontDescription& font_description,
const AtomicString& family,
const String& text) {
- CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
+ CSSSegmentedFontFace* face = font_face_cache_->Get(font_description, family);
if (face)
face->WillUseFontData(font_description, text);
}
@@ -83,7 +83,7 @@ void OffscreenFontSelector::WillUseRange(
const FontDescription& font_description,
const AtomicString& family,
const FontDataForRangeSet& range_set) {
- CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
+ CSSSegmentedFontFace* face = font_face_cache_->Get(font_description, family);
if (face)
face->WillUseRange(font_description, range_set);
}
@@ -166,7 +166,7 @@ void OffscreenFontSelector::ReportLastResortFallbackFontLookup(
}
void OffscreenFontSelector::FontCacheInvalidated() {
- font_face_cache_.IncrementVersion();
+ font_face_cache_->IncrementVersion();
}
void OffscreenFontSelector::FontFaceInvalidated(FontInvalidationReason) {
diff --git a/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.h b/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.h
index 528e9f74931..9f6708563c2 100644
--- a/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/offscreen_font_selector.h
@@ -81,7 +81,7 @@ class CORE_EXPORT OffscreenFontSelector : public FontSelector {
void UpdateGenericFontFamilySettings(const GenericFontFamilySettings&);
- FontFaceCache* GetFontFaceCache() override { return &font_face_cache_; }
+ FontFaceCache* GetFontFaceCache() override { return font_face_cache_; }
bool IsPlatformFamilyMatchAvailable(
const FontDescription&,
@@ -99,7 +99,7 @@ class CORE_EXPORT OffscreenFontSelector : public FontSelector {
private:
GenericFontFamilySettings generic_font_family_settings_;
- FontFaceCache font_face_cache_;
+ Member<FontFaceCache> font_face_cache_;
Member<WorkerGlobalScope> worker_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
index 6d524bea227..00028f6e730 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/at_rule_counter_style_descriptor_parser.cc
@@ -6,6 +6,8 @@
#include "third_party/blink/renderer/core/css/css_string_value.h"
#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/css_value_pair.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
@@ -13,48 +15,220 @@ namespace blink {
namespace {
-CSSValue* ConsumeCounterStyleName(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
+CSSValue* ConsumeCounterStyleSymbol(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // <symbol> = <string> | <image> | <custom-ident>
+ if (CSSValue* string = css_parsing_utils::ConsumeString(range))
+ return string;
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleImageSymbolsEnabled()) {
+ if (CSSValue* image = css_parsing_utils::ConsumeImage(range, context))
+ return image;
+ }
+ if (CSSCustomIdentValue* custom_ident =
+ css_parsing_utils::ConsumeCustomIdent(range, context)) {
+ return custom_ident;
+ }
return nullptr;
}
-CSSValue* ConsumeCounterStyleSymbol(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
+CSSValue* ConsumeCounterStyleSystem(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: cyclic | numeric | alphabetic | symbolic | additive |
+ // [ fixed <integer>? ] | [ extends <counter-style-name> ]
+ if (CSSValue* ident = css_parsing_utils::ConsumeIdent<
+ CSSValueID::kCyclic, CSSValueID::kSymbolic, CSSValueID::kAlphabetic,
+ CSSValueID::kNumeric, CSSValueID::kAdditive>(range))
+ return ident;
+
+ if (CSSValue* ident =
+ css_parsing_utils::ConsumeIdent<CSSValueID::kFixed>(range)) {
+ CSSValue* first_symbol_value =
+ css_parsing_utils::ConsumeInteger(range, context);
+ if (!first_symbol_value) {
+ first_symbol_value = CSSNumericLiteralValue::Create(
+ 1, CSSPrimitiveValue::UnitType::kInteger);
+ }
+ return MakeGarbageCollected<CSSValuePair>(
+ ident, first_symbol_value, CSSValuePair::kKeepIdenticalValues);
+ }
+
+ if (CSSValue* ident =
+ css_parsing_utils::ConsumeIdent<CSSValueID::kExtends>(range)) {
+ CSSValue* extended =
+ css_parsing_utils::ConsumeCounterStyleName(range, context);
+ if (!extended)
+ return nullptr;
+ return MakeGarbageCollected<CSSValuePair>(
+ ident, extended, CSSValuePair::kKeepIdenticalValues);
+ }
+
+ // Internal keywords for predefined counter styles that use special
+ // algorithms. For example, 'simp-chinese-informal'.
+ if (context.Mode() == kUASheetMode) {
+ if (CSSValue* ident = css_parsing_utils::ConsumeIdent<
+ CSSValueID::kInternalHebrew,
+ CSSValueID::kInternalSimpChineseInformal,
+ CSSValueID::kInternalSimpChineseFormal,
+ CSSValueID::kInternalTradChineseInformal,
+ CSSValueID::kInternalTradChineseFormal,
+ CSSValueID::kInternalKoreanHangulFormal,
+ CSSValueID::kInternalKoreanHanjaInformal,
+ CSSValueID::kInternalKoreanHanjaFormal,
+ CSSValueID::kInternalLowerArmenian,
+ CSSValueID::kInternalUpperArmenian,
+ CSSValueID::kInternalEthiopicNumeric>(range))
+ return ident;
+ }
+
return nullptr;
}
-CSSValue* ConsumeCounterStyleSystem(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
- return nullptr;
+CSSValue* ConsumeCounterStyleNegative(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: <symbol> <symbol>?
+ CSSValue* prepend = ConsumeCounterStyleSymbol(range, context);
+ if (!prepend)
+ return nullptr;
+ if (range.AtEnd())
+ return prepend;
+
+ CSSValue* append = ConsumeCounterStyleSymbol(range, context);
+ if (!append || !range.AtEnd())
+ return nullptr;
+
+ return MakeGarbageCollected<CSSValuePair>(prepend, append,
+ CSSValuePair::kKeepIdenticalValues);
}
-CSSValue* ConsumeCounterStyleNegative(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
+CSSValue* ConsumeCounterStyleRangeBound(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ if (CSSValue* infinite =
+ css_parsing_utils::ConsumeIdent<CSSValueID::kInfinite>(range))
+ return infinite;
+ if (CSSValue* integer = css_parsing_utils::ConsumeInteger(range, context))
+ return integer;
return nullptr;
}
-CSSValue* ConsumeCounterStyleRange(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
- return nullptr;
+CSSValue* ConsumeCounterStyleRange(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: [ [ <integer> | infinite ]{2} ]# | auto
+ if (CSSValue* auto_value =
+ css_parsing_utils::ConsumeIdent<CSSValueID::kAuto>(range))
+ return auto_value;
+
+ CSSValueList* list = CSSValueList::CreateCommaSeparated();
+ do {
+ CSSValue* lower_bound = ConsumeCounterStyleRangeBound(range, context);
+ if (!lower_bound)
+ return nullptr;
+ CSSValue* upper_bound = ConsumeCounterStyleRangeBound(range, context);
+ if (!upper_bound)
+ return nullptr;
+
+ // If the lower bound of any range is higher than the upper bound, the
+ // entire descriptor is invalid and must be ignored.
+ if (lower_bound->IsPrimitiveValue() && upper_bound->IsPrimitiveValue() &&
+ To<CSSPrimitiveValue>(lower_bound)->GetIntValue() >
+ To<CSSPrimitiveValue>(upper_bound)->GetIntValue())
+ return nullptr;
+
+ list->Append(*MakeGarbageCollected<CSSValuePair>(
+ lower_bound, upper_bound, CSSValuePair::kKeepIdenticalValues));
+ } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
+ if (!range.AtEnd() || !list->length())
+ return nullptr;
+ return list;
}
-CSSValue* ConsumeCounterStylePad(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
- return nullptr;
+CSSValue* ConsumeCounterStylePad(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: <integer [0,∞]> && <symbol>
+ CSSValue* integer = nullptr;
+ CSSValue* symbol = nullptr;
+ while (!integer || !symbol) {
+ if (!integer) {
+ integer = css_parsing_utils::ConsumeInteger(range, context, 0);
+ if (integer)
+ continue;
+ }
+ if (!symbol) {
+ symbol = ConsumeCounterStyleSymbol(range, context);
+ if (symbol)
+ continue;
+ }
+ return nullptr;
+ }
+ if (!range.AtEnd())
+ return nullptr;
+
+ return MakeGarbageCollected<CSSValuePair>(integer, symbol,
+ CSSValuePair::kKeepIdenticalValues);
}
-CSSValue* ConsumeCounterStyleSymbols(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
- return nullptr;
+CSSValue* ConsumeCounterStyleSymbols(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: <symbol>+
+ CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+ while (!range.AtEnd()) {
+ CSSValue* symbol = ConsumeCounterStyleSymbol(range, context);
+ if (!symbol)
+ return nullptr;
+ list->Append(*symbol);
+ }
+ if (!list->length())
+ return nullptr;
+ return list;
}
-CSSValue* ConsumeCounterStyleAdditiveSymbols(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
- return nullptr;
+CSSValue* ConsumeCounterStyleAdditiveSymbols(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: [ <integer [0,∞]> && <symbol> ]#
+ CSSValueList* list = CSSValueList::CreateCommaSeparated();
+ CSSPrimitiveValue* last_integer = nullptr;
+ do {
+ CSSPrimitiveValue* integer = nullptr;
+ CSSValue* symbol = nullptr;
+ while (!integer || !symbol) {
+ if (!integer) {
+ integer = css_parsing_utils::ConsumeInteger(range, context, 0);
+ if (integer)
+ continue;
+ }
+ if (!symbol) {
+ symbol = ConsumeCounterStyleSymbol(range, context);
+ if (symbol)
+ continue;
+ }
+ return nullptr;
+ }
+
+ if (last_integer) {
+ // The additive tuples must be specified in order of strictly descending
+ // weight; otherwise, the declaration is invalid and must be ignored.
+ if (integer->GetIntValue() >= last_integer->GetIntValue())
+ return nullptr;
+ }
+ last_integer = integer;
+
+ list->Append(*MakeGarbageCollected<CSSValuePair>(
+ integer, symbol, CSSValuePair::kKeepIdenticalValues));
+ } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
+ if (!range.AtEnd() || !list->length())
+ return nullptr;
+ return list;
}
-CSSValue* ConsumeCounterStyleSpeakAs(CSSParserTokenRange& range) {
- // TODO(crbug.com/687225): Implement.
+CSSValue* ConsumeCounterStyleSpeakAs(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ // Syntax: auto | bullets | numbers | words | spell-out | <counter-style-name>
+ if (CSSValue* ident = css_parsing_utils::ConsumeIdent<
+ CSSValueID::kAuto, CSSValueID::kBullets, CSSValueID::kNumbers,
+ CSSValueID::kWords, CSSValueID::kSpellOut>(range))
+ return ident;
+ if (CSSValue* name =
+ css_parsing_utils::ConsumeCounterStyleName(range, context))
+ return name;
return nullptr;
}
@@ -70,40 +244,40 @@ CSSValue* AtRuleDescriptorParser::ParseAtCounterStyleDescriptor(
switch (id) {
case AtRuleDescriptorID::System:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleSystem(range);
+ parsed_value = ConsumeCounterStyleSystem(range, context);
break;
case AtRuleDescriptorID::Negative:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleNegative(range);
+ parsed_value = ConsumeCounterStyleNegative(range, context);
break;
case AtRuleDescriptorID::Prefix:
case AtRuleDescriptorID::Suffix:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleSymbol(range);
+ parsed_value = ConsumeCounterStyleSymbol(range, context);
break;
case AtRuleDescriptorID::Range:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleRange(range);
+ parsed_value = ConsumeCounterStyleRange(range, context);
break;
case AtRuleDescriptorID::Pad:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStylePad(range);
+ parsed_value = ConsumeCounterStylePad(range, context);
break;
case AtRuleDescriptorID::Fallback:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleName(range);
+ parsed_value = css_parsing_utils::ConsumeCounterStyleName(range, context);
break;
case AtRuleDescriptorID::Symbols:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleSymbols(range);
+ parsed_value = ConsumeCounterStyleSymbols(range, context);
break;
case AtRuleDescriptorID::AdditiveSymbols:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleAdditiveSymbols(range);
+ parsed_value = ConsumeCounterStyleAdditiveSymbols(range, context);
break;
case AtRuleDescriptorID::SpeakAs:
range.ConsumeWhitespace();
- parsed_value = ConsumeCounterStyleSpeakAs(range);
+ parsed_value = ConsumeCounterStyleSpeakAs(range, context);
break;
default:
break;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
index 2e7cdda6542..17b3d4a5d07 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/css/css_string_value.h"
#include "third_party/blink/renderer/core/css/css_unicode_range_value.h"
#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
@@ -179,6 +180,7 @@ CSSValue* ConsumeDescriptor(StyleRule::RuleType rule_type,
case StyleRule::kScrollTimeline:
return Parser::ParseAtScrollTimelineDescriptor(id, range, context);
case StyleRule::kCharset:
+ case StyleRule::kContainer:
case StyleRule::kStyle:
case StyleRule::kImport:
case StyleRule::kMedia:
@@ -210,14 +212,21 @@ CSSValue* ConsumeAdvanceOverride(CSSParserTokenRange& range,
const CSSParserContext& context) {
if (!RuntimeEnabledFeatures::CSSFontFaceAdvanceOverrideEnabled())
return nullptr;
- return css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll);
-}
-
-CSSValue* ConsumeAdvanceProportionalOverride(CSSParserTokenRange& range,
- const CSSParserContext& context) {
- if (!RuntimeEnabledFeatures::CSSFontFaceAdvanceProportionalOverrideEnabled())
+ if (CSSIdentifierValue* normal =
+ css_parsing_utils::ConsumeIdent<CSSValueID::kNormal>(range)) {
+ return normal;
+ }
+ CSSValue* override_horizontal =
+ css_parsing_utils::ConsumePercent(range, context, kValueRangeNonNegative);
+ if (!override_horizontal)
return nullptr;
- return ConsumeFontMetricOverride(range, context);
+ CSSValue* override_vertical_upright =
+ css_parsing_utils::ConsumePercent(range, context, kValueRangeNonNegative);
+ if (!override_vertical_upright)
+ override_vertical_upright = override_horizontal;
+ return MakeGarbageCollected<CSSValuePair>(override_horizontal,
+ override_vertical_upright,
+ CSSValuePair::kDropIdenticalValues);
}
} // namespace
@@ -277,9 +286,6 @@ CSSValue* AtRuleDescriptorParser::ParseFontFaceDescriptor(
case AtRuleDescriptorID::AdvanceOverride:
parsed_value = ConsumeAdvanceOverride(range, context);
break;
- case AtRuleDescriptorID::AdvanceProportionalOverride:
- parsed_value = ConsumeAdvanceProportionalOverride(range, context);
- break;
default:
break;
}
diff --git a/chromium/third_party/blink/renderer/core/css/parser/at_rule_names.json5 b/chromium/third_party/blink/renderer/core/css/parser/at_rule_names.json5
index 37fdaf01071..100c2311f8b 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/at_rule_names.json5
+++ b/chromium/third_party/blink/renderer/core/css/parser/at_rule_names.json5
@@ -61,9 +61,6 @@
name: "advance-override"
},
{
- name: "advance-proportional-override"
- },
- {
name: "fallback",
},
{
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css.proto b/chromium/third_party/blink/renderer/core/css/parser/css.proto
index 035d4c3a23a..aaf078faa44 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css.proto
+++ b/chromium/third_party/blink/renderer/core/css/parser/css.proto
@@ -1443,7 +1443,11 @@ message Property {
OVERSCROLL_BEHAVIOR_Y = 554;
ANIMATION_TIMELINE = 555;
COUNTER_SET = 556;
- INVALID_PROPERTY = 557;
+ BORDER_START_START_RADIUS = 557;
+ BORDER_START_END_RADIUS = 558;
+ BORDER_END_START_RADIUS = 559;
+ BORDER_END_END_RADIUS = 560;
+ INVALID_PROPERTY = 561;
}
required NameId name_id = 1;
}
@@ -1507,29 +1511,29 @@ message Selector {
_INTERNAL_LIST_BOX = 4;
_INTERNAL_MEDIA_CONTROLS_OVERLAY_CAST_BUTTON = 5;
_INTERNAL_MULTI_SELECT_FOCUS = 6;
- _INTERNAL_SHADOW_HOST_HAS_APPEARANCE = 7;
- _INTERNAL_SPATIAL_NAVIGATION_FOCUS = 8;
- _INTERNAL_VIDEO_PERSISTENT = 9;
- _INTERNAL_VIDEO_PERSISTENT_ANCESTOR = 10;
- _WEBKIT_ANY_LINK = 11;
- _WEBKIT_AUTOFILL = 12;
- _WEBKIT_DRAG = 13;
- _WEBKIT_FULL_PAGE_MEDIA = 14;
- _WEBKIT_FULL_SCREEN = 15;
- _WEBKIT_FULL_SCREEN_ANCESTOR = 16;
- _WEBKIT_RESIZER = 17;
- _WEBKIT_SCROLLBAR = 18;
- _WEBKIT_SCROLLBAR_BUTTON = 19;
- _WEBKIT_SCROLLBAR_CORNER = 20;
- _WEBKIT_SCROLLBAR_THUMB = 21;
- _WEBKIT_SCROLLBAR_TRACK = 22;
- _WEBKIT_SCROLLBAR_TRACK_PIECE = 23;
- ACTIVE = 24;
- AFTER = 25;
- BACKDROP = 26;
- BEFORE = 27;
- CHECKED = 28;
- CONTENT = 29;
+ _INTERNAL_POPUP_OPEN = 7;
+ _INTERNAL_SHADOW_HOST_HAS_APPEARANCE = 8;
+ _INTERNAL_SPATIAL_NAVIGATION_FOCUS = 9;
+ _INTERNAL_VIDEO_PERSISTENT = 10;
+ _INTERNAL_VIDEO_PERSISTENT_ANCESTOR = 11;
+ _WEBKIT_ANY_LINK = 12;
+ _WEBKIT_AUTOFILL = 13;
+ _WEBKIT_DRAG = 14;
+ _WEBKIT_FULL_PAGE_MEDIA = 15;
+ _WEBKIT_FULL_SCREEN = 16;
+ _WEBKIT_FULL_SCREEN_ANCESTOR = 17;
+ _WEBKIT_RESIZER = 18;
+ _WEBKIT_SCROLLBAR = 19;
+ _WEBKIT_SCROLLBAR_BUTTON = 20;
+ _WEBKIT_SCROLLBAR_CORNER = 21;
+ _WEBKIT_SCROLLBAR_THUMB = 22;
+ _WEBKIT_SCROLLBAR_TRACK = 23;
+ _WEBKIT_SCROLLBAR_TRACK_PIECE = 24;
+ ACTIVE = 25;
+ AFTER = 26;
+ BACKDROP = 27;
+ BEFORE = 28;
+ CHECKED = 29;
CORNER_PRESENT = 30;
CUE = 31;
DECREMENT = 32;
@@ -1575,25 +1579,24 @@ message Selector {
ROOT = 72;
SCOPE = 73;
SELECTION = 74;
- SHADOW = 75;
- SINGLE_BUTTON = 76;
- START = 77;
- TARGET = 78;
- UNRESOLVED = 79;
- VALID = 80;
- VERTICAL = 81;
- VISITED = 82;
- WINDOW_INACTIVE = 83;
- _WEBKIT_ANY = 84;
- HOST_CONTEXT = 85;
- LANG = 86;
- NOT = 87;
- NTH_CHILD = 88;
- NTH_LAST_CHILD = 89;
- NTH_LAST_OF_TYPE = 90;
- NTH_OF_TYPE = 91;
- SLOTTED = 92;
- INVALID_PSEUDO_VALUE = 93;
+ SINGLE_BUTTON = 75;
+ START = 76;
+ TARGET = 77;
+ VALID = 78;
+ VERTICAL = 79;
+ VISITED = 80;
+ WINDOW_INACTIVE = 81;
+ _WEBKIT_ANY = 82;
+ HOST_CONTEXT = 83;
+ LANG = 84;
+ NOT = 85;
+ NTH_CHILD = 86;
+ NTH_LAST_CHILD = 87;
+ NTH_LAST_OF_TYPE = 88;
+ NTH_OF_TYPE = 89;
+ SLOTTED = 90;
+ XR_OVERLAY = 91;
+ INVALID_PSEUDO_VALUE = 92;
}
optional PseudoValueId pseudo_value_id = 4;
required Combinator combinator = 5;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc b/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
index b5280fd284f..050c681591d 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
@@ -27,6 +27,11 @@ CSSAtRuleID CssAtRuleID(StringView name) {
return kCSSAtRulePage;
if (EqualIgnoringASCIICase(name, "property"))
return kCSSAtRuleProperty;
+ if (EqualIgnoringASCIICase(name, "container")) {
+ if (RuntimeEnabledFeatures::CSSContainerQueriesEnabled())
+ return kCSSAtRuleContainer;
+ return kCSSAtRuleInvalid;
+ }
if (EqualIgnoringASCIICase(name, "counter-style")) {
if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled())
return kCSSAtRuleCounterStyle;
@@ -74,9 +79,12 @@ void CountAtRule(const CSSParserContext* context, CSSAtRuleID rule_id) {
case kCSSAtRuleProperty:
feature = WebFeature::kCSSAtRuleProperty;
break;
- case kCSSAtRuleCounterStyle:
- // TODO(crbug.com/687225): Add feature counter
+ case kCSSAtRuleContainer:
+ // TODO(crbug.com/1145970): Add use-counter.
return;
+ case kCSSAtRuleCounterStyle:
+ feature = WebFeature::kCSSAtRuleCounterStyle;
+ break;
case kCSSAtRuleScrollTimeline:
feature = WebFeature::kCSSAtRuleScrollTimeline;
break;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.h b/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
index 7927d2cbfb7..9ec2aa3ec04 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
@@ -21,6 +21,7 @@ enum CSSAtRuleID {
kCSSAtRuleNamespace,
kCSSAtRulePage,
kCSSAtRuleProperty,
+ kCSSAtRuleContainer,
kCSSAtRuleCounterStyle,
kCSSAtRuleScrollTimeline,
kCSSAtRuleSupports,
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser.cc
index 386f86a6b2c..24e43759b04 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser.cc
@@ -113,7 +113,7 @@ MutableCSSPropertyValueSet::SetResult CSSParser::ParseValue(
return MutableCSSPropertyValueSet::SetResult{did_parse, did_change};
}
- CSSPropertyID resolved_property = resolveCSSPropertyID(unresolved_property);
+ CSSPropertyID resolved_property = ResolveCSSPropertyID(unresolved_property);
CSSParserMode parser_mode = declaration->CssParserMode();
CSSValue* value = CSSParserFastPaths::MaybeParseValue(resolved_property,
string, parser_mode);
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
index 8ddafa76a01..797c63f628c 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.cc
@@ -53,27 +53,25 @@ CSSParserContext::CSSParserContext(const CSSParserContext* other,
is_ad_related_ = other->is_ad_related_;
}
-CSSParserContext::CSSParserContext(
- const CSSParserContext* other,
- const KURL& base_url,
- bool origin_clean,
- network::mojom::ReferrerPolicy referrer_policy,
- const WTF::TextEncoding& charset,
- const Document* use_counter_document)
- : CSSParserContext(
- base_url,
- origin_clean,
- charset,
- other->mode_,
- other->match_mode_,
- other->profile_,
- Referrer(base_url.StrippedForUseAsReferrer(), referrer_policy),
- other->is_html_document_,
- other->use_legacy_background_size_shorthand_behavior_,
- other->secure_context_mode_,
- other->world_,
- use_counter_document,
- other->resource_fetch_restriction_) {
+CSSParserContext::CSSParserContext(const CSSParserContext* other,
+ const KURL& base_url,
+ bool origin_clean,
+ const Referrer& referrer,
+ const WTF::TextEncoding& charset,
+ const Document* use_counter_document)
+ : CSSParserContext(base_url,
+ origin_clean,
+ charset,
+ other->mode_,
+ other->match_mode_,
+ other->profile_,
+ referrer,
+ other->is_html_document_,
+ other->use_legacy_background_size_shorthand_behavior_,
+ other->secure_context_mode_,
+ other->world_,
+ use_counter_document,
+ other->resource_fetch_restriction_) {
is_ad_related_ = other->is_ad_related_;
}
@@ -96,18 +94,23 @@ CSSParserContext::CSSParserContext(CSSParserMode mode,
ResourceFetchRestriction::kNone) {}
CSSParserContext::CSSParserContext(const Document& document)
- : CSSParserContext(document,
- document.BaseURL(),
- true /* origin_clean */,
- document.GetReferrerPolicy(),
- WTF::TextEncoding(),
- kLiveProfile) {}
+ : CSSParserContext(
+ document,
+ document.BaseURL(),
+ true /* origin_clean */,
+ Referrer(document.GetExecutionContext()
+ ? document.GetExecutionContext()->OutgoingReferrer()
+ : String(), // GetExecutionContext() only returns null
+ // in tests.
+ document.GetReferrerPolicy()),
+ WTF::TextEncoding(),
+ kLiveProfile) {}
CSSParserContext::CSSParserContext(
const Document& document,
const KURL& base_url_override,
bool origin_clean,
- network::mojom::ReferrerPolicy referrer_policy_override,
+ const Referrer& referrer,
const WTF::TextEncoding& charset,
SelectorProfile profile,
enum ResourceFetchRestriction resource_fetch_restriction)
@@ -122,8 +125,7 @@ CSSParserContext::CSSParserContext(
: kHTMLStandardMode)
: document.InQuirksMode() ? kHTMLQuirksMode : kHTMLStandardMode,
profile,
- Referrer(base_url_override.StrippedForUseAsReferrer(),
- referrer_policy_override),
+ referrer,
IsA<HTMLDocument>(document),
document.GetSettings()
? document.GetSettings()
@@ -213,7 +215,7 @@ const CSSParserContext* StrictCSSParserContext(
if (!context) {
context = MakeGarbageCollected<CSSParserContext>(kHTMLStandardMode,
secure_context_mode);
- context.RegisterAsStaticReference();
+ LEAK_SANITIZER_IGNORE_OBJECT(&context);
}
return context;
@@ -281,10 +283,6 @@ void CSSParserContext::ReportLayoutAnimationsViolationIfNeeded(
}
}
-bool CSSParserContext::CustomElementsV0Enabled() const {
- return RuntimeEnabledFeatures::CustomElementsV0Enabled();
-}
-
bool CSSParserContext::IsForMarkupSanitization() const {
return document_ && document_->IsForMarkupSanitization();
}
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
index 3167a5fcb82..9b654dea96c 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_context.h
@@ -42,10 +42,15 @@ class CORE_EXPORT CSSParserContext final
explicit CSSParserContext(const CSSParserContext* other,
const Document* use_counter_document = nullptr);
+ // Creates a context with most of its constructor attributes provided by
+ // copying from |other|, except that the remaining constructor arguments take
+ // precedence over the corresponding characteristics of |other|. This is
+ // useful for initializing @imported sheets' contexts, which inherit most of
+ // their characteristics from their parents.
CSSParserContext(const CSSParserContext* other,
const KURL& base_url_override,
bool origin_clean,
- network::mojom::ReferrerPolicy referrer_policy_override,
+ const Referrer& referrer,
const WTF::TextEncoding& charset_override,
const Document* use_counter_document);
CSSParserContext(CSSParserMode,
@@ -56,7 +61,7 @@ class CORE_EXPORT CSSParserContext final
CSSParserContext(const Document&,
const KURL& base_url_override,
bool origin_clean,
- network::mojom::ReferrerPolicy referrer_policy_override,
+ const Referrer& referrer,
const WTF::TextEncoding& charset = WTF::TextEncoding(),
SelectorProfile = kLiveProfile,
ResourceFetchRestriction resource_fetch_restriction =
@@ -71,7 +76,7 @@ class CORE_EXPORT CSSParserContext final
CSSParserMode,
CSSParserMode match_mode,
SelectorProfile,
- const Referrer&,
+ const Referrer& referrer,
bool is_html_document,
bool use_legacy_background_size_shorthand_behavior,
SecureContextMode,
@@ -137,9 +142,6 @@ class CORE_EXPORT CSSParserContext final
// report (https://crbug.com/906150, ).
void ReportLayoutAnimationsViolationIfNeeded(const StyleRuleKeyframe&) const;
- // TODO(yoichio): Remove when CustomElementsV0 is removed. crrev.com/660759.
- bool CustomElementsV0Enabled() const;
-
bool IsForMarkupSanitization() const;
// Overrides |mode_| of a CSSParserContext within the scope, allowing us to
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
index 926639cabc9..67c06ff2161 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
@@ -651,10 +651,6 @@ bool CSSParserFastPaths::IsValidKeywordPropertyAndValue(
case CSSPropertyID::kListStylePosition:
return value_id == CSSValueID::kInside ||
value_id == CSSValueID::kOutside;
- case CSSPropertyID::kListStyleType:
- return (value_id >= CSSValueID::kDisc &&
- value_id <= CSSValueID::kKatakanaIroha) ||
- value_id == CSSValueID::kNone;
case CSSPropertyID::kMaskType:
return value_id == CSSValueID::kLuminance ||
value_id == CSSValueID::kAlpha;
@@ -1035,7 +1031,6 @@ bool CSSParserFastPaths::IsKeywordPropertyID(CSSPropertyID property_id) {
case CSSPropertyID::kHyphens:
case CSSPropertyID::kImageRendering:
case CSSPropertyID::kListStylePosition:
- case CSSPropertyID::kListStyleType:
case CSSPropertyID::kMaskType:
case CSSPropertyID::kMathShift:
case CSSPropertyID::kMathStyle:
@@ -1123,15 +1118,6 @@ bool CSSParserFastPaths::IsKeywordPropertyID(CSSPropertyID property_id) {
}
}
-bool CSSParserFastPaths::IsPartialKeywordPropertyID(CSSPropertyID property_id) {
- switch (property_id) {
- case CSSPropertyID::kListStyleType:
- return true;
- default:
- return false;
- }
-}
-
static CSSValue* ParseKeywordValue(CSSPropertyID property_id,
const String& string,
CSSParserMode parser_mode) {
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h
index 943767ecaa7..85a29d953ae 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h
@@ -28,10 +28,6 @@ class CORE_EXPORT CSSParserFastPaths {
// CSSPropertyParser
static bool IsKeywordPropertyID(CSSPropertyID);
- // Returns if a property should be handled by the fast path, but have other
- // non-keyword values which should be handled by the CSSPropertyParser.
- static bool IsPartialKeywordPropertyID(CSSPropertyID);
-
static bool IsValidKeywordPropertyAndValue(CSSPropertyID,
CSSValueID,
CSSParserMode);
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths_fuzzer.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths_fuzzer.cc
index 004c9cafa37..144bf6e3e4e 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_fast_paths_fuzzer.cc
@@ -18,7 +18,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
blink::FuzzedDataProvider provider(data, size);
const auto property_id =
- blink::convertToCSSPropertyID(provider.ConsumeIntegralInRange<int>(
+ blink::ConvertToCSSPropertyID(provider.ConsumeIntegralInRange<int>(
blink::kIntFirstCSSProperty, blink::kIntLastCSSProperty));
const auto data_string = provider.ConsumeRemainingBytes();
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
index 55c4c9eaef2..167f96e88df 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/css/parser/media_query_parser.h"
#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
#include "third_party/blink/renderer/core/css/property_registry.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
#include "third_party/blink/renderer/core/css/style_rule_import.h"
#include "third_party/blink/renderer/core/css/style_rule_keyframe.h"
#include "third_party/blink/renderer/core/css/style_rule_namespace.h"
@@ -123,7 +124,7 @@ static inline void FilterProperties(
const HeapVector<CSSPropertyValue, 256>& input,
HeapVector<CSSPropertyValue, 256>& output,
wtf_size_t& unused_entries,
- std::bitset<numCSSProperties>& seen_properties,
+ std::bitset<kNumCSSProperties>& seen_properties,
HashSet<AtomicString>& seen_custom_properties) {
// Add properties in reverse order so that highest priority definitions are
// reached first. Duplicate definitions can then be ignored when found.
@@ -150,7 +151,7 @@ static inline void FilterProperties(
static ImmutableCSSPropertyValueSet* CreateCSSPropertyValueSet(
HeapVector<CSSPropertyValue, 256>& parsed_properties,
CSSParserMode mode) {
- std::bitset<numCSSProperties> seen_properties;
+ std::bitset<kNumCSSProperties> seen_properties;
wtf_size_t unused_entries = parsed_properties.size();
HeapVector<CSSPropertyValue, 256> results(unused_entries);
HashSet<AtomicString> seen_custom_properties;
@@ -210,7 +211,7 @@ bool CSSParserImpl::ParseDeclarationList(
if (parser.parsed_properties_.IsEmpty())
return false;
- std::bitset<numCSSProperties> seen_properties;
+ std::bitset<kNumCSSProperties> seen_properties;
wtf_size_t unused_entries = parser.parsed_properties_.size();
HeapVector<CSSPropertyValue, 256> results(unused_entries);
HashSet<AtomicString> seen_custom_properties;
@@ -545,6 +546,8 @@ StyleRuleBase* CSSParserImpl::ConsumeAtRule(CSSParserTokenStream& stream,
DCHECK_LE(allowed_rules, kRegularRules);
switch (id) {
+ case kCSSAtRuleContainer:
+ return ConsumeContainerRule(stream);
case kCSSAtRuleMedia:
return ConsumeMediaRule(stream);
case kCSSAtRuleSupports:
@@ -939,15 +942,11 @@ StyleRuleCounterStyle* CSSParserImpl::ConsumeCounterStyleRule(
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
- const CSSParserToken& name_token = prelude.ConsumeIncludingWhitespace();
- if (!prelude.AtEnd())
+ AtomicString name = css_parsing_utils::ConsumeCounterStyleNameInPrelude(
+ prelude, *GetContext());
+ if (!name)
return nullptr;
- // TODO(crbug.com/687225): If the name is invalid (none, decimal, disc and
- // CSS-wide keywords), should the entire rule be invalid, or does it simply
- // not define a counter style?
- AtomicString name(name_token.Value().ToString());
-
if (observer_) {
observer_->StartRuleHeader(StyleRule::kCounterStyle, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
@@ -988,6 +987,40 @@ StyleRuleScrollTimeline* CSSParserImpl::ConsumeScrollTimelineRule(
name, CreateCSSPropertyValueSet(parsed_properties_, context_->Mode()));
}
+StyleRuleContainer* CSSParserImpl::ConsumeContainerRule(
+ CSSParserTokenStream& stream) {
+ wtf_size_t prelude_offset_start = stream.LookAheadOffset();
+ CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
+ wtf_size_t prelude_offset_end = stream.LookAheadOffset();
+ if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
+ return nullptr;
+ CSSParserTokenStream::BlockGuard guard(stream);
+
+ if (observer_) {
+ observer_->StartRuleHeader(StyleRule::kContainer, prelude_offset_start);
+ observer_->EndRuleHeader(prelude_offset_end);
+ observer_->StartRuleBody(stream.Offset());
+ }
+
+ // TODO(crbug.com/1145970): Restrict what is allowed by @container.
+ scoped_refptr<MediaQuerySet> media_queries =
+ MediaQueryParser::ParseMediaQuerySet(prelude,
+ context_->GetExecutionContext());
+ if (!media_queries)
+ return nullptr;
+ ContainerQuery* container_query =
+ MakeGarbageCollected<ContainerQuery>(media_queries);
+
+ HeapVector<Member<StyleRuleBase>> rules;
+ ConsumeRuleList(stream, kRegularRuleList,
+ [&rules](StyleRuleBase* rule) { rules.push_back(rule); });
+
+ if (observer_)
+ observer_->EndRuleBody(stream.Offset());
+
+ return MakeGarbageCollected<StyleRuleContainer>(*container_query, rules);
+}
+
StyleRuleKeyframe* CSSParserImpl::ConsumeKeyframeStyleRule(
const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
@@ -1057,6 +1090,7 @@ void CSSParserImpl::ConsumeDeclarationList(CSSParserTokenStream& stream,
bool use_observer = observer_ && (rule_type == StyleRule::kStyle ||
rule_type == StyleRule::kProperty ||
+ rule_type == StyleRule::kContainer ||
rule_type == StyleRule::kCounterStyle ||
rule_type == StyleRule::kScrollTimeline ||
rule_type == StyleRule::kKeyframe);
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.h
index 8e5ddadd9c3..34c728d8000 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl.h
@@ -27,6 +27,7 @@ class CSSParserTokenStream;
class StyleRule;
class StyleRuleBase;
class StyleRuleCharset;
+class StyleRuleCounterStyle;
class StyleRuleFontFace;
class StyleRuleImport;
class StyleRuleKeyframe;
@@ -167,6 +168,7 @@ class CORE_EXPORT CSSParserImpl {
StyleRuleProperty* ConsumePropertyRule(CSSParserTokenStream&);
StyleRuleCounterStyle* ConsumeCounterStyleRule(CSSParserTokenStream&);
StyleRuleScrollTimeline* ConsumeScrollTimelineRule(CSSParserTokenStream&);
+ StyleRuleContainer* ConsumeContainerRule(CSSParserTokenStream&);
StyleRuleKeyframe* ConsumeKeyframeStyleRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
index 19fe15463b5..682bfe979af 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
@@ -6,10 +6,12 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/css_test_helpers.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_observer.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_token_stream.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
+#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -225,6 +227,40 @@ TEST(CSSParserImplTest, AtCounterStyleDisabled) {
EXPECT_EQ(style_sheet->ChildRules().size(), 0u);
}
+TEST(CSSParserImplTest, AtContainerOffsets) {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
+
+ String sheet_text = "@container (max-width: 100px) { }";
+
+ auto* context = MakeGarbageCollected<CSSParserContext>(
+ kHTMLStandardMode, SecureContextMode::kInsecureContext);
+ auto* style_sheet = MakeGarbageCollected<StyleSheetContents>(context);
+ TestCSSParserObserver test_css_parser_observer;
+ CSSParserImpl::ParseStyleSheetForInspector(sheet_text, context, style_sheet,
+ test_css_parser_observer);
+ EXPECT_EQ(style_sheet->ChildRules().size(), 1u);
+ EXPECT_EQ(test_css_parser_observer.rule_type_,
+ StyleRule::RuleType::kContainer);
+ EXPECT_EQ(test_css_parser_observer.rule_header_start_, 11u);
+ EXPECT_EQ(test_css_parser_observer.rule_header_end_, 30u);
+ EXPECT_EQ(test_css_parser_observer.rule_body_start_, 31u);
+ EXPECT_EQ(test_css_parser_observer.rule_body_end_, 32u);
+}
+
+TEST(CSSParserImplTest, AtContainerDisabled) {
+ String rule = "@container (max-width: 100px) { }";
+ {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
+ Document* document = Document::CreateForTest();
+ EXPECT_TRUE(css_test_helpers::ParseRule(*document, rule));
+ }
+ {
+ ScopedCSSContainerQueriesForTest scoped_feature(false);
+ Document* document = Document::CreateForTest();
+ EXPECT_FALSE(css_test_helpers::ParseRule(*document, rule));
+ }
+}
+
TEST(CSSParserImplTest, RemoveImportantAnnotationIfPresent) {
struct TestCase {
String input;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.cc b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.cc
index bba675bec73..362d4faef74 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.cc
@@ -96,8 +96,8 @@ RelationType CSSParserSelector::GetImplicitShadowCombinatorForMatching() const {
case PseudoType::kPseudoBlinkInternalElement:
case PseudoType::kPseudoCue:
case PseudoType::kPseudoPlaceholder:
- case PseudoType::kPseudoShadow:
- return RelationType::kShadowPseudo;
+ case PseudoType::kPseudoFileSelectorButton:
+ return RelationType::kUAShadow;
case PseudoType::kPseudoPart:
return RelationType::kShadowPart;
default:
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
index d7cc0bd3556..7176d628433 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_parser_selector.h
@@ -64,12 +64,6 @@ class CORE_EXPORT CSSParserSelector {
selector_->SetRelation(value);
}
void SetForPage() { selector_->SetForPage(); }
- void SetRelationIsAffectedByPseudoContent() {
- selector_->SetRelationIsAffectedByPseudoContent();
- }
- bool RelationIsAffectedByPseudoContent() const {
- return selector_->RelationIsAffectedByPseudoContent();
- }
void UpdatePseudoType(const AtomicString& value,
const CSSParserContext& context,
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser.cc
index cdb60c429c6..72a0f4d06b1 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser.cc
@@ -75,7 +75,7 @@ bool CSSPropertyParser::ParseValue(
int parsed_properties_size = parsed_properties.size();
CSSPropertyParser parser(range, context, &parsed_properties);
- CSSPropertyID resolved_property = resolveCSSPropertyID(unresolved_property);
+ CSSPropertyID resolved_property = ResolveCSSPropertyID(unresolved_property);
bool parse_success;
if (rule_type == StyleRule::kViewport) {
parse_success =
@@ -120,7 +120,7 @@ bool CSSPropertyParser::ParseValueStart(CSSPropertyID unresolved_property,
return true;
CSSParserTokenRange original_range = range_;
- CSSPropertyID property_id = resolveCSSPropertyID(unresolved_property);
+ CSSPropertyID property_id = ResolveCSSPropertyID(unresolved_property);
const CSSProperty& property = CSSProperty::Get(property_id);
// If a CSSPropertyID is only a known descriptor (@fontface, @property), not a
// style property, it will not be a valid declaration.
@@ -131,7 +131,7 @@ bool CSSPropertyParser::ParseValueStart(CSSPropertyID unresolved_property,
if (is_shorthand) {
const auto local_context =
CSSParserLocalContext()
- .WithAliasParsing(isPropertyAlias(unresolved_property))
+ .WithAliasParsing(IsPropertyAlias(unresolved_property))
.WithCurrentShorthand(property_id);
// Variable references will fail to parse here and will fall out to the
// variable ref parser below.
@@ -191,10 +191,10 @@ static CSSPropertyID UnresolvedCSSPropertyID(
return CSSPropertyID::kInvalid;
if (length >= 2 && property_name[0] == '-' && property_name[1] == '-')
return CSSPropertyID::kVariable;
- if (length > maxCSSPropertyNameLength)
+ if (length > kMaxCSSPropertyNameLength)
return CSSPropertyID::kInvalid;
- char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
+ char buffer[kMaxCSSPropertyNameLength + 1]; // 1 for null character
for (unsigned i = 0; i != length; ++i) {
CharacterType c = property_name[i];
@@ -210,12 +210,12 @@ static CSSPropertyID UnresolvedCSSPropertyID(
return CSSPropertyID::kInvalid;
CSSPropertyID property_id = static_cast<CSSPropertyID>(hash_table_entry->id);
const CSSProperty& property =
- CSSProperty::Get(resolveCSSPropertyID(property_id));
+ CSSProperty::Get(ResolveCSSPropertyID(property_id));
bool exposed = IsExposedInMode(execution_context, property, mode);
return exposed ? property_id : CSSPropertyID::kInvalid;
}
-CSSPropertyID unresolvedCSSPropertyID(const ExecutionContext* execution_context,
+CSSPropertyID UnresolvedCSSPropertyID(const ExecutionContext* execution_context,
const String& string) {
return WTF::VisitCharacters(string, [&](const auto* chars, unsigned length) {
return UnresolvedCSSPropertyID(execution_context, chars, length,
@@ -268,7 +268,7 @@ bool CSSPropertyParser::ConsumeCSSWideKeyword(CSSPropertyID unresolved_property,
if (!value)
return false;
- CSSPropertyID property = resolveCSSPropertyID(unresolved_property);
+ CSSPropertyID property = ResolveCSSPropertyID(unresolved_property);
const StylePropertyShorthand& shorthand = shorthandForProperty(property);
if (!shorthand.length()) {
if (!CSSProperty::Get(property).IsProperty())
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
index 75295a5a33a..cf864264775 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
@@ -387,8 +387,8 @@ TEST(CSSPropertyParserTest, GradientUseCount) {
TEST(CSSPropertyParserTest, PaintUseCount) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
dummy_page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("https://example.com")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("https://example.com")),
nullptr /* extra_data */);
Document& document = dummy_page_holder->GetDocument();
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.cc b/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
index bb573c1bd82..10f9bce4051 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
@@ -42,6 +42,7 @@ const std::string Converter::kPseudoLookupTable[] = {
"-internal-list-box",
"-internal-media-controls-overlay-cast-button",
"-internal-multi-select-focus",
+ "-internal-popup-open",
"-internal-shadow-host-has-appearance",
"-internal-spatial-navigation-focus",
"-internal-video-persistent",
@@ -64,7 +65,6 @@ const std::string Converter::kPseudoLookupTable[] = {
"backdrop",
"before",
"checked",
- "content",
"corner-present",
"cue",
"decrement",
@@ -110,11 +110,9 @@ const std::string Converter::kPseudoLookupTable[] = {
"root",
"scope",
"selection",
- "shadow",
"single-button",
"start",
"target",
- "unresolved",
"valid",
"vertical",
"visited",
@@ -1527,6 +1525,10 @@ const std::string Converter::kPropertyLookupTable[] = {
"overscroll-behavior-y",
"animation-timeline",
"counter-set",
+ "border-start-start-radius",
+ "border-start-end-radius",
+ "border-end-start-radius",
+ "border-end-end-radius",
"INVALID_PROPERTY",
};
@@ -1721,25 +1723,30 @@ void Converter::Visit(const StyleSheet& style_sheet) {
}
void Converter::Visit(const ViewportValue& viewport_value) {
- if (viewport_value.has_length())
+ if (viewport_value.has_length()) {
Visit(viewport_value.length());
- else if (viewport_value.has_num())
+ } else if (viewport_value.has_num()) {
Visit(viewport_value.num());
- else // Default value.
- AppendTableValue(viewport_value.value_id(), kViewportValueLookupTable);
+ } else { // Default value.
+ AppendTableValue<ViewportValue_ValueId_ValueId_ARRAYSIZE>(
+ viewport_value.value_id(), kViewportValueLookupTable);
+ }
}
void Converter::Visit(const Viewport& viewport) {
string_ += " @viewport {";
- for (auto& property_and_value : viewport.properties_and_values())
- AppendPropertyAndValue(property_and_value, kViewportPropertyLookupTable);
+ for (auto& property_and_value : viewport.properties_and_values()) {
+ AppendPropertyAndValue<ViewportProperty_PropertyId_PropertyId_ARRAYSIZE>(
+ property_and_value, kViewportPropertyLookupTable);
+ }
string_ += " } ";
}
void Converter::Visit(const CharsetDeclaration& charset_declaration) {
string_ += "@charset "; // CHARSET_SYM
string_ += "\"";
- AppendTableValue(charset_declaration.encoding_id(), kEncodingLookupTable);
+ AppendTableValue<CharsetDeclaration_EncodingId_EncodingId_ARRAYSIZE>(
+ charset_declaration.encoding_id(), kEncodingLookupTable);
string_ += "\"; ";
}
@@ -1817,7 +1824,8 @@ void Converter::Visit(const SupportsCondition& supports_condition, int depth) {
void Converter::Visit(const Import& import) {
string_ += "@import ";
- AppendTableValue(import.src_id(), kImportLookupTable);
+ AppendTableValue<Import_SrcId_SrcId_ARRAYSIZE>(import.src_id(),
+ kImportLookupTable);
string_ += " ";
if (import.has_media_query_list())
Visit(import.media_query_list());
@@ -1879,7 +1887,8 @@ void Converter::Visit(const MediaConditionWithoutOr& media_condition) {
}
void Converter::Visit(const MediaType& media_type) {
- AppendTableValue(media_type.value_id(), kMediaTypeLookupTable);
+ AppendTableValue<MediaType_ValueId_ValueId_ARRAYSIZE>(media_type.value_id(),
+ kMediaTypeLookupTable);
}
void Converter::Visit(const MediaNot& media_not) {
@@ -1922,7 +1931,8 @@ void Converter::Visit(const MediaFeature& media_feature) {
if (media_feature.has_mf_bool()) {
Visit(media_feature.mf_bool());
} else if (media_feature.has_mf_plain()) {
- AppendPropertyAndValue(media_feature.mf_plain(), kMfNameLookupTable, false);
+ AppendPropertyAndValue<MfName_ValueId_ValueId_ARRAYSIZE>(
+ media_feature.mf_plain(), kMfNameLookupTable, false);
}
string_ += ")";
}
@@ -1932,7 +1942,8 @@ void Converter::Visit(const MfBool& mf_bool) {
}
void Converter::Visit(const MfName& mf_name) {
- AppendTableValue(mf_name.id(), kMfNameLookupTable);
+ AppendTableValue<MfName_ValueId_ValueId_ARRAYSIZE>(mf_name.id(),
+ kMfNameLookupTable);
}
void Converter::Visit(const MfValue& mf_value) {
@@ -2014,7 +2025,8 @@ void Converter::Visit(const UnaryOperator& unary_operator) {
}
void Converter::Visit(const Property& property) {
- AppendTableValue(property.name_id(), kPropertyLookupTable);
+ AppendTableValue<Property_NameId_NameId_ARRAYSIZE>(property.name_id(),
+ kPropertyLookupTable);
}
void Converter::Visit(const Ruleset& ruleset) {
@@ -2066,7 +2078,8 @@ void Converter::Visit(const Selector& selector, bool is_first) {
string_ += ":";
if (selector.pseudo_type() == PseudoType::ELEMENT)
string_ += ":";
- AppendTableValue(selector.pseudo_value_id(), kPseudoLookupTable);
+ AppendTableValue<Selector_PseudoValueId_PseudoValueId_ARRAYSIZE>(
+ selector.pseudo_value_id(), kPseudoLookupTable);
}
}
@@ -2088,10 +2101,12 @@ void Converter::Visit(const PropertyAndValue& property_and_value) {
}
void Converter::Visit(const Expr& expr, int declaration_value_id) {
- if (!declaration_value_id)
+ if (!declaration_value_id) {
Visit(expr.term());
- else
- AppendTableValue(declaration_value_id, kValueLookupTable);
+ } else {
+ AppendTableValue<PropertyAndValue_ValueId_ValueId_ARRAYSIZE>(
+ declaration_value_id, kValueLookupTable);
+ }
for (auto& operator_term : expr.operator_terms())
Visit(operator_term);
}
@@ -2177,19 +2192,22 @@ void Converter::Reset() {
string_.clear();
}
-template <size_t TableSize>
+template <size_t EnumSize, size_t TableSize>
void Converter::AppendTableValue(int id,
const std::string (&lookup_table)[TableSize]) {
+ // If you hit this assert, you likely need to modify css/parser/css.proto.
+ static_assert(EnumSize == TableSize,
+ "Enum used as index should not overflow lookup table");
CHECK(id > 0 && static_cast<size_t>(id) < TableSize);
string_ += lookup_table[id];
}
-template <class T, size_t TableSize>
+template <size_t EnumSize, class T, size_t TableSize>
void Converter::AppendPropertyAndValue(
T property_and_value,
const std::string (&lookup_table)[TableSize],
bool append_semicolon) {
- AppendTableValue(property_and_value.property().id(), lookup_table);
+ AppendTableValue<EnumSize>(property_and_value.property().id(), lookup_table);
string_ += " : ";
Visit(property_and_value.value());
if (append_semicolon)
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.h b/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.h
index 167e8170e3f..76f0bb84676 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_proto_converter.h
@@ -105,11 +105,11 @@ class Converter {
void Visit(const AtRuleOrRuleset&, int depth);
void Reset();
- template <class T, size_t TableSize>
+ template <size_t EnumSize, class T, size_t TableSize>
void AppendPropertyAndValue(T property_and_value,
const std::string (&lookup_table)[TableSize],
bool append_semicolon = true);
- template <size_t TableSize>
+ template <size_t EnumSize, size_t TableSize>
void AppendTableValue(int id, const std::string (&lookup_table)[TableSize]);
};
} // namespace css_proto_converter
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
index c6e016e0ca7..cb5fbbfa0f9 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -34,7 +34,7 @@ CSSParserTokenRange ConsumeNestedArgument(CSSParserTokenRange& range) {
return range.MakeSubRange(&first, &range.Peek());
}
-bool AtEndIgnoringWhitepace(CSSParserTokenRange range) {
+bool AtEndIgnoringWhitespace(CSSParserTokenRange range) {
range.ConsumeWhitespace();
return range.AtEnd();
}
@@ -228,17 +228,12 @@ namespace {
enum CompoundSelectorFlags {
kHasPseudoElementForRightmostCompound = 1 << 0,
- kHasContentPseudoElement = 1 << 1
};
unsigned ExtractCompoundFlags(const CSSParserSelector& simple_selector,
CSSParserMode parser_mode) {
if (simple_selector.Match() != CSSSelector::kPseudoElement)
return 0;
- if (simple_selector.GetPseudoType() == CSSSelector::kPseudoContent)
- return kHasContentPseudoElement;
- if (simple_selector.GetPseudoType() == CSSSelector::kPseudoShadow)
- return 0;
// We don't restrict what follows custom ::-webkit-* pseudo elements in UA
// sheets. We currently use selectors in mediaControls.css like this:
//
@@ -279,8 +274,6 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumeComplexSelector(
compound_flags |= ExtractCompoundFlags(*end, context_->Mode());
}
end->SetRelation(combinator);
- if (previous_compound_flags & kHasContentPseudoElement)
- end->SetRelationIsAffectedByPseudoContent();
previous_compound_flags = compound_flags;
end->SetTagHistory(std::move(selector));
@@ -365,8 +358,6 @@ bool IsSimpleSelectorValidAfterPseudoElement(
RuntimeEnabledFeatures::CSSMarkerNestedPseudoElementEnabled())
return true;
break;
- case CSSSelector::kPseudoContent:
- return simple_selector.Match() != CSSSelector::kPseudoElement;
case CSSSelector::kPseudoSlotted:
return simple_selector.IsTreeAbidingPseudoElement();
case CSSSelector::kPseudoPart:
@@ -436,8 +427,9 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumeCompoundSelector(
// [1] https://drafts.csswg.org/selectors/#matches
// [2] https://drafts.csswg.org/selectors/#selector-subject
base::AutoReset<bool> ignore_namespace(
- &ignore_default_namespace_, resist_default_namespace_ && !has_q_name &&
- AtEndIgnoringWhitepace(range));
+ &ignore_default_namespace_,
+ ignore_default_namespace_ || (resist_default_namespace_ && !has_q_name &&
+ AtEndIgnoringWhitespace(range)));
if (!compound_selector) {
AtomicString namespace_uri = DetermineNamespace(namespace_prefix);
@@ -636,7 +628,7 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
selector->SetMatch(colons == 1 ? CSSSelector::kPseudoClass
: CSSSelector::kPseudoElement);
- AtomicString value = token.Value().ToAtomicString().LowerASCII();
+ AtomicString value = token.Value().ToAtomicString();
bool has_arguments = token.GetType() == kFunctionToken;
selector->UpdatePseudoType(value, *context_, has_arguments, context_->Mode());
@@ -647,17 +639,8 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
context_->Count(WebFeature::kHasBeforeOrAfterPseudoElement);
break;
case CSSSelector::kPseudoMarker:
- if (context_->Mode() != kUASheetMode) {
+ if (context_->Mode() != kUASheetMode)
context_->Count(WebFeature::kHasMarkerPseudoElement);
- if (!RuntimeEnabledFeatures::CSSMarkerPseudoElementEnabled())
- return nullptr;
- }
- break;
- case CSSSelector::kPseudoShadow:
- case CSSSelector::kPseudoContent:
- if (disallow_shadow_dom_v0_)
- return nullptr;
- disallow_nested_complex_ = true;
break;
default:
break;
@@ -684,9 +667,6 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
case CSSSelector::kPseudoIs: {
if (!RuntimeEnabledFeatures::CSSPseudoIsEnabled())
break;
- if (disallow_nested_complex_)
- return nullptr;
- disallow_shadow_dom_v0_ = true;
DisallowPseudoElementsScope scope(this);
base::AutoReset<bool> resist_namespace(&resist_default_namespace_, true);
@@ -702,9 +682,6 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
case CSSSelector::kPseudoWhere: {
if (!RuntimeEnabledFeatures::CSSPseudoWhereEnabled())
break;
- if (disallow_nested_complex_)
- return nullptr;
- disallow_shadow_dom_v0_ = true;
DisallowPseudoElementsScope scope(this);
base::AutoReset<bool> resist_namespace(&resist_default_namespace_, true);
@@ -723,6 +700,10 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
case CSSSelector::kPseudoCue: {
DisallowPseudoElementsScope scope(this);
base::AutoReset<bool> inside_compound(&inside_compound_pseudo_, true);
+ base::AutoReset<bool> ignore_namespace(
+ &ignore_default_namespace_,
+ ignore_default_namespace_ ||
+ selector->GetPseudoType() == CSSSelector::kPseudoCue);
std::unique_ptr<CSSSelectorList> selector_list =
std::make_unique<CSSSelectorList>();
@@ -750,19 +731,10 @@ std::unique_ptr<CSSParserSelector> CSSSelectorParser::ConsumePseudo(
if (!selector_list->IsValid() || !block.AtEnd())
return nullptr;
- // The initial implementation of :not() supported a single "simple"
- // compound selector. For backwards compatibility, we still support
- // ShadowDOM v0 features in this case.
- if (!selector_list->TreatAsNonComplexArgumentToNot()) {
- if (disallow_nested_complex_)
- return nullptr;
- disallow_shadow_dom_v0_ = true;
- }
-
selector->SetSelectorList(std::move(selector_list));
return selector;
}
- case CSSSelector::kPseudoState: {
+ case CSSSelector::kPseudoDir: {
const CSSParserToken& ident = block.ConsumeIncludingWhitespace();
if (ident.GetType() != kIdentToken || !block.AtEnd())
return nullptr;
@@ -846,24 +818,6 @@ CSSSelector::RelationType CSSSelectorParser::ConsumeCombinator(
range.ConsumeIncludingWhitespace();
return CSSSelector::kChild;
- case '/': {
- // Match /deep/
- range.Consume();
- const CSSParserToken& ident = range.Consume();
- if (ident.GetType() != kIdentToken ||
- !EqualIgnoringASCIICase(ident.Value(), "deep"))
- failed_parsing_ = true;
- const CSSParserToken& slash = range.ConsumeIncludingWhitespace();
- if (slash.GetType() != kDelimiterToken || slash.Delimiter() != '/')
- failed_parsing_ = true;
- if (disallow_shadow_dom_v0_)
- failed_parsing_ = true;
- else
- disallow_nested_complex_ = true;
- return context_->IsLiveProfile() ? CSSSelector::kShadowDeepAsDescendant
- : CSSSelector::kShadowDeep;
- }
-
default:
break;
}
@@ -901,6 +855,9 @@ CSSSelector::AttributeMatchType CSSSelectorParser::ConsumeAttributeFlags(
const CSSParserToken& flag = range.ConsumeIncludingWhitespace();
if (EqualIgnoringASCIICase(flag.Value(), "i"))
return CSSSelector::AttributeMatchType::kCaseInsensitive;
+ else if (EqualIgnoringASCIICase(flag.Value(), "s") &&
+ RuntimeEnabledFeatures::CSSCaseSensitiveSelectorEnabled())
+ return CSSSelector::AttributeMatchType::kCaseSensitiveAlways;
failed_parsing_ = true;
return CSSSelector::AttributeMatchType::kCaseSensitive;
}
@@ -1282,19 +1239,12 @@ void CSSSelectorParser::RecordUsageAndDeprecations(
DCHECK(RuntimeEnabledFeatures::CSSPseudoWhereEnabled());
feature = WebFeature::kCSSSelectorPseudoWhere;
break;
- case CSSSelector::kPseudoUnresolved:
- DCHECK(context_->CustomElementsV0Enabled());
- feature = WebFeature::kCSSSelectorPseudoUnresolved;
- break;
case CSSSelector::kPseudoDefined:
feature = WebFeature::kCSSSelectorPseudoDefined;
break;
case CSSSelector::kPseudoSlotted:
feature = WebFeature::kCSSSelectorPseudoSlotted;
break;
- case CSSSelector::kPseudoContent:
- feature = WebFeature::kCSSSelectorPseudoContent;
- break;
case CSSSelector::kPseudoHost:
feature = WebFeature::kCSSSelectorPseudoHost;
break;
@@ -1323,6 +1273,10 @@ void CSSSelectorParser::RecordUsageAndDeprecations(
case CSSSelector::kPseudoReadWrite:
feature = WebFeature::kCSSSelectorPseudoReadWrite;
break;
+ case CSSSelector::kPseudoDir:
+ DCHECK(RuntimeEnabledFeatures::CSSPseudoDirEnabled());
+ feature = WebFeature::kCSSSelectorPseudoDir;
+ break;
default:
break;
}
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.h b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.h
index c500482c188..87f205545d9 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.h
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser.h
@@ -97,12 +97,6 @@ class CORE_EXPORT CSSSelectorParser {
bool failed_parsing_ = false;
bool disallow_pseudo_elements_ = false;
- // We don't allow mixing ShadowDOMv0 features and nested complex selectors,
- // such as :is(). When :is() or :where() is encountered, ShadowDOM V0 features
- // are disallowed, and whenever /deep/, ::content or ::shadow is encountered
- // we disallow :is()/:where().
- bool disallow_shadow_dom_v0_ = false;
- bool disallow_nested_complex_ = false;
// If we're inside a pseudo class that only accepts compound selectors,
// for example :host, inner :is()/:where() pseudo classes are also only
// allowed to contain compound selectors.
diff --git a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
index abe7d825eed..69a4546f446 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
@@ -140,28 +140,6 @@ TEST(CSSSelectorParserTest, InvalidANPlusB) {
}
}
-TEST(CSSSelectorParserTest, ShadowDomPseudoInCompound) {
- const char* test_cases[][2] = {{"::content", "::content"},
- {".a::content", ".a::content"},
- {"::content.a", "::content.a"},
- {"::content.a.b", "::content.a.b"},
- {".a::content.b", ".a::content.b"},
- {"::content:not(#id)", "::content:not(#id)"}};
-
- for (auto** test_case : test_cases) {
- SCOPED_TRACE(test_case[0]);
- CSSTokenizer tokenizer(test_case[0]);
- const auto tokens = tokenizer.TokenizeToEOF();
- CSSParserTokenRange range(tokens);
- CSSSelectorList list = CSSSelectorParser::ParseSelector(
- range,
- MakeGarbageCollected<CSSParserContext>(
- kHTMLStandardMode, SecureContextMode::kInsecureContext),
- nullptr);
- EXPECT_EQ(test_case[1], list.SelectorsText());
- }
-}
-
TEST(CSSSelectorParserTest, PseudoElementsInCompoundLists) {
const char* test_cases[] = {":not(::before)",
":not(::content)",
@@ -260,22 +238,6 @@ TEST(CSSSelectorParserTest, WorkaroundForInvalidCustomPseudoInUAStyle) {
}
}
-TEST(CSSSelectorParserTest, ValidPseudoElementInNonRightmostCompound) {
- const char* test_cases[] = {"::content *", "::content div::before"};
-
- for (auto* test_case : test_cases) {
- CSSTokenizer tokenizer(test_case);
- const auto tokens = tokenizer.TokenizeToEOF();
- CSSParserTokenRange range(tokens);
- CSSSelectorList list = CSSSelectorParser::ParseSelector(
- range,
- MakeGarbageCollected<CSSParserContext>(
- kHTMLStandardMode, SecureContextMode::kInsecureContext),
- nullptr);
- EXPECT_TRUE(list.IsValid());
- }
-}
-
TEST(CSSSelectorParserTest, InvalidPseudoElementInNonRightmostCompound) {
const char* test_cases[] = {"::-webkit-volume-slider *", "::before *",
"::-webkit-scrollbar *", "::cue *",
@@ -441,44 +403,6 @@ INSTANTIATE_TEST_SUITE_P(InvalidPseudoIsArguments,
SelectorParseTest,
testing::ValuesIn(invalid_pseudo_is_argments_data));
-// To reduce complexity, ShadowDOM v0 features are not supported in
-// combination with nested complex selectors, e.g. :is/:where.
-static const SelectorTestCase shadow_v0_with_nested_complex_data[] = {
- // clang-format off
- {":is(.a) ::content", ""},
- {":is(.a /deep/ .b)", ":is()"},
- {":is(::content)", ":is()"},
- {":is(::shadow)", ":is()"},
- {":is(::content .a)", ":is()"},
- {":is(::shadow .b)", ":is()"},
- {":is(.a)::shadow", ""},
- {":is(.a) ::content", ""},
- {":is(.a) ::shadow", ""},
- {"::content :is(.a)", ""},
- {"::shadow :is(.a)", ""},
- {":is(.a) /deep/ .b", ""},
- {":.a /deep/ :is(.b)", ""},
- {":where(.a /deep/ .b)", ":where()"},
- {":where(.a) ::shadow", ""},
- {":not(.a .b)::shadow", ""},
- {":not(.a .b)::content", ""},
- {":not(.a .b) ::shadow", ""},
- {":not(.a .b) ::content", ""},
- {":not(.a, .b) ::content", ""},
- {":not(.a .b) /deep/ .c", ""},
- {":not(.a, .b) /deep/ .c", ""},
- {".a /deep/ :not(.b .c)", ""},
- // For backwards compatibility, ShadowDOM v0 features are allowed if
- // there is a single compound argument to :not().
- {":not(.a) /deep/ .b", ":not(.a) /deep/ .b"},
- {":not(.a)::content", ":not(.a)::content"},
- // clang-format on
-};
-
-INSTANTIATE_TEST_SUITE_P(ShadowDomV0WithNestedComplexSelector,
- SelectorParseTest,
- testing::ValuesIn(shadow_v0_with_nested_complex_data));
-
static const SelectorTestCase is_where_nesting_data[] = {
// clang-format off
// These pseudos only accept compound selectors:
@@ -494,7 +418,7 @@ static const SelectorTestCase is_where_nesting_data[] = {
{"::cue(:is(.a .b))", "::cue(:is())"},
{"::cue(:is(.a + .b))", "::cue(:is())"},
{"::cue(:is(.a, .b + .c))", "::cue(:is(.a))"},
- // Only user-action pseudos + :state() are allowed after kPseudoPart:
+ // Only user-action pseudos + :--state are allowed after kPseudoPart:
{"::part(foo):is(.a)", "::part(foo):is()"},
{"::part(foo):is(.a:hover)", "::part(foo):is()"},
{"::part(foo):is(:hover.a)", "::part(foo):is()"},
@@ -505,7 +429,7 @@ static const SelectorTestCase is_where_nesting_data[] = {
{"::part(foo):is(:hover, :where(.a))",
"::part(foo):is(:hover, :where())"},
{"::part(foo):is(:hover, .a)", "::part(foo):is(:hover)"},
- {"::part(foo):is(:state(bar), .a)", "::part(foo):is(:state(bar))"},
+ {"::part(foo):is(:--bar, .a)", "::part(foo):is(:--bar)"},
{"::part(foo):is(:enabled)", "::part(foo):is()"},
// Only scrollbar pseudos after kPseudoScrollbar:
{"::-webkit-scrollbar:is(:focus)", "::-webkit-scrollbar:is()"},
@@ -544,7 +468,7 @@ static const SelectorTestCase is_where_nesting_data[] = {
{"::part(foo):is(:is(:hover))"},
{"::part(foo):is(:focus, :hover)"},
{"::part(foo):is(:focus, :is(:hover))"},
- {"::part(foo):is(:focus, :state(bar))"},
+ {"::part(foo):is(:focus, :--bar)"},
{"::-webkit-scrollbar:is(:enabled)"},
{"::selection:is(:window-inactive)"},
{"::-webkit-input-placeholder:is(:hover)"},
@@ -873,7 +797,7 @@ TEST(CSSSelectorParserTest, ImplicitShadowCrossingCombinators) {
{
"*::placeholder",
{
- {"placeholder", CSSSelector::kShadowPseudo},
+ {"placeholder", CSSSelector::kUAShadow},
{g_null_atom, CSSSelector::kSubSelector},
},
},
@@ -887,7 +811,7 @@ TEST(CSSSelectorParserTest, ImplicitShadowCrossingCombinators) {
{
"::slotted(*)::placeholder",
{
- {"placeholder", CSSSelector::kShadowPseudo},
+ {"placeholder", CSSSelector::kUAShadow},
{"slotted", CSSSelector::kShadowSlot},
{g_null_atom, CSSSelector::kSubSelector},
},
@@ -902,7 +826,7 @@ TEST(CSSSelectorParserTest, ImplicitShadowCrossingCombinators) {
{
"video::-webkit-media-controls",
{
- {"-webkit-media-controls", CSSSelector::kShadowPseudo},
+ {"-webkit-media-controls", CSSSelector::kUAShadow},
{"video", CSSSelector::kSubSelector},
},
},
diff --git a/chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc b/chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
index d0e1629be3e..b98ed3a5030 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
#include "third_party/blink/renderer/core/media_type_names.h"
@@ -82,8 +83,8 @@ TEST(SizesAttributeParserTest, Basic) {
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
- data.primary_pointer_type = ui::POINTER_TYPE_FINE;
data.default_font_size = 16;
+ data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
data.strict_mode = true;
@@ -163,7 +164,7 @@ TEST(SizesAttributeParserTest, FloatViewportWidth) {
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
- data.primary_pointer_type = ui::POINTER_TYPE_FINE;
+ data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
data.default_font_size = 16;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
diff --git a/chromium/third_party/blink/renderer/core/css/parser/sizes_math_function_parser_test.cc b/chromium/third_party/blink/renderer/core/css/parser/sizes_math_function_parser_test.cc
index 3193c6cce63..e47d8070b79 100644
--- a/chromium/third_party/blink/renderer/core/css/parser/sizes_math_function_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/parser/sizes_math_function_parser_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/parser/sizes_math_function_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
#include "third_party/blink/renderer/core/css/css_math_function_value.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
@@ -93,13 +94,16 @@ TEST(SizesMathFunctionParserTest, Basic) {
{"calc(500px/0.5)", 1000, true, false},
{"calc(500px/.5)", 1000, true, false},
{"calc(500/0)", 0, false, false},
- {"calc(500px/0)", 0, false, false},
{"calc(-500px/10)", 0, true,
true}, // CSSCalculationValue does not clamp negative values to 0.
{"calc(((4) * ((10px))))", 40, true, false},
- {"calc(50px / 0)", 0, false, false},
+ // TODO(crbug.com/1133390): These test cases failed with Infinity and NaN
+ // parsing implementation. Below tests will be reactivated when the
+ // sizes_math function supports the infinity and NaN.
+ //{"calc(500px/0)", 0, false, false},
+ //{"calc(50px / 0)", 0, false, false},
+ //{"calc(50px / (10 - 10))", 0, false, false},
{"calc(50px / (10 + 10))", 2.5, true, false},
- {"calc(50px / (10 - 10))", 0, false, false},
{"calc(50px / (10 * 10))", 0.5, true, false},
{"calc(50px / (10 / 10))", 50, true, false},
{"calc(200px*)", 0, false, false},
@@ -175,7 +179,7 @@ TEST(SizesMathFunctionParserTest, Basic) {
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
- data.primary_pointer_type = ui::POINTER_TYPE_FINE;
+ data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
data.default_font_size = 16;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
diff --git a/chromium/third_party/blink/renderer/core/css/predefined_counter_styles.css b/chromium/third_party/blink/renderer/core/css/predefined_counter_styles.css
new file mode 100644
index 00000000000..ccec47f3097
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/predefined_counter_styles.css
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2020 The Chromium 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://drafts.csswg.org/css-counter-styles-3/#simple-numeric */
+
+@counter-style decimal {
+ system: numeric;
+ symbols: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
+}
+
+@counter-style decimal-leading-zero {
+ system: extends decimal;
+ pad: 2 '0';
+}
+
+@counter-style arabic-indic {
+ system: numeric;
+ symbols: "\660" "\661" "\662" "\663" "\664" "\665" "\666" "\667" "\668" "\669";
+ /* ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ */
+}
+
+@counter-style armenian {
+ system: -internal-upper-armenian;
+ /* Officially, 'armenian' is specified as an additive counter style supporting
+ * 1-9999. We extend the range to 99999999 using a special algorithm.
+ */
+ range: 1 99999999;
+}
+
+@counter-style upper-armenian {
+ system: extends armenian;
+}
+
+@counter-style lower-armenian {
+ system: -internal-lower-armenian;
+ /* Officially, 'lower-armenian' is specified as an additive counter style
+ * supporting 1-9999. We extend the range to 99999999 using a special
+ * algorithm.
+ */
+ range: 1 99999999;
+}
+
+@counter-style bengali {
+ system: numeric;
+ symbols: "\9E6" "\9E7" "\9E8" "\9E9" "\9EA" "\9EB" "\9EC" "\9ED" "\9EE" "\9EF";
+ /* ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ */
+}
+
+@counter-style cambodian {
+ system: numeric;
+ symbols: "\17E0" "\17E1" "\17E2" "\17E3" "\17E4" "\17E5" "\17E6" "\17E7" "\17E8" "\17E9";
+ /* ០ ១ ២ ៣ ៤ ៥ ៦ ៧ ៨ ៩ */
+}
+
+@counter-style khmer {
+ system: extends cambodian;
+}
+
+@counter-style cjk-decimal {
+ system: numeric;
+ range: 0 infinite;
+ symbols: "\3007" "\4E00" "\4E8C" "\4E09" "\56DB" "\4E94" "\516D" "\4E03" "\516B" "\4E5D";
+ /* 〇 一 二 三 四 五 六 七 八 九 */
+ suffix: "\3001";
+ /* "、" */
+}
+
+@counter-style devanagari {
+ system: numeric;
+ symbols: "\966" "\967" "\968" "\969" "\96A" "\96B" "\96C" "\96D" "\96E" "\96F";
+ /* ० १ २ ३ ४ ५ ६ ७ ८ ९ */
+}
+
+@counter-style georgian {
+ system: additive;
+ range: 1 19999;
+ additive-symbols: 10000 \10F5, 9000 \10F0, 8000 \10EF, 7000 \10F4, 6000 \10EE, 5000 \10ED, 4000 \10EC, 3000 \10EB, 2000 \10EA, 1000 \10E9, 900 \10E8, 800 \10E7, 700 \10E6, 600 \10E5, 500 \10E4, 400 \10F3, 300 \10E2, 200 \10E1, 100 \10E0, 90 \10DF, 80 \10DE, 70 \10DD, 60 \10F2, 50 \10DC, 40 \10DB, 30 \10DA, 20 \10D9, 10 \10D8, 9 \10D7, 8 \10F1, 7 \10D6, 6 \10D5, 5 \10D4, 4 \10D3, 3 \10D2, 2 \10D1, 1 \10D0;
+ /* 10000 ჵ, 9000 ჰ, 8000 ჯ, 7000 ჴ, 6000 ხ, 5000 ჭ, 4000 წ, 3000 ძ, 2000 ც, 1000 ჩ, 900 შ, 800 ყ, 700 ღ, 600 ქ, 500 ფ, 400 ჳ, 300 ტ, 200 ს, 100 რ, 90 ჟ, 80 პ, 70 ო, 60 ჲ, 50 ნ, 40 მ, 30 ლ, 20 კ, 10 ი, 9 თ, 8 ჱ, 7 ზ, 6 ვ, 5 ე, 4 დ, 3 გ, 2 ბ, 1 ა */
+}
+
+@counter-style gujarati {
+ system: numeric;
+ symbols: "\AE6" "\AE7" "\AE8" "\AE9" "\AEA" "\AEB" "\AEC" "\AED" "\AEE" "\AEF";
+ /* ૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯ */
+}
+
+@counter-style gurmukhi {
+ system: numeric;
+ symbols: "\A66" "\A67" "\A68" "\A69" "\A6A" "\A6B" "\A6C" "\A6D" "\A6E" "\A6F";
+ /* ੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯ */
+}
+
+@counter-style hebrew {
+ system: -internal-hebrew;
+ /* Officially, 'hebrew' is specified as an additive counter style supporting
+ * 1-10999. We extend the range to 0-999999 using a special algorithm. */
+ range: 0 999999;
+}
+
+@counter-style kannada {
+ system: numeric;
+ symbols: "\CE6" "\CE7" "\CE8" "\CE9" "\CEA" "\CEB" "\CEC" "\CED" "\CEE" "\CEF";
+ /* ೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯ */
+}
+
+@counter-style lao {
+ system: numeric;
+ symbols: "\ED0" "\ED1" "\ED2" "\ED3" "\ED4" "\ED5" "\ED6" "\ED7" "\ED8" "\ED9";
+ /* ໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙ */
+}
+
+@counter-style malayalam {
+ system: numeric;
+ symbols: "\D66" "\D67" "\D68" "\D69" "\D6A" "\D6B" "\D6C" "\D6D" "\D6E" "\D6F";
+ /* ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯ */
+}
+
+@counter-style mongolian {
+ system: numeric;
+ symbols: "\1810" "\1811" "\1812" "\1813" "\1814" "\1815" "\1816" "\1817" "\1818" "\1819";
+ /* ᠐ ᠑ ᠒ ᠓ ᠔ ᠕ ᠖ ᠗ ᠘ ᠙ */
+}
+
+@counter-style myanmar {
+ system: numeric;
+ symbols: "\1040" "\1041" "\1042" "\1043" "\1044" "\1045" "\1046" "\1047" "\1048" "\1049";
+ /* ၀ ၁ ၂ ၃ ၄ ၅ ၆ ၇ ၈ ၉ */
+}
+
+@counter-style oriya {
+ system: numeric;
+ symbols: "\B66" "\B67" "\B68" "\B69" "\B6A" "\B6B" "\B6C" "\B6D" "\B6E" "\B6F";
+ /* ୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯ */
+}
+
+@counter-style persian {
+ system: numeric;
+ symbols: "\6F0" "\6F1" "\6F2" "\6F3" "\6F4" "\6F5" "\6F6" "\6F7" "\6F8" "\6F9";
+ /* ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ */
+}
+
+@counter-style lower-roman {
+ system: additive;
+ range: 1 3999;
+ additive-symbols: 1000 m, 900 cm, 500 d, 400 cd, 100 c, 90 xc, 50 l, 40 xl, 10 x, 9 ix, 5 v, 4 iv, 1 i;
+}
+
+@counter-style upper-roman {
+ system: additive;
+ range: 1 3999;
+ additive-symbols: 1000 M, 900 CM, 500 D, 400 CD, 100 C, 90 XC, 50 L, 40 XL, 10 X, 9 IX, 5 V, 4 IV, 1 I;
+}
+
+@counter-style tamil {
+ system: numeric;
+ symbols: "\BE6" "\BE7" "\BE8" "\BE9" "\BEA" "\BEB" "\BEC" "\BED" "\BEE" "\BEF";
+ /* ௦ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯ */
+}
+
+@counter-style telugu {
+ system: numeric;
+ symbols: "\C66" "\C67" "\C68" "\C69" "\C6A" "\C6B" "\C6C" "\C6D" "\C6E" "\C6F";
+ /* ౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯ */
+}
+
+@counter-style thai {
+ system: numeric;
+ symbols: "\E50" "\E51" "\E52" "\E53" "\E54" "\E55" "\E56" "\E57" "\E58" "\E59";
+ /* ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙ */
+}
+
+@counter-style tibetan {
+ system: numeric;
+ symbols: "\F20" "\F21" "\F22" "\F23" "\F24" "\F25" "\F26" "\F27" "\F28" "\F29";
+ /* ༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩ */
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#simple-alphabetic */
+
+@counter-style lower-alpha {
+ system: alphabetic;
+ symbols: a b c d e f g h i j k l m n o p q r s t u v w x y z;
+}
+
+@counter-style lower-latin {
+ system: extends lower-alpha;
+}
+
+@counter-style upper-alpha {
+ system: alphabetic;
+ symbols: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z;
+}
+
+@counter-style upper-latin {
+ system: extends upper-alpha;
+}
+
+@counter-style lower-greek {
+ system: alphabetic;
+ symbols: "\3B1" "\3B2" "\3B3" "\3B4" "\3B5" "\3B6" "\3B7" "\3B8" "\3B9" "\3BA" "\3BB" "\3BC" "\3BD" "\3BE" "\3BF" "\3C0" "\3C1" "\3C3" "\3C4" "\3C5" "\3C6" "\3C7" "\3C8" "\3C9";
+ /* α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω */
+}
+
+@counter-style hiragana {
+ system: alphabetic;
+ symbols: "\3042" "\3044" "\3046" "\3048" "\304A" "\304B" "\304D" "\304F" "\3051" "\3053" "\3055" "\3057" "\3059" "\305B" "\305D" "\305F" "\3061" "\3064" "\3066" "\3068" "\306A" "\306B" "\306C" "\306D" "\306E" "\306F" "\3072" "\3075" "\3078" "\307B" "\307E" "\307F" "\3080" "\3081" "\3082" "\3084" "\3086" "\3088" "\3089" "\308A" "\308B" "\308C" "\308D" "\308F" "\3090" "\3091" "\3092" "\3093";
+ /* あ い う え お か き く け こ さ し す せ そ た ち つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ わ ゐ ゑ を ん */
+ suffix: "\3001";
+}
+
+@counter-style hiragana-iroha {
+ system: alphabetic;
+ symbols: "\3044" "\308D" "\306F" "\306B" "\307B" "\3078" "\3068" "\3061" "\308A" "\306C" "\308B" "\3092" "\308F" "\304B" "\3088" "\305F" "\308C" "\305D" "\3064" "\306D" "\306A" "\3089" "\3080" "\3046" "\3090" "\306E" "\304A" "\304F" "\3084" "\307E" "\3051" "\3075" "\3053" "\3048" "\3066" "\3042" "\3055" "\304D" "\3086" "\3081" "\307F" "\3057" "\3091" "\3072" "\3082" "\305B" "\3059";
+ /* い ろ は に ほ へ と ち り ぬ る を わ か よ た れ そ つ ね な ら む う ゐ の お く や ま け ふ こ え て あ さ き ゆ め み し ゑ ひ も せ す */
+ suffix: "\3001";
+}
+
+@counter-style katakana {
+ system: alphabetic;
+ symbols: "\30A2" "\30A4" "\30A6" "\30A8" "\30AA" "\30AB" "\30AD" "\30AF" "\30B1" "\30B3" "\30B5" "\30B7" "\30B9" "\30BB" "\30BD" "\30BF" "\30C1" "\30C4" "\30C6" "\30C8" "\30CA" "\30CB" "\30CC" "\30CD" "\30CE" "\30CF" "\30D2" "\30D5" "\30D8" "\30DB" "\30DE" "\30DF" "\30E0" "\30E1" "\30E2" "\30E4" "\30E6" "\30E8" "\30E9" "\30EA" "\30EB" "\30EC" "\30ED" "\30EF" "\30F0" "\30F1" "\30F2" "\30F3";
+ /* ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ヰ ヱ ヲ ン */
+ suffix: "\3001";
+}
+
+@counter-style katakana-iroha {
+ system: alphabetic;
+ symbols: "\30A4" "\30ED" "\30CF" "\30CB" "\30DB" "\30D8" "\30C8" "\30C1" "\30EA" "\30CC" "\30EB" "\30F2" "\30EF" "\30AB" "\30E8" "\30BF" "\30EC" "\30BD" "\30C4" "\30CD" "\30CA" "\30E9" "\30E0" "\30A6" "\30F0" "\30CE" "\30AA" "\30AF" "\30E4" "\30DE" "\30B1" "\30D5" "\30B3" "\30A8" "\30C6" "\30A2" "\30B5" "\30AD" "\30E6" "\30E1" "\30DF" "\30B7" "\30F1" "\30D2" "\30E2" "\30BB" "\30B9";
+ /* イ ロ ハ ニ ホ ヘ ト チ リ ヌ ル ヲ ワ カ ヨ タ レ ソ ツ ネ ナ ラ ム ウ ヰ ノ オ ク ヤ マ ケ フ コ エ テ ア サ キ ユ メ ミ シ ヱ ヒ モ セ ス */
+ suffix: "\3001";
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#simple-symbolic */
+
+@counter-style disc {
+ system: cyclic;
+ symbols: \2022;
+ /* • */
+ suffix: " ";
+}
+
+@counter-style circle {
+ system: cyclic;
+ symbols: \25E6;
+ /* ◦ */
+ suffix: " ";
+}
+
+@counter-style square {
+ system: cyclic;
+ symbols: \25A0;
+ /* Note: Spec requires \25FE, but we've always been using \25A0. */
+ suffix: " ";
+}
+
+@counter-style disclosure-open {
+ system: cyclic;
+ symbols: \25BE;
+ suffix: " ";
+}
+
+@counter-style disclosure-closed {
+ system: cyclic;
+ symbols: \25B8;
+ suffix: " ";
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#simple-fixed */
+
+@counter-style cjk-earthly-branch {
+ system: alphabetic;
+ symbols: "\5B50" "\4E11" "\5BC5" "\536F" "\8FB0" "\5DF3" "\5348" "\672A" "\7533" "\9149" "\620C" "\4EA5";
+ /* 子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥 */
+ suffix: "\3001";
+}
+
+@counter-style cjk-heavenly-stem {
+ system: alphabetic;
+ symbols: "\7532" "\4E59" "\4E19" "\4E01" "\620A" "\5DF1" "\5E9A" "\8F9B" "\58EC" "\7678";
+ /* 甲 乙 丙 丁 戊 己 庚 辛 壬 癸 */
+ suffix: "\3001";
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#limited-japanese */
+
+@counter-style japanese-informal {
+ system: additive;
+ range: -9999 9999;
+ additive-symbols: 9000 \4E5D\5343, 8000 \516B\5343, 7000 \4E03\5343, 6000 \516D\5343, 5000 \4E94\5343, 4000 \56DB\5343, 3000 \4E09\5343, 2000 \4E8C\5343, 1000 \5343, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4E94\767E, 400 \56DB\767E, 300 \4E09\767E, 200 \4E8C\767E, 100 \767E, 90 \4E5D\5341, 80 \516B\5341, 70 \4E03\5341, 60 \516D\5341, 50 \4E94\5341, 40 \56DB\5341, 30 \4E09\5341, 20 \4E8C\5341, 10 \5341, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4E94, 4 \56DB, 3 \4E09, 2 \4E8C, 1 \4E00, 0 \3007;
+ /* 9000 九千, 8000 八千, 7000 七千, 6000 六千, 5000 五千, 4000 四千, 3000 三千, 2000 二千, 1000 千, 900 九百, 800 八百, 700 七百, 600 六百, 500 五百, 400 四百, 300 三百, 200 二百, 100 百, 90 九十, 80 八十, 70 七十, 60 六十, 50 五十, 40 四十, 30 三十, 20 二十, 10 十, 9 九, 8 八, 7 七, 6 六, 5 五, 4 四, 3 三, 2 二, 1 一, 0 〇 */
+ suffix: '\3001';
+ /* 、 */
+ negative: "\30DE\30A4\30CA\30B9";
+ /* マイナス */
+ fallback: cjk-decimal;
+}
+
+@counter-style japanese-formal {
+ system: additive;
+ range: -9999 9999;
+ additive-symbols: 9000 \4E5D\9621, 8000 \516B\9621, 7000 \4E03\9621, 6000 \516D\9621, 5000 \4F0D\9621, 4000 \56DB\9621, 3000 \53C2\9621, 2000 \5F10\9621, 1000 \58F1\9621, 900 \4E5D\767E, 800 \516B\767E, 700 \4E03\767E, 600 \516D\767E, 500 \4F0D\767E, 400 \56DB\767E, 300 \53C2\767E, 200 \5F10\767E, 100 \58F1\767E, 90 \4E5D\62FE, 80 \516B\62FE, 70 \4E03\62FE, 60 \516D\62FE, 50 \4F0D\62FE, 40 \56DB\62FE, 30 \53C2\62FE, 20 \5F10\62FE, 10 \58F1\62FE, 9 \4E5D, 8 \516B, 7 \4E03, 6 \516D, 5 \4F0D, 4 \56DB, 3 \53C2, 2 \5F10, 1 \58F1, 0 \96F6;
+ /* 9000 九阡, 8000 八阡, 7000 七阡, 6000 六阡, 5000 伍阡, 4000 四阡, 3000 参阡, 2000 弐阡, 1000 壱阡, 900 九百, 800 八百, 700 七百, 600 六百, 500 伍百, 400 四百, 300 参百, 200 弐百, 100 壱百, 90 九拾, 80 八拾, 70 七拾, 60 六拾, 50 伍拾, 40 四拾, 30 参拾, 20 弐拾, 10 壱拾, 9 九, 8 八, 7 七, 6 六, 5 伍, 4 四, 3 参, 2 弐, 1 壱, 0 零 */
+ suffix: '\3001';
+ /* 、 */
+ negative: "\30DE\30A4\30CA\30B9";
+ /* マイナス */
+ fallback: cjk-decimal;
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#limited-korean */
+
+/* Note: While the officially specified range is -9999 to 9999 for these counter
+ * styles, implementations are allowed to support a larger range for
+ * investigative purposes. Therefore, we support the full int range. */
+
+@counter-style korean-hangul-formal {
+ system: -internal-korean-hangul-formal;
+ suffix: ', ';
+ negative: "\B9C8\C774\B108\C2A4 ";
+ /* 마이너스 (followed by a space) */
+ fallback: cjk-decimal;
+}
+
+@counter-style korean-hanja-informal {
+ system: -internal-korean-hanja-informal;
+ suffix: ', ';
+ negative: "\B9C8\C774\B108\C2A4 ";
+ /* 마이너스 (followed by a space) */
+ fallback: cjk-decimal;
+}
+
+@counter-style korean-hanja-formal {
+ system: -internal-korean-hanja-formal;
+ suffix: ', ';
+ negative: "\B9C8\C774\B108\C2A4 ";
+ /* 마이너스 (followed by a space) */
+ fallback: cjk-decimal;
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#limited-chinese */
+
+/* Note: While the officially specified range is -9999 to 9999 for these counter
+ * styles, implementations are allowed to support a larger range for
+ * investigative purposes. Therefore, we support the full int range. */
+
+@counter-style simp-chinese-informal {
+ system: -internal-simp-chinese-informal;
+ suffix: \3001;
+ /* 、 */
+ negative: \8D1F;
+ /* 负 */
+ fallback: cjk-decimal;
+}
+
+@counter-style simp-chinese-formal {
+ system: -internal-simp-chinese-formal;
+ suffix: \3001;
+ /* 、 */
+ negative: \8D1F;
+ /* 负 */
+ fallback: cjk-decimal;
+}
+
+@counter-style trad-chinese-informal {
+ system: -internal-trad-chinese-informal;
+ suffix: \3001;
+ /* 、 */
+ negative: \8CA0;
+ /* 負 */
+ fallback: cjk-decimal;
+}
+
+@counter-style trad-chinese-formal {
+ system: -internal-trad-chinese-formal;
+ suffix: \3001;
+ /* 、 */
+ negative: \8CA0;
+ /* 負 */
+ fallback: cjk-decimal;
+}
+
+@counter-style cjk-ideographic {
+ system: extends trad-chinese-informal;
+}
+
+/* https://drafts.csswg.org/css-counter-styles-3/#ethiopic-numeric-counter-style
+ */
+
+@counter-style ethiopic-numeric {
+ system: -internal-ethiopic-numeric;
+ range: 1 infinite;
+ suffix: "/ ";
+}
+
+/* Non-standard counter styles that we've been supporting */
+
+@counter-style ethiopic-halehame {
+ system: alphabetic;
+ symbols: '\1200' '\1208' '\1210' '\1218' '\1220' '\1228' '\1230' '\1240' '\1260' '\1270' '\1280' '\1290' '\12A0' '\12A8' '\12C8' '\12D0' '\12D8' '\12E8' '\12F0' '\1308' '\1320' '\1330' '\1338' '\1340' '\1348' '\1350';
+ suffix: '\1366 ';
+}
+
+@counter-style ethiopic-halehame-am {
+ system: alphabetic;
+ symbols: '\1200' '\1208' '\1210' '\1218' '\1220' '\1228' '\1230' '\1238' '\1240' '\1260' '\1270' '\1278' '\1280' '\1290' '\1298' '\12A0' '\12A8' '\12B8' '\12C8' '\12D0' '\12D8' '\12E0' '\12E8' '\12F0' '\1300' '\1308' '\1320' '\1328' '\1330' '\1338' '\1340' '\1348' '\1350';
+ suffix: '\1366 ';
+}
+
+@counter-style ethiopic-halehame-ti-er {
+ system: alphabetic;
+ symbols: '\1200' '\1208' '\1210' '\1218' '\1228' '\1230' '\1238' '\1240' '\1250' '\1260' '\1270' '\1278' '\1290' '\1298' '\12A0' '\12A8' '\12B8' '\12C8' '\12D0' '\12D8' '\12E0' '\12E8' '\12F0' '\1300' '\1308' '\1320' '\1328' '\1330' '\1338' '\1348' '\1350';
+ suffix: '\1366 ';
+}
+
+@counter-style ethiopic-halehame-ti-et {
+ system: alphabetic;
+ symbols: '\1200' '\1208' '\1210' '\1218' '\1220' '\1228' '\1230' '\1238' '\1240' '\1250' '\1260' '\1270' '\1278' '\1280' '\1290' '\1298' '\12A0' '\12A8' '\12B8' '\12C8' '\12D0' '\12D8' '\12E0' '\12E8' '\12F0' '\1300' '\1308' '\1320' '\1328' '\1330' '\1338' '\1340' '\1348' '\1350';
+ suffix: '\1366 ';
+}
+
+@counter-style hangul {
+ system: alphabetic;
+ symbols: '\AC00' '\B098' '\B2E4' '\B77C' '\B9C8' '\BC14' '\C0AC' '\C544' '\C790' '\CC28' '\CE74' '\D0C0' '\D30C' '\D558';
+}
+
+@counter-style hangul-consonant {
+ system: alphabetic;
+ symbols: '\3131' '\3134' '\3137' '\3139' '\3141' '\3142' '\3145' '\3147' '\3148' '\314A' '\314B' '\314C' '\314D' '\314E';
+}
+
+@counter-style urdu {
+ system: extends persian;
+}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 22fb558d35f..8af2ba5d82f 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -330,69 +330,42 @@ const CSSValue* ComputedStyleUtils::BackgroundPositionYOrWebkitMaskPositionY(
return list;
}
+static CSSNumericLiteralValue* ValueForImageSlice(const Length& slice) {
+ // TODO(alancutter): Make this code aware of calc lengths.
+ return CSSNumericLiteralValue::Create(
+ slice.Value(), slice.IsPercentOrCalc()
+ ? CSSPrimitiveValue::UnitType::kPercentage
+ : CSSPrimitiveValue::UnitType::kNumber);
+}
+
cssvalue::CSSBorderImageSliceValue*
ComputedStyleUtils::ValueForNinePieceImageSlice(const NinePieceImage& image) {
+ const LengthBox& slices = image.ImageSlices();
+
// Create the slices.
- CSSPrimitiveValue* top = nullptr;
+ CSSPrimitiveValue* top = ValueForImageSlice(slices.Top());
+
CSSPrimitiveValue* right = nullptr;
CSSPrimitiveValue* bottom = nullptr;
CSSPrimitiveValue* left = nullptr;
-
- // TODO(alancutter): Make this code aware of calc lengths.
- if (image.ImageSlices().Top().IsPercentOrCalc()) {
- top = CSSNumericLiteralValue::Create(
- image.ImageSlices().Top().Value(),
- CSSPrimitiveValue::UnitType::kPercentage);
- } else {
- top = CSSNumericLiteralValue::Create(image.ImageSlices().Top().Value(),
- CSSPrimitiveValue::UnitType::kNumber);
- }
-
- if (image.ImageSlices().Right() == image.ImageSlices().Top() &&
- image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
- image.ImageSlices().Left() == image.ImageSlices().Top()) {
+ if (slices.Right() == slices.Top() && slices.Bottom() == slices.Top() &&
+ slices.Left() == slices.Top()) {
right = top;
bottom = top;
left = top;
} else {
- if (image.ImageSlices().Right().IsPercentOrCalc()) {
- right = CSSNumericLiteralValue::Create(
- image.ImageSlices().Right().Value(),
- CSSPrimitiveValue::UnitType::kPercentage);
- } else {
- right =
- CSSNumericLiteralValue::Create(image.ImageSlices().Right().Value(),
- CSSPrimitiveValue::UnitType::kNumber);
- }
+ right = ValueForImageSlice(slices.Right());
- if (image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
- image.ImageSlices().Right() == image.ImageSlices().Left()) {
+ if (slices.Bottom() == slices.Top() && slices.Right() == slices.Left()) {
bottom = top;
left = right;
} else {
- if (image.ImageSlices().Bottom().IsPercentOrCalc()) {
- bottom = CSSNumericLiteralValue::Create(
- image.ImageSlices().Bottom().Value(),
- CSSPrimitiveValue::UnitType::kPercentage);
- } else {
- bottom = CSSNumericLiteralValue::Create(
- image.ImageSlices().Bottom().Value(),
- CSSPrimitiveValue::UnitType::kNumber);
- }
+ bottom = ValueForImageSlice(slices.Bottom());
- if (image.ImageSlices().Left() == image.ImageSlices().Right()) {
+ if (slices.Left() == slices.Right())
left = right;
- } else {
- if (image.ImageSlices().Left().IsPercentOrCalc()) {
- left = CSSNumericLiteralValue::Create(
- image.ImageSlices().Left().Value(),
- CSSPrimitiveValue::UnitType::kPercentage);
- } else {
- left = CSSNumericLiteralValue::Create(
- image.ImageSlices().Left().Value(),
- CSSPrimitiveValue::UnitType::kNumber);
- }
- }
+ else
+ left = ValueForImageSlice(slices.Left());
}
}
@@ -590,12 +563,14 @@ CSSValue* ComputedStyleUtils::ValueForPositionOffset(
if (offset.IsPercentOrCalc() && box && layout_object->IsPositioned()) {
LayoutUnit containing_block_size;
if (layout_object->IsStickyPositioned()) {
- const LayoutBox& enclosing_scrollport_box = box->EnclosingScrollportBox();
- bool use_inline_size = is_horizontal_property ==
- enclosing_scrollport_box.IsHorizontalWritingMode();
+ const LayoutBox* enclosing_scrollport_box = box->EnclosingScrollportBox();
+ DCHECK(enclosing_scrollport_box);
+ bool use_inline_size =
+ is_horizontal_property ==
+ enclosing_scrollport_box->IsHorizontalWritingMode();
containing_block_size =
- use_inline_size ? enclosing_scrollport_box.ContentLogicalWidth()
- : enclosing_scrollport_box.ContentLogicalHeight();
+ use_inline_size ? enclosing_scrollport_box->ContentLogicalWidth()
+ : enclosing_scrollport_box->ContentLogicalHeight();
} else {
containing_block_size =
is_horizontal_property ==
@@ -1365,6 +1340,8 @@ CSSValue* ComputedStyleUtils::ValueForGridTrackList(
: style.GridTemplateRows().LegacyTrackList();
const Vector<GridTrackSize>& auto_repeat_track_sizes =
is_row_axis ? style.GridAutoRepeatColumns() : style.GridAutoRepeatRows();
+
+ // TODO(crbug.com/1045599): Implement similar logic for GridNG.
bool is_layout_grid = layout_object && layout_object->IsLayoutGrid();
// Handle the 'none' case.
@@ -1374,8 +1351,8 @@ CSSValue* ComputedStyleUtils::ValueForGridTrackList(
// For grids we should consider every listed track, whether implicitly or
// explicitly created. Empty grids have a sole grid line per axis.
auto& positions = is_row_axis
- ? ToLayoutGrid(layout_object)->ColumnPositions()
- : ToLayoutGrid(layout_object)->RowPositions();
+ ? To<LayoutGrid>(layout_object)->ColumnPositions()
+ : To<LayoutGrid>(layout_object)->RowPositions();
track_list_is_empty = positions.size() == 1;
}
@@ -1387,7 +1364,7 @@ CSSValue* ComputedStyleUtils::ValueForGridTrackList(
// If the element is a grid container, the resolved value is the used value,
// specifying track sizes in pixels and expanding the repeat() notation.
if (is_layout_grid) {
- const auto* grid = ToLayoutGrid(layout_object);
+ const auto* grid = To<LayoutGrid>(layout_object);
OrderedNamedLinesCollectorInGridLayout collector(
style, is_row_axis, grid->AutoRepeatCountForDirection(direction),
auto_repeat_track_sizes.size());
@@ -2048,22 +2025,13 @@ CSSValue* ComputedStyleUtils::ValueForContentData(const ComputedStyle& style,
for (const ContentData* content_data = style.GetContentData(); content_data;
content_data = content_data->Next()) {
if (content_data->IsCounter()) {
- const CounterContent* counter =
- To<CounterContentData>(content_data)->Counter();
- DCHECK(counter);
+ const CounterContentData& counter = To<CounterContentData>(*content_data);
auto* identifier =
- MakeGarbageCollected<CSSCustomIdentValue>(counter->Identifier());
+ MakeGarbageCollected<CSSCustomIdentValue>(counter.Identifier());
auto* separator =
- MakeGarbageCollected<CSSStringValue>(counter->Separator());
- CSSValueID list_style_ident = CSSValueID::kNone;
- if (counter->ListStyle() != EListStyleType::kNone) {
- // TODO(sashab): Change this to use a converter instead of
- // CSSPrimitiveValueMappings.
- list_style_ident =
- CSSIdentifierValue::Create(counter->ListStyle())->GetValueID();
- }
- CSSIdentifierValue* list_style =
- CSSIdentifierValue::Create(list_style_ident);
+ MakeGarbageCollected<CSSStringValue>(counter.Separator());
+ auto* list_style =
+ MakeGarbageCollected<CSSCustomIdentValue>(counter.ListStyle());
list->Append(*MakeGarbageCollected<cssvalue::CSSCounterValue>(
identifier, list_style, separator));
} else if (content_data->IsImage()) {
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_bitset.h b/chromium/third_party/blink/renderer/core/css/properties/css_bitset.h
index 998864c8e6b..f9c92c7912d 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_bitset.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_bitset.h
@@ -24,7 +24,7 @@ template <size_t kBits>
class CORE_EXPORT CSSBitsetBase {
public:
static_assert(
- kBits <= numCSSProperties,
+ kBits <= kNumCSSProperties,
"Bit count must not exceed numCSSProperties, as each bit position must "
"be representable as a CSSPropertyID");
@@ -98,7 +98,7 @@ class CORE_EXPORT CSSBitsetBase {
}
inline CSSPropertyID operator*() const {
- DCHECK_LT(index_, static_cast<size_t>(numCSSProperties));
+ DCHECK_LT(index_, static_cast<size_t>(kNumCSSProperties));
return static_cast<CSSPropertyID>(index_);
}
@@ -158,7 +158,7 @@ class CORE_EXPORT CSSBitsetBase {
uint64_t chunks_[kChunks];
};
-using CSSBitset = CSSBitsetBase<numCSSProperties>;
+using CSSBitset = CSSBitsetBase<kNumCSSProperties>;
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_bitset_test.cc b/chromium/third_party/blink/renderer/core/css/properties/css_bitset_test.cc
index 020be2fafad..b6bf9753014 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_bitset_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_bitset_test.cc
@@ -161,7 +161,7 @@ TEST(CSSBitsetTest, BaseBitCount129) {
TEST(CSSBitsetTest, AllBits) {
std::vector<size_t> all_bits;
- for (size_t i = 0; i < numCSSProperties; ++i)
+ for (size_t i = 0; i < kNumCSSProperties; ++i)
all_bits.push_back(i);
AssertBitset<1>(all_bits.data(), all_bits.data() + 1);
@@ -265,7 +265,7 @@ TEST(CSSBitsetTest, Iterator) {
actual.Set(CSSPropertyID::kWidth);
actual.Set(CSSPropertyID::kVariable);
- std::bitset<numCSSProperties> expected;
+ std::bitset<kNumCSSProperties> expected;
expected.set(static_cast<size_t>(CSSPropertyID::kHeight));
expected.set(static_cast<size_t>(CSSPropertyID::kWidth));
expected.set(static_cast<size_t>(CSSPropertyID::kVariable));
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc b/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc
index 451c66bec37..3b1b6963106 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc
@@ -11,110 +11,260 @@ namespace blink {
namespace {
template <size_t size>
-using PhysicalGroup = CSSDirectionAwareResolver::PhysicalGroup<size>;
+using LogicalMapping = CSSDirectionAwareResolver::LogicalMapping<size>;
+template <size_t size>
+using PhysicalMapping = CSSDirectionAwareResolver::PhysicalMapping<size>;
enum PhysicalAxis { kPhysicalAxisX, kPhysicalAxisY };
enum PhysicalBoxSide { kTopSide, kRightSide, kBottomSide, kLeftSide };
+enum PhysicalBoxCorner {
+ kTopLeftCorner,
+ kTopRightCorner,
+ kBottomRightCorner,
+ kBottomLeftCorner
+};
} // namespace
template <size_t size>
-CSSDirectionAwareResolver::PhysicalGroup<size>::PhysicalGroup(
+CSSDirectionAwareResolver::Group<size>::Group(
const StylePropertyShorthand& shorthand)
: properties_(shorthand.properties()) {
DCHECK_EQ(size, shorthand.length());
}
template <size_t size>
-CSSDirectionAwareResolver::PhysicalGroup<size>::PhysicalGroup(
+CSSDirectionAwareResolver::Group<size>::Group(
const CSSProperty* (&properties)[size])
: properties_(properties) {}
template <size_t size>
-const CSSProperty& CSSDirectionAwareResolver::PhysicalGroup<size>::GetProperty(
+const CSSProperty& CSSDirectionAwareResolver::Group<size>::GetProperty(
size_t index) const {
DCHECK_LT(index, size);
return *properties_[index];
}
-PhysicalGroup<4> CSSDirectionAwareResolver::BorderGroup() {
+template <size_t size>
+bool CSSDirectionAwareResolver::Group<size>::Contains(CSSPropertyID id) const {
+ for (size_t i = 0; i < size; ++i) {
+ if (properties_[i]->IDEquals(id))
+ return true;
+ }
+ return false;
+}
+
+template class CSSDirectionAwareResolver::Group<2ul>;
+template class CSSDirectionAwareResolver::Group<4ul>;
+
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalBorderMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyBorderBlockStart(), &GetCSSPropertyBorderBlockEnd(),
+ &GetCSSPropertyBorderInlineStart(), &GetCSSPropertyBorderInlineEnd()};
+ return LogicalMapping<4>(kProperties);
+}
+
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalBorderMapping() {
static const CSSProperty* kProperties[] = {
&GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
&GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
- return PhysicalGroup<4>(kProperties);
+ return PhysicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::BorderColorGroup() {
- return PhysicalGroup<4>(borderColorShorthand());
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalBorderColorMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyBorderBlockStartColor(),
+ &GetCSSPropertyBorderBlockEndColor(),
+ &GetCSSPropertyBorderInlineStartColor(),
+ &GetCSSPropertyBorderInlineEndColor()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::BorderStyleGroup() {
- return PhysicalGroup<4>(borderStyleShorthand());
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalBorderColorMapping() {
+ return PhysicalMapping<4>(borderColorShorthand());
}
-PhysicalGroup<4> CSSDirectionAwareResolver::BorderWidthGroup() {
- return PhysicalGroup<4>(borderWidthShorthand());
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalBorderStyleMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyBorderBlockStartStyle(),
+ &GetCSSPropertyBorderBlockEndStyle(),
+ &GetCSSPropertyBorderInlineStartStyle(),
+ &GetCSSPropertyBorderInlineEndStyle()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::InsetGroup() {
- return PhysicalGroup<4>(insetShorthand());
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalBorderStyleMapping() {
+ return PhysicalMapping<4>(borderStyleShorthand());
}
-PhysicalGroup<4> CSSDirectionAwareResolver::MarginGroup() {
- return PhysicalGroup<4>(marginShorthand());
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalBorderWidthMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyBorderBlockStartWidth(),
+ &GetCSSPropertyBorderBlockEndWidth(),
+ &GetCSSPropertyBorderInlineStartWidth(),
+ &GetCSSPropertyBorderInlineEndWidth()};
+ return LogicalMapping<4>(kProperties);
+}
+
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalBorderRadiusMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyBorderStartStartRadius(),
+ &GetCSSPropertyBorderStartEndRadius(),
+ &GetCSSPropertyBorderEndStartRadius(),
+ &GetCSSPropertyBorderEndEndRadius()};
+ return LogicalMapping<4>(kProperties);
+}
+
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalBorderRadiusMapping() {
+ return PhysicalMapping<4>(borderRadiusShorthand());
+}
+
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalBorderWidthMapping() {
+ return PhysicalMapping<4>(borderWidthShorthand());
}
-PhysicalGroup<2> CSSDirectionAwareResolver::MaxSizeGroup() {
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalInsetMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyInsetBlockStart(), &GetCSSPropertyInsetBlockEnd(),
+ &GetCSSPropertyInsetInlineStart(), &GetCSSPropertyInsetInlineEnd()};
+ return LogicalMapping<4>(kProperties);
+}
+
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalInsetMapping() {
+ return PhysicalMapping<4>(insetShorthand());
+}
+
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalMarginMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyMarginBlockStart(), &GetCSSPropertyMarginBlockEnd(),
+ &GetCSSPropertyMarginInlineStart(), &GetCSSPropertyMarginInlineEnd()};
+ return LogicalMapping<4>(kProperties);
+}
+
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalMarginMapping() {
+ return PhysicalMapping<4>(marginShorthand());
+}
+
+LogicalMapping<2> CSSDirectionAwareResolver::LogicalMaxSizeMapping() {
+ static const CSSProperty* kProperties[] = {&GetCSSPropertyMaxBlockSize(),
+ &GetCSSPropertyMaxInlineSize()};
+ return LogicalMapping<2>(kProperties);
+}
+
+PhysicalMapping<2> CSSDirectionAwareResolver::PhysicalMaxSizeMapping() {
static const CSSProperty* kProperties[] = {&GetCSSPropertyMaxWidth(),
&GetCSSPropertyMaxHeight()};
- return PhysicalGroup<2>(kProperties);
+ return PhysicalMapping<2>(kProperties);
}
-PhysicalGroup<2> CSSDirectionAwareResolver::MinSizeGroup() {
+LogicalMapping<2> CSSDirectionAwareResolver::LogicalMinSizeMapping() {
+ static const CSSProperty* kProperties[] = {&GetCSSPropertyMinBlockSize(),
+ &GetCSSPropertyMinInlineSize()};
+ return LogicalMapping<2>(kProperties);
+}
+
+PhysicalMapping<2> CSSDirectionAwareResolver::PhysicalMinSizeMapping() {
static const CSSProperty* kProperties[] = {&GetCSSPropertyMinWidth(),
&GetCSSPropertyMinHeight()};
- return PhysicalGroup<2>(kProperties);
+ return PhysicalMapping<2>(kProperties);
+}
+
+LogicalMapping<2> CSSDirectionAwareResolver::LogicalOverflowMapping() {
+ static const CSSProperty* kProperties[] = {&GetCSSPropertyOverflowBlock(),
+ &GetCSSPropertyOverflowInline()};
+ return LogicalMapping<2>(kProperties);
+}
+
+PhysicalMapping<2> CSSDirectionAwareResolver::PhysicalOverflowMapping() {
+ return PhysicalMapping<2>(overflowShorthand());
+}
+
+LogicalMapping<2>
+CSSDirectionAwareResolver::LogicalOverscrollBehaviorMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyOverscrollBehaviorBlock(),
+ &GetCSSPropertyOverscrollBehaviorInline()};
+ return LogicalMapping<2>(kProperties);
+}
+
+PhysicalMapping<2>
+CSSDirectionAwareResolver::PhysicalOverscrollBehaviorMapping() {
+ return PhysicalMapping<2>(overscrollBehaviorShorthand());
+}
+
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalPaddingMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyPaddingBlockStart(), &GetCSSPropertyPaddingBlockEnd(),
+ &GetCSSPropertyPaddingInlineStart(), &GetCSSPropertyPaddingInlineEnd()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<2> CSSDirectionAwareResolver::OverflowGroup() {
- return PhysicalGroup<2>(overflowShorthand());
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalPaddingMapping() {
+ return PhysicalMapping<4>(paddingShorthand());
}
-PhysicalGroup<2> CSSDirectionAwareResolver::OverscrollBehaviorGroup() {
- return PhysicalGroup<2>(overscrollBehaviorShorthand());
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalScrollMarginMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyScrollMarginBlockStart(),
+ &GetCSSPropertyScrollMarginBlockEnd(),
+ &GetCSSPropertyScrollMarginInlineStart(),
+ &GetCSSPropertyScrollMarginInlineEnd()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::PaddingGroup() {
- return PhysicalGroup<4>(paddingShorthand());
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalScrollMarginMapping() {
+ return PhysicalMapping<4>(scrollMarginShorthand());
}
-PhysicalGroup<4> CSSDirectionAwareResolver::ScrollMarginGroup() {
- return PhysicalGroup<4>(scrollMarginShorthand());
+LogicalMapping<4> CSSDirectionAwareResolver::LogicalScrollPaddingMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyScrollPaddingBlockStart(),
+ &GetCSSPropertyScrollPaddingBlockEnd(),
+ &GetCSSPropertyScrollPaddingInlineStart(),
+ &GetCSSPropertyScrollPaddingInlineEnd()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::ScrollPaddingGroup() {
- return PhysicalGroup<4>(scrollPaddingShorthand());
+PhysicalMapping<4> CSSDirectionAwareResolver::PhysicalScrollPaddingMapping() {
+ return PhysicalMapping<4>(scrollPaddingShorthand());
}
-PhysicalGroup<2> CSSDirectionAwareResolver::SizeGroup() {
+LogicalMapping<2> CSSDirectionAwareResolver::LogicalSizeMapping() {
+ static const CSSProperty* kProperties[] = {&GetCSSPropertyBlockSize(),
+ &GetCSSPropertyInlineSize()};
+ return LogicalMapping<2>(kProperties);
+}
+
+PhysicalMapping<2> CSSDirectionAwareResolver::PhysicalSizeMapping() {
static const CSSProperty* kProperties[] = {&GetCSSPropertyWidth(),
&GetCSSPropertyHeight()};
- return PhysicalGroup<2>(kProperties);
+ return PhysicalMapping<2>(kProperties);
+}
+
+LogicalMapping<4>
+CSSDirectionAwareResolver::LogicalVisitedBorderColorMapping() {
+ static const CSSProperty* kProperties[] = {
+ &GetCSSPropertyInternalVisitedBorderBlockStartColor(),
+ &GetCSSPropertyInternalVisitedBorderBlockEndColor(),
+ &GetCSSPropertyInternalVisitedBorderInlineStartColor(),
+ &GetCSSPropertyInternalVisitedBorderInlineEndColor()};
+ return LogicalMapping<4>(kProperties);
}
-PhysicalGroup<4> CSSDirectionAwareResolver::VisitedBorderColorGroup() {
+PhysicalMapping<4>
+CSSDirectionAwareResolver::PhysicalVisitedBorderColorMapping() {
static const CSSProperty* kProperties[] = {
&GetCSSPropertyInternalVisitedBorderTopColor(),
&GetCSSPropertyInternalVisitedBorderRightColor(),
&GetCSSPropertyInternalVisitedBorderBottomColor(),
&GetCSSPropertyInternalVisitedBorderLeftColor()};
- return PhysicalGroup<4>(kProperties);
+ return PhysicalMapping<4>(kProperties);
}
const CSSProperty& CSSDirectionAwareResolver::ResolveInlineStart(
TextDirection direction,
WritingMode writing_mode,
- const PhysicalGroup<4>& group) {
+ const PhysicalMapping<4>& group) {
if (direction == TextDirection::kLtr) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kLeftSide);
@@ -128,7 +278,7 @@ const CSSProperty& CSSDirectionAwareResolver::ResolveInlineStart(
const CSSProperty& CSSDirectionAwareResolver::ResolveInlineEnd(
TextDirection direction,
WritingMode writing_mode,
- const PhysicalGroup<4>& group) {
+ const PhysicalMapping<4>& group) {
if (direction == TextDirection::kLtr) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kRightSide);
@@ -142,7 +292,7 @@ const CSSProperty& CSSDirectionAwareResolver::ResolveInlineEnd(
const CSSProperty& CSSDirectionAwareResolver::ResolveBlockStart(
TextDirection direction,
WritingMode writing_mode,
- const PhysicalGroup<4>& group) {
+ const PhysicalMapping<4>& group) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kTopSide);
if (IsFlippedLinesWritingMode(writing_mode))
@@ -153,7 +303,7 @@ const CSSProperty& CSSDirectionAwareResolver::ResolveBlockStart(
const CSSProperty& CSSDirectionAwareResolver::ResolveBlockEnd(
TextDirection direction,
WritingMode writing_mode,
- const PhysicalGroup<4>& group) {
+ const PhysicalMapping<4>& group) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kBottomSide);
if (IsFlippedLinesWritingMode(writing_mode))
@@ -164,7 +314,7 @@ const CSSProperty& CSSDirectionAwareResolver::ResolveBlockEnd(
const CSSProperty& CSSDirectionAwareResolver::ResolveInline(
TextDirection,
WritingMode writing_mode,
- const PhysicalGroup<2>& group) {
+ const PhysicalMapping<2>& group) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kPhysicalAxisX);
return group.GetProperty(kPhysicalAxisY);
@@ -173,10 +323,78 @@ const CSSProperty& CSSDirectionAwareResolver::ResolveInline(
const CSSProperty& CSSDirectionAwareResolver::ResolveBlock(
TextDirection,
WritingMode writing_mode,
- const PhysicalGroup<2>& group) {
+ const PhysicalMapping<2>& group) {
if (IsHorizontalWritingMode(writing_mode))
return group.GetProperty(kPhysicalAxisY);
return group.GetProperty(kPhysicalAxisX);
}
+const CSSProperty& CSSDirectionAwareResolver::ResolveStartStart(
+ TextDirection direction,
+ WritingMode writing_mode,
+ const PhysicalMapping<4>& group) {
+ if (direction == TextDirection::kLtr) {
+ if (IsHorizontalWritingMode(writing_mode) ||
+ IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kTopLeftCorner);
+ return group.GetProperty(kTopRightCorner);
+ }
+ if (IsHorizontalWritingMode(writing_mode))
+ return group.GetProperty(kTopRightCorner);
+ if (IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kBottomLeftCorner);
+ return group.GetProperty(kBottomRightCorner);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveStartEnd(
+ TextDirection direction,
+ WritingMode writing_mode,
+ const PhysicalMapping<4>& group) {
+ if (direction == TextDirection::kLtr) {
+ if (IsHorizontalWritingMode(writing_mode))
+ return group.GetProperty(kTopRightCorner);
+ if (IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kBottomLeftCorner);
+ return group.GetProperty(kBottomRightCorner);
+ }
+ if (IsHorizontalWritingMode(writing_mode) ||
+ IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kTopLeftCorner);
+ return group.GetProperty(kTopRightCorner);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveEndStart(
+ TextDirection direction,
+ WritingMode writing_mode,
+ const PhysicalMapping<4>& group) {
+ if (direction == TextDirection::kLtr) {
+ if (IsHorizontalWritingMode(writing_mode))
+ return group.GetProperty(kBottomLeftCorner);
+ if (IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kTopRightCorner);
+ return group.GetProperty(kTopLeftCorner);
+ }
+ if (IsHorizontalWritingMode(writing_mode) ||
+ IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kBottomRightCorner);
+ return group.GetProperty(kBottomLeftCorner);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveEndEnd(
+ TextDirection direction,
+ WritingMode writing_mode,
+ const PhysicalMapping<4>& group) {
+ if (direction == TextDirection::kLtr) {
+ if (IsHorizontalWritingMode(writing_mode) ||
+ IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kBottomRightCorner);
+ return group.GetProperty(kBottomLeftCorner);
+ }
+ if (IsHorizontalWritingMode(writing_mode))
+ return group.GetProperty(kBottomLeftCorner);
+ if (IsFlippedLinesWritingMode(writing_mode))
+ return group.GetProperty(kTopRightCorner);
+ return group.GetProperty(kTopLeftCorner);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h b/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h
index 4340a49a9c1..b8fc2efebbb 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h
@@ -11,65 +11,163 @@
namespace blink {
+enum class CSSPropertyID;
class CSSProperty;
class StylePropertyShorthand;
class CSSDirectionAwareResolver {
STATIC_ONLY(CSSDirectionAwareResolver);
- public:
- // A group of physical properties that's used by the 'Resolve*' functions
- // to convert a direction-aware property into a physical property.
+ private:
template <size_t size>
- class PhysicalGroup {
+ class Group {
public:
- PhysicalGroup(const StylePropertyShorthand&);
- PhysicalGroup(const CSSProperty* (&properties)[size]);
+ explicit Group(const StylePropertyShorthand&);
+ explicit Group(const CSSProperty* (&properties)[size]);
const CSSProperty& GetProperty(size_t index) const;
+ bool Contains(CSSPropertyID) const;
private:
const CSSProperty** properties_;
};
- static PhysicalGroup<4> BorderGroup();
- static PhysicalGroup<4> BorderColorGroup();
- static PhysicalGroup<4> BorderStyleGroup();
- static PhysicalGroup<4> BorderWidthGroup();
- static PhysicalGroup<4> InsetGroup();
- static PhysicalGroup<4> MarginGroup();
- static PhysicalGroup<2> MaxSizeGroup();
- static PhysicalGroup<2> MinSizeGroup();
- static PhysicalGroup<2> OverflowGroup();
- static PhysicalGroup<2> OverscrollBehaviorGroup();
- static PhysicalGroup<4> PaddingGroup();
- static PhysicalGroup<4> ScrollMarginGroup();
- static PhysicalGroup<4> ScrollPaddingGroup();
- static PhysicalGroup<2> SizeGroup();
- static PhysicalGroup<4> VisitedBorderColorGroup();
-
- // These resolvers expect a PhysicalGroup with box sides, in the following
+ public:
+ // A group of logical properties that's used by the 'Resolve*' functions
+ // to convert a physical property into a direction-aware property.
+ // It represents the properties in a logical property group [1] with
+ // a flow-relative mapping logic [2].
+ // [1]: https://drafts.csswg.org/css-logical/#logical-property-group
+ // [2]: https://drafts.csswg.org/css-logical/#mapping-logic
+ template <size_t size>
+ class LogicalMapping : public Group<size> {
+ using Group<size>::Group;
+ };
+
+ // A group of physical properties that's used by the 'Resolve*' functions
+ // to convert a direction-aware property into a physical property.
+ // It represents the properties in a logical property group [1] with
+ // a physical mapping logic [2].
+ // [1]: https://drafts.csswg.org/css-logical/#logical-property-group
+ // [2]: https://drafts.csswg.org/css-logical/#mapping-logic
+ template <size_t size>
+ class PhysicalMapping : public Group<size> {
+ using Group<size>::Group;
+ };
+
+ static LogicalMapping<4> LogicalBorderMapping();
+ static LogicalMapping<4> LogicalBorderColorMapping();
+ static LogicalMapping<4> LogicalBorderRadiusMapping();
+ static LogicalMapping<4> LogicalBorderStyleMapping();
+ static LogicalMapping<4> LogicalBorderWidthMapping();
+ static LogicalMapping<4> LogicalInsetMapping();
+ static LogicalMapping<4> LogicalMarginMapping();
+ static LogicalMapping<2> LogicalMaxSizeMapping();
+ static LogicalMapping<2> LogicalMinSizeMapping();
+ static LogicalMapping<2> LogicalOverflowMapping();
+ static LogicalMapping<2> LogicalOverscrollBehaviorMapping();
+ static LogicalMapping<4> LogicalPaddingMapping();
+ static LogicalMapping<4> LogicalScrollMarginMapping();
+ static LogicalMapping<4> LogicalScrollPaddingMapping();
+ static LogicalMapping<2> LogicalSizeMapping();
+ static LogicalMapping<4> LogicalVisitedBorderColorMapping();
+
+ static PhysicalMapping<4> PhysicalBorderMapping();
+ static PhysicalMapping<4> PhysicalBorderColorMapping();
+ static PhysicalMapping<4> PhysicalBorderRadiusMapping();
+ static PhysicalMapping<4> PhysicalBorderStyleMapping();
+ static PhysicalMapping<4> PhysicalBorderWidthMapping();
+ static PhysicalMapping<4> PhysicalInsetMapping();
+ static PhysicalMapping<4> PhysicalMarginMapping();
+ static PhysicalMapping<2> PhysicalMaxSizeMapping();
+ static PhysicalMapping<2> PhysicalMinSizeMapping();
+ static PhysicalMapping<2> PhysicalOverflowMapping();
+ static PhysicalMapping<2> PhysicalOverscrollBehaviorMapping();
+ static PhysicalMapping<4> PhysicalPaddingMapping();
+ static PhysicalMapping<4> PhysicalScrollMarginMapping();
+ static PhysicalMapping<4> PhysicalScrollPaddingMapping();
+ static PhysicalMapping<2> PhysicalSizeMapping();
+ static PhysicalMapping<4> PhysicalVisitedBorderColorMapping();
+
+ // These resolvers expect a PhysicalMapping with box sides, in the following
// order: top, right, bottom, left.
static const CSSProperty& ResolveInlineStart(TextDirection,
WritingMode,
- const PhysicalGroup<4>&);
+ const PhysicalMapping<4>&);
static const CSSProperty& ResolveInlineEnd(TextDirection,
WritingMode,
- const PhysicalGroup<4>&);
+ const PhysicalMapping<4>&);
static const CSSProperty& ResolveBlockStart(TextDirection,
WritingMode,
- const PhysicalGroup<4>&);
+ const PhysicalMapping<4>&);
static const CSSProperty& ResolveBlockEnd(TextDirection,
WritingMode,
- const PhysicalGroup<4>&);
+ const PhysicalMapping<4>&);
- // These resolvers expect a PhysicalGroup with dimensions, in the following
+ // These resolvers expect a LogicalMapping with box sides, in the following
+ // order: block-start, block-end, inline-start, inline-end.
+ // TODO(layout-dev): Implement them, if needed.
+ static const CSSProperty& ResolveTop(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveBottom(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveLeft(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveRight(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+
+ // These resolvers expect a PhysicalMapping with dimensions, in the following
// order: horizontal, vertical.
static const CSSProperty& ResolveInline(TextDirection,
WritingMode,
- const PhysicalGroup<2>&);
+ const PhysicalMapping<2>&);
static const CSSProperty& ResolveBlock(TextDirection,
WritingMode,
- const PhysicalGroup<2>&);
+ const PhysicalMapping<2>&);
+
+ // These resolvers expect a LogicalMapping with dimensions, in the following
+ // order: block, inline.
+ // TODO(layout-dev): Implement them, if needed.
+ static const CSSProperty& ResolveHorizontal(TextDirection,
+ WritingMode,
+ const LogicalMapping<2>&);
+ static const CSSProperty& ResolveVertical(TextDirection,
+ WritingMode,
+ const LogicalMapping<2>&);
+
+ // These resolvers expect a a PhysicalMapping with box corners, in the
+ // following order: top-left, top-right, bottom-right, bottom-left.
+ static const CSSProperty& ResolveStartStart(TextDirection,
+ WritingMode,
+ const PhysicalMapping<4>&);
+ static const CSSProperty& ResolveStartEnd(TextDirection,
+ WritingMode,
+ const PhysicalMapping<4>&);
+ static const CSSProperty& ResolveEndStart(TextDirection,
+ WritingMode,
+ const PhysicalMapping<4>&);
+ static const CSSProperty& ResolveEndEnd(TextDirection,
+ WritingMode,
+ const PhysicalMapping<4>&);
+
+ // These resolvers expect a a LogicalMapping with box corners, in the
+ // following order: start-start, start-end, end-start, end-end.
+ // TODO(layout-dev): Implement them, if needed.
+ static const CSSProperty& ResolveTopLeft(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveTopRight(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveBottomRight(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
+ static const CSSProperty& ResolveBottomLeft(TextDirection,
+ WritingMode,
+ const LogicalMapping<4>&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index d169af4d044..da5eebcb425 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
#include "third_party/blink/renderer/core/css/css_axis_value.h"
#include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
#include "third_party/blink/renderer/core/css/css_border_image.h"
@@ -69,6 +70,7 @@
#include "third_party/blink/renderer/platform/geometry/length.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/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -2163,28 +2165,29 @@ static CSSValue* ConsumeGeneratedImage(CSSParserTokenRange& range,
return result;
}
-static CSSValue* CreateCSSImageValueWithReferrer(
+static CSSImageValue* CreateCSSImageValueWithReferrer(
const AtomicString& raw_value,
const CSSParserContext& context) {
- CSSValue* image_value = MakeGarbageCollected<CSSImageValue>(
+ return MakeGarbageCollected<CSSImageValue>(
raw_value, context.CompleteURL(raw_value), context.GetReferrer(),
context.IsOriginClean() ? OriginClean::kTrue : OriginClean::kFalse,
context.IsAdRelated());
- return image_value;
}
static CSSValue* ConsumeImageSet(CSSParserTokenRange& range,
const CSSParserContext& context) {
CSSParserTokenRange range_copy = range;
CSSParserTokenRange args = ConsumeFunction(range_copy);
- auto* image_set = MakeGarbageCollected<CSSImageSetValue>(context.Mode());
+ auto* image_set = MakeGarbageCollected<CSSImageSetValue>();
do {
AtomicString url_value =
ConsumeUrlAsStringView(args, context).ToAtomicString();
if (url_value.IsNull())
return nullptr;
- CSSValue* image = CreateCSSImageValueWithReferrer(url_value, context);
+ CSSImageValue* image = CreateCSSImageValueWithReferrer(url_value, context);
+ if (context.Mode() == kUASheetMode)
+ image->SetInitiator(fetch_initiator_type_names::kUacss);
image_set->Append(*image);
const CSSParserToken& token = args.ConsumeIncludingWhitespace();
@@ -2251,14 +2254,14 @@ void AddProperty(CSSPropertyID resolved_property,
bool important,
IsImplicitProperty implicit,
HeapVector<CSSPropertyValue, 256>& properties) {
- DCHECK(!isPropertyAlias(resolved_property));
+ DCHECK(!IsPropertyAlias(resolved_property));
DCHECK(implicit == IsImplicitProperty::kNotImplicit ||
implicit == IsImplicitProperty::kImplicit);
int shorthand_index = 0;
bool set_from_shorthand = false;
- if (isValidCSSPropertyID(current_shorthand)) {
+ if (IsValidCSSPropertyID(current_shorthand)) {
Vector<StylePropertyShorthand, 4> shorthands;
getMatchingShorthandsForLonghand(resolved_property, &shorthands);
set_from_shorthand = true;
@@ -2408,7 +2411,7 @@ const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
CSSPropertyID current_shorthand,
const CSSParserContext& context,
CSSParserTokenRange& range) {
- CSSPropertyID property_id = resolveCSSPropertyID(unresolved_property);
+ CSSPropertyID property_id = ResolveCSSPropertyID(unresolved_property);
DCHECK(!CSSProperty::Get(property_id).IsShorthand());
if (CSSParserFastPaths::IsKeywordPropertyID(property_id)) {
if (CSSParserFastPaths::IsValidKeywordPropertyAndValue(
@@ -2417,14 +2420,12 @@ const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
return ConsumeIdent(range);
}
- // Some properties need to fallback onto the regular parser.
- if (!CSSParserFastPaths::IsPartialKeywordPropertyID(property_id))
- return nullptr;
+ return nullptr;
}
const auto local_context =
CSSParserLocalContext()
- .WithAliasParsing(isPropertyAlias(unresolved_property))
+ .WithAliasParsing(IsPropertyAlias(unresolved_property))
.WithCurrentShorthand(current_shorthand);
const CSSValue* result = To<Longhand>(CSSProperty::Get(property_id))
@@ -4803,7 +4804,7 @@ CSSValue* ConsumeTransitionProperty(CSSParserTokenRange& range,
if (unresolved_property != CSSPropertyID::kInvalid &&
unresolved_property != CSSPropertyID::kVariable) {
#if DCHECK_IS_ON()
- DCHECK(CSSProperty::Get(resolveCSSPropertyID(unresolved_property))
+ DCHECK(CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
.IsWebExposed(execution_context));
#endif
range.ConsumeIncludingWhitespace();
@@ -4847,8 +4848,8 @@ CSSValue* ParseSpacing(CSSParserTokenRange& range,
return ConsumeLength(range, context, kValueRangeAll, UnitlessQuirk::kAllow);
}
-CSSValue* ParsePaintStroke(CSSParserTokenRange& range,
- const CSSParserContext& context) {
+CSSValue* ConsumeSVGPaint(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
if (range.Peek().Id() == CSSValueID::kNone)
return ConsumeIdent(range);
cssvalue::CSSURIValue* url = ConsumeUrl(range, context);
@@ -4877,5 +4878,61 @@ UnitlessQuirk UnitlessUnlessShorthand(
: UnitlessQuirk::kForbid;
}
+bool ShouldLowerCaseCounterStyleNameOnParse(const AtomicString& name,
+ const CSSParserContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+
+ if (context.Mode() == kUASheetMode) {
+ // Names in UA sheet should be already in lower case.
+ DCHECK_EQ(name, name.LowerASCII());
+ return false;
+ }
+ return CounterStyleMap::GetUACounterStyleMap()->FindCounterStyleAcrossScopes(
+ name.LowerASCII());
+}
+
+CSSCustomIdentValue* ConsumeCounterStyleName(CSSParserTokenRange& range,
+ const CSSParserContext& context) {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+
+ CSSParserTokenRange original_range = range;
+
+ // <counter-style-name> is a <custom-ident> that is not an ASCII
+ // case-insensitive match for "none".
+ const CSSParserToken& name_token = range.ConsumeIncludingWhitespace();
+ if (name_token.GetType() != kIdentToken ||
+ !css_parsing_utils::IsCustomIdent<CSSValueID::kNone>(name_token.Id())) {
+ range = original_range;
+ return nullptr;
+ }
+
+ AtomicString name(name_token.Value().ToString());
+ if (ShouldLowerCaseCounterStyleNameOnParse(name, context))
+ name = name.LowerASCII();
+ return MakeGarbageCollected<CSSCustomIdentValue>(name);
+}
+
+AtomicString ConsumeCounterStyleNameInPrelude(CSSParserTokenRange& prelude,
+ const CSSParserContext& context) {
+ const CSSParserToken& name_token = prelude.ConsumeIncludingWhitespace();
+ if (!prelude.AtEnd())
+ return g_null_atom;
+
+ if (name_token.GetType() != kIdentToken ||
+ !IsCustomIdent<CSSValueID::kNone>(name_token.Id()))
+ return g_null_atom;
+
+ if (context.Mode() != kUASheetMode) {
+ if (name_token.Id() == CSSValueID::kDecimal ||
+ name_token.Id() == CSSValueID::kDisc)
+ return g_null_atom;
+ }
+
+ AtomicString name(name_token.Value().ToString());
+ if (ShouldLowerCaseCounterStyleNameOnParse(name, context))
+ name = name.LowerASCII();
+ return name;
+}
+
} // namespace css_parsing_utils
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index 543a8615638..ac372d91226 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -444,11 +444,22 @@ CSSValue* ConsumeBorderColorSide(CSSParserTokenRange&,
CSSValue* ConsumeBorderWidth(CSSParserTokenRange&,
const CSSParserContext&,
UnitlessQuirk);
-CSSValue* ParsePaintStroke(CSSParserTokenRange&, const CSSParserContext&);
+CSSValue* ConsumeSVGPaint(CSSParserTokenRange&, const CSSParserContext&);
CSSValue* ParseSpacing(CSSParserTokenRange&, const CSSParserContext&);
UnitlessQuirk UnitlessUnlessShorthand(const CSSParserLocalContext&);
+// https://drafts.csswg.org/css-counter-styles-3/#typedef-counter-style-name
+CSSCustomIdentValue* ConsumeCounterStyleName(CSSParserTokenRange&,
+ const CSSParserContext&);
+AtomicString ConsumeCounterStyleNameInPrelude(CSSParserTokenRange&,
+ const CSSParserContext&);
+
+// When parsing a counter style name, it should be ASCII lowercased if it's an
+// ASCII case-insensitive match of any predefined counter style name.
+bool ShouldLowerCaseCounterStyleNameOnParse(const AtomicString&,
+ const CSSParserContext&);
+
// Template implementations are at the bottom of the file for readability.
template <typename... emptyBaseCase>
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property.cc b/chromium/third_party/blink/renderer/core/css/properties/css_property.cc
index af17d6cc31b..ac97989bd73 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/css/cssom/style_value_factory.h"
#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
namespace blink {
@@ -20,7 +19,7 @@ const CSSProperty& GetCSSPropertyVariable() {
const CSSProperty& CSSProperty::Get(CSSPropertyID id) {
DCHECK_NE(id, CSSPropertyID::kInvalid);
- DCHECK_LE(id, lastCSSProperty); // last property id
+ DCHECK_LE(id, kLastCSSProperty); // last property id
return To<CSSProperty>(CSSUnresolvedProperty::GetNonAliasProperty(id));
}
@@ -45,11 +44,10 @@ const CSSValue* CSSProperty::CSSValueFromComputedStyle(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style) const {
- const SVGComputedStyle& svg_style = style.SvgStyle();
const CSSProperty& resolved_property =
ResolveDirectionAwareProperty(style.Direction(), style.GetWritingMode());
return resolved_property.CSSValueFromComputedStyleInternal(
- style, svg_style, layout_object, allow_visited_style);
+ style, layout_object, allow_visited_style);
}
void CSSProperty::FilterWebExposedCSSPropertiesIntoVector(
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property.h b/chromium/third_party/blink/renderer/core/css/properties/css_property.h
index f50158c64fb..f44487e025d 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property.h
@@ -8,6 +8,7 @@
#include <memory>
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h"
#include "third_party/blink/renderer/core/css/properties/css_unresolved_property.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
@@ -21,7 +22,6 @@ class ComputedStyle;
class CrossThreadStyleValue;
class ExecutionContext;
class LayoutObject;
-class SVGComputedStyle;
class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
public:
@@ -58,10 +58,10 @@ class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
bool AffectsFont() const { return flags_ & kAffectsFont; }
bool IsBackground() const { return flags_ & kBackground; }
bool IsBorder() const { return flags_ & kBorder; }
- bool IsComputedValueComparable() const {
- return flags_ & kComputedValueComparable;
- }
bool TakesTreeScopedValue() const { return flags_ & kTreeScopedValue; }
+ bool IsInLogicalPropertyGroup() const {
+ return flags_ & kInLogicalPropertyGroup;
+ }
bool IsRepeated() const { return repetition_separator_ != '\0'; }
char RepetitionSeparator() const { return repetition_separator_; }
@@ -75,16 +75,8 @@ class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
return false;
}
- virtual bool ComputedValuesEqual(const ComputedStyle&,
- const ComputedStyle&) const {
- // May only be called if IsComputedValueComparable() is true.
- NOTREACHED();
- return false;
- }
-
virtual const CSSValue* CSSValueFromComputedStyleInternal(
const ComputedStyle&,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return nullptr;
@@ -100,6 +92,10 @@ class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
WritingMode) const {
return *this;
}
+ virtual bool IsInSameLogicalPropertyGroupWithDifferentMappingLogic(
+ CSSPropertyID) const {
+ return false;
+ }
virtual const CSSProperty* GetVisitedProperty() const { return nullptr; }
virtual const CSSProperty* GetUnvisitedProperty() const { return nullptr; }
@@ -145,12 +141,12 @@ class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
// element, the native appearance must be disabled.
kBackground = 1 << 15,
kBorder = 1 << 16,
- // Set if ComputedValuesEqual is implemented for the given CSSProperty.
- kComputedValueComparable = 1 << 17,
// Set if the property values are tree-scoped references.
- kTreeScopedValue = 1 << 18,
+ kTreeScopedValue = 1 << 17,
// https://drafts.csswg.org/css-pseudo-4/#highlight-styling
- kValidForHighlight = 1 << 19,
+ kValidForHighlight = 1 << 18,
+ // https://drafts.csswg.org/css-logical/#logical-property-group
+ kInLogicalPropertyGroup = 1 << 19,
};
constexpr CSSProperty(CSSPropertyID property_id,
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property_methods.json5 b/chromium/third_party/blink/renderer/core/css/properties/css_property_methods.json5
index b3b00959700..326bc0e5cff 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property_methods.json5
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property_methods.json5
@@ -32,7 +32,7 @@
{
name: "CSSValueFromComputedStyleInternal",
return_type: "const CSSValue*",
- parameters: "(const ComputedStyle&, const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style)",
+ parameters: "(const ComputedStyle&, const LayoutObject*, bool allow_visited_style)",
},
{
name: "ColorIncludingFallback",
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.cc b/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.cc
index 0cd1fdcae0a..d93f3fbdb7d 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.cc
@@ -10,7 +10,7 @@ namespace blink {
CSSPropertyRef::CSSPropertyRef(const String& name, const Document& document)
: property_id_(
- unresolvedCSSPropertyID(document.GetExecutionContext(), name)) {
+ UnresolvedCSSPropertyID(document.GetExecutionContext(), name)) {
if (property_id_ == CSSPropertyID::kVariable)
custom_property_ = CustomProperty(AtomicString(name), document);
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.h b/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.h
index c956e974602..6855c397af6 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property_ref.h
@@ -57,11 +57,11 @@ class CORE_EXPORT CSSPropertyRef {
DCHECK(IsValid());
if (property_id_ == CSSPropertyID::kVariable)
return custom_property_;
- return CSSProperty::Get(resolveCSSPropertyID(property_id_));
+ return CSSProperty::Get(ResolveCSSPropertyID(property_id_));
}
const CSSUnresolvedProperty& GetUnresolvedProperty() const {
- if (isPropertyAlias(property_id_))
+ if (IsPropertyAlias(property_id_))
return *CSSUnresolvedProperty::GetAliasProperty(property_id_);
return GetProperty();
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_property_test.cc b/chromium/third_party/blink/renderer/core/css/properties/css_property_test.cc
index 7495249acac..851f356e326 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_property_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_property_test.cc
@@ -129,164 +129,18 @@ TEST_F(CSSPropertyTest, Surrogates) {
WritingMode::kHorizontalTb));
}
-TEST_F(CSSPropertyTest, ComputedValuesEqualsSelf) {
- scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
-
- for (CSSPropertyID id : CSSPropertyIDList()) {
- const CSSProperty& property = CSSProperty::Get(id);
- if (!property.IsComputedValueComparable())
- continue;
- EXPECT_TRUE(property.ComputedValuesEqual(*style, *style));
- }
-}
-
-namespace {
-
-// Examples must produce unique computed values. For example, it's not
-// allowed to list both 2px and calc(1px + 1px).
-const char* align_content_examples[] = {"normal", "first baseline", "stretch",
- "safe end", nullptr};
-const char* border_style_examples[] = {"none", "solid", "dashed", nullptr};
-const char* color_examples[] = {"red", "green", "#fef", "#faf", nullptr};
-const char* direction_examples[] = {"ltr", "rtl", nullptr};
-const char* flex_direction_examples[] = {"row", "column", nullptr};
-const char* flex_wrap_examples[] = {"nowrap", "wrap", nullptr};
-const char* float_examples[] = {"1", "2.5", nullptr};
-const char* justify_content_examples[] = {"normal", "stretch", "safe end",
- "left", nullptr};
-const char* length_or_auto_examples[] = {"auto", "1px", "2px", "5%", nullptr};
-const char* length_or_none_examples[] = {"none", "1px", "2px", "5%", nullptr};
-const char* length_percentage_examples[] = {"1px", "2%", "calc(1% + 2px)",
- nullptr};
-const char* length_size_examples[] = {"4px", "1px 2px", "3%", "calc(1% + 1px)",
- nullptr};
-const char* line_width_examples[] = {"medium", "thin", "100px", nullptr};
-const char* none_auto_examples[] = {"none", "auto", nullptr};
-const char* self_align_examples[] = {"flex-start", "flex-end", "first baseline",
- "safe end", nullptr};
-const char* text_decoration_line_examples[] = {"none", "underline", nullptr};
-const char* text_decoration_style_examples[] = {"solid", "dashed", nullptr};
-const char* vertical_align_examples[] = {"sub", "super", "1px", "3%", nullptr};
-const char* writing_mode_examples[] = {"horizontal-tb", "vertical-rl", nullptr};
-
-struct ComputedValuesEqualData {
- const char* name;
- const char** examples;
-} computed_values_equal_data[] = {
- {"-webkit-writing-mode", writing_mode_examples},
- {"align-content", align_content_examples},
- {"align-items", self_align_examples},
- {"align-self", self_align_examples},
- {"border-bottom-color", color_examples},
- {"border-bottom-left-radius", length_size_examples},
- {"border-bottom-right-radius", length_size_examples},
- {"border-bottom-style", border_style_examples},
- {"border-bottom-width", line_width_examples},
- {"border-left-color", color_examples},
- {"border-left-style", border_style_examples},
- {"border-left-width", line_width_examples},
- {"border-right-color", color_examples},
- {"border-right-style", border_style_examples},
- {"border-right-width", line_width_examples},
- {"border-top-color", color_examples},
- {"border-top-left-radius", length_size_examples},
- {"border-top-right-radius", length_size_examples},
- {"border-top-style", border_style_examples},
- {"border-top-width", line_width_examples},
- {"bottom", length_or_auto_examples},
- {"direction", direction_examples},
- {"flex-basis", length_or_auto_examples},
- {"flex-direction", flex_direction_examples},
- {"flex-grow", float_examples},
- {"flex-shrink", float_examples},
- {"flex-wrap", flex_wrap_examples},
- {"height", length_or_auto_examples},
- {"justify-content", justify_content_examples},
- {"justify-items", self_align_examples},
- {"justify-self", self_align_examples},
- {"left", length_or_auto_examples},
- {"margin-bottom", length_or_auto_examples},
- {"margin-left", length_or_auto_examples},
- {"margin-right", length_or_auto_examples},
- {"margin-top", length_or_auto_examples},
- {"max-height", length_or_none_examples},
- {"max-width", length_or_none_examples},
- {"min-height", length_or_auto_examples},
- {"min-width", length_or_auto_examples},
- {"padding-bottom", length_percentage_examples},
- {"padding-left", length_percentage_examples},
- {"padding-right", length_percentage_examples},
- {"padding-top", length_percentage_examples},
- {"right", length_or_auto_examples},
- {"text-decoration-color", color_examples},
- {"text-decoration-line", text_decoration_line_examples},
- {"text-decoration-skip-ink", none_auto_examples},
- {"text-decoration-style", text_decoration_style_examples},
- {"text-decoration-thickness", length_or_auto_examples},
- {"top", length_or_auto_examples},
- {"vertical-align", vertical_align_examples},
- {"width", length_or_auto_examples},
- {"writing-mode", writing_mode_examples},
-};
-
-} // namespace
-
-TEST_F(CSSPropertyTest, ComparablePropertiesAreListed) {
- HashSet<String> names;
- for (const auto& data : computed_values_equal_data)
- names.insert(data.name);
-
- for (CSSPropertyID id : CSSPropertyIDList()) {
- const CSSProperty& property = CSSProperty::Get(id);
- EXPECT_TRUE(!property.IsComputedValueComparable() ||
- names.Contains(property.GetPropertyNameString()))
- << property.GetPropertyNameString() << " missing";
- }
-}
-
-// This test verifies the correctness of CSSProperty::ComputedValuesEqual for
-// all properties that have the kComputedValueComparable flag.
-class ComputedValuesEqual
- : public CSSPropertyTest,
- public testing::WithParamInterface<ComputedValuesEqualData> {};
-
-INSTANTIATE_TEST_SUITE_P(CSSPropertyTest,
- ComputedValuesEqual,
- testing::ValuesIn(computed_values_equal_data));
-
-TEST_P(ComputedValuesEqual, Examples) {
- auto data = GetParam();
-
- CSSPropertyRef ref(data.name, GetDocument());
- ASSERT_TRUE(ref.IsValid()) << data.name;
- const CSSProperty& property = ref.GetProperty();
- ASSERT_TRUE(property.IsComputedValueComparable()) << data.name;
-
- // Convert const char* examples to CSSValues.
- HeapVector<Member<const CSSValue>> values;
- for (const char** example = data.examples; *example; ++example) {
- const CSSValue* value = Parse(data.name, *example);
- ASSERT_TRUE(value) << data.name << ":" << *example;
- values.push_back(value);
- }
-
- for (const CSSValue* value_a : values) {
- for (const CSSValue* value_b : values) {
- auto style_a = ComputedStyleWithValue(property, *value_a);
- auto style_b = ComputedStyleWithValue(property, *value_b);
- if (value_a == value_b) {
- EXPECT_TRUE(property.ComputedValuesEqual(*style_a, *style_b))
- << property.GetPropertyNameString()
- << ": expected equality between " << value_a->CssText() << " and "
- << value_b->CssText();
- } else {
- EXPECT_FALSE(property.ComputedValuesEqual(*style_a, *style_b))
- << property.GetPropertyNameString()
- << ": expected non-equality between " << value_a->CssText()
- << " and " << value_b->CssText();
- }
- }
- }
+TEST_F(CSSPropertyTest, PairsWithIdenticalValues) {
+ const CSSValue* border_radius = css_test_helpers::ParseLonghand(
+ GetDocument(), GetCSSPropertyBorderTopLeftRadius(), "1% 1%");
+ const CSSValue* perspective_origin = css_test_helpers::ParseLonghand(
+ GetDocument(), GetCSSPropertyPerspectiveOrigin(), "1% 1%");
+
+ // Border radius drops identical values
+ EXPECT_EQ("1%", border_radius->CssText());
+ // Perspective origin keeps identical values
+ EXPECT_EQ("1% 1%", perspective_origin->CssText());
+ // Therefore, the values are different
+ EXPECT_NE(*border_radius, *perspective_origin);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/properties/css_unresolved_property.cc b/chromium/third_party/blink/renderer/core/css/properties/css_unresolved_property.cc
index 901de0c53ae..904443d3438 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/css_unresolved_property.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/css_unresolved_property.cc
@@ -27,8 +27,8 @@ const CSSUnresolvedProperty& CSSUnresolvedProperty::GetNonAliasProperty(
const CSSUnresolvedProperty& CSSUnresolvedProperty::Get(CSSPropertyID id) {
DCHECK_NE(id, CSSPropertyID::kInvalid);
- DCHECK_LE(id, lastUnresolvedCSSProperty);
- if (id <= lastCSSProperty)
+ DCHECK_LE(id, kLastUnresolvedCSSProperty);
+ if (id <= kLastCSSProperty)
return GetNonAliasProperty(id);
return *GetAliasProperty(id);
}
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
index ddb9465d25a..8baa9775229 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -38,8 +38,7 @@ CustomProperty::CustomProperty(const AtomicString& name,
CustomProperty::CustomProperty(const AtomicString& name,
const PropertyRegistration* registration)
- : Variable(InheritedFlag(registration) |
- CSSProperty::kComputedValueComparable),
+ : Variable(InheritedFlag(registration)),
name_(name),
registration_(registration) {}
@@ -156,23 +155,8 @@ const CSSValue* CustomProperty::ParseSingleValue(
}
}
-bool CustomProperty::ComputedValuesEqual(const ComputedStyle& a,
- const ComputedStyle& b) const {
- if (registration_) {
- const CSSValue* a_value = a.GetVariableValue(name_, IsInherited());
- const CSSValue* b_value = b.GetVariableValue(name_, IsInherited());
- if (!DataEquivalent(a_value, b_value))
- return false;
- }
-
- CSSVariableData* a_data = a.GetVariableData(name_, IsInherited());
- CSSVariableData* b_data = b.GetVariableData(name_, IsInherited());
- return DataEquivalent(a_data, b_data);
-}
-
const CSSValue* CustomProperty::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (registration_) {
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
index e847acf2a7b..2666dc84bd5 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property.h
@@ -41,12 +41,8 @@ class CORE_EXPORT CustomProperty : public Variable {
const CSSParserContext&,
const CSSParserLocalContext&) const override;
- bool ComputedValuesEqual(const ComputedStyle&,
- const ComputedStyle&) const override;
-
const CSSValue* CSSValueFromComputedStyleInternal(
const ComputedStyle&,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const override;
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
index 3adeb6553bd..ec5b1bed86b 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -87,38 +87,6 @@ TEST_F(CustomPropertyTest, GetPropertyNameAtomicString) {
EXPECT_EQ(AtomicString("--x"), property.GetPropertyNameAtomicString());
}
-TEST_F(CustomPropertyTest, ComputedValuesEqual) {
- RegisterProperty(GetDocument(), "--y", "<length>", "100px", false);
-
- CustomProperty x("--x", GetDocument());
- CustomProperty y("--y", GetDocument());
-
- SetElementWithStyle("--x:foo;--y:10px");
- auto style1 = ComputedStyle::Clone(GetComputedStyle());
-
- SetElementWithStyle("--x:foo;--y:10px");
- auto style2 = ComputedStyle::Clone(GetComputedStyle());
-
- SetElementWithStyle("--x:bar;--y:30px");
- auto style3 = ComputedStyle::Clone(GetComputedStyle());
-
- ASSERT_TRUE(x.IsComputedValueComparable());
- EXPECT_TRUE(x.ComputedValuesEqual(*style1, *style1));
- EXPECT_TRUE(x.ComputedValuesEqual(*style2, *style2));
- EXPECT_TRUE(x.ComputedValuesEqual(*style1, *style2));
- EXPECT_TRUE(x.ComputedValuesEqual(*style2, *style1));
- EXPECT_FALSE(x.ComputedValuesEqual(*style1, *style3));
- EXPECT_FALSE(x.ComputedValuesEqual(*style2, *style3));
-
- ASSERT_TRUE(y.IsComputedValueComparable());
- EXPECT_TRUE(y.ComputedValuesEqual(*style1, *style1));
- EXPECT_TRUE(y.ComputedValuesEqual(*style2, *style2));
- EXPECT_TRUE(y.ComputedValuesEqual(*style1, *style2));
- EXPECT_TRUE(y.ComputedValuesEqual(*style2, *style1));
- EXPECT_FALSE(y.ComputedValuesEqual(*style1, *style3));
- EXPECT_FALSE(y.ComputedValuesEqual(*style2, *style3));
-}
-
TEST_F(CustomPropertyTest, ComputedCSSValueUnregistered) {
CustomProperty property("--x", GetDocument());
SetElementWithStyle("--x:foo");
diff --git a/chromium/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index aca3425b947..a50b34f73be 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/css/css_cursor_image_value.h"
#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
#include "third_party/blink/renderer/core/css/css_font_feature_value.h"
+#include "third_party/blink/renderer/core/css/css_font_selector.h"
#include "third_party/blink/renderer/core/css/css_font_variation_value.h"
#include "third_party/blink/renderer/core/css/css_function_value.h"
#include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
@@ -74,7 +75,6 @@ const CSSValue* AlignContent::ParseSingleValue(
const CSSValue* AlignContent::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::
@@ -95,7 +95,6 @@ const CSSValue* AlignItems::ParseSingleValue(
const CSSValue* AlignItems::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment(
@@ -112,7 +111,6 @@ const CSSValue* AlignSelf::ParseSingleValue(
const CSSValue* AlignSelf::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment(
@@ -120,10 +118,9 @@ const CSSValue* AlignSelf::CSSValueFromComputedStyleInternal(
}
const CSSValue* AlignmentBaseline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.AlignmentBaseline());
+ return CSSIdentifierValue::Create(style.AlignmentBaseline());
}
const CSSValue* AnimationDelay::ParseSingleValue(
@@ -136,7 +133,6 @@ const CSSValue* AnimationDelay::ParseSingleValue(
const CSSValue* AnimationDelay::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationDelay(style.Animations());
@@ -163,7 +159,6 @@ const CSSValue* AnimationDirection::ParseSingleValue(
const CSSValue* AnimationDirection::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -195,7 +190,6 @@ const CSSValue* AnimationDuration::ParseSingleValue(
const CSSValue* AnimationDuration::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationDuration(style.Animations());
@@ -222,7 +216,6 @@ const CSSValue* AnimationFillMode::ParseSingleValue(
const CSSValue* AnimationFillMode::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -254,7 +247,6 @@ const CSSValue* AnimationIterationCount::ParseSingleValue(
const CSSValue* AnimationIterationCount::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -291,7 +283,6 @@ const CSSValue* AnimationName::ParseSingleValue(
const CSSValue* AnimationName::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -331,7 +322,6 @@ const CSSValue* AnimationPlayState::ParseSingleValue(
const CSSValue* AnimationPlayState::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -363,7 +353,6 @@ const CSSValue* AnimationTimeline::ParseSingleValue(
const CSSValue* AnimationTimeline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -391,7 +380,6 @@ const CSSValue* AnimationTimingFunction::ParseSingleValue(
const CSSValue* AnimationTimingFunction::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationTimingFunction(
@@ -424,6 +412,8 @@ const CSSValue* AspectRatio::ParseSingleValue(
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
height = css_parsing_utils::ConsumeNumber(range, context,
kValueRangeNonNegative);
+ if (!height)
+ return nullptr;
} else {
// A missing height is treated as 1.
height = CSSNumericLiteralValue::Create(
@@ -451,7 +441,6 @@ const CSSValue* AspectRatio::ParseSingleValue(
const CSSValue* AspectRatio::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
auto& ratio = style.AspectRatio();
@@ -482,14 +471,20 @@ const CSSValue* BackdropFilter::ParseSingleValue(
const CSSValue* BackdropFilter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFilter(style, style.BackdropFilter());
}
+
+void BackdropFilter::ApplyValue(StyleResolverState& state,
+ const CSSValue& value) const {
+ state.Style()->SetBackdropFilter(
+ StyleBuilderConverter::ConvertFilterOperations(state, value,
+ PropertyID()));
+}
+
const CSSValue* BackfaceVisibility::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(
@@ -508,7 +503,6 @@ const CSSValue* BackgroundAttachment::ParseSingleValue(
const CSSValue* BackgroundAttachment::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -528,7 +522,6 @@ const CSSValue* BackgroundBlendMode::ParseSingleValue(
const CSSValue* BackgroundBlendMode::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -548,7 +541,6 @@ const CSSValue* BackgroundClip::ParseSingleValue(
const CSSValue* BackgroundClip::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -572,13 +564,17 @@ const blink::Color BackgroundColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.BackgroundColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor background_color = style.BackgroundColor();
+ if (style.ShouldForceColor(background_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBackgroundColor())
+ .ColorIncludingFallback(false, style);
+ }
+ return background_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* BackgroundColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (allow_visited_style) {
@@ -586,10 +582,15 @@ const CSSValue* BackgroundColor::CSSValueFromComputedStyleInternal(
style.VisitedDependentColor(*this).Rgb());
}
+ StyleColor background_color = style.BackgroundColor();
+ if (style.ShouldForceColor(background_color)) {
+ return GetCSSPropertyInternalForcedBackgroundColor()
+ .CSSValueFromComputedStyle(style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.BackgroundColor(), CSSValuePhase::kUsedValue);
+ style, background_color, CSSValuePhase::kUsedValue);
}
const CSSValue* BackgroundImage::ParseSingleValue(
@@ -602,7 +603,6 @@ const CSSValue* BackgroundImage::ParseSingleValue(
const CSSValue* BackgroundImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer& fill_layer = style.BackgroundLayers();
@@ -620,7 +620,6 @@ const CSSValue* BackgroundOrigin::ParseSingleValue(
const CSSValue* BackgroundOrigin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -644,7 +643,6 @@ const CSSValue* BackgroundPositionX::ParseSingleValue(
const CSSValue* BackgroundPositionX::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer* curr_layer = &style.BackgroundLayers();
@@ -664,7 +662,6 @@ const CSSValue* BackgroundPositionY::ParseSingleValue(
const CSSValue* BackgroundPositionY::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer* curr_layer = &style.BackgroundLayers();
@@ -682,7 +679,6 @@ const CSSValue* BackgroundSize::ParseSingleValue(
const CSSValue* BackgroundSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer& fill_layer = style.BackgroundLayers();
@@ -704,54 +700,49 @@ const CSSValue* BaselineShift::ParseSingleValue(
const CSSValue* BaselineShift::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- switch (svg_style.BaselineShift()) {
- case BS_SUPER:
+ switch (style.BaselineShiftType()) {
+ case EBaselineShiftType::kSuper:
return CSSIdentifierValue::Create(CSSValueID::kSuper);
- case BS_SUB:
+ case EBaselineShiftType::kSub:
return CSSIdentifierValue::Create(CSSValueID::kSub);
- case BS_LENGTH:
+ case EBaselineShiftType::kLength:
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
- svg_style.BaselineShiftValue(), style);
+ style.BaselineShift(), style);
}
NOTREACHED();
return nullptr;
}
void BaselineShift::ApplyInherit(StyleResolverState& state) const {
- const SVGComputedStyle& parent_svg_style = state.ParentStyle()->SvgStyle();
- EBaselineShift baseline_shift = parent_svg_style.BaselineShift();
- SVGComputedStyle& svg_style = state.Style()->AccessSVGStyle();
- svg_style.SetBaselineShift(baseline_shift);
- if (baseline_shift == BS_LENGTH)
- svg_style.SetBaselineShiftValue(parent_svg_style.BaselineShiftValue());
+ state.Style()->SetBaselineShiftType(state.ParentStyle()->BaselineShiftType());
+ state.Style()->SetBaselineShift(state.ParentStyle()->BaselineShift());
}
void BaselineShift::ApplyValue(StyleResolverState& state,
const CSSValue& value) const {
- SVGComputedStyle& svg_style = state.Style()->AccessSVGStyle();
- auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
- if (!identifier_value) {
- svg_style.SetBaselineShift(BS_LENGTH);
- svg_style.SetBaselineShiftValue(StyleBuilderConverter::ConvertLength(
+ if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
+ EBaselineShiftType baseline_shift_type = EBaselineShiftType::kLength;
+ switch (identifier_value->GetValueID()) {
+ case CSSValueID::kBaseline:
+ baseline_shift_type = EBaselineShiftType::kLength;
+ break;
+ case CSSValueID::kSub:
+ baseline_shift_type = EBaselineShiftType::kSub;
+ break;
+ case CSSValueID::kSuper:
+ baseline_shift_type = EBaselineShiftType::kSuper;
+ break;
+ default:
+ NOTREACHED();
+ }
+ state.Style()->SetBaselineShiftType(baseline_shift_type);
+ state.Style()->SetBaselineShift(Length::Fixed());
+ } else {
+ state.Style()->SetBaselineShiftType(EBaselineShiftType::kLength);
+ state.Style()->SetBaselineShift(StyleBuilderConverter::ConvertLength(
state, To<CSSPrimitiveValue>(value)));
- return;
- }
- switch (identifier_value->GetValueID()) {
- case CSSValueID::kBaseline:
- svg_style.SetBaselineShift(BS_LENGTH);
- svg_style.SetBaselineShiftValue(Length::Fixed());
- return;
- case CSSValueID::kSub:
- svg_style.SetBaselineShift(BS_SUB);
- return;
- case CSSValueID::kSuper:
- svg_style.SetBaselineShift(BS_SUPER);
- return;
- default:
- NOTREACHED();
}
}
@@ -809,23 +800,31 @@ const blink::Color BorderBottomColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return ComputedStyleUtils::BorderSideColor(style, style.BorderBottomColor(),
- style.BorderBottomStyle(),
- visited_link);
+ StyleColor border_bottom_color = style.BorderBottomColor();
+ if (style.ShouldForceColor(border_bottom_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(false, style);
+ }
+ return ComputedStyleUtils::BorderSideColor(
+ style, border_bottom_color, style.BorderBottomStyle(), visited_link);
}
const CSSValue* BorderBottomColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ StyleColor border_bottom_color = style.BorderBottomColor();
+ if (style.ShouldForceColor(border_bottom_color)) {
+ return GetCSSPropertyInternalForcedBorderColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return allow_visited_style
? cssvalue::CSSColorValue::Create(
style.VisitedDependentColor(*this).Rgb())
: ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.BorderBottomColor(), CSSValuePhase::kUsedValue);
+ style, border_bottom_color, CSSValuePhase::kUsedValue);
}
const CSSValue* BorderBottomLeftRadius::ParseSingleValue(
@@ -837,7 +836,6 @@ const CSSValue* BorderBottomLeftRadius::ParseSingleValue(
const CSSValue* BorderBottomLeftRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForBorderRadiusCorner(
@@ -853,7 +851,6 @@ const CSSValue* BorderBottomRightRadius::ParseSingleValue(
const CSSValue* BorderBottomRightRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForBorderRadiusCorner(
@@ -861,7 +858,6 @@ const CSSValue* BorderBottomRightRadius::CSSValueFromComputedStyleInternal(
}
const CSSValue* BorderBottomStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BorderBottomStyle());
@@ -876,7 +872,6 @@ const CSSValue* BorderBottomWidth::ParseSingleValue(
const CSSValue* BorderBottomWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.BorderBottomWidth(), style);
@@ -884,7 +879,6 @@ const CSSValue* BorderBottomWidth::CSSValueFromComputedStyleInternal(
const CSSValue* BorderCollapse::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.BorderCollapse() == EBorderCollapse::kCollapse)
@@ -892,6 +886,20 @@ const CSSValue* BorderCollapse::CSSValueFromComputedStyleInternal(
return CSSIdentifierValue::Create(CSSValueID::kSeparate);
}
+const CSSValue* BorderEndEndRadius::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext&) const {
+ return css_parsing_utils::ParseBorderRadiusCorner(range, context);
+}
+
+const CSSValue* BorderEndStartRadius::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext&) const {
+ return css_parsing_utils::ParseBorderRadiusCorner(range, context);
+}
+
const CSSValue* BorderImageOutset::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
@@ -901,7 +909,6 @@ const CSSValue* BorderImageOutset::ParseSingleValue(
const CSSValue* BorderImageOutset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageQuad(
@@ -926,7 +933,6 @@ const CSSValue* BorderImageRepeat::ParseSingleValue(
const CSSValue* BorderImageRepeat::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageRepeat(style.BorderImage());
@@ -948,7 +954,6 @@ const CSSValue* BorderImageSlice::ParseSingleValue(
const CSSValue* BorderImageSlice::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageSlice(style.BorderImage());
@@ -975,7 +980,6 @@ const CSSValue* BorderImageSource::ParseSingleValue(
const CSSValue* BorderImageSource::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.BorderImageSource()) {
@@ -1006,7 +1010,6 @@ const CSSValue* BorderImageWidth::ParseSingleValue(
const CSSValue* BorderImageWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageQuad(
@@ -1064,27 +1067,35 @@ const blink::Color BorderLeftColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
+ StyleColor border_left_color = style.BorderLeftColor();
+ if (style.ShouldForceColor(border_left_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(false, style);
+ }
return ComputedStyleUtils::BorderSideColor(
- style, style.BorderLeftColor(), style.BorderLeftStyle(), visited_link);
+ style, border_left_color, style.BorderLeftStyle(), visited_link);
}
const CSSValue* BorderLeftColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ StyleColor border_left_color = style.BorderLeftColor();
+ if (style.ShouldForceColor(border_left_color)) {
+ return GetCSSPropertyInternalForcedBorderColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return allow_visited_style
? cssvalue::CSSColorValue::Create(
style.VisitedDependentColor(*this).Rgb())
: ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.BorderLeftColor(), CSSValuePhase::kUsedValue);
+ style, border_left_color, CSSValuePhase::kUsedValue);
}
const CSSValue* BorderLeftStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BorderLeftStyle());
@@ -1099,7 +1110,6 @@ const CSSValue* BorderLeftWidth::ParseSingleValue(
const CSSValue* BorderLeftWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.BorderLeftWidth(), style);
@@ -1117,27 +1127,35 @@ const blink::Color BorderRightColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return ComputedStyleUtils::BorderSideColor(
- style, style.BorderRightColor(), style.BorderRightStyle(), visited_link);
+ StyleColor border_right_color = style.BorderRightColor();
+ if (style.ShouldForceColor(border_right_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(false, style);
+ }
+ return ComputedStyleUtils::BorderSideColor(style, border_right_color,
+ style.BorderRightStyle(), false);
}
const CSSValue* BorderRightColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ StyleColor border_right_color = style.BorderRightColor();
+ if (style.ShouldForceColor(border_right_color)) {
+ return GetCSSPropertyInternalForcedBorderColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return allow_visited_style
? cssvalue::CSSColorValue::Create(
style.VisitedDependentColor(*this).Rgb())
: ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.BorderRightColor(), CSSValuePhase::kUsedValue);
+ style, border_right_color, CSSValuePhase::kUsedValue);
}
const CSSValue* BorderRightStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BorderRightStyle());
@@ -1152,12 +1170,25 @@ const CSSValue* BorderRightWidth::ParseSingleValue(
const CSSValue* BorderRightWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.BorderRightWidth(), style);
}
+const CSSValue* BorderStartStartRadius::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext&) const {
+ return css_parsing_utils::ParseBorderRadiusCorner(range, context);
+}
+
+const CSSValue* BorderStartEndRadius::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext&) const {
+ return css_parsing_utils::ParseBorderRadiusCorner(range, context);
+}
+
const CSSValue* BorderTopColor::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
@@ -1170,22 +1201,31 @@ const blink::Color BorderTopColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
+ StyleColor border_top_color = style.BorderTopColor();
+ if (style.ShouldForceColor(border_top_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(false, style);
+ }
return ComputedStyleUtils::BorderSideColor(
- style, style.BorderTopColor(), style.BorderTopStyle(), visited_link);
+ style, border_top_color, style.BorderTopStyle(), visited_link);
}
const CSSValue* BorderTopColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ StyleColor border_top_color = style.BorderTopColor();
+ if (style.ShouldForceColor(border_top_color)) {
+ return GetCSSPropertyInternalForcedBorderColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return allow_visited_style
? cssvalue::CSSColorValue::Create(
style.VisitedDependentColor(*this).Rgb())
: ComputedStyleUtils::ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.BorderTopColor(), CSSValuePhase::kUsedValue);
+ style, border_top_color, CSSValuePhase::kUsedValue);
}
const CSSValue* BorderTopLeftRadius::ParseSingleValue(
@@ -1197,7 +1237,6 @@ const CSSValue* BorderTopLeftRadius::ParseSingleValue(
const CSSValue* BorderTopLeftRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForBorderRadiusCorner(
@@ -1213,7 +1252,6 @@ const CSSValue* BorderTopRightRadius::ParseSingleValue(
const CSSValue* BorderTopRightRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForBorderRadiusCorner(
@@ -1222,7 +1260,6 @@ const CSSValue* BorderTopRightRadius::CSSValueFromComputedStyleInternal(
const CSSValue* BorderTopStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BorderTopStyle());
@@ -1237,7 +1274,6 @@ const CSSValue* BorderTopWidth::ParseSingleValue(
const CSSValue* BorderTopWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.BorderTopWidth(), style);
@@ -1259,7 +1295,6 @@ bool Bottom::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Bottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPositionOffset(style, *this,
@@ -1276,7 +1311,6 @@ const CSSValue* BoxShadow::ParseSingleValue(
const CSSValue* BoxShadow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
// https://drafts.csswg.org/cssom/#resolved-values
@@ -1287,7 +1321,6 @@ const CSSValue* BoxShadow::CSSValueFromComputedStyleInternal(
const CSSValue* BoxSizing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.BoxSizing() == EBoxSizing::kContentBox)
@@ -1297,7 +1330,6 @@ const CSSValue* BoxSizing::CSSValueFromComputedStyleInternal(
const CSSValue* BreakAfter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BreakAfter());
@@ -1305,7 +1337,6 @@ const CSSValue* BreakAfter::CSSValueFromComputedStyleInternal(
const CSSValue* BreakBefore::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BreakBefore());
@@ -1313,7 +1344,6 @@ const CSSValue* BreakBefore::CSSValueFromComputedStyleInternal(
const CSSValue* BreakInside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BreakInside());
@@ -1321,15 +1351,13 @@ const CSSValue* BreakInside::CSSValueFromComputedStyleInternal(
const CSSValue* BufferedRendering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.BufferedRendering());
+ return CSSIdentifierValue::Create(style.BufferedRendering());
}
const CSSValue* CaptionSide::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.CaptionSide());
@@ -1353,12 +1381,13 @@ const blink::Color CaretColor::ColorIncludingFallback(
// the background to ensure good visibility and contrast.
StyleColor result = auto_color.IsAutoColor() ? StyleColor::CurrentColor()
: auto_color.ToStyleColor();
+ if (style.ShouldForceColor(result))
+ return style.GetInternalForcedCurrentColor();
return result.Resolve(style.GetCurrentColor(), style.UsedColorScheme());
}
const CSSValue* CaretColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (allow_visited_style) {
@@ -1366,6 +1395,16 @@ const CSSValue* CaretColor::CSSValueFromComputedStyleInternal(
style.VisitedDependentColor(*this).Rgb());
}
+ StyleAutoColor auto_color = style.CaretColor();
+ // TODO(rego): We may want to adjust the caret color if it's the same as
+ // the background to ensure good visibility and contrast.
+ StyleColor result = auto_color.IsAutoColor() ? StyleColor::CurrentColor()
+ : auto_color.ToStyleColor();
+ if (style.ShouldForceColor(result)) {
+ return cssvalue::CSSColorValue::Create(
+ style.GetInternalForcedCurrentColor().Rgb());
+ }
+
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return ComputedStyleUtils::ValueForStyleAutoColor(style, style.CaretColor(),
@@ -1388,7 +1427,6 @@ void CaretColor::ApplyValue(StyleResolverState& state,
const CSSValue* Clear::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Clear());
@@ -1438,7 +1476,6 @@ const CSSValue* Clip::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Clip::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasAutoClip())
@@ -1469,7 +1506,6 @@ const CSSValue* ClipPath::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* ClipPath::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (ClipPathOperation* operation = style.ClipPath()) {
@@ -1487,10 +1523,9 @@ const CSSValue* ClipPath::CSSValueFromComputedStyleInternal(
const CSSValue* ClipRule::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.ClipRule());
+ return CSSIdentifierValue::Create(style.ClipRule());
}
const CSSValue* Color::ParseSingleValue(CSSParserTokenRange& range,
@@ -1504,14 +1539,21 @@ const blink::Color Color::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
+ if (style.ShouldForceColor(style.GetColor())) {
+ return To<Longhand>(GetCSSPropertyInternalForcedColor())
+ .ColorIncludingFallback(false, style);
+ }
return style.GetCurrentColor();
}
const CSSValue* Color::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ if (style.ShouldForceColor(style.GetColor())) {
+ return GetCSSPropertyInternalForcedColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
return cssvalue::CSSColorValue::Create(
allow_visited_style ? style.VisitedDependentColor(*this).Rgb()
: style.GetCurrentColor().Rgb());
@@ -1544,26 +1586,23 @@ void Color::ApplyValue(StyleResolverState& state, const CSSValue& value) const {
const CSSValue* ColorInterpolation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.ColorInterpolation());
+ return CSSIdentifierValue::Create(style.ColorInterpolation());
}
const CSSValue* ColorInterpolationFilters::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.ColorInterpolationFilters());
+ return CSSIdentifierValue::Create(style.ColorInterpolationFilters());
}
const CSSValue* ColorRendering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.ColorRendering());
+ return CSSIdentifierValue::Create(style.ColorRendering());
}
const CSSValue* ColorScheme::ParseSingleValue(
@@ -1597,7 +1636,6 @@ const CSSValue* ColorScheme::ParseSingleValue(
const CSSValue* ColorScheme::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.ColorScheme().IsEmpty())
@@ -1674,7 +1712,6 @@ const CSSValue* ColumnCount::ParseSingleValue(
const CSSValue* ColumnCount::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasAutoColumnCount())
@@ -1685,7 +1722,6 @@ const CSSValue* ColumnCount::CSSValueFromComputedStyleInternal(
const CSSValue* ColumnFill::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetColumnFill());
@@ -1700,7 +1736,6 @@ const CSSValue* ColumnGap::ParseSingleValue(
const CSSValue* ColumnGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool) const {
return ComputedStyleUtils::ValueForGapLength(style.ColumnGap(), style);
@@ -1717,13 +1752,15 @@ const blink::Color ColumnRuleColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.ColumnRuleColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor column_rule_color = style.ColumnRuleColor();
+ if (style.ShouldForceColor(column_rule_color))
+ return style.GetInternalForcedCurrentColor();
+ return column_rule_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* ColumnRuleColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return allow_visited_style ? cssvalue::CSSColorValue::Create(
@@ -1735,7 +1772,6 @@ const CSSValue* ColumnRuleColor::CSSValueFromComputedStyleInternal(
const CSSValue* ColumnRuleStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ColumnRuleStyle());
@@ -1751,7 +1787,6 @@ const CSSValue* ColumnRuleWidth::ParseSingleValue(
const CSSValue* ColumnRuleWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.ColumnRuleWidth(), style);
@@ -1767,7 +1802,6 @@ const CSSValue* ColumnSpan::ParseSingleValue(
const CSSValue* ColumnSpan::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(static_cast<unsigned>(style.GetColumnSpan())
@@ -1784,7 +1818,6 @@ const CSSValue* ColumnWidth::ParseSingleValue(
const CSSValue* ColumnWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasAutoColumnWidth())
@@ -1812,16 +1845,20 @@ const CSSValue* Contain::ParseSingleValue(CSSParserTokenRange& range,
CSSIdentifierValue* paint = nullptr;
while (true) {
id = range.Peek().Id();
- if (id == CSSValueID::kSize && !size)
+ if ((id == CSSValueID::kSize ||
+ (RuntimeEnabledFeatures::CSSContainSize1DEnabled() &&
+ (id == CSSValueID::kBlockSize || id == CSSValueID::kInlineSize))) &&
+ !size) {
size = css_parsing_utils::ConsumeIdent(range);
- else if (id == CSSValueID::kLayout && !layout)
+ } else if (id == CSSValueID::kLayout && !layout) {
layout = css_parsing_utils::ConsumeIdent(range);
- else if (id == CSSValueID::kStyle && !style)
+ } else if (id == CSSValueID::kStyle && !style) {
style = css_parsing_utils::ConsumeIdent(range);
- else if (id == CSSValueID::kPaint && !paint)
+ } else if (id == CSSValueID::kPaint && !paint) {
paint = css_parsing_utils::ConsumeIdent(range);
- else
+ } else {
break;
+ }
}
if (size)
list->Append(*size);
@@ -1840,7 +1877,6 @@ const CSSValue* Contain::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Contain::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.Contain())
@@ -1851,9 +1887,15 @@ const CSSValue* Contain::CSSValueFromComputedStyleInternal(
return CSSIdentifierValue::Create(CSSValueID::kContent);
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
- if (style.ContainsSize())
+ if (style.ContainsSize()) {
list->Append(*CSSIdentifierValue::Create(CSSValueID::kSize));
- if (style.Contain() & kContainsLayout)
+ } else {
+ if (style.ContainsInlineSize())
+ list->Append(*CSSIdentifierValue::Create(CSSValueID::kInlineSize));
+ else if (style.ContainsBlockSize())
+ list->Append(*CSSIdentifierValue::Create(CSSValueID::kBlockSize));
+ }
+ if (style.ContainsLayout())
list->Append(*CSSIdentifierValue::Create(CSSValueID::kLayout));
if (style.ContainsStyle())
list->Append(*CSSIdentifierValue::Create(CSSValueID::kStyle));
@@ -1883,7 +1925,6 @@ const CSSValue* ContainIntrinsicSize::ParseSingleValue(
const CSSValue* ContainIntrinsicSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
auto& size = style.ContainIntrinsicSize();
@@ -1939,18 +1980,32 @@ CSSValue* ConsumeCounterContent(CSSParserTokenRange args,
args.ConsumeIncludingWhitespace().Value().ToString());
}
- CSSIdentifierValue* list_style = nullptr;
+ CSSCustomIdentValue* list_style = nullptr;
if (css_parsing_utils::ConsumeCommaIncludingWhitespace(args)) {
- CSSValueID id = args.Peek().Id();
- if ((id != CSSValueID::kNone &&
- (id < CSSValueID::kDisc || id > CSSValueID::kKatakanaIroha)))
- return nullptr;
- list_style = css_parsing_utils::ConsumeIdent(args);
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ CSSValueID id = args.Peek().Id();
+ if ((id != CSSValueID::kNone &&
+ (id < CSSValueID::kDisc || id > CSSValueID::kKatakanaIroha)))
+ return nullptr;
+ list_style = MakeGarbageCollected<CSSCustomIdentValue>(
+ AtomicString(getValueName(id)));
+ args.ConsumeIncludingWhitespace();
+ } else {
+ // Note: CSS3 spec doesn't allow 'none' but CSS2.1 allows it. We currently
+ // allow it for backward compatibility.
+ // See https://github.com/w3c/csswg-drafts/issues/5795 for details.
+ if (args.Peek().Id() == CSSValueID::kNone) {
+ list_style = MakeGarbageCollected<CSSCustomIdentValue>("none");
+ args.ConsumeIncludingWhitespace();
+ } else {
+ list_style = css_parsing_utils::ConsumeCounterStyleName(args, context);
+ }
+ }
} else {
- list_style = CSSIdentifierValue::Create(CSSValueID::kDecimal);
+ list_style = MakeGarbageCollected<CSSCustomIdentValue>("decimal");
}
- if (!args.AtEnd())
+ if (!list_style || !args.AtEnd())
return nullptr;
return MakeGarbageCollected<cssvalue::CSSCounterValue>(identifier, list_style,
separator);
@@ -2015,7 +2070,6 @@ const CSSValue* Content::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Content::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForContentData(style, allow_visited_style);
@@ -2032,6 +2086,12 @@ void Content::ApplyInherit(StyleResolverState& state) const {
void Content::ApplyValue(StyleResolverState& state,
const CSSValue& value) const {
+ NOTREACHED();
+}
+
+void Content::ApplyValue(StyleResolverState& state,
+ const ScopedCSSValue& scoped_value) const {
+ const CSSValue& value = scoped_value.GetCSSValue();
if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
DCHECK(identifier_value->GetValueID() == CSSValueID::kNormal ||
identifier_value->GetValueID() == CSSValueID::kNone);
@@ -2052,14 +2112,10 @@ void Content::ApplyValue(StyleResolverState& state,
state.GetStyleImage(CSSPropertyID::kContent, *item));
} else if (const auto* counter_value =
DynamicTo<cssvalue::CSSCounterValue>(item.Get())) {
- const auto list_style_type =
- CssValueIDToPlatformEnum<EListStyleType>(counter_value->ListStyle());
- std::unique_ptr<CounterContent> counter =
- std::make_unique<CounterContent>(
- AtomicString(counter_value->Identifier()), list_style_type,
- AtomicString(counter_value->Separator()));
- next_content =
- MakeGarbageCollected<CounterContentData>(std::move(counter));
+ next_content = MakeGarbageCollected<CounterContentData>(
+ AtomicString(counter_value->Identifier()), counter_value->ListStyle(),
+ AtomicString(counter_value->Separator()),
+ scoped_value.GetTreeScope());
} else if (auto* item_identifier_value =
DynamicTo<CSSIdentifierValue>(item.Get())) {
QuoteType quote_type;
@@ -2135,7 +2191,6 @@ const CSSValue* CounterIncrement::ParseSingleValue(
const CSSValue* CounterIncrement::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForCounterDirectives(
@@ -2154,7 +2209,6 @@ const CSSValue* CounterReset::ParseSingleValue(
const CSSValue* CounterReset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForCounterDirectives(style,
@@ -2173,7 +2227,6 @@ const CSSValue* CounterSet::ParseSingleValue(
const CSSValue* CounterSet::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForCounterDirectives(style,
@@ -2240,7 +2293,6 @@ const CSSValue* Cursor::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Cursor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = nullptr;
@@ -2305,11 +2357,9 @@ const CSSValue* Cx::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Cx::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.Cx(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Cx(), style);
}
const CSSValue* Cy::ParseSingleValue(CSSParserTokenRange& range,
@@ -2321,11 +2371,9 @@ const CSSValue* Cy::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Cy::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.Cy(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Cy(), style);
}
const CSSValue* D::ParseSingleValue(CSSParserTokenRange& range,
@@ -2336,17 +2384,15 @@ const CSSValue* D::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* D::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- if (const StylePath* style_path = svg_style.D())
+ if (const StylePath* style_path = style.D())
return style_path->ComputedCSSValue();
return CSSIdentifierValue::Create(CSSValueID::kNone);
}
const CSSValue* Direction::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Direction());
@@ -2451,7 +2497,6 @@ const CSSValue* Display::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Display::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.IsDisplayLayoutCustomBox()) {
@@ -2522,15 +2567,13 @@ void Display::ApplyValue(StyleResolverState& state,
const CSSValue* DominantBaseline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.DominantBaseline());
+ return CSSIdentifierValue::Create(style.DominantBaseline());
}
const CSSValue* EmptyCells::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.EmptyCells());
@@ -2539,15 +2582,25 @@ const CSSValue* EmptyCells::CSSValueFromComputedStyleInternal(
const CSSValue* Fill::ParseSingleValue(CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&) const {
- return css_parsing_utils::ParsePaintStroke(range, context);
+ return css_parsing_utils::ConsumeSVGPaint(range, context);
}
const CSSValue* Fill::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGPaint(svg_style.FillPaint(), style);
+ return ComputedStyleUtils::ValueForSVGPaint(style.FillPaint(), style);
+}
+
+const blink::Color Fill::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(!visited_link);
+ DCHECK(style.FillPaint().HasColor());
+ const StyleColor& fill_color = style.FillPaint().GetColor();
+ if (style.ShouldForceColor(fill_color))
+ return style.GetInternalForcedCurrentColor();
+ return fill_color.Resolve(style.GetCurrentColor(), style.UsedColorScheme());
}
const CSSValue* FillOpacity::ParseSingleValue(
@@ -2558,20 +2611,18 @@ const CSSValue* FillOpacity::ParseSingleValue(
}
const CSSValue* FillOpacity::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSNumericLiteralValue::Create(svg_style.FillOpacity(),
+ return CSSNumericLiteralValue::Create(style.FillOpacity(),
CSSPrimitiveValue::UnitType::kNumber);
}
const CSSValue* FillRule::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.FillRule());
+ return CSSIdentifierValue::Create(style.FillRule());
}
const CSSValue* Filter::ParseSingleValue(CSSParserTokenRange& range,
@@ -2582,12 +2633,17 @@ const CSSValue* Filter::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Filter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFilter(style, style.Filter());
}
+void Filter::ApplyValue(StyleResolverState& state,
+ const CSSValue& value) const {
+ state.Style()->SetFilter(StyleBuilderConverter::ConvertFilterOperations(
+ state, value, PropertyID()));
+}
+
const CSSValue* FlexBasis::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
@@ -2601,7 +2657,6 @@ const CSSValue* FlexBasis::ParseSingleValue(
const CSSValue* FlexBasis::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.FlexBasis(),
@@ -2610,7 +2665,6 @@ const CSSValue* FlexBasis::CSSValueFromComputedStyleInternal(
const CSSValue* FlexDirection::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.FlexDirection());
@@ -2625,7 +2679,6 @@ const CSSValue* FlexGrow::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* FlexGrow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.FlexGrow(),
@@ -2642,7 +2695,6 @@ const CSSValue* FlexShrink::ParseSingleValue(
const CSSValue* FlexShrink::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.FlexShrink(),
@@ -2651,7 +2703,6 @@ const CSSValue* FlexShrink::CSSValueFromComputedStyleInternal(
const CSSValue* FlexWrap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.FlexWrap());
@@ -2659,7 +2710,6 @@ const CSSValue* FlexWrap::CSSValueFromComputedStyleInternal(
const CSSValue* Float::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasOutOfFlowPosition())
@@ -2677,12 +2727,14 @@ const CSSValue* FloodColor::ParseSingleValue(
const blink::Color FloodColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
- return style.ResolvedColor(style.FloodColor());
+ StyleColor flood_color = style.FloodColor();
+ if (style.ShouldForceColor(flood_color))
+ return style.GetInternalForcedCurrentColor();
+ return style.ResolvedColor(flood_color);
}
const CSSValue* FloodColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -2697,11 +2749,10 @@ const CSSValue* FloodOpacity::ParseSingleValue(
}
const CSSValue* FloodOpacity::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSNumericLiteralValue::Create(svg_style.FloodOpacity(),
+ return CSSNumericLiteralValue::Create(style.FloodOpacity(),
CSSPrimitiveValue::UnitType::kNumber);
}
@@ -2714,7 +2765,6 @@ const CSSValue* FontFamily::ParseSingleValue(
const CSSValue* FontFamily::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontFamily(style);
@@ -2722,11 +2772,25 @@ const CSSValue* FontFamily::CSSValueFromComputedStyleInternal(
void FontFamily::ApplyValue(StyleResolverState& state,
const ScopedCSSValue& scoped_value) const {
- // TODO(futhark): Set TreeScope on the FontBuilder so that it can create a
- // Font with a FontSelector for that TreeScope.
+ state.GetFontBuilder().SetFamilyTreeScope(scoped_value.GetTreeScope());
ApplyValue(state, scoped_value.GetCSSValue());
}
+void FontFamily::ApplyInitial(StyleResolverState& state) const {
+ state.GetFontBuilder().SetFamilyDescription(
+ FontBuilder::InitialFamilyDescription());
+ state.GetFontBuilder().SetFamilyTreeScope(nullptr);
+}
+
+void FontFamily::ApplyInherit(StyleResolverState& state) const {
+ state.GetFontBuilder().SetFamilyDescription(
+ state.ParentFontDescription().GetFamilyDescription());
+ CSSFontSelector* selector = static_cast<CSSFontSelector*>(
+ state.ParentStyle()->GetFont().GetFontSelector());
+ const TreeScope* tree_scope = selector ? selector->GetTreeScope() : nullptr;
+ state.GetFontBuilder().SetFamilyTreeScope(tree_scope);
+}
+
const CSSValue* FontFeatureSettings::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
@@ -2736,7 +2800,6 @@ const CSSValue* FontFeatureSettings::ParseSingleValue(
const CSSValue* FontFeatureSettings::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const blink::FontFeatureSettings* feature_settings =
@@ -2755,7 +2818,6 @@ const CSSValue* FontFeatureSettings::CSSValueFromComputedStyleInternal(
const CSSValue* FontKerning::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetFontDescription().GetKerning());
@@ -2763,7 +2825,6 @@ const CSSValue* FontKerning::CSSValueFromComputedStyleInternal(
const CSSValue* FontOpticalSizing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(
@@ -2783,7 +2844,6 @@ const CSSValue* FontSizeAdjust::ParseSingleValue(
const CSSValue* FontSizeAdjust::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasFontSizeAdjust()) {
@@ -2802,7 +2862,6 @@ const CSSValue* FontSize::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* FontSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontSize(style);
@@ -2817,7 +2876,6 @@ const CSSValue* FontStretch::ParseSingleValue(
const CSSValue* FontStretch::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontStretch(style);
@@ -2832,7 +2890,6 @@ const CSSValue* FontStyle::ParseSingleValue(
const CSSValue* FontStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontStyle(style);
@@ -2850,7 +2907,6 @@ const CSSValue* FontVariantCaps::ParseSingleValue(
const CSSValue* FontVariantCaps::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontVariantCaps(style);
@@ -2875,7 +2931,6 @@ const CSSValue* FontVariantEastAsian::ParseSingleValue(
const CSSValue* FontVariantEastAsian::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontVariantEastAsian(style);
@@ -2901,7 +2956,6 @@ const CSSValue* FontVariantLigatures::ParseSingleValue(
const CSSValue* FontVariantLigatures::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontVariantLigatures(style);
@@ -2926,7 +2980,6 @@ const CSSValue* FontVariantNumeric::ParseSingleValue(
const CSSValue* FontVariantNumeric::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontVariantNumeric(style);
@@ -2983,7 +3036,6 @@ const CSSValue* FontVariationSettings::ParseSingleValue(
const CSSValue* FontVariationSettings::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const blink::FontVariationSettings* variation_settings =
@@ -3010,7 +3062,6 @@ const CSSValue* FontWeight::ParseSingleValue(
const CSSValue* FontWeight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFontWeight(style);
@@ -3018,7 +3069,6 @@ const CSSValue* FontWeight::CSSValueFromComputedStyleInternal(
const CSSValue* ForcedColorAdjust::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ForcedColorAdjust());
@@ -3056,6 +3106,10 @@ const blink::Color InternalVisitedColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
+ if (style.ShouldForceColor(style.InternalVisitedColor())) {
+ return To<Longhand>(GetCSSPropertyInternalForcedVisitedColor())
+ .ColorIncludingFallback(true, style);
+ }
return style.GetInternalVisitedCurrentColor();
}
@@ -3084,7 +3138,6 @@ const CSSValue* GridAutoColumns::ParseSingleValue(
// http://lists.w3.org/Archives/Public/www-style/2013Nov/0014.html
const CSSValue* GridAutoColumns::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridTrackSizeList(kForColumns, style);
@@ -3116,7 +3169,6 @@ const CSSValue* GridAutoFlow::ParseSingleValue(
const CSSValue* GridAutoFlow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -3156,7 +3208,6 @@ const CSSValue* GridAutoRows::ParseSingleValue(
const CSSValue* GridAutoRows::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridTrackSizeList(kForRows, style);
@@ -3171,7 +3222,6 @@ const CSSValue* GridColumnEnd::ParseSingleValue(
const CSSValue* GridColumnEnd::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridPosition(style.GridColumnEnd());
@@ -3186,7 +3236,6 @@ const CSSValue* GridColumnStart::ParseSingleValue(
const CSSValue* GridColumnStart::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridPosition(style.GridColumnStart());
@@ -3201,7 +3250,6 @@ const CSSValue* GridRowEnd::ParseSingleValue(
const CSSValue* GridRowEnd::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridPosition(style.GridRowEnd());
@@ -3216,7 +3264,6 @@ const CSSValue* GridRowStart::ParseSingleValue(
const CSSValue* GridRowStart::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridPosition(style.GridRowStart());
@@ -3250,7 +3297,6 @@ const CSSValue* GridTemplateAreas::ParseSingleValue(
const CSSValue* GridTemplateAreas::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.NamedGridAreaRowCount()) {
@@ -3328,12 +3374,11 @@ const CSSValue* GridTemplateColumns::ParseSingleValue(
bool GridTemplateColumns::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsLayoutGrid();
+ return layout_object && layout_object->IsLayoutGridIncludingNG();
}
const CSSValue* GridTemplateColumns::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridTrackList(kForColumns, layout_object,
@@ -3349,12 +3394,11 @@ const CSSValue* GridTemplateRows::ParseSingleValue(
bool GridTemplateRows::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsLayoutGrid();
+ return layout_object && layout_object->IsLayoutGridIncludingNG();
}
const CSSValue* GridTemplateRows::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForGridTrackList(kForRows, layout_object,
@@ -3375,7 +3419,6 @@ bool Height::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Height::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(layout_object)) {
@@ -3388,7 +3431,6 @@ const CSSValue* Height::CSSValueFromComputedStyleInternal(
const CSSValue* Hyphens::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetHyphens());
@@ -3398,7 +3440,6 @@ const CSSValue* ImageOrientation::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&) const {
- DCHECK(RuntimeEnabledFeatures::ImageOrientationEnabled());
if (range.Peek().Id() == CSSValueID::kFromImage)
return css_parsing_utils::ConsumeIdent(range);
if (range.Peek().Id() == CSSValueID::kNone) {
@@ -3409,7 +3450,6 @@ const CSSValue* ImageOrientation::ParseSingleValue(
const CSSValue* ImageOrientation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.RespectImageOrientation() == kRespectImageOrientation)
@@ -3419,7 +3459,6 @@ const CSSValue* ImageOrientation::CSSValueFromComputedStyleInternal(
const CSSValue* ImageRendering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ImageRendering());
@@ -3474,7 +3513,12 @@ const blink::Color InternalVisitedBackgroundColor::ColorIncludingFallback(
const ComputedStyle& style) const {
DCHECK(visited_link);
- blink::Color color = style.InternalVisitedBackgroundColor().Resolve(
+ StyleColor visited_background_color = style.InternalVisitedBackgroundColor();
+ if (style.ShouldForceColor(visited_background_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBackgroundColor())
+ .ColorIncludingFallback(true, style);
+ }
+ blink::Color color = visited_background_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
// TODO: Technically someone could explicitly specify the color
@@ -3504,7 +3548,12 @@ const blink::Color InternalVisitedBorderLeftColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedBorderLeftColor().Resolve(
+ StyleColor visited_border_left_color = style.InternalVisitedBorderLeftColor();
+ if (style.ShouldForceColor(visited_border_left_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(true, style);
+ }
+ return visited_border_left_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3520,7 +3569,12 @@ const blink::Color InternalVisitedBorderTopColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedBorderTopColor().Resolve(
+ StyleColor visited_border_top_color = style.InternalVisitedBorderTopColor();
+ if (style.ShouldForceColor(visited_border_top_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(true, style);
+ }
+ return visited_border_top_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3539,6 +3593,8 @@ const blink::Color InternalVisitedCaretColor::ColorIncludingFallback(
StyleAutoColor auto_color = style.InternalVisitedCaretColor();
StyleColor result = auto_color.IsAutoColor() ? StyleColor::CurrentColor()
: auto_color.ToStyleColor();
+ if (style.ShouldForceColor(result))
+ return style.GetInternalForcedVisitedCurrentColor();
return result.Resolve(style.GetInternalVisitedCurrentColor(),
style.UsedColorScheme());
}
@@ -3555,7 +3611,13 @@ const blink::Color InternalVisitedBorderRightColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedBorderRightColor().Resolve(
+ StyleColor visited_border_right_color =
+ style.InternalVisitedBorderRightColor();
+ if (style.ShouldForceColor(visited_border_right_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(true, style);
+ }
+ return visited_border_right_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3571,7 +3633,13 @@ const blink::Color InternalVisitedBorderBottomColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedBorderBottomColor().Resolve(
+ StyleColor visited_border_bottom_color =
+ style.InternalVisitedBorderBottomColor();
+ if (style.ShouldForceColor(visited_border_bottom_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedBorderColor())
+ .ColorIncludingFallback(true, style);
+ }
+ return visited_border_bottom_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3619,14 +3687,36 @@ const CSSValue* InternalVisitedFill::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) const {
- return css_parsing_utils::ParsePaintStroke(range, context);
+ return css_parsing_utils::ConsumeSVGPaint(range, context);
+}
+
+const blink::Color InternalVisitedFill::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(visited_link);
+ const SVGPaint& paint = style.InternalVisitedFillPaint();
+
+ // FIXME: This code doesn't support the uri component of the visited link
+ // paint, https://bugs.webkit.org/show_bug.cgi?id=70006
+ if (!paint.HasColor()) {
+ return To<Longhand>(GetCSSPropertyFill())
+ .ColorIncludingFallback(false, style);
+ }
+ const StyleColor& visited_fill_color = paint.GetColor();
+ if (style.ShouldForceColor(visited_fill_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_fill_color.Resolve(style.GetInternalVisitedCurrentColor(),
+ style.UsedColorScheme());
}
const blink::Color InternalVisitedColumnRuleColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedColumnRuleColor().Resolve(
+ StyleColor visited_column_rule_color = style.InternalVisitedColumnRuleColor();
+ if (style.ShouldForceColor(visited_column_rule_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_column_rule_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3641,8 +3731,13 @@ const blink::Color InternalVisitedOutlineColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedOutlineColor().Resolve(
- style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
+ StyleColor visited_outline_color = style.InternalVisitedOutlineColor();
+ if (style.ShouldForceColor(visited_outline_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedOutlineColor())
+ .ColorIncludingFallback(true, style);
+ }
+ return visited_outline_color.Resolve(style.GetInternalVisitedCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* InternalVisitedOutlineColor::ParseSingleValue(
@@ -3657,15 +3752,38 @@ const CSSValue* InternalVisitedStroke::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) const {
- return css_parsing_utils::ParsePaintStroke(range, context);
+ return css_parsing_utils::ConsumeSVGPaint(range, context);
+}
+
+const blink::Color InternalVisitedStroke::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(visited_link);
+ const SVGPaint& paint = style.InternalVisitedStrokePaint();
+
+ // FIXME: This code doesn't support the uri component of the visited link
+ // paint, https://bugs.webkit.org/show_bug.cgi?id=70006
+ if (!paint.HasColor()) {
+ return To<Longhand>(GetCSSPropertyStroke())
+ .ColorIncludingFallback(false, style);
+ }
+ const StyleColor& visited_stroke_color = paint.GetColor();
+ if (style.ShouldForceColor(visited_stroke_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_stroke_color.Resolve(style.GetInternalVisitedCurrentColor(),
+ style.UsedColorScheme());
}
const blink::Color InternalVisitedTextDecorationColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.DecorationColorIncludingFallback(visited_link)
- .Resolve(style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
+ StyleColor visited_decoration_color =
+ style.DecorationColorIncludingFallback(visited_link);
+ if (style.ShouldForceColor(visited_decoration_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_decoration_color.Resolve(
+ style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
const CSSValue* InternalVisitedTextDecorationColor::ParseSingleValue(
@@ -3679,7 +3797,11 @@ const blink::Color InternalVisitedTextEmphasisColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedTextEmphasisColor().Resolve(
+ StyleColor visited_text_emphasis_color =
+ style.InternalVisitedTextEmphasisColor();
+ if (style.ShouldForceColor(visited_text_emphasis_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_text_emphasis_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3694,8 +3816,11 @@ const blink::Color InternalVisitedTextFillColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedTextFillColor().Resolve(
- style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
+ StyleColor visited_text_fill_color = style.InternalVisitedTextFillColor();
+ if (style.ShouldForceColor(visited_text_fill_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_text_fill_color.Resolve(style.GetInternalVisitedCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* InternalVisitedTextFillColor::ParseSingleValue(
@@ -3709,7 +3834,10 @@ const blink::Color InternalVisitedTextStrokeColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(visited_link);
- return style.InternalVisitedTextStrokeColor().Resolve(
+ StyleColor visited_text_stroke_color = style.InternalVisitedTextStrokeColor();
+ if (style.ShouldForceColor(visited_text_stroke_color))
+ return style.GetInternalForcedVisitedCurrentColor();
+ return visited_text_stroke_color.Resolve(
style.GetInternalVisitedCurrentColor(), style.UsedColorScheme());
}
@@ -3720,9 +3848,203 @@ const CSSValue* InternalVisitedTextStrokeColor::ParseSingleValue(
return css_parsing_utils::ConsumeColor(range, context);
}
+const blink::Color InternalForcedBackgroundColor::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ blink::Color forced_current_color;
+ int alpha;
+ if (visited_link) {
+ forced_current_color = style.GetInternalForcedVisitedCurrentColor();
+ alpha = style.InternalVisitedBackgroundColor()
+ .Resolve(style.GetInternalVisitedCurrentColor(),
+ style.UsedColorScheme())
+ .Alpha();
+ } else {
+ forced_current_color = style.GetInternalForcedCurrentColor();
+ alpha = style.BackgroundColor()
+ .Resolve(style.GetCurrentColor(), style.UsedColorScheme())
+ .Alpha();
+ }
+
+ return style.InternalForcedBackgroundColor().ResolveWithAlpha(
+ forced_current_color, style.UsedColorScheme(), alpha,
+ /* is_forced_color */ true);
+}
+
+const CSSValue*
+InternalForcedBackgroundColor::CSSValueFromComputedStyleInternal(
+ const ComputedStyle& style,
+ const LayoutObject*,
+ bool allow_visited_style) const {
+ bool visited_link = allow_visited_style &&
+ style.InsideLink() == EInsideLink::kInsideVisitedLink;
+ return cssvalue::CSSColorValue::Create(
+ ColorIncludingFallback(visited_link, style).Rgb());
+}
+
+const CSSValue* InternalForcedBackgroundColor::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
+ return css_parsing_utils::ConsumeColor(range, context,
+ IsQuirksModeBehavior(context.Mode()));
+}
+
+const blink::Color InternalForcedBorderColor::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ blink::Color current_color =
+ visited_link ? style.GetInternalForcedVisitedCurrentColor()
+ : style.GetInternalForcedCurrentColor();
+
+ return style.InternalForcedBorderColor().Resolve(current_color,
+ style.UsedColorScheme());
+}
+
+const CSSValue* InternalForcedBorderColor::CSSValueFromComputedStyleInternal(
+ const ComputedStyle& style,
+ const LayoutObject*,
+ bool allow_visited_style) const {
+ bool visited_link = allow_visited_style &&
+ style.InsideLink() == EInsideLink::kInsideVisitedLink;
+ return cssvalue::CSSColorValue::Create(
+ ColorIncludingFallback(visited_link, style).Rgb());
+}
+
+const CSSValue* InternalForcedBorderColor::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
+ return css_parsing_utils::ConsumeColor(range, context,
+ IsQuirksModeBehavior(context.Mode()));
+}
+
+void InternalForcedColor::ApplyInitial(StyleResolverState& state) const {
+ state.Style()->SetInternalForcedColor(
+ ComputedStyleInitialValues::InitialInternalForcedColor());
+}
+
+void InternalForcedColor::ApplyInherit(StyleResolverState& state) const {
+ auto color = state.ParentStyle()->InternalForcedColor();
+ state.Style()->SetInternalForcedColor(color);
+}
+
+void InternalForcedColor::ApplyValue(StyleResolverState& state,
+ const CSSValue& value) const {
+ auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
+ if (identifier_value &&
+ identifier_value->GetValueID() == CSSValueID::kCurrentcolor) {
+ ApplyInherit(state);
+ return;
+ }
+ if (auto* initial_color_value = DynamicTo<CSSInitialColorValue>(value)) {
+ DCHECK_EQ(state.GetElement(), state.GetDocument().documentElement());
+ state.Style()->SetInternalForcedColor(
+ ComputedStyleInitialValues::InitialInternalForcedColor());
+ return;
+ }
+ state.Style()->SetInternalForcedColor(
+ StyleBuilderConverter::ConvertStyleColor(state, value));
+}
+
+const blink::Color InternalForcedColor::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(!visited_link);
+ return style.GetInternalForcedCurrentColor();
+}
+
+const CSSValue* InternalForcedColor::CSSValueFromComputedStyleInternal(
+ const ComputedStyle& style,
+ const LayoutObject*,
+ bool allow_visited_style) const {
+ return cssvalue::CSSColorValue::Create(
+ allow_visited_style ? style.VisitedDependentColor(*this).Rgb()
+ : style.GetInternalForcedCurrentColor().Rgb());
+}
+
+const CSSValue* InternalForcedColor::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
+ return css_parsing_utils::ConsumeColor(range, context,
+ IsQuirksModeBehavior(context.Mode()));
+}
+
+const blink::Color InternalForcedOutlineColor::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ blink::Color current_color =
+ visited_link ? style.GetInternalForcedVisitedCurrentColor()
+ : style.GetInternalForcedCurrentColor();
+
+ return style.InternalForcedOutlineColor().Resolve(current_color,
+ style.UsedColorScheme());
+}
+
+const CSSValue* InternalForcedOutlineColor::CSSValueFromComputedStyleInternal(
+ const ComputedStyle& style,
+ const LayoutObject*,
+ bool allow_visited_style) const {
+ bool visited_link = allow_visited_style &&
+ style.InsideLink() == EInsideLink::kInsideVisitedLink;
+ return cssvalue::CSSColorValue::Create(
+ ColorIncludingFallback(visited_link, style).Rgb());
+}
+
+const CSSValue* InternalForcedOutlineColor::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
+ return css_parsing_utils::ConsumeColor(range, context,
+ IsQuirksModeBehavior(context.Mode()));
+}
+
+void InternalForcedVisitedColor::ApplyInitial(StyleResolverState& state) const {
+ state.Style()->SetInternalForcedVisitedColor(
+ ComputedStyleInitialValues::InitialInternalForcedVisitedColor());
+}
+
+void InternalForcedVisitedColor::ApplyInherit(StyleResolverState& state) const {
+ auto color = state.ParentStyle()->InternalForcedVisitedColor();
+ state.Style()->SetInternalForcedVisitedColor(color);
+}
+
+void InternalForcedVisitedColor::ApplyValue(StyleResolverState& state,
+ const CSSValue& value) const {
+ auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
+ if (identifier_value &&
+ identifier_value->GetValueID() == CSSValueID::kCurrentcolor) {
+ ApplyInherit(state);
+ return;
+ }
+ if (auto* initial_color_value = DynamicTo<CSSInitialColorValue>(value)) {
+ DCHECK_EQ(state.GetElement(), state.GetDocument().documentElement());
+ state.Style()->SetInternalForcedVisitedColor(
+ ComputedStyleInitialValues::InitialInternalForcedVisitedColor());
+ return;
+ }
+ state.Style()->SetInternalForcedVisitedColor(
+ StyleBuilderConverter::ConvertStyleColor(state, value, true));
+}
+
+const blink::Color InternalForcedVisitedColor::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(visited_link);
+ return style.GetInternalForcedVisitedCurrentColor();
+}
+
+const CSSValue* InternalForcedVisitedColor::ParseSingleValue(
+ CSSParserTokenRange& range,
+ const CSSParserContext& context,
+ const CSSParserLocalContext& local_context) const {
+ return css_parsing_utils::ConsumeColor(range, context,
+ IsQuirksModeBehavior(context.Mode()));
+}
+
const CSSValue* Isolation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Isolation());
@@ -3742,7 +4064,6 @@ const CSSValue* JustifyContent::ParseSingleValue(
const CSSValue* JustifyContent::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::
@@ -3782,7 +4103,6 @@ const CSSValue* JustifyItems::ParseSingleValue(
const CSSValue* JustifyItems::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment(
@@ -3801,7 +4121,6 @@ const CSSValue* JustifySelf::ParseSingleValue(
const CSSValue* JustifySelf::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment(
@@ -3824,7 +4143,6 @@ bool Left::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Left::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPositionOffset(style, *this,
@@ -3840,7 +4158,6 @@ const CSSValue* LetterSpacing::ParseSingleValue(
const CSSValue* LetterSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.LetterSpacing())
@@ -3858,12 +4175,14 @@ const CSSValue* LightingColor::ParseSingleValue(
const blink::Color LightingColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
- return style.ResolvedColor(style.LightingColor());
+ StyleColor lighting_color = style.LightingColor();
+ if (style.ShouldForceColor(lighting_color))
+ return style.GetInternalForcedCurrentColor();
+ return style.ResolvedColor(lighting_color);
}
const CSSValue* LightingColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -3872,7 +4191,6 @@ const CSSValue* LightingColor::CSSValueFromComputedStyleInternal(
const CSSValue* LineBreak::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetLineBreak());
@@ -3887,7 +4205,6 @@ const CSSValue* LineHeight::ParseSingleValue(
const CSSValue* LineHeight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForLineHeight(style);
@@ -3903,7 +4220,6 @@ const CSSValue* LineHeightStep::ParseSingleValue(
const CSSValue* LineHeightStep::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.LineHeightStep(), style);
@@ -3918,7 +4234,6 @@ const CSSValue* ListStyleImage::ParseSingleValue(
const CSSValue* ListStyleImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.ListStyleImage())
@@ -3934,7 +4249,6 @@ void ListStyleImage::ApplyValue(StyleResolverState& state,
const CSSValue* ListStylePosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ListStylePosition());
@@ -3944,47 +4258,74 @@ const CSSValue* ListStyleType::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&) const {
- // NOTE: All the keyword values for the list-style-type property are handled
- // by the CSSParserFastPaths.
+ if (auto* none = css_parsing_utils::ConsumeIdent<CSSValueID::kNone>(range))
+ return none;
+
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ if (auto* ident = css_parsing_utils::ConsumeIdent(range)) {
+ CSSValueID value_id = ident->GetValueID();
+ if (value_id < CSSValueID::kDisc || value_id > CSSValueID::kKatakanaIroha)
+ return nullptr;
+ return MakeGarbageCollected<CSSCustomIdentValue>(
+ AtomicString(getValueName(value_id)));
+ }
+ } else {
+ if (auto* counter_style_name =
+ css_parsing_utils::ConsumeCounterStyleName(range, context))
+ return counter_style_name;
+ }
+
return css_parsing_utils::ConsumeString(range);
}
const CSSValue* ListStyleType::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
- if (style.ListStyleType() == EListStyleType::kString)
- return MakeGarbageCollected<CSSStringValue>(style.ListStyleStringValue());
- return CSSIdentifierValue::Create(style.ListStyleType());
+ if (!style.GetListStyleType())
+ return CSSIdentifierValue::Create(CSSValueID::kNone);
+ if (style.GetListStyleType()->IsString()) {
+ return MakeGarbageCollected<CSSStringValue>(
+ style.GetListStyleType()->GetStringValue());
+ }
+ // TODO(crbug.com/687225): Return a scoped CSSValue?
+ return MakeGarbageCollected<CSSCustomIdentValue>(
+ style.GetListStyleType()->GetCounterStyleName());
}
void ListStyleType::ApplyInitial(StyleResolverState& state) const {
state.Style()->SetListStyleType(
ComputedStyleInitialValues::InitialListStyleType());
- state.Style()->SetListStyleStringValue(
- ComputedStyleInitialValues::InitialListStyleStringValue());
}
void ListStyleType::ApplyInherit(StyleResolverState& state) const {
- state.Style()->SetListStyleType(state.ParentStyle()->ListStyleType());
- state.Style()->SetListStyleStringValue(
- state.ParentStyle()->ListStyleStringValue());
+ state.Style()->SetListStyleType(state.ParentStyle()->GetListStyleType());
}
void ListStyleType::ApplyValue(StyleResolverState& state,
const CSSValue& value) const {
- if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
+ NOTREACHED();
+}
+
+void ListStyleType::ApplyValue(StyleResolverState& state,
+ const ScopedCSSValue& scoped_value) const {
+ const CSSValue& value = scoped_value.GetCSSValue();
+ if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
+ DCHECK_EQ(CSSValueID::kNone, identifier_value->GetValueID());
+ state.Style()->SetListStyleType(nullptr);
+ return;
+ }
+
+ if (const auto* string_value = DynamicTo<CSSStringValue>(value)) {
state.Style()->SetListStyleType(
- identifier_value->ConvertTo<EListStyleType>());
- state.Style()->SetListStyleStringValue(
- ComputedStyleInitialValues::InitialListStyleStringValue());
+ ListStyleTypeData::CreateString(AtomicString(string_value->Value())));
return;
}
- state.Style()->SetListStyleType(EListStyleType::kString);
- state.Style()->SetListStyleStringValue(
- AtomicString(To<CSSStringValue>(value).Value()));
+ DCHECK(value.IsCustomIdentValue());
+ const auto& custom_ident_value = To<CSSCustomIdentValue>(value);
+ state.Style()->SetListStyleType(ListStyleTypeData::CreateCounterStyle(
+ custom_ident_value.Value(), scoped_value.GetTreeScope()));
}
bool MarginBlockEnd::IsLayoutDependent(const ComputedStyle* style,
@@ -4029,7 +4370,6 @@ bool MarginBottom::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* MarginBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& margin_bottom = style.MarginBottom();
@@ -4083,7 +4423,6 @@ bool MarginLeft::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* MarginLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& margin_left = style.MarginLeft();
@@ -4111,7 +4450,6 @@ bool MarginRight::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* MarginRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& margin_right = style.MarginRight();
@@ -4152,7 +4490,6 @@ bool MarginTop::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* MarginTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& margin_top = style.MarginTop();
@@ -4175,10 +4512,9 @@ const CSSValue* MarkerEnd::ParseSingleValue(
const CSSValue* MarkerEnd::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGResource(svg_style.MarkerEndResource());
+ return ComputedStyleUtils::ValueForSVGResource(style.MarkerEndResource());
}
const CSSValue* MarkerMid::ParseSingleValue(
@@ -4192,10 +4528,9 @@ const CSSValue* MarkerMid::ParseSingleValue(
const CSSValue* MarkerMid::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGResource(svg_style.MarkerMidResource());
+ return ComputedStyleUtils::ValueForSVGResource(style.MarkerMidResource());
}
const CSSValue* MarkerStart::ParseSingleValue(
@@ -4209,11 +4544,9 @@ const CSSValue* MarkerStart::ParseSingleValue(
const CSSValue* MarkerStart::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGResource(
- svg_style.MarkerStartResource());
+ return ComputedStyleUtils::ValueForSVGResource(style.MarkerStartResource());
}
const CSSValue* Mask::ParseSingleValue(CSSParserTokenRange& range,
@@ -4226,23 +4559,20 @@ const CSSValue* Mask::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Mask::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGResource(svg_style.MaskerResource());
+ return ComputedStyleUtils::ValueForSVGResource(style.MaskerResource());
}
const CSSValue* MaskType::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.MaskType());
+ return CSSIdentifierValue::Create(style.MaskType());
}
const CSSValue* MathShift::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.MathShift());
@@ -4250,7 +4580,6 @@ const CSSValue* MathShift::CSSValueFromComputedStyleInternal(
const CSSValue* MathStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.MathStyle());
@@ -4265,7 +4594,6 @@ const CSSValue* MathDepth::ParseSingleValue(
const CSSValue* MathDepth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.MathDepth(),
@@ -4307,7 +4635,6 @@ const CSSValue* MaxHeight::ParseSingleValue(
const CSSValue* MaxHeight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const Length& max_height = style.MaxHeight();
@@ -4332,7 +4659,6 @@ const CSSValue* MaxWidth::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* MaxWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const Length& max_width = style.MaxWidth();
@@ -4358,7 +4684,6 @@ const CSSValue* MinHeight::ParseSingleValue(
const CSSValue* MinHeight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (style.MinHeight().IsAuto())
@@ -4383,7 +4708,6 @@ const CSSValue* MinWidth::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* MinWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (style.MinWidth().IsAuto())
@@ -4394,7 +4718,6 @@ const CSSValue* MinWidth::CSSValueFromComputedStyleInternal(
const CSSValue* MixBlendMode::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetBlendMode());
@@ -4402,7 +4725,6 @@ const CSSValue* MixBlendMode::CSSValueFromComputedStyleInternal(
const CSSValue* ObjectFit::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetObjectFit());
@@ -4419,7 +4741,6 @@ const CSSValue* ObjectPosition::ParseSingleValue(
const CSSValue* ObjectPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return MakeGarbageCollected<CSSValuePair>(
@@ -4444,7 +4765,6 @@ const CSSValue* OffsetAnchor::ParseSingleValue(
const CSSValue* OffsetAnchor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPosition(style.OffsetAnchor(), style);
@@ -4460,7 +4780,6 @@ const CSSValue* OffsetDistance::ParseSingleValue(
const CSSValue* OffsetDistance::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -4476,7 +4795,6 @@ const CSSValue* OffsetPath::ParseSingleValue(
const CSSValue* OffsetPath::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (const BasicShape* style_motion_path = style.OffsetPath())
@@ -4503,7 +4821,6 @@ const CSSValue* OffsetPosition::ParseSingleValue(
const CSSValue* OffsetPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPosition(style.OffsetPosition(), style);
@@ -4517,7 +4834,6 @@ const CSSValue* OffsetRotate::ParseSingleValue(
}
const CSSValue* OffsetRotate::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -4536,7 +4852,6 @@ const CSSValue* Opacity::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Opacity::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.Opacity(),
@@ -4551,7 +4866,6 @@ const CSSValue* Order::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Order::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.Order(),
@@ -4560,7 +4874,6 @@ const CSSValue* Order::CSSValueFromComputedStyleInternal(
const CSSValue* OriginTrialTestProperty::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OriginTrialTestProperty());
@@ -4575,7 +4888,6 @@ const CSSValue* Orphans::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Orphans::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.Orphans(),
@@ -4596,22 +4908,31 @@ const blink::Color OutlineColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.OutlineColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor outline_color = style.OutlineColor();
+ if (style.ShouldForceColor(outline_color)) {
+ return To<Longhand>(GetCSSPropertyInternalForcedOutlineColor())
+ .ColorIncludingFallback(false, style);
+ }
+ return outline_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* OutlineColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
+ StyleColor outline_color = style.OutlineColor();
+ if (style.ShouldForceColor(outline_color)) {
+ return GetCSSPropertyInternalForcedOutlineColor().CSSValueFromComputedStyle(
+ style, nullptr, allow_visited_style);
+ }
// https://drafts.csswg.org/cssom/#resolved-values
// For this property, the resolved value is the used value.
return allow_visited_style
? cssvalue::CSSColorValue::Create(
style.VisitedDependentColor(*this).Rgb())
: ComputedStyleUtils::CurrentColorOrValidColor(
- style, style.OutlineColor(), CSSValuePhase::kUsedValue);
+ style, outline_color, CSSValuePhase::kUsedValue);
}
const CSSValue* OutlineOffset::ParseSingleValue(
@@ -4623,7 +4944,6 @@ const CSSValue* OutlineOffset::ParseSingleValue(
const CSSValue* OutlineOffset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.OutlineOffset(), style);
@@ -4631,7 +4951,6 @@ const CSSValue* OutlineOffset::CSSValueFromComputedStyleInternal(
const CSSValue* OutlineStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.OutlineStyleIsAuto())
@@ -4669,7 +4988,6 @@ const CSSValue* OutlineWidth::ParseSingleValue(
const CSSValue* OutlineWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.OutlineWidth(), style);
@@ -4677,7 +4995,6 @@ const CSSValue* OutlineWidth::CSSValueFromComputedStyleInternal(
const CSSValue* OverflowAnchor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverflowAnchor());
@@ -4685,7 +5002,6 @@ const CSSValue* OverflowAnchor::CSSValueFromComputedStyleInternal(
const CSSValue* OverflowClipMargin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.OverflowClipMargin(), style);
@@ -4701,7 +5017,6 @@ const CSSValue* OverflowClipMargin::ParseSingleValue(
const CSSValue* OverflowWrap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverflowWrap());
@@ -4709,7 +5024,6 @@ const CSSValue* OverflowWrap::CSSValueFromComputedStyleInternal(
const CSSValue* OverflowX::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverflowX());
@@ -4717,7 +5031,6 @@ const CSSValue* OverflowX::CSSValueFromComputedStyleInternal(
const CSSValue* OverflowY::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverflowY());
@@ -4725,7 +5038,6 @@ const CSSValue* OverflowY::CSSValueFromComputedStyleInternal(
const CSSValue* OverscrollBehaviorX::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverscrollBehaviorX());
@@ -4733,7 +5045,6 @@ const CSSValue* OverscrollBehaviorX::CSSValueFromComputedStyleInternal(
const CSSValue* OverscrollBehaviorY::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.OverscrollBehaviorY());
@@ -4781,7 +5092,6 @@ bool PaddingBottom::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* PaddingBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& padding_bottom = style.PaddingBottom();
@@ -4835,7 +5145,6 @@ bool PaddingLeft::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* PaddingLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& padding_left = style.PaddingLeft();
@@ -4863,7 +5172,6 @@ bool PaddingRight::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* PaddingRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& padding_right = style.PaddingRight();
@@ -4891,7 +5199,6 @@ bool PaddingTop::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* PaddingTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const Length& padding_top = style.PaddingTop();
@@ -4913,7 +5220,6 @@ const CSSValue* Page::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Page::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.Page().IsNull())
@@ -4975,11 +5281,10 @@ const CSSValue* PaintOrder::ParseSingleValue(
}
const CSSValue* PaintOrder::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- const EPaintOrder paint_order = svg_style.PaintOrder();
+ const EPaintOrder paint_order = style.PaintOrder();
if (paint_order == kPaintOrderNormal)
return CSSIdentifierValue::Create(CSSValueID::kNormal);
@@ -5036,7 +5341,6 @@ const CSSValue* Perspective::ParseSingleValue(
const CSSValue* Perspective::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.HasPerspective())
@@ -5060,7 +5364,6 @@ bool PerspectiveOrigin::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* PerspectiveOrigin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (layout_object) {
@@ -5088,7 +5391,6 @@ const CSSValue* PerspectiveOrigin::CSSValueFromComputedStyleInternal(
const CSSValue* PointerEvents::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.PointerEvents());
@@ -5096,7 +5398,6 @@ const CSSValue* PointerEvents::CSSValueFromComputedStyleInternal(
const CSSValue* Position::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetPosition());
@@ -5129,7 +5430,6 @@ const CSSValue* Quotes::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Quotes::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.Quotes())
@@ -5156,16 +5456,13 @@ const CSSValue* R::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* R::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.R(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.R(), style);
}
const CSSValue* Resize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Resize());
@@ -5204,7 +5501,6 @@ bool Right::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Right::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPositionOffset(style, *this,
@@ -5244,7 +5540,6 @@ const CSSValue* Rotate::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Rotate::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.Rotate())
@@ -5271,7 +5566,6 @@ const CSSValue* RowGap::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* RowGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool) const {
return ComputedStyleUtils::ValueForGapLength(style.RowGap(), style);
@@ -5288,11 +5582,9 @@ const CSSValue* Rx::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Rx::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.Rx(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Rx(), style);
}
const CSSValue* Ry::ParseSingleValue(CSSParserTokenRange& range,
@@ -5306,11 +5598,9 @@ const CSSValue* Ry::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Ry::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.Ry(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Ry(), style);
}
const CSSValue* Scale::ParseSingleValue(CSSParserTokenRange& range,
@@ -5349,7 +5639,6 @@ const CSSValue* Scale::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Scale::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
ScaleTransformOperation* scale = style.Scale();
@@ -5421,7 +5710,6 @@ const CSSValue* ScrollbarGutter::ParseSingleValue(
const CSSValue* ScrollbarGutter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
auto scrollbar_gutter = style.ScrollbarGutter();
@@ -5450,7 +5738,6 @@ const CSSValue* ScrollbarGutter::CSSValueFromComputedStyleInternal(
const CSSValue* ScrollbarWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ScrollbarWidth());
@@ -5458,7 +5745,6 @@ const CSSValue* ScrollbarWidth::CSSValueFromComputedStyleInternal(
const CSSValue* ScrollBehavior::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetScrollBehavior());
@@ -5513,7 +5799,6 @@ const CSSValue* ScrollCustomization::ParseSingleValue(
const CSSValue* ScrollCustomization::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ScrollCustomizationFlagsToCSSValue(
@@ -5546,7 +5831,6 @@ const CSSValue* ScrollMarginBottom::ParseSingleValue(
const CSSValue* ScrollMarginBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.ScrollMarginBottom(), style);
@@ -5578,7 +5862,6 @@ const CSSValue* ScrollMarginLeft::ParseSingleValue(
const CSSValue* ScrollMarginLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.ScrollMarginLeft(), style);
@@ -5594,7 +5877,6 @@ const CSSValue* ScrollMarginRight::ParseSingleValue(
const CSSValue* ScrollMarginRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.ScrollMarginRight(), style);
@@ -5610,7 +5892,6 @@ const CSSValue* ScrollMarginTop::ParseSingleValue(
const CSSValue* ScrollMarginTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.ScrollMarginTop(), style);
@@ -5639,7 +5920,6 @@ const CSSValue* ScrollPaddingBottom::ParseSingleValue(
const CSSValue* ScrollPaddingBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -5669,7 +5949,6 @@ const CSSValue* ScrollPaddingLeft::ParseSingleValue(
const CSSValue* ScrollPaddingLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -5685,7 +5964,6 @@ const CSSValue* ScrollPaddingRight::ParseSingleValue(
const CSSValue* ScrollPaddingRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -5701,7 +5979,6 @@ const CSSValue* ScrollPaddingTop::ParseSingleValue(
const CSSValue* ScrollPaddingTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -5734,7 +6011,6 @@ const CSSValue* ScrollSnapAlign::ParseSingleValue(
const CSSValue* ScrollSnapAlign::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForScrollSnapAlign(style.GetScrollSnapAlign(),
@@ -5743,7 +6019,6 @@ const CSSValue* ScrollSnapAlign::CSSValueFromComputedStyleInternal(
const CSSValue* ScrollSnapStop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ScrollSnapStop());
@@ -5776,7 +6051,6 @@ const CSSValue* ScrollSnapType::ParseSingleValue(
const CSSValue* ScrollSnapType::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForScrollSnapType(style.GetScrollSnapType(),
@@ -5792,7 +6066,6 @@ const CSSValue* ShapeImageThreshold::ParseSingleValue(
const CSSValue* ShapeImageThreshold::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.ShapeImageThreshold(),
@@ -5809,7 +6082,6 @@ const CSSValue* ShapeMargin::ParseSingleValue(
const CSSValue* ShapeMargin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSValue::Create(style.ShapeMargin(), style.EffectiveZoom());
@@ -5840,7 +6112,6 @@ const CSSValue* ShapeOutside::ParseSingleValue(
const CSSValue* ShapeOutside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForShape(style, allow_visited_style,
@@ -5849,10 +6120,9 @@ const CSSValue* ShapeOutside::CSSValueFromComputedStyleInternal(
const CSSValue* ShapeRendering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.ShapeRendering());
+ return CSSIdentifierValue::Create(style.ShapeRendering());
}
static CSSValue* ConsumePageSize(CSSParserTokenRange& range) {
@@ -6001,7 +6271,6 @@ void Size::ApplyValue(StyleResolverState& state, const CSSValue& value) const {
const CSSValue* Speak::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Speak());
@@ -6017,12 +6286,14 @@ const CSSValue* StopColor::ParseSingleValue(
const blink::Color StopColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
- return style.ResolvedColor(style.StopColor());
+ StyleColor stop_color = style.StopColor();
+ if (style.ShouldForceColor(stop_color))
+ return style.GetInternalForcedCurrentColor();
+ return style.ResolvedColor(stop_color);
}
const CSSValue* StopColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -6037,26 +6308,35 @@ const CSSValue* StopOpacity::ParseSingleValue(
}
const CSSValue* StopOpacity::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSNumericLiteralValue::Create(svg_style.StopOpacity(),
+ return CSSNumericLiteralValue::Create(style.StopOpacity(),
CSSPrimitiveValue::UnitType::kNumber);
}
const CSSValue* Stroke::ParseSingleValue(CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&) const {
- return css_parsing_utils::ParsePaintStroke(range, context);
+ return css_parsing_utils::ConsumeSVGPaint(range, context);
}
const CSSValue* Stroke::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ValueForSVGPaint(svg_style.StrokePaint(), style);
+ return ComputedStyleUtils::ValueForSVGPaint(style.StrokePaint(), style);
+}
+
+const blink::Color Stroke::ColorIncludingFallback(
+ bool visited_link,
+ const ComputedStyle& style) const {
+ DCHECK(!visited_link);
+ DCHECK(style.StrokePaint().HasColor());
+ const StyleColor& stroke_color = style.StrokePaint().GetColor();
+ if (style.ShouldForceColor(stroke_color))
+ return style.GetInternalForcedCurrentColor();
+ return stroke_color.Resolve(style.GetCurrentColor(), style.UsedColorScheme());
}
const CSSValue* StrokeDasharray::ParseSingleValue(
@@ -6082,11 +6362,10 @@ const CSSValue* StrokeDasharray::ParseSingleValue(
const CSSValue* StrokeDasharray::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::StrokeDashArrayToCSSValueList(
- *svg_style.StrokeDashArray(), style);
+ *style.StrokeDashArray(), style);
}
const CSSValue* StrokeDashoffset::ParseSingleValue(
@@ -6101,7 +6380,6 @@ const CSSValue* StrokeDashoffset::ParseSingleValue(
const CSSValue* StrokeDashoffset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -6110,18 +6388,16 @@ const CSSValue* StrokeDashoffset::CSSValueFromComputedStyleInternal(
const CSSValue* StrokeLinecap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.CapStyle());
+ return CSSIdentifierValue::Create(style.CapStyle());
}
const CSSValue* StrokeLinejoin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.JoinStyle());
+ return CSSIdentifierValue::Create(style.JoinStyle());
}
const CSSValue* StrokeMiterlimit::ParseSingleValue(
@@ -6133,11 +6409,10 @@ const CSSValue* StrokeMiterlimit::ParseSingleValue(
}
const CSSValue* StrokeMiterlimit::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSNumericLiteralValue::Create(svg_style.StrokeMiterLimit(),
+ return CSSNumericLiteralValue::Create(style.StrokeMiterLimit(),
CSSPrimitiveValue::UnitType::kNumber);
}
@@ -6149,11 +6424,10 @@ const CSSValue* StrokeOpacity::ParseSingleValue(
}
const CSSValue* StrokeOpacity::CSSValueFromComputedStyleInternal(
- const ComputedStyle&,
- const SVGComputedStyle& svg_style,
+ const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSNumericLiteralValue::Create(svg_style.StrokeOpacity(),
+ return CSSNumericLiteralValue::Create(style.StrokeOpacity(),
CSSPrimitiveValue::UnitType::kNumber);
}
@@ -6169,17 +6443,15 @@ const CSSValue* StrokeWidth::ParseSingleValue(
const CSSValue* StrokeWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
// We store the unzoomed stroke-width value using ConvertUnzoomedLength().
// Don't apply zoom here either.
- return CSSValue::Create(svg_style.StrokeWidth().length(), 1);
+ return CSSValue::Create(style.StrokeWidth().length(), 1);
}
const CSSValue* ContentVisibility::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.ContentVisibility());
@@ -6212,7 +6484,6 @@ const CSSValue* TabSize::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* TabSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(
@@ -6223,7 +6494,6 @@ const CSSValue* TabSize::CSSValueFromComputedStyleInternal(
const CSSValue* TableLayout::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TableLayout());
@@ -6231,7 +6501,6 @@ const CSSValue* TableLayout::CSSValueFromComputedStyleInternal(
const CSSValue* TextAlign::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetTextAlign());
@@ -6266,7 +6535,6 @@ void TextAlign::ApplyValue(StyleResolverState& state,
const CSSValue* TextAlignLast::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TextAlignLast());
@@ -6274,15 +6542,13 @@ const CSSValue* TextAlignLast::CSSValueFromComputedStyleInternal(
const CSSValue* TextAnchor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.TextAnchor());
+ return CSSIdentifierValue::Create(style.TextAnchor());
}
const CSSValue* TextCombineUpright::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TextCombine());
@@ -6299,13 +6565,16 @@ const blink::Color TextDecorationColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.DecorationColorIncludingFallback(visited_link)
- .Resolve(style.GetCurrentColor(), style.UsedColorScheme());
+ StyleColor decoration_color =
+ style.DecorationColorIncludingFallback(visited_link);
+ if (style.ShouldForceColor(decoration_color))
+ return style.GetInternalForcedCurrentColor();
+ return decoration_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* TextDecorationColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -6321,7 +6590,6 @@ const CSSValue* TextDecorationLine::ParseSingleValue(
const CSSValue* TextDecorationLine::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::RenderTextDecorationFlagsToCSSValue(
@@ -6330,7 +6598,6 @@ const CSSValue* TextDecorationLine::CSSValueFromComputedStyleInternal(
const CSSValue* TextDecorationSkipInk::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForTextDecorationSkipInk(
@@ -6339,7 +6606,6 @@ const CSSValue* TextDecorationSkipInk::CSSValueFromComputedStyleInternal(
const CSSValue* TextDecorationStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForTextDecorationStyle(
@@ -6361,7 +6627,6 @@ const CSSValue* TextDecorationThickness::ParseSingleValue(
const CSSValue* TextDecorationThickness::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
DCHECK(RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled());
@@ -6425,7 +6690,6 @@ const CSSValue* TextIndent::ParseSingleValue(
const CSSValue* TextIndent::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -6485,7 +6749,6 @@ void TextIndent::ApplyValue(StyleResolverState& state,
const CSSValue* TextJustify::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetTextJustify());
@@ -6493,7 +6756,6 @@ const CSSValue* TextJustify::CSSValueFromComputedStyleInternal(
const CSSValue* TextOrientation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetTextOrientation());
@@ -6516,7 +6778,6 @@ void TextOrientation::ApplyValue(StyleResolverState& state,
const CSSValue* TextOverflow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.TextOverflow() != ETextOverflow::kClip)
@@ -6526,7 +6787,6 @@ const CSSValue* TextOverflow::CSSValueFromComputedStyleInternal(
const CSSValue* TextRendering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetFontDescription().TextRendering());
@@ -6542,7 +6802,6 @@ const CSSValue* TextShadow::ParseSingleValue(
const CSSValue* TextShadow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForShadowList(
@@ -6563,7 +6822,6 @@ const CSSValue* TextSizeAdjust::ParseSingleValue(
const CSSValue* TextSizeAdjust::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.GetTextSizeAdjust().IsAuto())
@@ -6575,7 +6833,6 @@ const CSSValue* TextSizeAdjust::CSSValueFromComputedStyleInternal(
const CSSValue* TextTransform::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TextTransform());
@@ -6617,7 +6874,6 @@ const CSSValue* TextUnderlinePosition::ParseSingleValue(
const CSSValue* TextUnderlinePosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
auto text_underline_position = style.TextUnderlinePosition();
@@ -6660,7 +6916,6 @@ const CSSValue* TextUnderlineOffset::ParseSingleValue(
const CSSValue* TextUnderlineOffset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
@@ -6683,7 +6938,6 @@ bool Top::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Top::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPositionOffset(style, *this,
@@ -6748,7 +7002,6 @@ const CSSValue* TouchAction::ParseSingleValue(
const CSSValue* TouchAction::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::TouchActionFlagsToCSSValue(style.GetTouchAction());
@@ -6756,7 +7009,6 @@ const CSSValue* TouchAction::CSSValueFromComputedStyleInternal(
const CSSValue* TransformBox::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TransformBox());
@@ -6777,7 +7029,6 @@ bool Transform::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Transform::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ResolvedTransform(layout_object, style);
@@ -6812,7 +7063,6 @@ bool TransformOrigin::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* TransformOrigin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -6837,7 +7087,6 @@ const CSSValue* TransformOrigin::CSSValueFromComputedStyleInternal(
const CSSValue* TransformStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(
@@ -6856,7 +7105,6 @@ const CSSValue* TransitionDelay::ParseSingleValue(
const CSSValue* TransitionDelay::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationDelay(style.Transitions());
@@ -6880,7 +7128,6 @@ const CSSValue* TransitionDuration::ParseSingleValue(
const CSSValue* TransitionDuration::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationDuration(style.Transitions());
@@ -6907,7 +7154,6 @@ const CSSValue* TransitionProperty::ParseSingleValue(
const CSSValue* TransitionProperty::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForTransitionProperty(style.Transitions());
@@ -6929,7 +7175,6 @@ const CSSValue* TransitionTimingFunction::ParseSingleValue(
const CSSValue* TransitionTimingFunction::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForAnimationTimingFunction(
@@ -6981,7 +7226,6 @@ bool Translate::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Translate::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (!style.Translate())
@@ -7004,7 +7248,6 @@ const CSSValue* Translate::CSSValueFromComputedStyleInternal(
const CSSValue* UnicodeBidi::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetUnicodeBidi());
@@ -7012,7 +7255,6 @@ const CSSValue* UnicodeBidi::CSSValueFromComputedStyleInternal(
const CSSValue* UserSelect::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.UserSelect());
@@ -7020,10 +7262,9 @@ const CSSValue* UserSelect::CSSValueFromComputedStyleInternal(
const CSSValue* VectorEffect::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return CSSIdentifierValue::Create(svg_style.VectorEffect());
+ return CSSIdentifierValue::Create(style.VectorEffect());
}
const CSSValue* VerticalAlign::ParseSingleValue(
@@ -7042,7 +7283,6 @@ const CSSValue* VerticalAlign::ParseSingleValue(
const CSSValue* VerticalAlign::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
switch (style.VerticalAlign()) {
@@ -7095,7 +7335,6 @@ void VerticalAlign::ApplyValue(StyleResolverState& state,
const CSSValue* Visibility::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Visibility());
@@ -7103,7 +7342,6 @@ const CSSValue* Visibility::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitAppRegion::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.DraggableRegionMode() == EDraggableRegionMode::kNone)
@@ -7146,7 +7384,6 @@ const CSSValue* Appearance::ParseSingleValue(
const CSSValue* Appearance::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.Appearance());
@@ -7163,7 +7400,6 @@ const CSSValue* WebkitBorderHorizontalSpacing::ParseSingleValue(
const CSSValue*
WebkitBorderHorizontalSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.HorizontalBorderSpacing(), style);
@@ -7178,7 +7414,6 @@ const CSSValue* WebkitBorderImage::ParseSingleValue(
const CSSValue* WebkitBorderImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImage(style.BorderImage(), style,
@@ -7203,7 +7438,6 @@ const CSSValue* WebkitBorderVerticalSpacing::ParseSingleValue(
const CSSValue* WebkitBorderVerticalSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.VerticalBorderSpacing(), style);
@@ -7211,7 +7445,6 @@ const CSSValue* WebkitBorderVerticalSpacing::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitBoxAlign::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BoxAlign());
@@ -7219,7 +7452,6 @@ const CSSValue* WebkitBoxAlign::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitBoxDecorationBreak::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.BoxDecorationBreak() == EBoxDecorationBreak::kSlice)
@@ -7229,7 +7461,6 @@ const CSSValue* WebkitBoxDecorationBreak::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitBoxDirection::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BoxDirection());
@@ -7244,7 +7475,6 @@ const CSSValue* WebkitBoxFlex::ParseSingleValue(
const CSSValue* WebkitBoxFlex::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.BoxFlex(),
@@ -7260,7 +7490,6 @@ const CSSValue* WebkitBoxOrdinalGroup::ParseSingleValue(
const CSSValue* WebkitBoxOrdinalGroup::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.BoxOrdinalGroup(),
@@ -7269,7 +7498,6 @@ const CSSValue* WebkitBoxOrdinalGroup::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitBoxOrient::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BoxOrient());
@@ -7277,7 +7505,6 @@ const CSSValue* WebkitBoxOrient::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitBoxPack::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.BoxPack());
@@ -7326,7 +7553,6 @@ const CSSValue* WebkitBoxReflect::ParseSingleValue(
const CSSValue* WebkitBoxReflect::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForReflection(style.BoxReflect(), style,
@@ -7343,7 +7569,6 @@ const CSSValue* InternalFontSizeDelta::ParseSingleValue(
const CSSValue* WebkitFontSmoothing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetFontDescription().FontSmoothing());
@@ -7360,7 +7585,6 @@ const CSSValue* WebkitHighlight::ParseSingleValue(
const CSSValue* WebkitHighlight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.Highlight() == g_null_atom)
@@ -7379,7 +7603,6 @@ const CSSValue* WebkitHyphenateCharacter::ParseSingleValue(
const CSSValue* WebkitHyphenateCharacter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HyphenationString().IsNull())
@@ -7389,7 +7612,6 @@ const CSSValue* WebkitHyphenateCharacter::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitLineBreak::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetLineBreak());
@@ -7405,7 +7627,6 @@ const CSSValue* WebkitLineClamp::ParseSingleValue(
const CSSValue* WebkitLineClamp::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (!style.HasLineClamp())
@@ -7425,7 +7646,6 @@ const CSSValue* WebkitLocale::ParseSingleValue(
const CSSValue* WebkitLocale::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.Locale().IsNull())
@@ -7453,7 +7673,6 @@ const CSSValue* WebkitMaskBoxImageOutset::ParseSingleValue(
const CSSValue* WebkitMaskBoxImageOutset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageQuad(
@@ -7469,7 +7688,6 @@ const CSSValue* WebkitMaskBoxImageRepeat::ParseSingleValue(
const CSSValue* WebkitMaskBoxImageRepeat::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageRepeat(style.MaskBoxImage());
@@ -7485,7 +7703,6 @@ const CSSValue* WebkitMaskBoxImageSlice::ParseSingleValue(
const CSSValue* WebkitMaskBoxImageSlice::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageSlice(style.MaskBoxImage());
@@ -7500,7 +7717,6 @@ const CSSValue* WebkitMaskBoxImageSource::ParseSingleValue(
const CSSValue* WebkitMaskBoxImageSource::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.MaskBoxImageSource()) {
@@ -7525,7 +7741,6 @@ const CSSValue* WebkitMaskBoxImageWidth::ParseSingleValue(
const CSSValue* WebkitMaskBoxImageWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImageQuad(
@@ -7543,7 +7758,6 @@ const CSSValue* WebkitMaskClip::ParseSingleValue(
const CSSValue* WebkitMaskClip::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -7565,7 +7779,6 @@ const CSSValue* WebkitMaskComposite::ParseSingleValue(
const CSSValue* WebkitMaskComposite::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -7585,7 +7798,6 @@ const CSSValue* WebkitMaskImage::ParseSingleValue(
const CSSValue* WebkitMaskImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer& fill_layer = style.MaskLayers();
@@ -7604,7 +7816,6 @@ const CSSValue* WebkitMaskOrigin::ParseSingleValue(
const CSSValue* WebkitMaskOrigin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
@@ -7628,7 +7839,6 @@ const CSSValue* WebkitMaskPositionX::ParseSingleValue(
const CSSValue* WebkitMaskPositionX::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer* curr_layer = &style.MaskLayers();
@@ -7648,7 +7858,6 @@ const CSSValue* WebkitMaskPositionY::ParseSingleValue(
const CSSValue* WebkitMaskPositionY::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer* curr_layer = &style.MaskLayers();
@@ -7666,7 +7875,6 @@ const CSSValue* WebkitMaskSize::ParseSingleValue(
const CSSValue* WebkitMaskSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const FillLayer& fill_layer = style.MaskLayers();
@@ -7693,7 +7901,6 @@ const CSSValue* WebkitPerspectiveOriginY::ParseSingleValue(
const CSSValue* WebkitPrintColorAdjust::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.PrintColorAdjust());
@@ -7701,7 +7908,6 @@ const CSSValue* WebkitPrintColorAdjust::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitRtlOrdering::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.RtlOrdering() == EOrder::kVisual
@@ -7711,7 +7917,6 @@ const CSSValue* WebkitRtlOrdering::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitRubyPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetRubyPosition());
@@ -7719,7 +7924,6 @@ const CSSValue* WebkitRubyPosition::CSSValueFromComputedStyleInternal(
const CSSValue* RubyPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
switch (style.GetRubyPosition()) {
@@ -7742,12 +7946,16 @@ const CSSValue* WebkitTapHighlightColor::ParseSingleValue(
const blink::Color WebkitTapHighlightColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
+ StyleColor highlight_color = style.TapHighlightColor();
+ if (style.ShouldForceColor(highlight_color)) {
+ return visited_link ? style.GetInternalForcedVisitedCurrentColor()
+ : style.GetInternalForcedCurrentColor();
+ }
return style.ResolvedColor(style.TapHighlightColor());
}
const CSSValue* WebkitTapHighlightColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -7756,7 +7964,6 @@ const CSSValue* WebkitTapHighlightColor::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitTextCombine::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.TextCombine() == ETextCombine::kAll)
@@ -7774,7 +7981,6 @@ const CSSValue* WebkitTextDecorationsInEffect::ParseSingleValue(
const CSSValue*
WebkitTextDecorationsInEffect::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::RenderTextDecorationFlagsToCSSValue(
@@ -7792,13 +7998,15 @@ const blink::Color WebkitTextEmphasisColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.TextEmphasisColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor text_emphasis_color = style.TextEmphasisColor();
+ if (style.ShouldForceColor(text_emphasis_color))
+ return style.GetInternalForcedCurrentColor();
+ return text_emphasis_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* WebkitTextEmphasisColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -7858,7 +8066,6 @@ const CSSValue* WebkitTextEmphasisPosition::ParseSingleValue(
const CSSValue* WebkitTextEmphasisPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -7920,7 +8127,6 @@ const CSSValue* WebkitTextEmphasisStyle::ParseSingleValue(
const CSSValue* WebkitTextEmphasisStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
switch (style.GetTextEmphasisMark()) {
@@ -8019,13 +8225,15 @@ const blink::Color WebkitTextFillColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.TextFillColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor text_fill_color = style.TextFillColor();
+ if (style.ShouldForceColor(text_fill_color))
+ return style.GetInternalForcedCurrentColor();
+ return text_fill_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* WebkitTextFillColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -8034,7 +8242,6 @@ const CSSValue* WebkitTextFillColor::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitTextOrientation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.GetTextOrientation() == ETextOrientation::kMixed)
@@ -8059,7 +8266,6 @@ void WebkitTextOrientation::ApplyValue(StyleResolverState& state,
const CSSValue* WebkitTextSecurity::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.TextSecurity());
@@ -8076,13 +8282,15 @@ const blink::Color WebkitTextStrokeColor::ColorIncludingFallback(
bool visited_link,
const ComputedStyle& style) const {
DCHECK(!visited_link);
- return style.TextStrokeColor().Resolve(style.GetCurrentColor(),
- style.UsedColorScheme());
+ StyleColor text_stroke_color = style.TextStrokeColor();
+ if (style.ShouldForceColor(text_stroke_color))
+ return style.GetInternalForcedCurrentColor();
+ return text_stroke_color.Resolve(style.GetCurrentColor(),
+ style.UsedColorScheme());
}
const CSSValue* WebkitTextStrokeColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::CurrentColorOrValidColor(
@@ -8099,7 +8307,6 @@ const CSSValue* WebkitTextStrokeWidth::ParseSingleValue(
const CSSValue* WebkitTextStrokeWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.TextStrokeWidth(), style);
@@ -8132,7 +8339,6 @@ const CSSValue* WebkitTransformOriginZ::ParseSingleValue(
const CSSValue* WebkitUserDrag::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.UserDrag());
@@ -8140,7 +8346,6 @@ const CSSValue* WebkitUserDrag::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitUserModify::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.UserModify());
@@ -8148,7 +8353,6 @@ const CSSValue* WebkitUserModify::CSSValueFromComputedStyleInternal(
const CSSValue* WebkitWritingMode::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetWritingMode());
@@ -8169,7 +8373,6 @@ void WebkitWritingMode::ApplyValue(StyleResolverState& state,
const CSSValue* WhiteSpace::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.WhiteSpace());
@@ -8183,7 +8386,6 @@ const CSSValue* Widows::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Widows::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.Widows(),
@@ -8204,7 +8406,6 @@ bool Width::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Width::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
if (ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(layout_object)) {
@@ -8233,7 +8434,7 @@ const CSSValue* WillChange::ParseSingleValue(
if (unresolved_property != CSSPropertyID::kInvalid &&
unresolved_property != CSSPropertyID::kVariable) {
#if DCHECK_IS_ON()
- DCHECK(CSSProperty::Get(resolveCSSPropertyID(unresolved_property))
+ DCHECK(CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
.IsWebExposed(context.GetExecutionContext()));
#endif
// Now "all" is used by both CSSValue and CSSPropertyValue.
@@ -8275,7 +8476,6 @@ const CSSValue* WillChange::ParseSingleValue(
const CSSValue* WillChange::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForWillChange(
@@ -8335,7 +8535,6 @@ void WillChange::ApplyValue(StyleResolverState& state,
const CSSValue* WordBreak::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.WordBreak());
@@ -8350,7 +8549,6 @@ const CSSValue* WordSpacing::ParseSingleValue(
const CSSValue* WordSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ZoomAdjustedPixelValue(style.WordSpacing(), style);
@@ -8358,7 +8556,6 @@ const CSSValue* WordSpacing::CSSValueFromComputedStyleInternal(
const CSSValue* WritingMode::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSIdentifierValue::Create(style.GetWritingMode());
@@ -8387,11 +8584,9 @@ const CSSValue* X::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* X::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.X(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.X(), style);
}
const CSSValue* Y::ParseSingleValue(CSSParserTokenRange& range,
@@ -8403,11 +8598,9 @@ const CSSValue* Y::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Y::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject*,
bool allow_visited_style) const {
- return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(svg_style.Y(),
- style);
+ return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(style.Y(), style);
}
const CSSValue* ZIndex::ParseSingleValue(CSSParserTokenRange& range,
@@ -8420,7 +8613,6 @@ const CSSValue* ZIndex::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* ZIndex::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
if (style.HasAutoZIndex())
@@ -8457,7 +8649,6 @@ const CSSValue* Zoom::ParseSingleValue(CSSParserTokenRange& range,
const CSSValue* Zoom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return CSSNumericLiteralValue::Create(style.Zoom(),
diff --git a/chromium/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/chromium/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index 47bd06e633f..485b157c49a 100644
--- a/chromium/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/chromium/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -102,7 +102,6 @@ bool Animation::ParseShorthand(
const CSSValue* Animation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const CSSAnimationData* animation_data = style.Animations();
@@ -177,7 +176,6 @@ bool Background::ParseShorthand(
const CSSValue* Background::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForBackgroundShorthand(style, layout_object,
@@ -213,7 +211,6 @@ bool BackgroundPosition::ParseShorthand(
const CSSValue* BackgroundPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::BackgroundPositionOrWebkitMaskPosition(
@@ -252,7 +249,6 @@ bool BackgroundRepeat::ParseShorthand(
const CSSValue* BackgroundRepeat::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::BackgroundRepeatOrWebkitMaskRepeat(
@@ -271,7 +267,6 @@ bool BorderBlockColor::ParseShorthand(
const CSSValue* BorderBlockColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -305,7 +300,6 @@ bool BorderBlock::ParseShorthand(
const CSSValue* BorderBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const CSSValue* value_start =
@@ -352,7 +346,6 @@ bool BorderBlockStyle::ParseShorthand(
const CSSValue* BorderBlockStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -371,7 +364,6 @@ bool BorderBlockWidth::ParseShorthand(
const CSSValue* BorderBlockWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -390,7 +382,6 @@ bool BorderBottom::ParseShorthand(
const CSSValue* BorderBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -409,7 +400,6 @@ bool BorderColor::ParseShorthand(
const CSSValue* BorderColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -446,7 +436,6 @@ bool Border::ParseShorthand(
const CSSValue* Border::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const CSSValue* value = GetCSSPropertyBorderTop().CSSValueFromComputedStyle(
@@ -521,7 +510,6 @@ bool BorderImage::ParseShorthand(
const CSSValue* BorderImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImage(style.BorderImage(), style,
@@ -540,7 +528,6 @@ bool BorderInlineColor::ParseShorthand(
const CSSValue* BorderInlineColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -574,7 +561,6 @@ bool BorderInline::ParseShorthand(
const CSSValue* BorderInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const CSSValue* value_start =
@@ -621,7 +607,6 @@ bool BorderInlineStyle::ParseShorthand(
const CSSValue* BorderInlineStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -640,7 +625,6 @@ bool BorderInlineWidth::ParseShorthand(
const CSSValue* BorderInlineWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -659,7 +643,6 @@ bool BorderLeft::ParseShorthand(
const CSSValue* BorderLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -713,7 +696,6 @@ bool BorderRadius::ParseShorthand(
const CSSValue* BorderRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForBorderRadiusShorthand(style);
@@ -731,7 +713,6 @@ bool BorderRight::ParseShorthand(
const CSSValue* BorderRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -769,7 +750,6 @@ bool BorderSpacing::ParseShorthand(
const CSSValue* BorderSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -790,7 +770,6 @@ bool BorderStyle::ParseShorthand(
const CSSValue* BorderStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -809,7 +788,6 @@ bool BorderTop::ParseShorthand(
const CSSValue* BorderTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -828,7 +806,6 @@ bool BorderWidth::ParseShorthand(
const CSSValue* BorderWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -847,7 +824,6 @@ bool ColumnRule::ParseShorthand(
const CSSValue* ColumnRule::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -886,7 +862,6 @@ bool Columns::ParseShorthand(
const CSSValue* Columns::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -975,7 +950,6 @@ bool Flex::ParseShorthand(bool important,
const CSSValue* Flex::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -994,7 +968,6 @@ bool FlexFlow::ParseShorthand(
const CSSValue* FlexFlow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -1221,7 +1194,6 @@ bool Font::ParseShorthand(bool important,
const CSSValue* Font::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForFont(style);
@@ -1322,7 +1294,6 @@ bool FontVariant::ParseShorthand(
const CSSValue* FontVariant::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForFontVariantProperty(style, layout_object,
@@ -1352,7 +1323,6 @@ bool Gap::ParseShorthand(bool important,
const CSSValue* Gap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGapShorthand(
@@ -1428,7 +1398,6 @@ bool GridArea::ParseShorthand(
const CSSValue* GridArea::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGridShorthand(
@@ -1466,7 +1435,6 @@ bool GridColumn::ParseShorthand(
const CSSValue* GridColumn::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGridShorthand(
@@ -1492,7 +1460,6 @@ bool GridColumnGap::ParseShorthand(
const CSSValue* GridColumnGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -1667,12 +1634,11 @@ bool Grid::ParseShorthand(bool important,
bool Grid::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsLayoutGrid();
+ return layout_object && layout_object->IsLayoutGridIncludingNG();
}
const CSSValue* Grid::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGridShorthand(
@@ -1703,7 +1669,6 @@ bool GridGap::ParseShorthand(
const CSSValue* GridGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -1741,7 +1706,6 @@ bool GridRow::ParseShorthand(
const CSSValue* GridRow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGridShorthand(
@@ -1767,7 +1731,6 @@ bool GridRowGap::ParseShorthand(
const CSSValue* GridRowGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -1810,12 +1773,11 @@ bool GridTemplate::ParseShorthand(
bool GridTemplate::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
- return layout_object && layout_object->IsLayoutGrid();
+ return layout_object && layout_object->IsLayoutGridIncludingNG();
}
const CSSValue* GridTemplate::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForGridShorthand(
@@ -1834,7 +1796,6 @@ bool InsetBlock::ParseShorthand(
const CSSValue* InsetBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -1853,7 +1814,6 @@ bool Inset::ParseShorthand(
const CSSValue* Inset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -1872,7 +1832,6 @@ bool InsetInline::ParseShorthand(
const CSSValue* InsetInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -1968,7 +1927,6 @@ bool ListStyle::ParseShorthand(
const CSSValue* ListStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -1987,7 +1945,6 @@ bool MarginBlock::ParseShorthand(
const CSSValue* MarginBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2014,7 +1971,6 @@ bool Margin::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Margin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -2033,7 +1989,6 @@ bool MarginInline::ParseShorthand(
const CSSValue* MarginInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2065,15 +2020,14 @@ bool Marker::ParseShorthand(
const CSSValue* Marker::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle& svg_style,
const LayoutObject* layout_object,
bool allow_visited_style) const {
const CSSValue* marker_start =
- ComputedStyleUtils::ValueForSVGResource(svg_style.MarkerStartResource());
- if (*marker_start == *ComputedStyleUtils::ValueForSVGResource(
- svg_style.MarkerMidResource()) &&
- *marker_start == *ComputedStyleUtils::ValueForSVGResource(
- svg_style.MarkerEndResource())) {
+ ComputedStyleUtils::ValueForSVGResource(style.MarkerStartResource());
+ if (*marker_start ==
+ *ComputedStyleUtils::ValueForSVGResource(style.MarkerMidResource()) &&
+ *marker_start ==
+ *ComputedStyleUtils::ValueForSVGResource(style.MarkerEndResource())) {
return marker_start;
}
return nullptr;
@@ -2185,7 +2139,6 @@ bool Offset::ParseShorthand(
const CSSValue* Offset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForOffset(style, layout_object,
@@ -2204,7 +2157,6 @@ bool Outline::ParseShorthand(
const CSSValue* Outline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
@@ -2223,7 +2175,6 @@ bool Overflow::ParseShorthand(
const CSSValue* Overflow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -2246,7 +2197,6 @@ bool OverscrollBehavior::ParseShorthand(
const CSSValue* OverscrollBehavior::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -2269,7 +2219,6 @@ bool PaddingBlock::ParseShorthand(
const CSSValue* PaddingBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2296,7 +2245,6 @@ bool Padding::IsLayoutDependent(const ComputedStyle* style,
const CSSValue* Padding::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -2315,7 +2263,6 @@ bool PaddingInline::ParseShorthand(
const CSSValue* PaddingInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2343,7 +2290,6 @@ bool PageBreakAfter::ParseShorthand(
const CSSValue* PageBreakAfter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPageBreakBetween(style.BreakAfter());
@@ -2370,7 +2316,6 @@ bool PageBreakBefore::ParseShorthand(
const CSSValue* PageBreakBefore::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPageBreakBetween(style.BreakBefore());
@@ -2396,7 +2341,6 @@ bool PageBreakInside::ParseShorthand(
const CSSValue* PageBreakInside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForPageBreakInside(style.BreakInside());
@@ -2454,7 +2398,6 @@ bool PlaceContent::ParseShorthand(
const CSSValue* PlaceContent::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
@@ -2502,7 +2445,6 @@ bool PlaceItems::ParseShorthand(
const CSSValue* PlaceItems::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
@@ -2550,7 +2492,6 @@ bool PlaceSelf::ParseShorthand(
const CSSValue* PlaceSelf::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
@@ -2569,7 +2510,6 @@ bool ScrollMarginBlock::ParseShorthand(
const CSSValue* ScrollMarginBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2588,7 +2528,6 @@ bool ScrollMargin::ParseShorthand(
const CSSValue* ScrollMargin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -2607,7 +2546,6 @@ bool ScrollMarginInline::ParseShorthand(
const CSSValue* ScrollMarginInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2626,7 +2564,6 @@ bool ScrollPaddingBlock::ParseShorthand(
const CSSValue* ScrollPaddingBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2645,7 +2582,6 @@ bool ScrollPadding::ParseShorthand(
const CSSValue* ScrollPadding::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
@@ -2664,7 +2600,6 @@ bool ScrollPaddingInline::ParseShorthand(
const CSSValue* ScrollPaddingInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
@@ -2687,7 +2622,6 @@ bool TextDecoration::ParseShorthand(
const CSSValue* TextDecoration::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject* layout_object,
bool allow_visited_style) const {
// Use RuntimeEnabledFeature-aware shorthandForProperty() method until
@@ -2777,7 +2711,6 @@ bool Transition::ParseShorthand(
const CSSValue* Transition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
const CSSTransitionData* transition_data = style.Transitions();
@@ -2835,7 +2768,6 @@ bool WebkitColumnBreakAfter::ParseShorthand(
const CSSValue* WebkitColumnBreakAfter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakBetween(
@@ -2862,7 +2794,6 @@ bool WebkitColumnBreakBefore::ParseShorthand(
const CSSValue* WebkitColumnBreakBefore::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakBetween(
@@ -2889,7 +2820,6 @@ bool WebkitColumnBreakInside::ParseShorthand(
const CSSValue* WebkitColumnBreakInside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakInside(
@@ -2945,7 +2875,6 @@ bool WebkitMaskBoxImage::ParseShorthand(
const CSSValue* WebkitMaskBoxImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::ValueForNinePieceImage(style.MaskBoxImage(), style,
@@ -2991,7 +2920,6 @@ bool WebkitMaskPosition::ParseShorthand(
const CSSValue* WebkitMaskPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::BackgroundPositionOrWebkitMaskPosition(
@@ -3030,7 +2958,6 @@ bool WebkitMaskRepeat::ParseShorthand(
const CSSValue* WebkitMaskRepeat::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
- const SVGComputedStyle&,
const LayoutObject*,
bool allow_visited_style) const {
return ComputedStyleUtils::BackgroundRepeatOrWebkitMaskRepeat(
diff --git a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
index f21dd534e20..75ad43c50c9 100644
--- a/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
+++ b/chromium/third_party/blink/renderer/core/css/remote_font_face_source.cc
@@ -191,7 +191,7 @@ void RemoteFontFaceSource::NotifyFinished(Resource* resource) {
if (window && window->document()->IsDetached())
return;
- FontResource* font = ToFontResource(resource);
+ auto* font = To<FontResource>(resource);
histograms_.RecordRemoteFont(font);
custom_font_data_ = font->GetCustomFontData();
@@ -367,7 +367,7 @@ void RemoteFontFaceSource::BeginLoadIfNeeded() {
SetDisplay(face_->GetFontFace()->GetFontDisplay());
- FontResource* font = ToFontResource(GetResource());
+ auto* font = To<FontResource>(GetResource());
if (font->StillNeedsLoad()) {
if (font->IsLowPriorityLoadingAllowedForRemoteFont()) {
font_selector_->GetExecutionContext()->AddConsoleMessage(
@@ -468,51 +468,27 @@ void RemoteFontFaceSource::FontLoadHistograms::RecordLoadTimeHistogram(
// bucket.
if (font->ErrorOccurred()) {
base::UmaHistogramTimes("WebFont.DownloadTime.LoadError", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.LoadError",
- delta);
- }
return;
}
size_t size = font->EncodedSize();
if (size < 10 * 1024) {
base::UmaHistogramTimes("WebFont.DownloadTime.0.Under10KB", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.0.Under10KB",
- delta);
- }
return;
}
if (size < 50 * 1024) {
base::UmaHistogramTimes("WebFont.DownloadTime.1.10KBTo50KB", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.1.10KBTo50KB",
- delta);
- }
return;
}
if (size < 100 * 1024) {
base::UmaHistogramTimes("WebFont.DownloadTime.2.50KBTo100KB", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.2.50KBTo100KB",
- delta);
- }
return;
}
if (size < 1024 * 1024) {
base::UmaHistogramTimes("WebFont.DownloadTime.3.100KBTo1MB", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.3.100KBTo1MB",
- delta);
- }
return;
}
base::UmaHistogramTimes("WebFont.DownloadTime.4.Over1MB", delta);
- if (data_source_ == kFromNetwork) {
- base::UmaHistogramTimes("WebFont.MissedCache.DownloadTime.4.Over1MB",
- delta);
- }
}
RemoteFontFaceSource::FontLoadHistograms::CacheHitMetrics
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/cascade_expansion.cc b/chromium/third_party/blink/renderer/core/css/resolver/cascade_expansion.cc
index cde8186771a..343856cca27 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/cascade_expansion.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/cascade_expansion.cc
@@ -137,7 +137,7 @@ void CascadeExpansion::AdvanceNormal() {
break;
case CSSPropertyID::kAll:
state_ = State::kAll;
- id_ = firstCSSProperty;
+ id_ = kFirstCSSProperty;
property_ = &CSSProperty::Get(id_);
// If this DCHECK is triggered, it means firstCSSProperty is not affected
// by 'all', and we need a function for figuring out the first property
@@ -171,7 +171,7 @@ void CascadeExpansion::AdvanceAll() {
int end = kIntLastCSSProperty + 1;
for (; i < end; ++i) {
- id_ = convertToCSSPropertyID(i);
+ id_ = ConvertToCSSPropertyID(i);
if (IsAffectedByAll(id_))
break;
}
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations.h b/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations.h
index a3a664a1ea4..f4a2510e67d 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations.h
@@ -25,14 +25,14 @@ inline uint32_t EncodeInterpolationPosition(CSSPropertyID id,
static_assert(kIntLastCSSProperty < std::numeric_limits<uint16_t>::max(),
"Enough bits for CSSPropertyID");
DCHECK_NE(id, CSSPropertyID::kInvalid);
- DCHECK_LE(id, lastCSSProperty);
+ DCHECK_LE(id, kLastCSSProperty);
return (static_cast<uint32_t>(!is_presentation_attribute) << 24) |
(static_cast<uint32_t>(index & 0xFF) << 16) |
(static_cast<uint32_t>(id) & 0xFFFF);
}
inline CSSPropertyID DecodeInterpolationPropertyID(uint32_t position) {
- return convertToCSSPropertyID(position & 0xFFFF);
+ return ConvertToCSSPropertyID(position & 0xFFFF);
}
inline uint8_t DecodeInterpolationIndex(uint32_t position) {
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations_test.cc
index 9af6d156af2..6a2414b0205 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/cascade_interpolations_test.cc
@@ -55,7 +55,7 @@ TEST(CascadeInterpolationsTest, EncodeDecodeInterpolationPropertyID) {
}
TEST(CascadeInterpolationsTest, EncodeDecodeInterpolationIndex) {
- CSSPropertyID id = lastCSSProperty;
+ CSSPropertyID id = kLastCSSProperty;
for (uint8_t index : Vector<uint8_t>({0u, 1u, 15u, 51u, 254u, 255u})) {
EXPECT_EQ(index, DecodeInterpolationIndex(
EncodeInterpolationPosition(id, index, false)));
@@ -63,7 +63,7 @@ TEST(CascadeInterpolationsTest, EncodeDecodeInterpolationIndex) {
}
TEST(CascadeInterpolationsTest, EncodeDecodeIsPresentationAttribute) {
- CSSPropertyID id = lastCSSProperty;
+ CSSPropertyID id = kLastCSSProperty;
EXPECT_FALSE(DecodeIsPresentationAttribute(
EncodeInterpolationPosition(id, 0u, false)));
EXPECT_FALSE(DecodeIsPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.cc b/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.cc
index 70e02fd8552..10c56197870 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.cc
@@ -42,7 +42,7 @@ inline CascadePriority* FindCustom(const CSSPropertyName& name,
inline CascadePriority* FindNative(const CSSPropertyName& name,
CascadeMap::NativeMap& map) {
size_t index = static_cast<size_t>(name.Id());
- DCHECK_LT(index, static_cast<size_t>(numCSSProperties));
+ DCHECK_LT(index, static_cast<size_t>(kNumCSSProperties));
return map.Bits().Has(name.Id()) ? (map.Buffer() + index) : nullptr;
}
@@ -54,7 +54,7 @@ inline CascadePriority AtCustom(const CSSPropertyName& name,
inline CascadePriority AtNative(const CSSPropertyName& name,
const CascadeMap::NativeMap& map) {
size_t index = static_cast<size_t>(name.Id());
- DCHECK_LT(index, static_cast<size_t>(numCSSProperties));
+ DCHECK_LT(index, static_cast<size_t>(kNumCSSProperties));
return map.Bits().Has(name.Id()) ? map.Buffer()[index] : CascadePriority();
}
@@ -121,7 +121,7 @@ void CascadeMap::Add(const CSSPropertyName& name, CascadePriority priority) {
CSSPropertyID id = name.Id();
size_t index = static_cast<size_t>(id);
- DCHECK_LT(index, static_cast<size_t>(numCSSProperties));
+ DCHECK_LT(index, static_cast<size_t>(kNumCSSProperties));
// Set bit in high_priority_, if appropriate.
static_assert(static_cast<int>(kLastHighPriorityCSSProperty) < 64,
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.h b/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.h
index dc3255ce23e..2b193f3cdcd 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/cascade_map.h
@@ -68,7 +68,7 @@ class CORE_EXPORT CascadeMap {
// CascadePriority objects. A companion bitset keeps track of which
// properties are initialized.
CSSBitset bits_;
- alignas(CascadePriority) char properties_[numCSSProperties *
+ alignas(CascadePriority) char properties_[kNumCSSProperties *
sizeof(CascadePriority)];
};
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
index ec04b3b42bf..8d289e342d4 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/dom/visited_link_state.h"
namespace blink {
@@ -36,19 +35,9 @@ ElementResolveContext::ElementResolveContext(Element& element)
layout_parent_(nullptr),
element_link_state_(
element.GetDocument().GetVisitedLinkState().DetermineLinkState(
- element)),
- distributed_to_insertion_point_(false) {
- if (!element.NeedsDistributionRecalc() &&
- element.CanParticipateInFlatTree()) {
- LayoutTreeBuilderTraversal::ParentDetails parent_details;
- parent_node_ = LayoutTreeBuilderTraversal::Parent(element);
- layout_parent_ =
- LayoutTreeBuilderTraversal::LayoutParent(element, &parent_details);
- distributed_to_insertion_point_ = parent_details.GetInsertionPoint();
- } else {
- parent_node_ = nullptr;
- layout_parent_ = nullptr;
- }
+ element)) {
+ parent_node_ = LayoutTreeBuilderTraversal::Parent(element);
+ layout_parent_ = LayoutTreeBuilderTraversal::LayoutParent(element);
if (auto* document_element = element.GetDocument().documentElement()) {
if (element != document_element)
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
index 3af63d30b8e..43503c963a6 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
@@ -55,9 +55,6 @@ class CORE_EXPORT ElementResolveContext {
return LayoutParent() ? LayoutParent()->GetComputedStyle() : nullptr;
}
EInsideLink ElementLinkState() const { return element_link_state_; }
- bool DistributedToV0InsertionPoint() const {
- return distributed_to_insertion_point_;
- }
private:
Element* element_;
@@ -65,7 +62,6 @@ class CORE_EXPORT ElementResolveContext {
ContainerNode* layout_parent_;
scoped_refptr<const ComputedStyle> root_element_style_;
EInsideLink element_link_state_;
- bool distributed_to_insertion_point_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
index 7c3b4695993..0d3f61763e0 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
@@ -24,7 +24,9 @@
#include "third_party/blink/renderer/core/css/resolver/element_style_resources.h"
#include "third_party/blink/renderer/core/css/css_gradient_value.h"
+#include "third_party/blink/renderer/core/css/css_image_set_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h"
+#include "third_party/blink/renderer/core/css/css_paint_value.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_uri_value.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -55,7 +57,7 @@ namespace blink {
ElementStyleResources::ElementStyleResources(Element& element,
float device_scale_factor,
PseudoElement* pseudo_element)
- : element_(&element),
+ : element_(element),
device_scale_factor_(device_scale_factor),
pseudo_element_(pseudo_element) {}
@@ -100,38 +102,59 @@ StyleImage* ElementStyleResources::CachedOrPendingFromValue(
pending_image_properties_.insert(property);
return MakeGarbageCollected<StylePendingImage>(value);
}
- value.RestoreCachedResourceIfNeeded(element_->GetDocument());
+ value.RestoreCachedResourceIfNeeded(element_.GetDocument());
return value.CachedImage();
}
+static bool AllowExternalResources(CSSPropertyID property) {
+ return property == CSSPropertyID::kBackdropFilter ||
+ property == CSSPropertyID::kFilter;
+}
+
SVGResource* ElementStyleResources::GetSVGResourceFromValue(
- TreeScope& tree_scope,
- const cssvalue::CSSURIValue& value,
- AllowExternal allow_external) const {
- if (value.IsLocal(element_->GetDocument())) {
+ CSSPropertyID property,
+ const cssvalue::CSSURIValue& value) {
+ if (value.IsLocal(element_.GetDocument())) {
SVGTreeScopeResources& tree_scope_resources =
- tree_scope.EnsureSVGTreeScopedResources();
+ element_.OriginatingTreeScope().EnsureSVGTreeScopedResources();
AtomicString decoded_fragment(DecodeURLEscapeSequences(
value.FragmentIdentifier(), DecodeURLMode::kUTF8OrIsomorphic));
return tree_scope_resources.ResourceForId(decoded_fragment);
}
- if (allow_external == kAllowExternalResource)
+ if (AllowExternalResources(property)) {
+ pending_svg_resource_properties_.insert(property);
return value.EnsureResourceReference();
+ }
return nullptr;
}
-void ElementStyleResources::LoadPendingSVGResources(ComputedStyle& style) {
- if (!style.HasFilter())
- return;
- FilterOperations::FilterOperationVector& filter_operations =
- style.MutableFilter().Operations();
+static void LoadResourcesForFilter(
+ FilterOperations::FilterOperationVector& filter_operations,
+ Document& document) {
for (const auto& filter_operation : filter_operations) {
auto* reference_operation =
DynamicTo<ReferenceFilterOperation>(filter_operation.Get());
if (!reference_operation)
continue;
if (SVGResource* resource = reference_operation->Resource())
- resource->Load(element_->GetDocument());
+ resource->Load(document);
+ }
+}
+
+void ElementStyleResources::LoadPendingSVGResources(ComputedStyle& style) {
+ Document& document = element_.GetDocument();
+ for (CSSPropertyID property : pending_svg_resource_properties_) {
+ switch (property) {
+ case CSSPropertyID::kBackdropFilter:
+ LoadResourcesForFilter(style.MutableBackdropFilter().Operations(),
+ document);
+ break;
+ case CSSPropertyID::kFilter:
+ LoadResourcesForFilter(style.MutableFilter().Operations(), document);
+ break;
+ default:
+ NOTREACHED();
+ }
}
}
@@ -147,28 +170,27 @@ static bool BackgroundLayerMayBeSprite(const FillLayer& background_layer) {
StyleImage* ElementStyleResources::LoadPendingImage(
ComputedStyle& style,
- StylePendingImage* pending_image,
+ CSSValue& value,
FetchParameters::ImageRequestBehavior image_request_behavior,
CrossOriginAttributeValue cross_origin) {
- if (CSSImageValue* image_value = pending_image->CssImageValue()) {
- return image_value->CacheImage(element_->GetDocument(),
+ if (auto* image_value = DynamicTo<CSSImageValue>(value)) {
+ return image_value->CacheImage(element_.GetDocument(),
image_request_behavior, cross_origin);
}
- if (CSSPaintValue* paint_value = pending_image->CssPaintValue()) {
+ if (auto* paint_value = DynamicTo<CSSPaintValue>(value)) {
auto* image = MakeGarbageCollected<StyleGeneratedImage>(*paint_value);
style.AddPaintImage(image);
return image;
}
- if (CSSImageGeneratorValue* image_generator_value =
- pending_image->CssImageGeneratorValue()) {
- image_generator_value->LoadSubimages(element_->GetDocument());
+ if (auto* image_generator_value = DynamicTo<CSSImageGeneratorValue>(value)) {
+ image_generator_value->LoadSubimages(element_.GetDocument());
return MakeGarbageCollected<StyleGeneratedImage>(*image_generator_value);
}
- if (CSSImageSetValue* image_set_value = pending_image->CssImageSetValue()) {
- return image_set_value->CacheImage(element_->GetDocument(),
+ if (auto* image_set_value = DynamicTo<CSSImageSetValue>(value)) {
+ return image_set_value->CacheImage(element_.GetDocument(),
device_scale_factor_,
image_request_behavior, cross_origin);
}
@@ -177,6 +199,12 @@ StyleImage* ElementStyleResources::LoadPendingImage(
return nullptr;
}
+static CSSValue* PendingCssValue(StyleImage* style_image) {
+ if (auto* pending_image = DynamicTo<StylePendingImage>(style_image))
+ return pending_image->CssValue();
+ return nullptr;
+}
+
void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
// We must loop over the properties and then look at the style to see if
// a pending image exists, and only load that image. For example:
@@ -201,12 +229,12 @@ void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
case CSSPropertyID::kBackgroundImage: {
for (FillLayer* background_layer = &style.AccessBackgroundLayers();
background_layer; background_layer = background_layer->Next()) {
- StyleImage* background_image = background_layer->GetImage();
- if (background_image && background_image->IsPendingImage()) {
+ if (auto* pending_value =
+ PendingCssValue(background_layer->GetImage())) {
FetchParameters::ImageRequestBehavior image_request_behavior =
FetchParameters::kNone;
if (!BackgroundLayerMayBeSprite(*background_layer)) {
- if (element_->GetDocument()
+ if (element_.GetDocument()
.GetFrame()
->GetLazyLoadImageSetting() ==
LocalFrame::LazyLoadImageSetting::kEnabledAutomatic) {
@@ -214,11 +242,10 @@ void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
}
}
StyleImage* new_image =
- LoadPendingImage(style, To<StylePendingImage>(background_image),
- image_request_behavior);
+ LoadPendingImage(style, *pending_value, image_request_behavior);
if (new_image && new_image->IsLazyloadPossiblyDeferred()) {
LazyImageHelper::StartMonitoring(pseudo_element_ ? pseudo_element_
- : element_);
+ : &element_);
}
background_layer->SetImage(new_image);
}
@@ -229,13 +256,11 @@ void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
for (ContentData* content_data =
const_cast<ContentData*>(style.GetContentData());
content_data; content_data = content_data->Next()) {
- if (content_data->IsImage()) {
- StyleImage* image = To<ImageContentData>(content_data)->GetImage();
- if (image->IsPendingImage()) {
- To<ImageContentData>(content_data)
- ->SetImage(LoadPendingImage(style,
- To<StylePendingImage>(image),
- FetchParameters::kNone));
+ if (auto* image_content =
+ DynamicTo<ImageContentData>(*content_data)) {
+ if (auto* pending_value =
+ PendingCssValue(image_content->GetImage())) {
+ image_content->SetImage(LoadPendingImage(style, *pending_value));
}
}
}
@@ -243,45 +268,28 @@ void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
}
case CSSPropertyID::kCursor: {
if (CursorList* cursor_list = style.Cursors()) {
- for (wtf_size_t i = 0; i < cursor_list->size(); ++i) {
- CursorData& current_cursor = cursor_list->at(i);
- if (StyleImage* image = current_cursor.GetImage()) {
- if (image->IsPendingImage()) {
- current_cursor.SetImage(
- LoadPendingImage(style, To<StylePendingImage>(image),
- FetchParameters::kNone));
- }
- }
+ for (CursorData& cursor : *cursor_list) {
+ if (auto* pending_value = PendingCssValue(cursor.GetImage()))
+ cursor.SetImage(LoadPendingImage(style, *pending_value));
}
}
break;
}
case CSSPropertyID::kListStyleImage: {
- if (style.ListStyleImage() &&
- style.ListStyleImage()->IsPendingImage()) {
- style.SetListStyleImage(LoadPendingImage(
- style, To<StylePendingImage>(style.ListStyleImage()),
- FetchParameters::kNone));
- }
+ if (auto* pending_value = PendingCssValue(style.ListStyleImage()))
+ style.SetListStyleImage(LoadPendingImage(style, *pending_value));
break;
}
case CSSPropertyID::kBorderImageSource: {
- if (style.BorderImageSource() &&
- style.BorderImageSource()->IsPendingImage()) {
- style.SetBorderImageSource(LoadPendingImage(
- style, To<StylePendingImage>(style.BorderImageSource()),
- FetchParameters::kNone));
- }
+ if (auto* pending_value = PendingCssValue(style.BorderImageSource()))
+ style.SetBorderImageSource(LoadPendingImage(style, *pending_value));
break;
}
case CSSPropertyID::kWebkitBoxReflect: {
if (StyleReflection* reflection = style.BoxReflect()) {
const NinePieceImage& mask_image = reflection->Mask();
- if (mask_image.GetImage() &&
- mask_image.GetImage()->IsPendingImage()) {
- StyleImage* loaded_image = LoadPendingImage(
- style, To<StylePendingImage>(mask_image.GetImage()),
- FetchParameters::kNone);
+ if (auto* pending_value = PendingCssValue(mask_image.GetImage())) {
+ StyleImage* loaded_image = LoadPendingImage(style, *pending_value);
reflection->SetMask(NinePieceImage(
loaded_image, mask_image.ImageSlices(), mask_image.Fill(),
mask_image.BorderSlices(), mask_image.Outset(),
@@ -291,32 +299,28 @@ void ElementStyleResources::LoadPendingImages(ComputedStyle& style) {
break;
}
case CSSPropertyID::kWebkitMaskBoxImageSource: {
- if (style.MaskBoxImageSource() &&
- style.MaskBoxImageSource()->IsPendingImage()) {
- style.SetMaskBoxImageSource(LoadPendingImage(
- style, To<StylePendingImage>(style.MaskBoxImageSource()),
- FetchParameters::kNone));
- }
+ if (auto* pending_value = PendingCssValue(style.MaskBoxImageSource()))
+ style.SetMaskBoxImageSource(LoadPendingImage(style, *pending_value));
break;
}
case CSSPropertyID::kWebkitMaskImage: {
for (FillLayer* mask_layer = &style.AccessMaskLayers(); mask_layer;
mask_layer = mask_layer->Next()) {
- if (mask_layer->GetImage() &&
- mask_layer->GetImage()->IsPendingImage()) {
- mask_layer->SetImage(LoadPendingImage(
- style, To<StylePendingImage>(mask_layer->GetImage()),
- FetchParameters::kNone, kCrossOriginAttributeAnonymous));
+ if (auto* pending_value = PendingCssValue(mask_layer->GetImage())) {
+ mask_layer->SetImage(
+ LoadPendingImage(style, *pending_value, FetchParameters::kNone,
+ kCrossOriginAttributeAnonymous));
}
}
break;
}
case CSSPropertyID::kShapeOutside:
- if (style.ShapeOutside() && style.ShapeOutside()->GetImage() &&
- style.ShapeOutside()->GetImage()->IsPendingImage()) {
- style.ShapeOutside()->SetImage(LoadPendingImage(
- style, To<StylePendingImage>(style.ShapeOutside()->GetImage()),
- FetchParameters::kNone, kCrossOriginAttributeAnonymous));
+ if (ShapeValue* shape_value = style.ShapeOutside()) {
+ if (auto* pending_value = PendingCssValue(shape_value->GetImage())) {
+ shape_value->SetImage(
+ LoadPendingImage(style, *pending_value, FetchParameters::kNone,
+ kCrossOriginAttributeAnonymous));
+ }
}
break;
default:
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.h b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.h
index 2925ff471f3..b76a99f915c 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/element_style_resources.h
@@ -43,8 +43,6 @@ class Element;
class PseudoElement;
class SVGResource;
class StyleImage;
-class StylePendingImage;
-class TreeScope;
namespace cssvalue {
@@ -68,11 +66,8 @@ class ElementStyleResources {
StyleImage* CachedOrPendingFromValue(CSSPropertyID, const CSSImageValue&);
StyleImage* SetOrPendingFromValue(CSSPropertyID, const CSSImageSetValue&);
- enum AllowExternal { kDontAllowExternalResource, kAllowExternalResource };
- SVGResource* GetSVGResourceFromValue(
- TreeScope&,
- const cssvalue::CSSURIValue&,
- AllowExternal = kDontAllowExternalResource) const;
+ SVGResource* GetSVGResourceFromValue(CSSPropertyID,
+ const cssvalue::CSSURIValue&);
void LoadPendingResources(ComputedStyle&);
@@ -85,12 +80,13 @@ class ElementStyleResources {
StyleImage* LoadPendingImage(
ComputedStyle&,
- StylePendingImage*,
- FetchParameters::ImageRequestBehavior,
+ CSSValue&,
+ FetchParameters::ImageRequestBehavior = FetchParameters::kNone,
CrossOriginAttributeValue = kCrossOriginAttributeNotSet);
- Element* element_;
+ Element& element_;
HashSet<CSSPropertyID> pending_image_properties_;
+ HashSet<CSSPropertyID> pending_svg_resource_properties_;
float device_scale_factor_;
PseudoElement* pseudo_element_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
index d7612ea1755..ea69697deb3 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
@@ -156,7 +156,8 @@ double FilterOperationResolver::ResolveNumericArgumentForFunction(
FilterOperations FilterOperationResolver::CreateFilterOperations(
StyleResolverState& state,
- const CSSValue& in_value) {
+ const CSSValue& in_value,
+ CSSPropertyID property_id) {
FilterOperations operations;
if (auto* in_identifier_value = DynamicTo<CSSIdentifierValue>(in_value)) {
@@ -173,9 +174,8 @@ FilterOperations FilterOperationResolver::CreateFilterOperations(
CountFilterUse(FilterOperation::REFERENCE, state.GetDocument());
SVGResource* resource =
- state.GetElementStyleResources().GetSVGResourceFromValue(
- state.GetTreeScope(), *url_value,
- ElementStyleResources::kAllowExternalResource);
+ state.GetElementStyleResources().GetSVGResourceFromValue(property_id,
+ *url_value);
operations.Operations().push_back(
MakeGarbageCollected<ReferenceFilterOperation>(
url_value->ValueForSerialization(), resource));
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h b/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h
index dc9a930311f..b0961e0fec9 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h
@@ -34,13 +34,16 @@ class CSSFunctionValue;
class CSSValue;
class StyleResolverState;
+enum class CSSPropertyID;
+
class CORE_EXPORT FilterOperationResolver {
STATIC_ONLY(FilterOperationResolver);
public:
static FilterOperation::OperationType FilterOperationForType(CSSValueID);
static FilterOperations CreateFilterOperations(StyleResolverState&,
- const CSSValue&);
+ const CSSValue&,
+ CSSPropertyID);
static FilterOperations CreateOffscreenFilterOperations(const CSSValue&,
const Font&);
static double ResolveNumericArgumentForFunction(
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/font_builder.cc b/chromium/third_party/blink/renderer/core/css/resolver/font_builder.cc
index 08667ae3f4a..2a4b1aa50b9 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/font_builder.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/font_builder.cc
@@ -37,7 +37,7 @@
namespace blink {
-FontBuilder::FontBuilder(Document* document) : document_(document), flags_(0) {
+FontBuilder::FontBuilder(Document* document) : document_(document) {
DCHECK(!document || document->GetFrame());
}
@@ -48,6 +48,7 @@ void FontBuilder::SetInitial(float effective_zoom) {
SetFamilyDescription(font_description_,
FontBuilder::InitialFamilyDescription());
+ SetFamilyTreeScope(nullptr);
SetSize(font_description_, FontBuilder::InitialSize());
}
@@ -110,6 +111,10 @@ void FontBuilder::SetFamilyDescription(
SetFamilyDescription(font_description_, family_description);
}
+void FontBuilder::SetFamilyTreeScope(const TreeScope* tree_scope) {
+ family_tree_scope_ = tree_scope;
+}
+
void FontBuilder::SetWeight(FontSelectionValue weight) {
Set(PropertySetFlag::kWeight);
@@ -410,6 +415,25 @@ void FontBuilder::UpdateFontDescription(FontDescription& description,
description.SetAdjustedSize(size);
}
+FontSelector* FontBuilder::FontSelectorFromTreeScope(
+ const TreeScope* tree_scope) {
+ // TODO(crbug.com/437837): The tree_scope may be from a different Document in
+ // the case where we are resolving style for elements in a <svg:use> shadow
+ // tree.
+ DCHECK(!tree_scope || tree_scope->GetDocument() == document_ ||
+ tree_scope->GetDocument().IsSVGDocument());
+ // TODO(crbug.com/336876): Font selector should be based on tree_scope for
+ // tree-scoped references.
+ return document_->GetStyleEngine().GetFontSelector();
+}
+
+FontSelector* FontBuilder::ComputeFontSelector(const ComputedStyle& style) {
+ if (IsSet(PropertySetFlag::kFamily))
+ return FontSelectorFromTreeScope(family_tree_scope_);
+ else
+ return style.GetFont().GetFontSelector();
+}
+
void FontBuilder::CreateFont(ComputedStyle& style,
const ComputedStyle* parent_style) {
DCHECK(document_);
@@ -423,7 +447,7 @@ void FontBuilder::CreateFont(ComputedStyle& style,
UpdateSpecifiedSize(description, style, parent_style);
UpdateComputedSize(description, style);
- FontSelector* font_selector = document_->GetStyleEngine().GetFontSelector();
+ FontSelector* font_selector = ComputeFontSelector(style);
UpdateAdjustedSize(description, style, font_selector);
style.SetFontInternal(Font(description, font_selector));
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/font_builder.h b/chromium/third_party/blink/renderer/core/css/resolver/font_builder.h
index f761f2e5ee6..3d894d75a5d 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/font_builder.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/font_builder.h
@@ -34,8 +34,9 @@
namespace blink {
-class FontSelector;
class ComputedStyle;
+class FontSelector;
+class TreeScope;
class CORE_EXPORT FontBuilder {
STACK_ALLOCATED();
@@ -65,6 +66,8 @@ class CORE_EXPORT FontBuilder {
void SetWeight(FontSelectionValue);
void SetFamilyDescription(const FontDescription::FamilyDescription&);
+ // font-family is a tree-scoped reference.
+ void SetFamilyTreeScope(const TreeScope*);
void SetFeatureSettings(scoped_refptr<FontFeatureSettings>);
void SetLocale(scoped_refptr<const LayoutLocale>);
void SetVariantCaps(FontDescription::FontVariantCaps);
@@ -141,7 +144,11 @@ class CORE_EXPORT FontBuilder {
float effective_zoom,
float specified_size);
- Document* document_;
+ FontSelector* FontSelectorFromTreeScope(const TreeScope* tree_scope);
+ FontSelector* ComputeFontSelector(const ComputedStyle& style);
+
+ Document* document_{nullptr};
+ const TreeScope* family_tree_scope_{nullptr};
FontDescription font_description_;
enum class PropertySetFlag {
@@ -173,7 +180,7 @@ class CORE_EXPORT FontBuilder {
return flags_ & (1 << unsigned(flag));
}
- unsigned flags_;
+ unsigned flags_{0};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/match_result.cc b/chromium/third_party/blink/renderer/core/css/resolver/match_result.cc
index df2515c9189..6a04ddcd71a 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/match_result.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/match_result.cc
@@ -92,6 +92,7 @@ MatchedExpansionsRange MatchResult::Expansions(const Document& document,
void MatchResult::Reset() {
matched_properties_.clear();
is_cacheable_ = true;
+ depends_on_container_queries_ = false;
current_origin_ = CascadeOrigin::kUserAgent;
current_tree_order_ = 0;
tree_scopes_.clear();
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/match_result.h b/chromium/third_party/blink/renderer/core/css/resolver/match_result.h
index 0786dab3ed7..b8ab8595873 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/match_result.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/match_result.h
@@ -144,6 +144,10 @@ class CORE_EXPORT MatchResult {
void SetIsCacheable(bool cacheable) { is_cacheable_ = cacheable; }
bool IsCacheable() const { return is_cacheable_; }
+ void SetDependsOnContainerQueries() { depends_on_container_queries_ = true; }
+ bool DependsOnContainerQueries() const {
+ return depends_on_container_queries_;
+ }
MatchedExpansionsRange Expansions(const Document&, CascadeFilter) const;
@@ -164,6 +168,7 @@ class CORE_EXPORT MatchResult {
MatchedPropertiesVector matched_properties_;
HeapVector<Member<const TreeScope>, 4> tree_scopes_;
bool is_cacheable_{true};
+ bool depends_on_container_queries_{false};
CascadeOrigin current_origin_{CascadeOrigin::kUserAgent};
uint16_t current_tree_order_{0};
};
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
index 415a5d059f0..2547c37b448 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
@@ -45,11 +45,9 @@ static unsigned ComputeMatchedPropertiesHash(const MatchResult& result) {
sizeof(MatchedProperties) * vector.size());
}
-void CachedMatchedProperties::Set(
- const ComputedStyle& style,
- const ComputedStyle& parent_style,
- const MatchedPropertiesVector& properties,
- const HashSet<CSSPropertyName>& new_dependencies) {
+void CachedMatchedProperties::Set(const ComputedStyle& style,
+ const ComputedStyle& parent_style,
+ const MatchedPropertiesVector& properties) {
for (const auto& new_matched_properties : properties) {
matched_properties.push_back(new_matched_properties.properties);
matched_properties_types.push_back(new_matched_properties.types_);
@@ -60,24 +58,6 @@ void CachedMatchedProperties::Set(
// for the substructures and never used as-is.
this->computed_style = ComputedStyle::Clone(style);
this->parent_computed_style = ComputedStyle::Clone(parent_style);
-
- DCHECK(
- RuntimeEnabledFeatures::CSSMatchedPropertiesCacheDependenciesEnabled() ||
- new_dependencies.IsEmpty());
- if (new_dependencies.size()) {
- DCHECK(new_dependencies.size() <= StyleResolverState::kMaxDependencies);
- // Plus one for g_null_atom.
- dependencies =
- std::make_unique<AtomicString[]>(new_dependencies.size() + 1);
-
- size_t index = 0;
- for (const CSSPropertyName& name : new_dependencies) {
- DCHECK_LT(index, new_dependencies.size());
- dependencies[index++] = name.ToAtomicString();
- }
- DCHECK_EQ(index, new_dependencies.size());
- dependencies[index] = g_null_atom;
- }
}
void CachedMatchedProperties::Clear() {
@@ -85,7 +65,6 @@ void CachedMatchedProperties::Clear() {
matched_properties_types.clear();
computed_style = nullptr;
parent_computed_style = nullptr;
- dependencies.reset();
}
bool CachedMatchedProperties::DependenciesEqual(
@@ -104,12 +83,15 @@ bool CachedMatchedProperties::DependenciesEqual(
return false;
}
- for (const AtomicString* name = dependencies.get(); name && !name->IsNull();
- name++) {
- CSSPropertyRef ref(*name, state.GetDocument());
- DCHECK(ref.IsValid());
- if (!ref.GetProperty().ComputedValuesEqual(*parent_computed_style,
- *state.ParentStyle())) {
+ if (parent_computed_style->GetWritingMode() !=
+ state.ParentStyle()->GetWritingMode()) {
+ return false;
+ }
+ if (parent_computed_style->Direction() != state.ParentStyle()->Direction())
+ return false;
+ if (computed_style->HasVariableReferenceFromNonInheritedProperty()) {
+ if (parent_computed_style->InheritedVariables() !=
+ state.ParentStyle()->InheritedVariables()) {
return false;
}
}
@@ -174,8 +156,7 @@ bool CachedMatchedProperties::operator!=(
void MatchedPropertiesCache::Add(const Key& key,
const ComputedStyle& style,
- const ComputedStyle& parent_style,
- const HashSet<CSSPropertyName>& dependencies) {
+ const ComputedStyle& parent_style) {
DCHECK(key.IsValid());
Cache::AddResult add_result = cache_.insert(key.hash_, nullptr);
if (add_result.is_new_entry || !add_result.stored_value->value) {
@@ -187,8 +168,7 @@ void MatchedPropertiesCache::Add(const Key& key,
if (!add_result.is_new_entry)
cache_item->Clear();
- cache_item->Set(style, parent_style, key.result_.GetMatchedProperties(),
- dependencies);
+ cache_item->Set(style, parent_style, key.result_.GetMatchedProperties());
}
void MatchedPropertiesCache::Clear() {
@@ -222,18 +202,6 @@ bool MatchedPropertiesCache::IsStyleCacheable(const ComputedStyle& style) {
return false;
if (style.TextAutosizingMultiplier() != 1)
return false;
- if (!RuntimeEnabledFeatures::CSSMatchedPropertiesCacheDependenciesEnabled()) {
- if (style.GetWritingMode() !=
- ComputedStyleInitialValues::InitialWritingMode() ||
- style.Direction() != ComputedStyleInitialValues::InitialDirection()) {
- return false;
- }
-
- // styles with non inherited properties that reference variables are not
- // cacheable.
- if (style.HasVariableReferenceFromNonInheritedProperty())
- return false;
- }
// -internal-light-dark() values in UA sheets have different computed values
// based on the used value of color-scheme.
if (style.HasNonInheritedLightDarkValue())
@@ -248,16 +216,13 @@ bool MatchedPropertiesCache::IsCacheable(const StyleResolverState& state) {
if (!IsStyleCacheable(style))
return false;
- if (!RuntimeEnabledFeatures::CSSMatchedPropertiesCacheDependenciesEnabled()) {
- // The cache assumes static knowledge about which properties are inherited.
- // Without a flat tree parent, StyleBuilder::ApplyProperty will not
- // SetChildHasExplicitInheritance on the parent style.
- if (!state.ParentNode() || parent_style.ChildHasExplicitInheritance())
- return false;
- return true;
- }
+ // The cache assumes static knowledge about which properties are inherited.
+ // Without a flat tree parent, StyleBuilder::ApplyProperty will not
+ // SetChildHasExplicitInheritance on the parent style.
+ if (!state.ParentNode() || parent_style.ChildHasExplicitInheritance())
+ return false;
- return state.HasValidDependencies() && !state.HasIncomparableDependency();
+ return true;
}
void MatchedPropertiesCache::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
index 68176e8ab15..c7456bff006 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
@@ -48,21 +48,11 @@ class CORE_EXPORT CachedMatchedProperties final
scoped_refptr<ComputedStyle> computed_style;
scoped_refptr<ComputedStyle> parent_computed_style;
- // g_null_atom-terminated array of property names.
- //
- // Note that this stores AtomicString for both standard and custom
- // properties, for memory saving purposes. (CSSPropertyName is twice as
- // big).
- std::unique_ptr<AtomicString[]> dependencies;
-
void Set(const ComputedStyle&,
const ComputedStyle& parent_style,
- const MatchedPropertiesVector&,
- const HashSet<CSSPropertyName>& new_dependencies);
+ const MatchedPropertiesVector&);
void Clear();
- // True if the computed value for each dependency is equal for the
- // cached parent style vs. the incoming parent style.
bool DependenciesEqual(const StyleResolverState&);
void Trace(Visitor*) const {}
@@ -104,10 +94,7 @@ class CORE_EXPORT MatchedPropertiesCache {
};
const CachedMatchedProperties* Find(const Key&, const StyleResolverState&);
- void Add(const Key&,
- const ComputedStyle&,
- const ComputedStyle& parent_style,
- const HashSet<CSSPropertyName>& dependencies);
+ void Add(const Key&, const ComputedStyle&, const ComputedStyle& parent_style);
void Clear();
void ClearViewportDependent();
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
index b12c3c3e2ca..0803cfc3730 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -58,14 +57,8 @@ class MatchedPropertiesCacheTestCache {
void Add(const TestKey& key,
const ComputedStyle& style,
- const ComputedStyle& parent_style,
- const Vector<String>& dependencies = Vector<String>()) {
- HashSet<CSSPropertyName> set;
- for (String name_string : dependencies) {
- set.insert(
- *CSSPropertyName::From(document_.GetExecutionContext(), name_string));
- }
- cache_.Add(key.InnerKey(), style, parent_style, set);
+ const ComputedStyle& parent_style) {
+ cache_.Add(key.InnerKey(), style, parent_style);
}
const CachedMatchedProperties* Find(const TestKey& key,
@@ -84,97 +77,13 @@ class MatchedPropertiesCacheTestCache {
using TestCache = MatchedPropertiesCacheTestCache;
-class MatchedPropertiesCacheTest
- : public PageTestBase,
- private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
+class MatchedPropertiesCacheTest : public PageTestBase {
public:
- MatchedPropertiesCacheTest()
- : ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
-
scoped_refptr<ComputedStyle> CreateStyle() {
return StyleResolver::InitialStyleForElement(GetDocument());
}
};
-TEST_F(MatchedPropertiesCacheTest, ClearEntry) {
- MatchResult result;
- result.AddMatchedProperties(
- css_test_helpers::ParseDeclarationBlock("top:inherit"));
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- HashSet<CSSPropertyName> dependencies;
- dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
-
- auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
- entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
-
- EXPECT_TRUE(entry->computed_style);
- EXPECT_TRUE(entry->parent_computed_style);
- EXPECT_FALSE(entry->matched_properties.IsEmpty());
- EXPECT_FALSE(entry->matched_properties_types.IsEmpty());
- EXPECT_TRUE(entry->dependencies);
-
- entry->Clear();
-
- EXPECT_FALSE(entry->computed_style);
- EXPECT_FALSE(entry->parent_computed_style);
- EXPECT_TRUE(entry->matched_properties.IsEmpty());
- EXPECT_TRUE(entry->matched_properties_types.IsEmpty());
- EXPECT_FALSE(entry->dependencies);
-}
-
-TEST_F(MatchedPropertiesCacheTest, NoDependencies) {
- MatchResult result;
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- HashSet<CSSPropertyName> dependencies;
-
- auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
- entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
-
- EXPECT_FALSE(entry->dependencies);
-}
-
-TEST_F(MatchedPropertiesCacheTest, OneDependency) {
- MatchResult result;
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- HashSet<CSSPropertyName> dependencies;
- dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
-
- auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
- entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
-
- ASSERT_TRUE(entry->dependencies);
- EXPECT_EQ("top", entry->dependencies[0]);
- EXPECT_EQ(g_null_atom, entry->dependencies[1]);
-}
-
-TEST_F(MatchedPropertiesCacheTest, TwoDependencies) {
- MatchResult result;
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- HashSet<CSSPropertyName> dependencies;
- dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
- dependencies.insert(CSSPropertyName(CSSPropertyID::kLeft));
-
- auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
- entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
-
- ASSERT_TRUE(entry->dependencies);
- EXPECT_TRUE(entry->dependencies[0] == "top" ||
- entry->dependencies[0] == "left");
- EXPECT_TRUE(entry->dependencies[1] == "top" ||
- entry->dependencies[1] == "left");
- EXPECT_NE(entry->dependencies[0], entry->dependencies[1]);
- EXPECT_TRUE(entry->dependencies[2] == g_null_atom);
-}
-
TEST_F(MatchedPropertiesCacheTest, AllowedKeyValues) {
unsigned empty = HashTraits<unsigned>::EmptyValue();
unsigned deleted = std::numeric_limits<unsigned>::max();
@@ -231,306 +140,6 @@ TEST_F(MatchedPropertiesCacheTest, HitOnlyForAddedEntry) {
EXPECT_FALSE(cache.Find(key2, *style, *parent));
}
-TEST_F(MatchedPropertiesCacheTest, HitWithStandardDependency) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- TestKey key("top:inherit", 1, GetDocument());
-
- cache.Add(key, *style, *parent, Vector<String>{"top"});
- EXPECT_TRUE(cache.Find(key, *style, *parent));
-}
-
-TEST_F(MatchedPropertiesCacheTest, MissWithStandardDependency) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent1 = CreateStyle();
- parent1->SetTop(Length(1, Length::kFixed));
-
- auto parent2 = CreateStyle();
- parent2->SetTop(Length(2, Length::kFixed));
-
- TestKey key("top:inherit", 1, GetDocument());
- cache.Add(key, *style, *parent1, Vector<String>{"top"});
- EXPECT_TRUE(cache.Find(key, *style, *parent1));
- EXPECT_FALSE(cache.Find(key, *style, *parent2));
-}
-
-TEST_F(MatchedPropertiesCacheTest, HitWithCustomDependency) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent = CreateStyle();
- parent->SetVariableData("--x", CreateVariableData("1px"), true);
-
- TestKey key("top:var(--x)", 1, GetDocument());
-
- cache.Add(key, *style, *parent, Vector<String>{"--x"});
- EXPECT_TRUE(cache.Find(key, *style, *parent));
-}
-
-TEST_F(MatchedPropertiesCacheTest, MissWithCustomDependency) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent1 = CreateStyle();
- parent1->SetVariableData("--x", CreateVariableData("1px"), true);
-
- auto parent2 = CreateStyle();
- parent2->SetVariableData("--x", CreateVariableData("2px"), true);
-
- TestKey key("top:var(--x)", 1, GetDocument());
-
- cache.Add(key, *style, *parent1, Vector<String>{"--x"});
- EXPECT_FALSE(cache.Find(key, *style, *parent2));
-}
-
-TEST_F(MatchedPropertiesCacheTest, HitWithMultipleCustomDependencies) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent1 = CreateStyle();
- parent1->SetVariableData("--x", CreateVariableData("1px"), true);
- parent1->SetVariableData("--y", CreateVariableData("2px"), true);
- parent1->SetVariableData("--z", CreateVariableData("3px"), true);
-
- auto parent2 = ComputedStyle::Clone(*parent1);
- parent2->SetVariableData("--z", CreateVariableData("4px"), true);
-
- TestKey key("top:var(--x);left:var(--y)", 1, GetDocument());
-
- // Does not depend on --z, so doesn't matter that --z changed.
- cache.Add(key, *style, *parent1, Vector<String>{"--x", "--y"});
- EXPECT_TRUE(cache.Find(key, *style, *parent2));
-}
-
-TEST_F(MatchedPropertiesCacheTest, MissWithMultipleCustomDependencies) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent1 = CreateStyle();
- parent1->SetVariableData("--x", CreateVariableData("1px"), true);
- parent1->SetVariableData("--y", CreateVariableData("2px"), true);
-
- auto parent2 = ComputedStyle::Clone(*parent1);
- parent2->SetVariableData("--y", CreateVariableData("3px"), true);
-
- TestKey key("top:var(--x);left:var(--y)", 1, GetDocument());
-
- cache.Add(key, *style, *parent1, Vector<String>{"--x", "--y"});
- EXPECT_FALSE(cache.Find(key, *style, *parent2));
-}
-
-TEST_F(MatchedPropertiesCacheTest, HitWithMixedDependencies) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
-
- auto parent1 = CreateStyle();
- parent1->SetVariableData("--x", CreateVariableData("1px"), true);
- parent1->SetVariableData("--y", CreateVariableData("2px"), true);
- parent1->SetLeft(Length(3, Length::kFixed));
- parent1->SetRight(Length(4, Length::kFixed));
-
- auto parent2 = ComputedStyle::Clone(*parent1);
- parent2->SetVariableData("--y", CreateVariableData("5px"), true);
- parent2->SetRight(Length(6, Length::kFixed));
-
- TestKey key("left:inherit;top:var(--x)", 1, GetDocument());
-
- cache.Add(key, *style, *parent1, Vector<String>{"left", "--x"});
- EXPECT_TRUE(cache.Find(key, *style, *parent2));
-}
-
-TEST_F(MatchedPropertiesCacheTest, ExplicitlyInheritedCacheable) {
- ASSERT_TRUE(GetCSSPropertyVerticalAlign().IsComputedValueComparable());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- parent->SetChildHasExplicitInheritance();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
- // Simulate explicit inheritance on vertical-align.
- state.MarkDependency(GetCSSPropertyVerticalAlign());
-
- EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, NotCacheableWithIncomparableDependency) {
- const CSSProperty& incomparable = GetCSSPropertyInternalEmptyLineHeight();
- ASSERT_FALSE(incomparable.IsComputedValueComparable());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- parent->SetChildHasExplicitInheritance();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
- // Simulate explicit inheritance on the incomparable property.
- state.MarkDependency(incomparable);
-
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, WritingModeCacheable) {
- ASSERT_NE(WritingMode::kVerticalRl,
- ComputedStyleInitialValues::InitialWritingMode());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- style->SetWritingMode(WritingMode::kVerticalRl);
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, DirectionCacheable) {
- ASSERT_NE(TextDirection::kRtl,
- ComputedStyleInitialValues::InitialDirection());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- style->SetDirection(TextDirection::kRtl);
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, VarInNonInheritedPropertyCachable) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- // Simulate non-inherited-property: var(--my-prop)
- style->SetHasVariableReferenceFromNonInheritedProperty();
-
- auto parent = CreateStyle();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, MaxDependencies) {
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
- for (size_t i = 0; i < StyleResolverState::kMaxDependencies; i++) {
- CustomProperty property(AtomicString(String::Format("--x%zu", i)),
- GetDocument());
- state.MarkDependency(property);
- EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
- }
- CustomProperty property("--y", GetDocument());
- state.MarkDependency(property);
- // Limit exceeded.
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest,
- ExplicitlyInheritedNotCacheableWithoutFeature) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- parent->SetChildHasExplicitInheritance();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest,
- VarInNonInheritedPropertyNotCachableWithoutFeature) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- // Simulate non-inherited-property: var(--my-prop)
- style->SetHasVariableReferenceFromNonInheritedProperty();
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, WritingModeNotCacheableWithoutFeature) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
-
- ASSERT_NE(WritingMode::kVerticalRl,
- ComputedStyleInitialValues::InitialWritingMode());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- style->SetWritingMode(WritingMode::kVerticalRl);
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
-TEST_F(MatchedPropertiesCacheTest, DirectionNotCacheableWithoutFeature) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
-
- ASSERT_NE(TextDirection::kRtl,
- ComputedStyleInitialValues::InitialDirection());
-
- TestCache cache(GetDocument());
-
- auto style = CreateStyle();
- auto parent = CreateStyle();
- style->SetDirection(TextDirection::kRtl);
-
- StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
- parent.get());
- state.SetStyle(style);
-
- EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
-}
-
TEST_F(MatchedPropertiesCacheTest, EnsuredInDisplayNone) {
TestCache cache(GetDocument());
@@ -588,4 +197,99 @@ TEST_F(MatchedPropertiesCacheTest, EnsuredOutsideFlatTreeAndDisplayNone) {
EXPECT_TRUE(cache.Find(key1, *style, *parent_none));
}
+TEST_F(MatchedPropertiesCacheTest, WritingModeDependency) {
+ TestCache cache(GetDocument());
+
+ auto parent_a = CreateStyle();
+ auto parent_b = CreateStyle();
+ auto style_a = CreateStyle();
+ auto style_b = CreateStyle();
+ parent_a->SetWritingMode(WritingMode::kHorizontalTb);
+ parent_b->SetWritingMode(WritingMode::kVerticalRl);
+
+ TestKey key("display:block", 1, GetDocument());
+
+ cache.Add(key, *style_a, *parent_a);
+ EXPECT_TRUE(cache.Find(key, *style_a, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_a));
+ EXPECT_FALSE(cache.Find(key, *style_b, *parent_b));
+}
+
+TEST_F(MatchedPropertiesCacheTest, DirectionDependency) {
+ TestCache cache(GetDocument());
+
+ auto parent_a = CreateStyle();
+ auto parent_b = CreateStyle();
+ auto style_a = CreateStyle();
+ auto style_b = CreateStyle();
+ parent_a->SetDirection(TextDirection::kLtr);
+ parent_b->SetDirection(TextDirection::kRtl);
+
+ TestKey key("display:block", 1, GetDocument());
+
+ cache.Add(key, *style_a, *parent_a);
+ EXPECT_TRUE(cache.Find(key, *style_a, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_a));
+ EXPECT_FALSE(cache.Find(key, *style_b, *parent_b));
+}
+
+TEST_F(MatchedPropertiesCacheTest, VariableDependency) {
+ TestCache cache(GetDocument());
+
+ auto parent_a = CreateStyle();
+ auto parent_b = CreateStyle();
+ auto style_a = CreateStyle();
+ auto style_b = CreateStyle();
+ parent_a->SetVariableData("--x", CreateVariableData("1px"), true);
+ parent_b->SetVariableData("--x", CreateVariableData("2px"), true);
+ style_a->SetHasVariableReferenceFromNonInheritedProperty();
+ style_b->SetHasVariableReferenceFromNonInheritedProperty();
+
+ TestKey key("top:var(--x)", 1, GetDocument());
+
+ cache.Add(key, *style_a, *parent_a);
+ EXPECT_TRUE(cache.Find(key, *style_a, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_a));
+ EXPECT_FALSE(cache.Find(key, *style_b, *parent_b));
+}
+
+TEST_F(MatchedPropertiesCacheTest, VariableDependencyNoVars) {
+ TestCache cache(GetDocument());
+
+ auto parent_a = CreateStyle();
+ auto parent_b = CreateStyle();
+ auto style_a = CreateStyle();
+ auto style_b = CreateStyle();
+ style_a->SetHasVariableReferenceFromNonInheritedProperty();
+ style_b->SetHasVariableReferenceFromNonInheritedProperty();
+
+ TestKey key("top:var(--x)", 1, GetDocument());
+
+ cache.Add(key, *style_a, *parent_a);
+ // parent_a/b both have no variables, so this should be a cache hit.
+ EXPECT_TRUE(cache.Find(key, *style_a, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_b));
+}
+
+TEST_F(MatchedPropertiesCacheTest, NoVariableDependency) {
+ TestCache cache(GetDocument());
+
+ auto parent_a = CreateStyle();
+ auto parent_b = CreateStyle();
+ auto style_a = CreateStyle();
+ auto style_b = CreateStyle();
+ parent_a->SetVariableData("--x", CreateVariableData("1px"), true);
+ parent_b->SetVariableData("--x", CreateVariableData("2px"), true);
+
+ TestKey key("top:var(--x)", 1, GetDocument());
+
+ cache.Add(key, *style_a, *parent_a);
+ // parent_a/b both have variables, but style_a/b is not marked as
+ // depending on them.
+ EXPECT_TRUE(cache.Find(key, *style_a, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_a));
+ EXPECT_TRUE(cache.Find(key, *style_b, *parent_b));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
index a06274fcab1..c1bbef07aa0 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/font_face.h"
@@ -58,15 +59,18 @@ ScopedStyleResolver* ScopedStyleResolver::Parent() const {
}
void ScopedStyleResolver::AddKeyframeRules(const RuleSet& rule_set) {
- if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled())
- return;
-
const HeapVector<Member<StyleRuleKeyframes>> keyframes_rules =
rule_set.KeyframesRules();
for (auto rule : keyframes_rules)
AddKeyframeStyle(rule);
}
+CounterStyleMap& ScopedStyleResolver::EnsureCounterStyleMap() {
+ if (!counter_style_map_)
+ counter_style_map_ = CounterStyleMap::CreateAuthorCounterStyleMap(*scope_);
+ return *counter_style_map_;
+}
+
void ScopedStyleResolver::AddFontFaceRules(const RuleSet& rule_set) {
// FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for
// the moment.
@@ -86,6 +90,19 @@ void ScopedStyleResolver::AddFontFaceRules(const RuleSet& rule_set) {
document.GetStyleResolver().InvalidateMatchedPropertiesCache();
}
+void ScopedStyleResolver::AddCounterStyleRules(const RuleSet& rule_set) {
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleInShadowDOMEnabled()) {
+ // Our support of @counter-style rules in shadow DOM is experimental and
+ // non-standard. See https://github.com/w3c/csswg-drafts/issues/5693
+ if (!GetTreeScope().RootNode().IsDocumentNode())
+ return;
+ }
+
+ if (rule_set.CounterStyleRules().IsEmpty())
+ return;
+ EnsureCounterStyleMap().AddCounterStyles(rule_set);
+}
+
void ScopedStyleResolver::AppendActiveStyleSheets(
unsigned index,
const ActiveStyleSheetVector& active_sheets) {
@@ -99,10 +116,10 @@ void ScopedStyleResolver::AppendActiveStyleSheets(
if (!active_iterator->second)
continue;
const RuleSet& rule_set = *active_iterator->second;
- author_style_sheets_.push_back(sheet);
+ style_sheets_.push_back(sheet);
AddKeyframeRules(rule_set);
AddFontFaceRules(rule_set);
- AddTreeBoundaryCrossingRules(rule_set, sheet, index);
+ AddCounterStyleRules(rule_set);
AddSlottedRules(rule_set, sheet, index++);
}
}
@@ -116,7 +133,7 @@ void ScopedStyleResolver::CollectFeaturesTo(
features.DeviceDependentMediaQueryResults().AppendVector(
device_dependent_media_query_results_);
- for (auto sheet : author_style_sheets_) {
+ for (auto sheet : style_sheets_) {
DCHECK(sheet->ownerNode() || sheet->IsConstructed());
StyleSheetContents* contents = sheet->Contents();
if (contents->HasOneClient() ||
@@ -124,63 +141,25 @@ void ScopedStyleResolver::CollectFeaturesTo(
features.Add(contents->GetRuleSet().Features());
}
- if (tree_boundary_crossing_rule_set_) {
- for (const auto& rules : *tree_boundary_crossing_rule_set_)
- features.Add(rules->rule_set_->Features());
- }
if (slotted_rule_set_) {
for (const auto& rules : *slotted_rule_set_)
features.Add(rules->rule_set_->Features());
}
}
-void ScopedStyleResolver::ResetAuthorStyle() {
- author_style_sheets_.clear();
+void ScopedStyleResolver::ResetStyle() {
+ style_sheets_.clear();
viewport_dependent_media_query_results_.clear();
device_dependent_media_query_results_.clear();
keyframes_rule_map_.clear();
- tree_boundary_crossing_rule_set_ = nullptr;
+ if (counter_style_map_)
+ counter_style_map_->Dispose();
slotted_rule_set_ = nullptr;
- has_deep_or_shadow_selector_ = false;
needs_append_all_sheets_ = false;
}
-const ActiveStyleSheetVector& ScopedStyleResolver::ActiveAuthorStyleSheets() {
- StyleSheetCollection* collection =
- GetTreeScope().GetDocument().GetStyleEngine().StyleSheetCollectionFor(
- *scope_);
- DCHECK(collection);
- return collection->ActiveAuthorStyleSheets();
-}
-
-// static
-StyleRuleKeyframes*
-ScopedStyleResolver::KeyframeStylesForAnimationFromActiveSheets(
- const AtomicString& name,
- const ActiveStyleSheetVector& sheets) {
- // We prefer non-vendor-prefixed over vendor-prefixed rules.
- StyleRuleKeyframes* vendor_prefixed_result = nullptr;
- for (auto sheet = sheets.rbegin(); sheet != sheets.rend(); ++sheet) {
- RuleSet* rule_set = sheet->second;
- if (!rule_set)
- continue;
- if (StyleRuleKeyframes* rule = rule_set->KeyframeStylesForAnimation(name)) {
- if (!rule->IsVendorPrefixed())
- return rule;
- if (!vendor_prefixed_result)
- vendor_prefixed_result = rule;
- }
- }
- return vendor_prefixed_result;
-}
-
StyleRuleKeyframes* ScopedStyleResolver::KeyframeStylesForAnimation(
const AtomicString& animation_name) {
- if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled()) {
- return KeyframeStylesForAnimationFromActiveSheets(
- animation_name, ActiveAuthorStyleSheets());
- }
-
if (keyframes_rule_map_.IsEmpty())
return nullptr;
@@ -192,7 +171,6 @@ StyleRuleKeyframes* ScopedStyleResolver::KeyframeStylesForAnimation(
}
void ScopedStyleResolver::AddKeyframeStyle(StyleRuleKeyframes* rule) {
- DCHECK(!RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled());
AtomicString name = rule->GetName();
if (rule->IsVendorPrefixed()) {
@@ -254,170 +232,89 @@ void ScopedStyleResolver::KeyframesRulesAdded(const TreeScope& tree_scope) {
tree_scope.GetDocument().Timeline().InvalidateKeyframeEffects(tree_scope);
}
-void ScopedStyleResolver::CollectMatchingAuthorRules(
- ElementRuleCollector& collector,
- ShadowV0CascadeOrder cascade_order) {
+void ScopedStyleResolver::CollectMatchingElementScopeRules(
+ ElementRuleCollector& collector) {
wtf_size_t sheet_index = 0;
- for (auto sheet : author_style_sheets_) {
+ for (auto sheet : style_sheets_) {
DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
- collector.CollectMatchingRules(match_request, cascade_order);
+ collector.CollectMatchingRules(match_request);
}
}
void ScopedStyleResolver::CollectMatchingShadowHostRules(
- ElementRuleCollector& collector,
- ShadowV0CascadeOrder cascade_order) {
+ ElementRuleCollector& collector) {
wtf_size_t sheet_index = 0;
- for (auto sheet : author_style_sheets_) {
+ for (auto sheet : style_sheets_) {
DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
- collector.CollectMatchingShadowHostRules(match_request, cascade_order);
+ collector.CollectMatchingShadowHostRules(match_request);
}
}
void ScopedStyleResolver::CollectMatchingSlottedRules(
- ElementRuleCollector& collector,
- ShadowV0CascadeOrder cascade_order) {
+ ElementRuleCollector& collector) {
if (!slotted_rule_set_)
return;
for (const auto& rules : *slotted_rule_set_) {
MatchRequest request(rules->rule_set_.Get(), &GetTreeScope().RootNode(),
rules->parent_style_sheet_, rules->parent_index_);
- collector.CollectMatchingRules(request, cascade_order, true);
- }
-}
-
-void ScopedStyleResolver::CollectMatchingTreeBoundaryCrossingRules(
- ElementRuleCollector& collector,
- ShadowV0CascadeOrder cascade_order) {
- if (!tree_boundary_crossing_rule_set_)
- return;
-
- for (const auto& rules : *tree_boundary_crossing_rule_set_) {
- MatchRequest request(rules->rule_set_.Get(), &GetTreeScope().RootNode(),
- rules->parent_style_sheet_, rules->parent_index_);
- collector.CollectMatchingRules(request, cascade_order, true);
+ collector.CollectMatchingRules(request, true);
}
}
void ScopedStyleResolver::CollectMatchingPartPseudoRules(
ElementRuleCollector& collector,
PartNames& part_names,
- ShadowV0CascadeOrder cascade_order) {
+ bool for_shadow_pseudo) {
wtf_size_t sheet_index = 0;
- for (auto sheet : author_style_sheets_) {
+ for (auto sheet : style_sheets_) {
DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++);
collector.CollectMatchingPartPseudoRules(match_request, part_names,
- cascade_order);
+ for_shadow_pseudo);
}
}
void ScopedStyleResolver::MatchPageRules(PageRuleCollector& collector) {
- // Only consider the global author RuleSet for @page rules, as per the HTML5
- // spec.
+ // Currently, only @page rules in the document scope apply.
DCHECK(scope_->RootNode().IsDocumentNode());
- for (auto sheet : author_style_sheets_)
+ for (auto sheet : style_sheets_)
collector.MatchPageRules(&sheet->Contents()->GetRuleSet());
}
void ScopedStyleResolver::Trace(Visitor* visitor) const {
visitor->Trace(scope_);
- visitor->Trace(author_style_sheets_);
+ visitor->Trace(style_sheets_);
visitor->Trace(keyframes_rule_map_);
- visitor->Trace(tree_boundary_crossing_rule_set_);
+ visitor->Trace(counter_style_map_);
visitor->Trace(slotted_rule_set_);
}
static void AddRules(RuleSet* rule_set,
const HeapVector<MinimalRuleData>& rules) {
- for (const auto& info : rules)
- rule_set->AddRule(info.rule_, info.selector_index_, info.flags_);
-}
-
-void ScopedStyleResolver::AddTreeBoundaryCrossingRules(
- const RuleSet& author_rules,
- CSSStyleSheet* parent_style_sheet,
- unsigned sheet_index) {
- bool is_document_scope = GetTreeScope().RootNode().IsDocumentNode();
- if (author_rules.DeepCombinatorOrShadowPseudoRules().IsEmpty() &&
- (is_document_scope ||
- (author_rules.ContentPseudoElementRules().IsEmpty())))
- return;
-
- if (!author_rules.DeepCombinatorOrShadowPseudoRules().IsEmpty())
- has_deep_or_shadow_selector_ = true;
-
- auto* rule_set_for_scope = MakeGarbageCollected<RuleSet>();
- AddRules(rule_set_for_scope,
- author_rules.DeepCombinatorOrShadowPseudoRules());
-
- if (!is_document_scope)
- AddRules(rule_set_for_scope, author_rules.ContentPseudoElementRules());
-
- if (!tree_boundary_crossing_rule_set_) {
- tree_boundary_crossing_rule_set_ =
- MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
- GetTreeScope().GetDocument().GetStyleEngine().AddTreeBoundaryCrossingScope(
- GetTreeScope());
- }
-
- tree_boundary_crossing_rule_set_->push_back(MakeGarbageCollected<RuleSubSet>(
- parent_style_sheet, sheet_index, rule_set_for_scope));
-}
-
-void ScopedStyleResolver::V0ShadowAddedOnV1Document() {
- // See the comment in AddSlottedRules().
- if (!slotted_rule_set_)
- return;
-
- if (!tree_boundary_crossing_rule_set_) {
- tree_boundary_crossing_rule_set_ =
- MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
- GetTreeScope().GetDocument().GetStyleEngine().AddTreeBoundaryCrossingScope(
- GetTreeScope());
+ for (const auto& info : rules) {
+ // TODO(crbug.com/1145970): Store container_query on MinimalRuleData
+ // and propagate it here.
+ rule_set->AddRule(info.rule_, info.selector_index_, info.flags_,
+ nullptr /* container_query */);
}
- tree_boundary_crossing_rule_set_->AppendVector(*slotted_rule_set_);
- slotted_rule_set_ = nullptr;
}
-void ScopedStyleResolver::AddSlottedRules(const RuleSet& author_rules,
+void ScopedStyleResolver::AddSlottedRules(const RuleSet& rules,
CSSStyleSheet* parent_style_sheet,
unsigned sheet_index) {
bool is_document_scope = GetTreeScope().RootNode().IsDocumentNode();
- if (is_document_scope || author_rules.SlottedPseudoElementRules().IsEmpty())
+ if (is_document_scope || rules.SlottedPseudoElementRules().IsEmpty())
return;
auto* slotted_rule_set = MakeGarbageCollected<RuleSet>();
- AddRules(slotted_rule_set, author_rules.SlottedPseudoElementRules());
-
- // In case ::slotted rule is used in V0/V1 mixed document, put ::slotted
- // rules in tree boundary crossing rules as the pure v1 fast path in
- // StyleResolver misses them.
- // Adding this tree scope to tree boundary crossing scopes may end up in
- // O(N^2) where N is number of scopes which has ::slotted() rules.
- // Once the document-wide cascade order flag downgrades from V1 to V0,
- // these slotted rules have to be moved back to tree boundary crossing
- // rule sets. See V0ShadowAddedOnV1Document().
- if (GetTreeScope().GetDocument().MayContainV0Shadow()) {
- if (!tree_boundary_crossing_rule_set_) {
- tree_boundary_crossing_rule_set_ =
- MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
- GetTreeScope()
- .GetDocument()
- .GetStyleEngine()
- .AddTreeBoundaryCrossingScope(GetTreeScope());
- }
- tree_boundary_crossing_rule_set_->push_back(
- MakeGarbageCollected<RuleSubSet>(parent_style_sheet, sheet_index,
- slotted_rule_set));
- return;
- }
+ AddRules(slotted_rule_set, rules.SlottedPseudoElementRules());
+
if (!slotted_rule_set_)
slotted_rule_set_ = MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
slotted_rule_set_->push_back(MakeGarbageCollected<RuleSubSet>(
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
index 9460d748ff4..c60f4c637dc 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
@@ -38,14 +38,15 @@
namespace blink {
+class CounterStyleMap;
class PageRuleCollector;
class PartNames;
class StyleSheetContents;
// ScopedStyleResolver collects the style sheets that occur within a TreeScope
// and provides methods to collect the rules that apply to a given element,
-// broken down by what kind of scope they apply to (e.g. shadow host,
-// tree-boundary-crossing, etc).
+// broken down by what kind of scope they apply to (e.g. shadow host, slotted,
+// etc).
class CORE_EXPORT ScopedStyleResolver final
: public GarbageCollected<ScopedStyleResolver> {
public:
@@ -56,33 +57,24 @@ class CORE_EXPORT ScopedStyleResolver final
const TreeScope& GetTreeScope() const { return *scope_; }
ScopedStyleResolver* Parent() const;
- static StyleRuleKeyframes* KeyframeStylesForAnimationFromActiveSheets(
- const AtomicString& name,
- const ActiveStyleSheetVector& sheets);
StyleRuleKeyframes* KeyframeStylesForAnimation(
const AtomicString& animation_name);
+ CounterStyleMap* GetCounterStyleMap() { return counter_style_map_; }
+ static void CounterStyleRulesChanged(TreeScope& scope);
+
void AppendActiveStyleSheets(unsigned index, const ActiveStyleSheetVector&);
- void CollectMatchingAuthorRules(ElementRuleCollector&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
- void CollectMatchingShadowHostRules(
- ElementRuleCollector&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
- void CollectMatchingSlottedRules(ElementRuleCollector&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
- void CollectMatchingTreeBoundaryCrossingRules(
- ElementRuleCollector&,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
- void CollectMatchingPartPseudoRules(
- ElementRuleCollector&,
- PartNames& part_names,
- ShadowV0CascadeOrder = kIgnoreCascadeOrder);
+ void CollectMatchingElementScopeRules(ElementRuleCollector&);
+ void CollectMatchingShadowHostRules(ElementRuleCollector&);
+ void CollectMatchingSlottedRules(ElementRuleCollector&);
+ void CollectMatchingPartPseudoRules(ElementRuleCollector&,
+ PartNames& part_names,
+ bool for_shadow_pseudo);
void MatchPageRules(PageRuleCollector&);
void CollectFeaturesTo(RuleFeatureSet&,
HeapHashSet<Member<const StyleSheetContents>>&
visited_shared_style_sheet_contents) const;
- void ResetAuthorStyle();
- bool HasDeepOrShadowSelector() const { return has_deep_or_shadow_selector_; }
+ void ResetStyle();
void SetHasUnresolvedKeyframesRule() {
has_unresolved_keyframes_rule_ = true;
}
@@ -90,24 +82,21 @@ class CORE_EXPORT ScopedStyleResolver final
void SetNeedsAppendAllSheets() { needs_append_all_sheets_ = true; }
static void KeyframesRulesAdded(const TreeScope&);
static Element& InvalidationRootForTreeScope(const TreeScope&);
- void V0ShadowAddedOnV1Document();
void Trace(Visitor*) const;
private:
- void AddTreeBoundaryCrossingRules(const RuleSet&,
- CSSStyleSheet*,
- unsigned sheet_index);
void AddSlottedRules(const RuleSet&, CSSStyleSheet*, unsigned sheet_index);
- void AddKeyframeRules(const RuleSet&);
void AddFontFaceRules(const RuleSet&);
+ void AddCounterStyleRules(const RuleSet&);
+ void AddKeyframeRules(const RuleSet&);
void AddKeyframeStyle(StyleRuleKeyframes*);
- const ActiveStyleSheetVector& ActiveAuthorStyleSheets();
+ CounterStyleMap& EnsureCounterStyleMap();
Member<TreeScope> scope_;
- HeapVector<Member<CSSStyleSheet>> author_style_sheets_;
+ HeapVector<Member<CSSStyleSheet>> style_sheets_;
MediaQueryResultList viewport_dependent_media_query_results_;
MediaQueryResultList device_dependent_media_query_results_;
@@ -115,6 +104,8 @@ class CORE_EXPORT ScopedStyleResolver final
HeapHashMap<AtomicString, Member<StyleRuleKeyframes>>;
KeyframesRuleMap keyframes_rule_map_;
+ Member<CounterStyleMap> counter_style_map_;
+
class RuleSubSet final : public GarbageCollected<RuleSubSet> {
public:
RuleSubSet(CSSStyleSheet* sheet, unsigned index, RuleSet* rules)
@@ -128,10 +119,8 @@ class CORE_EXPORT ScopedStyleResolver final
};
using CSSStyleSheetRuleSubSet = HeapVector<Member<RuleSubSet>>;
- Member<CSSStyleSheetRuleSubSet> tree_boundary_crossing_rule_set_;
Member<CSSStyleSheetRuleSubSet> slotted_rule_set_;
- bool has_deep_or_shadow_selector_ = false;
bool has_unresolved_keyframes_rule_ = false;
bool needs_append_all_sheets_ = false;
};
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.cc b/chromium/third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.cc
index 7274982965d..30bd28f2a67 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.cc
@@ -3,20 +3,21 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
namespace blink {
SelectorFilterParentScope* SelectorFilterParentScope::current_scope_ = nullptr;
void SelectorFilterParentScope::PushAncestors(Element& element) {
- if (Element* ancestor = element.ParentOrShadowHostElement()) {
+ if (Element* ancestor = FlatTreeTraversal::ParentElement(element)) {
PushAncestors(*ancestor);
resolver_->GetSelectorFilter().PushParent(*ancestor);
}
}
void SelectorFilterParentScope::PopAncestors(Element& element) {
- if (Element* ancestor = element.ParentOrShadowHostElement()) {
+ if (Element* ancestor = FlatTreeTraversal::ParentElement(element)) {
resolver_->GetSelectorFilter().PopParent(*ancestor);
PopAncestors(*ancestor);
}
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index 36a524db6d9..62030873890 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -44,7 +44,6 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
@@ -264,7 +263,9 @@ static void AdjustStyleForMarker(ComputedStyle& style,
!parent_style.IsInsideListElement());
if (is_inside) {
- auto margins = ListMarker::InlineMarginsForInside(style, parent_style);
+ Document& document = parent_element.GetDocument();
+ auto margins =
+ ListMarker::InlineMarginsForInside(document, style, parent_style);
style.SetMarginStart(Length::Fixed(margins.first));
style.SetMarginEnd(Length::Fixed(margins.second));
} else {
@@ -394,7 +395,8 @@ static void AdjustStyleForHTMLElement(ComputedStyle& style,
return;
}
- if (IsA<HTMLSummaryElement>(element)) {
+ if (IsA<HTMLSummaryElement>(element) &&
+ !RuntimeEnabledFeatures::SummaryListItemEnabled()) {
// <summary> should be a list item by default, but currently it's a block
// and the disclosure symbol is not a ::marker (bug 590014). If an author
// specifies 'display: list-item', the <summary> would seem to have two
@@ -418,7 +420,7 @@ static void AdjustStyleForHTMLElement(ComputedStyle& style,
}
}
-void StyleAdjuster::AdjustOverflow(ComputedStyle& style) {
+void StyleAdjuster::AdjustOverflow(ComputedStyle& style, Element* element) {
DCHECK(style.OverflowX() != EOverflow::kVisible ||
style.OverflowY() != EOverflow::kVisible);
@@ -455,6 +457,11 @@ void StyleAdjuster::AdjustOverflow(ComputedStyle& style) {
else if (style.OverflowY() == EOverflow::kClip)
style.SetOverflowY(EOverflow::kHidden);
}
+ if (element && (style.OverflowX() == EOverflow::kClip ||
+ style.OverflowY() == EOverflow::kClip)) {
+ UseCounter::Count(element->GetDocument(),
+ WebFeature::kOverflowClipAlongEitherAxis);
+ }
}
static void AdjustStyleForDisplay(ComputedStyle& style,
@@ -636,6 +643,17 @@ static void AdjustStateForContentVisibility(ComputedStyle& style,
context->AdjustElementStyle(&style);
}
+void StyleAdjuster::AdjustForForcedColorsMode(ComputedStyle& style) {
+ if (!style.InForcedColorsMode() ||
+ style.ForcedColorAdjust() == EForcedColorAdjust::kNone)
+ return;
+
+ style.SetTextShadow(ComputedStyleInitialValues::InitialTextShadow());
+ style.SetBoxShadow(ComputedStyleInitialValues::InitialBoxShadow());
+ if (!style.HasUrlBackgroundImage())
+ style.ClearBackgroundImage();
+}
+
void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state,
Element* element) {
DCHECK(state.LayoutParentStyle());
@@ -688,20 +706,6 @@ void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state,
AdjustStyleForDisplay(style, layout_parent_style, element,
element ? &element->GetDocument() : nullptr);
- // TOOD(crbug.com/1146925): Sticky content in a scrollable FIELDSET triggers
- // a DHCECK failure in |StickyPositionScrollingConstraints::
- // AncestorContainingBlockOffset()|. We disable it until the root cause is
- // fixed.
- if (style.GetPosition() == EPosition::kSticky && element) {
- for (const Node& ancestor : FlatTreeTraversal::AncestorsOf(*element)) {
- if (const auto* fieldset = DynamicTo<HTMLFieldSetElement>(ancestor)) {
- if (!fieldset->ComputedStyleRef().IsOverflowVisibleAlongBothAxes())
- style.SetPosition(EPosition::kStatic);
- break;
- }
- }
- }
-
// If this is a child of a LayoutNGCustom, we need the name of the parent
// layout function for invalidation purposes.
if (layout_parent_style.IsDisplayLayoutCustomBox()) {
@@ -734,13 +738,14 @@ void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state,
if (style.OverflowX() != EOverflow::kVisible ||
style.OverflowY() != EOverflow::kVisible)
- AdjustOverflow(style);
+ AdjustOverflow(style, element);
// overflow-clip-margin only applies if 'overflow: clip' is set along both
- // axis.
- if (style.OverflowX() != EOverflow::kClip ||
- style.OverflowY() != EOverflow::kClip) {
- style.SetOverflowClipMargin(LayoutUnit());
+ // axis or 'contain: paint'.
+ if (!style.ContainsPaint() && !(style.OverflowX() == EOverflow::kClip &&
+ style.OverflowY() == EOverflow::kClip)) {
+ style.SetOverflowClipMargin(
+ ComputedStyleInitialValues::InitialOverflowClipMargin());
}
if (StopPropagateTextDecorations(style, element))
@@ -756,6 +761,10 @@ void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state,
style.AdjustBackgroundLayers();
style.AdjustMaskLayers();
+ // A subset of CSS properties should be forced at computed value time:
+ // https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties.
+ AdjustForForcedColorsMode(style);
+
// Let the theme also have a crack at adjusting the style.
LayoutTheme::GetTheme().AdjustStyle(element, style);
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.h b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.h
index e62d5818921..e32fe3682ed 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster.h
@@ -43,7 +43,8 @@ class StyleAdjuster {
static void AdjustStyleForEditing(ComputedStyle&);
private:
- static void AdjustOverflow(ComputedStyle& style);
+ static void AdjustOverflow(ComputedStyle& style, Element* element);
+ static void AdjustForForcedColorsMode(ComputedStyle& style);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster_test.cc
index 5af052be31d..b83eb724373 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_adjuster_test.cc
@@ -128,6 +128,7 @@ TEST_F(StyleAdjusterTest, AdjustOverflow) {
overflow-clip-margin: 1px;'>
<div id='vishidden' style='overflow-x: visible; overflow-y: hidden;
overflow-clip-margin: 1px;'>
+ <div id='containpaint' style='contain: paint; overflow-clip-margin: 1px;'>
</div>
)HTML");
UpdateAllLifecyclePhasesForTest();
@@ -173,6 +174,11 @@ TEST_F(StyleAdjusterTest, AdjustOverflow) {
EXPECT_EQ(EOverflow::kHidden, target->GetComputedStyle()->OverflowX());
EXPECT_EQ(EOverflow::kAuto, target->GetComputedStyle()->OverflowY());
EXPECT_EQ(LayoutUnit(), target->GetComputedStyle()->OverflowClipMargin());
+
+ target = GetDocument().getElementById("containpaint");
+ ASSERT_TRUE(target);
+ EXPECT_TRUE(target->GetComputedStyle()->ContainsPaint());
+ EXPECT_EQ(LayoutUnit(1), target->GetComputedStyle()->OverflowClipMargin());
}
TEST_F(StyleAdjusterTest, TouchActionContentEditableArea) {
@@ -249,4 +255,24 @@ TEST_F(StyleAdjusterTest, TouchActionNoPanXScrollsWhenNoPanX) {
target->GetComputedStyle()->GetEffectiveTouchAction());
}
+TEST_F(StyleAdjusterTest, OverflowClipUseCount) {
+ GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+ SetBodyInnerHTML(R"HTML(
+ <div></div>
+ <div style='overflow: hidden'></div>
+ <div style='overflow: scroll'></div>
+ <div></div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(
+ GetDocument().IsUseCounted(WebFeature::kOverflowClipAlongEitherAxis));
+
+ SetBodyInnerHTML(R"HTML(
+ <div style='overflow: clip'></div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(
+ GetDocument().IsUseCounted(WebFeature::kOverflowClipAlongEitherAxis));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_builder.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_builder.cc
index 39826113635..d0553b7cfcc 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_builder.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_builder.cc
@@ -90,7 +90,6 @@ void StyleBuilder::ApplyProperty(const CSSProperty& property,
DCHECK(!is_inherit || (state.ParentNode() && state.ParentStyle()));
if (is_inherit && !is_inherited) {
- state.MarkDependency(property);
state.Style()->SetHasExplicitInheritance();
state.ParentStyle()->SetChildHasExplicitInheritance();
} else if (value.IsUnsetValue()) {
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index b3749f040fa..764a237136c 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -114,24 +114,19 @@ scoped_refptr<StyleReflection> StyleBuilderConverter::ConvertBoxReflect(
return reflection;
}
-Color StyleBuilderConverter::ConvertColor(StyleResolverState& state,
- const CSSValue& value,
- bool for_visited_link) {
- return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
- value, state.Style()->GetCurrentColor(), state.Style()->UsedColorScheme(),
- for_visited_link);
-}
-
scoped_refptr<StyleSVGResource> StyleBuilderConverter::ConvertElementReference(
StyleResolverState& state,
const CSSValue& value) {
- const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value);
- if (!url_value)
+ if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
+ DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
return nullptr;
+ }
+
+ const auto& url_value = To<cssvalue::CSSURIValue>(value);
SVGResource* resource =
state.GetElementStyleResources().GetSVGResourceFromValue(
- state.GetElement().OriginatingTreeScope(), *url_value);
- return StyleSVGResource::Create(resource, url_value->ValueForSerialization());
+ CSSPropertyID::kInvalid, url_value);
+ return StyleSVGResource::Create(resource, url_value.ValueForSerialization());
}
LengthBox StyleBuilderConverter::ConvertClip(StyleResolverState& state,
@@ -153,7 +148,7 @@ scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
if (const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value)) {
SVGResource* resource =
state.GetElementStyleResources().GetSVGResourceFromValue(
- state.GetElement().OriginatingTreeScope(), *url_value);
+ CSSPropertyID::kClipPath, *url_value);
// TODO(fs): Doesn't work with external SVG references (crbug.com/109212.)
return ReferenceClipPathOperation::Create(
url_value->ValueForSerialization(), resource);
@@ -166,8 +161,10 @@ scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
FilterOperations StyleBuilderConverter::ConvertFilterOperations(
StyleResolverState& state,
- const CSSValue& value) {
- return FilterOperationResolver::CreateFilterOperations(state, value);
+ const CSSValue& value,
+ CSSPropertyID property_id) {
+ return FilterOperationResolver::CreateFilterOperations(state, value,
+ property_id);
}
FilterOperations StyleBuilderConverter::ConvertOffscreenFilterOperations(
@@ -379,12 +376,11 @@ static float ComputeFontSize(const CSSToLengthConversionData& conversion_data,
}
return result;
}
- if (primitive_value.IsCalculatedPercentageWithLength()) {
+ if (primitive_value.IsCalculated()) {
return To<CSSMathFunctionValue>(primitive_value)
.ToCalcValue(conversion_data)
->Evaluate(parent_size.value);
}
-
NOTREACHED();
return 0;
}
@@ -418,7 +414,9 @@ FontDescription::Size StyleBuilderConverterBase::ConvertFontSize(
// have revealed an existing bug with calculated lengths. Investigate.
const bool is_absolute =
parent_size.is_absolute || primitive_value.IsMathFunctionValue() ||
- !To<CSSNumericLiteralValue>(primitive_value).IsFontRelativeLength();
+ !To<CSSNumericLiteralValue>(primitive_value).IsFontRelativeLength() ||
+ To<CSSNumericLiteralValue>(primitive_value).GetType() ==
+ CSSPrimitiveValue::UnitType::kRems;
return FontDescription::Size(
0, ComputeFontSize(conversion_data, primitive_value, parent_size),
is_absolute);
@@ -1490,7 +1488,7 @@ scoped_refptr<SVGDashArray> StyleBuilderConverter::ConvertStrokeDasharray(
const CSSValue& value) {
const auto* dashes = DynamicTo<CSSValueList>(value);
if (!dashes)
- return SVGComputedStyle::InitialStrokeDashArray();
+ return EmptyDashArray();
scoped_refptr<SVGDashArray> array = base::MakeRefCounted<SVGDashArray>();
@@ -1560,7 +1558,8 @@ StyleAutoColor StyleBuilderConverter::ConvertStyleAutoColor(
}
SVGPaint StyleBuilderConverter::ConvertSVGPaint(StyleResolverState& state,
- const CSSValue& value) {
+ const CSSValue& value,
+ bool for_visited_link) {
const CSSValue* local_value = &value;
SVGPaint paint;
if (const auto* list = DynamicTo<CSSValueList>(value)) {
@@ -1579,6 +1578,7 @@ SVGPaint StyleBuilderConverter::ConvertSVGPaint(StyleResolverState& state,
paint.type =
!paint.resource ? SVG_PAINTTYPE_NONE : SVG_PAINTTYPE_URI_NONE;
} else {
+ // TODO(fs): Pass along |for_visited_link|.
paint.color = ConvertStyleColor(state, *local_value);
paint.type =
!paint.resource ? SVG_PAINTTYPE_COLOR : SVG_PAINTTYPE_URI_COLOR;
@@ -2039,7 +2039,7 @@ bool ListHasAuto(const CSSValueList& list) {
} // namespace
StyleAspectRatio StyleBuilderConverter::ConvertAspectRatio(
- StyleResolverState& state,
+ const StyleResolverState& state,
const CSSValue& value) {
auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
index 16347660cf6..ca48485e7a1 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -46,7 +46,6 @@
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/core/style/style_offset_rotation.h"
#include "third_party/blink/renderer/core/style/style_reflection.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
#include "third_party/blink/renderer/core/style/transform_origin.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/geometry/length_size.h"
@@ -99,9 +98,6 @@ class StyleBuilderConverter {
public:
static scoped_refptr<StyleReflection> ConvertBoxReflect(StyleResolverState&,
const CSSValue&);
- static Color ConvertColor(StyleResolverState&,
- const CSSValue&,
- bool for_visited_link = false);
template <typename T>
static T ConvertComputedLength(StyleResolverState&, const CSSValue&);
static LengthBox ConvertClip(StyleResolverState&, const CSSValue&);
@@ -111,7 +107,8 @@ class StyleBuilderConverter {
StyleResolverState&,
const CSSValue&);
static FilterOperations ConvertFilterOperations(StyleResolverState&,
- const CSSValue&);
+ const CSSValue&,
+ CSSPropertyID);
static FilterOperations ConvertOffscreenFilterOperations(const CSSValue&,
const Font&);
template <typename T>
@@ -204,7 +201,9 @@ class StyleBuilderConverter {
static StyleAutoColor ConvertStyleAutoColor(StyleResolverState&,
const CSSValue&,
bool for_visited_link = false);
- static SVGPaint ConvertSVGPaint(StyleResolverState&, const CSSValue&);
+ static SVGPaint ConvertSVGPaint(StyleResolverState&,
+ const CSSValue&,
+ bool for_visited_link);
static TextDecorationThickness ConvertTextDecorationThickness(
StyleResolverState&,
const CSSValue&);
@@ -279,7 +278,7 @@ class StyleBuilderConverter {
static LengthSize ConvertIntrinsicSize(StyleResolverState&, const CSSValue&);
- static StyleAspectRatio ConvertAspectRatio(StyleResolverState&,
+ static StyleAspectRatio ConvertAspectRatio(const StyleResolverState&,
const CSSValue&);
static bool ConvertInternalAlignSelfBlock(StyleResolverState& state,
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index 13ce88a0770..9dbf951f5ba 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -195,7 +195,6 @@ void StyleCascade::Apply(CascadeFilter filter) {
if (resolver.AuthorFlags() & CSSProperty::kBorder)
state_.Style()->SetHasAuthorBorder();
}
- ForceColors();
}
std::unique_ptr<CSSBitset> StyleCascade::GetImportantSet() {
@@ -287,8 +286,6 @@ void StyleCascade::AnalyzeMatchResult() {
map_.Add(property.GetCSSPropertyName(), e.Priority());
}
}
-
- MaybeUseCountSummaryDisplayBlock();
}
void StyleCascade::AnalyzeInterpolations() {
@@ -339,11 +336,6 @@ void StyleCascade::ApplyCascadeAffecting(CascadeResolver& resolver) {
LookupAndApply(GetCSSPropertyWritingMode(), resolver);
if (depends_on_cascade_affecting_property_) {
- // We could avoid marking these if this cascade provided a value, but
- // marking them unconditionally keeps it simple. See also note about
- // over-marking in StyleResolverState::Dependencies.
- MarkDependency(GetCSSPropertyDirection());
- MarkDependency(GetCSSPropertyWritingMode());
if (direction != state_.Style()->Direction() ||
writing_mode != state_.Style()->GetWritingMode()) {
Reanalyze();
@@ -359,7 +351,7 @@ void StyleCascade::ApplyHighPriority(CascadeResolver& resolver) {
int last = static_cast<int>(kLastHighPriorityCSSProperty);
for (int i = first; i <= last; ++i) {
if (bits & (static_cast<uint64_t>(1) << i))
- LookupAndApply(CSSProperty::Get(convertToCSSPropertyID(i)), resolver);
+ LookupAndApply(CSSProperty::Get(ConvertToCSSPropertyID(i)), resolver);
}
}
@@ -568,109 +560,6 @@ void StyleCascade::LookupAndApplyInterpolation(const CSSProperty& property,
ApplyInterpolation(property, priority, *entry->value, resolver);
}
-void StyleCascade::ForceColors() {
- ComputedStyle* style = state_.Style();
- if (!GetDocument().InForcedColorsMode() ||
- style->ForcedColorAdjust() == EForcedColorAdjust::kNone)
- return;
-
- int bg_color_alpha =
- style->VisitedDependentColor(GetCSSPropertyBackgroundColor()).Alpha();
- int visited_bg_color_alpha =
- style->ResolvedColor(style->InternalVisitedBackgroundColor()).Alpha();
- const SVGComputedStyle& svg_style = style->SvgStyle();
-
- MaybeForceColor(GetCSSPropertyColor(), style->GetColor());
- MaybeForceColor(GetCSSPropertyBackgroundColor(), style->BackgroundColor());
- MaybeForceColor(GetCSSPropertyBorderBottomColor(),
- style->BorderBottomColor());
- MaybeForceColor(GetCSSPropertyBorderLeftColor(), style->BorderLeftColor());
- MaybeForceColor(GetCSSPropertyBorderRightColor(), style->BorderRightColor());
- MaybeForceColor(GetCSSPropertyBorderTopColor(), style->BorderTopColor());
- MaybeForceColor(GetCSSPropertyFill(), svg_style.FillPaint().GetColor());
- MaybeForceColor(GetCSSPropertyOutlineColor(), style->OutlineColor());
- MaybeForceColor(GetCSSPropertyStroke(), svg_style.StrokePaint().GetColor());
- MaybeForceColor(GetCSSPropertyTextDecorationColor(),
- style->TextDecorationColor());
- MaybeForceColor(GetCSSPropertyColumnRuleColor(), style->ColumnRuleColor());
- MaybeForceColor(GetCSSPropertyWebkitTapHighlightColor(),
- style->TapHighlightColor());
- MaybeForceColor(GetCSSPropertyWebkitTextEmphasisColor(),
- style->TextEmphasisColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedColor(),
- style->InternalVisitedColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedBackgroundColor(),
- style->InternalVisitedBackgroundColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedBorderBottomColor(),
- style->InternalVisitedBorderBottomColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedBorderLeftColor(),
- style->InternalVisitedBorderLeftColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedBorderRightColor(),
- style->InternalVisitedBorderRightColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedBorderTopColor(),
- style->InternalVisitedBorderTopColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedFill(),
- svg_style.InternalVisitedFillPaint().GetColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedOutlineColor(),
- style->InternalVisitedOutlineColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedStroke(),
- svg_style.InternalVisitedStrokePaint().GetColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedTextDecorationColor(),
- style->InternalVisitedTextDecorationColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedColumnRuleColor(),
- style->InternalVisitedColumnRuleColor());
- MaybeForceColor(GetCSSPropertyInternalVisitedTextEmphasisColor(),
- style->InternalVisitedTextEmphasisColor());
-
- ScopedCSSValue scoped_none(*CSSIdentifierValue::Create(CSSValueID::kNone),
- nullptr);
- StyleBuilder::ApplyProperty(GetCSSPropertyTextShadow(), state_, scoped_none);
- StyleBuilder::ApplyProperty(GetCSSPropertyBoxShadow(), state_, scoped_none);
- if (!style->HasUrlBackgroundImage()) {
- StyleBuilder::ApplyProperty(GetCSSPropertyBackgroundImage(), state_,
- scoped_none);
- }
-
- // Preserve the author/user defined background alpha channel.
- style->SetBackgroundColor(
- StyleColor(style->BackgroundColor().ResolveWithAlpha(
- style->GetCurrentColor(), mojom::blink::ColorScheme::kLight,
- bg_color_alpha)));
- style->SetInternalVisitedBackgroundColor(
- StyleColor(style->InternalVisitedBackgroundColor().ResolveWithAlpha(
- style->GetCurrentColor(), mojom::blink::ColorScheme::kLight,
- visited_bg_color_alpha)));
-}
-
-void StyleCascade::MaybeForceColor(const CSSProperty& property,
- const StyleColor& color) {
- DCHECK(GetDocument().InForcedColorsMode() &&
- state_.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone);
-
- // Preserve the author/user color if it computes to a system color.
- if (color.IsSystemColor())
- return;
-
- StyleBuilder::ApplyProperty(
- property, state_,
- ScopedCSSValue(*GetForcedColorValue(property.GetCSSPropertyName()),
- nullptr));
-}
-
-const CSSValue* StyleCascade::GetForcedColorValue(CSSPropertyName name) {
- DCHECK(GetDocument().InForcedColorsMode() &&
- state_.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone);
-
- CascadePriority* p = map_.Find(name, CascadeOrigin::kUserAgent);
- if (p)
- return ValueAt(match_result_, p->GetPosition());
- if (name.Id() == CSSPropertyID::kBackgroundColor ||
- name.Id() == CSSPropertyID::kInternalVisitedBackgroundColor) {
- return CSSIdentifierValue::Create(CSSValueID::kCanvas);
- }
- return cssvalue::CSSUnsetValue::Create();
-}
-
bool StyleCascade::IsRootElement() const {
return &state_.GetElement() == state_.GetDocument().documentElement();
}
@@ -1008,7 +897,7 @@ CSSVariableData* StyleCascade::GetVariableData(
CSSVariableData* StyleCascade::GetEnvironmentVariable(
const AtomicString& name) const {
// If we are in a User Agent Shadow DOM then we should not record metrics.
- ContainerNode& scope_root = state_.GetTreeScope().RootNode();
+ ContainerNode& scope_root = state_.GetElement().GetTreeScope().RootNode();
auto* shadow_root = DynamicTo<ShadowRoot>(&scope_root);
bool is_ua_scope = shadow_root && shadow_root->IsUserAgent();
@@ -1053,11 +942,6 @@ bool StyleCascade::ValidateFallback(const CustomProperty& property,
void StyleCascade::MarkIsReferenced(const CSSProperty& referencer,
const CustomProperty& referenced) {
- // For simplicity, we mark all inherited custom property references as
- // dependencies, even though it might not be a dependency if this cascade
- // defines a value for that property.
- if (!referencer.IsInherited() && referenced.IsInherited())
- MarkDependency(referenced);
if (!referenced.IsRegistered())
return;
const AtomicString& name = referenced.GetPropertyNameAtomicString();
@@ -1070,10 +954,6 @@ void StyleCascade::MarkHasVariableReference(const CSSProperty& property) {
state_.Style()->SetHasVariableReference();
}
-void StyleCascade::MarkDependency(const CSSProperty& property) {
- state_.MarkDependency(property);
-}
-
const Document& StyleCascade::GetDocument() const {
return state_.GetDocument();
}
@@ -1097,27 +977,10 @@ void StyleCascade::CountUse(WebFeature feature) {
}
void StyleCascade::MaybeUseCountRevert(const CSSValue& value) {
- // In forced colors mode, any value can behave like 'revert' [1], but we
- // should only use-count the true uses of 'revert'.
- // [1] https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties
if (IsRevert(value))
CountUse(WebFeature::kCSSKeywordRevert);
}
-// TODO(crbug.com/590014): Remove this when display type of <summary> is fixed
-void StyleCascade::MaybeUseCountSummaryDisplayBlock() {
- if (!state_.GetElement().HasTagName(html_names::kSummaryTag))
- return;
- CascadePriority priority = map_.At(CSSPropertyName(CSSPropertyID::kDisplay));
- if (priority.GetOrigin() <= CascadeOrigin::kUserAgent)
- return;
- const CSSValue* value = ValueAt(match_result_, priority.GetPosition());
- if (auto* identifier = DynamicTo<CSSIdentifierValue>(value)) {
- if (identifier->GetValueID() == CSSValueID::kBlock)
- CountUse(WebFeature::kSummaryElementWithDisplayBlockAuthorRule);
- }
-}
-
void StyleCascade::MaybeUseCountInvalidVariableUnset(
const CustomProperty& property) {
if (!property.SupportsGuaranteedInvalid())
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.h b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.h
index be7eec5c1f7..40422a1e571 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade.h
@@ -36,7 +36,6 @@ class CSSVariableData;
class CSSVariableReferenceValue;
class CustomProperty;
class MatchResult;
-class StyleColor;
class StyleResolverState;
namespace cssvalue {
@@ -212,12 +211,6 @@ class CORE_EXPORT StyleCascade {
CascadePriority,
CascadeResolver&);
- // Update the ComputedStyle to use the colors specified in Forced Colors Mode.
- // https://www.w3.org/TR/css-color-adjust-1/#forced
- void ForceColors();
- void MaybeForceColor(const CSSProperty& property, const StyleColor& color);
- const CSSValue* GetForcedColorValue(CSSPropertyName name);
-
// Whether or not we are calculating the style for the root element.
// We need to know this to detect cycles with 'rem' units.
// https://drafts.css-houdini.org/css-properties-values-api-1/#dependency-cycles
@@ -340,13 +333,6 @@ class CORE_EXPORT StyleCascade {
// Marks a CSSProperty as having a reference to a custom property. Needed to
// disable the matched property cache in some cases.
void MarkHasVariableReference(const CSSProperty&);
- // The resulting ComputedStyle may depend on values from the parent style,
- // for example, explicit inheritance or var() references means we hold a
- // dependency on the relevant property. We maintain a set of these
- // dependencies on StyleResolverState, which is later used by the
- // MatchedPropertiesCache to figure out if a given cache lookup is a hit or a
- // miss.
- void MarkDependency(const CSSProperty&);
const Document& GetDocument() const;
const CSSProperty& ResolveSurrogate(const CSSProperty& surrogate);
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index 25ca4ebd5f4..c1553206177 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -292,13 +292,8 @@ class TestCascadeAutoLock {
CascadeResolver::AutoLock lock_;
};
-class StyleCascadeTest
- : public PageTestBase,
- private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
+class StyleCascadeTest : public PageTestBase {
public:
- StyleCascadeTest()
- : ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
-
CSSStyleSheet* CreateSheet(const String& css_text) {
auto* init = MakeGarbageCollected<CSSStyleSheetInit>();
DummyExceptionStateForTesting exception_state;
@@ -3240,77 +3235,6 @@ TEST_F(StyleCascadeTest, GetImportantSetMany) {
*cascade.GetImportantSet());
}
-TEST_F(StyleCascadeTest, NoDependenciesPresent) {
- TestCascade cascade(GetDocument());
- cascade.Add("left:2px");
- cascade.Add("top:initial");
- cascade.Add("border:1px solid black");
- cascade.Add("--x:bar");
- cascade.Add("direction:rtl");
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_TRUE(state.Dependencies().IsEmpty());
- EXPECT_FALSE(state.HasIncomparableDependency());
-}
-
-TEST_F(StyleCascadeTest, ExplicitInheritanceDependencyIsDetected) {
- TestCascade cascade(GetDocument());
- cascade.Add("left:inherit");
- cascade.Add("right:inherit");
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_EQ(2u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(PropertyName("left")));
- EXPECT_TRUE(state.Dependencies().Contains(PropertyName("right")));
- EXPECT_FALSE(state.HasIncomparableDependency());
-}
-
-TEST_F(StyleCascadeTest, IncomparableDependencyDetected) {
- ASSERT_FALSE(
- GetCSSPropertyInternalEmptyLineHeight().IsComputedValueComparable());
-
- TestCascade cascade(GetDocument());
- cascade.Add("-internal-empty-line-height:inherit", CascadeOrigin::kUserAgent);
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_EQ(1u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(
- CSSPropertyName(CSSPropertyID::kInternalEmptyLineHeight)));
- EXPECT_TRUE(state.HasIncomparableDependency());
-}
-
-TEST_F(StyleCascadeTest, CustomPropertyDependencyIsDetected) {
- TestCascade cascade(GetDocument());
- cascade.Add("left:var(--x,1px)");
- cascade.Add("right:var(--x,2px)");
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_EQ(1u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(PropertyName("--x")));
- EXPECT_FALSE(state.HasIncomparableDependency());
-}
-
-TEST_F(StyleCascadeTest, NonInheritedCustomPropertyIsNoDependency) {
- RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
- TestCascade cascade(GetDocument());
- cascade.Add("left:var(--x,1px)");
- cascade.Add("right:var(--x,2px)");
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_EQ(0u, state.Dependencies().size());
-}
-
-TEST_F(StyleCascadeTest, DirectionAndWritingModeDependenciesAreDetected) {
- TestCascade cascade(GetDocument());
- cascade.Add("margin-inline-start: 2px");
- cascade.Apply();
- const auto& state = cascade.State();
- EXPECT_EQ(2u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(PropertyName("direction")));
- EXPECT_TRUE(state.Dependencies().Contains(PropertyName("writing-mode")));
- EXPECT_FALSE(state.HasIncomparableDependency());
-}
-
TEST_F(StyleCascadeTest, RootColorNotModifiedByEmptyCascade) {
TestCascade cascade(GetDocument(), GetDocument().documentElement());
cascade.Add("color:red");
@@ -3385,55 +3309,6 @@ TEST_F(StyleCascadeTest, MaxSubstitutionTokens) {
cascade.ComputedValue("--above-limit-reference-fallback"));
}
-TEST_F(StyleCascadeTest, UseCountSummary) {
- const auto feature = WebFeature::kSummaryElementWithDisplayBlockAuthorRule;
-
- Element* summary = GetDocument().CreateRawElement(html_names::kSummaryTag);
- GetDocument().body()->AppendChild(summary);
-
- {
- ASSERT_FALSE(GetDocument().IsUseCounted(feature));
-
- TestCascade cascade(GetDocument(), summary);
- cascade.Apply();
- EXPECT_FALSE(GetDocument().IsUseCounted(feature));
- }
- {
- ASSERT_FALSE(GetDocument().IsUseCounted(feature));
-
- TestCascade cascade(GetDocument(), summary);
- cascade.Add("color:green");
- cascade.Apply();
- EXPECT_FALSE(GetDocument().IsUseCounted(feature));
- }
- {
- ASSERT_FALSE(GetDocument().IsUseCounted(feature));
-
- TestCascade cascade(GetDocument(), summary);
- cascade.Add("display:block", CascadeOrigin::kUserAgent);
- cascade.Apply();
- EXPECT_FALSE(GetDocument().IsUseCounted(feature));
- }
- {
- ASSERT_FALSE(GetDocument().IsUseCounted(feature));
-
- TestCascade cascade(GetDocument(), summary);
- cascade.Add("display:block", CascadeOrigin::kUser);
- cascade.Apply();
- EXPECT_TRUE(GetDocument().IsUseCounted(feature));
- GetDocument().ClearUseCounterForTesting(feature);
- }
- {
- ASSERT_FALSE(GetDocument().IsUseCounted(feature));
-
- TestCascade cascade(GetDocument(), summary);
- cascade.Add("display:block", CascadeOrigin::kAuthor);
- cascade.Apply();
- EXPECT_TRUE(GetDocument().IsUseCounted(feature));
- GetDocument().ClearUseCounterForTesting(feature);
- }
-}
-
TEST_F(StyleCascadeTest, GetCascadedValues) {
TestCascade cascade(GetDocument());
cascade.Add("top:1px", CascadeOrigin::kUserAgent);
@@ -3538,32 +3413,6 @@ TEST_F(StyleCascadeTest, GetCascadedValuesInterpolated) {
EXPECT_EQ("-5s", CssTextAt(map, "animation-delay"));
}
-TEST_F(StyleCascadeTest, ForcedVisitedBackgroundColor) {
- ScopedForcedColorsForTest scoped_feature(true);
- ColorSchemeHelper color_scheme_helper(GetDocument());
- color_scheme_helper.SetForcedColors(GetDocument(), ForcedColors::kActive);
- UpdateAllLifecyclePhasesForTest();
-
- TestCascade cascade(GetDocument());
- cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
- cascade.Add(ParseDeclarationBlock("background-color:#aabbccdd"),
- CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
- cascade.Apply();
-
- Color forced_bg_color =
- StyleColor(CSSValueID::kCanvas)
- .Resolve(Color(), mojom::blink::ColorScheme::kLight);
- Color expected_bg_color =
- Color(forced_bg_color.Red(), forced_bg_color.Green(),
- forced_bg_color.Blue(), 0xdd);
-
- // Verify that the visited background color alpha channel is preserved in
- // Forced Colors Mode.
- EXPECT_EQ(
- expected_bg_color,
- cascade.State().Style()->InternalVisitedBackgroundColor().GetColor());
-}
-
TEST_F(StyleCascadeTest, RevertOrigin) {
TestCascade cascade(GetDocument());
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 683b1d0bc04..dce90e8fd17 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -400,7 +400,7 @@ const static TextTrack* GetTextTrackFromElement(const Element& element) {
}
static void MatchVTTRules(const Element& element,
- ElementRuleCollector& collector) {
+ ElementRuleCollector& collector) {
const TextTrack* text_track = GetTextTrackFromElement(element);
if (!text_track)
return;
@@ -430,8 +430,7 @@ static void MatchElementScopeRules(const Element& element,
ElementRuleCollector& collector) {
if (element_scope_resolver) {
collector.ClearMatchedRules();
- element_scope_resolver->CollectMatchingAuthorRules(collector);
- element_scope_resolver->CollectMatchingTreeBoundaryCrossingRules(collector);
+ element_scope_resolver->CollectMatchingElementScopeRules(collector);
collector.SortAndTransferMatchedRules();
}
@@ -452,18 +451,24 @@ static void MatchElementScopeRules(const Element& element,
void StyleResolver::MatchPseudoPartRulesForUAHost(
const Element& element,
ElementRuleCollector& collector) {
- if (element.ShadowPseudoId() != shadow_element_names::kPseudoInputPlaceholder)
+ const AtomicString& pseudo_id = element.ShadowPseudoId();
+ if (pseudo_id != shadow_element_names::kPseudoInputPlaceholder &&
+ pseudo_id != shadow_element_names::kPseudoFileUploadButton) {
return;
+ }
// We allow ::placeholder pseudo element after ::part(). See
// MatchSlottedRulesForUAHost for a more detailed explanation.
DCHECK(element.OwnerShadowHost());
- MatchPseudoPartRules(*element.OwnerShadowHost(), collector);
+ MatchPseudoPartRules(*element.OwnerShadowHost(), collector,
+ /* for_shadow_pseudo */ true);
}
void StyleResolver::MatchPseudoPartRules(const Element& element,
- ElementRuleCollector& collector) {
- MatchPseudoPartRulesForUAHost(element, collector);
+ ElementRuleCollector& collector,
+ bool for_shadow_pseudo) {
+ if (!for_shadow_pseudo)
+ MatchPseudoPartRulesForUAHost(element, collector);
DOMTokenList* part = element.GetPart();
if (!part)
return;
@@ -480,7 +485,8 @@ void StyleResolver::MatchPseudoPartRules(const Element& element,
TreeScope& tree_scope = host->GetTreeScope();
if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver()) {
collector.ClearMatchedRules();
- resolver->CollectMatchingPartPseudoRules(collector, current_names);
+ resolver->CollectMatchingPartPseudoRules(collector, current_names,
+ for_shadow_pseudo);
collector.SortAndTransferMatchedRules();
collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope());
}
@@ -499,138 +505,16 @@ void StyleResolver::MatchPseudoPartRules(const Element& element,
}
}
-static bool ShouldCheckScope(const Element& element,
- const Node& scoping_node,
- bool is_inner_tree_scope) {
- if (is_inner_tree_scope &&
- element.GetTreeScope() != scoping_node.GetTreeScope()) {
- // Check if |element| may be affected by a ::content rule in |scopingNode|'s
- // style. If |element| is a descendant of a shadow host which is ancestral
- // to |scopingNode|, the |element| should be included for rule collection.
- // Skip otherwise.
- const TreeScope* scope = &scoping_node.GetTreeScope();
- while (scope && scope->ParentTreeScope() != &element.GetTreeScope())
- scope = scope->ParentTreeScope();
- Element* shadow_host =
- scope ? scope->RootNode().OwnerShadowHost() : nullptr;
- return shadow_host && element.IsDescendantOf(shadow_host);
- }
-
- // When |element| can be distributed to |scopingNode| via <shadow>, ::content
- // rule can match, thus the case should be included.
- if (!is_inner_tree_scope &&
- scoping_node.ParentOrShadowHostNode() ==
- element.GetTreeScope().RootNode().ParentOrShadowHostNode())
- return true;
-
- // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be
- // included. Skip otherwise.
- return scoping_node.GetTreeScope()
- .GetScopedStyleResolver()
- ->HasDeepOrShadowSelector();
-}
-
-void StyleResolver::MatchScopedRulesV0(
- const Element& element,
- ElementRuleCollector& collector,
- ScopedStyleResolver* element_scope_resolver) {
- // Match rules from treeScopes in the reverse tree-of-trees order, since the
- // cascading order for normal rules is such that when comparing rules from
- // different shadow trees, the rule from the tree which comes first in the
- // tree-of-trees order wins. From other treeScopes than the element's own
- // scope, only tree-boundary-crossing rules may match.
-
- bool match_element_scope_done =
- !element_scope_resolver && !element.InlineStyle();
-
- const auto& tree_boundary_crossing_scopes =
- GetDocument().GetStyleEngine().TreeBoundaryCrossingScopes();
- for (auto it = tree_boundary_crossing_scopes.rbegin();
- it != tree_boundary_crossing_scopes.rend(); ++it) {
- const TreeScope& scope = (*it)->ContainingTreeScope();
- ScopedStyleResolver* resolver = scope.GetScopedStyleResolver();
- DCHECK(resolver);
-
- bool is_inner_tree_scope =
- element.ContainingTreeScope().IsInclusiveAncestorOf(scope);
- if (!ShouldCheckScope(element, **it, is_inner_tree_scope))
- continue;
-
- if (!match_element_scope_done &&
- scope.IsInclusiveAncestorOf(element.ContainingTreeScope())) {
- match_element_scope_done = true;
-
- // At this point, the iterator has either encountered the scope for the
- // element itself (if that scope has boundary-crossing rules), or the
- // iterator has moved to a scope which appears before the element's scope
- // in the tree-of-trees order. Try to match all rules from the element's
- // scope.
-
- MatchElementScopeRules(element, element_scope_resolver, collector);
- if (resolver == element_scope_resolver) {
- // Boundary-crossing rules already collected in matchElementScopeRules.
- continue;
- }
- }
-
- collector.ClearMatchedRules();
- resolver->CollectMatchingTreeBoundaryCrossingRules(collector);
- collector.SortAndTransferMatchedRules();
- collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope());
- }
-
- if (!match_element_scope_done)
- MatchElementScopeRules(element, element_scope_resolver, collector);
-}
-
void StyleResolver::MatchAuthorRules(
const Element& element,
ScopedStyleResolver* element_scope_resolver,
ElementRuleCollector& collector) {
- if (GetDocument().GetShadowCascadeOrder() ==
- ShadowCascadeOrder::kShadowCascadeV0) {
- MatchAuthorRulesV0(element, element_scope_resolver, collector);
- return;
- }
MatchHostAndCustomElementRules(element, collector);
-
- if (GetDocument().MayContainV0Shadow()) {
- MatchScopedRulesV0(element, collector, element_scope_resolver);
- return;
- }
-
MatchSlottedRules(element, collector);
MatchElementScopeRules(element, element_scope_resolver, collector);
MatchPseudoPartRules(element, collector);
}
-void StyleResolver::MatchAuthorRulesV0(
- const Element& element,
- ScopedStyleResolver* element_scope_resolver,
- ElementRuleCollector& collector) {
- collector.ClearMatchedRules();
-
- ShadowV0CascadeOrder cascade_order = 0;
- HeapVector<Member<ScopedStyleResolver>, 8> resolvers_in_shadow_tree;
- CollectScopedResolversForHostedShadowTrees(element, resolvers_in_shadow_tree);
-
- // Apply :host and :host-context rules from inner scopes.
- for (int j = resolvers_in_shadow_tree.size() - 1; j >= 0; --j)
- resolvers_in_shadow_tree.at(j)->CollectMatchingShadowHostRules(
- collector, ++cascade_order);
-
- // Apply normal rules from element scope.
- if (element_scope_resolver) {
- element_scope_resolver->CollectMatchingAuthorRules(collector,
- ++cascade_order);
- }
-
- // Apply /deep/ and ::shadow rules from outer scopes, and ::content from
- // inner.
- CollectTreeBoundaryCrossingRulesV0CascadeOrder(element, collector);
- collector.SortAndTransferMatchedRules();
-}
-
void StyleResolver::MatchUserRules(ElementRuleCollector& collector) {
collector.ClearMatchedRules();
GetDocument().GetStyleEngine().CollectMatchingUserRules(collector);
@@ -638,6 +522,22 @@ void StyleResolver::MatchUserRules(ElementRuleCollector& collector) {
collector.FinishAddingUserRules();
}
+namespace {
+
+bool IsInMediaUAShadow(const Element& element) {
+ ShadowRoot* root = element.ContainingShadowRoot();
+ if (!root || !root->IsUserAgent())
+ return false;
+ ShadowRoot* outer_root;
+ do {
+ outer_root = root;
+ root = root->host().ContainingShadowRoot();
+ } while (root && root->IsUserAgent());
+ return outer_root->host().IsMediaElement();
+}
+
+} // namespace
+
void StyleResolver::MatchUARules(const Element& element,
ElementRuleCollector& collector) {
collector.SetMatchingUARules(true);
@@ -645,12 +545,17 @@ void StyleResolver::MatchUARules(const Element& element,
CSSDefaultStyleSheets& default_style_sheets =
CSSDefaultStyleSheets::Instance();
if (!print_media_type_) {
- if (LIKELY(element.IsHTMLElement() || element.IsVTTElement()))
+ if (LIKELY(element.IsHTMLElement() || element.IsVTTElement())) {
MatchRuleSet(collector, default_style_sheets.DefaultStyle());
- else if (element.IsSVGElement())
+ if (UNLIKELY(IsInMediaUAShadow(element))) {
+ MatchRuleSet(collector,
+ default_style_sheets.DefaultMediaControlsStyle());
+ }
+ } else if (element.IsSVGElement()) {
MatchRuleSet(collector, default_style_sheets.DefaultSVGStyle());
- else if (element.namespaceURI() == mathml_names::kNamespaceURI)
+ } else if (element.namespaceURI() == mathml_names::kNamespaceURI) {
MatchRuleSet(collector, default_style_sheets.DefaultMathMLStyle());
+ }
} else {
MatchRuleSet(collector, default_style_sheets.DefaultPrintStyle());
}
@@ -707,14 +612,11 @@ void StyleResolver::MatchAllRules(StyleResolverState& state,
element.AdditionalPresentationAttributeStyle());
if (auto* html_element = DynamicTo<HTMLElement>(element)) {
- bool is_auto;
- TextDirection text_direction =
- html_element->DirectionalityIfhasDirAutoAttribute(is_auto);
- if (is_auto) {
- state.SetHasDirAutoAttribute(true);
+ if (html_element->HasDirectionAuto()) {
collector.AddElementStyleProperties(
- text_direction == TextDirection::kLtr ? LeftToRightDeclaration()
- : RightToLeftDeclaration());
+ html_element->CachedDirectionality() == TextDirection::kLtr
+ ? LeftToRightDeclaration()
+ : RightToLeftDeclaration());
}
}
}
@@ -723,17 +625,6 @@ void StyleResolver::MatchAllRules(StyleResolverState& state,
MatchAuthorRules(element, element_scope_resolver, collector);
if (element.IsStyledElement() && !state.IsForPseudoElement()) {
- // For Shadow DOM V1, inline style is already collected in
- // matchScopedRules().
- if (GetDocument().GetShadowCascadeOrder() ==
- ShadowCascadeOrder::kShadowCascadeV0 &&
- element.InlineStyle()) {
- // Inline style is immutable as long as there is no CSSOM wrapper.
- bool is_inline_style_cacheable = !element.InlineStyle()->IsMutable();
- collector.AddElementStyleProperties(element.InlineStyle(),
- is_inline_style_cacheable);
- }
-
// Now check SMIL animation override style.
auto* svg_element = DynamicTo<SVGElement>(element);
if (include_smil_properties && svg_element) {
@@ -747,41 +638,6 @@ void StyleResolver::MatchAllRules(StyleResolverState& state,
: element.GetTreeScope());
}
-void StyleResolver::CollectTreeBoundaryCrossingRulesV0CascadeOrder(
- const Element& element,
- ElementRuleCollector& collector) {
- const auto& tree_boundary_crossing_scopes =
- GetDocument().GetStyleEngine().TreeBoundaryCrossingScopes();
- if (tree_boundary_crossing_scopes.IsEmpty())
- return;
-
- // When comparing rules declared in outer treescopes, outer's rules win.
- ShadowV0CascadeOrder outer_cascade_order =
- tree_boundary_crossing_scopes.size() * 2;
- // When comparing rules declared in inner treescopes, inner's rules win.
- ShadowV0CascadeOrder inner_cascade_order =
- tree_boundary_crossing_scopes.size();
-
- for (const auto& scoping_node : tree_boundary_crossing_scopes) {
- // Skip rule collection for element when tree boundary crossing rules of
- // scopingNode's scope can never apply to it.
- bool is_inner_tree_scope =
- element.ContainingTreeScope().IsInclusiveAncestorOf(
- scoping_node->ContainingTreeScope());
- if (!ShouldCheckScope(element, *scoping_node, is_inner_tree_scope))
- continue;
-
- ShadowV0CascadeOrder cascade_order =
- is_inner_tree_scope ? inner_cascade_order : outer_cascade_order;
- scoping_node->GetTreeScope()
- .GetScopedStyleResolver()
- ->CollectMatchingTreeBoundaryCrossingRules(collector, cascade_order);
-
- ++inner_cascade_order;
- --outer_cascade_order;
- }
-}
-
scoped_refptr<ComputedStyle> StyleResolver::StyleForViewport() {
scoped_refptr<ComputedStyle> viewport_style =
InitialStyleForElement(GetDocument());
@@ -847,6 +703,7 @@ static void UpdateAnimationBaseComputedStyle(StyleResolverState& state,
scoped_refptr<ComputedStyle> StyleResolver::StyleForElement(
Element* element,
+ const StyleRecalcContext& style_recalc_context,
const ComputedStyle* default_parent,
const ComputedStyle* default_layout_parent,
RuleMatchingBehavior matching_behavior) {
@@ -872,8 +729,9 @@ scoped_refptr<ComputedStyle> StyleResolver::StyleForElement(
STACK_UNINITIALIZED StyleCascade cascade(state);
- ApplyBaseStyle(element, state, cascade, cascade.MutableMatchResult(),
- matching_behavior, can_cache_animation_base_computed_style);
+ ApplyBaseStyle(element, style_recalc_context, state, cascade,
+ cascade.MutableMatchResult(), matching_behavior,
+ can_cache_animation_base_computed_style);
if (ApplyAnimatedStyle(state, cascade)) {
INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
@@ -918,7 +776,7 @@ void StyleResolver::InitStyleAndApplyInheritance(Element& element,
// contenteditable attribute (implemented by -webkit-user-modify) should
// be propagated from shadow host to distributed node.
- if (state.DistributedToV0InsertionPoint() || element.AssignedSlot()) {
+ if (element.AssignedSlot()) {
if (Element* parent = element.parentElement()) {
if (const ComputedStyle* shadow_host_style = parent->GetComputedStyle())
state.Style()->SetUserModify(shadow_host_style->UserModify());
@@ -932,11 +790,10 @@ void StyleResolver::InitStyleAndApplyInheritance(Element& element,
// Strictly, we should only allow the root element to inherit from
// initial styles, but we allow getComputedStyle() for connected
// elements outside the flat tree rooted at an unassigned shadow host
- // child, a slot fallback element, or Shadow DOM V0 insertion points.
- DCHECK(element.IsV0InsertionPoint() ||
- ((IsShadowHost(element.parentNode()) ||
- IsA<HTMLSlotElement>(element.parentNode())) &&
- !LayoutTreeBuilderTraversal::ParentElement(element)));
+ // child or a slot fallback element.
+ DCHECK((IsShadowHost(element.parentNode()) ||
+ IsA<HTMLSlotElement>(element.parentNode())) &&
+ !LayoutTreeBuilderTraversal::ParentElement(element));
state.Style()->SetIsEnsuredOutsideFlatTree();
}
}
@@ -988,6 +845,7 @@ void StyleResolver::ApplyMathMLCustomStyleProperties(
void StyleResolver::ApplyBaseStyle(
Element* element,
+ const StyleRecalcContext& style_recalc_context,
StyleResolverState& state,
StyleCascade& cascade,
MatchResult& match_result,
@@ -1014,9 +872,9 @@ void StyleResolver::ApplyBaseStyle(
DocumentElementUserAgentDeclarations());
}
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
- match_result, state.Style(),
- state.Style()->InsideLink());
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_, match_result,
+ state.Style(), state.Style()->InsideLink());
MatchAllRules(state, collector,
matching_behavior != kMatchAllRulesExcludingSMIL);
@@ -1035,11 +893,11 @@ void StyleResolver::ApplyBaseStyle(
element->GetComputedStyle()->TextAutosizingMultiplier());
}
- if (state.HasDirAutoAttribute())
- state.Style()->SetSelfOrAncestorHasDirAutoAttribute(true);
-
CascadeAndApplyMatchedProperties(state, cascade);
+ if (collector.MatchedResult().DependsOnContainerQueries())
+ state.Style()->SetDependsOnContainerQueries(true);
+
ApplyCallbackSelectors(state);
// Cache our original display.
@@ -1069,7 +927,8 @@ CompositorKeyframeValue* StyleResolver::CreateCompositorKeyframeValueSnapshot(
const ComputedStyle& base_style,
const ComputedStyle* parent_style,
const PropertyHandle& property,
- const CSSValue* value) {
+ const CSSValue* value,
+ double offset) {
// TODO(alancutter): Avoid creating a StyleResolverState just to apply a
// single value on a ComputedStyle.
StyleResolverState state(element.GetDocument(), element, parent_style,
@@ -1087,11 +946,13 @@ CompositorKeyframeValue* StyleResolver::CreateCompositorKeyframeValueSnapshot(
element.GetTreeScope());
cascade.Apply();
}
- return CompositorKeyframeValueFactory::Create(property, *state.Style());
+ return CompositorKeyframeValueFactory::Create(property, *state.Style(),
+ offset);
}
scoped_refptr<ComputedStyle> StyleResolver::PseudoStyleForElement(
Element* element,
+ const StyleRecalcContext& style_recalc_context,
const PseudoElementStyleRequest& pseudo_style_request,
const ComputedStyle* parent_style,
const ComputedStyle* parent_layout_object_style) {
@@ -1134,7 +995,8 @@ scoped_refptr<ComputedStyle> StyleResolver::PseudoStyleForElement(
state.Style()->SetStyleType(pseudo_style_request.pseudo_id);
// Check UA, user and author rules.
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_,
cascade.MutableMatchResult(), state.Style(),
state.Style()->InsideLink());
collector.SetPseudoElementStyleRequest(pseudo_style_request);
@@ -1160,6 +1022,9 @@ scoped_refptr<ComputedStyle> StyleResolver::PseudoStyleForElement(
CascadeAndApplyMatchedProperties(state, cascade);
+ if (collector.MatchedResult().DependsOnContainerQueries())
+ state.Style()->SetDependsOnContainerQueries(true);
+
ApplyCallbackSelectors(state);
// Cache our original display.
@@ -1250,6 +1115,7 @@ scoped_refptr<ComputedStyle> StyleResolver::InitialStyleForElement(
initial_style->SetZoom(frame && !document.Printing() ? frame->PageZoomFactor()
: 1);
initial_style->SetEffectiveZoom(initial_style->Zoom());
+ initial_style->SetInForcedColorsMode(document.InForcedColorsMode());
FontDescription document_font_description =
initial_style->GetFontDescription();
@@ -1298,8 +1164,10 @@ StyleRuleList* StyleResolver::StyleRulesForElement(Element* element,
DCHECK(element);
StyleResolverState state(GetDocument(), *element);
MatchResult match_result;
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
- match_result, state.Style(),
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_, match_result, state.Style(),
EInsideLink::kNotInsideLink);
collector.SetMode(SelectorChecker::kCollectingStyleRules);
CollectPseudoRulesForElement(*element, collector, kPseudoIdNone,
@@ -1313,9 +1181,11 @@ StyleResolver::CascadedValuesForElement(Element* element, PseudoId pseudo_id) {
state.SetStyle(ComputedStyle::Create());
STACK_UNINITIALIZED StyleCascade cascade(state);
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
- cascade.MutableMatchResult(), state.Style(),
- EInsideLink::kNotInsideLink);
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_, cascade.MutableMatchResult(),
+ state.Style(), EInsideLink::kNotInsideLink);
collector.SetPseudoElementStyleRequest(PseudoElementStyleRequest(pseudo_id));
MatchAllRules(state, collector, false /* include_smil_properties */);
@@ -1330,8 +1200,10 @@ RuleIndexList* StyleResolver::PseudoCSSRulesForElement(
DCHECK(element);
StyleResolverState state(GetDocument(), *element);
MatchResult match_result;
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
- match_result, state.Style(),
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_, match_result, state.Style(),
EInsideLink::kNotInsideLink);
collector.SetMode(SelectorChecker::kCollectingCSSRules);
// TODO(obrufau): support collecting rules for nested ::marker
@@ -1535,12 +1407,11 @@ StyleResolver::CacheSuccess StyleResolver::ApplyMatchedCache(
// earlier style object built using the same exact style declarations. We
// then only need to apply the inherited properties, if any, as their values
// can depend on the element context. This is fast and saves memory by
- // reusing the style data structures.
+ // reusing the style data structures. Note that we cannot do this if the
+ // direct parent is a ShadowRoot.
if (state.ParentStyle()->InheritedDataShared(
*cached_matched_properties->parent_computed_style) &&
- !IsAtShadowBoundary(&element) &&
- (!state.DistributedToV0InsertionPoint() || element.AssignedSlot() ||
- state.Style()->UserModify() == EUserModify::kReadOnly)) {
+ !IsAtShadowBoundary(&element)) {
INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
matched_property_cache_inherited_hit, 1);
@@ -1582,7 +1453,7 @@ void StyleResolver::MaybeAddToMatchedPropertiesCache(
INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
matched_property_cache_added, 1);
matched_properties_cache_.Add(cache_success.key, *state.Style(),
- *state.ParentStyle(), state.Dependencies());
+ *state.ParentStyle());
}
}
@@ -1601,6 +1472,10 @@ void StyleResolver::CalculateAnimationUpdate(StyleResolverState& state) {
}
bool StyleResolver::CanReuseBaseComputedStyle(const StyleResolverState& state) {
+ // TODO(crbug.com/1180159): @container and transitions properly.
+ if (RuntimeEnabledFeatures::CSSContainerQueriesEnabled())
+ return false;
+
ElementAnimations* element_animations = GetElementAnimations(state);
if (!element_animations || !element_animations->BaseComputedStyle())
return false;
@@ -1677,8 +1552,10 @@ scoped_refptr<ComputedStyle> StyleResolver::StyleForInterpolations(
StyleResolverState state(GetDocument(), element);
STACK_UNINITIALIZED StyleCascade cascade(state);
- ApplyBaseStyle(&element, state, cascade, cascade.MutableMatchResult(),
- kMatchAllRules, true);
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+ ApplyBaseStyle(&element, style_recalc_context, state, cascade,
+ cascade.MutableMatchResult(), kMatchAllRules, true);
ApplyInterpolations(state, cascade, interpolations);
return state.TakeStyle();
@@ -1748,9 +1625,11 @@ void StyleResolver::ApplyCallbackSelectors(StyleResolverState& state) {
if (!watched_selectors_rule_set)
return;
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
MatchResult match_result;
- ElementRuleCollector collector(state.ElementContext(), selector_filter_,
- match_result, state.Style(),
+ ElementRuleCollector collector(state.ElementContext(), style_recalc_context,
+ selector_filter_, match_result, state.Style(),
state.Style()->InsideLink());
collector.SetMode(SelectorChecker::kCollectingStyleRules);
collector.SetIncludeEmptyRules(true);
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 56403de5970..462cd69f3be 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -50,6 +50,7 @@ class MatchResult;
class PropertyHandle;
class RuleSet;
class StyleCascade;
+class StyleRecalcContext;
class StyleRuleUsageTracker;
enum RuleMatchingBehavior { kMatchAllRules, kMatchAllRulesExcludingSMIL };
@@ -67,6 +68,7 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> {
scoped_refptr<ComputedStyle> StyleForElement(
Element*,
+ const StyleRecalcContext&,
const ComputedStyle* parent_style = nullptr,
const ComputedStyle* layout_parent_style = nullptr,
RuleMatchingBehavior = kMatchAllRules);
@@ -78,10 +80,12 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> {
const ComputedStyle& base_style,
const ComputedStyle* parent_style,
const PropertyHandle&,
- const CSSValue*);
+ const CSSValue*,
+ double offset);
scoped_refptr<ComputedStyle> PseudoStyleForElement(
Element*,
+ const StyleRecalcContext&,
const PseudoElementStyleRequest&,
const ComputedStyle* parent_style,
const ComputedStyle* layout_parent_style);
@@ -163,6 +167,7 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> {
void InitStyleAndApplyInheritance(Element& element,
StyleResolverState& state);
void ApplyBaseStyle(Element* element,
+ const StyleRecalcContext&,
StyleResolverState& state,
StyleCascade& cascade,
MatchResult& match_result,
@@ -186,22 +191,16 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> {
void MatchUserRules(ElementRuleCollector&);
// This matches `::part` selectors. It looks in ancestor scopes as far as
// part mapping requires.
- void MatchPseudoPartRules(const Element&, ElementRuleCollector&);
+ void MatchPseudoPartRules(const Element&,
+ ElementRuleCollector&,
+ bool for_shadow_pseudo = false);
void MatchPseudoPartRulesForUAHost(const Element&, ElementRuleCollector&);
- void MatchScopedRulesV0(const Element&,
- ElementRuleCollector&,
- ScopedStyleResolver*);
void MatchAuthorRules(const Element&,
ScopedStyleResolver*,
ElementRuleCollector&);
- void MatchAuthorRulesV0(const Element&,
- ScopedStyleResolver*,
- ElementRuleCollector&);
void MatchAllRules(StyleResolverState&,
ElementRuleCollector&,
bool include_smil_properties);
- void CollectTreeBoundaryCrossingRulesV0CascadeOrder(const Element&,
- ElementRuleCollector&);
void ApplyMathMLCustomStyleProperties(Element*, StyleResolverState&);
struct CacheSuccess {
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 6a45207dc60..339a4dc6731 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -101,10 +101,6 @@ StyleResolverState::~StyleResolverState() {
animation_update_.Clear();
}
-TreeScope& StyleResolverState::GetTreeScope() const {
- return GetElement().GetTreeScope();
-}
-
void StyleResolverState::SetStyle(scoped_refptr<ComputedStyle> style) {
// FIXME: Improve RAII of StyleResolverState to remove this function.
style_ = std::move(style);
@@ -151,9 +147,11 @@ void StyleResolverState::SetLayoutParentStyle(
void StyleResolverState::LoadPendingResources() {
if (pseudo_request_type_ == PseudoElementStyleRequest::kForComputedStyle ||
(ParentStyle() && ParentStyle()->IsEnsuredInDisplayNone()) ||
- StyleRef().Display() == EDisplay::kNone ||
- StyleRef().IsEnsuredOutsideFlatTree())
+ (StyleRef().Display() == EDisplay::kNone &&
+ !GetElement().LayoutObjectIsNeeded(StyleRef())) ||
+ StyleRef().IsEnsuredOutsideFlatTree()) {
return;
+ }
if (StyleRef().StyleType() == kPseudoIdTargetText) {
// Do not load any resources for ::target-text since that could leak text
@@ -226,14 +224,4 @@ const CSSValue& StyleResolverState::ResolveLightDarkPair(
return value;
}
-void StyleResolverState::MarkDependency(const CSSProperty& property) {
- if (!RuntimeEnabledFeatures::CSSMatchedPropertiesCacheDependenciesEnabled())
- return;
- if (!HasValidDependencies())
- return;
-
- has_incomparable_dependency_ |= !property.IsComputedValueComparable();
- dependencies_.insert(property.GetCSSPropertyName());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index 3b1172e4247..f9883f4e4d6 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -77,7 +77,6 @@ class CORE_EXPORT StyleResolverState {
Document& GetDocument() const { return *document_; }
// These are all just pass-through methods to ElementResolveContext.
Element& GetElement() const { return element_context_.GetElement(); }
- TreeScope& GetTreeScope() const;
const ContainerNode* ParentNode() const {
return element_context_.ParentNode();
}
@@ -89,9 +88,6 @@ class CORE_EXPORT StyleResolverState {
EInsideLink ElementLinkState() const {
return element_context_.ElementLinkState();
}
- bool DistributedToV0InsertionPoint() const {
- return element_context_.DistributedToV0InsertionPoint();
- }
const ElementResolveContext& ElementContext() const {
return element_context_;
@@ -169,9 +165,6 @@ class CORE_EXPORT StyleResolverState {
void SetWritingMode(WritingMode);
void SetTextOrientation(ETextOrientation);
- void SetHasDirAutoAttribute(bool value) { has_dir_auto_attribute_ = value; }
- bool HasDirAutoAttribute() const { return has_dir_auto_attribute_; }
-
CSSParserMode GetParserMode() const;
// If the input CSSValue is a CSSLightDarkValuePair, return the light or dark
@@ -181,54 +174,6 @@ class CORE_EXPORT StyleResolverState {
// stored in the MatchedPropertiesCache.
const CSSValue& ResolveLightDarkPair(const CSSProperty&, const CSSValue&);
- // The dependencies we track here end up in an entry in the
- // MatchedPropertiesCache. Declarations such as "all:inherit" incurs several
- // hundred dependencies, which is too big to cache, hence the number of
- // dependencies we can track is limited.
- static const size_t kMaxDependencies = 8;
-
- // Mark the ComputedStyle as possibly dependent on the specified property.
- //
- // A "dependency" in this context means that one or more of the computed
- // values held by the ComputedStyle depends on the computed value of the
- // parent ComputedStyle.
- //
- // For example, a declaration such as background-color:var(--x) would incur
- // a dependency on --x.
- void MarkDependency(const CSSProperty&);
-
- // Returns the set of all properties seen by MarkDependency.
- //
- // The caller must check if the dependencies are valid via
- // HasValidDependencies() before calling this function.
- //
- // Note that this set might be larger than the actual set of dependencies,
- // as we do some degree of over-marking to keep the implementation simple.
- //
- // For example, we mark all custom properties referenced as dependencies, even
- // though the ComputedStyle itself may define a value for some or all of those
- // custom properties. In the following example, both --x and --y will be
- // added to this set, even though only --y is a true dependency:
- //
- // div {
- // --x: 10px;
- // margin: var(--x) (--y);
- // }
- //
- const HashSet<CSSPropertyName>& Dependencies() const {
- DCHECK(HasValidDependencies());
- return dependencies_;
- }
-
- // True if there's a dependency without the kComputedValueComparable flag.
- bool HasIncomparableDependency() const {
- return has_incomparable_dependency_;
- }
-
- bool HasValidDependencies() const {
- return dependencies_.size() <= kMaxDependencies;
- }
-
void SetCanCacheBaseStyle(bool state) { can_cache_base_style_ = state; }
bool CanCacheBaseStyle() const { return can_cache_base_style_; }
@@ -262,7 +207,6 @@ class CORE_EXPORT StyleResolverState {
CSSAnimationUpdate animation_update_;
bool is_animation_interpolation_map_ready_ = false;
- bool has_dir_auto_attribute_ = false;
PseudoElementStyleRequest::RequestType pseudo_request_type_;
FontBuilder font_builder_;
@@ -271,13 +215,6 @@ class CORE_EXPORT StyleResolverState {
Element* pseudo_element_;
ElementType element_type_;
- // Properties depended on by the ComputedStyle. This is known after the
- // cascade is applied.
- HashSet<CSSPropertyName> dependencies_;
- // True if there's an entry in 'dependencies_' which does not have the
- // CSSProperty::kComputedValueComparable flag set.
- bool has_incomparable_dependency_ = false;
-
// True if the base style can be cached to optimize style recalculations for
// animation updates or transition retargeting.
bool can_cache_base_style_ = false;
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state_test.cc
deleted file mode 100644
index f78d52131d6..00000000000
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_state_test.cc
+++ /dev/null
@@ -1,66 +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/core/css/resolver/style_resolver_state.h"
-#include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-
-namespace blink {
-
-class StyleResolverStateTest
- : public PageTestBase,
- private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
- public:
- StyleResolverStateTest()
- : ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
-};
-
-TEST_F(StyleResolverStateTest, Dependencies) {
- StyleResolverState state(GetDocument(), *GetDocument().body(), nullptr,
- nullptr);
-
- EXPECT_TRUE(state.Dependencies().IsEmpty());
-
- const auto& left = GetCSSPropertyLeft();
- const auto& right = GetCSSPropertyRight();
- const auto& incomparable = GetCSSPropertyInternalEmptyLineHeight();
-
- state.MarkDependency(left);
- EXPECT_EQ(1u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(left.GetCSSPropertyName()));
- EXPECT_FALSE(state.HasIncomparableDependency());
-
- state.MarkDependency(right);
- EXPECT_EQ(2u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(left.GetCSSPropertyName()));
- EXPECT_TRUE(state.Dependencies().Contains(right.GetCSSPropertyName()));
- EXPECT_FALSE(state.HasIncomparableDependency());
-
- state.MarkDependency(incomparable);
- EXPECT_EQ(3u, state.Dependencies().size());
- EXPECT_TRUE(state.Dependencies().Contains(left.GetCSSPropertyName()));
- EXPECT_TRUE(state.Dependencies().Contains(right.GetCSSPropertyName()));
- EXPECT_TRUE(state.Dependencies().Contains(incomparable.GetCSSPropertyName()));
- EXPECT_TRUE(state.HasIncomparableDependency());
-}
-
-TEST_F(StyleResolverStateTest, MaxDependencies) {
- StyleResolverState state(GetDocument(), *GetDocument().body(), nullptr,
- nullptr);
-
- EXPECT_TRUE(state.HasValidDependencies());
-
- for (size_t i = 0; i < StyleResolverState::kMaxDependencies; ++i) {
- auto name = AtomicString(String::Format("--v%zu", i));
- state.MarkDependency(CustomProperty(name, GetDocument()));
- EXPECT_TRUE(state.HasValidDependencies());
- }
-
- state.MarkDependency(CustomProperty("--exceeds-limit", GetDocument()));
- EXPECT_FALSE(state.HasValidDependencies());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
index d985f59d94b..fdc6c75f36f 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -33,7 +33,8 @@ class StyleResolverTest : public PageTestBase {
public:
scoped_refptr<ComputedStyle> StyleForId(AtomicString id) {
Element* element = GetDocument().getElementById(id);
- auto style = GetStyleEngine().GetStyleResolver().StyleForElement(element);
+ auto style = GetStyleEngine().GetStyleResolver().StyleForElement(
+ element, StyleRecalcContext());
DCHECK(style);
return style;
}
@@ -82,8 +83,9 @@ TEST_F(StyleResolverTest, AnimationBaseComputedStyle) {
animations.SetAnimationStyleChange(true);
StyleResolver& resolver = GetStyleEngine().GetStyleResolver();
- ASSERT_TRUE(resolver.StyleForElement(div));
- EXPECT_EQ(20, resolver.StyleForElement(div)->FontSize());
+ ASSERT_TRUE(resolver.StyleForElement(div, StyleRecalcContext()));
+ EXPECT_EQ(20,
+ resolver.StyleForElement(div, StyleRecalcContext())->FontSize());
ASSERT_TRUE(animations.BaseComputedStyle());
EXPECT_EQ(20, animations.BaseComputedStyle()->FontSize());
@@ -91,31 +93,14 @@ TEST_F(StyleResolverTest, AnimationBaseComputedStyle) {
// animation base computed style.
const ComputedStyle* parent_style =
GetDocument().documentElement()->GetComputedStyle();
- EXPECT_EQ(
- 10,
- resolver.StyleForElement(div, parent_style, parent_style)->FontSize());
+ EXPECT_EQ(10, resolver
+ .StyleForElement(div, StyleRecalcContext(), parent_style,
+ parent_style)
+ ->FontSize());
ASSERT_TRUE(animations.BaseComputedStyle());
EXPECT_EQ(20, animations.BaseComputedStyle()->FontSize());
- EXPECT_EQ(20, resolver.StyleForElement(div)->FontSize());
-}
-
-TEST_F(StyleResolverTest, ShadowDOMV0Crash) {
- GetDocument().documentElement()->setInnerHTML(R"HTML(
- <style>
- span { display: contents; }
- </style>
- <summary><span id="outer"><span id="inner"></b></b></summary>
- )HTML");
-
- Element* outer = GetDocument().getElementById("outer");
- Element* inner = GetDocument().getElementById("inner");
- ShadowRoot& outer_root = outer->CreateV0ShadowRootForTesting();
- ShadowRoot& inner_root = inner->CreateV0ShadowRootForTesting();
- outer_root.setInnerHTML("<content>");
- inner_root.setInnerHTML("<span>");
-
- // Test passes if it doesn't crash.
- UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(20,
+ resolver.StyleForElement(div, StyleRecalcContext())->FontSize());
}
TEST_F(StyleResolverTest, HasEmUnits) {
@@ -256,34 +241,6 @@ TEST_F(StyleResolverTest, AnimationMaskedByImportant) {
EXPECT_FALSE(StyleResolver::CanReuseBaseComputedStyle(state));
}
-TEST_F(StyleResolverTest, CachedExplicitInheritanceFlags) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(true);
-
- GetDocument().documentElement()->setInnerHTML(R"HTML(
- <style>
- #outer { height: 10px; }
- #inner { height: inherit; }
- </style>
- <div id=outer>
- <div id=inner></div>
- </div>
- )HTML");
- UpdateAllLifecyclePhasesForTest();
-
- Element* outer = GetDocument().getElementById("outer");
- ASSERT_TRUE(outer);
- EXPECT_TRUE(outer->ComputedStyleRef().ChildHasExplicitInheritance());
-
- auto recalc_reason = StyleChangeReasonForTracing::Create("test");
-
- // This will hit the MatchedPropertiesCache for both #outer/#inner,
- // which means special care must be taken for the ChildHasExplicit-
- // Inheritance flag to persist.
- GetStyleEngine().MarkAllElementsForStyleRecalc(recalc_reason);
- UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(outer->ComputedStyleRef().ChildHasExplicitInheritance());
-}
-
TEST_F(StyleResolverTest,
TransitionRetargetRelativeFontSizeOnParentlessElement) {
GetDocument().documentElement()->setInnerHTML(R"HTML(
@@ -314,7 +271,7 @@ TEST_F(StyleResolverTest,
EXPECT_EQ("20px", ComputedValue("font-size", *StyleForId("target")));
// Bump the animation time to ensure a transition reversal.
- transition->setCurrentTime(50);
+ transition->setCurrentTime(CSSNumberish::FromDouble(50));
transition->pause();
UpdateAllLifecyclePhasesForTest();
const String before_reversal_font_size =
@@ -358,7 +315,7 @@ TEST_F(StyleResolverTest, NonCachableStyleCheckDoesNotAffectBaseComputedStyle) {
EXPECT_TRUE(transition);
// Advance to the midpoint of the transition.
- transition->setCurrentTime(500);
+ transition->setCurrentTime(CSSNumberish::FromDouble(500));
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ("rgb(0, 64, 0)", ComputedValue("color", *StyleForId("target")));
EXPECT_TRUE(element_animations->BaseComputedStyle());
@@ -368,7 +325,8 @@ TEST_F(StyleResolverTest, NonCachableStyleCheckDoesNotAffectBaseComputedStyle) {
// Perform a non-cacheable style resolution, and ensure that the base computed
// style is not updated.
GetStyleEngine().GetStyleResolver().StyleForElement(
- target, nullptr, nullptr, kMatchAllRulesExcludingSMIL);
+ target, StyleRecalcContext(), nullptr, nullptr,
+ kMatchAllRulesExcludingSMIL);
EXPECT_FALSE(element_animations->BaseComputedStyle());
// Computing the style with default args updates the base computed style.
@@ -434,6 +392,30 @@ INSTANTIATE_TEST_SUITE_P(All,
StyleResolverFontRelativeUnitTest,
testing::Values("em", "rem", "ex", "ch"));
+// TODO(crbug.com/1180159): Remove this test when @container and transitions
+// work properly.
+TEST_F(StyleResolverTest, BaseNotReusableWithContainerQueries) {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
+
+ GetDocument().documentElement()->setInnerHTML("<div id=div>Test</div>");
+ UpdateAllLifecyclePhasesForTest();
+ Element* div = GetDocument().getElementById("div");
+
+ auto* effect = CreateSimpleKeyframeEffectForTest(div, CSSPropertyID::kWidth,
+ "50px", "100px");
+ GetDocument().Timeline().Play(effect);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("50px", ComputedValue("width", *StyleForId("div")));
+
+ div->SetNeedsAnimationStyleRecalc();
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ StyleForId("div");
+
+ StyleResolverState state(GetDocument(), *div);
+ EXPECT_FALSE(StyleResolver::CanReuseBaseComputedStyle(state));
+}
+
namespace {
const CSSImageValue& GetBackgroundImageValue(const ComputedStyle& style) {
@@ -495,6 +477,11 @@ TEST_F(StyleResolverTest, BackgroundImageFetch) {
#first-line-none::first-line {
background-image: url(first-line-none.png);
}
+ frameset {
+ display: none;
+ border-color: currentColor; /* UA inherit defeats caching */
+ background-image: url(frameset-none.png);
+ }
</style>
<div id="none">
<div id="inside-none"></div>
@@ -515,6 +502,11 @@ TEST_F(StyleResolverTest, BackgroundImageFetch) {
<div id="first-line-none">XXX</div>
)HTML");
+ auto* frameset1 = GetDocument().CreateRawElement(html_names::kFramesetTag);
+ auto* frameset2 = GetDocument().CreateRawElement(html_names::kFramesetTag);
+ GetDocument().documentElement()->AppendChild(frameset1);
+ GetDocument().documentElement()->AppendChild(frameset2);
+
GetDocument().getElementById("host")->AttachShadowRootInternal(
ShadowRootType::kOpen);
UpdateAllLifecyclePhasesForTest();
@@ -566,6 +558,17 @@ TEST_F(StyleResolverTest, BackgroundImageFetch) {
<< "Fetch for image inherited from display:contents";
EXPECT_TRUE(GetBackgroundImageValue(non_slotted).IsCachePending())
<< "No fetch for element outside the flat tree";
+
+ // Added two frameset elements to hit the MatchedPropertiesCache for the
+ // second one. Frameset adjusts style to display:block in StyleAdjuster, but
+ // adjustments are not run before ComputedStyle is added to the
+ // MatchedPropertiesCache leaving the cached style with StylePendingImage
+ // unless we also check for LayoutObjectIsNeeded in
+ // StyleResolverState::LoadPendingImages.
+ EXPECT_FALSE(GetBackgroundImageValue(frameset1).IsCachePending())
+ << "Fetch for display:none frameset";
+ EXPECT_FALSE(GetBackgroundImageValue(frameset2).IsCachePending())
+ << "Fetch for display:none frameset - cached";
}
TEST_F(StyleResolverTest, NoFetchForAtPage) {
@@ -615,14 +618,16 @@ TEST_F(StyleResolverTest, NoFetchForHighlightPseudoElements) {
scoped_refptr<ComputedStyle> target_text_style =
GetDocument().GetStyleResolver().PseudoStyleForElement(
- GetDocument().body(), PseudoElementStyleRequest(kPseudoIdTargetText),
- element_style, element_style);
+ GetDocument().body(), StyleRecalcContext(),
+ PseudoElementStyleRequest(kPseudoIdTargetText), element_style,
+ element_style);
ASSERT_TRUE(target_text_style);
scoped_refptr<ComputedStyle> selection_style =
GetDocument().GetStyleResolver().PseudoStyleForElement(
- GetDocument().body(), PseudoElementStyleRequest(kPseudoIdSelection),
- element_style, element_style);
+ GetDocument().body(), StyleRecalcContext(),
+ PseudoElementStyleRequest(kPseudoIdSelection), element_style,
+ element_style);
ASSERT_TRUE(selection_style);
// Check that we don't fetch the cursor url() for ::target-text.
@@ -729,8 +734,6 @@ TEST_F(StyleResolverTest, CSSMarkerPseudoElement) {
}
TEST_F(StyleResolverTest, ApplyInheritedOnlyCustomPropertyChange) {
- ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(true);
-
// This test verifies that when we get a "apply inherited only"-type
// hit in the MatchesPropertiesCache, we're able to detect that custom
// properties changed, and that we therefore need to apply the non-inherited
@@ -975,8 +978,9 @@ TEST_F(StyleResolverTest, TreeScopedReferences) {
StyleResolverState state(GetDocument(), *host);
SelectorFilter filter;
MatchResult match_result;
- ElementRuleCollector collector(state.ElementContext(), filter, match_result,
- state.Style(), EInsideLink::kNotInsideLink);
+ ElementRuleCollector collector(state.ElementContext(), StyleRecalcContext(),
+ filter, match_result, state.Style(),
+ EInsideLink::kNotInsideLink);
GetDocument().GetStyleEngine().GetStyleResolver().MatchAllRules(
state, collector, false /* include_smil_properties */);
const auto& properties = match_result.GetMatchedProperties();
@@ -1001,8 +1005,9 @@ TEST_F(StyleResolverTest, TreeScopedReferences) {
StyleResolverState state(GetDocument(), *span);
SelectorFilter filter;
MatchResult match_result;
- ElementRuleCollector collector(state.ElementContext(), filter, match_result,
- state.Style(), EInsideLink::kNotInsideLink);
+ ElementRuleCollector collector(state.ElementContext(), StyleRecalcContext(),
+ filter, match_result, state.Style(),
+ EInsideLink::kNotInsideLink);
GetDocument().GetStyleEngine().GetStyleResolver().MatchAllRules(
state, collector, false /* include_smil_properties */);
const auto& properties = match_result.GetMatchedProperties();
@@ -1094,18 +1099,112 @@ TEST_F(StyleResolverTest, InheritStyleImagesFromDisplayContents) {
<< "-webkit-mask-image is fetched";
}
-// https://crbug.com/1145406
-TEST_F(StyleResolverTest, StyleSheetWithNullRuleSet) {
- ScopedCSSKeyframesMemoryReductionForTest enabled_scope(true);
+TEST_F(StyleResolverTest, DependsOnContainerQueries) {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
GetDocument().documentElement()->setInnerHTML(R"HTML(
- <style>.c6 { animation-name: anim; }</style>
- <style media=print></style>
- <div class=c6></div>
+ <style>
+ #a { color: red; }
+ @container (min-width: 0px) {
+ #b { color: blue; }
+ span { color: green; }
+ #d { color: coral; }
+ }
+ </style>
+ <div id=a></div>
+ <span id=b></span>
+ <span id=c></span>
+ <div id=d></div>
+ <div id=e></div>
)HTML");
- // Should not crash inside
UpdateAllLifecyclePhasesForTest();
+
+ auto* a = GetDocument().getElementById("a");
+ auto* b = GetDocument().getElementById("b");
+ auto* c = GetDocument().getElementById("c");
+ auto* d = GetDocument().getElementById("d");
+ auto* e = GetDocument().getElementById("e");
+
+ ASSERT_TRUE(a);
+ ASSERT_TRUE(b);
+ ASSERT_TRUE(c);
+ ASSERT_TRUE(d);
+ ASSERT_TRUE(e);
+
+ EXPECT_FALSE(a->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_TRUE(b->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_TRUE(c->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_TRUE(d->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_FALSE(e->ComputedStyleRef().DependsOnContainerQueries());
+}
+
+TEST_F(StyleResolverTest, DependsOnContainerQueriesPseudo) {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
+
+ GetDocument().documentElement()->setInnerHTML(R"HTML(
+ <style>
+ main { contain: size layout; width: 100px; }
+ #a::before { content: "before"; }
+ @container (min-width: 0px) {
+ #a::after { content: "after"; }
+ }
+ </style>
+ <main>
+ <div id=a></div>
+ </main>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+
+ auto* a = GetDocument().getElementById("a");
+ auto* before = a->GetPseudoElement(kPseudoIdBefore);
+ auto* after = a->GetPseudoElement(kPseudoIdAfter);
+
+ ASSERT_TRUE(a);
+ ASSERT_TRUE(before);
+ ASSERT_TRUE(after);
+
+ EXPECT_TRUE(a->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_FALSE(before->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_TRUE(after->ComputedStyleRef().DependsOnContainerQueries());
+}
+
+// Verify that the ComputedStyle::DependsOnContainerQuery flag does
+// not end up in the MatchedPropertiesCache (MPC).
+TEST_F(StyleResolverTest, DependsOnContainerQueriesMPC) {
+ ScopedCSSContainerQueriesForTest scoped_feature(true);
+
+ GetDocument().documentElement()->setInnerHTML(R"HTML(
+ <style>
+ @container (min-width: 9999999px) {
+ #a { color: green; }
+ }
+ </style>
+ <div id=a></div>
+ <div id=b></div>
+ )HTML");
+
+ // In the above example, both <div id=a> and <div id=b> match the same
+ // rules (i.e. whatever is provided by UA style). The selector inside
+ // the @container rule does ultimately _not_ match <div id=a> (because the
+ // container query evaluates to 'false'), however, it _does_ cause the
+ // ComputedStyle::DependsOnContainerQuery flag to be set on #a.
+ //
+ // We must ensure that we don't add the DependsOnContainerQuery-flagged
+ // style to the MPC, otherwise the subsequent cache hit for #b would result
+ // in the flag being (incorrectly) set for that element.
+
+ UpdateAllLifecyclePhasesForTest();
+
+ auto* a = GetDocument().getElementById("a");
+ auto* b = GetDocument().getElementById("b");
+
+ ASSERT_TRUE(a);
+ ASSERT_TRUE(b);
+
+ EXPECT_TRUE(a->ComputedStyleRef().DependsOnContainerQueries());
+ EXPECT_FALSE(b->ComputedStyleRef().DependsOnContainerQueries());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc b/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
index 978975c7a75..59e969843b1 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
@@ -36,7 +36,6 @@
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
#include "third_party/blink/renderer/core/css/document_style_sheet_collection.h"
-#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/core/css/style_rule_import.h"
@@ -50,7 +49,6 @@
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/viewport_description.h"
namespace blink {
@@ -67,15 +65,10 @@ bool HasViewportFitProperty(const CSSPropertyValueSet* property_set) {
ViewportStyleResolver::ViewportStyleResolver(Document& document)
: document_(document) {
DCHECK(document.GetFrame());
- initial_viewport_medium_ = MakeGarbageCollected<MediaQueryEvaluator>(
- MakeGarbageCollected<MediaValuesInitialViewport>(*document.GetFrame()));
}
void ViewportStyleResolver::Reset() {
- viewport_dependent_media_query_results_.clear();
- device_dependent_media_query_results_.clear();
property_set_ = nullptr;
- has_author_style_ = false;
has_viewport_units_ = false;
DCHECK(initial_style_);
initial_style_->SetHasViewportUnits(false);
@@ -101,92 +94,38 @@ void ViewportStyleResolver::CollectViewportRulesFromUASheets() {
break;
}
if (viewport_contents)
- CollectViewportChildRules(viewport_contents->ChildRules(),
- kUserAgentOrigin);
+ CollectViewportRules(viewport_contents->ChildRules());
if (document_->IsMobileDocument()) {
- CollectViewportChildRules(
- default_style_sheets.EnsureXHTMLMobileProfileStyleSheet()->ChildRules(),
- kUserAgentOrigin);
+ CollectViewportRules(
+ default_style_sheets.EnsureXHTMLMobileProfileStyleSheet()
+ ->ChildRules());
}
DCHECK(!default_style_sheets.DefaultStyleSheet()->HasViewportRule());
}
-void ViewportStyleResolver::CollectViewportChildRules(
- const HeapVector<Member<StyleRuleBase>>& rules,
- Origin origin) {
+void ViewportStyleResolver::CollectViewportRules(
+ const HeapVector<Member<StyleRuleBase>>& rules) {
for (auto& rule : rules) {
- if (auto* viewport_rule = DynamicTo<StyleRuleViewport>(rule.Get())) {
- AddViewportRule(*viewport_rule, origin);
- } else if (auto* media_rule = DynamicTo<StyleRuleMedia>(rule.Get())) {
- if (!media_rule->MediaQueries() ||
- initial_viewport_medium_->Eval(
- *media_rule->MediaQueries(),
- &viewport_dependent_media_query_results_,
- &device_dependent_media_query_results_))
- CollectViewportChildRules(media_rule->ChildRules(), origin);
- } else if (auto* supports_rule = DynamicTo<StyleRuleSupports>(rule.Get())) {
- if (supports_rule->ConditionIsSupported())
- CollectViewportChildRules(supports_rule->ChildRules(), origin);
- }
- }
-}
-
-void ViewportStyleResolver::CollectViewportRulesFromImports(
- StyleSheetContents& contents) {
- for (const auto& import_rule : contents.ImportRules()) {
- if (!import_rule->GetStyleSheet())
- continue;
- if (!import_rule->GetStyleSheet()->HasViewportRule())
- continue;
- if (import_rule->MediaQueries() &&
- initial_viewport_medium_->Eval(*import_rule->MediaQueries(),
- &viewport_dependent_media_query_results_,
- &device_dependent_media_query_results_))
- CollectViewportRulesFromAuthorSheetContents(
- *import_rule->GetStyleSheet());
+ if (auto* viewport_rule = DynamicTo<StyleRuleViewport>(rule.Get()))
+ AddViewportRule(*viewport_rule);
}
}
-void ViewportStyleResolver::CollectViewportRulesFromAuthorSheetContents(
- StyleSheetContents& contents) {
- CollectViewportRulesFromImports(contents);
- if (contents.HasViewportRule())
- CollectViewportChildRules(contents.ChildRules(), kAuthorOrigin);
-}
-
-void ViewportStyleResolver::CollectViewportRulesFromAuthorSheet(
- const CSSStyleSheet& sheet) {
- DCHECK(sheet.Contents());
- StyleSheetContents& contents = *sheet.Contents();
- if (!contents.HasViewportRule() && contents.ImportRules().IsEmpty())
- return;
- if (sheet.MediaQueries() &&
- !initial_viewport_medium_->Eval(*sheet.MediaQueries(),
- &viewport_dependent_media_query_results_,
- &device_dependent_media_query_results_))
- return;
- CollectViewportRulesFromAuthorSheetContents(contents);
-}
-
-void ViewportStyleResolver::AddViewportRule(StyleRuleViewport& viewport_rule,
- Origin origin) {
+void ViewportStyleResolver::AddViewportRule(StyleRuleViewport& viewport_rule) {
CSSPropertyValueSet& property_set = viewport_rule.MutableProperties();
unsigned property_count = property_set.PropertyCount();
if (!property_count)
return;
- if (origin == kAuthorOrigin)
- has_author_style_ = true;
-
if (!property_set_) {
property_set_ = property_set.MutableCopy();
return;
}
- // We cannot use mergeAndOverrideOnConflict() here because it doesn't
- // respect the !important declaration (but addRespectingCascade() does).
+ // We cannot use MergeAndOverrideOnConflict() here because it doesn't
+ // respect the !important declaration (but AddRespectingCascade() does).
for (unsigned i = 0; i < property_count; ++i) {
CSSPropertyValueSet::PropertyReference property =
property_set.PropertyAt(i);
@@ -202,9 +141,7 @@ void ViewportStyleResolver::Resolve() {
return;
}
- ViewportDescription description(
- has_author_style_ ? ViewportDescription::kAuthorStyleSheet
- : ViewportDescription::kUserAgentStyleSheet);
+ ViewportDescription description(ViewportDescription::kUserAgentStyleSheet);
description.user_zoom = ViewportArgumentValue(CSSPropertyID::kUserZoom);
description.zoom = ViewportArgumentValue(CSSPropertyID::kZoom);
@@ -357,11 +294,6 @@ void ViewportStyleResolver::InitialViewportChanged() {
return;
if (has_viewport_units_)
needs_update_ = kResolve;
-
- if (initial_viewport_medium_->DidResultsChange(
- viewport_dependent_media_query_results_)) {
- needs_update_ = kCollectRules;
- }
if (needs_update_ == kNoUpdate)
return;
document_->ScheduleLayoutTreeUpdateIfNeeded();
@@ -393,7 +325,6 @@ void ViewportStyleResolver::UpdateViewport(
void ViewportStyleResolver::Trace(Visitor* visitor) const {
visitor->Trace(document_);
visitor->Trace(property_set_);
- visitor->Trace(initial_viewport_medium_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h b/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
index 4ce4c71f7ed..d12a8068355 100644
--- a/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
+++ b/chromium/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
@@ -63,15 +63,11 @@ class CORE_EXPORT ViewportStyleResolver final
void Reset();
void Resolve();
- enum Origin { kUserAgentOrigin, kAuthorOrigin };
enum UpdateType { kNoUpdate, kResolve, kCollectRules };
void CollectViewportRulesFromUASheets();
- void CollectViewportChildRules(const HeapVector<Member<StyleRuleBase>>&,
- Origin);
- void CollectViewportRulesFromImports(StyleSheetContents&);
- void CollectViewportRulesFromAuthorSheetContents(StyleSheetContents&);
- void AddViewportRule(StyleRuleViewport&, Origin);
+ void CollectViewportRules(const HeapVector<Member<StyleRuleBase>>&);
+ void AddViewportRule(StyleRuleViewport&);
float ViewportArgumentValue(CSSPropertyID) const;
Length ViewportLengthValue(CSSPropertyID);
@@ -79,11 +75,7 @@ class CORE_EXPORT ViewportStyleResolver final
Member<Document> document_;
Member<MutableCSSPropertyValueSet> property_set_;
- Member<MediaQueryEvaluator> initial_viewport_medium_;
scoped_refptr<ComputedStyle> initial_style_;
- MediaQueryResultList viewport_dependent_media_query_results_;
- MediaQueryResultList device_dependent_media_query_results_;
- bool has_author_style_ = false;
bool has_viewport_units_ = false;
UpdateType needs_update_ = kCollectRules;
};
diff --git a/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc b/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
index aa23290e085..60e6106dde7 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_feature_set.cc
@@ -128,8 +128,10 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) {
case CSSSelector::kPseudoModal:
case CSSSelector::kPseudoBackdrop:
case CSSSelector::kPseudoLang:
+ case CSSSelector::kPseudoDir:
case CSSSelector::kPseudoNot:
case CSSSelector::kPseudoPlaceholder:
+ case CSSSelector::kPseudoFileSelectorButton:
case CSSSelector::kPseudoResizer:
case CSSSelector::kPseudoRoot:
case CSSSelector::kPseudoScope:
@@ -162,11 +164,8 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) {
case CSSSelector::kPseudoCue:
case CSSSelector::kPseudoFutureCue:
case CSSSelector::kPseudoPastCue:
- case CSSSelector::kPseudoUnresolved:
case CSSSelector::kPseudoDefined:
- case CSSSelector::kPseudoContent:
case CSSSelector::kPseudoHost:
- case CSSSelector::kPseudoShadow:
case CSSSelector::kPseudoSpatialNavigationFocus:
case CSSSelector::kPseudoSpatialNavigationInterest:
case CSSSelector::kPseudoHasDatalist:
@@ -174,6 +173,7 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) {
case CSSSelector::kPseudoListBox:
case CSSSelector::kPseudoMultiSelectFocus:
case CSSSelector::kPseudoHostHasAppearance:
+ case CSSSelector::kPseudoPopupOpen:
case CSSSelector::kPseudoSlotted:
case CSSSelector::kPseudoVideoPersistent:
case CSSSelector::kPseudoVideoPersistentAncestor:
@@ -181,6 +181,8 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) {
case CSSSelector::kPseudoIs:
case CSSSelector::kPseudoWhere:
case CSSSelector::kPseudoTargetText:
+ case CSSSelector::kPseudoSpellingError:
+ case CSSSelector::kPseudoGrammarError:
return true;
case CSSSelector::kPseudoUnknown:
case CSSSelector::kPseudoLeftPage:
@@ -500,13 +502,10 @@ void RuleFeatureSet::UpdateFeaturesFromCombinator(
sibling_features = nullptr;
- if (last_in_compound.IsShadowSelector())
+ if (last_in_compound.IsUAShadowSelector())
descendant_features.invalidation_flags.SetTreeBoundaryCrossing(true);
- if (last_in_compound.Relation() == CSSSelector::kShadowSlot ||
- last_in_compound.RelationIsAffectedByPseudoContent())
+ if (last_in_compound.Relation() == CSSSelector::kShadowSlot)
descendant_features.invalidation_flags.SetInsertionPointCrossing(true);
- if (last_in_compound.RelationIsAffectedByPseudoContent())
- descendant_features.content_pseudo_crossing = true;
}
void RuleFeatureSet::ExtractInvalidationSetFeaturesFromSimpleSelector(
@@ -595,14 +594,15 @@ InvalidationSet* RuleFeatureSet::InvalidationSetForSimpleSelector(
case CSSSelector::kPseudoIndeterminate:
case CSSSelector::kPseudoTarget:
case CSSSelector::kPseudoLang:
+ case CSSSelector::kPseudoDir:
case CSSSelector::kPseudoFullScreen:
case CSSSelector::kPseudoFullScreenAncestor:
case CSSSelector::kPseudoFullscreen:
case CSSSelector::kPseudoPictureInPicture:
case CSSSelector::kPseudoInRange:
case CSSSelector::kPseudoOutOfRange:
- case CSSSelector::kPseudoUnresolved:
case CSSSelector::kPseudoDefined:
+ case CSSSelector::kPseudoPopupOpen:
case CSSSelector::kPseudoVideoPersistent:
case CSSSelector::kPseudoVideoPersistentAncestor:
case CSSSelector::kPseudoXrOverlay:
@@ -888,8 +888,6 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForSelectorList(
if (simple_selector.IsHostPseudoClass())
descendant_features.invalidation_flags.SetTreeBoundaryCrossing(true);
- if (simple_selector.IsV0InsertionPointCrossing())
- descendant_features.invalidation_flags.SetInsertionPointCrossing(true);
descendant_features.has_features_for_rule_set_invalidation = false;
diff --git a/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc b/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
index 5d1c551714a..a2c62fd028e 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_feature_set_test.cc
@@ -61,8 +61,9 @@ class RuleFeatureSetTest : public testing::Test {
RuleFeatureSet::SelectorPreMatch result =
RuleFeatureSet::SelectorPreMatch::kSelectorNeverMatches;
for (unsigned i = 0; i < indices.size(); ++i) {
- RuleData* rule_data = RuleData::MaybeCreate(style_rule, indices[i], 0,
- kRuleHasNoSpecialState);
+ RuleData* rule_data = RuleData::MaybeCreate(
+ style_rule, indices[i], 0, kRuleHasNoSpecialState,
+ nullptr /* container_query */);
DCHECK(rule_data);
if (set.CollectFeaturesFromRuleData(rule_data))
result = RuleFeatureSet::SelectorPreMatch::kSelectorMayMatch;
@@ -599,22 +600,6 @@ TEST_F(RuleFeatureSetTest, tagName) {
ExpectTagNameInvalidation("e", invalidation_lists.descendants);
}
-TEST_F(RuleFeatureSetTest, contentPseudo) {
- EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
- CollectFeatures(".a ::content .b"));
- EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a .c"));
-
- InvalidationLists invalidation_lists;
- CollectInvalidationSetsForClass(invalidation_lists, "a");
- ExpectClassInvalidation("c", invalidation_lists.descendants);
-
- EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a .b"));
-
- invalidation_lists.descendants.clear();
- CollectInvalidationSetsForClass(invalidation_lists, "a");
- ExpectClassInvalidation("b", "c", invalidation_lists.descendants);
-}
-
TEST_F(RuleFeatureSetTest, nonMatchingHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches, CollectFeatures(".a:host"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
@@ -1622,7 +1607,6 @@ RefTestData ref_not_equal_test_data[] = {
{"", ":host"},
{"", ":host(.a)"},
{"", ":host-context(.a)"},
- {"", "::content"},
{"", "*"},
{"", ":not(.a)"},
{".a", ".b"},
diff --git a/chromium/third_party/blink/renderer/core/css/rule_set.cc b/chromium/third_party/blink/renderer/core/css/rule_set.cc
index 8228fedc697..98c9f9c39e3 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_set.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_set.cc
@@ -85,7 +85,8 @@ static unsigned DetermineLinkMatchType(const AddRuleFlags add_rule_flags,
RuleData* RuleData::MaybeCreate(StyleRule* rule,
unsigned selector_index,
unsigned position,
- AddRuleFlags add_rule_flags) {
+ AddRuleFlags add_rule_flags,
+ const ContainerQuery* container_query) {
// The selector index field in RuleData is only 13 bits so we can't support
// selectors at index 8192 or beyond.
// See https://crbug.com/804179
@@ -93,6 +94,11 @@ RuleData* RuleData::MaybeCreate(StyleRule* rule,
return nullptr;
if (position >= (1 << RuleData::kPositionBits))
return nullptr;
+ if (container_query) {
+ return MakeGarbageCollected<ExtendedRuleData>(
+ base::PassKey<RuleData>(), rule, selector_index, position,
+ add_rule_flags, container_query);
+ }
return MakeGarbageCollected<RuleData>(rule, selector_index, position,
add_rule_flags);
}
@@ -101,6 +107,13 @@ RuleData::RuleData(StyleRule* rule,
unsigned selector_index,
unsigned position,
AddRuleFlags add_rule_flags)
+ : RuleData(Type::kNormal, rule, selector_index, position, add_rule_flags) {}
+
+RuleData::RuleData(Type type,
+ StyleRule* rule,
+ unsigned selector_index,
+ unsigned position,
+ AddRuleFlags add_rule_flags)
: rule_(rule),
selector_index_(selector_index),
position_(position),
@@ -111,6 +124,7 @@ RuleData::RuleData(StyleRule* rule,
valid_property_filter_(
static_cast<std::underlying_type_t<ValidPropertyFilter>>(
DetermineValidPropertyFilter(add_rule_flags, Selector()))),
+ type_(static_cast<unsigned>(type)),
descendant_selector_identifier_hashes_() {
SelectorFilter::CollectIdentifierHashes(
Selector(), descendant_selector_identifier_hashes_,
@@ -157,7 +171,9 @@ static void ExtractSelectorValues(const CSSSelector* selector,
case CSSSelector::kPseudoWebkitAnyLink:
case CSSSelector::kPseudoAnyLink:
case CSSSelector::kPseudoFocus:
+ case CSSSelector::kPseudoFocusVisible:
case CSSSelector::kPseudoPlaceholder:
+ case CSSSelector::kPseudoFileSelectorButton:
case CSSSelector::kPseudoHost:
case CSSSelector::kPseudoHostContext:
case CSSSelector::kPseudoSpatialNavigationInterest:
@@ -222,7 +238,8 @@ bool RuleSet::FindBestRuleSetAndAdd(const CSSSelector& component,
DCHECK(id.IsEmpty());
DCHECK(class_name.IsEmpty());
AddToRuleSet(custom_pseudo_element_name,
- EnsurePendingRules()->shadow_pseudo_element_rules, rule_data);
+ EnsurePendingRules()->ua_shadow_pseudo_element_rules,
+ rule_data);
return true;
}
@@ -247,12 +264,18 @@ bool RuleSet::FindBestRuleSetAndAdd(const CSSSelector& component,
case CSSSelector::kPseudoFocus:
focus_pseudo_class_rules_.push_back(rule_data);
return true;
+ case CSSSelector::kPseudoFocusVisible:
+ focus_visible_pseudo_class_rules_.push_back(rule_data);
+ return true;
case CSSSelector::kPseudoPlaceholder:
+ case CSSSelector::kPseudoFileSelectorButton:
if (it->FollowsPart()) {
part_pseudo_rules_.push_back(rule_data);
} else {
- AddToRuleSet(shadow_element_names::kPseudoInputPlaceholder,
- EnsurePendingRules()->shadow_pseudo_element_rules,
+ const auto& name = pseudo_type == CSSSelector::kPseudoFileSelectorButton
+ ? shadow_element_names::kPseudoFileUploadButton
+ : shadow_element_names::kPseudoInputPlaceholder;
+ AddToRuleSet(name, EnsurePendingRules()->ua_shadow_pseudo_element_rules,
rule_data);
}
return true;
@@ -274,9 +297,10 @@ bool RuleSet::FindBestRuleSetAndAdd(const CSSSelector& component,
void RuleSet::AddRule(StyleRule* rule,
unsigned selector_index,
- AddRuleFlags add_rule_flags) {
- RuleData* rule_data =
- RuleData::MaybeCreate(rule, selector_index, rule_count_, add_rule_flags);
+ AddRuleFlags add_rule_flags,
+ const ContainerQuery* container_query) {
+ RuleData* rule_data = RuleData::MaybeCreate(rule, selector_index, rule_count_,
+ add_rule_flags, container_query);
if (!rule_data) {
// This can happen if selector_index or position is out of range.
return;
@@ -300,7 +324,7 @@ void RuleSet::AddRule(StyleRule* rule,
if (rule_data->LinkMatchType() == CSSSelector::kMatchLink) {
RuleData* visited_dependent = RuleData::MaybeCreate(
rule, rule_data->SelectorIndex(), rule_data->GetPosition(),
- add_rule_flags | kRuleIsVisitedDependent);
+ add_rule_flags | kRuleIsVisitedDependent, container_query);
DCHECK(visited_dependent);
visited_dependent_rules_.push_back(visited_dependent);
}
@@ -319,50 +343,6 @@ void RuleSet::AddFontFaceRule(StyleRuleFontFace* rule) {
void RuleSet::AddKeyframesRule(StyleRuleKeyframes* rule) {
EnsurePendingRules(); // So that keyframes_rules_.ShrinkToFit() gets called.
keyframes_rules_.push_back(rule);
- keyframes_rules_sorted_ = false;
-}
-
-void RuleSet::SortKeyframesRulesIfNeeded() {
- if (keyframes_rules_sorted_)
- return;
- // Sort keyframes rules by name, breaking ties with vendor prefixing.
- // Since equal AtomicStrings always have the same impl, there's no need to
- // actually compare the contents of two AtomicStrings. Comparing their impl
- // addresses is enough.
- std::stable_sort(
- keyframes_rules_.begin(), keyframes_rules_.end(),
- [](const StyleRuleKeyframes* lhs, const StyleRuleKeyframes* rhs) {
- if (lhs->GetName() != rhs->GetName())
- return lhs->GetName().Impl() < rhs->GetName().Impl();
- if (lhs->IsVendorPrefixed() != rhs->IsVendorPrefixed())
- return lhs->IsVendorPrefixed();
- return false;
- });
- // Deduplicate rules, erase all but the last one for each animation name,
- // since all the preceding ones are overridden.
- auto boundary = std::unique(
- keyframes_rules_.rbegin(), keyframes_rules_.rend(),
- [](const StyleRuleKeyframes* lhs, const StyleRuleKeyframes* rhs) {
- return lhs->GetName() == rhs->GetName();
- });
- keyframes_rules_.erase(keyframes_rules_.begin(), boundary.base());
- keyframes_rules_.ShrinkToFit();
- keyframes_rules_sorted_ = true;
-}
-
-StyleRuleKeyframes* RuleSet::KeyframeStylesForAnimation(
- const AtomicString& name) {
- SortKeyframesRulesIfNeeded();
- Member<StyleRuleKeyframes>* rule_iterator = std::lower_bound(
- keyframes_rules_.begin(), keyframes_rules_.end(), name,
- [](const StyleRuleKeyframes* rule, const AtomicString& name) {
- return rule->GetName().Impl() < name.Impl();
- });
- if (rule_iterator != keyframes_rules_.end() &&
- (*rule_iterator)->GetName() == name) {
- return *rule_iterator;
- }
- return nullptr;
}
void RuleSet::AddPropertyRule(StyleRuleProperty* rule) {
@@ -370,6 +350,12 @@ void RuleSet::AddPropertyRule(StyleRuleProperty* rule) {
property_rules_.push_back(rule);
}
+void RuleSet::AddCounterStyleRule(StyleRuleCounterStyle* rule) {
+ EnsurePendingRules(); // So that counter_style_rules_.ShrinkToFit() gets
+ // called.
+ counter_style_rules_.push_back(rule);
+}
+
void RuleSet::AddScrollTimelineRule(StyleRuleScrollTimeline* rule) {
EnsurePendingRules(); // So that property_rules_.ShrinkToFit() gets called.
scroll_timeline_rules_.push_back(rule);
@@ -377,7 +363,8 @@ void RuleSet::AddScrollTimelineRule(StyleRuleScrollTimeline* rule) {
void RuleSet::AddChildRules(const HeapVector<Member<StyleRuleBase>>& rules,
const MediaQueryEvaluator& medium,
- AddRuleFlags add_rule_flags) {
+ AddRuleFlags add_rule_flags,
+ const ContainerQuery* container_query) {
for (unsigned i = 0; i < rules.size(); ++i) {
StyleRuleBase* rule = rules[i].Get();
@@ -386,36 +373,42 @@ void RuleSet::AddChildRules(const HeapVector<Member<StyleRuleBase>>& rules,
for (const CSSSelector* selector = selector_list.First(); selector;
selector = selector_list.Next(*selector)) {
wtf_size_t selector_index = selector_list.SelectorIndex(*selector);
- if (selector->HasDeepCombinatorOrShadowPseudo()) {
- deep_combinator_or_shadow_pseudo_rules_.push_back(
- MinimalRuleData(style_rule, selector_index, add_rule_flags));
- } else if (selector->HasContentPseudo()) {
- content_pseudo_element_rules_.push_back(
- MinimalRuleData(style_rule, selector_index, add_rule_flags));
- } else if (selector->HasSlottedPseudo()) {
+ if (selector->HasSlottedPseudo()) {
slotted_pseudo_element_rules_.push_back(
MinimalRuleData(style_rule, selector_index, add_rule_flags));
} else {
- AddRule(style_rule, selector_index, add_rule_flags);
+ AddRule(style_rule, selector_index, add_rule_flags, container_query);
}
}
} else if (auto* page_rule = DynamicTo<StyleRulePage>(rule)) {
AddPageRule(page_rule);
} else if (auto* media_rule = DynamicTo<StyleRuleMedia>(rule)) {
- if (MatchMediaForAddRules(medium, media_rule->MediaQueries()))
- AddChildRules(media_rule->ChildRules(), medium, add_rule_flags);
+ if (MatchMediaForAddRules(medium, media_rule->MediaQueries())) {
+ AddChildRules(media_rule->ChildRules(), medium, add_rule_flags,
+ container_query);
+ }
} else if (auto* font_face_rule = DynamicTo<StyleRuleFontFace>(rule)) {
AddFontFaceRule(font_face_rule);
} else if (auto* keyframes_rule = DynamicTo<StyleRuleKeyframes>(rule)) {
AddKeyframesRule(keyframes_rule);
} else if (auto* property_rule = DynamicTo<StyleRuleProperty>(rule)) {
AddPropertyRule(property_rule);
+ } else if (auto* counter_style_rule =
+ DynamicTo<StyleRuleCounterStyle>(rule)) {
+ AddCounterStyleRule(counter_style_rule);
} else if (auto* scroll_timeline_rule =
DynamicTo<StyleRuleScrollTimeline>(rule)) {
AddScrollTimelineRule(scroll_timeline_rule);
} else if (auto* supports_rule = DynamicTo<StyleRuleSupports>(rule)) {
- if (supports_rule->ConditionIsSupported())
- AddChildRules(supports_rule->ChildRules(), medium, add_rule_flags);
+ if (supports_rule->ConditionIsSupported()) {
+ AddChildRules(supports_rule->ChildRules(), medium, add_rule_flags,
+ container_query);
+ }
+ } else if (auto* container_rule = DynamicTo<StyleRuleContainer>(rule)) {
+ // TODO(crbug.com/1145970): Handle nested container queries.
+ // For now only the innermost applies.
+ AddChildRules(container_rule->ChildRules(), medium, add_rule_flags,
+ &container_rule->GetContainerQuery());
}
}
}
@@ -449,7 +442,8 @@ void RuleSet::AddRulesFromSheet(StyleSheetContents* sheet,
}
}
- AddChildRules(sheet->ChildRules(), medium, add_rule_flags);
+ AddChildRules(sheet->ChildRules(), medium, add_rule_flags,
+ nullptr /* container_query */);
}
void RuleSet::AddStyleRule(StyleRule* rule, AddRuleFlags add_rule_flags) {
@@ -457,8 +451,10 @@ void RuleSet::AddStyleRule(StyleRule* rule, AddRuleFlags add_rule_flags) {
rule->SelectorList().SelectorIndex(*rule->SelectorList().First());
selector_index != kNotFound;
selector_index =
- rule->SelectorList().IndexOfNextSelectorAfter(selector_index))
- AddRule(rule, selector_index, add_rule_flags);
+ rule->SelectorList().IndexOfNextSelectorAfter(selector_index)) {
+ AddRule(rule, selector_index, add_rule_flags,
+ nullptr /* container_query */);
+ }
}
void RuleSet::CompactPendingRules(PendingRuleMap& pending_map,
@@ -487,21 +483,23 @@ void RuleSet::CompactRules() {
CompactPendingRules(pending_rules->id_rules, id_rules_);
CompactPendingRules(pending_rules->class_rules, class_rules_);
CompactPendingRules(pending_rules->tag_rules, tag_rules_);
- CompactPendingRules(pending_rules->shadow_pseudo_element_rules,
- shadow_pseudo_element_rules_);
+ CompactPendingRules(pending_rules->ua_shadow_pseudo_element_rules,
+ ua_shadow_pseudo_element_rules_);
link_pseudo_class_rules_.ShrinkToFit();
cue_pseudo_rules_.ShrinkToFit();
focus_pseudo_class_rules_.ShrinkToFit();
+ focus_visible_pseudo_class_rules_.ShrinkToFit();
spatial_navigation_interest_class_rules_.ShrinkToFit();
universal_rules_.ShrinkToFit();
shadow_host_rules_.ShrinkToFit();
+ part_pseudo_rules_.ShrinkToFit();
+ visited_dependent_rules_.ShrinkToFit();
page_rules_.ShrinkToFit();
font_face_rules_.ShrinkToFit();
keyframes_rules_.ShrinkToFit();
property_rules_.ShrinkToFit();
- deep_combinator_or_shadow_pseudo_rules_.ShrinkToFit();
- part_pseudo_rules_.ShrinkToFit();
- content_pseudo_element_rules_.ShrinkToFit();
+ counter_style_rules_.ShrinkToFit();
+ scroll_timeline_rules_.ShrinkToFit();
slotted_pseudo_element_rules_.ShrinkToFit();
}
@@ -514,37 +512,68 @@ void MinimalRuleData::Trace(Visitor* visitor) const {
visitor->Trace(rule_);
}
+const ContainerQuery* RuleData::GetContainerQuery() const {
+ if (auto* extended = DynamicTo<ExtendedRuleData>(this))
+ return extended->container_query_;
+ return nullptr;
+}
+
void RuleData::Trace(Visitor* visitor) const {
+ switch (static_cast<Type>(type_)) {
+ case Type::kNormal:
+ TraceAfterDispatch(visitor);
+ break;
+ case Type::kExtended:
+ To<ExtendedRuleData>(*this).TraceAfterDispatch(visitor);
+ break;
+ }
+}
+
+void RuleData::TraceAfterDispatch(blink::Visitor* visitor) const {
visitor->Trace(rule_);
}
+ExtendedRuleData::ExtendedRuleData(base::PassKey<RuleData>,
+ StyleRule* rule,
+ unsigned selector_index,
+ unsigned position,
+ AddRuleFlags flags,
+ const ContainerQuery* container_query)
+ : RuleData(Type::kExtended, rule, selector_index, position, flags),
+ container_query_(container_query) {}
+
+void ExtendedRuleData::TraceAfterDispatch(Visitor* visitor) const {
+ RuleData::TraceAfterDispatch(visitor);
+ visitor->Trace(container_query_);
+}
+
void RuleSet::PendingRuleMaps::Trace(Visitor* visitor) const {
visitor->Trace(id_rules);
visitor->Trace(class_rules);
visitor->Trace(tag_rules);
- visitor->Trace(shadow_pseudo_element_rules);
+ visitor->Trace(ua_shadow_pseudo_element_rules);
}
void RuleSet::Trace(Visitor* visitor) const {
visitor->Trace(id_rules_);
visitor->Trace(class_rules_);
visitor->Trace(tag_rules_);
- visitor->Trace(shadow_pseudo_element_rules_);
+ visitor->Trace(ua_shadow_pseudo_element_rules_);
visitor->Trace(link_pseudo_class_rules_);
visitor->Trace(cue_pseudo_rules_);
visitor->Trace(focus_pseudo_class_rules_);
+ visitor->Trace(focus_visible_pseudo_class_rules_);
visitor->Trace(spatial_navigation_interest_class_rules_);
visitor->Trace(universal_rules_);
visitor->Trace(shadow_host_rules_);
+ visitor->Trace(part_pseudo_rules_);
+ visitor->Trace(visited_dependent_rules_);
visitor->Trace(page_rules_);
visitor->Trace(font_face_rules_);
visitor->Trace(keyframes_rules_);
visitor->Trace(property_rules_);
+ visitor->Trace(counter_style_rules_);
visitor->Trace(scroll_timeline_rules_);
- visitor->Trace(deep_combinator_or_shadow_pseudo_rules_);
- visitor->Trace(part_pseudo_rules_);
- visitor->Trace(visited_dependent_rules_);
- visitor->Trace(content_pseudo_element_rules_);
visitor->Trace(slotted_pseudo_element_rules_);
visitor->Trace(pending_rules_);
#ifndef NDEBUG
diff --git a/chromium/third_party/blink/renderer/core/css/rule_set.h b/chromium/third_party/blink/renderer/core/css/rule_set.h
index 594d7740424..a3c2049a4ac 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_set.h
+++ b/chromium/third_party/blink/renderer/core/css/rule_set.h
@@ -23,13 +23,16 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RULE_SET_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RULE_SET_H_
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
#include "third_party/blink/renderer/core/css/resolver/media_query_result.h"
#include "third_party/blink/renderer/core/css/rule_feature_set.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
@@ -96,18 +99,30 @@ namespace blink {
// and makes it accessible cheaply.
class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
public:
+ enum class Type {
+ kNormal = 0,
+ kExtended = 1,
+ // Note that the above values are stored in a 1-bit field.
+ // See RuleData::type_.
+ };
+
static RuleData* MaybeCreate(StyleRule*,
unsigned selector_index,
unsigned position,
- AddRuleFlags);
+ AddRuleFlags,
+ const ContainerQuery*);
RuleData(StyleRule*,
unsigned selector_index,
unsigned position,
AddRuleFlags);
+ bool IsExtended() const {
+ return static_cast<Type>(type_) == Type::kExtended;
+ }
unsigned GetPosition() const { return position_; }
StyleRule* Rule() const { return rule_; }
+ const ContainerQuery* GetContainerQuery() const;
const CSSSelector& Selector() const {
return rule_->SelectorList().SelectorAt(selector_index_);
}
@@ -135,6 +150,7 @@ class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
}
void Trace(Visitor*) const;
+ void TraceAfterDispatch(blink::Visitor* visitor) const;
// This number is picked fairly arbitrary. If lowered, be aware that there
// might be sites and extensions using style rules with selector lists
@@ -146,6 +162,13 @@ class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
// need to. Some simple testing showed <100,000 RuleData's on large sites.
static constexpr size_t kPositionBits = 18;
+ protected:
+ RuleData(Type type,
+ StyleRule*,
+ unsigned selector_index,
+ unsigned position,
+ AddRuleFlags);
+
private:
Member<StyleRule> rule_;
unsigned selector_index_ : kSelectorIndexBits;
@@ -156,11 +179,37 @@ class CORE_EXPORT RuleData : public GarbageCollected<RuleData> {
unsigned link_match_type_ : 2;
unsigned has_document_security_origin_ : 1;
unsigned valid_property_filter_ : 3;
- // 30 bits above
+ unsigned type_ : 1; // RuleData::Type
+ // 31 bits above
// Use plain array instead of a Vector to minimize memory overhead.
unsigned descendant_selector_identifier_hashes_[kMaximumIdentifierCount];
};
+// Big websites can have a large number of RuleData objects (30k+). This class
+// exists to avoid allocating unnecessary memory for "rare" fields.
+class CORE_EXPORT ExtendedRuleData : public RuleData {
+ public:
+ // Do not create ExtendedRuleData objects directly; RuleData::MaybeCreate
+ // will decide if ExtendedRuleData is needed or not.
+ ExtendedRuleData(base::PassKey<RuleData>,
+ StyleRule*,
+ unsigned selector_index,
+ unsigned position,
+ AddRuleFlags,
+ const ContainerQuery*);
+ void TraceAfterDispatch(Visitor*) const;
+
+ private:
+ friend class RuleData;
+
+ Member<const ContainerQuery> container_query_;
+};
+
+template <>
+struct DowncastTraits<ExtendedRuleData> {
+ static bool AllowFrom(const RuleData& data) { return data.IsExtended(); }
+};
+
} // namespace blink
WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::RuleData)
@@ -194,7 +243,10 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
const MediaQueryEvaluator&,
AddRuleFlags = kRuleHasNoSpecialState);
void AddStyleRule(StyleRule*, AddRuleFlags);
- void AddRule(StyleRule*, unsigned selector_index, AddRuleFlags);
+ void AddRule(StyleRule*,
+ unsigned selector_index,
+ AddRuleFlags,
+ const ContainerQuery*);
const RuleFeatureSet& Features() const { return features_; }
@@ -213,10 +265,10 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
DCHECK(!pending_rules_);
return tag_rules_.at(key);
}
- const HeapVector<Member<const RuleData>>* ShadowPseudoElementRules(
+ const HeapVector<Member<const RuleData>>* UAShadowPseudoElementRules(
const AtomicString& key) const {
DCHECK(!pending_rules_);
- return shadow_pseudo_element_rules_.at(key);
+ return ua_shadow_pseudo_element_rules_.at(key);
}
const HeapVector<Member<const RuleData>>* LinkPseudoClassRules() const {
DCHECK(!pending_rules_);
@@ -230,6 +282,11 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
DCHECK(!pending_rules_);
return &focus_pseudo_class_rules_;
}
+ const HeapVector<Member<const RuleData>>* FocusVisiblePseudoClassRules()
+ const {
+ DCHECK(!pending_rules_);
+ return &focus_visible_pseudo_class_rules_;
+ }
const HeapVector<Member<const RuleData>>*
SpatialNavigationInterestPseudoClassRules() const {
DCHECK(!pending_rules_);
@@ -261,20 +318,16 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
const HeapVector<Member<StyleRuleKeyframes>>& KeyframesRules() const {
return keyframes_rules_;
}
- StyleRuleKeyframes* KeyframeStylesForAnimation(const AtomicString& name);
const HeapVector<Member<StyleRuleProperty>>& PropertyRules() const {
return property_rules_;
}
+ const HeapVector<Member<StyleRuleCounterStyle>>& CounterStyleRules() const {
+ return counter_style_rules_;
+ }
const HeapVector<Member<StyleRuleScrollTimeline>>& ScrollTimelineRules()
const {
return scroll_timeline_rules_;
}
- const HeapVector<MinimalRuleData>& DeepCombinatorOrShadowPseudoRules() const {
- return deep_combinator_or_shadow_pseudo_rules_;
- }
- const HeapVector<MinimalRuleData>& ContentPseudoElementRules() const {
- return content_pseudo_element_rules_;
- }
const HeapVector<MinimalRuleData>& SlottedPseudoElementRules() const {
return slotted_pseudo_element_rules_;
}
@@ -291,14 +344,8 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
return !slotted_pseudo_element_rules_.IsEmpty();
}
- bool HasV0BoundaryCrossingRules() const {
- return !deep_combinator_or_shadow_pseudo_rules_.IsEmpty() ||
- !content_pseudo_element_rules_.IsEmpty();
- }
-
bool NeedsFullRecalcForRuleSetInvalidation() const {
- return features_.NeedsFullRecalcForRuleSetInvalidation() ||
- HasV0BoundaryCrossingRules();
+ return features_.NeedsFullRecalcForRuleSetInvalidation();
}
bool DidMediaQueryResultsChange(const MediaQueryEvaluator& evaluator) const;
@@ -323,12 +370,14 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
void AddKeyframesRule(StyleRuleKeyframes*);
void AddPropertyRule(StyleRuleProperty*);
void AddScrollTimelineRule(StyleRuleScrollTimeline*);
+ void AddCounterStyleRule(StyleRuleCounterStyle*);
bool MatchMediaForAddRules(const MediaQueryEvaluator& evaluator,
const MediaQuerySet* media_queries);
void AddChildRules(const HeapVector<Member<StyleRuleBase>>&,
const MediaQueryEvaluator& medium,
- AddRuleFlags);
+ AddRuleFlags,
+ const ContainerQuery*);
bool FindBestRuleSetAndAdd(const CSSSelector&, RuleData*);
void SortKeyframesRulesIfNeeded();
@@ -343,7 +392,7 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
PendingRuleMap id_rules;
PendingRuleMap class_rules;
PendingRuleMap tag_rules;
- PendingRuleMap shadow_pseudo_element_rules;
+ PendingRuleMap ua_shadow_pseudo_element_rules;
void Trace(Visitor*) const;
};
@@ -357,10 +406,11 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
CompactRuleMap id_rules_;
CompactRuleMap class_rules_;
CompactRuleMap tag_rules_;
- CompactRuleMap shadow_pseudo_element_rules_;
+ CompactRuleMap ua_shadow_pseudo_element_rules_;
HeapVector<Member<const RuleData>> link_pseudo_class_rules_;
HeapVector<Member<const RuleData>> cue_pseudo_rules_;
HeapVector<Member<const RuleData>> focus_pseudo_class_rules_;
+ HeapVector<Member<const RuleData>> focus_visible_pseudo_class_rules_;
HeapVector<Member<const RuleData>> spatial_navigation_interest_class_rules_;
HeapVector<Member<const RuleData>> universal_rules_;
HeapVector<Member<const RuleData>> shadow_host_rules_;
@@ -371,14 +421,11 @@ class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
HeapVector<Member<StyleRuleFontFace>> font_face_rules_;
HeapVector<Member<StyleRuleKeyframes>> keyframes_rules_;
HeapVector<Member<StyleRuleProperty>> property_rules_;
+ HeapVector<Member<StyleRuleCounterStyle>> counter_style_rules_;
HeapVector<Member<StyleRuleScrollTimeline>> scroll_timeline_rules_;
- HeapVector<MinimalRuleData> deep_combinator_or_shadow_pseudo_rules_;
- HeapVector<MinimalRuleData> content_pseudo_element_rules_;
HeapVector<MinimalRuleData> slotted_pseudo_element_rules_;
Vector<MediaQuerySetResult> media_query_set_results_;
- bool keyframes_rules_sorted_ = true;
-
unsigned rule_count_;
Member<PendingRuleMaps> pending_rules_;
diff --git a/chromium/third_party/blink/renderer/core/css/rule_set_test.cc b/chromium/third_party/blink/renderer/core/css/rule_set_test.cc
index 54774b757db..6e6773933c5 100644
--- a/chromium/third_party/blink/renderer/core/css/rule_set_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/rule_set_test.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/css/rule_set.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
#include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
#include "third_party/blink/renderer/core/css/css_rule_list.h"
#include "third_party/blink/renderer/core/css/css_test_helpers.h"
@@ -58,7 +59,7 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_CustomPseudoElements) {
RuleSet& rule_set = sheet.GetRuleSet();
AtomicString str("-webkit-details-marker");
const HeapVector<Member<const RuleData>>* rules =
- rule_set.ShadowPseudoElementRules(str);
+ rule_set.UAShadowPseudoElementRules(str);
ASSERT_EQ(1u, rules->size());
ASSERT_EQ(str, rules->at(0)->Selector().Value());
}
@@ -133,18 +134,6 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_TagThenAttrThenId) {
ASSERT_EQ(tag_str, rules->at(0)->Selector().TagQName().LocalName());
}
-TEST(RuleSetTest, findBestRuleSetAndAdd_DivWithContent) {
- css_test_helpers::TestStyleSheet sheet;
-
- sheet.AddCSSRules("div::content { }");
- RuleSet& rule_set = sheet.GetRuleSet();
- AtomicString str("div");
- const HeapVector<Member<const RuleData>>* rules = rule_set.TagRules(str);
- ASSERT_EQ(1u, rules->size());
- AtomicString value_str("content");
- ASSERT_EQ(value_str, rules->at(0)->Selector().TagHistory()->Value());
-}
-
TEST(RuleSetTest, findBestRuleSetAndAdd_Host) {
css_test_helpers::TestStyleSheet sheet;
@@ -256,7 +245,8 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_PlaceholderPseudo) {
sheet.AddCSSRules("::placeholder { }");
sheet.AddCSSRules("input::placeholder { }");
RuleSet& rule_set = sheet.GetRuleSet();
- auto* rules = rule_set.ShadowPseudoElementRules("-webkit-input-placeholder");
+ auto* rules =
+ rule_set.UAShadowPseudoElementRules("-webkit-input-placeholder");
ASSERT_EQ(2u, rules->size());
}
@@ -300,22 +290,28 @@ TEST(RuleSetTest, RuleDataSelectorIndexLimit) {
StyleRule* rule = CreateDummyStyleRule();
AddRuleFlags flags = kRuleHasNoSpecialState;
const unsigned position = 0;
- EXPECT_TRUE(RuleData::MaybeCreate(rule, 0, position, flags));
+ EXPECT_TRUE(RuleData::MaybeCreate(rule, 0, position, flags,
+ nullptr /* container_query */));
EXPECT_FALSE(RuleData::MaybeCreate(rule, (1 << RuleData::kSelectorIndexBits),
- position, flags));
- EXPECT_FALSE(RuleData::MaybeCreate(
- rule, (1 << RuleData::kSelectorIndexBits) + 1, position, flags));
+ position, flags,
+ nullptr /* container_query */));
+ EXPECT_FALSE(
+ RuleData::MaybeCreate(rule, (1 << RuleData::kSelectorIndexBits) + 1,
+ position, flags, nullptr /* container_query */));
}
TEST(RuleSetTest, RuleDataPositionLimit) {
StyleRule* rule = CreateDummyStyleRule();
AddRuleFlags flags = kRuleHasNoSpecialState;
const unsigned selector_index = 0;
- EXPECT_TRUE(RuleData::MaybeCreate(rule, selector_index, 0, flags));
+ EXPECT_TRUE(RuleData::MaybeCreate(rule, selector_index, 0, flags,
+ nullptr /* container_query */));
EXPECT_FALSE(RuleData::MaybeCreate(rule, selector_index,
- (1 << RuleData::kPositionBits), flags));
- EXPECT_FALSE(RuleData::MaybeCreate(
- rule, selector_index, (1 << RuleData::kPositionBits) + 1, flags));
+ (1 << RuleData::kPositionBits), flags,
+ nullptr /* container_query */));
+ EXPECT_FALSE(RuleData::MaybeCreate(rule, selector_index,
+ (1 << RuleData::kPositionBits) + 1, flags,
+ nullptr /* container_query */));
}
TEST(RuleSetTest, RuleCountNotIncreasedByInvalidRuleData) {
@@ -326,69 +322,23 @@ TEST(RuleSetTest, RuleCountNotIncreasedByInvalidRuleData) {
StyleRule* rule = CreateDummyStyleRule();
// Add with valid selector_index=0.
- rule_set->AddRule(rule, 0, flags);
+ rule_set->AddRule(rule, 0, flags, nullptr /* container_query */);
EXPECT_EQ(1u, rule_set->RuleCount());
// Adding with invalid selector_index should not lead to a change in count.
- rule_set->AddRule(rule, 1 << RuleData::kSelectorIndexBits, flags);
+ rule_set->AddRule(rule, 1 << RuleData::kSelectorIndexBits, flags,
+ nullptr /* container_query */);
EXPECT_EQ(1u, rule_set->RuleCount());
}
-TEST(RuleSetTest, KeyframesRulesBasic) {
- ScopedCSSKeyframesMemoryReductionForTest enabled_scope(true);
-
- css_test_helpers::TestStyleSheet sheet;
- sheet.AddCSSRules("@keyframes foo { from {top: 0;} to {top: 100px;} }");
- sheet.AddCSSRules("@keyframes bar { from {top: 100px;} to {top: 0;} }");
-
- RuleSet& rule_set = sheet.GetRuleSet();
-
- StyleRuleKeyframes* foo = rule_set.KeyframeStylesForAnimation("foo");
- EXPECT_TRUE(foo);
- EXPECT_EQ("foo", foo->GetName());
-
- StyleRuleKeyframes* bar = rule_set.KeyframeStylesForAnimation("bar");
- EXPECT_TRUE(bar);
- EXPECT_EQ("bar", bar->GetName());
+TEST(RuleSetTest, UACounterStyleRules) {
+ ScopedCSSAtRuleCounterStyleForTest enabled_scope(true);
- StyleRuleKeyframes* nonexist =
- rule_set.KeyframeStylesForAnimation("nonexist");
- EXPECT_FALSE(nonexist);
-}
-
-TEST(RuleSetTest, KeyframesRulesOverriding) {
- ScopedCSSKeyframesMemoryReductionForTest enabled_scope(true);
-
- // Among multiple @keyframes rules with the same name, the last one wins.
- css_test_helpers::TestStyleSheet sheet;
- sheet.AddCSSRules("@keyframes foo { from1 {top: 0;} to1 {top: 100px;} }");
- sheet.AddCSSRules("@keyframes foo { from2 {top: 100px;} to2 {top: 0;} }");
-
- RuleSet& rule_set = sheet.GetRuleSet();
-
- StyleRuleKeyframes* rule = rule_set.KeyframeStylesForAnimation("foo");
- EXPECT_TRUE(rule);
- EXPECT_EQ("foo", rule->GetName());
-
- CSSKeyframesRule* css_rule = To<CSSKeyframesRule>(sheet.CssRules()->item(1));
- EXPECT_EQ(rule, css_rule->Keyframes());
-}
-
-TEST(RuleSetTest, KeyframesRulesVendorPrefixed) {
- ScopedCSSKeyframesMemoryReductionForTest enabled_scope(true);
-
- // Non-vendor-prefixed keyframes rules win against vendor-prefixed ones.
- css_test_helpers::TestStyleSheet sheet;
- sheet.AddCSSRules("@keyframes foo { from1 {top: 0;} to1 {top: 100px;} }");
- sheet.AddCSSRules(
- "@-webkit-keyframes foo { from2 {top: 100px;} to2 {top: 0;} }");
-
- RuleSet& rule_set = sheet.GetRuleSet();
+ RuleSet* default_rule_set = CSSDefaultStyleSheets::Instance().DefaultStyle();
+ ASSERT_TRUE(default_rule_set);
+ ASSERT_FALSE(default_rule_set->CounterStyleRules().IsEmpty());
- StyleRuleKeyframes* rule = rule_set.KeyframeStylesForAnimation("foo");
- EXPECT_TRUE(rule);
- EXPECT_EQ("foo", rule->GetName());
- EXPECT_FALSE(rule->IsVendorPrefixed());
+ EXPECT_EQ("decimal", default_rule_set->CounterStyleRules()[0]->GetName());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/selector_checker.cc b/chromium/third_party/blink/renderer/core/css/selector_checker.cc
index a63926ddac5..9539077cffd 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_checker.cc
@@ -42,7 +42,6 @@
#include "third_party/blink/renderer/core/dom/nth_index_cache.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
@@ -56,6 +55,7 @@
#include "third_party/blink/renderer/core/html/html_dialog_element.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
+#include "third_party/blink/renderer/core/html/html_popup_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
@@ -154,30 +154,6 @@ static const HTMLSlotElement* FindSlotElementInScope(
return nullptr;
}
-static bool ScopeContainsLastMatchedElement(
- const SelectorChecker::SelectorCheckingContext& context) {
- // If this context isn't scoped, skip checking.
- if (!context.scope)
- return true;
-
- if (context.scope->GetTreeScope() == context.element->GetTreeScope())
- return true;
-
- // The scope-contains-last-matched-element check is only relevant for
- // ShadowDOM V0 features (::content, ::shadow, /deep/), and the selector
- // parser does not allow mixing ShadowDOM V0 with nested complex
- // selectors, hence we can skip the check inside a nested complex selector.
- if (context.in_nested_complex_selector)
- return true;
-
- // Because Blink treats a shadow host's TreeScope as a separate one from its
- // descendent shadow roots, if the last matched element is a shadow host, the
- // condition above isn't met, even though it should be.
- return context.element == context.scope->OwnerShadowHost() &&
- (!context.previous_element ||
- context.previous_element->IsInDescendantTreeOf(context.element));
-}
-
static inline bool NextSelectorExceedsScope(
const SelectorChecker::SelectorCheckingContext& context) {
if (context.scope && context.scope->IsInShadowTree())
@@ -235,7 +211,7 @@ bool SelectorChecker::Match(const SelectorCheckingContext& context,
#endif // DCHECK_IS_ON()
if (UNLIKELY(context.vtt_originating_element)) {
- // A kShadowPseudo combinator is required for VTT matching.
+ // A kUAShadow combinator is required for VTT matching.
if (context.selector->IsLastInTagHistory())
return false;
}
@@ -260,11 +236,8 @@ SelectorChecker::MatchStatus SelectorChecker::MatchSelector(
result.dynamic_pseudo = sub_result.dynamic_pseudo;
if (context.selector->IsLastInTagHistory()) {
- if (ScopeContainsLastMatchedElement(context)) {
- result.specificity += sub_result.specificity;
- return kSelectorMatches;
- }
- return kSelectorFailsLocally;
+ result.specificity += sub_result.specificity;
+ return kSelectorMatches;
}
MatchStatus match;
@@ -322,30 +295,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForSubSelector(
return MatchSelector(next_context, result);
}
-static inline bool IsV0ShadowRoot(const Node* node) {
- auto* shadow_root = DynamicTo<ShadowRoot>(node);
- return shadow_root && shadow_root->GetType() == ShadowRootType::V0;
-}
-
-SelectorChecker::MatchStatus SelectorChecker::MatchForPseudoShadow(
- const SelectorCheckingContext& context,
- const ContainerNode* node,
- MatchResult& result) const {
- if (!IsV0ShadowRoot(node))
- return kSelectorFailsCompletely;
- if (!context.previous_element)
- return kSelectorFailsCompletely;
- return MatchSelector(context, result);
-}
-
-static inline Element* ParentOrV0ShadowHostElement(const Element& element) {
- if (auto* shadow_root = DynamicTo<ShadowRoot>(element.parentNode())) {
- if (shadow_root->GetType() != ShadowRootType::V0)
- return nullptr;
- }
- return element.ParentOrShadowHostElement();
-}
-
SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
const SelectorCheckingContext& context,
MatchResult& result) const {
@@ -366,10 +315,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
next_context.pseudo_id = kPseudoIdNone;
switch (relation) {
- case CSSSelector::kShadowDeepAsDescendant:
- Deprecation::CountDeprecation(context.element->GetExecutionContext(),
- WebFeature::kCSSDeepCombinator);
- FALLTHROUGH;
case CSSSelector::kDescendant:
if (next_context.selector->GetPseudoType() == CSSSelector::kPseudoScope) {
if (next_context.selector->IsLastInTagHistory()) {
@@ -377,21 +322,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
return kSelectorMatches;
}
}
-
- if (context.selector->RelationIsAffectedByPseudoContent()) {
- for (Element* element = context.element; element;
- element = element->parentElement()) {
- if (MatchForPseudoContent(next_context, *element, result) ==
- kSelectorMatches)
- return kSelectorMatches;
- }
- return kSelectorFailsCompletely;
- }
-
- if (next_context.selector->GetPseudoType() == CSSSelector::kPseudoShadow)
- return MatchForPseudoShadow(
- next_context, context.element->ContainingShadowRoot(), result);
-
for (next_context.element = ParentElement(next_context);
next_context.element;
next_context.element = ParentElement(next_context)) {
@@ -413,23 +343,12 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
}
}
- if (context.selector->RelationIsAffectedByPseudoContent())
- return MatchForPseudoContent(next_context, *context.element, result);
-
- if (next_context.selector->GetPseudoType() == CSSSelector::kPseudoShadow)
- return MatchForPseudoShadow(next_context, context.element->parentNode(),
- result);
-
next_context.element = ParentElement(next_context);
if (!next_context.element)
return kSelectorFailsCompletely;
return MatchSelector(next_context, result);
}
case CSSSelector::kDirectAdjacent:
- // Shadow roots can't have sibling elements
- if (next_context.selector->GetPseudoType() == CSSSelector::kPseudoShadow)
- return kSelectorFailsCompletely;
-
if (mode_ == kResolvingStyle) {
if (ContainerNode* parent =
context.element->ParentElementOrShadowRoot())
@@ -442,10 +361,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
return MatchSelector(next_context, result);
case CSSSelector::kIndirectAdjacent:
- // Shadow roots can't have sibling elements
- if (next_context.selector->GetPseudoType() == CSSSelector::kPseudoShadow)
- return kSelectorFailsCompletely;
-
if (mode_ == kResolvingStyle) {
if (ContainerNode* parent =
context.element->ParentElementOrShadowRoot())
@@ -463,15 +378,9 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
}
return kSelectorFailsAllSiblings;
- case CSSSelector::kShadowPseudo: {
- DCHECK(mode_ == kQueryingRules ||
- context.selector->GetPseudoType() != CSSSelector::kPseudoShadow);
- if (context.selector->GetPseudoType() == CSSSelector::kPseudoShadow) {
- UseCounter::Count(context.element->GetDocument(),
- WebFeature::kPseudoShadowInStaticProfile);
- }
+ case CSSSelector::kUAShadow: {
// If we're in the same tree-scope as the scoping element, then following
- // a shadow descendant combinator would escape that and thus the scope.
+ // a kUAShadow combinator would escape that and thus the scope.
if (context.scope && context.scope->OwnerShadowHost() &&
context.scope->OwnerShadowHost()->GetTreeScope() ==
context.element->GetTreeScope())
@@ -488,49 +397,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
return MatchSelector(next_context, result);
}
- case CSSSelector::kShadowDeep: {
- DCHECK(mode_ == kQueryingRules);
- UseCounter::Count(context.element->GetDocument(),
- WebFeature::kDeepCombinatorInStaticProfile);
- if (ShadowRoot* root = context.element->ContainingShadowRoot()) {
- if (root->IsUserAgent())
- return kSelectorFailsCompletely;
- }
-
- if (context.selector->RelationIsAffectedByPseudoContent()) {
- // TODO(kochi): closed mode tree should be handled as well for
- // ::content.
- for (Element* element = context.element; element;
- element = element->ParentOrShadowHostElement()) {
- if (MatchForPseudoContent(next_context, *element, result) ==
- kSelectorMatches) {
- if (context.element->IsInShadowTree()) {
- UseCounter::Count(context.element->GetDocument(),
- WebFeature::kCSSDeepCombinatorAndShadow);
- }
- return kSelectorMatches;
- }
- }
- return kSelectorFailsCompletely;
- }
-
- for (next_context.element = ParentOrV0ShadowHostElement(*context.element);
- next_context.element;
- next_context.element =
- ParentOrV0ShadowHostElement(*next_context.element)) {
- MatchStatus match = MatchSelector(next_context, result);
- if (match == kSelectorMatches && context.element->IsInShadowTree()) {
- UseCounter::Count(context.element->GetDocument(),
- WebFeature::kCSSDeepCombinatorAndShadow);
- }
- if (match == kSelectorMatches || match == kSelectorFailsCompletely)
- return match;
- if (NextSelectorExceedsScope(next_context))
- return kSelectorFailsCompletely;
- }
- return kSelectorFailsCompletely;
- }
-
case CSSSelector::kShadowSlot: {
if (ToHTMLSlotElementIfSupportsAssignmentOrNull(*context.element))
return kSelectorFailsCompletely;
@@ -563,21 +429,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
return kSelectorFailsCompletely;
}
-SelectorChecker::MatchStatus SelectorChecker::MatchForPseudoContent(
- const SelectorCheckingContext& context,
- const Element& element,
- MatchResult& result) const {
- HeapVector<Member<V0InsertionPoint>, 8> insertion_points;
- CollectDestinationInsertionPoints(element, insertion_points);
- SelectorCheckingContext next_context(context);
- for (const auto& insertion_point : insertion_points) {
- next_context.element = insertion_point;
- if (MatchSelector(next_context, result) == kSelectorMatches)
- return kSelectorMatches;
- }
- return kSelectorFailsLocally;
-}
-
static bool AttributeValueMatches(const Attribute& attribute_item,
CSSSelector::MatchType match,
const AtomicString& selector_value,
@@ -700,6 +551,14 @@ static bool AnyAttributeMatches(Element& element,
if (legacy_case_insensitive &&
AttributeValueMatches(attribute_item, match, selector_value,
kTextCaseASCIIInsensitive)) {
+ // If the `s` modifier is in the attribute selector, return false
+ // despite of legacy_case_insensitive.
+ if (selector.AttributeMatch() ==
+ CSSSelector::AttributeMatchType::kCaseSensitiveAlways) {
+ DCHECK(RuntimeEnabledFeatures::CSSCaseSensitiveSelectorEnabled());
+ return false;
+ }
+
UseCounter::Count(element.GetDocument(),
WebFeature::kCaseInsensitiveAttrSelectorMatch);
return true;
@@ -764,8 +623,7 @@ bool SelectorChecker::CheckPseudoNot(const SelectorCheckingContext& context,
DCHECK(selector.SelectorList());
SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true;
- sub_context.in_nested_complex_selector =
- !selector.SelectorList()->TreatAsNonComplexArgumentToNot();
+ sub_context.in_nested_complex_selector = true;
sub_context.pseudo_id = kPseudoIdNone;
for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector;
@@ -920,6 +778,10 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
return selector.MatchNth(NthIndexCache::NthLastOfTypeIndex(element));
}
case CSSSelector::kPseudoTarget:
+ probe::ForcePseudoState(&element, CSSSelector::kPseudoTarget,
+ &force_pseudo_state);
+ if (force_pseudo_state)
+ return true;
return element == element.GetDocument().CssTarget();
case CSSSelector::kPseudoIs:
case CSSSelector::kPseudoWhere:
@@ -1070,6 +932,28 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
break;
return true;
}
+ case CSSSelector::kPseudoDir: {
+ const AtomicString& argument = selector.Argument();
+ if (argument.IsEmpty())
+ break;
+
+ TextDirection direction;
+ if (EqualIgnoringASCIICase(argument, "ltr"))
+ direction = TextDirection::kLtr;
+ else if (EqualIgnoringASCIICase(argument, "rtl"))
+ direction = TextDirection::kRtl;
+ else
+ break;
+
+ if (auto* html_element = DynamicTo<HTMLElement>(element)) {
+ return html_element->CachedDirectionality() == direction;
+ }
+ break;
+ }
+ case CSSSelector::kPseudoPopupOpen:
+ if (auto* popup_element = DynamicTo<HTMLPopupElement>(element))
+ return popup_element->open();
+ break;
case CSSSelector::kPseudoFullscreen:
// fall through
case CSSSelector::kPseudoFullScreen:
@@ -1112,10 +996,8 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
if (auto* shadow_root = DynamicTo<ShadowRoot>(context.scope))
return element == shadow_root->host();
return context.scope == &element;
- case CSSSelector::kPseudoUnresolved:
- return !element.IsDefined() && element.IsUnresolvedV0CustomElement();
case CSSSelector::kPseudoDefined:
- return element.IsDefined() || element.IsUpgradedV0CustomElement();
+ return element.IsDefined();
case CSSSelector::kPseudoHostContext:
UseCounter::Count(
context.element->GetDocument(),
@@ -1158,7 +1040,7 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
return !element.GetDocument().GetPage()->GetFocusController().IsActive();
case CSSSelector::kPseudoState: {
return element.DidAttachInternals() &&
- element.EnsureElementInternals().HasState(selector.Argument());
+ element.EnsureElementInternals().HasState(selector.Value());
}
case CSSSelector::kPseudoHorizontal:
case CSSSelector::kPseudoVertical:
@@ -1184,6 +1066,11 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
return false;
}
+static bool MatchesUAShadowElement(Element& element, const AtomicString& id) {
+ ShadowRoot* root = element.ContainingShadowRoot();
+ return root && root->IsUserAgent() && element.ShadowPseudoId() == id;
+}
+
bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
MatchResult& result) const {
const CSSSelector& selector = *context.selector;
@@ -1212,35 +1099,17 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
return false;
}
return true;
+ case CSSSelector::kPseudoFileSelectorButton:
+ return MatchesUAShadowElement(
+ element, shadow_element_names::kPseudoFileUploadButton);
case CSSSelector::kPseudoPlaceholder:
- if (ShadowRoot* root = element.ContainingShadowRoot()) {
- return root->IsUserAgent() &&
- element.ShadowPseudoId() ==
- shadow_element_names::kPseudoInputPlaceholder;
- }
- return false;
- case CSSSelector::kPseudoWebKitCustomElement: {
- if (ShadowRoot* root = element.ContainingShadowRoot()) {
- if (!root->IsUserAgent())
- return false;
- if (element.ShadowPseudoId() != selector.Value())
- return false;
- if (!is_ua_rule_ &&
- selector.Value() ==
- shadow_element_names::kPseudoWebKitDetailsMarker) {
- UseCounter::Count(element.GetDocument(),
- WebFeature::kCSSSelectorPseudoWebKitDetailsMarker);
- }
- return true;
- }
- return false;
- }
+ return MatchesUAShadowElement(
+ element, shadow_element_names::kPseudoInputPlaceholder);
+ case CSSSelector::kPseudoWebKitCustomElement:
+ return MatchesUAShadowElement(element, selector.Value());
case CSSSelector::kPseudoBlinkInternalElement:
DCHECK(is_ua_rule_);
- if (ShadowRoot* root = element.ContainingShadowRoot())
- return root->IsUserAgent() &&
- element.ShadowPseudoId() == selector.Value();
- return false;
+ return MatchesUAShadowElement(element, selector.Value());
case CSSSelector::kPseudoSlotted: {
SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true;
@@ -1256,10 +1125,12 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
return false;
return true;
}
- case CSSSelector::kPseudoContent:
- return element.IsInShadowTree() && element.IsV0InsertionPoint();
- case CSSSelector::kPseudoShadow:
- return element.IsInShadowTree() && context.previous_element;
+ case CSSSelector::kPseudoTargetText:
+ if (!is_ua_rule_) {
+ UseCounter::Count(context.element->GetDocument(),
+ WebFeature::kCSSSelectorTargetText);
+ }
+ FALLTHROUGH;
default:
DCHECK_NE(mode_, kQueryingRules);
result.dynamic_pseudo =
@@ -1283,12 +1154,10 @@ bool SelectorChecker::CheckPseudoHost(const SelectorCheckingContext& context,
return false;
DCHECK(IsShadowHost(element));
DCHECK(element.GetShadowRoot());
- bool is_v1_shadow = element.GetShadowRoot()->IsV1();
// For the case with no parameters, i.e. just :host.
if (!selector.SelectorList()) {
- if (is_v1_shadow)
- result.specificity += CSSSelector::kClassLikeSpecificity;
+ result.specificity += CSSSelector::kClassLikeSpecificity;
return true;
}
@@ -1331,9 +1200,7 @@ bool SelectorChecker::CheckPseudoHost(const SelectorCheckingContext& context,
} while (next_element);
}
if (matched) {
- result.specificity += max_specificity;
- if (is_v1_shadow)
- result.specificity += CSSSelector::kClassLikeSpecificity;
+ result.specificity += max_specificity + CSSSelector::kClassLikeSpecificity;
if (result.specificity !=
selector.Specificity(
diff --git a/chromium/third_party/blink/renderer/core/css/selector_checker.h b/chromium/third_party/blink/renderer/core/css/selector_checker.h
index 6e11ebe4005..c93a484cead 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_checker.h
+++ b/chromium/third_party/blink/renderer/core/css/selector_checker.h
@@ -90,11 +90,8 @@ class CORE_EXPORT SelectorChecker {
scrollbar_(init.scrollbar),
part_names_(init.part_names),
scrollbar_part_(init.scrollbar_part),
- mode_(init.mode) {
-#if DCHECK_IS_ON()
- is_ua_rule_ = init.is_ua_rule;
-#endif
- }
+ mode_(init.mode),
+ is_ua_rule_(init.is_ua_rule) {}
SelectorChecker(const SelectorChecker&) = delete;
SelectorChecker& operator=(const SelectorChecker&) = delete;
@@ -194,11 +191,9 @@ class CORE_EXPORT SelectorChecker {
PartNames* part_names_;
ScrollbarPart scrollbar_part_;
Mode mode_;
+ bool is_ua_rule_;
#if DCHECK_IS_ON()
mutable bool inside_match_ = false;
- bool is_ua_rule_;
-#else
- static constexpr bool is_ua_rule_ = true;
#endif
};
diff --git a/chromium/third_party/blink/renderer/core/css/selector_filter.cc b/chromium/third_party/blink/renderer/core/css/selector_filter.cc
index 16e336cd1dd..7d129889597 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_filter.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_filter.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/css/css_selector.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
namespace blink {
@@ -65,8 +66,9 @@ static inline void CollectElementIdentifierHashes(
void SelectorFilter::PushParentStackFrame(Element& parent) {
DCHECK(ancestor_identifier_filter_);
DCHECK(parent_stack_.IsEmpty() ||
- parent_stack_.back().element == parent.ParentOrShadowHostElement());
- DCHECK(!parent_stack_.IsEmpty() || !parent.ParentOrShadowHostElement());
+ parent_stack_.back().element ==
+ FlatTreeTraversal::ParentElement(parent));
+ DCHECK(!parent_stack_.IsEmpty() || !FlatTreeTraversal::ParentElement(parent));
parent_stack_.push_back(ParentStackFrame(parent));
ParentStackFrame& parent_frame = parent_stack_.back();
// Mix tags, class names and ids into some sort of weird bouillabaisse.
@@ -106,7 +108,7 @@ void SelectorFilter::PushParent(Element& parent) {
DCHECK(ancestor_identifier_filter_);
// We may get invoked for some random elements in some wacky cases during
// style resolve. Pause maintaining the stack in this case.
- if (parent_stack_.back().element != parent.ParentOrShadowHostElement())
+ if (parent_stack_.back().element != FlatTreeTraversal::ParentElement(parent))
return;
PushParentStackFrame(parent);
}
@@ -152,12 +154,6 @@ void SelectorFilter::CollectIdentifierHashes(
unsigned* hash = identifier_hashes;
unsigned* end = identifier_hashes + maximum_identifier_count;
CSSSelector::RelationType relation = selector.Relation();
- if (selector.RelationIsAffectedByPseudoContent()) {
- // Disable fastRejectSelector.
- *identifier_hashes = 0;
- return;
- }
-
// Skip the rightmost compound. It is handled quickly by the rule hashes.
bool skip_over_subselectors = true;
for (const CSSSelector* current = selector.TagHistory(); current;
@@ -173,15 +169,10 @@ void SelectorFilter::CollectIdentifierHashes(
skip_over_subselectors = true;
break;
case CSSSelector::kShadowSlot:
- // Disable fastRejectSelector.
- *identifier_hashes = 0;
- return;
case CSSSelector::kDescendant:
- case CSSSelector::kShadowDeepAsDescendant:
case CSSSelector::kChild:
- case CSSSelector::kShadowPseudo:
+ case CSSSelector::kUAShadow:
case CSSSelector::kShadowPart:
- case CSSSelector::kShadowDeep:
skip_over_subselectors = false;
CollectDescendantSelectorIdentifierHashes(*current, hash);
break;
@@ -189,11 +180,6 @@ void SelectorFilter::CollectIdentifierHashes(
if (hash == end)
return;
relation = current->Relation();
- if (current->RelationIsAffectedByPseudoContent()) {
- // Disable fastRejectSelector.
- *identifier_hashes = 0;
- return;
- }
}
*hash = 0;
}
diff --git a/chromium/third_party/blink/renderer/core/css/selector_query.cc b/chromium/third_party/blink/renderer/core/css/selector_query.cc
index 0f962e17a48..2b29519e231 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_query.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_query.cc
@@ -108,8 +108,6 @@ inline bool SelectorMatches(const CSSSelector& selector,
bool SelectorQuery::Matches(Element& target_element) const {
QUERY_STATS_RESET();
- if (needs_updated_distribution_)
- target_element.UpdateDistributionForFlatTreeTraversal();
return SelectorListMatches(target_element, target_element);
}
@@ -117,8 +115,6 @@ Element* SelectorQuery::Closest(Element& target_element) const {
QUERY_STATS_RESET();
if (selectors_.IsEmpty())
return nullptr;
- if (needs_updated_distribution_)
- target_element.UpdateDistributionForFlatTreeTraversal();
for (Element* current_element = &target_element; current_element;
current_element = current_element->parentElement()) {
@@ -305,57 +301,6 @@ void SelectorQuery::ExecuteSlow(
}
}
-// FIXME: Move the following helper functions, AuthorShadowRootOf,
-// NextTraversingShadowTree to the best place, e.g. NodeTraversal.
-static ShadowRoot* AuthorShadowRootOf(const ContainerNode& node) {
- if (!node.IsElementNode())
- return nullptr;
- ShadowRoot* root = node.GetShadowRoot();
- if (root && root->IsOpenOrV0())
- return root;
- return nullptr;
-}
-
-static ContainerNode* NextTraversingShadowTree(const ContainerNode& node,
- const ContainerNode* root_node) {
- if (ShadowRoot* shadow_root = AuthorShadowRootOf(node))
- return shadow_root;
-
- const ContainerNode* current = &node;
- while (current) {
- if (Element* next = ElementTraversal::Next(*current, root_node))
- return next;
-
- if (!current->IsInShadowTree())
- return nullptr;
-
- ShadowRoot* shadow_root = current->ContainingShadowRoot();
- if (shadow_root == root_node)
- return nullptr;
-
- current = &shadow_root->host();
- }
- return nullptr;
-}
-
-template <typename SelectorQueryTrait>
-void SelectorQuery::ExecuteSlowTraversingShadowTree(
- ContainerNode& root_node,
- typename SelectorQueryTrait::OutputType& output) const {
- for (ContainerNode* node = NextTraversingShadowTree(root_node, &root_node);
- node; node = NextTraversingShadowTree(*node, &root_node)) {
- auto* element = DynamicTo<Element>(node);
- if (!element)
- continue;
- QUERY_STATS_INCREMENT(slow_traversing_shadow_tree_scan);
- if (!SelectorListMatches(root_node, *element))
- continue;
- SelectorQueryTrait::AppendElement(output, *element);
- if (SelectorQueryTrait::kShouldOnlyMatchFirstElement)
- return;
- }
-}
-
template <typename SelectorQueryTrait>
void SelectorQuery::ExecuteWithId(
ContainerNode& root_node,
@@ -417,19 +362,11 @@ void SelectorQuery::Execute(
return;
if (use_slow_scan_) {
- if (needs_updated_distribution_)
- root_node.UpdateDistributionForFlatTreeTraversal();
- if (uses_deep_combinator_or_shadow_pseudo_) {
- ExecuteSlowTraversingShadowTree<SelectorQueryTrait>(root_node, output);
- } else {
- ExecuteSlow<SelectorQueryTrait>(root_node, output);
- }
+ ExecuteSlow<SelectorQueryTrait>(root_node, output);
return;
}
DCHECK_EQ(selectors_.size(), 1u);
- DCHECK(!needs_updated_distribution_);
- DCHECK(!uses_deep_combinator_or_shadow_pseudo_);
// In quirks mode getElementById("a") is case sensitive and should only
// match elements with lowercase id "a", but querySelector is case-insensitive
@@ -477,8 +414,6 @@ SelectorQuery::SelectorQuery(CSSSelectorList selector_list)
: selector_list_(std::move(selector_list)),
selector_id_is_rightmost_(true),
selector_id_affected_by_sibling_combinator_(false),
- uses_deep_combinator_or_shadow_pseudo_(false),
- needs_updated_distribution_(false),
use_slow_scan_(true) {
selectors_.ReserveInitialCapacity(selector_list_.ComputeLength());
for (const CSSSelector* selector = selector_list_.First(); selector;
@@ -486,13 +421,9 @@ SelectorQuery::SelectorQuery(CSSSelectorList selector_list)
if (selector->MatchesPseudoElement())
continue;
selectors_.UncheckedAppend(selector);
- uses_deep_combinator_or_shadow_pseudo_ |=
- selector->HasDeepCombinatorOrShadowPseudo();
- needs_updated_distribution_ |= selector->NeedsUpdatedDistribution();
}
- if (selectors_.size() == 1 && !uses_deep_combinator_or_shadow_pseudo_ &&
- !needs_updated_distribution_) {
+ if (selectors_.size() == 1) {
use_slow_scan_ = false;
for (const CSSSelector* current = selectors_[0]; current;
current = current->TagHistory()) {
@@ -535,9 +466,8 @@ SelectorQuery* SelectorQueryCache::Add(const AtomicString& selectors,
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
- document, document.BaseURL(), true /* origin_clean */,
- document.GetReferrerPolicy(), WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ document, document.BaseURL(), true /* origin_clean */, Referrer(),
+ WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, selectors);
if (!selector_list.First()) {
diff --git a/chromium/third_party/blink/renderer/core/css/selector_query.h b/chromium/third_party/blink/renderer/core/css/selector_query.h
index b114a5339bb..9e9b8ad2ecf 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_query.h
+++ b/chromium/third_party/blink/renderer/core/css/selector_query.h
@@ -99,10 +99,6 @@ class CORE_EXPORT SelectorQuery {
void ExecuteSlow(ContainerNode& root_node,
typename SelectorQueryTrait::OutputType&) const;
template <typename SelectorQueryTrait>
- void ExecuteSlowTraversingShadowTree(
- ContainerNode& root_node,
- typename SelectorQueryTrait::OutputType&) const;
- template <typename SelectorQueryTrait>
void Execute(ContainerNode& root_node,
typename SelectorQueryTrait::OutputType&) const;
@@ -117,8 +113,6 @@ class CORE_EXPORT SelectorQuery {
AtomicString selector_id_;
bool selector_id_is_rightmost_ : 1;
bool selector_id_affected_by_sibling_combinator_ : 1;
- bool uses_deep_combinator_or_shadow_pseudo_ : 1;
- bool needs_updated_distribution_ : 1;
bool use_slow_scan_ : 1;
};
diff --git a/chromium/third_party/blink/renderer/core/css/selector_query_test.cc b/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
index 8d701d91372..54234b94200 100644
--- a/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/selector_query_test.cc
@@ -72,9 +72,8 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
- *document, NullURL(), true /* origin_clean */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ *document, NullURL(), true /* origin_clean */, Referrer(),
+ WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "span::before");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
@@ -83,9 +82,8 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
- *document, NullURL(), true /* origin_clean */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ *document, NullURL(), true /* origin_clean */, Referrer(),
+ WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "span");
query = SelectorQuery::Adopt(std::move(selector_list));
elm = query->QueryFirst(*document);
@@ -103,9 +101,8 @@ TEST(SelectorQueryTest, LastOfTypeNotFinishedParsing) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
- *document, NullURL(), true /* origin_clean */,
- network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
- CSSParserContext::kSnapshotProfile),
+ *document, NullURL(), true /* origin_clean */, Referrer(),
+ WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "p:last-of-type");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
@@ -214,14 +211,6 @@ TEST(SelectorQueryTest, StandardsModeFastPaths) {
// sure it's worth it unless we're dealing with ids.
{"#a, #b", false, 1, {5, 0, 0, 0, 0, 5, 0}},
{"#a, #b", true, 2, {14, 0, 0, 0, 0, 14, 0}},
-
- // Anything that crosses shadow boundaries is slow path.
- {"#foo /deep/ .a", false, 0, {14, 0, 0, 0, 0, 0, 14}},
- {"#foo::shadow .a", false, 0, {14, 0, 0, 0, 0, 0, 14}},
- {"::content .a", false, 0, {14, 0, 0, 0, 0, 14, 0}},
- {"#foo /deep/ .a", true, 0, {14, 0, 0, 0, 0, 0, 14}},
- {"#foo::shadow .a", true, 0, {14, 0, 0, 0, 0, 0, 14}},
- {"::content .a", true, 0, {14, 0, 0, 0, 0, 14, 0}},
};
RunTests(*document, kTestCases);
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_change_reason.cc b/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
index b7b0b868261..ca40b55182c 100644
--- a/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_change_reason.cc
@@ -30,8 +30,10 @@ const char kInlineCSSStyleMutated[] =
const char kInspector[] = "Inspector";
const char kLanguage[] = "Language";
const char kLinkColorChange[] = "LinkColorChange";
+const char kPictureSourceChanged[] = "PictureSourceChange";
const char kPlatformColorChange[] = "PlatformColorChange";
const char kPluginChanged[] = "Plugin Changed";
+const char kPopupVisibilityChange[] = "Popup Visibility Change";
const char kPropertyRegistration[] = "PropertyRegistration";
const char kPseudoClass[] = "PseudoClass";
const char kScrollTimeline[] = "ScrollTimeline";
diff --git a/chromium/third_party/blink/renderer/core/css/style_change_reason.h b/chromium/third_party/blink/renderer/core/css/style_change_reason.h
index 76cbd3c0c5a..cdd0ec20f0b 100644
--- a/chromium/third_party/blink/renderer/core/css/style_change_reason.h
+++ b/chromium/third_party/blink/renderer/core/css/style_change_reason.h
@@ -31,8 +31,10 @@ extern const char kInlineCSSStyleMutated[];
extern const char kInspector[];
extern const char kLanguage[];
extern const char kLinkColorChange[];
+extern const char kPictureSourceChanged[];
extern const char kPlatformColorChange[];
extern const char kPluginChanged[];
+extern const char kPopupVisibilityChange[];
extern const char kPropertyRegistration[];
extern const char kPseudoClass[];
extern const char kScrollTimeline[];
diff --git a/chromium/third_party/blink/renderer/core/css/style_color.cc b/chromium/third_party/blink/renderer/core/css/style_color.cc
index 37b09660ace..0a9dab2cd79 100644
--- a/chromium/third_party/blink/renderer/core/css/style_color.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_color.cc
@@ -10,18 +10,21 @@
namespace blink {
Color StyleColor::Resolve(Color current_color,
- mojom::blink::ColorScheme color_scheme) const {
+ mojom::blink::ColorScheme color_scheme,
+ bool is_forced_color) const {
if (IsCurrentColor())
return current_color;
- if (EffectiveColorKeyword() != CSSValueID::kInvalid)
+ if (EffectiveColorKeyword() != CSSValueID::kInvalid ||
+ (is_forced_color && IsSystemColor()))
return ColorFromKeyword(color_keyword_, color_scheme);
return color_;
}
Color StyleColor::ResolveWithAlpha(Color current_color,
mojom::blink::ColorScheme color_scheme,
- int alpha) const {
- Color color = Resolve(current_color, color_scheme);
+ int alpha,
+ bool is_forced_color) const {
+ Color color = Resolve(current_color, color_scheme, is_forced_color);
return Color(color.Red(), color.Green(), color.Blue(), alpha);
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_color.h b/chromium/third_party/blink/renderer/core/css/style_color.h
index 3193b404181..4cab8f2cade 100644
--- a/chromium/third_party/blink/renderer/core/css/style_color.h
+++ b/chromium/third_party/blink/renderer/core/css/style_color.h
@@ -71,14 +71,20 @@ class CORE_EXPORT StyleColor {
return color_keyword_;
}
+ // TODO(1081945): Once CSSSystemColorComputeToSelf is enabled, we can remove
+ // |is_forced_color|.
Color Resolve(Color current_color,
- mojom::blink::ColorScheme color_scheme) const;
+ mojom::blink::ColorScheme color_scheme,
+ bool is_forced_color = false) const;
// Resolve and override the resolved color's alpha channel as specified by
// |alpha|.
+ // TODO(1081945): Once CSSSystemColorComputeToSelf is enabled, we can remove
+ // |is_forced_color|.
Color ResolveWithAlpha(Color current_color,
mojom::blink::ColorScheme color_scheme,
- int alpha) const;
+ int alpha,
+ bool is_forced_color = false) const;
bool IsNumeric() const {
return EffectiveColorKeyword() == CSSValueID::kInvalid;
diff --git a/chromium/third_party/blink/renderer/core/css/style_element.cc b/chromium/third_party/blink/renderer/core/css/style_element.cc
index 7e6e23ff100..c255d8e5dde 100644
--- a/chromium/third_party/blink/renderer/core/css/style_element.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_element.cc
@@ -131,7 +131,7 @@ StyleElement::ProcessingResult StyleElement::CreateSheet(Element& element,
DCHECK(element.isConnected());
Document& document = element.GetDocument();
- const ContentSecurityPolicy* csp =
+ ContentSecurityPolicy* csp =
element.GetExecutionContext()
? element.GetExecutionContext()
->GetContentSecurityPolicyForCurrentWorld()
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine.cc b/chromium/third_party/blink/renderer/core/css/style_engine.cc
index 3c77ef95b2b..348528e8ec7 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_engine.cc
@@ -32,6 +32,8 @@
#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
+#include "third_party/blink/renderer/core/css/container_query_evaluator.h"
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
#include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
#include "third_party/blink/renderer/core/css/css_font_family_value.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
@@ -75,6 +77,8 @@
#include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -100,10 +104,9 @@ namespace {
CSSFontSelector* CreateCSSFontSelectorFor(Document& document) {
DCHECK(document.GetFrame());
- if (UNLIKELY(document.GetFrame()->PagePopupOwner())) {
+ if (UNLIKELY(document.GetFrame()->PagePopupOwner()))
return PagePopupController::CreateCSSFontSelector(document);
- }
- return MakeGarbageCollected<CSSFontSelector>(&document);
+ return MakeGarbageCollected<CSSFontSelector>(document);
}
} // namespace
@@ -380,62 +383,12 @@ void StyleEngine::AddedCustomElementDefaultStyles(
global_rule_set_->MarkDirty();
}
-namespace {
-
-bool HasMediaQueries(const ActiveStyleSheetVector& active_style_sheets) {
- for (const auto& active_sheet : active_style_sheets) {
- if (const MediaQuerySet* media_queries =
- active_sheet.first->MediaQueries()) {
- if (!media_queries->QueryVector().IsEmpty())
- return true;
- }
- StyleSheetContents* contents = active_sheet.first->Contents();
- if (contents->HasMediaQueries())
- return true;
- }
- return false;
-}
-
-bool HasSizeDependentMediaQueries(
- const ActiveStyleSheetVector& active_style_sheets) {
- for (const auto& active_sheet : active_style_sheets) {
- if (active_sheet.first->HasMediaQueryResults())
- return true;
- StyleSheetContents* contents = active_sheet.first->Contents();
- if (!contents->HasRuleSet())
- continue;
- if (contents->GetRuleSet().Features().HasMediaQueryResults())
- return true;
- }
- return false;
-}
-
-} // namespace
-
-bool StyleEngine::MediaQueryAffectingValueChanged(
- const ActiveStyleSheetVector& active_sheets,
- MediaValueChange change) {
- if (change == MediaValueChange::kSize)
- return HasSizeDependentMediaQueries(active_sheets);
-
- DCHECK(change == MediaValueChange::kOther);
- return HasMediaQueries(active_sheets);
-}
-
void StyleEngine::MediaQueryAffectingValueChanged(TreeScope& tree_scope,
MediaValueChange change) {
auto* collection = StyleSheetCollectionFor(tree_scope);
DCHECK(collection);
- if (MediaQueryAffectingValueChanged(collection->ActiveAuthorStyleSheets(),
- change)) {
+ if (AffectedByMediaValueChange(collection->ActiveStyleSheets(), change))
SetNeedsActiveStyleUpdate(tree_scope);
- }
-}
-
-void StyleEngine::MediaQueriesChangedInScope(TreeScope& tree_scope) {
- if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver())
- resolver->SetNeedsAppendAllSheets();
- SetNeedsActiveStyleUpdate(tree_scope);
}
void StyleEngine::WatchedSelectorsChanged() {
@@ -497,7 +450,7 @@ void StyleEngine::MediaQueryAffectingValueChanged(
}
}
- if (style_needs_recalc) {
+ if (style_needs_recalc && text_track->Owner()) {
// Use kSubtreeTreeStyleChange instead of RuleSet style invalidation
// because it won't be expensive for tracks and we won't have dynamic
// changes.
@@ -509,7 +462,7 @@ void StyleEngine::MediaQueryAffectingValueChanged(
}
void StyleEngine::MediaQueryAffectingValueChanged(MediaValueChange change) {
- if (MediaQueryAffectingValueChanged(active_user_style_sheets_, change))
+ if (AffectedByMediaValueChange(active_user_style_sheets_, change))
MarkUserStyleDirty();
MediaQueryAffectingValueChanged(GetDocument(), change);
MediaQueryAffectingValueChanged(active_tree_scopes_, change);
@@ -588,6 +541,13 @@ void StyleEngine::UpdateActiveStyleSheets() {
active_tree_scopes_.erase(tree_scope);
}
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ // TODO(crbug.com/687225): We initialize the predefined counter styles here.
+ // Moving the initialization to other places causes test failures, which
+ // needs investigation and fixing.
+ CounterStyleMap::GetUACounterStyleMap();
+ }
+
probe::ActiveStyleSheetsUpdated(document_);
dirty_tree_scopes_.clear();
@@ -596,6 +556,16 @@ void StyleEngine::UpdateActiveStyleSheets() {
user_style_dirty_ = false;
}
+void StyleEngine::UpdateCounterStyles() {
+ if (!counter_styles_need_update_)
+ return;
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+ CounterStyleMap::MarkAllDirtyCounterStyles(GetDocument(),
+ active_tree_scopes_);
+ CounterStyleMap::ResolveAllReferences(GetDocument(), active_tree_scopes_);
+ counter_styles_need_update_ = false;
+}
+
void StyleEngine::UpdateViewport() {
if (viewport_resolver_)
viewport_resolver_->UpdateViewport(GetDocumentStyleSheetCollection());
@@ -621,16 +591,16 @@ const ActiveStyleSheetVector StyleEngine::ActiveStyleSheetsForInspector() {
UpdateActiveStyle();
if (active_tree_scopes_.IsEmpty())
- return GetDocumentStyleSheetCollection().ActiveAuthorStyleSheets();
+ return GetDocumentStyleSheetCollection().ActiveStyleSheets();
ActiveStyleSheetVector active_style_sheets;
active_style_sheets.AppendVector(
- GetDocumentStyleSheetCollection().ActiveAuthorStyleSheets());
+ GetDocumentStyleSheetCollection().ActiveStyleSheets());
for (TreeScope* tree_scope : active_tree_scopes_) {
if (TreeScopeStyleSheetCollection* collection =
style_sheet_collection_map_.at(tree_scope))
- active_style_sheets.AppendVector(collection->ActiveAuthorStyleSheets());
+ active_style_sheets.AppendVector(collection->ActiveStyleSheets());
}
// FIXME: Inspector needs a vector which has all active stylesheets.
@@ -656,13 +626,7 @@ void StyleEngine::ShadowRootRemovedFromDocument(ShadowRoot* shadow_root) {
ResetAuthorStyle(*shadow_root);
}
-void StyleEngine::AddTreeBoundaryCrossingScope(const TreeScope& tree_scope) {
- tree_boundary_crossing_scopes_.Add(&tree_scope.RootNode());
-}
-
void StyleEngine::ResetAuthorStyle(TreeScope& tree_scope) {
- tree_boundary_crossing_scopes_.Remove(&tree_scope.RootNode());
-
ScopedStyleResolver* scoped_resolver = tree_scope.GetScopedStyleResolver();
if (!scoped_resolver)
return;
@@ -670,7 +634,7 @@ void StyleEngine::ResetAuthorStyle(TreeScope& tree_scope) {
if (global_rule_set_)
global_rule_set_->MarkDirty();
if (tree_scope.RootNode().IsDocumentNode()) {
- scoped_resolver->ResetAuthorStyle();
+ scoped_resolver->ResetStyle();
return;
}
@@ -718,7 +682,6 @@ void StyleEngine::DidDetach() {
if (global_rule_set_)
global_rule_set_->Dispose();
global_rule_set_ = nullptr;
- tree_boundary_crossing_scopes_.Clear();
dirty_tree_scopes_.clear();
active_tree_scopes_.clear();
viewport_resolver_ = nullptr;
@@ -734,7 +697,8 @@ void StyleEngine::DidDetach() {
environment_variables_ = nullptr;
}
-bool StyleEngine::ClearFontFaceCacheAndAddUserFonts() {
+bool StyleEngine::ClearFontFaceCacheAndAddUserFonts(
+ const ActiveStyleSheetVector& user_sheets) {
bool fonts_changed = false;
if (font_selector_ &&
@@ -745,9 +709,9 @@ bool StyleEngine::ClearFontFaceCacheAndAddUserFonts() {
}
// Rebuild the font cache with @font-face rules from user style sheets.
- for (unsigned i = 0; i < active_user_style_sheets_.size(); ++i) {
- DCHECK(active_user_style_sheets_[i].second);
- if (AddUserFontFaceRules(*active_user_style_sheets_[i].second))
+ for (unsigned i = 0; i < user_sheets.size(); ++i) {
+ DCHECK(user_sheets[i].second);
+ if (AddUserFontFaceRules(*user_sheets[i].second))
fonts_changed = true;
}
@@ -903,6 +867,7 @@ void StyleEngine::InvalidateStyleAndLayoutForFontUpdates() {
root->MarkSubtreeNeedsStyleRecalcForFontUpdates();
}
+ // TODO(xiaochengh): Move layout invalidation after style update.
if (LayoutView* layout_view = GetDocument().GetLayoutView()) {
TRACE_EVENT0("blink", "LayoutObject::InvalidateSubtreeForFontUpdates");
layout_view->InvalidateSubtreeLayoutForFontUpdates();
@@ -914,6 +879,13 @@ void StyleEngine::MarkFontsNeedUpdate() {
GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
}
+void StyleEngine::MarkCounterStylesNeedUpdate() {
+ counter_styles_need_update_ = true;
+ if (LayoutView* layout_view = GetDocument().GetLayoutView())
+ layout_view->SetNeedsMarkerOrCounterUpdate();
+ GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
+}
+
void StyleEngine::FontsNeedUpdate(FontSelector*, FontInvalidationReason) {
if (!GetDocument().IsActive())
return;
@@ -929,6 +901,7 @@ void StyleEngine::FontsNeedUpdate(FontSelector*, FontInvalidationReason) {
void StyleEngine::PlatformColorsChanged() {
UpdateForcedBackgroundColor();
+ UpdateColorSchemeBackground(/* color_scheme_changed */ true);
if (resolver_)
resolver_->InvalidateMatchedPropertiesCache();
MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
@@ -1425,6 +1398,17 @@ void StyleEngine::EnsureUAStyleForPseudoElement(PseudoId pseudo_id) {
}
}
+void StyleEngine::EnsureUAStyleForForcedColors() {
+ DCHECK(!IsHTMLImport());
+ DCHECK(global_rule_set_);
+ if (CSSDefaultStyleSheets::Instance()
+ .EnsureDefaultStyleSheetForForcedColors()) {
+ global_rule_set_->MarkDirty();
+ if (GetDocument().IsActive())
+ UpdateActiveStyle();
+ }
+}
+
bool StyleEngine::HasRulesForId(const AtomicString& id) const {
DCHECK(!IsHTMLImport());
DCHECK(global_rule_set_);
@@ -1481,15 +1465,6 @@ void StyleEngine::HtmlImportAddedOrRemoved() {
}
}
-void StyleEngine::V0ShadowAddedOnV1Document() {
- // No need to look into the ScopedStyleResolver for document, as ::slotted
- // never matches anything in a document tree.
- for (TreeScope* tree_scope : active_tree_scopes_) {
- if (ScopedStyleResolver* resolver = tree_scope->GetScopedStyleResolver())
- resolver->V0ShadowAddedOnV1Document();
- }
-}
-
namespace {
enum RuleSetFlags {
@@ -1498,6 +1473,7 @@ enum RuleSetFlags {
kFullRecalcRules = 1 << 2,
kPropertyRules = 1 << 3,
kScrollTimelineRules = 1 << 4,
+ kCounterStyleRules = 1 << 5,
};
unsigned GetRuleSetFlags(const HeapHashSet<Member<RuleSet>> rule_sets) {
@@ -1512,6 +1488,8 @@ unsigned GetRuleSetFlags(const HeapHashSet<Member<RuleSet>> rule_sets) {
flags |= kFullRecalcRules;
if (!rule_set->PropertyRules().IsEmpty())
flags |= kPropertyRules;
+ if (!rule_set->CounterStyleRules().IsEmpty())
+ flags |= kCounterStyleRules;
if (!rule_set->ScrollTimelineRules().IsEmpty())
flags |= kScrollTimelineRules;
}
@@ -1583,7 +1561,8 @@ void StyleEngine::ApplyUserRuleSetChanges(
scoped_resolver->SetNeedsAppendAllSheets();
MarkDocumentDirty();
} else {
- has_rebuilt_font_face_cache = ClearFontFaceCacheAndAddUserFonts();
+ has_rebuilt_font_face_cache =
+ ClearFontFaceCacheAndAddUserFonts(new_style_sheets);
}
}
@@ -1599,6 +1578,20 @@ void StyleEngine::ApplyUserRuleSetChanges(
ScopedStyleResolver::KeyframesRulesAdded(GetDocument());
}
+ if (changed_rule_flags & kCounterStyleRules) {
+ if (change == kActiveSheetsChanged && user_counter_style_map_)
+ user_counter_style_map_->Dispose();
+
+ for (auto* it = new_style_sheets.begin(); it != new_style_sheets.end();
+ it++) {
+ DCHECK(it->second);
+ if (!it->second->CounterStyleRules().IsEmpty())
+ EnsureUserCounterStyleMap().AddCounterStyles(*it->second);
+ }
+
+ MarkCounterStylesNeedUpdate();
+ }
+
if (changed_rule_flags & (kPropertyRules | kScrollTimelineRules)) {
if (changed_rule_flags & kPropertyRules) {
ClearPropertyRules();
@@ -1662,6 +1655,9 @@ void StyleEngine::ApplyRuleSetChanges(
if (changed_rule_flags & kKeyframesRules)
ScopedStyleResolver::KeyframesRulesAdded(tree_scope);
+ if (changed_rule_flags & kCounterStyleRules)
+ MarkCounterStylesNeedUpdate();
+
if ((changed_rule_flags & kPropertyRules) || rebuild_at_property_registry) {
// @property rules are (for now) ignored in shadow trees, per spec.
// https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule
@@ -1684,8 +1680,10 @@ void StyleEngine::ApplyRuleSetChanges(
}
bool has_rebuilt_font_face_cache = false;
- if (rebuild_font_face_cache)
- has_rebuilt_font_face_cache = ClearFontFaceCacheAndAddUserFonts();
+ if (rebuild_font_face_cache) {
+ has_rebuilt_font_face_cache =
+ ClearFontFaceCacheAndAddUserFonts(active_user_style_sheets_);
+ }
unsigned append_start_index = 0;
if (scoped_resolver) {
@@ -1699,7 +1697,7 @@ void StyleEngine::ApplyRuleSetChanges(
else if (change == kActiveSheetsAppended)
append_start_index = old_style_sheets.size();
else
- scoped_resolver->ResetAuthorStyle();
+ scoped_resolver->ResetStyle();
}
if (!new_style_sheets.IsEmpty()) {
@@ -1813,6 +1811,7 @@ void StyleEngine::EnvironmentVariableChanged() {
}
void StyleEngine::MarkForWhitespaceReattachment() {
+ DCHECK(GetDocument().InStyleRecalc());
for (auto element : whitespace_reattach_set_) {
if (element->NeedsReattachLayoutTree() || !element->GetLayoutObject())
continue;
@@ -1863,7 +1862,7 @@ void StyleEngine::NodeWillBeRemoved(Node& node) {
void StyleEngine::ChildrenRemoved(ContainerNode& parent) {
if (!parent.isConnected())
return;
- if (in_dom_removal_) {
+ if (InDOMRemoval()) {
// This is necessary for nested removals. There are elements which
// removes parts of its UA shadow DOM as part of being removed which means
// we do a removal from within another removal where isConnected() is not
@@ -1873,10 +1872,10 @@ void StyleEngine::ChildrenRemoved(ContainerNode& parent) {
// TODO(crbug.com/888448): TextFieldInputType::ListAttributeTargetChanged
return;
}
- style_invalidation_root_.ChildrenRemoved(parent);
- style_recalc_root_.ChildrenRemoved(parent);
+ style_invalidation_root_.SubtreeModified(parent);
+ style_recalc_root_.SubtreeModified(parent);
DCHECK(!layout_tree_rebuild_root_.GetRootNode());
- layout_tree_rebuild_root_.ChildrenRemoved(parent);
+ layout_tree_rebuild_root_.SubtreeModified(parent);
}
void StyleEngine::CollectMatchingUserRules(
@@ -1929,9 +1928,6 @@ bool StyleEngine::AddUserFontFaceRules(const RuleSet& rule_set) {
}
void StyleEngine::AddUserKeyframeRules(const RuleSet& rule_set) {
- if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled())
- return;
-
const HeapVector<Member<StyleRuleKeyframes>> keyframes_rules =
rule_set.KeyframesRules();
for (unsigned i = 0; i < keyframes_rules.size(); ++i)
@@ -1939,8 +1935,6 @@ void StyleEngine::AddUserKeyframeRules(const RuleSet& rule_set) {
}
void StyleEngine::AddUserKeyframeStyle(StyleRuleKeyframes* rule) {
- DCHECK(!RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled());
-
AtomicString animation_name(rule->GetName());
if (rule->IsVendorPrefixed()) {
@@ -1977,11 +1971,6 @@ void StyleEngine::AddScrollTimelineRules(const RuleSet& rule_set) {
StyleRuleKeyframes* StyleEngine::KeyframeStylesForAnimation(
const AtomicString& animation_name) {
- if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled()) {
- return ScopedStyleResolver::KeyframeStylesForAnimationFromActiveSheets(
- animation_name, active_user_style_sheets_);
- }
-
if (keyframes_rule_map_.IsEmpty())
return nullptr;
@@ -2015,22 +2004,70 @@ scoped_refptr<StyleInitialData> StyleEngine::MaybeCreateAndGetInitialData() {
return initial_data_;
}
-void StyleEngine::RecalcStyle() {
+void StyleEngine::UpdateStyleAndLayoutTreeForContainer(
+ Element& container,
+ const LogicalSize& logical_size,
+ LogicalAxes contained_axes) {
+ DCHECK(!style_recalc_root_.GetRootNode());
+ DCHECK(!container.NeedsStyleRecalc());
+ DCHECK(!in_container_query_style_recalc_);
+
+ base::AutoReset<bool> cq_recalc(&in_container_query_style_recalc_, true);
+
+ WritingMode writing_mode = container.ComputedStyleRef().GetWritingMode();
+ PhysicalSize physical_size = ToPhysicalSize(logical_size, writing_mode);
+ PhysicalAxes physical_axes = ToPhysicalAxes(contained_axes, writing_mode);
+
+ if (auto* evaluator = container.GetContainerQueryEvaluator()) {
+ if (!evaluator->ContainerChanged(physical_size, physical_axes))
+ return;
+ } else {
+ container.SetContainerQueryEvaluator(
+ MakeGarbageCollected<ContainerQueryEvaluator>(physical_size,
+ physical_axes));
+ }
+
+ style_recalc_root_.Update(nullptr, &container);
+ RecalcStyle({StyleRecalcChange::kRecalcContainerQueryDependent},
+ StyleRecalcContext());
+
+ // Nodes are marked for whitespace reattachment for DOM removal only. This set
+ // should have been cleared before layout.
+ DCHECK(!NeedsWhitespaceReattachment());
+
+ if (container.ChildNeedsReattachLayoutTree()) {
+ DCHECK(layout_tree_rebuild_root_.GetRootNode());
+ if (layout_tree_rebuild_root_.GetRootNode()->IsDocumentNode()) {
+ // Avoid traversing from outside the container root. We know none of the
+ // elements outside the subtree should be marked dirty in this pass, but
+ // we may have fallen back to the document root.
+ layout_tree_rebuild_root_.Clear();
+ layout_tree_rebuild_root_.Update(nullptr, &container);
+ }
+ RebuildLayoutTree();
+ }
+
+ GetDocument().GetLayoutView()->UpdateMarkersAndCountersAfterStyleChange();
+}
+
+void StyleEngine::RecalcStyle(StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(GetDocument().documentElement());
- Element* root_element = &style_recalc_root_.RootElement();
- Element* parent = root_element->ParentOrShadowHostElement();
+ Element& root_element = style_recalc_root_.RootElement();
+ Element* parent = FlatTreeTraversal::ParentElement(root_element);
SelectorFilterRootScope filter_scope(parent);
- root_element->RecalcStyle({});
+ root_element.RecalcStyle(change, style_recalc_context);
- for (ContainerNode* ancestor = root_element->GetStyleRecalcParent(); ancestor;
+ for (ContainerNode* ancestor = root_element.GetStyleRecalcParent(); ancestor;
ancestor = ancestor->GetStyleRecalcParent()) {
if (auto* ancestor_element = DynamicTo<Element>(ancestor))
ancestor_element->RecalcStyleForTraversalRootAncestor();
ancestor->ClearChildNeedsStyleRecalc();
}
style_recalc_root_.Clear();
- PropagateWritingModeAndDirectionToHTMLRoot();
+ if (!parent || IsA<HTMLBodyElement>(root_element))
+ PropagateWritingModeAndDirectionToHTMLRoot();
}
void StyleEngine::ClearEnsuredDescendantStyles(Element& root) {
@@ -2053,7 +2090,7 @@ void StyleEngine::ClearEnsuredDescendantStyles(Element& root) {
void StyleEngine::RebuildLayoutTree() {
DCHECK(GetDocument().documentElement());
DCHECK(!InRebuildLayoutTree());
- in_layout_tree_rebuild_ = true;
+ base::AutoReset<bool> rebuild_scope(&in_layout_tree_rebuild_, true);
// We need a root scope here in case we recalc style for ::first-letter
// elements as part of UpdateFirstLetterPseudoElement.
@@ -2073,7 +2110,6 @@ void StyleEngine::RebuildLayoutTree() {
ancestor->ClearChildNeedsReattachLayoutTree();
}
layout_tree_rebuild_root_.Clear();
- in_layout_tree_rebuild_ = false;
}
void StyleEngine::UpdateStyleAndLayoutTree() {
@@ -2112,6 +2148,10 @@ void StyleEngine::UpdateStyleAndLayoutTree() {
}
void StyleEngine::ViewportDefiningElementDidChange() {
+ // Guarded by if-test in UpdateStyleAndLayoutTree().
+ DCHECK(GetDocument().documentElement());
+ if (GetDocument().documentElement()->NeedsReattachLayoutTree())
+ return;
HTMLBodyElement* body = GetDocument().FirstBodyElement();
if (!body || body->NeedsReattachLayoutTree())
return;
@@ -2132,7 +2172,7 @@ void StyleEngine::UpdateStyleInvalidationRoot(ContainerNode* ancestor,
Node* dirty_node) {
DCHECK(!IsHTMLImport());
if (GetDocument().IsActive()) {
- if (in_dom_removal_) {
+ if (InDOMRemoval()) {
ancestor = nullptr;
dirty_node = document_;
}
@@ -2154,8 +2194,8 @@ void StyleEngine::UpdateStyleRecalcRoot(ContainerNode* ancestor,
DCHECK(allow_mark_style_dirty_from_recalc_);
return;
}
- DCHECK(!in_layout_tree_rebuild_);
- if (in_dom_removal_) {
+ DCHECK(!InRebuildLayoutTree());
+ if (InDOMRemoval()) {
ancestor = nullptr;
dirty_node = document_;
}
@@ -2164,9 +2204,24 @@ void StyleEngine::UpdateStyleRecalcRoot(ContainerNode* ancestor,
void StyleEngine::UpdateLayoutTreeRebuildRoot(ContainerNode* ancestor,
Node* dirty_node) {
- DCHECK(!in_dom_removal_);
- if (GetDocument().IsActive())
- layout_tree_rebuild_root_.Update(ancestor, dirty_node);
+ DCHECK(!InDOMRemoval());
+ if (!GetDocument().IsActive())
+ return;
+ if (InRebuildLayoutTree()) {
+ DCHECK(allow_mark_for_reattach_from_rebuild_layout_tree_);
+ return;
+ }
+ DCHECK(GetDocument().InStyleRecalc());
+ DCHECK(dirty_node);
+ if (!ancestor && !dirty_node->NeedsReattachLayoutTree() &&
+ !dirty_node->ChildNeedsReattachLayoutTree()) {
+ // The StyleTraversalRoot requires the root node to be dirty or child-dirty.
+ // When we mark for whitespace re-attachment, we only mark the ancestor
+ // chain. Use the parent as the dirty node if the dirty_node is not dirty.
+ dirty_node = dirty_node->GetReattachParent();
+ DCHECK(dirty_node && dirty_node->ChildNeedsReattachLayoutTree());
+ }
+ layout_tree_rebuild_root_.Update(ancestor, dirty_node);
}
bool StyleEngine::SupportsDarkColorScheme() {
@@ -2216,13 +2271,10 @@ void StyleEngine::UpdateColorScheme() {
if (GetDocument().Printing())
preferred_color_scheme_ = mojom::blink::PreferredColorScheme::kLight;
- bool color_scheme_changed = false;
if (forced_colors_ != old_forced_colors ||
preferred_color_scheme_ != old_preferred_color_scheme) {
PlatformColorsChanged();
- color_scheme_changed = true;
}
- UpdateColorSchemeBackground(color_scheme_changed);
UpdateColorSchemeMetrics();
}
@@ -2374,6 +2426,35 @@ void StyleEngine::PropagateWritingModeAndDirectionToHTMLRoot() {
root_element->PropagateWritingModeAndDirectionFromBody();
}
+CounterStyleMap& StyleEngine::EnsureUserCounterStyleMap() {
+ if (!user_counter_style_map_) {
+ user_counter_style_map_ =
+ CounterStyleMap::CreateUserCounterStyleMap(GetDocument());
+ }
+ return *user_counter_style_map_;
+}
+
+const CounterStyle& StyleEngine::FindCounterStyleAcrossScopes(
+ const AtomicString& name,
+ const TreeScope* scope) const {
+ CounterStyleMap* target_map = nullptr;
+ while (scope) {
+ if (CounterStyleMap* map =
+ CounterStyleMap::GetAuthorCounterStyleMap(*scope)) {
+ target_map = map;
+ break;
+ }
+ scope = scope->ParentTreeScope();
+ }
+ if (!target_map && user_counter_style_map_)
+ target_map = user_counter_style_map_;
+ if (!target_map)
+ target_map = CounterStyleMap::GetUACounterStyleMap();
+ if (CounterStyle* result = target_map->FindCounterStyleAcrossScopes(name))
+ return *result;
+ return CounterStyle::GetDecimal();
+}
+
void StyleEngine::Trace(Visitor* visitor) const {
visitor->Trace(document_);
visitor->Trace(injected_user_style_sheets_);
@@ -2381,13 +2462,13 @@ void StyleEngine::Trace(Visitor* visitor) const {
visitor->Trace(active_user_style_sheets_);
visitor->Trace(custom_element_default_style_sheets_);
visitor->Trace(keyframes_rule_map_);
+ visitor->Trace(user_counter_style_map_);
visitor->Trace(scroll_timeline_map_);
visitor->Trace(inspector_style_sheet_);
visitor->Trace(document_style_sheet_collection_);
visitor->Trace(style_sheet_collection_map_);
visitor->Trace(dirty_tree_scopes_);
visitor->Trace(active_tree_scopes_);
- visitor->Trace(tree_boundary_crossing_scopes_);
visitor->Trace(resolver_);
visitor->Trace(vision_deficiency_filter_);
visitor->Trace(viewport_resolver_);
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine.h b/chromium/third_party/blink/renderer/core/css/style_engine.h
index b7169d2304f..89efdb87740 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine.h
+++ b/chromium/third_party/blink/renderer/core/css/style_engine.h
@@ -52,6 +52,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/tree_ordered_list.h"
#include "third_party/blink/renderer/core/html/track/text_track.h"
+#include "third_party/blink/renderer/core/layout/geometry/axis.h"
#include "third_party/blink/renderer/core/style/filter_operations.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/fonts/font_selector_client.h"
@@ -62,6 +63,8 @@
namespace blink {
+class CounterStyle;
+class CounterStyleMap;
class CSSFontSelector;
class CSSStyleSheet;
class FontSelector;
@@ -75,6 +78,7 @@ class StyleRuleUsageTracker;
class StyleSheetContents;
class StyleInitialData;
class ViewportStyleResolver;
+struct LogicalSize;
enum InvalidationScope { kInvalidateCurrentScope, kInvalidateAllScopes };
@@ -117,6 +121,24 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
base::AutoReset<bool> allow_marking_;
};
+ // We postpone updating ::first-letter styles until layout tree rebuild to
+ // know which text node contains the first letter. If we need to re-attach the
+ // ::first-letter element as a result means we mark for re-attachment during
+ // layout tree rebuild. That is not generally allowed, and we make sure we
+ // explicitly allow it for that case.
+ class AllowMarkForReattachFromRebuildLayoutTreeScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit AllowMarkForReattachFromRebuildLayoutTreeScope(StyleEngine& engine)
+ : allow_marking_(
+ &engine.allow_mark_for_reattach_from_rebuild_layout_tree_,
+ true) {}
+
+ private:
+ base::AutoReset<bool> allow_marking_;
+ };
+
explicit StyleEngine(Document&);
~StyleEngine() override;
@@ -154,7 +176,6 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
const HeapVector<Member<CSSStyleSheet>>& new_sheets);
void AddedCustomElementDefaultStyles(
const HeapVector<Member<CSSStyleSheet>>& default_styles);
- void MediaQueriesChangedInScope(TreeScope&);
void WatchedSelectorsChanged();
void InitialStyleChanged();
void ColorSchemeChanged();
@@ -165,7 +186,6 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void InitialViewportChanged();
void ViewportRulesChanged();
void HtmlImportAddedOrRemoved();
- void V0ShadowAddedOnV1Document();
void InjectSheet(const StyleSheetKey&, StyleSheetContents*,
WebDocument::CSSOrigin =
@@ -229,10 +249,6 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void ShadowRootInsertedToDocument(ShadowRoot&);
void ShadowRootRemovedFromDocument(ShadowRoot*);
- void AddTreeBoundaryCrossingScope(const TreeScope&);
- const TreeOrderedList& TreeBoundaryCrossingScopes() const {
- return tree_boundary_crossing_scopes_;
- }
void ResetAuthorStyle(TreeScope&);
StyleResolver& GetStyleResolver() const {
@@ -297,6 +313,7 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void EnsureUAStyleForXrOverlay();
void EnsureUAStyleForElement(const Element&);
void EnsureUAStyleForPseudoElement(PseudoId);
+ void EnsureUAStyleForForcedColors();
void PlatformColorsChanged();
@@ -336,7 +353,7 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
style_recalc_root_.RemovedFromFlatTree(node);
}
void PseudoElementRemoved(Element& originating_element) {
- layout_tree_rebuild_root_.ChildrenRemoved(originating_element);
+ layout_tree_rebuild_root_.SubtreeModified(originating_element);
}
unsigned StyleForElementCount() const { return style_for_element_count_; }
@@ -379,10 +396,17 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void MarkFontsNeedUpdate();
void InvalidateStyleAndLayoutForFontUpdates();
+ void MarkCounterStylesNeedUpdate();
+ void UpdateCounterStyles();
+
StyleRuleKeyframes* KeyframeStylesForAnimation(
const AtomicString& animation_name);
StyleRuleScrollTimeline* FindScrollTimelineRule(const AtomicString& name);
+ CounterStyleMap* GetUserCounterStyleMap() { return user_counter_style_map_; }
+ const CounterStyle& FindCounterStyleAcrossScopes(const AtomicString&,
+ const TreeScope*) const;
+
DocumentStyleEnvironmentVariables& EnsureEnvironmentVariables();
scoped_refptr<StyleInitialData> MaybeCreateAndGetInitialData();
@@ -399,10 +423,19 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void UpdateViewport();
void UpdateViewportStyle();
void UpdateStyleAndLayoutTree();
- void RecalcStyle();
+ // To be called from layout when container queries change for the container.
+ void UpdateStyleAndLayoutTreeForContainer(Element& container,
+ const LogicalSize&,
+ LogicalAxes contained_axes);
+ void RecalcStyle() { RecalcStyle({}, StyleRecalcContext()); }
+
void ClearEnsuredDescendantStyles(Element& element);
void RebuildLayoutTree();
bool InRebuildLayoutTree() const { return in_layout_tree_rebuild_; }
+ bool InDOMRemoval() const { return in_dom_removal_; }
+ bool InContainerQueryStyleRecalc() const {
+ return in_container_query_style_recalc_;
+ }
void SetColorSchemeFromMeta(const CSSValue* color_scheme);
const CSSValue* GetMetaColorSchemeValue() const { return meta_color_scheme_; }
@@ -414,8 +447,6 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
Color ForcedBackgroundColor() const { return forced_background_color_; }
Color ColorAdjustBackgroundColor() const;
- TreeScopeStyleSheetCollection* StyleSheetCollectionFor(TreeScope&);
-
void Trace(Visitor*) const override;
const char* NameInHeapSnapshot() const override { return "StyleEngine"; }
@@ -432,6 +463,7 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
}
TreeScopeStyleSheetCollection& EnsureStyleSheetCollectionFor(TreeScope&);
+ TreeScopeStyleSheetCollection* StyleSheetCollectionFor(TreeScope&);
bool ShouldUpdateDocumentStyleSheetCollection() const;
bool ShouldUpdateShadowTreeStyleSheetCollection() const;
@@ -507,7 +539,8 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void UpdateStyleSheetList(TreeScope&);
// Returns true if any @font-face rules are added or removed.
- bool ClearFontFaceCacheAndAddUserFonts();
+ bool ClearFontFaceCacheAndAddUserFonts(
+ const ActiveStyleSheetVector& user_sheets);
void ClearKeyframeRules() { keyframes_rule_map_.clear(); }
void ClearPropertyRules();
@@ -523,6 +556,8 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void AddPropertyRules(const RuleSet&);
void AddScrollTimelineRules(const RuleSet&);
+ CounterStyleMap& EnsureUserCounterStyleMap();
+
void UpdateColorScheme();
bool SupportsDarkColorScheme();
void UpdateForcedBackgroundColor();
@@ -532,6 +567,8 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void ViewportDefiningElementDidChange();
void PropagateWritingModeAndDirectionToHTMLRoot();
+ void RecalcStyle(StyleRecalcChange, const StyleRecalcContext&);
+
Member<Document> document_;
// True if this StyleEngine is for an HTML Import document.
@@ -577,21 +614,26 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
bool user_style_dirty_{false};
UnorderedTreeScopeSet dirty_tree_scopes_;
UnorderedTreeScopeSet active_tree_scopes_;
- TreeOrderedList tree_boundary_crossing_scopes_;
String preferred_stylesheet_set_name_;
bool uses_rem_units_{false};
bool in_layout_tree_rebuild_{false};
+ bool in_container_query_style_recalc_{false};
bool in_dom_removal_{false};
bool viewport_style_dirty_{false};
bool fonts_need_update_{false};
+ bool counter_styles_need_update_{false};
// Set to true if we allow marking style dirty from style recalc. Ideally, we
// should get rid of this, but we keep track of where we allow it with
// AllowMarkStyleDirtyFromRecalcScope.
bool allow_mark_style_dirty_from_recalc_{false};
+ // Set to true if we allow marking for reattachment from layout tree rebuild.
+ // AllowMarkStyleDirtyFromRecalcScope.
+ bool allow_mark_for_reattach_from_rebuild_layout_tree_{false};
+
VisionDeficiency vision_deficiency_{VisionDeficiency::kNoVisionDeficiency};
Member<ReferenceFilterOperation> vision_deficiency_filter_;
@@ -634,6 +676,8 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
HeapHashMap<AtomicString, Member<StyleRuleKeyframes>>;
KeyframesRuleMap keyframes_rule_map_;
+ Member<CounterStyleMap> user_counter_style_map_;
+
HeapHashMap<AtomicString, Member<StyleRuleScrollTimeline>>
scroll_timeline_map_;
diff --git a/chromium/third_party/blink/renderer/core/css/style_engine_test.cc b/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
index 9b25f111678..da73b70fe59 100644
--- a/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/css/forced_colors.h"
#include "third_party/blink/public/common/css/navigation_controls.h"
@@ -31,13 +32,17 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_collection.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_span_element.h"
#include "third_party/blink/renderer/core/html/html_style_element.h"
+#include "third_party/blink/renderer/core/layout/layout_counter.h"
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
+#include "third_party/blink/renderer/core/layout/list_marker.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
@@ -104,6 +109,13 @@ class StyleEngineTest : public testing::Test {
DCHECK(!IsUseCounted(feature));
}
+ String GetListMarkerText(LayoutObject* list_item) {
+ LayoutObject* marker = ListMarker::MarkerFromListItem(list_item);
+ if (auto* legacy_marker = DynamicTo<LayoutListMarker>(marker))
+ return legacy_marker->TextAlternative();
+ return ListMarker::Get(marker)->TextAlternative(*marker);
+ }
+
private:
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
};
@@ -651,6 +663,29 @@ TEST_F(StyleEngineTest, AnalyzedInject) {
t11->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor()));
}
+TEST_F(StyleEngineTest, InjectedUserNoAuthorFontFace) {
+ UpdateAllLifecyclePhases();
+
+ FontDescription font_description;
+ FontFaceCache* cache = GetStyleEngine().GetFontSelector()->GetFontFaceCache();
+ EXPECT_FALSE(cache->Get(font_description, "User"));
+
+ auto* user_sheet = MakeGarbageCollected<StyleSheetContents>(
+ MakeGarbageCollected<CSSParserContext>(GetDocument()));
+ user_sheet->ParseString(
+ "@font-face {"
+ " font-family: 'User';"
+ " src: url(font.ttf);"
+ "}");
+
+ StyleSheetKey user_key("user");
+ GetStyleEngine().InjectSheet(user_key, user_sheet, WebDocument::kUserOrigin);
+
+ UpdateAllLifecyclePhases();
+
+ EXPECT_TRUE(cache->Get(font_description, "User"));
+}
+
TEST_F(StyleEngineTest, InjectedFontFace) {
GetDocument().body()->setInnerHTML(R"HTML(
<style>
@@ -902,22 +937,6 @@ TEST_F(StyleEngineTest, RuleSetInvalidationHostContext) {
kRuleSetInvalidationFullRecalc);
}
-TEST_F(StyleEngineTest, RuleSetInvalidationV0BoundaryCrossing) {
- GetDocument().body()->setInnerHTML("<div id=host></div>");
- Element* host = GetDocument().getElementById("host");
- ASSERT_TRUE(host);
-
- ShadowRoot& shadow_root =
- host->AttachShadowRootInternal(ShadowRootType::kOpen);
-
- shadow_root.setInnerHTML("<div></div><div class=a></div><div></div>");
- UpdateAllLifecyclePhases();
-
- EXPECT_EQ(ScheduleInvalidationsForRules(
- shadow_root, ".a ::content span { background: green}"),
- kRuleSetInvalidationFullRecalc);
-}
-
TEST_F(StyleEngineTest, HasViewportDependentMediaQueries) {
GetDocument().body()->setInnerHTML(R"HTML(
<style>div {}</style>
@@ -2033,14 +2052,19 @@ TEST_F(StyleEngineTest, GetComputedStyleOutsideFlatTreeCrash) {
body, div { display: contents }
div::before { display: contents; content: "" }
</style>
- <div id=inner></div>
+ <div id=host>
+ <!-- no slots here -->
+ </host>
+ <div id=non-slotted></div>
)HTML");
- GetDocument().documentElement()->CreateV0ShadowRootForTesting();
+ GetDocument().getElementById("host")->AttachShadowRootInternal(
+ ShadowRootType::kOpen);
UpdateAllLifecyclePhases();
GetDocument().body()->EnsureComputedStyle();
- GetDocument().getElementById("inner")->SetInlineStyleProperty(
- CSSPropertyID::kColor, "blue");
+ GetDocument()
+ .getElementById("non-slotted")
+ ->SetInlineStyleProperty(CSSPropertyID::kColor, "blue");
UpdateAllLifecyclePhases();
}
@@ -2094,7 +2118,9 @@ TEST_F(StyleEngineTest, MarkForWhitespaceReattachment) {
EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
GetStyleEngine().MarkForWhitespaceReattachment();
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
UpdateAllLifecyclePhases();
@@ -2106,7 +2132,9 @@ TEST_F(StyleEngineTest, MarkForWhitespaceReattachment) {
EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
GetStyleEngine().MarkForWhitespaceReattachment();
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
UpdateAllLifecyclePhases();
@@ -2117,7 +2145,9 @@ TEST_F(StyleEngineTest, MarkForWhitespaceReattachment) {
EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
GetStyleEngine().MarkForWhitespaceReattachment();
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
EXPECT_TRUE(GetStyleEngine().NeedsLayoutTreeRebuild());
}
@@ -2712,30 +2742,6 @@ TEST_F(StyleEngineTest, SlottedWithEnsuredStyleOutsideFlatTree) {
EXPECT_FALSE(span->GetComputedStyle());
}
-TEST_F(StyleEngineTest, RecalcEnsuredStyleOutsideFlatTreeV0) {
- GetDocument().body()->setInnerHTML(R"HTML(
- <div id="host"><span></span></div>
- )HTML");
-
- auto* host = GetDocument().getElementById("host");
- auto* span = To<Element>(host->firstChild());
-
- host->CreateV0ShadowRootForTesting();
- UpdateAllLifecyclePhases();
-
- EXPECT_FALSE(span->FlatTreeParentForChildDirty());
-
- // Ensure style outside the flat tree.
- const ComputedStyle* style = span->EnsureComputedStyle();
- ASSERT_TRUE(style);
- EXPECT_TRUE(style->IsEnsuredOutsideFlatTree());
- EXPECT_EQ(EDisplay::kInline, style->Display());
-
- span->SetInlineStyleProperty(CSSPropertyID::kDisplay, "block");
- EXPECT_FALSE(GetStyleRecalcRoot());
- EXPECT_FALSE(GetDocument().body()->ChildNeedsStyleRecalc());
-}
-
TEST_F(StyleEngineTest, ForceReattachRecalcRootAttachShadow) {
GetDocument().body()->setInnerHTML(R"HTML(
<div id="reattach"></div><div id="host"><span></span></div>
@@ -2916,29 +2922,6 @@ TEST_F(StyleEngineTest,
GetCSSPropertyColor()));
}
-TEST_F(StyleEngineTest, SummaryDisplayUseCount) {
- // Should not be use-counted: wrong element type.
- GetDocument().body()->setInnerHTML(
- "<style>div { display: block; }</style><div></div>");
- UpdateAllLifecyclePhases();
- EXPECT_FALSE(GetDocument().IsUseCounted(
- WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
-
- // Should not be use-counted: wrong display type:
- GetDocument().body()->setInnerHTML(
- "<style>summary { display: inline; }</style><summary></summary>");
- UpdateAllLifecyclePhases();
- EXPECT_FALSE(GetDocument().IsUseCounted(
- WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
-
- // Should be use-counted:
- GetDocument().body()->setInnerHTML(
- "<style>summary { display: block; }</style><summary></summary>");
- UpdateAllLifecyclePhases();
- EXPECT_TRUE(GetDocument().IsUseCounted(
- WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
-}
-
TEST_F(StyleEngineTest, RevertUseCount) {
GetDocument().body()->setInnerHTML(
"<style>div { display: unset; }</style><div></div>");
@@ -3453,32 +3436,21 @@ TEST_F(StyleEngineTest, MediaAttributeChangeUpdatesFontCacheVersion) {
UpdateAllLifecyclePhases();
}
-// https://crbug.com/1137624
-TEST_F(StyleEngineTest, DisabledAdvanceOverrideDescriptor) {
- ScopedCSSFontFaceAdvanceOverrideForTest advance_override_disabled(false);
-
- GetDocument().body()->setInnerHTML(R"HTML(
- <style>
- @font-face {
- font-family: custom-font;
- src: url(fake-font.woff);
- advance-override: 0.1;
- }
- </style>
- )HTML");
-
- // Shouldn't crash.
- UpdateAllLifecyclePhases();
-
- // 'advance-override' should be ignored when disabled.
- const FontFace* font_face = GetStyleEngine()
- .GetFontSelector()
- ->GetFontFaceCache()
- ->CssConnectedFontFaces()
- .front()
- .Get();
- ASSERT_TRUE(font_face);
- EXPECT_FALSE(font_face->HasFontMetricsOverride());
+// Properties stored for forced colors mode should only be usable by the UA.
+TEST_F(StyleEngineTest, InternalForcedProperties) {
+ String properties_to_test[] = {
+ "-internal-forced-background-color", "-internal-forced-border-color",
+ "-internal-forced-color", "-internal-forced-outline-color",
+ "-internal-forced-visited-color"};
+ for (auto property : properties_to_test) {
+ String declaration = property + ":red";
+ ASSERT_TRUE(
+ css_test_helpers::ParseDeclarationBlock(declaration, kHTMLStandardMode)
+ ->IsEmpty());
+ ASSERT_TRUE(
+ !css_test_helpers::ParseDeclarationBlock(declaration, kUASheetMode)
+ ->IsEmpty());
+ }
}
class StyleEngineSimTest : public SimTest {};
@@ -3747,4 +3719,498 @@ TEST_F(StyleEngineTest, CSSPseudoHostDynamicSpecificity) {
ClearUseCounter(WebFeature::kCSSPseudoHostDynamicSpecificity);
}
+namespace {
+
+void SetDependsOnContainerQueries(Element& element) {
+ if (const ComputedStyle* style = element.GetComputedStyle()) {
+ scoped_refptr<ComputedStyle> cloned_style = ComputedStyle::Clone(*style);
+ cloned_style->SetDependsOnContainerQueries(true);
+ element.SetComputedStyle(cloned_style);
+ }
+}
+
+void SetDependsOnContainerQueries(HTMLCollection& affected) {
+ for (Element* element : affected)
+ SetDependsOnContainerQueries(*element);
+}
+
+} // namespace
+
+TEST_F(StyleEngineTest, UpdateStyleAndLayoutTreeForContainer) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ .container {
+ contain: layout size;
+ }
+ </style>
+ <div id="container1" class="container">
+ <span class="affected"></span>
+ <div id="container2" class="container affected">
+ <span class="affected"></span>
+ <span></span>
+ <span class="affected"></span>
+ <span><span class="affected"></span></span>
+ <span class="affected"></span>
+ <div style="display:none" class="affected">
+ <span class="affected"></span>
+ </div>
+ <div style="display:none">
+ <span class="affected"></span>
+ <span class="affected"></span>
+ </div>
+ </div>
+ <span></span>
+ <div class="container">
+ <span class="affected"></span>
+ <span class="affected"></span>
+ </div>
+ <span class="container" style="display:inline-block">
+ <span class="affected"></span>
+ </span>
+ </div>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+
+ auto* container1 = GetDocument().getElementById("container1");
+ auto* container2 = GetDocument().getElementById("container2");
+ auto* affected = GetDocument().getElementsByClassName("affected");
+ ASSERT_TRUE(container1);
+ ASSERT_TRUE(container2);
+ ASSERT_TRUE(affected);
+ SetDependsOnContainerQueries(*affected);
+
+ unsigned start_count = GetStyleEngine().StyleForElementCount();
+ GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *container1, LogicalSize(), LogicalAxes(kLogicalAxisBoth));
+
+ // The first span.affected child and #container2
+ EXPECT_EQ(2u, GetStyleEngine().StyleForElementCount() - start_count);
+
+ start_count = GetStyleEngine().StyleForElementCount();
+ GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *container2, LogicalSize(), LogicalAxes(kLogicalAxisBoth));
+
+ // Three direct span.affected children, and the two display:none elements.
+ EXPECT_EQ(6u, GetStyleEngine().StyleForElementCount() - start_count);
+}
+
+TEST_F(StyleEngineTest, ContainerQueriesContainmentNotApplying) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ .container {
+ contain: layout size;
+ }
+ </style>
+ <div id="container" class="container">
+ <div class="container" style="display:contents">
+ <span class="affected"></span>
+ </div>
+ <span class="container">
+ <span class="affected"></span>
+ </span>
+ <rt class="container">
+ <span class="affected"></span>
+ </rt>
+ <div class="container" style="display:table">
+ <span class="affected"></span>
+ </div>
+ <div class="container" style="display:table-cell">
+ <span class="affected"></span>
+ </div>
+ <div class="container" style="display:table-row">
+ <span class="affected"></span>
+ </div>
+ <div class="container" style="display:table-row-group">
+ <span class="affected"></span>
+ </div>
+ </div>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+
+ auto* container = GetDocument().getElementById("container");
+ auto* affected = GetDocument().getElementsByClassName("affected");
+ ASSERT_TRUE(container);
+ ASSERT_TRUE(affected);
+ SetDependsOnContainerQueries(*affected);
+
+ unsigned start_count = GetStyleEngine().StyleForElementCount();
+ GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *container, LogicalSize(), LogicalAxes(kLogicalAxisBoth));
+
+ // span.affected is updated because containment does not apply to the display
+ // types on the element styled with containment. All marked as affected are
+ // recalculated.
+ EXPECT_EQ(7u, GetStyleEngine().StyleForElementCount() - start_count);
+}
+
+TEST_F(StyleEngineTest, PseudoElementContainerQueryRecalc) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ #container { contain: layout size }
+ #container::before { content: " " }
+ span::before { content: " " }
+ </style>
+ <div id="container">
+ <span id="span"></span>
+ </div>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+
+ auto* container = GetDocument().getElementById("container");
+ auto* span = GetDocument().getElementById("span");
+ ASSERT_TRUE(container);
+ ASSERT_TRUE(span);
+
+ auto* before = span->GetPseudoElement(kPseudoIdBefore);
+ ASSERT_TRUE(before);
+ SetDependsOnContainerQueries(*before);
+
+ before = container->GetPseudoElement(kPseudoIdBefore);
+ ASSERT_TRUE(before);
+ SetDependsOnContainerQueries(*before);
+
+ unsigned start_count = GetStyleEngine().StyleForElementCount();
+ GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *container, LogicalSize(), LogicalAxes(kLogicalAxisBoth));
+
+ EXPECT_EQ(2u, GetStyleEngine().StyleForElementCount() - start_count);
+}
+
+TEST_F(StyleEngineTest, MarkStyleDirtyFromContainerRecalc) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="container" style="contain: layout size">
+ <input id="input" type="text" class="affected">
+ </div>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+
+ auto* container = GetDocument().getElementById("container");
+ auto* input = GetDocument().getElementById("input");
+ auto* affected = GetDocument().getElementsByClassName("affected");
+ ASSERT_TRUE(container);
+ ASSERT_TRUE(input);
+ auto* inner_editor = DynamicTo<HTMLInputElement>(input)->InnerEditorElement();
+ ASSERT_TRUE(inner_editor);
+ ASSERT_TRUE(affected);
+ SetDependsOnContainerQueries(*affected);
+
+ scoped_refptr<const ComputedStyle> old_inner_style =
+ inner_editor->GetComputedStyle();
+ EXPECT_TRUE(old_inner_style);
+
+ unsigned start_count = GetStyleEngine().StyleForElementCount();
+ GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *container, LogicalSize(), LogicalAxes(kLogicalAxisBoth));
+
+ // Input elements mark their InnerEditorElement() style-dirty when they are
+ // recalculated. That means the UpdateStyleAndLayoutTreeForContainer() call
+ // above will involve marking ChildNeedsStyleRecalc all the way up to the
+ // documentElement. Check that we don't leave anything dirty.
+ EXPECT_FALSE(GetDocument().NeedsLayoutTreeUpdate());
+ EXPECT_FALSE(GetDocument().documentElement()->ChildNeedsStyleRecalc());
+
+ // The input element is recalculated. The inner editor element isn't counted
+ // because we don't do normal style resolution to create the ComputedStyle for
+ // it, but check that we have a new ComputedStyle object for it.
+ EXPECT_EQ(1u, GetStyleEngine().StyleForElementCount() - start_count);
+
+ const ComputedStyle* new_inner_style = inner_editor->GetComputedStyle();
+ EXPECT_TRUE(new_inner_style);
+ EXPECT_NE(old_inner_style, new_inner_style);
+}
+
+TEST_F(StyleEngineTest, VideoControlsReject) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <video controls></video>
+ <div id="target"></div>
+ )HTML");
+ UpdateAllLifecyclePhases();
+
+ StyleEngine& engine = GetStyleEngine();
+ // If the Stats() were already enabled, we would not start with 0 counts.
+ EXPECT_FALSE(engine.Stats());
+ engine.SetStatsEnabled(true);
+
+ StyleResolverStats* stats = engine.Stats();
+ ASSERT_TRUE(stats);
+ EXPECT_EQ(0u, stats->rules_fast_rejected);
+ EXPECT_EQ(0u, stats->rules_rejected);
+
+ Element* target = GetDocument().getElementById("target");
+ ASSERT_TRUE(target);
+ target->SetInlineStyleProperty(CSSPropertyID::kColor, "green");
+
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ GetStyleEngine().RecalcStyle();
+
+ // There should be no UA rules for a div to reject
+ EXPECT_EQ(0u, stats->rules_fast_rejected);
+ EXPECT_EQ(0u, stats->rules_rejected);
+}
+
+TEST_F(StyleEngineTest, FastRejectForHostChild) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ .notfound span {
+ color: pink;
+ }
+ </style>
+ <div id="host">
+ <span id="slotted"></span>
+ </div>
+ )HTML");
+
+ Element* host = GetDocument().getElementById("host");
+ ASSERT_TRUE(host);
+ ShadowRoot& shadow_root =
+ host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML(R"HTML(
+ <slot></slot>
+ )HTML");
+ UpdateAllLifecyclePhases();
+
+ StyleEngine& engine = GetStyleEngine();
+ // If the Stats() were already enabled, we would not start with 0 counts.
+ EXPECT_FALSE(engine.Stats());
+ engine.SetStatsEnabled(true);
+
+ StyleResolverStats* stats = engine.Stats();
+ ASSERT_TRUE(stats);
+ EXPECT_EQ(0u, stats->rules_fast_rejected);
+
+ Element* span = GetDocument().getElementById("slotted");
+ ASSERT_TRUE(span);
+ span->SetInlineStyleProperty(CSSPropertyID::kColor, "green");
+
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ GetStyleEngine().RecalcStyle();
+
+ // Should fast reject ".notfound span"
+ EXPECT_EQ(1u, stats->rules_fast_rejected);
+}
+
+TEST_F(StyleEngineTest, RejectSlottedSelector) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="host">
+ <span id="slotted"></span>
+ </div>
+ )HTML");
+
+ Element* host = GetDocument().getElementById("host");
+ ASSERT_TRUE(host);
+ ShadowRoot& shadow_root =
+ host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML(R"HTML(
+ <style>
+ .notfound ::slotted(span) {
+ color: pink;
+ }
+ </style>
+ <slot></slot>
+ )HTML");
+ UpdateAllLifecyclePhases();
+
+ StyleEngine& engine = GetStyleEngine();
+ // If the Stats() were already enabled, we would not start with 0 counts.
+ EXPECT_FALSE(engine.Stats());
+ engine.SetStatsEnabled(true);
+
+ StyleResolverStats* stats = engine.Stats();
+ ASSERT_TRUE(stats);
+ EXPECT_EQ(0u, stats->rules_fast_rejected);
+
+ Element* span = GetDocument().getElementById("slotted");
+ ASSERT_TRUE(span);
+ span->SetInlineStyleProperty(CSSPropertyID::kColor, "green");
+
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
+ GetStyleEngine().RecalcStyle();
+
+ // Should fast reject ".notfound ::slotted(span)"
+ EXPECT_EQ(1u, stats->rules_fast_rejected);
+}
+
+TEST_F(StyleEngineTest, AudioUAStyleNameSpace) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <audio id="html-audio"></audio>
+ )HTML");
+ Element* html_audio = GetDocument().getElementById("html-audio");
+ Element* audio = GetDocument().createElementNS("http://dummyns", "audio",
+ ASSERT_NO_EXCEPTION);
+ GetDocument().body()->appendChild(audio);
+ UpdateAllLifecyclePhases();
+
+ // display:none UA rule for audio element should not apply outside html.
+ EXPECT_TRUE(audio->GetComputedStyle());
+ EXPECT_FALSE(html_audio->GetComputedStyle());
+
+ FloatSize page_size(400, 400);
+ GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
+
+ // Also for printing.
+ EXPECT_TRUE(audio->GetComputedStyle());
+ EXPECT_FALSE(html_audio->GetComputedStyle());
+}
+
+TEST_F(StyleEngineTest, TargetTextUseCount) {
+ ClearUseCounter(WebFeature::kCSSSelectorTargetText);
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ #nevermatch::target-text { background-color: pink }
+ </style>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(IsUseCounted(WebFeature::kCSSSelectorTargetText));
+ ClearUseCounter(WebFeature::kCSSSelectorTargetText);
+
+ // Count ::target-text if we would have matched if the page was loaded with a
+ // text fragment url.
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ div::target-text { background-color: pink }
+ </style>
+ <div></div>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(IsUseCounted(WebFeature::kCSSSelectorTargetText));
+ ClearUseCounter(WebFeature::kCSSSelectorTargetText);
+}
+
+// https://crbug.com/1172679
+TEST_F(StyleEngineTest, CounterContentNameCase) {
+ // Reproducible only with legacy counter styles
+ ScopedCSSAtRuleCounterStyleForTest disabled_scope(false);
+
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ body { counter-reset: a; }
+ #target::before {
+ counter-increment: a;
+ content: counter(a, Hiragana);
+ }
+ </style>
+ <p id="target"></p>
+ )HTML");
+
+ // Shouldn't crash
+ UpdateAllLifecyclePhases();
+
+ PseudoElement* before =
+ GetDocument().getElementById("target")->GetPseudoElement(kPseudoIdBefore);
+ LayoutCounter* counter =
+ To<LayoutCounter>(before->GetLayoutObject()->SlowFirstChild());
+
+ // Hiragana "A"
+ EXPECT_EQ(String(u"\u3042"), counter->GetText());
+}
+
+// https://crbug.com/1182969
+TEST_F(StyleEngineTest, CountersShouldNotCauseListMarkerUpdates) {
+ // Reproducible only when @counter-style rules are disabled
+ ScopedCSSAtRuleCounterStyleForTest disabled_scope(false);
+
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ body { counter-reset: a; }
+ p::before {
+ counter-increment: a;
+ content: counter(a);
+ }
+ </style>
+ <ol><li id="target"></li></ol>
+ )HTML");
+
+ // Shouldn't crash
+ UpdateAllLifecyclePhases();
+
+ LayoutObject* list_item =
+ GetDocument().getElementById("target")->GetLayoutObject();
+ LayoutObject* marker = ListMarker::MarkerFromListItem(list_item);
+
+ GetDocument().body()->appendChild(GetDocument().CreateElementForBinding("p"));
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(marker->NeedsLayout());
+}
+
+TEST_F(StyleEngineTest, NonDirtyStyleRecalcRoot) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="host">
+ <span id="slotted"></span>
+ </div>
+ )HTML");
+
+ auto* host = GetDocument().getElementById("host");
+ auto* slotted = GetDocument().getElementById("slotted");
+
+ ShadowRoot& shadow_root =
+ host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML("<slot></slot>");
+ UpdateAllLifecyclePhases();
+
+ slotted->remove();
+ GetDocument().body()->appendChild(slotted);
+ host->remove();
+ auto* recalc_root = GetStyleRecalcRoot();
+ ASSERT_TRUE(recalc_root);
+ EXPECT_TRUE(recalc_root->NeedsStyleRecalc());
+}
+
+TEST_F(StyleEngineTest, AtCounterStyleUseCounter) {
+ ScopedCSSAtRuleCounterStyleForTest scope(true);
+
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(IsUseCounted(WebFeature::kCSSAtRuleCounterStyle));
+
+ GetDocument().body()->setInnerHTML("<style>@counter-style foo {}</style>");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(IsUseCounted(WebFeature::kCSSAtRuleCounterStyle));
+}
+
+TEST_F(StyleEngineTest, CounterStyleDisabledInShadowDOM) {
+ ScopedCSSAtRuleCounterStyleForTest counter_style_enabled(true);
+ ScopedCSSAtRuleCounterStyleInShadowDOMForTest
+ counter_style_in_shadow_dom_disabled(false);
+
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo { symbols: A; }
+ </style>
+ <ol id="foo" style="list-style-type: foo"><li></li></ol>
+ <div id="host"></div>
+ )HTML");
+
+ Element* host = GetDocument().getElementById("host");
+ ShadowRoot& shadow_root =
+ host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML(R"HTML(
+ <style>
+ @counter-style bar { symbols: B; }
+ </style>
+ <ol id="foo" style="list-style-type: foo"><li></li></ol>
+ <ol id="bar" style="list-style-type: bar"><li></li></ol>
+ )HTML");
+
+ UpdateAllLifecyclePhases();
+
+ // Only @counter-style rules defined in the document scope are effective,
+ // matching the spec status as of Feb 2021.
+
+ LayoutObject* document_foo =
+ GetDocument().getElementById("foo")->firstChild()->GetLayoutObject();
+ EXPECT_EQ("A. ", GetListMarkerText(document_foo));
+
+ LayoutObject* shadow_foo =
+ shadow_root.getElementById("foo")->firstChild()->GetLayoutObject();
+ EXPECT_EQ("A. ", GetListMarkerText(shadow_foo));
+
+ LayoutObject* shadow_bar =
+ shadow_root.getElementById("bar")->firstChild()->GetLayoutObject();
+ EXPECT_EQ("1. ", GetListMarkerText(shadow_bar));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_environment_variables.cc b/chromium/third_party/blink/renderer/core/css/style_environment_variables.cc
index 0be4a09d55b..75d7c553fc2 100644
--- a/chromium/third_party/blink/renderer/core/css/style_environment_variables.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_environment_variables.cc
@@ -115,6 +115,18 @@ const AtomicString StyleEnvironmentVariables::GetVariableName(
case UADefinedVariable::kFoldHeight:
DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
return "fold-height";
+ case UADefinedVariable::kTitlebarAreaInsetTop:
+ DCHECK(RuntimeEnabledFeatures::WebAppWindowControlsOverlayEnabled());
+ return "titlebar-area-inset-top";
+ case UADefinedVariable::kTitlebarAreaInsetLeft:
+ DCHECK(RuntimeEnabledFeatures::WebAppWindowControlsOverlayEnabled());
+ return "titlebar-area-inset-left";
+ case UADefinedVariable::kTitlebarAreaInsetRight:
+ DCHECK(RuntimeEnabledFeatures::WebAppWindowControlsOverlayEnabled());
+ return "titlebar-area-inset-right";
+ case UADefinedVariable::kTitlebarAreaInsetBottom:
+ DCHECK(RuntimeEnabledFeatures::WebAppWindowControlsOverlayEnabled());
+ return "titlebar-area-inset-bottom";
default:
break;
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_environment_variables.h b/chromium/third_party/blink/renderer/core/css/style_environment_variables.h
index 115fa2e6aa7..9447ddb4ed0 100644
--- a/chromium/third_party/blink/renderer/core/css/style_environment_variables.h
+++ b/chromium/third_party/blink/renderer/core/css/style_environment_variables.h
@@ -49,6 +49,16 @@ enum class UADefinedVariable {
kFoldLeft,
kFoldWidth,
kFoldHeight,
+
+ // The title bar area inset are four environment variables that define a
+ // rectangle by its top, right, bottom, and left insets from the edge of the
+ // viewport, intended for desktop pwas with window controls overlay.
+ // Explainer:
+ // https://github.com/WICG/window-controls-overlay/blob/master/explainer.md
+ kTitlebarAreaInsetTop,
+ kTitlebarAreaInsetLeft,
+ kTitlebarAreaInsetBottom,
+ kTitlebarAreaInsetRight
};
// StyleEnvironmentVariables stores user agent and user defined CSS environment
diff --git a/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc b/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
index 283e3cac4b7..4d6d6a3c9b8 100644
--- a/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_environment_variables_test.cc
@@ -75,7 +75,8 @@ class StyleEnvironmentVariablesTest : public PageTestBase {
void SimulateNavigation() {
const KURL& url = KURL(NullURL(), "https://www.example.com");
GetDocument().GetFrame()->Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
diff --git a/chromium/third_party/blink/renderer/core/css/style_invalidation_root.cc b/chromium/third_party/blink/renderer/core/css/style_invalidation_root.cc
index c5a8b386671..c72b0b37720 100644
--- a/chromium/third_party/blink/renderer/core/css/style_invalidation_root.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_invalidation_root.cc
@@ -23,13 +23,19 @@ Element* StyleInvalidationRoot::RootElement() const {
ContainerNode* StyleInvalidationRoot::Parent(const Node& node) const {
return node.ParentOrShadowHostNode();
}
+
+bool StyleInvalidationRoot::IsChildDirty(const Node& node) const {
+ return node.ChildNeedsStyleInvalidation();
+}
#endif // DCHECK_IS_ON()
bool StyleInvalidationRoot::IsDirty(const Node& node) const {
return node.NeedsStyleInvalidation();
}
-void StyleInvalidationRoot::RootRemoved(ContainerNode& parent) {
+void StyleInvalidationRoot::SubtreeModified(ContainerNode& parent) {
+ if (!GetRootNode() || GetRootNode()->isConnected())
+ return;
for (Node* ancestor = &parent; ancestor;
ancestor = ancestor->ParentOrShadowHostNode()) {
DCHECK(ancestor->ChildNeedsStyleInvalidation());
diff --git a/chromium/third_party/blink/renderer/core/css/style_invalidation_root.h b/chromium/third_party/blink/renderer/core/css/style_invalidation_root.h
index 19448df5e13..4725f225407 100644
--- a/chromium/third_party/blink/renderer/core/css/style_invalidation_root.h
+++ b/chromium/third_party/blink/renderer/core/css/style_invalidation_root.h
@@ -14,13 +14,14 @@ class CORE_EXPORT StyleInvalidationRoot : public StyleTraversalRoot {
public:
Element* RootElement() const;
+ void SubtreeModified(ContainerNode& parent) final;
private:
#if DCHECK_IS_ON()
ContainerNode* Parent(const Node& node) const final;
+ bool IsChildDirty(const Node& node) const final;
#endif // DCHECK_IS_ON()
bool IsDirty(const Node& node) const final;
- void RootRemoved(ContainerNode& parent) final;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc b/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
index 78bceb89481..d536af0a403 100644
--- a/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/css_value_pool.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
+#include "third_party/blink/renderer/core/css/properties/longhand.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -65,7 +66,7 @@ StylePropertySerializer::CSSPropertyValueSetForSerializer::
continue;
need_to_expand_all_ = true;
}
- if (!isCSSPropertyIDWithName(property.Id()))
+ if (!IsCSSPropertyIDWithName(property.Id()))
continue;
longhand_property_used_.set(GetCSSPropertyIDIndex(property.Id()));
}
@@ -93,7 +94,7 @@ StylePropertySerializer::CSSPropertyValueSetForSerializer::PropertyAt(
CSSPropertyID property_id =
static_cast<CSSPropertyID>(index + kIntFirstCSSProperty);
- DCHECK(isCSSPropertyIDWithName(property_id));
+ DCHECK(IsCSSPropertyIDWithName(property_id));
if (longhand_property_used_.test(index)) {
int real_index = property_set_->FindPropertyIndex(property_id);
DCHECK_NE(real_index, -1);
@@ -120,16 +121,16 @@ bool StylePropertySerializer::CSSPropertyValueSetForSerializer::
property_set_->PropertyAt(index);
if (property.Id() == CSSPropertyID::kAll || !property.IsAffectedByAll())
return true;
- if (!isCSSPropertyIDWithName(property.Id()))
+ if (!IsCSSPropertyIDWithName(property.Id()))
return false;
return longhand_property_used_.test(GetCSSPropertyIDIndex(property.Id()));
}
CSSPropertyID property_id =
static_cast<CSSPropertyID>(index + kIntFirstCSSProperty);
- DCHECK(isCSSPropertyIDWithName(property_id));
+ DCHECK(IsCSSPropertyIDWithName(property_id));
const CSSProperty& property_class =
- CSSProperty::Get(resolveCSSPropertyID(property_id));
+ CSSProperty::Get(ResolveCSSPropertyID(property_id));
// Since "all" is expanded, we don't need to process "all".
// We should not process expanded shorthands (e.g. font, background,
@@ -213,8 +214,8 @@ String StylePropertySerializer::GetPropertyText(const CSSProperty& property,
String StylePropertySerializer::AsText() const {
StringBuilder result;
- std::bitset<numCSSProperties> longhand_serialized;
- std::bitset<numCSSProperties> shorthand_appeared;
+ std::bitset<kNumCSSProperties> longhand_serialized;
+ std::bitset<kNumCSSProperties> shorthand_appeared;
unsigned size = property_set_.PropertyCount();
unsigned num_decls = 0;
@@ -330,7 +331,6 @@ static bool AllowInitialInShorthand(CSSPropertyID property_id) {
case CSSPropertyID::kOutline:
case CSSPropertyID::kColumnRule:
case CSSPropertyID::kColumns:
- case CSSPropertyID::kFlex:
case CSSPropertyID::kFlexFlow:
case CSSPropertyID::kGridColumn:
case CSSPropertyID::kGridRow:
@@ -1108,10 +1108,29 @@ String StylePropertySerializer::BorderPropertyValue(
const StylePropertyShorthand& width,
const StylePropertyShorthand& style,
const StylePropertyShorthand& color) const {
- const StylePropertyShorthand properties[3] = {width, style, color};
+ const CSSProperty* border_image_properties[] = {
+ &GetCSSPropertyBorderImageSource(), &GetCSSPropertyBorderImageSlice(),
+ &GetCSSPropertyBorderImageWidth(), &GetCSSPropertyBorderImageOutset(),
+ &GetCSSPropertyBorderImageRepeat()};
+
+ // If any of the border-image longhands differ from their initial
+ // specified values, we should not serialize to a border shorthand
+ // declaration.
+ for (const auto* border_image_property : border_image_properties) {
+ const CSSValue* value =
+ property_set_.GetPropertyCSSValue(*border_image_property);
+ const CSSValue* initial_specified_value =
+ To<Longhand>(*border_image_property).InitialValue();
+ if (value && !value->IsInitialValue() &&
+ *value != *initial_specified_value) {
+ return String();
+ }
+ }
+
+ const StylePropertyShorthand shorthand_properties[3] = {width, style, color};
StringBuilder result;
- for (size_t i = 0; i < base::size(properties); ++i) {
- String value = GetCommonValue(properties[i]);
+ for (const auto& shorthand_property : shorthand_properties) {
+ const String value = GetCommonValue(shorthand_property);
if (value.IsNull())
return String();
if (value == "initial")
diff --git a/chromium/third_party/blink/renderer/core/css/style_property_serializer.h b/chromium/third_party/blink/renderer/core/css/style_property_serializer.h
index 355c291495a..00edf39e27f 100644
--- a/chromium/third_party/blink/renderer/core/css/style_property_serializer.h
+++ b/chromium/third_party/blink/renderer/core/css/style_property_serializer.h
@@ -135,7 +135,7 @@ class StylePropertySerializer {
Member<const CSSPropertyValueSet> property_set_;
int all_index_;
- std::bitset<numCSSProperties> longhand_property_used_;
+ std::bitset<kNumCSSProperties> longhand_property_used_;
bool need_to_expand_all_;
};
diff --git a/chromium/third_party/blink/renderer/core/css/style_recalc.cc b/chromium/third_party/blink/renderer/core/css/style_recalc.cc
index 757a6a77642..c92bb6f2d5d 100644
--- a/chromium/third_party/blink/renderer/core/css/style_recalc.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_recalc.cc
@@ -9,16 +9,19 @@
namespace blink {
-bool StyleRecalcChange::TraverseChildren(const Node& node) const {
- return RecalcChildren() || node.ChildNeedsStyleRecalc();
+bool StyleRecalcChange::TraverseChildren(const Element& element) const {
+ return RecalcChildren() || RecalcContainerQueryDependent() ||
+ element.ChildNeedsStyleRecalc();
}
-bool StyleRecalcChange::TraversePseudoElements(const Node& node) const {
- return UpdatePseudoElements() || node.ChildNeedsStyleRecalc();
+bool StyleRecalcChange::TraversePseudoElements(const Element& element) const {
+ return UpdatePseudoElements() || RecalcContainerQueryDependent() ||
+ element.ChildNeedsStyleRecalc();
}
bool StyleRecalcChange::TraverseChild(const Node& node) const {
- return ShouldRecalcStyleFor(node) || node.ChildNeedsStyleRecalc();
+ return ShouldRecalcStyleFor(node) || node.ChildNeedsStyleRecalc() ||
+ RecalcContainerQueryDependent();
}
bool StyleRecalcChange::ShouldRecalcStyleFor(const Node& node) const {
@@ -28,16 +31,57 @@ bool StyleRecalcChange::ShouldRecalcStyleFor(const Node& node) const {
return true;
if (node.GetForceReattachLayoutTree())
return true;
- if (propagate_ != kClearEnsured)
+ // Early exit before getting the computed style.
+ if (propagate_ != kClearEnsured && !RecalcContainerQueryDependent())
return false;
- if (const ComputedStyle* old_style = node.GetComputedStyle())
- return old_style->IsEnsuredInDisplayNone();
- return false;
+ if (const ComputedStyle* old_style = node.GetComputedStyle()) {
+ return (propagate_ == kClearEnsured &&
+ old_style->IsEnsuredInDisplayNone()) ||
+ (RecalcContainerQueryDependent() &&
+ old_style->DependsOnContainerQueries());
+ }
+ // Container queries may affect display:none elements, and we since we store
+ // that dependency on ComputedStyle we need to recalc style for display:none
+ // subtree roots.
+ return RecalcContainerQueryDependent();
}
bool StyleRecalcChange::ShouldUpdatePseudoElement(
const PseudoElement& pseudo_element) const {
- return UpdatePseudoElements() || pseudo_element.NeedsStyleRecalc();
+ if (UpdatePseudoElements())
+ return true;
+ if (pseudo_element.NeedsStyleRecalc())
+ return true;
+ return RecalcContainerQueryDependent() &&
+ pseudo_element.ComputedStyleRef().DependsOnContainerQueries();
+}
+
+bool StyleRecalcChange::RecalcContainerQueryDependentChildren(
+ const Element& element) const {
+ // We are at the container root for a container query recalc.
+ if (propagate_ == kRecalcContainerQueryDependent)
+ return true;
+ if (!RecalcContainerQueryDependent())
+ return false;
+ // Don't traverse into children if we hit a descendant container while
+ // recalculating container queries. If the queries for this container also
+ // changes, we will enter another container query recalc for this subtree from
+ // layout.
+ if (LayoutObject* layout_object = element.GetLayoutObject())
+ return !layout_object->IsContainerForContainerQueries();
+ return true;
+}
+
+StyleRecalcContext StyleRecalcContext::FromAncestors(Element& element) {
+ Element* ancestor = &element;
+ // TODO(crbug.com/1145970): Avoid this work if we're not inside a container.
+ while ((ancestor = DynamicTo<Element>(
+ LayoutTreeBuilderTraversal::Parent(*ancestor)))) {
+ ContainerQueryEvaluator* evaluator = ancestor->GetContainerQueryEvaluator();
+ if (evaluator)
+ return StyleRecalcContext{evaluator};
+ }
+ return StyleRecalcContext();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_recalc.h b/chromium/third_party/blink/renderer/core/css/style_recalc.h
index 6fb3c216a26..6c958c9c829 100644
--- a/chromium/third_party/blink/renderer/core/css/style_recalc.h
+++ b/chromium/third_party/blink/renderer/core/css/style_recalc.h
@@ -5,8 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_RECALC_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_RECALC_H_
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
namespace blink {
+class ContainerQueryEvaluator;
+class Element;
class Node;
class PseudoElement;
@@ -21,6 +25,11 @@ class StyleRecalcChange {
// Need to traverse children in display:none or non-slotted/distributed
// children of shadow hosts to clear ensured computed styles.
kClearEnsured,
+ // Need to traverse descendants to invalidate style for container queries.
+ // This value is passed in for the container itself, it will translate into
+ // recalc_container_query_dependent_=true for descendants. We should not
+ // recalc style for the container itself.
+ kRecalcContainerQueryDependent,
// Need to update existence and style for pseudo elements.
kUpdatePseudoElements,
// Need to recalculate style for children for inheritance. All changed
@@ -37,24 +46,25 @@ class StyleRecalcChange {
StyleRecalcChange(const StyleRecalcChange&) = default;
StyleRecalcChange(Propagate propagate) : propagate_(propagate) {}
- StyleRecalcChange ForChildren() const {
- return {RecalcDescendants() ? kRecalcDescendants : kNo, reattach_};
+ StyleRecalcChange ForChildren(const Element& element) const {
+ return {RecalcDescendants() ? kRecalcDescendants : kNo, reattach_,
+ RecalcContainerQueryDependentChildren(element)};
}
StyleRecalcChange ForPseudoElement() const {
if (propagate_ == kUpdatePseudoElements)
- return {kRecalcChildren, reattach_};
+ return {kRecalcChildren, reattach_, recalc_container_query_dependent_};
return *this;
}
StyleRecalcChange EnsureAtLeast(Propagate propagate) const {
if (propagate > propagate_)
- return {propagate, reattach_};
- return {propagate_, reattach_};
+ return {propagate, reattach_, recalc_container_query_dependent_};
+ return {propagate_, reattach_, recalc_container_query_dependent_};
}
StyleRecalcChange ForceRecalcDescendants() const {
- return {kRecalcDescendants, reattach_};
+ return {kRecalcDescendants, reattach_, recalc_container_query_dependent_};
}
StyleRecalcChange ForceReattachLayoutTree() const {
- return {propagate_, true};
+ return {propagate_, true, recalc_container_query_dependent_};
}
bool ReattachLayoutTree() const { return reattach_; }
@@ -62,20 +72,51 @@ class StyleRecalcChange {
bool RecalcDescendants() const { return propagate_ == kRecalcDescendants; }
bool UpdatePseudoElements() const { return propagate_ != kNo; }
bool IndependentInherit() const { return propagate_ == kIndependentInherit; }
- bool TraverseChildren(const Node&) const;
+ bool TraverseChildren(const Element&) const;
bool TraverseChild(const Node&) const;
- bool TraversePseudoElements(const Node&) const;
+ bool TraversePseudoElements(const Element&) const;
bool ShouldRecalcStyleFor(const Node&) const;
bool ShouldUpdatePseudoElement(const PseudoElement&) const;
private:
- StyleRecalcChange(Propagate propagate, bool reattach)
- : propagate_(propagate), reattach_(reattach) {}
+ StyleRecalcChange(Propagate propagate,
+ bool reattach,
+ bool recalc_container_query_dependent)
+ : propagate_(propagate),
+ reattach_(reattach),
+ recalc_container_query_dependent_(recalc_container_query_dependent) {}
+
+ bool RecalcContainerQueryDependent() const {
+ return recalc_container_query_dependent_;
+ }
+ bool RecalcContainerQueryDependentChildren(const Element&) const;
// To what extent do we need to update style for children.
Propagate propagate_ = kNo;
// Need to reattach layout tree if true.
bool reattach_ = false;
+ // Force recalc of elements depending on container queries.
+ bool recalc_container_query_dependent_ = false;
+};
+
+// StyleRecalcContext is an object that is passed on the stack during
+// the style recalc process.
+//
+// Its purpose is to hold context related to the style recalc process as
+// a whole, i.e. information not directly associated to the specific element
+// style is being calculated for.
+class StyleRecalcContext {
+ STACK_ALLOCATED();
+
+ public:
+ // Using the ancestor chain, build a StyleRecalcContext suitable for
+ // resolving the style of the given Element.
+ static StyleRecalcContext FromAncestors(Element&);
+
+ // If style is being calculated for an element inside a container,
+ // this ContainerQueryEvaluator may be used to evaluate @container
+ // rules against that container.
+ ContainerQueryEvaluator* cq_evaluator = nullptr;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_recalc_root.cc b/chromium/third_party/blink/renderer/core/css/style_recalc_root.cc
index 7d741d334d0..afb11900bb1 100644
--- a/chromium/third_party/blink/renderer/core/css/style_recalc_root.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_recalc_root.cc
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
#include "third_party/blink/renderer/core/dom/slot_assignment.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
@@ -31,6 +30,10 @@ Element& StyleRecalcRoot::RootElement() const {
ContainerNode* StyleRecalcRoot::Parent(const Node& node) const {
return node.GetStyleRecalcParent();
}
+
+bool StyleRecalcRoot::IsChildDirty(const Node& node) const {
+ return node.ChildNeedsStyleRecalc();
+}
#endif // DCHECK_IS_ON()
bool StyleRecalcRoot::IsDirty(const Node& node) const {
@@ -49,18 +52,6 @@ base::Optional<Member<Element>> FirstFlatTreeAncestorForChildDirty(
ShadowRoot* root = parent.GetShadowRoot();
if (!root)
return To<Element>(&parent);
- if (root->IsV0()) {
- // The child has already been removed, so we cannot look up its insertion
- // point directly. Find the insertion point which was part of the ancestor
- // chain before the removal by checking the child-dirty bits. Since the
- // recalc root was removed, there is at most one such child-dirty insertion
- // point.
- for (const auto& insertion_point : root->V0().DescendantInsertionPoints()) {
- if (insertion_point->ChildNeedsStyleRecalc())
- return insertion_point;
- }
- return base::nullopt;
- }
if (!root->HasSlotAssignment())
return base::nullopt;
// The child has already been removed, so we cannot look up its slot
@@ -76,9 +67,25 @@ base::Optional<Member<Element>> FirstFlatTreeAncestorForChildDirty(
return base::nullopt;
}
+bool IsFlatTreeConnected(const Node& root) {
+ if (!root.isConnected())
+ return false;
+ // If the recalc root is removed from the flat tree because its assigned slot
+ // is removed from the flat tree, the recalc flags will be cleared in
+ // DetachLayoutTree() with performing_reattach=false. We use that to decide if
+ // the root node is no longer part of the flat tree.
+ return root.IsDirtyForStyleRecalc() || root.ChildNeedsStyleRecalc();
+}
+
} // namespace
-void StyleRecalcRoot::RootRemoved(ContainerNode& parent) {
+void StyleRecalcRoot::SubtreeModified(ContainerNode& parent) {
+ if (!GetRootNode())
+ return;
+ if (GetRootNode()->IsDocumentNode())
+ return;
+ if (IsFlatTreeConnected(*GetRootNode()))
+ return;
// We are notified with the light tree parent of the node(s) which were
// removed from the DOM. If 'parent' is a shadow host, there are elements in
// its shadow tree which are marked child-dirty which needs to be cleared in
@@ -107,18 +114,8 @@ void StyleRecalcRoot::RemovedFromFlatTree(const Node& node) {
return;
if (GetRootNode()->IsDocumentNode())
return;
- // If the recalc root is the removed node, or if it's a descendant of the root
- // node, the recalc flags will be cleared in DetachLayoutTree() since
- // performing_reattach=false. If that's the case, call RootRemoved() below to
- // make sure we don't have a recalc root outside the flat tree, which is not
- // allowed with FlatTreeStyleRecalc enabled.
- if (GetRootNode()->NeedsStyleRecalc() ||
- GetRootNode()->GetForceReattachLayoutTree() ||
- GetRootNode()->ChildNeedsStyleRecalc()) {
- return;
- }
DCHECK(node.parentElement());
- RootRemoved(*node.parentElement());
+ SubtreeModified(*node.parentElement());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_recalc_root.h b/chromium/third_party/blink/renderer/core/css/style_recalc_root.h
index 86be5eb736d..f88efd5d234 100644
--- a/chromium/third_party/blink/renderer/core/css/style_recalc_root.h
+++ b/chromium/third_party/blink/renderer/core/css/style_recalc_root.h
@@ -15,13 +15,14 @@ class CORE_EXPORT StyleRecalcRoot : public StyleTraversalRoot {
public:
Element& RootElement() const;
void RemovedFromFlatTree(const Node& node);
+ void SubtreeModified(ContainerNode& parent) final;
private:
#if DCHECK_IS_ON()
ContainerNode* Parent(const Node& node) const final;
+ bool IsChildDirty(const Node& node) const final;
#endif // DCHECK_IS_ON()
bool IsDirty(const Node& node) const final;
- void RootRemoved(ContainerNode& parent) final;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule.cc b/chromium/third_party/blink/renderer/core/css/style_rule.cc
index 3956440b09b..536701a8bf1 100644
--- a/chromium/third_party/blink/renderer/core/css/style_rule.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_rule.cc
@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/core/css/style_rule.h"
+#include "third_party/blink/renderer/core/css/css_container_rule.h"
#include "third_party/blink/renderer/core/css/css_counter_style_rule.h"
#include "third_party/blink/renderer/core/css/css_font_face_rule.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
@@ -33,7 +34,7 @@
#include "third_party/blink/renderer/core/css/css_scroll_timeline_rule.h"
#include "third_party/blink/renderer/core/css/css_style_rule.h"
#include "third_party/blink/renderer/core/css/css_supports_rule.h"
-#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
#include "third_party/blink/renderer/core/css/style_rule_import.h"
#include "third_party/blink/renderer/core/css/style_rule_keyframe.h"
#include "third_party/blink/renderer/core/css/style_rule_namespace.h"
@@ -97,6 +98,9 @@ void StyleRuleBase::Trace(Visitor* visitor) const {
case kViewport:
To<StyleRuleViewport>(this)->TraceAfterDispatch(visitor);
return;
+ case kContainer:
+ To<StyleRuleContainer>(this)->TraceAfterDispatch(visitor);
+ return;
case kCounterStyle:
To<StyleRuleCounterStyle>(this)->TraceAfterDispatch(visitor);
return;
@@ -145,6 +149,9 @@ void StyleRuleBase::FinalizeGarbageCollectedObject() {
case kViewport:
To<StyleRuleViewport>(this)->~StyleRuleViewport();
return;
+ case kContainer:
+ To<StyleRuleContainer>(this)->~StyleRuleContainer();
+ return;
case kCounterStyle:
To<StyleRuleCounterStyle>(this)->~StyleRuleCounterStyle();
return;
@@ -182,6 +189,8 @@ StyleRuleBase* StyleRuleBase::Copy() const {
case kKeyframe:
NOTREACHED();
return nullptr;
+ case kContainer:
+ return To<StyleRuleContainer>(this)->Copy();
case kCounterStyle:
return To<StyleRuleCounterStyle>(this)->Copy();
}
@@ -234,6 +243,10 @@ CSSRule* StyleRuleBase::CreateCSSOMWrapper(CSSStyleSheet* parent_sheet,
rule = MakeGarbageCollected<CSSNamespaceRule>(
To<StyleRuleNamespace>(self), parent_sheet);
break;
+ case kContainer:
+ rule = MakeGarbageCollected<CSSContainerRule>(
+ To<StyleRuleContainer>(self), parent_sheet);
+ break;
case kCounterStyle:
rule = MakeGarbageCollected<CSSCounterStyleRule>(
To<StyleRuleCounterStyle>(self), parent_sheet);
@@ -480,6 +493,24 @@ StyleRuleSupports::StyleRuleSupports(const StyleRuleSupports& supports_rule)
: StyleRuleCondition(supports_rule),
condition_is_supported_(supports_rule.condition_is_supported_) {}
+StyleRuleContainer::StyleRuleContainer(
+ ContainerQuery& container_query,
+ HeapVector<Member<StyleRuleBase>>& adopt_rules)
+ : StyleRuleCondition(kContainer, adopt_rules),
+ container_query_(&container_query) {}
+
+StyleRuleContainer::StyleRuleContainer(const StyleRuleContainer& container_rule)
+ : StyleRuleCondition(container_rule) {
+ DCHECK(container_rule.container_query_);
+ container_query_ =
+ MakeGarbageCollected<ContainerQuery>(*container_rule.container_query_);
+}
+
+void StyleRuleContainer::TraceAfterDispatch(blink::Visitor* visitor) const {
+ visitor->Trace(container_query_);
+ StyleRuleCondition::TraceAfterDispatch(visitor);
+}
+
StyleRuleViewport::StyleRuleViewport(CSSPropertyValueSet* properties)
: StyleRuleBase(kViewport), properties_(properties) {}
@@ -498,41 +529,4 @@ void StyleRuleViewport::TraceAfterDispatch(blink::Visitor* visitor) const {
StyleRuleBase::TraceAfterDispatch(visitor);
}
-StyleRuleCounterStyle::StyleRuleCounterStyle(const AtomicString& name,
- CSSPropertyValueSet* properties)
- : StyleRuleBase(kCounterStyle),
- name_(name),
- system_(properties->GetPropertyCSSValue(CSSPropertyID::kSystem)),
- negative_(properties->GetPropertyCSSValue(CSSPropertyID::kNegative)),
- prefix_(properties->GetPropertyCSSValue(CSSPropertyID::kPrefix)),
- suffix_(properties->GetPropertyCSSValue(CSSPropertyID::kSuffix)),
- range_(properties->GetPropertyCSSValue(CSSPropertyID::kRange)),
- pad_(properties->GetPropertyCSSValue(CSSPropertyID::kPad)),
- fallback_(properties->GetPropertyCSSValue(CSSPropertyID::kFallback)),
- symbols_(properties->GetPropertyCSSValue(CSSPropertyID::kSymbols)),
- additive_symbols_(
- properties->GetPropertyCSSValue(CSSPropertyID::kAdditiveSymbols)),
- speak_as_(properties->GetPropertyCSSValue(CSSPropertyID::kSpeakAs)) {
- DCHECK(properties);
-}
-
-StyleRuleCounterStyle::StyleRuleCounterStyle(const StyleRuleCounterStyle&) =
- default;
-
-StyleRuleCounterStyle::~StyleRuleCounterStyle() = default;
-
-void StyleRuleCounterStyle::TraceAfterDispatch(blink::Visitor* visitor) const {
- visitor->Trace(system_);
- visitor->Trace(negative_);
- visitor->Trace(prefix_);
- visitor->Trace(suffix_);
- visitor->Trace(range_);
- visitor->Trace(pad_);
- visitor->Trace(fallback_);
- visitor->Trace(symbols_);
- visitor->Trace(additive_symbols_);
- visitor->Trace(speak_as_);
- StyleRuleBase::TraceAfterDispatch(visitor);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule.h b/chromium/third_party/blink/renderer/core/css/style_rule.h
index 71c8983d8ad..a3ba768834f 100644
--- a/chromium/third_party/blink/renderer/core/css/style_rule.h
+++ b/chromium/third_party/blink/renderer/core/css/style_rule.h
@@ -24,6 +24,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/container_query.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_selector_list.h"
#include "third_party/blink/renderer/core/css/media_list.h"
@@ -48,6 +49,7 @@ class CORE_EXPORT StyleRuleBase : public GarbageCollected<StyleRuleBase> {
kKeyframes,
kKeyframe,
kNamespace,
+ kContainer,
kCounterStyle,
kScrollTimeline,
kSupports,
@@ -57,6 +59,7 @@ class CORE_EXPORT StyleRuleBase : public GarbageCollected<StyleRuleBase> {
RuleType GetType() const { return static_cast<RuleType>(type_); }
bool IsCharsetRule() const { return GetType() == kCharset; }
+ bool IsContainerRule() const { return GetType() == kContainer; }
bool IsCounterStyleRule() const { return GetType() == kCounterStyle; }
bool IsFontFaceRule() const { return GetType() == kFontFace; }
bool IsKeyframesRule() const { return GetType() == kKeyframes; }
@@ -317,6 +320,24 @@ class StyleRuleSupports : public StyleRuleCondition {
bool condition_is_supported_;
};
+class CORE_EXPORT StyleRuleContainer : public StyleRuleCondition {
+ public:
+ StyleRuleContainer(ContainerQuery&,
+ HeapVector<Member<StyleRuleBase>>& adopt_rules);
+ StyleRuleContainer(const StyleRuleContainer&);
+
+ ContainerQuery& GetContainerQuery() const { return *container_query_; }
+
+ StyleRuleContainer* Copy() const {
+ return MakeGarbageCollected<StyleRuleContainer>(*this);
+ }
+
+ void TraceAfterDispatch(blink::Visitor*) const;
+
+ private:
+ Member<ContainerQuery> container_query_;
+};
+
class StyleRuleViewport : public StyleRuleBase {
public:
explicit StyleRuleViewport(CSSPropertyValueSet*);
@@ -346,63 +367,6 @@ class StyleRuleCharset : public StyleRuleBase {
private:
};
-class CORE_EXPORT StyleRuleCounterStyle : public StyleRuleBase {
- public:
- StyleRuleCounterStyle(const AtomicString&, CSSPropertyValueSet*);
- StyleRuleCounterStyle(const StyleRuleCounterStyle&);
- ~StyleRuleCounterStyle();
-
- AtomicString GetName() const { return name_; }
- const CSSValue* GetSystem() const { return system_; }
- const CSSValue* GetNegative() const { return negative_; }
- const CSSValue* GetPrefix() const { return prefix_; }
- const CSSValue* GetSuffix() const { return suffix_; }
- const CSSValue* GetRange() const { return range_; }
- const CSSValue* GetPad() const { return pad_; }
- const CSSValue* GetFallback() const { return fallback_; }
- const CSSValue* GetSymbols() const { return symbols_; }
- const CSSValue* GetAdditiveSymbols() const { return additive_symbols_; }
- const CSSValue* GetSpeakAs() const { return speak_as_; }
-
- void SetName(const AtomicString& name) { name_ = name; }
- void SetSystem(const CSSValue* system) { system_ = system; }
- void SetNegative(const CSSValue* negative) { negative_ = negative; }
- void SetPrefix(const CSSValue* prefix) { prefix_ = prefix; }
- void SetSuffix(const CSSValue* suffix) { suffix_ = suffix; }
- void SetRange(const CSSValue* range) { range_ = range; }
- void SetPad(const CSSValue* pad) { pad_ = pad; }
- void SetFallback(const CSSValue* fallback) { fallback_ = fallback; }
- void SetSymbols(const CSSValue* symbols) { symbols_ = symbols; }
- void SetAdditiveSymbols(const CSSValue* additive_symbols) {
- additive_symbols_ = additive_symbols;
- }
- void SetSpeakAs(const CSSValue* speak_as) { speak_as_ = speak_as; }
-
- bool HasFailedOrCanceledSubresources() const {
- // TODO(crbug.com/687225): Implement.
- return false;
- }
-
- StyleRuleCounterStyle* Copy() const {
- return MakeGarbageCollected<StyleRuleCounterStyle>(*this);
- }
-
- void TraceAfterDispatch(blink::Visitor*) const;
-
- private:
- AtomicString name_;
- Member<const CSSValue> system_;
- Member<const CSSValue> negative_;
- Member<const CSSValue> prefix_;
- Member<const CSSValue> suffix_;
- Member<const CSSValue> range_;
- Member<const CSSValue> pad_;
- Member<const CSSValue> fallback_;
- Member<const CSSValue> symbols_;
- Member<const CSSValue> additive_symbols_;
- Member<const CSSValue> speak_as_;
-};
-
template <>
struct DowncastTraits<StyleRule> {
static bool AllowFrom(const StyleRuleBase& rule) {
@@ -437,6 +401,14 @@ struct DowncastTraits<StyleRuleScrollTimeline> {
};
template <>
+struct DowncastTraits<StyleRuleGroup> {
+ static bool AllowFrom(const StyleRuleBase& rule) {
+ return rule.IsMediaRule() || rule.IsSupportsRule() ||
+ rule.IsContainerRule();
+ }
+};
+
+template <>
struct DowncastTraits<StyleRuleMedia> {
static bool AllowFrom(const StyleRuleBase& rule) {
return rule.IsMediaRule();
@@ -451,23 +423,23 @@ struct DowncastTraits<StyleRuleSupports> {
};
template <>
-struct DowncastTraits<StyleRuleViewport> {
+struct DowncastTraits<StyleRuleContainer> {
static bool AllowFrom(const StyleRuleBase& rule) {
- return rule.IsViewportRule();
+ return rule.IsContainerRule();
}
};
template <>
-struct DowncastTraits<StyleRuleCharset> {
+struct DowncastTraits<StyleRuleViewport> {
static bool AllowFrom(const StyleRuleBase& rule) {
- return rule.IsCharsetRule();
+ return rule.IsViewportRule();
}
};
template <>
-struct DowncastTraits<StyleRuleCounterStyle> {
+struct DowncastTraits<StyleRuleCharset> {
static bool AllowFrom(const StyleRuleBase& rule) {
- return rule.IsCounterStyleRule();
+ return rule.IsCharsetRule();
}
};
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.cc b/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.cc
new file mode 100644
index 00000000000..a76d94d98dc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.cc
@@ -0,0 +1,144 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
+
+#include "third_party/blink/renderer/core/css/counter_style.h"
+#include "third_party/blink/renderer/core/css/css_counter_style_rule.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
+
+namespace blink {
+
+StyleRuleCounterStyle::StyleRuleCounterStyle(const AtomicString& name,
+ CSSPropertyValueSet* properties)
+ : StyleRuleBase(kCounterStyle),
+ name_(name),
+ system_(properties->GetPropertyCSSValue(CSSPropertyID::kSystem)),
+ negative_(properties->GetPropertyCSSValue(CSSPropertyID::kNegative)),
+ prefix_(properties->GetPropertyCSSValue(CSSPropertyID::kPrefix)),
+ suffix_(properties->GetPropertyCSSValue(CSSPropertyID::kSuffix)),
+ range_(properties->GetPropertyCSSValue(CSSPropertyID::kRange)),
+ pad_(properties->GetPropertyCSSValue(CSSPropertyID::kPad)),
+ fallback_(properties->GetPropertyCSSValue(CSSPropertyID::kFallback)),
+ symbols_(properties->GetPropertyCSSValue(CSSPropertyID::kSymbols)),
+ additive_symbols_(
+ properties->GetPropertyCSSValue(CSSPropertyID::kAdditiveSymbols)),
+ speak_as_(properties->GetPropertyCSSValue(CSSPropertyID::kSpeakAs)) {
+ DCHECK(properties);
+}
+
+StyleRuleCounterStyle::StyleRuleCounterStyle(const StyleRuleCounterStyle&) =
+ default;
+
+StyleRuleCounterStyle::~StyleRuleCounterStyle() = default;
+
+bool StyleRuleCounterStyle::HasValidSymbols() const {
+ CounterStyleSystem system =
+ CounterStyle::ToCounterStyleSystemEnum(GetSystem());
+ const auto* symbols = To<CSSValueList>(GetSymbols());
+ const auto* additive_symbols = To<CSSValueList>(GetAdditiveSymbols());
+ switch (system) {
+ case CounterStyleSystem::kCyclic:
+ case CounterStyleSystem::kFixed:
+ case CounterStyleSystem::kSymbolic:
+ return symbols && symbols->length();
+ case CounterStyleSystem::kAlphabetic:
+ case CounterStyleSystem::kNumeric:
+ return symbols && symbols->length() > 1u;
+ case CounterStyleSystem::kAdditive:
+ return additive_symbols && additive_symbols->length();
+ case CounterStyleSystem::kUnresolvedExtends:
+ return !symbols && !additive_symbols;
+ case CounterStyleSystem::kHebrew:
+ case CounterStyleSystem::kSimpChineseInformal:
+ case CounterStyleSystem::kSimpChineseFormal:
+ case CounterStyleSystem::kTradChineseInformal:
+ case CounterStyleSystem::kTradChineseFormal:
+ case CounterStyleSystem::kKoreanHangulFormal:
+ case CounterStyleSystem::kKoreanHanjaInformal:
+ case CounterStyleSystem::kKoreanHanjaFormal:
+ case CounterStyleSystem::kLowerArmenian:
+ case CounterStyleSystem::kUpperArmenian:
+ case CounterStyleSystem::kEthiopicNumeric:
+ return true;
+ }
+}
+
+Member<const CSSValue>& StyleRuleCounterStyle::GetDescriptorReference(
+ AtRuleDescriptorID descriptor_id) {
+ switch (descriptor_id) {
+ case AtRuleDescriptorID::System:
+ return system_;
+ case AtRuleDescriptorID::Negative:
+ return negative_;
+ case AtRuleDescriptorID::Prefix:
+ return prefix_;
+ case AtRuleDescriptorID::Suffix:
+ return suffix_;
+ case AtRuleDescriptorID::Range:
+ return range_;
+ case AtRuleDescriptorID::Pad:
+ return pad_;
+ case AtRuleDescriptorID::Fallback:
+ return fallback_;
+ case AtRuleDescriptorID::Symbols:
+ return symbols_;
+ case AtRuleDescriptorID::AdditiveSymbols:
+ return additive_symbols_;
+ case AtRuleDescriptorID::SpeakAs:
+ return speak_as_;
+ default:
+ NOTREACHED();
+ return speak_as_;
+ }
+}
+
+bool StyleRuleCounterStyle::NewValueInvalidOrEqual(
+ AtRuleDescriptorID descriptor_id,
+ const CSSValue* new_value) {
+ Member<const CSSValue>& original_value =
+ GetDescriptorReference(descriptor_id);
+ if (DataEquivalent(original_value.Get(), new_value))
+ return false;
+
+ switch (descriptor_id) {
+ case AtRuleDescriptorID::System:
+ // If the attribute being set is system, and the new value would change
+ // the algorithm used, do nothing and abort these steps.
+ return CounterStyle::ToCounterStyleSystemEnum(system_) ==
+ CounterStyle::ToCounterStyleSystemEnum(new_value);
+ case AtRuleDescriptorID::Symbols:
+ case AtRuleDescriptorID::AdditiveSymbols: {
+ // If the returned value would cause the @counter-style rule to become
+ // invalid, do nothing and abort these steps.
+ base::AutoReset<Member<const CSSValue>> auto_reset(&original_value,
+ new_value);
+ return HasValidSymbols();
+ }
+ default:
+ return true;
+ }
+}
+
+void StyleRuleCounterStyle::SetDescriptorValue(AtRuleDescriptorID descriptor_id,
+ const CSSValue* new_value) {
+ GetDescriptorReference(descriptor_id) = new_value;
+ ++version_;
+}
+
+void StyleRuleCounterStyle::TraceAfterDispatch(blink::Visitor* visitor) const {
+ visitor->Trace(system_);
+ visitor->Trace(negative_);
+ visitor->Trace(prefix_);
+ visitor->Trace(suffix_);
+ visitor->Trace(range_);
+ visitor->Trace(pad_);
+ visitor->Trace(fallback_);
+ visitor->Trace(symbols_);
+ visitor->Trace(additive_symbols_);
+ visitor->Trace(speak_as_);
+ StyleRuleBase::TraceAfterDispatch(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.h b/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.h
new file mode 100644
index 00000000000..2772dbc629f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/css/style_rule_counter_style.h
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_RULE_COUNTER_STYLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_RULE_COUNTER_STYLE_H_
+
+#include "third_party/blink/renderer/core/css/parser/at_rule_descriptors.h"
+#include "third_party/blink/renderer/core/css/style_rule.h"
+
+namespace blink {
+
+class CORE_EXPORT StyleRuleCounterStyle : public StyleRuleBase {
+ public:
+ StyleRuleCounterStyle(const AtomicString&, CSSPropertyValueSet*);
+ StyleRuleCounterStyle(const StyleRuleCounterStyle&);
+ ~StyleRuleCounterStyle();
+
+ int GetVersion() const { return version_; }
+
+ // Different 'system' values have different requirements on 'symbols' and
+ // 'additive-symbols'. Returns true if the requirement is met.
+ // https://drafts.csswg.org/css-counter-styles-3/#counter-style-symbols
+ bool HasValidSymbols() const;
+
+ AtomicString GetName() const { return name_; }
+ const CSSValue* GetSystem() const { return system_; }
+ const CSSValue* GetNegative() const { return negative_; }
+ const CSSValue* GetPrefix() const { return prefix_; }
+ const CSSValue* GetSuffix() const { return suffix_; }
+ const CSSValue* GetRange() const { return range_; }
+ const CSSValue* GetPad() const { return pad_; }
+ const CSSValue* GetFallback() const { return fallback_; }
+ const CSSValue* GetSymbols() const { return symbols_; }
+ const CSSValue* GetAdditiveSymbols() const { return additive_symbols_; }
+ const CSSValue* GetSpeakAs() const { return speak_as_; }
+
+ // Returns false if the new value is invalid or equivalent to the old value.
+ bool NewValueInvalidOrEqual(AtRuleDescriptorID, const CSSValue*);
+ void SetDescriptorValue(AtRuleDescriptorID, const CSSValue*);
+
+ void SetName(const AtomicString& name) {
+ name_ = name;
+ ++version_;
+ }
+
+ bool HasFailedOrCanceledSubresources() const {
+ // TODO(crbug.com/1176323): Handle image symbols when we implement it.
+ return false;
+ }
+
+ StyleRuleCounterStyle* Copy() const {
+ return MakeGarbageCollected<StyleRuleCounterStyle>(*this);
+ }
+
+ void TraceAfterDispatch(blink::Visitor*) const;
+
+ private:
+ Member<const CSSValue>& GetDescriptorReference(AtRuleDescriptorID);
+
+ AtomicString name_;
+ Member<const CSSValue> system_;
+ Member<const CSSValue> negative_;
+ Member<const CSSValue> prefix_;
+ Member<const CSSValue> suffix_;
+ Member<const CSSValue> range_;
+ Member<const CSSValue> pad_;
+ Member<const CSSValue> fallback_;
+ Member<const CSSValue> symbols_;
+ Member<const CSSValue> additive_symbols_;
+ Member<const CSSValue> speak_as_;
+
+ // Tracks mutations due to setter functions.
+ int version_ = 0;
+};
+
+template <>
+struct DowncastTraits<StyleRuleCounterStyle> {
+ static bool AllowFrom(const StyleRuleBase& rule) {
+ return rule.IsCounterStyleRule();
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_RULE_COUNTER_STYLE_H_
diff --git a/chromium/third_party/blink/renderer/core/css/style_rule_import.cc b/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
index 60c3dd50eed..31a3e98bfbd 100644
--- a/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_rule_import.cc
@@ -65,7 +65,7 @@ void StyleRuleImport::NotifyFinished(Resource* resource) {
if (style_sheet_)
style_sheet_->ClearOwnerRule();
- CSSStyleSheetResource* cached_style_sheet = ToCSSStyleSheetResource(resource);
+ auto* cached_style_sheet = To<CSSStyleSheetResource>(resource);
Document* document = nullptr;
// Fallback to an insecure context parser if we don't have a parent style
@@ -83,8 +83,9 @@ void StyleRuleImport::NotifyFinished(Resource* resource) {
CSSParserContext* context = MakeGarbageCollected<CSSParserContext>(
parent_context, cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetResponse().IsCorsSameOrigin(),
- cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding(),
- document);
+ Referrer(cached_style_sheet->GetResponse().ResponseUrl(),
+ cached_style_sheet->GetReferrerPolicy()),
+ cached_style_sheet->Encoding(), document);
if (cached_style_sheet->GetResourceRequest().IsAdResource())
context->SetIsAdRelated();
@@ -160,6 +161,10 @@ void StyleRuleImport::RequestStyleSheet() {
params.SetFromOriginDirtyStyleSheet(origin_clean_ != OriginClean::kTrue);
loading_ = true;
DCHECK(!style_sheet_client_->GetResource());
+
+ params.SetRenderBlockingBehavior(root_sheet->GetRenderBlockingBehavior());
+ // TODO(yoav): Set defer status based on the IsRenderBlocking flag.
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1001078
CSSStyleSheetResource::Fetch(params, fetcher, style_sheet_client_);
if (loading_) {
// if the import rule is issued dynamically, the sheet may be
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
index a06c56b4cda..04507e2844f 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.cc
@@ -37,13 +37,13 @@ StyleSheetCollection::StyleSheetCollection() = default;
void StyleSheetCollection::Dispose() {
style_sheets_for_style_sheet_list_.clear();
- active_author_style_sheets_.clear();
+ active_style_sheets_.clear();
}
void StyleSheetCollection::Swap(StyleSheetCollection& other) {
swap(style_sheets_for_style_sheet_list_,
other.style_sheets_for_style_sheet_list_);
- active_author_style_sheets_.swap(other.active_author_style_sheets_);
+ active_style_sheets_.swap(other.active_style_sheets_);
sheet_list_dirty_ = false;
}
@@ -55,7 +55,7 @@ void StyleSheetCollection::SwapSheetsForSheetList(
void StyleSheetCollection::AppendActiveStyleSheet(
const ActiveStyleSheet& active_sheet) {
- active_author_style_sheets_.push_back(active_sheet);
+ active_style_sheets_.push_back(active_sheet);
}
void StyleSheetCollection::AppendSheetForList(StyleSheet* sheet) {
@@ -63,7 +63,7 @@ void StyleSheetCollection::AppendSheetForList(StyleSheet* sheet) {
}
void StyleSheetCollection::Trace(Visitor* visitor) const {
- visitor->Trace(active_author_style_sheets_);
+ visitor->Trace(active_style_sheets_);
visitor->Trace(style_sheets_for_style_sheet_list_);
}
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.h b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.h
index cc5de1a607c..c2f9311a3a8 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_collection.h
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_collection.h
@@ -53,8 +53,8 @@ class CORE_EXPORT StyleSheetCollection
StyleSheetCollection& operator=(const StyleSheetCollection&) = delete;
virtual ~StyleSheetCollection() = default;
- const ActiveStyleSheetVector& ActiveAuthorStyleSheets() const {
- return active_author_style_sheets_;
+ const ActiveStyleSheetVector& ActiveStyleSheets() const {
+ return active_style_sheets_;
}
const HeapVector<Member<StyleSheet>>& StyleSheetsForStyleSheetList() const {
return style_sheets_for_style_sheet_list_;
@@ -75,7 +75,7 @@ class CORE_EXPORT StyleSheetCollection
protected:
HeapVector<Member<StyleSheet>> style_sheets_for_style_sheet_list_;
- ActiveStyleSheetVector active_author_style_sheets_;
+ ActiveStyleSheetVector active_style_sheets_;
bool sheet_list_dirty_ = true;
};
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
index 69355d96568..0d116d833f1 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
+#include "third_party/blink/renderer/core/css/style_rule_counter_style.h"
#include "third_party/blink/renderer/core/css/style_rule_import.h"
#include "third_party/blink/renderer/core/css/style_rule_namespace.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -490,9 +491,10 @@ static bool ChildRulesHaveFailedOrCanceledSubresources(
.HasFailedOrCanceledSubresources())
return true;
break;
+ case StyleRuleBase::kContainer:
case StyleRuleBase::kMedia:
if (ChildRulesHaveFailedOrCanceledSubresources(
- To<StyleRuleMedia>(rule)->ChildRules()))
+ To<StyleRuleGroup>(rule)->ChildRules()))
return true;
break;
case StyleRuleBase::kCharset:
diff --git a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
index 6cf8a20e239..c1b8345e697 100644
--- a/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
+++ b/chromium/third_party/blink/renderer/core/css/style_sheet_contents.h
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/rule_set.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
@@ -189,6 +190,13 @@ class CORE_EXPORT StyleSheetContents final
String SourceMapURL() const { return source_map_url_; }
+ void SetRenderBlocking(RenderBlockingBehavior behavior) {
+ render_blocking_behavior_ = behavior;
+ }
+ RenderBlockingBehavior GetRenderBlockingBehavior() const {
+ return render_blocking_behavior_;
+ }
+
void Trace(Visitor*) const;
private:
@@ -226,6 +234,8 @@ class CORE_EXPORT StyleSheetContents final
Member<RuleSet> rule_set_;
String source_map_url_;
+ RenderBlockingBehavior render_blocking_behavior_ =
+ RenderBlockingBehavior::kUnset;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_traversal_root.cc b/chromium/third_party/blink/renderer/core/css/style_traversal_root.cc
index af9eba2125f..497a076dad2 100644
--- a/chromium/third_party/blink/renderer/core/css/style_traversal_root.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_traversal_root.cc
@@ -13,6 +13,7 @@ void StyleTraversalRoot::Update(ContainerNode* common_ancestor,
Node* dirty_node) {
DCHECK(dirty_node);
DCHECK(dirty_node->isConnected());
+ AssertRootNodeInvariants();
if (!common_ancestor) {
// This is either first dirty node in which case we are using it as a
@@ -55,9 +56,12 @@ void StyleTraversalRoot::Update(ContainerNode* common_ancestor,
root_type_ = RootType::kCommonRoot;
}
-void StyleTraversalRoot::ChildrenRemoved(ContainerNode& parent) {
- if (root_node_ && !root_node_->isConnected())
- RootRemoved(parent);
+#if DCHECK_IS_ON()
+bool StyleTraversalRoot::RootIsBeingRemoved() const {
+ DCHECK(root_node_);
+ return !root_node_->isConnected() &&
+ root_node_->GetDocument().GetStyleEngine().InDOMRemoval();
}
+#endif
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/css/style_traversal_root.h b/chromium/third_party/blink/renderer/core/css/style_traversal_root.h
index aab33381285..53378ce0252 100644
--- a/chromium/third_party/blink/renderer/core/css/style_traversal_root.h
+++ b/chromium/third_party/blink/renderer/core/css/style_traversal_root.h
@@ -36,9 +36,10 @@ class CORE_EXPORT StyleTraversalRoot {
// marked as having dirty children.
void Update(ContainerNode* common_ancestor, Node* dirty_node);
- // Clear the root if the removal caused the current root_node_ to be
- // disconnected.
- void ChildrenRemoved(ContainerNode& parent);
+ // Update the root node if the current has been removed from the tree.
+ // The 'tree' here may refer to the flat tree if marking ancestors happen in
+ // the flat for the given subclass.
+ virtual void SubtreeModified(ContainerNode& parent) = 0;
Node* GetRootNode() const { return root_node_; }
void Clear() {
@@ -55,19 +56,31 @@ class CORE_EXPORT StyleTraversalRoot {
// Return the parent node for type of traversal for which the implementation
// is a root.
virtual ContainerNode* Parent(const Node&) const = 0;
+
+ // Return true if the given node is marked dirty or child-dirty.
+ virtual bool IsChildDirty(const Node&) const = 0;
#endif // DCHECK_IS_ON()
// Return true if the given node is dirty.
virtual bool IsDirty(const Node&) const = 0;
- // Update the root node when removed.
- virtual void RootRemoved(ContainerNode& parent) = 0;
-
bool IsSingleRoot() const { return root_type_ == RootType::kSingleRoot; }
private:
friend class StyleTraversalRootTestImpl;
+#if DCHECK_IS_ON()
+ bool RootIsBeingRemoved() const;
+#endif
+
+ void AssertRootNodeInvariants() {
+#if DCHECK_IS_ON()
+ DCHECK(!root_node_ || root_node_->IsDocumentNode() ||
+ IsDirty(*root_node_) || IsChildDirty(*root_node_) ||
+ RootIsBeingRemoved());
+#endif
+ }
+
// The current root for dirty nodes.
Member<Node> root_node_;
diff --git a/chromium/third_party/blink/renderer/core/css/style_traversal_root_test.cc b/chromium/third_party/blink/renderer/core/css/style_traversal_root_test.cc
index 04bdb857ae4..538b03ecbe6 100644
--- a/chromium/third_party/blink/renderer/core/css/style_traversal_root_test.cc
+++ b/chromium/third_party/blink/renderer/core/css/style_traversal_root_test.cc
@@ -18,10 +18,25 @@ class StyleTraversalRootTestImpl : public StyleTraversalRoot {
public:
StyleTraversalRootTestImpl() = default;
- void MarkDirty(const Node* node) { dirty_nodes_.insert(node); }
+ void MarkDirty(const Node* node) {
+ DCHECK(node);
+ dirty_nodes_.insert(node);
+#if DCHECK_IS_ON()
+ for (const Element* element = node->parentElement(); element;
+ element = element->parentElement()) {
+ child_dirty_nodes_.insert(element);
+ }
+#endif
+ }
bool IsSingleRoot() const { return root_type_ == RootType::kSingleRoot; }
bool IsCommonRoot() const { return root_type_ == RootType::kCommonRoot; }
+ void SubtreeModified(ContainerNode& parent) override {
+ if (!GetRootNode() || GetRootNode()->isConnected())
+ return;
+ Clear();
+ }
+
private:
virtual ContainerNode* ParentInternal(const Node& node) const {
return node.parentNode();
@@ -30,15 +45,18 @@ class StyleTraversalRootTestImpl : public StyleTraversalRoot {
ContainerNode* Parent(const Node& node) const override {
return ParentInternal(node);
}
+ bool IsChildDirty(const Node& node) const override {
+ return child_dirty_nodes_.Contains(&node);
+ }
#endif // DCHECK_IS_ON()
bool IsDirty(const Node& node) const final {
return dirty_nodes_.Contains(&node);
}
- void RootRemoved(ContainerNode& parent) override {
- Clear();
- }
HeapHashSet<Member<const Node>> dirty_nodes_;
+#if DCHECK_IS_ON()
+ HeapHashSet<Member<const Node>> child_dirty_nodes_;
+#endif
};
class StyleTraversalRootTest : public testing::Test {
@@ -137,7 +155,7 @@ TEST_F(StyleTraversalRootTest, Update_CommonRootDocumentFallback) {
EXPECT_TRUE(root.IsCommonRoot());
}
-TEST_F(StyleTraversalRootTest, ChildrenRemoved) {
+TEST_F(StyleTraversalRootTest, SubtreeModified) {
StyleTraversalRootTestImpl root;
// Initially make E a single root.
root.MarkDirty(DivElement(kE));
@@ -147,13 +165,13 @@ TEST_F(StyleTraversalRootTest, ChildrenRemoved) {
// Removing D not affecting E.
DivElement(kD)->remove();
- root.ChildrenRemoved(*DivElement(kB));
+ root.SubtreeModified(*DivElement(kB));
EXPECT_EQ(DivElement(kE), root.GetRootNode());
EXPECT_TRUE(root.IsSingleRoot());
// Removing B
DivElement(kB)->remove();
- root.ChildrenRemoved(*DivElement(kA));
+ root.SubtreeModified(*DivElement(kA));
EXPECT_FALSE(root.GetRootNode());
EXPECT_TRUE(root.IsSingleRoot());
}
diff --git a/chromium/third_party/blink/renderer/core/css/svg.css b/chromium/third_party/blink/renderer/core/css/svg.css
index ed746bbc946..557df4ed050 100644
--- a/chromium/third_party/blink/renderer/core/css/svg.css
+++ b/chromium/third_party/blink/renderer/core/css/svg.css
@@ -90,10 +90,6 @@ tspan, textPath {
https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties
*/
@media ua-forced-colors {
- svg:root {
- color: CanvasText;
- }
-
svg {
forced-color-adjust: none;
}
diff --git a/chromium/third_party/blink/renderer/core/css/tree_scope_style_sheet_collection.cc b/chromium/third_party/blink/renderer/core/css/tree_scope_style_sheet_collection.cc
index 19d3520504f..0098f78a919 100644
--- a/chromium/third_party/blink/renderer/core/css/tree_scope_style_sheet_collection.cc
+++ b/chromium/third_party/blink/renderer/core/css/tree_scope_style_sheet_collection.cc
@@ -53,8 +53,7 @@ void TreeScopeStyleSheetCollection::AddStyleSheetCandidateNode(Node& node) {
void TreeScopeStyleSheetCollection::ApplyActiveStyleSheetChanges(
StyleSheetCollection& new_collection) {
GetDocument().GetStyleEngine().ApplyRuleSetChanges(
- GetTreeScope(), ActiveAuthorStyleSheets(),
- new_collection.ActiveAuthorStyleSheets());
+ GetTreeScope(), ActiveStyleSheets(), new_collection.ActiveStyleSheets());
new_collection.Swap(*this);
}
diff --git a/chromium/third_party/blink/renderer/core/css/view-source.css b/chromium/third_party/blink/renderer/core/css/view-source.css
index aca01f73d7c..a54f79a9fc1 100644
--- a/chromium/third_party/blink/renderer/core/css/view-source.css
+++ b/chromium/third_party/blink/renderer/core/css/view-source.css
@@ -27,16 +27,39 @@ body {
}
table {
- width: 100%;
+ width: max-content;
+ min-width: 100vw;
border-spacing: 0;
- white-space: pre-wrap !important;
- word-break: break-word;
+ white-space: pre;
margin: 0;
font-size: initial;
font-family: monospace;
tab-size: 4;
}
+.line-wrap {
+ width: 100%;
+ white-space: pre-wrap !important;
+ word-break: normal;
+ overflow-wrap: anywhere;
+}
+
+.line-wrap-control {
+ width: 100%;
+ font-size: initial;
+ font-family: monospace;
+ user-select: none;
+ background-color: rgb(240, 240, 240);
+ border-bottom: 1px solid rgb(187, 187, 187);
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+.line-wrap-cell {
+ white-space: normal;
+}
+
td {
padding: 0 !important;
vertical-align: baseline
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index af78c7ef3d9..3cc702c395f 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/auto_reset.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
@@ -92,6 +93,19 @@ void RecordActivationReason(Document* document,
if (document && reason == DisplayLockActivationReason::kFindInPage)
document->MarkHasFindInPageContentVisibilityActiveMatch();
}
+
+ScrollableArea* GetScrollableArea(Node* node) {
+ if (!node)
+ return nullptr;
+
+ LayoutBoxModelObject* object =
+ DynamicTo<LayoutBoxModelObject>(node->GetLayoutObject());
+ if (!object)
+ return nullptr;
+
+ return object->GetScrollableArea();
+}
+
} // namespace
DisplayLockContext::DisplayLockContext(Element* element)
@@ -105,6 +119,7 @@ void DisplayLockContext::SetRequestedState(EContentVisibility state) {
if (state_ == state)
return;
state_ = state;
+ base::AutoReset<bool> scope(&set_requested_state_scope_, true);
switch (state_) {
case EContentVisibility::kVisible:
RequestUnlock();
@@ -145,10 +160,6 @@ void DisplayLockContext::SetRequestedState(EContentVisibility state) {
// Since our state changed, check if we need to create a scoped force update
// object.
- // Note that creating this forced object may cause us to dirty style, which is
- // fine since we are in a style update for this subtree anyway.
- StyleEngine::AllowMarkStyleDirtyFromRecalcScope scope(
- element_->GetDocument().GetStyleEngine());
element_->GetDocument().GetDisplayLockDocumentState().ForceLockIfNeeded(
element_.Get());
}
@@ -289,7 +300,7 @@ void DisplayLockContext::Lock() {
// In the first case, we are already in style processing, so we don't need to
// invalidate style. However, in the second case we invalidate style so that
// `AdjustElementStyle()` can be called.
- if (!document_->InStyleRecalc()) {
+ if (CanDirtyStyle()) {
element_->SetNeedsStyleRecalc(
kLocalStyleChange,
StyleChangeReasonForTracing::Create(style_change_reason::kDisplayLock));
@@ -321,6 +332,12 @@ void DisplayLockContext::Lock() {
if (!element_->GetLayoutObject())
return;
+ // If this element is a scroller, then stash its current scroll offset, so
+ // that we can restore it when needed.
+ // Note that this only applies if the element itself is a scroller. Any
+ // subtree scrollers' scroll offsets are not affected.
+ StashScrollOffsetIfAvailable();
+
MarkNeedsRepaintAndPaintArtifactCompositorUpdate();
}
@@ -366,6 +383,11 @@ void DisplayLockContext::DidLayoutChildren() {
// Since we did layout on children already, we'll clear this.
child_layout_was_blocked_ = false;
had_lifecycle_update_since_last_unlock_ = true;
+
+ // If we're not locked and we laid out the children, then now is a good time
+ // to restore the scroll offset.
+ if (!is_locked_)
+ RestoreScrollOffsetIfStashed();
}
bool DisplayLockContext::ShouldPrePaintChildren() const {
@@ -491,8 +513,12 @@ void DisplayLockContext::NotifyForcedUpdateScopeStarted() {
// Now that the update is forced, we should ensure that style layout, and
// prepaint code can reach it via dirty bits. Note that paint isn't a part
// of this, since |update_forced_| doesn't force paint to happen. See
- // ShouldPaint().
- MarkForStyleRecalcIfNeeded();
+ // ShouldPaint(). Also, we could have forced a lock from SetRequestedState
+ // during a style update. If that's the case, don't mark style as dirty
+ // from within style recalc. We rely on `AdjustStyleRecalcChangeForChildren`
+ // instead.
+ if (CanDirtyStyle())
+ MarkForStyleRecalcIfNeeded();
MarkForLayoutIfNeeded();
MarkAncestorsForPrePaintIfNeeded();
}
@@ -524,7 +550,7 @@ void DisplayLockContext::Unlock() {
// In the first case, we are already in style processing, so we don't need to
// invalidate style. However, in the second case we invalidate style so that
// `AdjustElementStyle()` can be called.
- if (!document_->InStyleRecalc()) {
+ if (CanDirtyStyle()) {
// Since size containment depends on the activatability state, we should
// invalidate the style for this element, so that the style adjuster can
// properly remove the containment.
@@ -553,6 +579,7 @@ void DisplayLockContext::Unlock() {
MarkForLayoutIfNeeded();
MarkAncestorsForPrePaintIfNeeded();
MarkNeedsRepaintAndPaintArtifactCompositorUpdate();
+ MarkNeedsCullRectUpdate();
}
void DisplayLockContext::AddToWhitespaceReattachSet(Element& element) {
@@ -577,7 +604,7 @@ StyleRecalcChange DisplayLockContext::AdjustStyleRecalcChangeForChildren(
// |change| and not on |element_|. This is only called during style recalc.
// Note that since we're already in self style recalc, this code is shorter
// since it doesn't have to deal with dirtying self-style.
- DCHECK(document_->InStyleRecalc());
+ DCHECK(!CanDirtyStyle());
if (reattach_layout_tree_was_blocked_) {
change = change.ForceReattachLayoutTree();
@@ -592,6 +619,10 @@ StyleRecalcChange DisplayLockContext::AdjustStyleRecalcChangeForChildren(
return change;
}
+bool DisplayLockContext::CanDirtyStyle() const {
+ return !set_requested_state_scope_ && !document_->InStyleRecalc();
+}
+
bool DisplayLockContext::MarkForStyleRecalcIfNeeded() {
if (reattach_layout_tree_was_blocked_) {
// We previously blocked a layout tree reattachment on |element_|'s
@@ -634,13 +665,23 @@ bool DisplayLockContext::MarkForLayoutIfNeeded() {
// Forces the marking of ancestors to happen, even if
// |DisplayLockContext::ShouldLayout()| returns false.
base::AutoReset<int> scoped_force(&update_forced_, update_forced_ + 1);
- if (child_layout_was_blocked_) {
+ if (child_layout_was_blocked_ || HasStashedScrollOffset()) {
// We've previously blocked a child traversal when doing self-layout for
// the locked element, so we're marking it with child-needs-layout so that
// it will traverse to the locked element and do the child traversal
// again. We don't need to mark it for self-layout (by calling
// |LayoutObject::SetNeedsLayout()|) because the locked element itself
// doesn't need to relayout.
+ //
+ // Note that we also make sure to visit the children when we have a
+ // stashed scroll offset. This is so that we can restore the offset after
+ // laying out the children. If we try to restore it before the layout, it
+ // will be ignored since the scroll area may think that it doesn't have
+ // enough contents.
+ // TODO(vmpstr): In the scroll offset case, we're doing this just so we
+ // can reach DisplayLockContext::DidLayoutChildren where we restore the
+ // offset. If performance becomes an issue, then we should think of a
+ // different time / opportunity to restore the offset.
element_->GetLayoutObject()->SetChildNeedsLayout();
child_layout_was_blocked_ = false;
} else {
@@ -698,6 +739,18 @@ bool DisplayLockContext::MarkNeedsRepaintAndPaintArtifactCompositorUpdate() {
return false;
}
+bool DisplayLockContext::MarkNeedsCullRectUpdate() {
+ DCHECK(ConnectedToView());
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return false;
+
+ if (auto* layout_object = element_->GetLayoutObject()) {
+ layout_object->PaintingLayer()->SetForcesChildrenCullRectUpdate();
+ return true;
+ }
+ return false;
+}
+
bool DisplayLockContext::MarkForCompositingUpdatesIfNeeded() {
if (!ConnectedToView())
return false;
@@ -760,8 +813,10 @@ bool DisplayLockContext::IsElementDirtyForStyleRecalc() const {
}
bool DisplayLockContext::IsElementDirtyForLayout() const {
- if (auto* layout_object = element_->GetLayoutObject())
- return layout_object->NeedsLayout() || child_layout_was_blocked_;
+ if (auto* layout_object = element_->GetLayoutObject()) {
+ return layout_object->NeedsLayout() || child_layout_was_blocked_ ||
+ HasStashedScrollOffset();
+ }
return false;
}
@@ -1058,7 +1113,8 @@ void DisplayLockContext::NotifyRenderAffectingStateChanged() {
(!state(RenderAffectingState::kIntersectsViewport) &&
!state(RenderAffectingState::kSubtreeHasFocus) &&
!state(RenderAffectingState::kSubtreeHasSelection) &&
- !state(RenderAffectingState::kAutoStateUnlockedUntilLifecycle)));
+ !state(RenderAffectingState::kAutoStateUnlockedUntilLifecycle) &&
+ !state(RenderAffectingState::kAutoUnlockedForPrint)));
if (should_be_locked && !IsLocked())
Lock();
@@ -1072,6 +1128,10 @@ void DisplayLockContext::Trace(Visitor* visitor) const {
visitor->Trace(whitespace_reattach_set_);
}
+void DisplayLockContext::SetShouldUnlockAutoForPrint(bool flag) {
+ SetRenderAffectingState(RenderAffectingState::kAutoUnlockedForPrint, flag);
+}
+
const char* DisplayLockContext::RenderAffectingStateName(int state) const {
switch (static_cast<RenderAffectingState>(state)) {
case RenderAffectingState::kLockRequested:
@@ -1084,6 +1144,8 @@ const char* DisplayLockContext::RenderAffectingStateName(int state) const {
return "SubtreeHasSelection";
case RenderAffectingState::kAutoStateUnlockedUntilLifecycle:
return "AutoStateUnlockedUntilLifecycle";
+ case RenderAffectingState::kAutoUnlockedForPrint:
+ return "AutoUnlockedForPrint";
case RenderAffectingState::kNumRenderAffectingStates:
break;
}
@@ -1103,4 +1165,31 @@ String DisplayLockContext::RenderAffectingStateToString() const {
return builder.ToString();
}
+void DisplayLockContext::StashScrollOffsetIfAvailable() {
+ if (auto* area = GetScrollableArea(element_)) {
+ const ScrollOffset& offset = area->GetScrollOffset();
+ // Only store the offset if it's non-zero. This is because scroll
+ // restoration has a small performance implication and restoring to a zero
+ // offset is the same as not restoring it.
+ if (!offset.IsZero())
+ stashed_scroll_offset_.emplace(offset);
+ }
+}
+
+void DisplayLockContext::RestoreScrollOffsetIfStashed() {
+ if (!stashed_scroll_offset_.has_value())
+ return;
+
+ // Restore the offset and reset the value.
+ if (auto* area = GetScrollableArea(element_)) {
+ area->SetScrollOffset(*stashed_scroll_offset_,
+ mojom::blink::ScrollType::kAnchoring);
+ stashed_scroll_offset_.reset();
+ }
+}
+
+bool DisplayLockContext::HasStashedScrollOffset() const {
+ return stashed_scroll_offset_.has_value();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 56ea1a3cec5..1ffb7a7fbab 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/core/style/computed_style_base_constants.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -215,6 +216,9 @@ class CORE_EXPORT DisplayLockContext final
return had_lifecycle_update_since_last_unlock_;
}
+ // We unlock auto locks for printing, which is set here.
+ void SetShouldUnlockAutoForPrint(bool);
+
private:
// Give access to |NotifyForcedUpdateScopeStarted()| and
// |NotifyForcedUpdateScopeEnded()|.
@@ -261,6 +265,7 @@ class CORE_EXPORT DisplayLockContext final
bool MarkForLayoutIfNeeded();
bool MarkAncestorsForPrePaintIfNeeded();
bool MarkNeedsRepaintAndPaintArtifactCompositorUpdate();
+ bool MarkNeedsCullRectUpdate();
bool MarkForCompositingUpdatesIfNeeded();
bool IsElementDirtyForStyleRecalc() const;
@@ -319,6 +324,19 @@ class CORE_EXPORT DisplayLockContext final
// setting.
void SetKeepUnlockedUntilLifecycleCount(int count);
+ // Returns true if the context can dirty element's style in the current
+ // processing. Note that this returns false if the document is doing a style
+ // recalc, or if we're currently setting a new requested state which happens
+ // in style adjustment.
+ bool CanDirtyStyle() const;
+
+ // When a scroller becomes locked, we store off its current scroll offset, to
+ // avoid losing the offset when the scroller becomes unlocked in the future.
+ // The following functions enable this functionality.
+ void StashScrollOffsetIfAvailable();
+ void RestoreScrollOffsetIfStashed();
+ bool HasStashedScrollOffset() const;
+
WeakMember<Element> element_;
WeakMember<Document> document_;
EContentVisibility state_ = EContentVisibility::kVisible;
@@ -392,6 +410,7 @@ class CORE_EXPORT DisplayLockContext final
kSubtreeHasFocus,
kSubtreeHasSelection,
kAutoStateUnlockedUntilLifecycle,
+ kAutoUnlockedForPrint,
kNumRenderAffectingStates
};
void SetRenderAffectingState(RenderAffectingState state, bool flag);
@@ -403,6 +422,14 @@ class CORE_EXPORT DisplayLockContext final
int keep_unlocked_count_ = 0;
bool had_lifecycle_update_since_last_unlock_ = false;
+
+ // Tracks whether we're updating requested state, which can only happen from
+ // the style adjuster. Note that this is different from a InStyleRecalc check
+ // since we can also force update style outside of this call (via ensure
+ // computed style).
+ bool set_requested_state_scope_ = false;
+
+ base::Optional<ScrollOffset> stashed_scroll_offset_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 8fb4be2df8c..9118d6d867f 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -405,7 +405,10 @@ TEST_F(DisplayLockContextTest, FindInPageTargetBelowLockedSize) {
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(container->GetDisplayLockContext()->IsLocked());
- EXPECT_FLOAT_EQ(GetDocument().scrollingElement()->scrollTop(), 1768);
+ if (RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled())
+ EXPECT_FLOAT_EQ(GetDocument().scrollingElement()->scrollTop(), 1768.5);
+ else
+ EXPECT_FLOAT_EQ(GetDocument().scrollingElement()->scrollTop(), 1768);
}
TEST_F(DisplayLockContextTest,
@@ -735,9 +738,11 @@ TEST_F(DisplayLockContextTest, CallUpdateStyleAndLayoutAfterChange) {
EXPECT_FALSE(element->ChildNeedsReattachLayoutTree());
// Simulating style recalc happening, will mark for reattachment.
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
element->ClearChildNeedsStyleRecalc();
element->firstChild()->ClearNeedsStyleRecalc();
element->GetDisplayLockContext()->DidStyleChildren();
+ GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
EXPECT_FALSE(element->ChildNeedsStyleRecalc());
EXPECT_FALSE(element->NeedsReattachLayoutTree());
@@ -3376,4 +3381,92 @@ TEST_F(DisplayLockContextTest, GraphicsLayerBitsNotCheckedInLockedSubtree) {
EXPECT_FALSE(
target_layer->GetCompositedLayerMapping()->NeedsGraphicsLayerUpdate());
}
+
+TEST_F(DisplayLockContextTest, PrintingUnlocksAutoLocks) {
+ ResizeAndFocus();
+
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ .spacer { height: 30000px; }
+ .auto { content-visibility: auto; }
+ </style>
+ <div class=spacer></div>
+ <div id=target class=auto>
+ <div id=nested class=auto></div>
+ </div>
+ )HTML");
+
+ auto* target = GetDocument().getElementById("target");
+ auto* nested = GetDocument().getElementById("nested");
+ ASSERT_TRUE(target->GetDisplayLockContext());
+ EXPECT_TRUE(target->GetDisplayLockContext()->IsLocked());
+ // Nested should not have a display lock since we would have skipped style.
+ EXPECT_FALSE(nested->GetDisplayLockContext());
+
+ {
+ // Create a paint preview scope.
+ Document::PaintPreviewScope scope(GetDocument());
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FALSE(target->GetDisplayLockContext()->IsLocked());
+ // Nested should have created a context...
+ ASSERT_TRUE(nested->GetDisplayLockContext());
+ // ... but it should be unlocked.
+ EXPECT_FALSE(nested->GetDisplayLockContext()->IsLocked());
+ }
+
+ EXPECT_TRUE(target->GetDisplayLockContext()->IsLocked());
+ EXPECT_TRUE(nested->GetDisplayLockContext()->IsLocked());
+}
+
+TEST_F(DisplayLockContextTest, CullRectUpdate) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+ ResizeAndFocus();
+ SetHtmlInnerHTML(R"HTML(
+ <style>
+ #clip {
+ width: 100px;
+ height: 100px;
+ overflow: hidden;
+ }
+ #container {
+ width: 300px;
+ height: 300px;
+ contain: paint layout;
+ }
+ .locked {
+ content-visibility: hidden;
+ }
+ </style>
+ <div id="clip">
+ <div id="container"
+ style="width: 300px; height: 300px; contain: paint layout">
+ <div id="target" style="position: relative"></div>
+ </div>
+ </div>
+ )HTML");
+
+ // Check if the result is correct if we update the contents.
+ auto* container = GetDocument().getElementById("container");
+ auto* target = GetDocument().getElementById("target")->GetLayoutBox();
+ EXPECT_EQ(IntRect(0, 0, 100, 100),
+ target->FirstFragment().GetCullRect().Rect());
+
+ container->classList().Add("locked");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(IntRect(0, 0, 100, 100),
+ target->FirstFragment().GetCullRect().Rect());
+
+ GetDocument().getElementById("clip")->setAttribute(html_names::kStyleAttr,
+ "width: 200px");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(IntRect(0, 0, 100, 100),
+ target->FirstFragment().GetCullRect().Rect());
+
+ container->classList().Remove("locked");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(IntRect(0, 0, 200, 100),
+ target->FirstFragment().GetCullRect().Rect());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc
index 7c5796cdf09..9aa3952d054 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc
@@ -27,6 +27,7 @@ void DisplayLockDocumentState::Trace(Visitor* visitor) const {
void DisplayLockDocumentState::AddDisplayLockContext(
DisplayLockContext* context) {
display_lock_contexts_.insert(context);
+ context->SetShouldUnlockAutoForPrint(printing_);
}
void DisplayLockDocumentState::RemoveDisplayLockContext(
@@ -43,11 +44,13 @@ void DisplayLockDocumentState::AddLockedDisplayLock() {
"LockedDisplayLockCount", TRACE_ID_LOCAL(this),
locked_display_lock_count_);
++locked_display_lock_count_;
+ last_lock_update_timestamp_ = base::TimeTicks::Now();
}
void DisplayLockDocumentState::RemoveLockedDisplayLock() {
DCHECK(locked_display_lock_count_);
--locked_display_lock_count_;
+ last_lock_update_timestamp_ = base::TimeTicks::Now();
TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"),
"LockedDisplayLockCount", TRACE_ID_LOCAL(this),
locked_display_lock_count_);
@@ -70,6 +73,10 @@ int DisplayLockDocumentState::DisplayLockBlockingAllActivationCount() const {
return display_lock_blocking_all_activation_count_;
}
+base::TimeTicks DisplayLockDocumentState::GetLockUpdateTimestamp() {
+ return last_lock_update_timestamp_;
+}
+
void DisplayLockDocumentState::RegisterDisplayLockActivationObservation(
Element* element) {
EnsureIntersectionObserver().observe(element);
@@ -90,6 +97,9 @@ IntersectionObserver& DisplayLockDocumentState::EnsureIntersectionObserver() {
//
// Note that we use 150% margin (on the viewport) so that we get the
// observation before the element enters the viewport.
+ //
+ // Paint containment requires using the overflow clip edge. To do otherwise
+ // results in overflow-clip-margin not being painted in certain scenarios.
intersection_observer_ = IntersectionObserver::Create(
{Length::Percent(150.f)}, {std::numeric_limits<float>::min()},
document_,
@@ -100,7 +110,8 @@ IntersectionObserver& DisplayLockDocumentState::EnsureIntersectionObserver() {
IntersectionObserver::kDeliverDuringPostLayoutSteps,
IntersectionObserver::kFractionOfTarget, 0 /* delay */,
false /* track_visibility */, false /* always report_root_bounds */,
- IntersectionObserver::kApplyMarginToTarget);
+ IntersectionObserver::kApplyMarginToTarget,
+ true /* use_overflow_clip_edge */);
}
return *intersection_observer_;
}
@@ -239,4 +250,14 @@ DisplayLockDocumentState::ScopedForceActivatableDisplayLocks::
--state_->activatable_display_locks_forced_;
}
+void DisplayLockDocumentState::NotifyPrintingOrPreviewChanged() {
+ bool was_printing = printing_;
+ printing_ = document_->IsPrintingOrPaintingPreview();
+ if (printing_ == was_printing)
+ return;
+
+ for (auto& context : display_lock_contexts_)
+ context->SetShouldUnlockAutoForPrint(printing_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.h b/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
index 5a310b5a36c..9a2e4c9901b 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
@@ -126,6 +126,10 @@ class CORE_EXPORT DisplayLockDocumentState final
Member<DisplayLockUtilities::ScopedForcedUpdate::Impl> chain;
};
+ void NotifyPrintingOrPreviewChanged();
+
+ base::TimeTicks GetLockUpdateTimestamp();
+
private:
IntersectionObserver& EnsureIntersectionObserver();
@@ -150,6 +154,10 @@ class CORE_EXPORT DisplayLockDocumentState final
// Contains all of the currently forced node infos, each of which represents
// the node that caused the scope to be created.
HeapVector<ForcedNodeInfo> forced_node_info_;
+
+ bool printing_ = false;
+
+ base::TimeTicks last_lock_update_timestamp_ = base::TimeTicks();
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index 89020ba1e2a..bebc5dbeb82 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -139,7 +139,6 @@ DisplayLockUtilities::ActivatableLockedInclusiveAncestors(
const Node& node,
DisplayLockActivationReason reason) {
HeapVector<Member<Element>> elements_to_activate;
- const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
if (!RuntimeEnabledFeatures::CSSContentVisibilityEnabled() ||
node.GetDocument()
.GetDisplayLockDocumentState()
@@ -185,7 +184,6 @@ DisplayLockUtilities::ScopedForcedUpdate::Impl::Impl(const Node* node,
.GetDisplayLockDocumentState()
.LockedDisplayLockCount() == 0)
return;
- const_cast<Node*>(node)->UpdateDistributionForFlatTreeTraversal();
// Get the right ancestor view. Only use inclusive ancestors if the node
// itself is locked and it prevents self layout, or if |include_self| is true.
@@ -235,7 +233,6 @@ void DisplayLockUtilities::ScopedForcedUpdate::Impl::
const Element* DisplayLockUtilities::NearestLockedInclusiveAncestor(
const Node& node) {
- const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
auto* element = DynamicTo<Element>(node);
if (!element)
return NearestLockedExclusiveAncestor(node);
@@ -276,7 +273,6 @@ Element* DisplayLockUtilities::NearestHiddenMatchableInclusiveAncestor(
}
}
- element.UpdateDistributionForFlatTreeTraversal();
// TODO(crbug.com/924550): Once we figure out a more efficient way to
// determine whether we're inside a locked subtree or not, change this.
for (Node& ancestor : FlatTreeTraversal::AncestorsOf(element)) {
@@ -302,7 +298,6 @@ Element* DisplayLockUtilities::NearestLockedExclusiveAncestor(
!node.CanParticipateInFlatTree()) {
return nullptr;
}
- const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
// TODO(crbug.com/924550): Once we figure out a more efficient way to
// determine whether we're inside a locked subtree or not, change this.
for (Node& ancestor : FlatTreeTraversal::AncestorsOf(node)) {
@@ -324,7 +319,6 @@ Element* DisplayLockUtilities::HighestLockedInclusiveAncestor(
return nullptr;
}
auto* node_ptr = const_cast<Node*>(&node);
- node_ptr->UpdateDistributionForFlatTreeTraversal();
// If the exclusive result exists, then that's higher than this node, so
// return it.
if (auto* result = HighestLockedExclusiveAncestor(node))
@@ -346,7 +340,6 @@ Element* DisplayLockUtilities::HighestLockedExclusiveAncestor(
!node.CanParticipateInFlatTree()) {
return nullptr;
}
- const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
Node* parent = FlatTreeTraversal::Parent(node);
Element* locked_ancestor = nullptr;
@@ -360,11 +353,8 @@ Element* DisplayLockUtilities::HighestLockedExclusiveAncestor(
parent = nullptr;
}
- if (!parent) {
+ if (!parent)
parent = GetFrameOwnerNode(last_node);
- if (parent)
- parent->UpdateDistributionForFlatTreeTraversal();
- }
}
return locked_ancestor;
}
@@ -398,9 +388,6 @@ bool DisplayLockUtilities::IsInUnlockedOrActivatableSubtree(
node.GetDocument()
.GetDisplayLockDocumentState()
.LockedDisplayLockCount() == 0 ||
- node.GetDocument()
- .GetDisplayLockDocumentState()
- .DisplayLockBlockingAllActivationCount() == 0 ||
!node.CanParticipateInFlatTree()) {
return true;
}
@@ -418,8 +405,11 @@ bool DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
const Node& source_node) {
if (!RuntimeEnabledFeatures::CSSContentVisibilityEnabled())
return false;
+ if (LocalFrameView* frame_view = source_node.GetDocument().View()) {
+ if (frame_view->IsDisplayLocked())
+ return true;
+ }
const Node* node = &source_node;
- const_cast<Node*>(node)->UpdateDistributionForFlatTreeTraversal();
// Since we handled the self-check above, we need to do inclusive checks
// starting from the parent.
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc
index f15245afa97..b52fb3eadd2 100644
--- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc
+++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities_test.cc
@@ -5,12 +5,15 @@
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intersection_observer_init.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/intersection_observer_test_helper.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
@@ -37,6 +40,21 @@ class DisplayLockUtilitiesTest
}
};
+TEST_F(DisplayLockUtilitiesTest, ShouldIgnoreHiddenMatchableChildren) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .hidden { content-visibility: hidden-matchable }
+ </style>
+ <div class=hidden>
+ <div id=target></div>
+ </div>
+ )HTML");
+
+ Node* target = GetDocument().getElementById("target");
+ EXPECT_TRUE(DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock(
+ *target, DisplayLockActivationReason::kAccessibility));
+}
+
TEST_F(DisplayLockUtilitiesTest, DISABLED_ActivatableLockedInclusiveAncestors) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -247,4 +265,70 @@ TEST_F(DisplayLockUtilitiesTest, LockedSubtreeCrossingFrames) {
EXPECT_FALSE(DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(*parent));
EXPECT_FALSE(DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(*child));
}
+
+TEST_F(DisplayLockUtilitiesTest, InteractionWithIntersectionObserver) {
+ SetHtmlInnerHTML(R"HTML(
+ <div id="container"><iframe id="frame"></iframe></div>
+ )HTML");
+ SetChildFrameHTML(R"HTML(
+ <div id="target"></target>
+ )HTML");
+
+ auto* container = GetDocument().getElementById("container");
+ auto* target = ChildDocument().getElementById("target");
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+ LockElement(*container, false);
+ EXPECT_TRUE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+
+ target->setInnerHTML("Hello, world!");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+ EXPECT_TRUE(ChildDocument().Lifecycle().GetState() ==
+ DocumentLifecycle::kVisualUpdatePending);
+
+ IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
+ TestIntersectionObserverDelegate* observer_delegate =
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(ChildDocument());
+ IntersectionObserver* observer =
+ IntersectionObserver::Create(observer_init, *observer_delegate);
+ observer->observe(target);
+ UpdateAllLifecyclePhasesForTest();
+ test::RunPendingTasks();
+ EXPECT_TRUE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+ EXPECT_EQ(ChildDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kVisualUpdatePending);
+ EXPECT_EQ(observer_delegate->CallCount(), 1);
+ EXPECT_EQ(observer_delegate->EntryCount(), 1);
+ EXPECT_FALSE(observer_delegate->LastEntry()->GetGeometry().IsIntersecting());
+ EXPECT_EQ(observer_delegate->LastEntry()->GetGeometry().TargetRect(),
+ PhysicalRect());
+ EXPECT_EQ(observer_delegate->LastEntry()->GetGeometry().RootRect(),
+ PhysicalRect());
+
+ CommitElement(*container);
+ test::RunPendingTasks();
+ EXPECT_FALSE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+ EXPECT_EQ(ChildDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kVisualUpdatePending);
+ EXPECT_EQ(observer_delegate->CallCount(), 1);
+
+ UpdateAllLifecyclePhasesForTest();
+ test::RunPendingTasks();
+ EXPECT_FALSE(ChildDocument().View()->ShouldThrottleRenderingForTest());
+ EXPECT_FALSE(ChildDocument().View()->NeedsLayout());
+ EXPECT_EQ(ChildDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPaintClean);
+ EXPECT_EQ(observer_delegate->CallCount(), 2);
+ EXPECT_EQ(observer_delegate->EntryCount(), 2);
+ EXPECT_TRUE(observer_delegate->LastEntry()->GetGeometry().IsIntersecting());
+ EXPECT_NE(observer_delegate->LastEntry()->GetGeometry().TargetRect(),
+ PhysicalRect());
+ EXPECT_EQ(observer_delegate->LastEntry()->GetGeometry().IntersectionRect(),
+ observer_delegate->LastEntry()->GetGeometry().TargetRect());
+ EXPECT_NE(observer_delegate->LastEntry()->GetGeometry().RootRect(),
+ PhysicalRect());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/document_transition/DEPS b/chromium/third_party/blink/renderer/core/document_transition/DEPS
new file mode 100644
index 00000000000..ae6214e9e53
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+cc/document_transition/document_transition_request.h"
+]
diff --git a/chromium/third_party/blink/renderer/core/document_transition/README.md b/chromium/third_party/blink/renderer/core/document_transition/README.md
new file mode 100644
index 00000000000..a2f2fb33372
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/README.md
@@ -0,0 +1,35 @@
+# Document Transitions
+
+This directory contains the script interface and implementation of the Document
+Transition, and Shared Element Transition APIs.
+
+Document Transition is a type of an animated transition that allows content to
+animate to a new DOM state easily. For instance, modifying the DOM to change the
+background color is a change that can easily be done without document
+transitions. However, document transition also allows the new background state
+to, for example, slide in from the left instead of simply atomically appearing
+on top of the content.
+
+For a detailed explanation, please see the
+[explainer](https://github.com/vmpstr/shared-element-transitions/blob/main/README.md)
+
+## Code Structure
+
+A new method is exposed on window.document, called createTransition(). This is
+the main interface to getting a new transition object from JavaScript. It is
+specified in the `document_create_transition.idl` and is implemented in
+corresponding `.cc` and `.h` files.
+
+When called, `createTransition()` constructs a DocumentTransition object which
+is specified in `document_transition.idl` and is implemented in corresponding
+`.cc` and `.h` files.
+
+The rest of the script interactions happen with this object.
+
+## Additional Notes
+
+Note that this project is in early stages of design and implementation. To
+follow the design evolution, please see [our github
+repo](https://github.com/vmpstr/shared-element-transitions/). Furthermore, this
+README's Code Structure section will be updated as we make progress with our
+implementation.
diff --git a/chromium/third_party/blink/renderer/core/document_transition/build.gni b/chromium/third_party/blink/renderer/core/document_transition/build.gni
new file mode 100644
index 00000000000..92f3747263d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/build.gni
@@ -0,0 +1,10 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+blink_core_sources_document_transition = [
+ "document_transition.cc",
+ "document_transition.h",
+ "document_transition_supplement.cc",
+ "document_transition_supplement.h",
+]
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition.cc b/chromium/third_party/blink/renderer/core/document_transition/document_transition.cc
new file mode 100644
index 00000000000..6ad6380ee0d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition.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/core/document_transition/document_transition.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+namespace {
+
+const int32_t kDefaultDurationMs = 300;
+
+DocumentTransition::Request::Effect ParseEffect(const String& input) {
+ using MapType = HashMap<String, DocumentTransition::Request::Effect>;
+ DEFINE_STATIC_LOCAL(
+ MapType*, lookup_map,
+ (new MapType{
+ {"cover-down", DocumentTransition::Request::Effect::kCoverDown},
+ {"cover-left", DocumentTransition::Request::Effect::kCoverLeft},
+ {"cover-right", DocumentTransition::Request::Effect::kCoverRight},
+ {"cover-up", DocumentTransition::Request::Effect::kCoverUp},
+ {"explode", DocumentTransition::Request::Effect::kExplode},
+ {"fade", DocumentTransition::Request::Effect::kFade},
+ {"implode", DocumentTransition::Request::Effect::kImplode},
+ {"reveal-down", DocumentTransition::Request::Effect::kRevealDown},
+ {"reveal-left", DocumentTransition::Request::Effect::kRevealLeft},
+ {"reveal-right", DocumentTransition::Request::Effect::kRevealRight},
+ {"reveal-up", DocumentTransition::Request::Effect::kRevealUp}}));
+
+ auto it = lookup_map->find(input);
+ return it != lookup_map->end() ? it->value
+ : DocumentTransition::Request::Effect::kNone;
+}
+
+} // namespace
+
+DocumentTransition::DocumentTransition(Document* document)
+ : ExecutionContextLifecycleObserver(document->GetExecutionContext()),
+ document_(document) {}
+
+void DocumentTransition::Trace(Visitor* visitor) const {
+ visitor->Trace(document_);
+ visitor->Trace(prepare_promise_resolver_);
+
+ ScriptWrappable::Trace(visitor);
+ ActiveScriptWrappable::Trace(visitor);
+ ExecutionContextLifecycleObserver::Trace(visitor);
+}
+
+void DocumentTransition::ContextDestroyed() {
+ if (prepare_promise_resolver_) {
+ prepare_promise_resolver_->Detach();
+ prepare_promise_resolver_ = nullptr;
+ }
+}
+
+bool DocumentTransition::HasPendingActivity() const {
+ if (prepare_promise_resolver_)
+ return true;
+ return false;
+}
+
+ScriptPromise DocumentTransition::prepare(
+ ScriptState* script_state,
+ const DocumentTransitionInit* params) {
+ // Reject any previous prepare promises.
+ if (state_ == State::kPreparing || state_ == State::kPrepared) {
+ if (prepare_promise_resolver_) {
+ prepare_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, "Aborted due to prepare() call"));
+ prepare_promise_resolver_ = nullptr;
+ }
+ state_ = State::kIdle;
+ }
+
+ // Increment the sequence id before any early outs so we will correctly
+ // process callbacks from previous requests.
+ ++prepare_sequence_id_;
+
+ // If we are not attached to a view, then we can't prepare a transition.
+ // Reject the promise. We also reject the promise if we're in any state other
+ // than idle.
+ if (!document_ || !document_->View() || state_ != State::kIdle) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ MakeGarbageCollected<DOMException>(DOMExceptionCode::kInvalidStateError,
+ "Invalid state"));
+ }
+
+ // We're going to be creating a new transition, initialize the params.
+ ParseAndSetTransitionParameters(params);
+
+ prepare_promise_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+
+ state_ = State::kPreparing;
+ pending_request_ = Request::CreatePrepare(
+ effect_, duration_,
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ &DocumentTransition::NotifyPrepareCommitted,
+ WrapCrossThreadWeakPersistent(this), prepare_sequence_id_)));
+
+ NotifyHasChangesToCommit();
+ return prepare_promise_resolver_->Promise();
+}
+
+void DocumentTransition::start() {
+ if (state_ != State::kPrepared)
+ return;
+
+ state_ = State::kStarted;
+ pending_request_ = Request::CreateStart(ConvertToBaseOnceCallback(
+ CrossThreadBindOnce(&DocumentTransition::NotifyStartCommitted,
+ WrapCrossThreadWeakPersistent(this))));
+ NotifyHasChangesToCommit();
+}
+
+void DocumentTransition::NotifyHasChangesToCommit() {
+ if (!document_ || !document_->GetPage() || !document_->View())
+ return;
+
+ // Schedule a new frame.
+ document_->GetPage()->Animator().ScheduleVisualUpdate(document_->GetFrame());
+
+ // Ensure paint artifact compositor does an update, since that's the mechanism
+ // we use to pass transition requests to the compositor.
+ document_->View()->SetPaintArtifactCompositorNeedsUpdate();
+}
+
+void DocumentTransition::NotifyPrepareCommitted(uint32_t sequence_id) {
+ // This notification is for a different sequence id.
+ if (sequence_id != prepare_sequence_id_)
+ return;
+
+ DCHECK(state_ == State::kPreparing);
+ DCHECK(prepare_promise_resolver_);
+
+ prepare_promise_resolver_->Resolve();
+ prepare_promise_resolver_ = nullptr;
+ state_ = State::kPrepared;
+}
+
+void DocumentTransition::NotifyStartCommitted() {
+ // TODO(vmpstr): This should only be cleared when the animation is actually
+ // over which means we need to plumb the callback all the way to viz.
+ state_ = State::kIdle;
+}
+
+std::unique_ptr<DocumentTransition::Request>
+DocumentTransition::TakePendingRequest() {
+ return std::move(pending_request_);
+}
+
+void DocumentTransition::ParseAndSetTransitionParameters(
+ const DocumentTransitionInit* params) {
+ duration_ = base::TimeDelta::FromMilliseconds(
+ params->hasDuration() ? params->duration() : kDefaultDurationMs);
+ effect_ = params->hasRootTransition() ? ParseEffect(params->rootTransition())
+ : Request::Effect::kNone;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition.h b/chromium/third_party/blink/renderer/core/document_transition/document_transition.h
new file mode 100644
index 00000000000..3923b6ce963
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition.h
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_H_
+
+#include "cc/document_transition/document_transition_request.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/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class Document;
+class DocumentTransitionInit;
+class ScriptState;
+
+class CORE_EXPORT DocumentTransition
+ : public ScriptWrappable,
+ public ActiveScriptWrappable<DocumentTransition>,
+ public ExecutionContextLifecycleObserver {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ using Request = cc::DocumentTransitionRequest;
+
+ explicit DocumentTransition(Document*);
+
+ // GC functionality.
+ void Trace(Visitor* visitor) const override;
+
+ // ExecutionContextLifecycleObserver implementation.
+ void ContextDestroyed() override;
+
+ // ActiveScriptWrappable functionality.
+ bool HasPendingActivity() const override;
+
+ // JavaScript API implementation.
+ ScriptPromise prepare(ScriptState*, const DocumentTransitionInit*);
+ void start();
+
+ // This uses std::move semantics to take the request from this object.
+ std::unique_ptr<Request> TakePendingRequest();
+
+ private:
+ friend class DocumentTransitionTest;
+
+ enum class State { kIdle, kPreparing, kPrepared, kStarted };
+
+ void NotifyHasChangesToCommit();
+
+ void NotifyPrepareCommitted(uint32_t sequence_id);
+ void NotifyStartCommitted();
+
+ void ParseAndSetTransitionParameters(const DocumentTransitionInit* params);
+
+ Member<Document> document_;
+
+ State state_ = State::kIdle;
+
+ Member<ScriptPromiseResolver> prepare_promise_resolver_;
+ base::TimeDelta duration_;
+ Request::Effect effect_ = Request::Effect::kNone;
+
+ std::unique_ptr<Request> pending_request_;
+
+ uint32_t prepare_sequence_id_ = 0u;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_H_
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition.idl b/chromium/third_party/blink/renderer/core/document_transition/document_transition.idl
new file mode 100644
index 00000000000..7296c86a87d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition.idl
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// See third_party/blink/renderer/core/document_transition/README.md.
+[
+ ActiveScriptWrappable,
+ Exposed=Window,
+ RuntimeEnabled=DocumentTransition
+] interface DocumentTransition {
+ // - This should only be called after any previous start() calls have resolved.
+ // - Rejects any previous unresolved prepare() promises.
+ // - Returns a promise that resolves after the transition has been
+ // prepared.
+ [CallWith=ScriptState] Promise<void> prepare(optional DocumentTransitionInit params = {});
+
+ // Can only be called after prepare(), during the task during
+ // which prepare() most recently resolved.
+ // TODO(vmpstr): This should return a promise that resolves when the
+ // transition completes.
+ void start();
+};
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition_init.idl b/chromium/third_party/blink/renderer/core/document_transition/document_transition_init.idl
new file mode 100644
index 00000000000..3ff0d265f6c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition_init.idl
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+enum RootTransitionType {
+ "none",
+ "cover-down",
+ "cover-left",
+ "cover-right",
+ "cover-up",
+ "explode",
+ "fade",
+ "implode",
+ "reveal-down",
+ "reveal-left",
+ "reveal-right",
+ "reveal-up"
+};
+
+dictionary DocumentTransitionInit {
+ RootTransitionType rootTransition = "none";
+ DOMTimeStamp duration = 0;
+};
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc
new file mode 100644
index 00000000000..7e964eea8c8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
+
+#include "third_party/blink/renderer/core/document_transition/document_transition.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+
+namespace blink {
+
+// static
+const char DocumentTransitionSupplement::kSupplementName[] =
+ "DocumentTransition";
+
+// static
+DocumentTransitionSupplement* DocumentTransitionSupplement::FromIfExists(
+ Document& document) {
+ return Supplement<Document>::From<DocumentTransitionSupplement>(document);
+}
+
+// static
+DocumentTransitionSupplement* DocumentTransitionSupplement::From(
+ Document& document) {
+ auto* supplement =
+ Supplement<Document>::From<DocumentTransitionSupplement>(document);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<DocumentTransitionSupplement>(document);
+ Supplement<Document>::ProvideTo(document, supplement);
+ }
+ return supplement;
+}
+
+// static
+DocumentTransition* DocumentTransitionSupplement::documentTransition(
+ Document& document) {
+ auto* supplement = From(document);
+ DCHECK(supplement->GetTransition());
+ return supplement->GetTransition();
+}
+
+DocumentTransition* DocumentTransitionSupplement::GetTransition() {
+ return transition_;
+}
+
+DocumentTransitionSupplement::DocumentTransitionSupplement(Document& document)
+ : Supplement<Document>(document),
+ transition_(MakeGarbageCollected<DocumentTransition>(&document)) {}
+
+void DocumentTransitionSupplement::Trace(Visitor* visitor) const {
+ visitor->Trace(transition_);
+
+ Supplement<Document>::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.h b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.h
new file mode 100644
index 00000000000..c998dbcbed0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+class DocumentTransition;
+
+class CORE_EXPORT DocumentTransitionSupplement
+ : public GarbageCollected<DocumentTransitionSupplement>,
+ public Supplement<Document> {
+ public:
+ static const char kSupplementName[];
+
+ // Supplement functionality.
+ static DocumentTransitionSupplement* From(Document&);
+ static DocumentTransitionSupplement* FromIfExists(Document&);
+
+ static DocumentTransition* documentTransition(Document&);
+
+ DocumentTransition* GetTransition();
+
+ explicit DocumentTransitionSupplement(Document&);
+
+ // GC functionality.
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ Member<DocumentTransition> transition_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl
new file mode 100644
index 00000000000..cf6c1b86f9f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ ImplementedAs=DocumentTransitionSupplement,
+ RuntimeEnabled=DocumentTransition
+] partial interface Document {
+ [SameObject] readonly attribute DocumentTransition documentTransition;
+};
diff --git a/chromium/third_party/blink/renderer/core/document_transition/document_transition_test.cc b/chromium/third_party/blink/renderer/core/document_transition/document_transition_test.cc
new file mode 100644
index 00000000000..cd5262a4a08
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/document_transition/document_transition_test.cc
@@ -0,0 +1,259 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/document_transition/document_transition.h"
+
+#include "base/test/scoped_feature_list.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/bindings/core/v8/v8_document_transition_init.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+class DocumentTransitionTest : public RenderingTest,
+ private ScopedDocumentTransitionForTest {
+ public:
+ DocumentTransitionTest()
+ : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()),
+ ScopedDocumentTransitionForTest(true) {}
+
+ void SetUp() override {
+ EnableCompositing();
+ RenderingTest::SetUp();
+ }
+
+ // Testing the compositor interaction is not in scope for these unittests. So,
+ // instead of setting up a full commit flow, simulate it by calling the commit
+ // callback directly.
+ void UpdateAllLifecyclePhasesAndSimulateCommit() {
+ UpdateAllLifecyclePhasesForTest();
+ for (auto& request : GetChromeClient()
+ .layer_tree_host()
+ ->TakeDocumentTransitionRequestsForTesting()) {
+ request->TakeCommitCallback().Run();
+ }
+ }
+
+ using State = DocumentTransition::State;
+
+ State GetState(DocumentTransition* transition) const {
+ return transition->state_;
+ }
+};
+
+TEST_F(DocumentTransitionTest, TransitionObjectPersists) {
+ auto* first_transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+ auto* second_transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ EXPECT_TRUE(first_transition);
+ EXPECT_EQ(GetState(first_transition), State::kIdle);
+ EXPECT_TRUE(second_transition);
+ EXPECT_EQ(first_transition, second_transition);
+}
+
+TEST_F(DocumentTransitionTest, TransitionPreparePromiseResolves) {
+ DocumentTransitionInit init;
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+ ASSERT_TRUE(transition);
+ EXPECT_EQ(GetState(transition), State::kIdle);
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ ScriptPromiseTester promise_tester(script_state,
+ transition->prepare(script_state, &init));
+
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ promise_tester.WaitUntilSettled();
+
+ EXPECT_TRUE(promise_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+}
+
+TEST_F(DocumentTransitionTest, AdditionalPrepareRejectsPreviousPromise) {
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ DocumentTransitionInit init;
+ ScriptPromiseTester first_promise_tester(
+ script_state, transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ ScriptPromiseTester second_promise_tester(
+ script_state, transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ first_promise_tester.WaitUntilSettled();
+ second_promise_tester.WaitUntilSettled();
+
+ EXPECT_TRUE(first_promise_tester.IsRejected());
+ EXPECT_TRUE(second_promise_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+}
+
+TEST_F(DocumentTransitionTest, EffectParsing) {
+ // Test default init.
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ DocumentTransitionInit default_init;
+ transition->prepare(script_state, &default_init);
+
+ auto request = transition->TakePendingRequest();
+ ASSERT_TRUE(request);
+
+ auto directive = request->ConstructDirective();
+ EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kNone);
+
+ // Test "explode" effect parsing.
+ DocumentTransitionInit explode_init;
+ explode_init.setRootTransition("explode");
+ transition->prepare(script_state, &explode_init);
+
+ request = transition->TakePendingRequest();
+ ASSERT_TRUE(request);
+
+ directive = request->ConstructDirective();
+ EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kExplode);
+
+ // Test invalid effect parsing.
+ DocumentTransitionInit invalid_init;
+ invalid_init.setRootTransition("invalid effect");
+ transition->prepare(script_state, &invalid_init);
+
+ request = transition->TakePendingRequest();
+ ASSERT_TRUE(request);
+
+ directive = request->ConstructDirective();
+ EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kNone);
+}
+
+TEST_F(DocumentTransitionTest, AdditionalPrepareAfterPreparedSucceeds) {
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ DocumentTransitionInit init;
+ ScriptPromiseTester first_promise_tester(
+ script_state, transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ first_promise_tester.WaitUntilSettled();
+ EXPECT_TRUE(first_promise_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+
+ ScriptPromiseTester second_promise_tester(
+ script_state, transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ second_promise_tester.WaitUntilSettled();
+ EXPECT_TRUE(second_promise_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+}
+
+TEST_F(DocumentTransitionTest, TransitionCleanedUpBeforePromiseResolution) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ DocumentTransitionInit init;
+ ScriptPromiseTester tester(
+ script_state,
+ DocumentTransitionSupplement::documentTransition(GetDocument())
+ ->prepare(script_state, &init));
+
+ // ActiveScriptWrappable should keep the transition alive.
+ ThreadState::Current()->CollectAllGarbageForTesting();
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ tester.WaitUntilSettled();
+ EXPECT_TRUE(tester.IsFulfilled());
+}
+
+TEST_F(DocumentTransitionTest, StartHasNoEffectUnlessPrepared) {
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+ EXPECT_EQ(GetState(transition), State::kIdle);
+ EXPECT_FALSE(transition->TakePendingRequest());
+
+ transition->start();
+
+ EXPECT_EQ(GetState(transition), State::kIdle);
+ EXPECT_FALSE(transition->TakePendingRequest());
+}
+
+TEST_F(DocumentTransitionTest, StartAfterPrepare) {
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ DocumentTransitionInit init;
+ ScriptPromiseTester prepare_tester(script_state,
+ transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ prepare_tester.WaitUntilSettled();
+ EXPECT_TRUE(prepare_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+
+ transition->start();
+ EXPECT_EQ(GetState(transition), State::kStarted);
+
+ // Take the request.
+ EXPECT_TRUE(transition->TakePendingRequest());
+
+ // Subsequent starts should not do anything.
+ transition->start();
+ EXPECT_EQ(GetState(transition), State::kStarted);
+ EXPECT_FALSE(transition->TakePendingRequest());
+}
+
+TEST_F(DocumentTransitionTest, StartIsPropagated) {
+ auto* transition =
+ DocumentTransitionSupplement::documentTransition(GetDocument());
+
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ DocumentTransitionInit init;
+ ScriptPromiseTester prepare_tester(script_state,
+ transition->prepare(script_state, &init));
+ EXPECT_EQ(GetState(transition), State::kPreparing);
+
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+ prepare_tester.WaitUntilSettled();
+ EXPECT_TRUE(prepare_tester.IsFulfilled());
+ EXPECT_EQ(GetState(transition), State::kPrepared);
+
+ transition->start();
+
+ EXPECT_EQ(GetState(transition), State::kStarted);
+ UpdateAllLifecyclePhasesAndSimulateCommit();
+
+ // TODO(vmpstr): This test relies on the fact that the commit callback will
+ // switch the state to kIdle. Long term, the state should only switch to
+ // kStarted here, and have a separate callback for when the transition is
+ // finished. When that happens, the expectations of this test should change.
+ EXPECT_EQ(GetState(transition), State::kIdle);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/DIR_METADATA b/chromium/third_party/blink/renderer/core/dom/DIR_METADATA
new file mode 100644
index 00000000000..347a1b0a71d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>DOM"
+}
+
+team_email: "dom-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/dom/OWNERS b/chromium/third_party/blink/renderer/core/dom/OWNERS
index 5f9506deb7c..9f2610d247f 100644
--- a/chromium/third_party/blink/renderer/core/dom/OWNERS
+++ b/chromium/third_party/blink/renderer/core/dom/OWNERS
@@ -4,6 +4,3 @@ per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
-
-# TEAM: dom-dev@chromium.org
-# COMPONENT: Blink>DOM
diff --git a/chromium/third_party/blink/renderer/core/dom/abstract_range.cc b/chromium/third_party/blink/renderer/core/dom/abstract_range.cc
new file mode 100644
index 00000000000..e7111b875b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/abstract_range.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/dom/abstract_range.h"
+
+namespace blink {
+
+AbstractRange::AbstractRange() = default;
+AbstractRange::~AbstractRange() = default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/abstract_range.h b/chromium/third_party/blink/renderer/core/dom/abstract_range.h
new file mode 100644
index 00000000000..bac6bb9efef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/abstract_range.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ABSTRACT_RANGE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ABSTRACT_RANGE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class Node;
+
+class CORE_EXPORT AbstractRange : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ virtual Node* startContainer() const = 0;
+ virtual unsigned startOffset() const = 0;
+ virtual Node* endContainer() const = 0;
+ virtual unsigned endOffset() const = 0;
+ virtual bool collapsed() const = 0;
+
+ protected:
+ AbstractRange();
+ ~AbstractRange() override;
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ABSTRACT_RANGE_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/abstract_range.idl b/chromium/third_party/blink/renderer/core/dom/abstract_range.idl
new file mode 100644
index 00000000000..a0ef599c2a7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/abstract_range.idl
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://dom.spec.whatwg.org/#interface-abstractrange
+
+[
+ Exposed=Window
+] interface AbstractRange {
+ readonly attribute Node startContainer;
+ readonly attribute unsigned long startOffset;
+ readonly attribute Node endContainer;
+ readonly attribute unsigned long endOffset;
+ readonly attribute boolean collapsed;
+};
diff --git a/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl b/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
index 9987d175edd..06aa9621094 100644
--- a/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
+++ b/chromium/third_party/blink/renderer/core/dom/aria_attributes.idl
@@ -46,6 +46,7 @@
[CEReactions, Reflect=aria_valuemin] attribute DOMString? ariaValueMin;
[CEReactions, Reflect=aria_valuenow] attribute DOMString? ariaValueNow;
[CEReactions, Reflect=aria_valuetext] attribute DOMString? ariaValueText;
+ [RuntimeEnabled=AccessibilityAriaVirtualContent, CEReactions, Reflect=aria_virtualcontent] attribute DOMString? ariaVirtualContent;
};
Element includes AriaAttributes;
diff --git a/chromium/third_party/blink/renderer/core/dom/attr.idl b/chromium/third_party/blink/renderer/core/dom/attr.idl
index 6ad8f016e73..cebf78eabf3 100644
--- a/chromium/third_party/blink/renderer/core/dom/attr.idl
+++ b/chromium/third_party/blink/renderer/core/dom/attr.idl
@@ -26,7 +26,7 @@
readonly attribute DOMString? prefix;
readonly attribute DOMString localName;
readonly attribute DOMString name;
- [RaisesException=Setter, CEReactions, CustomElementCallbacks] attribute DOMString value;
+ [RaisesException=Setter, CEReactions] attribute DOMString value;
readonly attribute Element? ownerElement;
diff --git a/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.cc b/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.cc
index 38a80e26eb8..243f202d35e 100644
--- a/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.cc
+++ b/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/event_type_names.h"
#include "third_party/blink/renderer/core/events/before_unload_event.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.h b/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.h
index 75586b00c18..c1342db24e2 100644
--- a/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.h
+++ b/chromium/third_party/blink/renderer/core/dom/beforeunload_event_listener.h
@@ -7,13 +7,13 @@
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
class Document;
class Event;
class ExecutionContext;
-class Visitor;
// Helper class used to setup beforeunload listener for certain documents which
// include plugins that are handled externally and need user verification before
diff --git a/chromium/third_party/blink/renderer/core/dom/build.gni b/chromium/third_party/blink/renderer/core/dom/build.gni
index cfee1972491..eaa501d85e5 100644
--- a/chromium/third_party/blink/renderer/core/dom/build.gni
+++ b/chromium/third_party/blink/renderer/core/dom/build.gni
@@ -35,6 +35,8 @@ blink_core_sources_dom = [
"abort_controller.h",
"abort_signal.cc",
"abort_signal.h",
+ "abstract_range.cc",
+ "abstract_range.h",
"attr.cc",
"attr.h",
"attribute.h",
@@ -68,8 +70,6 @@ blink_core_sources_dom = [
"dataset_dom_string_map.h",
"decoded_data_document_parser.cc",
"decoded_data_document_parser.h",
- "distributed_nodes.cc",
- "distributed_nodes.h",
"document.cc",
"document.h",
"document_and_element_event_handlers.h",
@@ -247,8 +247,6 @@ blink_core_sources_dom = [
"scripted_idle_task_controller.h",
"shadow_root.cc",
"shadow_root.h",
- "shadow_root_v0.cc",
- "shadow_root_v0.h",
"sink_document.cc",
"sink_document.h",
"slot_assignment.cc",
@@ -287,8 +285,6 @@ blink_core_sources_dom = [
"tree_walker.h",
"user_action_element_set.cc",
"user_action_element_set.h",
- "v0_insertion_point.cc",
- "v0_insertion_point.h",
"visited_link_state.cc",
"visited_link_state.h",
"weak_identifier_map.h",
@@ -297,3 +293,35 @@ blink_core_sources_dom = [
"xml_document.cc",
"xml_document.h",
]
+
+blink_core_tests_dom = [
+ "attr_test.cc",
+ "document_statistics_collector_test.cc",
+ "document_test.cc",
+ "dom_node_ids_test.cc",
+ "element_test.cc",
+ "events/event_path_test.cc",
+ "events/event_target_test.cc",
+ "events/listener_leak_test.cc",
+ "first_letter_pseudo_element_test.cc",
+ "flat_tree_traversal_test.cc",
+ "idle_deadline_test.cc",
+ "layout_tree_builder_traversal_test.cc",
+ "live_node_list_registry_test.cc",
+ "mutation_observer_test.cc",
+ "names_map_test.cc",
+ "node_test.cc",
+ "nth_index_cache_test.cc",
+ "range_test.cc",
+ "scripted_animation_controller_test.cc",
+ "scripted_idle_task_controller_test.cc",
+ "slot_assignment_test.cc",
+ "space_split_string_test.cc",
+ "static_range_test.cc",
+ "text_test.cc",
+ "tree_ordered_map_test.cc",
+ "tree_scope_adopter_test.cc",
+ "tree_scope_test.cc",
+ "weak_identifier_map_test.cc",
+ "whitespace_attacher_test.cc",
+]
diff --git a/chromium/third_party/blink/renderer/core/dom/character_data.cc b/chromium/third_party/blink/renderer/core/dom/character_data.cc
index 55a99d7eb1c..07fd4c0724a 100644
--- a/chromium/third_party/blink/renderer/core/dom/character_data.cc
+++ b/chromium/third_party/blink/renderer/core/dom/character_data.cc
@@ -234,7 +234,8 @@ void CharacterData::DidModifyData(const String& old_data, UpdateSource source) {
this,
previousSibling(),
nextSibling(),
- nullptr};
+ {},
+ old_data};
parentNode()->ChildrenChanged(change);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/child_node.idl b/chromium/third_party/blink/renderer/core/dom/child_node.idl
index 38bc7fec1ce..fd58ee2c685 100644
--- a/chromium/third_party/blink/renderer/core/dom/child_node.idl
+++ b/chromium/third_party/blink/renderer/core/dom/child_node.idl
@@ -25,8 +25,8 @@
[
LegacyTreatAsPartialInterface
] interface mixin ChildNode {
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void before((Node or DOMString or TrustedScript) ... nodes);
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void after((Node or DOMString or TrustedScript)... nodes);
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void replaceWith((Node or DOMString or TrustedScript)... nodes);
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void remove();
+ [Unscopable, RaisesException, CEReactions] void before((Node or DOMString or TrustedScript) ... nodes);
+ [Unscopable, RaisesException, CEReactions] void after((Node or DOMString or TrustedScript)... nodes);
+ [Unscopable, RaisesException, CEReactions] void replaceWith((Node or DOMString or TrustedScript)... nodes);
+ [Unscopable, RaisesException, CEReactions] void remove();
};
diff --git a/chromium/third_party/blink/renderer/core/dom/container_node.cc b/chromium/third_party/blink/renderer/core/dom/container_node.cc
index d336d0ce494..ba6cc662704 100644
--- a/chromium/third_party/blink/renderer/core/dom/container_node.cc
+++ b/chromium/third_party/blink/renderer/core/dom/container_node.cc
@@ -326,7 +326,7 @@ void ContainerNode::InsertNodeVector(
Node& child = *target_node;
mutator(*this, child, next);
ChildListMutationScope(*this).ChildAdded(child);
- if (GetDocument().ContainsV1ShadowTree())
+ if (GetDocument().ContainsShadowTree())
child.CheckSlotChangeAfterInserted();
probe::DidInsertDOMNode(&child);
NotifyNodeInsertedInternal(child, *post_insertion_notification_targets);
@@ -814,11 +814,8 @@ void ContainerNode::RemoveChildren(SubtreeModificationAction action) {
GetDocument().NodeChildrenWillBeRemoved(*this);
}
- HeapVector<Member<Node>>* removed_nodes = nullptr;
- if (ChildrenChangedAllChildrenRemovedNeedsList()) {
- removed_nodes =
- MakeGarbageCollected<HeapVector<Member<Node>>>(CountChildren());
- }
+ HeapVector<Member<Node>> removed_nodes;
+ const bool children_changed = ChildrenChangedAllChildrenRemovedNeedsList();
{
HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
TreeOrderedMap::RemoveScope tree_remove_scope;
@@ -831,8 +828,8 @@ void ContainerNode::RemoveChildren(SubtreeModificationAction action) {
while (Node* child = first_child_) {
RemoveBetween(nullptr, child->nextSibling(), *child);
NotifyNodeRemoved(*child);
- if (removed_nodes)
- removed_nodes->push_back(child);
+ if (children_changed)
+ removed_nodes.push_back(child);
}
}
@@ -841,7 +838,8 @@ void ContainerNode::RemoveChildren(SubtreeModificationAction action) {
nullptr,
nullptr,
nullptr,
- removed_nodes};
+ std::move(removed_nodes),
+ String()};
ChildrenChanged(change);
}
@@ -923,7 +921,7 @@ void ContainerNode::NotifyNodeInserted(Node& root,
#endif
DCHECK(!root.IsShadowRoot());
- if (GetDocument().ContainsV1ShadowTree())
+ if (GetDocument().ContainsShadowTree())
root.CheckSlotChangeAfterInserted();
probe::DidInsertDOMNode(&root);
@@ -1347,7 +1345,9 @@ void ContainerNode::SetRestyleFlag(DynamicRestyleFlags mask) {
EnsureRareData().SetRestyleFlag(mask);
}
-void ContainerNode::RecalcDescendantStyles(const StyleRecalcChange change) {
+void ContainerNode::RecalcDescendantStyles(
+ const StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(GetDocument().InStyleRecalc());
DCHECK(!NeedsStyleRecalc());
@@ -1358,7 +1358,7 @@ void ContainerNode::RecalcDescendantStyles(const StyleRecalcChange change) {
child_text_node->RecalcTextStyle(change);
if (auto* child_element = DynamicTo<Element>(child))
- child_element->RecalcStyle(change);
+ child_element->RecalcStyle(change, style_recalc_context);
}
}
@@ -1387,12 +1387,9 @@ void ContainerNode::RebuildChildrenLayoutTrees(
WhitespaceAttacher& whitespace_attacher) {
DCHECK(!NeedsReattachLayoutTree());
- if (IsActiveSlotOrActiveV0InsertionPoint()) {
+ if (IsActiveSlot()) {
if (auto* slot = DynamicTo<HTMLSlotElement>(this)) {
slot->RebuildDistributedChildrenLayoutTrees(whitespace_attacher);
- } else {
- To<V0InsertionPoint>(this)->RebuildDistributedChildrenLayoutTrees(
- whitespace_attacher);
}
return;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/container_node.h b/chromium/third_party/blink/renderer/core/dom/container_node.h
index 6fddfe3a236..4bb881c2a01 100644
--- a/chromium/third_party/blink/renderer/core/dom/container_node.h
+++ b/chromium/third_party/blink/renderer/core/dom/container_node.h
@@ -40,6 +40,7 @@ class Element;
class ExceptionState;
class HTMLCollection;
class RadioNodeList;
+class StyleRecalcContext;
class WhitespaceAttacher;
using StaticElementList = StaticNodeTypeList<Element>;
@@ -92,6 +93,7 @@ class CORE_EXPORT ContainerNode : public Node {
Node* firstChild() const { return first_child_; }
Node* lastChild() const { return last_child_; }
+ bool hasChildren() const { return first_child_; }
bool HasChildren() const { return first_child_; }
bool HasOneChild() const {
@@ -286,7 +288,8 @@ class CORE_EXPORT ContainerNode : public Node {
Element* changed_element,
Node* node_before_change,
Node* node_after_change);
- void RecalcDescendantStyles(const StyleRecalcChange);
+ void RecalcDescendantStyles(const StyleRecalcChange,
+ const StyleRecalcContext&);
void RebuildChildrenLayoutTrees(WhitespaceAttacher&);
void RebuildLayoutTreeForChild(Node* child, WhitespaceAttacher&);
@@ -318,7 +321,8 @@ class CORE_EXPORT ContainerNode : public Node {
&node,
unchanged_previous,
unchanged_next,
- nullptr};
+ {},
+ String()};
return change;
}
@@ -333,7 +337,8 @@ class CORE_EXPORT ContainerNode : public Node {
&node,
previous_sibling,
next_sibling,
- nullptr};
+ {},
+ String()};
return change;
}
@@ -367,9 +372,11 @@ class CORE_EXPORT ContainerNode : public Node {
// - nextSibling of the last inserted node after multiple node insertion.
Node* sibling_after_change = nullptr;
// List of removed nodes for ChildrenChangeType::kAllChildrenRemoved.
- // This is available only if ChildrenChangedAllChildrenRemovedNeedsList()
- // returns true.
- HeapVector<Member<Node>>* removed_nodes;
+ // Only populated if ChildrenChangedAllChildrenRemovedNeedsList() returns
+ // true.
+ HeapVector<Member<Node>> removed_nodes;
+ // |old_text| is mostly empty, only used for text node changes.
+ const String& old_text;
};
// Notifies the node that it's list of children have changed (either by adding
diff --git a/chromium/third_party/blink/renderer/core/dom/create_element_flags.h b/chromium/third_party/blink/renderer/core/dom/create_element_flags.h
index dcabf7adf44..4163a2a51c1 100644
--- a/chromium/third_party/blink/renderer/core/dom/create_element_flags.h
+++ b/chromium/third_party/blink/renderer/core/dom/create_element_flags.h
@@ -18,8 +18,7 @@ class CreateElementFlags {
bool IsCreatedByParser() const { return created_by_parser_; }
Document* ParserDocument() const { return parser_document_; }
bool IsAsyncCustomElements() const { return async_custom_elements_; }
- bool IsCustomElementsV1() const { return custom_elements_v1_; }
- bool IsCustomElementsV0() const { return custom_elements_v0_; }
+ bool IsCustomElements() const { return custom_elements_; }
bool WasAlreadyStarted() const { return already_started_; }
// https://html.spec.whatwg.org/C/#create-an-element-for-the-token
@@ -34,12 +33,6 @@ class CreateElementFlags {
// https://dom.spec.whatwg.org/#dom-document-createelement
static CreateElementFlags ByCreateElement() { return CreateElementFlags(); }
- static CreateElementFlags ByCreateElementV1() {
- return CreateElementFlags().SetCustomElementsV1Only();
- }
- static CreateElementFlags ByCreateElementV0() {
- return CreateElementFlags().SetCustomElementsV0Only();
- }
// https://html.spec.whatwg.org/C/#create-an-element-for-the-token
static CreateElementFlags ByFragmentParser(Document* document) {
@@ -52,8 +45,7 @@ class CreateElementFlags {
CreateElementFlags()
: created_by_parser_(false),
async_custom_elements_(false),
- custom_elements_v1_(true),
- custom_elements_v0_(true),
+ custom_elements_(true),
already_started_(false) {}
CreateElementFlags& SetCreatedByParser(bool flag, Document* document) {
@@ -75,18 +67,6 @@ class CreateElementFlags {
return *this;
}
- CreateElementFlags& SetCustomElementsV1Only() {
- custom_elements_v1_ = true;
- custom_elements_v0_ = false;
- return *this;
- }
-
- CreateElementFlags& SetCustomElementsV0Only() {
- custom_elements_v0_ = true;
- custom_elements_v1_ = false;
- return *this;
- }
-
bool created_by_parser_ : 1;
// This implements the HTML Standard concept of a "parser document" [1].
// Contrary to the spec, this member can be null even when
@@ -101,8 +81,7 @@ class CreateElementFlags {
Document* parser_document_;
bool async_custom_elements_ : 1;
- bool custom_elements_v1_ : 1;
- bool custom_elements_v0_ : 1;
+ bool custom_elements_ : 1;
bool already_started_ : 1;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc
deleted file mode 100644
index 0119b90fef4..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/dom/distributed_nodes.h"
-
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-
-namespace blink {
-
-void DistributedNodes::Swap(DistributedNodes& other) {
- nodes_.swap(other.nodes_);
- indices_.swap(other.indices_);
-}
-
-void DistributedNodes::Append(Node* node) {
- DCHECK(node);
- DCHECK(node->CanParticipateInFlatTree());
- wtf_size_t size = nodes_.size();
- indices_.Set(node, size);
- nodes_.push_back(node);
-}
-
-wtf_size_t DistributedNodes::Find(const Node* node) const {
- HeapHashMap<Member<const Node>, wtf_size_t>::const_iterator it =
- indices_.find(node);
- if (it == indices_.end())
- return kNotFound;
-
- return it.Get()->value;
-}
-
-Node* DistributedNodes::NextTo(const Node* node) const {
- wtf_size_t index = Find(node);
- if (index == kNotFound || index + 1 == size())
- return nullptr;
- return at(index + 1);
-}
-
-Node* DistributedNodes::PreviousTo(const Node* node) const {
- wtf_size_t index = Find(node);
- if (index == kNotFound || !index)
- return nullptr;
- return at(index - 1);
-}
-
-void DistributedNodes::Trace(Visitor* visitor) const {
- visitor->Trace(nodes_);
- visitor->Trace(indices_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h b/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h
deleted file mode 100644
index b649acccf2e..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/distributed_nodes.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DISTRIBUTED_NODES_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DISTRIBUTED_NODES_H_
-
-#include "third_party/blink/renderer/core/dom/node.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class DistributedNodes final {
- DISALLOW_NEW();
-
- public:
- DistributedNodes() = default;
-
- Node* First() const { return nodes_.front(); }
- Node* Last() const { return nodes_.back(); }
- Node* at(wtf_size_t index) const { return nodes_.at(index); }
-
- wtf_size_t size() const { return nodes_.size(); }
- bool IsEmpty() const { return nodes_.IsEmpty(); }
-
- void Append(Node*);
- void Clear() {
- nodes_.clear();
- indices_.clear();
- }
- void ShrinkToFit() { nodes_.ShrinkToFit(); }
-
- bool Contains(const Node* node) const { return indices_.Contains(node); }
- wtf_size_t Find(const Node*) const;
- Node* NextTo(const Node*) const;
- Node* PreviousTo(const Node*) const;
-
- void Swap(DistributedNodes& other);
-
- void Trace(Visitor*) const;
-
- private:
- HeapVector<Member<Node>> nodes_;
- HeapHashMap<Member<const Node>, wtf_size_t> indices_;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/dom/document.cc b/chromium/third_party/blink/renderer/core/dom/document.cc
index 5f48e26bfde..c067ee55319 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document.cc
@@ -33,12 +33,13 @@
// instead of including more headers. If that is infeasible, adjust the limit.
// For more info, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 1000000
+#pragma clang max_tokens_here 1010000
#include <memory>
#include <utility>
#include "base/auto_reset.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/optional.h"
@@ -52,6 +53,7 @@
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
@@ -67,7 +69,6 @@
#include "third_party/blink/public/mojom/page_state/page_state.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_battery_savings.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/public/web/web_print_page_description.h"
@@ -78,9 +79,9 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_element_creation_options.h"
-#include "third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_element_creation_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_element_registration_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_interest_cohort.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
#include "third_party/blink/renderer/core/accessibility/ax_context.h"
@@ -187,6 +188,7 @@
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/anchor_element_metrics.h"
+#include "third_party/blink/renderer/core/html/battery_savings.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_font_cache.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
@@ -194,8 +196,6 @@
#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_descriptor.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/document_all_name_collection.h"
#include "third_party/blink/renderer/core/html/document_name_collection.h"
#include "third_party/blink/renderer/core/html/forms/email_input_type.h"
@@ -216,6 +216,7 @@
#include "third_party/blink/renderer/core/html/html_meta_element.h"
#include "third_party/blink/renderer/core/html/html_object_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
+#include "third_party/blink/renderer/core/html/html_popup_element.h"
#include "third_party/blink/renderer/core/html/html_script_element.h"
#include "third_party/blink/renderer/core/html/html_title_element.h"
#include "third_party/blink/renderer/core/html/html_unknown_element.h"
@@ -255,7 +256,7 @@
#include "third_party/blink/renderer/core/loader/http_refresh_scheduler.h"
#include "third_party/blink/renderer/core/loader/idleness_detector.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/loader/prerenderer_client.h"
+#include "third_party/blink/renderer/core/loader/no_state_prefetch_client.h"
#include "third_party/blink/renderer/core/loader/progress_tracker.h"
#include "third_party/blink/renderer/core/mathml/mathml_element.h"
#include "third_party/blink/renderer/core/mathml/mathml_row_element.h"
@@ -414,69 +415,6 @@ bool DefaultFaviconAllowedByCSP(const Document* document, const IconURL& icon) {
} // namespace
-class DocumentOutliveTimeReporter : public BlinkGCObserver {
- public:
- explicit DocumentOutliveTimeReporter(Document* document)
- : BlinkGCObserver(ThreadState::Current()), document_(document) {}
-
- ~DocumentOutliveTimeReporter() override {
- // As not all documents are destroyed before the process dies, this might
- // miss some long-lived documents or leaked documents.
- UMA_HISTOGRAM_EXACT_LINEAR(
- "Document.OutliveTimeAfterShutdown.DestroyedBeforeProcessDies",
- GetOutliveTimeCount() + 1, 101);
- }
-
- void OnCompleteSweepDone() override {
- enum GCCount {
- kGCCount5,
- kGCCount10,
- kGCCountMax,
- };
-
- // There are some cases that a document can live after shutting down because
- // the document can still be referenced (e.g. a document opened via
- // window.open can be referenced by the opener even after shutting down). To
- // avoid such cases as much as possible, outlive time count is started after
- // all DomWrapper of the document have disappeared.
- if (!gc_age_when_document_detached_) {
- if (document_->domWindow() &&
- DOMWrapperWorld::HasWrapperInAnyWorldInMainThread(
- document_->domWindow())) {
- return;
- }
- gc_age_when_document_detached_ = ThreadState::Current()->GcAge();
- }
-
- int outlive_time_count = GetOutliveTimeCount();
- if (outlive_time_count == 5 || outlive_time_count == 10) {
- const char* kUMAString = "Document.OutliveTimeAfterShutdown.GCCount";
-
- if (outlive_time_count == 5)
- UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount5, kGCCountMax);
- else if (outlive_time_count == 10)
- UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount10, kGCCountMax);
- else
- NOTREACHED();
- }
-
- if (outlive_time_count == 5 || outlive_time_count == 10 ||
- outlive_time_count == 20 || outlive_time_count == 50) {
- document_->RecordUkmOutliveTimeAfterShutdown(outlive_time_count);
- }
- }
-
- private:
- int GetOutliveTimeCount() const {
- if (!gc_age_when_document_detached_)
- return 0;
- return ThreadState::Current()->GcAge() - gc_age_when_document_detached_;
- }
-
- WeakPersistent<Document> document_;
- int gc_age_when_document_detached_ = 0;
-};
-
static const unsigned kCMaxWriteRecursionDepth = 21;
// This amount of time must have elapsed before we will even consider scheduling
@@ -705,6 +643,7 @@ Document::Document(const DocumentInit& initializer,
: ContainerNode(nullptr, kCreateDocument),
TreeScope(*this),
is_initial_empty_document_(initializer.IsInitialEmptyDocument()),
+ is_prerendering_(initializer.IsPrerendering()),
evaluate_media_queries_on_style_recalc_(false),
pending_sheet_layout_(kNoLayoutWithPendingSheets),
dom_window_(initializer.GetWindow()),
@@ -782,7 +721,6 @@ Document::Document(const DocumentInit& initializer,
write_recursion_depth_(0),
scripted_animation_controller_(
MakeGarbageCollected<ScriptedAnimationController>(domWindow())),
- registration_context_(initializer.RegistrationContext(this)),
element_data_cache_clear_timer_(
GetTaskRunner(TaskType::kInternalUserInteraction),
this,
@@ -813,7 +751,6 @@ Document::Document(const DocumentInit& initializer,
ukm_source_id_(initializer.UkmSourceId() == ukm::kInvalidSourceId
? ukm::UkmRecorder::GetNewSourceID()
: initializer.UkmSourceId()),
- needs_to_record_ukm_outlive_time_(false),
viewport_data_(MakeGarbageCollected<ViewportData>(*this)),
is_for_external_handler_(initializer.IsForExternalHandler()),
fragment_directive_(MakeGarbageCollected<FragmentDirective>()),
@@ -826,9 +763,6 @@ Document::Document(const DocumentInit& initializer,
ProvideContextFeaturesToDocumentFrom(*this, *GetFrame()->GetPage());
fetcher_ = FrameFetchContext::CreateFetcherForCommittedDocument(
*GetFrame()->Loader().GetDocumentLoader(), *this);
- CustomElementRegistry* registry = dom_window_->MaybeCustomElements();
- if (registry && registration_context_)
- registry->Entangle(registration_context_);
cookie_jar_ = MakeGarbageCollected<CookieJar>(this);
} else {
// We disable fetches for frame-less Documents, including HTML-imported
@@ -838,11 +772,12 @@ Document::Document(const DocumentInit& initializer,
auto& properties =
*MakeGarbageCollected<DetachableResourceFetcherProperties>(
*MakeGarbageCollected<NullResourceFetcherProperties>());
- fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties, &FetchContext::NullInstance(),
- GetTaskRunner(TaskType::kNetworking),
- GetTaskRunner(TaskType::kNetworkingUnfreezable),
- nullptr /* loader_factory */, GetExecutionContext()));
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(properties, &FetchContext::NullInstance(),
+ GetTaskRunner(TaskType::kNetworking),
+ GetTaskRunner(TaskType::kNetworkingUnfreezable),
+ nullptr /* loader_factory */, GetExecutionContext(),
+ nullptr /* back_forward_cache_loader_helper */));
if (imports_controller_) {
// We don't expect the fetcher to be used, so count such unexpected use.
@@ -874,7 +809,7 @@ Document::Document(const DocumentInit& initializer,
is_vertical_scroll_enforced_ =
GetFrame() && !GetFrame()->IsMainFrame() &&
- RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+ RuntimeEnabledFeatures::ExperimentalPoliciesEnabled() &&
!dom_window_->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kVerticalScroll);
@@ -884,13 +819,13 @@ Document::Document(const DocumentInit& initializer,
lifecycle_.AdvanceTo(DocumentLifecycle::kInactive);
- UpdateForcedColors();
-
// Since CSSFontSelector requires Document::fetcher_ and StyleEngine owns
// CSSFontSelector, need to initialize |style_engine_| after initializing
// |fetcher_|.
style_engine_ = MakeGarbageCollected<StyleEngine>(*this);
+ UpdateForcedColors();
+
// The parent's parser should be suspended together with all the other
// objects, else this new Document would have a new ExecutionContext which
// suspended state would not match the one from the parent, and could start
@@ -1109,8 +1044,6 @@ Element* Document::CreateElementForBinding(const AtomicString& name,
return element;
QualifiedName q_name(g_null_atom, local_name,
html_names::xhtmlNamespaceURI);
- if (RegistrationContext() && V0CustomElement::IsValidName(local_name))
- return RegistrationContext()->CreateCustomTagElement(*this, q_name);
return MakeGarbageCollected<HTMLUnknownElement>(q_name, *this);
}
return MakeGarbageCollected<Element>(
@@ -1163,27 +1096,16 @@ Element* Document::CreateElementForBinding(
? html_names::xhtmlNamespaceURI
: g_null_atom);
- bool is_v1 =
- string_or_options.IsElementCreationOptions() || !RegistrationContext();
- // V0 is only allowed with the flag.
- DCHECK(is_v1 || RuntimeEnabledFeatures::CustomElementsV0Enabled());
- bool create_v1_builtin = string_or_options.IsElementCreationOptions();
- bool should_create_builtin =
- create_v1_builtin || string_or_options.IsString();
+ bool create_builtin = string_or_options.IsElementCreationOptions() ||
+ string_or_options.IsString();
// 3.
const AtomicString& is = GetTypeExtension(this, string_or_options);
// 5. Let element be the result of creating an element given ...
Element* element =
- CreateElement(q_name,
- is_v1 ? CreateElementFlags::ByCreateElementV1()
- : CreateElementFlags::ByCreateElementV0(),
- should_create_builtin ? is : g_null_atom);
-
- // 8. If 'is' is non-null, set 'is' attribute
- if (!is_v1 && !is.IsEmpty())
- element->setAttribute(html_names::kIsAttr, is);
+ CreateElement(q_name, CreateElementFlags::ByCreateElement(),
+ create_builtin ? is : g_null_atom);
return element;
}
@@ -1221,8 +1143,6 @@ Element* Document::createElementNS(const AtomicString& namespace_uri,
CreateElementFlags flags = CreateElementFlags::ByCreateElement();
if (CustomElement::ShouldCreateCustomElement(q_name))
return CustomElement::CreateCustomElement(*this, q_name, flags);
- if (RegistrationContext() && V0CustomElement::IsValidName(q_name.LocalName()))
- return RegistrationContext()->CreateCustomTagElement(*this, q_name);
return CreateRawElement(q_name, flags);
}
@@ -1241,13 +1161,8 @@ Element* Document::createElementNS(
if (q_name == QualifiedName::Null())
return nullptr;
- bool is_v1 =
- string_or_options.IsElementCreationOptions() || !RegistrationContext();
- // V0 is only allowed with the flag.
- DCHECK(is_v1 || RuntimeEnabledFeatures::CustomElementsV0Enabled());
- bool create_v1_builtin = string_or_options.IsElementCreationOptions();
- bool should_create_builtin =
- create_v1_builtin || string_or_options.IsString();
+ bool create_builtin = string_or_options.IsElementCreationOptions() ||
+ string_or_options.IsString();
// 2.
const AtomicString& is = GetTypeExtension(this, string_or_options);
@@ -1262,14 +1177,8 @@ Element* Document::createElementNS(
// 3. Let element be the result of creating an element
Element* element =
- CreateElement(q_name,
- is_v1 ? CreateElementFlags::ByCreateElementV1()
- : CreateElementFlags::ByCreateElementV0(),
- should_create_builtin ? is : g_null_atom);
-
- // 4. If 'is' is non-null, set 'is' attribute
- if (!is_v1 && !is.IsEmpty())
- element->setAttribute(html_names::kIsAttr, is);
+ CreateElement(q_name, CreateElementFlags::ByCreateElement(),
+ create_builtin ? is : g_null_atom);
return element;
}
@@ -1280,7 +1189,7 @@ Element* Document::CreateElement(const QualifiedName& q_name,
const CreateElementFlags flags,
const AtomicString& is) {
CustomElementDefinition* definition = nullptr;
- if (flags.IsCustomElementsV1() &&
+ if (flags.IsCustomElements() &&
q_name.NamespaceURI() == html_names::xhtmlNamespaceURI) {
const CustomElementDescriptor desc(is.IsNull() ? q_name.LocalName() : is,
q_name.LocalName());
@@ -1295,50 +1204,6 @@ Element* Document::CreateElement(const QualifiedName& q_name,
flags, is);
}
-ScriptValue Document::registerElement(ScriptState* script_state,
- const AtomicString& name,
- const ElementRegistrationOptions* options,
- ExceptionState& exception_state) {
- // TODO(crbug.com/937746): Anything caught by this DCHECK is using the
- // now-removed Custom Elements v0 API.
- DCHECK(false) << "Custom Elements v0 has been removed.";
-
- if (!RegistrationContext()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- "No element registration context is available.");
- return ScriptValue();
- }
-
- // Polymer V1 uses Custom Elements V0. <dom-module> is defined in its base
- // library and is a strong signal that this is a Polymer V1.
- // This counter is used to research how much users are affected once Custom
- // Element V0 is deprecated.
- if (name == "dom-module")
- UseCounter::Count(*this, WebFeature::kPolymerV1Detected);
-
- V0CustomElementConstructorBuilder constructor_builder(script_state, options);
- RegistrationContext()->RegisterElement(this, &constructor_builder, name,
- exception_state);
- if (exception_state.HadException())
- return ScriptValue();
- return constructor_builder.BindingsReturnValue();
-}
-
-V0CustomElementRegistrationContext* Document::RegistrationContext() const {
- if (RuntimeEnabledFeatures::CustomElementsV0Enabled())
- return registration_context_.Get();
- return nullptr;
-}
-
-V0CustomElementMicrotaskRunQueue* Document::CustomElementMicrotaskRunQueue() {
- if (!custom_element_microtask_run_queue_) {
- custom_element_microtask_run_queue_ =
- MakeGarbageCollected<V0CustomElementMicrotaskRunQueue>();
- }
- return custom_element_microtask_run_queue_.Get();
-}
-
void Document::ClearImportsController() {
fetcher_->ClearContext();
imports_controller_ = nullptr;
@@ -1909,9 +1774,9 @@ bool Document::IsPrefetchOnly() const {
if (!GetFrame() || !GetFrame()->GetPage())
return false;
- PrerendererClient* prerenderer_client =
- PrerendererClient::From(GetFrame()->GetPage());
- return prerenderer_client && prerenderer_client->IsPrefetchOnly();
+ NoStatePrefetchClient* no_state_prefetch_client =
+ NoStatePrefetchClient::From(GetFrame()->GetPage());
+ return no_state_prefetch_client && no_state_prefetch_client->IsPrefetchOnly();
}
AtomicString Document::visibilityState() const {
@@ -1931,6 +1796,13 @@ void Document::SetWasDiscarded(bool was_discarded) {
}
void Document::DidChangeVisibilityState() {
+ if (load_event_progress_ >= kUnloadVisibilityChangeInProgress) {
+ // It's possible to get here even after we've started unloading the document
+ // and dispatched the visibilitychange event, e.g. when we're closing a tab,
+ // where we would first try to dispatch unload events, and then close the
+ // tab and update the visibility state.
+ return;
+ }
DispatchEvent(*Event::CreateBubble(event_type_names::kVisibilitychange));
// Also send out the deprecated version until it can be removed.
DispatchEvent(
@@ -2076,6 +1948,8 @@ bool Document::ShouldScheduleLayoutTreeUpdate() const {
// recalc.
if (lifecycle_.GetState() == DocumentLifecycle::kInPreLayout)
return false;
+ if (lifecycle_.GetState() == DocumentLifecycle::kInPerformLayout)
+ return false;
if (!ShouldScheduleLayout())
return false;
return true;
@@ -2255,38 +2129,27 @@ void Document::PropagateStyleToViewport() {
}
}
- // TODO(954423, 952711): overscroll-behavior (and most likely
- // overflow-anchor) should be propagated from the document element and not
- // the viewport defining element.
+ // TODO(954423): overscroll-behavior (and most likely overflow-anchor)
+ // should be propagated from the document element and not the viewport
+ // defining element.
PROPAGATE_FROM(overflow_style, OverscrollBehaviorX, SetOverscrollBehaviorX,
EOverscrollBehavior::kAuto);
PROPAGATE_FROM(overflow_style, OverscrollBehaviorY, SetOverscrollBehaviorY,
EOverscrollBehavior::kAuto);
- // Counts any time scroll snapping and scroll padding break if we change its
- // viewport propagation logic. Scroll snapping only breaks if body has
- // non-none snap type that is different from the document one.
- // TODO(952711): Remove once propagation logic change is complete.
+ // Counts any time overscroll behavior break if we change its viewport
+ // propagation logic. Overscroll behavior only breaks if body has non-none
+ // type that is different from the document one.
+ // TODO(954423): Remove once propagation logic change is complete.
if (document_element_style && body_style) {
- bool snap_type_is_different =
- !body_style->GetScrollSnapType().is_none &&
- (body_style->GetScrollSnapType() !=
- document_element_style->GetScrollSnapType());
- bool scroll_padding_is_different =
- body_style->ScrollPaddingTop() !=
- document_element_style->ScrollPaddingTop() ||
- body_style->ScrollPaddingBottom() !=
- document_element_style->ScrollPaddingBottom() ||
- body_style->ScrollPaddingLeft() !=
- document_element_style->ScrollPaddingLeft() ||
- body_style->ScrollPaddingRight() !=
- document_element_style->ScrollPaddingRight();
-
- if (snap_type_is_different) {
- UseCounter::Count(*this, WebFeature::kScrollSnapOnViewportBreaks);
- }
- if (scroll_padding_is_different) {
- UseCounter::Count(*this, WebFeature::kScrollPaddingOnViewportBreaks);
+ bool overscroll_behavior_is_different =
+ body_style->OverscrollBehaviorX() !=
+ document_element_style->OverscrollBehaviorX() ||
+ body_style->OverscrollBehaviorY() !=
+ document_element_style->OverscrollBehaviorY();
+ if (overscroll_behavior_is_different) {
+ UseCounter::Count(*this,
+ WebFeature::kOversrollBehaviorOnViewportBreaks);
}
}
@@ -2370,7 +2233,6 @@ static void AssertNodeClean(const Node& node) {
DCHECK(!node.ChildNeedsStyleRecalc());
DCHECK(!node.NeedsReattachLayoutTree());
DCHECK(!node.ChildNeedsReattachLayoutTree());
- DCHECK(!node.ChildNeedsDistributionRecalc());
DCHECK(!node.NeedsStyleInvalidation());
DCHECK(!node.ChildNeedsStyleInvalidation());
DCHECK(!node.GetForceReattachLayoutTree());
@@ -2415,21 +2277,36 @@ static void AssertLayoutTreeUpdated(Node& root) {
void Document::UpdateStyleAndLayoutTree() {
DCHECK(IsMainThread());
- if (Lifecycle().LifecyclePostponed())
+ if (!IsActive() || !View() || View()->ShouldThrottleRendering() ||
+ Lifecycle().LifecyclePostponed()) {
return;
+ }
HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
ScriptForbiddenScope forbid_script;
- if (HTMLFrameOwnerElement* owner = LocalOwner()) {
+ if (HTMLFrameOwnerElement* owner = LocalOwner())
owner->GetDocument().UpdateStyleAndLayoutTree();
- }
- if (!View() || !IsActive())
- return;
+ UpdateStyleAndLayoutTreeForThisDocument();
+}
- if (View()->ShouldThrottleRendering())
+void Document::UpdateStyleAndLayoutTreeForThisDocument() {
+ DCHECK(IsMainThread());
+ if (!IsActive() || !View() || View()->ShouldThrottleRendering() ||
+ Lifecycle().LifecyclePostponed()) {
return;
+ }
+
+#if DCHECK_IS_ON()
+ if (HTMLFrameOwnerElement* owner = LocalOwner()) {
+ DCHECK(!owner->GetDocument()
+ .GetSlotAssignmentEngine()
+ .HasPendingSlotAssignmentRecalc());
+ DCHECK(!owner->GetDocument().NeedsLayoutTreeUpdate());
+ AssertLayoutTreeUpdated(owner->GetDocument());
+ }
+#endif
// RecalcSlotAssignments should be done before checking
// NeedsLayoutTreeUpdate().
@@ -2483,9 +2360,8 @@ void Document::UpdateStyleAndLayoutTree() {
EvaluateMediaQueryListIfNeeded();
UpdateUseShadowTreesIfNeeded();
- UpdateDistributionForLegacyDistributedNodes();
-
GetStyleEngine().UpdateActiveStyle();
+ GetStyleEngine().UpdateCounterStyles();
InvalidateStyleAndLayoutForFontUpdates();
UpdateStyleInvalidationIfNeeded();
UpdateStyle();
@@ -2541,7 +2417,7 @@ void Document::UpdateStyle() {
PropagateStyleToViewport();
- View()->UpdateCountersAfterStyleChange();
+ GetLayoutView()->UpdateMarkersAndCountersAfterStyleChange();
GetLayoutView()->RecalcLayoutOverflow();
DCHECK(!NeedsStyleRecalc());
@@ -2671,6 +2547,7 @@ void Document::UpdateStyleAndLayoutForNode(const Node* node,
}
void Document::ApplyScrollRestorationLogic() {
+ DCHECK(View());
// This function in not re-entrant. However, the places that invoke this are
// re-entrant. Specifically, UpdateStyleAndLayout() calls this, which in turn
// can do a find-in-page for the scroll-to-text feature, which can cause
@@ -2744,10 +2621,8 @@ void Document::ApplyScrollRestorationLogic() {
}
void Document::MarkHasFindInPageRequest() {
- // Note that although find-in-page requests happen in non-main frames, we only
- // record the main frame results (per UKM policy). Additionally, we only
- // record the event once.
- if (had_find_in_page_request_ || !IsInMainFrame())
+ // Only record the event once in a document.
+ if (had_find_in_page_request_)
return;
auto* recorder = UkmRecorder();
@@ -2760,10 +2635,8 @@ void Document::MarkHasFindInPageRequest() {
}
void Document::MarkHasFindInPageContentVisibilityActiveMatch() {
- // Note that although find-in-page in content-visibility requests happen in
- // non-main frames, we only record the main frame results (per UKM policy).
- // Additionally, we only record the event once.
- if (had_find_in_page_render_subtree_active_match_ || !IsInMainFrame())
+ // Only record the event once in a document.
+ if (had_find_in_page_render_subtree_active_match_)
return;
auto* recorder = UkmRecorder();
@@ -2777,11 +2650,8 @@ void Document::MarkHasFindInPageContentVisibilityActiveMatch() {
}
void Document::MarkHasFindInPageBeforematchExpandedHiddenMatchable() {
- // Note that although find-in-page in content-visibility requests happen in
- // non-main frames, we only record the main frame results (per UKM policy).
- // Additionally, we only record the event once.
- if (had_find_in_page_beforematch_expanded_hidden_matchable_ ||
- !IsInMainFrame())
+ // Only record the event once in a document.
+ if (had_find_in_page_beforematch_expanded_hidden_matchable_)
return;
auto* recorder = UkmRecorder();
@@ -2809,7 +2679,7 @@ void Document::UpdateStyleAndLayout(DocumentUpdateReason reason) {
if (HTMLFrameOwnerElement* owner = LocalOwner())
owner->GetDocument().UpdateStyleAndLayout(reason);
- UpdateStyleAndLayoutTree();
+ UpdateStyleAndLayoutTreeForThisDocument();
if (!IsActive()) {
if (reason != DocumentUpdateReason::kBeginMainFrame && frame_view)
@@ -2823,7 +2693,8 @@ void Document::UpdateStyleAndLayout(DocumentUpdateReason reason) {
if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
Lifecycle().AdvanceTo(DocumentLifecycle::kLayoutClean);
- ApplyScrollRestorationLogic();
+ if (frame_view)
+ ApplyScrollRestorationLogic();
if (LocalFrameView* frame_view_anchored = View())
frame_view_anchored->PerformScrollAnchoringAdjustments();
@@ -2926,24 +2797,6 @@ void Document::EnsurePaintLocationDataValidForNode(
// For all nodes we must have up-to-date style and have performed layout to do
// any location-based calculation.
UpdateStyleAndLayout(reason);
-
- // The location of elements that are position: sticky is not known until
- // compositing inputs are cleaned. Therefore, for any elements that are either
- // sticky or are in a sticky sub-tree (e.g. are affected by a sticky element),
- // we need to also clean compositing inputs.
- if (View() && node->GetLayoutObject() &&
- node->GetLayoutObject()->StyleRef().SubtreeIsSticky()) {
- bool success = false;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // In CAP, compositing inputs are cleaned as part of PrePaint.
- success = View()->UpdateAllLifecyclePhasesExceptPaint(reason);
- } else {
- success = View()->UpdateLifecycleToCompositingInputsClean(reason);
- }
- // The lifecycle update should always succeed, because forced lifecycles
- // from script are never throttled.
- DCHECK(success);
- }
}
bool Document::IsPageBoxVisible(uint32_t page_index) {
@@ -3172,9 +3025,6 @@ void Document::Shutdown() {
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
layout_view_->CleanUpCompositor();
- if (RegistrationContext())
- RegistrationContext()->DocumentWasDetached();
-
MutationObserver::CleanSlotChangeList(*this);
hover_element_ = nullptr;
@@ -3239,12 +3089,6 @@ void Document::Shutdown() {
lifecycle_.AdvanceTo(DocumentLifecycle::kStopped);
DCHECK(!View()->IsAttached());
- needs_to_record_ukm_outlive_time_ = IsInMainFrame();
- if (needs_to_record_ukm_outlive_time_) {
- // Ensure |ukm_recorder_| and |ukm_source_id_|.
- UkmRecorder();
- }
-
// Don't create a |ukm_recorder_| and |ukm_source_id_| unless necessary.
if (IdentifiabilityStudySettings::Get()->IsActive()) {
IdentifiabilitySampleCollector::Get()->FlushSource(UkmRecorder(),
@@ -3262,9 +3106,6 @@ void Document::Shutdown() {
// explicit in each of the callers of Document::detachLayoutTree().
dom_window_ = nullptr;
execution_context_ = nullptr;
-
- document_outlive_time_reporter_ =
- std::make_unique<DocumentOutliveTimeReporter>(this);
}
void Document::RemoveAllEventListeners() {
@@ -3392,6 +3233,8 @@ void Document::SetPrinting(PrintingState state) {
bool is_printing = Printing();
if (was_printing != is_printing) {
+ GetDisplayLockDocumentState().NotifyPrintingOrPreviewChanged();
+
// We force the color-scheme to light for printing.
ColorSchemeChanged();
// StyleResolver::InitialStyleForElement uses different zoom for printing.
@@ -3412,10 +3255,6 @@ void Document::SetPrinting(PrintingState state) {
}
}
-void Document::SetIsPaintingPreview(bool is_painting_preview) {
- is_painting_preview_ = is_painting_preview;
-}
-
// https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#document-open-steps
void Document::open(LocalDOMWindow* entered_window,
ExceptionState& exception_state) {
@@ -3476,29 +3315,55 @@ void Document::open(LocalDOMWindow* entered_window,
if (ignore_opens_and_writes_for_abort_)
return;
- // If this document is fully active, change |document|'s URL to the URL of the
- // responsible document specified by the entry settings object.
- if (dom_window_ && entered_window && dom_window_ != entered_window) {
- auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->CopyStateFrom(entered_window->GetContentSecurityPolicy());
- // We inherit the sandbox flags of the entered document, so mask on
- // the ones contained in the CSP.
- dom_window_->GetSecurityContext().ApplySandboxFlags(csp->GetSandboxMask());
- dom_window_->GetSecurityContext().SetContentSecurityPolicy(csp);
- dom_window_->GetContentSecurityPolicy()->BindToDelegate(
- dom_window_->GetContentSecurityPolicyDelegate());
+ // If this document is fully active, then run the URL and history update steps
+ // for this document with the entered window's url.
+ if (dom_window_ && entered_window) {
+ KURL new_url = entered_window->Url();
// Clear the hash fragment from the inherited URL to prevent a
// scroll-into-view for any document.open()'d frame.
- KURL new_url = entered_window->Url();
- new_url.SetFragmentIdentifier(String());
+ if (dom_window_ != entered_window)
+ new_url.SetFragmentIdentifier(String());
SetURL(new_url);
- if (Loader())
- Loader()->UpdateUrlForDocumentOpen(new_url);
- dom_window_->GetSecurityContext().SetSecurityOrigin(
- entered_window->GetMutableSecurityOrigin());
- dom_window_->SetReferrerPolicy(entered_window->GetReferrerPolicy());
- cookie_url_ = entered_window->document()->CookieURL();
+ auto* state_object = Loader()->GetHistoryItem()
+ ? Loader()->GetHistoryItem()->StateObject()
+ : nullptr;
+ Loader()->RunURLAndHistoryUpdateSteps(new_url, state_object);
+
+ if (dom_window_ != entered_window) {
+ auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
+ csp->CopyStateFrom(entered_window->GetContentSecurityPolicy());
+ // We inherit the sandbox flags of the entered document, so mask on
+ // the ones contained in the CSP. The operator| is a bitwise operation on
+ // the sandbox flags bits. It makes the sandbox policy stricter (or as
+ // strict) as both policy.
+ //
+ // TODO(arthursonzogni): Why merging sandbox flags?
+ // This doesn't look great at many levels:
+ // - The browser process won't be notified of the update.
+ // - The origin won't be made opaque, despite the new flags.
+ // - The sandbox flags of the document can't be considered to be an
+ // immutable property anymore.
+ //
+ // Ideally:
+ // - javascript-url document.
+ // - XSLT document.
+ // - document.open.
+ // should not mutate the security properties of the current document. From
+ // the browser process point of view, all of those operations are not
+ // considered to produce new documents. No IPCs are sent, it is as if it
+ // was a no-op.
+ dom_window_->GetSecurityContext().SetSandboxFlags(
+ dom_window_->GetSecurityContext().GetSandboxFlags() |
+ entered_window->GetSandboxFlags());
+ dom_window_->GetSecurityContext().SetContentSecurityPolicy(csp);
+ dom_window_->GetContentSecurityPolicy()->BindToDelegate(
+ dom_window_->GetContentSecurityPolicyDelegate());
+
+ dom_window_->GetSecurityContext().SetSecurityOrigin(
+ entered_window->GetMutableSecurityOrigin());
+ cookie_url_ = entered_window->document()->CookieURL();
+ }
}
open();
@@ -3970,20 +3835,11 @@ bool Document::CheckCompletedInternal() {
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kDocumentLoaded,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
GetFrame()->GetFrameScheduler()->OnLoad();
AnchorElementMetrics::NotifyOnLoad(*this);
DetectJavascriptFrameworksOnLoad(*this);
-
- // If this is a document associated with a resource loading hints based
- // preview, then record the resource loading hints UKM now that the load is
- // finished.
- PreviewsResourceLoadingHints* hints =
- Loader()->GetPreviewsResourceLoadingHints();
- if (hints) {
- hints->RecordUKM(UkmRecorder());
- }
}
if (auto* view = View()) {
@@ -4110,12 +3966,18 @@ bool Document::DispatchBeforeUnloadEvent(ChromeClient* chrome_client,
void Document::DispatchUnloadEvents(
SecurityOrigin* committing_origin,
base::Optional<Document::UnloadEventTiming>* unload_timing) {
+ // TODO(crbug.com/1161996): Remove this VLOG once the investigation is done.
+ VLOG(1) << "Document::DispatchUnloadEvents() URL = " << Url();
+
PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
PageDismissalScope in_page_dismissal;
if (parser_)
parser_->StopParsing();
if (load_event_progress_ == kLoadEventNotRun ||
+ // TODO(dcheng): We should consider if we can make this conditional check
+ // stronger with a DCHECK() that this isn't called if the unload event is
+ // already complete.
load_event_progress_ > kUnloadEventInProgress) {
return;
}
@@ -4182,6 +4044,9 @@ void Document::DispatchUnloadEvents(
GetFrame()->Loader().SaveScrollAnchor();
+ // TODO(crbug.com/1161996): Remove this VLOG once the investigation is done.
+ VLOG(1) << "Actually dispatching an UnloadEvent: URL = " << Url();
+
load_event_progress_ = kUnloadEventInProgress;
Event& unload_event = *Event::Create(event_type_names::kUnload);
const base::TimeTicks unload_event_start = base::TimeTicks::Now();
@@ -4195,13 +4060,10 @@ void Document::DispatchUnloadEvents(
("DocumentEventTiming.UnloadDuration", 0, 10000000, 50));
unload_histogram.CountMicroseconds(unload_event_end - unload_event_start);
- // Fill in the unload timing if the new document origin has access to
- // them.
- if (committing_origin->CanRequest(Url())) {
- auto& timing = unload_timing->emplace();
- timing.unload_event_start = unload_event_start;
- timing.unload_event_end = unload_event_end;
- }
+ auto& timing = unload_timing->emplace();
+ timing.can_request = committing_origin->CanRequest(Url());
+ timing.unload_event_start = unload_event_start;
+ timing.unload_event_end = unload_event_end;
}
load_event_progress_ = kUnloadEventHandled;
}
@@ -4948,8 +4810,7 @@ Document* Document::CloneDocumentWithoutChildren() const {
.WithURL(Url());
if (IsA<XMLDocument>(this)) {
if (IsXHTMLDocument())
- return XMLDocument::CreateXHTML(
- init.WithRegistrationContext(RegistrationContext()));
+ return XMLDocument::CreateXHTML(init);
return MakeGarbageCollected<XMLDocument>(init);
}
return MakeGarbageCollected<Document>(init);
@@ -5103,7 +4964,6 @@ bool Document::SetFocusedElement(Element* new_focused_element,
Element* old_focused_element = focused_element_;
focused_element_ = nullptr;
- UpdateDistributionForFlatTreeTraversal();
Node* ancestor = (old_focused_element && old_focused_element->isConnected() &&
new_focused_element)
? FlatTreeTraversal::CommonAncestor(*old_focused_element,
@@ -5120,7 +4980,8 @@ bool Document::SetFocusedElement(Element* new_focused_element,
// Dispatch the blur event and let the node do any other blur related
// activities (important for text fields)
// If page lost focus, blur event will have already been dispatched
- if (GetPage() && (GetPage()->GetFocusController().IsFocused())) {
+ if (!params.omit_blur_events && GetPage() &&
+ (GetPage()->GetFocusController().IsFocused())) {
old_focused_element->DispatchBlurEvent(new_focused_element, params.type,
params.source_capabilities);
if (focused_element_) {
@@ -5469,7 +5330,7 @@ void Document::NodeChildrenWillBeRemoved(ContainerNode& container) {
observer->NodeChildrenWillBeRemoved(container);
});
- if (ContainsV1ShadowTree()) {
+ if (ContainsShadowTree()) {
for (Node& n : NodeTraversal::ChildrenOf(container))
n.CheckSlotChangeBeforeRemoved();
}
@@ -5490,7 +5351,7 @@ void Document::NodeWillBeRemoved(Node& n) {
observer->NodeWillBeRemoved(n);
});
- if (ContainsV1ShadowTree())
+ if (ContainsShadowTree())
n.CheckSlotChangeBeforeRemoved();
if (n.InActiveDocument())
@@ -5897,7 +5758,7 @@ void Document::setDomain(const String& raw_domain,
}
const String feature_policy_error =
- "Setting `document.domain` is disabled by Feature Policy.";
+ "Setting `document.domain` is disabled by permissions policy.";
if (!dom_window_->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kDocumentDomain,
ReportOptions::kReportOnFailure, feature_policy_error)) {
@@ -5905,6 +5766,14 @@ void Document::setDomain(const String& raw_domain,
return;
}
+ const String document_policy_error =
+ "Setting `document.domain` is disabled by document policy.";
+ if (!dom_window_->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kDocumentDomain,
+ ReportOptions::kReportOnFailure, document_policy_error)) {
+ return;
+ }
+
if (dom_window_->IsSandboxed(
network::mojom::blink::WebSandboxFlags::kDocumentDomain)) {
exception_state.ThrowSecurityError(
@@ -5954,23 +5823,28 @@ void Document::setDomain(const String& raw_domain,
return;
}
- if (RuntimeEnabledFeatures::OriginIsolationHeaderEnabled(dom_window_) &&
- dom_window_->GetAgent()->IsOriginIsolated()) {
+ // We technically only need to IsOriginKeyed(), as IsCrossOriginIsolated()
+ // implies IsOriginKeyed(). (The spec only checks "is origin-keyed".) But,
+ // we'll check both, in order to give warning messages that are more specific
+ // about the cause. Note: this means the order of the checks is important.
+
+ if (RuntimeEnabledFeatures::CrossOriginIsolationEnabled() &&
+ Agent::IsCrossOriginIsolated()) {
AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kSecurity,
mojom::blink::ConsoleMessageLevel::kWarning,
"document.domain mutation is ignored because the surrounding agent "
- "cluster is origin-isolated."));
+ "cluster is cross-origin isolated."));
return;
}
- if (RuntimeEnabledFeatures::CrossOriginIsolationEnabled() &&
- Agent::IsCrossOriginIsolated()) {
+ if (RuntimeEnabledFeatures::OriginIsolationHeaderEnabled(dom_window_) &&
+ dom_window_->GetAgent()->IsOriginKeyed()) {
AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kSecurity,
mojom::blink::ConsoleMessageLevel::kWarning,
"document.domain mutation is ignored because the surrounding agent "
- "cluster is cross-origin isolated."));
+ "cluster is origin-keyed."));
return;
}
@@ -6096,11 +5970,8 @@ net::SiteForCookies Document::SiteForCookies() const {
while (current_frame) {
const url::Origin cur_security_origin =
current_frame->GetSecurityContext()->GetSecurityOrigin()->ToUrlOrigin();
- if (!candidate.IsEquivalent(
- net::SiteForCookies::FromOrigin(cur_security_origin))) {
- return net::SiteForCookies();
- }
- candidate.MarkIfCrossScheme(cur_security_origin);
+ if (!candidate.CompareWithFrameTreeOriginAndRevise(cur_security_origin))
+ return candidate;
current_frame = current_frame->Tree().Parent();
}
@@ -6358,7 +6229,24 @@ mojom::blink::FlocService* Document::GetFlocService(
return data_->floc_service_.get();
}
-ScriptPromise Document::interestCohort(ScriptState* script_state) {
+ScriptPromise Document::interestCohort(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (!GetFrame()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidAccessError,
+ "A browsing context is required when calling document.interestCohort.");
+ return ScriptPromise();
+ }
+
+ if (!GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kInterestCohort)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidAccessError,
+ "The \"interest-cohort\" Permissions Policy denied the use of "
+ "document.interestCohort.");
+ return ScriptPromise();
+ }
+
ScriptPromiseResolver* resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -6367,14 +6255,26 @@ ScriptPromise Document::interestCohort(ScriptState* script_state) {
GetFlocService(ExecutionContext::From(script_state))
->GetInterestCohort(WTF::Bind(
[](ScriptPromiseResolver* resolver, Document* document,
- const String& interest_cohort) {
+ mojom::blink::InterestCohortPtr interest_cohort) {
DCHECK(resolver);
DCHECK(document);
- if (interest_cohort.IsEmpty()) {
- resolver->Reject();
+ if (interest_cohort->version.IsEmpty()) {
+ ScriptState* state = resolver->GetScriptState();
+ ScriptState::Scope scope(state);
+
+ // TODO(yaoxia): Distinguish between the different causes.
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ state->GetIsolate(), DOMExceptionCode::kDataError,
+ "Failed to get the interest cohort: either it is "
+ "unavailable, or the preferences or content settings has "
+ "denined the access."));
} else {
- resolver->Resolve(interest_cohort);
+ InterestCohort* result = InterestCohort::Create();
+ result->setId(interest_cohort->id);
+ result->setVersion(interest_cohort->version);
+
+ resolver->Resolve(result);
}
},
WrapPersistent(resolver), WrapPersistent(this)));
@@ -6854,28 +6754,6 @@ DOMWindow* Document::defaultView() const {
return dom_window_;
}
-namespace {
-
-using performance_manager::mojom::InterventionPolicy;
-
-// A helper function to set the origin trial freeze policy of a document.
-void SetOriginTrialFreezePolicy(
- DocumentResourceCoordinator* document_resource_coordinator,
- ExecutionContext* context) {
- // An explicit opt-out overrides an explicit opt-in if both are present.
- if (RuntimeEnabledFeatures::PageFreezeOptOutEnabled(context)) {
- document_resource_coordinator->SetOriginTrialFreezePolicy(
- InterventionPolicy::kOptOut);
- UseCounter::Count(context, WebFeature::kPageFreezeOptOut);
- } else if (RuntimeEnabledFeatures::PageFreezeOptInEnabled(context)) {
- document_resource_coordinator->SetOriginTrialFreezePolicy(
- InterventionPolicy::kOptIn);
- UseCounter::Count(context, WebFeature::kPageFreezeOptIn);
- }
-}
-
-} // namespace
-
void Document::RecordAsyncScriptCount() {
UMA_HISTOGRAM_COUNTS_100("Blink.Script.AsyncScriptCount",
async_script_count_);
@@ -6967,7 +6845,7 @@ AllowState Document::GetDeclarativeShadowRootAllowState() const {
return declarative_shadow_root_allow_state_;
}
-void Document::setAllowDeclarativeShadowRoot(bool val) {
+void Document::setAllowDeclarativeShadowRoots(bool val) {
declarative_shadow_root_allow_state_ =
val ? AllowState::kAllow : AllowState::kDeny;
}
@@ -7029,11 +6907,6 @@ void Document::FinishedParsing() {
inspector_mark_load_event::Data(frame));
probe::DomContentLoadedEventFired(frame);
frame->GetIdlenessDetector()->DomContentLoadedEventFired();
-
- // Forward origin trial freeze policy to the corresponding frame object in
- // the resource coordinator.
- if (auto* document_resource_coordinator = GetResourceCoordinator())
- SetOriginTrialFreezePolicy(document_resource_coordinator, domWindow());
}
// Schedule dropping of the ElementDataCache. We keep it alive for a while
@@ -7059,7 +6932,11 @@ void Document::BeginLifecycleUpdatesIfRenderingReady() {
if (!HaveRenderBlockingResourcesLoaded())
return;
font_preload_manager_->WillBeginRendering();
- View()->BeginLifecycleUpdates();
+ // TODO(japhet): If IsActive() is true, View() should always be non-null.
+ // Speculative fix for https://crbug.com/1171891
+ if (auto* view = View()) {
+ view->BeginLifecycleUpdates();
+ }
}
Vector<IconURL> Document::IconURLs(int icon_types_mask) {
@@ -7181,7 +7058,7 @@ void Document::BatterySavingsMetaChanged() {
if (!root_element)
return;
- WebBatterySavingsFlags savings = 0;
+ BatterySavingsFlags savings = 0;
for (HTMLMetaElement& meta_element :
Traversal<HTMLMetaElement>::DescendantsOf(*root_element)) {
if (EqualIgnoringASCIICase(meta_element.GetName(), "battery-savings")) {
@@ -7227,7 +7104,7 @@ HTMLLinkElement* Document::LinkCanonical() const {
bool Document::AllowedToUseDynamicMarkUpInsertion(
const char* api_name,
ExceptionState& exception_state) {
- if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
+ if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled()) {
return true;
}
if (!GetFrame() || GetExecutionContext()->IsFeatureEnabled(
@@ -7243,7 +7120,7 @@ bool Document::AllowedToUseDynamicMarkUpInsertion(
exception_state.ThrowDOMException(
DOMExceptionCode::kNotAllowedError,
String::Format(
- "The use of method '%s' has been blocked by feature policy. The "
+ "The use of method '%s' has been blocked by permissions policy. The "
"feature "
"'document-write' is disabled in this document.",
api_name));
@@ -7445,6 +7322,23 @@ HTMLDialogElement* Document::ActiveModalDialog() const {
return nullptr;
}
+bool Document::PopupShowing() const {
+ return !popup_element_stack_.IsEmpty();
+}
+void Document::HideTopmostPopupElement() const {
+ if (popup_element_stack_.IsEmpty())
+ return;
+ popup_element_stack_.back()->hide();
+}
+void Document::HideAllPopupsUntil(const HTMLPopupElement* endpoint) {
+ while (!popup_element_stack_.IsEmpty() &&
+ popup_element_stack_.back() != endpoint) {
+ popup_element_stack_.back()->hide();
+ }
+ DCHECK(!endpoint || popup_element_stack_.back() == endpoint)
+ << "popup element not found in element stack";
+}
+
void Document::exitPointerLock() {
if (!GetPage())
return;
@@ -7487,15 +7381,6 @@ void Document::CheckLoadEventSoon() {
}
bool Document::IsDelayingLoadEvent() {
- // Always delay load events until after garbage collection.
- // This way we don't have to explicitly delay load events via
- // incrementLoadEventDelayCount and decrementLoadEventDelayCount in
- // Node destructors.
- if (ThreadState::Current()->SweepForbidden()) {
- if (!load_event_delay_count_)
- CheckLoadEventSoon();
- return true;
- }
return load_event_delay_count_;
}
@@ -7645,8 +7530,6 @@ void Document::UpdateHoverActiveState(bool is_active,
inner_element_in_document->GetDocument().LocalOwner();
}
- UpdateDistributionForFlatTreeTraversal();
-
UpdateActiveState(is_active, update_active_chain, inner_element_in_document);
UpdateHoverState(inner_element_in_document);
}
@@ -7800,8 +7683,7 @@ Document& Document::EnsureTemplateDocument() {
template_document_ = MakeGarbageCollected<HTMLDocument>(
DocumentInit::Create()
.WithExecutionContext(execution_context_.Get())
- .WithURL(BlankURL())
- .WithNewRegistrationContext());
+ .WithURL(BlankURL()));
} else {
template_document_ = MakeGarbageCollected<Document>(
DocumentInit::Create()
@@ -8137,23 +8019,6 @@ void Document::SetShadowCascadeOrder(ShadowCascadeOrder order) {
if (order == shadow_cascade_order_)
return;
- if (order == ShadowCascadeOrder::kShadowCascadeV0) {
- may_contain_v0_shadow_ = true;
- if (shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascadeV1) {
- // ::slotted() rules has to be moved to tree boundary rule sets.
- style_engine_->V0ShadowAddedOnV1Document();
- UseCounter::Count(*this, WebFeature::kMixedShadowRootV0AndV1);
- }
- }
-
- // For V0 -> V1 upgrade, we need style recalculation for all elements.
- if (shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascadeV0 &&
- order == ShadowCascadeOrder::kShadowCascadeV1) {
- GetStyleEngine().MarkAllElementsForStyleRecalc(
- StyleChangeReasonForTracing::Create(style_change_reason::kShadow));
- UseCounter::Count(*this, WebFeature::kMixedShadowRootV0AndV1);
- }
-
if (order > shadow_cascade_order_)
shadow_cascade_order_ = order;
}
@@ -8207,12 +8072,6 @@ DOMFeaturePolicy* Document::featurePolicy() {
return policy_.Get();
}
-const AtomicString& Document::RequiredCSP() {
- if (!Loader())
- return g_null_atom;
- return GetFrame()->Loader().RequiredCSP();
-}
-
StylePropertyMapReadOnly* Document::ComputedStyleMap(Element* element) {
ElementComputedStyleMap::AddResult add_result =
element_computed_style_map_.insert(element, nullptr);
@@ -8254,7 +8113,11 @@ void Document::Trace(Visitor* visitor) const {
visitor->Trace(lists_invalidated_at_document_);
visitor->Trace(node_lists_);
visitor->Trace(top_layer_elements_);
+ visitor->Trace(popup_element_stack_);
+ visitor->Trace(load_event_delay_timer_);
+ visitor->Trace(plugin_loading_timer_);
visitor->Trace(elem_sheet_);
+ visitor->Trace(clear_focused_element_timer_);
visitor->Trace(node_iterators_);
visitor->Trace(ranges_);
visitor->Trace(document_explicit_root_intersection_observer_data_);
@@ -8273,12 +8136,12 @@ void Document::Trace(Visitor* visitor) const {
visitor->Trace(scripted_animation_controller_);
visitor->Trace(scripted_idle_task_controller_);
visitor->Trace(text_autosizer_);
- visitor->Trace(registration_context_);
- visitor->Trace(custom_element_microtask_run_queue_);
+ visitor->Trace(element_data_cache_clear_timer_);
visitor->Trace(element_data_cache_);
visitor->Trace(use_elements_needing_update_);
visitor->Trace(template_document_);
visitor->Trace(template_document_host_);
+ visitor->Trace(did_associate_form_controls_timer_);
visitor->Trace(user_action_elements_);
visitor->Trace(svg_extensions_);
visitor->Trace(document_animations_);
@@ -8310,18 +8173,6 @@ void Document::Trace(Visitor* visitor) const {
ContainerNode::Trace(visitor);
}
-void Document::RecordUkmOutliveTimeAfterShutdown(int outlive_time_count) {
- if (!needs_to_record_ukm_outlive_time_)
- return;
-
- DCHECK(ukm_recorder_);
- DCHECK(ukm_source_id_ != ukm::kInvalidSourceId);
-
- ukm::builders::Document_OutliveTimeAfterShutdown(ukm_source_id_)
- .SetGCCount(outlive_time_count)
- .Record(ukm_recorder_.get());
-}
-
bool Document::CurrentFrameHadRAF() const {
return scripted_animation_controller_->CurrentFrameHadRAF();
}
@@ -8337,8 +8188,6 @@ SlotAssignmentEngine& Document::GetSlotAssignmentEngine() {
}
bool Document::IsSlotAssignmentOrLegacyDistributionDirty() const {
- if (ChildNeedsDistributionRecalc())
- return true;
if (slot_assignment_engine_ &&
slot_assignment_engine_->HasPendingSlotAssignmentRecalc()) {
return true;
@@ -8347,9 +8196,6 @@ bool Document::IsSlotAssignmentOrLegacyDistributionDirty() const {
}
bool Document::IsFocusAllowed() const {
- if (GetFrame() && GetFrame()->GetPage()->InsidePortal())
- return false;
-
if (!GetFrame() || GetFrame()->IsMainFrame() ||
LocalFrame::HasTransientUserActivation(GetFrame())) {
// 'autofocus' runs Element::focus asynchronously at which point the
@@ -8473,24 +8319,11 @@ void Document::SetShowBeforeUnloadDialog(bool show_dialog) {
}
void Document::ColorSchemeChanged() {
- InvalidateScrollbars();
UpdateForcedColors();
GetStyleEngine().ColorSchemeChanged();
MediaQueryAffectingValueChanged(MediaValueChange::kOther);
}
-void Document::InvalidateScrollbars() {
- if (PaintLayerScrollableArea* scrollable_area =
- GetLayoutView()->GetScrollableArea()) {
- if (auto* horizontal_scrollbar = scrollable_area->HorizontalScrollbar()) {
- horizontal_scrollbar->SetNeedsPaintInvalidation(kAllParts);
- }
- if (auto* vertical_scrollbar = scrollable_area->VerticalScrollbar()) {
- vertical_scrollbar->SetNeedsPaintInvalidation(kAllParts);
- }
- }
-}
-
void Document::VisionDeficiencyChanged() {
GetStyleEngine().VisionDeficiencyChanged();
}
@@ -8504,6 +8337,8 @@ void Document::UpdateForcedColors() {
? web_theme_engine->GetForcedColors()
: ForcedColors::kNone;
in_forced_colors_mode_ = forced_colors != ForcedColors::kNone;
+ if (in_forced_colors_mode_)
+ GetStyleEngine().EnsureUAStyleForForcedColors();
}
bool Document::InForcedColorsMode() const {
@@ -8591,6 +8426,22 @@ const Node* Document::GetFindInPageActiveMatchNode() const {
return find_in_page_active_match_node_;
}
+bool Document::InStyleRecalc() const {
+ return lifecycle_.GetState() == DocumentLifecycle::kInStyleRecalc ||
+ style_engine_->InContainerQueryStyleRecalc();
+}
+
+Document::PaintPreviewScope::PaintPreviewScope(Document& document)
+ : document_(document) {
+ document_.is_painting_preview_ = true;
+ document_.GetDisplayLockDocumentState().NotifyPrintingOrPreviewChanged();
+}
+
+Document::PaintPreviewScope::~PaintPreviewScope() {
+ document_.is_painting_preview_ = false;
+ document_.GetDisplayLockDocumentState().NotifyPrintingOrPreviewChanged();
+}
+
template class CORE_TEMPLATE_EXPORT Supplement<Document>;
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/document.h b/chromium/third_party/blink/renderer/core/dom/document.h
index 9e720fe7830..4269e8813f0 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.h
+++ b/chromium/third_party/blink/renderer/core/dom/document.h
@@ -42,6 +42,7 @@
#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/federated_learning/floc.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/permissions/permission.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink-forward.h"
@@ -61,7 +62,6 @@
#include "third_party/blink/renderer/core/dom/user_action_element_set.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/frame/fragment_directive.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
#include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
#include "third_party/blink/renderer/core/loader/font_preload_manager.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
@@ -114,20 +114,17 @@ class ComputedStyle;
class ConsoleMessage;
class ContextFeatures;
class CookieJar;
-class V0CustomElementMicrotaskRunQueue;
-class V0CustomElementRegistrationContext;
class DOMImplementation;
class DOMWindow;
+class DocumentAnimations;
class DocumentFragment;
class DocumentInit;
class DocumentLoader;
class DocumentMarkerController;
class DocumentNameCollection;
-class DocumentOutliveTimeReporter;
class DocumentParser;
class DocumentResourceCoordinator;
class DocumentState;
-class DocumentAnimations;
class DocumentTimeline;
class DocumentType;
class DOMFeaturePolicy;
@@ -155,6 +152,7 @@ class HTMLHeadElement;
class HTMLImportLoader;
class HTMLImportsController;
class HTMLLinkElement;
+class HTMLPopupElement;
class HTMLScriptElementOrSVGScriptElement;
class HitTestRequest;
class HttpRefreshScheduler;
@@ -246,11 +244,7 @@ enum DocumentClass {
kXMLDocumentClass = 1 << 6,
};
-enum ShadowCascadeOrder {
- kShadowCascadeNone,
- kShadowCascadeV0,
- kShadowCascadeV1
-};
+enum ShadowCascadeOrder { kShadowCascadeNone, kShadowCascade };
using DocumentClassFlags = unsigned char;
@@ -328,6 +322,8 @@ class CORE_EXPORT Document : public ContainerNode,
// document to cease to be the initial empty document.
void OverrideIsInitialEmptyDocument() { is_initial_empty_document_ = false; }
+ bool IsPrerendering() const { return is_prerendering_; }
+
// Gets the associated LocalDOMWindow even if this Document is associated with
// an HTMLImportsController.
LocalDOMWindow* ExecutingWindow() const;
@@ -583,8 +579,20 @@ class CORE_EXPORT Document : public ContainerNode,
bool ignore_adjacent_style = false) const;
// Update ComputedStyles and attach LayoutObjects if necessary, but don't
- // lay out.
+ // lay out. This recursively invokes itself for all ancestor LocalFrames,
+ // because style in an ancestor frame can affect style in a child frame.
+ // This method is appropriate for cases where we need to ensure that the
+ // style for a single Document is up-to-date.
void UpdateStyleAndLayoutTree();
+
+ // Same as UpdateStyleAndLayoutTree, but does not recursively update style in
+ // ancestor frames. This method is intended to be used in cases where we can
+ // guarantee that ancestor frames already have clean style (e.g., from
+ // LocalFrameView::UpdateLifecyclePhases, which is a top-down iteration over
+ // the entire LocalFrame tree; or from Document::UpdateStyleAndLayout, which
+ // does its own ancestor tree walk).
+ void UpdateStyleAndLayoutTreeForThisDocument();
+
void UpdateStyleAndLayoutTreeForNode(const Node*);
void UpdateStyleAndLayoutTreeForSubtree(const Node*);
@@ -700,6 +708,7 @@ class CORE_EXPORT Document : public ContainerNode,
bool& did_allow_navigation);
struct UnloadEventTiming {
+ bool can_request;
base::TimeTicks unload_event_start;
base::TimeTicks unload_event_end;
};
@@ -800,10 +809,9 @@ class CORE_EXPORT Document : public ContainerNode,
void SetPrinting(PrintingState);
bool IsPaintingPreview() const { return is_painting_preview_; }
- bool IsCapturingLayout() const {
- return printing_ == kPrinting || is_painting_preview_;
+ bool IsPrintingOrPaintingPreview() const {
+ return Printing() || IsPaintingPreview();
}
- void SetIsPaintingPreview(bool);
enum CompatibilityMode { kQuirksMode, kLimitedQuirksMode, kNoQuirksMode };
@@ -1000,7 +1008,7 @@ class CORE_EXPORT Document : public ContainerNode,
int margin_height,
mojom::blink::ScrollbarMode,
bool is_display_none,
- mojom::ColorScheme color_scheme);
+ mojom::blink::ColorScheme color_scheme);
String title() const { return title_; }
void setTitle(const String&);
@@ -1073,10 +1081,10 @@ class CORE_EXPORT Document : public ContainerNode,
ExecutionContext* execution_context);
// Sends a query via Mojo to ask for the interest cohort. This can reject on
- // permissions errors (e.g. cookies not allowed, etc.) or when the interest
- // cohort is unavailable.
+ // permissions errors (e.g. preferences, content settings, feature policy,
+ // etc.) or when the interest cohort is unavailable.
// https://github.com/jkarlin/floc
- ScriptPromise interestCohort(ScriptState* script_state);
+ ScriptPromise interestCohort(ScriptState* script_state, ExceptionState&);
// The following implements the rule from HTML 4 for what valid names are.
// To get this right for all the XML cases, we probably have to improve this
@@ -1316,8 +1324,6 @@ class CORE_EXPORT Document : public ContainerNode,
const AtomicString& name,
const ElementRegistrationOptions*,
ExceptionState&);
- V0CustomElementRegistrationContext* RegistrationContext() const;
- V0CustomElementMicrotaskRunQueue* CustomElementMicrotaskRunQueue();
void ClearImportsController();
HTMLImportsController* EnsureImportsController();
@@ -1346,9 +1352,7 @@ class CORE_EXPORT Document : public ContainerNode,
void DidLoadAllPendingParserBlockingStylesheets();
void DidRemoveAllPendingStylesheets();
- bool InStyleRecalc() const {
- return lifecycle_.GetState() == DocumentLifecycle::kInStyleRecalc;
- }
+ bool InStyleRecalc() const;
// Return a Locale for the default locale if the argument is null or empty.
Locale& GetCachedLocale(const AtomicString& locale = g_null_atom);
@@ -1372,11 +1376,21 @@ class CORE_EXPORT Document : public ContainerNode,
const HeapVector<Member<Element>>& TopLayerElements() const {
return top_layer_elements_;
}
+
HTMLDialogElement* ActiveModalDialog() const;
+ HeapVector<Member<HTMLPopupElement>>& PopupElementStack() {
+ return popup_element_stack_;
+ }
+ bool PopupShowing() const;
+ void HideTopmostPopupElement() const;
+ // This hides all visible popups up to, but not including,
+ // |endpoint|. If |endpoint| is nullptr, all popups are hidden.
+ void HideAllPopupsUntil(const HTMLPopupElement* endpoint);
+
// A non-null template_document_host_ implies that |this| was created by
// EnsureTemplateDocument().
- bool IsTemplateDocument() const { return !!template_document_host_; }
+ bool IsTemplateDocument() const { return template_document_host_; }
Document& EnsureTemplateDocument();
Document* TemplateDocumentHost() { return template_document_host_; }
@@ -1433,15 +1447,13 @@ class CORE_EXPORT Document : public ContainerNode,
SnapCoordinator& GetSnapCoordinator();
void PerformScrollSnappingTasks();
- bool MayContainV0Shadow() const { return may_contain_v0_shadow_; }
-
ShadowCascadeOrder GetShadowCascadeOrder() const {
return shadow_cascade_order_;
}
void SetShadowCascadeOrder(ShadowCascadeOrder);
- bool ContainsV1ShadowTree() const {
- return shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascadeV1;
+ bool ContainsShadowTree() const {
+ return shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascade;
}
RootScrollerController& GetRootScrollerController() const {
@@ -1488,13 +1500,9 @@ class CORE_EXPORT Document : public ContainerNode,
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType);
- void RecordUkmOutliveTimeAfterShutdown(int outlive_time_count);
-
bool CurrentFrameHadRAF() const;
bool NextFrameHasPendingRAF() const;
- const AtomicString& RequiredCSP();
-
StylePropertyMapReadOnly* ComputedStyleMap(Element*);
void AddComputedStyleMapItem(Element*, StylePropertyMapReadOnly*);
StylePropertyMapReadOnly* RemoveComputedStyleMapItem(Element*);
@@ -1625,15 +1633,6 @@ class CORE_EXPORT Document : public ContainerNode,
return use_count_fragment_directive_;
}
-#if DCHECK_IS_ON()
- bool AllowDirtyShadowV0Traversal() const {
- return allow_dirty_shadow_v0_traversal_;
- }
- void SetAllowDirtyShadowV0Traversal(bool allow) {
- allow_dirty_shadow_v0_traversal_ = allow;
- }
-#endif
-
void ApplyScrollRestorationLogic();
void MarkHasFindInPageRequest();
@@ -1668,11 +1667,28 @@ class CORE_EXPORT Document : public ContainerNode,
kDeny
};
DeclarativeShadowRootAllowState GetDeclarativeShadowRootAllowState() const;
- void setAllowDeclarativeShadowRoot(bool val);
+ void setAllowDeclarativeShadowRoots(bool val);
void SetFindInPageActiveMatchNode(Node*);
const Node* GetFindInPageActiveMatchNode() const;
+ class CORE_EXPORT PaintPreviewScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit PaintPreviewScope(Document& document);
+ ~PaintPreviewScope();
+
+ PaintPreviewScope(PaintPreviewScope&) = delete;
+ PaintPreviewScope& operator=(PaintPreviewScope&) = delete;
+
+ private:
+ Document& document_;
+ };
+
+ bool IsDirAttributeDirty() { return dir_attribute_dirty_; }
+ void SetDirAttributeDirty() { dir_attribute_dirty_ = true; }
+
protected:
void ClearXMLVersion() { xml_version_ = String(); }
@@ -1686,7 +1702,6 @@ class CORE_EXPORT Document : public ContainerNode,
private:
friend class DocumentTest;
friend class IgnoreDestructiveWriteCountIncrementer;
- friend class TextFragmentSelectorGeneratorTest;
friend class ThrowOnDynamicMarkupInsertionCountIncrementer;
friend class IgnoreOpensDuringUnloadCountIncrementer;
friend class NthIndexCache;
@@ -1695,12 +1710,11 @@ class CORE_EXPORT Document : public ContainerNode,
FRIEND_TEST_ALL_PREFIXES(FrameFetchContextSubresourceFilterTest,
DuringOnFreeze);
FRIEND_TEST_ALL_PREFIXES(DocumentTest, FindInPageUkm);
+ FRIEND_TEST_ALL_PREFIXES(DocumentTest, FindInPageUkmInFrame);
FRIEND_TEST_ALL_PREFIXES(TextFinderSimTest,
BeforeMatchExpandedHiddenMatchableUkm);
FRIEND_TEST_ALL_PREFIXES(TextFinderSimTest,
BeforeMatchExpandedHiddenMatchableUkmNoHandler);
- FRIEND_TEST_ALL_PREFIXES(TextFragmentAnchorMetricsTest, LinkOpenedSuccessUKM);
- FRIEND_TEST_ALL_PREFIXES(TextFragmentAnchorMetricsTest, LinkOpenedFailedUKM);
class NetworkStateObserver;
friend class AXContext;
@@ -1727,8 +1741,6 @@ class CORE_EXPORT Document : public ContainerNode,
void PropagateStyleToViewport();
- void InvalidateScrollbars();
-
void UpdateUseShadowTreesIfNeeded();
void EvaluateMediaQueryListIfNeeded();
@@ -1828,6 +1840,11 @@ class CORE_EXPORT Document : public ContainerNode,
bool is_initial_empty_document_;
+ // Track the prerendering state.
+ // TODO(crbug.com/1169032): Update the flag on the prerendering activation.
+ // Also, we will merge the state into the lifecycle state eventually.
+ const bool is_prerendering_;
+
bool evaluate_media_queries_on_style_recalc_;
// If we do ignore the pending stylesheet count, then we need to add a boolean
@@ -1900,7 +1917,7 @@ class CORE_EXPORT Document : public ContainerNode,
bool autofocus_processed_flag_ = false;
mojom::blink::FocusType last_focus_type_;
bool had_keyboard_event_;
- TaskRunnerTimer<Document> clear_focused_element_timer_;
+ HeapTaskRunnerTimer<Document> clear_focused_element_timer_;
// https://html.spec.whatwg.org/C/#autofocus-candidates
// We implement this as a Vector because its maximum size is typically 1.
HeapVector<Member<Element>> autofocus_candidates_;
@@ -2033,9 +2050,13 @@ class CORE_EXPORT Document : public ContainerNode,
// stack and is thus the one that will be visually on top.
HeapVector<Member<Element>> top_layer_elements_;
+ // The stack of currently-displayed popup elements. Elements in the stack
+ // go from earliest (bottom-most) to latest (top-most).
+ HeapVector<Member<HTMLPopupElement>> popup_element_stack_;
+
int load_event_delay_count_;
- TaskRunnerTimer<Document> load_event_delay_timer_;
- TaskRunnerTimer<Document> plugin_loading_timer_;
+ HeapTaskRunnerTimer<Document> load_event_delay_timer_;
+ HeapTaskRunnerTimer<Document> plugin_loading_timer_;
DocumentTiming document_timing_;
Member<MediaQueryMatcher> media_query_matcher_;
@@ -2046,11 +2067,8 @@ class CORE_EXPORT Document : public ContainerNode,
Member<ScriptedIdleTaskController> scripted_idle_task_controller_;
Member<TextAutosizer> text_autosizer_;
- Member<V0CustomElementRegistrationContext> registration_context_;
- Member<V0CustomElementMicrotaskRunQueue> custom_element_microtask_run_queue_;
-
void ElementDataCacheClearTimerFired(TimerBase*);
- TaskRunnerTimer<Document> element_data_cache_clear_timer_;
+ HeapTaskRunnerTimer<Document> element_data_cache_clear_timer_;
Member<ElementDataCache> element_data_cache_;
@@ -2066,7 +2084,7 @@ class CORE_EXPORT Document : public ContainerNode,
Member<Document> template_document_;
Member<Document> template_document_host_;
- TaskRunnerTimer<Document> did_associate_form_controls_timer_;
+ HeapTaskRunnerTimer<Document> did_associate_form_controls_timer_;
HeapHashSet<Member<SVGUseElement>> use_elements_needing_update_;
@@ -2080,8 +2098,6 @@ class CORE_EXPORT Document : public ContainerNode,
int node_count_;
- bool may_contain_v0_shadow_ = false;
-
Member<SnapCoordinator> snap_coordinator_;
Member<PropertyRegistry> property_registry_;
@@ -2092,13 +2108,10 @@ class CORE_EXPORT Document : public ContainerNode,
Member<NetworkStateObserver> network_state_observer_;
- std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_;
-
// |ukm_recorder_| and |source_id_| will allow objects that are part of
// the document to record UKM.
std::unique_ptr<ukm::UkmRecorder> ukm_recorder_;
const int64_t ukm_source_id_;
- bool needs_to_record_ukm_outlive_time_;
// Tracks and reports metrics of attempted font match attempts (both
// successful and not successful) by the page.
@@ -2145,12 +2158,6 @@ class CORE_EXPORT Document : public ContainerNode,
// opposed to a PluginView.
bool is_for_external_handler_;
-#if DCHECK_IS_ON()
- // Allow traversal of Shadow DOM V0 traversal with dirty distribution.
- // Required for marking ancestors style-child-dirty.
- bool allow_dirty_shadow_v0_traversal_ = false;
-#endif
-
Member<LazyLoadImageObserver> lazy_load_image_observer_;
// Tracks which feature policies have already been parsed, so as not to count
@@ -2205,6 +2212,8 @@ class CORE_EXPORT Document : public ContainerNode,
bool had_find_in_page_render_subtree_active_match_ = false;
bool had_find_in_page_beforematch_expanded_hidden_matchable_ = false;
+ bool dir_attribute_dirty_ = false;
+
// To reduce the API noisiness an explicit deny decision will set a
// flag that auto rejects the promise without the need for an IPC
// call or potential user prompt.
@@ -2246,10 +2255,6 @@ inline void Document::ScheduleLayoutTreeUpdateIfNeeded() {
ScheduleLayoutTreeUpdate();
}
-#define DEFINE_DOCUMENT_TYPE_CASTS(thisType) \
- DEFINE_TYPE_CASTS(thisType, Document, document, document->Is##thisType(), \
- document.Is##thisType())
-
// This is needed to avoid ambiguous overloads with the Node and TreeScope
// versions.
DEFINE_COMPARISON_OPERATORS_WITH_REFERENCES(Document)
diff --git a/chromium/third_party/blink/renderer/core/dom/document.idl b/chromium/third_party/blink/renderer/core/dom/document.idl
index c65d96e3cfb..74cdf804a97 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.idl
+++ b/chromium/third_party/blink/renderer/core/dom/document.idl
@@ -54,16 +54,16 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[Affects=Nothing] HTMLCollection getElementsByTagNameNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] HTMLCollection getElementsByClassName(DOMString classNames);
- [NewObject, DoNotTestNewObject, CustomElementCallbacks, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName);
- [NewObject, DoNotTestNewObject, CustomElementCallbacks, RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName);
+ [NewObject, DoNotTestNewObject, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName);
+ [NewObject, DoNotTestNewObject, RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName);
[NewObject] DocumentFragment createDocumentFragment();
[NewObject] Text createTextNode(DOMString data);
[NewObject, RaisesException] CDATASection createCDATASection(DOMString data);
[NewObject] Comment createComment(DOMString data);
[NewObject, RaisesException] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
- [NewObject, DoNotTestNewObject, CEReactions, CustomElementCallbacks, RaisesException] Node importNode(Node node, optional boolean deep = false);
- [RaisesException, CEReactions, CustomElementCallbacks] Node adoptNode(Node node);
+ [NewObject, DoNotTestNewObject, CEReactions, RaisesException] Node importNode(Node node, optional boolean deep = false);
+ [RaisesException, CEReactions] Node adoptNode(Node node);
[NewObject, RaisesException, MeasureAs=DocumentCreateAttribute] Attr createAttribute(DOMString localName);
[NewObject, RaisesException, MeasureAs=DocumentCreateAttributeNS] Attr createAttributeNS(DOMString? namespaceURI, DOMString qualifiedName);
@@ -97,9 +97,9 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// Named getter is implemented without IDL code generation for better
// performance. See local_window_proxy.cc.
// getter object (DOMString name);
- [Affects=Nothing, CEReactions, CustomElementCallbacks] attribute DOMString title;
- [CEReactions, CustomElementCallbacks] attribute DOMString dir;
- [Affects=Nothing, CEReactions, RaisesException=Setter, CustomElementCallbacks, PerWorldBindings] attribute HTMLElement? body;
+ [Affects=Nothing, CEReactions] attribute DOMString title;
+ [CEReactions] attribute DOMString dir;
+ [Affects=Nothing, CEReactions, RaisesException=Setter, PerWorldBindings] attribute HTMLElement? body;
[Affects=Nothing] readonly attribute HTMLHeadElement? head;
[SameObject, Measure] readonly attribute HTMLCollection images;
[SameObject, Measure] readonly attribute HTMLCollection embeds;
@@ -111,24 +111,24 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[ImplementedAs=currentScriptForBinding] readonly attribute HTMLOrSVGScriptElement? currentScript;
// dynamic markup insertion
- [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = "");
+ [CallWith=Isolate, CEReactions, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = "");
[CallWith=Isolate, RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(USVString url, DOMString name, DOMString features);
[CEReactions, RaisesException] void close();
- [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text);
- [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text);
+ [CallWith=Isolate, CEReactions, RaisesException] void write(DOMString... text);
+ [CallWith=Isolate, CEReactions, RaisesException] void writeln(DOMString... text);
// TrustedTypes variants of the above.
// Note: This should be gated on [RuntimeEnabled=TrustedDOMTypes], but
// since RuntimeEnabled isn't compatible with overloaded methods, we're
// handling these unconditionally.
- [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(TrustedHTML text);
- [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text);
+ [CallWith=Isolate, CEReactions, RaisesException] void write(TrustedHTML text);
+ [CallWith=Isolate, CEReactions, RaisesException] void writeln(TrustedHTML text);
// user interaction
[Affects=Nothing] readonly attribute Window? defaultView;
[Affects=Nothing] boolean hasFocus();
- [CEReactions, CustomElementCallbacks, MeasureAs=DocumentDesignMode] attribute DOMString designMode;
- [CEReactions, CustomElementCallbacks, RaisesException] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
+ [CEReactions, MeasureAs=DocumentDesignMode] attribute DOMString designMode;
+ [CEReactions, RaisesException] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
[RaisesException] boolean queryCommandEnabled(DOMString commandId);
[RaisesException] boolean queryCommandIndeterm(DOMString commandId);
[RaisesException] boolean queryCommandState(DOMString commandId);
@@ -143,11 +143,11 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[Measure] readonly attribute HTMLCollection anchors;
[Measure] readonly attribute HTMLCollection applets;
- [CEReactions, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString fgColor;
- [CEReactions, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString linkColor;
- [CEReactions, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString vlinkColor;
- [CEReactions, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString alinkColor;
- [CEReactions, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString bgColor;
+ [CEReactions] attribute [TreatNullAs=EmptyString] DOMString fgColor;
+ [CEReactions] attribute [TreatNullAs=EmptyString] DOMString linkColor;
+ [CEReactions] attribute [TreatNullAs=EmptyString] DOMString vlinkColor;
+ [CEReactions] attribute [TreatNullAs=EmptyString] DOMString alinkColor;
+ [CEReactions] attribute [TreatNullAs=EmptyString] DOMString bgColor;
[MeasureAs=DocumentClear] void clear();
[MeasureAs=DocumentCaptureEvents] void captureEvents();
@@ -166,8 +166,8 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// Custom Elements
// https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-register
// https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-instantiate
- [CustomElementCallbacks, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName, (DOMString or ElementCreationOptions) options);
- [CustomElementCallbacks, RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName, (DOMString or ElementCreationOptions) options);
+ [PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName, (DOMString or ElementCreationOptions) options);
+ [RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName, (DOMString or ElementCreationOptions) options);
// Page Visibility
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
@@ -188,7 +188,7 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// Interest Cohort API
// TODO(yaoxia): Add web tests. http://crbug/1130074.
- [CallWith=ScriptState, NewObject, RuntimeEnabled=InterestCohortAPI, MeasureAs=InterestCohortAPI_interestCohort_Method] Promise<DOMString> interestCohort();
+ [CallWith=ScriptState, RaisesException, NewObject, SecureContext, RuntimeEnabled=InterestCohortAPI, MeasureAs=InterestCohortAPI_interestCohort_Method] Promise<InterestCohort> interestCohort();
// Text fragment directive API
// https://wicg.github.io/scroll-to-text-fragment/#feature-detectability
diff --git a/chromium/third_party/blink/renderer/core/dom/document_data.h b/chromium/third_party/blink/renderer/core/dom/document_data.h
index 66aa59eb73a..40d00499ab7 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_data.h
@@ -33,6 +33,7 @@ class DocumentData final : public GarbageCollected<DocumentData> {
visitor->Trace(floc_service_);
visitor->Trace(has_trust_tokens_answerer_);
visitor->Trace(pending_has_trust_tokens_resolvers_);
+ visitor->Trace(email_regexp_);
}
private:
@@ -60,7 +61,7 @@ class DocumentData final : public GarbageCollected<DocumentData> {
pending_has_trust_tokens_resolvers_;
// To do email regex checks.
- std::unique_ptr<ScriptRegexp> email_regexp_;
+ Member<ScriptRegexp> email_regexp_;
friend class Document;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/document_fragment.h b/chromium/third_party/blink/renderer/core/dom/document_fragment.h
index a573910a923..518ebbf2067 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_fragment.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_fragment.h
@@ -50,13 +50,6 @@ class CORE_EXPORT DocumentFragment : public ContainerNode {
bool CanContainRangeEndPoint() const final { return true; }
virtual bool IsTemplateContent() const { return false; }
- bool allowDeclarativeShadowDom() const {
- return allow_declarative_shadow_dom_;
- }
- void setAllowDeclarativeShadowDom(bool value) {
- allow_declarative_shadow_dom_ = value;
- }
-
// This will catch anyone doing an unnecessary check.
bool IsDocumentFragment() const = delete;
@@ -67,8 +60,6 @@ class CORE_EXPORT DocumentFragment : public ContainerNode {
NodeType getNodeType() const final;
Node* Clone(Document&, CloneChildrenFlag) const override;
bool ChildTypeAllowed(NodeType) const override;
-
- bool allow_declarative_shadow_dom_{false};
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/dom/document_init.cc b/chromium/third_party/blink/renderer/core/dom/document_init.cc
index d49dc7cb85d..a43dcce78e4 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_init.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_init.cc
@@ -38,7 +38,6 @@
#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/settings.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_view_source_document.h"
@@ -111,6 +110,11 @@ DocumentInit& DocumentInit::ForInitialEmptyDocument(bool empty) {
return *this;
}
+DocumentInit& DocumentInit::ForPrerendering(bool is_prerendering) {
+ is_prerendering_ = is_prerendering;
+ return *this;
+}
+
// static
DocumentInit::Type DocumentInit::ComputeDocumentType(
LocalFrame* frame,
@@ -137,8 +141,7 @@ DocumentInit::Type DocumentInit::ComputeDocumentType(
if (HTMLMediaElement::GetSupportsType(ContentType(mime_type)))
return Type::kMedia;
- if (frame && frame->GetPage() &&
- frame->Loader().AllowPlugins(kNotAboutToInstantiatePlugin)) {
+ if (frame && frame->GetPage() && frame->Loader().AllowPlugins()) {
PluginData* plugin_data = GetPluginData(frame, url);
// Everything else except text/plain can be overridden by plugins.
@@ -214,7 +217,30 @@ DocumentInit& DocumentInit::WithURL(const KURL& url) {
}
const KURL& DocumentInit::GetCookieUrl() const {
- return owner_document_ ? owner_document_->CookieURL() : url_;
+ const KURL& cookie_url =
+ owner_document_ ? owner_document_->CookieURL() : url_;
+
+ // An "about:blank" should inherit the `cookie_url` from the initiator of the
+ // navigation, but sometimes "about:blank" may commit without an
+ // `owner_document` (e.g. if the original initiator has been navigated away).
+ // In such scenario, it is important to use a safe `cookie_url` (e.g.
+ // kCookieAverseUrl) to avoid triggering mojo::ReportBadMessage and renderer
+ // kills via RestrictedCookieManager::ValidateAccessToCookiesAt.
+ //
+ // TODO(https://crbug.com/1176291): Correctly inherit the `cookie_url` from
+ // the initiator.
+ if (cookie_url.IsAboutBlankURL()) {
+ // Signify a cookie-averse document [1] with an null URL. See how
+ // CookiesJar::GetCookies and other methods check `cookie_url` against
+ // KURL::IsEmpty.
+ //
+ // [1] https://html.spec.whatwg.org/#cookie-averse-document-object
+ const KURL& kCookieAverseUrl = NullURL();
+
+ return kCookieAverseUrl;
+ }
+
+ return cookie_url;
}
DocumentInit& DocumentInit::WithSrcdocDocument(bool is_srcdoc_document) {
@@ -223,32 +249,6 @@ DocumentInit& DocumentInit::WithSrcdocDocument(bool is_srcdoc_document) {
}
-DocumentInit& DocumentInit::WithRegistrationContext(
- V0CustomElementRegistrationContext* registration_context) {
- DCHECK(!create_new_registration_context_);
- DCHECK(!registration_context_);
- registration_context_ = registration_context;
- return *this;
-}
-
-DocumentInit& DocumentInit::WithNewRegistrationContext() {
- DCHECK(!create_new_registration_context_);
- DCHECK(!registration_context_);
- create_new_registration_context_ = true;
- return *this;
-}
-
-V0CustomElementRegistrationContext* DocumentInit::RegistrationContext(
- Document* document) const {
- if (!IsA<HTMLDocument>(document) && !document->IsXHTMLDocument())
- return nullptr;
-
- if (create_new_registration_context_)
- return MakeGarbageCollected<V0CustomElementRegistrationContext>();
-
- return registration_context_;
-}
-
DocumentInit& DocumentInit::WithWebBundleClaimedUrl(
const KURL& web_bundle_claimed_url) {
web_bundle_claimed_url_ = web_bundle_claimed_url;
diff --git a/chromium/third_party/blink/renderer/core/dom/document_init.h b/chromium/third_party/blink/renderer/core/dom/document_init.h
index 4040390a7d1..2815429a9a1 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_init.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_init.h
@@ -33,7 +33,6 @@
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -109,6 +108,9 @@ class CORE_EXPORT DocumentInit final {
DocumentInit& ForInitialEmptyDocument(bool empty);
bool IsInitialEmptyDocument() const { return is_initial_empty_document_; }
+ DocumentInit& ForPrerendering(bool is_prerendering);
+ bool IsPrerendering() const { return is_prerendering_; }
+
// Compute the type of document to be loaded inside a |frame|, given its |url|
// and its |mime_type|.
//
@@ -135,10 +137,6 @@ class CORE_EXPORT DocumentInit final {
DocumentInit& WithSrcdocDocument(bool is_srcdoc_document);
- DocumentInit& WithRegistrationContext(V0CustomElementRegistrationContext*);
- V0CustomElementRegistrationContext* RegistrationContext(Document*) const;
- DocumentInit& WithNewRegistrationContext();
-
DocumentInit& WithWebBundleClaimedUrl(const KURL& web_bundle_claimed_url);
const KURL& GetWebBundleClaimedUrl() const { return web_bundle_claimed_url_; }
@@ -151,6 +149,7 @@ class CORE_EXPORT DocumentInit final {
static PluginData* GetPluginData(LocalFrame* frame, const KURL& url);
Type type_ = Type::kUnspecified;
+ bool is_prerendering_ = false;
bool is_initial_empty_document_ = false;
String mime_type_;
LocalDOMWindow* window_ = nullptr;
@@ -163,8 +162,6 @@ class CORE_EXPORT DocumentInit final {
// affects security checks, since srcdoc's content comes directly from
// the parent document, not from loading a URL.
bool is_srcdoc_document_ = false;
- V0CustomElementRegistrationContext* registration_context_ = nullptr;
- bool create_new_registration_context_ = false;
// The claimed URL inside Web Bundle file from which the document is loaded.
// This URL is used for window.location and document.URL and relative path
diff --git a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
index cfed2ae42a7..5bb9914dc6d 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
+++ b/chromium/third_party/blink/renderer/core/dom/document_or_shadow_root.h
@@ -75,24 +75,10 @@ class DocumentOrShadowRoot {
const Element* target = document.PointerLockElement();
if (!target)
return nullptr;
- // For Shadow DOM V0 compatibility: We allow returning an element in V0
- // shadow tree, even though it leaks the Shadow DOM.
- // TODO(kochi): Once V0 code is removed, the following V0 check is
- // unnecessary.
- if (target && target->IsInV0ShadowTree()) {
- UseCounter::Count(document,
- WebFeature::kDocumentPointerLockElementInV0Shadow);
- return const_cast<Element*>(target);
- }
return document.AdjustedElement(*target);
}
static Element* pointerLockElement(ShadowRoot& shadow_root) {
- // TODO(kochi): Once V0 code is removed, the following non-V1 check is
- // unnecessary. After V0 code is removed, we can use the same logic for
- // Document and ShadowRoot.
- if (!shadow_root.IsV1())
- return nullptr;
UseCounter::Count(shadow_root.GetDocument(),
WebFeature::kShadowRootPointerLockElement);
const Element* target = shadow_root.GetDocument().PointerLockElement();
diff --git a/chromium/third_party/blink/renderer/core/dom/document_test.cc b/chromium/third_party/blink/renderer/core/dom/document_test.cc
index 3b8390cd231..1d9dc837abe 100644
--- a/chromium/third_party/blink/renderer/core/dom/document_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document_test.cc
@@ -57,13 +57,16 @@
#include "third_party/blink/renderer/core/dom/synchronous_mutation_observer.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.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/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
+#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
@@ -79,6 +82,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -816,7 +820,7 @@ TEST_F(DocumentTest,
// clean compositing inputs as well.
GetDocument().EnsurePaintLocationDataValidForNode(
GetDocument().getElementById("sticky"), DocumentUpdateReason::kTest);
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean,
GetDocument().Lifecycle().GetState());
// Dirty layout.
@@ -826,7 +830,7 @@ TEST_F(DocumentTest,
GetDocument().EnsurePaintLocationDataValidForNode(
GetDocument().getElementById("stickyChild"), DocumentUpdateReason::kTest);
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean,
GetDocument().Lifecycle().GetState());
}
@@ -1018,6 +1022,71 @@ TEST_F(DocumentTest, FindInPageUkm) {
EXPECT_FALSE(ukm::TestUkmRecorder::EntryHasMetric(entries[1], "DidSearch"));
}
+TEST_F(DocumentTest, FindInPageUkmInFrame) {
+ std::string base_url = "http://internal.test/";
+
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
+ WebString::FromUTF8("visible_iframe.html"));
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
+ WebString::FromUTF8("single_iframe.html"));
+
+ frame_test_helpers::WebViewHelper web_view_helper;
+ WebViewImpl* web_view_impl =
+ web_view_helper.InitializeAndLoad(base_url + "single_iframe.html");
+
+ web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
+ DocumentUpdateReason::kTest);
+
+ Document* top_doc = web_view_impl->MainFrameImpl()->GetFrame()->GetDocument();
+ auto* iframe = To<HTMLIFrameElement>(top_doc->QuerySelector("iframe"));
+ Document* document = iframe->contentDocument();
+ ASSERT_TRUE(document);
+ ASSERT_FALSE(document->IsInMainFrame());
+
+ // Save the old recorder and replace it with a test one.
+ auto old_recorder = std::move(document->ukm_recorder_);
+ document->ukm_recorder_ = std::make_unique<ukm::TestUkmRecorder>();
+
+ auto* recorder = static_cast<ukm::TestUkmRecorder*>(document->UkmRecorder());
+
+ EXPECT_EQ(recorder->entries_count(), 0u);
+ document->MarkHasFindInPageRequest();
+ EXPECT_EQ(recorder->entries_count(), 1u);
+ document->MarkHasFindInPageRequest();
+ EXPECT_EQ(recorder->entries_count(), 1u);
+
+ auto entries = recorder->GetEntriesByName("Blink.FindInPage");
+ EXPECT_EQ(entries.size(), 1u);
+ EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entries[0], "DidSearch"));
+ EXPECT_EQ(*ukm::TestUkmRecorder::GetEntryMetric(entries[0], "DidSearch"), 1);
+ EXPECT_FALSE(ukm::TestUkmRecorder::EntryHasMetric(
+ entries[0], "DidHaveRenderSubtreeMatch"));
+
+ document->MarkHasFindInPageContentVisibilityActiveMatch();
+ EXPECT_EQ(recorder->entries_count(), 2u);
+ document->MarkHasFindInPageContentVisibilityActiveMatch();
+ EXPECT_EQ(recorder->entries_count(), 2u);
+ entries = recorder->GetEntriesByName("Blink.FindInPage");
+ EXPECT_EQ(entries.size(), 2u);
+
+ EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entries[0], "DidSearch"));
+ EXPECT_EQ(*ukm::TestUkmRecorder::GetEntryMetric(entries[0], "DidSearch"), 1);
+ EXPECT_FALSE(ukm::TestUkmRecorder::EntryHasMetric(
+ entries[0], "DidHaveRenderSubtreeMatch"));
+
+ EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(
+ entries[1], "DidHaveRenderSubtreeMatch"));
+ EXPECT_EQ(*ukm::TestUkmRecorder::GetEntryMetric(entries[1],
+ "DidHaveRenderSubtreeMatch"),
+ 1);
+ EXPECT_FALSE(ukm::TestUkmRecorder::EntryHasMetric(entries[1], "DidSearch"));
+
+ // Restore the old recorder, since some ukm metrics are recorded at shutdown.
+ document->ukm_recorder_ = std::move(old_recorder);
+}
+
TEST_F(DocumentTest, AtPageMarginWithDeviceScaleFactor) {
GetDocument().GetFrame()->SetPageZoomFactor(2);
SetBodyInnerHTML("<style>@page { margin: 50px; size: 400px 10in; }</style>");
@@ -1293,8 +1362,7 @@ INSTANTIATE_TEST_SUITE_P(
class BatterySavingsChromeClient : public EmptyChromeClient {
public:
- MOCK_METHOD2(BatterySavingsChanged,
- void(LocalFrame&, WebBatterySavingsFlags));
+ MOCK_METHOD2(BatterySavingsChanged, void(LocalFrame&, BatterySavingsFlags));
};
class DocumentBatterySavingsTest : public PageTestBase,
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_exception.h b/chromium/third_party/blink/renderer/core/dom/dom_exception.h
index 89fb24b181c..fda8c5cb103 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_exception.h
+++ b/chromium/third_party/blink/renderer/core/dom/dom_exception.h
@@ -46,6 +46,7 @@ class CORE_EXPORT DOMException : public ScriptWrappable {
// This constructor shouldn't be used except for V8ThrowDOMException. Note
// that this constructor does not associate the stacktrace with the created
// object.
+ // TODO(https://crbug.com/991544): Replace DOMException constructor calls.
DOMException(DOMExceptionCode,
const String& sanitized_message = String(),
const String& unsanitized_message = String());
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc b/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
index 0c172c250f3..d2e684e78da 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
+++ b/chromium/third_party/blink/renderer/core/dom/dom_implementation.cc
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/dom/xml_document.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html/html_title_element.h"
@@ -79,8 +78,7 @@ XMLDocument* DOMImplementation::createDocument(
if (namespace_uri == svg_names::kNamespaceURI) {
doc = XMLDocument::CreateSVG(init);
} else if (namespace_uri == html_names::xhtmlNamespaceURI) {
- doc = XMLDocument::CreateXHTML(
- init.WithRegistrationContext(document_->RegistrationContext()));
+ doc = XMLDocument::CreateXHTML(init);
} else {
doc = MakeGarbageCollected<XMLDocument>(init);
}
@@ -104,12 +102,10 @@ XMLDocument* DOMImplementation::createDocument(
}
Document* DOMImplementation::createHTMLDocument(const String& title) {
- DocumentInit init =
- DocumentInit::Create()
- .WithExecutionContext(document_->GetExecutionContext())
- .WithRegistrationContext(document_->RegistrationContext());
+ DocumentInit init = DocumentInit::Create().WithExecutionContext(
+ document_->GetExecutionContext());
auto* d = MakeGarbageCollected<HTMLDocument>(init);
- d->setAllowDeclarativeShadowRoot(false);
+ d->setAllowDeclarativeShadowRoots(false);
d->open();
d->write("<!doctype html><html><head></head><body></body></html>");
if (!title.IsNull()) {
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc b/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
index 032b3ef1b49..1ae15adbc58 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
+++ b/chromium/third_party/blink/renderer/core/dom/dom_token_list.cc
@@ -255,14 +255,10 @@ void DOMTokenList::UpdateWithTokenSet(const SpaceSplitString& token_set) {
}
AtomicString DOMTokenList::value() const {
- DCHECK_NE(attribute_name_, g_null_name)
- << "The subclass of DOMTokenList should override value().";
return element_->getAttribute(attribute_name_);
}
void DOMTokenList::setValue(const AtomicString& value) {
- DCHECK_NE(attribute_name_, g_null_name)
- << "The subclass of DOMTokenList should override setValue().";
element_->setAttribute(attribute_name_, value);
// setAttribute() will call DidUpdateAttributeValue().
}
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_token_list.h b/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
index 9b8e18ac510..3a43d141f62 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/dom_token_list.h
@@ -60,8 +60,8 @@ class CORE_EXPORT DOMTokenList : public ScriptWrappable {
const AtomicString& new_token,
ExceptionState&);
bool supports(const AtomicString&, ExceptionState&);
- virtual AtomicString value() const;
- virtual void setValue(const AtomicString&);
+ AtomicString value() const;
+ void setValue(const AtomicString&);
AtomicString toString() const { return value(); }
// This function should be called when the associated attribute value was
diff --git a/chromium/third_party/blink/renderer/core/dom/dom_token_list.idl b/chromium/third_party/blink/renderer/core/dom/dom_token_list.idl
index c716d5edd55..2d40af5d732 100644
--- a/chromium/third_party/blink/renderer/core/dom/dom_token_list.idl
+++ b/chromium/third_party/blink/renderer/core/dom/dom_token_list.idl
@@ -31,11 +31,11 @@
[Affects=Nothing] readonly attribute unsigned long length;
[Affects=Nothing] getter DOMString? item(unsigned long index);
[Affects=Nothing] boolean contains(DOMString token);
- [RaisesException, CEReactions, CustomElementCallbacks] void add(DOMString... tokens);
- [RaisesException, CEReactions, CustomElementCallbacks] void remove(DOMString... tokens);
- [RaisesException, CEReactions, CustomElementCallbacks] boolean toggle(DOMString token, optional boolean force);
+ [RaisesException, CEReactions] void add(DOMString... tokens);
+ [RaisesException, CEReactions] void remove(DOMString... tokens);
+ [RaisesException, CEReactions] boolean toggle(DOMString token, optional boolean force);
[RaisesException, CEReactions] boolean replace(DOMString token, DOMString newToken);
- [RaisesException, CustomElementCallbacks] boolean supports(DOMString token);
+ [RaisesException] boolean supports(DOMString token);
[CEReactions] attribute DOMString value;
stringifier;
iterable<DOMString>;
diff --git a/chromium/third_party/blink/renderer/core/dom/element-hot.cc b/chromium/third_party/blink/renderer/core/dom/element-hot.cc
index bee9f40f492..69278b1b4bd 100644
--- a/chromium/third_party/blink/renderer/core/dom/element-hot.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element-hot.cc
@@ -21,29 +21,10 @@ namespace blink {
WTF::AtomicStringTable::WeakResult Element::WeakLowercaseIfNecessary(
const StringView& name) const {
if (LIKELY(IsHTMLElement() && IsA<HTMLDocument>(GetDocument()))) {
-#if defined(ARCH_CPU_ARMEL)
- // The compiler on x64 and ARM32 produces code with very different
- // performance characteristics for WeakFindLowercased(). On ARM, explicitly
- // lowercasing the string into a new buffer before doing the lookup in the
- // AtomicStringTable is ~15% faster than doing the WeakFindLowercased().
- // This appears to be due to different inlining choices. Thus far, a
- // single block of code that works well on both platforms hasn't been found
- // so settling of an ifdef.
- //
- // TODO(ajwong): Figure out why this architecture divergence exists and
- // remove.
- StringView::StackBackingStore buf;
- StringView lowered = name.LowerASCIIMaybeUsingBuffer(buf);
- // TODO(ajwong): Why is this nearly 2x faster than calling the inlined
- // WeakFind() which also does the same check?
- if (LIKELY(lowered.IsAtomic())) {
- return AtomicStringTable::WeakResult(lowered.SharedImpl());
- } else {
- return WTF::AtomicStringTable::Instance().WeakFind(lowered);
- }
-#else
+ StringImpl* impl = name.SharedImpl();
+ if (impl && impl->IsAtomic() && impl->IsLowerASCII())
+ return WTF::AtomicStringTable::WeakResult(impl);
return WTF::AtomicStringTable::Instance().WeakFindLowercased(name);
-#endif
}
return WTF::AtomicStringTable::Instance().WeakFind(name);
diff --git a/chromium/third_party/blink/renderer/core/dom/element.cc b/chromium/third_party/blink/renderer/core/dom/element.cc
index 071dbf64748..9b2e476d02a 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element.cc
@@ -44,7 +44,6 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_pointer_lock_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_to_options.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h"
#include "third_party/blink/renderer/core/accessibility/ax_context.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
@@ -90,15 +89,14 @@
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/dom/scriptable_document_parser.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
#include "third_party/blink/renderer/core/dom/slot_assignment.h"
#include "third_party/blink/renderer/core/dom/space_split_string.h"
#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
#include "third_party/blink/renderer/core/editing/set_selection_options.h"
@@ -116,8 +114,6 @@
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/forms/html_form_controls_collection.h"
#include "third_party/blink/renderer/core/html/forms/html_options_collection.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
@@ -222,7 +218,7 @@ class DisplayLockStyleScope {
StyleRecalcChange AdjustStyleRecalcChangeForChildren(
StyleRecalcChange change) {
DCHECK(element_->GetDisplayLockContext());
- DCHECK(!element_->GetDisplayLockContext()->IsLocked());
+ DCHECK(element_->GetDisplayLockContext()->ShouldStyleChildren());
return element_->GetDisplayLockContext()
->AdjustStyleRecalcChangeForChildren(change);
}
@@ -278,15 +274,29 @@ bool IsRootEditableElementWithCounting(const Element& element) {
}
// Return true if we're absolutely sure that this node is going to establish a
-// new formatting context. Whether or not it establishes a new formatting
-// context cannot be accurately determined until we have actually created the
-// object (see LayoutBlockFlow::CreatesNewFormattingContext()), so this function
-// may (and is allowed to) return false negatives, but NEVER false positives.
+// new formatting context that can serve as a layout engine boundary (NG
+// vs. legacy). Whether or not it establishes a new formatting context cannot be
+// accurately determined until we have actually created the object (see
+// LayoutBlockFlow::CreatesNewFormattingContext()), so this function may (and is
+// allowed to) return false negatives, but NEVER false positives.
bool DefinitelyNewFormattingContext(const Node& node,
const ComputedStyle& style) {
auto display = style.Display();
- if (display == EDisplay::kInline || display == EDisplay::kContents)
+ if (display == EDisplay::kInline || display == EDisplay::kContents ||
+ display == EDisplay::kTableRowGroup ||
+ display == EDisplay::kTableHeaderGroup ||
+ display == EDisplay::kTableFooterGroup ||
+ display == EDisplay::kTableRow ||
+ display == EDisplay::kTableColumnGroup ||
+ display == EDisplay::kTableColumn)
return false;
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ // TableNG requires that table parts be either all NG, or all Legacy. In
+ // other words, cells and captions aren't suitable engine boundaries.
+ if (display == EDisplay::kTableCell || display == EDisplay::kTableCaption)
+ return false;
+ }
+
// ::marker may establish a formatting context but still have some dependency
// on the originating list item, so return false.
if (node.IsMarkerPseudoElement())
@@ -334,8 +344,10 @@ bool DefinitelyNewFormattingContext(const Node& node,
if (IsA<SVGForeignObjectElement>(element))
return true;
}
+ // An item inside a flex or grid container always establishes a new formatting
+ // context. Same for a child of a MathML or custom layout container.
if (const Node* parent = LayoutTreeBuilderTraversal::LayoutParent(node))
- return parent->ComputedStyleRef().IsDisplayFlexibleOrGridBox();
+ return parent->ComputedStyleRef().BlockifiesChildren();
return false;
}
@@ -356,13 +368,6 @@ bool CalculateStyleShouldForceLegacyLayout(const Element& element,
}
}
- if (!RuntimeEnabledFeatures::LayoutNGWebkitBoxEnabled() &&
- style.IsDeprecatedFlexboxUsingFlexLayout()) {
- UseCounter::Count(
- document, WebFeature::kLegacyLayoutByWebkitBoxWithoutVerticalLineClamp);
- return true;
- }
-
if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
// Disable NG for the entire subtree if we're establishing a multicol
// container.
@@ -764,14 +769,9 @@ void Element::SetElementAttribute(const QualifiedName& name, Element* element) {
ExplicitlySetAttrElementsMap* explicitly_set_attr_elements_map =
GetDocument().GetExplicitlySetAttrElementsMap(this);
- // If the reflected element is explicitly null, or is not a member of this
- // elements shadow including ancestor tree, then we remove the content
+ // If the reflected element is explicitly null then we remove the content
// attribute and the explicitly set attr-element.
- // Note this means that explicitly set elements can cross ancestral shadow
- // boundaries, but not descendant ones. See the spec for more details:
- // https://whatpr.org/html/3917/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:concept-shadow-including-ancestor
- if (!element ||
- !ElementIsDescendantOfShadowIncludingAncestor(*this, *element)) {
+ if (!element) {
explicitly_set_attr_elements_map->erase(name);
removeAttribute(name);
return;
@@ -779,13 +779,15 @@ void Element::SetElementAttribute(const QualifiedName& name, Element* element) {
const AtomicString id = element->GetIdAttribute();
- // Explicitly set attr-elements must have a valid id attribute, and also
- // refer to the first element in tree order of |this| elements node tree in
- // order for the content attribute to reflect the ID. Where these conditions
- // aren't met, the content attribute should reflect the empty string. Note
- // that the explicitly set attr-element is still set. See the spec for more
- // details:
- // https://whatpr.org/html/3917/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:root-2
+ // In order to sprout a non-empty content attribute from an explicitly set
+ // attr-element, |element| must:
+ // 1) have a valid ID attribute, and
+ // 2) be the first element in tree order with this ID.
+ // Otherwise the content attribute will reflect the empty string.
+ //
+ // Note that the explicitly set attr-element is still set. See the spec for
+ // more details:
+ // https://whatpr.org/html/3917/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes
if (id.IsNull() || GetTreeScope() != element->GetTreeScope() ||
GetTreeScope().getElementById(id) != element)
setAttribute(name, g_empty_atom);
@@ -813,12 +815,19 @@ Element* Element::GetElementAttribute(const QualifiedName& name) {
if (element_attribute_vector) {
DCHECK_EQ(element_attribute_vector->size(), 1u);
Element* explicitly_set_element = element_attribute_vector->at(0);
- // Only return the explicit element if it still exists in the same scope.
- if (explicitly_set_element)
- return explicitly_set_element;
+ if (!explicitly_set_element)
+ return nullptr;
+
+ // Only return the explicit element if it still exists within a valid scope.
+ if (!ElementIsDescendantOfShadowIncludingAncestor(*this,
+ *explicitly_set_element))
+ return nullptr;
+
+ return explicitly_set_element;
}
- // Compute the attr-associated element, this can be null.
+ // Compute the attr-associated element from the content attribute if present,
+ // id can be null.
AtomicString id = getAttribute(name);
if (id.IsNull())
return nullptr;
@@ -851,14 +860,10 @@ void Element::SetElementArrayAttribute(
SpaceSplitString value;
for (auto element : given_elements.value()) {
- // Elements that are not descendants of this element's shadow including
- // ancestors are dropped.
- if (!ElementIsDescendantOfShadowIncludingAncestor(*this, *element))
- continue;
-
- // If |value| is null, this means a previous element must have been invalid,
- // and the content attribute should reflect the empty string, so we don't
- // continue trying to compute it.
+ // If |value| is null and |elements| is non-empty, then a previous element
+ // must have been invalid wrt. the content attribute string rules, and
+ // therefore the content attribute string should reflect the empty string.
+ // This means we can stop trying to compute the content attribute string.
if (value.IsNull() && !elements->IsEmpty()) {
elements->push_back(element);
continue;
@@ -893,16 +898,23 @@ void Element::SetElementArrayAttribute(
base::Optional<HeapVector<Member<Element>>> Element::GetElementArrayAttribute(
const QualifiedName& name) {
+ HeapVector<Member<Element>> result_elements;
HeapVector<Member<Element>>* explicitly_set_elements =
GetExplicitlySetElementsForAttr(this, name);
if (explicitly_set_elements) {
- return *explicitly_set_elements;
+ for (auto attrElement : *explicitly_set_elements) {
+ if (ElementIsDescendantOfShadowIncludingAncestor(*this, *attrElement))
+ result_elements.push_back(attrElement);
+ }
+ return result_elements;
}
QualifiedName attr = name;
// Account for labelled vs labeled spelling
+ // TODO(chrishall): should this be refactored into a method?
+ // e.g. hasAttributeAccountForSpelling(...) ?
if (attr == html_names::kAriaLabelledbyAttr) {
attr = hasAttribute(html_names::kAriaLabeledbyAttr) &&
!hasAttribute(html_names::kAriaLabelledbyAttr)
@@ -911,20 +923,22 @@ base::Optional<HeapVector<Member<Element>>> Element::GetElementArrayAttribute(
}
String attribute_value = getAttribute(attr).GetString();
- HeapVector<Member<Element>> content_elements;
-
Vector<String> tokens;
attribute_value = attribute_value.SimplifyWhiteSpace();
attribute_value.Split(' ', tokens);
- for (auto token : tokens) {
- Element* candidate = GetTreeScope().getElementById(AtomicString(token));
+ // Lookup each id within the same root.
+ // Since this is based on ID we know it cannot cross shadow boundaries, so we
+ // don't need to include additional logic to check that.
+ for (auto id : tokens) {
+ Element* candidate = GetTreeScope().getElementById(AtomicString(id));
if (candidate)
- content_elements.push_back(candidate);
+ result_elements.push_back(candidate);
}
- if (content_elements.IsEmpty())
+ if (result_elements.IsEmpty())
return base::nullopt;
- return content_elements;
+
+ return result_elements;
}
NamedNodeMap* Element::attributesForBindings() const {
@@ -1962,7 +1976,7 @@ Vector<IntRect> Element::OutlineRectsInVisualViewport(
Vector<PhysicalRect> outline_rects = layout_object->OutlineRects(
PhysicalOffset(),
- layout_object->OutlineRectsShouldIncludeBlockVisualOverflow());
+ layout_object->StyleRef().OutlineRectsShouldIncludeBlockVisualOverflow());
for (auto& r : outline_rects) {
PhysicalRect physical_rect = layout_object->LocalToAbsoluteRect(r);
IntRect absolute_rect =
@@ -2020,10 +2034,7 @@ IntRect Element::VisibleBoundsInVisualViewport() const {
return visible_rect;
}
-void Element::ClientQuads(Vector<FloatQuad>& quads) {
- GetDocument().EnsurePaintLocationDataValidForNode(
- this, DocumentUpdateReason::kJavaScript);
-
+void Element::ClientQuads(Vector<FloatQuad>& quads) const {
LayoutObject* element_layout_object = GetLayoutObject();
if (!element_layout_object)
return;
@@ -2032,7 +2043,7 @@ void Element::ClientQuads(Vector<FloatQuad>& quads) {
// cannot use LocalToAbsoluteQuad directly with ObjectBoundingBox which is
// SVG coordinates and not HTML coordinates. Instead, use the AbsoluteQuads
// codepath below.
- auto* svg_element = DynamicTo<SVGElement>(this);
+ const auto* svg_element = DynamicTo<SVGElement>(this);
if (svg_element && !element_layout_object->IsSVGRoot() &&
!element_layout_object->IsSVGForeignObject()) {
// Get the bounding rectangle from the SVG model.
@@ -2053,6 +2064,8 @@ void Element::ClientQuads(Vector<FloatQuad>& quads) {
}
DOMRectList* Element::getClientRects() {
+ GetDocument().EnsurePaintLocationDataValidForNode(
+ this, DocumentUpdateReason::kJavaScript);
Vector<FloatQuad> quads;
ClientQuads(quads);
if (quads.IsEmpty())
@@ -2065,11 +2078,11 @@ DOMRectList* Element::getClientRects() {
return MakeGarbageCollected<DOMRectList>(quads);
}
-DOMRect* Element::getBoundingClientRect() {
+FloatRect Element::GetBoundingClientRectNoLifecycleUpdate() const {
Vector<FloatQuad> quads;
ClientQuads(quads);
if (quads.IsEmpty())
- return DOMRect::Create();
+ return FloatRect();
FloatRect result = quads[0].BoundingBox();
for (wtf_size_t i = 1; i < quads.size(); ++i)
@@ -2079,7 +2092,13 @@ DOMRect* Element::getBoundingClientRect() {
DCHECK(element_layout_object);
GetDocument().AdjustFloatRectForScrollAndAbsoluteZoom(result,
*element_layout_object);
- return DOMRect::FromFloatRect(result);
+ return result;
+}
+
+DOMRect* Element::getBoundingClientRect() {
+ GetDocument().EnsurePaintLocationDataValidForNode(
+ this, DocumentUpdateReason::kJavaScript);
+ return DOMRect::FromFloatRect(GetBoundingClientRectNoLifecycleUpdate());
}
const AtomicString& Element::computedRole() {
@@ -2092,7 +2111,6 @@ const AtomicString& Element::computedRole() {
document.View()->UpdateLifecycleToCompositingCleanPlusScrolling(
DocumentUpdateReason::kJavaScript);
}
- UpdateDistributionForFlatTreeTraversal();
AXContext ax_context(document);
return ax_context.GetAXObjectCache().ComputedRoleForNode(this);
}
@@ -2107,7 +2125,6 @@ String Element::computedName() {
document.View()->UpdateLifecycleToCompositingCleanPlusScrolling(
DocumentUpdateReason::kJavaScript);
}
- UpdateDistributionForFlatTreeTraversal();
AXContext ax_context(document);
return ax_context.GetAXObjectCache().ComputedNameForNode(this);
}
@@ -2262,14 +2279,8 @@ static inline AtomicString MakeIdForStyleResolution(const AtomicString& value,
DISABLE_CFI_PERF
void Element::AttributeChanged(const AttributeModificationParams& params) {
const QualifiedName& name = params.name;
- if (ShadowRoot* parent_shadow_root =
- ShadowRootWhereNodeCanBeDistributedForV0(*this)) {
- if (ShouldInvalidateDistributionWhenAttributeChanged(
- *parent_shadow_root, name, params.new_value))
- parent_shadow_root->SetNeedsDistributionRecalc();
- }
if (name == html_names::kSlotAttr && params.old_value != params.new_value) {
- if (ShadowRoot* root = V1ShadowRootOfParent())
+ if (ShadowRoot* root = ShadowRootOfParent())
root->DidChangeHostChildSlotName(params.old_value, params.new_value);
}
@@ -2398,47 +2409,6 @@ void Element::UpdateClassList(const AtomicString& old_class_string,
class_list->DidUpdateAttributeValue(old_class_string, new_class_string);
}
-bool Element::ShouldInvalidateDistributionWhenAttributeChanged(
- ShadowRoot& shadow_root,
- const QualifiedName& name,
- const AtomicString& new_value) {
- if (shadow_root.IsV1())
- return false;
- const SelectRuleFeatureSet& feature_set =
- shadow_root.V0().EnsureSelectFeatureSet();
-
- if (name == html_names::kIdAttr) {
- AtomicString old_id = GetElementData()->IdForStyleResolution();
- AtomicString new_id =
- MakeIdForStyleResolution(new_value, GetDocument().InQuirksMode());
- if (new_id != old_id) {
- if (!old_id.IsEmpty() && feature_set.HasSelectorForId(old_id))
- return true;
- if (!new_id.IsEmpty() && feature_set.HasSelectorForId(new_id))
- return true;
- }
- }
-
- if (name == html_names::kClassAttr) {
- const AtomicString& new_class_string = new_value;
- if (ClassStringHasClassName(new_class_string) ==
- ClassStringContent::kHasClasses) {
- const SpaceSplitString& old_classes = GetElementData()->ClassNames();
- const SpaceSplitString new_classes(GetDocument().InQuirksMode()
- ? new_class_string.LowerASCII()
- : new_class_string);
- if (feature_set.CheckSelectorsForClassChange(old_classes, new_classes))
- return true;
- } else {
- const SpaceSplitString& old_classes = GetElementData()->ClassNames();
- if (feature_set.CheckSelectorsForClassChange(old_classes))
- return true;
- }
- }
-
- return feature_set.HasSelectorForAttribute(name.LocalName());
-}
-
// Returns true if the given attribute is an event handler.
// We consider an event handler any attribute that begins with "on".
// It is a simple solution that has the advantage of not requiring any
@@ -2595,8 +2565,6 @@ Node::InsertionNotificationRequest Element::InsertedInto(
if (GetCustomElementState() == CustomElementState::kCustom)
CustomElement::EnqueueConnectedCallback(*this);
- else if (IsUpgradedV0CustomElement())
- V0CustomElement::DidAttach(this, GetDocument());
else if (GetCustomElementState() == CustomElementState::kUndefined)
CustomElement::TryToUpgrade(*this);
}
@@ -2656,8 +2624,6 @@ void Element::RemovedFrom(ContainerNode& insertion_point) {
if (GetCustomElementState() == CustomElementState::kCustom)
CustomElement::EnqueueDisconnectedCallback(*this);
- else if (IsUpgradedV0CustomElement())
- V0CustomElement::DidDetach(this, insertion_point.GetDocument());
}
GetDocument().GetRootScrollerController().ElementRemoved(*this);
@@ -2709,35 +2675,33 @@ void Element::AttachLayoutTree(AttachContext& context) {
AttachContext children_context(context);
LayoutObject* layout_object = nullptr;
- if (CanParticipateInFlatTree()) {
- if (being_rendered) {
- AdjustForceLegacyLayout(style, &children_context.force_legacy_layout);
- LegacyLayout legacy = children_context.force_legacy_layout
- ? LegacyLayout::kForce
- : LegacyLayout::kAuto;
- LayoutTreeBuilderForElement builder(*this, context, style, legacy);
- builder.CreateLayoutObject();
-
- layout_object = GetLayoutObject();
- if (layout_object) {
- children_context.previous_in_flow = nullptr;
- children_context.parent = layout_object;
- children_context.next_sibling = nullptr;
- children_context.next_sibling_valid = true;
- } else if (style->Display() != EDisplay::kContents) {
- // The layout object creation was suppressed for other reasons than
- // being display:none or display:contents (E.g.
- // LayoutObject::CanHaveChildren() returning false). Make sure we don't
- // attempt to create LayoutObjects further down the subtree.
- children_context.parent = nullptr;
- }
- // For display:contents elements, we keep the previous_in_flow,
- // next_sibling, and parent, in the context for attaching children.
- } else {
- // We are a display:none element. Set the parent to nullptr to make sure
- // we never create any child layout boxes.
+ if (being_rendered) {
+ AdjustForceLegacyLayout(style, &children_context.force_legacy_layout);
+ LegacyLayout legacy = children_context.force_legacy_layout
+ ? LegacyLayout::kForce
+ : LegacyLayout::kAuto;
+ LayoutTreeBuilderForElement builder(*this, context, style, legacy);
+ builder.CreateLayoutObject();
+
+ layout_object = GetLayoutObject();
+ if (layout_object) {
+ children_context.previous_in_flow = nullptr;
+ children_context.parent = layout_object;
+ children_context.next_sibling = nullptr;
+ children_context.next_sibling_valid = true;
+ } else if (style->Display() != EDisplay::kContents) {
+ // The layout object creation was suppressed for other reasons than
+ // being display:none or display:contents (E.g.
+ // LayoutObject::CanHaveChildren() returning false). Make sure we don't
+ // attempt to create LayoutObjects further down the subtree.
children_context.parent = nullptr;
}
+ // For display:contents elements, we keep the previous_in_flow,
+ // next_sibling, and parent, in the context for attaching children.
+ } else {
+ // We are a display:none element. Set the parent to nullptr to make sure
+ // we never create any child layout boxes.
+ children_context.parent = nullptr;
}
children_context.use_previous_in_flow = true;
@@ -2771,8 +2735,10 @@ void Element::DetachLayoutTree(bool performing_reattach) {
HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
if (HasRareData()) {
ElementRareData* data = GetElementRareData();
- if (!performing_reattach)
+ if (!performing_reattach) {
data->ClearPseudoElements();
+ data->SetContainerQueryEvaluator(nullptr);
+ }
if (ElementAnimations* element_animations = data->GetElementAnimations()) {
if (performing_reattach) {
@@ -2831,7 +2797,8 @@ void Element::DetachLayoutTree(bool performing_reattach) {
GetDocument().GetStyleEngine().ClearNeedsWhitespaceReattachmentFor(this);
}
-scoped_refptr<ComputedStyle> Element::StyleForLayoutObject() {
+scoped_refptr<ComputedStyle> Element::StyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(GetDocument().InStyleRecalc());
// FIXME: Instead of clearing updates that may have been added from calls to
@@ -2840,9 +2807,10 @@ scoped_refptr<ComputedStyle> Element::StyleForLayoutObject() {
if (ElementAnimations* element_animations = GetElementAnimations())
element_animations->CssAnimations().ClearPendingUpdate();
- scoped_refptr<ComputedStyle> style = HasCustomStyleCallbacks()
- ? CustomStyleForLayoutObject()
- : OriginalStyleForLayoutObject();
+ scoped_refptr<ComputedStyle> style =
+ HasCustomStyleCallbacks()
+ ? CustomStyleForLayoutObject(style_recalc_context)
+ : OriginalStyleForLayoutObject(style_recalc_context);
if (!style) {
DCHECK(IsPseudoElement());
return nullptr;
@@ -2861,8 +2829,10 @@ scoped_refptr<ComputedStyle> Element::StyleForLayoutObject() {
return style;
}
-scoped_refptr<ComputedStyle> Element::OriginalStyleForLayoutObject() {
- return GetDocument().GetStyleResolver().StyleForElement(this);
+scoped_refptr<ComputedStyle> Element::OriginalStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
+ return GetDocument().GetStyleResolver().StyleForElement(this,
+ style_recalc_context);
}
void Element::RecalcStyleForTraversalRootAncestor() {
@@ -2872,7 +2842,8 @@ void Element::RecalcStyleForTraversalRootAncestor() {
DidRecalcStyle({});
}
-void Element::RecalcStyle(const StyleRecalcChange change) {
+void Element::RecalcStyle(const StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(InActiveDocument());
DCHECK(GetDocument().InStyleRecalc());
DCHECK(!GetDocument().Lifecycle().InDetach());
@@ -2881,9 +2852,9 @@ void Element::RecalcStyle(const StyleRecalcChange change) {
if (HasCustomStyleCallbacks())
WillRecalcStyle(change);
- StyleRecalcChange child_change = change.ForChildren();
+ StyleRecalcChange child_change = change.ForChildren(*this);
if (change.ShouldRecalcStyleFor(*this)) {
- child_change = RecalcOwnStyle(change);
+ child_change = RecalcOwnStyle(change, style_recalc_context);
if (GetStyleChangeType() == kSubtreeStyleChange)
child_change = child_change.ForceRecalcDescendants();
ClearNeedsStyleRecalc();
@@ -2921,35 +2892,41 @@ void Element::RecalcStyle(const StyleRecalcChange change) {
return;
}
+ StyleRecalcContext child_recalc_context = style_recalc_context;
+
+ if (LayoutObject* layout_object = GetLayoutObject()) {
+ if (layout_object->IsContainerForContainerQueries())
+ child_recalc_context.cq_evaluator = GetContainerQueryEvaluator();
+ }
+
if (child_change.TraversePseudoElements(*this)) {
- UpdatePseudoElement(kPseudoIdBackdrop, child_change);
- UpdatePseudoElement(kPseudoIdMarker, child_change);
- UpdatePseudoElement(kPseudoIdBefore, child_change);
+ UpdatePseudoElement(kPseudoIdBackdrop, child_change, child_recalc_context);
+ UpdatePseudoElement(kPseudoIdMarker, child_change, child_recalc_context);
+ UpdatePseudoElement(kPseudoIdBefore, child_change, child_recalc_context);
}
if (child_change.TraverseChildren(*this)) {
SelectorFilterParentScope filter_scope(*this);
- if (IsActiveV0InsertionPoint(*this)) {
- To<V0InsertionPoint>(this)->RecalcStyleForInsertionPointChildren(
- child_change);
- } else if (ShadowRoot* root = GetShadowRoot()) {
- root->RecalcDescendantStyles(child_change);
+ if (ShadowRoot* root = GetShadowRoot()) {
+ root->RecalcDescendantStyles(child_change, child_recalc_context);
// Sad panda. This is only to clear ensured ComputedStyles for elements
// outside the flat tree for getComputedStyle() in the cases where we
// kSubtreeStyleChange. Style invalidation and kLocalStyleChange will
// make sure we clear out-of-date ComputedStyles outside the flat tree
// in Element::EnsureComputedStyle().
- if (child_change.RecalcDescendants())
- RecalcDescendantStyles(StyleRecalcChange::kClearEnsured);
+ if (child_change.RecalcDescendants()) {
+ RecalcDescendantStyles(StyleRecalcChange::kClearEnsured,
+ child_recalc_context);
+ }
} else if (auto* slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(this)) {
- slot->RecalcStyleForSlotChildren(child_change);
+ slot->RecalcStyleForSlotChildren(child_change, child_recalc_context);
} else {
- RecalcDescendantStyles(child_change);
+ RecalcDescendantStyles(child_change, child_recalc_context);
}
}
if (child_change.TraversePseudoElements(*this)) {
- UpdatePseudoElement(kPseudoIdAfter, child_change);
+ UpdatePseudoElement(kPseudoIdAfter, child_change, child_recalc_context);
// If we are re-attaching us or any of our descendants, we need to attach
// the descendants before we know if this element generates a ::first-letter
@@ -3002,21 +2979,10 @@ static const StyleRecalcChange ApplyComputedStyleDiff(
return change.EnsureAtLeast(StyleRecalcChange::kUpdatePseudoElements);
}
-StyleRecalcChange Element::RecalcOwnStyle(const StyleRecalcChange change) {
+StyleRecalcChange Element::RecalcOwnStyle(
+ const StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(GetDocument().InStyleRecalc());
- if (!CanParticipateInFlatTree()) {
- // This is a V0InsertionPoint. This whole block can be removed when Shadow
- // DOM V0 is removed.
- DCHECK(IsV0InsertionPoint());
- if (NeedsStyleRecalc())
- SetComputedStyle(nullptr);
- if (GetForceReattachLayoutTree())
- return change.ForceReattachLayoutTree();
- // Keep recalculating computed style for fallback children as if they were
- // children of the insertion point parent.
- return change;
- }
-
if (change.RecalcChildren() && HasRareData() && NeedsStyleRecalc()) {
// This element needs recalc because its parent changed inherited
// properties or there was some style change in the ancestry which needed a
@@ -3030,7 +2996,7 @@ StyleRecalcChange Element::RecalcOwnStyle(const StyleRecalcChange change) {
scoped_refptr<ComputedStyle> new_style;
scoped_refptr<const ComputedStyle> old_style = GetComputedStyle();
- StyleRecalcChange child_change = change.ForChildren();
+ StyleRecalcChange child_change = change.ForChildren(*this);
if (ParentComputedStyle()) {
if (old_style && change.IndependentInherit()) {
@@ -3040,7 +3006,7 @@ StyleRecalcChange Element::RecalcOwnStyle(const StyleRecalcChange change) {
new_style = PropagateInheritedProperties();
}
if (!new_style)
- new_style = StyleForLayoutObject();
+ new_style = StyleForLayoutObject(style_recalc_context);
if (new_style && !ShouldStoreComputedStyle(*new_style))
new_style = nullptr;
}
@@ -3108,7 +3074,7 @@ StyleRecalcChange Element::RecalcOwnStyle(const StyleRecalcChange change) {
// context and as a result need to process more of the subtree than we would
// normally. Note that if this is not the first time, then
// AdjustStyleRecalcChangeForChildren() won't do any adjustments.
- if (!context->IsLocked())
+ if (context->ShouldStyleChildren())
child_change = context->AdjustStyleRecalcChangeForChildren(child_change);
}
@@ -3177,8 +3143,7 @@ void Element::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
// layout tree siblings.
WhitespaceAttacher local_attacher;
WhitespaceAttacher* child_attacher;
- if (GetLayoutObject() ||
- (!HasDisplayContentsStyle() && CanParticipateInFlatTree())) {
+ if (GetLayoutObject() || !HasDisplayContentsStyle()) {
whitespace_attacher.DidVisitElement(this);
if (GetDocument().GetStyleEngine().NeedsWhitespaceReattachment(this))
local_attacher.SetReattachAllWhitespaceNodes();
@@ -3235,6 +3200,9 @@ void Element::RebuildFirstLetterLayoutTree() {
// up here for #outer after AttachLayoutTree is called on #inner at which
// point the layout sub-tree is available for deciding on creating the
// ::first-letter.
+ StyleEngine::AllowMarkForReattachFromRebuildLayoutTreeScope scope(
+ GetDocument().GetStyleEngine());
+
UpdateFirstLetterPseudoElement(StyleUpdatePhase::kRebuildLayoutTree);
if (PseudoElement* element = GetPseudoElement(kPseudoIdFirstLetter)) {
WhitespaceAttacher whitespace_attacher;
@@ -3259,8 +3227,11 @@ void Element::RebuildMarkerLayoutTree(WhitespaceAttacher& whitespace_attacher) {
// The layout tree rebuilding for markers should be done similarly to how
// it is done for ::first-letter.
if (LayoutObject* layout_object = GetLayoutObject()) {
- if (layout_object->IsListItem() && !marker->GetLayoutObject())
+ if (layout_object->IsListItem() && !marker->GetLayoutObject()) {
+ StyleEngine::AllowMarkForReattachFromRebuildLayoutTreeScope scope(
+ GetDocument().GetStyleEngine());
marker->SetNeedsReattachLayoutTree();
+ }
}
if (marker->NeedsRebuildLayoutTree(whitespace_attacher))
@@ -3308,8 +3279,6 @@ ShadowRoot& Element::CreateAndAttachShadowRoot(ShadowRootType type) {
EnsureElementRareData().SetShadowRoot(*shadow_root);
shadow_root->SetParentOrShadowHostNode(this);
shadow_root->SetParentTreeScope(GetTreeScope());
- if (type == ShadowRootType::V0)
- shadow_root->SetNeedsDistributionRecalc();
shadow_root->InsertedInto(*this);
probe::DidPushShadowRoot(this, shadow_root);
@@ -3321,6 +3290,26 @@ ShadowRoot* Element::GetShadowRoot() const {
return HasRareData() ? GetElementRareData()->GetShadowRoot() : nullptr;
}
+EditContext* Element::editContext() const {
+ return HasRareData() ? GetElementRareData()->GetEditContext() : nullptr;
+}
+
+void Element::setEditContext(EditContext* edit_context) {
+ EnsureElementRareData().SetEditContext(edit_context);
+
+ // An element is considered editable if there is an active EditContext
+ // associated with the element.
+ if (auto* frame = GetDocument().GetFrame()) {
+ if (frame->GetInputMethodController().GetActiveEditContext()) {
+ MutableCSSPropertyValueSet& style = EnsureMutableInlineStyle();
+ AddPropertyToPresentationAttributeStyle(
+ &style, CSSPropertyID::kWebkitUserModify,
+ edit_context ? CSSValueID::kReadWrite : CSSValueID::kReadOnly);
+ InlineStyleChanged();
+ }
+ }
+}
+
void Element::PseudoStateChanged(CSSSelector::PseudoType pseudo) {
// We can't schedule invaliation sets from inside style recalc otherwise
// we'd never process them.
@@ -3374,20 +3363,6 @@ void Element::SetNeedsCompositingUpdate() {
layout_object->SetNeedsPaintPropertyUpdate();
}
-void Element::V0SetCustomElementDefinition(
- V0CustomElementDefinition* definition) {
- if (!HasRareData() && !definition)
- return;
- DCHECK(!GetV0CustomElementDefinition());
- EnsureElementRareData().V0SetCustomElementDefinition(definition);
-}
-
-V0CustomElementDefinition* Element::GetV0CustomElementDefinition() const {
- if (HasRareData())
- return GetElementRareData()->GetV0CustomElementDefinition();
- return nullptr;
-}
-
void Element::SetCustomElementDefinition(CustomElementDefinition* definition) {
DCHECK(definition);
DCHECK(!GetCustomElementDefinition());
@@ -3428,60 +3403,11 @@ const ElementInternals* Element::GetElementInternals() const {
return HasRareData() ? GetElementRareData()->GetElementInternals() : nullptr;
}
-ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) {
- // TODO(crbug.com/937746): Anything caught by this DCHECK is using the
- // now-removed Shadow DOM v0 API.
- DCHECK(false) << "Shadow DOM v0 has been removed.";
-
- DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled());
- if (ShadowRoot* root = GetShadowRoot()) {
- if (root->IsUserAgent()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "Shadow root cannot be created on a host which already hosts a "
- "user-agent shadow tree.");
- } else {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "Shadow root cannot be created on a host which already hosts a "
- "shadow tree.");
- }
- return nullptr;
- }
- if (AlwaysCreateUserAgentShadowRoot()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "Shadow root cannot be created on a host which already hosts a "
- "user-agent shadow tree.");
- return nullptr;
- }
- // Some elements make assumptions about what kind of layoutObjects they allow
- // as children so we can't allow author shadows on them for now.
- if (!AreAuthorShadowsAllowed()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kHierarchyRequestError,
- "Author-created shadow roots are disabled for this element.");
- return nullptr;
- }
-
- return &CreateShadowRootInternal();
-}
-
-ShadowRoot& Element::CreateShadowRootInternal() {
- DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled());
- DCHECK(!ClosedShadowRoot());
- DCHECK(AreAuthorShadowsAllowed());
- DCHECK(!AlwaysCreateUserAgentShadowRoot());
- GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
- return CreateAndAttachShadowRoot(ShadowRootType::V0);
-}
-
bool Element::CanAttachShadowRoot() const {
const AtomicString& tag_name = localName();
- // Checking Is{V0}CustomElement() here is just an optimization
+ // Checking IsCustomElement() here is just an optimization
// because IsValidName is not cheap.
return (IsCustomElement() && CustomElement::IsValidName(tag_name)) ||
- (IsV0CustomElement() && V0CustomElement::IsValidName(tag_name)) ||
tag_name == html_names::kArticleTag ||
tag_name == html_names::kAsideTag ||
tag_name == html_names::kBlockquoteTag ||
@@ -3492,6 +3418,7 @@ bool Element::CanAttachShadowRoot() const {
tag_name == html_names::kH6Tag || tag_name == html_names::kHeaderTag ||
tag_name == html_names::kNavTag || tag_name == html_names::kMainTag ||
tag_name == html_names::kPTag || tag_name == html_names::kSectionTag ||
+ tag_name == html_names::kSelectmenuTag ||
tag_name == html_names::kSpanTag;
}
@@ -3617,7 +3544,7 @@ ShadowRoot& Element::AttachShadowRootInternal(
<< type;
DCHECK(!AlwaysCreateUserAgentShadowRoot());
- GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV1);
+ GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascade);
if (auto* shadow_root = GetShadowRoot()) {
// NEW. If shadow host has a non-null shadow root whose "is declarative
@@ -3651,12 +3578,7 @@ ShadowRoot& Element::AttachShadowRootInternal(
ShadowRoot* Element::OpenShadowRoot() const {
ShadowRoot* root = GetShadowRoot();
- if (!root)
- return nullptr;
- return root->GetType() == ShadowRootType::V0 ||
- root->GetType() == ShadowRootType::kOpen
- ? root
- : nullptr;
+ return root && root->GetType() == ShadowRootType::kOpen ? root : nullptr;
}
ShadowRoot* Element::ClosedShadowRoot() const {
@@ -3749,7 +3671,7 @@ void Element::ChildrenChanged(const ChildrenChange& change) {
change.sibling_after_change);
if (ShadowRoot* shadow_root = GetShadowRoot())
- shadow_root->SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc();
+ shadow_root->SetNeedsAssignmentRecalc();
}
void Element::FinishParsingChildren() {
@@ -4218,7 +4140,6 @@ bool Element::ActivateDisplayLockIfNeeded(DisplayLockActivationReason reason) {
.GetDisplayLockDocumentState()
.DisplayLockBlockingAllActivationCount())
return false;
- const_cast<Element*>(this)->UpdateDistributionForFlatTreeTraversal();
HeapVector<std::pair<Member<Element>, Member<Element>>> activatable_targets;
for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(*this)) {
@@ -4257,7 +4178,6 @@ bool Element::DisplayLockPreventsActivation(
if (GetDocument().GetDisplayLockDocumentState().LockedDisplayLockCount() == 0)
return false;
- const_cast<Element*>(this)->UpdateDistributionForFlatTreeTraversal();
// TODO(vmpstr): Similar to Document::EnsurePaintLocationDataValidForNode(),
// this iterates up to the ancestor hierarchy looking for locked display
// locks. This is inefficient, particularly since it's unlikely that this will
@@ -4341,29 +4261,26 @@ void Element::UpdateForceLegacyLayout(const ComputedStyle& new_style,
void Element::ForceLegacyLayoutInFormattingContext(
const ComputedStyle& new_style) {
- // TableNG requires that table elements are either all NG, or all Legacy.
- bool needs_traverse_to_table =
- RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
- new_style.IsDisplayTableType();
- bool found_bfc = DefinitelyNewFormattingContext(*this, new_style);
- for (Element* ancestor = this; !found_bfc || needs_traverse_to_table;) {
+ bool found_fc = DefinitelyNewFormattingContext(*this, new_style);
+
+ for (Element* ancestor = this; !found_fc;) {
ancestor =
DynamicTo<Element>(LayoutTreeBuilderTraversal::Parent(*ancestor));
- if (!ancestor || ancestor->ShouldForceLegacyLayout())
+ if (!ancestor || ancestor->ShouldForceLegacyLayoutForChild())
break;
const ComputedStyle* style = ancestor->GetComputedStyle();
+
+ // Some layout types, such as MathML and custom layout, are only implemented
+ // in LayoutNG. We cannot fall back to legacy layout for such elements. If
+ // some descendant wants legacy fallback, while some ancestor in the same
+ // formatting context doesn't support legacy layout, we have ended up in an
+ // impossible situation.
+ DCHECK(!style->DisplayTypeRequiresLayoutNG());
+
if (style->Display() == EDisplay::kNone)
break;
- found_bfc = found_bfc || DefinitelyNewFormattingContext(*ancestor, *style);
- if (found_bfc && !needs_traverse_to_table) {
- needs_traverse_to_table =
- RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
- style->IsDisplayTableType();
- }
- if (needs_traverse_to_table) {
- if (style->IsDisplayTableBox())
- needs_traverse_to_table = false;
- }
+
+ found_fc = DefinitelyNewFormattingContext(*ancestor, *style);
ancestor->SetShouldForceLegacyLayoutForChild(true);
ancestor->SetNeedsReattachLayoutTree();
}
@@ -4464,16 +4381,14 @@ String Element::outerHTML() const {
}
void Element::SetInnerHTMLInternal(const String& html,
- const SetInnerHTMLOptions* options,
+ bool include_shadow_roots,
ExceptionState& exception_state) {
if (html.IsEmpty() && !HasNonInBodyInsertionMode()) {
setTextContent(html);
} else {
- bool allow_shadow_root =
- options->hasAllowShadowRoot() && options->allowShadowRoot();
if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
- html, this, kAllowScriptingContent, "innerHTML", allow_shadow_root,
- exception_state)) {
+ html, this, kAllowScriptingContent, "innerHTML",
+ include_shadow_roots, exception_state)) {
ContainerNode* container = this;
if (auto* template_element = DynamicTo<HTMLTemplateElement>(*this)) {
// Allow replacing innerHTML on declarative shadow templates, prior to
@@ -4490,16 +4405,13 @@ void Element::SetInnerHTMLInternal(const String& html,
void Element::setInnerHTML(const String& html,
ExceptionState& exception_state) {
probe::BreakableLocation(GetExecutionContext(), "Element.setInnerHTML");
- const SetInnerHTMLOptions options;
- SetInnerHTMLInternal(html, &options, exception_state);
+ SetInnerHTMLInternal(html, /*include_shadow_roots=*/false, exception_state);
}
-void Element::setInnerHTMLWithOptions(const String& html,
- const SetInnerHTMLOptions* options,
- ExceptionState& exception_state) {
- DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
- GetExecutionContext()));
- SetInnerHTMLInternal(html, options, exception_state);
+void Element::setInnerHTMLWithDeclarativeShadowDOMForTesting(
+ const String& html) {
+ SetInnerHTMLInternal(html, /*include_shadow_roots=*/true,
+ ASSERT_NO_EXCEPTION);
}
String Element::getInnerHTML(const GetInnerHTMLOptions* options) const {
@@ -4541,7 +4453,7 @@ void Element::setOuterHTML(const String& html,
DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
html, parent, kAllowScriptingContent, "outerHTML",
- /*allow_shadow_root=*/false, exception_state);
+ /*include_shadow_roots=*/false, exception_state);
if (exception_state.HadException())
return;
@@ -4652,17 +4564,29 @@ Element::EnsureResizeObserverData() {
return EnsureElementRareData().EnsureResizeObserverData();
}
-DisplayLockContext* Element::GetDisplayLockContext() const {
+DisplayLockContext* Element::GetDisplayLockContextFromRareData() const {
if (!RuntimeEnabledFeatures::CSSContentVisibilityEnabled())
return nullptr;
- return HasRareData() ? GetElementRareData()->GetDisplayLockContext()
- : nullptr;
+ DCHECK(HasDisplayLockContext());
+ DCHECK(HasRareData());
+ return GetElementRareData()->GetDisplayLockContext();
}
DisplayLockContext& Element::EnsureDisplayLockContext() {
+ SetHasDisplayLockContext();
return *EnsureElementRareData().EnsureDisplayLockContext(this);
}
+ContainerQueryEvaluator* Element::GetContainerQueryEvaluator() const {
+ if (HasRareData())
+ return GetElementRareData()->GetContainerQueryEvaluator();
+ return nullptr;
+}
+
+void Element::SetContainerQueryEvaluator(ContainerQueryEvaluator* evaluator) {
+ EnsureElementRareData().SetContainerQueryEvaluator(evaluator);
+}
+
// Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
static Node* ContextNodeForInsertion(const String& where,
Element* element,
@@ -4723,7 +4647,7 @@ void Element::insertAdjacentHTML(const String& where,
// Step 3 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
markup, context_element, kAllowScriptingContent, "insertAdjacentHTML",
- /*allow_shadow_root=*/false, exception_state);
+ /*include_shadow_roots=*/false, exception_state);
if (!fragment)
return;
InsertAdjacent(where, fragment, exception_state);
@@ -4850,6 +4774,29 @@ bool Element::IsInDescendantTreeOf(const Element* shadow_host) const {
return false;
}
+namespace {
+
+bool NeedsEnsureComputedStyle(Element& element) {
+ const ComputedStyle* style = element.GetComputedStyle();
+ return !style || style->IsEnsuredOutsideFlatTree();
+}
+
+HeapVector<Member<Element>> CollectAncestorsToEnsure(Element& element) {
+ HeapVector<Member<Element>> ancestors;
+
+ Element* ancestor = &element;
+ while ((ancestor = DynamicTo<Element>(
+ LayoutTreeBuilderTraversal::Parent(*ancestor)))) {
+ if (!NeedsEnsureComputedStyle(*ancestor))
+ break;
+ ancestors.push_back(ancestor);
+ }
+
+ return ancestors;
+}
+
+} // namespace
+
const ComputedStyle* Element::EnsureComputedStyle(
PseudoId pseudo_element_specifier) {
if (PseudoElement* element = GetPseudoElement(pseudo_element_specifier))
@@ -4875,33 +4822,51 @@ const ComputedStyle* Element::EnsureComputedStyle(
DCHECK(!GetDocument().NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(
*this, true /* ignore_adjacent_style */));
+ // Retrieve a list of (non-inclusive) ancestors that we need to ensure the
+ // ComputedStyle for *before* we can ensure the ComputedStyle for this
+ // element. Note that the list of ancestors can be empty if |this| is the
+ // root of the display:none subtree.
+ //
+ // The front() element is the LayoutTreeBuilderTraversal::Parent of |this|,
+ // and the back() element is the "top-most" ancestor in the chain.
+ HeapVector<Member<Element>> ancestors = CollectAncestorsToEnsure(*this);
+
+ Element* top = ancestors.IsEmpty() ? this : ancestors.back().Get();
+ auto style_recalc_context =
+ RuntimeEnabledFeatures::CSSContainerQueriesEnabled()
+ ? StyleRecalcContext::FromAncestors(*top)
+ : StyleRecalcContext();
+
+ while (!ancestors.IsEmpty()) {
+ Element* ancestor = ancestors.back();
+ ancestors.pop_back();
+ ancestor->EnsureOwnComputedStyle(style_recalc_context, kPseudoIdNone);
+ }
+
+ return EnsureOwnComputedStyle(style_recalc_context, pseudo_element_specifier);
+}
+
+const ComputedStyle* Element::EnsureOwnComputedStyle(
+ const StyleRecalcContext& style_recalc_context,
+ PseudoId pseudo_element_specifier) {
// FIXME: Find and use the layoutObject from the pseudo element instead of the
// actual element so that the 'length' properties, which are only known by the
// layoutObject because it did the layout, will be correct and so that the
// values returned for the ":selection" pseudo-element will be correct.
const ComputedStyle* element_style = GetComputedStyle();
- if (!element_style || element_style->IsEnsuredOutsideFlatTree()) {
- if (CanParticipateInFlatTree()) {
- if (ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*this)) {
- parent->EnsureComputedStyle();
- if (element_style)
- element_style = GetComputedStyle();
- }
- if (element_style && NeedsStyleRecalc()) {
- // RecalcStyle() will not traverse into connected elements outside the
- // flat tree and we may have a dirty element or ancestors if this
- // element is not in the flat tree. If we don't need a style recalc,
- // we can just re-use the ComputedStyle from the last
- // getComputedStyle(). Otherwise, we need to clear the ensured styles
- // for the uppermost dirty ancestor and all of its descendants. If
- // this element was not the uppermost dirty element, we would not end
- // up here because a dirty ancestor would have cleared the
- // ComputedStyle in the recursive call above and element_style would
- // have been null.
- GetDocument().GetStyleEngine().ClearEnsuredDescendantStyles(*this);
- element_style = nullptr;
- }
- } else {
+ if (NeedsEnsureComputedStyle(*this)) {
+ if (element_style && NeedsStyleRecalc()) {
+ // RecalcStyle() will not traverse into connected elements outside the
+ // flat tree and we may have a dirty element or ancestors if this
+ // element is not in the flat tree. If we don't need a style recalc,
+ // we can just re-use the ComputedStyle from the last
+ // getComputedStyle(). Otherwise, we need to clear the ensured styles
+ // for the uppermost dirty ancestor and all of its descendants. If
+ // this element was not the uppermost dirty element, we would not end
+ // up here because a dirty ancestor would have cleared the
+ // ComputedStyle via EnsureComputedStyle and element_style would
+ // have been null.
+ GetDocument().GetStyleEngine().ClearEnsuredDescendantStyles(*this);
element_style = nullptr;
}
if (!element_style) {
@@ -4909,9 +4874,9 @@ const ComputedStyle* Element::EnsureComputedStyle(
// TODO(crbug.com/953707): Avoid setting inline style during
// HTMLImageElement::CustomStyleForLayoutObject.
if (HasCustomStyleCallbacks() && !IsA<HTMLImageElement>(*this))
- new_style = CustomStyleForLayoutObject();
+ new_style = CustomStyleForLayoutObject(style_recalc_context);
else
- new_style = OriginalStyleForLayoutObject();
+ new_style = OriginalStyleForLayoutObject(style_recalc_context);
element_style = new_style.get();
new_style->SetIsEnsuredInDisplayNone();
SetComputedStyle(std::move(new_style));
@@ -4935,7 +4900,7 @@ const ComputedStyle* Element::EnsureComputedStyle(
scoped_refptr<ComputedStyle> result =
GetDocument().GetStyleResolver().PseudoStyleForElement(
- this,
+ this, style_recalc_context,
PseudoElementStyleRequest(
pseudo_element_specifier,
PseudoElementStyleRequest::kForComputedStyle),
@@ -5026,9 +4991,13 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
// The StyleUpdatePhase tells where we are in the process of updating style
// and layout tree.
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+
PseudoElement* element = GetPseudoElement(kPseudoIdFirstLetter);
if (!element) {
- element = CreatePseudoElementIfNeeded(kPseudoIdFirstLetter);
+ element =
+ CreatePseudoElementIfNeeded(kPseudoIdFirstLetter, style_recalc_context);
// If we are in Element::AttachLayoutTree, don't mess up the ancestor flags
// for layout tree attachment/rebuilding. We will unconditionally call
// AttachLayoutTree for the created pseudo element immediately after this
@@ -5066,7 +5035,8 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
// RemainingTextLayoutObject should have been cleared from DetachLayoutTree.
DCHECK(!To<FirstLetterPseudoElement>(element)->RemainingTextLayoutObject());
DCHECK(text_node_changed);
- scoped_refptr<ComputedStyle> pseudo_style = element->StyleForLayoutObject();
+ scoped_refptr<ComputedStyle> pseudo_style =
+ element->StyleForLayoutObject(style_recalc_context);
if (PseudoElementLayoutObjectIsNeeded(pseudo_style.get(), this))
element->SetComputedStyle(std::move(pseudo_style));
else
@@ -5081,7 +5051,8 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
if (text_node_changed || remaining_text_layout_object->PreviousSibling() !=
element->GetLayoutObject())
change = change.ForceReattachLayoutTree();
- element->RecalcStyle(change);
+
+ element->RecalcStyle(change, style_recalc_context);
if (element->NeedsReattachLayoutTree() &&
!PseudoElementLayoutObjectIsNeeded(element->GetComputedStyle(), this)) {
@@ -5090,13 +5061,17 @@ void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
}
}
-void Element::UpdatePseudoElement(PseudoId pseudo_id,
- const StyleRecalcChange change) {
+void Element::UpdatePseudoElement(
+ PseudoId pseudo_id,
+ const StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
PseudoElement* element = GetPseudoElement(pseudo_id);
if (!element) {
- if ((element = CreatePseudoElementIfNeeded(pseudo_id))) {
+ if ((element =
+ CreatePseudoElementIfNeeded(pseudo_id, style_recalc_context))) {
// ::before and ::after can have a nested ::marker
- element->CreatePseudoElementIfNeeded(kPseudoIdMarker);
+ element->CreatePseudoElementIfNeeded(kPseudoIdMarker,
+ style_recalc_context);
element->SetNeedsReattachLayoutTree();
}
return;
@@ -5104,7 +5079,7 @@ void Element::UpdatePseudoElement(PseudoId pseudo_id,
if (change.ShouldUpdatePseudoElement(*element)) {
if (CanGeneratePseudoElement(pseudo_id)) {
- element->RecalcStyle(change.ForPseudoElement());
+ element->RecalcStyle(change.ForPseudoElement(), style_recalc_context);
if (!element->NeedsReattachLayoutTree())
return;
if (PseudoElementLayoutObjectIsNeeded(element->GetComputedStyle(), this))
@@ -5115,7 +5090,9 @@ void Element::UpdatePseudoElement(PseudoId pseudo_id,
}
}
-PseudoElement* Element::CreatePseudoElementIfNeeded(PseudoId pseudo_id) {
+PseudoElement* Element::CreatePseudoElementIfNeeded(
+ PseudoId pseudo_id,
+ const StyleRecalcContext& style_recalc_context) {
if (!CanGeneratePseudoElement(pseudo_id))
return nullptr;
if (pseudo_id == kPseudoIdFirstLetter) {
@@ -5128,7 +5105,7 @@ PseudoElement* Element::CreatePseudoElementIfNeeded(PseudoId pseudo_id) {
pseudo_element->InsertedInto(*this);
scoped_refptr<ComputedStyle> pseudo_style =
- pseudo_element->StyleForLayoutObject();
+ pseudo_element->StyleForLayoutObject(style_recalc_context);
if (!PseudoElementLayoutObjectIsNeeded(pseudo_style.get(), this)) {
GetElementRareData()->SetPseudoElement(pseudo_id, nullptr);
return nullptr;
@@ -5214,13 +5191,23 @@ const ComputedStyle* Element::CachedStyleForPseudoElement(
style->GetCachedPseudoElementStyle(request.pseudo_id))
return cached;
- scoped_refptr<ComputedStyle> result = StyleForPseudoElement(request, style);
+ scoped_refptr<ComputedStyle> result =
+ UncachedStyleForPseudoElement(request, style);
if (result)
return style->AddCachedPseudoElementStyle(std::move(result));
return nullptr;
}
+scoped_refptr<ComputedStyle> Element::UncachedStyleForPseudoElement(
+ const PseudoElementStyleRequest& request,
+ const ComputedStyle* parent_style) {
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+ return StyleForPseudoElement(style_recalc_context, request, parent_style);
+}
+
scoped_refptr<ComputedStyle> Element::StyleForPseudoElement(
+ const StyleRecalcContext& style_recalc_context,
const PseudoElementStyleRequest& request,
const ComputedStyle* parent_style) {
const ComputedStyle* style = GetComputedStyle();
@@ -5243,22 +5230,30 @@ scoped_refptr<ComputedStyle> Element::StyleForPseudoElement(
}
}
return GetDocument().GetStyleResolver().PseudoStyleForElement(
- this, request, style, layout_parent_style);
+ this, style_recalc_context, request, style, layout_parent_style);
}
if (!parent_style)
parent_style = style;
if (request.pseudo_id == kPseudoIdFirstLineInherited) {
- scoped_refptr<ComputedStyle> result =
- GetDocument().GetStyleResolver().StyleForElement(this, parent_style,
- parent_style);
- result->SetStyleType(kPseudoIdFirstLineInherited);
+ scoped_refptr<ComputedStyle> result;
+ if (IsPseudoElement()) {
+ result = GetDocument().GetStyleResolver().PseudoStyleForElement(
+ parentElement(), style_recalc_context,
+ PseudoElementStyleRequest(To<PseudoElement>(this)->GetPseudoId()),
+ parent_style, parent_style);
+ } else {
+ result = GetDocument().GetStyleResolver().StyleForElement(
+ this, style_recalc_context, parent_style, parent_style);
+ }
+ if (result)
+ result->SetStyleType(kPseudoIdFirstLineInherited);
return result;
}
return GetDocument().GetStyleResolver().PseudoStyleForElement(
- this, request, parent_style, parent_style);
+ this, style_recalc_context, request, parent_style, parent_style);
}
bool Element::CanGeneratePseudoElement(PseudoId pseudo_id) const {
@@ -5490,7 +5485,7 @@ ScriptValue Element::requestPointerLock(ScriptState* script_state,
GetExecutionContext())) {
if (exception_state.HadException())
resolver->Reject(exception_state);
- return promise.GetScriptValue();
+ return promise.AsScriptValue();
}
// The current spec for PointerLock does not have any language about throwing
@@ -5610,18 +5605,14 @@ void Element::WillModifyAttribute(const QualifiedName& name,
if (old_value != new_value) {
GetDocument().GetStyleEngine().AttributeChangedForElement(name, *this);
- if (IsUpgradedV0CustomElement()) {
- V0CustomElement::AttributeDidChange(this, name.LocalName(), old_value,
- new_value);
- }
}
if (MutationObserverInterestGroup* recipients =
MutationObserverInterestGroup::CreateForAttributesMutation(*this,
- name))
+ name)) {
recipients->EnqueueMutationRecord(
MutationRecord::CreateAttributes(this, name, old_value));
-
+ }
probe::WillModifyDOMAttr(this, old_value, new_value);
}
@@ -5809,45 +5800,6 @@ void Element::DetachAllAttrNodesFromElement() {
RemoveAttrNodeList();
}
-Node::InsertionNotificationRequest Node::InsertedInto(
- ContainerNode& insertion_point) {
- DCHECK(!ChildNeedsStyleInvalidation());
- DCHECK(!NeedsStyleInvalidation());
- DCHECK(insertion_point.isConnected() || insertion_point.IsInShadowTree() ||
- IsContainerNode());
- if (insertion_point.isConnected()) {
- SetFlag(kIsConnectedFlag);
- insertion_point.GetDocument().IncrementNodeCount();
- }
- if (ParentOrShadowHostNode()->IsInShadowTree())
- SetFlag(kIsInShadowTreeFlag);
- if (ChildNeedsDistributionRecalc() &&
- !insertion_point.ChildNeedsDistributionRecalc())
- insertion_point.MarkAncestorsWithChildNeedsDistributionRecalc();
- if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
- cache->ChildrenChanged(&insertion_point);
- return kInsertionDone;
-}
-
-void Node::RemovedFrom(ContainerNode& insertion_point) {
- DCHECK(insertion_point.isConnected() || IsContainerNode() ||
- IsInShadowTree());
- if (insertion_point.isConnected()) {
- ClearNeedsStyleRecalc();
- ClearChildNeedsStyleRecalc();
- ClearNeedsStyleInvalidation();
- ClearChildNeedsStyleInvalidation();
- ClearFlag(kIsConnectedFlag);
- insertion_point.GetDocument().DecrementNodeCount();
- }
- if (IsInShadowTree() && !ContainingTreeScope().RootNode().IsShadowRoot())
- ClearFlag(kIsInShadowTreeFlag);
- if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) {
- cache->Remove(this);
- cache->ChildrenChanged(&insertion_point);
- }
-}
-
void Element::WillRecalcStyle(const StyleRecalcChange) {
DCHECK(HasCustomStyleCallbacks());
}
@@ -5856,9 +5808,10 @@ void Element::DidRecalcStyle(const StyleRecalcChange) {
DCHECK(HasCustomStyleCallbacks());
}
-scoped_refptr<ComputedStyle> Element::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> Element::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
DCHECK(HasCustomStyleCallbacks());
- return OriginalStyleForLayoutObject();
+ return OriginalStyleForLayoutObject(style_recalc_context);
}
void Element::CloneAttributesFrom(const Element& other) {
@@ -6155,8 +6108,7 @@ CSSPropertyValueSet* Element::CreatePresentationAttributeStyle() {
AttributeCollection attributes = AttributesWithoutUpdate();
for (const Attribute& attr : attributes)
CollectStyleForPresentationAttribute(attr.GetName(), attr.Value(), style);
- if (IsSVGElement())
- To<SVGElement>(this)->CollectStyleForAnimatedPresentationAttributes(style);
+ CollectExtraStyleForPresentationAttribute(style);
return style;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/element.h b/chromium/third_party/blink/renderer/core/dom/element.h
index d99e36e734e..606e36c0f78 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.h
+++ b/chromium/third_party/blink/renderer/core/dom/element.h
@@ -35,11 +35,14 @@
#include "third_party/blink/renderer/core/dom/container_node.h"
#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/dom/element_data.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/names_map.h"
#include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
@@ -58,6 +61,7 @@ class DOMStringMap;
class DOMTokenList;
class DisplayLockContext;
class Document;
+class EditContext;
class ElementAnimations;
class ElementInternals;
class ElementIntersectionObserverData;
@@ -66,7 +70,6 @@ class ExceptionState;
class FloatQuad;
class FloatSize;
class FocusOptions;
-class SetInnerHTMLOptions;
class GetInnerHTMLOptions;
class HTMLTemplateElement;
class Image;
@@ -88,7 +91,7 @@ class SpaceSplitString;
class StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL;
class StylePropertyMap;
class StylePropertyMapReadOnly;
-class V0CustomElementDefinition;
+class StyleRecalcContext;
enum class CSSPropertyID;
enum class CSSValueID;
@@ -336,6 +339,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
DocumentUpdateReason reason = DocumentUpdateReason::kUnknown) const;
DOMRectList* getClientRects();
+ FloatRect GetBoundingClientRectNoLifecycleUpdate() const;
DOMRect* getBoundingClientRect();
const AtomicString& computedRole();
@@ -444,6 +448,11 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) {}
+ // Subclasses can override these functions if there is extra style that needs
+ // to be mapped like attributes.
+ virtual bool HasExtraStyleForPresentationAttribute() const { return false; }
+ virtual void CollectExtraStyleForPresentationAttribute(
+ MutableCSSPropertyValueSet*) {}
// For exposing to DOM only.
NamedNodeMap* attributesForBindings() const;
@@ -512,7 +521,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
virtual LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout);
virtual bool LayoutObjectIsNeeded(const ComputedStyle&) const;
- void RecalcStyle(const StyleRecalcChange);
+ void RecalcStyle(const StyleRecalcChange, const StyleRecalcContext&);
void RecalcStyleForTraversalRootAncestor();
void RebuildLayoutTreeForTraversalRootAncestor() {
RebuildFirstLetterLayoutTree();
@@ -521,10 +530,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
}
bool NeedsRebuildLayoutTree(
const WhitespaceAttacher& whitespace_attacher) const {
- // TODO(futhark@chromium.org): !CanParticipateInFlatTree() can be removed
- // when Shadow DOM V0 support is removed.
return NeedsReattachLayoutTree() || ChildNeedsReattachLayoutTree() ||
- !CanParticipateInFlatTree() ||
(whitespace_attacher.TraverseIntoDisplayContents() &&
HasDisplayContentsStyle());
}
@@ -535,12 +541,6 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
void SetNeedsCompositingUpdate();
- // If type of ShadowRoot (either closed or open) is explicitly specified,
- // creation of multiple shadow roots is prohibited in any combination and
- // throws an exception. Multiple shadow roots are allowed only when
- // createShadowRoot() is used without any parameters from JavaScript.
- ShadowRoot* createShadowRoot(ExceptionState&);
-
ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&);
void AttachDeclarativeShadowRoot(HTMLTemplateElement*,
@@ -548,9 +548,6 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
FocusDelegation,
SlotAssignmentMode);
- ShadowRoot& CreateV0ShadowRootForTesting() {
- return CreateShadowRootInternal();
- }
ShadowRoot& CreateUserAgentShadowRoot();
ShadowRoot& AttachShadowRootInternal(
ShadowRootType,
@@ -564,8 +561,6 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
ShadowRoot* AuthorShadowRoot() const;
ShadowRoot* UserAgentShadowRoot() const;
- ShadowRoot* ShadowRootIfV1() const;
-
ShadowRoot& EnsureUserAgentShadowRoot();
bool IsInDescendantTreeOf(const Element* shadow_host) const;
@@ -603,17 +598,11 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
return GetCustomElementState() == CustomElementState::kUncustomized ||
GetCustomElementState() == CustomElementState::kCustom;
}
- bool IsUpgradedV0CustomElement() {
- return GetV0CustomElementState() == kV0Upgraded;
- }
- bool IsUnresolvedV0CustomElement() {
- return GetV0CustomElementState() == kV0WaitingForUpgrade;
- }
AtomicString ComputeInheritedLanguage() const;
Locale& GetLocale() const;
- virtual void AccessKeyAction(bool /*sendToAnyEvent*/) {}
+ virtual void AccessKeyAction(SimulatedClickCreationScope) {}
virtual bool IsURLAttribute(const Attribute&) const { return false; }
virtual bool IsHTMLContentAttribute(const Attribute&) const { return false; }
@@ -681,7 +670,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
Element* new_focused_element,
InputDeviceCapabilities* source_capabilities = nullptr);
- // The implementation of |innerText()| is found in "element_inner_text.cc".
+ // The implementations of |innerText()| and |GetInnerTextWithoutUpdate()| are
+ // found in "element_inner_text.cc".
+ String GetInnerTextWithoutUpdate(); // Avoids layout update.
String innerText();
String outerText();
@@ -698,9 +689,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
String innerHTML() const;
String outerHTML() const;
void setInnerHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);
- void setInnerHTMLWithOptions(const String&,
- const SetInnerHTMLOptions*,
- ExceptionState& = ASSERT_NO_EXCEPTION);
+ void setInnerHTMLWithDeclarativeShadowDOMForTesting(const String& html);
String getInnerHTML(const GetInnerHTMLOptions* options) const;
void setOuterHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);
@@ -732,17 +721,38 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
// parsing a special case in this respect should be avoided if possible.
virtual void FinishParsingChildren();
- void BeginParsingChildren() { SetIsFinishedParsingChildren(false); }
+ virtual void BeginParsingChildren() { SetIsFinishedParsingChildren(false); }
PseudoElement* GetPseudoElement(PseudoId) const;
LayoutObject* PseudoElementLayoutObject(PseudoId) const;
bool PseudoElementStylesDependOnFontMetrics() const;
+
+ // Retrieve the ComputedStyle (if any) corresponding to the provided
+ // PseudoElementStyleRequest from cache, calculating the ComputedStyle
+ // on-demand if it's missing from the cache.
const ComputedStyle* CachedStyleForPseudoElement(
const PseudoElementStyleRequest&);
+
+ // Calculate the ComputedStyle corresponding to the provided
+ // PseudoElementStyleRequest, bypassing the pseudo style cache.
+ //
+ // This is appropriate to use if the cached version is invalid in a given
+ // situation.
+ scoped_refptr<ComputedStyle> UncachedStyleForPseudoElement(
+ const PseudoElementStyleRequest&,
+ const ComputedStyle* parent_style = nullptr);
+
+ // This is the same as UncachedStyleForPseudoElement, except that the caller
+ // must provide an appropriate StyleRecalcContext such that e.g. @container
+ // queries are evaluated correctly.
+ //
+ // See StyleRecalcContext for more information.
scoped_refptr<ComputedStyle> StyleForPseudoElement(
+ const StyleRecalcContext&,
const PseudoElementStyleRequest&,
const ComputedStyle* parent_style = nullptr);
+
virtual bool CanGeneratePseudoElement(PseudoId) const;
virtual bool MatchesDefaultPseudoClass() const { return false; }
@@ -814,9 +824,6 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
virtual void BuildPendingResource() {}
- void V0SetCustomElementDefinition(V0CustomElementDefinition*);
- V0CustomElementDefinition* GetV0CustomElementDefinition() const;
-
void SetCustomElementDefinition(CustomElementDefinition*);
CustomElementDefinition* GetCustomElementDefinition() const;
// https://dom.spec.whatwg.org/#concept-element-is-value
@@ -850,7 +857,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
bool IsSpellCheckingEnabled() const;
// FIXME: public for LayoutTreeBuilder, we shouldn't expose this though.
- scoped_refptr<ComputedStyle> StyleForLayoutObject();
+ scoped_refptr<ComputedStyle> StyleForLayoutObject(const StyleRecalcContext&);
bool HasID() const;
bool HasClass() const;
@@ -888,6 +895,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
void setTabIndex(int);
int tabIndex() const;
+ void setEditContext(EditContext* editContext);
+ EditContext* editContext() const;
+
// Helpers for V8DOMActivityLogger::logEvent. They call logEvent only if
// the element is isConnected() and the context is an isolated world.
void LogAddElementIfIsolatedWorldAndInDocument(const char element[],
@@ -915,9 +925,16 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
HeapHashMap<Member<ResizeObserver>, Member<ResizeObservation>>&
EnsureResizeObserverData();
- DisplayLockContext* GetDisplayLockContext() const;
+ DisplayLockContext* GetDisplayLockContext() const {
+ if (LIKELY(!HasDisplayLockContext()))
+ return nullptr;
+ return GetDisplayLockContextFromRareData();
+ }
DisplayLockContext& EnsureDisplayLockContext();
+ ContainerQueryEvaluator* GetContainerQueryEvaluator() const;
+ void SetContainerQueryEvaluator(ContainerQueryEvaluator*);
+
bool ChildStyleRecalcBlockedByDisplayLock() const;
// Activates all activatable (for a given reason) locked ancestors for this
@@ -963,7 +980,8 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
virtual void WillRecalcStyle(const StyleRecalcChange);
virtual void DidRecalcStyle(const StyleRecalcChange);
- virtual scoped_refptr<ComputedStyle> CustomStyleForLayoutObject();
+ virtual scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&);
virtual NamedItemType GetNamedItemType() const {
return NamedItemType::kNone;
@@ -994,7 +1012,8 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
static bool AttributeValueIsJavaScriptURL(const Attribute&);
- scoped_refptr<ComputedStyle> OriginalStyleForLayoutObject();
+ scoped_refptr<ComputedStyle> OriginalStyleForLayoutObject(
+ const StyleRecalcContext&);
// Step 4 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
Node* InsertAdjacent(const String& where, Node* new_child, ExceptionState&);
@@ -1040,7 +1059,6 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
bool IsDocumentNode() const =
delete; // This will catch anyone doing an unnecessary check.
- ShadowRoot& CreateShadowRootInternal();
bool CanAttachShadowRoot() const;
const char* ErrorMessageForAttachShadow() const;
@@ -1058,9 +1076,13 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
// and returns the new style. Otherwise, returns null.
scoped_refptr<ComputedStyle> PropagateInheritedProperties();
+ const ComputedStyle* EnsureOwnComputedStyle(const StyleRecalcContext&,
+ PseudoId);
+
// Recalculate the ComputedStyle for this element and return a
// StyleRecalcChange for propagation/traversal into child nodes.
- StyleRecalcChange RecalcOwnStyle(const StyleRecalcChange);
+ StyleRecalcChange RecalcOwnStyle(const StyleRecalcChange,
+ const StyleRecalcContext&);
void RebuildPseudoElementLayoutTree(PseudoId, WhitespaceAttacher&);
void RebuildFirstLetterLayoutTree();
@@ -1069,7 +1091,9 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
inline void CheckForEmptyStyleChange(const Node* node_before_change,
const Node* node_after_change);
- void UpdatePseudoElement(PseudoId, const StyleRecalcChange);
+ void UpdatePseudoElement(PseudoId,
+ const StyleRecalcChange,
+ const StyleRecalcContext&);
enum class StyleUpdatePhase {
kRecalc,
@@ -1079,7 +1103,8 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
void UpdateFirstLetterPseudoElement(StyleUpdatePhase);
- inline PseudoElement* CreatePseudoElementIfNeeded(PseudoId);
+ inline PseudoElement* CreatePseudoElementIfNeeded(PseudoId,
+ const StyleRecalcContext&);
void AttachPseudoElement(PseudoId, AttachContext&);
void DetachPseudoElement(PseudoId, bool performing_reattach);
@@ -1113,7 +1138,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
const AtomicString& new_id);
void UpdateName(const AtomicString& old_name, const AtomicString& new_name);
- void ClientQuads(Vector<FloatQuad>& quads);
+ void ClientQuads(Vector<FloatQuad>& quads) const;
NodeType getNodeType() const final;
bool ChildTypeAllowed(NodeType) const final;
@@ -1190,7 +1215,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
const AtomicString&);
void SetInnerHTMLInternal(const String&,
- const SetInnerHTMLOptions*,
+ bool include_shadow_roots,
ExceptionState&);
ElementRareData* GetElementRareData() const;
@@ -1258,6 +1283,8 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
void SynchronizeContentAttributeAndElementReference(
const QualifiedName& name);
+ DisplayLockContext* GetDisplayLockContextFromRareData() const;
+
Member<ElementData> element_data_;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/element.idl b/chromium/third_party/blink/renderer/core/dom/element.idl
index 5ddc26a59d0..3508742715b 100644
--- a/chromium/third_party/blink/renderer/core/dom/element.idl
+++ b/chromium/third_party/blink/renderer/core/dom/element.idl
@@ -44,19 +44,21 @@ callback ScrollStateCallback = void (ScrollState scrollState);
[Affects=Nothing] sequence<DOMString> getAttributeNames();
[Affects=Nothing] DOMString? getAttribute(DOMString name);
[Affects=Nothing] DOMString? getAttributeNS(DOMString? namespaceURI, DOMString localName);
- [RaisesException, CEReactions, CustomElementCallbacks] void setAttribute(DOMString name, TrustedString value);
- [RaisesException, CEReactions, CustomElementCallbacks] void setAttributeNS(DOMString? namespaceURI, DOMString name, TrustedString value);
- [CEReactions, CustomElementCallbacks] void removeAttribute(DOMString name);
- [CEReactions, CustomElementCallbacks] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
- [RaisesException, CEReactions, CustomElementCallbacks] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
+ [RaisesException, CEReactions] void setAttribute(DOMString name, TrustedString value);
+ [RaisesException, CEReactions] void setAttributeNS(DOMString? namespaceURI, DOMString name, TrustedString value);
+ [CEReactions] void removeAttribute(DOMString name);
+ [CEReactions] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
+ [RaisesException, CEReactions] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
[Affects=Nothing] boolean hasAttribute(DOMString name);
[Affects=Nothing] boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
Attr? getAttributeNode(DOMString name);
Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
- [RaisesException, CEReactions, CustomElementCallbacks] Attr? setAttributeNode(Attr attr);
- [RaisesException, CEReactions, CustomElementCallbacks] Attr? setAttributeNodeNS(Attr attr);
- [RaisesException, CEReactions, CustomElementCallbacks] Attr removeAttributeNode(Attr attr);
+ [RaisesException, CEReactions] Attr? setAttributeNode(Attr attr);
+ [RaisesException, CEReactions] Attr? setAttributeNodeNS(Attr attr);
+ [RaisesException, CEReactions] Attr removeAttributeNode(Attr attr);
+
+ [RuntimeEnabled=EditContext] attribute EditContext? editContext;
[RaisesException, MeasureAs=ElementAttachShadow] ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
[Affects=Nothing, PerWorldBindings, ImplementedAs=OpenShadowRoot] readonly attribute ShadowRoot? shadowRoot;
@@ -69,7 +71,7 @@ callback ScrollStateCallback = void (ScrollState scrollState);
[Affects=Nothing] HTMLCollection getElementsByTagNameNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] HTMLCollection getElementsByClassName(DOMString classNames);
- [RaisesException, CEReactions, CustomElementCallbacks] Element? insertAdjacentElement(DOMString where, Element element);
+ [RaisesException, CEReactions] Element? insertAdjacentElement(DOMString where, Element element);
[RaisesException] void insertAdjacentText(DOMString where, DOMString data);
// CSS Shadow Parts
@@ -92,12 +94,11 @@ callback ScrollStateCallback = void (ScrollState scrollState);
// TODO(mkwst): Write a spec for the `TrustedHTML` variants.
// TODO(lyf): Change the type to `[TreatNullAs=xxx] HTMLString` after
// https://crbug.com/1058762 has been fixed.
- [Affects=Nothing, CEReactions, CustomElementCallbacks, RuntimeCallStatsCounter=ElementInnerHTML, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML;
- [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString outerHTML;
- [CEReactions, CustomElementCallbacks, RaisesException] void insertAdjacentHTML(DOMString position, HTMLString text);
+ [Affects=Nothing, CEReactions, RuntimeCallStatsCounter=ElementInnerHTML, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML;
+ [Affects=Nothing, CEReactions, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString outerHTML;
+ [CEReactions, RaisesException] void insertAdjacentHTML(DOMString position, HTMLString text);
- // Declarative Shadow DOM setInnerHTML/getInnerHTML() functions.
- [Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementSetInnerHTML, RaisesException, ImplementedAs=setInnerHTMLWithOptions] void setInnerHTML(HTMLString html, optional SetInnerHTMLOptions options = {});
+ // Declarative Shadow DOM getInnerHTML() function.
[Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementGetInnerHTML] HTMLString getInnerHTML(optional GetInnerHTMLOptions options = {});
// Pointer Lock
diff --git a/chromium/third_party/blink/renderer/core/dom/element_data.h b/chromium/third_party/blink/renderer/core/dom/element_data.h
index 4e40808615f..600cbbf8cab 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_data.h
@@ -133,6 +133,7 @@ class ElementData : public GarbageCollected<ElementData> {
private:
friend class Element;
+ friend class HTMLImageElement;
friend class ShareableElementData;
friend class UniqueElementData;
friend class SVGElement;
diff --git a/chromium/third_party/blink/renderer/core/dom/element_rare_data.cc b/chromium/third_party/blink/renderer/core/dom/element_rare_data.cc
index 743fec198ea..2cc01ae9478 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_rare_data.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element_rare_data.cc
@@ -31,7 +31,9 @@
#include "third_party/blink/renderer/core/dom/element_rare_data.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
+#include "third_party/blink/renderer/core/css/container_query_evaluator.h"
#include "third_party/blink/renderer/core/css/cssom/inline_style_property_map.h"
+#include "third_party/blink/renderer/core/editing/ime/edit_context.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observation.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
@@ -43,7 +45,7 @@ namespace blink {
struct SameSizeAsElementRareData : NodeRareData {
IntSize scroll_offset;
void* pointers_or_strings[3];
- Member<void*> members[17];
+ Member<void*> members[18];
bool flags[1];
};
@@ -99,6 +101,7 @@ void ElementRareData::TraceAfterDispatch(blink::Visitor* visitor) const {
visitor->Trace(class_list_);
visitor->Trace(part_);
visitor->Trace(shadow_root_);
+ visitor->Trace(edit_context_);
visitor->Trace(attribute_map_);
visitor->Trace(attr_node_list_);
visitor->Trace(element_animations_);
@@ -107,11 +110,11 @@ void ElementRareData::TraceAfterDispatch(blink::Visitor* visitor) const {
visitor->Trace(pseudo_element_data_);
visitor->Trace(accessible_node_);
visitor->Trace(display_lock_context_);
- visitor->Trace(v0_custom_element_definition_);
visitor->Trace(custom_element_definition_);
visitor->Trace(element_internals_);
visitor->Trace(intersection_observer_data_);
visitor->Trace(resize_observer_data_);
+ visitor->Trace(container_query_evaluator_);
NodeRareData::TraceAfterDispatch(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/element_rare_data.h b/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
index 24cdeb92ac3..f82d6732f28 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -39,13 +39,13 @@
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/space_split_string.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
#include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
+class ContainerQueryEvaluator;
class Element;
class HTMLElement;
class ResizeObservation;
@@ -81,6 +81,11 @@ class ElementRareData : public NodeRareData {
shadow_root_ = &shadow_root;
}
+ EditContext* GetEditContext() const { return edit_context_.Get(); }
+ void SetEditContext(EditContext* edit_context) {
+ edit_context_ = edit_context;
+ }
+
NamedNodeMap* AttributeMap() const { return attribute_map_.Get(); }
void SetAttributeMap(NamedNodeMap* attribute_map) {
attribute_map_ = attribute_map;
@@ -126,13 +131,6 @@ class ElementRareData : public NodeRareData {
bool HasPseudoElements() const;
void ClearPseudoElements();
- void V0SetCustomElementDefinition(V0CustomElementDefinition* definition) {
- v0_custom_element_definition_ = definition;
- }
- V0CustomElementDefinition* GetV0CustomElementDefinition() const {
- return v0_custom_element_definition_.Get();
- }
-
void SetCustomElementDefinition(CustomElementDefinition* definition) {
custom_element_definition_ = definition;
}
@@ -204,6 +202,12 @@ class ElementRareData : public NodeRareData {
DisplayLockContext* GetDisplayLockContext() const {
return display_lock_context_;
}
+ ContainerQueryEvaluator* GetContainerQueryEvaluator() const {
+ return container_query_evaluator_;
+ }
+ void SetContainerQueryEvaluator(ContainerQueryEvaluator* evaluator) {
+ container_query_evaluator_ = evaluator;
+ }
const AtomicString& GetNonce() const { return nonce_; }
void SetNonce(const AtomicString& nonce) { nonce_ = nonce; }
@@ -216,6 +220,7 @@ class ElementRareData : public NodeRareData {
Member<DatasetDOMStringMap> dataset_;
Member<ShadowRoot> shadow_root_;
+ Member<EditContext> edit_context_;
Member<DOMTokenList> class_list_;
Member<DOMTokenList> part_;
std::unique_ptr<NamesMap> part_names_map_;
@@ -228,8 +233,6 @@ class ElementRareData : public NodeRareData {
Member<ElementIntersectionObserverData> intersection_observer_data_;
Member<ResizeObserverDataMap> resize_observer_data_;
- // TODO(davaajav):remove this field when v0 custom elements are deprecated
- Member<V0CustomElementDefinition> v0_custom_element_definition_;
Member<CustomElementDefinition> custom_element_definition_;
AtomicString is_value_;
Member<ElementInternals> element_internals_;
@@ -239,6 +242,7 @@ class ElementRareData : public NodeRareData {
Member<AccessibleNode> accessible_node_;
Member<DisplayLockContext> display_lock_context_;
+ Member<ContainerQueryEvaluator> container_query_evaluator_;
bool did_attach_internals_ = false;
bool should_force_legacy_layout_for_child_ = false;
bool style_should_force_legacy_layout_ = false;
diff --git a/chromium/third_party/blink/renderer/core/dom/element_test.cc b/chromium/third_party/blink/renderer/core/dom/element_test.cc
index 304d227a772..2caedd9d0d5 100644
--- a/chromium/third_party/blink/renderer/core/dom/element_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/element_test.cc
@@ -72,11 +72,12 @@ TEST_F(ElementTest,
// Requesting the bounding client rect should cause both layout and
// compositing inputs clean to be run, and the sticky result shouldn't change.
bounding_client_rect = sticky->getBoundingClientRect();
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
- document.Lifecycle().GetState());
- EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
- ->Layer()
- ->NeedsCompositingInputsUpdate());
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean, document.Lifecycle().GetState());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_TRUE(sticky->GetLayoutBoxModelObject()
+ ->Layer()
+ ->NeedsCompositingInputsUpdate());
+ }
EXPECT_EQ(0, bounding_client_rect->top());
EXPECT_EQ(25, bounding_client_rect->left());
}
@@ -116,11 +117,12 @@ TEST_F(ElementTest, OffsetTopAndLeftCorrectForStickyElementsAfterInsertion) {
// Requesting either offset should cause both layout and compositing inputs
// clean to be run, and the sticky result shouldn't change.
EXPECT_EQ(scroller->scrollTop(), sticky->OffsetTop());
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
- document.Lifecycle().GetState());
- EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
- ->Layer()
- ->NeedsCompositingInputsUpdate());
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean, document.Lifecycle().GetState());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_TRUE(sticky->GetLayoutBoxModelObject()
+ ->Layer()
+ ->NeedsCompositingInputsUpdate());
+ }
// Dirty layout again, since |OffsetTop| will have cleaned it.
writer->setInnerHTML("<div style='height: 100px; width: 700px;'></div>");
@@ -129,11 +131,12 @@ TEST_F(ElementTest, OffsetTopAndLeftCorrectForStickyElementsAfterInsertion) {
// Again requesting an offset should cause layout and compositing to be clean.
EXPECT_EQ(scroller->scrollLeft() + 25, sticky->OffsetLeft());
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
- document.Lifecycle().GetState());
- EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
- ->Layer()
- ->NeedsCompositingInputsUpdate());
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean, document.Lifecycle().GetState());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_TRUE(sticky->GetLayoutBoxModelObject()
+ ->Layer()
+ ->NeedsCompositingInputsUpdate());
+ }
}
TEST_F(ElementTest, BoundsInViewportCorrectForStickyElementsAfterInsertion) {
@@ -172,11 +175,12 @@ TEST_F(ElementTest, BoundsInViewportCorrectForStickyElementsAfterInsertion) {
// Requesting the bounds in viewport should cause both layout and compositing
// inputs clean to be run, and the sticky result shouldn't change.
bounds_in_viewport = sticky->BoundsInViewport();
- EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
- document.Lifecycle().GetState());
- EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
- ->Layer()
- ->NeedsCompositingInputsUpdate());
+ EXPECT_EQ(DocumentLifecycle::kLayoutClean, document.Lifecycle().GetState());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_TRUE(sticky->GetLayoutBoxModelObject()
+ ->Layer()
+ ->NeedsCompositingInputsUpdate());
+ }
EXPECT_EQ(0, bounds_in_viewport.Y());
EXPECT_EQ(25, bounds_in_viewport.X());
}
@@ -509,10 +513,10 @@ class ScriptOnDestroyPlugin : public GarbageCollected<ScriptOnDestroyPlugin>,
WebPluginContainer* Container() const override { return container_; }
void UpdateAllLifecyclePhases(DocumentUpdateReason) override {}
- void Paint(cc::PaintCanvas*, const WebRect&) override {}
- void UpdateGeometry(const WebRect&,
- const WebRect&,
- const WebRect&,
+ void Paint(cc::PaintCanvas*, const gfx::Rect&) override {}
+ void UpdateGeometry(const gfx::Rect&,
+ const gfx::Rect&,
+ const gfx::Rect&,
bool) override {}
void UpdateFocus(bool, mojom::blink::FocusType) override {}
void UpdateVisibility(bool) override {}
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event.cc b/chromium/third_party/blink/renderer/core/dom/events/event.cc
index a5136771a81..b882dd0b3ce 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event.cc
@@ -42,22 +42,6 @@
namespace blink {
-static bool IsEventTypeScopedInV0(const AtomicString& event_type) {
- // WebKit never allowed selectstart event to cross the the shadow DOM
- // boundary. Changing this breaks existing sites.
- // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
- return event_type == event_type_names::kAbort ||
- event_type == event_type_names::kChange ||
- event_type == event_type_names::kError ||
- event_type == event_type_names::kLoad ||
- event_type == event_type_names::kReset ||
- event_type == event_type_names::kResize ||
- event_type == event_type_names::kScroll ||
- event_type == event_type_names::kSelect ||
- event_type == event_type_names::kSelectstart ||
- event_type == event_type_names::kSlotchange;
-}
-
Event::Event() : Event("", Bubbles::kNo, Cancelable::kNo) {
was_initialized_ = false;
}
@@ -91,7 +75,6 @@ Event::Event(const AtomicString& event_type,
bubbles_(bubbles == Bubbles::kYes),
cancelable_(cancelable == Cancelable::kYes),
composed_(composed_mode == ComposedMode::kComposed),
- is_event_type_scoped_in_v0_(IsEventTypeScopedInV0(event_type)),
propagation_stopped_(false),
immediate_propagation_stopped_(false),
default_prevented_(false),
@@ -120,10 +103,6 @@ Event::Event(const AtomicString& event_type,
Event::~Event() = default;
-bool Event::IsScopedInV0() const {
- return isTrusted() && is_event_type_scoped_in_v0_;
-}
-
void Event::initEvent(const AtomicString& event_type_arg,
bool bubbles_arg,
bool cancelable_arg) {
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event.h b/chromium/third_party/blink/renderer/core/dom/events/event.h
index 70de593a6ab..d6a612fea93 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event.h
@@ -39,6 +39,7 @@ class EventDispatcher;
class EventInit;
class EventPath;
class EventTarget;
+class Node;
class ScriptState;
class ScriptValue;
@@ -180,7 +181,6 @@ class CORE_EXPORT Event : public ScriptWrappable {
bool bubbles() const { return bubbles_; }
bool cancelable() const { return cancelable_; }
bool composed() const { return composed_; }
- bool IsScopedInV0() const;
// Event creation timestamp in milliseconds. It returns a DOMHighResTimeStamp
// using the platform timestamp (see |platform_time_stamp_|).
@@ -327,7 +327,6 @@ class CORE_EXPORT Event : public ScriptWrappable {
unsigned bubbles_ : 1;
unsigned cancelable_ : 1;
unsigned composed_ : 1;
- unsigned is_event_type_scoped_in_v0_ : 1;
unsigned propagation_stopped_ : 1;
unsigned immediate_propagation_stopped_ : 1;
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event.idl b/chromium/third_party/blink/renderer/core/dom/events/event.idl
index 702058feb88..4d92c2a4061 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event.idl
+++ b/chromium/third_party/blink/renderer/core/dom/events/event.idl
@@ -51,9 +51,10 @@
[Measure] void initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false);
- // Non-standard APIs
[MeasureAs=EventSrcElement] readonly attribute EventTarget srcElement;
[MeasureAs=EventReturnValue, CallWith=ScriptState, ImplementedAs=legacyReturnValue] attribute boolean returnValue;
[MeasureAs=EventCancelBubble, CallWith=ScriptState] attribute boolean cancelBubble;
+
+ // Non-standard APIs
[MeasureAs=EventPath, CallWith=ScriptState] readonly attribute object path;
};
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
index 52a3c1d3e53..db1146f9928 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -29,22 +29,24 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
-#include "third_party/blink/renderer/core/dom/container_node.h"
-#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
+#include "third_party/blink/renderer/core/dom/events/event_dispatch_result.h"
#include "third_party/blink/renderer/core/dom/events/event_path.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/events/window_event_context.h"
+#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
+#include "third_party/blink/renderer/core/events/simulated_event_util.h"
#include "third_party/blink/renderer/core/frame/ad_tracker.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_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
#include "third_party/blink/renderer/core/timing/event_timing.h"
@@ -79,7 +81,6 @@ void EventDispatcher::DispatchScopedEvent(Node& node, Event& event) {
void EventDispatcher::DispatchSimulatedClick(
Node& node,
const Event* underlying_event,
- SimulatedClickMouseEventOptions mouse_event_options,
SimulatedClickCreationScope creation_scope) {
// This persistent vector doesn't cause leaks, because added Nodes are removed
// before dispatchSimulatedClick() returns. This vector is here just to
@@ -97,34 +98,45 @@ void EventDispatcher::DispatchSimulatedClick(
nodes_dispatching_simulated_clicks->insert(&node);
- if (mouse_event_options == kSendMouseOverUpDownEvents)
- EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
- node.GetDocument().domWindow(),
- underlying_event, creation_scope))
- .Dispatch();
-
Element* element = DynamicTo<Element>(node);
- if (mouse_event_options != kSendNoEvents) {
- EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
- node.GetDocument().domWindow(),
- underlying_event, creation_scope))
- .Dispatch();
+ bool prevent_mouse_events = false;
+
+ if (creation_scope == SimulatedClickCreationScope::kFromAccessibility) {
+ DispatchEventResult dispatch_result =
+ EventDispatcher(node, *SimulatedEventUtil::CreateEvent(
+ event_type_names::kPointerdown, node,
+ underlying_event, creation_scope))
+ .Dispatch();
+ prevent_mouse_events =
+ dispatch_result == DispatchEventResult::kCanceledByEventHandler;
+ if (!prevent_mouse_events) {
+ EventDispatcher(node, *SimulatedEventUtil::CreateEvent(
+ event_type_names::kMousedown, node,
+ underlying_event, creation_scope))
+ .Dispatch();
+ }
if (element)
element->SetActive(true);
- EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
- node.GetDocument().domWindow(),
- underlying_event, creation_scope))
+ EventDispatcher(node, *SimulatedEventUtil::CreateEvent(
+ event_type_names::kPointerup, node,
+ underlying_event, creation_scope))
.Dispatch();
+ if (!prevent_mouse_events) {
+ EventDispatcher(node, *SimulatedEventUtil::CreateEvent(
+ event_type_names::kMouseup, node,
+ underlying_event, creation_scope))
+ .Dispatch();
+ }
}
// Some elements (e.g. the color picker) may set active state to true before
// calling this method and expect the state to be reset during the call.
if (element)
element->SetActive(false);
- // always send click
- EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
- node.GetDocument().domWindow(),
- underlying_event, creation_scope))
+ // Always send click.
+ EventDispatcher(
+ node, *SimulatedEventUtil::CreateEvent(event_type_names::kClick, node,
+ underlying_event, creation_scope))
.Dispatch();
nodes_dispatching_simulated_clicks->erase(&node);
@@ -148,6 +160,10 @@ DispatchEventResult EventDispatcher::Dispatch() {
LocalFrame* frame = node_->GetDocument().GetFrame();
if (frame && frame->DomWindow())
eventTiming = EventTiming::Create(frame->DomWindow(), *event_);
+ if (event_->type() == event_type_names::kChange && event_->isTrusted() &&
+ view_) {
+ view_->GetLayoutShiftTracker().NotifyChangeEvent();
+ }
event_->GetEventPath().EnsureWindowEventContext();
const bool is_click =
@@ -202,10 +218,8 @@ DispatchEventResult EventDispatcher::Dispatch() {
if (DispatchEventPreProcess(activation_target,
pre_dispatch_event_handler_result) ==
kContinueDispatching) {
- if (DispatchEventAtCapturing() == kContinueDispatching) {
- if (DispatchEventAtTarget() == kContinueDispatching)
- DispatchEventAtBubbling();
- }
+ if (DispatchEventAtCapturing() == kContinueDispatching)
+ DispatchEventAtBubbling();
}
DispatchEventPostProcess(activation_target,
pre_dispatch_event_handler_result);
@@ -233,7 +247,8 @@ inline EventDispatchContinuation EventDispatcher::DispatchEventPreProcess(
inline EventDispatchContinuation EventDispatcher::DispatchEventAtCapturing() {
// Trigger capturing event handlers, starting at the top and working our way
- // down.
+ // down. When we get to the last one, the target, change the event phase to
+ // AT_TARGET and fire only the capture listeners on it.
event_->SetEventPhase(Event::kCapturingPhase);
if (event_->GetEventPath().GetWindowEventContext().HandleLocalEvents(
@@ -241,8 +256,8 @@ inline EventDispatchContinuation EventDispatcher::DispatchEventAtCapturing() {
event_->PropagationStopped())
return kDoneDispatching;
- for (wtf_size_t i = event_->GetEventPath().size() - 1; i > 0; --i) {
- const NodeEventContext& event_context = event_->GetEventPath()[i];
+ for (wtf_size_t i = event_->GetEventPath().size(); i > 0; --i) {
+ const NodeEventContext& event_context = event_->GetEventPath()[i - 1];
if (event_context.CurrentTargetSameAsTarget()) {
event_->SetEventPhase(Event::kAtTarget);
event_->SetFireOnlyCaptureListenersAtTarget(true);
@@ -259,17 +274,12 @@ inline EventDispatchContinuation EventDispatcher::DispatchEventAtCapturing() {
return kContinueDispatching;
}
-inline EventDispatchContinuation EventDispatcher::DispatchEventAtTarget() {
- event_->SetEventPhase(Event::kAtTarget);
- event_->GetEventPath()[0].HandleLocalEvents(*event_);
- return event_->PropagationStopped() ? kDoneDispatching : kContinueDispatching;
-}
-
inline void EventDispatcher::DispatchEventAtBubbling() {
// Trigger bubbling event handlers, starting at the bottom and working our way
- // up.
+ // up. On the first one, the target, change the event phase to AT_TARGET and
+ // fire only the bubble listeners on it.
wtf_size_t size = event_->GetEventPath().size();
- for (wtf_size_t i = 1; i < size; ++i) {
+ for (wtf_size_t i = 0; i < size; ++i) {
const NodeEventContext& event_context = event_->GetEventPath()[i];
if (event_context.CurrentTargetSameAsTarget()) {
// TODO(hayato): Need to check cancelBubble() also here?
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
index d7d2b1f0221..0eb00ac1417 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.h
@@ -57,7 +57,6 @@ class EventDispatcher {
static void DispatchSimulatedClick(Node&,
const Event* underlying_event,
- SimulatedClickMouseEventOptions,
SimulatedClickCreationScope);
DispatchEventResult Dispatch();
@@ -71,7 +70,6 @@ class EventDispatcher {
Node* activation_target,
EventDispatchHandlingState*&);
EventDispatchContinuation DispatchEventAtCapturing();
- EventDispatchContinuation DispatchEventAtTarget();
void DispatchEventAtBubbling();
void DispatchEventPostProcess(Node* activation_target,
EventDispatchHandlingState*);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_path.cc b/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
index 241b224c6f4..7222d2944ea 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -29,7 +29,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/window_event_context.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/events/touch_event.h"
#include "third_party/blink/renderer/core/events/touch_event_context.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
@@ -50,14 +49,8 @@ EventTarget& EventPath::EventTargetRespectingTargetRules(Node& reference_node) {
static inline bool ShouldStopAtShadowRoot(Event& event,
ShadowRoot& shadow_root,
EventTarget& target) {
- if (shadow_root.IsV1()) {
- // In v1, an event is scoped by default unless event.composed flag is set.
- return !event.composed() && target.ToNode() &&
- target.ToNode()->OwnerShadowHost() == shadow_root.host();
- }
- // Ignores event.composed() for v0.
- // Instead, use event.isScopedInV0() for backward compatibility.
- return event.IsScopedInV0() && target.ToNode() &&
+ // An event is scoped by default unless event.composed flag is set.
+ return !event.composed() && target.ToNode() &&
target.ToNode()->OwnerShadowHost() == shadow_root.host();
}
@@ -90,7 +83,6 @@ void EventPath::Initialize() {
void EventPath::CalculatePath() {
DCHECK(node_);
DCHECK(node_event_contexts_.IsEmpty());
- node_->UpdateDistributionForLegacyDistributedNodes();
// For performance and memory usage reasons we want to store the
// path using as few bytes as possible and with as few allocations
@@ -103,15 +95,7 @@ void EventPath::CalculatePath() {
while (current) {
if (event_ && current->KeepEventInNode(*event_))
break;
- HeapVector<Member<V0InsertionPoint>, 8> insertion_points;
- CollectDestinationInsertionPoints(*current, insertion_points);
- if (!insertion_points.IsEmpty()) {
- for (const auto& insertion_point : insertion_points)
- nodes_in_path.push_back(insertion_point);
- current = insertion_points.back();
- continue;
- }
- if (current->IsChildOfV1ShadowHost()) {
+ if (current->IsChildOfShadowHost() && !current->IsPseudoElement()) {
if (HTMLSlotElement* slot = current->AssignedSlot()) {
current = slot;
nodes_in_path.push_back(current);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_queue.h b/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
index e127921daa2..120ac0fcd3e 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_queue.h
@@ -40,7 +40,7 @@ class CORE_EXPORT EventQueue final : public GarbageCollected<EventQueue>,
public ExecutionContextLifecycleObserver {
public:
EventQueue(ExecutionContext*, TaskType);
- ~EventQueue();
+ ~EventQueue() override;
void Trace(Visitor*) const override;
bool EnqueueEvent(const base::Location&, Event&);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_target.cc b/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
index 5576d440a71..7338903e0d4 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -208,14 +208,6 @@ void CountFiringEventListeners(const Event& event,
{event_type_names::kPointerover, WebFeature::kPointerOverOutFired},
{event_type_names::kPointerout, WebFeature::kPointerOverOutFired},
{event_type_names::kSearch, WebFeature::kSearchEventFired},
- {event_type_names::kWebkitprerenderstart,
- WebFeature::kWebkitPrerenderStartEventFired},
- {event_type_names::kWebkitprerenderstop,
- WebFeature::kWebkitPrerenderStopEventFired},
- {event_type_names::kWebkitprerenderload,
- WebFeature::kWebkitPrerenderLoadEventFired},
- {event_type_names::kWebkitprerenderdomcontentloaded,
- WebFeature::kWebkitPrerenderDOMContentLoadedEventFired},
};
for (const auto& counted_event : counted_events) {
if (CheckTypeThenUseCount(event, counted_event.event_type,
@@ -248,7 +240,7 @@ void RegisterWithScheduler(ExecutionContext* execution_context,
if (feature_for_scheduler) {
execution_context->GetScheduler()->RegisterStickyFeature(
feature_for_scheduler.value(),
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
}
@@ -506,6 +498,9 @@ bool EventTarget::AddEventListenerInternal(
if (!listener)
return false;
+ if (options->hasSignal() && options->signal()->aborted())
+ return false;
+
if (event_type == event_type_names::kTouchcancel ||
event_type == event_type_names::kTouchend ||
event_type == event_type_names::kTouchmove ||
@@ -533,13 +528,19 @@ bool EventTarget::AddEventListenerInternal(
bool added = EnsureEventTargetData().event_listener_map.Add(
event_type, listener, options, &registered_listener);
if (added) {
- if (options->signal()) {
+ if (options->hasSignal()) {
+ // Instead of passing the entire |options| here, which could create a
+ // circular reference due to |options| holding a Member<AbortSignal>, just
+ // pass the |options->capture()| boolean, which is the only thing
+ // removeEventListener actually uses to find and remove the event
+ // listener.
options->signal()->AddAlgorithm(WTF::Bind(
[](EventTarget* event_target, const AtomicString& event_type,
- const EventListener* listener) {
- event_target->removeEventListener(event_type, listener);
+ const EventListener* listener, bool capture) {
+ event_target->removeEventListener(event_type, listener, capture);
},
- WrapWeakPersistent(this), event_type, WrapWeakPersistent(listener)));
+ WrapWeakPersistent(this), event_type, WrapWeakPersistent(listener),
+ options->capture()));
if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
if (const Document* document = executing_window->document()) {
document->CountUse(WebFeature::kAddEventListenerWithAbortSignal);
diff --git a/chromium/third_party/blink/renderer/core/dom/events/simulated_click_options.h b/chromium/third_party/blink/renderer/core/dom/events/simulated_click_options.h
index 416a9c00b93..7cd2e9a1cf1 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/simulated_click_options.h
+++ b/chromium/third_party/blink/renderer/core/dom/events/simulated_click_options.h
@@ -23,14 +23,12 @@
namespace blink {
-enum SimulatedClickMouseEventOptions {
- kSendNoEvents,
- kSendMouseUpDownEvents,
- kSendMouseOverUpDownEvents
+enum class SimulatedClickCreationScope {
+ kFromScript,
+ kFromUserAgent,
+ kFromAccessibility
};
-enum class SimulatedClickCreationScope { kFromScript, kFromUserAgent };
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_SIMULATED_CLICK_OPTIONS_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
index 4c50097b8e1..a624375ce92 100644
--- a/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
+++ b/chromium/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
@@ -109,7 +109,7 @@ int TreeScopeEventContext::CalculateTreeOrderAndSetNearestAncestorClosedTree(
pre_order_ = order_number;
auto* shadow_root = DynamicTo<ShadowRoot>(&RootNode());
containing_closed_shadow_tree_ =
- (shadow_root && !shadow_root->IsOpenOrV0())
+ (shadow_root && !shadow_root->IsOpen())
? this
: nearest_ancestor_closed_tree_scope_event_context;
for (const auto& context : children_) {
diff --git a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index d9e01164538..3a741604ccb 100644
--- a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -169,7 +169,7 @@ LayoutText* FirstLetterPseudoElement::FirstLetterTextLayoutObject(
return nullptr;
} else if (first_letter_text_layout_object
->IsFlexibleBoxIncludingDeprecatedAndNG() ||
- first_letter_text_layout_object->IsLayoutGrid()) {
+ first_letter_text_layout_object->IsLayoutGridIncludingNG()) {
first_letter_text_layout_object =
first_letter_text_layout_object->NextSibling();
} else if (!first_letter_text_layout_object->IsInline() &&
@@ -180,6 +180,19 @@ LayoutText* FirstLetterPseudoElement::FirstLetterTextLayoutObject(
// PseudoIdFirstLetter set. When that node is attached we will handle
// setting up the first letter then.
return nullptr;
+ } else if (first_letter_text_layout_object->IsInline() &&
+ !first_letter_text_layout_object->SlowFirstChild()) {
+ if (LayoutObject* next_sibling =
+ first_letter_text_layout_object->NextSibling()) {
+ first_letter_text_layout_object = next_sibling;
+ continue;
+ }
+ LayoutObject* parent = first_letter_text_layout_object->Parent();
+ if (parent && parent != parent_layout_object) {
+ first_letter_text_layout_object = parent->NextSibling();
+ continue;
+ }
+ return nullptr;
} else {
first_letter_text_layout_object =
first_letter_text_layout_object->SlowFirstChild();
@@ -298,14 +311,15 @@ void FirstLetterPseudoElement::DetachLayoutTree(bool performing_reattach) {
}
scoped_refptr<ComputedStyle>
-FirstLetterPseudoElement::CustomStyleForLayoutObject() {
+FirstLetterPseudoElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
LayoutObject* first_letter_text =
FirstLetterPseudoElement::FirstLetterTextLayoutObject(*this);
if (!first_letter_text)
return nullptr;
DCHECK(first_letter_text->Parent());
return ParentOrShadowHostElement()->StyleForPseudoElement(
- PseudoElementStyleRequest(GetPseudoId()),
+ style_recalc_context, PseudoElementStyleRequest(GetPseudoId()),
first_letter_text->Parent()->FirstLineStyle());
}
diff --git a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
index 64b94100dc8..a3d9146368e 100644
--- a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
+++ b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
@@ -58,7 +58,8 @@ class CORE_EXPORT FirstLetterPseudoElement final : public PseudoElement {
Node* InnerNodeForHitTesting() const override;
private:
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
void AttachFirstLetterTextLayoutObjects(LayoutText* first_letter_text);
diff --git a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc
index 3090df52c5c..1d380f49c31 100644
--- a/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc
@@ -4,17 +4,32 @@
#include "third_party/blink/renderer/core/dom/first_letter_pseudo_element.h"
-#include <gtest/gtest.h>
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
-class FirstLetterPseudoElementTest : public testing::Test {};
+class FirstLetterPseudoElementTest : public PageTestBase {};
TEST_F(FirstLetterPseudoElementTest, DoesNotBreakEmoji) {
const UChar emoji[] = {0xD83D, 0xDE31, 0};
EXPECT_EQ(2u, FirstLetterPseudoElement::FirstLetterLength(emoji));
}
+// http://crbug.com/1161370
+TEST_F(FirstLetterPseudoElementTest, EmptySpanOnly) {
+ InsertStyleElement("p::first-letter { color: red; }");
+ SetBodyContent("<div><p id=sample><b></b></p>abc</div>");
+ Element& sample = *GetElementById("sample");
+ // Call Element::RebuildFirstLetterLayoutTree()
+ sample.setAttribute(html_names::kContenteditableAttr, "true");
+ const PseudoElement* const first_letter =
+ sample.GetPseudoElement(kPseudoIdFirstLetter);
+ // We should not have ::first-letter pseudo element because <p> has no text.
+ // See |FirstLetterPseudoElement::FirstLetterTextLayoutObject()| should
+ // return nullptr during rebuilding layout tree.
+ EXPECT_FALSE(first_letter);
+}
+
TEST_F(FirstLetterPseudoElementTest, UnicodePairBreaking) {
const UChar test_string[] = {0xD800, 0xDD00, 'A', 0xD800, 0xDD00,
0xD800, 0xDD00, 'B', 0};
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h b/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
index 46bc1e73ead..9f69a4b71c0 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_node_data.h
@@ -49,6 +49,7 @@ class FlatTreeNodeData final : public GarbageCollected<FlatTreeNodeData> {
friend class FlatTreeTraversal;
friend class HTMLSlotElement;
friend HTMLSlotElement* Node::AssignedSlot() const;
+ friend HTMLSlotElement* Node::AssignedSlotWithoutRecalc() const;
friend void Node::ClearFlatTreeNodeDataIfHostChanged(const ContainerNode&);
friend Element* Node::FlatTreeParentForChildDirty() const;
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
index bb95f1b0cd4..3b33d1be642 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
@@ -29,7 +29,6 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
#include "third_party/blink/renderer/core/dom/slot_assignment.h"
-#include "third_party/blink/renderer/core/html/html_shadow_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
namespace blink {
@@ -41,7 +40,7 @@ void FlatTreeTraversal::AssertFlatTreeNodeDataUpdated(
int& nodes_which_have_assigned_slot_count) {
for (Node& node : NodeTraversal::StartsAt(root)) {
if (auto* element = DynamicTo<Element>(node)) {
- if (ShadowRoot* shadow_root = element->ShadowRootIfV1()) {
+ if (ShadowRoot* shadow_root = element->GetShadowRoot()) {
DCHECK(!shadow_root->NeedsSlotAssignmentRecalc());
AssertFlatTreeNodeDataUpdated(*shadow_root,
assigned_nodes_in_slot_count,
@@ -52,7 +51,7 @@ void FlatTreeTraversal::AssertFlatTreeNodeDataUpdated(
ToHTMLSlotElementIfSupportsAssignmentOrNull(node)) {
assigned_nodes_in_slot_count += slot->AssignedNodes().size();
}
- if (node.IsChildOfV1ShadowHost()) {
+ if (node.IsChildOfShadowHost()) {
ShadowRoot* parent_shadow_root = node.ParentElementShadowRoot();
DCHECK(parent_shadow_root);
if (!parent_shadow_root->HasSlotAssignment()) {
@@ -91,10 +90,6 @@ void FlatTreeTraversal::AssertFlatTreeNodeDataUpdated(
}
#endif
-bool CanBeDistributedToV0InsertionPoint(const Node& node) {
- return node.IsInV0ShadowTree() || node.IsChildOfV0ShadowHost();
-}
-
Node* FlatTreeTraversal::TraverseChild(const Node& node,
TraversalDirection direction) {
if (auto* slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(node)) {
@@ -113,64 +108,19 @@ Node* FlatTreeTraversal::TraverseChild(const Node& node,
child = direction == kTraversalDirectionForward ? node.firstChild()
: node.lastChild();
}
-
- if (!child)
- return nullptr;
-
- if (child->IsInV0ShadowTree()) {
- return V0ResolveDistributionStartingAt(*child, direction);
- }
return child;
}
-Node* FlatTreeTraversal::V0ResolveDistributionStartingAt(
- const Node& node,
- TraversalDirection direction) {
- DCHECK(!ToHTMLSlotElementIfSupportsAssignmentOrNull(node));
- for (const Node* sibling = &node; sibling;
- sibling = (direction == kTraversalDirectionForward
- ? sibling->nextSibling()
- : sibling->previousSibling())) {
- if (!IsActiveV0InsertionPoint(*sibling))
- return const_cast<Node*>(sibling);
- const auto& insertion_point = To<V0InsertionPoint>(*sibling);
- if (Node* found = (direction == kTraversalDirectionForward
- ? insertion_point.FirstDistributedNode()
- : insertion_point.LastDistributedNode()))
- return found;
- DCHECK(IsA<HTMLShadowElement>(insertion_point) ||
- (IsA<HTMLContentElement>(insertion_point) &&
- !insertion_point.HasChildren()));
- }
- return nullptr;
-}
-
-// TODO(hayato): This may return a wrong result for a node which is not in a
-// document flat tree. See FlatTreeTraversalTest's redistribution test for
-// details.
Node* FlatTreeTraversal::TraverseSiblings(const Node& node,
TraversalDirection direction) {
- if (node.IsChildOfV1ShadowHost())
- return TraverseSiblingsForV1HostChild(node, direction);
+ if (node.IsChildOfShadowHost())
+ return TraverseSiblingsForHostChild(node, direction);
- if (ShadowRootWhereNodeCanBeDistributedForV0(node))
- return TraverseSiblingsForV0Distribution(node, direction);
-
- Node* sibling = direction == kTraversalDirectionForward
- ? node.nextSibling()
- : node.previousSibling();
-
- if (!node.IsInV0ShadowTree())
- return sibling;
-
- if (sibling) {
- if (Node* found = V0ResolveDistributionStartingAt(*sibling, direction))
- return found;
- }
- return nullptr;
+ return direction == kTraversalDirectionForward ? node.nextSibling()
+ : node.previousSibling();
}
-Node* FlatTreeTraversal::TraverseSiblingsForV1HostChild(
+Node* FlatTreeTraversal::TraverseSiblingsForHostChild(
const Node& node,
TraversalDirection direction) {
ShadowRoot* shadow_root = node.ParentElementShadowRoot();
@@ -197,28 +147,13 @@ Node* FlatTreeTraversal::TraverseSiblingsForV1HostChild(
return nullptr;
}
-Node* FlatTreeTraversal::TraverseSiblingsForV0Distribution(
- const Node& node,
- TraversalDirection direction) {
- const V0InsertionPoint* final_destination = ResolveReprojection(&node);
- if (!final_destination)
- return nullptr;
- if (Node* found = (direction == kTraversalDirectionForward
- ? final_destination->DistributedNodeNextTo(&node)
- : final_destination->DistributedNodePreviousTo(&node)))
- return found;
- return TraverseSiblings(*final_destination, direction);
-}
-
-ContainerNode* FlatTreeTraversal::TraverseParent(
- const Node& node,
- ParentTraversalDetails* details) {
+ContainerNode* FlatTreeTraversal::TraverseParent(const Node& node) {
// TODO(hayato): Stop this hack for a pseudo element because a pseudo element
// is not a child of its parentOrShadowHostNode() in a flat tree.
if (node.IsPseudoElement())
return node.ParentOrShadowHostNode();
- if (node.IsChildOfV1ShadowHost())
+ if (node.IsChildOfShadowHost())
return node.AssignedSlot();
if (auto* parent_slot =
@@ -227,35 +162,9 @@ ContainerNode* FlatTreeTraversal::TraverseParent(
return nullptr;
return parent_slot;
}
-
- if (CanBeDistributedToV0InsertionPoint(node))
- return TraverseParentForV0(node, details);
-
- DCHECK(!ShadowRootWhereNodeCanBeDistributedForV0(node));
return TraverseParentOrHost(node);
}
-ContainerNode* FlatTreeTraversal::TraverseParentForV0(
- const Node& node,
- ParentTraversalDetails* details) {
- if (ShadowRootWhereNodeCanBeDistributedForV0(node)) {
- if (const V0InsertionPoint* insertion_point = ResolveReprojection(&node)) {
- if (details)
- details->DidTraverseInsertionPoint(insertion_point);
- // The node is distributed. But the distribution was stopped at this
- // insertion point.
- if (ShadowRootWhereNodeCanBeDistributedForV0(*insertion_point))
- return nullptr;
- return TraverseParent(*insertion_point);
- }
- return nullptr;
- }
- ContainerNode* parent = TraverseParentOrHost(node);
- if (IsActiveV0InsertionPoint(*parent))
- return nullptr;
- return parent;
-}
-
ContainerNode* FlatTreeTraversal::TraverseParentOrHost(const Node& node) {
ContainerNode* parent = node.parentNode();
if (!parent)
@@ -296,7 +205,7 @@ bool FlatTreeTraversal::ContainsIncludingPseudoElement(
return false;
}
-Node* FlatTreeTraversal::PreviousSkippingChildren(const Node& node) {
+Node* FlatTreeTraversal::PreviousAbsoluteSibling(const Node& node) {
if (Node* previous_sibling = TraversePreviousSibling(node))
return previous_sibling;
return TraversePreviousAncestorSibling(node);
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
index 4518f906cd6..a4411ff8ba5 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal.h
@@ -33,7 +33,6 @@
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/traversal_range.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
@@ -41,8 +40,6 @@ namespace blink {
class ContainerNode;
class Node;
-bool CanBeDistributedToV0InsertionPoint(const Node& node);
-
// Flat tree version of |NodeTraversal|.
//
// None of member functions takes a |ShadowRoot| or an active insertion point,
@@ -54,7 +51,6 @@ class CORE_EXPORT FlatTreeTraversal {
STATIC_ONLY(FlatTreeTraversal);
public:
- typedef LayoutTreeBuilderTraversal::ParentDetails ParentTraversalDetails;
using TraversalNodeType = Node;
#if DCHECK_IS_ON()
@@ -75,7 +71,7 @@ class CORE_EXPORT FlatTreeTraversal {
static Node* LastChild(const Node&);
static bool HasChildren(const Node&);
- static ContainerNode* Parent(const Node&, ParentTraversalDetails* = nullptr);
+ static ContainerNode* Parent(const Node&);
static Element* ParentElement(const Node&);
static Node* NextSibling(const Node&);
@@ -85,17 +81,38 @@ class CORE_EXPORT FlatTreeTraversal {
// the children, this function returns |nullptr|.
static Node* ChildAt(const Node&, unsigned index);
- // Flat tree version of |NodeTraversal::nextSkippingChildren()|. This
- // function is similar to |next()| but skips child nodes of a specified
- // node.
+ // Flat tree version of |NodeTraversal::NextSkippingChildren()|. This
+ // function is similar to |Next()| but skips the child nodes of the specified
+ // node. E.g. for this tree:
+ // 0
+ // / \
+ // 1 4
+ // / \ / \
+ // 2 3 5 6
+ // NextSkippingChildren(1) will return 4.
+ // NextSkippingChildren(3) will return 4.
+ // NextSkippingChildren(2) will return 3.
+ // NextSkippingChildren(4) will return nullptr.
static Node* NextSkippingChildren(const Node&);
static Node* NextSkippingChildren(const Node&, const Node* stay_within);
static Node* FirstWithin(const Node& current) { return FirstChild(current); }
- // Flat tree version of |NodeTraversal::previousSkippingChildren()|
- // similar to |previous()| but skipping child nodes of the specified node.
- static Node* PreviousSkippingChildren(const Node&);
+ // Flat tree version of |NodeTraversal::PreviousAbsoluteSibling()|. This
+ // function returns the previous direct sibling of the node, if there is one.
+ // If not, it will traverse up the ancestor chain until it finds an ancestor
+ // that has a previous sibling, returning that sibling. Or nullptr if none.
+ // E.g. for this tree:
+ // 0
+ // / \
+ // 1 4
+ // / \ / \
+ // 2 3 5 6
+ // PreviousAbsoluteSibling(5) will return 1.
+ // PreviousAbsoluteSibling(4) will return 1.
+ // PreviousAbsoluteSibling(6) will return 5.
+ // PreviousAbsoluteSibling(2) will return nullptr.
+ static Node* PreviousAbsoluteSibling(const Node&);
// Like previous, but visits parents before their children.
static Node* PreviousPostOrder(const Node&,
@@ -152,7 +169,6 @@ class CORE_EXPORT FlatTreeTraversal {
static void AssertPrecondition(const Node& node) {
DCHECK(!node.GetDocument().IsFlatTreeTraversalForbidden());
- DCHECK(!node.NeedsDistributionRecalc());
DCHECK(node.CanParticipateInFlatTree());
}
@@ -164,7 +180,6 @@ class CORE_EXPORT FlatTreeTraversal {
}
static Node* ResolveDistributionStartingAt(const Node*, TraversalDirection);
- static Node* V0ResolveDistributionStartingAt(const Node&, TraversalDirection);
static Node* TraverseNext(const Node&);
static Node* TraverseNext(const Node&, const Node* stay_within);
@@ -176,20 +191,14 @@ class CORE_EXPORT FlatTreeTraversal {
static Node* TraverseLastChild(const Node&);
static Node* TraverseChild(const Node&, TraversalDirection);
- static ContainerNode* TraverseParent(const Node&,
- ParentTraversalDetails* = nullptr);
- // TODO(hayato): Make ParentTraversalDetails be aware of slot elements too.
- static ContainerNode* TraverseParentForV0(const Node&,
- ParentTraversalDetails* = nullptr);
+ static ContainerNode* TraverseParent(const Node&);
static ContainerNode* TraverseParentOrHost(const Node&);
static Node* TraverseNextSibling(const Node&);
static Node* TraversePreviousSibling(const Node&);
static Node* TraverseSiblings(const Node&, TraversalDirection);
- static Node* TraverseSiblingsForV1HostChild(const Node&, TraversalDirection);
- static Node* TraverseSiblingsForV0Distribution(const Node&,
- TraversalDirection);
+ static Node* TraverseSiblingsForHostChild(const Node&, TraversalDirection);
static Node* TraverseNextAncestorSibling(const Node&);
static Node* TraversePreviousAncestorSibling(const Node&);
@@ -197,11 +206,9 @@ class CORE_EXPORT FlatTreeTraversal {
const Node* stay_within);
};
-inline ContainerNode* FlatTreeTraversal::Parent(
- const Node& node,
- ParentTraversalDetails* details) {
+inline ContainerNode* FlatTreeTraversal::Parent(const Node& node) {
AssertPrecondition(node);
- ContainerNode* result = TraverseParent(node, details);
+ ContainerNode* result = TraverseParent(node);
AssertPostcondition(result);
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
index e880c282988..c490bd8055e 100644
--- a/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
@@ -39,7 +39,6 @@ class FlatTreeTraversalTest : public PageTestBase {
void SetupDocumentTree(const char* main_html);
- void AttachV0ShadowRoot(Element& shadow_host, const char* shadow_inner_html);
void AttachOpenShadowRoot(Element& shadow_host,
const char* shadow_inner_html);
};
@@ -50,9 +49,7 @@ void FlatTreeTraversalTest::SetupSampleHTML(const char* main_html,
Element* body = GetDocument().body();
body->setInnerHTML(String::FromUTF8(main_html));
auto* shadow_host = To<Element>(NodeTraversal::ChildAt(*body, index));
- ShadowRoot& shadow_root = shadow_host->CreateV0ShadowRootForTesting();
- shadow_root.setInnerHTML(String::FromUTF8(shadow_html));
- body->UpdateDistributionForFlatTreeTraversal();
+ AttachOpenShadowRoot(*shadow_host, shadow_html);
}
void FlatTreeTraversalTest::SetupDocumentTree(const char* main_html) {
@@ -60,20 +57,12 @@ void FlatTreeTraversalTest::SetupDocumentTree(const char* main_html) {
body->setInnerHTML(String::FromUTF8(main_html));
}
-void FlatTreeTraversalTest::AttachV0ShadowRoot(Element& shadow_host,
- const char* shadow_inner_html) {
- ShadowRoot& shadow_root = shadow_host.CreateV0ShadowRootForTesting();
- shadow_root.setInnerHTML(String::FromUTF8(shadow_inner_html));
- GetDocument().body()->UpdateDistributionForFlatTreeTraversal();
-}
-
void FlatTreeTraversalTest::AttachOpenShadowRoot(
Element& shadow_host,
const char* shadow_inner_html) {
ShadowRoot& shadow_root =
shadow_host.AttachShadowRootInternal(ShadowRootType::kOpen);
shadow_root.setInnerHTML(String::FromUTF8(shadow_inner_html));
- GetDocument().body()->UpdateDistributionForFlatTreeTraversal();
}
namespace {
@@ -102,14 +91,14 @@ void TestCommonAncestor(Node* expected_result,
TEST_F(FlatTreeTraversalTest, childAt) {
const char* main_html =
"<div id='m0'>"
- "<span id='m00'>m00</span>"
- "<span id='m01'>m01</span>"
+ "<span slot='#m00' id='m00'>m00</span>"
+ "<span slot='#m01' id='m01'>m01</span>"
"</div>";
const char* shadow_html =
"<a id='s00'>s00</a>"
- "<content select='#m01'></content>"
+ "<slot name='#m01'></slot>"
"<a id='s02'>s02</a>"
- "<a id='s03'><content select='#m00'></content></a>"
+ "<a id='s03'><slot name='#m00'></slot></a>"
"<a id='s04'>s04</a>";
SetupSampleHTML(main_html, shadow_html, 0);
@@ -134,8 +123,6 @@ TEST_F(FlatTreeTraversalTest, childAt) {
for (unsigned index = 0; index < kNumberOfChildNodes; ++index) {
Node* child = FlatTreeTraversal::ChildAt(*shadow_host, index);
- EXPECT_EQ(expected_child_nodes[index], child)
- << "FlatTreeTraversal::childAt(*shadowHost, " << index << ")";
EXPECT_EQ(index, FlatTreeTraversal::Index(*child))
<< "FlatTreeTraversal::index(FlatTreeTraversal(*shadowHost, " << index
<< "))";
@@ -143,13 +130,23 @@ TEST_F(FlatTreeTraversalTest, childAt) {
<< "FlatTreeTraversal::isDescendantOf(*FlatTreeTraversal(*"
"shadowHost, "
<< index << "), *shadowHost)";
+ bool is_slot_element = IsA<HTMLSlotElement>(child);
+ if (is_slot_element) {
+ child = FlatTreeTraversal::FirstChild(*child);
+ }
+ EXPECT_EQ(expected_child_nodes[index], child)
+ << "FlatTreeTraversal::childAt(*shadowHost, " << index << ")";
+ EXPECT_EQ(is_slot_element ? 0 : index, FlatTreeTraversal::Index(*child))
+ << "FlatTreeTraversal::index(FlatTreeTraversal(*shadowHost, " << index
+ << "))";
}
EXPECT_EQ(nullptr,
FlatTreeTraversal::ChildAt(*shadow_host, kNumberOfChildNodes + 1))
<< "Out of bounds childAt() returns nullptr.";
- // Distribute node |m00| is child of node in shadow tree |s03|.
- EXPECT_EQ(m00, FlatTreeTraversal::ChildAt(*s03, 0));
+ // Distributed node |m00| is child of slot in shadow tree |s03|.
+ EXPECT_EQ(
+ m00, FlatTreeTraversal::FirstChild(*FlatTreeTraversal::FirstChild(*s03)));
}
TEST_F(FlatTreeTraversalTest, ChildrenOf) {
@@ -196,19 +193,19 @@ TEST_F(FlatTreeTraversalTest, commonAncestor) {
// prefix "s" means node in shadow tree
const char* main_html =
"<a id='m0'><b id='m00'>m00</b><b id='m01'>m01</b></a>"
- "<a id='m1'>"
- "<b id='m10'>m10</b>"
- "<b id='m11'>m11</b>"
- "<b id='m12'>m12</b>"
- "</a>"
+ "<div id='m1'>"
+ "<b slot='#m10' id='m10'>m10</b>"
+ "<b slot='#m11' id='m11'>m11</b>"
+ "<b slot='#m12' id='m12'>m12</b>"
+ "</div>"
"<a id='m2'><b id='m20'>m20</b><b id='m21'>m21</b></a>";
const char* shadow_html =
"<a id='s10'>s10</a>"
- "<a id='s11'><content select='#m12'></content></a>"
+ "<a id='s11'><slot name='#m12'></slot></a>"
"<a id='s12'>s12</a>"
"<a id='s13'>"
- "<content select='#m10'></content>"
- "<content select='#m11'></content>"
+ "<slot name='#m10'></slot>"
+ "<slot name='#m11'></slot>"
"</a>"
"<a id='s14'>s14</a>";
SetupSampleHTML(main_html, shadow_html, 1);
@@ -263,22 +260,22 @@ TEST_F(FlatTreeTraversalTest, commonAncestor) {
}
// Test case for
-// - nextSkippingChildren
-// - previousSkippingChildren
-TEST_F(FlatTreeTraversalTest, nextSkippingChildren) {
+// - NextSkippingChildren
+// - PreviousAbsoluteSibling
+TEST_F(FlatTreeTraversalTest, SkippingChildrenFunctions) {
const char* main_html =
"<div id='m0'>m0</div>"
"<div id='m1'>"
- "<span id='m10'>m10</span>"
- "<span id='m11'>m11</span>"
+ "<span slot='#m10' id='m10'>m10</span>"
+ "<span slot='#m11' id='m11'>m11</span>"
"</div>"
"<div id='m2'>m2</div>";
const char* shadow_html =
- "<content select='#m11'></content>"
+ "<slot name='#m11'></slot>"
"<a id='s11'>s11</a>"
"<a id='s12'>"
"<b id='s120'>s120</b>"
- "<content select='#m10'></content>"
+ "<slot name='#m10'></slot>"
"</a>";
SetupSampleHTML(main_html, shadow_html, 1);
@@ -288,7 +285,9 @@ TEST_F(FlatTreeTraversalTest, nextSkippingChildren) {
Element* m2 = body->QuerySelector("#m2");
Element* m10 = body->QuerySelector("#m10");
+ Element* m10_slot_parent = To<Element>(FlatTreeTraversal::Parent(*m10));
Element* m11 = body->QuerySelector("#m11");
+ Element* m11_slot_parent = To<Element>(FlatTreeTraversal::Parent(*m11));
ShadowRoot* shadow_root = m1->OpenShadowRoot();
Element* s11 = shadow_root->QuerySelector("#s11");
@@ -297,26 +296,26 @@ TEST_F(FlatTreeTraversalTest, nextSkippingChildren) {
// Main tree node to main tree node
EXPECT_EQ(*m1, FlatTreeTraversal::NextSkippingChildren(*m0));
- EXPECT_EQ(*m0, FlatTreeTraversal::PreviousSkippingChildren(*m1));
+ EXPECT_EQ(*m0, FlatTreeTraversal::PreviousAbsoluteSibling(*m1));
// Distribute node to main tree node
EXPECT_EQ(*m2, FlatTreeTraversal::NextSkippingChildren(*m10));
- EXPECT_EQ(*m1, FlatTreeTraversal::PreviousSkippingChildren(*m2));
+ EXPECT_EQ(*m1, FlatTreeTraversal::PreviousAbsoluteSibling(*m2));
// Distribute node to node in shadow tree
EXPECT_EQ(*s11, FlatTreeTraversal::NextSkippingChildren(*m11));
- EXPECT_EQ(*m11, FlatTreeTraversal::PreviousSkippingChildren(*s11));
+ EXPECT_EQ(*m11_slot_parent, FlatTreeTraversal::PreviousAbsoluteSibling(*s11));
// Node in shadow tree to distributed node
EXPECT_EQ(*s11, FlatTreeTraversal::NextSkippingChildren(*m11));
- EXPECT_EQ(*m11, FlatTreeTraversal::PreviousSkippingChildren(*s11));
+ EXPECT_EQ(*m11_slot_parent, FlatTreeTraversal::PreviousAbsoluteSibling(*s11));
- EXPECT_EQ(*m10, FlatTreeTraversal::NextSkippingChildren(*s120));
- EXPECT_EQ(*s120, FlatTreeTraversal::PreviousSkippingChildren(*m10));
+ EXPECT_EQ(*m10_slot_parent, FlatTreeTraversal::NextSkippingChildren(*s120));
+ EXPECT_EQ(*s120, FlatTreeTraversal::PreviousAbsoluteSibling(*m10));
// Node in shadow tree to main tree
EXPECT_EQ(*m2, FlatTreeTraversal::NextSkippingChildren(*s12));
- EXPECT_EQ(*m1, FlatTreeTraversal::PreviousSkippingChildren(*m2));
+ EXPECT_EQ(*m1, FlatTreeTraversal::PreviousAbsoluteSibling(*m2));
}
TEST_F(FlatTreeTraversalTest, AncestorsOf) {
@@ -360,16 +359,16 @@ TEST_F(FlatTreeTraversalTest, lastWithin) {
const char* main_html =
"<div id='m0'>m0</div>"
"<div id='m1'>"
- "<span id='m10'>m10</span>"
- "<span id='m11'>m11</span>"
+ "<span slot='#m10' id='m10'>m10</span>"
+ "<span slot='#m11' id='m11'>m11</span>"
"<span id='m12'>m12</span>" // #m12 is not distributed.
"</div>"
"<div id='m2'></div>";
const char* shadow_html =
- "<content select='#m11'></content>"
+ "<slot name='#m11'></slot>"
"<a id='s11'>s11</a>"
"<a id='s12'>"
- "<content select='#m10'></content>"
+ "<slot name='#m10'></slot>"
"</a>";
SetupSampleHTML(main_html, shadow_html, 1);
@@ -404,16 +403,16 @@ TEST_F(FlatTreeTraversalTest, previousPostOrder) {
const char* main_html =
"<div id='m0'>m0</div>"
"<div id='m1'>"
- "<span id='m10'>m10</span>"
- "<span id='m11'>m11</span>"
+ "<span slot='#m10' id='m10'>m10</span>"
+ "<span slot='#m11' id='m11'>m11</span>"
"</div>"
"<div id='m2'>m2</div>";
const char* shadow_html =
- "<content select='#m11'></content>"
+ "<slot name='#m11'></slot>"
"<a id='s11'>s11</a>"
"<a id='s12'>"
"<b id='s120'>s120</b>"
- "<content select='#m10'></content>"
+ "<slot name='#m10'></slot>"
"</a>";
SetupSampleHTML(main_html, shadow_html, 1);
@@ -423,6 +422,7 @@ TEST_F(FlatTreeTraversalTest, previousPostOrder) {
Element* m2 = body->QuerySelector("#m2");
Element* m10 = body->QuerySelector("#m10");
+ Element* m10_slot_parent = To<Element>(FlatTreeTraversal::Parent(*m10));
Element* m11 = body->QuerySelector("#m11");
ShadowRoot* shadow_root = m1->OpenShadowRoot();
@@ -443,7 +443,7 @@ TEST_F(FlatTreeTraversalTest, previousPostOrder) {
EXPECT_EQ(*m2->firstChild(), FlatTreeTraversal::PreviousPostOrder(*m2));
EXPECT_EQ(*s11->firstChild(), FlatTreeTraversal::PreviousPostOrder(*s11));
- EXPECT_EQ(*m10, FlatTreeTraversal::PreviousPostOrder(*s12));
+ EXPECT_EQ(*m10_slot_parent, FlatTreeTraversal::PreviousPostOrder(*s12));
EXPECT_EQ(*s120->firstChild(), FlatTreeTraversal::PreviousPostOrder(*s120));
EXPECT_EQ(*s11, FlatTreeTraversal::PreviousPostOrder(*s120->firstChild()));
EXPECT_EQ(nullptr,
@@ -468,49 +468,6 @@ TEST_F(FlatTreeTraversalTest, nextSiblingNotInDocumentFlatTree) {
EXPECT_EQ(nullptr, FlatTreeTraversal::PreviousSibling(*m10));
}
-TEST_F(FlatTreeTraversalTest, redistribution) {
- const char* main_html =
- "<div id='m0'>m0</div>"
- "<div id='m1'>"
- "<span id='m10'>m10</span>"
- "<span id='m11'>m11</span>"
- "</div>"
- "<div id='m2'>m2</div>";
- const char* shadow_html1 =
- "<div id='s1'>"
- "<content></content>"
- "</div>";
-
- SetupSampleHTML(main_html, shadow_html1, 1);
-
- const char* shadow_html2 =
- "<div id='s2'>"
- "<content select='#m10'></content>"
- "<span id='s21'>s21</span>"
- "</div>";
-
- Element* body = GetDocument().body();
- Element* m1 = body->QuerySelector("#m1");
- Element* m10 = body->QuerySelector("#m10");
-
- ShadowRoot* shadow_root1 = m1->OpenShadowRoot();
- Element* s1 = shadow_root1->QuerySelector("#s1");
-
- AttachV0ShadowRoot(*s1, shadow_html2);
-
- ShadowRoot* shadow_root2 = s1->OpenShadowRoot();
- Element* s21 = shadow_root2->QuerySelector("#s21");
-
- EXPECT_EQ(s21, FlatTreeTraversal::NextSibling(*m10));
- EXPECT_EQ(m10, FlatTreeTraversal::PreviousSibling(*s21));
-
- // FlatTreeTraversal::traverseSiblings does not work for a node which is not
- // in a document flat tree.
- // e.g. The following test fails. The result of
- // FlatTreeTraversal::previousSibling(*m11)) will be #m10, instead of
- // nullptr. Element* m11 = body->querySelector("#m11"); EXPECT_EQ(nullptr,
- // FlatTreeTraversal::previousSibling(*m11));
-}
TEST_F(FlatTreeTraversalTest, v1Simple) {
const char* main_html =
diff --git a/chromium/third_party/blink/renderer/core/dom/focus_params.h b/chromium/third_party/blink/renderer/core/dom/focus_params.h
index 98c90ea10ef..c6245bcd9ea 100644
--- a/chromium/third_party/blink/renderer/core/dom/focus_params.h
+++ b/chromium/third_party/blink/renderer/core/dom/focus_params.h
@@ -31,6 +31,7 @@ struct FocusParams {
mojom::blink::FocusType type = mojom::blink::FocusType::kNone;
InputDeviceCapabilities* source_capabilities = nullptr;
const FocusOptions* options = nullptr;
+ bool omit_blur_events = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/interest_cohort.idl b/chromium/third_party/blink/renderer/core/dom/interest_cohort.idl
new file mode 100644
index 00000000000..d334a293426
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/interest_cohort.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/floc/#dictdef-interestcohort
+
+dictionary InterestCohort {
+ DOMString id;
+ DOMString version;
+};
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index b5e43511757..b7995dd0537 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -33,7 +33,6 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/generated_children.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
@@ -51,7 +50,6 @@ LayoutTreeBuilderForElement::LayoutTreeBuilderForElement(
const ComputedStyle* style,
LegacyLayout legacy)
: LayoutTreeBuilder(element, context, style), legacy_(legacy) {
- DCHECK(element.CanParticipateInFlatTree());
DCHECK(style_);
DCHECK(!style_->IsEnsuredInDisplayNone());
}
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
index 3ef1701dd42..e0e04334b16 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
@@ -46,39 +46,23 @@ static bool IsLayoutObjectReparented(const LayoutObject* layout_object) {
return element->IsInTopLayer();
}
-void LayoutTreeBuilderTraversal::ParentDetails::DidTraverseInsertionPoint(
- const V0InsertionPoint* insertion_point) {
- if (!insertion_point_) {
- insertion_point_ = insertion_point;
- }
-}
-
-inline static void AssertPseudoElementParent(
- const PseudoElement& pseudo_element) {
- DCHECK(pseudo_element.parentNode());
- DCHECK(pseudo_element.parentNode()->CanParticipateInFlatTree());
-}
-
-ContainerNode* LayoutTreeBuilderTraversal::Parent(const Node& node,
- ParentDetails* details) {
+ContainerNode* LayoutTreeBuilderTraversal::Parent(const Node& node) {
// TODO(hayato): Uncomment this once we can be sure
// LayoutTreeBuilderTraversal::parent() is used only for a node which is
// connected.
// DCHECK(node.isConnected());
if (auto* element = DynamicTo<PseudoElement>(node)) {
- AssertPseudoElementParent(*element);
+ DCHECK(node.parentNode());
return node.parentNode();
}
- return FlatTreeTraversal::Parent(node, details);
+ return FlatTreeTraversal::Parent(node);
}
-ContainerNode* LayoutTreeBuilderTraversal::LayoutParent(
- const Node& node,
- ParentDetails* details) {
- ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(node, details);
+ContainerNode* LayoutTreeBuilderTraversal::LayoutParent(const Node& node) {
+ ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(node);
while (parent && HasDisplayContentsStyle(*parent))
- parent = LayoutTreeBuilderTraversal::Parent(*parent, details);
+ parent = LayoutTreeBuilderTraversal::Parent(*parent);
return parent;
}
@@ -92,8 +76,8 @@ Node* LayoutTreeBuilderTraversal::NextSibling(const Node& node) {
PseudoId pseudo_id = node.GetPseudoId();
Element* parent_element;
if (pseudo_id != kPseudoIdNone) {
- AssertPseudoElementParent(To<PseudoElement>(node));
parent_element = DynamicTo<Element>(*node.parentNode());
+ DCHECK(parent_element);
}
switch (pseudo_id) {
case kPseudoIdMarker:
@@ -127,8 +111,8 @@ Node* LayoutTreeBuilderTraversal::PreviousSibling(const Node& node) {
PseudoId pseudo_id = node.GetPseudoId();
Element* parent_element;
if (pseudo_id != kPseudoIdNone) {
- AssertPseudoElementParent(To<PseudoElement>(node));
parent_element = DynamicTo<Element>(*node.parentNode());
+ DCHECK(parent_element);
}
switch (pseudo_id) {
case kPseudoIdAfter:
diff --git a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h
index 106020b85a9..108ea82bf9f 100644
--- a/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h
+++ b/chromium/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h
@@ -30,7 +30,6 @@
#include <cstdint>
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
@@ -42,28 +41,9 @@ class CORE_EXPORT LayoutTreeBuilderTraversal {
public:
static const int32_t kTraverseAllSiblings = -2;
- class ParentDetails {
- STACK_ALLOCATED();
- public:
- ParentDetails() : insertion_point_(nullptr) {}
-
- const V0InsertionPoint* GetInsertionPoint() const {
- return insertion_point_;
- }
-
- void DidTraverseInsertionPoint(const V0InsertionPoint*);
-
- bool operator==(const ParentDetails& other) {
- return insertion_point_ == other.insertion_point_;
- }
-
- private:
- const V0InsertionPoint* insertion_point_;
- };
-
- static ContainerNode* Parent(const Node&, ParentDetails* = nullptr);
- static ContainerNode* LayoutParent(const Node&, ParentDetails* = nullptr);
+ static ContainerNode* Parent(const Node&);
+ static ContainerNode* LayoutParent(const Node&);
static Node* FirstChild(const Node&);
static Node* LastChild(const Node&);
static Node* NextSibling(const Node&);
diff --git a/chromium/third_party/blink/renderer/core/dom/named_node_map.idl b/chromium/third_party/blink/renderer/core/dom/named_node_map.idl
index 13482eba277..63bb2867eca 100644
--- a/chromium/third_party/blink/renderer/core/dom/named_node_map.idl
+++ b/chromium/third_party/blink/renderer/core/dom/named_node_map.idl
@@ -28,8 +28,8 @@
[Affects=Nothing, MeasureAs=NamedNodeMapItem] getter Attr? item(unsigned long index);
[Affects=Nothing, MeasureAs=NamedNodeMapGetNamedItem] getter Attr? getNamedItem(DOMString name);
[MeasureAs=NamedNodeMapGetNamedItemNS] Attr? getNamedItemNS(DOMString? namespaceURI, DOMString localName);
- [RaisesException, CEReactions, CustomElementCallbacks, MeasureAs=NamedNodeMapSetNamedItem] Attr? setNamedItem(Attr attr);
- [RaisesException, CEReactions, CustomElementCallbacks, MeasureAs=NamedNodeMapSetNamedItemNS] Attr? setNamedItemNS(Attr attr);
- [RaisesException, CEReactions, CustomElementCallbacks, MeasureAs=NamedNodeMapRemoveNamedItem] Attr removeNamedItem(DOMString name);
- [RaisesException, CEReactions, CustomElementCallbacks, MeasureAs=NamedNodeMapRemoveNamedItemNS] Attr removeNamedItemNS(DOMString? namespaceURI, DOMString localName);
+ [RaisesException, CEReactions, MeasureAs=NamedNodeMapSetNamedItem] Attr? setNamedItem(Attr attr);
+ [RaisesException, CEReactions, MeasureAs=NamedNodeMapSetNamedItemNS] Attr? setNamedItemNS(Attr attr);
+ [RaisesException, CEReactions, MeasureAs=NamedNodeMapRemoveNamedItem] Attr removeNamedItem(DOMString name);
+ [RaisesException, CEReactions, MeasureAs=NamedNodeMapRemoveNamedItemNS] Attr removeNamedItemNS(DOMString? namespaceURI, DOMString localName);
};
diff --git a/chromium/third_party/blink/renderer/core/dom/node.cc b/chromium/third_party/blink/renderer/core/dom/node.cc
index df458766511..e0dbf8f56cb 100644
--- a/chromium/third_party/blink/renderer/core/dom/node.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node.cc
@@ -59,6 +59,7 @@
#include "third_party/blink/renderer/core/dom/events/event_path.h"
#include "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/dom/mutation_observer_registration.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -75,7 +76,6 @@
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/dom/tree_scope_adopter.h"
#include "third_party/blink/renderer/core/dom/user_action_element_set.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/events/event_util.h"
@@ -101,6 +101,7 @@
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
#include "third_party/blink/renderer/core/html/html_dialog_element.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_popup_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -1025,8 +1026,6 @@ Node* Node::cloneNode(bool deep) const {
}
void Node::normalize() {
- UpdateDistributionForFlatTreeTraversal();
-
// Go through the subtree beneath us, normalizing all nodes. This means that
// any two adjacent text nodes are merged and any empty text nodes are
// removed.
@@ -1153,7 +1152,7 @@ bool Node::IsClosedShadowHiddenFrom(const Node& other) const {
for (; scope->ParentTreeScope(); scope = scope->ParentTreeScope()) {
const ContainerNode& root = scope->RootNode();
auto* shadow_root = DynamicTo<ShadowRoot>(root);
- if (shadow_root && !shadow_root->IsOpenOrV0())
+ if (shadow_root && !shadow_root->IsOpen())
break;
}
@@ -1165,62 +1164,11 @@ bool Node::IsClosedShadowHiddenFrom(const Node& other) const {
return true;
}
-bool Node::NeedsDistributionRecalc() const {
- return ShadowIncludingRoot().ChildNeedsDistributionRecalc();
-}
-
-bool Node::MayContainLegacyNodeTreeWhereDistributionShouldBeSupported() const {
- if (isConnected() && !GetDocument().MayContainV0Shadow()) {
- // TODO(crbug.com/787717): Some built-in elements still use <content>
- // elements in their user-agent shadow roots. DCHECK() fails if such an
- // element is used.
- DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
- return false;
- }
- return true;
-}
-
void Node::UpdateDistributionForUnknownReasons() {
- UpdateDistributionInternal();
- // For the sake of safety, call RecalcSlotAssignments as well as
- // UpdateDistribution().
if (isConnected())
GetDocument().GetSlotAssignmentEngine().RecalcSlotAssignments();
}
-void Node::UpdateDistributionInternal() {
- if (!MayContainLegacyNodeTreeWhereDistributionShouldBeSupported())
- return;
- // Extra early out to avoid spamming traces.
- if (isConnected() && !GetDocument().ChildNeedsDistributionRecalc())
- return;
- TRACE_EVENT0("blink", "Node::updateDistribution");
- ScriptForbiddenScope forbid_script;
- Node& root = ShadowIncludingRoot();
- if (root.ChildNeedsDistributionRecalc())
- root.RecalcDistribution();
-}
-
-void Node::RecalcDistribution() {
- DCHECK(ChildNeedsDistributionRecalc());
-
- if (GetShadowRoot())
- GetShadowRoot()->DistributeIfNeeded();
-
- DCHECK(ScriptForbiddenScope::IsScriptForbidden());
- for (Node* child = firstChild(); child; child = child->nextSibling()) {
- if (child->ChildNeedsDistributionRecalc())
- child->RecalcDistribution();
- }
-
- if (ShadowRoot* root = GetShadowRoot()) {
- if (root->ChildNeedsDistributionRecalc())
- root->RecalcDistribution();
- }
-
- ClearChildNeedsDistributionRecalc();
-}
-
void Node::SetIsLink(bool is_link) {
SetFlag(is_link && !SVGImage::IsInSVGImage(To<Element>(this)), kIsLinkFlag);
}
@@ -1253,15 +1201,6 @@ void Node::MarkAncestorsWithChildNeedsStyleInvalidation() {
GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
}
-void Node::MarkAncestorsWithChildNeedsDistributionRecalc() {
- ScriptForbiddenScope forbid_script_during_raw_iteration;
- for (Node* node = this; node && !node->ChildNeedsDistributionRecalc();
- node = node->ParentOrShadowHostNode()) {
- node->SetChildNeedsDistributionRecalc();
- }
- GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
-}
-
void Node::MarkSubtreeNeedsStyleRecalcForFontUpdates() {
if (GetStyleChangeType() == kSubtreeStyleChange)
return;
@@ -1291,45 +1230,14 @@ void Node::MarkSubtreeNeedsStyleRecalcForFontUpdates() {
child->MarkSubtreeNeedsStyleRecalcForFontUpdates();
}
-#if DCHECK_IS_ON()
-namespace {
-class AllowDirtyShadowV0TraversalScope {
- STACK_ALLOCATED();
-
- public:
- explicit AllowDirtyShadowV0TraversalScope(Document& document)
- : document_(&document),
- old_value_(document.AllowDirtyShadowV0Traversal()) {
- document.SetAllowDirtyShadowV0Traversal(true);
- }
- ~AllowDirtyShadowV0TraversalScope() {
- document_->SetAllowDirtyShadowV0Traversal(old_value_);
- }
-
- private:
- Document* document_;
- bool old_value_;
-};
-} // namespace
-#define ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(document) \
- AllowDirtyShadowV0TraversalScope traversal_scope(document)
-#else // DCHECK_IS_ON()
-#define ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(document)
-#endif // DCHECK_IS_ON()
-
bool Node::ShouldSkipMarkingStyleDirty() const {
if (GetComputedStyle())
return false;
- ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(GetDocument());
-
// If we don't have a computed style, and our parent element does not have a
// computed style it's not necessary to mark this node for style recalc.
- if (auto* parent = GetStyleRecalcParent()) {
- while (parent && !parent->CanParticipateInFlatTree())
- parent = parent->GetStyleRecalcParent();
+ if (Element* parent = GetStyleRecalcParent())
return !parent || !parent->GetComputedStyle();
- }
// If this is the root element, and it does not have a computed style, we
// still need to mark it for style recalc since it may change from
// display:none. Otherwise, the node is not in the flat tree, and we can
@@ -1339,10 +1247,9 @@ bool Node::ShouldSkipMarkingStyleDirty() const {
}
void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
- ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(GetDocument());
- ContainerNode* style_parent = GetStyleRecalcParent();
+ Element* style_parent = GetStyleRecalcParent();
bool parent_dirty = style_parent && style_parent->IsDirtyForStyleRecalc();
- ContainerNode* ancestor = style_parent;
+ Element* ancestor = style_parent;
for (; ancestor && !ancestor->ChildNeedsStyleRecalc();
ancestor = ancestor->GetStyleRecalcParent()) {
if (!ancestor->isConnected())
@@ -1353,11 +1260,8 @@ void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
// If we reach a locked ancestor, we should abort since the ancestor marking
// will be done when the lock is committed.
if (RuntimeEnabledFeatures::CSSContentVisibilityEnabled()) {
- auto* ancestor_element = DynamicTo<Element>(ancestor);
- if (ancestor_element &&
- ancestor_element->ChildStyleRecalcBlockedByDisplayLock()) {
+ if (ancestor->ChildStyleRecalcBlockedByDisplayLock())
break;
- }
}
}
if (!isConnected())
@@ -1371,14 +1275,10 @@ void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
if (const ComputedStyle* current_style = GetComputedStyle()) {
if (current_style->IsEnsuredOutsideFlatTree())
return;
- } else {
- while (style_parent && !style_parent->CanParticipateInFlatTree())
- style_parent = style_parent->GetStyleRecalcParent();
- if (style_parent) {
- if (const auto* parent_style = style_parent->GetComputedStyle()) {
- if (parent_style->IsEnsuredOutsideFlatTree())
- return;
- }
+ } else if (style_parent) {
+ if (const auto* parent_style = style_parent->GetComputedStyle()) {
+ if (parent_style->IsEnsuredOutsideFlatTree())
+ return;
}
}
// If we're in a locked subtree, then we should not update the style recalc
@@ -1388,13 +1288,10 @@ void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
if (RuntimeEnabledFeatures::CSSContentVisibilityEnabled() &&
GetDocument().GetDisplayLockDocumentState().LockedDisplayLockCount() >
0) {
- for (auto* ancestor_copy = ancestor; ancestor_copy;
+ for (Element* ancestor_copy = ancestor; ancestor_copy;
ancestor_copy = ancestor_copy->GetStyleRecalcParent()) {
- auto* ancestor_copy_element = DynamicTo<Element>(ancestor_copy);
- if (ancestor_copy_element &&
- ancestor_copy_element->ChildStyleRecalcBlockedByDisplayLock()) {
+ if (ancestor_copy->ChildStyleRecalcBlockedByDisplayLock())
return;
- }
}
}
@@ -1405,20 +1302,11 @@ void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
Element* Node::FlatTreeParentForChildDirty() const {
if (IsPseudoElement())
return ParentOrShadowHostElement();
- if (IsChildOfV1ShadowHost()) {
+ if (IsChildOfShadowHost()) {
if (auto* data = GetFlatTreeNodeData())
return data->AssignedSlot();
return nullptr;
}
- if (IsInV0ShadowTree() || IsChildOfV0ShadowHost()) {
- if (ShadowRootWhereNodeCanBeDistributedForV0(*this)) {
- if (V0InsertionPoint* insertion_point =
- const_cast<V0InsertionPoint*>(ResolveReprojection(this))) {
- return insertion_point;
- }
- return nullptr;
- }
- }
return ParentOrShadowHostElement();
}
@@ -1441,7 +1329,6 @@ void Node::MarkAncestorsWithChildNeedsReattachLayoutTree() {
void Node::SetNeedsReattachLayoutTree() {
DCHECK(GetDocument().InStyleRecalc());
- DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
DCHECK(IsElementNode() || IsTextNode());
DCHECK(InActiveDocument());
SetFlag(kNeedsReattachLayoutTree);
@@ -1502,8 +1389,6 @@ bool Node::IsInert() const {
if (!isConnected() || !CanParticipateInFlatTree())
return true;
- DCHECK(!ChildNeedsDistributionRecalc());
-
if (this != GetDocument() && this != GetDocument().documentElement()) {
const Element* modal_element = GetDocument().ActiveModalDialog();
if (!modal_element)
@@ -1702,7 +1587,8 @@ void Node::AttachLayoutTree(AttachContext& context) {
}
void Node::DetachLayoutTree(bool performing_reattach) {
- DCHECK(GetDocument().Lifecycle().StateAllowsDetach());
+ DCHECK(GetDocument().Lifecycle().StateAllowsDetach() ||
+ GetDocument().GetStyleEngine().InContainerQueryStyleRecalc());
DCHECK(!performing_reattach ||
GetDocument().GetStyleEngine().InRebuildLayoutTree());
DocumentLifecycle::DetachScope will_detach(GetDocument().Lifecycle());
@@ -1808,12 +1694,11 @@ bool Node::IsStyledElement() const {
bool Node::CanParticipateInFlatTree() const {
// TODO(hayato): Return false for pseudo elements.
- return !IsShadowRoot() && !IsActiveV0InsertionPoint(*this);
+ return !IsShadowRoot();
}
-bool Node::IsActiveSlotOrActiveV0InsertionPoint() const {
- return ToHTMLSlotElementIfSupportsAssignmentOrNull(*this) ||
- IsActiveV0InsertionPoint(*this);
+bool Node::IsActiveSlot() const {
+ return ToHTMLSlotElementIfSupportsAssignmentOrNull(*this);
}
AtomicString Node::SlotName() const {
@@ -1826,34 +1711,18 @@ AtomicString Node::SlotName() const {
return g_empty_atom;
}
-bool Node::IsInV1ShadowTree() const {
- ShadowRoot* shadow_root = ContainingShadowRoot();
- return shadow_root && shadow_root->IsV1();
-}
-
-bool Node::IsInV0ShadowTree() const {
- ShadowRoot* shadow_root = ContainingShadowRoot();
- return shadow_root && !shadow_root->IsV1();
-}
-
ShadowRoot* Node::ParentElementShadowRoot() const {
Element* parent = parentElement();
return parent ? parent->GetShadowRoot() : nullptr;
}
-bool Node::IsChildOfV1ShadowHost() const {
- ShadowRoot* parent_shadow_root = ParentElementShadowRoot();
- return parent_shadow_root && parent_shadow_root->IsV1();
+bool Node::IsChildOfShadowHost() const {
+ return ParentElementShadowRoot();
}
-bool Node::IsChildOfV0ShadowHost() const {
- ShadowRoot* parent_shadow_root = ParentElementShadowRoot();
- return parent_shadow_root && !parent_shadow_root->IsV1();
-}
-
-ShadowRoot* Node::V1ShadowRootOfParent() const {
+ShadowRoot* Node::ShadowRootOfParent() const {
if (Element* parent = parentElement())
- return parent->ShadowRootIfV1();
+ return parent->GetShadowRoot();
return nullptr;
}
@@ -2333,6 +2202,40 @@ void Node::InvalidateIfHasEffectiveAppearance() const {
layout_object->SetSubtreeShouldDoFullPaintInvalidation();
}
+Node::InsertionNotificationRequest Node::InsertedInto(
+ ContainerNode& insertion_point) {
+ DCHECK(!ChildNeedsStyleInvalidation());
+ DCHECK(!NeedsStyleInvalidation());
+ DCHECK(insertion_point.isConnected() || insertion_point.IsInShadowTree() ||
+ IsContainerNode());
+ if (insertion_point.isConnected()) {
+ SetFlag(kIsConnectedFlag);
+ insertion_point.GetDocument().IncrementNodeCount();
+ }
+ if (ParentOrShadowHostNode()->IsInShadowTree())
+ SetFlag(kIsInShadowTreeFlag);
+ if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
+ cache->ChildrenChanged(&insertion_point);
+ return kInsertionDone;
+}
+
+void Node::RemovedFrom(ContainerNode& insertion_point) {
+ DCHECK(insertion_point.isConnected() || IsContainerNode() ||
+ IsInShadowTree());
+ if (insertion_point.isConnected()) {
+ ClearNeedsStyleRecalc();
+ ClearChildNeedsStyleRecalc();
+ ClearNeedsStyleInvalidation();
+ ClearChildNeedsStyleInvalidation();
+ ClearFlag(kIsConnectedFlag);
+ insertion_point.GetDocument().DecrementNodeCount();
+ }
+ if (IsInShadowTree() && !ContainingTreeScope().RootNode().IsShadowRoot())
+ ClearFlag(kIsInShadowTreeFlag);
+ if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
+ cache->Remove(this);
+}
+
String Node::DebugName() const {
StringBuilder name;
AppendUnsafe(name, DebugNodeName());
@@ -2651,6 +2554,17 @@ ExecutionContext* Node::GetExecutionContext() const {
void Node::WillMoveToNewDocument(Document& old_document,
Document& new_document) {
+ // In rare situations, this node may be the focused element of the old
+ // document. In this case, we need to clear the focused element of the old
+ // document, and since we are currently in an event forbidden scope, we can't
+ // fire the blur event.
+ if (old_document.FocusedElement() == this) {
+ FocusParams params(SelectionBehaviorOnFocus::kNone,
+ mojom::blink::FocusType::kNone, nullptr);
+ params.omit_blur_events = true;
+ old_document.SetFocusedElement(nullptr, params);
+ }
+
if (!old_document.GetPage() ||
old_document.GetPage() == new_document.GetPage())
return;
@@ -2925,6 +2839,17 @@ void Node::NotifyMutationObserversNodeWillDetach() {
}
void Node::HandleLocalEvents(Event& event) {
+ if (UNLIKELY(IsDocumentNode())) {
+ if (GetDocument().PopupShowing() &&
+ (event.eventPhase() == Event::kCapturingPhase ||
+ event.eventPhase() == Event::kAtTarget)) {
+ DCHECK(RuntimeEnabledFeatures::HTMLPopupElementEnabled());
+ // There is a popup visible - check if this event should "light dismiss"
+ // one or more popups.
+ HTMLPopupElement::HandleLightDismiss(event);
+ }
+ }
+
if (!HasEventTargetData())
return;
@@ -2990,14 +2915,12 @@ DispatchEventResult Node::DispatchDOMActivateEvent(int detail,
}
void Node::DispatchSimulatedClick(const Event* underlying_event,
- SimulatedClickMouseEventOptions event_options,
SimulatedClickCreationScope scope) {
if (auto* element = IsElementNode() ? To<Element>(this) : parentElement()) {
element->ActivateDisplayLockIfNeeded(
DisplayLockActivationReason::kSimulatedClick);
}
- EventDispatcher::DispatchSimulatedClick(*this, underlying_event,
- event_options, scope);
+ EventDispatcher::DispatchSimulatedClick(*this, underlying_event, scope);
}
void Node::DefaultEventHandler(Event& event) {
@@ -3115,34 +3038,17 @@ void Node::DecrementConnectedSubframeCount() {
RareData()->DecrementConnectedSubframeCount();
}
-StaticNodeList* Node::getDestinationInsertionPoints() {
- // TODO(crbug.com/937746): Anything caught by this DCHECK is using the
- // now-removed Shadow DOM v0 API.
- DCHECK(false)
- << "Shadow DOM v0 has been removed (getDestinationInsertionPoints).";
-
- UpdateDistributionForLegacyDistributedNodes();
- HeapVector<Member<V0InsertionPoint>, 8> insertion_points;
- CollectDestinationInsertionPoints(*this, insertion_points);
- HeapVector<Member<Node>> filtered_insertion_points;
- for (const auto& insertion_point : insertion_points) {
- DCHECK(insertion_point->ContainingShadowRoot());
- if (!insertion_point->ContainingShadowRoot()->IsOpenOrV0())
- break;
- filtered_insertion_points.push_back(insertion_point);
- }
- return StaticNodeList::Adopt(filtered_insertion_points);
+ShadowRoot* Node::GetSlotAssignmentRoot() const {
+ DCHECK(!IsPseudoElement());
+ ShadowRoot* root = ShadowRootOfParent();
+ return (root && root->HasSlotAssignment()) ? root : nullptr;
}
HTMLSlotElement* Node::AssignedSlot() const {
- DCHECK(!IsPseudoElement());
- ShadowRoot* root = V1ShadowRootOfParent();
+ ShadowRoot* root = GetSlotAssignmentRoot();
if (!root)
return nullptr;
- if (!root->HasSlotAssignment())
- return nullptr;
-
// TODO(hayato): Node::AssignedSlot() shouldn't be called while
// in executing RecalcAssignment(), however, unfortunately,
// that could happen as follows:
@@ -3171,9 +3077,21 @@ HTMLSlotElement* Node::AssignedSlot() const {
return nullptr;
}
+// Used when assignment recalc is forbidden, i.e., DetachLayoutTree().
+// Returned assignedSlot is not guaranteed up to date.
+HTMLSlotElement* Node::AssignedSlotWithoutRecalc() const {
+ if (!GetSlotAssignmentRoot())
+ return nullptr;
+
+ if (FlatTreeNodeData* data = GetFlatTreeNodeData())
+ return data->AssignedSlot();
+
+ return nullptr;
+}
+
HTMLSlotElement* Node::assignedSlotForBinding() {
// assignedSlot doesn't need to recalc slot assignment
- if (ShadowRoot* root = V1ShadowRootOfParent()) {
+ if (ShadowRoot* root = ShadowRootOfParent()) {
if (root->GetType() == ShadowRootType::kOpen)
return AssignedSlot();
}
@@ -3252,7 +3170,6 @@ void Node::SetCustomElementState(CustomElementState new_state) {
}
DCHECK(IsHTMLElement());
- DCHECK_NE(kV0Upgraded, GetV0CustomElementState());
auto* element = To<Element>(this);
bool was_defined = element->IsDefined();
@@ -3261,45 +3178,15 @@ void Node::SetCustomElementState(CustomElementState new_state) {
static_cast<NodeFlags>(new_state);
DCHECK(new_state == GetCustomElementState());
- if (element->IsDefined() != was_defined) {
+ if (element->IsDefined() != was_defined)
element->PseudoStateChanged(CSSSelector::kPseudoDefined);
- if (RuntimeEnabledFeatures::CustomElementsV0Enabled())
- element->PseudoStateChanged(CSSSelector::kPseudoUnresolved);
- }
-}
-
-void Node::SetV0CustomElementState(V0CustomElementState new_state) {
- DCHECK(RuntimeEnabledFeatures::CustomElementsV0Enabled());
- V0CustomElementState old_state = GetV0CustomElementState();
-
- switch (new_state) {
- case kV0NotCustomElement:
- NOTREACHED(); // Everything starts in this state
- return;
-
- case kV0WaitingForUpgrade:
- DCHECK_EQ(kV0NotCustomElement, old_state);
- break;
-
- case kV0Upgraded:
- DCHECK_EQ(kV0WaitingForUpgrade, old_state);
- break;
- }
-
- DCHECK(IsHTMLElement() || IsSVGElement());
- DCHECK(CustomElementState::kCustom != GetCustomElementState());
- SetFlag(kV0CustomElementFlag);
- SetFlag(new_state == kV0Upgraded, kV0CustomElementUpgradedFlag);
-
- if (old_state == kV0NotCustomElement || new_state == kV0Upgraded) {
- To<Element>(this)->PseudoStateChanged(CSSSelector::kPseudoUnresolved);
- To<Element>(this)->PseudoStateChanged(CSSSelector::kPseudoDefined);
- }
}
void Node::CheckSlotChange(SlotChangeType slot_change_type) {
// Common check logic is used in both cases, "after inserted" and "before
- // removed".
+ // removed". This function calls DidSlotChange() on the appropriate nodes,
+ // e.g. the assigned slot for this node, or the parent slot for a slot's
+ // fallback content.
// Relevant DOM Standard:
// https://dom.spec.whatwg.org/#concept-node-insert
@@ -3313,7 +3200,7 @@ void Node::CheckSlotChange(SlotChangeType slot_change_type) {
if (!IsSlotable())
return;
- if (ShadowRoot* root = V1ShadowRootOfParent()) {
+ if (ShadowRoot* root = ShadowRootOfParent()) {
// A shadow host's child can be assigned to a slot in the host's shadow
// tree.
@@ -3321,14 +3208,19 @@ void Node::CheckSlotChange(SlotChangeType slot_change_type) {
// slotables" at this timing, we skip it as an optimization.
if (HTMLSlotElement* slot = root->AssignedSlotFor(*this))
slot->DidSlotChange(slot_change_type);
- } else if (IsInV1ShadowTree()) {
- // Checking for fallback content if the node is in a v1 shadow tree.
+ } else if (IsInShadowTree()) {
+ // Checking for fallback content if the node is in a shadow tree.
if (auto* parent_slot = DynamicTo<HTMLSlotElement>(parentElement())) {
- DCHECK(parent_slot->SupportsAssignment());
// The parent_slot's assigned nodes might not be calculated because they
// are lazy evaluated later at UpdateDistribution() so we have to check it
- // here.
- if (!parent_slot->HasAssignedNodesSlow())
+ // here. Also, parent_slot may have already been removed, if this was the
+ // removal of nested slots, e.g.
+ // <slot name=parent-slot><slot name=this-slot>fallback</slot></slot>.
+ // In that case, parent-slot has already been removed, so parent_slot->
+ // SupportsAssignment() is false, but this-slot is still in the process
+ // of being removed, so IsInShadowTree() is still true.
+ if (parent_slot->SupportsAssignment() &&
+ !parent_slot->HasAssignedNodesSlow())
parent_slot->DidSlotChange(slot_change_type);
}
}
@@ -3374,12 +3266,7 @@ bool Node::HasMediaControlAncestor() const {
void Node::FlatTreeParentChanged() {
if (!isConnected())
return;
- // TODO(futhark): Replace with DCHECK(IsSlotable()) when Shadow DOM V0 support
- // is removed.
- if (!IsElementNode() && !IsTextNode()) {
- DCHECK(GetDocument().MayContainV0Shadow());
- return;
- }
+ DCHECK(IsSlotable());
if (const ComputedStyle* style = GetComputedStyle()) {
// We are moving a node with ensured computed style into the flat tree.
// Clear ensured styles so that we can use IsEnsuredOutsideFlatTree() to
@@ -3404,6 +3291,9 @@ void Node::FlatTreeParentChanged() {
// We also need to force a layout tree re-attach since the layout tree parent
// box may have changed.
SetForceReattachLayoutTree();
+
+ if (auto* element = DynamicTo<HTMLElement>(this))
+ element->AddCandidateDirectionalityForSlot();
}
void Node::RemovedFromFlatTree() {
diff --git a/chromium/third_party/blink/renderer/core/dom/node.h b/chromium/third_party/blink/renderer/core/dom/node.h
index 261c41a49e2..a3a9a7b3905 100644
--- a/chromium/third_party/blink/renderer/core/dom/node.h
+++ b/chromium/third_party/blink/renderer/core/dom/node.h
@@ -36,6 +36,9 @@
#include "third_party/blink/renderer/core/dom/tree_scope.h"
#include "third_party/blink/renderer/core/scroll/scroll_customization.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
// This needs to be here because element.cc also depends on it.
#define DUMP_NODE_STATISTICS 0
@@ -83,8 +86,8 @@ struct PhysicalRect;
const int kDOMNodeTypeShift = 2;
const int kElementNamespaceTypeShift = 4;
-const int kNodeStyleChangeShift = 17;
-const int kNodeCustomElementShift = 19;
+const int kNodeStyleChangeShift = 15;
+const int kNodeCustomElementShift = 17;
// Values for kChildNeedsStyleRecalcFlag, controlling whether a node gets its
// style recalculated.
@@ -166,6 +169,7 @@ class CORE_EXPORT Node : public EventTarget {
kDocumentPositionImplementationSpecific = 0x20,
};
+#if !BUILDFLAG(USE_V8_OILPAN)
template <typename T>
static void* AllocateObject(size_t size) {
ThreadState* state =
@@ -175,6 +179,7 @@ class CORE_EXPORT Node : public EventTarget {
state, size, BlinkGC::kNodeArenaIndex,
GCInfoTrait<GCInfoFoldedType<T>>::Index(), type_name);
}
+#endif // !BUILDFLAG(USE_V8_OILPAN)
static void DumpStatistics();
@@ -321,19 +326,6 @@ class CORE_EXPORT Node : public EventTarget {
return GetCustomElementState() != CustomElementState::kUncustomized;
}
void SetCustomElementState(CustomElementState);
- bool IsV0CustomElement() const { return GetFlag(kV0CustomElementFlag); }
- enum V0CustomElementState {
- kV0NotCustomElement = 0,
- kV0WaitingForUpgrade = 1 << 0,
- kV0Upgraded = 1 << 1
- };
- V0CustomElementState GetV0CustomElementState() const {
- return IsV0CustomElement()
- ? (GetFlag(kV0CustomElementUpgradedFlag) ? kV0Upgraded
- : kV0WaitingForUpgrade)
- : kV0NotCustomElement;
- }
- void SetV0CustomElementState(V0CustomElementState new_state);
virtual bool IsMediaControlElement() const { return false; }
virtual bool IsMediaControls() const { return false; }
@@ -355,14 +347,10 @@ class CORE_EXPORT Node : public EventTarget {
bool IsDocumentNode() const;
bool IsTreeScope() const;
bool IsShadowRoot() const { return IsDocumentFragment() && IsTreeScope(); }
- bool IsV0InsertionPoint() const { return GetFlag(kIsV0InsertionPointFlag); }
bool CanParticipateInFlatTree() const;
- bool IsActiveSlotOrActiveV0InsertionPoint() const;
- // A re-distribution across v0 and v1 shadow trees is not supported.
- bool IsSlotable() const {
- return IsTextNode() || (IsElementNode() && !IsV0InsertionPoint());
- }
+ bool IsActiveSlot() const;
+ bool IsSlotable() const { return IsTextNode() || IsElementNode(); }
AtomicString SlotName() const;
bool HasCustomStyleCallbacks() const {
@@ -530,19 +518,6 @@ class CORE_EXPORT Node : public EventTarget {
return NeedsStyleRecalc() || GetForceReattachLayoutTree();
}
- bool NeedsDistributionRecalc() const;
-
- bool ChildNeedsDistributionRecalc() const {
- return GetFlag(kChildNeedsDistributionRecalcFlag);
- }
- void SetChildNeedsDistributionRecalc() {
- SetFlag(kChildNeedsDistributionRecalcFlag);
- }
- void ClearChildNeedsDistributionRecalc() {
- ClearFlag(kChildNeedsDistributionRecalcFlag);
- }
- void MarkAncestorsWithChildNeedsDistributionRecalc();
-
// True if the style invalidation process should traverse this node's children
// when looking for pending invalidations.
bool ChildNeedsStyleInvalidation() const {
@@ -565,20 +540,6 @@ class CORE_EXPORT Node : public EventTarget {
// MarkAncestorsWithChildNeedsStyleInvalidation
void SetNeedsStyleInvalidation();
- // This needs to be called before using FlatTreeTraversal.
- // Once Shadow DOM v0 is removed, this function can be removed.
- void UpdateDistributionForFlatTreeTraversal() {
- UpdateDistributionInternal();
- }
-
- // This is not what you might want to call in most cases.
- // You should call UpdateDistributionForFlatTreeTraversal, instead.
- // Only the implementation of v0 shadow trees uses this.
- void UpdateDistributionForLegacyDistributedNodes() {
- // The implementation is same to UpdateDistributionForFlatTreeTraversal.
- UpdateDistributionInternal();
- }
-
// Please don't use this function.
// Background: When we investigated the usage of (old) UpdateDistribution,
// some caller's intents were unclear. Thus, we had to introduce this function
@@ -587,8 +548,6 @@ class CORE_EXPORT Node : public EventTarget {
// just RecalcSlotAssignments()) on a case-by-case basis.
void UpdateDistributionForUnknownReasons();
- bool MayContainLegacyNodeTreeWhereDistributionShouldBeSupported() const;
-
void SetIsLink(bool f);
bool HasEventTargetData() const { return GetFlag(kHasEventTargetDataFlag); }
@@ -657,11 +616,8 @@ class CORE_EXPORT Node : public EventTarget {
}
ShadowRoot* ParentElementShadowRoot() const;
- bool IsInV1ShadowTree() const;
- bool IsInV0ShadowTree() const;
- bool IsChildOfV1ShadowHost() const;
- bool IsChildOfV0ShadowHost() const;
- ShadowRoot* V1ShadowRootOfParent() const;
+ bool IsChildOfShadowHost() const;
+ ShadowRoot* ShadowRootOfParent() const;
Element* FlatTreeParentForChildDirty() const;
Element* GetStyleRecalcParent() const {
return FlatTreeParentForChildDirty();
@@ -871,7 +827,6 @@ class CORE_EXPORT Node : public EventTarget {
Event& underlying_event);
void DispatchSimulatedClick(const Event* underlying_event,
- SimulatedClickMouseEventOptions = kSendNoEvents,
SimulatedClickCreationScope =
SimulatedClickCreationScope::kFromUserAgent);
@@ -904,6 +859,7 @@ class CORE_EXPORT Node : public EventTarget {
StaticNodeList* getDestinationInsertionPoints();
HTMLSlotElement* AssignedSlot() const;
HTMLSlotElement* assignedSlotForBinding();
+ HTMLSlotElement* AssignedSlotWithoutRecalc() const;
bool IsFinishedParsingChildren() const {
return GetFlag(kIsFinishedParsingChildrenFlag);
@@ -936,6 +892,44 @@ class CORE_EXPORT Node : public EventTarget {
void RegisterScrollTimeline(ScrollTimeline*);
void UnregisterScrollTimeline(ScrollTimeline*);
+ // For Element.
+ void SetHasDisplayLockContext() { SetFlag(kHasDisplayLockContext); }
+ bool HasDisplayLockContext() const { return GetFlag(kHasDisplayLockContext); }
+
+ bool SelfOrAncestorHasDirAutoAttribute() const {
+ return GetFlag(kSelfOrAncestorHasDirAutoAttribute);
+ }
+ void SetSelfOrAncestorHasDirAutoAttribute() {
+ SetFlag(kSelfOrAncestorHasDirAutoAttribute);
+ }
+ void ClearSelfOrAncestorHasDirAutoAttribute() {
+ ClearFlag(kSelfOrAncestorHasDirAutoAttribute);
+ }
+ TextDirection CachedDirectionality() const {
+ return (node_flags_ & kCachedDirectionalityIsRtl) ? TextDirection::kRtl
+ : TextDirection::kLtr;
+ }
+ void SetCachedDirectionality(TextDirection direction) {
+ switch (direction) {
+ case TextDirection::kRtl:
+ SetFlag(kCachedDirectionalityIsRtl);
+ break;
+ case TextDirection::kLtr:
+ ClearFlag(kCachedDirectionalityIsRtl);
+ break;
+ }
+ ClearFlag(kNeedsInheritDirectionalityFromParent);
+ }
+ bool NeedsInheritDirectionalityFromParent() const {
+ return GetFlag(kNeedsInheritDirectionalityFromParent);
+ }
+ void SetNeedsInheritDirectionalityFromParent() {
+ SetFlag(kNeedsInheritDirectionalityFromParent);
+ }
+ void ClearNeedsInheritDirectionalityFromParent() {
+ ClearFlag(kNeedsInheritDirectionalityFromParent);
+ }
+
void Trace(Visitor*) const override;
private:
@@ -946,45 +940,46 @@ class CORE_EXPORT Node : public EventTarget {
kIsContainerFlag = 1 << 1,
kDOMNodeTypeMask = 0x3 << kDOMNodeTypeShift,
kElementNamespaceTypeMask = 0x3 << kElementNamespaceTypeShift,
- kIsV0InsertionPointFlag = 1 << 6,
// Changes based on if the element should be treated like a link,
// ex. When setting the href attribute on an <a>.
- kIsLinkFlag = 1 << 7,
+ kIsLinkFlag = 1 << 6,
// Changes based on :hover, :active and :focus state.
- kIsUserActionElementFlag = 1 << 8,
+ kIsUserActionElementFlag = 1 << 7,
// Tree state flags. These change when the element is added/removed
// from a DOM tree.
- kIsConnectedFlag = 1 << 9,
- kIsInShadowTreeFlag = 1 << 10,
+ kIsConnectedFlag = 1 << 8,
+ kIsInShadowTreeFlag = 1 << 9,
// Set by the parser when the children are done parsing.
- kIsFinishedParsingChildrenFlag = 1 << 11,
+ kIsFinishedParsingChildrenFlag = 1 << 10,
// Flags related to recalcStyle.
- kHasCustomStyleCallbacksFlag = 1 << 12,
- kChildNeedsStyleInvalidationFlag = 1 << 13,
- kNeedsStyleInvalidationFlag = 1 << 14,
- kChildNeedsDistributionRecalcFlag = 1 << 15,
- kChildNeedsStyleRecalcFlag = 1 << 16,
+ kHasCustomStyleCallbacksFlag = 1 << 11,
+ kChildNeedsStyleInvalidationFlag = 1 << 12,
+ kNeedsStyleInvalidationFlag = 1 << 13,
+ kChildNeedsStyleRecalcFlag = 1 << 14,
kStyleChangeMask = 0x3 << kNodeStyleChangeShift,
kCustomElementStateMask = 0x7 << kNodeCustomElementShift,
- kHasNameOrIsEditingTextFlag = 1 << 22,
- kHasEventTargetDataFlag = 1 << 23,
+ kHasNameOrIsEditingTextFlag = 1 << 20,
+ kHasEventTargetDataFlag = 1 << 21,
+
+ kNeedsReattachLayoutTree = 1 << 22,
+ kChildNeedsReattachLayoutTree = 1 << 23,
- kV0CustomElementFlag = 1 << 24,
- kV0CustomElementUpgradedFlag = 1 << 25,
+ kHasDuplicateAttributes = 1 << 24,
- kNeedsReattachLayoutTree = 1 << 26,
- kChildNeedsReattachLayoutTree = 1 << 27,
+ kForceReattachLayoutTree = 1 << 25,
- kHasDuplicateAttributes = 1 << 28,
+ kHasDisplayLockContext = 1 << 26,
- kForceReattachLayoutTree = 1 << 29,
+ kSelfOrAncestorHasDirAutoAttribute = 1 << 27,
+ kCachedDirectionalityIsRtl = 1 << 28,
+ kNeedsInheritDirectionalityFromParent = 1 << 29,
kDefaultNodeFlags = kIsFinishedParsingChildrenFlag,
@@ -1051,7 +1046,6 @@ class CORE_EXPORT Node : public EventTarget {
static_cast<NodeFlags>(DOMNodeType::kElement) |
static_cast<NodeFlags>(ElementNamespaceType::kSVG),
kCreateDocument = kCreateContainer | kIsConnectedFlag,
- kCreateV0InsertionPoint = kCreateHTMLElement | kIsV0InsertionPointFlag,
kCreateEditingText = kCreateText | kHasNameOrIsEditingTextFlag,
};
@@ -1107,9 +1101,6 @@ class CORE_EXPORT Node : public EventTarget {
bool IsUserActionElementFocused() const;
bool IsUserActionElementHasFocusWithin() const;
- void UpdateDistributionInternal();
- void RecalcDistribution();
-
void SetStyleChange(StyleChangeType change_type) {
node_flags_ = (node_flags_ & ~kStyleChangeMask) | change_type;
}
@@ -1134,6 +1125,7 @@ class CORE_EXPORT Node : public EventTarget {
DCHECK(!HasRareData());
return reinterpret_cast<NodeRenderingData*>(data_.Get());
}
+ ShadowRoot* GetSlotAssignmentRoot() const;
uint32_t node_flags_;
Member<Node> parent_or_shadow_host_node_;
@@ -1169,4 +1161,24 @@ void showTree(const blink::Node*);
void showNodePath(const blink::Node*);
#endif
+#if BUILDFLAG(USE_V8_OILPAN)
+namespace cppgc {
+// Assign Node to be allocated on custom NodeSpace.
+template <typename T>
+struct SpaceTrait<T, std::enable_if_t<std::is_base_of<blink::Node, T>::value>> {
+ using Space = blink::NodeSpace;
+};
+} // namespace cppgc
+
+namespace blink {
+template <typename T>
+struct ThreadingTrait<
+ T,
+ std::enable_if_t<std::is_base_of<blink::Node, T>::value>> {
+ static constexpr ThreadAffinity kAffinity = kMainThreadOnly;
+};
+} // namespace blink
+
+#endif // USE_V8_OILPAN
+
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/node.idl b/chromium/third_party/blink/renderer/core/dom/node.idl
index f3e793fdb01..c5e78d8b07f 100644
--- a/chromium/third_party/blink/renderer/core/dom/node.idl
+++ b/chromium/third_party/blink/renderer/core/dom/node.idl
@@ -56,12 +56,12 @@
[Affects=Nothing, PerWorldBindings] readonly attribute Node? nextSibling;
[MeasureAs=NodeGetRootNode] Node getRootNode(optional GetRootNodeOptions options = {});
- [Affects=Nothing, CEReactions, CustomElementCallbacks] attribute DOMString? nodeValue;
+ [Affects=Nothing, CEReactions] attribute DOMString? nodeValue;
- [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute (DOMString or TrustedScript)? textContent;
- [CEReactions, CustomElementCallbacks] void normalize();
+ [Affects=Nothing, CEReactions, RaisesException=Setter] attribute (DOMString or TrustedScript)? textContent;
+ [CEReactions] void normalize();
- [NewObject, DoNotTestNewObject, CEReactions, CustomElementCallbacks, RaisesException] Node cloneNode(optional boolean deep = false);
+ [NewObject, DoNotTestNewObject, CEReactions, RaisesException] Node cloneNode(optional boolean deep = false);
boolean isEqualNode(Node? otherNode);
boolean isSameNode(Node? otherNode); // historical alias of ===
@@ -78,8 +78,8 @@
DOMString? lookupNamespaceURI(DOMString? prefix);
boolean isDefaultNamespace(DOMString? namespaceURI);
- [CEReactions, CustomElementCallbacks, PerWorldBindings, RaisesException] Node insertBefore(Node node, Node? child);
- [CEReactions, CustomElementCallbacks, PerWorldBindings, RaisesException, RuntimeCallStatsCounter=NodeAppendChild] Node appendChild(Node node);
- [CEReactions, CustomElementCallbacks, PerWorldBindings, RaisesException] Node replaceChild(Node node, Node child);
- [CEReactions, CustomElementCallbacks, RaisesException, RuntimeCallStatsCounter=NodeRemoveChild] Node removeChild(Node child);
+ [CEReactions, PerWorldBindings, RaisesException] Node insertBefore(Node node, Node? child);
+ [CEReactions, PerWorldBindings, RaisesException, RuntimeCallStatsCounter=NodeAppendChild] Node appendChild(Node node);
+ [CEReactions, PerWorldBindings, RaisesException] Node replaceChild(Node node, Node child);
+ [CEReactions, RaisesException, RuntimeCallStatsCounter=NodeRemoveChild] Node removeChild(Node child);
};
diff --git a/chromium/third_party/blink/renderer/core/dom/node_computed_style.h b/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
index 3d28403ddc9..69c34a83ebb 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_computed_style.h
@@ -28,7 +28,6 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/dom/node.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
namespace blink {
@@ -51,8 +50,7 @@ inline const ComputedStyle* Node::GetComputedStyle() const {
}
inline const ComputedStyle* Node::ParentComputedStyle() const {
- if (!CanParticipateInFlatTree())
- return nullptr;
+ DCHECK(IsElementNode() || IsTextNode());
ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*this);
if (parent && parent->ChildrenCanHaveStyle()) {
const ComputedStyle* parent_style = parent->GetComputedStyle();
diff --git a/chromium/third_party/blink/renderer/core/dom/node_list.h b/chromium/third_party/blink/renderer/core/dom/node_list.h
index 80ca0a58b24..f3487ad1618 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_list.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_list.h
@@ -26,6 +26,8 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
namespace blink {
@@ -51,6 +53,15 @@ class CORE_EXPORT NodeList : public ScriptWrappable {
NodeList() = default;
};
+#if BUILDFLAG(USE_V8_OILPAN)
+template <typename T>
+struct ThreadingTrait<
+ T,
+ std::enable_if_t<std::is_base_of<blink::NodeList, T>::value>> {
+ static constexpr ThreadAffinity kAffinity = kMainThreadOnly;
+};
+#endif // USE_V8_OILPAN
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_LIST_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/node_rare_data.h b/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
index 95eb4e76758..3ea8cc3a9e9 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -24,7 +24,9 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/wtf/bit_field.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
@@ -228,6 +230,15 @@ class GC_PLUGIN_IGNORE("Manual dispatch implemented in NodeData.") NodeRareData
Member<HeapHashSet<Member<ScrollTimeline>>> scroll_timelines_;
};
+#if BUILDFLAG(USE_V8_OILPAN)
+template <typename T>
+struct ThreadingTrait<
+ T,
+ std::enable_if_t<std::is_base_of<blink::NodeRareData, T>::value>> {
+ static constexpr ThreadAffinity kAffinity = kMainThreadOnly;
+};
+#endif // USE_V8_OILPAN
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_RARE_DATA_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/node_test.cc b/chromium/third_party/blink/renderer/core/dom/node_test.cc
index 5dcd17b6417..7dd1960282d 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_test.cc
@@ -86,8 +86,7 @@ TEST_F(NodeTest, canStartSelection) {
TEST_F(NodeTest, canStartSelectionWithShadowDOM) {
const char* body_content = "<div id=host><span id=one>one</span></div>";
- const char* shadow_content =
- "<a href='http://www.msn.com'><content></content></a>";
+ const char* shadow_content = "<a href='http://www.msn.com'><slot></slot></a>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one");
@@ -102,17 +101,14 @@ TEST_F(NodeTest, customElementState) {
Element* div = GetDocument().getElementById("div");
EXPECT_EQ(CustomElementState::kUncustomized, div->GetCustomElementState());
EXPECT_TRUE(div->IsDefined());
- EXPECT_EQ(Node::kV0NotCustomElement, div->GetV0CustomElementState());
div->SetCustomElementState(CustomElementState::kUndefined);
EXPECT_EQ(CustomElementState::kUndefined, div->GetCustomElementState());
EXPECT_FALSE(div->IsDefined());
- EXPECT_EQ(Node::kV0NotCustomElement, div->GetV0CustomElementState());
div->SetCustomElementState(CustomElementState::kCustom);
EXPECT_EQ(CustomElementState::kCustom, div->GetCustomElementState());
EXPECT_TRUE(div->IsDefined());
- EXPECT_EQ(Node::kV0NotCustomElement, div->GetV0CustomElementState());
}
TEST_F(NodeTest, AttachContext_PreviousInFlow_TextRoot) {
@@ -281,19 +277,6 @@ TEST_F(NodeTest, AttachContext_PreviousInFlow_Slotted) {
EXPECT_EQ(span->GetLayoutObject(), previous_in_flow);
}
-TEST_F(NodeTest, AttachContext_PreviousInFlow_V0Content) {
- SetBodyContent("<div id=host><span id=inline></span></div>");
- ShadowRoot* shadow_root = CreateShadowRootForElementWithIDAndSetInnerHTML(
- GetDocument(), "host",
- "<div id=root style='display:contents'><span></span><content /></div>");
- Element* root = shadow_root->getElementById("root");
- Element* span = GetDocument().getElementById("inline");
- LayoutObject* previous_in_flow = ReattachLayoutTreeForNode(*root);
-
- EXPECT_TRUE(previous_in_flow);
- EXPECT_EQ(span->GetLayoutObject(), previous_in_flow);
-}
-
TEST_F(NodeTest, HasMediaControlAncestor_Fail) {
auto* node = MakeGarbageCollected<HTMLDivElement>(GetDocument());
EXPECT_FALSE(node->HasMediaControlAncestor());
@@ -478,19 +461,15 @@ TEST_F(NodeTest, UpdateChildDirtyAfterSlotRemoval) {
EXPECT_TRUE(GetDocument().body()->ChildNeedsStyleRecalc());
EXPECT_TRUE(GetDocument().GetStyleEngine().NeedsStyleRecalc());
- // The StyleRecalcRoot is now the span. Removing the slot would break the flat
- // tree ancestor chain so that when removing the span we would no longer be
- // able to clear the dirty bits for all of the previous ancestor chain. Thus,
- // we fall back to use the host as the style recalc root to be able to
- // traverse and clear the dirty bit of the shadow tree div element on the next
- // style recalc.
+ // The StyleRecalcRoot is now the span. Removing the slot breaks the flat
+ // tree ancestor chain so that the span is no longer in the flat tree. The
+ // StyleRecalcRoot is cleared.
slot->remove();
- span->remove();
- EXPECT_TRUE(div->ChildNeedsStyleRecalc());
- EXPECT_TRUE(host->ChildNeedsStyleRecalc());
- EXPECT_TRUE(GetDocument().body()->ChildNeedsStyleRecalc());
- EXPECT_TRUE(GetDocument().GetStyleEngine().NeedsStyleRecalc());
+ EXPECT_FALSE(div->ChildNeedsStyleRecalc());
+ EXPECT_FALSE(host->ChildNeedsStyleRecalc());
+ EXPECT_FALSE(GetDocument().body()->ChildNeedsStyleRecalc());
+ EXPECT_FALSE(GetDocument().GetStyleEngine().NeedsStyleRecalc());
}
TEST_F(NodeTest, UpdateChildDirtyAfterSlottingDirtyNode) {
@@ -522,41 +501,4 @@ TEST_F(NodeTest, UpdateChildDirtyAfterSlottingDirtyNode) {
UpdateAllLifecyclePhasesForTest();
}
-TEST_F(NodeTest, ChildDirtyNeedsV0Distribution) {
- SetBodyContent("<div id=host><span></span> </div>");
- ShadowRoot* shadow_root = CreateShadowRootForElementWithIDAndSetInnerHTML(
- GetDocument(), "host", "<content />");
- UpdateAllLifecyclePhasesForTest();
-
-#if DCHECK_IS_ON()
- GetDocument().SetAllowDirtyShadowV0Traversal(true);
-#endif
-
- auto* host = GetDocument().getElementById("host");
- auto* span = To<Element>(host->firstChild());
- auto* content = shadow_root->firstChild();
-
- host->lastChild()->remove();
-
- EXPECT_FALSE(GetDocument().documentElement()->ChildNeedsStyleRecalc());
- EXPECT_TRUE(GetDocument().documentElement()->ChildNeedsDistributionRecalc());
- EXPECT_EQ(content, host->firstChild()->GetStyleRecalcParent());
- EXPECT_FALSE(content->ChildNeedsStyleRecalc());
-
- // Make the span style dirty.
- span->setAttribute("style", "color:green");
-
- // Check that the flat tree ancestor chain is child-dirty while the
- // shadow distribution is still dirty.
- EXPECT_TRUE(GetDocument().documentElement()->ChildNeedsStyleRecalc());
- EXPECT_TRUE(GetDocument().body()->ChildNeedsStyleRecalc());
- EXPECT_TRUE(host->ChildNeedsStyleRecalc());
- EXPECT_TRUE(content->ChildNeedsStyleRecalc());
- EXPECT_TRUE(GetDocument().documentElement()->ChildNeedsDistributionRecalc());
-
-#if DCHECK_IS_ON()
- GetDocument().SetAllowDirtyShadowV0Traversal(false);
-#endif
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/node_traversal.cc b/chromium/third_party/blink/renderer/core/dom/node_traversal.cc
index d9ce9bf9e57..3c1b16a73b7 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/dom/node_traversal.cc
@@ -124,8 +124,8 @@ Node* NodeTraversal::Previous(const Node& current, const Node* stay_within) {
return current.parentNode();
}
-Node* NodeTraversal::PreviousSkippingChildren(const Node& current,
- const Node* stay_within) {
+Node* NodeTraversal::PreviousAbsoluteSibling(const Node& current,
+ const Node* stay_within) {
if (current == stay_within)
return nullptr;
if (current.previousSibling())
diff --git a/chromium/third_party/blink/renderer/core/dom/node_traversal.h b/chromium/third_party/blink/renderer/core/dom/node_traversal.h
index 7f0b6281eb4..516d04e587e 100644
--- a/chromium/third_party/blink/renderer/core/dom/node_traversal.h
+++ b/chromium/third_party/blink/renderer/core/dom/node_traversal.h
@@ -74,9 +74,12 @@ class NodeTraversal {
// current one in document order
static Node* Previous(const Node&, const Node* stay_within = nullptr);
- // Like previous, but skips children and starts with the next sibling.
- static Node* PreviousSkippingChildren(const Node&,
- const Node* stay_within = nullptr);
+ // Returns the previous direct sibling of the node, if there is one. If not,
+ // it will traverse up the ancestor chain until it finds an ancestor
+ // that has a previous sibling, returning that sibling. Or nullptr if none.
+ // See comment for |FlatTreeTraversal::PreviousAbsoluteSibling| for details.
+ static Node* PreviousAbsoluteSibling(const Node&,
+ const Node* stay_within = nullptr);
// Like next, but visits parents after their children.
static Node* NextPostOrder(const Node&, const Node* stay_within = nullptr);
diff --git a/chromium/third_party/blink/renderer/core/dom/parent_node.idl b/chromium/third_party/blink/renderer/core/dom/parent_node.idl
index 82cd8e948e1..35e38c0100c 100644
--- a/chromium/third_party/blink/renderer/core/dom/parent_node.idl
+++ b/chromium/third_party/blink/renderer/core/dom/parent_node.idl
@@ -38,9 +38,9 @@
[Affects=Nothing, PerWorldBindings] readonly attribute Element? lastElementChild;
[Affects=Nothing] readonly attribute unsigned long childElementCount;
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void prepend((Node or DOMString or TrustedScript)... nodes);
- [Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void append((Node or DOMString or TrustedScript)... nodes);
- [RuntimeEnabled=ParentNodeReplaceChildren, Unscopable, RaisesException, CEReactions, CustomElementCallbacks] void replaceChildren((Node or DOMString or TrustedScript)... nodes);
+ [Unscopable, RaisesException, CEReactions] void prepend((Node or DOMString or TrustedScript)... nodes);
+ [Unscopable, RaisesException, CEReactions] void append((Node or DOMString or TrustedScript)... nodes);
+ [Unscopable, RaisesException, CEReactions] void replaceChildren((Node or DOMString or TrustedScript)... nodes);
// [Unscopable] Element? query(DOMString relativeSelectors);
// [NewObject, Unscopable] Elements queryAll(DOMString relativeSelectors);
diff --git a/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc b/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
index 452c8adf643..e03b0d673bc 100644
--- a/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
+++ b/chromium/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
@@ -102,6 +102,8 @@ static unsigned MakePresentationAttributeCacheKey(
// attribute.
if (IsA<HTMLInputElement>(element))
return 0;
+ if (element.HasExtraStyleForPresentationAttribute())
+ return 0;
AttributeCollection attributes = element.AttributesWithoutUpdate();
for (const Attribute& attr : attributes) {
if (!element.IsPresentationAttribute(attr.GetName()))
diff --git a/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc b/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
index 40c84b5a26d..63f6777bcad 100644
--- a/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
+++ b/chromium/third_party/blink/renderer/core/dom/processing_instruction.cc
@@ -199,14 +199,16 @@ void ProcessingInstruction::NotifyFinished(Resource* resource) {
sheet_ = MakeGarbageCollected<XSLStyleSheet>(
this, resource->Url(), resource->GetResponse().ResponseUrl(), false);
To<XSLStyleSheet>(sheet_.Get())
- ->ParseString(ToXSLStyleSheetResource(resource)->Sheet());
+ ->ParseString(To<XSLStyleSheetResource>(resource)->Sheet());
} else {
DCHECK(is_css_);
- CSSStyleSheetResource* style_resource = ToCSSStyleSheetResource(resource);
+ auto* style_resource = To<CSSStyleSheetResource>(resource);
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
GetDocument(), style_resource->GetResponse().ResponseUrl(),
style_resource->GetResponse().IsCorsSameOrigin(),
- style_resource->GetReferrerPolicy(), style_resource->Encoding());
+ Referrer(style_resource->GetResponse().ResponseUrl(),
+ style_resource->GetReferrerPolicy()),
+ style_resource->Encoding());
if (style_resource->GetResourceRequest().IsAdResource())
parser_context->SetIsAdRelated();
diff --git a/chromium/third_party/blink/renderer/core/dom/pseudo_element.cc b/chromium/third_party/blink/renderer/core/dom/pseudo_element.cc
index 53dad593f4c..0d0d4741b91 100644
--- a/chromium/third_party/blink/renderer/core/dom/pseudo_element.cc
+++ b/chromium/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -99,7 +99,7 @@ bool PseudoElement::IsWebExposed(PseudoId pseudo_id, const Node* parent) {
case kPseudoIdMarker:
if (parent && parent->IsPseudoElement())
return RuntimeEnabledFeatures::CSSMarkerNestedPseudoElementEnabled();
- return RuntimeEnabledFeatures::CSSMarkerPseudoElementEnabled();
+ return true;
default:
return true;
}
@@ -121,9 +121,10 @@ PseudoElement::PseudoElement(Element* parent, PseudoId pseudo_id)
}
}
-scoped_refptr<ComputedStyle> PseudoElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> PseudoElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
return ParentOrShadowHostElement()->StyleForPseudoElement(
- PseudoElementStyleRequest(pseudo_id_));
+ style_recalc_context, PseudoElementStyleRequest(pseudo_id_));
}
scoped_refptr<ComputedStyle> PseudoElement::LayoutStyleForDisplayContents(
@@ -275,9 +276,8 @@ bool PseudoElementLayoutObjectIsNeeded(const ComputedStyle* pseudo_style,
return !pseudo_style->ContentPreventsBoxGeneration();
const ComputedStyle* parent_style =
originating_element->GetComputedStyle();
- return parent_style &&
- (parent_style->ListStyleType() != EListStyleType::kNone ||
- parent_style->GeneratesMarkerImage());
+ return parent_style && (parent_style->GetListStyleType() ||
+ parent_style->GeneratesMarkerImage());
}
default:
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/dom/pseudo_element.h b/chromium/third_party/blink/renderer/core/dom/pseudo_element.h
index 286d278c975..63f01b2dffb 100644
--- a/chromium/third_party/blink/renderer/core/dom/pseudo_element.h
+++ b/chromium/third_party/blink/renderer/core/dom/pseudo_element.h
@@ -41,7 +41,8 @@ class CORE_EXPORT PseudoElement : public Element {
PseudoElement(Element*, PseudoId);
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
void AttachLayoutTree(AttachContext&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
bool CanGeneratePseudoElement(PseudoId) const override;
diff --git a/chromium/third_party/blink/renderer/core/dom/range.cc b/chromium/third_party/blink/renderer/core/dom/range.cc
index 281682054ac..52460dfe922 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.cc
+++ b/chromium/third_party/blink/renderer/core/dom/range.cc
@@ -1597,7 +1597,7 @@ void Range::expand(const String& unit, ExceptionState& exception_state) {
start = StartOfParagraph(start);
end = EndOfParagraph(end);
} else if (unit == "document") {
- start = StartOfDocument(start);
+ start = CreateVisiblePosition(StartOfDocument(start.DeepEquivalent()));
end = EndOfDocument(end);
} else {
return;
diff --git a/chromium/third_party/blink/renderer/core/dom/range.h b/chromium/third_party/blink/renderer/core/dom/range.h
index 47e208f3b17..402ee3c66df 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.h
+++ b/chromium/third_party/blink/renderer/core/dom/range.h
@@ -27,6 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_RANGE_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/abstract_range.h"
#include "third_party/blink/renderer/core/dom/range_boundary_point.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -48,7 +49,7 @@ class Node;
class NodeWithIndex;
class Text;
-class CORE_EXPORT Range final : public ScriptWrappable {
+class CORE_EXPORT Range final : public AbstractRange {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -68,12 +69,12 @@ class CORE_EXPORT Range final : public ScriptWrappable {
DCHECK(owner_document_);
return *owner_document_.Get();
}
- Node* startContainer() const { return &start_.Container(); }
- unsigned startOffset() const { return start_.Offset(); }
- Node* endContainer() const { return &end_.Container(); }
- unsigned endOffset() const { return end_.Offset(); }
+ Node* startContainer() const override { return &start_.Container(); }
+ unsigned startOffset() const override { return start_.Offset(); }
+ Node* endContainer() const override { return &end_.Container(); }
+ unsigned endOffset() const override { return end_.Offset(); }
- bool collapsed() const { return start_ == end_; }
+ bool collapsed() const override { return start_ == end_; }
bool IsConnected() const;
Node* commonAncestorContainer() const;
diff --git a/chromium/third_party/blink/renderer/core/dom/range.idl b/chromium/third_party/blink/renderer/core/dom/range.idl
index 499e5b55452..067fe5d9b15 100644
--- a/chromium/third_party/blink/renderer/core/dom/range.idl
+++ b/chromium/third_party/blink/renderer/core/dom/range.idl
@@ -21,13 +21,8 @@
// https://dom.spec.whatwg.org/#interface-range
[
Exposed=Window
-] interface Range {
+] interface Range : AbstractRange {
[CallWith=Document] constructor();
- readonly attribute Node startContainer;
- readonly attribute unsigned long startOffset;
- readonly attribute Node endContainer;
- readonly attribute unsigned long endOffset;
- readonly attribute boolean collapsed;
readonly attribute Node commonAncestorContainer;
[RaisesException] void setStart(Node node, unsigned long offset);
@@ -46,11 +41,11 @@
const unsigned short END_TO_START = 3;
[RaisesException] short compareBoundaryPoints(unsigned short how, Range sourceRange);
- [RaisesException, CEReactions, CustomElementCallbacks] void deleteContents();
- [NewObject, RaisesException, CEReactions, CustomElementCallbacks, DoNotTestNewObject] DocumentFragment extractContents();
- [NewObject, RaisesException, CEReactions, CustomElementCallbacks] DocumentFragment cloneContents();
- [RaisesException, CEReactions, CustomElementCallbacks] void insertNode(Node node);
- [RaisesException, CEReactions, CustomElementCallbacks] void surroundContents(Node newParent);
+ [RaisesException, CEReactions] void deleteContents();
+ [NewObject, RaisesException, CEReactions, DoNotTestNewObject] DocumentFragment extractContents();
+ [NewObject, RaisesException, CEReactions] DocumentFragment cloneContents();
+ [RaisesException, CEReactions] void insertNode(Node node);
+ [RaisesException, CEReactions] void surroundContents(Node newParent);
[NewObject] Range cloneRange();
[MeasureAs=RangeDetach] void detach();
@@ -69,7 +64,7 @@
// DOM Parsing and Serialization
// https://w3c.github.io/DOM-Parsing/#extensions-to-the-range-interface
- [NewObject, RaisesException, CEReactions, CustomElementCallbacks] DocumentFragment createContextualFragment(HTMLString fragment);
+ [NewObject, RaisesException, CEReactions] DocumentFragment createContextualFragment(HTMLString fragment);
// Non-standard API
[RaisesException, DeprecateAs=RangeExpand] void expand(optional DOMString unit = "");
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
index 3f909b3c5dc..36d77748cad 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
@@ -69,6 +69,7 @@ void ScriptedAnimationController::Trace(Visitor* visitor) const {
visitor->Trace(callback_collection_);
visitor->Trace(event_queue_);
visitor->Trace(media_query_list_listeners_);
+ visitor->Trace(media_query_list_listeners_set_);
visitor->Trace(per_frame_events_);
}
@@ -169,7 +170,8 @@ void ScriptedAnimationController::ExecuteFrameCallbacks() {
void ScriptedAnimationController::CallMediaQueryListListeners() {
MediaQueryListListeners listeners;
- listeners.Swap(media_query_list_listeners_);
+ listeners.swap(media_query_list_listeners_);
+ media_query_list_listeners_set_.clear();
for (const auto& listener : listeners) {
listener->NotifyMediaQueryChanged();
@@ -267,8 +269,13 @@ void ScriptedAnimationController::EnqueuePerFrameEvent(Event* event) {
void ScriptedAnimationController::EnqueueMediaQueryChangeListeners(
HeapVector<Member<MediaQueryListListener>>& listeners) {
for (const auto& listener : listeners) {
- media_query_list_listeners_.insert(listener);
+ if (!media_query_list_listeners_set_.Contains(listener)) {
+ media_query_list_listeners_.push_back(listener);
+ media_query_list_listeners_set_.insert(listener);
+ }
}
+ DCHECK_EQ(media_query_list_listeners_.size(),
+ media_query_list_listeners_set_.size());
ScheduleAnimationIfNeeded();
}
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
index 7f55d6b6b94..6e09d92995b 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_animation_controller.h
@@ -121,9 +121,11 @@ class CORE_EXPORT ScriptedAnimationController
using PerFrameEventsMap =
HeapHashMap<Member<const EventTarget>, HashSet<const StringImpl*>>;
PerFrameEventsMap per_frame_events_;
- using MediaQueryListListeners =
- HeapListHashSet<Member<MediaQueryListListener>>;
+ using MediaQueryListListeners = HeapVector<Member<MediaQueryListListener>>;
MediaQueryListListeners media_query_list_listeners_;
+ // This is used to quickly lookup if a listener exists in
+ // media_query_list_listeners_. The contents should be exactly the same.
+ HeapHashSet<Member<MediaQueryListListener>> media_query_list_listeners_set_;
double current_frame_time_ms_ = 0.0;
double current_frame_legacy_time_ms_ = 0.0;
diff --git a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
index 9e04ad71286..461b6bf17a1 100644
--- a/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
@@ -110,6 +110,10 @@ class MockIdleTask : public IdleTask {
class ScriptedIdleTaskControllerTest : public testing::Test {
public:
+ ~ScriptedIdleTaskControllerTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
+
void SetUp() override {
execution_context_ = MakeGarbageCollected<NullExecutionContext>();
}
diff --git a/chromium/third_party/blink/renderer/core/dom/set_inner_html_options.idl b/chromium/third_party/blink/renderer/core/dom/set_inner_html_options.idl
deleted file mode 100644
index 5e5d89d9532..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/set_inner_html_options.idl
+++ /dev/null
@@ -1,7 +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.
-
-dictionary SetInnerHTMLOptions {
- boolean allowShadowRoot = false;
-};
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_dom_v0_test.cc b/chromium/third_party/blink/renderer/core/dom/shadow_dom_v0_test.cc
deleted file mode 100644
index d1f960ad995..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/shadow_dom_v0_test.cc
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css_value_keywords.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/html/html_body_element.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
-
-namespace blink {
-
-namespace {
-
-bool HasSelectorForIdInShadow(Element* host, const AtomicString& id) {
- DCHECK(host);
- return host->GetShadowRoot()->V0().EnsureSelectFeatureSet().HasSelectorForId(
- id);
-}
-
-bool HasSelectorForClassInShadow(Element* host,
- const AtomicString& class_name) {
- DCHECK(host);
- return host->GetShadowRoot()
- ->V0()
- .EnsureSelectFeatureSet()
- .HasSelectorForClass(class_name);
-}
-
-bool HasSelectorForAttributeInShadow(Element* host,
- const AtomicString& attribute_name) {
- DCHECK(host);
- return host->GetShadowRoot()
- ->V0()
- .EnsureSelectFeatureSet()
- .HasSelectorForAttribute(attribute_name);
-}
-
-class ShadowDOMV0Test : public SimTest {};
-
-TEST_F(ShadowDOMV0Test, FeatureSetId) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* content = GetDocument().CreateRawElement(html_names::kContentTag);
- content->setAttribute("select", "#foo");
- host->CreateV0ShadowRootForTesting().AppendChild(content);
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "host"));
- content->setAttribute("select", "#bar");
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "foo"));
- content->setAttribute("select", "");
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "foo"));
-}
-
-TEST_F(ShadowDOMV0Test, FeatureSetClassName) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* content = GetDocument().CreateRawElement(html_names::kContentTag);
- content->setAttribute("select", ".foo");
- host->CreateV0ShadowRootForTesting().AppendChild(content);
- EXPECT_TRUE(HasSelectorForClassInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "host"));
- content->setAttribute("select", ".bar");
- EXPECT_TRUE(HasSelectorForClassInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "foo"));
- content->setAttribute("select", "");
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "foo"));
-}
-
-TEST_F(ShadowDOMV0Test, FeatureSetAttributeName) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* content = GetDocument().CreateRawElement(html_names::kContentTag);
- content->setAttribute("select", "div[foo]");
- host->CreateV0ShadowRootForTesting().AppendChild(content);
- EXPECT_TRUE(HasSelectorForAttributeInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "host"));
- content->setAttribute("select", "div[bar]");
- EXPECT_TRUE(HasSelectorForAttributeInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "foo"));
- content->setAttribute("select", "");
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "foo"));
-}
-
-TEST_F(ShadowDOMV0Test, FeatureSetMultipleSelectors) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* content = GetDocument().CreateRawElement(html_names::kContentTag);
- content->setAttribute("select", "#foo,.bar,div[baz]");
- host->CreateV0ShadowRootForTesting().AppendChild(content);
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "baz"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "foo"));
- EXPECT_TRUE(HasSelectorForClassInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "baz"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "bar"));
- EXPECT_TRUE(HasSelectorForAttributeInShadow(host, "baz"));
-}
-
-TEST_F(ShadowDOMV0Test, FeatureSetSubtree) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- host->CreateV0ShadowRootForTesting().setInnerHTML(R"HTML(
- <div>
- <div></div>
- <content select='*'></content>
- <div>
- <content select='div[foo=piyo]'></content>
- </div>
- </div>
- )HTML");
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForClassInShadow(host, "foo"));
- EXPECT_TRUE(HasSelectorForAttributeInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForAttributeInShadow(host, "piyo"));
-}
-
-TEST_F(ShadowDOMV0Test, FeatureSetMultipleShadowRoots) {
- LoadURL("about:blank");
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto& host_shadow = host->CreateV0ShadowRootForTesting();
- host_shadow.setInnerHTML("<content select='#foo'></content>");
- auto* child = GetDocument().CreateRawElement(html_names::kDivTag);
- auto& child_root = child->CreateV0ShadowRootForTesting();
- auto* child_content = GetDocument().CreateRawElement(html_names::kContentTag);
- child_content->setAttribute("select", "#bar");
- child_root.AppendChild(child_content);
- host_shadow.AppendChild(child);
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "foo"));
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "baz"));
- child_content->setAttribute("select", "#baz");
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "foo"));
- EXPECT_FALSE(HasSelectorForIdInShadow(host, "bar"));
- EXPECT_TRUE(HasSelectorForIdInShadow(host, "baz"));
-}
-
-TEST_F(ShadowDOMV0Test, ReattachNonDistributedElements) {
- LoadURL("about:blank");
-
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* inner_host = GetDocument().CreateRawElement(html_names::kDivTag);
- auto* span = GetDocument().CreateRawElement(html_names::kSpanTag);
-
- GetDocument().body()->appendChild(host);
- host->appendChild(inner_host);
- inner_host->appendChild(span);
-
- Compositor().BeginFrame();
-
- host->CreateV0ShadowRootForTesting();
- inner_host->CreateV0ShadowRootForTesting();
- inner_host->SetInlineStyleProperty(CSSPropertyID::kDisplay,
- CSSValueID::kInlineBlock);
- span->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kBlock);
-
- Compositor().BeginFrame();
-
- EXPECT_FALSE(span->NeedsReattachLayoutTree());
-}
-
-TEST_F(ShadowDOMV0Test, DetachLayoutTreeOnShadowRootCreation) {
- LoadURL("about:blank");
-
- auto* host = GetDocument().CreateRawElement(html_names::kDivTag);
- host->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kContents);
- auto* span = GetDocument().CreateRawElement(html_names::kSpanTag);
- host->appendChild(span);
- GetDocument().body()->appendChild(host);
- Compositor().BeginFrame();
-
- EXPECT_TRUE(span->GetLayoutObject());
-
- host->CreateV0ShadowRootForTesting();
-
- EXPECT_FALSE(span->GetLayoutObject());
-}
-
-} // namespace
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root.cc b/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
index 1a1b104f7d5..9b7a8cfd9ea 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -27,22 +27,18 @@
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_get_inner_html_options.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css/style_sheet_list.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
#include "third_party/blink/renderer/core/dom/slot_assignment.h"
#include "third_party/blink/renderer/core/dom/slot_assignment_engine.h"
#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
-#include "third_party/blink/renderer/core/html/html_content_element.h"
-#include "third_party/blink/renderer/core/html/html_shadow_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
@@ -51,13 +47,8 @@
namespace blink {
-void ShadowRoot::Distribute() {
- if (!IsV1())
- V0().Distribute();
-}
-
struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope {
- Member<void*> member[3];
+ Member<void*> member[2];
unsigned flags[1];
};
@@ -72,11 +63,8 @@ ShadowRoot::ShadowRoot(Document& document, ShadowRootType type)
registered_with_parent_shadow_root_(false),
delegates_focus_(false),
slot_assignment_mode_(static_cast<unsigned>(SlotAssignmentMode::kAuto)),
- needs_distribution_recalc_(false),
- unused_(0) {
- if (IsV0())
- shadow_root_v0_ = MakeGarbageCollected<ShadowRootV0>(*this);
-}
+ needs_dir_auto_attribute_update_(false),
+ unused_(0) {}
ShadowRoot::~ShadowRoot() = default;
@@ -93,7 +81,6 @@ HTMLSlotElement* ShadowRoot::AssignedSlotFor(const Node& node) {
}
void ShadowRoot::DidAddSlot(HTMLSlotElement& slot) {
- DCHECK(IsV1());
EnsureSlotAssignment().DidAddSlot(slot);
}
@@ -117,30 +104,31 @@ String ShadowRoot::innerHTML() const {
return CreateMarkup(this, kChildrenOnly);
}
-void ShadowRoot::SetInnerHTMLInternal(const String& html,
- const SetInnerHTMLOptions* options,
- ExceptionState& exception_state) {
- bool allow_shadow_root =
- options->hasAllowShadowRoot() && options->allowShadowRoot();
- if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
- html, &host(), kAllowScriptingContent, "innerHTML", allow_shadow_root,
- exception_state)) {
- ReplaceChildrenWithFragment(this, fragment, exception_state);
+String ShadowRoot::getInnerHTML(const GetInnerHTMLOptions* options) const {
+ DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
+ GetExecutionContext()));
+ ClosedRootsSet include_closed_roots;
+ if (options->hasClosedRoots()) {
+ for (auto& shadow_root : options->closedRoots()) {
+ include_closed_roots.insert(shadow_root);
+ }
}
+ return CreateMarkup(
+ this, kChildrenOnly, kDoNotResolveURLs,
+ options->includeShadowRoots() ? kIncludeShadowRoots : kNoShadowRoots,
+ include_closed_roots);
}
void ShadowRoot::setInnerHTML(const String& html,
ExceptionState& exception_state) {
- const SetInnerHTMLOptions options;
- SetInnerHTMLInternal(html, &options, exception_state);
-}
-
-void ShadowRoot::setInnerHTMLWithOptions(const String& html,
- const SetInnerHTMLOptions* options,
- ExceptionState& exception_state) {
- DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
- GetExecutionContext()));
- SetInnerHTMLInternal(html, options, exception_state);
+ if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
+ html, &host(), kAllowScriptingContent, "innerHTML",
+ /*include_shadow_roots=*/false, exception_state)) {
+ ReplaceChildrenWithFragment(this, fragment, exception_state);
+ auto* element = DynamicTo<HTMLElement>(host());
+ if (element && !element->NeedsInheritDirectionalityFromParent())
+ element->UpdateDescendantDirectionality(element->CachedDirectionality());
+ }
}
void ShadowRoot::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
@@ -149,6 +137,20 @@ void ShadowRoot::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
RebuildChildrenLayoutTrees(whitespace_attacher);
}
+void ShadowRoot::DetachLayoutTree(bool performing_reattach) {
+ ContainerNode::DetachLayoutTree(performing_reattach);
+
+ // Shadow host may contain unassigned light dom children that need detaching.
+ // Assigned nodes are detached by the slot element.
+ for (Node& child : NodeTraversal::ChildrenOf(host())) {
+ if (!child.IsSlotable() || child.AssignedSlotWithoutRecalc())
+ continue;
+
+ if (child.GetDocument() == GetDocument())
+ child.DetachLayoutTree(performing_reattach);
+ }
+}
+
Node::InsertionNotificationRequest ShadowRoot::InsertedInto(
ContainerNode& insertion_point) {
DocumentFragment::InsertedInto(insertion_point);
@@ -195,7 +197,6 @@ void ShadowRoot::RemovedFrom(ContainerNode& insertion_point) {
}
void ShadowRoot::SetNeedsAssignmentRecalc() {
- DCHECK(IsV1());
if (!slot_assignment_)
return;
return slot_assignment_->SetNeedsAssignmentRecalc();
@@ -224,25 +225,9 @@ StyleSheetList& ShadowRoot::StyleSheets() {
return *style_sheet_list_;
}
-void ShadowRoot::SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc() {
- if (IsV1())
- SetNeedsAssignmentRecalc();
- else
- SetNeedsDistributionRecalc();
-}
-
-void ShadowRoot::SetNeedsDistributionRecalc() {
- DCHECK(!IsV1());
- if (needs_distribution_recalc_)
- return;
- needs_distribution_recalc_ = true;
- host().MarkAncestorsWithChildNeedsDistributionRecalc();
-}
-
void ShadowRoot::Trace(Visitor* visitor) const {
visitor->Trace(style_sheet_list_);
visitor->Trace(slot_assignment_);
- visitor->Trace(shadow_root_v0_);
TreeScope::Trace(visitor);
DocumentFragment::Trace(visitor);
}
@@ -252,9 +237,6 @@ std::ostream& operator<<(std::ostream& ostream, const ShadowRootType& type) {
case ShadowRootType::kUserAgent:
ostream << "UserAgent";
break;
- case ShadowRootType::V0:
- ostream << "V0";
- break;
case ShadowRootType::kOpen:
ostream << "Open";
break;
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root.h b/chromium/third_party/blink/renderer/core/dom/shadow_root.h
index 379c02a26c1..20584ad605d 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root.h
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root.h
@@ -40,18 +40,18 @@ namespace blink {
class Document;
class ExceptionState;
-class SetInnerHTMLOptions;
-class ShadowRootV0;
+class GetInnerHTMLOptions;
class SlotAssignment;
class WhitespaceAttacher;
-enum class ShadowRootType { V0, kOpen, kClosed, kUserAgent };
+enum class ShadowRootType { kOpen, kClosed, kUserAgent };
class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
DEFINE_WRAPPERTYPEINFO();
public:
ShadowRoot(Document&, ShadowRootType);
+ ~ShadowRoot() override;
ShadowRoot(const ShadowRoot&) = delete;
ShadowRoot& operator=(const ShadowRoot&) = delete;
@@ -75,10 +75,6 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
// UA ShadowRoot should not be exposed to the Web.
NOTREACHED();
return "";
- case ShadowRootType::V0:
- // v0 ShadowRoot shouldn't support |mode|, however, we must return
- // something. Return "open" here for a historical reason.
- return "open";
case ShadowRootType::kOpen:
return "open";
case ShadowRootType::kClosed:
@@ -89,16 +85,7 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
}
}
- bool IsV0() const { return GetType() == ShadowRootType::V0; }
- bool IsOpenOrV0() const {
- return GetType() == ShadowRootType::V0 ||
- GetType() == ShadowRootType::kOpen;
- }
- bool IsV1() const {
- return GetType() == ShadowRootType::kOpen ||
- GetType() == ShadowRootType::kClosed ||
- GetType() == ShadowRootType::kUserAgent;
- }
+ bool IsOpen() const { return GetType() == ShadowRootType::kOpen; }
bool IsUserAgent() const { return GetType() == ShadowRootType::kUserAgent; }
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
@@ -107,12 +94,11 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
void SetNeedsAssignmentRecalc();
bool NeedsSlotAssignmentRecalc() const;
- ShadowRootV0& V0() const;
-
// For Internals, don't use this.
unsigned ChildShadowRootCount() const { return child_shadow_root_count_; }
void RebuildLayoutTree(WhitespaceAttacher&);
+ void DetachLayoutTree(bool performing_reattach) override;
void RegisterScopedHTMLStyleChild();
void UnregisterScopedHTMLStyleChild();
@@ -129,19 +115,13 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
void DidChangeHostChildSlotName(const AtomicString& old_value,
const AtomicString& new_value);
- void SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc();
- void SetNeedsDistributionRecalc();
- bool NeedsDistributionRecalc() const { return needs_distribution_recalc_; }
-
void DistributeIfNeeded();
Element* ActiveElement() const;
String innerHTML() const;
+ String getInnerHTML(const GetInnerHTMLOptions* options) const;
void setInnerHTML(const String&, ExceptionState& = ASSERT_NO_EXCEPTION);
- void setInnerHTMLWithOptions(const String&,
- const SetInnerHTMLOptions*,
- ExceptionState& = ASSERT_NO_EXCEPTION);
Node* Clone(Document&, CloneChildrenFlag) const override;
@@ -176,6 +156,13 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
return available_to_element_internals_;
}
+ void SetNeedsDirAutoAttributeUpdate(bool flag) {
+ needs_dir_auto_attribute_update_ = flag;
+ }
+ bool NeedsDirAutoAttributeUpdate() const {
+ return needs_dir_auto_attribute_update_;
+ }
+
bool ContainsShadowRoots() const { return child_shadow_root_count_; }
StyleSheetList& StyleSheets();
@@ -186,26 +173,18 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
void Trace(Visitor*) const override;
private:
- ~ShadowRoot() override;
-
void ChildrenChanged(const ChildrenChange&) override;
SlotAssignment& EnsureSlotAssignment();
- void SetInnerHTMLInternal(const String&,
- const SetInnerHTMLOptions*,
- ExceptionState&);
-
void AddChildShadowRoot() { ++child_shadow_root_count_; }
void RemoveChildShadowRoot() {
DCHECK_GT(child_shadow_root_count_, 0u);
--child_shadow_root_count_;
}
- void Distribute();
Member<StyleSheetList> style_sheet_list_;
Member<SlotAssignment> slot_assignment_;
- Member<ShadowRootV0> shadow_root_v0_;
unsigned child_shadow_root_count_ : 16;
unsigned type_ : 2;
unsigned registered_with_parent_shadow_root_ : 1;
@@ -213,7 +192,7 @@ class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
unsigned slot_assignment_mode_ : 1;
unsigned is_declarative_shadow_root_ : 1;
unsigned available_to_element_internals_ : 1;
- unsigned needs_distribution_recalc_ : 1;
+ unsigned needs_dir_auto_attribute_update_ : 1;
unsigned unused_ : 8;
};
@@ -225,12 +204,6 @@ inline bool Node::IsInUserAgentShadowRoot() const {
return ContainingShadowRoot() && ContainingShadowRoot()->IsUserAgent();
}
-inline void ShadowRoot::DistributeIfNeeded() {
- if (needs_distribution_recalc_)
- Distribute();
- needs_distribution_recalc_ = false;
-}
-
inline ShadowRoot* Node::GetShadowRoot() const {
auto* this_element = DynamicTo<Element>(this);
if (!this_element)
@@ -238,19 +211,6 @@ inline ShadowRoot* Node::GetShadowRoot() const {
return this_element->GetShadowRoot();
}
-inline ShadowRoot* Element::ShadowRootIfV1() const {
- ShadowRoot* root = GetShadowRoot();
- if (root && root->IsV1())
- return root;
- return nullptr;
-}
-
-inline ShadowRootV0& ShadowRoot::V0() const {
- DCHECK(shadow_root_v0_);
- DCHECK(IsV0());
- return *shadow_root_v0_;
-}
-
template <>
struct DowncastTraits<ShadowRoot> {
static bool AllowFrom(const Node& node) { return node.IsShadowRoot(); }
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root.idl b/chromium/third_party/blink/renderer/core/dom/shadow_root.idl
index ebff48b67a2..b455e2f428d 100644
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root.idl
+++ b/chromium/third_party/blink/renderer/core/dom/shadow_root.idl
@@ -32,13 +32,12 @@ interface ShadowRoot : DocumentFragment {
readonly attribute Element host;
// TODO(lyf): Change the type to `[TreatNullAs=xxx] HTMLString` after
// https://crbug.com/1058762 has been fixed.
- [CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML;
+ [CEReactions, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML;
readonly attribute boolean delegatesFocus;
[RuntimeEnabled=ManualSlotting] readonly attribute SlotAssignmentMode slotAssignment;
- // Declarative Shadow DOM setInnerHTML function.
- // TODO(crbug.com/1147752): Add getInnerHTML() here also.
- [Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RaisesException, ImplementedAs=setInnerHTMLWithOptions] void setInnerHTML(HTMLString html, optional SetInnerHTMLOptions options = {});
+ // Declarative Shadow DOM getInnerHTML() function.
+ [Affects=Nothing, RuntimeEnabled=DeclarativeShadowDOM, RuntimeCallStatsCounter=ElementGetInnerHTML] HTMLString getInnerHTML(optional GetInnerHTMLOptions options = {});
};
ShadowRoot includes DocumentOrShadowRoot;
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.cc b/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.cc
deleted file mode 100644
index bed947c0bd9..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
-
-#include "third_party/blink/renderer/core/dom/element_traversal.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-#include "third_party/blink/renderer/core/html/html_content_element.h"
-#include "third_party/blink/renderer/core/html/html_shadow_element.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-
-namespace blink {
-
-class DistributionPool final {
- STACK_ALLOCATED();
-
- public:
- explicit DistributionPool(const ContainerNode&);
- void Clear();
- ~DistributionPool();
- void DistributeTo(V0InsertionPoint*, ShadowRoot*);
- void PopulateChildren(const ContainerNode&);
-
- private:
- void DetachNonDistributedNodes();
- HeapVector<Member<Node>, 32> nodes_;
- Vector<bool, 32> distributed_;
-};
-
-inline DistributionPool::DistributionPool(const ContainerNode& parent) {
- PopulateChildren(parent);
-}
-
-inline void DistributionPool::Clear() {
- DetachNonDistributedNodes();
- nodes_.clear();
- distributed_.clear();
-}
-
-inline void DistributionPool::PopulateChildren(const ContainerNode& parent) {
- Clear();
- for (Node* child = parent.firstChild(); child; child = child->nextSibling()) {
- // Re-distribution across v0 and v1 shadow trees is not supported
- if (IsA<HTMLSlotElement>(child))
- continue;
-
- if (IsActiveV0InsertionPoint(*child)) {
- auto* insertion_point = To<V0InsertionPoint>(child);
- for (wtf_size_t i = 0; i < insertion_point->DistributedNodesSize(); ++i)
- nodes_.push_back(insertion_point->DistributedNodeAt(i));
- } else {
- nodes_.push_back(child);
- }
- }
- distributed_.resize(nodes_.size());
- distributed_.Fill(false);
-}
-
-void DistributionPool::DistributeTo(V0InsertionPoint* insertion_point,
- ShadowRoot* shadow_root) {
- DistributedNodes distributed_nodes;
-
- for (wtf_size_t i = 0; i < nodes_.size(); ++i) {
- if (distributed_[i])
- continue;
-
- auto* html_content_element = DynamicTo<HTMLContentElement>(insertion_point);
- if (html_content_element && !html_content_element->CanSelectNode(nodes_, i))
- continue;
-
- Node* node = nodes_[i];
- distributed_nodes.Append(node);
- shadow_root->V0().DidDistributeNode(node, insertion_point);
- distributed_[i] = true;
- }
-
- // Distributes fallback elements
- if (insertion_point->IsContentInsertionPoint() &&
- distributed_nodes.IsEmpty()) {
- for (Node* fallback_node = insertion_point->firstChild(); fallback_node;
- fallback_node = fallback_node->nextSibling()) {
- distributed_nodes.Append(fallback_node);
- shadow_root->V0().DidDistributeNode(fallback_node, insertion_point);
- }
- }
- insertion_point->SetDistributedNodes(distributed_nodes);
-}
-
-inline DistributionPool::~DistributionPool() {
- DetachNonDistributedNodes();
-}
-
-inline void DistributionPool::DetachNonDistributedNodes() {
- for (wtf_size_t i = 0; i < nodes_.size(); ++i) {
- if (!distributed_[i])
- nodes_[i]->RemovedFromFlatTree();
- }
-}
-
-const HeapVector<Member<V0InsertionPoint>>&
-ShadowRootV0::DescendantInsertionPoints() {
- DEFINE_STATIC_LOCAL(
- Persistent<HeapVector<Member<V0InsertionPoint>>>, empty_list,
- (MakeGarbageCollected<HeapVector<Member<V0InsertionPoint>>>()));
- if (descendant_insertion_points_is_valid_)
- return descendant_insertion_points_;
-
- descendant_insertion_points_is_valid_ = true;
-
- if (!ContainsInsertionPoints())
- return *empty_list;
-
- HeapVector<Member<V0InsertionPoint>> insertion_points;
- for (V0InsertionPoint& insertion_point :
- Traversal<V0InsertionPoint>::DescendantsOf(GetShadowRoot()))
- insertion_points.push_back(&insertion_point);
-
- descendant_insertion_points_.swap(insertion_points);
- return descendant_insertion_points_;
-}
-
-const V0InsertionPoint* ShadowRootV0::FinalDestinationInsertionPointFor(
- const Node* key) const {
-#if DCHECK_IS_ON()
- DCHECK(key);
- // Allow traversal without V0 distribution up-to-date for marking ancestors
- // with ChildNeedsStyleRecalc() for marking ancestors with child-needs-style-
- // recalc on a tree with a dirty distribution.
- DCHECK(!key->NeedsDistributionRecalc() ||
- key->GetDocument().AllowDirtyShadowV0Traversal());
-#endif
- NodeToDestinationInsertionPoints::const_iterator it =
- node_to_insertion_points_.find(key);
- return it == node_to_insertion_points_.end() ? nullptr : it->value->back();
-}
-
-const DestinationInsertionPoints* ShadowRootV0::DestinationInsertionPointsFor(
- const Node* key) const {
- DCHECK(key);
- DCHECK(!key->NeedsDistributionRecalc());
- NodeToDestinationInsertionPoints::const_iterator it =
- node_to_insertion_points_.find(key);
- return it == node_to_insertion_points_.end() ? nullptr : it->value;
-}
-
-void ShadowRootV0::Distribute() {
- ClearDistribution();
-
- DistributionPool pool(GetShadowRoot().host());
- HTMLShadowElement* shadow_insertion_point = nullptr;
-
- for (const auto& point : DescendantInsertionPoints()) {
- if (!point->IsActive())
- continue;
- if (auto* shadow = DynamicTo<HTMLShadowElement>(*point)) {
- DCHECK(!shadow_insertion_point);
- shadow_insertion_point = shadow;
- } else {
- pool.DistributeTo(point, &GetShadowRoot());
- if (ShadowRoot* shadow_root =
- ShadowRootWhereNodeCanBeDistributedForV0(*point)) {
- if (!shadow_root->IsV1())
- shadow_root->SetNeedsDistributionRecalc();
- }
- }
- }
-
- if (shadow_insertion_point) {
- pool.DistributeTo(shadow_insertion_point, &GetShadowRoot());
- if (ShadowRoot* shadow_root =
- ShadowRootWhereNodeCanBeDistributedForV0(*shadow_insertion_point))
- shadow_root->SetNeedsDistributionRecalc();
- }
- probe::DidPerformElementShadowDistribution(&GetShadowRoot().host());
-}
-
-void ShadowRootV0::DidDistributeNode(const Node* node,
- V0InsertionPoint* insertion_point) {
- NodeToDestinationInsertionPoints::AddResult result =
- node_to_insertion_points_.insert(node, nullptr);
- if (result.is_new_entry) {
- result.stored_value->value =
- MakeGarbageCollected<DestinationInsertionPoints>();
- }
- result.stored_value->value->push_back(insertion_point);
-}
-
-void ShadowRootV0::ClearDistribution() {
- node_to_insertion_points_.clear();
-}
-
-void ShadowRootV0::WillAffectSelector() {
- for (ShadowRoot* shadow_root = &GetShadowRoot(); shadow_root;
- shadow_root = shadow_root->host().ContainingShadowRoot()) {
- if (shadow_root->IsV1() || shadow_root->V0().NeedsSelectFeatureSet())
- break;
- shadow_root->V0().SetNeedsSelectFeatureSet();
- }
- GetShadowRoot().SetNeedsDistributionRecalc();
-}
-
-const SelectRuleFeatureSet& ShadowRootV0::EnsureSelectFeatureSet() {
- if (!needs_select_feature_set_)
- return select_features_;
-
- select_features_.Clear();
- CollectSelectFeatureSetFrom();
- needs_select_feature_set_ = false;
- return SelectFeatures();
-}
-
-void ShadowRootV0::CollectSelectFeatureSetFrom() {
- if (!GetShadowRoot().ContainsShadowRoots() && !ContainsContentElements())
- return;
-
- auto& select_features = select_features_;
- for (Element& element : ElementTraversal::DescendantsOf(GetShadowRoot())) {
- if (ShadowRoot* shadow_root = element.GetShadowRoot()) {
- if (!shadow_root->IsV1())
- select_features.Add(shadow_root->V0().EnsureSelectFeatureSet());
- }
- if (auto* content = DynamicTo<HTMLContentElement>(element))
- select_features.CollectFeaturesFromSelectorList(content->SelectorList());
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h b/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h
deleted file mode 100644
index eb1fed968cb..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/shadow_root_v0.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_SHADOW_ROOT_V0_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_SHADOW_ROOT_V0_H_
-
-#include "third_party/blink/renderer/core/css/select_rule_feature_set.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class CORE_EXPORT ShadowRootV0 final : public GarbageCollected<ShadowRootV0> {
- public:
- using NodeToDestinationInsertionPoints =
- HeapHashMap<Member<const Node>, Member<DestinationInsertionPoints>>;
-
- explicit ShadowRootV0(ShadowRoot& shadow_root) : shadow_root_(&shadow_root) {}
- ShadowRootV0(const ShadowRootV0&) = delete;
- ShadowRootV0& operator=(const ShadowRootV0&) = delete;
-
- bool ContainsShadowElements() const {
- return descendant_shadow_element_count_;
- }
- bool ContainsContentElements() const {
- return descendant_content_element_count_;
- }
- bool ContainsInsertionPoints() const {
- return ContainsShadowElements() || ContainsContentElements();
- }
-
- unsigned DescendantShadowElementCount() const {
- return descendant_shadow_element_count_;
- }
- void DidAddInsertionPoint(V0InsertionPoint*);
- void DidRemoveInsertionPoint(V0InsertionPoint*);
-
- const HeapVector<Member<V0InsertionPoint>>& DescendantInsertionPoints();
- void InvalidateDescendantInsertionPoints();
-
- const V0InsertionPoint* FinalDestinationInsertionPointFor(
- const Node* key) const;
- const DestinationInsertionPoints* DestinationInsertionPointsFor(
- const Node* key) const;
-
- void Distribute();
- void DidDistributeNode(const Node*, V0InsertionPoint*);
- void ClearDistribution();
-
- void WillAffectSelector();
- const SelectRuleFeatureSet& EnsureSelectFeatureSet();
- void CollectSelectFeatureSetFrom();
- bool NeedsSelectFeatureSet() const { return needs_select_feature_set_; }
- void SetNeedsSelectFeatureSet() { needs_select_feature_set_ = true; }
- SelectRuleFeatureSet& SelectFeatures() { return select_features_; }
-
- void Trace(Visitor* visitor) const {
- visitor->Trace(shadow_root_);
- visitor->Trace(descendant_insertion_points_);
- visitor->Trace(node_to_insertion_points_);
- }
-
- private:
- ShadowRoot& GetShadowRoot() const { return *shadow_root_; }
-
- Member<ShadowRoot> shadow_root_;
- unsigned descendant_shadow_element_count_ = 0;
- unsigned descendant_content_element_count_ = 0;
- HeapVector<Member<V0InsertionPoint>> descendant_insertion_points_;
-
- NodeToDestinationInsertionPoints node_to_insertion_points_;
- SelectRuleFeatureSet select_features_;
- bool needs_select_feature_set_ = false;
- bool descendant_insertion_points_is_valid_ = false;
-};
-
-inline void ShadowRootV0::DidAddInsertionPoint(V0InsertionPoint* point) {
- DCHECK(point);
- if (IsA<HTMLShadowElement>(*point))
- ++descendant_shadow_element_count_;
- else if (IsA<HTMLContentElement>(*point))
- ++descendant_content_element_count_;
- else
- NOTREACHED();
- InvalidateDescendantInsertionPoints();
-}
-
-inline void ShadowRootV0::DidRemoveInsertionPoint(V0InsertionPoint* point) {
- DCHECK(point);
- if (IsA<HTMLShadowElement>(*point)) {
- DCHECK_GT(descendant_shadow_element_count_, 0u);
- --descendant_shadow_element_count_;
- } else if (IsA<HTMLContentElement>(*point)) {
- DCHECK_GT(descendant_content_element_count_, 0u);
- --descendant_content_element_count_;
- } else {
- NOTREACHED();
- }
- InvalidateDescendantInsertionPoints();
-}
-
-inline void ShadowRootV0::InvalidateDescendantInsertionPoints() {
- descendant_insertion_points_is_valid_ = false;
- descendant_insertion_points_.clear();
-}
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc b/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
index cc5f5ac9751..2b106ca99a1 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -77,7 +77,6 @@ void SlotAssignment::DidRemoveSlot(HTMLSlotElement& slot) {
return;
}
- DCHECK(GetCachedFirstSlotWithoutAccessingNodeTree(slot.GetName()));
DidRemoveSlotInternal(slot, slot.GetName(), SlotMutationType::kRemoved);
// Ensures that TreeOrderedMap has a cache if there is a slot for the name.
DCHECK(!slot_map_->Contains(slot.GetName()) ||
@@ -97,7 +96,7 @@ void SlotAssignment::DidAddSlotInternal(HTMLSlotElement& slot) {
// At this timing, we can't use FindSlotByName because what we are interested
// in is the first slot *before* |slot| was inserted. Here, |slot| was already
- // disconnected from the tree. Thus, we can't use on FindBySlotName because
+ // connected to the tree. Thus, we can't use on FindBySlotName because
// it might scan the current tree and return a wrong result.
HTMLSlotElement* old_active =
GetCachedFirstSlotWithoutAccessingNodeTree(slot_name);
@@ -146,11 +145,18 @@ void SlotAssignment::DidRemoveSlotInternal(
// At this timing, we can't use FindSlotByName because what we are interested
// in is the first slot *before* |slot| was removed. Here, |slot| was already
- // connected to the tree. Thus, we can't use FindBySlotName because
+ // disconnected from the tree. Thus, we can't use FindBySlotName because
// it might scan the current tree and return a wrong result.
HTMLSlotElement* old_active =
GetCachedFirstSlotWithoutAccessingNodeTree(slot_name);
- DCHECK(old_active);
+
+ // If we don't have a cached slot for this slot name, then we're
+ // likely removing a nested identically named slot, e.g.
+ // <slot id=removed><slot></slot</slot>, and this is the inner
+ // slot. It has already been removed from the map, so return.
+ if (!old_active)
+ return;
+
slot_map_->Remove(slot_name, slot);
// This also ensures that TreeOrderedMap has a cache for the first element.
HTMLSlotElement* new_active = FindSlotByName(slot_name);
@@ -224,7 +230,6 @@ SlotAssignment::SlotAssignment(ShadowRoot& owner)
owner_(&owner),
needs_collect_slots_(false),
slot_count_(0) {
- DCHECK(owner.IsV1());
}
void SlotAssignment::SetNeedsAssignmentRecalc() {
@@ -239,98 +244,119 @@ void SlotAssignment::SetNeedsAssignmentRecalc() {
void SlotAssignment::RecalcAssignment() {
if (!needs_assignment_recalc_)
return;
- NestingLevelIncrementer slot_assignment_recalc_depth(
- owner_->GetDocument().SlotAssignmentRecalcDepth());
-
-#if DCHECK_IS_ON()
- DCHECK(!owner_->GetDocument().IsSlotAssignmentRecalcForbidden());
+ {
+ NestingLevelIncrementer slot_assignment_recalc_depth(
+ owner_->GetDocument().SlotAssignmentRecalcDepth());
+
+// TODO(crbug.com/1176575): Revert https://crrev.com/c/2686770 to re-enable this
+// DCHECK on CrOS. See go/chrome-dcheck-on-cros or http://crbug.com/1113456 for
+// more details.
+#if DCHECK_IS_ON() && !defined(OS_CHROMEOS)
+ DCHECK(!owner_->GetDocument().IsSlotAssignmentRecalcForbidden());
#endif
- // To detect recursive RecalcAssignment, which shouldn't happen.
- SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(owner_->GetDocument());
+ // To detect recursive RecalcAssignment, which shouldn't happen.
+ SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(
+ owner_->GetDocument());
- FlatTreeTraversalForbiddenScope forbid_flat_tree_traversal(
- owner_->GetDocument());
+ FlatTreeTraversalForbiddenScope forbid_flat_tree_traversal(
+ owner_->GetDocument());
- needs_assignment_recalc_ = false;
+ needs_assignment_recalc_ = false;
- for (Member<HTMLSlotElement> slot : Slots())
- slot->WillRecalcAssignedNodes();
+ for (Member<HTMLSlotElement> slot : Slots())
+ slot->WillRecalcAssignedNodes();
- const bool is_user_agent = owner_->IsUserAgent();
+ const bool is_user_agent = owner_->IsUserAgent();
- HTMLSlotElement* user_agent_default_slot = nullptr;
- HTMLSlotElement* user_agent_custom_assign_slot = nullptr;
- if (is_user_agent) {
- user_agent_default_slot =
- FindSlotByName(HTMLSlotElement::UserAgentDefaultSlotName());
- user_agent_custom_assign_slot =
- FindSlotByName(HTMLSlotElement::UserAgentCustomAssignSlotName());
- }
-
- bool is_manual_slot_assignment = owner_->IsManualSlotting();
- // Replaces candidate_assigned_slot_map_ after the loop, to avoid stale
- // references resulting from calls to slot->DidRecalcAssignedNodes().
- HeapHashMap<Member<Node>, Member<HTMLSlotElement>> candidate_map;
-
- for (Node& child : NodeTraversal::ChildrenOf(owner_->host())) {
- if (!child.IsSlotable())
- continue;
+ HTMLSlotElement* user_agent_default_slot = nullptr;
+ HTMLSlotElement* user_agent_custom_assign_slot = nullptr;
+ if (is_user_agent) {
+ user_agent_default_slot =
+ FindSlotByName(HTMLSlotElement::UserAgentDefaultSlotName());
+ user_agent_custom_assign_slot =
+ FindSlotByName(HTMLSlotElement::UserAgentCustomAssignSlotName());
+ }
- HTMLSlotElement* slot = nullptr;
- if (!is_user_agent) {
- if (is_manual_slot_assignment) {
- if (auto* candidate_slot = candidate_assigned_slot_map_.at(&child)) {
- if (candidate_slot->ContainingShadowRoot() == owner_) {
- slot = candidate_slot;
- } else {
- candidate_assigned_slot_map_.erase(&child);
- const AtomicString& slot_name =
- (candidate_slot->GetName() != g_empty_atom)
- ? candidate_slot->GetName()
- : "SLOT";
- owner_->GetDocument().AddConsoleMessage(
- MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kRendering,
- mojom::blink::ConsoleMessageLevel::kWarning,
- "This code triggered a slot assignment recalculation. At "
- "the time of this recalculation, the assigned node '" +
- child.nodeName() + "' was no longer a child of '" +
- slot_name +
- "'s parent shadow host, so it could not be assigned."));
+ bool is_manual_slot_assignment = owner_->IsManualSlotting();
+ // Replaces candidate_assigned_slot_map_ after the loop, to avoid stale
+ // references resulting from calls to slot->DidRecalcAssignedNodes().
+ HeapHashMap<Member<Node>, Member<HTMLSlotElement>> candidate_map;
+
+ for (Node& child : NodeTraversal::ChildrenOf(owner_->host())) {
+ if (!child.IsSlotable())
+ continue;
+
+ HTMLSlotElement* slot = nullptr;
+ if (!is_user_agent) {
+ if (is_manual_slot_assignment) {
+ if (auto* candidate_slot = candidate_assigned_slot_map_.at(&child)) {
+ if (candidate_slot->ContainingShadowRoot() == owner_) {
+ slot = candidate_slot;
+ } else {
+ candidate_assigned_slot_map_.erase(&child);
+ const AtomicString& slot_name =
+ (candidate_slot->GetName() != g_empty_atom)
+ ? candidate_slot->GetName()
+ : "SLOT";
+ owner_->GetDocument().AddConsoleMessage(MakeGarbageCollected<
+ ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kRendering,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "This code triggered a slot assignment recalculation. At "
+ "the time of this recalculation, the assigned node '" +
+ child.nodeName() + "' was no longer a child of '" +
+ slot_name +
+ "'s parent shadow host, so it could not be assigned."));
+ }
}
+ } else {
+ slot = FindSlotByName(child.SlotName());
}
} else {
- slot = FindSlotByName(child.SlotName());
+ if (user_agent_custom_assign_slot && ShouldAssignToCustomSlot(child)) {
+ slot = user_agent_custom_assign_slot;
+ } else {
+ slot = user_agent_default_slot;
+ }
}
- } else {
- if (user_agent_custom_assign_slot && ShouldAssignToCustomSlot(child)) {
- slot = user_agent_custom_assign_slot;
+
+ if (slot) {
+ slot->AppendAssignedNode(child);
+ if (is_manual_slot_assignment)
+ candidate_map.Set(&child, slot);
} else {
- slot = user_agent_default_slot;
+ child.ClearFlatTreeNodeData();
+ child.RemovedFromFlatTree();
}
}
- if (slot) {
- slot->AppendAssignedNode(child);
- if (is_manual_slot_assignment)
- candidate_map.Set(&child, slot);
- } else {
- child.ClearFlatTreeNodeData();
- child.RemovedFromFlatTree();
+ if (owner_->isConnected()) {
+ owner_->GetDocument()
+ .GetSlotAssignmentEngine()
+ .RemoveShadowRootNeedingRecalc(*owner_);
}
- }
- if (owner_->isConnected()) {
- owner_->GetDocument()
- .GetSlotAssignmentEngine()
- .RemoveShadowRootNeedingRecalc(*owner_);
- }
+ for (auto& slot : Slots())
+ slot->DidRecalcAssignedNodes();
- for (auto& slot : Slots())
- slot->DidRecalcAssignedNodes();
+ if (is_manual_slot_assignment)
+ candidate_assigned_slot_map_.swap(candidate_map);
+ }
- if (is_manual_slot_assignment)
- candidate_assigned_slot_map_.swap(candidate_map);
+ // Update an dir=auto flag from a host of slots to its all descendants.
+ // We should call below functions outside FlatTreeTraversalForbiddenScope
+ // because we can go a tree walk to either their ancestors or descendants
+ // if needed.
+ if (owner_->NeedsDirAutoAttributeUpdate()) {
+ owner_->SetNeedsDirAutoAttributeUpdate(false);
+ if (auto* element = DynamicTo<HTMLElement>(owner_->host())) {
+ element->UpdateDescendantHasDirAutoAttribute(
+ element->SelfOrAncestorHasDirAutoAttribute());
+ }
+ }
+ // Resolve the directionality of elements deferred their adjustment.
+ HTMLElement::AdjustCandidateDirectionalityForSlot(
+ std::move(candidate_directionality_set_));
}
const HeapVector<Member<HTMLSlotElement>>& SlotAssignment::Slots() {
@@ -418,6 +444,7 @@ void SlotAssignment::Trace(Visitor* visitor) const {
visitor->Trace(slot_map_);
visitor->Trace(owner_);
visitor->Trace(candidate_assigned_slot_map_);
+ visitor->Trace(candidate_directionality_set_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment.h b/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
index 88778633d6f..c5a8315392b 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment.h
@@ -11,6 +11,7 @@
namespace blink {
+class HTMLElement;
class HTMLSlotElement;
class Node;
class ShadowRoot;
@@ -56,6 +57,9 @@ class SlotAssignment final : public GarbageCollected<SlotAssignment> {
void RecalcAssignment();
bool UpdateCandidateNodeAssignedSlot(Node&, HTMLSlotElement&);
void ClearCandidateNodes(const HeapLinkedHashSet<Member<Node>>& candidates);
+ HeapHashSet<Member<HTMLElement>>& GetCandidateDirectionality() {
+ return candidate_directionality_set_;
+ }
private:
enum class SlotMutationType {
@@ -84,6 +88,7 @@ class SlotAssignment final : public GarbageCollected<SlotAssignment> {
// TODO: (1067157) Ensure references inside the map are GCed.
HeapHashMap<Member<Node>, Member<HTMLSlotElement>>
candidate_assigned_slot_map_;
+ HeapHashSet<Member<HTMLElement>> candidate_directionality_set_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/slot_assignment_test.cc b/chromium/third_party/blink/renderer/core/dom/slot_assignment_test.cc
index 67e212282bc..6e60db473ee 100644
--- a/chromium/third_party/blink/renderer/core/dom/slot_assignment_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/slot_assignment_test.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
@@ -70,9 +69,7 @@ void SlotAssignmentTest::SetUp() {
void SlotAssignmentTest::SetBody(const char* html) {
Element* body = GetDocument().body();
- SetInnerHTMLOptions options;
- options.setAllowShadowRoot(true);
- body->setInnerHTMLWithOptions(String::FromUTF8(html), &options);
+ body->setInnerHTMLWithDeclarativeShadowDOMForTesting(String::FromUTF8(html));
RemoveWhiteSpaceOnlyTextNode(*body);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range.cc b/chromium/third_party/blink/renderer/core/dom/static_range.cc
index 1643e26fabd..bce0400dd95 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_range.cc
+++ b/chromium/third_party/blink/renderer/core/dom/static_range.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/dom/static_range.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_static_range_init.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/frame/local_dom_window.h"
@@ -40,6 +41,27 @@ StaticRange* StaticRange::Create(const EphemeralRange& range) {
range.EndPosition().ComputeOffsetInContainerNode());
}
+StaticRange* StaticRange::Create(Document& document,
+ const StaticRangeInit* static_range_init,
+ ExceptionState& exception_state) {
+ DCHECK(static_range_init);
+
+ if (static_range_init->startContainer()->IsDocumentTypeNode() ||
+ static_range_init->startContainer()->IsAttributeNode() ||
+ static_range_init->endContainer()->IsDocumentTypeNode() ||
+ static_range_init->endContainer()->IsAttributeNode()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidNodeTypeError,
+ "Neither startContainer nor endContainer can be a DocumentType or "
+ "Attribute node.");
+ }
+
+ return MakeGarbageCollected<StaticRange>(
+ document, static_range_init->startContainer(),
+ static_range_init->startOffset(), static_range_init->endContainer(),
+ static_range_init->endOffset());
+}
+
void StaticRange::setStart(Node* container, unsigned offset) {
start_container_ = container;
start_offset_ = offset;
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range.h b/chromium/third_party/blink/renderer/core/dom/static_range.h
index 5a232800f34..a1e45bffb60 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_range.h
+++ b/chromium/third_party/blink/renderer/core/dom/static_range.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_STATIC_RANGE_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/abstract_range.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -15,8 +16,9 @@ namespace blink {
class Document;
class ExceptionState;
+class StaticRangeInit;
-class CORE_EXPORT StaticRange final : public ScriptWrappable {
+class CORE_EXPORT StaticRange final : public AbstractRange {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -26,6 +28,9 @@ class CORE_EXPORT StaticRange final : public ScriptWrappable {
range->endContainer(), range->endOffset());
}
static StaticRange* Create(const EphemeralRange&);
+ static StaticRange* Create(Document&,
+ const StaticRangeInit*,
+ ExceptionState&);
explicit StaticRange(Document&);
StaticRange(Document&,
@@ -34,21 +39,21 @@ class CORE_EXPORT StaticRange final : public ScriptWrappable {
Node* end_container,
unsigned end_offset);
- Node* startContainer() const { return start_container_.Get(); }
+ Node* startContainer() const override { return start_container_.Get(); }
void setStartContainer(Node* start_container) {
start_container_ = start_container;
}
- unsigned startOffset() const { return start_offset_; }
+ unsigned startOffset() const override { return start_offset_; }
void setStartOffset(unsigned start_offset) { start_offset_ = start_offset; }
- Node* endContainer() const { return end_container_.Get(); }
+ Node* endContainer() const override { return end_container_.Get(); }
void setEndContainer(Node* end_container) { end_container_ = end_container; }
- unsigned endOffset() const { return end_offset_; }
+ unsigned endOffset() const override { return end_offset_; }
void setEndOffset(unsigned end_offset) { end_offset_ = end_offset; }
- bool collapsed() const {
+ bool collapsed() const override {
return start_container_ == end_container_ && start_offset_ == end_offset_;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range.idl b/chromium/third_party/blink/renderer/core/dom/static_range.idl
index 0aa967a0ad9..462ddecd5b2 100644
--- a/chromium/third_party/blink/renderer/core/dom/static_range.idl
+++ b/chromium/third_party/blink/renderer/core/dom/static_range.idl
@@ -4,12 +4,7 @@
// https://w3c.github.io/staticrange/#interface-staticrange
-[
- Exposed=Window
-] interface StaticRange {
- readonly attribute Node startContainer;
- readonly attribute unsigned long startOffset;
- readonly attribute Node endContainer;
- readonly attribute unsigned long endOffset;
- readonly attribute boolean collapsed;
-};
+[Exposed=Window]
+interface StaticRange : AbstractRange {
+ [CallWith=Document, RaisesException] constructor(StaticRangeInit init);
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/dom/static_range_init.idl b/chromium/third_party/blink/renderer/core/dom/static_range_init.idl
new file mode 100644
index 00000000000..33ef064ad29
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/static_range_init.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/staticrange/#interface-staticrange
+
+dictionary StaticRangeInit {
+ required Node startContainer;
+ required unsigned long startOffset;
+ required Node endContainer;
+ required unsigned long endOffset;
+};
diff --git a/chromium/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h b/chromium/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
index e574de51210..65ff054c596 100644
--- a/chromium/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
+++ b/chromium/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
@@ -13,6 +13,7 @@ namespace blink {
class CharacterData;
class ContainerNode;
class Document;
+class Node;
class NodeWithIndex;
class Text;
diff --git a/chromium/third_party/blink/renderer/core/dom/text.cc b/chromium/third_party/blink/renderer/core/dom/text.cc
index 5f6d0b5ff9d..f665be1b2e6 100644
--- a/chromium/third_party/blink/renderer/core/dom/text.cc
+++ b/chromium/third_party/blink/renderer/core/dom/text.cc
@@ -124,8 +124,13 @@ Text* Text::splitText(unsigned offset, ExceptionState& exception_state) {
if (exception_state.HadException())
return nullptr;
- if (GetLayoutObject())
+ if (GetLayoutObject()) {
GetLayoutObject()->SetTextWithOffset(DataImpl(), 0, old_str.length());
+ if (data().IsEmpty()) {
+ // To avoid |LayoutText| has empty text, we rebuild layout tree.
+ SetForceReattachLayoutTree();
+ }
+ }
if (parentNode())
GetDocument().DidSplitTextNode(*this);
@@ -259,7 +264,7 @@ static inline bool CanHaveWhitespaceChildren(
if (parent.IsTable() || parent.IsTableRow() || parent.IsTableSection() ||
parent.IsLayoutTableCol() || parent.IsFrameSet() ||
- parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutGrid() ||
+ parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutGridIncludingNG() ||
parent.IsSVGRoot() || parent.IsSVGContainer() || parent.IsSVGImage() ||
parent.IsSVGShape()) {
if (!context.use_previous_in_flow || !context.previous_in_flow ||
@@ -275,8 +280,6 @@ static inline bool CanHaveWhitespaceChildren(
bool Text::TextLayoutObjectIsNeeded(const AttachContext& context,
const ComputedStyle& style) const {
- DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
-
const LayoutObject& parent = *context.parent;
if (!parent.CanHaveChildren())
return false;
@@ -429,13 +432,9 @@ static bool ShouldUpdateLayoutByReattaching(const Text& text_node,
DCHECK_EQ(text_node.GetLayoutObject(), text_layout_object);
if (!text_layout_object)
return true;
- // In general we do not want to branch on lifecycle states such as
- // |ChildNeedsDistributionRecalc|, but this code tries to figure out if we can
- // use an optimized code path that avoids reattach.
Node::AttachContext context;
context.parent = text_layout_object->Parent();
- if (!text_node.GetDocument().ChildNeedsDistributionRecalc() &&
- !text_node.TextLayoutObjectIsNeeded(context,
+ if (!text_node.TextLayoutObjectIsNeeded(context,
*text_layout_object->Style())) {
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/text_link_colors.cc b/chromium/third_party/blink/renderer/core/dom/text_link_colors.cc
index d08b1673f7c..7179b7c4bad 100644
--- a/chromium/third_party/blink/renderer/core/dom/text_link_colors.cc
+++ b/chromium/third_party/blink/renderer/core/dom/text_link_colors.cc
@@ -62,7 +62,7 @@ void TextLinkColors::SetTextColor(const Color& color) {
}
Color TextLinkColors::TextColor() const {
- return TextColor(mojom::ColorScheme::kLight);
+ return TextColor(mojom::blink::ColorScheme::kLight);
}
Color TextLinkColors::TextColor(mojom::blink::ColorScheme color_scheme) const {
@@ -79,7 +79,7 @@ void TextLinkColors::SetLinkColor(const Color& color) {
}
const Color& TextLinkColors::LinkColor() const {
- return LinkColor(mojom::ColorScheme::kLight);
+ return LinkColor(mojom::blink::ColorScheme::kLight);
}
const Color& TextLinkColors::LinkColor(
@@ -97,7 +97,7 @@ void TextLinkColors::SetVisitedLinkColor(const Color& color) {
}
const Color& TextLinkColors::VisitedLinkColor() const {
- return VisitedLinkColor(mojom::ColorScheme::kLight);
+ return VisitedLinkColor(mojom::blink::ColorScheme::kLight);
}
const Color& TextLinkColors::VisitedLinkColor(
@@ -115,7 +115,7 @@ void TextLinkColors::SetActiveLinkColor(const Color& color) {
}
const Color& TextLinkColors::ActiveLinkColor() const {
- return ActiveLinkColor(mojom::ColorScheme::kLight);
+ return ActiveLinkColor(mojom::blink::ColorScheme::kLight);
}
const Color& TextLinkColors::ActiveLinkColor(
@@ -155,7 +155,7 @@ Color TextLinkColors::ColorFromCSSValue(const CSSValue& value,
case CSSValueID::kWebkitActivelink:
return ActiveLinkColor(color_scheme);
case CSSValueID::kWebkitFocusRingColor:
- return LayoutTheme::GetTheme().FocusRingColor();
+ return LayoutTheme::GetTheme().FocusRingColor(color_scheme);
case CSSValueID::kCurrentcolor:
return current_color;
default:
diff --git a/chromium/third_party/blink/renderer/core/dom/text_link_colors.h b/chromium/third_party/blink/renderer/core/dom/text_link_colors.h
index 23a5faf1800..055ae99fae0 100644
--- a/chromium/third_party/blink/renderer/core/dom/text_link_colors.h
+++ b/chromium/third_party/blink/renderer/core/dom/text_link_colors.h
@@ -30,7 +30,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TEXT_LINK_COLORS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TEXT_LINK_COLORS_H_
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-forward.h"
+#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -48,14 +48,14 @@ class TextLinkColors {
void SetTextColor(const Color& color);
Color TextColor() const;
- Color TextColor(mojom::ColorScheme color_scheme) const;
+ Color TextColor(mojom::blink::ColorScheme color_scheme) const;
const Color& LinkColor() const;
- const Color& LinkColor(mojom::ColorScheme color_scheme) const;
+ const Color& LinkColor(mojom::blink::ColorScheme color_scheme) const;
const Color& VisitedLinkColor() const;
- const Color& VisitedLinkColor(mojom::ColorScheme color_scheme) const;
+ const Color& VisitedLinkColor(mojom::blink::ColorScheme color_scheme) const;
const Color& ActiveLinkColor() const;
- const Color& ActiveLinkColor(mojom::ColorScheme color_scheme) const;
+ const Color& ActiveLinkColor(mojom::blink::ColorScheme color_scheme) const;
void SetLinkColor(const Color& color);
void SetVisitedLinkColor(const Color& color);
void SetActiveLinkColor(const Color& color);
@@ -64,7 +64,7 @@ class TextLinkColors {
void ResetActiveLinkColor() { has_custom_active_link_color_ = false; }
Color ColorFromCSSValue(const CSSValue&,
Color current_color,
- mojom::ColorScheme color_scheme,
+ mojom::blink::ColorScheme color_scheme,
bool for_visited_link = false) const;
private:
diff --git a/chromium/third_party/blink/renderer/core/dom/text_test.cc b/chromium/third_party/blink/renderer/core/dom/text_test.cc
index da82754f998..12a800a43fc 100644
--- a/chromium/third_party/blink/renderer/core/dom/text_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/text_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/html/html_pre_element.h"
@@ -40,6 +41,22 @@ TEST_F(TextTest, RemoveFirstLetterPseudoElementWhenNoLetter) {
EXPECT_FALSE(text->GetLayoutObject()->IsTextFragment());
}
+TEST_F(TextTest, splitTextToEmpty) {
+ V8TestingScope scope;
+
+ SetBodyContent("<p id=sample>ab</p>");
+ const Element& sample = *GetElementById("sample");
+ Text& text = *To<Text>(sample.firstChild());
+ // |new_text| is after |text|.
+ Text& new_text = *text.splitText(0, ASSERT_NO_EXCEPTION);
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("", text.data());
+ EXPECT_FALSE(text.GetLayoutObject());
+ EXPECT_EQ("ab", new_text.data());
+ EXPECT_TRUE(new_text.GetLayoutObject());
+}
+
TEST_F(TextTest, TextLayoutObjectIsNeeded_CannotHaveChildren) {
SetBodyContent("<img id=image>");
UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
index 425d212519a..f44ab4a28b5 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.cc
@@ -138,6 +138,9 @@ inline Element* TreeOrderedMap::Get(const AtomicString& key,
#if DCHECK_IS_ON()
DCHECK(g_remove_scope_level);
#endif
+ // Since we didn't find any elements for this key, remove the key from the
+ // map here.
+ map_.erase(key);
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
index 0a1a03abd3a..f9877e255e1 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map.h
@@ -32,6 +32,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TREE_ORDERED_MAP_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TREE_ORDERED_MAP_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -46,7 +47,12 @@ class Element;
class HTMLSlotElement;
class TreeScope;
-class TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
+// TreeOrderedMap is a map from keys to |Element|s, which allows multiple values
+// per key, maintained in tree order per key. Tree walks are avoided when
+// possible by retaining a cached, ordered array of matching nodes. Adding or
+// removing an element for a given key often clears the cache, forcing a tree
+// walk upon the next access.
+class CORE_EXPORT TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
public:
TreeOrderedMap();
@@ -73,7 +79,7 @@ class TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
// Rare trees, but ID lookups may legitimately fail across such removals;
// this scope object informs TreeOrderedMaps about the transitory state of the
// underlying tree.
- class RemoveScope {
+ class CORE_EXPORT RemoveScope {
STACK_ALLOCATED();
public:
@@ -81,7 +87,7 @@ class TreeOrderedMap : public GarbageCollected<TreeOrderedMap> {
~RemoveScope();
};
#else
- class RemoveScope {
+ class CORE_EXPORT RemoveScope {
STACK_ALLOCATED();
public:
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_ordered_map_test.cc b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map_test.cc
new file mode 100644
index 00000000000..09681258f7e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/dom/tree_ordered_map_test.cc
@@ -0,0 +1,143 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/dom/tree_ordered_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/html/html_slot_element.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+
+namespace blink {
+
+class TreeOrderedMapTest : public EditingTestBase {
+ protected:
+ void SetUp() override {
+ EditingTestBase::SetUp();
+ root_ = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+ root_->setAttribute(html_names::kIdAttr, AtomicString("ROOT"));
+ GetDocument().body()->appendChild(root_);
+ }
+
+ Element* AddElement(AtomicString slot_name) {
+ auto* slot = MakeGarbageCollected<HTMLSlotElement>(GetDocument());
+ slot->setAttribute(html_names::kNameAttr, slot_name);
+ std::string id = "SLOT_" + base::NumberToString(++element_num);
+ slot->setAttribute(html_names::kIdAttr, AtomicString(id.c_str()));
+ root_->appendChild(slot);
+ return static_cast<Element*>(slot);
+ }
+ TreeScope& GetTreeScope() { return root_->GetTreeScope(); }
+
+ private:
+ int element_num{0};
+ Persistent<HTMLDivElement> root_;
+};
+
+TEST_F(TreeOrderedMapTest, Basic) {
+ auto* map = MakeGarbageCollected<TreeOrderedMap>();
+ AtomicString key = "test";
+ auto& element = *AddElement(key);
+ map->Add(key, element);
+ EXPECT_TRUE(map->Contains(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), element);
+ map->Remove(key, element);
+ EXPECT_FALSE(map->Contains(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), nullptr);
+}
+
+TEST_F(TreeOrderedMapTest, DuplicateKeys) {
+ auto* map = MakeGarbageCollected<TreeOrderedMap>();
+ AtomicString key = "test";
+ auto& element1 = *AddElement(key);
+ auto& element2 = *AddElement(key);
+ map->Add(key, element1);
+ EXPECT_TRUE(map->Contains(key));
+ EXPECT_FALSE(map->ContainsMultiple(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), element1);
+ map->Add(key, element2);
+ EXPECT_TRUE(map->Contains(key));
+ EXPECT_TRUE(map->ContainsMultiple(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), nullptr)
+ << "No tree walk yet";
+ EXPECT_EQ(map->GetSlotByName(key, GetTreeScope()), element1);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), element1)
+ << "Tree walk forced by GetSlotByName";
+ element1.remove(); // Remove it from the tree also.
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), element1)
+ << "Make sure we don't touch the tree";
+ map->Remove(key, element1);
+ EXPECT_TRUE(map->Contains(key));
+ EXPECT_FALSE(map->ContainsMultiple(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), nullptr);
+ EXPECT_EQ(map->GetSlotByName(key, GetTreeScope()), element2);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), element2);
+ map->Remove(key, element2);
+ EXPECT_FALSE(map->Contains(key));
+ EXPECT_FALSE(map->ContainsMultiple(key));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key), nullptr);
+ EXPECT_EQ(map->GetSlotByName(key, GetTreeScope()), nullptr)
+ << "nullptr even though we never removed element2 from the tree";
+}
+
+TEST_F(TreeOrderedMapTest, ManyKeys) {
+ auto* map = MakeGarbageCollected<TreeOrderedMap>();
+ AtomicString key1 = "test1";
+ AtomicString key2 = ""; // Empty should be handled as a unique key
+ auto& element1 = *AddElement(key1);
+ auto& element2 = *AddElement(key1);
+ auto& element3 = *AddElement(key2);
+ auto& element4 = *AddElement(key2);
+ map->Add(key1, element1);
+ map->Add(key1, element2);
+ map->Add(key2, element3);
+ map->Add(key2, element4);
+ EXPECT_TRUE(map->Contains(key1));
+ EXPECT_TRUE(map->Contains(key2));
+ EXPECT_TRUE(map->ContainsMultiple(key1));
+ EXPECT_TRUE(map->ContainsMultiple(key2));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key1), nullptr);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key2), nullptr);
+ EXPECT_EQ(map->GetSlotByName(key1, GetTreeScope()), element1);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key1), element1);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key2), nullptr);
+ EXPECT_EQ(map->GetSlotByName(key2, GetTreeScope()), element3);
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key2), element3);
+ map->Remove(key1, element2);
+ map->Remove(key1, element1);
+ map->Remove(key2, element3);
+ element3.remove();
+ EXPECT_FALSE(map->Contains(key1));
+ EXPECT_TRUE(map->Contains(key2));
+ EXPECT_FALSE(map->ContainsMultiple(key2));
+ EXPECT_EQ(map->GetCachedFirstElementWithoutAccessingNodeTree(key2), nullptr);
+ EXPECT_EQ(map->GetSlotByName(key2, GetTreeScope()), element4);
+}
+
+TEST_F(TreeOrderedMapTest, RemovedDuplicateKeys) {
+ auto* map = MakeGarbageCollected<TreeOrderedMap>();
+ AtomicString key = "test";
+ auto& outer = *AddElement(key);
+ auto& inner = *AddElement(key);
+ outer.appendChild(&inner);
+ map->Add(key, outer);
+ map->Add(key, inner);
+ EXPECT_EQ(map->GetSlotByName(key, GetTreeScope()), outer);
+ EXPECT_TRUE(map->ContainsMultiple(key));
+ outer.remove(); // This removes both elements from the tree
+ EXPECT_TRUE(map->ContainsMultiple(key)) << "We haven't touched the map yet";
+ TreeOrderedMap::RemoveScope tree_remove_scope;
+ map->Remove(key, outer);
+ EXPECT_TRUE(map->Contains(key))
+ << "The map will still contain the entry for inner at this point";
+ EXPECT_FALSE(map->ContainsMultiple(key));
+ EXPECT_EQ(map->GetSlotByName(key, GetTreeScope()), nullptr);
+ EXPECT_FALSE(map->Contains(key))
+ << "The call to GetSlotByName should have cleared the key entirely";
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
index da0e951e56b..a2c60bebcc0 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope.cc
@@ -106,6 +106,8 @@ ScopedStyleResolver& TreeScope::EnsureScopedStyleResolver() {
}
void TreeScope::ClearScopedStyleResolver() {
+ if (scoped_style_resolver_)
+ scoped_style_resolver_->ResetStyle();
scoped_style_resolver_.Clear();
}
@@ -497,7 +499,7 @@ Element* TreeScope::AdjustedFocusedElement() const {
if (!element)
return nullptr;
- if (RootNode().IsInV1ShadowTree()) {
+ if (RootNode().IsInShadowTree()) {
if (Element* retargeted = AdjustedFocusedElementInternal(*element)) {
return (this == &retargeted->GetTreeScope()) ? retargeted : nullptr;
}
@@ -522,12 +524,7 @@ Element* TreeScope::AdjustedElement(const Element& target) const {
const Element* adjusted_target = &target;
for (const Element* ancestor = &target; ancestor;
ancestor = ancestor->OwnerShadowHost()) {
- // This adjustment is done only for V1 shadows, and is skipped for V0 or UA
- // shadows, because .pointerLockElement and .(webkit)fullscreenElement is
- // not available for non-V1 shadow roots.
- // TODO(kochi): Once V0 code is removed, use the same logic as
- // .activeElement for V1.
- if (ancestor->ShadowRootIfV1())
+ if (ancestor->GetShadowRoot())
adjusted_target = ancestor;
if (this == ancestor->GetTreeScope())
return const_cast<Element*>(adjusted_target);
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope.h b/chromium/third_party/blink/renderer/core/dom/tree_scope.h
index be9845962e8..3d63306438e 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope.h
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope.h
@@ -45,6 +45,7 @@ class Element;
class HTMLMapElement;
class HitTestResult;
class IdTargetObserverRegistry;
+class Node;
class SVGTreeScopeResources;
class ScopedStyleResolver;
@@ -150,7 +151,7 @@ class CORE_EXPORT TreeScope : public GarbageCollectedMixin {
protected:
TreeScope(ContainerNode&, Document&);
- TreeScope(Document&);
+ explicit TreeScope(Document&);
virtual ~TreeScope();
void ResetTreeScope();
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
index 2306a678738..46d9415afaf 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter.cc
@@ -99,10 +99,8 @@ void TreeScopeAdopter::MoveShadowTreeToNewDocument(
shadow_root.SetAdoptedStyleSheets(empty_vector);
}
- if (shadow_root.GetType() == ShadowRootType::V0) {
- new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
- } else if (shadow_root.IsV1() && !shadow_root.IsUserAgent()) {
- new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV1);
+ if (!shadow_root.IsUserAgent()) {
+ new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascade);
}
MoveTreeToNewDocument(shadow_root, old_document, new_document);
}
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter_test.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter_test.cc
index 6aaf589502f..eb5bbed00e5 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope_adopter_test.cc
@@ -42,107 +42,5 @@ TEST(TreeScopeAdopterTest, SimpleMove) {
EXPECT_EQ(div2->ownerDocument(), doc1);
}
-TEST(TreeScopeAdopterTest, AdoptV1ShadowRootToV0Document) {
- auto* doc1 = Document::CreateForTest();
- auto* doc2 = Document::CreateForTest();
-
- Element* html1 = doc1->CreateRawElement(html_names::kHTMLTag);
- doc1->AppendChild(html1);
- Element* div1 = doc1->CreateRawElement(html_names::kDivTag);
- html1->AppendChild(div1);
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeNone);
- div1->CreateV0ShadowRootForTesting();
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeV0);
- EXPECT_TRUE(doc1->MayContainV0Shadow());
-
- Element* html2 = doc2->CreateRawElement(html_names::kHTMLTag);
- doc2->AppendChild(html2);
- Element* div2 = doc1->CreateRawElement(html_names::kDivTag);
- html2->AppendChild(div2);
- div2->AttachShadowRootInternal(ShadowRootType::kOpen);
-
- EXPECT_EQ(div1->ownerDocument(), doc1);
- EXPECT_EQ(div2->ownerDocument(), doc2);
-
- TreeScopeAdopter adopter(*div2, *doc1);
- ASSERT_TRUE(adopter.NeedsScopeChange());
-
- adopter.Execute();
- EXPECT_EQ(div1->ownerDocument(), doc1);
- EXPECT_EQ(div2->ownerDocument(), doc1);
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeV1);
- EXPECT_TRUE(doc1->MayContainV0Shadow());
- EXPECT_FALSE(doc2->MayContainV0Shadow());
-}
-
-TEST(TreeScopeAdopterTest, AdoptV0ShadowRootToV1Document) {
- auto* doc1 = Document::CreateForTest();
- auto* doc2 = Document::CreateForTest();
-
- Element* html1 = doc1->CreateRawElement(html_names::kHTMLTag);
- doc1->AppendChild(html1);
- Element* div1 = doc1->CreateRawElement(html_names::kDivTag);
- html1->AppendChild(div1);
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeNone);
- div1->AttachShadowRootInternal(ShadowRootType::kOpen);
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeV1);
- EXPECT_FALSE(doc1->MayContainV0Shadow());
-
- Element* html2 = doc2->CreateRawElement(html_names::kHTMLTag);
- doc2->AppendChild(html2);
- Element* div2 = doc1->CreateRawElement(html_names::kDivTag);
- html2->AppendChild(div2);
- div2->CreateV0ShadowRootForTesting();
-
- EXPECT_EQ(div1->ownerDocument(), doc1);
- EXPECT_EQ(div2->ownerDocument(), doc2);
-
- TreeScopeAdopter adopter(*div2, *doc1);
- ASSERT_TRUE(adopter.NeedsScopeChange());
-
- adopter.Execute();
- EXPECT_EQ(div1->ownerDocument(), doc1);
- EXPECT_EQ(div2->ownerDocument(), doc1);
- EXPECT_EQ(doc1->GetShadowCascadeOrder(),
- ShadowCascadeOrder::kShadowCascadeV1);
- EXPECT_TRUE(doc1->MayContainV0Shadow());
- EXPECT_TRUE(doc2->MayContainV0Shadow());
-}
-
-TEST(TreeScopeAdopterTest, AdoptV0InV1ToNewDocument) {
- auto* old_doc = Document::CreateForTest();
- Element* html = old_doc->CreateRawElement(html_names::kHTMLTag);
- old_doc->AppendChild(html);
- Element* host1 = old_doc->CreateRawElement(html_names::kDivTag);
- html->AppendChild(host1);
- ShadowRoot& shadow_root_v1 =
- host1->AttachShadowRootInternal(ShadowRootType::kOpen);
- Element* host2 = old_doc->CreateRawElement(html_names::kDivTag);
- shadow_root_v1.AppendChild(host2);
- host2->CreateV0ShadowRootForTesting();
-
- // old_doc
- // └── html
- // └── host1
- // └──/shadow-root-v1
- // └── host2
- // └──/shadow-root-v0
- EXPECT_TRUE(old_doc->MayContainV0Shadow());
-
- auto* new_doc = Document::CreateForTest();
- EXPECT_FALSE(new_doc->MayContainV0Shadow());
-
- TreeScopeAdopter adopter(*host1, *new_doc);
- ASSERT_TRUE(adopter.NeedsScopeChange());
- adopter.Execute();
-
- EXPECT_TRUE(old_doc->MayContainV0Shadow());
- EXPECT_TRUE(new_doc->MayContainV0Shadow());
-}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/tree_scope_test.cc b/chromium/third_party/blink/renderer/core/dom/tree_scope_test.cc
index 4dcbf01ee5b..e68c53c8550 100644
--- a/chromium/third_party/blink/renderer/core/dom/tree_scope_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/tree_scope_test.cc
@@ -12,81 +12,96 @@
namespace blink {
-TEST(TreeScopeTest, CommonAncestorOfSameTrees) {
- auto* document = Document::CreateForTest();
- EXPECT_EQ(document, document->CommonAncestorTreeScope(*document));
-
- Element* html = document->CreateRawElement(html_names::kHTMLTag);
- document->AppendChild(html);
- ShadowRoot& shadow_root = html->CreateV0ShadowRootForTesting();
+class TreeScopeTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ document_ = Document::CreateForTest();
+ Element* html = document_->CreateRawElement(html_names::kHTMLTag);
+ document_->AppendChild(html);
+ body_ = document_->CreateRawElement(html_names::kBodyTag);
+ html->AppendChild(body_);
+ }
+ Document* GetDocument() { return document_; }
+ Element* GetBody() { return body_; }
+
+ private:
+ Persistent<Document> document_;
+ Persistent<Element> body_;
+};
+
+TEST_F(TreeScopeTest, CommonAncestorOfSameTrees) {
+ EXPECT_EQ(GetDocument(),
+ GetDocument()->CommonAncestorTreeScope(*GetDocument()));
+ ShadowRoot& shadow_root =
+ GetBody()->AttachShadowRootInternal(ShadowRootType::kOpen);
EXPECT_EQ(shadow_root, shadow_root.CommonAncestorTreeScope(shadow_root));
}
-TEST(TreeScopeTest, CommonAncestorOfInclusiveTrees) {
+TEST_F(TreeScopeTest, CommonAncestorOfInclusiveTrees) {
// document
// | : Common ancestor is document.
// shadowRoot
- auto* document = Document::CreateForTest();
- Element* html = document->CreateRawElement(html_names::kHTMLTag);
- document->AppendChild(html);
- ShadowRoot& shadow_root = html->CreateV0ShadowRootForTesting();
+ ShadowRoot& shadow_root =
+ GetBody()->AttachShadowRootInternal(ShadowRootType::kOpen);
- EXPECT_EQ(document, document->CommonAncestorTreeScope(shadow_root));
- EXPECT_EQ(document, shadow_root.CommonAncestorTreeScope(*document));
+ EXPECT_EQ(GetDocument(), GetDocument()->CommonAncestorTreeScope(shadow_root));
+ EXPECT_EQ(GetDocument(), shadow_root.CommonAncestorTreeScope(*GetDocument()));
}
-TEST(TreeScopeTest, CommonAncestorOfSiblingTrees) {
+TEST_F(TreeScopeTest, CommonAncestorOfSiblingTrees) {
// document
// / \ : Common ancestor is document.
// A B
- auto* document = Document::CreateForTest();
- Element* html = document->CreateRawElement(html_names::kHTMLTag);
- document->AppendChild(html);
- Element* head = document->CreateRawElement(html_names::kHeadTag);
- html->AppendChild(head);
- Element* body = document->CreateRawElement(html_names::kBodyTag);
- html->AppendChild(body);
+ Element* div_a = GetDocument()->CreateRawElement(html_names::kDivTag);
+ GetBody()->AppendChild(div_a);
+ Element* div_b = GetDocument()->CreateRawElement(html_names::kDivTag);
+ GetBody()->AppendChild(div_b);
- ShadowRoot& shadow_root_a = head->CreateV0ShadowRootForTesting();
- ShadowRoot& shadow_root_b = body->CreateV0ShadowRootForTesting();
+ ShadowRoot& shadow_root_a =
+ div_a->AttachShadowRootInternal(ShadowRootType::kOpen);
+ ShadowRoot& shadow_root_b =
+ div_b->AttachShadowRootInternal(ShadowRootType::kOpen);
- EXPECT_EQ(document, shadow_root_a.CommonAncestorTreeScope(shadow_root_b));
- EXPECT_EQ(document, shadow_root_b.CommonAncestorTreeScope(shadow_root_a));
+ EXPECT_EQ(GetDocument(),
+ shadow_root_a.CommonAncestorTreeScope(shadow_root_b));
+ EXPECT_EQ(GetDocument(),
+ shadow_root_b.CommonAncestorTreeScope(shadow_root_a));
}
-TEST(TreeScopeTest, CommonAncestorOfTreesAtDifferentDepths) {
+TEST_F(TreeScopeTest, CommonAncestorOfTreesAtDifferentDepths) {
// document
// / \ : Common ancestor is document.
// Y B
// /
// A
- auto* document = Document::CreateForTest();
- Element* html = document->CreateRawElement(html_names::kHTMLTag);
- document->AppendChild(html);
- Element* head = document->CreateRawElement(html_names::kHeadTag);
- html->AppendChild(head);
- Element* body = document->CreateRawElement(html_names::kBodyTag);
- html->AppendChild(body);
+ Element* div_y = GetDocument()->CreateRawElement(html_names::kDivTag);
+ GetBody()->AppendChild(div_y);
+ Element* div_b = GetDocument()->CreateRawElement(html_names::kDivTag);
+ GetBody()->AppendChild(div_b);
- ShadowRoot& shadow_root_y = head->CreateV0ShadowRootForTesting();
- ShadowRoot& shadow_root_b = body->CreateV0ShadowRootForTesting();
+ ShadowRoot& shadow_root_y =
+ div_y->AttachShadowRootInternal(ShadowRootType::kOpen);
+ ShadowRoot& shadow_root_b =
+ div_b->AttachShadowRootInternal(ShadowRootType::kOpen);
- Element* div_in_y = document->CreateRawElement(html_names::kDivTag);
+ Element* div_in_y = GetDocument()->CreateRawElement(html_names::kDivTag);
shadow_root_y.AppendChild(div_in_y);
- ShadowRoot& shadow_root_a = div_in_y->CreateV0ShadowRootForTesting();
+ ShadowRoot& shadow_root_a =
+ div_in_y->AttachShadowRootInternal(ShadowRootType::kOpen);
- EXPECT_EQ(document, shadow_root_a.CommonAncestorTreeScope(shadow_root_b));
- EXPECT_EQ(document, shadow_root_b.CommonAncestorTreeScope(shadow_root_a));
+ EXPECT_EQ(GetDocument(),
+ shadow_root_a.CommonAncestorTreeScope(shadow_root_b));
+ EXPECT_EQ(GetDocument(),
+ shadow_root_b.CommonAncestorTreeScope(shadow_root_a));
}
-TEST(TreeScopeTest, CommonAncestorOfTreesInDifferentDocuments) {
- auto* document1 = Document::CreateForTest();
+TEST_F(TreeScopeTest, CommonAncestorOfTreesInDifferentDocuments) {
auto* document2 = Document::CreateForTest();
- EXPECT_EQ(nullptr, document1->CommonAncestorTreeScope(*document2));
- EXPECT_EQ(nullptr, document2->CommonAncestorTreeScope(*document1));
+ EXPECT_EQ(nullptr, GetDocument()->CommonAncestorTreeScope(*document2));
+ EXPECT_EQ(nullptr, document2->CommonAncestorTreeScope(*GetDocument()));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc
deleted file mode 100644
index f7e50266302..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-
-#include "third_party/blink/renderer/core/css/style_change_reason.h"
-#include "third_party/blink/renderer/core/dom/element_traversal.h"
-#include "third_party/blink/renderer/core/dom/qualified_name.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
-#include "third_party/blink/renderer/core/dom/static_node_list.h"
-#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
-#include "third_party/blink/renderer/core/html_names.h"
-
-namespace blink {
-
-V0InsertionPoint::V0InsertionPoint(const QualifiedName& tag_name,
- Document& document)
- : HTMLElement(tag_name, document, kCreateV0InsertionPoint),
- registered_with_shadow_root_(false) {
-}
-
-V0InsertionPoint::~V0InsertionPoint() = default;
-
-void V0InsertionPoint::SetDistributedNodes(
- DistributedNodes& distributed_nodes) {
- // Attempt not to reattach nodes that would be distributed to the exact same
- // location by comparing the old and new distributions.
-
- if (DistributedNodesAreFallback() && distributed_nodes.size() &&
- distributed_nodes.at(0)->parentNode() != this) {
- // Detach fallback nodes. Host children which are no longer distributed are
- // detached in the DistributionPool destructor.
- for (wtf_size_t i = 0; i < distributed_nodes_.size(); ++i)
- distributed_nodes_.at(i)->RemovedFromFlatTree();
- distributed_nodes_.Clear();
- }
-
- wtf_size_t i = 0;
- wtf_size_t j = 0;
-
- for (; i < distributed_nodes_.size() && j < distributed_nodes.size();
- ++i, ++j) {
- if (distributed_nodes_.size() < distributed_nodes.size()) {
- // If the new distribution is larger than the old one, notify all nodes in
- // the new distribution that were inserted.
- for (; j < distributed_nodes.size() &&
- distributed_nodes_.at(i) != distributed_nodes.at(j);
- ++j)
- distributed_nodes.at(j)->FlatTreeParentChanged();
- if (j == distributed_nodes.size())
- break;
- } else if (distributed_nodes_.size() > distributed_nodes.size()) {
- // If the old distribution is larger than the new one, skip all nodes in
- // the old distribution that were removed.
- while (i < distributed_nodes_.size() &&
- distributed_nodes_.at(i) != distributed_nodes.at(j))
- ++i;
- if (i == distributed_nodes_.size())
- break;
- } else if (distributed_nodes_.at(i) != distributed_nodes.at(j)) {
- // If both distributions are the same length notify the new.
- distributed_nodes.at(j)->FlatTreeParentChanged();
- }
- }
-
- // If we hit the end of either list above we need to notify all remaining
- // nodes in the new distribution.
-
- for (; j < distributed_nodes.size(); ++j)
- distributed_nodes.at(j)->FlatTreeParentChanged();
-
- distributed_nodes_.Swap(distributed_nodes);
- // Deallocate a Vector and a HashMap explicitly so that
- // Oilpan can recycle them without an intervening GC.
- distributed_nodes.Clear();
- distributed_nodes_.ShrinkToFit();
-}
-
-void V0InsertionPoint::AttachLayoutTree(AttachContext& context) {
- // If the distributed children are the direct fallback children they are
- // attached in ContainerNodes::AttachLayoutTree() via the base class call
- // below.
- if (!DistributedNodesAreFallback()) {
- AttachContext children_context(context);
- for (wtf_size_t i = 0; i < distributed_nodes_.size(); ++i)
- distributed_nodes_.at(i)->AttachLayoutTree(children_context);
- if (children_context.previous_in_flow)
- context.previous_in_flow = children_context.previous_in_flow;
- }
- HTMLElement::AttachLayoutTree(context);
-}
-
-void V0InsertionPoint::DetachLayoutTree(bool performing_reattach) {
- for (wtf_size_t i = 0; i < distributed_nodes_.size(); ++i)
- distributed_nodes_.at(i)->DetachLayoutTree(performing_reattach);
-
- HTMLElement::DetachLayoutTree(performing_reattach);
-}
-
-void V0InsertionPoint::RebuildDistributedChildrenLayoutTrees(
- WhitespaceAttacher& whitespace_attacher) {
- // This loop traverses the nodes from right to left for the same reason as the
- // one described in ContainerNode::RebuildChildrenLayoutTrees().
- for (wtf_size_t i = distributed_nodes_.size(); i > 0; --i) {
- RebuildLayoutTreeForChild(distributed_nodes_.at(i - 1),
- whitespace_attacher);
- }
-}
-
-void V0InsertionPoint::RecalcStyleForInsertionPointChildren(
- const StyleRecalcChange change) {
- for (wtf_size_t i = 0; i < distributed_nodes_.size(); ++i) {
- Node* node = distributed_nodes_.at(i);
- if (!change.TraverseChild(*node))
- continue;
- if (auto* this_element = DynamicTo<Element>(node))
- this_element->RecalcStyle(change);
- else if (auto* text_node = DynamicTo<Text>(node))
- text_node->RecalcTextStyle(change);
- }
-}
-
-bool V0InsertionPoint::CanBeActive() const {
- ShadowRoot* shadow_root = ContainingShadowRoot();
- if (!shadow_root)
- return false;
- if (shadow_root->IsV1())
- return false;
- return !Traversal<V0InsertionPoint>::FirstAncestor(*this);
-}
-
-bool V0InsertionPoint::IsActive() const {
- if (!CanBeActive())
- return false;
- ShadowRoot* shadow_root = ContainingShadowRoot();
- DCHECK(shadow_root);
- if (!IsA<HTMLShadowElement>(*this) ||
- shadow_root->V0().DescendantShadowElementCount() <= 1)
- return true;
-
- // Slow path only when there are more than one shadow elements in a shadow
- // tree. That should be a rare case.
- for (const auto& point : shadow_root->V0().DescendantInsertionPoints()) {
- if (IsA<HTMLShadowElement>(*point))
- return point == this;
- }
- return true;
-}
-
-bool V0InsertionPoint::IsContentInsertionPoint() const {
- return IsA<HTMLContentElement>(*this) && IsActive();
-}
-
-StaticNodeList* V0InsertionPoint::getDistributedNodes() {
- UpdateDistributionForLegacyDistributedNodes();
-
- HeapVector<Member<Node>> nodes;
- nodes.ReserveInitialCapacity(distributed_nodes_.size());
- for (wtf_size_t i = 0; i < distributed_nodes_.size(); ++i)
- nodes.UncheckedAppend(distributed_nodes_.at(i));
-
- return StaticNodeList::Adopt(nodes);
-}
-
-bool V0InsertionPoint::LayoutObjectIsNeeded(const ComputedStyle& style) const {
- return !IsActive() && HTMLElement::LayoutObjectIsNeeded(style);
-}
-
-void V0InsertionPoint::ChildrenChanged(const ChildrenChange& change) {
- HTMLElement::ChildrenChanged(change);
- if (ShadowRoot* root = ContainingShadowRoot()) {
- if (!root->IsV1())
- root->SetNeedsDistributionRecalc();
- }
-}
-
-Node::InsertionNotificationRequest V0InsertionPoint::InsertedInto(
- ContainerNode& insertion_point) {
- HTMLElement::InsertedInto(insertion_point);
- if (ShadowRoot* root = ContainingShadowRoot()) {
- if (!root->IsV1()) {
- root->SetNeedsDistributionRecalc();
- if (CanBeActive() && !registered_with_shadow_root_ &&
- insertion_point.GetTreeScope().RootNode() == root) {
- registered_with_shadow_root_ = true;
- root->V0().DidAddInsertionPoint(this);
- if (CanAffectSelector())
- root->V0().WillAffectSelector();
- }
- }
- }
-
- // We could have been distributed into in a detached subtree, make sure to
- // clear the distribution when inserted again to avoid cycles.
- ClearDistribution();
-
- return kInsertionDone;
-}
-
-void V0InsertionPoint::RemovedFrom(ContainerNode& insertion_point) {
- ShadowRoot* root = ContainingShadowRoot();
- if (!root)
- root = insertion_point.ContainingShadowRoot();
-
- if (root && !root->IsV1())
- root->SetNeedsDistributionRecalc();
-
- // Since this insertion point is no longer visible from the shadow subtree, it
- // need to clean itself up.
- ClearDistribution();
-
- if (registered_with_shadow_root_ &&
- insertion_point.GetTreeScope().RootNode() == root) {
- DCHECK(root);
- registered_with_shadow_root_ = false;
- root->V0().DidRemoveInsertionPoint(this);
- if (!root->IsV1() && CanAffectSelector())
- root->V0().WillAffectSelector();
- }
-
- HTMLElement::RemovedFrom(insertion_point);
-}
-
-void V0InsertionPoint::Trace(Visitor* visitor) const {
- visitor->Trace(distributed_nodes_);
- HTMLElement::Trace(visitor);
-}
-
-const V0InsertionPoint* ResolveReprojection(const Node* projected_node) {
- DCHECK(projected_node);
- const V0InsertionPoint* insertion_point = nullptr;
- const Node* current = projected_node;
- ShadowRoot* last_shadow_root = nullptr;
- while (true) {
- ShadowRoot* shadow_root =
- ShadowRootWhereNodeCanBeDistributedForV0(*current);
- if (!shadow_root || shadow_root->IsV1() || shadow_root == last_shadow_root)
- break;
- last_shadow_root = shadow_root;
- const V0InsertionPoint* inserted_to =
- shadow_root->V0().FinalDestinationInsertionPointFor(projected_node);
- if (!inserted_to)
- break;
- DCHECK_NE(current, inserted_to);
- current = inserted_to;
- insertion_point = inserted_to;
- }
- return insertion_point;
-}
-
-void CollectDestinationInsertionPoints(
- const Node& node,
- HeapVector<Member<V0InsertionPoint>, 8>& results) {
- const Node* current = &node;
- ShadowRoot* last_shadow_root = nullptr;
- while (true) {
- ShadowRoot* shadow_root =
- ShadowRootWhereNodeCanBeDistributedForV0(*current);
- if (!shadow_root || shadow_root->IsV1() || shadow_root == last_shadow_root)
- return;
- last_shadow_root = shadow_root;
- const DestinationInsertionPoints* insertion_points =
- shadow_root->V0().DestinationInsertionPointsFor(&node);
- if (!insertion_points)
- return;
- for (wtf_size_t i = 0; i < insertion_points->size(); ++i)
- results.push_back(insertion_points->at(i).Get());
- DCHECK_NE(current, insertion_points->back().Get());
- current = insertion_points->back().Get();
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h b/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h
deleted file mode 100644
index b7375fb9de9..00000000000
--- a/chromium/third_party/blink/renderer/core/dom/v0_insertion_point.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_V0_INSERTION_POINT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_V0_INSERTION_POINT_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/css_selector_list.h"
-#include "third_party/blink/renderer/core/dom/distributed_nodes.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-
-namespace blink {
-
-class CORE_EXPORT V0InsertionPoint : public HTMLElement {
- public:
- ~V0InsertionPoint() override;
-
- bool HasDistribution() const { return !distributed_nodes_.IsEmpty(); }
- void SetDistributedNodes(DistributedNodes&);
- void ClearDistribution() { distributed_nodes_.Clear(); }
- bool IsActive() const;
- bool CanBeActive() const;
-
- bool IsContentInsertionPoint() const;
-
- StaticNodeList* getDistributedNodes();
-
- virtual bool CanAffectSelector() const { return false; }
-
- void AttachLayoutTree(AttachContext&) override;
- void DetachLayoutTree(bool performing_reattach) override;
- void RebuildDistributedChildrenLayoutTrees(WhitespaceAttacher&);
-
- size_t DistributedNodesSize() const { return distributed_nodes_.size(); }
- Node* DistributedNodeAt(wtf_size_t index) const {
- return distributed_nodes_.at(index);
- }
- Node* FirstDistributedNode() const {
- return distributed_nodes_.IsEmpty() ? nullptr : distributed_nodes_.First();
- }
- Node* LastDistributedNode() const {
- return distributed_nodes_.IsEmpty() ? nullptr : distributed_nodes_.Last();
- }
- Node* DistributedNodeNextTo(const Node* node) const {
- return distributed_nodes_.NextTo(node);
- }
- Node* DistributedNodePreviousTo(const Node* node) const {
- return distributed_nodes_.PreviousTo(node);
- }
- bool DistributedNodesAreFallback() const {
- // We either do not have distributed children or the distributed children
- // are the fallback children.
- return !HasDistribution() || DistributedNodeAt(0)->parentNode() == this;
- }
-
- void RecalcStyleForInsertionPointChildren(const StyleRecalcChange);
-
- void Trace(Visitor*) const override;
-
- protected:
- V0InsertionPoint(const QualifiedName&, Document&);
- bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
- void ChildrenChanged(const ChildrenChange&) override;
- InsertionNotificationRequest InsertedInto(ContainerNode&) override;
- void RemovedFrom(ContainerNode&) override;
-
- private:
- bool IsV0InsertionPoint() const =
- delete; // This will catch anyone doing an unnecessary check.
-
- DistributedNodes distributed_nodes_;
- bool registered_with_shadow_root_;
-};
-
-using DestinationInsertionPoints = HeapVector<Member<V0InsertionPoint>, 1>;
-
-inline bool IsActiveV0InsertionPoint(const Node& node) {
- auto* insertion_point = DynamicTo<V0InsertionPoint>(node);
- return insertion_point && insertion_point->IsActive();
-}
-
-inline ShadowRoot* ShadowRootWhereNodeCanBeDistributedForV0(const Node& node) {
- Node* parent = node.parentNode();
- if (!parent)
- return nullptr;
- if (IsActiveV0InsertionPoint(*parent))
- return node.ContainingShadowRoot();
- if (auto* parent_element = DynamicTo<Element>(parent))
- return parent_element->GetShadowRoot();
- return nullptr;
-}
-
-const V0InsertionPoint* ResolveReprojection(const Node*);
-
-void CollectDestinationInsertionPoints(
- const Node&,
- HeapVector<Member<V0InsertionPoint>, 8>& results);
-
-template <>
-inline bool IsElementOfType<const V0InsertionPoint>(const Node& node) {
- return node.IsV0InsertionPoint();
-}
-
-template <>
-struct DowncastTraits<V0InsertionPoint> {
- static bool AllowFrom(const Node& node) { return node.IsV0InsertionPoint(); }
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_V0_INSERTION_POINT_H_
diff --git a/chromium/third_party/blink/renderer/core/dom/whitespace_attacher.h b/chromium/third_party/blink/renderer/core/dom/whitespace_attacher.h
index 15563dee305..98054fd000e 100644
--- a/chromium/third_party/blink/renderer/core/dom/whitespace_attacher.h
+++ b/chromium/third_party/blink/renderer/core/dom/whitespace_attacher.h
@@ -12,6 +12,7 @@ namespace blink {
class Element;
class LayoutObject;
+class Node;
class Text;
// The WhitespaceAttacher is used during the layout tree rebuild to lazily re-
diff --git a/chromium/third_party/blink/renderer/core/dom/whitespace_attacher_test.cc b/chromium/third_party/blink/renderer/core/dom/whitespace_attacher_test.cc
index f4ffb1b13a5..e4d22036b68 100644
--- a/chromium/third_party/blink/renderer/core/dom/whitespace_attacher_test.cc
+++ b/chromium/third_party/blink/renderer/core/dom/whitespace_attacher_test.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
diff --git a/chromium/third_party/blink/renderer/core/editing/DIR_METADATA b/chromium/third_party/blink/renderer/core/editing/DIR_METADATA
new file mode 100644
index 00000000000..eba1b424d58
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Editing"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/editing/OWNERS b/chromium/third_party/blink/renderer/core/editing/OWNERS
index 9dae515cb22..72b76e7048c 100644
--- a/chromium/third_party/blink/renderer/core/editing/OWNERS
+++ b/chromium/third_party/blink/renderer/core/editing/OWNERS
@@ -1,8 +1,2 @@
yosin@chromium.org
xiaochengh@chromium.org
-
-# IME-related changes
-changwan@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Editing
diff --git a/chromium/third_party/blink/renderer/core/editing/build.gni b/chromium/third_party/blink/renderer/core/editing/build.gni
index 8243e4d31b3..0ada2a056c0 100644
--- a/chromium/third_party/blink/renderer/core/editing/build.gni
+++ b/chromium/third_party/blink/renderer/core/editing/build.gni
@@ -128,8 +128,13 @@ blink_core_sources_editing = [
"element_inner_text.cc",
"ephemeral_range.cc",
"ephemeral_range.h",
+ "finder/async_find_buffer.cc",
+ "finder/async_find_buffer.h",
+ "finder/sync_find_buffer.cc",
+ "finder/sync_find_buffer.h",
"finder/find_buffer.cc",
"finder/find_buffer.h",
+ "finder/find_buffer_runner.h",
"finder/find_in_page_coordinates.cc",
"finder/find_in_page_coordinates.h",
"finder/find_task_controller.cc",
@@ -246,6 +251,8 @@ blink_core_sources_editing = [
"position_iterator.h",
"position_with_affinity.cc",
"position_with_affinity.h",
+ "range_in_flat_tree.cc",
+ "range_in_flat_tree.h",
"relocatable_position.cc",
"relocatable_position.h",
"reveal_selection_scope.cc",
@@ -262,7 +269,6 @@ blink_core_sources_editing = [
"selection_strategy.h",
"selection_template.cc",
"selection_template.h",
- "selection_type.h",
"serializers/create_markup_options.cc",
"serializers/create_markup_options.h",
"serializers/html_interchange.cc",
diff --git a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index a7eb770326b..9c4dac7c737 100644
--- a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -238,6 +238,23 @@ void CaretDisplayItemClient::PaintCaret(
DarkModeFilter::ElementRole::kText);
}
+void CaretDisplayItemClient::RecordSelection(
+ GraphicsContext& context,
+ const PhysicalOffset& paint_offset) {
+ PhysicalRect drawing_rect = local_rect_;
+ drawing_rect.Move(paint_offset);
+ IntRect paint_rect = PixelSnappedIntRect(drawing_rect);
+
+ // For the caret, the start and selection selection bounds are recorded as
+ // the same edges, with the type marked as CENTER.
+ PaintedSelectionBound start = {gfx::SelectionBound::Type::CENTER,
+ paint_rect.MinXMinYCorner(),
+ paint_rect.MinXMaxYCorner(), false};
+ PaintedSelectionBound end = start;
+
+ context.GetPaintController().RecordSelection(start, end);
+}
+
String CaretDisplayItemClient::DebugName() const {
return "Caret";
}
diff --git a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.h b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.h
index eb9b8e1e0e9..91553d3a785 100644
--- a/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.h
+++ b/chromium/third_party/blink/renderer/core/editing/caret_display_item_client.h
@@ -66,6 +66,8 @@ class CORE_EXPORT CaretDisplayItemClient final : public DisplayItemClient {
const PhysicalOffset& paint_offset,
DisplayItem::Type) const;
+ void RecordSelection(GraphicsContext&, const PhysicalOffset& paint_offset);
+
// DisplayItemClient.
String DebugName() const final;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command.cc
index 81a99ce7a41..c4016e94a39 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command.cc
@@ -103,6 +103,21 @@ void ApplyBlockElementCommand::DoApply(EditingState* editing_state) {
ContainerNode* end_scope = nullptr;
int end_index = IndexForVisiblePosition(end_of_selection, end_scope);
+ // Due to visible position canonicalization, start and end positions could
+ // move to different selection contexts one of which could be inside an
+ // element that is not editable. e.g. <pre contenteditable>
+ // hello^
+ // <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
+ // <foreignObject x="20" y="20" width="80" height="80">
+ // L|orem
+ // </foreignObject>
+ // </svg>
+ // </pre>
+ if (!IsEditablePosition(start_of_selection.DeepEquivalent()) ||
+ !IsEditablePosition(end_of_selection.DeepEquivalent())) {
+ return;
+ }
+
FormatSelection(start_of_selection, end_of_selection, editing_state);
if (editing_state->IsAborted())
return;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
index 0e5736dcc45..1886137fb81 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -50,6 +51,9 @@ TEST_F(ApplyBlockElementCommandTest, selectionCrossingOverBody) {
command->Apply();
EXPECT_EQ(
+ "<head>"
+ "<style> .CLASS13 { -webkit-user-modify: read-write; }</style>"
+ "</head>foo"
"<body contenteditable=\"false\">\n"
"<pre><var id=\"va\" class=\"CLASS13\">\nC\n</var></pre><input></body>",
GetDocument().documentElement()->innerHTML());
@@ -139,9 +143,10 @@ TEST_F(ApplyBlockElementCommandTest, FormatBlockCrossingUserModifyBoundary) {
auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
html_names::kPreTag);
// Shouldn't crash here.
- EXPECT_FALSE(command->Apply());
+ EXPECT_TRUE(command->Apply());
EXPECT_EQ(
- "^<b style=\"-webkit-user-modify:read-only\"><button>|</button></b>",
+ "<pre>|<br></pre>"
+ "<b style=\"-webkit-user-modify:read-only\"><button></button></b>",
GetSelectionTextFromBody());
}
@@ -165,4 +170,48 @@ TEST_F(ApplyBlockElementCommandTest,
GetSelectionTextFromBody());
}
+// https://crbug.com/1172656
+TEST_F(ApplyBlockElementCommandTest, FormatBlockWithDirectChildrenOfRoot) {
+ GetDocument().setDesignMode("on");
+ DocumentFragment* fragment = DocumentFragment::Create(GetDocument());
+ Element* root = GetDocument().documentElement();
+ fragment->ParseXML("a<div>b</div>c", root);
+ root->setTextContent("");
+ root->appendChild(fragment);
+ UpdateAllLifecyclePhasesForTest();
+
+ Selection().SetSelection(
+ SelectionInDOMTree::Builder().SelectAllChildren(*root).Build(),
+ SetSelectionOptions());
+ auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
+ html_names::kPreTag);
+ // Shouldn't crash here.
+ EXPECT_FALSE(command->Apply());
+ const SelectionInDOMTree& selection = Selection().GetSelectionInDOMTree();
+ EXPECT_EQ("^a<div>b</div>c|",
+ SelectionSample::GetSelectionText(*root, selection));
+}
+
+// This is a regression test for https://crbug.com/1180699
+TEST_F(ApplyBlockElementCommandTest, OutdentEmptyBlockquote) {
+ Vector<std::string> selection_texts = {
+ "<blockquote style='padding:5px'>|</blockquote>",
+ "a<blockquote style='padding:5px'>|</blockquote>",
+ "<blockquote style='padding:5px'>|</blockquote>b",
+ "a<blockquote style='padding:5px'>|</blockquote>b"};
+ Vector<std::string> expectations = {"|", "a|<br>", "|<br>b", "a<br>|b"};
+
+ GetDocument().setDesignMode("on");
+ for (unsigned i = 0; i < selection_texts.size(); ++i) {
+ Selection().SetSelection(SetSelectionTextToBody(selection_texts[i]),
+ SetSelectionOptions());
+ auto* command = MakeGarbageCollected<IndentOutdentCommand>(
+ GetDocument(), IndentOutdentCommand::kOutdent);
+
+ // Shouldn't crash here.
+ command->Apply();
+ EXPECT_EQ(expectations[i], GetSelectionTextFromBody());
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
index 1dbbc0abfdf..7fb6484451c 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/editing/plain_text_range.h"
+#include "third_party/blink/renderer/core/editing/relocatable_position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
@@ -289,16 +290,22 @@ void ApplyStyleCommand::ApplyBlockStyle(EditingStyle* style,
const int end_index = TextIterator::RangeLength(end_range, behavior);
VisiblePosition paragraph_start(StartOfParagraph(visible_start));
- VisiblePosition next_paragraph_start(
- NextPositionOf(EndOfParagraph(paragraph_start)));
Position beyond_end =
NextPositionOf(EndOfParagraph(visible_end)).DeepEquivalent();
- // TODO(editing-dev): Use a saner approach (e.g., temporary Ranges) to keep
- // these positions in document instead of iteratively performing orphan checks
- // and recalculating them when they become orphans.
- while (paragraph_start.IsNotNull() &&
- paragraph_start.DeepEquivalent() != beyond_end) {
- DCHECK(!paragraph_start.IsOrphan()) << paragraph_start;
+ while (
+ paragraph_start.IsNotNull() &&
+ (beyond_end.IsNull() || paragraph_start.DeepEquivalent() < beyond_end)) {
+ DCHECK(paragraph_start.IsValidFor(GetDocument())) << paragraph_start;
+ RelocatablePosition next_paragraph_start(
+ NextPositionOf(EndOfParagraph(paragraph_start)).DeepEquivalent());
+ // RelocatablePosition turns the position into ParentAnchoredEquivalent(),
+ // which can affect the result of CreateVisiblePosition().
+ // To avoid an infinite loop, reconvert into a VisiblePosition and check
+ // that it's after the current paragraph_start.
+ bool will_advance =
+ next_paragraph_start.GetPosition().IsNull() ||
+ CreateVisiblePosition(next_paragraph_start.GetPosition())
+ .DeepEquivalent() > paragraph_start.DeepEquivalent();
StyleChange style_change(style, paragraph_start.DeepEquivalent());
if (style_change.CssStyle().length() || remove_only_) {
Element* block =
@@ -310,47 +317,23 @@ void ApplyStyleCommand::ApplyBlockStyle(EditingStyle* style,
paragraph_start_to_move, editing_state);
if (editing_state->IsAborted())
return;
- if (new_block) {
+ if (new_block)
block = new_block;
- if (paragraph_start.IsOrphan()) {
- GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
- paragraph_start = CreateVisiblePosition(
- Position::FirstPositionInNode(*new_block));
- }
- }
- DCHECK(!paragraph_start.IsOrphan()) << paragraph_start;
}
if (auto* html_element = DynamicTo<HTMLElement>(block)) {
RemoveCSSStyle(style, html_element, editing_state);
if (editing_state->IsAborted())
return;
- DCHECK(!paragraph_start.IsOrphan()) << paragraph_start;
- if (!remove_only_) {
+ if (!remove_only_)
AddBlockStyle(style_change, html_element);
- DCHECK(!paragraph_start.IsOrphan()) << paragraph_start;
- }
}
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
-
- // Make the VisiblePositions valid again after style changes.
- // TODO(editing-dev): We shouldn't store VisiblePositions and inspect
- // their properties after they have been invalidated by mutations. See
- // crbug.com/648949 for details.
- DCHECK(!paragraph_start.IsOrphan()) << paragraph_start;
- paragraph_start =
- CreateVisiblePosition(paragraph_start.ToPositionWithAffinity());
- if (next_paragraph_start.IsOrphan()) {
- next_paragraph_start = NextPositionOf(EndOfParagraph(paragraph_start));
- } else {
- next_paragraph_start = CreateVisiblePosition(
- next_paragraph_start.ToPositionWithAffinity());
- }
}
- DCHECK(!next_paragraph_start.IsOrphan()) << next_paragraph_start;
- paragraph_start = next_paragraph_start;
- next_paragraph_start = NextPositionOf(EndOfParagraph(paragraph_start));
+ if (!will_advance)
+ break;
+ paragraph_start = CreateVisiblePosition(next_paragraph_start.GetPosition());
}
// Update style and layout again, since added or removed styles could have
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
index 1c567cf58ca..77066774706 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
@@ -103,4 +103,35 @@ TEST_F(ApplyStyleCommandTest, FontSizeDeltaWithSpanElement) {
EXPECT_EQ("<div contenteditable><div></div><span>^a|</span></div>",
GetSelectionTextFromBody());
}
+
+// This is a regression test for https://crbug.com/1172007
+TEST_F(ApplyStyleCommandTest, JustifyRightWithSVGForeignObject) {
+ GetDocument().setDesignMode("on");
+ Selection().SetSelection(
+ SetSelectionTextToBody("<svg>"
+ "<foreignObject>1</foreignObject>"
+ "<foreignObject>&#x20;2^<b></b>|</foreignObject>"
+ "</svg>"),
+ SetSelectionOptions());
+
+ auto* style = MakeGarbageCollected<MutableCSSPropertyValueSet>(kUASheetMode);
+ style->SetProperty(CSSPropertyID::kTextAlign, "right",
+ /* important */ false,
+ GetFrame().DomWindow()->GetSecureContextMode());
+ MakeGarbageCollected<ApplyStyleCommand>(
+ GetDocument(), MakeGarbageCollected<EditingStyle>(style),
+ InputEvent::InputType::kFormatJustifyRight,
+ ApplyStyleCommand::kForceBlockProperties)
+ ->Apply();
+ EXPECT_EQ(
+ "<svg>"
+ "<foreignObject>"
+ "<div style=\"text-align: right;\">|1</div>"
+ "</foreignObject>"
+ "<foreignObject>"
+ "<div style=\"text-align: right;\">2</div><b></b>"
+ "</foreignObject>"
+ "</svg>",
+ GetSelectionTextFromBody());
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
index 1fc6accee82..9c0d976d657 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
@@ -606,7 +606,6 @@ Position CompositeEditCommand::PositionOutsideTabSpan(const Position& pos) {
return pos;
switch (pos.AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
case PositionAnchorType::kAfterChildren:
NOTREACHED();
return pos;
@@ -1138,6 +1137,8 @@ HTMLElement* CompositeEditCommand::MoveParagraphContentsToNewBlockIfNecessary(
visible_pos = CreateVisiblePosition(pos);
visible_paragraph_start = StartOfParagraph(visible_pos);
visible_paragraph_end = EndOfParagraph(visible_pos);
+ DCHECK_LE(visible_paragraph_start.DeepEquivalent(),
+ visible_paragraph_end.DeepEquivalent());
MoveParagraphs(visible_paragraph_start, visible_paragraph_end, destination,
editing_state);
if (editing_state->IsAborted())
@@ -1504,13 +1505,19 @@ void CompositeEditCommand::MoveParagraphs(
NextPositionOf(end_of_paragraph_to_move, kCannotCrossEditingBoundary)
.DeepEquivalent());
+ const Position& start_candidate = start_of_paragraph_to_move.DeepEquivalent();
+ const Position& end_candidate = end_of_paragraph_to_move.DeepEquivalent();
+ DCHECK_LE(start_candidate, end_candidate);
+
// We upstream() the end and downstream() the start so that we don't include
// collapsed whitespace in the move. When we paste a fragment, spaces after
// the end and before the start are treated as though they were rendered.
+ bool equal = start_candidate == end_candidate;
Position start =
- MostForwardCaretPosition(start_of_paragraph_to_move.DeepEquivalent());
+ equal ? start_candidate : MostForwardCaretPosition(start_candidate);
Position end =
- MostBackwardCaretPosition(end_of_paragraph_to_move.DeepEquivalent());
+ equal ? end_candidate : MostBackwardCaretPosition(end_candidate);
+ DCHECK_LE(start, end);
// FIXME: This is an inefficient way to preserve style on nodes in the
// paragraph to move. It shouldn't matter though, since moved paragraphs will
@@ -1906,8 +1913,10 @@ Position CompositeEditCommand::PositionAvoidingSpecialElementBoundary(
if (visible_pos.DeepEquivalent() == last_in_anchor.DeepEquivalent()) {
// Make sure anchors are pushed down before avoiding them so that we don't
// also avoid structural elements like lists and blocks (5142012).
- if (original.AnchorNode() != enclosing_anchor &&
- original.AnchorNode()->parentNode() != enclosing_anchor) {
+ Element* enclosing_block = EnclosingBlock(original.AnchorNode());
+ if (enclosing_block &&
+ enclosing_block->IsDescendantOf(enclosing_anchor)) {
+ // Only push down anchor element if there are block elements inside it.
PushAnchorElementDown(enclosing_anchor, editing_state);
if (editing_state->IsAborted())
return original;
@@ -1935,8 +1944,10 @@ Position CompositeEditCommand::PositionAvoidingSpecialElementBoundary(
if (visible_pos.DeepEquivalent() == first_in_anchor.DeepEquivalent()) {
// Make sure anchors are pushed down before avoiding them so that we don't
// also avoid structural elements like lists and blocks (5142012).
- if (original.AnchorNode() != enclosing_anchor &&
- original.AnchorNode()->parentNode() != enclosing_anchor) {
+ Element* enclosing_block = EnclosingBlock(original.AnchorNode());
+ if (enclosing_block &&
+ enclosing_block->IsDescendantOf(enclosing_anchor)) {
+ // Only push down anchor element if there are block elements inside it.
PushAnchorElementDown(enclosing_anchor, editing_state);
if (editing_state->IsAborted())
return original;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
index 760a475e3ae..6bc2c26118c 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/composite_edit_command_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
namespace blink {
@@ -142,6 +143,58 @@ TEST_F(CompositeEditCommandTest,
body->innerHTML());
}
+TEST_F(CompositeEditCommandTest,
+ MoveParagraphContentsToNewBlockWithUAShadowDOM1) {
+ SetBodyContent("<object contenteditable><input></object>");
+ base::RunLoop().RunUntilIdle();
+
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
+ Element* input = GetDocument().QuerySelector("input");
+ Position pos = Position::BeforeNode(*input);
+ EditingState editing_state;
+
+ // Should not crash
+ sample.MoveParagraphContentsToNewBlockIfNecessary(pos, &editing_state);
+ EXPECT_FALSE(editing_state.IsAborted());
+ EXPECT_EQ("<object contenteditable=\"\"><div><input></div></object>",
+ GetDocument().body()->innerHTML());
+}
+
+TEST_F(CompositeEditCommandTest,
+ MoveParagraphContentsToNewBlockWithUAShadowDOM2) {
+ GetDocument().setDesignMode("on");
+ SetBodyContent("<span></span><button><meter></meter></button>");
+
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
+ Element* button = GetDocument().QuerySelector("button");
+ Position pos = Position(button, 0);
+ EditingState editing_state;
+
+ // Should not crash
+ sample.MoveParagraphContentsToNewBlockIfNecessary(pos, &editing_state);
+ EXPECT_FALSE(editing_state.IsAborted());
+ EXPECT_EQ("<div></div><span></span><button><meter></meter></button>",
+ GetDocument().body()->innerHTML());
+}
+
+TEST_F(CompositeEditCommandTest,
+ MoveParagraphContentsToNewBlockWithButtonAndBr) {
+ GetDocument().setDesignMode("on");
+ InsertStyleElement("br { content: 'x'; }");
+ SetBodyContent("<button><br></button>");
+
+ SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
+ Element* button = GetDocument().QuerySelector("button");
+ Position pos = Position(button, 0);
+ EditingState editing_state;
+
+ // Should not crash
+ sample.MoveParagraphContentsToNewBlockIfNecessary(pos, &editing_state);
+ EXPECT_FALSE(editing_state.IsAborted());
+ EXPECT_EQ("<button><div><br></div><br></button>",
+ GetDocument().body()->innerHTML());
+}
+
TEST_F(CompositeEditCommandTest, InsertNodeOnDisconnectedParent) {
SetBodyContent("<p><b></b></p>");
SampleCommand& sample = *MakeGarbageCollected<SampleCommand>(GetDocument());
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc
index cbd87e87e9d..c39329c1d30 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc
@@ -837,23 +837,20 @@ void DeleteSelectionCommand::MergeParagraphs(EditingState* editing_state) {
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
- VisiblePosition start_of_paragraph_to_move =
- CreateVisiblePosition(downstream_end_);
+ VisiblePosition merge_origin = CreateVisiblePosition(downstream_end_);
VisiblePosition merge_destination = CreateVisiblePosition(upstream_start_);
// downstream_end_'s block has been emptied out by deletion. There is no
// content inside of it to move, so just remove it.
Element* end_block = EnclosingBlock(downstream_end_.AnchorNode());
if (!end_block ||
- !end_block->contains(
- start_of_paragraph_to_move.DeepEquivalent().AnchorNode()) ||
- !start_of_paragraph_to_move.DeepEquivalent().AnchorNode()) {
+ !end_block->contains(merge_origin.DeepEquivalent().AnchorNode()) ||
+ !merge_origin.DeepEquivalent().AnchorNode()) {
RemoveNode(EnclosingBlock(downstream_end_.AnchorNode()), editing_state);
return;
}
- RelocatablePosition relocatable_start(
- start_of_paragraph_to_move.DeepEquivalent());
+ RelocatablePosition relocatable_start(merge_origin.DeepEquivalent());
// We need to merge into upstream_start_'s block, but it's been emptied out
// and collapsed by deletion.
@@ -863,24 +860,22 @@ void DeleteSelectionCommand::MergeParagraphs(EditingState* editing_state) {
(!merge_destination.DeepEquivalent().AnchorNode()->hasChildren() ||
!upstream_start_.ComputeContainerNode()->hasChildren())) ||
(starts_at_empty_line_ &&
- merge_destination.DeepEquivalent() !=
- start_of_paragraph_to_move.DeepEquivalent())) {
+ merge_destination.DeepEquivalent() != merge_origin.DeepEquivalent())) {
InsertNodeAt(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
upstream_start_, editing_state);
if (editing_state->IsAborted())
return;
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
merge_destination = CreateVisiblePosition(upstream_start_);
- start_of_paragraph_to_move =
- CreateVisiblePosition(relocatable_start.GetPosition());
+ merge_origin = CreateVisiblePosition(relocatable_start.GetPosition());
}
- if (merge_destination.DeepEquivalent() ==
- start_of_paragraph_to_move.DeepEquivalent())
+ if (merge_destination.DeepEquivalent() == merge_origin.DeepEquivalent())
return;
+ VisiblePosition start_of_paragraph_to_move = StartOfParagraph(merge_origin);
VisiblePosition end_of_paragraph_to_move =
- EndOfParagraph(start_of_paragraph_to_move, kCanSkipOverEditingBoundary);
+ EndOfParagraph(merge_origin, kCanSkipOverEditingBoundary);
if (merge_destination.DeepEquivalent() ==
end_of_paragraph_to_move.DeepEquivalent())
@@ -908,8 +903,7 @@ void DeleteSelectionCommand::MergeParagraphs(EditingState* editing_state) {
// the right.
// FIXME: Consider RTL.
if (!starts_at_empty_line_ && IsStartOfParagraph(merge_destination) &&
- AbsoluteCaretBoundsOf(start_of_paragraph_to_move.ToPositionWithAffinity())
- .X() >
+ AbsoluteCaretBoundsOf(merge_origin.ToPositionWithAffinity()).X() >
AbsoluteCaretBoundsOf(merge_destination.ToPositionWithAffinity())
.X()) {
if (IsA<HTMLBRElement>(
@@ -932,7 +926,7 @@ void DeleteSelectionCommand::MergeParagraphs(EditingState* editing_state) {
// the caret to just before the selection we deleted. See
// https://bugs.webkit.org/show_bug.cgi?id=25439
if (IsRenderedAsNonInlineTableImageOrHR(
- start_of_paragraph_to_move.DeepEquivalent().AnchorNode()) &&
+ merge_origin.DeepEquivalent().AnchorNode()) &&
!IsStartOfParagraph(merge_destination)) {
ending_position_ = upstream_start_;
return;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command_test.cc
index d5ad9c4c4d1..7ec2d5fcb44 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/delete_selection_command_test.cc
@@ -6,6 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
@@ -80,4 +81,27 @@ TEST_F(DeleteSelectionCommandTest, ForwardDeleteWithFirstLetter) {
EXPECT_EQ("<p contenteditable>a|c</p>", GetSelectionTextFromBody());
}
+// This is a regression test for https://crbug.com/1172439
+TEST_F(DeleteSelectionCommandTest, DeleteWithEditabilityChange) {
+ Selection().SetSelection(
+ SetSelectionTextToBody(
+ "^<style>body{-webkit-user-modify:read-write}</style>x|"),
+ SetSelectionOptions());
+ EXPECT_TRUE(HasEditableStyle(*GetDocument().body()));
+
+ DeleteSelectionCommand& command =
+ *MakeGarbageCollected<DeleteSelectionCommand>(
+ GetDocument(), DeleteSelectionOptions::Builder()
+ .SetMergeBlocksAfterDelete(true)
+ .SetSanitizeMarkup(true)
+ .Build());
+ // Should not crash.
+ EXPECT_TRUE(command.Apply());
+
+ // The command removes the <style>, so the <body> stops being editable,
+ // and then "x" is not removed.
+ EXPECT_FALSE(HasEditableStyle(*GetDocument().body()));
+ EXPECT_EQ("|x", GetSelectionTextFromBody());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc b/chromium/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
index c7d74ec9318..04a42aac14b 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
@@ -655,7 +655,7 @@ void ChangeSelectionAfterCommand(LocalFrame* frame,
if (!selection_did_not_change_dom_position)
return;
frame->Client()->DidChangeSelection(
- frame->Selection().GetSelectionInDOMTree().Type() != kRangeSelection);
+ !frame->Selection().GetSelectionInDOMTree().IsRange());
}
InputEvent::EventIsComposing IsComposingFromCommand(
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
index 3cc668b4f45..e450c1d5eba 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/editor_command.cc
@@ -277,14 +277,10 @@ static bool ExecuteApplyParagraphStyle(LocalFrame& frame,
bool ExpandSelectionToGranularity(LocalFrame& frame,
TextGranularity granularity) {
- const VisibleSelection& selection = CreateVisibleSelectionWithGranularity(
- SelectionInDOMTree::Builder()
- .SetBaseAndExtent(
- frame.Selection().ComputeVisibleSelectionInDOMTree().Base(),
- frame.Selection().ComputeVisibleSelectionInDOMTree().Extent())
- .Build(),
+ const SelectionInDOMTree& selection = ExpandWithGranularity(
+ frame.Selection().ComputeVisibleSelectionInDOMTree().AsSelection(),
granularity);
- const EphemeralRange new_range = selection.ToNormalizedEphemeralRange();
+ const EphemeralRange& new_range = NormalizeRange(selection);
if (new_range.IsNull())
return false;
if (new_range.IsCollapsed())
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc
index 177107431ac..18216354087 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/editing/commands/editing_commands_utilities.h"
#include "third_party/blink/renderer/core/editing/commands/insert_list_command.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
+#include "third_party/blink/renderer/core/editing/relocatable_position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
@@ -174,6 +175,50 @@ void IndentOutdentCommand::IndentIntoBlockquote(const Position& start,
: SplitTreeToNode(start.ComputeContainerNode(), element_to_split_to);
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
+ // Before moving the paragraph under the new blockquote, make sure that there
+ // aren't any nested paragraphs or line breaks under the outer_block. If there
+ // are then split it into its own block so it doesn't copy multiple
+ // paragraphs.
+ Node* highest_inline_node = HighestEnclosingNodeOfType(
+ end, IsInline, kCannotCrossEditingBoundary, outer_block);
+ if (highest_inline_node) {
+ Position next_position = MostForwardCaretPosition(
+ NextPositionOf(CreateVisiblePosition(end)).DeepEquivalent());
+ if (IsStartOfParagraph(CreateVisiblePosition(next_position)) &&
+ next_position.AnchorNode()->IsDescendantOf(highest_inline_node)) {
+ // <div>Line <blockquote>
+ // <div>
+ // <span> 1<div>Line 2</div></span> -> Line<span> 1</span>
+ // </div>
+ // </div> </blockquote>
+ // <div><span><div>Line
+ // 2</div></span></div>
+ //
+ // <div>Line <blockquote>
+ // <span> 1<br>Line 2</span> -> Line<span> 1</span>
+ // </div> </blockquote>
+ // <div><span>Line
+ // 2</span></div>
+ // The below steps are essentially trying to figure out where the split
+ // needs to happen:
+ // 1. If the next paragraph is enclosed with nested block level elements.
+ // 2. If the next paragraph is enclosed with nested inline elements.
+ // 3. If the next paragraph doesn't have any inline or block level
+ // elements, but has elements like textarea/input/img etc.
+ Node* split_point = HighestEnclosingNodeOfType(
+ next_position, IsEnclosingBlock, kCannotCrossEditingBoundary,
+ highest_inline_node);
+ split_point =
+ split_point ? split_point
+ : HighestEnclosingNodeOfType(next_position, IsInline,
+ kCannotCrossEditingBoundary,
+ highest_inline_node);
+ split_point = split_point ? split_point : next_position.AnchorNode();
+ // Split the element to separate the paragraphs.
+ SplitElement(DynamicTo<Element>(highest_inline_node), split_point);
+ }
+ }
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
VisiblePosition start_of_contents = CreateVisiblePosition(start);
if (!target_blockquote) {
// Create a new blockquote and insert it as a child of the root editable
@@ -244,12 +289,20 @@ void IndentOutdentCommand::OutdentParagraph(EditingState* editing_state) {
VisiblePosition::LastPositionInNode(*enclosing_element);
VisiblePosition end_of_enclosing_block =
EndOfBlock(last_position_in_enclosing_block);
+ RelocatablePosition start_of_paragraph(
+ visible_start_of_paragraph.DeepEquivalent());
+ RelocatablePosition end_of_paragraph(
+ visible_end_of_paragraph.DeepEquivalent());
if (visible_start_of_paragraph.DeepEquivalent() ==
start_of_enclosing_block.DeepEquivalent() &&
visible_end_of_paragraph.DeepEquivalent() ==
end_of_enclosing_block.DeepEquivalent()) {
// The blockquote doesn't contain anything outside the paragraph, so it can
// be totally removed.
+ // This procedure will make {start,end}_of_paragraph out of sync if the
+ // blockquote has children, so store the first and last children.
+ Node* first_child = enclosing_element->firstChild();
+ Node* last_child = enclosing_element->lastChild();
Node* split_point = enclosing_element->nextSibling();
RemoveNodePreservingChildren(enclosing_element, editing_state);
if (editing_state->IsAborted())
@@ -268,9 +321,14 @@ void IndentOutdentCommand::OutdentParagraph(EditingState* editing_state) {
}
}
+ // Re-canonicalize visible_start_of_paragraph, make it valid again after DOM
+ // change. If enclosing_element had children, start_of_paragraph will be out
+ // of sync, so use first_child instead.
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
+ DCHECK(!first_child || first_child->isConnected());
visible_start_of_paragraph =
- CreateVisiblePosition(visible_start_of_paragraph.DeepEquivalent());
+ CreateVisiblePosition(first_child ? Position::BeforeNode(*first_child)
+ : start_of_paragraph.GetPosition());
if (visible_start_of_paragraph.IsNotNull() &&
!IsStartOfParagraph(visible_start_of_paragraph)) {
InsertNodeAt(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
@@ -279,9 +337,14 @@ void IndentOutdentCommand::OutdentParagraph(EditingState* editing_state) {
return;
}
+ // Re-canonicalize visible_end_of_paragraph, make it valid again after DOM
+ // change. If enclosing_element had children, end_of_paragraph will be out
+ // of sync, so use last_child instead.
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
+ DCHECK(!last_child || last_child->isConnected());
visible_end_of_paragraph =
- CreateVisiblePosition(visible_end_of_paragraph.DeepEquivalent());
+ CreateVisiblePosition(last_child ? Position::AfterNode(*last_child)
+ : end_of_paragraph.GetPosition());
if (visible_end_of_paragraph.IsNotNull() &&
!IsEndOfParagraph(visible_end_of_paragraph))
InsertNodeAt(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
@@ -326,37 +389,39 @@ void IndentOutdentCommand::OutdentParagraph(EditingState* editing_state) {
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
- // Re-canonicalize visible{Start,End}OfParagraph, make them valid again
+ // Re-canonicalize visible_{start,end}_of_paragraph, make them valid again
// after DOM change.
- // TODO(editing-dev): We should not store a VisiblePosition and later
- // inspect its properties when it is already invalidated.
- // See crbug.com/648949 for details.
- visible_start_of_paragraph = CreateVisiblePosition(
- visible_start_of_paragraph.ToPositionWithAffinity());
- visible_end_of_paragraph = CreateVisiblePosition(
- visible_end_of_paragraph.ToPositionWithAffinity());
+ visible_start_of_paragraph =
+ CreateVisiblePosition(start_of_paragraph.GetPosition());
+ visible_end_of_paragraph =
+ CreateVisiblePosition(end_of_paragraph.GetPosition());
}
- // TODO(editing-dev): We should not store a VisiblePosition and later
- // inspect its properties when it is already invalidated.
- // See crbug.com/648949 for details.
- VisiblePosition start_of_paragraph_to_move =
+ VisiblePosition visible_start_of_paragraph_to_move =
StartOfParagraph(visible_start_of_paragraph);
- VisiblePosition end_of_paragraph_to_move =
+ VisiblePosition visible_end_of_paragraph_to_move =
EndOfParagraph(visible_end_of_paragraph);
- if (start_of_paragraph_to_move.IsNull() || end_of_paragraph_to_move.IsNull())
+ if (visible_start_of_paragraph_to_move.IsNull() ||
+ visible_end_of_paragraph_to_move.IsNull())
return;
+ RelocatablePosition start_of_paragraph_to_move(
+ visible_start_of_paragraph_to_move.DeepEquivalent());
+ RelocatablePosition end_of_paragraph_to_move(
+ visible_end_of_paragraph_to_move.DeepEquivalent());
auto* placeholder = MakeGarbageCollected<HTMLBRElement>(GetDocument());
InsertNodeBefore(placeholder, split_blockquote_node, editing_state);
if (editing_state->IsAborted())
return;
+ // Re-canonicalize visible_{start,end}_of_paragraph_to_move, make them valid
+ // again after DOM change.
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
- start_of_paragraph_to_move = CreateVisiblePosition(
- start_of_paragraph_to_move.ToPositionWithAffinity());
- end_of_paragraph_to_move =
- CreateVisiblePosition(end_of_paragraph_to_move.ToPositionWithAffinity());
- MoveParagraph(start_of_paragraph_to_move, end_of_paragraph_to_move,
+ visible_start_of_paragraph_to_move =
+ CreateVisiblePosition(start_of_paragraph_to_move.GetPosition());
+ visible_end_of_paragraph_to_move =
+ CreateVisiblePosition(end_of_paragraph_to_move.GetPosition());
+ MoveParagraph(visible_start_of_paragraph_to_move,
+ visible_end_of_paragraph_to_move,
VisiblePosition::BeforeNode(*placeholder), editing_state,
kPreserveSelection);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/insert_commands.cc b/chromium/third_party/blink/renderer/core/editing/commands/insert_commands.cc
index 2a8448c8b42..ced8bf96471 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/insert_commands.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/insert_commands.cc
@@ -35,9 +35,13 @@
#include "third_party/blink/renderer/core/editing/commands/insert_list_command.h"
#include "third_party/blink/renderer/core/editing/commands/replace_selection_command.h"
#include "third_party/blink/renderer/core/editing/commands/typing_command.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/editor.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/html/html_hr_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -99,12 +103,43 @@ bool InsertCommands::ExecuteInsertHorizontalRule(LocalFrame& frame,
}
bool InsertCommands::ExecuteInsertHTML(LocalFrame& frame,
- Event*,
- EditorCommandSource,
+ Event* event,
+ EditorCommandSource source,
const String& value) {
DCHECK(frame.GetDocument());
- return ExecuteInsertFragment(
- frame, CreateFragmentFromMarkup(*frame.GetDocument(), value, ""));
+ DocumentFragment* fragment =
+ CreateFragmentFromMarkup(*frame.GetDocument(), value, "");
+ if (const auto* text_control = EnclosingTextControl(
+ frame.Selection().RootEditableElementOrDocumentElement())) {
+ if (IsA<HTMLInputElement>(text_control)) {
+ UseCounter::Count(frame.GetDocument(),
+ WebFeature::kInsertHTMLCommandOnInput);
+ // We'd like to turn off HTML insertion against <input> in order to avoid
+ // creating an anonymous block as a child of
+ // LayoutNGTextControlInnerEditor. See crbug.com/1174952
+ //
+ // |textContent()| contains the contents of <style> and <script>.
+ // It's not a reasonable behavior, but we think no one cares about
+ // the behavior of InsertHTML for <input>.
+
+ // Set convert_brs_to_newlines for fast/forms/8250.html.
+ const bool convert_brs_to_newlines = true;
+ return ExecuteInsertText(frame, event, source,
+ fragment->textContent(convert_brs_to_newlines));
+ } else {
+ UseCounter::Count(frame.GetDocument(),
+ WebFeature::kInsertHTMLCommandOnTextarea);
+ }
+ } else {
+ if (Node* anchor =
+ frame.Selection().GetSelectionInDOMTree().Base().AnchorNode()) {
+ if (HasEditableStyle(*anchor) && !HasRichlyEditableStyle(*anchor)) {
+ UseCounter::Count(frame.GetDocument(),
+ WebFeature::kInsertHTMLCommandOnReadWritePlainText);
+ }
+ }
+ }
+ return ExecuteInsertFragment(frame, fragment);
}
bool InsertCommands::ExecuteInsertImage(LocalFrame& frame,
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/insert_list_command.h b/chromium/third_party/blink/renderer/core/editing/commands/insert_list_command.h
index 74f44e0980c..a56f84f8fed 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/insert_list_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/insert_list_command.h
@@ -31,6 +31,7 @@
namespace blink {
class HTMLElement;
+class HTMLLIElement;
class HTMLUListElement;
class CORE_EXPORT InsertListCommand final : public CompositeEditCommand {
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/insert_node_before_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/insert_node_before_command.cc
index 45035bfc579..9798029a331 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/insert_node_before_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/insert_node_before_command.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/editing/commands/insert_node_before_command.h"
+#include "third_party/blink/renderer/core/editing/commands/editing_state.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -50,7 +51,7 @@ InsertNodeBeforeCommand::InsertNodeBeforeCommand(
<< ref_child_->parentNode();
}
-void InsertNodeBeforeCommand::DoApply(EditingState*) {
+void InsertNodeBeforeCommand::DoApply(EditingState* editing_state) {
ContainerNode* parent = ref_child_->parentNode();
GetDocument().UpdateStyleAndLayoutTree();
if (!parent || (should_assume_content_is_always_editable_ ==
@@ -59,8 +60,9 @@ void InsertNodeBeforeCommand::DoApply(EditingState*) {
return;
DCHECK(HasEditableStyle(*parent)) << parent;
- parent->InsertBefore(insert_child_.Get(), ref_child_.Get(),
- IGNORE_EXCEPTION_FOR_TESTING);
+ DummyExceptionStateForTesting exception_state;
+ parent->InsertBefore(insert_child_.Get(), ref_child_.Get(), exception_state);
+ ABORT_EDITING_COMMAND_IF(exception_state.HadException());
}
void InsertNodeBeforeCommand::DoUnapply() {
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command.cc
index 199f59516de..c100b5fa908 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command.cc
@@ -104,7 +104,23 @@ bool InsertTextCommand::PerformTrivialReplace(const String& text) {
if (text.Contains('\t') || text.Contains(' ') || text.Contains('\n'))
return false;
+ // Also if the text is surrounded by a hyperlink and all the contents of the
+ // link are selected, then we shouldn't be retaining the link with just one
+ // character because the user wouldn't be able to edit the link if it has only
+ // one character.
Position start = EndingVisibleSelection().Start();
+ Element* enclosing_anchor = EnclosingAnchorElement(start);
+ if (enclosing_anchor && text.length() <= 1) {
+ VisiblePosition first_in_anchor =
+ VisiblePosition::FirstPositionInNode(*enclosing_anchor);
+ VisiblePosition last_in_anchor =
+ VisiblePosition::LastPositionInNode(*enclosing_anchor);
+ Position end = EndingVisibleSelection().End();
+ if (first_in_anchor.DeepEquivalent() == start &&
+ last_in_anchor.DeepEquivalent() == end)
+ return false;
+ }
+
Position end_position = ReplaceSelectedTextInNode(text);
if (end_position.IsNull())
return false;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command_test.cc
index 14d4cfff12e..c8149b89dd2 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/insert_text_command_test.cc
@@ -297,9 +297,8 @@ TEST_F(InsertTextCommandTest, AnchorElementWithBlockCrash) {
// Crash happens here with when '\n' is inserted.
GetDocument().execCommand("inserttext", false, "a\n", ASSERT_NO_EXCEPTION);
EXPECT_EQ(
- "<i style=\"display: block;\">"
- "<a href=\"www\" style=\"display: block;\">a</a>"
- "</i>|",
+ "<a href=\"www\" style=\"display:block\"><i>a</i></a><a href=\"www\" "
+ "style=\"display:block\"><i>|<br></i></a>",
GetSelectionTextFromBody());
}
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/move_commands_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/move_commands_test.cc
index 41b4260caf9..385124efd60 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/move_commands_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/move_commands_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/editing/commands/move_commands.h"
+#include "third_party/blink/renderer/core/editing/editing_behavior.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
@@ -215,10 +216,19 @@ TEST_F(MoveCommandsTest, CaretBrowsingPositionAndFocusUpdate_MoveWordLeft) {
}
TEST_F(MoveCommandsTest, CaretBrowsingPositionAndFocusUpdate_MoveWordRight) {
+ bool should_skip_spaces = GetDocument()
+ .GetFrame()
+ ->GetEditor()
+ .Behavior()
+ .ShouldSkipSpaceWhenMovingRight();
VerifyCaretBrowsingPositionAndFocusUpdate(
"<div>a|<a href=\"foo\"> b</a></div>", "body",
- MoveCommands::ExecuteMoveWordRight, "<div>a<a href=\"foo\"> b|</a></div>",
+ MoveCommands::ExecuteMoveWordRight,
+ should_skip_spaces ? "<div>a<a href=\"foo\"> |b</a></div>"
+ : "<div>a<a href=\"foo\"> b|</a></div>",
"a");
+ // MoveRight skips the beginning of the word when started after
+ // end of previous word, placing caret at different position for macOS.
}
// This test verifies that focus returns to the body after browsing out of a
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/remove_css_property_command.h b/chromium/third_party/blink/renderer/core/editing/commands/remove_css_property_command.h
index c02fc8217a4..def9c501781 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/remove_css_property_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/remove_css_property_command.h
@@ -36,12 +36,11 @@ class Element;
class RemoveCSSPropertyCommand final : public SimpleEditCommand {
public:
RemoveCSSPropertyCommand(Document&, Element*, CSSPropertyID);
+ ~RemoveCSSPropertyCommand() override;
void Trace(Visitor*) const override;
private:
- ~RemoveCSSPropertyCommand() override;
-
void DoApply(EditingState*) override;
void DoUnapply() override;
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
index 2476f73fe1c..2dc8cf8b435 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
@@ -411,7 +411,7 @@ inline void ReplaceSelectionCommand::InsertedNodes::WillRemoveNode(Node& node) {
NodeTraversal::NextSkippingChildren(*first_node_inserted_);
} else if (last_node_inserted_ == node) {
last_node_inserted_ =
- NodeTraversal::PreviousSkippingChildren(*last_node_inserted_);
+ NodeTraversal::PreviousAbsoluteSibling(*last_node_inserted_);
}
if (node.contains(ref_node_))
ref_node_ = NodeTraversal::NextSkippingChildren(node);
@@ -820,10 +820,13 @@ void ReplaceSelectionCommand::RemoveUnrenderedTextNodesAtEnds(
// can't insert into those elements.
auto* first_node_inserted =
DynamicTo<Text>(inserted_nodes.FirstNodeInserted());
- if (first_node_inserted && !NodeHasVisibleLayoutText(*first_node_inserted)) {
- inserted_nodes.WillRemoveNode(*first_node_inserted);
- // Removing a Text node won't dispatch synchronous events.
- RemoveNode(first_node_inserted, ASSERT_NO_EDITING_ABORT);
+ if (first_node_inserted) {
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
+ if (!NodeHasVisibleLayoutText(*first_node_inserted)) {
+ inserted_nodes.WillRemoveNode(*first_node_inserted);
+ // Removing a Text node won't dispatch synchronous events.
+ RemoveNode(first_node_inserted, ASSERT_NO_EDITING_ABORT);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc b/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
index aaf00dd0f92..478bc20422b 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
@@ -185,4 +185,25 @@ TEST_F(ReplaceSelectionCommandTest, SmartPlainTextPaste) {
GetSelectionTextFromBody());
}
+// http://crbug.com/1155687
+TEST_F(ReplaceSelectionCommandTest, TableAndImages) {
+ GetDocument().setDesignMode("on");
+ SetBodyContent("<table>&#x20;<tbody></tbody>&#x20;</table>");
+ Element* tbody = GetDocument().QuerySelector("tbody");
+ tbody->AppendChild(GetDocument().CreateRawElement(html_names::kImgTag));
+ Selection().SetSelection(
+ SelectionInDOMTree::Builder().Collapse(Position(tbody, 1)).Build(),
+ SetSelectionOptions());
+
+ DocumentFragment* fragment = GetDocument().createDocumentFragment();
+ fragment->AppendChild(GetDocument().CreateRawElement(html_names::kImgTag));
+ auto& command = *MakeGarbageCollected<ReplaceSelectionCommand>(
+ GetDocument(), fragment, ReplaceSelectionCommand::kPreventNesting,
+ InputEvent::InputType::kNone);
+
+ // Should not crash
+ EXPECT_TRUE(command.Apply());
+ EXPECT_EQ("<table> <tbody><img><img></tbody><br><img>|<br> </table>",
+ GetSelectionTextFromBody());
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.cc b/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.cc
index 5cb701a6caf..9a103ad3556 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.cc
@@ -18,6 +18,7 @@ SelectionForUndoStep SelectionForUndoStep::From(
result.extent_ = selection.Extent();
result.affinity_ = selection.Affinity();
result.is_base_first_ = selection.IsBaseFirst();
+ result.root_editable_element_ = RootEditableElementOf(result.base_);
return result;
}
@@ -81,6 +82,7 @@ bool SelectionForUndoStep::IsValidFor(const Document& document) const {
void SelectionForUndoStep::Trace(Visitor* visitor) const {
visitor->Trace(base_);
visitor->Trace(extent_);
+ visitor->Trace(root_editable_element_);
}
// ---
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.h b/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.h
index aa7b148a10f..08e33fad25d 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/selection_for_undo_step.h
@@ -37,6 +37,7 @@ class SelectionForUndoStep final {
Position Base() const { return base_; }
Position Extent() const { return extent_; }
bool IsBaseFirst() const { return is_base_first_; }
+ Element* RootEditableElement() const { return root_editable_element_.Get(); }
SelectionInDOMTree AsSelection() const;
@@ -61,9 +62,12 @@ class SelectionForUndoStep final {
Position base_;
Position extent_;
TextAffinity affinity_ = TextAffinity::kDownstream;
- // Note: We should compute |is_base_first_| as construction otherwise we
+ // Note: We should compute |is_base_first_| at construction otherwise we
// fail "backward and forward delete" case in "undo-delete-boundary.html".
bool is_base_first_ = true;
+ // Since |base_| and |extent_| can be disconnected from document, we have to
+ // calculate the root editable element at construction time
+ Member<Element> root_editable_element_;
};
// Builds |SelectionForUndoStep| object with disconnected position. You should
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/typing_command.cc b/chromium/third_party/blink/renderer/core/editing/commands/typing_command.cc
index f32727d51fd..bc7089a4c7d 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/typing_command.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/typing_command.cc
@@ -42,6 +42,7 @@
#include "third_party/blink/renderer/core/editing/editor.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/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/editing/plain_text_range.h"
#include "third_party/blink/renderer/core/editing/selection_modifier.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
@@ -66,9 +67,13 @@ bool IsValidDocument(const Document& document) {
}
String DispatchBeforeTextInsertedEvent(const String& text,
- const VisibleSelection& selection,
+ const SelectionInDOMTree& selection,
EditingState* editing_state) {
- Node* start_node = selection.Start().ComputeContainerNode();
+ // We use SelectionForUndoStep because it is resilient to DOM
+ // mutation.
+ const SelectionForUndoStep& selection_as_undo_step =
+ SelectionForUndoStep::From(selection);
+ Node* start_node = selection_as_undo_step.Start().ComputeContainerNode();
if (!start_node || !RootEditableElement(*start_node))
return text;
@@ -77,7 +82,7 @@ String DispatchBeforeTextInsertedEvent(const String& text,
const Document& document = start_node->GetDocument();
auto* evt = MakeGarbageCollected<BeforeTextInsertedEvent>(text);
RootEditableElement(*start_node)->DispatchEvent(*evt);
- if (IsValidDocument(document) && selection.IsValidFor(document))
+ if (IsValidDocument(document) && selection_as_undo_step.IsValidFor(document))
return evt->GetText();
// editing/inserting/webkitBeforeTextInserted-removes-frame.html
// and
@@ -110,8 +115,7 @@ DispatchEventResult DispatchTextInputEvent(LocalFrame* frame,
}
PlainTextRange GetSelectionOffsets(const SelectionInDOMTree& selection) {
- const VisibleSelection visible_selection = CreateVisibleSelection(selection);
- const EphemeralRange range = FirstEphemeralRangeOf(visible_selection);
+ const EphemeralRange range = selection.ComputeRange();
if (range.IsNull())
return PlainTextRange();
ContainerNode* const editable =
@@ -140,9 +144,13 @@ SelectionInDOMTree CreateSelection(const wtf_size_t start,
return selection;
}
-bool CanAppendNewLineFeedToSelection(const VisibleSelection& selection,
+bool CanAppendNewLineFeedToSelection(const SelectionInDOMTree& selection,
EditingState* editing_state) {
- Element* element = selection.RootEditableElement();
+ // We use SelectionForUndoStep because it is resilient to DOM
+ // mutation.
+ const SelectionForUndoStep& selection_as_undo_step =
+ SelectionForUndoStep::From(selection);
+ Element* element = selection_as_undo_step.RootEditableElement();
if (!element)
return false;
@@ -150,7 +158,7 @@ bool CanAppendNewLineFeedToSelection(const VisibleSelection& selection,
auto* event = MakeGarbageCollected<BeforeTextInsertedEvent>(String("\n"));
element->DispatchEvent(*event);
// event may invalidate frame or selection
- if (IsValidDocument(document) && selection.IsValidFor(document))
+ if (IsValidDocument(document) && selection_as_undo_step.IsValidFor(document))
return event->GetText().length();
// editing/inserting/webkitBeforeTextInserted-removes-frame.html
// and
@@ -160,6 +168,25 @@ bool CanAppendNewLineFeedToSelection(const VisibleSelection& selection,
return false;
}
+// Example: <div><img style="display:block">|<br></p>
+// See "editing/deleting/delete_after_block_image.html"
+Position AfterBlockIfBeforeAnonymousPlaceholder(const Position& position) {
+ if (!position.IsBeforeAnchor())
+ return Position();
+ const LayoutObject* const layout_object =
+ position.AnchorNode()->GetLayoutObject();
+ if (!layout_object || !layout_object->IsBR() ||
+ layout_object->NextSibling() || layout_object->PreviousSibling())
+ return Position();
+ const LayoutObject* const parent = layout_object->Parent();
+ if (!parent || !parent->IsAnonymous())
+ return Position();
+ const LayoutObject* const previous = parent->PreviousSibling();
+ if (!previous || !previous->NonPseudoNode())
+ return Position();
+ return Position::AfterNode(*previous->NonPseudoNode());
+}
+
} // anonymous namespace
TypingCommand::TypingCommand(Document& document,
@@ -353,17 +380,19 @@ void TypingCommand::InsertText(
LocalFrame* frame = document.GetFrame();
DCHECK(frame);
- const VisibleSelection& current_selection =
- frame->Selection().ComputeVisibleSelectionInDOMTree();
- const VisibleSelection& selection_for_insertion =
- CreateVisibleSelection(passed_selection_for_insertion);
+ // We use SelectionForUndoStep because it is resilient to DOM
+ // mutation.
+ const SelectionForUndoStep& passed_selection_for_insertion_as_undo_step =
+ SelectionForUndoStep::From(passed_selection_for_insertion);
String new_text = text;
if (composition_type != kTextCompositionUpdate) {
- new_text = DispatchBeforeTextInsertedEvent(text, selection_for_insertion,
- editing_state);
+ new_text = DispatchBeforeTextInsertedEvent(
+ text, passed_selection_for_insertion, editing_state);
if (editing_state->IsAborted())
return;
+ ABORT_EDITING_COMMAND_IF(
+ !passed_selection_for_insertion_as_undo_step.IsValidFor(document));
}
if (composition_type == kTextCompositionConfirm) {
@@ -375,19 +404,21 @@ void TypingCommand::InsertText(
return;
// editing/inserting/insert-text-nodes-disconnect-on-textinput-event.html
// hits true for ABORT_EDITING_COMMAND_IF macro.
- ABORT_EDITING_COMMAND_IF(!selection_for_insertion.IsValidFor(document));
+ ABORT_EDITING_COMMAND_IF(
+ !passed_selection_for_insertion_as_undo_step.IsValidFor(document));
}
// Do nothing if no need to delete and insert.
- if (selection_for_insertion.IsCaret() && new_text.IsEmpty())
+ if (passed_selection_for_insertion_as_undo_step.IsCaret() &&
+ new_text.IsEmpty())
return;
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
document.UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
- const PlainTextRange selection_offsets =
- GetSelectionOffsets(selection_for_insertion.AsSelection());
+ const PlainTextRange selection_offsets = GetSelectionOffsets(
+ passed_selection_for_insertion_as_undo_step.AsSelection());
if (selection_offsets.IsNull())
return;
const wtf_size_t selection_start = selection_offsets.Start();
@@ -398,14 +429,12 @@ void TypingCommand::InsertText(
// that can be used by all of the commands.
if (TypingCommand* last_typing_command =
LastTypingCommandIfStillOpenForTyping(frame)) {
- if (last_typing_command->EndingVisibleSelection() !=
- selection_for_insertion) {
- const SelectionForUndoStep& selection_for_insertion_as_undo_step =
- SelectionForUndoStep::From(selection_for_insertion.AsSelection());
+ if (last_typing_command->EndingSelection() !=
+ passed_selection_for_insertion_as_undo_step) {
last_typing_command->SetStartingSelection(
- selection_for_insertion_as_undo_step);
+ passed_selection_for_insertion_as_undo_step);
last_typing_command->SetEndingSelection(
- selection_for_insertion_as_undo_step);
+ passed_selection_for_insertion_as_undo_step);
}
last_typing_command->SetCompositionType(composition_type);
@@ -422,12 +451,14 @@ void TypingCommand::InsertText(
TypingCommand* command = MakeGarbageCollected<TypingCommand>(
document, kInsertText, new_text, options, TextGranularity::kCharacter,
composition_type);
- bool change_selection = selection_for_insertion != current_selection;
+ const SelectionInDOMTree& current_selection =
+ frame->Selection().GetSelectionInDOMTree();
+ bool change_selection =
+ current_selection !=
+ passed_selection_for_insertion_as_undo_step.AsSelection();
if (change_selection) {
- const SelectionForUndoStep& selection_for_insertion_as_undo_step =
- SelectionForUndoStep::From(selection_for_insertion.AsSelection());
- command->SetStartingSelection(selection_for_insertion_as_undo_step);
- command->SetEndingSelection(selection_for_insertion_as_undo_step);
+ command->SetStartingSelection(passed_selection_for_insertion_as_undo_step);
+ command->SetEndingSelection(passed_selection_for_insertion_as_undo_step);
}
command->is_incremental_insertion_ = is_incremental_insertion;
command->selection_start_ = selection_start;
@@ -435,9 +466,8 @@ void TypingCommand::InsertText(
ABORT_EDITING_COMMAND_IF(!command->Apply());
if (change_selection) {
- ABORT_EDITING_COMMAND_IF(!current_selection.IsValidFor(document));
const SelectionInDOMTree& current_selection_as_dom =
- current_selection.AsSelection();
+ frame->Selection().GetSelectionInDOMTree();
command->SetEndingSelection(
SelectionForUndoStep::From(current_selection_as_dom));
frame->Selection().SetSelection(
@@ -510,6 +540,15 @@ void TypingCommand::CloseTyping(LocalFrame* frame) {
last_typing_command->CloseTyping();
}
+void TypingCommand::CloseTypingIfNeeded(LocalFrame* frame) {
+ if (frame->GetDocument()->IsRunningExecCommand() ||
+ frame->GetInputMethodController().HasComposition())
+ return;
+ if (TypingCommand* last_typing_command =
+ LastTypingCommandIfStillOpenForTyping(frame))
+ last_typing_command->CloseTyping();
+}
+
void TypingCommand::DoApply(EditingState* editing_state) {
if (EndingSelection().IsNone() ||
!EndingSelection().IsValidFor(GetDocument()))
@@ -688,7 +727,8 @@ void TypingCommand::InsertTextRunWithoutNewlines(const String& text,
}
void TypingCommand::InsertLineBreak(EditingState* editing_state) {
- if (!CanAppendNewLineFeedToSelection(EndingVisibleSelection(), editing_state))
+ if (!CanAppendNewLineFeedToSelection(EndingSelection().AsSelection(),
+ editing_state))
return;
ApplyCommandToComposite(
@@ -700,7 +740,8 @@ void TypingCommand::InsertLineBreak(EditingState* editing_state) {
}
void TypingCommand::InsertParagraphSeparator(EditingState* editing_state) {
- if (!CanAppendNewLineFeedToSelection(EndingVisibleSelection(), editing_state))
+ if (!CanAppendNewLineFeedToSelection(EndingSelection().AsSelection(),
+ editing_state))
return;
ApplyCommandToComposite(
@@ -763,19 +804,37 @@ bool TypingCommand::MakeEditableRootEmpty(EditingState* editing_state) {
// If there are multiple Unicode code points to be deleted, adjust the
// range to match platform conventions.
-static VisibleSelection AdjustSelectionForBackwardDelete(
- const VisibleSelection& selection) {
- if (selection.End().ComputeContainerNode() !=
- selection.Start().ComputeContainerNode())
- return selection;
- if (selection.End().ComputeOffsetInContainerNode() -
- selection.Start().ComputeOffsetInContainerNode() <=
+static SelectionForUndoStep AdjustSelectionForBackwardDelete(
+ const SelectionInDOMTree& selection) {
+ const Position& base = selection.Base();
+ if (selection.IsCaret()) {
+ // TODO(yosin): We should make |DeleteSelectionCommand| to work with
+ // anonymous placeholder.
+ if (Position after_block = AfterBlockIfBeforeAnonymousPlaceholder(base)) {
+ // We remove a anonymous placeholder <br> in <div> like <div><br></div>:
+ // <div><img style="display:block"><br></div>
+ // |selection_to_delete| is Before:<br>
+ // as
+ // <div><img style="display:block"><div><br></div></div>.
+ // |selection_to_delete| is <div>@0, After:<img>
+ // See "editing/deleting/delete_after_block_image.html"
+ return SelectionForUndoStep::Builder()
+ .SetBaseAndExtentAsBackwardSelection(base, after_block)
+ .Build();
+ }
+ return SelectionForUndoStep::From(selection);
+ }
+ if (base.ComputeContainerNode() != selection.Extent().ComputeContainerNode())
+ return SelectionForUndoStep::From(selection);
+ if (base.ComputeOffsetInContainerNode() -
+ selection.Extent().ComputeOffsetInContainerNode() <=
1)
- return selection;
- return VisibleSelection::CreateWithoutValidationDeprecated(
- selection.End(),
- PreviousPositionOf(selection.End(), PositionMoveType::kBackwardDeletion),
- selection.Affinity());
+ return SelectionForUndoStep::From(selection);
+ const Position& end = selection.ComputeEndPosition();
+ return SelectionForUndoStep::Builder()
+ .SetBaseAndExtentAsBackwardSelection(
+ end, PreviousPositionOf(end, PositionMoveType::kBackwardDeletion))
+ .Build();
}
void TypingCommand::DeleteKeyPressed(TextGranularity granularity,
@@ -887,17 +946,17 @@ void TypingCommand::DeleteKeyPressed(TextGranularity granularity,
return;
}
- const VisibleSelection& selection_to_delete =
+ const SelectionForUndoStep& selection_to_delete =
granularity == TextGranularity::kCharacter
- ? AdjustSelectionForBackwardDelete(selection_modifier.Selection())
- : selection_modifier.Selection();
+ ? AdjustSelectionForBackwardDelete(
+ selection_modifier.Selection().AsSelection())
+ : SelectionForUndoStep::From(
+ selection_modifier.Selection().AsSelection());
if (!StartingSelection().IsRange() ||
selection_to_delete.Base() != StartingSelection().Start()) {
- DeleteKeyPressedInternal(
- SelectionForUndoStep::From(selection_to_delete.AsSelection()),
- SelectionForUndoStep::From(selection_to_delete.AsSelection()),
- kill_ring, editing_state);
+ DeleteKeyPressedInternal(selection_to_delete, selection_to_delete,
+ kill_ring, editing_state);
return;
}
// Note: |StartingSelection().End()| can be disconnected.
@@ -909,9 +968,8 @@ void TypingCommand::DeleteKeyPressed(TextGranularity granularity,
CreateVisiblePosition(selection_to_delete.Extent())
.DeepEquivalent())
.Build();
- DeleteKeyPressedInternal(
- SelectionForUndoStep::From(selection_to_delete.AsSelection()),
- selection_after_undo, kill_ring, editing_state);
+ DeleteKeyPressedInternal(selection_to_delete, selection_after_undo, kill_ring,
+ editing_state);
}
void TypingCommand::DeleteKeyPressedInternal(
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/typing_command.h b/chromium/third_party/blink/renderer/core/editing/commands/typing_command.h
index cfec38f07c5..a34cc901653 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/typing_command.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/typing_command.h
@@ -85,6 +85,7 @@ class CORE_EXPORT TypingCommand final : public CompositeEditCommand {
static bool InsertParagraphSeparator(Document&);
static bool InsertParagraphSeparatorInQuotedContent(Document&);
static void CloseTyping(LocalFrame*);
+ static void CloseTypingIfNeeded(LocalFrame*);
static TypingCommand* LastTypingCommandIfStillOpenForTyping(LocalFrame*);
static void UpdateSelectionIfDifferentFromCurrentSelection(TypingCommand*,
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/undo_step.cc b/chromium/third_party/blink/renderer/core/editing/commands/undo_step.cc
index 4ab76ddd115..aaa4a38eb67 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/undo_step.cc
+++ b/chromium/third_party/blink/renderer/core/editing/commands/undo_step.cc
@@ -27,10 +27,6 @@ UndoStep::UndoStep(Document* document,
: document_(document),
starting_selection_(starting_selection),
ending_selection_(ending_selection),
- starting_root_editable_element_(
- RootEditableElementOf(starting_selection.Base())),
- ending_root_editable_element_(
- RootEditableElementOf(ending_selection.Base())),
input_type_(input_type),
sequence_number_(++g_current_sequence_number) {}
@@ -131,12 +127,10 @@ void UndoStep::Append(UndoStep* undo_step) {
void UndoStep::SetStartingSelection(const SelectionForUndoStep& selection) {
starting_selection_ = selection;
- starting_root_editable_element_ = RootEditableElementOf(selection.Base());
}
void UndoStep::SetEndingSelection(const SelectionForUndoStep& selection) {
ending_selection_ = selection;
- ending_root_editable_element_ = RootEditableElementOf(selection.Base());
}
void UndoStep::Trace(Visitor* visitor) const {
@@ -144,8 +138,6 @@ void UndoStep::Trace(Visitor* visitor) const {
visitor->Trace(starting_selection_);
visitor->Trace(ending_selection_);
visitor->Trace(commands_);
- visitor->Trace(starting_root_editable_element_);
- visitor->Trace(ending_root_editable_element_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/commands/undo_step.h b/chromium/third_party/blink/renderer/core/editing/commands/undo_step.h
index 43e3fa0621b..aa5af8632a1 100644
--- a/chromium/third_party/blink/renderer/core/editing/commands/undo_step.h
+++ b/chromium/third_party/blink/renderer/core/editing/commands/undo_step.h
@@ -65,10 +65,10 @@ class UndoStep final : public GarbageCollected<UndoStep> {
selection_is_directional_ = is_directional;
}
Element* StartingRootEditableElement() const {
- return starting_root_editable_element_.Get();
+ return starting_selection_.RootEditableElement();
}
Element* EndingRootEditableElement() const {
- return ending_root_editable_element_.Get();
+ return ending_selection_.RootEditableElement();
}
uint64_t SequenceNumber() const { return sequence_number_; }
@@ -80,8 +80,6 @@ class UndoStep final : public GarbageCollected<UndoStep> {
SelectionForUndoStep starting_selection_;
SelectionForUndoStep ending_selection_;
HeapVector<Member<SimpleEditCommand>> commands_;
- Member<Element> starting_root_editable_element_;
- Member<Element> ending_root_editable_element_;
InputEvent::InputType input_type_;
const uint64_t sequence_number_;
bool selection_is_directional_ = false;
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_behavior.h b/chromium/third_party/blink/renderer/core/editing/editing_behavior.h
index 34931d74742..dac5d1f17a7 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_behavior.h
+++ b/chromium/third_party/blink/renderer/core/editing/editing_behavior.h
@@ -77,8 +77,8 @@ class CORE_EXPORT EditingBehavior {
return type_ == mojom::blink::EditingBehavior::kEditingMacBehavior;
}
- // On Mac, when processing a contextual click, the object being clicked upon
- // should be selected.
+ // On Mac/ChromeOS, when processing a contextual click, the object being
+ // clicked upon should be selected.
bool ShouldSelectOnContextualMenuClick() const {
return type_ == mojom::blink::EditingBehavior::kEditingMacBehavior ||
type_ == mojom::blink::EditingBehavior::kEditingChromeOSBehavior;
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_strategy.cc b/chromium/third_party/blink/renderer/core/editing/editing_strategy.cc
index 535905a638b..11c660e56d8 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_strategy.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_strategy.cc
@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/core/editing/editing_strategy.h"
+#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/layout/layout_text.h"
namespace {
@@ -34,8 +36,8 @@ template <typename Traversal>
int EditingAlgorithm<Traversal>::CaretMaxOffset(const Node& node) {
// For rendered text nodes, return the last position that a caret could
// occupy.
- if (node.IsTextNode() && node.GetLayoutObject())
- return node.GetLayoutObject()->CaretMaxOffset();
+ if (IsA<Text>(node) && node.GetLayoutObject())
+ return To<Text>(node).GetLayoutObject()->CaretMaxOffset();
// For containers return the number of children. For others do the same as
// above.
return LastOffsetForEditing(&node);
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_strategy_test.cc b/chromium/third_party/blink/renderer/core/editing/editing_strategy_test.cc
index 2234f110a1c..59f484f9605 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_strategy_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_strategy_test.cc
@@ -12,9 +12,9 @@ class EditingStrategyTest : public EditingTestBase {};
TEST_F(EditingStrategyTest, caretMaxOffset) {
const char* body_content =
- "<p id='host'>00<b id='one'>1</b><b id='two'>22</b>333</p>";
- const char* shadow_content =
- "<content select=#two></content><content select=#one></content>";
+ "<p id='host'>00<b slot='#one' id='one'>1</b><b slot='#two' "
+ "id='two'>22</b>333</p>";
+ const char* shadow_content = "<slot name=#two></slot><slot name=#one></slot>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* host = GetDocument().getElementById("host");
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_style.cc b/chromium/third_party/blink/renderer/core/editing/editing_style.cc
index cb4fee97c9b..086314ffe76 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_style.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_style.cc
@@ -153,16 +153,9 @@ static inline bool IsEditingProperty(ExecutionContext* execution_context,
return false;
}
-static CSSComputedStyleDeclaration* EnsureComputedStyle(
- const Position& position) {
- Element* elem = AssociatedElementOf(position);
- if (!elem)
- return nullptr;
- return MakeGarbageCollected<CSSComputedStyleDeclaration>(elem);
-}
-
static MutableCSSPropertyValueSet* GetPropertiesNotIn(
CSSPropertyValueSet* style_with_redundant_properties,
+ Node*,
CSSStyleDeclaration* base_style,
SecureContextMode);
enum LegacyFontSizeMode {
@@ -470,8 +463,7 @@ static inline Color BackgroundColorInEffect(Node* node) {
EditingStyleUtilities::BackgroundColorValueInEffect(node));
}
-static CSSValueID TextAlignResolvingStartAndEnd(CSSValueID text_align,
- CSSValueID direction) {
+static CSSValueID NormalizeTextAlign(CSSValueID text_align) {
switch (text_align) {
case CSSValueID::kCenter:
case CSSValueID::kWebkitCenter:
@@ -485,21 +477,71 @@ static CSSValueID TextAlignResolvingStartAndEnd(CSSValueID text_align,
case CSSValueID::kWebkitRight:
return CSSValueID::kRight;
case CSSValueID::kStart:
- return direction != CSSValueID::kRtl ? CSSValueID::kLeft
- : CSSValueID::kRight;
case CSSValueID::kEnd:
- return direction == CSSValueID::kRtl ? CSSValueID::kRight
- : CSSValueID::kLeft;
+ return text_align;
default:
return CSSValueID::kInvalid;
}
}
+static CSSValueID TextAlignResolvingStartAndEnd(CSSValueID text_align,
+ TextDirection direction) {
+ const CSSValueID normalized = NormalizeTextAlign(text_align);
+ switch (normalized) {
+ case CSSValueID::kStart:
+ return IsLtr(direction) ? CSSValueID::kLeft : CSSValueID::kRight;
+ case CSSValueID::kEnd:
+ return IsLtr(direction) ? CSSValueID::kRight : CSSValueID::kLeft;
+ default:
+ return normalized;
+ }
+}
+// Returns true "text-align" property of |style| is redundant when applying
+// |style| inheriting from |base_style| to |node|.
+// Note: direction for "text-align:start" and "text-align:end" are taken
+// from |node|.
template <typename T>
-static CSSValueID TextAlignResolvingStartAndEnd(T* style) {
- return TextAlignResolvingStartAndEnd(
- GetIdentifierValue(style, CSSPropertyID::kTextAlign),
- GetIdentifierValue(style, CSSPropertyID::kDirection));
+static bool IsRedundantTextAlign(MutableCSSPropertyValueSet* style,
+ T* base_style,
+ Node* node) {
+ DCHECK(node);
+ const CSSValueID base_text_align = NormalizeTextAlign(
+ GetIdentifierValue(base_style, CSSPropertyID::kTextAlign));
+ if (base_text_align == CSSValueID::kInvalid)
+ return false;
+ const CSSValueID text_align =
+ NormalizeTextAlign(GetIdentifierValue(style, CSSPropertyID::kTextAlign));
+ if (text_align == CSSValueID::kInvalid)
+ return false;
+ if (text_align == base_text_align)
+ return true;
+ if (base_text_align == CSSValueID::kStart ||
+ base_text_align == CSSValueID::kEnd) {
+ // Returns true for "text-align:left" of <p>
+ // <div style="text-align:start"><p dir="ltr" style="text-align:left">
+ // because meaning of "text-align:start" in <p> is identical to
+ // "text-align:left".
+ //
+ // Returns false for "text-align:left" of <p>
+ // <div style="text-align:start"><p dir="rtl" style="text-align:left">
+ // because meaning of "text-align:start" in <p> is identical to
+ // "text-align:right".
+ return TextAlignResolvingStartAndEnd(
+ base_text_align, node->EnsureComputedStyle()->Direction()) ==
+ text_align;
+ }
+ if (text_align == CSSValueID::kStart || text_align == CSSValueID::kEnd) {
+ // Returns true for "text-align:start" of <p>
+ // <div style="text-align:left"><p dir="ltr" style="text-align:start">
+ // <div style="text-align:right"><p dir="rtl" style="text-align:start">
+ // Returns false for "text-align:start" of <p>
+ // <div style="text-align:left"><p dir="rtl" style="text-align:start">
+ // <div style="text-align:right"><p dir="ltr" style="text-align:start">
+ return TextAlignResolvingStartAndEnd(
+ text_align, node->EnsureComputedStyle()->Direction()) ==
+ base_text_align;
+ }
+ return false;
}
void EditingStyle::Init(Node* node, PropertiesToInclude properties_to_include) {
@@ -507,7 +549,7 @@ void EditingStyle::Init(Node* node, PropertiesToInclude properties_to_include) {
node = TabSpanElement(node)->parentNode();
else if (IsTabHTMLSpanElement(node))
node = node->parentNode();
-
+ node_ = node;
auto* computed_style_at_position =
MakeGarbageCollected<CSSComputedStyleDeclaration>(node);
mutable_style_ =
@@ -578,6 +620,10 @@ void EditingStyle::RemoveInheritedColorsIfNeeded(
mutable_style_->RemoveProperty(CSSPropertyID::kCaretColor);
}
+CSSValueID EditingStyle::GetProperty(CSSPropertyID property_id) const {
+ return GetIdentifierValue(mutable_style_.Get(), property_id);
+}
+
void EditingStyle::SetProperty(CSSPropertyID property_id,
const String& value,
bool important,
@@ -833,17 +879,21 @@ EditingTriState EditingStyle::TriStateOfStyle(
SecureContextMode secure_context_mode) const {
if (!style || !style->mutable_style_)
return EditingTriState::kFalse;
+ DCHECK(style->node_);
return TriStateOfStyle(
style->mutable_style_->EnsureCSSStyleDeclaration(execution_context),
- kDoNotIgnoreTextOnlyProperties, secure_context_mode);
+ style->node_, kDoNotIgnoreTextOnlyProperties, secure_context_mode);
}
EditingTriState EditingStyle::TriStateOfStyle(
CSSStyleDeclaration* style_to_compare,
+ Node* node,
ShouldIgnoreTextOnlyProperties should_ignore_text_only_properties,
SecureContextMode secure_context_mode) const {
+ // editing/execCommand/query-text-alignment.html requires |node|.
+ DCHECK(node);
MutableCSSPropertyValueSet* difference = GetPropertiesNotIn(
- mutable_style_.Get(), style_to_compare, secure_context_mode);
+ mutable_style_.Get(), node, style_to_compare, secure_context_mode);
// CSS properties that create a visual difference only when applied to text.
static const CSSProperty* kTextOnlyProperties[] = {
@@ -911,7 +961,7 @@ EditingTriState EditingStyle::TriStateOfStyle(
// node.isTextNode() because the node can be an element node. See bug
// http://crbug.com/584939.
EditingTriState node_state = TriStateOfStyle(
- node_style, EditingStyle::kDoNotIgnoreTextOnlyProperties,
+ node_style, &node, EditingStyle::kDoNotIgnoreTextOnlyProperties,
secure_context_mode);
if (node_is_start) {
state = node_state;
@@ -1158,7 +1208,7 @@ bool EditingStyle::ExtractConflictingImplicitStyleOfAttributes(
bool EditingStyle::StyleIsPresentInComputedStyleOfNode(Node* node) const {
return !mutable_style_ ||
GetPropertiesNotIn(
- mutable_style_.Get(),
+ mutable_style_.Get(), node,
MakeGarbageCollected<CSSComputedStyleDeclaration>(node),
node->GetExecutionContext()->GetSecureContextMode())
->IsEmpty();
@@ -1244,8 +1294,9 @@ void EditingStyle::PrepareToApplyAt(
mutable_style_->RemoveEquivalentProperties(style_at_position);
- if (TextAlignResolvingStartAndEnd(mutable_style_.Get()) ==
- TextAlignResolvingStartAndEnd(style_at_position))
+ DCHECK(editing_style_at_position->node_);
+ if (IsRedundantTextAlign(mutable_style_.Get(), style_at_position,
+ editing_style_at_position->node_))
mutable_style_->RemoveProperty(CSSPropertyID::kTextAlign);
if (GetFontColor(mutable_style_.Get()) == GetFontColor(style_at_position))
@@ -1529,7 +1580,7 @@ void EditingStyle::RemoveStyleFromRulesAndContext(Element* element,
StyleResolver::kAllButEmptyCSSRules);
if (style_from_matched_rules && !style_from_matched_rules->IsEmpty()) {
mutable_style_ =
- GetPropertiesNotIn(mutable_style_.Get(),
+ GetPropertiesNotIn(mutable_style_.Get(), element,
style_from_matched_rules->EnsureCSSStyleDeclaration(
element->GetExecutionContext()),
secure_context_mode);
@@ -1548,7 +1599,7 @@ void EditingStyle::RemoveStyleFromRulesAndContext(Element* element,
RemovePropertiesInStyle(computed_style->mutable_style_.Get(),
style_from_matched_rules);
mutable_style_ = GetPropertiesNotIn(
- mutable_style_.Get(),
+ mutable_style_.Get(), element,
computed_style->mutable_style_->EnsureCSSStyleDeclaration(
element->GetExecutionContext()),
secure_context_mode);
@@ -1560,12 +1611,10 @@ void EditingStyle::RemoveStyleFromRulesAndContext(Element* element,
if (IsStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
if (!style_from_matched_rules->GetPropertyCSSValue(
CSSPropertyID::kDisplay) &&
- GetIdentifierValue(mutable_style_.Get(), CSSPropertyID::kDisplay) ==
- CSSValueID::kInline)
+ GetProperty(CSSPropertyID::kDisplay) == CSSValueID::kInline)
mutable_style_->RemoveProperty(CSSPropertyID::kDisplay);
if (!style_from_matched_rules->GetPropertyCSSValue(CSSPropertyID::kFloat) &&
- GetIdentifierValue(mutable_style_.Get(), CSSPropertyID::kFloat) ==
- CSSValueID::kNone)
+ GetProperty(CSSPropertyID::kFloat) == CSSValueID::kNone)
mutable_style_->RemoveProperty(CSSPropertyID::kFloat);
}
}
@@ -1602,6 +1651,7 @@ int EditingStyle::LegacyFontSize(Document* document) const {
void EditingStyle::Trace(Visitor* visitor) const {
visitor->Trace(mutable_style_);
+ visitor->Trace(node_);
}
static void ReconcileTextDecorationProperties(
@@ -1635,14 +1685,19 @@ StyleChange::StyleChange(EditingStyle* style, const Position& position)
apply_subscript_(false),
apply_superscript_(false) {
Document* document = position.GetDocument();
- if (!style || !style->Style() || !document || !document->GetFrame() ||
- !AssociatedElementOf(position))
+ if (!style || !style->Style() || !document || !document->GetFrame())
+ return;
+ Element* const element = AssociatedElementOf(position);
+ if (!element)
return;
- CSSComputedStyleDeclaration* computed_style = EnsureComputedStyle(position);
+ CSSComputedStyleDeclaration* const computed_style =
+ MakeGarbageCollected<CSSComputedStyleDeclaration>(element);
// FIXME: take care of background-color in effect
+ // Note: editing/undo/redo-selection-modify-crash.html needs to pass
+ // |element| to |GetPropertiesNotIn()| to remove "text-align:left".
MutableCSSPropertyValueSet* mutable_style = GetPropertiesNotIn(
- style->Style(), computed_style,
+ style->Style(), element, computed_style,
document->GetExecutionContext()->GetSecureContextMode());
DCHECK(mutable_style);
@@ -1842,9 +1897,11 @@ static bool FontWeightNeedsResolving(const CSSValue* font_weight) {
MutableCSSPropertyValueSet* GetPropertiesNotIn(
CSSPropertyValueSet* style_with_redundant_properties,
+ Node* node,
CSSStyleDeclaration* base_style,
SecureContextMode secure_context_mode) {
DCHECK(style_with_redundant_properties);
+ DCHECK(node);
DCHECK(base_style);
MutableCSSPropertyValueSet* result =
style_with_redundant_properties->MutableCopy();
@@ -1874,9 +1931,7 @@ MutableCSSPropertyValueSet* GetPropertiesNotIn(
GetFontColor(result) == GetFontColor(base_style))
result->RemoveProperty(CSSPropertyID::kColor);
- if (base_style->GetPropertyCSSValueInternal(CSSPropertyID::kTextAlign) &&
- TextAlignResolvingStartAndEnd(result) ==
- TextAlignResolvingStartAndEnd(base_style))
+ if (IsRedundantTextAlign(result, base_style, node))
result->RemoveProperty(CSSPropertyID::kTextAlign);
if (base_style->GetPropertyCSSValueInternal(
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_style.h b/chromium/third_party/blink/renderer/core/editing/editing_style.h
index 08fbbec48db..8bebbbf5491 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_style.h
+++ b/chromium/third_party/blink/renderer/core/editing/editing_style.h
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -152,6 +153,7 @@ class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> {
float FontSizeDelta() const { return font_size_delta_; }
bool HasFontSizeDelta() const { return font_size_delta_ != kNoFontDelta; }
+ CSSValueID GetProperty(CSSPropertyID) const;
void SetProperty(CSSPropertyID,
const String& value,
bool important,
@@ -170,6 +172,7 @@ class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> {
CSSComputedStyleDeclaration*);
void ExtractFontSizeDelta();
EditingTriState TriStateOfStyle(CSSStyleDeclaration* style_to_compare,
+ Node* node,
ShouldIgnoreTextOnlyProperties,
SecureContextMode) const;
bool ConflictsWithInlineStyleOfElement(
@@ -179,6 +182,10 @@ class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> {
void MergeStyle(const CSSPropertyValueSet*, CSSPropertyOverrideMode);
Member<MutableCSSPropertyValueSet> mutable_style_;
+ // This |EditingStyle| is constructed from |node_|. |node_| is null when
+ // this |EditingStyle| is constructed from |CSSPropertyValueSet*| or
+ // |CSSPropertyID|.
+ Member<Node> node_;
bool is_monospace_font_ = false;
float font_size_delta_ = kNoFontDelta;
bool is_vertical_align_ = false;
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_style_test.cc b/chromium/third_party/blink/renderer/core/editing/editing_style_test.cc
index fcce2780f84..68b5368f031 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_style_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_style_test.cc
@@ -35,4 +35,30 @@ TEST_F(EditingStyleTest, mergeInlineStyleOfElement) {
<< "Keep unresolved value on merging style";
}
+// http://crbug.com/957952
+TEST_F(EditingStyleTest, RemoveStyleFromRulesAndContext_TextAlignEffective) {
+ // Note: <div>'s "text-align" is "start".
+ // For <p> with "text-align:start", it equivalents to "text-align:right"
+ SetBodyContent("<div><p dir=rtl id=target>");
+ Element& target = *GetElementById("target");
+ EditingStyle& style = *MakeGarbageCollected<EditingStyle>(
+ CSSPropertyID::kTextAlign, "left", SecureContextMode::kInsecureContext);
+ style.RemoveStyleFromRulesAndContext(&target, target.parentNode());
+
+ EXPECT_EQ(CSSValueID::kLeft, style.GetProperty(CSSPropertyID::kTextAlign));
+}
+
+// http://crbug.com/957952
+TEST_F(EditingStyleTest, RemoveStyleFromRulesAndContext_TextAlignRedundant) {
+ // Note: <div>'s "text-align" is "start".
+ // For <p> with "text-align:start", it equivalents to "text-align:right"
+ SetBodyContent("<div><p dir=rtl id=target>");
+ Element& target = *GetElementById("target");
+ EditingStyle& style = *MakeGarbageCollected<EditingStyle>(
+ CSSPropertyID::kTextAlign, "right", SecureContextMode::kInsecureContext);
+ style.RemoveStyleFromRulesAndContext(&target, target.parentNode());
+
+ EXPECT_EQ(CSSValueID::kInvalid, style.GetProperty(CSSPropertyID::kTextAlign));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc b/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
index 1bf24e39ae8..2442816623f 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -166,6 +166,11 @@ bool IsAtomicNode(const Node* node) {
return node && (!node->hasChildren() || EditingIgnoresContent(*node));
}
+bool IsAtomicNodeInFlatTree(const Node* node) {
+ return node && (!FlatTreeTraversal::HasChildren(*node) ||
+ EditingIgnoresContent(*node));
+}
+
template <typename Traversal>
static int16_t ComparePositions(const Node* container_a,
int offset_a,
@@ -338,8 +343,6 @@ bool IsNodeFullyContained(const EphemeralRange& range, const Node& node) {
// TODO(editing-dev): We should implement real version which refers
// "user-select" CSS property.
-// TODO(editing-dev): We should make |SelectionAdjuster| to use this funciton
-// instead of |isSelectionBondary()|.
bool IsUserSelectContain(const Node& node) {
return IsA<HTMLTextAreaElement>(node) || IsA<HTMLInputElement>(node) ||
IsA<HTMLSelectElement>(node);
@@ -1341,28 +1344,30 @@ HTMLSpanElement* CreateTabSpanElement(Document& document) {
PositionWithAffinity PositionRespectingEditingBoundary(
const Position& position,
- const PhysicalOffset& local_point,
- Node* target_node) {
+ const HitTestResult& hit_test_result) {
+ Node* target_node = hit_test_result.InnerPossiblyPseudoNode();
+ DCHECK(target_node);
const LayoutObject* target_object = target_node->GetLayoutObject();
if (!target_object)
return PositionWithAffinity();
- PhysicalOffset selection_end_point = local_point;
Element* editable_element = RootEditableElementOf(position);
+ if (!editable_element || editable_element->contains(target_node))
+ return hit_test_result.GetPosition();
- if (editable_element && !editable_element->contains(target_node)) {
- const LayoutObject* editable_object = editable_element->GetLayoutObject();
- if (!editable_object)
- return PositionWithAffinity();
-
- // TODO(yosin): Is this kIgnoreTransforms correct here?
- PhysicalOffset absolute_point = target_object->LocalToAbsolutePoint(
- selection_end_point, kIgnoreTransforms);
- selection_end_point = editable_object->AbsoluteToLocalPoint(
- absolute_point, kIgnoreTransforms);
- target_object = editable_object;
- }
+ const LayoutObject* editable_object = editable_element->GetLayoutObject();
+ if (!editable_object)
+ return PositionWithAffinity();
+ // TODO(yosin): Is this kIgnoreTransforms correct here?
+ PhysicalOffset selection_end_point = hit_test_result.LocalPoint();
+ PhysicalOffset absolute_point = target_object->LocalToAbsolutePoint(
+ selection_end_point, kIgnoreTransforms);
+ selection_end_point =
+ editable_object->AbsoluteToLocalPoint(absolute_point, kIgnoreTransforms);
+ target_object = editable_object;
+ // TODO(kojii): Support fragment-based |PositionForPoint|. LayoutObject-based
+ // |PositionForPoint| may not work if NG block fragmented.
return target_object->PositionForPoint(selection_end_point);
}
@@ -1374,15 +1379,28 @@ PositionWithAffinity AdjustForEditingBoundary(
const Node& node = *position.ComputeContainerNode();
if (HasEditableStyle(node))
return position_with_affinity;
+ // TODO(yosin): Once we fix |MostBackwardCaretPosition()| to handle
+ // positions other than |kOffsetInAnchor|, we don't need to use
+ // |adjusted_position|, e.g. <outer><inner contenteditable> with position
+ // before <inner> vs. outer@0[1].
+ // [1] editing/selection/click-outside-editable-div.html
+ const Position& adjusted_position = HasEditableStyle(*position.AnchorNode())
+ ? position.ToOffsetInAnchor()
+ : position;
const Position& forward =
- MostForwardCaretPosition(position, kCanCrossEditingBoundary);
+ MostForwardCaretPosition(adjusted_position, kCanCrossEditingBoundary);
if (HasEditableStyle(*forward.ComputeContainerNode()))
return PositionWithAffinity(forward);
const Position& backward =
- MostBackwardCaretPosition(position, kCanCrossEditingBoundary);
+ MostBackwardCaretPosition(adjusted_position, kCanCrossEditingBoundary);
if (HasEditableStyle(*backward.ComputeContainerNode()))
return PositionWithAffinity(backward);
- return position_with_affinity;
+ return PositionWithAffinity(adjusted_position,
+ position_with_affinity.Affinity());
+}
+
+PositionWithAffinity AdjustForEditingBoundary(const Position& position) {
+ return AdjustForEditingBoundary(PositionWithAffinity(position));
}
Position ComputePositionForNodeRemoval(const Position& position,
@@ -1392,20 +1410,13 @@ Position ComputePositionForNodeRemoval(const Position& position,
Node* container_node;
Node* anchor_node;
switch (position.AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
- container_node = position.ComputeContainerNode();
- if (!container_node ||
- !node.IsShadowIncludingInclusiveAncestorOf(*container_node)) {
- return position;
- }
- return Position::InParentBeforeNode(node);
case PositionAnchorType::kAfterChildren:
container_node = position.ComputeContainerNode();
if (!container_node ||
!node.IsShadowIncludingInclusiveAncestorOf(*container_node)) {
return position;
}
- return Position::InParentAfterNode(node);
+ return Position::InParentBeforeNode(node);
case PositionAnchorType::kOffsetInAnchor:
container_node = position.ComputeContainerNode();
if (container_node == node.parentNode() &&
@@ -1423,7 +1434,7 @@ Position ComputePositionForNodeRemoval(const Position& position,
if (!anchor_node ||
!node.IsShadowIncludingInclusiveAncestorOf(*anchor_node))
return position;
- return Position::InParentAfterNode(node);
+ return Position::InParentBeforeNode(node);
case PositionAnchorType::kBeforeAnchor:
anchor_node = position.AnchorNode();
if (!anchor_node ||
@@ -1550,6 +1561,33 @@ VisiblePosition VisiblePositionForIndex(int index, ContainerNode* scope) {
return CreateVisiblePosition(range.StartPosition());
}
+template <typename Strategy>
+bool AreSameRangesAlgorithm(Node* node,
+ const PositionTemplate<Strategy>& start_position,
+ const PositionTemplate<Strategy>& end_position) {
+ DCHECK(node);
+ const EphemeralRange range =
+ CreateVisibleSelection(
+ SelectionInDOMTree::Builder().SelectAllChildren(*node).Build())
+ .ToNormalizedEphemeralRange();
+ return ToPositionInDOMTree(start_position) == range.StartPosition() &&
+ ToPositionInDOMTree(end_position) == range.EndPosition();
+}
+
+bool AreSameRanges(Node* node,
+ const Position& start_position,
+ const Position& end_position) {
+ return AreSameRangesAlgorithm<EditingStrategy>(node, start_position,
+ end_position);
+}
+
+bool AreSameRanges(Node* node,
+ const PositionInFlatTree& start_position,
+ const PositionInFlatTree& end_position) {
+ return AreSameRangesAlgorithm<EditingInFlatTreeStrategy>(node, start_position,
+ end_position);
+}
+
bool IsRenderedAsNonInlineTableImageOrHR(const Node* node) {
if (!node)
return false;
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_utilities.h b/chromium/third_party/blink/renderer/core/editing/editing_utilities.h
index 861779c20fe..e530eb7c763 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_utilities.h
+++ b/chromium/third_party/blink/renderer/core/editing/editing_utilities.h
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/editing/editing_boundary.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/events/input_event.h"
+#include "third_party/blink/renderer/core/html/html_br_element.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -53,6 +54,7 @@ enum class PositionMoveType {
class Document;
class Element;
class HTMLElement;
+class HTMLImageElement;
class HTMLSpanElement;
struct LocalCaretRect;
class Node;
@@ -156,6 +158,7 @@ inline bool CanHaveChildrenForEditing(const Node* node) {
}
bool IsAtomicNode(const Node*);
+bool IsAtomicNodeInFlatTree(const Node*);
CORE_EXPORT bool IsEnclosingBlock(const Node*);
CORE_EXPORT bool IsTabHTMLSpanElement(const Node*);
bool IsTabHTMLSpanElementTextNode(const Node*);
@@ -259,10 +262,8 @@ CORE_EXPORT bool IsEditablePosition(const Position&);
bool IsEditablePosition(const PositionInFlatTree&);
bool IsRichlyEditablePosition(const Position&);
-PositionWithAffinity PositionRespectingEditingBoundary(
- const Position&,
- const PhysicalOffset& local_point,
- Node* target_node);
+PositionWithAffinity PositionRespectingEditingBoundary(const Position&,
+ const HitTestResult&);
// Move specified position to start/end of non-editable region.
// If it can be found, we prefer a visually equivalent position that is
@@ -273,8 +274,10 @@ PositionWithAffinity PositionRespectingEditingBoundary(
// =>
// <editable>|<non-editable>abc</non-editable></editable>
PositionWithAffinity AdjustForEditingBoundary(const PositionWithAffinity&);
+PositionWithAffinity AdjustForEditingBoundary(const Position&);
-Position ComputePositionForNodeRemoval(const Position&, const Node&);
+CORE_EXPORT Position ComputePositionForNodeRemoval(const Position&,
+ const Node&);
// TODO(editing-dev): These two functions should be eliminated.
CORE_EXPORT Position PositionBeforeNode(const Node&);
@@ -294,6 +297,13 @@ EphemeralRangeInFlatTree NormalizeRange(const EphemeralRangeInFlatTree&);
CORE_EXPORT VisiblePosition VisiblePositionForIndex(int index,
ContainerNode* scope);
+bool AreSameRanges(Node* node,
+ const Position& start_position,
+ const Position& end_position);
+bool AreSameRanges(Node* node,
+ const PositionInFlatTree& start_position,
+ const PositionInFlatTree& end_position);
+
// -------------------------------------------------------------------------
// HTMLElement
// -------------------------------------------------------------------------
diff --git a/chromium/third_party/blink/renderer/core/editing/editing_utilities_test.cc b/chromium/third_party/blink/renderer/core/editing/editing_utilities_test.cc
index 3c3a5ea8955..2ed51c13857 100644
--- a/chromium/third_party/blink/renderer/core/editing/editing_utilities_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editing_utilities_test.cc
@@ -12,12 +12,29 @@ namespace blink {
class EditingUtilitiesTest : public EditingTestBase {};
+TEST_F(EditingUtilitiesTest, ComputePositionForNodeRemovalAfterChildren) {
+ SetBodyContent("<div id=a><p id=b><img id=c></p></div>");
+ const Position position = Position::LastPositionInNode(*GetElementById("c"));
+ // Simulate <p> will be removed.
+ EXPECT_EQ(Position(*GetElementById("a"), 0),
+ ComputePositionForNodeRemoval(position, *GetElementById("b")));
+}
+
+TEST_F(EditingUtilitiesTest, ComputePositionForNodeRemovalAfterNode) {
+ // "editing/deleting/delete-start-block.html" hits this case.
+ SetBodyContent("<div id=a><p id=b><img id=c></p></div>");
+ const Position position = Position::AfterNode(*GetElementById("c"));
+ // Simulate <p> will be removed.
+ EXPECT_EQ(Position(*GetElementById("a"), 0),
+ ComputePositionForNodeRemoval(position, *GetElementById("b")));
+}
+
TEST_F(EditingUtilitiesTest, DirectionOfEnclosingBlockOf) {
const char* body_content =
- "<p id='host'><b id='one'></b><b id='two'>22</b></p>";
+ "<p id='host'><b slot='#one' id='one'></b><b slot='#two' "
+ "id='two'>22</b></p>";
const char* shadow_content =
- "<content select=#two></content><p dir=rtl><content "
- "select=#one></content><p>";
+ "<slot name=#two></slot><p dir=rtl><slot name=#one></slot><p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one");
@@ -27,12 +44,14 @@ TEST_F(EditingUtilitiesTest, DirectionOfEnclosingBlockOf) {
DirectionOfEnclosingBlockOf(PositionInFlatTree(one, 0)));
}
-TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(EditingUtilitiesTest,
+ DISABLED_firstEditablePositionAfterPositionInRoot) {
const char* body_content =
- "<p id='host' contenteditable><b id='one'>1</b><b id='two'>22</b></p>";
+ "<p id='host' contenteditable><b slot='#one' id='one'>1</b><b "
+ "slot='#two' id='two'>22</b></p>";
const char* shadow_content =
- "<content select=#two></content><content select=#one></content><b "
- "id='three'>333</b>";
+ "<slot name=#two></slot><slot name=#one></slot><b id='three'>333</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* host = GetDocument().getElementById("host");
@@ -42,7 +61,9 @@ TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) {
EXPECT_EQ(Position(one, 0),
FirstEditablePositionAfterPositionInRoot(Position(one, 0), *host));
- EXPECT_EQ(Position(one->firstChild(), 0),
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // end of "22".
+ EXPECT_EQ(Position(two->firstChild(), 2),
CreateVisiblePosition(FirstEditablePositionAfterPositionInRoot(
Position(one, 0), *host))
.DeepEquivalent());
@@ -50,6 +71,8 @@ TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) {
EXPECT_EQ(PositionInFlatTree(one, 0),
FirstEditablePositionAfterPositionInRoot(PositionInFlatTree(one, 0),
*host));
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // end of "22".
EXPECT_EQ(PositionInFlatTree(two->firstChild(), 2),
CreateVisiblePosition(FirstEditablePositionAfterPositionInRoot(
PositionInFlatTree(one, 0), *host))
@@ -58,7 +81,9 @@ TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) {
EXPECT_EQ(
Position::FirstPositionInNode(*host),
FirstEditablePositionAfterPositionInRoot(Position(three, 0), *host));
- EXPECT_EQ(Position(one->firstChild(), 0),
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // beginning of "22".
+ EXPECT_EQ(Position(two->firstChild(), 0),
CreateVisiblePosition(FirstEditablePositionAfterPositionInRoot(
Position(three, 0), *host))
.DeepEquivalent());
@@ -72,10 +97,9 @@ TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) {
}
TEST_F(EditingUtilitiesTest, enclosingBlock) {
- const char* body_content = "<p id='host'><b id='one'>11</b></p>";
+ const char* body_content = "<p id='host'><b slot='#one' id='one'>11</b></p>";
const char* shadow_content =
- "<content select=#two></content><div id='three'><content "
- "select=#one></content></div>";
+ "<slot name=#two></slot><div id='three'><slot name=#one></slot></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* host = GetDocument().getElementById("host");
@@ -89,10 +113,9 @@ TEST_F(EditingUtilitiesTest, enclosingBlock) {
}
TEST_F(EditingUtilitiesTest, enclosingNodeOfType) {
- const char* body_content = "<p id='host'><b id='one'>11</b></p>";
+ const char* body_content = "<p id='host'><b slot='#one' id='one'>11</b></p>";
const char* shadow_content =
- "<content select=#two></content><div id='three'><content "
- "select=#one></div></content>";
+ "<slot name=#two></slot><div id='three'><slot name=#one></div></slot>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* host = GetDocument().getElementById("host");
@@ -144,28 +167,32 @@ TEST_F(EditingUtilitiesTest, RepeatString) {
EXPECT_EQ("xyzxyzxyz", RepeatString("xyz", 3));
}
-TEST_F(EditingUtilitiesTest, tableElementJustBefore) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(EditingUtilitiesTest, DISABLED_tableElementJustBefore) {
const char* body_content =
- "<div contenteditable id=host><table "
- "id=table><tr><td>1</td></tr></table><b id=two>22</b></div>";
+ "<div contenteditable id=host><table slot=#table "
+ "id=table><tr><td>1</td></tr></table><b slot=#two id=two>22</b></div>";
const char* shadow_content =
- "<content select=#two></content><content select=#table></content>";
+ "<slot name=#two></slot><slot name=#table></slot>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* host = GetDocument().getElementById("host");
Node* table = GetDocument().getElementById("table");
EXPECT_EQ(table, TableElementJustBefore(VisiblePosition::AfterNode(*table)));
+ // TODO(crbug.com/1157146): This returns null instead of the table.
EXPECT_EQ(table, TableElementJustBefore(
VisiblePositionInFlatTree::AfterNode(*table)));
EXPECT_EQ(table, TableElementJustBefore(
VisiblePosition::LastPositionInNode(*table)));
+ // TODO(crbug.com/1157146): This returns null instead of the table.
EXPECT_EQ(table, TableElementJustBefore(CreateVisiblePosition(
PositionInFlatTree::LastPositionInNode(*table))));
EXPECT_EQ(nullptr,
TableElementJustBefore(CreateVisiblePosition(Position(host, 2))));
+ // TODO(crbug.com/1157146): This returns null instead of the table.
EXPECT_EQ(table, TableElementJustBefore(
CreateVisiblePosition(PositionInFlatTree(host, 2))));
@@ -175,15 +202,19 @@ TEST_F(EditingUtilitiesTest, tableElementJustBefore) {
EXPECT_EQ(nullptr,
TableElementJustBefore(VisiblePosition::LastPositionInNode(*host)));
+ // TODO(crbug.com/1157146): This returns null instead of the table.
EXPECT_EQ(table, TableElementJustBefore(CreateVisiblePosition(
PositionInFlatTree::LastPositionInNode(*host))));
}
-TEST_F(EditingUtilitiesTest, lastEditablePositionBeforePositionInRoot) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(EditingUtilitiesTest,
+ DISABLED_lastEditablePositionBeforePositionInRoot) {
const char* body_content =
- "<p id='host' contenteditable><b id='one'>1</b><b id='two'>22</b></p>";
+ "<p id='host' contenteditable><b slot=#one id='one'>1</b><b slot=#two "
+ "id='two'>22</b></p>";
const char* shadow_content =
- "<content select=#two></content><content select=#one></content><b "
+ "<slot name=#two></slot><slot name=#one></slot><b "
"id='three'>333</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -194,7 +225,9 @@ TEST_F(EditingUtilitiesTest, lastEditablePositionBeforePositionInRoot) {
EXPECT_EQ(Position(one, 0),
LastEditablePositionBeforePositionInRoot(Position(one, 0), *host));
- EXPECT_EQ(Position(one->firstChild(), 0),
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // end of "22".
+ EXPECT_EQ(Position(two->firstChild(), 2),
CreateVisiblePosition(LastEditablePositionBeforePositionInRoot(
Position(one, 0), *host))
.DeepEquivalent());
@@ -202,6 +235,8 @@ TEST_F(EditingUtilitiesTest, lastEditablePositionBeforePositionInRoot) {
EXPECT_EQ(PositionInFlatTree(one, 0),
LastEditablePositionBeforePositionInRoot(PositionInFlatTree(one, 0),
*host));
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // end of "22".
EXPECT_EQ(PositionInFlatTree(two->firstChild(), 2),
CreateVisiblePosition(LastEditablePositionBeforePositionInRoot(
PositionInFlatTree(one, 0), *host))
@@ -210,24 +245,29 @@ TEST_F(EditingUtilitiesTest, lastEditablePositionBeforePositionInRoot) {
EXPECT_EQ(
Position::FirstPositionInNode(*host),
LastEditablePositionBeforePositionInRoot(Position(three, 0), *host));
- EXPECT_EQ(Position(one->firstChild(), 0),
+ // TODO(crbug.com/1157146): This returns the beginning of "1" instead of the
+ // beginning of "22".
+ EXPECT_EQ(Position(two->firstChild(), 0),
CreateVisiblePosition(LastEditablePositionBeforePositionInRoot(
Position(three, 0), *host))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree::FirstPositionInNode(*host),
LastEditablePositionBeforePositionInRoot(
PositionInFlatTree(three, 0), *host));
+ // TODO(crbug.com/1157146): This returns nullptr instead of the beginning of
+ // "22".
EXPECT_EQ(PositionInFlatTree(two->firstChild(), 0),
CreateVisiblePosition(LastEditablePositionBeforePositionInRoot(
PositionInFlatTree(three, 0), *host))
.DeepEquivalent());
}
-TEST_F(EditingUtilitiesTest, NextNodeIndex) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(EditingUtilitiesTest, DISABLED_NextNodeIndex) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
- const char* shadow_content =
- "<content select=#two></content><content select=#one></content>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
+ const char* shadow_content = "<slot name=#two></slot><slot name=#one></slot>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* host = GetDocument().getElementById("host");
@@ -236,6 +276,7 @@ TEST_F(EditingUtilitiesTest, NextNodeIndex) {
EXPECT_EQ(
Position(host, 3),
NextPositionOf(Position(two, 1), PositionMoveType::kGraphemeCluster));
+ // TODO(crbug.com/1157146): This returns the slot instead of the <p>.
EXPECT_EQ(PositionInFlatTree(host, 1),
NextPositionOf(PositionInFlatTree(two, 1),
PositionMoveType::kGraphemeCluster));
@@ -243,18 +284,17 @@ TEST_F(EditingUtilitiesTest, NextNodeIndex) {
TEST_F(EditingUtilitiesTest, NextVisuallyDistinctCandidate) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b><b "
- "id='three'>33</b></p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b><b slot='#three' id='three'>33</b></p>";
const char* shadow_content =
- "<content select=#two></content><content select=#one></content><content "
- "select=#three></content>";
+ "<slot name=#two></slot><slot name=#one></slot><slot name=#three></slot>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one");
Node* two = GetDocument().getElementById("two");
Node* three = GetDocument().getElementById("three");
- EXPECT_EQ(Position(two->firstChild(), 1),
+ EXPECT_EQ(Position(two->firstChild(), 0),
NextVisuallyDistinctCandidate(Position(one, 1)));
EXPECT_EQ(PositionInFlatTree(three->firstChild(), 1),
NextVisuallyDistinctCandidate(PositionInFlatTree(one, 1)));
diff --git a/chromium/third_party/blink/renderer/core/editing/editor.cc b/chromium/third_party/blink/renderer/core/editing/editor.cc
index b06a2cc0b44..0a809e99445 100644
--- a/chromium/third_party/blink/renderer/core/editing/editor.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editor.cc
@@ -886,7 +886,7 @@ void Editor::SetMarkedTextMatchesAreHighlighted(bool flag) {
void Editor::RespondToChangedSelection() {
GetSpellChecker().RespondToChangedSelection();
frame_->Client()->DidChangeSelection(
- GetFrameSelection().GetSelectionInDOMTree().Type() != kRangeSelection);
+ !GetFrameSelection().GetSelectionInDOMTree().IsRange());
SetStartNewKillRingSequence(true);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/editor.h b/chromium/third_party/blink/renderer/core/editing/editor.h
index 9734e127760..3ae74e07c27 100644
--- a/chromium/third_party/blink/renderer/core/editing/editor.h
+++ b/chromium/third_party/blink/renderer/core/editing/editor.h
@@ -49,6 +49,7 @@ class EditorCommand;
class FrameSelection;
class LocalFrame;
class HitTestResult;
+class KeyboardEvent;
class KillRing;
class SpellChecker;
class CSSPropertyValueSet;
diff --git a/chromium/third_party/blink/renderer/core/editing/editor_key_bindings.cc b/chromium/third_party/blink/renderer/core/editing/editor_key_bindings.cc
index d695d23a0f5..5b98487dc13 100644
--- a/chromium/third_party/blink/renderer/core/editing/editor_key_bindings.cc
+++ b/chromium/third_party/blink/renderer/core/editing/editor_key_bindings.cc
@@ -26,11 +26,14 @@
#include "third_party/blink/renderer/core/editing/editor.h"
+#include "base/i18n/uchar.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/renderer/core/editing/commands/editor_command.h"
#include "third_party/blink/renderer/core/editing/editing_behavior.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/ime/edit_context.h"
+#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -59,7 +62,20 @@ bool Editor::HandleEditingKeyboardEvent(KeyboardEvent* evt) {
if (command.Execute(evt))
return true;
- if (!Behavior().ShouldInsertCharacter(*evt) || !CanEdit())
+ if (!Behavior().ShouldInsertCharacter(*evt))
+ return false;
+
+ // If EditContext is active, redirect text to EditContext, otherwise, send
+ // text to the focused element.
+ auto* edit_context =
+ GetFrame().GetInputMethodController().GetActiveEditContext();
+ if (edit_context) {
+ WebString text(WTF::String(key_event->text));
+ edit_context->InsertText(text);
+ return true;
+ }
+
+ if (!CanEdit())
return false;
const Element* const focused_element =
@@ -74,11 +90,12 @@ bool Editor::HandleEditingKeyboardEvent(KeyboardEvent* evt) {
return false;
// Return true to prevent default action. e.g. Space key scroll.
- if (DispatchBeforeInputInsertText(evt->target()->ToNode(), key_event->text) !=
+ if (DispatchBeforeInputInsertText(evt->target()->ToNode(),
+ base::i18n::ToUCharPtr(key_event->text)) !=
DispatchEventResult::kNotCanceled)
return true;
- return InsertText(key_event->text, evt);
+ return InsertText(base::i18n::ToUCharPtr(key_event->text), evt);
}
void Editor::HandleKeyboardEvent(KeyboardEvent* evt) {
diff --git a/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc b/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
index 9e8dbef2d1e..2571bab072f 100644
--- a/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
+++ b/chromium/third_party/blink/renderer/core/editing/element_inner_text.cc
@@ -464,6 +464,20 @@ String Element::innerText() {
// boxes in the layout tree.
GetDocument().UpdateStyleAndLayoutForNode(this,
DocumentUpdateReason::kJavaScript);
+ return GetInnerTextWithoutUpdate();
+}
+
+// Used for callers that must ensure no document lifecycle rewind.
+String Element::GetInnerTextWithoutUpdate() {
+ // TODO(https:://crbug.com/1165850 https:://crbug.com/1166296) Layout should
+ // always be clean here, but the lifecycle does not report the correctly
+ // updated value unless servicing animations. Fix the UpdateStyleAndLayout()
+ // to correctly advance the lifecycle, and then update the following DCHECK to
+ // always require clean layout in active documents.
+ // DCHECK(!GetDocument().IsActive() || !GetDocument().GetPage() ||
+ // GetDocument().Lifecycle().GetState() >=
+ // DocumentLifecycle::kLayoutClean)
+ // << "Layout must be clean when GetInnerTextWithoutUpdate() is called.";
return ElementInnerTextCollector().RunOn(*this);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc b/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
index a85ce97e5b2..941da596c1c 100644
--- a/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/element_inner_text_test.cc
@@ -60,4 +60,12 @@ TEST_P(ElementInnerTest, OverflowingListItemWithFloatFirstLetter) {
EXPECT_EQ("foo", target.innerText());
}
+// https://crbug.com/1164747
+TEST_P(ElementInnerTest, GetInnerTextWithoutUpdate) {
+ SetBodyContent("<div id=target>ab<span>c</span></div>");
+ Element& target = *GetDocument().getElementById("target");
+ EXPECT_EQ("abc", target.innerText());
+ EXPECT_EQ("abc", target.GetInnerTextWithoutUpdate());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/ephemeral_range.cc b/chromium/third_party/blink/renderer/core/editing/ephemeral_range.cc
index 1d193eb467a..d95b3918b26 100644
--- a/chromium/third_party/blink/renderer/core/editing/ephemeral_range.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ephemeral_range.cc
@@ -27,7 +27,7 @@ EphemeralRangeTemplate<Strategy>::EphemeralRangeTemplate(
const PositionTemplate<Strategy>& start,
const PositionTemplate<Strategy>& end)
: start_position_(start),
- end_position_(end)
+ end_position_(start.IsEquivalent(end) ? start : end)
#if DCHECK_IS_ON()
,
dom_tree_version_(start.IsNull() ? 0
@@ -212,16 +212,6 @@ std::ostream& operator<<(std::ostream& ostream,
EphemeralRangeInFlatTree ToEphemeralRangeInFlatTree(
const EphemeralRange& range) {
- // We need to update the distribution before getting the position in the flat
- // tree, since that operation requires us to navigate the flat tree.
- if (range.StartPosition().AnchorNode()) {
- range.StartPosition()
- .AnchorNode()
- ->UpdateDistributionForFlatTreeTraversal();
- }
- if (range.EndPosition().AnchorNode()) {
- range.EndPosition().AnchorNode()->UpdateDistributionForFlatTreeTraversal();
- }
PositionInFlatTree start = ToPositionInFlatTree(range.StartPosition());
PositionInFlatTree end = ToPositionInFlatTree(range.EndPosition());
if (start.IsNull() || end.IsNull() ||
diff --git a/chromium/third_party/blink/renderer/core/editing/ephemeral_range_test.cc b/chromium/third_party/blink/renderer/core/editing/ephemeral_range_test.cc
index 930aa4ec723..98715ce2d1b 100644
--- a/chromium/third_party/blink/renderer/core/editing/ephemeral_range_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ephemeral_range_test.cc
@@ -80,15 +80,15 @@ TEST_F(EphemeralRangeTest, rangeShadowTraversal) {
const char* body_content =
"<b id='zero'>0</b>"
"<p id='host'>"
- "<b id='one'>1</b>"
- "<b id='two'>22</b>"
+ "<b slot='#one' id='one'>1</b>"
+ "<b slot='#two' id='two'>22</b>"
"<b id='three'>333</b>"
"</p>"
"<b id='four'>4444</b>";
const char* shadow_content =
"<p id='five'>55555</p>"
- "<content select=#two></content>"
- "<content select=#one></content>"
+ "<slot name=#two></slot>"
+ "<slot name=#one></slot>"
"<span id='six'>666666</span>"
"<p id='seven'>7777777</p>";
SetBodyContent(body_content);
@@ -96,9 +96,9 @@ TEST_F(EphemeralRangeTest, rangeShadowTraversal) {
const std::string expected_nodes(
"[BODY][B id=\"zero\"][#text \"0\"][P id=\"host\"][P id=\"five\"][#text "
- "\"55555\"][B id=\"two\"][#text \"22\"][B id=\"one\"][#text \"1\"][SPAN "
- "id=\"six\"][#text \"666666\"][P id=\"seven\"][#text \"7777777\"][B "
- "id=\"four\"][#text \"4444\"]");
+ "\"55555\"][SLOT][B id=\"two\"][#text \"22\"][SLOT][B id=\"one\"][#text "
+ "\"1\"][SPAN id=\"six\"][#text \"666666\"][P id=\"seven\"][#text "
+ "\"7777777\"][B id=\"four\"][#text \"4444\"]");
EXPECT_EQ(expected_nodes, TraverseRange<FlatTreeTraversal>(GetBodyRange()));
EXPECT_EQ(TraverseRange<FlatTreeTraversal>(GetBodyRange()),
@@ -140,14 +140,14 @@ TEST_F(EphemeralRangeTest, rangeTraversalLimitedFlatTree) {
const char* body_content =
"<b id='zero'>0</b>"
"<p id='host'>"
- "<b id='one'>1</b>"
- "<b id='two'>22</b>"
+ "<b slot='#one' id='one'>1</b>"
+ "<b slot='#two' id='two'>22</b>"
"</p>"
"<b id='three'>333</b>";
const char* shadow_content =
"<p id='four'>4444</p>"
- "<content select=#two></content>"
- "<content select=#one></content>"
+ "<slot name=#two></slot>"
+ "<slot name=#one></slot>"
"<span id='five'>55555</span>"
"<p id='six'>666666</p>";
SetBodyContent(body_content);
@@ -206,14 +206,14 @@ TEST_F(EphemeralRangeTest, commonAncesstorFlatTree) {
const char* body_content =
"<b id='zero'>0</b>"
"<p id='host'>"
- "<b id='one'>1</b>"
- "<b id='two'>22</b>"
+ "<b slot='#one' id='one'>1</b>"
+ "<b slot='#two' id='two'>22</b>"
"</p>"
"<b id='three'>333</b>";
const char* shadow_content =
"<p id='four'>4444</p>"
- "<content select=#two></content>"
- "<content select=#one></content>"
+ "<slot name=#two></slot>"
+ "<slot name=#one></slot>"
"<p id='five'>55555</p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -226,4 +226,28 @@ TEST_F(EphemeralRangeTest, commonAncesstorFlatTree) {
range.CommonAncestorContainer());
}
+TEST_F(EphemeralRangeTest, EquivalentPositions) {
+ SetBodyContent(
+ "<div id='first'></div>"
+ "<div id='last'></div>");
+ Element* first = GetDocument().getElementById("first");
+ Element* last = GetDocument().getElementById("last");
+ Position after_first = Position::AfterNode(*first);
+ Position before_last = Position::BeforeNode(*last);
+
+ // Test ranges created with different but equivalent positions.
+ EXPECT_NE(after_first, before_last);
+ EXPECT_TRUE(after_first.IsEquivalent(before_last));
+
+ EphemeralRange range1(after_first, before_last);
+ EXPECT_TRUE(range1.IsCollapsed());
+ EXPECT_EQ(after_first, range1.StartPosition());
+ EXPECT_EQ(after_first, range1.EndPosition());
+
+ EphemeralRange range2(before_last, after_first);
+ EXPECT_TRUE(range2.IsCollapsed());
+ EXPECT_EQ(before_last, range2.StartPosition());
+ EXPECT_EQ(before_last, range2.EndPosition());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.cc b/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.cc
new file mode 100644
index 00000000000..8163219c1fa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.cc
@@ -0,0 +1,81 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "third_party/blink/renderer/core/editing/finder/async_find_buffer.h"
+
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
+
+namespace blink {
+
+namespace {
+// Indicates how long FindBuffer task should run before pausing the work.
+constexpr base::TimeDelta kFindBufferTaskTimeoutMs =
+ base::TimeDelta::FromMilliseconds(100);
+} // namespace
+
+void AsyncFindBuffer::FindMatchInRange(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) {
+ iterations_ = 0;
+ search_start_time_ = base::TimeTicks::Now();
+ NextIteration(search_range, search_text, options,
+ std::move(completeCallback));
+}
+
+void AsyncFindBuffer::Cancel() {
+ pending_find_match_task_.Cancel();
+}
+
+void AsyncFindBuffer::Run(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) {
+ // If range is not connected we should stop the search.
+ if (search_range->IsNull() || !search_range->IsConnected()) {
+ std::move(completeCallback).Run(EphemeralRangeInFlatTree());
+ return;
+ }
+ search_range->StartPosition().GetDocument()->UpdateStyleAndLayout(
+ DocumentUpdateReason::kFindInPage);
+
+ EphemeralRangeInFlatTree range = FindBuffer::FindMatchInRange(
+ search_range->ToEphemeralRange(), search_text, options,
+ kFindBufferTaskTimeoutMs);
+
+ if (range.IsNotNull() && range.IsCollapsed()) {
+ // FindBuffer reached time limit - Start/End of range is last checked
+ // position
+ search_range->SetStart(range.StartPosition());
+ NextIteration(search_range, search_text, options,
+ std::move(completeCallback));
+ return;
+ }
+
+ // Search finished, return the result
+ UMA_HISTOGRAM_COUNTS_100("SharedHighlights.AsyncTask.Iterations",
+ iterations_);
+ UMA_HISTOGRAM_TIMES("SharedHighlights.AsyncTask.SearchDuration",
+ base::TimeTicks::Now() - search_start_time_);
+
+ std::move(completeCallback).Run(range);
+}
+
+void AsyncFindBuffer::NextIteration(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) {
+ iterations_++;
+ pending_find_match_task_ = PostCancellableTask(
+ *search_range->StartPosition()
+ .GetDocument()
+ ->GetTaskRunner(TaskType::kInternalFindInPage)
+ .get(),
+ FROM_HERE,
+ WTF::Bind(&AsyncFindBuffer::Run, WrapWeakPersistent(this),
+ WrapWeakPersistent(search_range), search_text, options,
+ std::move(completeCallback)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.h b/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.h
new file mode 100644
index 00000000000..9a8bc48137a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/async_find_buffer.h
@@ -0,0 +1,52 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_ASYNC_FIND_BUFFER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_ASYNC_FIND_BUFFER_H_
+
+#include "base/callback.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer_runner.h"
+#include "third_party/blink/renderer/core/editing/finder/find_options.h"
+#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
+
+namespace blink {
+// This is used as an asynchronous wrapper around FindBuffer to provide a
+// callback-based interface.
+class AsyncFindBuffer final : public FindBufferRunner {
+ public:
+ explicit AsyncFindBuffer() = default;
+ ~AsyncFindBuffer() = default;
+
+ void FindMatchInRange(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) override;
+ void Cancel() override;
+ bool IsActive() override { return pending_find_match_task_.IsActive(); }
+
+ private:
+ void Run(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback);
+
+ void NextIteration(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback);
+
+ TaskHandle pending_find_match_task_;
+
+ // Number of iterations it took to complete |FindMatchInRange| request. Used
+ // for recording UMA histograms.
+ int iterations_ = 0;
+
+ // |FindMatchInRange| start time. Used for recorsing UMA histograms.
+ base::TimeTicks search_start_time_;
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_ASYNC_FIND_BUFFER_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc
index 7468ca85152..b5b3480c2b2 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
@@ -13,6 +14,7 @@
#include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
+#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
@@ -37,6 +39,8 @@ bool ShouldIgnoreContents(const Node& node) {
return false;
return (!element->ShouldSerializeEndTag() &&
!IsA<HTMLInputElement>(*element)) ||
+ (IsA<TextControlElement>(*element) &&
+ !To<TextControlElement>(*element).SuggestedValue().IsEmpty()) ||
IsA<HTMLIFrameElement>(*element) || IsA<HTMLImageElement>(*element) ||
IsA<HTMLMeterElement>(*element) || IsA<HTMLObjectElement>(*element) ||
IsA<HTMLProgressElement>(*element) ||
@@ -65,17 +69,6 @@ Node* GetNonSearchableAncestor(const Node& node) {
return nullptr;
}
-// TODO(gayane): Consider using |ComputedStyle::IsDisplayInlineType| or
-// |ElementInnerTextCollector::IsDisplayBlockLevel|. See
-// http://crrev.com/c/2283244/10/third_party/blink/renderer/core/editing/finder/find_buffer.cc#69
-// for context.
-// Returns true if the given |display| is considered a 'block'
-bool IsBlockLevel(EDisplay display) {
- return display == EDisplay::kBlock || display == EDisplay::kTable ||
- display == EDisplay::kFlowRoot || display == EDisplay::kGrid ||
- display == EDisplay::kFlex || display == EDisplay::kListItem;
-}
-
// Returns the next/previous node after |start_node| (including start node) that
// is a text node and is searchable and visible.
template <class Direction>
@@ -109,6 +102,23 @@ Node* GetVisibleTextNode(Node& start_node) {
return nullptr;
}
+// Returns true if the given |node| is considered a 'block' for find-in-page,
+// scroll-to-text and link-to-text even though it might not have a separate
+// LayoutBlockFlow. For example, input fields should be considered a block
+// boundary.
+bool IsExplicitFindBoundary(const Node& node) {
+ return IsTextControl(node);
+}
+
+// Checks if |start| appears before |end| in flat-tree order.
+bool AreInOrder(const Node& start, const Node& end) {
+ const Node* node = &start;
+ while (node && !node->isSameNode(&end)) {
+ node = FlatTreeTraversal::Next(*node);
+ }
+ return node->isSameNode(&end);
+}
+
} // namespace
// FindBuffer implementation.
@@ -140,15 +150,29 @@ bool FindBuffer::IsInvalidMatch(MatchResultICU match) const {
EphemeralRangeInFlatTree FindBuffer::FindMatchInRange(
const EphemeralRangeInFlatTree& range,
String search_text,
- FindOptions options) {
+ FindOptions options,
+ base::Optional<base::TimeDelta> timeout_ms) {
if (!range.StartPosition().IsConnected())
return EphemeralRangeInFlatTree();
+ base::TimeTicks start_time;
+
EphemeralRangeInFlatTree last_match_range;
Node* first_node = range.StartPosition().NodeAsRangeFirstNode();
Node* past_last_node = range.EndPosition().NodeAsRangePastLastNode();
Node* node = first_node;
while (node && node != past_last_node) {
+ if (start_time.is_null()) {
+ start_time = base::TimeTicks::Now();
+ } else {
+ auto time_elapsed = base::TimeTicks::Now() - start_time;
+ if (timeout_ms.has_value() && time_elapsed > timeout_ms.value()) {
+ return EphemeralRangeInFlatTree(
+ PositionInFlatTree::FirstPositionInNode(*node),
+ PositionInFlatTree::FirstPositionInNode(*node));
+ }
+ }
+
if (GetNonSearchableAncestor(*node)) {
node = FlatTreeTraversal::NextSkippingChildren(*node);
continue;
@@ -183,17 +207,62 @@ EphemeralRangeInFlatTree FindBuffer::FindMatchInRange(
return last_match_range;
}
-Node& FindBuffer::GetFirstBlockLevelAncestorInclusive(const Node& start_node) {
+const Node& FindBuffer::GetFirstBlockLevelAncestorInclusive(const Node& node) {
// Gets lowest inclusive ancestor that has block display value.
// <div id=outer>a<div id=inner>b</div>c</div>
// If we run this on "a" or "c" text node in we will get the outer div.
// If we run it on the "b" text node we will get the inner div.
- for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(start_node)) {
- const ComputedStyle* style = ancestor.EnsureComputedStyle();
- if (style && !ancestor.IsTextNode() && IsBlockLevel(style->Display()))
+ if (!node.GetLayoutObject())
+ return *node.GetDocument().documentElement();
+
+ for (const Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
+ if (!ancestor.GetLayoutObject())
+ continue;
+ if (!IsInSameUninterruptedBlock(ancestor, node))
return ancestor;
}
- return *start_node.GetDocument().documentElement();
+
+ return *node.GetDocument().documentElement();
+}
+
+bool FindBuffer::IsInSameUninterruptedBlock(const Node& start_node,
+ const Node& end_node) {
+ DCHECK(AreInOrder(start_node, end_node));
+ DCHECK(start_node.GetLayoutObject());
+ DCHECK(end_node.GetLayoutObject());
+
+ if (start_node.isSameNode(&end_node))
+ return true;
+
+ if (IsExplicitFindBoundary(start_node) || IsExplicitFindBoundary(end_node))
+ return false;
+
+ LayoutBlockFlow& start_block_flow =
+ *NGOffsetMapping::GetInlineFormattingContextOf(
+ *start_node.GetLayoutObject());
+ LayoutBlockFlow& end_block_flow =
+ *NGOffsetMapping::GetInlineFormattingContextOf(
+ *end_node.GetLayoutObject());
+ if (start_block_flow != end_block_flow)
+ return false;
+
+ // It's possible that 2 nodes are in the same block flow but there is a node
+ // in between that has a separate block flow. An example is an input field.
+ for (const Node* node = &start_node; !node->isSameNode(&end_node);
+ node = FlatTreeTraversal::Next(*node)) {
+ const ComputedStyle* style = node->GetComputedStyle();
+ if (ShouldIgnoreContents(*node) || !style ||
+ style->Display() == EDisplay::kNone ||
+ style->Visibility() != EVisibility::kVisible)
+ continue;
+
+ if (node->GetLayoutObject() &&
+ *NGOffsetMapping::GetInlineFormattingContextOf(
+ *node->GetLayoutObject()) != start_block_flow)
+ return false;
+ }
+
+ return true;
}
Node* FindBuffer::ForwardVisibleTextNode(Node& start_node) {
@@ -222,11 +291,6 @@ Node* FindBuffer::BackwardVisibleTextNode(Node& start_node) {
return GetVisibleTextNode<BackwardDirection>(start_node);
}
-bool FindBuffer::IsNodeBlockLevel(Node& node) {
- const ComputedStyle* style = node.EnsureComputedStyle();
- return style && !node.IsTextNode() && IsBlockLevel(style->Display());
-}
-
FindBuffer::Results FindBuffer::FindMatches(const WebString& search_text,
const blink::FindOptions options) {
// We should return empty result if it's impossible to get a match (buffer is
@@ -246,7 +310,6 @@ void FindBuffer::CollectTextUntilBlockBoundary(
// Collects text until block boundary located at or after |start_node|
// to |buffer_|. Saves the next starting node after the block to
// |node_after_block_|.
-
DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range;
node_after_block_ = nullptr;
@@ -259,17 +322,19 @@ void FindBuffer::CollectTextUntilBlockBoundary(
if (!node || !node->isConnected())
return;
- Node& block_ancestor = GetFirstBlockLevelAncestorInclusive(*node);
+ const Node& block_ancestor = GetFirstBlockLevelAncestorInclusive(*node);
const Node* just_after_block = FlatTreeTraversal::Next(
FlatTreeTraversal::LastWithinOrSelf(block_ancestor));
- const LayoutBlockFlow* last_block_flow = nullptr;
// Collect all text under |block_ancestor| to |buffer_|,
// unless we meet another block on the way. If so, we should split.
// Example: <div id="outer">a<span>b</span>c<div>d</div></div>
// Will try to collect all text in outer div but will actually
// stop when it encounters the inner div. So buffer will be "abc".
- Node* const first_traversed_node = node;
+
+ // Used for checking if we reached a new block.
+ Node* last_added_text_node = nullptr;
+
// We will also stop if we encountered/passed |end_node|.
Node* end_node = range.EndPosition().NodeAsRangeLastNode();
@@ -306,26 +371,22 @@ void FindBuffer::CollectTextUntilBlockBoundary(
break;
continue;
}
- // This node is in its own sub-block separate from our starting position.
- const auto* text_node = DynamicTo<Text>(node);
- if (first_traversed_node != node && !text_node &&
- IsBlockLevel(style->Display())) {
- break;
- }
- if (style->Visibility() == EVisibility::kVisible && text_node &&
+ if (style->Visibility() == EVisibility::kVisible &&
node->GetLayoutObject()) {
- LayoutBlockFlow& block_flow =
- *NGOffsetMapping::GetInlineFormattingContextOf(
- *text_node->GetLayoutObject());
- if (last_block_flow && last_block_flow != block_flow) {
- // We enter another block flow.
+ // This node is in its own sub-block separate from our starting position.
+ if (last_added_text_node && last_added_text_node->GetLayoutObject() &&
+ !IsInSameUninterruptedBlock(*last_added_text_node, *node))
break;
+
+ const auto* text_node = DynamicTo<Text>(node);
+ if (text_node) {
+ last_added_text_node = node;
+ LayoutBlockFlow& block_flow =
+ *NGOffsetMapping::GetInlineFormattingContextOf(
+ *text_node->GetLayoutObject());
+ AddTextToBuffer(*text_node, block_flow, range);
}
- if (!last_block_flow) {
- last_block_flow = &block_flow;
- }
- AddTextToBuffer(*text_node, block_flow, range);
}
if (node == end_node) {
node = FlatTreeTraversal::Next(*node);
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h
index 8db423585a2..a85c3477ade 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -29,19 +29,24 @@ class CORE_EXPORT FindBuffer {
static EphemeralRangeInFlatTree FindMatchInRange(
const EphemeralRangeInFlatTree& range,
String search_text,
- const FindOptions);
+ const FindOptions,
+ base::Optional<base::TimeDelta> timeout_ms = base::nullopt);
// Returns the closest ancestor of |start_node| (including the node itself)
// that is block level.
- static Node& GetFirstBlockLevelAncestorInclusive(const Node& start_node);
+ static const Node& GetFirstBlockLevelAncestorInclusive(
+ const Node& start_node);
+
+ // Returns true if start and end nodes are in the same layout block flow and
+ // there are no nodes in between that can be considered blocks. Otherwise,
+ // returns false.
+ static bool IsInSameUninterruptedBlock(const Node& start_node,
+ const Node& end_node);
// See |GetVisibleTextNode|.
static Node* ForwardVisibleTextNode(Node& start_node);
static Node* BackwardVisibleTextNode(Node& start_node);
- // Returns whether the given node is block level.
- static bool IsNodeBlockLevel(Node& node);
-
// A match result, containing the starting position of the match and
// the length of the match.
struct BufferMatchResult {
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_runner.h b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_runner.h
new file mode 100644
index 00000000000..94fdcfa90bf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_runner.h
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_RUNNER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_RUNNER_H_
+
+#include "third_party/blink/renderer/core/editing/finder/find_options.h"
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
+
+namespace blink {
+
+// This is a base for derived classes that are used as a wrapper around
+// FindBuffer to provide a callback-based interface.
+class FindBufferRunner : public GarbageCollected<FindBufferRunner> {
+ public:
+ using Callback = base::OnceCallback<void(const EphemeralRangeInFlatTree&)>;
+
+ virtual void FindMatchInRange(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) = 0;
+ virtual void Cancel() = 0;
+ virtual bool IsActive() = 0;
+
+ virtual void Trace(Visitor*) const {}
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_FIND_BUFFER_RUNNER_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
index 9696ca3e2ed..bf3b075e302 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
namespace blink {
@@ -740,4 +741,132 @@ TEST_F(FindBufferTest, FindMaxCodepointWithReplacedElementUTF16) {
const auto results = buffer.FindMatches("\uFFFF", 0);
ASSERT_EQ(0u, results.CountForTesting());
}
+
+// Tests that a suggested value is not found by searches.
+TEST_F(FindBufferTest, DoNotSearchInSuggestedValues) {
+ SetBodyContent("<input name='field' type='text'>");
+
+ // The first node of the document should be the input field.
+ Node* input_element = GetDocument().body()->firstChild();
+ ASSERT_TRUE(IsA<TextControlElement>(*input_element));
+ TextControlElement& text_control_element =
+ To<TextControlElement>(*input_element);
+ ASSERT_EQ(text_control_element.NameForAutofill(), "field");
+
+ // The suggested value to a string that contains the search string.
+ text_control_element.SetSuggestedValue("aba");
+ ASSERT_EQ(text_control_element.SuggestedValue(), "aba");
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+
+ {
+ // Apply a search for 'aba'.
+ FindBuffer buffer(WholeDocumentRange());
+ const auto results = buffer.FindMatches("aba", 0);
+
+ // There should be no result because the suggested value is not supposed to
+ // be considered in a search.
+ EXPECT_EQ(0U, results.CountForTesting());
+ }
+ // Convert the suggested value to an autofill value.
+ text_control_element.SetAutofillValue(text_control_element.SuggestedValue());
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+ {
+ // Apply a search for 'aba' again.
+ FindBuffer buffer(WholeDocumentRange());
+ const auto results = buffer.FindMatches("aba", 0);
+
+ // This time, there should be a match.
+ EXPECT_EQ(1U, results.CountForTesting());
+ }
+}
+
+TEST_F(FindBufferTest, FindInTable) {
+ SetBodyContent(
+ "<table id='table'><tbody><tr id='row'><td id='c1'>c1 "
+ "<i>i</i></td></tr></tbody></table>");
+ FindBuffer buffer(WholeDocumentRange());
+ const auto results = buffer.FindMatches("c1", 0);
+ ASSERT_EQ(1u, results.CountForTesting());
+}
+
+TEST_F(FindBufferTest, IsInSameUninterruptedBlock) {
+ SetBodyContent(
+ "<div id=outer>a<div id=inner>b</div><i id='styled'>i</i>c</div>");
+ Node* text_node_a = GetDocument().getElementById("outer")->firstChild();
+ Node* styled = GetDocument().getElementById("styled");
+ Node* text_node_i = GetDocument().getElementById("styled")->firstChild();
+ Node* text_node_c = GetDocument().getElementById("outer")->lastChild();
+ Node* text_node_b = GetDocument().getElementById("inner")->firstChild();
+
+ ASSERT_TRUE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_i, *text_node_c));
+ ASSERT_TRUE(FindBuffer::IsInSameUninterruptedBlock(*styled, *text_node_c));
+ ASSERT_FALSE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_a, *text_node_c));
+ ASSERT_FALSE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_a, *text_node_b));
+}
+
+TEST_F(FindBufferTest, IsInSameUninterruptedBlock_input) {
+ SetBodyContent("<div id='outer'>a<input value='input' id='input'>b</div>");
+ Node* text_node_a = GetDocument().getElementById("outer")->firstChild();
+ Node* text_node_b = GetDocument().getElementById("outer")->lastChild();
+ Node* input = GetDocument().getElementById("input");
+ Node* editable_div = FlatTreeTraversal::Next(*input);
+
+ // input elements are followed by an editable div that contains the input
+ // field value.
+ ASSERT_EQ("input", editable_div->textContent());
+
+ ASSERT_FALSE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_a, *text_node_b));
+ ASSERT_FALSE(FindBuffer::IsInSameUninterruptedBlock(*text_node_a, *input));
+ ASSERT_FALSE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_a, *editable_div));
+}
+
+TEST_F(FindBufferTest, IsInSameUninterruptedBlock_table) {
+ SetBodyContent(
+ "<table id='table'>"
+ "<tbody>"
+ "<tr id='row'>"
+ " <td id='c1'>c1</td>"
+ " <td id='c2'>c2</td>"
+ " <td id='c3'>c3</td>"
+ "</tr>"
+ "</tbody>"
+ "</table>");
+ Node* text_node_1 = GetDocument().getElementById("c1")->firstChild();
+ Node* text_node_3 = GetDocument().getElementById("c3")->firstChild();
+
+ ASSERT_FALSE(
+ FindBuffer::IsInSameUninterruptedBlock(*text_node_1, *text_node_3));
+}
+
+TEST_F(FindBufferTest, IsInSameUninterruptedBlock_comment) {
+ SetBodyContent(
+ "<div id='text'><span id='span1'>abc</span><!--comment--><span "
+ "id='span2'>def</span></div>");
+ Node* span_1 = GetDocument().getElementById("span1")->firstChild();
+ Node* span_2 = GetDocument().getElementById("span2")->firstChild();
+
+ ASSERT_TRUE(FindBuffer::IsInSameUninterruptedBlock(*span_1, *span_2));
+}
+
+TEST_F(FindBufferTest, GetFirstBlockLevelAncestorInclusive) {
+ SetBodyContent("<div id=outer>a<div id=inner>b</div>c</div>");
+ Node* outer_div = GetDocument().getElementById("outer");
+ Node* text_node_a = GetDocument().getElementById("outer")->firstChild();
+ Node* text_node_c = GetDocument().getElementById("outer")->lastChild();
+ Node* inner_div = GetDocument().getElementById("inner");
+ Node* text_node_b = GetDocument().getElementById("inner")->firstChild();
+
+ ASSERT_EQ(outer_div,
+ FindBuffer::GetFirstBlockLevelAncestorInclusive(*text_node_a));
+ ASSERT_EQ(outer_div,
+ FindBuffer::GetFirstBlockLevelAncestorInclusive(*text_node_c));
+ ASSERT_EQ(inner_div,
+ FindBuffer::GetFirstBlockLevelAncestorInclusive(*text_node_b));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.cc b/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.cc
new file mode 100644
index 00000000000..3f9eac8e51d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.cc
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "third_party/blink/renderer/core/editing/finder/sync_find_buffer.h"
+
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
+
+namespace blink {
+
+void SyncFindBuffer::FindMatchInRange(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) {
+ EphemeralRangeInFlatTree range = FindBuffer::FindMatchInRange(
+ search_range->ToEphemeralRange(), search_text, options);
+
+ DCHECK(range.IsNull() || !range.IsCollapsed());
+
+ // Search finished, return the result
+ std::move(completeCallback).Run(range);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.h b/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.h
new file mode 100644
index 00000000000..f4717e93930
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/finder/sync_find_buffer.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_SYNC_FIND_BUFFER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_SYNC_FIND_BUFFER_H_
+
+#include "third_party/blink/renderer/core/editing/finder/find_buffer_runner.h"
+#include "third_party/blink/renderer/core/editing/finder/find_options.h"
+#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
+
+namespace blink {
+
+// This is used as a synchronous wrapper around FindBuffer to provide a
+// callback-based interface.
+class SyncFindBuffer : public FindBufferRunner {
+ public:
+ explicit SyncFindBuffer() = default;
+ ~SyncFindBuffer() = default;
+
+ void FindMatchInRange(RangeInFlatTree* search_range,
+ String search_text,
+ FindOptions options,
+ Callback completeCallback) override;
+ void Cancel() override {}
+ bool IsActive() override { return false; }
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FINDER_SYNC_FIND_BUFFER_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
index cc3572cbe1a..b48733047ba 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -56,6 +56,7 @@
#include "third_party/blink/renderer/core/frame/find_in_page.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
@@ -601,6 +602,21 @@ void TextFinder::ClearFindMatchesCache() {
find_match_rects_are_valid_ = false;
}
+void TextFinder::InvalidateFindMatchRects() {
+ // Increase version number is required to trigger FindMatchRects update when
+ // next find.
+ if (!find_matches_cache_.IsEmpty())
+ ++find_match_markers_version_;
+
+ // For subframes, we need to recalculate the FindMatchRects when the
+ // document size of mainframe changed even if the document size of current
+ // frame has not changed because Find-in-page coordinates are represented as
+ // normalized fractions of the main frame document. So we need to force the
+ // FindMatchRects to be updated instead of changing according to the current
+ // document size.
+ find_match_rects_are_valid_ = false;
+}
+
void TextFinder::UpdateFindMatchRects() {
IntSize current_document_size = OwnerFrame().DocumentSize();
if (document_size_for_current_find_match_rects_ != current_document_size) {
@@ -747,7 +763,7 @@ int TextFinder::SelectFindMatch(unsigned index, gfx::Rect* selection_rect) {
// Zoom to the active match.
active_match_rect = OwnerFrame().GetFrameView()->ConvertToRootFrame(
active_match_bounding_box);
- OwnerFrame().LocalRoot()->FrameWidget()->ZoomToFindInPageRect(
+ OwnerFrame().LocalRoot()->FrameWidgetImpl()->ZoomToFindInPageRect(
active_match_rect);
}
@@ -887,7 +903,7 @@ void TextFinder::Scroll(std::unique_ptr<AsyncScrollContext> context) {
// Likewise, if the target scroll element is display locked, then we shouldn't
// scroll to it.
Element* beforematch_element = GetBeforematchElement(*context->range);
- if (context->range->collapsed() ||
+ if (context->range->collapsed() || !context->range->IsConnected() ||
(beforematch_element &&
DisplayLockUtilities::NearestHiddenMatchableInclusiveAncestor(
*beforematch_element))) {
@@ -899,7 +915,7 @@ void TextFinder::Scroll(std::unique_ptr<AsyncScrollContext> context) {
// We also need to re-assign to active_match_ here in order to make sure the
// search starts from context->range. active_match_ may have been unassigned
// during the async steps.
- active_match_ = context->range;
+ active_match_ = context->range->IsConnected() ? context->range : nullptr;
FindInternal(context->identifier, context->search_text, context->options,
context->wrap_within_frame, /*active_now=*/nullptr,
context->first_match, context->wrapped_around);
@@ -907,6 +923,8 @@ void TextFinder::Scroll(std::unique_ptr<AsyncScrollContext> context) {
}
if (context->was_match_hidden) {
+ UseCounter::Count(GetFrame()->GetDocument(),
+ WebFeature::kBeforematchRevealedHiddenMatchable);
GetFrame()
->GetDocument()
->MarkHasFindInPageBeforematchExpandedHiddenMatchable();
@@ -918,7 +936,7 @@ void TextFinder::Scroll(std::unique_ptr<AsyncScrollContext> context) {
// column where the next hit has been found. Doing this when autosizing is
// not set will result in a zoom reset on small devices.
if (GetFrame()->GetDocument()->GetTextAutosizer()->PageNeedsAutosizing()) {
- OwnerFrame().LocalRoot()->FrameWidget()->ZoomToFindInPageRect(
+ OwnerFrame().LocalRoot()->FrameWidgetImpl()->ZoomToFindInPageRect(
OwnerFrame().GetFrameView()->ConvertToRootFrame(
ComputeTextRect(EphemeralRange(context->range))));
}
@@ -939,4 +957,28 @@ void TextFinder::Scroll(std::unique_ptr<AsyncScrollContext> context) {
}
}
+void TextFinder::IncreaseMarkerVersion() {
+ ++find_match_markers_version_;
+
+ // This is called when the size of the content changes. Normally, the check
+ // for the document size changed at the beginning of UpdateFindMatchRects()
+ // would be responsible for invalidating the cached matches as well.
+ // However, a subframe might not change size but its match rects may still be
+ // affected because Find-in-page coordinates are represented as normalized
+ // fractions of the main frame document, so invalidate the cached matches of
+ // subframes as well.
+ for (Frame* frame = GetFrame()->Tree().TraverseNext(GetFrame()); frame;
+ frame = frame->Tree().TraverseNext(GetFrame())) {
+ // TODO(https://crbug.com/1147796) In OOPIFs mode, the text finder
+ // corresponding to the remote frame also needs to be notified, the
+ // match rects are invalid and need to be recalculated.
+ auto* web_local_frame_impl =
+ WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(frame));
+ if (web_local_frame_impl && web_local_frame_impl->GetTextFinder() &&
+ web_local_frame_impl->GetTextFinder()->TotalMatchCount() > 0) {
+ web_local_frame_impl->GetTextFinder()->InvalidateFindMatchRects();
+ }
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.h b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.h
index f3eab80734b..db5ded570b1 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/text_finder.h
+++ b/chromium/third_party/blink/renderer/core/editing/finder/text_finder.h
@@ -105,7 +105,7 @@ class CORE_EXPORT TextFinder final : public GarbageCollected<TextFinder> {
bool FrameScoping() const { return frame_scoping_; }
int TotalMatchCount() const { return total_match_count_; }
bool ScopingInProgress() const { return scoping_in_progress_; }
- void IncreaseMarkerVersion() { ++find_match_markers_version_; }
+ void IncreaseMarkerVersion();
// Finishes the current scoping effort and triggers any updates if
// appropriate.
@@ -181,6 +181,11 @@ class CORE_EXPORT TextFinder final : public GarbageCollected<TextFinder> {
// calculated again next time updateFindMatchRects is called.
void ClearFindMatchesCache();
+ // Forcing rects to be fully recomputed again next time UpdateFindMatchRects
+ // is called. This is different from ClearFindMatchesCache which will clear
+ // the matches cache.
+ void InvalidateFindMatchRects();
+
// Select a find-in-page match marker in the current frame using a cache
// match index returned by nearestFindMatch. Returns the ordinal of the new
// selected match or -1 in case of error. Also provides the bounding box of
diff --git a/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc b/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
index 55339c681d8..a16941dbc6d 100644
--- a/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
@@ -229,11 +229,10 @@ TEST_F(TextFinderTest, FindTextNotFound) {
}
TEST_F(TextFinderTest, FindTextInShadowDOM) {
- GetDocument().body()->setInnerHTML("<b>FOO</b><i>foo</i>");
+ GetDocument().body()->setInnerHTML("<b>FOO</b><i slot='bar'>foo</i>");
ShadowRoot& shadow_root =
- GetDocument().body()->CreateV0ShadowRootForTesting();
- shadow_root.setInnerHTML(
- "<content select=\"i\"></content><u>Foo</u><content></content>");
+ GetDocument().body()->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML("<slot name='bar'></slot><u>Foo</u><slot></slot>");
Node* text_in_b_element = GetDocument().body()->firstChild()->firstChild();
Node* text_in_i_element = GetDocument().body()->lastChild()->firstChild();
Node* text_in_u_element = shadow_root.childNodes()->item(1)->firstChild();
@@ -391,11 +390,10 @@ TEST_F(TextFinderTest, ScopeTextMatchesRepeated) {
}
TEST_F(TextFinderTest, ScopeTextMatchesWithShadowDOM) {
- GetDocument().body()->setInnerHTML("<b>FOO</b><i>foo</i>");
+ GetDocument().body()->setInnerHTML("<b>FOO</b><i slot='bar'>foo</i>");
ShadowRoot& shadow_root =
- GetDocument().body()->CreateV0ShadowRootForTesting();
- shadow_root.setInnerHTML(
- "<content select=\"i\"></content><u>Foo</u><content></content>");
+ GetDocument().body()->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML("<slot name='bar'></slot><u>Foo</u><slot></slot>");
Node* text_in_b_element = GetDocument().body()->firstChild()->firstChild();
Node* text_in_i_element = GetDocument().body()->lastChild()->firstChild();
Node* text_in_u_element = shadow_root.childNodes()->item(1)->firstChild();
@@ -848,6 +846,75 @@ TEST_F(TextFinderSimTest, BeforeMatchExpandedHiddenMatchableUkmNoHandler) {
EXPECT_EQ(entries.size(), 0u);
}
+TEST_F(TextFinderSimTest, BeforeMatchExpandedHiddenMatchableUseCounter) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ .hidden {
+ content-visibility: hidden-matchable;
+ }
+ </style>
+
+ <div id=hiddenid class=hidden>hidden</div>
+
+ <script>
+ hiddenid.addEventListener('beforematch', () => {
+ requestAnimationFrame(() => {
+ hiddenid.classList.remove('hidden');
+ }, 0);
+ });
+ </script>
+ )HTML");
+ Compositor().BeginFrame();
+
+ auto forced_activatable_locks = GetDocument()
+ .GetDisplayLockDocumentState()
+ .GetScopedForceActivatableLocks();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kFindInPage);
+ GetTextFinder().Find(/*identifier=*/0, WebString(String("hidden")),
+ *mojom::blink::FindOptions::New(),
+ /*wrap_within_frame=*/false);
+
+ Compositor().BeginFrame();
+ Compositor().BeginFrame();
+
+ EXPECT_TRUE(GetDocument().IsUseCounted(
+ WebFeature::kBeforematchRevealedHiddenMatchable));
+}
+
+TEST_F(TextFinderSimTest,
+ BeforeMatchExpandedHiddenMatchableUseCounterNoHandler) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ .hidden {
+ content-visibility: hidden-matchable;
+ }
+ </style>
+
+ <div id=hiddenid class=hidden>hidden</div>
+ )HTML");
+ Compositor().BeginFrame();
+
+ auto forced_activatable_locks = GetDocument()
+ .GetDisplayLockDocumentState()
+ .GetScopedForceActivatableLocks();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kFindInPage);
+ GetTextFinder().Find(/*identifier=*/0, WebString(String("hidden")),
+ *mojom::blink::FindOptions::New(),
+ /*wrap_within_frame=*/false);
+
+ Compositor().BeginFrame();
+ Compositor().BeginFrame();
+
+ EXPECT_FALSE(GetDocument().IsUseCounted(
+ WebFeature::kBeforematchRevealedHiddenMatchable));
+}
+
TEST_F(TextFinderTest, FindTextAcrossCommentNode) {
GetDocument().body()->setInnerHTML(
"<span>abc</span><!--comment--><span>def</span>");
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_caret.cc b/chromium/third_party/blink/renderer/core/editing/frame_caret.cc
index cefd716d5d3..e5f240dff4a 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_caret.cc
+++ b/chromium/third_party/blink/renderer/core/editing/frame_caret.cc
@@ -50,16 +50,16 @@ FrameCaret::FrameCaret(LocalFrame& frame,
: selection_editor_(&selection_editor),
frame_(frame),
display_item_client_(new CaretDisplayItemClient()),
- caret_blink_timer_(new TaskRunnerTimer<FrameCaret>(
- frame.GetTaskRunner(TaskType::kInternalDefault),
- this,
- &FrameCaret::CaretBlinkTimerFired)) {}
+ caret_blink_timer_(frame.GetTaskRunner(TaskType::kInternalDefault),
+ this,
+ &FrameCaret::CaretBlinkTimerFired) {}
FrameCaret::~FrameCaret() = default;
void FrameCaret::Trace(Visitor* visitor) const {
visitor->Trace(selection_editor_);
visitor->Trace(frame_);
+ visitor->Trace(caret_blink_timer_);
}
const PositionWithAffinity FrameCaret::CaretPosition() const {
@@ -102,22 +102,22 @@ void FrameCaret::UpdateAppearance() {
}
void FrameCaret::StopCaretBlinkTimer() {
- if (caret_blink_timer_->IsActive() ||
+ if (caret_blink_timer_.IsActive() ||
display_item_client_->IsVisibleIfActive())
ScheduleVisualUpdateForPaintInvalidationIfNeeded();
display_item_client_->SetVisibleIfActive(false);
- caret_blink_timer_->Stop();
+ caret_blink_timer_.Stop();
}
void FrameCaret::StartBlinkCaret() {
// Start blinking with a black caret. Be sure not to restart if we're
// already blinking in the right location.
- if (caret_blink_timer_->IsActive())
+ if (caret_blink_timer_.IsActive())
return;
base::TimeDelta blink_interval = LayoutTheme::GetTheme().CaretBlinkInterval();
if (!blink_interval.is_zero())
- caret_blink_timer_->StartRepeating(blink_interval, FROM_HERE);
+ caret_blink_timer_.StartRepeating(blink_interval, FROM_HERE);
display_item_client_->SetVisibleIfActive(true);
ScheduleVisualUpdateForPaintInvalidationIfNeeded();
@@ -173,6 +173,9 @@ bool FrameCaret::ShouldPaintCaret(const LayoutBlock& block) const {
void FrameCaret::PaintCaret(GraphicsContext& context,
const PhysicalOffset& paint_offset) const {
display_item_client_->PaintCaret(context, paint_offset, DisplayItem::kCaret);
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ frame_->Selection().IsHandleVisible() && !frame_->Selection().IsHidden())
+ display_item_client_->RecordSelection(context, paint_offset);
}
bool FrameCaret::ShouldShowCaret() const {
@@ -219,8 +222,7 @@ void FrameCaret::ScheduleVisualUpdateForPaintInvalidationIfNeeded() {
void FrameCaret::RecreateCaretBlinkTimerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- caret_blink_timer_.reset(new TaskRunnerTimer<FrameCaret>(
- std::move(task_runner), this, &FrameCaret::CaretBlinkTimerFired));
+ caret_blink_timer_.MoveToNewTaskRunner(std::move(task_runner));
}
bool FrameCaret::IsVisibleIfActiveForTesting() const {
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_caret.h b/chromium/third_party/blink/renderer/core/editing/frame_caret.h
index 11fe3f0dc06..1560492e6c2 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_caret.h
+++ b/chromium/third_party/blink/renderer/core/editing/frame_caret.h
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
+#include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/timer.h"
@@ -101,7 +102,7 @@ class CORE_EXPORT FrameCaret final : public GarbageCollected<FrameCaret> {
const Member<LocalFrame> frame_;
const std::unique_ptr<CaretDisplayItemClient> display_item_client_;
// TODO(https://crbug.com/668758): Consider using BeginFrame update for this.
- std::unique_ptr<TaskRunnerTimer<FrameCaret>> caret_blink_timer_;
+ HeapTaskRunnerTimer<FrameCaret> caret_blink_timer_;
bool is_caret_enabled_ = false;
bool should_show_caret_ = false;
bool is_caret_blinking_suspended_ = false;
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc b/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
index 3fbd4417f25..6231f23bc46 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/frame_caret_test.cc
@@ -92,8 +92,7 @@ TEST_F(FrameCaretTest, ShouldNotBlinkWhenSelectionLooseFocus) {
outer->focus();
UpdateAllLifecyclePhasesForTest();
const SelectionInDOMTree& selection = Selection().GetSelectionInDOMTree();
- EXPECT_EQ(selection.Base(),
- Position(input, PositionAnchorType::kBeforeChildren));
+ EXPECT_EQ(selection.Base(), Position::FirstPositionInNode(*input));
EXPECT_FALSE(ShouldShowCaret(caret));
}
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_selection.cc b/chromium/third_party/blink/renderer/core/editing/frame_selection.cc
index d311447ad78..d0133cc8da3 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/chromium/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -363,10 +363,9 @@ void FrameSelection::SetSelectionForAccessibility(
void FrameSelection::NodeChildrenWillBeRemoved(ContainerNode& container) {
if (!container.InActiveDocument())
return;
- // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
- // |Editor| class.
- if (!GetDocument().IsRunningExecCommand())
- TypingCommand::CloseTyping(frame_);
+ // TODO(yosin): We should move to call |TypingCommand::CloseTypingIfNeeded()|
+ // to |Editor| class.
+ TypingCommand::CloseTypingIfNeeded(frame_);
}
void FrameSelection::NodeWillBeRemoved(Node& node) {
@@ -375,10 +374,9 @@ void FrameSelection::NodeWillBeRemoved(Node& node) {
// needs no adjustment.
if (!node.InActiveDocument())
return;
- // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
- // |Editor| class.
- if (!GetDocument().IsRunningExecCommand())
- TypingCommand::CloseTyping(frame_);
+ // TODO(yosin): We should move to call |TypingCommand::CloseTypingIfNeeded()|
+ // to |Editor| class.
+ TypingCommand::CloseTypingIfNeeded(frame_);
}
void FrameSelection::DidChangeFocus() {
@@ -628,13 +626,8 @@ bool FrameSelection::Contains(const PhysicalOffset& point) {
HitTestLocation location(point);
HitTestResult result(request, location);
GetDocument().GetLayoutView()->HitTest(location, result);
- Node* inner_node = result.InnerNode();
- if (!inner_node || !inner_node->GetLayoutObject())
- return false;
-
const PositionInFlatTreeWithAffinity pos_with_affinity =
- FromPositionInDOMTree<EditingInFlatTreeStrategy>(
- inner_node->GetLayoutObject()->PositionForPoint(result.LocalPoint()));
+ FromPositionInDOMTree<EditingInFlatTreeStrategy>(result.GetPosition());
if (pos_with_affinity.IsNull())
return false;
@@ -667,9 +660,8 @@ void FrameSelection::SelectFrameElementInParentIfFullySelected() {
// Check if the selection contains the entire frame contents; if not, then
// there is nothing to do.
- if (GetSelectionInDOMTree().Type() != kRangeSelection) {
+ if (!GetSelectionInDOMTree().IsRange())
return;
- }
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
@@ -1243,20 +1235,20 @@ void FrameSelection::MoveRangeSelectionInternal(
if (new_selection.IsNone())
return;
- const VisibleSelection& visible_selection =
- CreateVisibleSelectionWithGranularity(new_selection, granularity);
- if (visible_selection.IsNone())
+ const SelectionInDOMTree& selection =
+ ExpandWithGranularity(new_selection, granularity);
+ if (selection.IsNone())
return;
SelectionInDOMTree::Builder builder;
- if (visible_selection.IsBaseFirst()) {
- builder.SetBaseAndExtent(visible_selection.Start(),
- visible_selection.End());
+ if (selection.IsBaseFirst()) {
+ builder.SetBaseAndExtent(selection.ComputeStartPosition(),
+ selection.ComputeEndPosition());
} else {
- builder.SetBaseAndExtent(visible_selection.End(),
- visible_selection.Start());
+ builder.SetBaseAndExtent(selection.ComputeEndPosition(),
+ selection.ComputeStartPosition());
}
- builder.SetAffinity(visible_selection.Affinity());
+ builder.SetAffinity(selection.Affinity());
SetSelection(builder.Build(), SetSelectionOptions::Builder()
.SetShouldCloseTyping(true)
.SetShouldClearTypingStyle(true)
@@ -1294,6 +1286,16 @@ LayoutSelectionStatus FrameSelection::ComputeLayoutSelectionStatus(
return layout_selection_->ComputeSelectionStatus(cursor);
}
+SelectionState FrameSelection::ComputeLayoutSelectionStateForCursor(
+ const NGInlineCursorPosition& position) const {
+ return layout_selection_->ComputeSelectionStateForCursor(position);
+}
+
+SelectionState FrameSelection::ComputeLayoutSelectionStateForInlineTextBox(
+ const InlineTextBox& text_box) const {
+ return layout_selection_->ComputeSelectionStateForInlineTextBox(text_box);
+}
+
bool FrameSelection::IsDirectional() const {
return is_directional_;
}
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_selection.h b/chromium/third_party/blink/renderer/core/editing/frame_selection.h
index 0eb5d113cd2..2b302c46ad5 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_selection.h
+++ b/chromium/third_party/blink/renderer/core/editing/frame_selection.h
@@ -44,6 +44,7 @@ namespace blink {
class CaretDisplayItemClient;
class Element;
+class InlineTextBox;
class LayoutBlock;
class LayoutText;
class LocalFrame;
@@ -51,6 +52,7 @@ class FrameCaret;
class GranularityStrategy;
class GraphicsContext;
class NGInlineCursor;
+class NGInlineCursorPosition;
class Range;
class SelectionEditor;
class LayoutSelection;
@@ -239,6 +241,7 @@ class CORE_EXPORT FrameSelection final
void PageActivationChanged();
bool IsHandleVisible() const { return is_handle_visible_; }
+ void SetHandleVisibleForTesting() { is_handle_visible_ = true; }
bool ShouldShrinkNextTap() const { return should_shrink_next_tap_; }
// Returns true if a word is selected.
@@ -285,6 +288,10 @@ class CORE_EXPORT FrameSelection final
const LayoutText& text) const;
LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGInlineCursor& cursor) const;
+ SelectionState ComputeLayoutSelectionStateForCursor(
+ const NGInlineCursorPosition& position) const;
+ SelectionState ComputeLayoutSelectionStateForInlineTextBox(
+ const InlineTextBox& text_box) const;
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/core/editing/frame_selection_test.cc b/chromium/third_party/blink/renderer/core/editing/frame_selection_test.cc
index 6f84da9afb6..67b50ae5039 100644
--- a/chromium/third_party/blink/renderer/core/editing/frame_selection_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/frame_selection_test.cc
@@ -189,7 +189,7 @@ TEST_F(FrameSelectionTest, SelectWordAroundCaret2) {
TEST_F(FrameSelectionTest, ModifyExtendWithFlatTree) {
SetBodyContent("<span id=host></span>one");
- SetShadowContent("two<content></content>", "host");
+ SetShadowContent("two<slot></slot>", "host");
Element* host = GetDocument().getElementById("host");
Node* const two = FlatTreeTraversal::FirstChild(*host);
// Select "two" for selection in DOM tree
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc b/chromium/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
index 47a6a6b5d10..614d0ca0a8e 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -28,6 +29,7 @@ void CachedTextInputInfo::ClearIfNeeded(const LayoutObject& layout_object) {
text_ = g_empty_string;
composition_.Clear();
selection_.Clear();
+ offset_map_.clear();
}
void CachedTextInputInfo::DidLayoutSubtree(const LayoutObject& layout_object) {
@@ -70,8 +72,17 @@ void CachedTextInputInfo::EnsureCached(const ContainerNode& container) const {
constexpr unsigned kInitialCapacity = 1 << 15;
StringBuilder builder;
- if (needs_text)
- builder.ReserveCapacity(kInitialCapacity);
+ if (needs_text) {
+ unsigned capacity = kInitialCapacity;
+ if (auto* block_flow =
+ DynamicTo<LayoutBlockFlow>(container.GetLayoutObject())) {
+ if (block_flow->HasNGInlineNodeData()) {
+ if (const auto* mapping = NGInlineNode::GetOffsetMapping(block_flow))
+ capacity = mapping->GetText().length();
+ }
+ }
+ builder.ReserveCapacity(capacity);
+ }
const Node* last_text_node = nullptr;
unsigned length = 0;
@@ -108,16 +119,21 @@ PlainTextRange CachedTextInputInfo::GetPlainTextRange(
const EphemeralRange& range) const {
if (range.IsNull())
return PlainTextRange();
- const unsigned start_offset = RangeLength(
- EphemeralRange(Position(*container_, 0), range.StartPosition()));
+ const Position container_start = Position(*container_, 0);
+ // When selection is moved to another editable during IME composition,
+ // |range| may not in |container|. See http://crbug.com/1161562
+ if (container_start > range.StartPosition())
+ return PlainTextRange();
+ const unsigned start_offset =
+ RangeLength(EphemeralRange(container_start, range.StartPosition()));
const unsigned end_offset =
- range.IsCollapsed() ? start_offset
- : RangeLength(EphemeralRange(Position(*container_, 0),
- range.EndPosition()));
- DCHECK_EQ(static_cast<unsigned>(TextIterator::RangeLength(
- EphemeralRange(Position(*container_, 0), range.EndPosition()),
- Behavior())),
- end_offset);
+ range.IsCollapsed()
+ ? start_offset
+ : RangeLength(EphemeralRange(container_start, range.EndPosition()));
+ DCHECK_EQ(
+ static_cast<unsigned>(TextIterator::RangeLength(
+ EphemeralRange(container_start, range.EndPosition()), Behavior())),
+ end_offset);
return PlainTextRange(start_offset, end_offset);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/edit_context.cc b/chromium/third_party/blink/renderer/core/editing/ime/edit_context.cc
index 5bbc1b0de20..91955743c86 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/edit_context.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ime/edit_context.cc
@@ -380,10 +380,10 @@ String EditContext::enterKeyHint() const {
}
}
-void EditContext::GetLayoutBounds(WebRect* web_control_bounds,
- WebRect* web_selection_bounds) {
- *web_control_bounds = control_bounds_;
- *web_selection_bounds = selection_bounds_;
+void EditContext::GetLayoutBounds(gfx::Rect* control_bounds,
+ gfx::Rect* selection_bounds) {
+ *control_bounds = control_bounds_;
+ *selection_bounds = selection_bounds_;
}
bool EditContext::SetComposition(
@@ -417,7 +417,7 @@ bool EditContext::SetComposition(
selection_end_ = composition_range_start_ + selection_end;
DispatchTextUpdateEvent(update_text, update_range_start, update_range_end,
selection_start_, selection_end_);
- composition_range_end_ = composition_range_start_ + selection_end;
+ composition_range_end_ = composition_range_start_ + text.length();
DispatchTextFormatEvent(ime_text_spans);
return true;
}
@@ -457,6 +457,20 @@ bool EditContext::SetCompositionFromExistingText(
return true;
}
+bool EditContext::InsertText(const WebString& text) {
+ String update_text(text);
+ text_ = text_.Substring(0, selection_start_) + update_text +
+ text_.Substring(selection_end_);
+ uint32_t update_range_start = selection_start_;
+ uint32_t update_range_end = selection_end_;
+ selection_start_ = selection_start_ + text.length();
+ selection_end_ = selection_start_;
+
+ DispatchTextUpdateEvent(update_text, update_range_start, update_range_end,
+ selection_start_, selection_end_);
+ return true;
+}
+
bool EditContext::CommitText(const WebString& text,
const WebVector<ui::ImeTextSpan>& ime_text_spans,
const WebRange& replacement_range,
@@ -596,16 +610,17 @@ int EditContext::TextInputFlags() const {
}
WebRange EditContext::CompositionRange() {
- return WebRange(composition_range_start_, composition_range_end_);
+ return WebRange(composition_range_start_,
+ composition_range_end_ - composition_range_start_);
}
-bool EditContext::GetCompositionCharacterBounds(WebVector<WebRect>& bounds) {
+bool EditContext::GetCompositionCharacterBounds(WebVector<gfx::Rect>& bounds) {
bounds[0] = selection_bounds_;
return true;
}
WebRange EditContext::GetSelectionOffsets() const {
- return WebRange(selection_start_, selection_end_);
+ return WebRange(selection_start_, selection_end_ - selection_start_);
}
void EditContext::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/edit_context.h b/chromium/third_party/blink/renderer/core/editing/ime/edit_context.h
index 62e9f05e6a6..6b40d5b8958 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/edit_context.h
+++ b/chromium/third_party/blink/renderer/core/editing/ime/edit_context.h
@@ -6,7 +6,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_IME_EDIT_CONTEXT_H_
#include "base/macros.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_text_input_mode.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/web/web_input_method_controller.h"
@@ -159,13 +158,13 @@ class CORE_EXPORT EditContext final : public EventTargetWithInlineData,
WebTextInputType TextInputType() override;
int TextInputFlags() const;
WebRange CompositionRange() override;
- bool GetCompositionCharacterBounds(WebVector<WebRect>& bounds) override;
+ bool GetCompositionCharacterBounds(WebVector<gfx::Rect>& bounds) override;
WebRange GetSelectionOffsets() const override;
// Populate |control_bounds| and |selection_bounds| with the bounds fetched
// from the active EditContext.
- void GetLayoutBounds(WebRect* web_control_bounds,
- WebRect* web_selection_bounds) override;
+ void GetLayoutBounds(gfx::Rect* control_bounds,
+ gfx::Rect* selection_bounds) override;
// Sets the composition range from the already existing text
// This is used for reconversion scenarios in JPN IME.
@@ -174,6 +173,9 @@ class CORE_EXPORT EditContext final : public EventTargetWithInlineData,
int composition_end,
const WebVector<ui::ImeTextSpan>& ime_text_spans);
+ // For English typing.
+ bool InsertText(const WebString& text);
+
bool IsVirtualKeyboardPolicyManual() const override;
bool IsEditContextActive() const override;
// Returns whether show()/hide() API is called from virtualkeyboard or not.
@@ -244,8 +246,8 @@ class CORE_EXPORT EditContext final : public EventTargetWithInlineData,
ui::TextInputAction enter_key_hint_ = ui::TextInputAction::kEnter;
EditContextInputPanelPolicy input_panel_policy_ =
EditContextInputPanelPolicy::kManual;
- WebRect control_bounds_;
- WebRect selection_bounds_;
+ gfx::Rect control_bounds_;
+ gfx::Rect selection_bounds_;
// This flag is set when the input method controller receives a
// composition event from the IME. It keeps track of the start and
// end composition events and fires JS events accordingly.
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
index 111690494bc..e326f0591a7 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -1495,8 +1495,8 @@ void InputMethodController::DeleteSurroundingTextInCodePoints(int before,
return DeleteSurroundingText(before_length, after_length);
}
-void InputMethodController::GetLayoutBounds(WebRect* control_bounds,
- WebRect* selection_bounds) {
+void InputMethodController::GetLayoutBounds(gfx::Rect* control_bounds,
+ gfx::Rect* selection_bounds) {
if (!IsAvailable())
return;
@@ -1583,12 +1583,7 @@ WebTextInputInfo InputMethodController::TextInputInfo() const {
info.selection_end = selection_plain_text_range.End();
}
- // Only gets ime text spans when there is no selection range.
- // ie. the selection range is just a cursor position.
- if (first_range.IsCollapsed()) {
- info.ime_text_spans =
- GetImeTextSpansAroundPosition(first_range.StartPosition());
- }
+ info.ime_text_spans = GetImeTextSpans();
const EphemeralRange& range = CompositionEphemeralRange();
const PlainTextRange& composition_plain_text_range =
@@ -1818,8 +1813,7 @@ void InputMethodController::Trace(Visitor* visitor) const {
ExecutionContextLifecycleObserver::Trace(visitor);
}
-WebVector<ui::ImeTextSpan> InputMethodController::GetImeTextSpansAroundPosition(
- const Position& position) const {
+WebVector<ui::ImeTextSpan> InputMethodController::GetImeTextSpans() const {
DCHECK(!GetDocument().NeedsLayoutTreeUpdate());
Element* target = GetDocument().FocusedElement();
if (!target)
@@ -1833,12 +1827,16 @@ WebVector<ui::ImeTextSpan> InputMethodController::GetImeTextSpansAroundPosition(
return WebVector<ui::ImeTextSpan>();
WebVector<ui::ImeTextSpan> ime_text_spans;
- // Only queries Suggestion markers for now.
- // This can be expanded when browser needs information for
- // other types of markers.
+
+ const EphemeralRange range = EphemeralRange::RangeOfContents(*editable);
+ if (range.IsNull())
+ return WebVector<ui::ImeTextSpan>();
+
+ // MarkersIntersectingRange() might be expensive. In practice, we hope we will
+ // only check one node for the range.
const HeapVector<std::pair<Member<const Text>, Member<DocumentMarker>>>&
- node_marker_pairs = GetDocument().Markers().MarkersAroundPosition(
- ToPositionInFlatTree(position),
+ node_marker_pairs = GetDocument().Markers().MarkersIntersectingRange(
+ ToEphemeralRangeInFlatTree(range),
DocumentMarker::MarkerTypes::Suggestion());
for (const std::pair<Member<const Text>, Member<DocumentMarker>>&
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.h b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.h
index de76cd2184b..77932e739bb 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller.h
@@ -28,7 +28,6 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_text_input_info.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -61,7 +60,7 @@ class CORE_EXPORT InputMethodController final
};
explicit InputMethodController(LocalDOMWindow&, LocalFrame&);
- virtual ~InputMethodController();
+ ~InputMethodController() override;
void Trace(Visitor*) const override;
// international text input composition
@@ -134,7 +133,7 @@ class CORE_EXPORT InputMethodController final
// Returns either the focused editable element's control bounds or the
// EditContext's control and selection bounds if available.
- void GetLayoutBounds(WebRect* control_bounds, WebRect* selection_bounds);
+ void GetLayoutBounds(gfx::Rect* control_bounds, gfx::Rect* selection_bounds);
// Sets the state of the VK show()/hide() calls from virtualkeyboard.
void SetVirtualKeyboardVisibilityRequest(
@@ -249,9 +248,7 @@ class CORE_EXPORT InputMethodController final
TypingCommand::TextCompositionType composition_type);
void DispatchCompositionEndEvent(LocalFrame& frame, const String& text);
- // Gets ime text spans of interest at the cursor position.
- WebVector<ui::ImeTextSpan> GetImeTextSpansAroundPosition(
- const Position& position) const;
+ WebVector<ui::ImeTextSpan> GetImeTextSpans() const;
FRIEND_TEST_ALL_PREFIXES(InputMethodControllerTest,
InputModeOfFocusedElement);
diff --git a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
index 12f94cbd91f..b6f7b166228 100644
--- a/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -32,6 +32,8 @@ namespace blink {
class InputMethodControllerTest : public EditingTestBase {
protected:
+ enum SelectionType { kNoSelection, kCaretSelection, kRangeSelection };
+
InputMethodController& Controller() {
return GetFrame().GetInputMethodController();
}
@@ -3409,4 +3411,73 @@ TEST_F(InputMethodControllerTest, VirtualKeyboardPolicyOfFocusedElement) {
Controller().VirtualKeyboardPolicyOfFocusedElement());
}
+TEST_F(InputMethodControllerTest, SetCompositionInTibetan) {
+ GetFrame().Selection().SetSelectionAndEndTyping(
+ SetSelectionTextToBody(u8"<div id='sample' contenteditable>|</div>"));
+ Element* const div = GetDocument().getElementById("sample");
+ div->focus();
+
+ Vector<ImeTextSpan> ime_text_spans;
+ Controller().SetComposition(String(Vector<UChar>{0xF56}), ime_text_spans, 1,
+ 1);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0F56|</div>",
+ GetSelectionTextFromBody());
+
+ Controller().CommitText(String(Vector<UChar>{0xF56}), ime_text_spans, 0);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0F56|</div>",
+ GetSelectionTextFromBody());
+
+ Controller().SetComposition(String(Vector<UChar>{0xFB7}), ime_text_spans, 1,
+ 1);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0F56\u0FB7|</div>",
+ GetSelectionTextFromBody());
+
+ // Attempt to replace part of grapheme cluster "\u0FB7" in composition
+ Controller().CommitText(String(Vector<UChar>{0xFB7}), ime_text_spans, 0);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0F56\u0FB7|</div>",
+ GetSelectionTextFromBody());
+
+ Controller().SetComposition(String(Vector<UChar>{0xF74}), ime_text_spans, 1,
+ 1);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0F56\u0FB7\u0F74|</div>",
+ GetSelectionTextFromBody());
+}
+
+TEST_F(InputMethodControllerTest, SetCompositionInDevanagari) {
+ GetFrame().Selection().SetSelectionAndEndTyping(SetSelectionTextToBody(
+ u8"<div id='sample' contenteditable>\u0958|</div>"));
+ Element* const div = GetDocument().getElementById("sample");
+ div->focus();
+
+ Vector<ImeTextSpan> ime_text_spans;
+ Controller().SetComposition(String(Vector<UChar>{0x94D}), ime_text_spans, 1,
+ 1);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0958\u094D|</div>",
+ GetSelectionTextFromBody());
+
+ Controller().CommitText(String(Vector<UChar>{0x94D, 0x930}), ime_text_spans,
+ 0);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u0958\u094D\u0930|</div>",
+ GetSelectionTextFromBody());
+}
+
+TEST_F(InputMethodControllerTest, SetCompositionTamil) {
+ GetFrame().Selection().SetSelectionAndEndTyping(
+ SetSelectionTextToBody(u8"<div id='sample' contenteditable>|</div>"));
+ Element* const div = GetDocument().getElementById("sample");
+ div->focus();
+
+ Vector<ImeTextSpan> ime_text_spans;
+ // Note: region starts out with space.
+ Controller().CommitText(String(Vector<UChar>{0xA0}), ime_text_spans, 0);
+ // Add character U+0BB5: 'TAMIL LETTER VA'
+ Controller().SetComposition(String(Vector<UChar>{0xBB5}), ime_text_spans, 0,
+ 0);
+ // Add character U+0BC7: 'TAMIL VOWEL SIGN EE'
+ Controller().CommitText(String(Vector<UChar>{0xBB5, 0xBC7}), ime_text_spans,
+ 1);
+ EXPECT_EQ(u8"<div contenteditable id=\"sample\">\u00A0\u0BB5\u0BC7|</div>",
+ GetSelectionTextFromBody());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc b/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
index d20b9b55bc1..3c3fb8e624d 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_position.cc
@@ -197,6 +197,7 @@ template <typename Strategy>
PositionWithAffinityTemplate<Strategy> AdjustBlockFlowPositionToInline(
const PositionTemplate<Strategy>& position,
int recursion_depth) {
+ DCHECK(position.IsNotNull());
if (recursion_depth >= kBlockFlowAdjustmentMaxRecursionDepth) {
// TODO(editing-dev): This function enters infinite recursion in some cases.
// Find the root cause and fix it. See https://crbug.com/857266
@@ -209,7 +210,9 @@ PositionWithAffinityTemplate<Strategy> AdjustBlockFlowPositionToInline(
// |LayoutObject::CreatePositionWithAffinity()|.
const PositionTemplate<Strategy>& downstream_equivalent =
DownstreamIgnoringEditingBoundaries(position);
- if (downstream_equivalent != position) {
+ DCHECK(downstream_equivalent.IsNotNull());
+ if (downstream_equivalent != position &&
+ downstream_equivalent.AnchorNode()->GetLayoutObject()) {
return ComputeInlineAdjustedPositionAlgorithm(
PositionWithAffinityTemplate<Strategy>(downstream_equivalent,
TextAffinity::kUpstream),
@@ -217,7 +220,9 @@ PositionWithAffinityTemplate<Strategy> AdjustBlockFlowPositionToInline(
}
const PositionTemplate<Strategy>& upstream_equivalent =
UpstreamIgnoringEditingBoundaries(position);
- if (upstream_equivalent == position)
+ DCHECK(upstream_equivalent.IsNotNull());
+ if (upstream_equivalent == position ||
+ !upstream_equivalent.AnchorNode()->GetLayoutObject())
return PositionWithAffinityTemplate<Strategy>();
return ComputeInlineAdjustedPositionAlgorithm(
@@ -232,6 +237,7 @@ PositionWithAffinityTemplate<Strategy> ComputeInlineAdjustedPositionAlgorithm(
int recursion_depth) {
// TODO(yoichio): We don't assume |position| is canonicalized no longer and
// there are few cases failing to compute. Fix it: crbug.com/812535.
+ DCHECK(position.IsNotNull());
DCHECK(!position.AnchorNode()->IsShadowRoot()) << position;
DCHECK(position.GetPosition().AnchorNode()->GetLayoutObject()) << position;
const LayoutObject& layout_object =
@@ -324,20 +330,23 @@ InlineBoxPosition ComputeInlineBoxPositionForInlineAdjustedPositionAlgorithm(
const PositionTemplate<Strategy>& position = adjusted.GetPosition();
DCHECK(!position.AnchorNode()->IsShadowRoot()) << adjusted;
DCHECK(position.AnchorNode()->GetLayoutObject()) << adjusted;
- const LayoutObject& layout_object = *position.AnchorNode()->GetLayoutObject();
+ LayoutObject& layout_object = *position.AnchorNode()->GetLayoutObject();
const int caret_offset = position.ComputeEditingOffset();
- const int round_offset =
- std::min(caret_offset, layout_object.CaretMaxOffset());
if (layout_object.IsText()) {
// TODO(yoichio): Consider |ToLayoutText(layout_object)->TextStartOffset()|
// for first-letter tested with LocalCaretRectTest::FloatFirstLetter.
- return ComputeInlineBoxPositionForTextNode(
- &To<LayoutText>(layout_object), round_offset, adjusted.Affinity());
+ const LayoutText& layout_text = To<LayoutText>(layout_object);
+ const int round_offset =
+ std::min(caret_offset, layout_text.CaretMaxOffset());
+ return ComputeInlineBoxPositionForTextNode(&layout_text, round_offset,
+ adjusted.Affinity());
}
DCHECK(layout_object.IsAtomicInlineLevel());
DCHECK(layout_object.IsInline());
+ const int round_offset =
+ std::min(caret_offset, LineLayoutItem(&layout_object).CaretMaxOffset());
return ComputeInlineBoxPositionForAtomicInline(&layout_object, round_offset);
}
@@ -366,11 +375,6 @@ InlineBoxPosition ComputeInlineBoxPosition(
return ComputeInlineBoxPositionTemplate<EditingInFlatTreeStrategy>(position);
}
-InlineBoxPosition ComputeInlineBoxPosition(const VisiblePosition& position) {
- DCHECK(position.IsValid()) << position;
- return ComputeInlineBoxPosition(position.ToPositionWithAffinity());
-}
-
PositionWithAffinity ComputeInlineAdjustedPosition(
const PositionWithAffinity& position) {
return ComputeInlineAdjustedPositionAlgorithm(position, 0);
@@ -381,13 +385,6 @@ PositionInFlatTreeWithAffinity ComputeInlineAdjustedPosition(
return ComputeInlineAdjustedPositionAlgorithm(position, 0);
}
-PositionWithAffinity ComputeInlineAdjustedPosition(
- const VisiblePosition& position) {
- DCHECK(position.IsValid()) << position;
- return ComputeInlineAdjustedPositionAlgorithm(
- position.ToPositionWithAffinity(), 0);
-}
-
InlineBoxPosition ComputeInlineBoxPositionForInlineAdjustedPosition(
const PositionWithAffinity& position) {
return ComputeInlineBoxPositionForInlineAdjustedPositionAlgorithm(position);
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_position.h b/chromium/third_party/blink/renderer/core/editing/inline_box_position.h
index 3d58ea1ad42..5dab73edaae 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_position.h
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_position.h
@@ -69,12 +69,10 @@ CORE_EXPORT InlineBoxPosition
ComputeInlineBoxPosition(const PositionWithAffinity&);
CORE_EXPORT InlineBoxPosition
ComputeInlineBoxPosition(const PositionInFlatTreeWithAffinity&);
-CORE_EXPORT InlineBoxPosition ComputeInlineBoxPosition(const VisiblePosition&);
PositionWithAffinity ComputeInlineAdjustedPosition(const PositionWithAffinity&);
PositionInFlatTreeWithAffinity ComputeInlineAdjustedPosition(
const PositionInFlatTreeWithAffinity&);
-PositionWithAffinity ComputeInlineAdjustedPosition(const VisiblePosition&);
InlineBoxPosition ComputeInlineBoxPositionForInlineAdjustedPosition(
const PositionWithAffinity&);
diff --git a/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc b/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
index 45788e13d42..e54653726ea 100644
--- a/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/inline_box_position_test.cc
@@ -22,14 +22,14 @@ std::ostream& operator<<(std::ostream& ostream,
<< inline_box_position.offset_in_box;
}
-class InlineBoxPositionTest : public EditingTestBase {};
-
-TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionBidiIsolate) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
+class InlineBoxPositionTest : public EditingTestBase,
+ private ScopedLayoutNGForTest {
+ public:
// InlineBoxPosition is a legacy-only data structure.
- ScopedLayoutNGForTest scoped_layout_ng(false);
+ InlineBoxPositionTest() : ScopedLayoutNGForTest(false) {}
+};
+TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionBidiIsolate) {
// "|" is bidi-level 0, and "foo" and "bar" are bidi-level 2
SetBodyContent(
"|<span id=sample style='unicode-bidi: isolate;'>foo<br>bar</span>|");
@@ -45,9 +45,6 @@ TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionBidiIsolate) {
// http://crbug.com/716093
TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionMixedEditable) {
- // InlineBoxPosition is a legacy-only data structure.
- ScopedLayoutNGForTest scoped_layout_ng(false);
-
SetBodyContent(
"<div contenteditable id=sample>abc<input contenteditable=false></div>");
Element* const sample = GetDocument().getElementById("sample");
@@ -68,9 +65,6 @@ TEST_F(InlineBoxPositionTest, ComputeInlineBoxPositionMixedEditable) {
// http://crbug.com/841363
TEST_F(InlineBoxPositionTest, InFlatTreeAfterInputWithPlaceholderDoesntCrash) {
- // InlineBoxPosition is a legacy-only data structure.
- ScopedLayoutNGForTest scoped_layout_ng(false);
-
SetBodyContent("foo <input placeholder=bla> bar");
const Element* const input = GetDocument().QuerySelector("input");
const auto* const input_layout = input->GetLayoutBox();
@@ -89,11 +83,6 @@ TEST_F(InlineBoxPositionTest, InFlatTreeAfterInputWithPlaceholderDoesntCrash) {
}
TEST_F(InlineBoxPositionTest, DownstreamBeforeLineBreakLTR) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- // InlineBoxPosition is a legacy-only data structure.
- ScopedLayoutNGForTest scoped_layout_ng(false);
-
// This test is for a bidi caret afinity specific behavior.
ScopedBidiCaretAffinityForTest scoped_bidi_affinity(true);
@@ -113,11 +102,6 @@ TEST_F(InlineBoxPositionTest, DownstreamBeforeLineBreakLTR) {
}
TEST_F(InlineBoxPositionTest, DownstreamBeforeLineBreakRTL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- // InlineBoxPosition is a legacy-only data structure.
- ScopedLayoutNGForTest scoped_layout_ng(false);
-
// This test is for a bidi caret afinity specific behavior.
ScopedBidiCaretAffinityForTest scoped_bidi_affinity(true);
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator_test.cc b/chromium/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator_test.cc
index cf442f1828e..eec33e24221 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/simplified_backwards_text_iterator_test.cc
@@ -153,9 +153,10 @@ TEST_F(SimplifiedBackwardsTextIteratorTest, FirstLetter) {
TEST_F(SimplifiedBackwardsTextIteratorTest, SubrangeWithReplacedElements) {
static const char* body_content =
- "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>";
+ "<span id=host><b slot='#one' id=one>one</b> not appeared <b slot='#two' "
+ "id=two>two</b></span>";
const char* shadow_content =
- "three <content select=#two></content> <content select=#one></content> "
+ "three <slot name=#two></slot> <slot name=#one></slot> "
"zero";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -172,9 +173,10 @@ TEST_F(SimplifiedBackwardsTextIteratorTest, SubrangeWithReplacedElements) {
TEST_F(SimplifiedBackwardsTextIteratorTest, characterAt) {
const char* body_content =
- "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>";
+ "<span id=host><b slot='#one' id=one>one</b> not appeared <b slot='#two' "
+ "id=two>two</b></span>";
const char* shadow_content =
- "three <content select=#two></content> <content select=#one></content> "
+ "three <slot name=#two></slot> <slot name=#one></slot> "
"zero";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index a7d566b8092..a9cf8b3b462 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -342,8 +342,7 @@ void TextIteratorAlgorithm<Strategy>::Advance() {
if (std::is_same<Strategy, EditingStrategy>::value &&
EntersOpenShadowRoots() && element && element->OpenShadowRoot()) {
ShadowRoot* youngest_shadow_root = element->OpenShadowRoot();
- DCHECK(youngest_shadow_root->GetType() == ShadowRootType::V0 ||
- youngest_shadow_root->GetType() == ShadowRootType::kOpen);
+ DCHECK(youngest_shadow_root->IsOpen());
node_ = youngest_shadow_root;
iteration_progress_ = kHandledNone;
++shadow_depth_;
@@ -442,8 +441,7 @@ void TextIteratorAlgorithm<Strategy>::Advance() {
should_stop_ = true;
return;
}
- if (shadow_root->GetType() == ShadowRootType::V0 ||
- shadow_root->GetType() == ShadowRootType::kOpen) {
+ if (shadow_root->IsOpen()) {
// We are the shadow root; exit from here and go back to
// where we were.
node_ = &shadow_root->host();
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.h b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.h
index 18b04186f8e..1d26a330c0d 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.h
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator.h
@@ -42,8 +42,9 @@ CORE_EXPORT String
PlainText(const EphemeralRange&,
const TextIteratorBehavior& = TextIteratorBehavior());
-String PlainText(const EphemeralRangeInFlatTree&,
- const TextIteratorBehavior& = TextIteratorBehavior());
+CORE_EXPORT String
+PlainText(const EphemeralRangeInFlatTree&,
+ const TextIteratorBehavior& = TextIteratorBehavior());
// Iterates through the DOM range, returning all the text, and 0-length
// boundaries at points where replaced elements break up the text flow. The
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
index 31325c245af..795558dfe52 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
@@ -266,7 +266,7 @@ TEST_P(TextIteratorTest, NotEnteringShadowTreeWithContentInsertionPoint) {
static const char* body_content =
"<div>Hello, <span id='host'>text</span> iterator.</div>";
static const char* shadow_content =
- "<span>shadow <content>content</content></span>";
+ "<span>shadow <slot>content</slot></span>";
SetBodyContent(body_content);
CreateShadowRootForElementWithIDAndSetInnerHTML(GetDocument(), "host",
shadow_content);
@@ -312,7 +312,7 @@ TEST_P(TextIteratorTest,
static const char* body_content =
"<div>Hello, <span id='host'>text</span> iterator.</div>";
static const char* shadow_content =
- "<span><content>content</content> shadow</span>";
+ "<span><slot>content</slot> shadow</span>";
// In this case a layoutObject for "text" is created, and emitted AFTER any
// nodes in the shadow tree. This order does not match the order of the
// rendered texts, but at this moment it's the expected behavior.
@@ -331,22 +331,22 @@ TEST_P(TextIteratorTest, StartingAtNodeInShadowRoot) {
static const char* body_content =
"<div id='outer'>Hello, <span id='host'>text</span> iterator.</div>";
static const char* shadow_content =
- "<span><content>content</content> shadow</span>";
+ "<span><slot>content</slot> shadow</span>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = CreateShadowRootForElementWithIDAndSetInnerHTML(
GetDocument(), "host", shadow_content);
Node* outer_div = GetDocument().getElementById("outer");
Node* span_in_shadow = shadow_root->firstChild();
- Position start(span_in_shadow, PositionAnchorType::kBeforeChildren);
- Position end(outer_div, PositionAnchorType::kAfterChildren);
+ Position start = Position::FirstPositionInNode(*span_in_shadow);
+ Position end = Position::LastPositionInNode(*outer_div);
EXPECT_EQ(
"[ shadow][text][ iterator.]",
IteratePartial<DOMTree>(start, end, EntersOpenShadowRootsBehavior()));
- PositionInFlatTree start_in_flat_tree(span_in_shadow,
- PositionAnchorType::kBeforeChildren);
- PositionInFlatTree end_in_flat_tree(outer_div,
- PositionAnchorType::kAfterChildren);
+ PositionInFlatTree start_in_flat_tree =
+ PositionInFlatTree::FirstPositionInNode(*span_in_shadow);
+ PositionInFlatTree end_in_flat_tree =
+ PositionInFlatTree::LastPositionInNode(*outer_div);
EXPECT_EQ("[text][ shadow][ iterator.]",
IteratePartial<FlatTree>(start_in_flat_tree, end_in_flat_tree,
EntersOpenShadowRootsBehavior()));
@@ -356,22 +356,22 @@ TEST_P(TextIteratorTest, FinishingAtNodeInShadowRoot) {
static const char* body_content =
"<div id='outer'>Hello, <span id='host'>text</span> iterator.</div>";
static const char* shadow_content =
- "<span><content>content</content> shadow</span>";
+ "<span><slot>content</slot> shadow</span>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = CreateShadowRootForElementWithIDAndSetInnerHTML(
GetDocument(), "host", shadow_content);
Node* outer_div = GetDocument().getElementById("outer");
Node* span_in_shadow = shadow_root->firstChild();
- Position start(outer_div, PositionAnchorType::kBeforeChildren);
- Position end(span_in_shadow, PositionAnchorType::kAfterChildren);
+ Position start = Position::FirstPositionInNode(*outer_div);
+ Position end = Position::LastPositionInNode(*span_in_shadow);
EXPECT_EQ(
"[Hello, ][ shadow]",
IteratePartial<DOMTree>(start, end, EntersOpenShadowRootsBehavior()));
- PositionInFlatTree start_in_flat_tree(outer_div,
- PositionAnchorType::kBeforeChildren);
- PositionInFlatTree end_in_flat_tree(span_in_shadow,
- PositionAnchorType::kAfterChildren);
+ PositionInFlatTree start_in_flat_tree =
+ PositionInFlatTree::FirstPositionInNode(*outer_div);
+ PositionInFlatTree end_in_flat_tree =
+ PositionInFlatTree::LastPositionInNode(*span_in_shadow);
EXPECT_EQ("[Hello, ][text][ shadow]",
IteratePartial<FlatTree>(start_in_flat_tree, end_in_flat_tree,
EntersOpenShadowRootsBehavior()));
@@ -408,7 +408,7 @@ TEST_P(TextIteratorTest, FullyClippedContentsDistributed) {
"</div>";
static const char* shadow_content =
"<div style='overflow: hidden; width: 200px; height: 0;'>"
- "<content></content>"
+ "<slot></slot>"
"</div>";
SetBodyContent(body_content);
CreateShadowRootForElementWithIDAndSetInnerHTML(GetDocument(), "host",
@@ -428,7 +428,7 @@ TEST_P(TextIteratorTest, IgnoresContainersClipDistributed) {
static const char* shadow_content =
"<div style='position: absolute; width: 200px; height: 200px; top: 0; "
"right: 0;'>"
- "<content></content>"
+ "<slot></slot>"
"</div>";
SetBodyContent(body_content);
CreateShadowRootForElementWithIDAndSetInnerHTML(GetDocument(), "host",
@@ -579,9 +579,10 @@ TEST_P(TextIteratorTest, WhitespaceCollapseForReplacedElements) {
TEST_P(TextIteratorTest, characterAt) {
const char* body_content =
- "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>";
+ "<span id=host><b slot='#one' id=one>one</b> not appeared <b slot='#two' "
+ "id=two>two</b></span>";
const char* shadow_content =
- "three <content select=#two></content> <content select=#one></content> "
+ "three <slot name=#two></slot> <slot name=#one></slot> "
"zero";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -863,6 +864,14 @@ TEST_P(TextIteratorTest, StartAndEndInMultiCharFirstLetterInPre) {
EXPECT_TRUE(iter.AtEnd());
}
+// crbug.com/1175482
+TEST_P(TextIteratorTest, FirstLetterAndReaminingAreDifferentBlocks) {
+ SetBodyContent(R"HTML(
+ <style>.class11 { float:left; } *:first-letter { float:inherit; }</style>
+ <body contenteditable=true autofocus><dt class="class11">Cascade)HTML");
+ EXPECT_EQ("[C][ascade]", Iterate<DOMTree>());
+}
+
TEST_P(TextIteratorTest, StartAtRemainingTextInPre) {
SetBodyContent("<style>pre:first-letter {color:red;}</style><pre>Axyz</pre>");
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc
index 0660d726a83..3004b87711e 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc
@@ -26,7 +26,6 @@ const unsigned kMaxOffset = std::numeric_limits<unsigned>::max();
bool ShouldSkipInvisibleTextAt(const Text& text,
unsigned offset,
bool ignores_visibility) {
- // TODO(xiaochengh): Get style from NGInlineItem or NGPhysicalTextFragment.
const LayoutObject* layout_object = AssociatedLayoutObjectOf(text, offset);
if (!layout_object)
return true;
@@ -96,6 +95,7 @@ bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() {
void TextIteratorTextNodeHandler::HandleTextNodeWithLayoutNG() {
DCHECK_LE(offset_, end_offset_);
DCHECK_LE(end_offset_, text_node_->data().length());
+ DCHECK_LE(mapping_units_index_, mapping_units_.size());
while (offset_ < end_offset_ && !text_state_.PositionNode()) {
const EphemeralRange range_to_emit(Position(text_node_, offset_),
@@ -109,9 +109,18 @@ void TextIteratorTextNodeHandler::HandleTextNodeWithLayoutNG() {
return;
}
+ if (mapping_units_index_ >= mapping_units_.size()) {
+ // mapping_units_ got in HandleTextNodeInRange() ran out. It was for
+ // :first-letter. We call GetMappingUnitsForDOMRange() again for the
+ // remaining part of |text_node_|.
+ mapping_units_ = mapping->GetMappingUnitsForDOMRange(range_to_emit);
+ mapping_units_index_ = 0;
+ }
+
const unsigned initial_offset = offset_;
- for (const NGOffsetMappingUnit& unit :
- mapping->GetMappingUnitsForDOMRange(range_to_emit)) {
+ for (; mapping_units_index_ < mapping_units_.size();
+ ++mapping_units_index_) {
+ const auto& unit = mapping_units_[mapping_units_index_];
if (unit.TextContentEnd() == unit.TextContentStart() ||
ShouldSkipInvisibleTextAt(*text_node_, unit.DOMStart(),
IgnoresStyleVisibility())) {
@@ -127,6 +136,7 @@ void TextIteratorTextNodeHandler::HandleTextNodeWithLayoutNG() {
text_state_.EmitText(*text_node_, unit.DOMStart(), unit.DOMEnd(), string,
text_content_start, text_content_end);
offset_ = unit.DOMEnd();
+ ++mapping_units_index_;
return;
}
@@ -238,12 +248,16 @@ void TextIteratorTextNodeHandler::HandleTextNodeInRange(const Text* node,
handled_first_letter_ = false;
first_letter_text_ = nullptr;
uses_layout_ng_ = false;
+ mapping_units_.clear();
- if (NGOffsetMapping::GetFor(Position(node, offset_))) {
+ if (auto* mapping = NGOffsetMapping::GetFor(Position(node, offset_))) {
// Restore end offset from magic value.
if (end_offset_ == kMaxOffset)
end_offset_ = node->data().length();
uses_layout_ng_ = true;
+ mapping_units_ = mapping->GetMappingUnitsForDOMRange(
+ EphemeralRange(Position(node, offset_), Position(node, end_offset_)));
+ mapping_units_index_ = 0;
HandleTextNodeWithLayoutNG();
return;
}
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.h b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.h
index e1ffb8fc480..1fb4859c59e 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.h
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -82,6 +83,9 @@ class TextIteratorTextNodeHandler {
// Indicates if the text node is laid out with LayoutNG.
bool uses_layout_ng_ = false;
+ // UnitVector for text_node_. This is available only if uses_layout_ng_.
+ NGOffsetMapping::UnitVector mapping_units_;
+ wtf_size_t mapping_units_index_;
InlineTextBox* text_box_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
index b508e5ad516..2dfa572bbdf 100644
--- a/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
+++ b/chromium/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
@@ -36,6 +36,7 @@ namespace blink {
class ContainerNode;
class HTMLElement;
+class Node;
class Text;
class CORE_EXPORT TextIteratorTextState {
diff --git a/chromium/third_party/blink/renderer/core/editing/layout_selection.cc b/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
index 416baaf4d84..ee69daa84d5 100644
--- a/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/chromium/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -30,14 +30,15 @@
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.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/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
@@ -582,10 +583,10 @@ static SelectionState GetSelectionStateFor(const LayoutText& layout_text) {
return layout_text.GetSelectionState();
}
-static SelectionState GetSelectionStateFor(const NGInlineCursor& cursor) {
- DCHECK(cursor.Current().GetLayoutObject());
- return GetSelectionStateFor(
- To<LayoutText>(*cursor.Current().GetLayoutObject()));
+static SelectionState GetSelectionStateFor(
+ const NGInlineCursorPosition& position) {
+ DCHECK(position.GetLayoutObject());
+ return GetSelectionStateFor(To<LayoutText>(*position.GetLayoutObject()));
}
bool LayoutSelection::IsSelected(const LayoutObject& layout_object) {
@@ -665,7 +666,7 @@ LayoutSelectionStatus LayoutSelection::ComputeSelectionStatus(
const NGTextOffset offset = cursor.Current().TextOffset();
const unsigned start_offset = offset.start;
const unsigned end_offset = offset.end;
- switch (GetSelectionStateFor(cursor)) {
+ switch (GetSelectionStateFor(cursor.Current())) {
case SelectionState::kStart: {
const unsigned start_in_block = paint_range_->start_offset.value();
const bool is_continuous = start_in_block <= end_offset;
@@ -709,6 +710,91 @@ LayoutSelectionStatus LayoutSelection::ComputeSelectionStatus(
}
}
+// Given |state| that describes the provided offsets relationship to the
+// |paint_range_| (and thus which comparisons are valid), returns a
+// SelectionState that reflects where the endpoints of the selection fall,
+// relative to the range expressed by the offsets.
+SelectionState LayoutSelection::ComputeSelectionStateFromOffsets(
+ SelectionState state,
+ unsigned start_offset,
+ unsigned end_offset) const {
+ switch (state) {
+ case SelectionState::kStart: {
+ const unsigned start_in_block =
+ paint_range_->start_offset.value_or(start_offset);
+ return start_offset <= start_in_block && start_in_block <= end_offset
+ ? SelectionState::kStart
+ : SelectionState::kNone;
+ }
+ case SelectionState::kEnd: {
+ const unsigned end_in_block =
+ paint_range_->end_offset.value_or(end_offset);
+ return start_offset <= end_in_block && end_in_block <= end_offset
+ ? SelectionState::kEnd
+ : SelectionState::kNone;
+ }
+ case SelectionState::kStartAndEnd: {
+ const unsigned start_in_block =
+ paint_range_->start_offset.value_or(start_offset);
+ const unsigned end_in_block =
+ paint_range_->end_offset.value_or(end_offset);
+ const bool is_start_in_current_cursor =
+ start_offset <= start_in_block && start_in_block <= end_offset;
+ const bool is_end_in_current_cursor =
+ start_offset <= end_in_block && end_in_block <= end_offset;
+ if (is_start_in_current_cursor && is_end_in_current_cursor)
+ return SelectionState::kStartAndEnd;
+ else if (is_start_in_current_cursor)
+ return SelectionState::kStart;
+ else if (is_end_in_current_cursor)
+ return SelectionState::kEnd;
+ else
+ return SelectionState::kInside;
+ }
+ case SelectionState::kInside: {
+ return SelectionState::kInside;
+ }
+ default:
+ return SelectionState::kNone;
+ }
+}
+
+SelectionState LayoutSelection::ComputeSelectionStateForCursor(
+ const NGInlineCursorPosition& position) const {
+ if (!position)
+ return SelectionState::kNone;
+
+ DCHECK(position.IsText());
+
+ // Selection on ellipsis is not supported.
+ if (position.IsEllipsis())
+ return SelectionState::kNone;
+
+ const NGTextOffset offset = position.TextOffset();
+ const unsigned start_offset = offset.start;
+ const unsigned end_offset = offset.end;
+ // Determine the state of the overall selection, relative to the LayoutObject
+ // associated with the current cursor position. This state will allow us know
+ // which offset comparisons are valid, and determine if the selection
+ // endpoints fall within the current cursor position.
+ SelectionState state = GetSelectionStateFor(position);
+ return ComputeSelectionStateFromOffsets(state, start_offset, end_offset);
+}
+
+SelectionState LayoutSelection::ComputeSelectionStateForInlineTextBox(
+ const InlineTextBox& text_box) const {
+ AssertIsValid();
+ unsigned start_offset = static_cast<unsigned>(text_box.CaretMinOffset());
+ unsigned end_offset = static_cast<unsigned>(text_box.CaretMaxOffset());
+ // Determine the state of the overall selection, relative to the
+ // InlineTextBox. This state will allow us know which offset comparisons are
+ // valid, and determine if the selection endpoints fall within InlineTextBox.
+ const LayoutText* text = To<LayoutText>(
+ LineLayoutAPIShim::ConstLayoutObjectFrom(text_box.GetLineLayoutItem()));
+ SelectionState state = GetSelectionStateFor(*text);
+ return ComputeSelectionStateFromOffsets(state, start_offset, end_offset);
+}
+
static NewPaintRangeAndSelectedNodes CalcSelectionRangeAndSetSelectionState(
const FrameSelection& frame_selection) {
const SelectionInDOMTree& selection_in_dom =
diff --git a/chromium/third_party/blink/renderer/core/editing/layout_selection.h b/chromium/third_party/blink/renderer/core/editing/layout_selection.h
index 1cd02edd5a3..a29df9a9160 100644
--- a/chromium/third_party/blink/renderer/core/editing/layout_selection.h
+++ b/chromium/third_party/blink/renderer/core/editing/layout_selection.h
@@ -29,14 +29,17 @@
namespace blink {
+class InlineTextBox;
class IntRect;
class LayoutObject;
class LayoutText;
class NGInlineCursor;
+class NGInlineCursorPosition;
class FrameSelection;
struct LayoutSelectionStatus;
struct LayoutTextSelectionStatus;
class SelectionPaintRange;
+enum class SelectionState;
class LayoutSelection final : public GarbageCollected<LayoutSelection> {
public:
@@ -50,6 +53,23 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
LayoutTextSelectionStatus ComputeSelectionStatus(const LayoutText&) const;
LayoutSelectionStatus ComputeSelectionStatus(const NGInlineCursor&) const;
+
+ // Compute the layout selection state relative to the current item of the
+ // given NGInlineCursor. E.g. a state of kStart means that the selection
+ // starts within the position (and ends elsewhere), where kStartAndEnd means
+ // the selection both starts and ends within the position. This information is
+ // used at paint time to determine the edges of the layout selection.
+ SelectionState ComputeSelectionStateForCursor(
+ const NGInlineCursorPosition&) const;
+
+ // Compute the layout selection state relative to the InlineTextBox.
+ // E.g. a state of kStart means that the selection starts within the line
+ // (and ends elsewhere), where kStartAndEnd means the selection both starts
+ // and ends within the line. This information is used at paint time to
+ // determine the edges of the layout selection.
+ SelectionState ComputeSelectionStateForInlineTextBox(
+ const InlineTextBox&) const;
+
static bool IsSelected(const LayoutObject&);
void ContextDestroyed();
@@ -57,6 +77,10 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
void Trace(Visitor*) const;
private:
+ SelectionState ComputeSelectionStateFromOffsets(SelectionState state,
+ unsigned start_offset,
+ unsigned end_offset) const;
+
void AssertIsValid() const;
Member<FrameSelection> frame_selection_;
diff --git a/chromium/third_party/blink/renderer/core/editing/layout_selection_test.cc b/chromium/third_party/blink/renderer/core/editing/layout_selection_test.cc
index c2c784cccba..5acd68b1cee 100644
--- a/chromium/third_party/blink/renderer/core/editing/layout_selection_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/layout_selection_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -943,6 +944,69 @@ TEST_P(LayoutSelectionTest, InvalidateSlot) {
DumpSelectionInfo());
}
+TEST_P(LayoutSelectionTest, StartAndEndSelectionState) {
+ if (LayoutNGEnabled())
+ return;
+
+ Selection().SetSelectionAndEndTyping(
+ SetSelectionTextToBody("<div>f^oo|</div><div>bar</div>"));
+ UpdateAllLifecyclePhasesForTest();
+ Node* foo_div = GetDocument().body()->firstChild();
+ auto& foo_text = *To<LayoutText>(foo_div->firstChild()->GetLayoutObject());
+ InlineTextBox* text_box = foo_text.FirstTextBox();
+
+ EXPECT_EQ(SelectionState::kStartAndEnd,
+ Selection().ComputeLayoutSelectionStateForInlineTextBox(*text_box));
+
+ Node* bar_div = GetDocument().body()->lastChild();
+ auto& bar_text = *To<LayoutText>(bar_div->firstChild()->GetLayoutObject());
+ text_box = bar_text.FirstTextBox();
+ EXPECT_EQ(SelectionState::kNone,
+ Selection().ComputeLayoutSelectionStateForInlineTextBox(*text_box));
+}
+
+TEST_P(LayoutSelectionTest, StartAndEndMultilineSelectionState) {
+ if (LayoutNGEnabled())
+ return;
+
+ Selection().SetSelectionAndEndTyping(SetSelectionTextToBody(
+ "<div style='white-space:pre'>f^oo\nbar\nba|z</div>"));
+ UpdateAllLifecyclePhasesForTest();
+ auto& div_text = *To<LayoutText>(
+ GetDocument().body()->firstChild()->firstChild()->GetLayoutObject());
+ for (const InlineTextBox* box : div_text.TextBoxes()) {
+ SelectionState state =
+ Selection().ComputeLayoutSelectionStateForInlineTextBox(*box);
+ if (box == div_text.FirstTextBox())
+ EXPECT_EQ(SelectionState::kStart, state);
+ else if (box == div_text.LastTextBox())
+ EXPECT_EQ(SelectionState::kEnd, state);
+ else
+ EXPECT_EQ(SelectionState::kInside, state);
+ }
+}
+
+TEST_P(LayoutSelectionTest, StartAndEndBR) {
+ if (LayoutNGEnabled())
+ return;
+
+ Selection().SetSelectionAndEndTyping(SetSelectionTextToBody(
+ "<div style='white-space:pre'>^<br>foo<br>|</div>"));
+ UpdateAllLifecyclePhasesForTest();
+ auto& first_br_text = *To<LayoutText>(
+ GetDocument().body()->firstChild()->firstChild()->GetLayoutObject());
+ const InlineTextBox* box = first_br_text.FirstTextBox();
+ SelectionState state =
+ Selection().ComputeLayoutSelectionStateForInlineTextBox(*box);
+ EXPECT_EQ(SelectionState::kStart, state);
+ auto& last_br_text = *To<LayoutText>(
+ GetDocument().body()->firstChild()->lastChild()->GetLayoutObject());
+
+ box = last_br_text.FirstTextBox();
+ state = Selection().ComputeLayoutSelectionStateForInlineTextBox(*box);
+ EXPECT_EQ(SelectionState::kEnd, state);
+}
+
class NGLayoutSelectionTest
: public LayoutSelectionTestBase,
private ScopedLayoutNGForTest,
@@ -982,6 +1046,14 @@ class NGLayoutSelectionTest
return Selection().ComputeLayoutSelectionStatus(cursor);
}
+ SelectionState ComputeLayoutSelectionStateForCursor(
+ const LayoutObject& layout_object) const {
+ DCHECK(layout_object.IsText());
+ NGInlineCursor cursor;
+ cursor.MoveTo(layout_object);
+ return Selection().ComputeLayoutSelectionStateForCursor(cursor.Current());
+ }
+
void SetSelectionAndUpdateLayoutSelection(const std::string& selection_text) {
const SelectionInDOMTree& selection =
SetSelectionTextToBody(selection_text);
@@ -1033,6 +1105,7 @@ TEST_F(NGLayoutSelectionTest, TwoNGBlockFlows) {
GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kSelected),
ComputeLayoutSelectionStatus(*foo));
+ EXPECT_EQ(SelectionState::kStart, ComputeLayoutSelectionStateForCursor(*foo));
LayoutObject* const bar = GetDocument()
.body()
->firstChild()
@@ -1041,6 +1114,101 @@ TEST_F(NGLayoutSelectionTest, TwoNGBlockFlows) {
->GetLayoutObject();
EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
ComputeLayoutSelectionStatus(*bar));
+ EXPECT_EQ(SelectionState::kEnd, ComputeLayoutSelectionStateForCursor(*bar));
+}
+
+TEST_F(NGLayoutSelectionTest, StartAndEndState) {
+ SetSelectionAndUpdateLayoutSelection("<div>f^oo|</div><div>bar</div>");
+ LayoutObject* const foo =
+ GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+ EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kNotSelected),
+ ComputeLayoutSelectionStatus(*foo));
+ EXPECT_EQ(SelectionState::kStartAndEnd,
+ ComputeLayoutSelectionStateForCursor(*foo));
+ LayoutObject* const bar = GetDocument()
+ .body()
+ ->firstChild()
+ ->nextSibling()
+ ->firstChild()
+ ->GetLayoutObject();
+ EXPECT_EQ(LayoutSelectionStatus(0u, 0u, SelectSoftLineBreak::kNotSelected),
+ ComputeLayoutSelectionStatus(*bar));
+ EXPECT_EQ(SelectionState::kNone, ComputeLayoutSelectionStateForCursor(*bar));
+}
+
+TEST_F(NGLayoutSelectionTest, StartAndEndMultilineState) {
+ SetSelectionAndUpdateLayoutSelection(
+ "<div style='white-space:pre'>f^oo\nbar\nba|z</div>");
+ LayoutObject* const div_text =
+ GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+
+ NGInlineCursor cursor(*(div_text->ContainingNGBlockFlow()));
+ cursor.MoveTo(*div_text);
+ EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(cursor));
+ EXPECT_EQ(SelectionState::kStart,
+ Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+ // Move to 'bar' text.
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ EXPECT_EQ(LayoutSelectionStatus(4u, 7u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(cursor));
+ EXPECT_EQ(SelectionState::kInside,
+ Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+ // Move to 'baz' text.
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ EXPECT_EQ(LayoutSelectionStatus(8u, 10u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(cursor));
+ EXPECT_EQ(SelectionState::kEnd,
+ Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+}
+
+TEST_F(NGLayoutSelectionTest, BeforeStartAndAfterEndMultilineState) {
+ SetSelectionAndUpdateLayoutSelection(
+ "<div style='white-space:pre'>foo\nba^r</div><div "
+ "style='white-space:pre'>ba|z\nquu</div>");
+ LayoutObject* const div_text =
+ GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+ NGInlineCursor cursor(*(div_text->ContainingNGBlockFlow()));
+ cursor.MoveTo(*div_text);
+ EXPECT_EQ(LayoutSelectionStatus(3u, 3u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(cursor));
+ EXPECT_EQ(SelectionState::kNone,
+ Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+ // Move to 'bar' text.
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ cursor.MoveToNext();
+ EXPECT_EQ(LayoutSelectionStatus(6u, 7u, SelectSoftLineBreak::kSelected),
+ Selection().ComputeLayoutSelectionStatus(cursor));
+ EXPECT_EQ(SelectionState::kStart,
+ Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+ LayoutObject* const second_div_text =
+ GetDocument().body()->lastChild()->firstChild()->GetLayoutObject();
+ NGInlineCursor second_cursor(*(second_div_text->ContainingNGBlockFlow()));
+ second_cursor.MoveTo(*second_div_text);
+ EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(second_cursor));
+ EXPECT_EQ(SelectionState::kEnd,
+ Selection().ComputeLayoutSelectionStateForCursor(
+ second_cursor.Current()));
+
+ // Move to 'quu' text.
+ second_cursor.MoveToNext();
+ second_cursor.MoveToNext();
+ second_cursor.MoveToNext();
+ EXPECT_EQ(LayoutSelectionStatus(4u, 4u, SelectSoftLineBreak::kNotSelected),
+ Selection().ComputeLayoutSelectionStatus(second_cursor));
+ EXPECT_EQ(SelectionState::kNone,
+ Selection().ComputeLayoutSelectionStateForCursor(
+ second_cursor.Current()));
}
// TODO(editing-dev): Once LayoutNG supports editing, we should change this
@@ -1135,6 +1303,8 @@ TEST_F(NGLayoutSelectionTest, BRStatus) {
CHECK(layout_br->IsBR());
EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kNotSelected),
ComputeLayoutSelectionStatus(*layout_br));
+ EXPECT_EQ(SelectionState::kStartAndEnd,
+ ComputeLayoutSelectionStateForCursor(*layout_br));
}
// https://crbug.com/907186
@@ -1145,6 +1315,8 @@ TEST_F(NGLayoutSelectionTest, WBRStatus) {
GetDocument().QuerySelector("wbr")->GetLayoutObject();
EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kSelected),
ComputeLayoutSelectionStatus(*layout_wbr));
+ EXPECT_EQ(SelectionState::kInside,
+ ComputeLayoutSelectionStateForCursor(*layout_wbr));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc b/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
index 4ecc98db5a3..5cb742c7c22 100644
--- a/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
+++ b/chromium/third_party/blink/renderer/core/editing/local_caret_rect.cc
@@ -36,15 +36,54 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
-#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
-#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
namespace blink {
namespace {
+// Returns a position suitable for |ComputeNGCaretPosition()| to calculate
+// local caret rect by |ComputeLocalCaretRect()|:
+// - A position in |Text| node
+// - A position before/after atomic inline element. Note: This function
+// doesn't check whether anchor node is atomic inline level or not.
+template <typename Strategy>
+PositionWithAffinityTemplate<Strategy> AdjustForNGCaretPosition(
+ const PositionWithAffinityTemplate<Strategy>& position_with_affinity) {
+ switch (position_with_affinity.GetPosition().AnchorType()) {
+ case PositionAnchorType::kAfterAnchor:
+ case PositionAnchorType::kBeforeAnchor:
+ return position_with_affinity;
+ case PositionAnchorType::kAfterChildren:
+ // For caret rect computation, |kAfterChildren| and |kAfterNode| are
+ // equivalent. See http://crbug.com/1174101
+ return PositionWithAffinityTemplate<Strategy>(
+ PositionTemplate<Strategy>::AfterNode(
+ *position_with_affinity.GetPosition().AnchorNode()),
+ position_with_affinity.Affinity());
+ case PositionAnchorType::kOffsetInAnchor: {
+ const Node& node = *position_with_affinity.GetPosition().AnchorNode();
+ if (IsA<Text>(node) ||
+ position_with_affinity.GetPosition().OffsetInContainerNode())
+ return position_with_affinity;
+ const LayoutObject* const layout_object = node.GetLayoutObject();
+ if (!layout_object || IsA<LayoutBlockFlow>(layout_object)) {
+ // In case of <div>@0
+ return position_with_affinity;
+ }
+ // For caret rect computation, we paint caret before |layout_object|
+ // instead of inside of it.
+ return PositionWithAffinityTemplate<Strategy>(
+ PositionTemplate<Strategy>::BeforeNode(node),
+ position_with_affinity.Affinity());
+ }
+ }
+ NOTREACHED();
+ return position_with_affinity;
+}
+
template <typename Strategy>
LocalCaretRect LocalCaretRectOfPositionTemplate(
const PositionWithAffinityTemplate<Strategy>& position,
@@ -60,8 +99,9 @@ LocalCaretRect LocalCaretRectOfPositionTemplate(
ComputeInlineAdjustedPosition(position);
if (adjusted.IsNotNull()) {
- if (NGInlineFormattingContextOf(adjusted.GetPosition()))
- return ComputeNGLocalCaretRect(adjusted);
+ if (auto caret_position =
+ ComputeNGCaretPosition(AdjustForNGCaretPosition(adjusted)))
+ return ComputeLocalCaretRect(caret_position);
const InlineBoxPosition& box_position =
ComputeInlineBoxPositionForInlineAdjustedPosition(adjusted);
@@ -101,9 +141,9 @@ LocalCaretRect LocalSelectionRectOfPositionTemplate(
if (adjusted.IsNull())
return LocalCaretRect();
- if (NGInlineFormattingContextOf(adjusted.GetPosition())) {
- return ComputeNGLocalSelectionRect(adjusted);
- }
+ if (auto caret_position =
+ ComputeNGCaretPosition(AdjustForNGCaretPosition(adjusted)))
+ return ComputeLocalSelectionRect(caret_position);
const InlineBoxPosition& box_position =
ComputeInlineBoxPositionForInlineAdjustedPosition(adjusted);
diff --git a/chromium/third_party/blink/renderer/core/editing/local_caret_rect_test.cc b/chromium/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
index 03a5401462b..48fa06afeab 100644
--- a/chromium/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
@@ -39,15 +39,19 @@ class ParameterizedLocalCaretRectTest
bool LayoutNGEnabled() const {
return RuntimeEnabledFeatures::LayoutNGEnabled();
}
+
+ LocalCaretRect LocalCaretRectOf(const Position& position) {
+ return LocalCaretRectOfPosition(PositionWithAffinity(position));
+ }
};
INSTANTIATE_TEST_SUITE_P(All, ParameterizedLocalCaretRectTest, testing::Bool());
TEST_P(ParameterizedLocalCaretRectTest, DOMAndFlatTrees) {
const char* body_content =
- "<p id='host'><b id='one'>1</b></p><b id='two'>22</b>";
+ "<p id='host'><b slot='#one' id='one'>1</b></p><b id='two'>22</b>";
const char* shadow_content =
- "<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
+ "<b id='two'>22</b><slot name=#one></slot><b id='three'>333</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -63,6 +67,46 @@ TEST_P(ParameterizedLocalCaretRectTest, DOMAndFlatTrees) {
EXPECT_EQ(caret_rect_from_dom_tree, caret_rect_from_flat_tree);
}
+// http://crbug.com/1174101
+TEST_P(ParameterizedLocalCaretRectTest, EmptyInlineFlex) {
+ LoadAhem();
+ InsertStyleElement(R"CSS(
+ div { font: 10px/15px Ahem; width: 100px; }
+ i {
+ display: inline-flex;
+ width: 30px; height: 30px;
+ border: solid 10px red;
+ })CSS");
+ // |ComputeInlinePosition(AfterChildren:<div>)=AfterChildren:<b>
+ // When removing <i>, we have <b>@0
+ SetBodyContent(
+ "<div id=target contenteditable>"
+ "ab<i contenteditable=false><b></b></i></div>");
+ const auto& target = *GetElementById("target");
+ const auto& ab = *To<Text>(target.firstChild());
+ const auto& inline_flex = *ab.nextSibling();
+ const LocalCaretRect before_ab =
+ LocalCaretRect(ab.GetLayoutObject(), {0, 32, 1, 10});
+ const LocalCaretRect before_inline_flex =
+ // LayoutNG is correct. legacy layout places caret inside inline-flex.
+ LayoutNGEnabled()
+ ? LocalCaretRect(ab.GetLayoutObject(), {20, 32, 1, 10})
+ : LocalCaretRect(inline_flex.GetLayoutObject(), {10, 10, 1, 50});
+ const LocalCaretRect after_inline_flex =
+ // LayoutNG is correct. legacy layout places caret inside inline-flex.
+ LayoutNGEnabled()
+ ? LocalCaretRect(inline_flex.GetLayoutObject(), {49, 0, 1, 50})
+ : LocalCaretRect(inline_flex.GetLayoutObject(), {59, 10, 1, 50});
+
+ EXPECT_EQ(before_ab, LocalCaretRectOf(Position(target, 0)));
+ EXPECT_EQ(before_inline_flex, LocalCaretRectOf(Position(target, 1)));
+ EXPECT_EQ(after_inline_flex, LocalCaretRectOf(Position(target, 2)));
+ EXPECT_EQ(before_ab, LocalCaretRectOf(Position::BeforeNode(target)));
+ EXPECT_EQ(after_inline_flex, LocalCaretRectOf(Position::AfterNode(target)));
+ EXPECT_EQ(after_inline_flex,
+ LocalCaretRectOf(Position::LastPositionInNode(target)));
+}
+
TEST_P(ParameterizedLocalCaretRectTest, SimpleText) {
// This test only records the current behavior. Future changes are allowed.
@@ -782,9 +826,9 @@ TEST_P(ParameterizedLocalCaretRectTest, CollapsedSpace) {
// TODO(yoichio): Following should return valid rect: crbug.com/812535.
EXPECT_EQ(
LocalCaretRect(first_span->GetLayoutObject(), PhysicalRect(0, 0, 0, 0)),
- LocalCaretRectOfPosition(PositionWithAffinity(
- Position(first_span, PositionAnchorType::kAfterChildren),
- TextAffinity::kDownstream)));
+ LocalCaretRectOfPosition(
+ PositionWithAffinity(Position::LastPositionInNode(*first_span),
+ TextAffinity::kDownstream)));
EXPECT_EQ(LayoutNGEnabled() ? LocalCaretRect(foo->GetLayoutObject(),
PhysicalRect(30, 0, 1, 10))
: LocalCaretRect(white_spaces->GetLayoutObject(),
@@ -807,10 +851,10 @@ TEST_P(ParameterizedLocalCaretRectTest, CollapsedSpace) {
TEST_P(ParameterizedLocalCaretRectTest, AbsoluteCaretBoundsOfWithShadowDOM) {
const char* body_content =
- "<p id='host'><b id='one'>11</b><b id='two'>22</b></p>";
+ "<p id='host'><b slot='#one' id='one'>11</b><b name='#two' "
+ "id='two'>22</b></p>";
const char* shadow_content =
- "<div><content select=#two></content><content "
- "select=#one></content></div>";
+ "<div><slot name=#two></slot><slot name=#one></slot></div>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -832,9 +876,8 @@ TEST_P(ParameterizedLocalCaretRectTest, AbsoluteSelectionBoundsOfWithImage) {
SetBodyContent("<div>foo<img></div>");
Node* node = GetDocument().QuerySelector("img");
- IntRect rect =
- AbsoluteSelectionBoundsOf(VisiblePosition::Create(PositionWithAffinity(
- Position(node, PositionAnchorType::kAfterChildren))));
+ IntRect rect = AbsoluteSelectionBoundsOf(VisiblePosition::Create(
+ PositionWithAffinity(Position::LastPositionInNode(*node))));
EXPECT_FALSE(rect.IsEmpty());
}
@@ -996,4 +1039,30 @@ TEST_P(ParameterizedLocalCaretRectTest, AfterIneditableInline) {
LocalCaretRectOfPosition(PositionWithAffinity(position)));
}
+// https://crbug.com/1155399
+TEST_P(ParameterizedLocalCaretRectTest, OptionWithDisplayContents) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { font: 10px/10px Ahem; width: 300px }"
+ "option { display: contents; }");
+ SetBodyContent("<option>a</option>");
+ const Element* body = GetDocument().body();
+ const Element* option = GetDocument().QuerySelector("option");
+ LocalCaretRect empty;
+ LocalCaretRect start(body->GetLayoutObject(), PhysicalRect(0, 0, 1, 10));
+ LocalCaretRect end(body->GetLayoutObject(), PhysicalRect(299, 0, 1, 10));
+
+ // LocalCaretRectOfPosition shouldn't crash
+ for (const Position& p : {Position::BeforeNode(*body), Position(body, 0)})
+ EXPECT_EQ(start, LocalCaretRectOfPosition(PositionWithAffinity(p)));
+ for (const Position& p :
+ {Position::BeforeNode(*option), Position(option, 0), Position(option, 1),
+ Position::LastPositionInNode(*option), Position::AfterNode(*option)})
+ EXPECT_EQ(empty, LocalCaretRectOfPosition(PositionWithAffinity(p)));
+ for (const Position& p :
+ {Position(body, 1), Position::LastPositionInNode(*body),
+ Position::AfterNode(*body)})
+ EXPECT_EQ(end, LocalCaretRectOfPosition(PositionWithAffinity(p)));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/markers/text_match_marker_list_impl.h b/chromium/third_party/blink/renderer/core/editing/markers/text_match_marker_list_impl.h
index 3484dbb3800..df8e2edb25d 100644
--- a/chromium/third_party/blink/renderer/core/editing/markers/text_match_marker_list_impl.h
+++ b/chromium/third_party/blink/renderer/core/editing/markers/text_match_marker_list_impl.h
@@ -11,6 +11,7 @@
namespace blink {
class IntRect;
+class Node;
// Implementation of TextMarkerBaseListImpl for TextMatch markers.
// Markers are kept sorted by start offset, under the assumption that
diff --git a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
index 77e7ff4f619..03c03e45c04 100644
--- a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
+++ b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.cc
@@ -24,16 +24,6 @@ NGCaretPosition ComputeNGCaretPosition(
return ComputeNGCaretPosition(ToPositionInDOMTreeWithAffinity(position));
}
-LocalCaretRect ComputeNGLocalCaretRect(
- const PositionInFlatTreeWithAffinity& position) {
- return ComputeNGLocalCaretRect(ToPositionInDOMTreeWithAffinity(position));
-}
-
-LocalCaretRect ComputeNGLocalSelectionRect(
- const PositionInFlatTreeWithAffinity& position) {
- return ComputeNGLocalSelectionRect(ToPositionInDOMTreeWithAffinity(position));
-}
-
bool InSameNGLineBox(const PositionInFlatTreeWithAffinity& position1,
const PositionInFlatTreeWithAffinity& position2) {
return InSameNGLineBox(ToPositionInDOMTreeWithAffinity(position1),
diff --git a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
index fb866a55212..0183fd082d2 100644
--- a/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
+++ b/chromium/third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h
@@ -11,7 +11,6 @@ namespace blink {
struct NGCaretPosition;
class LayoutBlockFlow;
-struct LocalCaretRect;
// This file contains shorthands that converts FlatTree-variants of editing
// objects into DOM tree variants, and then pass them to LayoutNG utility
@@ -21,10 +20,6 @@ const LayoutBlockFlow* NGInlineFormattingContextOf(const PositionInFlatTree&);
NGCaretPosition ComputeNGCaretPosition(const PositionInFlatTreeWithAffinity&);
-LocalCaretRect ComputeNGLocalCaretRect(const PositionInFlatTreeWithAffinity&);
-LocalCaretRect ComputeNGLocalSelectionRect(
- const PositionInFlatTreeWithAffinity&);
-
bool InSameNGLineBox(const PositionInFlatTreeWithAffinity&,
const PositionInFlatTreeWithAffinity&);
diff --git a/chromium/third_party/blink/renderer/core/editing/position.cc b/chromium/third_party/blink/renderer/core/editing/position.cc
index b3569b7b9e4..ccdfb734336 100644
--- a/chromium/third_party/blink/renderer/core/editing/position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/position.cc
@@ -45,7 +45,7 @@ bool CanBeAnchorNode<EditingStrategy>(Node* node) {
template <>
bool CanBeAnchorNode<EditingInFlatTreeStrategy>(Node* node) {
return CanBeAnchorNode<EditingStrategy>(node) &&
- node->CanParticipateInFlatTree();
+ (!node || node->CanParticipateInFlatTree());
}
#endif
@@ -180,7 +180,6 @@ Node* PositionTemplate<Strategy>::ComputeContainerNode() const {
return nullptr;
switch (AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
case PositionAnchorType::kAfterChildren:
case PositionAnchorType::kOffsetInAnchor:
return anchor_node_.Get();
@@ -215,8 +214,6 @@ int PositionTemplate<Strategy>::ComputeOffsetInContainerNode() const {
return 0;
switch (AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
- return 0;
case PositionAnchorType::kAfterChildren:
return LastOffsetInNode(*anchor_node_);
case PositionAnchorType::kOffsetInAnchor:
@@ -282,8 +279,6 @@ Node* PositionTemplate<Strategy>::ComputeNodeBeforePosition() const {
if (!anchor_node_)
return nullptr;
switch (AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
- return nullptr;
case PositionAnchorType::kAfterChildren:
return Strategy::LastChild(*anchor_node_);
case PositionAnchorType::kOffsetInAnchor:
@@ -303,8 +298,6 @@ Node* PositionTemplate<Strategy>::ComputeNodeAfterPosition() const {
return nullptr;
switch (AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
- return Strategy::FirstChild(*anchor_node_);
case PositionAnchorType::kAfterChildren:
return nullptr;
case PositionAnchorType::kOffsetInAnchor:
@@ -376,6 +369,13 @@ static bool IsPositionConnected(const PositionInFlatTree& position) {
}
template <typename Strategy>
+bool PositionTemplate<Strategy>::IsBeforeChildren() const {
+ if (IsBeforeAnchor())
+ return !Strategy::PreviousSibling(*anchor_node_);
+ return IsOffsetInAnchor() && !offset_;
+}
+
+template <typename Strategy>
bool PositionTemplate<Strategy>::IsConnected() const {
return IsPositionConnected(*this);
}
@@ -397,9 +397,7 @@ int16_t ComparePositions(const PositionInFlatTree& position_a,
DCHECK(position_a.IsNotNull());
DCHECK(position_b.IsNotNull());
- position_a.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
Node* container_a = position_a.ComputeContainerNode();
- position_b.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
Node* container_b = position_b.ComputeContainerNode();
int offset_a = position_a.ComputeOffsetInContainerNode();
int offset_b = position_b.ComputeOffsetInContainerNode();
@@ -456,7 +454,6 @@ bool PositionTemplate<Strategy>::AtFirstEditingPositionForNode() const {
switch (anchor_type_) {
case PositionAnchorType::kOffsetInAnchor:
return offset_ == 0;
- case PositionAnchorType::kBeforeChildren:
case PositionAnchorType::kBeforeAnchor:
return true;
case PositionAnchorType::kAfterChildren:
@@ -550,10 +547,7 @@ int PositionTemplate<Strategy>::LastOffsetInNode(const Node& node) {
template <typename Strategy>
PositionTemplate<Strategy> PositionTemplate<Strategy>::FirstPositionInNode(
const Node& anchor_node) {
- if (anchor_node.IsTextNode())
- return PositionTemplate<Strategy>(anchor_node, 0);
- return PositionTemplate<Strategy>(&anchor_node,
- PositionAnchorType::kBeforeChildren);
+ return PositionTemplate<Strategy>(anchor_node, 0);
}
// static
@@ -594,14 +588,15 @@ PositionInFlatTree ToPositionInFlatTree(const Position& pos) {
return PositionInFlatTree(anchor, pos.ComputeOffsetInContainerNode());
DCHECK(!anchor->IsElementNode() || anchor->CanParticipateInFlatTree());
int offset = pos.ComputeOffsetInContainerNode();
+ if (!offset) {
+ Node* node = anchor->IsShadowRoot() ? anchor->OwnerShadowHost() : anchor;
+ return PositionInFlatTree::FirstPositionInNode(*node);
+ }
Node* child = NodeTraversal::ChildAt(*anchor, offset);
if (!child) {
- if (anchor->IsShadowRoot())
- return PositionInFlatTree(anchor->OwnerShadowHost(),
- PositionAnchorType::kAfterChildren);
- return PositionInFlatTree(anchor, PositionAnchorType::kAfterChildren);
+ Node* node = anchor->IsShadowRoot() ? anchor->OwnerShadowHost() : anchor;
+ return PositionInFlatTree::LastPositionInNode(*node);
}
- child->UpdateDistributionForFlatTreeTraversal();
if (!child->CanParticipateInFlatTree()) {
if (anchor->IsShadowRoot())
return PositionInFlatTree(anchor->OwnerShadowHost(), offset);
@@ -612,17 +607,17 @@ PositionInFlatTree ToPositionInFlatTree(const Position& pos) {
// When |pos| isn't appeared in flat tree, we map |pos| to after
// children of shadow host.
// e.g. "foo",0 in <progress>foo</progress>
- if (anchor->IsShadowRoot())
- return PositionInFlatTree(anchor->OwnerShadowHost(),
- PositionAnchorType::kAfterChildren);
- return PositionInFlatTree(anchor, PositionAnchorType::kAfterChildren);
+ if (anchor->IsShadowRoot()) {
+ return PositionInFlatTree::LastPositionInNode(*anchor->OwnerShadowHost());
+ }
+ return PositionInFlatTree::LastPositionInNode(*anchor);
}
if (anchor->IsShadowRoot())
return PositionInFlatTree(anchor->OwnerShadowHost(), pos.AnchorType());
+ DCHECK(anchor->CanParticipateInFlatTree());
if (pos.IsBeforeAnchor() || pos.IsAfterAnchor()) {
- if (anchor->CanParticipateInFlatTree() &&
- !FlatTreeTraversal::Parent(*anchor)) {
+ if (!FlatTreeTraversal::Parent(*anchor)) {
// For Before/AfterAnchor, if |anchor| doesn't have parent in the flat
// tree, there is no valid corresponding PositionInFlatTree.
// Since this function is a primitive function, we do not adjust |pos|
@@ -637,6 +632,10 @@ PositionInFlatTree ToPositionInFlatTree(const Position& pos) {
return PositionInFlatTree(anchor, pos.AnchorType());
}
+PositionInFlatTree ToPositionInFlatTree(const PositionInFlatTree& position) {
+ return position;
+}
+
Position ToPositionInDOMTree(const Position& position) {
return position;
}
@@ -650,26 +649,24 @@ Position ToPositionInDOMTree(const PositionInFlatTree& position) {
switch (position.AnchorType()) {
case PositionAnchorType::kAfterChildren:
// FIXME: When anchorNode is <img>, assertion fails in the constructor.
- return Position(anchor_node, PositionAnchorType::kAfterChildren);
+ return Position::LastPositionInNode(*anchor_node);
case PositionAnchorType::kAfterAnchor:
return Position::AfterNode(*anchor_node);
- case PositionAnchorType::kBeforeChildren:
- return Position(anchor_node, PositionAnchorType::kBeforeChildren);
case PositionAnchorType::kBeforeAnchor:
return Position::BeforeNode(*anchor_node);
case PositionAnchorType::kOffsetInAnchor: {
int offset = position.OffsetInContainerNode();
if (anchor_node->IsCharacterDataNode())
return Position(anchor_node, offset);
+ if (!offset)
+ return Position::FirstPositionInNode(*anchor_node);
Node* child = FlatTreeTraversal::ChildAt(*anchor_node, offset);
if (child)
return Position(child->parentNode(), child->NodeIndex());
- if (!position.OffsetInContainerNode())
- return Position(anchor_node, PositionAnchorType::kBeforeChildren);
// |child| is null when the position is at the end of the children.
// <div>foo|</div>
- return Position(anchor_node, PositionAnchorType::kAfterChildren);
+ return Position::LastPositionInNode(*anchor_node);
}
default:
NOTREACHED();
@@ -687,8 +684,6 @@ String PositionTemplate<Strategy>::ToAnchorTypeAndOffsetString() const {
builder.Append("]");
return builder.ToString();
}
- case PositionAnchorType::kBeforeChildren:
- return "beforeChildren";
case PositionAnchorType::kAfterChildren:
return "afterChildren";
case PositionAnchorType::kBeforeAnchor:
@@ -744,8 +739,6 @@ std::ostream& operator<<(std::ostream& ostream,
return ostream << "afterChildren";
case PositionAnchorType::kBeforeAnchor:
return ostream << "beforeAnchor";
- case PositionAnchorType::kBeforeChildren:
- return ostream << "beforeChildren";
case PositionAnchorType::kOffsetInAnchor:
return ostream << "offsetInAnchor";
}
diff --git a/chromium/third_party/blink/renderer/core/editing/position.h b/chromium/third_party/blink/renderer/core/editing/position.h
index 71a7014a59b..f9e109346a8 100644
--- a/chromium/third_party/blink/renderer/core/editing/position.h
+++ b/chromium/third_party/blink/renderer/core/editing/position.h
@@ -40,7 +40,6 @@ enum class PositionAnchorType : unsigned {
kOffsetInAnchor,
kBeforeAnchor,
kAfterAnchor,
- kBeforeChildren,
kAfterChildren,
};
@@ -98,9 +97,7 @@ class PositionTemplate {
bool IsBeforeAnchor() const {
return anchor_type_ == PositionAnchorType::kBeforeAnchor;
}
- bool IsBeforeChildren() const {
- return anchor_type_ == PositionAnchorType::kBeforeChildren;
- }
+ bool IsBeforeChildren() const;
bool IsOffsetInAnchor() const {
return anchor_type_ == PositionAnchorType::kOffsetInAnchor;
}
@@ -135,7 +132,6 @@ class PositionTemplate {
// Returns an offset for editing based on anchor type for using with
// |AnchorNode()| function:
// - kOffsetInAnchor offset_
- // - kBeforeChildren 0
// - kBeforeAnchor 0
// - kAfterChildren last editing offset in anchor node
// - kAfterAnchor last editing offset in anchor node
@@ -274,6 +270,7 @@ bool operator!=(const PositionTemplate<Strategy>& a,
}
CORE_EXPORT PositionInFlatTree ToPositionInFlatTree(const Position&);
+CORE_EXPORT PositionInFlatTree ToPositionInFlatTree(const PositionInFlatTree&);
CORE_EXPORT Position ToPositionInDOMTree(const Position&);
CORE_EXPORT Position ToPositionInDOMTree(const PositionInFlatTree&);
diff --git a/chromium/third_party/blink/renderer/core/editing/position_test.cc b/chromium/third_party/blink/renderer/core/editing/position_test.cc
index c43cbfa0c76..beeef35fdc6 100644
--- a/chromium/third_party/blink/renderer/core/editing/position_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/position_test.cc
@@ -106,12 +106,13 @@ TEST_F(PositionTest, NodeAsRangeLastNode) {
EXPECT_EQ(t3, PositionInFlatTree::AfterNode(*p3).NodeAsRangeLastNode());
}
-TEST_F(PositionTest, NodeAsRangeLastNodeShadow) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(PositionTest, DISABLED_NodeAsRangeLastNodeShadow) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
const char* shadow_content =
- "<a id='a'><content select=#two></content><content "
- "select=#one></content></a>";
+ "<a id='a'><slot name='#two'></slot><slot name='#one'></slot></a>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -130,8 +131,10 @@ TEST_F(PositionTest, NodeAsRangeLastNodeShadow) {
EXPECT_EQ(t2, Position::InParentAfterNode(*n2).NodeAsRangeLastNode());
EXPECT_EQ(t3, Position::AfterNode(*host).NodeAsRangeLastNode());
+ // TODO(crbug.com/1157146): This returns <slot name='#one'> instead of t2:
EXPECT_EQ(t2,
PositionInFlatTree::InParentBeforeNode(*n1).NodeAsRangeLastNode());
+ // TODO(crbug.com/1157146): This returns <slot name='#two'> instead of a:
EXPECT_EQ(a,
PositionInFlatTree::InParentBeforeNode(*n2).NodeAsRangeLastNode());
EXPECT_EQ(t1,
@@ -148,10 +151,10 @@ TEST_F(PositionTest, OperatorBool) {
}
TEST_F(PositionTest, ToPositionInFlatTreeWithActiveInsertionPoint) {
- const char* body_content = "<p id='host'>00<b id='one'>11</b>22</p>";
+ const char* body_content =
+ "<p id='host'>00<b slot='#one' id='one'>11</b>22</p>";
const char* shadow_content =
- "<a id='a'><content select=#one "
- "id='content'></content><content></content></a>";
+ "<a id='a'><slot name=#one id='content'></slot><slot></slot></a>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* anchor = shadow_root->getElementById("a");
@@ -160,18 +163,18 @@ TEST_F(PositionTest, ToPositionInFlatTreeWithActiveInsertionPoint) {
ToPositionInFlatTree(Position(anchor, 0)));
EXPECT_EQ(PositionInFlatTree(anchor, 1),
ToPositionInFlatTree(Position(anchor, 1)));
- EXPECT_EQ(PositionInFlatTree(anchor, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*anchor),
ToPositionInFlatTree(Position(anchor, 2)));
}
TEST_F(PositionTest, ToPositionInFlatTreeWithInactiveInsertionPoint) {
- const char* body_content = "<p id='p'><content></content></p>";
+ const char* body_content = "<p id='p'><slot></slot></p>";
SetBodyContent(body_content);
Element* anchor = GetDocument().getElementById("p");
EXPECT_EQ(PositionInFlatTree(anchor, 0),
ToPositionInFlatTree(Position(anchor, 0)));
- EXPECT_EQ(PositionInFlatTree(anchor, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*anchor),
ToPositionInFlatTree(Position(anchor, 1)));
}
@@ -180,40 +183,40 @@ TEST_F(PositionTest, ToPositionInFlatTreeWithNotDistributed) {
SetBodyContent("<progress id=sample>foo</progress>");
Element* sample = GetDocument().getElementById("sample");
- EXPECT_EQ(PositionInFlatTree(sample, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::FirstPositionInNode(*sample),
ToPositionInFlatTree(Position(sample, 0)));
}
TEST_F(PositionTest, ToPositionInFlatTreeWithShadowRoot) {
- const char* body_content = "<p id='host'>00<b id='one'>11</b>22</p>";
- const char* shadow_content = "<a><content select=#one></content></a>";
+ const char* body_content =
+ "<p id='host'>00<b slot='#one' id='one'>11</b>22</p>";
+ const char* shadow_content = "<a><slot name=#one></slot></a>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* host = GetDocument().getElementById("host");
EXPECT_EQ(PositionInFlatTree(host, 0),
ToPositionInFlatTree(Position(shadow_root, 0)));
- EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*host),
ToPositionInFlatTree(Position(shadow_root, 1)));
- EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::kAfterChildren),
- ToPositionInFlatTree(
- Position(shadow_root, PositionAnchorType::kAfterChildren)));
- EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::kBeforeChildren),
- ToPositionInFlatTree(
- Position(shadow_root, PositionAnchorType::kBeforeChildren)));
+ EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*host),
+ ToPositionInFlatTree(Position::LastPositionInNode(*shadow_root)));
+ EXPECT_EQ(PositionInFlatTree::FirstPositionInNode(*host),
+ ToPositionInFlatTree(Position::FirstPositionInNode(*shadow_root)));
}
TEST_F(PositionTest,
ToPositionInFlatTreeWithShadowRootContainingSingleContent) {
- const char* body_content = "<p id='host'>00<b id='one'>11</b>22</p>";
- const char* shadow_content = "<content select=#one></content>";
+ const char* body_content =
+ "<p id='host'>00<b slot='#one' id='one'>11</b>22</p>";
+ const char* shadow_content = "<slot name=#one></slot>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* host = GetDocument().getElementById("host");
EXPECT_EQ(PositionInFlatTree(host, 0),
ToPositionInFlatTree(Position(shadow_root, 0)));
- EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*host),
ToPositionInFlatTree(Position(shadow_root, 1)));
}
@@ -224,7 +227,7 @@ TEST_F(PositionTest, ToPositionInFlatTreeWithEmptyShadowRoot) {
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* host = GetDocument().getElementById("host");
- EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::kAfterChildren),
+ EXPECT_EQ(PositionInFlatTree::FirstPositionInNode(*host),
ToPositionInFlatTree(Position(shadow_root, 0)));
}
@@ -250,4 +253,26 @@ TEST_F(PositionTest, IsConnectedInFlatTree) {
EXPECT_FALSE(ToPositionInFlatTree(position).IsConnected());
}
+TEST_F(PositionTest, FirstPositionInShadowHost) {
+ SetBodyContent("<p id=host>foo</p>");
+ SetShadowContent("bar", "host");
+ Element* host = GetDocument().getElementById("host");
+
+ Position dom = Position::FirstPositionInNode(*host);
+ PositionInFlatTree flat = PositionInFlatTree::FirstPositionInNode(*host);
+ EXPECT_EQ(dom, ToPositionInDOMTree(flat));
+ EXPECT_EQ(flat, ToPositionInFlatTree(dom));
+}
+
+TEST_F(PositionTest, LastPositionInShadowHost) {
+ SetBodyContent("<p id=host>foo</p>");
+ SetShadowContent("bar", "host");
+ Element* host = GetDocument().getElementById("host");
+
+ Position dom = Position::LastPositionInNode(*host);
+ PositionInFlatTree flat = PositionInFlatTree::LastPositionInNode(*host);
+ EXPECT_EQ(dom, ToPositionInDOMTree(flat));
+ EXPECT_EQ(flat, ToPositionInFlatTree(dom));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.cc b/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.cc
new file mode 100644
index 00000000000..93796a38cb8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.cc
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
+
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+
+namespace blink {
+
+RangeInFlatTree::RangeInFlatTree(const PositionInFlatTree& start,
+ const PositionInFlatTree& end)
+ : start_(MakeGarbageCollected<RelocatablePosition>(
+ ToPositionInDOMTree(start))),
+ end_(
+ MakeGarbageCollected<RelocatablePosition>(ToPositionInDOMTree(end))) {
+ DCHECK_LE(start, end);
+}
+
+void RangeInFlatTree::SetStart(const PositionInFlatTree& start) {
+ start_->SetPosition(ToPositionInDOMTree(start));
+}
+
+void RangeInFlatTree::SetEnd(const PositionInFlatTree& end) {
+ end_->SetPosition(ToPositionInDOMTree(end));
+}
+
+PositionInFlatTree RangeInFlatTree::StartPosition() const {
+ return ToPositionInFlatTree(start_->GetPosition());
+}
+
+PositionInFlatTree RangeInFlatTree::EndPosition() const {
+ return ToPositionInFlatTree(end_->GetPosition());
+}
+
+bool RangeInFlatTree::IsCollapsed() const {
+ return start_ == end_;
+}
+
+bool RangeInFlatTree::IsConnected() const {
+ return StartPosition().ComputeContainerNode()->isConnected() &&
+ EndPosition().ComputeContainerNode()->isConnected();
+}
+
+bool RangeInFlatTree::IsNull() const {
+ return StartPosition().IsNull() || EndPosition().IsNull();
+}
+
+EphemeralRangeInFlatTree RangeInFlatTree::ToEphemeralRange() const {
+ return EphemeralRangeInFlatTree(StartPosition(), EndPosition());
+}
+
+void RangeInFlatTree::Trace(Visitor* visitor) const {
+ visitor->Trace(start_);
+ visitor->Trace(end_);
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.h b/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.h
new file mode 100644
index 00000000000..c1091b5de97
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/range_in_flat_tree.h
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_RANGE_IN_FLAT_TREE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_RANGE_IN_FLAT_TREE_H_
+
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/relocatable_position.h"
+
+namespace blink {
+
+// This is a wrapper class for a range in flat tree that is relocatable by
+// relacating the start and end positions in DOM tree.
+class RangeInFlatTree final : public GarbageCollected<RangeInFlatTree> {
+ public:
+ RangeInFlatTree(const PositionInFlatTree& start,
+ const PositionInFlatTree& end);
+
+ void SetStart(const PositionInFlatTree& start);
+
+ void SetEnd(const PositionInFlatTree& end);
+
+ PositionInFlatTree StartPosition() const;
+
+ PositionInFlatTree EndPosition() const;
+
+ bool IsCollapsed() const;
+
+ bool IsConnected() const;
+
+ bool IsNull() const;
+
+ EphemeralRangeInFlatTree ToEphemeralRange() const;
+
+ void Trace(Visitor* visitor) const;
+
+ private:
+ Member<RelocatablePosition> start_;
+ Member<RelocatablePosition> end_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_RANGE_IN_FLAT_TREE_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/relocatable_position.cc b/chromium/third_party/blink/renderer/core/editing/relocatable_position.cc
index 464ceb31b12..a11dddb5da6 100644
--- a/chromium/third_party/blink/renderer/core/editing/relocatable_position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/relocatable_position.cc
@@ -14,10 +14,12 @@ RelocatablePosition::RelocatablePosition(const Position& position)
position)
: nullptr) {}
-RelocatablePosition::~RelocatablePosition() {
- if (!range_)
- return;
- range_->Dispose();
+void RelocatablePosition::SetPosition(const Position& position) {
+ DCHECK(position.IsNotNull());
+ DCHECK(range_);
+ DCHECK_EQ(position.GetDocument(), range_->StartPosition().GetDocument());
+ range_->setStart(position);
+ range_->setEnd(position);
}
Position RelocatablePosition::GetPosition() const {
@@ -27,4 +29,8 @@ Position RelocatablePosition::GetPosition() const {
return range_->StartPosition();
}
+void RelocatablePosition::Trace(Visitor* visitor) const {
+ visitor->Trace(range_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/relocatable_position.h b/chromium/third_party/blink/renderer/core/editing/relocatable_position.h
index 99fa3ba0eb7..8d3ba42d9b5 100644
--- a/chromium/third_party/blink/renderer/core/editing/relocatable_position.h
+++ b/chromium/third_party/blink/renderer/core/editing/relocatable_position.h
@@ -15,19 +15,18 @@ namespace blink {
// anchor node is moved out of document. The class is implemented by using a
// temporary |Range| object to keep track of the |Position|, and disposing the
// |Range| when out of scope.
-class CORE_EXPORT RelocatablePosition final {
- STACK_ALLOCATED();
-
+class CORE_EXPORT RelocatablePosition final
+ : public GarbageCollected<RelocatablePosition> {
public:
explicit RelocatablePosition(const Position&);
- ~RelocatablePosition();
+ void SetPosition(const Position&);
Position GetPosition() const;
- private:
- Range* const range_;
+ void Trace(Visitor* visitor) const;
- DISALLOW_COPY_AND_ASSIGN(RelocatablePosition);
+ private:
+ Member<Range> const range_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection.idl b/chromium/third_party/blink/renderer/core/editing/selection.idl
index 465a945ceab..e328aa5040f 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection.idl
+++ b/chromium/third_party/blink/renderer/core/editing/selection.idl
@@ -54,7 +54,7 @@
[MeasureAs=SelectionSetBaseAndExtent, RaisesException] void setBaseAndExtent(Node? baseNode, unsigned long baseOffset,
Node? extentNode, unsigned long extentOffset);
[MeasureAs=SelectionSelectAllChildren, RaisesException] void selectAllChildren(Node node);
- [MeasureAs=SelectionDeleteDromDocument, CEReactions, CustomElementCallbacks] void deleteFromDocument();
+ [MeasureAs=SelectionDeleteDromDocument, CEReactions] void deleteFromDocument();
[MeasureAs=SelectionContainsNode] boolean containsNode(Node node, optional boolean allowPartialContainment = false);
[MeasureAs=SelectionDOMString] stringifier;
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_adjuster.cc b/chromium/third_party/blink/renderer/core/editing/selection_adjuster.cc
index f9b357f2a7b..c446c8da348 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_adjuster.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_adjuster.cc
@@ -43,11 +43,6 @@ template <typename Strategy>
SelectionTemplate<Strategy> ComputeAdjustedSelection(
const SelectionTemplate<Strategy> selection,
const EphemeralRangeTemplate<Strategy>& range) {
- if (selection.ComputeRange() == range) {
- // To pass "editing/deleting/delete_after_block_image.html", we need to
- // return original selection.
- return selection;
- }
if (range.StartPosition().CompareTo(range.EndPosition()) == 0) {
return typename SelectionTemplate<Strategy>::Builder()
.Collapse(selection.IsBaseFirst() ? range.StartPosition()
@@ -132,8 +127,7 @@ class GranularityAdjuster final {
return CreateVisiblePosition(word_start).DeepEquivalent();
}
case TextGranularity::kSentence:
- return StartOfSentence(CreateVisiblePosition(passed_start))
- .DeepEquivalent();
+ return StartOfSentencePosition(passed_start.GetPosition());
case TextGranularity::kLine:
return StartOfLine(CreateVisiblePosition(passed_start))
.DeepEquivalent();
@@ -148,14 +142,14 @@ class GranularityAdjuster final {
return StartOfParagraph(pos).DeepEquivalent();
}
case TextGranularity::kDocumentBoundary:
- return StartOfDocument(CreateVisiblePosition(passed_start))
+ return CreateVisiblePosition(
+ StartOfDocument(passed_start.GetPosition()))
.DeepEquivalent();
case TextGranularity::kParagraphBoundary:
return StartOfParagraph(CreateVisiblePosition(passed_start))
.DeepEquivalent();
case TextGranularity::kSentenceBoundary:
- return StartOfSentence(CreateVisiblePosition(passed_start))
- .DeepEquivalent();
+ return StartOfSentencePosition(passed_start.GetPosition());
}
NOTREACHED();
@@ -231,7 +225,7 @@ class GranularityAdjuster final {
.DeepEquivalent();
case TextGranularity::kLine: {
const VisiblePositionTemplate<Strategy> end =
- EndOfLine(CreateVisiblePosition(passed_end));
+ CreateVisiblePosition(EndOfLine(passed_end));
if (!IsEndOfParagraph(end))
return end.DeepEquivalent();
// If the end of this line is at the end of a paragraph, include the
@@ -242,7 +236,7 @@ class GranularityAdjuster final {
return next.DeepEquivalent();
}
case TextGranularity::kLineBoundary:
- return EndOfLine(CreateVisiblePosition(passed_end)).DeepEquivalent();
+ return EndOfLine(passed_end).GetPosition();
case TextGranularity::kParagraph: {
const VisiblePositionTemplate<Strategy> visible_paragraph_end =
EndOfParagraph(CreateVisiblePosition(passed_end));
@@ -418,11 +412,6 @@ class ShadowBoundaryAdjuster final {
return FlatTreeTraversal::IsDescendantOf(*anchor_node, node);
}
- static bool IsSelectionBoundary(const Node& node) {
- return IsA<HTMLTextAreaElement>(node) || IsA<HTMLInputElement>(node) ||
- IsA<HTMLSelectElement>(node);
- }
-
static Node* EnclosingShadowHostForStart(const PositionInFlatTree& position) {
Node* node = position.NodeAsRangeFirstNode();
if (!node)
@@ -432,7 +421,7 @@ class ShadowBoundaryAdjuster final {
return nullptr;
if (!IsEnclosedBy(position, *shadow_host))
return nullptr;
- return IsSelectionBoundary(*shadow_host) ? shadow_host : nullptr;
+ return IsUserSelectContain(*shadow_host) ? shadow_host : nullptr;
}
static Node* EnclosingShadowHostForEnd(const PositionInFlatTree& position) {
@@ -444,7 +433,7 @@ class ShadowBoundaryAdjuster final {
return nullptr;
if (!IsEnclosedBy(position, *shadow_host))
return nullptr;
- return IsSelectionBoundary(*shadow_host) ? shadow_host : nullptr;
+ return IsUserSelectContain(*shadow_host) ? shadow_host : nullptr;
}
static PositionInFlatTree AdjustPositionInFlatTreeForStart(
@@ -751,7 +740,7 @@ class SelectionTypeAdjuster final {
const EphemeralRangeTemplate<Strategy> minimal_range(
MostForwardCaretPosition(range.StartPosition()),
MostBackwardCaretPosition(range.EndPosition()));
- if (selection.IsBaseFirst()) {
+ if (minimal_range.IsCollapsed() || selection.IsBaseFirst()) {
return typename SelectionTemplate<Strategy>::Builder()
.SetAsForwardSelection(minimal_range)
.Build();
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_adjuster_test.cc b/chromium/third_party/blink/renderer/core/editing/selection_adjuster_test.cc
index 447cc6a84a1..88e5f1f3cca 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_adjuster_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_adjuster_test.cc
@@ -517,4 +517,23 @@ TEST_F(SelectionAdjusterTest, ShadowHostAndShadowTreeAreEditable) {
</div>)HTML",
GetSelectionTextInFlatTreeFromBody(result2));
}
+
+TEST_F(SelectionAdjusterTest, AdjustSelectionTypeWithShadow) {
+ SetBodyContent("<p id='host'>foo</p>");
+ SetShadowContent("bar<slot></slot>", "host");
+
+ Element* host = GetDocument().getElementById("host");
+ const Position& base = Position(host->firstChild(), 0);
+ const Position& extent = Position(host, 0);
+ const SelectionInDOMTree& selection =
+ SelectionInDOMTree::Builder().Collapse(base).Extend(extent).Build();
+
+ // Should not crash
+ const SelectionInDOMTree& adjusted =
+ SelectionAdjuster::AdjustSelectionType(selection);
+
+ EXPECT_EQ(base, adjusted.Base());
+ EXPECT_EQ(extent, adjusted.Extent());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_controller.cc b/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
index f9ed58f6bfc..ea865fbfed6 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_controller.cc
@@ -491,7 +491,7 @@ void SelectionController::UpdateSelectionForMouseDrag(
Selection().SelectionHasFocus()
? PositionRespectingEditingBoundary(
Selection().ComputeVisibleSelectionInDOMTree().Start(),
- hit_test_result.LocalPoint(), target)
+ hit_test_result)
: PositionWithAffinity();
const PositionInFlatTreeWithAffinity target_position =
CreateVisiblePosition(
@@ -627,10 +627,9 @@ bool SelectionController::SelectClosestWordFromHitTestResult(
.ToPositionWithAffinity();
const SelectionInFlatTree new_selection =
pos.IsNotNull()
- ? CreateVisibleSelectionWithGranularity(
+ ? ExpandWithGranularity(
SelectionInFlatTree::Builder().Collapse(pos).Build(),
TextGranularity::kWord)
- .AsSelection()
: SelectionInFlatTree();
// TODO(editing-dev): Fix CreateVisibleSelectionWithGranularity() to not
@@ -966,10 +965,9 @@ bool SelectionController::HandleTripleClick(
.ToPositionWithAffinity();
const SelectionInFlatTree new_selection =
pos.IsNotNull()
- ? CreateVisibleSelectionWithGranularity(
+ ? ExpandWithGranularity(
SelectionInFlatTree::Builder().Collapse(pos).Build(),
TextGranularity::kParagraph)
- .AsSelection()
: SelectionInFlatTree();
const bool is_handle_visible =
@@ -1193,11 +1191,7 @@ void SelectionController::HandleGestureTwoFingerTap(
}
static bool HitTestResultIsMisspelled(const HitTestResult& result) {
- Node* inner_node = result.InnerPossiblyPseudoNode();
- if (!inner_node || !inner_node->GetLayoutObject())
- return false;
- PositionWithAffinity pos_with_affinity =
- inner_node->GetLayoutObject()->PositionForPoint(result.LocalPoint());
+ PositionWithAffinity pos_with_affinity = result.GetPosition();
if (pos_with_affinity.IsNull())
return false;
// TODO(xiaochengh): Don't use |ParentAnchoredEquivalent()|.
@@ -1205,8 +1199,9 @@ static bool HitTestResultIsMisspelled(const HitTestResult& result) {
pos_with_affinity.GetPosition().ParentAnchoredEquivalent();
if (!SpellChecker::IsSpellCheckingEnabledAt(marker_position))
return false;
- return SpellCheckMarkerAtPosition(inner_node->GetDocument().Markers(),
- ToPositionInFlatTree(marker_position));
+ return SpellCheckMarkerAtPosition(
+ result.InnerPossiblyPseudoNode()->GetDocument().Markers(),
+ ToPositionInFlatTree(marker_position));
}
template <typename MouseEventObject>
@@ -1241,6 +1236,9 @@ void SelectionController::UpdateSelectionForContextMenuEvent(
if (!frame_->GetEditor().Behavior().ShouldSelectOnContextualMenuClick())
return;
+ if (mouse_event->GetMenuSourceType() == kMenuSourceLongPress)
+ return;
+
SelectClosestWordOrLinkFromMouseEvent(mouse_event, hit_test_result);
}
@@ -1296,18 +1294,16 @@ void SelectionController::NotifySelectionChanged() {
const SelectionInDOMTree& selection =
this->Selection().GetSelectionInDOMTree();
- switch (selection.Type()) {
- case kNoSelection:
- selection_state_ = SelectionState::kHaveNotStartedSelection;
- return;
- case kCaretSelection:
- selection_state_ = SelectionState::kPlacedCaret;
- return;
- case kRangeSelection:
- selection_state_ = SelectionState::kExtendedSelection;
- return;
+ if (selection.IsNone()) {
+ selection_state_ = SelectionState::kHaveNotStartedSelection;
+ return;
+ }
+ if (selection.IsCaret()) {
+ selection_state_ = SelectionState::kPlacedCaret;
+ return;
}
- NOTREACHED() << "We should handle all SelectionType" << selection;
+ DCHECK(selection.IsRange()) << selection;
+ selection_state_ = SelectionState::kExtendedSelection;
}
FrameSelection& SelectionController::Selection() const {
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_controller.h b/chromium/third_party/blink/renderer/core/editing/selection_controller.h
index b514f295896..2f68d8f64d0 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/selection_controller.h
@@ -47,7 +47,7 @@ class CORE_EXPORT SelectionController final
public ExecutionContextLifecycleObserver {
public:
explicit SelectionController(LocalFrame&);
- virtual ~SelectionController();
+ ~SelectionController() override;
void Trace(Visitor*) const override;
bool HandleMousePressEvent(const MouseEventWithHitTestResults&);
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_controller_test.cc b/chromium/third_party/blink/renderer/core/editing/selection_controller_test.cc
index 34e21643448..55e2f92e020 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_controller_test.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -33,16 +34,14 @@ class SelectionControllerTest : public EditingTestBase {
return GetFrame().GetEventHandler().HitTestResultAtLocation(location);
}
- static PositionWithAffinity GetPositionFromHitTestResult(
- const HitTestResult& hit_test_result) {
- return hit_test_result.InnerNode()->GetLayoutObject()->PositionForPoint(
- hit_test_result.LocalPoint());
+ HitTestResult HitTestResultAtLocation(int x, int y) {
+ HitTestLocation location(IntPoint(x, y));
+ return HitTestResultAtLocation(location);
}
- PositionWithAffinity GetPositionAtLocation(const IntPoint& point) {
- HitTestLocation location(point);
- HitTestResult result = HitTestResultAtLocation(location);
- return GetPositionFromHitTestResult(result);
+ static PositionWithAffinity GetPositionFromHitTestResult(
+ const HitTestResult& hit_test_result) {
+ return hit_test_result.GetPosition();
}
VisibleSelection VisibleSelectionInDOMTree() const {
@@ -97,6 +96,8 @@ class ParameterizedSelectionControllerTest
private ScopedLayoutNGForTest {
public:
ParameterizedSelectionControllerTest() : ScopedLayoutNGForTest(GetParam()) {}
+
+ bool LayoutNGEnabled() const { return GetParam(); }
};
INSTANTIATE_TEST_SUITE_P(SelectionControllerTest,
@@ -241,15 +242,14 @@ TEST_F(SelectionControllerTest, AdjustSelectionWithTrailingWhitespace) {
"<div style='user-select:none'>abc</div>");
Element* const input = GetDocument().QuerySelector("input");
- const VisibleSelectionInFlatTree& selection =
- CreateVisibleSelectionWithGranularity(
- SelectionInFlatTree::Builder()
- .Collapse(PositionInFlatTree::BeforeNode(*input))
- .Extend(PositionInFlatTree::AfterNode(*input))
- .Build(),
- TextGranularity::kWord);
+ const SelectionInFlatTree& selection = ExpandWithGranularity(
+ SelectionInFlatTree::Builder()
+ .Collapse(PositionInFlatTree::BeforeNode(*input))
+ .Extend(PositionInFlatTree::AfterNode(*input))
+ .Build(),
+ TextGranularity::kWord);
const SelectionInFlatTree& result =
- AdjustSelectionWithTrailingWhitespace(selection.AsSelection());
+ AdjustSelectionWithTrailingWhitespace(selection);
EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
result.ComputeStartPosition());
@@ -445,11 +445,11 @@ TEST_P(ParameterizedSelectionControllerTest, Scroll) {
html, body {
margin: 0;
font-size: 50px;
- line-height: 1;
+ line-height: 2;
}
#scroller {
width: 400px;
- height: 5em;
+ height: 600px;
overflow: scroll;
}
</style>
@@ -458,21 +458,26 @@ TEST_P(ParameterizedSelectionControllerTest, Scroll) {
<span>line2</span><br>
<span>line3</span><br>
<span>line4</span><br>
- <span>line5</span><br>
- <span>line6</span><br>
- <span>line7</span><br>
- <span>line8</span><br>
+ <span style="padding-left: 100px">line5</span><br>
+ <span style="border-left: 100px solid blue">line6</span><br>
+ <span style="margin-left: 100px">line7</span><br>
+ <span style="display: inline-block; width: 100px; height: 1em; line-height: 1">x</span>line8<br>
<span>line9</span><br>
</div>
)HTML");
// Scroll #scroller by 2 lines. "line3" should be at the top.
Element* scroller = GetElementById("scroller");
- scroller->setScrollTop(100);
+ scroller->setScrollTop(200);
// Hit-test on the first visible line. This should be "line3".
- PositionWithAffinity line3 = GetPositionAtLocation(IntPoint(5, 5));
- EXPECT_EQ(line3.AnchorNode()->textContent(), "line3");
+ HitTestResult line3_result = HitTestResultAtLocation(5, 50);
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line3_result.LocalPoint(), PhysicalOffset(5, 50));
+ PositionWithAffinity line3 = line3_result.GetPosition();
+ Node* line3_node = line3.AnchorNode();
+ EXPECT_EQ(line3_node->nodeName(), "#text");
+ EXPECT_EQ(line3_node->textContent(), "line3");
// Then hit-test beyond the end of the first visible line. This should snap to
// the end of the "line3".
@@ -480,8 +485,59 @@ TEST_P(ParameterizedSelectionControllerTest, Scroll) {
// +------------
// |line3 x <-- Click here
// |line4
- PositionWithAffinity line3_end = GetPositionAtLocation(IntPoint(300, 5));
- EXPECT_EQ(line3_end.AnchorNode()->textContent(), "line3");
+ HitTestResult line3_end_result = HitTestResultAtLocation(300, 50);
+ EXPECT_EQ(line3_end_result.LocalPoint(), PhysicalOffset(300, 50));
+ PositionWithAffinity line3_end = line3_end_result.GetPosition();
+ Node* line3_end_node = line3_end.AnchorNode();
+ EXPECT_EQ(line3_end_node->nodeName(), "#text");
+ EXPECT_EQ(line3_end_node->textContent(), "line3");
+
+ // At the line-gap between line3 and line4.
+ // There is no |LayoutText| here, but it should snap to line4.
+ HitTestResult line4_over_result = HitTestResultAtLocation(5, 101);
+ EXPECT_EQ(line4_over_result.LocalPoint(), PhysicalOffset(5, 101));
+ PositionWithAffinity line4_over = line4_over_result.GetPosition();
+ Node* line4_over_node = line4_over.AnchorNode();
+ EXPECT_EQ(line4_over_node->nodeName(), "#text");
+ EXPECT_EQ(line4_over_node->textContent(), "line4");
+
+ // At the padding of an inline box.
+ HitTestResult line5_result = HitTestResultAtLocation(5, 250);
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line5_result.LocalPoint(), PhysicalOffset(5, 250));
+ PositionWithAffinity line5 = line5_result.GetPosition();
+ Node* line5_node = line5.AnchorNode();
+ EXPECT_EQ(line5_node->nodeName(), "#text");
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line5_node->textContent(), "line5");
+
+ // At the border of an inline box.
+ HitTestResult line6_result = HitTestResultAtLocation(5, 350);
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line6_result.LocalPoint(), PhysicalOffset(5, 350));
+ PositionWithAffinity line6 = line6_result.GetPosition();
+ Node* line6_node = line6.AnchorNode();
+ EXPECT_EQ(line6_node->nodeName(), "#text");
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line6_node->textContent(), "line6");
+
+ // At the margin of an inline box.
+ HitTestResult line7_result = HitTestResultAtLocation(5, 450);
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line7_result.LocalPoint(), PhysicalOffset(5, 450));
+ PositionWithAffinity line7 = line7_result.GetPosition();
+ Node* line7_node = line7.AnchorNode();
+ EXPECT_EQ(line7_node->nodeName(), "#text");
+ if (LayoutNGEnabled()) // Legacy fails this test.
+ EXPECT_EQ(line7_node->textContent(), "line7");
+
+ // At the inline-block.
+ HitTestResult line8_result = HitTestResultAtLocation(5, 550);
+ EXPECT_EQ(line8_result.LocalPoint(), PhysicalOffset(5, 25));
+ PositionWithAffinity line8 = line8_result.GetPosition();
+ Node* line8_node = line8.AnchorNode();
+ EXPECT_EQ(line8_node->nodeName(), "#text");
+ EXPECT_EQ(line8_node->textContent(), "x");
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_editor.cc b/chromium/third_party/blink/renderer/core/editing/selection_editor.cc
index 8937677efc9..31f71d52186 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_editor.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_editor.cc
@@ -318,7 +318,6 @@ static Position UpdatePostionAfterAdoptingTextNodesMerged(
Node* const anchor_node = position.AnchorNode();
const Node& node_to_be_removed = node_to_be_removed_with_index.GetNode();
switch (position.AnchorType()) {
- case PositionAnchorType::kBeforeChildren:
case PositionAnchorType::kAfterChildren:
return position;
case PositionAnchorType::kBeforeAnchor:
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
index 61766be9b0c..15d75e08ecb 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/inline_box_position.h"
#include "third_party/blink/renderer/core/editing/local_caret_rect.h"
+#include "third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
@@ -44,7 +45,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/page/spatial_navigation.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
namespace blink {
@@ -54,15 +54,16 @@ namespace {
// enters an infinite loop. Work around it by hard-limiting the iteration.
const unsigned kMaxIterationForPageGranularityMovement = 1024;
-VisiblePosition LeftBoundaryOfLine(const VisiblePosition& c,
- TextDirection direction) {
+VisiblePositionInFlatTree LeftBoundaryOfLine(const VisiblePositionInFlatTree& c,
+ TextDirection direction) {
DCHECK(c.IsValid()) << c;
return direction == TextDirection::kLtr ? LogicalStartOfLine(c)
: LogicalEndOfLine(c);
}
-VisiblePosition RightBoundaryOfLine(const VisiblePosition& c,
- TextDirection direction) {
+VisiblePositionInFlatTree RightBoundaryOfLine(
+ const VisiblePositionInFlatTree& c,
+ TextDirection direction) {
DCHECK(c.IsValid()) << c;
return direction == TextDirection::kLtr ? LogicalEndOfLine(c)
: LogicalStartOfLine(c);
@@ -70,15 +71,26 @@ VisiblePosition RightBoundaryOfLine(const VisiblePosition& c,
} // namespace
+static bool InSameParagraph(const VisiblePositionInFlatTree& a,
+ const VisiblePositionInFlatTree& b,
+ EditingBoundaryCrossingRule boundary_crossing_rule =
+ kCannotCrossEditingBoundary) {
+ DCHECK(a.IsValid()) << a;
+ DCHECK(b.IsValid()) << b;
+ return a.IsNotNull() &&
+ StartOfParagraph(a, boundary_crossing_rule).DeepEquivalent() ==
+ StartOfParagraph(b, boundary_crossing_rule).DeepEquivalent();
+}
+
// static
-VisiblePosition SelectionModifier::PreviousParagraphPosition(
- const VisiblePosition& passed_position,
+VisiblePositionInFlatTree SelectionModifier::PreviousParagraphPosition(
+ const VisiblePositionInFlatTree& passed_position,
LayoutUnit x_point) {
- DCHECK(passed_position.IsValid()) << passed_position;
- VisiblePosition position = passed_position;
+ VisiblePositionInFlatTree position = passed_position;
do {
- const VisiblePosition& new_position =
- PreviousLinePosition(position, x_point);
+ DCHECK(position.IsValid()) << position;
+ const VisiblePositionInFlatTree& new_position = CreateVisiblePosition(
+ PreviousLinePosition(position.ToPositionWithAffinity(), x_point));
if (new_position.IsNull() ||
new_position.DeepEquivalent() == position.DeepEquivalent())
break;
@@ -88,13 +100,14 @@ VisiblePosition SelectionModifier::PreviousParagraphPosition(
}
// static
-VisiblePosition SelectionModifier::NextParagraphPosition(
- const VisiblePosition& passed_position,
+VisiblePositionInFlatTree SelectionModifier::NextParagraphPosition(
+ const VisiblePositionInFlatTree& passed_position,
LayoutUnit x_point) {
- DCHECK(passed_position.IsValid()) << passed_position;
- VisiblePosition position = passed_position;
+ VisiblePositionInFlatTree position = passed_position;
do {
- const VisiblePosition& new_position = NextLinePosition(position, x_point);
+ DCHECK(position.IsValid()) << position;
+ const VisiblePositionInFlatTree& new_position = CreateVisiblePosition(
+ NextLinePosition(position.ToPositionWithAffinity(), x_point));
if (new_position.IsNull() ||
new_position.DeepEquivalent() == position.DeepEquivalent())
break;
@@ -117,7 +130,7 @@ SelectionModifier::SelectionModifier(
const SelectionInDOMTree& selection,
LayoutUnit x_pos_for_vertical_arrow_navigation)
: frame_(&frame),
- current_selection_(selection),
+ current_selection_(ConvertToSelectionInFlatTree(selection)),
x_pos_for_vertical_arrow_navigation_(
x_pos_for_vertical_arrow_navigation) {}
@@ -126,20 +139,21 @@ SelectionModifier::SelectionModifier(const LocalFrame& frame,
: SelectionModifier(frame, selection, NoXPosForVerticalArrowNavigation()) {}
VisibleSelection SelectionModifier::Selection() const {
- return CreateVisibleSelection(current_selection_);
+ return CreateVisibleSelection(
+ ConvertToSelectionInDOMTree(current_selection_));
}
-static VisiblePosition ComputeVisibleExtent(
- const VisibleSelection& visible_selection) {
+static VisiblePositionInFlatTree ComputeVisibleExtent(
+ const VisibleSelectionInFlatTree& visible_selection) {
return CreateVisiblePosition(visible_selection.Extent(),
visible_selection.Affinity());
}
TextDirection SelectionModifier::DirectionOfEnclosingBlock() const {
- const Position& selection_extent = selection_.Extent();
+ const PositionInFlatTree& selection_extent = selection_.Extent();
- // TODO(editing-dev): Check for Position::IsNotNull is an easy fix for few
- // editing/ web tests, that didn't expect that (e.g.
+ // TODO(editing-dev): Check for PositionInFlatTree::IsNotNull is an easy fix
+ // for few editing/ web tests, that didn't expect that (e.g.
// editing/selection/extend-byline-withfloat.html).
// That should be fixed in a more appropriate manner.
// We should either have SelectionModifier aborted earlier for null selection,
@@ -151,10 +165,12 @@ TextDirection SelectionModifier::DirectionOfEnclosingBlock() const {
namespace {
-base::Optional<TextDirection> DirectionAt(const VisiblePosition& position) {
+base::Optional<TextDirection> DirectionAt(
+ const PositionInFlatTreeWithAffinity& position) {
if (position.IsNull())
return base::nullopt;
- const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+ const PositionInFlatTreeWithAffinity adjusted =
+ ComputeInlineAdjustedPosition(position);
if (adjusted.IsNull())
return base::nullopt;
@@ -173,10 +189,12 @@ base::Optional<TextDirection> DirectionAt(const VisiblePosition& position) {
}
// TODO(xiaochengh): Deduplicate code with |DirectionAt()|.
-base::Optional<TextDirection> LineDirectionAt(const VisiblePosition& position) {
+base::Optional<TextDirection> LineDirectionAt(
+ const PositionInFlatTreeWithAffinity& position) {
if (position.IsNull())
return base::nullopt;
- const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+ const PositionInFlatTreeWithAffinity adjusted =
+ ComputeInlineAdjustedPosition(position);
if (adjusted.IsNull())
return base::nullopt;
@@ -196,11 +214,11 @@ base::Optional<TextDirection> LineDirectionAt(const VisiblePosition& position) {
return base::nullopt;
}
-TextDirection DirectionOf(const VisibleSelection& visible_selection) {
+TextDirection DirectionOf(const VisibleSelectionInFlatTree& visible_selection) {
base::Optional<TextDirection> maybe_start_direction =
- DirectionAt(visible_selection.VisibleStart());
+ DirectionAt(visible_selection.VisibleStart().ToPositionWithAffinity());
base::Optional<TextDirection> maybe_end_direction =
- DirectionAt(visible_selection.VisibleEnd());
+ DirectionAt(visible_selection.VisibleEnd().ToPositionWithAffinity());
if (maybe_start_direction.has_value() && maybe_end_direction.has_value() &&
maybe_start_direction.value() == maybe_end_direction.value())
return maybe_start_direction.value();
@@ -215,11 +233,11 @@ TextDirection SelectionModifier::DirectionOfSelection() const {
}
TextDirection SelectionModifier::LineDirectionOfExtent() const {
- return LineDirectionAt(selection_.VisibleExtent())
+ return LineDirectionAt(selection_.VisibleExtent().ToPositionWithAffinity())
.value_or(DirectionOfEnclosingBlockOf(selection_.Extent()));
}
-static bool IsBaseStart(const VisibleSelection& visible_selection,
+static bool IsBaseStart(const VisibleSelectionInFlatTree& visible_selection,
SelectionModifyDirection direction) {
switch (direction) {
case SelectionModifyDirection::kRight:
@@ -235,25 +253,27 @@ static bool IsBaseStart(const VisibleSelection& visible_selection,
return true;
}
-// This function returns |VisibleSelection| from start and end position of
-// current_selection_'s |VisibleSelection| with |direction| and ordering of base
-// and extent to handle base/extent don't match to start/end, e.g. granularity
-// != character, and start/end adjustment in |visibleSelection::validate()| for
-// range selection.
-VisibleSelection SelectionModifier::PrepareToModifySelection(
+// This function returns |VisibleSelectionInFlatTree| from start and end
+// position of current_selection_'s |VisibleSelectionInFlatTree| with
+// |direction| and ordering of base and extent to handle base/extent don't match
+// to start/end, e.g. granularity
+// != character, and start/end adjustment in
+// |VisibleSelectionInFlatTree::validate()| for range selection.
+VisibleSelectionInFlatTree SelectionModifier::PrepareToModifySelection(
SelectionModifyAlteration alter,
SelectionModifyDirection direction) const {
- const VisibleSelection& visible_selection =
+ const VisibleSelectionInFlatTree& visible_selection =
CreateVisibleSelection(current_selection_);
if (alter != SelectionModifyAlteration::kExtend)
return visible_selection;
if (visible_selection.IsNone())
return visible_selection;
- const EphemeralRange& range = visible_selection.AsSelection().ComputeRange();
+ const EphemeralRangeInFlatTree& range =
+ visible_selection.AsSelection().ComputeRange();
if (range.IsCollapsed())
return visible_selection;
- SelectionInDOMTree::Builder builder;
+ SelectionInFlatTree::Builder builder;
// Make base and extent match start and end so we extend the user-visible
// selection. This only matters for cases where base and extend point to
// different positions than start and end (e.g. after a double-click to
@@ -268,63 +288,65 @@ VisibleSelection SelectionModifier::PrepareToModifySelection(
return CreateVisibleSelection(builder.Build());
}
-VisiblePosition SelectionModifier::PositionForPlatform(
+VisiblePositionInFlatTree SelectionModifier::PositionForPlatform(
bool is_get_start) const {
Settings* settings = GetFrame().GetSettings();
if (settings && settings->GetEditingBehaviorType() ==
mojom::blink::EditingBehavior::kEditingMacBehavior)
return is_get_start ? selection_.VisibleStart() : selection_.VisibleEnd();
// Linux and Windows always extend selections from the extent endpoint.
- // FIXME: VisibleSelection should be fixed to ensure as an invariant that
- // base/extent always point to the same nodes as start/end, but which points
- // to which depends on the value of isBaseFirst. Then this can be changed
- // to just return selection_.extent().
+ // FIXME: VisibleSelectionInFlatTree should be fixed to ensure as an invariant
+ // that base/extent always point to the same nodes as start/end, but which
+ // points to which depends on the value of isBaseFirst. Then this can be
+ // changed to just return selection_.extent().
return selection_.IsBaseFirst() ? selection_.VisibleEnd()
: selection_.VisibleStart();
}
-VisiblePosition SelectionModifier::StartForPlatform() const {
+VisiblePositionInFlatTree SelectionModifier::StartForPlatform() const {
return PositionForPlatform(true);
}
-VisiblePosition SelectionModifier::EndForPlatform() const {
+VisiblePositionInFlatTree SelectionModifier::EndForPlatform() const {
return PositionForPlatform(false);
}
-Position SelectionModifier::NextWordPositionForPlatform(
- const Position& original_position) {
+PositionInFlatTree SelectionModifier::NextWordPositionForPlatform(
+ const PositionInFlatTree& original_position) {
const PlatformWordBehavior platform_word_behavior =
GetFrame().GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight()
? PlatformWordBehavior::kWordSkipSpaces
: PlatformWordBehavior::kWordDontSkipSpaces;
// Next word position can't be upstream.
- const Position position_after_current_word =
+ const PositionInFlatTree position_after_current_word =
NextWordPosition(original_position, platform_word_behavior).GetPosition();
return position_after_current_word;
}
-static VisiblePosition AdjustForwardPositionForUserSelectAll(
- const VisiblePosition& position) {
+static VisiblePositionInFlatTree AdjustForwardPositionForUserSelectAll(
+ const VisiblePositionInFlatTree& position) {
Node* const root_user_select_all = EditingStrategy::RootUserSelectAllForNode(
position.DeepEquivalent().AnchorNode());
if (!root_user_select_all)
return position;
return CreateVisiblePosition(MostForwardCaretPosition(
- Position::AfterNode(*root_user_select_all), kCanCrossEditingBoundary));
+ PositionInFlatTree::AfterNode(*root_user_select_all),
+ kCanCrossEditingBoundary));
}
-static VisiblePosition AdjustBackwardPositionForUserSelectAll(
- const VisiblePosition& position) {
+static VisiblePositionInFlatTree AdjustBackwardPositionForUserSelectAll(
+ const VisiblePositionInFlatTree& position) {
Node* const root_user_select_all = EditingStrategy::RootUserSelectAllForNode(
position.DeepEquivalent().AnchorNode());
if (!root_user_select_all)
return position;
return CreateVisiblePosition(MostBackwardCaretPosition(
- Position::BeforeNode(*root_user_select_all), kCanCrossEditingBoundary));
+ PositionInFlatTree::BeforeNode(*root_user_select_all),
+ kCanCrossEditingBoundary));
}
-VisiblePosition SelectionModifier::ModifyExtendingRightInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingRightInternal(
TextGranularity granularity) {
// The difference between modifyExtendingRight and modifyExtendingForward is:
// modifyExtendingForward always extends forward logically.
@@ -361,18 +383,19 @@ VisiblePosition SelectionModifier::ModifyExtendingRightInternal(
return ModifyExtendingForwardInternal(granularity);
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyExtendingRight(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingRight(
TextGranularity granularity) {
- const VisiblePosition& pos = ModifyExtendingRightInternal(granularity);
+ const VisiblePositionInFlatTree& pos =
+ ModifyExtendingRightInternal(granularity);
if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
return AdjustForwardPositionForUserSelectAll(pos);
return AdjustBackwardPositionForUserSelectAll(pos);
}
-VisiblePosition SelectionModifier::ModifyExtendingForwardInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingForwardInternal(
TextGranularity granularity) {
switch (granularity) {
case TextGranularity::kCharacter:
@@ -382,11 +405,17 @@ VisiblePosition SelectionModifier::ModifyExtendingForwardInternal(
return CreateVisiblePosition(NextWordPositionForPlatform(
ComputeVisibleExtent(selection_).DeepEquivalent()));
case TextGranularity::kSentence:
- return NextSentencePosition(ComputeVisibleExtent(selection_));
- case TextGranularity::kLine:
- return NextLinePosition(
- ComputeVisibleExtent(selection_),
- LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
+ return CreateVisiblePosition(
+ NextSentencePosition(
+ ComputeVisibleExtent(selection_).DeepEquivalent()),
+ TextAffinity::kUpstreamIfPossible);
+ case TextGranularity::kLine: {
+ const VisiblePositionInFlatTree& pos = ComputeVisibleExtent(selection_);
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(NextLinePosition(
+ pos.ToPositionWithAffinity(),
+ LineDirectionPointForBlockDirectionNavigation(selection_.Extent())));
+ }
case TextGranularity::kParagraph:
return NextParagraphPosition(
ComputeVisibleExtent(selection_),
@@ -398,25 +427,29 @@ VisiblePosition SelectionModifier::ModifyExtendingForwardInternal(
case TextGranularity::kParagraphBoundary:
return EndOfParagraph(EndForPlatform());
case TextGranularity::kDocumentBoundary: {
- const VisiblePosition& pos = EndForPlatform();
- if (IsEditablePosition(pos.DeepEquivalent()))
- return EndOfEditableContent(pos);
+ const VisiblePositionInFlatTree& pos = EndForPlatform();
+ if (IsEditablePosition(pos.DeepEquivalent())) {
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(
+ EndOfEditableContent(pos.DeepEquivalent()));
+ }
return EndOfDocument(pos);
}
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyExtendingForward(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingForward(
TextGranularity granularity) {
- const VisiblePosition pos = ModifyExtendingForwardInternal(granularity);
+ const VisiblePositionInFlatTree pos =
+ ModifyExtendingForwardInternal(granularity);
if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
return AdjustForwardPositionForUserSelectAll(pos);
return AdjustBackwardPositionForUserSelectAll(pos);
}
-VisiblePosition SelectionModifier::ModifyMovingRight(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingRight(
TextGranularity granularity) {
switch (granularity) {
case TextGranularity::kCharacter:
@@ -445,10 +478,10 @@ VisiblePosition SelectionModifier::ModifyMovingRight(
DirectionOfEnclosingBlock());
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyMovingForward(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingForward(
TextGranularity granularity) {
// TODO(editing-dev): Stay in editable content for the less common
// granularities.
@@ -462,17 +495,21 @@ VisiblePosition SelectionModifier::ModifyMovingForward(
return CreateVisiblePosition(NextWordPositionForPlatform(
ComputeVisibleExtent(selection_).DeepEquivalent()));
case TextGranularity::kSentence:
- return NextSentencePosition(ComputeVisibleExtent(selection_));
+ return CreateVisiblePosition(
+ NextSentencePosition(
+ ComputeVisibleExtent(selection_).DeepEquivalent()),
+ TextAffinity::kUpstreamIfPossible);
case TextGranularity::kLine: {
// down-arrowing from a range selection that ends at the start of a line
// needs to leave the selection at that line start (no need to call
// nextLinePosition!)
- const VisiblePosition& pos = EndForPlatform();
+ const VisiblePositionInFlatTree& pos = EndForPlatform();
if (selection_.IsRange() && IsStartOfLine(pos))
return pos;
- return NextLinePosition(
- pos,
- LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(NextLinePosition(
+ pos.ToPositionWithAffinity(),
+ LineDirectionPointForBlockDirectionNavigation(selection_.Start())));
}
case TextGranularity::kParagraph:
return NextParagraphPosition(
@@ -485,17 +522,20 @@ VisiblePosition SelectionModifier::ModifyMovingForward(
case TextGranularity::kParagraphBoundary:
return EndOfParagraph(EndForPlatform());
case TextGranularity::kDocumentBoundary: {
- const VisiblePosition& pos = EndForPlatform();
- if (IsEditablePosition(pos.DeepEquivalent()))
- return EndOfEditableContent(pos);
+ const VisiblePositionInFlatTree& pos = EndForPlatform();
+ if (IsEditablePosition(pos.DeepEquivalent())) {
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(
+ EndOfEditableContent(pos.DeepEquivalent()));
+ }
return EndOfDocument(pos);
}
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyExtendingLeftInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingLeftInternal(
TextGranularity granularity) {
// The difference between modifyExtendingLeft and modifyExtendingBackward is:
// modifyExtendingBackward always extends backward logically.
@@ -531,23 +571,24 @@ VisiblePosition SelectionModifier::ModifyExtendingLeftInternal(
return ModifyExtendingBackwardInternal(granularity);
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyExtendingLeft(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingLeft(
TextGranularity granularity) {
- const VisiblePosition& pos = ModifyExtendingLeftInternal(granularity);
+ const VisiblePositionInFlatTree& pos =
+ ModifyExtendingLeftInternal(granularity);
if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
return AdjustBackwardPositionForUserSelectAll(pos);
return AdjustForwardPositionForUserSelectAll(pos);
}
-VisiblePosition SelectionModifier::ModifyExtendingBackwardInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingBackwardInternal(
TextGranularity granularity) {
// Extending a selection backward by word or character from just after a table
// selects the table. This "makes sense" from the user perspective, esp. when
- // deleting. It was done here instead of in VisiblePosition because we want
- // VPs to iterate over everything.
+ // deleting. It was done here instead of in VisiblePositionInFlatTree because
+ // we want VPs to iterate over everything.
switch (granularity) {
case TextGranularity::kCharacter:
return PreviousPositionOf(ComputeVisibleExtent(selection_),
@@ -556,41 +597,50 @@ VisiblePosition SelectionModifier::ModifyExtendingBackwardInternal(
return CreateVisiblePosition(PreviousWordPosition(
ComputeVisibleExtent(selection_).DeepEquivalent()));
case TextGranularity::kSentence:
- return PreviousSentencePosition(ComputeVisibleExtent(selection_));
- case TextGranularity::kLine:
- return PreviousLinePosition(
- ComputeVisibleExtent(selection_),
- LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
+ return CreateVisiblePosition(PreviousSentencePosition(
+ ComputeVisibleExtent(selection_).DeepEquivalent()));
+ case TextGranularity::kLine: {
+ const VisiblePositionInFlatTree& pos = ComputeVisibleExtent(selection_);
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(PreviousLinePosition(
+ pos.ToPositionWithAffinity(),
+ LineDirectionPointForBlockDirectionNavigation(selection_.Extent())));
+ }
case TextGranularity::kParagraph:
return PreviousParagraphPosition(
ComputeVisibleExtent(selection_),
LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
case TextGranularity::kSentenceBoundary:
- return StartOfSentence(StartForPlatform());
+ return CreateVisiblePosition(
+ StartOfSentencePosition(StartForPlatform().DeepEquivalent()));
case TextGranularity::kLineBoundary:
return LogicalStartOfLine(StartForPlatform());
case TextGranularity::kParagraphBoundary:
return StartOfParagraph(StartForPlatform());
case TextGranularity::kDocumentBoundary: {
- const VisiblePosition pos = StartForPlatform();
- if (IsEditablePosition(pos.DeepEquivalent()))
- return StartOfEditableContent(pos);
- return StartOfDocument(pos);
+ const VisiblePositionInFlatTree pos = StartForPlatform();
+ if (IsEditablePosition(pos.DeepEquivalent())) {
+ DCHECK(pos.IsValid()) << pos;
+ return CreateVisiblePosition(
+ StartOfEditableContent(pos.DeepEquivalent()));
+ }
+ return CreateVisiblePosition(StartOfDocument(pos.DeepEquivalent()));
}
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyExtendingBackward(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingBackward(
TextGranularity granularity) {
- const VisiblePosition pos = ModifyExtendingBackwardInternal(granularity);
+ const VisiblePositionInFlatTree pos =
+ ModifyExtendingBackwardInternal(granularity);
if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
return AdjustBackwardPositionForUserSelectAll(pos);
return AdjustForwardPositionForUserSelectAll(pos);
}
-VisiblePosition SelectionModifier::ModifyMovingLeft(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingLeft(
TextGranularity granularity) {
switch (granularity) {
case TextGranularity::kCharacter:
@@ -619,12 +669,12 @@ VisiblePosition SelectionModifier::ModifyMovingLeft(
DirectionOfEnclosingBlock());
}
NOTREACHED() << static_cast<int>(granularity);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
-VisiblePosition SelectionModifier::ModifyMovingBackward(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingBackward(
TextGranularity granularity) {
- VisiblePosition pos;
+ VisiblePositionInFlatTree pos;
switch (granularity) {
case TextGranularity::kCharacter:
if (selection_.IsRange()) {
@@ -639,20 +689,25 @@ VisiblePosition SelectionModifier::ModifyMovingBackward(
ComputeVisibleExtent(selection_).DeepEquivalent()));
break;
case TextGranularity::kSentence:
- pos = PreviousSentencePosition(ComputeVisibleExtent(selection_));
+ pos = CreateVisiblePosition(PreviousSentencePosition(
+ ComputeVisibleExtent(selection_).DeepEquivalent()));
break;
- case TextGranularity::kLine:
- pos = PreviousLinePosition(
- StartForPlatform(),
- LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
+ case TextGranularity::kLine: {
+ const VisiblePositionInFlatTree& start = StartForPlatform();
+ DCHECK(start.IsValid()) << start;
+ pos = CreateVisiblePosition(PreviousLinePosition(
+ start.ToPositionWithAffinity(),
+ LineDirectionPointForBlockDirectionNavigation(selection_.Start())));
break;
+ }
case TextGranularity::kParagraph:
pos = PreviousParagraphPosition(
StartForPlatform(),
LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
break;
case TextGranularity::kSentenceBoundary:
- pos = StartOfSentence(StartForPlatform());
+ pos = CreateVisiblePosition(
+ StartOfSentencePosition(StartForPlatform().DeepEquivalent()));
break;
case TextGranularity::kLineBoundary:
pos = LogicalStartOfLine(StartForPlatform());
@@ -662,10 +717,13 @@ VisiblePosition SelectionModifier::ModifyMovingBackward(
break;
case TextGranularity::kDocumentBoundary:
pos = StartForPlatform();
- if (IsEditablePosition(pos.DeepEquivalent()))
- pos = StartOfEditableContent(pos);
- else
- pos = StartOfDocument(pos);
+ if (IsEditablePosition(pos.DeepEquivalent())) {
+ DCHECK(pos.IsValid()) << pos;
+ pos =
+ CreateVisiblePosition(StartOfEditableContent(pos.DeepEquivalent()));
+ } else {
+ pos = CreateVisiblePosition(StartOfDocument(pos.DeepEquivalent()));
+ }
break;
}
return pos;
@@ -677,7 +735,7 @@ static bool IsBoundary(TextGranularity granularity) {
granularity == TextGranularity::kDocumentBoundary;
}
-VisiblePosition SelectionModifier::ComputeModifyPosition(
+VisiblePositionInFlatTree SelectionModifier::ComputeModifyPosition(
SelectionModifyAlteration alter,
SelectionModifyDirection direction,
TextGranularity granularity) {
@@ -700,7 +758,7 @@ VisiblePosition SelectionModifier::ComputeModifyPosition(
return ModifyMovingBackward(granularity);
}
NOTREACHED() << static_cast<int>(direction);
- return VisiblePosition();
+ return VisiblePositionInFlatTree();
}
bool SelectionModifier::Modify(SelectionModifyAlteration alter,
@@ -715,8 +773,8 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
return false;
bool was_range = selection_.IsRange();
- VisiblePosition original_start_position = selection_.VisibleStart();
- VisiblePosition position =
+ VisiblePositionInFlatTree original_start_position = selection_.VisibleStart();
+ VisiblePositionInFlatTree position =
ComputeModifyPosition(alter, direction, granularity);
if (position.IsNull())
return false;
@@ -737,10 +795,9 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
switch (alter) {
case SelectionModifyAlteration::kMove:
- current_selection_ =
- SelectionInDOMTree::Builder()
- .Collapse(position.ToPositionWithAffinity())
- .Build();
+ current_selection_ = SelectionInFlatTree::Builder()
+ .Collapse(position.ToPositionWithAffinity())
+ .Build();
break;
case SelectionModifyAlteration::kExtend:
@@ -757,10 +814,11 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
// starting with the caret in the middle of a word and then
// word-selecting forward, leaving the caret in the same place where it
// was, instead of directly selecting to the end of the word.
- const VisibleSelection& new_selection = CreateVisibleSelection(
- SelectionInDOMTree::Builder(selection_.AsSelection())
- .Extend(position.DeepEquivalent())
- .Build());
+ const VisibleSelectionInFlatTree& new_selection =
+ CreateVisibleSelection(
+ SelectionInFlatTree::Builder(selection_.AsSelection())
+ .Extend(position.DeepEquivalent())
+ .Build());
if (selection_.IsBaseFirst() != new_selection.IsBaseFirst())
position = selection_.VisibleBase();
}
@@ -773,7 +831,7 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
.Behavior()
.ShouldAlwaysGrowSelectionWhenExtendingToBoundary() ||
selection_.IsCaret() || !IsBoundary(granularity)) {
- current_selection_ = SelectionInDOMTree::Builder()
+ current_selection_ = SelectionInFlatTree::Builder()
.Collapse(selection_.Base())
.Extend(position.DeepEquivalent())
.Build();
@@ -785,7 +843,7 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
(text_direction == TextDirection::kRtl &&
direction == SelectionModifyDirection::kLeft)) {
current_selection_ =
- SelectionInDOMTree::Builder()
+ SelectionInFlatTree::Builder()
.Collapse(selection_.IsBaseFirst()
? selection_.Base()
: position.DeepEquivalent())
@@ -794,7 +852,7 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
.Build();
} else {
current_selection_ =
- SelectionInDOMTree::Builder()
+ SelectionInFlatTree::Builder()
.Collapse(selection_.IsBaseFirst() ? position.DeepEquivalent()
: selection_.Base())
.Extend(selection_.IsBaseFirst() ? selection_.Extent()
@@ -813,9 +871,8 @@ bool SelectionModifier::Modify(SelectionModifyAlteration alter,
}
// TODO(yosin): Maybe baseline would be better?
-static bool AbsoluteCaretY(const VisiblePosition& c, int& y) {
- DCHECK(c.IsValid()) << c;
- IntRect rect = AbsoluteCaretBoundsOf(c.ToPositionWithAffinity());
+static bool AbsoluteCaretY(const PositionInFlatTreeWithAffinity& c, int& y) {
+ IntRect rect = AbsoluteCaretBoundsOf(c);
if (rect.IsEmpty())
return false;
y = rect.Y() + rect.Height() / 2;
@@ -838,7 +895,7 @@ bool SelectionModifier::ModifyWithPageGranularity(
? SelectionModifyDirection::kBackward
: SelectionModifyDirection::kForward);
- VisiblePosition pos;
+ VisiblePositionInFlatTree pos;
LayoutUnit x_pos;
switch (alter) {
case SelectionModifyAlteration::kMove:
@@ -860,28 +917,33 @@ bool SelectionModifier::ModifyWithPageGranularity(
}
int start_y;
- if (!AbsoluteCaretY(pos, start_y))
+ DCHECK(pos.IsValid()) << pos;
+ if (!AbsoluteCaretY(pos.ToPositionWithAffinity(), start_y))
return false;
if (direction == SelectionModifyVerticalDirection::kUp)
start_y = -start_y;
int last_y = start_y;
- VisiblePosition result;
- VisiblePosition next;
+ VisiblePositionInFlatTree result;
+ VisiblePositionInFlatTree next;
unsigned iteration_count = 0;
- for (VisiblePosition p = pos;
+ for (VisiblePositionInFlatTree p = pos;
iteration_count < kMaxIterationForPageGranularityMovement; p = next) {
++iteration_count;
- if (direction == SelectionModifyVerticalDirection::kUp)
- next = PreviousLinePosition(p, x_pos);
- else
- next = NextLinePosition(p, x_pos);
+ if (direction == SelectionModifyVerticalDirection::kUp) {
+ next = CreateVisiblePosition(
+ PreviousLinePosition(p.ToPositionWithAffinity(), x_pos));
+ } else {
+ next = CreateVisiblePosition(
+ NextLinePosition(p.ToPositionWithAffinity(), x_pos));
+ }
if (next.IsNull() || next.DeepEquivalent() == p.DeepEquivalent())
break;
int next_y;
- if (!AbsoluteCaretY(next, next_y))
+ DCHECK(next.IsValid()) << next;
+ if (!AbsoluteCaretY(next.ToPositionWithAffinity(), next_y))
break;
if (direction == SelectionModifyVerticalDirection::kUp)
next_y = -next_y;
@@ -899,7 +961,7 @@ bool SelectionModifier::ModifyWithPageGranularity(
switch (alter) {
case SelectionModifyAlteration::kMove:
current_selection_ =
- SelectionInDOMTree::Builder()
+ SelectionInFlatTree::Builder()
.Collapse(result.ToPositionWithAffinity())
.SetAffinity(direction == SelectionModifyVerticalDirection::kUp
? TextAffinity::kUpstream
@@ -907,7 +969,7 @@ bool SelectionModifier::ModifyWithPageGranularity(
.Build();
break;
case SelectionModifyAlteration::kExtend: {
- current_selection_ = SelectionInDOMTree::Builder()
+ current_selection_ = SelectionInFlatTree::Builder()
.Collapse(selection_.Base())
.Extend(result.DeepEquivalent())
.Build();
@@ -921,7 +983,7 @@ bool SelectionModifier::ModifyWithPageGranularity(
// Abs x/y position of the caret ignoring transforms.
// TODO(yosin) navigation with transforms should be smarter.
static LayoutUnit LineDirectionPointForBlockDirectionNavigationOf(
- const VisiblePosition& visible_position) {
+ const VisiblePositionInFlatTree& visible_position) {
if (visible_position.IsNull())
return LayoutUnit();
@@ -944,7 +1006,7 @@ static LayoutUnit LineDirectionPointForBlockDirectionNavigationOf(
}
LayoutUnit SelectionModifier::LineDirectionPointForBlockDirectionNavigation(
- const Position& pos) {
+ const PositionInFlatTree& pos) {
LayoutUnit x;
if (selection_.IsNone())
@@ -952,11 +1014,11 @@ LayoutUnit SelectionModifier::LineDirectionPointForBlockDirectionNavigation(
if (x_pos_for_vertical_arrow_navigation_ ==
NoXPosForVerticalArrowNavigation()) {
- VisiblePosition visible_position =
+ VisiblePositionInFlatTree visible_position =
CreateVisiblePosition(pos, selection_.Affinity());
- // VisiblePosition creation can fail here if a node containing the selection
- // becomes visibility:hidden after the selection is created and before this
- // function is called.
+ // VisiblePositionInFlatTree creation can fail here if a node containing the
+ // selection becomes visibility:hidden after the selection is created and
+ // before this function is called.
x = LineDirectionPointForBlockDirectionNavigationOf(visible_position);
x_pos_for_vertical_arrow_navigation_ = x;
} else {
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier.h b/chromium/third_party/blink/renderer/core/editing/selection_modifier.h
index 0beea6227d1..d83545cb51a 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier.h
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier.h
@@ -77,50 +77,55 @@ class CORE_EXPORT SelectionModifier {
const LocalFrame& GetFrame() const { return *frame_; }
static bool ShouldAlwaysUseDirectionalSelection(const LocalFrame&);
- VisibleSelection PrepareToModifySelection(SelectionModifyAlteration,
- SelectionModifyDirection) const;
+ VisibleSelectionInFlatTree PrepareToModifySelection(
+ SelectionModifyAlteration,
+ SelectionModifyDirection) const;
TextDirection DirectionOfEnclosingBlock() const;
TextDirection LineDirectionOfExtent() const;
- VisiblePosition PositionForPlatform(bool is_get_start) const;
- VisiblePosition StartForPlatform() const;
- VisiblePosition EndForPlatform() const;
- LayoutUnit LineDirectionPointForBlockDirectionNavigation(const Position&);
- VisiblePosition ComputeModifyPosition(SelectionModifyAlteration,
- SelectionModifyDirection,
- TextGranularity);
- VisiblePosition ModifyExtendingRight(TextGranularity);
- VisiblePosition ModifyExtendingRightInternal(TextGranularity);
- VisiblePosition ModifyExtendingForward(TextGranularity);
- VisiblePosition ModifyExtendingForwardInternal(TextGranularity);
- VisiblePosition ModifyMovingRight(TextGranularity);
- VisiblePosition ModifyMovingForward(TextGranularity);
- VisiblePosition ModifyExtendingLeft(TextGranularity);
- VisiblePosition ModifyExtendingLeftInternal(TextGranularity);
- VisiblePosition ModifyExtendingBackward(TextGranularity);
- VisiblePosition ModifyExtendingBackwardInternal(TextGranularity);
- VisiblePosition ModifyMovingLeft(TextGranularity);
- VisiblePosition ModifyMovingBackward(TextGranularity);
- Position NextWordPositionForPlatform(const Position&);
-
- static VisiblePosition PreviousLinePosition(const VisiblePosition&,
- LayoutUnit line_direction_point);
- static VisiblePosition NextLinePosition(const VisiblePosition&,
- LayoutUnit line_direction_point);
- static VisiblePosition PreviousParagraphPosition(
- const VisiblePosition&,
+ VisiblePositionInFlatTree PositionForPlatform(bool is_get_start) const;
+ VisiblePositionInFlatTree StartForPlatform() const;
+ VisiblePositionInFlatTree EndForPlatform() const;
+ LayoutUnit LineDirectionPointForBlockDirectionNavigation(
+ const PositionInFlatTree&);
+ VisiblePositionInFlatTree ComputeModifyPosition(SelectionModifyAlteration,
+ SelectionModifyDirection,
+ TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingRight(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingRightInternal(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingForward(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingForwardInternal(TextGranularity);
+ VisiblePositionInFlatTree ModifyMovingRight(TextGranularity);
+ VisiblePositionInFlatTree ModifyMovingForward(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingLeft(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingLeftInternal(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingBackward(TextGranularity);
+ VisiblePositionInFlatTree ModifyExtendingBackwardInternal(TextGranularity);
+ VisiblePositionInFlatTree ModifyMovingLeft(TextGranularity);
+ VisiblePositionInFlatTree ModifyMovingBackward(TextGranularity);
+ PositionInFlatTree NextWordPositionForPlatform(const PositionInFlatTree&);
+
+ static PositionInFlatTreeWithAffinity PreviousLinePosition(
+ const PositionInFlatTreeWithAffinity&,
+ LayoutUnit line_direction_point);
+ static PositionInFlatTreeWithAffinity NextLinePosition(
+ const PositionInFlatTreeWithAffinity&,
+ LayoutUnit line_direction_point);
+ static VisiblePositionInFlatTree PreviousParagraphPosition(
+ const VisiblePositionInFlatTree&,
+ LayoutUnit line_direction_point);
+ static VisiblePositionInFlatTree NextParagraphPosition(
+ const VisiblePositionInFlatTree&,
LayoutUnit line_direction_point);
- static VisiblePosition NextParagraphPosition(const VisiblePosition&,
- LayoutUnit line_direction_point);
const LocalFrame* frame_;
// TODO(editing-dev): We should get rid of |selection_| once we change
// all member functions not to use |selection_|.
// |selection_| is used as implicit parameter or a cache instead of pass it.
- VisibleSelection selection_;
+ VisibleSelectionInFlatTree selection_;
// TODO(editing-dev): We should introduce |GetSelection()| to return
// |result_| to replace |Selection().AsSelection()|.
// |current_selection_| holds initial value and result of |Modify()|.
- SelectionInDOMTree current_selection_;
+ SelectionInFlatTree current_selection_;
LayoutUnit x_pos_for_vertical_arrow_navigation_;
bool selection_is_directional_ = false;
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier_line.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier_line.cc
index f65413db75f..bc9cd358664 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier_line.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier_line.cc
@@ -51,7 +51,7 @@ class AbstractLineBox {
public:
AbstractLineBox() = default;
- static AbstractLineBox CreateFor(const VisiblePosition&);
+ static AbstractLineBox CreateFor(const PositionInFlatTreeWithAffinity&);
bool IsNull() const { return type_ == Type::kNull; }
@@ -121,7 +121,7 @@ class AbstractLineBox {
line_direction_point - absolute_block_point.top);
}
- PositionWithAffinity PositionForPoint(
+ PositionInFlatTreeWithAffinity PositionForPoint(
const PhysicalOffset& point_in_container,
bool only_editable_leaves) const {
if (IsOldLayout()) {
@@ -130,11 +130,14 @@ class AbstractLineBox {
GetBlock().FlipForWritingMode(point_in_container),
only_editable_leaves);
if (!closest_leaf_child)
- return PositionWithAffinity();
+ return PositionInFlatTreeWithAffinity();
const Node* node = closest_leaf_child->GetNode();
- if (node && EditingIgnoresContent(*node))
- return PositionWithAffinity(Position::InParentBeforeNode(*node));
- return closest_leaf_child->PositionForPoint(point_in_container);
+ if (node && EditingIgnoresContent(*node)) {
+ return PositionInFlatTreeWithAffinity(
+ PositionInFlatTree::InParentBeforeNode(*node));
+ }
+ return ToPositionInFlatTreeWithAffinity(
+ closest_leaf_child->PositionForPoint(point_in_container));
}
return PositionForPoint(cursor_, point_in_container, only_editable_leaves);
}
@@ -164,7 +167,7 @@ class AbstractLineBox {
GetRootInlineBox().BlockDirectionPointInLine());
}
const PhysicalOffset physical_offset =
- cursor_.Current().OffsetInContainerBlock();
+ cursor_.Current().OffsetInContainerFragment();
return cursor_.Current().Style().IsHorizontalWritingMode()
? physical_offset.top
: physical_offset.left;
@@ -186,9 +189,10 @@ class AbstractLineBox {
HasEditableStyle(*layout_object->GetNode());
}
- static PositionWithAffinity PositionForPoint(const NGInlineCursor& line,
- const PhysicalOffset& point,
- bool only_editable_leaves) {
+ static PositionInFlatTreeWithAffinity PositionForPoint(
+ const NGInlineCursor& line,
+ const PhysicalOffset& point,
+ bool only_editable_leaves) {
DCHECK(line.Current().IsLineBox());
const PhysicalSize unit_square(LayoutUnit(1), LayoutUnit(1));
const LogicalOffset logical_point =
@@ -213,7 +217,7 @@ class AbstractLineBox {
const LogicalRect fragment_logical_rect =
line.Current().ConvertChildToLogical(
- cursor.Current().RectInContainerBlock());
+ cursor.Current().RectInContainerFragment());
const LayoutUnit inline_min = fragment_logical_rect.offset.inline_offset;
const LayoutUnit inline_max = fragment_logical_rect.offset.inline_offset +
fragment_logical_rect.size.inline_size;
@@ -232,13 +236,16 @@ class AbstractLineBox {
}
}
if (!closest_leaf_child)
- return PositionWithAffinity();
+ return PositionInFlatTreeWithAffinity();
const Node* const node = closest_leaf_child.Current().GetNode();
if (!node)
- return PositionWithAffinity();
- if (EditingIgnoresContent(*node))
- return PositionWithAffinity(Position::BeforeNode(*node));
- return closest_leaf_child.PositionForPointInChild(point);
+ return PositionInFlatTreeWithAffinity();
+ if (EditingIgnoresContent(*node)) {
+ return PositionInFlatTreeWithAffinity(
+ PositionInFlatTree::BeforeNode(*node));
+ }
+ return ToPositionInFlatTreeWithAffinity(
+ closest_leaf_child.PositionForPointInChild(point));
}
enum class Type { kNull, kOldLayout, kLayoutNG };
@@ -249,13 +256,15 @@ class AbstractLineBox {
};
// static
-AbstractLineBox AbstractLineBox::CreateFor(const VisiblePosition& position) {
+AbstractLineBox AbstractLineBox::CreateFor(
+ const PositionInFlatTreeWithAffinity& position) {
if (position.IsNull() ||
- !position.DeepEquivalent().AnchorNode()->GetLayoutObject()) {
+ !position.GetPosition().AnchorNode()->GetLayoutObject()) {
return AbstractLineBox();
}
- const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+ const PositionWithAffinity adjusted =
+ ToPositionInDOMTreeWithAffinity(ComputeInlineAdjustedPosition(position));
if (adjusted.IsNull())
return AbstractLineBox();
@@ -275,25 +284,27 @@ ContainerNode* HighestEditableRootOfNode(const Node& node) {
}
Node* PreviousNodeConsideringAtomicNodes(const Node& start) {
- if (start.previousSibling()) {
- Node* node = start.previousSibling();
- while (!IsAtomicNode(node) && node->lastChild())
- node = node->lastChild();
+ if (Node* previous_sibling = FlatTreeTraversal::PreviousSibling(start)) {
+ Node* node = previous_sibling;
+ while (!IsAtomicNodeInFlatTree(node)) {
+ if (Node* last_child = FlatTreeTraversal::LastChild(*node))
+ node = last_child;
+ }
return node;
}
- return start.parentNode();
+ return FlatTreeTraversal::Parent(start);
}
Node* NextNodeConsideringAtomicNodes(const Node& start) {
- if (!IsAtomicNode(&start) && start.hasChildren())
- return start.firstChild();
- if (start.nextSibling())
- return start.nextSibling();
+ if (!IsAtomicNodeInFlatTree(&start) && FlatTreeTraversal::HasChildren(start))
+ return FlatTreeTraversal::FirstChild(start);
+ if (Node* next_sibling = FlatTreeTraversal::NextSibling(start))
+ return next_sibling;
const Node* node = &start;
- while (node && !node->nextSibling())
- node = node->parentNode();
+ while (node && !FlatTreeTraversal::NextSibling(*node))
+ node = FlatTreeTraversal::Parent(*node);
if (node)
- return node->nextSibling();
+ return FlatTreeTraversal::NextSibling(*node);
return nullptr;
}
@@ -302,7 +313,7 @@ Node* NextNodeConsideringAtomicNodes(const Node& start) {
Node* PreviousAtomicLeafNode(const Node& start) {
Node* node = PreviousNodeConsideringAtomicNodes(start);
while (node) {
- if (IsAtomicNode(node))
+ if (IsAtomicNodeInFlatTree(node))
return node;
node = PreviousNodeConsideringAtomicNodes(*node);
}
@@ -314,7 +325,7 @@ Node* PreviousAtomicLeafNode(const Node& start) {
Node* NextAtomicLeafNode(const Node& start) {
Node* node = NextNodeConsideringAtomicNodes(start);
while (node) {
- if (IsAtomicNode(node))
+ if (IsAtomicNodeInFlatTree(node))
return node;
node = NextNodeConsideringAtomicNodes(*node);
}
@@ -343,58 +354,57 @@ Node* NextLeafWithGivenEditability(Node* node, bool editable) {
return nullptr;
}
-bool InSameLine(const Node& node, const VisiblePosition& visible_position) {
+bool InSameLine(const Node& node,
+ const PositionInFlatTreeWithAffinity& position) {
if (!node.GetLayoutObject())
return true;
- return InSameLine(CreateVisiblePosition(FirstPositionInOrBeforeNode(node)),
- visible_position);
+ return InSameLine(CreateVisiblePosition(
+ PositionInFlatTree::FirstPositionInOrBeforeNode(node))
+ .ToPositionWithAffinity(),
+ position);
}
Node* FindNodeInPreviousLine(const Node& start_node,
- const VisiblePosition& visible_position) {
+ const PositionInFlatTreeWithAffinity& position) {
for (Node* runner = PreviousLeafWithSameEditability(start_node); runner;
runner = PreviousLeafWithSameEditability(*runner)) {
- if (!InSameLine(*runner, visible_position))
+ if (!InSameLine(*runner, position))
return runner;
}
return nullptr;
}
// FIXME: consolidate with code in previousLinePosition.
-Position PreviousRootInlineBoxCandidatePosition(
+PositionInFlatTree PreviousRootInlineBoxCandidatePosition(
Node* node,
- const VisiblePosition& visible_position) {
- DCHECK(visible_position.IsValid()) << visible_position;
- ContainerNode* highest_root =
- HighestEditableRoot(visible_position.DeepEquivalent());
- Node* const previous_node = FindNodeInPreviousLine(*node, visible_position);
+ const PositionInFlatTreeWithAffinity& position) {
+ ContainerNode* highest_root = HighestEditableRoot(position.GetPosition());
+ Node* const previous_node = FindNodeInPreviousLine(*node, position);
for (Node* runner = previous_node; runner && !runner->IsShadowRoot();
runner = PreviousLeafWithSameEditability(*runner)) {
if (HighestEditableRootOfNode(*runner) != highest_root)
break;
- const Position& candidate =
- IsA<HTMLBRElement>(*runner)
- ? Position::BeforeNode(*runner)
- : Position::EditingPositionOf(runner, CaretMaxOffset(runner));
+ const PositionInFlatTree& candidate =
+ IsA<HTMLBRElement>(*runner) ? PositionInFlatTree::BeforeNode(*runner)
+ : PositionInFlatTree::EditingPositionOf(
+ runner, CaretMaxOffset(runner));
if (IsVisuallyEquivalentCandidate(candidate))
return candidate;
}
- return Position();
+ return PositionInFlatTree();
}
-Position NextRootInlineBoxCandidatePosition(
+PositionInFlatTree NextRootInlineBoxCandidatePosition(
Node* node,
- const VisiblePosition& visible_position) {
- DCHECK(visible_position.IsValid()) << visible_position;
- ContainerNode* highest_root =
- HighestEditableRoot(visible_position.DeepEquivalent());
+ const PositionInFlatTreeWithAffinity& position) {
+ ContainerNode* highest_root = HighestEditableRoot(position.GetPosition());
// TODO(xiaochengh): We probably also need to pass in the starting editability
// to |PreviousLeafWithSameEditability|.
- const bool is_editable = HasEditableStyle(
- *visible_position.DeepEquivalent().ComputeContainerNode());
+ const bool is_editable =
+ HasEditableStyle(*position.GetPosition().ComputeContainerNode());
Node* next_node = NextLeafWithGivenEditability(node, is_editable);
- while (next_node && InSameLine(*next_node, visible_position)) {
+ while (next_node && InSameLine(*next_node, position)) {
next_node = NextLeafWithGivenEditability(next_node, is_editable);
}
@@ -403,35 +413,33 @@ Position NextRootInlineBoxCandidatePosition(
if (HighestEditableRootOfNode(*runner) != highest_root)
break;
- const Position& candidate =
- Position::EditingPositionOf(runner, CaretMinOffset(runner));
+ const PositionInFlatTree& candidate =
+ PositionInFlatTree::EditingPositionOf(runner, CaretMinOffset(runner));
if (IsVisuallyEquivalentCandidate(candidate))
return candidate;
}
- return Position();
+ return PositionInFlatTree();
}
} // namespace
// static
-VisiblePosition SelectionModifier::PreviousLinePosition(
- const VisiblePosition& visible_position,
+PositionInFlatTreeWithAffinity SelectionModifier::PreviousLinePosition(
+ const PositionInFlatTreeWithAffinity& position,
LayoutUnit line_direction_point) {
- DCHECK(visible_position.IsValid()) << visible_position;
-
// TODO(xiaochengh): Make all variables |const|.
- Position p = visible_position.DeepEquivalent();
+ PositionInFlatTree p = position.GetPosition();
Node* node = p.AnchorNode();
if (!node)
- return VisiblePosition();
+ return PositionInFlatTreeWithAffinity();
LayoutObject* layout_object = node->GetLayoutObject();
if (!layout_object)
- return VisiblePosition();
+ return PositionInFlatTreeWithAffinity();
- AbstractLineBox line = AbstractLineBox::CreateFor(visible_position);
+ AbstractLineBox line = AbstractLineBox::CreateFor(position);
if (!line.IsNull()) {
line = line.PreviousLine();
if (line.IsNull() || !line.CanBeCaretContainer())
@@ -439,15 +447,15 @@ VisiblePosition SelectionModifier::PreviousLinePosition(
}
if (line.IsNull()) {
- Position position =
- PreviousRootInlineBoxCandidatePosition(node, visible_position);
- if (position.IsNotNull()) {
- const VisiblePosition candidate = CreateVisiblePosition(position);
- line = AbstractLineBox::CreateFor(candidate);
+ PositionInFlatTree candidate =
+ PreviousRootInlineBoxCandidatePosition(node, position);
+ if (candidate.IsNotNull()) {
+ line = AbstractLineBox::CreateFor(
+ CreateVisiblePosition(candidate).ToPositionWithAffinity());
if (line.IsNull()) {
// TODO(editing-dev): Investigate if this is correct for null
- // |candidate|.
- return candidate;
+ // |CreateVisiblePosition(candidate)|.
+ return PositionInFlatTreeWithAffinity(candidate);
}
}
}
@@ -457,9 +465,18 @@ VisiblePosition SelectionModifier::PreviousLinePosition(
PhysicalOffset point_in_line =
line.AbsoluteLineDirectionPointToLocalPointInBlock(
line_direction_point);
- if (auto position =
- line.PositionForPoint(point_in_line, IsEditablePosition(p)))
- return CreateVisiblePosition(position);
+ if (auto candidate =
+ line.PositionForPoint(point_in_line, IsEditablePosition(p))) {
+ // If the current position is inside an editable position, then the next
+ // shouldn't end up inside non-editable as that would cross the editing
+ // boundaries which would be an invalid selection.
+ if (IsEditablePosition(p) &&
+ !IsEditablePosition(candidate.GetPosition())) {
+ return AdjustBackwardPositionToAvoidCrossingEditingBoundaries(candidate,
+ p);
+ }
+ return candidate;
+ }
}
// Could not find a previous line. This means we must already be on the first
@@ -469,29 +486,28 @@ VisiblePosition SelectionModifier::PreviousLinePosition(
? RootEditableElement(*node)
: node->GetDocument().documentElement();
if (!root_element)
- return VisiblePosition();
- return VisiblePosition::FirstPositionInNode(*root_element);
+ return PositionInFlatTreeWithAffinity();
+ return PositionInFlatTreeWithAffinity(
+ PositionInFlatTree::FirstPositionInNode(*root_element));
}
// static
-VisiblePosition SelectionModifier::NextLinePosition(
- const VisiblePosition& visible_position,
+PositionInFlatTreeWithAffinity SelectionModifier::NextLinePosition(
+ const PositionInFlatTreeWithAffinity& position,
LayoutUnit line_direction_point) {
- DCHECK(visible_position.IsValid()) << visible_position;
-
// TODO(xiaochengh): Make all variables |const|.
- Position p = visible_position.DeepEquivalent();
+ PositionInFlatTree p = position.GetPosition();
Node* node = p.AnchorNode();
if (!node)
- return VisiblePosition();
+ return PositionInFlatTreeWithAffinity();
LayoutObject* layout_object = node->GetLayoutObject();
if (!layout_object)
- return VisiblePosition();
+ return PositionInFlatTreeWithAffinity();
- AbstractLineBox line = AbstractLineBox::CreateFor(visible_position);
+ AbstractLineBox line = AbstractLineBox::CreateFor(position);
if (!line.IsNull()) {
line = line.NextLine();
if (line.IsNull() || !line.CanBeCaretContainer())
@@ -500,18 +516,18 @@ VisiblePosition SelectionModifier::NextLinePosition(
if (line.IsNull()) {
// FIXME: We need do the same in previousLinePosition.
- Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset());
+ Node* child = FlatTreeTraversal::ChildAt(*node, p.ComputeEditingOffset());
Node* search_start_node =
- child ? child : &NodeTraversal::LastWithinOrSelf(*node);
- Position position =
- NextRootInlineBoxCandidatePosition(search_start_node, visible_position);
- if (position.IsNotNull()) {
- const VisiblePosition candidate = CreateVisiblePosition(position);
- line = AbstractLineBox::CreateFor(candidate);
+ child ? child : &FlatTreeTraversal::LastWithinOrSelf(*node);
+ PositionInFlatTree candidate =
+ NextRootInlineBoxCandidatePosition(search_start_node, position);
+ if (candidate.IsNotNull()) {
+ line = AbstractLineBox::CreateFor(
+ CreateVisiblePosition(candidate).ToPositionWithAffinity());
if (line.IsNull()) {
// TODO(editing-dev): Investigate if this is correct for null
- // |candidate|.
- return candidate;
+ // |CreateVisiblePosition(candidate)|.
+ return PositionInFlatTreeWithAffinity(candidate);
}
}
}
@@ -521,9 +537,18 @@ VisiblePosition SelectionModifier::NextLinePosition(
PhysicalOffset point_in_line =
line.AbsoluteLineDirectionPointToLocalPointInBlock(
line_direction_point);
- if (auto position =
- line.PositionForPoint(point_in_line, IsEditablePosition(p)))
- return CreateVisiblePosition(position);
+ if (auto candidate =
+ line.PositionForPoint(point_in_line, IsEditablePosition(p))) {
+ // If the current position is inside an editable position, then the next
+ // shouldn't end up inside non-editable as that would cross the editing
+ // boundaries which would be an invalid selection.
+ if (IsEditablePosition(p) &&
+ !IsEditablePosition(candidate.GetPosition())) {
+ return AdjustForwardPositionToAvoidCrossingEditingBoundaries(candidate,
+ p);
+ }
+ return candidate;
+ }
}
// Could not find a next line. This means we must already be on the last line.
@@ -533,8 +558,9 @@ VisiblePosition SelectionModifier::NextLinePosition(
? RootEditableElement(*node)
: node->GetDocument().documentElement();
if (!root_element)
- return VisiblePosition();
- return VisiblePosition::LastPositionInNode(*root_element);
+ return PositionInFlatTreeWithAffinity();
+ return PositionInFlatTreeWithAffinity(
+ PositionInFlatTree::LastPositionInNode(*root_element));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc b/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
index 166d1419fd0..0e304508d82 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_modifier_test.cc
@@ -4,8 +4,11 @@
#include "third_party/blink/renderer/core/editing/selection_modifier.h"
+#include "third_party/blink/renderer/core/editing/editing_behavior.h"
+#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -128,4 +131,165 @@ TEST_F(SelectionModifierTest, StartOfSentenceWithNull) {
TextGranularity::kSentenceBoundary));
}
+TEST_F(SelectionModifierTest, MoveCaretWithShadow) {
+ const char* body_content =
+ "a a"
+ "<div id='host'>"
+ "<span slot='e'>e e</span>"
+ "<span slot='c'>c c</span>"
+ "</div>"
+ "f f";
+ const char* shadow_content =
+ "b b"
+ "<slot name='c'></slot>"
+ "d d"
+ "<slot name='e'></slot>";
+ LoadAhem();
+ InsertStyleElement("body {font-family: Ahem}");
+ SetBodyContent(body_content);
+ Element* host = GetDocument().getElementById("host");
+ ShadowRoot& shadow_root =
+ host->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow_root.setInnerHTML(shadow_content);
+ UpdateAllLifecyclePhasesForTest();
+
+ Element* body = GetDocument().body();
+ Node* a = body->childNodes()->item(0);
+ Node* b = shadow_root.childNodes()->item(0);
+ Node* c = host->QuerySelector("[slot=c]")->firstChild();
+ Node* d = shadow_root.childNodes()->item(2);
+ Node* e = host->QuerySelector("[slot=e]")->firstChild();
+ Node* f = body->childNodes()->item(2);
+
+ auto makeSelection = [&](Position position) {
+ return SelectionInDOMTree::Builder().Collapse(position).Build();
+ };
+ SelectionModifyAlteration move = SelectionModifyAlteration::kMove;
+ SelectionModifyDirection direction;
+ TextGranularity granularity;
+
+ {
+ // Test moving forward, character by character.
+ direction = SelectionModifyDirection::kForward;
+ granularity = TextGranularity::kCharacter;
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 0)));
+ EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+ for (Node* node : {a, b, c, d, e, f}) {
+ if (node == b || node == f) {
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+ }
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 1), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+ }
+ }
+ {
+ // Test moving backward, character by character.
+ direction = SelectionModifyDirection::kBackward;
+ granularity = TextGranularity::kCharacter;
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 3)));
+ for (Node* node : {f, e, d, c, b, a}) {
+ EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 1), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ if (node == f || node == b) {
+ EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ }
+ }
+ EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+ }
+ {
+ // Test moving forward, word by word.
+ direction = SelectionModifyDirection::kForward;
+ granularity = TextGranularity::kWord;
+ bool skip_space =
+ GetFrame().GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight();
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 0)));
+ EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+ for (Node* node : {a, b, c, d, e, f}) {
+ if (node == b || node == f) {
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+ }
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, skip_space ? 2 : 1),
+ modifier.Selection().Base());
+ if (node == a || node == e || node == f) {
+ modifier.Modify(move, direction, granularity);
+ EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+ }
+ }
+ }
+ {
+ // Test moving backward, word by word.
+ direction = SelectionModifyDirection::kBackward;
+ granularity = TextGranularity::kWord;
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 3)));
+ for (Node* node : {f, e, d, c, b, a}) {
+ if (node == f || node == e || node == a) {
+ EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ }
+ EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ if (node == f || node == b) {
+ EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ }
+ }
+ EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+ }
+
+ // Place the contents into different lines
+ InsertStyleElement("span {display: block}");
+ UpdateAllLifecyclePhasesForTest();
+
+ {
+ // Test moving forward, line by line.
+ direction = SelectionModifyDirection::kForward;
+ granularity = TextGranularity::kLine;
+ for (int i = 0; i <= 3; ++i) {
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(a, i)));
+ for (Node* node : {a, b, c, d, e, f}) {
+ EXPECT_EQ(Position(node, i), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ }
+ EXPECT_EQ(Position(f, 3), modifier.Selection().Base());
+ }
+ }
+ {
+ // Test moving backward, line by line.
+ direction = SelectionModifyDirection::kBackward;
+ granularity = TextGranularity::kLine;
+ for (int i = 0; i <= 3; ++i) {
+ SelectionModifier modifier(GetFrame(), makeSelection(Position(f, i)));
+ for (Node* node : {f, e, d, c, b, a}) {
+ EXPECT_EQ(Position(node, i), modifier.Selection().Base());
+ modifier.Modify(move, direction, granularity);
+ }
+ EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+ }
+ }
+}
+
+// For https://crbug.com/1155342 and https://crbug.com/1155309
+TEST_F(SelectionModifierTest, PreviousParagraphOfObject) {
+ const SelectionInDOMTree selection =
+ SetSelectionTextToBody("<object>|</object>");
+ SelectionModifier modifier(GetFrame(), selection);
+ modifier.Modify(SelectionModifyAlteration::kMove,
+ SelectionModifyDirection::kBackward,
+ TextGranularity::kParagraph);
+ EXPECT_EQ("|<object></object>",
+ GetSelectionTextFromBody(modifier.Selection().AsSelection()));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_template.cc b/chromium/third_party/blink/renderer/core/editing/selection_template.cc
index b671302c771..fb1131d1ed7 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_template.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_template.cc
@@ -186,15 +186,6 @@ void SelectionTemplate<Strategy>::ResetDirectionCache() const {
}
template <typename Strategy>
-SelectionType SelectionTemplate<Strategy>::Type() const {
- if (base_.IsNull())
- return kNoSelection;
- if (base_ == extent_)
- return kCaretSelection;
- return kRangeSelection;
-}
-
-template <typename Strategy>
void SelectionTemplate<Strategy>::PrintTo(std::ostream* ostream,
const char* type) const {
if (IsNone()) {
@@ -282,6 +273,8 @@ SelectionTemplate<Strategy>::Builder::Extend(
DCHECK_EQ(selection_.GetDocument(), position.GetDocument());
DCHECK(selection_.Base().IsConnected()) << selection_.Base();
DCHECK(selection_.AssertValid());
+ if (selection_.extent_.IsEquivalent(position))
+ return *this;
selection_.extent_ = position;
selection_.direction_ = Direction::kNotComputed;
return *this;
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_template.h b/chromium/third_party/blink/renderer/core/editing/selection_template.h
index 8730562adb1..742da5d427a 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_template.h
+++ b/chromium/third_party/blink/renderer/core/editing/selection_template.h
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/editing/position.h"
-#include "third_party/blink/renderer/core/editing/selection_type.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -118,9 +117,6 @@ class SelectionTemplate final {
PositionTemplate<Strategy> ComputeStartPosition() const;
EphemeralRangeTemplate<Strategy> ComputeRange() const;
- // Returns |SelectionType| for |this| based on |base_| and |extent_|.
- SelectionType Type() const;
-
void Trace(Visitor*) const;
void PrintTo(std::ostream*, const char* type) const;
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_template_test.cc b/chromium/third_party/blink/renderer/core/editing/selection_template_test.cc
index de00bfeb078..154ca4c2e3b 100644
--- a/chromium/third_party/blink/renderer/core/editing/selection_template_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/selection_template_test.cc
@@ -119,4 +119,35 @@ TEST_F(SelectionTest, SetAsBacwardAndForward) {
EXPECT_EQ(EphemeralRange(start, start), collapsed_selection.ComputeRange());
}
+TEST_F(SelectionTest, EquivalentPositions) {
+ SetBodyContent(
+ "<div id='first'></div>"
+ "<div id='last'></div>");
+ Element* first = GetDocument().getElementById("first");
+ Element* last = GetDocument().getElementById("last");
+ Position after_first = Position::AfterNode(*first);
+ Position before_last = Position::BeforeNode(*last);
+
+ // Test selections created with different but equivalent positions.
+ EXPECT_NE(after_first, before_last);
+ EXPECT_TRUE(after_first.IsEquivalent(before_last));
+
+ for (bool reversed : {false, true}) {
+ const Position& start = reversed ? before_last : after_first;
+ const Position& end = reversed ? after_first : before_last;
+ EphemeralRange range(start, end);
+
+ const SelectionInDOMTree& selection =
+ SelectionInDOMTree::Builder().Collapse(start).Extend(end).Build();
+ EXPECT_EQ(
+ selection,
+ SelectionInDOMTree::Builder().SetAsForwardSelection(range).Build());
+
+ EXPECT_TRUE(selection.IsCaret());
+ EXPECT_EQ(range, selection.ComputeRange());
+ EXPECT_EQ(start, selection.Base());
+ EXPECT_EQ(start, selection.Extent());
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/selection_type.h b/chromium/third_party/blink/renderer/core/editing/selection_type.h
deleted file mode 100644
index c2d2f2ace05..00000000000
--- a/chromium/third_party/blink/renderer/core/editing/selection_type.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_SELECTION_TYPE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_SELECTION_TYPE_H_
-
-namespace blink {
-
-enum SelectionType { kNoSelection, kCaretSelection, kRangeSelection };
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_SELECTION_TYPE_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc b/chromium/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
index 3b6c034c990..9eb48719842 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
@@ -550,7 +550,6 @@ std::pair<Node*, Element*> MarkupAccumulator::GetAuxiliaryDOMTree(
element.GetExecutionContext()));
AtomicString shadowroot_type;
switch (shadow_root->GetType()) {
- case ShadowRootType::V0:
case ShadowRootType::kUserAgent:
// Don't serialize user agent shadow roots, only explicit shadow roots.
return std::pair<Node*, Element*>();
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc b/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
index 110c76bcd17..186bbc7e27e 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
@@ -385,18 +385,28 @@ EntityMask MarkupFormatter::EntityMaskForText(const Text& text) const {
if (text.parentElement())
parent_name = &(text.parentElement())->TagQName();
- if (parent_name && (*parent_name == html_names::kScriptTag ||
- *parent_name == html_names::kStyleTag ||
- *parent_name == html_names::kXmpTag ||
- *parent_name == html_names::kIFrameTag ||
- *parent_name == html_names::kPlaintextTag ||
- *parent_name == html_names::kNoembedTag ||
- *parent_name == html_names::kNoframesTag ||
- (*parent_name == html_names::kNoscriptTag &&
- text.GetExecutionContext() &&
- text.GetExecutionContext()->CanExecuteScripts(
- kNotAboutToExecuteScript))))
- return kEntityMaskInCDATA;
+ if (parent_name) {
+ // For a NOSCRIPT tag, escape the string unless there's an execution context
+ // and scripting is enabled. Note that some documents (e.g. the one created
+ // by DOMParser) are created with a script-enabled execution context, but no
+ // DOMWindow. But per spec [1], they should behave as if they have no
+ // execution context. So check for a DOMWindow here.
+ // [1] https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html
+ bool is_noscript_tag_with_script_enabled =
+ *parent_name == html_names::kNoscriptTag &&
+ text.GetExecutionContext() && text.GetDocument().domWindow() &&
+ text.GetExecutionContext()->CanExecuteScripts(kNotAboutToExecuteScript);
+ if (*parent_name == html_names::kScriptTag ||
+ *parent_name == html_names::kStyleTag ||
+ *parent_name == html_names::kXmpTag ||
+ *parent_name == html_names::kIFrameTag ||
+ *parent_name == html_names::kPlaintextTag ||
+ *parent_name == html_names::kNoembedTag ||
+ *parent_name == html_names::kNoframesTag ||
+ is_noscript_tag_with_script_enabled) {
+ return kEntityMaskInCDATA;
+ }
+ }
return kEntityMaskInHTMLPCDATA;
}
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/serialization.cc b/chromium/third_party/blink/renderer/core/editing/serializers/serialization.cc
index af1d518ceca..654589ec635 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/serialization.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/serialization.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_value.h"
@@ -197,12 +198,7 @@ static HTMLElement* HighestAncestorToWrapMarkup(
FirstPositionInOrBeforeNode(*first_node);
if (Node* parent_list_node =
EnclosingNodeOfType(first_node_position, IsListItem)) {
- EphemeralRangeTemplate<Strategy> markup_range =
- EphemeralRangeTemplate<Strategy>(start_position, end_position);
- EphemeralRangeTemplate<Strategy> node_range =
- NormalizeRange(EphemeralRangeTemplate<Strategy>::RangeOfContents(
- *parent_list_node));
- if (node_range == markup_range) {
+ if (AreSameRanges(parent_list_node, start_position, end_position)) {
ContainerNode* ancestor = parent_list_node->parentNode();
while (ancestor && !IsHTMLListElement(ancestor))
ancestor = ancestor->parentNode();
@@ -609,7 +605,7 @@ DocumentFragment* CreateFragmentForInnerOuterHTML(
Element* context_element,
ParserContentPolicy parser_content_policy,
const char* method,
- bool allow_shadow_root,
+ bool include_shadow_roots,
ExceptionState& exception_state) {
DCHECK(context_element);
const HTMLTemplateElement* template_element =
@@ -623,7 +619,7 @@ DocumentFragment* CreateFragmentForInnerOuterHTML(
? context_element->GetDocument().EnsureTemplateDocument()
: context_element->GetDocument();
DocumentFragment* fragment = DocumentFragment::Create(document);
- document.setAllowDeclarativeShadowRoot(allow_shadow_root);
+ document.setAllowDeclarativeShadowRoots(include_shadow_roots);
if (IsA<HTMLDocument>(document)) {
fragment->ParseHTML(markup, context_element, parser_content_policy);
@@ -691,7 +687,7 @@ DocumentFragment* CreateContextualFragment(
DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
markup, element, parser_content_policy, "createContextualFragment",
- /*allow_shadow_root=*/false, exception_state);
+ /*include_shadow_roots=*/false, exception_state);
if (!fragment)
return nullptr;
@@ -776,10 +772,11 @@ void MergeWithNextTextNode(Text* text_node, ExceptionState& exception_state) {
text_next->remove(exception_state);
}
-static Document* CreateStagingDocumentForMarkupSanitization() {
+static Document* CreateStagingDocumentForMarkupSanitization(
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler) {
Page::PageClients page_clients;
FillWithEmptyClients(page_clients);
- Page* page = Page::CreateNonOrdinary(page_clients);
+ Page* page = Page::CreateNonOrdinary(page_clients, agent_group_scheduler);
page->GetSettings().SetScriptEnabled(false);
page->GetSettings().SetPluginsEnabled(false);
@@ -792,7 +789,7 @@ static Document* CreateStagingDocumentForMarkupSanitization() {
nullptr, // FrameOwner*
nullptr, // Frame* parent
nullptr, // Frame* previous_sibling
- FrameInsertType::kInsertInConstructor, base::UnguessableToken::Create(),
+ FrameInsertType::kInsertInConstructor, blink::LocalFrameToken(),
nullptr, // WindowAgentFactory*
nullptr, // InterfaceRegistry*
nullptr // policy_container
@@ -849,7 +846,8 @@ DocumentFragment* CreateSanitizedFragmentFromMarkupWithContext(
if (raw_markup.IsEmpty())
return nullptr;
- Document* staging_document = CreateStagingDocumentForMarkupSanitization();
+ Document* staging_document = CreateStagingDocumentForMarkupSanitization(
+ *document.GetFrame()->GetFrameScheduler()->GetAgentGroupScheduler());
Element* body = staging_document->body();
DocumentFragment* fragment = CreateFragmentFromMarkupWithContext(
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/serialization.h b/chromium/third_party/blink/renderer/core/editing/serializers/serialization.h
index a73b30f1965..41e05f71567 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/serialization.h
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/serialization.h
@@ -66,7 +66,7 @@ DocumentFragment* CreateFragmentForInnerOuterHTML(const String&,
Element*,
ParserContentPolicy,
const char* method,
- bool allow_shadow_root,
+ bool include_shadow_roots,
ExceptionState&);
DocumentFragment* CreateFragmentForTransformToFragment(
const String&,
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/serialization_test.cc b/chromium/third_party/blink/renderer/core/editing/serializers/serialization_test.cc
index fb59874462f..cd32aa10b6d 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/serialization_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/serialization_test.cc
@@ -4,11 +4,31 @@
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
-class SerializationTest : public EditingTestBase {};
+// See third_party/googletest/src/googletest/docs/advanced.md for supported
+// regexp operators.
+using ::testing::MatchesRegex;
+
+class SerializationTest : public EditingTestBase {
+ protected:
+ std::string SerailizeToHTMLText(const Node& node) {
+ // We use same |CreateMarkupOptions| used in
+ // |FrameSelection::SelectedHTMLForClipboard()|
+ return CreateMarkup(Position::BeforeNode(node), Position::AfterNode(node),
+ CreateMarkupOptions::Builder()
+ .SetShouldAnnotateForInterchange(true)
+ .SetShouldResolveURLs(kResolveNonLocalURLs)
+ .Build())
+ .Utf8();
+ }
+};
// Regression test for https://crbug.com/1032673
TEST_F(SerializationTest, CantCreateFragmentCrash) {
@@ -29,6 +49,58 @@ TEST_F(SerializationTest, CantCreateFragmentCrash) {
EXPECT_FALSE(sanitized);
}
+// http://crbug.com/938590
+TEST_F(SerializationTest, Link) {
+ InsertStyleElement(
+ "a { color: #010101; }"
+ "a:link { color: #020202; }"
+ "a:visited { color: #030303; }");
+ SetBodyContent(
+ "<a id=a1>text</a>"
+ "<a id=a2 href=''>visited</a>"
+ "<a id=a3 href='https://1.1.1.1/'>unvisited</a>");
+
+ const auto& a1 = *GetElementById("a1");
+ const auto& style1 = a1.ComputedStyleRef();
+ const auto& a2 = *GetElementById("a2");
+ const auto& style2 = a2.ComputedStyleRef();
+ const auto& a3 = *GetElementById("a3");
+ const auto& style3 = a3.ComputedStyleRef();
+
+ // a1
+ ASSERT_THAT(style1.InsideLink(), EInsideLink::kNotInsideLink);
+ ASSERT_THAT(style1.VisitedDependentColor(GetCSSPropertyColor()),
+ MakeRGB(1, 1, 1))
+ << "should not be :visited/:link color";
+ EXPECT_THAT(
+ SerailizeToHTMLText(a1),
+ MatchesRegex(
+ R"re(<a id="a1" style=".*;? ?color: rgb\(1, 1, 1\);.*">text</a>)re"));
+
+ // a2
+ // Note: Because href="" means current document URI, it is visited.
+ // We should have :link color instead of :visited color not to expose
+ // visited/unvisited state of link for privacy reason.
+ ASSERT_THAT(style2.InsideLink(), EInsideLink::kInsideVisitedLink);
+ ASSERT_THAT(style2.VisitedDependentColor(GetCSSPropertyColor()),
+ MakeRGB(3, 3, 3))
+ << "should be :visited color";
+ EXPECT_THAT(
+ SerailizeToHTMLText(a2),
+ MatchesRegex(
+ R"re(<a id="a2" href="" style=".*;? ?color: rgb\(2, 2, 2\);.*">visited</a>)re"));
+
+ // a3
+ ASSERT_THAT(style3.InsideLink(), EInsideLink::kInsideUnvisitedLink);
+ ASSERT_THAT(style3.VisitedDependentColor(GetCSSPropertyColor()),
+ MakeRGB(2, 2, 2))
+ << "should be :link color";
+ EXPECT_THAT(
+ SerailizeToHTMLText(a3),
+ MatchesRegex(
+ R"re(<a id="a3" href="https://1.1.1.1/" style=".*;? ?color: rgb\(2, 2, 2\);.*">unvisited</a>)re"));
+}
+
// Regression test for https://crbug.com/1032389
TEST_F(SerializationTest, SVGForeignObjectCrash) {
const String markup =
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
index d9e9edf2bbb..cebb9e190eb 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
@@ -159,19 +159,6 @@ static bool NeedInterchangeNewlineAt(
return NeedInterchangeNewlineAfter(PreviousPositionOf(v));
}
-template <typename Strategy>
-static bool AreSameRanges(Node* node,
- const PositionTemplate<Strategy>& start_position,
- const PositionTemplate<Strategy>& end_position) {
- DCHECK(node);
- const EphemeralRange range =
- CreateVisibleSelection(
- SelectionInDOMTree::Builder().SelectAllChildren(*node).Build())
- .ToNormalizedEphemeralRange();
- return ToPositionInDOMTree(start_position) == range.StartPosition() &&
- ToPositionInDOMTree(end_position) == range.EndPosition();
-}
-
static EditingStyle* StyleFromMatchedRulesAndInlineDecl(
const HTMLElement* element) {
EditingStyle* style =
diff --git a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
index 62bb40ef2e6..102e7d25025 100644
--- a/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
@@ -44,10 +44,10 @@ class StyledMarkupSerializerTest : public EditingTestBase {
template <typename Strategy>
std::string StyledMarkupSerializerTest::Serialize(
const CreateMarkupOptions& options) {
- PositionTemplate<Strategy> start = PositionTemplate<Strategy>(
- GetDocument().body(), PositionAnchorType::kBeforeChildren);
- PositionTemplate<Strategy> end = PositionTemplate<Strategy>(
- GetDocument().body(), PositionAnchorType::kAfterChildren);
+ PositionTemplate<Strategy> start =
+ PositionTemplate<Strategy>::FirstPositionInNode(*GetDocument().body());
+ PositionTemplate<Strategy> end =
+ PositionTemplate<Strategy>::LastPositionInNode(*GetDocument().body());
return CreateMarkup(start, end, options).Utf8();
}
@@ -133,65 +133,75 @@ TEST_F(StyledMarkupSerializerTest, Mixed) {
TEST_F(StyledMarkupSerializerTest, ShadowTreeDistributeOrder) {
const char* body_content =
- "<p id=\"host\">00<b id=\"one\">11</b><b id=\"two\">22</b>33</p>";
+ "<p id=\"host\">00<b slot='#one' id=\"one\">11</b><b slot='#two' "
+ "id=\"two\">22</b>33</p>";
const char* shadow_content =
- "<a><content select=#two></content><content select=#one></content></a>";
+ "<a><slot name='#two'></slot><slot name='#one'></slot></a>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
- EXPECT_EQ("<p id=\"host\"><b id=\"one\">11</b><b id=\"two\">22</b></p>",
- Serialize<EditingStrategy>())
+ EXPECT_EQ(
+ "<p id=\"host\"><b slot=\"#one\" id=\"one\">11</b><b slot=\"#two\" "
+ "id=\"two\">22</b></p>",
+ Serialize<EditingStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
EXPECT_EQ(
- "<p id=\"host\"><a><b id=\"two\">22</b><b id=\"one\">11</b></a></p>",
+ "<p id=\"host\"><a><slot name=\"#two\"><b slot=\"#two\" "
+ "id=\"two\">22</b></slot><slot name=\"#one\"><b slot=\"#one\" "
+ "id=\"one\">11</b></slot></a></p>",
Serialize<EditingInFlatTreeStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
}
TEST_F(StyledMarkupSerializerTest, ShadowTreeInput) {
const char* body_content =
- "<p id=\"host\">00<b id=\"one\">11</b><b id=\"two\"><input "
- "value=\"22\"></b>33</p>";
+ "<p id=\"host\">00<b slot='#one' id=\"one\">11</b><b slot='#two' "
+ "id=\"two\"><input value=\"22\"></b>33</p>";
const char* shadow_content =
- "<a><content select=#two></content><content select=#one></content></a>";
+ "<a><slot name='#two'></slot><slot name='#one'></slot></a>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
EXPECT_EQ(
- "<p id=\"host\"><b id=\"one\">11</b><b id=\"two\"><input "
- "value=\"22\"></b></p>",
+ "<p id=\"host\"><b slot=\"#one\" id=\"one\">11</b><b slot=\"#two\" "
+ "id=\"two\"><input value=\"22\"></b></p>",
Serialize<EditingStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
EXPECT_EQ(
- "<p id=\"host\"><a><b id=\"two\"><input value=\"22\"></b><b "
- "id=\"one\">11</b></a></p>",
+ "<p id=\"host\"><a><slot name=\"#two\"><b slot=\"#two\" "
+ "id=\"two\"><input value=\"22\"></b></slot><slot name=\"#one\"><b "
+ "slot=\"#one\" id=\"one\">11</b></slot></a></p>",
Serialize<EditingInFlatTreeStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
}
TEST_F(StyledMarkupSerializerTest, ShadowTreeNested) {
const char* body_content =
- "<p id=\"host\">00<b id=\"one\">11</b><b id=\"two\">22</b>33</p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
const char* shadow_content1 =
- "<a><content select=#two></content><b id=host2></b><content "
- "select=#one></content></a>";
+ "<a><slot name='#two'></slot><span id=host2></span><slot "
+ "name='#one'></slot></a>";
const char* shadow_content2 = "NESTED";
SetBodyContent(body_content);
ShadowRoot* shadow_root1 = SetShadowContent(shadow_content1, "host");
CreateShadowRootForElementWithIDAndSetInnerHTML(*shadow_root1, "host2",
shadow_content2);
- EXPECT_EQ("<p id=\"host\"><b id=\"one\">11</b><b id=\"two\">22</b></p>",
- Serialize<EditingStrategy>())
+ EXPECT_EQ(
+ "<p id=\"host\"><b slot=\"#one\" id=\"one\">11</b><b slot=\"#two\" "
+ "id=\"two\">22</b></p>",
+ Serialize<EditingStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
EXPECT_EQ(
- "<p id=\"host\"><a><b id=\"two\">22</b><b id=\"host2\">NESTED</b><b "
- "id=\"one\">11</b></a></p>",
+ "<p id=\"host\"><a><slot name=\"#two\"><b slot=\"#two\" "
+ "id=\"two\">22</b></slot><span id=\"host2\">NESTED</span><slot "
+ "name=\"#one\"><b slot=\"#one\" id=\"one\">11</b></slot></a></p>",
Serialize<EditingInFlatTreeStrategy>())
<< "00 and 33 aren't appeared since they aren't distributed.";
}
TEST_F(StyledMarkupSerializerTest, ShadowTreeInterchangedNewline) {
- const char* body_content = "<a id=host><b id=one>1</b></a>";
- const char* shadow_content = "<content select=#one></content><div><br></div>";
+ const char* body_content = "<span id=host><b slot='#one' id=one>1</b></span>";
+ const char* shadow_content = "<slot name='#one'></slot><div><br></div>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -205,9 +215,13 @@ TEST_F(StyledMarkupSerializerTest, ShadowTreeInterchangedNewline) {
// Note: We check difference between DOM tree result and flat tree
// result, because results contain "style" attribute and this test
// doesn't care about actual value of "style" attribute.
- EXPECT_EQ("/a>", result_from_dom_tree.substr(mismatched_index));
- EXPECT_EQ("div><br></div></a><br class=\"Apple-interchange-newline\">",
- result_from_flat_tree.substr(mismatched_index));
+ EXPECT_EQ("b slot=\"#one\" id=\"one\">1</b></span>",
+ result_from_dom_tree.substr(mismatched_index));
+ EXPECT_EQ(
+ "slot name=\"#one\"><b slot=\"#one\" "
+ "id=\"one\">1</b></slot><div><br></div></span><br "
+ "class=\"Apple-interchange-newline\">",
+ result_from_flat_tree.substr(mismatched_index));
}
TEST_F(StyledMarkupSerializerTest, StyleDisplayNone) {
@@ -238,9 +252,10 @@ TEST_F(StyledMarkupSerializerTest, ShadowTreeStyle) {
start_dom, end_dom, ShouldAnnotateOptions());
body_content =
- "<p id='host' style='color: red'>00<span id='one'>11</span>22</p>\n";
+ "<p id='host' style='color: red'>00<span slot='#one' "
+ "id='one'>11</span>22</p>\n";
const char* shadow_content =
- "<span style='font-weight: bold'><content select=#one></content></span>";
+ "<span style='font-weight: bold'><slot name='#one'></slot></span>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
one = GetDocument().getElementById("one");
@@ -253,7 +268,8 @@ TEST_F(StyledMarkupSerializerTest, ShadowTreeStyle) {
EXPECT_EQ(serialized_dom, serialized_ict);
}
-TEST_F(StyledMarkupSerializerTest, AcrossShadow) {
+// TODO(crbug.com/1157146): This test breaks without Shadow DOM v0.
+TEST_F(StyledMarkupSerializerTest, DISABLED_AcrossShadow) {
const char* body_content =
"<p id='host1'>[<span id='one'>11</span>]</p><p id='host2'>[<span "
"id='two'>22</span>]</p>";
@@ -266,10 +282,11 @@ TEST_F(StyledMarkupSerializerTest, AcrossShadow) {
start_dom, end_dom, ShouldAnnotateOptions());
body_content =
- "<p id='host1'><span id='one'>11</span></p><p id='host2'><span "
- "id='two'>22</span></p>";
- const char* shadow_content1 = "[<content select=#one></content>]";
- const char* shadow_content2 = "[<content select=#two></content>]";
+ "<p id='host1'><span slot='#one' id='one'>11</span></p><p "
+ "id='host2'><span "
+ "slot='#two' id='two'>22</span></p>";
+ const char* shadow_content1 = "[<slot name='#one'></slot>]";
+ const char* shadow_content2 = "[<slot name='#two'></slot>]";
SetBodyContent(body_content);
SetShadowContent(shadow_content1, "host1");
SetShadowContent(shadow_content2, "host2");
@@ -280,6 +297,8 @@ TEST_F(StyledMarkupSerializerTest, AcrossShadow) {
const std::string& serialized_ict = SerializePart<EditingInFlatTreeStrategy>(
start_ict, end_ict, ShouldAnnotateOptions());
+ // TODO(crbug.com/1157146): serialized_ict contains the <slot> elements, while
+ // serialized_dom does not.
EXPECT_EQ(serialized_dom, serialized_ict);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
index 4d30c47c32c..2593305adc0 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h
@@ -34,7 +34,7 @@ class CORE_EXPORT IdleSpellCheckController final
public:
explicit IdleSpellCheckController(LocalDOMWindow&, SpellCheckRequester&);
- ~IdleSpellCheckController();
+ ~IdleSpellCheckController() override;
enum class State {
#define V(state) k##state,
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
index e6f569d7cce..8189d456053 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
@@ -192,13 +192,17 @@ void SpellChecker::AdvanceToNextMisspelling(bool start_before_selection) {
// next word so we start checking at a word boundary. Going back by one char
// and then forward by a word does the trick.
if (started_with_selection) {
- VisiblePosition one_before_start =
- PreviousPositionOf(CreateVisiblePosition(spelling_search_start));
+ const Position& one_before_start =
+ PreviousPositionOf(CreateVisiblePosition(spelling_search_start))
+ .DeepEquivalent();
if (one_before_start.IsNotNull() &&
- RootEditableElementOf(one_before_start.DeepEquivalent()) ==
- RootEditableElementOf(spelling_search_start))
+ RootEditableElementOf(one_before_start) ==
+ RootEditableElementOf(spelling_search_start)) {
spelling_search_start =
- EndOfWord(one_before_start).ToParentAnchoredPosition();
+ CreateVisiblePosition(EndOfWordPosition(one_before_start),
+ TextAffinity::kUpstreamIfPossible)
+ .ToParentAnchoredPosition();
+ }
// else we were already at the start of the editable node
}
@@ -536,6 +540,14 @@ void SpellChecker::RespondToChangedContents() {
idle_spell_check_controller_->SetNeedsInvocation();
}
+void SpellChecker::RespondToChangedEnablement(const HTMLElement& element,
+ bool enabled) {
+ if (enabled)
+ idle_spell_check_controller_->SetNeedsInvocation();
+ else
+ RemoveSpellingAndGrammarMarkers(element);
+}
+
void SpellChecker::RemoveSpellingMarkers() {
GetFrame().GetDocument()->Markers().RemoveMarkersOfTypes(
DocumentMarker::MarkerTypes::Misspelling());
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
index c467defbfd1..96cf311f0bd 100644
--- a/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
@@ -40,6 +40,7 @@ class IdleSpellCheckController;
class LocalDOMWindow;
class LocalFrame;
class HTMLElement;
+class Node;
class SpellCheckMarker;
class SpellCheckRequest;
class SpellCheckRequester;
@@ -64,6 +65,7 @@ class CORE_EXPORT SpellChecker final : public GarbageCollected<SpellChecker> {
void ShowSpellingGuessPanel();
void RespondToChangedContents();
void RespondToChangedSelection();
+ void RespondToChangedEnablement(const HTMLElement&, bool enabled);
std::pair<Node*, SpellCheckMarker*> GetSpellCheckMarkerUnderSelection() const;
// The first String returned in the pair is the selected text.
// The second String is the marker's description.
diff --git a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
index 13d35c58583..1320ab2b328 100644
--- a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
+++ b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util.cc
@@ -85,13 +85,6 @@ bool IsGraphemeBreak(UChar32 prev_code_point, UChar32 next_code_point) {
Character::IsRegionalIndicator(next_code_point))
NOTREACHED() << "Do not use this function for regional indicators.";
- // This is an exception for Myanmar IMEs that uses zwnj character as base
- // character during a composition to avoid merging the actively composed text
- // into the previous character. We intentionally diverge from UAX#29.
- // Please see crbug.com/1027695 for more details.
- if (next_code_point == kZeroWidthNonJoinerCharacter)
- return true;
-
// Rule GB9, x (Extend | ZWJ)
// Rule GB9a, x SpacingMark
if (next_prop == U_GCB_EXTEND ||
diff --git a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util_test.cc b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util_test.cc
index f473c1f8b7e..3a1c58751d3 100644
--- a/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/state_machines/state_machine_util_test.cc
@@ -168,10 +168,4 @@ TEST(StateMachineUtilTest, IsGraphmeBreak_IndicSyllabicCategoryVirama) {
EXPECT_TRUE(IsGraphemeBreak(kTamilVirama, kDevangariKa));
}
-TEST(StateMachineUtilTest, IsGraphmeBreak_ZWNJSequecne) {
- // U+200C (kZeroWidthNonJoinerCharacter)
- EXPECT_TRUE(IsGraphemeBreak('a', WTF::unicode::kZeroWidthNonJoinerCharacter));
- EXPECT_TRUE(IsGraphemeBreak(WTF::unicode::kZeroWidthNonJoinerCharacter, 'a'));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/substring_util.h b/chromium/third_party/blink/renderer/core/editing/substring_util.h
index e0babc53cdf..362edfe00d1 100644
--- a/chromium/third_party/blink/renderer/core/editing/substring_util.h
+++ b/chromium/third_party/blink/renderer/core/editing/substring_util.h
@@ -46,17 +46,17 @@ class Point;
} // namespace gfx
namespace blink {
-class WebFrameWidgetBase;
+class WebFrameWidgetImpl;
class LocalFrame;
class SubstringUtil {
public:
// Returns an autoreleased NSAttributedString that is the word under
- // the given point inside the given WebFrameWidgetBase or nil on error.
+ // the given point inside the given WebFrameWidgetImpl or nil on error.
// Upon return, |baselinePoint| is set to the left baseline point in
// AppKit coordinates.
CORE_EXPORT static NSAttributedString* AttributedWordAtPoint(
- WebFrameWidgetBase*,
+ WebFrameWidgetImpl*,
gfx::Point,
gfx::Point& baseline_point);
diff --git a/chromium/third_party/blink/renderer/core/editing/substring_util.mm b/chromium/third_party/blink/renderer/core/editing/substring_util.mm
index e27858a33ab..20242302b39 100644
--- a/chromium/third_party/blink/renderer/core/editing/substring_util.mm
+++ b/chromium/third_party/blink/renderer/core/editing/substring_util.mm
@@ -48,7 +48,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -124,7 +124,8 @@ NSAttributedString* AttributedSubstringFromRange(const EphemeralRange& range,
String characters = it.GetTextState().GetTextForTesting();
characters.Ensure16Bit();
NSString* substring =
- [[[NSString alloc] initWithCharacters:characters.Characters16()
+ [[[NSString alloc] initWithCharacters:reinterpret_cast<const UniChar*>(
+ characters.Characters16())
length:characters.length()] autorelease];
[string replaceCharactersInRange:NSMakeRange(position, 0)
withString:substring];
@@ -153,7 +154,7 @@ gfx::Point GetBaselinePoint(LocalFrameView* frame_view,
} // namespace
NSAttributedString* SubstringUtil::AttributedWordAtPoint(
- WebFrameWidgetBase* frame_widget,
+ WebFrameWidgetImpl* frame_widget,
gfx::Point point,
gfx::Point& baseline_point) {
HitTestResult result =
@@ -168,10 +169,10 @@ NSAttributedString* SubstringUtil::AttributedWordAtPoint(
return nil;
// Expand to word under point.
- const VisibleSelection& selection = CreateVisibleSelectionWithGranularity(
+ const SelectionInDOMTree selection = ExpandWithGranularity(
SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(),
TextGranularity::kWord);
- const EphemeralRange word_range = selection.ToNormalizedEphemeralRange();
+ const EphemeralRange word_range = NormalizeRange(selection);
// Convert to NSAttributedString.
NSAttributedString* string = AttributedSubstringFromRange(
diff --git a/chromium/third_party/blink/renderer/core/editing/substring_util_test.mm b/chromium/third_party/blink/renderer/core/editing/substring_util_test.mm
index e43977116a1..6a5d38fabcb 100644
--- a/chromium/third_party/blink/renderer/core/editing/substring_util_test.mm
+++ b/chromium/third_party/blink/renderer/core/editing/substring_util_test.mm
@@ -10,7 +10,7 @@
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -46,7 +46,7 @@ TEST_F(SubStringUtilTest, SubstringUtil) {
base_url_ + "content_editable_populated.html"));
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(gfx::Size(400, 400));
+ web_view->MainFrameWidget()->Resize(gfx::Size(400, 400));
WebLocalFrameImpl* frame =
static_cast<WebLocalFrameImpl*>(web_view->MainFrame());
@@ -77,7 +77,7 @@ TEST_F(SubStringUtilTest, SubstringUtilBaselinePoint) {
WebView* web_view = static_cast<WebView*>(web_view_helper_.InitializeAndLoad(
base_url_ + "content_editable_multiline.html"));
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(gfx::Size(400, 400));
+ web_view->MainFrameWidget()->Resize(gfx::Size(400, 400));
WebLocalFrameImpl* frame =
static_cast<WebLocalFrameImpl*>(web_view->MainFrame());
@@ -98,7 +98,7 @@ TEST_F(SubStringUtilTest, SubstringUtilPinchZoom) {
WebView* web_view = static_cast<WebView*>(web_view_helper_.InitializeAndLoad(
base_url_ + "content_editable_populated.html"));
web_view->GetSettings()->SetDefaultFontSize(12);
- web_view->Resize(gfx::Size(400, 400));
+ web_view->MainFrameWidget()->Resize(gfx::Size(400, 400));
WebLocalFrameImpl* frame =
static_cast<WebLocalFrameImpl*>(web_view->MainFrame());
NSAttributedString* result = nil;
@@ -128,7 +128,7 @@ TEST_F(SubStringUtilTest, SubstringUtilIframe) {
web_view_helper_.InitializeAndLoad(base_url_ + "single_iframe.html"));
web_view->GetSettings()->SetDefaultFontSize(12);
web_view->GetSettings()->SetJavaScriptEnabled(true);
- web_view->Resize(gfx::Size(400, 400));
+ web_view->MainFrameWidget()->Resize(gfx::Size(400, 400));
WebLocalFrameImpl* main_frame =
static_cast<WebLocalFrameImpl*>(web_view->MainFrame());
WebLocalFrameImpl* child_frame = WebLocalFrameImpl::FromFrame(
diff --git a/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.cc b/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.cc
index e9bbc0773f0..a37666332db 100644
--- a/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.cc
+++ b/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.cc
@@ -72,7 +72,7 @@ ShadowRoot* EditingTestBase::CreateShadowRootForElementWithIDAndSetInnerHTML(
const char* shadow_root_content) {
ShadowRoot& shadow_root =
scope.getElementById(AtomicString::FromUTF8(host_element_id))
- ->CreateV0ShadowRootForTesting();
+ ->AttachShadowRootInternal(ShadowRootType::kOpen);
shadow_root.setInnerHTML(String::FromUTF8(shadow_root_content),
ASSERT_NO_EXCEPTION);
scope.GetDocument().View()->UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.h b/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.h
index 13e0bcb2198..5a892c96ef4 100644
--- a/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.h
+++ b/chromium/third_party/blink/renderer/core/editing/testing/editing_test_base.h
@@ -9,6 +9,7 @@
#include <memory>
#include <string>
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.cc b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.cc
index 4d9fbc36087..a5cbf252a51 100644
--- a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.cc
+++ b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample.cc
@@ -119,7 +119,7 @@ class Parser final {
}
void HandleElementNode(Element* element) {
- if (ShadowRoot* shadow_root = element->ShadowRootIfV1())
+ if (ShadowRoot* shadow_root = element->GetShadowRoot())
HandleChildren(shadow_root);
HandleChildren(element);
}
diff --git a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample_test.cc b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample_test.cc
index 85a0d2de848..1d59c97fe58 100644
--- a/chromium/third_party/blink/renderer/core/editing/testing/selection_sample_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/testing/selection_sample_test.cc
@@ -29,7 +29,6 @@ TEST_F(SelectionSampleTest, GetSelectionTextFlatTree) {
" </template>"
" <b slot=two>tw|o</b><b slot=one>one</b>"
"</p>");
- GetDocument().body()->UpdateDistributionForFlatTreeTraversal();
EXPECT_EQ(
"<p>"
" ze^ro <slot name=\"one\"><b slot=\"one\">one</b></slot> <slot "
@@ -264,7 +263,7 @@ TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRoots) {
Element* host = body->getElementById("host");
SelectionSample::ConvertTemplatesToShadowRootsForTesring(
*(To<HTMLElement>(host)));
- ShadowRoot* shadow_root = host->ShadowRootIfV1();
+ ShadowRoot* shadow_root = host->GetShadowRoot();
ASSERT_TRUE(shadow_root->IsShadowRoot());
EXPECT_EQ("<div>shadow_first</div><div>shadow_second</div>",
shadow_root->innerHTML());
@@ -280,7 +279,7 @@ TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRootsNoTemplates) {
Element* host = body->getElementById("host");
SelectionSample::ConvertTemplatesToShadowRootsForTesring(
*(To<HTMLElement>(host)));
- EXPECT_FALSE(host->ShadowRootIfV1());
+ EXPECT_FALSE(host->GetShadowRoot());
EXPECT_EQ("<div>first</div><div>second</div>", host->innerHTML());
}
@@ -303,8 +302,8 @@ TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRootsMultipleTemplates) {
Element* host2 = body->getElementById("host2");
SelectionSample::ConvertTemplatesToShadowRootsForTesring(
*(To<HTMLElement>(body)));
- ShadowRoot* shadow_root_1 = host1->ShadowRootIfV1();
- ShadowRoot* shadow_root_2 = host2->ShadowRootIfV1();
+ ShadowRoot* shadow_root_1 = host1->GetShadowRoot();
+ ShadowRoot* shadow_root_2 = host2->GetShadowRoot();
EXPECT_TRUE(shadow_root_1->IsShadowRoot());
EXPECT_EQ("<div>shadow_first</div><div>shadow_second</div>",
@@ -327,7 +326,7 @@ TEST_F(SelectionSampleTest, TraverseShadowContent) {
EXPECT_EQ("<div id=\"host\"></div>", body->innerHTML());
Element* host = body->getElementById("host");
- ShadowRoot* shadow_root = host->ShadowRootIfV1();
+ ShadowRoot* shadow_root = host->GetShadowRoot();
EXPECT_TRUE(shadow_root->IsShadowRoot());
EXPECT_EQ(
"<div id=\"shadow1\">shadow_first</div>"
@@ -356,7 +355,7 @@ TEST_F(SelectionSampleTest, TraverseShadowContentWithSlot) {
body->innerHTML());
Element* host = body->getElementById("host");
- ShadowRoot* shadow_root = host->ShadowRootIfV1();
+ ShadowRoot* shadow_root = host->GetShadowRoot();
EXPECT_TRUE(shadow_root->IsShadowRoot());
EXPECT_EQ(
"<div id=\"shadow1\">shadow_first</div>"
@@ -391,9 +390,9 @@ TEST_F(SelectionSampleTest, TraverseMultipleShadowContents) {
body->innerHTML());
Element* host1 = body->getElementById("host1");
- ShadowRoot* shadow_root1 = host1->ShadowRootIfV1();
+ ShadowRoot* shadow_root1 = host1->GetShadowRoot();
Element* host2 = body->getElementById("host2");
- ShadowRoot* shadow_root2 = host2->ShadowRootIfV1();
+ ShadowRoot* shadow_root2 = host2->GetShadowRoot();
EXPECT_TRUE(shadow_root1->IsShadowRoot());
EXPECT_TRUE(shadow_root2->IsShadowRoot());
EXPECT_EQ(
diff --git a/chromium/third_party/blink/renderer/core/editing/text_offset_mapping.cc b/chromium/third_party/blink/renderer/core/editing/text_offset_mapping.cc
index 5df7c74e327..27ba43aab53 100644
--- a/chromium/third_party/blink/renderer/core/editing/text_offset_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/editing/text_offset_mapping.cc
@@ -290,11 +290,17 @@ TextOffsetMapping::InlineContents TextOffsetMapping::FindBackwardInlineContents(
auto previous_skipping_text_control = [](const Node& node) -> const Node* {
DCHECK(!EnclosingTextControl(&node));
const Node* previous = PreviousNodeSkippingAncestors(node);
+ if (!previous)
+ return previous;
const TextControlElement* previous_text_control =
EnclosingTextControl(previous);
- if (!previous_text_control)
- return previous;
- return previous_text_control;
+ if (previous_text_control)
+ return previous_text_control;
+ if (ShadowRoot* root = previous->ContainingShadowRoot()) {
+ if (root->IsUserAgent())
+ return root->OwnerShadowHost();
+ }
+ return previous;
};
if (const TextControlElement* last_enclosing_text_control =
@@ -334,6 +340,10 @@ TextOffsetMapping::InlineContents TextOffsetMapping::FindForwardInlineContents(
DCHECK(!EnclosingTextControl(&node));
if (IsTextControl(node))
return FlatTreeTraversal::NextSkippingChildren(node);
+ if (ShadowRoot* root = node.GetShadowRoot()) {
+ if (root->IsUserAgent())
+ return FlatTreeTraversal::NextSkippingChildren(node);
+ }
return FlatTreeTraversal::Next(node);
};
DCHECK(!EnclosingTextControl(next_node));
diff --git a/chromium/third_party/blink/renderer/core/editing/text_offset_mapping_test.cc b/chromium/third_party/blink/renderer/core/editing/text_offset_mapping_test.cc
index 13cca33a718..6903907ea35 100644
--- a/chromium/third_party/blink/renderer/core/editing/text_offset_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/text_offset_mapping_test.cc
@@ -38,8 +38,11 @@ class ParameterizedTextOffsetMappingTest
}
std::string GetRange(const std::string& selection_text) {
- const PositionInFlatTree position =
- ToPositionInFlatTree(SetSelectionTextToBody(selection_text).Base());
+ return GetRange(
+ ToPositionInFlatTree(SetSelectionTextToBody(selection_text).Base()));
+ }
+
+ std::string GetRange(const PositionInFlatTree& position) {
return GetRange(GetInlineContents(position));
}
@@ -421,13 +424,41 @@ TEST_P(ParameterizedTextOffsetMappingTest, RangeWithNestedPosition) {
}
// http://crbug.com//834623
-TEST_P(ParameterizedTextOffsetMappingTest, RangeWithSelect) {
- EXPECT_EQ(
+TEST_P(ParameterizedTextOffsetMappingTest, RangeWithSelect1) {
+ SetBodyContent("<select></select>foo");
+ Element* select = GetDocument().QuerySelector("select");
+ const auto& expected_outer =
"^<select>"
"<div aria-hidden=\"true\"></div>"
"<slot name=\"user-agent-custom-assign-slot\"></slot>"
- "</select>foo|",
- GetRange("<select>|</select>foo"));
+ "</select>foo|";
+ const auto& expected_inner =
+ "<select>"
+ "<div aria-hidden=\"true\">^|</div>"
+ "<slot name=\"user-agent-custom-assign-slot\"></slot>"
+ "</select>foo";
+ EXPECT_EQ(expected_outer, GetRange(PositionInFlatTree::BeforeNode(*select)));
+ EXPECT_EQ(expected_inner, GetRange(PositionInFlatTree(select, 0)));
+ EXPECT_EQ(expected_outer, GetRange(PositionInFlatTree::AfterNode(*select)));
+}
+
+TEST_P(ParameterizedTextOffsetMappingTest, RangeWithSelect2) {
+ SetBodyContent("<select>bar</select>foo");
+ Element* select = GetDocument().QuerySelector("select");
+ const auto& expected_outer =
+ "^<select>"
+ "<div aria-hidden=\"true\"></div>"
+ "<slot name=\"user-agent-custom-assign-slot\"></slot>"
+ "</select>foo|";
+ const auto& expected_inner =
+ "<select>"
+ "<div aria-hidden=\"true\">^|</div>"
+ "<slot name=\"user-agent-custom-assign-slot\"></slot>"
+ "</select>foo";
+ EXPECT_EQ(expected_outer, GetRange(PositionInFlatTree::BeforeNode(*select)));
+ EXPECT_EQ(expected_inner, GetRange(PositionInFlatTree(select, 0)));
+ EXPECT_EQ(expected_outer, GetRange(PositionInFlatTree(select, 1)));
+ EXPECT_EQ(expected_outer, GetRange(PositionInFlatTree::AfterNode(*select)));
}
// http://crbug.com//832350
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_position.cc b/chromium/third_party/blink/renderer/core/editing/visible_position.cc
index 8d5860fe9bc..a8701ecf1a5 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_position.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_position.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
+#include "third_party/blink/renderer/core/editing/inline_box_position.h"
#include "third_party/blink/renderer/core/editing/local_caret_rect.h"
#include "third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
@@ -38,6 +39,8 @@
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/line/inline_box.h"
+#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
@@ -71,6 +74,37 @@ void VisiblePositionTemplate<Strategy>::Trace(Visitor* visitor) const {
}
template <typename Strategy>
+static inline bool InDifferentLinesOfSameInlineFormattingContext(
+ const PositionWithAffinityTemplate<Strategy>& position1,
+ const PositionWithAffinityTemplate<Strategy>& position2) {
+ DCHECK(position1.IsNotNull());
+ DCHECK(position2.IsNotNull());
+ // Optimization for common cases.
+ if (position1 == position2)
+ return false;
+ // InSameLine may DCHECK that the anchors have a layout object.
+ if (!position1.AnchorNode()->GetLayoutObject() ||
+ !position2.AnchorNode()->GetLayoutObject())
+ return false;
+ // Return false if the positions are in the same line.
+ if (InSameLine(position1, position2))
+ return false;
+ // Return whether the positions are in the same inline formatting context.
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ const LayoutBlockFlow* block1 =
+ NGInlineFormattingContextOf(position1.GetPosition());
+ return block1 &&
+ block1 == NGInlineFormattingContextOf(position2.GetPosition());
+ }
+ const InlineBox* inline_box1 = ComputeInlineBoxPosition(position1).inline_box;
+ if (!inline_box1)
+ return false;
+ const InlineBox* inline_box2 = ComputeInlineBoxPosition(position2).inline_box;
+ return inline_box2 &&
+ inline_box1->Root().LineBoxes() == inline_box2->Root().LineBoxes();
+}
+
+template <typename Strategy>
VisiblePositionTemplate<Strategy> VisiblePositionTemplate<Strategy>::Create(
const PositionWithAffinityTemplate<Strategy>& position_with_affinity) {
if (position_with_affinity.IsNull())
@@ -88,8 +122,30 @@ VisiblePositionTemplate<Strategy> VisiblePositionTemplate<Strategy>::Create(
return VisiblePositionTemplate<Strategy>();
const PositionWithAffinityTemplate<Strategy> downstream_position(
deep_position);
- if (position_with_affinity.Affinity() == TextAffinity::kDownstream)
+ if (position_with_affinity.Affinity() == TextAffinity::kDownstream) {
+ // Fast path for common cases.
+ if (position_with_affinity == downstream_position)
+ return VisiblePositionTemplate<Strategy>(downstream_position);
+
+ // If the canonical position went into a previous line of the same inline
+ // formatting context, use the start of the current line instead.
+ const PositionInFlatTree& flat_deep_position =
+ ToPositionInFlatTree(deep_position);
+ const PositionInFlatTree& flat_position =
+ ToPositionInFlatTree(position_with_affinity.GetPosition());
+ if (flat_deep_position.IsNotNull() && flat_position.IsNotNull() &&
+ flat_deep_position < flat_position &&
+ InDifferentLinesOfSameInlineFormattingContext(position_with_affinity,
+ downstream_position)) {
+ const PositionWithAffinityTemplate<Strategy>& start_of_line =
+ StartOfLine(position_with_affinity);
+ if (start_of_line.IsNotNull())
+ return VisiblePositionTemplate<Strategy>(start_of_line);
+ }
+
+ // Otherwise use the canonical position.
return VisiblePositionTemplate<Strategy>(downstream_position);
+ }
if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled() &&
NGInlineFormattingContextOf(deep_position)) {
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_position_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_position_test.cc
index 36547fc66d4..39a434a9602 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_position_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_position_test.cc
@@ -12,6 +12,23 @@ namespace blink {
class VisiblePositionTest : public EditingTestBase {};
+// Helper class to run the same test code with and without LayoutNG
+class ParameterizedVisiblePositionTest
+ : public testing::WithParamInterface<bool>,
+ private ScopedLayoutNGForTest,
+ public VisiblePositionTest {
+ protected:
+ ParameterizedVisiblePositionTest() : ScopedLayoutNGForTest(GetParam()) {}
+
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ ParameterizedVisiblePositionTest,
+ testing::Bool());
+
TEST_F(VisiblePositionTest, EmptyEditable) {
SetBodyContent("<div id=target contenteditable></div>");
const Element& target = *GetElementById("target");
@@ -138,57 +155,6 @@ TEST_F(VisiblePositionTest, PlaceholderBRWithCollapsedSpace) {
CreateVisiblePosition(Position(target.lastChild(), 1)).DeepEquivalent());
}
-TEST_F(VisiblePositionTest, ShadowV0DistributedNodes) {
- const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
- const char* shadow_content =
- "<a><span id='s4'>44</span><content select=#two></content><span "
- "id='s5'>55</span><content select=#one></content><span "
- "id='s6'>66</span></a>";
- SetBodyContent(body_content);
- ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
-
- Element* body = GetDocument().body();
- Element* one = body->QuerySelector("#one");
- Element* two = body->QuerySelector("#two");
- Element* four = shadow_root->QuerySelector("#s4");
- Element* five = shadow_root->QuerySelector("#s5");
-
- EXPECT_EQ(Position(one->firstChild(), 0),
- CanonicalPositionOf(Position(one, 0)));
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapBackward(Position(one, 0)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapForward(Position(one, 0)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 0),
- CreateVisiblePosition(Position(one, 0)).DeepEquivalent());
- EXPECT_EQ(Position(one->firstChild(), 2),
- CanonicalPositionOf(Position(two, 0)));
- EXPECT_EQ(Position(one->firstChild(), 2),
- SnapBackward(Position(two, 0)).GetPosition());
- EXPECT_EQ(Position(two->firstChild(), 0),
- SnapForward(Position(two, 0)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 2),
- CreateVisiblePosition(Position(two, 0)).DeepEquivalent());
-
- EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
- CanonicalPositionOf(PositionInFlatTree(one, 0)));
- EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
- SnapBackward(PositionInFlatTree(one, 0)).GetPosition());
- EXPECT_EQ(PositionInFlatTree(one->firstChild(), 0),
- SnapForward(PositionInFlatTree(one, 0)).GetPosition());
- EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
- CreateVisiblePosition(PositionInFlatTree(one, 0)).DeepEquivalent());
- EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
- CanonicalPositionOf(PositionInFlatTree(two, 0)));
- EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
- SnapBackward(PositionInFlatTree(two, 0)).GetPosition());
- EXPECT_EQ(PositionInFlatTree(two->firstChild(), 0),
- SnapForward(PositionInFlatTree(two, 0)).GetPosition());
- EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
- CreateVisiblePosition(PositionInFlatTree(two, 0)).DeepEquivalent());
-}
-
#if DCHECK_IS_ON()
TEST_F(VisiblePositionTest, NullIsValid) {
@@ -251,4 +217,114 @@ TEST_F(VisiblePositionTest, NonNullInvalidatedAfterStyleChange) {
#endif
+TEST_F(VisiblePositionTest, NormalizationAroundLineBreak) {
+ LoadAhem();
+ InsertStyleElement(
+ "div {"
+ "width: 5.5ch;"
+ "font: 10px/10px Ahem;"
+ "word-wrap: break-word;"
+ "}");
+ SetBodyContent(
+ "<div>line1line2</div>"
+ "<div>line1<br>line2</div>"
+ "<div>line1<wbr>line2</div>"
+ "<div>line1<span></span>line2</div>"
+ "<div>line1<span></span><span></span>line2</div>");
+
+ StaticElementList* tests = GetDocument().QuerySelectorAll("div");
+ for (unsigned i = 0; i < tests->length(); ++i) {
+ Element* test = tests->item(i);
+ Node* node1 = test->firstChild();
+ Node* node2 = test->lastChild();
+ PositionWithAffinity line1_end(Position(node1, 5), TextAffinity::kUpstream);
+ PositionWithAffinity line2_start(Position(node2, node1 == node2 ? 5 : 0),
+ TextAffinity::kDownstream);
+ PositionWithAffinity line1_end_normalized =
+ CreateVisiblePosition(line1_end).ToPositionWithAffinity();
+ PositionWithAffinity line2_start_normalized =
+ CreateVisiblePosition(line2_start).ToPositionWithAffinity();
+
+ EXPECT_FALSE(InSameLine(line1_end, line2_start));
+ EXPECT_FALSE(InSameLine(line1_end_normalized, line2_start_normalized));
+ EXPECT_TRUE(InSameLine(line1_end, line1_end_normalized));
+ EXPECT_TRUE(InSameLine(line2_start, line2_start_normalized));
+ }
+}
+
+TEST_P(ParameterizedVisiblePositionTest, SpacesAroundLineBreak) {
+ // Narrow <body> forces "a" and "b" to be in different lines.
+ InsertStyleElement("body { width: 1px }");
+ {
+ SetBodyContent("a b");
+ Node* ab = GetDocument().body()->firstChild();
+ EXPECT_EQ(Position(ab, 0),
+ CreateVisiblePosition(Position(ab, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(ab, 1),
+ CreateVisiblePosition(Position(ab, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(ab, 2),
+ CreateVisiblePosition(Position(ab, 2)).DeepEquivalent());
+ }
+ {
+ SetBodyContent("a<span> b</span>");
+ Node* a = GetDocument().body()->firstChild();
+ Node* b = a->nextSibling()->firstChild();
+ EXPECT_EQ(Position(a, 0),
+ CreateVisiblePosition(Position(a, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(a, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(b, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(LayoutNGEnabled() ? b : a, 1),
+ CreateVisiblePosition(Position(b, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(b, 2),
+ CreateVisiblePosition(Position(b, 2)).DeepEquivalent());
+ }
+ {
+ SetBodyContent("<span>a</span> b");
+ Node* b = GetDocument().body()->lastChild();
+ Node* a = b->previousSibling()->firstChild();
+ EXPECT_EQ(Position(a, 0),
+ CreateVisiblePosition(Position(a, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(a, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(b, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(LayoutNGEnabled() ? b : a, 1),
+ CreateVisiblePosition(Position(b, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(b, 2),
+ CreateVisiblePosition(Position(b, 2)).DeepEquivalent());
+ }
+ {
+ SetBodyContent("a <span>b</span>");
+ Node* a = GetDocument().body()->firstChild();
+ Node* b = a->nextSibling()->firstChild();
+ EXPECT_EQ(Position(a, 0),
+ CreateVisiblePosition(Position(a, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(a, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(a, LayoutNGEnabled() ? 2 : 1),
+ CreateVisiblePosition(Position(a, 2)).DeepEquivalent());
+ EXPECT_EQ(Position(a, LayoutNGEnabled() ? 2 : 1),
+ CreateVisiblePosition(Position(b, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(b, 1),
+ CreateVisiblePosition(Position(b, 1)).DeepEquivalent());
+ }
+ {
+ SetBodyContent("<span>a </span>b");
+ Node* b = GetDocument().body()->lastChild();
+ Node* a = b->previousSibling()->firstChild();
+ EXPECT_EQ(Position(a, 0),
+ CreateVisiblePosition(Position(a, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(a, 1),
+ CreateVisiblePosition(Position(a, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(a, LayoutNGEnabled() ? 2 : 1),
+ CreateVisiblePosition(Position(a, 2)).DeepEquivalent());
+ EXPECT_EQ(Position(a, LayoutNGEnabled() ? 2 : 1),
+ CreateVisiblePosition(Position(b, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(b, 1),
+ CreateVisiblePosition(Position(b, 1)).DeepEquivalent());
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_selection.cc b/chromium/third_party/blink/renderer/core/editing/visible_selection.cc
index c6ab0e1cb4d..22218ce2cac 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_selection.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_selection.cc
@@ -66,7 +66,6 @@ class VisibleSelectionTemplate<Strategy>::Creator {
ComputeVisibleSelection(selection, granularity));
}
- private:
static SelectionTemplate<Strategy> ComputeVisibleSelection(
const SelectionTemplate<Strategy>& passed_selection,
TextGranularity granularity) {
@@ -109,17 +108,15 @@ VisibleSelectionInFlatTree CreateVisibleSelection(
selection, TextGranularity::kCharacter);
}
-VisibleSelection CreateVisibleSelectionWithGranularity(
- const SelectionInDOMTree& selection,
- TextGranularity granularity) {
- return VisibleSelection::Creator::CreateWithGranularity(selection,
- granularity);
+SelectionInDOMTree ExpandWithGranularity(const SelectionInDOMTree& selection,
+ TextGranularity granularity) {
+ return VisibleSelection::Creator::ComputeVisibleSelection(selection,
+ granularity);
}
-VisibleSelectionInFlatTree CreateVisibleSelectionWithGranularity(
- const SelectionInFlatTree& selection,
- TextGranularity granularity) {
- return VisibleSelectionInFlatTree::Creator::CreateWithGranularity(
+SelectionInFlatTree ExpandWithGranularity(const SelectionInFlatTree& selection,
+ TextGranularity granularity) {
+ return VisibleSelectionInFlatTree::Creator::ComputeVisibleSelection(
selection, granularity);
}
@@ -190,21 +187,28 @@ EphemeralRange FirstEphemeralRangeOf(const VisibleSelection& selection) {
template <typename Strategy>
EphemeralRangeTemplate<Strategy>
VisibleSelectionTemplate<Strategy>::ToNormalizedEphemeralRange() const {
- if (IsNone())
+ return NormalizeRange(AsSelection());
+}
+
+template <typename Strategy>
+static EphemeralRangeTemplate<Strategy> NormalizeRangeAlgorithm(
+ const SelectionTemplate<Strategy>& selection) {
+ if (selection.IsNone())
return EphemeralRangeTemplate<Strategy>();
// Make sure we have an updated layout since this function is called
// in the course of running edit commands which modify the DOM.
// Failing to ensure this can result in equivalentXXXPosition calls returning
// incorrect results.
- DCHECK(!NeedsLayoutTreeUpdate(Start())) << *this;
+ DCHECK(!NeedsLayoutTreeUpdate(selection.Base())) << selection;
- if (IsCaret()) {
+ if (selection.IsCaret()) {
// If the selection is a caret, move the range start upstream. This
// helps us match the conventions of text editors tested, which make
// style determinations based on the character before the caret, if any.
const PositionTemplate<Strategy> start =
- MostBackwardCaretPosition(Start()).ParentAnchoredEquivalent();
+ MostBackwardCaretPosition(selection.ComputeStartPosition())
+ .ParentAnchoredEquivalent();
return EphemeralRangeTemplate<Strategy>(start, start);
}
// If the selection is a range, select the minimum range that encompasses
@@ -218,8 +222,16 @@ VisibleSelectionTemplate<Strategy>::ToNormalizedEphemeralRange() const {
// On a treasure map, <b>X</b> marks the spot.
// ^ selected
//
- DCHECK(IsRange());
- return NormalizeRange(EphemeralRangeTemplate<Strategy>(Start(), End()));
+ DCHECK(selection.IsRange());
+ return NormalizeRange(selection.ComputeRange());
+}
+
+EphemeralRange NormalizeRange(const SelectionInDOMTree& selection) {
+ return NormalizeRangeAlgorithm(selection);
+}
+
+EphemeralRangeInFlatTree NormalizeRange(const SelectionInFlatTree& selection) {
+ return NormalizeRangeAlgorithm(selection);
}
template <typename Strategy>
@@ -264,37 +276,6 @@ bool VisibleSelectionTemplate<Strategy>::IsValidFor(
return base_.IsValidFor(document) && extent_.IsValidFor(document);
}
-// TODO(yosin) This function breaks the invariant of this class.
-// But because we use VisibleSelection to store values in editing commands for
-// use when undoing the command, we need to be able to create a selection that
-// while currently invalid, will be valid once the changes are undone. This is a
-// design problem. To fix it we either need to change the invariants of
-// |VisibleSelection| or create a new class for editing to use that can
-// manipulate selections that are not currently valid.
-template <typename Strategy>
-VisibleSelectionTemplate<Strategy>
-VisibleSelectionTemplate<Strategy>::CreateWithoutValidationDeprecated(
- const PositionTemplate<Strategy>& base,
- const PositionTemplate<Strategy>& extent,
- TextAffinity affinity) {
- DCHECK(base.IsNotNull());
- DCHECK(extent.IsNotNull());
-
- VisibleSelectionTemplate<Strategy> visible_selection;
- visible_selection.base_ = base;
- visible_selection.extent_ = extent;
- visible_selection.base_is_first_ = base.CompareTo(extent) <= 0;
- if (base == extent) {
- visible_selection.affinity_ = affinity;
- return visible_selection;
- }
- // Since |affinity_| for non-|CaretSelection| is always |kDownstream|,
- // we should keep this invariant. Note: This function can be called with
- // |affinity_| is |kUpstream|.
- visible_selection.affinity_ = TextAffinity::kDownstream;
- return visible_selection;
-}
-
template <typename Strategy>
bool VisibleSelectionTemplate<Strategy>::IsContentEditable() const {
return IsEditablePosition(Start());
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_selection.h b/chromium/third_party/blink/renderer/core/editing/visible_selection.h
index 95dfd066969..20ef5afcb30 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_selection.h
+++ b/chromium/third_party/blink/renderer/core/editing/visible_selection.h
@@ -30,7 +30,6 @@
#include "third_party/blink/renderer/core/editing/editing_strategy.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/editing/position.h"
-#include "third_party/blink/renderer/core/editing/selection_type.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/editing/text_granularity.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
@@ -87,14 +86,6 @@ class VisibleSelectionTemplate {
bool IsValidFor(const Document&) const;
- // TODO(editing-dev): |CreateWithoutValidationDeprecated()| is allowed
- // only to use in |TypingCommand| to remove part of grapheme cluster.
- // Note: |base| and |extent| can be disconnect position.
- static VisibleSelectionTemplate<Strategy> CreateWithoutValidationDeprecated(
- const PositionTemplate<Strategy>& base,
- const PositionTemplate<Strategy>& extent,
- TextAffinity);
-
void Trace(Visitor*) const;
#if DCHECK_IS_ON()
@@ -134,17 +125,17 @@ CORE_EXPORT VisibleSelection CreateVisibleSelection(const SelectionInDOMTree&);
CORE_EXPORT VisibleSelectionInFlatTree
CreateVisibleSelection(const SelectionInFlatTree&);
-CORE_EXPORT VisibleSelection
-CreateVisibleSelectionWithGranularity(const SelectionInDOMTree&,
- TextGranularity);
+CORE_EXPORT SelectionInDOMTree ExpandWithGranularity(const SelectionInDOMTree&,
+ TextGranularity);
-CORE_EXPORT VisibleSelectionInFlatTree
-CreateVisibleSelectionWithGranularity(const SelectionInFlatTree&,
- TextGranularity);
+CORE_EXPORT SelectionInFlatTree
+ExpandWithGranularity(const SelectionInFlatTree&, TextGranularity);
// We don't yet support multi-range selections, so we only ever have one range
// to return.
CORE_EXPORT EphemeralRange FirstEphemeralRangeOf(const VisibleSelection&);
+CORE_EXPORT EphemeralRange NormalizeRange(const SelectionInDOMTree&);
+CORE_EXPORT EphemeralRangeInFlatTree NormalizeRange(const SelectionInFlatTree&);
CORE_EXPORT std::ostream& operator<<(std::ostream&, const VisibleSelection&);
CORE_EXPORT std::ostream& operator<<(std::ostream&,
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_selection_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_selection_test.cc
index 0fed925d2de..735008bd03b 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_selection_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_selection_test.cc
@@ -62,11 +62,9 @@ std::string VisibleSelectionTest::GetWordSelectionText(
const std::string& selection_text) {
const PositionInFlatTree position =
ToPositionInFlatTree(SetSelectionTextToBody(selection_text).Base());
- return GetSelectionTextInFlatTreeFromBody(
- CreateVisibleSelectionWithGranularity(
- SelectionInFlatTree::Builder().Collapse(position).Build(),
- TextGranularity::kWord)
- .AsSelection());
+ return GetSelectionTextInFlatTreeFromBody(ExpandWithGranularity(
+ SelectionInFlatTree::Builder().Collapse(position).Build(),
+ TextGranularity::kWord));
}
static void TestFlatTreePositionsToEqualToDOMTreePositions(
@@ -88,20 +86,38 @@ template <typename Strategy>
VisibleSelectionTemplate<Strategy> ExpandUsingGranularity(
const VisibleSelectionTemplate<Strategy>& selection,
TextGranularity granularity) {
- return CreateVisibleSelectionWithGranularity(
+ return CreateVisibleSelection(ExpandWithGranularity(
typename SelectionTemplate<Strategy>::Builder()
.SetBaseAndExtent(selection.Base(), selection.Extent())
.Build(),
- granularity);
+ granularity));
+}
+
+// For "editing/deleting/delete_after_block_image.html"
+TEST_F(VisibleSelectionTest, AnonymousPlaceholder) {
+ InsertStyleElement("img { display:block; width: 10px; height: 10px;");
+ SetBodyContent("<div><img id=i><br id=b></div>");
+ Element& img = *GetElementById("i");
+ Element& br = *GetElementById("b");
+
+ // Note: After:<img>, Before:<br>, DIV@1 are equivalent.
+ const VisibleSelection& selection =
+ CreateVisibleSelection(SelectionInDOMTree::Builder()
+ .Collapse(Position::BeforeNode(br))
+ .Extend(Position::AfterNode(img))
+ .Build());
+ EXPECT_TRUE(selection.IsCaret());
+ EXPECT_EQ(Position::BeforeNode(br), selection.Base());
+ EXPECT_EQ(Position::BeforeNode(br), selection.Extent());
}
TEST_F(VisibleSelectionTest, expandUsingGranularity) {
const char* body_content =
- "<span id=host><a id=one>1</a><a id=two>22</a></span>";
+ "<span id=host><a slot='#one' id=one>1</a><a slot='#two' "
+ "id=two>22</a></span>";
const char* shadow_content =
- "<p><b id=three>333</b><content select=#two></content><b "
- "id=four>4444</b><span id=space> </span><content "
- "select=#one></content><b id=five>55555</b></p>";
+ "<p><b id=three>333</b><slot name=#two></slot><b id=four>4444</b><span "
+ "id=space> </span><slot name=#one></slot><b id=five>55555</b></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -228,16 +244,15 @@ TEST_F(VisibleSelectionTest, ExpandUsingGranularityWithEmptyCell) {
"<td id='first' width='50' height='25pt'>|</td>"
"<td id='second' width='50' height='25pt'></td>"
"</tr></table></div>");
- const VisibleSelectionInFlatTree& selection =
- CreateVisibleSelectionWithGranularity(
- ConvertToSelectionInFlatTree(selection_in_dom_tree),
- TextGranularity::kWord);
+ const SelectionInFlatTree& selection =
+ ExpandWithGranularity(ConvertToSelectionInFlatTree(selection_in_dom_tree),
+ TextGranularity::kWord);
EXPECT_EQ(
"<div contenteditable><table cellspacing=\"0\"><tbody><tr>"
"<td height=\"25pt\" id=\"first\" width=\"50\">|</td>"
"<td height=\"25pt\" id=\"second\" width=\"50\"></td>"
"</tr></tbody></table></div>",
- GetSelectionTextInFlatTreeFromBody(selection.AsSelection()));
+ GetSelectionTextInFlatTreeFromBody(selection));
}
TEST_F(VisibleSelectionTest, Initialisation) {
@@ -421,11 +436,11 @@ TEST_F(VisibleSelectionTest, GetWordSelectionTextWithTextSecurity) {
TEST_F(VisibleSelectionTest, ShadowCrossing) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
const char* shadow_content =
- "<a><span id='s4'>44</span><content select=#two></content><span "
- "id='s5'>55</span><content select=#one></content><span "
- "id='s6'>66</span></a>";
+ "<a><span id='s4'>44</span><slot name=#two></slot><span "
+ "id='s5'>55</span><slot name=#one></slot><span id='s6'>66</span></a>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -447,56 +462,23 @@ TEST_F(VisibleSelectionTest, ShadowCrossing) {
EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor),
selection.Start());
- EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor), selection.End());
+ EXPECT_EQ(Position(one->firstChild(), 0), selection.End());
EXPECT_EQ(PositionInFlatTree(one->firstChild(), 0),
selection_in_flat_tree.Start());
EXPECT_EQ(PositionInFlatTree(six->firstChild(), 2),
selection_in_flat_tree.End());
}
-TEST_F(VisibleSelectionTest, ShadowV0DistributedNodes) {
- const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
- const char* shadow_content =
- "<a><span id='s4'>44</span><content select=#two></content><span "
- "id='s5'>55</span><content select=#one></content><span "
- "id='s6'>66</span></a>";
- SetBodyContent(body_content);
- ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
-
- Element* body = GetDocument().body();
- Element* one = body->QuerySelector("#one");
- Element* two = body->QuerySelector("#two");
- Element* five = shadow_root->QuerySelector("#s5");
-
- VisibleSelection selection =
- CreateVisibleSelection(SelectionInDOMTree::Builder()
- .Collapse(Position::FirstPositionInNode(*one))
- .Extend(Position::LastPositionInNode(*two))
- .Build());
- VisibleSelectionInFlatTree selection_in_flat_tree = CreateVisibleSelection(
- SelectionInFlatTree::Builder()
- .Collapse(PositionInFlatTree::FirstPositionInNode(*one))
- .Extend(PositionInFlatTree::LastPositionInNode(*two))
- .Build());
-
- EXPECT_EQ(Position(one->firstChild(), 0), selection.Start());
- EXPECT_EQ(Position(two->firstChild(), 2), selection.End());
- EXPECT_EQ(PositionInFlatTree(five->firstChild(), 0),
- selection_in_flat_tree.Start());
- EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
- selection_in_flat_tree.End());
-}
TEST_F(VisibleSelectionTest, ShadowNested) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
const char* shadow_content =
- "<a><span id='s4'>44</span><content select=#two></content><span "
- "id='s5'>55</span><content select=#one></content><span "
- "id='s6'>66</span></a>";
+ "<a><span id='s4'>44</span><slot name=#two></slot><span "
+ "id='s5'>55</span><slot name=#one></slot><span id='s6'>66</span></a>";
const char* shadow_content2 =
- "<span id='s7'>77</span><content></content><span id='s8'>88</span>";
+ "<span id='s7'>77</span><slot></slot><span id='s8'>88</span>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
ShadowRoot* shadow_root2 = CreateShadowRootForElementWithIDAndSetInnerHTML(
@@ -528,7 +510,7 @@ TEST_F(VisibleSelectionTest, ShadowNested) {
EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor),
selection.Start());
- EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor), selection.End());
+ EXPECT_EQ(Position(one->firstChild(), 0), selection.End());
EXPECT_EQ(PositionInFlatTree(eight->firstChild(), 2),
selection_in_flat_tree.Start());
EXPECT_EQ(PositionInFlatTree(eight->firstChild(), 2),
@@ -662,19 +644,18 @@ TEST_F(VisibleSelectionTest, WordGranularity) {
TEST_F(VisibleSelectionTest, WordGranularityAfterTextControl) {
const PositionInFlatTree position =
ToPositionInFlatTree(SetCaretTextToBody("foo<input value=\"bla\">b|ar"));
- const VisibleSelectionInFlatTree selection =
- CreateVisibleSelectionWithGranularity(
- SelectionInFlatTree::Builder().Collapse(position).Build(),
- TextGranularity::kWord);
+ const SelectionInFlatTree selection = ExpandWithGranularity(
+ SelectionInFlatTree::Builder().Collapse(position).Build(),
+ TextGranularity::kWord);
EXPECT_EQ("foo<input value=\"bla\"><div>bla</div></input>^bar|",
- GetSelectionTextInFlatTreeFromBody(selection.AsSelection()));
+ GetSelectionTextInFlatTreeFromBody(selection));
}
// This is for crbug.com/627783, simulating restoring selection
// in undo stack.
TEST_F(VisibleSelectionTest, updateIfNeededWithShadowHost) {
SetBodyContent("<div id=host></div><div id=sample>foo</div>");
- SetShadowContent("<content>", "host");
+ SetShadowContent("<slot>", "host");
Element* sample = GetDocument().getElementById("sample");
// Simulates saving selection in undo stack.
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units.cc b/chromium/third_party/blink/renderer/core/editing/visible_units.cc
index cd10e3e03d6..d9b42aa1d7a 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units.cc
@@ -40,6 +40,8 @@
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/position_iterator.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/editing/selection_adjuster.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
@@ -75,7 +77,32 @@ static PositionType CanonicalizeCandidate(const PositionType& candidate) {
}
template <typename PositionType>
-static PositionType SnapFallbackTemplate(const PositionType& position) {
+static PositionType CanonicalPosition(const PositionType& position) {
+ // Sometimes updating selection positions can be extremely expensive and
+ // occur frequently. Often calling preventDefault on mousedown events can
+ // avoid doing unnecessary text selection work. http://crbug.com/472258.
+ TRACE_EVENT0("input", "VisibleUnits::canonicalPosition");
+
+ // FIXME (9535): Canonicalizing to the leftmost candidate means that if
+ // we're at a line wrap, we will ask layoutObjects to paint downstream
+ // carets for other layoutObjects. To fix this, we need to either a) add
+ // code to all paintCarets to pass the responsibility off to the appropriate
+ // layoutObject for VisiblePosition's like these, or b) canonicalize to the
+ // rightmost candidate unless the affinity is upstream.
+ if (position.IsNull())
+ return PositionType();
+
+ DCHECK(position.GetDocument());
+ DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
+
+ const PositionType& backward_candidate = MostBackwardCaretPosition(position);
+ if (IsVisuallyEquivalentCandidate(backward_candidate))
+ return backward_candidate;
+
+ const PositionType& forward_candidate = MostForwardCaretPosition(position);
+ if (IsVisuallyEquivalentCandidate(forward_candidate))
+ return forward_candidate;
+
// When neither upstream or downstream gets us to a candidate
// (upstream/downstream won't leave blocks or enter new ones), we search
// forward and backward until we find one.
@@ -128,93 +155,12 @@ static PositionType SnapFallbackTemplate(const PositionType& position) {
return next;
}
-template <typename Strategy>
-static PositionWithAffinityTemplate<Strategy> SnapBackwardTemplate(
- const PositionTemplate<Strategy>& position) {
- // Sometimes updating selection positions can be extremely expensive and
- // occur frequently. Often calling preventDefault on mousedown events can
- // avoid doing unnecessary text selection work. http://crbug.com/472258.
- TRACE_EVENT0("input", "VisibleUnits::SnapBackward");
-
- if (position.IsNull())
- return PositionWithAffinityTemplate<Strategy>();
-
- DCHECK(position.GetDocument());
- DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
-
- const PositionTemplate<Strategy>& candidate1 =
- MostBackwardCaretPosition(position);
- if (IsVisuallyEquivalentCandidate(candidate1)) {
- return PositionWithAffinityTemplate<Strategy>(candidate1,
- TextAffinity::kUpstream);
- }
-
- const PositionTemplate<Strategy>& candidate2 =
- MostForwardCaretPosition(position);
- if (IsVisuallyEquivalentCandidate(candidate2)) {
- return PositionWithAffinityTemplate<Strategy>(candidate2,
- TextAffinity::kDownstream);
- }
-
- return PositionWithAffinityTemplate<Strategy>(SnapFallbackTemplate(position),
- TextAffinity::kDownstream);
-}
-
-PositionWithAffinity SnapBackward(const Position& position) {
- return SnapBackwardTemplate(position);
-}
-
-PositionInFlatTreeWithAffinity SnapBackward(
- const PositionInFlatTree& position) {
- return SnapBackwardTemplate(position);
-}
-
-template <typename Strategy>
-static PositionWithAffinityTemplate<Strategy> SnapForwardTemplate(
- const PositionTemplate<Strategy>& position) {
- // Sometimes updating selection positions can be extremely expensive and
- // occur frequently. Often calling preventDefault on mousedown events can
- // avoid doing unnecessary text selection work. http://crbug.com/472258.
- TRACE_EVENT0("input", "VisibleUnits::SnapForward");
-
- if (position.IsNull())
- return PositionWithAffinityTemplate<Strategy>();
-
- DCHECK(position.GetDocument());
- DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
-
- const PositionTemplate<Strategy>& candidate1 =
- MostForwardCaretPosition(position);
- if (IsVisuallyEquivalentCandidate(candidate1)) {
- return PositionWithAffinityTemplate<Strategy>(candidate1,
- TextAffinity::kDownstream);
- }
-
- const PositionTemplate<Strategy>& candidate2 =
- MostBackwardCaretPosition(position);
- if (IsVisuallyEquivalentCandidate(candidate2)) {
- return PositionWithAffinityTemplate<Strategy>(candidate2,
- TextAffinity::kDownstream);
- }
-
- return PositionWithAffinityTemplate<Strategy>(SnapFallbackTemplate(position),
- TextAffinity::kDownstream);
-}
-
-PositionWithAffinity SnapForward(const Position& position) {
- return SnapForwardTemplate(position);
-}
-
-PositionInFlatTreeWithAffinity SnapForward(const PositionInFlatTree& position) {
- return SnapForwardTemplate(position);
-}
-
Position CanonicalPositionOf(const Position& position) {
- return SnapBackward(position).GetPosition();
+ return CanonicalPosition(position);
}
PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree& position) {
- return SnapBackward(position).GetPosition();
+ return CanonicalPosition(position);
}
template <typename Strategy>
@@ -269,32 +215,6 @@ AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
}
template <typename Strategy>
-VisiblePositionTemplate<Strategy>
-AdjustBackwardPositionToAvoidCrossingEditingBoundariesAlgorithm(
- const VisiblePositionTemplate<Strategy>& pos,
- const PositionTemplate<Strategy>& anchor) {
- DCHECK(pos.IsValid()) << pos;
- return CreateVisiblePosition(
- AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
- pos.ToPositionWithAffinity(), anchor));
-}
-
-VisiblePosition AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePosition& visiblePosition,
- const Position& anchor) {
- return AdjustBackwardPositionToAvoidCrossingEditingBoundariesAlgorithm(
- visiblePosition, anchor);
-}
-
-VisiblePositionInFlatTree
-AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePositionInFlatTree& visiblePosition,
- const PositionInFlatTree& anchor) {
- return AdjustBackwardPositionToAvoidCrossingEditingBoundariesAlgorithm(
- visiblePosition, anchor);
-}
-
-template <typename Strategy>
static PositionWithAffinityTemplate<Strategy>
AdjustForwardPositionToAvoidCrossingEditingBoundariesTemplate(
const PositionWithAffinityTemplate<Strategy>& pos,
@@ -352,24 +272,6 @@ AdjustForwardPositionToAvoidCrossingEditingBoundaries(
PositionInFlatTreeWithAffinity(pos), anchor);
}
-VisiblePosition AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePosition& pos,
- const Position& anchor) {
- DCHECK(pos.IsValid()) << pos;
- return CreateVisiblePosition(
- AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- pos.ToPositionWithAffinity(), anchor));
-}
-
-VisiblePositionInFlatTree AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePositionInFlatTree& pos,
- const PositionInFlatTree& anchor) {
- DCHECK(pos.IsValid()) << pos;
- return CreateVisiblePosition(
- AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- pos.ToPositionWithAffinity(), anchor));
-}
-
template <typename Strategy>
static ContainerNode* NonShadowBoundaryParentNode(Node* node) {
ContainerNode* parent = Strategy::Parent(*node);
@@ -399,22 +301,21 @@ static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) {
// ---------
template <typename Strategy>
-static VisiblePositionTemplate<Strategy> StartOfDocumentAlgorithm(
- const VisiblePositionTemplate<Strategy>& visible_position) {
- DCHECK(visible_position.IsValid()) << visible_position;
- Node* node = visible_position.DeepEquivalent().AnchorNode();
+static PositionTemplate<Strategy> StartOfDocumentAlgorithm(
+ const PositionTemplate<Strategy>& position) {
+ const Node* const node = position.AnchorNode();
if (!node || !node->GetDocument().documentElement())
- return VisiblePositionTemplate<Strategy>();
+ return PositionTemplate<Strategy>();
- return CreateVisiblePosition(PositionTemplate<Strategy>::FirstPositionInNode(
- *node->GetDocument().documentElement()));
+ return PositionTemplate<Strategy>::FirstPositionInNode(
+ *node->GetDocument().documentElement());
}
-VisiblePosition StartOfDocument(const VisiblePosition& c) {
+Position StartOfDocument(const Position& c) {
return StartOfDocumentAlgorithm<EditingStrategy>(c);
}
-VisiblePositionInFlatTree StartOfDocument(const VisiblePositionInFlatTree& c) {
+PositionInFlatTree StartOfDocument(const PositionInFlatTree& c) {
return StartOfDocumentAlgorithm<EditingInFlatTreeStrategy>(c);
}
@@ -452,25 +353,20 @@ bool IsEndOfDocument(const VisiblePosition& p) {
// ---------
-VisiblePosition StartOfEditableContent(
- const VisiblePosition& visible_position) {
- DCHECK(visible_position.IsValid()) << visible_position;
- ContainerNode* highest_root =
- HighestEditableRoot(visible_position.DeepEquivalent());
+PositionInFlatTree StartOfEditableContent(const PositionInFlatTree& position) {
+ ContainerNode* highest_root = HighestEditableRoot(position);
if (!highest_root)
- return VisiblePosition();
+ return PositionInFlatTree();
- return VisiblePosition::FirstPositionInNode(*highest_root);
+ return PositionInFlatTree::FirstPositionInNode(*highest_root);
}
-VisiblePosition EndOfEditableContent(const VisiblePosition& visible_position) {
- DCHECK(visible_position.IsValid()) << visible_position;
- ContainerNode* highest_root =
- HighestEditableRoot(visible_position.DeepEquivalent());
+PositionInFlatTree EndOfEditableContent(const PositionInFlatTree& position) {
+ ContainerNode* highest_root = HighestEditableRoot(position);
if (!highest_root)
- return VisiblePosition();
+ return PositionInFlatTree();
- return VisiblePosition::LastPositionInNode(*highest_root);
+ return PositionInFlatTree::LastPositionInNode(*highest_root);
}
bool IsEndOfEditableOrNonEditableContent(const VisiblePosition& position) {
@@ -496,11 +392,6 @@ bool IsEndOfEditableOrNonEditableContent(
return IsTextControl(next_position.DeepEquivalent().AnchorNode());
}
-static LayoutUnit BoundingBoxLogicalHeight(LayoutObject* o,
- const LayoutRect& rect) {
- return o->Style()->IsHorizontalWritingMode() ? rect.Height() : rect.Width();
-}
-
// TODO(editing-dev): The semantics seems wrong when we're in a one-letter block
// with first-letter style, e.g., <div>F</div>, where the letter is laid-out in
// an anonymous first-letter LayoutTextFragment instead of the LayoutObject of
@@ -533,9 +424,7 @@ bool HasRenderedNonAnonymousDescendantsWithHeight(
(o->IsLayoutInline() && IsEmptyInline(LineLayoutItem(o)) &&
// TODO(crbug.com/771398): Find alternative ways to check whether an
// empty LayoutInline is rendered, without checking InlineBox.
- BoundingBoxLogicalHeight(
- o,
- To<LayoutInline>(o)->PhysicalLinesBoundingBox().ToLayoutRect())))
+ !To<LayoutInline>(o)->PhysicalLinesBoundingBox().IsEmpty()))
return true;
}
}
@@ -553,20 +442,21 @@ PositionWithAffinity PositionForContentsPointRespectingEditingBoundary(
HitTestResult result(request, location);
frame->GetDocument()->GetLayoutView()->HitTest(location, result);
- if (Node* node = result.InnerNode()) {
+ if (result.InnerNode()) {
return PositionRespectingEditingBoundary(
frame->Selection().ComputeVisibleSelectionInDOMTreeDeprecated().Start(),
- result.LocalPoint(), node);
+ result);
}
return PositionWithAffinity();
}
// TODO(yosin): We should use |AssociatedLayoutObjectOf()| in "visible_units.cc"
// where it takes |LayoutObject| from |Position|.
-
int CaretMinOffset(const Node* node) {
const LayoutObject* layout_object = AssociatedLayoutObjectOf(*node, 0);
- return layout_object ? layout_object->CaretMinOffset() : 0;
+ if (const LayoutText* layout_text = DynamicTo<LayoutText>(layout_object))
+ return layout_text->CaretMinOffset();
+ return 0;
}
int CaretMaxOffset(const Node* n) {
@@ -662,6 +552,58 @@ static bool IsStreamer(const PositionIteratorAlgorithm<Strategy>& pos) {
return pos.AtStartOfNode();
}
+template <typename F>
+static Position MostBackwardOrForwardCaretPosition(
+ const Position& position,
+ EditingBoundaryCrossingRule rule,
+ F AlgorithmInFlatTree) {
+ Node* position_anchor = position.AnchorNode();
+ if (!position_anchor)
+ return Position();
+ DCHECK(position.IsValidFor(*position.GetDocument()));
+
+ // Find the most backward or forward caret position in the flat tree.
+ const Position& candidate = ToPositionInDOMTree(
+ AlgorithmInFlatTree(ToPositionInFlatTree(position), rule));
+ Node* candidate_anchor = candidate.AnchorNode();
+ if (!candidate_anchor)
+ return position;
+
+ // Fast path for common cases when there is no shadow involved.
+ if (!position_anchor->IsInShadowTree() && !IsShadowHost(position_anchor) &&
+ !candidate_anchor->IsInShadowTree() && !IsShadowHost(candidate_anchor)) {
+ return candidate;
+ }
+
+ // Adjust the candidate to avoid crossing shadow boundaries.
+ const SelectionInDOMTree& selection =
+ SelectionInDOMTree::Builder()
+ .SetBaseAndExtent(position, candidate)
+ .Build();
+ if (selection.IsCaret())
+ return candidate;
+ const SelectionInDOMTree& shadow_adjusted_selection =
+ SelectionAdjuster::AdjustSelectionToAvoidCrossingShadowBoundaries(
+ selection);
+ const Position& adjusted_candidate = shadow_adjusted_selection.Extent();
+
+ // The adjusted candidate should be between the candidate and the original
+ // position. Otherwise, return the original position.
+ if (position.CompareTo(candidate) == candidate.CompareTo(adjusted_candidate))
+ return position;
+
+ // If we have to adjust the position, the editability may change, so avoid
+ // crossing editing boundaries if it's not allowed.
+ if (rule == kCannotCrossEditingBoundary &&
+ selection != shadow_adjusted_selection) {
+ const SelectionInDOMTree& editing_adjusted_selection =
+ SelectionAdjuster::AdjustSelectionToAvoidCrossingEditingBoundaries(
+ shadow_adjusted_selection);
+ return editing_adjusted_selection.Extent();
+ }
+ return adjusted_candidate;
+}
+
template <typename Strategy>
static PositionTemplate<Strategy> AdjustPositionForBackwardIteration(
const PositionTemplate<Strategy>& position) {
@@ -674,6 +616,14 @@ static PositionTemplate<Strategy> AdjustPositionForBackwardIteration(
position.AnchorNode(), Strategy::CaretMaxOffset(*position.AnchorNode()));
}
+// TODO(yosin): We should make |Most{Back,For}kwardCaretPosition()| to work for
+// positions other than |kOffsetInAnchor|. When we convert |position| to
+// |kOffsetInAnchor|, following tests are failed:
+// * editing/execCommand/delete-non-editable-range-crash.html
+// * editing/execCommand/keep_typing_style.html
+// * editing/selection/skip-over-contenteditable.html
+// See also |AdjustForEditingBoundary()|. It has workaround for before/after
+// positions.
template <typename Strategy>
static PositionTemplate<Strategy> MostBackwardCaretPosition(
const PositionTemplate<Strategy>& position,
@@ -771,7 +721,8 @@ static PositionTemplate<Strategy> MostBackwardCaretPosition(
// Until we resolve that, disable this so we can run the web tests!
// DCHECK_GE(currentOffset, layoutObject->caretMaxOffset());
return PositionTemplate<Strategy>(
- current_node, layout_object->CaretMaxOffset() + text_start_offset);
+ current_node,
+ text_layout_object->CaretMaxOffset() + text_start_offset);
}
DCHECK_GE(current_pos.OffsetInLeafNode(),
@@ -786,7 +737,8 @@ static PositionTemplate<Strategy> MostBackwardCaretPosition(
Position MostBackwardCaretPosition(const Position& position,
EditingBoundaryCrossingRule rule) {
- return MostBackwardCaretPosition<EditingStrategy>(position, rule);
+ return MostBackwardOrForwardCaretPosition(
+ position, rule, MostBackwardCaretPosition<EditingInFlatTreeStrategy>);
}
PositionInFlatTree MostBackwardCaretPosition(const PositionInFlatTree& position,
@@ -892,9 +844,8 @@ PositionTemplate<Strategy> MostForwardCaretPosition(
// ignored.
if (EditingIgnoresContent(*current_node) ||
IsDisplayInsideTable(current_node)) {
- if (current_pos.OffsetInLeafNode() <= layout_object->CaretMinOffset())
- return PositionTemplate<Strategy>::EditingPositionOf(
- current_node, layout_object->CaretMinOffset());
+ if (current_pos.OffsetInLeafNode() <= 0)
+ return PositionTemplate<Strategy>::EditingPositionOf(current_node, 0);
continue;
}
@@ -909,7 +860,8 @@ PositionTemplate<Strategy> MostForwardCaretPosition(
DCHECK(current_pos.AtStartOfNode() ||
HasInvisibleFirstLetter(current_node));
return PositionTemplate<Strategy>(
- current_node, layout_object->CaretMinOffset() + text_start_offset);
+ current_node,
+ text_layout_object->CaretMinOffset() + text_start_offset);
}
DCHECK_GE(current_pos.OffsetInLeafNode(),
@@ -924,7 +876,8 @@ PositionTemplate<Strategy> MostForwardCaretPosition(
Position MostForwardCaretPosition(const Position& position,
EditingBoundaryCrossingRule rule) {
- return MostForwardCaretPosition<EditingStrategy>(position, rule);
+ return MostBackwardOrForwardCaretPosition(
+ position, rule, MostForwardCaretPosition<EditingInFlatTreeStrategy>);
}
PositionInFlatTree MostForwardCaretPosition(const PositionInFlatTree& position,
@@ -1020,7 +973,7 @@ static bool IsVisuallyEquivalentCandidateAlgorithm(
if (layout_object->IsLayoutBlockFlow() ||
layout_object->IsFlexibleBoxIncludingNG() ||
- layout_object->IsLayoutGrid()) {
+ layout_object->IsLayoutGridIncludingNG()) {
if (To<LayoutBlock>(layout_object)->LogicalHeight() ||
anchor_node->GetDocument().body() == anchor_node) {
if (!HasRenderedNonAnonymousDescendantsWithHeight(layout_object))
@@ -1128,15 +1081,15 @@ static VisiblePositionTemplate<Strategy> NextPositionOfAlgorithm(
case kCanCrossEditingBoundary:
return next;
case kCannotCrossEditingBoundary:
- return AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- next, position.GetPosition());
+ return CreateVisiblePosition(
+ AdjustForwardPositionToAvoidCrossingEditingBoundaries(
+ next.ToPositionWithAffinity(), position.GetPosition()));
case kCanSkipOverEditingBoundary:
return CreateVisiblePosition(SkipToEndOfEditingBoundary(
next.DeepEquivalent(), position.GetPosition()));
}
NOTREACHED();
- return AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- next, position.GetPosition());
+ return next;
}
VisiblePosition NextPositionOf(const VisiblePosition& visible_position,
@@ -1207,15 +1160,16 @@ static VisiblePositionTemplate<Strategy> PreviousPositionOfAlgorithm(
case kCanCrossEditingBoundary:
return prev;
case kCannotCrossEditingBoundary:
- return AdjustBackwardPositionToAvoidCrossingEditingBoundaries(prev,
- position);
+ return CreateVisiblePosition(
+ AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
+ prev.ToPositionWithAffinity(), position));
case kCanSkipOverEditingBoundary:
return CreateVisiblePosition(
SkipToStartOfEditingBoundary(prev.DeepEquivalent(), position));
}
NOTREACHED();
- return AdjustBackwardPositionToAvoidCrossingEditingBoundaries(prev, position);
+ return prev;
}
VisiblePosition PreviousPositionOf(const VisiblePosition& visible_position,
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units.h b/chromium/third_party/blink/renderer/core/editing/visible_units.h
index 16fa1fb5a7b..7a142bb3e4c 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units.h
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units.h
@@ -92,12 +92,6 @@ CORE_EXPORT bool IsVisuallyEquivalentCandidate(const PositionInFlatTree&);
// If true, adjacent candidates are visually distinct.
CORE_EXPORT bool EndsOfNodeAreVisuallyDistinctPositions(const Node*);
-CORE_EXPORT PositionWithAffinity SnapBackward(const Position&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-SnapBackward(const PositionInFlatTree&);
-CORE_EXPORT PositionWithAffinity SnapForward(const Position&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-SnapForward(const PositionInFlatTree&);
CORE_EXPORT Position CanonicalPositionOf(const Position&);
CORE_EXPORT PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree&);
@@ -125,34 +119,32 @@ CORE_EXPORT Position StartOfWordPosition(const Position&,
CORE_EXPORT PositionInFlatTree
StartOfWordPosition(const PositionInFlatTree&,
WordSide = kNextWordIfOnBoundary);
-CORE_EXPORT VisiblePosition EndOfWord(const VisiblePosition&,
- WordSide = kNextWordIfOnBoundary);
CORE_EXPORT Position EndOfWordPosition(const Position&,
WordSide = kNextWordIfOnBoundary);
CORE_EXPORT PositionInFlatTree
EndOfWordPosition(const PositionInFlatTree&, WordSide = kNextWordIfOnBoundary);
-CORE_EXPORT VisiblePositionInFlatTree
-EndOfWord(const VisiblePositionInFlatTree&, WordSide = kNextWordIfOnBoundary);
CORE_EXPORT PositionWithAffinity PreviousWordPosition(const Position&);
+CORE_EXPORT PositionInFlatTreeWithAffinity
+PreviousWordPosition(const PositionInFlatTree&);
CORE_EXPORT PositionWithAffinity NextWordPosition(
const Position&,
PlatformWordBehavior = PlatformWordBehavior::kWordDontSkipSpaces);
+CORE_EXPORT PositionInFlatTreeWithAffinity NextWordPosition(
+ const PositionInFlatTree&,
+ PlatformWordBehavior = PlatformWordBehavior::kWordDontSkipSpaces);
// sentences
CORE_EXPORT Position StartOfSentencePosition(const Position&);
CORE_EXPORT PositionInFlatTree
StartOfSentencePosition(const PositionInFlatTree&);
-CORE_EXPORT VisiblePosition StartOfSentence(const VisiblePosition&);
-CORE_EXPORT VisiblePositionInFlatTree
-StartOfSentence(const VisiblePositionInFlatTree&);
CORE_EXPORT PositionWithAffinity EndOfSentence(const Position&);
CORE_EXPORT PositionInFlatTreeWithAffinity
EndOfSentence(const PositionInFlatTree&);
CORE_EXPORT VisiblePosition EndOfSentence(const VisiblePosition&);
CORE_EXPORT VisiblePositionInFlatTree
EndOfSentence(const VisiblePositionInFlatTree&);
-VisiblePosition PreviousSentencePosition(const VisiblePosition&);
-VisiblePosition NextSentencePosition(const VisiblePosition&);
+PositionInFlatTree PreviousSentencePosition(const PositionInFlatTree&);
+PositionInFlatTree NextSentencePosition(const PositionInFlatTree&);
EphemeralRange ExpandEndToSentenceBoundary(const EphemeralRange&);
EphemeralRange ExpandRangeToSentenceBoundary(const EphemeralRange&);
@@ -165,11 +157,6 @@ StartOfLine(const VisiblePositionInFlatTree&);
CORE_EXPORT PositionWithAffinity StartOfLine(const PositionWithAffinity&);
CORE_EXPORT PositionInFlatTreeWithAffinity
StartOfLine(const PositionInFlatTreeWithAffinity&);
-// TODO(yosin) Return values of |VisiblePosition| version of |endOfLine()| with
-// shadow tree isn't defined well. We should not use it for shadow tree.
-CORE_EXPORT VisiblePosition EndOfLine(const VisiblePosition&);
-CORE_EXPORT VisiblePositionInFlatTree
-EndOfLine(const VisiblePositionInFlatTree&);
CORE_EXPORT PositionWithAffinity EndOfLine(const PositionWithAffinity&);
CORE_EXPORT PositionInFlatTreeWithAffinity
EndOfLine(const PositionInFlatTreeWithAffinity&);
@@ -230,9 +217,8 @@ bool InSameParagraph(const VisiblePosition&,
EphemeralRange ExpandToParagraphBoundary(const EphemeralRange&);
// document
-CORE_EXPORT VisiblePosition StartOfDocument(const VisiblePosition&);
-CORE_EXPORT VisiblePositionInFlatTree
-StartOfDocument(const VisiblePositionInFlatTree&);
+CORE_EXPORT Position StartOfDocument(const Position&);
+CORE_EXPORT PositionInFlatTree StartOfDocument(const PositionInFlatTree&);
CORE_EXPORT VisiblePosition EndOfDocument(const VisiblePosition&);
CORE_EXPORT VisiblePositionInFlatTree
EndOfDocument(const VisiblePositionInFlatTree&);
@@ -240,8 +226,8 @@ bool IsStartOfDocument(const VisiblePosition&);
bool IsEndOfDocument(const VisiblePosition&);
// editable content
-VisiblePosition StartOfEditableContent(const VisiblePosition&);
-VisiblePosition EndOfEditableContent(const VisiblePosition&);
+PositionInFlatTree StartOfEditableContent(const PositionInFlatTree&);
+PositionInFlatTree EndOfEditableContent(const PositionInFlatTree&);
CORE_EXPORT bool IsEndOfEditableOrNonEditableContent(const VisiblePosition&);
CORE_EXPORT bool IsEndOfEditableOrNonEditableContent(
const VisiblePositionInFlatTree&);
@@ -285,24 +271,6 @@ AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
const PositionInFlatTreeWithAffinity&,
const PositionInFlatTree&);
-VisiblePosition AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePosition&,
- const Position&);
-
-VisiblePositionInFlatTree AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePositionInFlatTree&,
- const PositionInFlatTree&);
-
-// Export below functions only for |SelectionModifier|.
-VisiblePosition AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePosition&,
- const Position&);
-
-VisiblePositionInFlatTree
-AdjustBackwardPositionToAvoidCrossingEditingBoundaries(
- const VisiblePositionInFlatTree&,
- const PositionInFlatTree&);
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_VISIBLE_UNITS_H_
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
index bfe74dab2f6..09b6ac5e96b 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_line.cc
@@ -46,18 +46,13 @@ namespace {
struct VisualOrdering;
-// See also InlineBidiResolver::NeedsTrailingSpace()
-bool NeedsTrailingSpace(const ComputedStyle& style) {
- return style.BreakOnlyAfterWhiteSpace() && style.AutoWrap();
-}
-
static PositionWithAffinity AdjustForSoftLineWrap(
const NGInlineCursorPosition& line_box,
const PositionWithAffinity& position) {
DCHECK(line_box.IsLineBox());
if (position.IsNull())
return PositionWithAffinity();
- if (!NeedsTrailingSpace(line_box.Style()) ||
+ if (!line_box.Style().NeedsTrailingSpace() ||
!line_box.HasSoftWrapToNextLine())
return position;
// Returns a position after first space causing soft line wrap for editable.
@@ -76,7 +71,6 @@ static PositionWithAffinity AdjustForSoftLineWrap(
const Position adjusted_position = mapping->GetFirstPosition(*offset + 1);
if (adjusted_position.IsNull())
return position;
- DCHECK(IsA<Text>(adjusted_position.AnchorNode())) << adjusted_position;
if (!IsA<Text>(adjusted_position.AnchorNode()))
return position;
if (!adjusted_position.AnchorNode()
@@ -84,6 +78,8 @@ static PositionWithAffinity AdjustForSoftLineWrap(
->StyleRef()
.IsCollapsibleWhiteSpace(mapping->GetText()[*offset]))
return position;
+ // See |TryResolveCaretPositionInTextFragment()| to locate upstream position
+ // of caret after soft line wrap space.
return PositionWithAffinity(adjusted_position,
TextAffinity::kUpstreamIfPossible);
}
@@ -291,8 +287,11 @@ struct VisualOrdering {
const PositionWithAffinityTemplate<Strategy> candidate_position =
PositionWithAffinityTemplate<Strategy>(
candidate, TextAffinity::kUpstreamIfPossible);
- if (InSameLine(current_position, candidate_position))
- return candidate_position;
+ if (InSameLine(current_position, candidate_position)) {
+ return PositionWithAffinityTemplate<Strategy>(
+ CreateVisiblePosition(candidate).DeepEquivalent(),
+ TextAffinity::kUpstreamIfPossible);
+ }
const PositionWithAffinityTemplate<Strategy>& adjusted_position =
PreviousPositionOf(CreateVisiblePosition(current_position))
.ToPositionWithAffinity();
@@ -403,20 +402,6 @@ PositionInFlatTreeWithAffinity EndOfLine(
return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(position);
}
-// TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
-VisiblePosition EndOfLine(const VisiblePosition& current_position) {
- DCHECK(current_position.IsValid()) << current_position;
- return CreateVisiblePosition(
- EndOfLine(current_position.ToPositionWithAffinity()));
-}
-
-VisiblePositionInFlatTree EndOfLine(
- const VisiblePositionInFlatTree& current_position) {
- DCHECK(current_position.IsValid()) << current_position;
- return CreateVisiblePosition(
- EndOfLine(current_position.ToPositionWithAffinity()));
-}
-
template <typename Strategy>
static bool InSameLogicalLine(
const PositionWithAffinityTemplate<Strategy>& position1,
@@ -550,9 +535,14 @@ bool IsStartOfLine(const VisiblePositionInFlatTree& p) {
}
template <typename Strategy>
-static bool IsEndOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
- DCHECK(p.IsValid()) << p;
- return p.IsNotNull() && p.DeepEquivalent() == EndOfLine(p).DeepEquivalent();
+static bool IsEndOfLineAlgorithm(
+ const VisiblePositionTemplate<Strategy>& visible_position) {
+ DCHECK(visible_position.IsValid()) << visible_position;
+ if (visible_position.IsNull())
+ return false;
+ const auto& end_of_line =
+ EndOfLine(visible_position.ToPositionWithAffinity());
+ return visible_position.DeepEquivalent() == end_of_line.GetPosition();
}
bool IsEndOfLine(const VisiblePosition& p) {
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_line_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_line_test.cc
index c60ba7f1190..b99836835e4 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_line_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_line_test.cc
@@ -16,6 +16,15 @@
namespace blink {
+static VisiblePosition EndOfLine(const VisiblePosition& position) {
+ return CreateVisiblePosition(EndOfLine(position.ToPositionWithAffinity()));
+}
+
+static VisiblePositionInFlatTree EndOfLine(
+ const VisiblePositionInFlatTree& position) {
+ return CreateVisiblePosition(EndOfLine(position.ToPositionWithAffinity()));
+}
+
class VisibleUnitsLineTest : public EditingTestBase {
protected:
static PositionWithAffinity PositionWithAffinityInDOMTree(
@@ -97,11 +106,12 @@ TEST_F(VisibleUnitsLineTest, endOfLine) {
// 117777777
// 3334444
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -113,6 +123,7 @@ TEST_F(VisibleUnitsLineTest, endOfLine) {
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
+ Node* br = shadow_root->QuerySelector("br");
EXPECT_EQ(
Position(seven, 7),
@@ -129,7 +140,14 @@ TEST_F(VisibleUnitsLineTest, endOfLine) {
EndOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
- Position(seven, 7),
+ // The result on legacy layout is broken and not worth fixing.
+ LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
+ EndOfLine(
+ CreateVisiblePositionInDOMTree(*two, 0, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ EXPECT_EQ(
+ // The result on legacy layout is broken and not worth fixing.
+ LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
EndOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
@@ -137,15 +155,18 @@ TEST_F(VisibleUnitsLineTest, endOfLine) {
EXPECT_EQ(
// The result on legacy layout is broken and not worth fixing.
- LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
EndOfLine(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfLine(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(four, 4),
+ EndOfLine(CreateVisiblePositionInDOMTree(*three, 0,
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(
- // The result on legacy layout is broken and not worth fixing.
- LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ Position(four, 4),
EndOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
@@ -160,7 +181,7 @@ TEST_F(VisibleUnitsLineTest, endOfLine) {
EXPECT_EQ(
// The result on legacy layout is broken and not worth fixing.
- LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
EndOfLine(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
@@ -188,11 +209,12 @@ TEST_F(VisibleUnitsLineTest, isEndOfLine) {
// 117777777
// 3334444
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -211,6 +233,8 @@ TEST_F(VisibleUnitsLineTest, isEndOfLine) {
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
+ EXPECT_TRUE(IsEndOfLine(
+ CreateVisiblePositionInFlatTree(*two, 2, TextAffinity::kUpstream)));
// The result on legacy layout is broken and not worth fixing.
if (LayoutNGEnabled())
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
@@ -224,11 +248,7 @@ TEST_F(VisibleUnitsLineTest, isEndOfLine) {
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*four, 4)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*four, 4)));
- // The result on legacy layout is broken and not worth fixing.
- if (LayoutNGEnabled())
- EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
- else
- EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
+ EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*six, 6)));
@@ -245,11 +265,12 @@ TEST_F(VisibleUnitsLineTest, isLogicalEndOfLine) {
// 117777777
// 3334444
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -269,10 +290,15 @@ TEST_F(VisibleUnitsLineTest, isLogicalEndOfLine) {
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
// The result in legacy layout is broken and not worth fixing.
- if (LayoutNGEnabled())
+ if (LayoutNGEnabled()) {
+ EXPECT_TRUE(IsLogicalEndOfLine(
+ CreateVisiblePositionInDOMTree(*two, 2, TextAffinity::kUpstream)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
- else
+ } else {
+ EXPECT_FALSE(IsLogicalEndOfLine(
+ CreateVisiblePositionInDOMTree(*two, 2, TextAffinity::kUpstream)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
+ }
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 3)));
@@ -281,11 +307,7 @@ TEST_F(VisibleUnitsLineTest, isLogicalEndOfLine) {
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*four, 4)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*four, 4)));
- // The result in legacy layout is broken and not worth fixing.
- if (LayoutNGEnabled())
- EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
- else
- EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
+ EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*six, 6)));
@@ -297,10 +319,11 @@ TEST_F(VisibleUnitsLineTest, isLogicalEndOfLine) {
TEST_P(ParameterizedVisibleUnitsLineTest, inSameLine) {
const char* body_content =
- "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
+ "<p id='host'>00<b slot='#one' id='one'>11</b><b slot='#two' "
+ "id='two'>22</b>33</p>";
const char* shadow_content =
- "<div><span id='s4'>44</span><content select=#two></content><br><span "
- "id='s5'>55</span><br><content select=#one></content><span "
+ "<div><span id='s4'>44</span><slot name='#two'></slot><br><span "
+ "id='s5'>55</span><br><slot name='#one'></slot><span "
"id='s6'>66</span></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -311,26 +334,37 @@ TEST_P(ParameterizedVisibleUnitsLineTest, inSameLine) {
Element* four = shadow_root->QuerySelector("#s4");
Element* five = shadow_root->QuerySelector("#s5");
- EXPECT_TRUE(InSameLine(PositionWithAffinityInDOMTree(*one, 0),
- PositionWithAffinityInDOMTree(*two, 0)));
- EXPECT_TRUE(InSameLine(PositionWithAffinityInDOMTree(*one->firstChild(), 0),
- PositionWithAffinityInDOMTree(*two->firstChild(), 0)));
+ EXPECT_FALSE(InSameLine(PositionWithAffinityInDOMTree(*one, 0),
+ PositionWithAffinityInDOMTree(*two, 0)));
EXPECT_FALSE(
InSameLine(PositionWithAffinityInDOMTree(*one->firstChild(), 0),
- PositionWithAffinityInDOMTree(*five->firstChild(), 0)));
+ PositionWithAffinityInDOMTree(*two->firstChild(), 0)));
EXPECT_FALSE(
+ InSameLine(PositionWithAffinityInDOMTree(*one->firstChild(), 0),
+ PositionWithAffinityInDOMTree(*five->firstChild(), 0)));
+ EXPECT_TRUE(
InSameLine(PositionWithAffinityInDOMTree(*two->firstChild(), 0),
PositionWithAffinityInDOMTree(*four->firstChild(), 0)));
- EXPECT_TRUE(InSameLine(CreateVisiblePositionInDOMTree(*one, 0),
- CreateVisiblePositionInDOMTree(*two, 0)));
- EXPECT_TRUE(
+ EXPECT_FALSE(InSameLine(
+ CreateVisiblePositionInDOMTree(*one, 0),
+ CreateVisiblePositionInDOMTree(*two, 0, TextAffinity::kUpstream)));
+ EXPECT_FALSE(InSameLine(CreateVisiblePositionInDOMTree(*one, 0),
+ CreateVisiblePositionInDOMTree(*two, 0)));
+ EXPECT_FALSE(InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
+ CreateVisiblePositionInDOMTree(
+ *two->firstChild(), 0, TextAffinity::kUpstream)));
+ EXPECT_FALSE(
InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
CreateVisiblePositionInDOMTree(*two->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
CreateVisiblePositionInDOMTree(*five->firstChild(), 0)));
- EXPECT_FALSE(
+ EXPECT_TRUE(
+ InSameLine(CreateVisiblePositionInDOMTree(*two->firstChild(), 0,
+ TextAffinity::kUpstream),
+ CreateVisiblePositionInDOMTree(*four->firstChild(), 0)));
+ EXPECT_TRUE(
InSameLine(CreateVisiblePositionInDOMTree(*two->firstChild(), 0),
CreateVisiblePositionInDOMTree(*four->firstChild(), 0)));
@@ -361,11 +395,12 @@ TEST_P(ParameterizedVisibleUnitsLineTest, inSameLine) {
TEST_F(VisibleUnitsLineTest, isStartOfLine) {
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -387,7 +422,9 @@ TEST_F(VisibleUnitsLineTest, isStartOfLine) {
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*two, 0)));
- EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*three, 0)));
+ EXPECT_TRUE(IsStartOfLine(
+ CreateVisiblePositionInDOMTree(*three, 0, TextAffinity::kUpstream)));
+ EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInDOMTree(*three, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*three, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*four, 0)));
@@ -410,11 +447,12 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
// 117777777
// 3334444
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -426,6 +464,7 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
+ Node* br = shadow_root->QuerySelector("br");
EXPECT_EQ(Position(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*one, 0))
@@ -441,7 +480,13 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
- EXPECT_EQ(Position(seven, 7),
+ // The result on legacy layout is broken and not worth fixing.
+ EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
+ LogicalEndOfLine(CreateVisiblePositionInDOMTree(
+ *two, 0, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ // The result on legacy layout is broken and not worth fixing.
+ EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
@@ -449,16 +494,18 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
.DeepEquivalent());
// The result on legacy layout is broken and not worth fixing.
- EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
- // DOM VisiblePosition canonicalization moves input position to (two, 2),
- // which yields wrong results in both legacy layout and LayoutNG.
- EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ EXPECT_EQ(Position(four, 4),
+ LogicalEndOfLine(CreateVisiblePositionInDOMTree(
+ *three, 0, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ EXPECT_EQ(Position(four, 4),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four, 4),
@@ -473,7 +520,7 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
.DeepEquivalent());
// The result on legacy layout is broken and not worth fixing.
- EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+ EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position::BeforeNode(*br),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
@@ -497,11 +544,12 @@ TEST_F(VisibleUnitsLineTest, logicalEndOfLine) {
TEST_F(VisibleUnitsLineTest, logicalStartOfLine) {
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -528,7 +576,11 @@ TEST_F(VisibleUnitsLineTest, logicalStartOfLine) {
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
- EXPECT_EQ(Position(one, 0),
+ EXPECT_EQ(Position(five, 0),
+ LogicalStartOfLine(CreateVisiblePositionInDOMTree(
+ *two, 0, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ EXPECT_EQ(Position(five, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five, 0),
@@ -542,16 +594,22 @@ TEST_F(VisibleUnitsLineTest, logicalStartOfLine) {
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
- EXPECT_EQ(Position(five, 0),
+ EXPECT_EQ(Position(three, 0),
+ LogicalStartOfLine(CreateVisiblePositionInDOMTree(
+ *three, 0, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*three, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*three, 1))
.DeepEquivalent());
- // TODO(yosin) logicalStartOfLine(four, 1) -> (two, 2) is a broken result.
- // We keep it as a marker for future change.
- EXPECT_EQ(Position(two, 2),
+ EXPECT_EQ(Position(three, 0),
+ LogicalStartOfLine(CreateVisiblePositionInDOMTree(
+ *four, 1, TextAffinity::kUpstream))
+ .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
@@ -587,11 +645,12 @@ TEST_F(VisibleUnitsLineTest, startOfLine) {
// 117777777
// 3334444
const char* body_content =
- "<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
+ "<span id=host><b slot='#one' id=one>11</b><b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
- "<div><u id=five>55555</u><content select=#two></content><br><u "
- "id=six>666666</u><br><content select=#one></content><u "
+ "<div><u id=five>55555</u><slot name='#two'></slot><br><u "
+ "id=six>666666</u><br><slot name='#one'></slot><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -618,8 +677,12 @@ TEST_F(VisibleUnitsLineTest, startOfLine) {
PositionInFlatTree(one, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(five, 0),
+ StartOfLine(CreateVisiblePositionInDOMTree(*two, 0,
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(
- Position(one, 0),
+ Position(five, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 0),
@@ -632,17 +695,23 @@ TEST_F(VisibleUnitsLineTest, startOfLine) {
PositionInFlatTree(five, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(three, 0),
+ StartOfLine(CreateVisiblePositionInDOMTree(*three, 0,
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(
- Position(five, 0),
+ Position(three, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(three, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
- // TODO(yosin) startOfLine(four, 1) -> (two, 2) is a broken result. We keep
- // it as a marker for future change.
+ EXPECT_EQ(Position(three, 0),
+ StartOfLine(CreateVisiblePositionInDOMTree(*four, 1,
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(
- Position(two, 2),
+ Position(three, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(three, 0),
@@ -828,6 +897,29 @@ TEST_P(ParameterizedVisibleUnitsLineTest, EndOfLineWithSoftLineWrap4) {
TestEndOfLine("<div contenteditable>abc |def ghi</div>"));
}
+// http://crbug.com/1169583
+TEST_P(ParameterizedVisibleUnitsLineTest, EndOfLineWithWhiteSpacePre) {
+ LoadAhem();
+ InsertStyleElement("p { font: 10px/1 Ahem; white-space: pre; }");
+
+ EXPECT_EQ("<p dir=\"ltr\"><bdo dir=\"ltr\">ABC DEF|\nGHI JKL</bdo></p>",
+ TestEndOfLine(
+ "<p dir=\"ltr\"><bdo dir=\"ltr\">ABC| DEF\nGHI JKL</bdo></p>"))
+ << "LTR LTR";
+ EXPECT_EQ("<p dir=\"ltr\"><bdo dir=\"rtl\">ABC DEF|\nGHI JKL</bdo></p>",
+ TestEndOfLine(
+ "<p dir=\"ltr\"><bdo dir=\"rtl\">ABC| DEF\nGHI JKL</bdo></p>"))
+ << "LTR RTL";
+ EXPECT_EQ("<p dir=\"rtl\"><bdo dir=\"ltr\">ABC DEF|\nGHI JKL</bdo></p>",
+ TestEndOfLine(
+ "<p dir=\"rtl\"><bdo dir=\"ltr\">ABC| DEF\nGHI JKL</bdo></p>"))
+ << "RTL LTR";
+ EXPECT_EQ("<p dir=\"rtl\"><bdo dir=\"rtl\">ABC DEF|\nGHI JKL</bdo></p>",
+ TestEndOfLine(
+ "<p dir=\"rtl\"><bdo dir=\"rtl\">ABC| DEF\nGHI JKL</bdo></p>"))
+ << "RTL RTL";
+}
+
TEST_P(ParameterizedVisibleUnitsLineTest, LogicalEndOfLineWithSoftLineWrap3) {
LoadAhem();
InsertStyleElement(
@@ -917,6 +1009,75 @@ TEST_P(ParameterizedVisibleUnitsLineTest, InSameLineWithMixedEditability) {
EXPECT_FALSE(InSameLine(position1, position2));
}
+TEST_P(ParameterizedVisibleUnitsLineTest,
+ InSameLineWithGeneratedZeroWidthSpace) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 4ch; white-space: pre-wrap;");
+ // We have ZWS before "abc" due by "pre-wrap".
+ const Position& after_zws = SetCaretTextToBody("<p id=t> |abcd</p>");
+ const PositionWithAffinity after_zws_down =
+ PositionWithAffinity(after_zws, TextAffinity::kDownstream);
+ const PositionWithAffinity after_zws_up =
+ PositionWithAffinity(after_zws, TextAffinity::kUpstream);
+
+ EXPECT_EQ(
+ PositionWithAffinity(Position(*GetElementById("t")->firstChild(), 8),
+ TextAffinity::kUpstream),
+ EndOfLine(after_zws_down));
+ EXPECT_EQ(after_zws_up, EndOfLine(after_zws_up));
+ EXPECT_FALSE(InSameLine(after_zws_up, after_zws_down));
+}
+
+// http://crbug.com/1183269
+TEST_P(ParameterizedVisibleUnitsLineTest, InSameLineWithSoftLineWrap) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 3ch; }");
+ // Note: "contenteditable" adds
+ // line-break: after-white-space;
+ // overflow-wrap: break-word;
+ const SelectionInDOMTree& selection =
+ SetSelectionTextToBody("<p contenteditable id=t>abc |xyz</p>");
+ EXPECT_FALSE(InSameLine(
+ PositionWithAffinity(selection.Base(), TextAffinity::kUpstream),
+ PositionWithAffinity(selection.Base(), TextAffinity::kDownstream)));
+}
+
+TEST_P(ParameterizedVisibleUnitsLineTest, InSameLineWithZeroWidthSpace) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 4ch; }");
+ const SelectionInDOMTree& selection =
+ SetSelectionTextToBody(u8"<p id=t>abcd^\u200B|wxyz</p>");
+
+ const Position& after_zws = selection.Extent();
+ const PositionWithAffinity after_zws_down =
+ PositionWithAffinity(after_zws, TextAffinity::kDownstream);
+ const PositionWithAffinity after_zws_up =
+ PositionWithAffinity(after_zws, TextAffinity::kUpstream);
+
+ const Position& before_zws = selection.Base();
+ const PositionWithAffinity before_zws_down =
+ PositionWithAffinity(before_zws, TextAffinity::kDownstream);
+ const PositionWithAffinity before_zws_up =
+ PositionWithAffinity(before_zws, TextAffinity::kUpstream);
+
+ EXPECT_EQ(
+ PositionWithAffinity(Position(*GetElementById("t")->firstChild(), 9),
+ TextAffinity::kUpstream),
+ EndOfLine(after_zws_down));
+ EXPECT_EQ(after_zws_up, EndOfLine(after_zws_up));
+ EXPECT_FALSE(InSameLine(after_zws_up, after_zws_down));
+
+ EXPECT_EQ(after_zws_up, EndOfLine(before_zws_down));
+ EXPECT_EQ(after_zws_up, EndOfLine(before_zws_up));
+ EXPECT_TRUE(InSameLine(before_zws_up, before_zws_down));
+}
+
TEST_P(ParameterizedVisibleUnitsLineTest, StartOfLineWithBidi) {
LoadAhem();
InsertStyleElement("p { font: 30px/3 Ahem; }");
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
index e78ec75a89e..12b10d4b157 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
@@ -67,6 +67,31 @@ PositionTemplate<Strategy> StartOfParagraphAlgorithm(
int candidate_offset = position.ComputeEditingOffset();
Node* previous_node_iterator = start_node;
+ auto previousNodeSkippingChildren = [&]() -> Node* {
+ // Like Strategy::PreviousPostOrder(*previous_node_iterator, start_block),
+ // but skipping children.
+ for (const Node* parent = previous_node_iterator; parent;
+ parent = Strategy::Parent(*parent)) {
+ if (parent == start_block)
+ return nullptr;
+ if (Node* previous_sibling = Strategy::PreviousSibling(*parent))
+ return previous_sibling;
+ }
+ return nullptr;
+ };
+ auto previousNode = [&]() -> Node* {
+ DCHECK(previous_node_iterator);
+ if (previous_node_iterator == start_node) {
+ // For the first iteration, take the anchor type and offset into account.
+ Node* before_position = position.ComputeNodeBeforePosition();
+ if (!before_position)
+ return previousNodeSkippingChildren();
+ if (before_position != previous_node_iterator)
+ return before_position;
+ }
+ return Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ };
+
while (previous_node_iterator) {
if (boundary_crossing_rule == kCannotCrossEditingBoundary &&
!NodeIsUserSelectAll(previous_node_iterator) &&
@@ -76,8 +101,7 @@ PositionTemplate<Strategy> StartOfParagraphAlgorithm(
while (previous_node_iterator &&
HasEditableStyle(*previous_node_iterator) !=
start_node_is_editable) {
- previous_node_iterator =
- Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ previous_node_iterator = previousNode();
}
if (!previous_node_iterator ||
!previous_node_iterator->IsDescendantOf(highest_root))
@@ -87,14 +111,12 @@ PositionTemplate<Strategy> StartOfParagraphAlgorithm(
const LayoutObject* layout_object =
previous_node_iterator->GetLayoutObject();
if (!layout_object) {
- previous_node_iterator =
- Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ previous_node_iterator = previousNode();
continue;
}
const ComputedStyle& style = layout_object->StyleRef();
if (style.Visibility() != EVisibility::kVisible) {
- previous_node_iterator =
- Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ previous_node_iterator = previousNode();
continue;
}
@@ -102,10 +124,9 @@ PositionTemplate<Strategy> StartOfParagraphAlgorithm(
break;
if (layout_object->IsText() &&
- To<LayoutText>(previous_node_iterator->GetLayoutObject())
- ->ResolvedTextLength()) {
+ To<LayoutText>(layout_object)->ResolvedTextLength()) {
if (style.PreserveNewline()) {
- auto* text = To<LayoutText>(previous_node_iterator->GetLayoutObject());
+ auto* text = To<LayoutText>(layout_object);
int index = text->TextLength();
if (previous_node_iterator == start_node && candidate_offset < index)
index = max(0, candidate_offset);
@@ -119,19 +140,14 @@ PositionTemplate<Strategy> StartOfParagraphAlgorithm(
candidate_node = previous_node_iterator;
candidate_type = PositionAnchorType::kOffsetInAnchor;
candidate_offset = 0;
- previous_node_iterator =
- Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ previous_node_iterator = previousNode();
} else if (EditingIgnoresContent(*previous_node_iterator) ||
IsDisplayInsideTable(previous_node_iterator)) {
candidate_node = previous_node_iterator;
candidate_type = PositionAnchorType::kBeforeAnchor;
- previous_node_iterator = previous_node_iterator->previousSibling()
- ? previous_node_iterator->previousSibling()
- : Strategy::PreviousPostOrder(
- *previous_node_iterator, start_block);
+ previous_node_iterator = previousNodeSkippingChildren();
} else {
- previous_node_iterator =
- Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
+ previous_node_iterator = previousNode();
}
}
@@ -146,10 +162,13 @@ VisiblePositionTemplate<Strategy> StartOfParagraphAlgorithm(
const VisiblePositionTemplate<Strategy>& visible_position,
EditingBoundaryCrossingRule boundary_crossing_rule) {
DCHECK(visible_position.IsValid()) << visible_position;
- return CreateVisiblePosition(
- StartOfParagraphAlgorithm(visible_position.DeepEquivalent(),
- boundary_crossing_rule),
- TextAffinity::kDownstream);
+ const PositionTemplate<Strategy>& start = StartOfParagraphAlgorithm(
+ visible_position.DeepEquivalent(), boundary_crossing_rule);
+#if DCHECK_IS_ON()
+ if (start.IsNotNull() && visible_position.IsNotNull())
+ DCHECK_LE(start, visible_position.DeepEquivalent());
+#endif
+ return CreateVisiblePosition(start);
}
template <typename Strategy>
@@ -175,6 +194,19 @@ PositionTemplate<Strategy> EndOfParagraphAlgorithm(
int candidate_offset = position.ComputeEditingOffset();
Node* next_node_iterator = start_node;
+ auto nextNode = [&]() -> Node* {
+ DCHECK(next_node_iterator);
+ if (next_node_iterator == start_node) {
+ // For the first iteration, take the anchor type and offset into account.
+ Node* after_position = position.ComputeNodeAfterPosition();
+ if (!after_position)
+ return Strategy::NextSkippingChildren(*next_node_iterator, start_block);
+ if (after_position != candidate_node)
+ return after_position;
+ }
+ return Strategy::Next(*next_node_iterator, start_block);
+ };
+
while (next_node_iterator) {
if (boundary_crossing_rule == kCannotCrossEditingBoundary &&
!NodeIsUserSelectAll(next_node_iterator) &&
@@ -183,7 +215,7 @@ PositionTemplate<Strategy> EndOfParagraphAlgorithm(
if (boundary_crossing_rule == kCanSkipOverEditingBoundary) {
while (next_node_iterator &&
HasEditableStyle(*next_node_iterator) != start_node_is_editable)
- next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
+ next_node_iterator = nextNode();
if (!next_node_iterator ||
!next_node_iterator->IsDescendantOf(highest_root))
break;
@@ -191,12 +223,12 @@ PositionTemplate<Strategy> EndOfParagraphAlgorithm(
LayoutObject* const layout_object = next_node_iterator->GetLayoutObject();
if (!layout_object) {
- next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
+ next_node_iterator = nextNode();
continue;
}
const ComputedStyle& style = layout_object->StyleRef();
if (style.Visibility() != EVisibility::kVisible) {
- next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
+ next_node_iterator = nextNode();
continue;
}
@@ -221,9 +253,8 @@ PositionTemplate<Strategy> EndOfParagraphAlgorithm(
candidate_node = next_node_iterator;
candidate_type = PositionAnchorType::kOffsetInAnchor;
- candidate_offset =
- layout_object->CaretMaxOffset() + text->TextStartOffset();
- next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
+ candidate_offset = text->CaretMaxOffset() + text->TextStartOffset();
+ next_node_iterator = nextNode();
} else if (EditingIgnoresContent(*next_node_iterator) ||
IsDisplayInsideTable(next_node_iterator)) {
candidate_node = next_node_iterator;
@@ -231,7 +262,7 @@ PositionTemplate<Strategy> EndOfParagraphAlgorithm(
next_node_iterator =
Strategy::NextSkippingChildren(*next_node_iterator, start_block);
} else {
- next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
+ next_node_iterator = nextNode();
}
}
@@ -246,10 +277,13 @@ VisiblePositionTemplate<Strategy> EndOfParagraphAlgorithm(
const VisiblePositionTemplate<Strategy>& visible_position,
EditingBoundaryCrossingRule boundary_crossing_rule) {
DCHECK(visible_position.IsValid()) << visible_position;
- return CreateVisiblePosition(
- EndOfParagraphAlgorithm(visible_position.DeepEquivalent(),
- boundary_crossing_rule),
- TextAffinity::kUpstream);
+ const PositionTemplate<Strategy>& end = EndOfParagraphAlgorithm(
+ visible_position.DeepEquivalent(), boundary_crossing_rule);
+#if DCHECK_IS_ON()
+ if (visible_position.IsNotNull() && end.IsNotNull())
+ DCHECK_LE(visible_position.DeepEquivalent(), end);
+#endif
+ return CreateVisiblePosition(end);
}
template <typename Strategy>
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph_test.cc
index fa676994aa4..e165934f689 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_paragraph_test.cc
@@ -111,10 +111,10 @@ TEST_F(VisibleUnitsParagraphTest, endOfParagraphFirstLetterPre) {
TEST_F(VisibleUnitsParagraphTest, endOfParagraphShadow) {
const char* body_content =
- "<a id=host><b id=one>1</b><b id=two>22</b></a><b id=three>333</b>";
+ "<span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span><b id=three>333</b>";
const char* shadow_content =
- "<p><content select=#two></content></p><p><content "
- "select=#one></content></p>";
+ "<p><slot name=#two></slot></p><p><slot name=#one></slot></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -201,10 +201,10 @@ TEST_F(VisibleUnitsParagraphTest, endOfParagraphSimplePre) {
TEST_F(VisibleUnitsParagraphTest, isEndOfParagraph) {
const char* body_content =
- "<a id=host><b id=one>1</b><b id=two>22</b></a><b id=three>333</b>";
+ "<span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span><b id=three>333</b>";
const char* shadow_content =
- "<p><content select=#two></content></p><p><content "
- "select=#one></content></p>";
+ "<p><slot name=#two></slot></p><p><slot name=#one></slot></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -230,11 +230,10 @@ TEST_F(VisibleUnitsParagraphTest, isEndOfParagraph) {
TEST_F(VisibleUnitsParagraphTest, isStartOfParagraph) {
const char* body_content =
- "<b id=zero>0</b><a id=host><b id=one>1</b><b id=two>22</b></a><b "
- "id=three>333</b>";
+ "<b id=zero>0</b><span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span><b id=three>333</b>";
const char* shadow_content =
- "<p><content select=#two></content></p><p><content "
- "select=#one></content></p>";
+ "<p><slot name=#two></slot></p><p><slot name=#one></slot></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -259,4 +258,94 @@ TEST_F(VisibleUnitsParagraphTest, isStartOfParagraph) {
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*three, 0)));
}
+TEST_F(VisibleUnitsParagraphTest,
+ endOfParagraphWithDifferentUpAndDownVisiblePositions) {
+ InsertStyleElement("span, div { display: inline-block; width: 50vw; }");
+ SetBodyContent("x<span></span><div></div>");
+
+ const Position& text_end =
+ Position::LastPositionInNode(*GetDocument().body()->firstChild());
+ const Position& before_div =
+ Position::BeforeNode(*GetDocument().QuerySelector("div"));
+ const VisiblePosition& upstream =
+ CreateVisiblePosition(before_div, TextAffinity::kUpstream);
+ const VisiblePosition& downstream =
+ CreateVisiblePosition(before_div, TextAffinity::kDownstream);
+ EXPECT_LT(upstream.DeepEquivalent(), downstream.DeepEquivalent());
+ EXPECT_EQ(text_end, upstream.DeepEquivalent());
+ EXPECT_EQ(before_div, downstream.DeepEquivalent());
+
+ // The end of paragraph of a position shouldn't precede it (bug 1179113).
+ const VisiblePosition& end_of_paragraph = EndOfParagraph(downstream);
+ EXPECT_LE(downstream.DeepEquivalent(), end_of_paragraph.DeepEquivalent());
+
+ // In in this case they are equal.
+ EXPECT_EQ(downstream.DeepEquivalent(), end_of_paragraph.DeepEquivalent());
+}
+
+TEST_F(VisibleUnitsParagraphTest, endOfParagraphCannotBeBeforePosition) {
+ SetBodyContent(
+ "<span contenteditable>x<br contenteditable=false>"
+ "<br contenteditable=false></span>");
+ Element* span = GetDocument().QuerySelector("span");
+ const Position& p1 = Position(span, 2);
+ const Position& p2 = Position::LastPositionInNode(*span);
+ const Position& p3 = Position::AfterNode(*span);
+ const VisiblePosition& vp1 = CreateVisiblePosition(p1);
+ const VisiblePosition& vp2 = CreateVisiblePosition(p2);
+ const VisiblePosition& vp3 = CreateVisiblePosition(p3);
+
+ // The anchor should still be the span after the VisiblePosition
+ // normalization, or the test would become useless.
+ EXPECT_EQ(p1, vp1.DeepEquivalent());
+ EXPECT_EQ(p2, vp2.DeepEquivalent());
+ EXPECT_EQ(vp2.DeepEquivalent(), vp3.DeepEquivalent());
+
+ // No need to test vp3 since it's equal to vp2.
+ const VisiblePosition& end1 = EndOfParagraph(vp1);
+ const VisiblePosition& end2 = EndOfParagraph(vp2);
+
+ // EndOfParagraph() iterates nodes starting from the span, and "x"@1 would be
+ // a suitable candidate. But it's skipped because it precedes the positions.
+ EXPECT_LE(vp1.DeepEquivalent(), end1.DeepEquivalent());
+ EXPECT_LE(vp2.DeepEquivalent(), end2.DeepEquivalent());
+
+ // Test the actual values.
+ EXPECT_EQ(p1, end1.DeepEquivalent());
+ EXPECT_EQ(p2, end2.DeepEquivalent());
+}
+
+TEST_F(VisibleUnitsParagraphTest, startOfParagraphCannotBeAfterPosition) {
+ SetBodyContent(
+ "<span contenteditable><br contenteditable=false>"
+ "<br contenteditable=false>x</span>");
+ Element* span = GetDocument().QuerySelector("span");
+ const Position& p1 = Position(span, 1);
+ const Position& p2 = Position::FirstPositionInNode(*span);
+ const Position& p3 = Position::BeforeNode(*span);
+ const VisiblePosition& vp1 = CreateVisiblePosition(p1);
+ const VisiblePosition& vp2 = CreateVisiblePosition(p2);
+ const VisiblePosition& vp3 = CreateVisiblePosition(p3);
+
+ // The anchor should still be the span after the VisiblePosition
+ // normalization, or the test would become useless.
+ EXPECT_EQ(p1, vp1.DeepEquivalent());
+ EXPECT_EQ(p2, vp2.DeepEquivalent());
+ EXPECT_EQ(vp2.DeepEquivalent(), vp3.DeepEquivalent());
+
+ // No need to test vp3 since it's equal to vp2.
+ const VisiblePosition& start1 = StartOfParagraph(vp1);
+ const VisiblePosition& start2 = StartOfParagraph(vp2);
+
+ // StartOfParagraph() iterates nodes in post order starting from the span, and
+ // "x"@0 would be a suitable candidate. But it's skipped because it's after
+ // the positions.
+ EXPECT_LE(start1.DeepEquivalent(), vp1.DeepEquivalent());
+ EXPECT_LE(start2.DeepEquivalent(), vp2.DeepEquivalent());
+
+ // Test the actual values.
+ EXPECT_EQ(p1, start1.DeepEquivalent());
+ EXPECT_EQ(p2, start2.DeepEquivalent());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_sentence.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_sentence.cc
index 8a328f5385d..3b5bd86fd58 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_sentence.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_sentence.cc
@@ -240,30 +240,15 @@ EphemeralRange ExpandRangeToSentenceBoundary(const EphemeralRange& range) {
// ----
-PositionInFlatTreeWithAffinity NextSentencePosition(
- const PositionInFlatTree& start) {
+PositionInFlatTree NextSentencePosition(const PositionInFlatTree& start) {
const PositionInFlatTree result = NextSentencePositionInternal(start);
return AdjustForwardPositionToAvoidCrossingEditingBoundaries(
- PositionInFlatTreeWithAffinity(result), start);
-}
-
-PositionWithAffinity NextSentencePosition(const Position& start) {
- const PositionInFlatTreeWithAffinity result =
- NextSentencePosition(ToPositionInFlatTree(start));
- return ToPositionInDOMTreeWithAffinity(result);
-}
-
-VisiblePosition NextSentencePosition(const VisiblePosition& c) {
- return CreateVisiblePosition(
- NextSentencePosition(c.DeepEquivalent()).GetPosition(),
- TextAffinity::kUpstreamIfPossible);
+ PositionInFlatTreeWithAffinity(result), start)
+ .GetPosition();
}
-VisiblePositionInFlatTree NextSentencePosition(
- const VisiblePositionInFlatTree& c) {
- return CreateVisiblePosition(
- NextSentencePosition(c.DeepEquivalent()).GetPosition(),
- TextAffinity::kUpstreamIfPossible);
+Position NextSentencePosition(const Position& start) {
+ return ToPositionInDOMTree(NextSentencePosition(ToPositionInFlatTree(start)));
}
// ----
@@ -283,10 +268,6 @@ Position PreviousSentencePosition(const Position& position) {
PreviousSentencePosition(ToPositionInFlatTree(position)));
}
-VisiblePosition PreviousSentencePosition(const VisiblePosition& c) {
- return CreateVisiblePosition(PreviousSentencePosition(c.DeepEquivalent()));
-}
-
// ----
PositionInFlatTree StartOfSentencePosition(const PositionInFlatTree& position) {
@@ -303,12 +284,4 @@ Position StartOfSentencePosition(const Position& position) {
StartOfSentencePosition(ToPositionInFlatTree(position)));
}
-VisiblePosition StartOfSentence(const VisiblePosition& c) {
- return CreateVisiblePosition(StartOfSentencePosition(c.DeepEquivalent()));
-}
-
-VisiblePositionInFlatTree StartOfSentence(const VisiblePositionInFlatTree& c) {
- return CreateVisiblePosition(StartOfSentencePosition(c.DeepEquivalent()));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_sentence_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_sentence_test.cc
index c71d3ad0a16..56c93cf8459 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_sentence_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_sentence_test.cc
@@ -49,83 +49,13 @@ class VisibleUnitsSentenceTest : public EditingTestBase {
}
};
-class ParameterizedVisibleUnitsSentenceTest
- : public ::testing::WithParamInterface<bool>,
- private ScopedLayoutNGForTest,
- public VisibleUnitsSentenceTest {
- protected:
- ParameterizedVisibleUnitsSentenceTest() : ScopedLayoutNGForTest(GetParam()) {}
-
- bool LayoutNGEnabled() const {
- return RuntimeEnabledFeatures::LayoutNGEnabled();
- }
-};
-
-INSTANTIATE_TEST_SUITE_P(All,
- ParameterizedVisibleUnitsSentenceTest,
- ::testing::Bool());
-
-TEST_P(ParameterizedVisibleUnitsSentenceTest, EndOfSentenceShadowDOMV0) {
- const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
- const char* shadow_content =
- "<p><i id=three>333</i> <content select=#two></content> <content "
- "select=#one></content> <i id=four>4444</i></p>";
- SetBodyContent(body_content);
- ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
-
- Node* one = GetDocument().getElementById("one")->firstChild();
- Node* two = GetDocument().getElementById("two")->firstChild();
- Node* three = shadow_root->getElementById("three")->firstChild();
- Node* four = shadow_root->getElementById("four")->firstChild();
-
- EXPECT_EQ(
- Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
-
- EXPECT_EQ(
- Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
-
- EXPECT_EQ(
- Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
-
- EXPECT_EQ(
- Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
-
- EXPECT_EQ(Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*three, 1))
- .DeepEquivalent());
- EXPECT_EQ(PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*three, 1))
- .DeepEquivalent());
-
- EXPECT_EQ(
- Position(four, 4),
- EndOfSentence(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
- EXPECT_EQ(PositionInFlatTree(four, 4),
- EndOfSentence(CreateVisiblePositionInFlatTree(*four, 1))
- .DeepEquivalent());
-}
-
TEST_F(VisibleUnitsSentenceTest, startOfSentence) {
- const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
+ const char* body_content =
+ "<span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span>";
const char* shadow_content =
- "<p><i id=three>333</i> <content select=#two></content> <content "
- "select=#one></content> <i id=four>4444</i></p>";
+ "<p><i id=three>333</i> <slot name=#two></slot> <slot name=#one></slot> "
+ "<i id=four>4444</i></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -134,47 +64,29 @@ TEST_F(VisibleUnitsSentenceTest, startOfSentence) {
Node* three = shadow_root->getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*one, 0))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*one, 0)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*one, 0))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*one, 0)));
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*one, 1))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*one, 1)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*one, 1))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*one, 1)));
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*two, 0))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*two, 0)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*two, 0))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*two, 0)));
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*two, 1))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*two, 1)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*two, 1))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*two, 1)));
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*three, 1))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*three, 1)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*three, 1))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*three, 1)));
- EXPECT_EQ(Position(three, 0),
- StartOfSentence(CreateVisiblePositionInDOMTree(*four, 1))
- .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0), StartOfSentencePosition(Position(*four, 1)));
EXPECT_EQ(PositionInFlatTree(three, 0),
- StartOfSentence(CreateVisiblePositionInFlatTree(*four, 1))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(*four, 1)));
}
TEST_F(VisibleUnitsSentenceTest, SentenceBoundarySkipTextControl) {
@@ -187,12 +99,10 @@ TEST_F(VisibleUnitsSentenceTest, SentenceBoundarySkipTextControl) {
EndOfSentence(PositionInFlatTree(foo, 1)).GetPosition());
EXPECT_EQ(Position(foo, 0),
- StartOfSentence(CreateVisiblePosition(Position(bar, 3)))
- .DeepEquivalent());
+ StartOfSentencePosition(Position(Position(bar, 3))));
EXPECT_EQ(PositionInFlatTree(foo, 0),
- StartOfSentence(CreateVisiblePosition(PositionInFlatTree(bar, 3)))
- .DeepEquivalent());
+ StartOfSentencePosition(PositionInFlatTree(bar, 3)));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_test.cc
index 80a60b4721f..11f14e38cc0 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_test.cc
@@ -46,7 +46,22 @@ VisiblePositionInFlatTree CreateVisiblePositionInFlatTree(
return CreateVisiblePosition(PositionInFlatTree(&anchor, offset), affinity);
}
-class VisibleUnitsTest : public EditingTestBase {};
+class VisibleUnitsTest : public EditingTestBase {
+ protected:
+ std::string TestSnapBackward(
+ const std::string& selection_text,
+ EditingBoundaryCrossingRule rule = kCannotCrossEditingBoundary) {
+ const Position position = SetSelectionTextToBody(selection_text).Base();
+ return GetCaretTextFromBody(MostBackwardCaretPosition(position, rule));
+ }
+
+ std::string TestSnapForward(
+ const std::string& selection_text,
+ EditingBoundaryCrossingRule rule = kCannotCrossEditingBoundary) {
+ const Position position = SetSelectionTextToBody(selection_text).Base();
+ return GetCaretTextFromBody(MostForwardCaretPosition(position, rule));
+ }
+};
TEST_F(VisibleUnitsTest, caretMinOffset) {
const char* body_content = "<p id=one>one</p>";
@@ -69,28 +84,47 @@ TEST_F(VisibleUnitsTest, caretMinOffsetWithFirstLetter) {
TEST_F(VisibleUnitsTest, characterAfter) {
const char* body_content =
- "<p id='host'><b id='one'>1</b><b id='two'>22</b></p><b "
+ "<p id='host'><b slot='#one' id='one'>1</b><b slot='#two' "
+ "id='two'>22</b></p><b "
"id='three'>333</b>";
const char* shadow_content =
- "<b id='four'>4444</b><content select=#two></content><content "
- "select=#one></content><b id='five'>5555</b>";
+ "<b id='four'>4444</b><slot name='#two'></slot><slot name=#one></slot><b "
+ "id='five'>5555</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
- EXPECT_EQ('2', CharacterAfter(
- CreateVisiblePositionInDOMTree(*one->firstChild(), 1)));
+ EXPECT_EQ(
+ 0, CharacterAfter(CreateVisiblePositionInDOMTree(*one->firstChild(), 1)));
EXPECT_EQ('5', CharacterAfter(
CreateVisiblePositionInFlatTree(*one->firstChild(), 1)));
- EXPECT_EQ(
- 0, CharacterAfter(CreateVisiblePositionInDOMTree(*two->firstChild(), 2)));
+ EXPECT_EQ('1', CharacterAfter(
+ CreateVisiblePositionInDOMTree(*two->firstChild(), 2)));
EXPECT_EQ('1', CharacterAfter(
CreateVisiblePositionInFlatTree(*two->firstChild(), 2)));
}
+// http://crbug.com/1176202
+TEST_F(VisibleUnitsTest, CanonicalPositionOfWithBefore) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { font: 10px/15px Ahem; }"
+ "b::before { content: '\\u200B'");
+ // |LayoutInline::PhysicalLinesBoundingBox()| for <span></span> returns
+ // LayoutNG: (0,0)+(0x10)
+ // Legacy: (0,0)+(0x0)
+ // because we don't cull empty <span> in LayoutNG.
+ SetBodyContent("<div contenteditable id=target><span></span><b></b></div>");
+ Element& target = *GetElementById("target");
+
+ EXPECT_EQ(Position(target, 0), CanonicalPositionOf(Position(target, 0)));
+ EXPECT_EQ(Position(target, 0), CanonicalPositionOf(Position(target, 1)));
+ EXPECT_EQ(Position(target, 0), CanonicalPositionOf(Position(target, 2)));
+}
+
TEST_F(VisibleUnitsTest, canonicalPositionOfWithHTMLHtmlElement) {
const char* body_content =
"<html><div id=one contenteditable>1</div><span id=two "
@@ -113,66 +147,25 @@ TEST_F(VisibleUnitsTest, canonicalPositionOfWithHTMLHtmlElement) {
EXPECT_EQ(Position(),
CanonicalPositionOf(Position(GetDocument().documentElement(), 0)));
- EXPECT_EQ(
- Position(),
- SnapBackward(Position(GetDocument().documentElement(), 0)).GetPosition());
- EXPECT_EQ(
- Position(),
- SnapForward(Position(GetDocument().documentElement(), 0)).GetPosition());
EXPECT_EQ(Position(one->firstChild(), 0),
CanonicalPositionOf(Position(one, 0)));
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapBackward(Position(one, 0)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapForward(Position(one, 0)).GetPosition());
-
EXPECT_EQ(Position(one->firstChild(), 1),
CanonicalPositionOf(Position(one, 1)));
- EXPECT_EQ(Position(one->firstChild(), 1),
- SnapBackward(Position(one, 1)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 1),
- SnapForward(Position(one, 1)).GetPosition());
EXPECT_EQ(Position(one->firstChild(), 0),
CanonicalPositionOf(Position(one->firstChild(), 0)));
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapBackward(Position(one->firstChild(), 0)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 0),
- SnapForward(Position(one->firstChild(), 0)).GetPosition());
-
EXPECT_EQ(Position(one->firstChild(), 1),
CanonicalPositionOf(Position(one->firstChild(), 1)));
- EXPECT_EQ(Position(one->firstChild(), 1),
- SnapBackward(Position(one->firstChild(), 1)).GetPosition());
- EXPECT_EQ(Position(one->firstChild(), 1),
- SnapForward(Position(one->firstChild(), 1)).GetPosition());
EXPECT_EQ(Position(html, 0), CanonicalPositionOf(Position(html, 0)));
- EXPECT_EQ(Position(html, 0), SnapBackward(Position(html, 0)).GetPosition());
- EXPECT_EQ(Position(html, 0), SnapForward(Position(html, 0)).GetPosition());
-
EXPECT_EQ(Position(html, 1), CanonicalPositionOf(Position(html, 1)));
- EXPECT_EQ(Position(html, 1), SnapBackward(Position(html, 1)).GetPosition());
- EXPECT_EQ(Position(html, 1), SnapForward(Position(html, 1)).GetPosition());
-
EXPECT_EQ(Position(html, 2), CanonicalPositionOf(Position(html, 2)));
- EXPECT_EQ(Position(html, 2), SnapBackward(Position(html, 2)).GetPosition());
- EXPECT_EQ(Position(html, 2), SnapForward(Position(html, 2)).GetPosition());
EXPECT_EQ(Position(two->firstChild(), 0),
CanonicalPositionOf(Position(two, 0)));
- EXPECT_EQ(Position(two->firstChild(), 0),
- SnapBackward(Position(two, 0)).GetPosition());
- EXPECT_EQ(Position(two->firstChild(), 0),
- SnapForward(Position(two, 0)).GetPosition());
-
EXPECT_EQ(Position(two->firstChild(), 2),
CanonicalPositionOf(Position(two, 1)));
- EXPECT_EQ(Position(two->firstChild(), 2),
- SnapBackward(Position(two, 1)).GetPosition());
- EXPECT_EQ(Position(two->firstChild(), 2),
- SnapForward(Position(two, 1)).GetPosition());
}
// For http://crbug.com/695317
@@ -180,28 +173,22 @@ TEST_F(VisibleUnitsTest, canonicalPositionOfWithInputElement) {
SetBodyContent("<input>123");
Element* const input = GetDocument().QuerySelector("input");
- Position position =
- Position::FirstPositionInNode(*GetDocument().documentElement());
- EXPECT_EQ(Position::BeforeNode(*input), CanonicalPositionOf(position));
- EXPECT_EQ(Position::BeforeNode(*input), SnapBackward(position).GetPosition());
- EXPECT_EQ(Position::BeforeNode(*input), SnapForward(position).GetPosition());
+ EXPECT_EQ(Position::BeforeNode(*input),
+ CanonicalPositionOf(Position::FirstPositionInNode(
+ *GetDocument().documentElement())));
- PositionInFlatTree pos_in_flat_tree =
- PositionInFlatTree::FirstPositionInNode(*GetDocument().documentElement());
- EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
- CanonicalPositionOf(pos_in_flat_tree));
- EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
- SnapBackward(pos_in_flat_tree).GetPosition());
EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
- SnapForward(pos_in_flat_tree).GetPosition());
+ CanonicalPositionOf(PositionInFlatTree::FirstPositionInNode(
+ *GetDocument().documentElement())));
}
TEST_F(VisibleUnitsTest, characterBefore) {
const char* body_content =
- "<p id=host><b id=one>1</b><b id=two>22</b></p><b id=three>333</b>";
+ "<p id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></p><b id=three>333</b>";
const char* shadow_content =
- "<b id=four>4444</b><content select=#two></content><content "
- "select=#one></content><b id=five>5555</b>";
+ "<b id=four>4444</b><slot name='#two'></slot><slot name=#one></slot><b "
+ "id=five>5555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -209,24 +196,25 @@ TEST_F(VisibleUnitsTest, characterBefore) {
Node* two = GetDocument().getElementById("two")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
- EXPECT_EQ(0, CharacterBefore(CreateVisiblePositionInDOMTree(*one, 0)));
+ EXPECT_EQ('2', CharacterBefore(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_EQ('2', CharacterBefore(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInFlatTree(*one, 1)));
- EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInDOMTree(*two, 0)));
+ EXPECT_EQ(0, CharacterBefore(CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_EQ('4', CharacterBefore(CreateVisiblePositionInFlatTree(*two, 0)));
- EXPECT_EQ('4', CharacterBefore(CreateVisiblePositionInDOMTree(*five, 0)));
+ EXPECT_EQ(0, CharacterBefore(CreateVisiblePositionInDOMTree(*five, 0)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInFlatTree(*five, 0)));
}
TEST_F(VisibleUnitsTest, endOfDocument) {
- const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
+ const char* body_content =
+ "<span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span>";
const char* shadow_content =
- "<p><content select=#two></content></p><p><content "
- "select=#one></content></p>";
+ "<p><slot name='#two'></slot></p><p><slot name=#one></slot></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -274,9 +262,10 @@ TEST_F(VisibleUnitsTest,
TEST_F(VisibleUnitsTest, isEndOfEditableOrNonEditableContent) {
const char* body_content =
- "<a id=host><b id=one contenteditable>1</b><b id=two>22</b></a>";
+ "<span id=host><b slot='#one' id=one contenteditable>1</b><b slot='#two' "
+ "id=two>22</b></span>";
const char* shadow_content =
- "<content select=#two></content></p><p><content select=#one></content>";
+ "<slot name='#two'></slot></p><p><slot name='#one'></slot>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -411,7 +400,7 @@ TEST_F(VisibleUnitsTest, mostBackwardCaretPositionAfterAnchor) {
const char* body_content =
"<p id='host'><b id='one'>1</b></p><b id='two'>22</b>";
const char* shadow_content =
- "<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
+ "<b id='two'>22</b><slot name='#one'></slot><b id='three'>333</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -490,16 +479,15 @@ TEST_F(VisibleUnitsTest, mostBackwardCaretPositionFirstLetterSplit) {
TEST_F(VisibleUnitsTest, mostForwardCaretPositionAfterAnchor) {
const char* body_content = "<p id='host'><b id='one'>1</b></p>";
const char* shadow_content =
- "<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
+ "<b id='two'>22</b><slot name='#one'></slot><b id='three'>333</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
UpdateAllLifecyclePhasesForTest();
Element* host = GetDocument().getElementById("host");
- Element* one = GetDocument().getElementById("one");
Element* three = shadow_root->getElementById("three");
- EXPECT_EQ(Position(one->firstChild(), 1),
+ EXPECT_EQ(Position::AfterNode(*host),
MostBackwardCaretPosition(Position::AfterNode(*host)));
EXPECT_EQ(PositionInFlatTree(three->firstChild(), 3),
MostBackwardCaretPosition(PositionInFlatTree::AfterNode(*host)));
@@ -534,11 +522,12 @@ TEST_F(VisibleUnitsTest, mostForwardCaretPositionFirstLetter) {
TEST_F(VisibleUnitsTest, nextPositionOf) {
const char* body_content =
- "<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
+ "<b id=zero>0</b><p id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></p><b "
"id=three>333</b>";
const char* shadow_content =
- "<b id=four>4444</b><content select=#two></content><content "
- "select=#one></content><b id=five>55555</b>";
+ "<b id=four>4444</b><slot name='#two'></slot><slot name=#one></slot><b "
+ "id=five>55555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -549,23 +538,25 @@ TEST_F(VisibleUnitsTest, nextPositionOf) {
Element* four = shadow_root->getElementById("four");
Element* five = shadow_root->getElementById("five");
- EXPECT_EQ(Position(one->firstChild(), 0),
+ EXPECT_EQ(Position(two->firstChild(), 2),
NextPositionOf(CreateVisiblePosition(Position(zero, 1)))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four->firstChild(), 0),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(zero, 1)))
.DeepEquivalent());
- EXPECT_EQ(
- Position(one->firstChild(), 1),
- NextPositionOf(CreateVisiblePosition(Position(one, 0))).DeepEquivalent());
+ EXPECT_EQ(Position(three->firstChild(), 0),
+ NextPositionOf(CreateVisiblePosition(Position(one, 0),
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 0)))
.DeepEquivalent());
- EXPECT_EQ(
- Position(two->firstChild(), 1),
- NextPositionOf(CreateVisiblePosition(Position(one, 1))).DeepEquivalent());
+ EXPECT_EQ(Position(two->firstChild(), 0),
+ NextPositionOf(CreateVisiblePosition(Position(one, 1),
+ TextAffinity::kUpstream))
+ .DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 1)))
.DeepEquivalent());
@@ -597,11 +588,11 @@ TEST_F(VisibleUnitsTest, nextPositionOfTable) {
TEST_F(VisibleUnitsTest, previousPositionOf) {
const char* body_content =
- "<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
- "id=three>333</b>";
+ "<b id=zero>0</b><p id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></p><b id=three>333</b>";
const char* shadow_content =
- "<b id=four>4444</b><content select=#two></content><content "
- "select=#one></content><b id=five>55555</b>";
+ "<b id=four>4444</b><slot name='#two'></slot><slot name=#one></slot><b "
+ "id=five>55555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -620,7 +611,7 @@ TEST_F(VisibleUnitsTest, previousPositionOf) {
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(zero, 1)))
.DeepEquivalent());
- EXPECT_EQ(Position(zero, 1),
+ EXPECT_EQ(Position(two, 1),
PreviousPositionOf(CreateVisiblePosition(Position(one, 0)))
.DeepEquivalent());
EXPECT_EQ(
@@ -628,7 +619,7 @@ TEST_F(VisibleUnitsTest, previousPositionOf) {
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 0)))
.DeepEquivalent());
- EXPECT_EQ(Position(one, 0),
+ EXPECT_EQ(Position(two, 2),
PreviousPositionOf(CreateVisiblePosition(Position(one, 1)))
.DeepEquivalent());
EXPECT_EQ(
@@ -636,7 +627,7 @@ TEST_F(VisibleUnitsTest, previousPositionOf) {
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 1)))
.DeepEquivalent());
- EXPECT_EQ(Position(one, 0),
+ EXPECT_EQ(Position(one, 1),
PreviousPositionOf(CreateVisiblePosition(Position(two, 0)))
.DeepEquivalent());
EXPECT_EQ(
@@ -662,9 +653,9 @@ TEST_F(VisibleUnitsTest, previousPositionOf) {
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(four, 0)))
.DeepEquivalent());
- // Note: Canonicalization maps (five, 0) to (four, 4) in DOM tree and
+ // Note: Canonicalization maps (five, 0) to (five, 0) in DOM tree and
// (one, 1) in flat tree.
- EXPECT_EQ(Position(four, 4),
+ EXPECT_EQ(Position(five, 0),
PreviousPositionOf(CreateVisiblePosition(Position(five, 1)))
.DeepEquivalent());
EXPECT_EQ(
@@ -768,10 +759,11 @@ TEST_F(VisibleUnitsTest, renderedOffset) {
}
TEST_F(VisibleUnitsTest, startOfDocument) {
- const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
+ const char* body_content =
+ "<span id=host><b slot='#one' id=one>1</b><b slot='#two' "
+ "id=two>22</b></span>";
const char* shadow_content =
- "<p><content select=#two></content></p><p><content "
- "select=#one></content></p>";
+ "<p><slot name='#two'></slot></p><p><slot name=#one></slot></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
@@ -779,17 +771,17 @@ TEST_F(VisibleUnitsTest, startOfDocument) {
Node* two = GetDocument().getElementById("two")->firstChild();
EXPECT_EQ(Position(one, 0),
- StartOfDocument(CreateVisiblePositionInDOMTree(*one, 0))
+ CreateVisiblePosition(StartOfDocument(Position(*one, 0)))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 0),
- StartOfDocument(CreateVisiblePositionInFlatTree(*one, 0))
+ CreateVisiblePosition(StartOfDocument(PositionInFlatTree(*one, 0)))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
- StartOfDocument(CreateVisiblePositionInDOMTree(*two, 1))
+ CreateVisiblePosition(StartOfDocument(Position(*two, 1)))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 0),
- StartOfDocument(CreateVisiblePositionInFlatTree(*two, 1))
+ CreateVisiblePosition(StartOfDocument(PositionInFlatTree(*two, 1)))
.DeepEquivalent());
}
@@ -822,12 +814,8 @@ TEST_F(VisibleUnitsTest,
Node* paragraph = GetDocument().QuerySelector("p");
Node* text = paragraph->firstChild();
- EXPECT_EQ(Position(text, 2),
- CanonicalPositionOf(Position::BeforeNode(*paragraph)));
- EXPECT_EQ(Position(text, 2),
- SnapBackward(Position::BeforeNode(*paragraph)).GetPosition());
- EXPECT_EQ(Position(text, 2),
- SnapForward(Position::BeforeNode(*paragraph)).GetPosition());
+ Position start = CanonicalPositionOf(Position::BeforeNode(*paragraph));
+ EXPECT_EQ(Position(text, 2), start);
}
TEST_F(VisibleUnitsTest, MostForwardCaretPositionWithInvisibleFirstLetter) {
@@ -838,5 +826,64 @@ TEST_F(VisibleUnitsTest, MostForwardCaretPositionWithInvisibleFirstLetter) {
EXPECT_EQ(Position(foo, 1), MostForwardCaretPosition(position));
}
+// Regression test for crbug.com/1172091
+TEST_F(VisibleUnitsTest, MostBackwardOrForwardCaretPositionWithBrInOptgroup) {
+ SetBodyContent("<optgroup><br></optgroup>");
+ Node* br = GetDocument().QuerySelector("br");
+ const Position& before = Position::BeforeNode(*br);
+ EXPECT_EQ(before, MostBackwardCaretPosition(before));
+ EXPECT_EQ(before, MostForwardCaretPosition(before));
+ const Position& after = Position::AfterNode(*br);
+ EXPECT_EQ(after, MostBackwardCaretPosition(after));
+ EXPECT_EQ(after, MostForwardCaretPosition(after));
+}
+
+// http://crbug.com/1134470
+TEST_F(VisibleUnitsTest, SnapBackwardWithZeroWidthSpace) {
+ // Note: We should skip <wbr> otherwise caret stops before/after <wbr>.
+
+ EXPECT_EQ(u8"<p>ab|<wbr></p>", TestSnapBackward(u8"<p>ab<wbr>|</p>"));
+ EXPECT_EQ(u8"<p>ab\u200B|</p>", TestSnapBackward(u8"<p>ab\u200B|</p>"));
+ EXPECT_EQ(u8"<p>ab<!-- -->\u200B|</p>",
+ TestSnapBackward(u8"<p>ab<!-- -->\u200B|</p>"));
+
+ EXPECT_EQ(u8"<p>ab|<wbr><wbr></p>",
+ TestSnapBackward(u8"<p>ab<wbr><wbr>|</p>"));
+ EXPECT_EQ(u8"<p>ab\u200B\u200B|</p>",
+ TestSnapBackward(u8"<p>ab\u200B\u200B|</p>"));
+
+ EXPECT_EQ(u8"<p>ab|<wbr>cd</p>", TestSnapBackward(u8"<p>ab<wbr>|cd</p>"));
+ EXPECT_EQ(u8"<p>ab\u200B|cd</p>", TestSnapBackward(u8"<p>ab\u200B|cd</p>"));
+
+ EXPECT_EQ(u8"<p>ab|<wbr><wbr>cd</p>",
+ TestSnapBackward(u8"<p>ab<wbr><wbr>|cd</p>"));
+ EXPECT_EQ(u8"<p>ab\u200B\u200B|cd</p>",
+ TestSnapBackward(u8"<p>ab\u200B\u200B|cd</p>"));
+}
+
+// http://crbug.com/1134470
+TEST_F(VisibleUnitsTest, SnapForwardWithZeroWidthSpace) {
+ // Note: We should skip <wbr> otherwise caret stops before/after <wbr>.
+
+ EXPECT_EQ(u8"<p>ab<wbr></p>", TestSnapForward(u8"<p>ab|<wbr></p>"))
+ << "We get <wbr>@0";
+ EXPECT_EQ(u8"<p>ab|\u200B</p>", TestSnapForward(u8"<p>ab|\u200B</p>"));
+ EXPECT_EQ(u8"<p>ab<!-- -->|\u200B</p>",
+ TestSnapForward(u8"<p>ab<!-- -->|\u200B</p>"));
+
+ EXPECT_EQ(u8"<p>ab<wbr><wbr></p>", TestSnapForward(u8"<p>ab|<wbr><wbr></p>"))
+ << "We get <wbr>@0";
+ EXPECT_EQ(u8"<p>ab|\u200B\u200B</p>",
+ TestSnapForward(u8"<p>ab|\u200B\u200B</p>"));
+
+ EXPECT_EQ(u8"<p>ab<wbr>|cd</p>", TestSnapForward(u8"<p>ab|<wbr>cd</p>"));
+ EXPECT_EQ(u8"<p>ab|\u200Bcd</p>", TestSnapForward(u8"<p>ab|\u200Bcd</p>"));
+
+ EXPECT_EQ(u8"<p>ab<wbr><wbr>|cd</p>",
+ TestSnapForward(u8"<p>ab|<wbr><wbr>cd</p>"));
+ EXPECT_EQ(u8"<p>ab|\u200B\u200Bcd</p>",
+ TestSnapForward(u8"<p>ab|\u200B\u200Bcd</p>"));
+}
+
} // namespace visible_units_test
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_word.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_word.cc
index 8358c13e096..bd082c7cc02 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_word.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_word.cc
@@ -134,11 +134,21 @@ PositionInFlatTree NextWordPositionInternal(
return SkipWhitespaceIfNeeded(text, runner);
continue;
}
- // We stop searching when the character preceding the break is
- // alphanumeric or punctuations or underscore or linebreaks.
+ // We stop searching in the following conditions:
+ // 1. When the character preceding the break is
+ // alphanumeric or punctuations or underscore or linebreaks.
+ // Only on Windows:
+ // 2. When the character preceding the break is a whitespace and
+ // the character following it is an alphanumeric or punctuations
+ // or underscore or linebreaks.
if (static_cast<unsigned>(runner) < text.length() &&
IsWordBreak(text[runner - 1]))
return SkipWhitespaceIfNeeded(text, runner);
+ else if (platform_word_behavior_ ==
+ PlatformWordBehavior::kWordSkipSpaces &&
+ static_cast<unsigned>(runner) < text.length() &&
+ IsWhitespace(text[runner - 1]) && IsWordBreak(text[runner]))
+ return SkipWhitespaceIfNeeded(text, runner);
}
if (text[text.length() - 1] != kNewlineCharacter)
return Position::After(text.length() - 1);
@@ -276,19 +286,6 @@ Position EndOfWordPosition(const Position& position, WordSide side) {
EndOfWordPosition(ToPositionInFlatTree(position), side));
}
-VisiblePosition EndOfWord(const VisiblePosition& position, WordSide side) {
- return CreateVisiblePosition(
- EndOfWordPosition(position.DeepEquivalent(), side),
- TextAffinity::kUpstreamIfPossible);
-}
-
-VisiblePositionInFlatTree EndOfWord(const VisiblePositionInFlatTree& position,
- WordSide side) {
- return CreateVisiblePosition(
- EndOfWordPosition(position.DeepEquivalent(), side),
- TextAffinity::kUpstreamIfPossible);
-}
-
// ----
// TODO(editing-dev): Because of word boundary can not be an upstream position,
// we should make this function to return |PositionInFlatTree|.
diff --git a/chromium/third_party/blink/renderer/core/editing/visible_units_word_test.cc b/chromium/third_party/blink/renderer/core/editing/visible_units_word_test.cc
index 2dc0001e2b3..4be0c65c8b3 100644
--- a/chromium/third_party/blink/renderer/core/editing/visible_units_word_test.cc
+++ b/chromium/third_party/blink/renderer/core/editing/visible_units_word_test.cc
@@ -24,8 +24,7 @@ class VisibleUnitsWordTest : public EditingTestBase {
const std::string& selection_text,
WordSide word_side = WordSide::kNextWordIfOnBoundary) {
const Position position = SetSelectionTextToBody(selection_text).Base();
- return GetCaretTextFromBody(
- EndOfWord(CreateVisiblePosition(position), word_side).DeepEquivalent());
+ return GetCaretTextFromBody(EndOfWordPosition(position, word_side));
}
std::string DoNextWord(const std::string& selection_text) {
@@ -178,10 +177,11 @@ TEST_P(ParameterizedVisibleUnitsWordTest, StartOfWordFirstLetter) {
TEST_P(ParameterizedVisibleUnitsWordTest, StartOfWordShadowDOM) {
const char* body_content =
- "<a id=host><b id=one>1</b> <b id=two>22</b></a><i id=three>333</i>";
+ "<span id=host><b slot='#one' id=one>1</b> <b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i>";
const char* shadow_content =
- "<p><u id=four>44444</u><content select=#two></content><span id=space> "
- "</span><content select=#one></content><u id=five>55555</u></p>";
+ "<p><u id=four>44444</u><slot name=#two></slot><span id=space> "
+ "</span><slot name=#one></slot><u id=five>55555</u></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -213,7 +213,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, StartOfWordShadowDOM) {
StartOfWordPosition(
CreateVisiblePositionInFlatTree(*one, 1).DeepEquivalent()))
.DeepEquivalent());
- EXPECT_EQ(Position(one, 0),
+ EXPECT_EQ(Position(four, 0),
CreateVisiblePosition(
StartOfWordPosition(
CreateVisiblePositionInDOMTree(*two, 0).DeepEquivalent()))
@@ -233,8 +233,13 @@ TEST_P(ParameterizedVisibleUnitsWordTest, StartOfWordShadowDOM) {
StartOfWordPosition(
CreateVisiblePositionInFlatTree(*two, 1).DeepEquivalent()))
.DeepEquivalent());
- // DOM tree canonicalization moves the result to a wrong position.
- EXPECT_EQ(Position(two, 2),
+ EXPECT_EQ(Position(three, 0),
+ CreateVisiblePosition(
+ StartOfWordPosition(CreateVisiblePositionInDOMTree(
+ *three, 1, TextAffinity::kUpstream)
+ .DeepEquivalent()))
+ .DeepEquivalent());
+ EXPECT_EQ(Position(three, 0),
CreateVisiblePosition(
StartOfWordPosition(
CreateVisiblePositionInDOMTree(*three, 1).DeepEquivalent()))
@@ -344,7 +349,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, EndOfWordBasic) {
EXPECT_EQ("<p> (1) abc def|</p>", DoEndOfWord("<p> (1) abc d|ef</p>"));
EXPECT_EQ("<p> (1) abc def|</p>", DoEndOfWord("<p> (1) abc de|f</p>"));
EXPECT_EQ("<p> (1) abc def|</p>", DoEndOfWord("<p> (1) abc def|</p>"));
- EXPECT_EQ("<p> (1) abc def|</p>", DoEndOfWord("<p> (1) abc def</p>|"));
+ EXPECT_EQ("<p> (1) abc def</p>|", DoEndOfWord("<p> (1) abc def</p>|"));
}
TEST_P(ParameterizedVisibleUnitsWordTest,
@@ -389,16 +394,17 @@ TEST_P(ParameterizedVisibleUnitsWordTest,
"<p> (1) abc def|</p>",
DoEndOfWord("<p> (1) abc def|</p>", WordSide::kPreviousWordIfOnBoundary));
EXPECT_EQ(
- "<p> (1) abc def|</p>",
+ "<p> (1) abc def</p>|",
DoEndOfWord("<p> (1) abc def</p>|", WordSide::kPreviousWordIfOnBoundary));
}
TEST_P(ParameterizedVisibleUnitsWordTest, EndOfWordShadowDOM) {
const char* body_content =
- "<a id=host><b id=one>1</b> <b id=two>22</b></a><i id=three>333</i>";
+ "<span id=host><b slot='#one' id=one>1</b> <b slot='#two' "
+ "id=two>22</b></span><i id=three>333</i>";
const char* shadow_content =
- "<p><u id=four>44444</u><content select=#two></content><span id=space> "
- "</span><content select=#one></content><u id=five>55555</u></p>";
+ "<p><u id=four>44444</u><slot name=#two></slot><span id=space> "
+ "</span><slot name=#one></slot><u id=five>55555</u></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
@@ -408,54 +414,33 @@ TEST_P(ParameterizedVisibleUnitsWordTest, EndOfWordShadowDOM) {
Node* four = shadow_root->getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
- EXPECT_EQ(
- Position(five, 5),
- EndOfWord(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(five, 5),
- EndOfWord(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(five, 5), EndOfWordPosition(Position(*one, 0)));
+ EXPECT_EQ(PositionInFlatTree(five, 5),
+ EndOfWordPosition(PositionInFlatTree(*one, 0)));
- EXPECT_EQ(
- Position(five, 5),
- EndOfWord(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(five, 5),
- EndOfWord(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(five, 5), EndOfWordPosition(Position(*one, 1)));
+ EXPECT_EQ(PositionInFlatTree(five, 5),
+ EndOfWordPosition(PositionInFlatTree(*one, 1)));
- EXPECT_EQ(
- Position(five, 5),
- EndOfWord(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(two, 2),
- EndOfWord(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
+ EXPECT_EQ(Position(two, 2), EndOfWordPosition(Position(*two, 0)));
+ EXPECT_EQ(PositionInFlatTree(two, 2),
+ EndOfWordPosition(PositionInFlatTree(*two, 0)));
- EXPECT_EQ(
- Position(two, 2),
- EndOfWord(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(two, 2),
- EndOfWord(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(two, 2), EndOfWordPosition(Position(*two, 1)));
+ EXPECT_EQ(PositionInFlatTree(two, 2),
+ EndOfWordPosition(PositionInFlatTree(*two, 1)));
- EXPECT_EQ(
- Position(three, 3),
- EndOfWord(CreateVisiblePositionInDOMTree(*three, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(three, 3),
- EndOfWord(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(three, 3), EndOfWordPosition(Position(*three, 1)));
+ EXPECT_EQ(PositionInFlatTree(three, 3),
+ EndOfWordPosition(PositionInFlatTree(*three, 1)));
- EXPECT_EQ(
- Position(two, 2),
- EndOfWord(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(two, 2),
- EndOfWord(CreateVisiblePositionInFlatTree(*four, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(two, 2), EndOfWordPosition(Position(*four, 1)));
+ EXPECT_EQ(PositionInFlatTree(two, 2),
+ EndOfWordPosition(PositionInFlatTree(*four, 1)));
- EXPECT_EQ(
- Position(five, 5),
- EndOfWord(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
- EXPECT_EQ(
- PositionInFlatTree(five, 5),
- EndOfWord(CreateVisiblePositionInFlatTree(*five, 1)).DeepEquivalent());
+ EXPECT_EQ(Position(five, 5), EndOfWordPosition(Position(*five, 1)));
+ EXPECT_EQ(PositionInFlatTree(five, 5),
+ EndOfWordPosition(PositionInFlatTree(*five, 1)));
}
TEST_P(ParameterizedVisibleUnitsWordTest, EndOfWordTextSecurity) {
@@ -528,7 +513,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, NextWordSkipSpacesBasic) {
DoNextWordSkippingSpaces("<p> (|1) abc def</p>"));
EXPECT_EQ("<p> (1) |abc def</p>",
DoNextWordSkippingSpaces("<p> (1|) abc def</p>"));
- EXPECT_EQ("<p> (1) abc |def</p>",
+ EXPECT_EQ("<p> (1) |abc def</p>",
DoNextWordSkippingSpaces("<p> (1)| abc def</p>"));
EXPECT_EQ("<p> (1) abc |def</p>",
DoNextWordSkippingSpaces("<p> (1) |abc def</p>"));
@@ -536,7 +521,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, NextWordSkipSpacesBasic) {
DoNextWordSkippingSpaces("<p> (1) a|bc def</p>"));
EXPECT_EQ("<p> (1) abc |def</p>",
DoNextWordSkippingSpaces("<p> (1) ab|c def</p>"));
- EXPECT_EQ("<p> (1) abc def|</p>",
+ EXPECT_EQ("<p> (1) abc |def</p>",
DoNextWordSkippingSpaces("<p> (1) abc| def</p>"));
EXPECT_EQ("<p> (1) abc def|</p>",
DoNextWordSkippingSpaces("<p> (1) abc |def</p>"));
diff --git a/chromium/third_party/blink/renderer/core/events/build.gni b/chromium/third_party/blink/renderer/core/events/build.gni
index a111c9f1fee..aaf379a22cf 100644
--- a/chromium/third_party/blink/renderer/core/events/build.gni
+++ b/chromium/third_party/blink/renderer/core/events/build.gni
@@ -67,6 +67,8 @@ blink_core_sources_events = [
"resource_progress_event.h",
"security_policy_violation_event.cc",
"security_policy_violation_event.h",
+ "simulated_event_util.cc",
+ "simulated_event_util.h",
"text_event.cc",
"text_event.h",
"text_event_input_type.h",
diff --git a/chromium/third_party/blink/renderer/core/events/current_input_event.h b/chromium/third_party/blink/renderer/core/events/current_input_event.h
index 9cf588025c6..faf00d19909 100644
--- a/chromium/third_party/blink/renderer/core/events/current_input_event.h
+++ b/chromium/third_party/blink/renderer/core/events/current_input_event.h
@@ -22,7 +22,7 @@ class CORE_EXPORT CurrentInputEvent {
static const WebInputEvent* Get() { return current_input_event_; }
private:
- friend class WebFrameWidgetBase;
+ friend class WebFrameWidgetImpl;
friend class NavigationPolicyTest;
static const WebInputEvent* current_input_event_;
diff --git a/chromium/third_party/blink/renderer/core/events/event_target_names.json5 b/chromium/third_party/blink/renderer/core/events/event_target_names.json5
index a462ff2c7ba..42f72e1bfe4 100644
--- a/chromium/third_party/blink/renderer/core/events/event_target_names.json5
+++ b/chromium/third_party/blink/renderer/core/events/event_target_names.json5
@@ -42,6 +42,7 @@
ImplementedAs: "DOMWindow",
},
"DedicatedWorkerGlobalScope",
+ "Screen",
"SharedWorker",
"SharedWorkerGlobalScope",
"Worker",
diff --git a/chromium/third_party/blink/renderer/core/events/event_type_names.json5 b/chromium/third_party/blink/renderer/core/events/event_type_names.json5
index ce539efd0b9..3e4443409ee 100644
--- a/chromium/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/chromium/third_party/blink/renderer/core/events/event_type_names.json5
@@ -44,12 +44,13 @@
"backgroundfetchclick",
"backgroundfetchfail",
"backgroundfetchsuccess",
- "beforematch",
+ "beforeclose",
"beforecopy",
"beforecreatepolicy",
"beforecut",
"beforeinput",
"beforeinstallprompt",
+ "beforematch",
"beforepaste",
"beforeprint",
"beforeunload",
@@ -72,6 +73,7 @@
"click",
"close",
"closing",
+ "colorselect",
"complete",
"compositionend",
"compositionstart",
@@ -149,6 +151,7 @@
"gestureflingstart",
"gotpointercapture",
"hashchange",
+ "hide",
"icecandidate",
"icecandidateerror",
"iceconnectionstatechange",
@@ -176,6 +179,7 @@
"loadingerror",
"loadstart",
"lostpointercapture",
+ "managedconfigurationchange",
"mark",
"message",
"messageerror",
@@ -233,6 +237,7 @@
"quotachange",
"ratechange",
"reading",
+ "readingerror",
"readystatechange",
"reflectionchange",
"rejectionhandled",
@@ -337,10 +342,6 @@
"webkitTransitionEnd",
"webkitfullscreenchange",
"webkitfullscreenerror",
- "webkitprerenderdomcontentloaded",
- "webkitprerenderload",
- "webkitprerenderstart",
- "webkitprerenderstop",
"webkitspeechchange",
"webkitvisibilitychange",
"wheel",
diff --git a/chromium/third_party/blink/renderer/core/events/event_util.cc b/chromium/third_party/blink/renderer/core/events/event_util.cc
index a4d311ca620..6e430b48830 100644
--- a/chromium/third_party/blink/renderer/core/events/event_util.cc
+++ b/chromium/third_party/blink/renderer/core/events/event_util.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/events/event_util.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "third_party/blink/renderer/core/event_type_names.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
diff --git a/chromium/third_party/blink/renderer/core/events/hash_change_event.h b/chromium/third_party/blink/renderer/core/events/hash_change_event.h
index c84d59b8417..1e91467a79c 100644
--- a/chromium/third_party/blink/renderer/core/events/hash_change_event.h
+++ b/chromium/third_party/blink/renderer/core/events/hash_change_event.h
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_hash_change_event_init.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/event_interface_names.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/events/message_event.cc b/chromium/third_party/blink/renderer/core/events/message_event.cc
index 03c1daaf7a3..bdb4a6e210d 100644
--- a/chromium/third_party/blink/renderer/core/events/message_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/message_event.cc
@@ -160,7 +160,8 @@ MessageEvent::MessageEvent(scoped_refptr<SerializedScriptValue> data,
const String& last_event_id,
EventTarget* source,
Vector<MessagePortChannel> channels,
- UserActivation* user_activation)
+ UserActivation* user_activation,
+ bool delegate_payment_request)
: Event(event_type_names::kMessage, Bubbles::kNo, Cancelable::kNo),
data_type_(kDataTypeSerializedScriptValue),
data_as_serialized_script_value_(
@@ -169,7 +170,8 @@ MessageEvent::MessageEvent(scoped_refptr<SerializedScriptValue> data,
last_event_id_(last_event_id),
source_(source),
channels_(std::move(channels)),
- user_activation_(user_activation) {
+ user_activation_(user_activation),
+ delegate_payment_request_(delegate_payment_request) {
DCHECK(IsValidSource(source_.Get()));
RegisterAmountOfExternallyAllocatedMemory();
}
@@ -257,7 +259,8 @@ void MessageEvent::initMessageEvent(const AtomicString& type,
const String& last_event_id,
EventTarget* source,
MessagePortArray* ports,
- UserActivation* user_activation) {
+ UserActivation* user_activation,
+ bool delegate_payment_request) {
if (IsBeingDispatched())
return;
@@ -273,6 +276,7 @@ void MessageEvent::initMessageEvent(const AtomicString& type,
ports_ = ports;
is_ports_dirty_ = true;
user_activation_ = user_activation;
+ delegate_payment_request_ = delegate_payment_request;
RegisterAmountOfExternallyAllocatedMemory();
}
diff --git a/chromium/third_party/blink/renderer/core/events/message_event.h b/chromium/third_party/blink/renderer/core/events/message_event.h
index 0132a4f203b..c6209098ba7 100644
--- a/chromium/third_party/blink/renderer/core/events/message_event.h
+++ b/chromium/third_party/blink/renderer/core/events/message_event.h
@@ -79,10 +79,11 @@ class CORE_EXPORT MessageEvent final : public Event {
const String& origin = String(),
const String& last_event_id = String(),
EventTarget* source = nullptr,
- UserActivation* user_activation = nullptr) {
+ UserActivation* user_activation = nullptr,
+ bool delegate_payment_request = false) {
return MakeGarbageCollected<MessageEvent>(
std::move(data), origin, last_event_id, source, std::move(channels),
- user_activation);
+ user_activation, delegate_payment_request);
}
static MessageEvent* CreateError(const String& origin = String(),
EventTarget* source = nullptr) {
@@ -120,7 +121,8 @@ class CORE_EXPORT MessageEvent final : public Event {
const String& last_event_id,
EventTarget* source,
Vector<MessagePortChannel>,
- UserActivation* user_activation);
+ UserActivation* user_activation,
+ bool delegate_payment_request);
// Creates a "messageerror" event.
MessageEvent(const String& origin, EventTarget* source);
MessageEvent(const String& data, const String& origin);
@@ -144,7 +146,8 @@ class CORE_EXPORT MessageEvent final : public Event {
const String& last_event_id,
EventTarget* source,
MessagePortArray*,
- UserActivation* user_activation);
+ UserActivation* user_activation,
+ bool delegate_payment_request);
void initMessageEvent(const AtomicString& type,
bool bubbles,
bool cancelable,
@@ -162,6 +165,7 @@ class CORE_EXPORT MessageEvent final : public Event {
MessagePortArray ports();
bool isPortsDirty() const { return is_ports_dirty_; }
UserActivation* userActivation() const { return user_activation_; }
+ bool delegatePaymentRequest() const { return delegate_payment_request_; }
Vector<MessagePortChannel> ReleaseChannels() { return std::move(channels_); }
@@ -227,6 +231,7 @@ class CORE_EXPORT MessageEvent final : public Event {
bool is_ports_dirty_ = true;
Vector<MessagePortChannel> channels_;
Member<UserActivation> user_activation_;
+ bool delegate_payment_request_ = false;
size_t amount_of_external_memory_ = 0;
// For serialized messages across process this attribute contains the
// information of whether the actual original SerializedScriptValue was locked
diff --git a/chromium/third_party/blink/renderer/core/events/mouse_event.cc b/chromium/third_party/blink/renderer/core/events/mouse_event.cc
index fab28aa55f2..f2ba3b0b913 100644
--- a/chromium/third_party/blink/renderer/core/events/mouse_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/mouse_event.cc
@@ -42,6 +42,7 @@
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.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/wtf/math_extras.h"
namespace blink {
@@ -128,53 +129,6 @@ MouseEvent* MouseEvent::Create(const AtomicString& event_type,
menu_source_type);
}
-MouseEvent* MouseEvent::Create(const AtomicString& event_type,
- AbstractView* view,
- const Event* underlying_event,
- SimulatedClickCreationScope creation_scope) {
- WebInputEvent::Modifiers modifiers = WebInputEvent::kNoModifiers;
- if (const UIEventWithKeyState* key_state_event =
- FindEventWithKeyState(underlying_event)) {
- modifiers = key_state_event->GetModifiers();
- }
-
- SyntheticEventType synthetic_type = kPositionless;
- MouseEventInit* initializer = MouseEventInit::Create();
- if (const auto* mouse_event = DynamicTo<MouseEvent>(underlying_event)) {
- synthetic_type = kRealOrIndistinguishable;
- initializer->setScreenX(mouse_event->screenX());
- initializer->setScreenY(mouse_event->screenY());
- initializer->setSourceCapabilities(
- view ? view->GetInputDeviceCapabilities()->FiresTouchEvents(false)
- : nullptr);
- }
-
- initializer->setBubbles(true);
- initializer->setCancelable(true);
- initializer->setView(view);
- initializer->setComposed(true);
- UIEventWithKeyState::SetFromWebInputEventModifiers(initializer, modifiers);
- initializer->setButtons(
- MouseEvent::WebInputEventModifiersToButtons(modifiers));
-
- base::TimeTicks timestamp = underlying_event
- ? underlying_event->PlatformTimeStamp()
- : base::TimeTicks::Now();
- MouseEvent* created_event = MakeGarbageCollected<MouseEvent>(
- event_type, initializer, timestamp, synthetic_type);
-
- created_event->SetTrusted(creation_scope ==
- SimulatedClickCreationScope::kFromUserAgent);
- created_event->SetUnderlyingEvent(underlying_event);
- if (synthetic_type == kRealOrIndistinguishable) {
- auto* mouse_event = To<MouseEvent>(created_event->UnderlyingEvent());
- created_event->InitCoordinates(mouse_event->clientX(),
- mouse_event->clientY());
- }
-
- return created_event;
-}
-
MouseEvent::MouseEvent()
: position_type_(PositionType::kPosition),
button_(0),
@@ -258,8 +212,6 @@ void MouseEvent::SetCoordinatesFromWebPointerProperties(
}
}
-MouseEvent::~MouseEvent() = default;
-
uint16_t MouseEvent::WebInputEventModifiersToButtons(unsigned modifiers) {
uint16_t buttons = 0;
@@ -542,22 +494,14 @@ int MouseEvent::layerX() {
if (!has_cached_relative_position_)
ComputeRelativePosition();
- // TODO(mustaq): Remove the PointerEvent specific code when mouse has
- // fractional coordinates. See crbug.com/655786.
-
- return IsPointerEvent() ? layer_location_.X()
- : static_cast<int>(layer_location_.X());
+ return clampTo<int, double>(std::floor(layer_location_.X()));
}
int MouseEvent::layerY() {
if (!has_cached_relative_position_)
ComputeRelativePosition();
- // TODO(mustaq): Remove the PointerEvent specific code when mouse has
- // fractional coordinates. See crbug.com/655786.
-
- return IsPointerEvent() ? layer_location_.Y()
- : static_cast<int>(layer_location_.Y());
+ return clampTo<int, double>(std::floor(layer_location_.Y()));
}
double MouseEvent::offsetX() const {
diff --git a/chromium/third_party/blink/renderer/core/events/mouse_event.h b/chromium/third_party/blink/renderer/core/events/mouse_event.h
index 838ca84ce80..3108b5df87f 100644
--- a/chromium/third_party/blink/renderer/core/events/mouse_event.h
+++ b/chromium/third_party/blink/renderer/core/events/mouse_event.h
@@ -24,12 +24,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_MOUSE_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_MOUSE_EVENT_H_
+#include <cmath>
+
#include "third_party/blink/public/common/input/web_menu_source_type.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/events/ui_event_with_key_state.h"
#include "third_party/blink/renderer/platform/geometry/double_point.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -56,6 +57,7 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
static MouseEvent* Create() { return MakeGarbageCollected<MouseEvent>(); }
+ // TODO(mustaq): looks like we don't need so many variations of Create() here
static MouseEvent* Create(const AtomicString& event_type,
const MouseEventInit*,
base::TimeTicks platform_time_stamp,
@@ -66,20 +68,12 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
const AtomicString& event_type,
const MouseEventInit*);
- static MouseEvent* Create(const AtomicString& event_type,
- AbstractView*,
- const Event* underlying_event,
- SimulatedClickCreationScope);
-
MouseEvent(const AtomicString& type,
const MouseEventInit*,
- base::TimeTicks platform_time_stamp,
+ base::TimeTicks platform_time_stamp = base::TimeTicks::Now(),
SyntheticEventType = kRealOrIndistinguishable,
WebMenuSourceType = kMenuSourceNone);
- MouseEvent(const AtomicString& type, const MouseEventInit* init)
- : MouseEvent(type, init, base::TimeTicks::Now()) {}
MouseEvent();
- ~MouseEvent() override;
static uint16_t WebInputEventModifiersToButtons(unsigned modifiers);
static void SetCoordinatesFromWebPointerProperties(
@@ -143,21 +137,13 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
// Note that these values are adjusted to counter the effects of zoom, so that
// values exposed via DOM APIs are invariant under zooming.
- virtual double screenX() const {
- return static_cast<int>(screen_location_.X());
- }
+ virtual double screenX() const { return std::floor(screen_location_.X()); }
- virtual double screenY() const {
- return static_cast<int>(screen_location_.Y());
- }
+ virtual double screenY() const { return std::floor(screen_location_.Y()); }
- virtual double clientX() const {
- return static_cast<int>(client_location_.X());
- }
+ virtual double clientX() const { return std::floor(client_location_.X()); }
- virtual double clientY() const {
- return static_cast<int>(client_location_.Y());
- }
+ virtual double clientY() const { return std::floor(client_location_.Y()); }
int movementX() const { return movement_delta_.X(); }
int movementY() const { return movement_delta_.Y(); }
@@ -168,9 +154,9 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
virtual double offsetX() const;
virtual double offsetY() const;
- virtual double pageX() const { return static_cast<int>(page_location_.X()); }
+ virtual double pageX() const { return std::floor(page_location_.X()); }
- virtual double pageY() const { return static_cast<int>(page_location_.Y()); }
+ virtual double pageY() const { return std::floor(page_location_.Y()); }
double x() const { return clientX(); }
double y() const { return clientY(); }
@@ -186,6 +172,8 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
DispatchEventResult DispatchEvent(EventDispatcher&) override;
+ void InitCoordinates(const double client_x, const double client_y);
+
void Trace(Visitor*) const override;
DoublePoint screen_location_;
@@ -218,8 +206,6 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
InputDeviceCapabilities* source_capabilities,
uint16_t buttons = 0);
- void InitCoordinates(const double client_x, const double client_y);
-
void ComputePageLocation();
DoublePoint movement_delta_;
diff --git a/chromium/third_party/blink/renderer/core/events/mouse_event_test.cc b/chromium/third_party/blink/renderer/core/events/mouse_event_test.cc
new file mode 100644
index 00000000000..05ba1970847
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/mouse_event_test.cc
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/events/mouse_event.h"
+
+#include <limits>
+#include <tuple>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_mouse_event_init.h"
+#include "third_party/blink/renderer/platform/geometry/double_point.h"
+#include "third_party/blink/renderer/platform/geometry/int_point.h"
+
+namespace blink {
+
+class MouseEventScreenClientPagePositionTest
+ : public ::testing::TestWithParam<std::tuple<double, double>> {};
+class MouseEventLayerPositionTest
+ : public ::testing::TestWithParam<std::tuple<double, double>> {};
+
+TEST_P(MouseEventScreenClientPagePositionTest, PositionAsExpected) {
+ MouseEvent& mouse_event = *MouseEvent::Create();
+ DoublePoint input_location(std::get<0>(GetParam()), std::get<0>(GetParam()));
+ DoublePoint expected_location(std::get<1>(GetParam()),
+ std::get<1>(GetParam()));
+
+ mouse_event.screen_location_ = input_location;
+ mouse_event.client_location_ = input_location;
+ mouse_event.page_location_ = input_location;
+
+ ASSERT_EQ(mouse_event.clientX(), expected_location.X());
+ ASSERT_EQ(mouse_event.clientY(), expected_location.Y());
+ ASSERT_EQ(mouse_event.screenX(), expected_location.X());
+ ASSERT_EQ(mouse_event.screenY(), expected_location.Y());
+ ASSERT_EQ(mouse_event.pageX(), expected_location.X());
+ ASSERT_EQ(mouse_event.pageY(), expected_location.Y());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ MouseEventScreenClientPagePositionNoOverflow,
+ MouseEventScreenClientPagePositionTest,
+ ::testing::Values(
+ std::make_tuple(std::numeric_limits<int>::min() * 1.0,
+ std::numeric_limits<int>::min() * 1.0),
+ std::make_tuple(std::numeric_limits<int>::min() * 1.0 - 1.55,
+ std::numeric_limits<int>::min() * 1.0 - 2.0),
+ std::make_tuple(std::numeric_limits<int>::max() * 1.0,
+ std::numeric_limits<int>::max() * 1.0),
+ std::make_tuple(std::numeric_limits<int>::max() * 1.0 + 1.55,
+ std::numeric_limits<int>::max() * 1.0 + 1.00),
+ std::make_tuple(std::numeric_limits<double>::lowest(),
+ std::ceil(std::numeric_limits<double>::lowest())),
+ std::make_tuple(std::numeric_limits<double>::lowest() + 1.45,
+ std::ceil(std::numeric_limits<double>::lowest() +
+ 1.45)),
+ std::make_tuple(std::numeric_limits<double>::max(),
+ std::floor(std::numeric_limits<double>::max())),
+ std::make_tuple(std::numeric_limits<double>::max() - 1.45,
+ std::floor(std::numeric_limits<double>::max() -
+ 1.45))));
+
+TEST_P(MouseEventLayerPositionTest, LayerPositionAsExpected) {
+ DoublePoint input_layer_location(std::get<0>(GetParam()),
+ std::get<0>(GetParam()));
+ IntPoint expected_layer_location(std::get<1>(GetParam()),
+ std::get<1>(GetParam()));
+
+ MouseEventInit& mouse_event_init = *MouseEventInit::Create();
+ mouse_event_init.setClientX(input_layer_location.X());
+ mouse_event_init.setClientY(input_layer_location.Y());
+ MouseEvent mouse_event("mousedown", &mouse_event_init);
+
+ ASSERT_EQ(mouse_event.layerX(), expected_layer_location.X());
+ ASSERT_EQ(mouse_event.layerY(), expected_layer_location.Y());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ MouseEventLayerPositionNoOverflow,
+ MouseEventLayerPositionTest,
+ ::testing::Values(
+ std::make_tuple(std::numeric_limits<int>::min() * 1.0,
+ std::numeric_limits<int>::min()),
+ std::make_tuple(std::numeric_limits<int>::min() * 1.0 - 1.45,
+ std::numeric_limits<int>::min()),
+ std::make_tuple(std::numeric_limits<int>::max() * 1.0,
+ std::numeric_limits<int>::max()),
+ std::make_tuple(std::numeric_limits<int>::max() * 1.0 + 1.45,
+ std::numeric_limits<int>::max()),
+ std::make_tuple(std::numeric_limits<double>::lowest(),
+ std::numeric_limits<int>::min()),
+ std::make_tuple(std::numeric_limits<double>::lowest() + 1.45,
+ std::numeric_limits<int>::min()),
+ std::make_tuple(std::numeric_limits<double>::max(),
+ std::numeric_limits<int>::max()),
+ std::make_tuple(std::numeric_limits<double>::max() - 1.45,
+ std::numeric_limits<int>::max())));
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event.cc b/chromium/third_party/blink/renderer/core/events/pointer_event.cc
index 6386b0decb8..3b3e1bdc8df 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
+
PointerEvent::PointerEvent(const AtomicString& type,
const PointerEventInit* initializer,
base::TimeTicks platform_time_stamp,
@@ -63,29 +64,27 @@ PointerEvent::PointerEvent(const AtomicString& type,
for (auto predicted_event : initializer->predictedEvents())
predicted_events_.push_back(predicted_event);
}
- if (RuntimeEnabledFeatures::AzimuthAltitudeEnabled()) {
- if (initializer->hasAzimuthAngle())
- azimuth_angle_ = initializer->azimuthAngle();
- if (initializer->hasAltitudeAngle())
- altitude_angle_ = initializer->altitudeAngle();
- if ((initializer->hasTiltX() || initializer->hasTiltY()) &&
- !initializer->hasAzimuthAngle() && !initializer->hasAltitudeAngle()) {
- azimuth_angle_ = PointerEventUtil::AzimuthFromTilt(
- PointerEventUtil::TransformToTiltInValidRange(tilt_x_),
- PointerEventUtil::TransformToTiltInValidRange(tilt_y_));
- altitude_angle_ = PointerEventUtil::AltitudeFromTilt(
- PointerEventUtil::TransformToTiltInValidRange(tilt_x_),
- PointerEventUtil::TransformToTiltInValidRange(tilt_y_));
- }
- if ((initializer->hasAzimuthAngle() || initializer->hasAltitudeAngle()) &&
- !initializer->hasTiltX() && !initializer->hasTiltY()) {
- tilt_x_ = PointerEventUtil::TiltXFromSpherical(
- PointerEventUtil::TransformToAzimuthInValidRange(azimuth_angle_),
- PointerEventUtil::TransformToAltitudeInValidRange(altitude_angle_));
- tilt_y_ = PointerEventUtil::TiltYFromSpherical(
- PointerEventUtil::TransformToAzimuthInValidRange(azimuth_angle_),
- PointerEventUtil::TransformToAltitudeInValidRange(altitude_angle_));
- }
+ if (initializer->hasAzimuthAngle())
+ azimuth_angle_ = initializer->azimuthAngle();
+ if (initializer->hasAltitudeAngle())
+ altitude_angle_ = initializer->altitudeAngle();
+ if ((initializer->hasTiltX() || initializer->hasTiltY()) &&
+ !initializer->hasAzimuthAngle() && !initializer->hasAltitudeAngle()) {
+ azimuth_angle_ = PointerEventUtil::AzimuthFromTilt(
+ PointerEventUtil::TransformToTiltInValidRange(tilt_x_),
+ PointerEventUtil::TransformToTiltInValidRange(tilt_y_));
+ altitude_angle_ = PointerEventUtil::AltitudeFromTilt(
+ PointerEventUtil::TransformToTiltInValidRange(tilt_x_),
+ PointerEventUtil::TransformToTiltInValidRange(tilt_y_));
+ }
+ if ((initializer->hasAzimuthAngle() || initializer->hasAltitudeAngle()) &&
+ !initializer->hasTiltX() && !initializer->hasTiltY()) {
+ tilt_x_ = PointerEventUtil::TiltXFromSpherical(
+ PointerEventUtil::TransformToAzimuthInValidRange(azimuth_angle_),
+ PointerEventUtil::TransformToAltitudeInValidRange(altitude_angle_));
+ tilt_y_ = PointerEventUtil::TiltYFromSpherical(
+ PointerEventUtil::TransformToAzimuthInValidRange(azimuth_angle_),
+ PointerEventUtil::TransformToAltitudeInValidRange(altitude_angle_));
}
}
@@ -100,11 +99,22 @@ bool PointerEvent::IsMouseEvent() const {
return false;
}
+bool PointerEvent::ShouldHaveIntegerCoordinates() const {
+ if (RuntimeEnabledFeatures::ClickPointerEventIntegerCoordinatesEnabled() &&
+ (type() == event_type_names::kClick ||
+ type() == event_type_names::kContextmenu)) {
+ return true;
+ }
+ return false;
+}
+
bool PointerEvent::IsPointerEvent() const {
return true;
}
double PointerEvent::offsetX() const {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::offsetX();
if (!HasPosition())
return 0;
if (!has_cached_relative_position_)
@@ -113,6 +123,8 @@ double PointerEvent::offsetX() const {
}
double PointerEvent::offsetY() const {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::offsetY();
if (!HasPosition())
return 0;
if (!has_cached_relative_position_)
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event.h b/chromium/third_party/blink/renderer/core/events/pointer_event.h
index d03d9976f18..de54b4e6cff 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event.h
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event.h
@@ -13,14 +13,14 @@ namespace blink {
class PointerEventInit;
-class CORE_EXPORT PointerEvent final : public MouseEvent {
+class CORE_EXPORT PointerEvent : public MouseEvent {
DEFINE_WRAPPERTYPEINFO();
public:
static PointerEvent* Create(
const AtomicString& type,
const PointerEventInit* initializer,
- base::TimeTicks platform_time_stamp,
+ base::TimeTicks platform_time_stamp = base::TimeTicks::Now(),
MouseEvent::SyntheticEventType synthetic_event_type =
kRealOrIndistinguishable,
WebMenuSourceType menu_source_type = kMenuSourceNone) {
@@ -28,16 +28,12 @@ class CORE_EXPORT PointerEvent final : public MouseEvent {
type, initializer, platform_time_stamp, synthetic_event_type,
menu_source_type);
}
- static PointerEvent* Create(const AtomicString& type,
- const PointerEventInit* initializer) {
- return PointerEvent::Create(type, initializer, base::TimeTicks::Now());
- }
PointerEvent(const AtomicString&,
const PointerEventInit*,
base::TimeTicks platform_time_stamp,
MouseEvent::SyntheticEventType synthetic_event_type,
- WebMenuSourceType menu_source_type);
+ WebMenuSourceType menu_source_type = kMenuSourceNone);
PointerId pointerId() const { return pointer_id_; }
double width() const { return width_; }
@@ -56,12 +52,36 @@ class CORE_EXPORT PointerEvent final : public MouseEvent {
bool IsMouseEvent() const override;
bool IsPointerEvent() const override;
- double screenX() const override { return screen_location_.X(); }
- double screenY() const override { return screen_location_.Y(); }
- double clientX() const override { return client_location_.X(); }
- double clientY() const override { return client_location_.Y(); }
- double pageX() const override { return page_location_.X(); }
- double pageY() const override { return page_location_.Y(); }
+ double screenX() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::screenX();
+ return screen_location_.X();
+ }
+ double screenY() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::screenY();
+ return screen_location_.Y();
+ }
+ double clientX() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::clientX();
+ return client_location_.X();
+ }
+ double clientY() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::clientY();
+ return client_location_.Y();
+ }
+ double pageX() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::pageX();
+ return page_location_.X();
+ }
+ double pageY() const override {
+ if (ShouldHaveIntegerCoordinates())
+ return MouseEvent::pageY();
+ return page_location_.Y();
+ }
double offsetX() const override;
double offsetY() const override;
@@ -82,6 +102,8 @@ class CORE_EXPORT PointerEvent final : public MouseEvent {
void Trace(Visitor*) const override;
private:
+ bool ShouldHaveIntegerCoordinates() const;
+
PointerId pointer_id_;
double width_;
double height_;
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event.idl b/chromium/third_party/blink/renderer/core/events/pointer_event.idl
index 39e7ad8ff72..60bc5ec7b2c 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event.idl
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event.idl
@@ -14,8 +14,8 @@
[MeasureAs=PointerEventAttributeCount] readonly attribute float pressure;
[MeasureAs=PointerEventAttributeCount] readonly attribute long tiltX;
[MeasureAs=PointerEventAttributeCount] readonly attribute long tiltY;
- [RuntimeEnabled=AzimuthAltitude, Measure] readonly attribute double azimuthAngle;
- [RuntimeEnabled=AzimuthAltitude, Measure] readonly attribute double altitudeAngle;
+ [MeasureAs=PointerEventAttributeCount] readonly attribute double azimuthAngle;
+ [MeasureAs=PointerEventAttributeCount] readonly attribute double altitudeAngle;
[MeasureAs=PointerEventAttributeCount] readonly attribute float tangentialPressure;
[MeasureAs=PointerEventAttributeCount] readonly attribute long twist;
[MeasureAs=PointerEventAttributeCount] readonly attribute DOMString pointerType;
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event_init.idl b/chromium/third_party/blink/renderer/core/events/pointer_event_init.idl
index ef9620ecb76..a1888c788d4 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event_init.idl
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event_init.idl
@@ -11,8 +11,8 @@ dictionary PointerEventInit : MouseEventInit {
float pressure = 0;
long tiltX;
long tiltY;
- [RuntimeEnabled=AzimuthAltitude] double azimuthAngle;
- [RuntimeEnabled=AzimuthAltitude] double altitudeAngle;
+ double azimuthAngle;
+ double altitudeAngle;
float tangentialPressure = 0;
long twist = 0;
DOMString pointerType = "";
diff --git a/chromium/third_party/blink/renderer/core/events/pointer_event_util.h b/chromium/third_party/blink/renderer/core/events/pointer_event_util.h
index b3cb2b4d0df..53707c46902 100644
--- a/chromium/third_party/blink/renderer/core/events/pointer_event_util.h
+++ b/chromium/third_party/blink/renderer/core/events/pointer_event_util.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
+
class CORE_EXPORT PointerEventUtil {
public:
PointerEventUtil() = delete;
@@ -31,6 +32,7 @@ class CORE_EXPORT PointerEventUtil {
// altitude = altitude_radians - k*PI/2
static double TransformToAltitudeInValidRange(double altitude_radians);
};
+
} // namespace blink
-#endif
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_POINTER_EVENT_UTIL_H_
diff --git a/chromium/third_party/blink/renderer/core/events/promise_rejection_event.h b/chromium/third_party/blink/renderer/core/events/promise_rejection_event.h
index 4dfbd60087f..bb3aae1019b 100644
--- a/chromium/third_party/blink/renderer/core/events/promise_rejection_event.h
+++ b/chromium/third_party/blink/renderer/core/events/promise_rejection_event.h
@@ -32,6 +32,7 @@ class CORE_EXPORT PromiseRejectionEvent final : public Event {
PromiseRejectionEvent(ScriptState*,
const AtomicString&,
const PromiseRejectionEventInit*);
+ ~PromiseRejectionEvent() override;
ScriptValue reason(ScriptState*) const;
ScriptPromise promise(ScriptState*) const;
@@ -45,8 +46,6 @@ class CORE_EXPORT PromiseRejectionEvent final : public Event {
void Trace(Visitor*) const override;
private:
- ~PromiseRejectionEvent() override;
-
scoped_refptr<DOMWrapperWorld> world_;
TraceWrapperV8Reference<v8::Value> promise_;
TraceWrapperV8Reference<v8::Value> reason_;
diff --git a/chromium/third_party/blink/renderer/core/events/simulated_event_util.cc b/chromium/third_party/blink/renderer/core/events/simulated_event_util.cc
new file mode 100644
index 00000000000..5042c526243
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/simulated_event_util.cc
@@ -0,0 +1,207 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/events/simulated_event_util.h"
+
+#include "base/time/time.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_mouse_event_init.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_pointer_event_init.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_ui_event_init.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/events/mouse_event.h"
+#include "third_party/blink/renderer/core/events/pointer_event.h"
+#include "third_party/blink/renderer/core/events/pointer_event_factory.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/input/input_device_capabilities.h"
+#include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/map_coordinates_flags.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/platform/geometry/int_point.h"
+#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink {
+
+namespace {
+
+void PopulateMouseEventInitCoordinates(
+ Node& node,
+ MouseEventInit* initializer,
+ SimulatedClickCreationScope creation_scope) {
+ Element* element = DynamicTo<Element>(node);
+ LocalDOMWindow* dom_window = node.GetDocument().domWindow();
+
+ if (element && dom_window && element->GetLayoutObject() &&
+ element->GetLayoutBox() &&
+ creation_scope == SimulatedClickCreationScope::kFromAccessibility) {
+ // If we have an element we will set coordinates to the center of the
+ // element.
+ // TODO(crbug.com/1171924): User Agent Simulated Clicks should change
+ // hover states, fire events like mouseout/mouseover etc.
+ LayoutBox* layout_box = element->GetLayoutBox();
+ LayoutObject* layout_object = element->GetLayoutObject();
+ PhysicalOffset center = layout_box->PhysicalBorderBoxRect().Center();
+ PhysicalOffset root_frame_center = layout_object->LocalToAncestorPoint(
+ center, nullptr, MapCoordinatesMode::kTraverseDocumentBoundaries);
+ PhysicalOffset frame_center =
+ dom_window->GetFrame()->View()->ConvertFromRootFrame(root_frame_center);
+ IntPoint frame_center_point = RoundedIntPoint(frame_center);
+ // We are only interested in the top left corner.
+ IntRect center_rect(frame_center_point.X(), frame_center_point.Y(), 1, 1);
+ IntPoint screen_center = dom_window->GetFrame()
+ ->View()
+ ->FrameToScreen(center_rect)
+ .MinXMinYCorner();
+
+ initializer->setScreenX(
+ AdjustForAbsoluteZoom::AdjustInt(screen_center.X(), layout_object));
+ initializer->setScreenY(
+ AdjustForAbsoluteZoom::AdjustInt(screen_center.Y(), layout_object));
+ initializer->setClientX(AdjustForAbsoluteZoom::AdjustInt(
+ frame_center_point.X(), layout_object));
+ initializer->setClientY(AdjustForAbsoluteZoom::AdjustInt(
+ frame_center_point.Y(), layout_object));
+ }
+}
+
+void PopulateSimulatedMouseEventInit(
+ const AtomicString& event_type,
+ Node& node,
+ const Event* underlying_event,
+ MouseEventInit* initializer,
+ SimulatedClickCreationScope creation_scope) {
+ WebInputEvent::Modifiers modifiers = WebInputEvent::kNoModifiers;
+ if (const UIEventWithKeyState* key_state_event =
+ FindEventWithKeyState(underlying_event)) {
+ modifiers = key_state_event->GetModifiers();
+ }
+
+ PopulateMouseEventInitCoordinates(node, initializer, creation_scope);
+ LocalDOMWindow* dom_window = node.GetDocument().domWindow();
+ if (const auto* mouse_event = DynamicTo<MouseEvent>(underlying_event)) {
+ initializer->setScreenX(mouse_event->screen_location_.X());
+ initializer->setScreenY(mouse_event->screen_location_.Y());
+ initializer->setSourceCapabilities(
+ dom_window
+ ? dom_window->GetInputDeviceCapabilities()->FiresTouchEvents(false)
+ : nullptr);
+ }
+
+ initializer->setBubbles(true);
+ initializer->setCancelable(true);
+ initializer->setView(dom_window);
+ initializer->setComposed(true);
+ UIEventWithKeyState::SetFromWebInputEventModifiers(initializer, modifiers);
+ initializer->setButtons(
+ MouseEvent::WebInputEventModifiersToButtons(modifiers));
+}
+
+enum class EventClassType { kMouse, kPointer };
+
+MouseEvent* CreateMouseOrPointerEvent(
+ EventClassType event_class_type,
+ const AtomicString& event_type,
+ Node& node,
+ const Event* underlying_event,
+ SimulatedClickCreationScope creation_scope) {
+ // We picked |PointerEventInit| object to be able to create either
+ // |MouseEvent| or |PointerEvent| below. When a |PointerEvent| is created,
+ // any event attributes not initialized in the |PointerEventInit| below get
+ // their default values, all of which are appropriate for a simulated
+ // |PointerEvent|.
+ //
+ // TODO(mustaq): Set |pointerId| to -1 after we have a spec change to fix the
+ // issue https://github.com/w3c/pointerevents/issues/343.
+ PointerEventInit* initializer = PointerEventInit::Create();
+ PopulateSimulatedMouseEventInit(event_type, node, underlying_event,
+ initializer, creation_scope);
+
+ base::TimeTicks timestamp = underlying_event
+ ? underlying_event->PlatformTimeStamp()
+ : base::TimeTicks::Now();
+ MouseEvent::SyntheticEventType synthetic_type = MouseEvent::kPositionless;
+ if (const auto* mouse_event = DynamicTo<MouseEvent>(underlying_event)) {
+ synthetic_type = MouseEvent::kRealOrIndistinguishable;
+ }
+ if (creation_scope == SimulatedClickCreationScope::kFromAccessibility &&
+ (event_type == event_type_names::kClick ||
+ event_type == event_type_names::kPointerdown ||
+ event_type == event_type_names::kMousedown)) {
+ // Set primary button pressed.
+ initializer->setButton(
+ static_cast<int>(WebPointerProperties::Button::kLeft));
+ initializer->setButtons(MouseEvent::WebInputEventModifiersToButtons(
+ WebInputEvent::Modifiers::kLeftButtonDown));
+ }
+ if (creation_scope == SimulatedClickCreationScope::kFromAccessibility &&
+ event_type == event_type_names::kClick) {
+ // Set number of clicks for click event.
+ initializer->setDetail(1);
+ }
+
+ MouseEvent* created_event;
+ if (event_class_type == EventClassType::kPointer) {
+ if (creation_scope == SimulatedClickCreationScope::kFromAccessibility) {
+ initializer->setPointerId(PointerEventFactory::kMouseId);
+ initializer->setPointerType("mouse");
+ initializer->setIsPrimary(true);
+ }
+ created_event = MakeGarbageCollected<PointerEvent>(
+ event_type, initializer, timestamp, synthetic_type);
+ } else {
+ created_event = MakeGarbageCollected<MouseEvent>(event_type, initializer,
+ timestamp, synthetic_type);
+ }
+
+ created_event->SetTrusted(
+ creation_scope == SimulatedClickCreationScope::kFromUserAgent ||
+ creation_scope == SimulatedClickCreationScope::kFromAccessibility);
+ created_event->SetUnderlyingEvent(underlying_event);
+ if (synthetic_type == MouseEvent::kRealOrIndistinguishable) {
+ auto* mouse_event = To<MouseEvent>(created_event->UnderlyingEvent());
+ created_event->InitCoordinates(mouse_event->client_location_.X(),
+ mouse_event->client_location_.Y());
+ }
+
+ return created_event;
+}
+
+} // namespace
+
+Event* SimulatedEventUtil::CreateEvent(
+ const AtomicString& event_type,
+ Node& node,
+ const Event* underlying_event,
+ SimulatedClickCreationScope creation_scope) {
+ DCHECK(event_type == event_type_names::kClick ||
+ event_type == event_type_names::kMousedown ||
+ event_type == event_type_names::kMouseup ||
+ event_type == event_type_names::kPointerdown ||
+ event_type == event_type_names::kPointerup);
+
+ EventClassType event_class_type = EventClassType::kMouse;
+ if ((RuntimeEnabledFeatures::ClickPointerEventEnabled() &&
+ event_type == event_type_names::kClick) ||
+ event_type == event_type_names::kPointerdown ||
+ event_type == event_type_names::kPointerup) {
+ event_class_type = EventClassType::kPointer;
+ }
+
+ return CreateMouseOrPointerEvent(event_class_type, event_type, node,
+ underlying_event, creation_scope);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/events/simulated_event_util.h b/chromium/third_party/blink/renderer/core/events/simulated_event_util.h
new file mode 100644
index 00000000000..4624a586d33
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/events/simulated_event_util.h
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.sy
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_SIMULATED_EVENT_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_SIMULATED_EVENT_UTIL_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink {
+
+class CORE_EXPORT SimulatedEventUtil {
+ public:
+ SimulatedEventUtil() = delete;
+
+ static Event* CreateEvent(const AtomicString& event_type,
+ Node& node,
+ const Event* underlying_event,
+ SimulatedClickCreationScope creation_scope);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_SIMULATED_EVENT_UTIL_H_
diff --git a/chromium/third_party/blink/renderer/core/events/wheel_event.cc b/chromium/third_party/blink/renderer/core/events/wheel_event.cc
index 04fe7967e42..86f9e24198a 100644
--- a/chromium/third_party/blink/renderer/core/events/wheel_event.cc
+++ b/chromium/third_party/blink/renderer/core/events/wheel_event.cc
@@ -86,6 +86,7 @@ WheelEvent* WheelEvent::Create(const WebMouseWheelEvent& event,
WheelEvent::WheelEvent()
: delta_x_(0), delta_y_(0), delta_z_(0), delta_mode_(kDomDeltaPixel) {}
+// crbug.com/1173525: tweak the initialization behavior.
WheelEvent::WheelEvent(const AtomicString& type,
const WheelEventInit* initializer)
: MouseEvent(type, initializer),
@@ -95,12 +96,12 @@ WheelEvent::WheelEvent(const AtomicString& type,
initializer->wheelDeltaY()
? initializer->wheelDeltaY()
: static_cast<int32_t>(initializer->deltaY())),
- delta_x_(initializer->deltaX()
- ? initializer->deltaX()
- : -static_cast<int32_t>(initializer->wheelDeltaX())),
- delta_y_(initializer->deltaY()
- ? initializer->deltaY()
- : -static_cast<int32_t>(initializer->wheelDeltaY())),
+ delta_x_(initializer->deltaX() ? initializer->deltaX()
+ : clampTo<int32_t>(-static_cast<double>(
+ initializer->wheelDeltaX()))),
+ delta_y_(initializer->deltaY() ? initializer->deltaY()
+ : clampTo<int32_t>(-static_cast<double>(
+ initializer->wheelDeltaY()))),
delta_z_(initializer->deltaZ()),
delta_mode_(initializer->deltaMode()) {}
diff --git a/chromium/third_party/blink/renderer/core/execution_context/DEPS b/chromium/third_party/blink/renderer/core/execution_context/DEPS
new file mode 100644
index 00000000000..292eac72df0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/execution_context/DEPS
@@ -0,0 +1,7 @@
+specific_include_rules = {
+ "agent_metrics_collector\.cc": [
+ # Intentionally limited to scope to encourage use of histogram helpers over
+ # the raw factory getters.
+ "+base/metrics/histogram_base.h",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/core/execution_context/DIR_METADATA b/chromium/third_party/blink/renderer/core/execution_context/DIR_METADATA
new file mode 100644
index 00000000000..622ef56a4e2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/execution_context/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Internals>Frames"
+}
+
+team_email: "platform-architecture-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/execution_context/OWNERS b/chromium/third_party/blink/renderer/core/execution_context/OWNERS
index 1c887596d62..40edfd4ccd8 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/OWNERS
+++ b/chromium/third_party/blink/renderer/core/execution_context/OWNERS
@@ -2,6 +2,3 @@
#
# The owner list is made intentionally empty.
# Ask core/OWNERS for code reviews.
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>Frames
diff --git a/chromium/third_party/blink/renderer/core/execution_context/agent.cc b/chromium/third_party/blink/renderer/core/execution_context/agent.cc
index d869d6a91d2..f78f0e7bd89 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/agent.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/agent.cc
@@ -52,19 +52,24 @@ void Agent::SetIsCrossOriginIsolated(bool value) {
is_cross_origin_isolated = value;
}
-bool Agent::IsOriginIsolated() {
+bool Agent::IsOriginKeyed() {
+ if (IsCrossOriginIsolated()) {
+ return true;
+ }
+
#if DCHECK_IS_ON()
- DCHECK(is_origin_isolated_set_);
+ DCHECK(is_explicitly_origin_keyed_set_);
#endif
- return is_origin_isolated_;
+ return is_explicitly_origin_keyed_;
}
-void Agent::SetIsOriginIsolated(bool value) {
+void Agent::SetIsExplicitlyOriginKeyed(bool value) {
#if DCHECK_IS_ON()
- DCHECK(!is_origin_isolated_set_ || value == is_origin_isolated_);
- is_origin_isolated_set_ = true;
+ DCHECK(!is_explicitly_origin_keyed_set_ ||
+ value == is_explicitly_origin_keyed_);
+ is_explicitly_origin_keyed_set_ = true;
#endif
- is_origin_isolated_ = value;
+ is_explicitly_origin_keyed_ = value;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/execution_context/agent.h b/chromium/third_party/blink/renderer/core/execution_context/agent.h
index 41b19292ab6..8622de656cd 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/agent.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/agent.h
@@ -62,27 +62,35 @@ class CORE_EXPORT Agent : public GarbageCollected<Agent> {
// Only called from blink::SetIsCrossOriginIsolated.
static void SetIsCrossOriginIsolated(bool value);
- // Representing agent cluster's "origin isolated" concept.
- // https://github.com/whatwg/html/pull/5545
- // TODO(domenic): update to final spec URL when that pull request is merged.
+ // Representing agent cluster's "is origin-keyed" concept:
+ // https://html.spec.whatwg.org/C/#is-origin-keyed
//
// Note that unlike IsCrossOriginIsolated(), this is not static/process-global
// because we do not guarantee that a given process only contains agents with
- // the same origin-isolation status.
+ // the same origin-keying status.
//
- // For example, a page with no Origin-Isolation header, that uses a data: URL
- // to create an iframe, would have an origin-isolated data: URL Agent, plus a
- // non-origin-isolated outer page Agent, both in the same process.
- bool IsOriginIsolated();
- void SetIsOriginIsolated(bool value);
+ // For example, a page with no Origin-Agent-Cluster header, that uses a data:
+ // URL to create an iframe, would have an origin-keyed data: URL Agent,
+ // plus a site-keyed outer page Agent, both in the same process.
+ bool IsOriginKeyed();
+
+ // TODO(domenic,wjmaclean): once logical cross-origin isolation is implemented
+ // and unified with origin-keyed agent clusters, then this should no longer be
+ // necessary; we can just check IsOriginKeyed().
+ bool IsExplicitlyOriginKeyed() const { return is_explicitly_origin_keyed_; }
+
+ // This sets whether the agent cluster is explicitly requested to be
+ // origin-keyed via the Origin-Agent-Cluster header. It can also be
+ // implicitly origin-keyed if it is in a cross-origin isolated agent cluster.
+ void SetIsExplicitlyOriginKeyed(bool value);
private:
scoped_refptr<scheduler::EventLoop> event_loop_;
const base::UnguessableToken cluster_id_;
- bool is_origin_isolated_ = false;
+ bool is_explicitly_origin_keyed_ = false;
#if DCHECK_IS_ON()
- bool is_origin_isolated_set_ = false;
+ bool is_explicitly_origin_keyed_set_ = false;
#endif
};
diff --git a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.cc b/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.cc
deleted file mode 100644
index 18eff6efba3..00000000000
--- a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.cc
+++ /dev/null
@@ -1,179 +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/core/execution_context/agent_metrics_collector.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/default_tick_clock.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/scheduler/web_thread_scheduler.h"
-#include "third_party/blink/renderer/core/execution_context/window_agent.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
-#include "third_party/blink/renderer/platform/web_test_support.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-using WTF::HashSet;
-using WTF::String;
-using WTF::Vector;
-
-namespace blink {
-
-namespace {
-
-const char kAgentsPerRendererByTimeHistogram[] =
- "PerformanceManager.AgentsPerRendererByTime";
-
-base::TimeDelta kReportingInterval = base::TimeDelta::FromMinutes(5);
-
-} // namespace
-
-AgentMetricsCollector::AgentMetricsCollector()
- : reporting_timer_(std::make_unique<TaskRunnerTimer<AgentMetricsCollector>>(
- // Some tests might not have a MainThreadScheduler.
- scheduler::WebThreadScheduler::MainThreadScheduler()
- ? scheduler::WebThreadScheduler::MainThreadScheduler()
- ->DefaultTaskRunner()
- : nullptr,
- this,
- &AgentMetricsCollector::ReportingTimerFired)),
- clock_(base::DefaultTickClock::GetInstance()) {
- // From now until we call CreatedNewAgent will be reported as having 0
- // agents.
- time_last_reported_ = clock_->NowTicks();
-}
-
-AgentMetricsCollector::~AgentMetricsCollector() {
- // Note: This won't be called during a fast-shutdown (i.e. tab closed). We
- // manually call it from Page::WillBeDestroyed().
- ReportMetrics();
-}
-
-void AgentMetricsCollector::DidAttachWindow(const LocalDOMWindow& window) {
- ReportMetrics();
-
- AgentToWindowsMap::AddResult result =
- agent_to_windows_map_.insert(window.GetAgent(), nullptr);
- if (result.is_new_entry)
- result.stored_value->value = MakeGarbageCollected<WindowSet>();
-
- result.stored_value->value->insert(&window);
-
- ReportToBrowser();
-}
-
-void AgentMetricsCollector::DidDetachWindow(const LocalDOMWindow& window) {
- ReportMetrics();
-
- auto agent_itr = agent_to_windows_map_.find(window.GetAgent());
- DCHECK(agent_itr != agent_to_windows_map_.end());
-
- WindowSet& windows = *agent_itr->value.Get();
- auto window_itr = windows.find(&window);
- DCHECK(window_itr != windows.end());
-
- windows.erase(window_itr);
-
- if (windows.IsEmpty())
- agent_to_windows_map_.erase(agent_itr);
-
- ReportToBrowser();
-}
-
-void AgentMetricsCollector::ReportMetrics() {
- DCHECK(!time_last_reported_.is_null());
-
- // Don't run the timer in tests. Doing so causes tests that RunUntilIdle to
- // never exit.
- if (!reporting_timer_->IsActive() && !WebTestSupport::IsRunningWebTest()) {
- reporting_timer_->StartRepeating(kReportingInterval, FROM_HERE);
- }
-
- // This computation and reporting is based on the one in
- // chrome/browser/performance_manager/observers/isolation_context_metrics.cc.
- base::TimeTicks now = clock_->NowTicks();
-
- base::TimeDelta elapsed = now - time_last_reported_;
- time_last_reported_ = now;
-
- // Account for edge cases like hibernate/sleep. See
- // GetSecondsSinceLastReportAndUpdate in isolation_context_metrics.cc
- if (elapsed >= 2 * kReportingInterval)
- elapsed = base::TimeDelta();
-
- int to_add = static_cast<int>(std::round(elapsed.InSecondsF()));
-
- // Time can be negative in tests when we replace the clock_.
- if (to_add <= 0)
- return;
-
- AddTimeToTotalAgents(to_add);
-}
-
-void AgentMetricsCollector::AddTimeToTotalAgents(int time_delta_to_add) {
- DEFINE_STATIC_LOCAL(LinearHistogram, agents_per_renderer_histogram,
- (kAgentsPerRendererByTimeHistogram, 1, 100, 101));
- agents_per_renderer_histogram.CountMany(agent_to_windows_map_.size(),
- time_delta_to_add);
-}
-
-void AgentMetricsCollector::ReportToBrowser() {
- Vector<String> agents;
- for (const auto& kv : agent_to_windows_map_) {
- const Member<WindowSet>& window_set = kv.value;
-
- String tuple_origin;
- DCHECK(!window_set->IsEmpty());
- const auto& window = *window_set->begin();
- auto* security_origin = window->GetSecurityOrigin();
- if (security_origin && !security_origin->IsOpaque() &&
- !security_origin->IsLocal()) {
- // We shouldn't ever host multiple tuple-origins in an Agent. However,
- // this does happen in tests because we have
- // GetAllowUniversalAccessFromFileURLs enabled but that's ok in tests.
- tuple_origin = security_origin->Protocol() + "://" +
- security_origin->RegistrableDomain();
- } else {
- // We use an empty string to specify that there isn't any one
- // tuple-origin this agent represents. This will typically be for
- // file:// or opaque origins. We shouldn't ever host multiple sites
- // inside an agent.
- tuple_origin = "";
- }
-
- agents.push_back(tuple_origin);
- }
-
- mojom::blink::AgentMetricsDataPtr data =
- mojom::blink::AgentMetricsData::New();
- data->agents = agents;
-
- GetAgentMetricsCollectorHost()->ReportRendererMetrics(std::move(data));
-}
-
-void AgentMetricsCollector::ReportingTimerFired(TimerBase*) {
- ReportMetrics();
- ReportToBrowser();
-}
-
-blink::mojom::blink::AgentMetricsCollectorHost*
-AgentMetricsCollector::GetAgentMetricsCollectorHost() {
- if (!agent_metrics_collector_host_.is_bound()) {
- blink::Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- agent_metrics_collector_host_.BindNewPipeAndPassReceiver(
- ThreadScheduler::Current()->DeprecatedDefaultTaskRunner()));
- }
- return agent_metrics_collector_host_.get();
-}
-
-void AgentMetricsCollector::Trace(Visitor* visitor) const {
- visitor->Trace(agent_to_windows_map_);
- visitor->Trace(agent_metrics_collector_host_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.h b/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.h
deleted file mode 100644
index f031291f2e2..00000000000
--- a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector.h
+++ /dev/null
@@ -1,88 +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_CORE_EXECUTION_CONTEXT_AGENT_METRICS_COLLECTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_AGENT_METRICS_COLLECTOR_H_
-
-#include "base/time/time.h"
-#include "third_party/blink/public/mojom/agents/agent_metrics.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/timer.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace blink {
-
-class Agent;
-class LocalDOMWindow;
-class TimerBase;
-
-// This class tracks agent-related metrics for reporting in TRACE and UMA
-// metrics. It listens for windows being attached/detached to an execution
-// context and tracks which agent these windows are associated with.
-//
-// We report metrics periodically to track how long we spent in any given state.
-// For example, suppose that for 10 seconds a page had just one agent, then an
-// ad frame loads causing a windows to load with a second agent. After 5
-// seconds, the user closes the browser. In this case, we report:
-//
-// Histogram
-// 1 ----------O 10
-// 2 -----O 5
-//
-// We therefore keep track of how much time has elapsed since the previous
-// report. Metrics are reported whenever a windows is added or removed, as
-// well as at a regular interval.
-//
-// This class is based on the metrics tracked in:
-// chrome/browser/performance_manager/observers/isolation_context_metrics.cc
-// It should eventually be migrated to that place.
-class AgentMetricsCollector final
- : public GarbageCollected<AgentMetricsCollector> {
- public:
- AgentMetricsCollector();
- ~AgentMetricsCollector();
-
- void DidAttachWindow(const LocalDOMWindow&);
- void DidDetachWindow(const LocalDOMWindow&);
-
- void ReportMetrics();
-
- void SetTickClockForTesting(const base::TickClock* clock) { clock_ = clock; }
-
- void Trace(Visitor*) const;
-
- private:
- void AddTimeToTotalAgents(int time_delta_to_add);
- void ReportToBrowser();
-
- void ReportingTimerFired(TimerBase*);
-
- blink::mojom::blink::AgentMetricsCollectorHost*
- GetAgentMetricsCollectorHost();
-
- std::unique_ptr<TaskRunnerTimer<AgentMetricsCollector>> reporting_timer_;
- base::TimeTicks time_last_reported_;
-
- // Keep a map from each agent to all the windows associated with that
- // agent. When the last window from the set is removed, we delete the key
- // from the map.
- using WindowSet = HeapHashSet<WeakMember<const LocalDOMWindow>>;
- using AgentToWindowsMap = HeapHashMap<WeakMember<Agent>, Member<WindowSet>>;
- AgentToWindowsMap agent_to_windows_map_;
-
- const base::TickClock* clock_;
-
- // AgentMetricsCollector is not tied to ExecutionContext
- HeapMojoRemote<blink::mojom::blink::AgentMetricsCollectorHost,
- HeapMojoWrapperMode::kWithoutContextObserver>
- agent_metrics_collector_host_{nullptr};
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_AGENT_METRICS_COLLECTOR_H_
diff --git a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector_test.cc b/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector_test.cc
deleted file mode 100644
index 0e31e2823bb..00000000000
--- a/chromium/third_party/blink/renderer/core/execution_context/agent_metrics_collector_test.cc
+++ /dev/null
@@ -1,181 +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/core/execution_context/agent_metrics_collector.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/time/default_tick_clock.h"
-#include "testing/gtest/include/gtest/gtest.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/location.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
-#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
-#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-
-namespace blink {
-
-class AgentMetricsCollectorUnitTest : public SimTest {
- public:
- AgentMetricsCollectorUnitTest() = default;
-
- void SetUp() override {
- SimTest::SetUp();
-
- tick_clock_.SetNowTicks(base::TimeTicks::Now());
-
- // Tests turn this on but it would force all frames into a single agent.
- // Turn it off so we get an agent per-origin.
- WebView().GetPage()->GetSettings().SetAllowUniversalAccessFromFileURLs(
- false);
-
- WebView().GetPage()->GetAgentMetricsCollector()->SetTickClockForTesting(
- &tick_clock_);
- WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
- }
-
- void TearDown() override {
- if (!torn_down_) {
- // Avoid UAF when tick_clock_ is destroyed.
- auto* collector = WebView().GetPage()->GetAgentMetricsCollector();
-
- SimTest::TearDown();
- torn_down_ = true;
-
- collector->SetTickClockForTesting(base::DefaultTickClock::GetInstance());
- }
- }
-
- bool torn_down_ = false;
-
- HistogramTester tester_;
- const char* kHistogramName = "PerformanceManager.AgentsPerRendererByTime";
-
- base::SimpleTestTickClock tick_clock_;
-};
-
-// Tests that we record samples across a navigation.
-TEST_F(AgentMetricsCollectorUnitTest, AgentsPerRendererRecordOnDocumentChange) {
- SimRequest request_a("https://example.com/a.html", "text/html");
- SimRequest request_b("https://example.com/b.html", "text/html");
-
- // Load the first page. The histogram won't yet have any data because it
- // records samples by time and only when documents are created/destroyed.
- // Immediately after we load a.html, no time has passed yet.
- LoadURL("https://example.com/a.html");
- request_a.Complete(R"HTML(
- <!DOCTYPE html>
- )HTML");
- Compositor().BeginFrame();
-
- tick_clock_.Advance(base::TimeDelta::FromSeconds(10));
-
- // Load the second page. Since 10 seconds have now elapsed, as the documents
- // are swapped we should see 10 samples recorded in the 1 agent bucket.
- LoadURL("https://example.com/b.html");
- request_b.Complete(R"HTML(
- <!DOCTYPE html>
- )HTML");
- Compositor().BeginFrame();
-
- tester_.ExpectUniqueSample(kHistogramName, 1, 10);
-}
-
-// Test that we correctly record the case where a second agent is added to the
-// page.
-TEST_F(AgentMetricsCollectorUnitTest, MultipleAgents) {
- SimRequest request_a("https://foo.com/a.html", "text/html");
- SimRequest request_b("https://bar.com/b.html", "text/html");
-
- // Load the first page. The histogram won't yet have any data because it
- // records samples by time and only when documents are created/destroyed.
- // Immediately after we load a.html, no time has passed yet.
- LoadURL("https://foo.com/a.html");
- request_a.Complete(R"HTML(
- <!DOCTYPE html>
- <iframe src="about:blank"></iframe>
- )HTML");
- Compositor().BeginFrame();
-
- tick_clock_.Advance(base::TimeDelta::FromSeconds(10));
-
- // Navigate to a cross-origin page, this should create a second agent.
- frame_test_helpers::LoadFrameDontWait(
- MainFrame().FirstChild()->ToWebLocalFrame(),
- KURL("https://bar.com/b.html"));
- request_b.Complete(R"HTML(
- <!DOCTYPE html>
- )HTML");
- tester_.ExpectBucketCount(kHistogramName, 1, 10);
-
- tick_clock_.Advance(base::TimeDelta::FromSeconds(20));
-
- // Simulate closing the page. This should cause us to report the metrics.
- TearDown();
-
- // The final 20 seconds had 2 agents.
- tester_.ExpectBucketCount(kHistogramName, 1, 10);
- tester_.ExpectBucketCount(kHistogramName, 2, 20);
-}
-
-// Ensure that multiple Pages in the same Agent are reported as only one agent.
-TEST_F(AgentMetricsCollectorUnitTest, WindowOpenSameAgents) {
- SimRequest request_a("https://example.com/a.html", "text/html");
- SimRequest request_b("https://example.com/b.html", "text/html");
-
- LoadURL("https://example.com/a.html");
- request_a.Complete(R"HTML(
- <!DOCTYPE html>
- <script>
- window.open('https://example.com/b.html');
- </script>
- )HTML");
- request_b.Complete(R"HTML(
- <!DOCTYPE html>
- )HTML");
- Compositor().BeginFrame();
-
- ASSERT_EQ(2u, Page::OrdinaryPages().size());
-
- tick_clock_.Advance(base::TimeDelta::FromSeconds(10));
-
- // Simulate closing the page. This should cause us to report the metrics.
- TearDown();
-
- // Both documents should end up in the same Agent, despite having separate
- // WebViews/Page.
- tester_.ExpectUniqueSample(kHistogramName, 1, 10);
-}
-
-// Ensure that multiple Pages in different Agents are reported as multiple
-// agents.
-TEST_F(AgentMetricsCollectorUnitTest, WindowOpenDifferentAgents) {
- SimRequest request_a("https://example.com/a.html", "text/html");
- SimRequest request_b("https://different.com/a.html", "text/html");
-
- LoadURL("https://example.com/a.html");
- request_a.Complete(R"HTML(
- <!DOCTYPE html>
- <script>
- window.open('https://different.com/a.html');
- </script>
- )HTML");
- request_b.Complete(R"HTML(
- <!DOCTYPE html>
- )HTML");
- Compositor().BeginFrame();
-
- ASSERT_EQ(2u, Page::OrdinaryPages().size());
-
- tick_clock_.Advance(base::TimeDelta::FromSeconds(10));
-
- // Simulate closing the page. This should cause us to report the metrics.
- TearDown();
-
- // Each document should have its own Agent.
- tester_.ExpectUniqueSample(kHistogramName, 2, 10);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/execution_context/build.gni b/chromium/third_party/blink/renderer/core/execution_context/build.gni
index 85f3a39da7d..6e4069fde9a 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/build.gni
+++ b/chromium/third_party/blink/renderer/core/execution_context/build.gni
@@ -5,14 +5,13 @@
blink_core_sources_execution_context = [
"agent.cc",
"agent.h",
- "agent_metrics_collector.cc",
- "agent_metrics_collector.h",
"execution_context.cc",
"execution_context.h",
"execution_context_lifecycle_observer.cc",
"execution_context_lifecycle_observer.h",
"execution_context_lifecycle_state_observer.cc",
"execution_context_lifecycle_state_observer.h",
+ "navigator_base.h",
"remote_security_context.cc",
"remote_security_context.h",
"security_context.cc",
diff --git a/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc b/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
index 644537afdfc..8ea3ef75412 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -28,7 +28,9 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
+#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -47,6 +49,7 @@
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_notifier.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/loader/fetch/fetch_client_settings_object_snapshot.h"
@@ -72,7 +75,9 @@ ExecutionContext::ExecutionContext(v8::Isolate* isolate, Agent* agent)
DCHECK(agent_);
}
-ExecutionContext::~ExecutionContext() = default;
+ExecutionContext::~ExecutionContext() {
+ DCHECK(is_context_destroyed_);
+}
// static
ExecutionContext* ExecutionContext::From(const ScriptState* script_state) {
@@ -123,7 +128,7 @@ void ExecutionContext::SetLifecycleState(mojom::FrameLifecycleState state) {
if (lifecycle_state_ == state)
return;
lifecycle_state_ = state;
- context_lifecycle_observer_set_.ForEachObserver(
+ ContextLifecycleNotifier::observers().ForEachObserver(
[&](ContextLifecycleObserver* observer) {
if (!observer->IsExecutionContextLifecycleObserver())
return;
@@ -145,30 +150,14 @@ void ExecutionContext::SetLifecycleState(mojom::FrameLifecycleState state) {
void ExecutionContext::NotifyContextDestroyed() {
is_context_destroyed_ = true;
- context_lifecycle_observer_set_.ForEachObserver(
- [](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- observer->ObserverSetWillBeCleared();
- });
- context_lifecycle_observer_set_.Clear();
-}
-
-void ExecutionContext::AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) {
- context_lifecycle_observer_set_.AddObserver(observer);
-}
-
-void ExecutionContext::RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) {
- DCHECK(context_lifecycle_observer_set_.HasObserver(observer));
- context_lifecycle_observer_set_.RemoveObserver(observer);
+ ContextLifecycleNotifier::NotifyContextDestroyed();
}
unsigned ExecutionContext::ContextLifecycleStateObserverCountForTesting()
const {
- DCHECK(!context_lifecycle_observer_set_.IsIteratingOverObservers());
+ DCHECK(!ContextLifecycleNotifier::observers().IsIteratingOverObservers());
unsigned lifecycle_state_observers = 0;
- context_lifecycle_observer_set_.ForEachObserver(
+ ContextLifecycleNotifier::observers().ForEachObserver(
[&](ContextLifecycleObserver* observer) {
if (!observer->IsExecutionContextLifecycleObserver())
return;
@@ -182,8 +171,67 @@ unsigned ExecutionContext::ContextLifecycleStateObserverCountForTesting()
}
bool ExecutionContext::SharedArrayBufferTransferAllowed() const {
- return RuntimeEnabledFeatures::SharedArrayBufferEnabled(this) ||
- CrossOriginIsolatedCapability();
+ if (RuntimeEnabledFeatures::SharedArrayBufferEnabled(this) ||
+ CrossOriginIsolatedCapability()) {
+ return true;
+ }
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return RuntimeEnabledFeatures::UnrestrictedSharedArrayBufferEnabled(this);
+#endif
+}
+
+namespace {
+mojom::blink::InspectorIssueInfoPtr CreateSharedArrayBufferIssue(
+ const SourceLocation* source_location) {
+ auto details = mojom::blink::InspectorIssueDetails::New();
+ auto issue_details = mojom::blink::SharedArrayBufferIssueDetails::New();
+ auto affected_location = mojom::blink::AffectedLocation::New();
+ affected_location->url = source_location->Url();
+ affected_location->line = source_location->LineNumber() - 1;
+ affected_location->column = source_location->ColumnNumber();
+ affected_location->script_id =
+ WTF::String::Number(source_location->ScriptId());
+ issue_details->affected_location = std::move(affected_location);
+ details->sab_issue_details = std::move(issue_details);
+ return mojom::blink::InspectorIssueInfo::New(
+ mojom::blink::InspectorIssueCode::kSharedArrayBufferIssue,
+ std::move(details));
+}
+} // namespace
+
+bool ExecutionContext::CheckSharedArrayBufferTransferAllowedAndReport() {
+ const bool allowed = SharedArrayBufferTransferAllowed();
+ // File an issue if the transfer is prohibited, or if it will be prohibited
+ // in the future, and the problem is encountered for the first time in this
+ // execution context. This preserves postMessage performance during the
+ // transition period.
+ if (!allowed || (!has_filed_shared_array_buffer_transfer_issue_ &&
+ !CrossOriginIsolatedCapability())) {
+ has_filed_shared_array_buffer_transfer_issue_ = true;
+ auto source_location = SourceLocation::Capture(this);
+ auto issue = CreateSharedArrayBufferIssue(source_location.get());
+ issue->details->sab_issue_details->is_warning = allowed;
+ issue->details->sab_issue_details->type =
+ mojom::blink::SharedArrayBufferIssueType::kTransferIssue;
+ AddInspectorIssue(std::move(issue));
+ }
+ return allowed;
+}
+
+void ExecutionContext::FileSharedArrayBufferCreationIssue() {
+ // This is performance critical, only do it once per context.
+ if (has_filed_shared_array_buffer_creation_issue_)
+ return;
+ has_filed_shared_array_buffer_creation_issue_ = true;
+ auto source_location = SourceLocation::Capture(this);
+ auto issue = CreateSharedArrayBufferIssue(source_location.get());
+ // In enforced mode, the SAB constructor isn't available.
+ issue->details->sab_issue_details->is_warning = true;
+ issue->details->sab_issue_details->type =
+ mojom::blink::SharedArrayBufferIssueType::kCreationIssue;
+ AddInspectorIssue(std::move(issue));
}
void ExecutionContext::AddConsoleMessageImpl(mojom::ConsoleMessageSource source,
@@ -355,47 +403,58 @@ String ExecutionContext::OutgoingReferrer() const {
}
void ExecutionContext::ParseAndSetReferrerPolicy(
- const String& policies,
- bool support_legacy_keywords,
- bool from_meta_tag_with_list_of_policies) {
+ const String& policy,
+ const ReferrerPolicySource source) {
network::mojom::ReferrerPolicy referrer_policy;
+ bool policy_is_valid = false;
+
+ if (source == kPolicySourceHttpHeader) {
+ policy_is_valid = SecurityPolicy::ReferrerPolicyFromHeaderValue(
+ policy, kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy);
+ } else if (source == kPolicySourceMetaTag) {
+ policy_is_valid = (SecurityPolicy::ReferrerPolicyFromString(
+ policy, kSupportReferrerPolicyLegacyKeywords, &referrer_policy));
+ } else {
+ NOTREACHED();
+ return;
+ }
+
+ if (policy_is_valid) {
+ SetReferrerPolicy(referrer_policy);
+ } else {
+ String error_reason;
+ if (source == kPolicySourceMetaTag && policy.Contains(',')) {
+ // Only a single token is permitted for Meta-specified policies
+ // (https://crbug.com/1093914).
+ error_reason =
+ "A policy specified by a meta element must contain only one token.";
+ } else {
+ error_reason =
+ "The value '" + policy + "' is not one of " +
+ ((source == kPolicySourceMetaTag)
+ ? "'always', 'default', 'never', 'origin-when-crossorigin', "
+ : "") +
+ "'no-referrer', 'no-referrer-when-downgrade', 'origin', "
+ "'origin-when-cross-origin', 'same-origin', 'strict-origin', "
+ "'strict-origin-when-cross-origin', or 'unsafe-url'.";
+ }
- if (!SecurityPolicy::ReferrerPolicyFromHeaderValue(
- policies,
- support_legacy_keywords ? kSupportReferrerPolicyLegacyKeywords
- : kDoNotSupportReferrerPolicyLegacyKeywords,
- &referrer_policy)) {
AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kRendering,
mojom::ConsoleMessageLevel::kError,
- "Failed to set referrer policy: The value '" + policies +
- "' is not one of " +
- (support_legacy_keywords
- ? "'always', 'default', 'never', 'origin-when-crossorigin', "
- : "") +
- "'no-referrer', 'no-referrer-when-downgrade', 'origin', "
- "'origin-when-cross-origin', 'same-origin', 'strict-origin', "
- "'strict-origin-when-cross-origin', or 'unsafe-url'. The referrer "
- "policy "
- "has been left unchanged."));
- return;
+ "Failed to set referrer policy: " + error_reason +
+ " The referrer policy has been left unchanged."));
}
-
- SetReferrerPolicy(referrer_policy, from_meta_tag_with_list_of_policies);
}
void ExecutionContext::SetReferrerPolicy(
- network::mojom::ReferrerPolicy referrer_policy,
- bool from_meta_tag_with_list_of_policies) {
+ network::mojom::ReferrerPolicy referrer_policy) {
// When a referrer policy has already been set, the latest value takes
// precedence.
UseCounter::Count(this, WebFeature::kSetReferrerPolicy);
if (referrer_policy_ != network::mojom::ReferrerPolicy::kDefault)
UseCounter::Count(this, WebFeature::kResetReferrerPolicy);
- if (!from_meta_tag_with_list_of_policies)
- referrer_policy_but_for_meta_tags_with_lists_of_policies_ = referrer_policy;
-
referrer_policy_ = referrer_policy;
}
@@ -410,7 +469,6 @@ void ExecutionContext::Trace(Visitor* visitor) const {
visitor->Trace(pending_exceptions_);
visitor->Trace(csp_delegate_);
visitor->Trace(timers_);
- visitor->Trace(context_lifecycle_observer_set_);
visitor->Trace(origin_trial_context_);
ContextLifecycleNotifier::Trace(visitor);
ConsoleLogger::Trace(visitor);
@@ -479,7 +537,7 @@ bool ExecutionContext::IsFeatureEnabled(
const String& source_file) const {
// The default value for any feature should be true unless restricted by
// document policy
- if (!RuntimeEnabledFeatures::DocumentPolicyEnabled(this))
+ if (!RuntimeEnabledFeatures::DocumentPolicyEnabled())
return true;
SecurityContext::FeatureStatus status =
diff --git a/chromium/third_party/blink/renderer/core/execution_context/execution_context.h b/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
index 050e047a163..5d405822100 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -37,11 +37,13 @@
#include "services/network/public/mojom/ip_address_space.mojom-blink-forward.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -54,13 +56,13 @@
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "v8/include/v8.h"
namespace base {
-class SingleThreadTaskRunner;
class UnguessableToken;
} // namespace base
@@ -71,7 +73,6 @@ class UkmRecorder;
namespace blink {
class Agent;
-class BrowserInterfaceBrokerProxy;
class ConsoleMessage;
class ContentSecurityPolicy;
class ContentSecurityPolicyDelegate;
@@ -91,13 +92,13 @@ class ScriptState;
class ScriptWrappable;
class TrustedTypePolicyFactory;
-enum class TaskType : unsigned char;
-
enum ReasonForCallingCanExecuteScripts {
kAboutToExecuteScript,
kNotAboutToExecuteScript
};
+enum ReferrerPolicySource { kPolicySourceHttpHeader, kPolicySourceMetaTag };
+
// An environment in which script can execute. This class exposes the common
// properties of script execution environments on the web (i.e, common between
// script executing in a window and script executing in a worker), such as:
@@ -121,7 +122,7 @@ enum ReasonForCallingCanExecuteScripts {
// by an extension developer, but these share an ExecutionContext (the window)
// in common.
class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
- public ContextLifecycleNotifier,
+ public MojoBindingContext,
public ConsoleLogger,
public UseCounter,
public FeatureContext {
@@ -186,6 +187,9 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
virtual KURL CompleteURL(const String& url) const = 0;
virtual void DisableEval(const String& error_message) = 0;
virtual String UserAgent() const = 0;
+ virtual UserAgentMetadata GetUserAgentMetadata() const {
+ return UserAgentMetadata();
+ }
virtual HttpsState GetHttpsState() const = 0;
@@ -213,6 +217,9 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
virtual bool CanExecuteScripts(ReasonForCallingCanExecuteScripts) {
return false;
}
+ virtual mojom::blink::V8CacheOptions GetV8CacheOptions() const {
+ return mojom::blink::V8CacheOptions::kDefault;
+ }
void DispatchErrorEvent(ErrorEvent*, SanitizeScriptErrors);
@@ -272,41 +279,24 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
virtual String OutgoingReferrer() const;
- // Parses a comma-separated list of referrer policy tokens, and sets
- // the context's referrer policy to the last one that is a valid
- // policy. Logs a message to the console if none of the policy
- // tokens are valid policies.
+ // Parses a referrer policy directive using either Header or Meta rules and
+ // sets the context to use that policy. If the supplied policy is invalid,
+ // the context's policy is unchanged and a message is logged to the console.
//
- // If |supportLegacyKeywords| is true, then the legacy keywords
- // "never", "default", "always", and "origin-when-crossorigin" are
- // parsed as valid policies.
- //
- // If |from_meta_tag_with_list_of_policies| is *false*, also updates
- // |referrer_policy_but_for_meta_tags_with_lists_of_policies_|, which
- // maintains a counterfactual to determine what the policy would look like if
- // we started ignoring <meta name=referrer content=policy1,policy2,...> tags
- // in order to align with the HTML standard (crbug.com/1092930).
- void ParseAndSetReferrerPolicy(
- const String& policies,
- bool support_legacy_keywords = false,
- bool from_meta_tag_with_list_of_policies = false);
- void SetReferrerPolicy(network::mojom::ReferrerPolicy,
- bool from_meta_tag_with_list_of_policies = false);
+ // For a header-set policy, parses a comma-delimited list of tokens, and sets
+ // the context's policy to the last one that is a valid policy. For a meta-set
+ // policy, accepts only a single token, and allows the legacy tokens defined
+ // in the HTML specification.
+ void ParseAndSetReferrerPolicy(const String& policy,
+ ReferrerPolicySource source);
+ void SetReferrerPolicy(network::mojom::ReferrerPolicy);
virtual network::mojom::ReferrerPolicy GetReferrerPolicy() const {
return referrer_policy_;
}
- virtual network::mojom::blink::ReferrerPolicy
- ReferrerPolicyButForMetaTagsWithListsOfPolicies() const {
- return referrer_policy_but_for_meta_tags_with_lists_of_policies_;
- }
virtual CoreProbeSink* GetProbeSink() { return nullptr; }
- virtual BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() = 0;
-
virtual FrameOrWorkerScheduler* GetScheduler() = 0;
- virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
- TaskType) = 0;
v8::Isolate* GetIsolate() const { return isolate_; }
Agent* GetAgent() const { return agent_; }
@@ -366,10 +356,8 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
}
network::mojom::IPAddressSpace AddressSpace() const { return address_space_; }
- void AddContextLifecycleObserver(ContextLifecycleObserver*) override;
- void RemoveContextLifecycleObserver(ContextLifecycleObserver*) override;
HeapObserverSet<ContextLifecycleObserver>& ContextLifecycleObserverSet() {
- return context_lifecycle_observer_set_;
+ return ContextLifecycleNotifier::observers();
}
unsigned ContextLifecycleStateObserverCountForTesting() const;
@@ -382,6 +370,10 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
// timers useful for Spectre-style side channel attacks, so are restricted
// to cross-origin isolated contexts.
bool SharedArrayBufferTransferAllowed() const;
+ // Returns SharedArrayBufferTransferAllowed() but potentially reports an
+ // inspector issue if the transfer was disallowed, or will be disallowed in
+ // the future.
+ bool CheckSharedArrayBufferTransferAllowedAndReport();
virtual ukm::UkmRecorder* UkmRecorder() { return nullptr; }
virtual ukm::SourceId UkmSourceID() const { return ukm::kInvalidSourceId; }
@@ -408,6 +400,12 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
return nullptr;
}
+ bool has_filed_shared_array_buffer_creation_issue() const {
+ return has_filed_shared_array_buffer_creation_issue_;
+ }
+
+ void FileSharedArrayBufferCreationIssue();
+
protected:
explicit ExecutionContext(v8::Isolate* isolate, Agent*);
ExecutionContext(const ExecutionContext&) = delete;
@@ -445,14 +443,15 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
bool is_in_back_forward_cache_ = false;
+ bool has_filed_shared_array_buffer_transfer_issue_ = false;
+ bool has_filed_shared_array_buffer_creation_issue_ = false;
+
Member<PublicURLManager> public_url_manager_;
const Member<ContentSecurityPolicyDelegate> csp_delegate_;
DOMTimerCoordinator timers_;
- HeapObserverSet<ContextLifecycleObserver> context_lifecycle_observer_set_;
-
// Counter that keeps track of how many window interaction calls are allowed
// for this ExecutionContext. Callers are expected to call
// |allowWindowInteraction()| and |consumeWindowInteraction()| in order to
@@ -461,14 +460,6 @@ class CORE_EXPORT ExecutionContext : public Supplementable<ExecutionContext>,
network::mojom::ReferrerPolicy referrer_policy_;
- // This is the same value as |referrer_policy_| except that it ignores
- // referrer policies set as the result of parsing <meta name=referrer> tags
- // whose values are comma-separated lists of policies. Its purpose is to allow
- // evaluating the impact of switching to a behavior of no longer supporting
- // these lists (crbug.com/1092930).
- network::mojom::blink::ReferrerPolicy
- referrer_policy_but_for_meta_tags_with_lists_of_policies_;
-
network::mojom::blink::IPAddressSpace address_space_;
Member<OriginTrialContext> origin_trial_context_;
diff --git a/chromium/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h b/chromium/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h
index f8f23a436fb..edc7a21802c 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h
@@ -72,7 +72,7 @@ class CORE_EXPORT ExecutionContextLifecycleStateObserver
void SetExecutionContext(ExecutionContext*) override;
protected:
- virtual ~ExecutionContextLifecycleStateObserver();
+ ~ExecutionContextLifecycleStateObserver() override;
private:
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/execution_context/navigator_base.h b/chromium/third_party/blink/renderer/core/execution_context/navigator_base.h
new file mode 100644
index 00000000000..4bc9c2e5c57
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/execution_context/navigator_base.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_NAVIGATOR_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_NAVIGATOR_BASE_H_
+
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h"
+#include "third_party/blink/renderer/core/frame/navigator_device_memory.h"
+#include "third_party/blink/renderer/core/frame/navigator_id.h"
+#include "third_party/blink/renderer/core/frame/navigator_language.h"
+#include "third_party/blink/renderer/core/frame/navigator_on_line.h"
+#include "third_party/blink/renderer/core/frame/navigator_ua.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+// NavigatorBase is a helper for shared logic between Navigator and
+// WorkerNavigator. It is also a Supplementable, and can therefore be used for
+// classes that need to Supplement both Navigator and WorkerNavigator.
+class NavigatorBase : public ScriptWrappable,
+ public NavigatorConcurrentHardware,
+ public NavigatorDeviceMemory,
+ public NavigatorID,
+ public NavigatorLanguage,
+ public NavigatorOnLine,
+ public NavigatorUA,
+ public ExecutionContextClient,
+ public Supplementable<NavigatorBase> {
+ public:
+ explicit NavigatorBase(ExecutionContext* context)
+ : NavigatorLanguage(context), ExecutionContextClient(context) {}
+
+ // NavigatorID override
+ String userAgent() const override {
+ return GetExecutionContext() ? GetExecutionContext()->UserAgent()
+ : String();
+ }
+
+ void Trace(Visitor* visitor) const override {
+ ScriptWrappable::Trace(visitor);
+ NavigatorLanguage::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+ Supplementable<NavigatorBase>::Trace(visitor);
+ }
+
+ protected:
+ ExecutionContext* GetUAExecutionContext() const override {
+ return GetExecutionContext();
+ }
+
+ UserAgentMetadata GetUserAgentMetadata() const override {
+ return GetExecutionContext() ? GetExecutionContext()->GetUserAgentMetadata()
+ : blink::UserAgentMetadata();
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_NAVIGATOR_BASE_H_
diff --git a/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.cc b/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.cc
index f0736874dcc..08180f0bad3 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.cc
@@ -29,13 +29,11 @@ void RemoteSecurityContext::SetReplicatedOrigin(
scoped_refptr<SecurityOrigin> origin) {
DCHECK(origin);
SetSecurityOrigin(std::move(origin));
- GetContentSecurityPolicy()->SetupSelf(*GetSecurityOrigin());
}
void RemoteSecurityContext::ResetReplicatedContentSecurityPolicy() {
DCHECK(GetSecurityOrigin());
SetContentSecurityPolicy(MakeGarbageCollected<ContentSecurityPolicy>());
- GetContentSecurityPolicy()->SetupSelf(*GetSecurityOrigin());
}
void RemoteSecurityContext::ResetAndEnforceSandboxFlags(
@@ -51,24 +49,10 @@ void RemoteSecurityContext::ResetAndEnforceSandboxFlags(
void RemoteSecurityContext::InitializeFeaturePolicy(
const ParsedFeaturePolicy& parsed_header,
const ParsedFeaturePolicy& container_policy,
- const FeaturePolicy* parent_feature_policy,
- const FeaturePolicyFeatureState* opener_feature_state) {
- // Feature policy should either come from a parent in the case of an embedded
- // child frame, or from an opener if any when a new window is created by an
- // opener. A main frame without an opener would not have a parent policy nor
- // an opener feature state.
- DCHECK(!parent_feature_policy || !opener_feature_state);
+ const FeaturePolicy* parent_feature_policy) {
report_only_feature_policy_ = nullptr;
- if (!opener_feature_state ||
- !RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
- parent_feature_policy, container_policy,
- security_origin_->ToUrlOrigin());
- } else {
- DCHECK(!parent_feature_policy);
- feature_policy_ = FeaturePolicy::CreateWithOpenerPolicy(
- *opener_feature_state, security_origin_->ToUrlOrigin());
- }
+ feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
+ parent_feature_policy, container_policy, security_origin_->ToUrlOrigin());
feature_policy_->SetHeaderPolicy(parsed_header);
}
diff --git a/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.h b/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.h
index f715a66708d..cb0f18421ce 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/remote_security_context.h
@@ -28,16 +28,11 @@ class CORE_EXPORT RemoteSecurityContext final : public SecurityContext {
// * |container_policy|: from <iframe>'s allow attribute.
// * |parent_feature_policy|: which is the current state of feature policies
// in a parent browsing context (frame).
- // * |opener_feature_state|: the current state of the policies in an opener
- // if any.
- // Note that at most one of the |parent_feature_policy| or
- // |opener_feature_state| should be provided. The |container_policy| is empty
+ // Note that |parent_feature_policy| is null, and |container_policy| is empty
// for a top-level security context.
- void InitializeFeaturePolicy(
- const ParsedFeaturePolicy& parsed_header,
- const ParsedFeaturePolicy& container_policy,
- const FeaturePolicy* parent_feature_policy,
- const FeaturePolicyFeatureState* opener_feature_state);
+ void InitializeFeaturePolicy(const ParsedFeaturePolicy& parsed_header,
+ const ParsedFeaturePolicy& container_policy,
+ const FeaturePolicy* parent_feature_policy);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context.cc b/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
index a6a14db6b0f..68b014b63a3 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -139,19 +139,13 @@ void SecurityContext::SetContentSecurityPolicy(
bool SecurityContext::IsSandboxed(
network::mojom::blink::WebSandboxFlags mask) const {
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- mojom::blink::FeaturePolicyFeature feature =
- FeaturePolicy::FeatureForSandboxFlag(mask);
- if (feature != mojom::blink::FeaturePolicyFeature::kNotFound)
- return !feature_policy_->IsFeatureEnabled(feature);
- }
return (sandbox_flags_ & mask) !=
network::mojom::blink::WebSandboxFlags::kNone;
}
-void SecurityContext::ApplySandboxFlags(
+void SecurityContext::SetSandboxFlags(
network::mojom::blink::WebSandboxFlags flags) {
- sandbox_flags_ |= flags;
+ sandbox_flags_ = flags;
}
void SecurityContext::SetRequireTrustedTypes() {
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context.h b/chromium/third_party/blink/renderer/core/execution_context/security_context.h
index 7b72f12f57b..b1759df9e62 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context.h
@@ -113,7 +113,7 @@ class CORE_EXPORT SecurityContext {
return sandbox_flags_;
}
bool IsSandboxed(network::mojom::blink::WebSandboxFlags mask) const;
- void ApplySandboxFlags(network::mojom::blink::WebSandboxFlags flags);
+ void SetSandboxFlags(network::mojom::blink::WebSandboxFlags flags);
void SetRequireTrustedTypes();
void SetRequireTrustedTypesForTesting(); // Skips sanity checks.
@@ -146,6 +146,9 @@ class CORE_EXPORT SecurityContext {
const FeaturePolicy* GetFeaturePolicy() const {
return feature_policy_.get();
}
+ const FeaturePolicy* GetReportOnlyFeaturePolicy() const {
+ return report_only_feature_policy_.get();
+ }
void SetFeaturePolicy(std::unique_ptr<FeaturePolicy>);
void SetReportOnlyFeaturePolicy(std::unique_ptr<FeaturePolicy>);
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context_init.cc b/chromium/third_party/blink/renderer/core/execution_context/security_context_init.cc
index 5acfa322d16..24bb90a7d57 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context_init.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context_init.cc
@@ -15,7 +15,6 @@
#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/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -79,7 +78,7 @@ SecurityContextInit::SecurityContextInit(ExecutionContext* context)
void SecurityContextInit::ApplyDocumentPolicy(
DocumentPolicy::ParsedDocumentPolicy& document_policy,
const String& report_only_document_policy_header) {
- if (!RuntimeEnabledFeatures::DocumentPolicyEnabled(execution_context_))
+ if (!RuntimeEnabledFeatures::DocumentPolicyEnabled())
return;
// Because Document-Policy http header is parsed in DocumentLoader,
@@ -193,25 +192,14 @@ void SecurityContextInit::ApplyFeaturePolicy(
message.content));
}
- // DocumentLoader applied the sandbox flags before calling this function, so
- // they are accessible here.
- auto sandbox_flags = execution_context_->GetSandboxFlags();
- if (sandbox_flags != network::mojom::blink::WebSandboxFlags::kNone &&
- RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- // The sandbox flags might have come from CSP header or the browser; in
- // such cases the sandbox is not part of the container policy. They are
- // added to the header policy (which specifically makes sense in the case
- // of CSP sandbox).
- ApplySandboxFlagsToParsedFeaturePolicy(sandbox_flags,
- feature_policy_header_);
- }
-
ParsedFeaturePolicy container_policy;
if (frame && frame->Owner())
container_policy = frame_policy.container_policy;
- // TODO(icelland): This is problematic querying sandbox flags before
- // feature policy is initialized.
+ // DocumentLoader applied the sandbox flags before calling this function, so
+ // they are accessible here.
+ auto sandbox_flags = execution_context_->GetSandboxFlags();
+
if (RuntimeEnabledFeatures::BlockingFocusWithoutUserActivationEnabled() &&
frame && frame->Tree().Parent() &&
(sandbox_flags & network::mojom::blink::WebSandboxFlags::kNavigation) !=
@@ -223,26 +211,14 @@ void SecurityContextInit::ApplyFeaturePolicy(
container_policy);
}
- // Feature policy should either come from a parent in the case of an
- // embedded child frame, or from an opener if any when a new window is
- // created by an opener. A main frame without an opener would not have a
- // parent policy nor an opener feature state.
- // For a main frame, get inherited feature policy from the opener if any.
std::unique_ptr<FeaturePolicy> feature_policy;
- if (!frame->IsMainFrame() || frame->OpenerFeatureState().empty() ||
- !RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- auto* parent_feature_policy =
- frame->Tree().Parent()
- ? frame->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy()
- : nullptr;
- feature_policy = FeaturePolicy::CreateFromParentPolicy(
- parent_feature_policy, container_policy,
- execution_context_->GetSecurityOrigin()->ToUrlOrigin());
- } else {
- feature_policy = FeaturePolicy::CreateWithOpenerPolicy(
- frame->OpenerFeatureState(),
- execution_context_->GetSecurityOrigin()->ToUrlOrigin());
- }
+ auto* parent_feature_policy =
+ frame->Tree().Parent()
+ ? frame->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy()
+ : nullptr;
+ feature_policy = FeaturePolicy::CreateFromParentPolicy(
+ parent_feature_policy, container_policy,
+ execution_context_->GetSecurityOrigin()->ToUrlOrigin());
feature_policy->SetHeaderPolicy(feature_policy_header_);
execution_context_->GetSecurityContext().SetFeaturePolicy(
std::move(feature_policy));
@@ -266,4 +242,19 @@ void SecurityContextInit::ApplyFeaturePolicy(
}
}
+void SecurityContextInit::InitFeaturePolicyFrom(const SecurityContext& other) {
+ auto& security_context = execution_context_->GetSecurityContext();
+ security_context.SetFeaturePolicy(
+ FeaturePolicy::CopyStateFrom(other.GetFeaturePolicy()));
+ security_context.SetReportOnlyFeaturePolicy(
+ FeaturePolicy::CopyStateFrom(other.GetReportOnlyFeaturePolicy()));
+}
+
+void SecurityContextInit::InitDocumentPolicyFrom(const SecurityContext& other) {
+ auto& security_context = execution_context_->GetSecurityContext();
+ security_context.SetDocumentPolicy(
+ DocumentPolicy::CopyStateFrom(other.GetDocumentPolicy()));
+ security_context.SetReportOnlyDocumentPolicy(
+ DocumentPolicy::CopyStateFrom(other.GetReportOnlyDocumentPolicy()));
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/execution_context/security_context_init.h b/chromium/third_party/blink/renderer/core/execution_context/security_context_init.h
index e58f7b37448..7add6e9f74e 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/security_context_init.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/security_context_init.h
@@ -29,6 +29,20 @@ class CORE_EXPORT SecurityContextInit {
public:
explicit SecurityContextInit(ExecutionContext*);
+ // Init |feature_policy_| and |report_only_feature_policy_| by copying
+ // state from another security context instance.
+ // Used to carry feature policy information from previous document
+ // to current document during XSLT navigation, because XSLT navigation
+ // does not have header information available.
+ void InitFeaturePolicyFrom(const SecurityContext& other);
+
+ // Init |document_policy_| and |report_only_document_policy_| by copying
+ // state from another security context instance.
+ // Used to carry document policy information from previous document
+ // to current document during XSLT navigation, because XSLT navigation
+ // does not have header information available.
+ void InitDocumentPolicyFrom(const SecurityContext& other);
+
void ApplyFeaturePolicy(LocalFrame* frame,
const ResourceResponse& response,
const base::Optional<WebOriginPolicy>& origin_policy,
diff --git a/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.cc b/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
index 1f28a744860..f49519db20e 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
+++ b/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
@@ -18,7 +18,8 @@ WindowAgentFactory::WindowAgentFactory() = default;
WindowAgent* WindowAgentFactory::GetAgentForOrigin(
bool has_potential_universal_access_privilege,
v8::Isolate* isolate,
- const SecurityOrigin* origin) {
+ const SecurityOrigin* origin,
+ bool is_origin_agent_cluster) {
if (has_potential_universal_access_privilege) {
if (!universal_access_agent_) {
universal_access_agent_ = MakeGarbageCollected<WindowAgent>(isolate);
@@ -41,6 +42,18 @@ WindowAgent* WindowAgentFactory::GetAgentForOrigin(
return inserted.stored_value->value;
}
+ // For origin-keyed agent cluster origins.
+ // Note: this map is specific to OAC, and does not represent origin-keyed
+ // agents specified via Coop/Coep.
+ if (is_origin_agent_cluster) {
+ auto inserted = origin_keyed_agent_cluster_agents_.insert(origin, nullptr);
+ if (inserted.is_new_entry) {
+ inserted.stored_value->value = MakeGarbageCollected<WindowAgent>(isolate);
+ inserted.stored_value->value->SetIsExplicitlyOriginKeyed(true);
+ }
+ return inserted.stored_value->value;
+ }
+
// For tuple origins.
String registrable_domain = origin->RegistrableDomain();
if (registrable_domain.IsNull())
@@ -67,6 +80,7 @@ void WindowAgentFactory::Trace(Visitor* visitor) const {
visitor->Trace(universal_access_agent_);
visitor->Trace(file_url_agent_);
visitor->Trace(opaque_origin_agents_);
+ visitor->Trace(origin_keyed_agent_cluster_agents_);
visitor->Trace(tuple_origin_agents_);
}
diff --git a/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.h b/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.h
index f80b2945671..33d750e36ef 100644
--- a/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.h
+++ b/chromium/third_party/blink/renderer/core/execution_context/window_agent_factory.h
@@ -41,6 +41,9 @@ class WindowAgentFactory final : public GarbageCollected<WindowAgentFactory> {
// - |has_potential_universal_access_privilege| is true,
// - both A and B have `file:` scheme,
// - or, they have the same scheme and the same registrable origin.
+ // If |is_origin_agent_cluster| is true though, then the same instance will
+ // only return the same instance for an exact match (scheme, host, port) to
+ // |origin|.
//
// Set |has_potential_universal_access_privilege| if an agent may be able to
// access all other agents synchronously.
@@ -50,7 +53,8 @@ class WindowAgentFactory final : public GarbageCollected<WindowAgentFactory> {
// * or, the Blink instance is running for Android WebView.
WindowAgent* GetAgentForOrigin(bool has_potential_universal_access_privilege,
v8::Isolate* isolate,
- const SecurityOrigin* origin);
+ const SecurityOrigin* origin,
+ bool is_origin_agent_cluster);
void Trace(Visitor*) const;
@@ -98,6 +102,15 @@ class WindowAgentFactory final : public GarbageCollected<WindowAgentFactory> {
SecurityOriginHash>
opaque_origin_agents_;
+ // Use the SecurityOrigin itself as the key for origin-keyed origins.
+ // TODO(wjmaclean,domenic): In future when logical cross-origin-isolation
+ // (COI) is implemented, we should unify it with logical-OAC so that all the
+ // origin-keyed isolation relies on a single mechanism.
+ HeapHashMap<scoped_refptr<const SecurityOrigin>,
+ WeakMember<WindowAgent>,
+ SecurityOriginHash>
+ origin_keyed_agent_cluster_agents_;
+
// Use registerable domain as the key for general tuple origins.
using TupleOriginAgents = HeapHashMap<SchemeAndRegistrableDomain,
WeakMember<WindowAgent>,
diff --git a/chromium/third_party/blink/renderer/core/exported/BUILD.gn b/chromium/third_party/blink/renderer/core/exported/BUILD.gn
index 85225e62627..05fdb41bf92 100644
--- a/chromium/third_party/blink/renderer/core/exported/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/exported/BUILD.gn
@@ -4,6 +4,20 @@
import("//build/config/dcheck_always_on.gni")
import("//third_party/blink/renderer/core/core.gni")
+static_library("test_support") {
+ testonly = true
+
+ sources = [ "test_web_frame_content_dumper.cc" ]
+
+ deps = [
+ "//third_party/blink/public:test_headers",
+ "//third_party/blink/renderer/core",
+ "//third_party/blink/renderer/platform",
+ ]
+
+ visibility = [ "//third_party/blink/public:test_support" ]
+}
+
blink_core_sources("exported") {
configs += [ "//build/config/compiler:noshadowing" ]
@@ -76,6 +90,7 @@ blink_core_sources("exported") {
"web_v8_context_snapshot.cc",
"web_view_impl.cc",
"web_view_impl.h",
+ "web_view_observer.cc",
]
if (is_debug || dcheck_always_on) {
@@ -83,6 +98,7 @@ blink_core_sources("exported") {
}
deps = [
+ "//build:chromeos_buildflags",
"//third_party/blink/renderer/core:core_generated",
"//third_party/blink/renderer/core/probe",
"//third_party/blink/renderer/core/typed_arrays:typed_arrays",
diff --git a/chromium/third_party/blink/renderer/core/exported/test_web_frame_content_dumper.cc b/chromium/third_party/blink/renderer/core/exported/test_web_frame_content_dumper.cc
new file mode 100644
index 00000000000..2a4e363dd3e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/exported/test_web_frame_content_dumper.cc
@@ -0,0 +1,67 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/test/test_web_frame_content_dumper.h"
+
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/frame_content_as_text.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html_element_type_helpers.h"
+#include "third_party/blink/renderer/core/layout/layout_tree_as_text.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+WebString TestWebFrameContentDumper::DumpWebViewAsText(WebView* web_view,
+ size_t max_chars) {
+ DCHECK(web_view);
+ WebLocalFrame* frame = web_view->MainFrame()->ToWebLocalFrame();
+
+ WebViewImpl* web_view_impl = static_cast<WebViewImpl*>(web_view);
+ DCHECK(web_view_impl->MainFrameViewWidget());
+ // Updating the document lifecycle isn't enough, the BeginFrame() step
+ // should come first which runs events such as notifying of media query
+ // changes or raf-based events.
+ web_view_impl->MainFrameViewWidget()->BeginMainFrame(base::TimeTicks::Now());
+ web_view_impl->MainFrameViewWidget()->UpdateAllLifecyclePhases(
+ DocumentUpdateReason::kTest);
+
+ StringBuilder text;
+ FrameContentAsText(max_chars, To<WebLocalFrameImpl>(frame)->GetFrame(), text);
+ return text.ToString();
+}
+
+WebString TestWebFrameContentDumper::DumpAsMarkup(WebLocalFrame* frame) {
+ return CreateMarkup(To<WebLocalFrameImpl>(frame)->GetFrame()->GetDocument());
+}
+
+WebString TestWebFrameContentDumper::DumpLayoutTreeAsText(
+ WebLocalFrame* frame,
+ LayoutAsTextControls to_show) {
+ LayoutAsTextBehavior behavior = kLayoutAsTextShowAllLayers;
+
+ if (to_show & kLayoutAsTextWithLineTrees)
+ behavior |= kLayoutAsTextShowLineTrees;
+
+ if (to_show & kLayoutAsTextDebug) {
+ behavior |= kLayoutAsTextShowCompositedLayers | kLayoutAsTextShowAddresses |
+ kLayoutAsTextShowIDAndClass | kLayoutAsTextShowLayerNesting;
+ }
+
+ if (to_show & kLayoutAsTextPrinting)
+ behavior |= kLayoutAsTextPrintingMode;
+
+ return ExternalRepresentation(To<WebLocalFrameImpl>(frame)->GetFrame(),
+ behavior);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_content_holder.cc b/chromium/third_party/blink/renderer/core/exported/web_content_holder.cc
index ba69605e14e..be38d01092e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_content_holder.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_content_holder.cc
@@ -27,8 +27,8 @@ WebString WebContentHolder::GetValue() const {
return private_->node()->nodeValue();
}
-WebRect WebContentHolder::GetBoundingBox() const {
- return WebRect(private_->rect());
+gfx::Rect WebContentHolder::GetBoundingBox() const {
+ return private_->rect();
}
uint64_t WebContentHolder::GetId() const {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
index 89cddd09600..ce027d46fb0 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -35,7 +35,6 @@
#include <utility>
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_scoped_page_pauser.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_settings.h"
@@ -50,7 +49,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
#include "third_party/blink/renderer/core/inspector/devtools_agent.h"
@@ -73,6 +72,7 @@
#include "third_party/blink/renderer/core/inspector/inspector_overlay_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_performance_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_resource_container.h"
#include "third_party/blink/renderer/core/inspector/inspector_resource_content_loader.h"
#include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
@@ -159,7 +159,7 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
agent->FlushProtocolNotifications();
// 1. Disable input events.
- WebFrameWidgetBase::SetIgnoreInputEvents(true);
+ WebFrameWidgetImpl::SetIgnoreInputEvents(true);
for (auto* const view : WebViewImpl::AllInstances())
view->GetChromeClient().NotifyPopupOpeningObservers();
@@ -192,7 +192,7 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
// code, but it is moved here to support browser-side navigation.
message_loop_->QuitNow();
page_pauser_.reset();
- WebFrameWidgetBase::SetIgnoreInputEvents(false);
+ WebFrameWidgetImpl::SetIgnoreInputEvents(false);
}
bool running_for_debug_break_;
@@ -278,7 +278,8 @@ void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
session->Append(MakeGarbageCollected<InspectorAuditsAgent>(
network_agent,
- &inspected_frames->Root()->GetPage()->GetInspectorIssueStorage()));
+ &inspected_frames->Root()->GetPage()->GetInspectorIssueStorage(),
+ inspected_frames));
session->Append(MakeGarbageCollected<InspectorMediaAgent>(inspected_frames));
@@ -288,6 +289,9 @@ void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
session->Append(MakeGarbageCollected<InspectorEmulationAgent>(
web_local_frame_impl_.Get()));
+ session->Append(MakeGarbageCollected<InspectorPerformanceTimelineAgent>(
+ inspected_frames));
+
// Call session init callbacks registered from higher layers.
CoreInitializer::GetInstance().InitInspectorAgentSession(
session, include_view_agents_, dom_agent, inspected_frames,
@@ -480,6 +484,11 @@ void WebDevToolsAgentImpl::DispatchBufferedTouchEvents() {
it.value->DispatchBufferedTouchEvents();
}
+void WebDevToolsAgentImpl::SetPageIsScrolling(bool is_scrolling) {
+ for (auto& it : overlay_agents_)
+ it.value->SetPageIsScrolling(is_scrolling);
+}
+
WebInputEventResult WebDevToolsAgentImpl::HandleInputEvent(
const WebInputEvent& event) {
for (auto& it : overlay_agents_) {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
index 6bde1bb591c..e6a27b71e03 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
@@ -81,6 +81,7 @@ class CORE_EXPORT WebDevToolsAgentImpl final
WebInputEventResult HandleInputEvent(const WebInputEvent&);
void DispatchBufferedTouchEvents();
+ void SetPageIsScrolling(bool is_scrolling);
void BindReceiver(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost>,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent>);
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
index 984a197662a..e45da36ebe5 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
@@ -38,7 +38,6 @@
#include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/web_document_subresource_filter.h"
-#include "third_party/blink/public/platform/web_loading_hints_provider.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -114,6 +113,11 @@ WebDocumentLoader::ExtraData* WebDocumentLoaderImpl::GetExtraData() const {
return extra_data_.get();
}
+std::unique_ptr<WebDocumentLoader::ExtraData>
+WebDocumentLoaderImpl::TakeExtraData() {
+ return std::move(extra_data_);
+}
+
void WebDocumentLoaderImpl::SetExtraData(
std::unique_ptr<ExtraData> extra_data) {
extra_data_ = std::move(extra_data);
@@ -146,13 +150,6 @@ void WebDocumentLoaderImpl::SetSubresourceFilter(
GetFrame()->DomWindow(), base::WrapUnique(subresource_filter)));
}
-void WebDocumentLoaderImpl::SetLoadingHintsProvider(
- std::unique_ptr<blink::WebLoadingHintsProvider> loading_hints_provider) {
- DocumentLoader::SetPreviewsResourceLoadingHints(
- PreviewsResourceLoadingHints::CreateFromLoadingHintsProvider(
- *GetFrame()->DomWindow(), std::move(loading_hints_provider)));
-}
-
void WebDocumentLoaderImpl::SetServiceWorkerNetworkProvider(
std::unique_ptr<WebServiceWorkerNetworkProvider> provider) {
DocumentLoader::SetServiceWorkerNetworkProvider(std::move(provider));
@@ -200,8 +197,8 @@ WebArchiveInfo WebDocumentLoaderImpl::GetArchiveInfo() const {
};
}
-bool WebDocumentLoaderImpl::HadUserGesture() const {
- return DocumentLoader::HadTransientActivation();
+bool WebDocumentLoaderImpl::LastNavigationHadTransientUserActivation() const {
+ return DocumentLoader::LastNavigationHadTransientUserActivation();
}
bool WebDocumentLoaderImpl::IsListingFtpDirectory() const {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
index 2b9cc8d84ac..b61daa7d880 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_loader_impl.h
@@ -55,6 +55,7 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
WebNavigationType navigation_type,
ContentSecurityPolicy*,
std::unique_ptr<WebNavigationParams> navigation_params);
+ ~WebDocumentLoaderImpl() override;
static WebDocumentLoaderImpl* FromDocumentLoader(DocumentLoader* loader) {
return static_cast<WebDocumentLoaderImpl*>(loader);
@@ -75,10 +76,9 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
bool ReplacesCurrentHistoryItem() const override;
WebNavigationType GetNavigationType() const override;
ExtraData* GetExtraData() const override;
+ std::unique_ptr<ExtraData> TakeExtraData() override;
void SetExtraData(std::unique_ptr<ExtraData>) override;
void SetSubresourceFilter(WebDocumentSubresourceFilter*) override;
- void SetLoadingHintsProvider(
- std::unique_ptr<blink::WebLoadingHintsProvider>) override;
void SetServiceWorkerNetworkProvider(
std::unique_ptr<WebServiceWorkerNetworkProvider>) override;
WebServiceWorkerNetworkProvider* GetServiceWorkerNetworkProvider() override;
@@ -87,13 +87,12 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
bool HasBeenLoadedAsWebArchive() const override;
PreviewsState GetPreviewsState() const override;
WebArchiveInfo GetArchiveInfo() const override;
- bool HadUserGesture() const override;
+ bool LastNavigationHadTransientUserActivation() const override;
bool IsListingFtpDirectory() const override;
void Trace(Visitor*) const override;
private:
- ~WebDocumentLoaderImpl() override;
void DetachFromFrame(bool flush_microtask_queue) override;
// Mutable because the const getters will magically sync these to the
diff --git a/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
index 3b7ab3495b1..f72fa2829fc 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -70,9 +70,12 @@ class TestDocumentSubresourceFilter : public WebDocumentSubresourceFilter {
class SubresourceFilteringWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- void DidCommitNavigation(const WebHistoryItem&,
- WebHistoryCommitType,
- bool) override {
+ void DidCommitNavigation(
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) override {
subresource_filter_ =
new TestDocumentSubresourceFilter(load_policy_for_next_load_);
subresource_filter_->AddToBlocklist("1x1.png");
diff --git a/chromium/third_party/blink/renderer/core/exported/web_dom_message_event.cc b/chromium/third_party/blink/renderer/core/exported/web_dom_message_event.cc
index e7ff1a4c527..45cb3eb807b 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_dom_message_event.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_dom_message_event.cc
@@ -64,7 +64,7 @@ WebDOMMessageEvent::WebDOMMessageEvent(
// right?
Unwrap<MessageEvent>()->initMessageEvent(
"message", false, false, message_data, origin, "" /*lastEventId*/, window,
- ports, nullptr /*user_activation*/);
+ ports, nullptr /*user_activation*/, false);
}
WebString WebDOMMessageEvent::Origin() const {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_element.cc b/chromium/third_party/blink/renderer/core/exported/web_element.cc
index 9eba6341ad4..1829c4f850c 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_element.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_element.cc
@@ -30,16 +30,12 @@
#include "third_party/blink/public/web/web_element.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_element.h"
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
-#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -83,6 +79,10 @@ WebString WebElement::TagName() const {
return ConstUnwrap<Element>()->tagName();
}
+WebString WebElement::GetIdAttribute() const {
+ return ConstUnwrap<Element>()->GetIdAttribute();
+}
+
bool WebElement::HasHTMLTagName(const WebString& tag_name) const {
// How to create class nodeName localName
// createElement('input') HTMLInputElement INPUT input
@@ -104,10 +104,6 @@ WebString WebElement::GetAttribute(const WebString& attr_name) const {
void WebElement::SetAttribute(const WebString& attr_name,
const WebString& attr_value) {
- // TODO: Custom element callbacks need to be called on WebKit API methods that
- // mutate the DOM in any way.
- V0CustomElementProcessingStack::CallbackDeliveryScope
- deliver_custom_element_callbacks;
Unwrap<Element>()->setAttribute(attr_name, attr_value,
IGNORE_EXCEPTION_FOR_TESTING);
}
@@ -142,8 +138,6 @@ bool WebElement::IsAutonomousCustomElement() const {
auto* element = ConstUnwrap<Element>();
if (element->GetCustomElementState() == CustomElementState::kCustom)
return CustomElement::IsValidName(element->localName());
- if (element->GetV0CustomElementState() == Node::kV0Upgraded)
- return V0CustomElement::IsValidName(element->localName());
return false;
}
@@ -162,7 +156,7 @@ WebNode WebElement::OpenOrClosedShadowRoot() {
return WebNode(root);
}
-WebRect WebElement::BoundsInViewport() const {
+gfx::Rect WebElement::BoundsInViewport() const {
return ConstUnwrap<Element>()->BoundsInViewport();
}
@@ -194,17 +188,12 @@ gfx::Size WebElement::GetImageSize() {
return gfx::Size(image->width(), image->height());
}
-void WebElement::RequestFullscreen() {
- Element* element = Unwrap<Element>();
- Fullscreen::RequestFullscreen(*element);
-}
-
WebString WebElement::GetComputedValue(const WebString& property_name) {
if (IsNull())
return WebString();
Element* element = Unwrap<Element>();
- CSSPropertyID property_id = cssPropertyID(
+ CSSPropertyID property_id = CssPropertyID(
element->GetDocument().GetExecutionContext(), property_name);
if (property_id == CSSPropertyID::kInvalid)
return WebString();
diff --git a/chromium/third_party/blink/renderer/core/exported/web_element_test.cc b/chromium/third_party/blink/renderer/core/exported/web_element_test.cc
index febcef17306..0441e318247 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_element_test.cc
@@ -98,16 +98,6 @@ TEST_F(WebElementTest, ShadowRoot) {
<< "ShadowRoot() should not return a UA ShadowRoot.";
{
- InsertHTML("<div id=testElement></div>");
- EXPECT_TRUE(TestElement().ShadowRoot().IsNull())
- << "No ShadowRoot initially.";
- auto* element = GetDocument().getElementById("testElement");
- element->CreateV0ShadowRootForTesting();
- EXPECT_FALSE(TestElement().ShadowRoot().IsNull())
- << "Should return V0 ShadowRoot.";
- }
-
- {
InsertHTML("<span id=testElement></span>");
EXPECT_TRUE(TestElement().ShadowRoot().IsNull())
<< "No ShadowRoot initially.";
diff --git a/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc
index c4f6df8a2f8..9ea4108348c 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.cc
@@ -109,7 +109,7 @@ WebFormElementObserver* WebFormElementObserver::Create(
WebFormElement& element,
base::OnceClosure callback) {
return MakeGarbageCollected<WebFormElementObserverImpl>(
- util::PassKey<WebFormElementObserver>(),
+ base::PassKey<WebFormElementObserver>(),
*element.Unwrap<HTMLFormElement>(), std::move(callback));
}
@@ -117,12 +117,12 @@ WebFormElementObserver* WebFormElementObserver::Create(
WebFormControlElement& element,
base::OnceClosure callback) {
return MakeGarbageCollected<WebFormElementObserverImpl>(
- util::PassKey<WebFormElementObserver>(), *element.Unwrap<HTMLElement>(),
+ base::PassKey<WebFormElementObserver>(), *element.Unwrap<HTMLElement>(),
std::move(callback));
}
WebFormElementObserverImpl::WebFormElementObserverImpl(
- util::PassKey<WebFormElementObserver>,
+ base::PassKey<WebFormElementObserver>,
HTMLElement& element,
base::OnceClosure callback)
: self_keep_alive_(PERSISTENT_FROM_HERE, this) {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h b/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
index b8ae2bf04a7..814d48511a0 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_form_element_observer_impl.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_WEB_FORM_ELEMENT_OBSERVER_IMPL_H_
#include "base/macros.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/public/web/modules/autofill/web_form_element_observer.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -21,7 +21,7 @@ class CORE_EXPORT WebFormElementObserverImpl final
: public GarbageCollected<WebFormElementObserverImpl>,
public WebFormElementObserver {
public:
- WebFormElementObserverImpl(util::PassKey<WebFormElementObserver>,
+ WebFormElementObserverImpl(base::PassKey<WebFormElementObserver>,
HTMLElement&,
base::OnceClosure);
~WebFormElementObserverImpl() override;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
index baca3c4a980..c756d0ad26e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
@@ -4,146 +4,20 @@
#include "third_party/blink/public/web/web_frame_content_dumper.h"
-#include "base/stl_util.h"
-#include "third_party/blink/public/web/web_document.h"
-#include "third_party/blink/public/web/web_frame_widget.h"
+#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_local_frame.h"
-#include "third_party/blink/public/web/web_view.h"
-#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
-#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
-#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
-#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/frame_content_as_text.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
-#include "third_party/blink/renderer/core/html_element_type_helpers.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/layout/layout_tree_as_text.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
-namespace {
-
-void FrameContentAsPlainText(size_t max_chars,
- LocalFrame* frame,
- StringBuilder& output) {
- Document* document = frame->GetDocument();
- if (!document)
- return;
-
- if (!frame->View() || frame->View()->CanThrottleRendering())
- return;
-
- DCHECK(!frame->View()->NeedsLayout());
- DCHECK(!document->NeedsLayoutTreeUpdate());
-
- if (document->documentElement()) {
- output.Append(document->documentElement()->innerText());
- if (output.length() >= max_chars)
- output.Resize(max_chars);
- }
-
- // The separator between frames when the frames are converted to plain text.
- const LChar kFrameSeparator[] = {'\n', '\n'};
- const size_t frame_separator_length = base::size(kFrameSeparator);
-
- // Recursively walk the children.
- const FrameTree& frame_tree = frame->Tree();
- for (Frame* cur_child = frame_tree.FirstChild(); cur_child;
- cur_child = cur_child->Tree().NextSibling()) {
- auto* cur_local_child = DynamicTo<LocalFrame>(cur_child);
- if (!cur_local_child)
- continue;
- // Ignore the text of non-visible frames.
- LayoutView* layout_view = cur_local_child->ContentLayoutObject();
- LayoutObject* owner_layout_object = cur_local_child->OwnerLayoutObject();
- if (!layout_view || !layout_view->Size().Width() ||
- !layout_view->Size().Height() ||
- (layout_view->Location().X() + layout_view->Size().Width() <= 0) ||
- (layout_view->Location().Y() + layout_view->Size().Height() <= 0) ||
- (owner_layout_object && owner_layout_object->Style() &&
- owner_layout_object->Style()->Visibility() != EVisibility::kVisible)) {
- continue;
- }
-
- // Make sure the frame separator won't fill up the buffer, and give up if
- // it will. The danger is if the separator will make the buffer longer than
- // maxChars. This will cause the computation above:
- // maxChars - output->size()
- // to be a negative number which will crash when the subframe is added.
- if (output.length() >= max_chars - frame_separator_length)
- return;
-
- output.Append(kFrameSeparator, frame_separator_length);
- FrameContentAsPlainText(max_chars, cur_local_child, output);
- if (output.length() >= max_chars)
- return; // Filled up the buffer.
- }
-}
-
-} // namespace
-
-WebString WebFrameContentDumper::DeprecatedDumpFrameTreeAsText(
- WebLocalFrame* frame,
- size_t max_chars) {
- if (!frame)
- return WebString();
+WebString WebFrameContentDumper::DumpFrameTreeAsText(WebLocalFrame* frame,
+ size_t max_chars) {
StringBuilder text;
- FrameContentAsPlainText(max_chars, To<WebLocalFrameImpl>(frame)->GetFrame(),
- text);
+ FrameContentAsText(max_chars, To<WebLocalFrameImpl>(frame)->GetFrame(), text);
return text.ToString();
}
-WebString WebFrameContentDumper::DumpWebViewAsText(WebView* web_view,
- size_t max_chars) {
- DCHECK(web_view);
- WebLocalFrame* frame = web_view->MainFrame()->ToWebLocalFrame();
- if (!frame)
- return WebString();
-
- WebViewImpl* web_view_impl = static_cast<WebViewImpl*>(web_view);
- DCHECK(web_view_impl->MainFrameViewWidget());
- // Updating the document lifecycle isn't enough, the BeginFrame() step
- // should come first which runs events such as notifying of media query
- // changes or raf-based events.
- web_view_impl->MainFrameViewWidget()->BeginMainFrame(base::TimeTicks::Now());
- web_view_impl->MainFrameViewWidget()->UpdateAllLifecyclePhases(
- DocumentUpdateReason::kTest);
-
- StringBuilder text;
- FrameContentAsPlainText(max_chars, To<WebLocalFrameImpl>(frame)->GetFrame(),
- text);
- return text.ToString();
-}
-
-WebString WebFrameContentDumper::DumpAsMarkup(WebLocalFrame* frame) {
- if (!frame)
- return WebString();
- return CreateMarkup(To<WebLocalFrameImpl>(frame)->GetFrame()->GetDocument());
-}
-
-WebString WebFrameContentDumper::DumpLayoutTreeAsText(
- WebLocalFrame* frame,
- LayoutAsTextControls to_show) {
- if (!frame)
- return WebString();
- LayoutAsTextBehavior behavior = kLayoutAsTextShowAllLayers;
-
- if (to_show & kLayoutAsTextWithLineTrees)
- behavior |= kLayoutAsTextShowLineTrees;
-
- if (to_show & kLayoutAsTextDebug) {
- behavior |= kLayoutAsTextShowCompositedLayers | kLayoutAsTextShowAddresses |
- kLayoutAsTextShowIDAndClass | kLayoutAsTextShowLayerNesting;
- }
-
- if (to_show & kLayoutAsTextPrinting)
- behavior |= kLayoutAsTextPrintingMode;
-
- return ExternalRepresentation(To<WebLocalFrameImpl>(frame)->GetFrame(),
- behavior);
-}
-}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
index e85df7c89c7..66af4db1076 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
@@ -101,13 +101,8 @@ class WebFrameSerializerSanitizationTest : public testing::Test {
FocusDelegation focus_delegation = FocusDelegation::kNone) {
Element* host_element = scope.getElementById(AtomicString::FromUTF8(host));
ShadowRoot* shadow_root;
- if (shadow_type == ShadowRootType::V0) {
- DCHECK_EQ(focus_delegation, FocusDelegation::kNone);
- shadow_root = &host_element->CreateV0ShadowRootForTesting();
- } else {
- shadow_root = &host_element->AttachShadowRootInternal(shadow_type,
- focus_delegation);
- }
+ shadow_root =
+ &host_element->AttachShadowRootInternal(shadow_type, focus_delegation);
shadow_root->SetDelegatesFocus(focus_delegation ==
FocusDelegation::kDelegateFocus);
shadow_root->setInnerHTML(String::FromUTF8(shadow_content),
@@ -336,7 +331,6 @@ TEST_F(WebFrameSerializerSanitizationTest, RemoveElements) {
TEST_F(WebFrameSerializerSanitizationTest, ShadowDOM) {
LoadFrame("http://www.test.com", "shadow_dom.html", "text/html");
Document* document = MainFrameImpl()->GetFrame()->GetDocument();
- SetShadowContent(*document, "h1", ShadowRootType::V0, "V0 shadow");
ShadowRoot* shadowRoot = SetShadowContent(
*document, "h2", ShadowRootType::kOpen,
"Parent shadow\n<p id=\"h3\">Foo</p>", FocusDelegation::kDelegateFocus);
@@ -344,7 +338,6 @@ TEST_F(WebFrameSerializerSanitizationTest, ShadowDOM) {
String mhtml = WebFrameSerializerTestHelper::GenerateMHTML(MainFrameImpl());
// Template with special attribute should be created for each shadow DOM tree.
- EXPECT_NE(WTF::kNotFound, mhtml.Find("<template shadowmode=3D\"v0\">"));
EXPECT_NE(WTF::kNotFound,
mhtml.Find("<template shadowmode=3D\"open\" shadowdelegatesfocus"));
EXPECT_NE(WTF::kNotFound, mhtml.Find("<template shadowmode=3D\"closed\">"));
diff --git a/chromium/third_party/blink/renderer/core/exported/web_heap.cc b/chromium/third_party/blink/renderer/core/exported/web_heap.cc
index 8d9af331697..f7919fbfff2 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_heap.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_heap.cc
@@ -44,12 +44,4 @@ void WebHeap::CollectAllGarbageForTesting() {
ThreadState::Current()->CollectAllGarbageForTesting();
}
-void WebHeap::SetAllocationHook(AllocationHook alloc_hook) {
- HeapAllocHooks::SetAllocationHook(alloc_hook);
-}
-
-void WebHeap::SetFreeHook(FreeHook free_hook) {
- HeapAllocHooks::SetFreeHook(free_hook);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
index 8d651628a38..02740e2d77a 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/exported/web_input_method_controller_impl.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_vector.h"
#include "third_party/blink/public/web/web_plugin.h"
@@ -187,8 +186,9 @@ WebTextInputType WebInputMethodControllerImpl::TextInputType() {
return GetFrame()->GetInputMethodController().TextInputType();
}
-void WebInputMethodControllerImpl::GetLayoutBounds(WebRect* control_bounds,
- WebRect* selection_bounds) {
+void WebInputMethodControllerImpl::GetLayoutBounds(
+ gfx::Rect* control_bounds,
+ gfx::Rect* selection_bounds) {
GetInputMethodController().GetLayoutBounds(control_bounds, selection_bounds);
}
@@ -223,7 +223,7 @@ WebRange WebInputMethodControllerImpl::CompositionRange() {
}
bool WebInputMethodControllerImpl::GetCompositionCharacterBounds(
- WebVector<WebRect>& bounds) {
+ WebVector<gfx::Rect>& bounds) {
if (IsEditContextActive())
return false;
@@ -233,14 +233,14 @@ bool WebInputMethodControllerImpl::GetCompositionCharacterBounds(
size_t character_count = range.length();
size_t offset = range.StartOffset();
- WebVector<WebRect> result(character_count);
- WebRect webrect;
+ WebVector<gfx::Rect> result(character_count);
+ gfx::Rect rect;
for (size_t i = 0; i < character_count; ++i) {
- if (!web_frame_->FirstRectForCharacterRange(offset + i, 1, webrect)) {
+ if (!web_frame_->FirstRectForCharacterRange(offset + i, 1, rect)) {
DLOG(ERROR) << "Could not retrieve character rectangle at " << i;
return false;
}
- result[i] = webrect;
+ result[i] = rect;
}
bounds.Swap(result);
diff --git a/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.h b/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.h
index 9d987fe745a..95f2a37b3bc 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_input_method_controller_impl.h
@@ -48,12 +48,12 @@ class CORE_EXPORT WebInputMethodControllerImpl
int ComputeWebTextInputNextPreviousFlags() override;
WebTextInputType TextInputType() override;
WebRange CompositionRange() override;
- bool GetCompositionCharacterBounds(WebVector<WebRect>& bounds) override;
+ bool GetCompositionCharacterBounds(WebVector<gfx::Rect>& bounds) override;
WebRange GetSelectionOffsets() const override;
- void GetLayoutBounds(WebRect* control_bounds,
- WebRect* selection_bounds) override;
+ void GetLayoutBounds(gfx::Rect* control_bounds,
+ gfx::Rect* selection_bounds) override;
bool IsVirtualKeyboardPolicyManual() const override;
bool IsEditContextActive() const override;
ui::mojom::VirtualKeyboardVisibilityRequest
diff --git a/chromium/third_party/blink/renderer/core/exported/web_isolated_world_info.cc b/chromium/third_party/blink/renderer/core/exported/web_isolated_world_info.cc
index d47897ddf78..5a12533aec0 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_isolated_world_info.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_isolated_world_info.cc
@@ -27,6 +27,12 @@ void SetIsolatedWorldInfo(int32_t world_id, const WebIsolatedWorldInfo& info) {
world_id, info.content_security_policy, security_origin);
}
+bool IsEqualOrExceedEmbedderWorldIdLimit(int world_id) {
+ if (world_id >= IsolatedWorldId::kEmbedderWorldIdLimit)
+ return true;
+ return false;
+}
+
WebString GetIsolatedWorldStableId(v8::Local<v8::Context> context) {
const DOMWrapperWorld& world = DOMWrapperWorld::World(context);
DCHECK(!world.IsMainWorld());
diff --git a/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc b/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc
index 2313f0e881b..220f8c644ae 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_navigation_params.cc
@@ -41,16 +41,15 @@ std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateFromInfo(
result->navigation_timings.input_start = info.input_start;
result->initiator_origin_trial_features =
info.initiator_origin_trial_features;
- result->ip_address_space = info.initiator_address_space;
result->frame_policy = info.frame_policy;
- result->had_transient_activation = info.url_request.HasUserGesture();
+ result->had_transient_user_activation = info.url_request.HasUserGesture();
return result;
}
// static
-std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateWithHTMLString(
- base::span<const char> html,
- const WebURL& base_url) {
+std::unique_ptr<WebNavigationParams>
+WebNavigationParams::CreateWithHTMLStringForTesting(base::span<const char> html,
+ const WebURL& base_url) {
auto result = std::make_unique<WebNavigationParams>();
result->url = base_url;
FillStaticResponse(result.get(), "text/html", "UTF-8", html);
@@ -59,7 +58,8 @@ std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateWithHTMLString(
#if INSIDE_BLINK
// static
-std::unique_ptr<WebNavigationParams> WebNavigationParams::CreateWithHTMLBuffer(
+std::unique_ptr<WebNavigationParams>
+WebNavigationParams::CreateWithHTMLBufferForTesting(
scoped_refptr<SharedBuffer> buffer,
const KURL& base_url) {
auto result = std::make_unique<WebNavigationParams>();
@@ -102,6 +102,7 @@ void WebNavigationParams::FillStaticResponse(WebNavigationParams* params,
params->response = WebURLResponse(params->url);
params->response.SetMimeType(mime_type);
params->response.SetTextEncodingName(text_encoding);
+ params->response.SetHttpStatusCode(params->http_status_code);
FillBodyLoader(params, data);
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_node.cc b/chromium/third_party/blink/renderer/core/exported/web_node.cc
index 35ce6544824..83c3510146a 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_node.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_node.cc
@@ -176,11 +176,10 @@ bool WebNode::IsDocumentTypeNode() const {
void WebNode::SimulateClick() {
private_->GetExecutionContext()
->GetTaskRunner(TaskType::kUserInteraction)
- ->PostTask(
- FROM_HERE,
- WTF::Bind(&Node::DispatchSimulatedClick,
- WrapWeakPersistent(private_.Get()), nullptr, kSendNoEvents,
- SimulatedClickCreationScope::kFromUserAgent));
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&Node::DispatchSimulatedClick,
+ WrapWeakPersistent(private_.Get()), nullptr,
+ SimulatedClickCreationScope::kFromUserAgent));
}
WebElementCollection WebNode::GetElementsByHTMLTagName(
diff --git a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index c46d2d2583d..73920eb35e1 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -34,6 +34,7 @@
#include "cc/animation/animation_host.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/ukm_manager.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
#include "third_party/blink/public/platform/scheduler/web_render_widget_scheduling_state.h"
#include "third_party/blink/public/web/web_view_client.h"
@@ -54,8 +55,8 @@
#include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -73,8 +74,10 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
#include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
#include "third_party/blink/renderer/platform/widget/widget_base.h"
@@ -166,31 +169,27 @@ class PagePopupChromeClient final : public EmptyChromeClient {
}
void ScheduleAnimation(const LocalFrameView*,
- base::TimeDelta = base::TimeDelta()) override {
- if (WebTestSupport::IsRunningWebTest()) {
- // In single threaded web tests, the main frame's WebWidgetClient
- // (provided by WebViewTestProxy or WebWidgetTestProxy) runs the composite
- // step for the current popup. We don't run popup tests with a compositor
- // thread.
- WebLocalFrameImpl* web_frame = popup_->web_view_->MainFrameImpl();
- WebWidgetClient* widget_client = nullptr;
-
- if (web_frame) {
- widget_client = web_frame->FrameWidgetImpl()->Client();
- } else {
- // We'll enter this case for a popup in an out-of-proc iframe.
- // Get the WidgetClient for the frame of the popup's owner element,
- // instead of the WebView's MainFrame.
- Element& popup_owner_element = popup_->popup_client_->OwnerElement();
- WebLocalFrameImpl* web_local_frame_impl = WebLocalFrameImpl::FromFrame(
- popup_owner_element.GetDocument().GetFrame());
- widget_client = web_local_frame_impl->FrameWidgetImpl()->Client();
- }
-
- widget_client->ScheduleAnimation();
+ base::TimeDelta delay = base::TimeDelta()) override {
+ // Destroying/removing the popup's content can be seen as a mutation that
+ // ends up calling ScheduleAnimation(). Since the popup is going away, we
+ // do not wish to actually do anything.
+ if (popup_->closing_)
+ return;
+
+ // When the renderer has a compositor thread we need to follow the
+ // normal code path.
+ if (WebTestSupport::IsRunningWebTest() && !Thread::CompositorThread()) {
+ // In single-threaded web tests, the owner frame tree runs the composite
+ // step for the popup. Popup widgets don't run any composite step on their
+ // own. And we don't run popup tests with a compositor thread, so no need
+ // to check for that.
+ Document& opener_document =
+ popup_->popup_client_->OwnerElement().GetDocument();
+ opener_document.GetPage()->GetChromeClient().ScheduleAnimation(
+ opener_document.GetFrame()->View(), delay);
return;
}
- popup_->WidgetClient()->ScheduleAnimation();
+ popup_->widget_base_->RequestAnimationAfterDelay(delay);
}
void AttachCompositorAnimationTimeline(CompositorAnimationTimeline* timeline,
@@ -205,19 +204,13 @@ class PagePopupChromeClient final : public EmptyChromeClient {
timeline->GetAnimationTimeline());
}
- ScreenInfo GetScreenInfo(LocalFrame&) const override {
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
// LocalFrame is ignored since there is only 1 frame in a popup.
return popup_->GetScreenInfo();
}
- WebViewImpl* GetWebView() const override { return popup_->web_view_; }
-
IntSize MinimumWindowSize() const override { return IntSize(0, 0); }
- void SetCursor(const ui::Cursor& cursor, LocalFrame* local_frame) override {
- popup_->WidgetClient()->DidChangeCursor(cursor);
- }
-
void SetEventListenerProperties(
LocalFrame* frame,
cc::EventListenerClass event_class,
@@ -282,7 +275,6 @@ bool PagePopupFeaturesClient::IsEnabled(Document*,
// WebPagePopupImpl ----------------------------------------------------------
WebPagePopupImpl::WebPagePopupImpl(
- WebPagePopupClient* client,
CrossVariantMojoAssociatedRemote<mojom::blink::PopupWidgetHostInterfaceBase>
popup_widget_host,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
@@ -290,17 +282,15 @@ WebPagePopupImpl::WebPagePopupImpl(
CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
widget,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : web_page_popup_client_(client),
- popup_widget_host_(std::move(popup_widget_host)),
+ : popup_widget_host_(std::move(popup_widget_host)),
widget_base_(
- std::make_unique<WidgetBase>(this,
+ std::make_unique<WidgetBase>(/*widget_base_client=*/this,
std::move(widget_host),
std::move(widget),
task_runner,
/*hidden=*/false,
/*never_composited=*/false,
/*is_for_child_local_root=*/false)) {
- DCHECK(client);
popup_widget_host_.set_disconnect_handler(WTF::Bind(
&WebPagePopupImpl::WidgetHostDisconnected, WTF::Unretained(this)));
}
@@ -309,15 +299,15 @@ WebPagePopupImpl::~WebPagePopupImpl() {
DCHECK(!page_);
}
-void WebPagePopupImpl::InitializeForTesting(WebView* web_view) {
- SetWebView(static_cast<WebViewImpl*>(web_view));
+void WebPagePopupImpl::InitializeForTesting(WebView* opener_web_view) {
+ SetWebView(static_cast<WebViewImpl*>(opener_web_view));
}
-void WebPagePopupImpl::SetWebView(WebViewImpl* web_view) {
- DCHECK(web_view);
- DCHECK(!web_view_);
- web_view_ = web_view;
- if (auto* widget = web_view->MainFrameViewWidget()) {
+void WebPagePopupImpl::SetWebView(WebViewImpl* opener_web_view) {
+ DCHECK(opener_web_view);
+ DCHECK(!opener_web_view_);
+ opener_web_view_ = opener_web_view;
+ if (auto* widget = opener_web_view->MainFrameViewWidget()) {
if (auto* device_emulator = widget->DeviceEmulator()) {
opener_widget_screen_origin_ = device_emulator->ViewRectOrigin();
opener_original_widget_screen_origin_ =
@@ -327,19 +317,21 @@ void WebPagePopupImpl::SetWebView(WebViewImpl* web_view) {
}
}
-void WebPagePopupImpl::Initialize(WebViewImpl* web_view,
+void WebPagePopupImpl::Initialize(WebViewImpl* opener_web_view,
PagePopupClient* popup_client) {
DCHECK(popup_client);
popup_client_ = popup_client;
- SetWebView(web_view);
+ SetWebView(opener_web_view);
Page::PageClients page_clients;
FillWithEmptyClients(page_clients);
chrome_client_ = MakeGarbageCollected<PagePopupChromeClient>(this);
page_clients.chrome_client = chrome_client_.Get();
- Settings& main_settings = web_view_->GetPage()->GetSettings();
- page_ = Page::CreateNonOrdinary(page_clients);
+ Settings& main_settings = opener_web_view_->GetPage()->GetSettings();
+ page_ = Page::CreateNonOrdinary(page_clients, opener_web_view_->GetPage()
+ ->GetPageScheduler()
+ ->GetAgentGroupScheduler());
page_->GetSettings().SetAcceleratedCompositingEnabled(true);
page_->GetSettings().SetScriptEnabled(true);
page_->GetSettings().SetAllowScriptsToCloseWindows(true);
@@ -364,8 +356,15 @@ void WebPagePopupImpl::Initialize(WebViewImpl* web_view,
// an UpdateStyleAndLayoutTree() before opening the popup in the various
// default event handlers.
if (const auto* style = popup_client_->OwnerElement().GetComputedStyle()) {
+ // Avoid using dark color scheme stylesheet for popups when forced colors
+ // mode is active.
+ // TODO(iopopesc): move this to popup CSS when the FocedColors feature is
+ // enabled by default.
+ bool in_forced_colors_mode =
+ popup_client_->OwnerElement().GetDocument().InForcedColorsMode();
page_->GetSettings().SetPreferredColorScheme(
- style->UsedColorScheme() == mojom::blink::ColorScheme::kDark
+ style->UsedColorScheme() == mojom::blink::ColorScheme::kDark &&
+ !in_forced_colors_mode
? mojom::blink::PreferredColorScheme::kDark
: mojom::blink::PreferredColorScheme::kLight);
}
@@ -389,7 +388,7 @@ void WebPagePopupImpl::Initialize(WebViewImpl* web_view,
empty_local_frame_client, *page_,
/* FrameOwner* */ nullptr, /* Frame* parent */ nullptr,
/* Frame* previous_sibling */ nullptr,
- FrameInsertType::kInsertInConstructor, base::UnguessableToken::Create(),
+ FrameInsertType::kInsertInConstructor, LocalFrameToken(),
window_agent_factory,
/* InterfaceRegistry* */ nullptr,
/* policy_container */ nullptr);
@@ -446,19 +445,23 @@ void WebPagePopupImpl::DidSetBounds() {
widget_base_->AckPendingWindowRect();
}
-cc::LayerTreeHost* WebPagePopupImpl::InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
+void WebPagePopupImpl::InitializeCompositing(
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
cc::TaskGraphRunner* task_graph_runner,
- bool for_child_local_root_frame,
const ScreenInfo& screen_info,
std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
const cc::LayerTreeSettings* settings) {
// Careful Initialize() is called after InitializeCompositing, so don't do
// much work here.
- widget_base_->InitializeCompositing(
- main_thread_scheduler, task_graph_runner, for_child_local_root_frame,
- screen_info, std::move(ukm_recorder_factory), settings);
- return widget_base_->LayerTreeHost();
+ widget_base_->InitializeCompositing(agent_group_scheduler, task_graph_runner,
+ /*for_child_local_root_frame=*/false,
+ screen_info,
+ std::move(ukm_recorder_factory), settings,
+ /*frame_widget_input_handler=*/nullptr);
+ cc::LayerTreeDebugState debug_state =
+ widget_base_->LayerTreeHost()->GetDebugState();
+ debug_state.TurnOffHudInfoDisplay();
+ widget_base_->LayerTreeHost()->SetDebugState(debug_state);
}
scheduler::WebRenderWidgetSchedulingState*
@@ -685,6 +688,10 @@ WebInputEventResult WebPagePopupImpl::HandleKeyEvent(
return MainFrame().GetEventHandler().KeyEvent(event);
}
+cc::LayerTreeHost* WebPagePopupImpl::LayerTreeHostForTesting() {
+ return widget_base_->LayerTreeHost();
+}
+
void WebPagePopupImpl::BeginMainFrame(base::TimeTicks last_frame_time) {
if (!page_)
return;
@@ -863,7 +870,7 @@ void WebPagePopupImpl::FocusChanged(bool enable) {
}
void WebPagePopupImpl::ScheduleAnimation() {
- WidgetClient()->ScheduleAnimation();
+ widget_base_->LayerTreeHost()->SetNeedsAnimate();
}
void WebPagePopupImpl::UpdateVisualProperties(
@@ -875,6 +882,14 @@ void WebPagePopupImpl::UpdateVisualProperties(
widget_base_->SetVisibleViewportSizeInDIPs(
visual_properties.visible_viewport_size);
+ // TODO(crbug.com/1155388): Popups are a single "global" object that don't
+ // inherit the scale factor of the frame containing the corresponding element
+ // so compositing_scale_factor is always 1 and has no effect.
+ float combined_scale_factor = visual_properties.page_scale_factor *
+ visual_properties.compositing_scale_factor;
+ widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
+ combined_scale_factor, visual_properties.is_pinch_gesture_active);
+
Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size));
}
@@ -889,20 +904,18 @@ gfx::Rect WebPagePopupImpl::ViewportVisibleRect() {
KURL WebPagePopupImpl::GetURLForDebugTrace() {
if (!page_)
return {};
- WebFrame* main_frame = web_view_->MainFrame();
+ WebFrame* main_frame = opener_web_view_->MainFrame();
if (main_frame->IsWebLocalFrame())
return main_frame->ToWebLocalFrame()->GetDocument().Url();
return {};
}
void WebPagePopupImpl::WidgetHostDisconnected() {
- DCHECK(web_page_popup_client_);
- web_page_popup_client_->BrowserClosedIpcChannelForPopupWidget();
+ Close();
// Careful, this is now destroyed.
}
-void WebPagePopupImpl::Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) {
+void WebPagePopupImpl::Close() {
// If the popup is closed from the renderer via Cancel(), then ClosePopup()
// has already run on another stack, and destroyed |page_|. If the popup is
// closed from the browser via IPC to RenderWidget, then we come here first
@@ -915,9 +928,8 @@ void WebPagePopupImpl::Close(
Cancel();
}
- widget_base_->Shutdown(std::move(cleanup_runner));
+ widget_base_->Shutdown();
widget_base_.reset();
- web_page_popup_client_ = nullptr;
// Self-delete on Close().
Release();
@@ -972,7 +984,7 @@ void WebPagePopupImpl::ClosePopup() {
// owner of itself. Note however that WebViewImpl may briefly extend the
// lifetime of this object since it owns a reference, but it should only be
// to call HasSamePopupClient().
- web_view_->CleanupPagePopup();
+ opener_web_view_->CleanupPagePopup();
}
LocalDOMWindow* WebPagePopupImpl::Window() {
@@ -983,10 +995,6 @@ WebDocument WebPagePopupImpl::GetDocument() {
return WebDocument(MainFrame().GetDocument());
}
-WebPagePopupClient* WebPagePopupImpl::GetClientForTesting() const {
- return web_page_popup_client_;
-}
-
void WebPagePopupImpl::Cancel() {
if (popup_client_)
popup_client_->CancelPopup();
@@ -1038,7 +1046,6 @@ WebPagePopupImpl::AllocateNewLayerTreeFrameSink() {
// WebPagePopup ----------------------------------------------------------------
WebPagePopup* WebPagePopup::Create(
- WebPagePopupClient* client,
CrossVariantMojoAssociatedRemote<mojom::blink::PopupWidgetHostInterfaceBase>
popup_widget_host,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
@@ -1046,16 +1053,15 @@ WebPagePopup* WebPagePopup::Create(
CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
widget,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- CHECK(client);
// A WebPagePopupImpl instance usually has two references.
// - One owned by the instance itself. It represents the visible widget.
// - One owned by a WebViewImpl. It's released when the WebViewImpl ask the
// WebPagePopupImpl to close.
// We need them because the closing operation is asynchronous and the widget
// can be closed while the WebViewImpl is unaware of it.
- auto popup = base::AdoptRef(new WebPagePopupImpl(
- client, std::move(popup_widget_host), std::move(widget_host),
- std::move(widget), task_runner));
+ auto popup = base::AdoptRef(
+ new WebPagePopupImpl(std::move(popup_widget_host), std::move(widget_host),
+ std::move(widget), task_runner));
popup->AddRef();
return popup.get();
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
index 753d0ce2d46..675700ff93e 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -54,6 +54,7 @@ class Layer;
namespace blink {
class Element;
+class Node;
class Page;
class PagePopupChromeClient;
class PagePopupClient;
@@ -100,13 +101,10 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
return other && popup_client_ == other->popup_client_;
}
- WebWidgetClient* WidgetClient() const { return web_page_popup_client_; }
-
LocalDOMWindow* Window();
// WebPagePopup implementation.
WebDocument GetDocument() override;
- WebPagePopupClient* GetClientForTesting() const override;
void InitializeForTesting(WebView* view) override;
// PagePopup implementation.
@@ -116,6 +114,9 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
// PageWidgetEventHandler implementation.
WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
+ // Return the LayerTreeHost backing this popup widget.
+ cc::LayerTreeHost* LayerTreeHostForTesting();
+
private:
// WidgetBaseClient overrides:
void BeginMainFrame(base::TimeTicks last_frame_time) override;
@@ -151,16 +152,14 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
void UpdateLifecycle(WebLifecycleUpdate requested_update,
DocumentUpdateReason reason) override;
void Resize(const gfx::Size&) override;
- void Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) override;
+ void Close() override;
WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
void SetFocus(bool) override;
bool HasFocus() override;
WebHitTestResult HitTestResultAt(const gfx::PointF&) override { return {}; }
- cc::LayerTreeHost* InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
+ void InitializeCompositing(
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
cc::TaskGraphRunner* task_graph_runner,
- bool for_child_local_root_frame,
const ScreenInfo& screen_info,
std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
const cc::LayerTreeSettings* settings) override;
@@ -208,7 +207,6 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
void SetWindowRect(const IntRect&) override;
WebPagePopupImpl(
- WebPagePopupClient*,
CrossVariantMojoAssociatedRemote<
mojom::blink::PopupWidgetHostInterfaceBase> popup_widget_host,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
@@ -232,8 +230,8 @@ class CORE_EXPORT WebPagePopupImpl final : public WebPagePopup,
void DidShowPopup();
void DidSetBounds();
- WebPagePopupClient* web_page_popup_client_;
- WebViewImpl* web_view_ = nullptr;
+ // This is the WebView that opened the popup.
+ WebViewImpl* opener_web_view_ = nullptr;
// WebPagePopupImpl wraps its own Page that renders the content in the popup.
// This member is non-null between the call to Initialize() and the call to
// ClosePopup(). If page_ is non-null, it is guaranteed to have an attached
diff --git a/chromium/third_party/blink/renderer/core/exported/web_performance.cc b/chromium/third_party/blink/renderer/core/exported/web_performance.cc
index 4b4dc26e89f..f97415d6512 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_performance.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_performance.cc
@@ -212,6 +212,10 @@ uint64_t WebPerformance::LargestTextPaintSize() const {
return private_->timing()->LargestTextPaintSize();
}
+base::TimeTicks WebPerformance::LargestContentfulPaintAsMonotonicTime() const {
+ return private_->timing()->LargestContentfulPaintAsMonotonicTime();
+}
+
double WebPerformance::ExperimentalLargestImagePaint() const {
return MillisecondsToSeconds(
private_->timing()->ExperimentalLargestImagePaint());
@@ -304,6 +308,18 @@ base::Optional<base::TimeTicks> WebPerformance::LastPortalActivatedPaint()
return private_->timing()->LastPortalActivatedPaint();
}
+base::Optional<base::TimeTicks> WebPerformance::UnloadStart() const {
+ return private_->timing()->UnloadStart();
+}
+
+base::Optional<base::TimeTicks> WebPerformance::UnloadEnd() const {
+ return private_->timing()->UnloadEnd();
+}
+
+base::Optional<base::TimeTicks> WebPerformance::CommitNavigationEnd() const {
+ return private_->timing()->CommitNavigationEnd();
+}
+
WebPerformance::WebPerformance(WindowPerformance* performance)
: private_(performance) {}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index 6be2044edcd..1901d212803 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -36,7 +36,6 @@
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_drag_data.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_error.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -361,15 +360,10 @@ float WebPluginContainerImpl::PageZoomFactor() {
return frame->PageZoomFactor();
}
-void WebPluginContainerImpl::SetCcLayer(cc::Layer* new_layer,
- bool prevent_contents_opaque_changes) {
- if (layer_ == new_layer &&
- prevent_contents_opaque_changes == prevent_contents_opaque_changes_)
+void WebPluginContainerImpl::SetCcLayer(cc::Layer* new_layer) {
+ if (layer_ == new_layer)
return;
-
layer_ = new_layer;
- prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
-
if (element_)
element_->SetNeedsCompositingUpdate();
}
@@ -542,7 +536,7 @@ void WebPluginContainerImpl::Invalidate() {
InvalidateRect(IntRect(0, 0, Size().Width(), Size().Height()));
}
-void WebPluginContainerImpl::InvalidateRect(const WebRect& rect) {
+void WebPluginContainerImpl::InvalidateRect(const gfx::Rect& rect) {
InvalidateRect(static_cast<IntRect>(rect));
}
@@ -599,7 +593,7 @@ void WebPluginContainerImpl::LoadFrameRequest(const WebURLRequest& request,
target_frame->Navigate(frame_request, WebFrameLoadType::kStandard);
}
-bool WebPluginContainerImpl::IsRectTopmost(const WebRect& rect) {
+bool WebPluginContainerImpl::IsRectTopmost(const gfx::Rect& rect) {
// Disallow access to the frame during Dispose(), because it is not guaranteed
// to be valid memory once this object has started disposal. In particular,
// we might be being disposed because the frame has already be deleted and
@@ -612,7 +606,7 @@ bool WebPluginContainerImpl::IsRectTopmost(const WebRect& rect) {
if (!frame)
return false;
- IntRect frame_rect = rect;
+ IntRect frame_rect(rect);
frame_rect.MoveBy(Location());
HitTestLocation location((PhysicalRect(frame_rect)));
HitTestResult result = frame->GetEventHandler().HitTestResultAtLocation(
@@ -735,10 +729,6 @@ cc::Layer* WebPluginContainerImpl::CcLayer() const {
return layer_;
}
-bool WebPluginContainerImpl::PreventContentsOpaqueChangesToCcLayer() const {
- return prevent_contents_opaque_changes_;
-}
-
v8::Local<v8::Object> WebPluginContainerImpl::ScriptableObject(
v8::Isolate* isolate) {
// With Oilpan, on plugin element detach dispose() will be called to safely
@@ -783,7 +773,6 @@ WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement& element,
web_plugin_(web_plugin),
layer_(nullptr),
touch_event_request_type_(kTouchEventRequestTypeNone),
- prevent_contents_opaque_changes_(false),
wants_wheel_events_(false) {}
WebPluginContainerImpl::~WebPluginContainerImpl() {
diff --git a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
index fbc1467bba5..d52c28501a3 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -98,7 +98,6 @@ class CORE_EXPORT WebPluginContainerImpl final
void Hide() override;
cc::Layer* CcLayer() const;
- bool PreventContentsOpaqueChangesToCcLayer() const;
v8::Local<v8::Object> ScriptableObject(v8::Isolate*);
bool SupportsKeyboardFocus() const;
bool SupportsInputMethod() const;
@@ -122,12 +121,12 @@ class CORE_EXPORT WebPluginContainerImpl final
const WebString& url) override;
void EnqueueMessageEvent(const WebDOMMessageEvent&) override;
void Invalidate() override;
- void InvalidateRect(const WebRect&) override;
+ void InvalidateRect(const gfx::Rect&) override;
void ScheduleAnimation() override;
void ReportGeometry() override;
v8::Local<v8::Object> V8ObjectForElement() override;
void LoadFrameRequest(const WebURLRequest&, const WebString& target) override;
- bool IsRectTopmost(const WebRect&) override;
+ bool IsRectTopmost(const gfx::Rect&) override;
void RequestTouchEventType(TouchEventRequestType) override;
void SetWantsWheelEvents(bool) override;
gfx::Point RootFrameToLocalPoint(const gfx::Point&) override;
@@ -145,7 +144,7 @@ class CORE_EXPORT WebPluginContainerImpl final
float DeviceScaleFactor() override;
float PageScaleFactor() override;
float PageZoomFactor() override;
- void SetCcLayer(cc::Layer*, bool prevent_contents_opaque_changes) override;
+ void SetCcLayer(cc::Layer*) override;
void RequestFullscreen() override;
bool IsFullscreenElement() const override;
void CancelFullscreen() override;
@@ -238,7 +237,6 @@ class CORE_EXPORT WebPluginContainerImpl final
WebPlugin* web_plugin_;
cc::Layer* layer_;
TouchEventRequestType touch_event_request_type_;
- bool prevent_contents_opaque_changes_;
bool wants_wheel_events_;
};
diff --git a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index a5ff8d42067..3c6feb6afff 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -200,15 +200,16 @@ class TestPluginWithEditableText : public FakeWebPlugin {
class TestPluginWebFrameClient : public frame_test_helpers::TestWebFrameClient {
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType owner_type) override {
- return CreateLocalChild(*parent, scope,
- std::make_unique<TestPluginWebFrameClient>());
+ mojom::blink::FrameOwnerElementType owner_type,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
+ return CreateLocalChild(*Frame(), scope,
+ std::make_unique<TestPluginWebFrameClient>(),
+ std::move(policy_container_bind_params));
}
WebPlugin* CreatePlugin(const WebPluginParams& params) override {
@@ -731,9 +732,9 @@ TEST_F(WebPluginContainerTest, GestureLongPressReachesPlugin) {
// Next, send an event that does hit the plugin, and verify it does receive
// it.
- WebRect rect = plugin_container_one_element.BoundsInViewport();
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
event.SetPositionInWidget(
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2));
+ gfx::PointF(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -765,8 +766,9 @@ TEST_F(WebPluginContainerTest, MouseEventButtons) {
IntPoint(30, 30),
WebInputEvent::kMiddleButtonDown | WebInputEvent::kShiftKey);
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -799,8 +801,9 @@ TEST_F(WebPluginContainerTest, MouseWheelEventTranslated) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -808,8 +811,8 @@ TEST_F(WebPluginContainerTest, MouseWheelEventTranslated) {
EXPECT_EQ(WebInputEvent::Type::kMouseWheel,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, TouchEventScrolled) {
@@ -834,14 +837,15 @@ TEST_F(WebPluginContainerTest, TouchEventScrolled) {
->Plugin();
EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
- WebRect rect = plugin_container_one_element.BoundsInViewport();
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
WebPointerEvent event(
WebInputEvent::Type::kPointerDown,
- WebPointerProperties(
- 1, WebPointerProperties::PointerType::kTouch,
- WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2),
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2)),
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
+ WebPointerProperties::Button::kLeft,
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2),
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2)),
1.0f, 1.0f);
web_view->MainFrameWidget()->HandleInputEvent(
@@ -851,8 +855,8 @@ TEST_F(WebPluginContainerTest, TouchEventScrolled) {
EXPECT_EQ(WebInputEvent::Type::kTouchStart,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
@@ -878,14 +882,15 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
{
- WebRect rect = plugin_container_one_element.BoundsInViewport();
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
WebPointerEvent event(
WebInputEvent::Type::kPointerDown,
- WebPointerProperties(
- 1, WebPointerProperties::PointerType::kTouch,
- WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2),
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2)),
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
+ WebPointerProperties::Button::kLeft,
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2),
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2)),
1.0f, 1.0f);
WebCoalescedInputEvent coalesced_event(event, ui::LatencyInfo());
@@ -898,20 +903,20 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
test_plugin->GetCoalescedEventCount());
EXPECT_EQ(WebInputEvent::Type::kTouchStart,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2, test_plugin->GetLastEventLocation().Y());
}
{
- WebRect rect = plugin_container_one_element.BoundsInViewport();
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
WebPointerEvent event1(
WebInputEvent::Type::kPointerMove,
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2 + 1,
- rect.y + rect.height / 2 + 1),
- gfx::PointF(rect.x + rect.width / 2 + 1,
- rect.y + rect.height / 2 + 1)),
+ gfx::PointF(rect.x() + rect.width() / 2 + 1,
+ rect.y() + rect.height() / 2 + 1),
+ gfx::PointF(rect.x() + rect.width() / 2 + 1,
+ rect.y() + rect.height() / 2 + 1)),
1.0f, 1.0f);
WebCoalescedInputEvent coalesced_event(event1, ui::LatencyInfo());
@@ -920,19 +925,19 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
WebInputEvent::Type::kPointerMove,
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2 + 2,
- rect.y + rect.height / 2 + 2),
- gfx::PointF(rect.x + rect.width / 2 + 2,
- rect.y + rect.height / 2 + 2)),
+ gfx::PointF(rect.x() + rect.width() / 2 + 2,
+ rect.y() + rect.height() / 2 + 2),
+ gfx::PointF(rect.x() + rect.width() / 2 + 2,
+ rect.y() + rect.height() / 2 + 2)),
1.0f, 1.0f);
WebPointerEvent event3(
WebInputEvent::Type::kPointerMove,
WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2 + 3,
- rect.y + rect.height / 2 + 3),
- gfx::PointF(rect.x + rect.width / 2 + 3,
- rect.y + rect.height / 2 + 3)),
+ gfx::PointF(rect.x() + rect.width() / 2 + 3,
+ rect.y() + rect.height() / 2 + 3),
+ gfx::PointF(rect.x() + rect.width() / 2 + 3,
+ rect.y() + rect.height() / 2 + 3)),
1.0f, 1.0f);
coalesced_event.AddCoalescedEvent(event2);
@@ -946,8 +951,8 @@ TEST_F(WebPluginContainerTest, TouchEventScrolledWithCoalescedTouches) {
test_plugin->GetCoalescedEventCount());
EXPECT_EQ(WebInputEvent::Type::kTouchMove,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2 + 1, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2 + 1, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2 + 1, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2 + 1, test_plugin->GetLastEventLocation().Y());
}
}
@@ -977,8 +982,9 @@ TEST_F(WebPluginContainerTest, MouseWheelEventScrolled) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -986,8 +992,8 @@ TEST_F(WebPluginContainerTest, MouseWheelEventScrolled) {
EXPECT_EQ(WebInputEvent::Type::kMouseWheel,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, MouseEventScrolled) {
@@ -1016,8 +1022,9 @@ TEST_F(WebPluginContainerTest, MouseEventScrolled) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -1025,8 +1032,8 @@ TEST_F(WebPluginContainerTest, MouseEventScrolled) {
EXPECT_EQ(WebInputEvent::Type::kMouseMove,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 2, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 2, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, MouseEventZoomed) {
@@ -1058,8 +1065,9 @@ TEST_F(WebPluginContainerTest, MouseEventZoomed) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -1069,8 +1077,8 @@ TEST_F(WebPluginContainerTest, MouseEventZoomed) {
// there is a scale of 2 set.
EXPECT_EQ(WebInputEvent::Type::kMouseMove,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 4, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 4, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, MouseWheelEventZoomed) {
@@ -1102,8 +1110,9 @@ TEST_F(WebPluginContainerTest, MouseWheelEventZoomed) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- WebRect rect = plugin_container_one_element.BoundsInViewport();
- event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
+ event.SetPositionInWidget(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2);
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(event, ui::LatencyInfo()));
@@ -1113,8 +1122,8 @@ TEST_F(WebPluginContainerTest, MouseWheelEventZoomed) {
// there is a scale of 2 set.
EXPECT_EQ(WebInputEvent::Type::kMouseWheel,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 4, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 4, test_plugin->GetLastEventLocation().Y());
}
TEST_F(WebPluginContainerTest, TouchEventZoomed) {
@@ -1142,14 +1151,15 @@ TEST_F(WebPluginContainerTest, TouchEventZoomed) {
->Plugin();
EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
- WebRect rect = plugin_container_one_element.BoundsInViewport();
+ gfx::Rect rect = plugin_container_one_element.BoundsInViewport();
WebPointerEvent event(
WebInputEvent::Type::kPointerDown,
- WebPointerProperties(
- 1, WebPointerProperties::PointerType::kTouch,
- WebPointerProperties::Button::kLeft,
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2),
- gfx::PointF(rect.x + rect.width / 2, rect.y + rect.height / 2)),
+ WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
+ WebPointerProperties::Button::kLeft,
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2),
+ gfx::PointF(rect.x() + rect.width() / 2,
+ rect.y() + rect.height() / 2)),
1.0f, 1.0f);
web_view->MainFrameWidget()->HandleInputEvent(
@@ -1161,8 +1171,8 @@ TEST_F(WebPluginContainerTest, TouchEventZoomed) {
// there is a scale of 2 set.
EXPECT_EQ(WebInputEvent::Type::kTouchStart,
test_plugin->GetLastInputEventType());
- EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
- EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
+ EXPECT_EQ(rect.width() / 4, test_plugin->GetLastEventLocation().X());
+ EXPECT_EQ(rect.height() / 4, test_plugin->GetLastEventLocation().Y());
}
// Verify that isRectTopmost returns false when the document is detached.
@@ -1180,7 +1190,7 @@ TEST_F(WebPluginContainerTest, IsRectTopmostTest) {
web_view, WebString::FromUTF8("translated-plugin")));
plugin_container_impl->SetFrameRect(IntRect(0, 0, 300, 300));
- WebRect rect = plugin_container_impl->GetElement().BoundsInViewport();
+ gfx::Rect rect = plugin_container_impl->GetElement().BoundsInViewport();
EXPECT_TRUE(plugin_container_impl->IsRectTopmost(rect));
// Cause the plugin's frame to be detached.
@@ -1373,7 +1383,7 @@ TEST_F(WebPluginContainerTest, ClippedRectsForSubpixelPositionedPlugin) {
}
TEST_F(WebPluginContainerTest, TopmostAfterDetachTest) {
- static constexpr WebRect kTopmostRect(10, 10, 40, 40);
+ static constexpr gfx::Rect kTopmostRect(10, 10, 40, 40);
// Plugin that checks isRectTopmost in destroy().
class TopmostPlugin : public FakeWebPlugin {
@@ -1432,12 +1442,12 @@ class CompositedPlugin : public FakeWebPlugin {
bool Initialize(WebPluginContainer* container) override {
if (!FakeWebPlugin::Initialize(container))
return false;
- container->SetCcLayer(layer_.get(), false);
+ container->SetCcLayer(layer_.get());
return true;
}
void Destroy() override {
- Container()->SetCcLayer(nullptr, false);
+ Container()->SetCcLayer(nullptr);
FakeWebPlugin::Destroy();
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_security_policy.cc b/chromium/third_party/blink/renderer/core/exported/web_security_policy.cc
index 8345594c05c..cefc8182640 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_security_policy.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_security_policy.cc
@@ -112,11 +112,6 @@ void WebSecurityPolicy::ClearOriginAccessList() {
SecurityPolicy::ClearOriginAccessList();
}
-void WebSecurityPolicy::AddOriginToTrustworthySafelist(
- const WebString& origin) {
- SecurityPolicy::AddOriginToTrustworthySafelist(origin);
-}
-
void WebSecurityPolicy::AddSchemeToSecureContextSafelist(
const WebString& scheme) {
SchemeRegistry::RegisterURLSchemeBypassingSecureContextCheck(scheme);
@@ -140,4 +135,8 @@ void WebSecurityPolicy::RegisterURLSchemeAsAllowedForReferrer(
SchemeRegistry::RegisterURLSchemeAsAllowedForReferrer(scheme);
}
+void WebSecurityPolicy::RegisterURLSchemeAsError(const WebString& scheme) {
+ SchemeRegistry::RegisterURLSchemeAsError(scheme);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
index 7606c5c0cf8..b644fb71443 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -259,7 +259,7 @@ void WebSettingsImpl::SetAvailablePointerTypes(int pointers) {
dev_tools_emulator_->SetAvailablePointerTypes(pointers);
}
-void WebSettingsImpl::SetPrimaryPointerType(ui::PointerType pointer) {
+void WebSettingsImpl::SetPrimaryPointerType(mojom::blink::PointerType pointer) {
dev_tools_emulator_->SetPrimaryPointerType(pointer);
}
@@ -267,7 +267,7 @@ void WebSettingsImpl::SetAvailableHoverTypes(int types) {
dev_tools_emulator_->SetAvailableHoverTypes(types);
}
-void WebSettingsImpl::SetPrimaryHoverType(ui::HoverType type) {
+void WebSettingsImpl::SetPrimaryHoverType(mojom::blink::HoverType type) {
dev_tools_emulator_->SetPrimaryHoverType(type);
}
@@ -285,7 +285,7 @@ void WebSettingsImpl::SetDOMPasteAllowed(bool enabled) {
void WebSettingsImpl::SetShrinksViewportContentToFit(
bool shrink_viewport_content) {
- settings_->SetShrinksViewportContentToFit(shrink_viewport_content);
+ dev_tools_emulator_->SetShrinksViewportContentToFit(shrink_viewport_content);
}
void WebSettingsImpl::SetSpatialNavigationEnabled(bool enabled) {
@@ -613,11 +613,11 @@ void WebSettingsImpl::SetImmersiveModeEnabled(bool enabled) {
}
void WebSettingsImpl::SetViewportEnabled(bool enabled) {
- settings_->SetViewportEnabled(enabled);
+ dev_tools_emulator_->SetViewportEnabled(enabled);
}
void WebSettingsImpl::SetViewportMetaEnabled(bool enabled) {
- settings_->SetViewportMetaEnabled(enabled);
+ dev_tools_emulator_->SetViewportMetaEnabled(enabled);
}
void WebSettingsImpl::SetSyncXHRInDocumentsEnabled(bool enabled) {
@@ -629,6 +629,10 @@ void WebSettingsImpl::SetTargetBlankImpliesNoOpenerEnabledWillBeRemoved(
settings_->SetTargetBlankImpliesNoOpenerEnabledWillBeRemoved(enabled);
}
+void WebSettingsImpl::SetAllowNonEmptyNavigatorPlugins(bool enabled) {
+ settings_->SetAllowNonEmptyNavigatorPlugins(enabled);
+}
+
void WebSettingsImpl::SetCaretBrowsingEnabled(bool enabled) {
settings_->SetCaretBrowsingEnabled(enabled);
}
@@ -806,4 +810,9 @@ void WebSettingsImpl::SetAccessibilityIncludeSvgGElement(bool include) {
settings_->SetAccessibilityIncludeSvgGElement(include);
}
+void WebSettingsImpl::SetWebXRImmersiveArAllowed(
+ bool webxr_immersive_ar_allowed) {
+ settings_->SetWebXRImmersiveArAllowed(webxr_immersive_ar_allowed);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
index 2a28774b195..a62d2a309d7 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -130,9 +130,9 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
UScriptCode = USCRIPT_COMMON) override;
void SetPluginsEnabled(bool) override;
void SetAvailablePointerTypes(int) override;
- void SetPrimaryPointerType(ui::PointerType) override;
+ void SetPrimaryPointerType(mojom::blink::PointerType) override;
void SetAvailableHoverTypes(int) override;
- void SetPrimaryHoverType(ui::HoverType) override;
+ void SetPrimaryHoverType(mojom::blink::HoverType) override;
void SetPreferHiddenVolumeControls(bool) override;
void SetShouldProtectAgainstIpcFlooding(bool) override;
void SetRenderVSyncNotificationEnabled(bool) override;
@@ -163,6 +163,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetSupportsMultipleWindows(bool) override;
void SetSyncXHRInDocumentsEnabled(bool) override;
void SetTargetBlankImpliesNoOpenerEnabledWillBeRemoved(bool) override;
+ void SetAllowNonEmptyNavigatorPlugins(bool) override;
void SetTextAreasAreResizable(bool) override;
void SetTextAutosizingEnabled(bool) override;
void SetAccessibilityFontScaleFactor(float) override;
@@ -231,6 +232,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetUseAXMenuList(bool) override;
void SetSelectionClipboardBufferAvailable(bool) override;
void SetAccessibilityIncludeSvgGElement(bool) override;
+ void SetWebXRImmersiveArAllowed(bool webxr_immersive_ar_allowed) override;
bool RenderVSyncNotificationEnabled() const {
return render_v_sync_notification_enabled_;
diff --git a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
index 01ed859429f..110d57bd71c 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
@@ -53,6 +53,7 @@
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/events/message_event.h"
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/worker_devtools_params.h"
#include "third_party/blink/renderer/core/script/script.h"
@@ -78,15 +79,13 @@ WebSharedWorkerImpl::WebSharedWorkerImpl(
const blink::SharedWorkerToken& token,
const base::UnguessableToken& appcache_host_id,
CrossVariantMojoRemote<mojom::SharedWorkerHostInterfaceBase> host,
- WebSharedWorkerClient* client,
- ukm::SourceId ukm_source_id)
+ WebSharedWorkerClient* client)
: reporting_proxy_(MakeGarbageCollected<SharedWorkerReportingProxy>(
this,
ParentExecutionContextTaskRunners::Create())),
worker_thread_(std::make_unique<SharedWorkerThread>(*reporting_proxy_,
token,
- appcache_host_id,
- ukm_source_id)),
+ appcache_host_id)),
host_(std::move(host)),
client_(client) {
DCHECK(IsMainThread());
@@ -170,7 +169,7 @@ void WebSharedWorkerImpl::ConnectToChannel(int connection_request_id,
*task_runner_for_connect_event_, FROM_HERE,
CrossThreadBindOnce(&WebSharedWorkerImpl::ConnectTaskOnWorkerThread,
WTF::CrossThreadUnretained(this),
- WTF::Passed(std::move(channel))));
+ std::move(channel)));
host_->OnConnected(connection_request_id);
}
@@ -198,8 +197,7 @@ void WebSharedWorkerImpl::StartWorkerContext(
WebSecurityOrigin constructor_origin,
const WebString& user_agent,
const UserAgentMetadata& ua_metadata,
- const WebString& content_security_policy,
- network::mojom::ContentSecurityPolicyType policy_type,
+ const WebVector<WebContentSecurityPolicy>& content_security_policies,
network::mojom::IPAddressSpace creation_address_space,
const WebFetchClientSettingsObject& outside_fetch_client_settings_object,
const base::UnguessableToken& devtools_worker_token,
@@ -210,7 +208,8 @@ void WebSharedWorkerImpl::StartWorkerContext(
bool pause_worker_context_on_start,
std::unique_ptr<WorkerMainScriptLoadParameters>
worker_main_script_load_params,
- scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context) {
+ scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context,
+ ukm::SourceId ukm_source_id) {
DCHECK(IsMainThread());
DCHECK(web_worker_fetch_context);
CHECK(constructor_origin.Get()->CanAccessSharedWorkers());
@@ -246,18 +245,13 @@ void WebSharedWorkerImpl::StartWorkerContext(
false /* strictly_block_blockable_mixed_content */,
GenericFontFamilySettings());
- // CSP headers for parent Window's CSP.
- Vector<CSPHeaderAndType> outside_csp_headers;
- outside_csp_headers.ReserveInitialCapacity(1);
- outside_csp_headers.UncheckedAppend(
- CSPHeaderAndType(content_security_policy, policy_type));
-
// Some params (e.g. address space) passed to GlobalScopeCreationParams are
// dummy values. They will be updated after worker script fetch on the worker
// thread.
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
script_request_url, script_type, name, user_agent, ua_metadata,
- std::move(web_worker_fetch_context), outside_csp_headers,
+ std::move(web_worker_fetch_context),
+ ConvertToMojoBlink(content_security_policies),
outside_settings_object->GetReferrerPolicy(),
outside_settings_object->GetSecurityOrigin(), constructor_secure_context,
outside_settings_object->GetHttpsState(),
@@ -269,7 +263,8 @@ void WebSharedWorkerImpl::StartWorkerContext(
std::move(worker_settings), mojom::blink::V8CacheOptions::kDefault,
nullptr /* worklet_module_response_map */,
std::move(browser_interface_broker), BeginFrameProviderParams(),
- nullptr /* parent_feature_policy */, base::UnguessableToken());
+ nullptr /* parent_feature_policy */, base::UnguessableToken(),
+ ukm_source_id);
auto thread_startup_data = WorkerBackingThreadStartupData::CreateDefault();
thread_startup_data.atomics_wait_mode =
@@ -334,8 +329,7 @@ std::unique_ptr<WebSharedWorker> WebSharedWorker::CreateAndStart(
WebSecurityOrigin constructor_origin,
const WebString& user_agent,
const UserAgentMetadata& ua_metadata,
- const WebString& content_security_policy,
- network::mojom::ContentSecurityPolicyType policy_type,
+ const WebVector<WebContentSecurityPolicy>& content_security_policies,
network::mojom::IPAddressSpace creation_address_space,
const WebFetchClientSettingsObject& outside_fetch_client_settings_object,
const base::UnguessableToken& appcache_host_id,
@@ -352,15 +346,15 @@ std::unique_ptr<WebSharedWorker> WebSharedWorker::CreateAndStart(
WebSharedWorkerClient* client,
ukm::SourceId ukm_source_id) {
auto worker = base::WrapUnique(new WebSharedWorkerImpl(
- token, appcache_host_id, std::move(host), client, ukm_source_id));
+ token, appcache_host_id, std::move(host), client));
worker->StartWorkerContext(
script_request_url, script_type, credentials_mode, name,
- constructor_origin, user_agent, ua_metadata, content_security_policy,
- policy_type, creation_address_space, outside_fetch_client_settings_object,
+ constructor_origin, user_agent, ua_metadata, content_security_policies,
+ creation_address_space, outside_fetch_client_settings_object,
devtools_worker_token, std::move(content_settings),
std::move(browser_interface_broker), pause_worker_context_on_start,
std::move(worker_main_script_load_params),
- std::move(web_worker_fetch_context));
+ std::move(web_worker_fetch_context), ukm_source_id);
return worker;
}
diff --git a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
index 22e76cadb4a..0fce76809ef 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
@@ -93,8 +93,7 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker {
const blink::SharedWorkerToken& token,
const base::UnguessableToken& appcache_host_id,
CrossVariantMojoRemote<mojom::SharedWorkerHostInterfaceBase> host,
- WebSharedWorkerClient*,
- ukm::SourceId ukm_source_id);
+ WebSharedWorkerClient*);
void StartWorkerContext(
const WebURL&,
@@ -104,8 +103,7 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker {
WebSecurityOrigin constructor_origin,
const WebString& user_agent,
const blink::UserAgentMetadata& ua_metadata,
- const WebString& content_security_policy,
- network::mojom::ContentSecurityPolicyType,
+ const WebVector<WebContentSecurityPolicy>& content_security_policies,
network::mojom::IPAddressSpace,
const WebFetchClientSettingsObject& outside_fetch_client_settings_object,
const base::UnguessableToken& devtools_worker_token,
@@ -117,7 +115,8 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker {
bool pause_worker_context_on_start,
std::unique_ptr<WorkerMainScriptLoadParameters>
worker_main_script_load_params,
- scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context);
+ scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context,
+ ukm::SourceId ukm_source_id);
void DispatchPendingConnections();
void ConnectToChannel(int connection_request_id,
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
index 4b7d0d5811b..a8e1730397b 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -72,7 +72,6 @@
#include "third_party/blink/public/web/web_range.h"
#include "third_party/blink/public/web/web_render_theme.h"
#include "third_party/blink/public/web/web_view_client.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/public/web/web_window_features.h"
#include "third_party/blink/renderer/core/clipboard/data_object.h"
#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
@@ -115,10 +114,9 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
@@ -135,7 +133,7 @@
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/loader/prerenderer_client.h"
+#include "third_party/blink/renderer/core/loader/no_state_prefetch_client.h"
#include "third_party/blink/renderer/core/page/chrome_client_impl.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "third_party/blink/renderer/core/page/context_menu_provider.h"
@@ -191,6 +189,8 @@
#undef pow
#include <cmath> // for std::pow
+#include "build/chromeos_buildflags.h"
+
// The following constants control parameters for automated scaling of webpages
// (such as due to a double tap gesture or find in page etc.). These are
// experimentally determined.
@@ -220,6 +220,8 @@ static const int caretPadding = 10;
namespace blink {
+using mojom::blink::EffectiveConnectionType;
+
// Historically, these values came from Webkit in
// WebKitLegacy/mac/WebView/WebView.mm (named MinimumZoomMultiplier and
// MaximumZoomMultiplier there).
@@ -410,7 +412,9 @@ ui::mojom::blink::WindowOpenDisposition NavigationPolicyToDisposition(
#if !defined(OS_MAC) && !defined(OS_WIN)
SkFontHinting RendererPreferencesToSkiaHinting(
const blink::RendererPreferences& prefs) {
-#if defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (!prefs.should_antialias_text) {
// When anti-aliasing is off, GTK maps all non-zero hinting settings to
// 'Normal' hinting so we do the same. Otherwise, folks who have 'Slight'
@@ -491,11 +495,12 @@ void WebView::ResetVisitedLinkState(bool invalidate_visited_link_hashes) {
Page::AllVisitedStateChanged(invalidate_visited_link_hashes);
}
-void WebViewImpl::SetPrerendererClient(
- WebPrerendererClient* prerenderer_client) {
+void WebViewImpl::SetNoStatePrefetchClient(
+ WebNoStatePrefetchClient* no_state_prefetch_client) {
DCHECK(page_);
- ProvidePrerendererClientTo(*page_, MakeGarbageCollected<PrerendererClient>(
- *page_, prerenderer_client));
+ ProvideNoStatePrefetchClientTo(*page_,
+ MakeGarbageCollected<NoStatePrefetchClient>(
+ *page_, no_state_prefetch_client));
}
void WebViewImpl::CloseWindowSoon() {
@@ -637,8 +642,8 @@ void WebViewImpl::EnableFakePageScaleAnimationForTesting(bool enable) {
}
void WebViewImpl::AcceptLanguagesChanged() {
- if (web_view_client_)
- FontCache::AcceptLanguagesChanged(web_view_client_->AcceptLanguages());
+ FontCache::AcceptLanguagesChanged(
+ String::FromUTF8(renderer_preferences_.accept_languages));
if (!GetPage())
return;
@@ -646,9 +651,9 @@ void WebViewImpl::AcceptLanguagesChanged() {
GetPage()->AcceptLanguagesChanged();
}
-WebRect WebViewImpl::WidenRectWithinPageBounds(const WebRect& source,
- int target_margin,
- int minimum_margin) {
+gfx::Rect WebViewImpl::WidenRectWithinPageBounds(const gfx::Rect& source,
+ int target_margin,
+ int minimum_margin) {
// Caller should guarantee that the main frame exists and is local.
DCHECK(MainFrame());
DCHECK(MainFrame()->IsWebLocalFrame());
@@ -658,26 +663,26 @@ WebRect WebViewImpl::WidenRectWithinPageBounds(const WebRect& source,
int left_margin = target_margin;
int right_margin = target_margin;
- const int absolute_source_x = source.x + scroll_offset.Width();
+ const int absolute_source_x = source.x() + scroll_offset.Width();
if (left_margin > absolute_source_x) {
left_margin = absolute_source_x;
right_margin = std::max(left_margin, minimum_margin);
}
const int maximum_right_margin =
- max_size.width - (source.width + absolute_source_x);
+ max_size.width - (source.width() + absolute_source_x);
if (right_margin > maximum_right_margin) {
right_margin = maximum_right_margin;
left_margin = std::min(left_margin, std::max(right_margin, minimum_margin));
}
- const int new_width = source.width + left_margin + right_margin;
- const int new_x = source.x - left_margin;
+ const int new_width = source.width() + left_margin + right_margin;
+ const int new_x = source.x() - left_margin;
DCHECK_GE(new_width, 0);
DCHECK_LE(scroll_offset.Width() + new_x + new_width, max_size.width);
- return WebRect(new_x, source.y, new_width, source.height);
+ return gfx::Rect(new_x, source.y(), new_width, source.height());
}
float WebViewImpl::MaximumLegiblePageScale() const {
@@ -694,7 +699,7 @@ float WebViewImpl::MaximumLegiblePageScale() const {
void WebViewImpl::ComputeScaleAndScrollForBlockRect(
const gfx::Point& hit_point_in_root_frame,
- const WebRect& block_rect_in_root_frame,
+ const gfx::Rect& block_rect_in_root_frame,
float padding,
float default_scale_when_already_legible,
float& scale,
@@ -702,7 +707,7 @@ void WebViewImpl::ComputeScaleAndScrollForBlockRect(
scale = PageScaleFactor();
scroll = IntPoint();
- WebRect rect = block_rect_in_root_frame;
+ gfx::Rect rect = block_rect_in_root_frame;
if (!rect.IsEmpty()) {
float default_margin = doubleTapZoomContentDefaultMargin;
@@ -714,10 +719,10 @@ void WebViewImpl::ComputeScaleAndScrollForBlockRect(
// correct if we end up fully zooming to it, and won't matter if we
// don't.
rect = WidenRectWithinPageBounds(
- rect, static_cast<int>(default_margin * rect.width / size_.width()),
- static_cast<int>(minimum_margin * rect.width / size_.width()));
+ rect, static_cast<int>(default_margin * rect.width() / size_.width()),
+ static_cast<int>(minimum_margin * rect.width() / size_.width()));
// Fit block to screen, respecting limits.
- scale = static_cast<float>(size_.width()) / rect.width;
+ scale = static_cast<float>(size_.width()) / rect.width();
scale = std::min(scale, MaximumLegiblePageScale());
if (PageScaleFactor() < default_scale_when_already_legible)
scale = std::max(scale, default_scale_when_already_legible);
@@ -735,25 +740,25 @@ void WebViewImpl::ComputeScaleAndScrollForBlockRect(
float screen_height = size_.height() / scale;
// Scroll to vertically align the block.
- if (rect.height < screen_height) {
+ if (rect.height() < screen_height) {
// Vertically center short blocks.
- rect.y -= 0.5 * (screen_height - rect.height);
+ rect.Offset(0, -0.5 * (screen_height - rect.height()));
} else {
// Ensure position we're zooming to (+ padding) isn't off the bottom of
// the screen.
- rect.y = std::max<float>(
- rect.y, hit_point_in_root_frame.y() + padding - screen_height);
+ rect.set_y(std::max<float>(
+ rect.y(), hit_point_in_root_frame.y() + padding - screen_height));
} // Otherwise top align the block.
// Do the same thing for horizontal alignment.
- if (rect.width < screen_width) {
- rect.x -= 0.5 * (screen_width - rect.width);
+ if (rect.width() < screen_width) {
+ rect.Offset(-0.5 * (screen_width - rect.width()), 0);
} else {
- rect.x = std::max<float>(
- rect.x, hit_point_in_root_frame.x() + padding - screen_width);
+ rect.set_x(std::max<float>(
+ rect.x(), hit_point_in_root_frame.x() + padding - screen_width));
}
- scroll.SetX(rect.x);
- scroll.SetY(rect.y);
+ scroll.SetX(rect.x());
+ scroll.SetY(rect.y());
scale = ClampPageScaleFactorToLimits(scale);
scroll = MainFrameImpl()->GetFrameView()->RootFrameToDocument(scroll);
@@ -848,14 +853,15 @@ Node* WebViewImpl::BestTapNode(
void WebViewImpl::EnableTapHighlightAtPoint(
const GestureEventWithHitTestResults& targeted_tap_event) {
+ DCHECK(MainFrameImpl());
Node* touch_node = BestTapNode(targeted_tap_event);
GetPage()->GetLinkHighlight().SetTapHighlight(touch_node);
- UpdateLifecycle(WebLifecycleUpdate::kAll,
- DocumentUpdateReason::kTapHighlight);
+ MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kAll,
+ DocumentUpdateReason::kTapHighlight);
}
void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
- const WebRect& rect_to_zoom) {
+ const gfx::Rect& rect_to_zoom) {
DCHECK(MainFrameImpl());
float scale;
@@ -899,13 +905,14 @@ void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
}
}
-void WebViewImpl::ZoomToFindInPageRect(const WebRect& rect_in_root_frame) {
+void WebViewImpl::ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame) {
DCHECK(MainFrameImpl());
- WebRect block_bounds = MainFrameImpl()->FrameWidgetImpl()->ComputeBlockBound(
- gfx::Point(rect_in_root_frame.x + rect_in_root_frame.width / 2,
- rect_in_root_frame.y + rect_in_root_frame.height / 2),
- true);
+ gfx::Rect block_bounds =
+ MainFrameImpl()->FrameWidgetImpl()->ComputeBlockBound(
+ gfx::Point(rect_in_root_frame.x() + rect_in_root_frame.width() / 2,
+ rect_in_root_frame.y() + rect_in_root_frame.height() / 2),
+ true);
if (block_bounds.IsEmpty()) {
// Keep current scale (no need to scroll as x,y will normally already
@@ -916,9 +923,9 @@ void WebViewImpl::ZoomToFindInPageRect(const WebRect& rect_in_root_frame) {
float scale;
IntPoint scroll;
- ComputeScaleAndScrollForBlockRect(
- gfx::Point(rect_in_root_frame.x, rect_in_root_frame.y), block_bounds,
- nonUserInitiatedPointPadding, MinimumPageScaleFactor(), scale, scroll);
+ ComputeScaleAndScrollForBlockRect(rect_in_root_frame.origin(), block_bounds,
+ nonUserInitiatedPointPadding,
+ MinimumPageScaleFactor(), scale, scroll);
StartPageScaleAnimation(scroll, false, scale, kFindInPageAnimationDuration);
}
@@ -1058,6 +1065,9 @@ void WebViewImpl::Close() {
// deleted.
web_view_client_ = nullptr;
+ for (auto& observer : observers_)
+ observer.WebViewDestroyed();
+
Release(); // Balances a reference acquired in WebView::Create
}
@@ -1144,7 +1154,7 @@ void WebViewImpl::DidUpdateBrowserControls() {
if (!main_frame)
return;
- WebFrameWidgetBase* widget = main_frame->LocalRootFrameWidget();
+ WebFrameWidgetImpl* widget = main_frame->LocalRootFrameWidget();
widget->SetBrowserControlsShownRatio(GetBrowserControls().TopShownRatio(),
GetBrowserControls().BottomShownRatio());
widget->SetBrowserControlsParams(GetBrowserControls().Params());
@@ -1193,7 +1203,8 @@ void WebViewImpl::ResizeViewWhileAnchored(
// Update lifecycle phases immediately to recalculate the minimum scale limit
// for rotation anchoring, and to make sure that no lifecycle states are
// stale if this WebView is embedded in another one.
- UpdateLifecycle(WebLifecycleUpdate::kAll, DocumentUpdateReason::kSizeChange);
+ MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kAll,
+ DocumentUpdateReason::kSizeChange);
}
void WebViewImpl::ResizeWithBrowserControls(
@@ -1286,7 +1297,7 @@ void WebViewImpl::SetScreenOrientationOverrideForTesting(
// Since we updated the override value, notify all widgets.
for (WebFrame* frame = MainFrame(); frame; frame = frame->TraverseNext()) {
if (frame->IsWebLocalFrame()) {
- if (WebFrameWidgetBase* widget = static_cast<WebFrameWidgetBase*>(
+ if (WebFrameWidgetImpl* widget = static_cast<WebFrameWidgetImpl*>(
frame->ToWebLocalFrame()->FrameWidget()))
widget->UpdateScreenInfo(widget->GetScreenInfo());
}
@@ -1315,7 +1326,8 @@ void WebViewImpl::DidExitFullscreen() {
fullscreen_controller_->DidExitFullscreen();
}
-void WebViewImpl::SetMainFrameViewWidget(WebViewFrameWidget* widget) {
+void WebViewImpl::SetMainFrameViewWidget(WebFrameWidgetImpl* widget) {
+ DCHECK(!widget || widget->ForMainFrame());
web_widget_ = widget;
}
@@ -1329,65 +1341,10 @@ void WebViewImpl::SetKeyboardFocusURL(const KURL& url) {
UpdateTargetURL(focus_url_, mouse_over_url_);
}
-WebViewFrameWidget* WebViewImpl::MainFrameViewWidget() {
+WebFrameWidgetImpl* WebViewImpl::MainFrameViewWidget() {
return web_widget_;
}
-void WebViewImpl::UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason) {
- TRACE_EVENT0("blink", "WebViewImpl::updateAllLifecyclePhases");
- if (!MainFrameImpl())
- return;
-
- PageWidgetDelegate::UpdateLifecycle(*page_, *MainFrameImpl()->GetFrame(),
- requested_update, reason);
- if (requested_update != WebLifecycleUpdate::kAll)
- return;
-
- UpdatePagePopup();
-
- // There is no background color for non-composited WebViews (eg printing).
- if (does_composite_) {
- SkColor background_color = BackgroundColor();
- MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(background_color);
- if (background_color != last_background_color_) {
- last_background_color_ = background_color;
- if (Page* page = page_.Get()) {
- if (auto* main_local_frame = DynamicTo<LocalFrame>(page->MainFrame())) {
- main_local_frame->DidChangeBackgroundColor(background_color,
- false /* color_adjust */);
- }
- }
- }
- }
-
- if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) {
- LocalFrame* frame = MainFrameImpl()->GetFrame();
- WebFrameWidgetBase* frame_widget =
- WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
-
- if (should_dispatch_first_visually_non_empty_layout_ &&
- view->IsVisuallyNonEmpty()) {
- should_dispatch_first_visually_non_empty_layout_ = false;
- // TODO(esprehn): Move users of this callback to something
- // better, the heuristic for "visually non-empty" is bad.
- frame_widget->DidMeaningfulLayout(WebMeaningfulLayout::kVisuallyNonEmpty);
- }
-
- if (should_dispatch_first_layout_after_finished_parsing_ &&
- frame->GetDocument()->HasFinishedParsing()) {
- should_dispatch_first_layout_after_finished_parsing_ = false;
- frame_widget->DidMeaningfulLayout(WebMeaningfulLayout::kFinishedParsing);
- }
-
- if (should_dispatch_first_layout_after_finished_loading_ &&
- frame->GetDocument()->IsLoadCompleted()) {
- should_dispatch_first_layout_after_finished_loading_ = false;
- frame_widget->DidMeaningfulLayout(WebMeaningfulLayout::kFinishedLoading);
- }
- }
-}
-
void WebViewImpl::PaintContent(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
// This should only be used when compositing is not being used for this
// WebView, and it is painting into the recording of its parent.
@@ -1457,6 +1414,8 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
settings->SetSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
settings->SetTargetBlankImpliesNoOpenerEnabledWillBeRemoved(
prefs.target_blank_implies_no_opener_enabled_will_be_removed);
+ settings->SetAllowNonEmptyNavigatorPlugins(
+ prefs.allow_non_empty_navigator_plugins);
RuntimeEnabledFeatures::SetDatabaseEnabled(prefs.databases_enabled);
settings->SetOfflineWebApplicationCacheEnabled(
prefs.application_cache_enabled);
@@ -1701,31 +1660,31 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
for (const auto& ect_distance_pair :
prefs.lazy_frame_loading_distance_thresholds_px) {
switch (ect_distance_pair.first) {
- case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+ case EffectiveConnectionType::kEffectiveConnectionUnknownType:
settings->SetLazyFrameLoadingDistanceThresholdPxUnknown(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ case EffectiveConnectionType::kEffectiveConnectionOfflineType:
settings->SetLazyFrameLoadingDistanceThresholdPxOffline(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+ case EffectiveConnectionType::kEffectiveConnectionSlow2GType:
settings->SetLazyFrameLoadingDistanceThresholdPxSlow2G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_2G:
+ case EffectiveConnectionType::kEffectiveConnection2GType:
settings->SetLazyFrameLoadingDistanceThresholdPx2G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_3G:
+ case EffectiveConnectionType::kEffectiveConnection3GType:
settings->SetLazyFrameLoadingDistanceThresholdPx3G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_4G:
+ case EffectiveConnectionType::kEffectiveConnection4GType:
settings->SetLazyFrameLoadingDistanceThresholdPx4G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+ case EffectiveConnectionType::kEffectiveConnectionTypeLast:
continue;
}
NOTREACHED();
@@ -1734,31 +1693,31 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
for (const auto& ect_distance_pair :
prefs.lazy_image_loading_distance_thresholds_px) {
switch (ect_distance_pair.first) {
- case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+ case EffectiveConnectionType::kEffectiveConnectionUnknownType:
settings->SetLazyImageLoadingDistanceThresholdPxUnknown(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ case EffectiveConnectionType::kEffectiveConnectionOfflineType:
settings->SetLazyImageLoadingDistanceThresholdPxOffline(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+ case EffectiveConnectionType::kEffectiveConnectionSlow2GType:
settings->SetLazyImageLoadingDistanceThresholdPxSlow2G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_2G:
+ case EffectiveConnectionType::kEffectiveConnection2GType:
settings->SetLazyImageLoadingDistanceThresholdPx2G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_3G:
+ case EffectiveConnectionType::kEffectiveConnection3GType:
settings->SetLazyImageLoadingDistanceThresholdPx3G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_4G:
+ case EffectiveConnectionType::kEffectiveConnection4GType:
settings->SetLazyImageLoadingDistanceThresholdPx4G(
ect_distance_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+ case EffectiveConnectionType::kEffectiveConnectionTypeLast:
continue;
}
NOTREACHED();
@@ -1766,24 +1725,24 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
for (const auto& fully_load_k_pair : prefs.lazy_image_first_k_fully_load) {
switch (fully_load_k_pair.first) {
- case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ case EffectiveConnectionType::kEffectiveConnectionOfflineType:
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+ case EffectiveConnectionType::kEffectiveConnectionUnknownType:
settings->SetLazyImageFirstKFullyLoadUnknown(fully_load_k_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+ case EffectiveConnectionType::kEffectiveConnectionSlow2GType:
settings->SetLazyImageFirstKFullyLoadSlow2G(fully_load_k_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_2G:
+ case EffectiveConnectionType::kEffectiveConnection2GType:
settings->SetLazyImageFirstKFullyLoad2G(fully_load_k_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_3G:
+ case EffectiveConnectionType::kEffectiveConnection3GType:
settings->SetLazyImageFirstKFullyLoad3G(fully_load_k_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_4G:
+ case EffectiveConnectionType::kEffectiveConnection4GType:
settings->SetLazyImageFirstKFullyLoad4G(fully_load_k_pair.second);
continue;
- case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+ case EffectiveConnectionType::kEffectiveConnectionTypeLast:
continue;
}
NOTREACHED();
@@ -1791,6 +1750,7 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
settings->SetTouchDragDropEnabled(prefs.touch_drag_drop_enabled);
settings->SetTouchDragEndContextMenu(prefs.touch_dragend_context_menu);
+ settings->SetWebXRImmersiveArAllowed(prefs.webxr_immersive_ar_allowed);
#if defined(OS_MAC)
web_view_impl->SetMaximumLegibleScale(
@@ -1812,7 +1772,7 @@ void WebViewImpl::ThemeChanged() {
return;
LocalFrameView* view = GetPage()->DeprecatedLocalMainFrame()->View();
- WebRect damaged_rect(0, 0, size_.width(), size_.height());
+ IntRect damaged_rect(0, 0, size_.width(), size_.height());
view->InvalidateRect(damaged_rect);
}
@@ -1827,8 +1787,11 @@ void WebViewImpl::ExitFullscreen(LocalFrame& frame) {
}
void WebViewImpl::FullscreenElementChanged(Element* old_element,
- Element* new_element) {
- fullscreen_controller_->FullscreenElementChanged(old_element, new_element);
+ Element* new_element,
+ const FullscreenOptions* options,
+ FullscreenRequestType request_type) {
+ fullscreen_controller_->FullscreenElementChanged(old_element, new_element,
+ options, request_type);
}
bool WebViewImpl::HasHorizontalScrollbar() {
@@ -1842,14 +1805,7 @@ bool WebViewImpl::HasVerticalScrollbar() {
return MainFrameImpl()->GetFrameView()->LayoutViewport()->VerticalScrollbar();
}
-void WebViewImpl::MouseCaptureLost() {
- TRACE_EVENT_NESTABLE_ASYNC_END0("input", "capturing mouse",
- TRACE_ID_LOCAL(this));
- if (page_->DeprecatedLocalMainFrame())
- page_->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
-}
-
-void WebViewImpl::SetFocus(bool enable) {
+void WebViewImpl::SetPageFocus(bool enable) {
if (enable)
page_->GetFocusController().SetActive(true);
page_->GetFocusController().SetFocused(enable);
@@ -1877,19 +1833,10 @@ void WebViewImpl::SetFocus(bool enable) {
}
}
}
- ime_accept_events_ = true;
} else {
CancelPagePopup();
- // Clear focus on the currently focused frame if any.
- if (!page_)
- return;
-
- LocalFrame* frame = DynamicTo<LocalFrame>(page_->MainFrame());
- if (!frame)
- return;
-
- LocalFrame* focused_frame = FocusedLocalFrameInWidget();
+ LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame();
if (focused_frame) {
// Finish an ongoing composition to delete the composition node.
if (focused_frame->GetInputMethodController().HasComposition()) {
@@ -1902,7 +1849,6 @@ void WebViewImpl::SetFocus(bool enable) {
focused_frame->GetInputMethodController().FinishComposingText(
InputMethodController::kKeepSelection);
}
- ime_accept_events_ = false;
}
}
}
@@ -1939,7 +1885,7 @@ WebString WebViewImpl::PageEncoding() const {
WebFrame* WebViewImpl::MainFrame() {
Page* page = page_.Get();
- return WebFrame::FromFrame(page ? page->MainFrame() : nullptr);
+ return WebFrame::FromCoreFrame(page ? page->MainFrame() : nullptr);
}
WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
@@ -1949,6 +1895,18 @@ WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(page->MainFrame()));
}
+std::string WebViewImpl::GetNullFrameReasonForBug1139104() const {
+ Page* page = page_.Get();
+ if (!page)
+ return "WebViewImpl::page";
+ if (!page->MainFrame())
+ return "WebViewImpl::page->MainFrame";
+ LocalFrame* local_frame = DynamicTo<LocalFrame>(page->MainFrame());
+ if (!local_frame)
+ return "WebViewImpl::local_frame";
+ return WebLocalFrameImpl::GetNullFrameReasonForBug1139104(local_frame);
+}
+
void WebViewImpl::DidAttachLocalMainFrame() {
DCHECK(MainFrameImpl());
@@ -1988,10 +1946,13 @@ void WebViewImpl::DidAttachRemoteMainFrame() {
->GetPageScheduler()
->GetAgentGroupScheduler()
.DefaultTaskRunner()));
+
+ auto& viewport = GetPage()->GetVisualViewport();
+ viewport.Reset();
}
void WebViewImpl::DidDetachLocalMainFrame() {
- // The WebWidgetClient that generated the |scoped_defer_main_frame_update_|
+ // The WebFrameWidget that generated the |scoped_defer_main_frame_update_|
// for a local main frame is going away.
scoped_defer_main_frame_update_ = nullptr;
local_main_frame_host_remote_.reset();
@@ -2021,67 +1982,6 @@ void WebViewImpl::SetFocusedFrame(WebFrame* frame) {
core_frame->GetPage()->GetFocusController().SetFocusedFrame(core_frame);
}
-// TODO(dglazkov): Remove and replace with Node:hasEditableStyle.
-// http://crbug.com/612560
-static bool IsElementEditable(const Element* element) {
- element->GetDocument().UpdateStyleAndLayoutTree();
- if (HasEditableStyle(*element))
- return true;
-
- if (auto* text_control = ToTextControlOrNull(element)) {
- if (!text_control->IsDisabledOrReadOnly())
- return true;
- }
-
- return EqualIgnoringASCIICase(
- element->FastGetAttribute(html_names::kRoleAttr), "textbox");
-}
-
-bool WebViewImpl::ScrollFocusedEditableElementIntoView() {
- DCHECK(MainFrameImpl());
- LocalFrameView* main_frame_view = MainFrameImpl()->GetFrame()->View();
- if (!main_frame_view)
- return false;
-
- Element* element = FocusedElement();
- if (!element || !IsElementEditable(element))
- return false;
-
- element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
-
- LayoutObject* layout_object = element->GetLayoutObject();
- if (!layout_object)
- return false;
-
- // Since the page has been resized, the layout may have changed. The page
- // scale animation started by ZoomAndScrollToFocusedEditableRect will scroll
- // only the visual and layout viewports. We'll call ScrollRectToVisible with
- // the stop_at_main_frame_layout_viewport param to ensure the element is
- // actually visible in the page.
- auto params = ScrollAlignment::CreateScrollIntoViewParams(
- ScrollAlignment::CenterIfNeeded(), ScrollAlignment::CenterIfNeeded(),
- mojom::blink::ScrollType::kProgrammatic, false,
- mojom::blink::ScrollBehavior::kInstant);
- params->stop_at_main_frame_layout_viewport = true;
- layout_object->ScrollRectToVisible(
- PhysicalRect(layout_object->AbsoluteBoundingBoxRect()),
- std::move(params));
-
- ZoomAndScrollToFocusedEditableElementRect(
- main_frame_view->RootFrameToDocument(
- element->GetDocument().View()->ConvertToRootFrame(
- layout_object->AbsoluteBoundingBoxRect())),
- main_frame_view->RootFrameToDocument(
- element->GetDocument().View()->ConvertToRootFrame(
- element->GetDocument()
- .GetFrame()
- ->Selection()
- .ComputeRectToScroll(kDoNotRevealExtent))),
- ShouldZoomToLegibleScale(*element));
-
- return true;
-}
-
bool WebViewImpl::ShouldZoomToLegibleScale(const Element& element) {
bool zoom_into_legible_scale =
web_settings_->AutoZoomFocusedNodeToLegibleScale() &&
@@ -2292,7 +2192,8 @@ double WebViewImpl::SetZoomLevel(double zoom_level) {
PropagateZoomFactorToLocalFrameRoots(page_->MainFrame(), zoom_factor);
if (old_zoom_level != zoom_level_) {
- Client()->ZoomLevelChanged();
+ for (auto& observer : observers_)
+ observer.OnZoomLevelChanged();
CancelPagePopup();
}
@@ -2410,6 +2311,8 @@ void WebViewImpl::SetPageLifecycleStateInternal(
(new_state->pagehide_dispatch ==
mojom::blink::PagehideDispatch::kNotDispatched) &&
GetPage()->DispatchedPagehideAndStillHidden();
+ bool eviction_changed =
+ new_state->eviction_enabled != old_state->eviction_enabled;
if (dispatching_pagehide) {
RemoveFocusAndTextInputState();
@@ -2430,8 +2333,6 @@ void WebViewImpl::SetPageLifecycleStateInternal(
}
if (freezing_page)
SetPageFrozen(true);
- if (storing_in_bfcache)
- HookBackForwardCacheEviction(true);
if (restoring_from_bfcache) {
DCHECK(page_restore_params);
// Update the history offset and length value saved in RenderViewImpl, as
@@ -2440,8 +2341,9 @@ void WebViewImpl::SetPageLifecycleStateInternal(
web_view_client_->OnSetHistoryOffsetAndLength(
page_restore_params->pending_history_list_offset,
page_restore_params->current_history_list_length);
- HookBackForwardCacheEviction(false);
}
+ if (eviction_changed)
+ HookBackForwardCacheEviction(new_state->eviction_enabled);
if (resuming_page)
SetPageFrozen(false);
if (showing_page) {
@@ -2504,7 +2406,7 @@ void WebViewImpl::RemoveFocusAndTextInputState() {
// Note that the TextInputState itself is cleared when we clear the focus,
// but no updates to the browser will be triggered until the next animation
// frame, which won't happen if we're freezing the page.
- if (auto* widget = static_cast<WebFrameWidgetBase*>(
+ if (auto* widget = static_cast<WebFrameWidgetImpl*>(
focused_frame->GetWidgetForLocalRoot())) {
widget->FinishComposingText(false /* keep_selection */);
widget->UpdateTextInputState();
@@ -2610,7 +2512,7 @@ void WebViewImpl::DisableAutoResizeForTesting(
}
void WebViewImpl::SetDefaultPageScaleLimits(float min_scale, float max_scale) {
- GetPage()->SetDefaultPageScaleLimits(min_scale, max_scale);
+ dev_tools_emulator_->SetDefaultPageScaleLimits(min_scale, max_scale);
}
void WebViewImpl::SetInitialPageScaleOverride(
@@ -2866,7 +2768,7 @@ void WebViewImpl::TakeFocus(bool reverse) {
}
}
-void WebViewImpl::Show(const base::UnguessableToken& opener_frame_token,
+void WebViewImpl::Show(const LocalFrameToken& opener_frame_token,
NavigationPolicy policy,
const gfx::Rect& rect,
bool opened_by_user_gesture) {
@@ -2886,16 +2788,11 @@ void WebViewImpl::DidShowCreatedWindow() {
web_widget_->AckPendingWindowRect();
}
-void WebViewImpl::SetWindowRect(const gfx::Rect& bounds) {
+void WebViewImpl::SendWindowRectToMainFrameHost(
+ const gfx::Rect& bounds,
+ base::OnceClosure ack_callback) {
DCHECK(local_main_frame_host_remote_);
- DCHECK(web_widget_);
- web_widget_->SetPendingWindowRect(bounds);
- local_main_frame_host_remote_->SetWindowRect(
- bounds, WTF::Bind(&WebViewImpl::DidSetWindowRect, WTF::Unretained(this)));
-}
-
-void WebViewImpl::DidSetWindowRect() {
- web_widget_->AckPendingWindowRect();
+ local_main_frame_host_remote_->SetWindowRect(bounds, std::move(ack_callback));
}
void WebViewImpl::UpdateTargetURL(const WebURL& url,
@@ -3161,13 +3058,14 @@ void WebViewImpl::UpdateFontRenderingFromRendererPrefs() {
#if defined(OS_WIN)
// Cache the system font metrics in blink.
WebFontRendering::SetMenuFontMetrics(
- renderer_preferences_.menu_font_family_name.c_str(),
+ WebString::FromUTF16(renderer_preferences_.menu_font_family_name),
renderer_preferences_.menu_font_height);
WebFontRendering::SetSmallCaptionFontMetrics(
- renderer_preferences_.small_caption_font_family_name.c_str(),
+ WebString::FromUTF16(
+ renderer_preferences_.small_caption_font_family_name),
renderer_preferences_.small_caption_font_height);
WebFontRendering::SetStatusFontMetrics(
- renderer_preferences_.status_font_family_name.c_str(),
+ WebString::FromUTF16(renderer_preferences_.status_font_family_name),
renderer_preferences_.status_font_height);
WebFontRendering::SetAntialiasedTextEnabled(
renderer_preferences_.should_antialias_text);
@@ -3185,12 +3083,15 @@ void WebViewImpl::UpdateFontRenderingFromRendererPrefs() {
gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE);
WebFontRenderStyle::SetSubpixelPositioning(
renderer_preferences_.use_subpixel_positioning);
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && !defined(OS_ANDROID)
if (!renderer_preferences_.system_font_family_name.empty()) {
WebFontRenderStyle::SetSystemFontFamily(blink::WebString::FromUTF8(
renderer_preferences_.system_font_family_name));
}
-#endif // defined(OS_LINUX) && !defined(OS_ANDROID)
+#endif // (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) &&
+ // !defined(OS_ANDROID)
#endif // defined(OS_WIN)
#endif // !defined(OS_MAC)
}
@@ -3289,6 +3190,14 @@ void WebViewImpl::UpdateWebPreferences(
ApplyCommandLineToSettings(SettingsImpl());
}
+void WebViewImpl::AddObserver(WebViewObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void WebViewImpl::RemoveObserver(WebViewObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
void WebViewImpl::SetIsActive(bool active) {
if (GetPage())
GetPage()->GetFocusController().SetActive(active);
@@ -3309,9 +3218,8 @@ void WebViewImpl::SetOpenedByDOM() {
void WebViewImpl::DidCommitLoad(bool is_new_navigation,
bool is_navigation_within_page) {
if (!is_navigation_within_page) {
- should_dispatch_first_visually_non_empty_layout_ = true;
- should_dispatch_first_layout_after_finished_parsing_ = true;
- should_dispatch_first_layout_after_finished_loading_ = true;
+ if (web_widget_)
+ web_widget_->ResetMeaningfulLayoutStateForMainFrame();
if (is_new_navigation)
GetPageScaleConstraintsSet().SetNeedsReset(true);
@@ -3321,6 +3229,11 @@ void WebViewImpl::DidCommitLoad(bool is_new_navigation,
GetPage()->GetVisualViewport().MainFrameDidChangeSize();
}
+void WebViewImpl::DidCommitCompositorFrameForLocalMainFrame() {
+ for (auto& observer : observers_)
+ observer.DidCommitCompositorFrame();
+}
+
void WebViewImpl::ResizeAfterLayout() {
DCHECK(MainFrameImpl());
@@ -3355,7 +3268,8 @@ void WebViewImpl::MainFrameLayoutUpdated() {
if (!web_view_client_)
return;
- web_view_client_->DidUpdateMainFrameLayout();
+ for (auto& observer : observers_)
+ observer.DidUpdateMainFrameLayout();
needs_preferred_size_update_ = true;
}
@@ -3491,12 +3405,17 @@ bool WebViewImpl::TabsToLinks() const {
}
void WebViewImpl::DidChangeRootLayer(bool root_layer_exists) {
+ // The Layer is removed when the main frame's `Document` changes. It also is
+ // removed when the whole `LocalFrame` goes away, in which case we don't
+ // need to DeferMainFrameUpdate() as we will do so if a local MainFrame is
+ // attached in the future.
if (!MainFrameImpl()) {
DCHECK(!root_layer_exists);
return;
}
if (root_layer_exists) {
- UpdateDeviceEmulationTransform();
+ if (!device_emulation_transform_.IsIdentity())
+ UpdateDeviceEmulationTransform();
} else {
// When the document in an already-attached main frame is being replaced by
// a navigation then DidChangeRootLayer(false) will be called. Since we are
@@ -3517,6 +3436,9 @@ void WebViewImpl::InvalidateRect(const IntRect& rect) {
}
void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
+ // TODO(https://crbug.com/1160652): Figure out if Page is null.
+ CHECK(page_);
+
VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
// Store the desired offsets the visual viewport before setting the top
@@ -3543,30 +3465,10 @@ void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
args.elastic_overscroll_delta.y());
UpdateBrowserControlsConstraint(args.browser_controls_constraint);
- if (args.scroll_gesture_did_end)
+ if (args.scroll_gesture_did_end) {
+ // TODO(https://crbug.com/1160652): Figure out if MainFrameImpl is null.
+ CHECK(MainFrameImpl());
MainFrameImpl()->GetFrame()->GetEventHandler().MarkHoverStateDirty();
-}
-
-void WebViewImpl::RecordManipulationTypeCounts(cc::ManipulationInfo info) {
- if (!MainFrameImpl())
- return;
-
- if ((info & cc::kManipulationInfoWheel) == cc::kManipulationInfoWheel) {
- UseCounter::Count(MainFrameImpl()->GetDocument(),
- WebFeature::kScrollByWheel);
- }
- if ((info & cc::kManipulationInfoTouch) == cc::kManipulationInfoTouch) {
- UseCounter::Count(MainFrameImpl()->GetDocument(),
- WebFeature::kScrollByTouch);
- }
- if ((info & cc::kManipulationInfoPinchZoom) ==
- cc::kManipulationInfoPinchZoom) {
- UseCounter::Count(MainFrameImpl()->GetDocument(), WebFeature::kPinchZoom);
- }
- if ((info & cc::kManipulationInfoPrecisionTouchPad) ==
- cc::kManipulationInfoPrecisionTouchPad) {
- UseCounter::Count(MainFrameImpl()->GetDocument(),
- WebFeature::kScrollByPrecisionTouchPad);
}
}
@@ -3597,13 +3499,18 @@ Node* WebViewImpl::FindNodeFromScrollableCompositorElementId(
void WebViewImpl::UpdateDeviceEmulationTransform() {
GetPage()->GetVisualViewport().SetNeedsPaintPropertyUpdate();
- if (MainFrameImpl()) {
+ if (auto* main_frame = MainFrameImpl()) {
// When the device emulation transform is updated, to avoid incorrect
// scales and fuzzy raster from the compositor, force all content to
// pick ideal raster scales.
// TODO(wjmaclean): This is only done on the main frame's widget currently,
// it should update all local frames.
- MainFrameImpl()->FrameWidgetImpl()->SetNeedsRecalculateRasterScales();
+ main_frame->FrameWidgetImpl()->SetNeedsRecalculateRasterScales();
+
+ // Device emulation transform also affects the overriding visible rect
+ // which is used as the overflow rect of the main frame layout view.
+ if (auto* view = main_frame->GetFrameView())
+ view->SetNeedsPaintPropertyUpdate();
}
}
@@ -3619,6 +3526,8 @@ void WebViewImpl::SetVisibilityState(
if (!is_initial_state) {
// Preserve the side effects of visibility change.
web_view_client_->OnPageVisibilityChanged(visibility_state);
+ for (auto& observer : observers_)
+ observer.OnPageVisibilityChanged(visibility_state);
}
GetPage()->SetVisibilityState(visibility_state, is_initial_state);
GetPage()->GetPageScheduler()->SetPageVisible(
@@ -3650,10 +3559,6 @@ LocalFrame* WebViewImpl::FocusedLocalFrameInWidget() const {
return focused_frame;
}
-LocalFrame* WebViewImpl::FocusedLocalFrameAvailableForIme() const {
- return ime_accept_events_ ? FocusedLocalFrameInWidget() : nullptr;
-}
-
void WebViewImpl::SetPageFrozen(bool frozen) {
Scheduler()->SetPageFrozen(frozen);
web_view_client_->OnPageFrozenChanged(frozen);
@@ -3689,11 +3594,4 @@ void WebViewImpl::SetDeviceColorSpaceForTesting(
web_widget_->SetDeviceColorSpaceForTesting(color_space);
}
-void WebViewImpl::RunPaintBenchmark(int repeat_count,
- cc::PaintBenchmarkResult& result) {
- DCHECK(MainFrameImpl());
- if (auto* frame_view = MainFrameImpl()->GetFrameView())
- frame_view->RunPaintBenchmark(repeat_count, result);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
index 165699ca8d9..297d3e515ab 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -41,6 +41,7 @@
#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/page/page.mojom-blink.h"
@@ -48,12 +49,12 @@
#include "third_party/blink/public/mojom/renderer_preference_watcher.mojom-blink.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/web_input_event_result.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_vector.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_navigation_policy.h"
#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/public/web/web_view_observer.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/exported/web_page_popup_impl.h"
#include "third_party/blink/renderer/core/frame/resize_viewport_anchor.h"
@@ -94,7 +95,7 @@ class WebLocalFrame;
class WebLocalFrameImpl;
class WebSettingsImpl;
class WebViewClient;
-class WebViewFrameWidget;
+class WebFrameWidgetImpl;
enum class FullscreenRequestType;
@@ -136,7 +137,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void DidDetachLocalMainFrame() override;
void DidAttachRemoteMainFrame() override;
void DidDetachRemoteMainFrame() override;
- void SetPrerendererClient(WebPrerendererClient*) override;
+ void SetNoStatePrefetchClient(WebNoStatePrefetchClient*) override;
WebSettings* GetSettings() override;
WebString PageEncoding() const override;
void SetTabKeyCyclesThroughElements(bool value) override;
@@ -144,13 +145,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetIsActive(bool value) override;
void SetWindowFeatures(const WebWindowFeatures&) override;
void SetOpenedByDOM() override;
- void ResizeWithBrowserControls(const gfx::Size& main_frame_widget_size,
- float top_controls_height,
- float bottom_controls_height,
- bool browser_controls_shrink_layout) override;
- void ResizeWithBrowserControls(const gfx::Size& main_frame_widget_size,
- const gfx::Size& visible_viewport_size,
- cc::BrowserControlsParams) override;
WebFrame* MainFrame() override;
WebLocalFrame* FocusedFrame() override;
void SetFocusedFrame(WebFrame*) override;
@@ -169,7 +163,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetVisualViewportOffset(const gfx::PointF&) override;
gfx::PointF VisualViewportOffset() const override;
gfx::SizeF VisualViewportSize() const override;
- void Resize(const gfx::Size&) override;
void SetScreenOrientationOverrideForTesting(
base::Optional<blink::mojom::ScreenOrientation> orientation) override;
void UseSynchronousResizeModeForTesting(bool enable) override;
@@ -196,7 +189,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void DidCloseContextMenu() override;
void CancelPagePopup() override;
WebPagePopupImpl* GetPagePopup() const override { return page_popup_.get(); }
- void AcceptLanguagesChanged() override;
void SetPageFrozen(bool frozen) override;
WebFrameWidget* MainFrameWidget() override;
void SetBaseBackgroundColor(SkColor) override;
@@ -211,6 +203,10 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetWebPreferences(const web_pref::WebPreferences& preferences) override;
const web_pref::WebPreferences& GetWebPreferences() override;
+ // Functions to add and remove observers for this object.
+ void AddObserver(WebViewObserver* observer);
+ void RemoveObserver(WebViewObserver* observer);
+
// Overrides the page's background and base background color. You
// can use this to enforce a transparent background, which is useful if you
// want to have some custom background rendered behind the widget.
@@ -221,8 +217,26 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void SetBaseBackgroundColorOverride(SkColor);
void ClearBaseBackgroundColorOverride();
+ // Resize the WebView. You likely should be using
+ // MainFrameWidget()->Resize instead.
+ void Resize(const gfx::Size&);
+
+ // This method is used for testing.
+ // Resize the view at the same time as changing the state of the top
+ // controls. If |browser_controls_shrink_layout| is true, the embedder shrunk
+ // the WebView size by the browser controls height.
+ void ResizeWithBrowserControls(const gfx::Size& main_frame_widget_size,
+ float top_controls_height,
+ float bottom_controls_height,
+ bool browser_controls_shrink_layout);
+ // Same as ResizeWithBrowserControls(const gfx::Size&,float,float,bool), but
+ // includes all browser controls params such as the min heights.
+ void ResizeWithBrowserControls(const gfx::Size& main_frame_widget_size,
+ const gfx::Size& visible_viewport_size,
+ cc::BrowserControlsParams);
+
// Requests a page-scale animation based on the specified point/rect.
- void AnimateDoubleTapZoom(const gfx::Point&, const WebRect& block_bounds);
+ void AnimateDoubleTapZoom(const gfx::Point&, const gfx::Rect& block_bounds);
// mojom::blink::PageBroadcast method:
void SetPageLifecycleState(
@@ -290,6 +304,9 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// outside this class.
WebLocalFrameImpl* MainFrameImpl() const;
+ // TODO(https://crbug.com/1139104): Remove this.
+ std::string GetNullFrameReasonForBug1139104() const;
+
// Changes the zoom and scroll for zooming into an editable element
// with bounds |element_bounds_in_document| and caret bounds
// |caret_bounds_in_document|.
@@ -324,7 +341,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// notification unless the view did not need a layout.
void MainFrameLayoutUpdated();
void ResizeAfterLayout();
-
+ void DidCommitCompositorFrameForLocalMainFrame();
void DidChangeContentsSize();
void PageScaleFactorChanged();
void MainFrameScrollOffsetChanged();
@@ -367,11 +384,11 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void FullFramePluginZoomLevelChanged(double zoom_level);
// Requests a page-scale animation based on the specified rect.
- void ZoomToFindInPageRect(const WebRect&);
+ void ZoomToFindInPageRect(const gfx::Rect&);
void ComputeScaleAndScrollForBlockRect(
const gfx::Point& hit_point,
- const WebRect& block_rect,
+ const gfx::Rect& block_rect,
float padding,
float default_scale_when_already_legible,
float& scale,
@@ -398,7 +415,10 @@ class CORE_EXPORT WebViewImpl final : public WebView,
const FullscreenOptions*,
FullscreenRequestType);
void ExitFullscreen(LocalFrame&);
- void FullscreenElementChanged(Element* old_element, Element* new_element);
+ void FullscreenElementChanged(Element* old_element,
+ Element* new_element,
+ const FullscreenOptions* options,
+ FullscreenRequestType);
// Sends a request to the main frame's view to resize, and updates the page
// scale limits if needed.
@@ -467,8 +487,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// limit.
void SetMaximumLegibleScale(float);
- void SetMainFrameViewWidget(WebViewFrameWidget* widget);
- WebViewFrameWidget* MainFrameViewWidget();
+ void SetMainFrameViewWidget(WebFrameWidgetImpl* widget);
+ WebFrameWidgetImpl* MainFrameViewWidget();
// Called when hovering over an anchor with the given URL.
void SetMouseOverURL(const KURL&);
@@ -476,8 +496,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// Called when keyboard focus switches to an anchor with the given URL.
void SetKeyboardFocusURL(const KURL&);
- void RunPaintBenchmark(int repeat_count, cc::PaintBenchmarkResult& result);
-
// Asks the browser process to activate this web view.
void Focus();
@@ -486,12 +504,25 @@ class CORE_EXPORT WebViewImpl final : public WebView,
void TakeFocus(bool reverse);
// Shows a previously created WebView (via window.open()).
- void Show(const base::UnguessableToken& opener_frame_token,
+ void Show(const LocalFrameToken& opener_frame_token,
NavigationPolicy policy,
const gfx::Rect& rect,
bool opened_by_user_gesture);
- void SetWindowRect(const gfx::Rect& bounds);
+ // Send the window rect to the browser and call `ack_callback` when the
+ // browser has processed it.
+ void SendWindowRectToMainFrameHost(const gfx::Rect& bounds,
+ base::OnceClosure ack_callback);
+
+ // TODO(crbug.com/1149992): This is called from the associated widget and this
+ // code should eventually move out of WebView into somewhere else.
+ void ApplyViewportChanges(const ApplyViewportChangesArgs& args);
+
+ // Indication that the root layer for the main frame widget has changed.
+ void DidChangeRootLayer(bool root_layer_exists);
+
+ // Sets the page focus.
+ void SetPageFocus(bool enable);
// This method is used for testing.
// Resizes the unscaled (page scale = 1.0) visual viewport. Normally the
@@ -518,18 +549,10 @@ class CORE_EXPORT WebViewImpl final : public WebView,
friend class frame_test_helpers::WebViewHelper;
friend class SimCompositor;
friend class WebView; // So WebView::Create can call our constructor
- friend class WebViewFrameWidget;
friend class WTF::RefCounted<WebViewImpl>;
- // These are temporary methods to allow WebViewFrameWidget to delegate to
- // WebViewImpl. We expect to eventually move these out.
- void UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason);
+ void AcceptLanguagesChanged();
void ThemeChanged();
- void ApplyViewportChanges(const ApplyViewportChangesArgs& args);
- void RecordManipulationTypeCounts(cc::ManipulationInfo info);
- void MouseCaptureLost();
- void SetFocus(bool enable) override;
// Update the target url locally and tell the browser that the target URL has
// changed. If |url| is empty, show |fallback_url|.
@@ -587,26 +610,22 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// while keeping it smaller than page width.
//
// This method can only be called if the main frame is local.
- WebRect WidenRectWithinPageBounds(const WebRect& source,
- int target_margin,
- int minimum_margin);
+ gfx::Rect WidenRectWithinPageBounds(const gfx::Rect& source,
+ int target_margin,
+ int minimum_margin);
void EnablePopupMouseWheelEventListener(WebLocalFrameImpl* local_root);
void DisablePopupMouseWheelEventListener();
float DeviceScaleFactor() const;
- void DidChangeRootLayer(bool root_layer_exists);
-
LocalFrame* FocusedLocalFrameInWidget() const;
- LocalFrame* FocusedLocalFrameAvailableForIme() const;
// Clear focus and text input state of the page. If there was a focused
// element, this will trigger updates to observers and send focus, selection,
// and text input-related events.
void RemoveFocusAndTextInputState();
- bool ScrollFocusedEditableElementIntoView();
// Finds the zoom and scroll parameters for zooming into an editable element
// with bounds |element_bounds_in_document| and caret bounds
// |caret_bounds_in_document|. If the original element belongs to the local
@@ -629,10 +648,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// Corresponds to a Show method call.
void DidShowCreatedWindow();
- // Callback when the window rect has been adjusted by the browser.
- // Corresponds to a SetWindowRect method call.
- void DidSetWindowRect();
-
// Can be null (e.g. unittests, shared workers, etc).
WebViewClient* web_view_client_;
Persistent<ChromeClient> chrome_client_;
@@ -714,11 +729,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
float compositor_device_scale_factor_override_ = 0.f;
TransformationMatrix device_emulation_transform_;
- // TODO(ekaramad): Can we remove this and make sure IME events are not called
- // when there is no page focus?
- // Represents whether or not this object should process incoming IME events.
- bool ime_accept_events_ = true;
-
// The popup associated with an input/select element. The popup is owned via
// closership (self-owned-but-deleted-via-close) by RenderWidget. We also hold
// a reference here because we can extend the lifetime of the popup while
@@ -753,13 +763,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
SkColor base_background_color_override_ = Color::kTransparent;
bool background_color_override_enabled_ = false;
SkColor background_color_override_ = Color::kTransparent;
- base::Optional<SkColor> last_background_color_;
float zoom_factor_override_ = 0.f;
- bool should_dispatch_first_visually_non_empty_layout_ = false;
- bool should_dispatch_first_layout_after_finished_parsing_ = false;
- bool should_dispatch_first_layout_after_finished_loading_ = false;
-
FloatSize elastic_overscroll_;
// If true, we send IPC messages when |preferred_size_| changes.
@@ -785,7 +790,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// The WebWidget for the main frame. This is expected to be unset when the
// WebWidget destroys itself. This will be null if the main frame is remote.
- WeakPersistent<WebViewFrameWidget> web_widget_;
+ WeakPersistent<WebFrameWidgetImpl> web_widget_;
// We defer commits when transitioning to a new page. ChromeClientImpl calls
// StopDeferringCommits() to release this when a new page is loaded.
@@ -810,7 +815,6 @@ class CORE_EXPORT WebViewImpl final : public WebView,
base::Optional<mojom::blink::ScreenOrientation> screen_orientation_override_;
- mojom::blink::PageLifecycleStatePtr lifecycle_state_;
mojo::AssociatedReceiver<mojom::blink::PageBroadcast> receiver_;
// These are observing changes in |renderer_preferences_|. This is used for
@@ -818,6 +822,9 @@ class CORE_EXPORT WebViewImpl final : public WebView,
mojo::RemoteSet<mojom::blink::RendererPreferenceWatcher>
renderer_preference_watchers_;
+ // All the registered observers.
+ base::ObserverList<WebViewObserver> observers_;
+
base::WeakPtrFactory<WebViewImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_observer.cc b/chromium/third_party/blink/renderer/core/exported/web_view_observer.cc
new file mode 100644
index 00000000000..c206c59a4a1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_observer.cc
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/web/web_view_observer.h"
+
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+
+namespace blink {
+
+WebViewObserver::WebViewObserver(WebView* web_view)
+ : web_view_(static_cast<WebViewImpl*>(web_view)) {
+ // |web_view_| can be null on unit testing or if Observe() is used.
+ if (web_view_) {
+ web_view_->AddObserver(this);
+ }
+}
+
+WebViewObserver::~WebViewObserver() {
+ Observe(nullptr);
+}
+
+WebView* WebViewObserver::GetWebView() const {
+ return web_view_;
+}
+
+void WebViewObserver::Observe(WebView* web_view) {
+ if (web_view_) {
+ web_view_->RemoveObserver(this);
+ }
+
+ web_view_ = static_cast<WebViewImpl*>(web_view);
+ if (web_view_) {
+ web_view_->AddObserver(this);
+ }
+}
+
+void WebViewObserver::WebViewDestroyed() {
+ Observe(nullptr);
+ OnDestruct();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_test.cc b/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
index e1c97389c15..ceeba555963 100644
--- a/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -56,6 +56,7 @@
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/page/drag_operation.h"
#include "third_party/blink/public/common/page/page_zoom.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/widget/device_emulation_params.h"
#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
@@ -67,22 +68,22 @@
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/public_buildflags.h"
+#include "third_party/blink/public/test/test_web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_console_message.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_frame.h"
-#include "third_party/blink/public/web/web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_hit_test_result.h"
#include "third_party/blink/public/web/web_input_method_controller.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/public/web/web_non_composited_widget_client.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/public/web/web_widget.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_document.h"
#include "third_party/blink/renderer/core/css/media_query_list_listener.h"
#include "third_party/blink/renderer/core/css/media_query_matcher.h"
@@ -102,8 +103,8 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/forms/external_date_time_chooser.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
@@ -152,6 +153,7 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-blink.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "v8/include/v8.h"
@@ -162,9 +164,9 @@
#endif // BUILDFLAG(ENABLE_UNHANDLED_TAP)
using blink::frame_test_helpers::LoadFrame;
-using blink::url_test_helpers::ToKURL;
-using blink::url_test_helpers::RegisterMockedURLLoad;
using blink::test::RunPendingTasks;
+using blink::url_test_helpers::RegisterMockedURLLoad;
+using blink::url_test_helpers::ToKURL;
namespace blink {
@@ -216,7 +218,9 @@ class AutoResizeWebViewClient : public frame_test_helpers::TestWebViewClient {
class WebViewTest : public testing::Test {
public:
- WebViewTest() : base_url_("http://www.test.com/") {}
+ explicit WebViewTest(frame_test_helpers::CreateTestWebFrameWidgetCallback
+ create_web_frame_callback = base::NullCallback())
+ : web_view_helper_(std::move(create_web_frame_callback)) {}
void SetUp() override {
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
@@ -283,33 +287,7 @@ class WebViewTest : public testing::Test {
return detector;
}
- // Helper function that creates a widget for a main frame.
- // Copy the steps done from WebViewHelper::InitializeWithOpener() to set up
- // the appropriate pointers!
- WebFrameWidget* CreateWidgetForMainFrame(WebWidgetClient* client,
- WebLocalFrame* frame) {
- mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
- frame_widget_receiver =
- frame_widget.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
- ignore_result(frame_widget_host.BindNewEndpointAndPassDedicatedReceiver());
-
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
- widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::WidgetHost> widget_host_remote;
- ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
-
- return blink::WebFrameWidget::CreateForMainFrame(
- client, frame, frame_widget_host.Unbind(),
- std::move(frame_widget_receiver), widget_host_remote.Unbind(),
- std::move(widget_receiver), viz::FrameSinkId());
- }
-
- std::string base_url_;
+ std::string base_url_{"http://www.test.com/"};
frame_test_helpers::WebViewHelper web_view_helper_;
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
};
@@ -503,18 +481,13 @@ TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) {
// Note: this test doesn't use WebViewHelper since it intentionally runs
// initialization code between WebView and WebLocalFrame creation.
frame_test_helpers::TestWebViewClient web_view_client;
- frame_test_helpers::TestWebWidgetClient web_widget_client;
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler =
- blink::scheduler::WebThreadScheduler::MainThreadScheduler()
- ->CreateAgentGroupScheduler();
WebViewImpl* web_view = static_cast<WebViewImpl*>(
WebView::Create(&web_view_client,
/*is_hidden=*/false,
/*is_inside_portal=*/false,
/*compositing_enabled=*/true,
/*opener=*/nullptr, mojo::NullAssociatedReceiver(),
- *agent_group_scheduler));
+ web_view_helper_.GetAgentGroupScheduler()));
EXPECT_NE(SK_ColorBLUE, web_view->BackgroundColor());
// WebView does not have a frame yet, but we should still be able to set the
@@ -523,28 +496,16 @@ TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) {
EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
frame_test_helpers::TestWebFrameClient web_frame_client;
- WebLocalFrame* frame =
- WebLocalFrame::CreateMainFrame(web_view, &web_frame_client, nullptr,
- base::UnguessableToken::Create(), nullptr);
+ WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
+ web_view, &web_frame_client, nullptr, LocalFrameToken(), nullptr);
web_frame_client.Bind(frame);
- {
- // Copy the steps done from WebViewHelper::InitializeWithOpener() to set up
- // the appropriate pointers!
- WebFrameWidget* widget =
- CreateWidgetForMainFrame(&web_widget_client, frame);
- cc::LayerTreeSettings layer_tree_settings =
- frame_test_helpers::GetSynchronousSingleThreadLayerTreeSettings();
- web_widget_client.set_layer_tree_host(widget->InitializeCompositing(
- web_widget_client.main_thread_scheduler(),
- web_widget_client.task_graph_runner(), true, ScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- widget->SetCompositorVisible(true);
- web_view->DidAttachLocalMainFrame();
- }
+ frame_test_helpers::TestWebFrameWidget* widget =
+ web_view_helper_.CreateFrameWidgetAndInitializeCompositing(frame);
+ web_view->DidAttachLocalMainFrame();
// The color should be passed to the compositor.
- cc::LayerTreeHost* host = web_widget_client.layer_tree_host();
+ cc::LayerTreeHost* host = widget->LayerTreeHostForTesting();
EXPECT_EQ(SK_ColorBLUE, web_view->BackgroundColor());
EXPECT_EQ(SK_ColorBLUE, host->background_color());
@@ -733,7 +694,9 @@ TEST_F(WebViewTest, PlatformColorsChangedOnDeviceEmulation) {
ASSERT_TRUE(span1);
// Check non-MobileLayoutTheme color.
- Color original = LayoutTheme::GetTheme().FocusRingColor();
+ // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
+ Color original = LayoutTheme::GetTheme().FocusRingColor(
+ ComputedStyle::InitialStyle().UsedColorScheme());
EXPECT_EQ(original, OutlineColor(span1));
// Set the focus ring color for the mobile theme to something known.
@@ -1897,6 +1860,9 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition) {
}
TEST_F(WebViewTest, IsSelectionAnchorFirst) {
+ // TODO(xidachen): crbug.com/1150389, Make this test work with the feature.
+ if (RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled())
+ return;
RegisterMockedHttpURLLoad("input_field_populated.html");
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "input_field_populated.html");
@@ -2526,13 +2492,19 @@ TEST_F(WebViewTest, BackForwardRestoreScroll) {
// Go back, then forward, then back again.
main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, false /* has_event */,
+ nullptr);
main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item2->Url(), WebFrameLoadType::kBackForward, item2.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, false /* has_event */,
+ nullptr);
main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, false /* has_event */,
+ nullptr);
web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
DocumentUpdateReason::kTest);
@@ -2550,11 +2522,15 @@ TEST_F(WebViewTest, BackForwardRestoreScroll) {
// forward navigation.
main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, false /* has_event */,
+ nullptr);
main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item3->Url(), WebFrameLoadType::kBackForward, item3.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, false, nullptr);
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, false /* has_event */,
+ nullptr);
// The scroll offset is only applied via invoking the anchor via the main
// lifecycle, or a forced layout.
// TODO(chrishtr): At the moment, WebLocalFrameImpl::GetScrollOffset() does
@@ -2747,21 +2723,20 @@ ExternalDateTimeChooser* WebViewTest::GetExternalDateTimeChooser(
TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient) {
// Note: this test doesn't use WebViewHelper since WebViewHelper creates an
// internal WebViewClient on demand if the supplied WebViewClient is null.
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler =
- blink::scheduler::WebThreadScheduler::MainThreadScheduler()
- ->CreateAgentGroupScheduler();
WebViewImpl* web_view = static_cast<WebViewImpl*>(WebView::Create(
/*client=*/nullptr, /*is_hidden=*/false, /*is_inside_portal=*/false,
/*compositing_enabled=*/false, /*opener=*/nullptr,
- mojo::NullAssociatedReceiver(), *agent_group_scheduler));
+ mojo::NullAssociatedReceiver(),
+ web_view_helper_.GetAgentGroupScheduler()));
frame_test_helpers::TestWebFrameClient web_frame_client;
- frame_test_helpers::TestWebWidgetClient web_widget_client;
- WebLocalFrame* local_frame =
- WebLocalFrame::CreateMainFrame(web_view, &web_frame_client, nullptr,
- base::UnguessableToken::Create(), nullptr);
+ WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
+ web_view, &web_frame_client, nullptr, LocalFrameToken(), nullptr);
web_frame_client.Bind(local_frame);
- CreateWidgetForMainFrame(&web_widget_client, local_frame);
+ WebNonCompositedWidgetClient widget_client;
+ frame_test_helpers::TestWebFrameWidget* widget =
+ web_view_helper_.CreateFrameWidget(local_frame);
+ widget->InitializeNonCompositing(&widget_client);
+ web_view->DidAttachLocalMainFrame();
WebGestureEvent event(WebInputEvent::Type::kGestureTap,
WebInputEvent::kNoModifiers,
@@ -3007,7 +2982,7 @@ TEST_F(WebViewTest, TouchDragContextMenuWithoutDrag) {
// Simulate the end of a non-moving drag.
const gfx::PointF dragend_point(250, 8);
web_view->MainFrameViewWidget()->DragSourceEndedAt(
- dragend_point, dragend_point, kDragOperationNone);
+ dragend_point, dragend_point, ui::mojom::blink::DragOperation::kNone);
EXPECT_TRUE(
web_view->GetPage()->GetContextMenuController().ContextMenuNodeForFrame(
web_view->MainFrameImpl()->GetFrame()));
@@ -3046,7 +3021,7 @@ TEST_F(WebViewTest, TouchDragContextMenuWithDrag) {
// Simulate the end of a drag.
const gfx::PointF dragend_point(270, 28);
web_view->MainFrameViewWidget()->DragSourceEndedAt(
- dragend_point, dragend_point, kDragOperationNone);
+ dragend_point, dragend_point, ui::mojom::blink::DragOperation::kNone);
EXPECT_FALSE(
web_view->GetPage()->GetContextMenuController().ContextMenuNodeForFrame(
web_view->MainFrameImpl()->GetFrame()));
@@ -3154,7 +3129,7 @@ TEST_F(WebViewTest, FinishComposingTextDoesNotDismissHandles) {
WebString target = WebString::FromUTF8("target");
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
- static_cast<WebView*>(web_view)->SetFocus(true);
+ web_view->SetPageFocus(true);
WebInputMethodController* active_input_method_controller =
frame->FrameWidget()->GetActiveWebInputMethodController();
EXPECT_TRUE(TapElementById(WebInputEvent::Type::kGestureTap, target));
@@ -3431,11 +3406,14 @@ TEST_F(WebViewTest, KeyDownScrollsHandled) {
WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
}
-class MiddleClickAutoscrollWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
+class MiddleClickAutoscrollWebFrameWidget
+ : public frame_test_helpers::TestWebFrameWidget {
public:
- // WebWidgetClient methods
+ template <typename... Args>
+ explicit MiddleClickAutoscrollWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {}
+ // FrameWidget overrides:
void DidChangeCursor(const ui::Cursor& cursor) override {
last_cursor_type_ = cursor.type();
}
@@ -3449,8 +3427,15 @@ class MiddleClickAutoscrollWebWidgetClient
ui::mojom::blink::CursorType::kPointer;
};
-TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
- MiddleClickAutoscrollWebWidgetClient client;
+class MiddleClickWebViewTest : public WebViewTest {
+ public:
+ MiddleClickWebViewTest()
+ : WebViewTest(base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ MiddleClickAutoscrollWebFrameWidget>)) {}
+};
+
+TEST_F(MiddleClickWebViewTest, MiddleClickAutoscrollCursor) {
ScopedMiddleClickAutoscrollForTest middle_click_autoscroll(true);
RegisterMockedHttpURLLoad("content-width-1000.html");
@@ -3473,12 +3458,15 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
for (const CursorTests current_test : cursor_tests) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
- base_url_ + "content-width-1000.html", nullptr, nullptr, &client);
+ base_url_ + "content-width-1000.html", nullptr, nullptr);
web_view->MainFrameWidget()->Resize(
gfx::Size(current_test.resize_width, current_test.resize_height));
UpdateAllLifecyclePhases();
RunPendingTasks();
+ MiddleClickAutoscrollWebFrameWidget* widget =
+ static_cast<MiddleClickAutoscrollWebFrameWidget*>(
+ web_view_helper_.GetMainFrameWidget());
LocalFrame* local_frame =
To<WebLocalFrameImpl>(web_view->MainFrame())->GetFrame();
@@ -3501,13 +3489,13 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
web_view->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
- EXPECT_EQ(current_test.expected_cursor, client.GetLastCursorType());
+ EXPECT_EQ(current_test.expected_cursor, widget->GetLastCursorType());
// Even if a plugin tries to change the cursor type, that should be ignored
// during middle-click autoscroll.
web_view->GetChromeClient().SetCursorForPlugin(PointerCursor(),
local_frame);
- EXPECT_EQ(current_test.expected_cursor, client.GetLastCursorType());
+ EXPECT_EQ(current_test.expected_cursor, widget->GetLastCursorType());
// End middle-click autoscroll.
mouse_event.SetType(WebInputEvent::Type::kMouseDown);
@@ -3518,7 +3506,7 @@ TEST_F(WebViewTest, MiddleClickAutoscrollCursor) {
WebCoalescedInputEvent(mouse_event, ui::LatencyInfo()));
web_view->GetChromeClient().SetCursorForPlugin(IBeamCursor(), local_frame);
- EXPECT_EQ(IBeamCursor().type(), client.GetLastCursorType());
+ EXPECT_EQ(IBeamCursor().type(), widget->GetLastCursorType());
}
// Explicitly reset to break dependency on locally scoped client.
@@ -3754,20 +3742,18 @@ class ViewCreatingWebViewClient : public frame_test_helpers::TestWebViewClient {
public:
ViewCreatingWebViewClient() : did_focus_called_(false) {}
- // WebViewClient methods
+ // WebViewClient overrides.
WebView* CreateView(WebLocalFrame* opener,
const WebURLRequest&,
const WebWindowFeatures&,
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) override {
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) override {
return web_view_helper_.InitializeWithOpener(opener);
}
-
- // WebWidgetClient methods
void DidFocus() override { did_focus_called_ = true; }
bool DidFocusCalled() const { return did_focus_called_; }
@@ -3846,9 +3832,9 @@ class ViewReusingWebViewClient : public frame_test_helpers::TestWebViewClient {
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) override {
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) override {
return web_view_;
}
@@ -4007,13 +3993,14 @@ class CreateChildCounterFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
CreateChildCounterFrameClient() : count_(0) {}
- WebLocalFrame* CreateChildFrame(WebLocalFrame* parent,
- mojom::blink::TreeScopeType,
- const WebString& name,
- const WebString& fallback_name,
- const FramePolicy&,
- const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override;
+ WebLocalFrame* CreateChildFrame(
+ mojom::blink::TreeScopeType,
+ const WebString& name,
+ const WebString& fallback_name,
+ const FramePolicy&,
+ const WebFrameOwnerProperties&,
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override;
int Count() const { return count_; }
@@ -4022,17 +4009,17 @@ class CreateChildCounterFrameClient
};
WebLocalFrame* CreateChildCounterFrameClient::CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy& frame_policy,
const WebFrameOwnerProperties& frame_owner_properties,
- mojom::blink::FrameOwnerElementType frame_owner_element_type) {
+ mojom::blink::FrameOwnerElementType frame_owner_element_type,
+ WebPolicyContainerBindParams policy_container_bind_params) {
++count_;
return TestWebFrameClient::CreateChildFrame(
- parent, scope, name, fallback_name, frame_policy, frame_owner_properties,
- frame_owner_element_type);
+ scope, name, fallback_name, frame_policy, frame_owner_properties,
+ frame_owner_element_type, std::move(policy_container_bind_params));
}
TEST_F(WebViewTest, ChangeDisplayMode) {
@@ -4040,12 +4027,12 @@ TEST_F(WebViewTest, ChangeDisplayMode) {
WebViewImpl* web_view =
web_view_helper_.InitializeAndLoad(base_url_ + "display_mode.html");
- String content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ String content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
EXPECT_EQ("regular-ui", content);
web_view->MainFrameImpl()->LocalRootFrameWidget()->SetDisplayMode(
mojom::blink::DisplayMode::kMinimalUi);
- content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
EXPECT_EQ("minimal-ui", content);
web_view_helper_.Reset();
}
@@ -4056,13 +4043,13 @@ TEST_F(WebViewTest, ChangeDisplayModeChildFrame) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "iframe-display_mode.html");
- String content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ String content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
// An iframe inserts whitespace into the content.
EXPECT_EQ("regular-ui", content.StripWhiteSpace());
web_view->MainFrameImpl()->LocalRootFrameWidget()->SetDisplayMode(
mojom::blink::DisplayMode::kMinimalUi);
- content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
// An iframe inserts whitespace into the content.
EXPECT_EQ("minimal-ui", content.StripWhiteSpace());
web_view_helper_.Reset();
@@ -4073,12 +4060,12 @@ TEST_F(WebViewTest, ChangeDisplayModeAlertsListener) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "display_mode_listener.html");
- String content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ String content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
EXPECT_EQ("regular-ui", content);
web_view->MainFrameImpl()->LocalRootFrameWidget()->SetDisplayMode(
mojom::blink::DisplayMode::kMinimalUi);
- content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
EXPECT_EQ("minimal-ui", content);
web_view_helper_.Reset();
}
@@ -4089,13 +4076,13 @@ TEST_F(WebViewTest, ChangeDisplayModeChildFrameAlertsListener) {
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
base_url_ + "iframe-display_mode_listener.html");
- String content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ String content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
// An iframe inserts whitespace into the content.
EXPECT_EQ("regular-ui", content.StripWhiteSpace());
web_view->MainFrameImpl()->LocalRootFrameWidget()->SetDisplayMode(
mojom::blink::DisplayMode::kMinimalUi);
- content = WebFrameContentDumper::DumpWebViewAsText(web_view, 21);
+ content = TestWebFrameContentDumper::DumpWebViewAsText(web_view, 21);
// An iframe inserts whitespace into the content.
EXPECT_EQ("minimal-ui", content.StripWhiteSpace());
web_view_helper_.Reset();
@@ -4144,31 +4131,16 @@ TEST_F(WebViewTest, AddFrameInChildInNavigateUnload) {
web_view_helper_.Reset();
}
-class FakeFrameWidgetHost : public mojom::blink::FrameWidgetHost {
+class TouchEventConsumersWebFrameWidgetHost
+ : public frame_test_helpers::TestWebFrameWidgetHost {
public:
- FakeFrameWidgetHost()
- : has_touch_event_handler_count_(), has_touch_event_handler_(false) {}
- ~FakeFrameWidgetHost() override = default;
-
- mojo::PendingAssociatedRemote<mojom::blink::FrameWidgetHost>
- BindNewFrameWidgetInterfaces() {
- frame_widget_host_receiver_.reset();
- return frame_widget_host_receiver_.BindNewEndpointAndPassDedicatedRemote();
- }
-
int GetAndResetHasTouchEventHandlerCallCount(bool state) {
int value = has_touch_event_handler_count_[state];
has_touch_event_handler_count_[state] = 0;
return value;
}
- private:
- // blink::mojom::FrameWidgetHost overrides.
- void AnimateDoubleTapZoomInMainFrame(const gfx::Point& tap_point,
- const gfx::Rect& rect_to_zoom) override {
- }
- void ZoomToFindInPageRectInMainFrame(const gfx::Rect& rect_to_zoom) override {
- }
+ // mojom::FrameWidgetHost overrides:
void SetHasTouchEventConsumers(
mojom::blink::TouchEventConsumersPtr consumers) override {
// Only count the times the state changes.
@@ -4177,89 +4149,51 @@ class FakeFrameWidgetHost : public mojom::blink::FrameWidgetHost {
has_touch_event_handler_count_[state]++;
has_touch_event_handler_ = state;
}
- void IntrinsicSizingInfoChanged(
- mojom::blink::IntrinsicSizingInfoPtr sizing_info) override {}
- void AutoscrollStart(const gfx::PointF& position) override {}
- void AutoscrollFling(const gfx::Vector2dF& position) override {}
- void AutoscrollEnd() override {}
- void DidFirstVisuallyNonEmptyPaint() override {}
- void StartDragging(const blink::WebDragData& drag_data,
- blink::DragOperationsMask operations_allowed,
- const SkBitmap& bitmap,
- const gfx::Vector2d& bitmap_offset_in_dip,
- mojom::blink::DragEventSourceInfoPtr event_info) override {
- }
private:
- mojo::AssociatedReceiver<mojom::blink::FrameWidgetHost>
- frame_widget_host_receiver_{this};
- int has_touch_event_handler_count_[2];
- bool has_touch_event_handler_;
+ int has_touch_event_handler_count_[2]{};
+ bool has_touch_event_handler_ = false;
+};
- DISALLOW_COPY_AND_ASSIGN(FakeFrameWidgetHost);
+class TouchEventConsumersWebFrameWidget
+ : public frame_test_helpers::TestWebFrameWidget {
+ public:
+ template <typename... Args>
+ explicit TouchEventConsumersWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {}
+
+ // frame_test_helpers::TestWebFrameWidget overrides.
+ std::unique_ptr<frame_test_helpers::TestWebFrameWidgetHost> CreateWidgetHost()
+ override {
+ return std::make_unique<TouchEventConsumersWebFrameWidgetHost>();
+ }
+
+ TouchEventConsumersWebFrameWidgetHost& TouchEventWidgetHost() {
+ return static_cast<TouchEventConsumersWebFrameWidgetHost&>(WidgetHost());
+ }
+};
+
+class TouchEventConsumersWebViewTest : public WebViewTest {
+ public:
+ TouchEventConsumersWebViewTest()
+ : WebViewTest(base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ TouchEventConsumersWebFrameWidget>)) {}
};
// This test verifies that FrameWidgetHost::SetHasTouchEventConsumers is called
// accordingly for various calls to EventHandlerRegistry::did{Add|Remove|
// RemoveAll}EventHandler(..., TouchEvent). Verifying that those calls are made
// correctly is the job of web_tests/fast/events/event-handler-count.html.
-TEST_F(WebViewTest, SetHasTouchEventConsumers) {
- // Note: this test doesn't use WebViewHelper since it intentionally runs
- // initialization code between WebView and WebLocalFrame creation.
- frame_test_helpers::TestWebViewClient web_view_client;
- frame_test_helpers::TestWebWidgetClient web_widget_client;
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler =
- blink::scheduler::WebThreadScheduler::MainThreadScheduler()
- ->CreateAgentGroupScheduler();
- WebViewImpl* web_view_impl = static_cast<WebViewImpl*>(WebView::Create(
- &web_view_client, /*is_hidden=*/false, /*is_inside_portal=*/false,
- /*compositing_enabled=*/true, /*opener=*/nullptr,
- mojo::NullAssociatedReceiver(), *agent_group_scheduler));
-
- frame_test_helpers::TestWebFrameClient web_frame_client;
- WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
- web_view_impl, &web_frame_client, nullptr,
- base::UnguessableToken::Create(),
- std::make_unique<WebPolicyContainer>(WebPolicyContainerDocumentPolicies(),
- mojo::NullAssociatedRemote()));
- web_frame_client.Bind(frame);
-
- FakeFrameWidgetHost frame_widget_host;
- auto blink_frame_widget_host =
- frame_widget_host.BindNewFrameWidgetInterfaces();
-
- {
- mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
- frame_widget_receiver =
- frame_widget.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
- widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::WidgetHost> widget_host_remote;
- ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
-
- // Copy the steps done from WebViewHelper::InitializeWithOpener() to set up
- // the appropriate pointers!
- WebFrameWidget* widget = blink::WebFrameWidget::CreateForMainFrame(
- &web_widget_client, frame, std::move(blink_frame_widget_host),
- std::move(frame_widget_receiver), widget_host_remote.Unbind(),
- std::move(widget_receiver), viz::FrameSinkId());
- cc::LayerTreeSettings layer_tree_settings =
- frame_test_helpers::GetSynchronousSingleThreadLayerTreeSettings();
- web_widget_client.set_layer_tree_host(widget->InitializeCompositing(
- web_widget_client.main_thread_scheduler(),
- web_widget_client.task_graph_runner(), true, ScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- widget->SetCompositorVisible(true);
- web_view_impl->DidAttachLocalMainFrame();
- }
-
+TEST_F(TouchEventConsumersWebViewTest, SetHasTouchEventConsumers) {
std::string url = RegisterMockedHttpURLLoad("has_touch_event_handlers.html");
- LoadFrame(web_view_impl->MainFrameImpl(), url);
+ WebViewImpl* web_view_impl = web_view_helper_.InitializeAndLoad(url);
+
+ TouchEventConsumersWebFrameWidget* widget =
+ static_cast<TouchEventConsumersWebFrameWidget*>(
+ web_view_helper_.GetMainFrameWidget());
+ TouchEventConsumersWebFrameWidgetHost& frame_widget_host =
+ widget->TouchEventWidgetHost();
const EventHandlerRegistry::EventHandlerClass kTouchEvent =
EventHandlerRegistry::kTouchStartOrMoveEventBlocking;
@@ -4426,10 +4360,6 @@ TEST_F(WebViewTest, SetHasTouchEventConsumers) {
frame_widget_host.GetAndResetHasTouchEventHandlerCallCount(false));
EXPECT_EQ(0,
frame_widget_host.GetAndResetHasTouchEventHandlerCallCount(true));
-
- // Free the webView before the TouchEventHandlerWebViewClient gets freed.
- web_view_helper_.Reset();
- web_view_impl->Close();
}
// This test checks that deleting nodes which have only non-JS-registered touch
@@ -4595,7 +4525,7 @@ TEST_F(WebViewTest, CompositionIsUserGesture) {
}
// Currently, SelectionAsText() is built upon TextIterator, but
-// WebFrameContentDumper is built upon TextDumperForTests. Their results can
+// TestWebFrameContentDumper is built upon TextDumperForTests. Their results can
// be different, making the test fail.
// TODO(crbug.com/781434): Build a selection serializer upon TextDumperForTests.
TEST_F(WebViewTest, DISABLED_CompareSelectAllToContentAsText) {
@@ -4609,9 +4539,9 @@ TEST_F(WebViewTest, DISABLED_CompareSelectAllToContentAsText) {
std::string actual = frame->SelectionAsText().Utf8();
const int kMaxOutputCharacters = 1024;
- std::string expected =
- WebFrameContentDumper::DumpWebViewAsText(web_view, kMaxOutputCharacters)
- .Utf8();
+ std::string expected = TestWebFrameContentDumper::DumpWebViewAsText(
+ web_view, kMaxOutputCharacters)
+ .Utf8();
EXPECT_EQ(expected, actual);
}
@@ -5149,7 +5079,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
{
IntRect visible_rect(1, 2, 3, 4);
dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
- EXPECT_EQ(IntRect(50, 55, 50, 75), visible_rect);
+ EXPECT_EQ(IntRect(50, 55, 100, 150), visible_rect);
}
// Setting new override discards previous one.
@@ -5160,7 +5090,7 @@ TEST_F(WebViewTest, ForceAndResetViewport) {
{
IntRect visible_rect(1, 2, 3, 4);
dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
- EXPECT_EQ(IntRect(5, 10, 68, 101), visible_rect); // Was modified.
+ EXPECT_EQ(IntRect(5, 10, 101, 151), visible_rect); // Was modified.
}
// Clearing override restores original transform, visible rect and
@@ -5195,10 +5125,7 @@ TEST_F(WebViewTest, ViewportOverrideIntegratesDeviceMetricsOffsetAndScale) {
emulation_params.viewport_offset = gfx::PointF(5, 10);
emulation_params.viewport_scale = 1.5f;
web_view_impl->EnableDeviceEmulation(emulation_params);
- expected_matrix.MakeIdentity()
- .Scale(1.5f)
- .Translate(-5, -10)
- .Scale(2.f);
+ expected_matrix.MakeIdentity().Scale(1.5f).Translate(-5, -10).Scale(2.f);
EXPECT_EQ(expected_matrix, web_view_impl->GetDeviceEmulationTransform());
}
@@ -5237,7 +5164,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
{
IntRect visible_rect(1, 2, 3, 4);
dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
- EXPECT_EQ(IntRect(50 - 100, 55 - 150, 50, 75), visible_rect);
+ EXPECT_EQ(IntRect(50 - 100, 55 - 150, 100, 150), visible_rect);
}
// Transform adapts to scroll changes.
@@ -5254,7 +5181,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
{
IntRect visible_rect(1, 2, 3, 4);
dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
- EXPECT_EQ(IntRect(50 - 50, 55 - 55, 50, 75), visible_rect);
+ EXPECT_EQ(IntRect(50 - 50, 55 - 55, 100, 150), visible_rect);
}
// Transform adapts to page scale changes.
@@ -5269,7 +5196,7 @@ TEST_F(WebViewTest, ViewportOverrideAdaptsToScaleAndScroll) {
{
IntRect visible_rect(1, 2, 3, 4);
dev_tools_emulator->OverrideVisibleRect(IntSize(100, 150), &visible_rect);
- EXPECT_EQ(IntRect(50 - 50, 55 - 55, 50, 75), visible_rect);
+ EXPECT_EQ(IntRect(50 - 50, 55 - 55, 100, 150), visible_rect);
}
}
@@ -5292,20 +5219,19 @@ TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
EXPECT_EQ(800, vw_element->OffsetWidth());
- FloatSize page_size(300, 360);
+ gfx::Size page_size(300, 360);
WebPrintParams print_params;
- print_params.print_content_area.width = page_size.Width();
- print_params.print_content_area.height = page_size.Height();
+ print_params.print_content_area.set_size(page_size);
- IntSize expected_size = PrintICBSizeFromPageSize(page_size);
+ IntSize expected_size = PrintICBSizeFromPageSize(FloatSize(page_size));
frame->PrintBegin(print_params, WebNode());
EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
- web_view->MainFrameWidget()->Resize(gfx::Size(FlooredIntSize(page_size)));
+ web_view->MainFrameWidget()->Resize(page_size);
EXPECT_EQ(expected_size.Width(), vw_element->OffsetWidth());
EXPECT_EQ(expected_size.Height(), vw_element->OffsetHeight());
@@ -5338,11 +5264,10 @@ TEST_F(WebViewTest, WidthMediaQueryWithPageZoomAfterPrinting) {
EXPECT_EQ(MakeRGB(0, 128, 0), div->GetComputedStyle()->VisitedDependentColor(
GetCSSPropertyColor()));
- FloatSize page_size(300, 360);
+ gfx::Size page_size(300, 360);
WebPrintParams print_params;
- print_params.print_content_area.width = page_size.Width();
- print_params.print_content_area.height = page_size.Height();
+ print_params.print_content_area.set_size(page_size);
frame->PrintBegin(print_params, WebNode());
frame->PrintEnd();
@@ -5375,12 +5300,11 @@ TEST_F(WebViewTest, ViewportUnitsPrintingWithPageZoom) {
EXPECT_EQ(400, t1->OffsetWidth());
EXPECT_EQ(400, t2->OffsetWidth());
- FloatSize page_size(600, 720);
- int expected_width = PrintICBSizeFromPageSize(page_size).Width();
+ gfx::Size page_size(600, 720);
+ int expected_width = PrintICBSizeFromPageSize(FloatSize(page_size)).Width();
WebPrintParams print_params;
- print_params.print_content_area.width = page_size.Width();
- print_params.print_content_area.height = page_size.Height();
+ print_params.print_content_area.set_size(page_size);
frame->PrintBegin(print_params, WebNode());
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/README.md b/chromium/third_party/blink/renderer/core/feature_policy/README.md
index c35a27cca0b..11ea7a139af 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/README.md
+++ b/chromium/third_party/blink/renderer/core/feature_policy/README.md
@@ -1,21 +1,23 @@
-This directory contains the renderer-specific portions of the [Feature
-Policy API](https://wicg.github.io/feature-policy/).
+This directory contains the renderer-specific portions of the
+ [Permissions Policy API](https://w3c.github.io/webappsec-permissions-policy/),
+ and [Document Policy API](https://github.com/w3c/webappsec-permissions-policy/blob/master/document-policy-explainer.md).
This includes:
-* The parser for the HTTP Feature-Policy header and the iframe allow attribute.
+* The parser for the HTTP `Permissions-Policy`/`Feature-Policy` header and the iframe `allow` attribute.
+
+* The parser for the HTTP `Document-Policy` header and the iframe `policy` attribute.
* Helpers for manipulating the parsed declarations.
-* Implementation of the `document.policy` and `iframe.policy` interfaces.
+* Implementation of the `document.featurePolicy` and `iframe.featurePolicy` interfaces.
-## Other feature policy resources
+## Other policy resources
-* The core feature policy algorithms can be found in `/common/feature\_policy/`.
+* The core algorithms can be found in `/common/feature\_policy/`.
* The feature list enum is found in `/public/mojom/feature\_policy/`.
* The recommended API for checking whether features should be enabled or not is
-Document::IsFeatureEnabled() (or SecurityContext::IsFeatureEnabled in a non-
-document context).
+ExecutionContext::IsFeatureEnabled().
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/build.gni b/chromium/third_party/blink/renderer/core/feature_policy/build.gni
index 4023e9c7840..69c354fb393 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/build.gni
+++ b/chromium/third_party/blink/renderer/core/feature_policy/build.gni
@@ -9,6 +9,8 @@ blink_core_sources_feature_policy = [
"dom_feature_policy.h",
"feature_policy_parser.cc",
"feature_policy_parser.h",
+ "feature_policy_devtools_support.h",
+ "feature_policy_devtools_support.cc",
"iframe_policy.h",
"layout_animations_policy.cc",
"layout_animations_policy.h",
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/document_policy.dict b/chromium/third_party/blink/renderer/core/feature_policy/document_policy.dict
index 52c42ef06ab..4cdf4129825 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/document_policy.dict
+++ b/chromium/third_party/blink/renderer/core/feature_policy/document_policy.dict
@@ -8,6 +8,7 @@
"lossy-images-max-bpp"
"oversized-images"
"report-to"
+"js-profiling"
"*"
"="
"bpp"
@@ -17,4 +18,4 @@
"1"
".0"
"("
-")" \ No newline at end of file
+")"
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/document_policy_features.json5 b/chromium/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
index 6a66add58d3..d11c8233d12 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
+++ b/chromium/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
@@ -1,8 +1,8 @@
{
// All document policy (https://w3c.github.io/webappsec-feature-policy/document-policy.html)
// features are defined here.
- // All Features have to be defined in FeaturePolicyFeature enum as well
- // (defined in third_party/blink/public/mojom/feature_policy/feature_policy.mojom).
+ // All Features have to be defined in DocumentPolicyFeature enum as well
+ // (defined in third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom).
// The enum value has to have the same name as the feature name here.
parameters: {
@@ -26,6 +26,26 @@
default: [],
valid_type: "list",
},
+ // "default_value_behind_flag" specifies default_value override values
+ // based on different runtime flags set.
+ //
+ // When multiple flags are set, default_value correspond to the first
+ // flag in the list will be used, e.g.
+ // default_value_behind_flag: [
+ // ["A", 1.0],
+ // ["B", 2.0],
+ // ]
+ // 1.0 will be used as default value when both flag A and B are set.
+ //
+ // Note: the runtime flags here refer to features defined in
+ // "third_party/blink/public/common/features.h", instead of those defined in
+ // "runtime_enabled_features.json5" because the latter is only available
+ // on renderer side, while default_value is needed from browser side as
+ // well.
+ default_value_behind_flag: {
+ default: [],
+ valid_type: "list",
+ }
},
data: [
@@ -41,14 +61,14 @@
document_policy_name: "font-display-late-swap",
value_type: "Bool",
default_value: "true",
- depends_on: ["ExperimentalProductivityFeatures"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "LosslessImagesMaxBpp",
document_policy_name: "lossless-images-max-bpp",
value_type: "DecDouble",
default_value: "max",
- depends_on: ["UnoptimizedImagePolicies"],
+ depends_on: ["ExperimentalPolicies"],
},
{
// The ForceLoadAtTop policy lets pages opt-out of scrolling that
@@ -65,49 +85,73 @@
document_policy_name: "lossless-images-strict-max-bpp",
value_type: "DecDouble",
default_value: "max",
- depends_on: ["UnoptimizedImagePolicies"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "LossyImagesMaxBpp",
document_policy_name: "lossy-images-max-bpp",
value_type: "DecDouble",
default_value: "max",
- depends_on: ["UnoptimizedImagePolicies"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "OversizedImages",
document_policy_name: "oversized-images",
value_type: "DecDouble",
default_value: "max",
- depends_on: ["UnoptimizedImagePolicies"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "UnsizedMedia",
document_policy_name: "unsized-media",
value_type: "Bool",
default_value: "true",
- depends_on: ["UnsizedMediaPolicy"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "LayoutAnimations",
document_policy_name: "layout-animations",
value_type: "Bool",
default_value: "true",
- depends_on: ["ExperimentalProductivityFeatures"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "DocumentWrite",
document_policy_name: "document-write",
value_type: "Bool",
default_value: "true",
- depends_on: ["ExperimentalProductivityFeatures"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "SyncScript",
document_policy_name: "sync-script",
value_type: "Bool",
default_value: "true",
- depends_on: ["ExperimentalProductivityFeatures"],
+ depends_on: ["ExperimentalPolicies"],
},
+ {
+ name: "JSProfiling",
+ document_policy_name: "js-profiling",
+ value_type: "Bool",
+ default_value: "false",
+ depends_on: ["ExperimentalJSProfiler"],
+ },
+ {
+ name: "SyncXHR",
+ document_policy_name: "sync-xhr",
+ value_type: "Bool",
+ default_value: "true",
+ depends_on: ["DocumentPolicySyncXHR"],
+ },
+ {
+ name: "DocumentDomain",
+ document_policy_name: "document-domain",
+ value_type: "Bool",
+ default_value: "true",
+ depends_on: ["DocumentPolicyDocumentDomain"],
+ default_value_behind_flag: [
+ ["DisableDocumentDomainByDefault", "false"],
+ ],
+ }
],
}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/document_policy_sim_test.cc b/chromium/third_party/blink/renderer/core/feature_policy/document_policy_sim_test.cc
new file mode 100644
index 00000000000..636509b3850
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/feature_policy/document_policy_sim_test.cc
@@ -0,0 +1,457 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink.h"
+#include "third_party/blink/renderer/core/feature_policy/policy_helper.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+
+namespace blink {
+
+class DocumentPolicySimTest : public SimTest {
+ public:
+ DocumentPolicySimTest()
+ : scoped_document_policy_(true),
+ scoped_document_policy_negotiation_(true) {
+ ResetAvailableDocumentPolicyFeaturesForTest();
+ }
+
+ private:
+ ScopedDocumentPolicyForTest scoped_document_policy_;
+ ScopedDocumentPolicyNegotiationForTest scoped_document_policy_negotiation_;
+};
+
+// When runtime feature DocumentPolicy is not enabled, specifying
+// Document-Policy, Require-Document-Policy and policy attribute
+// should have no effect, i.e.
+// document load should not be blocked even if the required policy and incoming
+// policy are incompatible and calling
+// |Document::IsFeatureEnabled(DocumentPolicyFeature...)| should always return
+// true.
+TEST_F(DocumentPolicySimTest, DocumentPolicyNoEffectWhenFlagNotSet) {
+ ScopedDocumentPolicyForTest sdp(false);
+ ScopedDocumentPolicyNegotiationForTest sdpn(false);
+ ResetAvailableDocumentPolicyFeaturesForTest();
+
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Document-Policy", "lossless-images-max-bpp=1.1"}};
+
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe
+ src="https://example.com/foo.html"
+ policy="lossless-images-max-bpp=1.0">
+ </iframe>
+ )");
+
+ iframe_resource.Finish();
+ auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
+ auto* child_window = child_frame->GetFrame()->DomWindow();
+ auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
+ child_frame->Client())
+ ->ConsoleMessages();
+
+ // Should not receive a console error message caused by document policy
+ // violation blocking document load.
+ EXPECT_TRUE(console_messages.IsEmpty());
+
+ EXPECT_EQ(child_window->Url(), KURL("https://example.com/foo.html"));
+
+ EXPECT_FALSE(child_window->document()->IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyCausedPageUnload));
+
+ // lossless-images-max-bpp should be set to inf in main document, i.e. allow
+ // all values.
+ EXPECT_TRUE(Window().IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(2.0)));
+ EXPECT_TRUE(Window().IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(1.0)));
+
+ // lossless-images-max-bpp should be set to inf in child document, i.e. allow
+ // all values.
+ EXPECT_TRUE(child_window->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(2.0)));
+ EXPECT_TRUE(child_window->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(1.0)));
+}
+
+// When runtime feature DocumentPolicyNegotiation is not enabled, specifying
+// Require-Document-Policy HTTP header and policy attribute on iframe should
+// have no effect, i.e. document load should not be blocked even if the required
+// policy and incoming policy are incompatible. Document-Policy header should
+// function as normal.
+TEST_F(DocumentPolicySimTest, DocumentPolicyNegotiationNoEffectWhenFlagNotSet) {
+ ScopedDocumentPolicyNegotiationForTest sdpn(false);
+ ResetAvailableDocumentPolicyFeaturesForTest();
+
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Document-Policy", "lossless-images-max-bpp=1.1"}};
+
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe
+ src="https://example.com/foo.html"
+ policy="lossless-images-max-bpp=1.0">
+ </iframe>
+ )");
+
+ iframe_resource.Finish();
+ auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
+ auto* child_window = child_frame->GetFrame()->DomWindow();
+ auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
+ child_frame->Client())
+ ->ConsoleMessages();
+
+ // Should not receive a console error message caused by document policy
+ // violation blocking document load.
+ EXPECT_TRUE(console_messages.IsEmpty());
+
+ EXPECT_EQ(child_window->Url(), KURL("https://example.com/foo.html"));
+
+ EXPECT_FALSE(child_window->document()->IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyCausedPageUnload));
+
+ // lossless-images-max-bpp should be set to inf in main document, i.e. allow
+ // all values.
+ EXPECT_TRUE(Window().IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(2.0)));
+ EXPECT_TRUE(Window().IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(1.0)));
+
+ // lossless-images-max-bpp should be set to 1.1 in child document.
+ EXPECT_FALSE(child_window->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(2.0)));
+ EXPECT_TRUE(child_window->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
+ PolicyValue::CreateDecDouble(1.0)));
+}
+
+TEST_F(DocumentPolicySimTest, ReportDocumentPolicyHeaderParsingError) {
+ SimRequest::Params params;
+ params.response_http_headers = {{"Document-Policy", "bad-feature-name"}};
+ SimRequest main_resource("https://example.com", "text/html", params);
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ EXPECT_EQ(ConsoleMessages().size(), 1u);
+ EXPECT_TRUE(
+ ConsoleMessages().front().StartsWith("Document-Policy HTTP header:"));
+}
+
+TEST_F(DocumentPolicySimTest, ReportRequireDocumentPolicyHeaderParsingError) {
+ SimRequest::Params params;
+ params.response_http_headers = {
+ {"Require-Document-Policy", "bad-feature-name"}};
+ SimRequest main_resource("https://example.com", "text/html", params);
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ EXPECT_EQ(ConsoleMessages().size(), 1u);
+ EXPECT_TRUE(ConsoleMessages().front().StartsWith(
+ "Require-Document-Policy HTTP header:"));
+}
+
+TEST_F(DocumentPolicySimTest, ReportErrorWhenDocumentPolicyIncompatible) {
+ SimRequest::Params params;
+ params.response_http_headers = {
+ {"Document-Policy", "lossless-images-max-bpp=1.1"}};
+
+ SimRequest main_resource("https://example.com", "text/html");
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe
+ src="https://example.com/foo.html"
+ policy="lossless-images-max-bpp=1.0">
+ </iframe>
+ )");
+
+ // When blocked by document policy, the document should be filled in with an
+ // empty response, with Finish called on |navigation_body_loader| already.
+ // If Finish was not called on the loader, because the document was not
+ // blocked, this test will fail by crashing here.
+ iframe_resource.Finish(true /* body_loader_finished */);
+
+ auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
+ auto* child_document = child_frame->GetFrame()->GetDocument();
+
+ // Should console log a error message.
+ auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
+ child_frame->Client())
+ ->ConsoleMessages();
+
+ ASSERT_EQ(console_messages.size(), 1u);
+ EXPECT_TRUE(console_messages.front().Contains("document policy"));
+
+ // Should replace the document's origin with an opaque origin.
+ EXPECT_EQ(child_document->Url(), SecurityOrigin::UrlWithUniqueOpaqueOrigin());
+
+ EXPECT_TRUE(child_document->IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyCausedPageUnload));
+}
+
+// HTTP header Require-Document-Policy should only take effect on subtree of
+// current document, but not on current document.
+TEST_F(DocumentPolicySimTest,
+ RequireDocumentPolicyHeaderShouldNotAffectCurrentDocument) {
+ SimRequest::Params params;
+ params.response_http_headers = {
+ {"Require-Document-Policy", "lossless-images-max-bpp=1.0"},
+ {"Document-Policy", "lossless-images-max-bpp=1.1"}};
+
+ SimRequest main_resource("https://example.com", "text/html", params);
+ LoadURL("https://example.com");
+ // If document is blocked by document policy because of incompatible document
+ // policy, this test will fail by crashing here.
+ main_resource.Finish();
+}
+
+TEST_F(DocumentPolicySimTest, DocumentPolicyHeaderHistogramTest) {
+ HistogramTester histogram_tester;
+
+ SimRequest::Params params;
+ params.response_http_headers = {
+ {"Document-Policy",
+ "font-display-late-swap, lossless-images-max-bpp=1.1"}};
+
+ SimRequest main_resource("https://example.com", "text/html", params);
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Header",
+ 2);
+ histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Header",
+ 1 /* kFontDisplay */, 1);
+ histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Header",
+ 2 /* kUnoptimizedLosslessImages */, 1);
+}
+
+TEST_F(DocumentPolicySimTest, DocumentPolicyPolicyAttributeHistogramTest) {
+ HistogramTester histogram_tester;
+
+ SimRequest main_resource("https://example.com", "text/html");
+ LoadURL("https://example.com");
+
+ // Same feature should only be reported once in a document despite its
+ // occurrence.
+ main_resource.Complete(R"(
+ <iframe policy="font-display-late-swap"></iframe>
+ <iframe policy="font-display-late-swap=?0"></iframe>
+ <iframe
+ policy="font-display-late-swap, lossless-images-max-bpp=1.1">
+ </iframe>
+ )");
+
+ histogram_tester.ExpectTotalCount(
+ "Blink.UseCounter.DocumentPolicy.PolicyAttribute", 2);
+ histogram_tester.ExpectBucketCount(
+ "Blink.UseCounter.DocumentPolicy.PolicyAttribute", 1 /* kFontDisplay */,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.UseCounter.DocumentPolicy.PolicyAttribute",
+ 2 /* kUnoptimizedLosslessImages */, 1);
+}
+
+TEST_F(DocumentPolicySimTest, DocumentPolicyEnforcedReportHistogramTest) {
+ HistogramTester histogram_tester;
+
+ SimRequest main_resource("https://example.com", "text/html");
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ Window().ReportDocumentPolicyViolation(
+ mojom::blink::DocumentPolicyFeature::kFontDisplay,
+ mojom::blink::PolicyDisposition::kEnforce,
+ "first font display violation");
+
+ histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
+ 1);
+ histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Enforced",
+ 1 /* kFontDisplay */, 1);
+
+ // Multiple reports should be recorded multiple times.
+ Window().ReportDocumentPolicyViolation(
+ mojom::blink::DocumentPolicyFeature::kFontDisplay,
+ mojom::blink::PolicyDisposition::kEnforce,
+ "second font display violation");
+
+ histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
+ 2);
+ histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Enforced",
+ 1 /* kFontDisplay */, 2);
+}
+
+TEST_F(DocumentPolicySimTest, DocumentPolicyReportOnlyReportHistogramTest) {
+ HistogramTester histogram_tester;
+
+ SimRequest::Params params;
+ params.response_http_headers = {
+ {"Document-Policy-Report-Only", "font-display-late-swap"}};
+ SimRequest main_resource("https://example.com", "text/html", params);
+
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ Window().ReportDocumentPolicyViolation(
+ mojom::blink::DocumentPolicyFeature::kFontDisplay,
+ mojom::blink::PolicyDisposition::kReport, "first font display violation");
+
+ histogram_tester.ExpectTotalCount(
+ "Blink.UseCounter.DocumentPolicy.ReportOnly", 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.UseCounter.DocumentPolicy.ReportOnly", 1 /* kFontDisplay */, 1);
+
+ // Multiple reports should be recorded multiple times.
+ Window().ReportDocumentPolicyViolation(
+ mojom::blink::DocumentPolicyFeature::kFontDisplay,
+ mojom::blink::PolicyDisposition::kReport,
+ "second font display violation");
+
+ histogram_tester.ExpectTotalCount(
+ "Blink.UseCounter.DocumentPolicy.ReportOnly", 2);
+ histogram_tester.ExpectBucketCount(
+ "Blink.UseCounter.DocumentPolicy.ReportOnly", 1 /* kFontDisplay */, 2);
+}
+
+class DocumentPolicyHeaderUseCounterTest
+ : public DocumentPolicySimTest,
+ public testing::WithParamInterface<std::tuple<bool, bool, bool>> {};
+
+TEST_P(DocumentPolicyHeaderUseCounterTest, ShouldObserveUseCounterUpdate) {
+ bool has_document_policy_header, has_report_only_header, has_require_header;
+ std::tie(has_document_policy_header, has_report_only_header,
+ has_require_header) = GetParam();
+
+ SimRequest::Params params;
+ if (has_document_policy_header) {
+ params.response_http_headers.insert("Document-Policy",
+ "lossless-images-max-bpp=1.0");
+ }
+ if (has_report_only_header) {
+ params.response_http_headers.insert("Document-Policy-Report-Only",
+ "lossless-images-max-bpp=1.0");
+ }
+ if (has_require_header) {
+ params.response_http_headers.insert("Require-Document-Policy",
+ "lossless-images-max-bpp=1.0");
+ }
+ SimRequest main_resource("https://example.com", "text/html", params);
+ LoadURL("https://example.com");
+ main_resource.Complete();
+
+ EXPECT_EQ(
+ GetDocument().IsUseCounted(mojom::WebFeature::kDocumentPolicyHeader),
+ has_document_policy_header);
+ EXPECT_EQ(GetDocument().IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyReportOnlyHeader),
+ has_report_only_header);
+ EXPECT_EQ(GetDocument().IsUseCounted(
+ mojom::WebFeature::kRequireDocumentPolicyHeader),
+ has_require_header);
+}
+
+INSTANTIATE_TEST_SUITE_P(DocumentPolicyHeaderValues,
+ DocumentPolicyHeaderUseCounterTest,
+ ::testing::Combine(::testing::Bool(),
+ ::testing::Bool(),
+ ::testing::Bool()));
+
+TEST_F(DocumentPolicySimTest,
+ DocumentPolicyIframePolicyAttributeUseCounterTest) {
+ SimRequest main_resource("https://example.com", "text/html");
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Document-Policy", "lossless-images-max-bpp=1.0"}};
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ iframe_params);
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe
+ src="https://example.com/foo.html"
+ policy="lossless-images-max-bpp=1.0"
+ ></iframe>
+ )");
+ iframe_resource.Finish();
+
+ EXPECT_TRUE(GetDocument().IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
+ EXPECT_FALSE(
+ GetDocument().IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
+
+ auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
+ auto* child_document = child_frame->GetFrame()->GetDocument();
+
+ EXPECT_FALSE(child_document->IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
+ EXPECT_TRUE(
+ child_document->IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
+}
+
+TEST_F(DocumentPolicySimTest, RequiredDocumentPolicyUseCounterTest) {
+ SimRequest::Params main_frame_params;
+ main_frame_params.response_http_headers = {
+ {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
+ SimRequest main_resource("https://example.com", "text/html",
+ main_frame_params);
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Document-Policy", "lossless-images-max-bpp=1.0"}};
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://example.com/foo.html"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ EXPECT_FALSE(GetDocument().IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
+ EXPECT_FALSE(
+ GetDocument().IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
+
+ auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
+ auto* child_document = child_frame->GetFrame()->GetDocument();
+
+ EXPECT_FALSE(child_document->IsUseCounted(
+ mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
+ EXPECT_TRUE(
+ child_document->IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
index 08d2a8b4e73..365b6e9db9a 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
@@ -8,6 +8,7 @@
#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/feature_policy/feature_policy_parser.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -29,6 +30,10 @@ bool DOMFeaturePolicy::allowsFeature(ScriptState* script_state,
const String& feature) const {
ExecutionContext* execution_context =
script_state ? ExecutionContext::From(script_state) : nullptr;
+ UseCounter::Count(execution_context,
+ IsIFramePolicy()
+ ? WebFeature::kFeaturePolicyJSAPIAllowsFeatureIFrame
+ : WebFeature::kFeaturePolicyJSAPIAllowsFeatureDocument);
if (FeatureAvailable(feature, execution_context)) {
auto feature_name = GetDefaultFeatureNameMap().at(feature);
return GetPolicy()->IsFeatureEnabled(feature_name);
@@ -43,12 +48,17 @@ bool DOMFeaturePolicy::allowsFeature(ScriptState* script_state,
const String& url) const {
ExecutionContext* execution_context =
script_state ? ExecutionContext::From(script_state) : nullptr;
+ UseCounter::Count(
+ execution_context,
+ IsIFramePolicy()
+ ? WebFeature::kFeaturePolicyJSAPIAllowsFeatureOriginIFrame
+ : WebFeature::kFeaturePolicyJSAPIAllowsFeatureOriginDocument);
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(url);
if (!origin || origin->IsOpaque()) {
context_->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kOther,
- mojom::ConsoleMessageLevel::kWarning,
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kWarning,
"Invalid origin url for feature '" + feature + "': " + url + "."));
return false;
}
@@ -66,6 +76,10 @@ bool DOMFeaturePolicy::allowsFeature(ScriptState* script_state,
Vector<String> DOMFeaturePolicy::features(ScriptState* script_state) const {
ExecutionContext* execution_context =
script_state ? ExecutionContext::From(script_state) : nullptr;
+ UseCounter::Count(execution_context,
+ IsIFramePolicy()
+ ? WebFeature::kFeaturePolicyJSAPIFeaturesIFrame
+ : WebFeature::kFeaturePolicyJSAPIFeaturesDocument);
return GetAvailableFeatures(execution_context);
}
@@ -73,6 +87,11 @@ Vector<String> DOMFeaturePolicy::allowedFeatures(
ScriptState* script_state) const {
ExecutionContext* execution_context =
script_state ? ExecutionContext::From(script_state) : nullptr;
+ UseCounter::Count(
+ execution_context,
+ IsIFramePolicy()
+ ? WebFeature::kFeaturePolicyJSAPIAllowedFeaturesIFrame
+ : WebFeature::kFeaturePolicyJSAPIAllowedFeaturesDocument);
Vector<String> allowed_features;
for (const String& feature : GetAvailableFeatures(execution_context)) {
auto feature_name = GetDefaultFeatureNameMap().at(feature);
@@ -87,6 +106,10 @@ Vector<String> DOMFeaturePolicy::getAllowlistForFeature(
const String& feature) const {
ExecutionContext* execution_context =
script_state ? ExecutionContext::From(script_state) : nullptr;
+ UseCounter::Count(execution_context,
+ IsIFramePolicy()
+ ? WebFeature::kFeaturePolicyJSAPIGetAllowlistIFrame
+ : WebFeature::kFeaturePolicyJSAPIGetAllowlistDocument);
if (FeatureAvailable(feature, execution_context)) {
auto feature_name = GetDefaultFeatureNameMap().at(feature);
@@ -111,7 +134,8 @@ Vector<String> DOMFeaturePolicy::getAllowlistForFeature(
void DOMFeaturePolicy::AddWarningForUnrecognizedFeature(
const String& feature) const {
context_->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kOther, mojom::ConsoleMessageLevel::kWarning,
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kWarning,
"Unrecognized feature: '" + feature + "'."));
}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
index 95f5b4c9f4c..744ce93c488 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
@@ -57,6 +57,8 @@ class CORE_EXPORT DOMFeaturePolicy : public ScriptWrappable {
return context_->GetSecurityContext().GetFeaturePolicy();
}
+ virtual bool IsIFramePolicy() const { return false; }
+
Member<ExecutionContext> context_;
private:
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.dict b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.dict
index d7dcd9a54c9..d8688749c65 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.dict
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy.dict
@@ -9,6 +9,7 @@
"clipboard-read"
"clipboard-write"
"cross-origin-isolated"
+"display-capture"
"document-domain"
"document-write"
"encrypted-media"
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.cc
new file mode 100644
index 00000000000..802303a0c5a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h"
+
+#include "third_party/blink/public/common/feature_policy/feature_policy.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/frame.h"
+#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+
+namespace blink {
+
+base::Optional<FeaturePolicyBlockLocator> TraceFeaturePolicyBlockSource(
+ Frame* frame,
+ mojom::FeaturePolicyFeature feature) {
+ const FeaturePolicy* current_policy =
+ frame->GetSecurityContext()->GetFeaturePolicy();
+ DCHECK(current_policy);
+ if (current_policy->IsFeatureEnabled(feature))
+ return base::nullopt;
+
+ Frame* current_frame = frame;
+ Frame* child_frame = nullptr;
+
+ // Trace up the frame tree until feature is not disabled by inherited policy
+ // in |current_frame|.
+ // After the trace up, the only 2 possibilities for a feature to be disabled
+ // become
+ // - The HTTP header of |current_frame|.
+ // - The iframe attribute on |child_frame|'s html frame owner element.
+ while (true) {
+ DCHECK(current_frame);
+ current_policy = current_frame->GetSecurityContext()->GetFeaturePolicy();
+ DCHECK(current_policy);
+
+ if (current_policy->IsFeatureEnabledByInheritedPolicy(feature))
+ break;
+
+ child_frame = current_frame;
+ current_frame = current_frame->Tree().Parent();
+ }
+
+ const FeaturePolicy::Allowlist allowlist =
+ current_policy->GetAllowlistForDevTools(feature);
+
+ bool allowed_by_current_frame = allowlist.Contains(
+ current_frame->GetSecurityContext()->GetSecurityOrigin()->ToUrlOrigin());
+ bool allowed_by_child_frame =
+ child_frame ? allowlist.Contains(child_frame->GetSecurityContext()
+ ->GetSecurityOrigin()
+ ->ToUrlOrigin())
+ : true;
+
+ if (!allowed_by_current_frame || !allowed_by_child_frame) {
+ // Feature disabled by allowlist, i.e. value in HTTP header.
+ return FeaturePolicyBlockLocator{
+ IdentifiersFactory::FrameId(current_frame),
+ FeaturePolicyBlockReason::kHeader,
+ };
+ } else {
+ // Otherwise, feature must be disabled by iframe attribute.
+
+ // |child_frame| is nullptr iff
+ // - feature is disabled in the starting frame (1)
+ // - feature is enabled by inherited policy in the starting frame (2)
+ // Container policy (iframe attribute) is part of inherited policy.
+ // Along with (2), we can conclude feature is enabled by container policy
+ // (iframe attribute) which contradicts with the else branch condition.
+ DCHECK(child_frame);
+ return FeaturePolicyBlockLocator{
+ IdentifiersFactory::FrameId(child_frame),
+ FeaturePolicyBlockReason::kIframeAttribute,
+ };
+ }
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h
new file mode 100644
index 00000000000..92068cd2974
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_FEATURE_POLICY_DEVTOOLS_SUPPORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_FEATURE_POLICY_DEVTOOLS_SUPPORT_H_
+
+#include "base/optional.h"
+
+#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-forward.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+class Frame;
+
+// The reason for a feature to be disallowed.
+enum class FeaturePolicyBlockReason {
+ // Feature's allowlist declaration can be overridden either in HTTP header,
+ // or in iframe attribute.
+ kHeader,
+ kIframeAttribute,
+};
+
+struct FeaturePolicyBlockLocator {
+ // FrameId used in devtools protocol.
+ String frame_id;
+ // Note: Attribute declaration is on frame's owner element, which is
+ // technically above 1 level in the frame tree.
+ FeaturePolicyBlockReason reason;
+};
+
+// Traces the root reason for a feature to be disabled in a frame.
+// Returns base::nullopt when the feature is enabled in the frame.
+CORE_EXPORT base::Optional<FeaturePolicyBlockLocator>
+TraceFeaturePolicyBlockSource(Frame*, mojom::FeaturePolicyFeature);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_FEATURE_POLICY_DEVTOOLS_SUPPORT_H_
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support_test.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support_test.cc
new file mode 100644
index 00000000000..51b6baf20f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support_test.cc
@@ -0,0 +1,297 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/frame.h"
+#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+
+namespace blink {
+using FeaturePolicyDevtoolsSupportSimTest = SimTest;
+
+// Note: fullscreen has default allowlist 'EnableForSelf'.
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectIframeAttributeBlockage) {
+ SimRequest main_resource("https://example.com", "text/html");
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html");
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://example.com/foo.html" allow="fullscreen 'none'"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+ DetectNestedIframeAttributeBlockage) {
+ SimRequest main_resource("https://example.com", "text/html");
+ SimRequest iframe_resource1("https://example.com/foo.html", "text/html");
+ SimRequest iframe_resource2("https://example.com/bar.html", "text/html");
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://example.com/foo.html" allow="fullscreen 'none'"></iframe>
+ )");
+ iframe_resource1.Complete(R"(
+ <iframe src="https://example.com/bar.html"></iframe>
+ )");
+ iframe_resource2.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectHeaderBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=()"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNestedHeaderBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=()"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html");
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://example.com/foo.html"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+}
+
+// When feature is disabled at multiple level of frames, report blockage
+// closest to the root of frame tree.
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectRootHeaderBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=()"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=()"},
+ };
+ SimRequest iframe_resource("https://example.com/foo.html", "text/html",
+ iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://example.com/foo.html"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectCrossOriginHeaderBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=self"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest iframe_resource("https://foo.com", "text/html", iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://foo.com" allow="fullscreen *"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+ DetectCrossOriginDefaultAllowlistBlockage) {
+ SimRequest main_resource("https://example.com", "text/html");
+ SimRequest iframe_resource("https://foo.com", "text/html");
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://foo.com"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+ DetectCrossOriginIframeAttributeBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ SimRequest::Params iframe_params;
+ iframe_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest iframe_resource("https://foo.com", "text/html", iframe_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://foo.com" allow="fullscreen 'self'"></iframe>
+ )");
+ iframe_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ ASSERT_NE(locator, base::nullopt);
+ EXPECT_EQ(locator->frame_id,
+ IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
+ EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNestedCrossOriginNoBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=(self \"https://foo.com)\""},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ SimRequest::Params foo_params;
+ foo_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest foo_resource("https://foo.com", "text/html", foo_params);
+
+ SimRequest::Params bar_params;
+ bar_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest bar_resource("https://bar.com", "text/html", bar_params);
+
+ LoadURL("https://example.com");
+ main_resource.Complete(R"(
+ <iframe src="https://foo.com" allow="fullscreen *"></iframe>
+ )");
+ foo_resource.Complete(R"(
+ <iframe src="https://bar.com" allow="fullscreen *"></iframe>
+ )");
+ bar_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame()->FirstChild()->FirstChild(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ EXPECT_TRUE(MainFrame().GetFrame()->GetSecurityContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kFullscreen));
+ EXPECT_TRUE(
+ MainFrame()
+ .GetFrame()
+ ->FirstChild()
+ ->GetSecurityContext()
+ ->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kFullscreen));
+ EXPECT_TRUE(
+ MainFrame()
+ .GetFrame()
+ ->FirstChild()
+ ->FirstChild()
+ ->GetSecurityContext()
+ ->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kFullscreen));
+ EXPECT_EQ(locator, base::nullopt);
+}
+
+TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNoBlockage) {
+ SimRequest::Params main_params;
+ main_params.response_http_headers = {
+ {"Permissions-Policy", "fullscreen=*"},
+ };
+ SimRequest main_resource("https://example.com", "text/html", main_params);
+
+ LoadURL("https://example.com");
+ main_resource.Finish();
+
+ base::Optional<FeaturePolicyBlockLocator> locator =
+ TraceFeaturePolicyBlockSource(
+ MainFrame().GetFrame(),
+ mojom::blink::FeaturePolicyFeature::kFullscreen);
+
+ EXPECT_EQ(locator, base::nullopt);
+}
+} // namespace blink \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5 b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
index b4885c514c6..bd3f6634d80 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
@@ -29,7 +29,7 @@
// public/common/feature_policy/feature_policy_features.h
feature_default: {
default: "EnableForSelf",
- valid_values: ["DisableForAll", "EnableForAll", "EnableForSelf"]
+ valid_values: ["EnableForAll", "EnableForSelf"]
}
},
@@ -147,15 +147,14 @@
depends_on: ["CrossOriginIsolation"],
},
{
- name: "DocumentDomain",
- feature_policy_name: "document-domain",
- feature_default: "EnableForAll",
+ name: "DisplayCapture",
+ feature_policy_name: "display-capture",
+ depends_on: ["GetCurrentBrowsingContextMedia"],
},
{
- name: "Downloads",
- feature_policy_name: "downloads",
+ name: "DocumentDomain",
+ feature_policy_name: "document-domain",
feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
},
{
name: "EncryptedMedia",
@@ -180,12 +179,6 @@
depends_on: ["BlockingFocusWithoutUserActivation"],
},
{
- name: "FormSubmission",
- feature_policy_name: "forms",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
name: "Fullscreen",
feature_policy_name: "fullscreen",
},
@@ -218,6 +211,12 @@
depends_on: ["IdleDetection"],
},
{
+ name: "InterestCohort",
+ feature_policy_name: "interest-cohort",
+ feature_default: "EnableForAll",
+ depends_on: ["InterestCohortFeaturePolicy"],
+ },
+ {
name: "Magnetometer",
feature_policy_name: "magnetometer",
},
@@ -230,16 +229,9 @@
feature_policy_name: "midi",
},
{
- name: "Modals",
- feature_policy_name: "modals",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
- name: "OrientationLock",
- feature_policy_name: "orientation-lock",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
+ name: "OTPCredentials",
+ feature_policy_name: "otp-credentials",
+ depends_on: ["WebOTPAssertionFeaturePolicy"],
},
{
name: "Payment",
@@ -253,24 +245,6 @@
depends_on: ["PictureInPictureAPI"],
},
{
- name: "PointerLock",
- feature_policy_name: "pointer-lock",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
- name: "Popups",
- feature_policy_name: "popups",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
- name: "Presentation",
- feature_policy_name: "presentation",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
name: "PublicKeyCredentialsGet",
feature_policy_name: "publickey-credentials-get",
depends_on: ["WebAuthenticationGetAssertionFeaturePolicy"],
@@ -281,12 +255,6 @@
depends_on: ["WakeLock"],
},
{
- name: "Script",
- feature_policy_name: "scripts",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
name: "Serial",
feature_policy_name: "serial",
depends_on: ["Serial"],
@@ -303,12 +271,6 @@
feature_policy_name: "sync-xhr",
},
{
- name: "TopNavigation",
- feature_policy_name: "top-navigation",
- feature_default: "EnableForAll",
- depends_on: ["FeaturePolicyForSandbox"],
- },
- {
name: "TrustTokenRedemption",
feature_policy_name: "trust-token-redemption",
depends_on: ["TrustTokens"],
@@ -322,7 +284,7 @@
name: "VerticalScroll",
feature_policy_name: "vertical-scroll",
feature_default: "EnableForAll",
- depends_on: ["ExperimentalProductivityFeatures"],
+ depends_on: ["ExperimentalPolicies"],
},
{
name: "WebShare",
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_parser.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_parser.cc
index 60f142978bb..dbc40ec7eea 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_parser.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_parser.cc
@@ -407,12 +407,19 @@ ParsingContext::FeaturePolicyNode ParsingContext::ParseFeaturePolicyToIR(
return {};
}
- // RFC2616, section 4.2 specifies that headers appearing multiple times can be
- // combined with a comma. Walk the header string, and parse each comma
- // separated chunk as a separate header.
Vector<String> policy_items;
- // policy_items = [ policy *( "," [ policy ] ) ]
- policy.Split(',', policy_items);
+
+ if (src_origin_) {
+ // Attribute parsing.
+ policy_items.push_back(policy);
+ } else {
+ // Header parsing.
+ // RFC2616, section 4.2 specifies that headers appearing multiple times can
+ // be combined with a comma. Walk the header string, and parse each comma
+ // separated chunk as a separate header.
+ // policy_items = [ policy *( "," [ policy ] ) ]
+ policy.Split(',', policy_items);
+ }
if (policy_items.size() > 1) {
UseCounter::Count(
@@ -466,8 +473,8 @@ ParsingContext::FeaturePolicyNode ParsingContext::ParsePermissionsPolicyToIR(
auto root = net::structured_headers::ParseDictionary(policy.Utf8());
if (!root) {
logger_.Error(
- "Parse of permission policy failed because of errors reported by "
- "strctured header parser.");
+ "Parse of permissions policy failed because of errors reported by "
+ "structured header parser.");
return {};
}
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
index 49d71985071..0a4e241d067 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
+++ b/chromium/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
@@ -34,7 +34,7 @@ namespace blink {
namespace {
-const char* const kValidPolicies[] = {
+const char* const kValidHeaderPolicies[] = {
"", // An empty policy.
" ", // An empty policy.
";;", // Empty policies.
@@ -44,8 +44,7 @@ const char* const kValidPolicies[] = {
",;,", // Empty policies.
"geolocation 'none'",
"geolocation 'self'",
- "geolocation 'src'", // Only valid for iframe allow attribute.
- "geolocation", // Only valid for iframe allow attribute.
+ "geolocation",
"geolocation; fullscreen; payment",
"geolocation *",
"geolocation " ORIGIN_A "",
@@ -58,10 +57,11 @@ const char* const kValidPolicies[] = {
"fullscreen " ORIGIN_A "; payment 'self'",
"fullscreen " ORIGIN_A "; payment *, geolocation 'self'"};
-const char* const kInvalidPolicies[] = {
+const char* const kInvalidHeaderPolicies[] = {
"badfeaturename",
"badfeaturename 'self'",
"1.0",
+ "geolocation 'src'", // Only valid for iframe allow attribute.
"geolocation data://badorigin",
"geolocation https://bad;origin",
"geolocation https:/bad,origin",
@@ -301,7 +301,7 @@ const FeaturePolicyParserTestCase FeaturePolicyParserParsingTest::kCases[] = {
/* test_name */ "MultiplePoliciesIncludingBadFeatureName",
/* feature_policy_string */
"geolocation * " ORIGIN_B "; "
- "fullscreen " ORIGIN_B " bad_feature_name " ORIGIN_C ","
+ "fullscreen " ORIGIN_B " bad_feature_name " ORIGIN_C ";"
"payment 'self' badorigin",
/* permissions_policy_string */
"geolocation=(* \"" ORIGIN_B "\"),"
@@ -680,23 +680,50 @@ TEST_F(FeaturePolicyParserParsingTest,
});
}
-TEST_F(FeaturePolicyParserTest, ParseValidPolicy) {
- for (const char* policy_string : kValidPolicies) {
+TEST_F(FeaturePolicyParserParsingTest, CommaSeparatorInAttribute) {
+ PolicyParserMessageBuffer logger;
+
+ CheckParsedPolicy(
+ FeaturePolicyParser::ParseAttribute(
+ "geolocation 'none', fullscreen 'self'",
+ /* self_origin */ origin_a_.get(),
+ /* src_origin */ origin_a_.get(), logger, /* context */ nullptr),
+ {
+ {
+ mojom::blink::FeaturePolicyFeature::kGeolocation,
+ /* matches_all_origins */ false,
+ /* matches_opaque_src */ false,
+ {ORIGIN_A},
+ },
+ });
+
+ EXPECT_EQ(logger.GetMessages().size(), 2u)
+ << "Parser should report parsing error.";
+
+ EXPECT_EQ(logger.GetMessages().front().content.Ascii(),
+ "Unrecognized origin: ''none','.")
+ << "\"'none',\" should be treated as an invalid allowlist item ";
+
+ EXPECT_EQ(logger.GetMessages().back().content.Ascii(),
+ "Unrecognized origin: 'fullscreen'.")
+ << "\"fullscreen\" should be treated as an invalid allowlist item";
+}
+
+TEST_F(FeaturePolicyParserTest, ParseValidHeaderPolicy) {
+ for (const char* policy_string : kValidHeaderPolicies) {
PolicyParserMessageBuffer logger;
FeaturePolicyParser::ParseFeaturePolicyForTest(
- policy_string, origin_a_.get(), origin_b_.get(), logger,
- test_feature_name_map);
+ policy_string, origin_a_.get(), nullptr, logger, test_feature_name_map);
EXPECT_EQ(0UL, logger.GetMessages().size())
<< "Should parse " << policy_string;
}
}
-TEST_F(FeaturePolicyParserTest, ParseInvalidPolicy) {
- for (const char* policy_string : kInvalidPolicies) {
+TEST_F(FeaturePolicyParserTest, ParseInvalidHeaderPolicy) {
+ for (const char* policy_string : kInvalidHeaderPolicies) {
PolicyParserMessageBuffer logger;
FeaturePolicyParser::ParseFeaturePolicyForTest(
- policy_string, origin_a_.get(), origin_b_.get(), logger,
- test_feature_name_map);
+ policy_string, origin_a_.get(), nullptr, logger, test_feature_name_map);
EXPECT_LT(0UL, logger.GetMessages().size())
<< "Should fail to parse " << policy_string;
}
@@ -891,26 +918,18 @@ class FeaturePolicyAllowlistHistogramTest
const AllowlistHistogramData FeaturePolicyAllowlistHistogramTest::kCases[] = {
{"Empty", "fullscreen", 1, {FeaturePolicyAllowlistType::kEmpty}},
- {"Empty_MultipleDirectivesComma",
- "fullscreen, geolocation, payment",
- 1,
- {FeaturePolicyAllowlistType::kEmpty}},
{"Empty_MultipleDirectivesSemicolon",
"fullscreen; payment",
1,
{FeaturePolicyAllowlistType::kEmpty}},
{"Star", "fullscreen *", 1, {FeaturePolicyAllowlistType::kStar}},
- {"Star_MultipleDirectivesComma",
- "fullscreen *, payment *",
- 1,
- {FeaturePolicyAllowlistType::kStar}},
{"Star_MultipleDirectivesSemicolon",
"fullscreen *; payment *",
1,
{FeaturePolicyAllowlistType::kStar}},
{"Self", "fullscreen 'self'", 1, {FeaturePolicyAllowlistType::kSelf}},
{"Self_MultipleDirectives",
- "fullscreen 'self', geolocation 'self', payment 'self'",
+ "fullscreen 'self'; geolocation 'self'; payment 'self'",
1,
{FeaturePolicyAllowlistType::kSelf}},
{"None", "fullscreen 'none'", 1, {FeaturePolicyAllowlistType::kNone}},
@@ -922,10 +941,6 @@ const AllowlistHistogramData FeaturePolicyAllowlistHistogramTest::kCases[] = {
"fullscreen " ORIGIN_A,
1,
{FeaturePolicyAllowlistType::kOrigins}},
- {"Origins_MultipleDirectivesComma",
- "fullscreen " ORIGIN_A ", payment " ORIGIN_A,
- 1,
- {FeaturePolicyAllowlistType::kOrigins}},
{"Origins_MultipleDirectivesSemicolon",
"fullscreen " ORIGIN_A "; payment " ORIGIN_A " " ORIGIN_B,
1,
@@ -935,7 +950,7 @@ const AllowlistHistogramData FeaturePolicyAllowlistHistogramTest::kCases[] = {
1,
{FeaturePolicyAllowlistType::kMixed}},
{"Mixed_MultipleDirectives",
- "fullscreen 'self' " ORIGIN_A ", payment 'none' " ORIGIN_A " " ORIGIN_B,
+ "fullscreen 'self' " ORIGIN_A "; payment 'none' " ORIGIN_A " " ORIGIN_B,
1,
{FeaturePolicyAllowlistType::kMixed}},
{"KeywordsOnly",
@@ -954,11 +969,7 @@ const AllowlistHistogramData FeaturePolicyAllowlistHistogramTest::kCases[] = {
"fullscreen *; geolocation 'none' " ORIGIN_A,
2,
{FeaturePolicyAllowlistType::kStar, FeaturePolicyAllowlistType::kMixed}},
- {"MultipleDirectives_SeparateTypes_Comma",
- "fullscreen *, geolocation 'none', payment " ORIGIN_A " " ORIGIN_B,
- 3,
- {FeaturePolicyAllowlistType::kStar, FeaturePolicyAllowlistType::kNone,
- FeaturePolicyAllowlistType::kOrigins}}};
+};
INSTANTIATE_TEST_SUITE_P(
All,
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h b/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
index d61d5fd36c5..93e29710a62 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/iframe_policy.h
@@ -41,6 +41,8 @@ class IFramePolicy final : public DOMFeaturePolicy {
protected:
const FeaturePolicy* GetPolicy() const override { return policy_.get(); }
+ bool IsIFramePolicy() const override { return true; }
+
private:
std::unique_ptr<FeaturePolicy> policy_;
};
diff --git a/chromium/third_party/blink/renderer/core/feature_policy/policy_helper.h b/chromium/third_party/blink/renderer/core/feature_policy/policy_helper.h
index a0292f4776a..b7321a82642 100644
--- a/chromium/third_party/blink/renderer/core/feature_policy/policy_helper.h
+++ b/chromium/third_party/blink/renderer/core/feature_policy/policy_helper.h
@@ -10,6 +10,7 @@
#include "third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink-forward.h"
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -79,6 +80,9 @@ const FeatureNameMap& GetDefaultFeatureNameMap();
// policy object.
const DocumentPolicyFeatureSet& GetAvailableDocumentPolicyFeatures();
+// Refresh the set content based on current RuntimeFeatures environment.
+CORE_EXPORT void ResetAvailableDocumentPolicyFeaturesForTest();
+
// Returns true if this FeaturePolicyFeature is currently disabled by an origin
// trial (it is origin trial controlled, and the origin trial is not enabled).
// The first String param should be a name of FeaturePolicyFeature.
@@ -88,6 +92,11 @@ bool DisabledByOriginTrial(const String&, FeatureContext*);
// trial (it is origin trial controlled, and the origin trial is not enabled).
bool DisabledByOriginTrial(mojom::blink::DocumentPolicyFeature,
FeatureContext*);
+
+// Converts |mojom::blink::FeaturePolicyFeature| to enum used in devtools
+// protocol.
+String PermissionsPolicyFeatureToProtocol(mojom::blink::FeaturePolicyFeature);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FEATURE_POLICY_POLICY_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/core/fetch/DEPS b/chromium/third_party/blink/renderer/core/fetch/DEPS
index 26583be0e15..5a78494f81c 100644
--- a/chromium/third_party/blink/renderer/core/fetch/DEPS
+++ b/chromium/third_party/blink/renderer/core/fetch/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+net/http/http_response_info.h",
"+services/network/public/cpp",
"+services/network/public/mojom",
+ "+storage/common/quota/padding_key.h",
"+url/gurl.h",
]
diff --git a/chromium/third_party/blink/renderer/core/fetch/DIR_METADATA b/chromium/third_party/blink/renderer/core/fetch/DIR_METADATA
new file mode 100644
index 00000000000..dbf37153e33
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fetch/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Network>FetchAPI"
+}
+
+team_email: "blink-network-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/fetch/OWNERS b/chromium/third_party/blink/renderer/core/fetch/OWNERS
index 160a1ff3a30..0f061320cce 100644
--- a/chromium/third_party/blink/renderer/core/fetch/OWNERS
+++ b/chromium/third_party/blink/renderer/core/fetch/OWNERS
@@ -1,6 +1,3 @@
hiroshige@chromium.org
horo@chromium.org
yhirano@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>FetchAPI
diff --git a/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc
index 9950d222eea..94232f7585a 100644
--- a/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc
@@ -83,7 +83,7 @@ BytesConsumer::Result BlobBytesConsumer::BeginRead(const char** buffer,
mojo::ScopedDataPipeConsumerHandle consumer_handle;
mojo::ScopedDataPipeProducerHandle producer_handle;
MojoResult rv =
- mojo::CreateDataPipe(&options, &producer_handle, &consumer_handle);
+ mojo::CreateDataPipe(&options, producer_handle, consumer_handle);
if (rv != MOJO_RESULT_OK)
return Result::kError;
diff --git a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
index b29ef07b829..e8fca9e7e7d 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -107,22 +108,27 @@ BodyStreamBuffer* BodyStreamBuffer::Create(
ScriptState* script_state,
BytesConsumer* consumer,
AbortSignal* signal,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
scoped_refptr<BlobDataHandle> side_data_blob) {
auto* buffer = MakeGarbageCollected<BodyStreamBuffer>(
- PassKey(), script_state, consumer, signal, std::move(side_data_blob));
+ PassKey(), script_state, consumer, signal, cached_metadata_handler,
+ std::move(side_data_blob));
buffer->Init();
return buffer;
}
-BodyStreamBuffer::BodyStreamBuffer(PassKey,
- ScriptState* script_state,
- BytesConsumer* consumer,
- AbortSignal* signal,
- scoped_refptr<BlobDataHandle> side_data_blob)
+BodyStreamBuffer::BodyStreamBuffer(
+ PassKey,
+ ScriptState* script_state,
+ BytesConsumer* consumer,
+ AbortSignal* signal,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
+ scoped_refptr<BlobDataHandle> side_data_blob)
: UnderlyingSourceBase(script_state),
script_state_(script_state),
consumer_(consumer),
signal_(signal),
+ cached_metadata_handler_(cached_metadata_handler),
side_data_blob_(std::move(side_data_blob)),
made_from_readable_stream_(false) {}
@@ -153,13 +159,16 @@ void BodyStreamBuffer::Init() {
OnStateChange();
}
-BodyStreamBuffer::BodyStreamBuffer(ScriptState* script_state,
- ReadableStream* stream,
- scoped_refptr<BlobDataHandle> side_data_blob)
+BodyStreamBuffer::BodyStreamBuffer(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
+ scoped_refptr<BlobDataHandle> side_data_blob)
: UnderlyingSourceBase(script_state),
script_state_(script_state),
stream_(stream),
signal_(nullptr),
+ cached_metadata_handler_(cached_metadata_handler),
side_data_blob_(std::move(side_data_blob)),
made_from_readable_stream_(true) {
DCHECK(stream_);
@@ -243,6 +252,7 @@ void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
DCHECK(!IsStreamDisturbed());
*branch1 = nullptr;
*branch2 = nullptr;
+ auto* cached_metadata_handler = cached_metadata_handler_.Get();
scoped_refptr<BlobDataHandle> side_data_blob = TakeSideDataBlob();
if (made_from_readable_stream_) {
@@ -263,10 +273,10 @@ void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
return;
}
- *branch1 = MakeGarbageCollected<BodyStreamBuffer>(script_state_, stream1,
- side_data_blob);
- *branch2 = MakeGarbageCollected<BodyStreamBuffer>(script_state_, stream2,
- side_data_blob);
+ *branch1 = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state_, stream1, cached_metadata_handler, side_data_blob);
+ *branch2 = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state_, stream2, cached_metadata_handler, side_data_blob);
return;
}
BytesConsumer* dest1 = nullptr;
@@ -278,10 +288,10 @@ void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
}
BytesConsumerTee(ExecutionContext::From(script_state_), handle, &dest1,
&dest2);
- *branch1 =
- BodyStreamBuffer::Create(script_state_, dest1, signal_, side_data_blob);
- *branch2 =
- BodyStreamBuffer::Create(script_state_, dest2, signal_, side_data_blob);
+ *branch1 = BodyStreamBuffer::Create(script_state_, dest1, signal_,
+ cached_metadata_handler, side_data_blob);
+ *branch2 = BodyStreamBuffer::Create(script_state_, dest2, signal_,
+ cached_metadata_handler, side_data_blob);
}
ScriptPromise BodyStreamBuffer::pull(ScriptState* script_state) {
@@ -360,6 +370,8 @@ bool BodyStreamBuffer::IsStreamDisturbed() const {
void BodyStreamBuffer::CloseAndLockAndDisturb() {
DCHECK(!stream_broken_);
+ cached_metadata_handler_ = nullptr;
+
if (IsStreamReadable()) {
// Note that the stream cannot be "draining", because it doesn't have
// the internal buffer.
@@ -386,6 +398,7 @@ void BodyStreamBuffer::Trace(Visitor* visitor) const {
visitor->Trace(consumer_);
visitor->Trace(loader_);
visitor->Trace(signal_);
+ visitor->Trace(cached_metadata_handler_);
UnderlyingSourceBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.h b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.h
index 25b16f316f6..cf949e90612 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.h
+++ b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_BODY_STREAM_BUFFER_H_
#include <memory>
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -27,11 +27,12 @@ class EncodedFormData;
class ExceptionState;
class ReadableStream;
class ScriptState;
+class ScriptCachedMetadataHandler;
class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
public BytesConsumer::Client {
public:
- using PassKey = util::PassKey<BodyStreamBuffer>;
+ using PassKey = base::PassKey<BodyStreamBuffer>;
// Create a BodyStreamBuffer for |consumer|.
// |consumer| must not have a client.
@@ -42,6 +43,7 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
ScriptState*,
BytesConsumer* consumer,
AbortSignal* signal,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
scoped_refptr<BlobDataHandle> side_data_blob = nullptr);
// Create() should be used instead of calling this constructor directly.
@@ -49,10 +51,12 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
ScriptState*,
BytesConsumer* consumer,
AbortSignal* signal,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
scoped_refptr<BlobDataHandle> side_data_blob);
BodyStreamBuffer(ScriptState*,
ReadableStream* stream,
+ ScriptCachedMetadataHandler* cached_metadata_handler,
scoped_refptr<BlobDataHandle> side_data_blob = nullptr);
ReadableStream* Stream() { return stream_; }
@@ -93,6 +97,15 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
bool IsAborted();
+ // Returns the ScriptCachedMetadataHandler associated with the contents of
+ // this stream. This can return nullptr. Streams' ownership model applies, so
+ // this function is expected to be called by the owner of this stream.
+ ScriptCachedMetadataHandler* GetCachedMetadataHandler() {
+ DCHECK(!IsStreamLocked());
+ DCHECK(!IsStreamDisturbed());
+ return cached_metadata_handler_;
+ }
+
// Take the blob representing any side data associated with this body
// stream. This must be called before the body is drained or begins
// loading.
@@ -131,6 +144,8 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
// We need this to ensure that we detect that abort has been signalled
// correctly.
Member<AbortSignal> signal_;
+ // CachedMetadata handler used for loading compiled WASM code.
+ Member<ScriptCachedMetadataHandler> cached_metadata_handler_;
// Additional side data associated with this body stream. It should only be
// retained until the body is drained or starts loading. Client code, such
// as service workers, can call TakeSideDataBlob() prior to consumption.
diff --git a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
index 79fb7f0d930..5ee3800f06f 100644
--- a/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
@@ -27,6 +27,8 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/loader/testing/replaying_bytes_consumer.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
@@ -128,7 +130,8 @@ TEST_F(BodyStreamBufferTest, Tee) {
src->Add(Command(Command::kDone));
BodyStreamBuffer* buffer =
BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr,
+ /*cached_metadata=*/nullptr, side_data_blob);
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
BodyStreamBuffer* new1;
@@ -194,8 +197,8 @@ TEST_F(BodyStreamBufferTest, TeeFromHandleMadeFromStream) {
EXPECT_CALL(*client2, DidFetchDataLoadedString(String("ABUX")));
EXPECT_CALL(checkpoint, Call(4));
- BodyStreamBuffer* buffer =
- MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), stream, /*cached_metadta_handler=*/nullptr);
BodyStreamBuffer* new1;
BodyStreamBuffer* new2;
@@ -238,7 +241,8 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandle) {
scope.GetScriptState(),
MakeGarbageCollected<BlobBytesConsumer>(scope.GetExecutionContext(),
blob_data_handle),
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
@@ -261,9 +265,10 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandleReturnsNull) {
BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
@@ -286,8 +291,8 @@ TEST_F(BodyStreamBufferTest,
auto* stream =
ReadableStream::Create(scope.GetScriptState(), exception_state);
ASSERT_TRUE(stream);
- BodyStreamBuffer* buffer =
- MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), stream, /*cached_metadata_handler=*/nullptr);
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked());
@@ -316,7 +321,8 @@ TEST_F(BodyStreamBufferTest, DrainAsFormData) {
scope.GetScriptState(),
MakeGarbageCollected<FormDataBytesConsumer>(scope.GetExecutionContext(),
input_form_data),
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
@@ -338,9 +344,10 @@ TEST_F(BodyStreamBufferTest, DrainAsFormDataReturnsNull) {
BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
@@ -361,8 +368,8 @@ TEST_F(BodyStreamBufferTest,
NonThrowableExceptionState exception_state;
auto* stream =
ReadableStream::Create(scope.GetScriptState(), exception_state);
- BodyStreamBuffer* buffer =
- MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(), stream);
+ BodyStreamBuffer* buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ scope.GetScriptState(), stream, /*cached_metadata_handler=*/nullptr);
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked());
@@ -395,9 +402,10 @@ TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsArrayBuffer) {
src->Add(Command(Command::kData, "hello"));
src->Add(Command(Command::kDone));
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
buffer->StartLoading(FetchDataLoader::CreateLoaderAsArrayBuffer(), client,
ASSERT_NO_EXCEPTION);
@@ -460,9 +468,10 @@ TEST_F(BodyStreamBufferBlobTest, LoadBodyStreamBufferAsBlob) {
src->Add(Command(Command::kData, "hello"));
src->Add(Command(Command::kDone));
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
buffer->StartLoading(FetchDataLoader::CreateLoaderAsBlobHandle(
"text/plain", fake_task_runner_),
@@ -500,9 +509,10 @@ TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsString) {
src->Add(Command(Command::kData, "hello"));
src->Add(Command(Command::kDone));
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src,
- /* abort_signal = */ nullptr, side_data_blob);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
buffer->StartLoading(FetchDataLoader::CreateLoaderAsString(
TextResourceDecoderOptions::CreateUTF8Decode()),
@@ -535,7 +545,8 @@ TEST_F(BodyStreamBufferTest, LoadClosedHandle) {
scoped_refptr<BlobDataHandle> side_data_blob = CreateBlob("side data");
BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
scope.GetScriptState(), BytesConsumer::CreateClosed(),
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_TRUE(buffer->IsStreamClosed());
@@ -569,7 +580,8 @@ TEST_F(BodyStreamBufferTest, LoadErroredHandle) {
BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
scope.GetScriptState(),
BytesConsumer::CreateErrored(BytesConsumer::Error()),
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_TRUE(buffer->IsStreamErrored());
@@ -605,7 +617,8 @@ TEST_F(BodyStreamBufferTest, LoaderShouldBeKeptAliveByBodyStreamBuffer) {
src->Add(Command(Command::kData, "hello"));
src->Add(Command(Command::kDone));
Persistent<BodyStreamBuffer> buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr,
+ /*cached_metadata_handler=*/nullptr);
buffer->StartLoading(FetchDataLoader::CreateLoaderAsString(
TextResourceDecoderOptions::CreateUTF8Decode()),
client, ASSERT_NO_EXCEPTION);
@@ -623,7 +636,8 @@ TEST_F(BodyStreamBufferTest, SourceShouldBeCanceledWhenCanceled) {
scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), consumer, nullptr);
+ BodyStreamBuffer::Create(scope.GetScriptState(), consumer, nullptr,
+ /*cached_metadata_handler=*/nullptr);
ScriptValue reason(scope.GetIsolate(),
V8String(scope.GetIsolate(), "reason"));
EXPECT_FALSE(consumer->IsCancelled());
@@ -639,7 +653,8 @@ TEST_F(BodyStreamBufferTest, NestedPull) {
src->Add(Command(Command::kData, "hello"));
src->Add(Command(Command::kError));
Persistent<BodyStreamBuffer> buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr,
+ /*cached_metadata_handler=*/nullptr);
auto result =
scope.GetScriptState()->GetContext()->Global()->CreateDataProperty(
@@ -667,7 +682,8 @@ TEST_F(BodyStreamBufferTest, NullAbortSignalIsNotAborted) {
BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr);
+ BodyStreamBuffer::Create(scope.GetScriptState(), src, nullptr,
+ /*cached_metadata_handler=*/nullptr);
EXPECT_FALSE(buffer->IsAborted());
}
@@ -678,8 +694,8 @@ TEST_F(BodyStreamBufferTest, AbortSignalMakesAborted) {
BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, signal);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src, signal, /*cached_metadata_handler=*/nullptr);
EXPECT_FALSE(buffer->IsAborted());
signal->SignalAbort();
@@ -710,8 +726,8 @@ TEST_F(BodyStreamBufferTest,
EXPECT_CALL(checkpoint, Call(3));
auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, signal);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src, signal, /*cached_metadata_handler=*/nullptr);
checkpoint.Call(1);
signal->SignalAbort();
@@ -744,8 +760,8 @@ TEST_F(BodyStreamBufferTest, AbortAfterStartLoadingCallsDataLoaderClientAbort) {
EXPECT_CALL(checkpoint, Call(3));
auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, signal);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src, signal, /*cached_metadata_handler=*/nullptr);
checkpoint.Call(1);
buffer->StartLoading(loader, client, ASSERT_NO_EXCEPTION);
@@ -779,8 +795,8 @@ TEST_F(BodyStreamBufferTest,
EXPECT_CALL(checkpoint, Call(3));
auto* signal = MakeGarbageCollected<AbortSignal>(scope.GetExecutionContext());
- BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(scope.GetScriptState(), src, signal);
+ BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
+ scope.GetScriptState(), src, signal, /*cached_metadata_handler=*/nullptr);
checkpoint.Call(1);
buffer->StartLoading(loader, client, ASSERT_NO_EXCEPTION);
@@ -792,6 +808,69 @@ TEST_F(BodyStreamBufferTest,
checkpoint.Call(3);
}
+TEST_F(BodyStreamBufferTest, CachedMetadataHandler) {
+ V8TestingScope scope;
+ Persistent<BodyStreamBuffer> buffer;
+ WeakPersistent<ScriptCachedMetadataHandler> weak_handler;
+ {
+ BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
+ scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
+ auto* handler = MakeGarbageCollected<ScriptCachedMetadataHandler>(
+ WTF::TextEncoding(), nullptr);
+ weak_handler = handler;
+ buffer = BodyStreamBuffer::Create(scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, handler);
+
+ EXPECT_EQ(handler, buffer->GetCachedMetadataHandler());
+ EXPECT_NE(weak_handler.Get(), nullptr);
+
+ buffer->CloseAndLockAndDisturb();
+ }
+
+ ThreadState::Current()->CollectAllGarbageForTesting();
+
+ EXPECT_EQ(weak_handler.Get(), nullptr);
+}
+
+TEST_F(BodyStreamBufferTest, CachedMetadataHandlerAndTee) {
+ V8TestingScope scope;
+ BytesConsumer* src = MakeGarbageCollected<ReplayingBytesConsumer>(
+ scope.GetDocument().GetTaskRunner(TaskType::kNetworking));
+ auto* handler = MakeGarbageCollected<ScriptCachedMetadataHandler>(
+ WTF::TextEncoding(), nullptr);
+ auto* buffer = BodyStreamBuffer::Create(scope.GetScriptState(), src,
+ /*abort_signal=*/nullptr, handler);
+
+ EXPECT_EQ(handler, buffer->GetCachedMetadataHandler());
+
+ BodyStreamBuffer* dest1 = nullptr;
+ BodyStreamBuffer* dest2 = nullptr;
+ buffer->Tee(&dest1, &dest2, ASSERT_NO_EXCEPTION);
+
+ EXPECT_EQ(dest1->GetCachedMetadataHandler(), handler);
+ EXPECT_EQ(dest2->GetCachedMetadataHandler(), handler);
+}
+
+TEST_F(BodyStreamBufferTest,
+ CachedMetadataHandlerAndTeeForBufferMadeFromStream) {
+ V8TestingScope scope;
+ auto* handler = MakeGarbageCollected<ScriptCachedMetadataHandler>(
+ WTF::TextEncoding(), nullptr);
+ auto* stream =
+ ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ auto* buffer = MakeGarbageCollected<BodyStreamBuffer>(scope.GetScriptState(),
+ stream, handler);
+
+ EXPECT_EQ(handler, buffer->GetCachedMetadataHandler());
+
+ BodyStreamBuffer* dest1 = nullptr;
+ BodyStreamBuffer* dest2 = nullptr;
+ buffer->Tee(&dest1, &dest2, ASSERT_NO_EXCEPTION);
+
+ EXPECT_EQ(dest1->GetCachedMetadataHandler(), handler);
+ EXPECT_EQ(dest2->GetCachedMetadataHandler(), handler);
+}
+
TEST_F(BodyStreamBufferTest, TakeSideDataBlob) {
V8TestingScope scope;
scoped_refptr<BlobDataHandle> blob_data_handle = CreateBlob("hello");
@@ -800,7 +879,8 @@ TEST_F(BodyStreamBufferTest, TakeSideDataBlob) {
scope.GetScriptState(),
MakeGarbageCollected<BlobBytesConsumer>(scope.GetExecutionContext(),
blob_data_handle),
- /* abort_signal = */ nullptr, side_data_blob);
+ /*abort_signal=*/nullptr, /*cached_metadata_handler=*/nullptr,
+ side_data_blob);
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
EXPECT_EQ(side_data_blob, buffer->TakeSideDataBlob());
diff --git a/chromium/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc b/chromium/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
index 61eed927154..1d847e30c26 100644
--- a/chromium/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
@@ -52,7 +52,7 @@ class BytesUploaderTest : public ::testing::Test {
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1,
capacity};
ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&data_pipe_options, &writable_, &readable_));
+ mojo::CreateDataPipe(&data_pipe_options, writable_, readable_));
}
MockBytesConsumer& Mock() const { return *mock_bytes_consumer_; }
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
index 2bcb7b3fcf9..c9534bfa342 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -559,7 +559,7 @@ class FetchDataLoaderAsDataPipe final : public FetchDataLoader,
options.capacity_num_bytes = 0;
MojoResult rv =
- mojo::CreateDataPipe(&options, &out_data_pipe_, &pipe_consumer);
+ mojo::CreateDataPipe(&options, out_data_pipe_, pipe_consumer);
if (rv != MOJO_RESULT_OK) {
StopInternal();
client_->DidFetchDataLoadFailed();
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
index cddab3ece3f..9cc561e7651 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
@@ -839,7 +839,7 @@ TEST_F(FetchDataLoaderTest, LoadAsDataPipeFromDataPipe) {
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
mojo::ScopedDataPipeConsumerHandle readable;
mojo::ScopedDataPipeProducerHandle writable;
- MojoResult rv = mojo::CreateDataPipe(nullptr, &writable, &readable);
+ MojoResult rv = mojo::CreateDataPipe(nullptr, writable, readable);
ASSERT_EQ(rv, MOJO_RESULT_OK);
ASSERT_TRUE(mojo::BlockingCopyFromString("hello", writable));
@@ -880,7 +880,7 @@ TEST_F(FetchDataLoaderTest, LoadAsDataPipeFromDataPipeFailure) {
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
mojo::ScopedDataPipeConsumerHandle readable;
mojo::ScopedDataPipeProducerHandle writable;
- MojoResult rv = mojo::CreateDataPipe(nullptr, &writable, &readable);
+ MojoResult rv = mojo::CreateDataPipe(nullptr, writable, readable);
ASSERT_EQ(rv, MOJO_RESULT_OK);
ASSERT_TRUE(mojo::BlockingCopyFromString("hello", writable));
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_header_list.h b/chromium/third_party/blink/renderer/core/fetch/fetch_header_list.h
index 3a8199c994f..b26b4c93584 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_header_list.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_header_list.h
@@ -19,7 +19,7 @@ class CORE_EXPORT FetchHeaderList final
public:
struct ByteCaseInsensitiveCompare {
bool operator()(const String& lhs, const String& rhs) const {
- return CodeUnitCompareLessThan(lhs.LowerASCII(), rhs.LowerASCII());
+ return CodeUnitCompareIgnoringASCIICaseLessThan(lhs, rhs);
}
};
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 9d835e1052c..13f399df3b8 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -17,6 +17,7 @@
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_response_init.h"
@@ -53,12 +54,14 @@
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h"
#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
@@ -90,90 +93,6 @@ bool HasNonEmptyLocationHeader(const FetchHeaderList* headers) {
return !value.IsEmpty();
}
-// FailedReason enumerates reasons a fetch can return "TypeError: Failed to
-// fetch". This is a temporary measure for debugging a surprisingly high
-// incidence of "TypeError: Failed to fetch" when executing Trust Tokens
-// issuance operations (crbug.com/1128174).
-//
-// Since these values are persisted to histograms, please do not remove or
-// renumber entries.
-//
-// TODO(crbug.com/1133944): Once the investigation of Trust Tokens failures has
-// ended, remove this enum and the associated logging logic.
-enum class FailedReason {
- kRedirectToDataUrlWithImpermissibleFetchMode = 0,
- kContentSecurityPolicyViolation = 1,
- kSameOriginModeButUrlNotSameOrigin = 2,
- kModeIsNoCorsButRedirectModeIsNotFollow = 3,
- kCorsRequestToUrlWithUnsupportedScheme = 4,
- kSchemeFetchToUrlWithUnsupportedScheme = 5,
- kSubresourceIntegrityVerificationError = 6,
- kFailedRedirectCheck = 7,
- kTrustTokensError = 8,
- // The fetch call failed due to a reason other than any of the above, and the
- // response was not blocked. (If it was blocked, the histogram will contain a
- // ResourceRequestBlockedReason value.)
- kOtherNonBlockReason = 9,
-
- // The following correspond to the values of ResourceRequestBlockedReason:
- kBlockedBecauseOther = 10,
- kBlockedBecauseCSP = 11,
- kBlockedBecauseMixedContent = 12,
- kBlockedBecauseOrigin = 13,
- kBlockedBecauseInspector = 14,
- kBlockedBecauseSubresourceFilter = 15,
- kBlockedBecauseContentType = 16,
- kBlockedBecauseCollapsedByClient = 17,
- kBlockedBecauseCoepFrameResourceNeedsCoepHeader = 18,
- kBlockedBecauseCoopSandboxedIFrameCannotNavigateToCoopPage = 19,
- kBlockedBecauseCorpNotSameOrigin = 20,
- kBlockedBecauseCorpNotSameOriginAfterDefaultedToSameOriginByCoep = 21,
- kBlockedBecauseCorpNotSameSite = 22,
- kBlockedBecauseBlockedByExtensionCrbug1128174Investigation = 23,
-
- kMaxValue = kBlockedBecauseBlockedByExtensionCrbug1128174Investigation,
-};
-
-FailedReason ResourceRequestBlockedReasonToFailedReason(
- ResourceRequestBlockedReason blocked_reason) {
- switch (blocked_reason) {
- case ResourceRequestBlockedReason::kOther:
- return FailedReason::kBlockedBecauseOther;
- case ResourceRequestBlockedReason::kCSP:
- return FailedReason::kBlockedBecauseCSP;
- case ResourceRequestBlockedReason::kMixedContent:
- return FailedReason::kBlockedBecauseMixedContent;
- case ResourceRequestBlockedReason::kOrigin:
- return FailedReason::kBlockedBecauseOrigin;
- case ResourceRequestBlockedReason::kInspector:
- return FailedReason::kBlockedBecauseInspector;
- case ResourceRequestBlockedReason::kSubresourceFilter:
- return FailedReason::kBlockedBecauseSubresourceFilter;
- case ResourceRequestBlockedReason::kContentType:
- return FailedReason::kBlockedBecauseContentType;
- case ResourceRequestBlockedReason::kCollapsedByClient:
- return FailedReason::kBlockedBecauseCollapsedByClient;
- case ResourceRequestBlockedReason::kCoepFrameResourceNeedsCoepHeader:
- return FailedReason::kBlockedBecauseCoepFrameResourceNeedsCoepHeader;
- case ResourceRequestBlockedReason::
- kCoopSandboxedIFrameCannotNavigateToCoopPage:
- return FailedReason::
- kBlockedBecauseCoopSandboxedIFrameCannotNavigateToCoopPage;
- case ResourceRequestBlockedReason::kCorpNotSameOrigin:
- return FailedReason::kBlockedBecauseCorpNotSameOrigin;
- case ResourceRequestBlockedReason::
- kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
- return FailedReason::
- kBlockedBecauseCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
- case ResourceRequestBlockedReason::kCorpNotSameSite:
- return FailedReason::kBlockedBecauseCorpNotSameSite;
- case ResourceRequestBlockedReason::
- kBlockedByExtensionCrbug1128174Investigation:
- return FailedReason::
- kBlockedBecauseBlockedByExtensionCrbug1128174Investigation;
- }
-}
-
const char* SerializeTrustTokenOperationType(
network::mojom::TrustTokenOperationType operation_type) {
switch (operation_type) {
@@ -186,19 +105,6 @@ const char* SerializeTrustTokenOperationType(
}
}
-// Logs a more descriptive reason why a fetch with Trust Tokens parameters
-// failed. This is a temporary measure for debugging a surprisingly high
-// incidence of "TypeError: Failed to fetch" when executing Trust Tokens
-// issuance operations (crbug.com/1128174).
-void HistogramFetchFailureReasonForTrustTokensOperation(
- network::mojom::blink::TrustTokenOperationType operation_type,
- FailedReason reason) {
- base::UmaHistogramEnumeration(
- base::StrCat({"Net.TrustTokens.FetchFailedReason", ".",
- SerializeTrustTokenOperationType(operation_type)}),
- reason);
-}
-
// Logs a net error describing why a fetch with Trust Tokens parameters
// failed. This is a temporary measure for debugging a surprisingly high
// incidence of "TypeError: Failed to fetch" when executing Trust Tokens
@@ -230,6 +136,7 @@ class FetchManager::Loader final
// ThreadableLoaderClient implementation.
bool WillFollowRedirect(const KURL&, const ResourceResponse&) override;
void DidReceiveResponse(uint64_t, const ResourceResponse&) override;
+ void DidReceiveCachedMetadata(mojo_base::BigBuffer) override;
void DidStartLoadingResponseBody(BytesConsumer&) override;
void DidFinishLoading(uint64_t) override;
void DidFail(const ResourceError&) override;
@@ -317,8 +224,7 @@ class FetchManager::Loader final
"Unknown error occurred while trying to verify integrity.";
updater_->Update(
BytesConsumer::CreateErrored(BytesConsumer::Error(error_message)));
- loader_->PerformNetworkError(
- error_message, FailedReason::kSubresourceIntegrityVerificationError);
+ loader_->PerformNetworkError(error_message);
}
String DebugName() const override { return "SRIVerifier"; }
@@ -348,14 +254,12 @@ class FetchManager::Loader final
private:
void PerformSchemeFetch();
- void PerformNetworkError(const String& message, FailedReason reason);
+ void PerformNetworkError(const String& message);
void PerformHTTPFetch();
void PerformDataFetch();
// If |dom_exception| is provided, throws the specified DOMException instead
// of the usual "Failed to fetch" TypeError.
- void Failed(const String& message,
- DOMException* dom_exception,
- FailedReason reason);
+ void Failed(const String& message, DOMException* dom_exception);
void NotifyFinished();
ExecutionContext* GetExecutionContext() { return execution_context_; }
@@ -373,6 +277,7 @@ class FetchManager::Loader final
Member<AbortSignal> signal_;
Vector<KURL> url_list_;
Member<ExecutionContext> execution_context_;
+ Member<ScriptCachedMetadataHandler> cached_metadata_handler_;
};
FetchManager::Loader::Loader(ExecutionContext* execution_context,
@@ -408,6 +313,7 @@ void FetchManager::Loader::Trace(Visitor* visitor) const {
visitor->Trace(integrity_verifier_);
visitor->Trace(signal_);
visitor->Trace(execution_context_);
+ visitor->Trace(cached_metadata_handler_);
ThreadableLoaderClient::Trace(visitor);
}
@@ -461,112 +367,60 @@ void FetchManager::Loader::DidReceiveResponse(
ScriptState::Scope scope(script_state);
response_http_status_code_ = response.HttpStatusCode();
- FetchRequestData::Tainting tainting = fetch_request_data_->ResponseTainting();
- if (response.CurrentRequestUrl().ProtocolIsData()) {
- if (fetch_request_data_->Url() == response.CurrentRequestUrl()) {
- // A direct request to data.
- tainting = FetchRequestData::kBasicTainting;
- } else {
- // A redirect to data: scheme occured.
- // Redirects to data URLs are rejected by the spec because
- // same-origin data-URL flag is unset, except for no-cors mode.
- // TODO(hiroshige): currently redirects to data URLs in no-cors
- // mode is also rejected by Chromium side.
- switch (fetch_request_data_->Mode()) {
- case RequestMode::kNoCors:
- tainting = FetchRequestData::kOpaqueTainting;
- break;
- case RequestMode::kSameOrigin:
- case RequestMode::kCors:
- case RequestMode::kCorsWithForcedPreflight:
- case RequestMode::kNavigate:
- PerformNetworkError(
- "Fetch API cannot load " +
- fetch_request_data_->Url().GetString() +
- ". Redirects to data: URL are allowed only when "
- "mode is \"no-cors\".",
- FailedReason::kRedirectToDataUrlWithImpermissibleFetchMode);
- return;
- }
- }
- } else if (!fetch_request_data_->Origin()->CanReadContent(
- response.CurrentRequestUrl())) {
- // Recompute the tainting if the request was redirected to a different
- // origin.
- switch (fetch_request_data_->Mode()) {
- case RequestMode::kSameOrigin:
- NOTREACHED();
- break;
- case RequestMode::kNoCors:
- tainting = FetchRequestData::kOpaqueTainting;
- break;
- case RequestMode::kCors:
- case RequestMode::kCorsWithForcedPreflight:
- tainting = FetchRequestData::kCorsTainting;
- break;
- case RequestMode::kNavigate:
- LOG(FATAL);
- break;
- }
- }
- if (response.WasFetchedViaServiceWorker()) {
- switch (response.GetType()) {
- case FetchResponseType::kBasic:
- case FetchResponseType::kDefault:
- tainting = FetchRequestData::kBasicTainting;
- break;
- case FetchResponseType::kCors:
- tainting = FetchRequestData::kCorsTainting;
- break;
- case FetchResponseType::kOpaque:
- tainting = FetchRequestData::kOpaqueTainting;
- break;
- case FetchResponseType::kOpaqueRedirect:
- DCHECK(
- network_utils::IsRedirectResponseCode(response_http_status_code_));
- break; // The code below creates an opaque-redirect filtered response.
- case FetchResponseType::kError:
- LOG(FATAL) << "When ServiceWorker respond to the request from fetch() "
- "with an error response, FetchManager::Loader::didFail() "
- "must be called instead.";
- break;
- }
+ if (response.MimeType() == "application/wasm" &&
+ response.CurrentRequestUrl().ProtocolIsInHTTPFamily()) {
+ // We create a ScriptCachedMetadataHandler for WASM modules.
+ cached_metadata_handler_ =
+ MakeGarbageCollected<ScriptCachedMetadataHandler>(
+ WTF::TextEncoding(),
+ CachedMetadataSender::Create(
+ response, mojom::blink::CodeCacheType::kWebAssembly,
+ execution_context_->GetSecurityOrigin()));
}
place_holder_body_ = MakeGarbageCollected<PlaceHolderBytesConsumer>();
- FetchResponseData* response_data = FetchResponseData::CreateWithBuffer(
- BodyStreamBuffer::Create(script_state, place_holder_body_, signal_));
-
- response_data->InitFromResourceResponse(
- url_list_, fetch_request_data_->Method(),
- fetch_request_data_->Credentials(), tainting, response);
-
- FetchResponseData* tainted_response = nullptr;
+ FetchResponseData* response_data =
+ FetchResponseData::CreateWithBuffer(BodyStreamBuffer::Create(
+ script_state, place_holder_body_, signal_, cached_metadata_handler_));
DCHECK(!(network_utils::IsRedirectResponseCode(response_http_status_code_) &&
HasNonEmptyLocationHeader(response_data->HeaderList()) &&
fetch_request_data_->Redirect() != RedirectMode::kManual));
+ auto response_type = response.GetType();
if (network_utils::IsRedirectResponseCode(response_http_status_code_) &&
fetch_request_data_->Redirect() == RedirectMode::kManual) {
- tainted_response = response_data->CreateOpaqueRedirectFilteredResponse();
- } else {
- switch (tainting) {
- case FetchRequestData::kBasicTainting:
- tainted_response = response_data->CreateBasicFilteredResponse();
- break;
- case FetchRequestData::kCorsTainting: {
- HTTPHeaderSet header_names = cors::ExtractCorsExposedHeaderNamesList(
- fetch_request_data_->Credentials(), response);
- tainted_response =
- response_data->CreateCorsFilteredResponse(header_names);
- break;
- }
- case FetchRequestData::kOpaqueTainting:
- tainted_response = response_data->CreateOpaqueFilteredResponse();
- break;
+ response_type = network::mojom::FetchResponseType::kOpaqueRedirect;
+ }
+
+ response_data->InitFromResourceResponse(
+ execution_context_, response_type, url_list_,
+ fetch_request_data_->Method(), fetch_request_data_->Credentials(),
+ response);
+
+ FetchResponseData* tainted_response = nullptr;
+ switch (response_type) {
+ case FetchResponseType::kBasic:
+ case FetchResponseType::kDefault:
+ tainted_response = response_data->CreateBasicFilteredResponse();
+ break;
+ case FetchResponseType::kCors: {
+ HTTPHeaderSet header_names = cors::ExtractCorsExposedHeaderNamesList(
+ fetch_request_data_->Credentials(), response);
+ tainted_response =
+ response_data->CreateCorsFilteredResponse(header_names);
+ break;
}
+ case FetchResponseType::kOpaque:
+ tainted_response = response_data->CreateOpaqueFilteredResponse();
+ break;
+ case FetchResponseType::kOpaqueRedirect:
+ tainted_response = response_data->CreateOpaqueRedirectFilteredResponse();
+ break;
+ case FetchResponseType::kError:
+ NOTREACHED();
+ break;
}
response_has_no_store_header_ = response.CacheControlContainsNoStore();
@@ -590,6 +444,12 @@ void FetchManager::Loader::DidReceiveResponse(
}
}
+void FetchManager::Loader::DidReceiveCachedMetadata(mojo_base::BigBuffer data) {
+ if (cached_metadata_handler_) {
+ cached_metadata_handler_->SetSerializedCachedMetadata(std::move(data));
+ }
+}
+
void FetchManager::Loader::DidStartLoadingResponseBody(BytesConsumer& body) {
if (fetch_request_data_->Integrity().IsEmpty() &&
!response_has_no_store_header_) {
@@ -633,23 +493,15 @@ void FetchManager::Loader::DidFail(const ResourceError& error) {
if (error.TrustTokenOperationError() !=
network::mojom::blink::TrustTokenOperationStatus::kOk) {
Failed(String(),
- TrustTokenErrorToDOMException(error.TrustTokenOperationError()),
- FailedReason::kTrustTokensError);
- return;
- }
-
- if (base::Optional<ResourceRequestBlockedReason> blocked_reason =
- error.GetResourceRequestBlockedReason()) {
- Failed(String(), nullptr,
- ResourceRequestBlockedReasonToFailedReason(*blocked_reason));
+ TrustTokenErrorToDOMException(error.TrustTokenOperationError()));
return;
}
- Failed(String(), nullptr, FailedReason::kOtherNonBlockReason);
+ Failed(String(), nullptr);
}
void FetchManager::Loader::DidFailRedirectCheck() {
- Failed(String(), nullptr, FailedReason::kFailedRedirectCheck);
+ Failed(String(), nullptr);
}
void FetchManager::Loader::Start() {
@@ -682,8 +534,7 @@ void FetchManager::Loader::Start() {
// "A network error."
PerformNetworkError(
"Refused to connect to '" + fetch_request_data_->Url().ElidedString() +
- "' because it violates the document's Content Security Policy.",
- FailedReason::kContentSecurityPolicyViolation);
+ "' because it violates the document's Content Security Policy.");
return;
}
@@ -707,11 +558,10 @@ void FetchManager::Loader::Start() {
if (fetch_request_data_->Mode() == RequestMode::kSameOrigin) {
// "A network error."
PerformNetworkError("Fetch API cannot load " +
- fetch_request_data_->Url().GetString() +
- ". Request mode is \"same-origin\" but the URL\'s "
- "origin is not same as the request origin " +
- fetch_request_data_->Origin()->ToString() + ".",
- FailedReason::kSameOriginModeButUrlNotSameOrigin);
+ fetch_request_data_->Url().GetString() +
+ ". Request mode is \"same-origin\" but the URL\'s "
+ "origin is not same as the request origin " +
+ fetch_request_data_->Origin()->ToString() + ".");
return;
}
@@ -720,16 +570,17 @@ void FetchManager::Loader::Start() {
// "If |request|'s redirect mode is not |follow|, then return a network
// error.
if (fetch_request_data_->Redirect() != RedirectMode::kFollow) {
- PerformNetworkError(
- "Fetch API cannot load " + fetch_request_data_->Url().GetString() +
- ". Request mode is \"no-cors\" but the redirect mode "
- "is not \"follow\".",
- FailedReason::kModeIsNoCorsButRedirectModeIsNotFollow);
+ PerformNetworkError("Fetch API cannot load " +
+ fetch_request_data_->Url().GetString() +
+ ". Request mode is \"no-cors\" but the redirect mode "
+ "is not \"follow\".");
return;
}
// "Set |request|'s response tainting to |opaque|."
- fetch_request_data_->SetResponseTainting(FetchRequestData::kOpaqueTainting);
+ // Response tainting is calculated in the CORS module in the network
+ // service.
+ //
// "The result of performing a scheme fetch using |request|."
PerformSchemeFetch();
return;
@@ -743,13 +594,13 @@ void FetchManager::Loader::Start() {
// "A network error."
PerformNetworkError(
"Fetch API cannot load " + fetch_request_data_->Url().GetString() +
- ". URL scheme must be \"http\" or \"https\" for CORS request.",
- FailedReason::kCorsRequestToUrlWithUnsupportedScheme);
+ ". URL scheme must be \"http\" or \"https\" for CORS request.");
return;
}
// "Set |request|'s response tainting to |CORS|."
- fetch_request_data_->SetResponseTainting(FetchRequestData::kCorsTainting);
+ // Response tainting is calculated in the CORS module in the network
+ // service.
// "The result of performing an HTTP fetch using |request| with the
// |CORS flag| set."
@@ -803,15 +654,13 @@ void FetchManager::Loader::PerformSchemeFetch() {
// FIXME: implement other protocols.
PerformNetworkError(
"Fetch API cannot load " + fetch_request_data_->Url().GetString() +
- ". URL scheme \"" + fetch_request_data_->Url().Protocol() +
- "\" is not supported.",
- FailedReason::kSchemeFetchToUrlWithUnsupportedScheme);
+ ". URL scheme \"" + fetch_request_data_->Url().Protocol() +
+ "\" is not supported.");
}
}
-void FetchManager::Loader::PerformNetworkError(const String& message,
- FailedReason reason) {
- Failed(message, nullptr, reason);
+void FetchManager::Loader::PerformNetworkError(const String& message) {
+ Failed(message, nullptr);
}
void FetchManager::Loader::PerformHTTPFetch() {
@@ -955,8 +804,7 @@ void FetchManager::Loader::PerformDataFetch() {
}
void FetchManager::Loader::Failed(const String& message,
- DOMException* dom_exception,
- FailedReason reason) {
+ DOMException* dom_exception) {
if (failed_ || finished_)
return;
failed_ = true;
@@ -967,12 +815,6 @@ void FetchManager::Loader::Failed(const String& message,
mojom::ConsoleMessageSource::kJavaScript,
mojom::ConsoleMessageLevel::kError, message));
}
-
- if (fetch_request_data_ && fetch_request_data_->TrustTokenParams()) {
- HistogramFetchFailureReasonForTrustTokensOperation(
- fetch_request_data_->TrustTokenParams()->type, reason);
- }
-
if (resolver_) {
ScriptState* state = resolver_->GetScriptState();
ScriptState::Scope scope(state);
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index ddf999403d7..4a6fab2c8cf 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -67,6 +67,11 @@ bool IsExcludedHeaderForServiceWorkerFetchEvent(const String& header_name) {
return false;
}
+void SignalError(
+ Persistent<DataPipeBytesConsumer::CompletionNotifier> notifier) {
+ notifier->SignalError(BytesConsumer::Error());
+}
+
void SignalSize(
std::unique_ptr<mojo::Remote<network::mojom::blink::ChunkedDataPipeGetter>>,
Persistent<DataPipeBytesConsumer::CompletionNotifier> notifier,
@@ -109,33 +114,34 @@ FetchRequestData* FetchRequestData::Create(
script_state,
MakeGarbageCollected<BlobBytesConsumer>(
ExecutionContext::From(script_state), fetch_api_request->blob),
- nullptr /* AbortSignal */));
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr));
} else if (fetch_api_request->body.FormBody()) {
- request->SetBuffer(
- BodyStreamBuffer::Create(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- ExecutionContext::From(script_state),
- fetch_api_request->body.FormBody()),
- nullptr /* AbortSignal */));
+ request->SetBuffer(BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(
+ ExecutionContext::From(script_state),
+ fetch_api_request->body.FormBody()),
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr));
} else if (fetch_api_request->body.StreamBody()) {
mojo::ScopedDataPipeConsumerHandle readable;
mojo::ScopedDataPipeProducerHandle writable;
MojoCreateDataPipeOptions options{sizeof(MojoCreateDataPipeOptions),
MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
const MojoResult result =
- mojo::CreateDataPipe(&options, &writable, &readable);
+ mojo::CreateDataPipe(&options, writable, readable);
if (result == MOJO_RESULT_OK) {
DataPipeBytesConsumer::CompletionNotifier* completion_notifier = nullptr;
// Explicitly creating a ReadableStream here in order to remember
// that the request is created from a ReadableStream.
- auto* stream = BodyStreamBuffer::Create(
- script_state,
- MakeGarbageCollected<DataPipeBytesConsumer>(
- ExecutionContext::From(script_state)
- ->GetTaskRunner(TaskType::kNetworking),
- std::move(readable), &completion_notifier),
- /*AbortSignal=*/nullptr)
- ->Stream();
+ auto* stream =
+ BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<DataPipeBytesConsumer>(
+ ExecutionContext::From(script_state)
+ ->GetTaskRunner(TaskType::kNetworking),
+ std::move(readable), &completion_notifier),
+ /*AbortSignal=*/nullptr, /*cached_metadata_handler=*/nullptr)
+ ->Stream();
request->SetBuffer(
MakeGarbageCollected<BodyStreamBuffer>(script_state, stream,
/*AbortSignal=*/nullptr));
@@ -143,6 +149,8 @@ FetchRequestData* FetchRequestData::Create(
auto body_remote = std::make_unique<
mojo::Remote<network::mojom::blink::ChunkedDataPipeGetter>>(
fetch_api_request->body.TakeStreamBody());
+ body_remote->set_disconnect_handler(
+ WTF::Bind(SignalError, WrapPersistent(completion_notifier)));
auto* body_remote_raw = body_remote.get();
(*body_remote_raw)
->GetSize(WTF::Bind(SignalSize, std::move(body_remote),
@@ -151,7 +159,7 @@ FetchRequestData* FetchRequestData::Create(
} else {
request->SetBuffer(BodyStreamBuffer::Create(
script_state, BytesConsumer::CreateErrored(BytesConsumer::Error()),
- nullptr /* AbortSignal */));
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr));
}
}
@@ -198,7 +206,6 @@ FetchRequestData* FetchRequestData::CloneExceptBody() {
request->credentials_ = credentials_;
request->cache_mode_ = cache_mode_;
request->redirect_ = redirect_;
- request->response_tainting_ = response_tainting_;
request->mime_type_ = mime_type_;
request->integrity_ = integrity_;
request->priority_ = priority_;
@@ -238,7 +245,8 @@ FetchRequestData* FetchRequestData::Pass(ScriptState* script_state) {
if (buffer_) {
request->buffer_ = buffer_;
buffer_ = BodyStreamBuffer::Create(
- script_state, BytesConsumer::CreateClosed(), nullptr /* AbortSignal */);
+ script_state, BytesConsumer::CreateClosed(), nullptr /* AbortSignal */,
+ /*cached_metadata_handler=*/nullptr);
buffer_->CloseAndLockAndDisturb();
}
request->url_loader_factory_ = std::move(url_loader_factory_);
@@ -258,7 +266,6 @@ FetchRequestData::FetchRequestData(ExecutionContext* execution_context)
cache_mode_(mojom::FetchCacheMode::kDefault),
redirect_(network::mojom::RedirectMode::kFollow),
importance_(mojom::FetchImportanceMode::kImportanceAuto),
- response_tainting_(kBasicTainting),
priority_(ResourceLoadPriority::kUnresolved),
keepalive_(false),
url_loader_factory_(execution_context),
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
index e1497335f71..0d4ce70651b 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_request_data.h
@@ -36,7 +36,6 @@ class ScriptState;
class CORE_EXPORT FetchRequestData final
: public GarbageCollected<FetchRequestData> {
public:
- enum Tainting { kBasicTainting, kCorsTainting, kOpaqueTainting };
enum class ForServiceWorkerFetchEvent { kFalse, kTrue };
static FetchRequestData* Create(ScriptState*,
@@ -95,8 +94,6 @@ class CORE_EXPORT FetchRequestData final
importance_ = importance;
}
mojom::FetchImportanceMode Importance() const { return importance_; }
- void SetResponseTainting(Tainting tainting) { response_tainting_ = tainting; }
- Tainting ResponseTainting() const { return response_tainting_; }
FetchHeaderList* HeaderList() const { return header_list_.Get(); }
void SetHeaderList(FetchHeaderList* header_list) {
header_list_ = header_list;
@@ -171,7 +168,6 @@ class CORE_EXPORT FetchRequestData final
base::Optional<network::mojom::blink::TrustTokenParams> trust_token_params_;
// FIXME: Support m_useURLCredentialsFlag;
// FIXME: Support m_redirectCount;
- Tainting response_tainting_;
Member<BodyStreamBuffer> buffer_;
String mime_type_;
String integrity_;
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 532fa2b3d10..309db261b46 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
+#include "storage/common/quota/padding_key.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h"
#include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -188,6 +189,7 @@ FetchResponseData* FetchResponseData::Clone(ScriptState* script_state,
ExceptionState& exception_state) {
FetchResponseData* new_response = Create();
new_response->type_ = type_;
+ new_response->padding_ = padding_;
new_response->response_source_ = response_source_;
if (termination_reason_) {
new_response->termination_reason_ = std::make_unique<TerminationReason>();
@@ -204,9 +206,12 @@ FetchResponseData* FetchResponseData::Clone(ScriptState* script_state,
new_response->cors_exposed_header_names_ = cors_exposed_header_names_;
new_response->connection_info_ = connection_info_;
new_response->alpn_negotiated_protocol_ = alpn_negotiated_protocol_;
- new_response->loaded_with_credentials_ = loaded_with_credentials_;
new_response->was_fetched_via_spdy_ = was_fetched_via_spdy_;
new_response->has_range_requested_ = has_range_requested_;
+ if (auth_challenge_info_) {
+ new_response->auth_challenge_info_ =
+ std::make_unique<net::AuthChallengeInfo>(*auth_challenge_info_);
+ }
switch (type_) {
case Type::kBasic:
@@ -269,6 +274,7 @@ mojom::blink::FetchAPIResponsePtr FetchResponseData::PopulateFetchAPIResponse(
response->status_code = status_;
response->status_text = status_message_;
response->response_type = type_;
+ response->padding = padding_;
response->response_source = response_source_;
response->mime_type = mime_type_;
response->request_method = request_method_;
@@ -278,21 +284,24 @@ mojom::blink::FetchAPIResponsePtr FetchResponseData::PopulateFetchAPIResponse(
HeaderSetToVector(cors_exposed_header_names_);
response->connection_info = connection_info_;
response->alpn_negotiated_protocol = alpn_negotiated_protocol_;
- response->loaded_with_credentials = loaded_with_credentials_;
response->was_fetched_via_spdy = was_fetched_via_spdy_;
response->has_range_requested = has_range_requested_;
for (const auto& header : HeaderList()->List())
response->headers.insert(header.first, header.second);
response->parsed_headers = ParseHeaders(
HeaderList()->GetAsRawString(status_, status_message_), request_url);
+ if (auth_challenge_info_) {
+ response->auth_challenge_info = *auth_challenge_info_;
+ }
return response;
}
void FetchResponseData::InitFromResourceResponse(
+ ExecutionContext* context,
+ network::mojom::FetchResponseType response_type,
const Vector<KURL>& request_url_list,
const AtomicString& request_method,
network::mojom::CredentialsMode request_credentials,
- FetchRequestData::Tainting tainting,
const ResourceResponse& response) {
SetStatus(response.HttpStatusCode());
if (response.CurrentRequestUrl().ProtocolIsAbout() ||
@@ -339,14 +348,25 @@ void FetchResponseData::InitFromResourceResponse(
SetWasFetchedViaSpdy(response.WasFetchedViaSPDY());
- // TODO(wanderview): Remove |tainting| and use |response.GetType()|
- // instead once the OOR-CORS disabled path is removed.
- SetLoadedWithCredentials(
- request_credentials == network::mojom::CredentialsMode::kInclude ||
- (request_credentials == network::mojom::CredentialsMode::kSameOrigin &&
- tainting == FetchRequestData::kBasicTainting));
-
SetHasRangeRequested(response.HasRangeRequested());
+
+ // Use the explicit padding in the response provided by a service worker
+ // or compute a new padding if necessary.
+ if (response.GetPadding()) {
+ SetPadding(response.GetPadding());
+ } else {
+ if (storage::ShouldPadResponseType(response_type)) {
+ int64_t padding = response.WasCached()
+ ? storage::ComputeStableResponsePadding(
+ context->GetSecurityOrigin()->ToUrlOrigin(),
+ Url()->GetString().Utf8(), ResponseTime(),
+ request_method.Utf8())
+ : storage::ComputeRandomResponsePadding();
+ SetPadding(padding);
+ }
+ }
+
+ SetAuthChallengeInfo(response.AuthChallengeInfo());
}
FetchResponseData::FetchResponseData(Type type,
@@ -354,6 +374,7 @@ FetchResponseData::FetchResponseData(Type type,
uint16_t status,
AtomicString status_message)
: type_(type),
+ padding_(0),
response_source_(source),
status_(status),
status_message_(status_message),
@@ -361,10 +382,17 @@ FetchResponseData::FetchResponseData(Type type,
response_time_(base::Time::Now()),
connection_info_(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
alpn_negotiated_protocol_("unknown"),
- loaded_with_credentials_(false),
was_fetched_via_spdy_(false),
has_range_requested_(false) {}
+void FetchResponseData::SetAuthChallengeInfo(
+ const base::Optional<net::AuthChallengeInfo>& auth_challenge_info) {
+ if (auth_challenge_info) {
+ auth_challenge_info_ =
+ std::make_unique<net::AuthChallengeInfo>(*auth_challenge_info);
+ }
+}
+
void FetchResponseData::ReplaceBodyStreamBuffer(BodyStreamBuffer* buffer) {
if (type_ == Type::kBasic || type_ == Type::kCors) {
DCHECK(internal_response_);
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
index 33657bb877c..ae38d29921d 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -85,6 +85,8 @@ class CORE_EXPORT FetchResponseData final
}
bool HasRangeRequested() const { return has_range_requested_; }
+ int64_t GetPadding() const { return padding_; }
+ void SetPadding(int64_t padding) { padding_ = padding; }
void SetResponseSource(network::mojom::FetchResponseSource response_source) {
response_source_ = response_source;
}
@@ -116,15 +118,14 @@ class CORE_EXPORT FetchResponseData final
void SetAlpnNegotiatedProtocol(AtomicString alpn_negotiated_protocol) {
alpn_negotiated_protocol_ = alpn_negotiated_protocol;
}
- void SetLoadedWithCredentials(bool loaded_with_credentials) {
- loaded_with_credentials_ = loaded_with_credentials;
- }
void SetWasFetchedViaSpdy(bool was_fetched_via_spdy) {
was_fetched_via_spdy_ = was_fetched_via_spdy;
}
void SetHasRangeRequested(bool has_range_requested) {
has_range_requested_ = has_range_requested;
}
+ void SetAuthChallengeInfo(
+ const base::Optional<net::AuthChallengeInfo>& auth_challenge_info);
// If the type is Default, replaces |buffer_|.
// If the type is Basic or CORS, replaces |buffer_| and
@@ -138,16 +139,18 @@ class CORE_EXPORT FetchResponseData final
// Initialize non-body data from the given |response|.
void InitFromResourceResponse(
+ ExecutionContext* context,
+ network::mojom::FetchResponseType response_type,
const Vector<KURL>& request_url_list,
const AtomicString& request_method,
network::mojom::CredentialsMode request_credentials,
- FetchRequestData::Tainting tainting,
const ResourceResponse& response);
void Trace(Visitor*) const;
private:
network::mojom::FetchResponseType type_;
+ int64_t padding_;
network::mojom::FetchResponseSource response_source_;
std::unique_ptr<TerminationReason> termination_reason_;
Vector<KURL> url_list_;
@@ -163,9 +166,11 @@ class CORE_EXPORT FetchResponseData final
HTTPHeaderSet cors_exposed_header_names_;
net::HttpResponseInfo::ConnectionInfo connection_info_;
AtomicString alpn_negotiated_protocol_;
- bool loaded_with_credentials_;
bool was_fetched_via_spdy_;
bool has_range_requested_;
+ // |auth_challenge_info_| is a std::unique_ptr instead of base::Optional
+ // |because this member is empty in most cases.
+ std::unique_ptr<net::AuthChallengeInfo> auth_challenge_info_;
DISALLOW_COPY_AND_ASSIGN(FetchResponseData);
};
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
index ac21aeea0c9..3bf7b973b54 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
@@ -274,7 +274,8 @@ TEST_F(FetchResponseDataTest, ContentSecurityPolicy) {
"frame-ancestors 'none'");
mojom::blink::FetchAPIResponsePtr fetch_api_response =
- internal_response->PopulateFetchAPIResponse(KURL());
+ internal_response->PopulateFetchAPIResponse(
+ KURL("https://www.example.org"));
auto& csp = fetch_api_response->parsed_headers->content_security_policy;
EXPECT_EQ(csp.size(), 2U);
@@ -284,4 +285,18 @@ TEST_F(FetchResponseDataTest, ContentSecurityPolicy) {
network::mojom::ContentSecurityPolicyType::kReport);
}
+TEST_F(FetchResponseDataTest, AuthChallengeInfo) {
+ FetchResponseData* internal_response = CreateInternalResponse();
+ net::AuthChallengeInfo auth_challenge_info;
+ auth_challenge_info.is_proxy = true;
+ auth_challenge_info.challenge = "foobar";
+ internal_response->SetAuthChallengeInfo(auth_challenge_info);
+
+ mojom::blink::FetchAPIResponsePtr fetch_api_response =
+ internal_response->PopulateFetchAPIResponse(KURL());
+ ASSERT_TRUE(fetch_api_response->auth_challenge_info.has_value());
+ EXPECT_TRUE(fetch_api_response->auth_challenge_info->is_proxy);
+ EXPECT_EQ("foobar", fetch_api_response->auth_challenge_info->challenge);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
index 3a4f3513681..697f9596f24 100644
--- a/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -190,8 +190,8 @@ class DataPipeAndDataBytesConsumer final : public BytesConsumer {
mojo::ScopedDataPipeProducerHandle pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle pipe_consumer_handle;
- MojoResult rv = mojo::CreateDataPipe(nullptr, &pipe_producer_handle,
- &pipe_consumer_handle);
+ MojoResult rv = mojo::CreateDataPipe(nullptr, pipe_producer_handle,
+ pipe_consumer_handle);
if (rv != MOJO_RESULT_OK) {
return Result::kError;
}
@@ -408,7 +408,8 @@ class ComplexFormDataBytesConsumer final : public BytesConsumer {
case FormDataElement::kEncodedFile: {
auto file_length = element.file_length_;
if (file_length < 0) {
- if (!GetFileSize(element.filename_, file_length)) {
+ if (!GetFileSize(element.filename_, *execution_context,
+ file_length)) {
form_data_ = nullptr;
blob_bytes_consumer_ = BytesConsumer::CreateErrored(
Error("Cannot determine a file size"));
diff --git a/chromium/third_party/blink/renderer/core/fetch/place_holder_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/place_holder_bytes_consumer_test.cc
index 86ed0004f96..fe4a86bf2d6 100644
--- a/chromium/third_party/blink/renderer/core/fetch/place_holder_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/place_holder_bytes_consumer_test.cc
@@ -70,7 +70,7 @@ TEST_F(PlaceHolderBytesConsumerTest, Update) {
TEST_F(PlaceHolderBytesConsumerTest, DrainAsDataPipe) {
mojo::ScopedDataPipeConsumerHandle consumer_end;
mojo::ScopedDataPipeProducerHandle producer_end;
- auto result = mojo::CreateDataPipe(nullptr, &producer_end, &consumer_end);
+ auto result = mojo::CreateDataPipe(nullptr, producer_end, consumer_end);
ASSERT_EQ(result, MOJO_RESULT_OK);
diff --git a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
index 261f4b75822..5bba4165edc 100644
--- a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
@@ -112,6 +112,14 @@ BytesConsumer::Result ReadableStreamBytesConsumer::BeginRead(
return Result::kDone;
if (pending_buffer_) {
+ // The UInt8Array has become detached due to, for example, the site
+ // transferring it away via postMessage(). Since we were in the middle
+ // of reading the array we must error out.
+ if (pending_buffer_->IsDetached()) {
+ SetErrored();
+ return Result::kError;
+ }
+
DCHECK_LE(pending_offset_, pending_buffer_->length());
*buffer = reinterpret_cast<const char*>(pending_buffer_->Data()) +
pending_offset_;
@@ -141,6 +149,15 @@ BytesConsumer::Result ReadableStreamBytesConsumer::BeginRead(
BytesConsumer::Result ReadableStreamBytesConsumer::EndRead(size_t read_size) {
DCHECK(pending_buffer_);
+
+ // While the buffer size is immutable once constructed, the buffer can be
+ // detached if the site does something like transfer it away using
+ // postMessage(). Since we were in the middle of a read we must error out.
+ if (pending_buffer_->IsDetached()) {
+ SetErrored();
+ return Result::kError;
+ }
+
DCHECK_LE(pending_offset_ + read_size, pending_buffer_->length());
pending_offset_ += read_size;
if (pending_offset_ >= pending_buffer_->length()) {
@@ -220,12 +237,18 @@ void ReadableStreamBytesConsumer::OnRejected() {
if (state_ == PublicState::kClosed)
return;
DCHECK_EQ(state_, PublicState::kReadableOrWaiting);
- state_ = PublicState::kErrored;
- reader_ = nullptr;
Client* client = client_;
- ClearClient();
+ SetErrored();
if (client)
client->OnStateChange();
}
+void ReadableStreamBytesConsumer::SetErrored() {
+ DCHECK_NE(state_, PublicState::kClosed);
+ DCHECK_NE(state_, PublicState::kErrored);
+ state_ = PublicState::kErrored;
+ ClearClient();
+ reader_ = nullptr;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
index 860933e7b97..c33c32bea9b 100644
--- a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
+++ b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
@@ -47,6 +47,7 @@ class CORE_EXPORT ReadableStreamBytesConsumer final : public BytesConsumer {
void OnRead(DOMUint8Array*);
void OnReadDone();
void OnRejected();
+ void SetErrored();
void Notify();
Member<ReadableStreamDefaultReader> reader_;
diff --git a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
index e309feee8b6..5fe5edb91fc 100644
--- a/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
@@ -239,6 +239,109 @@ TEST(ReadableStreamBytesConsumerTest, TwoPhaseRead) {
EXPECT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available));
}
+TEST(ReadableStreamBytesConsumerTest, TwoPhaseReadDetachedDuringRead) {
+ V8TestingScope scope;
+ ScriptState* script_state = scope.GetScriptState();
+
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(script_state);
+ auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_source, 0);
+
+ auto* chunk = DOMUint8Array::Create(4);
+ chunk->Data()[0] = 0x43;
+ chunk->Data()[1] = 0x44;
+ chunk->Data()[2] = 0x45;
+ chunk->Data()[3] = 0x46;
+ underlying_source->Enqueue(
+ ScriptValue(script_state->GetIsolate(), ToV8(chunk, script_state)));
+ underlying_source->Close();
+
+ Persistent<BytesConsumer> consumer =
+ MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
+ Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
+ consumer->SetClient(client);
+ Checkpoint checkpoint;
+
+ InSequence s;
+ EXPECT_CALL(checkpoint, Call(1));
+ EXPECT_CALL(checkpoint, Call(2));
+ EXPECT_CALL(checkpoint, Call(3));
+ EXPECT_CALL(*client, OnStateChange());
+ EXPECT_CALL(checkpoint, Call(4));
+
+ const char* buffer = nullptr;
+ size_t available = 0;
+ checkpoint.Call(1);
+ test::RunPendingTasks();
+ checkpoint.Call(2);
+ EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available));
+ checkpoint.Call(3);
+ test::RunPendingTasks();
+ checkpoint.Call(4);
+ EXPECT_EQ(Result::kOk, consumer->BeginRead(&buffer, &available));
+ ASSERT_EQ(4u, available);
+ EXPECT_EQ(0x43, buffer[0]);
+ EXPECT_EQ(0x44, buffer[1]);
+ EXPECT_EQ(0x45, buffer[2]);
+ EXPECT_EQ(0x46, buffer[3]);
+ chunk->DetachForTesting();
+ EXPECT_EQ(Result::kError, consumer->EndRead(4));
+ EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState());
+}
+
+TEST(ReadableStreamBytesConsumerTest, TwoPhaseReadDetachedBetweenReads) {
+ V8TestingScope scope;
+ ScriptState* script_state = scope.GetScriptState();
+
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(script_state);
+ auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_source, 0);
+
+ auto* chunk = DOMUint8Array::Create(4);
+ chunk->Data()[0] = 0x43;
+ chunk->Data()[1] = 0x44;
+ chunk->Data()[2] = 0x45;
+ chunk->Data()[3] = 0x46;
+ underlying_source->Enqueue(
+ ScriptValue(script_state->GetIsolate(), ToV8(chunk, script_state)));
+ underlying_source->Close();
+
+ Persistent<BytesConsumer> consumer =
+ MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
+ Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
+ consumer->SetClient(client);
+ Checkpoint checkpoint;
+
+ InSequence s;
+ EXPECT_CALL(checkpoint, Call(1));
+ EXPECT_CALL(checkpoint, Call(2));
+ EXPECT_CALL(checkpoint, Call(3));
+ EXPECT_CALL(*client, OnStateChange());
+ EXPECT_CALL(checkpoint, Call(4));
+
+ const char* buffer = nullptr;
+ size_t available = 0;
+ checkpoint.Call(1);
+ test::RunPendingTasks();
+ checkpoint.Call(2);
+ EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available));
+ checkpoint.Call(3);
+ test::RunPendingTasks();
+ checkpoint.Call(4);
+ EXPECT_EQ(Result::kOk, consumer->BeginRead(&buffer, &available));
+ ASSERT_EQ(4u, available);
+ EXPECT_EQ(0x43, buffer[0]);
+ EXPECT_EQ(0x44, buffer[1]);
+ EXPECT_EQ(0x45, buffer[2]);
+ EXPECT_EQ(0x46, buffer[3]);
+ EXPECT_EQ(Result::kOk, consumer->EndRead(1));
+ chunk->DetachForTesting();
+ EXPECT_EQ(Result::kError, consumer->BeginRead(&buffer, &available));
+ EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState());
+}
+
TEST(ReadableStreamBytesConsumerTest, EnqueueUndefined) {
V8TestingScope scope;
ScriptState* script_state = scope.GetScriptState();
diff --git a/chromium/third_party/blink/renderer/core/fetch/request.cc b/chromium/third_party/blink/renderer/core/fetch/request.cc
index 51d193e2d77..911cf0eb35b 100644
--- a/chromium/third_party/blink/renderer/core/fetch/request.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/request.cc
@@ -125,7 +125,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
script_state,
MakeGarbageCollected<BlobBytesConsumer>(execution_context,
blob->GetBlobDataHandle()),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = blob->type();
} else if (body->IsArrayBuffer()) {
// Avoid calling into V8 from the following constructor parameters, which
@@ -139,7 +139,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
}
return_buffer = BodyStreamBuffer::Create(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(array_buffer),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
} else if (body->IsArrayBufferView()) {
// Avoid calling into V8 from the following constructor parameters, which
// is potentially unsafe.
@@ -154,7 +154,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
return_buffer = BodyStreamBuffer::Create(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(array_buffer_view),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
} else if (V8FormData::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
V8FormData::ToImpl(body.As<v8::Object>())->EncodeMultiPartFormData();
@@ -162,19 +162,19 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
// FormDataEncoder::generateUniqueBoundaryString.
content_type = AtomicString("multipart/form-data; boundary=") +
form_data->Boundary().data();
- return_buffer =
- BodyStreamBuffer::Create(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ return_buffer = BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
} else if (V8URLSearchParams::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
V8URLSearchParams::ToImpl(body.As<v8::Object>())->ToEncodedFormData();
- return_buffer =
- BodyStreamBuffer::Create(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ return_buffer = BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = "application/x-www-form-urlencoded;charset=UTF-8";
} else if (RuntimeEnabledFeatures::FetchUploadStreamingEnabled(
execution_context) &&
@@ -195,8 +195,8 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
return nullptr;
}
// "Set |stream| to |object|."
- return_buffer =
- MakeGarbageCollected<BodyStreamBuffer>(script_state, readable_stream);
+ return_buffer = MakeGarbageCollected<BodyStreamBuffer>(
+ script_state, readable_stream, /*cached_metadata_handler=*/nullptr);
} else {
String string = NativeValueTraits<IDLUSVString>::NativeValue(
isolate, body, exception_state);
@@ -205,7 +205,7 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
return_buffer = BodyStreamBuffer::Create(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(string),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = "text/plain;charset=UTF-8";
}
@@ -695,8 +695,9 @@ Request* Request::CreateRequestWithRequestOrString(
// non-null, run these substeps:"
if (input_request && input_request->BodyBuffer()) {
// "Let |dummyStream| be an empty ReadableStream object."
- auto* dummy_stream = BodyStreamBuffer::Create(
- script_state, BytesConsumer::CreateClosed(), nullptr);
+ auto* dummy_stream =
+ BodyStreamBuffer::Create(script_state, BytesConsumer::CreateClosed(),
+ nullptr, /*cached_metadata_handler=*/nullptr);
// "Set |input|'s request's body to a new body whose stream is
// |dummyStream|."
input_request->request_->SetBuffer(dummy_stream);
diff --git a/chromium/third_party/blink/renderer/core/fetch/response.cc b/chromium/third_party/blink/renderer/core/fetch/response.cc
index 6584b973ec3..2d632ba2810 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/response.cc
@@ -89,7 +89,8 @@ FetchResponseData* CreateFetchResponseDataFromFetchAPIResponse(
script_state,
MakeGarbageCollected<BlobBytesConsumer>(
ExecutionContext::From(script_state), fetch_api_response.blob),
- nullptr /* AbortSignal */, fetch_api_response.side_data_blob));
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr,
+ fetch_api_response.side_data_blob));
}
// Filter the response according to |fetch_api_response|'s ResponseType.
@@ -152,7 +153,7 @@ Response* Response::Create(ScriptState* script_state,
script_state,
MakeGarbageCollected<BlobBytesConsumer>(execution_context,
blob->GetBlobDataHandle()),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = blob->type();
} else if (body->IsArrayBuffer()) {
// Avoid calling into V8 from the following constructor parameters, which
@@ -166,7 +167,7 @@ Response* Response::Create(ScriptState* script_state,
body_buffer = BodyStreamBuffer::Create(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(array_buffer),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
}
} else if (body->IsArrayBufferView()) {
// Avoid calling into V8 from the following constructor parameters, which
@@ -181,7 +182,7 @@ Response* Response::Create(ScriptState* script_state,
body_buffer = BodyStreamBuffer::Create(
script_state,
MakeGarbageCollected<FormDataBytesConsumer>(array_buffer_view),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
}
} else if (V8FormData::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
@@ -190,25 +191,26 @@ Response* Response::Create(ScriptState* script_state,
// FormDataEncoder::generateUniqueBoundaryString.
content_type = AtomicString("multipart/form-data; boundary=") +
form_data->Boundary().data();
- body_buffer =
- BodyStreamBuffer::Create(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ body_buffer = BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
} else if (V8URLSearchParams::HasInstance(body, isolate)) {
scoped_refptr<EncodedFormData> form_data =
V8URLSearchParams::ToImpl(body.As<v8::Object>())->ToEncodedFormData();
- body_buffer =
- BodyStreamBuffer::Create(script_state,
- MakeGarbageCollected<FormDataBytesConsumer>(
- execution_context, std::move(form_data)),
- nullptr /* AbortSignal */);
+ body_buffer = BodyStreamBuffer::Create(
+ script_state,
+ MakeGarbageCollected<FormDataBytesConsumer>(execution_context,
+ std::move(form_data)),
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = "application/x-www-form-urlencoded;charset=UTF-8";
} else if (V8ReadableStream::HasInstance(body, isolate)) {
UseCounter::Count(execution_context,
WebFeature::kFetchResponseConstructionWithStream);
body_buffer = MakeGarbageCollected<BodyStreamBuffer>(
- script_state, V8ReadableStream::ToImpl(body.As<v8::Object>()));
+ script_state, V8ReadableStream::ToImpl(body.As<v8::Object>()),
+ /*cached_metadata_handler=*/nullptr);
} else {
String string = NativeValueTraits<IDLUSVString>::NativeValue(
isolate, body, exception_state);
@@ -216,7 +218,7 @@ Response* Response::Create(ScriptState* script_state,
return nullptr;
body_buffer = BodyStreamBuffer::Create(
script_state, MakeGarbageCollected<FormDataBytesConsumer>(string),
- nullptr /* AbortSignal */);
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr);
content_type = "text/plain;charset=UTF-8";
}
return Create(script_state, body_buffer, content_type, init, exception_state);
@@ -373,6 +375,7 @@ FetchResponseData* Response::CreateUnfilteredFetchResponseDataWithoutBody(
else
response = FetchResponseData::CreateNetworkErrorResponse();
+ response->SetPadding(fetch_api_response.padding);
response->SetResponseSource(fetch_api_response.response_source);
response->SetURLList(fetch_api_response.url_list);
response->SetStatus(fetch_api_response.status_code);
@@ -385,8 +388,6 @@ FetchResponseData* Response::CreateUnfilteredFetchResponseDataWithoutBody(
response->SetConnectionInfo(fetch_api_response.connection_info);
response->SetAlpnNegotiatedProtocol(
WTF::AtomicString(fetch_api_response.alpn_negotiated_protocol));
- response->SetLoadedWithCredentials(
- fetch_api_response.loaded_with_credentials);
response->SetWasFetchedViaSpdy(fetch_api_response.was_fetched_via_spdy);
response->SetHasRangeRequested(fetch_api_response.has_range_requested);
diff --git a/chromium/third_party/blink/renderer/core/fetch/response_test.cc b/chromium/third_party/blink/renderer/core/fetch/response_test.cc
index a2808538d1e..5dc11b16401 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response_test.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/response_test.cc
@@ -101,7 +101,8 @@ BodyStreamBuffer* CreateHelloWorldBuffer(ScriptState* script_state) {
src->Add(Command(Command::kData, "Hello, "));
src->Add(Command(Command::kData, "world"));
src->Add(Command(Command::kDone));
- return BodyStreamBuffer::Create(script_state, src, nullptr);
+ return BodyStreamBuffer::Create(script_state, src, nullptr,
+ /*cached_metadata_handler=*/nullptr);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneDefault) {
@@ -167,7 +168,8 @@ TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneError) {
V8TestingScope scope;
BodyStreamBuffer* buffer = BodyStreamBuffer::Create(
scope.GetScriptState(),
- BytesConsumer::CreateErrored(BytesConsumer::Error()), nullptr);
+ BytesConsumer::CreateErrored(BytesConsumer::Error()), nullptr,
+ /*cached_metadata_handler=*/nullptr);
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
diff --git a/chromium/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc b/chromium/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
index 9f0007b9d33..a8382e1bfef 100644
--- a/chromium/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/fetch/testing/worker_internals_fetch.h"
+#include <utility>
+
#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/fetch/response.h"
@@ -38,7 +40,7 @@ ScriptPromise WorkerInternalsFetch::getResourcePriority(
DCHECK(worker_global);
auto callback = WTF::Bind(&WorkerInternalsFetch::ResolveResourcePriority,
- WTF::Passed(WrapPersistent(resolver)));
+ WrapPersistent(resolver));
ResourceFetcher::AddPriorityObserverForTesting(resource_url,
std::move(callback));
diff --git a/chromium/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc b/chromium/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
index 5921d8b9c19..93cc917c1ac 100644
--- a/chromium/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
@@ -112,6 +112,13 @@ DOMException* TrustTokenErrorToDOMException(
"cache hit",
DOMException::GetErrorName(
DOMExceptionCode::kNoModificationAllowedError));
+ case network::mojom::blink::TrustTokenOperationStatus::
+ kOperationSuccessfullyFulfilledLocally:
+ return DOMException::Create(
+ "Trust Tokens operation satisfied locally, without needing to send "
+ "the request to its initial destination",
+ DOMException::GetErrorName(
+ DOMExceptionCode::kNoModificationAllowedError));
case network::mojom::blink::TrustTokenOperationStatus::kFailedPrecondition:
return DOMException::Create(
"Precondition failed during Trust Tokens operation",
diff --git a/chromium/third_party/blink/renderer/core/fileapi/DIR_METADATA b/chromium/third_party/blink/renderer/core/fileapi/DIR_METADATA
new file mode 100644
index 00000000000..955fe83177b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fileapi/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Storage>FileAPI"
+}
+
+team_email: "storage-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/fileapi/OWNERS b/chromium/third_party/blink/renderer/core/fileapi/OWNERS
index 792720cc02c..fa93d1042db 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/OWNERS
+++ b/chromium/third_party/blink/renderer/core/fileapi/OWNERS
@@ -1,6 +1,3 @@
jsbell@chromium.org
mek@chromium.org
pwnall@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>FileAPI
diff --git a/chromium/third_party/blink/renderer/core/fileapi/blob.cc b/chromium/third_party/blink/renderer/core/fileapi/blob.cc
index 300edc142fa..06fd75c3085 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/blob.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/blob.cc
@@ -159,8 +159,7 @@ void Blob::PopulateBlobData(
DOMArrayBuffer* array_buffer = item.GetAsArrayBuffer();
blob_data->AppendBytes(array_buffer->Data(), array_buffer->ByteLength());
} else if (item.IsArrayBufferView()) {
- DOMArrayBufferView* array_buffer_view =
- item.GetAsArrayBufferView().View();
+ auto&& array_buffer_view = item.GetAsArrayBufferView();
blob_data->AppendBytes(array_buffer_view->BaseAddress(),
array_buffer_view->byteLength());
} else if (item.IsBlob()) {
@@ -219,7 +218,7 @@ ReadableStream* Blob::stream(ScriptState* script_state) const {
script_state,
MakeGarbageCollected<BlobBytesConsumer>(
ExecutionContext::From(script_state), blob_data_handle_),
- nullptr);
+ /*signal=*/nullptr, /*cached_metadata_handler=*/nullptr);
return body_buffer->Stream();
}
diff --git a/chromium/third_party/blink/renderer/core/fileapi/file_reader.cc b/chromium/third_party/blink/renderer/core/fileapi/file_reader.cc
index 2bbc4db7923..93221ba5cf9 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/file_reader.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/file_reader.cc
@@ -335,7 +335,10 @@ void FileReader::abort() {
loading_state_ = kLoadingStateAborted;
DCHECK_NE(kDone, state_);
- state_ = kDone;
+ // Synchronously cancel the loader before dispatching events. This way we make
+ // sure the FileReader internal state stays consistent even if another load
+ // is started from one of the event handlers, or right after abort returns.
+ Terminate();
base::AutoReset<bool> firing_events(&still_firing_events_, true);
@@ -347,15 +350,12 @@ void FileReader::abort() {
ThrottlingController::RemoveReader(GetExecutionContext(), this);
FireEvent(event_type_names::kAbort);
+ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was
+ // started from the abort event handler.
FireEvent(event_type_names::kLoadend);
// All possible events have fired and we're done, no more pending activity.
ThrottlingController::FinishReader(GetExecutionContext(), this, final_step);
-
- // Also synchronously cancel the loader, as script might initiate a new load
- // right after this method returns, in which case an async termination would
- // terminate the wrong loader.
- Terminate();
}
void FileReader::result(StringOrArrayBuffer& result_attribute) const {
@@ -428,6 +428,8 @@ void FileReader::DidFinishLoading() {
ThrottlingController::RemoveReader(GetExecutionContext(), this);
FireEvent(event_type_names::kLoad);
+ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was
+ // started from the abort event handler.
FireEvent(event_type_names::kLoadend);
// All possible events have fired and we're done, no more pending activity.
diff --git a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index f6fda6f5329..67d16f0df58 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -92,7 +92,7 @@ void FileReaderLoader::Start(scoped_refptr<BlobDataHandle> blob_data) {
blink::BlobUtils::GetDataPipeCapacity(blob_data->size());
mojo::ScopedDataPipeProducerHandle producer_handle;
- MojoResult rv = CreateDataPipe(&options, &producer_handle, &consumer_handle_);
+ MojoResult rv = CreateDataPipe(&options, producer_handle, consumer_handle_);
if (rv != MOJO_RESULT_OK) {
Failed(FileErrorCode::kNotReadableErr, FailureType::kMojoPipeCreation);
return;
diff --git a/chromium/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc b/chromium/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
index 9c44beb2f88..c91d004f2a2 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
+++ b/chromium/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
@@ -67,6 +67,9 @@ class FakeURLRegistry : public URLRegistry {
class PublicURLManagerTest : public testing::Test {
public:
PublicURLManagerTest() : url_store_receiver_(&url_store_) {}
+ ~PublicURLManagerTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
void SetUp() override {
execution_context_ = MakeGarbageCollected<NullExecutionContext>();
diff --git a/chromium/third_party/blink/renderer/core/frame/DEPS b/chromium/third_party/blink/renderer/core/frame/DEPS
index 3ebe612468a..0c8b737e7d1 100644
--- a/chromium/third_party/blink/renderer/core/frame/DEPS
+++ b/chromium/third_party/blink/renderer/core/frame/DEPS
@@ -25,18 +25,27 @@ specific_include_rules = {
"+cc/tiles/frame_viewer_instrumentation.h",
"+components/paint_preview/common/paint_preview_tracker.h",
],
+ "mhtml_archive_test\.cc": [
+ "+services/network/public/cpp/is_potentially_trustworthy.h",
+ ],
+ "remote_frame\.h": [
+ "+components/viz/common/surfaces/parent_local_surface_id_allocator.h",
+ ],
"remote_frame_view\.cc": [
+ "+cc/base/math_util.h",
"+components/paint_preview/common/paint_preview_tracker.h",
"+printing/buildflags/buildflags.h",
"+printing/metafile_skia.h",
+ "+ui/gfx/transform_util.h",
],
"visual_viewport\.cc": [
"+cc/layers/solid_color_scrollbar_layer.h",
],
- "web_frame_widget_base\.cc": [
+ "web_frame_widget_impl\.cc": [
"+cc/trees/swap_promise.h",
+ "+cc/trees/compositor_commit_data.h",
],
- "web_frame_widget_base\.h": [
+ "web_frame_widget_impl\.h": [
"+services/viz/public/mojom/hit_test/input_target_client.mojom-blink.h",
"+ui/base/mojom/ui_base_types.mojom-shared.h",
],
diff --git a/chromium/third_party/blink/renderer/core/frame/DIR_METADATA b/chromium/third_party/blink/renderer/core/frame/DIR_METADATA
new file mode 100644
index 00000000000..622ef56a4e2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Internals>Frames"
+}
+
+team_email: "platform-architecture-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/frame/OWNERS b/chromium/third_party/blink/renderer/core/frame/OWNERS
index c91bc1ee546..1661967c4fc 100644
--- a/chromium/third_party/blink/renderer/core/frame/OWNERS
+++ b/chromium/third_party/blink/renderer/core/frame/OWNERS
@@ -4,6 +4,3 @@ japhet@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>Frames
diff --git a/chromium/third_party/blink/renderer/core/frame/ad_tracker.cc b/chromium/third_party/blink/renderer/core/frame/ad_tracker.cc
index 051822a637b..8bfd9a19b7b 100644
--- a/chromium/third_party/blink/renderer/core/frame/ad_tracker.cc
+++ b/chromium/third_party/blink/renderer/core/frame/ad_tracker.cc
@@ -51,11 +51,6 @@ namespace features {
// the currently running stack is ad related.
const base::Feature kAsyncStackAdTagging{"AsyncStackAdTagging",
base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether the AdTracker analyzes the bottom and top of the stack or
-// just the top of the stack when detecting ads.
-const base::Feature kTopOfStackAdTagging{"TopOfStackAdTagging",
- base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
// static
@@ -82,9 +77,7 @@ bool AdTracker::IsAdScriptExecutingInDocument(Document* document,
AdTracker::AdTracker(LocalFrame* local_root)
: local_root_(local_root),
async_stack_enabled_(
- base::FeatureList::IsEnabled(features::kAsyncStackAdTagging)),
- top_of_stack_only_(
- base::FeatureList::IsEnabled(features::kTopOfStackAdTagging)) {
+ base::FeatureList::IsEnabled(features::kAsyncStackAdTagging)) {
local_root_->GetProbeSink()->AddAdTracker(this);
}
@@ -112,7 +105,7 @@ String AdTracker::ScriptAtTopOfStack() {
return String();
v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(isolate, 0);
- v8::Local<v8::String> script_name = frame->GetScriptNameOrSourceURL();
+ v8::Local<v8::String> script_name = frame->GetScriptName();
if (script_name.IsEmpty() || !script_name->Length())
return GenerateFakeUrlFromScriptId(frame->GetScriptId());
@@ -149,9 +142,6 @@ void AdTracker::WillExecuteScript(ExecutionContext* execution_context,
}
}
- if (top_of_stack_only_)
- return;
-
if (!should_track_with_id)
is_ad = IsKnownAdScript(execution_context, script_url);
@@ -161,9 +151,6 @@ void AdTracker::WillExecuteScript(ExecutionContext* execution_context,
}
void AdTracker::DidExecuteScript() {
- if (top_of_stack_only_)
- return;
-
if (stack_frame_is_ad_.back()) {
DCHECK_LT(0u, num_ads_in_stack_);
num_ads_in_stack_ -= 1;
@@ -208,12 +195,14 @@ void AdTracker::Did(const probe::CallFunction& probe) {
bool AdTracker::CalculateIfAdSubresource(
ExecutionContext* execution_context,
- const ResourceRequest& request,
+ const KURL& request_url,
ResourceType resource_type,
const FetchInitiatorInfo& initiator_info,
bool known_ad) {
// Check if the document loading the resource is an ad.
- known_ad = known_ad || IsKnownAdExecutionContext(execution_context);
+ const bool is_ad_execution_context =
+ IsKnownAdExecutionContext(execution_context);
+ known_ad = known_ad || is_ad_execution_context;
// We skip script checking for stylesheet-initiated resource requests as the
// stack may represent the cause of a style recalculation rather than the
@@ -232,8 +221,8 @@ bool AdTracker::CalculateIfAdSubresource(
// contexts, because any script executed inside an ad context is considered an
// ad script by IsKnownAdScript.
if (resource_type == ResourceType::kScript && known_ad &&
- !IsKnownAdExecutionContext(execution_context)) {
- AppendToKnownAdScripts(*execution_context, request.Url().GetString());
+ !is_ad_execution_context) {
+ AppendToKnownAdScripts(*execution_context, request_url.GetString());
}
return known_ad;
@@ -286,7 +275,7 @@ bool AdTracker::IsAdScriptInStack(StackType stack_type) {
// (e.g., when v8 is executed) but not the entire stack. For a small cost we
// can also check the top of the stack (this is much cheaper than getting the
// full stack from v8).
- return IsKnownAdScript(execution_context, ScriptAtTopOfStack());
+ return IsKnownAdScriptForCheckedContext(*execution_context, String());
}
bool AdTracker::IsKnownAdScript(ExecutionContext* execution_context,
@@ -297,13 +286,25 @@ bool AdTracker::IsKnownAdScript(ExecutionContext* execution_context,
if (IsKnownAdExecutionContext(execution_context))
return true;
- if (url.IsEmpty())
- return false;
+ return IsKnownAdScriptForCheckedContext(*execution_context, url);
+}
- auto it = known_ad_scripts_.find(execution_context);
+bool AdTracker::IsKnownAdScriptForCheckedContext(
+ ExecutionContext& execution_context,
+ const String& url) {
+ DCHECK(!IsKnownAdExecutionContext(&execution_context));
+ auto it = known_ad_scripts_.find(&execution_context);
if (it == known_ad_scripts_.end())
return false;
- return it->value.Contains(url);
+
+ if (it->value.IsEmpty())
+ return false;
+
+ // Delay calling ScriptAtTopOfStack() as much as possible due to its cost.
+ String script_url = url.IsNull() ? ScriptAtTopOfStack() : url;
+ if (script_url.IsEmpty())
+ return false;
+ return it->value.Contains(script_url);
}
// This is a separate function for testing purposes.
diff --git a/chromium/third_party/blink/renderer/core/frame/ad_tracker.h b/chromium/third_party/blink/renderer/core/frame/ad_tracker.h
index 2506a79d6bf..e93aa2de5cd 100644
--- a/chromium/third_party/blink/renderer/core/frame/ad_tracker.h
+++ b/chromium/third_party/blink/renderer/core/frame/ad_tracker.h
@@ -21,7 +21,6 @@ namespace blink {
class Document;
class ExecutionContext;
class LocalFrame;
-class ResourceRequest;
enum class ResourceType : uint8_t;
namespace probe {
@@ -31,7 +30,6 @@ class ExecuteScript;
namespace features {
CORE_EXPORT extern const base::Feature kAsyncStackAdTagging;
-CORE_EXPORT extern const base::Feature kTopOfStackAdTagging;
}
// Tracker for tagging resources as ads based on the call stack scripts.
@@ -63,7 +61,7 @@ class CORE_EXPORT AdTracker : public GarbageCollected<AdTracker> {
// Virtual for testing.
virtual bool CalculateIfAdSubresource(
ExecutionContext* execution_context,
- const ResourceRequest& request,
+ const KURL& request_url,
ResourceType resource_type,
const FetchInitiatorInfo& initiator_info,
bool known_ad);
@@ -110,7 +108,8 @@ class CORE_EXPORT AdTracker : public GarbageCollected<AdTracker> {
const String& script_name,
int script_id);
void DidExecuteScript();
- bool IsKnownAdScript(ExecutionContext* execution_context, const String& url);
+ bool IsKnownAdScript(ExecutionContext*, const String& url);
+ bool IsKnownAdScriptForCheckedContext(ExecutionContext&, const String& url);
void AppendToKnownAdScripts(ExecutionContext&, const String& url);
Member<LocalFrame> local_root_;
@@ -121,8 +120,9 @@ class CORE_EXPORT AdTracker : public GarbageCollected<AdTracker> {
uint32_t num_ads_in_stack_ = 0;
- // The set of ad scripts detected outside of ad-frame contexts. Scripts with
- // no name (i.e. URL) use a String created by GenerateFakeUrlFromScriptId().
+ // The set of ad scripts detected outside of ad-frame contexts. Scripts are
+ // identified by name (i.e. resource URL). Scripts with no name (i.e. inline
+ // scripts) use a String created by GenerateFakeUrlFromScriptId() instead.
HeapHashMap<WeakMember<ExecutionContext>, HashSet<String>> known_ad_scripts_;
// The number of ad-related async tasks currently running in the stack.
@@ -133,10 +133,6 @@ class CORE_EXPORT AdTracker : public GarbageCollected<AdTracker> {
// callstack to run (e.g., registered callbacks).
const bool async_stack_enabled_;
- // True if the TopOfStack experiment is running, which forces the AdTracker to
- // ignore the bottom of stack frames when looking for ad script.
- const bool top_of_stack_only_;
-
DISALLOW_COPY_AND_ASSIGN(AdTracker);
};
diff --git a/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index b9444b9be43..e0da6a1c31e 100644
--- a/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -49,6 +49,10 @@ const char kPageWithAdScript[] = R"HTML(
<head><script defer src="script.js?ad=true"></script></head>
<body><div class="test">Test</div></body>
)HTML";
+const char kPageWithFrame[] = R"HTML(
+ <head></head>
+ <body><div class="test">Test</div><iframe src="frame.html"></iframe></body>
+ )HTML";
const char kPageWithStyleTagLoadingVanillaResources[] = R"HTML(
<head><style>
@font-face {
@@ -63,12 +67,6 @@ const char kPageWithStyleTagLoadingVanillaResources[] = R"HTML(
<body><div class="test">Test</div></body>
)HTML";
-const char kScriptToCreateFrame[] = R"SCRIPT(
- let iframe = document.createElement("iframe");
- iframe.src = "frame.html";
- document.body.appendChild(iframe);
- )SCRIPT";
-
const char kStylesheetWithVanillaResources[] = R"CSS(
@font-face {
font-family: "Vanilla";
@@ -142,20 +140,19 @@ class TestAdTracker : public AdTracker {
}
bool CalculateIfAdSubresource(ExecutionContext* execution_context,
- const ResourceRequest& resource_request,
+ const KURL& request_url,
ResourceType resource_type,
const FetchInitiatorInfo& initiator_info,
bool ad_request) override {
- if (!ad_suffix_.IsEmpty() &&
- resource_request.Url().GetString().EndsWith(ad_suffix_)) {
+ if (!ad_suffix_.IsEmpty() && request_url.GetString().EndsWith(ad_suffix_)) {
ad_request = true;
}
ad_request = AdTracker::CalculateIfAdSubresource(
- execution_context, resource_request, resource_type, initiator_info,
+ execution_context, request_url, resource_type, initiator_info,
ad_request);
- String resource_url = resource_request.Url().GetString();
+ String resource_url = request_url.GetString();
is_ad_.insert(resource_url, ad_request);
if (quit_closure_ && url_to_wait_for_ == resource_url) {
@@ -263,36 +260,6 @@ TEST_F(AdTrackerTest, TopScriptTaggedAsAdResource) {
AdTracker::StackType::kBottomOnly));
}
-TEST_F(AdTrackerTest, TopOfStackOnly_NoAdsOnTop) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kTopOfStackAdTagging);
- CreateAdTracker();
-
- String ad_script_url("https://example.com/bar.js");
- AppendToKnownAdScripts(ad_script_url);
-
- WillExecuteScript(ad_script_url);
- WillExecuteScript("https://example.com/foo.js");
- ad_tracker_->SetScriptAtTopOfStack("https://www.example.com/baz.js");
-
- EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
-}
-
-TEST_F(AdTrackerTest, TopOfStackOnly_AdsOnTop) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kTopOfStackAdTagging);
- CreateAdTracker();
-
- String ad_script_url("https://example.com/bar.js");
- AppendToKnownAdScripts(ad_script_url);
-
- WillExecuteScript(ad_script_url);
- WillExecuteScript("https://example.com/foo.js");
- ad_tracker_->SetScriptAtTopOfStack(ad_script_url);
-
- EXPECT_TRUE(AnyExecutingScriptsTaggedAsAdResource());
-}
-
// Tests that if neither script in the stack is an ad,
// AnyExecutingScriptsTaggedAsAdResource should return false.
TEST_F(AdTrackerTest, AnyExecutingScriptsTaggedAsAdResource_False) {
@@ -463,25 +430,11 @@ TEST_F(AdTrackerSimTest, ScriptLoadedWhileExecutingAdScript) {
// Unknown script running in an ad context should be labeled as ad script.
TEST_F(AdTrackerSimTest, ScriptDetectedByContext) {
- const char kAdScriptUrl[] = "https://example.com/ad_script.js";
- SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
-
- ad_tracker_->SetAdSuffix("ad_script.js");
-
// Create an iframe that's considered an ad.
- main_resource_->Complete("<body><script src='ad_script.js'></script></body>");
- ad_script.Complete(R"SCRIPT(
- frame = document.createElement("iframe");
- document.body.appendChild(frame);
- )SCRIPT");
-
- // Wait for script to run.
- base::RunLoop().RunUntilIdle();
-
- // The child frame should be an ad subframe.
+ main_resource_->Complete("<body><iframe></iframe></body>");
auto* child_frame =
To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
- EXPECT_TRUE(child_frame->IsAdSubframe());
+ child_frame->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
// Now run unknown script in the child's context. It should be considered an
// ad based on context alone.
@@ -561,27 +514,15 @@ TEST_F(AdTrackerSimTest, RedirectToAdUrl) {
}
TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
- SimSubresourceRequest ad_script("https://example.com/ad_script.js",
- "text/javascript");
SimRequest ad_frame("https://example.com/ad_frame.html", "text/html");
SimSubresourceRequest foo_css("https://example.com/foo.css", "text/style");
- ad_tracker_->SetAdSuffix("ad_script.js");
// Create an iframe that's considered an ad.
- main_resource_->Complete("<body><script src='ad_script.js'></script></body>");
- ad_script.Complete(R"SCRIPT(
- frame = document.createElement("iframe");
- frame.src="ad_frame.html";
- document.body.appendChild(frame);
- )SCRIPT");
-
- // Wait for script to run.
- base::RunLoop().RunUntilIdle();
-
- // The child frame should be an ad subframe.
+ main_resource_->Complete(
+ "<body><iframe src='ad_frame.html'></iframe></body>");
auto* child_frame =
To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
- EXPECT_TRUE(child_frame->IsAdSubframe());
+ child_frame->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
// Load a resource from the frame. It should be detected as an ad resource due
// to its context.
@@ -596,7 +537,8 @@ TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
}
// When inline script in an ad frame inserts an iframe into a non-ad frame, the
-// new frame should be considered an ad.
+// new frame should be considered as created by ad script (and would therefore
+// be tagged as an ad).
TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
SimSubresourceRequest ad_script("https://example.com/ad_script.js",
"text/javascript");
@@ -613,9 +555,13 @@ TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
// Wait for script to run.
base::RunLoop().RunUntilIdle();
- // Verify that the new frame is an ad frame.
- EXPECT_TRUE(To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild())
- ->IsAdSubframe());
+ auto* child_frame =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+
+ // Verify that the new frame is considered created by ad script then set it
+ // as an ad subframe. This emulates the embedder tagging a frame as an ad.
+ EXPECT_TRUE(child_frame->IsSubframeCreatedByAdScript());
+ child_frame->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
// Create a new sibling frame to the ad frame. The ad context calls the non-ad
// context's (top frame) appendChild.
@@ -627,10 +573,10 @@ TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
</script>
)HTML");
- // The new sibling frame should also be identified as an ad.
+ // The new sibling frame should also be identified as created by ad script.
EXPECT_TRUE(
To<LocalFrame>(GetDocument().GetFrame()->Tree().ScopedChild("ad_sibling"))
- ->IsAdSubframe());
+ ->IsSubframeCreatedByAdScript());
}
// Image loaded by ad script is tagged as ad.
@@ -782,7 +728,7 @@ TEST_F(AdTrackerSimTest, DataURLImageLoadedWhileExecutingAdScriptAsyncEnabled) {
EXPECT_TRUE(image_element->IsAdRelated());
}
-// Frame loaded by ad script is tagged as ad.
+// Frame loaded by ad script is considered created by ad script.
TEST_F(AdTrackerSimTest, FrameLoadedWhileExecutingAdScript) {
const char kAdUrl[] = "https://example.com/ad_script.js";
const char kVanillaUrl[] = "https://example.com/vanilla_page.html";
@@ -804,13 +750,19 @@ TEST_F(AdTrackerSimTest, FrameLoadedWhileExecutingAdScript) {
// Wait for script to run.
base::RunLoop().RunUntilIdle();
+ auto* child_frame =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+
+ // Verify that the new frame is considered created by ad script then set it
+ // as an ad subframe. This emulates the SubresourceFilterAgent's tagging.
+ EXPECT_TRUE(child_frame->IsSubframeCreatedByAdScript());
+ child_frame->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
+
vanilla_page.Complete("<img src=vanilla_img.jpg></img>");
vanilla_image.Complete("");
EXPECT_TRUE(IsKnownAdScript(GetDocument().GetExecutionContext(), kAdUrl));
EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kAdUrl));
- Frame* child_frame = GetDocument().GetFrame()->Tree().FirstChild();
- EXPECT_TRUE(To<LocalFrame>(child_frame)->IsAdSubframe());
EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kVanillaImgUrl));
}
@@ -876,9 +828,9 @@ TEST_F(AdTrackerSimTest, SameOriginSubframeFromAdScript) {
iframe_resource.Complete("iframe data");
- Frame* subframe = GetDocument().GetFrame()->Tree().FirstChild();
- auto* local_subframe = To<LocalFrame>(subframe);
- EXPECT_TRUE(local_subframe->IsAdSubframe());
+ auto* subframe =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+ EXPECT_TRUE(subframe->IsSubframeCreatedByAdScript());
}
TEST_F(AdTrackerSimTest, SameOriginDocWrittenSubframeFromAdScript) {
@@ -901,9 +853,9 @@ TEST_F(AdTrackerSimTest, SameOriginDocWrittenSubframeFromAdScript) {
// Wait for script to run.
base::RunLoop().RunUntilIdle();
- Frame* subframe = GetDocument().GetFrame()->Tree().FirstChild();
- auto* local_subframe = To<LocalFrame>(subframe);
- EXPECT_TRUE(local_subframe->IsAdSubframe());
+ auto* subframe =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+ EXPECT_TRUE(subframe->IsSubframeCreatedByAdScript());
}
// This test class allows easy running of tests that only differ by whether
@@ -1012,21 +964,23 @@ TEST_P(AdTrackerVanillaOrAdSimTest, LinkRelStylesheetAddedByScript) {
}
TEST_P(AdTrackerVanillaOrAdSimTest, ExternalStylesheetInFrame) {
- String script_url = FlipURLOnAdRun("https://example.com/script.js");
String vanilla_stylesheet_url = "https://example.com/style.css";
String vanilla_font_url = "https://example.com/font.woff2";
String vanilla_image_url = "https://example.com/pixel.png";
SimRequest frame("https://example.com/frame.html", "text/html");
- SimSubresourceRequest script(script_url, "text/javascript");
SimSubresourceRequest stylesheet(vanilla_stylesheet_url, "text/css");
SimSubresourceRequest font(vanilla_font_url, "font/woff2");
SimSubresourceRequest image(vanilla_image_url, "image/png");
ad_tracker_->SetAdSuffix("ad=true");
- main_resource_->Complete(IsAdRun() ? kPageWithAdScript
- : kPageWithVanillaScript);
- script.Complete(kScriptToCreateFrame);
+ main_resource_->Complete(kPageWithFrame);
+ if (IsAdRun()) {
+ auto* subframe =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+ subframe->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
+ }
+
frame.Complete(kPageWithVanillaExternalStylesheet);
stylesheet.Complete(kStylesheetWithVanillaResources);
@@ -1037,11 +991,6 @@ TEST_P(AdTrackerVanillaOrAdSimTest, ExternalStylesheetInFrame) {
font.Complete();
image.Complete();
- Frame* subframe = GetDocument().GetFrame()->Tree().FirstChild();
- auto* local_subframe = To<LocalFrame>(subframe);
- EXPECT_EQ(local_subframe->IsAdSubframe(), IsAdRun());
-
- EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(script_url), IsAdRun());
EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_stylesheet_url),
IsAdRun());
EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_font_url), IsAdRun());
@@ -1099,19 +1048,21 @@ TEST_F(AdTrackerSimTest, StyleTagInMainframe) {
// according to the heuristic that all requests from an ad frame should also be
// tagged as ads.
TEST_P(AdTrackerVanillaOrAdSimTest, StyleTagInSubframe) {
- String script_url = FlipURLOnAdRun("https://example.com/script.js");
String vanilla_font_url = "https://example.com/font.woff2";
String vanilla_image_url = "https://example.com/pixel.png";
SimRequest frame("https://example.com/frame.html", "text/html");
- SimSubresourceRequest script(script_url, "text/javascript");
SimSubresourceRequest font(vanilla_font_url, "font/woff2");
SimSubresourceRequest image(vanilla_image_url, "image/png");
ad_tracker_->SetAdSuffix("ad=true");
- main_resource_->Complete(IsAdRun() ? kPageWithAdScript
- : kPageWithVanillaScript);
- script.Complete(kScriptToCreateFrame);
+ main_resource_->Complete(kPageWithFrame);
+ if (IsAdRun()) {
+ auto* subframe =
+ To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+ subframe->SetIsAdSubframe(blink::mojom::AdFrameType::kRootAd);
+ }
+
frame.Complete(kPageWithStyleTagLoadingVanillaResources);
// Wait for stylesheet to fetch resources.
@@ -1121,11 +1072,6 @@ TEST_P(AdTrackerVanillaOrAdSimTest, StyleTagInSubframe) {
font.Complete();
image.Complete();
- Frame* subframe = GetDocument().GetFrame()->Tree().FirstChild();
- auto* local_subframe = To<LocalFrame>(subframe);
- EXPECT_EQ(local_subframe->IsAdSubframe(), IsAdRun());
-
- EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(script_url), IsAdRun());
EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_font_url), IsAdRun());
EXPECT_EQ(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_image_url),
IsAdRun());
@@ -1487,6 +1433,80 @@ TEST_F(AdTrackerSimTest, AdModuleScript_ResourceTagged) {
EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_image_url));
}
+// A resource fetched with ad script at top of stack is still tagged as an ad
+// when the ad script defines a sourceURL.
+TEST_F(AdTrackerSimTest, AdScriptWithSourceURLAtTopOfStack_StillTagged) {
+ String vanilla_script_url = "https://example.com/script.js";
+ String ad_script_url = "https://example.com/script.js?ad=true";
+ String vanilla_image_url = "https://example.com/pixel.png";
+ SimSubresourceRequest vanilla_script(vanilla_script_url, "text/javascript");
+ SimSubresourceRequest ad_script(ad_script_url, "text/javascript");
+ SimSubresourceRequest image(vanilla_image_url, "image/png");
+
+ ad_tracker_->SetAdSuffix("ad=true");
+
+ main_resource_->Complete(R"HTML(
+ <head><script src="script.js?ad=true"></script>
+ <script src="script.js"></script></head>
+ <body><div>Test</div></body>
+ )HTML");
+
+ // We don't directly fetch in ad script as we aim to test ScriptAtTopOfStack()
+ // not WillExecuteScript().
+ ad_script.Complete(R"SCRIPT(
+ function getImage() { fetch('pixel.png'); }
+ //# sourceURL=source.js
+ )SCRIPT");
+
+ vanilla_script.Complete(R"SCRIPT(
+ getImage();
+ )SCRIPT");
+
+ ad_tracker_->WaitForSubresource(vanilla_image_url);
+
+ EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(ad_script_url));
+ EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_script_url));
+ EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_image_url));
+}
+
+// A dynamically added script with no src is still tagged as an ad if created
+// by an ad script even if it defines a sourceURL.
+TEST_F(AdTrackerSimTest, InlineAdScriptWithSourceURLAtTopOfStack_StillTagged) {
+ String ad_script_url = "https://example.com/script.js?ad=true";
+ String vanilla_script_url = "https://example.com/script.js";
+ String vanilla_image_url = "https://example.com/pixel.png";
+ SimSubresourceRequest ad_script(ad_script_url, "text/javascript");
+ SimSubresourceRequest vanilla_script(vanilla_script_url, "text/javascript");
+ SimSubresourceRequest image(vanilla_image_url, "image/png");
+
+ ad_tracker_->SetAdSuffix("ad=true");
+
+ main_resource_->Complete(R"HTML(
+ <body><script src="script.js?ad=true"></script>
+ <script src="script.js"></script></body>
+ )HTML");
+
+ ad_script.Complete(R"SCRIPT(
+ let script = document.createElement("script");
+ let text = document.createTextNode(
+ "function getImage() { fetch('pixel.png'); } \n"
+ + "//# sourceURL=source.js");
+ script.appendChild(text);
+ document.body.appendChild(script);
+ )SCRIPT");
+
+ // Fetch a resource using the function defined by dynamically added ad script.
+ vanilla_script.Complete(R"SCRIPT(
+ getImage();
+ )SCRIPT");
+
+ ad_tracker_->WaitForSubresource(vanilla_image_url);
+
+ EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(ad_script_url));
+ EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_script_url));
+ EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(vanilla_image_url));
+}
+
class AdTrackerDisabledSimTest : public SimTest,
private ScopedAdTaggingForTest {
protected:
diff --git a/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc b/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
index bfa4bda3524..244c086f3ec 100644
--- a/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -83,7 +83,7 @@ class BrowserControlsTest : public testing::Test,
WebViewImpl* Initialize(const std::string& page_name = "large-div.html") {
// Load a page with large body and set viewport size to 400x400 to ensure
// main frame is scrollable.
- helper_.InitializeAndLoad(base_url_ + page_name, nullptr, nullptr, nullptr,
+ helper_.InitializeAndLoad(base_url_ + page_name, nullptr, nullptr,
&ConfigureSettings);
GetWebView()->MainFrameViewWidget()->Resize(gfx::Size(400, 400));
@@ -169,7 +169,7 @@ class BrowserControlsSimTest : public SimTest {
WebView().GetSettings()->SetMainFrameResizesAreOrientationChanges(true);
WebView().GetSettings()->SetShrinksViewportContentToFit(true);
WebView().SetDefaultPageScaleLimits(0.25f, 5);
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown,
false);
WebView().ResizeWithBrowserControls(gfx::Size(412, 604), 56.f, 50.f, true);
@@ -785,7 +785,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(StateConstraints)) {
ScrollOffset(0, 100), mojom::blink::ScrollType::kProgrammatic);
// Setting permitted state should change the content offset to match the
// constraint.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kShown, cc::BrowserControlsState::kShown,
false);
Compositor().BeginFrame();
@@ -804,7 +804,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(StateConstraints)) {
// Setting permitted state should change content offset to match the
// constraint.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kHidden,
false);
Compositor().BeginFrame();
@@ -817,7 +817,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(StateConstraints)) {
GetDocument().View()->LayoutViewport()->GetScrollOffset());
// Setting permitted state to "both" should not change content offset.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kBoth, false);
Compositor().BeginFrame();
EXPECT_FLOAT_EQ(0, WebView().GetBrowserControls().ContentOffset());
@@ -843,19 +843,19 @@ TEST_F(BrowserControlsSimTest, MAYBE(StateConstraints)) {
WebView().MainFrameViewWidget()->HandleInputEvent(
GenerateEvent(WebInputEvent::Type::kGestureScrollEnd));
EXPECT_FLOAT_EQ(0, WebView().GetBrowserControls().ContentOffset());
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kBoth, false);
Compositor().BeginFrame();
EXPECT_FLOAT_EQ(0, WebView().GetBrowserControls().ContentOffset());
// Setting just the constraint should affect the content offset.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kBoth,
false);
Compositor().BeginFrame();
EXPECT_FLOAT_EQ(0, WebView().GetBrowserControls().ContentOffset());
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kShown, cc::BrowserControlsState::kBoth, false);
Compositor().BeginFrame();
EXPECT_FLOAT_EQ(50, WebView().GetBrowserControls().ContentOffset());
@@ -939,7 +939,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
Compositor().BeginFrame();
WebView().ResizeWithBrowserControls(gfx::Size(400, 300), 100.f, 0, true);
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown, false);
Compositor().BeginFrame();
@@ -957,7 +957,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
// Now lock the controls in a hidden state. The layout and elements should
// resize without a WebView::resize.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kBoth,
false);
Compositor().BeginFrame();
@@ -969,7 +969,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
// Unlock the controls, the sizes should change even though the controls are
// still hidden.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kBoth, false);
Compositor().BeginFrame();
@@ -979,7 +979,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
EXPECT_EQ(300, GetDocument().GetFrame()->View()->GetLayoutSize().Height());
// Now lock the controls in a shown state.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kShown, cc::BrowserControlsState::kBoth, false);
WebView().ResizeWithBrowserControls(gfx::Size(400, 300), 100.f, 0, true);
Compositor().BeginFrame();
@@ -991,7 +991,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
// Shown -> Hidden
WebView().ResizeWithBrowserControls(gfx::Size(400, 400), 100.f, 0, false);
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kBoth,
false);
Compositor().BeginFrame();
@@ -1003,14 +1003,14 @@ TEST_F(BrowserControlsSimTest, MAYBE(AffectLayoutHeightWhenConstrained)) {
// Go from Unlocked and showing, to locked and hidden but issue the resize
// before the constraint update to check for race issues.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown, false);
WebView().ResizeWithBrowserControls(gfx::Size(400, 300), 100.f, 0, true);
Compositor().BeginFrame();
ASSERT_EQ(300, GetDocument().GetFrame()->View()->GetLayoutSize().Height());
WebView().ResizeWithBrowserControls(gfx::Size(400, 400), 100.f, 0, false);
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kHidden,
false);
Compositor().BeginFrame();
@@ -1401,7 +1401,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(ViewportUnitsWhenControlsLocked)) {
<div id="spacer"></div>
)HTML");
WebView().ResizeWithBrowserControls(gfx::Size(400, 300), 100.f, 0, true);
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown, false);
Compositor().BeginFrame();
@@ -1414,7 +1414,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(ViewportUnitsWhenControlsLocked)) {
// Lock the browser controls to hidden.
{
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kHidden,
false);
WebView().ResizeWithBrowserControls(gfx::Size(400, 400), 100.f, 0, false);
@@ -1435,7 +1435,7 @@ TEST_F(BrowserControlsSimTest, MAYBE(ViewportUnitsWhenControlsLocked)) {
// Lock the browser controls to shown. This should cause the vh units to
// behave as usual by including the browser controls region in 100vh.
{
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kShown, cc::BrowserControlsState::kShown,
false);
WebView().ResizeWithBrowserControls(gfx::Size(400, 300), 100.f, 0, true);
@@ -1640,12 +1640,12 @@ TEST_F(BrowserControlsSimTest, MixAnimatedAndNonAnimatedUpdateState) {
ASSERT_EQ(1.f, WebView().GetBrowserControls().TopShownRatio());
// Kick off a non-animated clamp to hide the top controls.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kBoth,
false /* animated */);
// Now kick off an animated one to do the same thing.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kBoth,
true /* animated */);
@@ -1688,7 +1688,7 @@ TEST_F(BrowserControlsSimTest, HideAnimated) {
ASSERT_EQ(1.f, WebView().GetBrowserControls().BottomShownRatio());
// Kick off an animated hide.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kHidden,
true /* animated */);
@@ -1722,7 +1722,7 @@ TEST_F(BrowserControlsSimTest, ShowAnimated) {
)HTML");
Compositor().BeginFrame();
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kHidden,
false);
@@ -1732,7 +1732,7 @@ TEST_F(BrowserControlsSimTest, ShowAnimated) {
ASSERT_EQ(0.f, WebView().GetBrowserControls().BottomShownRatio());
// Kick off an animated show.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown,
true /* animated */);
@@ -1788,7 +1788,7 @@ TEST_F(BrowserControlsSimTest, ConstraintDoesntClampRatioInBlink) {
// Constrain the controls to hidden from the compositor. This should
// actually cause the controls to hide when we commit.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kHidden,
false /* animated */);
Compositor().BeginFrame();
@@ -1811,7 +1811,7 @@ TEST_F(BrowserControlsSimTest, ConstraintDoesntClampRatioInBlink) {
// Constrain the controls to hidden from the compositor. This should
// actually cause the controls to hide when we commit.
- Compositor().layer_tree_host()->UpdateBrowserControlsState(
+ Compositor().LayerTreeHost()->UpdateBrowserControlsState(
cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown,
false /* animated */);
Compositor().BeginFrame();
diff --git a/chromium/third_party/blink/renderer/core/frame/build.gni b/chromium/third_party/blink/renderer/core/frame/build.gni
index 9c164212e43..1aba36c7cd8 100644
--- a/chromium/third_party/blink/renderer/core/frame/build.gni
+++ b/chromium/third_party/blink/renderer/core/frame/build.gni
@@ -13,7 +13,8 @@ blink_core_sources_frame = [
"coop_access_violation_report_body.h",
"csp/content_security_policy.cc",
"csp/content_security_policy.h",
- "csp/csp_directive.h",
+ "csp/conversion_util.cc",
+ "csp/conversion_util.h",
"csp/csp_directive_list.cc",
"csp/csp_directive_list.h",
"csp/csp_source.cc",
@@ -22,18 +23,18 @@ blink_core_sources_frame = [
"csp/csp_violation_report_body.h",
"csp/execution_context_csp_delegate.cc",
"csp/execution_context_csp_delegate.h",
- "csp/media_list_directive.cc",
- "csp/media_list_directive.h",
"csp/navigation_initiator_impl.cc",
"csp/navigation_initiator_impl.h",
"csp/require_trusted_types_for_directive.cc",
"csp/require_trusted_types_for_directive.h",
"csp/source_list_directive.cc",
"csp/source_list_directive.h",
- "csp/string_list_directive.cc",
- "csp/string_list_directive.h",
+ "csp/trusted_types_directive.cc",
+ "csp/trusted_types_directive.h",
"dactyloscoper.cc",
"dactyloscoper.h",
+ "frame_content_as_text.h",
+ "frame_content_as_text.cc",
"deprecated_schedule_style_recalc_during_layout.cc",
"deprecated_schedule_style_recalc_during_layout.h",
"deprecation.cc",
@@ -172,8 +173,6 @@ blink_core_sources_frame = [
"root_frame_viewport.h",
"rotation_viewport_anchor.cc",
"rotation_viewport_anchor.h",
- "sandbox_flags.cc",
- "sandbox_flags.h",
"savable_resources.cc",
"savable_resources.h",
"scheduling.cc",
@@ -209,8 +208,6 @@ blink_core_sources_frame = [
"local_frame_client_impl.cc",
"local_frame_client_impl.h",
"web_frame.cc",
- "web_frame_widget_base.cc",
- "web_frame_widget_base.h",
"web_frame_widget_impl.cc",
"web_frame_widget_impl.h",
"web_local_frame_impl.cc",
@@ -218,9 +215,9 @@ blink_core_sources_frame = [
"web_remote_frame_impl.cc",
"web_local_frame_client.cc",
"web_remote_frame_impl.h",
- "web_view_frame_widget.cc",
- "web_view_frame_widget.h",
"window_event_handlers.h",
+ "window_controls_overlay.cc",
+ "window_controls_overlay.h",
"window_or_worker_global_scope.cc",
"window_or_worker_global_scope.h",
]
diff --git a/chromium/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h b/chromium/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h
index 0c31f02e4a1..2e83b7d8b53 100644
--- a/chromium/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h
+++ b/chromium/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h
@@ -12,7 +12,8 @@
namespace blink {
-class CORE_EXPORT CoopAccessViolationReportBody : public LocationReportBody {
+class CORE_EXPORT CoopAccessViolationReportBody final
+ : public LocationReportBody {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/DEPS b/chromium/third_party/blink/renderer/core/frame/csp/DEPS
index 4f0cae7a1a9..76ceececdf2 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/DEPS
+++ b/chromium/third_party/blink/renderer/core/frame/csp/DEPS
@@ -1,3 +1,8 @@
include_rules = [
"+testing/libfuzzer",
]
+specific_include_rules = {
+ "csp_directive_list.cc": [
+ "+services/network/public/cpp/content_security_policy/content_security_policy.h",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 9033b2050fc..b05faa096f1 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -29,7 +29,6 @@
#include <utility>
#include "base/debug/dump_without_crashing.h"
-#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
@@ -47,8 +46,6 @@
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/frame/csp/csp_directive_list.h"
#include "third_party/blink/renderer/core/frame/csp/csp_source.h"
-#include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
-#include "third_party/blink/renderer/core/frame/csp/source_list_directive.h"
#include "third_party/blink/renderer/core/frame/frame_client.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -100,6 +97,17 @@ bool CheckHeaderTypeMatches(
return false;
}
+int32_t HashAlgorithmsUsed(
+ const network::mojom::blink::CSPSourceList* source_list) {
+ int32_t hash_algorithms_used = 0;
+ if (!source_list)
+ return hash_algorithms_used;
+ for (const auto& hash : source_list->hashes) {
+ hash_algorithms_used |= static_cast<int32_t>(hash->algorithm);
+ }
+ return hash_algorithms_used;
+}
+
} // namespace
bool ContentSecurityPolicy::IsNonceableElement(const Element* element) {
@@ -174,43 +182,14 @@ void ContentSecurityPolicy::BindToDelegate(
// call this function multiple times.
delegate_ = &delegate;
ApplyPolicySideEffectsToDelegate();
-}
-void ContentSecurityPolicy::SetupSelf(const SecurityOrigin& security_origin) {
- // Ensure that 'self' processes correctly.
- self_protocol_ = security_origin.Protocol();
- self_source_ = MakeGarbageCollected<CSPSource>(
- this, self_protocol_, security_origin.Host(),
- // CSPSource uses port CSPSource::kPortUnspecified to represent a
- // missing port and reserves port 0 specifically for origins with port set
- // to 0; SecurityOrigin uses port 0 for origins with port 0 as well as for
- // origins without ports.
- //
- // TODO(crbug.com/1136678): Once SecurityOrigin starts treating port 0 as
- // a specifically set port, rather than as a sentinel for an
- // omitted or default-valued port, modify this logic.
- security_origin.Port() == 0 ? CSPSource::kPortUnspecified
- : security_origin.Port(),
- String(), CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-}
-
-void ContentSecurityPolicy::SetupSelf(const ContentSecurityPolicy& other) {
- self_protocol_ = other.self_protocol_;
- if (other.self_source_) {
- self_source_ =
- MakeGarbageCollected<CSPSource>(this, *(other.self_source_.Get()));
- }
+ // Report use counters for all the policies that have been parsed until now.
+ ReportUseCounters(policies_);
}
void ContentSecurityPolicy::ApplyPolicySideEffectsToDelegate() {
DCHECK(delegate_);
- const SecurityOrigin* self_origin =
- delegate_->GetSecurityOrigin()->GetOriginOrPrecursorOriginIfOpaque();
- DCHECK(self_origin);
-
- SetupSelf(*self_origin);
-
// Set mixed content checking and sandbox flags, then dump all the parsing
// error messages, then poke at histograms.
if (sandbox_mask_ != network::mojom::blink::WebSandboxFlags::kNone) {
@@ -229,17 +208,27 @@ void ContentSecurityPolicy::ApplyPolicySideEffectsToDelegate() {
delegate_->AddConsoleMessage(console_message);
console_messages_.clear();
- for (const auto& policy : policies_) {
- Count(GetUseCounterHelperType(policy->HeaderType()));
- if (policy->AllowDynamic(
- ContentSecurityPolicy::DirectiveType::kScriptSrcAttr) ||
- policy->AllowDynamic(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem)) {
+ // We disable 'eval()' even in the case of report-only policies, and rely on
+ // the check in the V8Initializer::codeGenerationCheckCallbackInMainThread
+ // callback to determine whether the call should execute or not.
+ if (!disable_eval_error_message_.IsNull())
+ delegate_->DisableEval(disable_eval_error_message_);
+}
+
+void ContentSecurityPolicy::ReportUseCounters(
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>& policies) {
+ for (const auto& policy : policies) {
+ Count(GetUseCounterHelperType(policy->header->type));
+ if (CSPDirectiveListAllowDynamic(*policy,
+ CSPDirectiveName::ScriptSrcAttr) ||
+ CSPDirectiveListAllowDynamic(*policy,
+ CSPDirectiveName::ScriptSrcElem)) {
Count(WebFeature::kCSPWithStrictDynamic);
}
- if (policy->AllowEval(ReportingDisposition::kSuppressReporting,
- kWillNotThrowException, g_empty_string)) {
+ if (CSPDirectiveListAllowEval(*policy, this,
+ ReportingDisposition::kSuppressReporting,
+ kWillNotThrowException, g_empty_string)) {
Count(WebFeature::kCSPWithUnsafeEval);
}
@@ -251,148 +240,149 @@ void ContentSecurityPolicy::ApplyPolicySideEffectsToDelegate() {
//
// https://chromium.googlesource.com/chromium/src/+/master/docs/security/web-mitigation-metrics.md
// has more detail.
- if (policy->IsObjectRestrictionReasonable()) {
- Count(policy->HeaderType() == ContentSecurityPolicyType::kEnforce
+ if (CSPDirectiveListIsObjectRestrictionReasonable(*policy)) {
+ Count(policy->header->type == ContentSecurityPolicyType::kEnforce
? WebFeature::kCSPWithReasonableObjectRestrictions
: WebFeature::kCSPROWithReasonableObjectRestrictions);
}
- if (policy->IsBaseRestrictionReasonable()) {
- Count(policy->HeaderType() == ContentSecurityPolicyType::kEnforce
+ if (CSPDirectiveListIsBaseRestrictionReasonable(*policy)) {
+ Count(policy->header->type == ContentSecurityPolicyType::kEnforce
? WebFeature::kCSPWithReasonableBaseRestrictions
: WebFeature::kCSPROWithReasonableBaseRestrictions);
}
- if (policy->IsScriptRestrictionReasonable()) {
- Count(policy->HeaderType() == ContentSecurityPolicyType::kEnforce
+ if (CSPDirectiveListIsScriptRestrictionReasonable(*policy)) {
+ Count(policy->header->type == ContentSecurityPolicyType::kEnforce
? WebFeature::kCSPWithReasonableScriptRestrictions
: WebFeature::kCSPROWithReasonableScriptRestrictions);
}
- if (policy->IsObjectRestrictionReasonable() &&
- policy->IsBaseRestrictionReasonable() &&
- policy->IsScriptRestrictionReasonable()) {
- Count(policy->HeaderType() == ContentSecurityPolicyType::kEnforce
+ if (CSPDirectiveListIsObjectRestrictionReasonable(*policy) &&
+ CSPDirectiveListIsBaseRestrictionReasonable(*policy) &&
+ CSPDirectiveListIsScriptRestrictionReasonable(*policy)) {
+ Count(policy->header->type == ContentSecurityPolicyType::kEnforce
? WebFeature::kCSPWithReasonableRestrictions
: WebFeature::kCSPROWithReasonableRestrictions);
- if (!policy->AllowDynamic(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem)) {
- Count(policy->HeaderType() == ContentSecurityPolicyType::kEnforce
+ if (!CSPDirectiveListAllowDynamic(*policy,
+ CSPDirectiveName::ScriptSrcElem)) {
+ Count(policy->header->type == ContentSecurityPolicyType::kEnforce
? WebFeature::kCSPWithBetterThanReasonableRestrictions
: WebFeature::kCSPROWithBetterThanReasonableRestrictions);
}
}
- if (policy->RequiresTrustedTypes()) {
- Count(policy->IsReportOnly() ? WebFeature::kTrustedTypesEnabledReportOnly
- : WebFeature::kTrustedTypesEnabledEnforcing);
+ if (CSPDirectiveListRequiresTrustedTypes(*policy)) {
+ Count(CSPDirectiveListIsReportOnly(*policy)
+ ? WebFeature::kTrustedTypesEnabledReportOnly
+ : WebFeature::kTrustedTypesEnabledEnforcing);
}
- if (policy->TrustedTypesAllowDuplicates()) {
+ if (policy->trusted_types && policy->trusted_types->allow_duplicates) {
Count(WebFeature::kTrustedTypesAllowDuplicates);
}
}
-
- // We disable 'eval()' even in the case of report-only policies, and rely on
- // the check in the V8Initializer::codeGenerationCheckCallbackInMainThread
- // callback to determine whether the call should execute or not.
- if (!disable_eval_error_message_.IsNull())
- delegate_->DisableEval(disable_eval_error_message_);
}
ContentSecurityPolicy::~ContentSecurityPolicy() = default;
void ContentSecurityPolicy::Trace(Visitor* visitor) const {
visitor->Trace(delegate_);
- visitor->Trace(policies_);
visitor->Trace(console_messages_);
- visitor->Trace(self_source_);
}
void ContentSecurityPolicy::CopyStateFrom(const ContentSecurityPolicy* other) {
DCHECK(policies_.IsEmpty());
- for (const auto& policy : other->policies_)
- AddAndReportPolicyFromHeaderValue(policy->Header(), policy->HeaderType(),
- policy->HeaderSource());
- SetupSelf(*other);
-}
-
-void ContentSecurityPolicy::CopyPluginTypesFrom(
- const ContentSecurityPolicy* other) {
- for (const auto& policy : other->policies_) {
- if (policy->HasPluginTypes()) {
- AddAndReportPolicyFromHeaderValue(policy->PluginTypesText(),
- policy->HeaderType(),
- policy->HeaderSource());
- }
- }
+ policies_ = mojo::Clone(other->policies_);
+ for (const auto& policy : policies_)
+ ComputeInternalStateForParsedPolicy(*policy);
+ if (delegate_)
+ ReportAccumulatedHeaders();
}
void ContentSecurityPolicy::DidReceiveHeaders(
const ContentSecurityPolicyResponseHeaders& headers) {
+ scoped_refptr<SecurityOrigin> self_origin =
+ SecurityOrigin::Create(headers.ResponseUrl());
if (headers.ShouldParseWasmEval())
supports_wasm_eval_ = true;
+
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> parsed_policies;
if (!headers.ContentSecurityPolicy().IsEmpty()) {
- AddAndReportPolicyFromHeaderValue(headers.ContentSecurityPolicy(),
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
+ parsed_policies = Parse(headers.ContentSecurityPolicy(), *self_origin,
+ ContentSecurityPolicyType::kEnforce,
+ ContentSecurityPolicySource::kHTTP);
}
if (!headers.ContentSecurityPolicyReportOnly().IsEmpty()) {
- AddAndReportPolicyFromHeaderValue(headers.ContentSecurityPolicyReportOnly(),
- ContentSecurityPolicyType::kReport,
- ContentSecurityPolicySource::kHTTP);
+ for (auto& policy : Parse(headers.ContentSecurityPolicyReportOnly(),
+ *self_origin, ContentSecurityPolicyType::kReport,
+ ContentSecurityPolicySource::kHTTP)) {
+ parsed_policies.push_back(std::move(policy));
+ }
}
+
+ AddPolicies(std::move(parsed_policies));
+}
+
+// static
+WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ContentSecurityPolicy::ParseHeaders(
+ const ContentSecurityPolicyResponseHeaders& headers) {
+ auto* content_security_policy = MakeGarbageCollected<ContentSecurityPolicy>();
+ content_security_policy->DidReceiveHeaders(headers);
+ return std::move(content_security_policy->policies_);
}
void ContentSecurityPolicy::DidReceiveHeader(
const String& header,
+ const SecurityOrigin& self_origin,
ContentSecurityPolicyType type,
ContentSecurityPolicySource source) {
- AddAndReportPolicyFromHeaderValue(header, type, source);
-
- // This might be called after we've been bound to a delegate. For example, a
- // <meta> element might be injected after page load.
- if (delegate_)
- ApplyPolicySideEffectsToDelegate();
+ AddPolicies(Parse(header, self_origin, type, source));
}
-bool ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- const ResourceResponse& response,
- const SecurityOrigin* parent_origin) {
- if (response.CurrentRequestUrl().IsEmpty() ||
- response.CurrentRequestUrl().ProtocolIsAbout() ||
- response.CurrentRequestUrl().ProtocolIsData() ||
- response.CurrentRequestUrl().ProtocolIs("blob") ||
- response.CurrentRequestUrl().ProtocolIs("filesystem")) {
- return true;
+void ContentSecurityPolicy::AddPolicies(
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies) {
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies_to_report;
+ if (delegate_) {
+ policies_to_report = mojo::Clone(policies);
}
- if (parent_origin->CanAccess(
- SecurityOrigin::Create(response.CurrentRequestUrl()).get()))
- return true;
-
- String header = response.HttpHeaderField(http_names::kAllowCSPFrom);
- header = header.StripWhiteSpace();
- if (header == "*")
- return true;
- if (scoped_refptr<const SecurityOrigin> child_origin =
- SecurityOrigin::CreateFromString(header)) {
- return parent_origin->CanAccess(child_origin.get());
+ for (network::mojom::blink::ContentSecurityPolicyPtr& policy : policies) {
+ ComputeInternalStateForParsedPolicy(*policy);
+ policies_.push_back(std::move(policy));
}
- return false;
+ // If this ContentSecurityPolicy is not bound to a delegate yet, return. The
+ // following logic will be executed in BindToDelegate when that will happen.
+ if (!delegate_)
+ return;
+
+ ApplyPolicySideEffectsToDelegate();
+ ReportUseCounters(policies_to_report);
+
+ // Notify about the new header, so that it can be reported back to the
+ // browser process. This is needed in order to:
+ // 1) replicate CSP directives (i.e. frame-src) to OOPIFs (only for now /
+ // short-term).
+ // 2) enforce CSP in the browser process (long-term - see
+ // https://crbug.com/376522).
+ // TODO(arthursonzogni): policies are actually replicated (1) and some of
+ // them are enforced on the browser process (2). Stop doing (1) when (2) is
+ // finished.
+ delegate_->DidAddContentSecurityPolicies(std::move(policies_to_report));
}
-void ContentSecurityPolicy::AddPolicyFromHeaderValue(
- const String& header,
- ContentSecurityPolicyType type,
- ContentSecurityPolicySource source) {
+Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ContentSecurityPolicy::Parse(const String& header,
+ const SecurityOrigin& self_origin,
+ ContentSecurityPolicyType type,
+ ContentSecurityPolicySource source) {
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies;
+
// If this is a report-only header inside a <meta> element, bail out.
if (source == ContentSecurityPolicySource::kMeta &&
type == ContentSecurityPolicyType::kReport) {
ReportReportOnlyInMeta(header);
- return;
+ return policies;
}
- if (source == ContentSecurityPolicySource::kHTTP)
- header_delivered_ = true;
-
Vector<UChar> characters;
header.AppendTo(characters);
@@ -408,98 +398,88 @@ void ContentSecurityPolicy::AddPolicyFromHeaderValue(
// header1,header2 OR header1
// ^ ^
- Member<CSPDirectiveList> policy =
- CSPDirectiveList::Create(this, begin, position, type, source);
-
- if (policy->ShouldDisableEval() && disable_eval_error_message_.IsNull()) {
- disable_eval_error_message_ = policy->EvalDisabledErrorMessage();
- }
-
- policies_.push_back(policy.Release());
+ policies.push_back(CSPDirectiveListParse(this, begin, position, self_origin,
+ type, source));
// Skip the comma, and begin the next header from the current position.
DCHECK(position == end || *position == ',');
SkipExactly<UChar>(position, end, ',');
begin = position;
}
+ return policies;
}
-void ContentSecurityPolicy::ReportAccumulatedHeaders() const {
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies;
- for (const auto& policy : policies_)
- policies.push_back(policy->ExposeForNavigationalChecks());
+void ContentSecurityPolicy::ComputeInternalStateForParsedPolicy(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ if (csp.header->source == ContentSecurityPolicySource::kHTTP)
+ header_delivered_ = true;
- DCHECK(delegate_);
- delegate_->DidAddContentSecurityPolicies(std::move(policies));
-}
+ if (csp.block_all_mixed_content && !CSPDirectiveListIsReportOnly(csp))
+ EnforceStrictMixedContentChecking();
-void ContentSecurityPolicy::AddAndReportPolicyFromHeaderValue(
- const String& header,
- ContentSecurityPolicyType type,
- ContentSecurityPolicySource source) {
- wtf_size_t previous_policy_count = policies_.size();
- AddPolicyFromHeaderValue(header, type, source);
- // Notify about the new header, so that it can be reported back to the
- // browser process. This is needed in order to:
- // 1) replicate CSP directives (i.e. frame-src) to OOPIFs (only for now /
- // short-term).
- // 2) enforce CSP in the browser process (long-term - see
- // https://crbug.com/376522).
- // TODO(arthursonzogni): policies are actually replicated (1) and some of
- // them are enforced on the browser process (2). Stop doing (1) when (2) is
- // finished.
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies(
- policies_.size() - previous_policy_count);
- for (wtf_size_t i = previous_policy_count; i < policies_.size(); ++i) {
- policies[i - previous_policy_count] =
- policies_[i]->ExposeForNavigationalChecks();
- }
+ if (CSPDirectiveListRequiresTrustedTypes(csp))
+ RequireTrustedTypes();
- if (delegate_)
- delegate_->DidAddContentSecurityPolicies(std::move(policies));
-}
+ EnforceSandboxFlags(csp.sandbox);
-void ContentSecurityPolicy::SetOverrideAllowInlineStyle(bool value) {
- override_inline_style_allowed_ = value;
+ if (csp.upgrade_insecure_requests)
+ UpgradeInsecureRequests();
+
+ String disable_eval_message;
+ if (CSPDirectiveListShouldDisableEval(csp, disable_eval_message) &&
+ disable_eval_error_message_.IsNull()) {
+ disable_eval_error_message_ = disable_eval_message;
+ }
+
+ for (const auto& directive : csp.directives) {
+ switch (directive.key) {
+ case CSPDirectiveName::DefaultSrc:
+ // TODO(mkwst) It seems unlikely that developers would use different
+ // algorithms for scripts and styles. We may want to combine the
+ // usesScriptHashAlgorithms() and usesStyleHashAlgorithms.
+ UsesScriptHashAlgorithms(HashAlgorithmsUsed(directive.value.get()));
+ UsesStyleHashAlgorithms(HashAlgorithmsUsed(directive.value.get()));
+ break;
+ case CSPDirectiveName::ScriptSrc:
+ case CSPDirectiveName::ScriptSrcAttr:
+ case CSPDirectiveName::ScriptSrcElem:
+ UsesScriptHashAlgorithms(HashAlgorithmsUsed(directive.value.get()));
+ break;
+ case CSPDirectiveName::StyleSrc:
+ case CSPDirectiveName::StyleSrcAttr:
+ case CSPDirectiveName::StyleSrcElem:
+ UsesStyleHashAlgorithms(HashAlgorithmsUsed(directive.value.get()));
+ break;
+ default:
+ break;
+ }
+ }
}
-void ContentSecurityPolicy::SetOverrideURLForSelf(const KURL& url) {
- // Create a temporary CSPSource so that 'self' expressions can be resolved
- // before we bind to an execution context (for 'frame-ancestor' resolution,
- // for example). This CSPSource will be overwritten when we bind this object
- // to an execution context.
- scoped_refptr<const SecurityOrigin> origin = SecurityOrigin::Create(url);
- self_protocol_ = origin->Protocol();
- self_source_ = MakeGarbageCollected<CSPSource>(
- this, self_protocol_, origin->Host(), origin->Port(), String(),
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+void ContentSecurityPolicy::ReportAccumulatedHeaders() const {
+ DCHECK(delegate_);
+ delegate_->DidAddContentSecurityPolicies(mojo::Clone(GetParsedPolicies()));
}
-Vector<CSPHeaderAndType> ContentSecurityPolicy::Headers() const {
- Vector<CSPHeaderAndType> headers;
- headers.ReserveInitialCapacity(policies_.size());
- for (const auto& policy : policies_) {
- headers.UncheckedAppend(
- CSPHeaderAndType(policy->Header(), policy->HeaderType()));
- }
- return headers;
+void ContentSecurityPolicy::SetOverrideAllowInlineStyle(bool value) {
+ override_inline_style_allowed_ = value;
}
// static
void ContentSecurityPolicy::FillInCSPHashValues(
const String& source,
uint8_t hash_algorithms_used,
- Vector<CSPHashValue>* csp_hash_values) {
+ Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values) {
// Any additions or subtractions from this struct should also modify the
// respective entries in the kSupportedPrefixes array in
// SourceListDirective::parseHash().
static const struct {
- ContentSecurityPolicyHashAlgorithm csp_hash_algorithm;
+ network::mojom::blink::CSPHashAlgorithm csp_hash_algorithm;
HashAlgorithm algorithm;
} kAlgorithmMap[] = {
- {kContentSecurityPolicyHashAlgorithmSha256, kHashAlgorithmSha256},
- {kContentSecurityPolicyHashAlgorithmSha384, kHashAlgorithmSha384},
- {kContentSecurityPolicyHashAlgorithmSha512, kHashAlgorithmSha512}};
+ {network::mojom::blink::CSPHashAlgorithm::SHA256, kHashAlgorithmSha256},
+ {network::mojom::blink::CSPHashAlgorithm::SHA384, kHashAlgorithmSha384},
+ {network::mojom::blink::CSPHashAlgorithm::SHA512, kHashAlgorithmSha512}};
// Only bother normalizing the source/computing digests if there are any
// checks to be done.
@@ -511,13 +491,14 @@ void ContentSecurityPolicy::FillInCSPHashValues(
for (const auto& algorithm_map : kAlgorithmMap) {
DigestValue digest;
- if (algorithm_map.csp_hash_algorithm & hash_algorithms_used) {
+ if (static_cast<int32_t>(algorithm_map.csp_hash_algorithm) &
+ hash_algorithms_used) {
bool digest_success =
ComputeDigest(algorithm_map.algorithm, utf8_source.data(),
utf8_source.size(), digest);
if (digest_success) {
- csp_hash_values->push_back(
- CSPHashValue(algorithm_map.csp_hash_algorithm, digest));
+ csp_hash_values.push_back(network::mojom::blink::CSPHashSource::New(
+ algorithm_map.csp_hash_algorithm, Vector<uint8_t>(digest)));
}
}
}
@@ -525,11 +506,11 @@ void ContentSecurityPolicy::FillInCSPHashValues(
// static
bool ContentSecurityPolicy::CheckHashAgainstPolicy(
- Vector<CSPHashValue>& csp_hash_values,
- const Member<CSPDirectiveList>& policy,
+ Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values,
+ const network::mojom::blink::ContentSecurityPolicy& csp,
InlineType inline_type) {
for (const auto& csp_hash_value : csp_hash_values) {
- if (policy->AllowHash(csp_hash_value, inline_type))
+ if (CSPDirectiveListAllowHash(csp, *csp_hash_value, inline_type))
return true;
}
return false;
@@ -543,7 +524,7 @@ bool ContentSecurityPolicy::AllowInline(
const String& nonce,
const String& context_url,
const WTF::OrdinalNumber& context_line,
- ReportingDisposition reporting_disposition) const {
+ ReportingDisposition reporting_disposition) {
DCHECK(element || inline_type == InlineType::kScriptAttribute ||
inline_type == InlineType::kNavigation);
@@ -552,11 +533,11 @@ bool ContentSecurityPolicy::AllowInline(
return true;
}
- Vector<CSPHashValue> csp_hash_values;
+ Vector<network::mojom::blink::CSPHashSourcePtr> csp_hash_values;
FillInCSPHashValues(
content,
is_script ? script_hash_algorithms_used_ : style_hash_algorithms_used_,
- &csp_hash_values);
+ csp_hash_values);
// Step 2. Let result be "Allowed". [spec text]
bool is_allowed = true;
@@ -568,9 +549,10 @@ bool ContentSecurityPolicy::AllowInline(
// Check against the digest of the |content| and also check whether inline
// script is allowed.
is_allowed &=
- CheckHashAgainstPolicy(csp_hash_values, policy, inline_type) ||
- policy->AllowInline(inline_type, element, content, nonce, context_url,
- context_line, reporting_disposition);
+ CheckHashAgainstPolicy(csp_hash_values, *policy, inline_type) ||
+ CSPDirectiveListAllowInline(*policy, this, inline_type, element,
+ content, nonce, context_url, context_line,
+ reporting_disposition);
}
return is_allowed;
@@ -591,7 +573,7 @@ bool ContentSecurityPolicy::IsScriptInlineType(InlineType inline_type) {
bool ContentSecurityPolicy::ShouldCheckEval() const {
for (const auto& policy : policies_) {
- if (policy->ShouldCheckEval())
+ if (CSPDirectiveListShouldCheckEval(*policy))
return true;
}
return IsRequireTrustedTypes();
@@ -600,11 +582,11 @@ bool ContentSecurityPolicy::ShouldCheckEval() const {
bool ContentSecurityPolicy::AllowEval(
ReportingDisposition reporting_disposition,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& script_content) const {
+ const String& script_content) {
bool is_allowed = true;
for (const auto& policy : policies_) {
- is_allowed &= policy->AllowEval(reporting_disposition, exception_status,
- script_content);
+ is_allowed &= CSPDirectiveListAllowEval(
+ *policy, this, reporting_disposition, exception_status, script_content);
}
return is_allowed;
}
@@ -612,44 +594,31 @@ bool ContentSecurityPolicy::AllowEval(
bool ContentSecurityPolicy::AllowWasmEval(
ReportingDisposition reporting_disposition,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& script_content) const {
+ const String& script_content) {
bool is_allowed = true;
for (const auto& policy : policies_) {
- is_allowed &= policy->AllowWasmEval(reporting_disposition, exception_status,
- script_content);
+ is_allowed &= CSPDirectiveListAllowWasmEval(
+ *policy, this, reporting_disposition, exception_status, script_content);
}
return is_allowed;
}
String ContentSecurityPolicy::EvalDisabledErrorMessage() const {
for (const auto& policy : policies_) {
- if (policy->ShouldDisableEval())
- return policy->EvalDisabledErrorMessage();
+ String message;
+ if (CSPDirectiveListShouldDisableEval(*policy, message))
+ return message;
}
return String();
}
-bool ContentSecurityPolicy::AllowPluginType(
- const String& type,
- const String& type_attribute,
- const KURL& url,
- ReportingDisposition reporting_disposition) const {
- for (const auto& policy : policies_) {
- if (!policy->AllowPluginType(type, type_attribute, url,
- reporting_disposition))
- return false;
- }
- return true;
-}
-
-static base::Optional<ContentSecurityPolicy::DirectiveType>
-GetDirectiveTypeFromRequestContextType(
+static base::Optional<CSPDirectiveName> GetDirectiveTypeFromRequestContextType(
mojom::blink::RequestContextType context) {
switch (context) {
case mojom::blink::RequestContextType::AUDIO:
case mojom::blink::RequestContextType::TRACK:
case mojom::blink::RequestContextType::VIDEO:
- return ContentSecurityPolicy::DirectiveType::kMediaSrc;
+ return CSPDirectiveName::MediaSrc;
case mojom::blink::RequestContextType::BEACON:
case mojom::blink::RequestContextType::EVENT_SOURCE:
@@ -657,45 +626,46 @@ GetDirectiveTypeFromRequestContextType(
case mojom::blink::RequestContextType::PING:
case mojom::blink::RequestContextType::XML_HTTP_REQUEST:
case mojom::blink::RequestContextType::SUBRESOURCE:
- return ContentSecurityPolicy::DirectiveType::kConnectSrc;
+ case mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE:
+ return CSPDirectiveName::ConnectSrc;
case mojom::blink::RequestContextType::EMBED:
case mojom::blink::RequestContextType::OBJECT:
- return ContentSecurityPolicy::DirectiveType::kObjectSrc;
+ return CSPDirectiveName::ObjectSrc;
case mojom::blink::RequestContextType::PREFETCH:
- return ContentSecurityPolicy::DirectiveType::kPrefetchSrc;
+ return CSPDirectiveName::PrefetchSrc;
case mojom::blink::RequestContextType::FAVICON:
case mojom::blink::RequestContextType::IMAGE:
case mojom::blink::RequestContextType::IMAGE_SET:
- return ContentSecurityPolicy::DirectiveType::kImgSrc;
+ return CSPDirectiveName::ImgSrc;
case mojom::blink::RequestContextType::FONT:
- return ContentSecurityPolicy::DirectiveType::kFontSrc;
+ return CSPDirectiveName::FontSrc;
case mojom::blink::RequestContextType::FORM:
- return ContentSecurityPolicy::DirectiveType::kFormAction;
+ return CSPDirectiveName::FormAction;
case mojom::blink::RequestContextType::FRAME:
case mojom::blink::RequestContextType::IFRAME:
- return ContentSecurityPolicy::DirectiveType::kFrameSrc;
+ return CSPDirectiveName::FrameSrc;
case mojom::blink::RequestContextType::IMPORT:
case mojom::blink::RequestContextType::SCRIPT:
case mojom::blink::RequestContextType::XSLT:
- return ContentSecurityPolicy::DirectiveType::kScriptSrcElem;
+ return CSPDirectiveName::ScriptSrcElem;
case mojom::blink::RequestContextType::MANIFEST:
- return ContentSecurityPolicy::DirectiveType::kManifestSrc;
+ return CSPDirectiveName::ManifestSrc;
case mojom::blink::RequestContextType::SERVICE_WORKER:
case mojom::blink::RequestContextType::SHARED_WORKER:
case mojom::blink::RequestContextType::WORKER:
- return ContentSecurityPolicy::DirectiveType::kWorkerSrc;
+ return CSPDirectiveName::WorkerSrc;
case mojom::blink::RequestContextType::STYLE:
- return ContentSecurityPolicy::DirectiveType::kStyleSrcElem;
+ return CSPDirectiveName::StyleSrcElem;
case mojom::blink::RequestContextType::CSP_REPORT:
case mojom::blink::RequestContextType::DOWNLOAD:
@@ -718,8 +688,8 @@ bool ContentSecurityPolicy::AllowRequest(
const KURL& url_before_redirects,
RedirectStatus redirect_status,
ReportingDisposition reporting_disposition,
- CheckHeaderType check_header_type) const {
- base::Optional<ContentSecurityPolicy::DirectiveType> type =
+ CheckHeaderType check_header_type) {
+ base::Optional<CSPDirectiveName> type =
GetDirectiveTypeFromRequestContextType(context);
if (!type)
@@ -738,7 +708,7 @@ void ContentSecurityPolicy::UsesStyleHashAlgorithms(uint8_t algorithms) {
}
bool ContentSecurityPolicy::AllowFromSource(
- ContentSecurityPolicy::DirectiveType type,
+ CSPDirectiveName type,
const KURL& url,
const KURL& url_before_redirects,
RedirectStatus redirect_status,
@@ -746,15 +716,15 @@ bool ContentSecurityPolicy::AllowFromSource(
CheckHeaderType check_header_type,
const String& nonce,
const IntegrityMetadataSet& hashes,
- ParserDisposition parser_disposition) const {
+ ParserDisposition parser_disposition) {
SchemeRegistry::PolicyAreas area = SchemeRegistry::kPolicyAreaAll;
- if (type == ContentSecurityPolicy::DirectiveType::kImgSrc)
+ if (type == CSPDirectiveName::ImgSrc)
area = SchemeRegistry::kPolicyAreaImage;
- else if (type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem)
+ else if (type == CSPDirectiveName::StyleSrcElem)
area = SchemeRegistry::kPolicyAreaStyle;
if (ShouldBypassContentSecurityPolicy(url, area)) {
- if (type != ContentSecurityPolicy::DirectiveType::kScriptSrcElem)
+ if (type != CSPDirectiveName::ScriptSrcElem)
return true;
Count(parser_disposition == kParserInserted
@@ -779,22 +749,22 @@ bool ContentSecurityPolicy::AllowFromSource(
bool is_allowed = true;
for (const auto& policy : policies_) {
- if (!CheckHeaderTypeMatches(check_header_type, policy->HeaderType()))
+ if (!CheckHeaderTypeMatches(check_header_type, policy->header->type))
continue;
- is_allowed &= policy->AllowFromSource(
- type, url, url_before_redirects, redirect_status, reporting_disposition,
- nonce, hashes, parser_disposition);
+ is_allowed &= CSPDirectiveListAllowFromSource(
+ *policy, this, type, url, url_before_redirects, redirect_status,
+ reporting_disposition, nonce, hashes, parser_disposition);
}
return is_allowed;
}
-bool ContentSecurityPolicy::AllowBaseURI(const KURL& url) const {
+bool ContentSecurityPolicy::AllowBaseURI(const KURL& url) {
// `base-uri` isn't affected by 'upgrade-insecure-requests', so we use
// CheckHeaderType::kCheckAll to check both report-only and enforce headers
// here.
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kBaseURI, url,
- url, RedirectStatus::kNoRedirect);
+ return AllowFromSource(CSPDirectiveName::BaseURI, url, url,
+ RedirectStatus::kNoRedirect);
}
bool ContentSecurityPolicy::AllowConnectToSource(
@@ -802,15 +772,15 @@ bool ContentSecurityPolicy::AllowConnectToSource(
const KURL& url_before_redirects,
RedirectStatus redirect_status,
ReportingDisposition reporting_disposition,
- CheckHeaderType check_header_type) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kConnectSrc, url,
+ CheckHeaderType check_header_type) {
+ return AllowFromSource(CSPDirectiveName::ConnectSrc, url,
url_before_redirects, redirect_status,
reporting_disposition, check_header_type);
}
-bool ContentSecurityPolicy::AllowFormAction(const KURL& url) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kFormAction, url,
- url, RedirectStatus::kNoRedirect);
+bool ContentSecurityPolicy::AllowFormAction(const KURL& url) {
+ return AllowFromSource(CSPDirectiveName::FormAction, url, url,
+ RedirectStatus::kNoRedirect);
}
bool ContentSecurityPolicy::AllowImageFromSource(
@@ -818,20 +788,20 @@ bool ContentSecurityPolicy::AllowImageFromSource(
const KURL& url_before_redirects,
RedirectStatus redirect_status,
ReportingDisposition reporting_disposition,
- CheckHeaderType check_header_type) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kImgSrc, url,
- url_before_redirects, redirect_status,
- reporting_disposition, check_header_type);
+ CheckHeaderType check_header_type) {
+ return AllowFromSource(CSPDirectiveName::ImgSrc, url, url_before_redirects,
+ redirect_status, reporting_disposition,
+ check_header_type);
}
-bool ContentSecurityPolicy::AllowMediaFromSource(const KURL& url) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kMediaSrc, url,
- url, RedirectStatus::kNoRedirect);
+bool ContentSecurityPolicy::AllowMediaFromSource(const KURL& url) {
+ return AllowFromSource(CSPDirectiveName::MediaSrc, url, url,
+ RedirectStatus::kNoRedirect);
}
-bool ContentSecurityPolicy::AllowObjectFromSource(const KURL& url) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kObjectSrc, url,
- url, RedirectStatus::kNoRedirect);
+bool ContentSecurityPolicy::AllowObjectFromSource(const KURL& url) {
+ return AllowFromSource(CSPDirectiveName::ObjectSrc, url, url,
+ RedirectStatus::kNoRedirect);
}
bool ContentSecurityPolicy::AllowScriptFromSource(
@@ -842,28 +812,43 @@ bool ContentSecurityPolicy::AllowScriptFromSource(
const KURL& url_before_redirects,
RedirectStatus redirect_status,
ReportingDisposition reporting_disposition,
- CheckHeaderType check_header_type) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- url, url_before_redirects, redirect_status,
+ CheckHeaderType check_header_type) {
+ return AllowFromSource(CSPDirectiveName::ScriptSrcElem, url,
+ url_before_redirects, redirect_status,
reporting_disposition, check_header_type, nonce,
hashes, parser_disposition);
}
-bool ContentSecurityPolicy::AllowWorkerContextFromSource(
- const KURL& url) const {
- return AllowFromSource(ContentSecurityPolicy::DirectiveType::kWorkerSrc, url,
- url, RedirectStatus::kNoRedirect);
+bool ContentSecurityPolicy::AllowWorkerContextFromSource(const KURL& url) {
+ return AllowFromSource(CSPDirectiveName::WorkerSrc, url, url,
+ RedirectStatus::kNoRedirect);
}
-bool ContentSecurityPolicy::AllowTrustedTypePolicy(const String& policy_name,
- bool is_duplicate) const {
+// The return value indicates whether the policy is allowed or not.
+// If the return value is false, the out-parameter violation_details indicates
+// the type of the violation, and if the return value is true,
+// it indicates if a report-only violation occurred.
+bool ContentSecurityPolicy::AllowTrustedTypePolicy(
+ const String& policy_name,
+ bool is_duplicate,
+ AllowTrustedTypePolicyDetails& violation_details) {
bool is_allowed = true;
+ violation_details = AllowTrustedTypePolicyDetails::kAllowed;
for (const auto& policy : policies_) {
if (!CheckHeaderTypeMatches(CheckHeaderType::kCheckAll,
- policy->HeaderType())) {
+ policy->header->type)) {
continue;
}
- is_allowed &= policy->AllowTrustedTypePolicy(policy_name, is_duplicate);
+ auto new_violation_details = AllowTrustedTypePolicyDetails::kAllowed;
+ bool new_allowed = CSPDirectiveListAllowTrustedTypePolicy(
+ *policy, this, policy_name, is_duplicate, new_violation_details);
+ // Report the first violation that is enforced.
+ // If there is none, report the first violation that is report-only.
+ if ((is_allowed && !new_allowed) ||
+ violation_details == AllowTrustedTypePolicyDetails::kAllowed) {
+ violation_details = new_violation_details;
+ }
+ is_allowed &= new_allowed;
}
return is_allowed;
@@ -872,11 +857,11 @@ bool ContentSecurityPolicy::AllowTrustedTypePolicy(const String& policy_name,
bool ContentSecurityPolicy::AllowTrustedTypeAssignmentFailure(
const String& message,
const String& sample,
- const String& sample_prefix) const {
+ const String& sample_prefix) {
bool allow = true;
for (const auto& policy : policies_) {
- allow &= policy->AllowTrustedTypeAssignmentFailure(message, sample,
- sample_prefix);
+ allow &= CSPDirectiveListAllowTrustedTypeAssignmentFailure(
+ *policy, this, message, sample, sample_prefix);
}
return allow;
}
@@ -887,7 +872,7 @@ bool ContentSecurityPolicy::IsActive() const {
bool ContentSecurityPolicy::IsActiveForConnections() const {
for (const auto& policy : policies_) {
- if (policy->IsActiveForConnections())
+ if (CSPDirectiveListIsActiveForConnections(*policy))
return true;
}
return false;
@@ -918,11 +903,10 @@ void ContentSecurityPolicy::UpgradeInsecureRequests() {
mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests;
}
-static String StripURLForUseInReport(
- const SecurityOrigin* security_origin,
- const KURL& url,
- RedirectStatus redirect_status,
- const ContentSecurityPolicy::DirectiveType& effective_type) {
+static String StripURLForUseInReport(const SecurityOrigin* security_origin,
+ const KURL& url,
+ RedirectStatus redirect_status,
+ CSPDirectiveName effective_type) {
if (!url.IsValid())
return String();
if (!url.IsHierarchical() || url.ProtocolIs("file"))
@@ -934,8 +918,8 @@ static String StripURLForUseInReport(
bool can_safely_expose_url =
security_origin->CanRequest(url) ||
(redirect_status == RedirectStatus::kNoRedirect &&
- effective_type != ContentSecurityPolicy::DirectiveType::kFrameSrc &&
- effective_type != ContentSecurityPolicy::DirectiveType::kObjectSrc);
+ effective_type != CSPDirectiveName::FrameSrc &&
+ effective_type != CSPDirectiveName::ObjectSrc);
if (can_safely_expose_url) {
// 'KURL::strippedForUseAsReferrer()' dumps 'String()' for non-webby URLs.
@@ -947,11 +931,12 @@ static String StripURLForUseInReport(
return SecurityOrigin::Create(url)->ToString();
}
-static void GatherSecurityPolicyViolationEventData(
+namespace {
+std::unique_ptr<SourceLocation> GatherSecurityPolicyViolationEventData(
SecurityPolicyViolationEventInit* init,
ContentSecurityPolicyDelegate* delegate,
const String& directive_text,
- const ContentSecurityPolicy::DirectiveType& effective_type,
+ CSPDirectiveName effective_type,
const KURL& blocked_url,
const String& header,
RedirectStatus redirect_status,
@@ -960,20 +945,19 @@ static void GatherSecurityPolicyViolationEventData(
std::unique_ptr<SourceLocation> source_location,
const String& script_source,
const String& sample_prefix) {
- if (effective_type == ContentSecurityPolicy::DirectiveType::kFrameAncestors) {
+ if (effective_type == CSPDirectiveName::FrameAncestors) {
// If this load was blocked via 'frame-ancestors', then the URL of
// |document| has not yet been initialized. In this case, we'll set both
// 'documentURI' and 'blockedURI' to the blocked document's URL.
String stripped_url = StripURLForUseInReport(
delegate->GetSecurityOrigin(), blocked_url, RedirectStatus::kNoRedirect,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc);
+ CSPDirectiveName::DefaultSrc);
init->setDocumentURI(stripped_url);
init->setBlockedURI(stripped_url);
} else {
String stripped_url = StripURLForUseInReport(
delegate->GetSecurityOrigin(), delegate->Url(),
- RedirectStatus::kNoRedirect,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc);
+ RedirectStatus::kNoRedirect, CSPDirectiveName::DefaultSrc);
init->setDocumentURI(stripped_url);
switch (violation_type) {
case ContentSecurityPolicy::kInlineViolation:
@@ -1077,11 +1061,14 @@ static void GatherSecurityPolicyViolationEventData(
}
if (!sample.IsEmpty())
init->setSample(sample.ToString());
+
+ return source_location;
}
+} // namespace
void ContentSecurityPolicy::ReportViolation(
const String& directive_text,
- const DirectiveType& effective_type,
+ CSPDirectiveName effective_type,
const String& console_message,
const KURL& blocked_url,
const Vector<String>& report_endpoints,
@@ -1101,15 +1088,15 @@ void ContentSecurityPolicy::ReportViolation(
// https://crbug.com/611232 (or move CSP child-src and frame-src checks to the
// browser process - see https://crbug.com/376522).
if (!delegate_ && !context_frame) {
- DCHECK(effective_type == DirectiveType::kChildSrc ||
- effective_type == DirectiveType::kFrameSrc ||
- effective_type == DirectiveType::kPluginTypes ||
- effective_type == DirectiveType::kTrustedTypes ||
- effective_type == DirectiveType::kRequireTrustedTypesFor);
+ DCHECK(effective_type == CSPDirectiveName::ChildSrc ||
+ effective_type == CSPDirectiveName::FrameSrc ||
+ effective_type == CSPDirectiveName::TrustedTypes ||
+ effective_type == CSPDirectiveName::RequireTrustedTypesFor);
return;
}
- DCHECK((delegate_ && !context_frame) ||
- ((effective_type == DirectiveType::kFrameAncestors) && context_frame));
+ DCHECK(
+ (delegate_ && !context_frame) ||
+ ((effective_type == CSPDirectiveName::FrameAncestors) && context_frame));
SecurityPolicyViolationEventInit* violation_data =
SecurityPolicyViolationEventInit::Create();
@@ -1122,7 +1109,9 @@ void ContentSecurityPolicy::ReportViolation(
? &context_frame->DomWindow()->GetContentSecurityPolicyDelegate()
: delegate_.Get();
DCHECK(relevant_delegate);
- GatherSecurityPolicyViolationEventData(
+ // Let GatherSecurityPolicyViolationEventData decide which source location to
+ // report.
+ source_location = GatherSecurityPolicyViolationEventData(
violation_data, relevant_delegate, directive_text, effective_type,
blocked_url, header, redirect_status, header_type, violation_type,
std::move(source_location), source, source_prefix);
@@ -1145,7 +1134,8 @@ void ContentSecurityPolicy::ReportViolation(
delegate_->DispatchViolationEvent(*violation_data, element);
ReportContentSecurityPolicyIssue(*violation_data, header_type, violation_type,
- context_frame, element);
+ context_frame, element,
+ source_location.get());
}
void ContentSecurityPolicy::PostViolationReport(
@@ -1213,11 +1203,20 @@ void ContentSecurityPolicy::PostViolationReport(
}
}
-void ContentSecurityPolicy::ReportMixedContent(
- const KURL& blocked_url,
- RedirectStatus redirect_status) const {
- for (const auto& policy : policies_)
- policy->ReportMixedContent(blocked_url, redirect_status);
+void ContentSecurityPolicy::ReportMixedContent(const KURL& blocked_url,
+ RedirectStatus redirect_status) {
+ for (const auto& policy : policies_) {
+ if (policy->block_all_mixed_content) {
+ ReportViolation(GetDirectiveName(CSPDirectiveName::BlockAllMixedContent),
+ CSPDirectiveName::BlockAllMixedContent, String(),
+ blocked_url, policy->report_endpoints,
+ policy->use_reporting_api, policy->header->header_value,
+ policy->header->type,
+ ContentSecurityPolicy::kURLViolation,
+ std::unique_ptr<SourceLocation>(),
+ /*contextFrame=*/nullptr, redirect_status);
+ }
+ }
}
void ContentSecurityPolicy::ReportReportOnlyInMeta(const String& header) {
@@ -1265,6 +1264,7 @@ void ContentSecurityPolicy::ReportUnsupportedDirective(const String& name) {
static const char kAllow[] = "allow";
static const char kOptions[] = "options";
static const char kPolicyURI[] = "policy-uri";
+ static const char kPluginTypes[] = "plugin-types";
static const char kAllowMessage[] =
"The 'allow' directive has been replaced with 'default-src'. Please use "
"that directive instead, as 'allow' has no effect.";
@@ -1277,6 +1277,11 @@ void ContentSecurityPolicy::ReportUnsupportedDirective(const String& name) {
"The 'policy-uri' directive has been removed from the "
"specification. Please specify a complete policy via "
"the Content-Security-Policy header.";
+ static const char kPluginTypesMessage[] =
+ "The Content-Security-Policy directive 'plugin-types' has been removed "
+ "from the specification. "
+ "If you want to block plugins, consider specifying \"object-src 'none'\" "
+ "instead.";
String message =
"Unrecognized Content-Security-Policy directive '" + name + "'.\n";
@@ -1287,7 +1292,9 @@ void ContentSecurityPolicy::ReportUnsupportedDirective(const String& name) {
message = kOptionsMessage;
} else if (EqualIgnoringASCIICase(name, kPolicyURI)) {
message = kPolicyURIMessage;
- } else if (GetDirectiveType(name) != DirectiveType::kUndefined) {
+ } else if (EqualIgnoringASCIICase(name, kPluginTypes)) {
+ message = kPluginTypesMessage;
+ } else if (GetDirectiveType(name) != CSPDirectiveName::Unknown) {
message = "The Content-Security-Policy directive '" + name +
"' is implemented behind a flag which is currently disabled.\n";
level = mojom::ConsoleMessageLevel::kInfo;
@@ -1312,25 +1319,27 @@ void ContentSecurityPolicy::ReportDuplicateDirective(const String& name) {
LogToConsole(message);
}
-void ContentSecurityPolicy::ReportInvalidPluginTypes(
- const String& plugin_type) {
+void ContentSecurityPolicy::ReportInvalidRequireTrustedTypesFor(
+ const String& require_trusted_types_for) {
String message;
- if (plugin_type.IsNull())
- message =
- "'plugin-types' Content Security Policy directive is empty; all "
- "plugins will be blocked.\n";
- else if (plugin_type == "'none'")
+ if (require_trusted_types_for.IsNull()) {
message =
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: '" +
- plugin_type +
- "'. Did you mean to set the object-src directive to 'none'?\n";
- else
+ "'require-trusted-types-for' Content Security Policy directive is "
+ "empty; The directive has no effect.\n";
+ } else {
+ const char* hint = "";
+ if (require_trusted_types_for == "script" ||
+ require_trusted_types_for == "scripts" ||
+ require_trusted_types_for == "'scripts'") {
+ hint = " Did you mean 'script'?";
+ }
+
message =
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: '" +
- plugin_type + "'.\n";
- LogToConsole(message);
+ "Invalid expression in 'require-trusted-types-for' "
+ "Content Security Policy directive: " +
+ require_trusted_types_for + "." + hint + "\n";
+ }
+ LogToConsole(message, mojom::ConsoleMessageLevel::kWarning);
}
void ContentSecurityPolicy::ReportInvalidSandboxFlags(
@@ -1343,12 +1352,14 @@ void ContentSecurityPolicy::ReportInvalidSandboxFlags(
void ContentSecurityPolicy::ReportInvalidDirectiveValueCharacter(
const String& directive_name,
const String& value) {
- String message = "The value for Content Security Policy directive '" +
- directive_name + "' contains an invalid character: '" +
- value +
- "'. Non-whitespace characters outside ASCII 0x21-0x7E must "
- "be percent-encoded, as described in RFC 3986, section 2.1: "
- "http://tools.ietf.org/html/rfc3986#section-2.1.";
+ String message =
+ "The value for Content Security Policy directive '" + directive_name +
+ "' contains an invalid character: '" + value +
+ "'. In a source expression, non-whitespace characters outside ASCII "
+ "0x21-0x7E must be Punycode-encoded, as described in RFC 3492 "
+ "(https://tools.ietf.org/html/rfc3492), if part of the hostname and "
+ "percent-encoded, as described in RFC 3986, section 2.1 "
+ "(http://tools.ietf.org/html/rfc3986#section-2.1), if part of the path.";
LogToConsole(message);
}
@@ -1424,7 +1435,8 @@ void ContentSecurityPolicy::ReportContentSecurityPolicyIssue(
ContentSecurityPolicyType header_type,
ContentSecurityPolicyViolationType violation_type,
LocalFrame* frame_ancestor,
- Element* element) {
+ Element* element,
+ SourceLocation* source_location) {
auto cspDetails = mojom::blink::ContentSecurityPolicyIssueDetails::New();
cspDetails->is_report_only =
header_type == ContentSecurityPolicyType::kReport;
@@ -1442,12 +1454,16 @@ void ContentSecurityPolicy::ReportContentSecurityPolicyIssue(
cspDetails->frame_ancestor = std::move(affected_frame);
}
if (violation_data.sourceFile() && violation_data.lineNumber()) {
- auto source_location = network::mojom::blink::SourceLocation::New();
- source_location->url = violation_data.sourceFile();
+ auto affected_location = mojom::blink::AffectedLocation::New();
+ affected_location->url = violation_data.sourceFile();
// The frontend expects 0-based line numbers.
- source_location->line = violation_data.lineNumber() - 1;
- source_location->column = violation_data.columnNumber();
- cspDetails->source_location = std::move(source_location);
+ affected_location->line = violation_data.lineNumber() - 1;
+ affected_location->column = violation_data.columnNumber();
+ if (source_location) {
+ affected_location->script_id =
+ String::Number(source_location->ScriptId());
+ }
+ cspDetails->affected_location = std::move(affected_location);
}
if (element) {
cspDetails->violating_node_id = DOMNodeIds::IdForNode(element);
@@ -1489,25 +1505,12 @@ bool ContentSecurityPolicy::ExperimentalFeaturesEnabled() const {
}
bool ContentSecurityPolicy::ShouldSendCSPHeader(ResourceType type) const {
- for (const auto& policy : policies_) {
- if (policy->ShouldSendCSPHeader(type))
- return true;
- }
+ // TODO(mkwst): Revisit this once the CORS prefetch issue with the 'CSP'
+ // header is worked out, one way or another:
+ // https://github.com/whatwg/fetch/issues/52
return false;
}
-bool ContentSecurityPolicy::UrlMatchesSelf(const KURL& url) const {
- return self_source_->MatchesAsSelf(url);
-}
-
-bool ContentSecurityPolicy::ProtocolEqualsSelf(const String& protocol) const {
- return EqualIgnoringASCIICase(protocol, self_protocol_);
-}
-
-const String& ContentSecurityPolicy::GetSelfProtocol() const {
- return self_protocol_;
-}
-
// static
bool ContentSecurityPolicy::ShouldBypassMainWorld(
const ExecutionContext* context) {
@@ -1537,70 +1540,68 @@ void ContentSecurityPolicy::DidSendViolationReport(const String& report) {
violation_reports_sent_.insert(report.Impl()->GetHash());
}
-const char* ContentSecurityPolicy::GetDirectiveName(const DirectiveType& type) {
+const char* ContentSecurityPolicy::GetDirectiveName(CSPDirectiveName type) {
switch (type) {
- case DirectiveType::kBaseURI:
+ case CSPDirectiveName::BaseURI:
return "base-uri";
- case DirectiveType::kBlockAllMixedContent:
+ case CSPDirectiveName::BlockAllMixedContent:
return "block-all-mixed-content";
- case DirectiveType::kChildSrc:
+ case CSPDirectiveName::ChildSrc:
return "child-src";
- case DirectiveType::kConnectSrc:
+ case CSPDirectiveName::ConnectSrc:
return "connect-src";
- case DirectiveType::kDefaultSrc:
+ case CSPDirectiveName::DefaultSrc:
return "default-src";
- case DirectiveType::kFontSrc:
+ case CSPDirectiveName::FontSrc:
return "font-src";
- case DirectiveType::kFormAction:
+ case CSPDirectiveName::FormAction:
return "form-action";
- case DirectiveType::kFrameAncestors:
+ case CSPDirectiveName::FrameAncestors:
return "frame-ancestors";
- case DirectiveType::kFrameSrc:
+ case CSPDirectiveName::FrameSrc:
return "frame-src";
- case DirectiveType::kImgSrc:
+ case CSPDirectiveName::ImgSrc:
return "img-src";
- case DirectiveType::kManifestSrc:
+ case CSPDirectiveName::ManifestSrc:
return "manifest-src";
- case DirectiveType::kMediaSrc:
+ case CSPDirectiveName::MediaSrc:
return "media-src";
- case DirectiveType::kNavigateTo:
+ case CSPDirectiveName::NavigateTo:
return "navigate-to";
- case DirectiveType::kObjectSrc:
+ case CSPDirectiveName::ObjectSrc:
return "object-src";
- case DirectiveType::kPluginTypes:
- return "plugin-types";
- case DirectiveType::kPrefetchSrc:
+ case CSPDirectiveName::PrefetchSrc:
return "prefetch-src";
- case DirectiveType::kReportTo:
+ case CSPDirectiveName::ReportTo:
return "report-to";
- case DirectiveType::kReportURI:
+ case CSPDirectiveName::ReportURI:
return "report-uri";
- case DirectiveType::kRequireTrustedTypesFor:
+ case CSPDirectiveName::RequireTrustedTypesFor:
return "require-trusted-types-for";
- case DirectiveType::kSandbox:
+ case CSPDirectiveName::Sandbox:
return "sandbox";
- case DirectiveType::kScriptSrc:
+ case CSPDirectiveName::ScriptSrc:
return "script-src";
- case DirectiveType::kScriptSrcAttr:
+ case CSPDirectiveName::ScriptSrcAttr:
return "script-src-attr";
- case DirectiveType::kScriptSrcElem:
+ case CSPDirectiveName::ScriptSrcElem:
return "script-src-elem";
- case DirectiveType::kStyleSrc:
+ case CSPDirectiveName::StyleSrc:
return "style-src";
- case DirectiveType::kStyleSrcAttr:
+ case CSPDirectiveName::StyleSrcAttr:
return "style-src-attr";
- case DirectiveType::kStyleSrcElem:
+ case CSPDirectiveName::StyleSrcElem:
return "style-src-elem";
- case DirectiveType::kTreatAsPublicAddress:
+ case CSPDirectiveName::TreatAsPublicAddress:
return "treat-as-public-address";
- case DirectiveType::kTrustedTypes:
+ case CSPDirectiveName::TrustedTypes:
return "trusted-types";
- case DirectiveType::kUpgradeInsecureRequests:
+ case CSPDirectiveName::UpgradeInsecureRequests:
return "upgrade-insecure-requests";
- case DirectiveType::kWorkerSrc:
+ case CSPDirectiveName::WorkerSrc:
return "worker-src";
- case DirectiveType::kUndefined:
+ case CSPDirectiveName::Unknown:
NOTREACHED();
return "";
}
@@ -1609,87 +1610,67 @@ const char* ContentSecurityPolicy::GetDirectiveName(const DirectiveType& type) {
return "";
}
-ContentSecurityPolicy::DirectiveType ContentSecurityPolicy::GetDirectiveType(
- const String& name) {
+CSPDirectiveName ContentSecurityPolicy::GetDirectiveType(const String& name) {
if (name == "base-uri")
- return DirectiveType::kBaseURI;
+ return CSPDirectiveName::BaseURI;
if (name == "block-all-mixed-content")
- return DirectiveType::kBlockAllMixedContent;
+ return CSPDirectiveName::BlockAllMixedContent;
if (name == "child-src")
- return DirectiveType::kChildSrc;
+ return CSPDirectiveName::ChildSrc;
if (name == "connect-src")
- return DirectiveType::kConnectSrc;
+ return CSPDirectiveName::ConnectSrc;
if (name == "default-src")
- return DirectiveType::kDefaultSrc;
+ return CSPDirectiveName::DefaultSrc;
if (name == "font-src")
- return DirectiveType::kFontSrc;
+ return CSPDirectiveName::FontSrc;
if (name == "form-action")
- return DirectiveType::kFormAction;
+ return CSPDirectiveName::FormAction;
if (name == "frame-ancestors")
- return DirectiveType::kFrameAncestors;
+ return CSPDirectiveName::FrameAncestors;
if (name == "frame-src")
- return DirectiveType::kFrameSrc;
+ return CSPDirectiveName::FrameSrc;
if (name == "img-src")
- return DirectiveType::kImgSrc;
+ return CSPDirectiveName::ImgSrc;
if (name == "manifest-src")
- return DirectiveType::kManifestSrc;
+ return CSPDirectiveName::ManifestSrc;
if (name == "media-src")
- return DirectiveType::kMediaSrc;
+ return CSPDirectiveName::MediaSrc;
if (name == "navigate-to")
- return DirectiveType::kNavigateTo;
+ return CSPDirectiveName::NavigateTo;
if (name == "object-src")
- return DirectiveType::kObjectSrc;
- if (name == "plugin-types")
- return DirectiveType::kPluginTypes;
+ return CSPDirectiveName::ObjectSrc;
if (name == "prefetch-src")
- return DirectiveType::kPrefetchSrc;
+ return CSPDirectiveName::PrefetchSrc;
if (name == "report-to")
- return DirectiveType::kReportTo;
+ return CSPDirectiveName::ReportTo;
if (name == "report-uri")
- return DirectiveType::kReportURI;
+ return CSPDirectiveName::ReportURI;
if (name == "require-trusted-types-for")
- return DirectiveType::kRequireTrustedTypesFor;
+ return CSPDirectiveName::RequireTrustedTypesFor;
if (name == "sandbox")
- return DirectiveType::kSandbox;
+ return CSPDirectiveName::Sandbox;
if (name == "script-src")
- return DirectiveType::kScriptSrc;
+ return CSPDirectiveName::ScriptSrc;
if (name == "script-src-attr")
- return DirectiveType::kScriptSrcAttr;
+ return CSPDirectiveName::ScriptSrcAttr;
if (name == "script-src-elem")
- return DirectiveType::kScriptSrcElem;
+ return CSPDirectiveName::ScriptSrcElem;
if (name == "style-src")
- return DirectiveType::kStyleSrc;
+ return CSPDirectiveName::StyleSrc;
if (name == "style-src-attr")
- return DirectiveType::kStyleSrcAttr;
+ return CSPDirectiveName::StyleSrcAttr;
if (name == "style-src-elem")
- return DirectiveType::kStyleSrcElem;
+ return CSPDirectiveName::StyleSrcElem;
if (name == "treat-as-public-address")
- return DirectiveType::kTreatAsPublicAddress;
+ return CSPDirectiveName::TreatAsPublicAddress;
if (name == "trusted-types")
- return DirectiveType::kTrustedTypes;
+ return CSPDirectiveName::TrustedTypes;
if (name == "upgrade-insecure-requests")
- return DirectiveType::kUpgradeInsecureRequests;
+ return CSPDirectiveName::UpgradeInsecureRequests;
if (name == "worker-src")
- return DirectiveType::kWorkerSrc;
-
- return DirectiveType::kUndefined;
-}
-
-bool ContentSecurityPolicy::Subsumes(const ContentSecurityPolicy& other) const {
- DCHECK(!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE));
- if (!policies_.size() || !other.policies_.size())
- return !policies_.size();
- // Required-CSP must specify only one policy.
- if (policies_.size() != 1)
- return false;
-
- CSPDirectiveListVector other_vector;
- for (const auto& policy : other.policies_) {
- if (!policy->IsReportOnly())
- other_vector.push_back(policy);
- }
+ return CSPDirectiveName::WorkerSrc;
- return policies_[0]->Subsumes(other_vector);
+ return CSPDirectiveName::Unknown;
}
bool ContentSecurityPolicy::ShouldBypassContentSecurityPolicy(
@@ -1713,57 +1694,15 @@ bool ContentSecurityPolicy::ShouldBypassContentSecurityPolicy(
return should_bypass_csp;
}
-// static
-bool ContentSecurityPolicy::IsValidCSPAttr(const String& attr,
- const String& context_required_csp) {
- DCHECK(!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE));
-
- // we don't allow any newline characters in the CSP attributes
- if (attr.Contains('\n') || attr.Contains('\r'))
- return false;
-
- auto* attr_policy = MakeGarbageCollected<ContentSecurityPolicy>();
- attr_policy->AddPolicyFromHeaderValue(attr,
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- if (!attr_policy->console_messages_.IsEmpty() ||
- attr_policy->policies_.size() != 1) {
- return false;
- }
-
- // Don't allow any report endpoints in "csp" attributes.
- for (auto& directiveList : attr_policy->policies_) {
- if (directiveList->ReportEndpoints().size() != 0)
- return false;
- }
-
- if (context_required_csp.IsEmpty() || context_required_csp.IsNull()) {
- return true;
- }
-
- auto* context_policy = MakeGarbageCollected<ContentSecurityPolicy>();
- context_policy->AddPolicyFromHeaderValue(context_required_csp,
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
-
- DCHECK(context_policy->console_messages_.IsEmpty() &&
- context_policy->policies_.size() == 1);
-
- return context_policy->Subsumes(*attr_policy);
-}
-
-WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
-ContentSecurityPolicy::ExposeForNavigationalChecks() const {
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> list;
- for (const auto& policy : policies_)
- list.push_back(policy->ExposeForNavigationalChecks());
- return list;
+const WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>&
+ContentSecurityPolicy::GetParsedPolicies() const {
+ return policies_;
}
bool ContentSecurityPolicy::HasPolicyFromSource(
ContentSecurityPolicySource source) const {
for (const auto& policy : policies_) {
- if (policy->HeaderSource() == source)
+ if (policy->header->source == source)
return true;
}
return false;
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index d8aa25abeba..4ca6b299bba 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -63,8 +63,6 @@ namespace blink {
class ContentSecurityPolicyResponseHeaders;
class ConsoleMessage;
-class CSPDirectiveList;
-class CSPSource;
class DOMWrapperWorld;
class Element;
class ExecutionContext;
@@ -76,11 +74,9 @@ class SecurityPolicyViolationEventInit;
class SourceLocation;
enum class ResourceType : uint8_t;
-typedef HeapVector<Member<CSPDirectiveList>> CSPDirectiveListVector;
typedef HeapVector<Member<ConsoleMessage>> ConsoleMessageVector;
-typedef std::pair<String, network::mojom::ContentSecurityPolicyType>
- CSPHeaderAndType;
using RedirectStatus = ResourceRequest::RedirectStatus;
+using network::mojom::blink::CSPDirectiveName;
// A delegate interface to implement violation reporting, support for some
// directives and other miscellaneous functionality.
@@ -165,40 +161,6 @@ class CORE_EXPORT ContentSecurityPolicy final
kStyleAttribute
};
- enum class DirectiveType {
- kBaseURI,
- kBlockAllMixedContent,
- kChildSrc,
- kConnectSrc,
- kDefaultSrc,
- kFontSrc,
- kFormAction,
- kFrameAncestors,
- kFrameSrc,
- kImgSrc,
- kManifestSrc,
- kMediaSrc,
- kNavigateTo,
- kObjectSrc,
- kPluginTypes,
- kPrefetchSrc,
- kReportTo,
- kReportURI,
- kRequireTrustedTypesFor,
- kSandbox,
- kScriptSrc,
- kScriptSrcAttr,
- kScriptSrcElem,
- kStyleSrc,
- kStyleSrcAttr,
- kStyleSrcElem,
- kTreatAsPublicAddress,
- kTrustedTypes,
- kUndefined,
- kUpgradeInsecureRequests,
- kWorkerSrc,
- };
-
// CheckHeaderType can be passed to Allow*FromSource methods to control which
// types of CSP headers are checked.
enum class CheckHeaderType {
@@ -213,29 +175,36 @@ class CORE_EXPORT ContentSecurityPolicy final
kCheckReportOnly
};
+ // Helper type for the method AllowTrustedTypePolicy.
+ enum AllowTrustedTypePolicyDetails {
+ kAllowed,
+ kDisallowedName,
+ kDisallowedDuplicateName
+ };
+
static const size_t kMaxSampleLength = 40;
+ // Parse raw Content Security Policy strings into mojo types.
+ static WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ ParseHeaders(const ContentSecurityPolicyResponseHeaders& headers);
+
ContentSecurityPolicy();
~ContentSecurityPolicy();
void Trace(Visitor*) const;
bool IsBound();
void BindToDelegate(ContentSecurityPolicyDelegate&);
- void SetupSelf(const SecurityOrigin&);
- void SetupSelf(const ContentSecurityPolicy&);
void CopyStateFrom(const ContentSecurityPolicy*);
- void CopyPluginTypesFrom(const ContentSecurityPolicy*);
void DidReceiveHeaders(const ContentSecurityPolicyResponseHeaders&);
void DidReceiveHeader(const String&,
+ const SecurityOrigin& self_origin,
network::mojom::ContentSecurityPolicyType,
network::mojom::ContentSecurityPolicySource);
- void AddPolicyFromHeaderValue(const String&,
- network::mojom::ContentSecurityPolicyType,
- network::mojom::ContentSecurityPolicySource);
void ReportAccumulatedHeaders() const;
- Vector<CSPHeaderAndType> Headers() const;
+ void AddPolicies(
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies);
// Returns whether or not the Javascript code generation should call back the
// CSP checker before any script evaluation from a string attempts.
@@ -251,33 +220,28 @@ class CORE_EXPORT ContentSecurityPolicy final
// message to the console because it would be redundant.
bool AllowEval(ReportingDisposition,
ExceptionStatus,
- const String& script_content) const;
+ const String& script_content);
bool AllowWasmEval(ReportingDisposition,
ExceptionStatus,
- const String& script_content) const;
- bool AllowPluginType(
- const String& type,
- const String& type_attribute,
- const KURL&,
- ReportingDisposition = ReportingDisposition::kReport) const;
+ const String& script_content);
// AllowFromSource() wrappers.
- bool AllowBaseURI(const KURL&) const;
+ bool AllowBaseURI(const KURL&);
bool AllowConnectToSource(
const KURL&,
const KURL& url_before_redirects,
RedirectStatus,
ReportingDisposition = ReportingDisposition::kReport,
- CheckHeaderType = CheckHeaderType::kCheckAll) const;
- bool AllowFormAction(const KURL&) const;
+ CheckHeaderType = CheckHeaderType::kCheckAll);
+ bool AllowFormAction(const KURL&);
bool AllowImageFromSource(
const KURL&,
const KURL& url_before_redirects,
RedirectStatus,
ReportingDisposition = ReportingDisposition::kReport,
- CheckHeaderType = CheckHeaderType::kCheckAll) const;
- bool AllowMediaFromSource(const KURL&) const;
- bool AllowObjectFromSource(const KURL&) const;
+ CheckHeaderType = CheckHeaderType::kCheckAll);
+ bool AllowMediaFromSource(const KURL&);
+ bool AllowObjectFromSource(const KURL&);
bool AllowScriptFromSource(
const KURL&,
const String& nonce,
@@ -286,11 +250,12 @@ class CORE_EXPORT ContentSecurityPolicy final
const KURL& url_before_redirects,
RedirectStatus,
ReportingDisposition = ReportingDisposition::kReport,
- CheckHeaderType = CheckHeaderType::kCheckAll) const;
- bool AllowWorkerContextFromSource(const KURL&) const;
+ CheckHeaderType = CheckHeaderType::kCheckAll);
+ bool AllowWorkerContextFromSource(const KURL&);
bool AllowTrustedTypePolicy(const String& policy_name,
- bool is_duplicate) const;
+ bool is_duplicate,
+ AllowTrustedTypePolicyDetails& violation_details);
// Passing 'String()' into the |nonce| arguments in the following methods
// represents an unnonced resource load.
@@ -309,7 +274,7 @@ class CORE_EXPORT ContentSecurityPolicy final
const String& nonce,
const String& context_url,
const WTF::OrdinalNumber& context_line,
- ReportingDisposition = ReportingDisposition::kReport) const;
+ ReportingDisposition = ReportingDisposition::kReport);
static bool IsScriptInlineType(InlineType);
@@ -335,14 +300,14 @@ class CORE_EXPORT ContentSecurityPolicy final
const KURL& url_before_redirects,
RedirectStatus,
ReportingDisposition = ReportingDisposition::kReport,
- CheckHeaderType = CheckHeaderType::kCheckAll) const;
+ CheckHeaderType = CheckHeaderType::kCheckAll);
// Determine whether to enforce the assignment failure. Also handle reporting.
// Returns whether enforcing Trusted Types CSP directives are present.
bool AllowTrustedTypeAssignmentFailure(
const String& message,
const String& sample = String(),
- const String& sample_prefix = String()) const;
+ const String& sample_prefix = String());
void UsesScriptHashAlgorithms(uint8_t content_security_policy_hash_algorithm);
void UsesStyleHashAlgorithms(uint8_t content_security_policy_hash_algorithm);
@@ -366,7 +331,7 @@ class CORE_EXPORT ContentSecurityPolicy final
void ReportInvalidPathCharacter(const String& directive_name,
const String& value,
const char);
- void ReportInvalidPluginTypes(const String&);
+ void ReportInvalidRequireTrustedTypesFor(const String&);
void ReportInvalidSandboxFlags(const String&);
void ReportInvalidSourceExpression(const String& directive_name,
const String& source);
@@ -387,7 +352,7 @@ class CORE_EXPORT ContentSecurityPolicy final
// If |sourceLocation| is not set, the source location will be the context's
// current location.
void ReportViolation(const String& directive_text,
- const DirectiveType& effective_type,
+ CSPDirectiveName effective_type,
const String& console_message,
const KURL& blocked_url,
const Vector<String>& report_endpoints,
@@ -405,7 +370,7 @@ class CORE_EXPORT ContentSecurityPolicy final
// Called when mixed content is detected on a page; will trigger a violation
// report if the 'block-all-mixed-content' directive is specified for a
// policy.
- void ReportMixedContent(const KURL& blocked_url, RedirectStatus) const;
+ void ReportMixedContent(const KURL& blocked_url, RedirectStatus);
void ReportBlockedScriptExecutionToInspector(
const String& directive_text) const;
@@ -426,16 +391,10 @@ class CORE_EXPORT ContentSecurityPolicy final
return insecure_request_policy_;
}
- bool UrlMatchesSelf(const KURL&) const;
- bool ProtocolEqualsSelf(const String&) const;
- const String& GetSelfProtocol() const;
-
bool ExperimentalFeaturesEnabled() const;
bool ShouldSendCSPHeader(ResourceType) const;
- CSPSource* GetSelfSource() const { return self_source_; }
-
// Whether the main world's CSP should be bypassed based on the current
// javascript world we are in.
// Note: This is deprecated. New usages should not be added. Operations in an
@@ -455,36 +414,18 @@ class CORE_EXPORT ContentSecurityPolicy final
static bool IsNonceableElement(const Element*);
- // This method checks whether the request should be allowed for an
- // experimental EmbeddingCSP feature
- // Please, see https://w3c.github.io/webappsec-csp/embedded/#origin-allowed.
- static bool ShouldEnforceEmbeddersPolicy(const ResourceResponse&,
- const SecurityOrigin*);
-
- static const char* GetDirectiveName(const DirectiveType&);
- static DirectiveType GetDirectiveType(const String& name);
-
- // This method checks if if this policy subsumes a given policy.
- // Note the correct result is guaranteed if this policy contains only one
- // CSPDirectiveList. More information here:
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
- bool Subsumes(const ContentSecurityPolicy&) const;
+ static const char* GetDirectiveName(CSPDirectiveName type);
+ static CSPDirectiveName GetDirectiveType(const String& name);
bool HasHeaderDeliveredPolicy() const { return header_delivered_; }
- static bool IsValidCSPAttr(const String& attr,
- const String& context_required_csp);
-
// Returns the 'wasm-eval' source is supported.
bool SupportsWasmEval() const { return supports_wasm_eval_; }
void SetSupportsWasmEval(bool value) { supports_wasm_eval_ = value; }
- // Sometimes we don't know the initiator or it might be destroyed already
- // for certain navigational checks. We create a string version of the relevant
- // CSP directives to be passed around with the request. This allows us to
- // perform these checks in NavigationRequest::CheckContentSecurityPolicy.
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
- ExposeForNavigationalChecks() const;
+ // Retrieve the parsed policies.
+ const WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>&
+ GetParsedPolicies() const;
// Retrieves the parsed sandbox flags. A lot of the time the execution
// context will be used for all sandbox checks but there are situations
@@ -496,21 +437,16 @@ class CORE_EXPORT ContentSecurityPolicy final
bool HasPolicyFromSource(network::mojom::ContentSecurityPolicySource) const;
- static bool IsScriptDirective(
- ContentSecurityPolicy::DirectiveType directive_type) {
- return (
- directive_type == ContentSecurityPolicy::DirectiveType::kScriptSrc ||
- directive_type ==
- ContentSecurityPolicy::DirectiveType::kScriptSrcAttr ||
- directive_type == ContentSecurityPolicy::DirectiveType::kScriptSrcElem);
+ static bool IsScriptDirective(CSPDirectiveName directive_type) {
+ return (directive_type == CSPDirectiveName::ScriptSrc ||
+ directive_type == CSPDirectiveName::ScriptSrcAttr ||
+ directive_type == CSPDirectiveName::ScriptSrcElem);
}
- static bool IsStyleDirective(
- ContentSecurityPolicy::DirectiveType directive_type) {
- return (
- directive_type == ContentSecurityPolicy::DirectiveType::kStyleSrc ||
- directive_type == ContentSecurityPolicy::DirectiveType::kStyleSrcAttr ||
- directive_type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem);
+ static bool IsStyleDirective(CSPDirectiveName directive_type) {
+ return (directive_type == CSPDirectiveName::StyleSrc ||
+ directive_type == CSPDirectiveName::StyleSrcAttr ||
+ directive_type == CSPDirectiveName::StyleSrcElem);
}
void Count(WebFeature feature) const;
@@ -527,17 +463,21 @@ class CORE_EXPORT ContentSecurityPolicy final
FRIEND_TEST_ALL_PREFIXES(FrameFetchContextTest,
PopulateResourceRequestChecksReportOnlyCSP);
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> Parse(
+ const String&,
+ const SecurityOrigin& self_origin,
+ network::mojom::ContentSecurityPolicyType,
+ network::mojom::ContentSecurityPolicySource);
void ApplyPolicySideEffectsToDelegate();
+ void ReportUseCounters(
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>& policies);
+ void ComputeInternalStateForParsedPolicy(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
void LogToConsole(
const String& message,
mojom::ConsoleMessageLevel = mojom::ConsoleMessageLevel::kError);
- void AddAndReportPolicyFromHeaderValue(
- const String&,
- network::mojom::ContentSecurityPolicyType,
- network::mojom::ContentSecurityPolicySource);
-
bool ShouldSendViolationReport(const String&) const;
void DidSendViolationReport(const String&);
void PostViolationReport(const SecurityPolicyViolationEventInit*,
@@ -545,7 +485,7 @@ class CORE_EXPORT ContentSecurityPolicy final
const Vector<String>& report_endpoints,
bool use_reporting_api);
- bool AllowFromSource(ContentSecurityPolicy::DirectiveType,
+ bool AllowFromSource(CSPDirectiveName,
const KURL&,
const KURL& url_before_redirects,
RedirectStatus,
@@ -553,17 +493,19 @@ class CORE_EXPORT ContentSecurityPolicy final
CheckHeaderType = CheckHeaderType::kCheckAll,
const String& = String(),
const IntegrityMetadataSet& = IntegrityMetadataSet(),
- ParserDisposition = kParserInserted) const;
+ ParserDisposition = kParserInserted);
- static void FillInCSPHashValues(const String& source,
- uint8_t hash_algorithms_used,
- Vector<CSPHashValue>* csp_hash_values);
+ static void FillInCSPHashValues(
+ const String& source,
+ uint8_t hash_algorithms_used,
+ Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values);
// checks a vector of csp hashes against policy, probably a good idea
// to use in tandem with FillInCSPHashValues.
- static bool CheckHashAgainstPolicy(Vector<CSPHashValue>&,
- const Member<CSPDirectiveList>&,
- InlineType);
+ static bool CheckHashAgainstPolicy(
+ Vector<network::mojom::blink::CSPHashSourcePtr>&,
+ const network::mojom::blink::ContentSecurityPolicy&,
+ InlineType);
bool ShouldBypassContentSecurityPolicy(
const KURL&,
@@ -578,12 +520,13 @@ class CORE_EXPORT ContentSecurityPolicy final
const blink::SecurityPolicyViolationEventInit& violation_data,
network::mojom::ContentSecurityPolicyType header_type,
ContentSecurityPolicyViolationType violation_type,
- LocalFrame* = nullptr,
- Element* = nullptr);
+ LocalFrame*,
+ Element*,
+ SourceLocation*);
Member<ContentSecurityPolicyDelegate> delegate_;
- bool override_inline_style_allowed_;
- CSPDirectiveListVector policies_;
+ bool override_inline_style_allowed_ = false;
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies_;
ConsoleMessageVector console_messages_;
bool header_delivered_{false};
@@ -601,7 +544,6 @@ class CORE_EXPORT ContentSecurityPolicy final
String disable_eval_error_message_;
mojom::blink::InsecureRequestPolicy insecure_request_policy_;
- Member<CSPSource> self_source_;
String self_protocol_;
bool supports_wasm_eval_ = false;
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
index ab7d3bca654..862650f7138 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
@@ -26,19 +26,29 @@ int LLVMFuzzerInitialize(int* argc, char*** argv) {
LEAK_SANITIZER_DISABLED_SCOPE;
g_page_holder = std::make_unique<DummyPageHolder>().release();
- // Set loader sandbox flags and install a new document so the document
- // has all possible sandbox flags set on the document already when the
- // CSP is bound.
scoped_refptr<SharedBuffer> empty_document_data = SharedBuffer::Create();
- g_page_holder->GetFrame().Loader().ForceSandboxFlags(
- network::mojom::blink::WebSandboxFlags::kAll);
g_page_holder->GetFrame().ForceSynchronousDocumentInstall(
"text/html", empty_document_data);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- String header = String::FromUTF8(data, size);
+ // We need two pieces of input: a URL and a CSP string. Split |data| in two at
+ // the first whitespace.
+ const uint8_t* it = data;
+ for (; it < data + size; it++) {
+ if (base::IsAsciiWhitespace(*reinterpret_cast<const char*>(it))) {
+ it++;
+ break;
+ }
+ }
+ if (it == data + size) {
+ // Not much point in going on with an empty CSP string.
+ return EXIT_SUCCESS;
+ }
+
+ String url = String(data, it - 1 - data);
+ String header = String(it, size - (it - data));
unsigned hash = header.IsNull() ? 0 : header.Impl()->GetHash();
// Use the 'hash' value to pick header_type and header_source input.
@@ -57,9 +67,11 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
: network::mojom::ContentSecurityPolicySource::kOriginPolicy;
}
+ scoped_refptr<SecurityOrigin> self_origin = SecurityOrigin::Create(KURL(url));
+
// Construct and initialize a policy from the string.
auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(header, header_type, header_source);
+ csp->DidReceiveHeader(header, *self_origin, header_type, header_source);
auto& context = g_page_holder->GetFrame().DomWindow()->GetSecurityContext();
context.SetContentSecurityPolicy(csp);
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index a349dd90e51..81363ca659f 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -37,18 +37,22 @@ class ContentSecurityPolicyTest : public testing::Test {
public:
ContentSecurityPolicyTest()
: csp(MakeGarbageCollected<ContentSecurityPolicy>()),
- secure_url("https://example.test/image.png"),
+ secure_url("https://example.test/index.html"),
secure_origin(SecurityOrigin::Create(secure_url)) {}
+ ~ContentSecurityPolicyTest() override {
+ execution_context->NotifyContextDestroyed();
+ }
protected:
- void SetUp() override { execution_context = CreateExecutionContext(); }
-
- NullExecutionContext* CreateExecutionContext() {
- NullExecutionContext* context =
- MakeGarbageCollected<NullExecutionContext>();
- context->SetUpSecurityContextForTesting();
- context->GetSecurityContext().SetSecurityOriginForTesting(secure_origin);
- return context;
+ void SetUp() override { CreateExecutionContext(); }
+
+ void CreateExecutionContext() {
+ if (execution_context)
+ execution_context->NotifyContextDestroyed();
+ execution_context = MakeGarbageCollected<NullExecutionContext>();
+ execution_context->SetUpSecurityContextForTesting();
+ execution_context->GetSecurityContext().SetSecurityOriginForTesting(
+ secure_origin);
}
Persistent<ContentSecurityPolicy> csp;
@@ -80,7 +84,8 @@ TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
SCOPED_TRACE(testing::Message()
<< "[Enforce] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.expected_policy, csp->GetInsecureRequestPolicy());
@@ -108,12 +113,13 @@ TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
SCOPED_TRACE(testing::Message()
<< "[Report-Only] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone,
csp->GetInsecureRequestPolicy());
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
execution_context->GetSecurityContext().SetSecurityOrigin(secure_origin);
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(
@@ -126,10 +132,10 @@ TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
}
TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
- csp->DidReceiveHeader("script-src 'none'; plugin-types application/x-type-1",
+ csp->DidReceiveHeader("script-src 'none'", *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- csp->DidReceiveHeader("img-src http://example.com",
+ csp->DidReceiveHeader("img-src http://example.com", *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
@@ -143,9 +149,6 @@ TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
example_url, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting,
ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
- EXPECT_TRUE(csp2->AllowPluginType("application/x-type-1",
- "application/x-type-1", example_url,
- ReportingDisposition::kSuppressReporting));
EXPECT_TRUE(csp2->AllowImageFromSource(
example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting,
@@ -155,46 +158,11 @@ TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting,
ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
- EXPECT_FALSE(csp2->AllowPluginType("application/x-type-2",
- "application/x-type-2", example_url,
- ReportingDisposition::kSuppressReporting));
-}
-
-TEST_F(ContentSecurityPolicyTest, CopyPluginTypesFrom) {
- csp->DidReceiveHeader("script-src 'none'; plugin-types application/x-type-1",
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- csp->DidReceiveHeader("img-src http://example.com",
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
-
- const KURL example_url("http://example.com");
- const KURL not_example_url("http://not-example.com");
-
- auto* csp2 = MakeGarbageCollected<ContentSecurityPolicy>();
- csp2->CopyPluginTypesFrom(csp.Get());
- EXPECT_TRUE(csp2->AllowScriptFromSource(
- example_url, String(), IntegrityMetadataSet(), kParserInserted,
- example_url, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting));
- EXPECT_TRUE(csp2->AllowPluginType("application/x-type-1",
- "application/x-type-1", example_url,
- ReportingDisposition::kSuppressReporting));
- EXPECT_TRUE(csp2->AllowImageFromSource(
- example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting));
- EXPECT_TRUE(
- csp2->AllowImageFromSource(not_example_url, not_example_url,
- ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting));
- EXPECT_FALSE(csp2->AllowPluginType("application/x-type-2",
- "application/x-type-2", example_url,
- ReportingDisposition::kSuppressReporting));
}
TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithConnectSrc) {
EXPECT_FALSE(csp->IsActiveForConnections());
- csp->DidReceiveHeader("connect-src 'none';",
+ csp->DidReceiveHeader("connect-src 'none';", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(csp->IsActiveForConnections());
@@ -202,7 +170,7 @@ TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithConnectSrc) {
TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithDefaultSrc) {
EXPECT_FALSE(csp->IsActiveForConnections());
- csp->DidReceiveHeader("default-src 'none';",
+ csp->DidReceiveHeader("default-src 'none';", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(csp->IsActiveForConnections());
@@ -214,43 +182,27 @@ TEST_F(ContentSecurityPolicyTest, SandboxInMeta) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kNone,
csp->GetSandboxMask());
- csp->DidReceiveHeader("sandbox;", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("sandbox;", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kMeta);
EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kNone,
csp->GetSandboxMask());
- execution_context->GetSecurityContext().ApplySandboxFlags(
+ execution_context->GetSecurityContext().SetSandboxFlags(
network::mojom::blink::WebSandboxFlags::kAll);
- csp->DidReceiveHeader("sandbox;", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("sandbox;", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kAll,
csp->GetSandboxMask());
}
-// Tests that report-uri directives are discarded from policies
-// delivered in <meta> elements.
-TEST_F(ContentSecurityPolicyTest, ReportURIInMeta) {
- String policy = "img-src 'none'; report-uri http://foo.test";
- Vector<UChar> characters;
- policy.AppendTo(characters);
- const UChar* begin = characters.data();
- const UChar* end = begin + characters.size();
- CSPDirectiveList* directive_list(CSPDirectiveList::Create(
- csp, begin, end, ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kMeta));
- EXPECT_TRUE(directive_list->ReportEndpoints().IsEmpty());
- directive_list = CSPDirectiveList::Create(csp, begin, end,
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- EXPECT_FALSE(directive_list->ReportEndpoints().IsEmpty());
-}
-
// Tests that object-src directives are applied to a request to load a
// plugin, but not to subresource requests that the plugin itself
// makes. https://crbug.com/603952
TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
const KURL url("https://example.test");
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("object-src 'none';",
+ csp->DidReceiveHeader("object-src 'none';", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kMeta);
EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
@@ -276,7 +228,7 @@ TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
TEST_F(ContentSecurityPolicyTest, ConnectSrc) {
const KURL url("https://example.test");
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("connect-src 'none';",
+ csp->DidReceiveHeader("connect-src 'none';", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kMeta);
EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
@@ -341,7 +293,8 @@ TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) {
MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy, ContentSecurityPolicyType::kEnforce,
+ policy->DidReceiveHeader(test.policy, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.allowed,
policy->AllowScriptFromSource(
@@ -356,7 +309,8 @@ TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) {
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy, ContentSecurityPolicyType::kReport,
+ policy->DidReceiveHeader(test.policy, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(policy->AllowScriptFromSource(
resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
@@ -405,6 +359,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("script-src ") + test.policy,
+ *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.allowed,
@@ -416,7 +371,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Enforce 'style-src'
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(String("style-src ") + test.policy,
+ policy->DidReceiveHeader(String("style-src ") + test.policy, *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.allowed,
@@ -429,7 +384,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
policy->DidReceiveHeader(String("script-src ") + test.policy,
- ContentSecurityPolicyType::kReport,
+ *secure_origin, ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(policy->AllowInline(ContentSecurityPolicy::InlineType::kScript,
element, content, String(test.nonce),
@@ -439,7 +394,7 @@ TEST_F(ContentSecurityPolicyTest, NonceInline) {
// Report 'style-src'
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(String("style-src ") + test.policy,
+ policy->DidReceiveHeader(String("style-src ") + test.policy, *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(policy->AllowInline(ContentSecurityPolicy::InlineType::kStyle,
@@ -511,9 +466,11 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kEnforce,
+ policy->DidReceiveHeader(test.policy1, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kReport,
+ policy->DidReceiveHeader(test.policy2, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.allowed1,
policy->AllowScriptFromSource(
@@ -533,9 +490,11 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kReport,
+ policy->DidReceiveHeader(test.policy1, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kEnforce,
+ policy->DidReceiveHeader(test.policy2, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(policy->AllowScriptFromSource(
resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
@@ -555,9 +514,11 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kEnforce,
+ policy->DidReceiveHeader(test.policy1, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kEnforce,
+ policy->DidReceiveHeader(test.policy2, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_EQ(test.allowed1 && test.allowed2,
policy->AllowScriptFromSource(
@@ -572,9 +533,11 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
policy = MakeGarbageCollected<ContentSecurityPolicy>();
policy->BindToDelegate(
execution_context->GetContentSecurityPolicyDelegate());
- policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kReport,
+ policy->DidReceiveHeader(test.policy1, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kReport,
+ policy->DidReceiveHeader(test.policy2, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(policy->AllowScriptFromSource(
resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
@@ -585,99 +548,44 @@ TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
}
}
-TEST_F(ContentSecurityPolicyTest, ShouldEnforceEmbeddersPolicy) {
- struct TestCase {
- const char* resource_url;
- const bool inherits;
- } cases[] = {
- // Same-origin
- {"https://example.test/index.html", true},
- // Cross-origin
- {"http://example.test/index.html", false},
- {"http://example.test:8443/index.html", false},
- {"https://example.test:8443/index.html", false},
- {"http://not.example.test/index.html", false},
- {"https://not.example.test/index.html", false},
- {"https://not.example.test:8443/index.html", false},
-
- // Inherit
- {"about:blank", true},
- {"data:text/html,yay", true},
- {"blob:https://example.test/bbe708f3-defd-4852-93b6-cf94e032f08d", true},
- {"filesystem:http://example.test/temporary/index.html", true},
- };
-
- for (const auto& test : cases) {
- ResourceResponse response(KURL(test.resource_url));
- EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, secure_origin.get()),
- test.inherits);
-
- response.SetHttpHeaderField(http_names::kAllowCSPFrom, AtomicString("*"));
- EXPECT_TRUE(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, secure_origin.get()));
-
- response.SetHttpHeaderField(http_names::kAllowCSPFrom,
- AtomicString("* not a valid header"));
- EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, secure_origin.get()),
- test.inherits);
-
- response.SetHttpHeaderField(http_names::kAllowCSPFrom,
- AtomicString("http://example.test"));
- EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, secure_origin.get()),
- test.inherits);
-
- response.SetHttpHeaderField(http_names::kAllowCSPFrom,
- AtomicString("https://example.test"));
- EXPECT_TRUE(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, secure_origin.get()));
- }
-}
-
TEST_F(ContentSecurityPolicyTest, DirectiveType) {
struct TestCase {
- ContentSecurityPolicy::DirectiveType type;
+ CSPDirectiveName type;
const String& name;
} cases[] = {
- {ContentSecurityPolicy::DirectiveType::kBaseURI, "base-uri"},
- {ContentSecurityPolicy::DirectiveType::kBlockAllMixedContent,
- "block-all-mixed-content"},
- {ContentSecurityPolicy::DirectiveType::kChildSrc, "child-src"},
- {ContentSecurityPolicy::DirectiveType::kConnectSrc, "connect-src"},
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc, "default-src"},
- {ContentSecurityPolicy::DirectiveType::kFrameAncestors,
- "frame-ancestors"},
- {ContentSecurityPolicy::DirectiveType::kFrameSrc, "frame-src"},
- {ContentSecurityPolicy::DirectiveType::kFontSrc, "font-src"},
- {ContentSecurityPolicy::DirectiveType::kFormAction, "form-action"},
- {ContentSecurityPolicy::DirectiveType::kImgSrc, "img-src"},
- {ContentSecurityPolicy::DirectiveType::kManifestSrc, "manifest-src"},
- {ContentSecurityPolicy::DirectiveType::kMediaSrc, "media-src"},
- {ContentSecurityPolicy::DirectiveType::kNavigateTo, "navigate-to"},
- {ContentSecurityPolicy::DirectiveType::kObjectSrc, "object-src"},
- {ContentSecurityPolicy::DirectiveType::kPluginTypes, "plugin-types"},
- {ContentSecurityPolicy::DirectiveType::kReportURI, "report-uri"},
- {ContentSecurityPolicy::DirectiveType::kSandbox, "sandbox"},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc, "script-src"},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr, "script-src-attr"},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem, "script-src-elem"},
- {ContentSecurityPolicy::DirectiveType::kStyleSrc, "style-src"},
- {ContentSecurityPolicy::DirectiveType::kStyleSrcAttr, "style-src-attr"},
- {ContentSecurityPolicy::DirectiveType::kStyleSrcElem, "style-src-elem"},
- {ContentSecurityPolicy::DirectiveType::kUpgradeInsecureRequests,
- "upgrade-insecure-requests"},
- {ContentSecurityPolicy::DirectiveType::kWorkerSrc, "worker-src"},
+ {CSPDirectiveName::BaseURI, "base-uri"},
+ {CSPDirectiveName::BlockAllMixedContent, "block-all-mixed-content"},
+ {CSPDirectiveName::ChildSrc, "child-src"},
+ {CSPDirectiveName::ConnectSrc, "connect-src"},
+ {CSPDirectiveName::DefaultSrc, "default-src"},
+ {CSPDirectiveName::FrameAncestors, "frame-ancestors"},
+ {CSPDirectiveName::FrameSrc, "frame-src"},
+ {CSPDirectiveName::FontSrc, "font-src"},
+ {CSPDirectiveName::FormAction, "form-action"},
+ {CSPDirectiveName::ImgSrc, "img-src"},
+ {CSPDirectiveName::ManifestSrc, "manifest-src"},
+ {CSPDirectiveName::MediaSrc, "media-src"},
+ {CSPDirectiveName::NavigateTo, "navigate-to"},
+ {CSPDirectiveName::ObjectSrc, "object-src"},
+ {CSPDirectiveName::ReportURI, "report-uri"},
+ {CSPDirectiveName::Sandbox, "sandbox"},
+ {CSPDirectiveName::ScriptSrc, "script-src"},
+ {CSPDirectiveName::ScriptSrcAttr, "script-src-attr"},
+ {CSPDirectiveName::ScriptSrcElem, "script-src-elem"},
+ {CSPDirectiveName::StyleSrc, "style-src"},
+ {CSPDirectiveName::StyleSrcAttr, "style-src-attr"},
+ {CSPDirectiveName::StyleSrcElem, "style-src-elem"},
+ {CSPDirectiveName::UpgradeInsecureRequests, "upgrade-insecure-requests"},
+ {CSPDirectiveName::WorkerSrc, "worker-src"},
};
- EXPECT_EQ(ContentSecurityPolicy::DirectiveType::kUndefined,
+ EXPECT_EQ(CSPDirectiveName::Unknown,
ContentSecurityPolicy::GetDirectiveType("random"));
for (const auto& test : cases) {
const String& name_from_type =
ContentSecurityPolicy::GetDirectiveName(test.type);
- ContentSecurityPolicy::DirectiveType type_from_name =
+ CSPDirectiveName type_from_name =
ContentSecurityPolicy::GetDirectiveType(test.name);
EXPECT_EQ(name_from_type, test.name);
EXPECT_EQ(type_from_name, test.type);
@@ -688,50 +596,14 @@ TEST_F(ContentSecurityPolicyTest, DirectiveType) {
}
}
-// TODO(antoniosartori): Remove this test and the function
-// ContentSecurityPolicy::Subsumes when we remove the feature flag.
-TEST_F(ContentSecurityPolicyTest, Subsumes) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE);
-
- auto* other = MakeGarbageCollected<ContentSecurityPolicy>();
- EXPECT_TRUE(csp->Subsumes(*other));
- EXPECT_TRUE(other->Subsumes(*csp));
-
- csp->DidReceiveHeader("default-src http://example.com;",
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- // If this CSP is not empty, the other must not be empty either.
- EXPECT_FALSE(csp->Subsumes(*other));
- EXPECT_TRUE(other->Subsumes(*csp));
-
- // Report-only policies do not impact subsumption.
- other->DidReceiveHeader("default-src http://example.com;",
- ContentSecurityPolicyType::kReport,
- ContentSecurityPolicySource::kHTTP);
- EXPECT_FALSE(csp->Subsumes(*other));
-
- // CSPDirectiveLists have to subsume.
- other->DidReceiveHeader("default-src http://example.com https://another.com;",
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- EXPECT_FALSE(csp->Subsumes(*other));
-
- // `other` is stricter than `this`.
- other->DidReceiveHeader("default-src https://example.com;",
- ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->Subsumes(*other));
-}
-
TEST_F(ContentSecurityPolicyTest, RequestsAllowedWhenBypassingCSP) {
const KURL base;
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
execution_context->GetSecurityContext().SetSecurityOrigin(
secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("default-src https://example.com",
+ csp->DidReceiveHeader("default-src https://example.com", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
@@ -773,12 +645,12 @@ TEST_F(ContentSecurityPolicyTest, RequestsAllowedWhenBypassingCSP) {
}
TEST_F(ContentSecurityPolicyTest, FilesystemAllowedWhenBypassingCSP) {
const KURL base;
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
execution_context->GetSecurityContext().SetSecurityOrigin(
secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("default-src https://example.com",
+ csp->DidReceiveHeader("default-src https://example.com", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
@@ -821,12 +693,12 @@ TEST_F(ContentSecurityPolicyTest, FilesystemAllowedWhenBypassingCSP) {
TEST_F(ContentSecurityPolicyTest, BlobAllowedWhenBypassingCSP) {
const KURL base;
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
execution_context->GetSecurityContext().SetSecurityOrigin(
secure_origin); // https://example.com
execution_context->SetURL(secure_url); // https://example.com
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("default-src https://example.com",
+ csp->DidReceiveHeader("default-src https://example.com", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
@@ -869,11 +741,11 @@ TEST_F(ContentSecurityPolicyTest, BlobAllowedWhenBypassingCSP) {
TEST_F(ContentSecurityPolicyTest, CSPBypassDisabledWhenSchemeIsPrivileged) {
const KURL base;
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
execution_context->GetSecurityContext().SetSecurityOrigin(secure_origin);
execution_context->SetURL(BlankURL());
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("script-src http://example.com",
+ csp->DidReceiveHeader("script-src http://example.com", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
@@ -913,263 +785,251 @@ TEST_F(ContentSecurityPolicyTest, CSPBypassDisabledWhenSchemeIsPrivileged) {
SchemeRegistry::RemoveURLSchemeAsNotAllowingJavascriptURLs("https");
}
-// TODO(antoniosartori): Remove this test and the function
-// ContentSecurityPolicy::IsValidCSPAttr when we remove the feature flag.
-TEST_F(ContentSecurityPolicyTest, IsValidCSPAttrTest) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE);
-
- // Empty string is invalid
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("", ""));
-
- // Policy with single directive
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("base-uri http://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "invalid-policy-name http://example.com", ""));
-
- // Policy with multiple directives
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri http://example.com 'self'; child-src http://example.com; "
- "default-src http://example.com",
- ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "default-src http://example.com; "
- "invalid-policy-name http://example.com",
- ""));
-
- // 'self', 'none'
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr("script-src 'self'", ""));
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr("default-src 'none'", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src 'slef'", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("default-src 'non'", ""));
-
- // invalid ascii character
- EXPECT_FALSE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src https: \x08", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1%2F%DFisnotSorB%2F", ""));
-
- // paths on script-src
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:*/", ""));
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:*/path", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:*/path?query=string", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:*/path#anchor", ""));
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:8000/", ""));
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:8000/path", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:8000/path?query=string", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:8000/path#anchor", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 127.0.0.1:8000/thisisa;pathwithasemicolon", ""));
-
- // script-src invalid hosts
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src http:/", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src http://", ""));
- EXPECT_FALSE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src http:/127.0.0.1", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src http:///127.0.0.1", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src http://127.0.0.1:/", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src https://127.?.0.1:*", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src https://127.0.0.1:", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src https://127.0.0.1:\t* ", ""));
-
- // script-src host wildcards
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src http://*.0.1:8000", ""));
- EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src http://*.0.1:8000/", ""));
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src http://*.0.1:*", ""));
- EXPECT_TRUE(
- ContentSecurityPolicy::IsValidCSPAttr("script-src http://*.0.1:*/", ""));
-
- // missing semicolon
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "default-src 'self' script-src example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 'self' object-src 'self' style-src *", ""));
-
- // 'none' with other sources
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src http://127.0.0.1:8000 'none'", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 'none' 'none' 'none'", ""));
-
- // comma separated
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 'none', object-src 'none'", ""));
-
- // reporting not allowed
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 'none'; report-uri http://example.com/reporting", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "report-uri relative-path/reporting;"
- "base-uri http://example.com 'self'",
- ""));
-
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "script-src 'none'; report-to http://example.com/reporting", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "report-to relative-path/reporting;"
- "base-uri http://example.com 'self'",
- ""));
-
- // CRLF should not be allowed
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri\nhttp://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri http://example.com\nhttp://example2.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base\n-uri http://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "\nbase-uri http://example.com", ""));
-
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri\r\nhttp://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri http://example.com\r\nhttp://example2.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base\r\n-uri http://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "\r\nbase-uri http://example.com", ""));
-
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri\rhttp://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base-uri http://example.com\rhttp://example2.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "base\r-uri http://example.com", ""));
- EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
- "\rbase-uri http://example.com", ""));
-}
-
TEST_F(ContentSecurityPolicyTest, TrustedTypesNoDirective) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("", *secure_origin, ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesSimpleDirective) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one two three",
+ csp->DidReceiveHeader("trusted-types one two three", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
+ csp->DidReceiveHeader("trusted-types one\ntwo\rthree", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("two", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("three", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("one", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("two", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("three", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("one", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("trusted-types", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_FALSE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("trusted-types *", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_FALSE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesStarMix) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types abc * def",
+ csp->DidReceiveHeader("trusted-types abc * def", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("abc", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("def", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("ghi", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("abc", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("def", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("ghi", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("abc", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("def", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("ghi", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("abc", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("def", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("ghi", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypeDupe) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
csp->DidReceiveHeader("trusted-types somepolicy 'allow-duplicates'",
- ContentSecurityPolicyType::kEnforce,
+ *secure_origin, ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypeDupeStar) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types * 'allow-duplicates'",
+ csp->DidReceiveHeader("trusted-types * 'allow-duplicates'", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesReserved) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one \"two\" 'three'",
+ csp->DidReceiveHeader("trusted-types one \"two\" 'three'", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("one", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
// Quoted strings are considered 'reserved':
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", true));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'", true));
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(
+ csp->AllowTrustedTypePolicy("\"two\"", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(
+ csp->AllowTrustedTypePolicy("'three'", false, violation_details));
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypesReportingStar) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader("trusted-types *", *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypeReportingSimple) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types a b c",
+ csp->DidReceiveHeader("trusted-types a b c", *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", false));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, TrustedTypeEnforce) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
+ csp->DidReceiveHeader("trusted-types one\ntwo\rthree", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_FALSE(csp->IsRequireTrustedTypes());
@@ -1178,7 +1038,7 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypeEnforce) {
TEST_F(ContentSecurityPolicyTest, TrustedTypeReport) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
+ csp->DidReceiveHeader("trusted-types one\ntwo\rthree", *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_FALSE(csp->IsRequireTrustedTypes());
@@ -1187,9 +1047,10 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypeReport) {
TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndEnforce) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one", ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader("trusted-types one", *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- csp->DidReceiveHeader("trusted-types two",
+ csp->DidReceiveHeader("trusted-types two", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_FALSE(csp->IsRequireTrustedTypes());
@@ -1198,9 +1059,11 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndEnforce) {
TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndNonTTEnforce) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types one", ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader("trusted-types one", *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
- csp->DidReceiveHeader("script-src none", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("script-src none", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_FALSE(csp->IsRequireTrustedTypes());
EXPECT_TRUE(csp->AllowTrustedTypeAssignmentFailure("blabla"));
@@ -1209,12 +1072,12 @@ TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndNonTTEnforce) {
TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForEnforce) {
execution_context->GetSecurityContext().SetRequireTrustedTypesForTesting();
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("require-trusted-types-for ''",
+ csp->DidReceiveHeader("require-trusted-types-for ''", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_FALSE(csp->IsRequireTrustedTypes());
- csp->DidReceiveHeader("require-trusted-types-for 'script'",
+ csp->DidReceiveHeader("require-trusted-types-for 'script'", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(csp->IsRequireTrustedTypes());
@@ -1223,7 +1086,7 @@ TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForEnforce) {
TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForReport) {
execution_context->GetSecurityContext().SetRequireTrustedTypesForTesting();
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("require-trusted-types-for 'script'",
+ csp->DidReceiveHeader("require-trusted-types-for 'script'", *secure_origin,
ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
EXPECT_TRUE(csp->IsRequireTrustedTypes());
@@ -1231,10 +1094,18 @@ TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForReport) {
TEST_F(ContentSecurityPolicyTest, DefaultPolicy) {
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader("trusted-types *", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("default", false));
- EXPECT_FALSE(csp->AllowTrustedTypePolicy("default", true));
+
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+ EXPECT_TRUE(csp->AllowTrustedTypePolicy("default", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_FALSE(csp->AllowTrustedTypePolicy("default", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
}
TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
@@ -1243,7 +1114,7 @@ TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
// Directive name is case insensitive.
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader("sCrIpt-sRc http://example.com",
+ csp->DidReceiveHeader("sCrIpt-sRc http://example.com", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
@@ -1260,7 +1131,8 @@ TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
csp = MakeGarbageCollected<ContentSecurityPolicy>();
csp->DidReceiveHeader(
"SCRipt-SRC http://example.com; script-src http://not-example.com;",
- ContentSecurityPolicyType::kEnforce, ContentSecurityPolicySource::kHTTP);
+ *secure_origin, ContentSecurityPolicyType::kEnforce,
+ ContentSecurityPolicySource::kHTTP);
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
EXPECT_TRUE(csp->AllowScriptFromSource(
@@ -1286,7 +1158,6 @@ TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
auto* element =
MakeGarbageCollected<HTMLScriptElement>(*document, CreateElementFlags());
- EXPECT_TRUE(csp->Headers().IsEmpty());
EXPECT_TRUE(csp->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
element, source, String() /* nonce */,
context_url, ordinal_number));
@@ -1299,26 +1170,15 @@ TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
EXPECT_TRUE(csp->AllowWasmEval(ReportingDisposition::kReport,
ContentSecurityPolicy::kWillNotThrowException,
g_empty_string));
- EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
- "application/x-type-1", example_url));
- EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
- "application/x-type-1", example_url,
- ReportingDisposition::kSuppressReporting));
-
- ContentSecurityPolicy::DirectiveType types_to_test[] = {
- ContentSecurityPolicy::DirectiveType::kBaseURI,
- ContentSecurityPolicy::DirectiveType::kConnectSrc,
- ContentSecurityPolicy::DirectiveType::kFontSrc,
- ContentSecurityPolicy::DirectiveType::kFormAction,
- ContentSecurityPolicy::DirectiveType::kFrameSrc,
- ContentSecurityPolicy::DirectiveType::kImgSrc,
- ContentSecurityPolicy::DirectiveType::kManifestSrc,
- ContentSecurityPolicy::DirectiveType::kMediaSrc,
- ContentSecurityPolicy::DirectiveType::kObjectSrc,
- ContentSecurityPolicy::DirectiveType::kPrefetchSrc,
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem,
- ContentSecurityPolicy::DirectiveType::kWorkerSrc};
+
+ CSPDirectiveName types_to_test[] = {
+ CSPDirectiveName::BaseURI, CSPDirectiveName::ConnectSrc,
+ CSPDirectiveName::FontSrc, CSPDirectiveName::FormAction,
+ CSPDirectiveName::FrameSrc, CSPDirectiveName::ImgSrc,
+ CSPDirectiveName::ManifestSrc, CSPDirectiveName::MediaSrc,
+ CSPDirectiveName::ObjectSrc, CSPDirectiveName::PrefetchSrc,
+ CSPDirectiveName::ScriptSrcElem, CSPDirectiveName::StyleSrcElem,
+ CSPDirectiveName::WorkerSrc};
for (auto type : types_to_test) {
EXPECT_TRUE(
csp->AllowFromSource(type, example_url, example_url,
@@ -1338,8 +1198,16 @@ TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
example_url, nonce, IntegrityMetadataSet(), kParserInserted, example_url,
ResourceRequest::RedirectStatus::kNoRedirect));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
- EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", true, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_TRUE(
+ csp->AllowTrustedTypePolicy("somepolicy", false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
EXPECT_TRUE(csp->AllowInline(ContentSecurityPolicy::InlineType::kScript,
element, source, nonce, context_url,
ordinal_number));
@@ -1370,9 +1238,9 @@ TEST_F(ContentSecurityPolicyTest, OpaqueOriginBeforeBind) {
// are applied. This shouldn't change the application of the 'self'
// determination.
secure_origin = secure_origin->DeriveNewOpaqueOrigin();
- execution_context = CreateExecutionContext();
+ CreateExecutionContext();
csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
- csp->DidReceiveHeader("default-src 'self';",
+ csp->DidReceiveHeader("default-src 'self';", *secure_origin,
ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kMeta);
EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
@@ -1383,6 +1251,32 @@ TEST_F(ContentSecurityPolicyTest, OpaqueOriginBeforeBind) {
ReportingDisposition::kSuppressReporting));
}
+TEST_F(ContentSecurityPolicyTest, SelfForDataMatchesNothing) {
+ const KURL url("https://example.test");
+ auto reference_origin = SecurityOrigin::Create(url);
+ const KURL data_url("data:text/html,hello");
+ secure_origin = SecurityOrigin::CreateWithReferenceOrigin(
+ data_url, reference_origin.get());
+
+ CreateExecutionContext();
+ csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
+ csp->DidReceiveHeader("default-src 'self';", *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
+ ContentSecurityPolicySource::kMeta);
+ EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
+ network::mojom::RequestDestination::kEmpty, url,
+ String(), IntegrityMetadataSet(),
+ kParserInserted, url,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting));
+ EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
+ network::mojom::RequestDestination::kEmpty,
+ data_url, String(), IntegrityMetadataSet(),
+ kParserInserted, url,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting));
+}
+
TEST_F(ContentSecurityPolicyTest, ReasonableRestrictionMetrics) {
struct TestCase {
const char* header;
@@ -1415,7 +1309,8 @@ TEST_F(ContentSecurityPolicyTest, ReasonableRestrictionMetrics) {
SCOPED_TRACE(testing::Message()
<< "[Enforce] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
auto dummy = std::make_unique<DummyPageHolder>();
csp->BindToDelegate(
@@ -1441,7 +1336,8 @@ TEST_F(ContentSecurityPolicyTest, ReasonableRestrictionMetrics) {
SCOPED_TRACE(testing::Message()
<< "[ReportOnly] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
auto dummy = std::make_unique<DummyPageHolder>();
csp->BindToDelegate(
@@ -1491,7 +1387,8 @@ TEST_F(ContentSecurityPolicyTest, BetterThanReasonableRestrictionMetrics) {
SCOPED_TRACE(testing::Message()
<< "[Enforce] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicySource::kHTTP);
auto dummy = std::make_unique<DummyPageHolder>();
csp->BindToDelegate(
@@ -1507,7 +1404,8 @@ TEST_F(ContentSecurityPolicyTest, BetterThanReasonableRestrictionMetrics) {
SCOPED_TRACE(testing::Message()
<< "[ReportOnly] Header: `" << test.header << "`");
csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
+ csp->DidReceiveHeader(test.header, *secure_origin,
+ ContentSecurityPolicyType::kReport,
ContentSecurityPolicySource::kHTTP);
auto dummy = std::make_unique<DummyPageHolder>();
csp->BindToDelegate(
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.cc b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.cc
new file mode 100644
index 00000000000..2984fd3252e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.cc
@@ -0,0 +1,191 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
+
+namespace blink {
+
+namespace {
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+WebCSPSource ConvertToPublic(network::mojom::blink::CSPSourcePtr source) {
+ return {source->scheme,
+ source->host,
+ source->port,
+ source->path,
+ source->is_host_wildcard,
+ source->is_port_wildcard};
+}
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+WebCSPHashSource ConvertToPublic(
+ network::mojom::blink::CSPHashSourcePtr hash_source) {
+ return {hash_source->algorithm, std::move(hash_source->value)};
+}
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+WebCSPSourceList ConvertToPublic(
+ network::mojom::blink::CSPSourceListPtr source_list) {
+ WebVector<WebCSPSource> sources(source_list->sources.size());
+ for (size_t i = 0; i < sources.size(); ++i)
+ sources[i] = ConvertToPublic(std::move(source_list->sources[i]));
+ WebVector<WebCSPHashSource> hashes(source_list->hashes.size());
+ for (size_t i = 0; i < hashes.size(); ++i)
+ hashes[i] = ConvertToPublic(std::move(source_list->hashes[i]));
+ return {std::move(sources),
+ std::move(source_list->nonces),
+ std::move(hashes),
+ source_list->allow_self,
+ source_list->allow_star,
+ source_list->allow_response_redirects,
+ source_list->allow_inline,
+ source_list->allow_eval,
+ source_list->allow_wasm_eval,
+ source_list->allow_dynamic,
+ source_list->allow_unsafe_hashes,
+ source_list->report_sample};
+}
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+base::Optional<WebCSPTrustedTypes> ConvertToPublic(
+ network::mojom::blink::CSPTrustedTypesPtr trusted_types) {
+ if (!trusted_types)
+ return base::nullopt;
+ return WebCSPTrustedTypes{std::move(trusted_types->list),
+ trusted_types->allow_any,
+ trusted_types->allow_duplicates};
+}
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+WebContentSecurityPolicyHeader ConvertToPublic(
+ network::mojom::blink::ContentSecurityPolicyHeaderPtr header) {
+ return {header->header_value, header->type, header->source};
+}
+
+Vector<String> ConvertToWTF(const WebVector<blink::WebString>& list_in) {
+ Vector<String> list_out;
+ for (const auto& element : list_in)
+ list_out.emplace_back(element);
+ return list_out;
+}
+
+network::mojom::blink::CSPSourcePtr ConvertToMojoBlink(
+ const WebCSPSource& source) {
+ return network::mojom::blink::CSPSource::New(
+ source.scheme, source.host, source.port, source.path,
+ source.is_host_wildcard, source.is_port_wildcard);
+}
+
+network::mojom::blink::CSPHashSourcePtr ConvertToMojoBlink(
+ const WebCSPHashSource& hash_source) {
+ Vector<uint8_t> hash_value;
+ for (uint8_t el : hash_source.value)
+ hash_value.emplace_back(el);
+ return network::mojom::blink::CSPHashSource::New(hash_source.algorithm,
+ std::move(hash_value));
+}
+
+network::mojom::blink::CSPSourceListPtr ConvertToMojoBlink(
+ const WebCSPSourceList& source_list) {
+ Vector<network::mojom::blink::CSPSourcePtr> sources;
+ for (const auto& source : source_list.sources)
+ sources.push_back(ConvertToMojoBlink(source));
+
+ Vector<network::mojom::blink::CSPHashSourcePtr> hashes;
+ for (const auto& hash : source_list.hashes)
+ hashes.push_back(ConvertToMojoBlink(hash));
+
+ return network::mojom::blink::CSPSourceList::New(
+ std::move(sources), ConvertToWTF(source_list.nonces), std::move(hashes),
+ source_list.allow_self, source_list.allow_star,
+ source_list.allow_response_redirects, source_list.allow_inline,
+ source_list.allow_eval, source_list.allow_wasm_eval,
+ source_list.allow_dynamic, source_list.allow_unsafe_hashes,
+ source_list.report_sample);
+}
+
+} // namespace
+
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+WebContentSecurityPolicy ConvertToPublic(
+ network::mojom::blink::ContentSecurityPolicyPtr policy) {
+ WebVector<WebContentSecurityPolicyDirective> directives(
+ policy->directives.size());
+ size_t i = 0;
+ for (auto& directive : policy->directives) {
+ directives[i++] = {directive.key,
+ ConvertToPublic(std::move(directive.value))};
+ }
+
+ WebVector<WebContentSecurityPolicyRawDirective> raw_directives(
+ policy->raw_directives.size());
+ i = 0;
+ for (auto& directive : policy->raw_directives) {
+ raw_directives[i++] = {directive.key, std::move(directive.value)};
+ }
+
+ return {ConvertToPublic(std::move(policy->self_origin)),
+ std::move(raw_directives),
+ std::move(directives),
+ policy->upgrade_insecure_requests,
+ policy->treat_as_public_address,
+ policy->block_all_mixed_content,
+ policy->sandbox,
+ ConvertToPublic(std::move(policy->header)),
+ policy->use_reporting_api,
+ std::move(policy->report_endpoints),
+ policy->require_trusted_types_for,
+ ConvertToPublic(std::move(policy->trusted_types)),
+ std::move(policy->parsing_errors)};
+}
+
+network::mojom::blink::ContentSecurityPolicyPtr ConvertToMojoBlink(
+ const WebContentSecurityPolicy& policy_in) {
+ HashMap<network::mojom::CSPDirectiveName, String> raw_directives;
+ for (const auto& directive : policy_in.raw_directives) {
+ raw_directives.insert(directive.name, directive.value);
+ }
+
+ HashMap<network::mojom::CSPDirectiveName,
+ network::mojom::blink::CSPSourceListPtr>
+ directives;
+ for (const auto& directive : policy_in.directives) {
+ directives.insert(directive.name,
+ ConvertToMojoBlink(directive.source_list));
+ }
+
+ return network::mojom::blink::ContentSecurityPolicy::New(
+ ConvertToMojoBlink(policy_in.self_origin), std::move(raw_directives),
+ std::move(directives), policy_in.upgrade_insecure_requests,
+ policy_in.treat_as_public_address, policy_in.block_all_mixed_content,
+ policy_in.sandbox,
+ network::mojom::blink::ContentSecurityPolicyHeader::New(
+ policy_in.header.header_value, policy_in.header.type,
+ policy_in.header.source),
+ policy_in.use_reporting_api, ConvertToWTF(policy_in.report_endpoints),
+ policy_in.require_trusted_types_for,
+ policy_in.trusted_types ? network::mojom::blink::CSPTrustedTypes::New(
+ ConvertToWTF(policy_in.trusted_types->list),
+ policy_in.trusted_types->allow_any,
+ policy_in.trusted_types->allow_duplicates)
+ : nullptr,
+ ConvertToWTF(policy_in.parsing_errors));
+}
+
+Vector<network::mojom::blink::ContentSecurityPolicyPtr> ConvertToMojoBlink(
+ const WebVector<WebContentSecurityPolicy>& list_in) {
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> list_out;
+ for (const auto& element : list_in)
+ list_out.emplace_back(ConvertToMojoBlink(element));
+ return list_out;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.h b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.h
new file mode 100644
index 00000000000..b84c0bff61b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util.h
@@ -0,0 +1,37 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CONVERSION_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CONVERSION_UTIL_H_
+
+#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
+#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
+#include "third_party/blink/renderer/core/core_export.h"
+
+namespace blink {
+
+// Convert a ContentSecurityPolicy into a WebContentSecurityPolicy. These two
+// classes represent the exact same thing, but one is public, the other is
+// private.
+// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
+// from blink.
+CORE_EXPORT
+WebContentSecurityPolicy ConvertToPublic(
+ network::mojom::blink::ContentSecurityPolicyPtr policy);
+
+// Convert a WebContentSecurityPolicy into a ContentSecurityPolicy. These two
+// classes represent the exact same thing, but one is in public, the other is
+// private.
+CORE_EXPORT
+network::mojom::blink::ContentSecurityPolicyPtr ConvertToMojoBlink(
+ const WebContentSecurityPolicy& policy);
+
+// Helper function that applies ConvertToBlink above to a WebVector.
+CORE_EXPORT
+Vector<network::mojom::blink::ContentSecurityPolicyPtr> ConvertToMojoBlink(
+ const WebVector<WebContentSecurityPolicy>& policy);
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_fuzzer.cc b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_fuzzer.cc
new file mode 100644
index 00000000000..b8b7b192b4e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_fuzzer.cc
@@ -0,0 +1,77 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
+
+ // We need two pieces of input: a URL and a CSP string. Split |data| in two at
+ // the first whitespace.
+ const uint8_t* it = data;
+ for (; it < data + size; it++) {
+ if (base::IsAsciiWhitespace(*reinterpret_cast<const char*>(it))) {
+ it++;
+ break;
+ }
+ }
+ if (it == data + size) {
+ // Not much point in going on with an empty CSP string.
+ return EXIT_SUCCESS;
+ }
+
+ String url = String(data, it - 1 - data);
+ String header = String(it, size - (it - data));
+ unsigned hash = header.IsNull() ? 0 : header.Impl()->GetHash();
+
+ // Use the 'hash' value to pick header_type and header_source input.
+ // 1st bit: header type.
+ // 2nd bit: header source: HTTP (or other)
+ // 3rd bit: header source: Meta or OriginPolicy (if not HTTP)
+ network::mojom::ContentSecurityPolicyType header_type =
+ hash & 0x01 ? network::mojom::ContentSecurityPolicyType::kEnforce
+ : network::mojom::ContentSecurityPolicyType::kReport;
+ network::mojom::ContentSecurityPolicySource header_source =
+ network::mojom::ContentSecurityPolicySource::kHTTP;
+ if (hash & 0x02) {
+ header_source =
+ (hash & 0x04)
+ ? network::mojom::ContentSecurityPolicySource::kMeta
+ : network::mojom::ContentSecurityPolicySource::kOriginPolicy;
+ }
+
+ scoped_refptr<SecurityOrigin> self_origin = SecurityOrigin::Create(KURL(url));
+
+ // Construct a policy from the string.
+ auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
+ csp->DidReceiveHeader(header, *self_origin, header_type, header_source);
+
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>&
+ parsed_policies = csp->GetParsedPolicies();
+ if (parsed_policies.size() > 0) {
+ network::mojom::blink::ContentSecurityPolicyPtr converted_csp =
+ ConvertToMojoBlink(ConvertToPublic(parsed_policies[0]->Clone()));
+ CHECK(converted_csp->Equals(*parsed_policies[0]));
+ }
+
+ // Force a garbage collection.
+ // Specify namespace explicitly. Otherwise it conflicts on Mac OS X with:
+ // CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Threads.h.
+ ThreadState::Current()->CollectAllGarbageForTesting(
+ BlinkGC::kNoHeapPointersOnStack);
+
+ return 0;
+}
+
+} // namespace blink
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ return blink::LLVMFuzzerTestOneInput(data, size);
+}
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_test.cc
new file mode 100644
index 00000000000..89823c266d1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/conversion_util_test.cc
@@ -0,0 +1,165 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
+
+#include "services/network/public/cpp/web_sandbox_flags.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(ContentSecurityPolicyConversionUtilTest, BackAndForthConversion) {
+ using network::mojom::blink::ContentSecurityPolicy;
+ using network::mojom::blink::ContentSecurityPolicyHeader;
+ using network::mojom::blink::CSPDirectiveName;
+ using network::mojom::blink::CSPTrustedTypes;
+
+ auto basic_csp = ContentSecurityPolicy::New(
+ network::mojom::blink::CSPSource::New("http", "www.example.org", 80, "",
+ false, false),
+ HashMap<CSPDirectiveName, String>(),
+ HashMap<CSPDirectiveName, network::mojom::blink::CSPSourceListPtr>(),
+ false, false, false, network::mojom::blink::WebSandboxFlags::kNone,
+ ContentSecurityPolicyHeader::New(
+ "my-csp", network::mojom::blink::ContentSecurityPolicyType::kEnforce,
+ network::mojom::blink::ContentSecurityPolicySource::kHTTP),
+ false, Vector<String>(),
+ network::mojom::blink::CSPRequireTrustedTypesFor::None, nullptr,
+ Vector<String>());
+
+ using ModifyCSP = void(ContentSecurityPolicy&);
+ ModifyCSP* test_cases[] = {
+ [](ContentSecurityPolicy& csp) {},
+ [](ContentSecurityPolicy& csp) {
+ csp.raw_directives.insert(CSPDirectiveName::ScriptSrc, "'none'");
+ csp.raw_directives.insert(
+ CSPDirectiveName::DefaultSrc,
+ " http://www.example.org:443/path 'self' invalid ");
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.raw_directives.insert(CSPDirectiveName::ScriptSrc, "'none'");
+ csp.raw_directives.insert(
+ CSPDirectiveName::DefaultSrc,
+ " http://www.example.org:443/path 'self' invalid ");
+ },
+ [](ContentSecurityPolicy& csp) { csp.upgrade_insecure_requests = true; },
+ [](ContentSecurityPolicy& csp) { csp.treat_as_public_address = true; },
+ [](ContentSecurityPolicy& csp) { csp.block_all_mixed_content = true; },
+ [](ContentSecurityPolicy& csp) {
+ csp.sandbox = network::mojom::blink::WebSandboxFlags::kPointerLock |
+ network::mojom::blink::WebSandboxFlags::kDownloads;
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.header = ContentSecurityPolicyHeader::New(
+ "my-csp", network::mojom::blink::ContentSecurityPolicyType::kReport,
+ network::mojom::blink::ContentSecurityPolicySource::kMeta);
+ },
+ [](ContentSecurityPolicy& csp) { csp.use_reporting_api = true; },
+ [](ContentSecurityPolicy& csp) {
+ csp.report_endpoints = {"endpoint1", "endpoint2"};
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.require_trusted_types_for =
+ network::mojom::blink::CSPRequireTrustedTypesFor::Script;
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.trusted_types = CSPTrustedTypes::New();
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.trusted_types = CSPTrustedTypes::New(
+ Vector<String>({"policy1", "policy2"}), false, false);
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.trusted_types = CSPTrustedTypes::New(
+ Vector<String>({"policy1", "policy2"}), true, false);
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.trusted_types = CSPTrustedTypes::New(
+ Vector<String>({"policy1", "policy2"}), false, true);
+ },
+ [](ContentSecurityPolicy& csp) {
+ csp.parsing_errors = {"error1", "error2"};
+ },
+ };
+
+ for (const auto& modify_csp : test_cases) {
+ auto test_csp = basic_csp.Clone();
+ (*modify_csp)(*test_csp);
+ EXPECT_EQ(ConvertToMojoBlink(ConvertToPublic(test_csp.Clone())), test_csp);
+ }
+}
+
+TEST(ContentSecurityPolicyConversionUtilTest,
+ BackAndForthConversionForCSPSourceList) {
+ using network::mojom::blink::ContentSecurityPolicy;
+ using network::mojom::blink::CSPDirectiveName;
+ using network::mojom::blink::CSPSource;
+ using network::mojom::blink::CSPSourceList;
+
+ auto basic_csp = ContentSecurityPolicy::New(
+ CSPSource::New("http", "www.example.org", 80, "", false, false),
+ HashMap<CSPDirectiveName, String>(),
+ HashMap<CSPDirectiveName, network::mojom::blink::CSPSourceListPtr>(),
+ false, false, false, network::mojom::blink::WebSandboxFlags::kNone,
+ network::mojom::blink::ContentSecurityPolicyHeader::New(
+ "my-csp", network::mojom::blink::ContentSecurityPolicyType::kEnforce,
+ network::mojom::blink::ContentSecurityPolicySource::kHTTP),
+ false, Vector<String>(),
+ network::mojom::blink::CSPRequireTrustedTypesFor::None, nullptr,
+ Vector<String>());
+
+ using ModifyCSP = void(CSPSourceList&);
+ ModifyCSP* test_cases[] = {
+ [](CSPSourceList& source_list) {},
+ [](CSPSourceList& source_list) {
+ source_list.sources.emplace_back(
+ CSPSource::New("http", "www.example.org", 80, "", false, false));
+ source_list.sources.emplace_back(CSPSource::New(
+ "http", "www.example.org", -1, "/path", false, false));
+ source_list.sources.emplace_back(
+ CSPSource::New("http", "www.example.org", 80, "", true, false));
+ source_list.sources.emplace_back(
+ CSPSource::New("http", "www.example.org", 8080, "", false, true));
+ },
+ [](CSPSourceList& source_list) {
+ source_list.nonces.emplace_back("nonce-abc");
+ source_list.nonces.emplace_back("nonce-cde");
+ },
+ [](CSPSourceList& source_list) {
+ source_list.hashes.emplace_back(
+ network::mojom::blink::CSPHashSource::New(
+ network::mojom::blink::CSPHashAlgorithm::SHA256,
+ Vector<uint8_t>({'a', 'd'})));
+ source_list.hashes.emplace_back(
+ network::mojom::blink::CSPHashSource::New(
+ network::mojom::blink::CSPHashAlgorithm::SHA384,
+ Vector<uint8_t>({'c', 'd', 'e'})));
+ },
+ [](CSPSourceList& source_list) { source_list.allow_self = true; },
+ [](CSPSourceList& source_list) { source_list.allow_star = true; },
+ [](CSPSourceList& source_list) {
+ source_list.allow_response_redirects = true;
+ },
+ [](CSPSourceList& source_list) { source_list.allow_inline = true; },
+ [](CSPSourceList& source_list) { source_list.allow_eval = true; },
+ [](CSPSourceList& source_list) { source_list.allow_wasm_eval = true; },
+ [](CSPSourceList& source_list) { source_list.allow_dynamic = true; },
+ [](CSPSourceList& source_list) {
+ source_list.allow_unsafe_hashes = true;
+ },
+ [](CSPSourceList& source_list) { source_list.report_sample = true; },
+ };
+
+ for (const auto& modify_csp : test_cases) {
+ auto test_csp = basic_csp.Clone();
+ auto script_src = CSPSourceList::New();
+ (*modify_csp)(*script_src);
+ test_csp->directives.insert(CSPDirectiveName::ScriptSrc,
+ std::move(script_src));
+ EXPECT_EQ(ConvertToMojoBlink(ConvertToPublic(test_csp.Clone())), test_csp);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive.h
deleted file mode 100644
index bdbfdbd70a8..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class CORE_EXPORT CSPDirective : public GarbageCollected<CSPDirective> {
- public:
- CSPDirective(const String& name,
- const String& value,
- ContentSecurityPolicy* policy)
- : name_(name), text_(name + ' ' + value), policy_(policy) {}
- virtual ~CSPDirective() = default;
- virtual void Trace(Visitor* visitor) const { visitor->Trace(policy_); }
-
- const String& GetName() const { return name_; }
- const String& GetText() const { return text_; }
-
- protected:
- ContentSecurityPolicy* Policy() const { return policy_; }
-
- private:
- String name_;
- String text_;
- Member<ContentSecurityPolicy> policy_;
-
- DISALLOW_COPY_AND_ASSIGN(CSPDirective);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index 894c0f59fd8..76590740ee6 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/content_security_policy.mojom-shared.h"
@@ -14,9 +15,11 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/space_split_string.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h"
+#include "third_party/blink/renderer/core/frame/csp/source_list_directive.h"
+#include "third_party/blink/renderer/core/frame/csp/trusted_types_directive.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
#include "third_party/blink/renderer/core/html/html_script_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
@@ -25,6 +28,7 @@
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/weborigin/known_ports.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
@@ -34,8 +38,21 @@
namespace blink {
+using network::mojom::ContentSecurityPolicySource;
+using network::mojom::ContentSecurityPolicyType;
+
namespace {
+String GetRawDirectiveForMessage(
+ const HashMap<CSPDirectiveName, String> raw_directives,
+ CSPDirectiveName directive_name) {
+ StringBuilder builder;
+ builder.Append(ContentSecurityPolicy::GetDirectiveName(directive_name));
+ builder.Append(" ");
+ builder.Append(raw_directives.at(directive_name));
+ return builder.ToString();
+}
+
String GetSha256String(const String& content) {
DigestValue digest;
StringUTF8Adaptor utf8_content(content);
@@ -48,39 +65,41 @@ String GetSha256String(const String& content) {
return "sha256-" + Base64Encode(digest);
}
-ContentSecurityPolicyHashAlgorithm ConvertHashAlgorithmToCSPHashAlgorithm(
+network::mojom::blink::CSPHashAlgorithm ConvertHashAlgorithmToCSPHashAlgorithm(
IntegrityAlgorithm algorithm) {
+ // TODO(antoniosartori): Consider merging these two enums.
switch (algorithm) {
case IntegrityAlgorithm::kSha256:
- return kContentSecurityPolicyHashAlgorithmSha256;
+ return network::mojom::blink::CSPHashAlgorithm::SHA256;
case IntegrityAlgorithm::kSha384:
- return kContentSecurityPolicyHashAlgorithmSha384;
+ return network::mojom::blink::CSPHashAlgorithm::SHA384;
case IntegrityAlgorithm::kSha512:
- return kContentSecurityPolicyHashAlgorithmSha512;
+ return network::mojom::blink::CSPHashAlgorithm::SHA512;
}
NOTREACHED();
- return kContentSecurityPolicyHashAlgorithmNone;
+ return network::mojom::blink::CSPHashAlgorithm::None;
}
// IntegrityMetadata (from SRI) has base64-encoded digest values, but CSP uses
// binary format. This converts from the former to the latter.
-bool ParseBase64Digest(String base64, DigestValue* hash) {
- Vector<char> hash_vector;
+bool ParseBase64Digest(String base64, Vector<uint8_t>& hash) {
+ DCHECK(hash.IsEmpty());
+
// We accept base64url-encoded data here by normalizing it to base64.
- if (!Base64Decode(NormalizeToBase64(base64), hash_vector))
+ Vector<char> out;
+ if (!Base64Decode(NormalizeToBase64(base64), out))
return false;
- if (hash_vector.IsEmpty() || hash_vector.size() > kMaxDigestSize)
+ if (out.IsEmpty() || out.size() > kMaxDigestSize)
return false;
- hash->Append(reinterpret_cast<uint8_t*>(hash_vector.data()),
- hash_vector.size());
+ for (char el : out)
+ hash.push_back(el);
return true;
}
// https://w3c.github.io/webappsec-csp/#effective-directive-for-inline-check
// TODO(hiroshige): The following two methods are slightly different.
// Investigate the correct behavior and merge them.
-ContentSecurityPolicy::DirectiveType
-GetDirectiveTypeForAllowInlineFromInlineType(
+CSPDirectiveName GetDirectiveTypeForAllowInlineFromInlineType(
ContentSecurityPolicy::InlineType inline_type) {
// 1. Switch on type: [spec text]
switch (inline_type) {
@@ -89,363 +108,658 @@ GetDirectiveTypeForAllowInlineFromInlineType(
// 1. Return script-src-elem. [spec text]
case ContentSecurityPolicy::InlineType::kScript:
case ContentSecurityPolicy::InlineType::kNavigation:
- return ContentSecurityPolicy::DirectiveType::kScriptSrcElem;
+ return CSPDirectiveName::ScriptSrcElem;
// "script attribute":
// 1. Return script-src-attr. [spec text]
case ContentSecurityPolicy::InlineType::kScriptAttribute:
- return ContentSecurityPolicy::DirectiveType::kScriptSrcAttr;
+ return CSPDirectiveName::ScriptSrcAttr;
// "style":
// 1. Return style-src-elem. [spec text]
case ContentSecurityPolicy::InlineType::kStyle:
- return ContentSecurityPolicy::DirectiveType::kStyleSrcElem;
+ return CSPDirectiveName::StyleSrcElem;
// "style attribute":
// 1. Return style-src-attr. [spec text]
case ContentSecurityPolicy::InlineType::kStyleAttribute:
- return ContentSecurityPolicy::DirectiveType::kStyleSrcAttr;
+ return CSPDirectiveName::StyleSrcAttr;
}
}
-ContentSecurityPolicy::DirectiveType GetDirectiveTypeForAllowHashFromInlineType(
+CSPDirectiveName GetDirectiveTypeForAllowHashFromInlineType(
ContentSecurityPolicy::InlineType inline_type) {
switch (inline_type) {
case ContentSecurityPolicy::InlineType::kScript:
- return ContentSecurityPolicy::DirectiveType::kScriptSrcElem;
+ return CSPDirectiveName::ScriptSrcElem;
case ContentSecurityPolicy::InlineType::kNavigation:
case ContentSecurityPolicy::InlineType::kScriptAttribute:
- return ContentSecurityPolicy::DirectiveType::kScriptSrcAttr;
+ return CSPDirectiveName::ScriptSrcAttr;
case ContentSecurityPolicy::InlineType::kStyleAttribute:
- return ContentSecurityPolicy::DirectiveType::kStyleSrcAttr;
+ return CSPDirectiveName::StyleSrcAttr;
case ContentSecurityPolicy::InlineType::kStyle:
- return ContentSecurityPolicy::DirectiveType::kStyleSrcElem;
+ return CSPDirectiveName::StyleSrcElem;
}
}
-} // namespace
+CSPOperativeDirective OperativeDirective(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ CSPDirectiveName type,
+ CSPDirectiveName original_type = CSPDirectiveName::Unknown) {
+ if (type == CSPDirectiveName::Unknown) {
+ return CSPOperativeDirective{CSPDirectiveName::Unknown, nullptr};
+ }
-using network::mojom::ContentSecurityPolicySource;
-using network::mojom::ContentSecurityPolicyType;
+ if (original_type == CSPDirectiveName::Unknown) {
+ original_type = type;
+ }
-CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy,
- ContentSecurityPolicyType type,
- ContentSecurityPolicySource source)
- : policy_(policy),
- header_type_(type),
- header_source_(source),
- has_sandbox_policy_(false),
- strict_mixed_content_checking_enforced_(false),
- upgrade_insecure_requests_(false),
- use_reporting_api_(false) {}
-
-CSPDirectiveList* CSPDirectiveList::Create(ContentSecurityPolicy* policy,
- const UChar* begin,
- const UChar* end,
- ContentSecurityPolicyType type,
- ContentSecurityPolicySource source,
- bool should_parse_wasm_eval) {
- CSPDirectiveList* directives =
- MakeGarbageCollected<CSPDirectiveList>(policy, type, source);
- directives->Parse(begin, end, should_parse_wasm_eval);
-
- if (!directives->CheckEval(directives->OperativeDirective(
- ContentSecurityPolicy::DirectiveType::kScriptSrc))) {
- String message =
- "Refused to evaluate a string as JavaScript because 'unsafe-eval' is "
- "not an allowed source of script in the following Content Security "
- "Policy directive: \"" +
- directives
- ->OperativeDirective(
- ContentSecurityPolicy::DirectiveType::kScriptSrc)
- ->GetText() +
- "\".\n";
- directives->SetEvalDisabledErrorMessage(message);
- } else if (directives->RequiresTrustedTypes()) {
- String message =
- "Refused to evaluate a string as JavaScript because this document "
- "requires 'Trusted Type' assignment.";
- directives->SetEvalDisabledErrorMessage(message);
+ const auto directive = csp.directives.find(type);
+
+ // If the directive does not exist, rely on the fallback directive.
+ return (directive != csp.directives.end())
+ ? CSPOperativeDirective{type, directive->value.get()}
+ : OperativeDirective(
+ csp, network::CSPFallbackDirective(type, original_type),
+ original_type);
+}
+
+bool ParseBlockAllMixedContent(const String& name,
+ const String& value,
+ ContentSecurityPolicy* policy) {
+ if (!value.IsEmpty())
+ policy->ReportValueForEmptyDirective(name, value);
+ return true;
+}
+
+// For "report-uri" directive, this method corresponds to:
+// https://w3c.github.io/webappsec-csp/#report-violation
+// Step 3.4.2. For each token returned by splitting a string on ASCII whitespace
+// with directive's value as the input. [spec text]
+//
+// For "report-to" directive, the spec says |value| is a single token
+// but we use the same logic as "report-uri" and thus we split |value| by
+// ASCII whitespaces. The tokens after the first one are discarded in
+// ParseReportTo.
+// https://w3c.github.io/webappsec-csp/#directive-report-to
+Vector<String> ParseReportEndpoints(const String& value) {
+ Vector<UChar> characters;
+ value.AppendTo(characters);
+
+ // https://infra.spec.whatwg.org/#split-on-ascii-whitespace
+
+ // Step 2. Let tokens be a list of strings, initially empty. [spec text]
+ Vector<String> report_endpoints;
+
+ const UChar* position = characters.data();
+ const UChar* end = position + characters.size();
+
+ // Step 4. While position is not past the end of input: [spec text]
+ while (position < end) {
+ // Step 3. Skip ASCII whitespace within input given position. [spec text]
+ // Step 4.3. Skip ASCII whitespace within input given position. [spec text]
+ //
+ // Note: IsASCIISpace returns true for U+000B which is not included in
+ // https://infra.spec.whatwg.org/#ascii-whitespace.
+ // TODO(mkwst): Investigate why the restrictions in the infra spec are
+ // different than those in Blink here.
+ SkipWhile<UChar, IsASCIISpace>(position, end);
+
+ // Step 4.1. Let token be the result of collecting a sequence of code points
+ // that are not ASCII whitespace from input, given position. [spec text]
+ const UChar* endpoint_begin = position;
+ SkipWhile<UChar, IsNotASCIISpace>(position, end);
+
+ if (endpoint_begin < position) {
+ // Step 4.2. Append token to tokens. [spec text]
+ String endpoint = String(
+ endpoint_begin, static_cast<wtf_size_t>(position - endpoint_begin));
+ report_endpoints.push_back(endpoint);
+ }
}
- return directives;
+ return report_endpoints;
}
-void CSPDirectiveList::ReportViolation(
- const String& directive_text,
- const ContentSecurityPolicy::DirectiveType effective_type,
- const String& console_message,
- const KURL& blocked_url,
- ResourceRequest::RedirectStatus redirect_status,
- ContentSecurityPolicy::ContentSecurityPolicyViolationType violation_type,
- const String& sample,
- const String& sample_prefix) const {
- String message =
- IsReportOnly() ? "[Report Only] " + console_message : console_message;
- policy_->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kSecurity,
- mojom::ConsoleMessageLevel::kError, message));
- policy_->ReportViolation(directive_text, effective_type, message, blocked_url,
- report_endpoints_, use_reporting_api_, header_,
- header_type_, violation_type,
- std::unique_ptr<SourceLocation>(),
- nullptr, // localFrame
- redirect_status,
- nullptr, // Element*
- sample, sample_prefix);
+void ParseReportTo(const String& name,
+ const String& value,
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ if (!base::FeatureList::IsEnabled(network::features::kReporting))
+ return;
+
+ csp.use_reporting_api = true;
+ csp.report_endpoints = ParseReportEndpoints(value);
+
+ if (csp.report_endpoints.size() > 1) {
+ // The directive "report-to" only accepts one endpoint.
+ csp.report_endpoints.Shrink(1);
+ policy->ReportMultipleReportToEndpoints();
+ }
}
-void CSPDirectiveList::ReportViolationWithFrame(
- const String& directive_text,
- const ContentSecurityPolicy::DirectiveType effective_type,
- const String& console_message,
- const KURL& blocked_url,
- LocalFrame* frame) const {
- String message =
- IsReportOnly() ? "[Report Only] " + console_message : console_message;
- policy_->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kSecurity,
- mojom::ConsoleMessageLevel::kError, message),
- frame);
- policy_->ReportViolation(directive_text, effective_type, message, blocked_url,
- report_endpoints_, use_reporting_api_, header_,
- header_type_, ContentSecurityPolicy::kURLViolation,
- std::unique_ptr<SourceLocation>(), frame);
+void ParseReportURI(const String& name,
+ const String& value,
+ const SecurityOrigin& self_origin,
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ // report-to supersedes report-uri
+ if (csp.use_reporting_api)
+ return;
+
+ // Remove report-uri in meta policies, per
+ // https://html.spec.whatwg.org/C/#attr-meta-http-equiv-content-security-policy.
+ if (csp.header->source == ContentSecurityPolicySource::kMeta) {
+ policy->ReportInvalidDirectiveInMeta(name);
+ return;
+ }
+
+ csp.report_endpoints = ParseReportEndpoints(value);
+
+ policy->Count(csp.report_endpoints.size() > 1
+ ? WebFeature::kReportUriMultipleEndpoints
+ : WebFeature::kReportUriSingleEndpoint);
+
+ csp.report_endpoints.erase(
+ std::remove_if(csp.report_endpoints.begin(), csp.report_endpoints.end(),
+ [policy, &self_origin](const String& endpoint) {
+ KURL parsed_endpoint = KURL(endpoint);
+ if (!parsed_endpoint.IsValid()) {
+ // endpoint is not absolute, so it cannot violate
+ // MixedContent
+ return false;
+ }
+ if (MixedContentChecker::IsMixedContent(
+ self_origin.Protocol(), parsed_endpoint)) {
+ policy->ReportMixedContentReportURI(endpoint);
+ return true;
+ }
+ return false;
+ }),
+ csp.report_endpoints.end());
+}
+
+void ParseTreatAsPublicAddress(
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ // Remove treat-as-public-address directives in meta policies, per
+ // https://wicg.github.io/cors-rfc1918/#csp
+ if (csp.header->source == ContentSecurityPolicySource::kMeta) {
+ policy->ReportInvalidDirectiveInMeta("treat-as-public-address");
+ return;
+ }
+
+ // Remove treat-as-public-address directives in report-only, per
+ // https://wicg.github.io/cors-rfc1918/#csp
+ if (CSPDirectiveListIsReportOnly(csp)) {
+ policy->ReportInvalidInReportOnly("treat-as-public-address");
+ return;
+ }
+ csp.treat_as_public_address = true;
+}
+
+void ParseSandboxPolicy(const String& name,
+ const String& sandbox_policy,
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ // Remove sandbox directives in meta policies, per
+ // https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
+ if (csp.header->source == ContentSecurityPolicySource::kMeta) {
+ policy->ReportInvalidDirectiveInMeta(name);
+ return;
+ }
+ if (CSPDirectiveListIsReportOnly(csp)) {
+ policy->ReportInvalidInReportOnly(name);
+ return;
+ }
+
+ using network::mojom::blink::WebSandboxFlags;
+ WebSandboxFlags ignored_flags =
+ !RuntimeEnabledFeatures::StorageAccessAPIEnabled()
+ ? WebSandboxFlags::kStorageAccessByUserActivation
+ : WebSandboxFlags::kNone;
+
+ network::WebSandboxFlagsParsingResult parsed =
+ network::ParseWebSandboxPolicy(sandbox_policy.Utf8(), ignored_flags);
+ csp.sandbox = parsed.flags;
+ if (!parsed.error_message.empty()) {
+ policy->ReportInvalidSandboxFlags(
+ WebString::FromUTF8(parsed.error_message));
+ }
}
-void CSPDirectiveList::ReportViolationWithLocation(
+void ParseUpgradeInsecureRequests(
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& name,
+ const String& value) {
+ if (CSPDirectiveListIsReportOnly(csp)) {
+ policy->ReportInvalidInReportOnly(name);
+ return;
+ }
+ csp.upgrade_insecure_requests = true;
+
+ if (!value.IsEmpty())
+ policy->ReportValueForEmptyDirective(name, value);
+}
+
+void AddDirective(const String& name,
+ const String& value,
+ const SecurityOrigin& self_origin,
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ DCHECK(!name.IsEmpty());
+
+ CSPDirectiveName type = ContentSecurityPolicy::GetDirectiveType(name);
+
+ if (type == CSPDirectiveName::Unknown) {
+ policy->ReportUnsupportedDirective(name);
+ return;
+ }
+
+ if (!csp.raw_directives.insert(type, value).is_new_entry) {
+ policy->ReportDuplicateDirective(name);
+ return;
+ }
+
+ network::mojom::blink::CSPSourceListPtr source_list = nullptr;
+
+ switch (type) {
+ case CSPDirectiveName::BaseURI:
+ case CSPDirectiveName::ChildSrc:
+ case CSPDirectiveName::ConnectSrc:
+ case CSPDirectiveName::DefaultSrc:
+ case CSPDirectiveName::FontSrc:
+ case CSPDirectiveName::FormAction:
+ case CSPDirectiveName::FrameSrc:
+ case CSPDirectiveName::ImgSrc:
+ case CSPDirectiveName::ManifestSrc:
+ case CSPDirectiveName::MediaSrc:
+ case CSPDirectiveName::NavigateTo:
+ case CSPDirectiveName::ObjectSrc:
+ case CSPDirectiveName::ScriptSrc:
+ case CSPDirectiveName::ScriptSrcAttr:
+ case CSPDirectiveName::ScriptSrcElem:
+ case CSPDirectiveName::StyleSrc:
+ case CSPDirectiveName::StyleSrcAttr:
+ case CSPDirectiveName::StyleSrcElem:
+ case CSPDirectiveName::WorkerSrc:
+ csp.directives.insert(type, CSPSourceListParse(name, value, policy));
+ return;
+ case CSPDirectiveName::FrameAncestors:
+ // Remove frame-ancestors directives in meta policies, per
+ // https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
+ if (csp.header->source == ContentSecurityPolicySource::kMeta) {
+ policy->ReportInvalidDirectiveInMeta(name);
+ } else {
+ csp.directives.insert(type, CSPSourceListParse(name, value, policy));
+ }
+ return;
+ case CSPDirectiveName::PrefetchSrc:
+ if (!policy->ExperimentalFeaturesEnabled())
+ policy->ReportUnsupportedDirective(name);
+ else
+ csp.directives.insert(type, CSPSourceListParse(name, value, policy));
+ return;
+ case CSPDirectiveName::BlockAllMixedContent:
+ csp.block_all_mixed_content =
+ ParseBlockAllMixedContent(name, value, policy);
+ return;
+ case CSPDirectiveName::ReportTo:
+ ParseReportTo(name, value, csp, policy);
+ return;
+ case CSPDirectiveName::ReportURI:
+ ParseReportURI(name, value, self_origin, csp, policy);
+ return;
+ case CSPDirectiveName::RequireTrustedTypesFor:
+ csp.require_trusted_types_for =
+ CSPRequireTrustedTypesForParse(value, policy);
+ return;
+ case CSPDirectiveName::Sandbox:
+ ParseSandboxPolicy(name, value, csp, policy);
+ return;
+ case CSPDirectiveName::TreatAsPublicAddress:
+ ParseTreatAsPublicAddress(csp, policy);
+ return;
+ case CSPDirectiveName::TrustedTypes:
+ csp.trusted_types = CSPTrustedTypesParse(value, policy);
+ return;
+ case CSPDirectiveName::UpgradeInsecureRequests:
+ ParseUpgradeInsecureRequests(csp, policy, name, value);
+ return;
+ case CSPDirectiveName::Unknown:
+ NOTREACHED();
+ return;
+ }
+}
+
+// directive = *WSP [ directive-name [ WSP directive-value ] ]
+// directive-name = 1*( ALPHA / DIGIT / "-" )
+// directive-value = *( WSP / <VCHAR except ";"> )
+//
+bool ParseDirective(const UChar* begin,
+ const UChar* end,
+ String* name,
+ String* value,
+ ContentSecurityPolicy* policy) {
+ DCHECK(name->IsEmpty());
+ DCHECK(value->IsEmpty());
+
+ const UChar* position = begin;
+ SkipWhile<UChar, IsASCIISpace>(position, end);
+
+ // Empty directive (e.g. ";;;"). Exit early.
+ if (position == end)
+ return false;
+
+ const UChar* name_begin = position;
+ SkipWhile<UChar, IsCSPDirectiveNameCharacter>(position, end);
+
+ // The directive-name must be non-empty.
+ if (name_begin == position) {
+ // Malformed CSP: directive starts with invalid characters
+ policy->Count(WebFeature::kMalformedCSP);
+
+ SkipWhile<UChar, IsNotASCIISpace>(position, end);
+ policy->ReportUnsupportedDirective(
+ String(name_begin, static_cast<wtf_size_t>(position - name_begin)));
+ return false;
+ }
+
+ *name = String(name_begin, static_cast<wtf_size_t>(position - name_begin))
+ .LowerASCII();
+
+ if (position == end)
+ return true;
+
+ if (!SkipExactly<UChar, IsASCIISpace>(position, end)) {
+ // Malformed CSP: after the directive name we don't have a space
+ policy->Count(WebFeature::kMalformedCSP);
+
+ SkipWhile<UChar, IsNotASCIISpace>(position, end);
+ policy->ReportUnsupportedDirective(
+ String(name_begin, static_cast<wtf_size_t>(position - name_begin)));
+ return false;
+ }
+
+ SkipWhile<UChar, IsASCIISpace>(position, end);
+
+ const UChar* value_begin = position;
+ SkipWhile<UChar, IsCSPDirectiveValueCharacter>(position, end);
+
+ if (position != end) {
+ // Malformed CSP: directive value has invalid characters
+ policy->Count(WebFeature::kMalformedCSP);
+
+ policy->ReportInvalidDirectiveValueCharacter(
+ *name, String(value_begin, static_cast<wtf_size_t>(end - value_begin)));
+ return false;
+ }
+
+ // The directive-value may be empty.
+ if (value_begin == position)
+ return true;
+
+ *value = String(value_begin, static_cast<wtf_size_t>(position - value_begin));
+ return true;
+}
+
+// policy = directive-list
+// directive-list = [ directive *( ";" [ directive ] ) ]
+//
+void Parse(const UChar* begin,
+ const UChar* end,
+ const SecurityOrigin& self_origin,
+ bool should_parse_wasm_eval,
+ network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy) {
+ if (begin == end)
+ return;
+
+ const UChar* position = begin;
+ while (position < end) {
+ const UChar* directive_begin = position;
+ SkipUntil<UChar>(position, end, ';');
+
+ // |name| and |value| must always be initialized in order to avoid mojo
+ // serialization errors.
+ String name, value = "";
+ if (ParseDirective(directive_begin, position, &name, &value, policy)) {
+ DCHECK(!name.IsEmpty());
+ AddDirective(name, value, self_origin, csp, policy);
+ }
+
+ DCHECK(position == end || *position == ';');
+ SkipExactly<UChar>(position, end, ';');
+ }
+}
+
+void ReportViolation(const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& directive_text,
+ CSPDirectiveName effective_type,
+ const String& console_message,
+ const KURL& blocked_url,
+ ResourceRequest::RedirectStatus redirect_status,
+ ContentSecurityPolicy::ContentSecurityPolicyViolationType
+ violation_type = ContentSecurityPolicy::kURLViolation,
+ const String& sample = String(),
+ const String& sample_prefix = String()) {
+ String message = CSPDirectiveListIsReportOnly(csp)
+ ? "[Report Only] " + console_message
+ : console_message;
+ policy->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kSecurity,
+ mojom::ConsoleMessageLevel::kError, message));
+ policy->ReportViolation(directive_text, effective_type, message, blocked_url,
+ csp.report_endpoints, csp.use_reporting_api,
+ csp.header->header_value, csp.header->type,
+ violation_type, std::unique_ptr<SourceLocation>(),
+ nullptr, // localFrame
+ redirect_status,
+ nullptr, // Element*
+ sample, sample_prefix);
+}
+
+void ReportViolationWithLocation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
const String& directive_text,
- const ContentSecurityPolicy::DirectiveType effective_type,
+ CSPDirectiveName effective_type,
const String& console_message,
const KURL& blocked_url,
const String& context_url,
const WTF::OrdinalNumber& context_line,
Element* element,
- const String& source) const {
- String message =
- IsReportOnly() ? "[Report Only] " + console_message : console_message;
+ const String& source) {
+ String message = CSPDirectiveListIsReportOnly(csp)
+ ? "[Report Only] " + console_message
+ : console_message;
std::unique_ptr<SourceLocation> source_location =
SourceLocation::Capture(context_url, context_line.OneBasedInt(), 0);
- policy_->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
+ policy->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kSecurity,
mojom::ConsoleMessageLevel::kError, message, source_location->Clone()));
- policy_->ReportViolation(directive_text, effective_type, message, blocked_url,
- report_endpoints_, use_reporting_api_, header_,
- header_type_,
- ContentSecurityPolicy::kInlineViolation,
- std::move(source_location), nullptr, // localFrame
- RedirectStatus::kNoRedirect, element, source);
+ policy->ReportViolation(directive_text, effective_type, message, blocked_url,
+ csp.report_endpoints, csp.use_reporting_api,
+ csp.header->header_value, csp.header->type,
+ ContentSecurityPolicy::kInlineViolation,
+ std::move(source_location), nullptr, // localFrame
+ RedirectStatus::kNoRedirect, element, source);
}
-void CSPDirectiveList::ReportEvalViolation(
+void ReportEvalViolation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
const String& directive_text,
- const ContentSecurityPolicy::DirectiveType effective_type,
+ CSPDirectiveName effective_type,
const String& message,
const KURL& blocked_url,
const ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& content) const {
- String report_message = IsReportOnly() ? "[Report Only] " + message : message;
+ const String& content) {
+ String report_message =
+ CSPDirectiveListIsReportOnly(csp) ? "[Report Only] " + message : message;
// Print a console message if it won't be redundant with a
// JavaScript exception that the caller will throw. (Exceptions will
// never get thrown in report-only mode because the caller won't see
// a violation.)
- if (IsReportOnly() ||
+ if (CSPDirectiveListIsReportOnly(csp) ||
exception_status == ContentSecurityPolicy::kWillNotThrowException) {
auto* console_message = MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kSecurity,
mojom::ConsoleMessageLevel::kError, report_message);
- policy_->LogToConsole(console_message);
+ policy->LogToConsole(console_message);
}
- policy_->ReportViolation(directive_text, effective_type, message, blocked_url,
- report_endpoints_, use_reporting_api_, header_,
- header_type_, ContentSecurityPolicy::kEvalViolation,
- std::unique_ptr<SourceLocation>(), nullptr,
- RedirectStatus::kNoRedirect, nullptr, content);
+ policy->ReportViolation(directive_text, effective_type, message, blocked_url,
+ csp.report_endpoints, csp.use_reporting_api,
+ csp.header->header_value, csp.header->type,
+ ContentSecurityPolicy::kEvalViolation,
+ std::unique_ptr<SourceLocation>(), nullptr,
+ RedirectStatus::kNoRedirect, nullptr, content);
}
-bool CSPDirectiveList::CheckEval(SourceListDirective* directive) const {
- return !directive || directive->AllowEval();
+bool CheckEval(const network::mojom::blink::CSPSourceList* directive) {
+ return !directive || directive->allow_eval;
}
-bool CSPDirectiveList::CheckWasmEval(SourceListDirective* directive) const {
- return !directive || directive->AllowWasmEval();
+bool CheckWasmEval(const network::mojom::blink::CSPSourceList* directive) {
+ return !directive || directive->allow_wasm_eval;
}
-bool CSPDirectiveList::IsMatchingNoncePresent(SourceListDirective* directive,
- const String& nonce) const {
- return directive && directive->AllowNonce(nonce);
+bool CheckHash(const network::mojom::blink::CSPSourceList* directive,
+ const network::mojom::blink::CSPHashSource& hash_value) {
+ return !directive || CSPSourceListAllowHash(*directive, hash_value);
}
-bool CSPDirectiveList::AreAllMatchingHashesPresent(
- SourceListDirective* directive,
- const IntegrityMetadataSet& hashes) const {
+bool CheckUnsafeHashesAllowed(
+ const network::mojom::blink::CSPSourceList* directive) {
+ return !directive || directive->allow_unsafe_hashes;
+}
+
+bool CheckDynamic(const network::mojom::blink::CSPSourceList* directive,
+ CSPDirectiveName effective_type) {
+ // 'strict-dynamic' only applies to scripts
+ if (effective_type != CSPDirectiveName::ScriptSrc &&
+ effective_type != CSPDirectiveName::ScriptSrcAttr &&
+ effective_type != CSPDirectiveName::ScriptSrcElem &&
+ effective_type != CSPDirectiveName::WorkerSrc) {
+ return false;
+ }
+ return !directive || directive->allow_dynamic;
+}
+
+bool IsMatchingNoncePresent(
+ const network::mojom::blink::CSPSourceList* directive,
+ const String& nonce) {
+ return directive && CSPSourceListAllowNonce(*directive, nonce);
+}
+
+bool AreAllMatchingHashesPresent(
+ const network::mojom::blink::CSPSourceList* directive,
+ const IntegrityMetadataSet& hashes) {
if (!directive || hashes.IsEmpty())
return false;
for (const std::pair<String, IntegrityAlgorithm>& hash : hashes) {
// Convert the hash from integrity metadata format to CSP format.
- CSPHashValue csp_hash;
- csp_hash.first = ConvertHashAlgorithmToCSPHashAlgorithm(hash.second);
- if (!ParseBase64Digest(hash.first, &csp_hash.second))
+ network::mojom::blink::CSPHashSourcePtr csp_hash =
+ network::mojom::blink::CSPHashSource::New();
+ csp_hash->algorithm = ConvertHashAlgorithmToCSPHashAlgorithm(hash.second);
+ if (!ParseBase64Digest(hash.first, csp_hash->value))
return false;
// All integrity hashes must be listed in the CSP.
- if (!directive->AllowHash(csp_hash))
+ if (!CSPSourceListAllowHash(*directive, *csp_hash))
return false;
}
return true;
}
-bool CSPDirectiveList::CheckHash(SourceListDirective* directive,
- const CSPHashValue& hash_value) const {
- return !directive || directive->AllowHash(hash_value);
-}
-
-bool CSPDirectiveList::CheckUnsafeHashesAllowed(
- SourceListDirective* directive) const {
- return !directive || directive->AllowUnsafeHashes();
-}
-
-bool CSPDirectiveList::CheckDynamic(SourceListDirective* directive) const {
- return !directive || directive->AllowDynamic();
-}
-
-void CSPDirectiveList::ReportMixedContent(
- const KURL& blocked_url,
- ResourceRequest::RedirectStatus redirect_status) const {
- if (StrictMixedContentChecking()) {
- policy_->ReportViolation(
- ContentSecurityPolicy::GetDirectiveName(
- ContentSecurityPolicy::DirectiveType::kBlockAllMixedContent),
- ContentSecurityPolicy::DirectiveType::kBlockAllMixedContent, String(),
- blocked_url, report_endpoints_, use_reporting_api_, header_,
- header_type_, ContentSecurityPolicy::kURLViolation,
- std::unique_ptr<SourceLocation>(),
- nullptr, // contextFrame,
- redirect_status);
- }
-}
-
-bool CSPDirectiveList::AllowTrustedTypeAssignmentFailure(
- const String& message,
- const String& sample,
- const String& sample_prefix) const {
- if (!require_trusted_types_for_ || !require_trusted_types_for_->require())
- return true;
-
- ReportViolation(
- ContentSecurityPolicy::GetDirectiveName(
- ContentSecurityPolicy::DirectiveType::kRequireTrustedTypesFor),
- ContentSecurityPolicy::DirectiveType::kRequireTrustedTypesFor, message,
- KURL(), RedirectStatus::kNoRedirect,
- ContentSecurityPolicy::kTrustedTypesSinkViolation, sample, sample_prefix);
- return IsReportOnly();
-}
-
-bool CSPDirectiveList::CheckSource(
- SourceListDirective* directive,
- const KURL& url,
- ResourceRequest::RedirectStatus redirect_status) const {
+bool CheckSource(ContentSecurityPolicy* policy,
+ const network::mojom::blink::CSPSourceList* directive,
+ const network::mojom::blink::CSPSource& self_origin,
+ const KURL& url,
+ ResourceRequest::RedirectStatus redirect_status) {
// If |url| is empty, fall back to the policy URL to ensure that <object>'s
// without a `src` can be blocked/allowed, as they can still load plugins
// even though they don't actually have a URL.
- return !directive ||
- directive->Allows(
- url.IsEmpty() ? policy_->FallbackUrlForPlugin() : url,
- redirect_status);
-}
-
-bool CSPDirectiveList::CheckMediaType(MediaListDirective* directive,
- const String& type,
- const String& type_attribute) const {
if (!directive)
return true;
- if (type_attribute.IsEmpty() || type_attribute.StripWhiteSpace() != type)
- return false;
- return directive->Allows(type);
+
+ return CSPSourceListAllows(
+ *directive, self_origin,
+ url.IsEmpty() ? policy->FallbackUrlForPlugin() : url, redirect_status);
}
-bool CSPDirectiveList::CheckEvalAndReportViolation(
- SourceListDirective* directive,
+bool CheckEvalAndReportViolation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
const String& console_message,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& content) const {
- if (CheckEval(directive))
+ const String& content) {
+ CSPOperativeDirective directive =
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc);
+ if (CheckEval(directive.source_list))
return true;
String suffix = String();
- if (directive == default_src_)
+ if (directive.type == CSPDirectiveName::DefaultSrc) {
suffix =
" Note that 'script-src' was not explicitly set, so 'default-src' is "
"used as a fallback.";
+ }
+ String raw_directive =
+ GetRawDirectiveForMessage(csp.raw_directives, directive.type);
ReportEvalViolation(
- directive->GetText(), ContentSecurityPolicy::DirectiveType::kScriptSrc,
- console_message + "\"" + directive->GetText() + "\"." + suffix + "\n",
- KURL(), exception_status,
- directive->AllowReportSample() ? content : g_empty_string);
- if (!IsReportOnly()) {
- policy_->ReportBlockedScriptExecutionToInspector(directive->GetText());
+ csp, policy, raw_directive, CSPDirectiveName::ScriptSrc,
+ console_message + "\"" + raw_directive + "\"." + suffix + "\n", KURL(),
+ exception_status,
+ directive.source_list->report_sample ? content : g_empty_string);
+ if (!CSPDirectiveListIsReportOnly(csp)) {
+ policy->ReportBlockedScriptExecutionToInspector(raw_directive);
return false;
}
return true;
}
-bool CSPDirectiveList::CheckWasmEvalAndReportViolation(
- SourceListDirective* directive,
+bool CheckWasmEvalAndReportViolation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
const String& console_message,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& content) const {
- if (CheckWasmEval(directive))
+ const String& content) {
+ CSPOperativeDirective directive =
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc);
+ if (CheckWasmEval(directive.source_list))
return true;
String suffix = String();
- if (directive == default_src_) {
+ if (directive.type == CSPDirectiveName::DefaultSrc) {
suffix =
" Note that 'script-src' was not explicitly set, so 'default-src' is "
"used as a fallback.";
}
+ String raw_directive =
+ GetRawDirectiveForMessage(csp.raw_directives, directive.type);
ReportEvalViolation(
- directive->GetText(), ContentSecurityPolicy::DirectiveType::kScriptSrc,
- console_message + "\"" + directive->GetText() + "\"." + suffix + "\n",
- KURL(), exception_status,
- directive->AllowReportSample() ? content : g_empty_string);
- if (!IsReportOnly()) {
- policy_->ReportBlockedScriptExecutionToInspector(directive->GetText());
+ csp, policy, raw_directive, CSPDirectiveName::ScriptSrc,
+ console_message + "\"" + raw_directive + "\"." + suffix + "\n", KURL(),
+ exception_status,
+ directive.source_list->report_sample ? content : g_empty_string);
+ if (!CSPDirectiveListIsReportOnly(csp)) {
+ policy->ReportBlockedScriptExecutionToInspector(raw_directive);
return false;
}
return true;
}
-bool CSPDirectiveList::CheckMediaTypeAndReportViolation(
- MediaListDirective* directive,
- const String& type,
- const String& type_attribute,
- const String& console_message) const {
- if (CheckMediaType(directive, type, type_attribute))
- return true;
-
- String message = console_message + "\'" + directive->GetText() + "\'.";
- if (type_attribute.IsEmpty())
- message = message +
- " When enforcing the 'plugin-types' directive, the plugin's "
- "media type must be explicitly declared with a 'type' attribute "
- "on the containing element (e.g. '<object type=\"[TYPE GOES "
- "HERE]\" ...>').";
-
- // 'RedirectStatus::NoRedirect' is safe here, as we do the media type check
- // before actually loading data; this means that we shouldn't leak redirect
- // targets, as we won't have had a chance to redirect yet.
- ReportViolation(
- directive->GetText(), ContentSecurityPolicy::DirectiveType::kPluginTypes,
- message + "\n", NullURL(), ResourceRequest::RedirectStatus::kNoRedirect);
- return DenyIfEnforcingPolicy();
-}
-
-bool CSPDirectiveList::CheckInlineAndReportViolation(
- SourceListDirective* directive,
+bool CheckInlineAndReportViolation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ CSPOperativeDirective directive,
const String& console_message,
Element* element,
const String& source,
@@ -453,12 +767,14 @@ bool CSPDirectiveList::CheckInlineAndReportViolation(
const WTF::OrdinalNumber& context_line,
bool is_script,
const String& hash_value,
- ContentSecurityPolicy::DirectiveType effective_type) const {
- if (!directive || directive->AllowAllInline())
+ CSPDirectiveName effective_type) {
+ if (!directive.source_list ||
+ CSPSourceListAllowAllInline(directive.type, *directive.source_list))
return true;
String suffix = String();
- if (directive->AllowInline() && directive->IsHashOrNoncePresent()) {
+ if (directive.source_list->allow_inline &&
+ CSPSourceListIsHashOrNoncePresent(*directive.source_list)) {
// If inline is allowed, but a hash or nonce is present, we ignore
// 'unsafe-inline'. Throw a reasonable error.
suffix =
@@ -468,83 +784,91 @@ bool CSPDirectiveList::CheckInlineAndReportViolation(
suffix =
" Either the 'unsafe-inline' keyword, a hash ('" + hash_value +
"'), or a nonce ('nonce-...') is required to enable inline execution.";
- if (directive == default_src_)
+ if (directive.type == CSPDirectiveName::DefaultSrc) {
suffix = suffix + " Note also that '" +
String(is_script ? "script" : "style") +
"-src' was not explicitly set, so 'default-src' is used as a "
"fallback.";
+ }
}
+ String raw_directive =
+ GetRawDirectiveForMessage(csp.raw_directives, directive.type);
ReportViolationWithLocation(
- directive->GetText(), effective_type,
- console_message + "\"" + directive->GetText() + "\"." + suffix + "\n",
- KURL(), context_url, context_line, element,
- directive->AllowReportSample() ? source : g_empty_string);
+ csp, policy, raw_directive, effective_type,
+ console_message + "\"" + raw_directive + "\"." + suffix + "\n", KURL(),
+ context_url, context_line, element,
+ directive.source_list->report_sample ? source : g_empty_string);
- if (!IsReportOnly()) {
+ if (!CSPDirectiveListIsReportOnly(csp)) {
if (is_script)
- policy_->ReportBlockedScriptExecutionToInspector(directive->GetText());
+ policy->ReportBlockedScriptExecutionToInspector(raw_directive);
return false;
}
return true;
}
-bool CSPDirectiveList::CheckSourceAndReportViolation(
- SourceListDirective* directive,
+bool CheckSourceAndReportViolation(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ CSPOperativeDirective directive,
const KURL& url,
- const ContentSecurityPolicy::DirectiveType effective_type,
+ CSPDirectiveName effective_type,
const KURL& url_before_redirects,
- ResourceRequest::RedirectStatus redirect_status) const {
- if (!directive)
+ ResourceRequest::RedirectStatus redirect_status) {
+ if (!directive.source_list)
return true;
// We ignore URL-based allowlists if we're allowing dynamic script injection.
- if (CheckSource(directive, url, redirect_status) && !CheckDynamic(directive))
+ if (CheckSource(policy, directive.source_list, *csp.self_origin, url,
+ redirect_status) &&
+ !CheckDynamic(directive.source_list, effective_type))
return true;
// We should never have a violation against `child-src` or `default-src`
// directly; the effective directive should always be one of the explicit
// fetch directives.
- DCHECK_NE(ContentSecurityPolicy::DirectiveType::kChildSrc, effective_type);
- DCHECK_NE(ContentSecurityPolicy::DirectiveType::kDefaultSrc, effective_type);
+ DCHECK_NE(CSPDirectiveName::ChildSrc, effective_type);
+ DCHECK_NE(CSPDirectiveName::DefaultSrc, effective_type);
String prefix = "Refused to ";
- if (ContentSecurityPolicy::DirectiveType::kBaseURI == effective_type)
+ if (CSPDirectiveName::BaseURI == effective_type)
prefix = prefix + "set the document's base URI to '";
- else if (ContentSecurityPolicy::DirectiveType::kWorkerSrc == effective_type)
+ else if (CSPDirectiveName::WorkerSrc == effective_type)
prefix = prefix + "create a worker from '";
- else if (ContentSecurityPolicy::DirectiveType::kConnectSrc == effective_type)
+ else if (CSPDirectiveName::ConnectSrc == effective_type)
prefix = prefix + "connect to '";
- else if (ContentSecurityPolicy::DirectiveType::kFontSrc == effective_type)
+ else if (CSPDirectiveName::FontSrc == effective_type)
prefix = prefix + "load the font '";
- else if (ContentSecurityPolicy::DirectiveType::kFormAction == effective_type)
+ else if (CSPDirectiveName::FormAction == effective_type)
prefix = prefix + "send form data to '";
- else if (ContentSecurityPolicy::DirectiveType::kFrameSrc == effective_type)
+ else if (CSPDirectiveName::FrameSrc == effective_type)
prefix = prefix + "frame '";
- else if (ContentSecurityPolicy::DirectiveType::kImgSrc == effective_type)
+ else if (CSPDirectiveName::ImgSrc == effective_type)
prefix = prefix + "load the image '";
- else if (ContentSecurityPolicy::DirectiveType::kMediaSrc == effective_type)
+ else if (CSPDirectiveName::MediaSrc == effective_type)
prefix = prefix + "load media from '";
- else if (ContentSecurityPolicy::DirectiveType::kManifestSrc == effective_type)
+ else if (CSPDirectiveName::ManifestSrc == effective_type)
prefix = prefix + "load manifest from '";
- else if (ContentSecurityPolicy::DirectiveType::kObjectSrc == effective_type)
+ else if (CSPDirectiveName::ObjectSrc == effective_type)
prefix = prefix + "load plugin data from '";
- else if (ContentSecurityPolicy::DirectiveType::kPrefetchSrc == effective_type)
+ else if (CSPDirectiveName::PrefetchSrc == effective_type)
prefix = prefix + "prefetch content from '";
else if (ContentSecurityPolicy::IsScriptDirective(effective_type))
prefix = prefix + "load the script '";
else if (ContentSecurityPolicy::IsStyleDirective(effective_type))
prefix = prefix + "load the stylesheet '";
- else if (ContentSecurityPolicy::DirectiveType::kNavigateTo == effective_type)
+ else if (CSPDirectiveName::NavigateTo == effective_type)
prefix = prefix + "navigate to '";
String suffix = String();
- if (CheckDynamic(directive)) {
+ if (CheckDynamic(directive.source_list, effective_type)) {
suffix =
" 'strict-dynamic' is present, so host-based allowlisting is disabled.";
}
- String directive_name = directive->GetName();
+ String directive_name =
+ ContentSecurityPolicy::GetDirectiveName(directive.type);
String effective_directive_name =
ContentSecurityPolicy::GetDirectiveName(effective_type);
if (directive_name != effective_directive_name) {
@@ -553,35 +877,111 @@ bool CSPDirectiveList::CheckSourceAndReportViolation(
"' is used as a fallback.";
}
- ReportViolation(directive->GetText(), effective_type,
+ String raw_directive =
+ GetRawDirectiveForMessage(csp.raw_directives, directive.type);
+ ReportViolation(csp, policy, raw_directive, effective_type,
prefix + url.ElidedString() +
"' because it violates the following Content Security "
"Policy directive: \"" +
- directive->GetText() + "\"." + suffix + "\n",
+ raw_directive + "\"." + suffix + "\n",
url_before_redirects, redirect_status);
- return DenyIfEnforcingPolicy();
+ return CSPDirectiveListIsReportOnly(csp);
+}
+
+bool AllowDynamicWorker(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ const network::mojom::blink::CSPSourceList* worker_src =
+ OperativeDirective(csp, CSPDirectiveName::WorkerSrc).source_list;
+ return CheckDynamic(worker_src, CSPDirectiveName::WorkerSrc);
}
-bool CSPDirectiveList::AllowInline(
+network::mojom::blink::CSPSourcePtr ComputeSelfOrigin(
+ const SecurityOrigin& self_origin) {
+ DCHECK(self_origin.Protocol());
+ return network::mojom::blink::CSPSource::New(
+ self_origin.Protocol(),
+ // Forget the host for file schemes. Host can anyway only be `localhost`
+ // or empty and this is platform dependent.
+ //
+ // TODO(antoniosartori): Consider returning mojom::CSPSource::New() for
+ // file: urls, so that 'self' for file: would match nothing.
+ self_origin.Protocol() == "file" ? "" : self_origin.Host(),
+ self_origin.Port() == DefaultPortForProtocol(self_origin.Protocol())
+ ? url::PORT_UNSPECIFIED
+ : self_origin.Port(),
+ "",
+ /*is_host_wildcard=*/false, /*is_port_wildcard=*/false);
+}
+
+} // namespace
+
+network::mojom::blink::ContentSecurityPolicyPtr CSPDirectiveListParse(
+ ContentSecurityPolicy* policy,
+ const UChar* begin,
+ const UChar* end,
+ const SecurityOrigin& self_origin,
+ ContentSecurityPolicyType type,
+ ContentSecurityPolicySource source,
+ bool should_parse_wasm_eval) {
+ auto csp = network::mojom::blink::ContentSecurityPolicy::New();
+ csp->header = network::mojom::blink::ContentSecurityPolicyHeader::New(
+ String(begin, static_cast<wtf_size_t>(end - begin)).StripWhiteSpace(),
+ type, source);
+
+ const SecurityOrigin& real_self_origin =
+ *(self_origin.GetOriginOrPrecursorOriginIfOpaque());
+ csp->self_origin = ComputeSelfOrigin(real_self_origin);
+
+ Parse(begin, end, real_self_origin, should_parse_wasm_eval, *csp, policy);
+ return csp;
+}
+
+bool CSPDirectiveListIsReportOnly(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ return csp.header->type == network::mojom::ContentSecurityPolicyType::kReport;
+}
+
+bool CSPDirectiveListAllowTrustedTypeAssignmentFailure(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& message,
+ const String& sample,
+ const String& sample_prefix) {
+ if (!CSPDirectiveListRequiresTrustedTypes(csp))
+ return true;
+
+ ReportViolation(csp, policy,
+ ContentSecurityPolicy::GetDirectiveName(
+ CSPDirectiveName::RequireTrustedTypesFor),
+ CSPDirectiveName::RequireTrustedTypesFor, message, KURL(),
+ RedirectStatus::kNoRedirect,
+ ContentSecurityPolicy::kTrustedTypesSinkViolation, sample,
+ sample_prefix);
+ return CSPDirectiveListIsReportOnly(csp);
+}
+
+bool CSPDirectiveListAllowInline(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
ContentSecurityPolicy::InlineType inline_type,
Element* element,
const String& content,
const String& nonce,
const String& context_url,
const WTF::OrdinalNumber& context_line,
- ReportingDisposition reporting_disposition) const {
- ContentSecurityPolicy::DirectiveType type =
+ ReportingDisposition reporting_disposition) {
+ CSPDirectiveName type =
GetDirectiveTypeForAllowInlineFromInlineType(inline_type);
- SourceListDirective* directive = OperativeDirective(type);
- if (IsMatchingNoncePresent(directive, nonce))
+ CSPOperativeDirective directive = OperativeDirective(csp, type);
+ if (IsMatchingNoncePresent(directive.source_list, nonce))
return true;
auto* html_script_element = DynamicTo<HTMLScriptElement>(element);
if (html_script_element &&
inline_type == ContentSecurityPolicy::InlineType::kScript &&
!html_script_element->Loader()->IsParserInserted() &&
- AllowDynamic(type)) {
+ CSPDirectiveListAllowDynamic(csp, type)) {
return true;
}
if (reporting_disposition == ReportingDisposition::kReport) {
@@ -620,7 +1020,7 @@ bool CSPDirectiveList::AllowInline(
}
return CheckInlineAndReportViolation(
- directive,
+ csp, policy, directive,
"Refused to " + message +
" because it violates the following Content Security Policy "
"directive: ",
@@ -629,158 +1029,182 @@ bool CSPDirectiveList::AllowInline(
type);
}
- return !directive || directive->AllowAllInline();
+ return !directive.source_list ||
+ CSPSourceListAllowAllInline(directive.type, *directive.source_list);
}
-bool CSPDirectiveList::ShouldCheckEval() const {
+bool CSPDirectiveListShouldCheckEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
return !CheckEval(
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kScriptSrc));
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc).source_list);
}
-bool CSPDirectiveList::AllowEval(
+bool CSPDirectiveListAllowEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
ReportingDisposition reporting_disposition,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& content) const {
+ const String& content) {
if (reporting_disposition == ReportingDisposition::kReport) {
return CheckEvalAndReportViolation(
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kScriptSrc),
+ csp, policy,
"Refused to evaluate a string as JavaScript because 'unsafe-eval' is "
"not an allowed source of script in the following Content Security "
"Policy directive: ",
exception_status, content);
}
- return IsReportOnly() ||
- CheckEval(OperativeDirective(
- ContentSecurityPolicy::DirectiveType::kScriptSrc));
+ return CSPDirectiveListIsReportOnly(csp) ||
+ CheckEval(
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc).source_list);
}
-bool CSPDirectiveList::AllowWasmEval(
+bool CSPDirectiveListAllowWasmEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
ReportingDisposition reporting_disposition,
ContentSecurityPolicy::ExceptionStatus exception_status,
- const String& content) const {
+ const String& content) {
if (reporting_disposition == ReportingDisposition::kReport) {
return CheckWasmEvalAndReportViolation(
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kScriptSrc),
+ csp, policy,
"Refused to compile or instantiate WebAssembly module because "
"'wasm-eval' is not an allowed source of script in the following "
"Content Security Policy directive: ",
exception_status, content);
}
- return IsReportOnly() ||
- CheckWasmEval(OperativeDirective(
- ContentSecurityPolicy::DirectiveType::kScriptSrc));
-}
-
-bool CSPDirectiveList::ShouldDisableEvalBecauseScriptSrc() const {
- return !AllowEval(ReportingDisposition::kSuppressReporting,
- ContentSecurityPolicy::kWillNotThrowException,
- g_empty_string);
+ return CSPDirectiveListIsReportOnly(csp) ||
+ CheckWasmEval(
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc).source_list);
}
-bool CSPDirectiveList::ShouldDisableEvalBecauseTrustedTypes() const {
- return RequiresTrustedTypes();
-}
-
-bool CSPDirectiveList::AllowPluginType(
- const String& type,
- const String& type_attribute,
- const KURL& url,
- ReportingDisposition reporting_disposition) const {
- return reporting_disposition == ReportingDisposition::kReport
- ? CheckMediaTypeAndReportViolation(
- plugin_types_.Get(), type, type_attribute,
- "Refused to load '" + url.ElidedString() + "' (MIME type '" +
- type_attribute +
- "') because it violates the following Content Security "
- "Policy Directive: ")
- : CheckMediaType(plugin_types_.Get(), type, type_attribute);
+bool CSPDirectiveListShouldDisableEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ String& error_message) {
+ CSPOperativeDirective directive =
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc);
+ if (!CheckEval(directive.source_list)) {
+ error_message =
+ "Refused to evaluate a string as JavaScript because 'unsafe-eval' is "
+ "not an allowed source of script in the following Content Security "
+ "Policy directive: \"" +
+ GetRawDirectiveForMessage(csp.raw_directives, directive.type) + "\".\n";
+ return true;
+ } else if (CSPDirectiveListRequiresTrustedTypes(csp)) {
+ error_message =
+ "Refused to evaluate a string as JavaScript because this document "
+ "requires 'Trusted Type' assignment.";
+ return true;
+ }
+ return false;
}
-bool CSPDirectiveList::AllowFromSource(
- ContentSecurityPolicy::DirectiveType type,
+bool CSPDirectiveListAllowFromSource(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ CSPDirectiveName type,
const KURL& url,
const KURL& url_before_redirects,
ResourceRequest::RedirectStatus redirect_status,
ReportingDisposition reporting_disposition,
const String& nonce,
const IntegrityMetadataSet& hashes,
- ParserDisposition parser_disposition) const {
- DCHECK(type == ContentSecurityPolicy::DirectiveType::kBaseURI ||
- type == ContentSecurityPolicy::DirectiveType::kConnectSrc ||
- type == ContentSecurityPolicy::DirectiveType::kFontSrc ||
- type == ContentSecurityPolicy::DirectiveType::kFormAction ||
- type == ContentSecurityPolicy::DirectiveType::kFrameSrc ||
- type == ContentSecurityPolicy::DirectiveType::kImgSrc ||
- type == ContentSecurityPolicy::DirectiveType::kManifestSrc ||
- type == ContentSecurityPolicy::DirectiveType::kMediaSrc ||
- type == ContentSecurityPolicy::DirectiveType::kObjectSrc ||
- type == ContentSecurityPolicy::DirectiveType::kPrefetchSrc ||
- type == ContentSecurityPolicy::DirectiveType::kScriptSrcElem ||
- type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem ||
- type == ContentSecurityPolicy::DirectiveType::kWorkerSrc);
-
- if (type == ContentSecurityPolicy::DirectiveType::kObjectSrc ||
- type == ContentSecurityPolicy::DirectiveType::kFrameSrc) {
+ ParserDisposition parser_disposition) {
+ DCHECK(type == CSPDirectiveName::BaseURI ||
+ type == CSPDirectiveName::ConnectSrc ||
+ type == CSPDirectiveName::FontSrc ||
+ type == CSPDirectiveName::FormAction ||
+ type == CSPDirectiveName::FrameSrc ||
+ type == CSPDirectiveName::ImgSrc ||
+ type == CSPDirectiveName::ManifestSrc ||
+ type == CSPDirectiveName::MediaSrc ||
+ type == CSPDirectiveName::ObjectSrc ||
+ type == CSPDirectiveName::PrefetchSrc ||
+ type == CSPDirectiveName::ScriptSrcElem ||
+ type == CSPDirectiveName::StyleSrcElem ||
+ type == CSPDirectiveName::WorkerSrc);
+
+ if (type == CSPDirectiveName::ObjectSrc ||
+ type == CSPDirectiveName::FrameSrc) {
if (url.ProtocolIsAbout())
return true;
}
- if (type == ContentSecurityPolicy::DirectiveType::kWorkerSrc &&
- AllowDynamicWorker())
+ if (type == CSPDirectiveName::WorkerSrc && AllowDynamicWorker(csp))
return true;
- if (type == ContentSecurityPolicy::DirectiveType::kScriptSrcElem ||
- type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem) {
- if (IsMatchingNoncePresent(OperativeDirective(type), nonce))
+ if (type == CSPDirectiveName::ScriptSrcElem ||
+ type == CSPDirectiveName::StyleSrcElem) {
+ if (IsMatchingNoncePresent(OperativeDirective(csp, type).source_list,
+ nonce))
return true;
}
- if (type == ContentSecurityPolicy::DirectiveType::kScriptSrcElem) {
- if (parser_disposition == kNotParserInserted && AllowDynamic(type))
+ if (type == CSPDirectiveName::ScriptSrcElem) {
+ if (parser_disposition == kNotParserInserted &&
+ CSPDirectiveListAllowDynamic(csp, type))
return true;
- if (AreAllMatchingHashesPresent(OperativeDirective(type), hashes))
+ if (AreAllMatchingHashesPresent(OperativeDirective(csp, type).source_list,
+ hashes))
return true;
}
+ CSPOperativeDirective directive = OperativeDirective(csp, type);
bool result =
reporting_disposition == ReportingDisposition::kReport
- ? CheckSourceAndReportViolation(OperativeDirective(type), url, type,
+ ? CheckSourceAndReportViolation(csp, policy, directive, url, type,
url_before_redirects, redirect_status)
- : CheckSource(OperativeDirective(type), url, redirect_status);
+ : CheckSource(policy, directive.source_list, *csp.self_origin, url,
+ redirect_status);
- if (type == ContentSecurityPolicy::DirectiveType::kBaseURI) {
- if (result &&
- !CheckSource(OperativeDirective(type), url, redirect_status)) {
- policy_->Count(WebFeature::kBaseWouldBeBlockedByDefaultSrc);
+ if (type == CSPDirectiveName::BaseURI) {
+ if (result && !CheckSource(policy, directive.source_list, *csp.self_origin,
+ url, redirect_status)) {
+ policy->Count(WebFeature::kBaseWouldBeBlockedByDefaultSrc);
}
}
return result;
}
-bool CSPDirectiveList::AllowTrustedTypePolicy(const String& policy_name,
- bool is_duplicate) const {
- if (!trusted_types_ || trusted_types_->Allows(policy_name, is_duplicate))
+bool CSPDirectiveListAllowTrustedTypePolicy(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& policy_name,
+ bool is_duplicate,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails& violation_details) {
+ if (!csp.trusted_types ||
+ CSPTrustedTypesAllows(*csp.trusted_types, policy_name, is_duplicate,
+ violation_details)) {
return true;
+ }
+ String raw_directive = GetRawDirectiveForMessage(
+ csp.raw_directives,
+ network::mojom::blink::CSPDirectiveName::TrustedTypes);
ReportViolation(
- "trusted-types", ContentSecurityPolicy::DirectiveType::kTrustedTypes,
+ csp, policy, "trusted-types", CSPDirectiveName::TrustedTypes,
String::Format(
"Refused to create a TrustedTypePolicy named '%s' because "
"it violates the following Content Security Policy directive: "
"\"%s\".",
- policy_name.Utf8().c_str(),
- trusted_types_.Get()->GetText().Utf8().c_str()),
+ policy_name.Utf8().c_str(), raw_directive.Utf8().c_str()),
KURL(), RedirectStatus::kNoRedirect,
ContentSecurityPolicy::kTrustedTypesPolicyViolation, policy_name);
- return DenyIfEnforcingPolicy();
+ return CSPDirectiveListIsReportOnly(csp);
+}
+
+bool CSPDirectiveListRequiresTrustedTypes(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ return csp.require_trusted_types_for ==
+ network::mojom::blink::CSPRequireTrustedTypesFor::Script;
}
-bool CSPDirectiveList::AllowHash(
- const CSPHashValue& hash_value,
- const ContentSecurityPolicy::InlineType inline_type) const {
- ContentSecurityPolicy::DirectiveType directive_type =
+bool CSPDirectiveListAllowHash(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ const network::mojom::blink::CSPHashSource& hash_value,
+ const ContentSecurityPolicy::InlineType inline_type) {
+ CSPDirectiveName directive_type =
GetDirectiveTypeForAllowHashFromInlineType(inline_type);
// https://w3c.github.io/webappsec-csp/#match-element-to-source-list
@@ -790,7 +1214,8 @@ bool CSPDirectiveList::AllowHash(
case ContentSecurityPolicy::InlineType::kNavigation:
case ContentSecurityPolicy::InlineType::kScriptAttribute:
case ContentSecurityPolicy::InlineType::kStyleAttribute:
- if (!CheckUnsafeHashesAllowed(OperativeDirective(directive_type)))
+ if (!CheckUnsafeHashesAllowed(
+ OperativeDirective(csp, directive_type).source_list))
return false;
break;
@@ -798,793 +1223,62 @@ bool CSPDirectiveList::AllowHash(
case ContentSecurityPolicy::InlineType::kStyle:
break;
}
- return CheckHash(OperativeDirective(directive_type), hash_value);
+ return CheckHash(OperativeDirective(csp, directive_type).source_list,
+ hash_value);
}
-bool CSPDirectiveList::AllowDynamic(
- ContentSecurityPolicy::DirectiveType directive_type) const {
- return CheckDynamic(OperativeDirective(directive_type));
+bool CSPDirectiveListAllowDynamic(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ CSPDirectiveName directive_type) {
+ return CheckDynamic(OperativeDirective(csp, directive_type).source_list,
+ directive_type);
}
-bool CSPDirectiveList::AllowDynamicWorker() const {
- SourceListDirective* worker_src =
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kWorkerSrc);
- return CheckDynamic(worker_src);
+bool CSPDirectiveListIsObjectRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ const network::mojom::blink::CSPSourceList* object_src =
+ OperativeDirective(csp, CSPDirectiveName::ObjectSrc).source_list;
+ return object_src && CSPSourceListIsNone(*object_src);
}
-const String& CSPDirectiveList::PluginTypesText() const {
- DCHECK(HasPluginTypes());
- return plugin_types_->GetText();
+bool CSPDirectiveListIsBaseRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ const auto base_uri = csp.directives.find(CSPDirectiveName::BaseURI);
+ return (base_uri != csp.directives.end()) &&
+ (CSPSourceListIsNone(*base_uri->value) ||
+ CSPSourceListIsSelf(*base_uri->value));
}
-bool CSPDirectiveList::ShouldSendCSPHeader(ResourceType type) const {
- // TODO(mkwst): Revisit this once the CORS prefetch issue with the 'CSP'
- // header is worked out, one way or another:
- // https://github.com/whatwg/fetch/issues/52
- return false;
-}
-
-// policy = directive-list
-// directive-list = [ directive *( ";" [ directive ] ) ]
-//
-void CSPDirectiveList::Parse(const UChar* begin,
- const UChar* end,
- bool should_parse_wasm_eval) {
- header_ =
- String(begin, static_cast<wtf_size_t>(end - begin)).StripWhiteSpace();
-
- if (begin == end)
- return;
-
- const UChar* position = begin;
- while (position < end) {
- const UChar* directive_begin = position;
- SkipUntil<UChar>(position, end, ';');
-
- String name, value;
- if (ParseDirective(directive_begin, position, &name, &value)) {
- DCHECK(!name.IsEmpty());
- AddDirective(name, value);
- }
-
- DCHECK(position == end || *position == ';');
- SkipExactly<UChar>(position, end, ';');
- }
-}
-
-// directive = *WSP [ directive-name [ WSP directive-value ] ]
-// directive-name = 1*( ALPHA / DIGIT / "-" )
-// directive-value = *( WSP / <VCHAR except ";"> )
-//
-bool CSPDirectiveList::ParseDirective(const UChar* begin,
- const UChar* end,
- String* name,
- String* value) {
- DCHECK(name->IsEmpty());
- DCHECK(value->IsEmpty());
-
- const UChar* position = begin;
- SkipWhile<UChar, IsASCIISpace>(position, end);
-
- // Empty directive (e.g. ";;;"). Exit early.
- if (position == end)
- return false;
-
- const UChar* name_begin = position;
- SkipWhile<UChar, IsCSPDirectiveNameCharacter>(position, end);
-
- // The directive-name must be non-empty.
- if (name_begin == position) {
- // Malformed CSP: directive starts with invalid characters
- policy_->Count(WebFeature::kMalformedCSP);
-
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- policy_->ReportUnsupportedDirective(
- String(name_begin, static_cast<wtf_size_t>(position - name_begin)));
- return false;
- }
-
- *name = String(name_begin, static_cast<wtf_size_t>(position - name_begin))
- .LowerASCII();
-
- if (position == end)
- return true;
-
- if (!SkipExactly<UChar, IsASCIISpace>(position, end)) {
- // Malformed CSP: after the directive name we don't have a space
- policy_->Count(WebFeature::kMalformedCSP);
-
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- policy_->ReportUnsupportedDirective(
- String(name_begin, static_cast<wtf_size_t>(position - name_begin)));
- return false;
- }
-
- SkipWhile<UChar, IsASCIISpace>(position, end);
-
- const UChar* value_begin = position;
- SkipWhile<UChar, IsCSPDirectiveValueCharacter>(position, end);
-
- if (position != end) {
- // Malformed CSP: directive value has invalid characters
- policy_->Count(WebFeature::kMalformedCSP);
-
- policy_->ReportInvalidDirectiveValueCharacter(
- *name, String(value_begin, static_cast<wtf_size_t>(end - value_begin)));
- return false;
- }
-
- // The directive-value may be empty.
- if (value_begin == position)
- return true;
-
- *value = String(value_begin, static_cast<wtf_size_t>(position - value_begin));
- return true;
-}
-
-void CSPDirectiveList::ParseReportTo(const String& name, const String& value) {
- if (!use_reporting_api_) {
- use_reporting_api_ = true;
- report_endpoints_.clear();
- }
-
- if (!report_endpoints_.IsEmpty()) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
-
- ParseAndAppendReportEndpoints(value);
-
- if (report_endpoints_.size() > 1) {
- // The directive "report-to" only accepts one endpoint.
- report_endpoints_.Shrink(1);
- policy_->ReportMultipleReportToEndpoints();
- }
-}
-
-void CSPDirectiveList::ParseReportURI(const String& name, const String& value) {
- // report-to supersedes report-uri
- if (use_reporting_api_)
- return;
-
- if (!report_endpoints_.IsEmpty()) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
-
- // Remove report-uri in meta policies, per
- // https://html.spec.whatwg.org/C/#attr-meta-http-equiv-content-security-policy.
- if (header_source_ == ContentSecurityPolicySource::kMeta) {
- policy_->ReportInvalidDirectiveInMeta(name);
- return;
- }
-
- ParseAndAppendReportEndpoints(value);
-
- // Ignore right away report-uri endpoints which would be blocked later when
- // reporting because of Mixed Content and report a warning.
- if (!policy_->GetSelfSource()) {
- return;
- }
- report_endpoints_.erase(
- std::remove_if(report_endpoints_.begin(), report_endpoints_.end(),
- [this](const String& endpoint) {
- KURL parsed_endpoint = KURL(endpoint);
- if (!parsed_endpoint.IsValid()) {
- // endpoint is not absolute, so it cannot violate
- // MixedContent
- return false;
- }
- if (MixedContentChecker::IsMixedContent(
- policy_->GetSelfSource()->GetScheme(),
- parsed_endpoint)) {
- policy_->ReportMixedContentReportURI(endpoint);
- return true;
- }
- return false;
- }),
- report_endpoints_.end());
-}
-
-// For "report-uri" directive, this method corresponds to:
-// https://w3c.github.io/webappsec-csp/#report-violation
-// Step 3.4.2. For each token returned by splitting a string on ASCII whitespace
-// with directive's value as the input. [spec text]
-
-// For "report-to" directive, the spec says |value| is a single token
-// but we use the same logic as "report-uri" and thus we split |value| by
-// ASCII whitespaces. The tokens after the first one are discarded in
-// CSPDirectiveList::ParseReportTo.
-// https://w3c.github.io/webappsec-csp/#directive-report-to
-void CSPDirectiveList::ParseAndAppendReportEndpoints(const String& value) {
- Vector<UChar> characters;
- value.AppendTo(characters);
-
- // https://infra.spec.whatwg.org/#split-on-ascii-whitespace
-
- // Step 2. Let tokens be a list of strings, initially empty. [spec text]
- DCHECK(report_endpoints_.IsEmpty());
-
- const UChar* position = characters.data();
- const UChar* end = position + characters.size();
-
- // Step 4. While position is not past the end of input: [spec text]
- while (position < end) {
- // Step 3. Skip ASCII whitespace within input given position. [spec text]
- // Step 4.3. Skip ASCII whitespace within input given position. [spec text]
- //
- // Note: IsASCIISpace returns true for U+000B which is not included in
- // https://infra.spec.whatwg.org/#ascii-whitespace.
- // TODO(mkwst): Investigate why the restrictions in the infra spec are
- // different than those in Blink here.
- SkipWhile<UChar, IsASCIISpace>(position, end);
-
- // Step 4.1. Let token be the result of collecting a sequence of code points
- // that are not ASCII whitespace from input, given position. [spec text]
- const UChar* endpoint_begin = position;
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
-
- if (endpoint_begin < position) {
- // Step 4.2. Append token to tokens. [spec text]
- String endpoint = String(
- endpoint_begin, static_cast<wtf_size_t>(position - endpoint_begin));
- report_endpoints_.push_back(endpoint);
- }
- }
-
- policy_->Count(report_endpoints_.size() > 1
- ? WebFeature::kReportUriMultipleEndpoints
- : WebFeature::kReportUriSingleEndpoint);
-}
-
-template <class CSPDirectiveType>
-void CSPDirectiveList::SetCSPDirective(const String& name,
- const String& value,
- Member<CSPDirectiveType>& directive,
- bool should_parse_wasm_eval) {
- if (directive) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
-
- // Remove frame-ancestors directives in meta policies, per
- // https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
- if (header_source_ == ContentSecurityPolicySource::kMeta &&
- ContentSecurityPolicy::GetDirectiveType(name) ==
- ContentSecurityPolicy::DirectiveType::kFrameAncestors) {
- policy_->ReportInvalidDirectiveInMeta(name);
- return;
- }
-
- directive = MakeGarbageCollected<CSPDirectiveType>(name, value, policy_);
-}
-
-void CSPDirectiveList::ApplySandboxPolicy(const String& name,
- const String& sandbox_policy) {
- // Remove sandbox directives in meta policies, per
- // https://www.w3.org/TR/CSP2/#delivery-html-meta-element.
- if (header_source_ == ContentSecurityPolicySource::kMeta) {
- policy_->ReportInvalidDirectiveInMeta(name);
- return;
- }
- if (IsReportOnly()) {
- policy_->ReportInvalidInReportOnly(name);
- return;
- }
- if (has_sandbox_policy_) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
-
- using network::mojom::blink::WebSandboxFlags;
- WebSandboxFlags ignored_flags =
- !RuntimeEnabledFeatures::StorageAccessAPIEnabled()
- ? WebSandboxFlags::kStorageAccessByUserActivation
- : WebSandboxFlags::kNone;
-
- has_sandbox_policy_ = true;
- network::WebSandboxFlagsParsingResult parsed =
- network::ParseWebSandboxPolicy(sandbox_policy.Utf8(), ignored_flags);
- policy_->EnforceSandboxFlags(parsed.flags);
- if (!parsed.error_message.empty()) {
- policy_->ReportInvalidSandboxFlags(
- WebString::FromUTF8(parsed.error_message));
- }
-}
-
-void CSPDirectiveList::ApplyTreatAsPublicAddress() {
- // Remove treat-as-public-address directives in meta policies, per
- // https://wicg.github.io/cors-rfc1918/#csp
- if (header_source_ == ContentSecurityPolicySource::kMeta) {
- policy_->ReportInvalidDirectiveInMeta("treat-as-public-address");
- return;
- }
-
- // Remove treat-as-public-address directives in report-only, per
- // https://wicg.github.io/cors-rfc1918/#csp
- if (IsReportOnly()) {
- policy_->ReportInvalidInReportOnly("treat-as-public-address");
- return;
- }
-
- // Nothing to do, since treat-as-public-address directive is handled by the
- // browser process.
-}
-
-void CSPDirectiveList::AddTrustedTypes(const String& name,
- const String& value) {
- if (trusted_types_) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
- trusted_types_ =
- MakeGarbageCollected<StringListDirective>(name, value, policy_);
-}
-
-void CSPDirectiveList::RequireTrustedTypesFor(const String& name,
- const String& value) {
- if (require_trusted_types_for_) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
- require_trusted_types_for_ =
- MakeGarbageCollected<RequireTrustedTypesForDirective>(name, value,
- policy_);
- if (require_trusted_types_for_->require())
- policy_->RequireTrustedTypes();
-}
-
-void CSPDirectiveList::EnforceStrictMixedContentChecking(const String& name,
- const String& value) {
- if (strict_mixed_content_checking_enforced_) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
- if (!value.IsEmpty())
- policy_->ReportValueForEmptyDirective(name, value);
-
- strict_mixed_content_checking_enforced_ = true;
-
- if (!IsReportOnly())
- policy_->EnforceStrictMixedContentChecking();
-}
-
-void CSPDirectiveList::EnableInsecureRequestsUpgrade(const String& name,
- const String& value) {
- if (IsReportOnly()) {
- policy_->ReportInvalidInReportOnly(name);
- return;
- }
- if (upgrade_insecure_requests_) {
- policy_->ReportDuplicateDirective(name);
- return;
- }
- upgrade_insecure_requests_ = true;
-
- policy_->UpgradeInsecureRequests();
- if (!value.IsEmpty())
- policy_->ReportValueForEmptyDirective(name, value);
-}
-
-void CSPDirectiveList::AddDirective(const String& name, const String& value) {
- DCHECK(!name.IsEmpty());
-
- ContentSecurityPolicy::DirectiveType type =
- ContentSecurityPolicy::GetDirectiveType(name);
- switch (type) {
- case ContentSecurityPolicy::DirectiveType::kBaseURI:
- SetCSPDirective<SourceListDirective>(name, value, base_uri_);
- return;
- case ContentSecurityPolicy::DirectiveType::kBlockAllMixedContent:
- EnforceStrictMixedContentChecking(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kChildSrc:
- SetCSPDirective<SourceListDirective>(name, value, child_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kConnectSrc:
- SetCSPDirective<SourceListDirective>(name, value, connect_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kDefaultSrc:
- SetCSPDirective<SourceListDirective>(name, value, default_src_);
- // TODO(mkwst) It seems unlikely that developers would use different
- // algorithms for scripts and styles. We may want to combine the
- // usesScriptHashAlgorithms() and usesStyleHashAlgorithms.
- policy_->UsesScriptHashAlgorithms(default_src_->HashAlgorithmsUsed());
- policy_->UsesStyleHashAlgorithms(default_src_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kFontSrc:
- SetCSPDirective<SourceListDirective>(name, value, font_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kFormAction:
- SetCSPDirective<SourceListDirective>(name, value, form_action_);
- return;
- case ContentSecurityPolicy::DirectiveType::kFrameAncestors:
- SetCSPDirective<SourceListDirective>(name, value, frame_ancestors_);
- return;
- case ContentSecurityPolicy::DirectiveType::kFrameSrc:
- SetCSPDirective<SourceListDirective>(name, value, frame_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kImgSrc:
- SetCSPDirective<SourceListDirective>(name, value, img_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kManifestSrc:
- SetCSPDirective<SourceListDirective>(name, value, manifest_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kMediaSrc:
- SetCSPDirective<SourceListDirective>(name, value, media_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kNavigateTo:
- SetCSPDirective<SourceListDirective>(name, value, navigate_to_);
- return;
- case ContentSecurityPolicy::DirectiveType::kObjectSrc:
- SetCSPDirective<SourceListDirective>(name, value, object_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kPluginTypes:
- SetCSPDirective<MediaListDirective>(name, value, plugin_types_);
- return;
- case ContentSecurityPolicy::DirectiveType::kPrefetchSrc:
- if (!policy_->ExperimentalFeaturesEnabled())
- policy_->ReportUnsupportedDirective(name);
- else
- SetCSPDirective<SourceListDirective>(name, value, prefetch_src_);
- return;
- case ContentSecurityPolicy::DirectiveType::kReportTo:
- if (base::FeatureList::IsEnabled(network::features::kReporting))
- ParseReportTo(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kReportURI:
- ParseReportURI(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kRequireTrustedTypesFor:
- RequireTrustedTypesFor(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kSandbox:
- ApplySandboxPolicy(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kScriptSrc:
- SetCSPDirective<SourceListDirective>(name, value, script_src_);
- policy_->UsesScriptHashAlgorithms(script_src_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kScriptSrcAttr:
- SetCSPDirective<SourceListDirective>(name, value, script_src_attr_);
- policy_->UsesScriptHashAlgorithms(script_src_attr_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kScriptSrcElem:
- SetCSPDirective<SourceListDirective>(name, value, script_src_elem_);
- policy_->UsesScriptHashAlgorithms(script_src_elem_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kStyleSrc:
- SetCSPDirective<SourceListDirective>(name, value, style_src_);
- policy_->UsesStyleHashAlgorithms(style_src_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kStyleSrcAttr:
- SetCSPDirective<SourceListDirective>(name, value, style_src_attr_);
- policy_->UsesStyleHashAlgorithms(style_src_attr_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kStyleSrcElem:
- SetCSPDirective<SourceListDirective>(name, value, style_src_elem_);
- policy_->UsesStyleHashAlgorithms(style_src_elem_->HashAlgorithmsUsed());
- return;
- case ContentSecurityPolicy::DirectiveType::kTreatAsPublicAddress:
- ApplyTreatAsPublicAddress();
- return;
- case ContentSecurityPolicy::DirectiveType::kTrustedTypes:
- AddTrustedTypes(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kUpgradeInsecureRequests:
- EnableInsecureRequestsUpgrade(name, value);
- return;
- case ContentSecurityPolicy::DirectiveType::kUndefined:
- policy_->ReportUnsupportedDirective(name);
- return;
- case ContentSecurityPolicy::DirectiveType::kWorkerSrc:
- SetCSPDirective<SourceListDirective>(name, value, worker_src_);
- return;
- }
-}
-
-ContentSecurityPolicy::DirectiveType CSPDirectiveList::FallbackDirective(
- const ContentSecurityPolicy::DirectiveType current_directive,
- const ContentSecurityPolicy::DirectiveType original_directive) const {
- switch (current_directive) {
- case ContentSecurityPolicy::DirectiveType::kConnectSrc:
- case ContentSecurityPolicy::DirectiveType::kFontSrc:
- case ContentSecurityPolicy::DirectiveType::kImgSrc:
- case ContentSecurityPolicy::DirectiveType::kManifestSrc:
- case ContentSecurityPolicy::DirectiveType::kMediaSrc:
- case ContentSecurityPolicy::DirectiveType::kPrefetchSrc:
- case ContentSecurityPolicy::DirectiveType::kObjectSrc:
- case ContentSecurityPolicy::DirectiveType::kScriptSrc:
- case ContentSecurityPolicy::DirectiveType::kStyleSrc:
- return ContentSecurityPolicy::DirectiveType::kDefaultSrc;
-
- case ContentSecurityPolicy::DirectiveType::kScriptSrcAttr:
- case ContentSecurityPolicy::DirectiveType::kScriptSrcElem:
- return ContentSecurityPolicy::DirectiveType::kScriptSrc;
-
- case ContentSecurityPolicy::DirectiveType::kStyleSrcAttr:
- case ContentSecurityPolicy::DirectiveType::kStyleSrcElem:
- return ContentSecurityPolicy::DirectiveType::kStyleSrc;
-
- case ContentSecurityPolicy::DirectiveType::kFrameSrc:
- case ContentSecurityPolicy::DirectiveType::kWorkerSrc:
- return ContentSecurityPolicy::DirectiveType::kChildSrc;
-
- // Because the fallback chain of child-src can be different if we are
- // checking a worker or a frame request, we need to know the original type
- // of the request to decide. These are the fallback chains for worker-src
- // and frame-src specifically.
-
- // worker-src > child-src > script-src > default-src
- // frame-src > child-src > default-src
-
- // Since there are some situations and tests that will operate on the
- // `child-src` directive directly (like for example the EE subsumption
- // algorithm), we consider the child-src > default-src fallback path as the
- // "default" and the worker-src fallback path as an exception.
- case ContentSecurityPolicy::DirectiveType::kChildSrc:
- if (original_directive ==
- ContentSecurityPolicy::DirectiveType::kWorkerSrc)
- return ContentSecurityPolicy::DirectiveType::kScriptSrc;
-
- return ContentSecurityPolicy::DirectiveType::kDefaultSrc;
-
- default:
- return ContentSecurityPolicy::DirectiveType::kUndefined;
- }
-}
-
-SourceListDirective* CSPDirectiveList::OperativeDirective(
- const ContentSecurityPolicy::DirectiveType type,
- ContentSecurityPolicy::DirectiveType original_type) const {
- if (type == ContentSecurityPolicy::DirectiveType::kUndefined) {
- return nullptr;
- }
-
- SourceListDirective* directive;
- if (original_type == ContentSecurityPolicy::DirectiveType::kUndefined) {
- original_type = type;
- }
-
- switch (type) {
- case ContentSecurityPolicy::DirectiveType::kBaseURI:
- directive = base_uri_;
- break;
- case ContentSecurityPolicy::DirectiveType::kDefaultSrc:
- directive = default_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kFrameAncestors:
- directive = frame_ancestors_;
- break;
- case ContentSecurityPolicy::DirectiveType::kFormAction:
- directive = form_action_;
- break;
- case ContentSecurityPolicy::DirectiveType::kNavigateTo:
- directive = navigate_to_;
- break;
- case ContentSecurityPolicy::DirectiveType::kChildSrc:
- directive = child_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kConnectSrc:
- directive = connect_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kFontSrc:
- directive = font_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kImgSrc:
- directive = img_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kManifestSrc:
- directive = manifest_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kMediaSrc:
- directive = media_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kObjectSrc:
- directive = object_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kPrefetchSrc:
- directive = prefetch_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kScriptSrc:
- directive = script_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kScriptSrcAttr:
- directive = script_src_attr_;
- break;
- case ContentSecurityPolicy::DirectiveType::kScriptSrcElem:
- directive = script_src_elem_;
- break;
- case ContentSecurityPolicy::DirectiveType::kStyleSrc:
- directive = style_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kStyleSrcAttr:
- directive = style_src_attr_;
- break;
- case ContentSecurityPolicy::DirectiveType::kStyleSrcElem:
- directive = style_src_elem_;
- break;
- case ContentSecurityPolicy::DirectiveType::kFrameSrc:
- directive = frame_src_;
- break;
- case ContentSecurityPolicy::DirectiveType::kWorkerSrc:
- directive = worker_src_;
- break;
- default:
- return nullptr;
- }
-
- // if the directive does not exist, rely on the fallback directive
- return directive ? directive
- : OperativeDirective(FallbackDirective(type, original_type),
- original_type);
-}
-
-SourceListDirectiveVector CSPDirectiveList::GetSourceVector(
- const ContentSecurityPolicy::DirectiveType type,
- const CSPDirectiveListVector& policies) {
- SourceListDirectiveVector source_list_directives;
- for (const auto& policy : policies) {
- if (SourceListDirective* directive = policy->OperativeDirective(type)) {
- if (directive->IsNone())
- return SourceListDirectiveVector(1, directive);
- source_list_directives.push_back(directive);
- }
- }
-
- return source_list_directives;
-}
-
-bool CSPDirectiveList::Subsumes(const CSPDirectiveListVector& other) {
- // A list of directives that we consider for subsumption.
- // See more about source lists here:
- // https://w3c.github.io/webappsec-csp/#framework-directive-source-list
- static ContentSecurityPolicy::DirectiveType directives[] = {
- ContentSecurityPolicy::DirectiveType::kChildSrc,
- ContentSecurityPolicy::DirectiveType::kConnectSrc,
- ContentSecurityPolicy::DirectiveType::kFontSrc,
- ContentSecurityPolicy::DirectiveType::kFrameSrc,
- ContentSecurityPolicy::DirectiveType::kImgSrc,
- ContentSecurityPolicy::DirectiveType::kManifestSrc,
- ContentSecurityPolicy::DirectiveType::kMediaSrc,
- ContentSecurityPolicy::DirectiveType::kObjectSrc,
- ContentSecurityPolicy::DirectiveType::kScriptSrc,
- ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- ContentSecurityPolicy::DirectiveType::kStyleSrc,
- ContentSecurityPolicy::DirectiveType::kStyleSrcAttr,
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem,
- ContentSecurityPolicy::DirectiveType::kWorkerSrc,
- ContentSecurityPolicy::DirectiveType::kBaseURI,
- ContentSecurityPolicy::DirectiveType::kFrameAncestors,
- ContentSecurityPolicy::DirectiveType::kFormAction,
- ContentSecurityPolicy::DirectiveType::kNavigateTo};
-
- for (const auto& directive : directives) {
- // There should only be one SourceListDirective for each directive in
- // Embedding-CSP.
- SourceListDirectiveVector required_list =
- GetSourceVector(directive, CSPDirectiveListVector(1, this));
- if (!required_list.size())
- continue;
- SourceListDirective* required = required_list[0];
- // Aggregate all serialized source lists of the returned CSP into a vector
- // based on a directive type, defaulting accordingly (for example, to
- // `default-src`).
- SourceListDirectiveVector returned = GetSourceVector(directive, other);
- // TODO(amalika): Add checks for plugin-types, sandbox, disown-opener,
- // navigation-to, worker-src.
- if (!required->Subsumes(returned))
- return false;
- }
-
- if (!HasPluginTypes())
- return true;
-
- HeapVector<Member<MediaListDirective>> plugin_types_other;
- for (const auto& policy : other) {
- if (policy->HasPluginTypes())
- plugin_types_other.push_back(policy->plugin_types_);
- }
-
- return plugin_types_->Subsumes(plugin_types_other);
-}
-
-network::mojom::blink::ContentSecurityPolicyPtr
-CSPDirectiveList::ExposeForNavigationalChecks() const {
- using CSPDirectiveName = network::mojom::blink::CSPDirectiveName;
-
- auto policy = network::mojom::blink::ContentSecurityPolicy::New();
-
- policy->use_reporting_api = use_reporting_api_;
- policy->report_endpoints = report_endpoints_;
- policy->header = network::mojom::blink::ContentSecurityPolicyHeader::New(
- header_, header_type_, header_source_);
-
- if (child_src_) {
- policy->directives.Set(CSPDirectiveName::ChildSrc,
- child_src_->ExposeForNavigationalChecks());
- }
-
- if (default_src_) {
- policy->directives.Set(CSPDirectiveName::DefaultSrc,
- default_src_->ExposeForNavigationalChecks());
- }
-
- if (form_action_) {
- policy->directives.Set(CSPDirectiveName::FormAction,
- form_action_->ExposeForNavigationalChecks());
- }
-
- if (frame_src_) {
- policy->directives.Set(CSPDirectiveName::FrameSrc,
- frame_src_->ExposeForNavigationalChecks());
- }
-
- if (navigate_to_) {
- policy->directives.Set(CSPDirectiveName::NavigateTo,
- navigate_to_->ExposeForNavigationalChecks());
- }
-
- policy->upgrade_insecure_requests = upgrade_insecure_requests_;
-
- return policy;
-}
-
-bool CSPDirectiveList::IsObjectRestrictionReasonable() const {
- SourceListDirective* object_src =
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kObjectSrc);
- return object_src && object_src->IsNone();
-}
-
-bool CSPDirectiveList::IsBaseRestrictionReasonable() const {
- return base_uri_ && (base_uri_->IsNone() || base_uri_->IsSelf());
-}
-
-bool CSPDirectiveList::IsScriptRestrictionReasonable() const {
- SourceListDirective* script_src =
- OperativeDirective(ContentSecurityPolicy::DirectiveType::kScriptSrc);
+bool CSPDirectiveListIsScriptRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ CSPOperativeDirective script_src =
+ OperativeDirective(csp, CSPDirectiveName::ScriptSrc);
// If no `script-src` enforcement occurs, or it allows any and all inline
// script, the restriction is not reasonable.
- if (!script_src || script_src->AllowAllInline())
+ if (!script_src.source_list ||
+ CSPSourceListAllowAllInline(script_src.type, *script_src.source_list))
return false;
- if (script_src->IsNone())
+ if (CSPSourceListIsNone(*script_src.source_list))
return true;
// Policies containing `'strict-dynamic'` are reasonable, as that keyword
// ensures that host-based expressions and `'unsafe-inline'` are ignored.
- return script_src->IsHashOrNoncePresent() &&
- (script_src->AllowDynamic() || !script_src->AllowsURLBasedMatching());
+ return CSPSourceListIsHashOrNoncePresent(*script_src.source_list) &&
+ (script_src.source_list->allow_dynamic ||
+ !CSPSourceListAllowsURLBasedMatching(*script_src.source_list));
+}
+
+bool CSPDirectiveListIsActiveForConnections(
+ const network::mojom::blink::ContentSecurityPolicy& csp) {
+ return OperativeDirective(csp, CSPDirectiveName::ConnectSrc).source_list;
}
-void CSPDirectiveList::Trace(Visitor* visitor) const {
- visitor->Trace(policy_);
- visitor->Trace(plugin_types_);
- visitor->Trace(base_uri_);
- visitor->Trace(child_src_);
- visitor->Trace(connect_src_);
- visitor->Trace(default_src_);
- visitor->Trace(font_src_);
- visitor->Trace(form_action_);
- visitor->Trace(frame_ancestors_);
- visitor->Trace(frame_src_);
- visitor->Trace(img_src_);
- visitor->Trace(media_src_);
- visitor->Trace(manifest_src_);
- visitor->Trace(object_src_);
- visitor->Trace(prefetch_src_);
- visitor->Trace(script_src_);
- visitor->Trace(script_src_attr_);
- visitor->Trace(script_src_elem_);
- visitor->Trace(style_src_);
- visitor->Trace(style_src_attr_);
- visitor->Trace(style_src_elem_);
- visitor->Trace(worker_src_);
- visitor->Trace(navigate_to_);
- visitor->Trace(trusted_types_);
- visitor->Trace(require_trusted_types_for_);
+CSPOperativeDirective CSPDirectiveListOperativeDirective(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ CSPDirectiveName type) {
+ return OperativeDirective(csp, type);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
index 5100d32b375..4298a002d6d 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -7,15 +7,10 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
-#include "third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h"
-#include "third_party/blink/renderer/core/frame/csp/source_list_directive.h"
-#include "third_party/blink/renderer/core/frame/csp/string_list_directive.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/reporting_disposition.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -23,333 +18,149 @@
namespace blink {
-class ContentSecurityPolicy;
-enum class ResourceType : uint8_t;
-
-typedef HeapVector<Member<SourceListDirective>> SourceListDirectiveVector;
-
-class CORE_EXPORT CSPDirectiveList final
- : public GarbageCollected<CSPDirectiveList> {
- public:
- static CSPDirectiveList* Create(ContentSecurityPolicy*,
- const UChar* begin,
- const UChar* end,
- network::mojom::ContentSecurityPolicyType,
- network::mojom::ContentSecurityPolicySource,
- bool should_parse_wasm_eval = false);
-
- CSPDirectiveList(ContentSecurityPolicy*,
- network::mojom::ContentSecurityPolicyType,
- network::mojom::ContentSecurityPolicySource);
-
- void Parse(const UChar* begin,
- const UChar* end,
- bool should_parse_wasm_eval = false);
-
- const String& Header() const { return header_; }
- network::mojom::ContentSecurityPolicyType HeaderType() const {
- return header_type_;
- }
- network::mojom::ContentSecurityPolicySource HeaderSource() const {
- return header_source_;
- }
-
- bool AllowInline(ContentSecurityPolicy::InlineType,
- Element*,
- const String& content,
- const String& nonce,
- const String& context_url,
- const WTF::OrdinalNumber& context_line,
- ReportingDisposition) const;
-
- // Returns whether or not the Javascript code generation should call back the
- // CSP checker before any script evaluation from a string is being made.
- bool ShouldCheckEval() const;
-
- bool AllowEval(ReportingDisposition,
- ContentSecurityPolicy::ExceptionStatus,
- const String& script_content) const;
- bool AllowWasmEval(ReportingDisposition,
- ContentSecurityPolicy::ExceptionStatus,
- const String& script_content) const;
- bool AllowPluginType(const String& type,
- const String& type_attribute,
- const KURL&,
- ReportingDisposition) const;
-
- bool AllowFromSource(ContentSecurityPolicy::DirectiveType,
- const KURL&,
- const KURL& url_before_redirects,
- ResourceRequest::RedirectStatus,
- ReportingDisposition,
- const String& nonce = String(),
- const IntegrityMetadataSet& = IntegrityMetadataSet(),
- ParserDisposition = kParserInserted) const;
-
- bool AllowTrustedTypePolicy(const String& policy_name,
- bool is_duplicate) const;
-
- bool AllowDynamic(ContentSecurityPolicy::DirectiveType) const;
- bool AllowDynamicWorker() const;
-
- bool AllowTrustedTypeAssignmentFailure(const String& message,
- const String& sample,
- const String& sample_prefix) const;
-
- bool StrictMixedContentChecking() const {
- return strict_mixed_content_checking_enforced_;
- }
- void ReportMixedContent(const KURL& blocked_url,
- ResourceRequest::RedirectStatus) const;
-
- bool ShouldDisableEval() const {
- return ShouldDisableEvalBecauseScriptSrc() ||
- ShouldDisableEvalBecauseTrustedTypes();
- }
- bool ShouldDisableEvalBecauseScriptSrc() const;
- bool ShouldDisableEvalBecauseTrustedTypes() const;
- const String& EvalDisabledErrorMessage() const {
- return eval_disabled_error_message_;
- }
- bool IsReportOnly() const {
- return header_type_ == network::mojom::ContentSecurityPolicyType::kReport;
- }
- bool IsActiveForConnections() const {
- return OperativeDirective(
- ContentSecurityPolicy::DirectiveType::kConnectSrc);
- }
- const Vector<String>& ReportEndpoints() const { return report_endpoints_; }
- bool UseReportingApi() const { return use_reporting_api_; }
-
- // Used to copy plugin-types into a plugin document in a nested
- // browsing context.
- bool HasPluginTypes() const { return !!plugin_types_; }
- const String& PluginTypesText() const;
-
- bool ShouldSendCSPHeader(ResourceType) const;
-
- bool AllowHash(const CSPHashValue& hash_value,
- const ContentSecurityPolicy::InlineType inline_type) const;
-
- // The algorithm is described here:
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
- bool Subsumes(const CSPDirectiveListVector&);
-
- // Export a subset of the Policy. The primary goal of this method is to make
- // the embedders aware of the directives that affect navigation, as the
- // embedder is responsible for navigational enforcement.
- // It currently contains the following ones:
- // * default-src
- // * child-src
- // * frame-src
- // * form-action
- // * upgrade-insecure-requests
- // * navigate-to
- // The exported directives only contains sources that affect navigation. For
- // instance it doesn't contains 'unsafe-inline' or 'unsafe-eval'
- network::mojom::blink::ContentSecurityPolicyPtr ExposeForNavigationalChecks()
- const;
-
- // We consider `object-src` restrictions to be reasonable iff they're
- // equivalent to `object-src 'none'`.
- bool IsObjectRestrictionReasonable() const;
-
- // We consider `base-uri` restrictions to be reasonable iff they're equivalent
- // to `base-uri 'none'` or `base-uri 'self'`.
- bool IsBaseRestrictionReasonable() const;
-
- // We consider `script-src` restrictions to be reasonable iff they're not
- // URL-based (e.g. they contain only nonces and hashes, or they use
- // 'strict-dynamic'). Neither `'unsafe-eval'` nor `'unsafe-hashes'` affect
- // this judgement.
- bool IsScriptRestrictionReasonable() const;
+class KURL;
+class SecurityOrigin;
- bool RequiresTrustedTypes() const {
- return require_trusted_types_for_ && require_trusted_types_for_->require();
- }
- bool TrustedTypesAllowDuplicates() const {
- return trusted_types_ && trusted_types_->IsAllowDuplicates();
- }
-
- void Trace(Visitor*) const;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, IsMatchingNoncePresent);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, GetSourceVector);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, OperativeDirectiveGivenType);
-
- bool ParseDirective(const UChar* begin,
- const UChar* end,
- String* name,
- String* value);
- void ParseReportURI(const String& name, const String& value);
- void ParseReportTo(const String& name, const String& value);
- void ParseAndAppendReportEndpoints(const String& value);
- void ParsePluginTypes(const String& name, const String& value);
- void AddDirective(const String& name, const String& value);
- void ApplySandboxPolicy(const String& name, const String& sandbox_policy);
- void ApplyTreatAsPublicAddress();
- void EnforceStrictMixedContentChecking(const String& name,
- const String& value);
- void EnableInsecureRequestsUpgrade(const String& name, const String& value);
- void AddTrustedTypes(const String& name, const String& value);
- void RequireTrustedTypesFor(const String& name, const String& value);
-
- template <class CSPDirectiveType>
- void SetCSPDirective(const String& name,
- const String& value,
- Member<CSPDirectiveType>&,
- bool should_parse_wasm_eval = false);
-
- ContentSecurityPolicy::DirectiveType FallbackDirective(
- const ContentSecurityPolicy::DirectiveType current_directive,
- const ContentSecurityPolicy::DirectiveType original_directive) const;
- void ReportViolation(
- const String& directive_text,
- const ContentSecurityPolicy::DirectiveType,
- const String& console_message,
- const KURL& blocked_url,
- ResourceRequest::RedirectStatus,
- ContentSecurityPolicy::ContentSecurityPolicyViolationType violation_type =
- ContentSecurityPolicy::kURLViolation,
- const String& sample = String(),
- const String& sample_prefix = String()) const;
- void ReportViolationWithFrame(const String& directive_text,
- const ContentSecurityPolicy::DirectiveType,
- const String& console_message,
- const KURL& blocked_url,
- LocalFrame*) const;
- void ReportViolationWithLocation(const String& directive_text,
- const ContentSecurityPolicy::DirectiveType,
- const String& console_message,
- const KURL& blocked_url,
- const String& context_url,
- const WTF::OrdinalNumber& context_line,
- Element*,
- const String& source) const;
- void ReportEvalViolation(const String& directive_text,
- const ContentSecurityPolicy::DirectiveType,
- const String& message,
- const KURL& blocked_url,
- const ContentSecurityPolicy::ExceptionStatus,
- const String& content) const;
-
- bool CheckEval(SourceListDirective*) const;
- bool CheckWasmEval(SourceListDirective*) const;
- bool CheckDynamic(SourceListDirective*) const;
- bool IsMatchingNoncePresent(SourceListDirective*, const String&) const;
- bool AreAllMatchingHashesPresent(SourceListDirective*,
- const IntegrityMetadataSet&) const;
- bool CheckHash(SourceListDirective*, const CSPHashValue&) const;
- bool CheckUnsafeHashesAllowed(SourceListDirective*) const;
- bool CheckSource(SourceListDirective*,
- const KURL&,
- ResourceRequest::RedirectStatus) const;
- bool CheckMediaType(MediaListDirective*,
- const String& type,
- const String& type_attribute) const;
-
- void SetEvalDisabledErrorMessage(const String& error_message) {
- eval_disabled_error_message_ = error_message;
- }
-
- bool CheckEvalAndReportViolation(SourceListDirective*,
- const String& console_message,
- ContentSecurityPolicy::ExceptionStatus,
- const String& script_content) const;
- bool CheckWasmEvalAndReportViolation(SourceListDirective*,
- const String& console_message,
- ContentSecurityPolicy::ExceptionStatus,
- const String& script_content) const;
- bool CheckInlineAndReportViolation(
- SourceListDirective*,
- const String& console_message,
- Element*,
- const String& source,
- const String& context_url,
- const WTF::OrdinalNumber& context_line,
- bool is_script,
- const String& hash_value,
- ContentSecurityPolicy::DirectiveType effective_type) const;
-
- bool CheckSourceAndReportViolation(SourceListDirective*,
- const KURL&,
- const ContentSecurityPolicy::DirectiveType,
- const KURL& url_before_redirects,
- ResourceRequest::RedirectStatus) const;
- bool CheckMediaTypeAndReportViolation(MediaListDirective*,
- const String& type,
- const String& type_attribute,
- const String& console_message) const;
-
- bool DenyIfEnforcingPolicy() const { return IsReportOnly(); }
-
- // This function returns a SourceListDirective of a given type
- // or if it is not defined, the fallback SourceListDirective for that type.
- SourceListDirective* OperativeDirective(
- const ContentSecurityPolicy::DirectiveType type,
- ContentSecurityPolicy::DirectiveType original_type =
- ContentSecurityPolicy::DirectiveType::kUndefined) const;
-
- // This function aggregates from a vector of policies all operative
- // SourceListDirectives of a given type into a vector.
- static SourceListDirectiveVector GetSourceVector(
- const ContentSecurityPolicy::DirectiveType,
- const CSPDirectiveListVector& policies);
-
- Member<ContentSecurityPolicy> policy_;
-
- String header_;
- network::mojom::ContentSecurityPolicyType header_type_;
- network::mojom::ContentSecurityPolicySource header_source_;
-
- bool has_sandbox_policy_;
-
- bool strict_mixed_content_checking_enforced_;
-
- bool upgrade_insecure_requests_;
-
- Member<MediaListDirective> plugin_types_;
- Member<SourceListDirective> base_uri_;
- Member<SourceListDirective> child_src_;
- Member<SourceListDirective> connect_src_;
- Member<SourceListDirective> default_src_;
- Member<SourceListDirective> font_src_;
- Member<SourceListDirective> form_action_;
- Member<SourceListDirective> frame_ancestors_;
- Member<SourceListDirective> frame_src_;
- Member<SourceListDirective> img_src_;
- Member<SourceListDirective> media_src_;
- Member<SourceListDirective> manifest_src_;
- Member<SourceListDirective> object_src_;
- Member<SourceListDirective> prefetch_src_;
- Member<SourceListDirective> script_src_;
- Member<SourceListDirective> script_src_attr_;
- Member<SourceListDirective> script_src_elem_;
- Member<SourceListDirective> style_src_;
- Member<SourceListDirective> style_src_attr_;
- Member<SourceListDirective> style_src_elem_;
- Member<SourceListDirective> worker_src_;
- Member<SourceListDirective> navigate_to_;
- Member<StringListDirective> trusted_types_;
- Member<RequireTrustedTypesForDirective> require_trusted_types_for_;
-
- // If a "report-to" directive is used:
- // - |report_endpoints_| is a list of token parsed from the "report-to"
- // directive's value, and
- // - |use_reporting_api_| is true.
- // Otherwise,
- // - |report_endpoints_| is a list of uri-reference parsed from a
- // "report-uri" directive's value if any, and
- // - |use_reporting_api_| is false.
- Vector<String> report_endpoints_;
- bool use_reporting_api_;
-
- String eval_disabled_error_message_;
+enum class ResourceType : uint8_t;
- DISALLOW_COPY_AND_ASSIGN(CSPDirectiveList);
+struct CORE_EXPORT CSPOperativeDirective {
+ CSPDirectiveName type;
+ const network::mojom::blink::CSPSourceList* source_list;
};
+CORE_EXPORT
+network::mojom::blink::ContentSecurityPolicyPtr CSPDirectiveListParse(
+ ContentSecurityPolicy*,
+ const UChar* begin,
+ const UChar* end,
+ const SecurityOrigin& self_origin,
+ network::mojom::ContentSecurityPolicyType,
+ network::mojom::ContentSecurityPolicySource,
+ bool should_parse_wasm_eval = false);
+
+CORE_EXPORT
+bool CSPDirectiveListIsReportOnly(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowFromSource(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ CSPDirectiveName type,
+ const KURL& url,
+ const KURL& url_before_redirects,
+ ResourceRequest::RedirectStatus redirect_status,
+ ReportingDisposition reporting_disposition,
+ const String& nonce = String(),
+ const IntegrityMetadataSet& hashes = IntegrityMetadataSet(),
+ ParserDisposition parser_disposition = kParserInserted);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowTrustedTypeAssignmentFailure(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& message,
+ const String& sample,
+ const String& sample_prefix);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowTrustedTypePolicy(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ const String& policy_name,
+ bool is_duplicate,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails& violation_details);
+
+CORE_EXPORT
+bool CSPDirectiveListRequiresTrustedTypes(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowInline(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ ContentSecurityPolicy::InlineType inline_type,
+ Element* element,
+ const String& content,
+ const String& nonce,
+ const String& context_url,
+ const WTF::OrdinalNumber& context_line,
+ ReportingDisposition reporting_disposition);
+
+// Returns whether or not the Javascript code generation should call back the
+// CSP checker before any script evaluation from a string is being made.
+CORE_EXPORT
+bool CSPDirectiveListShouldCheckEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ ReportingDisposition reporting_disposition,
+ ContentSecurityPolicy::ExceptionStatus exception_status,
+ const String& content);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowWasmEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ ContentSecurityPolicy* policy,
+ ReportingDisposition reporting_disposition,
+ ContentSecurityPolicy::ExceptionStatus exception_status,
+ const String& content);
+
+CORE_EXPORT
+bool CSPDirectiveListShouldDisableEval(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ String& error_message);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowDynamic(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ CSPDirectiveName directive_type);
+
+CORE_EXPORT
+bool CSPDirectiveListAllowHash(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ const network::mojom::blink::CSPHashSource& hash_value,
+ const ContentSecurityPolicy::InlineType inline_type);
+
+// We consider `object-src` restrictions to be reasonable iff they're
+// equivalent to `object-src 'none'`.
+CORE_EXPORT
+bool CSPDirectiveListIsObjectRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+// We consider `base-uri` restrictions to be reasonable iff they're equivalent
+// to `base-uri 'none'` or `base-uri 'self'`.
+CORE_EXPORT
+bool CSPDirectiveListIsBaseRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+// We consider `script-src` restrictions to be reasonable iff they're not
+// URL-based (e.g. they contain only nonces and hashes, or they use
+// 'strict-dynamic'). Neither `'unsafe-eval'` nor `'unsafe-hashes'` affect
+// this judgement.
+CORE_EXPORT
+bool CSPDirectiveListIsScriptRestrictionReasonable(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+CORE_EXPORT
+bool CSPDirectiveListIsActiveForConnections(
+ const network::mojom::blink::ContentSecurityPolicy& csp);
+
+// Return the operative directive name and CSPSourceList for a given directive
+// name, falling back to generic directives according to Content Security
+// Policies rules. For example, if 'default-src' is defined but 'media-src' is
+// not, OperativeDirective(CSPDirectiveName::MediaSrc) will return type
+// CSPDirectiveName::DefaultSrc and the corresponding CSPSourceList. If no
+// operative directive for the given type is defined, this will return
+// CSPDirectiveName::Unknown and nullptr.
+CORE_EXPORT
+CSPOperativeDirective CSPDirectiveListOperativeDirective(
+ const network::mojom::blink::ContentSecurityPolicy& csp,
+ CSPDirectiveName type);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_LIST_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
index c0876d47168..7679bfe74d7 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
@@ -12,7 +12,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/frame/csp/source_list_directive.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
@@ -30,11 +29,9 @@ class CSPDirectiveListTest : public testing::Test {
CSPDirectiveListTest() : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
void SetUp() override {
scoped_feature_list_.InitWithFeatures({network::features::kReporting}, {});
- csp->SetupSelf(
- *SecurityOrigin::CreateFromString("https://example.test/image.png"));
}
- CSPDirectiveList* CreateList(
+ network::mojom::blink::ContentSecurityPolicyPtr CreateList(
const String& list,
ContentSecurityPolicyType type,
ContentSecurityPolicySource source = ContentSecurityPolicySource::kHTTP) {
@@ -43,7 +40,10 @@ class CSPDirectiveListTest : public testing::Test {
const UChar* begin = characters.data();
const UChar* end = begin + characters.size();
- return CSPDirectiveList::Create(csp, begin, end, type, source);
+ scoped_refptr<SecurityOrigin> self_origin =
+ SecurityOrigin::Create(KURL("https://example.test/index.html"));
+ return CSPDirectiveListParse(csp.Get(), begin, end, *self_origin, type,
+ source);
}
protected:
@@ -61,98 +61,78 @@ TEST_F(CSPDirectiveListTest, Header) {
{"script-src 'self' \t", "script-src 'self'"}};
for (const auto& test : cases) {
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- EXPECT_EQ(test.expected, directive_list->Header());
+ EXPECT_EQ(test.expected, directive_list->header->header_value);
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.expected, directive_list->Header());
+ EXPECT_EQ(test.expected, directive_list->header->header_value);
}
}
TEST_F(CSPDirectiveListTest, IsMatchingNoncePresent) {
struct TestCase {
- ContentSecurityPolicy::DirectiveType type;
const char* list;
const char* nonce;
bool expected;
} cases[] = {
- {ContentSecurityPolicy::DirectiveType::kScriptSrc, "script-src 'self'",
- "yay", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc, "script-src 'self'",
- "boo", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "script-src 'nonce-yay'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "script-src 'nonce-yay'", "boo", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "script-src 'nonce-yay' 'nonce-boo'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "script-src 'nonce-yay' 'nonce-boo'", "boo", true},
+ {"script-src 'self'", "yay", false},
+ {"script-src 'self'", "boo", false},
+ {"script-src 'nonce-yay'", "yay", true},
+ {"script-src 'nonce-yay'", "boo", false},
+ {"script-src 'nonce-yay' 'nonce-boo'", "yay", true},
+ {"script-src 'nonce-yay' 'nonce-boo'", "boo", true},
// Falls back to 'default-src'
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "default-src 'nonce-yay'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "default-src 'nonce-yay'", "boo", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "default-src 'nonce-boo'; script-src 'nonce-yay'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "default-src 'nonce-boo'; script-src 'nonce-yay'", "boo", false},
+ {"default-src 'nonce-yay'", "yay", true},
+ {"default-src 'nonce-yay'", "boo", false},
+ {"default-src 'nonce-boo'; script-src 'nonce-yay'", "yay", true},
+ {"default-src 'nonce-boo'; script-src 'nonce-yay'", "boo", false},
// Unrelated directives do not affect result
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "style-src 'nonce-yay'", "yay", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- "style-src 'nonce-yay'", "boo", false},
-
- // Script-src-elem/attr falls back on script-src and then default-src.
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- "script-src 'nonce-yay'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- "script-src 'nonce-yay'; default-src 'nonce-boo'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- "script-src 'nonce-boo'; default-src 'nonce-yay'", "yay", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- "script-src-elem 'nonce-yay'; script-src 'nonce-boo'; default-src "
- "'nonce-boo'",
- "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- "default-src 'nonce-yay'", "yay", true},
-
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- "script-src 'nonce-yay'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- "script-src 'nonce-yay'; default-src 'nonce-boo'", "yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- "script-src 'nonce-boo'; default-src 'nonce-yay'", "yay", false},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- "script-src-attr 'nonce-yay'; script-src 'nonce-boo'; default-src "
+ {"style-src 'nonce-yay'; default-src 'none'", "yay", false},
+ {"style-src 'nonce-yay'; default-src 'none'", "boo", false},
+ {"script-src-attr 'nonce-yay'; default-src 'none'", "yay", false},
+
+ // Script-src-elem falls back on script-src and then default-src.
+ {"script-src 'nonce-yay'", "yay", true},
+ {"script-src 'nonce-yay'; default-src 'nonce-boo'", "yay", true},
+ {"script-src 'nonce-boo'; default-src 'nonce-yay'", "yay", false},
+ {"script-src-elem 'nonce-yay'; script-src 'nonce-boo'; default-src "
"'nonce-boo'",
"yay", true},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- "default-src 'nonce-yay'", "yay", true},
+ {"default-src 'nonce-yay'", "yay", true},
+
+ {"script-src-attr 'nonce-yay'; script-src 'nonce-boo'; default-src "
+ "'nonce-foo'",
+ "yay", false},
+ {"script-src-attr 'nonce-yay'; script-src 'nonce-boo'; default-src "
+ "'nonce-foo'",
+ "boo", true},
+ {"script-src-attr 'nonce-yay'; script-src 'nonce-boo'; default-src "
+ "'nonce-foo'",
+ "foo", false},
};
+ KURL blocked_url = KURL("https://blocked.com");
for (const auto& test : cases) {
// Report-only
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- Member<SourceListDirective> directive =
- directive_list->OperativeDirective(test.type);
EXPECT_EQ(test.expected,
- directive_list->IsMatchingNoncePresent(directive, test.nonce));
- // Empty/null strings are always not present, regardless of the policy.
- EXPECT_FALSE(directive_list->IsMatchingNoncePresent(directive, ""));
- EXPECT_FALSE(directive_list->IsMatchingNoncePresent(directive, String()));
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ blocked_url, blocked_url,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting, test.nonce));
// Enforce
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- directive = directive_list->OperativeDirective(test.type);
EXPECT_EQ(test.expected,
- directive_list->IsMatchingNoncePresent(directive, test.nonce));
- // Empty/null strings are always not present, regardless of the policy.
- EXPECT_FALSE(directive_list->IsMatchingNoncePresent(directive, ""));
- EXPECT_FALSE(directive_list->IsMatchingNoncePresent(directive, String()));
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ blocked_url, blocked_url,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting, test.nonce));
}
}
@@ -211,25 +191,25 @@ TEST_F(CSPDirectiveListTest, AllowScriptFromSourceNoNonce) {
const KURL script_src(test.url);
// Report-only
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- EXPECT_EQ(
- test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, script_src,
- script_src, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting, String(),
- IntegrityMetadataSet(), kParserInserted));
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ script_src, script_src,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting, String(),
+ IntegrityMetadataSet(), kParserInserted));
// Enforce
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(
- test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, script_src,
- script_src, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting, String(),
- IntegrityMetadataSet(), kParserInserted));
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ script_src, script_src,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting, String(),
+ IntegrityMetadataSet(), kParserInserted));
}
}
@@ -270,13 +250,13 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
const KURL resource(test.url);
// Report-only 'script-src'
- Member<CSPDirectiveList> directive_list = CreateList(
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list = CreateList(
String("script-src ") + test.list, ContentSecurityPolicyType::kReport);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce),
IntegrityMetadataSet(), kParserInserted));
@@ -285,9 +265,9 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
ContentSecurityPolicyType::kEnforce);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce),
IntegrityMetadataSet(), kParserInserted));
@@ -296,9 +276,9 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
ContentSecurityPolicyType::kReport);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::StyleSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce)));
// Enforce 'style-src'
@@ -306,9 +286,9 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
ContentSecurityPolicyType::kEnforce);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::StyleSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce)));
// Report-only 'style-src'
@@ -316,15 +296,15 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
ContentSecurityPolicyType::kReport);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce)));
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::StyleSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce)));
// Enforce 'style-src'
@@ -332,16 +312,16 @@ TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) {
ContentSecurityPolicyType::kEnforce);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce),
IntegrityMetadataSet(), kParserInserted));
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kStyleSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::StyleSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(test.nonce)));
}
}
@@ -425,13 +405,13 @@ TEST_F(CSPDirectiveListTest, AllowScriptFromSourceWithHash) {
integrity_metadata));
// Report-only 'script-src'
- Member<CSPDirectiveList> directive_list = CreateList(
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list = CreateList(
String("script-src ") + test.list, ContentSecurityPolicyType::kReport);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(),
integrity_metadata, kParserInserted));
@@ -440,9 +420,9 @@ TEST_F(CSPDirectiveListTest, AllowScriptFromSourceWithHash) {
ContentSecurityPolicyType::kEnforce);
EXPECT_EQ(
test.expected,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kScriptSrcElem, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
+ CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(), CSPDirectiveName::ScriptSrcElem,
+ resource, resource, ResourceRequest::RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting, String(),
integrity_metadata, kParserInserted));
}
@@ -484,13 +464,13 @@ TEST_F(CSPDirectiveListTest, WorkerSrc) {
for (const auto& test : cases) {
SCOPED_TRACE(test.list);
const KURL resource("https://example.test/worker.js");
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.allowed,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kWorkerSrc, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting));
+ EXPECT_EQ(test.allowed, CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(),
+ CSPDirectiveName::WorkerSrc, resource, resource,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting));
}
}
@@ -530,329 +510,46 @@ TEST_F(CSPDirectiveListTest, WorkerSrcChildSrcFallback) {
for (const auto& test : cases) {
SCOPED_TRACE(test.list);
const KURL resource("https://example.test/worker.js");
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.allowed,
- directive_list->AllowFromSource(
- ContentSecurityPolicy::DirectiveType::kWorkerSrc, resource,
- resource, ResourceRequest::RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting));
- }
-}
-
-TEST_F(CSPDirectiveListTest, SubsumesBasedOnCSPSourcesOnly) {
- CSPDirectiveList* a = CreateList(
- "script-src http://*.one.com; img-src https://sub.one.com "
- "http://two.com/imgs/",
- ContentSecurityPolicyType::kEnforce);
-
- struct TestCase {
- const Vector<const char*> policies;
- bool expected;
- bool expected_first_policy_opposite;
- } cases[] = {
- // `listB`, which is not as restrictive as `A`, is not subsumed.
- {{""}, false, true},
- {{"script-src http://example.com"}, false, false},
- {{"img-src http://example.com"}, false, false},
- {{"script-src http://*.one.com"}, false, true},
- {{"img-src https://sub.one.com http://two.com/imgs/"}, false, true},
- {{"default-src http://example.com"}, false, false},
- {{"default-src https://sub.one.com http://two.com/imgs/"}, false, false},
- {{"default-src http://sub.one.com"}, false, false},
- {{"script-src http://*.one.com; img-src http://two.com/"}, false, false},
- {{"script-src http://*.one.com", "img-src http://sub.one.com"},
- false,
- true},
- {{"script-src http://*.one.com", "script-src https://two.com"},
- false,
- true},
- {{"script-src http://*.random.com", "script-src https://random.com"},
- false,
- false},
- {{"script-src http://sub.one.com", "script-src https://random.com"},
- false,
- false},
- {{"script-src http://*.random.com; default-src http://sub.one.com "
- "http://two.com/imgs/",
- "default-src https://sub.random.com"},
- false,
- false},
- // `listB`, which is as restrictive as `A`, is subsumed.
- {{"default-src https://sub.one.com"}, true, false},
- {{"default-src http://random.com",
- "default-src https://non-random.com:*"},
- true,
- false},
- {{"script-src http://*.one.com; img-src https://sub.one.com"},
- true,
- false},
- {{"script-src http://*.one.com; img-src https://sub.one.com "
- "http://two.com/imgs/"},
- true,
- true},
- {{"script-src http://*.one.com",
- "img-src https://sub.one.com http://two.com/imgs/"},
- true,
- true},
- {{"script-src http://*.random.com; default-src https://sub.one.com "
- "http://two.com/imgs/",
- "default-src https://else.com"},
- true,
- false},
- {{"script-src http://*.random.com; default-src https://sub.one.com "
- "http://two.com/imgs/",
- "default-src https://sub.one.com"},
- true,
- false},
- };
-
- CSPDirectiveList* empty_a =
- CreateList("", ContentSecurityPolicyType::kEnforce);
-
- for (const auto& test : cases) {
- HeapVector<Member<CSPDirectiveList>> list_b;
- for (auto* const policy : test.policies) {
- list_b.push_back(CreateList(policy, ContentSecurityPolicyType::kEnforce));
- }
-
- EXPECT_EQ(test.expected, a->Subsumes(list_b));
- // Empty CSPDirective subsumes any list.
- EXPECT_TRUE(empty_a->Subsumes(list_b));
- // Check if first policy of `listB` subsumes `A`.
- EXPECT_EQ(test.expected_first_policy_opposite,
- list_b[0]->Subsumes(HeapVector<Member<CSPDirectiveList>>(1, a)));
- }
-}
-
-TEST_F(CSPDirectiveListTest, SubsumesIfNoneIsPresent) {
- struct TestCase {
- const char* policy_a;
- const Vector<const char*> policies_b;
- bool expected;
- } cases[] = {
- // `policyA` subsumes any vector of policies.
- {"", {""}, true},
- {"", {"script-src http://example.com"}, true},
- {"", {"script-src 'none'"}, true},
- {"", {"script-src http://*.one.com", "script-src https://two.com"}, true},
- // `policyA` is 'none', but no policy in `policiesB` is.
- {"script-src ", {""}, false},
- {"script-src 'none'", {""}, false},
- {"script-src ", {"script-src http://example.com"}, false},
- {"script-src 'none'", {"script-src http://example.com"}, false},
- {"script-src ", {"img-src 'none'"}, false},
- {"script-src 'none'", {"img-src 'none'"}, false},
- {"script-src ",
- {"script-src http://*.one.com", "img-src https://two.com"},
- false},
- {"script-src 'none'",
- {"script-src http://*.one.com", "img-src https://two.com"},
- false},
- {"script-src 'none'",
- {"script-src http://*.one.com", "script-src https://two.com"},
- true},
- {"script-src 'none'",
- {"script-src http://*.one.com", "script-src 'self'"},
- true},
- // `policyA` is not 'none', but at least effective result of `policiesB`
- // is.
- {"script-src http://example.com 'none'", {"script-src 'none'"}, true},
- {"script-src http://example.com", {"script-src 'none'"}, true},
- {"script-src http://example.com 'none'",
- {"script-src http://*.one.com", "script-src http://one.com",
- "script-src 'none'"},
- true},
- {"script-src http://example.com",
- {"script-src http://*.one.com", "script-src http://one.com",
- "script-src 'none'"},
- true},
- {"script-src http://one.com 'none'",
- {"script-src http://*.one.com", "script-src http://one.com",
- "script-src https://one.com"},
- true},
- // `policyA` is `none` and at least effective result of `policiesB` is
- // too.
- {"script-src ", {"script-src ", "script-src "}, true},
- {"script-src 'none'", {"script-src", "script-src 'none'"}, true},
- {"script-src ", {"script-src 'none'", "script-src 'none'"}, true},
- {"script-src ",
- {"script-src 'none' http://example.com",
- "script-src 'none' http://example.com"},
- false},
- {"script-src 'none'", {"script-src 'none'", "script-src 'none'"}, true},
- {"script-src 'none'",
- {"script-src 'none'", "script-src 'none'", "script-src 'none'"},
- true},
- {"script-src 'none'",
- {"script-src http://*.one.com", "script-src http://one.com",
- "script-src 'none'"},
- true},
- {"script-src 'none'",
- {"script-src http://*.one.com", "script-src http://two.com",
- "script-src http://three.com"},
- true},
- // Policies contain special keywords.
- {"script-src ", {"script-src ", "script-src 'unsafe-eval'"}, true},
- {"script-src 'none'",
- {"script-src 'unsafe-inline'", "script-src 'none'"},
- true},
- {"script-src ",
- {"script-src 'none' 'unsafe-inline'",
- "script-src 'none' 'unsafe-inline'"},
- false},
- {"script-src ",
- {"script-src 'none' 'unsafe-inline'",
- "script-src 'unsafe-inline' 'strict-dynamic'"},
- false},
- {"script-src 'unsafe-eval'",
- {"script-src 'unsafe-eval'", "script 'unsafe-inline'"},
- true},
- {"script-src 'unsafe-inline'",
- {"script-src ", "script http://example.com"},
- true},
- };
-
- for (const auto& test : cases) {
- CSPDirectiveList* a =
- CreateList(test.policy_a, ContentSecurityPolicyType::kEnforce);
-
- HeapVector<Member<CSPDirectiveList>> list_b;
- for (auto* const policy_b : test.policies_b) {
- list_b.push_back(
- CreateList(policy_b, ContentSecurityPolicyType::kEnforce));
- }
-
- EXPECT_EQ(test.expected, a->Subsumes(list_b));
- }
-}
-
-TEST_F(CSPDirectiveListTest, SubsumesPluginTypes) {
- struct TestCase {
- const char* policy_a;
- const Vector<const char*> policies_b;
- bool expected;
- } cases[] = {
- // `policyA` subsumes `policiesB`.
- {"script-src 'unsafe-inline'",
- {"script-src ", "script-src http://example.com",
- "plugin-types text/plain"},
- true},
- {"script-src http://example.com",
- {"script-src http://example.com; plugin-types "},
- true},
- {"script-src http://example.com",
- {"script-src http://example.com; plugin-types text/plain"},
- true},
- {"script-src http://example.com; plugin-types text/plain",
- {"script-src http://example.com; plugin-types text/plain"},
- true},
- {"script-src http://example.com; plugin-types text/plain",
- {"script-src http://example.com; plugin-types "},
- true},
- {"script-src http://example.com; plugin-types text/plain",
- {"script-src http://example.com; plugin-types ", "plugin-types "},
- true},
- {"plugin-types application/pdf text/plain",
- {"plugin-types application/pdf text/plain",
- "plugin-types application/x-blink-test-plugin"},
- true},
- {"plugin-types application/pdf text/plain",
- {"plugin-types application/pdf text/plain",
- "plugin-types application/pdf text/plain "
- "application/x-blink-test-plugin"},
- true},
- {"plugin-types application/x-shockwave-flash application/pdf text/plain",
- {"plugin-types application/x-shockwave-flash application/pdf text/plain",
- "plugin-types application/x-shockwave-flash"},
- true},
- {"plugin-types application/x-shockwave-flash",
- {"plugin-types application/x-shockwave-flash application/pdf text/plain",
- "plugin-types application/x-shockwave-flash"},
- true},
- // `policyA` does not subsume `policiesB`.
- {"script-src http://example.com; plugin-types text/plain",
- {"script-src http://example.com"},
- false},
- {"plugin-types random-value",
- {"script-src 'unsafe-inline'", "plugin-types text/plain"},
- false},
- {"plugin-types random-value",
- {"script-src http://example.com", "script-src http://example.com"},
- false},
- {"plugin-types random-value",
- {"plugin-types text/plain", "plugin-types text/plain"},
- false},
- {"script-src http://example.com; plugin-types text/plain",
- {"plugin-types ", "plugin-types "},
- false},
- {"plugin-types application/pdf text/plain",
- {"plugin-types application/x-blink-test-plugin",
- "plugin-types application/x-blink-test-plugin"},
- false},
- {"plugin-types application/pdf text/plain",
- {"plugin-types application/pdf application/x-blink-test-plugin",
- "plugin-types application/x-blink-test-plugin"},
- false},
- };
-
- for (const auto& test : cases) {
- CSPDirectiveList* a =
- CreateList(test.policy_a, ContentSecurityPolicyType::kEnforce);
-
- HeapVector<Member<CSPDirectiveList>> list_b;
- for (auto* const policy_b : test.policies_b) {
- list_b.push_back(
- CreateList(policy_b, ContentSecurityPolicyType::kEnforce));
- }
-
- EXPECT_EQ(test.expected, a->Subsumes(list_b));
+ EXPECT_EQ(test.allowed, CSPDirectiveListAllowFromSource(
+ *directive_list, csp.Get(),
+ CSPDirectiveName::WorkerSrc, resource, resource,
+ ResourceRequest::RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting));
}
}
TEST_F(CSPDirectiveListTest, OperativeDirectiveGivenType) {
struct TestCase {
- ContentSecurityPolicy::DirectiveType directive;
- Vector<ContentSecurityPolicy::DirectiveType> fallback_list;
+ CSPDirectiveName directive;
+ Vector<CSPDirectiveName> fallback_list;
} cases[] = {
// Directives with default directive.
- {ContentSecurityPolicy::DirectiveType::kChildSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kConnectSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kFontSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kImgSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kManifestSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kMediaSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kObjectSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kStyleSrc,
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
+ {CSPDirectiveName::ChildSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ConnectSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::FontSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ImgSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ManifestSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::MediaSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ObjectSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ScriptSrc, {CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::StyleSrc, {CSPDirectiveName::DefaultSrc}},
// Directives with no default directive.
- {ContentSecurityPolicy::DirectiveType::kBaseURI, {}},
- {ContentSecurityPolicy::DirectiveType::kDefaultSrc, {}},
- {ContentSecurityPolicy::DirectiveType::kFrameAncestors, {}},
- {ContentSecurityPolicy::DirectiveType::kFormAction, {}},
+ {CSPDirectiveName::BaseURI, {}},
+ {CSPDirectiveName::DefaultSrc, {}},
+ {CSPDirectiveName::FrameAncestors, {}},
+ {CSPDirectiveName::FormAction, {}},
// Directive with multiple default directives.
- {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr,
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
- {ContentSecurityPolicy::DirectiveType::kScriptSrc,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kFrameSrc,
- {ContentSecurityPolicy::DirectiveType::kChildSrc,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
- {ContentSecurityPolicy::DirectiveType::kWorkerSrc,
- {ContentSecurityPolicy::DirectiveType::kChildSrc,
- ContentSecurityPolicy::DirectiveType::kScriptSrc,
- ContentSecurityPolicy::DirectiveType::kDefaultSrc}},
+ {CSPDirectiveName::ScriptSrcAttr,
+ {CSPDirectiveName::ScriptSrc, CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::ScriptSrcElem,
+ {CSPDirectiveName::ScriptSrc, CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::FrameSrc,
+ {CSPDirectiveName::ChildSrc, CSPDirectiveName::DefaultSrc}},
+ {CSPDirectiveName::WorkerSrc,
+ {CSPDirectiveName::ChildSrc, CSPDirectiveName::ScriptSrc,
+ CSPDirectiveName::DefaultSrc}},
};
std::stringstream all_directives;
@@ -861,15 +558,17 @@ TEST_F(CSPDirectiveListTest, OperativeDirectiveGivenType) {
all_directives << name << " http://" << name << ".com; ";
}
- CSPDirectiveList* empty = CreateList("", ContentSecurityPolicyType::kEnforce);
+ network::mojom::blink::ContentSecurityPolicyPtr empty =
+ CreateList("", ContentSecurityPolicyType::kEnforce);
std::string directive_string;
- CSPDirectiveList* directive_list;
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list;
// Initial set-up.
for (auto& test : cases) {
// With an empty directive list the returned directive should always be
// null.
- EXPECT_FALSE(empty->OperativeDirective(test.directive));
+ EXPECT_FALSE(
+ CSPDirectiveListOperativeDirective(*empty, test.directive).source_list);
// Add the directive itself as it should be the first one to be returned.
test.fallback_list.push_front(test.directive);
@@ -881,16 +580,14 @@ TEST_F(CSPDirectiveListTest, OperativeDirectiveGivenType) {
directive_list = CreateList(directive_string.c_str(),
ContentSecurityPolicyType::kEnforce);
- CSPDirective* operative_directive =
- directive_list->OperativeDirective(test.directive);
+ CSPOperativeDirective operative_directive =
+ CSPDirectiveListOperativeDirective(*directive_list, test.directive);
// We should have an actual directive returned here.
- EXPECT_TRUE(operative_directive);
+ EXPECT_TRUE(operative_directive.source_list);
// The OperativeDirective should be first one in the fallback chain.
- EXPECT_EQ(test.fallback_list.front(),
- ContentSecurityPolicy::GetDirectiveType(
- operative_directive->GetName()));
+ EXPECT_EQ(test.fallback_list.front(), operative_directive.type);
// Remove the first directive in the fallback chain from the directive
// list and continue by testing that the next one is returned until we
@@ -913,161 +610,9 @@ TEST_F(CSPDirectiveListTest, OperativeDirectiveGivenType) {
// the fallback chain that is returned.
directive_list = CreateList(directive_string.c_str(),
ContentSecurityPolicyType::kEnforce);
- EXPECT_FALSE(directive_list->OperativeDirective(test.directive));
- }
-}
-
-TEST_F(CSPDirectiveListTest, GetSourceVector) {
- const Vector<const char*> policies = {
- // Policy 1
- "default-src https://default-src.com",
- // Policy 2
- "child-src http://child-src.com",
- // Policy 3
- "child-src http://child-src.com; default-src https://default-src.com",
- // Policy 4
- "base-uri http://base-uri.com",
- // Policy 5
- "frame-src http://frame-src.com"};
-
- // Check expectations on the initial set-up.
- HeapVector<Member<CSPDirectiveList>> policy_vector;
- for (auto* const policy : policies) {
- policy_vector.push_back(
- CreateList(policy, ContentSecurityPolicyType::kEnforce));
- }
- HeapVector<Member<SourceListDirective>> result =
- CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kDefaultSrc, policy_vector);
- EXPECT_EQ(result.size(), 2u);
- result = CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kChildSrc, policy_vector);
- EXPECT_EQ(result.size(), 3u);
- result = CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kBaseURI, policy_vector);
- EXPECT_EQ(result.size(), 1u);
- result = CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kFrameSrc, policy_vector);
- EXPECT_EQ(result.size(), 4u);
-
- enum DefaultBehaviour { kDefault, kNoDefault, kChildAndDefault };
-
- struct TestCase {
- ContentSecurityPolicy::DirectiveType directive;
- const DefaultBehaviour type;
- size_t expected_total;
- int expected_current;
- int expected_default_src;
- int expected_child_src;
- } cases[] = {
- // Directives with default directive.
- {ContentSecurityPolicy::DirectiveType::kChildSrc, kDefault, 4u, 3, 1, 3},
- {ContentSecurityPolicy::DirectiveType::kConnectSrc, kDefault, 3u, 1, 2,
- 0},
- {ContentSecurityPolicy::DirectiveType::kFontSrc, kDefault, 3u, 1, 2, 0},
- {ContentSecurityPolicy::DirectiveType::kImgSrc, kDefault, 3u, 1, 2, 0},
- {ContentSecurityPolicy::DirectiveType::kManifestSrc, kDefault, 3u, 1, 2,
- 0},
- {ContentSecurityPolicy::DirectiveType::kMediaSrc, kDefault, 3u, 1, 2, 0},
- {ContentSecurityPolicy::DirectiveType::kObjectSrc, kDefault, 3u, 1, 2, 0},
- {ContentSecurityPolicy::DirectiveType::kScriptSrc, kDefault, 3u, 1, 2, 0},
- {ContentSecurityPolicy::DirectiveType::kStyleSrc, kDefault, 3u, 1, 2, 0},
- // Directives with no default directive.
- {ContentSecurityPolicy::DirectiveType::kBaseURI, kNoDefault, 2u, 2, 0, 0},
- {ContentSecurityPolicy::DirectiveType::kFrameAncestors, kNoDefault, 1u, 1,
- 0, 0},
- {ContentSecurityPolicy::DirectiveType::kFormAction, kNoDefault, 1u, 1, 0,
- 0},
- // Directive with multiple default directives.
- {ContentSecurityPolicy::DirectiveType::kFrameSrc, kChildAndDefault, 5u, 2,
- 1, 2},
- };
-
- for (const auto& test : cases) {
- // Initial set-up.
- HeapVector<Member<CSPDirectiveList>> policy_vector;
- for (auto* const policy : policies) {
- policy_vector.push_back(
- CreateList(policy, ContentSecurityPolicyType::kEnforce));
- }
- // Append current test's policy.
- std::stringstream current_directive;
- const char* name = ContentSecurityPolicy::GetDirectiveName(test.directive);
- current_directive << name << " http://" << name << ".com;";
- policy_vector.push_back(CreateList(current_directive.str().c_str(),
- ContentSecurityPolicyType::kEnforce));
-
- HeapVector<Member<SourceListDirective>> result =
- CSPDirectiveList::GetSourceVector(test.directive, policy_vector);
-
- EXPECT_EQ(result.size(), test.expected_total);
-
- int actual_current = 0, actual_default = 0, actual_child = 0;
- for (const auto& src_list : result) {
- HeapVector<Member<CSPSource>> sources = src_list->list_;
- for (const auto& source : sources) {
- if (source->host_.StartsWith(name))
- actual_current += 1;
- else if (source->host_ == "default-src.com")
- actual_default += 1;
-
- if (source->host_ == "child-src.com")
- actual_child += 1;
- }
- }
-
- EXPECT_EQ(actual_default, test.expected_default_src);
- EXPECT_EQ(actual_current, test.expected_current);
- EXPECT_EQ(actual_child, test.expected_child_src);
-
- // If another default-src is added that should only impact Fetch Directives
- policy_vector.push_back(CreateList("default-src https://default-src.com;",
- ContentSecurityPolicyType::kEnforce));
- size_t udpated_total =
- test.type != kNoDefault ? test.expected_total + 1 : test.expected_total;
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(test.directive, policy_vector).size(),
- udpated_total);
- size_t expected_child_src =
- test.directive == ContentSecurityPolicy::DirectiveType::kChildSrc ? 5u
- : 4u;
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kChildSrc, policy_vector)
- .size(),
- expected_child_src);
-
- // If another child-src is added that should only impact frame-src and
- // child-src
- policy_vector.push_back(CreateList("child-src http://child-src.com;",
- ContentSecurityPolicyType::kEnforce));
- udpated_total = test.type == kChildAndDefault ||
- test.directive ==
- ContentSecurityPolicy::DirectiveType::kChildSrc
- ? udpated_total + 1
- : udpated_total;
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(test.directive, policy_vector).size(),
- udpated_total);
- expected_child_src = expected_child_src + 1u;
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kChildSrc, policy_vector)
- .size(),
- expected_child_src);
-
- // If we add sandbox, nothing should change since it is currenly not
- // considered.
- policy_vector.push_back(CreateList("sandbox http://sandbox.com;",
- ContentSecurityPolicyType::kEnforce));
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(test.directive, policy_vector).size(),
- udpated_total);
- EXPECT_EQ(
- CSPDirectiveList::GetSourceVector(
- ContentSecurityPolicy::DirectiveType::kChildSrc, policy_vector)
- .size(),
- expected_child_src);
+ EXPECT_FALSE(
+ CSPDirectiveListOperativeDirective(*directive_list, test.directive)
+ .source_list);
}
}
@@ -1146,18 +691,18 @@ TEST_F(CSPDirectiveListTest, ReportEndpointsProperlyParsed) {
// Test both enforce and report, there should not be a difference
for (const auto& header_type : {ContentSecurityPolicyType::kEnforce,
ContentSecurityPolicyType::kReport}) {
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.policy, header_type, test.header_source);
- EXPECT_EQ(directive_list->UseReportingApi(),
+ EXPECT_EQ(directive_list->use_reporting_api,
test.expected_use_reporting_api);
- EXPECT_EQ(directive_list->ReportEndpoints().size(),
+ EXPECT_EQ(directive_list->report_endpoints.size(),
test.expected_endpoints.size());
for (const String& endpoint : test.expected_endpoints) {
- EXPECT_TRUE(directive_list->ReportEndpoints().Contains(endpoint));
+ EXPECT_TRUE(directive_list->report_endpoints.Contains(endpoint));
}
- for (const String& endpoint : directive_list->ReportEndpoints()) {
+ for (const String& endpoint : directive_list->report_endpoints) {
EXPECT_TRUE(test.expected_endpoints.Contains(endpoint));
}
}
@@ -1188,11 +733,13 @@ TEST_F(CSPDirectiveListTest, ReasonableObjectRestriction) {
for (const auto& test : cases) {
SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`");
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- EXPECT_EQ(test.expected, directive_list->IsObjectRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsObjectRestrictionReasonable(*directive_list));
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.expected, directive_list->IsObjectRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsObjectRestrictionReasonable(*directive_list));
}
}
@@ -1212,11 +759,13 @@ TEST_F(CSPDirectiveListTest, ReasonableBaseRestriction) {
for (const auto& test : cases) {
SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`");
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- EXPECT_EQ(test.expected, directive_list->IsBaseRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsBaseRestrictionReasonable(*directive_list));
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.expected, directive_list->IsBaseRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsBaseRestrictionReasonable(*directive_list));
}
}
@@ -1262,12 +811,27 @@ TEST_F(CSPDirectiveListTest, ReasonableScriptRestriction) {
for (const auto& test : cases) {
SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`");
- Member<CSPDirectiveList> directive_list =
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
CreateList(test.list, ContentSecurityPolicyType::kReport);
- EXPECT_EQ(test.expected, directive_list->IsScriptRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsScriptRestrictionReasonable(*directive_list));
directive_list = CreateList(test.list, ContentSecurityPolicyType::kEnforce);
- EXPECT_EQ(test.expected, directive_list->IsScriptRestrictionReasonable());
+ EXPECT_EQ(test.expected,
+ CSPDirectiveListIsScriptRestrictionReasonable(*directive_list));
}
}
+// Tests that report-uri directives are discarded from policies
+// delivered in <meta> elements.
+TEST_F(CSPDirectiveListTest, ReportURIInMeta) {
+ String policy = "img-src 'none'; report-uri https://foo.test";
+ network::mojom::blink::ContentSecurityPolicyPtr directive_list =
+ CreateList(policy, ContentSecurityPolicyType::kEnforce,
+ ContentSecurityPolicySource::kMeta);
+ EXPECT_TRUE(directive_list->report_endpoints.IsEmpty());
+ directive_list = CreateList(policy, ContentSecurityPolicyType::kEnforce,
+ ContentSecurityPolicySource::kHTTP);
+ EXPECT_FALSE(directive_list->report_endpoints.IsEmpty());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
index 1e93f6b20c8..d0c287755ec 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/frame/csp/csp_source.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -15,96 +16,28 @@
namespace blink {
-constexpr int CSPSource::kPortUnspecified = -1;
-
-CSPSource::CSPSource(ContentSecurityPolicy* policy,
- const String& scheme,
- const String& host,
- int port,
- const String& path,
- WildcardDisposition host_wildcard,
- WildcardDisposition port_wildcard)
- : policy_(policy),
- scheme_(scheme.DeprecatedLower()),
- host_(host),
- port_(port),
- path_(path),
- host_wildcard_(host_wildcard),
- port_wildcard_(port_wildcard) {}
-
-CSPSource::CSPSource(ContentSecurityPolicy* policy, const CSPSource& other)
- : CSPSource(policy,
- other.scheme_,
- other.host_,
- other.port_,
- other.path_,
- other.host_wildcard_,
- other.port_wildcard_) {}
-
-bool CSPSource::Matches(const KURL& url,
- ResourceRequest::RedirectStatus redirect_status) const {
- SchemeMatchingResult schemes_match = SchemeMatches(url.Protocol());
- if (schemes_match == SchemeMatchingResult::kNotMatching)
- return false;
- if (IsSchemeOnly())
- return true;
- bool paths_match = (redirect_status == RedirectStatus::kFollowedRedirect) ||
- PathMatches(url.GetPath());
- PortMatchingResult ports_match = PortMatches(
- url.HasPort() ? url.Port() : kPortUnspecified, url.Protocol());
-
- // if either the scheme or the port would require an upgrade (e.g. from http
- // to https) then check that both of them can upgrade to ensure that we don't
- // run into situations where we only upgrade the port but not the scheme or
- // viceversa
- if ((RequiresUpgrade(schemes_match) || (RequiresUpgrade(ports_match))) &&
- (!CanUpgrade(schemes_match) || !CanUpgrade(ports_match))) {
- return false;
- }
-
- return HostMatches(url.Host()) &&
- ports_match != PortMatchingResult::kNotMatching && paths_match;
-}
-
-bool CSPSource::MatchesAsSelf(const KURL& url) {
- // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression
- // Step 4.
- SchemeMatchingResult schemes_match = SchemeMatches(url.Protocol());
- bool hosts_match = HostMatches(url.Host());
- PortMatchingResult ports_match = PortMatches(
- url.HasPort() ? url.Port() : kPortUnspecified, url.Protocol());
-
- // check if the origin is exactly matching
- if (schemes_match == SchemeMatchingResult::kMatchingExact && hosts_match &&
- (ports_match == PortMatchingResult::kMatchingExact ||
- ports_match == PortMatchingResult::kMatchingWildcard)) {
- return true;
- }
-
- String self_scheme =
- (scheme_.IsEmpty() ? policy_->GetSelfProtocol() : scheme_);
-
- bool ports_match_or_defaults =
- (ports_match == PortMatchingResult::kMatchingExact ||
- ((IsDefaultPortForProtocol(port_, self_scheme) ||
- port_ == kPortUnspecified) &&
- (!url.HasPort() ||
- IsDefaultPortForProtocol(url.Port(), url.Protocol()))));
-
- if (hosts_match && ports_match_or_defaults &&
- (url.Protocol() == "https" || url.Protocol() == "wss" ||
- self_scheme == "http")) {
- return true;
- }
-
- return false;
-}
-
-CSPSource::SchemeMatchingResult CSPSource::SchemeMatches(
- const String& protocol) const {
+namespace {
+
+enum class SchemeMatchingResult {
+ kNotMatching,
+ kMatchingUpgrade,
+ kMatchingExact
+};
+
+enum class PortMatchingResult {
+ kNotMatching,
+ kMatchingWildcard,
+ kMatchingUpgrade,
+ kMatchingExact
+};
+
+SchemeMatchingResult SchemeMatches(
+ const network::mojom::blink::CSPSource& source,
+ const String& protocol,
+ const String& self_protocol) {
DCHECK_EQ(protocol, protocol.DeprecatedLower());
const String& scheme =
- (scheme_.IsEmpty() ? policy_->GetSelfProtocol() : scheme_);
+ (source.scheme.IsEmpty() ? self_protocol : source.scheme);
if (scheme == protocol)
return SchemeMatchingResult::kMatchingExact;
@@ -117,212 +50,157 @@ CSPSource::SchemeMatchingResult CSPSource::SchemeMatches(
return SchemeMatchingResult::kNotMatching;
}
-bool CSPSource::HostMatches(const String& host) const {
- bool match;
-
- bool equal_hosts = EqualIgnoringASCIICase(host_, host);
- if (host_wildcard_ == kHasWildcard) {
- if (host_.IsEmpty()) {
+bool HostMatches(const network::mojom::blink::CSPSource& source,
+ const String& host) {
+ if (source.is_host_wildcard) {
+ if (source.host.IsEmpty()) {
// host-part = "*"
- match = true;
- } else {
+ return true;
+ }
+ if (host.EndsWithIgnoringCase(String("." + source.host))) {
// host-part = "*." 1*host-char *( "." 1*host-char )
- match = host.EndsWithIgnoringCase(String("." + host_));
+ return true;
}
-
- // Chrome used to, incorrectly, match *.x.y to x.y. This was fixed, but
- // the following count measures when a match fails that would have
- // passed the old, incorrect style, in case a lot of sites were
- // relying on that behavior.
- if (equal_hosts)
- policy_->Count(WebFeature::kCSPSourceWildcardWouldMatchExactHost);
- } else {
- // host-part = 1*host-char *( "." 1*host-char )
- match = equal_hosts;
+ return false;
}
-
- return match;
+ return EqualIgnoringASCIICase(source.host, host);
}
-bool CSPSource::PathMatches(const String& url_path) const {
- if (path_.IsEmpty() || (path_ == "/" && url_path.IsEmpty()))
+bool PathMatches(const network::mojom::blink::CSPSource& source,
+ const String& url_path) {
+ if (source.path.IsEmpty() || (source.path == "/" && url_path.IsEmpty()))
return true;
String path =
DecodeURLEscapeSequences(url_path, DecodeURLMode::kUTF8OrIsomorphic);
- if (path_.EndsWith("/"))
- return path.StartsWith(path_);
+ if (source.path.EndsWith("/"))
+ return path.StartsWith(source.path);
- return path == path_;
+ return path == source.path;
}
-CSPSource::PortMatchingResult CSPSource::PortMatches(
- int port,
- const String& protocol) const {
- if (port_wildcard_ == kHasWildcard)
+PortMatchingResult PortMatches(const network::mojom::blink::CSPSource& source,
+ const String& self_protocol,
+ int port,
+ const String& protocol) {
+ if (source.is_port_wildcard)
return PortMatchingResult::kMatchingWildcard;
- if (port == port_) {
- if (port == kPortUnspecified)
+ if (port == source.port) {
+ if (port == url::PORT_UNSPECIFIED)
return PortMatchingResult::kMatchingWildcard;
return PortMatchingResult::kMatchingExact;
}
bool is_scheme_http; // needed for detecting an upgrade when the port is 0
- is_scheme_http = scheme_.IsEmpty() ? policy_->ProtocolEqualsSelf("http")
- : EqualIgnoringASCIICase("http", scheme_);
-
- if ((port_ == 80 ||
- ((port_ == kPortUnspecified || port_ == 443) && is_scheme_http)) &&
- (port == 443 ||
- (port == kPortUnspecified && DefaultPortForProtocol(protocol) == 443))) {
+ is_scheme_http = source.scheme.IsEmpty()
+ ? EqualIgnoringASCIICase("http", self_protocol)
+ : EqualIgnoringASCIICase("http", source.scheme);
+
+ if ((source.port == 80 ||
+ ((source.port == url::PORT_UNSPECIFIED || source.port == 443) &&
+ is_scheme_http)) &&
+ (port == 443 || (port == url::PORT_UNSPECIFIED &&
+ DefaultPortForProtocol(protocol) == 443))) {
return PortMatchingResult::kMatchingUpgrade;
}
- if (port == kPortUnspecified) {
- if (IsDefaultPortForProtocol(port_, protocol))
+ if (port == url::PORT_UNSPECIFIED) {
+ if (IsDefaultPortForProtocol(source.port, protocol))
return PortMatchingResult::kMatchingExact;
-
return PortMatchingResult::kNotMatching;
}
- if (port_ == kPortUnspecified) {
+ if (source.port == url::PORT_UNSPECIFIED) {
if (IsDefaultPortForProtocol(port, protocol))
return PortMatchingResult::kMatchingExact;
-
return PortMatchingResult::kNotMatching;
}
return PortMatchingResult::kNotMatching;
}
-bool CSPSource::Subsumes(CSPSource* other) const {
- if (SchemeMatches(other->scheme_) == SchemeMatchingResult::kNotMatching)
- return false;
-
- if (other->IsSchemeOnly() || IsSchemeOnly())
- return IsSchemeOnly();
+// Helper inline functions for Port and Scheme MatchingResult enums
+bool inline RequiresUpgrade(const PortMatchingResult result) {
+ return result == PortMatchingResult::kMatchingUpgrade;
+}
+bool inline RequiresUpgrade(const SchemeMatchingResult result) {
+ return result == SchemeMatchingResult::kMatchingUpgrade;
+}
- if ((host_wildcard_ == kNoWildcard &&
- other->host_wildcard_ == kHasWildcard) ||
- (port_wildcard_ == kNoWildcard &&
- other->port_wildcard_ == kHasWildcard)) {
- return false;
- }
+bool inline CanUpgrade(const PortMatchingResult result) {
+ return result == PortMatchingResult::kMatchingUpgrade ||
+ result == PortMatchingResult::kMatchingWildcard;
+}
- bool host_subsumes = other->host_wildcard_ == kHasWildcard
- ? HostMatches("." + other->host_)
- : HostMatches(other->host_);
- bool port_subsumes = (port_wildcard_ == kHasWildcard) ||
- PortMatches(other->port_, other->scheme_) !=
- PortMatchingResult::kNotMatching;
- bool path_subsumes = PathMatches(other->path_);
- return host_subsumes && port_subsumes && path_subsumes;
+bool inline CanUpgrade(const SchemeMatchingResult result) {
+ return result == SchemeMatchingResult::kMatchingUpgrade;
}
-bool CSPSource::IsSimilar(CSPSource* other) const {
- bool schemes_match =
- SchemeMatches(other->scheme_) != SchemeMatchingResult::kNotMatching ||
- other->SchemeMatches(scheme_) != SchemeMatchingResult::kNotMatching;
- if (!schemes_match || IsSchemeOnly() || other->IsSchemeOnly())
- return schemes_match;
- bool hosts_match =
- HostMatches((other->host_wildcard_ ? "*." : "") + other->host_) ||
- other->HostMatches((host_wildcard_ ? "*." : "") + host_);
- bool ports_match =
- (other->port_wildcard_ == kHasWildcard) ||
- PortMatches(other->port_, other->scheme_) !=
- PortMatchingResult::kNotMatching ||
- other->PortMatches(port_, scheme_) != PortMatchingResult::kNotMatching;
- bool paths_match = PathMatches(other->path_) || other->PathMatches(path_);
- if (hosts_match && ports_match && paths_match)
- return true;
+} // namespace
- return false;
-}
+bool CSPSourceMatches(const network::mojom::blink::CSPSource& source,
+ const String& self_protocol,
+ const KURL& url,
+ ResourceRequest::RedirectStatus redirect_status) {
+ SchemeMatchingResult schemes_match =
+ SchemeMatches(source, url.Protocol(), self_protocol);
+ if (schemes_match == SchemeMatchingResult::kNotMatching)
+ return false;
+ if (CSPSourceIsSchemeOnly(source))
+ return true;
+ bool paths_match = (redirect_status == RedirectStatus::kFollowedRedirect) ||
+ PathMatches(source, url.GetPath());
+ PortMatchingResult ports_match = PortMatches(
+ source, self_protocol, url.HasPort() ? url.Port() : url::PORT_UNSPECIFIED,
+ url.Protocol());
-CSPSource* CSPSource::Intersect(CSPSource* other) const {
- if (!IsSimilar(other))
- return nullptr;
-
- String scheme =
- other->SchemeMatches(scheme_) != SchemeMatchingResult::kNotMatching
- ? scheme_
- : other->scheme_;
- if (IsSchemeOnly() || other->IsSchemeOnly()) {
- const CSPSource* stricter = IsSchemeOnly() ? other : this;
- return MakeGarbageCollected<CSPSource>(
- policy_, scheme, stricter->host_, stricter->port_, stricter->path_,
- stricter->host_wildcard_, stricter->port_wildcard_);
+ // if either the scheme or the port would require an upgrade (e.g. from http
+ // to https) then check that both of them can upgrade to ensure that we don't
+ // run into situations where we only upgrade the port but not the scheme or
+ // viceversa
+ if ((RequiresUpgrade(schemes_match) || (RequiresUpgrade(ports_match))) &&
+ (!CanUpgrade(schemes_match) || !CanUpgrade(ports_match))) {
+ return false;
}
- // Pick the host without wildcard, or if both have a wildcard, pick the
- // longer one.
- String host = (host_wildcard_ == kNoWildcard ||
- (other->host_wildcard_ == kHasWildcard &&
- host_.length() > other->host_.length()))
- ? host_
- : other->host_;
- // Since sources are similar and paths match, pick the longer one.
- String path = path_.length() > other->path_.length() ? path_ : other->path_;
- // Choose this port if the other port is empty, has wildcard or is a port for
- // a less secure scheme such as "http" whereas scheme of this is "https", in
- // which case the lengths would differ.
- int port = (other->port_wildcard_ == kHasWildcard ||
- other->port_ == kPortUnspecified ||
- scheme_.length() > other->scheme_.length())
- ? port_
- : other->port_;
- WildcardDisposition host_wildcard =
- (host_wildcard_ == kHasWildcard) ? other->host_wildcard_ : host_wildcard_;
- WildcardDisposition port_wildcard =
- (port_wildcard_ == kHasWildcard) ? other->port_wildcard_ : port_wildcard_;
- return MakeGarbageCollected<CSPSource>(policy_, scheme, host, port, path,
- host_wildcard, port_wildcard);
+ return HostMatches(source, url.Host()) &&
+ ports_match != PortMatchingResult::kNotMatching && paths_match;
}
-bool CSPSource::IsSchemeOnly() const {
- return host_.IsEmpty() && (host_wildcard_ == kNoWildcard);
-}
+bool CSPSourceMatchesAsSelf(const network::mojom::blink::CSPSource& source,
+ const KURL& url) {
+ // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression
+ // Step 4.
+ SchemeMatchingResult schemes_match =
+ SchemeMatches(source, url.Protocol(), source.scheme);
+ bool hosts_match = HostMatches(source, url.Host());
+ PortMatchingResult ports_match = PortMatches(
+ source, source.scheme, url.HasPort() ? url.Port() : url::PORT_UNSPECIFIED,
+ url.Protocol());
-bool CSPSource::FirstSubsumesSecond(
- const HeapVector<Member<CSPSource>>& list_a,
- const HeapVector<Member<CSPSource>>& list_b) {
- // Empty vector of CSPSources has an effect of 'none'.
- if (!list_a.size() || !list_b.size())
- return !list_b.size();
-
- // Walk through all the items in |listB|, ensuring that each is subsumed by at
- // least one item in |listA|. If any item in |listB| is not subsumed, return
- // false.
- for (const auto& source_b : list_b) {
- bool found_match = false;
- for (const auto& source_a : list_a) {
- if ((found_match = source_a->Subsumes(source_b)))
- break;
- }
- if (!found_match)
- return false;
+ // check if the origin is exactly matching
+ if (schemes_match == SchemeMatchingResult::kMatchingExact && hosts_match &&
+ (ports_match == PortMatchingResult::kMatchingExact ||
+ ports_match == PortMatchingResult::kMatchingWildcard)) {
+ return true;
}
- return true;
-}
-network::mojom::blink::CSPSourcePtr CSPSource::ExposeForNavigationalChecks()
- const {
- return network::mojom::blink::CSPSource::New(
- scheme_ ? scheme_ : "", // scheme
- host_ ? host_ : "", // host
- port_ == kPortUnspecified ? -1 /* url::PORT_UNSPECIFIED */
- : port_, // port
- path_ ? path_ : "", // path
- host_wildcard_ == kHasWildcard, // is_host_wildcard
- port_wildcard_ == kHasWildcard // is_port_wildcard
- );
+ bool ports_match_or_defaults =
+ (ports_match == PortMatchingResult::kMatchingExact ||
+ ((IsDefaultPortForProtocol(source.port, source.scheme) ||
+ source.port == url::PORT_UNSPECIFIED) &&
+ (!url.HasPort() ||
+ IsDefaultPortForProtocol(url.Port(), url.Protocol()))));
+
+ return hosts_match && ports_match_or_defaults &&
+ (url.Protocol() == "https" || url.Protocol() == "wss" ||
+ source.scheme == "http");
}
-void CSPSource::Trace(Visitor* visitor) const {
- visitor->Trace(policy_);
+bool CSPSourceIsSchemeOnly(const network::mojom::blink::CSPSource& source) {
+ return source.host.IsEmpty() && (!source.is_host_wildcard);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
index 6c582cb555a..24a67ca802a 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_SOURCE_H_
+#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_content_security_policy_struct.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
@@ -15,108 +16,21 @@
namespace blink {
-class ContentSecurityPolicy;
class KURL;
-class CORE_EXPORT CSPSource final : public GarbageCollected<CSPSource> {
- public:
- // Represents the absence of a port.
- const static int kPortUnspecified;
+CORE_EXPORT
+bool CSPSourceIsSchemeOnly(const network::mojom::blink::CSPSource& source);
- enum WildcardDisposition { kNoWildcard, kHasWildcard };
+CORE_EXPORT
+bool CSPSourceMatches(const network::mojom::blink::CSPSource& source,
+ const String& self_protocol,
+ const KURL& url,
+ ResourceRequest::RedirectStatus =
+ ResourceRequest::RedirectStatus::kNoRedirect);
- // NotMatching is the only negative member, the rest are different types of
- // matches. NotMatching should always be 0 to let if statements work nicely
- enum class PortMatchingResult {
- kNotMatching,
- kMatchingWildcard,
- kMatchingUpgrade,
- kMatchingExact
- };
-
- enum class SchemeMatchingResult {
- kNotMatching,
- kMatchingUpgrade,
- kMatchingExact
- };
-
- CSPSource(ContentSecurityPolicy*,
- const String& scheme,
- const String& host,
- int port,
- const String& path,
- WildcardDisposition host_wildcard,
- WildcardDisposition port_wildcard);
- CSPSource(ContentSecurityPolicy* policy, const CSPSource& other);
- bool IsSchemeOnly() const;
- const String& GetScheme() { return scheme_; }
- bool Matches(const KURL&,
- ResourceRequest::RedirectStatus =
- ResourceRequest::RedirectStatus::kNoRedirect) const;
-
- bool MatchesAsSelf(const KURL&);
-
- // Returns true if this CSPSource subsumes the other, as defined by the
- // algorithm at https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
- bool Subsumes(CSPSource*) const;
- // Retrieve the most restrictive information from the two CSPSources if
- // isSimilar is true for the two. Otherwise, return nullptr.
- CSPSource* Intersect(CSPSource*) const;
- // Returns true if the first list subsumes the second, as defined by the
- // algorithm at
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-source-list
- static bool FirstSubsumesSecond(const HeapVector<Member<CSPSource>>&,
- const HeapVector<Member<CSPSource>>&);
-
- network::mojom::blink::CSPSourcePtr ExposeForNavigationalChecks() const;
-
- void Trace(Visitor*) const;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(CSPSourceTest, IsSimilar);
- FRIEND_TEST_ALL_PREFIXES(CSPSourceTest, Intersect);
- FRIEND_TEST_ALL_PREFIXES(CSPSourceTest, IntersectSchemesOnly);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetIntersectCSPSources);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest,
- GetIntersectCSPSourcesSchemes);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, GetSourceVector);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, OperativeDirectiveGivenType);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, SubsumesWithSelf);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetSources);
-
- SchemeMatchingResult SchemeMatches(const String&) const;
- bool HostMatches(const String&) const;
- bool PathMatches(const String&) const;
- // Protocol is necessary to determine default port if it is zero.
- PortMatchingResult PortMatches(int port, const String& protocol) const;
- bool IsSimilar(CSPSource* other) const;
-
- // Helper inline functions for Port and Scheme MatchingResult enums
- bool inline RequiresUpgrade(const PortMatchingResult result) const {
- return result == PortMatchingResult::kMatchingUpgrade;
- }
- bool inline RequiresUpgrade(const SchemeMatchingResult result) const {
- return result == SchemeMatchingResult::kMatchingUpgrade;
- }
-
- bool inline CanUpgrade(const PortMatchingResult result) const {
- return result == PortMatchingResult::kMatchingUpgrade ||
- result == PortMatchingResult::kMatchingWildcard;
- }
-
- bool inline CanUpgrade(const SchemeMatchingResult result) const {
- return result == SchemeMatchingResult::kMatchingUpgrade;
- }
-
- Member<ContentSecurityPolicy> policy_;
- String scheme_;
- String host_;
- int port_;
- String path_;
-
- WildcardDisposition host_wildcard_;
- WildcardDisposition port_wildcard_;
-};
+CORE_EXPORT
+bool CSPSourceMatchesAsSelf(const network::mojom::blink::CSPSource& source,
+ const KURL& url);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
index c0129a5f7b8..9ef2f4e367f 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
@@ -13,1170 +13,437 @@
namespace blink {
-class CSPSourceTest : public testing::Test {
- public:
- CSPSourceTest() : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
-
- protected:
- Persistent<ContentSecurityPolicy> csp;
- struct Source {
- String scheme;
- String host;
- String path;
- // port is CSPSource::kPortUnspecified if it was not specified so the
- // default port for a given scheme will be used.
- const int port;
- CSPSource::WildcardDisposition host_wildcard;
- CSPSource::WildcardDisposition port_wildcard;
- };
-
- bool EqualSources(const Source& a, const Source& b) {
- return a.scheme == b.scheme && a.host == b.host && a.port == b.port &&
- a.path == b.path && a.host_wildcard == b.host_wildcard &&
- a.port_wildcard == b.port_wildcard;
- }
-};
-
-TEST_F(CSPSourceTest, BasicMatching) {
+TEST(CSPSourceTest, BasicMatching) {
KURL base;
- CSPSource source(csp.Get(), "http", "example.com", 8000, "/foo/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com:8000/foo/")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com:8000/foo/bar")));
- EXPECT_TRUE(source.Matches(KURL(base, "HTTP://EXAMPLE.com:8000/foo/BAR")));
-
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:8000/bar/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.com:8000/bar/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:9000/bar/")));
- EXPECT_FALSE(source.Matches(KURL(base, "HTTP://example.com:8000/FOO/bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "HTTP://example.com:8000/FOO/BAR")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "example.com", 8000, "/foo/", false, false);
+
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:8000/foo/")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:8000/foo/bar")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "HTTP://EXAMPLE.com:8000/foo/BAR")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:8000/bar/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://example.com:8000/bar/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:9000/bar/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "HTTP://example.com:8000/FOO/bar")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "HTTP://example.com:8000/FOO/BAR")));
}
-TEST_F(CSPSourceTest, BasicPathMatching) {
+TEST(CSPSourceTest, BasicPathMatching) {
KURL base;
- CSPSource a(csp.Get(), "http", "example.com", 8000, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+ auto a = network::mojom::blink::CSPSource::New("http", "example.com", 8000,
+ "/", false, false);
- EXPECT_TRUE(a.Matches(KURL(base, "http://example.com:8000")));
- EXPECT_TRUE(a.Matches(KURL(base, "http://example.com:8000/")));
- EXPECT_TRUE(a.Matches(KURL(base, "http://example.com:8000/foo/bar")));
+ EXPECT_TRUE(CSPSourceMatches(*a, "", KURL(base, "http://example.com:8000")));
+ EXPECT_TRUE(CSPSourceMatches(*a, "", KURL(base, "http://example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*a, "", KURL(base, "http://example.com:8000/foo/bar")));
- EXPECT_FALSE(a.Matches(KURL(base, "http://example.com:8000path")));
- EXPECT_FALSE(a.Matches(KURL(base, "http://example.com:9000/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*a, "", KURL(base, "http://example.com:8000path")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*a, "", KURL(base, "http://example.com:9000/")));
- CSPSource b(csp.Get(), "http", "example.com", 8000, "",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(b.Matches(KURL(base, "http://example.com:8000")));
- EXPECT_TRUE(b.Matches(KURL(base, "http://example.com:8000/")));
- EXPECT_TRUE(a.Matches(KURL(base, "http://example.com:8000/foo/bar")));
+ auto b = network::mojom::blink::CSPSource::New("http", "example.com", 8000,
+ "", false, false);
+ EXPECT_TRUE(CSPSourceMatches(*b, "", KURL(base, "http://example.com:8000")));
+ EXPECT_TRUE(CSPSourceMatches(*b, "", KURL(base, "http://example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*a, "", KURL(base, "http://example.com:8000/foo/bar")));
- EXPECT_FALSE(b.Matches(KURL(base, "http://example.com:8000path")));
- EXPECT_FALSE(b.Matches(KURL(base, "http://example.com:9000/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*b, "", KURL(base, "http://example.com:8000path")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*b, "", KURL(base, "http://example.com:9000/")));
}
-TEST_F(CSPSourceTest, WildcardMatching) {
+TEST(CSPSourceTest, WildcardMatching) {
KURL base;
- CSPSource source(csp.Get(), "http", "example.com",
- CSPSource::kPortUnspecified, "/", CSPSource::kHasWildcard,
- CSPSource::kHasWildcard);
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "example.com", url::PORT_UNSPECIFIED, "/", true, true);
+
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://foo.example.com:8000/")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://foo.example.com:8000/foo")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://foo.example.com:9000/foo/")));
+ EXPECT_TRUE(CSPSourceMatches(
+ *source, "", KURL(base, "HTTP://FOO.EXAMPLE.com:8000/foo/BAR")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://foo.example.com:8000/")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://foo.example.com:8000/foo")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://foo.example.com:9000/foo/")));
- EXPECT_TRUE(
- source.Matches(KURL(base, "HTTP://FOO.EXAMPLE.com:8000/foo/BAR")));
-
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:8000/foo")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:9000/foo/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.foo.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.foo.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.com:8000/bar/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/foo")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:9000/foo/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.foo.com:8000/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://example.foo.com:8000/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://example.com:8000/bar/")));
}
-TEST_F(CSPSourceTest, RedirectMatching) {
+TEST(CSPSourceTest, RedirectMatching) {
KURL base;
- CSPSource source(csp.Get(), "http", "example.com", 8000, "/bar/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "example.com", 8000, "/bar/", false, false);
EXPECT_TRUE(
- source.Matches(KURL(base, "http://example.com:8000/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
EXPECT_TRUE(
- source.Matches(KURL(base, "http://example.com:8000/foo"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/foo"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
// Should not allow upgrade of port or scheme without upgrading both
EXPECT_FALSE(
- source.Matches(KURL(base, "https://example.com:8000/foo"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
- EXPECT_FALSE(
- source.Matches(KURL(base, "http://not-example.com:8000/foo"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:9000/foo/"),
- ResourceRequest::RedirectStatus::kNoRedirect));
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:8000/foo"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_FALSE(CSPSourceMatches(
+ *source, "", KURL(base, "http://not-example.com:8000/foo"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://example.com:9000/foo/"),
+ ResourceRequest::RedirectStatus::kNoRedirect));
}
-TEST_F(CSPSourceTest, InsecureSchemeMatchesSecureScheme) {
+TEST(CSPSourceTest, InsecureSchemeMatchesSecureScheme) {
KURL base;
- CSPSource source(csp.Get(), "http", "", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kHasWildcard);
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "", url::PORT_UNSPECIFIED, "/", false, true);
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com:8000/")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com:8000/")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://not-example.com:8000/")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://not-example.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "ftp://example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:8000/")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "http://not-example.com:8000/")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "",
+ KURL(base, "https://not-example.com:8000/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "ftp://example.com:8000/")));
}
-TEST_F(CSPSourceTest, InsecureHostSchemeMatchesSecureScheme) {
+TEST(CSPSourceTest, InsecureHostSchemeMatchesSecureScheme) {
KURL base;
- CSPSource source(csp.Get(), "http", "example.com",
- CSPSource::kPortUnspecified, "/", CSPSource::kNoWildcard,
- CSPSource::kHasWildcard);
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "example.com", url::PORT_UNSPECIFIED, "/", false, true);
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://not-example.com:8000/")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com:8000/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://not-example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8000/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://not-example.com:8000/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:8000/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://not-example.com:8000/")));
}
-TEST_F(CSPSourceTest, SchemeIsEmpty) {
+TEST(CSPSourceTest, SchemeIsEmpty) {
KURL base;
// Self scheme is http.
{
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(*SecurityOrigin::CreateFromString("http://a.com/"));
- CSPSource source(csp.Get(), "", "a.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://a.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://a.com")));
- EXPECT_FALSE(source.Matches(KURL(base, "ftp://a.com")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
+ EXPECT_TRUE(CSPSourceMatches(*source, "http", KURL(base, "http://a.com")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "http", KURL(base, "https://a.com")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "http", KURL(base, "ftp://a.com")));
}
// Self scheme is https.
{
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(*SecurityOrigin::CreateFromString("https://a.com/"));
- CSPSource source(csp.Get(), "", "a.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_FALSE(source.Matches(KURL(base, "http://a.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://a.com")));
- EXPECT_FALSE(source.Matches(KURL(base, "ftp://a.com")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "https", KURL(base, "http://a.com")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "https", KURL(base, "https://a.com")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "https", KURL(base, "ftp://a.com")));
}
// Self scheme is not in the http familly.
{
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(*SecurityOrigin::CreateFromString("ftp://a.com/"));
- CSPSource source(csp.Get(), "", "a.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_FALSE(source.Matches(KURL(base, "http://a.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "ftp://a.com")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
+ EXPECT_FALSE(CSPSourceMatches(*source, "ftp", KURL(base, "http://a.com")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "ftp", KURL(base, "ftp://a.com")));
}
// Self scheme is unique
{
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(
- *SecurityOrigin::CreateFromString("non-standard-scheme://a.com/"));
- CSPSource source(csp.Get(), "", "a.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_FALSE(source.Matches(KURL(base, "http://a.com")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
+ EXPECT_FALSE(CSPSourceMatches(*source, "non-standard-scheme",
+ KURL(base, "http://a.com")));
// The reason matching fails is because the host is parsed as "" when
// using a non standard scheme even though it should be parsed as "a.com"
// After adding it to the list of standard schemes it now gets parsed
// correctly. This does not matter in practice though because there is
// no way to render/load anything like "non-standard-scheme://a.com"
- EXPECT_FALSE(source.Matches(KURL(base, "non-standard-scheme://a.com")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "non-standard-scheme",
+ KURL(base, "non-standard-scheme://a.com")));
}
}
-TEST_F(CSPSourceTest, InsecureHostSchemePortMatchesSecurePort) {
+TEST(CSPSourceTest, InsecureHostSchemePortMatchesSecurePort) {
KURL base;
// source scheme is "http", source port is 80
{
- CSPSource source(csp.Get(), "http", "example.com", 80, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com/")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com:80/")));
+ auto source = network::mojom::blink::CSPSource::New("http", "example.com",
+ 80, "/", false, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:80/")));
// Should not allow scheme upgrades unless both port and scheme are upgraded
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:443/")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.com:80/")));
-
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com:443/")));
-
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:8443/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.com:8443/")));
-
- EXPECT_FALSE(source.Matches(KURL(base, "http://not-example.com/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://not-example.com:80/")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://not-example.com:443/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://not-example.com/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://not-example.com:80/")));
- EXPECT_FALSE(source.Matches(KURL(base, "https://not-example.com:443/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:443/")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:80/")));
+
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:443/")));
+
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:8443/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:8443/")));
+
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://not-example.com/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://not-example.com:80/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "http://not-example.com:443/")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "https://not-example.com/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://not-example.com:80/")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "",
+ KURL(base, "https://not-example.com:443/")));
}
// source scheme is "http", source port is 443
{
- CSPSource source(csp.Get(), "http", "example.com", 443, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com/")));
+ auto source = network::mojom::blink::CSPSource::New("http", "example.com",
+ 443, "/", false, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com/")));
}
// source scheme is empty
{
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(*SecurityOrigin::CreateFromString("http://example.com"));
- CSPSource source(csp.Get(), "", "example.com", 80, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com/")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com:443")));
+ auto source = network::mojom::blink::CSPSource::New("", "example.com", 80,
+ "/", false, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://example.com/")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "http",
+ KURL(base, "https://example.com:443")));
// Should not allow upgrade of port or scheme without upgrading both
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:443")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "http",
+ KURL(base, "http://example.com:443")));
}
// source port is empty
{
- CSPSource source(csp.Get(), "http", "example.com",
- CSPSource::kPortUnspecified, "/", CSPSource::kNoWildcard,
- CSPSource::kNoWildcard);
-
- EXPECT_TRUE(source.Matches(KURL(base, "http://example.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "https://example.com:443")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "example.com", url::PORT_UNSPECIFIED, "/", false, false);
+
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:443")));
// Should not allow upgrade of port or scheme without upgrading both
- EXPECT_FALSE(source.Matches(KURL(base, "https://example.com:80")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://example.com:443")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "https://example.com:80")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "", KURL(base, "http://example.com:443")));
}
}
-TEST_F(CSPSourceTest, HostMatches) {
+TEST(CSPSourceTest, HostMatches) {
KURL base;
- Persistent<ContentSecurityPolicy> csp(
- MakeGarbageCollected<ContentSecurityPolicy>());
- csp->SetupSelf(*SecurityOrigin::CreateFromString("http://a.com"));
// Host is * (source-expression = "http://*")
{
- CSPSource source(csp.Get(), "http", "", CSPSource::kPortUnspecified, "",
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://a.com")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://.")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "http", "", url::PORT_UNSPECIFIED, "", true, false);
+ EXPECT_TRUE(CSPSourceMatches(*source, "http", KURL(base, "http://a.com")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "http", KURL(base, "http://.")));
}
// Host is *.foo.bar
{
- CSPSource source(csp.Get(), "", "foo.bar", CSPSource::kPortUnspecified, "",
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- EXPECT_FALSE(source.Matches(KURL(base, "http://a.com")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://foo.bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://o.bar")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://*.foo.bar")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://sub.foo.bar")));
- EXPECT_TRUE(source.Matches(KURL(base, "http://sub.sub.foo.bar")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "foo.bar", url::PORT_UNSPECIFIED, "", true, false);
+ EXPECT_FALSE(CSPSourceMatches(*source, "http", KURL(base, "http://a.com")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "http", KURL(base, "http://bar")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://foo.bar")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "http", KURL(base, "http://o.bar")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://*.foo.bar")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://sub.foo.bar")));
+ EXPECT_TRUE(CSPSourceMatches(*source, "http",
+ KURL(base, "http://sub.sub.foo.bar")));
// Please see http://crbug.com/692505
- EXPECT_TRUE(source.Matches(KURL(base, "http://.foo.bar")));
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://.foo.bar")));
}
// Host is exact.
{
- CSPSource source(csp.Get(), "", "foo.bar", CSPSource::kPortUnspecified, "",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://foo.bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://sub.foo.bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://bar")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "foo.bar", url::PORT_UNSPECIFIED, "", false, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://foo.bar")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://sub.foo.bar")));
+ EXPECT_FALSE(CSPSourceMatches(*source, "http", KURL(base, "http://bar")));
// Please see http://crbug.com/692505
- EXPECT_FALSE(source.Matches(KURL(base, "http://.foo.bar")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://.foo.bar")));
}
// Host matching is case-insensitive.
{
- CSPSource source(csp.Get(), "", "FoO.BaR", CSPSource::kPortUnspecified, "",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://foo.bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://sub.foo.bar")));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "FoO.BaR", url::PORT_UNSPECIFIED, "", false, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://foo.bar")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://sub.foo.bar")));
}
// Wildcarded host matching is case-insensitive.
{
- CSPSource source(csp.Get(), "", "FoO.BaR", CSPSource::kPortUnspecified, "",
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- EXPECT_TRUE(source.Matches(KURL(base, "http://sub.foo.bar")));
- EXPECT_FALSE(source.Matches(KURL(base, "http://foo.bar")));
- }
-}
-
-TEST_F(CSPSourceTest, DoesNotSubsume) {
- struct Source {
- const char* scheme;
- const char* host;
- const char* path;
- const int port;
- };
- struct TestCase {
- const Source a;
- const Source b;
- } cases[] = {
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "another.com", "/", CSPSource::kPortUnspecified}},
- {{"wss", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/", CSPSource::kPortUnspecified}},
- {{"wss", "example.com", "/", CSPSource::kPortUnspecified},
- {"about", "example.com", "/", CSPSource::kPortUnspecified}},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"about", "example.com", "/", CSPSource::kPortUnspecified}},
- {{"http", "example.com", "/1.html", CSPSource::kPortUnspecified},
- {"http", "example.com", "/2.html", CSPSource::kPortUnspecified}},
- {{"http", "example.com", "/", 443}, {"about", "example.com", "/", 800}},
- };
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- EXPECT_FALSE(required->Subsumes(returned));
- // Verify the same test with a and b swapped.
- EXPECT_FALSE(required->Subsumes(returned));
+ auto source = network::mojom::blink::CSPSource::New(
+ "", "FoO.BaR", url::PORT_UNSPECIFIED, "", true, false);
+ EXPECT_TRUE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://sub.foo.bar")));
+ EXPECT_FALSE(
+ CSPSourceMatches(*source, "http", KURL(base, "http://foo.bar")));
}
}
-TEST_F(CSPSourceTest, Subsumes) {
- struct Source {
- const char* scheme;
- const char* path;
- const int port;
- };
- struct TestCase {
- const Source a;
- const Source b;
- bool expected;
- bool expected_when_swapped;
- } cases[] = {
- // Equal signals
- {{"http", "/", CSPSource::kPortUnspecified},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- true},
- {{"https", "/", CSPSource::kPortUnspecified},
- {"https", "/", CSPSource::kPortUnspecified},
- true,
- true},
- {{"https", "/page1.html", CSPSource::kPortUnspecified},
- {"https", "/page1.html", CSPSource::kPortUnspecified},
- true,
- true},
- {{"http", "/", 70}, {"http", "/", 70}, true, true},
- {{"https", "/", 70}, {"https", "/", 70}, true, true},
- {{"https", "/page1.html", CSPSource::kPortUnspecified},
- {"https", "/page1.html", CSPSource::kPortUnspecified},
- true,
- true},
- {{"http", "/page1.html", 70}, {"http", "/page1.html", 70}, true, true},
- {{"https", "/page1.html", 70}, {"https", "/page1.html", 70}, true, true},
- {{"http", "/", CSPSource::kPortUnspecified},
- {"http", "", CSPSource::kPortUnspecified},
- true,
- true},
- {{"http", "/", 80}, {"http", "", 80}, true, true},
- {{"http", "/", 80}, {"https", "", 443}, false, true},
- // One stronger signal in the first CSPSource
- {{"https", "/", CSPSource::kPortUnspecified},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- false},
- {{"http", "/page1.html", CSPSource::kPortUnspecified},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- false},
- {{"http", "/", 80},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- true},
- {{"http", "/", 700},
- {"http", "/", CSPSource::kPortUnspecified},
- false,
- false},
- // Two stronger signals in the first CSPSource
- {{"https", "/page1.html", CSPSource::kPortUnspecified},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- false},
- {{"https", "/", 80},
- {"http", "/", CSPSource::kPortUnspecified},
- false,
- false},
- {{"http", "/page1.html", 80},
- {"http", "/", CSPSource::kPortUnspecified},
- true,
- false},
- // Three stronger signals in the first CSPSource
- {{"https", "/page1.html", 70},
- {"http", "/", CSPSource::kPortUnspecified},
- false,
- false},
- // Mixed signals
- {{"https", "/", CSPSource::kPortUnspecified},
- {"http", "/page1.html", CSPSource::kPortUnspecified},
- false,
- false},
- {{"https", "/", CSPSource::kPortUnspecified},
- {"http", "/", 70},
- false,
- false},
- {{"http", "/page1.html", CSPSource::kPortUnspecified},
- {"http", "/", 70},
- false,
- false},
- };
-
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, "example.com", test.a.port, test.a.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- EXPECT_EQ(required->Subsumes(returned), test.expected);
- // Verify the same test with a and b swapped.
- EXPECT_EQ(returned->Subsumes(required), test.expected_when_swapped);
- }
-
- // When returned CSP has a wildcard but the required csp doesn't, then it is
- // not subsumed.
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, "example.com", test.a.port, test.a.path,
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- EXPECT_FALSE(required->Subsumes(returned));
-
- // If required csp also allows a wildcard in host, then the answer should be
- // as expected.
- CSPSource* required2 = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, "example.com", test.b.port, test.b.path,
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- EXPECT_EQ(required2->Subsumes(returned), test.expected);
- }
-}
-
-TEST_F(CSPSourceTest, WildcardsSubsumes) {
- struct Wildcards {
- CSPSource::WildcardDisposition host_dispotion;
- CSPSource::WildcardDisposition port_dispotion;
- };
- struct TestCase {
- const Wildcards a;
- const Wildcards b;
- bool expected;
- } cases[] = {
- // One out of four possible wildcards.
- {{CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- false},
- {{CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- {CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- false},
- {{CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- true},
- {{CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- false},
- // Two out of four possible wildcards.
- {{CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- {CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- false},
- {{CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- true},
- {{CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- false},
- {{CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- {CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- false},
- {{CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- {CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- true},
- {{CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- false},
- // Three out of four possible wildcards.
- {{CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- {CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- false},
- {{CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- {CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- false},
- {{CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- true},
- {{CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- {CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- false},
- // Four out of four possible wildcards.
- {{CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- {CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- true},
- };
-
- // There are different cases for wildcards but now also the second CSPSource
- // has a more specific path.
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "example.com", CSPSource::kPortUnspecified, "/",
- test.a.host_dispotion, test.a.port_dispotion);
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "example.com", CSPSource::kPortUnspecified, "/",
- test.b.host_dispotion, test.b.port_dispotion);
- EXPECT_EQ(required->Subsumes(returned), test.expected);
-
- // Wildcards should not matter when required csp is stricter than returned
- // csp.
- CSPSource* required2 = MakeGarbageCollected<CSPSource>(
- csp.Get(), "https", "example.com", CSPSource::kPortUnspecified, "/",
- test.b.host_dispotion, test.b.port_dispotion);
- EXPECT_FALSE(required2->Subsumes(returned));
- }
-}
-
-TEST_F(CSPSourceTest, SchemesOnlySubsumes) {
- struct TestCase {
- String a_scheme;
- String b_scheme;
- bool expected;
- } cases[] = {
- // HTTP
- {"http", "http", true},
- {"http", "https", false},
- {"https", "http", true},
- {"https", "https", true},
- // WSS
- {"ws", "ws", true},
- {"ws", "wss", false},
- {"wss", "ws", true},
- {"wss", "wss", true},
- // Unequal
- {"ws", "http", false},
- {"http", "ws", false},
- {"http", "about", false},
- };
-
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a_scheme, "example.com", CSPSource::kPortUnspecified,
- "/", CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b_scheme, "example.com", CSPSource::kPortUnspecified,
- "/", CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- EXPECT_EQ(required->Subsumes(returned), test.expected);
- }
-}
-
-TEST_F(CSPSourceTest, IsSimilar) {
- struct Source {
- const char* scheme;
- const char* host;
- const char* path;
- const int port;
- };
- struct TestCase {
- const Source a;
- const Source b;
- bool is_similar;
- } cases[] = {
- // Similar
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- // Schemes
- {{"https", "example.com", "/", CSPSource::kPortUnspecified},
- {"https", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- {{"https", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- {{"ws", "example.com", "/", CSPSource::kPortUnspecified},
- {"wss", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- // Ports
- {{"http", "example.com", "/", 90},
- {"http", "example.com", "/", 90},
- true},
- {{"wss", "example.com", "/", CSPSource::kPortUnspecified},
- {"wss", "example.com", "/", CSPSource::kPortUnspecified},
- true}, // use default port
- {{"http", "example.com", "/", 80},
- {"http", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/", 80},
- {"https", "example.com", "/", 443},
- true},
- {{"http", "example.com", "/", 80},
- {"https", "example.com", "/", 444},
- false},
- // Paths
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/1.html", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/a/", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/a/b/1.html", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/1.html", CSPSource::kPortUnspecified},
- {"http", "example.com", "/1.html", CSPSource::kPortUnspecified},
- true},
- // Mixed
- {{"http", "example.com", "/1.html", 90},
- {"http", "example.com", "/", 90},
- true},
- {{"https", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/", CSPSource::kPortUnspecified},
- true},
- {{"http", "example.com", "/a/", 90},
- {"https", "example.com", "", 90},
- true},
- {{"wss", "example.com", "/a/", 90},
- {"ws", "example.com", "/a/b/", 90},
- true},
- {{"https", "example.com", "/a/", 90},
- {"https", "example.com", "/a/b/", 90},
- true},
- // Not Similar
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified},
- {"https", "example.com", "", 90},
- false},
- {{"https", "example.com", "/", CSPSource::kPortUnspecified},
- {"https", "example.com", "/", 90},
- false},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "another.com", "/", CSPSource::kPortUnspecified},
- false},
- {{"wss", "example.com", "/", CSPSource::kPortUnspecified},
- {"http", "example.com", "/", CSPSource::kPortUnspecified},
- false},
- {{"wss", "example.com", "/", CSPSource::kPortUnspecified},
- {"about", "example.com", "/", CSPSource::kPortUnspecified},
- false},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified},
- {"about", "example.com", "/", CSPSource::kPortUnspecified},
- false},
- {{"http", "example.com", "/1.html", CSPSource::kPortUnspecified},
- {"http", "example.com", "/2.html", CSPSource::kPortUnspecified},
- false},
- {{"http", "example.com", "/a/1.html", CSPSource::kPortUnspecified},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified},
- false},
- {{"http", "example.com", "/", 443},
- {"about", "example.com", "/", 800},
- false},
- };
-
- for (const auto& test : cases) {
- CSPSource* returned = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- CSPSource* required = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- EXPECT_EQ(returned->IsSimilar(required), test.is_similar);
- // Verify the same test with a and b swapped.
- EXPECT_EQ(required->IsSimilar(returned), test.is_similar);
- }
-}
-
-TEST_F(CSPSourceTest, FirstSubsumesSecond) {
- struct Source {
- const char* scheme;
- const char* host;
- const int port;
- const char* path;
- };
- struct TestCase {
- const Source source_b;
- String scheme_a;
- bool expected;
- } cases[] = {
- // Subsumed.
- {{"http", "example.com", CSPSource::kPortUnspecified, "/"}, "http", true},
- {{"http", "example.com", CSPSource::kPortUnspecified, "/page.html"},
- "http",
- true},
- {{"http", "second-example.com", 80, "/"}, "http", true},
- {{"https", "second-example.com", CSPSource::kPortUnspecified, "/"},
- "http",
- true},
- {{"http", "second-example.com", CSPSource::kPortUnspecified,
- "/page.html"},
- "http",
- true},
- {{"https", "second-example.com", 80, "/page.html"}, "http", true},
- {{"https", "second-example.com", CSPSource::kPortUnspecified, "/"},
- "https",
- true},
- {{"https", "second-example.com", CSPSource::kPortUnspecified,
- "/page.html"},
- "https",
- true},
- {{"http", "example.com", 900, "/"}, "http", true},
- // NOT subsumed.
- {{"http", "second-example.com", CSPSource::kPortUnspecified, "/"},
- "wss",
- false},
- {{"http", "non-example.com", 900, "/"}, "http", false},
- {{"http", "second-example.com", CSPSource::kPortUnspecified, "/"},
- "https",
- false},
- };
-
- CSPSource* no_wildcards = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "example.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* host_wildcard = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "third-example.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kHasWildcard, CSPSource::kNoWildcard);
- CSPSource* port_wildcard = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "third-example.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kNoWildcard, CSPSource::kHasWildcard);
- CSPSource* both_wildcards = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "third-example.com", CSPSource::kPortUnspecified, "/",
- CSPSource::kHasWildcard, CSPSource::kHasWildcard);
- CSPSource* http_only = MakeGarbageCollected<CSPSource>(
- csp.Get(), "http", "", CSPSource::kPortUnspecified, "",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
- CSPSource* https_only = MakeGarbageCollected<CSPSource>(
- csp.Get(), "https", "", CSPSource::kPortUnspecified, "",
- CSPSource::kNoWildcard, CSPSource::kNoWildcard);
-
- for (const auto& test : cases) {
- // Setup default vectors.
- HeapVector<Member<CSPSource>> list_a;
- HeapVector<Member<CSPSource>> list_b;
- list_b.push_back(no_wildcards);
- // Empty `listA` implies `none` is allowed.
- EXPECT_FALSE(CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- list_a.push_back(no_wildcards);
- // Add CSPSources based on the current test.
- list_b.push_back(MakeGarbageCollected<CSPSource>(
- csp.Get(), test.source_b.scheme, test.source_b.host,
- CSPSource::kPortUnspecified, test.source_b.path, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
- list_a.push_back(MakeGarbageCollected<CSPSource>(
- csp.Get(), test.scheme_a, "second-example.com",
- CSPSource::kPortUnspecified, "/", CSPSource::kNoWildcard,
- CSPSource::kNoWildcard));
- // listB contains: ["http://example.com/", test.listB]
- // listA contains: ["http://example.com/",
- // test.schemeA + "://second-example.com/"]
- EXPECT_EQ(test.expected, CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- // If we add another source to `listB` with a host wildcard,
- // then the result should definitely be false.
- list_b.push_back(host_wildcard);
- EXPECT_FALSE(CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- // If we add another source to `listA` with a port wildcard,
- // it does not make `listB` to be subsumed under `listA`.
- list_b.push_back(port_wildcard);
- EXPECT_FALSE(CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- // If however we add another source to `listA` with both wildcards, and the
- // source with the port wildcard, the answer should be as expected before.
- list_a.push_back(both_wildcards);
- list_a.push_back(port_wildcard);
- EXPECT_EQ(test.expected, CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- // If we add a scheme-source expression of 'https' to `listB`, then it
- // should not be subsumed.
- list_b.push_back(https_only);
- EXPECT_FALSE(CSPSource::FirstSubsumesSecond(list_a, list_b));
-
- // If we add a scheme-source expression of 'http' to `listA`, then it should
- // subsume all current epxression in `listB`.
- list_a.push_back(http_only);
- EXPECT_TRUE(CSPSource::FirstSubsumesSecond(list_a, list_b));
- }
-}
-
-TEST_F(CSPSourceTest, Intersect) {
- struct TestCase {
- const Source a;
- const Source b;
- const Source normalized;
- } cases[] = {
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"ws", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"wss", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"wss", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- // Wildcards
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kHasWildcard, CSPSource::kHasWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kHasWildcard, CSPSource::kNoWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kHasWildcard},
- {"http", "sub.example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- // Ports
- {{"http", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- {{"http", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- {{"https", "example.com", "/", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- // Paths
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/1.html", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/1.html", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "example.com", "/a/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/1.html", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/a/b/1.html", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- // Mixed
- {{"http", "example.com", "/1.html", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/1.html", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- };
-
- for (const auto& test : cases) {
- CSPSource* a = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
- test.a.host_wildcard, test.a.port_wildcard);
- CSPSource* b = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
- test.b.host_wildcard, test.b.port_wildcard);
-
- CSPSource* normalized = a->Intersect(b);
- Source intersect_ab = {
- normalized->scheme_, normalized->host_,
- normalized->path_, normalized->port_,
- normalized->host_wildcard_, normalized->port_wildcard_};
- EXPECT_TRUE(EqualSources(intersect_ab, test.normalized))
- <<
-
- "intersect_ab=" << normalized->scheme_ << normalized->host_
- << normalized->path_ << normalized->port_ << normalized->host_wildcard_
- << normalized->port_wildcard_
- << ", test.normalized=" << test.normalized.scheme
- << test.normalized.host << test.normalized.path << test.normalized.port
- << test.normalized.host_wildcard << test.normalized.port_wildcard;
-
- // Verify the same test with A and B swapped. The result should be
- // identical.
- normalized = b->Intersect(a);
- Source intersect_ba = {
- normalized->scheme_, normalized->host_,
- normalized->path_, normalized->port_,
- normalized->host_wildcard_, normalized->port_wildcard_};
- EXPECT_TRUE(EqualSources(intersect_ba, test.normalized))
- <<
-
- "intersect_ba=" << normalized->scheme_ << normalized->host_
- << normalized->path_ << normalized->port_ << normalized->host_wildcard_
- << normalized->port_wildcard_
- << ", test.normalized=" << test.normalized.scheme
- << test.normalized.host << test.normalized.path << test.normalized.port
- << test.normalized.host_wildcard << test.normalized.port_wildcard;
- }
-}
-
-TEST_F(CSPSourceTest, IntersectSchemesOnly) {
- struct TestCase {
- const Source a;
- const Source b;
- const Source normalized;
- } cases[] = {
- // Both sources are schemes only.
- {{"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- {{"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- {{"ws", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"wss", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"wss", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- // One source is a scheme only and the other one has no wildcards.
- {{"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
- {"http", "example.com", "/", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard}},
- {{"http", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- {{"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/page.html", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/page.html", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard}},
- // One source is a scheme only and the other has one or two wildcards.
- {{"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/page.html", 80, CSPSource::kHasWildcard,
- CSPSource::kNoWildcard},
- {"https", "example.com", "/page.html", 80, CSPSource::kHasWildcard,
- CSPSource::kNoWildcard}},
- {{"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/page.html", 80, CSPSource::kNoWildcard,
- CSPSource::kHasWildcard},
- {"https", "example.com", "/page.html", 80, CSPSource::kNoWildcard,
- CSPSource::kHasWildcard}},
- {{"https", "", "", CSPSource::kPortUnspecified, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
- {"http", "example.com", "/page.html", 80, CSPSource::kHasWildcard,
- CSPSource::kHasWildcard},
- {"https", "example.com", "/page.html", 80, CSPSource::kHasWildcard,
- CSPSource::kHasWildcard}},
- };
-
- for (const auto& test : cases) {
- CSPSource* a = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.a.scheme, test.a.host, test.a.port, test.a.path,
- test.a.host_wildcard, test.a.port_wildcard);
-
- CSPSource* b = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.b.scheme, test.b.host, test.b.port, test.b.path,
- test.b.host_wildcard, test.b.port_wildcard);
-
- CSPSource* normalized = a->Intersect(b);
- Source intersect_ab = {
- normalized->scheme_, normalized->host_,
- normalized->path_, normalized->port_,
- normalized->host_wildcard_, normalized->port_wildcard_};
- EXPECT_TRUE(EqualSources(intersect_ab, test.normalized));
-
- // Verify the same test with A and B swapped. The result should be
- // identical.
- normalized = b->Intersect(a);
- Source intersect_ba = {
- normalized->scheme_, normalized->host_,
- normalized->path_, normalized->port_,
- normalized->host_wildcard_, normalized->port_wildcard_};
- EXPECT_TRUE(EqualSources(intersect_ba, test.normalized));
- }
-}
-
-TEST_F(CSPSourceTest, MatchingAsSelf) {
+TEST(CSPSourceTest, MatchingAsSelf) {
// Testing Step 4 of
// https://w3c.github.io/webappsec-csp/#match-url-to-source-expression
+ struct Source {
+ String scheme;
+ String host;
+ String path;
+ int port;
+ bool host_wildcard;
+ bool port_wildcard;
+ };
struct TestCase {
const Source self_source;
const String& url;
bool expected;
} cases[] = {
// Same origin
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"http://example.com:80/",
true},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"https://example.com:443/",
true},
- {{"https", "example.com", "", 4545, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 4545, false, false},
"https://example.com:4545/",
true}, // Mismatching origin
// Mismatching host
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"http://example2.com:80/",
false},
// Ports not matching default schemes
- {{"http", "example.com", "", 8080, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 8080, false, false},
"https://example.com:443/",
false},
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"wss://example.com:8443/",
false},
// Allowed different scheme combinations (4.2.1 and 4.2.2)
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"https://example.com:443/",
true},
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"ws://example.com:80/",
true},
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"wss://example.com:443/",
true},
- {{"ws", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"ws", "example.com", "", 80, false, false},
"https://example.com:443/",
true},
- {{"wss", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"wss", "example.com", "", 443, false, false},
"https://example.com:443/",
true},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"wss://example.com:443/",
true},
// Ports not set (aka default)
- {{"https", "example.com", "", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
+ {{"https", "example.com", "", url::PORT_UNSPECIFIED, false, false},
"wss://example.com:443/",
true},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"wss://example.com/",
true},
// Paths are ignored
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"https://example.com:443/some-path-here",
true},
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"ws://example.com:80/some-other-path-here",
true},
// Custom schemes
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"custom-scheme://example.com/",
false},
- {{"http", "example.com", "", 80, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"http", "example.com", "", 80, false, false},
"custom-scheme://example.com:80/",
false},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"custom-scheme://example.com/",
false},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"custom-scheme://example.com:443/",
false},
- {{"https", "example.com", "", 443, CSPSource::kNoWildcard,
- CSPSource::kNoWildcard},
+ {{"https", "example.com", "", 443, false, false},
"custom-scheme://example.com/some-path",
false},
- {{"http", "example.com", "", CSPSource::kPortUnspecified,
- CSPSource::kNoWildcard, CSPSource::kNoWildcard},
+ {{"http", "example.com", "", url::PORT_UNSPECIFIED, false, false},
"custom-scheme://example.com/some-path",
false},
};
KURL base;
for (const auto& test : cases) {
- CSPSource* self_source = MakeGarbageCollected<CSPSource>(
- csp.Get(), test.self_source.scheme, test.self_source.host,
- test.self_source.port, test.self_source.path,
- test.self_source.host_wildcard, test.self_source.port_wildcard);
- EXPECT_EQ(self_source->MatchesAsSelf(KURL(base, test.url)), test.expected);
+ auto self_source = network::mojom::blink::CSPSource::New(
+ test.self_source.scheme, test.self_source.host, test.self_source.port,
+ test.self_source.path, test.self_source.host_wildcard,
+ test.self_source.port_wildcard);
+ EXPECT_EQ(test.expected,
+ CSPSourceMatchesAsSelf(*self_source, KURL(base, test.url)));
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
index c246ec60f02..3ca01aa7d45 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -61,7 +61,7 @@ void ExecutionContextCSPDelegate::SetSandboxFlags(
WorkerOrWorkletGlobalScope* worklet_or_worker =
DynamicTo<WorkerOrWorkletGlobalScope>(execution_context_.Get());
if (worklet_or_worker) {
- worklet_or_worker->ApplySandboxFlags(mask);
+ worklet_or_worker->SetSandboxFlags(mask);
}
// Just check that all the sandbox flags that are set by CSP have
// already been set on the security context. Meta tags can't set them
@@ -128,6 +128,7 @@ base::Optional<uint16_t> ExecutionContextCSPDelegate::GetStatusCode() {
// TODO(mkwst): We only have status code information for Documents. It would
// be nice to get them for Workers as well.
+ // TODO(crbug.com/1153336) Use network::IsUrlPotentiallyTrustworthy().
Document* document = GetDocument();
if (document && !SecurityOrigin::IsSecure(document->Url()) &&
document->Loader()) {
@@ -166,7 +167,7 @@ void ExecutionContextCSPDelegate::PostViolationReport(
const Vector<String>& report_endpoints,
bool use_reporting_api) {
DCHECK_EQ(is_frame_ancestors_violation,
- ContentSecurityPolicy::DirectiveType::kFrameAncestors ==
+ network::mojom::blink::CSPDirectiveName::FrameAncestors ==
ContentSecurityPolicy::GetDirectiveType(
violation_data.effectiveDirective()));
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.cc
deleted file mode 100644
index 9b791873f3e..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
-
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-MediaListDirective::MediaListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy* policy)
- : CSPDirective(name, value, policy) {
- Vector<UChar> characters;
- value.AppendTo(characters);
- Parse(characters.data(), characters.data() + characters.size());
-}
-
-bool MediaListDirective::Allows(const String& type) const {
- return plugin_types_.Contains(type);
-}
-
-void MediaListDirective::Parse(const UChar* begin, const UChar* end) {
- // TODO(amalika): Revisit parsing algorithm. Right now plugin types are not
- // validated when they are added to m_pluginTypes.
- const UChar* position = begin;
-
- // 'plugin-types ____;' OR 'plugin-types;'
- if (position == end) {
- Policy()->ReportInvalidPluginTypes(String());
- return;
- }
-
- while (position < end) {
- // _____ OR _____mime1/mime1
- // ^ ^
- SkipWhile<UChar, IsASCIISpace>(position, end);
- if (position == end)
- return;
-
- // mime1/mime1 mime2/mime2
- // ^
- begin = position;
- if (!SkipExactly<UChar, IsMediaTypeCharacter>(position, end)) {
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- Policy()->ReportInvalidPluginTypes(
- String(begin, static_cast<wtf_size_t>(position - begin)));
- continue;
- }
- SkipWhile<UChar, IsMediaTypeCharacter>(position, end);
-
- // mime1/mime1 mime2/mime2
- // ^
- if (!SkipExactly<UChar>(position, end, '/')) {
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- Policy()->ReportInvalidPluginTypes(
- String(begin, static_cast<wtf_size_t>(position - begin)));
- continue;
- }
-
- // mime1/mime1 mime2/mime2
- // ^
- if (!SkipExactly<UChar, IsMediaTypeCharacter>(position, end)) {
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- Policy()->ReportInvalidPluginTypes(
- String(begin, static_cast<wtf_size_t>(position - begin)));
- continue;
- }
- SkipWhile<UChar, IsMediaTypeCharacter>(position, end);
-
- // mime1/mime1 mime2/mime2 OR mime1/mime1 OR mime1/mime1/error
- // ^ ^ ^
- if (position < end && IsNotASCIISpace(*position)) {
- SkipWhile<UChar, IsNotASCIISpace>(position, end);
- Policy()->ReportInvalidPluginTypes(
- String(begin, static_cast<wtf_size_t>(position - begin)));
- continue;
- }
- plugin_types_.insert(
- String(begin, static_cast<wtf_size_t>(position - begin)));
-
- DCHECK(position == end || IsASCIISpace(*position));
- }
-}
-
-bool MediaListDirective::Subsumes(
- const HeapVector<Member<MediaListDirective>>& other) const {
- if (!other.size())
- return false;
-
- // Find the effective set of plugins allowed by `other`.
- HashSet<String> normalized_b = other[0]->plugin_types_;
- for (wtf_size_t i = 1; i < other.size(); i++)
- normalized_b = other[i]->GetIntersect(normalized_b);
-
- // Empty list of plugins is equivalent to no plugins being allowed.
- if (!plugin_types_.size())
- return !normalized_b.size();
-
- // Check that each element of `normalizedB` is allowed by `m_pluginTypes`.
- for (auto it = normalized_b.begin(); it != normalized_b.end(); ++it) {
- if (!Allows(*it))
- return false;
- }
-
- return true;
-}
-
-HashSet<String> MediaListDirective::GetIntersect(
- const HashSet<String>& other) const {
- HashSet<String> normalized;
- for (const auto& type : plugin_types_) {
- if (other.Contains(type))
- normalized.insert(type);
- }
-
- return normalized;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.h
deleted file mode 100644
index df84c3e1e55..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_MEDIA_LIST_DIRECTIVE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_MEDIA_LIST_DIRECTIVE_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/frame/csp/csp_directive.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class ContentSecurityPolicy;
-
-class CORE_EXPORT MediaListDirective final : public CSPDirective {
- public:
- MediaListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy*);
- bool Allows(const String& type) const;
-
- // The algorothm is described more extensively here:
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy.
- bool Subsumes(const HeapVector<Member<MediaListDirective>>& other) const;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(MediaListDirectiveTest, GetIntersect);
- FRIEND_TEST_ALL_PREFIXES(MediaListDirectiveTest, Subsumes);
-
- void Parse(const UChar* begin, const UChar* end);
-
- // The algorothm is described more extensively here:
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy.
- HashSet<String> GetIntersect(const HashSet<String>& other) const;
-
- HashSet<String> plugin_types_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaListDirective);
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc
deleted file mode 100644
index 3436ce31d89..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class MediaListDirectiveTest : public testing::Test {
- public:
- MediaListDirectiveTest()
- : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
-
- protected:
- Persistent<ContentSecurityPolicy> csp;
-};
-
-TEST_F(MediaListDirectiveTest, GetIntersect) {
- MediaListDirective a(
- "plugin-types",
- "application/x-shockwave-flash application/pdf text/plain", csp.Get());
- MediaListDirective empty_a("plugin-types", "", csp.Get());
-
- struct TestCase {
- const char* policy_b;
- const Vector<const char*> expected;
- } cases[] = {
- {"", Vector<const char*>()},
- {"text/", Vector<const char*>()},
- {"text/*", Vector<const char*>()},
- {"*/plain", Vector<const char*>()},
- {"text/plain */plain", {"text/plain"}},
- {"text/plain application/*", {"text/plain"}},
- {"text/plain", {"text/plain"}},
- {"application/pdf", {"application/pdf"}},
- {"application/x-shockwave-flash", {"application/x-shockwave-flash"}},
- {"application/x-shockwave-flash text/plain",
- {"application/x-shockwave-flash", "text/plain"}},
- {"application/pdf text/plain", {"text/plain", "application/pdf"}},
- {"application/x-shockwave-flash application/pdf text/plain",
- {"application/x-shockwave-flash", "application/pdf", "text/plain"}},
- };
-
- for (const auto& test : cases) {
- MediaListDirective b("plugin-types", test.policy_b, csp.Get());
-
- HashSet<String> result = a.GetIntersect(b.plugin_types_);
- EXPECT_EQ(result.size(), test.expected.size());
-
- for (auto* const type : test.expected)
- EXPECT_TRUE(result.Contains(type));
-
- // If we change the order of `A` and `B`, intersection should not change.
- result = b.GetIntersect(a.plugin_types_);
- EXPECT_EQ(result.size(), test.expected.size());
-
- for (auto* const type : test.expected)
- EXPECT_TRUE(result.Contains(type));
-
- // When `A` is empty, there should not be any intersection.
- result = empty_a.GetIntersect(b.plugin_types_);
- EXPECT_FALSE(result.size());
- }
-}
-
-TEST_F(MediaListDirectiveTest, Subsumes) {
- MediaListDirective a(
- "plugin-types",
- "application/x-shockwave-flash application/pdf text/plain text/*",
- csp.Get());
-
- struct TestCase {
- const Vector<const char*> policies_b;
- bool subsumed;
- bool subsumed_by_empty_a;
- } cases[] = {
- // `A` subsumes `policiesB`.
- {{""}, true, true},
- {{"text/"}, true, true},
- {{"text/*"}, true, false},
- {{"application/*"}, false, false},
- {{"application/"}, true, true},
- {{"*/plain"}, false, false},
- {{"application"}, true, true},
- {{"text/plain"}, true, false},
- {{"application/pdf"}, true, false},
- {{"application/x-shockwave-flash"}, true, false},
- {{"application/x-shockwave-flash text/plain"}, true, false},
- {{"application/pdf text/plain"}, true, false},
- {{"application/x-shockwave-flash text/plain application/pdf"},
- true,
- false},
- {{"application/x-shockwave-flash text "}, true, false},
- {{"text/* application/x-shockwave-flash"}, true, false},
- {{"application/ application/x-shockwave-flash"}, true, false},
- {{"*/plain application/x-shockwave-flash"}, false, false},
- {{"text/ application/x-shockwave-flash"}, true, false},
- {{"application application/x-shockwave-flash"}, true, false},
- {{"application/x-shockwave-flash text/plain "
- "application/x-blink-test-plugin",
- "application/x-shockwave-flash text/plain"},
- true,
- false},
- {{"application/x-shockwave-flash text/plain "
- "application/x-blink-test-plugin",
- "text/plain"},
- true,
- false},
- {{"application/x-blink-test-plugin", "text/plain"}, true, true},
- {{"application/x-shockwave-flash",
- "text/plain application/x-shockwave-flash"},
- true,
- false},
- {{"application/x-shockwave-flash text/plain",
- "application/x-blink-test-plugin", "text/plain"},
- true,
- true},
- // `A` does not subsumes `policiesB`.
- {Vector<const char*>(), false, false},
- {{"application/x-blink-test-plugin"}, false, false},
- {{"application/x-shockwave-flash text/plain "
- "application/x-blink-test-plugin"},
- false,
- false},
- {{"application/x-shockwave-flash text application/x-blink-test-plugin"},
- false,
- false},
- {{"application/x-invalid-type text application/"}, false, false},
- {{"application/x-blink-test-plugin text application/",
- "application/x-blink-test-plugin"},
- false,
- false},
- };
-
- MediaListDirective empty_a("plugin-types", "", csp.Get());
-
- for (const auto& test : cases) {
- HeapVector<Member<MediaListDirective>> policies_b;
- for (auto* const policy : test.policies_b) {
- policies_b.push_back(MakeGarbageCollected<MediaListDirective>(
- "plugin-types", policy, csp.Get()));
- }
-
- EXPECT_EQ(a.Subsumes(policies_b), test.subsumed);
- EXPECT_EQ(empty_a.Subsumes(policies_b), test.subsumed_by_empty_a);
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.cc
index 3d0dca4726d..3dcf92d9163 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.cc
@@ -2,35 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "require_trusted_types_for_directive.h"
+#include "third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h"
namespace blink {
-RequireTrustedTypesForDirective::RequireTrustedTypesForDirective(
- const String& name,
+network::mojom::blink::CSPRequireTrustedTypesFor CSPRequireTrustedTypesForParse(
const String& value,
- ContentSecurityPolicy* policy)
- : CSPDirective(name, value, policy),
- require_trusted_types_for_script_(false) {
+ ContentSecurityPolicy* policy) {
Vector<String> list;
value.SimplifyWhiteSpace().Split(' ', false, list);
+ network::mojom::blink::CSPRequireTrustedTypesFor result =
+ network::mojom::blink::CSPRequireTrustedTypesFor::None;
+
for (const String& v : list) {
// The only value in the sink group is 'script'.
// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-sink-group
if (v == "'script'") {
- require_trusted_types_for_script_ = true;
- break;
+ result = network::mojom::blink::CSPRequireTrustedTypesFor::Script;
+ } else {
+ policy->ReportInvalidRequireTrustedTypesFor(v);
}
}
-}
-
-bool RequireTrustedTypesForDirective::require() const {
- return require_trusted_types_for_script_;
-}
+ if (result == network::mojom::blink::CSPRequireTrustedTypesFor::None) {
+ policy->ReportInvalidRequireTrustedTypesFor(String());
+ }
-void RequireTrustedTypesForDirective::Trace(Visitor* visitor) const {
- CSPDirective::Trace(visitor);
+ return result;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h
index cdba8df6b65..f3fe6146c2e 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h
@@ -5,23 +5,17 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE_H_
-#include "third_party/blink/renderer/core/frame/csp/csp_directive.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-class ContentSecurityPolicy;
-
-class CORE_EXPORT RequireTrustedTypesForDirective final : public CSPDirective {
- public:
- RequireTrustedTypesForDirective(const String& name,
- const String& value,
- ContentSecurityPolicy*);
- void Trace(Visitor*) const override;
- bool require() const;
-
- private:
- bool require_trusted_types_for_script_;
-};
+CORE_EXPORT
+network::mojom::blink::CSPRequireTrustedTypesFor CSPRequireTrustedTypesForParse(
+ const String& value,
+ ContentSecurityPolicy* policy);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive_test.cc
index c2a48f4a3cb..4c3d45489a8 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive_test.cc
@@ -8,24 +8,29 @@
namespace blink {
-TEST(RequireTrustedTypesForDirectiveTest, TestSinks) {
+TEST(CSPRequireTrustedTypesForTest, Parse) {
struct {
const char* directive;
- const bool result;
- } test_cases[] = {{"'script'", true},
- {"*", false},
- {"", false},
- {"''", false},
- {"script", false},
- {"'script' 'css'", true},
- {"'script' 'script'", true}};
+ network::mojom::blink::CSPRequireTrustedTypesFor result;
+ } test_cases[] = {
+ {"'script'", network::mojom::blink::CSPRequireTrustedTypesFor::Script},
+ {"*", network::mojom::blink::CSPRequireTrustedTypesFor::None},
+ {"", network::mojom::blink::CSPRequireTrustedTypesFor::None},
+ {"''", network::mojom::blink::CSPRequireTrustedTypesFor::None},
+ {"script", network::mojom::blink::CSPRequireTrustedTypesFor::None},
+ {"'script' 'css'",
+ network::mojom::blink::CSPRequireTrustedTypesFor::Script},
+ {"'script' 'script'",
+ network::mojom::blink::CSPRequireTrustedTypesFor::Script}};
for (const auto& test_case : test_cases) {
- RequireTrustedTypesForDirective directive("require-trusted-types-for",
- test_case.directive, nullptr);
SCOPED_TRACE(testing::Message() << " require-trusted-types-for "
<< test_case.directive << ";");
- EXPECT_EQ(directive.require(), test_case.result);
+ EXPECT_EQ(
+ CSPRequireTrustedTypesForParse(
+ test_case.directive, MakeGarbageCollected<ContentSecurityPolicy>()),
+ test_case.result);
}
}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
index 2ae6af8fe24..17ae1426ef9 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.cc
@@ -10,42 +10,25 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
#include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace {
+
struct SupportedPrefixesStruct {
const char* prefix;
- blink::ContentSecurityPolicyHashAlgorithm type;
+ network::mojom::blink::CSPHashAlgorithm type;
};
+
} // namespace
namespace blink {
-SourceListDirective::SourceListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy* policy)
- : CSPDirective(name, value, policy),
- policy_(policy),
- directive_name_(name),
- allow_self_(false),
- allow_star_(false),
- allow_inline_(false),
- allow_eval_(false),
- allow_wasm_eval_(false),
- allow_dynamic_(false),
- allow_unsafe_hashes_(false),
- report_sample_(false),
- hash_algorithms_used_(0) {
- Vector<UChar> characters;
- value.AppendTo(characters);
- Parse(characters.data(), characters.data() + characters.size());
-}
+namespace {
-static bool IsSourceListNone(const UChar* begin, const UChar* end) {
+bool IsSourceListNone(const UChar* begin, const UChar* end) {
SkipWhile<UChar, IsASCIISpace>(begin, end);
const UChar* position = begin;
@@ -62,300 +45,10 @@ static bool IsSourceListNone(const UChar* begin, const UChar* end) {
return true;
}
-bool SourceListDirective::Allows(
- const KURL& url,
- ResourceRequest::RedirectStatus redirect_status) const {
- // Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and
- // the scheme of the protected resource:
- // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
- // schemes, including custom schemes, must be explicitly listed in a source
- // list.
- if (allow_star_) {
- if (url.ProtocolIsInHTTPFamily() || url.ProtocolIs("ftp") ||
- url.ProtocolIs("ws") || url.ProtocolIs("wss") ||
- policy_->ProtocolEqualsSelf(url.Protocol()))
- return true;
-
- return HasSourceMatchInList(url, redirect_status);
- }
-
- if (allow_self_ && policy_->UrlMatchesSelf(url))
- return true;
-
- return HasSourceMatchInList(url, redirect_status);
-}
-
-bool SourceListDirective::AllowInline() const {
- return allow_inline_;
-}
-
-bool SourceListDirective::AllowEval() const {
- return allow_eval_;
-}
-
-bool SourceListDirective::AllowWasmEval() const {
- return allow_wasm_eval_;
-}
-
-bool SourceListDirective::AllowDynamic() const {
- return allow_dynamic_;
-}
-
-bool SourceListDirective::AllowNonce(const String& nonce) const {
- String nonce_stripped = nonce.StripWhiteSpace();
- return !nonce_stripped.IsNull() && nonces_.Contains(nonce_stripped);
-}
-
-bool SourceListDirective::AllowHash(const CSPHashValue& hash_value) const {
- return hashes_.Contains(hash_value);
-}
-
-bool SourceListDirective::AllowUnsafeHashes() const {
- return allow_unsafe_hashes_;
-}
-
-bool SourceListDirective::AllowReportSample() const {
- return report_sample_;
-}
-
-bool SourceListDirective::IsNone() const {
- return !list_.size() && !allow_self_ && !allow_star_ && !allow_inline_ &&
- !allow_unsafe_hashes_ && !allow_eval_ && !allow_wasm_eval_ &&
- !allow_dynamic_ && !nonces_.size() && !hashes_.size();
-}
-
-bool SourceListDirective::IsSelf() const {
- return allow_self_ && !list_.size() && !allow_star_ && !allow_inline_ &&
- !allow_unsafe_hashes_ && !allow_eval_ && !allow_wasm_eval_ &&
- !allow_dynamic_ && !nonces_.size() && !hashes_.size();
-}
-
-uint8_t SourceListDirective::HashAlgorithmsUsed() const {
- return hash_algorithms_used_;
-}
-
-bool SourceListDirective::IsHashOrNoncePresent() const {
- return !nonces_.IsEmpty() ||
- hash_algorithms_used_ != kContentSecurityPolicyHashAlgorithmNone;
-}
-
-bool SourceListDirective::AllowsURLBasedMatching() const {
- return !allow_dynamic_ && (list_.size() || allow_star_ || allow_self_);
-}
-
-// source-list = *WSP [ source *( 1*WSP source ) *WSP ]
-// / *WSP "'none'" *WSP
-//
-void SourceListDirective::Parse(const UChar* begin, const UChar* end) {
- // We represent 'none' as an empty m_list.
- if (IsSourceListNone(begin, end))
- return;
-
- const UChar* position = begin;
- while (position < end) {
- SkipWhile<UChar, IsASCIISpace>(position, end);
- if (position == end)
- return;
-
- const UChar* begin_source = position;
- SkipWhile<UChar, IsSourceCharacter>(position, end);
-
- String scheme, host, path;
- int port = CSPSource::kPortUnspecified;
- CSPSource::WildcardDisposition host_wildcard = CSPSource::kNoWildcard;
- CSPSource::WildcardDisposition port_wildcard = CSPSource::kNoWildcard;
-
- if (ParseSource(begin_source, position, &scheme, &host, &port, &path,
- &host_wildcard, &port_wildcard)) {
- // Wildcard hosts and keyword sources ('self', 'unsafe-inline',
- // etc.) aren't stored in m_list, but as attributes on the source
- // list itself.
- if (scheme.IsEmpty() && host.IsEmpty())
- continue;
- if (ContentSecurityPolicy::GetDirectiveType(host) !=
- ContentSecurityPolicy::DirectiveType::kUndefined)
- policy_->ReportDirectiveAsSourceExpression(directive_name_, host);
- list_.push_back(MakeGarbageCollected<CSPSource>(
- policy_, scheme, host, port, path, host_wildcard, port_wildcard));
- } else {
- policy_->ReportInvalidSourceExpression(
- directive_name_, String(begin_source, static_cast<wtf_size_t>(
- position - begin_source)));
- }
-
- DCHECK(position == end || IsASCIISpace(*position));
- }
-}
-
-// source = scheme ":"
-// / ( [ scheme "://" ] host [ port ] [ path ] )
-// / "'self'"
-bool SourceListDirective::ParseSource(
- const UChar* begin,
- const UChar* end,
- String* scheme,
- String* host,
- int* port,
- String* path,
- CSPSource::WildcardDisposition* host_wildcard,
- CSPSource::WildcardDisposition* port_wildcard) {
- if (begin == end)
- return false;
-
- StringView token(begin, static_cast<wtf_size_t>(end - begin));
-
- if (EqualIgnoringASCIICase("'none'", token))
- return false;
-
- if (end - begin == 1 && *begin == '*') {
- AddSourceStar();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'self'", token)) {
- AddSourceSelf();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'unsafe-inline'", token)) {
- AddSourceUnsafeInline();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'unsafe-eval'", token)) {
- AddSourceUnsafeEval();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'unsafe-allow-redirects'", token) &&
- DirectiveName() == "navigate-to") {
- AddSourceUnsafeAllowRedirects();
- return true;
- }
-
- if (policy_->SupportsWasmEval() &&
- EqualIgnoringASCIICase("'wasm-eval'", token)) {
- AddSourceWasmEval();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'strict-dynamic'", token)) {
- AddSourceStrictDynamic();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'unsafe-hashes'", token)) {
- AddSourceUnsafeHashes();
- return true;
- }
-
- if (EqualIgnoringASCIICase("'report-sample'", token)) {
- AddReportSample();
- return true;
- }
-
- String nonce;
- if (!ParseNonce(begin, end, &nonce))
- return false;
-
- if (!nonce.IsNull()) {
- AddSourceNonce(nonce);
- return true;
- }
-
- DigestValue hash;
- ContentSecurityPolicyHashAlgorithm algorithm =
- kContentSecurityPolicyHashAlgorithmNone;
- if (!ParseHash(begin, end, &hash, &algorithm))
- return false;
-
- if (hash.size() > 0) {
- AddSourceHash(algorithm, hash);
- return true;
- }
-
- const UChar* position = begin;
- const UChar* begin_host = begin;
- const UChar* begin_path = end;
- const UChar* begin_port = nullptr;
-
- SkipWhile<UChar, IsNotColonOrSlash>(position, end);
-
- if (position == end) {
- // host
- // ^
- return ParseHost(begin_host, position, host, host_wildcard);
- }
-
- if (position < end && *position == '/') {
- // host/path || host/ || /
- // ^ ^ ^
- return ParseHost(begin_host, position, host, host_wildcard) &&
- ParsePath(position, end, path);
- }
-
- if (position < end && *position == ':') {
- if (end - position == 1) {
- // scheme:
- // ^
- return ParseScheme(begin, position, scheme);
- }
-
- if (position[1] == '/') {
- // scheme://host || scheme://
- // ^ ^
- if (!ParseScheme(begin, position, scheme) ||
- !SkipExactly<UChar>(position, end, ':') ||
- !SkipExactly<UChar>(position, end, '/') ||
- !SkipExactly<UChar>(position, end, '/'))
- return false;
- if (position == end)
- return false;
- begin_host = position;
- SkipWhile<UChar, IsNotColonOrSlash>(position, end);
- }
-
- if (position < end && *position == ':') {
- // host:port || scheme://host:port
- // ^ ^
- begin_port = position;
- SkipUntil<UChar>(position, end, '/');
- }
- }
-
- if (position < end && *position == '/') {
- // scheme://host/path || scheme://host:port/path
- // ^ ^
- if (position == begin_host)
- return false;
- begin_path = position;
- }
-
- if (!ParseHost(begin_host, begin_port ? begin_port : begin_path, host,
- host_wildcard))
- return false;
-
- if (begin_port) {
- if (!ParsePort(begin_port, begin_path, port, port_wildcard))
- return false;
- } else {
- *port = CSPSource::kPortUnspecified;
- }
-
- if (begin_path != end) {
- if (!ParsePath(begin_path, end, path))
- return false;
- }
-
- return true;
-}
-
// nonce-source = "'nonce-" nonce-value "'"
// nonce-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
//
-bool SourceListDirective::ParseNonce(const UChar* begin,
- const UChar* end,
- String* nonce) {
+bool ParseNonce(const UChar* begin, const UChar* end, String* nonce) {
size_t nonce_length = end - begin;
StringView prefix("'nonce-");
@@ -383,42 +76,39 @@ bool SourceListDirective::ParseNonce(const UChar* begin,
// hash-algorithm = "sha1" / "sha256" / "sha384" / "sha512"
// hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" )
//
-bool SourceListDirective::ParseHash(
- const UChar* begin,
- const UChar* end,
- DigestValue* hash,
- ContentSecurityPolicyHashAlgorithm* hash_algorithm) {
+bool ParseHash(const UChar* begin,
+ const UChar* end,
+ Vector<uint8_t>& hash,
+ network::mojom::blink::CSPHashAlgorithm* hash_algorithm) {
// Any additions or subtractions from this struct should also modify the
// respective entries in the kAlgorithmMap array in
// ContentSecurityPolicy::FillInCSPHashValues().
constexpr SupportedPrefixesStruct kSupportedPrefixes[] = {
- {"'sha256-", kContentSecurityPolicyHashAlgorithmSha256},
- {"'sha384-", kContentSecurityPolicyHashAlgorithmSha384},
- {"'sha512-", kContentSecurityPolicyHashAlgorithmSha512},
- {"'sha-256-", kContentSecurityPolicyHashAlgorithmSha256},
- {"'sha-384-", kContentSecurityPolicyHashAlgorithmSha384},
- {"'sha-512-", kContentSecurityPolicyHashAlgorithmSha512}};
-
- constexpr size_t kSupportedPrefixesLength =
- sizeof(kSupportedPrefixes) / sizeof(kSupportedPrefixes[0]);
+ {"'sha256-", network::mojom::blink::CSPHashAlgorithm::SHA256},
+ {"'sha384-", network::mojom::blink::CSPHashAlgorithm::SHA384},
+ {"'sha512-", network::mojom::blink::CSPHashAlgorithm::SHA512},
+ {"'sha-256-", network::mojom::blink::CSPHashAlgorithm::SHA256},
+ {"'sha-384-", network::mojom::blink::CSPHashAlgorithm::SHA384},
+ {"'sha-512-", network::mojom::blink::CSPHashAlgorithm::SHA512}};
StringView prefix;
- *hash_algorithm = kContentSecurityPolicyHashAlgorithmNone;
size_t hash_length = end - begin;
- for (size_t i = 0; i < kSupportedPrefixesLength; i++) {
- prefix = kSupportedPrefixes[i].prefix;
+ DCHECK_EQ(*hash_algorithm, network::mojom::blink::CSPHashAlgorithm::None);
+
+ for (auto supported_prefix : kSupportedPrefixes) {
+ prefix = supported_prefix.prefix;
// TODO(esprehn): Should be StringView(begin, end -
// begin).startsWith(prefix).
if (hash_length > prefix.length() &&
EqualIgnoringASCIICase(prefix, StringView(begin, prefix.length()))) {
- *hash_algorithm = kSupportedPrefixes[i].type;
+ *hash_algorithm = supported_prefix.type;
break;
}
}
- if (*hash_algorithm == kContentSecurityPolicyHashAlgorithmNone)
+ if (*hash_algorithm == network::mojom::blink::CSPHashAlgorithm::None)
return true;
const UChar* position = begin + prefix.length();
@@ -437,24 +127,24 @@ bool SourceListDirective::ParseHash(
if (position + 1 != end || *position != '\'' || position == hash_begin)
return false;
- Vector<char> hash_vector;
// We accept base64url-encoded data here by normalizing it to base64.
+ Vector<char> out;
Base64Decode(NormalizeToBase64(String(
hash_begin, static_cast<wtf_size_t>(position - hash_begin))),
- hash_vector);
- if (hash_vector.size() > kMaxDigestSize)
+ out);
+ if (out.size() > kMaxDigestSize)
return false;
- hash->Append(reinterpret_cast<uint8_t*>(hash_vector.data()),
- hash_vector.size());
+
+ DCHECK(hash.IsEmpty());
+ for (char el : out)
+ hash.push_back(el);
return true;
}
// ; <scheme> production from RFC 3986
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
//
-bool SourceListDirective::ParseScheme(const UChar* begin,
- const UChar* end,
- String* scheme) {
+bool ParseScheme(const UChar* begin, const UChar* end, String* scheme) {
DCHECK(begin <= end);
DCHECK(scheme->IsEmpty());
@@ -480,14 +170,13 @@ bool SourceListDirective::ParseScheme(const UChar* begin,
// host-char = ALPHA / DIGIT / "-"
//
// static
-bool SourceListDirective::ParseHost(
- const UChar* begin,
- const UChar* end,
- String* host,
- CSPSource::WildcardDisposition* host_wildcard) {
+bool ParseHost(const UChar* begin,
+ const UChar* end,
+ String* host,
+ bool* host_wildcard) {
DCHECK(begin <= end);
DCHECK(host->IsEmpty());
- DCHECK(*host_wildcard == CSPSource::kNoWildcard);
+ DCHECK(!*host_wildcard);
if (begin == end)
return false;
@@ -496,7 +185,7 @@ bool SourceListDirective::ParseHost(
// Parse "*" or [ "*." ].
if (SkipExactly<UChar>(position, end, '*')) {
- *host_wildcard = CSPSource::kHasWildcard;
+ *host_wildcard = true;
if (position == end) {
// "*"
@@ -526,9 +215,11 @@ bool SourceListDirective::ParseHost(
return true;
}
-bool SourceListDirective::ParsePath(const UChar* begin,
- const UChar* end,
- String* path) {
+bool ParsePath(const UChar* begin,
+ const UChar* end,
+ String* path,
+ ContentSecurityPolicy* policy,
+ const String& directive_name) {
DCHECK(begin <= end);
DCHECK(path->IsEmpty());
@@ -537,8 +228,8 @@ bool SourceListDirective::ParsePath(const UChar* begin,
// path/to/file.js?query=string || path/to/file.js#anchor
// ^ ^
if (position < end) {
- policy_->ReportInvalidPathCharacter(
- directive_name_, String(begin, static_cast<wtf_size_t>(end - begin)),
+ policy->ReportInvalidPathCharacter(
+ directive_name, String(begin, static_cast<wtf_size_t>(end - begin)),
*position);
}
@@ -553,14 +244,13 @@ bool SourceListDirective::ParsePath(const UChar* begin,
// port = ":" ( 1*DIGIT / "*" )
//
-bool SourceListDirective::ParsePort(
- const UChar* begin,
- const UChar* end,
- int* port,
- CSPSource::WildcardDisposition* port_wildcard) {
+bool ParsePort(const UChar* begin,
+ const UChar* end,
+ int* port,
+ bool* port_wildcard) {
DCHECK(begin <= end);
- DCHECK_EQ(*port, CSPSource::kPortUnspecified);
- DCHECK(*port_wildcard == CSPSource::kNoWildcard);
+ DCHECK_EQ(*port, url::PORT_UNSPECIFIED);
+ DCHECK(!*port_wildcard);
if (!SkipExactly<UChar>(begin, end, ':'))
NOTREACHED();
@@ -569,8 +259,8 @@ bool SourceListDirective::ParsePort(
return false;
if (end - begin == 1 && *begin == '*') {
- *port = CSPSource::kPortUnspecified;
- *port_wildcard = CSPSource::kHasWildcard;
+ *port = url::PORT_UNSPECIFIED;
+ *port_wildcard = true;
return true;
}
@@ -586,299 +276,346 @@ bool SourceListDirective::ParsePort(
return ok;
}
-void SourceListDirective::AddSourceSelf() {
- allow_self_ = true;
-}
+// source = scheme ":"
+// / ( [ scheme "://" ] host [ port ] [ path ] )
+// / "'self'"
+bool ParseSourceExpression(const UChar* begin,
+ const UChar* end,
+ ContentSecurityPolicy* policy,
+ const String& directive_name,
+ network::mojom::blink::CSPSource& parsed_source) {
+ const UChar* position = begin;
+ const UChar* begin_host = begin;
+ const UChar* begin_path = end;
+ const UChar* begin_port = nullptr;
-void SourceListDirective::AddSourceStar() {
- allow_star_ = true;
-}
+ SkipWhile<UChar, IsNotColonOrSlash>(position, end);
-void SourceListDirective::AddSourceUnsafeAllowRedirects() {
- allow_redirects_ = true;
-}
+ if (position == end) {
+ // host
+ // ^
+ return ParseHost(begin_host, position, &parsed_source.host,
+ &parsed_source.is_host_wildcard);
+ }
-void SourceListDirective::AddSourceUnsafeInline() {
- allow_inline_ = true;
-}
+ if (position < end && *position == '/') {
+ // host/path || host/ || /
+ // ^ ^ ^
+ return ParseHost(begin_host, position, &parsed_source.host,
+ &parsed_source.is_host_wildcard) &&
+ ParsePath(position, end, &parsed_source.path, policy,
+ directive_name);
+ }
-void SourceListDirective::AddSourceUnsafeEval() {
- allow_eval_ = true;
-}
+ if (position < end && *position == ':') {
+ if (end - position == 1) {
+ // scheme:
+ // ^
+ return ParseScheme(begin, position, &parsed_source.scheme);
+ }
-void SourceListDirective::AddSourceWasmEval() {
- allow_wasm_eval_ = true;
-}
+ if (position[1] == '/') {
+ // scheme://host || scheme://
+ // ^ ^
+ if (!ParseScheme(begin, position, &parsed_source.scheme) ||
+ !SkipExactly<UChar>(position, end, ':') ||
+ !SkipExactly<UChar>(position, end, '/') ||
+ !SkipExactly<UChar>(position, end, '/'))
+ return false;
+ if (position == end)
+ return false;
+ begin_host = position;
+ SkipWhile<UChar, IsNotColonOrSlash>(position, end);
+ }
-void SourceListDirective::AddSourceStrictDynamic() {
- allow_dynamic_ = true;
-}
+ if (position < end && *position == ':') {
+ // host:port || scheme://host:port
+ // ^ ^
+ begin_port = position;
+ SkipUntil<UChar>(position, end, '/');
+ }
+ }
-void SourceListDirective::AddSourceUnsafeHashes() {
- allow_unsafe_hashes_ = true;
-}
+ if (position < end && *position == '/') {
+ // scheme://host/path || scheme://host:port/path
+ // ^ ^
+ if (position == begin_host)
+ return false;
+ begin_path = position;
+ }
-void SourceListDirective::AddReportSample() {
- report_sample_ = true;
-}
+ if (!ParseHost(begin_host, begin_port ? begin_port : begin_path,
+ &parsed_source.host, &parsed_source.is_host_wildcard))
+ return false;
-void SourceListDirective::AddSourceNonce(const String& nonce) {
- nonces_.insert(nonce);
-}
+ if (begin_port) {
+ if (!ParsePort(begin_port, begin_path, &parsed_source.port,
+ &parsed_source.is_port_wildcard))
+ return false;
+ } else {
+ parsed_source.port = url::PORT_UNSPECIFIED;
+ }
-void SourceListDirective::AddSourceHash(
- const ContentSecurityPolicyHashAlgorithm& algorithm,
- const DigestValue& hash) {
- hashes_.insert(CSPHashValue(algorithm, hash));
- hash_algorithms_used_ |= algorithm;
-}
+ if (begin_path != end) {
+ if (!ParsePath(begin_path, end, &parsed_source.path, policy,
+ directive_name))
+ return false;
+ }
-void SourceListDirective::AddSourceToMap(
- HeapHashMap<String, Member<CSPSource>>& hash_map,
- CSPSource* source) {
- hash_map.insert(source->GetScheme(), source);
- if (source->GetScheme() == "http")
- hash_map.insert("https", source);
- else if (source->GetScheme() == "ws")
- hash_map.insert("wss", source);
+ return true;
}
-bool SourceListDirective::HasSourceMatchInList(
- const KURL& url,
- ResourceRequest::RedirectStatus redirect_status) const {
- for (wtf_size_t i = 0; i < list_.size(); ++i) {
- if (list_[i]->Matches(url, redirect_status))
- return true;
- }
+bool ParseSource(const UChar* begin,
+ const UChar* end,
+ network::mojom::blink::CSPSourceList& source_list,
+ ContentSecurityPolicy* policy,
+ const String& directive_name) {
+ if (begin == end)
+ return false;
- return false;
-}
+ StringView token(begin, static_cast<wtf_size_t>(end - begin));
-bool SourceListDirective::AllowAllInline() const {
- const ContentSecurityPolicy::DirectiveType& type =
- ContentSecurityPolicy::GetDirectiveType(directive_name_);
- if (type != ContentSecurityPolicy::DirectiveType::kDefaultSrc &&
- !ContentSecurityPolicy::IsScriptDirective(type) &&
- !ContentSecurityPolicy::IsStyleDirective(type)) {
+ if (EqualIgnoringASCIICase("'none'", token))
return false;
+
+ if (end - begin == 1 && *begin == '*') {
+ source_list.allow_star = true;
+ return true;
}
- return allow_inline_ && !IsHashOrNoncePresent() &&
- (!ContentSecurityPolicy::IsScriptDirective(type) || !allow_dynamic_);
-}
+ if (EqualIgnoringASCIICase("'self'", token)) {
+ source_list.allow_self = true;
+ return true;
+ }
-HeapVector<Member<CSPSource>> SourceListDirective::GetSources(
- Member<CSPSource> self) const {
- HeapVector<Member<CSPSource>> sources = list_;
- if (allow_star_) {
- sources.push_back(MakeGarbageCollected<CSPSource>(
- policy_, "ftp", String(), CSPSource::kPortUnspecified, String(),
- CSPSource::kNoWildcard, CSPSource::kNoWildcard));
- sources.push_back(MakeGarbageCollected<CSPSource>(
- policy_, "ws", String(), CSPSource::kPortUnspecified, String(),
- CSPSource::kNoWildcard, CSPSource::kNoWildcard));
- sources.push_back(MakeGarbageCollected<CSPSource>(
- policy_, "http", String(), CSPSource::kPortUnspecified, String(),
- CSPSource::kNoWildcard, CSPSource::kNoWildcard));
- if (self) {
- sources.push_back(MakeGarbageCollected<CSPSource>(
- policy_, self->GetScheme(), String(), CSPSource::kPortUnspecified,
- String(), CSPSource::kNoWildcard, CSPSource::kNoWildcard));
- }
- } else if (allow_self_ && self) {
- sources.push_back(self);
+ if (EqualIgnoringASCIICase("'unsafe-inline'", token)) {
+ source_list.allow_inline = true;
+ return true;
}
- return sources;
-}
+ if (EqualIgnoringASCIICase("'unsafe-eval'", token)) {
+ source_list.allow_eval = true;
+ return true;
+ }
+
+ if (EqualIgnoringASCIICase("'unsafe-allow-redirects'", token)) {
+ source_list.allow_response_redirects = true;
+ return true;
+ }
+
+ if (policy->SupportsWasmEval() &&
+ EqualIgnoringASCIICase("'wasm-eval'", token)) {
+ source_list.allow_wasm_eval = true;
+ return true;
+ }
-bool SourceListDirective::Subsumes(
- const HeapVector<Member<SourceListDirective>>& other) const {
- if (!other.size() || other[0]->IsNone())
- return other.size();
-
- bool allow_inline_other = other[0]->allow_inline_;
- bool allow_eval_other = other[0]->allow_eval_;
- bool allow_wasm_eval_other = other[0]->allow_wasm_eval_;
- bool allow_dynamic_other = other[0]->allow_dynamic_;
- bool allow_unsafe_hashes = other[0]->allow_unsafe_hashes_;
- bool is_hash_or_nonce_present_other = other[0]->IsHashOrNoncePresent();
- HashSet<String> nonces_b = other[0]->nonces_;
- HashSet<CSPHashValue> hashes_b = other[0]->hashes_;
-
- HeapVector<Member<CSPSource>> normalized_b =
- other[0]->GetSources(other[0]->policy_->GetSelfSource());
- for (wtf_size_t i = 1; i < other.size(); i++) {
- allow_inline_other = allow_inline_other && other[i]->allow_inline_;
- allow_eval_other = allow_eval_other && other[i]->allow_eval_;
- allow_wasm_eval_other = allow_wasm_eval_other && other[i]->allow_wasm_eval_;
- allow_dynamic_other = allow_dynamic_other && other[i]->allow_dynamic_;
- allow_unsafe_hashes = allow_unsafe_hashes && other[i]->allow_unsafe_hashes_;
- is_hash_or_nonce_present_other =
- is_hash_or_nonce_present_other && other[i]->IsHashOrNoncePresent();
- nonces_b = other[i]->GetIntersectNonces(nonces_b);
- hashes_b = other[i]->GetIntersectHashes(hashes_b);
- normalized_b = other[i]->GetIntersectCSPSources(normalized_b);
+ if (EqualIgnoringASCIICase("'strict-dynamic'", token)) {
+ source_list.allow_dynamic = true;
+ return true;
+ }
+
+ if (EqualIgnoringASCIICase("'unsafe-hashes'", token)) {
+ source_list.allow_unsafe_hashes = true;
+ return true;
}
- if (!SubsumesNoncesAndHashes(nonces_b, hashes_b))
+ if (EqualIgnoringASCIICase("'report-sample'", token)) {
+ source_list.report_sample = true;
+ return true;
+ }
+
+ String nonce;
+ if (!ParseNonce(begin, end, &nonce))
return false;
- const ContentSecurityPolicy::DirectiveType type =
- ContentSecurityPolicy::GetDirectiveType(directive_name_);
- if (ContentSecurityPolicy::IsScriptDirective(type) ||
- ContentSecurityPolicy::IsStyleDirective(type)) {
- if (!allow_eval_ && allow_eval_other)
- return false;
- if (!allow_wasm_eval_ && allow_wasm_eval_other)
- return false;
- if (!allow_unsafe_hashes_ && allow_unsafe_hashes)
- return false;
- bool allow_all_inline_other =
- allow_inline_other && !is_hash_or_nonce_present_other &&
- (!ContentSecurityPolicy::IsScriptDirective(type) ||
- !allow_dynamic_other);
- if (!AllowAllInline() && allow_all_inline_other)
- return false;
+ if (!nonce.IsNull()) {
+ source_list.nonces.push_back(nonce);
+ return true;
}
- if (ContentSecurityPolicy::IsScriptDirective(type) &&
- (allow_dynamic_ || allow_dynamic_other)) {
- // If `this` does not allow `strict-dynamic`, then it must be that `other`
- // does allow, so the result is `false`.
- if (!allow_dynamic_)
- return false;
- // All keyword source expressions have been considered so only CSPSource
- // subsumption is left. However, `strict-dynamic` ignores all CSPSources so
- // for subsumption to be true either `other` must allow `strict-dynamic` or
- // have no allowed CSPSources.
- return allow_dynamic_other || !normalized_b.size();
+ Vector<uint8_t> hash;
+ network::mojom::blink::CSPHashAlgorithm algorithm =
+ network::mojom::blink::CSPHashAlgorithm::None;
+ if (!ParseHash(begin, end, hash, &algorithm))
+ return false;
+
+ if (hash.size() > 0) {
+ source_list.hashes.push_back(
+ network::mojom::blink::CSPHashSource::New(algorithm, hash));
+ return true;
}
- // If embedding CSP specifies `self`, `self` refers to the embedee's origin.
- HeapVector<Member<CSPSource>> normalized_a =
- GetSources(other[0]->policy_->GetSelfSource());
- return CSPSource::FirstSubsumesSecond(normalized_a, normalized_b);
+ // We must initialize all fields of |source_expression| so that it is always
+ // valid for serialization by mojo, even if scheme, host or path are not
+ // provided.
+ auto source_expression =
+ network::mojom::blink::CSPSource::New("", "", -1, "", false, false);
+ if (ParseSourceExpression(begin, end, policy, directive_name,
+ *source_expression)) {
+ source_list.sources.push_back(std::move(source_expression));
+ return true;
+ }
+
+ return false;
}
-network::mojom::blink::CSPSourceListPtr
-SourceListDirective::ExposeForNavigationalChecks() const {
- WTF::Vector<network::mojom::blink::CSPSourcePtr> sources;
- for (const auto& source : list_)
- sources.push_back(source->ExposeForNavigationalChecks());
+// source-list = *WSP [ source *( 1*WSP source ) *WSP ]
+// / *WSP "'none'" *WSP
+//
+network::mojom::blink::CSPSourceListPtr Parse(const UChar* begin,
+ const UChar* end,
+ ContentSecurityPolicy* policy,
+ const String& directive_name) {
+ network::mojom::blink::CSPSourceListPtr source_list =
+ network::mojom::blink::CSPSourceList::New();
+ if (IsSourceListNone(begin, end))
+ return source_list;
+
+ const UChar* position = begin;
+ while (position < end) {
+ SkipWhile<UChar, IsASCIISpace>(position, end);
+ if (position == end)
+ return source_list;
+
+ const UChar* begin_source = position;
+ SkipWhile<UChar, IsSourceCharacter>(position, end);
- // We do not need nonces and hashes for navigational checks
- WTF::Vector<WTF::String> nonces;
- WTF::Vector<network::mojom::blink::CSPHashSourcePtr> hashes;
+ if (ParseSource(begin_source, position, *source_list, policy,
+ directive_name)) {
+ String token(begin_source,
+ static_cast<wtf_size_t>(position - begin_source));
+ if (ContentSecurityPolicy::GetDirectiveType(token) !=
+ CSPDirectiveName::Unknown) {
+ policy->ReportDirectiveAsSourceExpression(
+ directive_name,
+ source_list->sources[source_list->sources.size() - 1]->host);
+ }
+ } else {
+ policy->ReportInvalidSourceExpression(
+ directive_name, String(begin_source, static_cast<wtf_size_t>(
+ position - begin_source)));
+ }
- return network::mojom::blink::CSPSourceList::New(
- std::move(sources), std::move(nonces), std::move(hashes), allow_self_,
- allow_star_, allow_redirects_, allow_inline_, allow_eval_,
- allow_wasm_eval_, allow_dynamic_, allow_unsafe_hashes_, report_sample_);
+ DCHECK(position == end || IsASCIISpace(*position));
+ }
+ return source_list;
}
-bool SourceListDirective::SubsumesNoncesAndHashes(
- const HashSet<String>& nonces,
- const HashSet<CSPHashValue> hashes) const {
- if (!nonces.IsEmpty() && nonces_.IsEmpty())
- return false;
-
- for (const auto& hash : hashes) {
- if (!hashes_.Contains(hash))
- return false;
+bool HasSourceMatchInList(
+ const Vector<network::mojom::blink::CSPSourcePtr>& list,
+ const String& self_protocol,
+ const KURL& url,
+ ResourceRequest::RedirectStatus redirect_status) {
+ for (const auto& source : list) {
+ if (CSPSourceMatches(*source, self_protocol, url, redirect_status)) {
+ return true;
+ }
}
+ return false;
+}
- return true;
+} // namespace
+
+network::mojom::blink::CSPSourceListPtr CSPSourceListParse(
+ const String& name,
+ const String& value,
+ ContentSecurityPolicy* policy) {
+ Vector<UChar> characters;
+ value.AppendTo(characters);
+ return Parse(characters.data(), characters.data() + characters.size(), policy,
+ name);
}
-HashSet<String> SourceListDirective::GetIntersectNonces(
- const HashSet<String>& other) const {
- if (!nonces_.size() || !other.size())
- return !nonces_.size() ? nonces_ : other;
+bool CSPSourceListAllows(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const network::mojom::blink::CSPSource& self_source,
+ const KURL& url,
+ ResourceRequest::RedirectStatus redirect_status) {
+ // Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and
+ // the scheme of the protected resource:
+ // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
+ // schemes, including custom schemes, must be explicitly listed in a source
+ // list.
+ if (source_list.allow_star) {
+ if (url.ProtocolIsInHTTPFamily() || url.ProtocolIs("ftp") ||
+ url.ProtocolIs("ws") || url.ProtocolIs("wss") ||
+ (!url.Protocol().IsEmpty() &&
+ EqualIgnoringASCIICase(url.Protocol(), self_source.scheme)))
+ return true;
- HashSet<String> normalized;
- for (const auto& nonce : nonces_) {
- if (other.Contains(nonce))
- normalized.insert(nonce);
+ return HasSourceMatchInList(source_list.sources, self_source.scheme, url,
+ redirect_status);
+ }
+ if (source_list.allow_self && CSPSourceMatchesAsSelf(self_source, url)) {
+ return true;
}
- return normalized;
+ return HasSourceMatchInList(source_list.sources, self_source.scheme, url,
+ redirect_status);
}
-HashSet<CSPHashValue> SourceListDirective::GetIntersectHashes(
- const HashSet<CSPHashValue>& other) const {
- if (!hashes_.size() || !other.size())
- return !hashes_.size() ? hashes_ : other;
+bool CSPSourceListAllowNonce(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const String& nonce) {
+ String nonce_stripped = nonce.StripWhiteSpace();
+ return !nonce_stripped.IsNull() &&
+ source_list.nonces.Contains(nonce_stripped);
+}
- HashSet<CSPHashValue> normalized;
- for (const auto& hash : hashes_) {
- if (other.Contains(hash))
- normalized.insert(hash);
+bool CSPSourceListAllowHash(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const network::mojom::blink::CSPHashSource& hash_value) {
+ for (const network::mojom::blink::CSPHashSourcePtr& hash :
+ source_list.hashes) {
+ if (*hash == hash_value)
+ return true;
}
+ return false;
+}
- return normalized;
+bool CSPSourceListIsNone(
+ const network::mojom::blink::CSPSourceList& source_list) {
+ return !source_list.sources.size() && !source_list.allow_self &&
+ !source_list.allow_star && !source_list.allow_inline &&
+ !source_list.allow_unsafe_hashes && !source_list.allow_eval &&
+ !source_list.allow_wasm_eval && !source_list.allow_dynamic &&
+ !source_list.nonces.size() && !source_list.hashes.size();
}
-HeapHashMap<String, Member<CSPSource>>
-SourceListDirective::GetIntersectSchemesOnly(
- const HeapVector<Member<CSPSource>>& other) const {
- HeapHashMap<String, Member<CSPSource>> schemes_a;
- for (const auto& source_a : list_) {
- if (source_a->IsSchemeOnly())
- AddSourceToMap(schemes_a, source_a);
- }
- // Add schemes only sources if they are present in both `this` and `other`,
- // allowing upgrading `http` to `https` and `ws` to `wss`.
- HeapHashMap<String, Member<CSPSource>> intersect;
- for (const auto& source_b : other) {
- if (source_b->IsSchemeOnly()) {
- if (schemes_a.Contains(source_b->GetScheme()))
- AddSourceToMap(intersect, source_b);
- else if (source_b->GetScheme() == "http" && schemes_a.Contains("https"))
- intersect.insert("https", schemes_a.at("https"));
- else if (source_b->GetScheme() == "ws" && schemes_a.Contains("wss"))
- intersect.insert("wss", schemes_a.at("wss"));
- }
- }
+bool CSPSourceListIsSelf(
+ const network::mojom::blink::CSPSourceList& source_list) {
+ return source_list.allow_self && !source_list.sources.size() &&
+ !source_list.allow_star && !source_list.allow_inline &&
+ !source_list.allow_unsafe_hashes && !source_list.allow_eval &&
+ !source_list.allow_wasm_eval && !source_list.allow_dynamic &&
+ !source_list.nonces.size() && !source_list.hashes.size();
+}
- return intersect;
+bool CSPSourceListIsHashOrNoncePresent(
+ const network::mojom::blink::CSPSourceList& source_list) {
+ return !source_list.nonces.IsEmpty() || !source_list.hashes.IsEmpty();
}
-HeapVector<Member<CSPSource>> SourceListDirective::GetIntersectCSPSources(
- const HeapVector<Member<CSPSource>>& other) const {
- auto schemes_map = GetIntersectSchemesOnly(other);
- HeapVector<Member<CSPSource>> normalized;
- // Add all normalized scheme source expressions.
- for (const auto& it : schemes_map) {
- // We do not add secure versions if insecure schemes are present.
- if ((it.key != "https" || !schemes_map.Contains("http")) &&
- (it.key != "wss" || !schemes_map.Contains("ws"))) {
- normalized.push_back(it.value);
- }
- }
+bool CSPSourceListAllowsURLBasedMatching(
+ const network::mojom::blink::CSPSourceList& source_list) {
+ return !source_list.allow_dynamic &&
+ (source_list.sources.size() || source_list.allow_star ||
+ source_list.allow_self);
+}
- HeapVector<Member<CSPSource>> this_vector =
- GetSources(policy_->GetSelfSource());
- for (const auto& source_a : this_vector) {
- if (schemes_map.Contains(source_a->GetScheme()))
- continue;
-
- for (const auto& source_b : other) {
- // No need to add a host source expression if it is subsumed by the
- // matching scheme source expression.
- if (schemes_map.Contains(source_b->GetScheme()))
- continue;
- if (CSPSource* match = source_b->Intersect(source_a))
- normalized.push_back(match);
- }
+bool CSPSourceListAllowAllInline(
+ CSPDirectiveName directive_type,
+ const network::mojom::blink::CSPSourceList& source_list) {
+ if (directive_type != CSPDirectiveName::DefaultSrc &&
+ !ContentSecurityPolicy::IsScriptDirective(directive_type) &&
+ !ContentSecurityPolicy::IsStyleDirective(directive_type)) {
+ return false;
}
- return normalized;
-}
-void SourceListDirective::Trace(Visitor* visitor) const {
- visitor->Trace(policy_);
- visitor->Trace(list_);
- CSPDirective::Trace(visitor);
+ return source_list.allow_inline &&
+ !CSPSourceListIsHashOrNoncePresent(source_list) &&
+ (!ContentSecurityPolicy::IsScriptDirective(directive_type) ||
+ !source_list.allow_dynamic);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.h
index 4472f7b8bf8..2e1a2732bb3 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.h
+++ b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive.h
@@ -7,141 +7,58 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/frame/csp/csp_directive.h"
#include "third_party/blink/renderer/core/frame/csp/csp_source.h"
-#include "third_party/blink/renderer/platform/crypto.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-class ContentSecurityPolicy;
class KURL;
-class CORE_EXPORT SourceListDirective final : public CSPDirective {
- public:
- SourceListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy*);
- void Trace(Visitor*) const override;
-
- void Parse(const UChar* begin, const UChar* end);
-
- bool Matches(const KURL&,
- ResourceRequest::RedirectStatus =
- ResourceRequest::RedirectStatus::kNoRedirect) const;
-
- bool Allows(const KURL&,
- ResourceRequest::RedirectStatus =
- ResourceRequest::RedirectStatus::kNoRedirect) const;
- bool AllowInline() const;
- bool AllowEval() const;
- bool AllowWasmEval() const;
- bool AllowDynamic() const;
- bool AllowNonce(const String& nonce) const;
- bool AllowHash(const CSPHashValue&) const;
- bool AllowUnsafeHashes() const;
- bool AllowReportSample() const;
- bool IsNone() const;
- bool IsSelf() const;
- bool IsHashOrNoncePresent() const;
- uint8_t HashAlgorithmsUsed() const;
- bool AllowAllInline() const;
- bool AllowsURLBasedMatching() const;
-
- // The algorithm is described more extensively here:
- // https://w3c.github.io/webappsec-csp/embedded/#subsume-source-list
- bool Subsumes(const HeapVector<Member<SourceListDirective>>&) const;
-
- // Export a subset of the source list that affect navigation.
- // It contains every source-expressions, '*', 'none' and 'self'.
- // It doesn't contain 'unsafe-inline' or 'unsafe-eval' for instance.
- network::mojom::blink::CSPSourceListPtr ExposeForNavigationalChecks() const;
- String DirectiveName() const { return directive_name_; }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetIntersectCSPSources);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest,
- GetIntersectCSPSourcesSchemes);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetIntersectNonces);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetIntersectHashes);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, GetSources);
- FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, ParseHost);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, GetSourceVector);
- FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, OperativeDirectiveGivenType);
-
- bool ParseSource(const UChar* begin,
- const UChar* end,
- String* scheme,
- String* host,
- int* port,
- String* path,
- CSPSource::WildcardDisposition*,
- CSPSource::WildcardDisposition*);
- bool ParseScheme(const UChar* begin, const UChar* end, String* scheme);
- static bool ParseHost(const UChar* begin,
- const UChar* end,
- String* host,
- CSPSource::WildcardDisposition*);
- bool ParsePort(const UChar* begin,
- const UChar* end,
- int* port,
- CSPSource::WildcardDisposition*);
- bool ParsePath(const UChar* begin, const UChar* end, String* path);
- bool ParseNonce(const UChar* begin, const UChar* end, String* nonce);
- bool ParseHash(const UChar* begin,
- const UChar* end,
- DigestValue* hash,
- ContentSecurityPolicyHashAlgorithm*);
-
- void AddSourceSelf();
- void AddSourceStar();
- void AddSourceUnsafeAllowRedirects();
- void AddSourceUnsafeInline();
- void AddSourceUnsafeEval();
- void AddSourceWasmEval();
- void AddSourceStrictDynamic();
- void AddSourceUnsafeHashes();
- void AddReportSample();
- void AddSourceNonce(const String& nonce);
- void AddSourceHash(const ContentSecurityPolicyHashAlgorithm&,
- const DigestValue& hash);
-
- static void AddSourceToMap(HeapHashMap<String, Member<CSPSource>>&,
- CSPSource*);
-
- bool HasSourceMatchInList(const KURL&, ResourceRequest::RedirectStatus) const;
- HashSet<String> GetIntersectNonces(const HashSet<String>& other) const;
- HashSet<CSPHashValue> GetIntersectHashes(
- const HashSet<CSPHashValue>& other) const;
- HeapVector<Member<CSPSource>> GetIntersectCSPSources(
- const HeapVector<Member<CSPSource>>& other) const;
- HeapHashMap<String, Member<CSPSource>> GetIntersectSchemesOnly(
- const HeapVector<Member<CSPSource>>& other) const;
- bool SubsumesNoncesAndHashes(const HashSet<String>& nonces,
- const HashSet<CSPHashValue> hashes) const;
- HeapVector<Member<CSPSource>> GetSources(Member<CSPSource>) const;
-
- Member<ContentSecurityPolicy> policy_;
- HeapVector<Member<CSPSource>> list_;
- String directive_name_;
- bool allow_self_;
- bool allow_star_;
- bool allow_inline_;
- bool allow_eval_;
- bool allow_wasm_eval_;
- bool allow_dynamic_;
- bool allow_unsafe_hashes_;
- bool allow_redirects_;
- bool report_sample_;
- HashSet<String> nonces_;
- HashSet<CSPHashValue> hashes_;
- uint8_t hash_algorithms_used_;
-
- DISALLOW_COPY_AND_ASSIGN(SourceListDirective);
-};
+CORE_EXPORT
+network::mojom::blink::CSPSourceListPtr CSPSourceListParse(
+ const String& name,
+ const String& value,
+ ContentSecurityPolicy* policy);
+
+CORE_EXPORT
+bool CSPSourceListAllows(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const network::mojom::blink::CSPSource& self_source,
+ const KURL&,
+ ResourceRequest::RedirectStatus =
+ ResourceRequest::RedirectStatus::kNoRedirect);
+
+CORE_EXPORT
+bool CSPSourceListAllowNonce(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const String& nonce);
+
+CORE_EXPORT
+bool CSPSourceListAllowHash(
+ const network::mojom::blink::CSPSourceList& source_list,
+ const network::mojom::blink::CSPHashSource& hash);
+
+CORE_EXPORT
+bool CSPSourceListIsNone(
+ const network::mojom::blink::CSPSourceList& source_list);
+
+CORE_EXPORT
+bool CSPSourceListIsSelf(
+ const network::mojom::blink::CSPSourceList& source_list);
+
+CORE_EXPORT
+bool CSPSourceListIsHashOrNoncePresent(
+ const network::mojom::blink::CSPSourceList& source_list);
+
+CORE_EXPORT
+bool CSPSourceListAllowAllInline(
+ CSPDirectiveName directive_type,
+ const network::mojom::blink::CSPSourceList& source_list);
+
+CORE_EXPORT
+bool CSPSourceListAllowsURLBasedMatching(
+ const network::mojom::blink::CSPSourceList& source_list);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
index bf0e9518739..004b0dbba58 100644
--- a/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
@@ -19,6 +19,7 @@ class SourceListDirectiveTest : public testing::Test {
public:
SourceListDirectiveTest()
: csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
+ ~SourceListDirectiveTest() override { context->NotifyContextDestroyed(); }
protected:
struct Source {
@@ -26,520 +27,251 @@ class SourceListDirectiveTest : public testing::Test {
String host;
const int port;
String path;
- CSPSource::WildcardDisposition host_wildcard;
- CSPSource::WildcardDisposition port_wildcard;
+ bool host_wildcard;
+ bool port_wildcard;
};
void SetUp() override {
KURL secure_url("https://example.test/image.png");
+ self_source = network::mojom::blink::CSPSource::New("https", "example.test",
+ 443, "", false, false);
context = MakeGarbageCollected<NullExecutionContext>();
context->GetSecurityContext().SetSecurityOrigin(
SecurityOrigin::Create(secure_url));
csp->BindToDelegate(context->GetContentSecurityPolicyDelegate());
}
- ContentSecurityPolicy* SetUpWithOrigin(const String& origin) {
- KURL secure_url(origin);
- auto* context = MakeGarbageCollected<NullExecutionContext>();
- context->GetSecurityContext().SetSecurityOrigin(
- SecurityOrigin::Create(secure_url));
- auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->BindToDelegate(context->GetContentSecurityPolicyDelegate());
- return csp;
- }
-
- bool EqualSources(const Source& a, const Source& b) {
- return a.scheme == b.scheme && a.host == b.host && a.port == b.port &&
- a.path == b.path && a.host_wildcard == b.host_wildcard &&
- a.port_wildcard == b.port_wildcard;
- }
-
Persistent<ContentSecurityPolicy> csp;
Persistent<ExecutionContext> context;
+ network::mojom::blink::CSPSourcePtr self_source;
};
TEST_F(SourceListDirectiveTest, BasicMatchingNone) {
KURL base;
String sources = "'none'";
- SourceListDirective source_list("script-src", sources, csp.Get());
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://example.com/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example.test/")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
+ ASSERT_TRUE(source_list);
+
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example.com/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example.test/")));
}
TEST_F(SourceListDirectiveTest, BasicMatchingStrictDynamic) {
String sources = "'strict-dynamic'";
- SourceListDirective source_list("script-src", sources, csp.Get());
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
- EXPECT_TRUE(source_list.AllowDynamic());
+ EXPECT_TRUE(source_list->allow_dynamic);
}
TEST_F(SourceListDirectiveTest, BasicMatchingUnsafeHashes) {
String sources = "'unsafe-hashes'";
- SourceListDirective source_list("script-src", sources, csp.Get());
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
- EXPECT_TRUE(source_list.AllowUnsafeHashes());
+ EXPECT_TRUE(source_list->allow_unsafe_hashes);
}
TEST_F(SourceListDirectiveTest, BasicMatchingStar) {
KURL base;
String sources = "*";
- SourceListDirective source_list("script-src", sources, csp.Get());
-
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example.com/bar")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.example.com/bar")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "ftp://example.com/")));
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "data:https://example.test/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "blob:https://example.test/")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
+
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example.com/bar")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://foo.example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://foo.example.com/bar")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "ftp://example.com/")));
+
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "data:https://example.test/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "blob:https://example.test/")));
EXPECT_FALSE(
- source_list.Allows(KURL(base, "filesystem:https://example.test/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "file:///etc/hosts")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "applewebdata://example.test/")));
+ CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "filesystem:https://example.test/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "file:///etc/hosts")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "applewebdata://example.test/")));
}
TEST_F(SourceListDirectiveTest, StarallowsSelf) {
KURL base;
String sources = "*";
- SourceListDirective source_list("script-src", sources, csp.Get());
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
- // With a protocol of 'file', '*' allows 'file:':
- scoped_refptr<const SecurityOrigin> origin =
- SecurityOrigin::CreateFromValidTuple("file", "", 0);
- csp->SetupSelf(*origin);
- EXPECT_TRUE(source_list.Allows(KURL(base, "file:///etc/hosts")));
+ auto self_origin =
+ network::mojom::blink::CSPSource::New("file", "", -1, "", false, false);
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "file:///etc/hosts")));
// The other results are the same as above:
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example.com/bar")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.example.com/bar")));
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "data:https://example.test/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "blob:https://example.test/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "http://example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "https://example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "http://example.com/bar")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "http://foo.example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "http://foo.example.com/bar")));
+
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "data:https://example.test/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "blob:https://example.test/")));
EXPECT_FALSE(
- source_list.Allows(KURL(base, "filesystem:https://example.test/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "applewebdata://example.test/")));
+ CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "filesystem:https://example.test/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin,
+ KURL(base, "applewebdata://example.test/")));
}
TEST_F(SourceListDirectiveTest, BasicMatchingSelf) {
KURL base;
String sources = "'self'";
- SourceListDirective source_list("script-src", sources, csp.Get());
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://example.com/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://not-example.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example.test/")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
+
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example.com/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://not-example.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example.test/")));
}
TEST_F(SourceListDirectiveTest, BlobMatchingBlob) {
KURL base;
String sources = "blob:";
- SourceListDirective source_list("script-src", sources, csp.Get());
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example.test/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "blob:https://example.test/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example.test/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "blob:https://example.test/")));
}
TEST_F(SourceListDirectiveTest, BasicMatching) {
KURL base;
String sources = "http://example1.com:8000/foo/ https://example2.com/";
- SourceListDirective source_list("script-src", sources, csp.Get());
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example1.com:8000/foo/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com:8000/foo/")));
EXPECT_TRUE(
- source_list.Allows(KURL(base, "http://example1.com:8000/foo/bar")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example2.com/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example2.com/foo/")));
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://not-example.com/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://example1.com/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example1.com/foo")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://example1.com:9000/foo/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://example1.com:8000/FOO/")));
+ CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com:8000/foo/bar")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example2.com/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example2.com/foo/")));
+
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://not-example.com/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example1.com/foo")));
+ EXPECT_FALSE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example1.com:9000/foo/")));
+ EXPECT_FALSE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example1.com:8000/FOO/")));
}
TEST_F(SourceListDirectiveTest, WildcardMatching) {
KURL base;
String sources =
"http://example1.com:*/foo/ https://*.example2.com/bar/ http://*.test/";
- SourceListDirective source_list("script-src", sources, csp.Get());
-
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example1.com/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example1.com:8000/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example1.com:9000/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://foo.example2.com/bar/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.test/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://foo.bar.test/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example1.com/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example1.com:8000/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://example1.com:9000/foo/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://foo.test/")));
- EXPECT_TRUE(source_list.Allows(KURL(base, "https://foo.bar.test/")));
-
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example1.com:8000/foo")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example2.com:8000/bar")));
- EXPECT_FALSE(
- source_list.Allows(KURL(base, "https://foo.example2.com:8000/bar")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example2.foo.com/bar")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://foo.test.bar/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "https://example2.com/bar/")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://test/")));
-}
-
-TEST_F(SourceListDirectiveTest, RedirectMatching) {
- KURL base;
- String sources = "http://example1.com/foo/ http://example2.com/bar/";
- SourceListDirective source_list("script-src", sources, csp.Get());
-
- EXPECT_TRUE(
- source_list.Allows(KURL(base, "http://example1.com/foo/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
+
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com/foo/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com:8000/foo/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example1.com:9000/foo/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://foo.example2.com/bar/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://foo.test/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://foo.bar.test/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example1.com/foo/")));
EXPECT_TRUE(
- source_list.Allows(KURL(base, "http://example1.com/bar/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
+ CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example1.com:8000/foo/")));
EXPECT_TRUE(
- source_list.Allows(KURL(base, "http://example2.com/bar/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
- EXPECT_TRUE(
- source_list.Allows(KURL(base, "http://example2.com/foo/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
- EXPECT_TRUE(
- source_list.Allows(KURL(base, "https://example1.com/foo/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
- EXPECT_TRUE(
- source_list.Allows(KURL(base, "https://example1.com/bar/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
-
+ CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example1.com:9000/foo/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://foo.test/")));
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://foo.bar.test/")));
+
+ EXPECT_FALSE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "https://example1.com:8000/foo")));
+ EXPECT_FALSE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "https://example2.com:8000/bar")));
EXPECT_FALSE(
- source_list.Allows(KURL(base, "http://example3.com/foo/"),
- ResourceRequest::RedirectStatus::kFollowedRedirect));
-}
-
-TEST_F(SourceListDirectiveTest, GetIntersectCSPSources) {
- String sources =
- "http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/";
- SourceListDirective source_list("script-src", sources, csp.Get());
- struct TestCase {
- String sources;
- String expected;
- } cases[] = {
- {"http://example1.com/foo/ http://sub.example2.com/bar/",
- "http://example1.com/foo/ http://sub.example2.com/bar/"},
- // Normalizing schemes.
- {"https://example1.com/foo/ http://sub.example2.com/bar/",
- "https://example1.com/foo/ http://sub.example2.com/bar/"},
- {"https://example1.com/foo/ https://sub.example2.com/bar/",
- "https://example1.com/foo/ https://sub.example2.com/bar/"},
- {"https://example1.com/foo/ wss://sub.example2.com/bar/",
- "https://example1.com/foo/"},
- // Normalizing hosts.
- {"http://*.com/foo/ http://*.example2.com/bar/",
- "http://example1.com/foo/ http://*.example2.com/bar/"},
- {"http://*.com/foo/ http://foo.example2.com/bar/",
- "http://example1.com/foo/ http://foo.example2.com/bar/"},
- // Normalizing ports.
- {"http://example1.com/foo/ http://sub.example2.com/bar/",
- "http://example1.com/foo/ http://sub.example2.com/bar/"},
- {"http://example1.com/foo/ http://sub.example2.com:90/bar/",
- "http://example1.com/foo/"},
- {"http://example1.com:*/foo/ http://sub.example2.com/bar/",
- "http://example1.com/foo/ http://sub.example2.com/bar/"},
- {"http://*.example3.com:100/bar/ http://example1.com/foo/",
- "http://example1.com/foo/ http://*.example3.com:100/bar/"},
- // Normalizing paths.
- {"http://example1.com/ http://sub.example2.com/",
- "http://example1.com/foo/ http://sub.example2.com/bar/"},
- {"http://example1.com/foo/index.html http://sub.example2.com/bar/",
- "http://example1.com/foo/index.html http://sub.example2.com/bar/"},
- {"http://example1.com/bar http://sub.example2.com/bar/",
- "http://sub.example2.com/bar/"},
- // Not similar to be normalized
- {"http://non-example1.com/foo/ http://non-example2.com/bar/", ""},
- {"https://non-example1.com/foo/ wss://non-example2.com/bar/", ""},
- };
-
- for (const auto& test : cases) {
- SourceListDirective second_list("script-src", test.sources, csp.Get());
- HeapVector<Member<CSPSource>> normalized =
- source_list.GetIntersectCSPSources(second_list.list_);
- SourceListDirective helper_source_list("script-src", test.expected,
- csp.Get());
- HeapVector<Member<CSPSource>> expected = helper_source_list.list_;
- EXPECT_EQ(normalized.size(), expected.size());
- for (wtf_size_t i = 0; i < normalized.size(); i++) {
- Source a = {normalized[i]->scheme_, normalized[i]->host_,
- normalized[i]->port_, normalized[i]->path_,
- normalized[i]->host_wildcard_, normalized[i]->port_wildcard_};
- Source b = {expected[i]->scheme_, expected[i]->host_,
- expected[i]->port_, expected[i]->path_,
- expected[i]->host_wildcard_, expected[i]->port_wildcard_};
- EXPECT_TRUE(EqualSources(a, b));
- }
- }
+ CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://foo.example2.com:8000/bar")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example2.foo.com/bar")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://foo.test.bar/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "https://example2.com/bar/")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://test/")));
}
-TEST_F(SourceListDirectiveTest, GetIntersectCSPSourcesSchemes) {
- SourceListDirective list_a("script-src",
- "http: http://example1.com/foo/ "
- "https://example1.com/foo/ "
- "http://example1.com/bar/page.html "
- "wss: ws://another.test/bar/",
- csp.Get());
- struct TestCase {
- String sources;
- String expected;
- } cases[] = {{"http:", "http:"},
- {"https:", "https:"},
- {"ws:", "wss: ws://another.test/bar/"},
- {"wss:", "wss:"},
- {"https: ws:", "wss: https: ws://another.test/bar/"},
- {"https: http: wss:", "http: wss:"},
- {"https: http: wss:", "http: wss:"},
- {"https: http://another-example1.com/bar/",
- "https: http://another-example1.com/bar/"},
- {"http://*.com/",
- "http://*.com/ http://example1.com/foo/ "
- "https://example1.com/foo/ http://example1.com/bar/page.html"},
- {"http://example1.com/foo/ https://example1.com/foo/",
- "http://example1.com/foo/ https://example1.com/foo/ "
- "http://example1.com/foo/ https://example1.com/foo/ "
- "https://example1.com/foo/ https://example1.com/foo/"},
- {"https://example1.com/foo/ http://example1.com/foo/",
- "https://example1.com/foo/ http://example1.com/foo/ "
- "https://example1.com/foo/ http://example1.com/foo/ "
- "https://example1.com/foo/ https://example1.com/foo/"},
- // If exactly the same policy is specified, it is optimized.
- {"http: http://example1.com/foo/ https://example1.com/foo/ "
- "http://example1.com/bar/page.html wss: ws://another.test/bar/",
- "http: wss: ws://another.test/bar/"}};
-
- for (const auto& test : cases) {
- SourceListDirective list_b("script-src", test.sources, csp.Get());
- HeapVector<Member<CSPSource>> normalized =
- list_a.GetIntersectCSPSources(list_b.list_);
-
- SourceListDirective helper_source_list("script-src", test.expected,
- csp.Get());
- HeapVector<Member<CSPSource>> expected = helper_source_list.list_;
- EXPECT_EQ(normalized.size(), expected.size());
- for (wtf_size_t i = 0; i < expected.size(); i++) {
- Source a = {expected[i]->scheme_, expected[i]->host_,
- expected[i]->port_, expected[i]->path_,
- expected[i]->host_wildcard_, expected[i]->port_wildcard_};
- Source b = {normalized[i]->scheme_, normalized[i]->host_,
- normalized[i]->port_, normalized[i]->path_,
- normalized[i]->host_wildcard_, normalized[i]->port_wildcard_};
- EXPECT_TRUE(EqualSources(a, b));
- }
- }
-}
-
-TEST_F(SourceListDirectiveTest, Subsumes) {
+TEST_F(SourceListDirectiveTest, RedirectMatching) {
KURL base;
- String required_sources =
- "http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/";
- SourceListDirective required("script-src", required_sources, csp.Get());
-
- struct TestCase {
- Vector<String> sources_vector;
- bool expected;
- } cases[] = {
- // Non-intersecting source lists give an effective policy of 'none', which
- // is always subsumed.
- {{"http://example1.com/bar/", "http://*.example3.com:*/bar/"}, true},
- {{"http://example1.com/bar/",
- "http://*.example3.com:*/bar/ http://*.example2.com/bar/"},
- true},
- // Lists that intersect into one of the required sources are subsumed.
- {{"http://example1.com/foo/"}, true},
- {{"http://*.example2.com/bar/"}, true},
- {{"http://*.example3.com:*/bar/"}, true},
- {{"https://example1.com/foo/",
- "http://*.example1.com/foo/ http://*.example2.com/bar/"},
- true},
- {{"http://sub.example2.com/bar/",
- "http://*.example3.com:*/bar/ http://*.example2.com/bar/"},
- true},
- {{"http://example3.com:100/bar/",
- "http://*.example3.com:*/bar/ http://*.example2.com/bar/"},
- true},
- // Lists that intersect into two of the required sources are subsumed.
- {{"http://example1.com/foo/ http://*.example2.com/bar/"}, true},
- {{"http://example1.com/foo/ http://sub.example2.com/bar/",
- "http://sub.example2.com/bar/ http://example1.com/foo/"},
- true},
- // Ordering should not matter.
- {{"https://example1.com/foo/ https://sub.example2.com/bar/",
- "http://sub.example2.com/bar/ http://example1.com/foo/"},
- true},
- // Lists that intersect into a policy identical to the required list are
- // subsumed.
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ http://example1.com/foo/"},
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/"},
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/",
- "http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ http://example4.com/foo/"},
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/",
- "http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ http://example1.com/foo/"},
- true},
- // Lists that include sources that aren't subsumed by the required list
- // are not subsumed.
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ http://*.example4.com:*/bar/"},
- false},
- {{"http://example1.com/foo/ http://sub.example2.com/foo/"}, false},
- {{"http://*.com/bar/", "http://example1.com/bar/"}, false},
- {{"http://*.example1.com/foo/"}, false},
- {{"wss://sub.example2.com/bar/"}, false},
- {{"http://*.non-example3.com:*/bar/"}, false},
- {{"http://sub.example3.com/foo/"}, false},
- {{"http://not-example1.com", "http://not-example1.com"}, false},
- {{"http://*", "http://*.com http://*.example3.com:*/bar/"}, false},
- };
-
- for (const auto& test : cases) {
- HeapVector<Member<SourceListDirective>> returned;
-
- for (const auto& sources : test.sources_vector) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- "script-src", sources, csp.Get());
- returned.push_back(member);
- }
-
- EXPECT_EQ(required.Subsumes(returned), test.expected);
- }
-}
-
-TEST_F(SourceListDirectiveTest, SubsumesWithSelf) {
- SourceListDirective a("script-src",
- "http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ 'self'",
- csp.Get());
-
- struct TestCase {
- Vector<const char*> sources_b;
- const char* origin_b;
- bool expected;
- } cases[] = {
- // "https://example.test/" is a secure origin for both A and B.
- {{"'self'"}, "https://example.test/", true},
- {{"'self' 'self' 'self'"}, "https://example.test/", true},
- {{"'self'", "'self'", "'self'"}, "https://example.test/", true},
- {{"'self'", "'self'", "https://*.example.test/"},
- "https://example.test/",
- true},
- {{"'self'", "'self'", "https://*.example.test/bar/"},
- "https://example.test/",
- true},
- {{"'self' https://another.test/bar", "'self' http://*.example.test/bar",
- "https://*.example.test/bar/"},
- "https://example.test/",
- true},
- {{"http://example1.com/foo/ 'self'"}, "https://example.test/", true},
- {{"http://example1.com/foo/ https://example.test/"},
- "https://example.test/",
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/"},
- "https://example.test/",
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ https://example.test/"},
- "https://example.test/",
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ 'self'"},
- "https://example.test/",
- true},
- {{"'self'", "'self'", "https://example.test/"},
- "https://example.test/",
- true},
- {{"'self'", "https://example.test/folder/"},
- "https://example.test/",
- true},
- {{"'self'", "http://example.test/folder/"},
- "https://example.test/",
- true},
- {{"'self' https://example.com/", "https://example.com/"},
- "https://example.test/",
- false},
- {{"http://example1.com/foo/ http://*.example2.com/bar/",
- "http://example1.com/foo/ http://*.example2.com/bar/ 'self'"},
- "https://example.test/",
- true},
- {{"http://*.example1.com/foo/", "http://*.example1.com/foo/ 'self'"},
- "https://example.test/",
- false},
- {{"https://*.example.test/", "https://*.example.test/ 'self'"},
- "https://example.test/",
- false},
- {{"http://example.test/"}, "https://example.test/", false},
- {{"https://example.test/"}, "https://example.test/", true},
- // Origins of A and B do not match.
- {{"https://example.test/"}, "https://other-origin.test/", false},
- {{"'self'"}, "https://other-origin.test/", true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ 'self'"},
- "https://other-origin.test/",
- true},
- {{"http://example1.com/foo/ http://*.example2.com/bar/ "
- "http://*.example3.com:*/bar/ https://other-origin.test/"},
- "https://other-origin.test/",
- true},
- {{"http://example1.com/foo/ 'self'"}, "https://other-origin.test/", true},
- {{"'self'", "https://example.test/"}, "https://other-origin.test/", true},
- {{"'self' https://example.test/", "https://example.test/"},
- "https://other-origin.test/",
- false},
- {{"https://example.test/", "http://example.test/"},
- "https://other-origin.test/",
- false},
- {{"'self'", "http://other-origin.test/"},
- "https://other-origin.test/",
- true},
- {{"'self'", "https://non-example.test/"},
- "https://other-origin.test/",
- true},
- // B's origin matches one of sources in the source list of A.
- {{"'self'", "http://*.example1.com/foo/"}, "http://example1.com/", true},
- {{"http://*.example2.com/bar/", "'self'"},
- "http://example2.com/bar/",
- true},
- {{"'self' http://*.example1.com/foo/", "http://*.example1.com/foo/"},
- "http://example1.com/",
- false},
- {{"http://*.example2.com/bar/ http://example1.com/",
- "'self' http://example1.com/"},
- "http://example2.com/bar/",
- false},
- };
-
- for (const auto& test : cases) {
- ContentSecurityPolicy* csp_b = SetUpWithOrigin(String(test.origin_b));
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (auto* const sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- "script-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(test.expected, a.Subsumes(vector_b));
- }
+ String sources = "http://example1.com/foo/ http://example2.com/bar/";
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", sources, csp.Get());
+
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example1.com/foo/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example1.com/bar/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example2.com/bar/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example2.com/foo/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "https://example1.com/foo/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+ EXPECT_TRUE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "https://example1.com/bar/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
+
+ EXPECT_FALSE(CSPSourceListAllows(
+ *source_list, *self_source, KURL(base, "http://example3.com/foo/"),
+ ResourceRequest::RedirectStatus::kFollowedRedirect));
}
TEST_F(SourceListDirectiveTest, AllowAllInline) {
@@ -578,222 +310,34 @@ TEST_F(SourceListDirectiveTest, AllowAllInline) {
};
// Script-src and style-src differently handle presence of 'strict-dynamic'.
- SourceListDirective script_src("script-src",
- "'strict-dynamic' 'unsafe-inline'", csp.Get());
- EXPECT_FALSE(script_src.AllowAllInline());
+ network::mojom::blink::CSPSourceListPtr script_src = CSPSourceListParse(
+ "script-src", "'strict-dynamic' 'unsafe-inline'", csp.Get());
+ EXPECT_FALSE(
+ CSPSourceListAllowAllInline(CSPDirectiveName::ScriptSrc, *script_src));
- SourceListDirective style_src("style-src", "'strict-dynamic' 'unsafe-inline'",
- csp.Get());
- EXPECT_TRUE(style_src.AllowAllInline());
+ network::mojom::blink::CSPSourceListPtr style_src = CSPSourceListParse(
+ "style-src", "'strict-dynamic' 'unsafe-inline'", csp.Get());
+ EXPECT_TRUE(
+ CSPSourceListAllowAllInline(CSPDirectiveName::StyleSrc, *style_src));
for (const auto& test : cases) {
- SourceListDirective script_src("script-src", test.sources, csp.Get());
- EXPECT_EQ(script_src.AllowAllInline(), test.expected);
-
- SourceListDirective style_src("style-src", test.sources, csp.Get());
- EXPECT_EQ(style_src.AllowAllInline(), test.expected);
+ network::mojom::blink::CSPSourceListPtr script_src =
+ CSPSourceListParse("script-src", test.sources, csp.Get());
+ EXPECT_EQ(
+ CSPSourceListAllowAllInline(CSPDirectiveName::ScriptSrc, *script_src),
+ test.expected);
+
+ network::mojom::blink::CSPSourceListPtr style_src =
+ CSPSourceListParse("style-src", test.sources, csp.Get());
+ EXPECT_EQ(
+ CSPSourceListAllowAllInline(CSPDirectiveName::StyleSrc, *style_src),
+ test.expected);
// If source list doesn't have a valid type, it must not allow all inline.
- SourceListDirective img_src("img-src", test.sources, csp.Get());
- EXPECT_FALSE(img_src.AllowAllInline());
- }
-}
-
-TEST_F(SourceListDirectiveTest, SubsumesAllowAllInline) {
- struct TestCase {
- bool is_script_src;
- String sources_a;
- Vector<String> sources_b;
- bool expected;
- } cases[] = {
- // `sourcesA` allows all inline behavior.
- {false,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'unsafe-inline' http://example1.com/foo/bar.html"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"http://example1.com/foo/ 'unsafe-inline'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'unsafe-inline' 'nonce-yay'", "'unsafe-inline'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'unsafe-inline' 'nonce-yay'", "'unsafe-inline'", "'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'unsafe-inline' 'nonce-yay'", "'unsafe-inline'",
- "'strict-dynamic' 'nonce-yay'"},
- true},
- // `sourcesA` does not allow all inline behavior.
- {false,
- "http://example1.com/foo/ 'self' 'strict-dynamic'",
- {"'unsafe-inline' http://example1.com/foo/bar.html"},
- false},
- {true, "http://example1.com/foo/ 'self'", {"'unsafe-inline'"}, false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'unsafe-inline' 'nonce-yay'", "'nonce-abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self'",
- {"'unsafe-inline' https://example.test/"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'unsafe-inline' https://example.test/"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'unsafe-inline' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'nonce-yay'",
- {"'unsafe-inline' 'nonce-yay'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic' "
- "'nonce-yay'",
- {"'unsafe-inline' 'nonce-yay'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic' "
- "'nonce-yay'",
- {"http://example1.com/foo/ 'unsafe-inline' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba' "
- "'strict-dynamic'",
- {"'unsafe-inline' 'sha512-321cba'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic' "
- "'sha512-321cba'",
- {"http://example1.com/foo/ 'unsafe-inline' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/ 'unsafe-inline'",
- "http://example1.com/foo/ 'sha512-321cba'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/ 'unsafe-inline'",
- "http://example1.com/foo/ 'unsafe-inline' 'sha512-321cba'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/ 'unsafe-inline' 'nonce-yay'",
- "http://example1.com/foo/ 'unsafe-inline' 'sha512-321cba'"},
- true},
- };
-
- for (const auto& test : cases) {
- SourceListDirective a(test.is_script_src ? "script-src" : "style-src",
- test.sources_a, csp.Get());
- ContentSecurityPolicy* csp_b =
- SetUpWithOrigin("https://another.test/image.png");
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (const auto& sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- test.is_script_src ? "script-src" : "style-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(a.Subsumes(vector_b), test.expected);
- }
-}
-
-TEST_F(SourceListDirectiveTest, SubsumesUnsafeAttributes) {
- struct TestCase {
- bool is_script_src;
- String sources_a;
- Vector<String> sources_b;
- bool expected;
- } cases[] = {
- // A or policiesB contain `unsafe-eval`.
- {false,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic' "
- "'unsafe-eval'",
- {"http://example1.com/foo/bar.html 'unsafe-eval'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-eval'",
- {"http://example1.com/foo/ 'unsafe-inline'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-eval'",
- {"http://example1.com/foo/ 'unsafe-inline' 'unsafe-eval'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-eval'",
- {"http://example1.com/foo/ 'unsafe-eval'",
- "http://example1.com/foo/bar 'self' unsafe-eval'",
- "http://non-example.com/foo/ 'unsafe-eval' 'self'"},
- true},
- {true,
- "http://example1.com/foo/ 'self'",
- {"http://example1.com/foo/ 'unsafe-eval'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"http://example1.com/foo/ 'unsafe-eval'",
- "http://example1.com/foo/bar 'self' 'unsafe-eval'",
- "http://non-example.com/foo/ 'unsafe-eval' 'self'"},
- false},
- // A or policiesB contain `unsafe-hashes`.
- {false,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'unsafe-eval' "
- "'strict-dynamic' "
- "'unsafe-hashes'",
- {"http://example1.com/foo/bar.html 'unsafe-hashes'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-hashes'",
- {"http://example1.com/foo/ 'unsafe-inline'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-hashes'",
- {"http://example1.com/foo/ 'unsafe-inline' 'unsafe-hashes'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-eval' "
- "'unsafe-hashes'",
- {"http://example1.com/foo/ 'unsafe-eval' 'unsafe-hashes'",
- "http://example1.com/foo/bar 'self' 'unsafe-hashes'",
- "http://non-example.com/foo/ 'unsafe-hashes' 'self'"},
- true},
- {true,
- "http://example1.com/foo/ 'self'",
- {"http://example1.com/foo/ 'unsafe-hashes'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"http://example1.com/foo/ 'unsafe-hashes'",
- "http://example1.com/foo/bar 'self' 'unsafe-hashes'",
- "https://example1.com/foo/bar 'unsafe-hashes' 'self'"},
- false},
- };
-
- ContentSecurityPolicy* csp_b =
- SetUpWithOrigin("https://another.test/image.png");
-
- for (const auto& test : cases) {
- SourceListDirective a(test.is_script_src ? "script-src" : "style-src",
- test.sources_a, csp.Get());
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (const auto& sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- test.is_script_src ? "script-src" : "style-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(a.Subsumes(vector_b), test.expected);
+ network::mojom::blink::CSPSourceListPtr img_src =
+ CSPSourceListParse("img-src", test.sources, csp.Get());
+ EXPECT_FALSE(
+ CSPSourceListAllowAllInline(CSPDirectiveName::ImgSrc, *img_src));
}
}
@@ -825,14 +369,17 @@ TEST_F(SourceListDirectiveTest, IsNone) {
for (const auto& test : cases) {
SCOPED_TRACE(test.sources);
- SourceListDirective script_src("script-src", test.sources, csp.Get());
- EXPECT_EQ(script_src.IsNone(), test.expected);
+ network::mojom::blink::CSPSourceListPtr script_src =
+ CSPSourceListParse("script-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsNone(*script_src), test.expected);
- SourceListDirective form_action("form-action", test.sources, csp.Get());
- EXPECT_EQ(form_action.IsNone(), test.expected);
+ network::mojom::blink::CSPSourceListPtr form_action =
+ CSPSourceListParse("form-action", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsNone(*form_action), test.expected);
- SourceListDirective frame_src("frame-src", test.sources, csp.Get());
- EXPECT_EQ(frame_src.IsNone(), test.expected);
+ network::mojom::blink::CSPSourceListPtr frame_src =
+ CSPSourceListParse("frame-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsNone(*frame_src), test.expected);
}
}
@@ -865,14 +412,17 @@ TEST_F(SourceListDirectiveTest, IsSelf) {
for (const auto& test : cases) {
SCOPED_TRACE(test.sources);
- SourceListDirective script_src("script-src", test.sources, csp.Get());
- EXPECT_EQ(script_src.IsSelf(), test.expected);
+ network::mojom::blink::CSPSourceListPtr script_src =
+ CSPSourceListParse("script-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsSelf(*script_src), test.expected);
- SourceListDirective form_action("form-action", test.sources, csp.Get());
- EXPECT_EQ(form_action.IsSelf(), test.expected);
+ network::mojom::blink::CSPSourceListPtr form_action =
+ CSPSourceListParse("form-action", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsSelf(*form_action), test.expected);
- SourceListDirective frame_src("frame-src", test.sources, csp.Get());
- EXPECT_EQ(frame_src.IsSelf(), test.expected);
+ network::mojom::blink::CSPSourceListPtr frame_src =
+ CSPSourceListParse("frame-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsSelf(*frame_src), test.expected);
}
}
@@ -914,524 +464,17 @@ TEST_F(SourceListDirectiveTest, AllowsURLBasedMatching) {
for (const auto& test : cases) {
SCOPED_TRACE(test.sources);
- SourceListDirective script_src("script-src", test.sources, csp.Get());
- EXPECT_EQ(script_src.AllowsURLBasedMatching(), test.expected);
-
- SourceListDirective form_action("form-action", test.sources, csp.Get());
- EXPECT_EQ(form_action.AllowsURLBasedMatching(), test.expected);
-
- SourceListDirective frame_src("frame-src", test.sources, csp.Get());
- EXPECT_EQ(frame_src.AllowsURLBasedMatching(), test.expected);
- }
-}
-
-TEST_F(SourceListDirectiveTest, GetIntersectNonces) {
- SourceListDirective list_a(
- "script-src",
- "http://example.com 'nonce-abc' 'nonce-xyz' 'nonce-' 'unsafe-inline'",
- csp.Get());
- struct TestCase {
- String sources;
- String expected;
- } cases[] = {
- {"http:", ""},
- {"http://example.com", ""},
- {"example.com", ""},
- {"'unsafe-inline'", ""},
- {"'nonce-abc'", "'nonce-abc'"},
- {"'nonce-xyz'", "'nonce-xyz'"},
- {"'nonce-123'", ""},
- {"'nonce-abc' 'nonce-xyz'", "'nonce-abc' 'nonce-xyz'"},
- {"'nonce-abc' 'nonce-xyz' 'nonce'", "'nonce-abc' 'nonce-xyz'"},
- {"'nonce-abc' 'nonce-123'", "'nonce-abc'"},
- {"'nonce-123' 'nonce-123'", ""},
- {"'nonce-123' 'nonce-abc'", "'nonce-abc'"},
- {"'nonce-123' 'nonce-xyz'", "'nonce-xyz'"},
- {"'nonce-123' 'nonce-xyx'", ""},
- };
-
- for (const auto& test : cases) {
- SourceListDirective list_b("script-src", test.sources, csp.Get());
- HashSet<String> normalized = list_a.GetIntersectNonces(list_b.nonces_);
-
- SourceListDirective expected_list("script-src", test.expected, csp.Get());
- HashSet<String> expected = expected_list.nonces_;
- EXPECT_EQ(normalized.size(), expected.size());
- for (const auto& nonce : normalized) {
- EXPECT_TRUE(expected.Contains(nonce));
- }
- }
-}
-
-TEST_F(SourceListDirectiveTest, GetIntersectHashes) {
- SourceListDirective list_a(
- "script-src",
- "http://example.com 'sha256-abc123' 'sha384-' 'sha512-321cba' 'self'",
- csp.Get());
- struct TestCase {
- String sources;
- String expected;
- } cases[] = {
- {"http:", ""},
- {"http://example.com", ""},
- {"example.com", ""},
- {"'unsafe-inline'", ""},
- {"'sha384-abc'", ""},
- {"'sha384-'", ""},
- {"'sha256-abc123'", "'sha256-abc123'"},
- {"'sha256-abc123' 'sha384-'", "'sha256-abc123'"},
- {"'sha256-abc123' 'sha512-321cba'", "'sha512-321cba' 'sha256-abc123'"},
- {"'sha256-abc123' 'sha384-' 'sha512-321cba'",
- "'sha256-abc123' 'sha512-321cba' "},
- {"'sha256-else' 'sha384-' 'sha512-321cba'", "'sha512-321cba' "},
- {"'hash-123'", ""},
- {"'sha256-123'", ""},
- };
-
- for (const auto& test : cases) {
- SourceListDirective list_b("script-src", test.sources, csp.Get());
- HashSet<CSPHashValue> normalized =
- list_a.GetIntersectHashes(list_b.hashes_);
-
- SourceListDirective expected_list("script-src", test.expected, csp.Get());
- HashSet<CSPHashValue> expected = expected_list.hashes_;
- EXPECT_EQ(normalized.size(), expected.size());
- for (const auto& hash : normalized) {
- EXPECT_TRUE(expected.Contains(hash));
- }
- }
-}
-
-TEST_F(SourceListDirectiveTest, SubsumesNoncesAndHashes) {
- struct TestCase {
- bool is_script_src;
- String sources_a;
- Vector<String> sources_b;
- bool expected;
- } cases[] = {
- // Check nonces.
- {true,
- "http://example1.com/foo/ 'unsafe-inline' 'nonce-abc'",
- {"'unsafe-inline'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'nonce-abc'",
- {"'nonce-abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'unsafe-inline' 'nonce-yay'", "'nonce-yay'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay'",
- {"'unsafe-inline' 'nonce-yay'", "'nonce-yay'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-abc' 'nonce-yay'",
- {"'unsafe-inline' https://example.test/"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-abc' 'nonce-yay'",
- {"'nonce-abc' https://example1.com/foo/"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'nonce-yay' "
- "'strict-dynamic'",
- {"https://example.test/ 'nonce-yay'"},
- false},
- {false,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'nonce-yay' "
- "'strict-dynamic'",
- {"'nonce-yay' https://example1.com/foo/"},
- true},
- {true,
- "http://example1.com/foo/ 'nonce-abc'",
- {"http://example1.com/foo/ 'nonce-xyz'"},
- true},
- {false,
- "http://example1.com/foo/ 'nonce-abc'",
- {"http://example1.com/foo/ 'nonce-xyz'"},
- true},
- // Check hashes.
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/page.html 'strict-dynamic'",
- "https://example1.com/foo/ 'sha512-321cba'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://some-other.com/ 'strict-dynamic' 'sha512-321cba'",
- "http://example1.com/foo/ 'unsafe-inline' 'sha512-321cba'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/ 'sha512-321abc' 'sha512-321cba'",
- "http://example1.com/foo/ 'sha512-321abc' 'sha512-321cba'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321cba'",
- {"http://example1.com/foo/ 'unsafe-inline'",
- "http://example1.com/foo/ 'sha512-321cba'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc'",
- {"http://example1.com/foo/ 'unsafe-inline' 'sha512-321abc'",
- "http://example1.com/foo/ 'sha512-321abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc'",
- {"'unsafe-inline' 'sha512-321abc'",
- "http://example1.com/foo/ 'sha512-321abc'"},
- true},
- // Nonces and hashes together.
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc' "
- "'nonce-abc'",
- {"'unsafe-inline' 'sha512-321abc' 'self'",
- "'unsafe-inline''sha512-321abc' https://example.test/"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc' "
- "'nonce-abc'",
- {"'unsafe-inline' 'sha512-321abc' 'self' 'nonce-abc'",
- "'sha512-321abc' https://example.test/"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc' "
- "'nonce-abc'",
- {"'unsafe-inline' 'sha512-321abc' 'self'",
- " 'sha512-321abc' https://example.test/ 'nonce-abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc' "
- "'nonce-abc'",
- {"'unsafe-inline' 'sha512-321abc' 'self' 'nonce-xyz'",
- "unsafe-inline' 'sha512-321abc' https://example.test/ 'nonce-xyz'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc' "
- "'nonce-abc'",
- {"'unsafe-inline' 'sha512-321abc' 'self' 'sha512-xyz'",
- "unsafe-inline' 'sha512-321abc' https://example.test/ 'sha512-xyz'"},
- false},
- {true,
- "http://example1.com/foo/ 'nonce-abc' 'sha512-321abc'",
- {"http://example1.com/foo/ 'nonce-xyz' 'sha512-321abc'"},
- true},
- {false,
- "http://example1.com/foo/ 'nonce-abc' 'sha512-321abc'",
- {"http://example1.com/foo/ 'nonce-xyz' 'sha512-321abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'nonce-abc' 'sha512-321abc'",
- {"http://example1.com/foo/ 'nonce-xyz' 'sha512-xyz'"},
- false},
- {false,
- "http://example1.com/foo/ 'nonce-abc' 'sha512-321abc'",
- {"http://example1.com/foo/ 'nonce-xyz' 'sha512-xyz'",
- "http://example1.com/foo/ 'nonce-zyx' 'nonce-xyz' 'sha512-xyz'"},
- false},
- };
-
- for (const auto& test : cases) {
- SourceListDirective a(test.is_script_src ? "script-src" : "style-src",
- test.sources_a, csp.Get());
- ContentSecurityPolicy* csp_b =
- SetUpWithOrigin("https://another.test/image.png");
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (const auto& sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- test.is_script_src ? "script-src" : "style-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(a.Subsumes(vector_b), test.expected);
- }
-}
-
-TEST_F(SourceListDirectiveTest, SubsumesStrictDynamic) {
- struct TestCase {
- bool is_script_src;
- String sources_a;
- Vector<String> sources_b;
- bool expected;
- } cases[] = {
- // Neither A nor effective policy of list B has `strict-dynamic`.
- {false,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'nonce-yay' 'strict-dynamic'"},
- true},
- {false,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'nonce-abc' 'strict-dynamic'"},
- true},
- {false,
- "http://example1.com/foo/ 'self' 'sha512-321abc'",
- {"'strict-dynamic' 'nonce-yay' 'sha512-321abc'",
- "'sha512-321abc' 'strict-dynamic'"},
- true},
- {false,
- "http://example1.com/foo/ 'self' 'sha512-321abc'",
- {"'strict-dynamic' 'nonce-yay' 'sha512-321abc'",
- "'sha512-321abc' 'strict-dynamic'", "'strict-dynamic'"},
- true},
- {false,
- "http://example1.com/foo/ 'self' 'sha512-321abc'",
- {"'strict-dynamic' 'nonce-yay' http://example1.com/",
- "http://example1.com/ 'strict-dynamic'"},
- false},
- // A has `strict-dynamic`, effective policy of list B does not.
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'nonce-yay'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'strict-dynamic' 'sha512-321abc'", "'unsafe-inline' 'sha512-321abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'sha512-321abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"http://example1.com/foo/ 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'self' 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'nonce-yay'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"http://example1.com/ 'sha512-321abc'",
- "http://example1.com/ 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'sha512-321abc' 'strict-dynamic'",
- {"https://example1.com/foo/ 'sha512-321abc'",
- "http://example1.com/foo/ 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'nonce-yay'", "'sha512-321abc'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-hashes' "
- "'strict-dynamic'",
- {"'strict-dynamic' 'unsafe-hashes'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay' 'unsafe-hashes'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-eval' 'strict-dynamic'",
- {"'strict-dynamic' 'unsafe-eval'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay' 'unsafe-eval'"},
- false},
- // A does not have `strict-dynamic`, but effective policy of list B does.
- // Note that any subsumption in this set-up should be `false`.
- {true,
- "http://example1.com/foo/ 'self' 'nonce-yay'",
- {"'strict-dynamic' 'nonce-yay'", "'sha512-321abc' 'strict-dynamic'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc'",
- {"'strict-dynamic' 'sha512-321abc'", "'strict-dynamic' 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline'",
- {"'strict-dynamic'"},
- false},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'sha512-321abc'",
- {"'strict-dynamic'"},
- false},
- // Both A and effective policy of list B has `strict-dynamic`.
- {true,
- "'strict-dynamic'",
- {"'strict-dynamic'", "'strict-dynamic'", "'strict-dynamic'"},
- true},
- {true,
- "'strict-dynamic'",
- {"'strict-dynamic'", "'strict-dynamic' 'nonce-yay'",
- "'strict-dynamic' 'nonce-yay'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'strict-dynamic' 'nonce-yay'", "'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'strict-dynamic' http://another.com/",
- "http://another.com/ 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'unsafe-inline' 'strict-dynamic'",
- {"'self' 'sha512-321abc' 'strict-dynamic'",
- "'self' 'strict-dynamic' 'sha512-321abc'"},
- false},
- {true,
- "http://example1.com/foo/ 'sha512-321abc' 'strict-dynamic'",
- {"'self' 'sha512-321abc' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-inline' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-inline' 'sha512-123xyz' 'strict-dynamic'"},
- false},
- {true,
- "'unsafe-eval' 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-eval' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-eval' 'strict-dynamic'"},
- false},
- {true,
- "'unsafe-hashes' 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-hashes' 'strict-dynamic'"},
- true},
- {true,
- "http://example1.com/foo/ 'self' 'sha512-321abc' 'strict-dynamic'",
- {"'unsafe-hashes' 'strict-dynamic'"},
- false},
- };
+ network::mojom::blink::CSPSourceListPtr script_src =
+ CSPSourceListParse("script-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*script_src), test.expected);
- for (const auto& test : cases) {
- SourceListDirective a(test.is_script_src ? "script-src" : "style-src",
- test.sources_a, csp.Get());
- ContentSecurityPolicy* csp_b =
- SetUpWithOrigin("https://another.test/image.png");
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (const auto& sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- test.is_script_src ? "script-src" : "style-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(a.Subsumes(vector_b), test.expected);
- }
-}
+ network::mojom::blink::CSPSourceListPtr form_action =
+ CSPSourceListParse("form-action", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*form_action), test.expected);
-TEST_F(SourceListDirectiveTest, SubsumesListWildcard) {
- struct TestCase {
- const char* sources_a;
- Vector<const char*> sources_b;
- bool expected;
- } cases[] = {
- // `A` subsumes `policiesB`..
- {"*", {""}, true},
- {"*", {"'none'"}, true},
- {"*", {"*"}, true},
- {"*", {"*", "*", "*"}, true},
- {"*", {"*", "* https: http: ftp: ws: wss:"}, true},
- {"*", {"*", "https: http: ftp: ws: wss:"}, true},
- {"https: http: ftp: ws: wss:", {"*", "https: http: ftp: ws: wss:"}, true},
- {"http: ftp: ws:", {"*", "https: http: ftp: ws: wss:"}, true},
- {"http: ftp: ws:", {"*", "https: 'strict-dynamic'"}, true},
- {"http://another.test", {"*", "'self'"}, true},
- {"http://another.test/", {"*", "'self'"}, true},
- {"http://another.test", {"https:", "'self'"}, true},
- {"'self'", {"*", "'self'"}, true},
- {"'unsafe-eval' * ", {"'unsafe-eval'"}, true},
- {"'unsafe-hashes' * ", {"'unsafe-hashes'"}, true},
- {"'unsafe-inline' * ", {"'unsafe-inline'"}, true},
- {"*", {"*", "http://a.com ws://b.com ftp://c.com"}, true},
- {"*", {"* data: blob:", "http://a.com ws://b.com ftp://c.com"}, true},
- {"*", {"data: blob:", "http://a.com ws://b.com ftp://c.com"}, true},
- {"*", {"*", "data://a.com ws://b.com ftp://c.com"}, true},
- {"* data:",
- {"data: blob: *", "data://a.com ws://b.com ftp://c.com"},
- true},
- {"http://a.com ws://b.com ftp://c.com",
- {"*", "http://a.com ws://b.com ftp://c.com"},
- true},
- // `A` does not subsume `policiesB`..
- {"*", Vector<const char*>(), false},
- {"", {"*"}, false},
- {"'none'", {"*"}, false},
- {"*", {"data:"}, false},
- {"*", {"blob:"}, false},
- {"http: ftp: ws:",
- {"* 'strict-dynamic'", "https: 'strict-dynamic'"},
- false},
- {"https://another.test", {"*"}, false},
- {"*", {"* 'unsafe-eval'"}, false},
- {"*", {"* 'unsafe-hashes'"}, false},
- {"*", {"* 'unsafe-inline'"}, false},
- {"'unsafe-eval'", {"* 'unsafe-eval'"}, false},
- {"'unsafe-hashes'", {"* 'unsafe-hashes'"}, false},
- {"'unsafe-inline'", {"* 'unsafe-inline'"}, false},
- {"*", {"data: blob:", "data://a.com ws://b.com ftp://c.com"}, false},
- {"* data:",
- {"data: blob:", "blob://a.com ws://b.com ftp://c.com"},
- false},
- };
-
- for (const auto& test : cases) {
- SourceListDirective a("script-src", test.sources_a, csp.Get());
- ContentSecurityPolicy* csp_b =
- SetUpWithOrigin("https://another.test/image.png");
-
- HeapVector<Member<SourceListDirective>> vector_b;
- for (auto* const sources : test.sources_b) {
- SourceListDirective* member = MakeGarbageCollected<SourceListDirective>(
- "script-src", sources, csp_b);
- vector_b.push_back(member);
- }
-
- EXPECT_EQ(a.Subsumes(vector_b), test.expected);
- }
-}
-
-TEST_F(SourceListDirectiveTest, GetSources) {
- struct TestCase {
- const char* sources;
- const char* expected;
- } cases[] = {
- {"", ""},
- {"*", "ftp: ws: http: https:"},
- {"* data:", "data: ftp: ws: http: https:"},
- {"blob: *", "blob: ftp: ws: http: https:"},
- {"* 'self'", "ftp: ws: http: https:"},
- {"https: 'self'", "https: https://example.test"},
- {"https://b.com/bar/", "https://b.com/bar/"},
- {"'self' http://a.com/foo/ https://b.com/bar/",
- "http://a.com/foo/ https://b.com/bar/ https://example.test"},
- {"http://a.com/foo/ https://b.com/bar/ 'self'",
- "http://a.com/foo/ https://b.com/bar/ https://example.test"},
- };
-
- for (const auto& test : cases) {
- SourceListDirective list("script-src", test.sources, csp.Get());
- HeapVector<Member<CSPSource>> normalized =
- list.GetSources(csp.Get()->GetSelfSource());
-
- SourceListDirective expected_list("script-src", test.expected, csp.Get());
- HeapVector<Member<CSPSource>> expected = expected_list.list_;
- EXPECT_EQ(normalized.size(), expected.size());
- for (wtf_size_t i = 0; i < expected.size(); i++) {
- Source a = {expected[i]->scheme_, expected[i]->host_,
- expected[i]->port_, expected[i]->path_,
- expected[i]->host_wildcard_, expected[i]->port_wildcard_};
- Source b = {normalized[i]->scheme_, normalized[i]->host_,
- normalized[i]->port_, normalized[i]->path_,
- normalized[i]->host_wildcard_, normalized[i]->port_wildcard_};
- EXPECT_TRUE(EqualSources(a, b));
- }
+ network::mojom::blink::CSPSourceListPtr frame_src =
+ CSPSourceListParse("frame-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*frame_src), test.expected);
}
}
@@ -1459,15 +502,10 @@ TEST_F(SourceListDirectiveTest, ParseHost) {
};
for (const auto& test : cases) {
- String host;
- CSPSource::WildcardDisposition disposition = CSPSource::kNoWildcard;
- Vector<UChar> characters;
- test.sources.AppendTo(characters);
- const UChar* start = characters.data();
- const UChar* end = start + characters.size();
- EXPECT_EQ(test.expected,
- SourceListDirective::ParseHost(start, end, &host, &disposition))
- << "SourceListDirective::parseHost fail to parse: " << test.sources;
+ network::mojom::blink::CSPSourceListPtr parsed =
+ CSPSourceListParse("default-src", test.sources, csp.Get());
+ EXPECT_EQ(CSPSourceListIsNone(*parsed), !test.expected)
+ << "CSPSourceListParse failed to parse: " << test.sources;
}
}
@@ -1477,24 +515,32 @@ TEST_F(SourceListDirectiveTest, AllowHostWildcard) {
// See crbug.com/682673.
{
String sources = "http://*:111";
- SourceListDirective source_list("default-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://a.com:111")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://a.com:222")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("default-src", sources, csp.Get());
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://a.com:111")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://a.com:222")));
}
// When the host-part is "*", the path must still be checked.
// See crbug.com/682673.
{
String sources = "http://*/welcome.html";
- SourceListDirective source_list("default-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://a.com/welcome.html")));
- EXPECT_FALSE(source_list.Allows(KURL(base, "http://a.com/passwords.txt")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("default-src", sources, csp.Get());
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://a.com/welcome.html")));
+ EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://a.com/passwords.txt")));
}
// When the host-part is "*" and the expression-source is not "*", then every
// host are allowed. See crbug.com/682673.
{
String sources = "http://*";
- SourceListDirective source_list("default-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://a.com")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("default-src", sources, csp.Get());
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://a.com")));
}
}
@@ -1503,14 +549,42 @@ TEST_F(SourceListDirectiveTest, AllowHostMixedCase) {
// Non-wildcard sources should match hosts case-insensitively.
{
String sources = "http://ExAmPle.com";
- SourceListDirective source_list("default-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://example.com")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("default-src", sources, csp.Get());
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://example.com")));
}
// Wildcard sources should match hosts case-insensitively.
{
String sources = "http://*.ExAmPle.com";
- SourceListDirective source_list("default-src", sources, csp.Get());
- EXPECT_TRUE(source_list.Allows(KURL(base, "http://www.example.com")));
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("default-src", sources, csp.Get());
+ EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source,
+ KURL(base, "http://www.example.com")));
+ }
+}
+
+TEST_F(SourceListDirectiveTest, AllowNonce) {
+ struct TestCase {
+ const char* directive_value;
+ const char* nonce;
+ bool expected;
+ } cases[] = {
+ {"'self'", "yay", false},
+ {"'self'", "boo", false},
+ {"'nonce-yay'", "yay", true},
+ {"'nonce-yay'", "boo", false},
+ {"'nonce-yay' 'nonce-boo'", "yay", true},
+ {"'nonce-yay' 'nonce-boo'", "boo", true},
+ };
+
+ for (const auto& test : cases) {
+ network::mojom::blink::CSPSourceListPtr source_list =
+ CSPSourceListParse("script-src", test.directive_value, csp.Get());
+ EXPECT_EQ(test.expected, CSPSourceListAllowNonce(*source_list, test.nonce));
+ // Empty/null strings are always not present.
+ EXPECT_FALSE(CSPSourceListAllowNonce(*source_list, ""));
+ EXPECT_FALSE(CSPSourceListAllowNonce(*source_list, String()));
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.cc
deleted file mode 100644
index b2977416d76..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/csp/string_list_directive.h"
-
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
-#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-StringListDirective::StringListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy* policy)
- : CSPDirective(name, value, policy),
- allow_any_(false),
- allow_duplicates_(false) {
- // Turn whitespace-y characters into ' ' and then split on ' ' into list_.
- value.SimplifyWhiteSpace().Split(' ', false, list_);
-
- auto drop_fn = [this](const String& value) -> bool {
- return !AllowOrProcessValue(value);
- };
-
- // There appears to be no wtf::Vector equivalent to STLs erase(from, to)
- // method, so we can't do the canonical .erase(remove_if(..), end) and have
- // to emulate this:
- list_.Shrink(std::remove_if(list_.begin(), list_.end(), drop_fn) -
- list_.begin());
-}
-
-bool StringListDirective::IsPolicyName(const String& name) {
- // This implements tt-policy-name from
- // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive/
- return name.Find(&IsNotPolicyNameChar) == kNotFound;
-}
-
-bool StringListDirective::IsNotPolicyNameChar(UChar c) {
- // This implements the negation of one char of tt-policy-name from
- // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive/
- bool is_name_char = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') || c == '-' || c == '#' ||
- c == '=' || c == '_' || c == '/' || c == '@' ||
- c == '.' || c == '%';
- return !is_name_char;
-}
-
-bool StringListDirective::AllowOrProcessValue(const String& src) {
- DCHECK_EQ(src, src.StripWhiteSpace());
- // Handle keywords and special tokens first:
- if (src == "'allow-duplicates'") {
- allow_duplicates_ = true;
- return false;
- }
- if (src == "*") {
- allow_any_ = true;
- return false;
- }
- if (src == "'none'") {
- if (list_.size() > 1) {
- Policy()->ReportInvalidSourceExpression(GetName(), src);
- }
- return false;
- }
- return IsPolicyName(src);
-}
-
-bool StringListDirective::Allows(const String& value, bool is_duplicate) {
- if (is_duplicate && !allow_duplicates_)
- return false;
- if (is_duplicate && value == "default")
- return false;
- if (!IsPolicyName(value))
- return false;
- return allow_any_ || list_.Contains(value);
-}
-
-void StringListDirective::Trace(Visitor* visitor) const {
- CSPDirective::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.h
deleted file mode 100644
index dca41c37754..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_STRING_LIST_DIRECTIVE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_STRING_LIST_DIRECTIVE_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/frame/csp/csp_directive.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class ContentSecurityPolicy;
-
-class CORE_EXPORT StringListDirective final : public CSPDirective {
- public:
- StringListDirective(const String& name,
- const String& value,
- ContentSecurityPolicy*);
- void Trace(Visitor*) const override;
- bool Allows(const String& string_piece, bool is_duplicate);
- bool IsAllowDuplicates() const { return allow_duplicates_; }
-
- private:
- // Determine whether a given string is a valid policy name or a special token
- // ("*" or "'allow-duplicates'"). In the token case, set the appropriate flags
- // as a side effect.
- bool AllowOrProcessValue(const String& src);
-
- static bool IsPolicyName(const String& name);
- static bool IsNotPolicyNameChar(UChar c);
-
- Vector<String> list_;
- bool allow_any_;
- bool allow_duplicates_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_STRING_LIST_DIRECTIVE_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive_test.cc
deleted file mode 100644
index 7800b9c3e3c..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/csp/string_list_directive_test.cc
+++ /dev/null
@@ -1,70 +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/core/frame/csp/string_list_directive.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-
-namespace blink {
-
-class StringListDirectiveTest : public testing::Test {
- public:
- StringListDirectiveTest()
- : csp_(MakeGarbageCollected<ContentSecurityPolicy>()) {}
-
- protected:
- Persistent<ContentSecurityPolicy> csp_;
-};
-
-TEST_F(StringListDirectiveTest, TestAllowLists) {
- struct {
- const char* directive;
- const char* should_be_allowed;
- const char* should_not_be_allowed;
- bool allow_dupes;
- } test_cases[] = {
- {"bla", "bla", "blubb", false},
- {"*", "bla blubb", "", false},
- {"", "", "bla blubb", false},
- {"*", "bla a.b 123 a-b", "'bla' abc*def a,e a+b", false},
- {"* 'allow-duplicates'", "bla blubb", "", true},
- {"'allow-duplicates' *", "bla blubb", "", true},
- {"bla 'allow-duplicates'", "bla", "blubb", true},
- {"'allow-duplicates' bla", "bla", "blub", true},
- {"'allow-duplicates'", "", "bla blub", true},
- {"'allow-duplicates' bla blubb", "bla blubb", "blubber", true},
- {"'none'", "", "default none abc", false},
- {"'none' default", "default", "none abc", false},
- {"* 'none'", "default none abc", "", false},
- {"'allow-duplicates' 'none'", "", "default none abc", true},
- };
-
- for (const auto& test_case : test_cases) {
- StringListDirective directive("trusted-types", test_case.directive,
- csp_.Get());
-
- Vector<String> allowed;
- String(test_case.should_be_allowed).Split(' ', allowed);
- for (const String& value : allowed) {
- SCOPED_TRACE(testing::Message()
- << " trusted-types " << test_case.directive
- << "; allow: " << value);
- EXPECT_TRUE(directive.Allows(value, false));
- EXPECT_EQ(directive.Allows(value, true), test_case.allow_dupes);
- }
-
- Vector<String> not_allowed;
- String(test_case.should_not_be_allowed).Split(' ', not_allowed);
- for (const String& value : not_allowed) {
- SCOPED_TRACE(testing::Message()
- << " trusted-types " << test_case.directive
- << "; do not allow: " << value);
- EXPECT_FALSE(directive.Allows(value, false));
- EXPECT_FALSE(directive.Allows(value, true));
- }
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.cc b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.cc
new file mode 100644
index 00000000000..0181289aab3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.cc
@@ -0,0 +1,96 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/trusted_types_directive.h"
+
+#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
+#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+namespace {
+
+bool IsNotPolicyNameChar(UChar c) {
+ // This implements the negation of one char of tt-policy-name from
+ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive/
+ bool is_name_char = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || c == '-' || c == '#' ||
+ c == '=' || c == '_' || c == '/' || c == '@' ||
+ c == '.' || c == '%';
+ return !is_name_char;
+}
+
+bool IsPolicyName(const String& name) {
+ // This implements tt-policy-name from
+ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive/
+ return name.Find(&IsNotPolicyNameChar) == kNotFound;
+}
+
+} // namespace
+
+network::mojom::blink::CSPTrustedTypesPtr CSPTrustedTypesParse(
+ const String& value,
+ ContentSecurityPolicy* policy) {
+ auto result = network::mojom::blink::CSPTrustedTypes::New();
+
+ // Turn whitespace-y characters into ' ' and then split on ' ' into list_.
+ value.SimplifyWhiteSpace().Split(' ', false, result->list);
+
+ auto drop_fn = [policy, &result](const String& src) -> bool {
+ DCHECK_EQ(src, src.StripWhiteSpace());
+ // Handle keywords and special tokens first:
+ if (src == "'allow-duplicates'") {
+ result->allow_duplicates = true;
+ return true;
+ }
+ if (src == "*") {
+ result->allow_any = true;
+ return true;
+ }
+ if (src == "'none'") {
+ if (result->list.size() > 1) {
+ policy->ReportInvalidSourceExpression("trusted-types", src);
+ }
+ return true;
+ }
+ return !IsPolicyName(src);
+ };
+
+ // There appears to be no wtf::Vector equivalent to STLs erase(from, to)
+ // method, so we can't do the canonical .erase(remove_if(..), end) and have
+ // to emulate this:
+ result->list.Shrink(
+ std::remove_if(result->list.begin(), result->list.end(), drop_fn) -
+ result->list.begin());
+
+ return result;
+}
+
+bool CSPTrustedTypesAllows(
+ const network::mojom::blink::CSPTrustedTypes& trusted_types,
+ const String& value,
+ bool is_duplicate,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails& violation_details) {
+ if (is_duplicate && !trusted_types.allow_duplicates) {
+ violation_details = ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName;
+ } else if (is_duplicate && value == "default") {
+ violation_details = ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName;
+ } else if (!IsPolicyName(value)) {
+ violation_details =
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName;
+ } else if (!(trusted_types.allow_any || trusted_types.list.Contains(value))) {
+ violation_details =
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kDisallowedName;
+ } else {
+ violation_details =
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed;
+ }
+ return violation_details ==
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.h b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.h
new file mode 100644
index 00000000000..1a23160bca6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_TRUSTED_TYPES_DIRECTIVE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_TRUSTED_TYPES_DIRECTIVE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+CORE_EXPORT
+network::mojom::blink::CSPTrustedTypesPtr CSPTrustedTypesParse(
+ const String& value,
+ ContentSecurityPolicy* policy);
+
+CORE_EXPORT
+bool CSPTrustedTypesAllows(
+ const network::mojom::blink::CSPTrustedTypes& trusted_types,
+ const String& string_piece,
+ bool is_duplicate,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails& violation_details);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_TRUSTED_TYPES_DIRECTIVE_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive_test.cc b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive_test.cc
new file mode 100644
index 00000000000..0f36357127e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/csp/trusted_types_directive_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/csp/trusted_types_directive.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+
+namespace blink {
+
+class TrustedTypesDirectiveTest : public testing::Test {
+ public:
+ TrustedTypesDirectiveTest()
+ : csp_(MakeGarbageCollected<ContentSecurityPolicy>()) {}
+
+ protected:
+ Persistent<ContentSecurityPolicy> csp_;
+};
+
+TEST_F(TrustedTypesDirectiveTest, TestAllowLists) {
+ struct {
+ const char* directive;
+ const char* should_be_allowed;
+ const char* should_not_be_allowed;
+ bool allow_dupes;
+ } test_cases[] = {
+ {"bla", "bla", "blubb", false},
+ {"*", "bla blubb", "", false},
+ {"", "", "bla blubb", false},
+ {"*", "bla a.b 123 a-b", "'bla' abc*def a,e a+b", false},
+ {"* 'allow-duplicates'", "bla blubb", "", true},
+ {"'allow-duplicates' *", "bla blubb", "", true},
+ {"bla 'allow-duplicates'", "bla", "blubb", true},
+ {"'allow-duplicates' bla", "bla", "blub", true},
+ {"'allow-duplicates'", "", "bla blub", true},
+ {"'allow-duplicates' bla blubb", "bla blubb", "blubber", true},
+ {"'none'", "", "default none abc", false},
+ {"'none' default", "default", "none abc", false},
+ {"* 'none'", "default none abc", "", false},
+ {"'allow-duplicates' 'none'", "", "default none abc", true},
+ };
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details;
+
+ for (const auto& test_case : test_cases) {
+ network::mojom::blink::CSPTrustedTypesPtr directive =
+ CSPTrustedTypesParse(test_case.directive, csp_.Get());
+
+ Vector<String> allowed;
+ String(test_case.should_be_allowed).Split(' ', allowed);
+ for (const String& value : allowed) {
+ SCOPED_TRACE(testing::Message()
+ << " trusted-types " << test_case.directive
+ << "; allow: " << value);
+ EXPECT_TRUE(
+ CSPTrustedTypesAllows(*directive, value, false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ EXPECT_EQ(
+ CSPTrustedTypesAllows(*directive, value, true, violation_details),
+ test_case.allow_dupes);
+ if (test_case.allow_dupes) {
+ EXPECT_EQ(
+ violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed);
+ } else {
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ }
+ }
+
+ Vector<String> not_allowed;
+ String(test_case.should_not_be_allowed).Split(' ', not_allowed);
+ for (const String& value : not_allowed) {
+ SCOPED_TRACE(testing::Message()
+ << " trusted-types " << test_case.directive
+ << "; do not allow: " << value);
+ EXPECT_FALSE(
+ CSPTrustedTypesAllows(*directive, value, false, violation_details));
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedName);
+ EXPECT_FALSE(
+ CSPTrustedTypesAllows(*directive, value, true, violation_details));
+ if (!test_case.allow_dupes || value == "default") {
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName);
+ } else {
+ EXPECT_EQ(violation_details,
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedName);
+ }
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/deprecation.cc b/chromium/third_party/blink/renderer/core/frame/deprecation.cc
index 72e3444f3d9..3b3506c29ac 100644
--- a/chromium/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/chromium/third_party/blink/renderer/core/frame/deprecation.cc
@@ -70,6 +70,11 @@ enum Milestone {
kM89 = 89,
kM90 = 90,
kM91 = 91,
+ kM92 = 92,
+ kM93 = 93,
+ kM94 = 94,
+ kM95 = 95,
+ kM96 = 96,
};
// Returns estimated milestone dates as milliseconds since January 1, 1970.
@@ -130,6 +135,16 @@ base::Time::Exploded MilestoneDate(Milestone milestone) {
return {2021, 4, 0, 13, 4};
case kM91:
return {2021, 5, 0, 25, 4};
+ case kM92:
+ return {2021, 7, 0, 20, 4};
+ case kM93:
+ return {2021, 8, 0, 31, 4};
+ case kM94:
+ return {2021, 10, 0, 12, 4};
+ case kM95:
+ return {2021, 11, 0, 30, 4};
+ case kM96:
+ return {2022, 1, 0, 25, 4};
}
NOTREACHED();
@@ -348,16 +363,6 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
"https://www.chromestatus.com/feature/6451284559265792 for more "
"details."};
- case WebFeature::kCSSDeepCombinator:
- return {"CSSDeepCombinator", kM65,
- "/deep/ combinator is no longer supported in CSS dynamic "
- "profile. "
- "It is now effectively no-op, acting as if it were a descendant "
- "combinator. /deep/ combinator will be removed, and will be "
- "invalid at M65. You should remove it. See "
- "https://www.chromestatus.com/features/4964279606312960 for more "
- "details."};
-
case WebFeature::kCSSSelectorInternalMediaControlsOverlayCastButton:
return {"CSSSelectorInternalMediaControlsOverlayCastButton", kUnknown,
"The disableRemotePlayback attribute should be used in order to "
@@ -402,25 +407,6 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
"https://www.chromestatus.com/feature/5144752345317376 for more "
"details."};
- case WebFeature::kElementCreateShadowRoot:
- return {"ElementCreateShadowRoot", kUnknown,
- "The Shadow DOM v0 API has been removed. See "
- "https://www.chromestatus.com/feature/4507242028072960 for more "
- "details."};
-
- case WebFeature::kDocumentRegisterElement:
- return {"DocumentRegisterElement", kUnknown,
- "The Custom Elements v0 API has been removed. See "
- "https://www.chromestatus.com/feature/4642138092470272 for more "
- "details."};
-
- case WebFeature::kCSSSelectorPseudoUnresolved:
- return {
- "CSSSelectorPseudoUnresolved", kUnknown,
- "The Custom Elements v0 API (:unresolved pseudo selector) has been "
- "removed. See https://www.chromestatus.com/feature/4642138092470272 "
- "for more details."};
-
case WebFeature::kLocalCSSFileExtensionRejected:
return {"LocalCSSFileExtensionRejected", kM64,
String("CSS cannot be loaded from `file:` URLs unless they end "
@@ -531,6 +517,16 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
"details.",
MilestoneString(kM84).Ascii().c_str())};
+ case WebFeature::kV8SharedArrayBufferConstructedWithoutIsolation:
+ return {
+ "SharedArrayBufferConstructedWithoutIsolation", kM91,
+ String::Format(
+ "SharedArrayBuffer will require cross-origin isolation as of "
+ "%s. See "
+ "https://developer.chrome.com/blog/enabling-shared-array-buffer/"
+ " for more details.",
+ MilestoneString(kM91).Ascii().c_str())};
+
case WebFeature::kV8RTCRtpSender_CreateEncodedAudioStreams_Method:
return {"V8RTCRtpSender_CreateEncodedAudioStreams_Method", kM88,
ReplacedWillBeRemoved("RTCRtpSender.createEncodedAudioStreams",
@@ -569,16 +565,72 @@ DeprecationInfo GetDeprecationInfo(WebFeature feature) {
"RTCConfiguration.encodedInsertableStreams", kM88,
"6321945865879552")};
- case WebFeature::kCommaSeparatorInAllowAttribute:
- return {"CommaSeparatorInAllowAttribute", kM89,
- ReplacedWillBeRemoved("Comma separator in iframe allow attribute",
- "semicolons", kM89, "5740835259809792")};
-
+ case WebFeature::kRTCConstraintEnableRtpDataChannelsFalse:
case WebFeature::kRTCConstraintEnableRtpDataChannelsTrue:
- return {"RTP data channel", kM88,
- ReplacedWillBeRemoved("RTP data channels",
- "standard SCTP data channels", kM90,
- "6485681910054912")};
+ return {
+ "RTP data channel", kM88,
+ "RTP data channels are no longer supported. "
+ "The \"RtpDataChannels\" constraint is currently ignored, and may "
+ "cause an error at a later date."};
+
+ case WebFeature::kCSSSelectorWebkitDetailsMarker:
+ if (!RuntimeEnabledFeatures::SummaryListItemEnabled())
+ return {"NotDeprecated", kUnknown, ""};
+ return {"CSSSeelctorWebKitDetailsMarker", kM89,
+ ReplacedBy("::-webkit-details-marker pseudo element selector",
+ "::marker") +
+ " See https://chromestatus.com/feature/6730096436051968 for "
+ "more details."};
+
+ case WebFeature::kV8SpeechRecognitionEvent_Interpretation_AttributeGetter:
+ return {"V8SpeechRecognitionEvent_Interpretation_AttributeGetter", kM91,
+ WillBeRemoved("SpeechRecognitionEvent's interpretation attribute",
+ kM91, "5769608873115648")};
+
+ case WebFeature::kV8SpeechRecognitionEvent_Emma_AttributeGetter:
+ return {"V8SpeechRecognitionEvent_Emma_AttributeGetter", kM91,
+ WillBeRemoved("SpeechRecognitionEvent's emma attribute", kM91,
+ "5769608873115648")};
+
+ case WebFeature::kRTCPeerConnectionSdpSemanticsPlanB:
+ return {"RTCPeerConnectionSdpSemanticsPlanB", kM93,
+ "Plan B SDP semantics, which is used when constructing an "
+ "RTCPeerConnection with {sdpSemantics:\"plan-b\"}, is a legacy "
+ "version of the Session Description Protocol that has severe "
+ "compatibility issues on modern browsers. The standardized SDP "
+ "format, \"unified-plan\", has been used by default since M72 "
+ "(January, 2019). Dropping support for Plan B is targeted for "
+ "M93 (Canary: July 15, 2021; Stable: August 24, 2021)."};
+
+ case WebFeature::kRTCPeerConnectionSdpSemanticsPlanBWithReverseOriginTrial:
+ return {"RTCPeerConnectionSdpSemanticsPlanBWithReverseOriginTrial", kM96,
+ "Plan B SDP semantics, which is used when constructing an "
+ "RTCPeerConnection with {sdpSemantics:\"plan-b\"}, is a legacy "
+ "version of the Session Description Protocol that has severe "
+ "compatibility issues on modern browsers. The standardized SDP "
+ "format, \"unified-plan\", has been used by default since M72 "
+ "(January, 2019). Dropping support for Plan B is targeted for "
+ "M93 (Canary: July 15, 2021; Stable: August 24, 2021), but "
+ "because you have opted in to the Reverse Origin Trial, you have "
+ "until M96 (Canary: November, 2021; Stable: January, 2022)."};
+
+ case WebFeature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate:
+ case WebFeature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal:
+ case WebFeature::kAddressSpacePublicNonSecureContextEmbeddedPrivate:
+ case WebFeature::kAddressSpacePublicNonSecureContextEmbeddedLocal:
+ case WebFeature::kAddressSpacePrivateNonSecureContextEmbeddedLocal:
+ return {"InsecurePrivateNetworkSubresourceRequest", kM92,
+ "The website requested a subresource from a "
+ "network that it could only access because of its users' "
+ "privileged network position. These requests expose non-public "
+ "devices and servers to the internet, increasing the risk of a "
+ "cross-site request forgery (CSRF) attack, and/or information "
+ "leakage. To mitigate these risks, Chrome deprecates requests to "
+ "non-public subresources when initiated from non-secure "
+ "contexts, and will start blocking them in Chrome 92 (July "
+ "2021). See https://chromestatus.com/feature/5436853517811712 "
+ "for more details."};
+
// Features that aren't deprecated don't have a deprecation message.
default:
return {"NotDeprecated", kUnknown, ""};
@@ -619,12 +671,12 @@ void Deprecation::UnmuteForInspector() {
}
void Deprecation::Suppress(CSSPropertyID unresolved_property) {
- DCHECK(isCSSPropertyIDWithName(unresolved_property));
+ DCHECK(IsCSSPropertyIDWithName(unresolved_property));
css_property_deprecation_bits_.set(static_cast<size_t>(unresolved_property));
}
bool Deprecation::IsSuppressed(CSSPropertyID unresolved_property) {
- DCHECK(isCSSPropertyIDWithName(unresolved_property));
+ DCHECK(IsCSSPropertyIDWithName(unresolved_property));
return css_property_deprecation_bits_[static_cast<size_t>(
unresolved_property)];
}
@@ -686,6 +738,11 @@ void Deprecation::CountDeprecation(ExecutionContext* context,
if (window->GetFrame())
deprecation = &window->GetFrame()->GetPage()->GetDeprecation();
} else if (auto* scope = DynamicTo<WorkerOrWorkletGlobalScope>(context)) {
+ // TODO(crbug.com/1146824): Remove this once PlzDedicatedWorker and
+ // PlzServiceWorker ship.
+ if (!scope->IsInitialized()) {
+ return;
+ }
deprecation = &scope->GetDeprecation();
}
@@ -697,11 +754,11 @@ void Deprecation::CountDeprecation(ExecutionContext* context,
// Don't count usage of WebComponentsV0 for chrome:// URLs, but still report
// the deprecation messages.
+ // Note that this only applies to HTML Imports, as Shadow DOM v0 and Custom
+ // Elements v0 have both now been removed.
bool count_usage = true;
if (context->Url().ProtocolIs("chrome") &&
- (feature == WebFeature::kHTMLImports ||
- feature == WebFeature::kElementCreateShadowRoot ||
- feature == WebFeature::kDocumentRegisterElement)) {
+ feature == WebFeature::kHTMLImports) {
count_usage = false;
}
if (count_usage)
diff --git a/chromium/third_party/blink/renderer/core/frame/deprecation.h b/chromium/third_party/blink/renderer/core/frame/deprecation.h
index f1def488d74..9c43a154d22 100644
--- a/chromium/third_party/blink/renderer/core/frame/deprecation.h
+++ b/chromium/third_party/blink/renderer/core/frame/deprecation.h
@@ -63,7 +63,7 @@ class CORE_EXPORT Deprecation final {
// each deprecation at most once per page load per renderer process.
std::bitset<static_cast<size_t>(WebFeature::kNumberOfFeatures)>
features_deprecation_bits_;
- std::bitset<numCSSPropertyIDs> css_property_deprecation_bits_;
+ std::bitset<kNumCSSPropertyIDs> css_property_deprecation_bits_;
unsigned mute_count_;
DISALLOW_COPY_AND_ASSIGN(Deprecation);
diff --git a/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc b/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
index f718f51a3b6..bfc68359114 100644
--- a/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/document_loading_rendering_test.cc
@@ -463,9 +463,10 @@ TEST_F(DocumentLoadingRenderingTest, StableSVGStopStylingWhileLoadingImport) {
Element* element = GetDocument().getElementById("test");
ASSERT_NE(nullptr, element);
- const SVGComputedStyle& svg_style = element->ComputedStyleRef().SvgStyle();
- EXPECT_EQ(0xff008000, svg_style.StopColor().GetColor());
- EXPECT_EQ(.5f, svg_style.StopOpacity());
+ const ComputedStyle& style = element->ComputedStyleRef();
+ EXPECT_EQ(0xff008000,
+ style.VisitedDependentColor(GetCSSPropertyStopColor()));
+ EXPECT_EQ(.5f, style.StopOpacity());
};
EXPECT_TRUE(GetDocument().HaveRenderBlockingResourcesLoaded());
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_window.cc b/chromium/third_party/blink/renderer/core/frame/dom_window.cc
index 5a768a029f9..59204c4d8db 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/chromium/third_party/blink/renderer/core/frame/dom_window.cc
@@ -72,6 +72,21 @@ v8::Local<v8::Value> DOMWindow::Wrap(v8::Isolate* isolate,
->GlobalProxyIfNotDetached();
}
+v8::MaybeLocal<v8::Value> DOMWindow::WrapV2(ScriptState* script_state) {
+ // TODO(yukishiino): Get understanding of why it's possible to initialize
+ // the context after the frame is detached. And then, remove the following
+ // lines. See also https://crbug.com/712638 .
+ Frame* frame = GetFrame();
+ if (!frame)
+ return v8::Null(script_state->GetIsolate());
+
+ // TODO(yukishiino): Make this function always return the non-empty handle
+ // even if the frame is detached because the global proxy must always exist
+ // per spec.
+ return frame->GetWindowProxy(script_state->World())
+ ->GlobalProxyIfNotDetached();
+}
+
v8::Local<v8::Object> DOMWindow::AssociateWithWrapper(
v8::Isolate*,
const WrapperTypeInfo*,
@@ -447,7 +462,7 @@ void DOMWindow::InstallCoopAccessMonitor(
DCHECK(accessing_frame->IsMainFrame());
monitor.report_type = report_type;
- monitor.accessing_main_frame = accessing_frame->GetFrameToken();
+ monitor.accessing_main_frame = accessing_frame->GetLocalFrameToken();
monitor.endpoint_defined = endpoint_defined;
monitor.reported_window_url = std::move(reported_window_url);
@@ -501,13 +516,25 @@ void DOMWindow::ReportCoopAccess(const char* property_name) {
// Iframes are allowed to trigger reports, only when they are same-origin with
// their top-level document.
- if (accessing_frame->IsCrossOriginToParentFrame())
+ if (accessing_frame->IsCrossOriginToMainFrame())
+ return;
+
+ // See https://crbug.com/1183571
+ // We assumed accessing_frame->IsCrossOriginToMainFrame() implies
+ // accessing_frame->Tree().Top() to be a LocalFrame. This might not be the
+ // case after all, some crashes are reported. This block speculatively returns
+ // early to avoid crashing.
+ // TODO(https://crbug.com/1183571): Check if crashes are still happening and
+ // remove this block.
+ if (!accessing_frame->Tree().Top().IsLocalFrame()) {
+ NOTREACHED();
return;
+ }
LocalFrame& accessing_main_frame =
To<LocalFrame>(accessing_frame->Tree().Top());
- const base::UnguessableToken& accessing_main_frame_token =
- accessing_main_frame.GetFrameToken();
+ const LocalFrameToken accessing_main_frame_token =
+ accessing_main_frame.GetLocalFrameToken();
auto* it = coop_access_monitor_.begin();
while (it != coop_access_monitor_.end()) {
@@ -656,10 +683,24 @@ void DOMWindow::DoPostMessage(scoped_refptr<SerializedScriptValue> message,
if (options->includeUserActivation())
user_activation = UserActivation::CreateSnapshot(source);
+ // TODO(mustaq): This is an ad-hoc mechanism to support delegating a single
+ // capability. We need to add a structure to support passing other
+ // capabilities. An explainer for the general delegation API is here:
+ // https://github.com/mustaqahmed/capability-delegation
+ bool delegate_payment_request = false;
+ if (RuntimeEnabledFeatures::CapabilityDelegationPaymentRequestEnabled(
+ GetExecutionContext()) &&
+ LocalFrame::HasTransientUserActivation(source_frame) &&
+ options->hasCreateToken()) {
+ Vector<String> capability_list;
+ options->createToken().Split(' ', capability_list);
+ delegate_payment_request = capability_list.Contains("paymentrequest");
+ }
+
MessageEvent* event =
MessageEvent::Create(std::move(channels), std::move(message),
source->GetSecurityOrigin()->ToString(), String(),
- source, user_activation);
+ source, user_activation, delegate_payment_request);
SchedulePostMessage(event, std::move(target), source);
}
@@ -673,13 +714,14 @@ void DOMWindow::Trace(Visitor* visitor) const {
}
void DOMWindow::DisconnectCoopAccessMonitor(
- base::UnguessableToken accessing_main_frame) {
+ const LocalFrameToken& accessing_main_frame) {
auto* it = coop_access_monitor_.begin();
while (it != coop_access_monitor_.end()) {
- if (it->accessing_main_frame == accessing_main_frame)
+ if (it->accessing_main_frame == accessing_main_frame) {
it = coop_access_monitor_.erase(it);
- else
+ } else {
++it;
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/dom_window.h b/chromium/third_party/blink/renderer/core/frame/dom_window.h
index dbbc913d339..0a3d30b0e1b 100644
--- a/chromium/third_party/blink/renderer/core/frame/dom_window.h
+++ b/chromium/third_party/blink/renderer/core/frame/dom_window.h
@@ -7,6 +7,7 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/cross_origin_opener_policy.mojom-blink.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/transferables.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
@@ -68,6 +69,7 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
// ScriptWrappable overrides:
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) final;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) final;
v8::Local<v8::Object> AssociateWithWrapper(
v8::Isolate*,
const WrapperTypeInfo*,
@@ -170,7 +172,7 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
// Removed the CoopAccessMonitor with the given |accessing_main_frame| from
// the |coop_access_monitor| list. This is called when the COOP reporter is
// gone or a more recent CoopAccessMonitor is being added.
- void DisconnectCoopAccessMonitor(base::UnguessableToken accessing_main_frame);
+ void DisconnectCoopAccessMonitor(const LocalFrameToken& accessing_main_frame);
Member<Frame> frame_;
// Unlike |frame_|, |window_proxy_manager_| is available even after the
@@ -192,7 +194,7 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
// happens a report will sent to |reporter|.
struct CoopAccessMonitor {
network::mojom::blink::CoopAccessReportType report_type;
- base::UnguessableToken accessing_main_frame;
+ blink::LocalFrameToken accessing_main_frame;
mojo::Remote<network::mojom::blink::CrossOriginOpenerPolicyReporter>
reporter;
bool endpoint_defined;
diff --git a/chromium/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h b/chromium/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
index 7b810fa1f40..cebd2ce76dd 100644
--- a/chromium/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
+++ b/chromium/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
@@ -19,7 +19,7 @@ class CORE_EXPORT FeaturePolicyViolationReportBody : public LocationReportBody {
const String& message,
const String& disposition)
: feature_id_(feature_id),
- message_("Feature policy violation: " +
+ message_("Permissions policy violation: " +
(message.IsEmpty()
? feature_id + " is not allowed in this document."
: message)),
diff --git a/chromium/third_party/blink/renderer/core/frame/find_in_page.cc b/chromium/third_party/blink/renderer/core/frame/find_in_page.cc
index 4161c1275da..efce143ad04 100644
--- a/chromium/third_party/blink/renderer/core/frame/find_in_page.cc
+++ b/chromium/third_party/blink/renderer/core/frame/find_in_page.cc
@@ -36,7 +36,6 @@
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_plugin.h"
#include "third_party/blink/public/web/web_plugin_document.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
@@ -277,15 +276,15 @@ void FindInPage::ClearActiveFindMatch() {
}
void WebLocalFrameImpl::SetTickmarks(const WebElement& target,
- const WebVector<WebRect>& tickmarks) {
+ const WebVector<gfx::Rect>& tickmarks) {
find_in_page_->SetTickmarks(target, tickmarks);
}
void FindInPage::SetTickmarks(const WebElement& target,
- const WebVector<WebRect>& tickmarks) {
+ const WebVector<gfx::Rect>& tickmarks) {
Vector<IntRect> tickmarks_converted(SafeCast<wtf_size_t>(tickmarks.size()));
for (wtf_size_t i = 0; i < tickmarks.size(); ++i)
- tickmarks_converted[i] = tickmarks[i];
+ tickmarks_converted[i] = IntRect(tickmarks[i]);
LayoutBox* box;
if (target.IsNull())
diff --git a/chromium/third_party/blink/renderer/core/frame/find_in_page.h b/chromium/third_party/blink/renderer/core/frame/find_in_page.h
index a66b5513bfd..7b7bcbe0fa7 100644
--- a/chromium/third_party/blink/renderer/core/frame/find_in_page.h
+++ b/chromium/third_party/blink/renderer/core/frame/find_in_page.h
@@ -37,7 +37,7 @@ class CORE_EXPORT FindInPage final : public GarbageCollected<FindInPage>,
bool* active_now = nullptr);
void SetTickmarks(const WebElement& target,
- const WebVector<WebRect>& tickmarks);
+ const WebVector<gfx::Rect>& tickmarks);
int FindMatchMarkersVersion() const;
diff --git a/chromium/third_party/blink/renderer/core/frame/frame.cc b/chromium/third_party/blink/renderer/core/frame/frame.cc
index 74d13ef0459..cc24d583ac9 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame.cc
@@ -55,6 +55,7 @@
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
@@ -63,24 +64,6 @@
namespace blink {
// static
-Frame* Frame::ResolveFrame(const base::UnguessableToken& frame_token) {
- if (!frame_token)
- return nullptr;
-
- // The frame token could refer to either a RemoteFrame or a LocalFrame, so
- // need to check both.
- auto* remote = RemoteFrame::FromFrameToken(frame_token);
- if (remote)
- return remote;
-
- auto* local = LocalFrame::FromFrameToken(frame_token);
- if (local)
- return local;
-
- return nullptr;
-}
-
-// static
Frame* Frame::ResolveFrame(const FrameToken& frame_token) {
if (frame_token.Is<RemoteFrameToken>())
return RemoteFrame::FromFrameToken(frame_token.GetAs<RemoteFrameToken>());
@@ -107,30 +90,63 @@ void Frame::Trace(Visitor* visitor) const {
visitor->Trace(next_sibling_);
visitor->Trace(first_child_);
visitor->Trace(last_child_);
+ visitor->Trace(provisional_frame_);
visitor->Trace(navigation_rate_limiter_);
visitor->Trace(window_agent_factory_);
visitor->Trace(opened_frame_tracker_);
}
-void Frame::Detach(FrameDetachType type) {
+bool Frame::Detach(FrameDetachType type) {
DCHECK(client_);
// Detach() can be re-entered, so this can't simply DCHECK(IsAttached()).
DCHECK(!IsDetached());
lifecycle_.AdvanceTo(FrameLifecycle::kDetaching);
PageDismissalScope in_page_dismissal;
- DetachImpl(type);
+ if (!DetachImpl(type))
+ return false;
- if (GetPage())
- GetPage()->GetFocusController().FrameDetached(this);
+ DCHECK(!IsDetached());
+ DCHECK(client_);
- // Due to re-entrancy, |this| could have completed detaching already.
- // TODO(dcheng): This DCHECK is not always true. See https://crbug.com/838348.
- DCHECK(IsDetached() == !client_);
+ GetPage()->GetFocusController().FrameDetached(this);
+ // FrameDetached() can fire JS event listeners, so `this` might have been
+ // reentrantly detached.
if (!client_)
- return;
+ return false;
+
+ DCHECK(!IsDetached());
+
+ // TODO(dcheng): FocusController::FrameDetached() *should* fire JS events,
+ // hence the above check for `client_` being null. However, when this was
+ // previously placed before the `FrameDetached()` call, nothing crashes, which
+ // is suspicious. Investigate if we really don't need to fire JS events--and
+ // if we don't, move `forbid_scripts` up to be instantiated sooner and
+ // simplify this code.
+ ScriptForbiddenScope forbid_scripts;
+
+ if (type == FrameDetachType::kRemove) {
+ if (provisional_frame_) {
+ provisional_frame_->Detach(FrameDetachType::kRemove);
+ }
+ SetOpener(nullptr);
+ // Clearing the window proxies can call back into `LocalFrameClient`, so
+ // this must be done before nulling out `client_` below.
+ GetWindowProxyManager()->ClearForClose();
+ } else {
+ // In the case of a swap, detach is carefully coordinated with `Swap()`.
+ // Intentionally avoid clearing the opener with `SetOpener(nullptr)` here,
+ // since `Swap()` needs the original value to clone to the new frame.
+ DCHECK_EQ(FrameDetachType::kSwap, type);
+
+ // Clearing the window proxies can call back into `LocalFrameClient`, so
+ // this must be done before nulling out `client_` below.
+ // `ClearForSwap()` preserves the v8::Objects that represent the global
+ // proxies; `Swap()` will later use `ReleaseGlobalProxies()` +
+ // `SetGlobalProxies()` to adopt the global proxies into the new frame.
+ GetWindowProxyManager()->ClearForSwap();
+ }
- SetOpener(nullptr);
// After this, we must no longer talk to the client since this clears
// its owning reference back to our owning LocalFrame.
client_->Detached(type);
@@ -147,6 +163,8 @@ void Frame::Detach(FrameDetachType type) {
DisconnectOwnerElement();
page_ = nullptr;
embedding_token_ = base::nullopt;
+
+ return true;
}
void Frame::DisconnectOwnerElement() {
@@ -308,7 +326,6 @@ bool Frame::IsAdRoot() const {
void Frame::UpdateInertIfPossible() {
if (auto* frame_owner_element =
DynamicTo<HTMLFrameOwnerElement>(owner_.Get())) {
- frame_owner_element->UpdateDistributionForFlatTreeTraversal();
if (frame_owner_element->IsInert())
SetIsInert(true);
}
@@ -369,7 +386,7 @@ Frame::Frame(FrameClient* client,
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const FrameToken& frame_token,
WindowProxyManager* window_proxy_manager,
WindowAgentFactory* inheriting_agent_factory)
: tree_node_(this),
@@ -506,36 +523,23 @@ Frame* Frame::Top() {
return parent;
}
-bool Frame::Swap(WebFrame* frame) {
+bool Frame::Swap(WebFrame* new_web_frame) {
+ DCHECK(IsAttached());
+
using std::swap;
- // TODO(dcheng): This should not be reachable. Reaching this implies `Swap()`
- // is being called on an already-detached frame which should never happen...
- if (!IsAttached())
- return false;
+
// Important: do not cache frame tree pointers (e.g. `previous_sibling_`,
// `next_sibling_`, `first_child_`, `last_child_`) here. It is possible for
- // `DetachDocument()` to mutate the frame tree and cause cached values to
- // become invalid.
+ // `Detach()` to mutate the frame tree and cause cached values to become
+ // invalid.
FrameOwner* owner = owner_;
FrameSwapScope frame_swap_scope(owner);
Page* page = page_;
AtomicString name = Tree().GetName();
- // Unload the current Document in this frame: this calls unload handlers,
- // detaches child frames, etc. Since this runs script, make sure this frame
- // wasn't detached before continuing with the swap.
- if (!DetachDocument()) {
- // If the Swap() fails, it should be because the frame has been detached
- // already. Otherwise the caller will not detach the frame when we return
- // false, and the browser and renderer will disagree about the destruction
- // of |this|.
- CHECK(!IsAttached());
- return false;
- }
-
// TODO(dcheng): This probably isn't necessary if we fix the ordering of
- // events in `Swap()`, e.g. `Detach()` should not happen before `new_frame` is
- // swapped in.
+ // events in `Swap()`, e.g. `Detach()` should not happen before
+ // `new_web_frame` is swapped in.
// If there is a local parent, it might incorrectly declare itself complete
// during the detach phase of this swap. Suppress its completion until swap is
// over, at which point its completion will be correctly dependent on its
@@ -546,28 +550,38 @@ bool Frame::Swap(WebFrame* frame) {
*parent_local_frame->GetDocument())
: nullptr;
+ // Unload the current Document in this frame: this calls unload handlers,
+ // detaches child frames, etc. Since this runs script, make sure this frame
+ // wasn't detached before continuing with the swap.
+ if (!Detach(FrameDetachType::kSwap)) {
+ // If the Swap() fails, it should be because the frame has been detached
+ // already. Otherwise the caller will not detach the frame when we return
+ // false, and the browser and renderer will disagree about the destruction
+ // of |this|.
+ CHECK(IsDetached());
+ return false;
+ }
+
+ // Otherwise, on a successful `Detach()` for swap, `this` is now detached--but
+ // crucially--still linked into the frame tree.
+
+ if (provisional_frame_) {
+ // `this` is about to be replaced, so if `provisional_frame_` is set, it
+ // should match `frame` which is being swapped in.
+ DCHECK_EQ(provisional_frame_, WebFrame::ToCoreFrame(*new_web_frame));
+ provisional_frame_ = nullptr;
+ }
+
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
WindowProxyManager::GlobalProxyVector global_proxies;
- GetWindowProxyManager()->ClearForSwap();
GetWindowProxyManager()->ReleaseGlobalProxies(global_proxies);
- // This must be before Detach so DidChangeOpener is not called.
- Frame* original_opener = opener_;
- if (original_opener)
- SetOpenerDoNotNotify(nullptr);
-
- // Although the Document in this frame is now unloaded, many resources
- // associated with the frame itself have not yet been freed yet. Note that
- // after `Detach()` returns, `this` is detached but *not* yet unlinked from
- // the frame tree.
- // TODO(dcheng): Merge this into the `DetachDocument()` step above. Executing
- // parts of `Detach()` twice is confusing.
- Detach(FrameDetachType::kSwap);
- if (frame->IsWebRemoteFrame()) {
- CHECK(!WebFrame::ToCoreFrame(*frame));
- To<WebRemoteFrameImpl>(frame)->InitializeCoreFrame(
- *page, owner, WebFrame::FromFrame(parent_), nullptr,
- FrameInsertType::kInsertLater, name, &window_agent_factory());
+ if (new_web_frame->IsWebRemoteFrame()) {
+ CHECK(!WebFrame::ToCoreFrame(*new_web_frame));
+ To<WebRemoteFrameImpl>(new_web_frame)
+ ->InitializeCoreFrame(*page, owner, WebFrame::FromCoreFrame(parent_),
+ nullptr, FrameInsertType::kInsertLater, name,
+ &window_agent_factory());
// At this point, a `RemoteFrame` will have already updated
// `Page::MainFrame()` or `FrameOwner::ContentFrame()` as appropriate, and
// its `parent_` pointer is also populated.
@@ -579,7 +593,7 @@ bool Frame::Swap(WebFrame* frame) {
// TODO(dcheng): Make local and remote frame updates more uniform.
}
- Frame* new_frame = WebFrame::ToCoreFrame(*frame);
+ Frame* new_frame = WebFrame::ToCoreFrame(*new_web_frame);
CHECK(new_frame);
// At this point, `new_frame->parent_` is correctly set, but `new_frame`'s
@@ -609,8 +623,9 @@ bool Frame::Swap(WebFrame* frame) {
parent_ = nullptr;
}
- if (original_opener) {
- new_frame->SetOpenerDoNotNotify(original_opener);
+ if (Frame* opener = opener_) {
+ SetOpenerDoNotNotify(nullptr);
+ new_frame->SetOpenerDoNotNotify(opener);
}
opened_frame_tracker_.TransferTo(new_frame);
diff --git a/chromium/third_party/blink/renderer/core/frame/frame.h b/chromium/third_party/blink/renderer/core/frame/frame.h
index 6cc3104135f..ebeaf456c5b 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame.h
@@ -32,6 +32,7 @@
#include "base/i18n/rtl.h"
#include "base/optional.h"
#include "base/unguessable_token.h"
+#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
#include "third_party/blink/public/common/feature_policy/feature_policy_features.h"
#include "third_party/blink/public/common/frame/user_activation_state.h"
@@ -93,8 +94,6 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
public:
// Returns the Frame instance for the given |frame_token|.
// Note that this Frame can be either a LocalFrame or Remote instance.
- // TODO(crbug.com/1096617): Remove the UnguessableToken version of this.
- static Frame* ResolveFrame(const base::UnguessableToken& frame_token);
static Frame* ResolveFrame(const FrameToken& frame_token);
virtual ~Frame();
@@ -106,7 +105,20 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
virtual void Navigate(FrameLoadRequest&, WebFrameLoadType) = 0;
- void Detach(FrameDetachType);
+ // Releases the resources associated with a frame. Used for:
+ // - closing a `WebView`, which detaches the main frame
+ // - removing a `FrameOwner` from the DOM, which detaches the `FrameOwner`'s
+ // content frame
+ // - preparing a frame to be replaced in `Frame::Swap()`.
+ //
+ // Since `Detach()` fires JS events and detaches all child frames, and JS can
+ // modify the DOM in ways that trigger frame removal, it is possible to
+ // reentrantly call `Detach() with `FrameDetachType::kRemove` before the
+ // original invocation of `Detach()` has completed. In that case, the
+ // interrupted invocation returns false to signal the interruption; otherwise,
+ // on successful completion (e.g. `Detach()` runs all the way through to the
+ // end), returns true.
+ bool Detach(FrameDetachType);
void DisconnectOwnerElement();
virtual bool ShouldClose() = 0;
virtual void HookBackForwardCacheEviction() = 0;
@@ -156,10 +168,15 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
Frame* FindUnsafeParentScrollPropagationBoundary();
- // This prepares the Frame for the next commit. It will detach children,
- // dispatch unload events, abort XHR requests and detach the document.
- // Returns true if the frame is ready to receive the next commit, or false
- // otherwise.
+ // Similar to `Detach()`, except that it does not completely detach `this`:
+ // instead, on successful completion (i.e. returns true), `this` will be ready
+ // to be swapped out (if necessary) and to commit the next navigation.
+ //
+ // Note that the caveats about `Detach()` being interrupted by reentrant
+ // removal also apply to this method; this method also returns false if
+ // interrupted by reentrant removal of `this`. A return value of false
+ // indicates that the caller should early return and skip any further work, as
+ // there is no longer a frame to commit a navigation into.
virtual bool DetachDocument() = 0;
// LayoutObject for the element that contains this frame.
@@ -210,8 +227,11 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
return lifecycle_.GetState() == FrameLifecycle::kAttached;
}
- // Ad Tagging
+ // Whether the frame is considered to be an ad subframe by Ad Tagging. Returns
+ // true for both root and child ad subframes.
bool IsAdSubframe() const;
+
+ // Whether the frame is considered to be a root ad subframe by Ad Tagging.
bool IsAdRoot() const;
// Called to make a frame inert or non-inert. A frame is inert when there
@@ -250,23 +270,21 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
return navigation_rate_limiter_;
}
- // Called to get the opener's FeatureState if any. This works with disowned
- // openers, i.e., even if WebFrame::Opener() is nullptr, there could be a
- // non-empty feature state which is taken from the the original opener of the
- // frame. This is similar to how sandbox flags are propagated to the opened
- // new browsing contexts.
- const FeaturePolicyFeatureState& OpenerFeatureState() const {
- return opener_feature_state_;
+ // Called to get the opener's sandbox flags if any. This works with disowned
+ // openers, i.e., even if WebFrame::Opener() is nullptr,
+ network::mojom::blink::WebSandboxFlags OpenerSandboxFlags() const {
+ return opener_sandbox_flags_;
}
- // Sets the opener's FeatureState for the main frame. Once a non-empty
+ // Sets the opener's sandbox_flags for the main frame. Once a non-empty
// |opener_feature_state| is set, it can no longer be modified (due to the
// fact that the original opener which passed down the FeatureState cannot be
// modified either).
- void SetOpenerFeatureState(const FeaturePolicyFeatureState& state) {
- DCHECK(state.empty() || IsMainFrame());
- DCHECK(opener_feature_state_.empty());
- opener_feature_state_ = state;
+ void SetOpenerSandboxFlags(network::mojom::blink::WebSandboxFlags flags) {
+ DCHECK(IsMainFrame());
+ DCHECK_EQ(network::mojom::blink::WebSandboxFlags::kNone,
+ opener_sandbox_flags_);
+ opener_sandbox_flags_ = flags;
}
const DocumentPolicyFeatureState& GetRequiredDocumentPolicy() const {
@@ -285,8 +303,7 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// This identifier represents the stable identifier between a
// LocalFrame <--> RenderFrameHostImpl or a
// RemoteFrame <--> RenderFrameProxyHost in the browser process.
- // TODO(crbug.com/1096617): Make this return a FrameToken instead.
- const base::UnguessableToken& GetFrameToken() const { return frame_token_; }
+ const FrameToken& GetFrameToken() const { return frame_token_; }
bool GetVisibleToHitTesting() const { return visible_to_hit_testing_; }
void UpdateVisibleToHitTesting();
@@ -334,6 +351,8 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// Returns the last child frame.
Frame* LastChild() const { return last_child_; }
+ // TODO(dcheng): these should probably all have restricted visibility. They
+ // are not intended for general usage.
// Detaches a frame from its parent frame if it has one.
void DetachFromParent();
@@ -342,6 +361,15 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// Removes the given child from this frame.
void RemoveChild(Frame* child);
+ LocalFrame* ProvisionalFrame() const { return provisional_frame_; }
+ void SetProvisionalFrame(LocalFrame* provisional_frame) {
+ // There should only be null -> non-null or non-null -> null transitions
+ // here. Anything else indicates a logic error in the code managing this
+ // state.
+ DCHECK_NE(!!provisional_frame, !!provisional_frame_);
+ provisional_frame_ = provisional_frame;
+ }
+
protected:
// |inheriting_agent_factory| should basically be set to the parent frame or
// opener's WindowAgentFactory. Pass nullptr if the frame is isolated from
@@ -354,7 +382,7 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const FrameToken& frame_token,
WindowProxyManager*,
WindowAgentFactory* inheriting_agent_factory);
@@ -362,9 +390,11 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// that vtables are initialized.
void Initialize();
- // DetachImpl() may be re-entered multiple times, if a frame is detached while
- // already being detached.
- virtual void DetachImpl(FrameDetachType) = 0;
+ // DetachImpl() may be reentered if a frame is reentrantly removed whilst in
+ // the process of detaching (for removal or swap). Overrides should return
+ // false if interrupted by reentrant removal of `this`, and true otherwise.
+ // See `Detach()` for more information.
+ virtual bool DetachImpl(FrameDetachType) = 0;
// Note that IsAttached() and IsDetached() are not strict opposites: frames
// that are detaching are considered to be in neither state.
@@ -405,10 +435,11 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// not typically reused for non-ad purposes.
//
// For LocalFrame, it might be (1) calculated directly in the renderer based
- // on script in the stack, or (2) replicated from the browser process, or (3)
- // signaled from the browser process at ready-to-commit time. For RemoteFrame,
- // it might be (1) replicated from the browser process or (2) signaled from
- // the browser process at ready-to-commit time.
+ // on script in the stack in the case of an initial synchronous commit, or (2)
+ // replicated from the browser process, or (3) signaled from the browser
+ // process at ready-to-commit time. For RemoteFrame, it might be (1)
+ // replicated from the browser process or (2) signaled from the browser
+ // process at ready-to-commit time.
mojom::blink::AdFrameType ad_frame_type_;
private:
@@ -428,11 +459,13 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
Member<Frame> first_child_;
Member<Frame> last_child_;
+ Member<LocalFrame> provisional_frame_;
+
NavigationRateLimiter navigation_rate_limiter_;
- // Feature policy state inherited from an opener. It is always empty for child
+ // Sandbox flags inherited from an opener. It is always empty for child
// frames.
- FeaturePolicyFeatureState opener_feature_state_;
+ network::mojom::blink::WebSandboxFlags opener_sandbox_flags_;
// The required document policy for any subframes of this frame.
// Note: current frame's document policy might not conform to
@@ -473,7 +506,7 @@ class CORE_EXPORT Frame : public GarbageCollected<Frame> {
// will *not* have the same identifier. This is different than the
// |devtools_frame_token_| in which all representations of this frame node
// have the same value in all processes.
- base::UnguessableToken frame_token_;
+ FrameToken frame_token_;
// This task is used for the async step in form submission when a form is
// targeting this frame. http://html.spec.whatwg.org/C/#plan-to-navigate
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_console.cc b/chromium/third_party/blink/renderer/core/frame/frame_console.cc
index 2e8f77d8c83..0ae65855a4a 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_console.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_console.cc
@@ -76,8 +76,9 @@ void FrameConsole::ReportMessageToClient(mojom::ConsoleMessageSource source,
if (source == mojom::ConsoleMessageSource::kConsoleApi) {
if (!frame_->GetPage())
return;
- if (frame_->GetChromeClient().ShouldReportDetailedMessageForSource(*frame_,
- url)) {
+ if (frame_->GetChromeClient()
+ .ShouldReportDetailedMessageForSourceAndSeverity(*frame_, level,
+ url)) {
std::unique_ptr<SourceLocation> full_location =
SourceLocation::CaptureWithFullStackTrace();
if (!full_location->IsUnknown())
@@ -85,8 +86,9 @@ void FrameConsole::ReportMessageToClient(mojom::ConsoleMessageSource source,
}
} else {
if (!location->IsUnknown() &&
- frame_->GetChromeClient().ShouldReportDetailedMessageForSource(*frame_,
- url))
+ frame_->GetChromeClient()
+ .ShouldReportDetailedMessageForSourceAndSeverity(*frame_, level,
+ url))
stack_trace = location->ToString();
}
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.cc b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.cc
new file mode 100644
index 00000000000..0dc762f65c3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.cc
@@ -0,0 +1,76 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/frame_content_as_text.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html_element_type_helpers.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/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+void FrameContentAsText(size_t max_chars,
+ LocalFrame* frame,
+ StringBuilder& output) {
+ Document* document = frame->GetDocument();
+ if (!document)
+ return;
+
+ if (!frame->View() || frame->View()->CanThrottleRendering())
+ return;
+
+ DCHECK(!frame->View()->NeedsLayout());
+ DCHECK(!document->NeedsLayoutTreeUpdate());
+
+ if (document->documentElement() &&
+ document->documentElement()->GetLayoutObject()) {
+ output.Append(document->documentElement()->innerText());
+ if (output.length() >= max_chars)
+ output.Resize(max_chars);
+ }
+
+ // The separator between frames when the frames are converted to plain text.
+ const LChar kFrameSeparator[] = {'\n', '\n'};
+ const size_t frame_separator_length = base::size(kFrameSeparator);
+
+ // Recursively walk the children.
+ const FrameTree& frame_tree = frame->Tree();
+ for (Frame* cur_child = frame_tree.FirstChild(); cur_child;
+ cur_child = cur_child->Tree().NextSibling()) {
+ auto* cur_local_child = DynamicTo<LocalFrame>(cur_child);
+ if (!cur_local_child)
+ continue;
+ // Ignore the text of non-visible frames.
+ LayoutView* layout_view = cur_local_child->ContentLayoutObject();
+ LayoutObject* owner_layout_object = cur_local_child->OwnerLayoutObject();
+ if (!layout_view || !layout_view->Size().Width() ||
+ !layout_view->Size().Height() ||
+ (layout_view->Location().X() + layout_view->Size().Width() <= 0) ||
+ (layout_view->Location().Y() + layout_view->Size().Height() <= 0) ||
+ (owner_layout_object && owner_layout_object->Style() &&
+ owner_layout_object->Style()->Visibility() != EVisibility::kVisible)) {
+ continue;
+ }
+
+ // Make sure the frame separator won't fill up the buffer, and give up if
+ // it will. The danger is if the separator will make the buffer longer than
+ // maxChars. This will cause the computation above:
+ // maxChars - output->size()
+ // to be a negative number which will crash when the subframe is added.
+ if (output.length() >= max_chars - frame_separator_length)
+ return;
+
+ output.Append(kFrameSeparator, frame_separator_length);
+ FrameContentAsText(max_chars, cur_local_child, output);
+ if (output.length() >= max_chars)
+ return; // Filled up the buffer.
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.h b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.h
new file mode 100644
index 00000000000..ebe0d5b64af
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text.h
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_CONTENT_AS_TEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_CONTENT_AS_TEXT_H_
+
+#include <stdint.h>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class LocalFrame;
+
+// Recursively dumps the text inside |frame| and its local subtree to
+// |output|, up to the length of |max_chars|.
+CORE_EXPORT void FrameContentAsText(size_t max_chars,
+ LocalFrame* frame,
+ StringBuilder& output);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_CONTENT_AS_TEXT_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_content_as_text_test.cc b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text_test.cc
new file mode 100644
index 00000000000..a25e3816aff
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/frame_content_as_text_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/frame_content_as_text.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_string.h"
+#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/web_local_frame_impl.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+class FrameContentAsTextTest : public testing::Test {
+ public:
+ FrameContentAsTextTest() = default;
+ ~FrameContentAsTextTest() override {
+ url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
+ }
+
+ void RegisterMockedHttpURLLoad(const std::string& file_path) {
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url_), test::CoreTestDataPath(),
+ WebString::FromUTF8(file_path));
+ }
+
+ protected:
+ const std::string base_url_ = "http://test.com/";
+};
+
+TEST_F(FrameContentAsTextTest, RenderedDocumentsOnly) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+
+ RegisterMockedHttpURLLoad("display_none_frame.html");
+
+ WebView* web_view =
+ web_view_helper.InitializeAndLoad(base_url_ + "display_none_frame.html");
+
+ StringBuilder text;
+
+ WebLocalFrame* local_frame = web_view->MainFrame()->ToWebLocalFrame();
+
+ FrameContentAsText(
+ /*max_chars=*/100, To<WebLocalFrameImpl>(local_frame)->GetFrame(), text);
+
+ EXPECT_EQ(String(""), text.ToString());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc b/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
index 43acfebdb0c..8921d951b43 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
@@ -97,6 +97,14 @@ IntSize FrameOverlay::Size() const {
IntRect FrameOverlay::ComputeInterestRect(const GraphicsLayer* graphics_layer,
const IntRect&) const {
DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ return IntRect(IntPoint(), Size());
+}
+
+IntRect FrameOverlay::PaintableRegion(
+ const GraphicsLayer* graphics_layer) const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
return IntRect(IntPoint(), Size());
}
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_overlay.h b/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
index 24af6f773a2..9666570128b 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
@@ -90,6 +90,7 @@ class CORE_EXPORT FrameOverlay : public GraphicsLayerClient,
bool NeedsRepaint(const GraphicsLayer&) const override { return true; }
IntRect ComputeInterestRect(const GraphicsLayer*,
const IntRect&) const override;
+ IntRect PaintableRegion(const GraphicsLayer*) const override;
void PaintContents(const GraphicsLayer*,
GraphicsContext&,
GraphicsLayerPaintingPhase,
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_owner.h b/chromium/third_party/blink/renderer/core/frame/frame_owner.h
index 90c1b81e456..00c4bcf9ae3 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_owner.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_owner.h
@@ -73,7 +73,7 @@ class CORE_EXPORT FrameOwner : public GarbageCollectedMixin {
virtual bool AllowFullscreen() const = 0;
virtual bool AllowPaymentRequest() const = 0;
virtual bool IsDisplayNone() const = 0;
- virtual mojom::ColorScheme GetColorScheme() const = 0;
+ virtual mojom::blink::ColorScheme GetColorScheme() const = 0;
virtual AtomicString RequiredCsp() const = 0;
// Returns whether or not children of the owned frame should be lazily loaded.
@@ -152,8 +152,8 @@ class CORE_EXPORT DummyFrameOwner final
bool AllowFullscreen() const override { return false; }
bool AllowPaymentRequest() const override { return false; }
bool IsDisplayNone() const override { return false; }
- mojom::ColorScheme GetColorScheme() const override {
- return mojom::ColorScheme::kLight;
+ mojom::blink::ColorScheme GetColorScheme() const override {
+ return mojom::blink::ColorScheme::kLight;
}
AtomicString RequiredCsp() const override { return g_null_atom; }
bool ShouldLazyLoadChildren() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_serializer.cc b/chromium/third_party/blink/renderer/core/frame/frame_serializer.cc
index 94c05864235..442bc666866 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_serializer.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_serializer.cc
@@ -506,7 +506,8 @@ void FrameSerializer::SerializeCSSRule(CSSRule* rule) {
// Rules inheriting CSSGroupingRule
case CSSRule::kMediaRule:
- case CSSRule::kSupportsRule: {
+ case CSSRule::kSupportsRule:
+ case CSSRule::kContainerRule: {
CSSRuleList* rule_list = rule->cssRules();
for (unsigned i = 0; i < rule_list->length(); ++i)
SerializeCSSRule(rule_list->item(i));
@@ -519,7 +520,8 @@ void FrameSerializer::SerializeCSSRule(CSSRule* rule) {
break;
case CSSRule::kCounterStyleRule:
- // TODO(crbug.com/687225): Implement
+ // TODO(crbug.com/1176323): Handle image symbols in @counter-style rules
+ // when we implement it.
break;
// Rules in which no external resources can be referenced
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_serializer.h b/chromium/third_party/blink/renderer/core/frame/frame_serializer.h
index b77fefde24b..d8a9f4695ed 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_serializer.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_serializer.h
@@ -43,6 +43,7 @@
namespace blink {
+class CSSPropertyValueSet;
class CSSRule;
class CSSStyleSheet;
class CSSValue;
@@ -51,7 +52,7 @@ class Element;
class FontResource;
class ImageResourceContent;
class LocalFrame;
-class CSSPropertyValueSet;
+class Node;
struct SerializedResource;
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc b/chromium/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc
index d2c8fb5de06..9c41e84efeb 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc
@@ -287,9 +287,6 @@ std::pair<Node*, Element*> FrameSerializerDelegateImpl::GetAuxiliaryDOMTree(
case ShadowRootType::kUserAgent:
// No need to serialize.
return std::pair<Node*, Element*>();
- case ShadowRootType::V0:
- shadow_mode = "v0";
- break;
case ShadowRootType::kOpen:
shadow_mode = "open";
break;
@@ -305,8 +302,7 @@ std::pair<Node*, Element*> FrameSerializerDelegateImpl::GetAuxiliaryDOMTree(
template_element->setAttribute(
QualifiedName(g_null_atom, kShadowModeAttributeName, g_null_atom),
AtomicString(shadow_mode));
- if (shadow_root->GetType() != ShadowRootType::V0 &&
- shadow_root->delegatesFocus()) {
+ if (shadow_root->delegatesFocus()) {
template_element->setAttribute(
QualifiedName(g_null_atom, kShadowDelegatesFocusAttributeName,
g_null_atom),
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test.cc b/chromium/third_party/blink/renderer/core/frame/frame_test.cc
index c999ed1c78e..fc37079cc3a 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test.cc
@@ -31,7 +31,8 @@ class FrameTest : public PageTestBase {
void Navigate(const String& destinationUrl, bool user_activated) {
const KURL& url = KURL(NullURL(), destinationUrl);
auto navigation_params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url);
if (user_activated)
navigation_params->is_user_activated = true;
GetDocument().GetFrame()->Loader().CommitNavigation(
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index e89f688d2cb..3bd062fca08 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -44,6 +44,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/frame/frame_policy.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
#include "third_party/blink/public/platform/interface_registry.h"
@@ -59,12 +60,13 @@
#include "third_party/blink/public/web/web_navigation_params.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view_client.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
+#include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -124,6 +126,17 @@ viz::FrameSinkId AllocateFrameSinkId() {
return viz::FrameSinkId(++s_frame_sink_count, 1);
}
+// Installs a create hook and uninstalls it when this object is
+// destroyed.
+class ScopedCreateWebFrameWidget {
+ public:
+ explicit ScopedCreateWebFrameWidget(CreateWebFrameWidgetCallback* hook) {
+ InstallCreateWebFrameWidgetHook(hook);
+ }
+
+ ~ScopedCreateWebFrameWidget() { InstallCreateWebFrameWidgetHook(nullptr); }
+};
+
} // namespace
cc::LayerTreeSettings GetSynchronousSingleThreadLayerTreeSettings() {
@@ -148,8 +161,10 @@ void LoadFrameDontWait(WebLocalFrame* frame, const WebURL& url) {
params->navigation_timings.navigation_start = base::TimeTicks::Now();
params->navigation_timings.fetch_start = base::TimeTicks::Now();
params->is_browser_initiated = true;
+ MockPolicyContainerHost mock_policy_container_host;
params->policy_container = std::make_unique<WebPolicyContainer>(
- WebPolicyContainerDocumentPolicies(), mojo::NullAssociatedRemote());
+ WebPolicyContainerPolicies(),
+ mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote());
FillNavigationParamsResponse(params.get());
impl->CommitNavigation(std::move(params), nullptr /* extra_data */);
}
@@ -166,7 +181,7 @@ void LoadHTMLString(WebLocalFrame* frame,
const base::TickClock* clock) {
auto* impl = To<WebLocalFrameImpl>(frame);
std::unique_ptr<WebNavigationParams> navigation_params =
- WebNavigationParams::CreateWithHTMLString(html, base_url);
+ WebNavigationParams::CreateWithHTMLStringForTesting(html, base_url);
navigation_params->tick_clock = clock;
impl->CommitNavigation(std::move(navigation_params),
nullptr /* extra_data */);
@@ -230,13 +245,18 @@ WebMouseEvent CreateMouseEvent(WebInputEvent::Type type,
return result;
}
-WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
- mojom::blink::TreeScopeType scope,
- TestWebFrameClient* client) {
+WebLocalFrameImpl* CreateLocalChild(
+ WebLocalFrame& parent,
+ mojom::blink::TreeScopeType scope,
+ TestWebFrameClient* client,
+ WebPolicyContainerBindParams policy_container_bind_params) {
+ MockPolicyContainerHost mock_policy_container_host;
+ mock_policy_container_host.BindWithNewEndpoint(
+ std::move(policy_container_bind_params.receiver));
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
- auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
- scope, client, nullptr, base::UnguessableToken::Create()));
+ auto* frame = To<WebLocalFrameImpl>(
+ parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(owned_client));
return frame;
}
@@ -244,150 +264,30 @@ WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
mojom::blink::TreeScopeType scope,
- std::unique_ptr<TestWebFrameClient> self_owned) {
+ std::unique_ptr<TestWebFrameClient> self_owned,
+ WebPolicyContainerBindParams policy_container_bind_params) {
+ MockPolicyContainerHost mock_policy_container_host;
+ mock_policy_container_host.BindWithNewEndpoint(
+ std::move(policy_container_bind_params.receiver));
DCHECK(self_owned);
TestWebFrameClient* client = self_owned.get();
- auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
- scope, client, nullptr, base::UnguessableToken::Create()));
+ auto* frame = To<WebLocalFrameImpl>(
+ parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(self_owned));
return frame;
}
-WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame,
- TestWebFrameClient* client) {
- std::unique_ptr<TestWebFrameClient> owned_client;
- client = CreateDefaultClientIfNeeded(client, owned_client);
- auto* frame = To<WebLocalFrameImpl>(WebLocalFrame::CreateProvisional(
- client, nullptr, base::UnguessableToken::Create(), &old_frame,
- FramePolicy(), WebFrame::ToCoreFrame(old_frame)->Tree().GetName()));
- client->Bind(frame, std::move(owned_client));
- std::unique_ptr<TestWebWidgetClient> widget_client;
-
- mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
- frame_widget_receiver =
- frame_widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
- frame_widget_host_receiver =
- frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
- widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- // Create a local root, if necessary.
- if (!frame->Parent()) {
- widget_client = std::make_unique<TestWebWidgetClient>();
- // TODO(dcheng): The main frame widget currently has a special case.
- // Eliminate this once WebView is no longer a WebWidget.
- WebFrameWidget* frame_widget = WebFrameWidget::CreateForMainFrame(
- widget_client.get(), frame, frame_widget_host.Unbind(),
- std::move(frame_widget_receiver), widget_client->BindNewWidgetHost(),
- std::move(widget_receiver), AllocateFrameSinkId());
- widget_client->SetFrameWidget(frame_widget, std::move(widget_remote));
- // The WebWidget requires the compositor to be set before it is used.
- cc::LayerTreeSettings layer_tree_settings =
- GetSynchronousSingleThreadLayerTreeSettings();
- widget_client->set_layer_tree_host(frame_widget->InitializeCompositing(
- widget_client->main_thread_scheduler(),
- widget_client->task_graph_runner(), true,
- widget_client->GetInitialScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- frame_widget->SetCompositorVisible(true);
- } else if (frame->Parent()->IsWebRemoteFrame()) {
- widget_client = std::make_unique<TestWebWidgetClient>();
-
- WebFrameWidget* frame_widget = WebFrameWidget::CreateForChildLocalRoot(
- widget_client.get(), frame, frame_widget_host.Unbind(),
- std::move(frame_widget_receiver), widget_client->BindNewWidgetHost(),
- std::move(widget_receiver), AllocateFrameSinkId());
- widget_client->SetFrameWidget(frame_widget, std::move(widget_remote));
- // The WebWidget requires the compositor to be set before it is used.
- cc::LayerTreeSettings layer_tree_settings =
- GetSynchronousSingleThreadLayerTreeSettings();
- widget_client->set_layer_tree_host(frame_widget->InitializeCompositing(
- widget_client->main_thread_scheduler(),
- widget_client->task_graph_runner(), true,
- widget_client->GetInitialScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- frame_widget->SetCompositorVisible(true);
- frame_widget->Resize(gfx::Size());
- }
- if (widget_client)
- client->BindWidgetClient(std::move(widget_client));
- return frame;
-}
-
WebRemoteFrameImpl* CreateRemote(TestWebRemoteFrameClient* client) {
std::unique_ptr<TestWebRemoteFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
auto* frame = MakeGarbageCollected<WebRemoteFrameImpl>(
mojom::blink::TreeScopeType::kDocument, client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
- client->GetRemoteAssociatedInterfaces(),
- base::UnguessableToken::Create());
+ client->GetRemoteAssociatedInterfaces(), RemoteFrameToken());
client->Bind(frame, std::move(owned_client));
return frame;
}
-WebLocalFrameImpl* CreateLocalChild(WebRemoteFrame& parent,
- const WebString& name,
- const WebFrameOwnerProperties& properties,
- WebFrame* previous_sibling,
- TestWebFrameClient* client,
- TestWebWidgetClient* widget_client) {
- std::unique_ptr<TestWebFrameClient> owned_client;
- client = CreateDefaultClientIfNeeded(client, owned_client);
- auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
- mojom::blink::TreeScopeType::kDocument, name, FramePolicy(), client,
- nullptr, previous_sibling, properties,
- mojom::blink::FrameOwnerElementType::kIframe,
- base::UnguessableToken::Create(), nullptr,
- std::make_unique<WebPolicyContainer>(WebPolicyContainerDocumentPolicies(),
- mojo::NullAssociatedRemote())));
- client->Bind(frame, std::move(owned_client));
-
- std::unique_ptr<TestWebWidgetClient> owned_widget_client;
- widget_client =
- CreateDefaultClientIfNeeded(widget_client, owned_widget_client);
-
- mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
- frame_widget_receiver =
- frame_widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
- frame_widget_host_receiver =
- frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
- widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- WebFrameWidget* frame_widget = WebFrameWidget::CreateForChildLocalRoot(
- widget_client, frame, frame_widget_host.Unbind(),
- std::move(frame_widget_receiver), widget_client->BindNewWidgetHost(),
- std::move(widget_receiver), AllocateFrameSinkId());
- // The WebWidget requires the compositor to be set before it is used.
- widget_client->SetFrameWidget(frame_widget, std::move(widget_remote));
- cc::LayerTreeSettings layer_tree_settings =
- GetSynchronousSingleThreadLayerTreeSettings();
- widget_client->set_layer_tree_host(frame_widget->InitializeCompositing(
- widget_client->main_thread_scheduler(),
- widget_client->task_graph_runner(), true,
- widget_client->GetInitialScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- frame_widget->SetCompositorVisible(true);
- // Set an initial size for subframes.
- if (frame->Parent())
- frame_widget->Resize(gfx::Size());
- client->BindWidgetClient(std::move(owned_widget_client));
- return frame;
-}
-
WebRemoteFrameImpl* CreateRemoteChild(
WebRemoteFrame& parent,
const WebString& name,
@@ -399,8 +299,7 @@ WebRemoteFrameImpl* CreateRemoteChild(
mojom::blink::TreeScopeType::kDocument, name, FramePolicy(),
mojom::blink::FrameOwnerElementType::kIframe, client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
- client->GetRemoteAssociatedInterfaces(), base::UnguessableToken::Create(),
- nullptr));
+ client->GetRemoteAssociatedInterfaces(), RemoteFrameToken(), nullptr));
client->Bind(frame, std::move(owned_client));
if (!security_origin)
security_origin = SecurityOrigin::CreateUniqueOpaque();
@@ -408,15 +307,46 @@ WebRemoteFrameImpl* CreateRemoteChild(
return frame;
}
-WebViewHelper::WebViewHelper()
+WebViewHelper::WebViewHelper(
+ CreateTestWebFrameWidgetCallback create_web_frame_callback)
: web_view_(nullptr),
agent_group_scheduler_(
blink::ThreadScheduler::Current()->CreateAgentGroupScheduler()),
- platform_(Platform::Current()) {}
+ platform_(Platform::Current()) {
+ CreateTestWebFrameWidgetCallback create_callback =
+ std::move(create_web_frame_callback);
+ if (!create_callback) {
+ create_callback =
+ base::BindRepeating(&WebViewHelper::CreateTestWebFrameWidget<>);
+ }
+ // Due to return type differences we need to bind the RepeatingCallback
+ // in a wrapper.
+ create_widget_callback_wrapper_ = base::BindRepeating(
+ [](const CreateTestWebFrameWidgetCallback& create_test_web_widget,
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<
+ mojom::blink::FrameWidgetInterfaceBase> frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id, bool hidden,
+ bool never_composited, bool is_for_child_local_root,
+ bool is_for_nested_main_frame) -> WebFrameWidget* {
+ return create_test_web_widget.Run(
+ std::move(pass_key), std::move(frame_widget_host),
+ std::move(frame_widget), std::move(widget_host), std::move(widget),
+ std::move(task_runner), frame_sink_id, hidden, never_composited,
+ is_for_child_local_root, is_for_nested_main_frame);
+ },
+ std::move(create_callback));
+}
WebViewHelper::~WebViewHelper() {
- // Close the WebViewImpl before the WebViewClient/WebWidgetClient are
- // destroyed.
+ // Close the WebViewImpl before the WebViewClient is destroyed.
Reset();
}
@@ -424,7 +354,6 @@ WebViewImpl* WebViewHelper::InitializeWithOpener(
WebFrame* opener,
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
- TestWebWidgetClient* web_widget_client,
void (*update_settings_func)(WebSettings*)) {
Reset();
@@ -435,86 +364,48 @@ WebViewImpl* WebViewHelper::InitializeWithOpener(
std::unique_ptr<TestWebFrameClient> owned_web_frame_client;
web_frame_client =
CreateDefaultClientIfNeeded(web_frame_client, owned_web_frame_client);
+ MockPolicyContainerHost mock_policy_container_host;
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
- web_view_, web_frame_client, nullptr, base::UnguessableToken::Create(),
- std::make_unique<WebPolicyContainer>(WebPolicyContainerDocumentPolicies(),
- mojo::NullAssociatedRemote()),
+ web_view_, web_frame_client, nullptr, LocalFrameToken(),
+ std::make_unique<WebPolicyContainer>(
+ WebPolicyContainerPolicies(),
+ mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote()),
opener);
web_frame_client->Bind(frame, std::move(owned_web_frame_client));
- test_web_widget_client_ = CreateDefaultClientIfNeeded(
- web_widget_client, owned_test_web_widget_client_);
-
- mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
- frame_widget_receiver =
- frame_widget.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
- mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
- frame_widget_host_receiver =
- frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
-
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
- widget_remote.BindNewEndpointAndPassDedicatedReceiver();
-
- // TODO(dcheng): The main frame widget currently has a special case.
- // Eliminate this once WebView is no longer a WebWidget.
- WebFrameWidget* widget = blink::WebFrameWidget::CreateForMainFrame(
- test_web_widget_client_, frame, frame_widget_host.Unbind(),
- std::move(frame_widget_receiver),
- test_web_widget_client_->BindNewWidgetHost(), std::move(widget_receiver),
- AllocateFrameSinkId());
- // The WebWidget requires the compositor to be set before it is used.
- test_web_widget_client_->SetFrameWidget(widget, std::move(widget_remote));
- cc::LayerTreeSettings layer_tree_settings =
- GetSynchronousSingleThreadLayerTreeSettings();
- test_web_widget_client_->set_layer_tree_host(widget->InitializeCompositing(
- test_web_widget_client_->main_thread_scheduler(),
- test_web_widget_client_->task_graph_runner(), true,
- test_web_widget_client_->GetInitialScreenInfo(),
- std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings));
- widget->SetCompositorVisible(true);
+ TestWebFrameWidget* frame_widget =
+ CreateFrameWidgetAndInitializeCompositing(frame);
// We inform the WebView when it has a local main frame attached once the
- // WebFrame it fully set up and the WebWidgetClient is initialized (which is
+ // WebFrame is fully set up and the WebFrameWidget is initialized (which is
// the case by this point).
web_view_->DidAttachLocalMainFrame();
- static_cast<WebFrameWidgetBase*>(widget)->UpdateScreenInfo(
- test_web_widget_client_->GetInitialScreenInfo());
-
// Set an initial size for subframes.
if (frame->Parent())
- frame->FrameWidget()->Resize(gfx::Size());
-
+ frame_widget->Resize(gfx::Size());
return web_view_;
}
WebViewImpl* WebViewHelper::Initialize(
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
- TestWebWidgetClient* web_widget_client,
void (*update_settings_func)(WebSettings*)) {
return InitializeWithOpener(nullptr, web_frame_client, web_view_client,
- web_widget_client, update_settings_func);
+ update_settings_func);
}
WebViewImpl* WebViewHelper::InitializeWithSettings(
void (*update_settings_func)(WebSettings*)) {
- return InitializeWithOpener(nullptr, nullptr, nullptr, nullptr,
- update_settings_func);
+ return InitializeWithOpener(nullptr, nullptr, nullptr, update_settings_func);
}
WebViewImpl* WebViewHelper::InitializeAndLoad(
const std::string& url,
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
- TestWebWidgetClient* web_widget_client,
void (*update_settings_func)(WebSettings*)) {
- Initialize(web_frame_client, web_view_client, web_widget_client,
- update_settings_func);
+ Initialize(web_frame_client, web_view_client, update_settings_func);
LoadFrame(GetWebView()->MainFrameImpl(), url);
@@ -524,18 +415,16 @@ WebViewImpl* WebViewHelper::InitializeAndLoad(
WebViewImpl* WebViewHelper::InitializeRemote(
TestWebRemoteFrameClient* client,
scoped_refptr<SecurityOrigin> security_origin,
- TestWebViewClient* web_view_client,
- TestWebWidgetClient* web_widget_client) {
+ TestWebViewClient* web_view_client) {
return InitializeRemoteWithOpener(nullptr, client, security_origin,
- web_view_client, web_widget_client);
+ web_view_client);
}
WebViewImpl* WebViewHelper::InitializeRemoteWithOpener(
WebFrame* opener,
TestWebRemoteFrameClient* web_remote_frame_client,
scoped_refptr<SecurityOrigin> security_origin,
- TestWebViewClient* web_view_client,
- TestWebWidgetClient* web_widget_client) {
+ TestWebViewClient* web_view_client) {
Reset();
InitializeWebView(web_view_client, nullptr);
@@ -547,18 +436,115 @@ WebViewImpl* WebViewHelper::InitializeRemoteWithOpener(
web_view_, web_remote_frame_client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
web_remote_frame_client->GetRemoteAssociatedInterfaces(),
- base::UnguessableToken::Create(), opener);
+ RemoteFrameToken(), opener);
web_remote_frame_client->Bind(frame,
std::move(owned_web_remote_frame_client));
if (!security_origin)
security_origin = SecurityOrigin::CreateUniqueOpaque();
frame->GetFrame()->SetReplicatedOrigin(std::move(security_origin), false);
-
- test_web_widget_client_ = CreateDefaultClientIfNeeded(
- web_widget_client, owned_test_web_widget_client_);
return web_view_;
}
+void WebViewHelper::CheckFrameIsAssociatedWithWebView(WebFrame* frame) {
+ // Find the main frame and assert that it is the same.
+ while (frame->Parent()) {
+ frame = frame->Parent();
+ }
+ CHECK_EQ(web_view_->MainFrame(), frame);
+}
+
+WebLocalFrameImpl* WebViewHelper::CreateLocalChild(
+ WebRemoteFrame& parent,
+ const WebString& name,
+ const WebFrameOwnerProperties& properties,
+ WebFrame* previous_sibling,
+ TestWebFrameClient* client) {
+ CheckFrameIsAssociatedWithWebView(&parent);
+ std::unique_ptr<TestWebFrameClient> owned_client;
+ client = CreateDefaultClientIfNeeded(client, owned_client);
+ auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
+ mojom::blink::TreeScopeType::kDocument, name, FramePolicy(), client,
+ nullptr, previous_sibling, properties,
+ mojom::blink::FrameOwnerElementType::kIframe, LocalFrameToken(), nullptr,
+ std::make_unique<WebPolicyContainer>(WebPolicyContainerPolicies(),
+ mojo::NullAssociatedRemote())));
+ client->Bind(frame, std::move(owned_client));
+
+ TestWebFrameWidget* frame_widget =
+ CreateFrameWidgetAndInitializeCompositing(frame);
+ // Set an initial size for subframes.
+ frame_widget->Resize(gfx::Size());
+ return frame;
+}
+
+WebLocalFrameImpl* WebViewHelper::CreateProvisional(
+ WebFrame& old_frame,
+ TestWebFrameClient* client) {
+ CheckFrameIsAssociatedWithWebView(&old_frame);
+ std::unique_ptr<TestWebFrameClient> owned_client;
+ client = CreateDefaultClientIfNeeded(client, owned_client);
+ auto* frame = To<WebLocalFrameImpl>(WebLocalFrame::CreateProvisional(
+ client, nullptr, LocalFrameToken(), &old_frame, FramePolicy(),
+ WebFrame::ToCoreFrame(old_frame)->Tree().GetName()));
+ client->Bind(frame, std::move(owned_client));
+
+ // Create a widget, if necessary.
+ if (!frame->Parent() || frame->Parent()->IsWebRemoteFrame()) {
+ TestWebFrameWidget* frame_widget =
+ CreateFrameWidgetAndInitializeCompositing(frame);
+ // Set an initial size for subframes.
+ if (frame->Parent())
+ frame_widget->Resize(gfx::Size());
+ }
+ return frame;
+}
+
+TestWebFrameWidget* WebViewHelper::CreateFrameWidget(WebLocalFrame* frame) {
+ ScopedCreateWebFrameWidget create_hook(&create_widget_callback_wrapper_);
+ mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget_remote;
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
+ frame_widget_receiver =
+ frame_widget_remote.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
+ frame_widget_host_receiver =
+ frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
+ mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
+ widget_remote.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<mojom::blink::WidgetHost> widget_host;
+ mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>
+ widget_host_receiver =
+ widget_host.BindNewEndpointAndPassDedicatedReceiver();
+
+ auto* frame_widget =
+ static_cast<TestWebFrameWidget*>(frame->InitializeFrameWidget(
+ frame_widget_host.Unbind(), std::move(frame_widget_receiver),
+ widget_host.Unbind(), std::move(widget_receiver),
+ AllocateFrameSinkId()));
+ frame_widget->BindWidgetChannels(std::move(widget_remote),
+ std::move(widget_host_receiver),
+ std::move(frame_widget_host_receiver));
+ return frame_widget;
+}
+
+TestWebFrameWidget* WebViewHelper::CreateFrameWidgetAndInitializeCompositing(
+ WebLocalFrame* frame) {
+ TestWebFrameWidget* frame_widget = CreateFrameWidget(frame);
+ // The WebWidget requires the compositor to be set before it is used.
+ cc::LayerTreeSettings layer_tree_settings =
+ GetSynchronousSingleThreadLayerTreeSettings();
+ frame_widget->InitializeCompositing(
+ frame_widget->GetAgentGroupScheduler(), frame_widget->task_graph_runner(),
+ frame_widget->GetInitialScreenInfo(),
+ std::make_unique<cc::TestUkmRecorderFactory>(), &layer_tree_settings);
+ frame_widget->SetCompositorVisible(true);
+ return frame_widget;
+}
+
void WebViewHelper::LoadAhem() {
LocalFrame* local_frame =
To<LocalFrame>(WebFrame::ToCoreFrame(*LocalMainFrame()));
@@ -581,6 +567,10 @@ void WebViewHelper::Reset() {
test_web_view_client_ = nullptr;
}
+cc::LayerTreeHost* WebViewHelper::GetLayerTreeHost() const {
+ return GetMainFrameWidget()->LayerTreeHostForTesting();
+}
+
WebLocalFrameImpl* WebViewHelper::LocalMainFrame() const {
return To<WebLocalFrameImpl>(web_view_->MainFrame());
}
@@ -589,8 +579,12 @@ WebRemoteFrameImpl* WebViewHelper::RemoteMainFrame() const {
return To<WebRemoteFrameImpl>(web_view_->MainFrame());
}
+TestWebFrameWidget* WebViewHelper::GetMainFrameWidget() const {
+ return static_cast<TestWebFrameWidget*>(LocalMainFrame()->FrameWidgetImpl());
+}
+
void WebViewHelper::Resize(const gfx::Size& size) {
- GetWebView()->Resize(size);
+ GetWebView()->MainFrameWidget()->Resize(size);
}
void WebViewHelper::InitializeWebView(TestWebViewClient* web_view_client,
@@ -644,32 +638,25 @@ void TestWebFrameClient::Bind(WebLocalFrame* frame,
self_owned_ = std::move(self_owned);
}
-void TestWebFrameClient::BindWidgetClient(
- std::unique_ptr<WebWidgetClient> client) {
- DCHECK(!owned_widget_client_);
- owned_widget_client_ = std::move(client);
-}
-
void TestWebFrameClient::FrameDetached() {
- if (frame_->FrameWidget())
- frame_->FrameWidget()->Close();
-
- owned_widget_client_.reset();
frame_->Close();
self_owned_.reset();
}
WebLocalFrame* TestWebFrameClient::CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties& frame_owner_properties,
- mojom::blink::FrameOwnerElementType owner_type) {
- return CreateLocalChild(*parent, scope);
+ mojom::blink::FrameOwnerElementType owner_type,
+ WebPolicyContainerBindParams policy_container_bind_params) {
+ return CreateLocalChild(*frame_, scope, /*test_web_frame_client=*/nullptr,
+ std::move(policy_container_bind_params));
}
+void TestWebFrameClient::InitializeAsChildFrame(WebLocalFrame* parent) {}
+
void TestWebFrameClient::DidStartLoading() {
++loads_in_progress_;
}
@@ -679,6 +666,15 @@ void TestWebFrameClient::DidStopLoading() {
--loads_in_progress_;
}
+bool TestWebFrameClient::SwapIn(WebFrame* previous_frame) {
+ bool result = previous_frame->Swap(frame_);
+
+ if (!frame_->Parent())
+ frame_->View()->DidAttachLocalMainFrame();
+
+ return result;
+}
+
void TestWebFrameClient::BeginNavigation(
std::unique_ptr<WebNavigationInfo> info) {
navigation_callback_.Cancel();
@@ -767,88 +763,125 @@ void TestWebRemoteFrameClient::FrameDetached(DetachType type) {
self_owned_.reset();
}
-TestWebWidgetClient::TestWebWidgetClient() = default;
-
-void TestWebWidgetClient::SetFrameWidget(
- WebFrameWidget* widget,
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote) {
- frame_widget_ = widget;
-
- mojo::Remote<mojom::blink::WidgetInputHandler> input_handler;
- widget_remote->GetWidgetInputHandler(
- input_handler.BindNewPipeAndPassReceiver(),
- GetInputHandlerHost()->BindNewRemote());
-}
-
-TestWidgetInputHandlerHost* TestWebWidgetClient::GetInputHandlerHost() {
+TestWidgetInputHandlerHost* TestWebFrameWidget::GetInputHandlerHost() {
if (!widget_input_handler_host_)
widget_input_handler_host_ = std::make_unique<TestWidgetInputHandlerHost>();
return widget_input_handler_host_.get();
}
-ScreenInfo TestWebWidgetClient::GetInitialScreenInfo() {
+ScreenInfo TestWebFrameWidget::GetInitialScreenInfo() {
return ScreenInfo();
}
-cc::FakeLayerTreeFrameSink* TestWebWidgetClient::LastCreatedFrameSink() {
- DCHECK(layer_tree_host_->IsSingleThreaded());
+cc::FakeLayerTreeFrameSink* TestWebFrameWidget::LastCreatedFrameSink() {
+ DCHECK(LayerTreeHostForTesting()->IsSingleThreaded());
return last_created_frame_sink_;
}
-mojo::PendingAssociatedRemote<mojom::blink::WidgetHost>
-TestWebWidgetClient::BindNewWidgetHost() {
- receiver_.reset();
- return receiver_.BindNewEndpointAndPassDedicatedRemote();
+std::unique_ptr<TestWebFrameWidgetHost> TestWebFrameWidget::CreateWidgetHost() {
+ return std::make_unique<TestWebFrameWidgetHost>();
}
-bool TestWebWidgetClient::HaveScrollEventHandlers() const {
- return layer_tree_host()->have_scroll_event_handlers();
+void TestWebFrameWidget::BindWidgetChannels(
+ mojo::AssociatedRemote<mojom::blink::Widget> widget_remote,
+ mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost> receiver,
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
+ frame_receiver) {
+ widget_host_ = CreateWidgetHost();
+ widget_host_->BindWidgetHost(std::move(receiver), std::move(frame_receiver));
+ mojo::Remote<mojom::blink::WidgetInputHandler> input_handler;
+ widget_remote->GetWidgetInputHandler(
+ input_handler.BindNewPipeAndPassReceiver(),
+ GetInputHandlerHost()->BindNewRemote());
+}
+
+bool TestWebFrameWidget::HaveScrollEventHandlers() const {
+ return LayerTreeHostForTesting()->have_scroll_event_handlers();
}
std::unique_ptr<cc::LayerTreeFrameSink>
-TestWebWidgetClient::AllocateNewLayerTreeFrameSink() {
+TestWebFrameWidget::AllocateNewLayerTreeFrameSink() {
std::unique_ptr<cc::FakeLayerTreeFrameSink> sink =
cc::FakeLayerTreeFrameSink::Create3d();
last_created_frame_sink_ = sink.get();
return sink;
}
-void TestWebWidgetClient::WillQueueSyntheticEvent(
+void TestWebFrameWidget::WillQueueSyntheticEvent(
const WebCoalescedInputEvent& event) {
injected_scroll_events_.push_back(
std::make_unique<WebCoalescedInputEvent>(event));
}
-void TestWebWidgetClient::SetCursor(const ui::Cursor& cursor) {
+void TestWebFrameWidgetHost::SetCursor(const ui::Cursor& cursor) {
cursor_set_count_++;
}
-void TestWebWidgetClient::SetToolTipText(
+void TestWebFrameWidgetHost::SetToolTipText(
const String& tooltip_text,
base::i18n::TextDirection text_direction_hint) {}
-void TestWebWidgetClient::TextInputStateChanged(
- ui::mojom::blink::TextInputStatePtr state) {}
+void TestWebFrameWidgetHost::TextInputStateChanged(
+ ui::mojom::blink::TextInputStatePtr state) {
+ if (state->show_ime_if_needed)
+ ++virtual_keyboard_request_count_;
+}
-void TestWebWidgetClient::SelectionBoundsChanged(
+void TestWebFrameWidgetHost::SelectionBoundsChanged(
const gfx::Rect& anchor_rect,
base::i18n::TextDirection anchor_dir,
const gfx::Rect& focus_rect,
base::i18n::TextDirection focus_dir,
bool is_anchor_first) {}
-void TestWebWidgetClient::CreateFrameSink(
+void TestWebFrameWidgetHost::CreateFrameSink(
mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSink>
compositor_frame_sink_receiver,
mojo::PendingRemote<viz::mojom::blink::CompositorFrameSinkClient>
compositor_frame_sink_client) {}
-void TestWebWidgetClient::RegisterRenderFrameMetadataObserver(
+void TestWebFrameWidgetHost::RegisterRenderFrameMetadataObserver(
mojo::PendingReceiver<cc::mojom::blink::RenderFrameMetadataObserverClient>
render_frame_metadata_observer_client_receiver,
mojo::PendingRemote<cc::mojom::blink::RenderFrameMetadataObserver>
render_frame_metadata_observer) {}
+void TestWebFrameWidgetHost::AnimateDoubleTapZoomInMainFrame(
+ const gfx::Point& tap_point,
+ const gfx::Rect& rect_to_zoom) {}
+
+void TestWebFrameWidgetHost::ZoomToFindInPageRectInMainFrame(
+ const gfx::Rect& rect_to_zoom) {}
+
+void TestWebFrameWidgetHost::SetHasTouchEventConsumers(
+ mojom::blink::TouchEventConsumersPtr consumers) {}
+
+void TestWebFrameWidgetHost::IntrinsicSizingInfoChanged(
+ mojom::blink::IntrinsicSizingInfoPtr sizing_info) {}
+
+void TestWebFrameWidgetHost::AutoscrollStart(const gfx::PointF& position) {}
+
+void TestWebFrameWidgetHost::AutoscrollFling(const gfx::Vector2dF& position) {}
+
+void TestWebFrameWidgetHost::AutoscrollEnd() {}
+
+void TestWebFrameWidgetHost::DidFirstVisuallyNonEmptyPaint() {}
+
+void TestWebFrameWidgetHost::StartDragging(
+ const blink::WebDragData& drag_data,
+ blink::DragOperationsMask operations_allowed,
+ const SkBitmap& bitmap,
+ const gfx::Vector2d& bitmap_offset_in_dip,
+ mojom::blink::DragEventSourceInfoPtr event_info) {}
+
+void TestWebFrameWidgetHost::BindWidgetHost(
+ mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost> receiver,
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
+ frame_receiver) {
+ receiver_.Bind(std::move(receiver));
+ frame_receiver_.Bind(std::move(frame_receiver));
+}
+
void TestWebViewClient::DestroyChildViews() {
child_web_views_.clear();
}
@@ -859,9 +892,9 @@ WebView* TestWebViewClient::CreateView(WebLocalFrame* opener,
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) {
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) {
auto webview_helper = std::make_unique<WebViewHelper>();
WebView* result = webview_helper->InitializeWithOpener(opener);
child_web_views_.push_back(std::move(webview_helper));
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
index 222830df594..dd8ce4ea2eb 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -64,7 +64,7 @@
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h"
#include "third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h"
@@ -106,7 +106,6 @@ class WebSettings;
namespace frame_test_helpers {
class TestWebFrameClient;
class TestWebRemoteFrameClient;
-class TestWebWidgetClient;
class TestWebViewClient;
class TestWidgetInputHandlerHost;
class WebViewHelper;
@@ -150,21 +149,20 @@ WebMouseEvent CreateMouseEvent(WebInputEvent::Type,
// ensuring that non-null clients outlive the created frame.
// Helper for creating a local child frame of a local parent frame.
-WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
- blink::mojom::blink::TreeScopeType,
- TestWebFrameClient* = nullptr);
+WebLocalFrameImpl* CreateLocalChild(
+ WebLocalFrame& parent,
+ blink::mojom::blink::TreeScopeType,
+ TestWebFrameClient*,
+ WebPolicyContainerBindParams policy_container_bind_params);
// Similar, but unlike the overload which takes the client as a raw pointer,
// ownership of the TestWebFrameClient is transferred to the test framework.
// TestWebFrameClient may not be null.
-WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
- blink::mojom::blink::TreeScopeType,
- std::unique_ptr<TestWebFrameClient>);
-
-// Helper for creating a provisional local frame that can replace a remote
-// frame.
-WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame,
- TestWebFrameClient* = nullptr);
+WebLocalFrameImpl* CreateLocalChild(
+ WebLocalFrame& parent,
+ blink::mojom::blink::TreeScopeType,
+ std::unique_ptr<TestWebFrameClient>,
+ WebPolicyContainerBindParams policy_container_bind_params);
// Helper for creating a remote frame. Generally used when creating a remote
// frame to swap into the frame tree.
@@ -172,40 +170,81 @@ WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame,
// frame tree moves back to core.
WebRemoteFrameImpl* CreateRemote(TestWebRemoteFrameClient* = nullptr);
-// Helper for creating a local child frame of a remote parent frame.
-WebLocalFrameImpl* CreateLocalChild(
- WebRemoteFrame& parent,
- const WebString& name = WebString(),
- const WebFrameOwnerProperties& = WebFrameOwnerProperties(),
- WebFrame* previous_sibling = nullptr,
- TestWebFrameClient* = nullptr,
- TestWebWidgetClient* = nullptr);
-
// Helper for creating a remote child frame of a remote parent frame.
WebRemoteFrameImpl* CreateRemoteChild(WebRemoteFrame& parent,
const WebString& name = WebString(),
scoped_refptr<SecurityOrigin> = nullptr,
TestWebRemoteFrameClient* = nullptr);
-class TestWebWidgetClient : public WebWidgetClient,
- public mojom::blink::WidgetHost {
+class TestWebFrameWidgetHost : public mojom::blink::WidgetHost,
+ public mojom::blink::FrameWidgetHost {
public:
- TestWebWidgetClient();
- ~TestWebWidgetClient() override = default;
+ size_t CursorSetCount() const { return cursor_set_count_; }
+ size_t VirtualKeyboardRequestCount() const {
+ return virtual_keyboard_request_count_;
+ }
+
+ // mojom::blink::WidgetHost overrides:
+ void SetCursor(const ui::Cursor& cursor) override;
+ void SetToolTipText(const String& tooltip_text,
+ base::i18n::TextDirection text_direction_hint) override;
+ void TextInputStateChanged(
+ ui::mojom::blink::TextInputStatePtr state) override;
+ void SelectionBoundsChanged(const gfx::Rect& anchor_rect,
+ base::i18n::TextDirection anchor_dir,
+ const gfx::Rect& focus_rect,
+ base::i18n::TextDirection focus_dir,
+ bool is_anchor_first) override;
+ void CreateFrameSink(
+ mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSink>
+ compositor_frame_sink_receiver,
+ mojo::PendingRemote<viz::mojom::blink::CompositorFrameSinkClient>
+ compositor_frame_sink_client) override;
+ void RegisterRenderFrameMetadataObserver(
+ mojo::PendingReceiver<cc::mojom::blink::RenderFrameMetadataObserverClient>
+ render_frame_metadata_observer_client_receiver,
+ mojo::PendingRemote<cc::mojom::blink::RenderFrameMetadataObserver>
+ render_frame_metadata_observer) override;
- // This method must be called just after the allocation of |widget| and
- // before usage of this class occurs.
- void SetFrameWidget(
- WebFrameWidget* widget,
- mojo::AssociatedRemote<mojom::blink::Widget> widget_remote);
+ // blink::mojom::FrameWidgetHost overrides.
+ void AnimateDoubleTapZoomInMainFrame(const gfx::Point& tap_point,
+ const gfx::Rect& rect_to_zoom) override;
+ void ZoomToFindInPageRectInMainFrame(const gfx::Rect& rect_to_zoom) override;
+ void SetHasTouchEventConsumers(
+ mojom::blink::TouchEventConsumersPtr consumers) override;
+ void IntrinsicSizingInfoChanged(
+ mojom::blink::IntrinsicSizingInfoPtr sizing_info) override;
+ void AutoscrollStart(const gfx::PointF& position) override;
+ void AutoscrollFling(const gfx::Vector2dF& position) override;
+ void AutoscrollEnd() override;
+ void DidFirstVisuallyNonEmptyPaint() override;
+ void StartDragging(const blink::WebDragData& drag_data,
+ blink::DragOperationsMask operations_allowed,
+ const SkBitmap& bitmap,
+ const gfx::Vector2d& bitmap_offset_in_dip,
+ mojom::blink::DragEventSourceInfoPtr event_info) override;
+
+ void BindWidgetHost(
+ mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>,
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>);
- cc::LayerTreeHost* layer_tree_host() { return layer_tree_host_; }
- const cc::LayerTreeHost* layer_tree_host() const { return layer_tree_host_; }
+ private:
+ size_t cursor_set_count_ = 0;
+ size_t virtual_keyboard_request_count_ = 0;
+ mojo::AssociatedReceiver<mojom::blink::WidgetHost> receiver_{this};
+ mojo::AssociatedReceiver<mojom::blink::FrameWidgetHost> frame_receiver_{this};
+};
- bool AnimationScheduled() const { return animation_scheduled_; }
- void ClearAnimationScheduled() { animation_scheduled_ = false; }
+class TestWebFrameWidget : public WebFrameWidgetImpl {
+ public:
+ template <typename... Args>
+ explicit TestWebFrameWidget(Args&&... args)
+ : WebFrameWidgetImpl(std::forward<Args>(args)...) {
+ agent_group_scheduler_ = fake_thread_scheduler_.CreateAgentGroupScheduler();
+ }
+ ~TestWebFrameWidget() override = default;
- size_t CursorSetCount() const { return cursor_set_count_; }
+ TestWebFrameWidgetHost& WidgetHost() { return *widget_host_; }
bool HaveScrollEventHandlers() const;
const Vector<std::unique_ptr<blink::WebCoalescedInputEvent>>&
@@ -219,8 +258,8 @@ class TestWebWidgetClient : public WebWidgetClient,
return &fake_thread_scheduler_;
}
- void set_layer_tree_host(cc::LayerTreeHost* layer_tree_host) {
- layer_tree_host_ = layer_tree_host;
+ blink::scheduler::WebAgentGroupScheduler& GetAgentGroupScheduler() {
+ return *agent_group_scheduler_;
}
// The returned pointer is valid after AllocateNewLayerTreeFrameSink() occurs,
@@ -230,15 +269,20 @@ class TestWebWidgetClient : public WebWidgetClient,
cc::FakeLayerTreeFrameSink* LastCreatedFrameSink();
virtual ScreenInfo GetInitialScreenInfo();
+ virtual std::unique_ptr<TestWebFrameWidgetHost> CreateWidgetHost();
- mojo::PendingAssociatedRemote<mojom::blink::WidgetHost> BindNewWidgetHost();
+ void BindWidgetChannels(
+ mojo::AssociatedRemote<mojom::blink::Widget>,
+ mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>,
+ mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>);
+
+ using WebFrameWidgetImpl::GetOriginalScreenInfo;
protected:
// Allow subclasses to provide their own input handler host.
virtual TestWidgetInputHandlerHost* GetInputHandlerHost();
- // WebWidgetClient overrides;
- void ScheduleAnimation() override { animation_scheduled_ = true; }
+ // WidgetBaseClient overrides.
std::unique_ptr<cc::LayerTreeFrameSink> AllocateNewLayerTreeFrameSink()
override;
void WillQueueSyntheticEvent(const WebCoalescedInputEvent& event) override;
@@ -246,41 +290,17 @@ class TestWebWidgetClient : public WebWidgetClient,
return false;
}
- // mojom::blink::WidgetHost overrides:
- void SetCursor(const ui::Cursor& cursor) override;
- void SetToolTipText(const String& tooltip_text,
- base::i18n::TextDirection text_direction_hint) override;
- void TextInputStateChanged(
- ui::mojom::blink::TextInputStatePtr state) override;
- void SelectionBoundsChanged(const gfx::Rect& anchor_rect,
- base::i18n::TextDirection anchor_dir,
- const gfx::Rect& focus_rect,
- base::i18n::TextDirection focus_dir,
- bool is_anchor_first) override;
- void CreateFrameSink(
- mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSink>
- compositor_frame_sink_receiver,
- mojo::PendingRemote<viz::mojom::blink::CompositorFrameSinkClient>
- compositor_frame_sink_client) override;
- void RegisterRenderFrameMetadataObserver(
- mojo::PendingReceiver<cc::mojom::blink::RenderFrameMetadataObserverClient>
- render_frame_metadata_observer_client_receiver,
- mojo::PendingRemote<cc::mojom::blink::RenderFrameMetadataObserver>
- render_frame_metadata_observer) override;
-
private:
- WebFrameWidget* frame_widget_ = nullptr;
- cc::LayerTreeHost* layer_tree_host_ = nullptr;
cc::TestTaskGraphRunner test_task_graph_runner_;
cc::FakeLayerTreeFrameSink* last_created_frame_sink_ = nullptr;
blink::scheduler::WebFakeThreadScheduler fake_thread_scheduler_;
+ std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
+ agent_group_scheduler_;
Vector<std::unique_ptr<blink::WebCoalescedInputEvent>>
injected_scroll_events_;
std::unique_ptr<TestWidgetInputHandlerHost> widget_input_handler_host_;
- bool animation_scheduled_ = false;
- size_t cursor_set_count_ = 0;
viz::FrameSinkId frame_sink_id_;
- mojo::AssociatedReceiver<mojom::blink::WidgetHost> receiver_{this};
+ std::unique_ptr<TestWebFrameWidgetHost> widget_host_;
};
class TestWebViewClient : public WebViewClient {
@@ -291,7 +311,6 @@ class TestWebViewClient : public WebViewClient {
void DestroyChildViews();
// WebViewClient overrides.
- bool CanHandleGestureEvent() override { return true; }
bool CanUpdateLayout() override { return true; }
WebView* CreateView(WebLocalFrame* opener,
const WebURLRequest&,
@@ -299,21 +318,39 @@ class TestWebViewClient : public WebViewClient {
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) override;
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) override;
private:
WTF::Vector<std::unique_ptr<WebViewHelper>> child_web_views_;
};
+using CreateTestWebFrameWidgetCallback =
+ base::RepeatingCallback<TestWebFrameWidget*(
+ base::PassKey<WebLocalFrame>,
+ CrossVariantMojoAssociatedRemote<mojom::FrameWidgetHostInterfaceBase>
+ frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::WidgetInterfaceBase> widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame)>;
+
// Convenience class for handling the lifetime of a WebView and its associated
// mainframe in tests.
class WebViewHelper : public ScopedMockOverlayScrollbars {
USING_FAST_MALLOC(WebViewHelper);
public:
- WebViewHelper();
+ explicit WebViewHelper(CreateTestWebFrameWidgetCallback
+ create_web_frame_callback = base::NullCallback());
~WebViewHelper();
// Helpers for creating the main frame. All methods that accept raw
@@ -327,13 +364,11 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
WebFrame* opener,
TestWebFrameClient* = nullptr,
TestWebViewClient* = nullptr,
- TestWebWidgetClient* = nullptr,
void (*update_settings_func)(WebSettings*) = nullptr);
// Same as InitializeWithOpener(), but always sets the opener to null.
WebViewImpl* Initialize(TestWebFrameClient* = nullptr,
TestWebViewClient* = nullptr,
- TestWebWidgetClient* = nullptr,
void (*update_settings_func)(WebSettings*) = nullptr);
// Same as InitializeWithOpener(), but passes null for everything but the
@@ -347,14 +382,12 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
const std::string& url,
TestWebFrameClient* = nullptr,
TestWebViewClient* = nullptr,
- TestWebWidgetClient* = nullptr,
void (*update_settings_func)(WebSettings*) = nullptr);
// Same as InitializeRemoteWithOpener(), but always sets the opener to null.
WebViewImpl* InitializeRemote(TestWebRemoteFrameClient* = nullptr,
scoped_refptr<SecurityOrigin> = nullptr,
- TestWebViewClient* = nullptr,
- TestWebWidgetClient* = nullptr);
+ TestWebViewClient* = nullptr);
// Creates and initializes the WebView with a main WebRemoteFrame. Passing
// nullptr as the SecurityOrigin results in a frame with a unique security
@@ -363,8 +396,27 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
WebFrame* opener,
TestWebRemoteFrameClient* = nullptr,
scoped_refptr<SecurityOrigin> = nullptr,
- TestWebViewClient* = nullptr,
- TestWebWidgetClient* = nullptr);
+ TestWebViewClient* = nullptr);
+
+ // Helper for creating a local child frame of a remote parent frame.
+ WebLocalFrameImpl* CreateLocalChild(
+ WebRemoteFrame& parent,
+ const WebString& name = WebString(),
+ const WebFrameOwnerProperties& = WebFrameOwnerProperties(),
+ WebFrame* previous_sibling = nullptr,
+ TestWebFrameClient* = nullptr);
+
+ // Helper for creating a provisional local frame that can replace a local or
+ // remote frame.
+ WebLocalFrameImpl* CreateProvisional(WebFrame& old_frame,
+ TestWebFrameClient* = nullptr);
+
+ // Creates a frame widget but does not initialize compositing.
+ TestWebFrameWidget* CreateFrameWidget(WebLocalFrame* frame);
+
+ // Creates a frame widget and initializes compositing.
+ TestWebFrameWidget* CreateFrameWidgetAndInitializeCompositing(
+ WebLocalFrame* frame);
// Load the 'Ahem' font to this WebView.
// The 'Ahem' font is the only font whose font metrics is consistent across
@@ -377,15 +429,10 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
void Reset();
WebViewImpl* GetWebView() const { return web_view_; }
- cc::LayerTreeHost* GetLayerTreeHost() const {
- return test_web_widget_client_->layer_tree_host();
- }
- TestWebWidgetClient* GetWebWidgetClient() const {
- return test_web_widget_client_;
- }
-
+ cc::LayerTreeHost* GetLayerTreeHost() const;
WebLocalFrameImpl* LocalMainFrame() const;
WebRemoteFrameImpl* RemoteMainFrame() const;
+ TestWebFrameWidget* GetMainFrameWidget() const;
void set_viewport_enabled(bool viewport) {
DCHECK(!web_view_)
@@ -393,9 +440,38 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
viewport_enabled_ = viewport;
}
+ template <class C = TestWebFrameWidget>
+ static TestWebFrameWidget* CreateTestWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame) {
+ return MakeGarbageCollected<C>(
+ std::move(pass_key), std::move(frame_widget_host),
+ std::move(frame_widget), std::move(widget_host), std::move(widget),
+ std::move(task_runner), frame_sink_id, hidden, never_composited,
+ is_for_child_local_root, is_for_nested_main_frame);
+ }
+
+ blink::scheduler::WebAgentGroupScheduler& GetAgentGroupScheduler() {
+ return *agent_group_scheduler_;
+ }
+
private:
void InitializeWebView(TestWebViewClient*,
class WebView* opener);
+ void CheckFrameIsAssociatedWithWebView(WebFrame* frame);
bool viewport_enabled_ = false;
@@ -403,11 +479,10 @@ class WebViewHelper : public ScopedMockOverlayScrollbars {
std::unique_ptr<TestWebViewClient> owned_test_web_view_client_;
TestWebViewClient* test_web_view_client_ = nullptr;
- std::unique_ptr<TestWebWidgetClient> owned_test_web_widget_client_;
- TestWebWidgetClient* test_web_widget_client_ = nullptr;
std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
agent_group_scheduler_;
+ CreateWebFrameWidgetCallback create_widget_callback_wrapper_;
// The Platform should not change during the lifetime of the test!
Platform* const platform_;
@@ -431,20 +506,21 @@ class TestWebFrameClient : public WebLocalFrameClient {
// TestWebFrameClient should delete itself on frame detach.
void Bind(WebLocalFrame*,
std::unique_ptr<TestWebFrameClient> self_owned = nullptr);
- // Note: only needed for local roots.
- void BindWidgetClient(std::unique_ptr<WebWidgetClient>);
// WebLocalFrameClient:
void FrameDetached() override;
- WebLocalFrame* CreateChildFrame(WebLocalFrame* parent,
- blink::mojom::blink::TreeScopeType,
- const WebString& name,
- const WebString& fallback_name,
- const FramePolicy&,
- const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override;
+ WebLocalFrame* CreateChildFrame(
+ blink::mojom::blink::TreeScopeType,
+ const WebString& name,
+ const WebString& fallback_name,
+ const FramePolicy&,
+ const WebFrameOwnerProperties&,
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override;
+ void InitializeAsChildFrame(WebLocalFrame* parent) override;
void DidStartLoading() override;
void DidStopLoading() override;
+ bool SwapIn(WebFrame* previous_frame) override;
std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory()
override {
return std::make_unique<WebURLLoaderFactoryWithMock>(
@@ -488,7 +564,6 @@ class TestWebFrameClient : public WebLocalFrameClient {
WebNavigationControl* frame_ = nullptr;
base::CancelableOnceCallback<void()> navigation_callback_;
- std::unique_ptr<WebWidgetClient> owned_widget_client_;
WebEffectiveConnectionType effective_connection_type_;
Vector<String> console_messages_;
int visually_non_empty_layout_count_ = 0;
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_view.cc b/chromium/third_party/blink/renderer/core/frame/frame_view.cc
index 74da41ca624..e2dcf9909f6 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_view.cc
@@ -43,10 +43,15 @@ bool FrameView::CanThrottleRenderingForPropagation() const {
bool FrameView::DisplayLockedInParentFrame() {
Frame& frame = GetFrame();
LayoutEmbeddedContent* owner = frame.OwnerLayoutObject();
+ if (!owner)
+ return false;
+ DCHECK(owner->GetFrameView());
+ if (owner->GetFrameView()->IsDisplayLocked())
+ return true;
// We check the inclusive ancestor to determine whether the subtree is locked,
// since the contents of the frame are in the subtree of the frame, so they
// would be locked if the frame owner is itself locked.
- return owner && DisplayLockUtilities::NearestLockedInclusiveAncestor(*owner);
+ return DisplayLockUtilities::NearestLockedInclusiveAncestor(*owner);
}
void FrameView::UpdateViewportIntersection(unsigned flags,
@@ -212,7 +217,8 @@ void FrameView::UpdateViewportIntersection(unsigned flags,
subtree_throttled =
parent_frame->View()->CanThrottleRenderingForPropagation();
}
- UpdateRenderThrottlingStatus(hidden_for_throttling, subtree_throttled);
+ UpdateRenderThrottlingStatus(hidden_for_throttling, subtree_throttled,
+ DisplayLockedInParentFrame());
}
void FrameView::UpdateFrameVisibility(bool intersects_viewport) {
@@ -235,12 +241,14 @@ void FrameView::UpdateFrameVisibility(bool intersects_viewport) {
void FrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
bool subtree_throttled,
+ bool display_locked,
bool recurse) {
- bool visibility_changed = (hidden_for_throttling_ || subtree_throttled_) !=
- (hidden_for_throttling || subtree_throttled ||
- DisplayLockedInParentFrame());
+ bool visibility_changed =
+ (hidden_for_throttling_ || subtree_throttled_ || display_locked_) !=
+ (hidden_for_throttling || subtree_throttled || display_locked);
hidden_for_throttling_ = hidden_for_throttling;
- subtree_throttled_ = subtree_throttled || DisplayLockedInParentFrame();
+ subtree_throttled_ = subtree_throttled;
+ display_locked_ = display_locked;
if (visibility_changed)
VisibilityForThrottlingChanged();
if (recurse) {
@@ -250,7 +258,7 @@ void FrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
child_view->UpdateRenderThrottlingStatus(
child_view->IsHiddenForThrottling(),
child_view->IsAttached() && CanThrottleRenderingForPropagation(),
- true);
+ child_view->IsDisplayLocked(), true);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/frame_view.h b/chromium/third_party/blink/renderer/core/frame/frame_view.h
index 74b4d0e9f61..3d89323433e 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_view.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_view.h
@@ -50,8 +50,15 @@ class CORE_EXPORT FrameView : public EmbeddedContentView {
// lifecycle updates in the child frame will skip rendering work.
bool IsHiddenForThrottling() const { return hidden_for_throttling_; }
bool IsSubtreeThrottled() const { return subtree_throttled_; }
+ // This indicates whether this is an iframe whose contents are display-locked
+ // due to an active DisplayLock in the parent frame. Note that this value must
+ // be stable between main frames, and only gets updated based on the current
+ // state of display locking in the parent frame when
+ // UpdateViewportIntersection is run during post-lifecycle steps.
+ bool IsDisplayLocked() const { return display_locked_; }
virtual void UpdateRenderThrottlingStatus(bool hidden_for_throttling,
bool subtree_throttled,
+ bool display_locked,
bool recurse = false);
bool RectInParentIsStable(const base::TimeTicks& timestamp) const;
@@ -75,8 +82,9 @@ class CORE_EXPORT FrameView : public EmbeddedContentView {
PhysicalRect rect_in_parent_;
base::TimeTicks rect_in_parent_stable_since_;
blink::mojom::FrameVisibility frame_visibility_;
- bool hidden_for_throttling_;
- bool subtree_throttled_;
+ bool hidden_for_throttling_ = false;
+ bool subtree_throttled_ = false;
+ bool display_locked_ = false;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
index 89ab3d0d370..9ccc064435f 100644
--- a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
+++ b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.cc
@@ -50,6 +50,34 @@
namespace blink {
+namespace {
+
+mojom::blink::FullscreenOptionsPtr ToMojoOptions(
+ LocalFrame* frame,
+ const FullscreenOptions* options,
+ FullscreenRequestType request_type) {
+ auto fullscreen_options = mojom::blink::FullscreenOptions::New();
+ fullscreen_options->prefers_navigation_bar =
+ options->navigationUI() != "hide";
+ if (options->hasScreen()) {
+ DCHECK(RuntimeEnabledFeatures::WindowPlacementEnabled(frame->DomWindow()));
+ if (options->screen()->DisplayId() != Screen::kInvalidDisplayId)
+ fullscreen_options->display_id = options->screen()->DisplayId();
+ }
+
+ // Propagate the type of fullscreen request (prefixed or unprefixed) to
+ // OOPIF ancestor frames so that they fire matching prefixed or unprefixed
+ // fullscreen events.
+ fullscreen_options->is_prefixed =
+ request_type & FullscreenRequestType::kPrefixed;
+ fullscreen_options->is_xr_overlay =
+ request_type & FullscreenRequestType::kForXrOverlay;
+
+ return fullscreen_options;
+}
+
+} // namespace
+
FullscreenController::FullscreenController(WebViewImpl* web_view_base)
: web_view_base_(web_view_base),
pending_frames_(MakeGarbageCollected<PendingFullscreenSet>()) {}
@@ -147,22 +175,8 @@ void FullscreenController::EnterFullscreen(LocalFrame& frame,
return;
DCHECK(state_ == State::kInitial);
- auto fullscreen_options = mojom::blink::FullscreenOptions::New();
- fullscreen_options->prefers_navigation_bar =
- options->navigationUI() != "hide";
- if (options->hasScreen()) {
- DCHECK(RuntimeEnabledFeatures::WindowPlacementEnabled(frame.DomWindow()));
- if (options->screen()->DisplayId() != Screen::kInvalidDisplayId)
- fullscreen_options->display_id = options->screen()->DisplayId();
- }
- // Propagate the type of fullscreen request (prefixed or unprefixed) to
- // OOPIF ancestor frames so that they fire matching prefixed or unprefixed
- // fullscreen events.
- fullscreen_options->is_prefixed =
- request_type & FullscreenRequestType::kPrefixed;
- fullscreen_options->is_xr_overlay =
- request_type & FullscreenRequestType::kForXrOverlay;
+ auto fullscreen_options = ToMojoOptions(&frame, options, request_type);
#if DCHECK_IS_ON()
DVLOG(2) << __func__ << ": request_type="
@@ -198,8 +212,11 @@ void FullscreenController::ExitFullscreen(LocalFrame& frame) {
state_ = State::kExitingFullscreen;
}
-void FullscreenController::FullscreenElementChanged(Element* old_element,
- Element* new_element) {
+void FullscreenController::FullscreenElementChanged(
+ Element* old_element,
+ Element* new_element,
+ const FullscreenOptions* options,
+ FullscreenRequestType request_type) {
DCHECK_NE(old_element, new_element);
// We only override the WebView's background color for overlay fullscreen
@@ -231,8 +248,14 @@ void FullscreenController::FullscreenElementChanged(Element* old_element,
// Tell the browser the fullscreen state has changed.
if (Element* owner = new_element ? new_element : old_element) {
Document& doc = owner->GetDocument();
+ bool in_fullscreen = !!new_element;
if (LocalFrame* frame = doc.GetFrame()) {
- frame->GetLocalFrameHostRemote().FullscreenStateChanged(!!new_element);
+ mojom::blink::FullscreenOptionsPtr mojo_options;
+ if (in_fullscreen)
+ mojo_options = ToMojoOptions(frame, options, request_type);
+
+ frame->GetLocalFrameHostRemote().FullscreenStateChanged(
+ in_fullscreen, std::move(mojo_options));
if (IsSpatialNavigationEnabled(frame)) {
doc.GetPage()->GetSpatialNavigationController().FullscreenStateChanged(
new_element);
diff --git a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.h b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.h
index 243b7348dc8..8e6522665f7 100644
--- a/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.h
+++ b/chromium/third_party/blink/renderer/core/frame/fullscreen_controller.h
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/platform/geometry/float_point.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -73,7 +74,10 @@ class CORE_EXPORT FullscreenController {
// Called by Fullscreen (via ChromeClient) to notify that the fullscreen
// element has changed.
- void FullscreenElementChanged(Element* old_element, Element* new_element);
+ void FullscreenElementChanged(Element* old_element,
+ Element* new_element,
+ const FullscreenOptions*,
+ FullscreenRequestType request_type);
bool IsFullscreenOrTransitioning() const { return state_ != State::kInitial; }
diff --git a/chromium/third_party/blink/renderer/core/frame/history.cc b/chromium/third_party/blink/renderer/core/frame/history.cc
index 2db3ecfcf0c..1c0cc93ee1b 100644
--- a/chromium/third_party/blink/renderer/core/frame/history.cc
+++ b/chromium/third_party/blink/renderer/core/frame/history.cc
@@ -341,9 +341,8 @@ void History::StateObjectAdded(
return;
}
- DomWindow()->document()->Loader()->UpdateForSameDocumentNavigation(
- full_url, kSameDocumentNavigationHistoryApi, std::move(data),
- restoration_type, type, DomWindow()->document());
+ DomWindow()->document()->Loader()->RunURLAndHistoryUpdateSteps(
+ full_url, std::move(data), restoration_type, type);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/impression_params.idl b/chromium/third_party/blink/renderer/core/frame/impression_params.idl
new file mode 100644
index 00000000000..3e25e357ab9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/impression_params.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.
+
+// An ImpressionParams object represents registration info for an impression for the Conversion Measurement API. These mirror the conversion measurement attributes exposed HTML anchor elements. See https://github.com/WICG/conversion-measurement-api/blob/master/README.md for more information.
+dictionary ImpressionParams {
+ required DOMString impressionData;
+ required USVString conversionDestination;
+ USVString reportingOrigin;
+ unsigned long long impressionExpiry;
+};
diff --git a/chromium/third_party/blink/renderer/core/frame/intervention.cc b/chromium/third_party/blink/renderer/core/frame/intervention.cc
index 3cd1a539d59..e3f1c7d41d2 100644
--- a/chromium/third_party/blink/renderer/core/frame/intervention.cc
+++ b/chromium/third_party/blink/renderer/core/frame/intervention.cc
@@ -19,7 +19,7 @@
namespace blink {
// static
-void Intervention::GenerateReport(const LocalFrame* frame,
+void Intervention::GenerateReport(LocalFrame* frame,
const String& id,
const String& message) {
if (!frame || !frame->Client())
diff --git a/chromium/third_party/blink/renderer/core/frame/intervention.h b/chromium/third_party/blink/renderer/core/frame/intervention.h
index 8089995d989..7e8858bb5c6 100644
--- a/chromium/third_party/blink/renderer/core/frame/intervention.h
+++ b/chromium/third_party/blink/renderer/core/frame/intervention.h
@@ -23,7 +23,7 @@ class CORE_EXPORT Intervention {
// Generates a intervention report, to be routed to the Reporting API and any
// ReportingObservers. Also sends the intervention message to the console.
- static void GenerateReport(const LocalFrame*,
+ static void GenerateReport(LocalFrame*,
const String& id,
const String& message);
diff --git a/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc b/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
index 1b7d52acbd1..664fd015bc9 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -30,8 +30,10 @@
#include <utility>
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
#include "cc/input/snap_selection_strategy.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/action_after_pagehide.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/features.h"
@@ -45,6 +47,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_impression_params.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_to_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
#include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
@@ -72,7 +75,6 @@
#include "third_party/blink/renderer/core/events/hash_change_event.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/events/pop_state_event.h"
-#include "third_party/blink/renderer/core/execution_context/agent_metrics_collector.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/execution_context/window_agent.h"
#include "third_party/blink/renderer/core/frame/bar_prop.h"
@@ -94,6 +96,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/html/conversion_measurement_parsing.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
@@ -135,6 +138,31 @@
namespace blink {
+namespace {
+
+constexpr size_t kMaxPostMessageUkmRecordedSourceIdsSize = 20;
+
+bool ShouldRecordPostMessageIncomingFrameUkmEvent(
+ ukm::SourceId source_frame_ukm_source_id,
+ Deque<ukm::SourceId>& already_recorded_source_frame_ids) {
+ DCHECK_LE(already_recorded_source_frame_ids.size(),
+ kMaxPostMessageUkmRecordedSourceIdsSize);
+
+ if (base::Contains(already_recorded_source_frame_ids,
+ source_frame_ukm_source_id)) {
+ return false;
+ }
+
+ if (already_recorded_source_frame_ids.size() ==
+ kMaxPostMessageUkmRecordedSourceIdsSize) {
+ already_recorded_source_frame_ids.pop_back();
+ }
+ already_recorded_source_frame_ids.push_front(source_frame_ukm_source_id);
+ return true;
+}
+
+} // namespace
+
LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent)
: DOMWindow(frame),
ExecutionContext(V8PerIsolateData::MainThreadIsolate(), agent),
@@ -152,7 +180,7 @@ LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent)
isolated_world_csp_map_(
MakeGarbageCollected<
HeapHashMap<int, Member<ContentSecurityPolicy>>>()),
- token_(LocalFrameToken(frame.GetFrameToken())) {}
+ token_(frame.GetLocalFrameToken()) {}
void LocalDOMWindow::BindContentSecurityPolicy() {
DCHECK(!GetContentSecurityPolicy()->IsBound());
@@ -162,18 +190,12 @@ void LocalDOMWindow::BindContentSecurityPolicy() {
void LocalDOMWindow::Initialize() {
GetAgent()->AttachContext(this);
- if (auto* agent_metrics = GetFrame()->GetPage()->GetAgentMetricsCollector())
- agent_metrics->DidAttachWindow(*this);
}
void LocalDOMWindow::ResetWindowAgent(WindowAgent* agent) {
GetAgent()->DetachContext(this);
- if (auto* agent_metrics = GetFrame()->GetPage()->GetAgentMetricsCollector())
- agent_metrics->DidDetachWindow(*this);
ResetAgent(agent);
GetAgent()->AttachContext(this);
- if (auto* agent_metrics = GetFrame()->GetPage()->GetAgentMetricsCollector())
- agent_metrics->DidAttachWindow(*this);
}
void LocalDOMWindow::AcceptLanguagesChanged() {
@@ -190,15 +212,6 @@ ScriptValue LocalDOMWindow::event(ScriptState* script_state) {
ToV8(ToV8UndefinedGenerator(), script_state));
}
- // Track usage of window.event when the event's target is inside V0 shadow
- // tree.
- if (current_event_->target()) {
- Node* target_node = current_event_->target()->ToNode();
- if (target_node && target_node->IsInV0ShadowTree()) {
- UseCounter::Count(this, WebFeature::kWindowEventInV0ShadowTree);
- }
- }
-
return ScriptValue(script_state->GetIsolate(),
ToV8(CurrentEvent(), script_state));
}
@@ -211,12 +224,22 @@ void LocalDOMWindow::SetCurrentEvent(Event* new_event) {
current_event_ = new_event;
}
-TrustedTypePolicyFactory* LocalDOMWindow::trustedTypes() const {
- if (!trusted_types_) {
- trusted_types_ =
- MakeGarbageCollected<TrustedTypePolicyFactory>(GetExecutionContext());
- }
- return trusted_types_.Get();
+TrustedTypePolicyFactory* LocalDOMWindow::GetTrustedTypesForWorld(
+ const DOMWrapperWorld& world) const {
+ DCHECK(world.IsMainWorld() || world.IsIsolatedWorld());
+ DCHECK(IsMainThread());
+ auto iter = trusted_types_map_.find(&world);
+ if (iter != trusted_types_map_.end())
+ return iter->value;
+ return trusted_types_map_
+ .insert(&world, MakeGarbageCollected<TrustedTypePolicyFactory>(
+ GetExecutionContext()))
+ .stored_value->value;
+}
+
+TrustedTypePolicyFactory* LocalDOMWindow::trustedTypes(
+ ScriptState* script_state) const {
+ return GetTrustedTypesForWorld(script_state->World());
}
bool LocalDOMWindow::IsCrossSiteSubframe() const {
@@ -238,6 +261,15 @@ LocalDOMWindow* LocalDOMWindow::From(const ScriptState* script_state) {
return blink::ToLocalDOMWindow(script_state->GetContext());
}
+mojom::blink::V8CacheOptions LocalDOMWindow::GetV8CacheOptions() const {
+ if (LocalFrame* frame = GetFrame()) {
+ if (const Settings* settings = frame->GetSettings())
+ return settings->GetV8CacheOptions();
+ }
+
+ return mojom::blink::V8CacheOptions::kDefault;
+}
+
bool LocalDOMWindow::IsContextThread() const {
return IsMainThread();
}
@@ -285,6 +317,11 @@ String LocalDOMWindow::UserAgent() const {
return GetFrame() ? GetFrame()->Loader().UserAgent() : String();
}
+UserAgentMetadata LocalDOMWindow::GetUserAgentMetadata() const {
+ return GetFrame()->Loader().UserAgentMetadata().value_or(
+ blink::UserAgentMetadata());
+}
+
HttpsState LocalDOMWindow::GetHttpsState() const {
// TODO(https://crbug.com/880986): Implement Document's HTTPS state in more
// spec-conformant way.
@@ -380,25 +417,12 @@ network::mojom::ReferrerPolicy LocalDOMWindow::GetReferrerPolicy() const {
return frame->DomWindow()->GetReferrerPolicy();
}
-network::mojom::blink::ReferrerPolicy
-LocalDOMWindow::ReferrerPolicyButForMetaTagsWithListsOfPolicies() const {
- network::mojom::ReferrerPolicy policy =
- ExecutionContext::ReferrerPolicyButForMetaTagsWithListsOfPolicies();
- // For srcdoc documents without their own policy, walk up the frame tree
- // analogously to when getting the referrer policy.
- if (!GetFrame() || policy != network::mojom::ReferrerPolicy::kDefault ||
- !document()->IsSrcdocDocument()) {
- return policy;
- }
- LocalFrame* frame = To<LocalFrame>(GetFrame()->Tree().Parent());
- return frame->DomWindow()->ReferrerPolicyButForMetaTagsWithListsOfPolicies();
-}
-
CoreProbeSink* LocalDOMWindow::GetProbeSink() {
return probe::ToCoreProbeSink(GetFrame());
}
-BrowserInterfaceBrokerProxy& LocalDOMWindow::GetBrowserInterfaceBroker() {
+const BrowserInterfaceBrokerProxy& LocalDOMWindow::GetBrowserInterfaceBroker()
+ const {
if (!GetFrame())
return GetEmptyBrowserInterfaceBroker();
@@ -611,25 +635,36 @@ bool LocalDOMWindow::HasInsecureContextInAncestors() {
}
Document* LocalDOMWindow::InstallNewDocument(const DocumentInit& init) {
- DCHECK_EQ(init.GetWindow(), this);
+ // Blink should never attempt to install a new Document to a LocalDOMWindow
+ // that's not attached to a LocalFrame.
+ DCHECK(GetFrame());
+ // Either:
+ // - `this` should be a new LocalDOMWindow, that has never had a Document
+ // associated with it or
+ // - `this` is being reused, and the previous Document has been disassociated
+ // via `ClearForReuse()`.
DCHECK(!document_);
+ DCHECK_EQ(init.GetWindow(), this);
+
document_ = init.CreateDocument();
document_->Initialize();
- if (!GetFrame())
- return document_;
-
GetScriptController().UpdateDocument();
document_->GetViewportData().UpdateViewportDescription();
- if (FrameScheduler* frame_scheduler = GetFrame()->GetFrameScheduler()) {
- frame_scheduler->TraceUrlChange(document_->Url().GetString());
- frame_scheduler->SetCrossOriginToMainFrame(
- GetFrame()->IsCrossOriginToMainFrame());
- }
- if (GetFrame()->GetPage() && GetFrame()->View()) {
- GetFrame()->GetPage()->GetChromeClient().InstallSupplements(*GetFrame());
+ auto* frame_scheduler = GetFrame()->GetFrameScheduler();
+ frame_scheduler->TraceUrlChange(document_->Url().GetString());
+ frame_scheduler->SetCrossOriginToMainFrame(
+ GetFrame()->IsCrossOriginToMainFrame());
+
+ GetFrame()->GetPage()->GetChromeClient().InstallSupplements(*GetFrame());
+
+#if !defined(OS_ANDROID)
+ // Enable SharedArrayBuffer for the reverse Origin Trial.
+ if (RuntimeEnabledFeatures::UnrestrictedSharedArrayBufferEnabled(this)) {
+ v8::V8::SetIsCrossOriginIsolated();
}
+#endif
return document_;
}
@@ -792,8 +827,6 @@ void LocalDOMWindow::FrameDestroyed() {
document()->Shutdown();
document()->RemoveAllEventListenersRecursively();
GetAgent()->DetachContext(this);
- if (auto* agent_metrics = GetFrame()->GetPage()->GetAgentMetricsCollector())
- agent_metrics->DidDetachWindow(*this);
NotifyContextDestroyed();
RemoveAllEventListeners();
MainThreadDebugger::Instance()->DidClearContextsForFrame(GetFrame());
@@ -821,7 +854,7 @@ void LocalDOMWindow::Reset() {
media_ = nullptr;
custom_elements_ = nullptr;
application_cache_ = nullptr;
- trusted_types_ = nullptr;
+ trusted_types_map_.clear();
}
void LocalDOMWindow::SendOrientationChangeEvent() {
@@ -944,6 +977,15 @@ void LocalDOMWindow::SchedulePostMessage(
MessageEvent* event,
scoped_refptr<const SecurityOrigin> target,
LocalDOMWindow* source) {
+ // Record UKM metrics for postMessage event.
+ ukm::SourceId source_frame_ukm_source_id = source->UkmSourceID();
+ if (ShouldRecordPostMessageIncomingFrameUkmEvent(
+ source_frame_ukm_source_id, post_message_ukm_recorded_source_ids_)) {
+ ukm::builders::PostMessage_Incoming_Frame(UkmSourceID())
+ .SetSourceFrameSourceId(source_frame_ukm_source_id)
+ .Record(UkmRecorder());
+ }
+
// Allowing unbounded amounts of messages to build up for a suspended context
// is problematic; consider imposing a limit or other restriction if this
// surfaces often as a problem (see crbug.com/587012).
@@ -1069,14 +1111,8 @@ Element* LocalDOMWindow::frameElement() const {
void LocalDOMWindow::blur() {}
void LocalDOMWindow::print(ScriptState* script_state) {
- // Don't print after detach begins, even if GetFrame() hasn't been nulled out
- // yet.
- // TODO(crbug.com/1063150): When a frame is being detached for a swap, the
- // document has already been Shutdown() and is no longer in a consistent
- // state, even though GetFrame() is not yet nulled out. This is an ordering
- // violation, and checking whether we're in the middle of detach here is
- // probably not the right long-term fix.
- if (!GetFrame() || !GetFrame()->IsAttached())
+ // Don't try to print if there's no frame attached anymore.
+ if (!GetFrame())
return;
if (script_state &&
@@ -1393,7 +1429,7 @@ HeapVector<Member<DOMRect>> LocalDOMWindow::getWindowSegments() const {
if (!page)
return window_segments;
- WebVector<WebRect> web_segments =
+ WebVector<gfx::Rect> web_segments =
frame->GetWidgetForLocalRoot()->WindowSegments();
// The rect passed to us from content is in DIP, relative to the main
@@ -1409,7 +1445,7 @@ HeapVector<Member<DOMRect>> LocalDOMWindow::getWindowSegments() const {
const float page_zoom_factor = frame->PageZoomFactor();
const float scale_factor = window_to_viewport_factor / page_zoom_factor;
for (auto const& web_segment : web_segments) {
- blink::FloatQuad quad = blink::FloatQuad(web_segment);
+ blink::FloatQuad quad = blink::FloatQuad(IntRect(web_segment));
quad.Scale(scale_factor, scale_factor);
window_segments.push_back(DOMRect::FromFloatRect(quad.BoundingBox()));
}
@@ -1696,8 +1732,8 @@ void LocalDOMWindow::SetOriginPolicyIds(const Vector<String>& ids) {
origin_policy_ids_ = ids;
}
-bool LocalDOMWindow::originIsolated() const {
- return GetAgent()->IsOriginIsolated();
+bool LocalDOMWindow::originAgentCluster() const {
+ return GetAgent()->IsOriginKeyed();
}
int LocalDOMWindow::requestIdleCallback(V8IdleRequestCallback* callback,
@@ -1919,6 +1955,42 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
const AtomicString& target,
const String& features,
ExceptionState& exception_state) {
+ return open(isolate, url_string, target, features,
+ nullptr /* impression_params */, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
+ const String& url_string,
+ const AtomicString& target,
+ const String& features,
+ bool unused,
+ ExceptionState& exception_state) {
+ UseCounter::Count(this, WebFeature::kWindowOpenWithAdditionalBoolParameter);
+
+ PrintErrorMessage(
+ "A boolean is being passed as a fourth parameter to "
+ "window.open. This is not used and may cause an "
+ "exception in a future release.");
+
+ // Ignore the unused bool argument.
+ return open(isolate, url_string, target, features,
+ nullptr /* impression_params */, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
+ const String& url_string,
+ const AtomicString& target,
+ const String& features,
+ const ImpressionParams* impression_params,
+ ExceptionState& exception_state) {
+ if (!RuntimeEnabledFeatures::ConversionMeasurementEnabled(this)) {
+ // The usage of `impression_params` is gated on a runtime enabled feature
+ // in the implementation rather than in the IDL definition, because the
+ // RuntimeEnabled extended attribute cannot be used with an operation
+ // overload.
+ impression_params = nullptr;
+ }
+
LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate);
LocalDOMWindow* entered_window = EnteredDOMWindow(isolate);
@@ -1974,10 +2046,17 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
frame_request.GetResourceRequest().SetReferrerPolicy(
referrer.referrer_policy);
- frame_request.GetResourceRequest().SetHasUserGesture(
- LocalFrame::HasTransientUserActivation(GetFrame()));
+ bool has_user_gesture = LocalFrame::HasTransientUserActivation(GetFrame());
+ frame_request.GetResourceRequest().SetHasUserGesture(has_user_gesture);
GetFrame()->MaybeLogAdClickNavigation();
+ if (has_user_gesture && impression_params) {
+ base::Optional<WebImpression> impression =
+ GetImpressionForParams(incumbent_window, impression_params);
+ if (impression)
+ frame_request.SetImpression(*impression);
+ }
+
FrameTree::FindResult result =
GetFrame()->Tree().FindOrCreateFrameForNavigation(
frame_request, target.IsEmpty() ? "_blank" : target);
@@ -2043,7 +2122,7 @@ void LocalDOMWindow::Trace(Visitor* visitor) const {
visitor->Trace(visualViewport_);
visitor->Trace(event_listener_observers_);
visitor->Trace(current_event_);
- visitor->Trace(trusted_types_);
+ visitor->Trace(trusted_types_map_);
visitor->Trace(input_method_controller_);
visitor->Trace(spell_checker_);
visitor->Trace(text_suggestion_controller_);
diff --git a/chromium/third_party/blink/renderer/core/frame/local_dom_window.h b/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
index 07101cfe0d2..290467577c8 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -64,6 +64,7 @@ class External;
class FrameConsole;
class History;
class IdleRequestOptions;
+class ImpressionParams;
class MediaQueryList;
class MessageEvent;
class Modulator;
@@ -128,6 +129,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
void ResetWindowAgent(WindowAgent*);
+ mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
+
// Bind Content Security Policy to this window. This will cause the
// CSP to resolve the 'self' attribute and all policies will then be
// applied to this document.
@@ -146,6 +149,7 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
KURL CompleteURL(const String&) const final;
void DisableEval(const String& error_message) final;
String UserAgent() const final;
+ UserAgentMetadata GetUserAgentMetadata() const final;
HttpsState GetHttpsState() const final;
ResourceFetcher* Fetcher() const final;
bool CanExecuteScripts(ReasonForCallingCanExecuteScripts) final;
@@ -154,14 +158,12 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
EventTarget* ErrorEventTarget() final { return this; }
String OutgoingReferrer() const final;
network::mojom::ReferrerPolicy GetReferrerPolicy() const final;
- network::mojom::blink::ReferrerPolicy
- ReferrerPolicyButForMetaTagsWithListsOfPolicies() const final;
CoreProbeSink* GetProbeSink() final;
- BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() final;
+ const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() const final;
FrameOrWorkerScheduler* GetScheduler() final;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) final;
TrustedTypePolicyFactory* GetTrustedTypes() const final {
- return trustedTypes();
+ return GetTrustedTypesForWorld(*GetCurrentWorld());
}
ScriptWrappable* ToScriptWrappable() final { return this; }
void CountPotentialFeaturePolicyViolation(
@@ -308,8 +310,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
const Vector<String>& originPolicyIds() const;
void SetOriginPolicyIds(const Vector<String>&);
- // https://github.com/whatwg/html/pull/5545
- bool originIsolated() const;
+ // https://html.spec.whatwg.org/C/#dom-originagentcluster
+ bool originAgentCluster() const;
// Idle callback extensions
int requestIdleCallback(V8IdleRequestCallback*, const IdleRequestOptions*);
@@ -346,6 +348,20 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
const String& features,
ExceptionState&);
+ DOMWindow* open(v8::Isolate*,
+ const String& url_string,
+ const AtomicString& target,
+ const String& features,
+ bool unused,
+ ExceptionState&);
+
+ DOMWindow* open(v8::Isolate*,
+ const String& url_string,
+ const AtomicString& target,
+ const String& features,
+ const ImpressionParams* impression_params,
+ ExceptionState&);
+
FrameConsole* GetFrameConsole() const;
void PrintErrorMessage(const String&) const;
@@ -391,7 +407,9 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
Event* CurrentEvent() const;
void SetCurrentEvent(Event*);
- TrustedTypePolicyFactory* trustedTypes() const;
+ TrustedTypePolicyFactory* trustedTypes(ScriptState*) const;
+ TrustedTypePolicyFactory* GetTrustedTypesForWorld(
+ const DOMWrapperWorld&) const;
// Returns true if this window is cross-site to the main frame. Defaults to
// false in a detached window.
@@ -484,7 +502,10 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
// We represent the "undefined" value as nullptr.
Member<Event> current_event_;
- mutable Member<TrustedTypePolicyFactory> trusted_types_;
+ // Store TrustedTypesPolicyFactory, per DOMWrapperWorld.
+ mutable HeapHashMap<scoped_refptr<const DOMWrapperWorld>,
+ Member<TrustedTypePolicyFactory>>
+ trusted_types_map_;
// A dummy scheduler to return when the window is detached.
// All operations on it result in no-op, but due to this it's safe to
@@ -517,6 +538,13 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
// this document, to avoid reporting duplicates. The value stored comes
// from |DocumentPolicyViolationReport::MatchId()|.
mutable HashSet<unsigned> document_policy_violation_reports_sent_;
+
+ // A list of the most recently recorded source frame UKM source IDs for the
+ // PostMessage.Incoming.Frame UKM event, in order to partially deduplicate
+ // logged events. Its size is limited to 20. See SchedulePostMessage() where
+ // this UKM is logged.
+ // TODO(crbug.com/1112491): Remove when no longer needed.
+ Deque<ukm::SourceId> post_message_ukm_recorded_source_ids_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/frame/local_dom_window_test.cc b/chromium/third_party/blink/renderer/core/frame/local_dom_window_test.cc
index 81af6269a09..78601512ff7 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_dom_window_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_dom_window_test.cc
@@ -33,6 +33,7 @@
#include "base/strings/stringprintf.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/loader/referrer_utils.h"
#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
#include "third_party/blink/renderer/core/execution_context/agent.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
@@ -67,7 +68,7 @@ TEST_F(LocalDOMWindowTest, referrerPolicyParsing) {
struct TestCase {
const char* policy;
network::mojom::ReferrerPolicy expected;
- bool is_legacy;
+ bool uses_legacy_tokens;
} tests[] = {
{"", network::mojom::ReferrerPolicy::kDefault, false},
// Test that invalid policy values are ignored.
@@ -80,12 +81,12 @@ TEST_F(LocalDOMWindowTest, referrerPolicyParsing) {
false},
// Test parsing each of the policy values.
{"always", network::mojom::ReferrerPolicy::kAlways, true},
- {"default", network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade,
+ {"default",
+ ReferrerUtils::MojoReferrerPolicyResolveDefault(
+ network::mojom::ReferrerPolicy::kDefault),
true},
{"never", network::mojom::ReferrerPolicy::kNever, true},
{"no-referrer", network::mojom::ReferrerPolicy::kNever, false},
- {"default", network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade,
- true},
{"no-referrer-when-downgrade",
network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade, false},
{"origin", network::mojom::ReferrerPolicy::kOrigin, false},
@@ -100,22 +101,51 @@ TEST_F(LocalDOMWindowTest, referrerPolicyParsing) {
{"unsafe-url", network::mojom::ReferrerPolicy::kAlways},
};
- for (auto test : tests) {
+ for (const auto test : tests) {
window->SetReferrerPolicy(network::mojom::ReferrerPolicy::kDefault);
- if (test.is_legacy) {
- // Legacy keyword support must be explicitly enabled for the policy to
- // parse successfully.
- window->ParseAndSetReferrerPolicy(test.policy);
+ if (test.uses_legacy_tokens) {
+ // Legacy tokens are supported only for meta-specified policy.
+ window->ParseAndSetReferrerPolicy(test.policy, kPolicySourceHttpHeader);
EXPECT_EQ(network::mojom::ReferrerPolicy::kDefault,
window->GetReferrerPolicy());
- window->ParseAndSetReferrerPolicy(test.policy, true);
+ window->ParseAndSetReferrerPolicy(test.policy, kPolicySourceMetaTag);
} else {
- window->ParseAndSetReferrerPolicy(test.policy);
+ window->ParseAndSetReferrerPolicy(test.policy, kPolicySourceHttpHeader);
}
EXPECT_EQ(test.expected, window->GetReferrerPolicy()) << test.policy;
}
}
+TEST_F(LocalDOMWindowTest, referrerPolicyParsingWithCommas) {
+ LocalDOMWindow* window = GetFrame().DomWindow();
+ EXPECT_EQ(network::mojom::ReferrerPolicy::kDefault,
+ window->GetReferrerPolicy());
+
+ struct TestCase {
+ const char* policy;
+ network::mojom::ReferrerPolicy expected;
+ } tests[] = {
+ {"same-origin,strict-origin",
+ network::mojom::ReferrerPolicy::kStrictOrigin},
+ {"same-origin,not-a-real-policy,strict-origin",
+ network::mojom::ReferrerPolicy::kStrictOrigin},
+ {"strict-origin, same-origin, not-a-real-policy",
+ network::mojom::ReferrerPolicy::kSameOrigin},
+ };
+
+ for (const auto test : tests) {
+ window->SetReferrerPolicy(network::mojom::ReferrerPolicy::kDefault);
+ // Policies containing commas are ignored when specified by a Meta element.
+ window->ParseAndSetReferrerPolicy(test.policy, kPolicySourceMetaTag);
+ EXPECT_EQ(network::mojom::ReferrerPolicy::kDefault,
+ window->GetReferrerPolicy());
+
+ // Header-specified policy permits commas and returns the last valid policy.
+ window->ParseAndSetReferrerPolicy(test.policy, kPolicySourceHttpHeader);
+ EXPECT_EQ(test.expected, window->GetReferrerPolicy()) << test.policy;
+ }
+}
+
TEST_F(LocalDOMWindowTest, OutgoingReferrer) {
NavigateTo(KURL("https://www.example.com/hoge#fuga?piyo"));
EXPECT_EQ("https://www.example.com/hoge",
@@ -144,28 +174,40 @@ TEST_F(LocalDOMWindowTest, EnforceSandboxFlags) {
// A unique origin does not bypass secure context checks unless it
// is also potentially trustworthy.
- url::ScopedSchemeRegistryForTests scoped_registry;
- url::AddStandardScheme("very-special-scheme", url::SCHEME_WITH_HOST);
- SchemeRegistry::RegisterURLSchemeBypassingSecureContextCheck(
- "very-special-scheme");
- NavigateTo(KURL("very-special-scheme://example.test"),
- {{http_names::kContentSecurityPolicy, "sandbox"}});
- EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
- EXPECT_FALSE(
- GetFrame().DomWindow()->GetSecurityOrigin()->IsPotentiallyTrustworthy());
+ {
+ url::ScopedSchemeRegistryForTests scoped_registry;
+ url::AddStandardScheme("very-special-scheme", url::SCHEME_WITH_HOST);
+ SchemeRegistry::RegisterURLSchemeBypassingSecureContextCheck(
+ "very-special-scheme");
+ NavigateTo(KURL("very-special-scheme://example.test"),
+ {{http_names::kContentSecurityPolicy, "sandbox"}});
+ EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
+ EXPECT_FALSE(GetFrame()
+ .DomWindow()
+ ->GetSecurityOrigin()
+ ->IsPotentiallyTrustworthy());
+ }
- SchemeRegistry::RegisterURLSchemeAsSecure("very-special-scheme");
- NavigateTo(KURL("very-special-scheme://example.test"),
- {{http_names::kContentSecurityPolicy, "sandbox"}});
- EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
- EXPECT_TRUE(
- GetFrame().DomWindow()->GetSecurityOrigin()->IsPotentiallyTrustworthy());
+ {
+ url::ScopedSchemeRegistryForTests scoped_registry;
+ url::AddStandardScheme("very-special-scheme", url::SCHEME_WITH_HOST);
+ url::AddSecureScheme("very-special-scheme");
+ NavigateTo(KURL("very-special-scheme://example.test"),
+ {{http_names::kContentSecurityPolicy, "sandbox"}});
+ EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
+ EXPECT_TRUE(GetFrame()
+ .DomWindow()
+ ->GetSecurityOrigin()
+ ->IsPotentiallyTrustworthy());
- NavigateTo(KURL("https://example.test"),
- {{http_names::kContentSecurityPolicy, "sandbox"}});
- EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
- EXPECT_TRUE(
- GetFrame().DomWindow()->GetSecurityOrigin()->IsPotentiallyTrustworthy());
+ NavigateTo(KURL("https://example.test"),
+ {{http_names::kContentSecurityPolicy, "sandbox"}});
+ EXPECT_TRUE(GetFrame().DomWindow()->GetSecurityOrigin()->IsOpaque());
+ EXPECT_TRUE(GetFrame()
+ .DomWindow()
+ ->GetSecurityOrigin()
+ ->IsPotentiallyTrustworthy());
+ }
}
// Tests ExecutionContext::GetContentSecurityPolicyForCurrentWorld().
@@ -175,8 +217,11 @@ TEST_F(PageTestBase, CSPForWorld) {
// Set a CSP for the main world.
const char* kMainWorldCSP = "connect-src https://google.com;";
GetFrame().DomWindow()->GetContentSecurityPolicy()->DidReceiveHeader(
- kMainWorldCSP, ContentSecurityPolicyType::kEnforce,
- ContentSecurityPolicySource::kHTTP);
+ kMainWorldCSP, *(GetFrame().DomWindow()->GetSecurityOrigin()),
+ ContentSecurityPolicyType::kEnforce, ContentSecurityPolicySource::kHTTP);
+ const Vector<
+ network::mojom::blink::ContentSecurityPolicyPtr>& parsed_main_world_csp =
+ GetFrame().DomWindow()->GetContentSecurityPolicy()->GetParsedPolicies();
LocalFrame* frame = &GetFrame();
ScriptState* main_world_script_state = ToScriptStateForMainWorld(frame);
@@ -201,18 +246,17 @@ TEST_F(PageTestBase, CSPForWorld) {
SecurityOrigin::Create(KURL("chrome-extension://123")));
// Returns the csp headers being used for the current world.
- auto get_csp_headers = [this]() {
+ auto get_csp = [this]()
+ -> const Vector<network::mojom::blink::ContentSecurityPolicyPtr>& {
auto* csp =
GetFrame().DomWindow()->GetContentSecurityPolicyForCurrentWorld();
- return csp->Headers();
+ return csp->GetParsedPolicies();
};
{
SCOPED_TRACE("In main world.");
ScriptState::Scope scope(main_world_script_state);
- EXPECT_THAT(get_csp_headers(),
- ElementsAre(CSPHeaderAndType(
- {kMainWorldCSP, ContentSecurityPolicyType::kEnforce})));
+ EXPECT_EQ(get_csp(), parsed_main_world_csp);
}
{
@@ -221,18 +265,14 @@ TEST_F(PageTestBase, CSPForWorld) {
// If we are in an isolated world with no CSP defined, we use the main world
// CSP.
- EXPECT_THAT(get_csp_headers(),
- ElementsAre(CSPHeaderAndType(
- {kMainWorldCSP, ContentSecurityPolicyType::kEnforce})));
+ EXPECT_EQ(get_csp(), parsed_main_world_csp);
}
{
SCOPED_TRACE("In isolated world with csp.");
ScriptState::Scope scope(isolated_world_with_csp_script_state);
// We use the isolated world's CSP if it specified one.
- EXPECT_THAT(get_csp_headers(),
- ElementsAre(CSPHeaderAndType(
- {kIsolatedWorldCSP, ContentSecurityPolicyType::kEnforce})));
+ EXPECT_EQ(get_csp()[0]->header->header_value, kIsolatedWorldCSP);
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.cc b/chromium/third_party/blink/renderer/core/frame/local_frame.cc
index 8e787861212..74d1e79e332 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame.cc
@@ -75,6 +75,7 @@
#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
#include "third_party/blink/renderer/core/core_initializer.h"
#include "third_party/blink/renderer/core/core_probe_sink.h"
+#include "third_party/blink/renderer/core/css/background_color_paint_image_generator.h"
#include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/child_frame_disconnector.h"
@@ -119,8 +120,9 @@
#include "third_party/blink/renderer/core/frame/user_activation.h"
#include "third_party/blink/renderer/core/frame/virtual_keyboard_overlay_changed_observer.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
@@ -163,6 +165,7 @@
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
@@ -216,6 +219,56 @@ static LocalFramesByTokenMap& GetLocalFramesMap() {
// Maximum number of burst download requests allowed.
const int kBurstDownloadLimit = 10;
+// Maximum number of bytes that can be buffered in total (per-process) by all
+// network requests in one renderer process while in back-forward cache.
+constexpr size_t kDefaultMaxBufferedBodyBytesPerProcess = 512 * 1000;
+
+// Singleton utility class for process-wide back-forward cache buffer limit
+// tracking.
+class BackForwardCacheBufferLimitTracker {
+ public:
+ BackForwardCacheBufferLimitTracker()
+ : max_buffered_bytes_per_process_(
+ blink::GetLoadingTasksUnfreezableParamAsInt(
+ "max_buffered_bytes_per_process",
+ kDefaultMaxBufferedBodyBytesPerProcess)) {}
+
+ BackForwardCacheBufferLimitTracker(BackForwardCacheBufferLimitTracker&) =
+ delete;
+
+ void DidBufferBytes(size_t num_bytes) {
+ total_bytes_buffered_ += num_bytes;
+ TRACE_EVENT2(
+ "loading", "BackForwardCacheBufferLimitTracker::DidBufferBytes",
+ "total_bytes_buffered", static_cast<int>(total_bytes_buffered_),
+ "added_bytes", static_cast<int>(num_bytes));
+ }
+
+ void DidRemoveFrameFromBackForwardCache(size_t frame_total_bytes) {
+ total_bytes_buffered_ -= frame_total_bytes;
+ TRACE_EVENT2("loading",
+ "BackForwardCacheBufferLimitTracker::"
+ "DidRemoveFrameFromBackForwardCache",
+ "total_bytes_buffered",
+ static_cast<int>(total_bytes_buffered_), "substracted_bytes",
+ static_cast<int>(frame_total_bytes));
+ }
+
+ bool IsUnderPerProcessBufferLimit() {
+ return total_bytes_buffered_ <= max_buffered_bytes_per_process_;
+ }
+
+ private:
+ const size_t max_buffered_bytes_per_process_;
+ size_t total_bytes_buffered_ = 0;
+};
+
+BackForwardCacheBufferLimitTracker& GetBackForwardCacheBufferLimitTracker() {
+ static base::NoDestructor<BackForwardCacheBufferLimitTracker>
+ back_forward_cache_buffer_limit_tracker;
+ return *back_forward_cache_buffer_limit_tracker;
+}
+
inline float ParentPageZoomFactor(LocalFrame* frame) {
auto* parent_local_frame = DynamicTo<LocalFrame>(frame->Tree().Parent());
return parent_local_frame ? parent_local_frame->PageZoomFactor() : 1;
@@ -259,7 +312,7 @@ HitTestResult HitTestResultForRootFramePos(
}
RemoteFrame* SourceFrameForOptionalToken(
- const base::Optional<base::UnguessableToken>& source_frame_token) {
+ const base::Optional<RemoteFrameToken>& source_frame_token) {
if (!source_frame_token)
return nullptr;
return RemoteFrame::FromFrameToken(source_frame_token.value());
@@ -373,18 +426,12 @@ class ActiveURLMessageFilter : public mojo::MessageFilter {
template class CORE_TEMPLATE_EXPORT Supplement<LocalFrame>;
// static
-LocalFrame* LocalFrame::FromFrameToken(
- const base::UnguessableToken& frame_token) {
+LocalFrame* LocalFrame::FromFrameToken(const LocalFrameToken& frame_token) {
LocalFramesByTokenMap& local_frames_map = GetLocalFramesMap();
- auto it = local_frames_map.find(base::UnguessableTokenHash()(frame_token));
+ auto it = local_frames_map.find(LocalFrameToken::Hasher()(frame_token));
return it == local_frames_map.end() ? nullptr : it->value.Get();
}
-// static
-LocalFrame* LocalFrame::FromFrameToken(const LocalFrameToken& frame_token) {
- return FromFrameToken(frame_token.value());
-}
-
void LocalFrame::Init(Frame* opener) {
CoreInitializer::GetInstance().InitLocalFrame(*this);
@@ -400,6 +447,9 @@ void LocalFrame::Init(Frame* opener) {
WTF::BindRepeating(&LocalFrame::BindToHighPriorityReceiver,
WrapWeakPersistent(this)),
GetTaskRunner(blink::TaskType::kInternalHighPriorityLocalFrame));
+ GetInterfaceRegistry()->AddAssociatedInterface(
+ WTF::BindRepeating(&LocalFrame::BindFullscreenVideoElementReceiver,
+ WrapWeakPersistent(this)));
if (IsMainFrame()) {
GetInterfaceRegistry()->AddInterface(
@@ -504,8 +554,10 @@ void LocalFrame::Trace(Visitor* visitor) const {
visitor->Trace(receiver_);
visitor->Trace(main_frame_receiver_);
visitor->Trace(high_priority_frame_receiver_);
+ visitor->Trace(fullscreen_video_receiver_);
visitor->Trace(text_fragment_selector_generator_);
visitor->Trace(saved_scroll_offsets_);
+ visitor->Trace(background_color_paint_image_generator_);
Frame::Trace(visitor);
Supplementable<LocalFrame>::Trace(visitor);
}
@@ -559,25 +611,22 @@ void LocalFrame::Navigate(FrameLoadRequest& request,
probe::FrameClearedScheduledNavigation(this);
}
-void LocalFrame::DetachImpl(FrameDetachType type) {
+bool LocalFrame::DetachImpl(FrameDetachType type) {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- // BEGIN RE-ENTRANCY SAFE BLOCK
- // Starting here, the code must be safe against re-entrancy. Dispatching
+ // BEGIN REENTRANCY SAFE BLOCK
+ // Starting here, the code must be safe against reentrancy. Dispatching
// events, et cetera can run Javascript, which can reenter Detach().
+ //
+ // Most cleanup code should *not* be in inside the reentrancy safe block.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- frame_color_overlay_.reset();
- if (IsLocalRoot()) {
- performance_monitor_->Shutdown();
- if (ad_tracker_)
- ad_tracker_->Shutdown();
+ if (IsProvisional()) {
+ Frame* provisional_owner = GetProvisionalOwnerFrame();
+ // Having multiple provisional frames somehow associated with the same frame
+ // to potentially replace is a logic error.
+ DCHECK_EQ(provisional_owner->ProvisionalFrame(), this);
+ provisional_owner->SetProvisionalFrame(nullptr);
}
- idleness_detector_->Shutdown();
- if (inspector_issue_reporter_)
- probe_sink_->RemoveInspectorIssueReporter(inspector_issue_reporter_);
- if (inspector_trace_events_)
- probe_sink_->RemoveInspectorTraceEvents(inspector_trace_events_);
- inspector_task_runner_->Dispose();
PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
// In a kSwap detach, if we have a navigation going, its moved to the frame
@@ -594,13 +643,13 @@ void LocalFrame::DetachImpl(FrameDetachType type) {
// both when unloading itself and when unloading its descendants.
IgnoreOpensDuringUnloadCountIncrementer ignore_opens_during_unload(
GetDocument());
- loader_.DispatchUnloadEvent(nullptr, nullptr);
- DetachChildren();
- // All done if detaching the subframes brought about a detach of this frame
- // also.
+ loader_.DispatchUnloadEvent(nullptr, nullptr);
if (!Client())
- return;
+ return false;
+
+ if (!DetachChildren())
+ return false;
// Detach() needs to be called after detachChildren(), because
// detachChildren() will trigger the unload event handlers of any child
@@ -609,11 +658,6 @@ void LocalFrame::DetachImpl(FrameDetachType type) {
loader_.Detach();
DomWindow()->FrameDestroyed();
- if (content_capture_manager_) {
- content_capture_manager_->Shutdown();
- content_capture_manager_ = nullptr;
- }
-
// Verify here that any LocalFrameView has been detached by now.
if (view_ && view_->IsAttached()) {
DCHECK(DeprecatedLocalOwner());
@@ -627,21 +671,45 @@ void LocalFrame::DetachImpl(FrameDetachType type) {
// - Document::Shutdown() can dispose plugins which can run script.
ScriptForbiddenScope forbid_script;
if (!Client())
- return;
+ return false;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- // END RE-ENTRANCY SAFE BLOCK
+ // END REENTRANCY SAFE BLOCK
// Past this point, no script should be executed. If this method was
- // re-entered, then check for a non-null Client() above should have already
- // returned.
+ // reentered, then a check for a null Client() above should have already
+ // returned false.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
DCHECK(!IsDetached());
+ frame_color_overlay_.reset();
+
+ if (IsLocalRoot()) {
+ performance_monitor_->Shutdown();
+ if (ad_tracker_)
+ ad_tracker_->Shutdown();
+ // Unregister only if this is LocalRoot because the paint_image_generator_
+ // was created on LocalRoot.
+ if (background_color_paint_image_generator_)
+ background_color_paint_image_generator_->Shutdown();
+ }
+ idleness_detector_->Shutdown();
+ if (inspector_issue_reporter_)
+ probe_sink_->RemoveInspectorIssueReporter(inspector_issue_reporter_);
+ if (inspector_trace_events_)
+ probe_sink_->RemoveInspectorTraceEvents(inspector_trace_events_);
+ inspector_task_runner_->Dispose();
+
+ if (content_capture_manager_) {
+ content_capture_manager_->Shutdown();
+ content_capture_manager_ = nullptr;
+ }
+
+ GetBackForwardCacheBufferLimitTracker().DidRemoveFrameFromBackForwardCache(
+ total_bytes_buffered_while_in_back_forward_cache_);
+ total_bytes_buffered_while_in_back_forward_cache_ = 0;
+
DCHECK(!view_->IsAttached());
Client()->WillBeDetached();
- // Notify WindowProxyManager that the frame is closing, since its cleanup ends
- // up calling back to LocalFrameClient via WindowProxy.
- GetWindowProxyManager()->ClearForClose();
// TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
CHECK(!view_->IsAttached());
@@ -657,6 +725,8 @@ void LocalFrame::DetachImpl(FrameDetachType type) {
main_frame_receiver_.reset();
high_priority_frame_receiver_.reset();
WeakIdentifierMap<LocalFrame>::NotifyObjectDestroyed(this);
+
+ return true;
}
bool LocalFrame::DetachDocument() {
@@ -667,6 +737,17 @@ void LocalFrame::CheckCompleted() {
GetDocument()->CheckCompleted();
}
+BackgroundColorPaintImageGenerator*
+LocalFrame::GetBackgroundColorPaintImageGenerator() {
+ LocalFrame& local_root = LocalFrameRoot();
+ // One background color paint worklet per root frame.
+ if (!local_root.background_color_paint_image_generator_) {
+ local_root.background_color_paint_image_generator_ =
+ BackgroundColorPaintImageGenerator::Create(local_root);
+ }
+ return local_root.background_color_paint_image_generator_.Get();
+}
+
const SecurityContext* LocalFrame::GetSecurityContext() const {
return DomWindow() ? &DomWindow()->GetSecurityContext() : nullptr;
}
@@ -685,10 +766,9 @@ void LocalFrame::PrintNavigationErrorMessage(const Frame& target_frame,
->GetSecurityOrigin()
->ToString() +
"'";
- String message =
- "Unsafe JavaScript attempt to initiate navigation for frame " +
- target_frame_description + " from frame with URL '" +
- GetDocument()->Url().GetString() + "'. " + reason + "\n";
+ String message = "Unsafe attempt to initiate navigation for frame " +
+ target_frame_description + " from frame with URL '" +
+ GetDocument()->Url().GetString() + "'. " + reason + "\n";
DomWindow()->PrintErrorMessage(message);
}
@@ -705,9 +785,10 @@ bool LocalFrame::ShouldClose() {
return loader_.ShouldClose();
}
-void LocalFrame::DetachChildren() {
+bool LocalFrame::DetachChildren() {
DCHECK(GetDocument());
ChildFrameDisconnector(*GetDocument()).Disconnect();
+ return !!Client();
}
void LocalFrame::DidAttachDocument() {
@@ -763,6 +844,14 @@ bool LocalFrame::IsTransientAllowFullscreenActive() const {
return transient_allow_fullscreen_.IsActive();
}
+bool LocalFrame::IsPaymentRequestTokenActive() const {
+ return payment_request_token_.IsActive();
+}
+
+bool LocalFrame::ConsumePaymentRequestToken() {
+ return payment_request_token_.ConsumeIfActive();
+}
+
void LocalFrame::SetOptimizationGuideHints(
mojom::blink::BlinkOptimizationGuideHintsPtr hints) {
DCHECK(hints);
@@ -801,7 +890,11 @@ LocalWindowProxy* LocalFrame::WindowProxy(DOMWrapperWorld& world) {
return To<LocalWindowProxy>(Frame::GetWindowProxy(world));
}
-LocalDOMWindow* LocalFrame::DomWindow() const {
+LocalDOMWindow* LocalFrame::DomWindow() {
+ return To<LocalDOMWindow>(dom_window_.Get());
+}
+
+const LocalDOMWindow* LocalFrame::DomWindow() const {
return To<LocalDOMWindow>(dom_window_.Get());
}
@@ -1254,7 +1347,7 @@ void LocalFrame::MediaQueryAffectingValueChangedForLocalSubtree(
}
void LocalFrame::WindowSegmentsChanged(
- const WebVector<WebRect>& window_segments) {
+ const WebVector<gfx::Rect>& window_segments) {
if (!RuntimeEnabledFeatures::CSSFoldablesEnabled())
return;
@@ -1270,7 +1363,7 @@ void LocalFrame::WindowSegmentsChanged(
}
void LocalFrame::UpdateCSSFoldEnvironmentVariables(
- const WebVector<WebRect>& window_segments) {
+ const WebVector<gfx::Rect>& window_segments) {
DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
// Update the variable values on the root instance so that documents that
@@ -1287,16 +1380,16 @@ void LocalFrame::UpdateCSSFoldEnvironmentVariables(
// describes the fold area (note that this may have a zero width or height,
// but not negative).
gfx::Rect fold_rect;
- if (window_segments[0].y == window_segments[1].y) {
- int fold_width = window_segments[1].x - window_segments[0].width;
+ if (window_segments[0].y() == window_segments[1].y()) {
+ int fold_width = window_segments[1].x() - window_segments[0].width();
DCHECK_GE(fold_width, 0);
- fold_rect.SetRect(window_segments[0].width, window_segments[0].y,
- fold_width, window_segments[0].height);
- } else if (window_segments[0].x == window_segments[1].x) {
- int fold_height = window_segments[1].y - window_segments[0].height;
+ fold_rect.SetRect(window_segments[0].width(), window_segments[0].y(),
+ fold_width, window_segments[0].height());
+ } else if (window_segments[0].x() == window_segments[1].x()) {
+ int fold_height = window_segments[1].y() - window_segments[0].height();
DCHECK_GE(fold_height, 0);
- fold_rect.SetRect(window_segments[0].x, window_segments[0].height,
- window_segments[0].width, fold_height);
+ fold_rect.SetRect(window_segments[0].x(), window_segments[0].height(),
+ window_segments[0].width(), fold_height);
}
vars.SetVariable(UADefinedVariable::kFoldTop,
@@ -1354,19 +1447,7 @@ PositionWithAffinity LocalFrame::PositionForPoint(
const PhysicalOffset& frame_point) {
HitTestLocation location(frame_point);
HitTestResult result = GetEventHandler().HitTestResultAtLocation(location);
- Node* node = result.InnerPossiblyPseudoNode();
- if (node && !node->IsPseudoElement())
- node = result.InnerNodeOrImageMapImage();
- if (!node)
- return PositionWithAffinity();
- LayoutObject* layout_object = node->GetLayoutObject();
- if (!layout_object)
- return PositionWithAffinity();
- const PositionWithAffinity position =
- layout_object->PositionForPoint(result.LocalPoint());
- if (position.IsNull())
- return PositionWithAffinity(FirstPositionInOrBeforeNode(*node));
- return position;
+ return result.GetPositionForInnerNodeOrImageMapImage();
}
Document* LocalFrame::DocumentAtPoint(
@@ -1418,7 +1499,7 @@ LocalFrame::LocalFrame(LocalFrameClient* client,
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WindowAgentFactory* inheriting_agent_factory,
InterfaceRegistry* interface_registry,
std::unique_ptr<PolicyContainer> policy_container,
@@ -1457,9 +1538,10 @@ LocalFrame::LocalFrame(LocalFrameClient* client,
: InterfaceRegistry::GetEmptyInterfaceRegistry()),
is_save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled()),
lifecycle_state_(mojom::FrameLifecycleState::kRunning),
- policy_container_(std::move(policy_container)) {
- auto frame_tracking_result = GetLocalFramesMap().insert(
- base::UnguessableTokenHash()(frame_token), this);
+ policy_container_(policy_container ? std::move(policy_container)
+ : PolicyContainer::CreateEmpty()) {
+ auto frame_tracking_result =
+ GetLocalFramesMap().insert(FrameToken::Hasher()(GetFrameToken()), this);
CHECK(frame_tracking_result.stored_value) << "Inserting a duplicate item.";
if (IsLocalRoot()) {
probe_sink_ = MakeGarbageCollected<CoreProbeSink>();
@@ -1485,11 +1567,11 @@ LocalFrame::LocalFrame(LocalFrameClient* client,
idleness_detector_ = MakeGarbageCollected<IdlenessDetector>(this, clock);
inspector_task_runner_->InitIsolate(V8PerIsolateData::MainThreadIsolate());
- if (ad_tracker_) {
- SetIsAdSubframeIfNecessary();
- }
DCHECK(ad_tracker_ ? RuntimeEnabledFeatures::AdTaggingEnabled()
: !RuntimeEnabledFeatures::AdTaggingEnabled());
+ is_subframe_created_by_ad_script_ =
+ !IsMainFrame() && ad_tracker_ &&
+ ad_tracker_->IsAdScriptInStack(AdTracker::StackType::kBottomAndTop);
if (IsMainFrame()) {
text_fragment_selector_generator_ =
MakeGarbageCollected<TextFragmentSelectorGenerator>();
@@ -1718,29 +1800,13 @@ bool LocalFrame::CanNavigate(const Frame& target_frame,
return false;
}
-void LocalFrame::SetIsAdSubframeIfNecessary() {
- DCHECK(ad_tracker_);
- if (IsAdSubframe())
- return;
-
- Frame* parent = Tree().Parent();
- if (!parent)
- return;
-
- bool parent_is_ad = parent->IsAdSubframe();
-
- if (parent_is_ad ||
- ad_tracker_->IsAdScriptInStack(AdTracker::StackType::kBottomAndTop)) {
- SetIsAdSubframe(parent_is_ad ? blink::mojom::AdFrameType::kChildAd
- : blink::mojom::AdFrameType::kRootAd);
- }
-}
-
ContentCaptureManager* LocalFrame::GetContentCaptureManager() {
DCHECK(Client());
if (!IsLocalRoot())
return nullptr;
+ // TODO(dcheng): Why does this function also Shutdown()? It seems rather
+ // surprising...
if (auto* content_capture_client = Client()->GetWebContentCaptureClient()) {
if (!content_capture_manager_) {
content_capture_manager_ =
@@ -1772,7 +1838,7 @@ FrameWidget* LocalFrame::GetWidgetForLocalRoot() {
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(this);
if (!web_frame)
return nullptr;
- // This WebFrameWidgetBase upcasts to a FrameWidget which is the interface
+ // This WebFrameWidgetImpl upcasts to a FrameWidget which is the interface
// exposed to Blink core.
return web_frame->LocalRootFrameWidget();
}
@@ -1782,7 +1848,7 @@ WebContentSettingsClient* LocalFrame::GetContentSettingsClient() {
}
PluginData* LocalFrame::GetPluginData() const {
- if (!Loader().AllowPlugins(kNotAboutToInstantiatePlugin))
+ if (!Loader().AllowPlugins())
return nullptr;
return GetPage()->GetPluginData(
Tree().Top().GetSecurityContext()->GetSecurityOrigin());
@@ -1961,6 +2027,9 @@ bool LocalFrame::ClipsContent() const {
if (GetDocument()->IsPaintingPreview())
return false;
+ if (ShouldUsePrintingLayout())
+ return false;
+
if (IsMainFrame())
return GetSettings()->GetMainFrameClipsContent();
// By default clip to viewport.
@@ -2026,12 +2095,13 @@ void LocalFrame::SetOpener(Frame* opener_frame) {
// Only a local frame should be able to update another frame's opener.
DCHECK(!opener_frame || opener_frame->IsLocalFrame());
- auto* web_frame = WebFrame::FromFrame(this);
+ auto* web_frame = WebFrame::FromCoreFrame(this);
if (web_frame && Opener() != opener_frame) {
GetLocalFrameHostRemote().DidChangeOpener(
- opener_frame ? base::Optional<base::UnguessableToken>(
- opener_frame->GetFrameToken())
- : base::nullopt);
+ opener_frame
+ ? base::Optional<blink::LocalFrameToken>(
+ opener_frame->GetFrameToken().GetAs<LocalFrameToken>())
+ : base::nullopt);
}
SetOpenerDoNotNotify(opener_frame);
}
@@ -2059,7 +2129,7 @@ bool LocalFrame::NeedsOcclusionTracking() const {
void LocalFrame::ForceSynchronousDocumentInstall(
const AtomicString& mime_type,
- scoped_refptr<SharedBuffer> data) {
+ scoped_refptr<const SharedBuffer> data) {
CHECK(GetDocument()->IsInitialEmptyDocument());
DCHECK(!Client()->IsLocalFrameClientImpl());
@@ -2068,20 +2138,20 @@ void LocalFrame::ForceSynchronousDocumentInstall(
GetDocument()->Shutdown();
DomWindow()->ClearForReuse();
- DomWindow()->InstallNewDocument(DocumentInit::Create()
- .WithWindow(DomWindow(), nullptr)
- .WithTypeFrom(mime_type));
-
- GetDocument()->OpenForNavigation(kForceSynchronousParsing, mime_type,
- AtomicString("UTF-8"));
+ Document* document =
+ DomWindow()->InstallNewDocument(DocumentInit::Create()
+ .WithWindow(DomWindow(), nullptr)
+ .WithTypeFrom(mime_type));
+ DocumentParser* parser = document->OpenForNavigation(
+ kForceSynchronousParsing, mime_type, AtomicString("UTF-8"));
for (const auto& segment : *data)
- GetDocument()->Parser()->AppendBytes(segment.data(), segment.size());
- GetDocument()->Parser()->Finish();
+ parser->AppendBytes(segment.data(), segment.size());
+ parser->Finish();
// Upon loading of SVGImages, log PageVisits in UseCounter.
// Do not track PageVisits for inspector, web page popups, and validation
// message overlays (the other callers of this method).
- if (GetDocument()->IsSVGDocument())
+ if (document->IsSVGDocument())
loader_.GetDocumentLoader()->GetUseCounterHelper().DidCommitLoad(this);
}
@@ -2185,7 +2255,7 @@ void LocalFrame::UpdateActiveSchedulerTrackedFeatures(uint64_t features_mask) {
}
const base::UnguessableToken& LocalFrame::GetAgentClusterId() const {
- if (LocalDOMWindow* window = DomWindow()) {
+ if (const LocalDOMWindow* window = DomWindow()) {
return window->GetAgentClusterID();
}
return base::UnguessableToken::Null();
@@ -2193,7 +2263,7 @@ const base::UnguessableToken& LocalFrame::GetAgentClusterId() const {
mojom::blink::ReportingServiceProxy* LocalFrame::GetReportingService() {
if (!reporting_service_.is_bound()) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ GetBrowserInterfaceBroker().GetInterface(
reporting_service_.BindNewPipeAndPassReceiver(
GetTaskRunner(blink::TaskType::kInternalDefault)));
}
@@ -2360,9 +2430,14 @@ bool LocalFrame::IsLoadDeferred() {
return frozen_ || paused_;
}
+bool LocalFrame::SwapIn() {
+ WebLocalFrameClient* client = Client()->GetWebFrame()->Client();
+ return client->SwapIn(WebFrame::FromCoreFrame(GetProvisionalOwnerFrame()));
+}
+
WebURLLoader::DeferType LocalFrame::GetLoadDeferType() {
if (GetPage()->GetPageScheduler()->IsInBackForwardCache() &&
- base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)) {
+ IsInflightNetworkRequestBackForwardCacheSupportEnabled()) {
return WebURLLoader::DeferType::kDeferredWithBackForwardCache;
}
if (paused_ || frozen_)
@@ -2414,6 +2489,9 @@ void LocalFrame::DidResume() {
Loader().SetDefersLoading(WebURLLoader::DeferType::kNotDeferred);
DomWindow()->SetIsInBackForwardCache(false);
+ GetBackForwardCacheBufferLimitTracker().DidRemoveFrameFromBackForwardCache(
+ total_bytes_buffered_while_in_back_forward_cache_);
+ total_bytes_buffered_while_in_back_forward_cache_ = 0;
}
void LocalFrame::MaybeLogAdClickNavigation() {
@@ -2516,9 +2594,21 @@ void LocalFrame::WasAttachedAsLocalMainFrame() {
void LocalFrame::EvictFromBackForwardCache(
mojom::blink::RendererEvictionReason reason) {
+ if (!GetPage()->GetPageScheduler()->IsInBackForwardCache())
+ return;
+ UMA_HISTOGRAM_ENUMERATION("BackForwardCache.Eviction.Renderer", reason);
GetBackForwardCacheControllerHostRemote().EvictFromBackForwardCache(reason);
}
+void LocalFrame::DidBufferLoadWhileInBackForwardCache(size_t num_bytes) {
+ total_bytes_buffered_while_in_back_forward_cache_ += num_bytes;
+ GetBackForwardCacheBufferLimitTracker().DidBufferBytes(num_bytes);
+}
+
+bool LocalFrame::CanContinueBufferingWhileInBackForwardCache() {
+ return GetBackForwardCacheBufferLimitTracker().IsUnderPerProcessBufferLimit();
+}
+
void LocalFrame::AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) {
GetPage()->GetChromeClient().AnimateDoubleTapZoom(point, rect);
@@ -2539,6 +2629,9 @@ void LocalFrame::ClosePage(
mojom::blink::LocalMainFrame::ClosePageCallback completion_callback) {
SECURITY_CHECK(IsMainFrame());
+ // TODO(crbug.com/1161996): Remove this VLOG once the investigation is done.
+ VLOG(1) << "LocalFrame::ClosePage() URL = " << GetDocument()->Url();
+
// There are two ways to close a page:
//
// 1/ Via webview()->Close() that currently sets the WebView's delegate_ to
@@ -2604,8 +2697,7 @@ void LocalFrame::EnablePreferredSizeChangedMode() {
}
void LocalFrame::ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame) {
- GetPage()->GetChromeClient().ZoomToFindInPageRect(
- WebRect(rect_in_root_frame));
+ GetPage()->GetChromeClient().ZoomToFindInPageRect(rect_in_root_frame);
}
#if defined(OS_MAC)
@@ -2625,15 +2717,13 @@ void LocalFrame::GetFirstRectForRange(const gfx::Range& range) {
return;
if (!client->GetCaretBoundsFromFocusedPlugin(rect)) {
- blink::WebRect web_rect;
// When request range is invalid we will try to obtain it from current
// frame selection. The fallback value will be 0.
uint32_t start =
range.IsValid() ? range.start() : GetCurrentCursorPositionInFrame(this);
WebLocalFrameImpl::FromFrame(this)->FirstRectForCharacterRange(
- start, range.length(), web_rect);
- rect.SetRect(web_rect.x, web_rect.y, web_rect.width, web_rect.height);
+ start, range.length(), rect);
}
GetTextInputHost().GotFirstRectForRange(rect);
@@ -2654,7 +2744,7 @@ void LocalFrame::GetStringForRange(const gfx::Range& range,
void LocalFrame::InstallCoopAccessMonitor(
network::mojom::blink::CoopAccessReportType report_type,
- const base::UnguessableToken& accessed_window,
+ const FrameToken& accessed_window,
mojo::PendingRemote<network::mojom::blink::CrossOriginOpenerPolicyReporter>
reporter,
bool endpoint_defined,
@@ -2711,6 +2801,56 @@ void LocalFrame::ForwardMessageFromHost(
.ReceiveMessage(std::move(message), source_origin);
}
+void LocalFrame::UpdateBrowserControlsState(
+ cc::BrowserControlsState constraints,
+ cc::BrowserControlsState current,
+ bool animate) {
+ DCHECK(IsMainFrame());
+ TRACE_EVENT2("renderer", "LocalFrame::UpdateBrowserControlsState",
+ "Constraint", static_cast<int>(constraints), "Current",
+ static_cast<int>(current));
+ TRACE_EVENT_INSTANT1("renderer", "is_animated", TRACE_EVENT_SCOPE_THREAD,
+ "animated", animate);
+
+ GetWidgetForLocalRoot()->UpdateBrowserControlsState(constraints, current,
+ animate);
+}
+
+void LocalFrame::UpdateWindowControlsOverlay(
+ const gfx::Rect& window_controls_overlay_rect,
+ const gfx::Insets& insets) {
+ is_window_controls_overlay_visible_ = !window_controls_overlay_rect.IsEmpty();
+ window_controls_overlay_rect_ = window_controls_overlay_rect;
+
+ DocumentStyleEnvironmentVariables& vars =
+ GetDocument()->GetStyleEngine().EnsureEnvironmentVariables();
+ vars.SetVariable(UADefinedVariable::kTitlebarAreaInsetTop,
+ StyleEnvironmentVariables::FormatPx(insets.top()));
+ vars.SetVariable(UADefinedVariable::kTitlebarAreaInsetLeft,
+ StyleEnvironmentVariables::FormatPx(insets.left()));
+ vars.SetVariable(UADefinedVariable::kTitlebarAreaInsetBottom,
+ StyleEnvironmentVariables::FormatPx(insets.bottom()));
+ vars.SetVariable(UADefinedVariable::kTitlebarAreaInsetRight,
+ StyleEnvironmentVariables::FormatPx(insets.right()));
+}
+
+void LocalFrame::RequestFullscreenVideoElement() {
+ // Find the first video element of the frame.
+ for (auto* child = GetDocument()->documentElement(); child;
+ child = Traversal<HTMLElement>::Next(*child)) {
+ if (IsA<HTMLVideoElement>(child)) {
+ // This is always initiated from browser side (which should require the
+ // user interacting with ui) which suffices for a user gesture even though
+ // there will have been no input to the frame at this point.
+ NotifyUserActivation(
+ mojom::blink::UserActivationNotificationType::kInteraction);
+
+ Fullscreen::RequestFullscreen(*child);
+ return;
+ }
+ }
+}
+
HitTestResult LocalFrame::HitTestResultForVisualViewportPos(
const IntPoint& pos_in_viewport) {
IntPoint root_frame_point(
@@ -2856,6 +2996,19 @@ void LocalFrame::AddInspectorIssue(mojom::blink::InspectorIssueInfoPtr info) {
}
}
+void LocalFrame::SwapInImmediately() {
+ SwapIn();
+ // Normally, this happens as part of committing a cross-Document navigation.
+ // However, there is no navigation being committed here. Instead, the browser
+ // navigation code is optimistically early-swapping in this frame to replace a
+ // crashed subframe after starting a navigation.
+ //
+ // While the provisional frame has a unique opaque origin, the Blink bindings
+ // code still expects the WindowProxy to be initialized for the access check
+ // failed callbacks.
+ DomWindow()->GetScriptController().UpdateDocument();
+}
+
void LocalFrame::StopLoading() {
Loader().StopAllLoaders(/*abort_client=*/true);
@@ -2959,6 +3112,7 @@ void LocalFrame::SaveImageAt(const gfx::Point& window_point) {
return;
auto params = mojom::blink::DownloadURLParams::New();
+ params->is_context_menu_save = true;
params->data_url_blob = DataURLToBlob(url);
GetLocalFrameHostRemote().DownloadURL(std::move(params));
}
@@ -3098,7 +3252,7 @@ void LocalFrame::MediaPlayerActionAt(
void LocalFrame::AdvanceFocusInFrame(
mojom::blink::FocusType focus_type,
- const base::Optional<base::UnguessableToken>& source_frame_token) {
+ const base::Optional<RemoteFrameToken>& source_frame_token) {
RemoteFrame* source_frame = SourceFrameForOptionalToken(source_frame_token);
if (!source_frame) {
SetInitialFocus(focus_type == mojom::blink::FocusType::kBackward);
@@ -3143,7 +3297,7 @@ void LocalFrame::ReportContentSecurityPolicyViolation(
auto directive_type =
ContentSecurityPolicy::GetDirectiveType(violation->effective_directive);
LocalFrame* context_frame =
- directive_type == ContentSecurityPolicy::DirectiveType::kFrameAncestors
+ directive_type == network::mojom::blink::CSPDirectiveName::FrameAncestors
? this
: nullptr;
@@ -3175,7 +3329,7 @@ void LocalFrame::OnScreensChange() {
}
void LocalFrame::PostMessageEvent(
- const base::Optional<base::UnguessableToken>& source_frame_token,
+ const base::Optional<RemoteFrameToken>& source_frame_token,
const String& source_origin,
const String& target_origin,
BlinkTransferableMessage message) {
@@ -3204,9 +3358,16 @@ void LocalFrame::PostMessageEvent(
message.user_activation->has_been_active,
message.user_activation->was_active);
}
+
+ if (RuntimeEnabledFeatures::CapabilityDelegationPaymentRequestEnabled() &&
+ message.delegate_payment_request) {
+ payment_request_token_.Activate();
+ }
+
message_event->initMessageEvent(
"message", false, false, std::move(message.message), source_origin,
- "" /*lastEventId*/, window, ports, user_activation);
+ "" /*lastEventId*/, window, ports, user_activation,
+ message.delegate_payment_request);
// If the agent cluster id had a value it means this was locked when it
// was serialized.
@@ -3227,8 +3388,8 @@ void LocalFrame::BindReportingObserver(
}
void LocalFrame::UpdateOpener(
- const base::Optional<base::UnguessableToken>& opener_frame_token) {
- if (auto* web_frame = WebFrame::FromFrame(this)) {
+ const base::Optional<blink::FrameToken>& opener_frame_token) {
+ if (auto* web_frame = WebFrame::FromCoreFrame(this)) {
Frame* opener_frame = nullptr;
if (opener_frame_token)
opener_frame = Frame::ResolveFrame(opener_frame_token.value());
@@ -3303,6 +3464,14 @@ mojom::blink::TextInputHost& LocalFrame::GetTextInputHost() {
}
#endif
+Frame* LocalFrame::GetProvisionalOwnerFrame() {
+ DCHECK(IsProvisional());
+ if (Owner()) {
+ return Owner()->ContentFrame();
+ }
+ return GetPage()->MainFrame();
+}
+
void LocalFrame::BindToReceiver(
blink::LocalFrame* frame,
mojo::PendingAssociatedReceiver<mojom::blink::LocalFrame> receiver) {
@@ -3342,6 +3511,18 @@ void LocalFrame::BindToHighPriorityReceiver(
std::make_unique<ActiveURLMessageFilter>(this));
}
+void LocalFrame::BindFullscreenVideoElementReceiver(
+ mojo::PendingAssociatedReceiver<mojom::blink::FullscreenVideoElementHandler>
+ receiver) {
+ if (IsDetached())
+ return;
+
+ fullscreen_video_receiver_.Bind(
+ std::move(receiver), GetTaskRunner(blink::TaskType::kInternalDefault));
+ fullscreen_video_receiver_.SetFilter(
+ std::make_unique<ActiveURLMessageFilter>(this));
+}
+
void LocalFrame::BindTextFragmentSelectorProducer(
mojo::PendingReceiver<mojom::blink::TextFragmentSelectorProducer>
receiver) {
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.h b/chromium/third_party/blink/renderer/core/frame/local_frame.h
index ce6ec98ec07..38153330251 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame.h
@@ -38,6 +38,7 @@
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
+#include "third_party/blink/public/common/frame/payment_request_token.h"
#include "third_party/blink/public/common/frame/transient_allow_fullscreen.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink.h"
@@ -49,11 +50,12 @@
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/link_to_text/link_to_text.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/media/fullscreen_video_element.mojom-blink.h"
#include "third_party/blink/public/mojom/optimization_guide/optimization_guide.mojom-blink.h"
#include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink-forward.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_rect.h"
+#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/renderer/core/clipboard/raw_system_clipboard.h"
#include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -63,6 +65,7 @@
#include "third_party/blink/renderer/core/frame/frame_types.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/policy_container.h"
+#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/platform/graphics/touch_action.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -127,6 +130,7 @@ class LayoutView;
class LocalDOMWindow;
class LocalWindowProxy;
class LocalFrameClient;
+class BackgroundColorPaintImageGenerator;
class Node;
class NodeTraversal;
class PerformanceMonitor;
@@ -151,11 +155,10 @@ class CORE_EXPORT LocalFrame final
public Supplementable<LocalFrame>,
public mojom::blink::LocalFrame,
public mojom::blink::LocalMainFrame,
+ public mojom::blink::FullscreenVideoElementHandler,
public mojom::blink::HighPriorityLocalFrame {
public:
// Returns the LocalFrame instance for the given |frame_token|.
- // TODO(crbug.com/1096617): Remove the UnguessableToken version of this.
- static LocalFrame* FromFrameToken(const base::UnguessableToken& frame_token);
static LocalFrame* FromFrameToken(const LocalFrameToken& frame_token);
// For a description of |inheriting_agent_factory| go see the comment on the
@@ -167,7 +170,7 @@ class CORE_EXPORT LocalFrame final
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WindowAgentFactory* inheriting_agent_factory,
InterfaceRegistry*,
std::unique_ptr<blink::PolicyContainer> policy_container,
@@ -202,12 +205,24 @@ class CORE_EXPORT LocalFrame final
Frame* child) override;
void DidFocus() override;
+ // Triggers eviction of this frame by notifying the browser side.
void EvictFromBackForwardCache(mojom::blink::RendererEvictionReason reason);
+ // Called when a network request buffered an additional `num_bytes` while the
+ // frame is in back-forward cache. Updates the total amount of bytes buffered
+ // for back-forward cache in the frame and in the process. Note that
+ // `num_bytes` is the amount of additional bytes that are newly buffered, on
+ // top of any previously buffered bytes for this frame.
+ void DidBufferLoadWhileInBackForwardCache(size_t num_bytes);
+ // Returns true if the total amount of bytes buffered while in back-forward
+ // cache in the whole renderer process is still under the per-process limit,
+ // false otherwise.
+ bool CanContinueBufferingWhileInBackForwardCache();
void DidChangeThemeColor();
void DidChangeBackgroundColor(SkColor background_color, bool color_adjust);
- void DetachChildren();
+ // Returns false if detaching child frames reentrantly detached `this`.
+ bool DetachChildren();
// After Document is attached, resets state related to document, and sets
// context to the current document.
void DidAttachDocument();
@@ -218,7 +233,8 @@ class CORE_EXPORT LocalFrame final
// corresponding method in the Frame base class to return the
// LocalFrame-specific subclass.
LocalWindowProxy* WindowProxy(DOMWrapperWorld&);
- LocalDOMWindow* DomWindow() const;
+ LocalDOMWindow* DomWindow();
+ const LocalDOMWindow* DomWindow() const;
void SetDOMWindow(LocalDOMWindow*);
LocalFrameView* View() const override;
Document* GetDocument() const;
@@ -237,6 +253,7 @@ class CORE_EXPORT LocalFrame final
TextSuggestionController& GetTextSuggestionController() const;
SpellChecker& GetSpellChecker() const;
FrameConsole& Console() const;
+ BackgroundColorPaintImageGenerator* GetBackgroundColorPaintImageGenerator();
// A local root is the root of a connected subtree that contains only
// LocalFrames. The local root is responsible for coordinating input, layout,
@@ -329,9 +346,9 @@ class CORE_EXPORT LocalFrame final
// media query value changed.
void MediaQueryAffectingValueChangedForLocalSubtree(MediaValueChange);
- void WindowSegmentsChanged(const WebVector<WebRect>& window_segments);
+ void WindowSegmentsChanged(const WebVector<gfx::Rect>& window_segments);
void UpdateCSSFoldEnvironmentVariables(
- const WebVector<WebRect>& window_segments);
+ const WebVector<gfx::Rect>& window_segments);
String SelectedText() const;
String SelectedTextForClipboard() const;
@@ -361,6 +378,8 @@ class CORE_EXPORT LocalFrame final
// navigation at a later time.
bool CanNavigate(const Frame&, const KURL& destination_url = KURL());
+ // Return this frame's BrowserInterfaceBroker. Must not be called on detached
+ // frames (that is, frames where `Client()` returns nullptr).
BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker();
InterfaceRegistry* GetInterfaceRegistry() { return interface_registry_; }
@@ -452,7 +471,7 @@ class CORE_EXPORT LocalFrame final
// |mime_type| and populated with the contents of |data|. Only intended for
// use in internal-implementation LocalFrames that aren't in the frame tree.
void ForceSynchronousDocumentInstall(const AtomicString& mime_type,
- scoped_refptr<SharedBuffer> data);
+ scoped_refptr<const SharedBuffer> data);
bool should_send_resource_timing_info_to_parent() const {
return should_send_resource_timing_info_to_parent_;
@@ -480,11 +499,16 @@ class CORE_EXPORT LocalFrame final
// be removed.
bool IsProvisional() const;
- // Called in the constructor if AdTracker heuristics have determined that this
- // frame is an ad; LocalFrames created on behalf of OOPIF aren't set until
- // just before commit (ReadyToCommitNavigation time) by the embedder.
+ // Called by the embedder if the evidence indicates the frame is an ad
+ // subframe. Called on creation of the initial empty document or, for
+ // LocalFrames created on behalf of OOPIF, just before commit
+ // (ReadyToCommitNavigation time).
void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type);
+ bool IsSubframeCreatedByAdScript() const {
+ return is_subframe_created_by_ad_script_;
+ }
+
// Updates the frame color overlay to match the highlight ad setting.
void UpdateAdHighlight();
@@ -603,6 +627,7 @@ class CORE_EXPORT LocalFrame final
const WTF::String& message,
bool discard_duplicates) final;
void AddInspectorIssue(mojom::blink::InspectorIssueInfoPtr) final;
+ void SwapInImmediately() final;
void StopLoading() final;
void Collapse(bool collapsed) final;
void EnableViewSourceMode() final;
@@ -624,7 +649,7 @@ class CORE_EXPORT LocalFrame final
blink::mojom::blink::MediaPlayerActionPtr action) final;
void AdvanceFocusInFrame(
mojom::blink::FocusType focus_type,
- const base::Optional<base::UnguessableToken>& source_frame_token) final;
+ const base::Optional<RemoteFrameToken>& source_frame_token) final;
void AdvanceFocusInForm(mojom::blink::FocusType focus_type) final;
void ReportContentSecurityPolicyViolation(
network::mojom::blink::CSPViolationPtr csp_violation) final;
@@ -636,14 +661,14 @@ class CORE_EXPORT LocalFrame final
void DidUpdateFramePolicy(const FramePolicy& frame_policy) final;
void OnScreensChange() final;
void PostMessageEvent(
- const base::Optional<base::UnguessableToken>& source_frame_token,
+ const base::Optional<RemoteFrameToken>& source_frame_token,
const String& source_origin,
const String& target_origin,
BlinkTransferableMessage message) final;
void BindReportingObserver(
mojo::PendingReceiver<mojom::blink::ReportingObserver> receiver) final;
void UpdateOpener(
- const base::Optional<base::UnguessableToken>& opener_routing_id) final;
+ const base::Optional<blink::FrameToken>& opener_routing_id) final;
void GetSavableResourceLinks(GetSavableResourceLinksCallback callback) final;
void MixedContentFound(
const KURL& main_resource_url,
@@ -660,7 +685,6 @@ class CORE_EXPORT LocalFrame final
void SetScaleFactor(float scale) override;
void ClosePage(
mojom::blink::LocalMainFrame::ClosePageCallback callback) override;
- // Performs the specified plugin action on the node at the given location.
void PluginActionAt(const gfx::Point& location,
mojom::blink::PluginActionType action) override;
void SetInitialFocus(bool reverse) override;
@@ -674,7 +698,7 @@ class CORE_EXPORT LocalFrame final
#endif
void InstallCoopAccessMonitor(
network::mojom::blink::CoopAccessReportType report_type,
- const base::UnguessableToken& accessed_window,
+ const FrameToken& accessed_window,
mojo::PendingRemote<
network::mojom::blink::CrossOriginOpenerPolicyReporter> reporter,
bool endpoint_defined,
@@ -689,6 +713,15 @@ class CORE_EXPORT LocalFrame final
void ForwardMessageFromHost(
BlinkTransferableMessage message,
const scoped_refptr<const SecurityOrigin>& source_origin) final;
+ void UpdateBrowserControlsState(cc::BrowserControlsState constraints,
+ cc::BrowserControlsState current,
+ bool animate) override;
+ void UpdateWindowControlsOverlay(
+ const gfx::Rect& window_controls_overlay_rect,
+ const gfx::Insets& insets) override;
+
+ // mojom::FullscreenVideoElementHandler implementation:
+ void RequestFullscreenVideoElement() final;
SystemClipboard* GetSystemClipboard();
RawSystemClipboard* GetRawSystemClipboard();
@@ -704,6 +737,12 @@ class CORE_EXPORT LocalFrame final
// Return true if the frame has a transient affordance to enter fullscreen.
bool IsTransientAllowFullscreenActive() const;
+ // Returns the state of the |PaymentRequestToken| in the current |Frame|.
+ bool IsPaymentRequestTokenActive() const;
+
+ // Consumes the |PaymentRequestToken| of the current |Frame| if it was active.
+ bool ConsumePaymentRequestToken();
+
void SetOptimizationGuideHints(
mojom::blink::BlinkOptimizationGuideHintsPtr hints);
mojom::blink::BlinkOptimizationGuideHints* GetOptimizationGuideHints() {
@@ -711,7 +750,7 @@ class CORE_EXPORT LocalFrame final
}
LocalFrameToken GetLocalFrameToken() const {
- return LocalFrameToken(GetFrameToken());
+ return GetFrameToken().GetAs<LocalFrameToken>();
}
TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator() const {
@@ -724,12 +763,24 @@ class CORE_EXPORT LocalFrame final
WebURLLoader::DeferType GetLoadDeferType();
bool IsLoadDeferred();
+ bool SwapIn();
+
+ // For PWAs with display_overrides, these getters are information about the
+ // titlebar bounds sent over from the browser via UpdateWindowControlsOverlay
+ // in LocalMainFrame that are needed to persist the lifetime of the frame.
+ bool IsWindowControlsOverlayVisible() const {
+ return is_window_controls_overlay_visible_;
+ }
+ const gfx::Rect& GetWindowControlsOverlayRect() const {
+ return window_controls_overlay_rect_;
+ }
+
private:
friend class FrameNavigationDisabler;
FRIEND_TEST_ALL_PREFIXES(LocalFrameTest, CharacterIndexAtPointWithPinchZoom);
// Frame protected overrides:
- void DetachImpl(FrameDetachType) override;
+ bool DetachImpl(FrameDetachType) override;
// Intentionally private to prevent redundant checks when the type is
// already LocalFrame.
@@ -739,8 +790,6 @@ class CORE_EXPORT LocalFrame final
void EnableNavigation() { --navigation_disable_count_; }
void DisableNavigation() { ++navigation_disable_count_; }
- void SetIsAdSubframeIfNecessary();
-
void PropagateInertToChildFrames();
// Internal implementation for starting or ending printing.
@@ -785,6 +834,10 @@ class CORE_EXPORT LocalFrame final
mojom::blink::TextInputHost& GetTextInputHost();
#endif
+ // Returns the `Frame` for which `provisional_frame_ == this`. May only be
+ // called on a provisional frame.
+ Frame* GetProvisionalOwnerFrame();
+
static void BindToReceiver(
blink::LocalFrame* frame,
mojo::PendingAssociatedReceiver<mojom::blink::LocalFrame> receiver);
@@ -793,7 +846,9 @@ class CORE_EXPORT LocalFrame final
mojo::PendingAssociatedReceiver<mojom::blink::LocalMainFrame> receiver);
void BindToHighPriorityReceiver(
mojo::PendingReceiver<mojom::blink::HighPriorityLocalFrame> receiver);
-
+ void BindFullscreenVideoElementReceiver(
+ mojo::PendingAssociatedReceiver<
+ mojom::blink::FullscreenVideoElementHandler> receiver);
void BindTextFragmentSelectorProducer(
mojo::PendingReceiver<mojom::blink::TextFragmentSelectorProducer>
receiver);
@@ -849,6 +904,11 @@ class CORE_EXPORT LocalFrame final
float page_zoom_factor_;
float text_zoom_factor_;
+ // The total bytes buffered by all network requests in this frame while frozen
+ // due to back-forward cache. This number gets reset when the frame gets out
+ // of the back-forward cache.
+ size_t total_bytes_buffered_while_in_back_forward_cache_ = 0;
+
Member<CoreProbeSink> probe_sink_;
scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
Member<PerformanceMonitor> performance_monitor_;
@@ -927,6 +987,11 @@ class CORE_EXPORT LocalFrame final
LocalFrame,
HeapMojoWrapperMode::kWithoutContextObserver>
high_priority_frame_receiver_{this, nullptr};
+ // LocalFrame can be reused by multiple ExecutionContext.
+ HeapMojoAssociatedReceiver<mojom::blink::FullscreenVideoElementHandler,
+ LocalFrame,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ fullscreen_video_receiver_{this, nullptr};
// Variable to control burst of download requests.
int num_burst_download_requests_ = 0;
@@ -937,6 +1002,9 @@ class CORE_EXPORT LocalFrame final
// Access to the global raw/unsanitized system clipboard
Member<RawSystemClipboard> raw_system_clipboard_;
+ Member<BackgroundColorPaintImageGenerator>
+ background_color_paint_image_generator_;
+
using SavedScrollOffsets = HeapHashMap<Member<Node>, ScrollOffset>;
Member<SavedScrollOffsets> saved_scroll_offsets_;
@@ -947,7 +1015,19 @@ class CORE_EXPORT LocalFrame final
// Manages a transient affordance for this frame to enter fullscreen.
TransientAllowFullscreen transient_allow_fullscreen_;
+ PaymentRequestToken payment_request_token_;
+
std::unique_ptr<PolicyContainer> policy_container_;
+
+ bool is_window_controls_overlay_visible_ = false;
+ gfx::Rect window_controls_overlay_rect_;
+
+ // True if this frame is a subframe that had a script tagged as an ad on the
+ // v8 stack at the time of creation. This is not currently propagated when a
+ // frame navigates cross-origin.
+ // TODO(crbug.com/1145634): propagate this bit for a frame that navigates
+ // cross-origin.
+ bool is_subframe_created_by_ad_script_ = false;
};
inline FrameLoader& LocalFrame::Loader() const {
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
index 1c62eb2a1b8..d376f9dc163 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
@@ -79,7 +79,7 @@ TEST_F(LocalFrameBackForwardCacheTest, EvictionOnV8ExecutionAtMicrotask) {
web_frame_client.GetRemoteNavigationAssociatedInterfaces());
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.Initialize(
- &web_frame_client, nullptr, nullptr,
+ &web_frame_client, nullptr,
[](WebSettings* settings) { settings->SetJavaScriptEnabled(true); });
web_view_helper.Resize(gfx::Size(640, 480));
@@ -88,6 +88,7 @@ TEST_F(LocalFrameBackForwardCacheTest, EvictionOnV8ExecutionAtMicrotask) {
// Freeze the frame and hook eviction.
frame->GetPage()->GetPageScheduler()->SetPageVisible(false);
frame->GetPage()->GetPageScheduler()->SetPageFrozen(true);
+ frame->GetPage()->GetPageScheduler()->SetPageBackForwardCached(true);
frame->HookBackForwardCacheEviction();
auto* script_state = ToScriptStateForMainWorld(frame);
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_client.h b/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
index d83455d1fb4..8ef6fcadbaa 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -39,11 +39,13 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink-forward.h"
+#include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
+#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h"
-#include "third_party/blink/public/common/navigation/triggering_event_info.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/portal/portal.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink-forward.h"
@@ -130,12 +132,17 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual void DispatchDidHandleOnloadEvents() = 0;
virtual void DidFinishSameDocumentNavigation(HistoryItem*,
WebHistoryCommitType,
- bool content_initiated) {}
+ bool content_initiated,
+ bool is_history_api_navigation) {
+ }
virtual void DispatchDidReceiveTitle(const String&) = 0;
virtual void DispatchDidCommitLoad(
- HistoryItem*,
- WebHistoryCommitType,
- bool should_reset_browser_interface_broker) = 0;
+ HistoryItem* item,
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const blink::ParsedFeaturePolicy& feature_policy_header,
+ const blink::DocumentPolicyFeatureState& document_policy_header) = 0;
virtual void DispatchDidFailLoad(const ResourceError&,
WebHistoryCommitType) = 0;
virtual void DispatchDidFinishDocumentLoad() = 0;
@@ -150,7 +157,7 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
NavigationPolicy,
WebFrameLoadType,
bool is_client_redirect,
- TriggeringEventInfo,
+ mojom::blink::TriggeringEventInfo,
HTMLFormElement*,
network::mojom::CSPDisposition
should_check_main_world_content_security_policy,
@@ -160,9 +167,11 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
const base::Optional<WebImpression>& impression,
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
initiator_csp,
- network::mojom::blink::CSPSourcePtr initiator_self_source,
network::mojom::IPAddressSpace,
- mojo::PendingRemote<mojom::blink::NavigationInitiator>) = 0;
+ mojo::PendingRemote<mojom::blink::NavigationInitiator>,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_handle) = 0;
virtual void DispatchWillSendSubmitEvent(HTMLFormElement*) = 0;
@@ -199,6 +208,11 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual void DidObserveLayoutShift(double score, bool after_input_or_scroll) {
}
+ // Reports input timestamps for segmenting layout shifts by users inputs to
+ // create Session window.
+ virtual void DidObserveInputForLayoutShiftTracking(
+ base::TimeTicks timestamp) {}
+
// Reports the number of LayoutBlock creation, and LayoutObject::UpdateLayout
// calls. All values are deltas since the last calls of this function.
virtual void DidObserveLayoutNg(uint32_t all_block_count,
@@ -276,7 +290,6 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
HTMLMediaElement&) = 0;
- virtual void DidCreateInitialEmptyDocument() = 0;
virtual void DidCommitDocumentReplacementNavigation(DocumentLoader*) = 0;
virtual void DispatchDidClearWindowObjectInMainWorld() = 0;
virtual void DocumentElementAvailable() = 0;
@@ -301,11 +314,6 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual void DidChangeName(const String&) {}
- virtual void DidSetFramePolicyHeaders(
- network::mojom::blink::WebSandboxFlags,
- const ParsedFeaturePolicy& feature_policy_header,
- const DocumentPolicyFeatureState& document_policy_header) {}
-
virtual std::unique_ptr<WebServiceWorkerProvider>
CreateServiceWorkerProvider() = 0;
@@ -353,7 +361,9 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual Frame* FindFrame(const AtomicString& name) const = 0;
- virtual void FrameRectsChanged(const IntRect&) {}
+ virtual void OnOverlayPopupAdDetected() {}
+
+ virtual void OnLargeStickyAdDetected() {}
virtual void FocusedElementChanged(Element* element) {}
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 1cb22fc5f0e..328c6d6d95d 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -33,6 +33,7 @@
#include <utility>
+#include "base/stl_util.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@@ -69,11 +70,12 @@
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.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_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
@@ -161,120 +163,6 @@ void ResetWheelAndTouchEventHandlerProperties(LocalFrame& frame) {
cc::EventListenerProperties::kNone);
}
-// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
-// from blink.
-WebContentSecurityPolicySourceExpression ConvertToPublic(
- network::mojom::blink::CSPSourcePtr source) {
- return {source->scheme,
- source->host,
- source->is_host_wildcard ? kWebWildcardDispositionHasWildcard
- : kWebWildcardDispositionNoWildcard,
- source->port,
- source->is_port_wildcard ? kWebWildcardDispositionHasWildcard
- : kWebWildcardDispositionNoWildcard,
- source->path};
-}
-
-// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
-// from blink.
-WebContentSecurityPolicySourceList ConvertToPublic(
- network::mojom::blink::CSPSourceListPtr source_list) {
- WebVector<WebContentSecurityPolicySourceExpression> sources(
- source_list->sources.size());
- for (size_t i = 0; i < sources.size(); ++i)
- sources[i] = ConvertToPublic(std::move(source_list->sources[i]));
- return {source_list->allow_self, source_list->allow_star,
- source_list->allow_response_redirects, std::move(sources)};
-}
-
-// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
-// from blink.
-WebString ConvertToPublic(
- network::mojom::blink::CSPDirectiveName directive_name) {
- using CSPDirectiveName = network::mojom::blink::CSPDirectiveName;
- switch (directive_name) {
- case CSPDirectiveName::BaseURI:
- return "base-uri";
- case CSPDirectiveName::ChildSrc:
- return "child-src";
- case CSPDirectiveName::ConnectSrc:
- return "connect-src";
- case CSPDirectiveName::DefaultSrc:
- return "default-src";
- case CSPDirectiveName::FrameAncestors:
- return "frame-ancestors";
- case CSPDirectiveName::FrameSrc:
- return "frame-src";
- case CSPDirectiveName::FontSrc:
- return "font-src";
- case CSPDirectiveName::FormAction:
- return "form-action";
- case CSPDirectiveName::ImgSrc:
- return "img-src";
- case CSPDirectiveName::ManifestSrc:
- return "manifest-src";
- case CSPDirectiveName::MediaSrc:
- return "media-src";
- case CSPDirectiveName::ObjectSrc:
- return "object-src";
- case CSPDirectiveName::PrefetchSrc:
- return "prefetch-src";
- case CSPDirectiveName::ReportURI:
- return "report-uri";
- case CSPDirectiveName::Sandbox:
- return "sandbox";
- case CSPDirectiveName::ScriptSrc:
- return "script-src";
- case CSPDirectiveName::ScriptSrcAttr:
- return "script-src-attr";
- case CSPDirectiveName::ScriptSrcElem:
- return "script-src-elem";
- case CSPDirectiveName::StyleSrc:
- return "style-src";
- case CSPDirectiveName::StyleSrcAttr:
- return "style-src-attr";
- case CSPDirectiveName::StyleSrcElem:
- return "style-src-elem";
- case CSPDirectiveName::UpgradeInsecureRequests:
- return "upgrade-insecure-requests";
- case CSPDirectiveName::TreatAsPublicAddress:
- return "treat-as-public-address";
- case CSPDirectiveName::WorkerSrc:
- return "worker-src";
- case CSPDirectiveName::ReportTo:
- return "report-to";
- case CSPDirectiveName::NavigateTo:
- return "navigate-to";
- case CSPDirectiveName::Unknown:
- NOTREACHED();
- return "";
- default:
- NOTREACHED();
- return "";
- };
-}
-
-// TODO(arthursonzogni): Remove this when BeginNavigation will be sent directly
-// from blink.
-WebContentSecurityPolicy ConvertToPublic(
- network::mojom::blink::ContentSecurityPolicyPtr policy) {
- WebVector<WebContentSecurityPolicyDirective> directives(
- policy->directives.size());
- size_t i = 0;
- for (auto& directive : policy->directives) {
- directives[i++] = {ConvertToPublic(directive.key),
- ConvertToPublic(std::move(directive.value))};
- }
-
- return {policy->header->type,
- policy->header->source,
- std::move(directives),
- policy->upgrade_insecure_requests,
- std::move(policy->report_endpoints),
- policy->header->header_value,
- policy->use_reporting_api};
-}
-
} // namespace
LocalFrameClientImpl::LocalFrameClientImpl(WebLocalFrameImpl* frame)
@@ -296,11 +184,6 @@ WebContentCaptureClient* LocalFrameClientImpl::GetWebContentCaptureClient()
return web_frame_->ContentCaptureClient();
}
-void LocalFrameClientImpl::DidCreateInitialEmptyDocument() {
- if (web_frame_->Client())
- web_frame_->Client()->DidCreateInitialEmptyDocument();
-}
-
void LocalFrameClientImpl::DidCommitDocumentReplacementNavigation(
DocumentLoader* loader) {
if (web_frame_->Client()) {
@@ -352,9 +235,7 @@ function createShadowRootWithin(node) {
continue;
parent.removeChild(template);
var shadowRoot;
- if (mode == 'v0') {
- shadowRoot = parent.createShadowRoot();
- } else if (mode == 'open' || mode == 'closed') {
+ if (mode == 'open' || mode == 'closed') {
var delegatesFocus = template.hasAttribute('shadowdelegatesfocus');
shadowRoot = parent.attachShadow({'mode': mode,
'delegatesFocus': delegatesFocus});
@@ -371,7 +252,7 @@ createShadowRootWithin(document.body);
ClassicScript::CreateUnspecifiedScript(
ScriptSourceCode(script, ScriptSourceLocationType::kInternal))
->RunScript(web_frame_->GetFrame()->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
}
if (web_frame_->Client()) {
@@ -502,13 +383,14 @@ void LocalFrameClientImpl::DispatchDidHandleOnloadEvents() {
void LocalFrameClientImpl::DidFinishSameDocumentNavigation(
HistoryItem* item,
WebHistoryCommitType commit_type,
- bool content_initiated) {
+ bool content_initiated,
+ bool is_history_api_navigation) {
bool should_create_history_entry = commit_type == kWebStandardCommit;
// TODO(dglazkov): Does this need to be called for subframes?
web_frame_->ViewImpl()->DidCommitLoad(should_create_history_entry, true);
if (web_frame_->Client()) {
web_frame_->Client()->DidFinishSameDocumentNavigation(
- WebHistoryItem(item), commit_type, content_initiated);
+ commit_type, content_initiated, is_history_api_navigation);
}
}
@@ -521,7 +403,10 @@ void LocalFrameClientImpl::DispatchDidReceiveTitle(const String& title) {
void LocalFrameClientImpl::DispatchDidCommitLoad(
HistoryItem* item,
WebHistoryCommitType commit_type,
- bool should_reset_browser_interface_broker) {
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const blink::ParsedFeaturePolicy& feature_policy_header,
+ const blink::DocumentPolicyFeatureState& document_policy_header) {
if (!web_frame_->Parent()) {
web_frame_->ViewImpl()->DidCommitLoad(commit_type == kWebStandardCommit,
false);
@@ -529,8 +414,14 @@ void LocalFrameClientImpl::DispatchDidCommitLoad(
if (web_frame_->Client()) {
web_frame_->Client()->DidCommitNavigation(
- WebHistoryItem(item), commit_type,
- should_reset_browser_interface_broker);
+ commit_type, should_reset_browser_interface_broker, sandbox_flags,
+ feature_policy_header, document_policy_header);
+
+ // With local to local swap it's possible for the frame to be deleted as a
+ // side effect of JS event handlers called in DidCommitNavigation
+ // (e.g. unload).
+ if (!web_frame_->Client())
+ return;
if (web_frame_->GetFrame()->IsLocalRoot()) {
// This update should be sent as soon as loading the new document begins
// so that the browser and compositor could reset their states. However,
@@ -544,17 +435,16 @@ void LocalFrameClientImpl::DispatchDidCommitLoad(
// a navigation on the main frame we setup the appropriate structures.
if (web_frame_->GetFrame()->IsMainFrame() &&
web_frame_->ViewImpl()->does_composite()) {
- cc::LayerTreeHost* layer_tree_host =
- web_frame_->FrameWidgetImpl()->LayerTreeHost();
+ WebFrameWidgetImpl* frame_widget = web_frame_->FrameWidgetImpl();
// Update the URL and the document source id used to key UKM metrics in
// the compositor. Note that the metrics for all frames are keyed to the
// main frame's URL.
- layer_tree_host->SetSourceURL(
+ frame_widget->SetSourceURLForCompositor(
web_frame_->GetDocument().GetUkmSourceId(),
KURL(web_frame_->Client()->LastCommittedUrlForUKM()));
- auto shmem = layer_tree_host->CreateSharedMemoryForSmoothnessUkm();
+ auto shmem = frame_widget->CreateSharedMemoryForSmoothnessUkm();
if (shmem.IsValid()) {
web_frame_->Client()->SetUpSharedMemoryForSmoothness(
std::move(shmem));
@@ -585,7 +475,7 @@ void LocalFrameClientImpl::BeginNavigation(
NavigationPolicy policy,
WebFrameLoadType frame_load_type,
bool is_client_redirect,
- TriggeringEventInfo triggering_event_info,
+ mojom::blink::TriggeringEventInfo triggering_event_info,
HTMLFormElement* form,
network::mojom::CSPDisposition
should_check_main_world_content_security_policy,
@@ -594,13 +484,19 @@ void LocalFrameClientImpl::BeginNavigation(
const String& href_translate,
const base::Optional<WebImpression>& impression,
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp,
- network::mojom::blink::CSPSourcePtr initiator_self_source,
network::mojom::IPAddressSpace initiator_address_space,
- mojo::PendingRemote<mojom::blink::NavigationInitiator>
- navigation_initiator) {
+ mojo::PendingRemote<mojom::blink::NavigationInitiator> navigation_initiator,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle) {
if (!web_frame_->Client())
return;
+ // |initiator_frame_token| and |initiator_policy_container_keep_alive_handle|
+ // should either be both specified or both null.
+ DCHECK(!initiator_frame_token ==
+ !initiator_policy_container_keep_alive_handle);
+
auto navigation_info = std::make_unique<WebNavigationInfo>();
navigation_info->url_request.CopyFrom(WrappedResourceRequest(request));
navigation_info->frame_type = frame_type;
@@ -614,20 +510,35 @@ void LocalFrameClientImpl::BeginNavigation(
should_check_main_world_content_security_policy;
navigation_info->blob_url_token = std::move(blob_url_token);
navigation_info->input_start = input_start_time;
+ navigation_info->initiator_frame_token =
+ base::OptionalFromPtr(initiator_frame_token);
+ navigation_info->initiator_policy_container_keep_alive_handle =
+ std::move(initiator_policy_container_keep_alive_handle);
if (origin_window && origin_window->GetFrame()) {
- navigation_info->initiator_frame =
- origin_window->GetFrame()->Client()->GetWebFrame();
+ // Many navigation paths do not pass an |initiator_frame_token|, so we need
+ // to compute it here.
+ if (!navigation_info->initiator_frame_token) {
+ navigation_info->initiator_frame_token =
+ origin_window->GetFrame()->GetLocalFrameToken();
+ }
+ // Similarly, many navigation paths do not pass an
+ // |initiator_policy_container_keep_alive_handle|.
+ if (!navigation_info->initiator_policy_container_keep_alive_handle) {
+ navigation_info->initiator_policy_container_keep_alive_handle =
+ origin_window->GetFrame()
+ ->GetPolicyContainer()
+ ->IssueKeepAliveHandle();
+ }
} else {
- navigation_info->initiator_frame = nullptr;
+ // TODO(https://crbug.com/1173409 and https://crbug.com/1059959): Check that
+ // we always pass an |initiator_frame_token| and an
+ // |initiator_policy_container_keep_alive_handle| if |origin_window| is not
+ // set.
}
for (auto& csp_policy : initiator_csp) {
navigation_info->initiator_csp.emplace_back(
ConvertToPublic(std::move(csp_policy)));
}
- if (initiator_self_source) {
- navigation_info->initiator_self_source =
- ConvertToPublic(std::move(initiator_self_source));
- }
navigation_info->initiator_address_space = initiator_address_space;
navigation_info->navigation_initiator_remote =
std::move(navigation_initiator);
@@ -715,6 +626,18 @@ void LocalFrameClientImpl::BeginNavigation(
navigation_info->frame_policy =
owner ? owner->GetFramePolicy() : FramePolicy();
+ // owner->GetFramePolicy() above only contains the sandbox flags defined by
+ // the <iframe> element. It doesn't take into account inheritance from the
+ // parent or the opener. This is not a problem in the general case, because
+ // this attribute is simply dropped! It matter only for the "fake" navigation
+ // to the "fake" initial empty document. It is:
+ // RenderFrameImpl::CommitInitialEmptyDocument().
+ // This one doesn't go toward the browser process, it commits synchronously.
+ // The sandbox flags must be defined. They correspond to the one already in
+ // use for the 'real' initial empty document.
+ navigation_info->frame_policy.sandbox_flags =
+ web_frame_->GetFrame()->Loader().PendingEffectiveSandboxFlags();
+
navigation_info->href_translate = href_translate;
web_frame_->Client()->BeginNavigation(std::move(navigation_info));
@@ -802,6 +725,12 @@ void LocalFrameClientImpl::DidObserveLayoutShift(double score,
client->DidObserveLayoutShift(score, after_input_or_scroll);
}
+void LocalFrameClientImpl::DidObserveInputForLayoutShiftTracking(
+ base::TimeTicks timestamp) {
+ if (WebLocalFrameClient* client = web_frame_->Client())
+ client->DidObserveInputForLayoutShiftTracking(timestamp);
+}
+
void LocalFrameClientImpl::DidObserveLayoutNg(uint32_t all_block_count,
uint32_t ng_block_count,
uint32_t all_call_count,
@@ -967,17 +896,6 @@ void LocalFrameClientImpl::DidChangeName(const String& name) {
web_frame_->Client()->DidChangeName(name);
}
-void LocalFrameClientImpl::DidSetFramePolicyHeaders(
- network::mojom::blink::WebSandboxFlags sandbox_flags,
- const ParsedFeaturePolicy& feature_policy_header,
- const DocumentPolicyFeatureState& document_policy_header) {
- if (web_frame_->Client()) {
- web_frame_->Client()->DidSetFramePolicyHeaders(
- static_cast<network::mojom::blink::WebSandboxFlags>(sandbox_flags),
- feature_policy_header, document_policy_header);
- }
-}
-
std::unique_ptr<WebServiceWorkerProvider>
LocalFrameClientImpl::CreateServiceWorkerProvider() {
if (!web_frame_->Client())
@@ -1086,13 +1004,9 @@ Frame* LocalFrameClientImpl::FindFrame(const AtomicString& name) const {
return ToCoreFrame(web_frame_->Client()->FindFrame(name));
}
-void LocalFrameClientImpl::FrameRectsChanged(const IntRect& frame_rect) {
- DCHECK(web_frame_->Client());
- web_frame_->Client()->FrameRectsChanged(frame_rect);
-}
-
void LocalFrameClientImpl::FocusedElementChanged(Element* element) {
DCHECK(web_frame_->Client());
+ web_frame_->ResetHasScrolledFocusedEditableIntoView();
web_frame_->Client()->FocusedElementChanged(element);
}
@@ -1102,6 +1016,16 @@ void LocalFrameClientImpl::OnMainFrameIntersectionChanged(
web_frame_->Client()->OnMainFrameIntersectionChanged(intersection_rect);
}
+void LocalFrameClientImpl::OnOverlayPopupAdDetected() {
+ DCHECK(web_frame_->Client());
+ web_frame_->Client()->OnOverlayPopupAdDetected();
+}
+
+void LocalFrameClientImpl::OnLargeStickyAdDetected() {
+ DCHECK(web_frame_->Client());
+ web_frame_->Client()->OnLargeStickyAdDetected();
+}
+
bool LocalFrameClientImpl::IsPluginHandledExternally(
HTMLPlugInElement& plugin_element,
const KURL& resource_url,
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index 537639f6b78..df94fc2462d 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -64,7 +64,6 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
// LocalFrameClient ----------------------------------------------
WebContentCaptureClient* GetWebContentCaptureClient() const override;
- void DidCreateInitialEmptyDocument() override;
void DidCommitDocumentReplacementNavigation(DocumentLoader*) override;
// Notifies the WebView delegate that the JS window object has been cleared,
// giving it a chance to bind native objects to the window before script
@@ -93,12 +92,16 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
void DispatchDidHandleOnloadEvents() override;
void DidFinishSameDocumentNavigation(HistoryItem*,
WebHistoryCommitType,
- bool content_initiated) override;
+ bool content_initiated,
+ bool is_history_api_navigation) override;
void DispatchDidReceiveTitle(const String&) override;
void DispatchDidCommitLoad(
HistoryItem*,
WebHistoryCommitType,
- bool should_reset_browser_interface_broker) override;
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const blink::ParsedFeaturePolicy& feature_policy_header,
+ const blink::DocumentPolicyFeatureState& document_policy_header) override;
void DispatchDidFailLoad(const ResourceError&, WebHistoryCommitType) override;
void DispatchDidFinishDocumentLoad() override;
void DispatchDidFinishLoad() override;
@@ -112,7 +115,7 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
NavigationPolicy,
WebFrameLoadType,
bool is_client_redirect,
- TriggeringEventInfo,
+ mojom::blink::TriggeringEventInfo,
HTMLFormElement*,
network::mojom::CSPDisposition should_bypass_main_world_csp,
mojo::PendingRemote<mojom::blink::BlobURLToken>,
@@ -121,9 +124,11 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
const base::Optional<WebImpression>& impression,
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
initiator_csp,
- network::mojom::blink::CSPSourcePtr initiator_self_source,
network::mojom::IPAddressSpace,
- mojo::PendingRemote<mojom::blink::NavigationInitiator>) override;
+ mojo::PendingRemote<mojom::blink::NavigationInitiator>,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle) override;
void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
void DidStartLoading() override;
void DidStopLoading() override;
@@ -136,6 +141,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
void DidObserveNewFeatureUsage(mojom::WebFeature) override;
void DidObserveNewCssPropertyUsage(mojom::CSSSampleId, bool) override;
void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
+ void DidObserveInputForLayoutShiftTracking(
+ base::TimeTicks timestamp) override;
void DidObserveLayoutNg(uint32_t all_block_count,
uint32_t ng_block_count,
uint32_t all_call_count,
@@ -190,10 +197,6 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
bool AllowContentInitiatedDataUrlNavigations(const KURL&) override;
void DidChangeName(const String&) override;
- void DidSetFramePolicyHeaders(
- network::mojom::blink::WebSandboxFlags,
- const ParsedFeaturePolicy& fp_header,
- const blink::DocumentPolicyFeatureState& dp_header) override;
std::unique_ptr<WebServiceWorkerProvider> CreateServiceWorkerProvider()
override;
@@ -236,13 +239,15 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
Frame* FindFrame(const AtomicString& name) const override;
- void FrameRectsChanged(const IntRect&) override;
-
void FocusedElementChanged(Element* element) override;
void OnMainFrameIntersectionChanged(
const IntRect& intersection_rect) override;
+ void OnOverlayPopupAdDetected() override;
+
+ void OnLargeStickyAdDetected() override;
+
bool IsPluginHandledExternally(HTMLPlugInElement&,
const KURL&,
const String&) override;
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
index 2b843d77e5f..a78fc3a470f 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -11,6 +11,7 @@
#include "cc/metrics/begin_main_frame_metrics.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -52,6 +53,13 @@ LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
recorder_(recorder),
clock_(base::DefaultTickClock::GetInstance()),
event_name_("Blink.UpdateTime") {
+ // All of these are assumed to have one entry per sub-metric.
+ DCHECK_EQ(base::size(absolute_metric_records_), metrics_data().size());
+ DCHECK_EQ(base::size(current_sample_.sub_metrics_durations),
+ metrics_data().size());
+ DCHECK_EQ(base::size(current_sample_.sub_main_frame_durations),
+ metrics_data().size());
+
// Record average and worst case for the primary metric.
primary_metric_.reset();
@@ -71,13 +79,13 @@ LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
const char* const uma_pre_fcp_aggregated_postscript = ".AggregatedPreFCP";
// Populate all the sub-metrics.
- absolute_metric_records_.ReserveInitialCapacity(kCount);
+ size_t metric_index = 0;
for (const MetricInitializationData& metric_data : metrics_data()) {
// Absolute records report the absolute time for each metric per frame.
// They also aggregate the time spent in each stage between navigation
// (LocalFrameView resets) and First Contentful Paint.
// They have an associated UMA too that we own and allocate here.
- auto& absolute_record = absolute_metric_records_.emplace_back();
+ auto& absolute_record = absolute_metric_records_[metric_index];
absolute_record.reset();
absolute_record.pre_fcp_aggregate = base::TimeDelta();
if (metric_data.has_uma) {
@@ -101,12 +109,9 @@ LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
absolute_record.uma_aggregate_counter.reset(new CustomCountHistogram(
aggregated_uma_name.ToString().Utf8().c_str(), 0, 10000000, 50));
}
- }
- // Make space in the current sample.
- current_sample_.sub_metrics_durations.Grow(static_cast<wtf_size_t>(kCount));
- current_sample_.sub_main_frame_durations.Grow(
- static_cast<wtf_size_t>(kCount));
+ metric_index++;
+ }
}
LocalFrameUkmAggregator::~LocalFrameUkmAggregator() {
@@ -174,22 +179,6 @@ void LocalFrameUkmAggregator::SetTickClockForTesting(
clock_ = clock;
}
-void LocalFrameUkmAggregator::RecordForcedStyleLayoutUMA(
- base::TimeDelta& duration) {
- if (!calls_to_next_forced_style_layout_uma_) {
- auto& record = absolute_metric_records_[kForcedStyleAndLayout];
- if (fcp_state_ == kHavePassedFCP)
- record.post_fcp_uma_counter->CountMicroseconds(duration);
- else
- record.pre_fcp_uma_counter->CountMicroseconds(duration);
- calls_to_next_forced_style_layout_uma_ =
- base::RandInt(0, mean_calls_between_forced_style_layout_uma_ * 2);
- } else {
- DCHECK_GT(calls_to_next_forced_style_layout_uma_, 0u);
- --calls_to_next_forced_style_layout_uma_;
- }
-}
-
void LocalFrameUkmAggregator::DidReachFirstContentfulPaint(
bool are_painting_main_frame) {
DCHECK(fcp_state_ != kHavePassedFCP);
@@ -205,11 +194,15 @@ void LocalFrameUkmAggregator::DidReachFirstContentfulPaint(
void LocalFrameUkmAggregator::RecordSample(size_t metric_index,
base::TimeTicks start,
base::TimeTicks end) {
+ // Always use RecordForcedLayoutSample for the kForcedStyleAndLayout
+ // metric id.
+ DCHECK_NE(metric_index, static_cast<size_t>(kForcedStyleAndLayout));
+
base::TimeDelta duration = end - start;
bool is_pre_fcp = (fcp_state_ != kHavePassedFCP);
// Accumulate for UKM and record the UMA
- DCHECK_LT(metric_index, absolute_metric_records_.size());
+ DCHECK_LT(metric_index, base::size(absolute_metric_records_));
auto& record = absolute_metric_records_[metric_index];
record.interval_duration += duration;
if (in_main_frame_update_)
@@ -221,14 +214,118 @@ void LocalFrameUkmAggregator::RecordSample(size_t metric_index,
// the signed 32 counter for number of events in a 30 minute period. So
// randomly record with probability 1/100.
if (record.pre_fcp_uma_counter) {
- if (metric_index == static_cast<size_t>(kForcedStyleAndLayout)) {
- RecordForcedStyleLayoutUMA(duration);
+ if (is_pre_fcp) {
+ record.pre_fcp_uma_counter->CountMicroseconds(duration);
} else {
- if (is_pre_fcp) {
- record.pre_fcp_uma_counter->CountMicroseconds(duration);
- } else {
- record.post_fcp_uma_counter->CountMicroseconds(duration);
- }
+ record.post_fcp_uma_counter->CountMicroseconds(duration);
+ }
+ }
+}
+
+void LocalFrameUkmAggregator::RecordForcedLayoutSample(
+ DocumentUpdateReason reason,
+ base::TimeTicks start,
+ base::TimeTicks end) {
+ base::TimeDelta duration = end - start;
+ bool is_pre_fcp = (fcp_state_ != kHavePassedFCP);
+
+ // Accumulate for UKM always, but only record the UMA for a subset of cases to
+ // avoid overflowing the counters.
+ bool should_report_uma_this_frame = !calls_to_next_forced_style_layout_uma_;
+ if (should_report_uma_this_frame) {
+ calls_to_next_forced_style_layout_uma_ =
+ base::RandInt(0, mean_calls_between_forced_style_layout_uma_ * 2);
+ } else {
+ DCHECK_GT(calls_to_next_forced_style_layout_uma_, 0u);
+ --calls_to_next_forced_style_layout_uma_;
+ }
+
+ auto& record =
+ absolute_metric_records_[static_cast<size_t>(kForcedStyleAndLayout)];
+ record.interval_duration += duration;
+ if (in_main_frame_update_)
+ record.main_frame_duration += duration;
+ if (is_pre_fcp)
+ record.pre_fcp_aggregate += duration;
+
+ if (should_report_uma_this_frame) {
+ if (is_pre_fcp)
+ record.pre_fcp_uma_counter->CountMicroseconds(duration);
+ else
+ record.post_fcp_uma_counter->CountMicroseconds(duration);
+ }
+
+ // Record a variety of DocumentUpdateReasons as distinct metrics
+ // Figure out which sub-metric, if any, we wish to report for UKM.
+ MetricId sub_metric = kCount;
+ switch (reason) {
+ case DocumentUpdateReason::kContextMenu:
+ case DocumentUpdateReason::kDragImage:
+ case DocumentUpdateReason::kEditing:
+ case DocumentUpdateReason::kFindInPage:
+ case DocumentUpdateReason::kFocus:
+ case DocumentUpdateReason::kForm:
+ case DocumentUpdateReason::kInput:
+ case DocumentUpdateReason::kInspector:
+ case DocumentUpdateReason::kPrinting:
+ case DocumentUpdateReason::kSelection:
+ case DocumentUpdateReason::kSpatialNavigation:
+ case DocumentUpdateReason::kTapHighlight:
+ sub_metric = kUserDrivenDocumentUpdate;
+ break;
+
+ case DocumentUpdateReason::kAccessibility:
+ case DocumentUpdateReason::kBaseColor:
+ case DocumentUpdateReason::kDisplayLock:
+ case DocumentUpdateReason::kIntersectionObservation:
+ case DocumentUpdateReason::kOverlay:
+ case DocumentUpdateReason::kPagePopup:
+ case DocumentUpdateReason::kSizeChange:
+ case DocumentUpdateReason::kSpellCheck:
+ sub_metric = kServiceDocumentUpdate;
+ break;
+
+ case DocumentUpdateReason::kCanvas:
+ case DocumentUpdateReason::kPlugin:
+ case DocumentUpdateReason::kSVGImage:
+ sub_metric = kContentDocumentUpdate;
+ break;
+
+ case DocumentUpdateReason::kScroll:
+ sub_metric = kScrollDocumentUpdate;
+ break;
+
+ case DocumentUpdateReason::kHitTest:
+ sub_metric = kHitTestDocumentUpdate;
+ break;
+
+ case DocumentUpdateReason::kJavaScript:
+ sub_metric = kJavascriptDocumentUpdate;
+ break;
+
+ // Do not report main frame because we have it already from
+ // in_main_frame_update_ above.
+ case DocumentUpdateReason::kBeginMainFrame:
+ // No metrics from testing.
+ case DocumentUpdateReason::kTest:
+ // Don't report if we don't know why.
+ case DocumentUpdateReason::kUnknown:
+ break;
+ }
+
+ if (sub_metric != kCount) {
+ auto& sub_record =
+ absolute_metric_records_[static_cast<size_t>(sub_metric)];
+ sub_record.interval_duration += duration;
+ if (in_main_frame_update_)
+ sub_record.main_frame_duration += duration;
+ if (is_pre_fcp)
+ sub_record.pre_fcp_aggregate += duration;
+ if (should_report_uma_this_frame) {
+ if (is_pre_fcp)
+ sub_record.pre_fcp_uma_counter->CountMicroseconds(duration);
+ else
+ sub_record.post_fcp_uma_counter->CountMicroseconds(duration);
}
}
}
@@ -328,7 +425,7 @@ void LocalFrameUkmAggregator::UpdateEventTimeAndUpdateSampleIfNeeded(
void LocalFrameUkmAggregator::UpdateSample(
cc::ActiveFrameSequenceTrackers trackers) {
current_sample_.primary_metric_duration = primary_metric_.interval_duration;
- for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) {
+ for (size_t i = 0; i < metrics_data().size(); ++i) {
current_sample_.sub_metrics_durations[i] =
absolute_metric_records_[i].interval_duration;
current_sample_.sub_main_frame_durations[i] =
@@ -347,7 +444,7 @@ void LocalFrameUkmAggregator::ReportPreFCPEvent() {
builder.SetMainFrame(primary_metric_.pre_fcp_aggregate.InMicroseconds());
primary_metric_.uma_aggregate_counter->CountMicroseconds(
primary_metric_.pre_fcp_aggregate);
- for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) {
+ for (size_t i = 0; i < metrics_data().size(); ++i) {
auto& absolute_record = absolute_metric_records_[i];
if (absolute_record.uma_aggregate_counter) {
absolute_record.uma_aggregate_counter->CountMicroseconds(
@@ -365,7 +462,6 @@ void LocalFrameUkmAggregator::ReportPreFCPEvent() {
CASE_FOR_ID(Style);
CASE_FOR_ID(Layout);
CASE_FOR_ID(ForcedStyleAndLayout);
- CASE_FOR_ID(HitTestDocumentUpdate);
CASE_FOR_ID(HandleInputEvents);
CASE_FOR_ID(Animate);
CASE_FOR_ID(UpdateLayers);
@@ -374,6 +470,13 @@ void LocalFrameUkmAggregator::ReportPreFCPEvent() {
CASE_FOR_ID(JavascriptIntersectionObserver);
CASE_FOR_ID(LazyLoadIntersectionObserver);
CASE_FOR_ID(MediaIntersectionObserver);
+ CASE_FOR_ID(UpdateViewportIntersection);
+ CASE_FOR_ID(UserDrivenDocumentUpdate);
+ CASE_FOR_ID(ServiceDocumentUpdate);
+ CASE_FOR_ID(ContentDocumentUpdate);
+ CASE_FOR_ID(ScrollDocumentUpdate);
+ CASE_FOR_ID(HitTestDocumentUpdate);
+ CASE_FOR_ID(JavascriptDocumentUpdate);
case kCount:
case kMainFrame:
NOTREACHED();
@@ -403,7 +506,7 @@ void LocalFrameUkmAggregator::ReportUpdateTimeEvent() {
current_sample_.primary_metric_duration.InMicroseconds());
builder.SetMainFrameIsBeforeFCP(fcp_state_ != kHavePassedFCP);
builder.SetMainFrameReasons(current_sample_.trackers);
- for (unsigned i = 0; i < static_cast<unsigned>(kCount); ++i) {
+ for (size_t i = 0; i < metrics_data().size(); ++i) {
switch (static_cast<MetricId>(i)) {
CASE_FOR_ID(CompositingAssignments, i);
CASE_FOR_ID(CompositingCommit, i);
@@ -415,7 +518,6 @@ void LocalFrameUkmAggregator::ReportUpdateTimeEvent() {
CASE_FOR_ID(Style, i);
CASE_FOR_ID(Layout, i);
CASE_FOR_ID(ForcedStyleAndLayout, i);
- CASE_FOR_ID(HitTestDocumentUpdate, i);
CASE_FOR_ID(HandleInputEvents, i);
CASE_FOR_ID(Animate, i);
CASE_FOR_ID(UpdateLayers, i);
@@ -424,6 +526,13 @@ void LocalFrameUkmAggregator::ReportUpdateTimeEvent() {
CASE_FOR_ID(JavascriptIntersectionObserver, i);
CASE_FOR_ID(LazyLoadIntersectionObserver, i);
CASE_FOR_ID(MediaIntersectionObserver, i);
+ CASE_FOR_ID(UpdateViewportIntersection, i);
+ CASE_FOR_ID(UserDrivenDocumentUpdate, i);
+ CASE_FOR_ID(ServiceDocumentUpdate, i);
+ CASE_FOR_ID(ContentDocumentUpdate, i);
+ CASE_FOR_ID(ScrollDocumentUpdate, i);
+ CASE_FOR_ID(HitTestDocumentUpdate, i);
+ CASE_FOR_ID(JavascriptDocumentUpdate, i);
case kCount:
case kMainFrame:
NOTREACHED();
@@ -444,13 +553,13 @@ void LocalFrameUkmAggregator::ResetAllMetrics() {
}
bool LocalFrameUkmAggregator::AllMetricsAreZero() {
- if (primary_metric_.interval_duration.InMicroseconds())
+ if (!primary_metric_.interval_duration.is_zero())
return false;
for (auto& record : absolute_metric_records_) {
- if (record.interval_duration.InMicroseconds()) {
+ if (!record.interval_duration.is_zero()) {
return false;
}
- if (record.main_frame_duration.InMicroseconds()) {
+ if (!record.main_frame_duration.is_zero()) {
return false;
}
}
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
index c7e12bae1b2..13019c9b664 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -25,6 +25,8 @@ class UkmRecorder;
namespace blink {
+enum class DocumentUpdateReason;
+
// This class aggregaties and records time based UKM and UMA metrics
// for LocalFrameView. The simplest way to use it is via the
// SCOPED_UMA_AND_UKM_TIMER macro combined with
@@ -129,8 +131,6 @@ class CORE_EXPORT LocalFrameUkmAggregator
kPrePaint,
kStyle,
kLayout,
- kForcedStyleAndLayout,
- kHitTestDocumentUpdate,
kHandleInputEvents,
kAnimate,
kUpdateLayers,
@@ -139,6 +139,14 @@ class CORE_EXPORT LocalFrameUkmAggregator
kJavascriptIntersectionObserver,
kLazyLoadIntersectionObserver,
kMediaIntersectionObserver,
+ kUpdateViewportIntersection,
+ kForcedStyleAndLayout,
+ kContentDocumentUpdate,
+ kHitTestDocumentUpdate,
+ kJavascriptDocumentUpdate,
+ kScrollDocumentUpdate,
+ kServiceDocumentUpdate,
+ kUserDrivenDocumentUpdate,
kCount,
kMainFrame
};
@@ -166,8 +174,6 @@ class CORE_EXPORT LocalFrameUkmAggregator
{"PrePaint", true},
{"Style", true},
{"Layout", true},
- {"ForcedStyleAndLayout", true},
- {"HitTestDocumentUpdate", true},
{"HandleInputEvents", true},
{"Animate", true},
{"UpdateLayers", false},
@@ -175,7 +181,15 @@ class CORE_EXPORT LocalFrameUkmAggregator
{"DisplayLockIntersectionObserver", true},
{"JavascriptIntersectionObserver", true},
{"LazyLoadIntersectionObserver", true},
- {"MediaIntersectionObserver", true}};
+ {"MediaIntersectionObserver", true},
+ {"UpdateViewportIntersection", true},
+ {"ForcedStyleAndLayout", true},
+ {"ContentDocumentUpdate", true},
+ {"HitTestDocumentUpdate", true},
+ {"JavascriptDocumentUpdate", true},
+ {"ScrollDocumentUpdate", true},
+ {"ServiceDocumentUpdate", true},
+ {"UserDrivenDocumentUpdate", true}};
static_assert(base::size(data) == kCount, "Metrics data mismatch");
return data;
}
@@ -230,6 +244,13 @@ class CORE_EXPORT LocalFrameUkmAggregator
base::TimeTicks start,
base::TimeTicks end);
+ // Record a ForcedLayout sample. The reason will determine which, if any,
+ // additional metrics are reported in order to diagnose the cause of
+ // ForcedLayout regressions.
+ void RecordForcedLayoutSample(DocumentUpdateReason reason,
+ base::TimeTicks start,
+ base::TimeTicks end);
+
// Record a sample for the impl-side compositor processing.
// - requested is the time the renderer proxy requests a commit
// - started is the time the impl thread begins processing the request
@@ -278,8 +299,8 @@ class CORE_EXPORT LocalFrameUkmAggregator
struct SampleToRecord {
base::TimeDelta primary_metric_duration;
- Vector<base::TimeDelta> sub_metrics_durations;
- Vector<base::TimeDelta> sub_main_frame_durations;
+ std::array<base::TimeDelta, kCount> sub_metrics_durations;
+ std::array<base::TimeDelta, kCount> sub_main_frame_durations;
cc::ActiveFrameSequenceTrackers trackers;
};
@@ -297,9 +318,6 @@ class CORE_EXPORT LocalFrameUkmAggregator
// frame after First Contentful Paint.
void ReportPreFCPEvent();
- // Implements throttling of the ForcedStyleAndLayoutUMA metric.
- void RecordForcedStyleLayoutUMA(base::TimeDelta& duration);
-
// To test event sampling. Controls whether we update the current sample
// on the next frame, or do not. Values persist until explicitly changed.
void ChooseNextFrameForTest();
@@ -320,7 +338,7 @@ class CORE_EXPORT LocalFrameUkmAggregator
// Event and metric data
const char* const event_name_;
AbsoluteMetricRecord primary_metric_;
- Vector<AbsoluteMetricRecord> absolute_metric_records_;
+ std::array<AbsoluteMetricRecord, kCount> absolute_metric_records_;
// The current sample to report. When RecordEvent() is called we
// check for uniform_random[0,1) < 1 / n where n is the number of frames
@@ -334,7 +352,7 @@ class CORE_EXPORT LocalFrameUkmAggregator
unsigned frames_since_last_report_ = 0;
// Control for the ForcedStyleAndUpdate UMA metric sampling
- unsigned mean_calls_between_forced_style_layout_uma_ = 100;
+ unsigned mean_calls_between_forced_style_layout_uma_ = 500;
unsigned calls_to_next_forced_style_layout_uma_ = 0;
// Set by BeginMainFrame() and cleared in RecordMEndOfFrameMetrics.
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
index 930b6dcb5dd..b02feae721f 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
@@ -8,6 +8,7 @@
#include "cc/metrics/begin_main_frame_metrics.h"
#include "components/ukm/test_ukm_recorder.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/metrics/document_update_reason.h"
namespace blink {
@@ -18,9 +19,7 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
void SetUp() override {
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
- aggregator_ = base::MakeRefCounted<LocalFrameUkmAggregator>(
- ukm::UkmRecorder::GetNewSourceID(), &recorder_);
- aggregator_->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
+ RestartAggregator();
}
void TearDown() override {
@@ -35,6 +34,11 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
ukm::TestUkmRecorder& recorder() { return recorder_; }
void ResetAggregator() { aggregator_.reset(); }
+ void RestartAggregator() {
+ aggregator_ = base::MakeRefCounted<LocalFrameUkmAggregator>(
+ ukm::UkmRecorder::GetNewSourceID(), &recorder_);
+ aggregator_->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
+ }
std::string GetPrimaryMetricName() {
return LocalFrameUkmAggregator::primary_metric_name();
@@ -73,7 +77,10 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
const int64_t* primary_metric_value =
ukm::TestUkmRecorder::GetEntryMetric(entry, GetPrimaryMetricName());
EXPECT_NEAR(*primary_metric_value / 1e3, expected_primary_metric, 0.001);
- for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
+ // All tests using this method check through kForcedStyleAndLayout because
+ // kForcedStyleAndLayout and subsequent metrics report and record
+ // differently.
+ for (int i = 0; i < LocalFrameUkmAggregator::kForcedStyleAndLayout; ++i) {
EXPECT_TRUE(
ukm::TestUkmRecorder::EntryHasMetric(entry, GetMetricName(i)));
const int64_t* metric_value =
@@ -110,7 +117,10 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
const int64_t* primary_metric_value =
ukm::TestUkmRecorder::GetEntryMetric(entry, GetPrimaryMetricName());
EXPECT_NEAR(*primary_metric_value / 1e3, expected_primary_metric, 0.001);
- for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
+ // All tests using this method check through kForcedStyleAndLayout because
+ // kForcedStyleAndLayout and subsequent metrics report and record
+ // differently.
+ for (int i = 0; i < LocalFrameUkmAggregator::kForcedStyleAndLayout; ++i) {
EXPECT_TRUE(
ukm::TestUkmRecorder::EntryHasMetric(entry, GetMetricName(i)));
const int64_t* metric_value =
@@ -125,7 +135,10 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
cc::ActiveFrameSequenceTrackers trackers,
bool mark_fcp = false) {
aggregator().BeginMainFrame();
- for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
+ // All tests using this method run through kForcedStyleAndLayout because
+ // kForcedStyleAndLayout is not reported using a ScopedTimer and the
+ // subsequent metrics are reported as part of kForcedStyleAndLayout.
+ for (int i = 0; i < LocalFrameUkmAggregator::kForcedStyleAndLayout; ++i) {
auto timer = aggregator().GetScopedTimer(i);
if (mark_fcp && i == static_cast<int>(LocalFrameUkmAggregator::kPaint))
aggregator().DidReachFirstContentfulPaint(true);
@@ -136,13 +149,60 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
}
void SimulatePreFrame(unsigned millisecond_per_step) {
- for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
+ // All tests using this method run through kForcedStyleAndLayout because
+ // kForcedStyleAndLayout is not reported using a ScopedTimer and the
+ // subsequent metrics are reported as part of kForcedStyleAndLayout.
+ for (int i = 0; i < LocalFrameUkmAggregator::kForcedStyleAndLayout; ++i) {
auto timer = aggregator().GetScopedTimer(i);
test_task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(millisecond_per_step));
}
}
+ void SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason reason,
+ LocalFrameUkmAggregator::MetricId target_metric,
+ unsigned expected_num_entries) {
+ base::TimeTicks start_time = Now();
+ test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(10));
+ base::TimeTicks end_time = Now();
+
+ aggregator().BeginMainFrame();
+ aggregator().RecordForcedLayoutSample(reason, start_time, end_time);
+ aggregator().RecordEndOfFrameMetrics(start_time, end_time, 0);
+ ResetAggregator();
+
+ EXPECT_EQ(recorder().entries_count(), expected_num_entries);
+ auto entries = recorder().GetEntriesByName("Blink.UpdateTime");
+ EXPECT_GT(entries.size(), expected_num_entries - 1);
+ auto* entry = entries[expected_num_entries - 1];
+
+ EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(
+ entry, GetMetricName(LocalFrameUkmAggregator::kForcedStyleAndLayout)));
+ const int64_t* metric_value = ukm::TestUkmRecorder::GetEntryMetric(
+ entry, GetMetricName(LocalFrameUkmAggregator::kForcedStyleAndLayout));
+ EXPECT_NEAR(*metric_value / 1e3, 10, 0.001);
+
+ if (target_metric != LocalFrameUkmAggregator::kCount) {
+ EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(
+ entry, GetMetricName(target_metric)));
+ metric_value = ukm::TestUkmRecorder::GetEntryMetric(
+ entry, GetMetricName(target_metric));
+ EXPECT_NEAR(*metric_value / 1e3, 10, 0.001);
+ }
+ for (int i = LocalFrameUkmAggregator::kForcedStyleAndLayout + 1;
+ i < LocalFrameUkmAggregator::kCount; ++i) {
+ if (i != target_metric) {
+ EXPECT_TRUE(
+ ukm::TestUkmRecorder::EntryHasMetric(entry, GetMetricName(i)));
+ metric_value =
+ ukm::TestUkmRecorder::GetEntryMetric(entry, GetMetricName(i));
+ EXPECT_EQ(*metric_value, 0);
+ }
+ }
+ RestartAggregator();
+ }
+
bool SampleMatchesIteration(int64_t iteration_count) {
return aggregator()
.current_sample_.sub_metrics_durations[0]
@@ -192,7 +252,7 @@ TEST_F(LocalFrameUkmAggregatorTest, FirstFrameIsRecorded) {
EXPECT_EQ(recorder().entries_count(), 1u);
float expected_primary_metric =
- millisecond_for_step * LocalFrameUkmAggregator::kCount;
+ millisecond_for_step * LocalFrameUkmAggregator::kForcedStyleAndLayout;
float expected_sub_metric = millisecond_for_step;
float expected_begin_main_frame = millisecond_for_step;
@@ -215,7 +275,7 @@ TEST_F(LocalFrameUkmAggregatorTest, PreFrameWorkIsRecorded) {
unsigned millisecond_for_step = 1;
base::TimeTicks start_time =
Now() + base::TimeDelta::FromMilliseconds(millisecond_for_step) *
- LocalFrameUkmAggregator::kCount;
+ LocalFrameUkmAggregator::kForcedStyleAndLayout;
SimulatePreFrame(millisecond_for_step);
SimulateFrame(start_time, millisecond_for_step, 12);
@@ -227,7 +287,7 @@ TEST_F(LocalFrameUkmAggregatorTest, PreFrameWorkIsRecorded) {
EXPECT_EQ(recorder().entries_count(), 1u);
float expected_primary_metric =
- millisecond_for_step * LocalFrameUkmAggregator::kCount;
+ millisecond_for_step * LocalFrameUkmAggregator::kForcedStyleAndLayout;
float expected_sub_metric = millisecond_for_step * 2;
float expected_begin_main_frame = millisecond_for_step;
@@ -247,7 +307,8 @@ TEST_F(LocalFrameUkmAggregatorTest, PreAndPostFCPAreRecorded) {
// The initial interval is always zero, so we should see one set of metrics
// for the initial frame, regardless of the initial interval.
base::TimeTicks start_time = Now();
- unsigned millisecond_per_step = 50 / (LocalFrameUkmAggregator::kCount + 1);
+ unsigned millisecond_per_step =
+ 50 / (LocalFrameUkmAggregator::kForcedStyleAndLayout + 1);
SimulateFrame(start_time, millisecond_per_step, 4, true);
// We marked FCP when we simulated, so we should report something. There
@@ -255,7 +316,7 @@ TEST_F(LocalFrameUkmAggregatorTest, PreAndPostFCPAreRecorded) {
EXPECT_EQ(recorder().entries_count(), 2u);
float expected_primary_metric =
- millisecond_per_step * LocalFrameUkmAggregator::kCount;
+ millisecond_per_step * LocalFrameUkmAggregator::kForcedStyleAndLayout;
float expected_sub_metric = millisecond_per_step;
float expected_begin_main_frame = millisecond_per_step;
@@ -266,7 +327,7 @@ TEST_F(LocalFrameUkmAggregatorTest, PreAndPostFCPAreRecorded) {
// fcp frame. A failure here iundicates that we did not reset the frame,
// or that we are incorrectly tracking pre/post fcp.
unsigned millisecond_per_frame =
- millisecond_per_step * LocalFrameUkmAggregator::kCount;
+ millisecond_per_step * LocalFrameUkmAggregator::kForcedStyleAndLayout;
start_time = Now();
SimulateFrame(start_time, millisecond_per_step, 4);
@@ -294,9 +355,10 @@ TEST_F(LocalFrameUkmAggregatorTest, AggregatedPreFCPEventRecorded) {
// Be sure to not choose the next frame. We shouldn't need to record an
// UpdateTime metric in order to record an aggregated metric.
DoNotChooseNextFrameForTest();
- unsigned millisecond_per_step = 50 / (LocalFrameUkmAggregator::kCount + 1);
+ unsigned millisecond_per_step =
+ 50 / (LocalFrameUkmAggregator::kForcedStyleAndLayout + 1);
unsigned millisecond_per_frame =
- millisecond_per_step * (LocalFrameUkmAggregator::kCount);
+ millisecond_per_step * (LocalFrameUkmAggregator::kForcedStyleAndLayout);
base::TimeTicks start_time = Now();
SimulateFrame(start_time, millisecond_per_step, 3);
@@ -317,6 +379,106 @@ TEST_F(LocalFrameUkmAggregatorTest, AggregatedPreFCPEventRecorded) {
ResetAggregator();
}
+TEST_F(LocalFrameUkmAggregatorTest, ForcedLayoutReasonsReportOnlyMetric) {
+ // Although the tests use a mock clock, the UKM aggregator checks if the
+ // system has a high resolution clock before recording results. As a result,
+ // the tests will fail if the system does not have a high resolution clock.
+ if (!base::TimeTicks::IsHighResolution())
+ return;
+
+ // Test that every layout reason reports the expected UKM metric.
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kContextMenu,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 1u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kEditing,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 2u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kEditing,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 3u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kFindInPage,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 4u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kFocus,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 5u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kForm,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 6u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kInput,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 7u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kInspector,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 8u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kPrinting,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 9u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kSelection,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 10u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kSpatialNavigation,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 11u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kTapHighlight,
+ LocalFrameUkmAggregator::kUserDrivenDocumentUpdate, 12u);
+
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kAccessibility,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 13u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kBaseColor,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 14u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kDisplayLock,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 15u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kIntersectionObservation,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 16u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kOverlay,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 17u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kPagePopup,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 18u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kSizeChange,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 19u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kSpellCheck,
+ LocalFrameUkmAggregator::kServiceDocumentUpdate, 20u);
+
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kCanvas,
+ LocalFrameUkmAggregator::kContentDocumentUpdate, 21u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kPlugin,
+ LocalFrameUkmAggregator::kContentDocumentUpdate, 22u);
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kSVGImage,
+ LocalFrameUkmAggregator::kContentDocumentUpdate, 23u);
+
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kScroll,
+ LocalFrameUkmAggregator::kScrollDocumentUpdate, 24u);
+
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kHitTest,
+ LocalFrameUkmAggregator::kHitTestDocumentUpdate, 25u);
+
+ SimulateAndVerifyForcedLayoutReason(
+ DocumentUpdateReason::kJavaScript,
+ LocalFrameUkmAggregator::kJavascriptDocumentUpdate, 26u);
+
+ SimulateAndVerifyForcedLayoutReason(DocumentUpdateReason::kBeginMainFrame,
+ LocalFrameUkmAggregator::kCount, 27u);
+ SimulateAndVerifyForcedLayoutReason(DocumentUpdateReason::kTest,
+ LocalFrameUkmAggregator::kCount, 28u);
+ SimulateAndVerifyForcedLayoutReason(DocumentUpdateReason::kUnknown,
+ LocalFrameUkmAggregator::kCount, 29u);
+}
+
TEST_F(LocalFrameUkmAggregatorTest, LatencyDataIsPopulated) {
// Although the tests use a mock clock, the UKM aggregator checks if the
// system has a high resolution clock before recording results. As a result,
@@ -328,9 +490,9 @@ TEST_F(LocalFrameUkmAggregatorTest, LatencyDataIsPopulated) {
// because we need to populate before the end of the frame.
unsigned millisecond_for_step = 1;
aggregator().BeginMainFrame();
- for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
- auto timer =
- aggregator().GetScopedTimer(i % LocalFrameUkmAggregator::kCount);
+ for (int i = 0; i < LocalFrameUkmAggregator::kForcedStyleAndLayout; ++i) {
+ auto timer = aggregator().GetScopedTimer(
+ i % LocalFrameUkmAggregator::kForcedStyleAndLayout);
test_task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(millisecond_for_step));
}
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
index cd23c7cd570..0bae92b6617 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -46,13 +46,13 @@
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/animation/document_animations.h"
#include "third_party/blink/renderer/core/css/font_face_set_document.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/editing/compute_layer_selection.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
@@ -124,6 +124,7 @@
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
+#include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
#include "third_party/blink/renderer/core/paint/frame_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
@@ -256,14 +257,11 @@ LocalFrameView::LocalFrameView(LocalFrame& frame, IntRect frame_rect)
// updates. We can't throttle it here or it seems the root compositor
// doesn't get setup properly.
lifecycle_updates_throttled_(!GetFrame().IsMainFrame()),
- current_update_lifecycle_phases_target_state_(
- DocumentLifecycle::kUninitialized),
- past_layout_lifecycle_update_(false),
+ target_state_(DocumentLifecycle::kUninitialized),
suppress_adjust_view_size_(false),
intersection_observation_state_(kNotNeeded),
needs_forced_compositing_update_(false),
needs_focus_on_fragment_(false),
- in_lifecycle_update_(false),
main_thread_scrolling_reasons_(0),
forced_layout_stack_depth_(0),
forced_layout_start_time_(base::TimeTicks()),
@@ -292,6 +290,7 @@ LocalFrameView::~LocalFrameView() {
void LocalFrameView::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
+ visitor->Trace(update_plugins_timer_);
visitor->Trace(fragment_anchor_);
visitor->Trace(scrollable_areas_);
visitor->Trace(animating_scrollable_areas_);
@@ -416,6 +415,24 @@ void LocalFrameView::Dispose() {
if (viewport_scrollable_area_)
viewport_scrollable_area_->ClearScrollableArea();
+ // If we have scheduled plugins to be updated, cancel it. They will still be
+ // notified before they are destroyed.
+ if (update_plugins_timer_.IsActive())
+ update_plugins_timer_.Stop();
+ part_update_set_.clear();
+
+ // These are LayoutObjects whose layout has been deferred to a subsequent
+ // lifecycle update. Not gonna happen.
+ layout_subtree_root_list_.Clear();
+
+ // TODO(szager): LayoutObjects are supposed to remove themselves from these
+ // tracking groups when they update style or are destroyed, but sometimes they
+ // are missed. It would be good to understand how/why that happens, but in the
+ // mean time, it's not safe to keep pointers around to defunct LayoutObjects.
+ orthogonal_writing_mode_root_list_.Clear();
+ viewport_constrained_objects_.reset();
+ background_attachment_fixed_objects_.clear();
+
// Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing
// partially destroyed |this| via |m_autoSizeInfo->m_frameView|.
auto_size_info_.Clear();
@@ -581,12 +598,6 @@ void LocalFrameView::AdjustViewSizeAndLayout() {
}
}
-void LocalFrameView::UpdateCountersAfterStyleChange() {
- auto* layout_view = GetLayoutView();
- DCHECK(layout_view);
- layout_view->UpdateCounters();
-}
-
void LocalFrameView::CountObjectsNeedingLayout(unsigned& needs_layout_objects,
unsigned& total_objects,
bool& is_subtree) {
@@ -629,7 +640,7 @@ void LocalFrameView::PerformPreLayoutTasks() {
document->EvaluateMediaQueryList();
}
- document->UpdateStyleAndLayoutTree();
+ document->UpdateStyleAndLayoutTreeForThisDocument();
// Update style for all embedded SVG documents underneath this frame, so
// that intrinsic size computation for any embedded objects has up-to-date
@@ -637,7 +648,7 @@ void LocalFrameView::PerformPreLayoutTasks() {
ForAllChildLocalFrameViews([](LocalFrameView& view) {
Document& document = *view.GetFrame().GetDocument();
if (document.IsSVGDocument())
- document.UpdateStyleAndLayoutTree();
+ document.UpdateStyleAndLayoutTreeForThisDocument();
});
Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
@@ -763,8 +774,6 @@ void LocalFrameView::PerformLayout(bool in_subtree_layout) {
if (!LayoutFromRootObject(*root))
continue;
- root->PaintingLayer()->UpdateLayerPositionsAfterLayout();
-
// We need to ensure that we mark up all layoutObjects up to the
// LayoutView for paint invalidation. This simplifies our code as we
// just always do a full tree walk.
@@ -943,9 +952,6 @@ void LocalFrameView::UpdateLayout() {
frame_timing_requests_dirty_ = true;
- if (!in_subtree_layout)
- GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
-
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", this,
TracedLayoutObject::Create(*GetLayoutView(), true));
@@ -1011,14 +1017,8 @@ void LocalFrameView::DidFinishForcedLayout(DocumentUpdateReason reason) {
forced_layout_stack_depth_--;
if (!forced_layout_stack_depth_ && base::TimeTicks::IsHighResolution()) {
LocalFrameUkmAggregator& aggregator = EnsureUkmAggregator();
- aggregator.RecordSample(
- static_cast<size_t>(LocalFrameUkmAggregator::kForcedStyleAndLayout),
- forced_layout_start_time_, base::TimeTicks::Now());
- if (reason == DocumentUpdateReason::kHitTest) {
- aggregator.RecordSample(
- static_cast<size_t>(LocalFrameUkmAggregator::kHitTestDocumentUpdate),
- forced_layout_start_time_, base::TimeTicks::Now());
- }
+ aggregator.RecordForcedLayoutSample(reason, forced_layout_start_time_,
+ base::TimeTicks::Now());
}
}
@@ -1094,6 +1094,9 @@ DocumentLifecycle& LocalFrameView::Lifecycle() const {
void LocalFrameView::RunPostLifecycleSteps() {
AllowThrottlingScope allow_throttling(*this);
RunIntersectionObserverSteps();
+ ForAllRemoteFrameViews([](RemoteFrameView& frame_view) {
+ frame_view.UpdateCompositingScaleFactor();
+ });
}
void LocalFrameView::RunIntersectionObserverSteps() {
@@ -1114,7 +1117,7 @@ void LocalFrameView::RunIntersectionObserverSteps() {
LayoutObject* layout_object = GetLayoutView();
IntRect main_frame_dimensions =
To<LayoutBox>(layout_object)->PixelSnappedLayoutOverflowRect();
- GetFrame().Client()->OnMainFrameIntersectionChanged(WebRect(
+ GetFrame().Client()->OnMainFrameIntersectionChanged(IntRect(
0, 0, main_frame_dimensions.Width(), main_frame_dimensions.Height()));
}
@@ -1137,7 +1140,7 @@ void LocalFrameView::ForceUpdateViewportIntersections() {
// update; but we can't wait for a lifecycle update to run them, because a
// hidden frame won't run lifecycle updates. Force layout and run them now.
DisallowThrottlingScope disallow_throttling(*this);
- UpdateLifecycleToCompositingCleanPlusScrolling(
+ UpdateLifecycleToPrePaintClean(
DocumentUpdateReason::kIntersectionObservation);
UpdateViewportIntersectionsForSubtree(
IntersectionObservation::kImplicitRootObserversNeedUpdate |
@@ -1251,25 +1254,20 @@ void LocalFrameView::AdjustMediaTypeForPrinting(bool printing) {
void LocalFrameView::AddBackgroundAttachmentFixedObject(LayoutObject* object) {
DCHECK(!background_attachment_fixed_objects_.Contains(object));
-
background_attachment_fixed_objects_.insert(object);
- // Ensure main thread scrolling reasons are recomputed.
- SetNeedsPaintPropertyUpdate();
- // The object's scroll properties are not affected by its own background.
- object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
+ // Ensure main thread scrolling reasons of the ancestor scroll nodes are
+ // recomputed. The object's own scroll properties are not affected.
+ object->ForceAllAncestorsNeedPaintPropertyUpdate();
}
void LocalFrameView::RemoveBackgroundAttachmentFixedObject(
LayoutObject* object) {
- DCHECK(background_attachment_fixed_objects_.Contains(object));
-
background_attachment_fixed_objects_.erase(object);
- // Ensure main thread scrolling reasons are recomputed.
- SetNeedsPaintPropertyUpdate();
- // The object's scroll properties are not affected by its own background.
- object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
+ // Ensure main thread scrolling reasons of the ancestor scroll nodes are
+ // recomputed. The object's own scroll properties are not affected.
+ object->ForceAllAncestorsNeedPaintPropertyUpdate();
}
bool LocalFrameView::RequiresMainThreadScrollingForBackgroundAttachmentFixed()
@@ -1525,6 +1523,9 @@ void LocalFrameView::UpdateCompositedSelectionIfNeeded() {
if (!RuntimeEnabledFeatures::CompositedSelectionUpdateEnabled())
return;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
TRACE_EVENT0("blink", "LocalFrameView::updateCompositedSelectionIfNeeded");
Page* page = GetFrame().GetPage();
@@ -1563,8 +1564,14 @@ void LocalFrameView::SetNeedsCompositingUpdate(
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (auto* layout_view = GetLayoutView()) {
- if (frame_->GetDocument()->IsActive())
- layout_view->Compositor()->SetNeedsCompositingUpdate(update_type);
+ if (frame_->GetDocument()->IsActive()) {
+ auto* compositor = layout_view->Compositor();
+ compositor->SetNeedsCompositingUpdate(update_type);
+ // Even if the frame is throttlable, we may still need to decomposite it
+ // in response to a visibility change.
+ if (compositor->StaleInCompositingMode())
+ needs_forced_compositing_update_ = true;
+ }
}
}
@@ -2000,6 +2007,7 @@ void LocalFrameView::PerformPostLayoutTasks() {
DCHECK(!IsInPerformLayout());
TRACE_EVENT0("blink,benchmark", "LocalFrameView::performPostLayoutTasks");
+ GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
frame_->Selection().DidLayout();
DCHECK(frame_->GetDocument());
@@ -2160,6 +2168,12 @@ void LocalFrameView::WillBeRemovedFromFrame() {
}
}
+bool LocalFrameView::IsUpdatingLifecycle() const {
+ LocalFrameView* root_view = GetFrame().LocalFrameRoot().View();
+ DCHECK(root_view);
+ return root_view->target_state_ != DocumentLifecycle::kUninitialized;
+}
+
LocalFrameView* LocalFrameView::ParentFrameView() const {
if (!IsAttached())
return nullptr;
@@ -2220,6 +2234,7 @@ bool LocalFrameView::UpdateAllLifecyclePhases(DocumentUpdateReason reason) {
// kLayoutClean.
ForAllThrottledLocalFrameViews([](LocalFrameView& frame_view) {
DCHECK(frame_view.intersection_observation_state_ != kRequired ||
+ frame_view.IsDisplayLocked() ||
frame_view.Lifecycle().GetState() >=
DocumentLifecycle::kLayoutClean);
});
@@ -2298,8 +2313,7 @@ bool LocalFrameView::UpdateLifecycleToLayoutClean(DocumentUpdateReason reason) {
void LocalFrameView::ScheduleVisualUpdateForPaintInvalidationIfNeeded() {
LocalFrame& local_frame_root = GetFrame().LocalFrameRoot();
// We need a full lifecycle update to clear pending paint invalidations.
- if (local_frame_root.View()->current_update_lifecycle_phases_target_state_ <
- DocumentLifecycle::kPaintClean ||
+ if (local_frame_root.View()->target_state_ < DocumentLifecycle::kPaintClean ||
Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean) {
// Schedule visual update to process the paint invalidation in the next
// cycle.
@@ -2360,6 +2374,18 @@ bool LocalFrameView::LocalFrameTreeAllowsThrottling() const {
return false;
}
+void LocalFrameView::PrepareForLifecycleUpdateRecursive() {
+ // We will run lifecycle phases for LocalFrameViews that are unthrottled; or
+ // are throttled but require IntersectionObserver steps to run.
+ if (!ShouldThrottleRendering() ||
+ intersection_observation_state_ == kRequired) {
+ Lifecycle().EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending);
+ ForAllChildLocalFrameViews([](LocalFrameView& child) {
+ child.PrepareForLifecycleUpdateRecursive();
+ });
+ }
+}
+
// TODO(leviw): We don't assert lifecycle information from documents in child
// WebPluginContainerImpls.
bool LocalFrameView::UpdateLifecyclePhases(
@@ -2406,36 +2432,27 @@ bool LocalFrameView::UpdateLifecyclePhases(
if (frame_->IsLocalRoot())
UpdateLayerDebugInfoEnabled();
+ // If we're throttling and we aren't required to run the IntersectionObserver
+ // steps, then we don't need to update lifecycle phases. The throttling status
+ // will get updated in RunPostLifecycleSteps().
+ if (ShouldThrottleRendering() &&
+ intersection_observation_state_ < kRequired) {
+ return Lifecycle().GetState() == target_state;
+ }
+
+ PrepareForLifecycleUpdateRecursive();
+
// This is used to guard against reentrance. It is also used in conjunction
// with the current lifecycle state to determine which phases are yet to run
- // in this cycle.
+ // in this cycle. Note that this may change the return value of
+ // ShouldThrottleRendering(), hence it cannot be moved before the preceeding
+ // code, which relies on the prior value of ShouldThrottleRendering().
base::AutoReset<DocumentLifecycle::LifecycleState> target_state_scope(
- &current_update_lifecycle_phases_target_state_, target_state);
- // This is used to check if we're within a lifecycle update but have passed
- // the layout update phase. Note there is a bit of a subtlety here: it's not
- // sufficient for us to check the current lifecycle state, since it can be
- // past kLayoutClean but the function to run style and layout phase has not
- // actually been run yet. Since this bool affects throttling, and throttling,
- // in turn, determines whether style and layout function will run, we need a
- // separate bool.
- base::AutoReset<bool> past_layout_lifecycle_resetter(
- &past_layout_lifecycle_update_, false);
- base::AutoReset<bool> in_lifecycle_scope(&in_lifecycle_update_, true);
-
- // If we're throttling, then we don't need to update lifecycle phases. The
- // throttling status will get updated in RunPostLifecycleSteps().
- if (ShouldThrottleRendering()) {
- return Lifecycle().GetState() == target_state;
- }
+ &target_state_, target_state);
lifecycle_data_.start_time = base::TimeTicks::Now();
++lifecycle_data_.count;
- ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
- frame_view.Lifecycle().EnsureStateAtMost(
- DocumentLifecycle::kVisualUpdatePending);
- });
-
if (target_state == DocumentLifecycle::kPaintClean) {
{
TRACE_EVENT0("blink", "LocalFrameView::WillStartLifecycleUpdate");
@@ -2487,6 +2504,9 @@ bool LocalFrameView::UpdateLifecyclePhases(
void LocalFrameView::UpdateLifecyclePhasesInternal(
DocumentLifecycle::LifecycleState target_state) {
+ // RunScrollTimelineSteps must not run more than once.
+ bool should_run_scroll_timeline_steps = true;
+
// Run style, layout, compositing and prepaint lifecycle phases and deliver
// resize observations if required. Resize observer callbacks/delegates have
// the potential to dirty layout (until loop limit is reached) and therefore
@@ -2495,7 +2515,23 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
// Note that after ResizeObserver has settled, we also run intersection
// observations that need to be delievered in post-layout. This process can
// also dirty layout, which will run this loop again.
+
+ // A LocalFrameView can be unthrottled at this point, but become throttled as
+ // it advances through lifecycle stages. If that happens, it will prevent
+ // subsequent passes through the loop from updating the newly-throttled views.
+ // To avoid that, we lock in the set of unthrottled views before entering the
+ // loop.
+ HeapVector<Member<LocalFrameView>> unthrottled_frame_views;
+ ForAllNonThrottledLocalFrameViews(
+ [&unthrottled_frame_views](LocalFrameView& frame_view) {
+ unthrottled_frame_views.push_back(&frame_view);
+ });
+
while (true) {
+ for (LocalFrameView* frame_view : unthrottled_frame_views) {
+ frame_view->Lifecycle().EnsureStateAtMost(
+ DocumentLifecycle::kVisualUpdatePending);
+ }
bool run_more_lifecycle_phases =
RunStyleAndLayoutLifecyclePhases(target_state);
if (!run_more_lifecycle_phases)
@@ -2536,7 +2572,7 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
run_more_lifecycle_phases = RunPrePaintLifecyclePhase(target_state);
DCHECK(ShouldThrottleRendering() ||
Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
- if (!run_more_lifecycle_phases)
+ if (ShouldThrottleRendering() || !run_more_lifecycle_phases)
return;
run_more_lifecycle_phases =
@@ -2546,6 +2582,24 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
}
}
+ // Some features may require several passes over style and layout
+ // within the same lifecycle update.
+ bool needs_to_repeat_lifecycle = false;
+
+ // ScrollTimelines may be associated with a source that never had a
+ // a chance to get a layout box at the time style was calculated; when
+ // this situation happens, RunScrollTimelineSteps will re-snapshot all
+ // affected timelines and dirty style for associated effect targets.
+ //
+ // https://github.com/w3c/csswg-drafts/issues/5261
+ if (RuntimeEnabledFeatures::CSSScrollTimelineEnabled() &&
+ should_run_scroll_timeline_steps) {
+ should_run_scroll_timeline_steps = false;
+ needs_to_repeat_lifecycle = RunScrollTimelineSteps();
+ if (needs_to_repeat_lifecycle)
+ continue;
+ }
+
// ResizeObserver and post-layout IntersectionObserver observation
// deliveries may dirty style and layout. RunResizeObserverSteps will return
// true if any observer ran that may have dirtied style or layout;
@@ -2553,7 +2607,7 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
// observations led to content-visibility intersection changing visibility
// state synchronously (which happens on the first intersection
// observeration of a context).
- bool needs_to_repeat_lifecycle = RunResizeObserverSteps(target_state);
+ needs_to_repeat_lifecycle = RunResizeObserverSteps(target_state);
// Only run the rest of the steps here if resize observer is done.
if (needs_to_repeat_lifecycle)
continue;
@@ -2576,14 +2630,29 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
DCHECK_EQ(target_state, DocumentLifecycle::kPaintClean);
RunPaintLifecyclePhase();
- DCHECK(ShouldThrottleRendering() ||
- frame_->GetDocument()->IsCapturingLayout() ||
+ DCHECK(ShouldThrottleRendering() || AnyFrameIsPrintingOrPaintingPreview() ||
Lifecycle().GetState() == DocumentLifecycle::kPaintClean);
ForAllRemoteFrameViews(
[](RemoteFrameView& frame_view) { frame_view.UpdateCompositingRect(); });
}
+bool LocalFrameView::RunScrollTimelineSteps() {
+ DCHECK_GE(Lifecycle().GetState(),
+ DocumentLifecycle::kCompositingAssignmentsClean);
+ bool re_run_lifecycles = false;
+ ForAllNonThrottledLocalFrameViews(
+ [&re_run_lifecycles](LocalFrameView& frame_view) {
+ frame_view.GetFrame()
+ .GetDocument()
+ ->GetDocumentAnimations()
+ .ValidateTimelines();
+ re_run_lifecycles |= (frame_view.Lifecycle().GetState() <
+ DocumentLifecycle::kCompositingAssignmentsClean);
+ });
+ return re_run_lifecycles;
+}
+
bool LocalFrameView::RunResizeObserverSteps(
DocumentLifecycle::LifecycleState target_state) {
bool re_run_lifecycles = false;
@@ -2612,7 +2681,10 @@ bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
TRACE_EVENT0("blink,benchmark",
"LocalFrameView::RunStyleAndLayoutLifecyclePhases");
UpdateStyleAndLayoutIfNeededRecursive();
- DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
+ DCHECK(ShouldThrottleRendering() ||
+ Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
+ if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
+ return false;
frame_->GetDocument()
->GetRootScrollerController()
@@ -2633,18 +2705,6 @@ bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
if (target_state == DocumentLifecycle::kLayoutClean)
return false;
- // This will be reset by AutoReset in the calling function
- // (UpdateLifecyclePhases()).
- past_layout_lifecycle_update_ = true;
-
- // After layout and the |past_layout_lifecycle_update_| update, the value of
- // ShouldThrottleRendering() can change. OOPIF local frame roots that are
- // throttled can return now that layout is clean. This situation happens if
- // the throttling was disabled due to required intersection observation, which
- // can now be run.
- if (ShouldThrottleRendering())
- return false;
-
// Now we can run post layout steps in preparation for further phases.
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.PerformScrollAnchoringAdjustments();
@@ -2735,21 +2795,41 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
#endif
}
- ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
- frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
- if (frame_view.CanThrottleRendering()) {
- // This frame can be throttled but not throttled, meaning we are not in an
- // AllowThrottlingScope. Now this frame may contain dirty paint flags, and
- // we need to propagate the flags into the ancestor chain so that
- // PrePaintTreeWalk can reach this frame.
- frame_view.SetNeedsPaintPropertyUpdate();
- // We may record more pre-composited layers under the frame.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- frame_view.SetPaintArtifactCompositorNeedsUpdate();
- if (auto* owner = frame_view.GetLayoutEmbeddedContent())
- owner->SetShouldCheckForPaintInvalidation();
- }
- });
+ ForAllNonThrottledLocalFrameViews(
+ [](LocalFrameView& frame_view) {
+ frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
+ // We skipped pre-paint for this frame while it was throttled, or we
+ // have never run pre-paint for this frame. Either way, we're
+ // unthrottled now, so we must propagate our dirty bits into our
+ // parent frame so that pre-paint reaches into this frame.
+ if (LayoutView* layout_view = frame_view.GetLayoutView()) {
+ if (auto* owner = frame_view.GetFrame().OwnerLayoutObject()) {
+ if (layout_view->NeedsPaintPropertyUpdate() ||
+ layout_view->DescendantNeedsPaintPropertyUpdate()) {
+ owner->SetDescendantNeedsPaintPropertyUpdate();
+ }
+ if (layout_view->ShouldCheckForPaintInvalidation()) {
+ owner->SetShouldCheckForPaintInvalidation();
+ }
+ if (layout_view->EffectiveAllowedTouchActionChanged() ||
+ layout_view->DescendantEffectiveAllowedTouchActionChanged()) {
+ owner->MarkDescendantEffectiveAllowedTouchActionChanged();
+ }
+ if (layout_view->BlockingWheelEventHandlerChanged() ||
+ layout_view->DescendantBlockingWheelEventHandlerChanged()) {
+ owner->MarkDescendantBlockingWheelEventHandlerChanged();
+ }
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ (layout_view->Layer()->NeedsCullRectUpdate() ||
+ layout_view->Layer()->DescendantNeedsCullRectUpdate())) {
+ layout_view->Layer()
+ ->MarkCompositingContainerChainForNeedsCullRectUpdate();
+ }
+ }
+ }
+ },
+ // Use post-order to ensure correct flag propagation for nested frames.
+ kPostOrder);
{
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
@@ -2767,98 +2847,110 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
return target_state > DocumentLifecycle::kPrePaintClean;
}
+bool LocalFrameView::AnyFrameIsPrintingOrPaintingPreview() {
+ bool any_frame_is_printing_or_painting_preview = false;
+ ForAllNonThrottledLocalFrameViews(
+ [&any_frame_is_printing_or_painting_preview](LocalFrameView& frame_view) {
+ if (frame_view.GetFrame().GetDocument()->IsPrintingOrPaintingPreview())
+ any_frame_is_printing_or_painting_preview = true;
+ });
+ return any_frame_is_printing_or_painting_preview;
+}
+
void LocalFrameView::RunPaintLifecyclePhase(PaintBenchmarkMode benchmark_mode) {
TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunPaintLifecyclePhase");
// While printing or capturing a paint preview of a document, the paint walk
// is done into a special canvas. There is no point doing a normal paint step
// (or animations update) when in this mode.
- bool is_capturing_layout = frame_->GetDocument()->IsCapturingLayout();
- bool repainted = false;
- if (!is_capturing_layout)
- repainted = PaintTree(benchmark_mode);
-
- if (benchmark_mode ==
- PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate ||
- // TODO(paint-dev): Separate requirement for update for repaint and full
- // PaintArtifactCompositor update.
- (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- benchmark_mode != PaintBenchmarkMode::kNormal)) {
+ if (AnyFrameIsPrintingOrPaintingPreview())
+ return;
+
+ bool repainted = PaintTree(benchmark_mode);
+
+ if (paint_artifact_compositor_ &&
+ (benchmark_mode ==
+ PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate ||
+ // TODO(paint-dev): Separate requirement for update for repaint and full
+ // PaintArtifactCompositor update.
+ (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ benchmark_mode != PaintBenchmarkMode::kNormal))) {
paint_artifact_compositor_->SetNeedsUpdate();
}
- if (!is_capturing_layout) {
- bool needed_update = !paint_artifact_compositor_ ||
- paint_artifact_compositor_->NeedsUpdate();
- PushPaintArtifactToCompositor(repainted);
- size_t total_animations_count = 0;
- bool current_frame_had_raf = false;
- bool next_frame_has_pending_raf = false;
- ForAllNonThrottledLocalFrameViews([this, &total_animations_count,
- &current_frame_had_raf,
- &next_frame_has_pending_raf](
- LocalFrameView& frame_view) {
- if (auto* scrollable_area = frame_view.GetScrollableArea())
- scrollable_area->UpdateCompositorScrollAnimations();
- if (const auto* animating_scrollable_areas =
- frame_view.AnimatingScrollableAreas()) {
- for (PaintLayerScrollableArea* area : *animating_scrollable_areas)
- area->UpdateCompositorScrollAnimations();
- }
- frame_view.GetLayoutView()
- ->GetDocument()
- .GetDocumentAnimations()
- .UpdateAnimations(DocumentLifecycle::kPaintClean,
- paint_artifact_compositor_.get());
- Document& document = frame_view.GetLayoutView()->GetDocument();
- total_animations_count +=
- document.GetDocumentAnimations().GetAnimationsCount();
- current_frame_had_raf |= document.CurrentFrameHadRAF();
- next_frame_has_pending_raf |= document.NextFrameHasPendingRAF();
- });
-
- if (GetLayoutView()->GetDocument().View() &&
- GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) {
- GetLayoutView()
- ->GetDocument()
- .View()
- ->GetCompositorAnimationHost()
- ->SetAnimationCounts(total_animations_count, current_frame_had_raf,
- next_frame_has_pending_raf);
- }
+ bool needed_update =
+ !paint_artifact_compositor_ || paint_artifact_compositor_->NeedsUpdate();
+ PushPaintArtifactToCompositor(repainted);
+ size_t total_animations_count = 0;
+ bool current_frame_had_raf = false;
+ bool next_frame_has_pending_raf = false;
+ ForAllNonThrottledLocalFrameViews(
+ [this, &total_animations_count, &current_frame_had_raf,
+ &next_frame_has_pending_raf](LocalFrameView& frame_view) {
+ if (auto* scrollable_area = frame_view.GetScrollableArea())
+ scrollable_area->UpdateCompositorScrollAnimations();
+ if (const auto* animating_scrollable_areas =
+ frame_view.AnimatingScrollableAreas()) {
+ for (PaintLayerScrollableArea* area : *animating_scrollable_areas)
+ area->UpdateCompositorScrollAnimations();
+ }
+ {
+ // Updating animations can notify ready promises which could mutate
+ // the DOM. We should delay these until we have finished the lifecycle
+ // update. https://crbug.com/1196781
+ ScriptForbiddenScope forbid_script;
+ frame_view.GetLayoutView()
+ ->GetDocument()
+ .GetDocumentAnimations()
+ .UpdateAnimations(DocumentLifecycle::kPaintClean,
+ paint_artifact_compositor_.get());
+ }
+ Document& document = frame_view.GetLayoutView()->GetDocument();
+ total_animations_count +=
+ document.GetDocumentAnimations().GetAnimationsCount();
+ current_frame_had_raf |= document.CurrentFrameHadRAF();
+ next_frame_has_pending_raf |= document.NextFrameHasPendingRAF();
+ });
- // Initialize animation properties in the newly created paint property
- // nodes according to the current animation state. This is mainly for
- // the running composited animations which didn't change state during
- // above UpdateAnimations() but associated with new paint property nodes.
- if (needed_update) {
- auto* root_layer = RootCcLayer();
- if (root_layer && root_layer->layer_tree_host()) {
- root_layer->layer_tree_host()
- ->mutator_host()
- ->InitClientAnimationState();
- }
+ if (GetLayoutView()->GetDocument().View() &&
+ GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) {
+ GetLayoutView()
+ ->GetDocument()
+ .View()
+ ->GetCompositorAnimationHost()
+ ->SetAnimationCounts(total_animations_count, current_frame_had_raf,
+ next_frame_has_pending_raf);
+ }
+
+ // Initialize animation properties in the newly created paint property
+ // nodes according to the current animation state. This is mainly for
+ // the running composited animations which didn't change state during
+ // above UpdateAnimations() but associated with new paint property nodes.
+ if (needed_update) {
+ auto* root_layer = RootCcLayer();
+ if (root_layer && root_layer->layer_tree_host()) {
+ root_layer->layer_tree_host()->mutator_host()->InitClientAnimationState();
}
+ }
- // Notify the controller that the artifact has been pushed and some
- // lifecycle state can be freed (such as raster invalidations).
- if (paint_controller_)
- paint_controller_->FinishCycle();
+ // Notify the controller that the artifact has been pushed and some
+ // lifecycle state can be freed (such as raster invalidations).
+ if (paint_controller_)
+ paint_controller_->FinishCycle();
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
- if (root) {
- ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) {
- // Notify the paint controller that the artifact has been pushed and
- // some lifecycle state can be freed (such as raster invalidations).
- layer.GetPaintController().FinishCycle();
- });
- }
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
+ if (root) {
+ ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) {
+ // Notify the paint controller that the artifact has been pushed and
+ // some lifecycle state can be freed (such as raster invalidations).
+ layer.GetPaintController().FinishCycle();
+ });
}
-
- if (paint_artifact_compositor_)
- paint_artifact_compositor_->ClearPropertyTreeChangedState();
}
+ if (paint_artifact_compositor_)
+ paint_artifact_compositor_->ClearPropertyTreeChangedState();
+
if (GetPage())
GetPage()->Animator().ReportFrameAnimations(GetCompositorAnimationHost());
}
@@ -3161,12 +3253,31 @@ void LocalFrameView::PushPaintArtifactToCompositor(bool repainted) {
});
}
+ WTF::Vector<std::unique_ptr<DocumentTransition::Request>>
+ document_transition_requests;
+ // TODO(vmpstr): We should make this work for subframes as well.
+ AppendDocumentTransitionRequests(document_transition_requests);
+
paint_artifact_compositor_->Update(
- pre_composited_layers_, viewport_properties, scroll_translation_nodes);
+ pre_composited_layers_, viewport_properties, scroll_translation_nodes,
+ std::move(document_transition_requests));
probe::LayerTreePainted(&GetFrame());
}
+void LocalFrameView::AppendDocumentTransitionRequests(
+ WTF::Vector<std::unique_ptr<DocumentTransition::Request>>& requests) {
+ DCHECK(frame_ && frame_->GetDocument());
+ auto* document_transition_supplement =
+ DocumentTransitionSupplement::FromIfExists(*frame_->GetDocument());
+ if (!document_transition_supplement)
+ return;
+ auto* document_transition = document_transition_supplement->GetTransition();
+ auto pending_request = document_transition->TakePendingRequest();
+ if (pending_request)
+ requests.push_back(std::move(pending_request));
+}
+
std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON(
LayerTreeFlags flags) {
auto* root_frame_view = GetFrame().LocalFrameRoot().View();
@@ -3196,7 +3307,7 @@ void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
{
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
LocalFrameUkmAggregator::kStyle);
- frame_->GetDocument()->UpdateStyleAndLayoutTree();
+ frame_->GetDocument()->UpdateStyleAndLayoutTreeForThisDocument();
// Update style for all embedded SVG documents underneath this frame, so
// that intrinsic size computation for any embedded objects has up-to-date
@@ -3204,7 +3315,7 @@ void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
ForAllChildLocalFrameViews([](LocalFrameView& view) {
Document& document = *view.GetFrame().GetDocument();
if (document.IsSVGDocument())
- document.UpdateStyleAndLayoutTree();
+ document.UpdateStyleAndLayoutTreeForThisDocument();
});
}
@@ -3691,7 +3802,8 @@ void LocalFrameView::AttachToLayout() {
if (parent_view->IsVisible())
SetParentVisible(true);
UpdateRenderThrottlingStatus(IsHiddenForThrottling(),
- parent_view->CanThrottleRendering());
+ parent_view->CanThrottleRendering(),
+ IsDisplayLocked());
// We may have updated paint properties in detached frame subtree for
// printing (see UpdateLifecyclePhasesForPrinting()). The paint properties
@@ -3775,7 +3887,15 @@ void LocalFrameView::PropagateFrameRects() {
}
});
- GetFrame().Client()->FrameRectsChanged(FrameRect());
+ // To limit the number of Mojo communications, only notify the browser when
+ // the rect's size changes, not when the position changes. The size needs to
+ // be replicated if the iframe goes out-of-process.
+ IntSize frame_size = FrameRect().Size();
+ if (!frame_size_ || *frame_size_ != frame_size) {
+ frame_size_ = frame_size;
+ GetFrame().GetLocalFrameHostRemote().FrameSizeChanged(
+ gfx::Size(frame_size));
+ }
// It's possible for changing the frame rect to not generate a layout
// or any other event tracked by accessibility, we've seen this with
@@ -3796,33 +3916,6 @@ void LocalFrameView::SetLayoutSizeInternal(const IntSize& size) {
SetNeedsLayout();
}
-void LocalFrameView::ClipPaintRect(FloatRect* paint_rect) const {
- // TODO(wangxianzhu): Support ChromeClient::VisibleContentRectForPainting()
- // with CompositeAfterPaint.
- DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-
- // Paint the whole rect if ClipsContent is false, meaning that the whole
- // document should be recorded. This occurs if:
- // - A paint preview is being captured.
- // - WebPreferences::record_whole_document is true.
- if (!frame_->ClipsContent())
- return;
-
- // By default we consider the bounds of the FrameView to be what is considered
- // visible for the Frame.
- IntRect visible_rect = IntRect(IntPoint(), Size());
- // Non-main frames always clip to their FrameView bounds. Main frames can
- // have this behaviour modified by devtools.
- if (frame_->IsMainFrame()) {
- // If devtools is overriding the viewport, then the FrameView's bounds are
- // not what we should paint, instead we should paint inside the bounds
- // specified by devtools.
- GetPage()->GetChromeClient().OverrideVisibleRectForMainFrame(*frame_,
- &visible_rect);
- }
- paint_rect->Intersect(visible_rect);
-}
-
void LocalFrameView::DidChangeScrollOffset() {
GetFrame().Client()->DidChangeScrollOffset();
if (GetFrame().IsMainFrame()) {
@@ -3998,13 +4091,19 @@ void LocalFrameView::Paint(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
const CullRect& cull_rect,
const IntSize& paint_offset) const {
- // When capturing a Paint Preview we want to capture scrollable embedded
- // content separately. Paint should stop here and ask the browser to
- // coordinate painting such frames as a separate task.
- if (context.IsPaintingPreview() && LayoutViewport()->ScrollsOverflow()) {
- // If capture fails we should fallback to capturing inline if possible.
- if (CapturePaintPreview(context, paint_offset))
- return;
+ const auto* owner_layout_object = GetFrame().OwnerLayoutObject();
+ base::Optional<Document::PaintPreviewScope> paint_preview;
+ if (owner_layout_object &&
+ owner_layout_object->GetDocument().IsPaintingPreview()) {
+ paint_preview.emplace(*GetFrame().GetDocument());
+ // When capturing a Paint Preview we want to capture scrollable embedded
+ // content separately. Paint should stop here and ask the browser to
+ // coordinate painting such frames as a separate task.
+ if (LayoutViewport()->ScrollsOverflow()) {
+ // If capture fails we should fallback to capturing inline if possible.
+ if (CapturePaintPreview(context, paint_offset))
+ return;
+ }
}
// |paint_offset| is not used because paint properties of the contents will
@@ -4051,7 +4150,10 @@ void LocalFrameView::PaintOutsideOfLifecycle(
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- PaintInternal(context, global_paint_flags, cull_rect);
+ {
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
+ PaintInternal(context, global_paint_flags, cull_rect);
+ }
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
@@ -4068,7 +4170,10 @@ void LocalFrameView::PaintContentsOutsideOfLifecycle(
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
+ {
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
+ FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
+ }
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
@@ -4078,6 +4183,7 @@ void LocalFrameView::PaintContentsOutsideOfLifecycle(
void LocalFrameView::PaintContentsForTest(const CullRect& cull_rect) {
AllowThrottlingScope allow_throttling(*this);
Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
PaintController& paint_controller = EnsurePaintController();
if (GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint()) {
@@ -4277,7 +4383,7 @@ bool LocalFrameView::UpdateViewportIntersectionsForSubtree(
unsigned flags = GetIntersectionObservationFlags(parent_flags);
bool needs_occlusion_tracking = false;
- if (!NeedsLayout()) {
+ if (!NeedsLayout() || IsDisplayLocked()) {
// Notify javascript IntersectionObservers
if (IntersectionObserverController* controller =
GetFrame().GetDocument()->GetIntersectionObserverController()) {
@@ -4287,7 +4393,12 @@ bool LocalFrameView::UpdateViewportIntersectionsForSubtree(
intersection_observation_state_ = kNotNeeded;
}
- UpdateViewportIntersection(flags, needs_occlusion_tracking);
+ {
+ SCOPED_UMA_AND_UKM_TIMER(
+ EnsureUkmAggregator(),
+ LocalFrameUkmAggregator::kUpdateViewportIntersection);
+ UpdateViewportIntersection(flags, needs_occlusion_tracking);
+ }
for (Frame* child = frame_->Tree().FirstChild(); child;
child = child->Tree().NextSibling()) {
@@ -4321,26 +4432,19 @@ void LocalFrameView::CrossOriginToMainFrameChanged() {
// If any of these conditions hold, then a change in cross-origin status does
// not affect throttling.
if (lifecycle_updates_throttled_ || IsSubtreeThrottled() ||
- !IsHiddenForThrottling()) {
+ IsDisplayLocked() || !IsHiddenForThrottling()) {
return;
}
RenderThrottlingStatusChanged();
- // We need to invalidate unconditionally, so if it didn't happen during
- // RenderThrottlingStatusChanged, do it now.
- if (CanThrottleRendering())
- InvalidateForThrottlingChange();
// Immediately propagate changes to children.
UpdateRenderThrottlingStatus(IsHiddenForThrottling(), IsSubtreeThrottled(),
- true);
+ IsDisplayLocked(), true);
}
void LocalFrameView::CrossOriginToParentFrameChanged() {
- if (base::FeatureList::IsEnabled(
- blink::features::kCompositeCrossOriginIframes)) {
- if (LayoutView* layout_view = GetLayoutView()) {
- if (PaintLayer* root_layer = layout_view->Layer())
- root_layer->SetNeedsCompositingInputsUpdate();
- }
+ if (LayoutView* layout_view = GetLayoutView()) {
+ if (PaintLayer* root_layer = layout_view->Layer())
+ root_layer->SetNeedsCompositingInputsUpdate();
}
}
@@ -4367,11 +4471,21 @@ void LocalFrameView::RenderThrottlingStatusChanged() {
SetPaintArtifactCompositorNeedsUpdate();
if (!CanThrottleRendering()) {
- InvalidateForThrottlingChange();
+ // Start ticking animation frames again if necessary.
+ if (GetPage())
+ GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
+ // Ensure we'll recompute viewport intersection for the frame subtree during
+ // the scheduled visual update.
+ SetIntersectionObservationState(kRequired);
+ // When a frame is throttled, we typically delete its previous painted
+ // output, so it will need to be repainted, even if nothing else has
+ // changed.
+ if (LayoutView* layout_view = GetLayoutView())
+ layout_view->Layer()->SetNeedsRepaint();
} else if (GetFrame().IsLocalRoot()) {
// By this point, every frame in the local frame tree has become throttled,
// so painting the tree should just clear the previous painted output.
- DCHECK(!in_lifecycle_update_);
+ DCHECK(!IsUpdatingLifecycle());
AllowThrottlingScope allow_throtting(*this);
RunPaintLifecyclePhase();
}
@@ -4386,26 +4500,6 @@ void LocalFrameView::RenderThrottlingStatusChanged() {
#endif
}
-void LocalFrameView::InvalidateForThrottlingChange() {
- // Start ticking animation frames again if necessary.
- if (GetPage())
- GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
- // Force a full repaint of this frame to ensure we are not left with a
- // partially painted version of this frame's contents if we skipped
- // painting them while the frame was throttled.
- LayoutView* layout_view = GetLayoutView();
- if (layout_view) {
- layout_view->InvalidatePaintForViewAndDescendants();
- // Also need to update all paint properties that might be skipped while
- // the frame was throttled.
- layout_view->AddSubtreePaintPropertyUpdateReason(
- SubtreePaintPropertyUpdateReason::kPreviouslySkipped);
- }
- // Ensure we'll recompute viewport intersection for the frame subtree during
- // the scheduled visual update.
- SetIntersectionObservationState(kRequired);
-}
-
void LocalFrameView::SetNeedsForcedCompositingUpdate() {
needs_forced_compositing_update_ = true;
if (LocalFrameView* parent = ParentFrameView())
@@ -4479,14 +4573,25 @@ bool LocalFrameView::ShouldThrottleRendering() const {
if (!throttled_for_global_reasons || needs_forced_compositing_update_)
return false;
- if (intersection_observation_state_ == kRequired) {
- auto* local_frame_root_view = GetFrame().LocalFrameRoot().View();
- // When doing a lifecycle update required by intersection observer, we can
- // throttle lifecycle states after layout. Outside of lifecycle updates,
- // the frame should be considered throttled because it is not fully updating
- // the lifecycle.
- return !local_frame_root_view->in_lifecycle_update_ ||
- local_frame_root_view->past_layout_lifecycle_update_;
+ // If we're currently running a lifecycle update, and we are required to run
+ // the IntersectionObserver steps at the end of the update, then there are two
+ // courses of action, depending on whether this frame is display locked by its
+ // parent frame:
+ //
+ // - If it is NOT display locked, then we suppress throttling to force the
+ // lifecycle update to proceed up to the state required to run
+ // IntersectionObserver.
+ //
+ // - If it IS display locked, then we still need IntersectionObserver to
+ // run; but the display lock status will short-circuit the
+ // IntersectionObserver algorithm and create degenerate "not intersecting"
+ // notifications. Hence, we don't need to force lifecycle phases to run,
+ // because IntersectionObserver will not need access to up-to-date
+ // geometry. So there is no point in suppressing throttling here.
+ auto* local_frame_root_view = GetFrame().LocalFrameRoot().View();
+ if (local_frame_root_view->IsUpdatingLifecycle() &&
+ intersection_observation_state_ == kRequired && !IsDisplayLocked()) {
+ return Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean;
}
return true;
@@ -4498,10 +4603,10 @@ bool LocalFrameView::ShouldThrottleRenderingForTest() const {
}
bool LocalFrameView::CanThrottleRendering() const {
- if (lifecycle_updates_throttled_)
- return true;
- if (IsSubtreeThrottled())
+ if (lifecycle_updates_throttled_ || IsSubtreeThrottled() ||
+ IsDisplayLocked()) {
return true;
+ }
// We only throttle hidden cross-origin frames. This is to avoid a situation
// where an ancestor frame directly depends on the pipeline timing of a
// descendant and breaks as a result of throttling. The rationale is that
@@ -4513,10 +4618,11 @@ bool LocalFrameView::CanThrottleRendering() const {
void LocalFrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
bool subtree_throttled,
+ bool display_locked,
bool recurse) {
bool was_throttled = CanThrottleRendering();
- FrameView::UpdateRenderThrottlingStatus(hidden_for_throttling,
- subtree_throttled, recurse);
+ FrameView::UpdateRenderThrottlingStatus(
+ hidden_for_throttling, subtree_throttled, display_locked, recurse);
if (was_throttled != CanThrottleRendering())
RenderThrottlingStatusChanged();
}
@@ -4528,8 +4634,6 @@ void LocalFrameView::BeginLifecycleUpdates() {
if (GetFrame().GetDocument()->IsInitialEmptyDocument())
return;
lifecycle_updates_throttled_ = false;
- if (auto* owner = GetLayoutEmbeddedContent())
- owner->SetShouldCheckForPaintInvalidation();
LayoutView* layout_view = GetLayoutView();
bool layout_view_is_empty = layout_view && !layout_view->FirstChild();
@@ -4588,20 +4692,6 @@ int LocalFrameView::InitialViewportHeight() const {
return initial_viewport_size_.Height();
}
-bool LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects() const {
- if (!ViewportConstrainedObjects())
- return false;
- for (const LayoutObject* layout_object : *ViewportConstrainedObjects()) {
- DCHECK(layout_object->HasLayer());
- DCHECK(layout_object->StyleRef().GetPosition() == EPosition::kFixed ||
- layout_object->StyleRef().GetPosition() == EPosition::kSticky);
- if (To<LayoutBoxModelObject>(layout_object)
- ->IsSlowRepaintConstrainedObject())
- return true;
- }
- return false;
-}
-
MainThreadScrollingReasons LocalFrameView::MainThreadScrollingReasonsPerFrame()
const {
MainThreadScrollingReasons reasons =
@@ -4614,18 +4704,6 @@ MainThreadScrollingReasons LocalFrameView::MainThreadScrollingReasonsPerFrame()
reasons |=
cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
}
-
- // Force main-thread scrolling if the frame has uncomposited position: fixed
- // elements. Note: we care about this not only for input-scrollable frames
- // but also for overflow: hidden frames, because script can run composited
- // smooth-scroll animations. For this reason, we use HasOverflow instead of
- // ScrollsOverflow (which is false for overflow: hidden).
- if (LayoutViewport()->HasOverflow() &&
- GetLayoutView()->StyleRef().VisibleToHitTesting() &&
- HasVisibleSlowRepaintViewportConstrainedObjects()) {
- reasons |=
- cc::MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
- }
return reasons;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.h b/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
index f88522138a1..b3369670391 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -34,6 +34,7 @@
#include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-blink.h"
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition.h"
#include "third_party/blink/renderer/core/dom/document_lifecycle.h"
#include "third_party/blink/renderer/core/frame/frame_view.h"
#include "third_party/blink/renderer/core/frame/layout_subtree_root_list.h"
@@ -74,7 +75,6 @@ class AXObjectCache;
class ChromeClient;
class CompositorAnimationTimeline;
class DocumentLifecycle;
-class FloatRect;
class FloatSize;
class FragmentAnchor;
class Frame;
@@ -255,8 +255,6 @@ class CORE_EXPORT LocalFrameView final
bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
bool HasIntrinsicSizingInfo() const override;
- void UpdateCountersAfterStyleChange();
-
void Dispose() override;
void PropagateFrameRects() override;
void InvalidateAllCustomScrollbarsOnActiveChanged();
@@ -348,10 +346,7 @@ class CORE_EXPORT LocalFrameView final
// LocalFrame.
void WillBeRemovedFromFrame();
- bool IsUpdatingLifecycle() {
- return current_update_lifecycle_phases_target_state_ !=
- DocumentLifecycle::kUninitialized;
- }
+ bool IsUpdatingLifecycle() const;
// Run all needed lifecycle stages. After calling this method, all frames will
// be in the lifecycle state PaintClean. If lifecycle throttling is allowed
@@ -402,7 +397,9 @@ class CORE_EXPORT LocalFrameView final
// desired state.
bool UpdateLifecycleToLayoutClean(DocumentUpdateReason reason);
- void SetInLifecycleUpdateForTest(bool val) { in_lifecycle_update_ = val; }
+ void SetTargetStateForTest(DocumentLifecycle::LifecycleState state) {
+ target_state_ = state;
+ }
// This for doing work that needs to run synchronously at the end of lifecyle
// updates, but needs to happen outside of the lifecycle code. It's OK to
@@ -500,11 +497,6 @@ class CORE_EXPORT LocalFrameView final
void RemoveScrollbar(Scrollbar*);
void AddScrollbar(Scrollbar*);
- // Clips the provided rect to the visible content area. For this purpose, we
- // also query the chrome client for any active overrides to the visible area
- // (e.g. DevTool's viewport override).
- void ClipPaintRect(FloatRect*) const;
-
// Indicates the root layer's scroll offset changed since the last frame
void SetRootLayerDidScroll() { root_layer_did_scroll_ = true; }
@@ -616,6 +608,7 @@ class CORE_EXPORT LocalFrameView final
bool CanThrottleRendering() const override;
void UpdateRenderThrottlingStatus(bool hidden_for_throttling,
bool subtree_throttled,
+ bool display_locked,
bool recurse = false) override;
void BeginLifecycleUpdates();
@@ -663,8 +656,6 @@ class CORE_EXPORT LocalFrameView final
// see: mainThreadScrollingReasons().
MainThreadScrollingReasons MainThreadScrollingReasonsPerFrame() const;
- bool HasVisibleSlowRepaintViewportConstrainedObjects() const;
-
bool MapToVisualRectInRemoteRootFrame(PhysicalRect& rect,
bool apply_overflow_clip = true);
@@ -852,6 +843,8 @@ class CORE_EXPORT LocalFrameView final
LayoutSVGRoot* EmbeddedReplacedContent() const;
+ void PrepareForLifecycleUpdateRecursive();
+
// Returns whether the lifecycle was successfully updated to the
// target state.
bool UpdateLifecyclePhases(DocumentLifecycle::LifecycleState target_state,
@@ -907,8 +900,6 @@ class CORE_EXPORT LocalFrameView final
DoublePoint ConvertFromContainingEmbeddedContentView(
const DoublePoint&) const;
- void InvalidateForThrottlingChange();
-
void UpdateGeometriesIfNeeded();
bool WasViewportResized();
void SendResizeEventIfNeeded();
@@ -955,6 +946,8 @@ class CORE_EXPORT LocalFrameView final
bool UpdateViewportIntersectionsForSubtree(unsigned parent_flags) override;
void DeliverSynchronousIntersectionObservations();
+ bool RunScrollTimelineSteps();
+
bool NotifyResizeObservers(DocumentLifecycle::LifecycleState target_state);
bool RunResizeObserverSteps(DocumentLifecycle::LifecycleState target_state);
void ClearResizeObserverLimit();
@@ -989,6 +982,12 @@ class CORE_EXPORT LocalFrameView final
// StyleEngine instead of the base background color.
bool ShouldUseColorAdjustBackground() const;
+ // Appends the document transition from this view into the given vector.
+ void AppendDocumentTransitionRequests(
+ WTF::Vector<std::unique_ptr<DocumentTransition::Request>>&);
+
+ bool AnyFrameIsPrintingOrPaintingPreview();
+
LayoutSize size_;
typedef HashSet<scoped_refptr<LayoutEmbeddedObject>> EmbeddedObjectSet;
@@ -1006,7 +1005,7 @@ class CORE_EXPORT LocalFrameView final
unsigned layout_count_for_testing_;
unsigned lifecycle_update_count_for_testing_;
unsigned nested_layout_count_;
- TaskRunnerTimer<LocalFrameView> update_plugins_timer_;
+ HeapTaskRunnerTimer<LocalFrameView> update_plugins_timer_;
bool first_layout_;
UseColorAdjustBackground use_color_adjust_background_{
@@ -1015,6 +1014,10 @@ class CORE_EXPORT LocalFrameView final
IntSize last_viewport_size_;
float last_zoom_factor_;
+ // Used for tracking the frame's size and replicating it to the browser
+ // process when it changes.
+ base::Optional<IntSize> frame_size_;
+
AtomicString media_type_;
AtomicString media_type_when_not_printing_;
@@ -1072,9 +1075,7 @@ class CORE_EXPORT LocalFrameView final
bool allow_throttling_ = false;
// This is set on the local root frame view only.
- DocumentLifecycle::LifecycleState
- current_update_lifecycle_phases_target_state_;
- bool past_layout_lifecycle_update_;
+ DocumentLifecycle::LifecycleState target_state_;
using AnchoringAdjustmentQueue =
HeapLinkedHashSet<WeakMember<ScrollableArea>>;
@@ -1092,7 +1093,6 @@ class CORE_EXPORT LocalFrameView final
bool needs_forced_compositing_update_;
bool needs_focus_on_fragment_;
- bool in_lifecycle_update_;
// True if the frame has deferred commits at least once per document load.
// We won't defer again for the same document.
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
index f4d780eb1f8..07aa767e9f5 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view_test.cc
@@ -179,7 +179,7 @@ TEST_F(LocalFrameViewTest, UpdateLifecyclePhasesForPrintingDetachedFrame) {
SetBodyInnerHTML("<iframe style='display: none'></iframe>");
SetChildFrameHTML("A");
- ChildDocument().SetPrinting(Document::kPrinting);
+ ChildFrame().StartPrinting(FloatSize(200, 200), FloatSize(200, 200), 1);
ChildDocument().View()->UpdateLifecyclePhasesForPrinting();
// The following checks that the detached frame has been walked for PrePaint.
@@ -191,6 +191,34 @@ TEST_F(LocalFrameViewTest, UpdateLifecyclePhasesForPrintingDetachedFrame) {
EXPECT_TRUE(child_layout_view->FirstFragment().PaintProperties());
}
+TEST_F(LocalFrameViewTest, PrintFrameUpdateAllLifecyclePhases) {
+ SetBodyInnerHTML("<iframe></iframe>");
+ SetChildFrameHTML("A");
+
+ ChildFrame().StartPrinting(FloatSize(200, 200), FloatSize(200, 200), 1);
+ ChildDocument().View()->UpdateLifecyclePhasesForPrinting();
+
+ EXPECT_EQ(DocumentLifecycle::kCompositingAssignmentsClean,
+ GetDocument().Lifecycle().GetState());
+ EXPECT_EQ(DocumentLifecycle::kCompositingAssignmentsClean,
+ ChildDocument().Lifecycle().GetState());
+
+ // In case UpdateAllLifecyclePhases is called during child frame printing for
+ // any reason, we should not paint.
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(DocumentLifecycle::kCompositingAssignmentsClean,
+ GetDocument().Lifecycle().GetState());
+ EXPECT_EQ(DocumentLifecycle::kCompositingAssignmentsClean,
+ ChildDocument().Lifecycle().GetState());
+
+ ChildFrame().EndPrinting();
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ GetDocument().Lifecycle().GetState());
+ EXPECT_EQ(DocumentLifecycle::kPaintClean,
+ ChildDocument().Lifecycle().GetState());
+}
+
TEST_F(LocalFrameViewTest, CanHaveScrollbarsIfScrollingAttrEqualsNoChanged) {
SetBodyInnerHTML("<iframe scrolling='no'></iframe>");
EXPECT_FALSE(ChildDocument().View()->CanHaveScrollbars());
@@ -435,6 +463,16 @@ TEST_F(LocalFrameViewTest, TogglePaintEligibility) {
EXPECT_TRUE(child_timing.FirstEligibleToPaint().is_null());
}
+TEST_F(LocalFrameViewTest, IsUpdatingLifecycle) {
+ SetBodyInnerHTML("<iframe srcdoc='Hello, world!'></iframe>>");
+ EXPECT_FALSE(GetFrame().View()->IsUpdatingLifecycle());
+ EXPECT_FALSE(ChildFrame().View()->IsUpdatingLifecycle());
+ GetFrame().View()->SetTargetStateForTest(DocumentLifecycle::kPaintClean);
+ EXPECT_TRUE(GetFrame().View()->IsUpdatingLifecycle());
+ EXPECT_TRUE(ChildFrame().View()->IsUpdatingLifecycle());
+ GetFrame().View()->SetTargetStateForTest(DocumentLifecycle::kUninitialized);
+}
+
TEST_F(SimTest, PaintEligibilityNoSubframe) {
SimRequest resource("https://example.com/", "text/html");
diff --git a/chromium/third_party/blink/renderer/core/frame/mhtml_archive_test.cc b/chromium/third_party/blink/renderer/core/frame/mhtml_archive_test.cc
index 87d5b91b6d6..ad98278d5a7 100644
--- a/chromium/third_party/blink/renderer/core/frame/mhtml_archive_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/mhtml_archive_test.cc
@@ -32,6 +32,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-blink.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_parser.h"
@@ -374,7 +375,8 @@ TEST_F(MHTMLArchiveTest, MHTMLFromScheme) {
CheckLoadResult(ToKURL("fooscheme://bar"), data.get(),
MHTMLLoadResult::kUrlSchemeNotAllowed);
- SchemeRegistry::RegisterURLSchemeAsLocal("fooscheme");
+ url::ScopedSchemeRegistryForTests scoped_registry;
+ url::AddLocalScheme("fooscheme");
CheckLoadResult(ToKURL("fooscheme://bar"), data.get(),
MHTMLLoadResult::kSuccess);
}
diff --git a/chromium/third_party/blink/renderer/core/frame/navigation_rate_limiter.h b/chromium/third_party/blink/renderer/core/frame/navigation_rate_limiter.h
index 7ff7bc349ed..9b78c250b61 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigation_rate_limiter.h
+++ b/chromium/third_party/blink/renderer/core/frame/navigation_rate_limiter.h
@@ -6,9 +6,9 @@
#include "base/time/time.h"
#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
-class Visitor;
class Frame;
// TODO(https://crbug.com/394296, https://crbug.com/882238)
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator.cc b/chromium/third_party/blink/renderer/core/frame/navigator.cc
index a1ca9b10d88..ff2573f855a 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator.cc
+++ b/chromium/third_party/blink/renderer/core/frame/navigator.cc
@@ -38,8 +38,7 @@
namespace blink {
-Navigator::Navigator(ExecutionContext* context)
- : NavigatorLanguage(context), ExecutionContextClient(context) {}
+Navigator::Navigator(ExecutionContext* context) : NavigatorBase(context) {}
String Navigator::productSub() const {
return "20030107";
@@ -69,27 +68,6 @@ String Navigator::platform() const {
: platform_override;
}
-String Navigator::userAgent() const {
- // If the frame is already detached it no longer has a meaningful useragent.
- if (!DomWindow())
- return String();
-
- return DomWindow()->GetFrame()->Loader().UserAgent();
-}
-
-UserAgentMetadata Navigator::GetUserAgentMetadata() const {
- // If the frame is already detached it no longer has a meaningful useragent.
- if (!DomWindow())
- return blink::UserAgentMetadata();
-
- base::Optional<UserAgentMetadata> maybe_ua_metadata =
- DomWindow()->GetFrame()->Loader().UserAgentMetadata();
- if (maybe_ua_metadata.has_value())
- return maybe_ua_metadata.value();
- else
- return blink::UserAgentMetadata();
-}
-
bool Navigator::cookieEnabled() const {
if (!DomWindow())
return false;
@@ -114,14 +92,8 @@ String Navigator::GetAcceptLanguages() {
}
void Navigator::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- NavigatorLanguage::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
+ NavigatorBase::Trace(visitor);
Supplementable<Navigator>::Trace(visitor);
}
-ExecutionContext* Navigator::GetUAExecutionContext() const {
- return GetExecutionContext();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator.h b/chromium/third_party/blink/renderer/core/frame/navigator.h
index 1e024cfa2b5..5eb1673a60a 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator.h
+++ b/chromium/third_party/blink/renderer/core/frame/navigator.h
@@ -22,28 +22,14 @@
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h"
-#include "third_party/blink/renderer/core/frame/navigator_device_memory.h"
-#include "third_party/blink/renderer/core/frame/navigator_id.h"
-#include "third_party/blink/renderer/core/frame/navigator_language.h"
-#include "third_party/blink/renderer/core/frame/navigator_on_line.h"
-#include "third_party/blink/renderer/core/frame/navigator_ua.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
-class CORE_EXPORT Navigator final : public ScriptWrappable,
- public NavigatorConcurrentHardware,
- public NavigatorDeviceMemory,
- public NavigatorID,
- public NavigatorLanguage,
- public NavigatorOnLine,
- public NavigatorUA,
- public ExecutionContextClient,
+class CORE_EXPORT Navigator final : public NavigatorBase,
public Supplementable<Navigator> {
DEFINE_WRAPPERTYPEINFO();
@@ -53,24 +39,21 @@ class CORE_EXPORT Navigator final : public ScriptWrappable,
// NavigatorCookies
bool cookieEnabled() const;
- bool webdriver() const { return true; }
+ bool webdriver() const {
+ return RuntimeEnabledFeatures::AutomationControlledEnabled();
+ }
String productSub() const;
String vendor() const;
String vendorSub() const;
String platform() const override;
- String userAgent() const override;
String GetAcceptLanguages() override;
- UserAgentMetadata GetUserAgentMetadata() const override;
void SetUserAgentMetadataForTesting(UserAgentMetadata);
void Trace(Visitor*) const override;
- protected:
- ExecutionContext* GetUAExecutionContext() const override;
-
private:
UserAgentMetadata metadata_;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_automation_information.idl b/chromium/third_party/blink/renderer/core/frame/navigator_automation_information.idl
index 62907d005f7..047fa678346 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_automation_information.idl
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_automation_information.idl
@@ -4,8 +4,6 @@
// https://w3c.github.io/webdriver/#interface
-[
- RuntimeEnabled=AutomationControlled
-] interface mixin NavigatorAutomationInformation {
- [LegacyUnforgeable] readonly attribute boolean webdriver;
+interface mixin NavigatorAutomationInformation {
+ readonly attribute boolean webdriver;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_id.cc b/chromium/third_party/blink/renderer/core/frame/navigator_id.cc
index 896a8919568..c4b66a398e7 100644
--- a/chromium/third_party/blink/renderer/core/frame/navigator_id.cc
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_id.cc
@@ -34,6 +34,7 @@
#include "base/feature_list.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#if !defined(OS_MAC) && !defined(OS_WIN)
#include <sys/utsname.h>
@@ -81,10 +82,15 @@ String NavigatorID::platform() const {
struct utsname osname;
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<String>, platform_name, ());
if (platform_name->IsNull()) {
- *platform_name =
- String(uname(&osname) >= 0 ? String(osname.sysname) + String(" ") +
- String(osname.machine)
- : g_empty_string);
+ StringBuilder result;
+ if (uname(&osname) >= 0) {
+ result.Append(osname.sysname);
+ if (strlen(osname.machine) != 0) {
+ result.Append(" ");
+ result.Append(osname.machine);
+ }
+ }
+ *platform_name = result.ToString();
}
return *platform_name;
#endif
diff --git a/chromium/third_party/blink/renderer/core/frame/navigator_window_controls_overlay.idl b/chromium/third_party/blink/renderer/core/frame/navigator_window_controls_overlay.idl
new file mode 100644
index 00000000000..2ea293c61ba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/navigator_window_controls_overlay.idl
@@ -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.
+
+// https://github.com/WICG/window-controls-overlay/blob/master/explainer.md
+
+[
+ ImplementedAs=WindowControlsOverlay,
+ RuntimeEnabled=WebAppWindowControlsOverlay
+] partial interface Navigator {
+ [SameObject] readonly attribute WindowControlsOverlay windowControlsOverlay;
+};
diff --git a/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc b/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
index 77f7b9c4cb5..4d7d7651072 100644
--- a/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
+++ b/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -18,8 +20,6 @@ namespace blink {
namespace {
-static bool g_frequency_capping_enabled = true;
-
constexpr base::TimeDelta kFireInterval = base::TimeDelta::FromSeconds(1);
constexpr double kLargeAdSizeToViewportSizeThreshold = 0.1;
@@ -75,7 +75,9 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
}
base::Time current_time = base::Time::Now();
- if (started_detection_ && g_frequency_capping_enabled &&
+ if (started_detection_ &&
+ base::FeatureList::IsEnabled(
+ features::kFrequencyCappingForOverlayPopupDetection) &&
current_time < last_detection_time_ + kFireInterval)
return;
@@ -201,11 +203,6 @@ void OverlayInterstitialAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
}
}
-// static
-void OverlayInterstitialAdDetector::DisableFrequencyCappingForTesting() {
- g_frequency_capping_enabled = false;
-}
-
void OverlayInterstitialAdDetector::OnPopupDetected(LocalFrame* main_frame,
bool is_ad) {
if (!popup_detected_) {
@@ -215,6 +212,7 @@ void OverlayInterstitialAdDetector::OnPopupDetected(LocalFrame* main_frame,
if (is_ad) {
DCHECK(!popup_ad_detected_);
+ main_frame->Client()->OnOverlayPopupAdDetected();
UseCounter::Count(main_frame->GetDocument(), WebFeature::kOverlayPopupAd);
popup_ad_detected_ = true;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h b/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h
index 542dbeab1f6..5e46f8f09be 100644
--- a/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h
+++ b/chromium/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.h
@@ -53,8 +53,6 @@ class CORE_EXPORT OverlayInterstitialAdDetector {
void MaybeFireDetection(LocalFrame* main_frame);
- static void DisableFrequencyCappingForTesting();
-
private:
void OnPopupDetected(LocalFrame* main_frame, bool is_ad);
diff --git a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
index 708cc8142c3..508d97d4af3 100644
--- a/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
+++ b/chromium/third_party/blink/renderer/core/frame/pausable_script_executor.h
@@ -53,7 +53,7 @@ class CORE_EXPORT PausableScriptExecutor final
ScriptState*,
WebScriptExecutionCallback*,
Executor*);
- virtual ~PausableScriptExecutor();
+ ~PausableScriptExecutor() override;
void Run();
void RunAsync(BlockingOption);
diff --git a/chromium/third_party/blink/renderer/core/frame/policy_container.cc b/chromium/third_party/blink/renderer/core/frame/policy_container.cc
index 407b56e1c4b..be039d893a2 100644
--- a/chromium/third_party/blink/renderer/core/frame/policy_container.cc
+++ b/chromium/third_party/blink/renderer/core/frame/policy_container.cc
@@ -8,18 +8,30 @@ namespace blink {
PolicyContainer::PolicyContainer(
mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost> remote,
- mojom::blink::PolicyContainerDocumentPoliciesPtr policies)
+ mojom::blink::PolicyContainerPoliciesPtr policies)
: policies_(std::move(policies)),
policy_container_host_remote_(std::move(remote)) {}
// static
+std::unique_ptr<PolicyContainer> PolicyContainer::CreateEmpty() {
+ // Create a dummy PolicyContainerHost remote. All the messages will be
+ // ignored.
+ mojo::AssociatedRemote<mojom::blink::PolicyContainerHost> dummy_host;
+ ignore_result(dummy_host.BindNewEndpointAndPassDedicatedReceiver());
+
+ return std::make_unique<PolicyContainer>(
+ dummy_host.Unbind(), mojom::blink::PolicyContainerPolicies::New());
+}
+
+// static
std::unique_ptr<PolicyContainer> PolicyContainer::CreateFromWebPolicyContainer(
std::unique_ptr<WebPolicyContainer> container) {
if (!container)
return nullptr;
- mojom::blink::PolicyContainerDocumentPoliciesPtr policies =
- mojom::blink::PolicyContainerDocumentPolicies::New(
- container->policies.referrer_policy);
+ mojom::blink::PolicyContainerPoliciesPtr policies =
+ mojom::blink::PolicyContainerPolicies::New(
+ container->policies.referrer_policy,
+ container->policies.ip_address_space);
return std::make_unique<PolicyContainer>(std::move(container->remote),
std::move(policies));
}
@@ -29,15 +41,29 @@ network::mojom::blink::ReferrerPolicy PolicyContainer::GetReferrerPolicy()
return policies_->referrer_policy;
}
+network::mojom::blink::IPAddressSpace PolicyContainer::GetIPAddressSpace()
+ const {
+ return policies_->ip_address_space;
+}
+
void PolicyContainer::UpdateReferrerPolicy(
network::mojom::blink::ReferrerPolicy policy) {
policies_->referrer_policy = policy;
policy_container_host_remote_->SetReferrerPolicy(policy);
}
-const mojom::blink::PolicyContainerDocumentPoliciesPtr&
-PolicyContainer::GetPolicies() const {
+const mojom::blink::PolicyContainerPoliciesPtr& PolicyContainer::GetPolicies()
+ const {
return policies_;
}
+mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+PolicyContainer::IssueKeepAliveHandle() {
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ keep_alive_remote;
+ policy_container_host_remote_->IssueKeepAliveHandle(
+ keep_alive_remote.InitWithNewPipeAndPassReceiver());
+ return keep_alive_remote;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/policy_container.h b/chromium/third_party/blink/renderer/core/frame/policy_container.h
index 1c7aa1661bf..4639781a003 100644
--- a/chromium/third_party/blink/renderer/core/frame/policy_container.h
+++ b/chromium/third_party/blink/renderer/core/frame/policy_container.h
@@ -6,6 +6,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_POLICY_CONTAINER_H_
#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
#include "third_party/blink/public/platform/web_policy_container.h"
@@ -27,11 +29,12 @@ class CORE_EXPORT PolicyContainer {
PolicyContainer() = delete;
PolicyContainer(
mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost> remote,
- mojom::blink::PolicyContainerDocumentPoliciesPtr policies);
+ mojom::blink::PolicyContainerPoliciesPtr policies);
PolicyContainer(const PolicyContainer&) = delete;
PolicyContainer& operator=(const PolicyContainer&) = delete;
~PolicyContainer() = default;
+ static std::unique_ptr<PolicyContainer> CreateEmpty();
static std::unique_ptr<PolicyContainer> CreateFromWebPolicyContainer(
std::unique_ptr<WebPolicyContainer> container);
@@ -40,10 +43,20 @@ class CORE_EXPORT PolicyContainer {
void UpdateReferrerPolicy(network::mojom::blink::ReferrerPolicy policy);
network::mojom::blink::ReferrerPolicy GetReferrerPolicy() const;
- const mojom::blink::PolicyContainerDocumentPoliciesPtr& GetPolicies() const;
+ network::mojom::blink::IPAddressSpace GetIPAddressSpace() const;
+
+ const mojom::blink::PolicyContainerPoliciesPtr& GetPolicies() const;
+
+ // Return a keep alive handle for the browser process' PolicyContainerHost. If
+ // that PolicyContainerHost is owned by a RenderFrameHost, holding a keep
+ // alive handle ensures that the PolicyContainerHost will still be retrievable
+ // via RenderFrameHostImpl::GetPolicyContainerHost, even if the
+ // RenderFrameHost has been deleted in between.
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ IssueKeepAliveHandle();
private:
- mojom::blink::PolicyContainerDocumentPoliciesPtr policies_;
+ mojom::blink::PolicyContainerPoliciesPtr policies_;
mojo::AssociatedRemote<mojom::blink::PolicyContainerHost>
policy_container_host_remote_;
diff --git a/chromium/third_party/blink/renderer/core/frame/policy_container_test.cc b/chromium/third_party/blink/renderer/core/frame/policy_container_test.cc
index 4aee7886807..b1036d5f723 100644
--- a/chromium/third_party/blink/renderer/core/frame/policy_container_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/policy_container_test.cc
@@ -8,10 +8,25 @@
namespace blink {
+TEST(PolicyContainerTest, MembersAreSetDuringConstruction) {
+ MockPolicyContainerHost host;
+ auto policies = mojom::blink::PolicyContainerPolicies::New(
+ network::mojom::blink::ReferrerPolicy::kNever,
+ network::mojom::blink::IPAddressSpace::kPrivate);
+ PolicyContainer policy_container(host.BindNewEndpointAndPassDedicatedRemote(),
+ std::move(policies));
+
+ EXPECT_EQ(network::mojom::blink::ReferrerPolicy::kNever,
+ policy_container.GetReferrerPolicy());
+ EXPECT_EQ(network::mojom::blink::IPAddressSpace::kPrivate,
+ policy_container.GetIPAddressSpace());
+}
+
TEST(PolicyContainerTest, UpdateReferrerPolicyIsPropagated) {
MockPolicyContainerHost host;
- auto policies = mojom::blink::PolicyContainerDocumentPolicies::New(
- network::mojom::blink::ReferrerPolicy::kAlways);
+ auto policies = mojom::blink::PolicyContainerPolicies::New(
+ network::mojom::blink::ReferrerPolicy::kAlways,
+ network::mojom::blink::IPAddressSpace::kPublic);
PolicyContainer policy_container(host.BindNewEndpointAndPassDedicatedRemote(),
std::move(policies));
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
index 724af9e7db0..0c1aa9a2d53 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/frame/remote_frame.h"
+#include "base/stl_util.h"
#include "cc/layers/surface_layer.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -77,18 +78,12 @@ FloatRect DeNormalizeRect(const gfx::RectF& normalized, const IntRect& base) {
} // namespace
// static
-RemoteFrame* RemoteFrame::FromFrameToken(
- const base::UnguessableToken& frame_token) {
+RemoteFrame* RemoteFrame::FromFrameToken(const RemoteFrameToken& frame_token) {
RemoteFramesByTokenMap& remote_frames_map = GetRemoteFramesMap();
- auto it = remote_frames_map.find(base::UnguessableTokenHash()(frame_token));
+ auto it = remote_frames_map.find(RemoteFrameToken::Hasher()(frame_token));
return it == remote_frames_map.end() ? nullptr : it->value.Get();
}
-// static
-RemoteFrame* RemoteFrame::FromFrameToken(const RemoteFrameToken& frame_token) {
- return FromFrameToken(frame_token.value());
-}
-
RemoteFrame::RemoteFrame(
RemoteFrameClient* client,
Page& page,
@@ -96,7 +91,7 @@ RemoteFrame::RemoteFrame(
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WindowAgentFactory* inheriting_agent_factory,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider)
@@ -109,6 +104,10 @@ RemoteFrame::RemoteFrame(
frame_token,
MakeGarbageCollected<RemoteWindowProxyManager>(*this),
inheriting_agent_factory),
+ // TODO(samans): Investigate if it is safe to delay creation of this
+ // object until a FrameSinkId is provided.
+ parent_local_surface_id_allocator_(
+ std::make_unique<viz::ParentLocalSurfaceIdAllocator>()),
interface_registry_(interface_registry
? interface_registry
: InterfaceRegistry::GetEmptyInterfaceRegistry()),
@@ -118,9 +117,9 @@ RemoteFrame::RemoteFrame(
// TODO(crbug.com/1094850): Remove this check once the renderer is correctly
// handling errors during the creation of HTML portal elements, which would
// otherwise cause RemoteFrame() being created with empty frame tokens.
- if (!frame_token.is_empty()) {
+ if (!frame_token.value().is_empty()) {
auto frame_tracking_result = GetRemoteFramesMap().insert(
- base::UnguessableTokenHash()(frame_token), this);
+ RemoteFrameToken::Hasher()(frame_token), this);
CHECK(frame_tracking_result.stored_value) << "Inserting a duplicate item.";
}
@@ -143,6 +142,11 @@ RemoteFrame::~RemoteFrame() {
DCHECK(!view_);
}
+void RemoteFrame::DetachAndDispose() {
+ DCHECK(!IsMainFrame());
+ Detach(FrameDetachType::kRemove);
+}
+
void RemoteFrame::Trace(Visitor* visitor) const {
visitor->Trace(view_);
visitor->Trace(security_context_);
@@ -168,6 +172,11 @@ void RemoteFrame::Navigate(FrameLoadRequest& frame_request,
const KURL& url = frame_request.GetResourceRequest().Url();
auto* window = frame_request.GetOriginWindow();
+
+ // Note that even if |window| is not null, it could have just been detached
+ // (so window->GetFrame() is null). This can happen for a form submission, if
+ // the frame containing the form has been deleted in between.
+
if (!frame_request.CanDisplay(url)) {
if (window) {
window->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
@@ -189,7 +198,9 @@ void RemoteFrame::Navigate(FrameLoadRequest& frame_request,
MixedContentChecker::UpgradeInsecureRequest(
frame_request.GetResourceRequest(), fetch_client_settings_object, window,
frame_request.GetFrameType(),
- window ? window->GetFrame()->GetContentSettingsClient() : nullptr);
+ (window && window->GetFrame())
+ ? window->GetFrame()->GetContentSettingsClient()
+ : nullptr);
// Navigations in portal contexts do not create back/forward entries.
if (GetPage()->InsidePortal() &&
@@ -197,44 +208,66 @@ void RemoteFrame::Navigate(FrameLoadRequest& frame_request,
frame_load_type = WebFrameLoadType::kReplaceCurrentItem;
}
- WebLocalFrame* initiator_frame =
- window ? window->GetFrame()->Client()->GetWebFrame() : nullptr;
-
bool is_opener_navigation = false;
bool initiator_frame_has_download_sandbox_flag = false;
bool initiator_frame_is_ad = false;
+ base::Optional<LocalFrameToken> initiator_frame_token =
+ base::OptionalFromPtr(frame_request.GetInitiatorFrameToken());
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle =
+ frame_request.TakeInitiatorPolicyContainerKeepAliveHandle();
+
+ // |initiator_frame_token| and |initiator_policy_container_keep_alive_handle|
+ // should either be both specified or both null.
+ DCHECK(!initiator_frame_token ==
+ !initiator_policy_container_keep_alive_handle);
+
if (window) {
- is_opener_navigation = window->GetFrame()->Opener() == this;
initiator_frame_has_download_sandbox_flag =
window->IsSandboxed(network::mojom::blink::WebSandboxFlags::kDownloads);
- initiator_frame_is_ad = window->GetFrame()->IsAdSubframe();
- if (frame_request.ClientRedirectReason() != ClientNavigationReason::kNone) {
- probe::FrameRequestedNavigation(window->GetFrame(), this, url,
- frame_request.ClientRedirectReason(),
- kNavigationPolicyCurrentTab);
+ if (window->GetFrame()) {
+ is_opener_navigation = window->GetFrame()->Opener() == this;
+ initiator_frame_is_ad = window->GetFrame()->IsAdSubframe();
+ if (frame_request.ClientRedirectReason() !=
+ ClientNavigationReason::kNone) {
+ probe::FrameRequestedNavigation(window->GetFrame(), this, url,
+ frame_request.ClientRedirectReason(),
+ kNavigationPolicyCurrentTab);
+ }
+
+ if (!initiator_frame_token) {
+ initiator_frame_token = window->GetFrame()->GetLocalFrameToken();
+ initiator_policy_container_keep_alive_handle =
+ window->GetFrame()->GetPolicyContainer()->IssueKeepAliveHandle();
+ }
}
}
- Client()->Navigate(frame_request.GetResourceRequest(), initiator_frame,
+ // TODO(https://crbug.com/1173409 and https://crbug.com/1059959): Check that
+ // we always have valid |initiator_frame_token| and
+ // |initiator_policy_container_keep_alive_handle|.
+
+ Client()->Navigate(frame_request.GetResourceRequest(),
frame_load_type == WebFrameLoadType::kReplaceCurrentItem,
is_opener_navigation,
initiator_frame_has_download_sandbox_flag,
initiator_frame_is_ad, frame_request.GetBlobURLToken(),
- frame_request.Impression());
+ frame_request.Impression(),
+ base::OptionalOrNullptr(initiator_frame_token),
+ std::move(initiator_policy_container_keep_alive_handle));
}
-void RemoteFrame::DetachImpl(FrameDetachType type) {
+bool RemoteFrame::DetachImpl(FrameDetachType type) {
PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
- DetachChildren();
- if (!Client())
- return;
+
+ if (!DetachChildren())
+ return false;
// Clean up the frame's view if needed. A remote frame only has a view if
// the parent is a local frame.
if (view_)
view_->Dispose();
- GetWindowProxyManager()->ClearForClose();
SetView(nullptr);
// ... the RemoteDOMWindow will need to be informed of detachment,
// as otherwise it will keep a strong reference back to this RemoteFrame.
@@ -243,14 +276,15 @@ void RemoteFrame::DetachImpl(FrameDetachType type) {
// of all these objects. Break the cycle by notifying of detachment.
To<RemoteDOMWindow>(dom_window_.Get())->FrameDetached();
if (cc_layer_)
- SetCcLayer(nullptr, false, false);
+ SetCcLayer(nullptr, false);
receiver_.reset();
main_frame_receiver_.reset();
+
+ return true;
}
bool RemoteFrame::DetachDocument() {
- DetachChildren();
- return !!GetPage();
+ return DetachChildren();
}
void RemoteFrame::CheckCompleted() {
@@ -358,9 +392,9 @@ void RemoteFrame::ForwardPostMessage(
base::Optional<base::UnguessableToken> cluster_id,
scoped_refptr<const SecurityOrigin> target_security_origin,
LocalFrame* source_frame) {
- base::Optional<base::UnguessableToken> source_token;
+ base::Optional<blink::LocalFrameToken> source_token;
if (source_frame)
- source_token = source_frame->GetFrameToken();
+ source_token = source_frame->GetLocalFrameToken();
String source_origin = message_event->origin();
String target_origin = g_empty_string;
@@ -393,16 +427,9 @@ void RemoteFrame::DidChangeVisibleToHitTesting() {
IsIgnoredForHitTest());
}
-void RemoteFrame::SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- const ParsedFeaturePolicy& parsed_header,
- const FeaturePolicyFeatureState& opener_feature_state) {
+void RemoteFrame::SetReplicatedFeaturePolicyHeader(
+ const ParsedFeaturePolicy& parsed_header) {
feature_policy_header_ = parsed_header;
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- DCHECK(opener_feature_state.empty() || IsMainFrame());
- if (OpenerFeatureState().empty()) {
- SetOpenerFeatureState(opener_feature_state);
- }
- }
ApplyReplicatedFeaturePolicyHeader();
}
@@ -420,6 +447,20 @@ void RemoteFrame::SetInsecureNavigationsSet(const WebVector<unsigned>& set) {
security_context_.SetInsecureNavigationsSet(set);
}
+void RemoteFrame::FrameRectsChanged(const IntRect& local_frame_rect,
+ const IntRect& screen_space_rect) {
+ pending_visual_properties_.screen_space_rect = gfx::Rect(screen_space_rect);
+ pending_visual_properties_.local_frame_size =
+ gfx::Size(local_frame_rect.Width(), local_frame_rect.Height());
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::InitializeFrameVisualProperties(
+ const FrameVisualProperties& properties) {
+ pending_visual_properties_ = properties;
+ SynchronizeVisualProperties();
+}
+
void RemoteFrame::WillEnterFullscreen(
mojom::blink::FullscreenOptionsPtr request_options) {
// This should only ever be called when the FrameOwner is local.
@@ -445,12 +486,9 @@ void RemoteFrame::WillEnterFullscreen(
}
void RemoteFrame::AddReplicatedContentSecurityPolicies(
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyHeaderPtr>
- headers) {
- for (auto& header : headers) {
- GetSecurityContext()->GetContentSecurityPolicy()->AddPolicyFromHeaderValue(
- header->header_value, header->type, header->source);
- }
+ WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> csps) {
+ GetSecurityContext()->GetContentSecurityPolicy()->AddPolicies(
+ std::move(csps));
}
void RemoteFrame::ResetReplicatedContentSecurityPolicy() {
@@ -569,7 +607,8 @@ void RemoteFrame::SetEmbeddingToken(
}
void RemoteFrame::SetPageFocus(bool is_focused) {
- WebFrame::FromFrame(this)->View()->SetFocus(is_focused);
+ static_cast<WebViewImpl*>(WebFrame::FromCoreFrame(this)->View())
+ ->SetPageFocus(is_focused);
}
void RemoteFrame::ScrollRectToVisible(
@@ -625,7 +664,7 @@ void RemoteFrame::ScrollRectToVisible(
// view on Android which also requires an automatic zoom into legible scale.
// This is handled by main frame's WebView.
WebViewImpl* web_view =
- static_cast<WebViewImpl*>(WebFrame::FromFrame(this)->View());
+ static_cast<WebViewImpl*>(WebFrame::FromCoreFrame(this)->View());
web_view->ZoomAndScrollToFocusedEditableElementRect(
element_bounds_in_document, caret_bounds_in_document, true);
}
@@ -672,8 +711,7 @@ void RemoteFrame::DidSetFramePolicyHeaders(
ParsedFeaturePolicy parsed_feature_policy_copy(parsed_feature_policy.size());
for (size_t i = 0; i < parsed_feature_policy.size(); ++i)
parsed_feature_policy_copy[i] = parsed_feature_policy[i];
- SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- parsed_feature_policy_copy, FeaturePolicyFeatureState());
+ SetReplicatedFeaturePolicyHeader(parsed_feature_policy_copy);
}
// Update the proxy's FrameOwner with new sandbox flags and container policy
@@ -698,8 +736,8 @@ void RemoteFrame::DidUpdateFramePolicy(const FramePolicy& frame_policy) {
}
void RemoteFrame::UpdateOpener(
- const base::Optional<base::UnguessableToken>& opener_frame_token) {
- if (auto* web_frame = WebFrame::FromFrame(this)) {
+ const base::Optional<blink::FrameToken>& opener_frame_token) {
+ if (auto* web_frame = WebFrame::FromCoreFrame(this)) {
Frame* opener_frame = nullptr;
if (opener_frame_token)
opener_frame = Frame::ResolveFrame(opener_frame_token.value());
@@ -725,7 +763,7 @@ void RemoteFrame::SetOpener(Frame* opener_frame) {
if (Opener() == opener_frame)
return;
- auto* web_frame = WebFrame::FromFrame(this);
+ auto* web_frame = WebFrame::FromCoreFrame(this);
if (web_frame) {
// A proxy shouldn't normally be disowning its opener. It is possible to
// get here when a proxy that is being detached clears its opener, in
@@ -735,9 +773,10 @@ void RemoteFrame::SetOpener(Frame* opener_frame) {
// update another frame's opener.
DCHECK(opener_frame->IsLocalFrame());
GetRemoteFrameHostRemote().DidChangeOpener(
- opener_frame ? base::Optional<base::UnguessableToken>(
- opener_frame->GetFrameToken())
- : base::nullopt);
+ opener_frame
+ ? base::Optional<blink::LocalFrameToken>(
+ opener_frame->GetFrameToken().GetAs<LocalFrameToken>())
+ : base::nullopt);
}
}
SetOpenerDoNotNotify(opener_frame);
@@ -761,8 +800,30 @@ void RemoteFrame::WasAttachedAsRemoteMainFrame() {
&RemoteFrame::BindToMainFrameReceiver, WrapWeakPersistent(this)));
}
+const viz::LocalSurfaceId& RemoteFrame::GetLocalSurfaceId() const {
+ return parent_local_surface_id_allocator_->GetCurrentLocalSurfaceId();
+}
+
viz::FrameSinkId RemoteFrame::GetFrameSinkId() {
- return Client()->GetFrameSinkId();
+ return frame_sink_id_;
+}
+
+void RemoteFrame::SetFrameSinkId(const viz::FrameSinkId& frame_sink_id) {
+ // This is a temporary workaround for https://crbug.com/1166729.
+ // TODO(https://crbug.com/1166722): Remove this once the migration is done.
+ Client()->DidSetFrameSinkId();
+
+ // The same ParentLocalSurfaceIdAllocator cannot provide LocalSurfaceIds for
+ // two different frame sinks, so recreate it here.
+ if (frame_sink_id_ != frame_sink_id) {
+ parent_local_surface_id_allocator_ =
+ std::make_unique<viz::ParentLocalSurfaceIdAllocator>();
+ }
+ frame_sink_id_ = frame_sink_id;
+
+ // Resend the FrameRects and allocate a new viz::LocalSurfaceId when the view
+ // changes.
+ ResendVisualProperties();
}
bool RemoteFrame::IsIgnoredForHitTest() const {
@@ -774,13 +835,10 @@ bool RemoteFrame::IsIgnoredForHitTest() const {
!visible_to_hit_testing_;
}
-void RemoteFrame::SetCcLayer(cc::Layer* cc_layer,
- bool prevent_contents_opaque_changes,
- bool is_surface_layer) {
+void RemoteFrame::SetCcLayer(cc::Layer* cc_layer, bool is_surface_layer) {
DCHECK(Owner());
cc_layer_ = cc_layer;
- prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
is_surface_layer_ = is_surface_layer;
if (cc_layer_) {
if (is_surface_layer) {
@@ -799,14 +857,18 @@ void RemoteFrame::SetCcLayer(cc::Layer* cc_layer,
if (layout_object && layout_object->Layer())
layout_object->Layer()->SetNeedsRepaint();
}
+
+ // Schedule an animation so that a new frame is produced with the updated
+ // layer, otherwise this local root's visible content may not be up to date.
+ owner->GetDocument().GetFrame()->View()->ScheduleAnimation();
}
void RemoteFrame::AdvanceFocus(mojom::blink::FocusType type,
LocalFrame* source) {
- GetRemoteFrameHostRemote().AdvanceFocus(type, source->GetFrameToken());
+ GetRemoteFrameHostRemote().AdvanceFocus(type, source->GetLocalFrameToken());
}
-void RemoteFrame::DetachChildren() {
+bool RemoteFrame::DetachChildren() {
using FrameVector = HeapVector<Member<Frame>>;
FrameVector children_to_detach;
children_to_detach.ReserveCapacity(Tree().ChildCount());
@@ -815,6 +877,8 @@ void RemoteFrame::DetachChildren() {
children_to_detach.push_back(child);
for (const auto& child : children_to_detach)
child->Detach(FrameDetachType::kRemove);
+
+ return !!Client();
}
void RemoteFrame::ApplyReplicatedFeaturePolicyHeader() {
@@ -826,10 +890,171 @@ void RemoteFrame::ApplyReplicatedFeaturePolicyHeader() {
ParsedFeaturePolicy container_policy;
if (Owner())
container_policy = Owner()->GetFramePolicy().container_policy;
- const FeaturePolicyFeatureState& opener_feature_state = OpenerFeatureState();
security_context_.InitializeFeaturePolicy(
- feature_policy_header_, container_policy, parent_feature_policy,
- opener_feature_state.empty() ? nullptr : &opener_feature_state);
+ feature_policy_header_, container_policy, parent_feature_policy);
+}
+
+bool RemoteFrame::SynchronizeVisualProperties(bool propagate) {
+ if (!GetFrameSinkId().is_valid() || Client()->RemoteProcessGone())
+ return false;
+
+ bool capture_sequence_number_changed =
+ sent_visual_properties_ &&
+ sent_visual_properties_->capture_sequence_number !=
+ pending_visual_properties_.capture_sequence_number;
+
+ if (view_) {
+ pending_visual_properties_.compositor_viewport =
+ view_->GetCompositingRect();
+ pending_visual_properties_.compositing_scale_factor =
+ view_->GetCompositingScaleFactor();
+ }
+
+ bool synchronized_props_changed =
+ !sent_visual_properties_ ||
+ sent_visual_properties_->auto_resize_enabled !=
+ pending_visual_properties_.auto_resize_enabled ||
+ sent_visual_properties_->min_size_for_auto_resize !=
+ pending_visual_properties_.min_size_for_auto_resize ||
+ sent_visual_properties_->max_size_for_auto_resize !=
+ pending_visual_properties_.max_size_for_auto_resize ||
+ sent_visual_properties_->local_frame_size !=
+ pending_visual_properties_.local_frame_size ||
+ sent_visual_properties_->screen_space_rect.size() !=
+ pending_visual_properties_.screen_space_rect.size() ||
+ sent_visual_properties_->screen_info !=
+ pending_visual_properties_.screen_info ||
+ sent_visual_properties_->zoom_level !=
+ pending_visual_properties_.zoom_level ||
+ sent_visual_properties_->page_scale_factor !=
+ pending_visual_properties_.page_scale_factor ||
+ sent_visual_properties_->compositing_scale_factor !=
+ pending_visual_properties_.compositing_scale_factor ||
+ sent_visual_properties_->is_pinch_gesture_active !=
+ pending_visual_properties_.is_pinch_gesture_active ||
+ sent_visual_properties_->visible_viewport_size !=
+ pending_visual_properties_.visible_viewport_size ||
+ sent_visual_properties_->compositor_viewport !=
+ pending_visual_properties_.compositor_viewport ||
+ sent_visual_properties_->root_widget_window_segments !=
+ pending_visual_properties_.root_widget_window_segments ||
+ sent_visual_properties_->capture_sequence_number !=
+ pending_visual_properties_.capture_sequence_number;
+
+ if (synchronized_props_changed)
+ parent_local_surface_id_allocator_->GenerateId();
+ pending_visual_properties_.local_surface_id = GetLocalSurfaceId();
+
+ viz::SurfaceId surface_id(frame_sink_id_,
+ pending_visual_properties_.local_surface_id);
+ Client()->WillSynchronizeVisualProperties(
+ capture_sequence_number_changed, surface_id,
+ pending_visual_properties_.compositor_viewport.size());
+
+ bool rect_changed = !sent_visual_properties_ ||
+ sent_visual_properties_->screen_space_rect !=
+ pending_visual_properties_.screen_space_rect;
+ bool visual_properties_changed = synchronized_props_changed || rect_changed;
+
+ if (!visual_properties_changed)
+ return false;
+
+ if (propagate) {
+ GetRemoteFrameHostRemote().SynchronizeVisualProperties(
+ pending_visual_properties_);
+ RecordSentVisualProperties();
+ }
+
+ return true;
+}
+
+void RemoteFrame::RecordSentVisualProperties() {
+ sent_visual_properties_ = pending_visual_properties_;
+ TRACE_EVENT_WITH_FLOW2(
+ TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
+ "RenderFrameProxy::SynchronizeVisualProperties Send Message",
+ TRACE_ID_GLOBAL(
+ pending_visual_properties_.local_surface_id.submission_trace_id()),
+ TRACE_EVENT_FLAG_FLOW_OUT, "message",
+ "FrameHostMsg_SynchronizeVisualProperties", "local_surface_id",
+ pending_visual_properties_.local_surface_id.ToString());
+}
+
+void RemoteFrame::ResendVisualProperties() {
+ sent_visual_properties_ = base::nullopt;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::DidUpdateVisualProperties(
+ const cc::RenderFrameMetadata& metadata) {
+ if (!parent_local_surface_id_allocator_->UpdateFromChild(
+ metadata.local_surface_id.value_or(viz::LocalSurfaceId()))) {
+ return;
+ }
+
+ // The viz::LocalSurfaceId has changed so we call SynchronizeVisualProperties
+ // here to embed it.
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::SetViewportIntersection(
+ const mojom::blink::ViewportIntersectionState& intersection_state) {
+ base::Optional<FrameVisualProperties> visual_properties;
+ if (SynchronizeVisualProperties(/*propagate=*/false)) {
+ visual_properties.emplace(pending_visual_properties_);
+ RecordSentVisualProperties();
+ }
+ GetRemoteFrameHostRemote().UpdateViewportIntersection(
+ intersection_state.Clone(), visual_properties);
+}
+
+void RemoteFrame::DidChangeScreenInfo(const ScreenInfo& screen_info) {
+ pending_visual_properties_.screen_info = screen_info;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::ZoomLevelChanged(double zoom_level) {
+ pending_visual_properties_.zoom_level = zoom_level;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::DidChangeRootWindowSegments(
+ const std::vector<gfx::Rect>& root_widget_window_segments) {
+ pending_visual_properties_.root_widget_window_segments =
+ std::move(root_widget_window_segments);
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::PageScaleFactorChanged(float page_scale_factor,
+ bool is_pinch_gesture_active) {
+ pending_visual_properties_.page_scale_factor = page_scale_factor;
+ pending_visual_properties_.is_pinch_gesture_active = is_pinch_gesture_active;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::DidChangeVisibleViewportSize(
+ const gfx::Size& visible_viewport_size) {
+ pending_visual_properties_.visible_viewport_size = visible_viewport_size;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::UpdateCaptureSequenceNumber(
+ uint32_t capture_sequence_number) {
+ pending_visual_properties_.capture_sequence_number = capture_sequence_number;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::EnableAutoResize(const gfx::Size& min_size,
+ const gfx::Size& max_size) {
+ pending_visual_properties_.auto_resize_enabled = true;
+ pending_visual_properties_.min_size_for_auto_resize = min_size;
+ pending_visual_properties_.max_size_for_auto_resize = max_size;
+ SynchronizeVisualProperties();
+}
+
+void RemoteFrame::DisableAutoResize() {
+ pending_visual_properties_.auto_resize_enabled = false;
+ SynchronizeVisualProperties();
}
void RemoteFrame::BindToReceiver(
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame.h b/chromium/third_party/blink/renderer/core/frame/remote_frame.h
index e0ee536a7ae..8de0cde8156 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame.h
@@ -5,9 +5,11 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_REMOTE_FRAME_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_REMOTE_FRAME_H_
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
+#include "third_party/blink/public/common/frame/frame_visual_properties.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
@@ -42,8 +44,6 @@ class CORE_EXPORT RemoteFrame final : public Frame,
public mojom::blink::RemoteFrame {
public:
// Returns the RemoteFrame for the given |frame_token|.
- // TODO(crbug.com/1096617): Remove the UnguessableToken version of this.
- static RemoteFrame* FromFrameToken(const base::UnguessableToken& frame_token);
static RemoteFrame* FromFrameToken(const RemoteFrameToken& frame_token);
// For a description of |inheriting_agent_factory| go see the comment on the
@@ -54,7 +54,7 @@ class CORE_EXPORT RemoteFrame final : public Frame,
Frame* parent,
Frame* previous_sibling,
FrameInsertType insert_type,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WindowAgentFactory* inheriting_agent_factory,
InterfaceRegistry*,
AssociatedInterfaceProvider*);
@@ -80,13 +80,8 @@ class CORE_EXPORT RemoteFrame final : public Frame,
void AddResourceTimingFromChild(
mojom::blink::ResourceTimingInfoPtr timing) override;
- void SetCcLayer(cc::Layer*,
- bool prevent_contents_opaque_changes,
- bool is_surface_layer);
+ void SetCcLayer(cc::Layer*, bool is_surface_layer);
cc::Layer* GetCcLayer() const { return cc_layer_; }
- bool WebLayerHasFixedContentsOpaque() const {
- return prevent_contents_opaque_changes_;
- }
void AdvanceFocus(mojom::blink::FocusType, LocalFrame* source);
@@ -111,21 +106,47 @@ class CORE_EXPORT RemoteFrame final : public Frame,
void DidChangeVisibleToHitTesting() override;
- void SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- const ParsedFeaturePolicy& parsed_header,
- const FeaturePolicyFeatureState&);
+ void SetReplicatedFeaturePolicyHeader(
+ const ParsedFeaturePolicy& parsed_header);
void SetReplicatedSandboxFlags(network::mojom::blink::WebSandboxFlags);
void SetInsecureRequestPolicy(mojom::blink::InsecureRequestPolicy);
void SetInsecureNavigationsSet(const WebVector<unsigned>&);
+ void FrameRectsChanged(const IntRect& local_frame_rect,
+ const IntRect& screen_space_rect);
+ void InitializeFrameVisualProperties(const FrameVisualProperties& properties);
+ // If 'propagate' is true, updated properties will be sent to the browser.
+ // Returns true if visual properties have changed.
+ bool SynchronizeVisualProperties(bool propagate = true);
+ void ResendVisualProperties();
+ void SetViewportIntersection(const mojom::blink::ViewportIntersectionState&);
+
+ // Called when the local root's screen info changes.
+ void DidChangeScreenInfo(const ScreenInfo& screen_info);
+ // Called when the main frame's zoom level is changed and should be propagated
+ // to the remote's associated view.
+ void ZoomLevelChanged(double zoom_level);
+ // Called when the local root's window segments change.
+ void DidChangeRootWindowSegments(
+ const std::vector<gfx::Rect>& root_widget_window_segments);
+ // Called when the local page scale factor changed.
+ void PageScaleFactorChanged(float page_scale_factor,
+ bool is_pinch_gesture_active);
+ // Called when the local root's visible viewport changes size.
+ void DidChangeVisibleViewportSize(const gfx::Size& visible_viewport_size);
+ // Called when the local root's capture sequence number has changed.
+ void UpdateCaptureSequenceNumber(uint32_t sequence_number);
const String& UniqueName() const { return unique_name_; }
+ const FrameVisualProperties& GetPendingVisualPropertiesForTesting() const {
+ return pending_visual_properties_;
+ }
// blink::mojom::RemoteFrame overrides:
void WillEnterFullscreen(mojom::blink::FullscreenOptionsPtr) override;
void AddReplicatedContentSecurityPolicies(
- WTF::Vector<network::mojom::blink::ContentSecurityPolicyHeaderPtr>
- headers) override;
+ WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> csps)
+ override;
void ResetReplicatedContentSecurityPolicy() override;
void EnforceInsecureNavigationsSet(const WTF::Vector<uint32_t>& set) override;
void SetFrameOwnerProperties(
@@ -169,8 +190,15 @@ class CORE_EXPORT RemoteFrame final : public Frame,
// sandbox flags or container policy. The new policy won't take effect until
// the next navigation.
void DidUpdateFramePolicy(const FramePolicy& frame_policy) override;
- void UpdateOpener(const base::Optional<base::UnguessableToken>&
- opener_frame_token) override;
+ void UpdateOpener(
+ const base::Optional<blink::FrameToken>& opener_frame_token) override;
+ void DetachAndDispose() override;
+ void EnableAutoResize(const gfx::Size& min_size,
+ const gfx::Size& max_size) override;
+ void DisableAutoResize() override;
+ void DidUpdateVisualProperties(
+ const cc::RenderFrameMetadata& metadata) override;
+ void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id) override;
// Called only when this frame has a local frame owner.
IntSize GetMainFrameViewportSize() const override;
@@ -189,22 +217,26 @@ class CORE_EXPORT RemoteFrame final : public Frame,
void WasAttachedAsRemoteMainFrame();
RemoteFrameToken GetRemoteFrameToken() const {
- return RemoteFrameToken(GetFrameToken());
+ return GetFrameToken().GetAs<RemoteFrameToken>();
}
+ const viz::LocalSurfaceId& GetLocalSurfaceId() const;
+
viz::FrameSinkId GetFrameSinkId();
private:
// Frame protected overrides:
- void DetachImpl(FrameDetachType) override;
+ bool DetachImpl(FrameDetachType) override;
// Intentionally private to prevent redundant checks when the type is
// already RemoteFrame.
bool IsLocalFrame() const override { return false; }
bool IsRemoteFrame() const override { return true; }
- void DetachChildren();
+ // Returns false if detaching child frames reentrantly detached `this`.
+ bool DetachChildren();
void ApplyReplicatedFeaturePolicyHeader();
+ void RecordSentVisualProperties();
static void BindToReceiver(
RemoteFrame* frame,
@@ -215,12 +247,17 @@ class CORE_EXPORT RemoteFrame final : public Frame,
Member<RemoteFrameView> view_;
RemoteSecurityContext security_context_;
+ base::Optional<blink::FrameVisualProperties> sent_visual_properties_;
+ blink::FrameVisualProperties pending_visual_properties_;
cc::Layer* cc_layer_ = nullptr;
- bool prevent_contents_opaque_changes_ = false;
bool is_surface_layer_ = false;
ParsedFeaturePolicy feature_policy_header_;
String unique_name_;
+ viz::FrameSinkId frame_sink_id_;
+ std::unique_ptr<viz::ParentLocalSurfaceIdAllocator>
+ parent_local_surface_id_allocator_;
+
InterfaceRegistry* const interface_registry_;
mojo::AssociatedRemote<mojom::blink::RemoteFrameHost>
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
index b9782dc1391..8606b6e0564 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client.h
@@ -7,7 +7,9 @@
#include "base/optional.h"
#include "cc/paint/paint_canvas.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_impression.h"
#include "third_party/blink/public/web/web_frame_load_type.h"
@@ -16,59 +18,42 @@
#include "third_party/blink/renderer/platform/graphics/touch_action.h"
namespace viz {
-class FrameSinkId;
+class SurfaceId;
}
namespace blink {
class AssociatedInterfaceProvider;
-class IntRect;
class ResourceRequest;
-struct ScreenInfo;
-class WebLocalFrame;
class RemoteFrameClient : public FrameClient {
public:
~RemoteFrameClient() override = default;
- virtual void Navigate(const ResourceRequest&,
- blink::WebLocalFrame* initiator_frame,
- bool should_replace_current_entry,
- bool is_opener_navigation,
- bool initiator_frame_has_download_sandbox_flag,
- bool initiator_frame_is_ad,
- mojo::PendingRemote<mojom::blink::BlobURLToken>,
- const base::Optional<WebImpression>& impression) = 0;
+ virtual void Navigate(
+ const ResourceRequest&,
+ bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool initiator_frame_has_download_sandbox_flag,
+ bool initiator_frame_is_ad,
+ mojo::PendingRemote<mojom::blink::BlobURLToken>,
+ const base::Optional<WebImpression>& impression,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle) = 0;
unsigned BackForwardLength() override = 0;
- // Forwards a change to the rects of a remote frame. |local_frame_rect| is the
- // size of the frame in its parent's coordinate space prior to applying CSS
- // transforms. |screen_space_rect| is in the screen's coordinate space, after
- // CSS transforms are applied.
- virtual void FrameRectsChanged(const IntRect& local_frame_rect,
- const IntRect& screen_space_rect) = 0;
+ virtual void WillSynchronizeVisualProperties(
+ bool capture_sequence_number_changed,
+ const viz::SurfaceId& surface_id,
+ const gfx::Size& compositor_viewport_size) = 0;
- virtual void ZoomLevelChanged(double zoom_level) = 0;
+ virtual bool RemoteProcessGone() const = 0;
- virtual void UpdateCaptureSequenceNumber(uint32_t sequence_number) = 0;
-
- virtual void PageScaleFactorChanged(float page_scale_factor,
- bool is_pinch_gesture_active) = 0;
-
- virtual void DidChangeScreenInfo(const ScreenInfo& original_screen_info) = 0;
-
- virtual void DidChangeRootWindowSegments(
- const std::vector<gfx::Rect>& root_widget_window_segments) = 0;
-
- virtual void DidChangeVisibleViewportSize(
- const gfx::Size& visible_viewport_size) = 0;
-
- virtual void SynchronizeVisualProperties() = 0;
+ // This is a temporary workaround for https://crbug.com/1166729.
+ // TODO(https://crbug.com/1166722): Remove this once the migration is done.
+ virtual void DidSetFrameSinkId() = 0;
virtual AssociatedInterfaceProvider* GetRemoteAssociatedInterfaces() = 0;
-
- virtual viz::FrameSinkId GetFrameSinkId() = 0;
-
- virtual void WasEvicted() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
index 6e4691185f0..b96e5d246f2 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -73,22 +73,24 @@ base::UnguessableToken RemoteFrameClientImpl::GetDevToolsFrameToken() const {
void RemoteFrameClientImpl::Navigate(
const ResourceRequest& request,
- blink::WebLocalFrame* initiator_frame,
bool should_replace_current_entry,
bool is_opener_navigation,
bool initiator_frame_has_download_sandbox_flag,
bool initiator_frame_is_ad,
mojo::PendingRemote<mojom::blink::BlobURLToken> blob_url_token,
- const base::Optional<WebImpression>& impression) {
+ const base::Optional<WebImpression>& impression,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle) {
bool blocking_downloads_in_sandbox_enabled =
RuntimeEnabledFeatures::BlockingDownloadsInSandboxEnabled();
if (web_frame_->Client()) {
web_frame_->Client()->Navigate(
- WrappedResourceRequest(request), initiator_frame,
- should_replace_current_entry, is_opener_navigation,
- initiator_frame_has_download_sandbox_flag,
+ WrappedResourceRequest(request), should_replace_current_entry,
+ is_opener_navigation, initiator_frame_has_download_sandbox_flag,
blocking_downloads_in_sandbox_enabled, initiator_frame_is_ad,
- std::move(blob_url_token), impression);
+ std::move(blob_url_token), impression, initiator_frame_token,
+ std::move(initiator_policy_container_keep_alive_handle));
}
}
@@ -100,46 +102,21 @@ unsigned RemoteFrameClientImpl::BackForwardLength() {
return 2;
}
-void RemoteFrameClientImpl::FrameRectsChanged(
- const IntRect& local_frame_rect,
- const IntRect& screen_space_rect) {
- web_frame_->Client()->FrameRectsChanged(local_frame_rect, screen_space_rect);
+void RemoteFrameClientImpl::WillSynchronizeVisualProperties(
+ bool capture_sequence_number_changed,
+ const viz::SurfaceId& surface_id,
+ const gfx::Size& compositor_viewport_size) {
+ web_frame_->Client()->WillSynchronizeVisualProperties(
+ capture_sequence_number_changed, surface_id,
+ compositor_viewport_size);
}
-void RemoteFrameClientImpl::ZoomLevelChanged(double zoom_level) {
- web_frame_->Client()->ZoomLevelChanged(zoom_level);
+bool RemoteFrameClientImpl::RemoteProcessGone() const {
+ return web_frame_->Client()->RemoteProcessGone();
}
-void RemoteFrameClientImpl::UpdateCaptureSequenceNumber(
- uint32_t sequence_number) {
- web_frame_->Client()->UpdateCaptureSequenceNumber(sequence_number);
-}
-
-void RemoteFrameClientImpl::PageScaleFactorChanged(
- float page_scale_factor,
- bool is_pinch_gesture_active) {
- web_frame_->Client()->PageScaleFactorChanged(page_scale_factor,
- is_pinch_gesture_active);
-}
-
-void RemoteFrameClientImpl::DidChangeScreenInfo(
- const ScreenInfo& original_screen_info) {
- web_frame_->Client()->DidChangeScreenInfo(original_screen_info);
-}
-
-void RemoteFrameClientImpl::DidChangeRootWindowSegments(
- const std::vector<gfx::Rect>& root_widget_window_segments) {
- web_frame_->Client()->DidChangeRootWindowSegments(
- root_widget_window_segments);
-}
-
-void RemoteFrameClientImpl::DidChangeVisibleViewportSize(
- const gfx::Size& visible_viewport_size) {
- web_frame_->Client()->DidChangeVisibleViewportSize(visible_viewport_size);
-}
-
-void RemoteFrameClientImpl::SynchronizeVisualProperties() {
- web_frame_->Client()->SynchronizeVisualProperties();
+void RemoteFrameClientImpl::DidSetFrameSinkId() {
+ web_frame_->Client()->DidSetFrameSinkId();
}
AssociatedInterfaceProvider*
@@ -147,12 +124,4 @@ RemoteFrameClientImpl::GetRemoteAssociatedInterfaces() {
return web_frame_->Client()->GetRemoteAssociatedInterfaces();
}
-viz::FrameSinkId RemoteFrameClientImpl::GetFrameSinkId() {
- return web_frame_->Client()->GetFrameSinkId();
-}
-
-void RemoteFrameClientImpl::WasEvicted() {
- return web_frame_->Client()->WasEvicted();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
index ab941bd4f6c..be0f2a57ea0 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -23,30 +23,25 @@ class RemoteFrameClientImpl final : public RemoteFrameClient {
base::UnguessableToken GetDevToolsFrameToken() const override;
// RemoteFrameClient overrides:
- void Navigate(const ResourceRequest&,
- blink::WebLocalFrame* initiator_frame,
- bool should_replace_current_entry,
- bool is_opener_navigation,
- bool prevent_sandboxed_download,
- bool initiator_frame_is_ad,
- mojo::PendingRemote<mojom::blink::BlobURLToken>,
- const base::Optional<WebImpression>& impression) override;
+ void Navigate(
+ const ResourceRequest&,
+ bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool prevent_sandboxed_download,
+ bool initiator_frame_is_ad,
+ mojo::PendingRemote<mojom::blink::BlobURLToken>,
+ const base::Optional<WebImpression>& impression,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle) override;
unsigned BackForwardLength() override;
- void FrameRectsChanged(const IntRect& local_frame_rect,
- const IntRect& screen_space_rect) override;
- void ZoomLevelChanged(double zoom_level) override;
- void UpdateCaptureSequenceNumber(uint32_t sequence_number) override;
- void PageScaleFactorChanged(float page_scale_factor,
- bool is_pinch_gesture_active) override;
- void DidChangeScreenInfo(const ScreenInfo& original_screen_info) override;
- void DidChangeRootWindowSegments(
- const std::vector<gfx::Rect>& root_widget_window_segments) override;
- void DidChangeVisibleViewportSize(
- const gfx::Size& visible_viewport_size) override;
- void SynchronizeVisualProperties() override;
+ void WillSynchronizeVisualProperties(
+ bool capture_sequence_number_changed,
+ const viz::SurfaceId& surface_id,
+ const gfx::Size& compositor_viewport_size) override;
+ bool RemoteProcessGone() const override;
+ void DidSetFrameSinkId() override;
AssociatedInterfaceProvider* GetRemoteAssociatedInterfaces() override;
- viz::FrameSinkId GetFrameSinkId() override;
- void WasEvicted() override;
WebRemoteFrameImpl* GetWebFrame() const { return web_frame_; }
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.cc
index 70e5b4020c0..b31db5f1e79 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.cc
@@ -9,11 +9,12 @@
#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/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
#include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.h
index 1350a6bc1fc..201ae55a63e 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_owner.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_REMOTE_FRAME_OWNER_H_
#include "third_party/blink/public/common/frame/frame_policy.h"
+#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
@@ -56,7 +57,9 @@ class CORE_EXPORT RemoteFrameOwner final
bool AllowFullscreen() const override { return allow_fullscreen_; }
bool AllowPaymentRequest() const override { return allow_payment_request_; }
bool IsDisplayNone() const override { return is_display_none_; }
- mojom::ColorScheme GetColorScheme() const override { return color_scheme_; }
+ mojom::blink::ColorScheme GetColorScheme() const override {
+ return color_scheme_;
+ }
AtomicString RequiredCsp() const override { return required_csp_; }
bool ShouldLazyLoadChildren() const final;
@@ -78,7 +81,7 @@ class CORE_EXPORT RemoteFrameOwner final
void SetIsDisplayNone(bool is_display_none) {
is_display_none_ = is_display_none;
}
- void SetColorScheme(mojom::ColorScheme color_scheme) {
+ void SetColorScheme(mojom::blink::ColorScheme color_scheme) {
color_scheme_ = color_scheme;
}
void SetRequiredCsp(const WebString& required_csp) {
@@ -102,7 +105,7 @@ class CORE_EXPORT RemoteFrameOwner final
bool allow_fullscreen_;
bool allow_payment_request_;
bool is_display_none_;
- mojom::ColorScheme color_scheme_;
+ mojom::blink::ColorScheme color_scheme_;
bool needs_occlusion_tracking_;
WebString required_csp_;
const mojom::blink::FrameOwnerElementType frame_owner_element_type_;
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
index f5d2eff67cc..51508bf1cb4 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -21,6 +21,8 @@
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
+#include "ui/gfx/transform_util.h"
#if BUILDFLAG(ENABLE_PRINTING)
// nogncheck because dependency on //printing is conditional upon
@@ -80,7 +82,8 @@ void RemoteFrameView::AttachToLayout() {
UpdateFrameVisibility(true);
UpdateRenderThrottlingStatus(
IsHiddenForThrottling(),
- ParentFrameView()->CanThrottleRenderingForPropagation());
+ ParentFrameView()->CanThrottleRenderingForPropagation(),
+ IsDisplayLocked());
needs_frame_rect_propagation_ = true;
ParentFrameView()->SetNeedsUpdateGeometries();
}
@@ -103,9 +106,8 @@ void RemoteFrameView::SetViewportIntersection(
new_state.compositor_visible_rect = gfx::Rect(compositing_rect_);
if (!last_intersection_state_.Equals(new_state)) {
last_intersection_state_ = new_state;
- remote_frame_->Client()->SynchronizeVisualProperties();
- remote_frame_->GetRemoteFrameHostRemote().UpdateViewportIntersection(
- new_state.Clone());
+ GetFrame().SynchronizeVisualProperties();
+ remote_frame_->SetViewportIntersection(new_state);
} else if (needs_frame_rect_propagation_) {
PropagateFrameRects();
}
@@ -178,6 +180,55 @@ void RemoteFrameView::UpdateCompositingRect() {
needs_frame_rect_propagation_ = true;
}
+void RemoteFrameView::UpdateCompositingScaleFactor() {
+ float previous_scale_factor = compositing_scale_factor_;
+
+ LocalFrameView* local_root_view = ParentLocalRootFrameView();
+ LayoutEmbeddedContent* owner_layout_object =
+ remote_frame_->OwnerLayoutObject();
+ if (!local_root_view || !owner_layout_object)
+ return;
+
+ TransformState local_root_transform_state(
+ TransformState::kApplyTransformDirection);
+ local_root_transform_state.Move(
+ owner_layout_object->PhysicalContentBoxOffset());
+ owner_layout_object->MapLocalToAncestor(nullptr, local_root_transform_state,
+ kTraverseDocumentBoundaries);
+
+ float frame_to_local_root_scale_factor = 1.0f;
+ gfx::Transform local_root_transform = TransformationMatrix::ToTransform(
+ local_root_transform_state.AccumulatedTransform());
+ if (local_root_transform.HasPerspective()) {
+ frame_to_local_root_scale_factor =
+ gfx::ComputeApproximateMaxScale(local_root_transform);
+ } else {
+ gfx::Vector2dF scale_components =
+ gfx::ComputeTransform2dScaleComponents(local_root_transform,
+ /*fallback_scale=*/1.0f);
+ frame_to_local_root_scale_factor =
+ std::max(scale_components.x(), scale_components.y());
+ }
+
+ // The compositing scale factor is calculated by multiplying the scale factor
+ // from the local root to main frame with the scale factor between child frame
+ // and local root.
+ FrameWidget* widget = local_root_view->GetFrame().GetWidgetForLocalRoot();
+ compositing_scale_factor_ =
+ widget->GetCompositingScaleFactor() * frame_to_local_root_scale_factor;
+
+ // Force compositing scale factor to be at least a reasonable minimum value to
+ // prevent dependent values such as scroll deltas in the compositor going to
+ // zero. It's possible for the calculated scale factor to go to zero since
+ // it depends on intermediate CSS transforms which could have zero scale.
+ constexpr float kMinCompositingScaleFactor = 0.25f;
+ compositing_scale_factor_ =
+ std::max(compositing_scale_factor_, kMinCompositingScaleFactor);
+
+ if (compositing_scale_factor_ != previous_scale_factor)
+ remote_frame_->SynchronizeVisualProperties();
+}
+
void RemoteFrameView::Dispose() {
HTMLFrameOwnerElement* owner_element = remote_frame_->DeprecatedLocalOwner();
// ownerElement can be null during frame swaps, because the
@@ -215,7 +266,7 @@ void RemoteFrameView::PropagateFrameRects() {
if (LocalFrameView* parent = ParentFrameView()) {
screen_space_rect = parent->ConvertToRootFrame(screen_space_rect);
}
- remote_frame_->Client()->FrameRectsChanged(frame_rect, screen_space_rect);
+ remote_frame_->FrameRectsChanged(frame_rect, screen_space_rect);
}
void RemoteFrameView::Paint(GraphicsContext& context,
@@ -225,18 +276,20 @@ void RemoteFrameView::Paint(GraphicsContext& context,
if (!rect.Intersects(FrameRect()))
return;
- if (context.IsPrintingOrPaintingPreview()) {
- DrawingRecorder recorder(context, *GetFrame().OwnerLayoutObject(),
+ const auto& owner_layout_object = *GetFrame().OwnerLayoutObject();
+ if (owner_layout_object.GetDocument().IsPrintingOrPaintingPreview()) {
+ DrawingRecorder recorder(context, owner_layout_object,
DisplayItem::kDocumentBackground);
context.Save();
context.Translate(paint_offset.Width(), paint_offset.Height());
DCHECK(context.Canvas());
uint32_t content_id = 0;
- if (context.Printing()) {
+ if (owner_layout_object.GetDocument().Printing()) {
// Inform the remote frame to print.
content_id = Print(FrameRect(), context.Canvas());
- } else if (context.IsPaintingPreview()) {
+ } else {
+ DCHECK(owner_layout_object.GetDocument().IsPaintingPreview());
// Inform the remote frame to capture a paint preview.
content_id = CapturePaintPreview(FrameRect(), context.Canvas());
}
@@ -249,7 +302,7 @@ void RemoteFrameView::Paint(GraphicsContext& context,
GetFrame().GetCcLayer()) {
auto offset = RoundedIntPoint(
GetLayoutEmbeddedContent()->ReplacedContentRect().offset);
- RecordForeignLayer(context, *GetFrame().OwnerLayoutObject(),
+ RecordForeignLayer(context, owner_layout_object,
DisplayItem::kForeignLayerRemoteFrame,
GetFrame().GetCcLayer(), offset);
}
@@ -281,8 +334,10 @@ void RemoteFrameView::ParentVisibleChanged() {
void RemoteFrameView::VisibilityForThrottlingChanged() {
TRACE_EVENT0("blink", "RemoteFrameView::VisibilityForThrottlingChanged");
+ // TODO(szager,vmpstr): Send IsSubtreeThrottled() and IsDisplayLocked() as
+ // separate bits.
remote_frame_->GetRemoteFrameHostRemote().UpdateRenderThrottlingStatus(
- IsHiddenForThrottling(), IsSubtreeThrottled());
+ IsHiddenForThrottling(), IsSubtreeThrottled(), IsDisplayLocked());
}
void RemoteFrameView::VisibilityChanged(
@@ -291,7 +346,7 @@ void RemoteFrameView::VisibilityChanged(
}
bool RemoteFrameView::CanThrottleRendering() const {
- return IsSubtreeThrottled() || IsHiddenForThrottling();
+ return IsHiddenForThrottling() || IsSubtreeThrottled() || IsDisplayLocked();
}
void RemoteFrameView::SetIntrinsicSizeInfo(
@@ -325,7 +380,7 @@ uint32_t RemoteFrameView::Print(const IntRect& rect,
// represents the state of the remote frame. See also comments on
// https://crrev.com/c/2245430/.
uint32_t content_id = metafile->CreateContentForRemoteFrame(
- rect, remote_frame_->GetFrameToken());
+ rect, remote_frame_->GetFrameToken().value());
// Inform browser to print the remote subframe.
remote_frame_->GetRemoteFrameHostRemote().PrintCrossProcessSubframe(
diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
index b8da01a1236..a97ceb48c4d 100644
--- a/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
+++ b/chromium/third_party/blink/renderer/core/frame/remote_frame_view.h
@@ -73,6 +73,9 @@ class RemoteFrameView final : public GarbageCollected<RemoteFrameView>,
void UpdateCompositingRect();
IntRect GetCompositingRect() const { return compositing_rect_; }
+ void UpdateCompositingScaleFactor();
+ float GetCompositingScaleFactor() const { return compositing_scale_factor_; }
+
uint32_t Print(const IntRect&, cc::PaintCanvas*) const;
uint32_t CapturePaintPreview(const IntRect&, cc::PaintCanvas*) const;
@@ -99,6 +102,7 @@ class RemoteFrameView final : public GarbageCollected<RemoteFrameView>,
Member<RemoteFrame> remote_frame_;
mojom::blink::ViewportIntersectionState last_intersection_state_;
IntRect compositing_rect_;
+ float compositing_scale_factor_ = 1.0f;
IntrinsicSizingInfo intrinsic_sizing_info_;
bool has_intrinsic_sizing_info_ = false;
diff --git a/chromium/third_party/blink/renderer/core/frame/reporting_context.cc b/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
index 18940ebe82a..83b93cc83e1 100644
--- a/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
+++ b/chromium/third_party/blink/renderer/core/frame/reporting_context.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/frame/reporting_context.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/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -143,7 +143,7 @@ void ReportingContext::CountReport(Report* report) {
const HeapMojoRemote<mojom::blink::ReportingServiceProxy>&
ReportingContext::GetReportingService() const {
if (!reporting_service_.is_bound()) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ execution_context_->GetBrowserInterfaceBroker().GetInterface(
reporting_service_.BindNewPipeAndPassReceiver(
execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI)));
}
diff --git a/chromium/third_party/blink/renderer/core/frame/reporting_context_test.cc b/chromium/third_party/blink/renderer/core/frame/reporting_context_test.cc
index 7ae687c38cc..4cb1eae3dad 100644
--- a/chromium/third_party/blink/renderer/core/frame/reporting_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/reporting_context_test.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "testing/gtest/include/gtest/gtest.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/renderer/core/frame/deprecation_report_body.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/report.h"
@@ -28,10 +28,10 @@ class MockReportingServiceProxy : public mojom::blink::ReportingServiceProxy {
using ReportingServiceProxy = mojom::blink::ReportingServiceProxy;
public:
- MockReportingServiceProxy(ThreadSafeBrowserInterfaceBrokerProxy& broker,
+ MockReportingServiceProxy(const BrowserInterfaceBrokerProxy& broker,
base::OnceClosure reached_callback)
: broker_(broker), reached_callback_(std::move(reached_callback)) {
- broker.SetBinderForTesting(
+ broker_.SetBinderForTesting(
ReportingServiceProxy::Name_,
WTF::BindRepeating(&MockReportingServiceProxy::BindReceiver,
WTF::Unretained(this)));
@@ -114,7 +114,7 @@ class MockReportingServiceProxy : public mojom::blink::ReportingServiceProxy {
std::move(reached_callback_).Run();
}
- ThreadSafeBrowserInterfaceBrokerProxy& broker_;
+ const BrowserInterfaceBrokerProxy& broker_;
mojo::ReceiverSet<ReportingServiceProxy> receivers_;
base::OnceClosure reached_callback_;
@@ -146,9 +146,8 @@ TEST_F(ReportingContextTest, DeprecationReportContent) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>();
auto* win = dummy_page_holder->GetFrame().DomWindow();
base::RunLoop run_loop;
- MockReportingServiceProxy reporting_service(
- *Platform::Current()->GetBrowserInterfaceBroker(),
- run_loop.QuitClosure());
+ MockReportingServiceProxy reporting_service(win->GetBrowserInterfaceBroker(),
+ run_loop.QuitClosure());
auto* body = MakeGarbageCollected<DeprecationReportBody>(
"FeatureId", base::Time::FromJsTime(1000), "Test report");
diff --git a/chromium/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc b/chromium/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
index 3f22e7a6f45..2b99489b1dd 100644
--- a/chromium/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
@@ -38,13 +38,6 @@ void ResizeViewportAnchor::EndScope() {
ScrollOffset visual_viewport_in_document =
frame_view->GetScrollableArea()->GetScrollOffset() - drift_;
- // TODO(bokan): Don't use RootFrameViewport::setScrollPosition since it
- // assumes we can just set a sub-pixel precision offset on the LocalFrameView.
- // While we "can" do this, the offset that will be shipped to CC will be the
- // truncated number and this class is used to handle TopControl movement
- // which needs the two threads to match exactly pixel-for-pixel. We can
- // replace this with RFV::setScrollPosition once Blink is sub-pixel scroll
- // offset aware. crbug.com/414283.
DCHECK(frame_view->GetRootFrameViewport());
frame_view->GetRootFrameViewport()->RestoreToAnchor(
visual_viewport_in_document);
diff --git a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc
index 440c3479d0a..c99474c8508 100644
--- a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc
+++ b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc
@@ -48,7 +48,9 @@ FloatRect GetUserScrollableRect(const ScrollableArea& area) {
} // namespace
RootFrameViewport::RootFrameViewport(ScrollableArea& visual_viewport,
ScrollableArea& layout_viewport)
- : visual_viewport_(visual_viewport), should_restore_scroll_(false) {
+ : ScrollableArea(visual_viewport.GetCompositorTaskRunner()),
+ visual_viewport_(visual_viewport),
+ should_restore_scroll_(false) {
SetLayoutViewport(layout_viewport);
}
@@ -107,18 +109,18 @@ void RootFrameViewport::RestoreToAnchor(const ScrollOffset& target_offset) {
delta = target_offset - GetScrollOffset();
- // Since the main thread LocalFrameView has integer scroll offsets, scroll it
- // to the next pixel and then we'll scroll the visual viewport again to
- // compensate for the sub-pixel offset. We need this "overscroll" to ensure
- // the pixel of which we want to be partially in appears fully inside the
- // LocalFrameView since the VisualViewport is bounded by the LocalFrameView.
- IntSize layout_delta = IntSize(
- delta.Width() < 0 ? floor(delta.Width()) : ceil(delta.Width()),
- delta.Height() < 0 ? floor(delta.Height()) : ceil(delta.Height()));
-
- LayoutViewport().SetScrollOffset(
- ScrollOffset(LayoutViewport().ScrollOffsetInt() + layout_delta),
- mojom::blink::ScrollType::kProgrammatic);
+ if (RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled()) {
+ LayoutViewport().SetScrollOffset(LayoutViewport().GetScrollOffset() + delta,
+ mojom::blink::ScrollType::kProgrammatic);
+ } else {
+ IntSize layout_delta = IntSize(
+ delta.Width() < 0 ? floor(delta.Width()) : ceil(delta.Width()),
+ delta.Height() < 0 ? floor(delta.Height()) : ceil(delta.Height()));
+
+ LayoutViewport().SetScrollOffset(
+ ScrollOffset(LayoutViewport().ScrollOffsetInt() + layout_delta),
+ mojom::blink::ScrollType::kProgrammatic);
+ }
delta = target_offset - GetScrollOffset();
GetVisualViewport().SetScrollOffset(
diff --git a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
index bac6d698c07..15f774f2c15 100644
--- a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
@@ -25,7 +25,8 @@ class ScrollableAreaStub : public GarbageCollected<ScrollableAreaStub>,
public ScrollableArea {
public:
ScrollableAreaStub(const IntSize& viewport_size, const IntSize& contents_size)
- : user_input_scrollable_x_(true),
+ : ScrollableArea(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+ user_input_scrollable_x_(true),
user_input_scrollable_y_(true),
viewport_size_(viewport_size),
contents_size_(contents_size),
diff --git a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc b/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc
deleted file mode 100644
index 8479d77988e..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
-
-#include "services/network/public/cpp/web_sandbox_flags.h"
-#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
-#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
-#include "third_party/blink/renderer/core/feature_policy/feature_policy_parser.h"
-
-namespace blink {
-
-const SandboxFlagFeaturePolicyPairs& SandboxFlagsWithFeaturePolicies() {
- DEFINE_STATIC_LOCAL(
- SandboxFlagFeaturePolicyPairs, array,
- ({
- {network::mojom::blink::WebSandboxFlags::kTopNavigation,
- mojom::blink::FeaturePolicyFeature::kTopNavigation},
- {network::mojom::blink::WebSandboxFlags::kForms,
- mojom::blink::FeaturePolicyFeature::kFormSubmission},
- {network::mojom::blink::WebSandboxFlags::kScripts,
- mojom::blink::FeaturePolicyFeature::kScript},
- {network::mojom::blink::WebSandboxFlags::kPopups,
- mojom::blink::FeaturePolicyFeature::kPopups},
- {network::mojom::blink::WebSandboxFlags::kPointerLock,
- mojom::blink::FeaturePolicyFeature::kPointerLock},
- {network::mojom::blink::WebSandboxFlags::kModals,
- mojom::blink::FeaturePolicyFeature::kModals},
- {network::mojom::blink::WebSandboxFlags::kOrientationLock,
- mojom::blink::FeaturePolicyFeature::kOrientationLock},
- {network::mojom::blink::WebSandboxFlags::kPresentationController,
- mojom::blink::FeaturePolicyFeature::kPresentation},
- {network::mojom::blink::WebSandboxFlags::kDownloads,
- mojom::blink::FeaturePolicyFeature::kDownloads},
- }));
- return array;
-}
-
-// This returns a super mask which indicates the set of all flags that have
-// corresponding feature policies. With FeaturePolicyForSandbox, these flags
-// are always removed from the set of sandbox flags set for a sandboxed
-// <iframe> (those sandbox flags are now contained in the |ContainerPolicy|).
-network::mojom::blink::WebSandboxFlags
-SandboxFlagsImplementedByFeaturePolicy() {
- DEFINE_STATIC_LOCAL(network::mojom::blink::WebSandboxFlags, mask,
- (network::mojom::blink::WebSandboxFlags::kNone));
- if (mask == network::mojom::blink::WebSandboxFlags::kNone) {
- for (const auto& pair : SandboxFlagsWithFeaturePolicies())
- mask |= pair.first;
- }
- return mask;
-}
-
-// Removes a certain set of flags from |sandbox_flags| for which we have feature
-// policies implemented.
-network::mojom::blink::WebSandboxFlags
-GetSandboxFlagsNotImplementedAsFeaturePolicy(
- network::mojom::blink::WebSandboxFlags sandbox_flags) {
- // Punch all the sandbox flags which are converted to feature policy.
- return sandbox_flags & ~SandboxFlagsImplementedByFeaturePolicy();
-}
-
-void ApplySandboxFlagsToParsedFeaturePolicy(
- network::mojom::blink::WebSandboxFlags sandbox_flags,
- ParsedFeaturePolicy& parsed_feature_policy) {
- for (const auto& pair : SandboxFlagsWithFeaturePolicies()) {
- if ((sandbox_flags & pair.first) !=
- network::mojom::blink::WebSandboxFlags::kNone)
- DisallowFeatureIfNotPresent(pair.second, parsed_feature_policy);
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.h b/chromium/third_party/blink/renderer/core/frame/sandbox_flags.h
deleted file mode 100644
index 8bbf7a95cbc..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/sandbox_flags.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_SANDBOX_FLAGS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_SANDBOX_FLAGS_H_
-
-#include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
-#include "third_party/blink/public/common/feature_policy/feature_policy.h"
-#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink-forward.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-
-namespace blink {
-using SandboxFlagFeaturePolicyPairs =
- Vector<std::pair<network::mojom::blink::WebSandboxFlags,
- mojom::blink::FeaturePolicyFeature>>;
-
-// Returns a vector of pairs of sandbox flags and the corresponding feature
-// policies. This includes most but not all sandbox flags as some flags have not
-// yet migrated to using feature policies.
-const SandboxFlagFeaturePolicyPairs& SandboxFlagsWithFeaturePolicies();
-
-// With FeaturePolicyForSandbox most sandbox flags will be represented with
-// features. This method returns the part of sandbox flags which were not mapped
-// to corresponding features.
-network::mojom::blink::WebSandboxFlags
- GetSandboxFlagsNotImplementedAsFeaturePolicy(
- network::mojom::blink::WebSandboxFlags);
-
-// Applies the sandbox flags as parsed feature policies; If a flag is present
-// both in the provided flags and in the parsed feature as a feature policy,
-// the parsed policy takes precedence.
-void ApplySandboxFlagsToParsedFeaturePolicy(
- network::mojom::blink::WebSandboxFlags,
- ParsedFeaturePolicy&);
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/frame/savable_resources.cc b/chromium/third_party/blink/renderer/core/frame/savable_resources.cc
index b4a4f6a9f18..f2b5197e7b0 100644
--- a/chromium/third_party/blink/renderer/core/frame/savable_resources.cc
+++ b/chromium/third_party/blink/renderer/core/frame/savable_resources.cc
@@ -22,8 +22,9 @@ namespace {
// a html document.
bool DoesFrameContainHtmlDocument(Frame* frame, Element* element) {
if (frame->IsLocalFrame()) {
- Document* document =
- LocalFrame::FromFrameToken(frame->GetFrameToken())->GetDocument();
+ Document* document = LocalFrame::FromFrameToken(
+ frame->GetFrameToken().GetAs<LocalFrameToken>())
+ ->GetDocument();
return document->IsHTMLDocument() || document->IsXHTMLDocument();
}
diff --git a/chromium/third_party/blink/renderer/core/frame/screen.cc b/chromium/third_party/blink/renderer/core/frame/screen.cc
index 50c1228be85..8feb2ae40fb 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen.cc
+++ b/chromium/third_party/blink/renderer/core/frame/screen.cc
@@ -31,6 +31,7 @@
#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/widget/screen_info.h"
+#include "third_party/blink/renderer/core/event_target_names.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/local_frame_view.h"
@@ -42,7 +43,7 @@ namespace blink {
namespace {
-ScreenInfo GetScreenInfo(LocalFrame& frame) {
+const ScreenInfo& GetScreenInfo(LocalFrame& frame) {
return frame.GetChromeClient().GetScreenInfo(frame);
}
@@ -56,12 +57,12 @@ int Screen::height() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(
lroundf(screen_info.rect.height() * screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).rect.height();
+ return screen_info.rect.height();
}
int Screen::width() const {
@@ -70,12 +71,12 @@ int Screen::width() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(
lroundf(screen_info.rect.width() * screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).rect.width();
+ return screen_info.rect.width();
}
unsigned Screen::colorDepth() const {
@@ -96,12 +97,12 @@ int Screen::availLeft() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(lroundf(screen_info.available_rect.x() *
screen_info.device_scale_factor));
}
- return static_cast<int>(GetScreenInfo(*frame).available_rect.x());
+ return static_cast<int>(screen_info.available_rect.x());
}
int Screen::availTop() const {
@@ -110,12 +111,12 @@ int Screen::availTop() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(lroundf(screen_info.available_rect.y() *
screen_info.device_scale_factor));
}
- return static_cast<int>(GetScreenInfo(*frame).available_rect.y());
+ return static_cast<int>(screen_info.available_rect.y());
}
int Screen::availHeight() const {
@@ -124,12 +125,12 @@ int Screen::availHeight() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(lroundf(screen_info.available_rect.height() *
screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).available_rect.height();
+ return screen_info.available_rect.height();
}
int Screen::availWidth() const {
@@ -138,20 +139,35 @@ int Screen::availWidth() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(lroundf(screen_info.available_rect.width() *
screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).available_rect.width();
+ return screen_info.available_rect.width();
}
void Screen::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
+ EventTargetWithInlineData::Trace(visitor);
ExecutionContextClient::Trace(visitor);
Supplementable<Screen>::Trace(visitor);
}
+const WTF::AtomicString& Screen::InterfaceName() const {
+ return event_target_names::kScreen;
+}
+
+ExecutionContext* Screen::GetExecutionContext() const {
+ return ExecutionContextClient::GetExecutionContext();
+}
+
+bool Screen::isExtended() const {
+ if (!DomWindow())
+ return false;
+ LocalFrame* frame = DomWindow()->GetFrame();
+ return GetScreenInfo(*frame).is_extended;
+}
+
Screen::Screen(display::mojom::blink::DisplayPtr display,
bool internal,
bool primary,
@@ -168,12 +184,12 @@ int Screen::left() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(
lroundf(screen_info.rect.x() * screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).rect.x();
+ return screen_info.rect.x();
}
int Screen::top() const {
@@ -182,19 +198,19 @@ int Screen::top() const {
if (!DomWindow())
return 0;
LocalFrame* frame = DomWindow()->GetFrame();
+ const ScreenInfo& screen_info = GetScreenInfo(*frame);
if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
- ScreenInfo screen_info = GetScreenInfo(*frame);
return static_cast<int>(
lroundf(screen_info.rect.y() * screen_info.device_scale_factor));
}
- return GetScreenInfo(*frame).rect.y();
+ return screen_info.rect.y();
}
bool Screen::internal() const {
if (display_)
return internal_.has_value() && internal_.value();
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for
- // proposed multi-screen info: https://github.com/webscreens/window-placement
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface
+ // that inherits from Screen: https://github.com/webscreens/window-placement
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
@@ -202,8 +218,8 @@ bool Screen::internal() const {
bool Screen::primary() const {
if (display_)
return primary_.has_value() && primary_.value();
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for
- // proposed multi-screen info: https://github.com/webscreens/window-placement
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface
+ // that inherits from Screen: https://github.com/webscreens/window-placement
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
@@ -219,8 +235,8 @@ float Screen::scaleFactor() const {
const String Screen::id() const {
if (display_)
return id_;
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for
- // proposed multi-screen info: https://github.com/webscreens/window-placement
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface
+ // that inherits from Screen: https://github.com/webscreens/window-placement
NOTIMPLEMENTED_LOG_ONCE();
return String();
}
@@ -230,8 +246,8 @@ bool Screen::touchSupport() const {
return display_->touch_support ==
display::mojom::blink::TouchSupport::AVAILABLE;
}
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for
- // proposed multi-screen info: https://github.com/webscreens/window-placement
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface
+ // that inherits from Screen: https://github.com/webscreens/window-placement
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/screen.h b/chromium/third_party/blink/renderer/core/frame/screen.h
index cb56fb2fb61..f8602ca5ab6 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen.h
+++ b/chromium/third_party/blink/renderer/core/frame/screen.h
@@ -31,6 +31,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.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/core/frame/web_feature_forward.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -43,7 +44,7 @@ namespace blink {
class LocalDOMWindow;
-class CORE_EXPORT Screen final : public ScriptWrappable,
+class CORE_EXPORT Screen final : public EventTargetWithInlineData,
public ExecutionContextClient,
public Supplementable<Screen> {
DEFINE_WRAPPERTYPEINFO();
@@ -62,8 +63,18 @@ class CORE_EXPORT Screen final : public ScriptWrappable,
void Trace(Visitor*) const override;
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for
- // proposed multi-screen info: https://github.com/webscreens/window-placement
+ // EventTargetWithInlineData:
+ const WTF::AtomicString& InterfaceName() const override;
+ ExecutionContext* GetExecutionContext() const override;
+
+ // Proposed: https://github.com/webscreens/window-placement
+ // Whether this Screen is part of a multi-screen extended visual workspace.
+ bool isExtended() const;
+ // An event fired when Screen attributes change.
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(change, kChange)
+
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface
+ // that inherits from Screen: https://github.com/webscreens/window-placement
Screen(display::mojom::blink::DisplayPtr display,
bool internal,
bool primary,
diff --git a/chromium/third_party/blink/renderer/core/frame/screen.idl b/chromium/third_party/blink/renderer/core/frame/screen.idl
index 46fd933695d..e0ab73348cf 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen.idl
+++ b/chromium/third_party/blink/renderer/core/frame/screen.idl
@@ -45,7 +45,13 @@
// Proposed
// https://github.com/webscreens/window-placement
- // TODO(crbug.com/1116528): Use a dictionary, not the Screen interface, for proposed multi-screen info.
+ [SecureContext, HighEntropy, MeasureAs=WindowScreenChange, RuntimeEnabled=WindowPlacement] attribute EventHandler onchange;
+ [SecureContext, HighEntropy=Direct, MeasureAs=WindowScreenIsExtended, RuntimeEnabled=WindowPlacement] readonly attribute boolean isExtended;
+ // TODO(crbug.com/1171486): Inherit from EventTarget or remove these:
+ [RuntimeEnabled=WindowPlacement] void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options);
+ [RuntimeEnabled=WindowPlacement] void removeEventListener(DOMString type, EventListener? listener, optional (EventListenerOptions or boolean) options);
+ [ImplementedAs=dispatchEventForBindings, RaisesException, RuntimeCallStatsCounter=EventTargetDispatchEvent, RuntimeEnabled=WindowPlacement] boolean dispatchEvent(Event event);
+ // TODO(crbug.com/1116528): Move permission-gated attributes to an interface that inherits from Screen.
[HighEntropy=Direct, MeasureAs=WindowScreenLeft, RuntimeEnabled=WindowPlacement] readonly attribute long left;
[HighEntropy=Direct, MeasureAs=WindowScreenTop, RuntimeEnabled=WindowPlacement] readonly attribute long top;
[HighEntropy=Direct, MeasureAs=WindowScreenInternal, RuntimeEnabled=WindowPlacement] readonly attribute boolean internal;
diff --git a/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.cc b/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.cc
index f52133f50c5..1b670e72f99 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.cc
+++ b/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.cc
@@ -6,18 +6,18 @@
#include "base/numerics/safe_conversions.h"
#include "third_party/blink/public/common/widget/visual_properties.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
namespace blink {
ScreenMetricsEmulator::ScreenMetricsEmulator(
- WebViewFrameWidget* delegate,
+ WebFrameWidgetImpl* frame_widget,
const ScreenInfo& screen_info,
const gfx::Size& widget_size,
const gfx::Size& visible_viewport_size,
const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect)
- : delegate_(delegate),
+ : frame_widget_(frame_widget),
original_screen_info_(screen_info),
original_widget_size_(widget_size),
original_visible_viewport_size_(visible_viewport_size),
@@ -25,16 +25,17 @@ ScreenMetricsEmulator::ScreenMetricsEmulator(
original_window_screen_rect_(window_screen_rect) {}
void ScreenMetricsEmulator::Trace(Visitor* vistor) const {
- vistor->Trace(delegate_);
+ vistor->Trace(frame_widget_);
}
void ScreenMetricsEmulator::DisableAndApply() {
- delegate_->SetScreenMetricsEmulationParameters(false, emulation_params_);
- delegate_->SetScreenRects(original_view_screen_rect_,
- original_window_screen_rect_);
- delegate_->SetWindowSegments(original_root_window_segments_);
- delegate_->SetScreenInfoAndSize(original_screen_info_, original_widget_size_,
- original_visible_viewport_size_);
+ frame_widget_->SetScreenMetricsEmulationParameters(false, emulation_params_);
+ frame_widget_->SetScreenRects(original_view_screen_rect_,
+ original_window_screen_rect_);
+ frame_widget_->SetWindowSegments(original_root_window_segments_);
+ frame_widget_->SetScreenInfoAndSize(original_screen_info_,
+ original_widget_size_,
+ original_visible_viewport_size_);
}
void ScreenMetricsEmulator::ChangeEmulationParams(
@@ -126,22 +127,22 @@ void ScreenMetricsEmulator::Apply() {
DeviceEmulationParams modified_emulation_params = emulation_params_;
modified_emulation_params.device_scale_factor =
original_screen_info().device_scale_factor;
- delegate_->SetScreenMetricsEmulationParameters(
+ frame_widget_->SetScreenMetricsEmulationParameters(
true, std::move(modified_emulation_params));
- delegate_->SetScreenRects(gfx::Rect(widget_pos, widget_size),
- gfx::Rect(window_pos, window_size));
+ frame_widget_->SetScreenRects(gfx::Rect(widget_pos, widget_size),
+ gfx::Rect(window_pos, window_size));
// If there are no emulated window segments, use the emulated widget size
// instead. When we switch from emulated segments to not having any, we should
// have a single segment that matches the widget size.
bool has_emulated_segments = emulation_params_.window_segments.size();
if (has_emulated_segments) {
- delegate_->SetWindowSegments(emulation_params_.window_segments);
+ frame_widget_->SetWindowSegments(emulation_params_.window_segments);
} else {
std::vector<gfx::Rect> emulated_segments{
{0, 0, widget_size.width(), widget_size.height()}};
- delegate_->SetWindowSegments(emulated_segments);
+ frame_widget_->SetWindowSegments(emulated_segments);
}
ScreenInfo screen_info = original_screen_info();
@@ -150,15 +151,15 @@ void ScreenMetricsEmulator::Apply() {
screen_info.available_rect = screen_rect;
screen_info.orientation_type = orientation_type;
screen_info.orientation_angle = orientation_angle;
- delegate_->SetScreenInfoAndSize(screen_info, /*widget_size=*/widget_size,
- /*visible_viewport_size=*/widget_size);
+ frame_widget_->SetScreenInfoAndSize(screen_info, /*widget_size=*/widget_size,
+ /*visible_viewport_size=*/widget_size);
}
void ScreenMetricsEmulator::UpdateVisualProperties(
const VisualProperties& visual_properties) {
// Device emulation isn't supported for widgets that have auto resize mode
// enabled.
- DCHECK(!delegate_->AutoResizeMode());
+ DCHECK(!frame_widget_->AutoResizeMode());
original_screen_info_ = visual_properties.screen_info;
original_widget_size_ = visual_properties.new_size;
@@ -170,7 +171,7 @@ void ScreenMetricsEmulator::UpdateVisualProperties(
// Appy the compositor viewport rect and surface id allocation. The screen
// info is kept the same as the current ScreenInfo state. The screen info
// already was updated in |Apply| via |SetScreenInfoAndSize|.
- delegate_->UpdateSurfaceAndCompositorRect(
+ frame_widget_->UpdateSurfaceAndCompositorRect(
visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
visual_properties.compositor_viewport_pixel_rect);
}
diff --git a/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.h b/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.h
index 9e4d3ca1ec9..5c6594868ed 100644
--- a/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.h
+++ b/chromium/third_party/blink/renderer/core/frame/screen_metrics_emulator.h
@@ -10,22 +10,24 @@
#include "third_party/blink/public/common/widget/device_emulation_params.h"
#include "third_party/blink/public/common/widget/screen_info.h"
#include "third_party/blink/public/mojom/widget/device_emulation_params.mojom-blink.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace blink {
struct VisualProperties;
-class WebViewFrameWidget;
+class WebFrameWidgetImpl;
// ScreenMetricsEmulator class manages screen emulation inside a
-// WebViewFrameWidget. This includes resizing, placing view on the screen at
+// WebFrameWidgetImpl. This includes resizing, placing view on the screen at
// desired position, changing device scale factor, and scaling down the whole
// widget if required to fit into the browser window.
class ScreenMetricsEmulator : public GarbageCollected<ScreenMetricsEmulator> {
public:
- ScreenMetricsEmulator(WebViewFrameWidget* delegate,
+ ScreenMetricsEmulator(WebFrameWidgetImpl* frame_widget,
const ScreenInfo& screen_info,
const gfx::Size& widget_size,
const gfx::Size& visible_viewport_size,
@@ -55,10 +57,10 @@ class ScreenMetricsEmulator : public GarbageCollected<ScreenMetricsEmulator> {
gfx::Point ViewRectOrigin();
// Disables emulation and applies non-emulated values to the
- // WebViewFrameWidget. Call this before destroying the ScreenMetricsEmulator.
+ // WebFrameWidgetImpl. Call this before destroying the ScreenMetricsEmulator.
void DisableAndApply();
- // Sets new parameters and applies them to the WebViewFrameWidget.
+ // Sets new parameters and applies them to the WebFrameWidgetImpl.
void ChangeEmulationParams(const DeviceEmulationParams& params);
void UpdateVisualProperties(const VisualProperties& visual_properties);
@@ -77,9 +79,9 @@ class ScreenMetricsEmulator : public GarbageCollected<ScreenMetricsEmulator> {
// Applies emulated values to the WidgetBase.
void Apply();
- Member<WebViewFrameWidget> const delegate_;
+ Member<WebFrameWidgetImpl> const frame_widget_;
- // Parameters as passed by WebViewFrameWidget::EnableDeviceEmulation.
+ // Parameters as passed by `WebFrameWidgetImpl::EnableDeviceEmulation()`
DeviceEmulationParams emulation_params_;
// Original values to restore back after emulation ends.
diff --git a/chromium/third_party/blink/renderer/core/frame/settings.cc b/chromium/third_party/blink/renderer/core/frame/settings.cc
index 20ed48e8eb8..129589f1a67 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings.cc
+++ b/chromium/third_party/blink/renderer/core/frame/settings.cc
@@ -36,6 +36,46 @@
namespace blink {
+namespace {
+
+// For generated Settings::SetFromStrings().
+template <typename T>
+struct FromString {
+ T operator()(const String& s) { return static_cast<T>(s.ToInt()); }
+};
+
+template <>
+struct FromString<String> {
+ const String& operator()(const String& s) { return s; }
+};
+
+template <>
+struct FromString<bool> {
+ bool operator()(const String& s) { return s.IsEmpty() || s == "true"; }
+};
+
+template <>
+struct FromString<float> {
+ float operator()(const String& s) { return s.ToFloat(); }
+};
+
+template <>
+struct FromString<double> {
+ double operator()(const String& s) { return s.ToDouble(); }
+};
+
+template <>
+struct FromString<IntSize> {
+ IntSize operator()(const String& s) {
+ Vector<String> fields;
+ s.Split(',', fields);
+ return IntSize(fields.size() > 0 ? fields[0].ToInt() : 0,
+ fields.size() > 1 ? fields[1].ToInt() : 0);
+ }
+};
+
+} // namespace
+
// NOTEs
// 1) EditingMacBehavior comprises builds on Mac;
// 2) EditingWindowsBehavior comprises builds on Windows;
@@ -51,7 +91,7 @@ static mojom::blink::EditingBehavior EditingBehaviorTypeForPlatform() {
mojom::blink::EditingBehavior::kEditingWindowsBehavior
#elif defined(OS_ANDROID)
mojom::blink::EditingBehavior::kEditingAndroidBehavior
-#elif BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
base::FeatureList::IsEnabled(features::kCrOSAutoSelect)
? mojom::blink::EditingBehavior::kEditingChromeOSBehavior
: mojom::blink::EditingBehavior::kEditingUnixBehavior
@@ -67,8 +107,7 @@ static const bool kDefaultSelectTrailingWhitespaceEnabled = true;
static const bool kDefaultSelectTrailingWhitespaceEnabled = false;
#endif
-Settings::Settings()
- : text_autosizing_enabled_(false) SETTINGS_INITIALIZER_LIST {}
+Settings::Settings() : delegate_(nullptr) SETTINGS_INITIALIZER_LIST {}
SETTINGS_SETTER_BODIES
@@ -81,23 +120,4 @@ void Settings::Invalidate(SettingsDelegate::ChangeType change_type) {
delegate_->SettingsChanged(change_type);
}
-void Settings::SetTextAutosizingEnabled(bool text_autosizing_enabled) {
- if (text_autosizing_enabled_ == text_autosizing_enabled)
- return;
-
- text_autosizing_enabled_ = text_autosizing_enabled;
- Invalidate(SettingsDelegate::kTextAutosizingChange);
-}
-
-// TODO: Move to Settings.json5 once make_settings can understand IntSize.
-void Settings::SetTextAutosizingWindowSizeOverride(
- const IntSize& text_autosizing_window_size_override) {
- if (text_autosizing_window_size_override_ ==
- text_autosizing_window_size_override)
- return;
-
- text_autosizing_window_size_override_ = text_autosizing_window_size_override;
- Invalidate(SettingsDelegate::kTextAutosizingChange);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/settings.h b/chromium/third_party/blink/renderer/core/frame/settings.h
index af8e5f495d8..5b6ab457bdb 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings.h
+++ b/chromium/third_party/blink/renderer/core/frame/settings.h
@@ -63,20 +63,7 @@ class CORE_EXPORT Settings {
return generic_font_family_settings_;
}
void NotifyGenericFontFamilyChange() {
- Invalidate(SettingsDelegate::kFontFamilyChange);
- }
-
- void SetTextAutosizingEnabled(bool);
- bool TextAutosizingEnabled() const { return text_autosizing_enabled_; }
-
- void SetBypassCSP(bool enabled) { bypass_csp_ = enabled; }
- bool BypassCSP() const { return bypass_csp_; }
-
- // Only set by web tests, and only used if TextAutosizingEnabled() returns
- // true.
- void SetTextAutosizingWindowSizeOverride(const IntSize&);
- const IntSize& TextAutosizingWindowSizeOverride() const {
- return text_autosizing_window_size_override_;
+ Invalidate(SettingsDelegate::ChangeType::kFontFamily);
}
SETTINGS_GETTERS_AND_SETTERS
@@ -89,9 +76,6 @@ class CORE_EXPORT Settings {
SettingsDelegate* delegate_;
GenericFontFamilySettings generic_font_family_settings_;
- IntSize text_autosizing_window_size_override_;
- bool text_autosizing_enabled_ : 1;
- bool bypass_csp_ = false;
SETTINGS_MEMBER_VARIABLES
diff --git a/chromium/third_party/blink/renderer/core/frame/settings.json5 b/chromium/third_party/blink/renderer/core/frame/settings.json5
index 64c4df2d44f..4c5ad792de9 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings.json5
+++ b/chromium/third_party/blink/renderer/core/frame/settings.json5
@@ -28,10 +28,15 @@
// Valid parameters for data entries below.
parameters: {
type: {
- default: "bool"
+ default: "bool",
+ valid_type: "str", // The string value should be a C++ type name
},
initial: {},
- invalidate: {},
+ invalidate: {
+ default: [],
+ valid_type: "list",
+ // See SettingsDelegate::ChangeType for valid values (without "k"),
+ },
},
data: [
@@ -70,7 +75,7 @@
{
name: "minimumFontSize",
initial: 0,
- invalidate: "Style",
+ invalidate: ["Style"],
type: "int",
},
@@ -79,19 +84,19 @@
{
name: "minimumLogicalFontSize",
initial: 0,
- invalidate: "Style",
+ invalidate: ["Style"],
type: "int",
},
{
name: "defaultFontSize",
initial: 0,
- invalidate: "Style",
+ invalidate: ["Style"],
type: "int",
},
{
name: "defaultFixedFontSize",
initial: 0,
- invalidate: "Style",
+ invalidate: ["Style"],
type: "int",
},
@@ -108,7 +113,7 @@
{
name: "allowUniversalAccessFromFileURLs",
initial: true,
- invalidate: "UniversalAccess",
+ invalidate: ["UniversalAccess"],
},
{
name: "allowFileAccessFromFileURLs",
@@ -133,17 +138,17 @@
{
name: "HighlightAds",
initial: false,
- invalidate: "HighlightAds"
+ invalidate: ["HighlightAds"],
},
{
name: "textAreasAreResizable",
initial: false,
- invalidate: "Style",
+ invalidate: ["Style"],
},
{
name: "acceleratedCompositingEnabled",
initial: false,
- invalidate: "AcceleratedCompositing",
+ invalidate: ["AcceleratedCompositing"],
},
{
@@ -166,7 +171,7 @@
{
name: "preferCompositingToLCDTextEnabled",
initial: false,
- invalidate: "AcceleratedCompositing",
+ invalidate: ["AcceleratedCompositing"],
},
{
@@ -231,7 +236,7 @@
{
name: "immersiveModeEnabled",
initial: false,
- invalidate: "MediaControls",
+ invalidate: ["MediaControls"],
},
// Only affects main thread scrolling
@@ -246,7 +251,7 @@
{
name: "threadedScrollingEnabled",
initial: true,
- invalidate: "Style",
+ invalidate: ["Style", "ViewportPaintProperties"],
},
// Used in web tests for gesture tap highlights. Makes the highlights square
@@ -289,6 +294,10 @@
initial: true,
},
{
+ name: "allowNonEmptyNavigatorPlugins",
+ initial: false,
+ },
+ {
name: "cookieEnabled",
initial: true,
},
@@ -315,7 +324,7 @@
{
name: "spatialNavigationEnabled",
initial: false,
- invalidate: "SpatialNavigation",
+ invalidate: ["SpatialNavigation"],
},
// This setting adds a means to enable/disable touch initiated drag & drop. If
@@ -411,13 +420,13 @@
{
name: "forceZeroLayoutHeight",
initial: false,
- invalidate: "ViewportDescription",
+ invalidate: ["ViewportDescription"],
},
{
name: "mainFrameClipsContent",
initial: true,
- invalidate: "ViewportPaintProperties",
+ invalidate: ["ViewportPaintProperties"],
},
// For android.webkit.WebSettings.setUseWideViewport()
@@ -425,7 +434,7 @@
{
name: "useWideViewport",
initial: true,
- invalidate: "ViewportDescription",
+ invalidate: ["ViewportDescription"],
},
// For android.webkit.WebSettings.setLoadWithOverviewMode()
@@ -433,7 +442,7 @@
{
name: "loadWithOverviewMode",
initial: true,
- invalidate: "ViewportDescription",
+ invalidate: ["ViewportDescription"],
},
// Used by android_webview to support legacy apps that inject script into a top-level initial empty
@@ -467,14 +476,14 @@
{
name: "caretBrowsingEnabled",
initial: false,
- invalidate: "Style",
+ invalidate: ["Style"],
},
// Font scale factor for accessibility, applied as part of text autosizing.
{
name: "accessibilityFontScaleFactor",
initial: "1.0",
- invalidate: "TextAutosizing",
+ invalidate: ["TextAutosizing"],
type: "double",
},
@@ -482,13 +491,13 @@
{
name: "mediaTypeOverride",
initial: "\"\"",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "String",
},
{
name: "displayModeOverride",
initial: "blink::mojom::DisplayMode::kUndefined",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "blink::mojom::DisplayMode",
},
@@ -497,12 +506,12 @@
{
name: "loadsImagesAutomatically",
initial: false,
- invalidate: "ImageLoading",
+ invalidate: ["ImageLoading"],
},
{
name: "imagesEnabled",
initial: true,
- invalidate: "ImageLoading",
+ invalidate: ["ImageLoading"],
},
{
name: "imageAnimationPolicy",
@@ -521,18 +530,18 @@
{
name: "pluginsEnabled",
initial: false,
- invalidate: "Plugins",
+ invalidate: ["Plugins"],
},
{
name: "viewportEnabled",
initial: false,
- invalidate: "ViewportDescription",
+ invalidate: ["ViewportDescription"],
},
{
name: "viewportMetaEnabled",
initial: false,
- invalidate: "ViewportDescription",
+ invalidate: ["ViewportDescription"],
},
// When true, Blink will use the content width and viewport size to set the
@@ -546,7 +555,7 @@
{
name: "dnsPrefetchingEnabled",
initial: false,
- invalidate: "DNSPrefetching",
+ invalidate: ["DNSPrefetching"],
},
// Clients that execute script should call ExecutionContext::canExecuteScripts()
@@ -567,7 +576,7 @@
{
name: "forceAndroidOverlayScrollbar",
initial: false,
- invalidate: "ScrollbarLayout",
+ invalidate: ["ScrollbarLayout"],
},
// Set the timeout seconds of the network-quiet timers in IdlenessDetector.
@@ -584,7 +593,7 @@
{
name: "forceMainWorldInitialization",
initial: false,
- invalidate: "DOMWorlds",
+ invalidate: ["DOMWorlds"],
},
// Forces TouchEventFeatureDetection conditional feature for all main
@@ -601,7 +610,7 @@
{
name: "deviceScaleAdjustment",
initial: "1.0",
- invalidate: "TextAutosizing",
+ invalidate: ["TextAutosizing"],
type: "double",
},
@@ -627,28 +636,28 @@
{
name: "availablePointerTypes",
initial: "ui::POINTER_TYPE_NONE",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "int",
},
{
name: "availableHoverTypes",
initial: "ui::HOVER_TYPE_NONE",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "int",
},
// These values specify properties of the user's primary pointing device only.
{
name: "primaryPointerType",
- initial: "ui::POINTER_TYPE_NONE",
- invalidate: "MediaQuery",
- type: "ui::PointerType",
+ initial: "mojom::blink::PointerType::kPointerNone",
+ invalidate: ["MediaQuery"],
+ type: "blink::mojom::PointerType",
},
{
name: "primaryHoverType",
- initial: "ui::HOVER_TYPE_NONE",
- invalidate: "MediaQuery",
- type: "ui::HoverType",
+ initial: "mojom::blink::HoverType::kHoverNone",
+ invalidate: ["MediaQuery"],
+ type: "mojom::blink::HoverType",
},
// If true, the value in password fields is exposed to assistive technologies.
@@ -721,7 +730,7 @@
{
name: "viewportStyle",
initial: "mojom::blink::ViewportStyle::kDefault",
- invalidate: "ViewportRule",
+ invalidate: ["ViewportRule"],
type: "mojom::blink::ViewportStyle",
},
@@ -730,7 +739,7 @@
{
name: "textTrackKindUserPreference",
initial: "TextTrackKindUserPreference::kDefault",
- invalidate: "TextTrackKindUserPreference",
+ invalidate: ["TextTrackKindUserPreference"],
type: "TextTrackKindUserPreference",
},
@@ -840,7 +849,7 @@
{
name: "hideScrollbars",
initial: false,
- invalidate: "ViewportPaintProperties",
+ invalidate: ["ViewportPaintProperties"],
},
// Spellchecking is enabled by default for elements that do not specify it explicitly
@@ -867,7 +876,7 @@
{
name: "mediaControlsEnabled",
initial: true,
- invalidate: "MediaControls",
+ invalidate: ["MediaControls"],
},
// Whether we should not update selection attributes when mutating selection range.
@@ -890,7 +899,7 @@
{
name: "forceDarkModeEnabled",
initial: false,
- invalidate: "ForceDark",
+ invalidate: ["ColorScheme", "Paint"],
},
{
@@ -1012,7 +1021,7 @@
{
name: "preferredColorScheme",
initial: "mojom::blink::PreferredColorScheme::kLight",
- invalidate: "ColorScheme",
+ invalidate: ["ColorScheme"],
type: "mojom::blink::PreferredColorScheme",
},
@@ -1021,7 +1030,7 @@
{
name: "preferredContrast",
initial: "mojom::blink::PreferredContrast::kNoPreference",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "mojom::blink::PreferredContrast",
},
@@ -1030,7 +1039,7 @@
{
name: "prefersReducedMotion",
initial: false,
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
},
{
name: "DontSendKeyEventsToJavascript",
@@ -1041,14 +1050,13 @@
{
name: "navigationControls",
initial: "NavigationControls::kNone",
- invalidate: "MediaQuery",
+ invalidate: ["MediaQuery"],
type: "NavigationControls",
},
{
name: "accessibilityAlwaysShowFocus",
initial: false,
- invalidate: "Style",
- type: "bool"
+ invalidate: ["Style"],
},
// aria-modal="true" on some platforms requires the accessibility tree to
// be pruned so no other background content is exposed to assistive
@@ -1057,7 +1065,6 @@
{
name: "ariaModalPrunesAXTree",
initial: false,
- type: "bool",
},
// The AXMenuList class provides a fake implementation of the
// select element pop-up menu, which is required on platforms like
@@ -1071,11 +1078,29 @@
{
name: "selectionClipboardBufferAvailable",
initial: false,
- type: "bool",
},
{
name: "accessibilityIncludeSvgGElement",
initial: false,
+ },
+ {
+ name: "bypassCSP",
+ initial: false,
+ },
+ {
+ name: "textAutosizingEnabled",
+ initial: false,
+ invalidate: ["TextAutosizing"],
+ },
+ // Only set by web tests, and only used if textAutosizingEnabled is true.
+ {
+ name: "textAutosizingWindowSizeOverride",
+ invalidate: ["TextAutosizing"],
+ type: "IntSize",
+ },
+ {
+ name: "WebXRImmersiveArAllowed",
+ initial: true,
type: "bool",
},
],
diff --git a/chromium/third_party/blink/renderer/core/frame/settings_delegate.h b/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
index 5f006670432..e6316017cc5 100644
--- a/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
+++ b/chromium/third_party/blink/renderer/core/frame/settings_delegate.h
@@ -50,30 +50,29 @@ class CORE_EXPORT SettingsDelegate {
// We currently use an enum instead of individual invalidation
// functions to make generating Settings.in slightly easier.
- enum ChangeType {
- kStyleChange,
- kViewportDescriptionChange,
- kViewportRuleChange,
- kViewportPaintPropertiesChange,
- kDNSPrefetchingChange,
- kImageLoadingChange,
- kTextAutosizingChange,
- kFontFamilyChange,
- kAcceleratedCompositingChange,
- kMediaQueryChange,
- kAccessibilityStateChange,
- kTextTrackKindUserPreferenceChange,
- kDOMWorldsChange,
- kMediaControlsChange,
- kPluginsChange,
- kHighlightAdsChange,
- kPaintChange,
- kScrollbarLayoutChange,
- kColorSchemeChange,
- kSpatialNavigationChange,
- kUniversalAccessChange,
- kVisionDeficiencyChange,
- kForceDarkChange,
+ enum class ChangeType {
+ kStyle,
+ kViewportDescription,
+ kViewportRule,
+ kViewportPaintProperties,
+ kDNSPrefetching,
+ kImageLoading,
+ kTextAutosizing,
+ kFontFamily,
+ kAcceleratedCompositing,
+ kMediaQuery,
+ kAccessibilityState,
+ kTextTrackKindUserPreference,
+ kDOMWorlds,
+ kMediaControls,
+ kPlugins,
+ kHighlightAds,
+ kPaint,
+ kScrollbarLayout,
+ kColorScheme,
+ kSpatialNavigation,
+ kUniversalAccess,
+ kVisionDeficiency,
};
virtual void SettingsChanged(ChangeType) = 0;
diff --git a/chromium/third_party/blink/renderer/core/frame/sticky_ad_detector.cc b/chromium/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
index 0748d359148..ae803ab8891 100644
--- a/chromium/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
+++ b/chromium/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/core/frame/sticky_ad_detector.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -67,6 +69,8 @@ void StickyAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
base::Time current_time = base::Time::Now();
if (last_detection_time_.has_value() &&
+ base::FeatureList::IsEnabled(
+ features::kFrequencyCappingForLargeStickyAdDetection) &&
current_time < last_detection_time_.value() + kFireInterval) {
return;
}
@@ -130,6 +134,7 @@ void StickyAdDetector::MaybeFireDetection(LocalFrame* main_frame) {
}
void StickyAdDetector::OnLargeStickyAdDetected(LocalFrame* main_frame) {
+ main_frame->Client()->OnLargeStickyAdDetected();
UseCounter::Count(main_frame->GetDocument(), WebFeature::kLargeStickyAd);
done_detection_ = true;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/use_counter_helper.cc b/chromium/third_party/blink/renderer/core/frame/use_counter_helper.cc
index e8efbf81947..633deb6bf79 100644
--- a/chromium/third_party/blink/renderer/core/frame/use_counter_helper.cc
+++ b/chromium/third_party/blink/renderer/core/frame/use_counter_helper.cc
@@ -193,7 +193,7 @@ void UseCounterHelper::ReportAndTraceMeasurementByCSSSampleId(
void UseCounterHelper::Count(CSSPropertyID property,
CSSPropertyType type,
const LocalFrame* source_frame) {
- DCHECK(isCSSPropertyIDWithName(property) ||
+ DCHECK(IsCSSPropertyIDWithName(property) ||
property == CSSPropertyID::kVariable);
if (mute_count_)
diff --git a/chromium/third_party/blink/renderer/core/frame/use_counter_helper_test.cc b/chromium/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
index 7a3f3c5d086..c0df8ff759d 100644
--- a/chromium/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
@@ -179,6 +179,17 @@ TEST_F(UseCounterHelperTest, CSSSelectorPseudoIs) {
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoWhere));
}
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoDir) {
+ auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
+ Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
+ Document& document = dummy_page_holder->GetDocument();
+ WebFeature feature = WebFeature::kCSSSelectorPseudoDir;
+ EXPECT_FALSE(document.IsUseCounted(feature));
+ document.documentElement()->setInnerHTML(
+ "<style>:dir(ltr) { color: red; }</style>");
+ EXPECT_TRUE(document.IsUseCounted(feature));
+}
+
TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
@@ -342,7 +353,8 @@ class DeprecationTest : public testing::Test {
TEST_F(DeprecationTest, InspectorDisablesDeprecation) {
// The specific feature we use here isn't important.
- WebFeature feature = WebFeature::kCSSDeepCombinator;
+ WebFeature feature =
+ WebFeature::kCSSSelectorInternalMediaControlsOverlayCastButton;
CSSPropertyID property = CSSPropertyID::kFontWeight;
EXPECT_FALSE(deprecation_.IsSuppressed(property));
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
index 1e01c53b5e6..11d7207adcf 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -74,7 +74,8 @@
namespace blink {
VisualViewport::VisualViewport(Page& owner)
- : page_(&owner),
+ : ScrollableArea(owner.GetAgentGroupScheduler().CompositorTaskRunner()),
+ page_(&owner),
parent_property_tree_state_(PropertyTreeState::Uninitialized()),
scale_(1),
is_pinch_gesture_active_(false),
@@ -219,8 +220,8 @@ PaintPropertyChangeType VisualViewport::UpdatePaintPropertyNodesIfNeeded(
state.max_scroll_offset_affected_by_page_scale = true;
state.compositor_element_id = GetScrollElementId();
- if (MainFrame() && MainFrame()->GetDocument()) {
- Document* document = MainFrame()->GetDocument();
+ if (LocalMainFrame() && LocalMainFrame()->GetDocument()) {
+ Document* document = LocalMainFrame()->GetDocument();
bool uses_default_root_scroller =
&document->GetRootScrollerController().EffectiveRootScroller() ==
document;
@@ -238,8 +239,8 @@ PaintPropertyChangeType VisualViewport::UpdatePaintPropertyNodesIfNeeded(
state.prevent_viewport_scrolling_from_inner = !uses_default_root_scroller;
}
- if (MainFrame() &&
- !MainFrame()->GetSettings()->GetThreadedScrollingEnabled()) {
+ if (LocalMainFrame() &&
+ !LocalMainFrame()->GetSettings()->GetThreadedScrollingEnabled()) {
state.main_thread_scrolling_reasons =
cc::MainThreadScrollingReason::kThreadedScrollingDisabled;
}
@@ -325,8 +326,10 @@ PaintPropertyChangeType VisualViewport::UpdatePaintPropertyNodesIfNeeded(
parent_property_tree_state_ =
PropertyTreeStateOrAlias(*transform_parent, *clip_parent, *effect_parent);
- if (change == PaintPropertyChangeType::kNodeAddedOrRemoved && MainFrame())
- MainFrame()->View()->SetVisualViewportNeedsRepaint();
+ if (change == PaintPropertyChangeType::kNodeAddedOrRemoved &&
+ LocalMainFrame()) {
+ LocalMainFrame()->View()->SetVisualViewportNeedsRepaint();
+ }
return change;
}
@@ -341,20 +344,20 @@ void VisualViewport::Trace(Visitor* visitor) const {
}
void VisualViewport::UpdateStyleAndLayout(DocumentUpdateReason reason) const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return;
- if (Document* document = MainFrame()->GetDocument())
+ if (Document* document = LocalMainFrame()->GetDocument())
document->UpdateStyleAndLayout(reason);
}
void VisualViewport::EnqueueScrollEvent() {
- if (Document* document = MainFrame()->GetDocument())
+ if (Document* document = LocalMainFrame()->GetDocument())
document->EnqueueVisualViewportScrollEvent();
}
void VisualViewport::EnqueueResizeEvent() {
- if (Document* document = MainFrame()->GetDocument())
+ if (Document* document = LocalMainFrame()->GetDocument())
document->EnqueueVisualViewportResizeEvent();
}
@@ -370,7 +373,7 @@ void VisualViewport::SetSize(const IntSize& size) {
TRACE_EVENT_INSTANT1("loading", "viewport", TRACE_EVENT_SCOPE_THREAD, "data",
ViewportToTracedValue());
- if (!MainFrame())
+ if (!LocalMainFrame())
return;
// Need to re-compute sizes for the overlay scrollbars.
@@ -378,7 +381,7 @@ void VisualViewport::SetSize(const IntSize& size) {
DCHECK(scrollbar_layer_vertical_);
UpdateScrollbarLayer(kHorizontalScrollbar);
UpdateScrollbarLayer(kVerticalScrollbar);
- MainFrame()->View()->SetVisualViewportNeedsRepaint();
+ LocalMainFrame()->View()->SetVisualViewportNeedsRepaint();
}
EnqueueResizeEvent();
@@ -433,21 +436,21 @@ void VisualViewport::SetScale(float scale) {
}
double VisualViewport::OffsetLeft() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return 0;
UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
- return VisibleRect().X() / MainFrame()->PageZoomFactor();
+ return VisibleRect().X() / LocalMainFrame()->PageZoomFactor();
}
double VisualViewport::OffsetTop() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return 0;
UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
- return VisibleRect().Y() / MainFrame()->PageZoomFactor();
+ return VisibleRect().Y() / LocalMainFrame()->PageZoomFactor();
}
double VisualViewport::Width() const {
@@ -469,7 +472,7 @@ void VisualViewport::SetScaleAndLocation(float scale,
const FloatPoint& location) {
if (DidSetScaleOrLocation(scale, is_pinch_gesture_active, location)) {
NotifyRootFrameViewport();
- Document* document = MainFrame()->GetDocument();
+ Document* document = LocalMainFrame()->GetDocument();
if (AXObjectCache* cache = document->ExistingAXObjectCache()) {
cache->HandleScaleAndLocationChanged(document);
}
@@ -477,19 +480,19 @@ void VisualViewport::SetScaleAndLocation(float scale,
}
double VisualViewport::VisibleWidthCSSPx() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return 0;
- float zoom = MainFrame()->PageZoomFactor();
+ float zoom = LocalMainFrame()->PageZoomFactor();
float width_css_px = VisibleRect().Width() / zoom;
return width_css_px;
}
double VisualViewport::VisibleHeightCSSPx() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return 0;
- float zoom = MainFrame()->PageZoomFactor();
+ float zoom = LocalMainFrame()->PageZoomFactor();
float height_css_px = VisibleRect().Height() / zoom;
return height_css_px;
}
@@ -497,8 +500,15 @@ double VisualViewport::VisibleHeightCSSPx() const {
bool VisualViewport::DidSetScaleOrLocation(float scale,
bool is_pinch_gesture_active,
const FloatPoint& location) {
- if (!MainFrame())
+ if (!LocalMainFrame()) {
+ is_pinch_gesture_active_ = is_pinch_gesture_active;
+ // The VisualViewport for a remote mainframe must always be 1.0 or else
+ // event targeting will fail.
+ DCHECK(scale == 1.f);
+ scale_ = scale;
+ offset_ = ScrollOffset();
return false;
+ }
bool values_changed = false;
@@ -539,20 +549,20 @@ bool VisualViewport::DidSetScaleOrLocation(float scale,
// ScrollingCoordinator.
if (auto* coordinator = GetPage().GetScrollingCoordinator()) {
if (scroll_layer_)
- coordinator->UpdateCompositorScrollOffset(*MainFrame(), *this);
+ coordinator->UpdateCompositorScrollOffset(*LocalMainFrame(), *this);
}
EnqueueScrollEvent();
- MainFrame()->View()->DidChangeScrollOffset();
+ LocalMainFrame()->View()->DidChangeScrollOffset();
values_changed = true;
}
if (!values_changed)
return false;
- probe::DidChangeViewport(MainFrame());
- MainFrame()->Loader().SaveScrollState();
+ probe::DidChangeViewport(LocalMainFrame());
+ LocalMainFrame()->Loader().SaveScrollState();
ClampToBoundaries();
@@ -582,14 +592,13 @@ void VisualViewport::CreateLayers() {
scroll_layer_->SetBounds(gfx::Size(ContentsSize()));
scroll_layer_->SetElementId(GetScrollElementId());
- ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
- DCHECK(coordinator);
- LayerForScrollingDidChange(coordinator->GetCompositorAnimationTimeline());
-
InitializeScrollbars();
- if (MainFrame())
- coordinator->UpdateCompositorScrollOffset(*MainFrame(), *this);
+ if (LocalMainFrame()) {
+ ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
+ DCHECK(coordinator);
+ coordinator->UpdateCompositorScrollOffset(*LocalMainFrame(), *this);
+ }
}
void VisualViewport::InitializeScrollbars() {
@@ -599,21 +608,18 @@ void VisualViewport::InitializeScrollbars() {
needs_paint_property_update_ = true;
+ scrollbar_layer_horizontal_ = nullptr;
+ scrollbar_layer_vertical_ = nullptr;
if (VisualViewportSuppliesScrollbars() &&
!GetPage().GetSettings().GetHideScrollbars()) {
- DCHECK(!scrollbar_layer_horizontal_);
- DCHECK(!scrollbar_layer_vertical_);
UpdateScrollbarLayer(kHorizontalScrollbar);
UpdateScrollbarLayer(kVerticalScrollbar);
- } else {
- scrollbar_layer_horizontal_ = nullptr;
- scrollbar_layer_vertical_ = nullptr;
}
// Ensure existing LocalFrameView scrollbars are removed if the visual
// viewport scrollbars are now supplied, or created if the visual viewport no
// longer supplies scrollbars.
- LocalFrame* frame = MainFrame();
+ LocalFrame* frame = LocalMainFrame();
if (frame && frame->View())
frame->View()->VisualViewportScrollbarsChanged();
}
@@ -657,7 +663,7 @@ bool VisualViewport::VisualViewportSuppliesScrollbars() const {
}
const Document* VisualViewport::GetDocument() const {
- return MainFrame() ? MainFrame()->GetDocument() : nullptr;
+ return LocalMainFrame() ? LocalMainFrame()->GetDocument() : nullptr;
}
CompositorElementId VisualViewport::GetScrollElementId() const {
@@ -673,9 +679,9 @@ ChromeClient* VisualViewport::GetChromeClient() const {
}
SmoothScrollSequencer* VisualViewport::GetSmoothScrollSequencer() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return nullptr;
- return &MainFrame()->GetSmoothScrollSequencer();
+ return &LocalMainFrame()->GetSmoothScrollSequencer();
}
void VisualViewport::SetScrollOffset(
@@ -745,7 +751,7 @@ IntSize VisualViewport::MaximumScrollOffsetInt() const {
}
ScrollOffset VisualViewport::MaximumScrollOffset() const {
- if (!MainFrame())
+ if (!LocalMainFrame())
return ScrollOffset();
// TODO(bokan): We probably shouldn't be storing the bounds in a float.
@@ -771,10 +777,10 @@ ScrollOffset VisualViewport::MaximumScrollOffset() const {
IntPoint VisualViewport::ClampDocumentOffsetAtScale(const IntPoint& offset,
float scale) {
- if (!MainFrame() || !MainFrame()->View())
+ if (!LocalMainFrame() || !LocalMainFrame()->View())
return IntPoint();
- LocalFrameView* view = MainFrame()->View();
+ LocalFrameView* view = LocalMainFrame()->View();
FloatSize scaled_size(ExcludeScrollbars(size_));
scaled_size.Scale(1 / scale);
@@ -808,7 +814,8 @@ float VisualViewport::BrowserControlsAdjustment() const {
bool VisualViewport::UserInputScrollable(ScrollbarOrientation) const {
// If there is a non-root fullscreen element, prevent the viewport from
// scrolling.
- Document* main_document = MainFrame() ? MainFrame()->GetDocument() : nullptr;
+ Document* main_document =
+ LocalMainFrame() ? LocalMainFrame()->GetDocument() : nullptr;
if (main_document) {
Element* fullscreen_element =
Fullscreen::FullscreenElementFrom(*main_document);
@@ -819,7 +826,7 @@ bool VisualViewport::UserInputScrollable(ScrollbarOrientation) const {
}
IntSize VisualViewport::ContentsSize() const {
- LocalFrame* frame = MainFrame();
+ LocalFrame* frame = LocalMainFrame();
if (!frame || !frame->View())
return IntSize();
@@ -833,11 +840,11 @@ IntRect VisualViewport::VisibleContentRect(
scoped_refptr<base::SingleThreadTaskRunner> VisualViewport::GetTimerTaskRunner()
const {
- return MainFrame()->GetTaskRunner(TaskType::kInternalDefault);
+ return LocalMainFrame()->GetTaskRunner(TaskType::kInternalDefault);
}
mojom::blink::ColorScheme VisualViewport::UsedColorScheme() const {
- if (LocalFrame* main_frame = MainFrame()) {
+ if (LocalFrame* main_frame = LocalMainFrame()) {
if (Document* main_document = main_frame->GetDocument())
return main_document->GetLayoutView()->StyleRef().UsedColorScheme();
}
@@ -870,13 +877,13 @@ cc::Layer* VisualViewport::LayerForVerticalScrollbar() const {
}
RootFrameViewport* VisualViewport::GetRootFrameViewport() const {
- if (!MainFrame() || !MainFrame()->View())
+ if (!LocalMainFrame() || !LocalMainFrame()->View())
return nullptr;
- return MainFrame()->View()->GetRootFrameViewport();
+ return LocalMainFrame()->View()->GetRootFrameViewport();
}
-LocalFrame* VisualViewport::MainFrame() const {
+LocalFrame* VisualViewport::LocalMainFrame() const {
return GetPage().MainFrame() && GetPage().MainFrame()->IsLocalFrame()
? GetPage().DeprecatedLocalMainFrame()
: nullptr;
@@ -892,7 +899,7 @@ IntSize VisualViewport::ExcludeScrollbars(const IntSize& size) const {
}
bool VisualViewport::ScheduleAnimation() {
- GetPage().GetChromeClient().ScheduleAnimation(MainFrame()->View());
+ GetPage().GetChromeClient().ScheduleAnimation(LocalMainFrame()->View());
return true;
}
@@ -959,10 +966,10 @@ IntPoint VisualViewport::RootFrameToViewport(
}
void VisualViewport::StartTrackingPinchStats() {
- if (!MainFrame())
+ if (!LocalMainFrame())
return;
- Document* document = MainFrame()->GetDocument();
+ Document* document = LocalMainFrame()->GetDocument();
if (!document)
return;
@@ -1001,10 +1008,10 @@ void VisualViewport::SendUMAMetrics() {
}
bool VisualViewport::ShouldDisableDesktopWorkarounds() const {
- if (!MainFrame() || !MainFrame()->View())
+ if (!LocalMainFrame() || !LocalMainFrame()->View())
return false;
- if (!MainFrame()->GetSettings()->GetViewportEnabled())
+ if (!LocalMainFrame()->GetSettings()->GetViewportEnabled())
return false;
// A document is considered adapted to small screen UAs if one of these holds:
@@ -1014,7 +1021,7 @@ bool VisualViewport::ShouldDisableDesktopWorkarounds() const {
const PageScaleConstraints& constraints =
GetPage().GetPageScaleConstraintsSet().PageDefinedConstraints();
- return MainFrame()->View()->GetLayoutSize().Width() == size_.Width() ||
+ return LocalMainFrame()->View()->GetLayoutSize().Width() == size_.Width() ||
(constraints.minimum_scale == constraints.maximum_scale &&
constraints.minimum_scale != -1);
}
@@ -1044,8 +1051,8 @@ ScrollbarTheme& VisualViewport::GetPageScrollbarTheme() const {
}
PaintArtifactCompositor* VisualViewport::GetPaintArtifactCompositor() const {
- if (MainFrame() && MainFrame()->View())
- return MainFrame()->View()->GetPaintArtifactCompositor();
+ if (LocalMainFrame() && LocalMainFrame()->View())
+ return LocalMainFrame()->View()->GetPaintArtifactCompositor();
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
index 388b889bcbd..4dc38ebe0af 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -289,7 +289,7 @@ class CORE_EXPORT VisualViewport : public GarbageCollected<VisualViewport>,
RootFrameViewport* GetRootFrameViewport() const;
- LocalFrame* MainFrame() const;
+ LocalFrame* LocalMainFrame() const;
Page& GetPage() const {
DCHECK(page_);
diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index a97d8d10a8d..0642a3dd99d 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -13,13 +13,13 @@
#include "cc/trees/transform_node.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/context_menu_data/context_menu_data.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/widget/device_emulation_params.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/web/web_ax_context.h"
-#include "third_party/blink/public/web/web_context_menu_data.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_script_source.h"
@@ -31,7 +31,7 @@
#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/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
@@ -71,7 +71,7 @@ using blink::url_test_helpers::ToKURL;
namespace blink {
-::std::ostream& operator<<(::std::ostream& os, const WebContextMenuData& data) {
+::std::ostream& operator<<(::std::ostream& os, const ContextMenuData& data) {
return os << "Context menu location: [" << data.mouse_position.x() << ", "
<< data.mouse_position.y() << "]";
}
@@ -100,7 +100,7 @@ class VisualViewportTest : public testing::Test,
void (*override_settings_func)(WebSettings*) = nullptr) {
if (!override_settings_func)
override_settings_func = &ConfigureSettings;
- helper_.Initialize(nullptr, nullptr, nullptr, override_settings_func);
+ helper_.Initialize(nullptr, nullptr, override_settings_func);
WebView()->SetDefaultPageScaleLimits(1, 4);
}
@@ -108,7 +108,7 @@ class VisualViewportTest : public testing::Test,
void (*override_settings_func)(WebSettings*) = nullptr) {
if (!override_settings_func)
override_settings_func = &ConfigureAndroidSettings;
- helper_.Initialize(nullptr, nullptr, nullptr, override_settings_func);
+ helper_.Initialize(nullptr, nullptr, override_settings_func);
WebView()->SetDefaultPageScaleLimits(0.25f, 5);
}
@@ -239,6 +239,7 @@ INSTANTIATE_PAINT_TEST_SUITE_P(VisualViewportTest);
// WebView resizes the VisualViewport.
TEST_P(VisualViewportTest, TestResize) {
InitializeWithDesktopSettings();
+ WebView()->MainFrameViewWidget()->Resize(gfx::Size(320, 240));
WebView()->ResizeWithBrowserControls(
gfx::Size(320, 240), gfx::Size(320, 240),
WebView()->GetBrowserControls().Params());
@@ -255,6 +256,7 @@ TEST_P(VisualViewportTest, TestResize) {
// Resizing the WebView should change the VisualViewport.
web_view_size = gfx::Size(640, 480);
+ WebView()->MainFrameViewWidget()->Resize(web_view_size);
WebView()->ResizeWithBrowserControls(
web_view_size, web_view_size, WebView()->GetBrowserControls().Params());
EXPECT_EQ(web_view_size, WebView()->MainFrameViewWidget()->Size());
@@ -1117,9 +1119,8 @@ TEST_P(VisualViewportTest, TestWebViewResizeCausesViewportConstrainedLayout) {
class VisualViewportMockWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- MOCK_METHOD2(ShowContextMenu,
- void(const WebContextMenuData&,
- const base::Optional<gfx::Point>&));
+ MOCK_METHOD2(UpdateContextMenuDataForTesting,
+ void(const ContextMenuData&, const base::Optional<gfx::Point>&));
MOCK_METHOD0(DidChangeScrollOffset, void());
};
@@ -1154,11 +1155,12 @@ TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
WebLocalFrameClient* old_client = WebView()->MainFrameImpl()->Client();
VisualViewportMockWebFrameClient mock_web_frame_client;
- EXPECT_CALL(mock_web_frame_client,
- ShowContextMenu(ContextMenuAtLocation(
- mouse_down_event.PositionInWidget().x(),
- mouse_down_event.PositionInWidget().y()),
- _));
+ EXPECT_CALL(
+ mock_web_frame_client,
+ UpdateContextMenuDataForTesting(
+ ContextMenuAtLocation(mouse_down_event.PositionInWidget().x(),
+ mouse_down_event.PositionInWidget().y()),
+ _));
// Do a sanity check with no scale applied.
WebView()->MainFrameImpl()->SetClient(&mock_web_frame_client);
@@ -1178,11 +1180,12 @@ TEST_P(VisualViewportTest, TestContextMenuShownInCorrectLocation) {
WebView()->SetPageScaleFactor(2);
EXPECT_CALL(mock_web_frame_client, DidChangeScrollOffset());
visual_viewport.SetLocation(FloatPoint(60, 80));
- EXPECT_CALL(mock_web_frame_client,
- ShowContextMenu(ContextMenuAtLocation(
- mouse_down_event.PositionInWidget().x(),
- mouse_down_event.PositionInWidget().y()),
- _));
+ EXPECT_CALL(
+ mock_web_frame_client,
+ UpdateContextMenuDataForTesting(
+ ContextMenuAtLocation(mouse_down_event.PositionInWidget().x(),
+ mouse_down_event.PositionInWidget().y()),
+ _));
mouse_down_event.button = WebMouseEvent::Button::kRight;
WebView()->MainFrameViewWidget()->HandleInputEvent(
@@ -2402,6 +2405,48 @@ TEST_P(VisualViewportTest, AutoResizeNoHeightUsesMinimumHeight) {
base_url);
}
+// When a provisional frame is committed, it will get swapped in. At that
+// point, the VisualViewport will be reset but the Document is in a detached
+// state with no domWindow(). Ensure we correctly reset the viewport properties
+// but don't crash trying to enqueue resize and scroll events in the document.
+// https://crbug.com/1175916.
+TEST_P(VisualViewportTest, SwapMainFrame) {
+ InitializeWithDesktopSettings();
+
+ WebView()->SetPageScaleFactor(2.0f);
+ WebView()->SetVisualViewportOffset(gfx::PointF(10, 20));
+
+ WebLocalFrame* local_frame =
+ helper_.CreateProvisional(*helper_.LocalMainFrame());
+
+ // Commit the provisional frame so it gets swapped in.
+ RegisterMockedHttpURLLoad("200-by-300.html");
+ frame_test_helpers::LoadFrame(local_frame, base_url_ + "200-by-300.html");
+
+ EXPECT_EQ(WebView()->PageScaleFactor(), 1.0f);
+ EXPECT_EQ(WebView()->VisualViewportOffset().x(), 0.0f);
+ EXPECT_EQ(WebView()->VisualViewportOffset().y(), 0.0f);
+}
+
+// Similar to above but checks the case where a page is loaded such that it
+// will zoom out as a result of loading and layout (i.e. loading a desktop page
+// on Android).
+TEST_P(VisualViewportTest, SwapMainFrameLoadZoomedOut) {
+ InitializeWithAndroidSettings();
+ WebView()->MainFrameViewWidget()->Resize(gfx::Size(100, 150));
+
+ WebLocalFrame* local_frame =
+ helper_.CreateProvisional(*helper_.LocalMainFrame());
+
+ // Commit the provisional frame so it gets swapped in.
+ RegisterMockedHttpURLLoad("200-by-300.html");
+ frame_test_helpers::LoadFrame(local_frame, base_url_ + "200-by-300.html");
+
+ EXPECT_EQ(WebView()->PageScaleFactor(), 0.5f);
+ EXPECT_EQ(WebView()->VisualViewportOffset().x(), 0.0f);
+ EXPECT_EQ(WebView()->VisualViewportOffset().y(), 0.0f);
+}
+
class VisualViewportSimTest : public SimTest {
public:
VisualViewportSimTest() {}
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame.cc b/chromium/third_party/blink/renderer/core/frame/web_frame.cc
index ad790bea78e..62f42638f43 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame.cc
@@ -53,7 +53,7 @@ WebVector<unsigned> WebFrame::GetInsecureRequestToUpgrade() const {
}
WebFrame* WebFrame::Opener() const {
- return FromFrame(ToCoreFrame(*this)->Opener());
+ return FromCoreFrame(ToCoreFrame(*this)->Opener());
}
void WebFrame::ClearOpener() {
@@ -63,42 +63,42 @@ void WebFrame::ClearOpener() {
WebFrame* WebFrame::Parent() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->Parent());
+ return FromCoreFrame(core_frame->Parent());
}
WebFrame* WebFrame::Top() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->Top());
+ return FromCoreFrame(core_frame->Top());
}
WebFrame* WebFrame::FirstChild() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->FirstChild());
+ return FromCoreFrame(core_frame->FirstChild());
}
WebFrame* WebFrame::LastChild() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->LastChild());
+ return FromCoreFrame(core_frame->LastChild());
}
WebFrame* WebFrame::NextSibling() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->NextSibling());
+ return FromCoreFrame(core_frame->NextSibling());
}
WebFrame* WebFrame::PreviousSibling() const {
Frame* core_frame = ToCoreFrame(*this);
CHECK(core_frame);
- return FromFrame(core_frame->PreviousSibling());
+ return FromCoreFrame(core_frame->PreviousSibling());
}
WebFrame* WebFrame::TraverseNext() const {
if (Frame* frame = ToCoreFrame(*this))
- return FromFrame(frame->Tree().TraverseNext());
+ return FromCoreFrame(frame->Tree().TraverseNext());
return nullptr;
}
@@ -106,7 +106,7 @@ WebFrame* WebFrame::FromFrameOwnerElement(const WebNode& web_node) {
Node* node = web_node;
if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node))
- return FromFrame(frame_owner->ContentFrame());
+ return FromCoreFrame(frame_owner->ContentFrame());
return nullptr;
}
@@ -116,7 +116,7 @@ bool WebFrame::IsLoading() const {
return false;
}
-WebFrame* WebFrame::FromFrame(Frame* frame) {
+WebFrame* WebFrame::FromCoreFrame(Frame* frame) {
if (!frame)
return nullptr;
@@ -126,9 +126,9 @@ WebFrame* WebFrame::FromFrame(Frame* frame) {
}
WebFrame::WebFrame(mojom::blink::TreeScopeType scope,
- const base::UnguessableToken& frame_token)
+ const FrameToken& frame_token)
: scope_(scope), frame_token_(frame_token) {
- DCHECK(frame_token_);
+ DCHECK(frame_token.value());
}
void WebFrame::Close() {}
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_serializer_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_serializer_impl.cc
index 5a4df2a7244..d01a042a3ff 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_serializer_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_serializer_impl.cc
@@ -320,7 +320,7 @@ void WebFrameSerializerImpl::OpenTagToString(Element* element,
// Find out if we need to do frame-specific link rewriting.
WebFrame* frame = nullptr;
if (auto* frame_owner_element = DynamicTo<HTMLFrameOwnerElement>(element)) {
- frame = WebFrame::FromFrame(frame_owner_element->ContentFrame());
+ frame = WebFrame::FromCoreFrame(frame_owner_element->ContentFrame());
}
WebString rewritten_frame_link;
bool should_rewrite_frame_src =
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_test.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_test.cc
index 7fddf509e0d..d85767a3502 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -37,6 +37,7 @@
#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -54,7 +55,9 @@
#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/common/context_menu_data/context_menu_data.h"
#include "third_party/blink/public/common/context_menu_data/edit_flags.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/loader/referrer_utils.h"
@@ -76,12 +79,11 @@
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/test/test_web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_console_message.h"
-#include "third_party/blink/public/web/web_context_menu_data.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_document_loader.h"
#include "third_party/blink/public/web/web_form_element.h"
-#include "third_party/blink/public/web/web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_local_frame.h"
@@ -114,6 +116,7 @@
#include "third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/editor.h"
@@ -124,6 +127,7 @@
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h"
#include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
@@ -140,7 +144,6 @@
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
@@ -171,6 +174,7 @@
#include "third_party/blink/renderer/core/testing/fake_remote_frame_host.h"
#include "third_party/blink/renderer/core/testing/fake_remote_main_frame_host.h"
#include "third_party/blink/renderer/core/testing/mock_clipboard_host.h"
+#include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/core/testing/scoped_fake_plugin_registry.h"
@@ -181,6 +185,7 @@
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
@@ -309,16 +314,16 @@ class WebFrameTest : public testing::Test {
void RegisterMockedHttpURLLoadWithCSP(const std::string& file_name,
const std::string& csp,
bool report_only = false) {
- WebURLResponse response;
+ std::string full_string = base_url_ + file_name;
+ KURL url = ToKURL(full_string);
+ WebURLResponse response = WebURLResponse(url);
response.SetMimeType("text/html");
response.AddHttpHeaderField(
report_only ? WebString("Content-Security-Policy-Report-Only")
: WebString("Content-Security-Policy"),
WebString::FromUTF8(csp));
- std::string full_string = base_url_ + file_name;
RegisterMockedURLLoadWithCustomResponse(
- ToKURL(full_string),
- test::CoreTestDataPath(WebString::FromUTF8(file_name)), response);
+ url, test::CoreTestDataPath(WebString::FromUTF8(file_name)), response);
}
void RegisterMockedHttpURLLoadWithMimeType(const std::string& file_name,
@@ -351,6 +356,7 @@ class WebFrameTest : public testing::Test {
frame_test_helpers::WebViewHelper* web_view_helper) {
web_view_helper->InitializeAndLoad(url);
web_view_helper->GetWebView()->GetSettings()->SetDefaultFontSize(12);
+ web_view_helper->GetWebView()->MainFrameWidget()->SetFocus(true);
web_view_helper->Resize(gfx::Size(640, 480));
}
@@ -457,7 +463,7 @@ TEST_F(WebFrameTest, ContentText) {
web_view_helper.InitializeAndLoad(base_url_ + "iframes_test.html");
// Now retrieve the frames text and test it only includes visible elements.
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
@@ -681,6 +687,98 @@ TEST_F(WebFrameTest, IframeScriptRemovesSelf) {
EXPECT_EQ(String(), callback_helper.StringValue());
}
+namespace {
+
+class CapabilityDelegationMessageListener final : public NativeEventListener {
+ public:
+ void Invoke(ExecutionContext*, Event* event) override {
+ delegate_payment_request_ =
+ static_cast<MessageEvent*>(event)->delegatePaymentRequest();
+ }
+
+ bool DelegatePaymentRequest() {
+ bool value = delegate_payment_request_.value();
+ delegate_payment_request_.reset();
+ return value;
+ }
+
+ private:
+ base::Optional<bool> delegate_payment_request_;
+};
+
+} // namespace
+
+TEST_F(WebFrameTest, CapabilityDelegationMessageEventTest) {
+ RuntimeEnabledFeatures::SetCapabilityDelegationPaymentRequestEnabled(true);
+
+ RegisterMockedHttpURLLoad("single_iframe.html");
+ RegisterMockedHttpURLLoad("visible_iframe.html");
+
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.InitializeAndLoad(base_url_ + "single_iframe.html");
+
+ auto* main_frame =
+ To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
+ auto* child_frame = To<LocalFrame>(main_frame->FirstChild());
+ DCHECK(main_frame);
+ DCHECK(child_frame);
+
+ auto* message_event_listener =
+ MakeGarbageCollected<CapabilityDelegationMessageListener>();
+ child_frame->GetDocument()->domWindow()->addEventListener(
+ event_type_names::kMessage, message_event_listener);
+
+ v8::HandleScope scope(v8::Isolate::GetCurrent());
+ ScriptExecutionCallbackHelper callback_helper(
+ web_view_helper.LocalMainFrame()->MainWorldScriptContext());
+
+ WebScriptSource post_message_wo_payment_request(
+ WebString("window.frames[0].postMessage('0', {targetOrigin: '*'});"));
+ WebScriptSource post_message_w_payment_request(
+ WebString("window.frames[0].postMessage("
+ "'1', {targetOrigin: '*', createToken: 'paymentrequest'});"));
+
+ // The delegation info is not passed through a postMessage that is sent
+ // without either user activation or the delegation option.
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->RequestExecuteScriptAndReturnValue(post_message_wo_payment_request,
+ false, &callback_helper);
+ RunPendingTasks();
+ EXPECT_TRUE(callback_helper.DidComplete());
+ EXPECT_FALSE(message_event_listener->DelegatePaymentRequest());
+
+ // The delegation info is not passed through a postMessage that is sent
+ // without user activation but with the delegation option.
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->RequestExecuteScriptAndReturnValue(post_message_w_payment_request,
+ false, &callback_helper);
+ RunPendingTasks();
+ EXPECT_TRUE(callback_helper.DidComplete());
+ EXPECT_FALSE(message_event_listener->DelegatePaymentRequest());
+
+ // The delegation info is not passed through a postMessage that is sent with
+ // user activation but without the delegation option.
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->RequestExecuteScriptAndReturnValue(post_message_wo_payment_request,
+ true, &callback_helper);
+ RunPendingTasks();
+ EXPECT_TRUE(callback_helper.DidComplete());
+ EXPECT_FALSE(message_event_listener->DelegatePaymentRequest());
+
+ // The delegation info is passed through a postMessage that is sent with both
+ // user activation and the delegation option.
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->RequestExecuteScriptAndReturnValue(post_message_w_payment_request, true,
+ &callback_helper);
+ RunPendingTasks();
+ EXPECT_TRUE(callback_helper.DidComplete());
+ EXPECT_TRUE(message_event_listener->DelegatePaymentRequest());
+}
+
TEST_F(WebFrameTest, FormWithNullFrame) {
RegisterMockedHttpURLLoad("form.html");
@@ -710,7 +808,7 @@ TEST_F(WebFrameTest, ChromePageJavascript) {
// Now retrieve the frame's text and ensure it was modified by running
// javascript.
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_NE(std::string::npos, content.find("Clobbered"));
@@ -730,7 +828,7 @@ TEST_F(WebFrameTest, ChromePageNoJavascript) {
// Now retrieve the frame's text and ensure it wasn't modified by running
// javascript.
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_EQ(std::string::npos, content.find("Clobbered"));
@@ -755,7 +853,7 @@ TEST_F(WebFrameTest, LocationSetHostWithMissingPort) {
web_view_helper.GetWebView()->MainFrameImpl(),
"javascript:document.body.textContent = location.href; void 0;");
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_EQ("http://internal.test/" + file_name, content);
@@ -778,7 +876,7 @@ TEST_F(WebFrameTest, LocationSetEmptyPort) {
web_view_helper.GetWebView()->MainFrameImpl(),
"javascript:document.body.textContent = location.href; void 0;");
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_EQ("http://internal.test/" + file_name, content);
@@ -1165,7 +1263,7 @@ TEST_F(WebFrameTest, PostMessageEvent) {
BlinkTransferableMessage::FromMessageEvent(message_event));
// Verify that only the first addition is in the body of the page.
- std::string content = WebFrameContentDumper::DumpWebViewAsText(
+ std::string content = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), 1024)
.Utf8();
EXPECT_NE(std::string::npos, content.find("Message 1."));
@@ -1209,18 +1307,6 @@ TEST_F(WebFrameTest, PostMessageThenDetach) {
namespace {
-class FixedLayoutTestWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
- public:
- FixedLayoutTestWebWidgetClient() = default;
- ~FixedLayoutTestWebWidgetClient() override = default;
-
- // frame_test_helpers::TestWebWidgetClient:
- ScreenInfo GetInitialScreenInfo() override { return screen_info_; }
-
- ScreenInfo screen_info_;
-};
-
// Helper function to set autosizing multipliers on a document.
bool SetTextAutosizingMultiplier(Document* document, float multiplier) {
bool multiplier_set = false;
@@ -1253,39 +1339,40 @@ bool CheckTextAutosizingMultiplier(Document* document, float multiplier) {
}
void UpdateScreenInfoAndResizeView(
- FixedLayoutTestWebWidgetClient* client,
+ frame_test_helpers::WebViewHelper* web_view_helper,
+ const ScreenInfo& screen_info) {
+ web_view_helper->GetWebView()->MainFrameViewWidget()->UpdateScreenInfo(
+ screen_info);
+ web_view_helper->Resize(screen_info.rect.size());
+}
+
+void UpdateScreenInfoAndResizeView(
frame_test_helpers::WebViewHelper* web_view_helper,
int viewport_width,
int viewport_height) {
- client->screen_info_.rect = gfx::Rect(viewport_width, viewport_height);
- web_view_helper->GetWebView()->MainFrameViewWidget()->UpdateScreenInfo(
- client->screen_info_);
- web_view_helper->Resize(gfx::Size(viewport_width, viewport_height));
+ ScreenInfo screen_info =
+ web_view_helper->GetMainFrameWidget()->GetOriginalScreenInfo();
+ screen_info.rect = gfx::Rect(viewport_width, viewport_height);
+ UpdateScreenInfoAndResizeView(web_view_helper, screen_info);
}
} // namespace
-class WebFixedLayoutFrameTest : public WebFrameTest {
- protected:
- FixedLayoutTestWebWidgetClient widget_client_;
-};
-
TEST_F(WebFrameTest, ChangeInFixedLayoutResetsTextAutosizingMultipliers) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
Document* document =
To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
->GetDocument();
document->GetSettings()->SetTextAutosizingEnabled(true);
- EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
+ EXPECT_TRUE(document->GetSettings()->GetTextAutosizingEnabled());
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
EXPECT_TRUE(SetTextAutosizingMultiplier(document, 2));
@@ -1306,17 +1393,15 @@ TEST_F(WebFrameTest, WorkingTextAutosizingMultipliers_VirtualViewport) {
const std::string html_file = "fixed_layout.html";
RegisterMockedHttpURLLoad(html_file);
- FixedLayoutTestWebWidgetClient client;
-
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + html_file, nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
Document* document =
To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
->GetDocument();
document->GetSettings()->SetTextAutosizingEnabled(true);
- EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
+ EXPECT_TRUE(document->GetSettings()->GetTextAutosizingEnabled());
web_view_helper.Resize(gfx::Size(490, 800));
@@ -1329,20 +1414,19 @@ TEST_F(WebFrameTest,
RegisterMockedHttpURLLoad("iframe_reload.html");
RegisterMockedHttpURLLoad("visible_iframe.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "iframe_reload.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
auto* main_frame =
To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
Document* document = main_frame->GetDocument();
LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
document->GetSettings()->SetTextAutosizingEnabled(true);
- EXPECT_TRUE(document->GetSettings()->TextAutosizingEnabled());
+ EXPECT_TRUE(document->GetSettings()->GetTextAutosizingEnabled());
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
for (Frame* frame = main_frame; frame; frame = frame->Tree().TraverseNext()) {
@@ -1374,13 +1458,11 @@ TEST_F(WebFrameTest,
}
TEST_F(WebFrameTest, ZeroHeightPositiveWidthNotIgnored) {
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 1280;
int viewport_height = 0;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
@@ -1401,13 +1483,12 @@ TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag) {
int viewport_width = 640;
int viewport_height = 480;
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 2;
-
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
- nullptr, &client, ConfigureAndroid);
-
+ nullptr, ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(2.f);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
EXPECT_EQ(
@@ -1427,15 +1508,13 @@ TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag) {
TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumScale) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
// Make sure we initialize to minimum scale, even if the window size
// only becomes available after the load begins.
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
base_url_ + "fixed_layout.html");
@@ -1470,15 +1549,13 @@ TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumScale) {
TEST_F(WebFrameTest, WideDocumentInitializeAtMinimumScale) {
RegisterMockedHttpURLLoad("wide_document.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
// Make sure we initialize to minimum scale, even if the window size
// only becomes available after the load begins.
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
base_url_ + "wide_document.html");
@@ -1512,14 +1589,12 @@ TEST_F(WebFrameTest, WideDocumentInitializeAtMinimumScale) {
TEST_F(WebFrameTest, DelayedViewportInitialScale) {
RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
+ base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -1539,14 +1614,12 @@ TEST_F(WebFrameTest, DelayedViewportInitialScale) {
TEST_F(WebFrameTest, setLoadWithOverviewModeToFalse) {
RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
+ base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -1560,14 +1633,12 @@ TEST_F(WebFrameTest, setLoadWithOverviewModeToFalse) {
TEST_F(WebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport) {
RegisterMockedHttpURLLoad("large-div.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -1582,14 +1653,12 @@ TEST_F(WebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport) {
TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidth) {
RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
+ base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -1613,15 +1682,13 @@ TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidth) {
TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale) {
RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
@@ -1645,14 +1712,12 @@ TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale) {
TEST_F(WebFrameTest, WideViewportSetsTo980WithoutViewportTag) {
RegisterMockedHttpURLLoad("no_viewport_tag.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
@@ -1676,13 +1741,11 @@ TEST_F(WebFrameTest, WideViewportSetsTo980WithoutViewportTag) {
TEST_F(WebFrameTest, WideViewportSetsTo980WithXhtmlMp) {
RegisterMockedHttpURLLoad("viewport/viewport-legacy-xhtmlmp.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
@@ -1706,15 +1769,12 @@ TEST_F(WebFrameTest, WideViewportSetsTo980WithXhtmlMp) {
TEST_F(WebFrameTest, NoWideViewportAndHeightInMeta) {
RegisterMockedHttpURLLoad("viewport-height-1000.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport-height-1000.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
@@ -1730,14 +1790,12 @@ TEST_F(WebFrameTest, NoWideViewportAndHeightInMeta) {
TEST_F(WebFrameTest, WideViewportSetsTo980WithAutoWidth) {
RegisterMockedHttpURLLoad("viewport-2x-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-2x-initial-scale.html", nullptr, nullptr, &client,
+ base_url_ + "viewport-2x-initial-scale.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -1760,15 +1818,13 @@ TEST_F(WebFrameTest, WideViewportSetsTo980WithAutoWidth) {
TEST_F(WebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode) {
RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -1780,13 +1836,11 @@ TEST_F(WebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode) {
TEST_F(WebFrameTest, setInitialPageScaleFactorPermanently) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
float enforced_page_scale_factor = 2.0f;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
@@ -1813,15 +1867,13 @@ TEST_F(WebFrameTest,
PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode) {
RegisterMockedHttpURLLoad("viewport-auto-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
float enforced_page_scale_factor = 0.5f;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr, &client,
+ base_url_ + "viewport-auto-initial-scale.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetLoadWithOverviewMode(false);
web_view_helper.GetWebView()->SetInitialPageScaleOverride(
@@ -1836,8 +1888,6 @@ TEST_F(WebFrameTest,
PermanentInitialPageScaleFactorOverridesPageViewportInitialScale) {
RegisterMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
float enforced_page_scale_factor = 0.5f;
@@ -1845,7 +1895,7 @@ TEST_F(WebFrameTest,
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-wide-2x-initial-scale.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->SetInitialPageScaleOverride(
enforced_page_scale_factor);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -1867,8 +1917,6 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
for (size_t i = 0; i < base::size(pages); ++i)
RegisterMockedHttpURLLoad(pages[i]);
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 400;
int viewport_height = 300;
float enforced_page_scale_factor = 0.75f;
@@ -1877,7 +1925,7 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
for (int quirk_enabled = 0; quirk_enabled <= 1; ++quirk_enabled) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + pages[i], nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()
->GetSettings()
->SetClobberUserAgentInitialScaleQuirk(quirk_enabled);
@@ -1896,14 +1944,12 @@ TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) {
}
TEST_F(WebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth) {
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
float enforced_page_scale_factor = 0.5;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr, &client,
+ web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -1926,15 +1972,13 @@ TEST_F(WebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth) {
TEST_F(WebFrameTest, DocumentElementClientHeightWorksWithWrapContentMode) {
RegisterMockedHttpURLLoad("0-by-0.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "0-by-0.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -1947,15 +1991,13 @@ TEST_F(WebFrameTest, DocumentElementClientHeightWorksWithWrapContentMode) {
TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksWithWrapContentMode) {
RegisterMockedHttpURLLoad("0-by-0.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "0-by-0.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
@@ -1993,15 +2035,13 @@ TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksWithWrapContentMode) {
TEST_F(WebFrameTest, SetForceZeroLayoutHeight) {
RegisterMockedHttpURLLoad("200-by-300.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
EXPECT_LE(viewport_height, web_view_helper.GetWebView()
@@ -2050,14 +2090,12 @@ TEST_F(WebFrameTest, SetForceZeroLayoutHeight) {
TEST_F(WebFrameTest, ToggleViewportMetaOnOff) {
RegisterMockedHttpURLLoad("viewport-device-width.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport-device-width.html",
- nullptr, nullptr, &client);
+ nullptr, nullptr);
WebSettings* settings = web_view_helper.GetWebView()->GetSettings();
settings->SetViewportMetaEnabled(false);
settings->SetViewportEnabled(true);
@@ -2088,15 +2126,13 @@ TEST_F(WebFrameTest,
// because the layout is only updated if either width or height is changed
RegisterMockedHttpURLLoad("button.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "button.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
// set view height to zero so that if the height of the view is not
// successfully updated during later resizes touch events will fail
// (as in not hit content included in the view)
@@ -2137,7 +2173,7 @@ TEST_F(WebFrameTest, FrameOwnerPropertiesMargin) {
WebFrameOwnerProperties properties;
properties.margin_width = 11;
properties.margin_height = 22;
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
+ WebLocalFrameImpl* local_frame = helper.CreateLocalChild(
*helper.RemoteMainFrame(), "frameName", properties);
RegisterMockedHttpURLLoad("frame_owner_properties.html");
@@ -2168,7 +2204,7 @@ TEST_F(WebFrameTest, FrameOwnerPropertiesScrolling) {
WebFrameOwnerProperties properties;
// Turn off scrolling in the subframe.
properties.scrollbar_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
+ WebLocalFrameImpl* local_frame = helper.CreateLocalChild(
*helper.RemoteMainFrame(), "frameName", properties);
RegisterMockedHttpURLLoad("frame_owner_properties.html");
@@ -2190,15 +2226,13 @@ TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations) {
RegisterMockedHttpURLLoad("200-by-300.html");
RegisterMockedHttpURLLoad("large-div.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetForceZeroLayoutHeight(true);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -2216,15 +2250,13 @@ TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations) {
TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk) {
RegisterMockedHttpURLLoad("200-by-300.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "200-by-300.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
@@ -2241,13 +2273,11 @@ TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk) {
TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight) {
RegisterMockedHttpURLLoad("viewport-height-1000.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 600;
int viewport_height = 800;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr, &client,
+ web_view_helper.InitializeAndLoad("about:blank", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -2269,13 +2299,11 @@ TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight) {
TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling) {
RegisterMockedHttpURLLoad("body-overflow-hidden.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client);
+ web_view_helper.Initialize(nullptr, nullptr);
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
base_url_ + "body-overflow-hidden.html");
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -2289,13 +2317,11 @@ TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling) {
TEST_F(WebFrameTest, OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars) {
RegisterMockedHttpURLLoad("body-overflow-hidden-short.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client);
+ web_view_helper.Initialize(nullptr, nullptr);
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
base_url_ + "body-overflow-hidden-short.html");
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -2314,13 +2340,11 @@ TEST_F(WebFrameTest, OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars) {
TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk) {
RegisterMockedHttpURLLoad("body-overflow-hidden.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client);
+ web_view_helper.Initialize(nullptr, nullptr);
web_view_helper.GetWebView()
->GetSettings()
->SetIgnoreMainFrameOverflowHiddenQuirk(true);
@@ -2335,14 +2359,12 @@ TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk) {
TEST_F(WebFrameTest, NonZeroValuesNoQuirk) {
RegisterMockedHttpURLLoad("viewport-nonzero-values.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
float expected_page_scale_factor = 0.5f;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->GetSettings()->SetViewportMetaZeroValuesQuirk(
true);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
@@ -2375,15 +2397,13 @@ TEST_F(WebFrameTest, NonZeroValuesNoQuirk) {
TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
// Small viewport to ensure there are always scrollbars.
int viewport_width = 64;
int viewport_height = 48;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
unsigned prev_layout_count =
@@ -2402,14 +2422,12 @@ TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout) {
TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
unsigned prev_layout_count =
@@ -2428,14 +2446,12 @@ TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) {
TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetPageScaleFactor(3);
@@ -2451,13 +2467,11 @@ TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem) {
TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
base_url_ + "fixed_layout.html");
@@ -2478,15 +2492,13 @@ TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem) {
TEST_F(WebFrameTest, pageScaleFactorDoesntShrinkFrameView) {
RegisterMockedHttpURLLoad("large-div.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
// Small viewport to ensure there are always scrollbars.
int viewport_width = 64;
int viewport_height = 48;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
@@ -2521,14 +2533,12 @@ TEST_F(WebFrameTest, pageScaleFactorDoesntShrinkFrameView) {
TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetPageScaleFactor(2);
@@ -2549,7 +2559,6 @@ TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform) {
TEST_F(WebFrameTest, targetDensityDpiHigh) {
RegisterMockedHttpURLLoad("viewport-target-densitydpi-high.html");
- FixedLayoutTestWebWidgetClient client;
// high-dpi = 240
float target_dpi = 240.0f;
float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
@@ -2559,12 +2568,14 @@ TEST_F(WebFrameTest, targetDensityDpiHigh) {
for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
float device_scale_factor = device_scale_factors[i];
float device_dpi = device_scale_factor * 160.0f;
- client.screen_info_.device_scale_factor = device_scale_factor;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-target-densitydpi-high.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factor);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()
@@ -2600,17 +2611,17 @@ TEST_F(WebFrameTest, targetDensityDpiDevice) {
float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
- client.screen_info_.device_scale_factor = device_scale_factors[i];
-
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-target-densitydpi-device.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factors[i]);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()
@@ -2618,21 +2629,21 @@ TEST_F(WebFrameTest, targetDensityDpiDevice) {
->SetSupportDeprecatedTargetDensityDPI(true);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
- EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_width * device_scale_factors[i],
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Width(),
1.0f);
- EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_height * device_scale_factors[i],
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Height(),
1.0f);
- EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(1.0f / device_scale_factors[i],
web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
}
}
@@ -2643,17 +2654,17 @@ TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth) {
float device_scale_factors[] = {1.0f, 4.0f / 3.0f, 2.0f};
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
for (size_t i = 0; i < base::size(device_scale_factors); ++i) {
- client.screen_info_.device_scale_factor = device_scale_factors[i];
-
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-target-densitydpi-device-and-fixed-width.html",
- nullptr, nullptr, &client, ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factors[i]);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
web_view_helper.GetWebView()
@@ -2683,15 +2694,17 @@ TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth) {
TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne) {
RegisterMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1.33f;
+ float device_scale_factor = 1.33f;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-initial-scale-less-than-1.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factor);
web_view_helper.GetWebView()
->GetSettings()
->SetSupportDeprecatedTargetDensityDPI(true);
@@ -2700,21 +2713,21 @@ TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne) {
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
- EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_width * device_scale_factor,
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Width(),
1.0f);
- EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_height * device_scale_factor,
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Height(),
1.0f);
- EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(1.0f / device_scale_factor,
web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
}
@@ -2722,15 +2735,17 @@ TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth) {
RegisterMockedHttpURLLoad(
"viewport-initial-scale-less-than-1-device-width.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1.33f;
+ float device_scale_factor = 1.33f;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-initial-scale-less-than-1-device-width.html",
- nullptr, nullptr, &client, ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factor);
web_view_helper.GetWebView()
->GetSettings()
->SetSupportDeprecatedTargetDensityDPI(true);
@@ -2740,37 +2755,34 @@ TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth) {
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
const float kPageZoom = 0.25f;
- EXPECT_NEAR(
- viewport_width * client.screen_info_.device_scale_factor / kPageZoom,
- web_view_helper.GetWebView()
- ->MainFrameImpl()
- ->GetFrameView()
- ->GetLayoutSize()
- .Width(),
- 1.0f);
- EXPECT_NEAR(
- viewport_height * client.screen_info_.device_scale_factor / kPageZoom,
- web_view_helper.GetWebView()
- ->MainFrameImpl()
- ->GetFrameView()
- ->GetLayoutSize()
- .Height(),
- 1.0f);
- EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_width * device_scale_factor / kPageZoom,
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->GetFrameView()
+ ->GetLayoutSize()
+ .Width(),
+ 1.0f);
+ EXPECT_NEAR(viewport_height * device_scale_factor / kPageZoom,
+ web_view_helper.GetWebView()
+ ->MainFrameImpl()
+ ->GetFrameView()
+ ->GetLayoutSize()
+ .Height(),
+ 1.0f);
+ EXPECT_NEAR(1.0f / device_scale_factor,
web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
}
TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride) {
RegisterMockedHttpURLLoad("large-div.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
float enforced_page_scale_factor = 5.0f;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "large-div.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -2800,14 +2812,13 @@ TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride) {
TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScale) {
RegisterMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-initial-scale-and-user-scalable-no.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()
->GetSettings()
->SetViewportMetaNonUserScalableQuirk(true);
@@ -2834,15 +2845,17 @@ TEST_F(WebFrameTest,
NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport) {
RegisterMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1.33f;
+ float device_scale_factor = 1.33f;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-initial-scale-and-user-scalable-no.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
+ web_view_helper.GetWebView()
+ ->MainFrameWidget()
+ ->SetDeviceScaleFactorForTesting(device_scale_factor);
web_view_helper.GetWebView()
->GetSettings()
->SetSupportDeprecatedTargetDensityDPI(true);
@@ -2854,35 +2867,34 @@ TEST_F(WebFrameTest,
web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
- EXPECT_NEAR(viewport_width * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_width * device_scale_factor,
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Width(),
1.0f);
- EXPECT_NEAR(viewport_height * client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(viewport_height * device_scale_factor,
web_view_helper.GetWebView()
->MainFrameImpl()
->GetFrameView()
->GetLayoutSize()
.Height(),
1.0f);
- EXPECT_NEAR(1.0f / client.screen_info_.device_scale_factor,
+ EXPECT_NEAR(1.0f / device_scale_factor,
web_view_helper.GetWebView()->PageScaleFactor(), 0.01f);
}
TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport) {
RegisterMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport-2x-initial-scale-non-user-scalable.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()
->GetSettings()
->SetViewportMetaNonUserScalableQuirk(true);
@@ -2911,13 +2923,12 @@ TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport) {
TEST_F(WebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff) {
RegisterMockedHttpURLLoad("no_viewport_tag.html");
- FixedLayoutTestWebWidgetClient client;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "no_viewport_tag.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -2954,7 +2965,7 @@ class WebFrameResizeTest : public WebFrameTest {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + url, nullptr, nullptr,
- nullptr, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
// Origin scrollOffsets preserved under resize.
@@ -3066,14 +3077,12 @@ TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout) {
TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars) {
RegisterMockedHttpURLLoad("fixed_layout.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "fixed_layout.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
LocalFrameView* view = web_view_helper.LocalMainFrame()->GetFrameView();
@@ -3094,15 +3103,12 @@ TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars) {
TEST_F(WebFrameTest, CanOverrideScaleLimits) {
RegisterMockedHttpURLLoad("no_scale_for_you.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "no_scale_for_you.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
@@ -3134,10 +3140,8 @@ TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
int view_width = 500;
int view_height = 500;
- FixedLayoutTestWebWidgetClient client;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client,
- &ConfigureCompositingWebView);
+ web_view_helper.Initialize(nullptr, nullptr, &ConfigureCompositingWebView);
web_view_helper.Resize(gfx::Size(view_width, view_height));
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
@@ -3172,11 +3176,11 @@ void SimulatePageScale(WebViewImpl* web_view_impl, float& scale) {
scale = web_view_impl->PageScaleFactor();
}
-WebRect ComputeBlockBoundHelper(WebViewImpl* web_view_impl,
- const gfx::Point& point,
- bool ignore_clipping) {
+gfx::Rect ComputeBlockBoundHelper(WebViewImpl* web_view_impl,
+ const gfx::Point& point,
+ bool ignore_clipping) {
DCHECK(web_view_impl->MainFrameImpl());
- WebFrameWidgetBase* widget =
+ WebFrameWidgetImpl* widget =
web_view_impl->MainFrameImpl()->FrameWidgetImpl();
DCHECK(widget);
return widget->ComputeBlockBound(point, ignore_clipping);
@@ -3201,16 +3205,16 @@ TEST_F(WebFrameTest, DivAutoZoomParamsTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_scale_for_auto_zoom_into_div_test.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.01f, 4);
web_view_helper.GetWebView()->SetPageScaleFactor(0.5f);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
- WebRect wide_div(200, 100, 400, 150);
- WebRect tall_div(200, 300, 400, 800);
- gfx::Point double_tap_point_wide(wide_div.x + 50, wide_div.y + 50);
- gfx::Point double_tap_point_tall(tall_div.x + 50, tall_div.y + 50);
+ gfx::Rect wide_div(200, 100, 400, 150);
+ gfx::Rect tall_div(200, 300, 400, 800);
+ gfx::Point double_tap_point_wide(wide_div.x() + 50, wide_div.y() + 50);
+ gfx::Point double_tap_point_tall(tall_div.x() + 50, tall_div.y() + 50);
float scale;
IntPoint scroll;
@@ -3219,15 +3223,15 @@ TEST_F(WebFrameTest, DivAutoZoomParamsTest) {
double_tap_zoom_already_legible_ratio;
// Test double-tap zooming into wide div.
- WebRect wide_block_bound = ComputeBlockBoundHelper(
+ gfx::Rect wide_block_bound = ComputeBlockBoundHelper(
web_view_helper.GetWebView(), double_tap_point_wide, false);
web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
double_tap_point_wide, wide_block_bound, kTouchPointPadding,
double_tap_zoom_already_legible_scale, scale, scroll);
// The div should horizontally fill the screen (modulo margins), and
// vertically centered (modulo integer rounding).
- EXPECT_NEAR(viewport_width / (float)wide_div.width, scale, 0.1);
- EXPECT_NEAR(wide_div.x, scroll.X(), 20);
+ EXPECT_NEAR(viewport_width / (float)wide_div.width(), scale, 0.1);
+ EXPECT_NEAR(wide_div.x(), scroll.X(), 20);
EXPECT_EQ(0, scroll.Y());
SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), scroll, scale);
@@ -3244,15 +3248,15 @@ TEST_F(WebFrameTest, DivAutoZoomParamsTest) {
SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), gfx::Point(), scale);
// Test double-tap zooming into tall div.
- WebRect tall_block_bound = ComputeBlockBoundHelper(
+ gfx::Rect tall_block_bound = ComputeBlockBoundHelper(
web_view_helper.GetWebView(), double_tap_point_tall, false);
web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
double_tap_point_tall, tall_block_bound, kTouchPointPadding,
double_tap_zoom_already_legible_scale, scale, scroll);
// The div should start at the top left of the viewport.
- EXPECT_NEAR(viewport_width / (float)tall_div.width, scale, 0.1);
- EXPECT_NEAR(tall_div.x, scroll.X(), 20);
- EXPECT_NEAR(tall_div.y, scroll.Y(), 20);
+ EXPECT_NEAR(viewport_width / (float)tall_div.width(), scale, 0.1);
+ EXPECT_NEAR(tall_div.x(), scroll.X(), 20);
+ EXPECT_NEAR(tall_div.y(), scroll.Y(), 20);
}
TEST_F(WebFrameTest, DivAutoZoomWideDivTest) {
@@ -3265,7 +3269,7 @@ TEST_F(WebFrameTest, DivAutoZoomWideDivTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_wide_div_for_auto_zoom_test.html", nullptr, nullptr,
- nullptr, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
web_view_helper.GetWebView()->SetPageScaleFactor(1.0f);
@@ -3277,8 +3281,8 @@ TEST_F(WebFrameTest, DivAutoZoomWideDivTest) {
web_view_helper.GetWebView()->MinimumPageScaleFactor() *
double_tap_zoom_already_legible_ratio;
- WebRect div(0, 100, viewport_width, 150);
- gfx::Point point(div.x + 50, div.y + 50);
+ gfx::Rect div(0, 100, viewport_width, 150);
+ gfx::Point point(div.x() + 50, div.y() + 50);
float scale;
SetScaleAndScrollAndLayout(
web_view_helper.GetWebView(), gfx::Point(),
@@ -3303,18 +3307,18 @@ TEST_F(WebFrameTest, DivAutoZoomVeryTallTest) {
int viewport_height = 1280 / kDeviceScaleFactor;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "very_tall_div.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
web_view_helper.GetWebView()->SetPageScaleFactor(1.0f);
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
- WebRect div(200, 300, 400, 5000);
- gfx::Point point(div.x + 50, div.y + 3000);
+ gfx::Rect div(200, 300, 400, 5000);
+ gfx::Point point(div.x() + 50, div.y() + 3000);
float scale;
IntPoint scroll;
- WebRect block_bound =
+ gfx::Rect block_bound =
ComputeBlockBoundHelper(web_view_helper.GetWebView(), point, true);
web_view_helper.GetWebView()->ComputeScaleAndScrollForBlockRect(
point, block_bound, 0, 1.0f, scale, scroll);
@@ -3332,7 +3336,7 @@ TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_multiple_divs_for_auto_zoom_test.html", nullptr, nullptr,
- nullptr, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.5f, 4);
web_view_helper.GetWebView()->SetDeviceScaleFactor(kDeviceScaleFactor);
@@ -3342,10 +3346,10 @@ TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- WebRect top_div(200, 100, 200, 150);
- WebRect bottom_div(200, 300, 200, 150);
- gfx::Point top_point(top_div.x + 50, top_div.y + 50);
- gfx::Point bottom_point(bottom_div.x + 50, bottom_div.y + 50);
+ gfx::Rect top_div(200, 100, 200, 150);
+ gfx::Rect bottom_div(200, 300, 200, 150);
+ gfx::Point top_point(top_div.x() + 50, top_div.y() + 50);
+ gfx::Point bottom_point(bottom_div.x() + 50, bottom_div.y() + 50);
float scale;
SetScaleAndScrollAndLayout(
web_view_helper.GetWebView(), gfx::Point(),
@@ -3383,7 +3387,7 @@ TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) {
1.1f, false, 0, 0,
cc::BrowserControlsState::kBoth});
- WebRect block_bounds =
+ gfx::Rect block_bounds =
ComputeBlockBoundHelper(web_view_helper.GetWebView(), top_point, false);
web_view_helper.GetWebView()->AnimateDoubleTapZoom(IntPoint(top_point),
block_bounds);
@@ -3403,7 +3407,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetDeviceScaleFactor(1.5f);
web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
@@ -3411,8 +3415,8 @@ TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) {
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- WebRect div(200, 100, 200, 150);
- gfx::Point double_tap_point(div.x + 50, div.y + 50);
+ gfx::Rect div(200, 100, 200, 150);
+ gfx::Point double_tap_point(div.x() + 50, div.y() + 50);
float scale;
// Test double tap scale bounds.
@@ -3493,7 +3497,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetMaximumLegibleScale(
maximum_legible_scale_factor);
@@ -3505,8 +3509,8 @@ TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest) {
->GetSettings()
.SetTextAutosizingEnabled(true);
- WebRect div(200, 100, 200, 150);
- gfx::Point double_tap_point(div.x + 50, div.y + 50);
+ gfx::Rect div(200, 100, 200, 150);
+ gfx::Point double_tap_point(div.x() + 50, div.y() + 50);
float scale;
// Test double tap scale bounds.
@@ -3616,7 +3620,7 @@ TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_scale_bounds_check_for_auto_zoom_test.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
web_view_helper.GetWebView()->SetMaximumLegibleScale(1.f);
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
@@ -3631,8 +3635,8 @@ TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) {
->GetSettings()
.SetAccessibilityFontScaleFactor(accessibility_font_scale_factor);
- WebRect div(200, 100, 200, 150);
- gfx::Point double_tap_point(div.x + 50, div.y + 50);
+ gfx::Rect div(200, 100, 200, 150);
+ gfx::Point double_tap_point(div.x() + 50, div.y() + 50);
float scale;
// Test double tap scale bounds.
@@ -3737,7 +3741,7 @@ TEST_F(WebFrameTest, BlockBoundTest) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "block_bound.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(300, 300));
IntRect rect_back = IntRect(0, 0, 200, 200);
@@ -3859,8 +3863,8 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTest) {
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- WebRect edit_box_with_text(200, 200, 250, 20);
- WebRect edit_box_with_no_text(200, 250, 250, 20);
+ gfx::Rect edit_box_with_text(200, 200, 250, 20);
+ gfx::Rect edit_box_with_no_text(200, 250, 250, 20);
// Test scrolling the focused node
// The edit box is shorter and narrower than the viewport when legible.
@@ -3893,10 +3897,11 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTest) {
need_animation);
EXPECT_TRUE(need_animation);
// The edit box should be left aligned with a margin for possible label.
- int h_scroll = edit_box_with_text.x - left_box_ratio * viewport_width / scale;
+ int h_scroll =
+ edit_box_with_text.x() - left_box_ratio * viewport_width / scale;
EXPECT_NEAR(h_scroll, scroll.X(), 2);
- int v_scroll = edit_box_with_text.y -
- (viewport_height / scale - edit_box_with_text.height) / 2;
+ int v_scroll = edit_box_with_text.y() -
+ (viewport_height / scale - edit_box_with_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 2);
EXPECT_NEAR(min_readable_caret_height / caret.height(), scale, 0.1);
@@ -3929,10 +3934,10 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTest) {
need_animation);
EXPECT_TRUE(need_animation);
// The edit box should be left aligned.
- h_scroll = edit_box_with_no_text.x;
+ h_scroll = edit_box_with_no_text.x();
EXPECT_NEAR(h_scroll, scroll.X(), 2);
- v_scroll = edit_box_with_no_text.y -
- (viewport_height / scale - edit_box_with_no_text.height) / 2;
+ v_scroll = edit_box_with_no_text.y() -
+ (viewport_height / scale - edit_box_with_no_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 2);
EXPECT_NEAR(min_readable_caret_height / caret.height(), scale, 0.1);
@@ -3971,7 +3976,7 @@ TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest) {
web_view_helper.Resize(gfx::Size(kViewportWidth, kViewportHeight));
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- const WebRect edit_box_with_text(200, 200, 250, 20);
+ const gfx::Rect edit_box_with_text(200, 200, 250, 20);
web_view_helper.GetWebView()->AdvanceFocus(false);
// Set the caret to the begining of the input box.
@@ -4002,10 +4007,10 @@ TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest) {
need_animation);
EXPECT_TRUE(need_animation);
// Edit box and caret should be left alinged
- int h_scroll = edit_box_with_text.x;
+ int h_scroll = edit_box_with_text.x();
EXPECT_NEAR(h_scroll, scroll.X(), 1);
- int v_scroll = edit_box_with_text.y -
- (kViewportHeight / scale - edit_box_with_text.height) / 2;
+ int v_scroll = edit_box_with_text.y() -
+ (kViewportHeight / scale - edit_box_with_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 1);
// Page scale have to be unchanged
EXPECT_EQ(new_scale, scale);
@@ -4023,8 +4028,8 @@ TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest) {
EXPECT_TRUE(need_animation);
// Horizontal scroll have to be the same
EXPECT_NEAR(h_scroll, scroll.X(), 1);
- v_scroll = edit_box_with_text.y -
- (kViewportHeight / scale - edit_box_with_text.height) / 2;
+ v_scroll = edit_box_with_text.y() -
+ (kViewportHeight / scale - edit_box_with_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 1);
// Page scale have to be unchanged
EXPECT_EQ(new_scale, scale);
@@ -4052,7 +4057,7 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTestZoomToLegibleScaleDisabled) {
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- WebRect edit_box_with_no_text(200, 250, 250, 20);
+ gfx::Rect edit_box_with_no_text(200, 250, 250, 20);
// Test scrolling the focused node
// Since we're zoomed out, the caret is considered too small to be legible and
@@ -4083,10 +4088,10 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTestZoomToLegibleScaleDisabled) {
// The edit box should be left aligned with a margin for possible label.
EXPECT_TRUE(need_animation);
int h_scroll =
- edit_box_with_no_text.x - left_box_ratio * viewport_width / scale;
+ edit_box_with_no_text.x() - left_box_ratio * viewport_width / scale;
EXPECT_NEAR(h_scroll, scroll.X(), 2);
- int v_scroll = edit_box_with_no_text.y -
- (viewport_height / scale - edit_box_with_no_text.height) / 2;
+ int v_scroll = edit_box_with_no_text.y() -
+ (viewport_height / scale - edit_box_with_no_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 2);
SetScaleAndScrollAndLayout(web_view_helper.GetWebView(), scroll, scale);
@@ -4121,7 +4126,7 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTestWithDeviceScaleFactor) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "get_scale_for_zoom_into_editable_test.html", nullptr,
- nullptr, nullptr, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
web_view_helper.GetWebView()
->GetPage()
->GetSettings()
@@ -4133,8 +4138,9 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTestWithDeviceScaleFactor) {
web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
- WebRect edit_box_with_text(200 * kDeviceScaleFactor, 200 * kDeviceScaleFactor,
- 250 * kDeviceScaleFactor, 20 * kDeviceScaleFactor);
+ gfx::Rect edit_box_with_text(
+ 200 * kDeviceScaleFactor, 200 * kDeviceScaleFactor,
+ 250 * kDeviceScaleFactor, 20 * kDeviceScaleFactor);
web_view_helper.GetWebView()->AdvanceFocus(false);
// Set the page scale to be smaller than the minimal readable scale.
@@ -4154,10 +4160,10 @@ TEST_F(WebFrameTest, DivScrollIntoEditableTestWithDeviceScaleFactor) {
need_animation);
EXPECT_TRUE(need_animation);
// The edit box wider than the viewport when legible should be left aligned.
- int h_scroll = edit_box_with_text.x;
+ int h_scroll = edit_box_with_text.x();
EXPECT_NEAR(h_scroll, scroll.X(), 2);
- int v_scroll = edit_box_with_text.y -
- (viewport_height / scale - edit_box_with_text.height) / 2;
+ int v_scroll = edit_box_with_text.y() -
+ (viewport_height / scale - edit_box_with_text.height()) / 2;
EXPECT_NEAR(v_scroll, scroll.Y(), 2);
EXPECT_NEAR(min_readable_caret_height / caret_bounds.Height(), scale, 0.1);
}
@@ -4172,7 +4178,7 @@ TEST_F(WebFrameTest, FirstRectForCharacterRangeWithPinchZoom) {
WebLocalFrame* main_frame = web_view_helper.LocalMainFrame();
main_frame->ExecuteScript(WebScriptSource("selectRange();"));
- WebRect old_rect;
+ gfx::Rect old_rect;
main_frame->FirstRectForCharacterRange(0, 5, old_rect);
gfx::PointF visual_offset(100, 130);
@@ -4180,13 +4186,13 @@ TEST_F(WebFrameTest, FirstRectForCharacterRangeWithPinchZoom) {
web_view_helper.GetWebView()->SetPageScaleFactor(scale);
web_view_helper.GetWebView()->SetVisualViewportOffset(visual_offset);
- WebRect rect;
+ gfx::Rect rect;
main_frame->FirstRectForCharacterRange(0, 5, rect);
- EXPECT_EQ((old_rect.x - visual_offset.x()) * scale, rect.x);
- EXPECT_EQ((old_rect.y - visual_offset.y()) * scale, rect.y);
- EXPECT_EQ(old_rect.width * scale, rect.width);
- EXPECT_EQ(old_rect.height * scale, rect.height);
+ EXPECT_EQ((old_rect.x() - visual_offset.x()) * scale, rect.x());
+ EXPECT_EQ((old_rect.y() - visual_offset.y()) * scale, rect.y());
+ EXPECT_EQ(old_rect.width() * scale, rect.width());
+ EXPECT_EQ(old_rect.height() * scale, rect.height());
}
class TestReloadDoesntRedirectWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
@@ -4224,9 +4230,12 @@ class ClearScrollStateOnCommitWebFrameClient
~ClearScrollStateOnCommitWebFrameClient() override = default;
// frame_test_helpers::TestWebFrameClient:
- void DidCommitNavigation(const WebHistoryItem&,
- WebHistoryCommitType,
- bool) override {
+ void DidCommitNavigation(
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) override {
Frame()->View()->ResetScrollAndScaleState();
}
};
@@ -4264,8 +4273,10 @@ TEST_F(WebFrameTest, ReloadWhileProvisional) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.Initialize();
- WebURLRequest request(ToKURL(base_url_ + "fixed_layout.html"));
- web_view_helper.GetWebView()->MainFrameImpl()->StartNavigation(request);
+ WebLocalFrameImpl* main_frame = web_view_helper.LocalMainFrame();
+ FrameLoadRequest frame_load_request(
+ nullptr, ResourceRequest(ToKURL(base_url_ + "fixed_layout.html")));
+ main_frame->GetFrame()->Loader().StartNavigation(frame_load_request);
// start reload before first request is delivered.
frame_test_helpers::ReloadFrameBypassingCache(
web_view_helper.GetWebView()->MainFrameImpl());
@@ -4439,16 +4450,17 @@ class ContextLifetimeTestWebFrameClient
// WebLocalFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override {
- return CreateLocalChild(*parent, scope,
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
+ return CreateLocalChild(*Frame(), scope,
std::make_unique<ContextLifetimeTestWebFrameClient>(
- create_notifications_, release_notifications_));
+ create_notifications_, release_notifications_),
+ std::move(policy_container_bind_params));
}
void DidCreateScriptContext(v8::Local<v8::Context> context,
@@ -4711,14 +4723,14 @@ TEST_F(WebFrameTest, GetContentAsPlainText) {
// Make sure it comes out OK.
const std::string expected("Foo bar\nbaz");
- WebString text = WebFrameContentDumper::DumpWebViewAsText(
+ WebString text = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
EXPECT_EQ(expected, text.Utf8());
// Try reading the same one with clipping of the text.
const int kLength = 5;
- text = WebFrameContentDumper::DumpWebViewAsText(web_view_helper.GetWebView(),
- kLength);
+ text = TestWebFrameContentDumper::DumpWebViewAsText(
+ web_view_helper.GetWebView(), kLength);
EXPECT_EQ(expected.substr(0, kLength), text.Utf8());
// Now do a new test with a subframe.
@@ -4730,14 +4742,14 @@ TEST_F(WebFrameTest, GetContentAsPlainText) {
ASSERT_TRUE(subframe);
frame_test_helpers::LoadHTMLString(subframe, "sub<p>text", test_url);
- text = WebFrameContentDumper::DumpWebViewAsText(
+ text = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
EXPECT_EQ("Hello world\n\nsub\n\ntext", text.Utf8());
// Get the frame text where the subframe separator falls on the boundary of
// what we'll take. There used to be a crash in this case.
- text = WebFrameContentDumper::DumpWebViewAsText(web_view_helper.GetWebView(),
- 12);
+ text = TestWebFrameContentDumper::DumpWebViewAsText(
+ web_view_helper.GetWebView(), 12);
EXPECT_EQ("Hello world", text.Utf8());
}
@@ -4751,18 +4763,19 @@ TEST_F(WebFrameTest, GetFullHtmlOfPage) {
KURL test_url = ToKURL("about:blank");
frame_test_helpers::LoadHTMLString(frame, kSimpleSource, test_url);
- WebString text = WebFrameContentDumper::DumpWebViewAsText(
+ WebString text = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
EXPECT_EQ("Hello\n\nWorld", text.Utf8());
- const std::string html = WebFrameContentDumper::DumpAsMarkup(frame).Utf8();
+ const std::string html =
+ TestWebFrameContentDumper::DumpAsMarkup(frame).Utf8();
// Load again with the output html.
frame_test_helpers::LoadHTMLString(frame, html, test_url);
- EXPECT_EQ(html, WebFrameContentDumper::DumpAsMarkup(frame).Utf8());
+ EXPECT_EQ(html, TestWebFrameContentDumper::DumpAsMarkup(frame).Utf8());
- text = WebFrameContentDumper::DumpWebViewAsText(
+ text = TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(), std::numeric_limits<size_t>::max());
EXPECT_EQ("Hello\n\nWorld", text.Utf8());
@@ -5916,7 +5929,7 @@ TEST_F(WebFrameTest, SmartClipData) {
"initial;\">Price 10,000,000won</div>";
WebString clip_text;
WebString clip_html;
- WebRect clip_rect;
+ gfx::Rect clip_rect;
RegisterMockedHttpURLLoad("Ahem.ttf");
RegisterMockedHttpURLLoad("smartclip.html");
frame_test_helpers::WebViewHelper web_view_helper;
@@ -5924,7 +5937,7 @@ TEST_F(WebFrameTest, SmartClipData) {
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
web_view_helper.Resize(gfx::Size(500, 500));
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
- WebRect crop_rect(300, 125, 152, 50);
+ gfx::Rect crop_rect(300, 125, 152, 50);
frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
EXPECT_EQ(kExpectedClipText, clip_text);
EXPECT_EQ(kExpectedClipHtml, clip_html);
@@ -5953,7 +5966,7 @@ TEST_F(WebFrameTest, SmartClipDataWithPinchZoom) {
"initial;\">Price 10,000,000won</div>";
WebString clip_text;
WebString clip_html;
- WebRect clip_rect;
+ gfx::Rect clip_rect;
RegisterMockedHttpURLLoad("Ahem.ttf");
RegisterMockedHttpURLLoad("smartclip.html");
frame_test_helpers::WebViewHelper web_view_helper;
@@ -5963,7 +5976,7 @@ TEST_F(WebFrameTest, SmartClipDataWithPinchZoom) {
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
web_view_helper.GetWebView()->SetPageScaleFactor(1.5);
web_view_helper.GetWebView()->SetVisualViewportOffset(gfx::PointF(167, 100));
- WebRect crop_rect(200, 38, 228, 75);
+ gfx::Rect crop_rect(200, 38, 228, 75);
frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
EXPECT_EQ(kExpectedClipText, clip_text);
EXPECT_EQ(kExpectedClipHtml, clip_html);
@@ -5972,7 +5985,7 @@ TEST_F(WebFrameTest, SmartClipDataWithPinchZoom) {
TEST_F(WebFrameTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone) {
WebString clip_text;
WebString clip_html;
- WebRect clip_rect;
+ gfx::Rect clip_rect;
RegisterMockedHttpURLLoad("Ahem.ttf");
RegisterMockedHttpURLLoad("smartclip_user_select_none.html");
frame_test_helpers::WebViewHelper web_view_helper;
@@ -5981,7 +5994,7 @@ TEST_F(WebFrameTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone) {
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
web_view_helper.Resize(gfx::Size(500, 500));
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
- WebRect crop_rect(0, 0, 100, 100);
+ gfx::Rect crop_rect(0, 0, 100, 100);
frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
EXPECT_STREQ("", clip_text.Utf8().c_str());
EXPECT_STREQ("", clip_html.Utf8().c_str());
@@ -5990,7 +6003,7 @@ TEST_F(WebFrameTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone) {
TEST_F(WebFrameTest, SmartClipDoesNotCrashPositionReversed) {
WebString clip_text;
WebString clip_html;
- WebRect clip_rect;
+ gfx::Rect clip_rect;
RegisterMockedHttpURLLoad("Ahem.ttf");
RegisterMockedHttpURLLoad("smartclip_reversed_positions.html");
frame_test_helpers::WebViewHelper web_view_helper;
@@ -6000,7 +6013,7 @@ TEST_F(WebFrameTest, SmartClipDoesNotCrashPositionReversed) {
web_view_helper.Resize(gfx::Size(500, 500));
UpdateAllLifecyclePhases(web_view_helper.GetWebView());
// Left upper corner of the rect will be end position in the DOM hierarchy.
- WebRect crop_rect(30, 110, 400, 250);
+ gfx::Rect crop_rect(30, 110, 400, 250);
// This should not still crash. See crbug.com/589082 for more details.
frame->ExtractSmartClipData(crop_rect, clip_text, clip_html, clip_rect);
}
@@ -6127,13 +6140,16 @@ TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved) {
class CompositedSelectionBoundsTest
: public WebFrameTest,
- private ScopedCompositedSelectionUpdateForTest {
+ public testing::WithParamInterface<bool>,
+ private ScopedCompositedSelectionUpdateForTest,
+ private ScopedCompositeAfterPaintForTest {
protected:
CompositedSelectionBoundsTest()
- : ScopedCompositedSelectionUpdateForTest(true) {
+ : ScopedCompositedSelectionUpdateForTest(true),
+ ScopedCompositeAfterPaintForTest(GetParam()) {
RegisterMockedHttpURLLoad("Ahem.ttf");
- web_view_helper_.Initialize(nullptr, nullptr, &web_widget_client_);
+ web_view_helper_.Initialize(nullptr, nullptr);
web_view_helper_.GetWebView()->GetSettings()->SetDefaultFontSize(12);
web_view_helper_.GetWebView()->SetDefaultPageScaleLimits(1, 1);
web_view_helper_.Resize(gfx::Size(640, 480));
@@ -6146,7 +6162,7 @@ class CompositedSelectionBoundsTest
web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
- cc::LayerTreeHost* layer_tree_host = web_widget_client_.layer_tree_host();
+ cc::LayerTreeHost* layer_tree_host = web_view_helper_.GetLayerTreeHost();
const cc::LayerSelection& selection = layer_tree_host->selection();
ASSERT_EQ(selection, cc::LayerSelection());
@@ -6159,6 +6175,20 @@ class CompositedSelectionBoundsTest
web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
frame_test_helpers::LoadFrame(
web_view_helper_.GetWebView()->MainFrameImpl(), base_url_ + test_file);
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // TODO(crbug.com/1065049) Ensure tapping on selection causes repainting
+ // of selection bounds if handle visible state changed. For now, just
+ // force this during the next paint.
+ WebLocalFrameImpl* frame = web_view_helper_.LocalMainFrame();
+ frame->GetFrame()->Selection().SetHandleVisibleForTesting();
+ for (Frame* child = frame->GetFrame()->FirstChild(); child;
+ child = child->NextSibling()) {
+ if (child->IsLocalFrame())
+ To<LocalFrame>(child)->Selection().SetHandleVisibleForTesting();
+ }
+ }
+
UpdateAllLifecyclePhases(web_view_helper_.GetWebView());
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
@@ -6245,7 +6275,7 @@ class CompositedSelectionBoundsTest
->GetEventHandler()
.HandleGestureEvent(gesture_event);
- cc::LayerTreeHost* layer_tree_host = web_widget_client_.layer_tree_host();
+ cc::LayerTreeHost* layer_tree_host = web_view_helper_.GetLayerTreeHost();
const cc::LayerSelection& selection = layer_tree_host->selection();
ASSERT_NE(selection, cc::LayerSelection());
@@ -6256,10 +6286,9 @@ class CompositedSelectionBoundsTest
v8::Isolate::GetCurrent(),
expected_result.Get(context, 0).ToLocalChecked());
ASSERT_TRUE(layer_owner_node_for_start);
- EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_start)
- ->CcLayer()
- .id(),
- selection.start.layer_id);
+ int id = LayerIdFromNode(layer_tree_host->root_layer(),
+ layer_owner_node_for_start);
+ EXPECT_EQ(selection.start.layer_id, id);
EXPECT_EQ(start_edge_start_in_layer_x, selection.start.edge_start.x());
EXPECT_EQ(start_edge_start_in_layer_y, selection.start.edge_start.y());
@@ -6268,12 +6297,10 @@ class CompositedSelectionBoundsTest
blink::Node* layer_owner_node_for_end = V8Node::ToImplWithTypeCheck(
v8::Isolate::GetCurrent(),
expected_result.Get(context, 5).ToLocalChecked());
-
ASSERT_TRUE(layer_owner_node_for_end);
- EXPECT_EQ(
- GetExpectedLayerForSelection(layer_owner_node_for_end)->CcLayer().id(),
- selection.end.layer_id);
-
+ id = LayerIdFromNode(layer_tree_host->root_layer(),
+ layer_owner_node_for_end);
+ EXPECT_EQ(selection.end.layer_id, id);
EXPECT_EQ(end_edge_start_in_layer_x, selection.end.edge_start.x());
EXPECT_EQ(end_edge_start_in_layer_y, selection.end.edge_start.y());
EXPECT_EQ(end_edge_end_in_layer_x, selection.end.edge_end.x());
@@ -6321,7 +6348,7 @@ class CompositedSelectionBoundsTest
RunTest(test_file);
}
- GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) const {
+ static GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) {
CompositedLayerMapping* clm = node->GetLayoutObject()
->EnclosingLayer()
->EnclosingLayerForPaintInvalidation()
@@ -6333,71 +6360,123 @@ class CompositedSelectionBoundsTest
: clm->MainGraphicsLayer();
}
- frame_test_helpers::TestWebWidgetClient web_widget_client_;
+ static int LayerIdFromNode(cc::Layer* root_layer, blink::Node* node) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ return GetExpectedLayerForSelection(node)->CcLayer().id();
+ } else {
+ Vector<const cc::Layer*> layers;
+ if (node->IsDocumentNode()) {
+ layers = CcLayersByName(root_layer,
+ "Scrolling background of LayoutView #document");
+ } else {
+ DCHECK(node->IsElementNode());
+ layers = CcLayersByDOMElementId(root_layer,
+ To<Element>(node)->GetIdAttribute());
+ }
+
+ EXPECT_EQ(layers.size(), 1u);
+ return layers[0]->id();
+ }
+ }
+
frame_test_helpers::WebViewHelper web_view_helper_;
};
-TEST_F(CompositedSelectionBoundsTest, None) {
+TEST_P(CompositedSelectionBoundsTest, None) {
RunTestWithNoSelection("composited_selection_bounds_none.html");
}
-TEST_F(CompositedSelectionBoundsTest, NoneReadonlyCaret) {
+TEST_P(CompositedSelectionBoundsTest, NoneReadonlyCaret) {
RunTestWithNoSelection(
"composited_selection_bounds_none_readonly_caret.html");
}
-TEST_F(CompositedSelectionBoundsTest, DetachedFrame) {
+TEST_P(CompositedSelectionBoundsTest, DetachedFrame) {
RunTestWithNoSelection("composited_selection_bounds_detached_frame.html");
}
-TEST_F(CompositedSelectionBoundsTest, Basic) {
+TEST_P(CompositedSelectionBoundsTest, Basic) {
RunTest("composited_selection_bounds_basic.html");
}
-TEST_F(CompositedSelectionBoundsTest, Transformed) {
+TEST_P(CompositedSelectionBoundsTest, Transformed) {
RunTest("composited_selection_bounds_transformed.html");
}
-TEST_F(CompositedSelectionBoundsTest, VerticalRightToLeft) {
+TEST_P(CompositedSelectionBoundsTest, VerticalRightToLeft) {
RunTest("composited_selection_bounds_vertical_rl.html");
}
-TEST_F(CompositedSelectionBoundsTest, VerticalLeftToRight) {
+TEST_P(CompositedSelectionBoundsTest, VerticalLeftToRight) {
RunTest("composited_selection_bounds_vertical_lr.html");
}
-TEST_F(CompositedSelectionBoundsTest, SplitLayer) {
+TEST_P(CompositedSelectionBoundsTest, BasicRTL) {
+ RunTest("composited_selection_bounds_basic_rtl.html");
+}
+TEST_P(CompositedSelectionBoundsTest, VerticalRightToLeftRTL) {
+ RunTest("composited_selection_bounds_vertical_rl_rtl.html");
+}
+TEST_P(CompositedSelectionBoundsTest, VerticalLeftToRightRTL) {
+ RunTest("composited_selection_bounds_vertical_lr_rtl.html");
+}
+TEST_P(CompositedSelectionBoundsTest, SplitLayer) {
RunTest("composited_selection_bounds_split_layer.html");
}
-TEST_F(CompositedSelectionBoundsTest, Iframe) {
+TEST_P(CompositedSelectionBoundsTest, Iframe) {
RunTestWithMultipleFiles("composited_selection_bounds_iframe.html",
{"composited_selection_bounds_basic.html"});
}
-TEST_F(CompositedSelectionBoundsTest, Editable) {
+TEST_P(CompositedSelectionBoundsTest, Editable) {
RunTest("composited_selection_bounds_editable.html");
}
-TEST_F(CompositedSelectionBoundsTest, EditableDiv) {
+TEST_P(CompositedSelectionBoundsTest, EditableDiv) {
RunTest("composited_selection_bounds_editable_div.html");
}
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#if !defined(OS_ANDROID)
-TEST_F(CompositedSelectionBoundsTest, Input) {
+TEST_P(CompositedSelectionBoundsTest, Input) {
+ // This test does not yet pass in CAP due to handling of
+ // LayerSelectionBound::hidden
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
RunTest("composited_selection_bounds_input.html");
}
-TEST_F(CompositedSelectionBoundsTest, InputScrolled) {
+TEST_P(CompositedSelectionBoundsTest, InputScrolled) {
+ // This test does not yet pass in CAP due to handling of
+ // LayerSelectionBound::hidden
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
RunTest("composited_selection_bounds_input_scrolled.html");
}
#endif
#endif
+struct CompositedSelectionBoundsTestPassToString {
+ std::string operator()(const testing::TestParamInfo<bool> b) const {
+ return b.param ? "CAP" : "NonCAP";
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ CompositedSelectionBoundsTest,
+ testing::Bool(),
+ CompositedSelectionBoundsTestPassToString());
+
class TestWillInsertBodyWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- TestWillInsertBodyWebFrameClient() : did_load_(false) {}
- ~TestWillInsertBodyWebFrameClient() override = default;
+ TestWillInsertBodyWebFrameClient() = default;
+ ~TestWillInsertBodyWebFrameClient() final = default;
+
+ bool did_load() const { return did_load_; }
// frame_test_helpers::TestWebFrameClient:
- void DidCommitNavigation(const WebHistoryItem&,
- WebHistoryCommitType,
- bool) override {
+ void DidCommitNavigation(
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) final {
did_load_ = true;
}
- bool did_load_;
+ private:
+ bool did_load_ = false;
};
TEST_F(WebFrameTest, HTMLDocument) {
@@ -6408,7 +6487,7 @@ TEST_F(WebFrameTest, HTMLDocument) {
web_view_helper.InitializeAndLoad(base_url_ + "clipped-body.html",
&web_frame_client);
- EXPECT_TRUE(web_frame_client.did_load_);
+ EXPECT_TRUE(web_frame_client.did_load());
}
TEST_F(WebFrameTest, EmptyDocument) {
@@ -6418,7 +6497,7 @@ TEST_F(WebFrameTest, EmptyDocument) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.Initialize(&web_frame_client);
- EXPECT_FALSE(web_frame_client.did_load_);
+ EXPECT_FALSE(web_frame_client.did_load());
}
TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection) {
@@ -6496,7 +6575,7 @@ TEST_F(WebFrameTest, ReplaceMisspelledRange) {
DocumentMarker::MarkerTypes::Spelling()));
frame->ReplaceMisspelledRange("welcome");
- EXPECT_EQ("_welcome_.", WebFrameContentDumper::DumpWebViewAsText(
+ EXPECT_EQ("_welcome_.", TestWebFrameContentDumper::DumpWebViewAsText(
web_view_helper.GetWebView(),
std::numeric_limits<size_t>::max())
.Utf8());
@@ -7080,9 +7159,9 @@ class TestNewWindowWebViewClient
const WebString&,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) override {
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) override {
EXPECT_TRUE(false);
return nullptr;
}
@@ -7137,7 +7216,8 @@ TEST_F(WebFrameTest, ModifiedClickNewWindow) {
MouseEvent::Create(nullptr, event_type_names::kClick, mouse_initializer);
FrameLoadRequest frame_request(window, ResourceRequest(destination));
frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(event));
- frame_request.SetTriggeringEventInfo(TriggeringEventInfo::kFromTrustedEvent);
+ frame_request.SetTriggeringEventInfo(
+ mojom::blink::TriggeringEventInfo::kFromTrustedEvent);
LocalFrame::NotifyUserActivation(
frame, mojom::UserActivationNotificationType::kTest);
web_frame_client.IgnoreNavigations();
@@ -7200,8 +7280,9 @@ TEST_F(WebFrameTest, ReloadPost) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "reload_post.html", &client);
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
+ auto* main_frame = web_view_helper.GetWebView()->MainFrameImpl();
- frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
+ frame_test_helpers::LoadFrame(main_frame,
"javascript:document.forms[0].submit()");
// Pump requests one more time after the javascript URL has executed to
// trigger the actual POST load request.
@@ -7233,17 +7314,18 @@ class TestCachePolicyWebFrameClient
// frame_test_helpers::TestWebFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString&,
const WebString&,
const FramePolicy&,
const WebFrameOwnerProperties& frame_owner_properties,
- mojom::blink::FrameOwnerElementType) override {
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
auto child = std::make_unique<TestCachePolicyWebFrameClient>();
auto* child_ptr = child.get();
child_clients_.push_back(std::move(child));
- return CreateLocalChild(*parent, scope, child_ptr);
+ return CreateLocalChild(*Frame(), scope, child_ptr,
+ std::move(policy_container_bind_params));
}
void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
cache_mode_ = info->url_request.GetCacheMode();
@@ -7342,14 +7424,14 @@ class TestMainFrameIntersectionChanged
// frame_test_helpers::TestWebFrameClient:
void OnMainFrameIntersectionChanged(
- const WebRect& intersection_rect) override {
+ const gfx::Rect& intersection_rect) override {
main_frame_intersection_ = intersection_rect;
}
- WebRect MainFrameIntersection() const { return main_frame_intersection_; }
+ gfx::Rect MainFrameIntersection() const { return main_frame_intersection_; }
private:
- WebRect main_frame_intersection_;
+ gfx::Rect main_frame_intersection_;
};
TEST_F(WebFrameTest, MainFrameIntersectionChanged) {
@@ -7357,9 +7439,9 @@ TEST_F(WebFrameTest, MainFrameIntersectionChanged) {
frame_test_helpers::WebViewHelper helper;
helper.InitializeRemote();
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
- *helper.RemoteMainFrame(), "frameName", WebFrameOwnerProperties(),
- nullptr, &client);
+ WebLocalFrameImpl* local_frame =
+ helper.CreateLocalChild(*helper.RemoteMainFrame(), "frameName",
+ WebFrameOwnerProperties(), nullptr, &client);
WebFrameWidget* widget = local_frame->FrameWidget();
ASSERT_TRUE(widget);
@@ -7371,12 +7453,12 @@ TEST_F(WebFrameTest, MainFrameIntersectionChanged) {
gfx::Transform transform;
transform.Translate(100, 100);
- auto intersection_state = blink::mojom::blink::ViewportIntersectionState(
+ auto intersection_state = blink::mojom::blink::ViewportIntersectionState::New(
viewport_intersection, mainframe_intersection, gfx::Rect(),
occlusion_state, gfx::Size(), gfx::Point(), transform);
- static_cast<WebFrameWidgetBase*>(widget)->SetRemoteViewportIntersection(
- intersection_state);
- EXPECT_EQ(client.MainFrameIntersection(), blink::WebRect(100, 100, 200, 140));
+ static_cast<WebFrameWidgetImpl*>(widget)->ApplyViewportIntersectionForTesting(
+ std::move(intersection_state));
+ EXPECT_EQ(client.MainFrameIntersection(), gfx::Rect(100, 100, 200, 140));
}
class TestSameDocumentWithImageWebFrameClient
@@ -7407,7 +7489,7 @@ TEST_F(WebFrameTest, NavigateToSameNoConditionalRequestForSubresource) {
TestSameDocumentWithImageWebFrameClient client;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "foo_with_image.html", &client,
- nullptr, nullptr,
+ nullptr,
&ConfigureLoadsImagesAutomatically);
WebCache::Clear();
@@ -7554,7 +7636,9 @@ TEST_F(WebFrameTest, IPAddressSpace) {
params->navigation_timings.navigation_start = base::TimeTicks::Now();
params->navigation_timings.fetch_start = base::TimeTicks::Now();
params->is_browser_initiated = true;
- params->ip_address_space = value;
+ params->policy_container = std::make_unique<WebPolicyContainer>(
+ WebPolicyContainerPolicies(), mojo::NullAssociatedRemote());
+ params->policy_container->policies.ip_address_space = value;
web_view_helper.LocalMainFrame()->CommitNavigation(std::move(params),
nullptr);
frame_test_helpers::PumpPendingRequestsForFrameToLoad(
@@ -7574,9 +7658,10 @@ class TestDidNavigateCommitTypeWebFrameClient
~TestDidNavigateCommitTypeWebFrameClient() override = default;
// frame_test_helpers::TestWebFrameClient:
- void DidFinishSameDocumentNavigation(const WebHistoryItem&,
- WebHistoryCommitType type,
- bool content_initiated) override {
+ void DidFinishSameDocumentNavigation(
+ WebHistoryCommitType type,
+ bool content_initiated,
+ bool is_history_api_navigation) override {
last_commit_type_ = type;
}
@@ -7599,8 +7684,9 @@ TEST_F(WebFrameTest, SameDocumentHistoryNavigationCommitType) {
local_frame->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
item->Url(), WebFrameLoadType::kBackForward, item.Get(),
- ClientRedirectPolicy::kNotClientRedirect, nullptr, /* origin_document */
- false, /* has_event */
+ ClientRedirectPolicy::kNotClientRedirect,
+ false /* has_transient_user_activation */, nullptr, /* origin_document */
+ false, /* has_event */
nullptr /* extra_data */);
EXPECT_EQ(kWebBackForwardCommit, client.LastCommitType());
}
@@ -7662,10 +7748,8 @@ TEST_F(WebFrameTest, FirstNonBlankSubframeNavigation) {
// Test verifies that layout will change a layer's scrollable attibutes
TEST_F(WebFrameTest, overflowHiddenRewrite) {
RegisterMockedHttpURLLoad("non-scrollable.html");
- FixedLayoutTestWebWidgetClient client;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, &client,
- &ConfigureCompositingWebView);
+ web_view_helper.Initialize(nullptr, nullptr, &ConfigureCompositingWebView);
web_view_helper.Resize(gfx::Size(100, 100));
frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
@@ -7701,15 +7785,14 @@ TEST_F(WebFrameTest, CurrentHistoryItem) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.Initialize();
- WebLocalFrame* frame = web_view_helper.GetWebView()->MainFrameImpl();
- const FrameLoader& main_frame_loader =
+ FrameLoader& main_frame_loader =
web_view_helper.LocalMainFrame()->GetFrame()->Loader();
- WebURLRequest request(ToKURL(url));
// Before navigation, there is no history item.
EXPECT_FALSE(main_frame_loader.GetDocumentLoader()->GetHistoryItem());
- frame->StartNavigation(request);
+ FrameLoadRequest frame_load_request(nullptr, ResourceRequest(ToKURL(url)));
+ main_frame_loader.StartNavigation(frame_load_request);
frame_test_helpers::PumpPendingRequestsForFrameToLoad(
web_view_helper.LocalMainFrame());
@@ -7726,13 +7809,13 @@ class FailCreateChildFrame : public frame_test_helpers::TestWebFrameClient {
// frame_test_helpers::TestWebFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties& frame_owner_properties,
- mojom::blink::FrameOwnerElementType) override {
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
++call_count_;
return nullptr;
}
@@ -7759,7 +7842,7 @@ TEST_F(WebFrameTest, fixedPositionInFixedViewport) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "fixed-position-in-fixed-viewport.html", nullptr, nullptr,
- nullptr, ConfigureAndroid);
+ ConfigureAndroid);
WebViewImpl* web_view = web_view_helper.GetWebView();
web_view_helper.Resize(gfx::Size(100, 100));
@@ -7796,11 +7879,10 @@ TEST_F(WebFrameTest, FrameViewMoveWithSetFrameRect) {
}
TEST_F(WebFrameTest, FrameViewScrollAccountsForBrowserControls) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("long_scroll.html");
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "long_scroll.html", nullptr,
- nullptr, &client, ConfigureAndroid);
+ nullptr, ConfigureAndroid);
WebViewImpl* web_view = web_view_helper.GetWebView();
LocalFrameView* frame_view = web_view_helper.LocalMainFrame()->GetFrameView();
@@ -7887,15 +7969,12 @@ TEST_F(WebFrameTest, FrameViewScrollAccountsForBrowserControls) {
TEST_F(WebFrameTest, MaximumScrollPositionCanBeNegative) {
RegisterMockedHttpURLLoad("rtl-overview-mode.html");
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.device_scale_factor = 1;
int viewport_width = 640;
int viewport_height = 480;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "rtl-overview-mode.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.GetWebView()->SetInitialPageScaleOverride(-1);
web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
true);
@@ -7910,15 +7989,14 @@ TEST_F(WebFrameTest, MaximumScrollPositionCanBeNegative) {
}
TEST_F(WebFrameTest, FullscreenLayerSize) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("fullscreen_div.html");
- frame_test_helpers::WebViewHelper web_view_helper;
int viewport_width = 640;
int viewport_height = 480;
- client.screen_info_.rect = gfx::Rect(viewport_width, viewport_height);
+
+ frame_test_helpers::WebViewHelper web_view_helper;
+ // client.screen_info_.rect = gfx::Rect(viewport_width, viewport_height);
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "fullscreen_div.html", nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
UpdateAllLifecyclePhases(web_view_impl);
@@ -7941,7 +8019,7 @@ TEST_F(WebFrameTest, FullscreenLayerSize) {
EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalHeight().ToInt());
// Verify it's updated after a device rotation.
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_height,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_height,
viewport_width);
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalWidth().ToInt());
@@ -7949,14 +8027,12 @@ TEST_F(WebFrameTest, FullscreenLayerSize) {
}
TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("fullscreen_div.html");
frame_test_helpers::WebViewHelper web_view_helper;
int viewport_width = 640;
int viewport_height = 480;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "fullscreen_div.html", nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
UpdateAllLifecyclePhases(web_view_impl);
@@ -8007,14 +8083,12 @@ TEST_F(WebFrameTest, FullscreenLayerNonScrollable) {
}
TEST_F(WebFrameTest, FullscreenMainFrame) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("fullscreen_div.html");
frame_test_helpers::WebViewHelper web_view_helper;
int viewport_width = 640;
int viewport_height = 480;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_div.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "fullscreen_div.html", nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
UpdateAllLifecyclePhases(web_view_impl);
@@ -8062,16 +8136,14 @@ TEST_F(WebFrameTest, FullscreenMainFrame) {
}
TEST_F(WebFrameTest, FullscreenSubframe) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("fullscreen_iframe.html");
RegisterMockedHttpURLLoad("fullscreen_div.html");
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_iframe.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "fullscreen_iframe.html", nullptr, nullptr, ConfigureAndroid);
int viewport_width = 640;
int viewport_height = 480;
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_width,
viewport_height);
UpdateAllLifecyclePhases(web_view_impl);
@@ -8094,7 +8166,7 @@ TEST_F(WebFrameTest, FullscreenSubframe) {
EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalHeight().ToInt());
// Verify it's updated after a device rotation.
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_height,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_height,
viewport_width);
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(viewport_height, fullscreen_layout_object->LogicalWidth().ToInt());
@@ -8148,15 +8220,13 @@ TEST_F(WebFrameTest, FullscreenNestedExit) {
}
TEST_F(WebFrameTest, FullscreenWithTinyViewport) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("viewport-tiny.html");
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-tiny.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "viewport-tiny.html", nullptr, nullptr, ConfigureAndroid);
int viewport_width = 384;
int viewport_height = 640;
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_width,
viewport_height);
UpdateAllLifecyclePhases(web_view_impl);
@@ -8192,15 +8262,13 @@ TEST_F(WebFrameTest, FullscreenWithTinyViewport) {
}
TEST_F(WebFrameTest, FullscreenResizeWithTinyViewport) {
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("viewport-tiny.html");
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-tiny.html", nullptr, nullptr, &client,
- ConfigureAndroid);
+ base_url_ + "viewport-tiny.html", nullptr, nullptr, ConfigureAndroid);
int viewport_width = 384;
int viewport_height = 640;
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_width,
viewport_height);
UpdateAllLifecyclePhases(web_view_impl);
@@ -8222,7 +8290,7 @@ TEST_F(WebFrameTest, FullscreenResizeWithTinyViewport) {
viewport_width = 640;
viewport_height = 384;
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, viewport_width,
+ UpdateScreenInfoAndResizeView(&web_view_helper, viewport_width,
viewport_height);
UpdateAllLifecyclePhases(web_view_impl);
EXPECT_EQ(640, layout_view->LogicalWidth().Floor());
@@ -8249,15 +8317,13 @@ TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
WebSize screen_size_minus_status_bars(598, 359);
WebSize screen_size(640, 384);
- FixedLayoutTestWebWidgetClient client;
RegisterMockedHttpURLLoad("fullscreen_restore_scale_factor.html");
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
base_url_ + "fullscreen_restore_scale_factor.html", nullptr, nullptr,
- &client, &ConfigureAndroid);
+ &ConfigureAndroid);
UpdateScreenInfoAndResizeView(
- &client, &web_view_helper,
- screen_size_minus_status_bars_minus_url_bar.width,
+ &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width,
screen_size_minus_status_bars_minus_url_bar.height);
auto* layout_view = web_view_helper.GetWebView()
->MainFrameImpl()
@@ -8280,10 +8346,10 @@ TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
web_view_impl->DidEnterFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
+ UpdateScreenInfoAndResizeView(&web_view_helper,
screen_size_minus_status_bars.width,
screen_size_minus_status_bars.height);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper, screen_size.width,
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_size.width,
screen_size.height);
EXPECT_EQ(screen_size.width, layout_view->LogicalWidth().Floor());
EXPECT_EQ(screen_size.height, layout_view->LogicalHeight().Floor());
@@ -8293,12 +8359,11 @@ TEST_F(WebFrameTest, FullscreenRestoreScaleFactorUponExiting) {
web_view_impl->DidExitFullscreen();
UpdateAllLifecyclePhases(web_view_impl);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
+ UpdateScreenInfoAndResizeView(&web_view_helper,
screen_size_minus_status_bars.width,
screen_size_minus_status_bars.height);
UpdateScreenInfoAndResizeView(
- &client, &web_view_helper,
- screen_size_minus_status_bars_minus_url_bar.width,
+ &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width,
screen_size_minus_status_bars_minus_url_bar.height);
EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width,
layout_view->LogicalWidth().Floor());
@@ -8318,8 +8383,7 @@ TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
int viewport_height = 200;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "viewport-tiny.html", nullptr, nullptr, nullptr,
- ConfigureAndroid);
+ base_url_ + "viewport-tiny.html", nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(viewport_width, viewport_height));
UpdateAllLifecyclePhases(web_view_impl);
@@ -8369,19 +8433,16 @@ TEST_F(WebFrameTest, ClearFullscreenConstraintsOnNavigation) {
TEST_F(WebFrameTest, OverlayFullscreenVideo) {
ScopedForceOverlayFullscreenVideoForTest force_overlay_fullscreen_video(true);
RegisterMockedHttpURLLoad("fullscreen_video.html");
- frame_test_helpers::TestWebWidgetClient web_widget_client;
frame_test_helpers::WebViewHelper web_view_helper;
- WebViewImpl* web_view_impl =
- web_view_helper.InitializeAndLoad(base_url_ + "fullscreen_video.html",
- nullptr, nullptr, &web_widget_client);
+ WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
+ base_url_ + "fullscreen_video.html", nullptr, nullptr);
// Ensure that the local frame view has a paint artifact compositor. It's
// created lazily, and doing so after entering fullscreen would undo the
// overlay video layer modification.
UpdateAllLifecyclePhases(web_view_impl);
- const cc::LayerTreeHost* layer_tree_host =
- web_widget_client.layer_tree_host();
+ const cc::LayerTreeHost* layer_tree_host = web_view_helper.GetLayerTreeHost();
LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
LocalFrame::NotifyUserActivation(
@@ -8426,14 +8487,11 @@ TEST_F(WebFrameTest, OverlayFullscreenVideoInIframe) {
ScopedForceOverlayFullscreenVideoForTest force_overlay_fullscreen_video(true);
RegisterMockedHttpURLLoad("fullscreen_video_in_iframe.html");
RegisterMockedHttpURLLoad("fullscreen_video.html");
- frame_test_helpers::TestWebWidgetClient web_widget_client;
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "fullscreen_video_in_iframe.html", nullptr, nullptr,
- &web_widget_client);
+ base_url_ + "fullscreen_video_in_iframe.html", nullptr, nullptr);
- const cc::LayerTreeHost* layer_tree_host =
- web_widget_client.layer_tree_host();
+ const cc::LayerTreeHost* layer_tree_host = web_view_helper.GetLayerTreeHost();
LocalFrame* iframe =
To<WebLocalFrameImpl>(
web_view_helper.GetWebView()->MainFrame()->FirstChild())
@@ -8461,10 +8519,9 @@ TEST_F(WebFrameTest, OverlayFullscreenVideoInIframe) {
TEST_F(WebFrameTest, WebXrImmersiveOverlay) {
RegisterMockedHttpURLLoad("webxr_overlay.html");
- frame_test_helpers::TestWebWidgetClient web_widget_client;
frame_test_helpers::WebViewHelper web_view_helper;
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "webxr_overlay.html", nullptr, nullptr, &web_widget_client);
+ base_url_ + "webxr_overlay.html", nullptr, nullptr);
web_view_helper.Resize(gfx::Size(640, 480));
// Ensure that the local frame view has a paint artifact compositor. It's
@@ -8472,8 +8529,7 @@ TEST_F(WebFrameTest, WebXrImmersiveOverlay) {
// overlay layer modification.
UpdateAllLifecyclePhases(web_view_impl);
- const cc::LayerTreeHost* layer_tree_host =
- web_widget_client.layer_tree_host();
+ const cc::LayerTreeHost* layer_tree_host = web_view_helper.GetLayerTreeHost();
LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
Document* document = frame->GetDocument();
@@ -8533,6 +8589,32 @@ TEST_F(WebFrameTest, WebXrImmersiveOverlay) {
EXPECT_EQ(1u, CcLayersByDOMElementId(root_layer, "inner").size());
}
+TEST_F(WebFrameTest, FullscreenFrameSet) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
+ "data:text/html,<frameset id=frameset></frameset>", nullptr, nullptr);
+ web_view_helper.Resize(gfx::Size(640, 480));
+ UpdateAllLifecyclePhases(web_view_impl);
+
+ LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
+ Document* document = frame->GetDocument();
+ LocalFrame::NotifyUserActivation(
+ frame, mojom::UserActivationNotificationType::kTest);
+ Element* frameset = document->getElementById("frameset");
+ Fullscreen::RequestFullscreen(*frameset);
+ EXPECT_EQ(nullptr, Fullscreen::FullscreenElementFrom(*document));
+ web_view_impl->DidEnterFullscreen();
+ EXPECT_EQ(frameset, Fullscreen::FullscreenElementFrom(*document));
+ UpdateAllLifecyclePhases(web_view_impl);
+ EXPECT_EQ(frameset, Fullscreen::FullscreenElementFrom(*document));
+
+ // Verify that the element is in the top layer, attached to the LayoutView.
+ EXPECT_TRUE(frameset->IsInTopLayer());
+ auto* fullscreen_layout_object = To<LayoutBox>(frameset->GetLayoutObject());
+ ASSERT_TRUE(fullscreen_layout_object);
+ EXPECT_EQ(fullscreen_layout_object->Parent(), document->GetLayoutView());
+}
+
TEST_F(WebFrameTest, LayoutBlockPercentHeightDescendants) {
RegisterMockedHttpURLLoad("percent-height-descendants.html");
frame_test_helpers::WebViewHelper web_view_helper;
@@ -8758,8 +8840,7 @@ TEST_F(WebFrameTest, PrintingBasic)
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
WebPrintParams print_params;
- print_params.print_content_area.width = 500;
- print_params.print_content_area.height = 500;
+ print_params.print_content_area.set_size(gfx::Size(500, 500));
uint32_t page_count = frame->PrintBegin(print_params, WebNode());
EXPECT_EQ(1u, page_count);
@@ -8841,7 +8922,7 @@ TEST_F(WebFrameTest, EmbedderTriggeredDetachWithRemoteMainFrame) {
frame_test_helpers::WebViewHelper helper;
helper.InitializeRemote();
WebLocalFrame* child_frame =
- frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
+ helper.CreateLocalChild(*helper.RemoteMainFrame());
// Purposely keep the LocalFrame alive so it's the last thing to be destroyed.
Persistent<Frame> child_core_frame = WebFrame::ToCoreFrame(*child_frame);
@@ -8859,15 +8940,16 @@ class WebFrameSwapTestClient : public frame_test_helpers::TestWebFrameClient {
}
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override {
- return CreateLocalChild(*parent, scope,
- std::make_unique<WebFrameSwapTestClient>(this));
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
+ return CreateLocalChild(*Frame(), scope,
+ std::make_unique<WebFrameSwapTestClient>(this),
+ std::move(policy_container_bind_params));
}
void DidChangeFrameOwnerProperties(
@@ -8890,7 +8972,7 @@ class WebFrameSwapTestClient : public frame_test_helpers::TestWebFrameClient {
// FakeLocalFrameHost:
void DidChangeFrameOwnerProperties(
- const base::UnguessableToken& child_frame_token,
+ const blink::FrameToken& child_frame_token,
mojom::blink::FrameOwnerPropertiesPtr properties) override {
if (parent_)
parent_->DidChangeFrameOwnerProperties(std::move(properties));
@@ -8922,8 +9004,10 @@ class WebFrameSwapTest : public WebFrameTest {
WebLocalFrame* MainFrame() const { return web_view_helper_.LocalMainFrame(); }
WebViewImpl* WebView() const { return web_view_helper_.GetWebView(); }
- private:
+ protected:
frame_test_helpers::WebViewHelper web_view_helper_;
+
+ private:
WebFrameSwapTestClient main_frame_client_;
};
@@ -8932,28 +9016,37 @@ TEST_F(WebFrameSwapTest, SwapMainFrame) {
MainFrame()->Swap(remote_frame);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
- remote_frame->Swap(local_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
- // Finally, make sure an embedder triggered load in the local frame swapped
- // back in works.
+ // Committing a navigation in `local_frame` should swap it back in.
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
- WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
+ TestWebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
EXPECT_EQ("hello", content);
}
+TEST_F(WebFrameSwapTest, SwapMainFrameWithPageScaleReset) {
+ WebView()->SetDefaultPageScaleLimits(1, 2);
+ WebView()->SetPageScaleFactor(1.25);
+ EXPECT_EQ(1.25, WebView()->PageScaleFactor());
+
+ WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
+ MainFrame()->Swap(remote_frame);
+ WebView()->DidAttachRemoteMainFrame();
+ EXPECT_EQ(1.0, WebView()->PageScaleFactor());
+}
+
TEST_F(WebFrameSwapTest, ValidateSizeOnRemoteToLocalMainFrameSwap) {
gfx::Size size(111, 222);
WebRemoteFrame* remote_frame = frame_test_helpers::CreateRemote();
MainFrame()->Swap(remote_frame);
- remote_frame->View()->Resize(size);
+ static_cast<WebViewImpl*>(remote_frame->View())->Resize(size);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
remote_frame->Swap(local_frame);
// Verify that the size that was set with a remote main frame is correct
@@ -8976,7 +9069,7 @@ TEST_F(WebFrameSwapTest,
// Create a provisional main frame frame but don't swap it in yet.
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
WebViewImpl* web_view = static_cast<WebViewImpl*>(local_frame->View());
EXPECT_TRUE(web_view->MainFrame() &&
@@ -9036,6 +9129,34 @@ TEST_F(WebFrameTest, SwapMainFrameWhileLoading) {
&frame_client);
}
+TEST_F(WebFrameTest, SwapChildAddFrameInUnload) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+
+ // This sets up a main frame with one child frame. When the document in the
+ // child frame is unloaded (e.g. due to the `Frame::Swap()` call below), the
+ // unload handler will insert a new <iframe> into the main frame's document.
+ RegisterMockedHttpURLLoad("add-frame-in-unload-main.html");
+ RegisterMockedHttpURLLoad("add-frame-in-unload-subframe.html");
+ web_view_helper.InitializeAndLoad(base_url_ +
+ "add-frame-in-unload-main.html");
+
+ WebLocalFrame* new_frame = web_view_helper.CreateProvisional(
+ *web_view_helper.LocalMainFrame()->FirstChild());
+
+ // This triggers the unload handler in the child frame's Document, mutating
+ // the frame tree during the `Frame::Swap()` call.
+ web_view_helper.LocalMainFrame()->FirstChild()->Swap(new_frame);
+
+ // TODO(dcheng): This is currently required to trigger a crash when the bug is
+ // not fixed. Removing a frame from the frame tree will fail one of the
+ // consistency checks in `Frame::RemoveChild()` if the frame tree is
+ // corrupted. This should be replaced with a test helper that comprehensively
+ // validates that a frame tree is not corrupted: this helper could also be
+ // used to simplify the various SwapAndVerify* helpers below.
+ web_view_helper.LocalMainFrame()->ExecuteScript(
+ WebScriptSource("document.querySelector('iframe').remove()"));
+}
+
void WebFrameTest::SwapAndVerifyFirstChildConsistency(const char* const message,
WebFrame* parent,
WebFrame* new_child) {
@@ -9055,7 +9176,7 @@ TEST_F(WebFrameSwapTest, SwapFirstChild) {
remote_frame);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
SwapAndVerifyFirstChildConsistency("remote->local", MainFrame(), local_frame);
// FIXME: This almost certainly fires more load events on the iframe element
@@ -9064,7 +9185,7 @@ TEST_F(WebFrameSwapTest, SwapFirstChild) {
// back in works.
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
- WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
+ TestWebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
EXPECT_EQ(" \n\nhello\n\nb \n\na\n\nc", content);
}
@@ -9082,7 +9203,7 @@ TEST_F(WebFrameSwapTest, DoNotPropagateDisplayNonePropertyOnSwap) {
EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
remote_frame->Swap(local_frame);
EXPECT_FALSE(main_frame_client->DidPropagateDisplayNoneProperty());
Reset();
@@ -9113,7 +9234,7 @@ TEST_F(WebFrameSwapTest, SwapMiddleChild) {
remote_frame);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
SwapAndVerifyMiddleChildConsistency("remote->local", MainFrame(),
local_frame);
@@ -9123,7 +9244,7 @@ TEST_F(WebFrameSwapTest, SwapMiddleChild) {
// back in works.
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
- WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
+ TestWebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
EXPECT_EQ(" \n\na\n\nhello\n\nc", content);
}
@@ -9145,7 +9266,7 @@ TEST_F(WebFrameSwapTest, SwapLastChild) {
SwapAndVerifyLastChildConsistency("local->remote", MainFrame(), remote_frame);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
SwapAndVerifyLastChildConsistency("remote->local", MainFrame(), local_frame);
// FIXME: This almost certainly fires more load events on the iframe element
@@ -9154,7 +9275,7 @@ TEST_F(WebFrameSwapTest, SwapLastChild) {
// back in works.
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
- WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
+ TestWebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
EXPECT_EQ(" \n\na\n\nb \n\na\n\nhello", content);
}
@@ -9164,7 +9285,7 @@ TEST_F(WebFrameSwapTest, DetachProvisionalFrame) {
remote_frame);
WebLocalFrameImpl* provisional_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
// The provisional frame should have a local frame owner.
FrameOwner* owner = provisional_frame->GetFrame()->Owner();
@@ -9203,8 +9324,8 @@ TEST_F(WebFrameSwapTest, EventsOnDisconnectedSubDocumentSkipped) {
remote_frame->SetReplicatedOrigin(
WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
- WebLocalFrameImpl* local_child = frame_test_helpers::CreateLocalChild(
- *remote_frame, "local-inside-remote");
+ WebLocalFrameImpl* local_child =
+ web_view_helper_.CreateLocalChild(*remote_frame, "local-inside-remote");
LocalFrame* main_frame = WebView()->MainFrameImpl()->GetFrame();
Document* child_document = local_child->GetFrame()->GetDocument();
@@ -9226,8 +9347,8 @@ TEST_F(WebFrameSwapTest, EventsOnDisconnectedElementSkipped) {
remote_frame->SetReplicatedOrigin(
WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
- WebLocalFrameImpl* local_child = frame_test_helpers::CreateLocalChild(
- *remote_frame, "local-inside-remote");
+ WebLocalFrameImpl* local_child =
+ web_view_helper_.CreateLocalChild(*remote_frame, "local-inside-remote");
LocalFrame* main_frame = WebView()->MainFrameImpl()->GetFrame();
@@ -9260,7 +9381,7 @@ TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren) {
frame_test_helpers::CreateRemoteChild(*remote_frame);
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
SwapAndVerifySubframeConsistency("remote->local", target_frame, local_frame);
// FIXME: This almost certainly fires more load events on the iframe element
@@ -9269,7 +9390,7 @@ TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren) {
// back in works.
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
std::string content =
- WebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
+ TestWebFrameContentDumper::DumpWebViewAsText(WebView(), 1024).Utf8();
EXPECT_EQ(" \n\na\n\nhello\n\nc", content);
}
@@ -9299,7 +9420,7 @@ TEST_F(WebFrameSwapTest, SwapPreservesGlobalContext) {
// Now check that remote -> local works too, since it goes through a different
// code path.
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
remote_frame->Swap(local_frame);
v8::Local<v8::Value> local_window = MainFrame()->ExecuteScriptAndReturnValue(
WebScriptSource("document.querySelector('#frame2').contentWindow;"));
@@ -9360,12 +9481,14 @@ TEST_F(WebFrameSwapTest, SwapInitializesGlobal) {
EXPECT_TRUE(window_top->StrictEquals(remote_window_top));
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
- remote_frame->Swap(local_frame);
+ web_view_helper_.CreateProvisional(*remote_frame);
+ // Committing a navigation in a provisional frame will swap it in.
+ frame_test_helpers::LoadFrame(local_frame, "data:text/html,");
v8::Local<v8::Value> local_window_top =
MainFrame()->ExecuteScriptAndReturnValue(WebScriptSource("saved.top"));
EXPECT_TRUE(local_window_top->IsObject());
EXPECT_TRUE(window_top->StrictEquals(local_window_top));
+ local_frame->ExecuteScriptAndReturnValue(WebScriptSource("42"));
}
TEST_F(WebFrameSwapTest, RemoteFramesAreIndexable) {
@@ -9436,7 +9559,7 @@ TEST_F(WebFrameSwapTest, FramesOfRemoteParentAreIndexable) {
WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
WebLocalFrame* child_frame =
- frame_test_helpers::CreateLocalChild(*remote_parent_frame);
+ web_view_helper_.CreateLocalChild(*remote_parent_frame);
frame_test_helpers::LoadFrame(child_frame, base_url_ + "subframe-hello.html");
v8::Local<v8::Value> window =
@@ -9464,7 +9587,7 @@ TEST_F(WebFrameSwapTest, FrameElementInFramesWithRemoteParent) {
WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
WebLocalFrame* child_frame =
- frame_test_helpers::CreateLocalChild(*remote_parent_frame);
+ web_view_helper_.CreateLocalChild(*remote_parent_frame);
frame_test_helpers::LoadFrame(child_frame, base_url_ + "subframe-hello.html");
v8::Local<v8::Value> frame_element = child_frame->ExecuteScriptAndReturnValue(
@@ -9477,25 +9600,23 @@ TEST_F(WebFrameSwapTest, FrameElementInFramesWithRemoteParent) {
class RemoteToLocalSwapWebFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- explicit RemoteToLocalSwapWebFrameClient(WebRemoteFrame* remote_frame)
- : history_commit_type_(kWebHistoryInertCommit),
- remote_frame_(remote_frame) {}
~RemoteToLocalSwapWebFrameClient() override = default;
// frame_test_helpers::TestWebFrameClient:
- void DidCommitNavigation(const WebHistoryItem&,
- WebHistoryCommitType history_commit_type,
- bool) override {
+ void DidCommitNavigation(
+ WebHistoryCommitType history_commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) override {
history_commit_type_ = history_commit_type;
- remote_frame_->Swap(Frame());
}
WebHistoryCommitType HistoryCommitType() const {
- return history_commit_type_;
+ return *history_commit_type_;
}
- WebHistoryCommitType history_commit_type_;
- WebRemoteFrame* remote_frame_;
+ base::Optional<WebHistoryCommitType> history_commit_type_;
};
// The commit type should be Initial if we are swapping a RemoteFrame to a
@@ -9510,9 +9631,9 @@ TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterNewRemoteToLocalSwap) {
ASSERT_TRUE(MainFrame()->FirstChild());
ASSERT_EQ(MainFrame()->FirstChild(), remote_frame);
- RemoteToLocalSwapWebFrameClient client(remote_frame);
+ RemoteToLocalSwapWebFrameClient client;
WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame, &client);
+ web_view_helper_.CreateProvisional(*remote_frame, &client);
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
EXPECT_EQ(kWebHistoryInertCommit, client.HistoryCommitType());
@@ -9532,9 +9653,9 @@ TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterExistingRemoteToLocalSwap) {
ASSERT_TRUE(MainFrame()->FirstChild());
ASSERT_EQ(MainFrame()->FirstChild(), remote_frame);
- RemoteToLocalSwapWebFrameClient client(remote_frame);
+ RemoteToLocalSwapWebFrameClient client;
WebLocalFrameImpl* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame, &client);
+ web_view_helper_.CreateProvisional(*remote_frame, &client);
local_frame->SetCommittedFirstRealLoad();
frame_test_helpers::LoadFrame(local_frame, base_url_ + "subframe-hello.html");
EXPECT_EQ(kWebStandardCommit, client.HistoryCommitType());
@@ -9551,15 +9672,19 @@ class RemoteNavigationClient
~RemoteNavigationClient() override = default;
// frame_test_helpers::TestWebRemoteFrameClient:
- void Navigate(const WebURLRequest& request,
- blink::WebLocalFrame* initiator_frame,
- bool should_replace_current_entry,
- bool is_opener_navigation,
- bool initiator_frame_has_download_sandbox_flag,
- bool blocking_downloads_in_sandbox_enabled,
- bool initiator_frame_is_ad,
- CrossVariantMojoRemote<mojom::blink::BlobURLTokenInterfaceBase>,
- const base::Optional<WebImpression>& impression) override {
+ void Navigate(
+ const WebURLRequest& request,
+ bool should_replace_current_entry,
+ bool is_opener_navigation,
+ bool initiator_frame_has_download_sandbox_flag,
+ bool blocking_downloads_in_sandbox_enabled,
+ bool initiator_frame_is_ad,
+ CrossVariantMojoRemote<mojom::blink::BlobURLTokenInterfaceBase>,
+ const base::Optional<WebImpression>& impression,
+ const blink::LocalFrameToken* initiator_frame_token,
+ blink::CrossVariantMojoRemote<
+ blink::mojom::PolicyContainerHostKeepAliveHandleInterfaceBase>
+ initiator_policy_container_keep_alive_handle) override {
last_request_.CopyFrom(request);
}
@@ -9709,13 +9834,14 @@ TEST_F(WebFrameTest, NavigateRemoteToLocalWithOpener) {
// Do a remote-to-local swap in the popup.
WebLocalFrame* popup_local_frame =
- frame_test_helpers::CreateProvisional(*popup_remote_frame);
+ popup_helper.CreateProvisional(*popup_remote_frame);
popup_remote_frame->Swap(popup_local_frame);
- // The initial document created during the remote-to-local swap should have
- // inherited its opener's SecurityOrigin.
- EXPECT_TRUE(main_frame->GetSecurityOrigin().CanAccess(
+ // The initial document created in a provisional frame should not be
+ // scriptable by any other frame.
+ EXPECT_FALSE(main_frame->GetSecurityOrigin().CanAccess(
popup_helper.LocalMainFrame()->GetSecurityOrigin()));
+ EXPECT_TRUE(popup_helper.LocalMainFrame()->GetSecurityOrigin().IsOpaque());
}
TEST_F(WebFrameTest, SwapWithOpenerCycle) {
@@ -9727,8 +9853,7 @@ TEST_F(WebFrameTest, SwapWithOpenerCycle) {
->SetOpenerDoNotNotify(WebFrame::ToCoreFrame(*remote_frame));
// Now swap in a local frame. It shouldn't crash.
- WebLocalFrame* local_frame =
- frame_test_helpers::CreateProvisional(*remote_frame);
+ WebLocalFrame* local_frame = helper.CreateProvisional(*remote_frame);
remote_frame->Swap(local_frame);
// And the opener cycle should still be preserved.
@@ -9737,22 +9862,25 @@ TEST_F(WebFrameTest, SwapWithOpenerCycle) {
class CommitTypeWebFrameClient : public frame_test_helpers::TestWebFrameClient {
public:
- CommitTypeWebFrameClient() : history_commit_type_(kWebHistoryInertCommit) {}
- ~CommitTypeWebFrameClient() override = default;
-
- // frame_test_helpers::TestWebFrameClient:
- void DidCommitNavigation(const WebHistoryItem&,
- WebHistoryCommitType history_commit_type,
- bool) override {
- history_commit_type_ = history_commit_type;
- }
+ CommitTypeWebFrameClient() = default;
+ ~CommitTypeWebFrameClient() final = default;
WebHistoryCommitType HistoryCommitType() const {
return history_commit_type_;
}
+ // frame_test_helpers::TestWebFrameClient:
+ void DidCommitNavigation(
+ WebHistoryCommitType history_commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) final {
+ history_commit_type_ = history_commit_type;
+ }
+
private:
- WebHistoryCommitType history_commit_type_;
+ WebHistoryCommitType history_commit_type_ = kWebHistoryInertCommit;
};
TEST_F(WebFrameTest, RemoteFrameInitialCommitType) {
@@ -9763,7 +9891,7 @@ TEST_F(WebFrameTest, RemoteFrameInitialCommitType) {
// If an iframe has a remote main frame, ensure the inital commit is correctly
// identified as kWebHistoryInertCommit.
CommitTypeWebFrameClient child_frame_client;
- WebLocalFrame* child_frame = frame_test_helpers::CreateLocalChild(
+ WebLocalFrame* child_frame = helper.CreateLocalChild(
*helper.RemoteMainFrame(), "frameName", WebFrameOwnerProperties(),
nullptr, &child_frame_client);
RegisterMockedHttpURLLoad("foo.html");
@@ -9827,7 +9955,7 @@ TEST_F(WebFrameTest, CrossDomainAccessErrorsUseCallingWindow) {
ASSERT_EQ(1u, popup_web_frame_client.messages.size());
EXPECT_TRUE(std::string::npos !=
popup_web_frame_client.messages[0].text.Utf8().find(
- "Unsafe JavaScript attempt to initiate navigation"));
+ "Unsafe attempt to initiate navigation"));
// Try setting a cross-origin iframe element's source to a javascript: URL,
// and check that this error is also printed on the calling window.
@@ -9848,55 +9976,43 @@ TEST_F(WebFrameTest, CrossDomainAccessErrorsUseCallingWindow) {
TEST_F(WebFrameTest, ResizeInvalidatesDeviceMediaQueries) {
RegisterMockedHttpURLLoad("device_media_queries.html");
- FixedLayoutTestWebWidgetClient client;
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "device_media_queries.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
auto* frame =
To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame());
Element* element = frame->GetDocument()->getElementById("test");
ASSERT_TRUE(element);
- client.screen_info_.available_rect = gfx::Rect(700, 500);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ ScreenInfo screen_info =
+ web_view_helper.GetMainFrameWidget()->GetOriginalScreenInfo();
+ screen_info.rect = screen_info.available_rect = gfx::Rect(700, 500);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(300, element->OffsetWidth());
EXPECT_EQ(300, element->OffsetHeight());
- client.screen_info_.available_rect = gfx::Rect(710, 500);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ screen_info.rect = screen_info.available_rect = gfx::Rect(710, 500);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(400, element->OffsetWidth());
EXPECT_EQ(300, element->OffsetHeight());
- client.screen_info_.available_rect = gfx::Rect(690, 500);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ screen_info.rect = screen_info.available_rect = gfx::Rect(690, 500);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(200, element->OffsetWidth());
EXPECT_EQ(300, element->OffsetHeight());
- client.screen_info_.available_rect = gfx::Rect(700, 510);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ screen_info.rect = screen_info.available_rect = gfx::Rect(700, 510);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(300, element->OffsetWidth());
EXPECT_EQ(400, element->OffsetHeight());
- client.screen_info_.available_rect = gfx::Rect(700, 490);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ screen_info.rect = screen_info.available_rect = gfx::Rect(700, 490);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(300, element->OffsetWidth());
EXPECT_EQ(200, element->OffsetHeight());
- client.screen_info_.available_rect = gfx::Rect(690, 510);
- UpdateScreenInfoAndResizeView(&client, &web_view_helper,
- client.screen_info_.available_rect.width(),
- client.screen_info_.available_rect.height());
+ screen_info.rect = screen_info.available_rect = gfx::Rect(690, 510);
+ UpdateScreenInfoAndResizeView(&web_view_helper, screen_info);
EXPECT_EQ(200, element->OffsetWidth());
EXPECT_EQ(400, element->OffsetHeight());
}
@@ -9905,16 +10021,15 @@ class DeviceEmulationTest : public WebFrameTest {
protected:
DeviceEmulationTest() {
RegisterMockedHttpURLLoad("device_emulation.html");
- client_.screen_info_.device_scale_factor = 1;
web_view_helper_.InitializeAndLoad(base_url_ + "device_emulation.html",
- nullptr, nullptr, &client_);
+ nullptr, nullptr);
}
void TestResize(const gfx::Size& size, const String& expected_size) {
- client_.screen_info_.available_rect = gfx::Rect(size);
- UpdateScreenInfoAndResizeView(&client_, &web_view_helper_,
- client_.screen_info_.available_rect.width(),
- client_.screen_info_.available_rect.height());
+ ScreenInfo screen_info =
+ web_view_helper_.GetMainFrameWidget()->GetOriginalScreenInfo();
+ screen_info.rect = screen_info.available_rect = gfx::Rect(size);
+ UpdateScreenInfoAndResizeView(&web_view_helper_, screen_info);
EXPECT_EQ(expected_size, DumpSize("test"));
}
@@ -9932,7 +10047,6 @@ class DeviceEmulationTest : public WebFrameTest {
return callback_helper.StringValue();
}
- FixedLayoutTestWebWidgetClient client_;
frame_test_helpers::WebViewHelper web_view_helper_;
};
@@ -9968,14 +10082,12 @@ TEST_F(WebFrameTest, CreateLocalChildWithPreviousSibling) {
helper.InitializeRemote();
WebRemoteFrame* parent = helper.RemoteMainFrame();
- WebLocalFrame* second_frame(
- frame_test_helpers::CreateLocalChild(*parent, "name2"));
- WebLocalFrame* fourth_frame(frame_test_helpers::CreateLocalChild(
+ WebLocalFrame* second_frame(helper.CreateLocalChild(*parent, "name2"));
+ WebLocalFrame* fourth_frame(helper.CreateLocalChild(
*parent, "name4", WebFrameOwnerProperties(), second_frame));
- WebLocalFrame* third_frame(frame_test_helpers::CreateLocalChild(
+ WebLocalFrame* third_frame(helper.CreateLocalChild(
*parent, "name3", WebFrameOwnerProperties(), second_frame));
- WebLocalFrame* first_frame(
- frame_test_helpers::CreateLocalChild(*parent, "name1"));
+ WebLocalFrame* first_frame(helper.CreateLocalChild(*parent, "name1"));
EXPECT_EQ(first_frame, parent->FirstChild());
EXPECT_EQ(nullptr, first_frame->PreviousSibling());
@@ -10002,7 +10114,7 @@ TEST_F(WebFrameTest, SendBeaconFromChildWithRemoteMainFrame) {
helper.InitializeRemote();
WebLocalFrame* local_frame =
- frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
+ helper.CreateLocalChild(*helper.RemoteMainFrame());
// Finally, make sure an embedder triggered load in the local frame swapped
// back in works.
@@ -10019,7 +10131,7 @@ TEST_F(WebFrameTest, SiteForCookiesFromChildWithRemoteMainFrame) {
SecurityOrigin::Create(ToKURL(not_base_url_)));
WebLocalFrame* local_frame =
- frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
+ helper.CreateLocalChild(*helper.RemoteMainFrame());
RegisterMockedHttpURLLoad("foo.html");
frame_test_helpers::LoadFrame(local_frame, base_url_ + "foo.html");
@@ -10036,11 +10148,11 @@ TEST_F(WebFrameTest, RemoteToLocalSwapOnMainFrameInitializesCoreFrame) {
frame_test_helpers::WebViewHelper helper;
helper.InitializeRemote();
- frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
+ helper.CreateLocalChild(*helper.RemoteMainFrame());
// Do a remote-to-local swap of the top frame.
WebLocalFrame* local_root =
- frame_test_helpers::CreateProvisional(*helper.RemoteMainFrame());
+ helper.CreateProvisional(*helper.RemoteMainFrame());
helper.RemoteMainFrame()->Swap(local_root);
// Load a page with a child frame in the new root to make sure this doesn't
@@ -10068,8 +10180,7 @@ TEST_F(WebFrameTest, PausedPageLoadWithRemoteMainFrame) {
// Repeat this for a page with a local child frame, and ensure that the
// child frame's loads are also suspended.
- WebLocalFrameImpl* web_local_child =
- frame_test_helpers::CreateLocalChild(*remote_root);
+ WebLocalFrameImpl* web_local_child = helper.CreateLocalChild(*remote_root);
RegisterMockedHttpURLLoad("foo.html");
frame_test_helpers::LoadFrame(web_local_child, base_url_ + "foo.html");
LocalFrame* local_child = web_local_child->GetFrame();
@@ -10105,10 +10216,11 @@ class OverscrollWidgetInputHandlerHost
}
};
-class OverscrollWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
+class OverscrollWebFrameWidget : public frame_test_helpers::TestWebFrameWidget {
public:
- OverscrollWebWidgetClient() = default;
+ template <typename... Args>
+ explicit OverscrollWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {}
frame_test_helpers::TestWidgetInputHandlerHost* GetInputHandlerHost()
override {
@@ -10178,109 +10290,121 @@ INSTANTIATE_TEST_SUITE_P(All,
TEST_P(WebFrameOverscrollTest,
AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
+
// Calculation of accumulatedRootOverscroll and unusedDelta on multiple
// scrollUpdate.
ScrollBegin(&web_view_helper, -300, -316);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(8, 16), gfx::Vector2dF(8, 16),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, -308, -316);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 13), gfx::Vector2dF(8, 29),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, -13);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(20, 13), gfx::Vector2dF(28, 42),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, -20, -13);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// Overscroll is not reported.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0, 1);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 1, 0);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// Overscroll is reported.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, -701), gfx::Vector2dF(0, -701),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, 1000);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// Overscroll is not reported.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollEnd(&web_view_helper);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
TEST_P(WebFrameOverscrollTest,
AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
+ base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
ScrollBegin(&web_view_helper, 0, -316);
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
+
// Scroll the Div to the end.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0, -316);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
ScrollEnd(&web_view_helper);
ScrollBegin(&web_view_helper, 0, -100);
// Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 100), gfx::Vector2dF(0, 100),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
@@ -10288,7 +10412,7 @@ TEST_P(WebFrameOverscrollTest,
ScrollUpdate(&web_view_helper, 0, -100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// TODO(bokan): This has never worked but by the accident that this test was
// being run in a WebView without a size. This test should be fixed along with
@@ -10312,54 +10436,64 @@ TEST_P(WebFrameOverscrollTest,
}
TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/div-overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr, &client,
+ base_url_ + "overscroll/div-overscroll.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
ScrollBegin(&web_view_helper, 0, -316);
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
// Scroll the Div to the end.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0, -316);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
ScrollEnd(&web_view_helper);
ScrollBegin(&web_view_helper, 0, -150);
// Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 50), gfx::Vector2dF(0, 50),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, -150);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(
base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
ScrollBegin(&web_view_helper, 0, -320);
// Scroll the IFrame to the end.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
@@ -10372,193 +10506,206 @@ TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll) {
ScrollUpdate(&web_view_helper, 0, -50);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
ScrollEnd(&web_view_helper);
ScrollBegin(&web_view_helper, 0, -150);
// Now On Scrolling IFrame, scroll is bubbled and root layer is over-scrolled.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 50), gfx::Vector2dF(0, 50),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, -150);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
ScrollEnd(&web_view_helper);
}
TEST_P(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
- base_url_ + "overscroll/overscroll.html", nullptr, nullptr, &client,
+ base_url_ + "overscroll/overscroll.html", nullptr, nullptr,
ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
web_view_impl->SetPageScaleFactor(3.0);
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
// Calculation of accumulatedRootOverscroll and unusedDelta on scaled page.
// The point is (99, 99) because we clamp in the division by 3 to 33 so when
// we go back to viewport coordinates it becomes (99, 99).
ScrollBegin(&web_view_helper, 0, 30);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, -30), gfx::Vector2dF(0, -30),
gfx::PointF(99, 99), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, 30);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, -30), gfx::Vector2dF(0, -60),
gfx::PointF(99, 99), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, 30);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-30, -30), gfx::Vector2dF(-30, -90),
gfx::PointF(99, 99), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 30, 30);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-30, 0), gfx::Vector2dF(-60, -90),
gfx::PointF(99, 99), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 30, 0);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// Overscroll is not reported.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollEnd(&web_view_helper);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
TEST_P(WebFrameOverscrollTest, NoOverscrollForSmallvalues) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
ScrollBegin(&web_view_helper, 10, 10);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-10, -10), gfx::Vector2dF(-10, -10),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 10, 10);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, -0.10),
gfx::Vector2dF(-10, -10.10), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0, 0.10);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_CALL(
- client.GetOverscrollWidgetInputHandlerHost(),
+ widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-0.10, 0), gfx::Vector2dF(-10.10, -10.10),
gfx::PointF(100, 100), gfx::Vector2dF(),
kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 0.10, 0);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
// For residual values overscrollDelta should be reset and DidOverscroll
// shouldn't be called.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0, 0.09);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0.09, 0.09);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0.09, 0);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, 0, -0.09);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, -0.09, -0.09);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollUpdate(&web_view_helper, -0.09, 0);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(_, _, _, _, _))
.Times(0);
ScrollEnd(&web_view_helper);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
TEST_P(WebFrameOverscrollTest, OverscrollBehaviorGoesToCompositor) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/overscroll.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(base_url_ + "overscroll/overscroll.html",
- nullptr, nullptr, &client,
- ConfigureAndroid);
+ nullptr, nullptr, ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
WebLocalFrame* mainFrame =
web_view_helper.GetWebView()->MainFrame()->ToWebLocalFrame();
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
@@ -10567,14 +10714,14 @@ TEST_P(WebFrameOverscrollTest, OverscrollBehaviorGoesToCompositor) {
WebScriptSource(WebString("document.body.style="
"'overscroll-behavior: auto;'")));
ScrollBegin(&web_view_helper, 100, 116);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-100, -100),
gfx::Vector2dF(-100, -100), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 100, 100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
kOverscrollBehaviorAuto);
@@ -10582,14 +10729,14 @@ TEST_P(WebFrameOverscrollTest, OverscrollBehaviorGoesToCompositor) {
WebScriptSource(WebString("document.body.style="
"'overscroll-behavior: contain;'")));
ScrollBegin(&web_view_helper, 100, 116);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-100, -100),
gfx::Vector2dF(-200, -200), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorContain));
ScrollUpdate(&web_view_helper, 100, 100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
kOverscrollBehaviorContain);
@@ -10597,29 +10744,34 @@ TEST_P(WebFrameOverscrollTest, OverscrollBehaviorGoesToCompositor) {
WebScriptSource(WebString("document.body.style="
"'overscroll-behavior: none;'")));
ScrollBegin(&web_view_helper, 100, 116);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-100, -100),
gfx::Vector2dF(-300, -300), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorNone));
ScrollUpdate(&web_view_helper, 100, 100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
kOverscrollBehaviorNone);
}
TEST_P(WebFrameOverscrollTest, OnlyMainFrameOverscrollBehaviorHasEffect) {
- OverscrollWebWidgetClient client;
RegisterMockedHttpURLLoad("overscroll/iframe-overscroll.html");
RegisterMockedHttpURLLoad("overscroll/scrollable-iframe.html");
- frame_test_helpers::WebViewHelper web_view_helper;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
web_view_helper.InitializeAndLoad(
base_url_ + "overscroll/iframe-overscroll.html", nullptr, nullptr,
- &client, ConfigureAndroid);
+ ConfigureAndroid);
web_view_helper.Resize(gfx::Size(200, 200));
+ OverscrollWebFrameWidget* widget = static_cast<OverscrollWebFrameWidget*>(
+ web_view_helper.GetMainFrameWidget());
WebLocalFrame* mainFrame =
web_view_helper.GetWebView()->MainFrame()->ToWebLocalFrame();
mainFrame->ExecuteScript(
@@ -10634,28 +10786,28 @@ TEST_P(WebFrameOverscrollTest, OnlyMainFrameOverscrollBehaviorHasEffect) {
"'overscroll-behavior: none;'")));
ScrollBegin(&web_view_helper, 100, 116);
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-100, -100),
gfx::Vector2dF(-100, -100), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorAuto));
ScrollUpdate(&web_view_helper, 100, 100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
kOverscrollBehaviorAuto);
mainFrame->ExecuteScript(
WebScriptSource(WebString("document.body.style="
"'overscroll-behavior: contain;'")));
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(-100, -100),
gfx::Vector2dF(-200, -200), gfx::PointF(100, 100),
gfx::Vector2dF(), kOverscrollBehaviorContain));
ScrollUpdate(&web_view_helper, 100, 100);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
EXPECT_EQ(web_view_helper.GetLayerTreeHost()->overscroll_behavior(),
kOverscrollBehaviorContain);
}
@@ -10675,7 +10827,7 @@ TEST_F(WebFrameTest, MaxFrames) {
Page* page = web_view_helper.GetWebView()->GetPage();
WebLocalFrameImpl* frame =
- frame_test_helpers::CreateLocalChild(*web_view_helper.RemoteMainFrame());
+ web_view_helper.CreateLocalChild(*web_view_helper.RemoteMainFrame());
while (page->SubframeCount() < Page::MaxNumberOfFrames()) {
frame_test_helpers::CreateRemoteChild(*web_view_helper.RemoteMainFrame());
}
@@ -10698,7 +10850,8 @@ class TestViewportIntersection : public FakeRemoteFrameHost {
// FakeRemoteFrameHost:
void UpdateViewportIntersection(
- mojom::blink::ViewportIntersectionStatePtr intersection_state) override {
+ mojom::blink::ViewportIntersectionStatePtr intersection_state,
+ const base::Optional<FrameVisualProperties>& visual_properties) override {
intersection_state_ = std::move(intersection_state);
}
@@ -10996,14 +11149,15 @@ class WebLocalFrameVisibilityChangeTest
// frame_test_helpers::TestWebFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override {
- return CreateLocalChild(*parent, scope, &child_client_);
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
+ return CreateLocalChild(*Frame(), scope, &child_client_,
+ std::move(policy_container_bind_params));
}
TestLocalFrameHostForVisibility& ChildHost() { return child_host_; }
@@ -11071,8 +11225,7 @@ TEST(WebFrameGlobalReuseTest, MainFrameWithNoOpener) {
// injected script before the initial navigation.
TEST(WebFrameGlobalReuseTest, ChildFrame) {
frame_test_helpers::WebViewHelper helper;
- helper.Initialize(nullptr, nullptr, nullptr,
- EnableGlobalReuseForUnownedMainFrames);
+ helper.Initialize(nullptr, nullptr, EnableGlobalReuseForUnownedMainFrames);
WebLocalFrame* main_frame = helper.LocalMainFrame();
frame_test_helpers::LoadFrame(main_frame, "data:text/html,<iframe></iframe>");
@@ -11094,8 +11247,7 @@ TEST(WebFrameGlobalReuseTest, MainFrameWithOpener) {
opener_helper.Initialize();
frame_test_helpers::WebViewHelper helper;
helper.InitializeWithOpener(opener_helper.GetWebView()->MainFrame(), nullptr,
- nullptr, nullptr,
- EnableGlobalReuseForUnownedMainFrames);
+ nullptr, EnableGlobalReuseForUnownedMainFrames);
WebLocalFrame* main_frame = helper.LocalMainFrame();
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -11113,8 +11265,7 @@ TEST(WebFrameGlobalReuseTest, MainFrameWithOpener) {
// to persist on the first navigation away from the initial empty document.
TEST(WebFrameGlobalReuseTest, ReuseForMainFrameIfEnabled) {
frame_test_helpers::WebViewHelper helper;
- helper.Initialize(nullptr, nullptr, nullptr,
- EnableGlobalReuseForUnownedMainFrames);
+ helper.Initialize(nullptr, nullptr, EnableGlobalReuseForUnownedMainFrames);
WebLocalFrame* main_frame = helper.LocalMainFrame();
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -11197,7 +11348,7 @@ class TestLocalFrameHostForSaveImageFromDataURL : public FakeLocalFrameHost {
mojo::ScopedDataPipeProducerHandle producer_handle;
mojo::ScopedDataPipeConsumerHandle consumer_handle;
auto result =
- mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle);
DCHECK(result == MOJO_RESULT_OK);
blob->ReadAll(std::move(producer_handle), mojo::NullRemote());
@@ -11554,7 +11705,7 @@ TEST_F(WebFrameTest, RootLayerMinimumHeight) {
constexpr int kBrowserControlsHeight = 100;
frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize(nullptr, nullptr, nullptr, ConfigureAndroid);
+ web_view_helper.Initialize(nullptr, nullptr, ConfigureAndroid);
WebViewImpl* web_view = web_view_helper.GetWebView();
web_view->ResizeWithBrowserControls(
gfx::Size(kViewportWidth, kViewportHeight - kBrowserControlsHeight),
@@ -12370,7 +12521,7 @@ TEST_F(WebFrameSimTest, DoubleTapZoomWhileScrolled) {
// contained in the visual viewport.
{
gfx::Point point(445, 455);
- WebRect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
+ gfx::Rect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
WebView().AnimateDoubleTapZoom(IntPoint(point), block_bounds);
EXPECT_TRUE(WebView().FakeDoubleTapAnimationPendingForTesting());
ScrollOffset new_offset = ToScrollOffset(
@@ -12392,7 +12543,7 @@ TEST_F(WebFrameSimTest, DoubleTapZoomWhileScrolled) {
// remain on screen.
{
gfx::Point point(445, 455);
- WebRect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
+ gfx::Rect block_bounds = ComputeBlockBoundHelper(&WebView(), point, false);
WebView().AnimateDoubleTapZoom(IntPoint(point), block_bounds);
EXPECT_TRUE(WebView().FakeDoubleTapAnimationPendingForTesting());
IntPoint target_offset(
@@ -12697,14 +12848,15 @@ TEST_F(WebFrameTest, NoLoadingCompletionCallbacksInDetach) {
// frame_test_helpers::TestWebFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy&,
const WebFrameOwnerProperties&,
- mojom::blink::FrameOwnerElementType) override {
- return CreateLocalChild(*parent, scope, &child_client_);
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
+ return CreateLocalChild(*Frame(), scope, &child_client_,
+ std::move(policy_container_bind_params));
}
LoadingObserverFrameClient& ChildClient() { return child_client_; }
@@ -12742,32 +12894,18 @@ TEST_F(WebFrameTest, ClearClosedOpener) {
EXPECT_EQ(nullptr, helper.LocalMainFrame()->Opener());
}
-class ShowVirtualKeyboardObserverWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
- public:
- ShowVirtualKeyboardObserverWidgetClient() = default;
- ~ShowVirtualKeyboardObserverWidgetClient() override = default;
-
- // frame_test_helpers::TestWebWidgetClient:
- void TextInputStateChanged(
- ui::mojom::blink::TextInputStatePtr state) override {
- did_show_virtual_keyboard_ |= state->show_ime_if_needed;
- }
-
- bool DidShowVirtualKeyboard() const { return did_show_virtual_keyboard_; }
-
- private:
- bool did_show_virtual_keyboard_ = false;
-};
-
TEST_F(WebFrameTest, ShowVirtualKeyboardOnElementFocus) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeRemote();
- ShowVirtualKeyboardObserverWidgetClient web_widget_client;
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
+ WebLocalFrameImpl* local_frame = web_view_helper.CreateLocalChild(
*web_view_helper.RemoteMainFrame(), "child", WebFrameOwnerProperties(),
- nullptr, nullptr, &web_widget_client);
+ nullptr, nullptr);
+
+ frame_test_helpers::TestWebFrameWidgetHost& widget_host =
+ static_cast<frame_test_helpers::TestWebFrameWidget*>(
+ local_frame->FrameWidgetImpl())
+ ->WidgetHost();
RegisterMockedHttpURLLoad("input_field_default.html");
frame_test_helpers::LoadFrame(local_frame,
@@ -12782,11 +12920,11 @@ TEST_F(WebFrameTest, ShowVirtualKeyboardOnElementFocus) {
"document.querySelector('input').focus();"));
RunPendingTasks();
- // Verify that the right WebWidgetClient has been notified.
-#if BUILDFLAG(IS_ASH)
- EXPECT_FALSE(web_widget_client.DidShowVirtualKeyboard());
+ // Verify that the right WidgetHost has been notified.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ EXPECT_EQ(0u, widget_host.VirtualKeyboardRequestCount());
#else
- EXPECT_TRUE(web_widget_client.DidShowVirtualKeyboard());
+ EXPECT_LT(0u, widget_host.VirtualKeyboardRequestCount());
#endif
web_view_helper.Reset();
}
@@ -12798,15 +12936,16 @@ class ContextMenuWebFrameClient
~ContextMenuWebFrameClient() override = default;
// WebLocalFrameClient:
- void ShowContextMenu(const WebContextMenuData& data,
- const base::Optional<gfx::Point>&) override {
+ void UpdateContextMenuDataForTesting(
+ const ContextMenuData& data,
+ const base::Optional<gfx::Point>&) override {
menu_data_ = data;
}
- WebContextMenuData GetMenuData() { return menu_data_; }
+ ContextMenuData GetMenuData() { return menu_data_; }
private:
- WebContextMenuData menu_data_;
+ ContextMenuData menu_data_;
DISALLOW_COPY_AND_ASSIGN(ContextMenuWebFrameClient);
};
@@ -12905,8 +13044,8 @@ TEST_F(WebFrameTest, ContextMenuDataPasswordSelectedText) {
RunPendingTasks();
web_view_helper.Reset();
EXPECT_EQ(frame.GetMenuData().input_field_type,
- blink::ContextMenuDataInputFieldType::kPassword);
- EXPECT_FALSE(frame.GetMenuData().selected_text.IsEmpty());
+ blink::mojom::ContextMenuDataInputFieldType::kPassword);
+ EXPECT_FALSE(frame.GetMenuData().selected_text.empty());
}
TEST_F(WebFrameTest, ContextMenuDataNonLocatedMenu) {
@@ -12941,7 +13080,7 @@ TEST_F(WebFrameTest, ContextMenuDataNonLocatedMenu) {
RunPendingTasks();
web_view_helper.Reset();
EXPECT_EQ(frame.GetMenuData().source_type, kMenuSourceTouch);
- EXPECT_FALSE(frame.GetMenuData().selected_text.IsEmpty());
+ EXPECT_FALSE(frame.GetMenuData().selected_text.empty());
}
TEST_F(WebFrameTest, LocalFrameWithRemoteParentIsTransparent) {
@@ -12949,7 +13088,7 @@ TEST_F(WebFrameTest, LocalFrameWithRemoteParentIsTransparent) {
helper.InitializeRemote();
WebLocalFrameImpl* local_frame =
- frame_test_helpers::CreateLocalChild(*helper.RemoteMainFrame());
+ helper.CreateLocalChild(*helper.RemoteMainFrame());
frame_test_helpers::LoadFrame(local_frame, "data:text/html,some page");
// Local frame with remote parent should have transparent baseBackgroundColor.
@@ -12969,15 +13108,16 @@ class TestFallbackWebFrameClient
// frame_test_helpers::TestWebFrameClient:
WebLocalFrame* CreateChildFrame(
- WebLocalFrame* parent,
mojom::blink::TreeScopeType scope,
const WebString&,
const WebString&,
const FramePolicy&,
const WebFrameOwnerProperties& frameOwnerProperties,
- mojom::blink::FrameOwnerElementType) override {
+ mojom::blink::FrameOwnerElementType,
+ WebPolicyContainerBindParams policy_container_bind_params) override {
DCHECK(child_client_);
- return CreateLocalChild(*parent, scope, child_client_);
+ return CreateLocalChild(*Frame(), scope, child_client_,
+ std::move(policy_container_bind_params));
}
void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
if (child_client_ || KURL(info->url_request.Url()) == BlankURL()) {
@@ -13001,8 +13141,9 @@ TEST_F(WebFrameTest, FallbackForNonexistentProvisionalNavigation) {
web_view_helper_.Initialize(&main_client);
WebLocalFrameImpl* main_frame = web_view_helper_.LocalMainFrame();
- WebURLRequest request(ToKURL(base_url_ + "fallback.html"));
- main_frame->StartNavigation(request);
+ KURL url = ToKURL(base_url_ + "fallback.html");
+ FrameLoadRequest frame_load_request(nullptr, ResourceRequest(url));
+ main_frame->GetFrame()->Loader().StartNavigation(frame_load_request);
// Because the child frame will have placeholder document loader, the main
// frame will not finish loading, so
@@ -13019,7 +13160,7 @@ TEST_F(WebFrameTest, FallbackForNonexistentProvisionalNavigation) {
// page.
EXPECT_EQ(WebNavigationControl::NoLoadInProgress,
To<WebLocalFrameImpl>(child)->MaybeRenderFallbackContent(
- WebURLError(ResourceError::Failure(request.Url()))));
+ WebURLError(ResourceError::Failure(url))));
}
TEST_F(WebFrameTest, AltTextOnAboutBlankPage) {
@@ -13050,24 +13191,6 @@ TEST_F(WebFrameTest, AltTextOnAboutBlankPage) {
EXPECT_EQ("foo alt", text.Utf8());
}
-TEST_F(WebFrameTest, NavigatorPluginsClearedWhenPluginsDisabled) {
- ScopedFakePluginRegistry fake_plugins;
- frame_test_helpers::WebViewHelper web_view_helper;
- web_view_helper.Initialize();
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::Local<v8::Context> context = isolate->GetCurrentContext();
- v8::HandleScope scope(isolate);
- v8::Local<v8::Value> result =
- web_view_helper.LocalMainFrame()->ExecuteScriptAndReturnValue(
- WebScriptSource("navigator.plugins.length"));
- EXPECT_NE(0, result->Int32Value(context).ToChecked());
- web_view_helper.GetWebView()->GetPage()->GetSettings().SetPluginsEnabled(
- false);
- result = web_view_helper.LocalMainFrame()->ExecuteScriptAndReturnValue(
- WebScriptSource("navigator.plugins.length"));
- EXPECT_EQ(0, result->Int32Value(context).ToChecked());
-}
-
TEST_F(WebFrameTest, RecordSameDocumentNavigationToHistogram) {
const char* histogramName =
"RendererScheduler.UpdateForSameDocumentNavigationCount";
@@ -13114,9 +13237,8 @@ TEST_F(WebFrameTest, RecordSameDocumentNavigationToHistogram) {
static void TestFramePrinting(WebLocalFrameImpl* frame) {
WebPrintParams print_params;
- WebSize page_size(500, 500);
- print_params.print_content_area.width = page_size.width;
- print_params.print_content_area.height = page_size.height;
+ gfx::Size page_size(500, 500);
+ print_params.print_content_area.set_size(page_size);
EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
PaintRecorder recorder;
frame->PrintPagesForTesting(recorder.beginRecording(IntRect()), page_size,
@@ -13192,9 +13314,8 @@ TEST_F(WebFrameTest, FirstLetterHasDOMNodeIdWhenPrinting) {
// Print the page and capture the PaintRecord.
WebPrintParams print_params;
- WebSize page_size(500, 500);
- print_params.print_content_area.width = page_size.width;
- print_params.print_content_area.height = page_size.height;
+ gfx::Size page_size(500, 500);
+ print_params.print_content_area.set_size(page_size);
WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
PaintRecorder recorder;
@@ -13446,8 +13567,7 @@ TEST_F(WebFrameSimTest, PageOrientation) {
auto* frame = WebView().MainFrame()->ToWebLocalFrame();
WebPrintParams print_params;
- print_params.print_content_area.width = page_size.width();
- print_params.print_content_area.height = page_size.height();
+ print_params.print_content_area.set_size(page_size);
EXPECT_EQ(4u, frame->PrintBegin(print_params, WebNode()));
WebPrintPageDescription description;
@@ -13499,13 +13619,17 @@ TEST_F(WebFrameTest, MediaQueriesInLocalFrameInsideRemote) {
frame_test_helpers::WebViewHelper helper;
helper.InitializeRemote();
- FixedLayoutTestWebWidgetClient client;
- client.screen_info_.is_monochrome = false;
- client.screen_info_.depth_per_component = 8;
+ WebLocalFrameImpl* local_frame =
+ helper.CreateLocalChild(*helper.RemoteMainFrame(), WebString(),
+ WebFrameOwnerProperties(), nullptr, nullptr);
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
- *helper.RemoteMainFrame(), WebString(), WebFrameOwnerProperties(),
- nullptr, nullptr, &client);
+ frame_test_helpers::TestWebFrameWidget* local_frame_widget =
+ static_cast<frame_test_helpers::TestWebFrameWidget*>(
+ local_frame->FrameWidgetImpl());
+ ScreenInfo screen_info = local_frame_widget->GetOriginalScreenInfo();
+ screen_info.is_monochrome = false;
+ screen_info.depth_per_component = 8;
+ local_frame_widget->UpdateScreenInfo(screen_info);
ASSERT_TRUE(local_frame->GetFrame());
MediaValues* media_values =
@@ -13521,8 +13645,8 @@ TEST_F(WebFrameTest, MediaQueriesInLocalFrameInsideRemote) {
TEST_F(WebFrameTest, RemoteViewportAndMainframeIntersections) {
frame_test_helpers::WebViewHelper helper;
helper.InitializeRemote();
- WebLocalFrameImpl* local_frame = frame_test_helpers::CreateLocalChild(
- *helper.RemoteMainFrame(), "frameName");
+ WebLocalFrameImpl* local_frame =
+ helper.CreateLocalChild(*helper.RemoteMainFrame(), "frameName");
frame_test_helpers::LoadHTMLString(local_frame, R"HTML(
<!DOCTYPE html>
<style>
@@ -13556,9 +13680,10 @@ TEST_F(WebFrameTest, RemoteViewportAndMainframeIntersections) {
blink::mojom::FrameOcclusionState occlusion_state =
blink::mojom::FrameOcclusionState::kUnknown;
- static_cast<WebFrameWidgetBase*>(widget)->SetRemoteViewportIntersection(
- {viewport_intersection, mainframe_intersection, viewport_intersection,
- occlusion_state, gfx::Size(), gfx::Point(), viewport_transform});
+ static_cast<WebFrameWidgetImpl*>(widget)->ApplyViewportIntersectionForTesting(
+ blink::mojom::blink::ViewportIntersectionState::New(
+ viewport_intersection, mainframe_intersection, viewport_intersection,
+ occlusion_state, gfx::Size(), gfx::Point(), viewport_transform));
// The viewport intersection should be applied by the layout geometry mapping
// code when these flags are used.
@@ -13737,6 +13862,9 @@ class TestLocalFrameHostForAnchorWithDownloadAttr : public FakeLocalFrameHost {
};
TEST_F(WebFrameTest, DownloadReferrerPolicy) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kPolicyContainer);
+
TestLocalFrameHostForAnchorWithDownloadAttr frame_host;
frame_test_helpers::TestWebFrameClient web_frame_client;
frame_host.Init(web_frame_client.GetRemoteNavigationAssociatedInterfaces());
@@ -13745,53 +13873,251 @@ TEST_F(WebFrameTest, DownloadReferrerPolicy) {
WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
KURL test_url = ToKURL("http://www.test.com/foo/index.html");
- // 1.<meta name='referrer' content='no-referrer'>
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy("no-referrer", std::string()),
- test_url);
- EXPECT_TRUE(frame_host.referrer_.IsEmpty());
- EXPECT_EQ(frame_host.referrer_policy_,
- network::mojom::ReferrerPolicy::kNever);
- // 2.<meta name='referrer' content='origin'>
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy("origin", std::string()), test_url);
- EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
- EXPECT_EQ(frame_host.referrer_policy_,
- network::mojom::ReferrerPolicy::kOrigin);
+ {
+ // 1.<meta name='referrer' content='no-referrer'>
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host,
+ SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever));
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy("no-referrer", std::string()),
+ test_url);
+ EXPECT_TRUE(frame_host.referrer_.IsEmpty());
+ EXPECT_EQ(frame_host.referrer_policy_,
+ network::mojom::ReferrerPolicy::kNever);
+ policy_container_host.FlushForTesting();
+ }
- // 3.Without any declared referrer-policy attribute
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy(std::string(), std::string()),
- test_url);
- EXPECT_EQ(frame_host.referrer_, test_url);
- EXPECT_EQ(frame_host.referrer_policy_,
- ReferrerUtils::MojoReferrerPolicyResolveDefault(
- network::mojom::ReferrerPolicy::kDefault));
-
- // 4.referrerpolicy='origin'
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy(std::string(), "origin"), test_url);
- EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
- EXPECT_EQ(frame_host.referrer_policy_,
- network::mojom::ReferrerPolicy::kOrigin);
+ {
+ // 2.<meta name='referrer' content='origin'>
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host,
+ SetReferrerPolicy(network::mojom::ReferrerPolicy::kOrigin));
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy("origin", std::string()),
+ test_url);
+ EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
+ EXPECT_EQ(frame_host.referrer_policy_,
+ network::mojom::ReferrerPolicy::kOrigin);
+ policy_container_host.FlushForTesting();
+ }
- // 5.referrerpolicy='same-origin'
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy(std::string(), "same-origin"),
- test_url);
- EXPECT_EQ(frame_host.referrer_, test_url);
- EXPECT_EQ(frame_host.referrer_policy_,
- network::mojom::ReferrerPolicy::kSameOrigin);
+ {
+ // 3.Without any declared referrer-policy attribute
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host, SetReferrerPolicy(_)).Times(0);
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy(std::string(), std::string()),
+ test_url);
+ EXPECT_EQ(frame_host.referrer_, test_url);
+ EXPECT_EQ(frame_host.referrer_policy_,
+ ReferrerUtils::MojoReferrerPolicyResolveDefault(
+ network::mojom::ReferrerPolicy::kDefault));
+ policy_container_host.FlushForTesting();
+ }
+
+ {
+ // 4.referrerpolicy='origin'
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host, SetReferrerPolicy(_)).Times(0);
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy(std::string(), "origin"),
+ test_url);
+ EXPECT_EQ(frame_host.referrer_, ToKURL("http://www.test.com/"));
+ EXPECT_EQ(frame_host.referrer_policy_,
+ network::mojom::ReferrerPolicy::kOrigin);
+ policy_container_host.FlushForTesting();
+ }
+
+ {
+ // 5.referrerpolicy='same-origin'
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host, SetReferrerPolicy(_)).Times(0);
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy(std::string(), "same-origin"),
+ test_url);
+ EXPECT_EQ(frame_host.referrer_, test_url);
+ EXPECT_EQ(frame_host.referrer_policy_,
+ network::mojom::ReferrerPolicy::kSameOrigin);
+ policy_container_host.FlushForTesting();
+ }
+
+ {
+ // 6.referrerpolicy='no-referrer'
+ MockPolicyContainerHost policy_container_host;
+ frame->GetFrame()->SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host, SetReferrerPolicy(_)).Times(0);
+ frame_test_helpers::LoadHTMLString(
+ frame, GetHTMLStringForReferrerPolicy(std::string(), "no-referrer"),
+ test_url);
+ EXPECT_TRUE(frame_host.referrer_.IsEmpty());
+ EXPECT_EQ(frame_host.referrer_policy_,
+ network::mojom::ReferrerPolicy::kNever);
+ policy_container_host.FlushForTesting();
+ }
- // 6.referrerpolicy='no-referrer'
- frame_test_helpers::LoadHTMLString(
- frame, GetHTMLStringForReferrerPolicy(std::string(), "no-referrer"),
- test_url);
- EXPECT_TRUE(frame_host.referrer_.IsEmpty());
- EXPECT_EQ(frame_host.referrer_policy_,
- network::mojom::ReferrerPolicy::kNever);
web_view_helper.Reset();
}
+TEST_F(WebFrameTest, RemoteFrameCompositingScaleFactor) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+
+ WebViewImpl* web_view = web_view_helper.GetWebView();
+ web_view->Resize(gfx::Size(800, 800));
+ InitializeWithHTML(*web_view->MainFrameImpl()->GetFrame(), R"HTML(
+ <!DOCTYPE html>
+ <style>
+ iframe {
+ width: 1600;
+ height: 1200;
+ transform-origin: top left;
+ transform: scale(0.5);
+ border: none;
+ }
+ </style>
+ <iframe></iframe>
+ )HTML");
+
+ WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
+ web_view_helper.LocalMainFrame()->FirstChild()->Swap(remote_frame);
+ remote_frame->SetReplicatedOrigin(
+ WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
+
+ // Call directly into frame view since we need to RunPostLifecycleSteps() too.
+ web_view->MainFrameImpl()
+ ->GetFrame()
+ ->View()
+ ->UpdateAllLifecyclePhasesForTest();
+ RunPendingTasks();
+
+ // The compositing scale factor tells the OOPIF compositor to raster at a
+ // lower scale since the frame is scaled down in the parent webview.
+ EXPECT_EQ(remote_frame->GetCompositingRect(), gfx::Rect(0, 0, 1600, 1200));
+ EXPECT_EQ(remote_frame->GetCompositingScaleFactor(), 0.5f);
+}
+
+TEST_F(WebFrameTest, RotatedRemoteFrameCompositingScaleFactor) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+
+ WebViewImpl* web_view = web_view_helper.GetWebView();
+ web_view->Resize(gfx::Size(800, 800));
+ InitializeWithHTML(*web_view->MainFrameImpl()->GetFrame(), R"HTML(
+ <!DOCTYPE html>
+ <style>
+ iframe {
+ width: 1600;
+ height: 1200;
+ transform-origin: top left;
+ transform: scale(0.5) rotate(45deg);
+ border: none;
+ }
+ </style>
+ <iframe></iframe>
+ )HTML");
+
+ WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
+ web_view_helper.LocalMainFrame()->FirstChild()->Swap(remote_frame);
+ remote_frame->SetReplicatedOrigin(
+ WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
+
+ // Call directly into frame view since we need to RunPostLifecycleSteps() too.
+ web_view->MainFrameImpl()
+ ->GetFrame()
+ ->View()
+ ->UpdateAllLifecyclePhasesForTest();
+ RunPendingTasks();
+
+ // The compositing scale factor tells the OOPIF compositor to raster at a
+ // lower scale since the frame is scaled down in the parent webview.
+ EXPECT_EQ(remote_frame->GetCompositingRect(), gfx::Rect(0, 0, 1600, 1200));
+ EXPECT_EQ(remote_frame->GetCompositingScaleFactor(), 0.5f);
+}
+
+TEST_F(WebFrameTest, ZeroScaleRemoteFrameCompositingScaleFactor) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+
+ WebViewImpl* web_view = web_view_helper.GetWebView();
+ web_view->Resize(gfx::Size(800, 800));
+ InitializeWithHTML(*web_view->MainFrameImpl()->GetFrame(), R"HTML(
+ <!DOCTYPE html>
+ <style>
+ iframe {
+ width: 1600;
+ height: 1200;
+ transform-origin: top left;
+ transform: scale(0);
+ border: none;
+ }
+ </style>
+ <iframe></iframe>
+ )HTML");
+
+ WebRemoteFrameImpl* remote_frame = frame_test_helpers::CreateRemote();
+ web_view_helper.LocalMainFrame()->FirstChild()->Swap(remote_frame);
+ remote_frame->SetReplicatedOrigin(
+ WebSecurityOrigin(SecurityOrigin::CreateUniqueOpaque()), false);
+
+ // Call directly into frame view since we need to RunPostLifecycleSteps() too.
+ web_view->MainFrameImpl()
+ ->GetFrame()
+ ->View()
+ ->UpdateAllLifecyclePhasesForTest();
+ RunPendingTasks();
+
+ // The compositing scale factor tells the OOPIF compositor to raster at a
+ // reasonable minimum scale even though the iframe's transform scale is zero.
+ EXPECT_EQ(remote_frame->GetCompositingScaleFactor(), 0.25f);
+}
+
+TEST_F(WebFrameTest, IsPrerendering) {
+ frame_test_helpers::WebViewHelper web_view_helper;
+ web_view_helper.Initialize();
+ auto params = std::make_unique<WebNavigationParams>();
+ params->url = KURL("about:blank");
+ params->is_prerendering = false;
+ web_view_helper.LocalMainFrame()->CommitNavigation(std::move(params),
+ nullptr);
+ WebViewImpl* web_view = web_view_helper.GetWebView();
+
+ EXPECT_FALSE(web_view->MainFrameImpl()
+ ->GetFrame()
+ ->GetDocument()
+ ->Fetcher()
+ ->Context()
+ .IsPrerendering());
+
+ params = std::make_unique<WebNavigationParams>();
+ params->url = KURL("about:blank");
+ params->is_prerendering = true;
+ web_view_helper.LocalMainFrame()->CommitNavigation(std::move(params),
+ nullptr);
+
+ EXPECT_TRUE(web_view->MainFrameImpl()
+ ->GetFrame()
+ ->GetDocument()
+ ->Fetcher()
+ ->Context()
+ .IsPrerendering());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
deleted file mode 100644
index 1aab30ab14d..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ /dev/null
@@ -1,2954 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "cc/trees/layer_tree_host.h"
-#include "cc/trees/swap_promise.h"
-#include "cc/trees/ukm_manager.h"
-#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
-#include "third_party/blink/public/mojom/input/touch_event.mojom-blink.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/scheduler/web_render_widget_scheduling_state.h"
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/web/web_autofill_client.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/public/web/web_plugin.h"
-#include "third_party/blink/public/web/web_settings.h"
-#include "third_party/blink/public/web/web_view_client.h"
-#include "third_party/blink/public/web/web_widget_client.h"
-#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
-#include "third_party/blink/renderer/core/events/current_input_event.h"
-#include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
-#include "third_party/blink/renderer/core/events/wheel_event.h"
-#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
-#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
-#include "third_party/blink/renderer/core/exported/web_view_impl.h"
-#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/remote_frame_client.h"
-#include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
-#include "third_party/blink/renderer/core/html/html_plugin_element.h"
-#include "third_party/blink/renderer/core/html/portal/document_portals.h"
-#include "third_party/blink/renderer/core/html/portal/portal_contents.h"
-#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
-#include "third_party/blink/renderer/core/input/event_handler.h"
-#include "third_party/blink/renderer/core/layout/hit_test_location.h"
-#include "third_party/blink/renderer/core/layout/hit_test_request.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/page/context_menu_controller.h"
-#include "third_party/blink/renderer/core/page/drag_actions.h"
-#include "third_party/blink/renderer/core/page/drag_controller.h"
-#include "third_party/blink/renderer/core/page/drag_data.h"
-#include "third_party/blink/renderer/core/page/focus_controller.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
-#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
-#include "third_party/blink/renderer/core/page/validation_message_client.h"
-#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
-#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
-#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
-#include "third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h"
-#include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
-#include "third_party/blink/renderer/platform/widget/widget_base.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
-#include "ui/gfx/geometry/point_conversions.h"
-
-#if defined(OS_MAC)
-#include "third_party/blink/renderer/core/editing/substring_util.h"
-#include "third_party/blink/renderer/platform/fonts/mac/attributed_string_type_converter.h"
-#include "ui/base/mojom/attributed_string.mojom-blink.h"
-#include "ui/gfx/geometry/point.h"
-#endif
-
-namespace WTF {
-template <>
-struct CrossThreadCopier<blink::WebReportTimeCallback>
- : public CrossThreadCopierByValuePassThrough<blink::WebReportTimeCallback> {
- STATIC_ONLY(CrossThreadCopier);
-};
-
-} // namespace WTF
-
-namespace blink {
-
-namespace {
-
-void ForEachLocalFrameControlledByWidget(
- LocalFrame* frame,
- const base::RepeatingCallback<void(WebLocalFrame*)>& callback) {
- callback.Run(WebLocalFrameImpl::FromFrame(frame));
- for (Frame* child = frame->FirstChild(); child;
- child = child->NextSibling()) {
- if (child->IsLocalFrame()) {
- ForEachLocalFrameControlledByWidget(DynamicTo<LocalFrame>(child),
- callback);
- }
- }
-}
-
-// Iterate the remote children that will be controlled by the widget. Skip over
-// any RemoteFrames have have another LocalFrame root as their parent.
-void ForEachRemoteFrameChildrenControlledByWidget(
- Frame* frame,
- const base::RepeatingCallback<void(RemoteFrame*)>& callback) {
- for (Frame* child = frame->Tree().FirstChild(); child;
- child = child->Tree().NextSibling()) {
- if (auto* remote_frame = DynamicTo<RemoteFrame>(child)) {
- callback.Run(remote_frame);
- ForEachRemoteFrameChildrenControlledByWidget(remote_frame, callback);
- } else if (auto* local_frame = DynamicTo<LocalFrame>(child)) {
- // If iteration arrives at a local root then don't descend as it will be
- // controlled by another widget.
- if (!local_frame->IsLocalRoot()) {
- ForEachRemoteFrameChildrenControlledByWidget(local_frame, callback);
- }
- }
- }
-
- // Iterate on any portals owned by a local frame.
- if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
- if (Document* document = local_frame->GetDocument()) {
- for (PortalContents* portal :
- DocumentPortals::From(*document).GetPortals()) {
- if (RemoteFrame* remote_frame = portal->GetFrame())
- callback.Run(remote_frame);
- }
- }
- }
-}
-
-viz::FrameSinkId GetRemoteFrameSinkId(const HitTestResult& result) {
- Node* node = result.InnerNode();
- auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node);
- if (!frame_owner || !frame_owner->ContentFrame() ||
- !frame_owner->ContentFrame()->IsRemoteFrame())
- return viz::FrameSinkId();
-
- RemoteFrame* remote_frame = To<RemoteFrame>(frame_owner->ContentFrame());
- if (remote_frame->IsIgnoredForHitTest())
- return viz::FrameSinkId();
- LayoutObject* object = result.GetLayoutObject();
- DCHECK(object);
- if (!object->IsBox())
- return viz::FrameSinkId();
-
- IntPoint local_point = RoundedIntPoint(result.LocalPoint());
- if (!To<LayoutBox>(object)->ComputedCSSContentBoxRect().Contains(local_point))
- return viz::FrameSinkId();
-
- return remote_frame->GetFrameSinkId();
-}
-
-} // namespace
-
-bool WebFrameWidgetBase::ignore_input_events_ = false;
-
-WebFrameWidgetBase::WebFrameWidgetBase(
- WebWidgetClient& client,
- CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
- frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- widget,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool hidden,
- bool never_composited,
- bool is_for_child_local_root)
- : widget_base_(std::make_unique<WidgetBase>(this,
- std::move(widget_host),
- std::move(widget),
- task_runner,
- hidden,
- never_composited,
- is_for_child_local_root)),
- client_(&client),
- frame_sink_id_(frame_sink_id) {
- DCHECK(task_runner);
- frame_widget_host_.Bind(std::move(frame_widget_host), task_runner);
- receiver_.Bind(std::move(frame_widget), task_runner);
-}
-
-WebFrameWidgetBase::~WebFrameWidgetBase() {
- // Ensure that Close is called and we aren't releasing |widget_base_| in the
- // destructor.
- // TODO(crbug.com/1139104): This CHECK can be changed to a DCHECK once
- // the issue is solved.
- CHECK(!widget_base_);
-}
-
-void WebFrameWidgetBase::BindLocalRoot(WebLocalFrame& local_root) {
- local_root_ = To<WebLocalFrameImpl>(local_root);
- local_root_->SetFrameWidget(this);
- request_animation_after_delay_timer_.reset(
- new TaskRunnerTimer<WebFrameWidgetBase>(
- local_root.GetTaskRunner(TaskType::kInternalDefault), this,
- &WebFrameWidgetBase::RequestAnimationAfterDelayTimerFired));
-}
-
-void WebFrameWidgetBase::Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) {
- mutator_dispatcher_ = nullptr;
- local_root_->SetFrameWidget(nullptr);
- local_root_ = nullptr;
- client_ = nullptr;
- request_animation_after_delay_timer_.reset();
- widget_base_->Shutdown(std::move(cleanup_runner));
- widget_base_.reset();
- receiver_.reset();
- input_target_receiver_.reset();
-}
-
-WebLocalFrame* WebFrameWidgetBase::LocalRoot() const {
- return local_root_;
-}
-
-WebRect WebFrameWidgetBase::ComputeBlockBound(
- const gfx::Point& point_in_root_frame,
- bool ignore_clipping) const {
- HitTestLocation location(local_root_->GetFrameView()->ConvertFromRootFrame(
- PhysicalOffset(IntPoint(point_in_root_frame))));
- HitTestRequest::HitTestRequestType hit_type =
- HitTestRequest::kReadOnly | HitTestRequest::kActive |
- (ignore_clipping ? HitTestRequest::kIgnoreClipping : 0);
- HitTestResult result =
- local_root_->GetFrame()->GetEventHandler().HitTestResultAtLocation(
- location, hit_type);
- result.SetToShadowHostIfInRestrictedShadowRoot();
-
- Node* node = result.InnerNodeOrImageMapImage();
- if (!node)
- return WebRect();
-
- // Find the block type node based on the hit node.
- // FIXME: This wants to walk flat tree with
- // LayoutTreeBuilderTraversal::parent().
- while (node &&
- (!node->GetLayoutObject() || node->GetLayoutObject()->IsInline()))
- node = LayoutTreeBuilderTraversal::Parent(*node);
-
- // Return the bounding box in the root frame's coordinate space.
- if (node) {
- IntRect absolute_rect = node->GetLayoutObject()->AbsoluteBoundingBoxRect();
- LocalFrame* frame = node->GetDocument().GetFrame();
- return frame->View()->ConvertToRootFrame(absolute_rect);
- }
- return WebRect();
-}
-
-void WebFrameWidgetBase::DragTargetDragEnter(
- const WebDragData& web_drag_data,
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperationsMask operations_allowed,
- uint32_t key_modifiers,
- DragTargetDragEnterCallback callback) {
- DCHECK(!current_drag_data_);
-
- current_drag_data_ = DataObject::Create(web_drag_data);
- operations_allowed_ = operations_allowed;
-
- blink::DragOperation operation = DragTargetDragEnterOrOver(
- point_in_viewport, screen_point, kDragEnter, key_modifiers);
- std::move(callback).Run(operation);
-}
-
-void WebFrameWidgetBase::DragTargetDragOver(
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperationsMask operations_allowed,
- uint32_t key_modifiers,
- DragTargetDragOverCallback callback) {
- operations_allowed_ = operations_allowed;
-
- blink::DragOperation operation = DragTargetDragEnterOrOver(
- point_in_viewport, screen_point, kDragOver, key_modifiers);
- std::move(callback).Run(operation);
-}
-
-void WebFrameWidgetBase::DragTargetDragLeave(
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point) {
- DCHECK(current_drag_data_);
-
- // TODO(paulmeyer): It shouldn't be possible for |current_drag_data_| to be
- // null here, but this is somehow happening (rarely). This suggests that in
- // some cases drag-leave is happening before drag-enter, which should be
- // impossible. This needs to be investigated further. Once fixed, the extra
- // check for |!current_drag_data_| should be removed. (crbug.com/671152)
- if (IgnoreInputEvents() || !current_drag_data_) {
- CancelDrag();
- return;
- }
-
- gfx::PointF point_in_root_frame(ViewportToRootFrame(point_in_viewport));
- DragData drag_data(current_drag_data_.Get(), FloatPoint(point_in_root_frame),
- FloatPoint(screen_point), operations_allowed_);
-
- GetPage()->GetDragController().DragExited(&drag_data,
- *local_root_->GetFrame());
-
- // FIXME: why is the drag scroll timer not stopped here?
-
- drag_operation_ = kDragOperationNone;
- current_drag_data_ = nullptr;
-}
-
-void WebFrameWidgetBase::DragTargetDrop(const WebDragData& web_drag_data,
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- uint32_t key_modifiers) {
- gfx::PointF point_in_root_frame(ViewportToRootFrame(point_in_viewport));
-
- DCHECK(current_drag_data_);
- current_drag_data_ = DataObject::Create(web_drag_data);
-
- // If this webview transitions from the "drop accepting" state to the "not
- // accepting" state, then our IPC message reply indicating that may be in-
- // flight, or else delayed by javascript processing in this webview. If a
- // drop happens before our IPC reply has reached the browser process, then
- // the browser forwards the drop to this webview. So only allow a drop to
- // proceed if our webview m_dragOperation state is not DragOperationNone.
-
- if (drag_operation_ == kDragOperationNone) {
- // IPC RACE CONDITION: do not allow this drop.
- DragTargetDragLeave(point_in_viewport, screen_point);
- return;
- }
-
- if (!IgnoreInputEvents()) {
- current_drag_data_->SetModifiers(key_modifiers);
- DragData drag_data(current_drag_data_.Get(),
- FloatPoint(point_in_root_frame),
- FloatPoint(screen_point), operations_allowed_);
-
- GetPage()->GetDragController().PerformDrag(&drag_data,
- *local_root_->GetFrame());
- }
- drag_operation_ = kDragOperationNone;
- current_drag_data_ = nullptr;
-}
-
-void WebFrameWidgetBase::DragSourceEndedAt(const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperation operation) {
- if (!local_root_) {
- // We should figure out why |local_root_| could be nullptr
- // (https://crbug.com/792345).
- return;
- }
-
- if (IgnoreInputEvents()) {
- CancelDrag();
- return;
- }
- gfx::PointF point_in_root_frame(
- GetPage()->GetVisualViewport().ViewportToRootFrame(
- FloatPoint(point_in_viewport)));
-
- WebMouseEvent fake_mouse_move(
- WebInputEvent::Type::kMouseMove, point_in_root_frame, screen_point,
- WebPointerProperties::Button::kLeft, 0, WebInputEvent::kNoModifiers,
- base::TimeTicks::Now());
- fake_mouse_move.SetFrameScale(1);
- local_root_->GetFrame()->GetEventHandler().DragSourceEndedAt(fake_mouse_move,
- operation);
-}
-
-void WebFrameWidgetBase::DragSourceSystemDragEnded() {
- CancelDrag();
-}
-
-void WebFrameWidgetBase::SetBackgroundOpaque(bool opaque) {
- if (opaque) {
- View()->ClearBaseBackgroundColorOverride();
- View()->ClearBackgroundColorOverride();
- } else {
- View()->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
- View()->SetBackgroundColorOverride(SK_ColorTRANSPARENT);
- }
-}
-
-void WebFrameWidgetBase::SetTextDirection(base::i18n::TextDirection direction) {
- LocalFrame* focusedFrame = FocusedLocalFrameInWidget();
- if (focusedFrame)
- focusedFrame->SetTextDirection(direction);
-}
-
-#if defined(OS_MAC)
-void WebFrameWidgetBase::GetStringAtPoint(const gfx::Point& point_in_local_root,
- GetStringAtPointCallback callback) {
- gfx::Point baseline_point;
- ui::mojom::blink::AttributedStringPtr attributed_string = nullptr;
- NSAttributedString* string = SubstringUtil::AttributedWordAtPoint(
- this, point_in_local_root, baseline_point);
- if (string)
- attributed_string = ui::mojom::blink::AttributedString::From(string);
-
- std::move(callback).Run(std::move(attributed_string), baseline_point);
-}
-#endif
-
-void WebFrameWidgetBase::BindWidgetCompositor(
- mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) {
- widget_base_->BindWidgetCompositor(std::move(receiver));
-}
-
-void WebFrameWidgetBase::BindInputTargetClient(
- mojo::PendingReceiver<viz::mojom::blink::InputTargetClient> receiver) {
- DCHECK(!input_target_receiver_.is_bound());
- input_target_receiver_.Bind(
- std::move(receiver),
- local_root_->GetTaskRunner(TaskType::kInternalDefault));
-}
-
-void WebFrameWidgetBase::FrameSinkIdAt(const gfx::PointF& point,
- const uint64_t trace_id,
- FrameSinkIdAtCallback callback) {
- TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Event.Pipeline",
- TRACE_ID_GLOBAL(trace_id),
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
- "step", "FrameSinkIdAt");
-
- gfx::PointF local_point;
- viz::FrameSinkId id = GetFrameSinkIdAtPoint(point, &local_point);
- std::move(callback).Run(id, local_point);
-}
-
-viz::FrameSinkId WebFrameWidgetBase::GetFrameSinkIdAtPoint(
- const gfx::PointF& point_in_dips,
- gfx::PointF* local_point_in_dips) {
- HitTestResult result =
- CoreHitTestResultAt(widget_base_->DIPsToBlinkSpace(point_in_dips));
-
- Node* result_node = result.InnerNode();
- *local_point_in_dips = gfx::PointF(point_in_dips);
-
- // TODO(crbug.com/797828): When the node is null the caller may
- // need to do extra checks. Like maybe update the layout and then
- // call the hit-testing API. Either way it might be better to have
- // a DCHECK for the node rather than a null check here.
- if (!result_node) {
- return frame_sink_id_;
- }
-
- viz::FrameSinkId remote_frame_sink_id = GetRemoteFrameSinkId(result);
- if (remote_frame_sink_id.is_valid()) {
- FloatPoint local_point = FloatPoint(result.LocalPoint());
- LayoutObject* object = result.GetLayoutObject();
- if (auto* box = DynamicTo<LayoutBox>(object))
- local_point.MoveBy(-FloatPoint(box->PhysicalContentBoxOffset()));
-
- *local_point_in_dips =
- widget_base_->BlinkSpaceToDIPs(gfx::PointF(local_point));
- return remote_frame_sink_id;
- }
-
- // Return the FrameSinkId for the current widget if the point did not hit
- // test to a remote frame, or the point is outside of the remote frame's
- // content box, or the remote frame doesn't have a valid FrameSinkId yet.
- return frame_sink_id_;
-}
-
-gfx::RectF WebFrameWidgetBase::BlinkSpaceToDIPs(const gfx::RectF& rect) {
- return widget_base_->BlinkSpaceToDIPs(rect);
-}
-
-gfx::Rect WebFrameWidgetBase::BlinkSpaceToEnclosedDIPs(const gfx::Rect& rect) {
- return widget_base_->BlinkSpaceToEnclosedDIPs(rect);
-}
-
-gfx::Size WebFrameWidgetBase::BlinkSpaceToFlooredDIPs(const gfx::Size& size) {
- return widget_base_->BlinkSpaceToFlooredDIPs(size);
-}
-
-gfx::RectF WebFrameWidgetBase::DIPsToBlinkSpace(const gfx::RectF& rect) {
- return widget_base_->DIPsToBlinkSpace(rect);
-}
-
-gfx::PointF WebFrameWidgetBase::DIPsToBlinkSpace(const gfx::PointF& point) {
- return widget_base_->DIPsToBlinkSpace(point);
-}
-
-gfx::Point WebFrameWidgetBase::DIPsToRoundedBlinkSpace(
- const gfx::Point& point) {
- return widget_base_->DIPsToRoundedBlinkSpace(point);
-}
-
-float WebFrameWidgetBase::DIPsToBlinkSpace(float scalar) {
- return widget_base_->DIPsToBlinkSpace(scalar);
-}
-
-void WebFrameWidgetBase::SetActive(bool active) {
- View()->SetIsActive(active);
-}
-
-void WebFrameWidgetBase::HandleMouseDown(LocalFrame& main_frame,
- const WebMouseEvent& event) {
- WebViewImpl* view_impl = View();
- // If there is a popup open, close it as the user is clicking on the page
- // (outside of the popup). We also save it so we can prevent a click on an
- // element from immediately reopening the same popup.
- scoped_refptr<WebPagePopupImpl> page_popup;
- if (event.button == WebMouseEvent::Button::kLeft) {
- page_popup = view_impl->GetPagePopup();
- view_impl->CancelPagePopup();
- }
-
- // Take capture on a mouse down on a plugin so we can send it mouse events.
- // If the hit node is a plugin but a scrollbar is over it don't start mouse
- // capture because it will interfere with the scrollbar receiving events.
- PhysicalOffset point(LayoutUnit(event.PositionInWidget().x()),
- LayoutUnit(event.PositionInWidget().y()));
- if (event.button == WebMouseEvent::Button::kLeft) {
- HitTestLocation location(
- LocalRootImpl()->GetFrameView()->ConvertFromRootFrame(point));
- HitTestResult result(
- LocalRootImpl()->GetFrame()->GetEventHandler().HitTestResultAtLocation(
- location));
- result.SetToShadowHostIfInRestrictedShadowRoot();
- Node* hit_node = result.InnerNode();
- auto* html_element = DynamicTo<HTMLElement>(hit_node);
- if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
- hit_node->GetLayoutObject()->IsEmbeddedObject() && html_element &&
- html_element->IsPluginElement()) {
- mouse_capture_element_ = To<HTMLPlugInElement>(hit_node);
- SetMouseCapture(true);
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("input", "capturing mouse",
- TRACE_ID_LOCAL(this));
- }
- }
-
- PageWidgetEventHandler::HandleMouseDown(main_frame, event);
- // PageWidgetEventHandler may have detached the frame.
- if (!LocalRootImpl())
- return;
-
- if (view_impl->GetPagePopup() && page_popup &&
- view_impl->GetPagePopup()->HasSamePopupClient(page_popup.get())) {
- // That click triggered a page popup that is the same as the one we just
- // closed. It needs to be closed.
- view_impl->CancelPagePopup();
- }
-
- // Dispatch the contextmenu event regardless of if the click was swallowed.
- if (!GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
-#if defined(OS_MAC)
- if (event.button == WebMouseEvent::Button::kRight ||
- (event.button == WebMouseEvent::Button::kLeft &&
- event.GetModifiers() & WebMouseEvent::kControlKey))
- MouseContextMenu(event);
-#else
- if (event.button == WebMouseEvent::Button::kRight)
- MouseContextMenu(event);
-#endif
- }
-}
-
-void WebFrameWidgetBase::MouseContextMenu(const WebMouseEvent& event) {
- GetPage()->GetContextMenuController().ClearContextMenu();
-
- WebMouseEvent transformed_event =
- TransformWebMouseEvent(LocalRootImpl()->GetFrameView(), event);
- transformed_event.menu_source_type = kMenuSourceMouse;
-
- // Find the right target frame. See issue 1186900.
- HitTestResult result = HitTestResultForRootFramePos(
- FloatPoint(transformed_event.PositionInRootFrame()));
- Frame* target_frame;
- if (result.InnerNodeOrImageMapImage())
- target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
- else
- target_frame = GetPage()->GetFocusController().FocusedOrMainFrame();
-
- // This will need to be changed to a nullptr check when focus control
- // is refactored, at which point focusedOrMainFrame will never return a
- // RemoteFrame.
- // See https://crbug.com/341918.
- LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
- if (!target_local_frame)
- return;
-
- {
- ContextMenuAllowedScope scope;
- target_local_frame->GetEventHandler().SendContextMenuEvent(
- transformed_event);
- }
- // Actually showing the context menu is handled by the ContextMenuClient
- // implementation...
-}
-
-WebInputEventResult WebFrameWidgetBase::HandleMouseUp(
- LocalFrame& main_frame,
- const WebMouseEvent& event) {
- WebInputEventResult result =
- PageWidgetEventHandler::HandleMouseUp(main_frame, event);
- // PageWidgetEventHandler may have detached the frame.
- if (!LocalRootImpl())
- return result;
-
- if (GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
- // Dispatch the contextmenu event regardless of if the click was swallowed.
- // On Mac/Linux, we handle it on mouse down, not up.
- if (event.button == WebMouseEvent::Button::kRight)
- MouseContextMenu(event);
- }
- return result;
-}
-
-WebInputEventResult WebFrameWidgetBase::HandleMouseWheel(
- LocalFrame& frame,
- const WebMouseWheelEvent& event) {
- View()->CancelPagePopup();
- return PageWidgetEventHandler::HandleMouseWheel(frame, event);
- // PageWidgetEventHandler may have detached the frame.
-}
-
-WebInputEventResult WebFrameWidgetBase::HandleCharEvent(
- const WebKeyboardEvent& event) {
- DCHECK_EQ(event.GetType(), WebInputEvent::Type::kChar);
-
- // Please refer to the comments explaining the m_suppressNextKeypressEvent
- // member. The m_suppressNextKeypressEvent is set if the KeyDown is
- // handled by Webkit. A keyDown event is typically associated with a
- // keyPress(char) event and a keyUp event. We reset this flag here as it
- // only applies to the current keyPress event.
- bool suppress = suppress_next_keypress_event_;
- suppress_next_keypress_event_ = false;
-
- // If there is a popup open, it should be the one processing the event,
- // not the page.
- scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
- if (page_popup)
- return page_popup->HandleKeyEvent(event);
-
- LocalFrame* frame = To<LocalFrame>(FocusedCoreFrame());
- if (!frame) {
- return suppress ? WebInputEventResult::kHandledSuppressed
- : WebInputEventResult::kNotHandled;
- }
-
- EventHandler& handler = frame->GetEventHandler();
-
- if (!event.IsCharacterKey())
- return WebInputEventResult::kHandledSuppressed;
-
- // Accesskeys are triggered by char events and can't be suppressed.
- // It is unclear whether a keypress should be dispatched as well
- // crbug.com/563507
- if (handler.HandleAccessKey(event))
- return WebInputEventResult::kHandledSystem;
-
- // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
- // the eventHandler::keyEvent. We mimic this behavior on all platforms since
- // for now we are converting other platform's key events to windows key
- // events.
- if (event.is_system_key)
- return WebInputEventResult::kNotHandled;
-
- if (suppress)
- return WebInputEventResult::kHandledSuppressed;
-
- WebInputEventResult result = handler.KeyEvent(event);
- if (result != WebInputEventResult::kNotHandled)
- return result;
-
- return WebInputEventResult::kNotHandled;
-}
-
-void WebFrameWidgetBase::CancelDrag() {
- // It's possible for this to be called while we're not doing a drag if
- // it's from a previous page that got unloaded.
- if (!doing_drag_and_drop_)
- return;
- GetPage()->GetDragController().DragEnded();
- doing_drag_and_drop_ = false;
-}
-
-void WebFrameWidgetBase::StartDragging(const WebDragData& drag_data,
- DragOperationsMask operations_allowed,
- const SkBitmap& drag_image,
- const gfx::Point& drag_image_offset) {
- doing_drag_and_drop_ = true;
- if (Client()->InterceptStartDragging(drag_data, operations_allowed,
- drag_image, drag_image_offset)) {
- return;
- }
-
- gfx::Point offset_in_dips =
- widget_base_->BlinkSpaceToFlooredDIPs(drag_image_offset);
- GetAssociatedFrameWidgetHost()->StartDragging(
- drag_data, operations_allowed, drag_image,
- gfx::Vector2d(offset_in_dips.x(), offset_in_dips.y()),
- possible_drag_event_info_.Clone());
-}
-
-DragOperation WebFrameWidgetBase::DragTargetDragEnterOrOver(
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragAction drag_action,
- uint32_t key_modifiers) {
- DCHECK(current_drag_data_);
- // TODO(paulmeyer): It shouldn't be possible for |m_currentDragData| to be
- // null here, but this is somehow happening (rarely). This suggests that in
- // some cases drag-over is happening before drag-enter, which should be
- // impossible. This needs to be investigated further. Once fixed, the extra
- // check for |!m_currentDragData| should be removed. (crbug.com/671504)
- if (IgnoreInputEvents() || !current_drag_data_) {
- CancelDrag();
- return kDragOperationNone;
- }
-
- FloatPoint point_in_root_frame(ViewportToRootFrame(point_in_viewport));
-
- current_drag_data_->SetModifiers(key_modifiers);
- DragData drag_data(current_drag_data_.Get(), FloatPoint(point_in_root_frame),
- FloatPoint(screen_point), operations_allowed_);
-
- DragOperation drag_operation =
- GetPage()->GetDragController().DragEnteredOrUpdated(
- &drag_data, *local_root_->GetFrame());
-
- // Mask the drag operation against the drag source's allowed
- // operations.
- if (!(drag_operation & drag_data.DraggingSourceOperationMask()))
- drag_operation = kDragOperationNone;
-
- drag_operation_ = drag_operation;
-
- return drag_operation_;
-}
-
-void WebFrameWidgetBase::SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) {
- if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
- return;
-
- Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
- scroll_latched_element_id);
- if (target_node) {
- target_node->GetDocument().EnqueueOverscrollEventForNode(
- target_node, overscroll_delta.x(), overscroll_delta.y());
- }
-}
-
-void WebFrameWidgetBase::SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) {
- if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
- return;
-
- Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
- scroll_latched_element_id);
- if (target_node)
- target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
-}
-
-WebInputMethodController*
-WebFrameWidgetBase::GetActiveWebInputMethodController() const {
- WebLocalFrameImpl* local_frame =
- WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
- return local_frame ? local_frame->GetInputMethodController() : nullptr;
-}
-
-gfx::PointF WebFrameWidgetBase::ViewportToRootFrame(
- const gfx::PointF& point_in_viewport) const {
- return GetPage()->GetVisualViewport().ViewportToRootFrame(
- FloatPoint(point_in_viewport));
-}
-
-WebViewImpl* WebFrameWidgetBase::View() const {
- return local_root_->ViewImpl();
-}
-
-Page* WebFrameWidgetBase::GetPage() const {
- return View()->GetPage();
-}
-
-mojom::blink::FrameWidgetHost*
-WebFrameWidgetBase::GetAssociatedFrameWidgetHost() const {
- return frame_widget_host_.get();
-}
-
-void WebFrameWidgetBase::RequestDecode(
- const PaintImage& image,
- base::OnceCallback<void(bool)> callback) {
- widget_base_->LayerTreeHost()->QueueImageDecode(image, std::move(callback));
-
- // In web tests the request does not actually cause a commit, because the
- // compositor is scheduled by the test runner to avoid flakiness. So for this
- // case we must request a main frame.
- Client()->ScheduleAnimationForWebTests();
-}
-
-void WebFrameWidgetBase::Trace(Visitor* visitor) const {
- visitor->Trace(local_root_);
- visitor->Trace(current_drag_data_);
- visitor->Trace(frame_widget_host_);
- visitor->Trace(receiver_);
- visitor->Trace(input_target_receiver_);
- visitor->Trace(mouse_capture_element_);
-}
-
-void WebFrameWidgetBase::SetNeedsRecalculateRasterScales() {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->SetNeedsRecalculateRasterScales();
-}
-
-void WebFrameWidgetBase::SetBackgroundColor(SkColor color) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->set_background_color(color);
-}
-
-void WebFrameWidgetBase::SetOverscrollBehavior(
- const cc::OverscrollBehavior& overscroll_behavior) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->SetOverscrollBehavior(overscroll_behavior);
-}
-
-void WebFrameWidgetBase::RegisterSelection(cc::LayerSelection selection) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->RegisterSelection(selection);
-}
-
-void WebFrameWidgetBase::StartPageScaleAnimation(
- const gfx::Vector2d& destination,
- bool use_anchor,
- float new_page_scale,
- base::TimeDelta duration) {
- widget_base_->LayerTreeHost()->StartPageScaleAnimation(
- destination, use_anchor, new_page_scale, duration);
-}
-
-void WebFrameWidgetBase::RequestBeginMainFrameNotExpected(bool request) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->RequestBeginMainFrameNotExpected(request);
-}
-
-void WebFrameWidgetBase::DidCommitAndDrawCompositorFrame() {
- ForEachLocalFrameControlledByWidget(
- local_root_->GetFrame(),
- WTF::BindRepeating([](WebLocalFrame* local_frame) {
- local_frame->Client()->DidCommitAndDrawCompositorFrame();
- }));
-}
-
-void WebFrameWidgetBase::DidObserveFirstScrollDelay(
- base::TimeDelta first_scroll_delay,
- base::TimeTicks first_scroll_timestamp) {
- if (!local_root_ || !(local_root_->GetFrame()) ||
- !(local_root_->GetFrame()->GetDocument())) {
- return;
- }
- InteractiveDetector* interactive_detector =
- InteractiveDetector::From(*(local_root_->GetFrame()->GetDocument()));
- if (interactive_detector) {
- interactive_detector->DidObserveFirstScrollDelay(first_scroll_delay,
- first_scroll_timestamp);
- }
-}
-
-std::unique_ptr<cc::LayerTreeFrameSink>
-WebFrameWidgetBase::AllocateNewLayerTreeFrameSink() {
- return Client()->AllocateNewLayerTreeFrameSink();
-}
-
-void WebFrameWidgetBase::DidBeginMainFrame() {
- Client()->DidBeginMainFrame();
- DCHECK(LocalRootImpl()->GetFrame());
- PageWidgetDelegate::DidBeginFrame(*LocalRootImpl()->GetFrame());
-}
-
-void WebFrameWidgetBase::WillBeginMainFrame() {
- Client()->WillBeginMainFrame();
-}
-
-void WebFrameWidgetBase::DidCompletePageScaleAnimation() {
- // Page scale animations only happen on the main frame.
- DCHECK(ForMainFrame());
- if (auto* focused_frame = View()->FocusedFrame()) {
- if (focused_frame->AutofillClient())
- focused_frame->AutofillClient()->DidCompleteFocusChangeInFrame();
- }
-}
-
-void WebFrameWidgetBase::ScheduleAnimation() {
- Client()->ScheduleAnimation();
-}
-
-bool WebFrameWidgetBase::ShouldAckSyntheticInputImmediately() {
- // TODO(bokan): The RequestPresentation API appears not to function in VR. As
- // a short term workaround for https://crbug.com/940063, ACK input
- // immediately rather than using RequestPresentation.
- if (GetPage()->GetSettings().GetImmersiveModeEnabled())
- return true;
- return false;
-}
-
-void WebFrameWidgetBase::UpdateVisualProperties(
- const VisualProperties& visual_properties) {
- SetZoomLevel(visual_properties.zoom_level);
-
- // TODO(danakj): In order to synchronize updates between local roots, the
- // display mode should be propagated to RenderFrameProxies and down through
- // their RenderWidgetHosts to child WebFrameWidgetBase via the
- // VisualProperties waterfall, instead of coming to each WebFrameWidgetBase
- // independently.
- // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode
- SetDisplayMode(visual_properties.display_mode);
-
- SetAutoResizeMode(visual_properties.auto_resize_enabled,
- visual_properties.min_size_for_auto_resize,
- visual_properties.max_size_for_auto_resize,
- visual_properties.screen_info.device_scale_factor);
-
- bool capture_sequence_number_changed =
- visual_properties.capture_sequence_number !=
- last_capture_sequence_number_;
- if (capture_sequence_number_changed) {
- last_capture_sequence_number_ = visual_properties.capture_sequence_number;
-
- // Send the capture sequence number to RemoteFrames that are below the
- // local root for this widget.
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](uint32_t capture_sequence_number, RemoteFrame* remote_frame) {
- remote_frame->Client()->UpdateCaptureSequenceNumber(
- capture_sequence_number);
- },
- visual_properties.capture_sequence_number));
- }
-
- if (!View()->AutoResizeMode()) {
- if (visual_properties.is_fullscreen_granted != is_fullscreen_granted_) {
- is_fullscreen_granted_ = visual_properties.is_fullscreen_granted;
- if (is_fullscreen_granted_)
- View()->DidEnterFullscreen();
- else
- View()->DidExitFullscreen();
- }
- }
-
- gfx::Size old_visible_viewport_size_in_dips =
- widget_base_->VisibleViewportSizeInDIPs();
- ApplyVisualPropertiesSizing(visual_properties);
-
- if (old_visible_viewport_size_in_dips !=
- widget_base_->VisibleViewportSizeInDIPs()) {
- ForEachLocalFrameControlledByWidget(
- local_root_->GetFrame(),
- WTF::BindRepeating([](WebLocalFrame* local_frame) {
- local_frame->Client()->ResetHasScrolledFocusedEditableIntoView();
- }));
-
- // Propagate changes down to child local root RenderWidgets and
- // BrowserPlugins in other frame trees/processes.
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](const gfx::Size& visible_viewport_size, RemoteFrame* remote_frame) {
- remote_frame->Client()->DidChangeVisibleViewportSize(
- visible_viewport_size);
- },
- widget_base_->VisibleViewportSizeInDIPs()));
- }
-
- // All non-top-level Widgets (child local-root frames, Portals, GuestViews,
- // etc.) propagate and consume the page scale factor as "external", meaning
- // that it comes from the top level widget's page scale.
- if (!ForTopLevelFrame()) {
- // The main frame controls the page scale factor, from blink. For other
- // frame widgets, the page scale is received from its parent as part of
- // the visual properties here. While blink doesn't need to know this
- // page scale factor outside the main frame, the compositor does in
- // order to produce its output at the correct scale.
- widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
- visual_properties.page_scale_factor,
- visual_properties.is_pinch_gesture_active);
-
- NotifyPageScaleFactorChanged(visual_properties.page_scale_factor,
- visual_properties.is_pinch_gesture_active);
- } else {
- // Ensure the external scale factor in top-level widgets is reset as it may
- // be leftover from when a widget was nested and was promoted to top level
- // (e.g. portal activation).
- widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
- 1.f,
- /*is_pinch_gesture_active=*/false);
- }
-
- // TODO(crbug.com/939118): ScrollFocusedNodeIntoViewForWidget does not work
- // when the focused node is inside an OOPIF. This code path where
- // scroll_focused_node_into_view is set is used only for WebView, crbug
- // 939118 tracks fixing webviews to not use scroll_focused_node_into_view.
- if (visual_properties.scroll_focused_node_into_view)
- ScrollFocusedEditableElementIntoView();
-}
-
-void WebFrameWidgetBase::ScheduleAnimationForWebTests() {
- Client()->ScheduleAnimationForWebTests();
-}
-
-int WebFrameWidgetBase::GetLayerTreeId() {
- if (!View()->does_composite())
- return 0;
- return widget_base_->LayerTreeHost()->GetId();
-}
-
-void WebFrameWidgetBase::SetHaveScrollEventHandlers(bool has_handlers) {
- widget_base_->LayerTreeHost()->SetHaveScrollEventHandlers(has_handlers);
-}
-
-void WebFrameWidgetBase::SetEventListenerProperties(
- cc::EventListenerClass listener_class,
- cc::EventListenerProperties listener_properties) {
- widget_base_->LayerTreeHost()->SetEventListenerProperties(
- listener_class, listener_properties);
-
- if (listener_class == cc::EventListenerClass::kTouchStartOrMove ||
- listener_class == cc::EventListenerClass::kTouchEndOrCancel) {
- bool has_touch_handlers =
- EventListenerProperties(cc::EventListenerClass::kTouchStartOrMove) !=
- cc::EventListenerProperties::kNone ||
- EventListenerProperties(cc::EventListenerClass::kTouchEndOrCancel) !=
- cc::EventListenerProperties::kNone;
- if (!has_touch_handlers_ || *has_touch_handlers_ != has_touch_handlers) {
- has_touch_handlers_ = has_touch_handlers;
-
- // Can be NULL when running tests.
- if (auto* scheduler_state = widget_base_->RendererWidgetSchedulingState())
- scheduler_state->SetHasTouchHandler(has_touch_handlers);
- // Set touch event consumers based on whether there are touch event
- // handlers or the page has hit testable scrollbars.
- auto touch_event_consumers = mojom::blink::TouchEventConsumers::New(
- has_touch_handlers, GetPage()->GetScrollbarTheme().AllowsHitTest());
- frame_widget_host_->SetHasTouchEventConsumers(
- std::move(touch_event_consumers));
- }
- } else if (listener_class == cc::EventListenerClass::kPointerRawUpdate) {
- SetHasPointerRawUpdateEventHandlers(listener_properties !=
- cc::EventListenerProperties::kNone);
- }
-}
-
-cc::EventListenerProperties WebFrameWidgetBase::EventListenerProperties(
- cc::EventListenerClass listener_class) const {
- return widget_base_->LayerTreeHost()->event_listener_properties(
- listener_class);
-}
-
-mojom::blink::DisplayMode WebFrameWidgetBase::DisplayMode() const {
- return display_mode_;
-}
-
-const WebVector<gfx::Rect>& WebFrameWidgetBase::WindowSegments() const {
- return window_segments_;
-}
-
-void WebFrameWidgetBase::StartDeferringCommits(base::TimeDelta timeout) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->StartDeferringCommits(timeout);
-}
-
-void WebFrameWidgetBase::StopDeferringCommits(
- cc::PaintHoldingCommitTrigger triggger) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->StopDeferringCommits(triggger);
-}
-
-std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
-WebFrameWidgetBase::DeferMainFrameUpdate() {
- return widget_base_->LayerTreeHost()->DeferMainFrameUpdate();
-}
-
-void WebFrameWidgetBase::SetBrowserControlsShownRatio(float top_ratio,
- float bottom_ratio) {
- widget_base_->LayerTreeHost()->SetBrowserControlsShownRatio(top_ratio,
- bottom_ratio);
-}
-
-void WebFrameWidgetBase::SetBrowserControlsParams(
- cc::BrowserControlsParams params) {
- widget_base_->LayerTreeHost()->SetBrowserControlsParams(params);
-}
-
-cc::LayerTreeDebugState WebFrameWidgetBase::GetLayerTreeDebugState() {
- return widget_base_->LayerTreeHost()->GetDebugState();
-}
-
-void WebFrameWidgetBase::SetLayerTreeDebugState(
- const cc::LayerTreeDebugState& state) {
- widget_base_->LayerTreeHost()->SetDebugState(state);
-}
-
-void WebFrameWidgetBase::SynchronouslyCompositeForTesting(
- base::TimeTicks frame_time) {
- widget_base_->LayerTreeHost()->CompositeForTest(frame_time, false);
-}
-
-// TODO(665924): Remove direct dispatches of mouse events from
-// PointerLockController, instead passing them through EventHandler.
-void WebFrameWidgetBase::PointerLockMouseEvent(
- const WebCoalescedInputEvent& coalesced_event) {
- const WebInputEvent& input_event = coalesced_event.Event();
- const WebMouseEvent& mouse_event =
- static_cast<const WebMouseEvent&>(input_event);
- WebMouseEvent transformed_event =
- TransformWebMouseEvent(local_root_->GetFrameView(), mouse_event);
-
- AtomicString event_type;
- switch (input_event.GetType()) {
- case WebInputEvent::Type::kMouseDown:
- event_type = event_type_names::kMousedown;
- if (!GetPage() || !GetPage()->GetPointerLockController().GetElement())
- break;
- LocalFrame::NotifyUserActivation(
- GetPage()
- ->GetPointerLockController()
- .GetElement()
- ->GetDocument()
- .GetFrame(),
- mojom::blink::UserActivationNotificationType::kInteraction);
- break;
- case WebInputEvent::Type::kMouseUp:
- event_type = event_type_names::kMouseup;
- break;
- case WebInputEvent::Type::kMouseMove:
- event_type = event_type_names::kMousemove;
- break;
- default:
- NOTREACHED() << input_event.GetType();
- }
-
- if (GetPage()) {
- GetPage()->GetPointerLockController().DispatchLockedMouseEvent(
- transformed_event,
- TransformWebMouseEventVector(
- local_root_->GetFrameView(),
- coalesced_event.GetCoalescedEventsPointers()),
- TransformWebMouseEventVector(
- local_root_->GetFrameView(),
- coalesced_event.GetPredictedEventsPointers()),
- event_type);
- }
-}
-bool WebFrameWidgetBase::IsPointerLocked() {
- if (GetPage()) {
- return GetPage()->GetPointerLockController().IsPointerLocked();
- }
- return false;
-}
-
-void WebFrameWidgetBase::ShowContextMenu(
- ui::mojom::blink::MenuSourceType source_type,
- const gfx::Point& location) {
- host_context_menu_location_ = location;
-
- if (!GetPage())
- return;
- GetPage()->GetContextMenuController().ClearContextMenu();
- {
- ContextMenuAllowedScope scope;
- if (LocalFrame* focused_frame =
- GetPage()->GetFocusController().FocusedFrame()) {
- focused_frame->GetEventHandler().ShowNonLocatedContextMenu(
- nullptr, static_cast<blink::WebMenuSourceType>(source_type));
- }
- }
- host_context_menu_location_.reset();
-}
-
-base::Optional<gfx::Point>
-WebFrameWidgetBase::GetAndResetContextMenuLocation() {
- return std::move(host_context_menu_location_);
-}
-
-void WebFrameWidgetBase::SetZoomLevel(double zoom_level) {
- View()->SetZoomLevel(zoom_level);
-
- // Part of the UpdateVisualProperties dance we send the zoom level to
- // RemoteFrames that are below the local root for this widget.
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](double zoom_level, RemoteFrame* remote_frame) {
- remote_frame->Client()->ZoomLevelChanged(zoom_level);
- },
- zoom_level));
-}
-
-LocalFrame* WebFrameWidgetBase::FocusedLocalFrameInWidget() const {
- if (!local_root_) {
- // WebFrameWidget is created in the call to CreateFrame. The corresponding
- // RenderWidget, however, might not swap in right away (InstallNewDocument()
- // will lead to it swapping in). During this interval local_root_ is nullptr
- // (see https://crbug.com/792345).
- return nullptr;
- }
-
- LocalFrame* frame = GetPage()->GetFocusController().FocusedFrame();
- return (frame && frame->LocalFrameRoot() == local_root_->GetFrame())
- ? frame
- : nullptr;
-}
-
-WebLocalFrame* WebFrameWidgetBase::FocusedWebLocalFrameInWidget() const {
- return WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
-}
-
-cc::LayerTreeHost* WebFrameWidgetBase::InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
- cc::TaskGraphRunner* task_graph_runner,
- bool for_child_local_root_frame,
- const ScreenInfo& screen_info,
- std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
- const cc::LayerTreeSettings* settings) {
- widget_base_->InitializeCompositing(
- main_thread_scheduler, task_graph_runner, for_child_local_root_frame,
- screen_info, std::move(ukm_recorder_factory), settings);
- GetPage()->AnimationHostInitialized(*AnimationHost(),
- GetLocalFrameViewForAnimationScrolling());
- return widget_base_->LayerTreeHost();
-}
-
-void WebFrameWidgetBase::SetCompositorVisible(bool visible) {
- widget_base_->SetCompositorVisible(visible);
-}
-
-void WebFrameWidgetBase::BeginMainFrame(base::TimeTicks last_frame_time) {
- TRACE_EVENT1("blink", "WebFrameWidgetBase::BeginMainFrame", "frameTime",
- last_frame_time);
- DCHECK(!last_frame_time.is_null());
- CHECK(LocalRootImpl());
-
- // Dirty bit on MouseEventManager is not cleared in OOPIFs after scroll
- // or layout changes. Ensure the hover state is recomputed if necessary.
- LocalRootImpl()
- ->GetFrame()
- ->GetEventHandler()
- .RecomputeMouseHoverStateIfNeeded();
-
- // Adjusting frame anchor only happens on the main frame.
- if (ForMainFrame()) {
- if (LocalFrameView* view = LocalRootImpl()->GetFrameView()) {
- if (FragmentAnchor* anchor = view->GetFragmentAnchor())
- anchor->PerformPreRafActions();
- }
- }
-
- base::Optional<LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer> ukm_timer;
- if (WidgetBase::ShouldRecordBeginMainFrameMetrics()) {
- ukm_timer.emplace(LocalRootImpl()
- ->GetFrame()
- ->View()
- ->EnsureUkmAggregator()
- .GetScopedTimer(LocalFrameUkmAggregator::kAnimate));
- }
-
- PageWidgetDelegate::Animate(*GetPage(), last_frame_time);
- // Animate can cause the local frame to detach.
- if (!LocalRootImpl())
- return;
-
- GetPage()->GetValidationMessageClient().LayoutOverlay();
-}
-
-void WebFrameWidgetBase::BeginCommitCompositorFrame() {
- commit_compositor_frame_start_time_.emplace(base::TimeTicks::Now());
-}
-
-void WebFrameWidgetBase::EndCommitCompositorFrame(
- base::TimeTicks commit_start_time) {
- DCHECK(commit_compositor_frame_start_time_.has_value());
- CHECK(LocalRootImpl());
- CHECK(LocalRootImpl()->GetFrame());
- CHECK(LocalRootImpl()->GetFrame()->View());
-
- if (ForMainFrame()) {
- View()->Client()->DidCommitCompositorFrameForLocalMainFrame(
- commit_start_time);
- View()->UpdatePreferredSize();
- }
-
- LocalRootImpl()
- ->GetFrame()
- ->View()
- ->EnsureUkmAggregator()
- .RecordImplCompositorSample(commit_compositor_frame_start_time_.value(),
- commit_start_time, base::TimeTicks::Now());
- commit_compositor_frame_start_time_.reset();
-}
-
-void WebFrameWidgetBase::RecordDispatchRafAlignedInputTime(
- base::TimeTicks raf_aligned_input_start_time) {
- if (LocalRootImpl()) {
- LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
- LocalFrameUkmAggregator::kHandleInputEvents,
- raf_aligned_input_start_time, base::TimeTicks::Now());
- }
-}
-
-void WebFrameWidgetBase::SetSuppressFrameRequestsWorkaroundFor704763Only(
- bool suppress_frame_requests) {
- GetPage()->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
- suppress_frame_requests);
-}
-
-std::unique_ptr<cc::BeginMainFrameMetrics>
-WebFrameWidgetBase::GetBeginMainFrameMetrics() {
- if (!LocalRootImpl())
- return nullptr;
-
- return LocalRootImpl()
- ->GetFrame()
- ->View()
- ->EnsureUkmAggregator()
- .GetBeginMainFrameMetrics();
-}
-
-void WebFrameWidgetBase::BeginUpdateLayers() {
- if (LocalRootImpl())
- update_layers_start_time_.emplace(base::TimeTicks::Now());
-}
-
-void WebFrameWidgetBase::EndUpdateLayers() {
- if (LocalRootImpl()) {
- DCHECK(update_layers_start_time_);
- LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
- LocalFrameUkmAggregator::kUpdateLayers,
- update_layers_start_time_.value(), base::TimeTicks::Now());
- probe::LayerTreeDidChange(LocalRootImpl()->GetFrame());
- }
- update_layers_start_time_.reset();
-}
-
-void WebFrameWidgetBase::RecordStartOfFrameMetrics() {
- if (!LocalRootImpl())
- return;
-
- LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().BeginMainFrame();
-}
-
-void WebFrameWidgetBase::RecordEndOfFrameMetrics(
- base::TimeTicks frame_begin_time,
- cc::ActiveFrameSequenceTrackers trackers) {
- if (!LocalRootImpl())
- return;
-
- LocalRootImpl()
- ->GetFrame()
- ->View()
- ->EnsureUkmAggregator()
- .RecordEndOfFrameMetrics(frame_begin_time, base::TimeTicks::Now(),
- trackers);
-}
-
-bool WebFrameWidgetBase::WillHandleGestureEvent(const WebGestureEvent& event) {
- possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kTouch;
- possible_drag_event_info_.location =
- gfx::ToFlooredPoint(event.PositionInScreen());
-
- bool move_cursor = false;
- switch (event.GetType()) {
- case WebInputEvent::Type::kGestureScrollBegin: {
- if (event.data.scroll_begin.cursor_control) {
- swipe_to_move_cursor_activated_ = true;
- move_cursor = true;
- }
- break;
- }
- case WebInputEvent::Type::kGestureScrollUpdate: {
- if (swipe_to_move_cursor_activated_)
- move_cursor = true;
- break;
- }
- case WebInputEvent::Type::kGestureScrollEnd: {
- if (swipe_to_move_cursor_activated_) {
- swipe_to_move_cursor_activated_ = false;
- }
- break;
- }
- default:
- break;
- }
- // TODO(crbug.com/1140106): Place cursor for scroll begin other than just move
- // cursor.
- if (move_cursor) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (focused_frame) {
- gfx::Point base(event.PositionInWidget().x(),
- event.PositionInWidget().y());
- focused_frame->MoveCaretSelection(base);
- }
- return true;
- }
- return false;
-}
-
-void WebFrameWidgetBase::WillHandleMouseEvent(const WebMouseEvent& event) {
- possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kMouse;
- possible_drag_event_info_.location =
- gfx::Point(event.PositionInScreen().x(), event.PositionInScreen().y());
-}
-
-void WebFrameWidgetBase::ObserveGestureEventAndResult(
- const WebGestureEvent& gesture_event,
- const gfx::Vector2dF& unused_delta,
- const cc::OverscrollBehavior& overscroll_behavior,
- bool event_processed) {
- if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
- return;
-
- cc::InputHandlerScrollResult scroll_result;
- scroll_result.did_scroll = event_processed;
- scroll_result.did_overscroll_root = !unused_delta.IsZero();
- scroll_result.unused_scroll_delta = unused_delta;
- scroll_result.overscroll_behavior = overscroll_behavior;
-
- widget_base_->widget_input_handler_manager()->ObserveGestureEventOnMainThread(
- gesture_event, scroll_result);
-}
-
-void WebFrameWidgetBase::DidHandleKeyEvent() {
- ClearEditCommands();
-}
-
-WebTextInputType WebFrameWidgetBase::GetTextInputType() {
- if (ShouldDispatchImeEventsToPlugin()) {
- return GetFocusedPluginContainer()->GetPluginTextInputType();
- }
-
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return WebTextInputType::kWebTextInputTypeNone;
- return controller->TextInputType();
-}
-
-void WebFrameWidgetBase::SetCursorVisibilityState(bool is_visible) {
- GetPage()->SetIsCursorVisible(is_visible);
-}
-
-void WebFrameWidgetBase::ApplyViewportChangesForTesting(
- const ApplyViewportChangesArgs& args) {
- widget_base_->ApplyViewportChanges(args);
-}
-
-void WebFrameWidgetBase::SetDisplayMode(mojom::blink::DisplayMode mode) {
- if (mode != display_mode_) {
- display_mode_ = mode;
- LocalFrame* frame = LocalRootImpl()->GetFrame();
- frame->MediaQueryAffectingValueChangedForLocalSubtree(
- MediaValueChange::kOther);
- }
-}
-
-void WebFrameWidgetBase::SetWindowSegments(
- const std::vector<gfx::Rect>& window_segments_param) {
- WebVector<gfx::Rect> window_segments(window_segments_param);
- if (!window_segments_.Equals(window_segments)) {
- window_segments_ = window_segments;
- LocalFrame* frame = LocalRootImpl()->GetFrame();
- frame->WindowSegmentsChanged(window_segments_);
-
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](const std::vector<gfx::Rect>& window_segments,
- RemoteFrame* remote_frame) {
- remote_frame->Client()->DidChangeRootWindowSegments(window_segments);
- },
- window_segments_param));
- }
-}
-
-void WebFrameWidgetBase::SetCursor(const ui::Cursor& cursor) {
- widget_base_->SetCursor(cursor);
-}
-
-bool WebFrameWidgetBase::HandlingInputEvent() {
- return widget_base_->input_handler().handling_input_event();
-}
-
-void WebFrameWidgetBase::SetHandlingInputEvent(bool handling) {
- widget_base_->input_handler().set_handling_input_event(handling);
-}
-
-void WebFrameWidgetBase::ProcessInputEventSynchronouslyForTesting(
- const WebCoalescedInputEvent& event,
- HandledEventCallback callback) {
- widget_base_->input_handler().HandleInputEvent(event, nullptr,
- std::move(callback));
-}
-
-WebInputEventResult WebFrameWidgetBase::DispatchBufferedTouchEvents() {
- CHECK(LocalRootImpl());
-
- if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl())
- devtools->DispatchBufferedTouchEvents();
-
- return LocalRootImpl()
- ->GetFrame()
- ->GetEventHandler()
- .DispatchBufferedTouchEvents();
-}
-
-WebInputEventResult WebFrameWidgetBase::HandleInputEvent(
- const WebCoalescedInputEvent& coalesced_event) {
- const WebInputEvent& input_event = coalesced_event.Event();
- TRACE_EVENT1("input,rail", "WebFrameWidgetBase::HandleInputEvent", "type",
- WebInputEvent::GetName(input_event.GetType()));
- DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
- CHECK(LocalRootImpl());
-
- // Only record metrics for the main frame.
- if (ForMainFrame()) {
- GetPage()->GetVisualViewport().StartTrackingPinchStats();
- }
-
- // If a drag-and-drop operation is in progress, ignore input events except
- // PointerCancel.
- if (doing_drag_and_drop_ &&
- input_event.GetType() != WebInputEvent::Type::kPointerCancel)
- return WebInputEventResult::kHandledSuppressed;
-
- // Don't handle events once we've started shutting down.
- if (!GetPage())
- return WebInputEventResult::kNotHandled;
-
- if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl()) {
- auto result = devtools->HandleInputEvent(input_event);
- if (result != WebInputEventResult::kNotHandled)
- return result;
- }
-
- // Report the event to be NOT processed by WebKit, so that the browser can
- // handle it appropriately.
- if (IgnoreInputEvents())
- return WebInputEventResult::kNotHandled;
-
- base::AutoReset<const WebInputEvent*> current_event_change(
- &CurrentInputEvent::current_input_event_, &input_event);
- UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld();
-
- if (GetPage()->GetPointerLockController().IsPointerLocked() &&
- WebInputEvent::IsMouseEventType(input_event.GetType())) {
- PointerLockMouseEvent(coalesced_event);
- return WebInputEventResult::kHandledSystem;
- }
-
- /// These metrics are only captured for the main frame.
- if (ForMainFrame()) {
- Document& main_frame_document = *LocalRootImpl()->GetFrame()->GetDocument();
-
- if (input_event.GetType() != WebInputEvent::Type::kMouseMove) {
- FirstMeaningfulPaintDetector::From(main_frame_document)
- .NotifyInputEvent();
- }
-
- if (input_event.GetType() != WebInputEvent::Type::kMouseMove &&
- input_event.GetType() != WebInputEvent::Type::kMouseEnter &&
- input_event.GetType() != WebInputEvent::Type::kMouseLeave) {
- InteractiveDetector* interactive_detector(
- InteractiveDetector::From(main_frame_document));
- if (interactive_detector) {
- interactive_detector->OnInvalidatingInputEvent(input_event.TimeStamp());
- }
- }
- }
-
- NotifyInputObservers(coalesced_event);
-
- // Notify the focus frame of the input. Note that the other frames are not
- // notified as input is only handled by the focused frame.
- Frame* frame = FocusedCoreFrame();
- if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
- if (auto* content_capture_manager =
- local_frame->LocalFrameRoot().GetContentCaptureManager()) {
- content_capture_manager->NotifyInputEvent(input_event.GetType(),
- *local_frame);
- }
- }
-
- // Skip the pointerrawupdate for mouse capture case.
- if (mouse_capture_element_ &&
- input_event.GetType() == WebInputEvent::Type::kPointerRawUpdate)
- return WebInputEventResult::kHandledSystem;
-
- if (mouse_capture_element_ &&
- WebInputEvent::IsMouseEventType(input_event.GetType()))
- return HandleCapturedMouseEvent(coalesced_event);
-
- // FIXME: This should take in the intended frame, not the local frame
- // root.
- return PageWidgetDelegate::HandleInputEvent(*this, coalesced_event,
- LocalRootImpl()->GetFrame());
-}
-
-WebInputEventResult WebFrameWidgetBase::HandleCapturedMouseEvent(
- const WebCoalescedInputEvent& coalesced_event) {
- const WebInputEvent& input_event = coalesced_event.Event();
- TRACE_EVENT1("input", "captured mouse event", "type", input_event.GetType());
- // Save |mouse_capture_element_| since |MouseCaptureLost()| will clear it.
- HTMLPlugInElement* element = mouse_capture_element_;
-
- // Not all platforms call mouseCaptureLost() directly.
- if (input_event.GetType() == WebInputEvent::Type::kMouseUp) {
- SetMouseCapture(false);
- MouseCaptureLost();
- }
-
- AtomicString event_type;
- switch (input_event.GetType()) {
- case WebInputEvent::Type::kMouseEnter:
- event_type = event_type_names::kMouseover;
- break;
- case WebInputEvent::Type::kMouseMove:
- event_type = event_type_names::kMousemove;
- break;
- case WebInputEvent::Type::kPointerRawUpdate:
- // There will be no mouse event for rawupdate events.
- event_type = event_type_names::kPointerrawupdate;
- break;
- case WebInputEvent::Type::kMouseLeave:
- event_type = event_type_names::kMouseout;
- break;
- case WebInputEvent::Type::kMouseDown:
- event_type = event_type_names::kMousedown;
- LocalFrame::NotifyUserActivation(
- element->GetDocument().GetFrame(),
- mojom::blink::UserActivationNotificationType::kInteraction);
- break;
- case WebInputEvent::Type::kMouseUp:
- event_type = event_type_names::kMouseup;
- break;
- default:
- NOTREACHED();
- }
-
- WebMouseEvent transformed_event =
- TransformWebMouseEvent(LocalRootImpl()->GetFrameView(),
- static_cast<const WebMouseEvent&>(input_event));
- if (LocalFrame* frame = element->GetDocument().GetFrame()) {
- frame->GetEventHandler().HandleTargetedMouseEvent(
- element, transformed_event, event_type,
- TransformWebMouseEventVector(
- LocalRootImpl()->GetFrameView(),
- coalesced_event.GetCoalescedEventsPointers()),
- TransformWebMouseEventVector(
- LocalRootImpl()->GetFrameView(),
- coalesced_event.GetPredictedEventsPointers()));
- }
- return WebInputEventResult::kHandledSystem;
-}
-
-void WebFrameWidgetBase::UpdateTextInputState() {
- widget_base_->UpdateTextInputState();
-}
-
-void WebFrameWidgetBase::UpdateSelectionBounds() {
- widget_base_->UpdateSelectionBounds();
-}
-
-void WebFrameWidgetBase::ShowVirtualKeyboard() {
- widget_base_->ShowVirtualKeyboard();
-}
-
-void WebFrameWidgetBase::FlushInputProcessedCallback() {
- widget_base_->FlushInputProcessedCallback();
-}
-
-void WebFrameWidgetBase::CancelCompositionForPepper() {
- widget_base_->CancelCompositionForPepper();
-}
-
-void WebFrameWidgetBase::RequestMouseLock(
- bool has_transient_user_activation,
- bool request_unadjusted_movement,
- mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback) {
- mojom::blink::WidgetInputHandlerHost* host =
- widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost();
-
- // If we don't have a host just leave the callback uncalled. This simulates
- // the browser indefinitely postponing the mouse request which is valid.
- // Note that |callback| is not a mojo bound callback (until it is passed
- // into the mojo interface) and can be destructed without invoking the
- // callback. It does share the same signature as the mojo definition
- // for simplicity.
- if (host) {
- host->RequestMouseLock(has_transient_user_activation,
- request_unadjusted_movement, std::move(callback));
- }
-}
-
-void WebFrameWidgetBase::ApplyVisualProperties(
- const VisualProperties& visual_properties) {
- widget_base_->UpdateVisualProperties(visual_properties);
-}
-
-bool WebFrameWidgetBase::IsFullscreenGranted() {
- return is_fullscreen_granted_;
-}
-
-bool WebFrameWidgetBase::PinchGestureActiveInMainFrame() {
- return is_pinch_gesture_active_in_mainframe_;
-}
-
-float WebFrameWidgetBase::PageScaleInMainFrame() {
- return page_scale_factor_in_mainframe_;
-}
-
-void WebFrameWidgetBase::UpdateSurfaceAndScreenInfo(
- const viz::LocalSurfaceId& new_local_surface_id,
- const gfx::Rect& compositor_viewport_pixel_rect,
- const ScreenInfo& new_screen_info) {
- widget_base_->UpdateSurfaceAndScreenInfo(
- new_local_surface_id, compositor_viewport_pixel_rect, new_screen_info);
-}
-
-void WebFrameWidgetBase::UpdateScreenInfo(const ScreenInfo& new_screen_info) {
- widget_base_->UpdateScreenInfo(new_screen_info);
-}
-
-void WebFrameWidgetBase::UpdateSurfaceAndCompositorRect(
- const viz::LocalSurfaceId& new_local_surface_id,
- const gfx::Rect& compositor_viewport_pixel_rect) {
- widget_base_->UpdateSurfaceAndCompositorRect(new_local_surface_id,
- compositor_viewport_pixel_rect);
-}
-
-void WebFrameWidgetBase::UpdateCompositorViewportRect(
- const gfx::Rect& compositor_viewport_pixel_rect) {
- widget_base_->UpdateCompositorViewportRect(compositor_viewport_pixel_rect);
-}
-
-const ScreenInfo& WebFrameWidgetBase::GetScreenInfo() {
- return widget_base_->GetScreenInfo();
-}
-
-gfx::Rect WebFrameWidgetBase::WindowRect() {
- return widget_base_->WindowRect();
-}
-
-gfx::Rect WebFrameWidgetBase::ViewRect() {
- return widget_base_->ViewRect();
-}
-
-void WebFrameWidgetBase::SetScreenRects(const gfx::Rect& widget_screen_rect,
- const gfx::Rect& window_screen_rect) {
- widget_base_->SetScreenRects(widget_screen_rect, window_screen_rect);
-}
-
-gfx::Size WebFrameWidgetBase::VisibleViewportSizeInDIPs() {
- return widget_base_->VisibleViewportSizeInDIPs();
-}
-
-void WebFrameWidgetBase::SetPendingWindowRect(
- const gfx::Rect& window_screen_rect) {
- widget_base_->SetPendingWindowRect(window_screen_rect);
-}
-
-void WebFrameWidgetBase::AckPendingWindowRect() {
- widget_base_->AckPendingWindowRect();
-}
-
-bool WebFrameWidgetBase::IsHidden() const {
- return widget_base_->is_hidden();
-}
-
-WebString WebFrameWidgetBase::GetLastToolTipTextForTesting() const {
- return GetPage()->GetChromeClient().GetLastToolTipTextForTesting();
-}
-
-void WebFrameWidgetBase::AutoscrollStart(const gfx::PointF& position) {
- GetAssociatedFrameWidgetHost()->AutoscrollStart(std::move(position));
-}
-
-void WebFrameWidgetBase::AutoscrollFling(const gfx::Vector2dF& velocity) {
- GetAssociatedFrameWidgetHost()->AutoscrollFling(std::move(velocity));
-}
-
-void WebFrameWidgetBase::AutoscrollEnd() {
- GetAssociatedFrameWidgetHost()->AutoscrollEnd();
-}
-
-void WebFrameWidgetBase::DidMeaningfulLayout(WebMeaningfulLayout layout_type) {
- if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty) {
- NotifySwapAndPresentationTime(
- base::NullCallback(),
- WTF::Bind(&WebFrameWidgetBase::PresentationCallbackForMeaningfulLayout,
- WrapPersistent(this)));
- }
-
- ForEachLocalFrameControlledByWidget(
- local_root_->GetFrame(),
- WTF::BindRepeating(
- [](WebMeaningfulLayout layout_type, WebLocalFrame* local_frame) {
- local_frame->Client()->DidMeaningfulLayout(layout_type);
- },
- layout_type));
-}
-
-void WebFrameWidgetBase::PresentationCallbackForMeaningfulLayout(
- blink::WebSwapResult,
- base::TimeTicks) {
- GetAssociatedFrameWidgetHost()->DidFirstVisuallyNonEmptyPaint();
-}
-
-void WebFrameWidgetBase::RequestAnimationAfterDelay(
- const base::TimeDelta& delay) {
- DCHECK(request_animation_after_delay_timer_.get());
- if (request_animation_after_delay_timer_->IsActive() &&
- request_animation_after_delay_timer_->NextFireInterval() > delay) {
- request_animation_after_delay_timer_->Stop();
- }
- if (!request_animation_after_delay_timer_->IsActive()) {
- request_animation_after_delay_timer_->StartOneShot(delay, FROM_HERE);
- }
-}
-
-void WebFrameWidgetBase::RequestAnimationAfterDelayTimerFired(TimerBase*) {
- if (client_)
- client_->ScheduleAnimation();
-}
-
-base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
-WebFrameWidgetBase::EnsureCompositorMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) {
- if (!mutator_task_runner_) {
- widget_base_->LayerTreeHost()->SetLayerTreeMutator(
- AnimationWorkletMutatorDispatcherImpl::CreateCompositorThreadClient(
- &mutator_dispatcher_, &mutator_task_runner_));
- }
-
- DCHECK(mutator_task_runner_);
- *mutator_task_runner = mutator_task_runner_;
- return mutator_dispatcher_;
-}
-
-HitTestResult WebFrameWidgetBase::CoreHitTestResultAt(
- const gfx::PointF& point_in_viewport) {
- LocalFrameView* view = LocalRootImpl()->GetFrameView();
- FloatPoint point_in_root_frame(
- view->ViewportToFrame(FloatPoint(point_in_viewport)));
- return HitTestResultForRootFramePos(point_in_root_frame);
-}
-
-cc::AnimationHost* WebFrameWidgetBase::AnimationHost() const {
- return widget_base_->AnimationHost();
-}
-
-base::WeakPtr<PaintWorkletPaintDispatcher>
-WebFrameWidgetBase::EnsureCompositorPaintDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* paint_task_runner) {
- // We check paint_task_runner_ not paint_dispatcher_ because the dispatcher is
- // a base::WeakPtr that should only be used on the compositor thread.
- if (!paint_task_runner_) {
- widget_base_->LayerTreeHost()->SetPaintWorkletLayerPainter(
- PaintWorkletPaintDispatcher::CreateCompositorThreadPainter(
- &paint_dispatcher_));
- paint_task_runner_ = Thread::CompositorThread()->GetTaskRunner();
- }
- DCHECK(paint_task_runner_);
- *paint_task_runner = paint_task_runner_;
- return paint_dispatcher_;
-}
-
-void WebFrameWidgetBase::SetDelegatedInkMetadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
- widget_base_->LayerTreeHost()->SetDelegatedInkMetadata(std::move(metadata));
-}
-
-// Enables measuring and reporting both presentation times and swap times in
-// swap promises.
-class ReportTimeSwapPromise : public cc::SwapPromise {
- public:
- ReportTimeSwapPromise(WebReportTimeCallback swap_time_callback,
- WebReportTimeCallback presentation_time_callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- WebFrameWidgetBase* widget)
- : swap_time_callback_(std::move(swap_time_callback)),
- presentation_time_callback_(std::move(presentation_time_callback)),
- task_runner_(std::move(task_runner)),
- widget_(widget) {}
- ~ReportTimeSwapPromise() override = default;
-
- void DidActivate() override {}
-
- void WillSwap(viz::CompositorFrameMetadata* metadata) override {
- DCHECK_GT(metadata->frame_token, 0u);
- // The interval between the current swap and its presentation time is
- // reported in UMA (see corresponding code in DidSwap() below).
- frame_token_ = metadata->frame_token;
- }
-
- void DidSwap() override {
- DCHECK_GT(frame_token_, 0u);
- PostCrossThreadTask(
- *task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &RunCallbackAfterSwap, widget_, base::TimeTicks::Now(),
- std::move(swap_time_callback_),
- std::move(presentation_time_callback_), frame_token_));
- }
-
- cc::SwapPromise::DidNotSwapAction DidNotSwap(
- DidNotSwapReason reason) override {
- WebSwapResult result;
- switch (reason) {
- case cc::SwapPromise::DidNotSwapReason::SWAP_FAILS:
- result = WebSwapResult::kDidNotSwapSwapFails;
- break;
- case cc::SwapPromise::DidNotSwapReason::COMMIT_FAILS:
- result = WebSwapResult::kDidNotSwapCommitFails;
- break;
- case cc::SwapPromise::DidNotSwapReason::COMMIT_NO_UPDATE:
- result = WebSwapResult::kDidNotSwapCommitNoUpdate;
- break;
- case cc::SwapPromise::DidNotSwapReason::ACTIVATION_FAILS:
- result = WebSwapResult::kDidNotSwapActivationFails;
- break;
- }
- // During a failed swap, return the current time regardless of whether we're
- // using presentation or swap timestamps.
- PostCrossThreadTask(
- *task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- [](WebSwapResult result, base::TimeTicks swap_time,
- WebReportTimeCallback swap_time_callback,
- WebReportTimeCallback presentation_time_callback) {
- ReportTime(std::move(swap_time_callback), result, swap_time);
- ReportTime(std::move(presentation_time_callback), result,
- swap_time);
- },
- result, base::TimeTicks::Now(), std::move(swap_time_callback_),
- std::move(presentation_time_callback_)));
- return DidNotSwapAction::BREAK_PROMISE;
- }
-
- int64_t TraceId() const override { return 0; }
-
- private:
- static void RunCallbackAfterSwap(
- WebFrameWidgetBase* widget,
- base::TimeTicks swap_time,
- WebReportTimeCallback swap_time_callback,
- WebReportTimeCallback presentation_time_callback,
- int frame_token) {
- // If the widget was collected or the widget wasn't collected yet, but
- // it was closed don't schedule a presentation callback.
- if (widget && widget->widget_base_) {
- widget->widget_base_->AddPresentationCallback(
- frame_token,
- WTF::Bind(&RunCallbackAfterPresentation,
- std::move(presentation_time_callback), swap_time));
- ReportTime(std::move(swap_time_callback), WebSwapResult::kDidSwap,
- swap_time);
- } else {
- ReportTime(std::move(swap_time_callback), WebSwapResult::kDidSwap,
- swap_time);
- ReportTime(std::move(presentation_time_callback), WebSwapResult::kDidSwap,
- swap_time);
- }
- }
-
- static void RunCallbackAfterPresentation(
- WebReportTimeCallback presentation_time_callback,
- base::TimeTicks swap_time,
- base::TimeTicks presentation_time) {
- DCHECK(!swap_time.is_null());
- bool presentation_time_is_valid =
- !presentation_time.is_null() && (presentation_time > swap_time);
- UMA_HISTOGRAM_BOOLEAN("PageLoad.Internal.Renderer.PresentationTime.Valid",
- presentation_time_is_valid);
- if (presentation_time_is_valid) {
- // This measures from 1ms to 10seconds.
- UMA_HISTOGRAM_TIMES(
- "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime",
- presentation_time - swap_time);
- }
- ReportTime(std::move(presentation_time_callback), WebSwapResult::kDidSwap,
- presentation_time_is_valid ? presentation_time : swap_time);
- }
-
- static void ReportTime(WebReportTimeCallback callback,
- WebSwapResult result,
- base::TimeTicks time) {
- if (callback)
- std::move(callback).Run(result, time);
- }
-
- WebReportTimeCallback swap_time_callback_;
- WebReportTimeCallback presentation_time_callback_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- CrossThreadWeakPersistent<WebFrameWidgetBase> widget_;
- uint32_t frame_token_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(ReportTimeSwapPromise);
-};
-
-void WebFrameWidgetBase::NotifySwapAndPresentationTimeInBlink(
- WebReportTimeCallback swap_time_callback,
- WebReportTimeCallback presentation_time_callback) {
- NotifySwapAndPresentationTime(std::move(swap_time_callback),
- std::move(presentation_time_callback));
-}
-
-void WebFrameWidgetBase::NotifySwapAndPresentationTime(
- WebReportTimeCallback swap_time_callback,
- WebReportTimeCallback presentation_time_callback) {
- if (!View()->does_composite())
- return;
- widget_base_->LayerTreeHost()->QueueSwapPromise(
- std::make_unique<ReportTimeSwapPromise>(
- std::move(swap_time_callback), std::move(presentation_time_callback),
- widget_base_->LayerTreeHost()
- ->GetTaskRunnerProvider()
- ->MainThreadTaskRunner(),
- this));
-}
-
-scheduler::WebRenderWidgetSchedulingState*
-WebFrameWidgetBase::RendererWidgetSchedulingState() {
- return widget_base_->RendererWidgetSchedulingState();
-}
-
-void WebFrameWidgetBase::WaitForDebuggerWhenShown() {
- local_root_->WaitForDebuggerWhenShown();
-}
-
-void WebFrameWidgetBase::SetTextZoomFactor(float text_zoom_factor) {
- local_root_->GetFrame()->SetTextZoomFactor(text_zoom_factor);
-}
-
-float WebFrameWidgetBase::TextZoomFactor() {
- return local_root_->GetFrame()->TextZoomFactor();
-}
-
-void WebFrameWidgetBase::SetMainFrameOverlayColor(SkColor color) {
- DCHECK(!local_root_->Parent());
- local_root_->GetFrame()->SetMainFrameColorOverlay(color);
-}
-
-void WebFrameWidgetBase::AddEditCommandForNextKeyEvent(const WebString& name,
- const WebString& value) {
- edit_commands_.push_back(mojom::blink::EditCommand::New(name, value));
-}
-
-bool WebFrameWidgetBase::HandleCurrentKeyboardEvent() {
- bool did_execute_command = false;
- WebLocalFrame* frame = FocusedWebLocalFrameInWidget();
- if (!frame)
- frame = local_root_;
- for (const auto& command : edit_commands_) {
- // In gtk and cocoa, it's possible to bind multiple edit commands to one
- // key (but it's the exception). Once one edit command is not executed, it
- // seems safest to not execute the rest.
- if (!frame->ExecuteCommand(command->name, command->value))
- break;
- did_execute_command = true;
- }
-
- return did_execute_command;
-}
-
-void WebFrameWidgetBase::ClearEditCommands() {
- edit_commands_ = Vector<mojom::blink::EditCommandPtr>();
-}
-
-WebTextInputInfo WebFrameWidgetBase::TextInputInfo() {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return WebTextInputInfo();
- return controller->TextInputInfo();
-}
-
-ui::mojom::blink::VirtualKeyboardVisibilityRequest
-WebFrameWidgetBase::GetLastVirtualKeyboardVisibilityRequest() {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE;
- return controller->GetLastVirtualKeyboardVisibilityRequest();
-}
-
-bool WebFrameWidgetBase::ShouldSuppressKeyboardForFocusedElement() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return false;
- return focused_frame->ShouldSuppressKeyboardForFocusedElement();
-}
-
-void WebFrameWidgetBase::GetEditContextBoundsInWindow(
- base::Optional<gfx::Rect>* edit_context_control_bounds,
- base::Optional<gfx::Rect>* edit_context_selection_bounds) {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return;
- WebRect control_bounds;
- WebRect selection_bounds;
- controller->GetLayoutBounds(&control_bounds, &selection_bounds);
- *edit_context_control_bounds =
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(control_bounds));
- if (controller->IsEditContextActive()) {
- *edit_context_selection_bounds =
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(selection_bounds));
- }
-}
-
-int32_t WebFrameWidgetBase::ComputeWebTextInputNextPreviousFlags() {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return 0;
- return controller->ComputeWebTextInputNextPreviousFlags();
-}
-
-void WebFrameWidgetBase::ResetVirtualKeyboardVisibilityRequest() {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return;
- controller->SetVirtualKeyboardVisibilityRequest(
- ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE);
- ;
-}
-
-bool WebFrameWidgetBase::GetSelectionBoundsInWindow(
- gfx::Rect* focus,
- gfx::Rect* anchor,
- base::i18n::TextDirection* focus_dir,
- base::i18n::TextDirection* anchor_dir,
- bool* is_anchor_first) {
- if (ShouldDispatchImeEventsToPlugin()) {
- // TODO(kinaba) http://crbug.com/101101
- // Current Pepper IME API does not handle selection bounds. So we simply
- // use the caret position as an empty range for now. It will be updated
- // after Pepper API equips features related to surrounding text retrieval.
- gfx::Rect pepper_caret_in_dips = widget_base_->BlinkSpaceToEnclosedDIPs(
- GetFocusedPluginContainer()->GetPluginCaretBounds());
- if (pepper_caret_in_dips == *focus && pepper_caret_in_dips == *anchor)
- return false;
- *focus = pepper_caret_in_dips;
- *anchor = *focus;
- return true;
- }
- gfx::Rect focus_root_frame;
- gfx::Rect anchor_root_frame;
- CalculateSelectionBounds(focus_root_frame, anchor_root_frame);
- gfx::Rect focus_rect_in_dips =
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(focus_root_frame));
- gfx::Rect anchor_rect_in_dips =
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(anchor_root_frame));
-
- // if the bounds are the same return false.
- if (focus_rect_in_dips == *focus && anchor_rect_in_dips == *anchor)
- return false;
- *focus = focus_rect_in_dips;
- *anchor = anchor_rect_in_dips;
-
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return true;
- focused_frame->SelectionTextDirection(*focus_dir, *anchor_dir);
- *is_anchor_first = focused_frame->IsSelectionAnchorFirst();
- return true;
-}
-
-void WebFrameWidgetBase::ClearTextInputState() {
- widget_base_->ClearTextInputState();
-}
-
-bool WebFrameWidgetBase::IsPasting() {
- return widget_base_->is_pasting();
-}
-
-bool WebFrameWidgetBase::HandlingSelectRange() {
- return widget_base_->handling_select_range();
-}
-
-void WebFrameWidgetBase::SetFocus(bool focus) {
- widget_base_->SetFocus(focus);
-}
-
-bool WebFrameWidgetBase::HasFocus() {
- return widget_base_->has_focus();
-}
-
-void WebFrameWidgetBase::SetToolTipText(const String& tooltip_text,
- TextDirection dir) {
- widget_base_->SetToolTipText(tooltip_text, dir);
-}
-
-void WebFrameWidgetBase::DidOverscroll(
- const gfx::Vector2dF& overscroll_delta,
- const gfx::Vector2dF& accumulated_overscroll,
- const gfx::PointF& position,
- const gfx::Vector2dF& velocity) {
-#if defined(OS_MAC)
- // On OSX the user can disable the elastic overscroll effect. If that's the
- // case, don't forward the overscroll notification.
- if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
- return;
-#endif
-
- cc::OverscrollBehavior overscroll_behavior =
- widget_base_->LayerTreeHost()->overscroll_behavior();
- if (!widget_base_->input_handler().DidOverscrollFromBlink(
- overscroll_delta, accumulated_overscroll, position, velocity,
- overscroll_behavior))
- return;
-
- // If we're currently handling an event, stash the overscroll data such that
- // it can be bundled in the event ack.
- if (mojom::blink::WidgetInputHandlerHost* host =
- widget_base_->widget_input_handler_manager()
- ->GetWidgetInputHandlerHost()) {
- host->DidOverscroll(mojom::blink::DidOverscrollParams::New(
- accumulated_overscroll, overscroll_delta, velocity, position,
- overscroll_behavior));
- }
-}
-
-void WebFrameWidgetBase::InjectGestureScrollEvent(
- blink::WebGestureDevice device,
- const gfx::Vector2dF& delta,
- ui::ScrollGranularity granularity,
- cc::ElementId scrollable_area_element_id,
- blink::WebInputEvent::Type injected_type) {
- if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
- // create a GestureScroll Event and post it to the compositor thread
- // TODO(crbug.com/1126098) use original input event's timestamp.
- // TODO(crbug.com/1082590) ensure continuity in scroll metrics collection
- base::TimeTicks now = base::TimeTicks::Now();
- std::unique_ptr<WebGestureEvent> gesture_event =
- WebGestureEvent::GenerateInjectedScrollGesture(
- injected_type, now, device, gfx::PointF(0, 0), delta, granularity);
- if (injected_type == WebInputEvent::Type::kGestureScrollBegin) {
- gesture_event->data.scroll_begin.scrollable_area_element_id =
- scrollable_area_element_id.GetStableId();
- gesture_event->data.scroll_begin.main_thread_hit_tested = true;
- }
-
- widget_base_->widget_input_handler_manager()
- ->DispatchScrollGestureToCompositor(std::move(gesture_event));
- } else {
- widget_base_->input_handler().InjectGestureScrollEvent(
- device, delta, granularity, scrollable_area_element_id, injected_type);
- }
-}
-
-void WebFrameWidgetBase::DidChangeCursor(const ui::Cursor& cursor) {
- widget_base_->SetCursor(cursor);
- Client()->DidChangeCursor(cursor);
-}
-
-bool WebFrameWidgetBase::SetComposition(
- const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int selection_start,
- int selection_end) {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return false;
-
- return controller->SetComposition(
- text, ime_text_spans,
- replacement_range.IsValid()
- ? WebRange(replacement_range.start(), replacement_range.length())
- : WebRange(),
- selection_start, selection_end);
-}
-
-void WebFrameWidgetBase::CommitText(
- const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int relative_cursor_pos) {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return;
- controller->CommitText(
- text, ime_text_spans,
- replacement_range.IsValid()
- ? WebRange(replacement_range.start(), replacement_range.length())
- : WebRange(),
- relative_cursor_pos);
-}
-
-void WebFrameWidgetBase::FinishComposingText(bool keep_selection) {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller)
- return;
- controller->FinishComposingText(
- keep_selection ? WebInputMethodController::kKeepSelection
- : WebInputMethodController::kDoNotKeepSelection);
-}
-
-bool WebFrameWidgetBase::IsProvisional() {
- return LocalRoot()->IsProvisional();
-}
-
-uint64_t WebFrameWidgetBase::GetScrollableContainerIdAt(
- const gfx::PointF& point_in_dips) {
- gfx::PointF point = widget_base_->DIPsToBlinkSpace(point_in_dips);
- return HitTestResultAt(point).GetScrollableContainerId();
-}
-
-void WebFrameWidgetBase::SetEditCommandsForNextKeyEvent(
- Vector<mojom::blink::EditCommandPtr> edit_commands) {
- edit_commands_ = std::move(edit_commands);
-}
-
-void WebFrameWidgetBase::FocusChangeComplete() {
- blink::WebLocalFrame* focused = LocalRoot()->View()->FocusedFrame();
-
- if (focused && focused->AutofillClient())
- focused->AutofillClient()->DidCompleteFocusChangeInFrame();
-}
-
-void WebFrameWidgetBase::ShowVirtualKeyboardOnElementFocus() {
- widget_base_->ShowVirtualKeyboardOnElementFocus();
-}
-
-void WebFrameWidgetBase::ProcessTouchAction(WebTouchAction touch_action) {
- widget_base_->ProcessTouchAction(touch_action);
-}
-
-void WebFrameWidgetBase::DidHandleGestureEvent(const WebGestureEvent& event,
- bool event_cancelled) {
- if (event_cancelled) {
- // The delegate() doesn't need to hear about cancelled events.
- return;
- }
-
-#if defined(OS_ANDROID) || defined(USE_AURA)
- if (event.GetType() == WebInputEvent::Type::kGestureTap) {
- widget_base_->ShowVirtualKeyboard();
- } else if (event.GetType() == WebInputEvent::Type::kGestureLongPress) {
- WebInputMethodController* controller = GetActiveWebInputMethodController();
- if (!controller || controller->TextInputInfo().value.IsEmpty())
- widget_base_->UpdateTextInputState();
- else
- widget_base_->ShowVirtualKeyboard();
- }
-#endif
-}
-
-void WebFrameWidgetBase::SetHasPointerRawUpdateEventHandlers(
- bool has_handlers) {
- widget_base_->widget_input_handler_manager()
- ->input_event_queue()
- ->HasPointerRawUpdateEventHandlers(has_handlers);
-}
-
-void WebFrameWidgetBase::SetNeedsLowLatencyInput(bool needs_low_latency) {
- widget_base_->widget_input_handler_manager()
- ->input_event_queue()
- ->SetNeedsLowLatency(needs_low_latency);
-}
-
-void WebFrameWidgetBase::RequestUnbufferedInputEvents() {
- widget_base_->widget_input_handler_manager()
- ->input_event_queue()
- ->RequestUnbufferedInputEvents();
-}
-
-void WebFrameWidgetBase::SetNeedsUnbufferedInputForDebugger(bool unbuffered) {
- widget_base_->widget_input_handler_manager()
- ->input_event_queue()
- ->SetNeedsUnbufferedInputForDebugger(unbuffered);
-}
-
-void WebFrameWidgetBase::DidNavigate() {
- // The input handler wants to know about navigation so that it can
- // suppress input until the newly navigated page has a committed frame.
- // It also resets the state for UMA reporting of input arrival with respect
- // to document lifecycle.
- if (!widget_base_->widget_input_handler_manager())
- return;
- widget_base_->widget_input_handler_manager()->DidNavigate();
-}
-
-void WebFrameWidgetBase::SetMouseCapture(bool capture) {
- if (mojom::blink::WidgetInputHandlerHost* host =
- widget_base_->widget_input_handler_manager()
- ->GetWidgetInputHandlerHost()) {
- host->SetMouseCapture(capture);
- }
-}
-
-gfx::Range WebFrameWidgetBase::CompositionRange() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame || ShouldDispatchImeEventsToPlugin())
- return gfx::Range::InvalidRange();
-
- blink::WebInputMethodController* controller =
- focused_frame->GetInputMethodController();
- WebRange web_range = controller->CompositionRange();
- if (web_range.IsNull())
- return gfx::Range::InvalidRange();
- return gfx::Range(web_range.StartOffset(), web_range.EndOffset());
-}
-
-void WebFrameWidgetBase::GetCompositionCharacterBoundsInWindow(
- Vector<gfx::Rect>* bounds_in_dips) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame || ShouldDispatchImeEventsToPlugin())
- return;
- blink::WebInputMethodController* controller =
- focused_frame->GetInputMethodController();
- blink::WebVector<blink::WebRect> bounds_from_blink;
- if (!controller->GetCompositionCharacterBounds(bounds_from_blink))
- return;
-
- for (auto& rect : bounds_from_blink) {
- bounds_in_dips->push_back(
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(rect)));
- }
-}
-
-void WebFrameWidgetBase::AddImeTextSpansToExistingText(
- uint32_t start,
- uint32_t end,
- const Vector<ui::ImeTextSpan>& ime_text_spans) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->AddImeTextSpansToExistingText(ime_text_spans, start, end);
-}
-
-Vector<ui::mojom::blink::ImeTextSpanInfoPtr>
-WebFrameWidgetBase::GetImeTextSpansInfo(
- const WebVector<ui::ImeTextSpan>& ime_text_spans) {
- auto* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return Vector<ui::mojom::blink::ImeTextSpanInfoPtr>();
-
- Vector<ui::mojom::blink::ImeTextSpanInfoPtr> ime_text_spans_info;
-
- for (const auto& ime_text_span : ime_text_spans) {
- WebRect webrect;
- unsigned length = ime_text_span.end_offset - ime_text_span.start_offset;
- focused_frame->FirstRectForCharacterRange(ime_text_span.start_offset,
- length, webrect);
-
- ime_text_spans_info.push_back(ui::mojom::blink::ImeTextSpanInfo::New(
- ime_text_span,
- widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(webrect))));
- }
- return ime_text_spans_info;
-}
-
-void WebFrameWidgetBase::ClearImeTextSpansByType(uint32_t start,
- uint32_t end,
- ui::ImeTextSpan::Type type) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ClearImeTextSpansByType(type, start, end);
-}
-
-void WebFrameWidgetBase::SetCompositionFromExistingText(
- int32_t start,
- int32_t end,
- const Vector<ui::ImeTextSpan>& ime_text_spans) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->SetCompositionFromExistingText(start, end, ime_text_spans);
-}
-
-void WebFrameWidgetBase::ExtendSelectionAndDelete(int32_t before,
- int32_t after) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExtendSelectionAndDelete(before, after);
-}
-
-void WebFrameWidgetBase::DeleteSurroundingText(int32_t before, int32_t after) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->DeleteSurroundingText(before, after);
-}
-
-void WebFrameWidgetBase::DeleteSurroundingTextInCodePoints(int32_t before,
- int32_t after) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->DeleteSurroundingTextInCodePoints(before, after);
-}
-
-void WebFrameWidgetBase::SetEditableSelectionOffsets(int32_t start,
- int32_t end) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->SetEditableSelectionOffsets(start, end);
-}
-
-void WebFrameWidgetBase::ExecuteEditCommand(const String& command,
- const String& value) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(command, value);
-}
-
-void WebFrameWidgetBase::Undo() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Undo"));
-}
-
-void WebFrameWidgetBase::Redo() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Redo"));
-}
-
-void WebFrameWidgetBase::Cut() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Cut"));
-}
-
-void WebFrameWidgetBase::Copy() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Copy"));
-}
-
-void WebFrameWidgetBase::CopyToFindPboard() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- To<WebLocalFrameImpl>(focused_frame)->CopyToFindPboard();
-}
-
-void WebFrameWidgetBase::Paste() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Paste"));
-}
-
-void WebFrameWidgetBase::PasteAndMatchStyle() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("PasteAndMatchStyle"));
-}
-
-void WebFrameWidgetBase::Delete() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("Delete"));
-}
-
-void WebFrameWidgetBase::SelectAll() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->ExecuteCommand(WebString::FromLatin1("SelectAll"));
-}
-
-void WebFrameWidgetBase::CollapseSelection() {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- const blink::WebRange& range =
- focused_frame->GetInputMethodController()->GetSelectionOffsets();
- if (range.IsNull())
- return;
-
- focused_frame->SelectRange(blink::WebRange(range.EndOffset(), 0),
- blink::WebLocalFrame::kHideSelectionHandle,
- mojom::blink::SelectionMenuBehavior::kHide);
-}
-
-void WebFrameWidgetBase::Replace(const String& word) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- if (!focused_frame->HasSelection())
- focused_frame->SelectWordAroundCaret();
- focused_frame->ReplaceSelection(word);
- focused_frame->Client()->SyncSelectionIfRequired();
-}
-
-void WebFrameWidgetBase::ReplaceMisspelling(const String& word) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- if (!focused_frame->HasSelection())
- return;
- focused_frame->ReplaceMisspelledRange(word);
-}
-
-void WebFrameWidgetBase::SelectRange(const gfx::Point& base_in_dips,
- const gfx::Point& extent_in_dips) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->SelectRange(
- widget_base_->DIPsToRoundedBlinkSpace(base_in_dips),
- widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
-}
-
-void WebFrameWidgetBase::AdjustSelectionByCharacterOffset(
- int32_t start,
- int32_t end,
- mojom::blink::SelectionMenuBehavior selection_menu_behavior) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- blink::WebRange range =
- focused_frame->GetInputMethodController()->GetSelectionOffsets();
- if (range.IsNull())
- return;
-
- // Sanity checks to disallow empty and out of range selections.
- if (start - end > range.length() || range.StartOffset() + start < 0)
- return;
-
- // A negative adjust amount moves the selection towards the beginning of
- // the document, a positive amount moves the selection towards the end of
- // the document.
- focused_frame->SelectRange(blink::WebRange(range.StartOffset() + start,
- range.length() + end - start),
- blink::WebLocalFrame::kPreserveHandleVisibility,
- selection_menu_behavior);
-}
-
-void WebFrameWidgetBase::MoveRangeSelectionExtent(
- const gfx::Point& extent_in_dips) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->MoveRangeSelectionExtent(
- widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
-}
-
-void WebFrameWidgetBase::ScrollFocusedEditableNodeIntoRect(
- const gfx::Rect& rect_in_dips) {
- WebLocalFrame* local_frame = FocusedWebLocalFrameInWidget();
- if (!local_frame)
- return;
-
- // OnSynchronizeVisualProperties does not call DidChangeVisibleViewport
- // on OOPIFs. Since we are starting a new scroll operation now, call
- // DidChangeVisibleViewport to ensure that we don't assume the element
- // is already in view and ignore the scroll.
- local_frame->Client()->ResetHasScrolledFocusedEditableIntoView();
- local_frame->Client()->ScrollFocusedEditableElementIntoRect(rect_in_dips);
-}
-
-void WebFrameWidgetBase::MoveCaret(const gfx::Point& point_in_dips) {
- WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame)
- return;
- focused_frame->MoveCaretSelection(
- widget_base_->DIPsToRoundedBlinkSpace(point_in_dips));
-}
-
-#if defined(OS_ANDROID)
-void WebFrameWidgetBase::SelectWordAroundCaret(
- SelectWordAroundCaretCallback callback) {
- auto* focused_frame = FocusedWebLocalFrameInWidget();
- if (!focused_frame) {
- std::move(callback).Run(false, 0, 0);
- return;
- }
-
- bool did_select = false;
- int start_adjust = 0;
- int end_adjust = 0;
- blink::WebRange initial_range = focused_frame->SelectionRange();
- SetHandlingInputEvent(true);
- if (!initial_range.IsNull())
- did_select = focused_frame->SelectWordAroundCaret();
- if (did_select) {
- blink::WebRange adjusted_range = focused_frame->SelectionRange();
- DCHECK(!adjusted_range.IsNull());
- start_adjust = adjusted_range.StartOffset() - initial_range.StartOffset();
- end_adjust = adjusted_range.EndOffset() - initial_range.EndOffset();
- }
- SetHandlingInputEvent(false);
- std::move(callback).Run(did_select, start_adjust, end_adjust);
-}
-#endif
-
-void WebFrameWidgetBase::ForEachRemoteFrameControlledByWidget(
- const base::RepeatingCallback<void(RemoteFrame*)>& callback) {
- ForEachRemoteFrameChildrenControlledByWidget(local_root_->GetFrame(),
- callback);
-}
-
-void WebFrameWidgetBase::BatterySavingsChanged(WebBatterySavingsFlags savings) {
- widget_base_->LayerTreeHost()->SetEnableFrameRateThrottling(
- savings & kAllowReducedFrameRate);
-}
-
-const viz::LocalSurfaceId& WebFrameWidgetBase::LocalSurfaceIdFromParent() {
- return widget_base_->local_surface_id_from_parent();
-}
-
-cc::LayerTreeHost* WebFrameWidgetBase::LayerTreeHost() {
- return widget_base_->LayerTreeHost();
-}
-
-void WebFrameWidgetBase::NotifyPageScaleFactorChanged(
- float page_scale_factor,
- bool is_pinch_gesture_active) {
- // Store the value to give to any new RemoteFrame that will be created as a
- // descendant of this widget.
- page_scale_factor_in_mainframe_ = page_scale_factor;
- is_pinch_gesture_active_in_mainframe_ = is_pinch_gesture_active;
- // Push the page scale factor down to any child RemoteFrames.
- // TODO(danakj): This ends up setting the page scale factor in the
- // RenderWidgetHost of the child WebFrameWidgetBase, so that it can bounce
- // the value down to its WebFrameWidgetBase. Since this is essentially a
- // global value per-page, we could instead store it once in the browser
- // (such as in RenderViewHost) and distribute it to each WebFrameWidgetBase
- // from there.
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](float page_scale_factor, bool is_pinch_gesture_active,
- RemoteFrame* remote_frame) {
- remote_frame->Client()->PageScaleFactorChanged(page_scale_factor,
- is_pinch_gesture_active);
- },
- page_scale_factor, is_pinch_gesture_active));
-}
-
-void WebFrameWidgetBase::SetPageScaleStateAndLimits(
- float page_scale_factor,
- bool is_pinch_gesture_active,
- float minimum,
- float maximum) {
- widget_base_->LayerTreeHost()->SetPageScaleFactorAndLimits(page_scale_factor,
- minimum, maximum);
-}
-
-void WebFrameWidgetBase::OrientationChanged() {
- local_root_->SendOrientationChangeEvent();
-}
-
-void WebFrameWidgetBase::DidUpdateSurfaceAndScreen(
- const ScreenInfo& previous_original_screen_info) {
- ScreenInfo screen_info = widget_base_->GetScreenInfo();
- if (Platform::Current()->IsUseZoomForDSFEnabled()) {
- View()->SetZoomFactorForDeviceScaleFactor(screen_info.device_scale_factor);
- } else {
- View()->SetDeviceScaleFactor(screen_info.device_scale_factor);
- }
-
- if (Client()->ShouldAutoDetermineCompositingToLCDTextSetting()) {
- // This causes compositing state to be modified which dirties the
- // document lifecycle. Android Webview relies on the document
- // lifecycle being clean after the RenderWidget is initialized, in
- // order to send IPCs that query and change compositing state. So
- // WebFrameWidgetBase::Resize() must come after this call, as it runs the
- // entire document lifecycle.
- View()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
- widget_base_->ComputePreferCompositingToLCDText());
- }
-
- // When the device scale changes, the size and position of the popup would
- // need to be adjusted, which we can't do. Just close the popup, which is
- // also consistent with page zoom and resize behavior.
- if (previous_original_screen_info.device_scale_factor !=
- screen_info.device_scale_factor) {
- View()->CancelPagePopup();
- }
-
- // Propagate changes down to child local root RenderWidgets and BrowserPlugins
- // in other frame trees/processes.
- ScreenInfo original_screen_info = GetOriginalScreenInfo();
- if (previous_original_screen_info != original_screen_info) {
- ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
- [](const ScreenInfo& original_screen_info, RemoteFrame* remote_frame) {
- remote_frame->Client()->DidChangeScreenInfo(original_screen_info);
- },
- original_screen_info));
- }
-}
-
-const ScreenInfo& WebFrameWidgetBase::GetOriginalScreenInfo() {
- return widget_base_->GetScreenInfo();
-}
-
-base::Optional<blink::mojom::ScreenOrientation>
-WebFrameWidgetBase::ScreenOrientationOverride() {
- return View()->ScreenOrientationOverride();
-}
-
-void WebFrameWidgetBase::WasHidden() {
- ForEachLocalFrameControlledByWidget(
- local_root_->GetFrame(),
- WTF::BindRepeating([](WebLocalFrame* local_frame) {
- local_frame->Client()->WasHidden();
- }));
-}
-
-void WebFrameWidgetBase::WasShown(bool was_evicted) {
- ForEachLocalFrameControlledByWidget(
- local_root_->GetFrame(),
- WTF::BindRepeating([](WebLocalFrame* local_frame) {
- local_frame->Client()->WasShown();
- }));
- if (was_evicted) {
- ForEachRemoteFrameControlledByWidget(
- WTF::BindRepeating([](RemoteFrame* remote_frame) {
- remote_frame->Client()->WasEvicted();
- }));
- }
-}
-
-void WebFrameWidgetBase::NotifyInputObservers(
- const WebCoalescedInputEvent& coalesced_event) {
- LocalFrame* frame = FocusedLocalFrameInWidget();
- if (!frame)
- return;
-
- LocalFrameView* frame_view = frame->View();
- if (!frame_view)
- return;
-
- const WebInputEvent& input_event = coalesced_event.Event();
- auto& paint_timing_detector = frame_view->GetPaintTimingDetector();
-
- if (paint_timing_detector.NeedToNotifyInputOrScroll())
- paint_timing_detector.NotifyInputEvent(input_event.GetType());
-}
-
-Frame* WebFrameWidgetBase::FocusedCoreFrame() const {
- return GetPage() ? GetPage()->GetFocusController().FocusedOrMainFrame()
- : nullptr;
-}
-
-HitTestResult WebFrameWidgetBase::HitTestResultForRootFramePos(
- const FloatPoint& pos_in_root_frame) {
- FloatPoint doc_point =
- LocalRootImpl()->GetFrame()->View()->ConvertFromRootFrame(
- pos_in_root_frame);
- HitTestLocation location(doc_point);
- HitTestResult result =
- LocalRootImpl()->GetFrame()->View()->HitTestWithThrottlingAllowed(
- location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
- result.SetToShadowHostIfInRestrictedShadowRoot();
- return result;
-}
-
-KURL WebFrameWidgetBase::GetURLForDebugTrace() {
- WebFrame* main_frame = View()->MainFrame();
- if (main_frame->IsWebLocalFrame())
- return main_frame->ToWebLocalFrame()->GetDocument().Url();
- return {};
-}
-
-void WebFrameWidgetBase::ReleaseMouseLockAndPointerCaptureForTesting() {
- GetPage()->GetPointerLockController().ExitPointerLock();
- MouseCaptureLost();
-}
-
-const viz::FrameSinkId& WebFrameWidgetBase::GetFrameSinkId() {
- // It is valid to create a WebFrameWidget with an invalid frame sink id for
- // printing and placeholders. But if we go to use it, it should be valid.
- DCHECK(frame_sink_id_.is_valid());
- return frame_sink_id_;
-}
-
-WebHitTestResult WebFrameWidgetBase::HitTestResultAt(const gfx::PointF& point) {
- return CoreHitTestResultAt(point);
-}
-
-WebPlugin* WebFrameWidgetBase::GetFocusedPluginContainer() {
- LocalFrame* focused_frame = FocusedLocalFrameInWidget();
- if (!focused_frame)
- return nullptr;
- if (auto* container = focused_frame->GetWebPluginContainer())
- return container->Plugin();
- return nullptr;
-}
-
-bool WebFrameWidgetBase::CanComposeInline() {
- if (auto* plugin = GetFocusedPluginContainer())
- return plugin->CanComposeInline();
- return true;
-}
-
-bool WebFrameWidgetBase::ShouldDispatchImeEventsToPlugin() {
- if (auto* plugin = GetFocusedPluginContainer())
- return plugin->ShouldDispatchImeEventsToPlugin();
- return false;
-}
-
-void WebFrameWidgetBase::ImeSetCompositionForPlugin(
- const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int selection_start,
- int selection_end) {
- if (auto* plugin = GetFocusedPluginContainer()) {
- plugin->ImeSetCompositionForPlugin(
- text,
- std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
- ime_text_spans.end()),
- replacement_range, selection_start, selection_end);
- }
-}
-
-void WebFrameWidgetBase::ImeCommitTextForPlugin(
- const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int relative_cursor_pos) {
- if (auto* plugin = GetFocusedPluginContainer()) {
- plugin->ImeCommitTextForPlugin(
- text,
- std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
- ime_text_spans.end()),
- replacement_range, relative_cursor_pos);
- }
-}
-
-void WebFrameWidgetBase::ImeFinishComposingTextForPlugin(bool keep_selection) {
- if (auto* plugin = GetFocusedPluginContainer())
- plugin->ImeFinishComposingTextForPlugin(keep_selection);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h
deleted file mode 100644
index d2ff4b4c569..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ /dev/null
@@ -1,824 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_FRAME_WIDGET_BASE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_FRAME_WIDGET_BASE_H_
-
-#include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
-#include "cc/input/event_listener_properties.h"
-#include "cc/input/layer_selection_bound.h"
-#include "cc/input/overscroll_behavior.h"
-#include "cc/trees/layer_tree_host.h"
-#include "services/viz/public/mojom/hit_test/input_target_client.mojom-blink.h"
-#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
-#include "third_party/blink/public/common/input/web_gesture_device.h"
-#include "third_party/blink/public/mojom/manifest/display_mode.mojom-blink.h"
-#include "third_party/blink/public/mojom/page/drag.mojom-blink.h"
-#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
-#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
-#include "third_party/blink/public/platform/web_battery_savings.h"
-#include "third_party/blink/public/platform/web_drag_data.h"
-#include "third_party/blink/public/web/web_frame_widget.h"
-#include "third_party/blink/public/web/web_meaningful_layout.h"
-#include "third_party/blink/renderer/core/clipboard/data_object.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/page/page_widget_delegate.h"
-#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
-#include "third_party/blink/renderer/platform/text/text_direction.h"
-#include "third_party/blink/renderer/platform/timer.h"
-#include "third_party/blink/renderer/platform/widget/frame_widget.h"
-#include "third_party/blink/renderer/platform/widget/widget_base_client.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-#include "ui/base/mojom/ui_base_types.mojom-shared.h"
-
-namespace gfx {
-class Point;
-class PointF;
-} // namespace gfx
-
-namespace blink {
-class AnimationWorkletMutatorDispatcherImpl;
-class FloatPoint;
-class HitTestResult;
-class HTMLPlugInElement;
-class LocalFrameView;
-class Page;
-class PageWidgetEventHandler;
-class PaintWorkletPaintDispatcher;
-class RemoteFrame;
-class WebLocalFrameImpl;
-class WebPlugin;
-class WebViewImpl;
-class WidgetBase;
-class ScreenMetricsEmulator;
-
-class CORE_EXPORT WebFrameWidgetBase
- : public GarbageCollected<WebFrameWidgetBase>,
- public WebFrameWidget,
- public WidgetBaseClient,
- public mojom::blink::FrameWidget,
- public viz::mojom::blink::InputTargetClient,
- public FrameWidget,
- public PageWidgetEventHandler {
- public:
- WebFrameWidgetBase(
- WebWidgetClient&,
- CrossVariantMojoAssociatedRemote<
- mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- widget,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool hidden,
- bool never_composited,
- bool is_for_child_local_root);
- ~WebFrameWidgetBase() override;
-
- // Returns the WebFrame that this widget is attached to. It will be a local
- // root since only local roots have a widget attached.
- WebLocalFrameImpl* LocalRootImpl() const { return local_root_; }
-
- // Returns the bounding box of the block type node touched by the WebPoint.
- WebRect ComputeBlockBound(const gfx::Point& point_in_root_frame,
- bool ignore_clipping) const;
-
- void BindLocalRoot(WebLocalFrame&);
-
- // If this widget is for the top level frame. This is different than
- // |ForMainFrame| because |ForMainFrame| could return true but this method
- // returns false. If this widget is a MainFrame widget embedded in another
- // widget, for example embedding a portal.
- virtual bool ForTopLevelFrame() const = 0;
-
- // Returns true if this widget is for a local root that is a child frame,
- // false otherwise.
- virtual bool ForSubframe() const = 0;
-
- // Opposite of |ForSubframe|. If this widget is for the local main frame.
- bool ForMainFrame() const { return !ForSubframe(); }
-
- virtual void IntrinsicSizingInfoChanged(
- mojom::blink::IntrinsicSizingInfoPtr) {}
-
- void AutoscrollStart(const gfx::PointF& position);
- void AutoscrollFling(const gfx::Vector2dF& position);
- void AutoscrollEnd();
-
- // Notifies RenderWidgetHostImpl that the frame widget has painted something.
- void DidMeaningfulLayout(WebMeaningfulLayout layout_type);
-
- bool HandleCurrentKeyboardEvent();
-
- // Creates or returns cached mutator dispatcher. This usually requires a
- // round trip to the compositor. The returned WeakPtr must only be
- // dereferenced on the output |mutator_task_runner|.
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
- EnsureCompositorMutatorDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner);
-
- // TODO: consider merge the input and return value to be one parameter.
- // Creates or returns cached paint dispatcher. The returned WeakPtr must only
- // be dereferenced on the output |paint_task_runner|.
- base::WeakPtr<PaintWorkletPaintDispatcher> EnsureCompositorPaintDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner>* paint_task_runner);
-
- HitTestResult CoreHitTestResultAt(const gfx::PointF&);
-
- // FrameWidget implementation.
- WebWidgetClient* Client() const final { return client_; }
- cc::AnimationHost* AnimationHost() const final;
- void SetOverscrollBehavior(
- const cc::OverscrollBehavior& overscroll_behavior) final;
- void RequestAnimationAfterDelay(const base::TimeDelta&) final;
- void RegisterSelection(cc::LayerSelection selection) final;
- void RequestDecode(const cc::PaintImage&,
- base::OnceCallback<void(bool)>) final;
- void NotifySwapAndPresentationTimeInBlink(
- WebReportTimeCallback swap_callback,
- WebReportTimeCallback presentation_callback) final;
- void RequestBeginMainFrameNotExpected(bool request) final;
- int GetLayerTreeId() final;
- void SetEventListenerProperties(cc::EventListenerClass,
- cc::EventListenerProperties) final;
- cc::EventListenerProperties EventListenerProperties(
- cc::EventListenerClass) const final;
- mojom::blink::DisplayMode DisplayMode() const override;
- const WebVector<gfx::Rect>& WindowSegments() const override;
- void SetDelegatedInkMetadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata) final;
- void DidOverscroll(const gfx::Vector2dF& overscroll_delta,
- const gfx::Vector2dF& accumulated_overscroll,
- const gfx::PointF& position,
- const gfx::Vector2dF& velocity) override;
- void InjectGestureScrollEvent(WebGestureDevice device,
- const gfx::Vector2dF& delta,
- ui::ScrollGranularity granularity,
- cc::ElementId scrollable_area_element_id,
- WebInputEvent::Type injected_type) override;
- void DidChangeCursor(const ui::Cursor&) override;
- void GetCompositionCharacterBoundsInWindow(
- Vector<gfx::Rect>* bounds_in_dips) override;
- gfx::Range CompositionRange() override;
- WebTextInputInfo TextInputInfo() override;
- ui::mojom::VirtualKeyboardVisibilityRequest
- GetLastVirtualKeyboardVisibilityRequest() override;
- bool ShouldSuppressKeyboardForFocusedElement() override;
- void GetEditContextBoundsInWindow(
- base::Optional<gfx::Rect>* control_bounds,
- base::Optional<gfx::Rect>* selection_bounds) override;
- int32_t ComputeWebTextInputNextPreviousFlags() override;
- void ResetVirtualKeyboardVisibilityRequest() override;
- bool GetSelectionBoundsInWindow(gfx::Rect* focus,
- gfx::Rect* anchor,
- base::i18n::TextDirection* focus_dir,
- base::i18n::TextDirection* anchor_dir,
- bool* is_anchor_first) override;
- void ClearTextInputState() override;
-
- bool SetComposition(const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int selection_start,
- int selection_end) override;
- void CommitText(const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int relative_cursor_pos) override;
- void FinishComposingText(bool keep_selection) override;
- bool IsProvisional() override;
- uint64_t GetScrollableContainerIdAt(
- const gfx::PointF& point_in_dips) override;
- void SetEditCommandsForNextKeyEvent(
- Vector<mojom::blink::EditCommandPtr> edit_commands) override;
-
- void AddImeTextSpansToExistingText(
- uint32_t start,
- uint32_t end,
- const Vector<ui::ImeTextSpan>& ime_text_spans) override;
- Vector<ui::mojom::blink::ImeTextSpanInfoPtr> GetImeTextSpansInfo(
- const WebVector<ui::ImeTextSpan>& ime_text_spans) override;
- void ClearImeTextSpansByType(uint32_t start,
- uint32_t end,
- ui::ImeTextSpan::Type type) override;
- void SetCompositionFromExistingText(
- int32_t start,
- int32_t end,
- const Vector<ui::ImeTextSpan>& ime_text_spans) override;
- void ExtendSelectionAndDelete(int32_t before, int32_t after) override;
- void DeleteSurroundingText(int32_t before, int32_t after) override;
- void DeleteSurroundingTextInCodePoints(int32_t before,
- int32_t after) override;
- void SetEditableSelectionOffsets(int32_t start, int32_t end) override;
- void ExecuteEditCommand(const String& command, const String& value) override;
- void Undo() override;
- void Redo() override;
- void Cut() override;
- void Copy() override;
- void CopyToFindPboard() override;
- void Paste() override;
- void PasteAndMatchStyle() override;
- void Delete() override;
- void SelectAll() override;
- void CollapseSelection() override;
- void Replace(const String& word) override;
- void ReplaceMisspelling(const String& word) override;
- void SelectRange(const gfx::Point& base_in_dips,
- const gfx::Point& extent_in_dips) override;
- void AdjustSelectionByCharacterOffset(
- int32_t start,
- int32_t end,
- mojom::blink::SelectionMenuBehavior behavior) override;
- void MoveRangeSelectionExtent(const gfx::Point& extent_in_dips) override;
- void ScrollFocusedEditableNodeIntoRect(
- const gfx::Rect& rect_in_dips) override;
- void MoveCaret(const gfx::Point& point_in_dips) override;
-#if defined(OS_ANDROID)
- void SelectWordAroundCaret(SelectWordAroundCaretCallback callback) override;
-#endif
- gfx::RectF BlinkSpaceToDIPs(const gfx::RectF& rect) override;
- gfx::Rect BlinkSpaceToEnclosedDIPs(const gfx::Rect& rect) override;
- gfx::Size BlinkSpaceToFlooredDIPs(const gfx::Size& size) override;
- gfx::RectF DIPsToBlinkSpace(const gfx::RectF& rect) override;
- gfx::PointF DIPsToBlinkSpace(const gfx::PointF& point) override;
- gfx::Point DIPsToRoundedBlinkSpace(const gfx::Point& point) override;
- float DIPsToBlinkSpace(float scalar) override;
- void RequestMouseLock(
- bool has_transient_user_activation,
- bool request_unadjusted_movement,
- mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback)
- override;
- bool CanComposeInline() override;
- bool ShouldDispatchImeEventsToPlugin() override;
- void ImeSetCompositionForPlugin(const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int selection_start,
- int selection_end) override;
- void ImeCommitTextForPlugin(const String& text,
- const Vector<ui::ImeTextSpan>& ime_text_spans,
- const gfx::Range& replacement_range,
- int relative_cursor_pos) override;
- void ImeFinishComposingTextForPlugin(bool keep_selection) override;
-
- // WebFrameWidget implementation.
- WebLocalFrame* LocalRoot() const override;
- void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) override;
- void SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) override;
- WebInputMethodController* GetActiveWebInputMethodController() const override;
- WebLocalFrame* FocusedWebLocalFrameInWidget() const override;
- void ApplyViewportChangesForTesting(
- const ApplyViewportChangesArgs& args) override;
- void NotifySwapAndPresentationTime(
- WebReportTimeCallback swap_callback,
- WebReportTimeCallback presentation_callback) override;
- scheduler::WebRenderWidgetSchedulingState* RendererWidgetSchedulingState()
- override;
- void WaitForDebuggerWhenShown() override;
- void SetTextZoomFactor(float text_zoom_factor) override;
- float TextZoomFactor() override;
- void SetMainFrameOverlayColor(SkColor) override;
- void AddEditCommandForNextKeyEvent(const WebString& name,
- const WebString& value) override;
- void ClearEditCommands() override;
- bool IsPasting() override;
- bool HandlingSelectRange() override;
- void ReleaseMouseLockAndPointerCaptureForTesting() override;
- const viz::FrameSinkId& GetFrameSinkId() override;
- WebHitTestResult HitTestResultAt(const gfx::PointF&) override;
-
- // Called when a drag-n-drop operation should begin.
- void StartDragging(const WebDragData&,
- DragOperationsMask,
- const SkBitmap& drag_image,
- const gfx::Point& drag_image_offset);
-
- bool DoingDragAndDrop() { return doing_drag_and_drop_; }
- static void SetIgnoreInputEvents(bool value) { ignore_input_events_ = value; }
- static bool IgnoreInputEvents() { return ignore_input_events_; }
-
- // WebWidget methods.
- cc::LayerTreeHost* InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
- cc::TaskGraphRunner* task_graph_runner,
- bool for_child_local_root_frame,
- const ScreenInfo& screen_info,
- std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
- const cc::LayerTreeSettings* settings) override;
- void Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) override;
- void SetCompositorVisible(bool visible) override;
- void SetCursor(const ui::Cursor& cursor) override;
- bool HandlingInputEvent() override;
- void SetHandlingInputEvent(bool handling) override;
- void ProcessInputEventSynchronouslyForTesting(const WebCoalescedInputEvent&,
- HandledEventCallback) override;
- WebInputEventResult DispatchBufferedTouchEvents() override;
- WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
- void UpdateTextInputState() override;
- void UpdateSelectionBounds() override;
- void ShowVirtualKeyboard() override;
- bool HasFocus() override;
- void SetFocus(bool focus) override;
- void FlushInputProcessedCallback() override;
- void CancelCompositionForPepper() override;
- void ApplyVisualProperties(
- const VisualProperties& visual_properties) override;
- bool PinchGestureActiveInMainFrame() override;
- float PageScaleInMainFrame() override;
- const ScreenInfo& GetScreenInfo() override;
- gfx::Rect WindowRect() override;
- gfx::Rect ViewRect() override;
- void SetScreenRects(const gfx::Rect& widget_screen_rect,
- const gfx::Rect& window_screen_rect) override;
- gfx::Size VisibleViewportSizeInDIPs() override;
- bool IsHidden() const override;
- WebString GetLastToolTipTextForTesting() const override;
-
- // WidgetBaseClient methods.
- void BeginMainFrame(base::TimeTicks last_frame_time) override;
- void BeginCommitCompositorFrame() override;
- void EndCommitCompositorFrame(base::TimeTicks commit_start_time) override;
- void RecordDispatchRafAlignedInputTime(
- base::TimeTicks raf_aligned_input_start_time) override;
- void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override;
- void RecordStartOfFrameMetrics() override;
- void RecordEndOfFrameMetrics(
- base::TimeTicks,
- cc::ActiveFrameSequenceTrackers trackers) override;
- std::unique_ptr<cc::BeginMainFrameMetrics> GetBeginMainFrameMetrics()
- override;
- void BeginUpdateLayers() override;
- void EndUpdateLayers() override;
- void DidCommitAndDrawCompositorFrame() override;
- std::unique_ptr<cc::LayerTreeFrameSink> AllocateNewLayerTreeFrameSink()
- override;
- void DidObserveFirstScrollDelay(
- base::TimeDelta first_scroll_delay,
- base::TimeTicks first_scroll_timestamp) override;
- void DidBeginMainFrame() override;
- void WillBeginMainFrame() override;
- void DidCompletePageScaleAnimation() override;
- void FocusChangeComplete() override;
- bool WillHandleGestureEvent(const WebGestureEvent& event) override;
- void WillHandleMouseEvent(const WebMouseEvent& event) override;
- void ObserveGestureEventAndResult(
- const WebGestureEvent& gesture_event,
- const gfx::Vector2dF& unused_delta,
- const cc::OverscrollBehavior& overscroll_behavior,
- bool event_processed) override;
- bool SupportsBufferedTouchEvents() override { return true; }
- void DidHandleKeyEvent() override;
- WebTextInputType GetTextInputType() override;
- void SetCursorVisibilityState(bool is_visible) override;
- blink::FrameWidget* FrameWidget() override { return this; }
- void ScheduleAnimation() override;
- bool ShouldAckSyntheticInputImmediately() override;
- void UpdateVisualProperties(
- const VisualProperties& visual_properties) override;
- void ScheduleAnimationForWebTests() override;
- void OrientationChanged() override;
- void DidUpdateSurfaceAndScreen(
- const ScreenInfo& previous_original_screen_info) override;
- const ScreenInfo& GetOriginalScreenInfo() override;
- base::Optional<blink::mojom::ScreenOrientation> ScreenOrientationOverride()
- override;
- void WasHidden() override;
- void WasShown(bool was_evicted) override;
- KURL GetURLForDebugTrace() override;
-
- // mojom::blink::FrameWidget methods.
- void DragTargetDragEnter(const WebDragData&,
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperationsMask operations_allowed,
- uint32_t key_modifiers,
- DragTargetDragEnterCallback callback) override;
- void DragTargetDragOver(const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperationsMask operations_allowed,
- uint32_t key_modifiers,
- DragTargetDragOverCallback callback) override;
- void DragTargetDragLeave(const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point) override;
- void DragTargetDrop(const WebDragData&,
- const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- uint32_t key_modifiers) override;
- void DragSourceEndedAt(const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragOperation) override;
- void DragSourceSystemDragEnded() override;
- void SetBackgroundOpaque(bool opaque) override;
- void SetActive(bool active) override;
- // For both mainframe and childframe change the text direction of the
- // currently selected input field (if any).
- void SetTextDirection(base::i18n::TextDirection direction) override;
- // Sets the inherited effective touch action on an out-of-process iframe.
- void SetInheritedEffectiveTouchActionForSubFrame(
- WebTouchAction touch_action) override {}
- // Toggles render throttling for an out-of-process iframe. Local frames are
- // throttled based on their visibility in the viewport, but remote frames
- // have to have throttling information propagated from parent to child
- // across processes.
- void UpdateRenderThrottlingStatusForSubFrame(
- bool is_throttled,
- bool subtree_throttled) override {}
- void ShowContextMenu(ui::mojom::MenuSourceType source_type,
- const gfx::Point& location) override;
- void SetViewportIntersection(
- mojom::blink::ViewportIntersectionStatePtr intersection_state) override {}
-
- // Sets the inert bit on an out-of-process iframe, causing it to ignore
- // input.
- void SetIsInertForSubFrame(bool inert) override {}
-#if defined(OS_MAC)
- void GetStringAtPoint(const gfx::Point& point_in_local_root,
- GetStringAtPointCallback callback) override;
-#endif
-
- // Sets the display mode, which comes from the top-level browsing context and
- // is applied to all widgets.
- void SetDisplayMode(mojom::blink::DisplayMode);
-
- base::Optional<gfx::Point> GetAndResetContextMenuLocation();
-
- void BindWidgetCompositor(
- mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) override;
-
- void BindInputTargetClient(
- mojo::PendingReceiver<viz::mojom::blink::InputTargetClient> receiver)
- override;
-
- // viz::mojom::blink::InputTargetClient:
- void FrameSinkIdAt(const gfx::PointF& point,
- const uint64_t trace_id,
- FrameSinkIdAtCallback callback) override;
-
- // Called when the FrameView for this Widget's local root is created.
- virtual void DidCreateLocalRootView() {}
-
- virtual void SetZoomLevel(double zoom_level);
-
- // Enable or disable auto-resize. This is part of
- // UpdateVisualProperties though tests may call to it more directly.
- virtual void SetAutoResizeMode(bool auto_resize,
- const gfx::Size& min_size_before_dsf,
- const gfx::Size& max_size_before_dsf,
- float device_scale_factor) = 0;
-
- // This method returns the focused frame belonging to this WebWidget, that
- // is, a focused frame with the same local root as the one corresponding
- // to this widget. It will return nullptr if no frame is focused or, the
- // focused frame has a different local root.
- LocalFrame* FocusedLocalFrameInWidget() const;
-
- virtual void Trace(Visitor*) const;
-
- // For when the embedder itself change scales on the page (e.g. devtools)
- // and wants all of the content at the new scale to be crisp
- void SetNeedsRecalculateRasterScales();
-
- // Sets the background color to be filled in as gutter behind/around the
- // painted content. Non-composited WebViews need not implement this, as they
- // paint into another widget which has a background color of its own.
- void SetBackgroundColor(SkColor color);
-
- // Starts an animation of the page scale to a target scale factor and scroll
- // offset.
- // If use_anchor is true, destination is a point on the screen that will
- // remain fixed for the duration of the animation.
- // If use_anchor is false, destination is the final top-left scroll position.
- void StartPageScaleAnimation(const gfx::Vector2d& destination,
- bool use_anchor,
- float new_page_scale,
- base::TimeDelta duration);
-
- // Called to update if scroll events should be sent.
- void SetHaveScrollEventHandlers(bool);
-
- // Start deferring commits to the compositor, allowing document lifecycle
- // updates without committing the layer tree. Commits are deferred
- // until at most the given |timeout| has passed. If multiple calls are made
- // when deferral is active then the initial timeout applies.
- void StartDeferringCommits(base::TimeDelta timeout);
- // Immediately stop deferring commits.
- void StopDeferringCommits(cc::PaintHoldingCommitTrigger);
-
- // Prevents any updates to the input for the layer tree, and the layer tree
- // itself, and the layer tree from becoming visible.
- std::unique_ptr<cc::ScopedDeferMainFrameUpdate> DeferMainFrameUpdate();
-
- // Sets the amount that the top and bottom browser controls are showing, from
- // 0 (hidden) to 1 (fully shown).
- void SetBrowserControlsShownRatio(float top_ratio, float bottom_ratio);
-
- // Set browser controls params. These params consist of top and bottom
- // heights, min-heights, browser_controls_shrink_blink_size, and
- // animate_browser_controls_height_changes. If
- // animate_browser_controls_height_changes is set to true, changes to the
- // browser controls height will be animated. If
- // browser_controls_shrink_blink_size is set to true, then Blink shrunk the
- // viewport clip layers by the top and bottom browser controls height. Top
- // controls will translate the web page down and do not immediately scroll
- // when hiding. The bottom controls scroll immediately and never translate the
- // content (only clip it).
- void SetBrowserControlsParams(cc::BrowserControlsParams params);
-
- cc::LayerTreeDebugState GetLayerTreeDebugState();
- void SetLayerTreeDebugState(const cc::LayerTreeDebugState& state);
-
- // Ask compositor to composite a frame for testing. This will generate a
- // BeginMainFrame, and update the document lifecycle.
- void SynchronouslyCompositeForTesting(base::TimeTicks frame_time);
-
- void SetToolTipText(const String& tooltip_text, TextDirection dir);
-
- void ShowVirtualKeyboardOnElementFocus();
- void ProcessTouchAction(WebTouchAction touch_action);
-
- // Called when a gesture event has been processed.
- void DidHandleGestureEvent(const WebGestureEvent& event,
- bool event_cancelled);
-
- // Called to update if pointerrawupdate events should be sent.
- void SetHasPointerRawUpdateEventHandlers(bool);
-
- // Called to update whether low latency input mode is enabled or not.
- void SetNeedsLowLatencyInput(bool);
-
- // Requests unbuffered (ie. low latency) input until a pointerup
- // event occurs.
- void RequestUnbufferedInputEvents();
-
- // Requests unbuffered (ie. low latency) input due to debugger being
- // attached. Debugger needs to paint when stopped in the event handler.
- void SetNeedsUnbufferedInputForDebugger(bool);
-
- // Called when the main frame navigates.
- void DidNavigate();
-
- // Called when the widget should get targeting input.
- void SetMouseCapture(bool capture);
-
- // Sets the current page scale factor and minimum / maximum limits. Both
- // limits are initially 1 (no page scale allowed).
- virtual void SetPageScaleStateAndLimits(float page_scale_factor,
- bool is_pinch_gesture_active,
- float minimum,
- float maximum);
-
- // The value of the applied battery-savings META element in the document
- // changed.
- void BatterySavingsChanged(WebBatterySavingsFlags savings);
-
- const viz::LocalSurfaceId& LocalSurfaceIdFromParent();
- cc::LayerTreeHost* LayerTreeHost();
-
- virtual ScreenMetricsEmulator* DeviceEmulator() { return nullptr; }
-
- // Called during |UpdateVisualProperties| to apply the new size to the widget.
- virtual void ApplyVisualPropertiesSizing(
- const VisualProperties& visual_properties) = 0;
-
- // Calculates the selection bounds in the root frame. Returns bounds unchanged
- // when there is no focused frame or no selection.
- virtual void CalculateSelectionBounds(gfx::Rect& anchor_in_root_frame,
- gfx::Rect& focus_in_root_frame) = 0;
-
- // Update the surface allocation information, compositor viewport rect and
- // screen info on the widget.
- void UpdateSurfaceAndScreenInfo(
- const viz::LocalSurfaceId& new_local_surface_id,
- const gfx::Rect& compositor_viewport_pixel_rect,
- const ScreenInfo& new_screen_info);
- // Similar to UpdateSurfaceAndScreenInfo but the surface allocation
- // and compositor viewport rect remains the same.
- void UpdateScreenInfo(const ScreenInfo& screen_info);
- void UpdateSurfaceAndCompositorRect(
- const viz::LocalSurfaceId& new_local_surface_id,
- const gfx::Rect& compositor_viewport_pixel_rect);
- void UpdateCompositorViewportRect(
- const gfx::Rect& compositor_viewport_pixel_rect);
- void SetWindowSegments(const std::vector<gfx::Rect>& window_segments);
- viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::PointF& point,
- gfx::PointF* local_point);
-
- // Set the pending window rect. For every SetPendingWindowRect
- // call there must be an AckPendingWindowRect call.
- void SetPendingWindowRect(const gfx::Rect& window_screen_rect);
-
- // Clear a previously set pending window rect. For every SetPendingWindowRect
- // call there must be an AckPendingWindowRect call.
- void AckPendingWindowRect();
-
- // Constrains the viewport intersection for use by IntersectionObserver,
- // and indicates whether the frame may be painted over or obscured in the
- // parent. This is needed for out-of-process iframes to know if they are
- // clipped or obscured by ancestor frames in another process.
- virtual void SetRemoteViewportIntersection(
- const mojom::blink::ViewportIntersectionState& intersection_state) {}
-
- // Return the focused WebPlugin if there is one.
- WebPlugin* GetFocusedPluginContainer();
-
- protected:
- enum DragAction { kDragEnter, kDragOver };
-
- // Consolidate some common code between starting a drag over a target and
- // updating a drag over a target. If we're starting a drag, |isEntering|
- // should be true.
- DragOperation DragTargetDragEnterOrOver(const gfx::PointF& point_in_viewport,
- const gfx::PointF& screen_point,
- DragAction,
- uint32_t key_modifiers);
-
- // Helper function to call VisualViewport::viewportToRootFrame().
- gfx::PointF ViewportToRootFrame(const gfx::PointF& point_in_viewport) const;
-
- WebViewImpl* View() const;
-
- // Returns the page object associated with this widget. This may be null when
- // the page is shutting down, but will be valid at all other times.
- Page* GetPage() const;
-
- mojom::blink::FrameWidgetHost* GetAssociatedFrameWidgetHost() const;
-
- // Helper function to process events while pointer locked.
- void PointerLockMouseEvent(const WebCoalescedInputEvent&);
- bool IsPointerLocked();
-
- // The fullscreen granted status from the most recent VisualProperties update.
- bool IsFullscreenGranted();
-
- // Return the LocalFrameView used for animation scrolling. This is overridden
- // by WebViewFrameWidget and should eventually be removed once null does not
- // need to be passed for the main frame.
- virtual LocalFrameView* GetLocalFrameViewForAnimationScrolling() = 0;
-
- void NotifyPageScaleFactorChanged(float page_scale_factor,
- bool is_pinch_gesture_active);
-
- // Helper for notifying frame-level objects that care about input events.
- // TODO: With some effort, this could be folded into a common implementation
- // of WebViewImpl::HandleInputEvent and WebFrameWidgetImpl::HandleInputEvent.
- void NotifyInputObservers(const WebCoalescedInputEvent& coalesced_event);
-
- Frame* FocusedCoreFrame() const;
-
- // Perform a hit test for a point relative to the root frame of the page.
- HitTestResult HitTestResultForRootFramePos(
- const FloatPoint& pos_in_root_frame);
-
- // A copy of the web drop data object we received from the browser.
- Member<DataObject> current_drag_data_;
-
- bool doing_drag_and_drop_ = false;
-
- // The available drag operations (copy, move link...) allowed by the source.
- DragOperation operations_allowed_ = kDragOperationNone;
-
- // The current drag operation as negotiated by the source and destination.
- // When not equal to DragOperationNone, the drag data can be dropped onto the
- // current drop target in this WebView (the drop target can accept the drop).
- DragOperation drag_operation_ = kDragOperationNone;
-
- // This field stores drag/drop related info for the event that is currently
- // being handled. If the current event results in starting a drag/drop
- // session, this info is sent to the browser along with other drag/drop info.
- mojom::blink::DragEventSourceInfo possible_drag_event_info_;
-
- // Base functionality all widgets have. This is a member as to avoid
- // complicated inheritance structures.
- std::unique_ptr<WidgetBase> widget_base_;
-
- // The last seen page scale state, which comes from the main frame if we're
- // in a child frame. This state is propagated through the RenderWidget tree
- // passed to any new child RenderWidget.
- float page_scale_factor_in_mainframe_ = 1.f;
- bool is_pinch_gesture_active_in_mainframe_ = false;
-
- // If set, the (plugin) element which has mouse capture.
- // TODO(dtapuska): Move to private once all input handling is moved to
- // base class.
- Member<HTMLPlugInElement> mouse_capture_element_;
-
- // keyPress events to be suppressed if the associated keyDown event was
- // handled.
- // TODO(dtapuska): Move to private once all input handling is moved to
- // base class.
- bool suppress_next_keypress_event_ = false;
-
- private:
- // PageWidgetEventHandler methods:
- void HandleMouseDown(LocalFrame&, const WebMouseEvent&) override;
- WebInputEventResult HandleMouseUp(LocalFrame&, const WebMouseEvent&) override;
- WebInputEventResult HandleMouseWheel(LocalFrame&,
- const WebMouseWheelEvent&) override;
- WebInputEventResult HandleCharEvent(const WebKeyboardEvent&) override;
-
- WebInputEventResult HandleCapturedMouseEvent(const WebCoalescedInputEvent&);
- void MouseContextMenu(const WebMouseEvent&);
- void CancelDrag();
- void RequestAnimationAfterDelayTimerFired(TimerBase*);
- void PresentationCallbackForMeaningfulLayout(blink::WebSwapResult,
- base::TimeTicks);
-
- void ForEachRemoteFrameControlledByWidget(
- const base::RepeatingCallback<void(RemoteFrame*)>& callback);
-
- static bool ignore_input_events_;
-
- WebWidgetClient* client_;
-
- const viz::FrameSinkId frame_sink_id_;
-
- // WebFrameWidget is associated with a subtree of the frame tree,
- // corresponding to a maximal connected tree of LocalFrames. This member
- // points to the root of that subtree.
- Member<WebLocalFrameImpl> local_root_;
-
- mojom::blink::DisplayMode display_mode_;
-
- WebVector<gfx::Rect> window_segments_;
-
- // This is owned by the LayerTreeHostImpl, and should only be used on the
- // compositor thread, so we keep the TaskRunner where you post tasks to
- // make that happen.
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher_;
- scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner_;
-
- // The |paint_dispatcher_| should only be dereferenced on the
- // |paint_task_runner_| (in practice this is the compositor thread). We keep a
- // copy of it here to provide to new PaintWorkletProxyClient objects (which
- // run on the worklet thread) so that they can talk to the
- // PaintWorkletPaintDispatcher on the compositor thread.
- base::WeakPtr<PaintWorkletPaintDispatcher> paint_dispatcher_;
- scoped_refptr<base::SingleThreadTaskRunner> paint_task_runner_;
-
- std::unique_ptr<TaskRunnerTimer<WebFrameWidgetBase>>
- request_animation_after_delay_timer_;
-
- // WebFrameWidgetBase is not tied to ExecutionContext
- HeapMojoAssociatedRemote<mojom::blink::FrameWidgetHost,
- HeapMojoWrapperMode::kWithoutContextObserver>
- frame_widget_host_{nullptr};
- // WebFrameWidgetBase is not tied to ExecutionContext
- HeapMojoAssociatedReceiver<mojom::blink::FrameWidget,
- WebFrameWidgetBase,
- HeapMojoWrapperMode::kWithoutContextObserver>
- receiver_{this, nullptr};
- HeapMojoReceiver<viz::mojom::blink::InputTargetClient,
- WebFrameWidgetBase,
- HeapMojoWrapperMode::kWithoutContextObserver>
- input_target_receiver_{this, nullptr};
-
- // Different consumers in the browser process makes different assumptions, so
- // must always send the first IPC regardless of value.
- base::Optional<bool> has_touch_handlers_;
-
- Vector<mojom::blink::EditCommandPtr> edit_commands_;
-
- base::Optional<gfx::Point> host_context_menu_location_;
- uint32_t last_capture_sequence_number_ = 0u;
-
- // Indicates whether tab-initiated fullscreen was granted.
- bool is_fullscreen_granted_ = false;
-
- // Indicates whether we need to consume scroll gestures to move cursor.
- bool swipe_to_move_cursor_activated_ = false;
-
- // Set when a measurement begins, reset when the measurement is taken.
- base::Optional<base::TimeTicks> update_layers_start_time_;
-
- // Metrics for gathering time for commit of compositor frame.
- base::Optional<base::TimeTicks> commit_compositor_frame_start_time_;
-
- friend class WebViewImpl;
- friend class ReportTimeSwapPromise;
-};
-
-template <>
-struct DowncastTraits<WebFrameWidgetBase> {
- // All concrete implementations of WebFrameWidget are derived from
- // WebFrameWidgetBase.
- static bool AllowFrom(const WebFrameWidget& widget) { return true; }
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index eaa7e12154b..e3e764c59b0 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -33,62 +33,112 @@
#include <memory>
#include <utility>
-#include "base/auto_reset.h"
-#include "base/optional.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
#include "build/build_config.h"
-#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h"
+#include "cc/trees/compositor_commit_data.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/swap_promise.h"
+#include "cc/trees/ukm_manager.h"
+#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
+#include "third_party/blink/public/mojom/input/touch_event.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/scheduler/web_render_widget_scheduling_state.h"
#include "third_party/blink/public/web/web_autofill_client.h"
-#include "third_party/blink/public/web/web_element.h"
-#include "third_party/blink/public/web/web_frame_widget.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/public/web/web_non_composited_widget_client.h"
+#include "third_party/blink/public/web/web_performance.h"
#include "third_party/blink/public/web/web_plugin.h"
-#include "third_party/blink/public/web/web_range.h"
-#include "third_party/blink/public/web/web_widget_client.h"
-#include "third_party/blink/renderer/core/editing/editing_utilities.h"
-#include "third_party/blink/renderer/core/editing/editor.h"
-#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/public/web/web_settings.h"
+#include "third_party/blink/public/web/web_view_client.h"
+#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
-#include "third_party/blink/renderer/core/editing/plain_text_range.h"
-#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/events/current_input_event.h"
#include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
+#include "third_party/blink/renderer/core/events/wheel_event.h"
#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
-#include "third_party/blink/renderer/core/exported/web_page_popup_impl.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
+#include "third_party/blink/renderer/core/exported/web_settings_impl.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/remote_frame.h"
+#include "third_party/blink/renderer/core/frame/remote_frame_client.h"
+#include "third_party/blink/renderer/core/frame/screen.h"
+#include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
-#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
+#include "third_party/blink/renderer/core/html/battery_savings.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
+#include "third_party/blink/renderer/core/html/portal/document_portals.h"
+#include "third_party/blink/renderer/core/html/portal/portal_contents.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/hit_test_location.h"
+#include "third_party/blink/renderer/core/layout/hit_test_request.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
+#include "third_party/blink/renderer/core/loader/interactive_detector.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
+#include "third_party/blink/renderer/core/page/drag_actions.h"
+#include "third_party/blink/renderer/core/page/drag_controller.h"
+#include "third_party/blink/renderer/core/page/drag_data.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
+#include "third_party/blink/renderer/core/page/link_highlight.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/page/page_popup.h"
#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
-#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
+#include "third_party/blink/renderer/core/page/validation_message_client.h"
+#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
+#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
+#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
+#include "third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h"
+#include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
#include "third_party/blink/renderer/platform/widget/widget_base.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
+#include "ui/gfx/geometry/point_conversions.h"
+
+#if defined(OS_MAC)
+#include "third_party/blink/renderer/core/editing/substring_util.h"
+#include "third_party/blink/renderer/platform/fonts/mac/attributed_string_type_converter.h"
+#include "ui/base/mojom/attributed_string.mojom-blink.h"
+#include "ui/gfx/geometry/point.h"
+#endif
+
+namespace WTF {
+template <>
+struct CrossThreadCopier<blink::WebReportTimeCallback>
+ : public CrossThreadCopierByValuePassThrough<blink::WebReportTimeCallback> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+} // namespace WTF
namespace blink {
+
namespace {
+
+using ::ui::mojom::blink::DragOperation;
+
const int kCaretPadding = 10;
const float kIdealPaddingRatio = 0.3f;
@@ -102,104 +152,80 @@ FloatRect NormalizeRect(const IntRect& to_normalize, const IntRect& base_rect) {
return result;
}
-} // namespace
-
-// WebFrameWidget ------------------------------------------------------------
+void ForEachLocalFrameControlledByWidget(
+ LocalFrame* frame,
+ const base::RepeatingCallback<void(WebLocalFrameImpl*)>& callback) {
+ callback.Run(WebLocalFrameImpl::FromFrame(frame));
+ for (Frame* child = frame->FirstChild(); child;
+ child = child->NextSibling()) {
+ if (child->IsLocalFrame()) {
+ ForEachLocalFrameControlledByWidget(DynamicTo<LocalFrame>(child),
+ callback);
+ }
+ }
+}
-static CreateWebViewFrameWidgetFunction g_create_web_view_frame_widget =
- nullptr;
+// Iterate the remote children that will be controlled by the widget. Skip over
+// any RemoteFrames have have another LocalFrame root as their parent.
+void ForEachRemoteFrameChildrenControlledByWidget(
+ Frame* frame,
+ const base::RepeatingCallback<void(RemoteFrame*)>& callback) {
+ for (Frame* child = frame->Tree().FirstChild(); child;
+ child = child->Tree().NextSibling()) {
+ if (auto* remote_frame = DynamicTo<RemoteFrame>(child)) {
+ callback.Run(remote_frame);
+ ForEachRemoteFrameChildrenControlledByWidget(remote_frame, callback);
+ } else if (auto* local_frame = DynamicTo<LocalFrame>(child)) {
+ // If iteration arrives at a local root then don't descend as it will be
+ // controlled by another widget.
+ if (!local_frame->IsLocalRoot()) {
+ ForEachRemoteFrameChildrenControlledByWidget(local_frame, callback);
+ }
+ }
+ }
-void InstallCreateWebViewFrameWidgetHook(
- CreateWebViewFrameWidgetFunction create_widget) {
- g_create_web_view_frame_widget = create_widget;
+ // Iterate on any portals owned by a local frame.
+ if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
+ if (Document* document = local_frame->GetDocument()) {
+ for (PortalContents* portal :
+ DocumentPortals::From(*document).GetPortals()) {
+ if (RemoteFrame* remote_frame = portal->GetFrame())
+ callback.Run(remote_frame);
+ }
+ }
+ }
}
-WebFrameWidget* WebFrameWidget::CreateForMainFrame(
- WebWidgetClient* client,
- WebLocalFrame* main_frame,
- CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
- mojo_frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- mojo_frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- mojo_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- mojo_widget,
- const viz::FrameSinkId& frame_sink_id,
- bool is_for_nested_main_frame,
- bool hidden,
- bool never_composited) {
- DCHECK(client) << "A valid WebWidgetClient must be supplied.";
- DCHECK(!main_frame->Parent()); // This is the main frame.
-
- // Grabs the WebViewImpl associated with the |main_frame|, which will then
- // be wrapped by the WebViewFrameWidget, with calls being forwarded to the
- // |main_frame|'s WebViewImpl.
- // Note: this can't DCHECK that the view's main frame points to
- // |main_frame|, as provisional frames violate this precondition.
- WebLocalFrameImpl& main_frame_impl = To<WebLocalFrameImpl>(*main_frame);
- DCHECK(main_frame_impl.ViewImpl());
- WebViewImpl& web_view_impl = *main_frame_impl.ViewImpl();
-
- WebViewFrameWidget* widget = nullptr;
- if (g_create_web_view_frame_widget) {
- widget = g_create_web_view_frame_widget(
- util::PassKey<WebFrameWidget>(), *client, web_view_impl,
- std::move(mojo_frame_widget_host), std::move(mojo_frame_widget),
- std::move(mojo_widget_host), std::move(mojo_widget),
- main_frame->Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
- frame_sink_id, is_for_nested_main_frame, hidden, never_composited);
- } else {
- // Note: this isn't a leak, as the object has a self-reference that the
- // caller needs to release by calling Close().
- // TODO(dcheng): Remove the special bridge class for main frame widgets.
- widget = MakeGarbageCollected<WebViewFrameWidget>(
- util::PassKey<WebFrameWidget>(), *client, web_view_impl,
- std::move(mojo_frame_widget_host), std::move(mojo_frame_widget),
- std::move(mojo_widget_host), std::move(mojo_widget),
- main_frame->Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
- frame_sink_id, is_for_nested_main_frame, hidden, never_composited);
- }
- widget->BindLocalRoot(*main_frame);
- return widget;
-}
-
-WebFrameWidget* WebFrameWidget::CreateForChildLocalRoot(
- WebWidgetClient* client,
- WebLocalFrame* local_root,
- CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
- mojo_frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- mojo_frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- mojo_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- mojo_widget,
- const viz::FrameSinkId& frame_sink_id,
- bool hidden,
- bool never_composited) {
- DCHECK(client) << "A valid WebWidgetClient must be supplied.";
- DCHECK(local_root->Parent()); // This is not the main frame.
- // Frames whose direct ancestor is a remote frame are local roots. Verify this
- // is one. Other frames should be using the widget for their nearest local
- // root.
- DCHECK(local_root->Parent()->IsWebRemoteFrame());
+viz::FrameSinkId GetRemoteFrameSinkId(const HitTestResult& result) {
+ Node* node = result.InnerNode();
+ auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node);
+ if (!frame_owner || !frame_owner->ContentFrame() ||
+ !frame_owner->ContentFrame()->IsRemoteFrame())
+ return viz::FrameSinkId();
- // Note: this isn't a leak, as the object has a self-reference that the
- // caller needs to release by calling Close().
- auto* widget = MakeGarbageCollected<WebFrameWidgetImpl>(
- util::PassKey<WebFrameWidget>(), *client,
- std::move(mojo_frame_widget_host), std::move(mojo_frame_widget),
- std::move(mojo_widget_host), std::move(mojo_widget),
- local_root->Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
- frame_sink_id, hidden, never_composited);
- widget->BindLocalRoot(*local_root);
- return widget;
+ RemoteFrame* remote_frame = To<RemoteFrame>(frame_owner->ContentFrame());
+ if (remote_frame->IsIgnoredForHitTest())
+ return viz::FrameSinkId();
+ LayoutObject* object = node->GetLayoutObject();
+ DCHECK(object);
+ if (!object->IsBox())
+ return viz::FrameSinkId();
+
+ IntPoint local_point = RoundedIntPoint(result.LocalPoint());
+ if (!To<LayoutBox>(object)->ComputedCSSContentBoxRect().Contains(local_point))
+ return viz::FrameSinkId();
+
+ return remote_frame->GetFrameSinkId();
}
+} // namespace
+
+// WebFrameWidget ------------------------------------------------------------
+
+bool WebFrameWidgetImpl::ignore_input_events_ = false;
+
WebFrameWidgetImpl::WebFrameWidgetImpl(
- util::PassKey<WebFrameWidget>,
- WebWidgetClient& client,
+ base::PassKey<WebLocalFrame>,
CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
frame_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
@@ -211,30 +237,1684 @@ WebFrameWidgetImpl::WebFrameWidgetImpl(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const viz::FrameSinkId& frame_sink_id,
bool hidden,
- bool never_composited)
- : WebFrameWidgetBase(client,
- std::move(frame_widget_host),
- std::move(frame_widget),
- std::move(widget_host),
- std::move(widget),
- std::move(task_runner),
- frame_sink_id,
- hidden,
- never_composited,
- /*is_for_child_local_root=*/true),
- self_keep_alive_(PERSISTENT_FROM_HERE, this) {}
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame)
+ : widget_base_(std::make_unique<WidgetBase>(/*widget_base_client=*/this,
+ std::move(widget_host),
+ std::move(widget),
+ task_runner,
+ hidden,
+ never_composited,
+ is_for_child_local_root)),
+ frame_sink_id_(frame_sink_id),
+ is_for_child_local_root_(is_for_child_local_root) {
+ DCHECK(task_runner);
+ if (is_for_nested_main_frame)
+ main_data().is_for_nested_main_frame = is_for_nested_main_frame;
+ frame_widget_host_.Bind(std::move(frame_widget_host), task_runner);
+ receiver_.Bind(std::move(frame_widget), task_runner);
+}
+
+WebFrameWidgetImpl::~WebFrameWidgetImpl() {
+ // Ensure that Close is called and we aren't releasing |widget_base_| in the
+ // destructor.
+ // TODO(crbug.com/1139104): This CHECK can be changed to a DCHECK once
+ // the issue is solved.
+ CHECK(!widget_base_);
+}
+
+void WebFrameWidgetImpl::BindLocalRoot(WebLocalFrame& local_root) {
+ local_root_ = To<WebLocalFrameImpl>(local_root);
+}
+
+bool WebFrameWidgetImpl::ForTopMostMainFrame() const {
+ return ForMainFrame() && !main_data().is_for_nested_main_frame;
+}
+
+void WebFrameWidgetImpl::SetIsNestedMainFrameWidget(bool is_nested) {
+ main_data().is_for_nested_main_frame = is_nested;
+}
+
+void WebFrameWidgetImpl::Close() {
+ LocalFrameView* frame_view;
+ if (is_for_child_local_root_) {
+ frame_view = LocalRootImpl()->GetFrame()->View();
+ } else {
+ // Scrolling for the root frame is special we need to pass null indicating
+ // we are at the top of the tree when setting up the Animation. Which will
+ // cause ownership of the timeline and animation host.
+ // See ScrollingCoordinator::AnimationHostInitialized.
+ frame_view = nullptr;
+ }
+ GetPage()->WillCloseAnimationHost(frame_view);
+
+ if (ForMainFrame()) {
+ // Closing the WebFrameWidgetImpl happens in response to the local main
+ // frame being detached from the Page/WebViewImpl.
+ View()->SetMainFrameViewWidget(nullptr);
+ }
+
+ mutator_dispatcher_ = nullptr;
+ local_root_ = nullptr;
+ widget_base_->Shutdown();
+ widget_base_.reset();
+ // These WeakPtrs must be invalidated for WidgetInputHandlerManager at the
+ // same time as the WidgetBase is.
+ input_handler_weak_ptr_factory_.InvalidateWeakPtrs();
+ receiver_.reset();
+ input_target_receiver_.reset();
+}
+
+WebLocalFrame* WebFrameWidgetImpl::LocalRoot() const {
+ return local_root_;
+}
+
+gfx::Rect WebFrameWidgetImpl::ComputeBlockBound(
+ const gfx::Point& point_in_root_frame,
+ bool ignore_clipping) const {
+ HitTestLocation location(local_root_->GetFrameView()->ConvertFromRootFrame(
+ PhysicalOffset(IntPoint(point_in_root_frame))));
+ HitTestRequest::HitTestRequestType hit_type =
+ HitTestRequest::kReadOnly | HitTestRequest::kActive |
+ (ignore_clipping ? HitTestRequest::kIgnoreClipping : 0);
+ HitTestResult result =
+ local_root_->GetFrame()->GetEventHandler().HitTestResultAtLocation(
+ location, hit_type);
+ result.SetToShadowHostIfInRestrictedShadowRoot();
+
+ Node* node = result.InnerNodeOrImageMapImage();
+ if (!node)
+ return gfx::Rect();
+
+ // Find the block type node based on the hit node.
+ // FIXME: This wants to walk flat tree with
+ // LayoutTreeBuilderTraversal::parent().
+ while (node &&
+ (!node->GetLayoutObject() || node->GetLayoutObject()->IsInline()))
+ node = LayoutTreeBuilderTraversal::Parent(*node);
+
+ // Return the bounding box in the root frame's coordinate space.
+ if (node) {
+ IntRect absolute_rect = node->GetLayoutObject()->AbsoluteBoundingBoxRect();
+ LocalFrame* frame = node->GetDocument().GetFrame();
+ return frame->View()->ConvertToRootFrame(absolute_rect);
+ }
+ return gfx::Rect();
+}
+
+void WebFrameWidgetImpl::DragTargetDragEnter(
+ const WebDragData& web_drag_data,
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragOperationsMask operations_allowed,
+ uint32_t key_modifiers,
+ DragTargetDragEnterCallback callback) {
+ DCHECK(!current_drag_data_);
+
+ current_drag_data_ = DataObject::Create(web_drag_data);
+ operations_allowed_ = operations_allowed;
+
+ DragOperation operation = DragTargetDragEnterOrOver(
+ point_in_viewport, screen_point, kDragEnter, key_modifiers);
+ std::move(callback).Run(operation);
+}
+
+void WebFrameWidgetImpl::DragTargetDragOver(
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragOperationsMask operations_allowed,
+ uint32_t key_modifiers,
+ DragTargetDragOverCallback callback) {
+ operations_allowed_ = operations_allowed;
+
+ DragOperation operation = DragTargetDragEnterOrOver(
+ point_in_viewport, screen_point, kDragOver, key_modifiers);
+ std::move(callback).Run(operation);
+}
+
+void WebFrameWidgetImpl::DragTargetDragLeave(
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point) {
+ DCHECK(current_drag_data_);
+
+ // TODO(paulmeyer): It shouldn't be possible for |current_drag_data_| to be
+ // null here, but this is somehow happening (rarely). This suggests that in
+ // some cases drag-leave is happening before drag-enter, which should be
+ // impossible. This needs to be investigated further. Once fixed, the extra
+ // check for |!current_drag_data_| should be removed. (crbug.com/671152)
+ if (IgnoreInputEvents() || !current_drag_data_) {
+ CancelDrag();
+ return;
+ }
+
+ gfx::PointF point_in_root_frame(ViewportToRootFrame(point_in_viewport));
+ DragData drag_data(current_drag_data_.Get(), FloatPoint(point_in_root_frame),
+ FloatPoint(screen_point), operations_allowed_);
+
+ GetPage()->GetDragController().DragExited(&drag_data,
+ *local_root_->GetFrame());
+
+ // FIXME: why is the drag scroll timer not stopped here?
+
+ drag_operation_ = DragOperation::kNone;
+ current_drag_data_ = nullptr;
+}
+
+void WebFrameWidgetImpl::DragTargetDrop(const WebDragData& web_drag_data,
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ uint32_t key_modifiers) {
+ gfx::PointF point_in_root_frame(ViewportToRootFrame(point_in_viewport));
+
+ DCHECK(current_drag_data_);
+ current_drag_data_ = DataObject::Create(web_drag_data);
+
+ // If this webview transitions from the "drop accepting" state to the "not
+ // accepting" state, then our IPC message reply indicating that may be in-
+ // flight, or else delayed by javascript processing in this webview. If a
+ // drop happens before our IPC reply has reached the browser process, then
+ // the browser forwards the drop to this webview. So only allow a drop to
+ // proceed if our webview drag_operation_ state is not DragOperation::kNone.
+
+ if (drag_operation_ == DragOperation::kNone) {
+ // IPC RACE CONDITION: do not allow this drop.
+ DragTargetDragLeave(point_in_viewport, screen_point);
+ return;
+ }
+
+ if (!IgnoreInputEvents()) {
+ current_drag_data_->SetModifiers(key_modifiers);
+ DragData drag_data(current_drag_data_.Get(),
+ FloatPoint(point_in_root_frame),
+ FloatPoint(screen_point), operations_allowed_);
+
+ GetPage()->GetDragController().PerformDrag(&drag_data,
+ *local_root_->GetFrame());
+ }
+ drag_operation_ = DragOperation::kNone;
+ current_drag_data_ = nullptr;
+}
+
+void WebFrameWidgetImpl::DragSourceEndedAt(const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragOperation operation) {
+ if (!local_root_) {
+ // We should figure out why |local_root_| could be nullptr
+ // (https://crbug.com/792345).
+ return;
+ }
+
+ if (IgnoreInputEvents()) {
+ CancelDrag();
+ return;
+ }
+ gfx::PointF point_in_root_frame(
+ GetPage()->GetVisualViewport().ViewportToRootFrame(
+ FloatPoint(point_in_viewport)));
+
+ WebMouseEvent fake_mouse_move(
+ WebInputEvent::Type::kMouseMove, point_in_root_frame, screen_point,
+ WebPointerProperties::Button::kLeft, 0, WebInputEvent::kNoModifiers,
+ base::TimeTicks::Now());
+ fake_mouse_move.SetFrameScale(1);
+ local_root_->GetFrame()->GetEventHandler().DragSourceEndedAt(fake_mouse_move,
+ operation);
+}
+
+void WebFrameWidgetImpl::DragSourceSystemDragEnded() {
+ CancelDrag();
+}
+
+void WebFrameWidgetImpl::SetBackgroundOpaque(bool opaque) {
+ if (opaque) {
+ View()->ClearBaseBackgroundColorOverride();
+ View()->ClearBackgroundColorOverride();
+ } else {
+ View()->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
+ View()->SetBackgroundColorOverride(SK_ColorTRANSPARENT);
+ }
+}
+
+void WebFrameWidgetImpl::SetTextDirection(base::i18n::TextDirection direction) {
+ LocalFrame* focusedFrame = FocusedLocalFrameInWidget();
+ if (focusedFrame)
+ focusedFrame->SetTextDirection(direction);
+}
+
+void WebFrameWidgetImpl::SetInheritedEffectiveTouchActionForSubFrame(
+ TouchAction touch_action) {
+ DCHECK(ForSubframe());
+ LocalRootImpl()->GetFrame()->SetInheritedEffectiveTouchAction(touch_action);
+}
+
+void WebFrameWidgetImpl::UpdateRenderThrottlingStatusForSubFrame(
+ bool is_throttled,
+ bool subtree_throttled,
+ bool display_locked) {
+ DCHECK(ForSubframe());
+ // TODO(szager,vmpstr): The parent render process currently rolls up
+ // display_locked into the value of subtree throttled here; display_locked
+ // should be maintained as a separate bit and transmitted between render
+ // processes.
+ LocalRootImpl()->GetFrameView()->UpdateRenderThrottlingStatus(
+ is_throttled, subtree_throttled, display_locked, /*recurse=*/true);
+}
+
+#if defined(OS_MAC)
+void WebFrameWidgetImpl::GetStringAtPoint(const gfx::Point& point_in_local_root,
+ GetStringAtPointCallback callback) {
+ gfx::Point baseline_point;
+ ui::mojom::blink::AttributedStringPtr attributed_string = nullptr;
+ NSAttributedString* string = SubstringUtil::AttributedWordAtPoint(
+ this, point_in_local_root, baseline_point);
+ if (string)
+ attributed_string = ui::mojom::blink::AttributedString::From(string);
+
+ std::move(callback).Run(std::move(attributed_string), baseline_point);
+}
+#endif
+
+void WebFrameWidgetImpl::BindWidgetCompositor(
+ mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) {
+ widget_base_->BindWidgetCompositor(std::move(receiver));
+}
+
+void WebFrameWidgetImpl::BindInputTargetClient(
+ mojo::PendingReceiver<viz::mojom::blink::InputTargetClient> receiver) {
+ DCHECK(!input_target_receiver_.is_bound());
+ input_target_receiver_.Bind(
+ std::move(receiver),
+ local_root_->GetTaskRunner(TaskType::kInternalDefault));
+}
+
+void WebFrameWidgetImpl::FrameSinkIdAt(const gfx::PointF& point,
+ const uint64_t trace_id,
+ FrameSinkIdAtCallback callback) {
+ TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Event.Pipeline",
+ TRACE_ID_GLOBAL(trace_id),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "step", "FrameSinkIdAt");
+
+ gfx::PointF local_point;
+ viz::FrameSinkId id = GetFrameSinkIdAtPoint(point, &local_point);
+ std::move(callback).Run(id, local_point);
+}
+
+viz::FrameSinkId WebFrameWidgetImpl::GetFrameSinkIdAtPoint(
+ const gfx::PointF& point_in_dips,
+ gfx::PointF* local_point_in_dips) {
+ HitTestResult result =
+ CoreHitTestResultAt(widget_base_->DIPsToBlinkSpace(point_in_dips));
+
+ Node* result_node = result.InnerNode();
+ *local_point_in_dips = gfx::PointF(point_in_dips);
+
+ // TODO(crbug.com/797828): When the node is null the caller may
+ // need to do extra checks. Like maybe update the layout and then
+ // call the hit-testing API. Either way it might be better to have
+ // a DCHECK for the node rather than a null check here.
+ if (!result_node) {
+ return frame_sink_id_;
+ }
+
+ viz::FrameSinkId remote_frame_sink_id = GetRemoteFrameSinkId(result);
+ if (remote_frame_sink_id.is_valid()) {
+ FloatPoint local_point = FloatPoint(result.LocalPoint());
+ LayoutObject* object = result_node->GetLayoutObject();
+ if (auto* box = DynamicTo<LayoutBox>(object))
+ local_point.MoveBy(-FloatPoint(box->PhysicalContentBoxOffset()));
+
+ *local_point_in_dips =
+ widget_base_->BlinkSpaceToDIPs(gfx::PointF(local_point));
+ return remote_frame_sink_id;
+ }
+
+ // Return the FrameSinkId for the current widget if the point did not hit
+ // test to a remote frame, or the point is outside of the remote frame's
+ // content box, or the remote frame doesn't have a valid FrameSinkId yet.
+ return frame_sink_id_;
+}
+
+gfx::RectF WebFrameWidgetImpl::BlinkSpaceToDIPs(const gfx::RectF& rect) {
+ return widget_base_->BlinkSpaceToDIPs(rect);
+}
+
+gfx::Rect WebFrameWidgetImpl::BlinkSpaceToEnclosedDIPs(const gfx::Rect& rect) {
+ return widget_base_->BlinkSpaceToEnclosedDIPs(rect);
+}
+
+gfx::Size WebFrameWidgetImpl::BlinkSpaceToFlooredDIPs(const gfx::Size& size) {
+ return widget_base_->BlinkSpaceToFlooredDIPs(size);
+}
+
+gfx::RectF WebFrameWidgetImpl::DIPsToBlinkSpace(const gfx::RectF& rect) {
+ return widget_base_->DIPsToBlinkSpace(rect);
+}
+
+gfx::PointF WebFrameWidgetImpl::DIPsToBlinkSpace(const gfx::PointF& point) {
+ return widget_base_->DIPsToBlinkSpace(point);
+}
+
+gfx::Point WebFrameWidgetImpl::DIPsToRoundedBlinkSpace(
+ const gfx::Point& point) {
+ return widget_base_->DIPsToRoundedBlinkSpace(point);
+}
+
+float WebFrameWidgetImpl::DIPsToBlinkSpace(float scalar) {
+ return widget_base_->DIPsToBlinkSpace(scalar);
+}
+
+gfx::Size WebFrameWidgetImpl::DIPsToCeiledBlinkSpace(const gfx::Size& size) {
+ return widget_base_->DIPsToCeiledBlinkSpace(size);
+}
+
+void WebFrameWidgetImpl::SetActive(bool active) {
+ View()->SetIsActive(active);
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleKeyEvent(
+ const WebKeyboardEvent& event) {
+ DCHECK((event.GetType() == WebInputEvent::Type::kRawKeyDown) ||
+ (event.GetType() == WebInputEvent::Type::kKeyDown) ||
+ (event.GetType() == WebInputEvent::Type::kKeyUp));
+
+ // Please refer to the comments explaining the m_suppressNextKeypressEvent
+ // member.
+ // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
+ // Webkit. A keyDown event is typically associated with a keyPress(char)
+ // event and a keyUp event. We reset this flag here as this is a new keyDown
+ // event.
+ suppress_next_keypress_event_ = false;
+
+ // If there is a popup open, it should be the one processing the event,
+ // not the page.
+ scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
+ if (page_popup) {
+ page_popup->HandleKeyEvent(event);
+ if (event.GetType() == WebInputEvent::Type::kRawKeyDown) {
+ suppress_next_keypress_event_ = true;
+ }
+ return WebInputEventResult::kHandledSystem;
+ }
+
+ auto* frame = DynamicTo<LocalFrame>(FocusedCoreFrame());
+ if (!frame)
+ return WebInputEventResult::kNotHandled;
+
+ WebInputEventResult result = frame->GetEventHandler().KeyEvent(event);
+ if (result != WebInputEventResult::kNotHandled) {
+ if (WebInputEvent::Type::kRawKeyDown == event.GetType()) {
+ // Suppress the next keypress event unless the focused node is a plugin
+ // node. (Flash needs these keypress events to handle non-US keyboards.)
+ Element* element = FocusedElement();
+ if (element && element->GetLayoutObject() &&
+ element->GetLayoutObject()->IsEmbeddedObject()) {
+ if (event.windows_key_code == VKEY_TAB) {
+ // If the plugin supports keyboard focus then we should not send a tab
+ // keypress event.
+ WebPluginContainerImpl* plugin_view =
+ To<LayoutEmbeddedContent>(element->GetLayoutObject())->Plugin();
+ if (plugin_view && plugin_view->SupportsKeyboardFocus()) {
+ suppress_next_keypress_event_ = true;
+ }
+ }
+ } else {
+ suppress_next_keypress_event_ = true;
+ }
+ }
+ return result;
+ }
+
+#if !defined(OS_MAC)
+ const WebInputEvent::Type kContextMenuKeyTriggeringEventType =
+#if defined(OS_WIN)
+ WebInputEvent::Type::kKeyUp;
+#else
+ WebInputEvent::Type::kRawKeyDown;
+#endif
+ const WebInputEvent::Type kShiftF10TriggeringEventType =
+ WebInputEvent::Type::kRawKeyDown;
+
+ bool is_unmodified_menu_key =
+ !(event.GetModifiers() & WebInputEvent::kInputModifiers) &&
+ event.windows_key_code == VKEY_APPS;
+ bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) ==
+ WebInputEvent::kShiftKey &&
+ event.windows_key_code == VKEY_F10;
+ if ((is_unmodified_menu_key &&
+ event.GetType() == kContextMenuKeyTriggeringEventType) ||
+ (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) {
+ View()->SendContextMenuEvent();
+ return WebInputEventResult::kHandledSystem;
+ }
+#endif // !defined(OS_MAC)
+
+ return WebInputEventResult::kNotHandled;
+}
+
+void WebFrameWidgetImpl::HandleMouseDown(LocalFrame& local_root,
+ const WebMouseEvent& event) {
+ WebViewImpl* view_impl = View();
+ // If there is a popup open, close it as the user is clicking on the page
+ // (outside of the popup). We also save it so we can prevent a click on an
+ // element from immediately reopening the same popup.
+ scoped_refptr<WebPagePopupImpl> page_popup;
+ if (event.button == WebMouseEvent::Button::kLeft) {
+ page_popup = view_impl->GetPagePopup();
+ view_impl->CancelPagePopup();
+ }
+
+ // Take capture on a mouse down on a plugin so we can send it mouse events.
+ // If the hit node is a plugin but a scrollbar is over it don't start mouse
+ // capture because it will interfere with the scrollbar receiving events.
+ PhysicalOffset point(LayoutUnit(event.PositionInWidget().x()),
+ LayoutUnit(event.PositionInWidget().y()));
+ if (event.button == WebMouseEvent::Button::kLeft) {
+ HitTestLocation location(
+ LocalRootImpl()->GetFrameView()->ConvertFromRootFrame(point));
+ HitTestResult result(
+ LocalRootImpl()->GetFrame()->GetEventHandler().HitTestResultAtLocation(
+ location));
+ result.SetToShadowHostIfInRestrictedShadowRoot();
+ Node* hit_node = result.InnerNode();
+ auto* html_element = DynamicTo<HTMLElement>(hit_node);
+ if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
+ hit_node->GetLayoutObject()->IsEmbeddedObject() && html_element &&
+ html_element->IsPluginElement()) {
+ mouse_capture_element_ = To<HTMLPlugInElement>(hit_node);
+ SetMouseCapture(true);
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("input", "capturing mouse",
+ TRACE_ID_LOCAL(this));
+ }
+ }
+
+ PageWidgetEventHandler::HandleMouseDown(local_root, event);
+ // PageWidgetEventHandler may have detached the frame.
+ if (!LocalRootImpl())
+ return;
+
+ if (view_impl->GetPagePopup() && page_popup &&
+ view_impl->GetPagePopup()->HasSamePopupClient(page_popup.get())) {
+ // That click triggered a page popup that is the same as the one we just
+ // closed. It needs to be closed.
+ view_impl->CancelPagePopup();
+ }
+
+ // Dispatch the contextmenu event regardless of if the click was swallowed.
+ if (!GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
+#if defined(OS_MAC)
+ if (event.button == WebMouseEvent::Button::kRight ||
+ (event.button == WebMouseEvent::Button::kLeft &&
+ event.GetModifiers() & WebMouseEvent::kControlKey))
+ MouseContextMenu(event);
+#else
+ if (event.button == WebMouseEvent::Button::kRight)
+ MouseContextMenu(event);
+#endif
+ }
+}
+
+void WebFrameWidgetImpl::HandleMouseLeave(LocalFrame& local_root,
+ const WebMouseEvent& event) {
+ View()->SetMouseOverURL(WebURL());
+ PageWidgetEventHandler::HandleMouseLeave(local_root, event);
+ // PageWidgetEventHandler may have detached the frame.
+}
+
+void WebFrameWidgetImpl::MouseContextMenu(const WebMouseEvent& event) {
+ GetPage()->GetContextMenuController().ClearContextMenu();
+
+ WebMouseEvent transformed_event =
+ TransformWebMouseEvent(LocalRootImpl()->GetFrameView(), event);
+ transformed_event.menu_source_type = kMenuSourceMouse;
+
+ // Find the right target frame. See issue 1186900.
+ HitTestResult result = HitTestResultForRootFramePos(
+ FloatPoint(transformed_event.PositionInRootFrame()));
+ Frame* target_frame;
+ if (result.InnerNodeOrImageMapImage())
+ target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
+ else
+ target_frame = GetPage()->GetFocusController().FocusedOrMainFrame();
+
+ // This will need to be changed to a nullptr check when focus control
+ // is refactored, at which point focusedOrMainFrame will never return a
+ // RemoteFrame.
+ // See https://crbug.com/341918.
+ LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
+ if (!target_local_frame)
+ return;
+
+ {
+ ContextMenuAllowedScope scope;
+ target_local_frame->GetEventHandler().SendContextMenuEvent(
+ transformed_event);
+ }
+ // Actually showing the context menu is handled by the ContextMenuClient
+ // implementation...
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleMouseUp(
+ LocalFrame& local_root,
+ const WebMouseEvent& event) {
+ WebInputEventResult result =
+ PageWidgetEventHandler::HandleMouseUp(local_root, event);
+ // PageWidgetEventHandler may have detached the frame.
+ if (!LocalRootImpl())
+ return result;
+
+ if (GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
+ // Dispatch the contextmenu event regardless of if the click was swallowed.
+ // On Mac/Linux, we handle it on mouse down, not up.
+ if (event.button == WebMouseEvent::Button::kRight)
+ MouseContextMenu(event);
+ }
+ return result;
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent(
+ const WebGestureEvent& event) {
+ WebInputEventResult event_result = WebInputEventResult::kNotHandled;
+
+ // Fling events are not sent to the renderer.
+ CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingStart);
+ CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingCancel);
+
+ WebViewImpl* web_view = View();
+
+ LocalFrame* frame = LocalRootImpl()->GetFrame();
+ WebGestureEvent scaled_event = TransformWebGestureEvent(frame->View(), event);
+
+ // Special handling for double tap and scroll events as we don't want to
+ // hit test for them.
+ switch (event.GetType()) {
+ case WebInputEvent::Type::kGestureDoubleTap:
+ if (web_view->SettingsImpl()->DoubleTapToZoomEnabled() &&
+ web_view->MinimumPageScaleFactor() !=
+ web_view->MaximumPageScaleFactor()) {
+ IntPoint pos_in_local_frame_root =
+ FlooredIntPoint(scaled_event.PositionInRootFrame());
+ auto block_bounds =
+ gfx::Rect(ComputeBlockBound(pos_in_local_frame_root, false));
+
+ if (ForMainFrame()) {
+ web_view->AnimateDoubleTapZoom(pos_in_local_frame_root, block_bounds);
+ } else {
+ // This sends the tap point and bounds to the main frame renderer via
+ // the browser, where their coordinates will be transformed into the
+ // main frame's coordinate space.
+ GetAssociatedFrameWidgetHost()->AnimateDoubleTapZoomInMainFrame(
+ pos_in_local_frame_root, block_bounds);
+ }
+ }
+ event_result = WebInputEventResult::kHandledSystem;
+ DidHandleGestureEvent(event);
+ return event_result;
+ case WebInputEvent::Type::kGestureScrollBegin:
+ case WebInputEvent::Type::kGestureScrollEnd:
+ case WebInputEvent::Type::kGestureScrollUpdate:
+ // If we are getting any scroll toss close any page popup that is open.
+ web_view->CancelPagePopup();
+
+ // Scrolling-related gesture events invoke EventHandler recursively for
+ // each frame down the chain, doing a single-frame hit-test per frame.
+ // This matches handleWheelEvent. Perhaps we could simplify things by
+ // rewriting scroll handling to work inner frame out, and then unify with
+ // other gesture events.
+ event_result =
+ frame->GetEventHandler().HandleGestureScrollEvent(scaled_event);
+ DidHandleGestureEvent(event);
+ return event_result;
+ default:
+ break;
+ }
+
+ // Hit test across all frames and do touch adjustment as necessary for the
+ // event type.
+ GestureEventWithHitTestResults targeted_event =
+ frame->GetEventHandler().TargetGestureEvent(scaled_event);
+
+ // Link highlight animations are only for the main frame.
+ if (ForMainFrame()) {
+ // Handle link highlighting outside the main switch to avoid getting lost in
+ // the complicated set of cases handled below.
+ switch (scaled_event.GetType()) {
+ case WebInputEvent::Type::kGestureShowPress:
+ // Queue a highlight animation, then hand off to regular handler.
+ web_view->EnableTapHighlightAtPoint(targeted_event);
+ break;
+ case WebInputEvent::Type::kGestureTapCancel:
+ case WebInputEvent::Type::kGestureTap:
+ case WebInputEvent::Type::kGestureLongPress:
+ GetPage()->GetLinkHighlight().StartHighlightAnimationIfNeeded();
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (scaled_event.GetType()) {
+ case WebInputEvent::Type::kGestureTap: {
+ {
+ ContextMenuAllowedScope scope;
+ event_result =
+ frame->GetEventHandler().HandleGestureEvent(targeted_event);
+ }
+
+ if (web_view->GetPagePopup() && last_hidden_page_popup_ &&
+ web_view->GetPagePopup()->HasSamePopupClient(
+ last_hidden_page_popup_.get())) {
+ // The tap triggered a page popup that is the same as the one we just
+ // closed. It needs to be closed.
+ web_view->CancelPagePopup();
+ }
+ // Don't have this value persist outside of a single tap gesture, plus
+ // we're done with it now.
+ last_hidden_page_popup_ = nullptr;
+ break;
+ }
+ case WebInputEvent::Type::kGestureTwoFingerTap:
+ case WebInputEvent::Type::kGestureLongPress:
+ case WebInputEvent::Type::kGestureLongTap:
+ if (scaled_event.GetType() == WebInputEvent::Type::kGestureLongTap) {
+ if (LocalFrame* inner_frame =
+ targeted_event.GetHitTestResult().InnerNodeFrame()) {
+ if (!inner_frame->GetEventHandler().LongTapShouldInvokeContextMenu())
+ break;
+ } else if (!frame->GetEventHandler().LongTapShouldInvokeContextMenu()) {
+ break;
+ }
+ }
+
+ GetPage()->GetContextMenuController().ClearContextMenu();
+ {
+ ContextMenuAllowedScope scope;
+ event_result =
+ frame->GetEventHandler().HandleGestureEvent(targeted_event);
+ }
+
+ break;
+ case WebInputEvent::Type::kGestureTapDown:
+ // Touch pinch zoom and scroll on the page (outside of a popup) must hide
+ // the popup. In case of a touch scroll or pinch zoom, this function is
+ // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
+ // When we close a popup because of a GestureTapDown, we also save it so
+ // we can prevent the following GestureTap from immediately reopening the
+ // same popup.
+ // This value should not persist outside of a gesture, so is cleared by
+ // GestureTap (where it is used) and by GestureCancel.
+ last_hidden_page_popup_ = web_view->GetPagePopup();
+ web_view->CancelPagePopup();
+ event_result =
+ frame->GetEventHandler().HandleGestureEvent(targeted_event);
+ break;
+ case WebInputEvent::Type::kGestureTapCancel:
+ // Don't have this value persist outside of a single tap gesture.
+ last_hidden_page_popup_ = nullptr;
+ event_result =
+ frame->GetEventHandler().HandleGestureEvent(targeted_event);
+ break;
+ case WebInputEvent::Type::kGestureShowPress:
+ case WebInputEvent::Type::kGestureTapUnconfirmed:
+ event_result =
+ frame->GetEventHandler().HandleGestureEvent(targeted_event);
+ break;
+ default:
+ NOTREACHED();
+ }
+ DidHandleGestureEvent(event);
+ return event_result;
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleMouseWheel(
+ LocalFrame& frame,
+ const WebMouseWheelEvent& event) {
+ View()->CancelPagePopup();
+ return PageWidgetEventHandler::HandleMouseWheel(frame, event);
+ // PageWidgetEventHandler may have detached the frame.
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleCharEvent(
+ const WebKeyboardEvent& event) {
+ DCHECK_EQ(event.GetType(), WebInputEvent::Type::kChar);
+
+ // Please refer to the comments explaining the m_suppressNextKeypressEvent
+ // member. The m_suppressNextKeypressEvent is set if the KeyDown is
+ // handled by Webkit. A keyDown event is typically associated with a
+ // keyPress(char) event and a keyUp event. We reset this flag here as it
+ // only applies to the current keyPress event.
+ bool suppress = suppress_next_keypress_event_;
+ suppress_next_keypress_event_ = false;
+
+ // If there is a popup open, it should be the one processing the event,
+ // not the page.
+ scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
+ if (page_popup)
+ return page_popup->HandleKeyEvent(event);
+
+ LocalFrame* frame = To<LocalFrame>(FocusedCoreFrame());
+ if (!frame) {
+ return suppress ? WebInputEventResult::kHandledSuppressed
+ : WebInputEventResult::kNotHandled;
+ }
+
+ EventHandler& handler = frame->GetEventHandler();
+
+ if (!event.IsCharacterKey())
+ return WebInputEventResult::kHandledSuppressed;
+
+ // Accesskeys are triggered by char events and can't be suppressed.
+ // It is unclear whether a keypress should be dispatched as well
+ // crbug.com/563507
+ if (handler.HandleAccessKey(event))
+ return WebInputEventResult::kHandledSystem;
+
+ // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
+ // the eventHandler::keyEvent. We mimic this behavior on all platforms since
+ // for now we are converting other platform's key events to windows key
+ // events.
+ if (event.is_system_key)
+ return WebInputEventResult::kNotHandled;
+
+ if (suppress)
+ return WebInputEventResult::kHandledSuppressed;
+
+ WebInputEventResult result = handler.KeyEvent(event);
+ if (result != WebInputEventResult::kNotHandled)
+ return result;
+
+ return WebInputEventResult::kNotHandled;
+}
+
+void WebFrameWidgetImpl::CancelDrag() {
+ // It's possible for this to be called while we're not doing a drag if
+ // it's from a previous page that got unloaded.
+ if (!doing_drag_and_drop_)
+ return;
+ GetPage()->GetDragController().DragEnded();
+ doing_drag_and_drop_ = false;
+}
+
+void WebFrameWidgetImpl::StartDragging(const WebDragData& drag_data,
+ DragOperationsMask operations_allowed,
+ const SkBitmap& drag_image,
+ const gfx::Point& drag_image_offset) {
+ doing_drag_and_drop_ = true;
+ if (drag_and_drop_disabled_) {
+ DragSourceSystemDragEnded();
+ return;
+ }
-WebFrameWidgetImpl::~WebFrameWidgetImpl() = default;
+ gfx::Point offset_in_dips =
+ widget_base_->BlinkSpaceToFlooredDIPs(drag_image_offset);
+ GetAssociatedFrameWidgetHost()->StartDragging(
+ drag_data, operations_allowed, drag_image,
+ gfx::Vector2d(offset_in_dips.x(), offset_in_dips.y()),
+ possible_drag_event_info_.Clone());
+}
+
+DragOperation WebFrameWidgetImpl::DragTargetDragEnterOrOver(
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragAction drag_action,
+ uint32_t key_modifiers) {
+ DCHECK(current_drag_data_);
+ // TODO(paulmeyer): It shouldn't be possible for |m_currentDragData| to be
+ // null here, but this is somehow happening (rarely). This suggests that in
+ // some cases drag-over is happening before drag-enter, which should be
+ // impossible. This needs to be investigated further. Once fixed, the extra
+ // check for |!m_currentDragData| should be removed. (crbug.com/671504)
+ if (IgnoreInputEvents() || !current_drag_data_) {
+ CancelDrag();
+ return DragOperation::kNone;
+ }
+
+ FloatPoint point_in_root_frame(ViewportToRootFrame(point_in_viewport));
+
+ current_drag_data_->SetModifiers(key_modifiers);
+ DragData drag_data(current_drag_data_.Get(), FloatPoint(point_in_root_frame),
+ FloatPoint(screen_point), operations_allowed_);
+
+ DragOperation drag_operation =
+ GetPage()->GetDragController().DragEnteredOrUpdated(
+ &drag_data, *local_root_->GetFrame());
+
+ // Mask the drag operation against the drag source's allowed
+ // operations.
+ if (!(static_cast<int>(drag_operation) &
+ drag_data.DraggingSourceOperationMask()))
+ drag_operation = DragOperation::kNone;
+
+ drag_operation_ = drag_operation;
+
+ return drag_operation_;
+}
+
+void WebFrameWidgetImpl::SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
+ scroll_latched_element_id);
+ if (target_node) {
+ target_node->GetDocument().EnqueueOverscrollEventForNode(
+ target_node, overscroll_delta.x(), overscroll_delta.y());
+ }
+}
+
+void WebFrameWidgetImpl::SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {
+ if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
+ return;
+
+ Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
+ scroll_latched_element_id);
+ if (target_node)
+ target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
+}
+
+void WebFrameWidgetImpl::UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) {
+ if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl())
+ devtools->SetPageIsScrolling(commit_data.is_scroll_active);
+
+ RecordManipulationTypeCounts(commit_data.manipulation_info);
+
+ if (commit_data.scroll_latched_element_id == cc::ElementId())
+ return;
+
+ if (!commit_data.overscroll_delta.IsZero()) {
+ SendOverscrollEventFromImplSide(commit_data.overscroll_delta,
+ commit_data.scroll_latched_element_id);
+ }
+
+ // TODO(bokan): If a scroll ended and a new one began in the same Blink frame
+ // (e.g. during a long running main thread task), this will erroneously
+ // dispatch the scroll end to the latter (still-scrolling) element.
+ // https://crbug.com/1116780.
+ if (commit_data.scroll_gesture_did_end)
+ SendScrollEndEventFromImplSide(commit_data.scroll_latched_element_id);
+}
+
+WebInputMethodController*
+WebFrameWidgetImpl::GetActiveWebInputMethodController() const {
+ WebLocalFrameImpl* local_frame =
+ WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
+ return local_frame ? local_frame->GetInputMethodController() : nullptr;
+}
+
+void WebFrameWidgetImpl::DisableDragAndDrop() {
+ drag_and_drop_disabled_ = true;
+}
+
+gfx::PointF WebFrameWidgetImpl::ViewportToRootFrame(
+ const gfx::PointF& point_in_viewport) const {
+ return GetPage()->GetVisualViewport().ViewportToRootFrame(
+ FloatPoint(point_in_viewport));
+}
+
+WebViewImpl* WebFrameWidgetImpl::View() const {
+ return local_root_->ViewImpl();
+}
+
+Page* WebFrameWidgetImpl::GetPage() const {
+ return View()->GetPage();
+}
+
+mojom::blink::FrameWidgetHost*
+WebFrameWidgetImpl::GetAssociatedFrameWidgetHost() const {
+ return frame_widget_host_.get();
+}
+
+void WebFrameWidgetImpl::RequestDecode(
+ const PaintImage& image,
+ base::OnceCallback<void(bool)> callback) {
+ widget_base_->LayerTreeHost()->QueueImageDecode(image, std::move(callback));
+}
+
+void WebFrameWidgetImpl::Trace(Visitor* visitor) const {
+ visitor->Trace(local_root_);
+ visitor->Trace(current_drag_data_);
+ visitor->Trace(frame_widget_host_);
+ visitor->Trace(receiver_);
+ visitor->Trace(input_target_receiver_);
+ visitor->Trace(mouse_capture_element_);
+ visitor->Trace(device_emulator_);
+}
+
+void WebFrameWidgetImpl::SetNeedsRecalculateRasterScales() {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->SetNeedsRecalculateRasterScales();
+}
+
+void WebFrameWidgetImpl::SetBackgroundColor(SkColor color) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->set_background_color(color);
+}
+
+void WebFrameWidgetImpl::SetOverscrollBehavior(
+ const cc::OverscrollBehavior& overscroll_behavior) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->SetOverscrollBehavior(overscroll_behavior);
+}
+
+void WebFrameWidgetImpl::RegisterSelection(cc::LayerSelection selection) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->RegisterSelection(selection);
+}
+
+void WebFrameWidgetImpl::StartPageScaleAnimation(
+ const gfx::Vector2d& destination,
+ bool use_anchor,
+ float new_page_scale,
+ base::TimeDelta duration) {
+ widget_base_->LayerTreeHost()->StartPageScaleAnimation(
+ destination, use_anchor, new_page_scale, duration);
+}
+
+void WebFrameWidgetImpl::RequestBeginMainFrameNotExpected(bool request) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->RequestBeginMainFrameNotExpected(request);
+}
+
+void WebFrameWidgetImpl::DidCommitAndDrawCompositorFrame() {
+ ForEachLocalFrameControlledByWidget(
+ local_root_->GetFrame(),
+ WTF::BindRepeating([](WebLocalFrameImpl* local_frame) {
+ local_frame->Client()->DidCommitAndDrawCompositorFrame();
+ }));
+}
+
+void WebFrameWidgetImpl::DidObserveFirstScrollDelay(
+ base::TimeDelta first_scroll_delay,
+ base::TimeTicks first_scroll_timestamp) {
+ if (!local_root_ || !(local_root_->GetFrame()) ||
+ !(local_root_->GetFrame()->GetDocument())) {
+ return;
+ }
+ InteractiveDetector* interactive_detector =
+ InteractiveDetector::From(*(local_root_->GetFrame()->GetDocument()));
+ if (interactive_detector) {
+ interactive_detector->DidObserveFirstScrollDelay(first_scroll_delay,
+ first_scroll_timestamp);
+ }
+}
+
+std::unique_ptr<cc::LayerTreeFrameSink>
+WebFrameWidgetImpl::AllocateNewLayerTreeFrameSink() {
+ return nullptr;
+}
+
+void WebFrameWidgetImpl::DidBeginMainFrame() {
+ DCHECK(LocalRootImpl()->GetFrame());
+ PageWidgetDelegate::DidBeginFrame(*LocalRootImpl()->GetFrame());
+}
+
+void WebFrameWidgetImpl::UpdateLifecycle(WebLifecycleUpdate requested_update,
+ DocumentUpdateReason reason) {
+ TRACE_EVENT0("blink", "WebFrameWidgetImpl::UpdateLifecycle");
+ if (!LocalRootImpl())
+ return;
+
+ PageWidgetDelegate::UpdateLifecycle(*GetPage(), *LocalRootImpl()->GetFrame(),
+ requested_update, reason);
+ if (requested_update != WebLifecycleUpdate::kAll)
+ return;
+
+ View()->UpdatePagePopup();
+
+ // Meaningful layout events and background colors only apply to main frames.
+ if (ForMainFrame()) {
+ MainFrameData& data = main_data();
+
+ // There is no background color for non-composited WebViews (eg
+ // printing).
+ if (View()->does_composite()) {
+ SkColor background_color = View()->BackgroundColor();
+ SetBackgroundColor(background_color);
+ if (background_color != data.last_background_color) {
+ LocalRootImpl()->GetFrame()->DidChangeBackgroundColor(
+ background_color, false /* color_adjust */);
+ data.last_background_color = background_color;
+ }
+ }
+
+ if (LocalFrameView* view = LocalRootImpl()->GetFrameView()) {
+ LocalFrame* frame = LocalRootImpl()->GetFrame();
+
+ if (data.should_dispatch_first_visually_non_empty_layout &&
+ view->IsVisuallyNonEmpty()) {
+ data.should_dispatch_first_visually_non_empty_layout = false;
+ // TODO(esprehn): Move users of this callback to something
+ // better, the heuristic for "visually non-empty" is bad.
+ DidMeaningfulLayout(WebMeaningfulLayout::kVisuallyNonEmpty);
+ }
+
+ if (data.should_dispatch_first_layout_after_finished_parsing &&
+ frame->GetDocument()->HasFinishedParsing()) {
+ data.should_dispatch_first_layout_after_finished_parsing = false;
+ DidMeaningfulLayout(WebMeaningfulLayout::kFinishedParsing);
+ }
+
+ if (data.should_dispatch_first_layout_after_finished_loading &&
+ frame->GetDocument()->IsLoadCompleted()) {
+ data.should_dispatch_first_layout_after_finished_loading = false;
+ DidMeaningfulLayout(WebMeaningfulLayout::kFinishedLoading);
+ }
+ }
+ }
+}
+
+void WebFrameWidgetImpl::DidCompletePageScaleAnimation() {
+ // Page scale animations only happen on the main frame.
+ DCHECK(ForMainFrame());
+ if (auto* focused_frame = View()->FocusedFrame()) {
+ if (focused_frame->AutofillClient())
+ focused_frame->AutofillClient()->DidCompleteFocusChangeInFrame();
+ }
+}
+
+void WebFrameWidgetImpl::ScheduleAnimation() {
+ if (!View()->does_composite()) {
+ non_composited_client_->ScheduleNonCompositedAnimation();
+ return;
+ }
+ widget_base_->LayerTreeHost()->SetNeedsAnimate();
+}
+
+void WebFrameWidgetImpl::FocusChanged(bool enable) {
+ // TODO(crbug.com/689777): FocusChange events are only sent to the MainFrame
+ // these maybe should goto the local root so that the rest of input messages
+ // sent to those are preserved in order.
+ DCHECK(ForMainFrame());
+ View()->SetPageFocus(enable);
+}
+
+bool WebFrameWidgetImpl::ShouldAckSyntheticInputImmediately() {
+ // TODO(bokan): The RequestPresentation API appears not to function in VR. As
+ // a short term workaround for https://crbug.com/940063, ACK input
+ // immediately rather than using RequestPresentation.
+ if (GetPage()->GetSettings().GetImmersiveModeEnabled())
+ return true;
+ return false;
+}
+
+void WebFrameWidgetImpl::UpdateVisualProperties(
+ const VisualProperties& visual_properties) {
+ SetZoomLevel(visual_properties.zoom_level);
+
+ // TODO(danakj): In order to synchronize updates between local roots, the
+ // display mode should be propagated to RenderFrameProxies and down through
+ // their RenderWidgetHosts to child WebFrameWidgetImpl via the
+ // VisualProperties waterfall, instead of coming to each WebFrameWidgetImpl
+ // independently.
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode
+ SetDisplayMode(visual_properties.display_mode);
+
+ if (ForMainFrame()) {
+ SetAutoResizeMode(visual_properties.auto_resize_enabled,
+ visual_properties.min_size_for_auto_resize,
+ visual_properties.max_size_for_auto_resize,
+ visual_properties.screen_info.device_scale_factor);
+ }
+
+ bool capture_sequence_number_changed =
+ visual_properties.capture_sequence_number !=
+ last_capture_sequence_number_;
+ if (capture_sequence_number_changed) {
+ last_capture_sequence_number_ = visual_properties.capture_sequence_number;
+
+ // Send the capture sequence number to RemoteFrames that are below the
+ // local root for this widget.
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](uint32_t capture_sequence_number, RemoteFrame* remote_frame) {
+ remote_frame->UpdateCaptureSequenceNumber(capture_sequence_number);
+ },
+ visual_properties.capture_sequence_number));
+ }
+
+ if (!View()->AutoResizeMode()) {
+ if (visual_properties.is_fullscreen_granted != is_fullscreen_granted_) {
+ is_fullscreen_granted_ = visual_properties.is_fullscreen_granted;
+ if (is_fullscreen_granted_)
+ View()->DidEnterFullscreen();
+ else
+ View()->DidExitFullscreen();
+ }
+ }
+
+ gfx::Size old_visible_viewport_size_in_dips =
+ widget_base_->VisibleViewportSizeInDIPs();
+ ApplyVisualPropertiesSizing(visual_properties);
+
+ if (old_visible_viewport_size_in_dips !=
+ widget_base_->VisibleViewportSizeInDIPs()) {
+ ForEachLocalFrameControlledByWidget(
+ local_root_->GetFrame(),
+ WTF::BindRepeating([](WebLocalFrameImpl* local_frame) {
+ local_frame->ResetHasScrolledFocusedEditableIntoView();
+ }));
+
+ // Propagate changes down to child local root RenderWidgets and
+ // BrowserPlugins in other frame trees/processes.
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](const gfx::Size& visible_viewport_size, RemoteFrame* remote_frame) {
+ remote_frame->DidChangeVisibleViewportSize(visible_viewport_size);
+ },
+ widget_base_->VisibleViewportSizeInDIPs()));
+ }
+
+ // All non-top-level Widgets (child local-root frames, Portals, GuestViews,
+ // etc.) propagate and consume the page scale factor as "external", meaning
+ // that it comes from the top level widget's page scale.
+ if (!ForTopMostMainFrame()) {
+ // The main frame controls the page scale factor, from blink. For other
+ // frame widgets, the page scale from pinch zoom and compositing scale is
+ // received from its parent as part of the visual properties here. While
+ // blink doesn't need to know this page scale factor outside the main frame,
+ // the compositor does in order to produce its output at the correct scale.
+ float combined_scale_factor = visual_properties.page_scale_factor *
+ visual_properties.compositing_scale_factor;
+ widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
+ combined_scale_factor, visual_properties.is_pinch_gesture_active);
+
+ NotifyPageScaleFactorChanged(visual_properties.page_scale_factor,
+ visual_properties.is_pinch_gesture_active);
+
+ NotifyCompositingScaleFactorChanged(
+ visual_properties.compositing_scale_factor);
+ } else {
+ // Ensure the external scale factor in top-level widgets is reset as it may
+ // be leftover from when a widget was nested and was promoted to top level
+ // (e.g. portal activation).
+ widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
+ 1.f,
+ /*is_pinch_gesture_active=*/false);
+ }
+
+ // TODO(crbug.com/939118): ScrollFocusedNodeIntoViewForWidget does not work
+ // when the focused node is inside an OOPIF. This code path where
+ // scroll_focused_node_into_view is set is used only for WebView, crbug
+ // 939118 tracks fixing webviews to not use scroll_focused_node_into_view.
+ if (visual_properties.scroll_focused_node_into_view)
+ ScrollFocusedEditableElementIntoView();
+}
+
+void WebFrameWidgetImpl::ApplyVisualPropertiesSizing(
+ const VisualProperties& visual_properties) {
+ gfx::Rect new_compositor_viewport_pixel_rect =
+ visual_properties.compositor_viewport_pixel_rect;
+ if (ForMainFrame()) {
+ if (size_ !=
+ widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)) {
+ // Only hide popups when the size changes. Eg https://crbug.com/761908.
+ View()->CancelPagePopup();
+ }
+
+ if (auto* device_emulator = DeviceEmulator()) {
+ device_emulator->UpdateVisualProperties(visual_properties);
+ return;
+ }
+
+ if (AutoResizeMode()) {
+ new_compositor_viewport_pixel_rect = gfx::Rect(gfx::ScaleToCeiledSize(
+ widget_base_->BlinkSpaceToFlooredDIPs(size_.value_or(gfx::Size())),
+ visual_properties.screen_info.device_scale_factor));
+ }
+ }
+
+ SetWindowSegments(visual_properties.root_widget_window_segments);
+
+ widget_base_->UpdateSurfaceAndScreenInfo(
+ visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
+ new_compositor_viewport_pixel_rect, visual_properties.screen_info);
+
+ // Store this even when auto-resizing, it is the size of the full viewport
+ // used for clipping, and this value is propagated down the Widget
+ // hierarchy via the VisualProperties waterfall.
+ widget_base_->SetVisibleViewportSizeInDIPs(
+ visual_properties.visible_viewport_size);
+
+ if (ForMainFrame()) {
+ if (!AutoResizeMode()) {
+ size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size);
+
+ View()->ResizeWithBrowserControls(
+ size_.value(),
+ widget_base_->DIPsToCeiledBlinkSpace(
+ widget_base_->VisibleViewportSizeInDIPs()),
+ visual_properties.browser_controls_params);
+ }
+ } else {
+ // Widgets in a WebView's frame tree without a local main frame
+ // set the size of the WebView to be the |visible_viewport_size|, in order
+ // to limit compositing in (out of process) child frames to what is visible.
+ //
+ // Note that child frames in the same process/WebView frame tree as the
+ // main frame do not do this in order to not clobber the source of truth in
+ // the main frame.
+ if (!View()->MainFrameImpl()) {
+ View()->Resize(widget_base_->DIPsToCeiledBlinkSpace(
+ widget_base_->VisibleViewportSizeInDIPs()));
+ }
+
+ Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size));
+ }
+}
+
+int WebFrameWidgetImpl::GetLayerTreeId() {
+ if (!View()->does_composite())
+ return 0;
+ return widget_base_->LayerTreeHost()->GetId();
+}
+
+const cc::LayerTreeSettings& WebFrameWidgetImpl::GetLayerTreeSettings() {
+ return widget_base_->LayerTreeHost()->GetSettings();
+}
+
+void WebFrameWidgetImpl::UpdateBrowserControlsState(
+ cc::BrowserControlsState constraints,
+ cc::BrowserControlsState current,
+ bool animate) {
+ DCHECK(View()->does_composite());
+ widget_base_->LayerTreeHost()->UpdateBrowserControlsState(constraints,
+ current, animate);
+}
+
+void WebFrameWidgetImpl::SetHaveScrollEventHandlers(bool has_handlers) {
+ widget_base_->LayerTreeHost()->SetHaveScrollEventHandlers(has_handlers);
+}
+
+void WebFrameWidgetImpl::SetEventListenerProperties(
+ cc::EventListenerClass listener_class,
+ cc::EventListenerProperties listener_properties) {
+ widget_base_->LayerTreeHost()->SetEventListenerProperties(
+ listener_class, listener_properties);
+
+ if (listener_class == cc::EventListenerClass::kTouchStartOrMove ||
+ listener_class == cc::EventListenerClass::kTouchEndOrCancel) {
+ bool has_touch_handlers =
+ EventListenerProperties(cc::EventListenerClass::kTouchStartOrMove) !=
+ cc::EventListenerProperties::kNone ||
+ EventListenerProperties(cc::EventListenerClass::kTouchEndOrCancel) !=
+ cc::EventListenerProperties::kNone;
+ if (!has_touch_handlers_ || *has_touch_handlers_ != has_touch_handlers) {
+ has_touch_handlers_ = has_touch_handlers;
+
+ // Can be null when running tests.
+ if (auto* scheduler_state = widget_base_->RendererWidgetSchedulingState())
+ scheduler_state->SetHasTouchHandler(has_touch_handlers);
+ // Set touch event consumers based on whether there are touch event
+ // handlers or the page has hit testable scrollbars.
+ auto touch_event_consumers = mojom::blink::TouchEventConsumers::New(
+ has_touch_handlers, GetPage()->GetScrollbarTheme().AllowsHitTest());
+ frame_widget_host_->SetHasTouchEventConsumers(
+ std::move(touch_event_consumers));
+ }
+ } else if (listener_class == cc::EventListenerClass::kPointerRawUpdate) {
+ SetHasPointerRawUpdateEventHandlers(listener_properties !=
+ cc::EventListenerProperties::kNone);
+ }
+}
+
+cc::EventListenerProperties WebFrameWidgetImpl::EventListenerProperties(
+ cc::EventListenerClass listener_class) const {
+ return widget_base_->LayerTreeHost()->event_listener_properties(
+ listener_class);
+}
-// WebWidget ------------------------------------------------------------------
+mojom::blink::DisplayMode WebFrameWidgetImpl::DisplayMode() const {
+ return display_mode_;
+}
+
+const WebVector<gfx::Rect>& WebFrameWidgetImpl::WindowSegments() const {
+ return window_segments_;
+}
+
+void WebFrameWidgetImpl::StartDeferringCommits(base::TimeDelta timeout) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->StartDeferringCommits(timeout);
+}
+
+void WebFrameWidgetImpl::StopDeferringCommits(
+ cc::PaintHoldingCommitTrigger triggger) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->StopDeferringCommits(triggger);
+}
+
+std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+WebFrameWidgetImpl::DeferMainFrameUpdate() {
+ return widget_base_->LayerTreeHost()->DeferMainFrameUpdate();
+}
+
+void WebFrameWidgetImpl::SetBrowserControlsShownRatio(float top_ratio,
+ float bottom_ratio) {
+ widget_base_->LayerTreeHost()->SetBrowserControlsShownRatio(top_ratio,
+ bottom_ratio);
+}
+
+void WebFrameWidgetImpl::SetBrowserControlsParams(
+ cc::BrowserControlsParams params) {
+ widget_base_->LayerTreeHost()->SetBrowserControlsParams(params);
+}
+
+void WebFrameWidgetImpl::SynchronouslyCompositeForTesting(
+ base::TimeTicks frame_time) {
+ widget_base_->LayerTreeHost()->CompositeForTest(frame_time, false);
+}
+
+void WebFrameWidgetImpl::UseSynchronousResizeModeForTesting(bool enable) {
+ main_data().synchronous_resize_mode_for_testing = enable;
+}
+
+void WebFrameWidgetImpl::SetDeviceColorSpaceForTesting(
+ const gfx::ColorSpace& color_space) {
+ DCHECK(ForMainFrame());
+ // We are changing the device color space from the renderer, so allocate a
+ // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
+ widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
+
+ blink::ScreenInfo info = widget_base_->GetScreenInfo();
+ info.display_color_spaces = gfx::DisplayColorSpaces(color_space);
+ widget_base_->UpdateScreenInfo(info);
+}
+
+// TODO(665924): Remove direct dispatches of mouse events from
+// PointerLockController, instead passing them through EventHandler.
+void WebFrameWidgetImpl::PointerLockMouseEvent(
+ const WebCoalescedInputEvent& coalesced_event) {
+ const WebInputEvent& input_event = coalesced_event.Event();
+ const WebMouseEvent& mouse_event =
+ static_cast<const WebMouseEvent&>(input_event);
+ WebMouseEvent transformed_event =
+ TransformWebMouseEvent(local_root_->GetFrameView(), mouse_event);
+
+ AtomicString event_type;
+ switch (input_event.GetType()) {
+ case WebInputEvent::Type::kMouseDown:
+ event_type = event_type_names::kMousedown;
+ if (!GetPage() || !GetPage()->GetPointerLockController().GetElement())
+ break;
+ LocalFrame::NotifyUserActivation(
+ GetPage()
+ ->GetPointerLockController()
+ .GetElement()
+ ->GetDocument()
+ .GetFrame(),
+ mojom::blink::UserActivationNotificationType::kInteraction);
+ break;
+ case WebInputEvent::Type::kMouseUp:
+ event_type = event_type_names::kMouseup;
+ break;
+ case WebInputEvent::Type::kMouseMove:
+ event_type = event_type_names::kMousemove;
+ break;
+ default:
+ NOTREACHED() << input_event.GetType();
+ }
+
+ if (GetPage()) {
+ GetPage()->GetPointerLockController().DispatchLockedMouseEvent(
+ transformed_event,
+ TransformWebMouseEventVector(
+ local_root_->GetFrameView(),
+ coalesced_event.GetCoalescedEventsPointers()),
+ TransformWebMouseEventVector(
+ local_root_->GetFrameView(),
+ coalesced_event.GetPredictedEventsPointers()),
+ event_type);
+ }
+}
+bool WebFrameWidgetImpl::IsPointerLocked() {
+ if (GetPage()) {
+ return GetPage()->GetPointerLockController().IsPointerLocked();
+ }
+ return false;
+}
+
+void WebFrameWidgetImpl::ShowContextMenu(
+ ui::mojom::blink::MenuSourceType source_type,
+ const gfx::Point& location) {
+ host_context_menu_location_ = location;
+
+ if (!GetPage())
+ return;
+ GetPage()->GetContextMenuController().ClearContextMenu();
+ {
+ ContextMenuAllowedScope scope;
+ if (LocalFrame* focused_frame =
+ GetPage()->GetFocusController().FocusedFrame()) {
+ focused_frame->GetEventHandler().ShowNonLocatedContextMenu(
+ nullptr, static_cast<blink::WebMenuSourceType>(source_type));
+ }
+ }
+ host_context_menu_location_.reset();
+}
+
+void WebFrameWidgetImpl::SetViewportIntersection(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state,
+ const base::Optional<VisualProperties>& visual_properties) {
+ // Remote viewports are only applicable to local frames with remote ancestors.
+ // TODO(https://crbug.com/1148960): Should this deal with portals?
+ DCHECK(ForSubframe());
+
+ if (visual_properties.has_value())
+ UpdateVisualProperties(visual_properties.value());
+ ApplyViewportIntersection(std::move(intersection_state));
+}
+
+void WebFrameWidgetImpl::ApplyViewportIntersectionForTesting(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state) {
+ ApplyViewportIntersection(std::move(intersection_state));
+}
+
+void WebFrameWidgetImpl::ApplyViewportIntersection(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state) {
+ child_data().compositor_visible_rect =
+ intersection_state->compositor_visible_rect;
+ widget_base_->LayerTreeHost()->SetVisualDeviceViewportIntersectionRect(
+ intersection_state->compositor_visible_rect);
+ LocalRootImpl()->GetFrame()->SetViewportIntersectionFromParent(
+ *intersection_state);
+}
+
+void WebFrameWidgetImpl::EnableDeviceEmulation(
+ const DeviceEmulationParams& parameters) {
+ // Device Emaulation is only supported for the main frame.
+ DCHECK(ForMainFrame());
+ if (!device_emulator_) {
+ gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(Size());
+
+ device_emulator_ = MakeGarbageCollected<ScreenMetricsEmulator>(
+ this, widget_base_->GetScreenInfo(), size_in_dips,
+ widget_base_->VisibleViewportSizeInDIPs(),
+ widget_base_->WidgetScreenRect(), widget_base_->WindowScreenRect());
+ }
+ device_emulator_->ChangeEmulationParams(parameters);
+}
+
+void WebFrameWidgetImpl::DisableDeviceEmulation() {
+ if (!device_emulator_)
+ return;
+ device_emulator_->DisableAndApply();
+ device_emulator_ = nullptr;
+}
+
+void WebFrameWidgetImpl::SetIsInertForSubFrame(bool inert) {
+ DCHECK(ForSubframe());
+ LocalRootImpl()->GetFrame()->SetIsInert(inert);
+}
+
+base::Optional<gfx::Point>
+WebFrameWidgetImpl::GetAndResetContextMenuLocation() {
+ return std::move(host_context_menu_location_);
+}
+
+void WebFrameWidgetImpl::SetZoomLevel(double zoom_level) {
+ // Override the zoom level with the testing one if necessary.
+ if (zoom_level_for_testing_ != -INFINITY)
+ zoom_level = zoom_level_for_testing_;
+
+ View()->SetZoomLevel(zoom_level);
+
+ // Part of the UpdateVisualProperties dance we send the zoom level to
+ // RemoteFrames that are below the local root for this widget.
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](double zoom_level, RemoteFrame* remote_frame) {
+ remote_frame->ZoomLevelChanged(zoom_level);
+ },
+ zoom_level));
+}
+
+void WebFrameWidgetImpl::SetAutoResizeMode(bool auto_resize,
+ const gfx::Size& min_window_size,
+ const gfx::Size& max_window_size,
+ float device_scale_factor) {
+ // Auto resize only applies to main frames.
+ DCHECK(ForMainFrame());
+
+ if (auto_resize) {
+ if (!Platform::Current()->IsUseZoomForDSFEnabled())
+ device_scale_factor = 1.f;
+ View()->EnableAutoResizeMode(
+ gfx::ScaleToCeiledSize(min_window_size, device_scale_factor),
+ gfx::ScaleToCeiledSize(max_window_size, device_scale_factor));
+ } else if (AutoResizeMode()) {
+ View()->DisableAutoResizeMode();
+ }
+}
+
+void WebFrameWidgetImpl::DidAutoResize(const gfx::Size& size) {
+ DCHECK(ForMainFrame());
+ gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(size);
+ size_ = size;
+
+ if (main_data().synchronous_resize_mode_for_testing) {
+ gfx::Rect new_pos(widget_base_->WindowRect());
+ new_pos.set_size(size_in_dips);
+ SetScreenRects(new_pos, new_pos);
+ }
+
+ // TODO(ccameron): Note that this destroys any information differentiating
+ // |size| from the compositor's viewport size.
+ gfx::Rect size_with_dsf = gfx::Rect(gfx::ScaleToCeiledSize(
+ gfx::Rect(size_in_dips).size(),
+ widget_base_->GetScreenInfo().device_scale_factor));
+ widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
+ widget_base_->UpdateCompositorViewportRect(size_with_dsf);
+}
+
+LocalFrame* WebFrameWidgetImpl::FocusedLocalFrameInWidget() const {
+ if (!local_root_) {
+ // WebFrameWidget is created in the call to CreateFrame. The corresponding
+ // RenderWidget, however, might not swap in right away (InstallNewDocument()
+ // will lead to it swapping in). During this interval local_root_ is nullptr
+ // (see https://crbug.com/792345).
+ return nullptr;
+ }
+
+ LocalFrame* frame = GetPage()->GetFocusController().FocusedFrame();
+ return (frame && frame->LocalFrameRoot() == local_root_->GetFrame())
+ ? frame
+ : nullptr;
+}
+
+WebLocalFrameImpl* WebFrameWidgetImpl::FocusedWebLocalFrameInWidget() const {
+ return WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
+}
+
+bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() {
+ Element* element = FocusedElement();
+ if (!element || !WebElement(element).IsEditable())
+ return false;
+
+ element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
+
+ if (!element->GetLayoutObject())
+ return false;
+
+ PhysicalRect rect_to_scroll;
+ auto params =
+ GetScrollParamsForFocusedEditableElement(*element, rect_to_scroll);
+ element->GetLayoutObject()->ScrollRectToVisible(rect_to_scroll,
+ std::move(params));
+
+ // Second phase for main frames is to schedule a zoom animation.
+ if (ForMainFrame()) {
+ LocalFrameView* main_frame_view = LocalRootImpl()->GetFrame()->View();
+
+ View()->ZoomAndScrollToFocusedEditableElementRect(
+ main_frame_view->RootFrameToDocument(
+ element->GetDocument().View()->ConvertToRootFrame(
+ element->GetLayoutObject()->AbsoluteBoundingBoxRect())),
+ main_frame_view->RootFrameToDocument(
+ element->GetDocument().View()->ConvertToRootFrame(
+ element->GetDocument()
+ .GetFrame()
+ ->Selection()
+ .ComputeRectToScroll(kDoNotRevealExtent))),
+ View()->ShouldZoomToLegibleScale(*element));
+ }
+
+ return true;
+}
+
+void WebFrameWidgetImpl::ResetMeaningfulLayoutStateForMainFrame() {
+ MainFrameData& data = main_data();
+ data.should_dispatch_first_visually_non_empty_layout = true;
+ data.should_dispatch_first_layout_after_finished_parsing = true;
+ data.should_dispatch_first_layout_after_finished_loading = true;
+}
-void WebFrameWidgetImpl::Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) {
- GetPage()->WillCloseAnimationHost(LocalRootImpl()->GetFrame()->View());
+void WebFrameWidgetImpl::InitializeCompositing(
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
+ cc::TaskGraphRunner* task_graph_runner,
+ const ScreenInfo& screen_info,
+ std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
+ const cc::LayerTreeSettings* settings) {
+ DCHECK(View()->does_composite());
+ DCHECK(!non_composited_client_); // Assure only one initialize is called.
+ widget_base_->InitializeCompositing(
+ agent_group_scheduler, task_graph_runner, is_for_child_local_root_,
+ screen_info, std::move(ukm_recorder_factory), settings,
+ input_handler_weak_ptr_factory_.GetWeakPtr());
- WebFrameWidgetBase::Close(std::move(cleanup_runner));
+ LocalFrameView* frame_view;
+ if (is_for_child_local_root_) {
+ frame_view = LocalRootImpl()->GetFrame()->View();
+ } else {
+ // Scrolling for the root frame is special we need to pass null indicating
+ // we are at the top of the tree when setting up the Animation. Which will
+ // cause ownership of the timeline and animation host.
+ // See ScrollingCoordinator::AnimationHostInitialized.
+ frame_view = nullptr;
+ }
- self_keep_alive_.Clear();
+ GetPage()->AnimationHostInitialized(*AnimationHost(), frame_view);
+}
+
+void WebFrameWidgetImpl::InitializeNonCompositing(
+ WebNonCompositedWidgetClient* client) {
+ DCHECK(!non_composited_client_);
+ DCHECK(client);
+ DCHECK(!View()->does_composite());
+ // Assure only one initialize is called.
+ DCHECK(!widget_base_->IsComposited());
+ non_composited_client_ = client;
+}
+
+void WebFrameWidgetImpl::SetCompositorVisible(bool visible) {
+ widget_base_->SetCompositorVisible(visible);
}
gfx::Size WebFrameWidgetImpl::Size() {
@@ -245,20 +1925,24 @@ void WebFrameWidgetImpl::Resize(const gfx::Size& new_size) {
if (size_ && *size_ == new_size)
return;
- if (did_suspend_parsing_) {
- did_suspend_parsing_ = false;
+ if (ForMainFrame()) {
+ size_ = new_size;
+ View()->Resize(new_size);
+ return;
+ }
+
+ if (child_data().did_suspend_parsing) {
+ child_data().did_suspend_parsing = false;
LocalRootImpl()->GetFrame()->Loader().GetDocumentLoader()->ResumeParser();
}
LocalFrameView* view = LocalRootImpl()->GetFrameView();
- if (!view)
- return;
+ DCHECK(view);
size_ = new_size;
- UpdateMainFrameLayoutSize();
-
- view->Resize(WebSize(*size_));
+ view->SetLayoutSize(IntSize(*size_));
+ view->Resize(IntSize(*size_));
// FIXME: In WebViewImpl this layout was a precursor to setting the minimum
// scale limit. It is not clear if this is necessary for frame-level widget
@@ -277,10 +1961,7 @@ void WebFrameWidgetImpl::Resize(const gfx::Size& new_size) {
// resizeEvent as part of layout. Layout is also responsible for sending
// invalidations to the embedder. This method and all callers may be wrong.
// -- eseidel.
- if (LocalRootImpl()->GetFrameView()) {
- // Enqueues the resize event.
- LocalRootImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
- }
+ LocalRootImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
// Pass the limits even though this is for subframes, as the limits will
// be needed in setting the raster scale. We set this value when setting
@@ -295,75 +1976,544 @@ void WebFrameWidgetImpl::Resize(const gfx::Size& new_size) {
}
}
-void WebFrameWidgetImpl::UpdateMainFrameLayoutSize() {
+void WebFrameWidgetImpl::BeginMainFrame(base::TimeTicks last_frame_time) {
+ TRACE_EVENT1("blink", "WebFrameWidgetImpl::BeginMainFrame", "frameTime",
+ last_frame_time);
+ DCHECK(!last_frame_time.is_null());
+ CHECK(LocalRootImpl());
+
+ // Dirty bit on MouseEventManager is not cleared in OOPIFs after scroll
+ // or layout changes. Ensure the hover state is recomputed if necessary.
+ LocalRootImpl()
+ ->GetFrame()
+ ->GetEventHandler()
+ .RecomputeMouseHoverStateIfNeeded();
+
+ // Adjusting frame anchor only happens on the main frame.
+ if (ForMainFrame()) {
+ if (LocalFrameView* view = LocalRootImpl()->GetFrameView()) {
+ if (FragmentAnchor* anchor = view->GetFragmentAnchor())
+ anchor->PerformPreRafActions();
+ }
+ }
+
+ base::Optional<LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer> ukm_timer;
+ if (WidgetBase::ShouldRecordBeginMainFrameMetrics()) {
+ ukm_timer.emplace(LocalRootImpl()
+ ->GetFrame()
+ ->View()
+ ->EnsureUkmAggregator()
+ .GetScopedTimer(LocalFrameUkmAggregator::kAnimate));
+ }
+
+ PageWidgetDelegate::Animate(*GetPage(), last_frame_time);
+ // Animate can cause the local frame to detach.
if (!LocalRootImpl())
return;
- LocalFrameView* view = LocalRootImpl()->GetFrameView();
- if (!view)
+ GetPage()->GetValidationMessageClient().LayoutOverlay();
+}
+
+void WebFrameWidgetImpl::BeginCommitCompositorFrame() {
+ commit_compositor_frame_start_time_.emplace(base::TimeTicks::Now());
+}
+
+void WebFrameWidgetImpl::EndCommitCompositorFrame(
+ base::TimeTicks commit_start_time) {
+ DCHECK(commit_compositor_frame_start_time_.has_value());
+ if (ForMainFrame()) {
+ View()->DidCommitCompositorFrameForLocalMainFrame();
+ View()->UpdatePreferredSize();
+ if (!View()->MainFrameImpl()) {
+ // Trying to track down why the view's idea of the main frame varies
+ // from LocalRootImpl's.
+ // TODO(https://crbug.com/1139104): Remove this.
+ std::string reason = View()->GetNullFrameReasonForBug1139104();
+ DCHECK(false) << reason;
+ SCOPED_CRASH_KEY_STRING32("Crbug1139104", "NullFrameReason", reason);
+ base::debug::DumpWithoutCrashing();
+ }
+ }
+
+ LocalRootImpl()
+ ->GetFrame()
+ ->View()
+ ->EnsureUkmAggregator()
+ .RecordImplCompositorSample(commit_compositor_frame_start_time_.value(),
+ commit_start_time, base::TimeTicks::Now());
+ commit_compositor_frame_start_time_.reset();
+}
+
+void WebFrameWidgetImpl::ApplyViewportChanges(
+ const ApplyViewportChangesArgs& args) {
+ // Viewport changes only change the main frame.
+ if (!ForMainFrame())
+ return;
+ WebViewImpl* web_view = View();
+ // TODO(https://crbug.com/1160652): Figure out if View is null.
+ CHECK(widget_base_);
+ CHECK(web_view);
+ web_view->ApplyViewportChanges(args);
+}
+
+void WebFrameWidgetImpl::RecordManipulationTypeCounts(
+ cc::ManipulationInfo info) {
+ // Manipulation counts are only recorded for the main frame.
+ if (!ForMainFrame())
return;
- gfx::Size layout_size = *size_;
+ if ((info & cc::kManipulationInfoWheel) == cc::kManipulationInfoWheel) {
+ UseCounter::Count(LocalRootImpl()->GetDocument(),
+ WebFeature::kScrollByWheel);
+ }
+ if ((info & cc::kManipulationInfoTouch) == cc::kManipulationInfoTouch) {
+ UseCounter::Count(LocalRootImpl()->GetDocument(),
+ WebFeature::kScrollByTouch);
+ }
+ if ((info & cc::kManipulationInfoPinchZoom) ==
+ cc::kManipulationInfoPinchZoom) {
+ UseCounter::Count(LocalRootImpl()->GetDocument(), WebFeature::kPinchZoom);
+ }
+ if ((info & cc::kManipulationInfoPrecisionTouchPad) ==
+ cc::kManipulationInfoPrecisionTouchPad) {
+ UseCounter::Count(LocalRootImpl()->GetDocument(),
+ WebFeature::kScrollByPrecisionTouchPad);
+ }
+}
- view->SetLayoutSize(WebSize(layout_size));
+void WebFrameWidgetImpl::RecordDispatchRafAlignedInputTime(
+ base::TimeTicks raf_aligned_input_start_time) {
+ if (LocalRootImpl()) {
+ LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
+ LocalFrameUkmAggregator::kHandleInputEvents,
+ raf_aligned_input_start_time, base::TimeTicks::Now());
+ }
}
-bool WebFrameWidgetImpl::ShouldHandleImeEvents() {
- // TODO(ekaramad): WebViewWidgetImpl returns true only if it has focus.
- // We track page focus in all RenderViews on the page but
- // the RenderWidgets corresponding to child local roots do not get the
- // update. For now, this method returns true when the RenderWidget is for a
- // child local frame, i.e., IME events will be processed regardless of page
- // focus. We should revisit this after page focus for OOPIFs has been fully
- // resolved (https://crbug.com/689777).
- return LocalRootImpl();
+void WebFrameWidgetImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
+ bool suppress_frame_requests) {
+ GetPage()->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
+ suppress_frame_requests);
}
-void WebFrameWidgetImpl::UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason) {
- TRACE_EVENT0("blink", "WebFrameWidgetImpl::updateAllLifecyclePhases");
+std::unique_ptr<cc::BeginMainFrameMetrics>
+WebFrameWidgetImpl::GetBeginMainFrameMetrics() {
+ if (!LocalRootImpl())
+ return nullptr;
+
+ return LocalRootImpl()
+ ->GetFrame()
+ ->View()
+ ->EnsureUkmAggregator()
+ .GetBeginMainFrameMetrics();
+}
+
+std::unique_ptr<cc::WebVitalMetrics> WebFrameWidgetImpl::GetWebVitalMetrics() {
+ if (!LocalRootImpl())
+ return nullptr;
+
+ // This class should be called at most once per commit.
+ WebPerformance perf = LocalRootImpl()->Performance();
+ auto metrics = std::make_unique<cc::WebVitalMetrics>();
+ if (perf.FirstInputDelay().has_value()) {
+ metrics->first_input_delay = perf.FirstInputDelay().value();
+ metrics->has_fid = true;
+ }
+
+ base::TimeTicks start = perf.NavigationStartAsMonotonicTime();
+ base::TimeTicks largest_contentful_paint =
+ perf.LargestContentfulPaintAsMonotonicTime();
+ if (largest_contentful_paint >= start) {
+ metrics->largest_contentful_paint = largest_contentful_paint - start;
+ metrics->has_lcp = true;
+ }
+
+ double layout_shift = LocalRootImpl()
+ ->GetFrame()
+ ->View()
+ ->GetLayoutShiftTracker()
+ .WeightedScore();
+ if (layout_shift > 0.f) {
+ metrics->layout_shift = layout_shift;
+ metrics->has_cls = true;
+ }
+
+ if (!metrics->HasValue())
+ return nullptr;
+
+ return metrics;
+}
+
+void WebFrameWidgetImpl::BeginUpdateLayers() {
+ if (LocalRootImpl())
+ update_layers_start_time_.emplace(base::TimeTicks::Now());
+}
+
+void WebFrameWidgetImpl::EndUpdateLayers() {
+ if (LocalRootImpl()) {
+ DCHECK(update_layers_start_time_);
+ LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
+ LocalFrameUkmAggregator::kUpdateLayers,
+ update_layers_start_time_.value(), base::TimeTicks::Now());
+ probe::LayerTreeDidChange(LocalRootImpl()->GetFrame());
+ }
+ update_layers_start_time_.reset();
+}
+
+void WebFrameWidgetImpl::RecordStartOfFrameMetrics() {
if (!LocalRootImpl())
return;
- PageWidgetDelegate::UpdateLifecycle(*GetPage(), *LocalRootImpl()->GetFrame(),
- requested_update, reason);
- View()->UpdatePagePopup();
+ LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().BeginMainFrame();
}
-bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() {
- Element* element = FocusedElement();
- if (!element || !WebElement(element).IsEditable())
- return false;
+void WebFrameWidgetImpl::RecordEndOfFrameMetrics(
+ base::TimeTicks frame_begin_time,
+ cc::ActiveFrameSequenceTrackers trackers) {
+ if (!LocalRootImpl())
+ return;
- if (!element->GetLayoutObject())
- return false;
+ LocalRootImpl()
+ ->GetFrame()
+ ->View()
+ ->EnsureUkmAggregator()
+ .RecordEndOfFrameMetrics(frame_begin_time, base::TimeTicks::Now(),
+ trackers);
+}
- PhysicalRect rect_to_scroll;
- auto params = ScrollAlignment::CreateScrollIntoViewParams();
- GetScrollParamsForFocusedEditableElement(*element, rect_to_scroll, params);
- element->GetLayoutObject()->ScrollRectToVisible(rect_to_scroll,
- std::move(params));
- return true;
+bool WebFrameWidgetImpl::WillHandleGestureEvent(const WebGestureEvent& event) {
+ possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kTouch;
+ possible_drag_event_info_.location =
+ gfx::ToFlooredPoint(event.PositionInScreen());
+
+ bool move_cursor = false;
+ switch (event.GetType()) {
+ case WebInputEvent::Type::kGestureScrollBegin: {
+ if (event.data.scroll_begin.cursor_control) {
+ swipe_to_move_cursor_activated_ = true;
+ move_cursor = true;
+ }
+ break;
+ }
+ case WebInputEvent::Type::kGestureScrollUpdate: {
+ if (swipe_to_move_cursor_activated_)
+ move_cursor = true;
+ break;
+ }
+ case WebInputEvent::Type::kGestureScrollEnd: {
+ if (swipe_to_move_cursor_activated_) {
+ swipe_to_move_cursor_activated_ = false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ // TODO(crbug.com/1140106): Place cursor for scroll begin other than just move
+ // cursor.
+ if (move_cursor) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (focused_frame) {
+ gfx::Point base(event.PositionInWidget().x(),
+ event.PositionInWidget().y());
+ focused_frame->MoveCaretSelection(base);
+ }
+ return true;
+ }
+ return false;
}
-void WebFrameWidgetImpl::SetZoomLevelForTesting(double zoom_level) {
- // Zoom level is only controlled for testing on the main frame.
- NOTREACHED();
+void WebFrameWidgetImpl::WillHandleMouseEvent(const WebMouseEvent& event) {
+ possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kMouse;
+ possible_drag_event_info_.location =
+ gfx::Point(event.PositionInScreen().x(), event.PositionInScreen().y());
}
-void WebFrameWidgetImpl::ResetZoomLevelForTesting() {
- // Zoom level is only controlled for testing on the main frame.
- NOTREACHED();
+void WebFrameWidgetImpl::ObserveGestureEventAndResult(
+ const WebGestureEvent& gesture_event,
+ const gfx::Vector2dF& unused_delta,
+ const cc::OverscrollBehavior& overscroll_behavior,
+ bool event_processed) {
+ if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
+ return;
+
+ cc::InputHandlerScrollResult scroll_result;
+ scroll_result.did_scroll = event_processed;
+ scroll_result.did_overscroll_root = !unused_delta.IsZero();
+ scroll_result.unused_scroll_delta = unused_delta;
+ scroll_result.overscroll_behavior = overscroll_behavior;
+
+ widget_base_->widget_input_handler_manager()->ObserveGestureEventOnMainThread(
+ gesture_event, scroll_result);
}
-void WebFrameWidgetImpl::SetDeviceScaleFactorForTesting(float factor) {
- NOTREACHED();
+void WebFrameWidgetImpl::DidHandleKeyEvent() {
+ ClearEditCommands();
}
-void WebFrameWidgetImpl::IntrinsicSizingInfoChanged(
- mojom::blink::IntrinsicSizingInfoPtr sizing_info) {
- GetAssociatedFrameWidgetHost()->IntrinsicSizingInfoChanged(
- std::move(sizing_info));
+WebTextInputType WebFrameWidgetImpl::GetTextInputType() {
+ if (ShouldDispatchImeEventsToPlugin()) {
+ return GetFocusedPluginContainer()->GetPluginTextInputType();
+ }
+
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return WebTextInputType::kWebTextInputTypeNone;
+ return controller->TextInputType();
+}
+
+void WebFrameWidgetImpl::SetCursorVisibilityState(bool is_visible) {
+ GetPage()->SetIsCursorVisible(is_visible);
+}
+
+void WebFrameWidgetImpl::ApplyViewportChangesForTesting(
+ const ApplyViewportChangesArgs& args) {
+ widget_base_->ApplyViewportChanges(args);
+}
+
+void WebFrameWidgetImpl::SetDisplayMode(mojom::blink::DisplayMode mode) {
+ if (mode != display_mode_) {
+ display_mode_ = mode;
+ LocalFrame* frame = LocalRootImpl()->GetFrame();
+ frame->MediaQueryAffectingValueChangedForLocalSubtree(
+ MediaValueChange::kOther);
+ }
+}
+
+void WebFrameWidgetImpl::SetWindowSegments(
+ const std::vector<gfx::Rect>& window_segments_param) {
+ WebVector<gfx::Rect> window_segments(window_segments_param);
+ if (!window_segments_.Equals(window_segments)) {
+ window_segments_ = window_segments;
+ LocalFrame* frame = LocalRootImpl()->GetFrame();
+ frame->WindowSegmentsChanged(window_segments_);
+
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](const std::vector<gfx::Rect>& window_segments,
+ RemoteFrame* remote_frame) {
+ remote_frame->DidChangeRootWindowSegments(window_segments);
+ },
+ window_segments_param));
+ }
+}
+
+void WebFrameWidgetImpl::SetCursor(const ui::Cursor& cursor) {
+ widget_base_->SetCursor(cursor);
+}
+
+bool WebFrameWidgetImpl::HandlingInputEvent() {
+ return widget_base_->input_handler().handling_input_event();
+}
+
+void WebFrameWidgetImpl::SetHandlingInputEvent(bool handling) {
+ widget_base_->input_handler().set_handling_input_event(handling);
+}
+
+void WebFrameWidgetImpl::ProcessInputEventSynchronouslyForTesting(
+ const WebCoalescedInputEvent& event,
+ HandledEventCallback callback) {
+ widget_base_->input_handler().HandleInputEvent(event, nullptr,
+ std::move(callback));
+}
+
+WebInputEventResult WebFrameWidgetImpl::DispatchBufferedTouchEvents() {
+ CHECK(LocalRootImpl());
+
+ if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl())
+ devtools->DispatchBufferedTouchEvents();
+
+ return LocalRootImpl()
+ ->GetFrame()
+ ->GetEventHandler()
+ .DispatchBufferedTouchEvents();
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleInputEvent(
+ const WebCoalescedInputEvent& coalesced_event) {
+ const WebInputEvent& input_event = coalesced_event.Event();
+ TRACE_EVENT1("input,rail", "WebFrameWidgetImpl::HandleInputEvent", "type",
+ WebInputEvent::GetName(input_event.GetType()));
+ DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
+ CHECK(LocalRootImpl());
+
+ // Only record metrics for the main frame.
+ if (ForMainFrame()) {
+ GetPage()->GetVisualViewport().StartTrackingPinchStats();
+ }
+
+ // If a drag-and-drop operation is in progress, ignore input events except
+ // PointerCancel.
+ if (doing_drag_and_drop_ &&
+ input_event.GetType() != WebInputEvent::Type::kPointerCancel)
+ return WebInputEventResult::kHandledSuppressed;
+
+ // Don't handle events once we've started shutting down.
+ if (!GetPage())
+ return WebInputEventResult::kNotHandled;
+
+ if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl()) {
+ auto result = devtools->HandleInputEvent(input_event);
+ if (result != WebInputEventResult::kNotHandled)
+ return result;
+ }
+
+ // Report the event to be NOT processed by WebKit, so that the browser can
+ // handle it appropriately.
+ if (IgnoreInputEvents())
+ return WebInputEventResult::kNotHandled;
+
+ base::AutoReset<const WebInputEvent*> current_event_change(
+ &CurrentInputEvent::current_input_event_, &input_event);
+ UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld();
+
+ if (GetPage()->GetPointerLockController().IsPointerLocked() &&
+ WebInputEvent::IsMouseEventType(input_event.GetType())) {
+ PointerLockMouseEvent(coalesced_event);
+ return WebInputEventResult::kHandledSystem;
+ }
+
+ /// These metrics are only captured for the main frame.
+ if (ForMainFrame()) {
+ Document& main_frame_document = *LocalRootImpl()->GetFrame()->GetDocument();
+
+ if (input_event.GetType() != WebInputEvent::Type::kMouseMove) {
+ FirstMeaningfulPaintDetector::From(main_frame_document)
+ .NotifyInputEvent();
+ }
+
+ if (input_event.GetType() != WebInputEvent::Type::kMouseMove &&
+ input_event.GetType() != WebInputEvent::Type::kMouseEnter &&
+ input_event.GetType() != WebInputEvent::Type::kMouseLeave) {
+ InteractiveDetector* interactive_detector(
+ InteractiveDetector::From(main_frame_document));
+ if (interactive_detector) {
+ interactive_detector->OnInvalidatingInputEvent(input_event.TimeStamp());
+ }
+ }
+ }
+
+ NotifyInputObservers(coalesced_event);
+
+ // Notify the focus frame of the input. Note that the other frames are not
+ // notified as input is only handled by the focused frame.
+ Frame* frame = FocusedCoreFrame();
+ if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
+ if (auto* content_capture_manager =
+ local_frame->LocalFrameRoot().GetContentCaptureManager()) {
+ content_capture_manager->NotifyInputEvent(input_event.GetType(),
+ *local_frame);
+ }
+ }
+
+ // Skip the pointerrawupdate for mouse capture case.
+ if (mouse_capture_element_ &&
+ input_event.GetType() == WebInputEvent::Type::kPointerRawUpdate)
+ return WebInputEventResult::kHandledSystem;
+
+ if (mouse_capture_element_ &&
+ WebInputEvent::IsMouseEventType(input_event.GetType()))
+ return HandleCapturedMouseEvent(coalesced_event);
+
+ // FIXME: This should take in the intended frame, not the local frame
+ // root.
+ return PageWidgetDelegate::HandleInputEvent(*this, coalesced_event,
+ LocalRootImpl()->GetFrame());
+}
+
+WebInputEventResult WebFrameWidgetImpl::HandleCapturedMouseEvent(
+ const WebCoalescedInputEvent& coalesced_event) {
+ const WebInputEvent& input_event = coalesced_event.Event();
+ TRACE_EVENT1("input", "captured mouse event", "type", input_event.GetType());
+ // Save |mouse_capture_element_| since |MouseCaptureLost()| will clear it.
+ HTMLPlugInElement* element = mouse_capture_element_;
+
+ // Not all platforms call mouseCaptureLost() directly.
+ if (input_event.GetType() == WebInputEvent::Type::kMouseUp) {
+ SetMouseCapture(false);
+ MouseCaptureLost();
+ }
+
+ AtomicString event_type;
+ switch (input_event.GetType()) {
+ case WebInputEvent::Type::kMouseEnter:
+ event_type = event_type_names::kMouseover;
+ break;
+ case WebInputEvent::Type::kMouseMove:
+ event_type = event_type_names::kMousemove;
+ break;
+ case WebInputEvent::Type::kPointerRawUpdate:
+ // There will be no mouse event for rawupdate events.
+ event_type = event_type_names::kPointerrawupdate;
+ break;
+ case WebInputEvent::Type::kMouseLeave:
+ event_type = event_type_names::kMouseout;
+ break;
+ case WebInputEvent::Type::kMouseDown:
+ event_type = event_type_names::kMousedown;
+ LocalFrame::NotifyUserActivation(
+ element->GetDocument().GetFrame(),
+ mojom::blink::UserActivationNotificationType::kInteraction);
+ break;
+ case WebInputEvent::Type::kMouseUp:
+ event_type = event_type_names::kMouseup;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ WebMouseEvent transformed_event =
+ TransformWebMouseEvent(LocalRootImpl()->GetFrameView(),
+ static_cast<const WebMouseEvent&>(input_event));
+ if (LocalFrame* frame = element->GetDocument().GetFrame()) {
+ frame->GetEventHandler().HandleTargetedMouseEvent(
+ element, transformed_event, event_type,
+ TransformWebMouseEventVector(
+ LocalRootImpl()->GetFrameView(),
+ coalesced_event.GetCoalescedEventsPointers()),
+ TransformWebMouseEventVector(
+ LocalRootImpl()->GetFrameView(),
+ coalesced_event.GetPredictedEventsPointers()));
+ }
+ return WebInputEventResult::kHandledSystem;
+}
+
+void WebFrameWidgetImpl::UpdateTextInputState() {
+ widget_base_->UpdateTextInputState();
+}
+
+void WebFrameWidgetImpl::UpdateSelectionBounds() {
+ widget_base_->UpdateSelectionBounds();
+}
+
+void WebFrameWidgetImpl::ShowVirtualKeyboard() {
+ widget_base_->ShowVirtualKeyboard();
+}
+
+void WebFrameWidgetImpl::FlushInputProcessedCallback() {
+ widget_base_->FlushInputProcessedCallback();
+}
+
+void WebFrameWidgetImpl::CancelCompositionForPepper() {
+ widget_base_->CancelCompositionForPepper();
+}
+
+void WebFrameWidgetImpl::RequestMouseLock(
+ bool has_transient_user_activation,
+ bool request_unadjusted_movement,
+ mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback) {
+ mojom::blink::WidgetInputHandlerHost* host =
+ widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost();
+
+ // If we don't have a host just leave the callback uncalled. This simulates
+ // the browser indefinitely postponing the mouse request which is valid.
+ // Note that |callback| is not a mojo bound callback (until it is passed
+ // into the mojo interface) and can be destructed without invoking the
+ // callback. It does share the same signature as the mojo definition
+ // for simplicity.
+ if (host) {
+ host->RequestMouseLock(has_transient_user_activation,
+ request_unadjusted_movement, std::move(callback));
+ }
}
void WebFrameWidgetImpl::MouseCaptureLost() {
@@ -372,63 +2522,1057 @@ void WebFrameWidgetImpl::MouseCaptureLost() {
mouse_capture_element_ = nullptr;
}
-void WebFrameWidgetImpl::FocusChanged(bool enable) {
- if (enable)
- GetPage()->GetFocusController().SetActive(true);
- GetPage()->GetFocusController().SetFocused(enable);
- if (enable) {
- LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame();
- if (focused_frame) {
- Element* element = focused_frame->GetDocument()->FocusedElement();
- if (element && focused_frame->Selection()
- .ComputeVisibleSelectionInDOMTreeDeprecated()
- .IsNone()) {
- // If the selection was cleared while the WebView was not
- // focused, then the focus element shows with a focus ring but
- // no caret and does respond to keyboard inputs.
- focused_frame->GetDocument()->UpdateStyleAndLayoutTree();
- if (element->IsTextControl()) {
- element->UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore);
- } else if (HasEditableStyle(*element)) {
- // updateFocusAppearance() selects all the text of
- // contentseditable DIVs. So we set the selection explicitly
- // instead. Note that this has the side effect of moving the
- // caret back to the beginning of the text.
- Position position(element, 0);
- focused_frame->Selection().SetSelectionAndEndTyping(
- SelectionInDOMTree::Builder().Collapse(position).Build());
- }
- }
+void WebFrameWidgetImpl::ApplyVisualProperties(
+ const VisualProperties& visual_properties) {
+ widget_base_->UpdateVisualProperties(visual_properties);
+}
+
+bool WebFrameWidgetImpl::IsFullscreenGranted() {
+ return is_fullscreen_granted_;
+}
+
+bool WebFrameWidgetImpl::PinchGestureActiveInMainFrame() {
+ return is_pinch_gesture_active_in_mainframe_;
+}
+
+float WebFrameWidgetImpl::PageScaleInMainFrame() {
+ return page_scale_factor_in_mainframe_;
+}
+
+void WebFrameWidgetImpl::UpdateSurfaceAndScreenInfo(
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Rect& compositor_viewport_pixel_rect,
+ const ScreenInfo& new_screen_info) {
+ widget_base_->UpdateSurfaceAndScreenInfo(
+ new_local_surface_id, compositor_viewport_pixel_rect, new_screen_info);
+}
+
+void WebFrameWidgetImpl::UpdateScreenInfo(const ScreenInfo& new_screen_info) {
+ widget_base_->UpdateScreenInfo(new_screen_info);
+}
+
+void WebFrameWidgetImpl::UpdateSurfaceAndCompositorRect(
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Rect& compositor_viewport_pixel_rect) {
+ widget_base_->UpdateSurfaceAndCompositorRect(new_local_surface_id,
+ compositor_viewport_pixel_rect);
+}
+
+void WebFrameWidgetImpl::UpdateCompositorViewportRect(
+ const gfx::Rect& compositor_viewport_pixel_rect) {
+ widget_base_->UpdateCompositorViewportRect(compositor_viewport_pixel_rect);
+}
+
+const ScreenInfo& WebFrameWidgetImpl::GetScreenInfo() {
+ return widget_base_->GetScreenInfo();
+}
+
+gfx::Rect WebFrameWidgetImpl::WindowRect() {
+ return widget_base_->WindowRect();
+}
+
+gfx::Rect WebFrameWidgetImpl::ViewRect() {
+ return widget_base_->ViewRect();
+}
+
+void WebFrameWidgetImpl::SetScreenRects(const gfx::Rect& widget_screen_rect,
+ const gfx::Rect& window_screen_rect) {
+ widget_base_->SetScreenRects(widget_screen_rect, window_screen_rect);
+}
+
+gfx::Size WebFrameWidgetImpl::VisibleViewportSizeInDIPs() {
+ return widget_base_->VisibleViewportSizeInDIPs();
+}
+
+void WebFrameWidgetImpl::SetPendingWindowRect(
+ const gfx::Rect& window_screen_rect) {
+ widget_base_->SetPendingWindowRect(window_screen_rect);
+}
+
+void WebFrameWidgetImpl::AckPendingWindowRect() {
+ widget_base_->AckPendingWindowRect();
+}
+
+bool WebFrameWidgetImpl::IsHidden() const {
+ return widget_base_->is_hidden();
+}
+
+WebString WebFrameWidgetImpl::GetLastToolTipTextForTesting() const {
+ return GetPage()->GetChromeClient().GetLastToolTipTextForTesting();
+}
+
+float WebFrameWidgetImpl::GetEmulatorScale() {
+ if (device_emulator_)
+ return device_emulator_->scale();
+ return 1.0f;
+}
+
+void WebFrameWidgetImpl::IntrinsicSizingInfoChanged(
+ mojom::blink::IntrinsicSizingInfoPtr sizing_info) {
+ DCHECK(ForSubframe());
+ GetAssociatedFrameWidgetHost()->IntrinsicSizingInfoChanged(
+ std::move(sizing_info));
+}
+
+void WebFrameWidgetImpl::AutoscrollStart(const gfx::PointF& position) {
+ GetAssociatedFrameWidgetHost()->AutoscrollStart(std::move(position));
+}
+
+void WebFrameWidgetImpl::AutoscrollFling(const gfx::Vector2dF& velocity) {
+ GetAssociatedFrameWidgetHost()->AutoscrollFling(std::move(velocity));
+}
+
+void WebFrameWidgetImpl::AutoscrollEnd() {
+ GetAssociatedFrameWidgetHost()->AutoscrollEnd();
+}
+
+void WebFrameWidgetImpl::DidMeaningfulLayout(WebMeaningfulLayout layout_type) {
+ if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty) {
+ NotifySwapAndPresentationTime(
+ base::NullCallback(),
+ WTF::Bind(&WebFrameWidgetImpl::PresentationCallbackForMeaningfulLayout,
+ WrapPersistent(this)));
+ }
+
+ ForEachLocalFrameControlledByWidget(
+ local_root_->GetFrame(),
+ WTF::BindRepeating(
+ [](WebMeaningfulLayout layout_type, WebLocalFrameImpl* local_frame) {
+ local_frame->Client()->DidMeaningfulLayout(layout_type);
+ },
+ layout_type));
+}
+
+void WebFrameWidgetImpl::PresentationCallbackForMeaningfulLayout(
+ blink::WebSwapResult,
+ base::TimeTicks) {
+ GetAssociatedFrameWidgetHost()->DidFirstVisuallyNonEmptyPaint();
+}
+
+void WebFrameWidgetImpl::RequestAnimationAfterDelay(
+ const base::TimeDelta& delay) {
+ widget_base_->RequestAnimationAfterDelay(delay);
+}
+
+void WebFrameWidgetImpl::SetRootLayer(scoped_refptr<cc::Layer> layer) {
+ if (!View()->does_composite()) {
+ DCHECK(ForMainFrame());
+ DCHECK(!layer);
+ return;
+ }
+
+ // Set up some initial state before we are setting the layer.
+ if (ForSubframe() && layer) {
+ // Child local roots will always have a transparent background color.
+ widget_base_->LayerTreeHost()->set_background_color(SK_ColorTRANSPARENT);
+ // Pass the limits even though this is for subframes, as the limits will
+ // be needed in setting the raster scale.
+ SetPageScaleStateAndLimits(1.f, false /* is_pinch_gesture_active */,
+ View()->MinimumPageScaleFactor(),
+ View()->MaximumPageScaleFactor());
+ }
+
+ bool root_layer_exists = !!layer;
+ widget_base_->LayerTreeHost()->SetRootLayer(std::move(layer));
+
+ // Notify the WebView that we did set a layer.
+ if (ForMainFrame()) {
+ View()->DidChangeRootLayer(root_layer_exists);
+ }
+}
+
+base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
+WebFrameWidgetImpl::EnsureCompositorMutatorDispatcher(
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner) {
+ if (!mutator_task_runner_) {
+ mutator_task_runner_ = std::move(mutator_task_runner);
+ widget_base_->LayerTreeHost()->SetLayerTreeMutator(
+ AnimationWorkletMutatorDispatcherImpl::CreateCompositorThreadClient(
+ mutator_dispatcher_, mutator_task_runner_));
+ }
+
+ DCHECK(mutator_task_runner_);
+ return mutator_dispatcher_;
+}
+
+HitTestResult WebFrameWidgetImpl::CoreHitTestResultAt(
+ const gfx::PointF& point_in_viewport) {
+ LocalFrameView* view = LocalRootImpl()->GetFrameView();
+ FloatPoint point_in_root_frame(
+ view->ViewportToFrame(FloatPoint(point_in_viewport)));
+ return HitTestResultForRootFramePos(point_in_root_frame);
+}
+
+cc::AnimationHost* WebFrameWidgetImpl::AnimationHost() const {
+ return widget_base_->AnimationHost();
+}
+
+base::WeakPtr<PaintWorkletPaintDispatcher>
+WebFrameWidgetImpl::EnsureCompositorPaintDispatcher(
+ scoped_refptr<base::SingleThreadTaskRunner>* paint_task_runner) {
+ // We check paint_task_runner_ not paint_dispatcher_ because the dispatcher is
+ // a base::WeakPtr that should only be used on the compositor thread.
+ if (!paint_task_runner_) {
+ widget_base_->LayerTreeHost()->SetPaintWorkletLayerPainter(
+ PaintWorkletPaintDispatcher::CreateCompositorThreadPainter(
+ &paint_dispatcher_));
+ paint_task_runner_ = Thread::CompositorThread()->GetTaskRunner();
+ }
+ DCHECK(paint_task_runner_);
+ *paint_task_runner = paint_task_runner_;
+ return paint_dispatcher_;
+}
+
+void WebFrameWidgetImpl::SetDelegatedInkMetadata(
+ std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
+ widget_base_->LayerTreeHost()->SetDelegatedInkMetadata(std::move(metadata));
+}
+
+// Enables measuring and reporting both presentation times and swap times in
+// swap promises.
+class ReportTimeSwapPromise : public cc::SwapPromise {
+ public:
+ ReportTimeSwapPromise(WebReportTimeCallback swap_time_callback,
+ WebReportTimeCallback presentation_time_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ WebFrameWidgetImpl* widget)
+ : swap_time_callback_(std::move(swap_time_callback)),
+ presentation_time_callback_(std::move(presentation_time_callback)),
+ task_runner_(std::move(task_runner)),
+ widget_(widget) {}
+ ~ReportTimeSwapPromise() override = default;
+
+ void DidActivate() override {}
+
+ void WillSwap(viz::CompositorFrameMetadata* metadata) override {
+ DCHECK_GT(metadata->frame_token, 0u);
+ // The interval between the current swap and its presentation time is
+ // reported in UMA (see corresponding code in DidSwap() below).
+ frame_token_ = metadata->frame_token;
+ }
+
+ void DidSwap() override {
+ DCHECK_GT(frame_token_, 0u);
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(
+ &RunCallbackAfterSwap, widget_, base::TimeTicks::Now(),
+ std::move(swap_time_callback_),
+ std::move(presentation_time_callback_), frame_token_));
+ }
+
+ cc::SwapPromise::DidNotSwapAction DidNotSwap(
+ DidNotSwapReason reason) override {
+ WebSwapResult result;
+ switch (reason) {
+ case cc::SwapPromise::DidNotSwapReason::SWAP_FAILS:
+ result = WebSwapResult::kDidNotSwapSwapFails;
+ break;
+ case cc::SwapPromise::DidNotSwapReason::COMMIT_FAILS:
+ result = WebSwapResult::kDidNotSwapCommitFails;
+ break;
+ case cc::SwapPromise::DidNotSwapReason::COMMIT_NO_UPDATE:
+ result = WebSwapResult::kDidNotSwapCommitNoUpdate;
+ break;
+ case cc::SwapPromise::DidNotSwapReason::ACTIVATION_FAILS:
+ result = WebSwapResult::kDidNotSwapActivationFails;
+ break;
}
- ime_accept_events_ = true;
- } else {
- LocalFrame* focused_frame = FocusedLocalFrameInWidget();
- if (focused_frame) {
- // Finish an ongoing composition to delete the composition node.
- if (focused_frame->GetInputMethodController().HasComposition()) {
- // TODO(editing-dev): The use of
- // UpdateStyleAndLayout needs to be audited.
- // See http://crbug.com/590369 for more details.
- focused_frame->GetDocument()->UpdateStyleAndLayout(
- DocumentUpdateReason::kFocus);
-
- focused_frame->GetInputMethodController().FinishComposingText(
- InputMethodController::kKeepSelection);
- }
- ime_accept_events_ = false;
+ // During a failed swap, return the current time regardless of whether we're
+ // using presentation or swap timestamps.
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(
+ [](WebSwapResult result, base::TimeTicks swap_time,
+ WebReportTimeCallback swap_time_callback,
+ WebReportTimeCallback presentation_time_callback) {
+ ReportTime(std::move(swap_time_callback), result, swap_time);
+ ReportTime(std::move(presentation_time_callback), result,
+ swap_time);
+ },
+ result, base::TimeTicks::Now(), std::move(swap_time_callback_),
+ std::move(presentation_time_callback_)));
+ return DidNotSwapAction::BREAK_PROMISE;
+ }
+
+ int64_t TraceId() const override { return 0; }
+
+ private:
+ static void RunCallbackAfterSwap(
+ WebFrameWidgetImpl* widget,
+ base::TimeTicks swap_time,
+ WebReportTimeCallback swap_time_callback,
+ WebReportTimeCallback presentation_time_callback,
+ int frame_token) {
+ // If the widget was collected or the widget wasn't collected yet, but
+ // it was closed don't schedule a presentation callback.
+ if (widget && widget->widget_base_) {
+ widget->widget_base_->AddPresentationCallback(
+ frame_token,
+ WTF::Bind(&RunCallbackAfterPresentation,
+ std::move(presentation_time_callback), swap_time));
+ ReportTime(std::move(swap_time_callback), WebSwapResult::kDidSwap,
+ swap_time);
+ } else {
+ ReportTime(std::move(swap_time_callback), WebSwapResult::kDidSwap,
+ swap_time);
+ ReportTime(std::move(presentation_time_callback), WebSwapResult::kDidSwap,
+ swap_time);
}
}
+
+ static void RunCallbackAfterPresentation(
+ WebReportTimeCallback presentation_time_callback,
+ base::TimeTicks swap_time,
+ base::TimeTicks presentation_time) {
+ DCHECK(!swap_time.is_null());
+ bool presentation_time_is_valid =
+ !presentation_time.is_null() && (presentation_time > swap_time);
+ UMA_HISTOGRAM_BOOLEAN("PageLoad.Internal.Renderer.PresentationTime.Valid",
+ presentation_time_is_valid);
+ if (presentation_time_is_valid) {
+ // This measures from 1ms to 10seconds.
+ UMA_HISTOGRAM_TIMES(
+ "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime",
+ presentation_time - swap_time);
+ }
+ ReportTime(std::move(presentation_time_callback), WebSwapResult::kDidSwap,
+ presentation_time_is_valid ? presentation_time : swap_time);
+ }
+
+ static void ReportTime(WebReportTimeCallback callback,
+ WebSwapResult result,
+ base::TimeTicks time) {
+ if (callback)
+ std::move(callback).Run(result, time);
+ }
+
+ WebReportTimeCallback swap_time_callback_;
+ WebReportTimeCallback presentation_time_callback_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ CrossThreadWeakPersistent<WebFrameWidgetImpl> widget_;
+ uint32_t frame_token_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(ReportTimeSwapPromise);
+};
+
+void WebFrameWidgetImpl::NotifyPresentationTimeInBlink(
+ WebReportTimeCallback presentation_time_callback) {
+ NotifySwapAndPresentationTime(base::NullCallback(),
+ std::move(presentation_time_callback));
}
-void WebFrameWidgetImpl::EnableDeviceEmulation(
- const DeviceEmulationParams& parameters) {
- // This message should only be sent to the top level FrameWidget.
- NOTREACHED();
+void WebFrameWidgetImpl::NotifySwapAndPresentationTime(
+ WebReportTimeCallback swap_time_callback,
+ WebReportTimeCallback presentation_time_callback) {
+ if (!View()->does_composite())
+ return;
+ widget_base_->LayerTreeHost()->QueueSwapPromise(
+ std::make_unique<ReportTimeSwapPromise>(
+ std::move(swap_time_callback), std::move(presentation_time_callback),
+ widget_base_->LayerTreeHost()
+ ->GetTaskRunnerProvider()
+ ->MainThreadTaskRunner(),
+ this));
}
-void WebFrameWidgetImpl::DisableDeviceEmulation() {
- // This message should only be sent to the top level FrameWidget.
- NOTREACHED();
+scheduler::WebRenderWidgetSchedulingState*
+WebFrameWidgetImpl::RendererWidgetSchedulingState() {
+ return widget_base_->RendererWidgetSchedulingState();
+}
+
+void WebFrameWidgetImpl::WaitForDebuggerWhenShown() {
+ local_root_->WaitForDebuggerWhenShown();
+}
+
+void WebFrameWidgetImpl::SetTextZoomFactor(float text_zoom_factor) {
+ local_root_->GetFrame()->SetTextZoomFactor(text_zoom_factor);
+}
+
+float WebFrameWidgetImpl::TextZoomFactor() {
+ return local_root_->GetFrame()->TextZoomFactor();
+}
+
+void WebFrameWidgetImpl::SetMainFrameOverlayColor(SkColor color) {
+ DCHECK(!local_root_->Parent());
+ local_root_->GetFrame()->SetMainFrameColorOverlay(color);
+}
+
+void WebFrameWidgetImpl::AddEditCommandForNextKeyEvent(const WebString& name,
+ const WebString& value) {
+ edit_commands_.push_back(mojom::blink::EditCommand::New(name, value));
+}
+
+bool WebFrameWidgetImpl::HandleCurrentKeyboardEvent() {
+ bool did_execute_command = false;
+ WebLocalFrame* frame = FocusedWebLocalFrameInWidget();
+ if (!frame)
+ frame = local_root_;
+ for (const auto& command : edit_commands_) {
+ // In gtk and cocoa, it's possible to bind multiple edit commands to one
+ // key (but it's the exception). Once one edit command is not executed, it
+ // seems safest to not execute the rest.
+ if (!frame->ExecuteCommand(command->name, command->value))
+ break;
+ did_execute_command = true;
+ }
+
+ return did_execute_command;
+}
+
+void WebFrameWidgetImpl::ClearEditCommands() {
+ edit_commands_ = Vector<mojom::blink::EditCommandPtr>();
+}
+
+WebTextInputInfo WebFrameWidgetImpl::TextInputInfo() {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return WebTextInputInfo();
+ return controller->TextInputInfo();
+}
+
+ui::mojom::blink::VirtualKeyboardVisibilityRequest
+WebFrameWidgetImpl::GetLastVirtualKeyboardVisibilityRequest() {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE;
+ return controller->GetLastVirtualKeyboardVisibilityRequest();
+}
+
+bool WebFrameWidgetImpl::ShouldSuppressKeyboardForFocusedElement() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return false;
+ return focused_frame->ShouldSuppressKeyboardForFocusedElement();
+}
+
+void WebFrameWidgetImpl::GetEditContextBoundsInWindow(
+ base::Optional<gfx::Rect>* edit_context_control_bounds,
+ base::Optional<gfx::Rect>* edit_context_selection_bounds) {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return;
+ gfx::Rect control_bounds;
+ gfx::Rect selection_bounds;
+ controller->GetLayoutBounds(&control_bounds, &selection_bounds);
+ *edit_context_control_bounds =
+ widget_base_->BlinkSpaceToEnclosedDIPs(control_bounds);
+ if (controller->IsEditContextActive()) {
+ *edit_context_selection_bounds =
+ widget_base_->BlinkSpaceToEnclosedDIPs(selection_bounds);
+ }
+}
+
+int32_t WebFrameWidgetImpl::ComputeWebTextInputNextPreviousFlags() {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return 0;
+ return controller->ComputeWebTextInputNextPreviousFlags();
+}
+
+void WebFrameWidgetImpl::ResetVirtualKeyboardVisibilityRequest() {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return;
+ controller->SetVirtualKeyboardVisibilityRequest(
+ ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE);
+ ;
+}
+
+bool WebFrameWidgetImpl::GetSelectionBoundsInWindow(
+ gfx::Rect* focus,
+ gfx::Rect* anchor,
+ base::i18n::TextDirection* focus_dir,
+ base::i18n::TextDirection* anchor_dir,
+ bool* is_anchor_first) {
+ if (ShouldDispatchImeEventsToPlugin()) {
+ // TODO(kinaba) http://crbug.com/101101
+ // Current Pepper IME API does not handle selection bounds. So we simply
+ // use the caret position as an empty range for now. It will be updated
+ // after Pepper API equips features related to surrounding text retrieval.
+ gfx::Rect pepper_caret_in_dips = widget_base_->BlinkSpaceToEnclosedDIPs(
+ GetFocusedPluginContainer()->GetPluginCaretBounds());
+ if (pepper_caret_in_dips == *focus && pepper_caret_in_dips == *anchor)
+ return false;
+ *focus = pepper_caret_in_dips;
+ *anchor = *focus;
+ return true;
+ }
+ gfx::Rect focus_root_frame;
+ gfx::Rect anchor_root_frame;
+ CalculateSelectionBounds(focus_root_frame, anchor_root_frame);
+ gfx::Rect focus_rect_in_dips =
+ widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(focus_root_frame));
+ gfx::Rect anchor_rect_in_dips =
+ widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(anchor_root_frame));
+
+ // if the bounds are the same return false.
+ if (focus_rect_in_dips == *focus && anchor_rect_in_dips == *anchor)
+ return false;
+ *focus = focus_rect_in_dips;
+ *anchor = anchor_rect_in_dips;
+
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return true;
+ focused_frame->SelectionTextDirection(*focus_dir, *anchor_dir);
+ *is_anchor_first = focused_frame->IsSelectionAnchorFirst();
+ return true;
+}
+
+void WebFrameWidgetImpl::ClearTextInputState() {
+ widget_base_->ClearTextInputState();
+}
+
+bool WebFrameWidgetImpl::IsPasting() {
+ return widget_base_->is_pasting();
+}
+
+bool WebFrameWidgetImpl::HandlingSelectRange() {
+ return widget_base_->handling_select_range();
+}
+
+void WebFrameWidgetImpl::SetFocus(bool focus) {
+ widget_base_->SetFocus(focus);
+}
+
+bool WebFrameWidgetImpl::HasFocus() {
+ return widget_base_->has_focus();
+}
+
+void WebFrameWidgetImpl::SetToolTipText(const String& tooltip_text,
+ TextDirection dir) {
+ widget_base_->SetToolTipText(tooltip_text, dir);
+}
+
+void WebFrameWidgetImpl::DidOverscroll(
+ const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::PointF& position,
+ const gfx::Vector2dF& velocity) {
+#if defined(OS_MAC)
+ // On OSX the user can disable the elastic overscroll effect. If that's the
+ // case, don't forward the overscroll notification.
+ if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
+ return;
+#endif
+
+ cc::OverscrollBehavior overscroll_behavior =
+ widget_base_->LayerTreeHost()->overscroll_behavior();
+ if (!widget_base_->input_handler().DidOverscrollFromBlink(
+ overscroll_delta, accumulated_overscroll, position, velocity,
+ overscroll_behavior))
+ return;
+
+ // If we're currently handling an event, stash the overscroll data such that
+ // it can be bundled in the event ack.
+ if (mojom::blink::WidgetInputHandlerHost* host =
+ widget_base_->widget_input_handler_manager()
+ ->GetWidgetInputHandlerHost()) {
+ host->DidOverscroll(mojom::blink::DidOverscrollParams::New(
+ accumulated_overscroll, overscroll_delta, velocity, position,
+ overscroll_behavior));
+ }
+}
+
+void WebFrameWidgetImpl::InjectGestureScrollEvent(
+ blink::WebGestureDevice device,
+ const gfx::Vector2dF& delta,
+ ui::ScrollGranularity granularity,
+ cc::ElementId scrollable_area_element_id,
+ blink::WebInputEvent::Type injected_type) {
+ if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
+ // create a GestureScroll Event and post it to the compositor thread
+ // TODO(crbug.com/1126098) use original input event's timestamp.
+ // TODO(crbug.com/1082590) ensure continuity in scroll metrics collection
+ base::TimeTicks now = base::TimeTicks::Now();
+ std::unique_ptr<WebGestureEvent> gesture_event =
+ WebGestureEvent::GenerateInjectedScrollGesture(
+ injected_type, now, device, gfx::PointF(0, 0), delta, granularity);
+ if (injected_type == WebInputEvent::Type::kGestureScrollBegin) {
+ gesture_event->data.scroll_begin.scrollable_area_element_id =
+ scrollable_area_element_id.GetStableId();
+ gesture_event->data.scroll_begin.main_thread_hit_tested = true;
+ }
+
+ widget_base_->widget_input_handler_manager()
+ ->DispatchScrollGestureToCompositor(std::move(gesture_event));
+ } else {
+ widget_base_->input_handler().InjectGestureScrollEvent(
+ device, delta, granularity, scrollable_area_element_id, injected_type);
+ }
+}
+
+void WebFrameWidgetImpl::DidChangeCursor(const ui::Cursor& cursor) {
+ widget_base_->SetCursor(cursor);
+}
+
+bool WebFrameWidgetImpl::SetComposition(
+ const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int selection_start,
+ int selection_end) {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return false;
+
+ return controller->SetComposition(
+ text, ime_text_spans,
+ replacement_range.IsValid()
+ ? WebRange(replacement_range.start(), replacement_range.length())
+ : WebRange(),
+ selection_start, selection_end);
+}
+
+void WebFrameWidgetImpl::CommitText(
+ const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int relative_cursor_pos) {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return;
+ controller->CommitText(
+ text, ime_text_spans,
+ replacement_range.IsValid()
+ ? WebRange(replacement_range.start(), replacement_range.length())
+ : WebRange(),
+ relative_cursor_pos);
+}
+
+void WebFrameWidgetImpl::FinishComposingText(bool keep_selection) {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller)
+ return;
+ controller->FinishComposingText(
+ keep_selection ? WebInputMethodController::kKeepSelection
+ : WebInputMethodController::kDoNotKeepSelection);
+}
+
+bool WebFrameWidgetImpl::IsProvisional() {
+ return LocalRoot()->IsProvisional();
+}
+
+uint64_t WebFrameWidgetImpl::GetScrollableContainerIdAt(
+ const gfx::PointF& point_in_dips) {
+ gfx::PointF point = widget_base_->DIPsToBlinkSpace(point_in_dips);
+ return HitTestResultAt(point).GetScrollableContainerId();
+}
+
+bool WebFrameWidgetImpl::ShouldHandleImeEvents() {
+ if (ForMainFrame()) {
+ return HasFocus();
+ } else {
+ // TODO(ekaramad): main frame widget returns true only if it has focus.
+ // We track page focus in all WebViews on the page but the WebFrameWidgets
+ // corresponding to child local roots do not get the update. For now, this
+ // method returns true when the WebFrameWidget is for a child local frame,
+ // i.e., IME events will be processed regardless of page focus. We should
+ // revisit this after page focus for OOPIFs has been fully resolved
+ // (https://crbug.com/689777).
+ return LocalRootImpl();
+ }
+}
+
+void WebFrameWidgetImpl::SetEditCommandsForNextKeyEvent(
+ Vector<mojom::blink::EditCommandPtr> edit_commands) {
+ edit_commands_ = std::move(edit_commands);
+}
+
+void WebFrameWidgetImpl::FocusChangeComplete() {
+ blink::WebLocalFrame* focused = LocalRoot()->View()->FocusedFrame();
+
+ if (focused && focused->AutofillClient())
+ focused->AutofillClient()->DidCompleteFocusChangeInFrame();
+}
+
+void WebFrameWidgetImpl::ShowVirtualKeyboardOnElementFocus() {
+ widget_base_->ShowVirtualKeyboardOnElementFocus();
+}
+
+void WebFrameWidgetImpl::ProcessTouchAction(WebTouchAction touch_action) {
+ widget_base_->ProcessTouchAction(touch_action);
+}
+
+void WebFrameWidgetImpl::DidHandleGestureEvent(const WebGestureEvent& event) {
+#if defined(OS_ANDROID) || defined(USE_AURA)
+ if (event.GetType() == WebInputEvent::Type::kGestureTap) {
+ widget_base_->ShowVirtualKeyboard();
+ } else if (event.GetType() == WebInputEvent::Type::kGestureLongPress) {
+ WebInputMethodController* controller = GetActiveWebInputMethodController();
+ if (!controller || controller->TextInputInfo().value.IsEmpty())
+ widget_base_->UpdateTextInputState();
+ else
+ widget_base_->ShowVirtualKeyboard();
+ }
+#endif
+}
+
+void WebFrameWidgetImpl::SetHasPointerRawUpdateEventHandlers(
+ bool has_handlers) {
+ widget_base_->widget_input_handler_manager()
+ ->input_event_queue()
+ ->HasPointerRawUpdateEventHandlers(has_handlers);
+}
+
+void WebFrameWidgetImpl::SetNeedsLowLatencyInput(bool needs_low_latency) {
+ widget_base_->widget_input_handler_manager()
+ ->input_event_queue()
+ ->SetNeedsLowLatency(needs_low_latency);
+}
+
+void WebFrameWidgetImpl::RequestUnbufferedInputEvents() {
+ widget_base_->widget_input_handler_manager()
+ ->input_event_queue()
+ ->RequestUnbufferedInputEvents();
+}
+
+void WebFrameWidgetImpl::SetNeedsUnbufferedInputForDebugger(bool unbuffered) {
+ widget_base_->widget_input_handler_manager()
+ ->input_event_queue()
+ ->SetNeedsUnbufferedInputForDebugger(unbuffered);
+}
+
+void WebFrameWidgetImpl::DidNavigate() {
+ // The input handler wants to know about navigation so that it can
+ // suppress input until the newly navigated page has a committed frame.
+ // It also resets the state for UMA reporting of input arrival with respect
+ // to document lifecycle.
+ if (!widget_base_->widget_input_handler_manager())
+ return;
+ widget_base_->widget_input_handler_manager()->DidNavigate();
+}
+
+void WebFrameWidgetImpl::SetMouseCapture(bool capture) {
+ if (mojom::blink::WidgetInputHandlerHost* host =
+ widget_base_->widget_input_handler_manager()
+ ->GetWidgetInputHandlerHost()) {
+ host->SetMouseCapture(capture);
+ }
+}
+
+gfx::Range WebFrameWidgetImpl::CompositionRange() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame || ShouldDispatchImeEventsToPlugin())
+ return gfx::Range::InvalidRange();
+
+ blink::WebInputMethodController* controller =
+ focused_frame->GetInputMethodController();
+ WebRange web_range = controller->CompositionRange();
+ if (web_range.IsNull())
+ return gfx::Range::InvalidRange();
+ return gfx::Range(web_range.StartOffset(), web_range.EndOffset());
+}
+
+void WebFrameWidgetImpl::GetCompositionCharacterBoundsInWindow(
+ Vector<gfx::Rect>* bounds_in_dips) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame || ShouldDispatchImeEventsToPlugin())
+ return;
+ blink::WebInputMethodController* controller =
+ focused_frame->GetInputMethodController();
+ blink::WebVector<gfx::Rect> bounds_from_blink;
+ if (!controller->GetCompositionCharacterBounds(bounds_from_blink))
+ return;
+
+ for (auto& rect : bounds_from_blink) {
+ bounds_in_dips->push_back(widget_base_->BlinkSpaceToEnclosedDIPs(rect));
+ }
+}
+
+void WebFrameWidgetImpl::AddImeTextSpansToExistingText(
+ uint32_t start,
+ uint32_t end,
+ const Vector<ui::ImeTextSpan>& ime_text_spans) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->AddImeTextSpansToExistingText(ime_text_spans, start, end);
+}
+
+Vector<ui::mojom::blink::ImeTextSpanInfoPtr>
+WebFrameWidgetImpl::GetImeTextSpansInfo(
+ const WebVector<ui::ImeTextSpan>& ime_text_spans) {
+ auto* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return Vector<ui::mojom::blink::ImeTextSpanInfoPtr>();
+
+ Vector<ui::mojom::blink::ImeTextSpanInfoPtr> ime_text_spans_info;
+
+ for (const auto& ime_text_span : ime_text_spans) {
+ gfx::Rect rect;
+ unsigned length = ime_text_span.end_offset - ime_text_span.start_offset;
+ focused_frame->FirstRectForCharacterRange(ime_text_span.start_offset,
+ length, rect);
+
+ ime_text_spans_info.push_back(ui::mojom::blink::ImeTextSpanInfo::New(
+ ime_text_span, widget_base_->BlinkSpaceToEnclosedDIPs(rect)));
+ }
+ return ime_text_spans_info;
+}
+
+void WebFrameWidgetImpl::ClearImeTextSpansByType(uint32_t start,
+ uint32_t end,
+ ui::ImeTextSpan::Type type) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ClearImeTextSpansByType(type, start, end);
+}
+
+void WebFrameWidgetImpl::SetCompositionFromExistingText(
+ int32_t start,
+ int32_t end,
+ const Vector<ui::ImeTextSpan>& ime_text_spans) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->SetCompositionFromExistingText(start, end, ime_text_spans);
+}
+
+void WebFrameWidgetImpl::ExtendSelectionAndDelete(int32_t before,
+ int32_t after) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExtendSelectionAndDelete(before, after);
+}
+
+void WebFrameWidgetImpl::DeleteSurroundingText(int32_t before, int32_t after) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->DeleteSurroundingText(before, after);
+}
+
+void WebFrameWidgetImpl::DeleteSurroundingTextInCodePoints(int32_t before,
+ int32_t after) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->DeleteSurroundingTextInCodePoints(before, after);
+}
+
+void WebFrameWidgetImpl::SetEditableSelectionOffsets(int32_t start,
+ int32_t end) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->SetEditableSelectionOffsets(start, end);
+}
+
+void WebFrameWidgetImpl::ExecuteEditCommand(const String& command,
+ const String& value) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(command, value);
+}
+
+void WebFrameWidgetImpl::Undo() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Undo"));
+}
+
+void WebFrameWidgetImpl::Redo() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Redo"));
+}
+
+void WebFrameWidgetImpl::Cut() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Cut"));
+}
+
+void WebFrameWidgetImpl::Copy() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Copy"));
+}
+
+void WebFrameWidgetImpl::CopyToFindPboard() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ To<WebLocalFrameImpl>(focused_frame)->CopyToFindPboard();
+}
+
+void WebFrameWidgetImpl::Paste() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Paste"));
+}
+
+void WebFrameWidgetImpl::PasteAndMatchStyle() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("PasteAndMatchStyle"));
+}
+
+void WebFrameWidgetImpl::Delete() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("Delete"));
+}
+
+void WebFrameWidgetImpl::SelectAll() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->ExecuteCommand(WebString::FromLatin1("SelectAll"));
+}
+
+void WebFrameWidgetImpl::CollapseSelection() {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ const blink::WebRange& range =
+ focused_frame->GetInputMethodController()->GetSelectionOffsets();
+ if (range.IsNull())
+ return;
+
+ focused_frame->SelectRange(blink::WebRange(range.EndOffset(), 0),
+ blink::WebLocalFrame::kHideSelectionHandle,
+ mojom::blink::SelectionMenuBehavior::kHide);
+}
+
+void WebFrameWidgetImpl::Replace(const String& word) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ if (!focused_frame->HasSelection())
+ focused_frame->SelectWordAroundCaret();
+ focused_frame->ReplaceSelection(word);
+ focused_frame->Client()->SyncSelectionIfRequired();
+}
+
+void WebFrameWidgetImpl::ReplaceMisspelling(const String& word) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ if (!focused_frame->HasSelection())
+ return;
+ focused_frame->ReplaceMisspelledRange(word);
+}
+
+void WebFrameWidgetImpl::SelectRange(const gfx::Point& base_in_dips,
+ const gfx::Point& extent_in_dips) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->SelectRange(
+ widget_base_->DIPsToRoundedBlinkSpace(base_in_dips),
+ widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
+}
+
+void WebFrameWidgetImpl::AdjustSelectionByCharacterOffset(
+ int32_t start,
+ int32_t end,
+ mojom::blink::SelectionMenuBehavior selection_menu_behavior) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ blink::WebRange range =
+ focused_frame->GetInputMethodController()->GetSelectionOffsets();
+ if (range.IsNull())
+ return;
+
+ // Sanity checks to disallow empty and out of range selections.
+ if (start - end > range.length() || range.StartOffset() + start < 0)
+ return;
+
+ // A negative adjust amount moves the selection towards the beginning of
+ // the document, a positive amount moves the selection towards the end of
+ // the document.
+ focused_frame->SelectRange(blink::WebRange(range.StartOffset() + start,
+ range.length() + end - start),
+ blink::WebLocalFrame::kPreserveHandleVisibility,
+ selection_menu_behavior);
+}
+
+void WebFrameWidgetImpl::MoveRangeSelectionExtent(
+ const gfx::Point& extent_in_dips) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->MoveRangeSelectionExtent(
+ widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
+}
+
+void WebFrameWidgetImpl::ScrollFocusedEditableNodeIntoRect(
+ const gfx::Rect& rect_in_dips) {
+ WebLocalFrameImpl* local_frame = FocusedWebLocalFrameInWidget();
+ if (!local_frame)
+ return;
+
+ // OnSynchronizeVisualProperties does not call DidChangeVisibleViewport
+ // on OOPIFs. Since we are starting a new scroll operation now, call
+ // DidChangeVisibleViewport to ensure that we don't assume the element
+ // is already in view and ignore the scroll.
+ local_frame->ResetHasScrolledFocusedEditableIntoView();
+ local_frame->ScrollFocusedEditableElementIntoRect(rect_in_dips);
+}
+
+void WebFrameWidgetImpl::ZoomToFindInPageRect(
+ const gfx::Rect& rect_in_root_frame) {
+ if (ForMainFrame()) {
+ View()->ZoomToFindInPageRect(rect_in_root_frame);
+ } else {
+ GetAssociatedFrameWidgetHost()->ZoomToFindInPageRectInMainFrame(
+ rect_in_root_frame);
+ }
+}
+
+void WebFrameWidgetImpl::MoveCaret(const gfx::Point& point_in_dips) {
+ WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame)
+ return;
+ focused_frame->MoveCaretSelection(
+ widget_base_->DIPsToRoundedBlinkSpace(point_in_dips));
+}
+
+#if defined(OS_ANDROID)
+void WebFrameWidgetImpl::SelectWordAroundCaret(
+ SelectWordAroundCaretCallback callback) {
+ auto* focused_frame = FocusedWebLocalFrameInWidget();
+ if (!focused_frame) {
+ std::move(callback).Run(false, 0, 0);
+ return;
+ }
+
+ bool did_select = false;
+ int start_adjust = 0;
+ int end_adjust = 0;
+ blink::WebRange initial_range = focused_frame->SelectionRange();
+ SetHandlingInputEvent(true);
+ if (!initial_range.IsNull())
+ did_select = focused_frame->SelectWordAroundCaret();
+ if (did_select) {
+ blink::WebRange adjusted_range = focused_frame->SelectionRange();
+ DCHECK(!adjusted_range.IsNull());
+ start_adjust = adjusted_range.StartOffset() - initial_range.StartOffset();
+ end_adjust = adjusted_range.EndOffset() - initial_range.EndOffset();
+ }
+ SetHandlingInputEvent(false);
+ std::move(callback).Run(did_select, start_adjust, end_adjust);
+}
+#endif
+
+void WebFrameWidgetImpl::ForEachRemoteFrameControlledByWidget(
+ const base::RepeatingCallback<void(RemoteFrame*)>& callback) {
+ ForEachRemoteFrameChildrenControlledByWidget(local_root_->GetFrame(),
+ callback);
}
void WebFrameWidgetImpl::CalculateSelectionBounds(gfx::Rect& anchor_root_frame,
@@ -442,198 +3586,259 @@ void WebFrameWidgetImpl::CalculateSelectionBounds(gfx::Rect& anchor_root_frame,
if (!local_frame->Selection().ComputeAbsoluteBounds(anchor, focus))
return;
- // FIXME: This doesn't apply page scale. This should probably be contents to
- // viewport. crbug.com/459293.
- anchor_root_frame = local_frame->View()->ConvertToRootFrame(anchor);
- focus_root_frame = local_frame->View()->ConvertToRootFrame(focus);
+ // Apply the visual viewport for main frames this will apply the page scale.
+ // For subframes it will just be a 1:1 transformation and the browser
+ // will then apply later transformations to these rects.
+ VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
+ anchor_root_frame = visual_viewport.RootFrameToViewport(
+ local_frame->View()->ConvertToRootFrame(anchor));
+ focus_root_frame = visual_viewport.RootFrameToViewport(
+ local_frame->View()->ConvertToRootFrame(focus));
}
-void WebFrameWidgetImpl::SetRemoteViewportIntersection(
- const mojom::blink::ViewportIntersectionState& intersection_state) {
- SetViewportIntersection(intersection_state.Clone());
+void WebFrameWidgetImpl::BatterySavingsChanged(BatterySavingsFlags savings) {
+ widget_base_->LayerTreeHost()->SetEnableFrameRateThrottling(
+ savings & kAllowReducedFrameRate);
}
-void WebFrameWidgetImpl::SetViewportIntersection(
- mojom::blink::ViewportIntersectionStatePtr intersection_state) {
- // Remote viewports are only applicable to local frames with remote ancestors.
- DCHECK(LocalRootImpl()->Parent() &&
- LocalRootImpl()->Parent()->IsWebRemoteFrame() &&
- LocalRootImpl()->GetFrame());
-
- compositor_visible_rect_ =
- gfx::Rect(intersection_state->compositor_visible_rect);
- widget_base_->LayerTreeHost()->SetViewportVisibleRect(
- compositor_visible_rect_);
- LocalRootImpl()->GetFrame()->SetViewportIntersectionFromParent(
- *intersection_state);
+const viz::LocalSurfaceId& WebFrameWidgetImpl::LocalSurfaceIdFromParent() {
+ return widget_base_->local_surface_id_from_parent();
}
-void WebFrameWidgetImpl::SetIsInertForSubFrame(bool inert) {
- DCHECK(LocalRootImpl()->Parent());
- DCHECK(LocalRootImpl()->Parent()->IsWebRemoteFrame());
- LocalRootImpl()->GetFrame()->SetIsInert(inert);
+cc::LayerTreeHost* WebFrameWidgetImpl::LayerTreeHost() {
+ return widget_base_->LayerTreeHost();
}
-void WebFrameWidgetImpl::SetInheritedEffectiveTouchActionForSubFrame(
- TouchAction touch_action) {
- DCHECK(LocalRootImpl()->Parent());
- DCHECK(LocalRootImpl()->Parent()->IsWebRemoteFrame());
- LocalRootImpl()->GetFrame()->SetInheritedEffectiveTouchAction(touch_action);
+cc::LayerTreeHost* WebFrameWidgetImpl::LayerTreeHostForTesting() const {
+ return widget_base_->LayerTreeHost();
}
-void WebFrameWidgetImpl::UpdateRenderThrottlingStatusForSubFrame(
- bool is_throttled,
- bool subtree_throttled) {
- DCHECK(LocalRootImpl()->Parent());
- DCHECK(LocalRootImpl()->Parent()->IsWebRemoteFrame());
- LocalRootImpl()->GetFrameView()->UpdateRenderThrottlingStatus(
- is_throttled, subtree_throttled, true);
+ScreenMetricsEmulator* WebFrameWidgetImpl::DeviceEmulator() {
+ return device_emulator_;
}
-void WebFrameWidgetImpl::HandleMouseLeave(LocalFrame& main_frame,
- const WebMouseEvent& event) {
- // FIXME: WebWidget doesn't have the method below.
- // m_client->setMouseOverURL(WebURL());
- PageWidgetEventHandler::HandleMouseLeave(main_frame, event);
+bool WebFrameWidgetImpl::AutoResizeMode() {
+ return View()->AutoResizeMode();
}
-WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent(
- const WebGestureEvent& event) {
- DCHECK(Client());
- WebInputEventResult event_result = WebInputEventResult::kNotHandled;
- bool event_cancelled = false;
- base::Optional<ContextMenuAllowedScope> maybe_context_menu_scope;
+void WebFrameWidgetImpl::SetScreenMetricsEmulationParameters(
+ bool enabled,
+ const DeviceEmulationParams& params) {
+ if (enabled)
+ View()->ActivateDevToolsTransform(params);
+ else
+ View()->DeactivateDevToolsTransform();
+}
- WebViewImpl* view_impl = View();
- switch (event.GetType()) {
- case WebInputEvent::Type::kGestureScrollBegin:
- case WebInputEvent::Type::kGestureScrollEnd:
- case WebInputEvent::Type::kGestureScrollUpdate:
- case WebInputEvent::Type::kGestureTap:
- case WebInputEvent::Type::kGestureTapUnconfirmed:
- case WebInputEvent::Type::kGestureTapDown:
- // Touch pinch zoom and scroll on the page (outside of a popup) must hide
- // the popup. In case of a touch scroll or pinch zoom, this function is
- // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
- // WebViewImpl takes additional steps to avoid the following GestureTap
- // from re-opening the popup being closed here, but since GestureTap will
- // unconditionally close the current popup here, it is not used/needed.
- // TODO(wjmaclean): We should maybe mirror what WebViewImpl does, the
- // HandleGestureEvent() needs to happen inside or before the GestureTap
- // case to do so.
- View()->CancelPagePopup();
- break;
- case WebInputEvent::Type::kGestureTapCancel:
- case WebInputEvent::Type::kGestureShowPress:
- break;
- case WebInputEvent::Type::kGestureDoubleTap:
- if (GetPage()->GetChromeClient().DoubleTapToZoomEnabled() &&
- view_impl->MinimumPageScaleFactor() !=
- view_impl->MaximumPageScaleFactor()) {
- LocalFrame* frame = LocalRootImpl()->GetFrame();
- WebGestureEvent scaled_event =
- TransformWebGestureEvent(frame->View(), event);
- IntPoint pos_in_local_frame_root =
- FlooredIntPoint(scaled_event.PositionInRootFrame());
- auto block_bounds =
- gfx::Rect(ComputeBlockBound(pos_in_local_frame_root, false));
+void WebFrameWidgetImpl::SetScreenInfoAndSize(
+ const ScreenInfo& screen_info,
+ const gfx::Size& widget_size_in_dips,
+ const gfx::Size& visible_viewport_size_in_dips) {
+ // Emulation happens on regular main frames which don't use auto-resize mode.
+ DCHECK(!AutoResizeMode());
- // This sends the tap point and bounds to the main frame renderer via
- // the browser, where their coordinates will be transformed into the
- // main frame's coordinate space.
- GetAssociatedFrameWidgetHost()->AnimateDoubleTapZoomInMainFrame(
- pos_in_local_frame_root, block_bounds);
- }
- event_result = WebInputEventResult::kHandledSystem;
- DidHandleGestureEvent(event, event_cancelled);
- return event_result;
- case WebInputEvent::Type::kGestureTwoFingerTap:
- case WebInputEvent::Type::kGestureLongPress:
- case WebInputEvent::Type::kGestureLongTap:
- GetPage()->GetContextMenuController().ClearContextMenu();
- maybe_context_menu_scope.emplace();
- break;
- default:
- NOTREACHED();
- }
- LocalFrame* frame = LocalRootImpl()->GetFrame();
- WebGestureEvent scaled_event = TransformWebGestureEvent(frame->View(), event);
- event_result = frame->GetEventHandler().HandleGestureEvent(scaled_event);
- DidHandleGestureEvent(event, event_cancelled);
- return event_result;
+ UpdateScreenInfo(screen_info);
+ widget_base_->SetVisibleViewportSizeInDIPs(visible_viewport_size_in_dips);
+ Resize(widget_base_->DIPsToCeiledBlinkSpace(widget_size_in_dips));
}
-LocalFrameView* WebFrameWidgetImpl::GetLocalFrameViewForAnimationScrolling() {
- return LocalRootImpl()->GetFrame()->View();
+float WebFrameWidgetImpl::GetCompositingScaleFactor() {
+ return compositing_scale_factor_;
}
-WebInputEventResult WebFrameWidgetImpl::HandleKeyEvent(
- const WebKeyboardEvent& event) {
- DCHECK((event.GetType() == WebInputEvent::Type::kRawKeyDown) ||
- (event.GetType() == WebInputEvent::Type::kKeyDown) ||
- (event.GetType() == WebInputEvent::Type::kKeyUp));
+const cc::LayerTreeDebugState& WebFrameWidgetImpl::GetLayerTreeDebugState() {
+ return widget_base_->LayerTreeHost()->GetDebugState();
+}
- // Please refer to the comments explaining the m_suppressNextKeypressEvent
- // member.
- // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
- // Webkit. A keyDown event is typically associated with a keyPress(char)
- // event and a keyUp event. We reset this flag here as this is a new keyDown
- // event.
- suppress_next_keypress_event_ = false;
+void WebFrameWidgetImpl::SetLayerTreeDebugState(
+ const cc::LayerTreeDebugState& state) {
+ widget_base_->LayerTreeHost()->SetDebugState(state);
+}
- // If there is a popup open, it should be the one processing the event,
- // not the page.
- scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
- if (page_popup) {
- page_popup->HandleKeyEvent(event);
- if (event.GetType() == WebInputEvent::Type::kRawKeyDown) {
- suppress_next_keypress_event_ = true;
+void WebFrameWidgetImpl::NotifyCompositingScaleFactorChanged(
+ float compositing_scale_factor) {
+ compositing_scale_factor_ = compositing_scale_factor;
+
+ // Update the scale factor for remote frames which in turn depends on the
+ // compositing scale factor set in the widget.
+ ForEachRemoteFrameControlledByWidget(
+ WTF::BindRepeating([](RemoteFrame* remote_frame) {
+ if (remote_frame->View())
+ remote_frame->View()->UpdateCompositingScaleFactor();
+ }));
+}
+
+void WebFrameWidgetImpl::NotifyPageScaleFactorChanged(
+ float page_scale_factor,
+ bool is_pinch_gesture_active) {
+ // Store the value to give to any new RemoteFrame that will be created as a
+ // descendant of this widget.
+ page_scale_factor_in_mainframe_ = page_scale_factor;
+ is_pinch_gesture_active_in_mainframe_ = is_pinch_gesture_active;
+ // Push the page scale factor down to any child RemoteFrames.
+ // TODO(danakj): This ends up setting the page scale factor in the
+ // RenderWidgetHost of the child WebFrameWidgetImpl, so that it can bounce
+ // the value down to its WebFrameWidgetImpl. Since this is essentially a
+ // global value per-page, we could instead store it once in the browser
+ // (such as in RenderViewHost) and distribute it to each WebFrameWidgetImpl
+ // from there.
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](float page_scale_factor, bool is_pinch_gesture_active,
+ RemoteFrame* remote_frame) {
+ remote_frame->PageScaleFactorChanged(page_scale_factor,
+ is_pinch_gesture_active);
+ },
+ page_scale_factor, is_pinch_gesture_active));
+}
+
+void WebFrameWidgetImpl::SetPageScaleStateAndLimits(
+ float page_scale_factor,
+ bool is_pinch_gesture_active,
+ float minimum,
+ float maximum) {
+ widget_base_->LayerTreeHost()->SetPageScaleFactorAndLimits(page_scale_factor,
+ minimum, maximum);
+
+ // Only propagate page scale from the main frame.
+ if (ForMainFrame()) {
+ // If page scale hasn't changed, then just return without notifying
+ // the remote frames.
+ if (page_scale_factor == page_scale_factor_in_mainframe_ &&
+ is_pinch_gesture_active == is_pinch_gesture_active_in_mainframe_) {
+ return;
}
- return WebInputEventResult::kHandledSystem;
+
+ NotifyPageScaleFactorChanged(page_scale_factor, is_pinch_gesture_active);
}
+}
- auto* frame = DynamicTo<LocalFrame>(FocusedCoreFrame());
- if (!frame)
- return WebInputEventResult::kNotHandled;
+bool WebFrameWidgetImpl::UpdateScreenRects(
+ const gfx::Rect& widget_screen_rect,
+ const gfx::Rect& window_screen_rect) {
+ if (!device_emulator_)
+ return false;
+ device_emulator_->OnUpdateScreenRects(widget_screen_rect, window_screen_rect);
+ return true;
+}
- WebInputEventResult result = frame->GetEventHandler().KeyEvent(event);
- if (result != WebInputEventResult::kNotHandled) {
- if (WebInputEvent::Type::kRawKeyDown == event.GetType()) {
- // Suppress the next keypress event unless the focused node is a plugin
- // node. (Flash needs these keypress events to handle non-US keyboards.)
- Element* element = FocusedElement();
- if (!element || !element->GetLayoutObject() ||
- !element->GetLayoutObject()->IsEmbeddedObject())
- suppress_next_keypress_event_ = true;
- }
- return result;
+void WebFrameWidgetImpl::OrientationChanged() {
+ local_root_->SendOrientationChangeEvent();
+}
+
+void WebFrameWidgetImpl::DidUpdateSurfaceAndScreen(
+ const ScreenInfo& previous_original_screen_info) {
+ ScreenInfo screen_info = widget_base_->GetScreenInfo();
+ if (Platform::Current()->IsUseZoomForDSFEnabled()) {
+ View()->SetZoomFactorForDeviceScaleFactor(screen_info.device_scale_factor);
+ } else {
+ View()->SetDeviceScaleFactor(screen_info.device_scale_factor);
}
-#if !defined(OS_MAC)
- const WebInputEvent::Type kContextMenuKeyTriggeringEventType =
-#if defined(OS_WIN)
- WebInputEvent::Type::kKeyUp;
-#else
- WebInputEvent::Type::kRawKeyDown;
-#endif
- const WebInputEvent::Type kShiftF10TriggeringEventType =
- WebInputEvent::Type::kRawKeyDown;
+ if (ShouldAutoDetermineCompositingToLCDTextSetting()) {
+ // This causes compositing state to be modified which dirties the
+ // document lifecycle. Android Webview relies on the document
+ // lifecycle being clean after the RenderWidget is initialized, in
+ // order to send IPCs that query and change compositing state. So
+ // WebFrameWidgetImpl::Resize() must come after this call, as it runs the
+ // entire document lifecycle.
+ View()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
+ widget_base_->ComputePreferCompositingToLCDText());
+ }
- bool is_unmodified_menu_key =
- !(event.GetModifiers() & WebInputEvent::kInputModifiers) &&
- event.windows_key_code == VKEY_APPS;
- bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) ==
- WebInputEvent::kShiftKey &&
- event.windows_key_code == VKEY_F10;
- if ((is_unmodified_menu_key &&
- event.GetType() == kContextMenuKeyTriggeringEventType) ||
- (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) {
- View()->SendContextMenuEvent();
- return WebInputEventResult::kHandledSystem;
+ // When the device scale changes, the size and position of the popup would
+ // need to be adjusted, which we can't do. Just close the popup, which is
+ // also consistent with page zoom and resize behavior.
+ ScreenInfo original_screen_info = GetOriginalScreenInfo();
+ if (previous_original_screen_info.device_scale_factor !=
+ original_screen_info.device_scale_factor) {
+ View()->CancelPagePopup();
}
-#endif // !defined(OS_MAC)
- return WebInputEventResult::kNotHandled;
+ if (previous_original_screen_info != original_screen_info) {
+ local_root_->GetFrame()->DomWindow()->screen()->DispatchEvent(
+ *Event::Create(event_type_names::kChange));
+
+ // Propagate changes down to child local root RenderWidgets and
+ // BrowserPlugins in other frame trees/processes.
+ ForEachRemoteFrameControlledByWidget(WTF::BindRepeating(
+ [](const ScreenInfo& original_screen_info, RemoteFrame* remote_frame) {
+ remote_frame->DidChangeScreenInfo(original_screen_info);
+ },
+ original_screen_info));
+ }
+}
+
+gfx::Rect WebFrameWidgetImpl::ViewportVisibleRect() {
+ if (ForMainFrame()) {
+ return widget_base_->CompositorViewportRect();
+ } else {
+ return child_data().compositor_visible_rect;
+ }
+}
+
+const ScreenInfo& WebFrameWidgetImpl::GetOriginalScreenInfo() {
+ if (device_emulator_)
+ return device_emulator_->original_screen_info();
+ return widget_base_->GetScreenInfo();
+}
+
+base::Optional<blink::mojom::ScreenOrientation>
+WebFrameWidgetImpl::ScreenOrientationOverride() {
+ return View()->ScreenOrientationOverride();
+}
+
+void WebFrameWidgetImpl::WasHidden() {
+ ForEachLocalFrameControlledByWidget(
+ local_root_->GetFrame(),
+ WTF::BindRepeating([](WebLocalFrameImpl* local_frame) {
+ local_frame->Client()->WasHidden();
+ }));
+}
+
+void WebFrameWidgetImpl::WasShown(bool was_evicted) {
+ ForEachLocalFrameControlledByWidget(
+ local_root_->GetFrame(),
+ WTF::BindRepeating([](WebLocalFrameImpl* local_frame) {
+ local_frame->Client()->WasShown();
+ }));
+ if (was_evicted) {
+ ForEachRemoteFrameControlledByWidget(
+ WTF::BindRepeating([](RemoteFrame* remote_frame) {
+ // On eviction, the last SurfaceId is invalidated. We need to
+ // allocate a new id.
+ remote_frame->ResendVisualProperties();
+ }));
+ }
+}
+
+void WebFrameWidgetImpl::RunPaintBenchmark(int repeat_count,
+ cc::PaintBenchmarkResult& result) {
+ if (!ForMainFrame())
+ return;
+ if (auto* frame_view = LocalRootImpl()->GetFrameView())
+ frame_view->RunPaintBenchmark(repeat_count, result);
+}
+
+void WebFrameWidgetImpl::NotifyInputObservers(
+ const WebCoalescedInputEvent& coalesced_event) {
+ LocalFrame* frame = FocusedLocalFrameInWidget();
+ if (!frame)
+ return;
+
+ LocalFrameView* frame_view = frame->View();
+ if (!frame_view)
+ return;
+
+ const WebInputEvent& input_event = coalesced_event.Event();
+ auto& paint_timing_detector = frame_view->GetPaintTimingDetector();
+
+ if (paint_timing_detector.NeedToNotifyInputOrScroll())
+ paint_timing_detector.NotifyInputEvent(input_event.GetType());
+}
+
+Frame* WebFrameWidgetImpl::FocusedCoreFrame() const {
+ return GetPage() ? GetPage()->GetFocusController().FocusedOrMainFrame()
+ : nullptr;
}
Element* WebFrameWidgetImpl::FocusedElement() const {
@@ -648,66 +3853,246 @@ Element* WebFrameWidgetImpl::FocusedElement() const {
return document->FocusedElement();
}
-PaintLayerCompositor* WebFrameWidgetImpl::Compositor() const {
- LocalFrame* frame = LocalRootImpl()->GetFrame();
- if (!frame || !frame->GetDocument() || !frame->GetDocument()->GetLayoutView())
- return nullptr;
+HitTestResult WebFrameWidgetImpl::HitTestResultForRootFramePos(
+ const FloatPoint& pos_in_root_frame) {
+ FloatPoint doc_point =
+ LocalRootImpl()->GetFrame()->View()->ConvertFromRootFrame(
+ pos_in_root_frame);
+ HitTestLocation location(doc_point);
+ HitTestResult result =
+ LocalRootImpl()->GetFrame()->View()->HitTestWithThrottlingAllowed(
+ location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
+ result.SetToShadowHostIfInRestrictedShadowRoot();
+ return result;
+}
- return frame->GetDocument()->GetLayoutView()->Compositor();
+bool WebFrameWidgetImpl::SynchronousResizeModeForTestingEnabled() {
+ return main_data().synchronous_resize_mode_for_testing;
}
-void WebFrameWidgetImpl::SetRootLayer(scoped_refptr<cc::Layer> layer) {
- if (!layer) {
- // This notifies the WebFrameWidgetImpl that its LocalFrame tree is being
- // detached.
+KURL WebFrameWidgetImpl::GetURLForDebugTrace() {
+ WebFrame* main_frame = View()->MainFrame();
+ if (main_frame->IsWebLocalFrame())
+ return main_frame->ToWebLocalFrame()->GetDocument().Url();
+ return {};
+}
+
+float WebFrameWidgetImpl::GetTestingDeviceScaleFactorOverride() {
+ return device_scale_factor_for_testing_;
+}
+
+void WebFrameWidgetImpl::ReleaseMouseLockAndPointerCaptureForTesting() {
+ GetPage()->GetPointerLockController().ExitPointerLock();
+ MouseCaptureLost();
+}
+
+const viz::FrameSinkId& WebFrameWidgetImpl::GetFrameSinkId() {
+ // It is valid to create a WebFrameWidget with an invalid frame sink id for
+ // printing and placeholders. But if we go to use it, it should be valid.
+ DCHECK(frame_sink_id_.is_valid());
+ return frame_sink_id_;
+}
+
+WebHitTestResult WebFrameWidgetImpl::HitTestResultAt(const gfx::PointF& point) {
+ return CoreHitTestResultAt(point);
+}
+
+void WebFrameWidgetImpl::SetZoomLevelForTesting(double zoom_level) {
+ DCHECK(ForMainFrame());
+ DCHECK_NE(zoom_level, -INFINITY);
+ zoom_level_for_testing_ = zoom_level;
+ SetZoomLevel(zoom_level);
+}
+
+void WebFrameWidgetImpl::ResetZoomLevelForTesting() {
+ DCHECK(ForMainFrame());
+ zoom_level_for_testing_ = -INFINITY;
+ SetZoomLevel(0);
+}
+
+void WebFrameWidgetImpl::SetDeviceScaleFactorForTesting(float factor) {
+ DCHECK(ForMainFrame());
+ DCHECK_GE(factor, 0.f);
+
+ // Stash the window size before we adjust the scale factor, as subsequent
+ // calls to convert will use the new scale factor.
+ gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(Size());
+ device_scale_factor_for_testing_ = factor;
+
+ // Receiving a 0 is used to reset between tests, it removes the override in
+ // order to listen to the browser for the next test.
+ if (!factor)
return;
+
+ // We are changing the device scale factor from the renderer, so allocate a
+ // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
+ widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
+
+ ScreenInfo info = widget_base_->GetScreenInfo();
+ info.device_scale_factor = factor;
+ gfx::Size size_with_dsf = gfx::ScaleToCeiledSize(size_in_dips, factor);
+ widget_base_->UpdateCompositorViewportAndScreenInfo(gfx::Rect(size_with_dsf),
+ info);
+ if (!AutoResizeMode()) {
+ // This picks up the new device scale factor as
+ // `UpdateCompositorViewportAndScreenInfo()` has applied a new value.
+ Resize(widget_base_->DIPsToCeiledBlinkSpace(size_in_dips));
}
+}
- // WebFrameWidgetImpl is used for child frames, which always have a
- // transparent background color.
- widget_base_->LayerTreeHost()->set_background_color(SK_ColorTRANSPARENT);
- // Pass the limits even though this is for subframes, as the limits will
- // be needed in setting the raster scale.
- SetPageScaleStateAndLimits(1.f, false /* is_pinch_gesture_active */,
- View()->MinimumPageScaleFactor(),
- View()->MaximumPageScaleFactor());
+FrameWidgetTestHelper*
+WebFrameWidgetImpl::GetFrameWidgetTestHelperForTesting() {
+ return nullptr;
+}
- widget_base_->LayerTreeHost()->SetRootLayer(layer);
+WebPlugin* WebFrameWidgetImpl::GetFocusedPluginContainer() {
+ LocalFrame* focused_frame = FocusedLocalFrameInWidget();
+ if (!focused_frame)
+ return nullptr;
+ if (auto* container = focused_frame->GetWebPluginContainer())
+ return container->Plugin();
+ return nullptr;
}
-void WebFrameWidgetImpl::ZoomToFindInPageRect(
- const WebRect& rect_in_root_frame) {
- GetAssociatedFrameWidgetHost()->ZoomToFindInPageRectInMainFrame(
- gfx::Rect(rect_in_root_frame));
+bool WebFrameWidgetImpl::HasPendingPageScaleAnimation() {
+ return LayerTreeHost()->HasPendingPageScaleAnimation();
}
-void WebFrameWidgetImpl::SetAutoResizeMode(bool auto_resize,
- const gfx::Size& min_size_before_dsf,
- const gfx::Size& max_size_before_dsf,
- float device_scale_factor) {
- // Auto resize mode only exists on the top level widget.
+void WebFrameWidgetImpl::SetSourceURLForCompositor(ukm::SourceId source_id,
+ const KURL& url) {
+ LayerTreeHost()->SetSourceURL(source_id, url);
}
-LocalFrame* WebFrameWidgetImpl::FocusedLocalFrameAvailableForIme() const {
- if (!ime_accept_events_)
- return nullptr;
- return FocusedLocalFrameInWidget();
+base::ReadOnlySharedMemoryRegion
+WebFrameWidgetImpl::CreateSharedMemoryForSmoothnessUkm() {
+ return LayerTreeHost()->CreateSharedMemoryForSmoothnessUkm();
+}
+
+bool WebFrameWidgetImpl::CanComposeInline() {
+ if (auto* plugin = GetFocusedPluginContainer())
+ return plugin->CanComposeInline();
+ return true;
+}
+
+bool WebFrameWidgetImpl::ShouldDispatchImeEventsToPlugin() {
+ if (auto* plugin = GetFocusedPluginContainer())
+ return plugin->ShouldDispatchImeEventsToPlugin();
+ return false;
+}
+
+void WebFrameWidgetImpl::ImeSetCompositionForPlugin(
+ const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int selection_start,
+ int selection_end) {
+ if (auto* plugin = GetFocusedPluginContainer()) {
+ plugin->ImeSetCompositionForPlugin(
+ text,
+ std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
+ ime_text_spans.end()),
+ replacement_range, selection_start, selection_end);
+ }
+}
+
+void WebFrameWidgetImpl::ImeCommitTextForPlugin(
+ const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int relative_cursor_pos) {
+ if (auto* plugin = GetFocusedPluginContainer()) {
+ plugin->ImeCommitTextForPlugin(
+ text,
+ std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
+ ime_text_spans.end()),
+ replacement_range, relative_cursor_pos);
+ }
+}
+
+void WebFrameWidgetImpl::ImeFinishComposingTextForPlugin(bool keep_selection) {
+ if (auto* plugin = GetFocusedPluginContainer())
+ plugin->ImeFinishComposingTextForPlugin(keep_selection);
+}
+
+void WebFrameWidgetImpl::SetWindowRect(const gfx::Rect& window_rect) {
+ DCHECK(ForMainFrame());
+ if (SynchronousResizeModeForTestingEnabled()) {
+ // This is a web-test-only path. At one point, it was planned to be
+ // removed. See https://crbug.com/309760.
+ SetWindowRectSynchronously(window_rect);
+ return;
+ }
+
+ SetPendingWindowRect(window_rect);
+ View()->SendWindowRectToMainFrameHost(
+ window_rect, WTF::Bind(&WebFrameWidgetImpl::AckPendingWindowRect,
+ WrapWeakPersistent(this)));
+}
+
+void WebFrameWidgetImpl::SetWindowRectSynchronouslyForTesting(
+ const gfx::Rect& new_window_rect) {
+ DCHECK(ForMainFrame());
+ SetWindowRectSynchronously(new_window_rect);
+}
+
+void WebFrameWidgetImpl::SetWindowRectSynchronously(
+ const gfx::Rect& new_window_rect) {
+ // This method is only call in tests, and it applies the |new_window_rect| to
+ // all three of:
+ // a) widget size (in |size_|)
+ // b) blink viewport (in |visible_viewport_size_|)
+ // c) compositor viewport (in cc::LayerTreeHost)
+ // Normally the browser controls these three things independently, but this is
+ // used in tests to control the size from the renderer.
+
+ // We are resizing the window from the renderer, so allocate a new
+ // viz::LocalSurfaceId to avoid surface invariants violations in tests.
+ widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
+
+ gfx::Rect compositor_viewport_pixel_rect(gfx::ScaleToCeiledSize(
+ new_window_rect.size(),
+ widget_base_->GetScreenInfo().device_scale_factor));
+ widget_base_->UpdateSurfaceAndScreenInfo(
+ widget_base_->local_surface_id_from_parent(),
+ compositor_viewport_pixel_rect, widget_base_->GetScreenInfo());
+
+ Resize(new_window_rect.size());
+ widget_base_->SetScreenRects(new_window_rect, new_window_rect);
}
void WebFrameWidgetImpl::DidCreateLocalRootView() {
// If this WebWidget still hasn't received its size from the embedder, block
// the parser. This is necessary, because the parser can cause layout to
// happen, which needs to be done with the correct size.
- if (!size_) {
- did_suspend_parsing_ = true;
+ if (ForSubframe() && !size_) {
+ child_data().did_suspend_parsing = true;
LocalRootImpl()->GetFrame()->Loader().GetDocumentLoader()->BlockParser();
}
}
-void WebFrameWidgetImpl::GetScrollParamsForFocusedEditableElement(
+mojom::blink::ScrollIntoViewParamsPtr
+WebFrameWidgetImpl::GetScrollParamsForFocusedEditableElement(
const Element& element,
- PhysicalRect& rect_to_scroll,
- mojom::blink::ScrollIntoViewParamsPtr& params) {
+ PhysicalRect& out_rect_to_scroll) {
+ // For main frames, scrolling takes place in two phases.
+ if (ForMainFrame()) {
+ // Since the page has been resized, the layout may have changed. The page
+ // scale animation started by ZoomAndScrollToFocusedEditableRect will scroll
+ // only the visual and layout viewports. We'll call ScrollRectToVisible with
+ // the stop_at_main_frame_layout_viewport param to ensure the element is
+ // actually visible in the page.
+ mojom::blink::ScrollIntoViewParamsPtr params =
+ ScrollAlignment::CreateScrollIntoViewParams(
+ ScrollAlignment::CenterIfNeeded(),
+ ScrollAlignment::CenterIfNeeded(),
+ mojom::blink::ScrollType::kProgrammatic, false,
+ mojom::blink::ScrollBehavior::kInstant);
+ params->stop_at_main_frame_layout_viewport = true;
+ out_rect_to_scroll =
+ PhysicalRect(element.GetLayoutObject()->AbsoluteBoundingBoxRect());
+ return params;
+ }
+
LocalFrameView& frame_view = *element.GetDocument().View();
IntRect absolute_element_bounds =
element.GetLayoutObject()->AbsoluteBoundingBoxRect();
@@ -716,7 +4101,7 @@ void WebFrameWidgetImpl::GetScrollParamsForFocusedEditableElement(
// Ideally, the chosen rectangle includes the element box and caret bounds
// plus some margin on the left. If this does not work (i.e., does not fit
// inside the frame view), then choose a subrect which includes the caret
- // bounds. It is preferrable to also include element bounds' location and left
+ // bounds. It is preferable to also include element bounds' location and left
// align the scroll. If this cant be satisfied, the scroll will be right
// aligned.
IntRect maximal_rect =
@@ -743,46 +4128,20 @@ void WebFrameWidgetImpl::GetScrollParamsForFocusedEditableElement(
}
}
+ mojom::blink::ScrollIntoViewParamsPtr params =
+ ScrollAlignment::CreateScrollIntoViewParams();
params->zoom_into_rect = View()->ShouldZoomToLegibleScale(element);
params->relative_element_bounds = NormalizeRect(
Intersection(absolute_element_bounds, maximal_rect), maximal_rect);
params->relative_caret_bounds = NormalizeRect(
Intersection(absolute_caret_bounds, maximal_rect), maximal_rect);
params->behavior = mojom::blink::ScrollBehavior::kInstant;
- rect_to_scroll = PhysicalRect(maximal_rect);
-}
-
-gfx::Rect WebFrameWidgetImpl::ViewportVisibleRect() {
- return compositor_visible_rect_;
+ out_rect_to_scroll = PhysicalRect(maximal_rect);
+ return params;
}
-void WebFrameWidgetImpl::ApplyVisualPropertiesSizing(
- const VisualProperties& visual_properties) {
- SetWindowSegments(visual_properties.root_widget_window_segments);
- widget_base_->UpdateSurfaceAndScreenInfo(
- visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
- visual_properties.compositor_viewport_pixel_rect,
- visual_properties.screen_info);
-
- // Store this even when auto-resizing, it is the size of the full viewport
- // used for clipping, and this value is propagated down the Widget
- // hierarchy via the VisualProperties waterfall.
- widget_base_->SetVisibleViewportSizeInDIPs(
- visual_properties.visible_viewport_size);
-
- // Widgets in a WebView's frame tree without a local main frame
- // set the size of the WebView to be the |visible_viewport_size|, in order
- // to limit compositing in (out of process) child frames to what is visible.
- //
- // Note that child frames in the same process/WebView frame tree as the
- // main frame do not do this in order to not clobber the source of truth in
- // the main frame.
- if (!View()->MainFrameImpl()) {
- View()->Resize(widget_base_->DIPsToCeiledBlinkSpace(
- widget_base_->VisibleViewportSizeInDIPs()));
- }
-
- Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size));
+bool WebFrameWidgetImpl::ShouldAutoDetermineCompositingToLCDTextSetting() {
+ return true;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index 229165d76d1..b638c3402cb 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -31,47 +31,81 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_FRAME_WIDGET_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_FRAME_WIDGET_IMPL_H_
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/optional.h"
+#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
+#include "build/build_config.h"
+#include "cc/input/event_listener_properties.h"
+#include "cc/input/layer_selection_bound.h"
+#include "cc/input/overscroll_behavior.h"
+#include "cc/trees/layer_tree_host.h"
+#include "services/viz/public/mojom/hit_test/input_target_client.mojom-blink.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
+#include "third_party/blink/public/common/input/web_gesture_device.h"
+#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
+#include "third_party/blink/public/mojom/manifest/display_mode.mojom-blink.h"
+#include "third_party/blink/public/mojom/page/drag.mojom-blink.h"
+#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
-#include "third_party/blink/public/platform/web_size.h"
-#include "third_party/blink/public/web/web_input_method_controller.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
+#include "third_party/blink/public/platform/web_drag_data.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
+#include "third_party/blink/public/web/web_meaningful_layout.h"
+#include "third_party/blink/renderer/core/clipboard/data_object.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/exported/web_page_popup_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/scroll/scroll_types.h"
+#include "third_party/blink/renderer/core/html/battery_savings.h"
+#include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
+#include "third_party/blink/renderer/core/page/page_widget_delegate.h"
#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
+#include "third_party/blink/renderer/platform/widget/widget_base_client.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/base/mojom/ui_base_types.mojom-shared.h"
-namespace cc {
-class Layer;
-}
+namespace gfx {
+class Point;
+class PointF;
+} // namespace gfx
namespace blink {
-class Element;
-class LocalFrame;
-class PaintLayerCompositor;
-class WebFrameWidget;
-class WebMouseEvent;
-class WebFrameWidgetImpl;
-
-// Implements WebFrameWidget for a child local root frame (OOPIF). This object
-// is created in the child renderer and attached to the OOPIF's WebLocalFrame.
-//
-// For the main frame's WebFrameWidget implementation, see WebViewFrameWidget.
-//
-class WebFrameWidgetImpl final : public WebFrameWidgetBase {
+class AnimationWorkletMutatorDispatcherImpl;
+class FloatPoint;
+class HitTestResult;
+class HTMLPlugInElement;
+class Page;
+class PageWidgetEventHandler;
+class PaintWorkletPaintDispatcher;
+class RemoteFrame;
+class WebLocalFrameImpl;
+class WebPlugin;
+class WebViewImpl;
+class WidgetBase;
+class ScreenMetricsEmulator;
+
+// Implements WebFrameWidget for both main frames and child local root frame
+// (OOPIF).
+class CORE_EXPORT WebFrameWidgetImpl
+ : public GarbageCollected<WebFrameWidgetImpl>,
+ public WebFrameWidget,
+ public WidgetBaseClient,
+ public mojom::blink::FrameWidget,
+ public viz::mojom::blink::InputTargetClient,
+ public mojom::blink::FrameWidgetInputHandler,
+ public FrameWidget,
+ public PageWidgetEventHandler {
public:
WebFrameWidgetImpl(
- util::PassKey<WebFrameWidget>,
- WebWidgetClient&,
+ base::PassKey<WebLocalFrame>,
CrossVariantMojoAssociatedRemote<
mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
@@ -83,107 +117,935 @@ class WebFrameWidgetImpl final : public WebFrameWidgetBase {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const viz::FrameSinkId& frame_sink_id,
bool hidden,
- bool never_composited);
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame);
~WebFrameWidgetImpl() override;
- // WebWidget functions:
- void Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) override;
- gfx::Size Size() override;
- void Resize(const gfx::Size&) override;
- void UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason) override;
+ virtual void Trace(Visitor*) const;
- void MouseCaptureLost() override;
- void SetRemoteViewportIntersection(
- const mojom::blink::ViewportIntersectionState& intersection_state)
- override;
- void SetIsInertForSubFrame(bool) override;
- void SetInheritedEffectiveTouchActionForSubFrame(TouchAction) override;
- void UpdateRenderThrottlingStatusForSubFrame(bool is_throttled,
- bool subtree_throttled) override;
+ // Shutdown the widget.
+ void Close();
- void SetViewportIntersection(
- mojom::blink::ViewportIntersectionStatePtr intersection_state) override;
+ // Returns the WebFrame that this widget is attached to. It will be a local
+ // root since only local roots have a widget attached.
+ WebLocalFrameImpl* LocalRootImpl() const { return local_root_; }
+
+ // Returns the bounding box of the block type node touched by the WebPoint.
+ gfx::Rect ComputeBlockBound(const gfx::Point& point_in_root_frame,
+ bool ignore_clipping) const;
+
+ virtual void BindLocalRoot(WebLocalFrame&);
+
+ // If this widget is for the top most main frame. This is different than
+ // |ForMainFrame| because |ForMainFrame| could return true but this method
+ // returns false. If this widget is a MainFrame widget embedded in another
+ // widget, for example embedding a portal.
+ bool ForTopMostMainFrame() const;
+
+ // Adjusts whether the widget is nested or not. This is called during portal
+ // transitions.
+ void SetIsNestedMainFrameWidget(bool is_nested);
+
+ // Returns true if this widget is for a local root that is a child frame,
+ // false otherwise.
+ bool ForSubframe() const { return is_for_child_local_root_; }
+
+ // Opposite of |ForSubframe|. If this widget is for the local main frame.
+ bool ForMainFrame() const { return !ForSubframe(); }
+
+ // Called when the intrinsic size of the owning container is changing its
+ // size. This should only be called when `ForSubframe` is true.
+ void IntrinsicSizingInfoChanged(mojom::blink::IntrinsicSizingInfoPtr);
+
+ void AutoscrollStart(const gfx::PointF& position);
+ void AutoscrollFling(const gfx::Vector2dF& position);
+ void AutoscrollEnd();
+
+ bool HandleCurrentKeyboardEvent();
+
+ // Creates or returns cached mutator dispatcher. This usually requires a
+ // round trip to the compositor. The returned WeakPtr must only be
+ // dereferenced on the output |mutator_task_runner|.
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
+ EnsureCompositorMutatorDispatcher(
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner);
+
+ // TODO: consider merge the input and return value to be one parameter.
+ // Creates or returns cached paint dispatcher. The returned WeakPtr must only
+ // be dereferenced on the output |paint_task_runner|.
+ base::WeakPtr<PaintWorkletPaintDispatcher> EnsureCompositorPaintDispatcher(
+ scoped_refptr<base::SingleThreadTaskRunner>* paint_task_runner);
+
+ HitTestResult CoreHitTestResultAt(const gfx::PointF&);
- // WebFrameWidget implementation.
+ // FrameWidget overrides.
+ cc::AnimationHost* AnimationHost() const final;
+ void SetOverscrollBehavior(
+ const cc::OverscrollBehavior& overscroll_behavior) final;
+ void RequestAnimationAfterDelay(const base::TimeDelta&) final;
+ void SetRootLayer(scoped_refptr<cc::Layer>) override;
+ void RegisterSelection(cc::LayerSelection selection) final;
+ void RequestDecode(const cc::PaintImage&,
+ base::OnceCallback<void(bool)>) override;
+ void NotifyPresentationTimeInBlink(
+ WebReportTimeCallback presentation_callback) final;
+ void RequestBeginMainFrameNotExpected(bool request) final;
+ int GetLayerTreeId() final;
+ const cc::LayerTreeSettings& GetLayerTreeSettings() final;
+ void UpdateBrowserControlsState(cc::BrowserControlsState constraints,
+ cc::BrowserControlsState current,
+ bool animate) final;
+ void SetEventListenerProperties(cc::EventListenerClass,
+ cc::EventListenerProperties) final;
+ cc::EventListenerProperties EventListenerProperties(
+ cc::EventListenerClass) const final;
+ mojom::blink::DisplayMode DisplayMode() const override;
+ const WebVector<gfx::Rect>& WindowSegments() const override;
+ void SetDelegatedInkMetadata(
+ std::unique_ptr<viz::DelegatedInkMetadata> metadata) final;
+ void DidOverscroll(const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::PointF& position,
+ const gfx::Vector2dF& velocity) override;
+ void InjectGestureScrollEvent(WebGestureDevice device,
+ const gfx::Vector2dF& delta,
+ ui::ScrollGranularity granularity,
+ cc::ElementId scrollable_area_element_id,
+ WebInputEvent::Type injected_type) override;
+ void DidChangeCursor(const ui::Cursor&) override;
+ void GetCompositionCharacterBoundsInWindow(
+ Vector<gfx::Rect>* bounds_in_dips) override;
+ gfx::Range CompositionRange() override;
+ WebTextInputInfo TextInputInfo() override;
+ ui::mojom::VirtualKeyboardVisibilityRequest
+ GetLastVirtualKeyboardVisibilityRequest() override;
+ bool ShouldSuppressKeyboardForFocusedElement() override;
+ void GetEditContextBoundsInWindow(
+ base::Optional<gfx::Rect>* control_bounds,
+ base::Optional<gfx::Rect>* selection_bounds) override;
+ int32_t ComputeWebTextInputNextPreviousFlags() override;
+ void ResetVirtualKeyboardVisibilityRequest() override;
+ bool GetSelectionBoundsInWindow(gfx::Rect* focus,
+ gfx::Rect* anchor,
+ base::i18n::TextDirection* focus_dir,
+ base::i18n::TextDirection* anchor_dir,
+ bool* is_anchor_first) override;
+ void ClearTextInputState() override;
+
+ bool SetComposition(const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int selection_start,
+ int selection_end) override;
+ void CommitText(const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int relative_cursor_pos) override;
+ void FinishComposingText(bool keep_selection) override;
+ bool IsProvisional() override;
+ uint64_t GetScrollableContainerIdAt(
+ const gfx::PointF& point_in_dips) override;
+ bool ShouldHandleImeEvents() override;
+ void SetEditCommandsForNextKeyEvent(
+ Vector<mojom::blink::EditCommandPtr> edit_commands) override;
+ Vector<ui::mojom::blink::ImeTextSpanInfoPtr> GetImeTextSpansInfo(
+ const WebVector<ui::ImeTextSpan>& ime_text_spans) override;
+ void RequestMouseLock(
+ bool has_transient_user_activation,
+ bool request_unadjusted_movement,
+ mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback)
+ override;
+ gfx::RectF BlinkSpaceToDIPs(const gfx::RectF& rect) override;
+ gfx::Rect BlinkSpaceToEnclosedDIPs(const gfx::Rect& rect) override;
+ gfx::Size BlinkSpaceToFlooredDIPs(const gfx::Size& size) override;
+ gfx::RectF DIPsToBlinkSpace(const gfx::RectF& rect) override;
+ gfx::PointF DIPsToBlinkSpace(const gfx::PointF& point) override;
+ gfx::Point DIPsToRoundedBlinkSpace(const gfx::Point& point) override;
+ float DIPsToBlinkSpace(float scalar) override;
+ void MouseCaptureLost() override;
+ bool CanComposeInline() override;
+ bool ShouldDispatchImeEventsToPlugin() override;
+ void ImeSetCompositionForPlugin(const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int selection_start,
+ int selection_end) override;
+ void ImeCommitTextForPlugin(const String& text,
+ const Vector<ui::ImeTextSpan>& ime_text_spans,
+ const gfx::Range& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingTextForPlugin(bool keep_selection) override;
+ float GetCompositingScaleFactor() override;
+ const cc::LayerTreeDebugState& GetLayerTreeDebugState() override;
+ void SetLayerTreeDebugState(const cc::LayerTreeDebugState& state) override;
+
+ // WebFrameWidget overrides.
+ void InitializeNonCompositing(WebNonCompositedWidgetClient* client) override;
+ WebLocalFrame* LocalRoot() const override;
+ void UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) override;
+ WebInputMethodController* GetActiveWebInputMethodController() const override;
+ void DisableDragAndDrop() override;
+ WebLocalFrameImpl* FocusedWebLocalFrameInWidget() const override;
bool ScrollFocusedEditableElementIntoView() override;
+ void ApplyViewportChangesForTesting(
+ const ApplyViewportChangesArgs& args) override;
+ void ApplyViewportIntersectionForTesting(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state);
+ void NotifySwapAndPresentationTime(
+ WebReportTimeCallback swap_callback,
+ WebReportTimeCallback presentation_callback) override;
+ scheduler::WebRenderWidgetSchedulingState* RendererWidgetSchedulingState()
+ override;
+ void WaitForDebuggerWhenShown() override;
+ void SetTextZoomFactor(float text_zoom_factor) override;
+ float TextZoomFactor() override;
+ void SetMainFrameOverlayColor(SkColor) override;
+ void AddEditCommandForNextKeyEvent(const WebString& name,
+ const WebString& value) override;
+ void ClearEditCommands() override;
+ bool IsPasting() override;
+ bool HandlingSelectRange() override;
+ void ReleaseMouseLockAndPointerCaptureForTesting() override;
+ const viz::FrameSinkId& GetFrameSinkId() override;
+ WebHitTestResult HitTestResultAt(const gfx::PointF&) override;
void SetZoomLevelForTesting(double zoom_level) override;
void ResetZoomLevelForTesting() override;
void SetDeviceScaleFactorForTesting(float factor) override;
+ FrameWidgetTestHelper* GetFrameWidgetTestHelperForTesting() override;
- // Returns the currently focused Element or null if no element has focus.
- Element* FocusedElement() const;
+ // Called when a drag-n-drop operation should begin.
+ virtual void StartDragging(const WebDragData&,
+ DragOperationsMask,
+ const SkBitmap& drag_image,
+ const gfx::Point& drag_image_offset);
- PaintLayerCompositor* Compositor() const;
+ bool DoingDragAndDrop() { return doing_drag_and_drop_; }
+ static void SetIgnoreInputEvents(bool value) { ignore_input_events_ = value; }
+ static bool IgnoreInputEvents() { return ignore_input_events_; }
- // WebFrameWidgetBase overrides:
- bool ForSubframe() const override { return true; }
- bool ForTopLevelFrame() const override { return false; }
- void IntrinsicSizingInfoChanged(
- mojom::blink::IntrinsicSizingInfoPtr) override;
- void DidCreateLocalRootView() override;
- void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) override;
- void SetAutoResizeMode(bool auto_resize,
- const gfx::Size& min_size_before_dsf,
- const gfx::Size& max_size_before_dsf,
- float device_scale_factor) override;
- void ApplyVisualPropertiesSizing(
+ // Resets the layout tracking steps for the main frame. When
+ // `UpdateLifecycle()` is called it generates `WebMeaningfulLayout` events
+ // only once. This resets the state back to the default so it will fire new
+ // events.
+ void ResetMeaningfulLayoutStateForMainFrame();
+
+ // WebWidget overrides.
+ void InitializeCompositing(
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
+ cc::TaskGraphRunner* task_graph_runner,
+ const ScreenInfo& screen_info,
+ std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
+ const cc::LayerTreeSettings* settings) override;
+ void SetCompositorVisible(bool visible) override;
+ gfx::Size Size() override;
+ void Resize(const gfx::Size& size_with_dsf) override;
+ void SetCursor(const ui::Cursor& cursor) override;
+ bool HandlingInputEvent() override;
+ void SetHandlingInputEvent(bool handling) override;
+ void ProcessInputEventSynchronouslyForTesting(const WebCoalescedInputEvent&,
+ HandledEventCallback) override;
+ WebInputEventResult DispatchBufferedTouchEvents() override;
+ WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override;
+ void UpdateTextInputState() override;
+ void UpdateSelectionBounds() override;
+ void ShowVirtualKeyboard() override;
+ bool HasFocus() override;
+ void SetFocus(bool focus) override;
+ void FlushInputProcessedCallback() override;
+ void CancelCompositionForPepper() override;
+ void ApplyVisualProperties(
const VisualProperties& visual_properties) override;
- void CalculateSelectionBounds(gfx::Rect& anchor, gfx::Rect& focus) override;
+ bool PinchGestureActiveInMainFrame() override;
+ float PageScaleInMainFrame() override;
+ const ScreenInfo& GetScreenInfo() override;
+ gfx::Rect WindowRect() override;
+ gfx::Rect ViewRect() override;
+ void SetScreenRects(const gfx::Rect& widget_screen_rect,
+ const gfx::Rect& window_screen_rect) override;
+ gfx::Size VisibleViewportSizeInDIPs() override;
+ bool IsHidden() const override;
+ WebString GetLastToolTipTextForTesting() const override;
+ float GetEmulatorScale() override;
- // FrameWidget overrides:
- void SetRootLayer(scoped_refptr<cc::Layer>) override;
- bool ShouldHandleImeEvents() override;
+ // WidgetBaseClient overrides:
+ void BeginMainFrame(base::TimeTicks last_frame_time) override;
+ void UpdateLifecycle(WebLifecycleUpdate requested_update,
+ DocumentUpdateReason reason) override;
+
+ // mojom::blink::FrameWidget overrides:
+ void ShowContextMenu(ui::mojom::MenuSourceType source_type,
+ const gfx::Point& location) override;
+ void SetViewportIntersection(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state,
+ const base::Optional<VisualProperties>& visual_properties) override;
+ void DragSourceEndedAt(const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ ui::mojom::blink::DragOperation) override;
+
+ // Sets the display mode, which comes from the top-level browsing context and
+ // is applied to all widgets.
+ void SetDisplayMode(mojom::blink::DisplayMode);
+
+ base::Optional<gfx::Point> GetAndResetContextMenuLocation();
+
+ void BindWidgetCompositor(
+ mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) override;
+
+ void BindInputTargetClient(
+ mojo::PendingReceiver<viz::mojom::blink::InputTargetClient> receiver)
+ override;
+
+ // viz::mojom::blink::InputTargetClient:
+ void FrameSinkIdAt(const gfx::PointF& point,
+ const uint64_t trace_id,
+ FrameSinkIdAtCallback callback) override;
+
+ // Called when the FrameView for this Widget's local root is created.
+ void DidCreateLocalRootView();
+
+ void SetZoomLevel(double zoom_level);
+
+ // Called when the View has auto resized.
+ void DidAutoResize(const gfx::Size& size);
+
+ // This method returns the focused frame belonging to this WebWidget, that
+ // is, a focused frame with the same local root as the one corresponding
+ // to this widget. It will return nullptr if no frame is focused or, the
+ // focused frame has a different local root.
+ LocalFrame* FocusedLocalFrameInWidget() const;
+
+ // For when the embedder itself change scales on the page (e.g. devtools)
+ // and wants all of the content at the new scale to be crisp
+ void SetNeedsRecalculateRasterScales();
+
+ // Sets the background color to be filled in as gutter behind/around the
+ // painted content. Non-composited WebViews need not implement this, as they
+ // paint into another widget which has a background color of its own.
+ void SetBackgroundColor(SkColor color);
+
+ // Starts an animation of the page scale to a target scale factor and scroll
+ // offset.
+ // If use_anchor is true, destination is a point on the screen that will
+ // remain fixed for the duration of the animation.
+ // If use_anchor is false, destination is the final top-left scroll position.
+ void StartPageScaleAnimation(const gfx::Vector2d& destination,
+ bool use_anchor,
+ float new_page_scale,
+ base::TimeDelta duration);
+
+ // Called to update if scroll events should be sent.
+ void SetHaveScrollEventHandlers(bool);
+
+ // Start deferring commits to the compositor, allowing document lifecycle
+ // updates without committing the layer tree. Commits are deferred
+ // until at most the given |timeout| has passed. If multiple calls are made
+ // when deferral is active then the initial timeout applies.
+ void StartDeferringCommits(base::TimeDelta timeout);
+ // Immediately stop deferring commits.
+ void StopDeferringCommits(cc::PaintHoldingCommitTrigger);
+
+ // Prevents any updates to the input for the layer tree, and the layer tree
+ // itself, and the layer tree from becoming visible.
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate> DeferMainFrameUpdate();
+
+ // Sets the amount that the top and bottom browser controls are showing, from
+ // 0 (hidden) to 1 (fully shown).
+ void SetBrowserControlsShownRatio(float top_ratio, float bottom_ratio);
+
+ // Set browser controls params. These params consist of top and bottom
+ // heights, min-heights, browser_controls_shrink_blink_size, and
+ // animate_browser_controls_height_changes. If
+ // animate_browser_controls_height_changes is set to true, changes to the
+ // browser controls height will be animated. If
+ // browser_controls_shrink_blink_size is set to true, then Blink shrunk the
+ // viewport clip layers by the top and bottom browser controls height. Top
+ // controls will translate the web page down and do not immediately scroll
+ // when hiding. The bottom controls scroll immediately and never translate the
+ // content (only clip it).
+ void SetBrowserControlsParams(cc::BrowserControlsParams params);
+
+ // This function provides zooming for find in page results when browsing with
+ // page autosize.
+ void ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame);
+
+ // Return the compositor LayerTreeHost.
+ cc::LayerTreeHost* LayerTreeHostForTesting() const;
+ // Ask compositor to composite a frame for testing. This will generate a
+ // BeginMainFrame, and update the document lifecycle.
+ void SynchronouslyCompositeForTesting(base::TimeTicks frame_time);
+
+ // Adjust the synchronous resize mode for testing. Normally resizes are
+ // asynchronous with sending the resize to the browser, however some tests
+ // still need the resize to happen in a synchronous fashion.
+ void UseSynchronousResizeModeForTesting(bool enable);
+
+ // Sets the device color space for testing.
+ void SetDeviceColorSpaceForTesting(const gfx::ColorSpace& color_space);
+
+ // Converts from DIPs to Blink coordinate space (ie. Viewport/Physical
+ // pixels).
+ gfx::Size DIPsToCeiledBlinkSpace(const gfx::Size& size);
+
+ void SetWindowRect(const gfx::Rect& window_rect);
+ void SetWindowRectSynchronouslyForTesting(const gfx::Rect& new_window_rect);
+
+ void SetToolTipText(const String& tooltip_text, TextDirection dir);
+
+ void ShowVirtualKeyboardOnElementFocus();
+ void ProcessTouchAction(WebTouchAction touch_action);
+
+ // Called to update whether low latency input mode is enabled or not.
+ void SetNeedsLowLatencyInput(bool);
+
+ // Requests unbuffered (ie. low latency) input until a pointerup
+ // event occurs.
+ void RequestUnbufferedInputEvents();
+
+ // Requests unbuffered (ie. low latency) input due to debugger being
+ // attached. Debugger needs to paint when stopped in the event handler.
+ void SetNeedsUnbufferedInputForDebugger(bool);
+
+ // Called when the main frame navigates.
+ void DidNavigate();
+
+ // Called when the widget should get targeting input.
+ void SetMouseCapture(bool capture);
+
+ // Sets the current page scale factor and minimum / maximum limits. Both
+ // limits are initially 1 (no page scale allowed).
+ void SetPageScaleStateAndLimits(float page_scale_factor,
+ bool is_pinch_gesture_active,
+ float minimum,
+ float maximum);
+
+ // The value of the applied battery-savings META element in the document
+ // changed.
+ void BatterySavingsChanged(BatterySavingsFlags savings);
+
+ const viz::LocalSurfaceId& LocalSurfaceIdFromParent();
+
+ ScreenMetricsEmulator* DeviceEmulator();
+
+ // Calculates the selection bounds in the root frame. Returns bounds unchanged
+ // when there is no focused frame or no selection.
+ void CalculateSelectionBounds(gfx::Rect& anchor_in_root_frame,
+ gfx::Rect& focus_in_root_frame);
+
+ // Returns if auto resize mode is enabled.
+ bool AutoResizeMode();
+
+ void SetScreenMetricsEmulationParameters(
+ bool enabled,
+ const blink::DeviceEmulationParams& params);
+ void SetScreenInfoAndSize(const blink::ScreenInfo& screen_info,
+ const gfx::Size& widget_size,
+ const gfx::Size& visible_viewport_size);
+
+ // Update the surface allocation information, compositor viewport rect and
+ // screen info on the widget.
+ void UpdateSurfaceAndScreenInfo(
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Rect& compositor_viewport_pixel_rect,
+ const ScreenInfo& new_screen_info);
+ // Similar to UpdateSurfaceAndScreenInfo but the surface allocation
+ // and compositor viewport rect remains the same.
+ void UpdateScreenInfo(const ScreenInfo& screen_info);
+ void UpdateSurfaceAndCompositorRect(
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Rect& compositor_viewport_pixel_rect);
+ void UpdateCompositorViewportRect(
+ const gfx::Rect& compositor_viewport_pixel_rect);
+ void SetWindowSegments(const std::vector<gfx::Rect>& window_segments);
+ viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::PointF& point,
+ gfx::PointF* local_point);
+
+ // Set the pending window rect. For every SetPendingWindowRect
+ // call there must be an AckPendingWindowRect call.
+ void SetPendingWindowRect(const gfx::Rect& window_screen_rect);
+
+ // Clear a previously set pending window rect. For every SetPendingWindowRect
+ // call there must be an AckPendingWindowRect call.
+ void AckPendingWindowRect();
+
+ // Return the focused WebPlugin if there is one.
+ WebPlugin* GetFocusedPluginContainer();
+ // Return if there is a pending scale animation.
+ bool HasPendingPageScaleAnimation();
+
+ // Set the source URL for the compositor.
+ void SetSourceURLForCompositor(ukm::SourceId source_id, const KURL& url);
+
+ // Ask compositor to create the shared memory for smoothness ukm region.
+ base::ReadOnlySharedMemoryRegion CreateSharedMemoryForSmoothnessUkm();
+
+ protected:
// WidgetBaseClient overrides:
+ void ScheduleAnimation() override;
+ void DidBeginMainFrame() override;
+ std::unique_ptr<cc::LayerTreeFrameSink> AllocateNewLayerTreeFrameSink()
+ override;
+ const ScreenInfo& GetOriginalScreenInfo() override;
+
+ // Whether compositing to LCD text should be auto determined. This can be
+ // overridden by tests to disable this.
+ virtual bool ShouldAutoDetermineCompositingToLCDTextSetting();
+
+ // WebFrameWidget overrides.
+ cc::LayerTreeHost* LayerTreeHost() override;
+
+ bool doing_drag_and_drop_ = false;
+
+ private:
+ friend class WebViewImpl;
+ friend class ReportTimeSwapPromise;
+
+ // WidgetBaseClient overrides.
+ void BeginCommitCompositorFrame() override;
+ void EndCommitCompositorFrame(base::TimeTicks commit_start_time) override;
+ void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override;
+ void RecordDispatchRafAlignedInputTime(
+ base::TimeTicks raf_aligned_input_start_time) override;
+ void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override;
+ void RecordStartOfFrameMetrics() override;
+ void RecordEndOfFrameMetrics(
+ base::TimeTicks,
+ cc::ActiveFrameSequenceTrackers trackers) override;
+ std::unique_ptr<cc::BeginMainFrameMetrics> GetBeginMainFrameMetrics()
+ override;
+ std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() override;
+ void BeginUpdateLayers() override;
+ void EndUpdateLayers() override;
+ void DidCommitAndDrawCompositorFrame() override;
+ void DidObserveFirstScrollDelay(
+ base::TimeDelta first_scroll_delay,
+ base::TimeTicks first_scroll_timestamp) override;
+ void DidCompletePageScaleAnimation() override;
+ void FocusChangeComplete() override;
+ bool WillHandleGestureEvent(const WebGestureEvent& event) override;
+ void WillHandleMouseEvent(const WebMouseEvent& event) override;
+ void ObserveGestureEventAndResult(
+ const WebGestureEvent& gesture_event,
+ const gfx::Vector2dF& unused_delta,
+ const cc::OverscrollBehavior& overscroll_behavior,
+ bool event_processed) override;
+ bool SupportsBufferedTouchEvents() override { return true; }
+ void DidHandleKeyEvent() override;
+ WebTextInputType GetTextInputType() override;
+ void SetCursorVisibilityState(bool is_visible) override;
+ blink::FrameWidget* FrameWidget() override { return this; }
void FocusChanged(bool enable) override;
+ bool ShouldAckSyntheticInputImmediately() override;
+ void UpdateVisualProperties(
+ const VisualProperties& visual_properties) override;
+ bool UpdateScreenRects(const gfx::Rect& widget_screen_rect,
+ const gfx::Rect& window_screen_rect) override;
+ void OrientationChanged() override;
+ void DidUpdateSurfaceAndScreen(
+ const ScreenInfo& previous_original_screen_info) override;
gfx::Rect ViewportVisibleRect() override;
+ base::Optional<blink::mojom::ScreenOrientation> ScreenOrientationOverride()
+ override;
+ void WasHidden() override;
+ void WasShown(bool was_evicted) override;
+ void RunPaintBenchmark(int repeat_count,
+ cc::PaintBenchmarkResult& result) override;
+ KURL GetURLForDebugTrace() override;
+ float GetTestingDeviceScaleFactorOverride() override;
- // blink::mojom::FrameWidget
+ // mojom::blink::FrameWidget overrides.
+ void DragTargetDragEnter(const WebDragData&,
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragOperationsMask operations_allowed,
+ uint32_t key_modifiers,
+ DragTargetDragEnterCallback callback) override;
+ void DragTargetDragOver(const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragOperationsMask operations_allowed,
+ uint32_t key_modifiers,
+ DragTargetDragOverCallback callback) override;
+ void DragTargetDragLeave(const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point) override;
+ void DragTargetDrop(const WebDragData&,
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ uint32_t key_modifiers) override;
+ void DragSourceSystemDragEnded() override;
+ void SetBackgroundOpaque(bool opaque) override;
+ void SetActive(bool active) override;
+ // For both mainframe and childframe change the text direction of the
+ // currently selected input field (if any).
+ void SetTextDirection(base::i18n::TextDirection direction) override;
+ // Sets the inherited effective touch action on an out-of-process iframe.
+ void SetInheritedEffectiveTouchActionForSubFrame(
+ WebTouchAction touch_action) override;
+ // Toggles render throttling for an out-of-process iframe. Local frames are
+ // throttled based on their visibility in the viewport, but remote frames
+ // have to have throttling information propagated from parent to child
+ // across processes.
+ void UpdateRenderThrottlingStatusForSubFrame(bool is_throttled,
+ bool subtree_throttled,
+ bool display_locked) override;
void EnableDeviceEmulation(const DeviceEmulationParams& parameters) override;
void DisableDeviceEmulation() override;
+ // Sets the inert bit on an out-of-process iframe, causing it to ignore
+ // input.
+ void SetIsInertForSubFrame(bool inert) override;
+#if defined(OS_MAC)
+ void GetStringAtPoint(const gfx::Point& point_in_local_root,
+ GetStringAtPointCallback callback) override;
+#endif
- void UpdateMainFrameLayoutSize();
-
- private:
- friend class WebFrameWidget; // For WebFrameWidget::create.
-
- void UpdateLayerTreeViewport();
+ // mojom::blink::FrameWidgetInputHandler overrides.
+ void AddImeTextSpansToExistingText(
+ uint32_t start,
+ uint32_t end,
+ const Vector<ui::ImeTextSpan>& ime_text_spans) override;
+ void ClearImeTextSpansByType(uint32_t start,
+ uint32_t end,
+ ui::ImeTextSpan::Type type) override;
+ void SetCompositionFromExistingText(
+ int32_t start,
+ int32_t end,
+ const Vector<ui::ImeTextSpan>& ime_text_spans) override;
+ void ExtendSelectionAndDelete(int32_t before, int32_t after) override;
+ void DeleteSurroundingText(int32_t before, int32_t after) override;
+ void DeleteSurroundingTextInCodePoints(int32_t before,
+ int32_t after) override;
+ void SetEditableSelectionOffsets(int32_t start, int32_t end) override;
+ void ExecuteEditCommand(const String& command, const String& value) override;
+ void Undo() override;
+ void Redo() override;
+ void Cut() override;
+ void Copy() override;
+ void CopyToFindPboard() override;
+ void Paste() override;
+ void PasteAndMatchStyle() override;
+ void Delete() override;
+ void SelectAll() override;
+ void CollapseSelection() override;
+ void Replace(const String& word) override;
+ void ReplaceMisspelling(const String& word) override;
+ void SelectRange(const gfx::Point& base_in_dips,
+ const gfx::Point& extent_in_dips) override;
+ void AdjustSelectionByCharacterOffset(
+ int32_t start,
+ int32_t end,
+ mojom::blink::SelectionMenuBehavior behavior) override;
+ void MoveRangeSelectionExtent(const gfx::Point& extent_in_dips) override;
+ void ScrollFocusedEditableNodeIntoRect(
+ const gfx::Rect& rect_in_dips) override;
+ void MoveCaret(const gfx::Point& point_in_dips) override;
+#if defined(OS_ANDROID)
+ void SelectWordAroundCaret(SelectWordAroundCaretCallback callback) override;
+#endif
- // PageWidgetEventHandler functions
+ // PageWidgetEventHandler overrides:
+ WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
+ void HandleMouseDown(LocalFrame&, const WebMouseEvent&) override;
void HandleMouseLeave(LocalFrame&, const WebMouseEvent&) override;
+ WebInputEventResult HandleMouseUp(LocalFrame&, const WebMouseEvent&) override;
WebInputEventResult HandleGestureEvent(const WebGestureEvent&) override;
- WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
+ WebInputEventResult HandleMouseWheel(LocalFrame&,
+ const WebMouseWheelEvent&) override;
+ WebInputEventResult HandleCharEvent(const WebKeyboardEvent&) override;
- LocalFrameView* GetLocalFrameViewForAnimationScrolling() override;
+ WebInputEventResult HandleCapturedMouseEvent(const WebCoalescedInputEvent&);
+ void MouseContextMenu(const WebMouseEvent&);
+ void CancelDrag();
+ void PresentationCallbackForMeaningfulLayout(blink::WebSwapResult,
+ base::TimeTicks);
- LocalFrame* FocusedLocalFrameAvailableForIme() const;
+ void ForEachRemoteFrameControlledByWidget(
+ const base::RepeatingCallback<void(RemoteFrame*)>& callback);
+
+ void SetWindowRectSynchronously(const gfx::Rect& new_window_rect);
+
+ void SendOverscrollEventFromImplSide(const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id);
+ void SendScrollEndEventFromImplSide(cc::ElementId scroll_latched_element_id);
+
+ void RecordManipulationTypeCounts(cc::ManipulationInfo info);
// Finds the parameters required for scrolling the focused editable |element|
- // into view. |rect_to_scroll| is used for recursive scrolling of the element
- // into view and contains all or part of element's bounding box and always
- // includes the caret and is with respect to absolute coordinates.
- void GetScrollParamsForFocusedEditableElement(
- const Element& element,
- PhysicalRect& rect_to_scroll,
- mojom::blink::ScrollIntoViewParamsPtr& params);
+ // into view. |out_rect_to_scroll| is used for recursive scrolling of the
+ // element into view and contains all or part of element's bounding box and
+ // always includes the caret and is with respect to absolute coordinates.
+ mojom::blink::ScrollIntoViewParamsPtr
+ GetScrollParamsForFocusedEditableElement(const Element& element,
+ PhysicalRect& out_rect_to_scroll);
+
+ enum DragAction { kDragEnter, kDragOver };
+ // Consolidate some common code between starting a drag over a target and
+ // updating a drag over a target. If we're starting a drag, |isEntering|
+ // should be true.
+ ui::mojom::blink::DragOperation DragTargetDragEnterOrOver(
+ const gfx::PointF& point_in_viewport,
+ const gfx::PointF& screen_point,
+ DragAction,
+ uint32_t key_modifiers);
+
+ // Helper function to call VisualViewport::viewportToRootFrame().
+ gfx::PointF ViewportToRootFrame(const gfx::PointF& point_in_viewport) const;
+
+ WebViewImpl* View() const;
+
+ // Returns the page object associated with this widget. This may be null when
+ // the page is shutting down, but will be valid at all other times.
+ Page* GetPage() const;
+
+ mojom::blink::FrameWidgetHost* GetAssociatedFrameWidgetHost() const;
+
+ // Notifies RenderWidgetHostImpl that the frame widget has painted something.
+ void DidMeaningfulLayout(WebMeaningfulLayout layout_type);
+
+ // Enable or disable auto-resize. This is part of
+ // UpdateVisualProperties though tests may call to it more directly.
+ void SetAutoResizeMode(bool auto_resize,
+ const gfx::Size& min_size_before_dsf,
+ const gfx::Size& max_size_before_dsf,
+ float device_scale_factor);
+
+ void ApplyViewportIntersection(
+ mojom::blink::ViewportIntersectionStatePtr intersection_state);
+
+ // Called when a gesture event has been processed.
+ void DidHandleGestureEvent(const WebGestureEvent& event);
+
+ // Called to update if pointerrawupdate events should be sent.
+ void SetHasPointerRawUpdateEventHandlers(bool);
+
+ // Helper function to process events while pointer locked.
+ void PointerLockMouseEvent(const WebCoalescedInputEvent&);
+ bool IsPointerLocked();
+
+ // The fullscreen granted status from the most recent VisualProperties update.
+ bool IsFullscreenGranted();
+
+ // Set the compositing scale factor for this widget and notify remote frames
+ // to update their compositing scale factor.
+ void NotifyCompositingScaleFactorChanged(float compositing_scale_factor);
+
+ void NotifyPageScaleFactorChanged(float page_scale_factor,
+ bool is_pinch_gesture_active);
+ // Helper for notifying frame-level objects that care about input events.
+ // TODO: With some effort, this could be folded into a common implementation
+ // of WebViewImpl::HandleInputEvent and WebFrameWidgetImpl::HandleInputEvent.
+ void NotifyInputObservers(const WebCoalescedInputEvent& coalesced_event);
+
+ Frame* FocusedCoreFrame() const;
+
+ // Returns the currently focused `Element` in any `LocalFrame` owned by the
+ // associated `WebView`.
+ Element* FocusedElement() const;
+
+ // Perform a hit test for a point relative to the root frame of the page.
+ HitTestResult HitTestResultForRootFramePos(
+ const FloatPoint& pos_in_root_frame);
+
+ // Called during |UpdateVisualProperties| to apply the new size to the widget.
+ void ApplyVisualPropertiesSizing(const VisualProperties& visual_properties);
+
+ // Returns the current state of synchronous resize mode for testing.
+ bool SynchronousResizeModeForTestingEnabled();
+
+ // A copy of the web drop data object we received from the browser.
+ Member<DataObject> current_drag_data_;
+
+ // The available drag operations (copy, move link...) allowed by the source.
+ DragOperationsMask operations_allowed_ = kDragOperationNone;
+
+ // The current drag operation as negotiated by the source and destination.
+ // When not equal to DragOperationNone, the drag data can be dropped onto the
+ // current drop target in this WebView (the drop target can accept the drop).
+ ui::mojom::blink::DragOperation drag_operation_ =
+ ui::mojom::blink::DragOperation::kNone;
+
+ // This field stores drag/drop related info for the event that is currently
+ // being handled. If the current event results in starting a drag/drop
+ // session, this info is sent to the browser along with other drag/drop info.
+ mojom::blink::DragEventSourceInfo possible_drag_event_info_;
+
+ // Base functionality all widgets have. This is a member as to avoid
+ // complicated inheritance structures.
+ std::unique_ptr<WidgetBase> widget_base_;
+
+ // Compositing scale factor for all frames attached to this widget sent from
+ // the remote parent frame.
+ float compositing_scale_factor_ = 1.f;
+
+ // The last seen page scale state, which comes from the main frame if we're
+ // in a child frame. This state is propagated through the RenderWidget tree
+ // passed to any new child RenderWidget.
+ float page_scale_factor_in_mainframe_ = 1.f;
+ bool is_pinch_gesture_active_in_mainframe_ = false;
+
+ // If set, the (plugin) element which has mouse capture.
+ Member<HTMLPlugInElement> mouse_capture_element_;
+
+ // The size of the widget in viewport coordinates. This is slightly different
+ // than the WebViewImpl::size_ since isn't set in auto resize mode.
base::Optional<gfx::Size> size_;
- // Metrics gathering timing information
+ static bool ignore_input_events_;
+
+ const viz::FrameSinkId frame_sink_id_;
+
+ // WebFrameWidget is associated with a subtree of the frame tree,
+ // corresponding to a maximal connected tree of LocalFrames. This member
+ // points to the root of that subtree.
+ Member<WebLocalFrameImpl> local_root_;
+
+ mojom::blink::DisplayMode display_mode_;
+
+ WebVector<gfx::Rect> window_segments_;
+
+ // This is owned by the LayerTreeHostImpl, and should only be used on the
+ // compositor thread, so we keep the TaskRunner where you post tasks to
+ // make that happen.
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher_;
+ scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner_;
+
+ // The |paint_dispatcher_| should only be dereferenced on the
+ // |paint_task_runner_| (in practice this is the compositor thread). We keep a
+ // copy of it here to provide to new PaintWorkletProxyClient objects (which
+ // run on the worklet thread) so that they can talk to the
+ // PaintWorkletPaintDispatcher on the compositor thread.
+ base::WeakPtr<PaintWorkletPaintDispatcher> paint_dispatcher_;
+ scoped_refptr<base::SingleThreadTaskRunner> paint_task_runner_;
+
+ // WebFrameWidgetImpl is not tied to ExecutionContext
+ HeapMojoAssociatedRemote<mojom::blink::FrameWidgetHost,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ frame_widget_host_{nullptr};
+ // WebFrameWidgetImpl is not tied to ExecutionContext
+ HeapMojoAssociatedReceiver<mojom::blink::FrameWidget,
+ WebFrameWidgetImpl,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ receiver_{this, nullptr};
+ HeapMojoReceiver<viz::mojom::blink::InputTargetClient,
+ WebFrameWidgetImpl,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ input_target_receiver_{this, nullptr};
+
+ // Different consumers in the browser process makes different assumptions, so
+ // must always send the first IPC regardless of value.
+ base::Optional<bool> has_touch_handlers_;
+
+ Vector<mojom::blink::EditCommandPtr> edit_commands_;
+
+ base::Optional<gfx::Point> host_context_menu_location_;
+ uint32_t last_capture_sequence_number_ = 0u;
+
+ // Indicates whether tab-initiated fullscreen was granted.
+ bool is_fullscreen_granted_ = false;
+
+ // Indicates whether we need to consume scroll gestures to move cursor.
+ bool swipe_to_move_cursor_activated_ = false;
+
+ // Set when a measurement begins, reset when the measurement is taken.
base::Optional<base::TimeTicks> update_layers_start_time_;
- bool did_suspend_parsing_ = false;
+ // Metrics for gathering time for commit of compositor frame.
+ base::Optional<base::TimeTicks> commit_compositor_frame_start_time_;
+
+ // Present when emulation is enabled, only on a main frame's WebFrameWidget.
+ // Used to override values given from the browser such as ScreenInfo,
+ // WidgetScreenRect, WindowScreenRect, and the widget's size.
+ Member<ScreenMetricsEmulator> device_emulator_;
+
+ // keyPress events to be suppressed if the associated keyDown event was
+ // handled.
+ bool suppress_next_keypress_event_ = false;
+
+ // Whether drag and drop is supported by this widget. When disabled
+ // any drag operation that is started will be canceled immediately.
+ bool drag_and_drop_disabled_ = false;
+
+ // A callback client for non-composited frame widgets.
+ WebNonCompositedWidgetClient* non_composited_client_ = nullptr;
+
+ // This struct contains data that is only valid for child local root widgets.
+ // You should use `child_data()` to access it.
+ struct ChildLocalRootData {
+ gfx::Rect compositor_visible_rect;
+ bool did_suspend_parsing = false;
+ } child_local_root_data_;
+
+ ChildLocalRootData& child_data() {
+ DCHECK(ForSubframe());
+ return child_local_root_data_;
+ }
+
+ // Web tests override the zoom factor in the renderer with this. We store it
+ // to keep the override if the browser passes along VisualProperties with the
+ // real device scale factor. A value of -INFINITY means this is ignored.
+ // It is always valid to read this variable but it can only be set for main
+ // frame widgets.
+ double zoom_level_for_testing_ = -INFINITY;
+
+ // Web tests override the device scale factor in the renderer with this. We
+ // store it to keep the override if the browser passes along VisualProperties
+ // with the real device scale factor. A value of 0.f means this is ignored.
+ // It is always valid to read this variable but it can only be set for main
+ // frame widgets.
+ float device_scale_factor_for_testing_ = 0;
+
+ // This struct contains data that is only valid for main frame widgets.
+ // You should use `main_data()` to access it.
+ struct MainFrameData {
+ // `UpdateLifecycle()` generates `WebMeaningfulLayout` events these
+ // variables track what events should be generated. They are only applicable
+ // for main frame widgets.
+ bool should_dispatch_first_visually_non_empty_layout = false;
+ bool should_dispatch_first_layout_after_finished_parsing = false;
+ bool should_dispatch_first_layout_after_finished_loading = false;
+ // Last background color sent to the browser. Only set for main frames.
+ base::Optional<SkColor> last_background_color;
+ // This bit is used to tell if this is a nested widget (an "inner web
+ // contents") like a <webview> or <portal> widget. If false, the widget is
+ // the top level widget.
+ bool is_for_nested_main_frame = false;
+
+ // In web tests, synchronous resizing mode may be used. Normally each
+ // widget's size is controlled by IPC from the browser. In synchronous
+ // resize mode the renderer controls the size directly, and IPCs from the
+ // browser must be ignored. This was deprecated but then later undeprecated,
+ // so it is now called unfortunate instead. See https://crbug.com/309760.
+ // When this is enabled the various size properties will be controlled
+ // directly when SetWindowRect() is called instead of needing a round trip
+ // through the browser. Note that SetWindowRectSynchronouslyForTesting()
+ // provides a secondary way to control the size of the FrameWidget
+ // independently from the renderer process, without the use of this mode,
+ // however it would be overridden by the browser if they disagree.
+ bool synchronous_resize_mode_for_testing = false;
+
+ } main_frame_data_;
+
+ MainFrameData& main_data() {
+ DCHECK(ForMainFrame());
+ return main_frame_data_;
+ }
+
+ const MainFrameData& main_data() const {
+ DCHECK(ForMainFrame());
+ return main_frame_data_;
+ }
- // TODO(ekaramad): Can we remove this and make sure IME events are not called
- // when there is no page focus?
- // Represents whether or not this object should process incoming IME events.
- bool ime_accept_events_ = true;
+ // Whether this widget is for a child local root, or otherwise a main frame.
+ const bool is_for_child_local_root_;
- gfx::Rect compositor_visible_rect_;
+ // This stores the last hidden page popup. If a GestureTap attempts to open
+ // the popup that is closed by its previous GestureTapDown, the popup remains
+ // closed.
+ scoped_refptr<WebPagePopupImpl> last_hidden_page_popup_;
- SelfKeepAlive<WebFrameWidgetImpl> self_keep_alive_;
+ base::WeakPtrFactory<mojom::blink::FrameWidgetInputHandler>
+ input_handler_weak_ptr_factory_{this};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_test.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
index 45e219f3605..54011858db9 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
@@ -2,19 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "cc/layers/solid_color_layer.h"
+#include "cc/test/property_tree_test_utils.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
#include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -52,7 +53,7 @@ class TouchMoveEventListener final : public NativeEventListener {
class WebFrameWidgetSimTest : public SimTest {};
// Tests that if a WebView is auto-resized, the associated
-// WebViewFrameWidget requests a new viz::LocalSurfaceId to be allocated on the
+// WebFrameWidgetImpl requests a new viz::LocalSurfaceId to be allocated on the
// impl thread.
TEST_F(WebFrameWidgetSimTest, AutoResizeAllocatedLocalSurfaceId) {
viz::ParentLocalSurfaceIdAllocator allocator;
@@ -74,17 +75,16 @@ TEST_F(WebFrameWidgetSimTest, AutoResizeAllocatedLocalSurfaceId) {
WebView().MainFrameViewWidget()->LocalSurfaceIdFromParent());
EXPECT_FALSE(WebView()
.MainFrameViewWidget()
- ->LayerTreeHost()
+ ->LayerTreeHostForTesting()
->new_local_surface_id_request_for_testing());
constexpr gfx::Size size(200, 200);
- static_cast<WebViewFrameWidget*>(WebView().MainFrameViewWidget())
- ->DidAutoResize(size);
+ WebView().MainFrameViewWidget()->DidAutoResize(size);
EXPECT_EQ(allocator.GetCurrentLocalSurfaceId(),
WebView().MainFrameViewWidget()->LocalSurfaceIdFromParent());
EXPECT_TRUE(WebView()
.MainFrameViewWidget()
- ->LayerTreeHost()
+ ->LayerTreeHostForTesting()
->new_local_surface_id_request_for_testing());
}
@@ -129,7 +129,7 @@ TEST_F(WebFrameWidgetSimTest, FrameSinkIdHitTestAPI) {
#if defined(OS_ANDROID)
TEST_F(WebFrameWidgetSimTest, ForceSendMetadataOnInput) {
cc::LayerTreeHost* layer_tree_host =
- WebView().MainFrameViewWidget()->LayerTreeHost();
+ WebView().MainFrameViewWidget()->LayerTreeHostForTesting();
// We should not have any force send metadata requests at start.
EXPECT_FALSE(layer_tree_host->TakeForceSendMetadataRequest());
// ShowVirtualKeyboard will trigger a text input state update.
@@ -139,14 +139,13 @@ TEST_F(WebFrameWidgetSimTest, ForceSendMetadataOnInput) {
}
#endif // defined(OS_ANDROID)
-// A test that forces a RemoteMainFrame to be created and the LocalFrameRoot
-// to be a WebFrameWidgetImpl.
-class WebFrameWidgetImplSimTest : public SimTest {
+// A test that forces a RemoteMainFrame to be created.
+class WebFrameWidgetImplRemoteFrameSimTest : public SimTest {
public:
void SetUp() override {
SimTest::SetUp();
InitializeRemote();
- CHECK(static_cast<WebFrameWidgetBase*>(LocalFrameRoot().FrameWidget())
+ CHECK(static_cast<WebFrameWidgetImpl*>(LocalFrameRoot().FrameWidget())
->ForSubframe());
}
@@ -158,9 +157,10 @@ class WebFrameWidgetImplSimTest : public SimTest {
// Tests that the value of VisualProperties::is_pinch_gesture_active is
// propagated to the LayerTreeHost when properties are synced for child local
// roots.
-TEST_F(WebFrameWidgetImplSimTest,
+TEST_F(WebFrameWidgetImplRemoteFrameSimTest,
ActivePinchGestureUpdatesLayerTreeHostSubFrame) {
- cc::LayerTreeHost* layer_tree_host = LocalFrameRootWidget()->LayerTreeHost();
+ cc::LayerTreeHost* layer_tree_host =
+ LocalFrameRootWidget()->LayerTreeHostForTesting();
EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
blink::VisualProperties visual_properties;
@@ -223,11 +223,11 @@ class MockHandledEventCallback {
DISALLOW_COPY_AND_ASSIGN(MockHandledEventCallback);
};
-class MockWebViewFrameWidget : public WebViewFrameWidget {
+class MockWebFrameWidgetImpl : public SimWebFrameWidget {
public:
template <typename... Args>
- explicit MockWebViewFrameWidget(Args&&... args)
- : WebViewFrameWidget(std::forward<Args>(args)...) {}
+ explicit MockWebFrameWidgetImpl(Args&&... args)
+ : SimWebFrameWidget(std::forward<Args>(args)...) {}
MOCK_METHOD1(HandleInputEvent,
WebInputEventResult(const WebCoalescedInputEvent&));
@@ -240,40 +240,39 @@ class MockWebViewFrameWidget : public WebViewFrameWidget {
bool event_processed));
MOCK_METHOD1(WillHandleGestureEvent, bool(const WebGestureEvent& event));
-};
-WebViewFrameWidget* CreateWebViewFrameWidget(
- util::PassKey<WebFrameWidget> pass_key,
- WebWidgetClient& client,
- WebViewImpl& web_view_impl,
- CrossVariantMojoAssociatedRemote<mojom::FrameWidgetHostInterfaceBase>
- frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::WidgetInterfaceBase> widget,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool is_for_nested_main_frame,
- bool hidden,
- bool never_composited) {
- return MakeGarbageCollected<MockWebViewFrameWidget>(
- pass_key, client, web_view_impl, std::move(frame_widget_host),
- std::move(frame_widget), std::move(widget_host), std::move(widget),
- std::move(task_runner), frame_sink_id, is_for_nested_main_frame, hidden,
- never_composited);
-}
+ // mojom::blink::WidgetHost overrides:
+ using SimWebFrameWidget::SetCursor;
+};
-class WebViewFrameWidgetSimTest : public SimTest {
+class WebFrameWidgetImplSimTest : public SimTest {
public:
- void SetUp() override {
- InstallCreateWebViewFrameWidgetHook(CreateWebViewFrameWidget);
- SimTest::SetUp();
+ SimWebFrameWidget* CreateSimWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ SimCompositor* compositor) override {
+ return MakeGarbageCollected<MockWebFrameWidgetImpl>(
+ compositor, pass_key, std::move(frame_widget_host),
+ std::move(frame_widget), std::move(widget_host), std::move(widget),
+ std::move(task_runner), frame_sink_id, hidden, never_composited,
+ is_for_child_local_root, is_for_nested_main_frame);
}
- MockWebViewFrameWidget* MockMainFrameWidget() {
- return static_cast<MockWebViewFrameWidget*>(MainFrame().FrameWidget());
+ MockWebFrameWidgetImpl* MockMainFrameWidget() {
+ return static_cast<MockWebFrameWidgetImpl*>(MainFrame().FrameWidget());
}
void SendInputEvent(const WebInputEvent& event,
@@ -305,16 +304,19 @@ class WebViewFrameWidgetSimTest : public SimTest {
base::HistogramTester histogram_tester_;
};
-TEST_F(WebViewFrameWidgetSimTest, CursorChange) {
+TEST_F(WebFrameWidgetImplSimTest, CursorChange) {
ui::Cursor cursor;
+ frame_test_helpers::TestWebFrameWidgetHost& widget_host =
+ MockMainFrameWidget()->WidgetHost();
+
MockMainFrameWidget()->SetCursor(cursor);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(WebWidgetClient().CursorSetCount(), 1u);
+ EXPECT_EQ(widget_host.CursorSetCount(), 1u);
MockMainFrameWidget()->SetCursor(cursor);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(WebWidgetClient().CursorSetCount(), 1u);
+ EXPECT_EQ(widget_host.CursorSetCount(), 1u);
EXPECT_CALL(*MockMainFrameWidget(), HandleInputEvent(_))
.WillOnce(::testing::Return(WebInputEventResult::kNotHandled));
@@ -322,17 +324,17 @@ TEST_F(WebViewFrameWidgetSimTest, CursorChange) {
SyntheticWebMouseEventBuilder::Build(WebInputEvent::Type::kMouseLeave),
base::DoNothing());
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(WebWidgetClient().CursorSetCount(), 1u);
+ EXPECT_EQ(widget_host.CursorSetCount(), 1u);
MockMainFrameWidget()->SetCursor(cursor);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(WebWidgetClient().CursorSetCount(), 2u);
+ EXPECT_EQ(widget_host.CursorSetCount(), 2u);
}
-TEST_F(WebViewFrameWidgetSimTest, EventOverscroll) {
+TEST_F(WebFrameWidgetImplSimTest, EventOverscroll) {
ON_CALL(*MockMainFrameWidget(), WillHandleGestureEvent(_))
.WillByDefault(testing::Invoke(
- this, &WebViewFrameWidgetSimTest::OverscrollGestureEvent));
+ this, &WebFrameWidgetImplSimTest::OverscrollGestureEvent));
EXPECT_CALL(*MockMainFrameWidget(), HandleInputEvent(_))
.WillRepeatedly(::testing::Return(WebInputEventResult::kNotHandled));
@@ -356,7 +358,7 @@ TEST_F(WebViewFrameWidgetSimTest, EventOverscroll) {
SendInputEvent(scroll, handled_event.GetCallback());
}
-TEST_F(WebViewFrameWidgetSimTest, RenderWidgetInputEventUmaMetrics) {
+TEST_F(WebFrameWidgetImplSimTest, RenderWidgetInputEventUmaMetrics) {
SyntheticWebTouchEvent touch;
touch.PressPoint(10, 10);
touch.touch_start_or_first_touch_move = true;
@@ -421,7 +423,7 @@ TEST_F(WebViewFrameWidgetSimTest, RenderWidgetInputEventUmaMetrics) {
// Ensures that the compositor thread gets sent the gesture event & overscroll
// amount for an overscroll initiated by a touchpad.
-TEST_F(WebViewFrameWidgetSimTest, SendElasticOverscrollForTouchpad) {
+TEST_F(WebFrameWidgetImplSimTest, SendElasticOverscrollForTouchpad) {
WebGestureEvent scroll(WebInputEvent::Type::kGestureScrollUpdate,
WebInputEvent::kNoModifiers, base::TimeTicks::Now(),
WebGestureDevice::kTouchpad);
@@ -441,7 +443,7 @@ TEST_F(WebViewFrameWidgetSimTest, SendElasticOverscrollForTouchpad) {
// Ensures that the compositor thread gets sent the gesture event & overscroll
// amount for an overscroll initiated by a touchscreen.
-TEST_F(WebViewFrameWidgetSimTest, SendElasticOverscrollForTouchscreen) {
+TEST_F(WebFrameWidgetImplSimTest, SendElasticOverscrollForTouchscreen) {
WebGestureEvent scroll(WebInputEvent::Type::kGestureScrollUpdate,
WebInputEvent::kNoModifiers, base::TimeTicks::Now(),
WebGestureDevice::kTouchscreen);
@@ -467,19 +469,17 @@ class NotifySwapTimesWebFrameWidgetTest : public SimTest {
WebView().StopDeferringMainFrameUpdate();
FrameWidgetBase()->UpdateCompositorViewportRect(gfx::Rect(200, 100));
- auto root_layer = cc::SolidColorLayer::Create();
- root_layer->SetBounds(gfx::Size(200, 100));
- root_layer->SetBackgroundColor(SK_ColorGREEN);
- FrameWidgetBase()->LayerTreeHost()->SetRootLayer(root_layer);
-
+ auto* root_layer =
+ FrameWidgetBase()->LayerTreeHostForTesting()->root_layer();
auto color_layer = cc::SolidColorLayer::Create();
color_layer->SetBounds(gfx::Size(100, 100));
- root_layer->AddChild(color_layer);
+ cc::CopyProperties(root_layer, color_layer.get());
+ root_layer->SetChildLayerList(cc::LayerList({color_layer}));
color_layer->SetBackgroundColor(SK_ColorRED);
}
- WebViewFrameWidget* FrameWidgetBase() {
- return static_cast<WebViewFrameWidget*>(MainFrame().FrameWidget());
+ WebFrameWidgetImpl* FrameWidgetBase() {
+ return static_cast<WebFrameWidgetImpl*>(MainFrame().FrameWidget());
}
// |swap_to_presentation| determines how long after swap should presentation
@@ -489,7 +489,7 @@ class NotifySwapTimesWebFrameWidgetTest : public SimTest {
base::RunLoop swap_run_loop;
base::RunLoop presentation_run_loop;
- // Register callbacks for swap time and presentation time.
+ // Register callbacks for presentation time.
base::TimeTicks swap_time;
MainFrame().FrameWidget()->NotifySwapAndPresentationTime(
base::BindOnce(
@@ -519,7 +519,7 @@ class NotifySwapTimesWebFrameWidgetTest : public SimTest {
/*presentation_time=*/swap_time + swap_to_presentation,
base::TimeDelta::FromMilliseconds(16), 0);
}
- auto* last_frame_sink = WebWidgetClient().LastCreatedFrameSink();
+ auto* last_frame_sink = GetWebFrameWidget().LastCreatedFrameSink();
last_frame_sink->NotifyDidPresentCompositorFrame(1, timing_details);
presentation_run_loop.Run();
}
@@ -572,7 +572,8 @@ TEST_F(NotifySwapTimesWebFrameWidgetTest,
// not propagated to the LayerTreeHost when properties are synced for main
// frame.
TEST_F(WebFrameWidgetSimTest, ActivePinchGestureUpdatesLayerTreeHost) {
- auto* layer_tree_host = WebView().MainFrameViewWidget()->LayerTreeHost();
+ auto* layer_tree_host =
+ WebView().MainFrameViewWidget()->LayerTreeHostForTesting();
EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
blink::VisualProperties visual_properties;
@@ -615,13 +616,13 @@ TEST_F(WebFrameWidgetSimTest, DispatchBufferedTouchEvents) {
// Expect listener does not get called, due to devtools flag.
touch.MovePoint(0, 12, 12);
- WebFrameWidgetBase::SetIgnoreInputEvents(true);
+ WebFrameWidgetImpl::SetIgnoreInputEvents(true);
widget->ProcessInputEventSynchronouslyForTesting(
WebCoalescedInputEvent(touch.Clone(), {}, {}, ui::LatencyInfo()),
base::DoNothing());
- EXPECT_TRUE(WebFrameWidgetBase::IgnoreInputEvents());
+ EXPECT_TRUE(WebFrameWidgetImpl::IgnoreInputEvents());
EXPECT_FALSE(listener->GetInvokedStateAndReset());
- WebFrameWidgetBase::SetIgnoreInputEvents(false);
+ WebFrameWidgetImpl::SetIgnoreInputEvents(false);
// Expect listener does not get called, due to drag.
touch.MovePoint(0, 14, 14);
@@ -631,7 +632,7 @@ TEST_F(WebFrameWidgetSimTest, DispatchBufferedTouchEvents) {
WebCoalescedInputEvent(touch.Clone(), {}, {}, ui::LatencyInfo()),
base::DoNothing());
EXPECT_TRUE(widget->DoingDragAndDrop());
- EXPECT_FALSE(WebFrameWidgetBase::IgnoreInputEvents());
+ EXPECT_FALSE(WebFrameWidgetImpl::IgnoreInputEvents());
EXPECT_FALSE(listener->GetInvokedStateAndReset());
}
@@ -648,28 +649,21 @@ TEST_F(WebFrameWidgetSimTest, PropagateScaleToRemoteFrames) {
)HTML");
base::RunLoop().RunUntilIdle();
- class PageScaleRemoteFrameClient
- : public frame_test_helpers::TestWebRemoteFrameClient {
- public:
- void PageScaleFactorChanged(float page_scale_factor,
- bool is_pinch_gesture_active) override {
- page_scale_factor_changed_ = true;
- }
- bool page_scale_factor_changed_ = false;
- };
-
- PageScaleRemoteFrameClient page_scale_remote_frame_client;
EXPECT_TRUE(WebView().MainFrame()->FirstChild());
{
WebFrame* grandchild = WebView().MainFrame()->FirstChild()->FirstChild();
EXPECT_TRUE(grandchild);
EXPECT_TRUE(grandchild->IsWebLocalFrame());
- grandchild->Swap(
- frame_test_helpers::CreateRemote(&page_scale_remote_frame_client));
+ grandchild->Swap(frame_test_helpers::CreateRemote());
}
auto* widget = WebView().MainFrameViewWidget();
widget->SetPageScaleStateAndLimits(1.3f, true, 1.0f, 3.0f);
- EXPECT_TRUE(page_scale_remote_frame_client.page_scale_factor_changed_);
+ EXPECT_EQ(
+ To<WebRemoteFrameImpl>(WebView().MainFrame()->FirstChild()->FirstChild())
+ ->GetFrame()
+ ->GetPendingVisualPropertiesForTesting()
+ .page_scale_factor,
+ 1.3f);
WebView().MainFrame()->FirstChild()->FirstChild()->Detach();
}
diff --git a/chromium/third_party/blink/renderer/core/frame/web_local_frame_client_test.cc b/chromium/third_party/blink/renderer/core/frame/web_local_frame_client_test.cc
index c690871b7f1..8c2a6569236 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_local_frame_client_test.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_local_frame_client_test.cc
@@ -32,17 +32,15 @@ class CallTrackingTestWebLocalFrameClient
}
void DidCommitNavigation(
- const WebHistoryItem& item,
- WebHistoryCommitType type,
- bool should_reset_browser_interface_broker) override {
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const ParsedFeaturePolicy& feature_policy_header,
+ const DocumentPolicyFeatureState& document_policy_header) override {
calls_.push_back("DidCommitNavigation");
TestWebFrameClient::DidCommitNavigation(
- item, type, should_reset_browser_interface_broker);
- }
-
- void DidCreateInitialEmptyDocument() override {
- calls_.push_back("DidCreateInitialEmptyDocument");
- TestWebFrameClient::DidCreateInitialEmptyDocument();
+ commit_type, should_reset_browser_interface_broker, sandbox_flags,
+ feature_policy_header, document_policy_header);
}
void DidCreateDocumentElement() override {
@@ -95,7 +93,6 @@ TEST(WebLocalFrameClientTest, Basic) {
web_view_helper.Initialize(&client);
EXPECT_THAT(client.TakeCalls(),
testing::ElementsAre("DidCreateDocumentLoader",
- "DidCreateInitialEmptyDocument",
"DidCreateDocumentElement",
"RunScriptsAtDocumentElementAvailable"));
diff --git a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 74d3cfff265..b8fa00c7abd 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -97,6 +97,8 @@
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
+#include "third_party/blink/public/common/context_menu_data/context_menu_params_builder.h"
+#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
@@ -106,7 +108,6 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_double_size.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_url_error.h"
@@ -120,6 +121,7 @@
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
+#include "third_party/blink/public/web/web_history_entry.h"
#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
@@ -189,7 +191,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/smart_clip.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
@@ -309,11 +311,13 @@ class ChromePrintContext : public PrintContext {
// The page rect gets scaled and translated, so specify the entire
// print content area here as the recording rect.
FloatRect bounds(0, 0, printed_page_height_, printed_page_width_);
- PaintRecordBuilder builder(canvas->GetPrintingMetafile());
- builder.Context().SetPrinting(true);
- builder.Context().BeginRecording(bounds);
- float scale = SpoolPage(builder.Context(), page_number);
- canvas->drawPicture(builder.Context().EndRecording());
+ PaintRecordBuilder builder;
+ GraphicsContext& context = builder.Context();
+ context.SetPrintingMetafile(canvas->GetPrintingMetafile());
+ context.SetPrinting(true);
+ context.BeginRecording(bounds);
+ float scale = SpoolPage(context, page_number);
+ canvas->drawPicture(context.EndRecording());
return scale;
}
@@ -336,8 +340,9 @@ class ChromePrintContext : public PrintContext {
FloatRect all_pages_rect(0, 0, spool_size_in_pixels.Width(),
spool_size_in_pixels.Height());
- PaintRecordBuilder builder(canvas->GetPrintingMetafile());
+ PaintRecordBuilder builder;
GraphicsContext& context = builder.Context();
+ context.SetPrintingMetafile(canvas->GetPrintingMetafile());
context.SetPrinting(true);
context.BeginRecording(all_pages_rect);
@@ -419,13 +424,11 @@ class ChromePrintContext : public PrintContext {
auto property_tree_state =
frame_view->GetLayoutView()->FirstFragment().LocalBorderBoxProperties();
- PaintRecordBuilder builder(context.Canvas()->GetPrintingMetafile(),
- &context);
-
+ PaintRecordBuilder builder(context);
frame_view->PaintContentsOutsideOfLifecycle(
builder.Context(),
kGlobalPaintNormalPhase | kGlobalPaintFlattenCompositingLayers |
- kGlobalPaintPrinting | kGlobalPaintAddUrlMetadata,
+ kGlobalPaintAddUrlMetadata,
CullRect(page_rect));
{
ScopedPaintChunkProperties scoped_paint_chunk_properties(
@@ -507,7 +510,7 @@ class ChromePluginPrintContext final : public ChromePrintContext {
// NativeTheme doesn't play well with scaling. Scaling is done browser side
// instead. Returns the scale to be applied.
float SpoolPage(GraphicsContext& context, int page_number) override {
- PaintRecordBuilder builder(context.Canvas()->GetPrintingMetafile());
+ PaintRecordBuilder builder(context);
plugin_->PrintPage(page_number, builder.Context());
context.DrawRecord(builder.EndRecording());
@@ -542,9 +545,8 @@ class PaintPreviewContext : public PrintContext {
!GetFrame()->GetDocument()->GetLayoutView())
return false;
FloatRect bounds(0, 0, size.Width(), size.Height());
- PaintRecordBuilder builder(nullptr, nullptr, nullptr,
- canvas->GetPaintPreviewTracker());
- builder.Context().SetIsPaintingPreview(true);
+ PaintRecordBuilder builder;
+ builder.Context().SetPaintPreviewTracker(canvas->GetPaintPreviewTracker());
LocalFrameView* frame_view = GetFrame()->View();
DCHECK(frame_view);
@@ -584,20 +586,44 @@ static WebDocumentLoader* DocumentLoaderForDocLoader(DocumentLoader* loader) {
// WebFrame -------------------------------------------------------------------
-int WebFrame::InstanceCount() {
- return g_frame_count;
+static CreateWebFrameWidgetCallback* g_create_web_frame_widget = nullptr;
+
+void InstallCreateWebFrameWidgetHook(
+ CreateWebFrameWidgetCallback* create_widget) {
+ // This DCHECK's aims to avoid unexpected replacement of the hook.
+ DCHECK(!g_create_web_frame_widget || !create_widget);
+ g_create_web_frame_widget = create_widget;
+}
+
+WebFrameWidget* WebLocalFrame::InitializeFrameWidget(
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ mojo_frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ mojo_frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ mojo_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ mojo_widget,
+ const viz::FrameSinkId& frame_sink_id,
+ bool is_for_nested_main_frame,
+ bool hidden,
+ bool never_composited) {
+ CreateFrameWidgetInternal(
+ base::PassKey<WebLocalFrame>(), std::move(mojo_frame_widget_host),
+ std::move(mojo_frame_widget), std::move(mojo_widget_host),
+ std::move(mojo_widget), frame_sink_id, is_for_nested_main_frame, hidden,
+ never_composited);
+ return FrameWidget();
}
-// static
-WebFrame* WebFrame::FromFrameToken(const base::UnguessableToken& frame_token) {
- auto* frame = Frame::ResolveFrame(frame_token);
- return WebFrame::FromFrame(frame);
+int WebFrame::InstanceCount() {
+ return g_frame_count;
}
// static
WebFrame* WebFrame::FromFrameToken(const FrameToken& frame_token) {
auto* frame = Frame::ResolveFrame(frame_token);
- return WebFrame::FromFrame(frame);
+ return WebFrame::FromCoreFrame(frame);
}
WebLocalFrame* WebLocalFrame::FrameForCurrentContext() {
@@ -675,6 +701,11 @@ WebRemoteFrame* WebLocalFrameImpl::ToWebRemoteFrame() {
void WebLocalFrameImpl::Close() {
WebLocalFrame::Close();
+ if (frame_widget_) {
+ frame_widget_->Close();
+ frame_widget_ = nullptr;
+ }
+
client_ = nullptr;
if (dev_tools_agent_)
@@ -706,6 +737,10 @@ void WebLocalFrameImpl::SetName(const WebString& name) {
GetFrame()->Tree().SetName(name, FrameTree::kReplicate);
}
+WebContentSettingsClient* WebLocalFrameImpl::GetContentSettingsClient() const {
+ return content_settings_client_;
+}
+
void WebLocalFrameImpl::SetContentSettingsClient(
WebContentSettingsClient* client) {
content_settings_client_ = client;
@@ -722,7 +757,7 @@ bool WebLocalFrameImpl::IsFocused() const {
return false;
return this ==
- WebFrame::FromFrame(
+ WebFrame::FromCoreFrame(
ViewImpl()->GetPage()->GetFocusController().FocusedFrame());
}
@@ -781,10 +816,10 @@ bool WebLocalFrameImpl::HasVisibleContent() const {
return false;
}
-WebRect WebLocalFrameImpl::VisibleContentRect() const {
+gfx::Rect WebLocalFrameImpl::VisibleContentRect() const {
if (LocalFrameView* view = GetFrameView())
return view->LayoutViewport()->VisibleContentRect();
- return WebRect();
+ return gfx::Rect();
}
WebView* WebLocalFrameImpl::View() const {
@@ -815,6 +850,11 @@ void WebLocalFrameImpl::SetIsAdSubframe(
GetFrame()->SetIsAdSubframe(ad_frame_type);
}
+bool WebLocalFrameImpl::IsSubframeCreatedByAdScript() {
+ DCHECK(GetFrame());
+ return GetFrame()->IsSubframeCreatedByAdScript();
+}
+
void WebLocalFrameImpl::ExecuteScript(const WebScriptSource& source) {
DCHECK(GetFrame());
ClassicScript::CreateUnspecifiedScript(source)->RunScript(
@@ -1032,20 +1072,19 @@ void WebLocalFrameImpl::ReloadImage(const WebNode& web_node) {
image_element->ForceReload();
}
-void WebLocalFrameImpl::StartNavigation(const WebURLRequest& request) {
- // TODO(clamy): Remove this function once RenderFrame calls CommitNavigation
- // for all requests.
+void WebLocalFrameImpl::ResetForTesting() {
DCHECK(GetFrame());
- DCHECK(!request.IsNull());
- DCHECK(!request.Url().ProtocolIs("javascript"));
- TRACE_EVENT0("navigation", "WebLocalFrameImpl::StartNavigation");
-
if (GetTextFinder())
GetTextFinder()->ClearActiveFindMatch();
-
- FrameLoadRequest frame_load_request(nullptr, request.ToResourceRequest());
- GetFrame()->Loader().StartNavigation(frame_load_request,
- WebFrameLoadType::kStandard);
+ ResourceRequest resource_request(url::kAboutBlankURL);
+ resource_request.SetMode(network::mojom::RequestMode::kNavigate);
+ resource_request.SetRedirectMode(network::mojom::RedirectMode::kManual);
+ resource_request.SetRequestContext(
+ mojom::blink::RequestContextType::INTERNAL);
+ resource_request.SetRequestorOrigin(
+ blink::WebSecurityOrigin::CreateUniqueOpaque());
+ FrameLoadRequest request(nullptr, resource_request);
+ GetFrame()->Loader().StartNavigation(request, WebFrameLoadType::kStandard);
}
WebDocumentLoader* WebLocalFrameImpl::GetDocumentLoader() const {
@@ -1114,7 +1153,7 @@ WebRange WebLocalFrameImpl::MarkedRange() const {
bool WebLocalFrameImpl::FirstRectForCharacterRange(
unsigned location,
unsigned length,
- WebRect& rect_in_viewport) const {
+ gfx::Rect& rect_in_viewport) const {
if ((location + length < location) && (location + length))
length = 0;
@@ -1131,9 +1170,8 @@ bool WebLocalFrameImpl::FirstRectForCharacterRange(
PlainTextRange(location, location + length).CreateRange(*editable);
if (range.IsNull())
return false;
- IntRect int_rect = FirstRectForRange(range);
- rect_in_viewport = WebRect(int_rect);
- rect_in_viewport = GetFrame()->View()->FrameToViewport(rect_in_viewport);
+ rect_in_viewport =
+ GetFrame()->View()->FrameToViewport(FirstRectForRange(range));
return true;
}
@@ -1590,7 +1628,7 @@ void WebLocalFrameImpl::DispatchBeforePrintEvent(
// popup properly.
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
blink::SchedulingPolicy::Feature::kPrinting,
- {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {blink::SchedulingPolicy::DisableBackForwardCache()});
GetFrame()->GetDocument()->SetPrinting(Document::kBeforePrinting);
DispatchPrintEventRecursively(event_type_names::kBeforeprint);
@@ -1664,8 +1702,7 @@ uint32_t WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
GetFrame(), print_params.use_printing_layout);
}
- FloatSize size(static_cast<float>(print_params.print_content_area.width),
- static_cast<float>(print_params.print_content_area.height));
+ FloatSize size(print_params.print_content_area.size());
print_context_->BeginPrintMode(size.Width(), size.Height());
print_context_->ComputePageRects(size);
@@ -1704,19 +1741,21 @@ bool WebLocalFrameImpl::GetPrintPresetOptionsForPlugin(
return plugin_container->GetPrintPresetOptionsFromDocument(preset_options);
}
-bool WebLocalFrameImpl::CapturePaintPreview(const WebRect& bounds,
+bool WebLocalFrameImpl::CapturePaintPreview(const gfx::Rect& bounds,
cc::PaintCanvas* canvas,
bool include_linked_destinations) {
- FloatSize float_bounds(bounds.width, bounds.height);
- GetFrame()->GetDocument()->SetIsPaintingPreview(true);
- ResourceCacheValidationSuppressor validation_suppressor(
- GetFrame()->GetDocument()->Fetcher());
- GetFrame()->View()->ForceLayoutForPagination(float_bounds, float_bounds, 1);
- PaintPreviewContext* paint_preview_context =
- MakeGarbageCollected<PaintPreviewContext>(GetFrame());
- bool success = paint_preview_context->Capture(canvas, float_bounds,
- include_linked_destinations);
- GetFrame()->GetDocument()->SetIsPaintingPreview(false);
+ FloatSize float_bounds(bounds.width(), bounds.height());
+ bool success = false;
+ {
+ Document::PaintPreviewScope paint_preview(*GetFrame()->GetDocument());
+ ResourceCacheValidationSuppressor validation_suppressor(
+ GetFrame()->GetDocument()->Fetcher());
+ GetFrame()->View()->ForceLayoutForPagination(float_bounds, float_bounds, 1);
+ PaintPreviewContext* paint_preview_context =
+ MakeGarbageCollected<PaintPreviewContext>(GetFrame());
+ success = paint_preview_context->Capture(canvas, float_bounds,
+ include_linked_destinations);
+ }
GetFrame()->EndPrinting();
return success;
}
@@ -1731,10 +1770,10 @@ void WebLocalFrameImpl::GetPageDescription(
GetFrame()->GetDocument()->GetPageDescription(page_index, description);
}
-WebSize WebLocalFrameImpl::SpoolSizeInPixelsForTesting(
- const WebSize& page_size_in_pixels,
+gfx::Size WebLocalFrameImpl::SpoolSizeInPixelsForTesting(
+ const gfx::Size& page_size_in_pixels,
uint32_t page_count) {
- int spool_width = page_size_in_pixels.width;
+ int spool_width = page_size_in_pixels.width();
int spool_height = 0;
for (uint32_t page_index = 0; page_index < page_count; page_index++) {
// Make room for the 1px tall page separator.
@@ -1744,33 +1783,31 @@ WebSize WebLocalFrameImpl::SpoolSizeInPixelsForTesting(
WebPrintPageDescription description;
GetFrame()->GetDocument()->GetPageDescription(page_index, &description);
if (description.orientation == PageOrientation::kUpright) {
- spool_height += page_size_in_pixels.height;
+ spool_height += page_size_in_pixels.height();
} else {
- spool_height += page_size_in_pixels.width;
- spool_width = std::max(spool_width, page_size_in_pixels.height);
+ spool_height += page_size_in_pixels.width();
+ spool_width = std::max(spool_width, page_size_in_pixels.height());
}
}
- return WebSize(spool_width, spool_height);
+ return gfx::Size(spool_width, spool_height);
}
void WebLocalFrameImpl::PrintPagesForTesting(
cc::PaintCanvas* canvas,
- const WebSize& page_size_in_pixels,
- const WebSize& spool_size_in_pixels) {
+ const gfx::Size& page_size_in_pixels,
+ const gfx::Size& spool_size_in_pixels) {
DCHECK(print_context_);
print_context_->SpoolAllPagesWithBoundariesForTesting(
- canvas, FloatSize(page_size_in_pixels.width, page_size_in_pixels.height),
- FloatSize(spool_size_in_pixels.width, spool_size_in_pixels.height));
+ canvas, FloatSize(page_size_in_pixels), FloatSize(spool_size_in_pixels));
}
-WebRect WebLocalFrameImpl::GetSelectionBoundsRectForTesting() const {
+gfx::Rect WebLocalFrameImpl::GetSelectionBoundsRectForTesting() const {
GetFrame()->View()->UpdateLifecycleToLayoutClean(
DocumentUpdateReason::kSelection);
- return HasSelection()
- ? WebRect(PixelSnappedIntRect(
- GetFrame()->Selection().AbsoluteUnclippedBounds()))
- : WebRect();
+ return HasSelection() ? PixelSnappedIntRect(
+ GetFrame()->Selection().AbsoluteUnclippedBounds())
+ : gfx::Rect();
}
gfx::Point WebLocalFrameImpl::GetPositionInViewportForTesting() const {
@@ -1784,21 +1821,20 @@ WebLocalFrame* WebLocalFrame::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token,
- std::unique_ptr<blink::WebPolicyContainer> policy_container,
+ const LocalFrameToken& frame_token,
+ std::unique_ptr<WebPolicyContainer> policy_container,
WebFrame* opener,
const WebString& name,
- network::mojom::blink::WebSandboxFlags sandbox_flags,
- const FeaturePolicyFeatureState& opener_feature_state) {
+ network::mojom::blink::WebSandboxFlags sandbox_flags) {
return WebLocalFrameImpl::CreateMainFrame(
web_view, client, interface_registry, frame_token, opener, name,
- sandbox_flags, std::move(policy_container), opener_feature_state);
+ sandbox_flags, std::move(policy_container));
}
WebLocalFrame* WebLocalFrame::CreateProvisional(
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* previous_frame,
const FramePolicy& frame_policy,
const WebString& name) {
@@ -1811,14 +1847,13 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags sandbox_flags,
- std::unique_ptr<blink::WebPolicyContainer> policy_container,
- const FeaturePolicyFeatureState& opener_feature_state) {
+ std::unique_ptr<WebPolicyContainer> policy_container) {
auto* frame = MakeGarbageCollected<WebLocalFrameImpl>(
- util::PassKey<WebLocalFrameImpl>(),
+ base::PassKey<WebLocalFrameImpl>(),
mojom::blink::TreeScopeType::kDocument, client, interface_registry,
frame_token);
Page& page = *static_cast<WebViewImpl*>(web_view)->GetPage();
@@ -1826,14 +1861,14 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
frame->InitializeCoreFrame(
page, nullptr, nullptr, nullptr, FrameInsertType::kInsertInConstructor,
name, opener ? &ToCoreFrame(*opener)->window_agent_factory() : nullptr,
- opener, std::move(policy_container), sandbox_flags, opener_feature_state);
+ opener, std::move(policy_container), sandbox_flags);
return frame;
}
WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* previous_web_frame,
const FramePolicy& frame_policy,
const WebString& name) {
@@ -1841,7 +1876,7 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
Frame* previous_frame = ToCoreFrame(*previous_web_frame);
DCHECK(name.IsEmpty() || name.Equals(previous_frame->Tree().GetName()));
auto* web_frame = MakeGarbageCollected<WebLocalFrameImpl>(
- util::PassKey<WebLocalFrameImpl>(),
+ base::PassKey<WebLocalFrameImpl>(),
previous_web_frame->InShadowTree()
? mojom::blink::TreeScopeType::kShadow
: mojom::blink::TreeScopeType::kDocument,
@@ -1854,9 +1889,6 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
// to inherit sandbox flags when a sandboxed frame does a window.open()
// which triggers a cross-process navigation.
sandbox_flags = frame_policy.sandbox_flags;
- // If there is an opener (even disowned), the opener policies must be
- // inherited the same way as sandbox flag.
- feature_state = previous_frame->OpenerFeatureState();
}
// Note: this *always* temporarily sets a frame owner, even for main frames!
// When a core Frame is created with no owner, it attempts to set itself as
@@ -1877,9 +1909,11 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
? nullptr
: &ToCoreFrame(*previous_web_frame)->window_agent_factory(),
previous_web_frame->Opener(), /* policy_container */ nullptr,
- sandbox_flags, feature_state);
+ sandbox_flags);
LocalFrame* new_frame = web_frame->GetFrame();
+ previous_frame->SetProvisionalFrame(new_frame);
+
new_frame->SetOwner(previous_frame->Owner());
if (auto* remote_frame_owner =
DynamicTo<RemoteFrameOwner>(new_frame->Owner())) {
@@ -1893,19 +1927,19 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateLocalChild(
mojom::blink::TreeScopeType scope,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token) {
+ const LocalFrameToken& frame_token) {
auto* frame = MakeGarbageCollected<WebLocalFrameImpl>(
- util::PassKey<WebLocalFrameImpl>(), scope, client, interface_registry,
+ base::PassKey<WebLocalFrameImpl>(), scope, client, interface_registry,
frame_token);
return frame;
}
WebLocalFrameImpl::WebLocalFrameImpl(
- util::PassKey<WebLocalFrameImpl>,
+ base::PassKey<WebLocalFrameImpl>,
mojom::blink::TreeScopeType scope,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token)
+ const LocalFrameToken& frame_token)
: WebNavigationControl(scope, frame_token),
client_(client),
local_frame_client_(MakeGarbageCollected<LocalFrameClientImpl>(this)),
@@ -1916,18 +1950,17 @@ WebLocalFrameImpl::WebLocalFrameImpl(
input_method_controller_(*this),
spell_check_panel_host_client_(nullptr),
self_keep_alive_(PERSISTENT_FROM_HERE, this) {
- DCHECK(client_);
+ CHECK(client_);
g_frame_count++;
client_->BindToFrame(this);
}
-WebLocalFrameImpl::WebLocalFrameImpl(
- util::PassKey<WebRemoteFrameImpl>,
- mojom::blink::TreeScopeType scope,
- WebLocalFrameClient* client,
- blink::InterfaceRegistry* interface_registry,
- const base::UnguessableToken& frame_token)
- : WebLocalFrameImpl(util::PassKey<WebLocalFrameImpl>(),
+WebLocalFrameImpl::WebLocalFrameImpl(base::PassKey<WebRemoteFrameImpl>,
+ mojom::blink::TreeScopeType scope,
+ WebLocalFrameClient* client,
+ InterfaceRegistry* interface_registry,
+ const LocalFrameToken& frame_token)
+ : WebLocalFrameImpl(base::PassKey<WebLocalFrameImpl>(),
scope,
client,
interface_registry,
@@ -1963,13 +1996,12 @@ void WebLocalFrameImpl::InitializeCoreFrame(
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
- network::mojom::blink::WebSandboxFlags sandbox_flags,
- const FeaturePolicyFeatureState& opener_feature_state) {
+ network::mojom::blink::WebSandboxFlags sandbox_flags) {
InitializeCoreFrameInternal(page, owner, parent, previous_sibling,
insert_type, name, window_agent_factory, opener,
PolicyContainer::CreateFromWebPolicyContainer(
std::move(policy_container)),
- sandbox_flags, opener_feature_state);
+ sandbox_flags);
}
void WebLocalFrameImpl::InitializeCoreFrameInternal(
@@ -1982,19 +2014,29 @@ void WebLocalFrameImpl::InitializeCoreFrameInternal(
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
std::unique_ptr<PolicyContainer> policy_container,
- network::mojom::blink::WebSandboxFlags sandbox_flags,
- const FeaturePolicyFeatureState& opener_feature_state) {
+ network::mojom::blink::WebSandboxFlags sandbox_flags) {
Frame* parent_frame = parent ? ToCoreFrame(*parent) : nullptr;
Frame* previous_sibling_frame =
previous_sibling ? ToCoreFrame(*previous_sibling) : nullptr;
SetCoreFrame(MakeGarbageCollected<LocalFrame>(
local_frame_client_.Get(), page, owner, parent_frame,
- previous_sibling_frame, insert_type, GetFrameToken(),
+ previous_sibling_frame, insert_type, GetLocalFrameToken(),
window_agent_factory, interface_registry_, std::move(policy_container)));
frame_->Tree().SetName(name);
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled())
- frame_->SetOpenerFeatureState(opener_feature_state);
- frame_->Loader().ForceSandboxFlags(sandbox_flags);
+
+ // See sandbox inheritance: content/browser/renderer_host/sandbox_flags.md
+ //
+ // New documents are either:
+ // 1. The initial empty document:
+ // a. In a new iframe.
+ // b. In a new popup.
+ // 2. A document replacing the previous, one via a navigation.
+ //
+ // This is about 1.b. This is used to define sandbox flags for the initial
+ // empty document in a new popup.
+ if (frame_->IsMainFrame())
+ frame_->SetOpenerSandboxFlags(sandbox_flags);
+
Frame* opener_frame = opener ? ToCoreFrame(*opener) : nullptr;
// We must call init() after frame_ is assigned because it is referenced
@@ -2030,26 +2072,30 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
owner_element->MarginHeight(), owner_element->AllowFullscreen(),
owner_element->AllowPaymentRequest(), owner_element->IsDisplayNone(),
owner_element->GetColorScheme(), owner_element->RequiredCsp());
+
+ mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost>
+ policy_container_remote;
+ mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
+ policy_container_receiver =
+ policy_container_remote.InitWithNewEndpointAndPassReceiver();
+
// FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes
// which can identify the element.
- WebLocalFrameImpl* webframe_child = To<WebLocalFrameImpl>(
- client_->CreateChildFrame(this, scope, name,
- owner_element->getAttribute(
- owner_element->SubResourceAttributeName()),
- owner_element->GetFramePolicy(),
- owner_properties, owner_element->OwnerType()));
+ WebLocalFrameImpl* webframe_child =
+ To<WebLocalFrameImpl>(client_->CreateChildFrame(
+ scope, name,
+ owner_element->getAttribute(
+ owner_element->SubResourceAttributeName()),
+ owner_element->GetFramePolicy(), owner_properties,
+ owner_element->OwnerType(),
+ WebPolicyContainerBindParams{std::move(policy_container_receiver)}));
if (!webframe_child)
return nullptr;
// Inherit policy container from parent.
- mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost>
- policy_container_remote;
- mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
- policy_container_receiver =
- policy_container_remote.InitWithNewEndpointAndPassReceiver();
- mojom::blink::PolicyContainerDocumentPoliciesPtr policy_container_data =
+ mojom::blink::PolicyContainerPoliciesPtr policy_container_data =
mojo::Clone(GetFrame()->GetPolicyContainer()->GetPolicies());
std::unique_ptr<PolicyContainer> policy_container =
std::make_unique<PolicyContainer>(std::move(policy_container_remote),
@@ -2063,14 +2109,7 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
: &GetFrame()->window_agent_factory(),
nullptr, std::move(policy_container));
- // TODO(antoniosartori): Ideally, we could have sent the mojo receiver to the
- // Browser with the CreateChildFrame IPC. Unfortunately, that's not so easy,
- // both because that is a legacy (non-mojo) IPC sync call, and because it
- // starts from the content layer, so it would require additional type
- // conversions. But we should revisit this after that IPC gets reworked (see
- // https://crbug.com/1064336).
- webframe_child->GetFrame()->GetLocalFrameHostRemote().BindPolicyContainer(
- std::move(policy_container_receiver));
+ webframe_child->Client()->InitializeAsChildFrame(/*parent=*/this);
DCHECK(webframe_child->Parent());
return webframe_child->GetFrame();
@@ -2155,6 +2194,19 @@ WebLocalFrameImpl* WebLocalFrameImpl::FromFrame(LocalFrame* frame) {
return FromFrame(*frame);
}
+std::string WebLocalFrameImpl::GetNullFrameReasonForBug1139104(
+ LocalFrame* frame) {
+ LocalFrameClient* client = frame->Client();
+ if (!client)
+ return "WebLocalFrameImpl::client";
+ if (!client->IsLocalFrameClientImpl())
+ return "WebLocalFrameImpl::client-not-local";
+ WebLocalFrame* web_frame = client->GetWebFrame();
+ if (!web_frame)
+ return "WebLocalFrameImpl::web_frame";
+ return "not-null";
+}
+
WebLocalFrameImpl* WebLocalFrameImpl::FromFrame(LocalFrame& frame) {
LocalFrameClient* client = frame.Client();
if (!client || !client->IsLocalFrameClientImpl())
@@ -2234,7 +2286,7 @@ WebLocalFrameImpl* WebLocalFrameImpl::LocalRoot() {
}
WebFrame* WebLocalFrameImpl::FindFrameByName(const WebString& name) {
- return WebFrame::FromFrame(GetFrame()->Tree().FindFrameByName(name));
+ return WebFrame::FromCoreFrame(GetFrame()->Tree().FindFrameByName(name));
}
void WebLocalFrameImpl::SetEmbeddingToken(
@@ -2279,6 +2331,7 @@ blink::mojom::CommitResult WebLocalFrameImpl::CommitSameDocumentNavigation(
WebFrameLoadType web_frame_load_type,
const WebHistoryItem& item,
bool is_client_redirect,
+ bool has_transient_user_activation,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(GetFrame());
DCHECK(!url.ProtocolIs("javascript"));
@@ -2288,8 +2341,8 @@ blink::mojom::CommitResult WebLocalFrameImpl::CommitSameDocumentNavigation(
url, web_frame_load_type, history_item,
is_client_redirect ? ClientRedirectPolicy::kClientRedirect
: ClientRedirectPolicy::kNotClientRedirect,
- nullptr, /* origin_document */
- false, /* has_event */
+ has_transient_user_activation, nullptr, /* origin_document */
+ false, /* has_event */
std::move(extra_data));
}
@@ -2395,6 +2448,10 @@ WebNode WebLocalFrameImpl::ContextMenuNode() const {
return ContextMenuNodeInner();
}
+WebNode WebLocalFrameImpl::ContextMenuImageNode() const {
+ return ContextMenuImageNodeInner();
+}
+
void WebLocalFrameImpl::WillBeDetached() {
if (frame_->IsMainFrame())
ViewImpl()->DidDetachLocalMainFrame();
@@ -2418,8 +2475,60 @@ void WebLocalFrameImpl::WillDetachParent() {
}
}
-void WebLocalFrameImpl::SetFrameWidget(WebFrameWidgetBase* frame_widget) {
- frame_widget_ = frame_widget;
+void WebLocalFrameImpl::CreateFrameWidgetInternal(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ mojo_frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ mojo_frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ mojo_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ mojo_widget,
+ const viz::FrameSinkId& frame_sink_id,
+ bool is_for_nested_main_frame,
+ bool hidden,
+ bool never_composited) {
+ DCHECK(!frame_widget_);
+ DCHECK(frame_->IsLocalRoot());
+ bool is_for_child_local_root = Parent();
+
+ // Check that if this is for a child local root |is_for_nested_main_frame|
+ // is false.
+ DCHECK(!is_for_child_local_root || !is_for_nested_main_frame);
+
+ if (g_create_web_frame_widget) {
+ // It is safe to cast to WebFrameWidgetImpl because the only concrete
+ // subclass of WebFrameWidget that is allowed is WebFrameWidgetImpl. This
+ // is enforced via a private constructor (and friend class) on
+ // WebFrameWidget.
+ frame_widget_ =
+ static_cast<WebFrameWidgetImpl*>(g_create_web_frame_widget->Run(
+ std::move(pass_key), std::move(mojo_frame_widget_host),
+ std::move(mojo_frame_widget), std::move(mojo_widget_host),
+ std::move(mojo_widget),
+ Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
+ frame_sink_id, hidden, never_composited, is_for_child_local_root,
+ is_for_nested_main_frame));
+ } else {
+ frame_widget_ = MakeGarbageCollected<WebFrameWidgetImpl>(
+ std::move(pass_key), std::move(mojo_frame_widget_host),
+ std::move(mojo_frame_widget), std::move(mojo_widget_host),
+ std::move(mojo_widget),
+ Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
+ frame_sink_id, hidden, never_composited, is_for_child_local_root,
+ is_for_nested_main_frame);
+ }
+ frame_widget_->BindLocalRoot(*this);
+
+ // If this is for a main frame grab the associated WebViewImpl and
+ // assign this widget as the main frame widget.
+ // Note: this can't DCHECK that the view's main frame points to
+ // |this|, as provisional frames violate this precondition.
+ if (!is_for_child_local_root) {
+ DCHECK(ViewImpl());
+ ViewImpl()->SetMainFrameViewWidget(frame_widget_);
+ }
}
WebFrameWidget* WebLocalFrameImpl::FrameWidget() const {
@@ -2431,21 +2540,86 @@ void WebLocalFrameImpl::CopyImageAtForTesting(
GetFrame()->CopyImageAtViewportPoint(IntPoint(pos_in_viewport));
}
+void WebLocalFrameImpl::ShowContextMenuFromExternal(
+ const UntrustworthyContextMenuParams& params,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::ContextMenuClientInterfaceBase> context_menu_client) {
+ GetFrame()->GetLocalFrameHostRemote().ShowContextMenu(
+ std::move(context_menu_client), params);
+}
+
+void WebLocalFrameImpl::ShowContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient> client,
+ const blink::ContextMenuData& data,
+ const base::Optional<gfx::Point>& host_context_menu_location) {
+ UntrustworthyContextMenuParams params =
+ blink::ContextMenuParamsBuilder::Build(data);
+ if (host_context_menu_location.has_value()) {
+ // If the context menu request came from the browser, it came with a
+ // position that was stored on blink::WebFrameWidgetImpl and is relative to
+ // the WindowScreenRect.
+ params.x = host_context_menu_location.value().x();
+ params.y = host_context_menu_location.value().y();
+ } else {
+ // If the context menu request came from the renderer, the position in
+ // |params| is real, but they come in blink viewport coordinates, which
+ // include the device scale factor, but not emulation scale. Here we convert
+ // them to DIP coordinates relative to the WindowScreenRect.
+ // TODO(crbug.com/1093904): This essentially is a floor of the coordinates.
+ // Determine if rounding is more appropriate.
+ gfx::Rect position_in_dips =
+ LocalRootFrameWidget()->BlinkSpaceToEnclosedDIPs(
+ gfx::Rect(params.x, params.y, 0, 0));
+
+ const float scale = LocalRootFrameWidget()->GetEmulatorScale();
+ params.x = position_in_dips.x() * scale;
+ params.y = position_in_dips.y() * scale;
+ }
+
+ // Serializing a GURL longer than kMaxURLChars will fail, so don't do
+ // it. We replace it with an empty GURL so the appropriate items are disabled
+ // in the context menu.
+ // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
+ // data encoded images. We should have a way to save them.
+ if (params.src_url.spec().size() > url::kMaxURLChars)
+ params.src_url = KURL();
+
+ params.selection_rect =
+ LocalRootFrameWidget()->BlinkSpaceToEnclosedDIPs(data.selection_rect);
+
+#if defined(OS_ANDROID)
+ // The Samsung Email app relies on the context menu being shown after the
+ // javascript onselectionchanged is triggered.
+ // See crbug.com/729488
+ GetFrame()
+ ->GetTaskRunner(TaskType::kInternalDefault)
+ ->PostTask(
+ FROM_HERE,
+ WTF::Bind(&WebLocalFrameImpl::ShowDeferredContextMenu,
+ WrapWeakPersistent(this), std::move(client), params));
+#else
+ ShowDeferredContextMenu(std::move(client), params);
+#endif
+
+ if (Client())
+ Client()->UpdateContextMenuDataForTesting(data, host_context_menu_location);
+}
+
+void WebLocalFrameImpl::ShowDeferredContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient> client,
+ const UntrustworthyContextMenuParams& params) {
+ // The local frame may become detached before the object is GC'ed. So, this
+ // method needs to check if GetFrame() returns a nullptr.
+ if (!GetFrame())
+ return;
+ GetFrame()->GetLocalFrameHostRemote().ShowContextMenu(std::move(client),
+ params);
+}
+
bool WebLocalFrameImpl::IsAllowedToDownload() const {
if (!GetFrame())
return true;
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- // Downloads could be disabled if the parent frame's FeaturePolicy does not
- // allow downloads.
- if (GetFrame()->Tree().Parent() &&
- !GetFrame()->Tree().Parent()->GetSecurityContext()->IsFeatureEnabled(
- mojom::blink::FeaturePolicyFeature::kDownloads)) {
- return false;
- }
- return !GetFrame()->Owner() ||
- GetFrame()->Owner()->GetFramePolicy().allowed_to_download;
- }
return (GetFrame()->Loader().PendingEffectiveSandboxFlags() &
network::mojom::blink::WebSandboxFlags::kDownloads) ==
network::mojom::blink::WebSandboxFlags::kNone;
@@ -2505,18 +2679,19 @@ WebInputMethodController* WebLocalFrameImpl::GetInputMethodController() {
// "core/editing/serializers/Serialization.cpp".
static String CreateMarkupInRect(LocalFrame*, const IntPoint&, const IntPoint&);
-void WebLocalFrameImpl::ExtractSmartClipData(WebRect rect_in_viewport,
+void WebLocalFrameImpl::ExtractSmartClipData(const gfx::Rect& rect_in_viewport,
WebString& clip_text,
WebString& clip_html,
- WebRect& clip_rect) {
+ gfx::Rect& clip_rect) {
// TODO(mahesh.ma): Check clip_data even after use-zoom-for-dsf is enabled.
- SmartClipData clip_data = SmartClip(GetFrame()).DataForRect(rect_in_viewport);
+ SmartClipData clip_data =
+ SmartClip(GetFrame()).DataForRect(IntRect(rect_in_viewport));
clip_text = clip_data.ClipData();
clip_rect = clip_data.RectInViewport();
- IntPoint start_point(rect_in_viewport.x, rect_in_viewport.y);
- IntPoint end_point(rect_in_viewport.x + rect_in_viewport.width,
- rect_in_viewport.y + rect_in_viewport.height);
+ IntPoint start_point(rect_in_viewport.x(), rect_in_viewport.y());
+ IntPoint end_point(rect_in_viewport.x() + rect_in_viewport.width(),
+ rect_in_viewport.y() + rect_in_viewport.height());
clip_html = CreateMarkupInRect(
GetFrame(), GetFrame()->View()->ViewportToFrame(start_point),
GetFrame()->View()->ViewportToFrame(end_point));
@@ -2588,7 +2763,7 @@ void WebLocalFrameImpl::SetSpellCheckPanelHostClient(
spell_check_panel_host_client_ = spell_check_panel_host_client;
}
-WebFrameWidgetBase* WebLocalFrameImpl::LocalRootFrameWidget() {
+WebFrameWidgetImpl* WebLocalFrameImpl::LocalRootFrameWidget() {
CHECK(LocalRoot());
return LocalRoot()->FrameWidgetImpl();
}
@@ -2602,6 +2777,15 @@ Node* WebLocalFrameImpl::ContextMenuNodeInner() const {
.ContextMenuNodeForFrame(GetFrame());
}
+Node* WebLocalFrameImpl::ContextMenuImageNodeInner() const {
+ if (!ViewImpl() || !ViewImpl()->GetPage())
+ return nullptr;
+ return ViewImpl()
+ ->GetPage()
+ ->GetContextMenuController()
+ .ContextMenuImageNodeForFrame(GetFrame());
+}
+
void WebLocalFrameImpl::WaitForDebuggerWhenShown() {
DCHECK(frame_->IsLocalRoot());
DevToolsAgentImpl()->WaitForDebuggerWhenShown();
@@ -2654,4 +2838,49 @@ void WebLocalFrameImpl::SetAllowsCrossBrowsingInstanceFrameLookup() {
window->GetMutableSecurityOrigin()->GrantCrossAgentClusterAccess();
}
+const WebHistoryItem& WebLocalFrameImpl::GetCurrentHistoryItem() const {
+ return current_history_item_;
+}
+
+void WebLocalFrameImpl::SetTargetToCurrentHistoryItem(const WebString& target) {
+ current_history_item_.SetTarget(target);
+}
+
+void WebLocalFrameImpl::UpdateCurrentHistoryItem() {
+ current_history_item_ = WebHistoryItem(
+ GetFrame()->Loader().GetDocumentLoader()->GetHistoryItem());
+}
+
+PageState WebLocalFrameImpl::CurrentHistoryItemToPageState() {
+ return SingleHistoryItemToPageState(current_history_item_);
+}
+
+void WebLocalFrameImpl::ScrollFocusedEditableElementIntoRect(
+ const gfx::Rect& rect) {
+ // TODO(ekaramad): Perhaps we should remove |rect| since all it seems to be
+ // doing is helping verify if scrolling animation for a given focused editable
+ // element has finished.
+ if (has_scrolled_focused_editable_node_into_rect_ &&
+ rect == rect_for_scrolled_focused_editable_node_ && autofill_client_) {
+ autofill_client_->DidCompleteFocusChangeInFrame();
+ return;
+ }
+
+ WebFrameWidgetImpl* local_root_frame_widget = LocalRootFrameWidget();
+
+ if (!local_root_frame_widget->ScrollFocusedEditableElementIntoView())
+ return;
+
+ rect_for_scrolled_focused_editable_node_ = rect;
+ has_scrolled_focused_editable_node_into_rect_ = true;
+ if (!local_root_frame_widget->HasPendingPageScaleAnimation() &&
+ autofill_client_) {
+ autofill_client_->DidCompleteFocusChangeInFrame();
+ }
+}
+
+void WebLocalFrameImpl::ResetHasScrolledFocusedEditableIntoView() {
+ has_scrolled_focused_editable_node_into_rect_ = false;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 0820c774272..e28eb9d4c44 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -36,16 +36,20 @@
#include <utility>
#include "base/single_thread_task_runner.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
+#include "build/build_config.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
+#include "third_party/blink/public/common/context_menu_data/context_menu_data.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/ad_tagging/ad_frame.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
+#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
#include "third_party/blink/public/mojom/portal/portal.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_file_system_type.h"
#include "third_party/blink/public/web/web_history_commit_type.h"
@@ -64,6 +68,7 @@
namespace blink {
class ChromePrintContext;
+struct ContextMenuData;
class FindInPage;
class HTMLPortalElement;
class IntSize;
@@ -77,7 +82,7 @@ class WebAutofillClient;
class WebContentSettingsClient;
class WebDevToolsAgentImpl;
class WebLocalFrameClient;
-class WebFrameWidgetBase;
+class WebFrameWidgetImpl;
class WebNode;
class WebPerformance;
class WebRemoteFrameImpl;
@@ -108,7 +113,7 @@ class CORE_EXPORT WebLocalFrameImpl final
mojom::blink::TreeScopeType,
WebLocalFrameClient*,
blink::InterfaceRegistry*,
- const base::UnguessableToken& frame_token) override;
+ const LocalFrameToken& frame_token) override;
WebLocalFrameClient* Client() const override { return client_; }
void SetAutofillClient(WebAutofillClient*) override;
WebAutofillClient* AutofillClient() override;
@@ -128,7 +133,7 @@ class CORE_EXPORT WebLocalFrameImpl final
const override;
void SendPings(const WebURL& destination_url) override;
void StartReload(WebFrameLoadType) override;
- void StartNavigation(const WebURLRequest&) override;
+ void ResetForTesting() override;
void EnableViewSourceMode(bool enable) override;
bool IsViewSourceModeEnabled() const override;
WebDocumentLoader* GetDocumentLoader() const override;
@@ -192,7 +197,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebRange MarkedRange() const override;
bool FirstRectForCharacterRange(unsigned location,
unsigned length,
- WebRect&) const override;
+ gfx::Rect&) const override;
bool ExecuteCommand(const WebString&) override;
bool ExecuteCommand(const WebString&, const WebString& value) override;
bool IsCommandEnabled(const WebString&) const override;
@@ -235,10 +240,10 @@ class CORE_EXPORT WebLocalFrameImpl final
void ReplaceSelection(const WebString&) override;
void DeleteSurroundingText(int before, int after) override;
void DeleteSurroundingTextInCodePoints(int before, int after) override;
- void ExtractSmartClipData(WebRect rect_in_viewport,
+ void ExtractSmartClipData(const gfx::Rect& rect_in_viewport,
WebString& clip_text,
WebString& clip_html,
- WebRect& clip_rect) override;
+ gfx::Rect& clip_rect) override;
void SetTextCheckClient(WebTextCheckClient*) override;
void SetSpellCheckPanelHostClient(WebSpellCheckPanelHostClient*) override;
WebSpellCheckPanelHostClient* SpellCheckPanelHostClient() const override {
@@ -248,6 +253,7 @@ class CORE_EXPORT WebLocalFrameImpl final
void RemoveSpellingMarkers() override;
void RemoveSpellingMarkersUnderWords(
const WebVector<WebString>& words) override;
+ WebContentSettingsClient* GetContentSettingsClient() const override;
void SetContentSettingsClient(WebContentSettingsClient*) override;
void ReloadImage(const WebNode&) override;
bool IsAllowedToDownload() const override;
@@ -260,9 +266,15 @@ class CORE_EXPORT WebLocalFrameImpl final
bool wrap_within_frame,
bool async) override;
void SetTickmarks(const WebElement& target,
- const WebVector<WebRect>& tickmarks) override;
+ const WebVector<gfx::Rect>& tickmarks) override;
+ WebNode ContextMenuImageNode() const override;
WebNode ContextMenuNode() const override;
void CopyImageAtForTesting(const gfx::Point&) override;
+ void ShowContextMenuFromExternal(
+ const UntrustworthyContextMenuParams& params,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::ContextMenuClientInterfaceBase> context_menu_client)
+ override;
void UsageCountChromeLoadTimes(const WebString& metric) override;
bool DispatchedPagehideAndStillHidden() const override;
FrameScheduler* Scheduler() const override;
@@ -276,7 +288,7 @@ class CORE_EXPORT WebLocalFrameImpl final
void SetScrollOffset(const WebSize&) override;
WebSize DocumentSize() const override;
bool HasVisibleContent() const override;
- WebRect VisibleContentRect() const override;
+ gfx::Rect VisibleContentRect() const override;
void DispatchBeforePrintEvent(
base::WeakPtr<WebPrintClient> print_client) override;
WebPlugin* GetPluginToPrint(const WebNode& constrain_to_node) override;
@@ -288,19 +300,20 @@ class CORE_EXPORT WebLocalFrameImpl final
void DispatchAfterPrintEvent() override;
bool GetPrintPresetOptionsForPlugin(const WebNode&,
WebPrintPresetOptions*) override;
- bool CapturePaintPreview(const WebRect& bounds,
+ bool CapturePaintPreview(const gfx::Rect& bounds,
cc::PaintCanvas* canvas,
bool include_linked_destinations) override;
bool ShouldSuppressKeyboardForFocusedElement() override;
WebPerformance Performance() const override;
bool IsAdSubframe() const override;
void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type) override;
- WebSize SpoolSizeInPixelsForTesting(const WebSize& page_size_in_pixels,
- uint32_t page_count) override;
+ bool IsSubframeCreatedByAdScript() override;
+ gfx::Size SpoolSizeInPixelsForTesting(const gfx::Size& page_size_in_pixels,
+ uint32_t page_count) override;
void PrintPagesForTesting(cc::PaintCanvas*,
- const WebSize& page_size_in_pixels,
- const WebSize& spool_size_in_pixels) override;
- WebRect GetSelectionBoundsRectForTesting() const override;
+ const gfx::Size& page_size_in_pixels,
+ const gfx::Size& spool_size_in_pixels) override;
+ gfx::Rect GetSelectionBoundsRectForTesting() const override;
gfx::Point GetPositionInViewportForTesting() const override;
void WasHidden() override;
void WasShown() override;
@@ -311,6 +324,10 @@ class CORE_EXPORT WebLocalFrameImpl final
bool HasTransientUserActivation() override;
bool ConsumeTransientUserActivation(UserActivationUpdateSource) override;
void SetOptimizationGuideHints(const WebOptimizationGuideHints&) override;
+ void SetTargetToCurrentHistoryItem(const WebString& target) override;
+ void UpdateCurrentHistoryItem() override;
+ PageState CurrentHistoryItemToPageState() override;
+ const WebHistoryItem& GetCurrentHistoryItem() const override;
// WebNavigationControl overrides:
bool DispatchBeforeUnloadEvent(bool) override;
@@ -322,6 +339,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebFrameLoadType,
const WebHistoryItem&,
bool is_client_redirect,
+ bool has_transient_user_activation,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) override;
void LoadJavaScriptURL(const WebURL&) override;
FallbackContentResult MaybeRenderFallbackContent(
@@ -347,9 +365,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebFrame* opener,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
network::mojom::blink::WebSandboxFlags sandbox_flags =
- network::mojom::blink::WebSandboxFlags::kNone,
- const FeaturePolicyFeatureState& opener_feature_state =
- FeaturePolicyFeatureState());
+ network::mojom::blink::WebSandboxFlags::kNone);
LocalFrame* GetFrame() const { return frame_.Get(); }
void WillBeDetached();
@@ -360,30 +376,29 @@ class CORE_EXPORT WebLocalFrameImpl final
WebView*,
WebLocalFrameClient*,
InterfaceRegistry*,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags,
- std::unique_ptr<blink::WebPolicyContainer>,
- const FeaturePolicyFeatureState&);
+ std::unique_ptr<WebPolicyContainer>);
static WebLocalFrameImpl* CreateProvisional(
WebLocalFrameClient*,
InterfaceRegistry*,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame*,
const FramePolicy&,
const WebString& name);
- WebLocalFrameImpl(util::PassKey<WebLocalFrameImpl>,
+ WebLocalFrameImpl(base::PassKey<WebLocalFrameImpl>,
mojom::blink::TreeScopeType,
WebLocalFrameClient*,
- blink::InterfaceRegistry*,
- const base::UnguessableToken& frame_token);
- WebLocalFrameImpl(util::PassKey<WebRemoteFrameImpl>,
+ InterfaceRegistry*,
+ const LocalFrameToken& frame_token);
+ WebLocalFrameImpl(base::PassKey<WebRemoteFrameImpl>,
mojom::blink::TreeScopeType,
WebLocalFrameClient*,
- blink::InterfaceRegistry*,
- const base::UnguessableToken& frame_token);
+ InterfaceRegistry*,
+ const LocalFrameToken& frame_token);
~WebLocalFrameImpl() override;
LocalFrame* CreateChildFrame(const AtomicString& name,
@@ -408,6 +423,8 @@ class CORE_EXPORT WebLocalFrameImpl final
// So note that FromFrame may return nullptr even for non-null frames.
static WebLocalFrameImpl* FromFrame(LocalFrame*);
static WebLocalFrameImpl* FromFrame(LocalFrame&);
+ // TODO(https://crbug.com/1139104): Remove this.
+ static std::string GetNullFrameReasonForBug1139104(LocalFrame* frame);
WebViewImpl* ViewImpl() const;
@@ -438,11 +455,7 @@ class CORE_EXPORT WebLocalFrameImpl final
void SetClient(WebLocalFrameClient* client) { client_ = client; }
- WebFrameWidgetBase* FrameWidgetImpl() { return frame_widget_; }
-
- WebContentSettingsClient* GetContentSettingsClient() {
- return content_settings_client_;
- }
+ WebFrameWidgetImpl* FrameWidgetImpl() { return frame_widget_; }
WebTextCheckClient* GetTextCheckerClient() const {
return text_check_client_;
@@ -455,11 +468,13 @@ class CORE_EXPORT WebLocalFrameImpl final
// Otherwise creates it and then returns.
TextFinder& EnsureTextFinder();
- void SetFrameWidget(WebFrameWidgetBase*);
-
// TODO(dcheng): Remove this and make |FrameWidget()| always return something
// useful.
- WebFrameWidgetBase* LocalRootFrameWidget();
+ WebFrameWidgetImpl* LocalRootFrameWidget();
+
+ // Scroll the focused editable element into the rect.
+ void ScrollFocusedEditableElementIntoRect(const gfx::Rect& rect);
+ void ResetHasScrolledFocusedEditableIntoView();
// Returns true if the frame is focused.
bool IsFocused() const;
@@ -470,6 +485,13 @@ class CORE_EXPORT WebLocalFrameImpl final
// Copy the current selection to the pboard.
void CopyToFindPboard();
+ // Shows a context menu with commands relevant to a specific element on
+ // the given frame. Additional context data and location are supplied.
+ void ShowContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient> client,
+ const blink::ContextMenuData& data,
+ const base::Optional<gfx::Point>& host_context_menu_location);
+
virtual void Trace(Visitor*) const;
protected:
@@ -491,6 +513,20 @@ class CORE_EXPORT WebLocalFrameImpl final
WebLocalFrame* ToWebLocalFrame() override;
bool IsWebRemoteFrame() const override;
WebRemoteFrame* ToWebRemoteFrame() override;
+ void CreateFrameWidgetInternal(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> mojo_frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ mojo_frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ mojo_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ mojo_widget,
+ const viz::FrameSinkId& frame_sink_id,
+ bool is_for_nested_main_frame,
+ bool hidden,
+ bool never_composited) override;
HitTestResult HitTestResultForVisualViewportPos(const IntPoint&);
@@ -503,6 +539,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebPluginContainerImpl* GetPluginToPrintHelper(
const WebNode& constrain_to_node);
+ Node* ContextMenuImageNodeInner() const;
Node* ContextMenuNodeInner() const;
void InitializeCoreFrameInternal(
@@ -516,9 +553,11 @@ class CORE_EXPORT WebLocalFrameImpl final
WebFrame* opener,
std::unique_ptr<PolicyContainer> policy_container,
network::mojom::blink::WebSandboxFlags sandbox_flags =
- network::mojom::blink::WebSandboxFlags::kNone,
- const FeaturePolicyFeatureState& opener_feature_state =
- FeaturePolicyFeatureState());
+ network::mojom::blink::WebSandboxFlags::kNone);
+
+ void ShowDeferredContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient> client,
+ const UntrustworthyContextMenuParams& params);
WebLocalFrameClient* client_;
@@ -532,7 +571,7 @@ class CORE_EXPORT WebLocalFrameImpl final
// This is set if the frame is the root of a local frame tree, and requires a
// widget for layout.
- Member<WebFrameWidgetBase> frame_widget_;
+ Member<WebFrameWidgetImpl> frame_widget_;
Member<WebDevToolsAgentImpl> dev_tools_agent_;
@@ -571,6 +610,13 @@ class CORE_EXPORT WebLocalFrameImpl final
// DispatchAfterPrintEvent() is not called yet.
bool is_in_printing_ = false;
#endif
+
+ // Bookkeeping to suppress redundant scroll and focus requests for an already
+ // scrolled and focused editable node.
+ bool has_scrolled_focused_editable_node_into_rect_ = false;
+ gfx::Rect rect_for_scrolled_focused_editable_node_;
+
+ WebHistoryItem current_history_item_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
index 5d8c32df51d..84bee1792d8 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
+++ b/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
@@ -7,9 +7,9 @@
#include <utility>
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
+#include "third_party/blink/public/common/frame/frame_visual_properties.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
#include "third_party/blink/public/web/web_performance.h"
@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/execution_context/security_context.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/remote_frame_client_impl.h"
@@ -47,7 +48,7 @@ WebRemoteFrame* WebRemoteFrame::Create(
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token) {
+ const RemoteFrameToken& frame_token) {
return MakeGarbageCollected<WebRemoteFrameImpl>(
scope, client, interface_registry, associated_interface_provider,
frame_token);
@@ -58,7 +59,7 @@ WebRemoteFrame* WebRemoteFrame::CreateMainFrame(
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WebFrame* opener) {
return WebRemoteFrameImpl::CreateMainFrame(
web_view, client, interface_registry, associated_interface_provider,
@@ -70,7 +71,7 @@ WebRemoteFrame* WebRemoteFrame::CreateForPortal(
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
const WebElement& portal_element) {
return WebRemoteFrameImpl::CreateForPortal(scope, client, interface_registry,
associated_interface_provider,
@@ -83,7 +84,7 @@ WebRemoteFrameImpl* WebRemoteFrameImpl::CreateMainFrame(
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WebFrame* opener) {
WebRemoteFrameImpl* frame = MakeGarbageCollected<WebRemoteFrameImpl>(
mojom::blink::TreeScopeType::kDocument, client, interface_registry,
@@ -111,7 +112,7 @@ WebRemoteFrameImpl* WebRemoteFrameImpl::CreateForPortal(
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
const WebElement& portal_element) {
auto* frame = MakeGarbageCollected<WebRemoteFrameImpl>(
scope, client, interface_registry, associated_interface_provider,
@@ -173,15 +174,15 @@ WebLocalFrame* WebRemoteFrameImpl::CreateLocalChild(
const WebString& name,
const FramePolicy& frame_policy,
WebLocalFrameClient* client,
- blink::InterfaceRegistry* interface_registry,
+ InterfaceRegistry* interface_registry,
WebFrame* previous_sibling,
const WebFrameOwnerProperties& frame_owner_properties,
mojom::blink::FrameOwnerElementType frame_owner_element_type,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* opener,
- std::unique_ptr<blink::WebPolicyContainer> policy_container) {
+ std::unique_ptr<WebPolicyContainer> policy_container) {
auto* child = MakeGarbageCollected<WebLocalFrameImpl>(
- util::PassKey<WebRemoteFrameImpl>(), scope, client, interface_registry,
+ base::PassKey<WebRemoteFrameImpl>(), scope, client, interface_registry,
frame_token);
auto* owner = MakeGarbageCollected<RemoteFrameOwner>(
frame_policy, frame_owner_properties, frame_owner_element_type);
@@ -214,8 +215,33 @@ void WebRemoteFrameImpl::InitializeCoreFrame(
previous_sibling ? ToCoreFrame(*previous_sibling) : nullptr;
SetCoreFrame(MakeGarbageCollected<RemoteFrame>(
frame_client_.Get(), page, owner, parent_frame, previous_sibling_frame,
- insert_type, GetFrameToken(), window_agent_factory, interface_registry_,
- associated_interface_provider_));
+ insert_type, GetRemoteFrameToken(), window_agent_factory,
+ interface_registry_, associated_interface_provider_));
+
+ // If this is not a top-level frame, we need to send FrameVisualProperties to
+ // the remote renderer process. Some of the properties are inherited from the
+ // WebFrameWidget containing this frame, and this is true for regular frames
+ // in the frame tree as well as for portals, which are not in the frame tree;
+ // hence the code to traverse up through FrameOwner.
+ WebFrameWidget* ancestor_widget = nullptr;
+ if (parent) {
+ while (parent && !parent->IsWebLocalFrame())
+ parent = parent->Parent();
+ if (parent) {
+ ancestor_widget =
+ To<WebLocalFrameImpl>(parent)->LocalRoot()->FrameWidget();
+ }
+ } else if (owner && owner->IsLocal()) {
+ ancestor_widget =
+ WebLocalFrameImpl::FromFrame(To<HTMLFrameOwnerElement>(owner)
+ ->GetDocument()
+ .GetFrame()
+ ->LocalFrameRoot())
+ ->FrameWidget();
+ }
+ if (ancestor_widget)
+ InitializeFrameVisualProperties(ancestor_widget, View());
+
GetFrame()->CreateView();
frame_->Tree().SetName(name);
}
@@ -226,9 +252,9 @@ WebRemoteFrame* WebRemoteFrameImpl::CreateRemoteChild(
const FramePolicy& frame_policy,
mojom::blink::FrameOwnerElementType frame_owner_element_type,
WebRemoteFrameClient* client,
- blink::InterfaceRegistry* interface_registry,
+ InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WebFrame* opener) {
auto* child = MakeGarbageCollected<WebRemoteFrameImpl>(
scope, client, interface_registry, associated_interface_provider,
@@ -251,16 +277,32 @@ WebRemoteFrame* WebRemoteFrameImpl::CreateRemoteChild(
}
void WebRemoteFrameImpl::SetCcLayer(cc::Layer* layer,
- bool prevent_contents_opaque_changes,
bool is_surface_layer) {
- GetFrame()->SetCcLayer(layer, prevent_contents_opaque_changes,
- is_surface_layer);
+ GetFrame()->SetCcLayer(layer, is_surface_layer);
}
void WebRemoteFrameImpl::SetCoreFrame(RemoteFrame* frame) {
frame_ = frame;
}
+void WebRemoteFrameImpl::InitializeFrameVisualProperties(
+ WebFrameWidget* ancestor_widget,
+ WebView* web_view) {
+ FrameVisualProperties visual_properties;
+ visual_properties.zoom_level = web_view->ZoomLevel();
+ visual_properties.page_scale_factor = ancestor_widget->PageScaleInMainFrame();
+ visual_properties.is_pinch_gesture_active =
+ ancestor_widget->PinchGestureActiveInMainFrame();
+ visual_properties.screen_info = ancestor_widget->GetOriginalScreenInfo();
+ visual_properties.visible_viewport_size =
+ ancestor_widget->VisibleViewportSizeInDIPs();
+ const WebVector<gfx::Rect>& window_segments =
+ ancestor_widget->WindowSegments();
+ visual_properties.root_widget_window_segments.assign(window_segments.begin(),
+ window_segments.end());
+ GetFrame()->InitializeFrameVisualProperties(visual_properties);
+}
+
WebRemoteFrameImpl* WebRemoteFrameImpl::FromFrame(RemoteFrame& frame) {
if (!frame.Client())
return nullptr;
@@ -289,22 +331,16 @@ void WebRemoteFrameImpl::SetReplicatedName(const WebString& name,
GetFrame()->SetReplicatedName(name, unique_name);
}
-void WebRemoteFrameImpl::SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- const ParsedFeaturePolicy& parsed_header,
- const FeaturePolicyFeatureState& opener_feature_state) {
+void WebRemoteFrameImpl::SetReplicatedFeaturePolicyHeader(
+ const ParsedFeaturePolicy& parsed_header) {
DCHECK(GetFrame());
- GetFrame()->SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- parsed_header, opener_feature_state);
+ GetFrame()->SetReplicatedFeaturePolicyHeader(parsed_header);
}
-void WebRemoteFrameImpl::AddReplicatedContentSecurityPolicyHeader(
- const WebString& header_value,
- network::mojom::ContentSecurityPolicyType type,
- network::mojom::ContentSecurityPolicySource source) {
- GetFrame()
- ->GetSecurityContext()
- ->GetContentSecurityPolicy()
- ->AddPolicyFromHeaderValue(header_value, type, source);
+void WebRemoteFrameImpl::AddReplicatedContentSecurityPolicies(
+ const WebVector<WebContentSecurityPolicy>& csps) {
+ GetFrame()->GetSecurityContext()->GetContentSecurityPolicy()->AddPolicies(
+ ConvertToMojoBlink(csps));
}
void WebRemoteFrameImpl::ResetReplicatedContentSecurityPolicy() {
@@ -354,20 +390,41 @@ v8::Local<v8::Object> WebRemoteFrameImpl::GlobalProxy() const {
->GlobalProxyIfNotDetached();
}
-WebRect WebRemoteFrameImpl::GetCompositingRect() {
+gfx::Rect WebRemoteFrameImpl::GetCompositingRect() {
return GetFrame()->View()->GetCompositingRect();
}
+void WebRemoteFrameImpl::SynchronizeVisualProperties() {
+ GetFrame()->SynchronizeVisualProperties();
+}
+
+void WebRemoteFrameImpl::ResendVisualProperties() {
+ GetFrame()->ResendVisualProperties();
+}
+
+float WebRemoteFrameImpl::GetCompositingScaleFactor() {
+ return GetFrame()->View()->GetCompositingScaleFactor();
+}
+
WebString WebRemoteFrameImpl::UniqueName() const {
return GetFrame()->UniqueName();
}
+const FrameVisualProperties&
+WebRemoteFrameImpl::GetPendingVisualPropertiesForTesting() const {
+ return GetFrame()->GetPendingVisualPropertiesForTesting();
+}
+
+bool WebRemoteFrameImpl::IsAdSubframe() const {
+ return GetFrame()->IsAdSubframe();
+}
+
WebRemoteFrameImpl::WebRemoteFrameImpl(
mojom::blink::TreeScopeType scope,
WebRemoteFrameClient* client,
InterfaceRegistry* interface_registry,
AssociatedInterfaceProvider* associated_interface_provider,
- const base::UnguessableToken& frame_token)
+ const RemoteFrameToken& frame_token)
: WebRemoteFrame(scope, frame_token),
client_(client),
frame_client_(MakeGarbageCollected<RemoteFrameClientImpl>(this)),
diff --git a/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.h b/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
index 210d99e58a3..d9ab22134a3 100644
--- a/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
+++ b/chromium/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_REMOTE_FRAME_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_REMOTE_FRAME_IMPL_H_
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink-forward.h"
@@ -22,11 +23,12 @@ class Layer;
namespace blink {
class FrameOwner;
+struct FrameVisualProperties;
class RemoteFrame;
class RemoteFrameClientImpl;
enum class WebFrameLoadType;
+class WebFrameWidget;
class WebView;
-struct WebRect;
class WindowAgentFactory;
class CORE_EXPORT WebRemoteFrameImpl final
@@ -38,21 +40,21 @@ class CORE_EXPORT WebRemoteFrameImpl final
WebRemoteFrameClient*,
InterfaceRegistry*,
AssociatedInterfaceProvider*,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WebFrame* opener);
static WebRemoteFrameImpl* CreateForPortal(
mojom::blink::TreeScopeType,
WebRemoteFrameClient*,
InterfaceRegistry*,
AssociatedInterfaceProvider*,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
const WebElement& portal_element);
WebRemoteFrameImpl(mojom::blink::TreeScopeType,
WebRemoteFrameClient*,
InterfaceRegistry*,
AssociatedInterfaceProvider*,
- const base::UnguessableToken& frame_token);
+ const RemoteFrameToken& frame_token);
~WebRemoteFrameImpl() override;
// WebFrame methods:
@@ -65,11 +67,11 @@ class CORE_EXPORT WebRemoteFrameImpl final
const WebString& name,
const FramePolicy&,
WebLocalFrameClient*,
- blink::InterfaceRegistry*,
+ InterfaceRegistry*,
WebFrame* previous_sibling,
const WebFrameOwnerProperties&,
mojom::FrameOwnerElementType,
- const base::UnguessableToken& frame_token,
+ const LocalFrameToken& frame_token,
WebFrame* opener,
std::unique_ptr<blink::WebPolicyContainer> policy_container) override;
WebRemoteFrame* CreateRemoteChild(mojom::blink::TreeScopeType,
@@ -77,13 +79,11 @@ class CORE_EXPORT WebRemoteFrameImpl final
const FramePolicy&,
mojom::FrameOwnerElementType,
WebRemoteFrameClient*,
- blink::InterfaceRegistry*,
+ InterfaceRegistry*,
AssociatedInterfaceProvider*,
- const base::UnguessableToken& frame_token,
+ const RemoteFrameToken& frame_token,
WebFrame* opener) override;
- void SetCcLayer(cc::Layer*,
- bool prevent_contents_opaque_changes,
- bool is_surface_layer) override;
+ void SetCcLayer(cc::Layer*, bool is_surface_layer) override;
void SetReplicatedOrigin(
const WebSecurityOrigin&,
bool is_potentially_trustworthy_opaque_origin) override;
@@ -91,13 +91,10 @@ class CORE_EXPORT WebRemoteFrameImpl final
network::mojom::blink::WebSandboxFlags) override;
void SetReplicatedName(const WebString& name,
const WebString& unique_name) override;
- void SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
- const ParsedFeaturePolicy& parsed_header,
- const FeaturePolicyFeatureState&) override;
- void AddReplicatedContentSecurityPolicyHeader(
- const WebString& header_value,
- network::mojom::ContentSecurityPolicyType,
- network::mojom::ContentSecurityPolicySource) override;
+ void SetReplicatedFeaturePolicyHeader(
+ const ParsedFeaturePolicy& parsed_header) override;
+ void AddReplicatedContentSecurityPolicies(
+ const WebVector<WebContentSecurityPolicy>& csps) override;
void ResetReplicatedContentSecurityPolicy() override;
void SetReplicatedInsecureRequestPolicy(
mojom::blink::InsecureRequestPolicy) override;
@@ -111,8 +108,13 @@ class CORE_EXPORT WebRemoteFrameImpl final
mojom::blink::UserActivationNotificationType notification_type) override;
void SetHadStickyUserActivationBeforeNavigation(bool value) override;
v8::Local<v8::Object> GlobalProxy() const override;
- WebRect GetCompositingRect() override;
+ void SynchronizeVisualProperties() override;
+ void ResendVisualProperties() override;
+ float GetCompositingScaleFactor() override;
WebString UniqueName() const override;
+ const FrameVisualProperties& GetPendingVisualPropertiesForTesting()
+ const override;
+ bool IsAdSubframe() const override;
void InitializeCoreFrame(Page&,
FrameOwner*,
WebFrame* parent,
@@ -128,10 +130,14 @@ class CORE_EXPORT WebRemoteFrameImpl final
void Trace(Visitor*) const;
+ gfx::Rect GetCompositingRect();
+
private:
friend class RemoteFrameClientImpl;
void SetCoreFrame(RemoteFrame*);
+ void InitializeFrameVisualProperties(WebFrameWidget* ancestor_widget,
+ WebView* web_view);
// Inherited from WebFrame, but intentionally hidden: it never makes sense
// to call these on a WebRemoteFrameImpl.
diff --git a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
deleted file mode 100644
index 53afc8ec6ef..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
+++ /dev/null
@@ -1,764 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be found
-// in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
-
-#include "build/build_config.h"
-#include "third_party/blink/public/common/input/web_keyboard_event.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/web_autofill_client.h"
-#include "third_party/blink/public/web/web_view_client.h"
-#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/events/ui_event_with_key_state.h"
-#include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
-#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
-#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
-#include "third_party/blink/renderer/core/exported/web_settings_impl.h"
-#include "third_party/blink/renderer/core/exported/web_view_impl.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
-#include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/html/html_plugin_element.h"
-#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
-#include "third_party/blink/renderer/core/input/event_handler.h"
-#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/page/context_menu_controller.h"
-#include "third_party/blink/renderer/core/page/focus_controller.h"
-#include "third_party/blink/renderer/core/page/link_highlight.h"
-#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
-#include "third_party/blink/renderer/platform/keyboard_codes.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/blink/renderer/platform/widget/widget_base.h"
-
-namespace blink {
-
-WebViewFrameWidget::WebViewFrameWidget(
- util::PassKey<WebFrameWidget>,
- WebWidgetClient& client,
- WebViewImpl& web_view,
- CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
- frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- widget,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool is_for_nested_main_frame,
- bool hidden,
- bool never_composited)
- : WebFrameWidgetBase(client,
- std::move(frame_widget_host),
- std::move(frame_widget),
- std::move(widget_host),
- std::move(widget),
- task_runner,
- frame_sink_id,
- hidden,
- never_composited,
- /*is_for_child_local_root=*/false),
- web_view_(&web_view),
- is_for_nested_main_frame_(is_for_nested_main_frame),
- self_keep_alive_(PERSISTENT_FROM_HERE, this) {
- web_view_->SetMainFrameViewWidget(this);
-}
-
-WebViewFrameWidget::~WebViewFrameWidget() = default;
-
-void WebViewFrameWidget::Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) {
- GetPage()->WillCloseAnimationHost(nullptr);
- // Closing the WebViewFrameWidget happens in response to the local main frame
- // being detached from the Page/WebViewImpl.
- web_view_->SetMainFrameViewWidget(nullptr);
- web_view_ = nullptr;
- WebFrameWidgetBase::Close(std::move(cleanup_runner));
- self_keep_alive_.Clear();
-}
-
-gfx::Size WebViewFrameWidget::Size() {
- return gfx::Size(web_view_->Size());
-}
-
-void WebViewFrameWidget::Resize(const gfx::Size& size) {
- size_ = size;
- web_view_->Resize(size);
-}
-
-void WebViewFrameWidget::UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason) {
- web_view_->UpdateLifecycle(requested_update, reason);
-}
-
-void WebViewFrameWidget::ApplyViewportChanges(
- const ApplyViewportChangesArgs& args) {
- web_view_->ApplyViewportChanges(args);
-}
-
-void WebViewFrameWidget::RecordManipulationTypeCounts(
- cc::ManipulationInfo info) {
- web_view_->RecordManipulationTypeCounts(info);
-}
-
-void WebViewFrameWidget::MouseCaptureLost() {
- mouse_capture_element_ = nullptr;
- web_view_->MouseCaptureLost();
-}
-
-void WebViewFrameWidget::FocusChanged(bool enable) {
- web_view_->SetFocus(enable);
-}
-
-float WebViewFrameWidget::GetDeviceScaleFactorForTesting() {
- return device_scale_factor_for_testing_;
-}
-
-gfx::Rect WebViewFrameWidget::ViewportVisibleRect() {
- return widget_base_->CompositorViewportRect();
-}
-
-bool WebViewFrameWidget::ShouldHandleImeEvents() {
- return HasFocus();
-}
-
-void WebViewFrameWidget::SetWindowRect(const gfx::Rect& window_rect) {
- if (synchronous_resize_mode_for_testing_) {
- // This is a web-test-only path. At one point, it was planned to be
- // removed. See https://crbug.com/309760.
- SetWindowRectSynchronously(window_rect);
- return;
- }
- View()->SetWindowRect(window_rect);
-}
-
-float WebViewFrameWidget::GetEmulatorScale() {
- if (device_emulator_)
- return device_emulator_->scale();
- return 1.0f;
-}
-
-void WebViewFrameWidget::CalculateSelectionBounds(gfx::Rect& anchor_root_frame,
- gfx::Rect& focus_root_frame) {
- const Frame* frame = View()->FocusedCoreFrame();
- const auto* local_frame = DynamicTo<LocalFrame>(frame);
- if (!local_frame)
- return;
-
- LocalFrameView* frame_view = local_frame->View();
- if (!frame_view)
- return;
-
- IntRect anchor;
- IntRect focus;
- if (!local_frame->Selection().ComputeAbsoluteBounds(anchor, focus))
- return;
-
- VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
- anchor_root_frame = visual_viewport.RootFrameToViewport(
- frame_view->ConvertToRootFrame(anchor));
- focus_root_frame = visual_viewport.RootFrameToViewport(
- frame_view->ConvertToRootFrame(focus));
-}
-
-void WebViewFrameWidget::EnableDeviceEmulation(
- const DeviceEmulationParams& parameters) {
- if (!device_emulator_) {
- gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(size_);
-
- device_emulator_ = MakeGarbageCollected<ScreenMetricsEmulator>(
- this, widget_base_->GetScreenInfo(), size_in_dips,
- widget_base_->VisibleViewportSizeInDIPs(),
- widget_base_->WidgetScreenRect(), widget_base_->WindowScreenRect());
- }
- device_emulator_->ChangeEmulationParams(parameters);
-}
-
-void WebViewFrameWidget::DisableDeviceEmulation() {
- if (!device_emulator_)
- return;
- device_emulator_->DisableAndApply();
- device_emulator_ = nullptr;
-}
-
-bool WebViewFrameWidget::ScrollFocusedEditableElementIntoView() {
- return web_view_->ScrollFocusedEditableElementIntoView();
-}
-
-void WebViewFrameWidget::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
- if (!web_view_->does_composite()) {
- DCHECK(!root_layer);
- return;
- }
- cc::LayerTreeHost* layer_tree_host = widget_base_->LayerTreeHost();
- layer_tree_host->SetRootLayer(root_layer);
- web_view_->DidChangeRootLayer(!!root_layer);
-}
-
-void WebViewFrameWidget::ZoomToFindInPageRect(
- const WebRect& rect_in_root_frame) {
- web_view_->ZoomToFindInPageRect(rect_in_root_frame);
-}
-
-void WebViewFrameWidget::Trace(Visitor* visitor) const {
- WebFrameWidgetBase::Trace(visitor);
- visitor->Trace(device_emulator_);
-}
-
-WebInputEventResult WebViewFrameWidget::HandleKeyEvent(
- const WebKeyboardEvent& event) {
- DCHECK((event.GetType() == WebInputEvent::Type::kRawKeyDown) ||
- (event.GetType() == WebInputEvent::Type::kKeyDown) ||
- (event.GetType() == WebInputEvent::Type::kKeyUp));
- TRACE_EVENT2("input", "WebViewFrameWidget::HandleKeyEvent", "type",
- WebInputEvent::GetName(event.GetType()), "text",
- String(event.text).Utf8());
-
- // Please refer to the comments explaining |suppress_next_keypress_event_|.
- //
- // |suppress_next_keypress_event_| is set if the KeyDown is handled by
- // Webkit. A keyDown event is typically associated with a keyPress(char)
- // event and a keyUp event. We reset this flag here as this is a new keyDown
- // event.
- suppress_next_keypress_event_ = false;
-
- // If there is a popup, it should be the one processing the event, not the
- // page.
- scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
- if (page_popup) {
- page_popup->HandleKeyEvent(event);
- // We need to ignore the next Char event after this otherwise pressing
- // enter when selecting an item in the popup will go to the page.
- if (WebInputEvent::Type::kRawKeyDown == event.GetType())
- suppress_next_keypress_event_ = true;
- return WebInputEventResult::kHandledSystem;
- }
-
- Frame* focused_frame = web_view_->FocusedCoreFrame();
- auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame);
- if (!focused_local_frame)
- return WebInputEventResult::kNotHandled;
-
- WebInputEventResult result =
- focused_local_frame->GetEventHandler().KeyEvent(event);
- if (result != WebInputEventResult::kNotHandled) {
- if (WebInputEvent::Type::kRawKeyDown == event.GetType()) {
- // Suppress the next keypress event unless the focused node is a plugin
- // node. (Flash needs these keypress events to handle non-US keyboards.)
- Element* element = web_view_->FocusedElement();
- if (element && element->GetLayoutObject() &&
- element->GetLayoutObject()->IsEmbeddedObject()) {
- if (event.windows_key_code == VKEY_TAB) {
- // If the plugin supports keyboard focus then we should not send a tab
- // keypress event.
- WebPluginContainerImpl* plugin_view =
- To<LayoutEmbeddedContent>(element->GetLayoutObject())->Plugin();
- if (plugin_view && plugin_view->SupportsKeyboardFocus()) {
- suppress_next_keypress_event_ = true;
- }
- }
- } else {
- suppress_next_keypress_event_ = true;
- }
- }
- return result;
- }
-
-#if !defined(OS_MAC)
- const WebInputEvent::Type kContextMenuKeyTriggeringEventType =
-#if defined(OS_WIN)
- WebInputEvent::Type::kKeyUp;
-#else
- WebInputEvent::Type::kRawKeyDown;
-#endif
- const WebInputEvent::Type kShiftF10TriggeringEventType =
- WebInputEvent::Type::kRawKeyDown;
-
- bool is_unmodified_menu_key =
- !(event.GetModifiers() & WebInputEvent::kInputModifiers) &&
- event.windows_key_code == VKEY_APPS;
- bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) ==
- WebInputEvent::kShiftKey &&
- event.windows_key_code == VKEY_F10;
- if ((is_unmodified_menu_key &&
- event.GetType() == kContextMenuKeyTriggeringEventType) ||
- (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) {
- View()->SendContextMenuEvent();
- return WebInputEventResult::kHandledSystem;
- }
-#endif // !defined(OS_MAC)
-
- return WebInputEventResult::kNotHandled;
-}
-
-void WebViewFrameWidget::HandleMouseLeave(LocalFrame& main_frame,
- const WebMouseEvent& event) {
- web_view_->SetMouseOverURL(WebURL());
- PageWidgetEventHandler::HandleMouseLeave(main_frame, event);
-}
-
-WebInputEventResult WebViewFrameWidget::HandleGestureEvent(
- const WebGestureEvent& event) {
- if (!web_view_->Client() || !web_view_->Client()->CanHandleGestureEvent()) {
- return WebInputEventResult::kNotHandled;
- }
-
- // TODO(https://crbug.com/1148346): We need to figure out why MainFrameImpl is
- // null but LocalRootImpl isn't.
- CHECK(LocalRootImpl());
- if (!web_view_->MainFrameImpl())
- return WebInputEventResult::kNotHandled;
-
- WebInputEventResult event_result = WebInputEventResult::kNotHandled;
- bool event_cancelled = false; // for disambiguation
-
- // Fling events are not sent to the renderer.
- CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingStart);
- CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingCancel);
-
- WebGestureEvent scaled_event = TransformWebGestureEvent(
- web_view_->MainFrameImpl()->GetFrameView(), event);
-
- // Special handling for double tap and scroll events as we don't want to
- // hit test for them.
- switch (event.GetType()) {
- case WebInputEvent::Type::kGestureDoubleTap:
- if (web_view_->SettingsImpl()->DoubleTapToZoomEnabled() &&
- web_view_->MinimumPageScaleFactor() !=
- web_view_->MaximumPageScaleFactor()) {
- if (auto* main_frame = web_view_->MainFrameImpl()) {
- IntPoint pos_in_root_frame =
- FlooredIntPoint(scaled_event.PositionInRootFrame());
- WebRect block_bounds =
- main_frame->FrameWidgetImpl()->ComputeBlockBound(
- pos_in_root_frame, false);
- web_view_->AnimateDoubleTapZoom(pos_in_root_frame, block_bounds);
- }
- }
- event_result = WebInputEventResult::kHandledSystem;
- DidHandleGestureEvent(event, event_cancelled);
- return event_result;
- case WebInputEvent::Type::kGestureScrollBegin:
- case WebInputEvent::Type::kGestureScrollEnd:
- case WebInputEvent::Type::kGestureScrollUpdate:
- // Scrolling-related gesture events invoke EventHandler recursively for
- // each frame down the chain, doing a single-frame hit-test per frame.
- // This matches handleWheelEvent. Perhaps we could simplify things by
- // rewriting scroll handling to work inner frame out, and then unify with
- // other gesture events.
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureScrollEvent(scaled_event);
- DidHandleGestureEvent(event, event_cancelled);
- return event_result;
- default:
- break;
- }
-
- // Hit test across all frames and do touch adjustment as necessary for the
- // event type.
- GestureEventWithHitTestResults targeted_event =
- GetPage()
- ->DeprecatedLocalMainFrame()
- ->GetEventHandler()
- .TargetGestureEvent(scaled_event);
-
- // Handle link highlighting outside the main switch to avoid getting lost in
- // the complicated set of cases handled below.
- switch (event.GetType()) {
- case WebInputEvent::Type::kGestureShowPress:
- // Queue a highlight animation, then hand off to regular handler.
- web_view_->EnableTapHighlightAtPoint(targeted_event);
- break;
- case WebInputEvent::Type::kGestureTapCancel:
- case WebInputEvent::Type::kGestureTap:
- case WebInputEvent::Type::kGestureLongPress:
- GetPage()->GetLinkHighlight().StartHighlightAnimationIfNeeded();
- break;
- default:
- break;
- }
-
- switch (event.GetType()) {
- case WebInputEvent::Type::kGestureTap: {
- {
- ContextMenuAllowedScope scope;
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- }
-
- if (web_view_->GetPagePopup() && last_hidden_page_popup_ &&
- web_view_->GetPagePopup()->HasSamePopupClient(
- last_hidden_page_popup_.get())) {
- // The tap triggered a page popup that is the same as the one we just
- // closed. It needs to be closed.
- web_view_->CancelPagePopup();
- }
- // Don't have this value persist outside of a single tap gesture, plus
- // we're done with it now.
- last_hidden_page_popup_ = nullptr;
- break;
- }
- case WebInputEvent::Type::kGestureTwoFingerTap:
- case WebInputEvent::Type::kGestureLongPress:
- case WebInputEvent::Type::kGestureLongTap: {
- if (!web_view_->MainFrameImpl() ||
- !web_view_->MainFrameImpl()->GetFrameView())
- break;
-
- if (event.GetType() == WebInputEvent::Type::kGestureLongTap) {
- if (LocalFrame* inner_frame =
- targeted_event.GetHitTestResult().InnerNodeFrame()) {
- if (!inner_frame->GetEventHandler().LongTapShouldInvokeContextMenu())
- break;
- } else if (!web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .LongTapShouldInvokeContextMenu()) {
- break;
- }
- }
-
- GetPage()->GetContextMenuController().ClearContextMenu();
- {
- ContextMenuAllowedScope scope;
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- }
-
- break;
- }
- case WebInputEvent::Type::kGestureTapDown: {
- // Touch pinch zoom and scroll on the page (outside of a popup) must hide
- // the popup. In case of a touch scroll or pinch zoom, this function is
- // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
- // When we close a popup because of a GestureTapDown, we also save it so
- // we can prevent the following GestureTap from immediately reopening the
- // same popup.
- // This value should not persist outside of a gesture, so is cleared by
- // GestureTap (where it is used) and by GestureCancel.
- last_hidden_page_popup_ = web_view_->GetPagePopup();
- web_view_->CancelPagePopup();
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- break;
- }
- case WebInputEvent::Type::kGestureTapCancel: {
- // Don't have this value persist outside of a single tap gesture.
- last_hidden_page_popup_ = nullptr;
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- break;
- }
- case WebInputEvent::Type::kGestureShowPress: {
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- break;
- }
- case WebInputEvent::Type::kGestureTapUnconfirmed: {
- event_result = web_view_->MainFrameImpl()
- ->GetFrame()
- ->GetEventHandler()
- .HandleGestureEvent(targeted_event);
- break;
- }
- default: {
- NOTREACHED();
- }
- }
- DidHandleGestureEvent(event, event_cancelled);
- return event_result;
-}
-
-LocalFrameView* WebViewFrameWidget::GetLocalFrameViewForAnimationScrolling() {
- // Scrolling for the root frame is special we need to pass null indicating
- // we are at the top of the tree when setting up the Animation. Which will
- // cause ownership of the timeline and animation host.
- // See ScrollingCoordinator::AnimationHostInitialized.
- return nullptr;
-}
-
-void WebViewFrameWidget::SetZoomLevelForTesting(double zoom_level) {
- DCHECK_NE(zoom_level, -INFINITY);
- zoom_level_for_testing_ = zoom_level;
- SetZoomLevel(zoom_level);
-}
-
-void WebViewFrameWidget::ResetZoomLevelForTesting() {
- zoom_level_for_testing_ = -INFINITY;
- SetZoomLevel(0);
-}
-
-void WebViewFrameWidget::SetDeviceScaleFactorForTesting(float factor) {
- DCHECK_GE(factor, 0.f);
-
- // Stash the window size before we adjust the scale factor, as subsequent
- // calls to convert will use the new scale factor.
- gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(size_);
- device_scale_factor_for_testing_ = factor;
-
- // Receiving a 0 is used to reset between tests, it removes the override in
- // order to listen to the browser for the next test.
- if (!factor)
- return;
-
- // We are changing the device scale factor from the renderer, so allocate a
- // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
- widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
-
- ScreenInfo info = widget_base_->GetScreenInfo();
- info.device_scale_factor = factor;
- gfx::Size size_with_dsf = gfx::ScaleToCeiledSize(size_in_dips, factor);
- widget_base_->UpdateCompositorViewportAndScreenInfo(gfx::Rect(size_with_dsf),
- info);
- if (!AutoResizeMode()) {
- // This picks up the new device scale factor as
- // UpdateCompositorViewportAndScreenInfo has applied a new value.
- Resize(widget_base_->DIPsToCeiledBlinkSpace(size_in_dips));
- }
-}
-
-void WebViewFrameWidget::SetZoomLevel(double zoom_level) {
- // Override the zoom level with the testing one if necessary
- if (zoom_level_for_testing_ != -INFINITY)
- zoom_level = zoom_level_for_testing_;
- WebFrameWidgetBase::SetZoomLevel(zoom_level);
-}
-
-void WebViewFrameWidget::SetAutoResizeMode(bool auto_resize,
- const gfx::Size& min_window_size,
- const gfx::Size& max_window_size,
- float device_scale_factor) {
- if (auto_resize) {
- if (!Platform::Current()->IsUseZoomForDSFEnabled())
- device_scale_factor = 1.f;
- web_view_->EnableAutoResizeMode(
- gfx::ScaleToCeiledSize(min_window_size, device_scale_factor),
- gfx::ScaleToCeiledSize(max_window_size, device_scale_factor));
- } else if (web_view_->AutoResizeMode()) {
- web_view_->DisableAutoResizeMode();
- }
-}
-
-void WebViewFrameWidget::SetIsNestedMainFrameWidget(bool is_nested) {
- is_for_nested_main_frame_ = is_nested;
-}
-
-void WebViewFrameWidget::SetPageScaleStateAndLimits(
- float page_scale_factor,
- bool is_pinch_gesture_active,
- float minimum,
- float maximum) {
- WebFrameWidgetBase::SetPageScaleStateAndLimits(
- page_scale_factor, is_pinch_gesture_active, minimum, maximum);
-
- // If page scale hasn't changed, then just return without notifying
- // the remote frames.
- if (page_scale_factor == page_scale_factor_in_mainframe_ &&
- is_pinch_gesture_active == is_pinch_gesture_active_in_mainframe_) {
- return;
- }
-
- NotifyPageScaleFactorChanged(page_scale_factor, is_pinch_gesture_active);
-}
-
-void WebViewFrameWidget::DidAutoResize(const gfx::Size& size) {
- gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(size);
- size_ = size;
-
- if (synchronous_resize_mode_for_testing_) {
- gfx::Rect new_pos(widget_base_->WindowRect());
- new_pos.set_size(size_in_dips);
- SetScreenRects(new_pos, new_pos);
- }
-
- // TODO(ccameron): Note that this destroys any information differentiating
- // |size| from the compositor's viewport size.
- gfx::Rect size_with_dsf = gfx::Rect(gfx::ScaleToCeiledSize(
- gfx::Rect(size_in_dips).size(),
- widget_base_->GetScreenInfo().device_scale_factor));
- widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
- widget_base_->UpdateCompositorViewportRect(size_with_dsf);
-}
-
-void WebViewFrameWidget::SetDeviceColorSpaceForTesting(
- const gfx::ColorSpace& color_space) {
- // We are changing the device color space from the renderer, so allocate a
- // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
- widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
-
- blink::ScreenInfo info = widget_base_->GetScreenInfo();
- info.display_color_spaces = gfx::DisplayColorSpaces(color_space);
- widget_base_->UpdateScreenInfo(info);
-}
-
-bool WebViewFrameWidget::AutoResizeMode() {
- return web_view_->AutoResizeMode();
-}
-
-bool WebViewFrameWidget::UpdateScreenRects(
- const gfx::Rect& widget_screen_rect,
- const gfx::Rect& window_screen_rect) {
- if (!device_emulator_)
- return false;
- device_emulator_->OnUpdateScreenRects(widget_screen_rect, window_screen_rect);
- return true;
-}
-
-void WebViewFrameWidget::RunPaintBenchmark(int repeat_count,
- cc::PaintBenchmarkResult& result) {
- web_view_->RunPaintBenchmark(repeat_count, result);
-}
-
-const ScreenInfo& WebViewFrameWidget::GetOriginalScreenInfo() {
- if (device_emulator_)
- return device_emulator_->original_screen_info();
- return GetScreenInfo();
-}
-
-ScreenMetricsEmulator* WebViewFrameWidget::DeviceEmulator() {
- return device_emulator_;
-}
-
-void WebViewFrameWidget::SetScreenMetricsEmulationParameters(
- bool enabled,
- const DeviceEmulationParams& params) {
- if (enabled)
- View()->ActivateDevToolsTransform(params);
- else
- View()->DeactivateDevToolsTransform();
-}
-
-void WebViewFrameWidget::SetScreenInfoAndSize(
- const ScreenInfo& screen_info,
- const gfx::Size& widget_size_in_dips,
- const gfx::Size& visible_viewport_size_in_dips) {
- // Emulation happens on regular main frames which don't use auto-resize mode.
- DCHECK(!web_view_->AutoResizeMode());
-
- UpdateScreenInfo(screen_info);
- widget_base_->SetVisibleViewportSizeInDIPs(visible_viewport_size_in_dips);
- Resize(widget_base_->DIPsToCeiledBlinkSpace(widget_size_in_dips));
-}
-
-void WebViewFrameWidget::SetWindowRectSynchronouslyForTesting(
- const gfx::Rect& new_window_rect) {
- SetWindowRectSynchronously(new_window_rect);
-}
-
-void WebViewFrameWidget::SetWindowRectSynchronously(
- const gfx::Rect& new_window_rect) {
- // This method is only call in tests, and it applies the |new_window_rect| to
- // all three of:
- // a) widget size (in |size_|)
- // b) blink viewport (in |visible_viewport_size_|)
- // c) compositor viewport (in cc::LayerTreeHost)
- // Normally the browser controls these three things independently, but this is
- // used in tests to control the size from the renderer.
-
- // We are resizing the window from the renderer, so allocate a new
- // viz::LocalSurfaceId to avoid surface invariants violations in tests.
- widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
-
- gfx::Rect compositor_viewport_pixel_rect(gfx::ScaleToCeiledSize(
- new_window_rect.size(),
- widget_base_->GetScreenInfo().device_scale_factor));
- widget_base_->UpdateSurfaceAndScreenInfo(
- widget_base_->local_surface_id_from_parent(),
- compositor_viewport_pixel_rect, widget_base_->GetScreenInfo());
-
- Resize(new_window_rect.size());
- widget_base_->SetScreenRects(new_window_rect, new_window_rect);
-}
-
-void WebViewFrameWidget::UseSynchronousResizeModeForTesting(bool enable) {
- synchronous_resize_mode_for_testing_ = enable;
-}
-
-gfx::Size WebViewFrameWidget::DIPsToCeiledBlinkSpace(const gfx::Size& size) {
- return widget_base_->DIPsToCeiledBlinkSpace(size);
-}
-
-void WebViewFrameWidget::ApplyVisualPropertiesSizing(
- const VisualProperties& visual_properties) {
- if (size_ !=
- widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)) {
- // Only hide popups when the size changes. Eg https://crbug.com/761908.
- web_view_->CancelPagePopup();
- }
-
- if (device_emulator_) {
- device_emulator_->UpdateVisualProperties(visual_properties);
- return;
- }
-
- SetWindowSegments(visual_properties.root_widget_window_segments);
-
- // We can ignore browser-initialized resizing during synchronous
- // (renderer-controlled) mode, unless it is switching us to/from
- // fullsreen mode or changing the device scale factor.
- bool ignore_resize = synchronous_resize_mode_for_testing_;
- if (ignore_resize) {
- // TODO(danakj): Does the browser actually change DSF inside a web test??
- // TODO(danakj): Isn't the display mode check redundant with the
- // fullscreen one?
- if (visual_properties.is_fullscreen_granted != IsFullscreenGranted() ||
- visual_properties.screen_info.device_scale_factor !=
- widget_base_->GetScreenInfo().device_scale_factor)
- ignore_resize = false;
- }
-
- // When controlling the size in the renderer, we should ignore sizes given
- // by the browser IPC here.
- // TODO(danakj): There are many things also being ignored that aren't the
- // widget's size params. It works because tests that use this mode don't
- // change those parameters, I guess. But it's more complicated then because
- // it looks like they are related to sync resize mode. Let's move them out
- // of this block.
- gfx::Rect new_compositor_viewport_pixel_rect =
- visual_properties.compositor_viewport_pixel_rect;
- if (AutoResizeMode()) {
- new_compositor_viewport_pixel_rect = gfx::Rect(gfx::ScaleToCeiledSize(
- widget_base_->BlinkSpaceToFlooredDIPs(size_),
- visual_properties.screen_info.device_scale_factor));
- }
-
- widget_base_->UpdateSurfaceAndScreenInfo(
- visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
- new_compositor_viewport_pixel_rect, visual_properties.screen_info);
-
- // Store this even when auto-resizing, it is the size of the full viewport
- // used for clipping, and this value is propagated down the Widget
- // hierarchy via the VisualProperties waterfall.
- widget_base_->SetVisibleViewportSizeInDIPs(
- visual_properties.visible_viewport_size);
-
- if (!AutoResizeMode()) {
- size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size);
-
- View()->ResizeWithBrowserControls(
- size_,
- widget_base_->DIPsToCeiledBlinkSpace(
- widget_base_->VisibleViewportSizeInDIPs()),
- visual_properties.browser_controls_params);
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h
deleted file mode 100644
index ab5f21eed60..00000000000
--- a/chromium/third_party/blink/renderer/core/frame/web_view_frame_widget.h
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be found
-// in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_VIEW_FRAME_WIDGET_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_VIEW_FRAME_WIDGET_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/util/type_safety/pass_key.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/exported/web_page_popup_impl.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
-
-namespace blink {
-
-class WebFrameWidget;
-class WebViewImpl;
-class WebWidgetClient;
-
-// Shim class to help normalize the widget interfaces in the Blink public API.
-// For OOPI, subframes have WebFrameWidgets for input and rendering.
-// Unfortunately, the main frame still uses WebView's WebWidget for input and
-// rendering. This results in complex code, since there are two different
-// implementations of WebWidget and code needs to have branches to handle both
-// cases.
-// This class allows a Blink embedder to create a WebFrameWidget that can be
-// used for the main frame. Internally, it currently wraps WebView's WebWidget
-// and just forwards almost everything to it.
-// After the embedder starts using a WebFrameWidget for the main frame,
-// WebView will be updated to no longer inherit WebWidget. The eventual goal is
-// to unfork the widget code duplicated in WebFrameWidgetImpl and WebViewImpl
-// into one class.
-// A more detailed writeup of this transition can be read at
-// https://goo.gl/7yVrnb.
-class CORE_EXPORT WebViewFrameWidget : public WebFrameWidgetBase {
- public:
- WebViewFrameWidget(
- util::PassKey<WebFrameWidget>,
- WebWidgetClient&,
- WebViewImpl&,
- CrossVariantMojoAssociatedRemote<
- mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
- widget,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool is_for_nested_main_frame,
- bool hidden,
- bool never_composited);
- ~WebViewFrameWidget() override;
-
- // WebWidget overrides:
- void Close(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) override;
- gfx::Size Size() override;
- void Resize(const gfx::Size& size_with_dsf) override;
- void UpdateLifecycle(WebLifecycleUpdate requested_update,
- DocumentUpdateReason reason) override;
- void MouseCaptureLost() override;
-
- // blink::mojom::FrameWidget
- void EnableDeviceEmulation(const DeviceEmulationParams& parameters) override;
- void DisableDeviceEmulation() override;
-
- // WebFrameWidget overrides:
- bool ScrollFocusedEditableElementIntoView() override;
- void SetZoomLevelForTesting(double zoom_level) override;
- void ResetZoomLevelForTesting() override;
- void SetDeviceScaleFactorForTesting(float factor) override;
-
- // WebFrameWidgetBase overrides:
- bool ForSubframe() const override { return false; }
- bool ForTopLevelFrame() const override { return !is_for_nested_main_frame_; }
- void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) override;
- void SetZoomLevel(double zoom_level) override;
- void SetAutoResizeMode(bool auto_resize,
- const gfx::Size& min_size_before_dsf,
- const gfx::Size& max_size_before_dsf,
- float device_scale_factor) override;
- void SetPageScaleStateAndLimits(float page_scale_factor,
- bool is_pinch_gesture_active,
- float minimum,
- float maximum) override;
- ScreenMetricsEmulator* DeviceEmulator() override;
- const ScreenInfo& GetOriginalScreenInfo() override;
- void ApplyVisualPropertiesSizing(
- const VisualProperties& visual_properties) override;
- void CalculateSelectionBounds(gfx::Rect& anchor, gfx::Rect& focus) override;
-
- // FrameWidget overrides:
- void SetRootLayer(scoped_refptr<cc::Layer>) override;
- bool ShouldHandleImeEvents() override;
- float GetEmulatorScale() override;
-
- // WidgetBaseClient overrides:
- void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override;
- void RecordManipulationTypeCounts(cc::ManipulationInfo info) override;
- void FocusChanged(bool enabled) override;
- float GetDeviceScaleFactorForTesting() override;
- gfx::Rect ViewportVisibleRect() override;
- bool UpdateScreenRects(const gfx::Rect& widget_screen_rect,
- const gfx::Rect& window_screen_rect) override;
- void RunPaintBenchmark(int repeat_count,
- cc::PaintBenchmarkResult& result) override;
-
- void SetScreenMetricsEmulationParameters(
- bool enabled,
- const blink::DeviceEmulationParams& params);
- void SetScreenInfoAndSize(const blink::ScreenInfo& screen_info,
- const gfx::Size& widget_size,
- const gfx::Size& visible_viewport_size);
-
- void Trace(Visitor*) const override;
-
- void SetIsNestedMainFrameWidget(bool is_nested);
- void DidAutoResize(const gfx::Size& size);
- void SetDeviceColorSpaceForTesting(const gfx::ColorSpace& color_space);
- bool AutoResizeMode();
- void SetWindowRect(const gfx::Rect& window_rect);
- void SetWindowRectSynchronouslyForTesting(const gfx::Rect& new_window_rect);
- void UseSynchronousResizeModeForTesting(bool enable);
-
- // Converts from DIPs to Blink coordinate space (ie. Viewport/Physical
- // pixels).
- gfx::Size DIPsToCeiledBlinkSpace(const gfx::Size& size);
-
- private:
- // PageWidgetEventHandler overrides:
- void HandleMouseLeave(LocalFrame&, const WebMouseEvent&) override;
- WebInputEventResult HandleGestureEvent(const WebGestureEvent&) override;
- WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) override;
-
- LocalFrameView* GetLocalFrameViewForAnimationScrolling() override;
- void SetWindowRectSynchronously(const gfx::Rect& new_window_rect);
-
- scoped_refptr<WebViewImpl> web_view_;
-
- // Web tests override the zoom factor in the renderer with this. We store it
- // to keep the override if the browser passes along VisualProperties with the
- // real device scale factor. A value of -INFINITY means this is ignored.
- double zoom_level_for_testing_ = -INFINITY;
-
- // Web tests override the device scale factor in the renderer with this. We
- // store it to keep the override if the browser passes along VisualProperties
- // with the real device scale factor. A value of 0.f means this is ignored.
- float device_scale_factor_for_testing_ = 0;
-
- // This bit is used to tell if this is a nested widget (an "inner web
- // contents") like a <webview> or <portal> widget. If false, the widget is the
- // top level widget.
- bool is_for_nested_main_frame_ = false;
-
- // Present when emulation is enabled, only in a main frame WidgetBase. Used
- // to override values given from the browser such as ScreenInfo,
- // WidgetScreenRect, WindowScreenRect, and the widget's size.
- Member<ScreenMetricsEmulator> device_emulator_;
-
- // In web tests, synchronous resizing mode may be used. Normally each widget's
- // size is controlled by IPC from the browser. In synchronous resize mode the
- // renderer controls the size directly, and IPCs from the browser must be
- // ignored. This was deprecated but then later undeprecated, so it is now
- // called unfortunate instead. See https://crbug.com/309760. When this is
- // enabled the various size properties will be controlled directly when
- // SetWindowRect() is called instead of needing a round trip through the
- // browser.
- // Note that SetWindowRectSynchronouslyForTesting() provides a secondary way
- // to control the size of the FrameWidget independently from the renderer
- // process, without the use of this mode, however it would be overridden by
- // the browser if they disagree.
- bool synchronous_resize_mode_for_testing_ = false;
-
- // The size of the widget in viewport coordinates. This is slightly different
- // than the WebViewImpl::size_ since isn't set in auto resize mode.
- gfx::Size size_;
-
- // This stores the last hidden page popup. If a GestureTap attempts to open
- // the popup that is closed by its previous GestureTapDown, the popup remains
- // closed.
- scoped_refptr<WebPagePopupImpl> last_hidden_page_popup_;
-
- SelfKeepAlive<WebViewFrameWidget> self_keep_alive_;
-
- DISALLOW_COPY_AND_ASSIGN(WebViewFrameWidget);
-};
-
-// Convenience type for creation method taken by
-// InstallCreateWebViewFrameWidgetHook(). The method signature matches the
-// WebViewFrameWidget constructor.
-using CreateWebViewFrameWidgetFunction =
- WebViewFrameWidget* (*)(util::PassKey<WebFrameWidget>,
- WebWidgetClient&,
- WebViewImpl&,
- CrossVariantMojoAssociatedRemote<
- mojom::blink::FrameWidgetHostInterfaceBase>
- frame_widget_host,
- CrossVariantMojoAssociatedReceiver<
- mojom::blink::FrameWidgetInterfaceBase>
- frame_widget,
- CrossVariantMojoAssociatedRemote<
- mojom::blink::WidgetHostInterfaceBase>
- widget_host,
- CrossVariantMojoAssociatedReceiver<
- mojom::blink::WidgetInterfaceBase> widget,
- scoped_refptr<base::SingleThreadTaskRunner>
- task_runner,
- const viz::FrameSinkId& frame_sink_id,
- bool is_for_nested_main_frame,
- bool hidden,
- bool never_composited);
-// Overrides the implementation of WebFrameWidget::CreateForMainFrame() function
-// below. Used by tests to override some functionality on WebViewFrameWidget.
-void CORE_EXPORT InstallCreateWebViewFrameWidgetHook(
- CreateWebViewFrameWidgetFunction create_widget);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WEB_VIEW_FRAME_WIDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/window.idl b/chromium/third_party/blink/renderer/core/frame/window.idl
index 1237ec42dfe..c817eabb268 100644
--- a/chromium/third_party/blink/renderer/core/frame/window.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window.idl
@@ -63,7 +63,17 @@
[CrossOrigin, Custom=Setter] attribute Window opener;
[Replaceable, CrossOrigin] readonly attribute Window? parent;
[CheckSecurity=ReturnValue, Custom=Getter] readonly attribute Element? frameElement;
- [CallWith=Isolate, RaisesException] Window? open(optional USVString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");
+
+ // The usage of |impression_params| is gated on a runtime enabled feature
+ // in the implementation rather than in this definition, because the
+ // RuntimeEnabled extended attribute cannot be used with an operation
+ // overload.
+ [CallWith=Isolate, RaisesException] Window? open(optional USVString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "", optional ImpressionParams impression_params);
+
+ // Overload which prevents exceptions caused by trying to convert a boolean
+ // to ImpressionParams when a boolean is passed as the fourth parameter.
+ // See https://crbug.com/1164959.
+ [CallWith=Isolate, RaisesException] Window? open(optional USVString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "", boolean unused);
// indexed properties
// https://html.spec.whatwg.org/C/browsers.html#windowproxy-getownproperty
@@ -76,10 +86,7 @@
[Affects=Nothing, LogActivity=GetterOnly] readonly attribute Navigator navigator;
[LogActivity=GetterOnly, SecureContext, RuntimeEnabled=AppCache] readonly attribute ApplicationCache applicationCache;
- // TODO(https://crbug.com/1157917): we implement the change at
- // https://github.com/whatwg/html/pull/6214 but should also rename the
- // backing implementation.
- [RuntimeEnabled=OriginIsolationHeader, ImplementedAs=originIsolated] readonly attribute boolean originAgentCluster;
+ [RuntimeEnabled=OriginIsolationHeader] readonly attribute boolean originAgentCluster;
// user prompts
[Measure, CallWith=ScriptState] void alert();
@@ -212,7 +219,7 @@
readonly attribute boolean isSecureContext;
// TrustedTypes API: http://github.com/wicg/trusted-types
- [RuntimeEnabled=TrustedDOMTypes] readonly attribute TrustedTypePolicyFactory trustedTypes;
+ [RuntimeEnabled=TrustedDOMTypes, CallWith=ScriptState] readonly attribute TrustedTypePolicyFactory trustedTypes;
};
Window includes GlobalEventHandlers;
diff --git a/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.cc b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.cc
new file mode 100644
index 00000000000..0804aa5ed53
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.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/core/frame/window_controls_overlay.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/heap/handle.h"
+
+namespace blink {
+
+// static
+const char WindowControlsOverlay::kSupplementName[] = "WindowControlsOverlay";
+
+// static
+WindowControlsOverlay& WindowControlsOverlay::From(Navigator& navigator) {
+ WindowControlsOverlay* supplement =
+ Supplement<Navigator>::From<WindowControlsOverlay>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<WindowControlsOverlay>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return *supplement;
+}
+
+// static
+WindowControlsOverlay* WindowControlsOverlay::windowControlsOverlay(
+ Navigator& navigator) {
+ return &From(navigator);
+}
+
+WindowControlsOverlay::WindowControlsOverlay(Navigator& navigator)
+ : Supplement<Navigator>(navigator) {}
+
+WindowControlsOverlay::~WindowControlsOverlay() = default;
+
+bool WindowControlsOverlay::visible() const {
+ if (!GetSupplementable()->DomWindow())
+ return false;
+
+ return GetSupplementable()
+ ->DomWindow()
+ ->GetFrame()
+ ->IsWindowControlsOverlayVisible();
+}
+
+DOMRect* WindowControlsOverlay::getBoundingClientRect() const {
+ if (!GetSupplementable()->DomWindow())
+ return DOMRect::Create(0, 0, 0, 0);
+
+ const auto& rect = GetSupplementable()
+ ->DomWindow()
+ ->GetFrame()
+ ->GetWindowControlsOverlayRect();
+ return DOMRect::Create(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+void WindowControlsOverlay::Trace(blink::Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ Supplement<Navigator>::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.h b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.h
new file mode 100644
index 00000000000..16a37311694
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.h
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WINDOW_CONTROLS_OVERLAY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WINDOW_CONTROLS_OVERLAY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/geometry/dom_rect.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Navigator;
+
+class CORE_EXPORT WindowControlsOverlay final : public ScriptWrappable,
+ public Supplement<Navigator> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static const char kSupplementName[];
+ // Web Exposed as navigator.windowControlsOverlay
+ static WindowControlsOverlay* windowControlsOverlay(Navigator& navigator);
+
+ static WindowControlsOverlay& From(Navigator& navigator);
+
+ explicit WindowControlsOverlay(Navigator& navigator);
+ WindowControlsOverlay(const WindowControlsOverlay&) = delete;
+ ~WindowControlsOverlay() override;
+
+ WindowControlsOverlay& operator=(const WindowControlsOverlay&) = delete;
+
+ bool visible() const;
+ DOMRect* getBoundingClientRect() const;
+
+ // ScriptWrappable
+ void Trace(Visitor*) const override;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WINDOW_CONTROLS_OVERLAY_H_
diff --git a/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.idl b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.idl
new file mode 100644
index 00000000000..1ef1d140698
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/frame/window_controls_overlay.idl
@@ -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.
+
+// https://github.com/WICG/window-controls-overlay/blob/master/explainer.md
+
+[
+ RuntimeEnabled=WebAppWindowControlsOverlay,
+ Exposed=Window
+] interface WindowControlsOverlay {
+ readonly attribute boolean visible;
+ DOMRect getBoundingClientRect();
+};
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
index 10b32ed7f82..86de8bf5495 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.cc
@@ -42,7 +42,6 @@
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/page_dismissal_scope.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
-#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -222,30 +221,6 @@ void WindowOrWorkerGlobalScope::clearInterval(EventTarget& event_target,
DOMTimer::RemoveByID(context, timeout_id);
}
-ScriptPromise WindowOrWorkerGlobalScope::createImageBitmap(
- ScriptState* script_state,
- EventTarget&,
- const ImageBitmapSourceUnion& bitmap_source,
- const ImageBitmapOptions* options,
- ExceptionState& exception_state) {
- return ImageBitmapFactories::CreateImageBitmap(script_state, bitmap_source,
- options, exception_state);
-}
-
-ScriptPromise WindowOrWorkerGlobalScope::createImageBitmap(
- ScriptState* script_state,
- EventTarget&,
- const ImageBitmapSourceUnion& bitmap_source,
- int sx,
- int sy,
- int sw,
- int sh,
- const ImageBitmapOptions* options,
- ExceptionState& exception_state) {
- return ImageBitmapFactories::CreateImageBitmap(
- script_state, bitmap_source, sx, sy, sw, sh, options, exception_state);
-}
-
bool WindowOrWorkerGlobalScope::crossOriginIsolated(
const ExecutionContext& execution_context) {
return execution_context.CrossOriginIsolatedCapability();
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
index 16250b8c439..3a1d93b8532 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.h
@@ -33,7 +33,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WINDOW_OR_WORKER_GLOBAL_SCOPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_WINDOW_OR_WORKER_GLOBAL_SCOPE_H_
-#include "third_party/blink/renderer/bindings/core/v8/image_bitmap_source.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -42,15 +44,10 @@ namespace blink {
class EventTarget;
class ExceptionState;
-class ImageBitmapOptions;
-class ScriptPromise;
class ScriptState;
class ScriptValue;
class V8Function;
-typedef HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas
- ImageBitmapSourceUnion;
-
class CORE_EXPORT WindowOrWorkerGlobalScope {
STATIC_ONLY(WindowOrWorkerGlobalScope);
@@ -85,21 +82,6 @@ class CORE_EXPORT WindowOrWorkerGlobalScope {
static void clearTimeout(EventTarget&, int timeout_id);
static void clearInterval(EventTarget&, int timeout_id);
- static ScriptPromise createImageBitmap(ScriptState*,
- EventTarget&,
- const ImageBitmapSourceUnion&,
- const ImageBitmapOptions*,
- ExceptionState&);
- static ScriptPromise createImageBitmap(ScriptState*,
- EventTarget&,
- const ImageBitmapSourceUnion&,
- int sx,
- int sy,
- int sw,
- int sh,
- const ImageBitmapOptions*,
- ExceptionState&);
-
static bool crossOriginIsolated(const ExecutionContext&);
};
diff --git a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
index 60191c0548c..5ad35847320 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window_or_worker_global_scope.idl
@@ -25,16 +25,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-// https://html.spec.whatwg.org/C/#imagebitmapsource
-typedef (HTMLImageElement or
- SVGImageElement or
- HTMLVideoElement or
- HTMLCanvasElement or
- Blob or
- ImageData or
- ImageBitmap or
- OffscreenCanvas) ImageBitmapSource;
-
// https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin
// https://html.spec.whatwg.org/C/#timers
[
@@ -53,12 +43,6 @@ typedef (HTMLImageElement or
[CallWith=ScriptState] long setInterval(ScriptString handler, optional long timeout = 0, any... arguments);
void clearInterval(optional long handle = 0);
- // ImageBitmap
- [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
- ImageBitmapSource imageBitmap, optional ImageBitmapOptions options = {});
- [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
- ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {});
-
[RuntimeEnabled=CrossOriginIsolation]
readonly attribute boolean crossOriginIsolated;
};
diff --git a/chromium/third_party/blink/renderer/core/frame/window_post_message_options.idl b/chromium/third_party/blink/renderer/core/frame/window_post_message_options.idl
index b019273d1fb..56b513f3324 100644
--- a/chromium/third_party/blink/renderer/core/frame/window_post_message_options.idl
+++ b/chromium/third_party/blink/renderer/core/frame/window_post_message_options.idl
@@ -6,4 +6,5 @@
dictionary WindowPostMessageOptions : PostMessageOptions {
USVString targetOrigin = "/";
+ [RuntimeEnabled = CapabilityDelegation] DOMString createToken = "";
};
diff --git a/chromium/third_party/blink/renderer/core/fullscreen/DIR_METADATA b/chromium/third_party/blink/renderer/core/fullscreen/DIR_METADATA
new file mode 100644
index 00000000000..1980012b582
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/fullscreen/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Fullscreen"
+}
diff --git a/chromium/third_party/blink/renderer/core/fullscreen/OWNERS b/chromium/third_party/blink/renderer/core/fullscreen/OWNERS
index ae781aed8a1..212e449935d 100644
--- a/chromium/third_party/blink/renderer/core/fullscreen/OWNERS
+++ b/chromium/third_party/blink/renderer/core/fullscreen/OWNERS
@@ -1,3 +1 @@
foolip@chromium.org
-
-# COMPONENT: Blink>Fullscreen
diff --git a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
index 9f57c5d5ef2..ec39d05fd73 100644
--- a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
+++ b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -66,7 +66,8 @@ namespace {
void FullscreenElementChanged(Document& document,
Element* old_element,
Element* new_element,
- FullscreenRequestType new_request_type) {
+ FullscreenRequestType new_request_type,
+ const FullscreenOptions* new_options) {
DCHECK_NE(old_element, new_element);
document.GetStyleEngine().EnsureUAStyleForFullscreen();
@@ -84,6 +85,8 @@ void FullscreenElementChanged(Document& document,
if (new_element) {
DCHECK_EQ(new_element, Fullscreen::FullscreenElementFrom(document));
+ // FullscreenOptions should be provided for incoming fullscreen element.
+ CHECK(new_options);
new_element->PseudoStateChanged(CSSSelector::kPseudoFullScreen);
new_element->PseudoStateChanged(CSSSelector::kPseudoFullscreen);
@@ -115,7 +118,8 @@ void FullscreenElementChanged(Document& document,
// TODO(foolip): Synchronize hover state changes with animation frames.
// https://crbug.com/668758
frame->GetEventHandler().ScheduleHoverStateUpdate();
- frame->GetChromeClient().FullscreenElementChanged(old_element, new_element);
+ frame->GetChromeClient().FullscreenElementChanged(
+ old_element, new_element, new_options, new_request_type);
// Update paint properties on the visual viewport since
// user-input-scrollable bits will change based on fullscreen state.
@@ -124,33 +128,63 @@ void FullscreenElementChanged(Document& document,
}
}
-using ElementRequestTypeMap =
- HeapHashMap<WeakMember<Element>, FullscreenRequestType>;
+class MetaParams : public GarbageCollected<MetaParams> {
+ public:
+ MetaParams() = default;
+ MetaParams(FullscreenRequestType request_type,
+ const FullscreenOptions* options)
+ : request_type_(request_type), options_(options) {}
+ virtual ~MetaParams() = default;
+
+ MetaParams(const MetaParams&) = delete;
+ MetaParams& operator=(const MetaParams&) = delete;
+
+ virtual void Trace(Visitor* visitor) const { visitor->Trace(options_); }
+
+ FullscreenRequestType request_type() const { return request_type_; }
+ const FullscreenOptions* options() const { return options_; }
+
+ private:
+ FullscreenRequestType request_type_;
+ Member<const FullscreenOptions> options_;
+};
+
+using ElementMetaParamsMap =
+ HeapHashMap<WeakMember<Element>, Member<const MetaParams>>;
-ElementRequestTypeMap& FullscreenFlagMap() {
- DEFINE_STATIC_LOCAL(Persistent<ElementRequestTypeMap>, map,
- (MakeGarbageCollected<ElementRequestTypeMap>()));
+ElementMetaParamsMap& FullscreenParamsMap() {
+ DEFINE_STATIC_LOCAL(Persistent<ElementMetaParamsMap>, map,
+ (MakeGarbageCollected<ElementMetaParamsMap>()));
return *map;
}
bool HasFullscreenFlag(Element& element) {
- return FullscreenFlagMap().Contains(&element);
+ return FullscreenParamsMap().Contains(&element);
}
-void SetFullscreenFlag(Element& element, FullscreenRequestType request_type) {
- FullscreenFlagMap().insert(&element, request_type);
+void SetFullscreenFlag(Element& element,
+ FullscreenRequestType request_type,
+ const FullscreenOptions* options) {
+ FullscreenParamsMap().insert(
+ &element, MakeGarbageCollected<MetaParams>(request_type, options));
}
void UnsetFullscreenFlag(Element& element) {
- FullscreenFlagMap().erase(&element);
+ FullscreenParamsMap().erase(&element);
}
FullscreenRequestType GetRequestType(Element& element) {
- return FullscreenFlagMap().find(&element)->value;
+ return FullscreenParamsMap().find(&element)->value->request_type();
+}
+
+const MetaParams* GetParams(Element& element) {
+ return FullscreenParamsMap().find(&element)->value;
}
// https://fullscreen.spec.whatwg.org/#fullscreen-an-element
-void GoFullscreen(Element& element, FullscreenRequestType request_type) {
+void GoFullscreen(Element& element,
+ FullscreenRequestType request_type,
+ const FullscreenOptions* options) {
Document& document = element.GetDocument();
Element* old_element = Fullscreen::FullscreenElementFrom(document);
@@ -163,11 +197,12 @@ void GoFullscreen(Element& element, FullscreenRequestType request_type) {
// To fullscreen an |element| within a |document|, set the |element|'s
// fullscreen flag and add it to |document|'s top layer.
- SetFullscreenFlag(element, request_type);
+ SetFullscreenFlag(element, request_type, options);
document.AddToTopLayer(&element);
DCHECK_EQ(&element, Fullscreen::FullscreenElementFrom(document));
- FullscreenElementChanged(document, old_element, &element, request_type);
+ FullscreenElementChanged(document, old_element, &element, request_type,
+ options);
}
// https://fullscreen.spec.whatwg.org/#unfullscreen-an-element
@@ -196,11 +231,18 @@ void Unfullscreen(Element& element) {
Element* new_element = Fullscreen::FullscreenElementFrom(document);
if (old_element != new_element) {
- FullscreenRequestType new_request_type =
- new_element ? GetRequestType(*new_element)
- : FullscreenRequestType::kUnprefixed;
+ FullscreenRequestType new_request_type;
+ const FullscreenOptions* new_options;
+ if (new_element) {
+ const MetaParams* params = GetParams(*new_element);
+ new_request_type = params->request_type();
+ new_options = params->options();
+ } else {
+ new_request_type = FullscreenRequestType::kUnprefixed;
+ new_options = FullscreenOptions::Create();
+ }
FullscreenElementChanged(document, old_element, new_element,
- new_request_type);
+ new_request_type, new_options);
}
}
@@ -326,8 +368,8 @@ bool RequestFullscreenConditionsMet(Element& pending, Document& document) {
if (!pending.IsHTMLElement() && !IsA<SVGSVGElement>(pending))
return false;
- // |pending| is not a dialog element.
- if (IsA<HTMLDialogElement>(pending))
+ // |pending| is not a dialog or popup element.
+ if (IsA<HTMLDialogElement>(pending) || IsA<HTMLPopupElement>(pending))
return false;
// The fullscreen element ready check for |pending| returns false.
@@ -535,22 +577,7 @@ Element* Fullscreen::FullscreenElementFrom(Document& document) {
Element* Fullscreen::FullscreenElementForBindingFrom(TreeScope& scope) {
Element* element = FullscreenElementFrom(scope.GetDocument());
if (!element)
- return element;
-
- // TODO(kochi): Once V0 code is removed, we can use the same logic for
- // Document and ShadowRoot.
- auto* shadow_root = DynamicTo<ShadowRoot>(scope.RootNode());
- if (!shadow_root) {
- // For Shadow DOM V0 compatibility: We allow returning an element in V0
- // shadow tree, even though it leaks the Shadow DOM.
- if (element->IsInV0ShadowTree()) {
- UseCounter::Count(scope.GetDocument(),
- WebFeature::kDocumentFullscreenElementInV0Shadow);
- return element;
- }
- } else if (!shadow_root->IsV1()) {
return nullptr;
- }
return scope.AdjustedElement(*element);
}
@@ -650,7 +677,8 @@ ScriptPromise Fullscreen::RequestFullscreen(Element& pending,
}
From(window).pending_requests_.push_back(
- MakeGarbageCollected<PendingRequest>(&pending, request_type, resolver));
+ MakeGarbageCollected<PendingRequest>(&pending, request_type, options,
+ resolver));
LocalFrame& frame = *window.GetFrame();
frame.GetChromeClient().EnterFullscreen(frame, options, request_type);
@@ -663,8 +691,8 @@ ScriptPromise Fullscreen::RequestFullscreen(Element& pending,
// synchronously because when |error| is true, |ContinueRequestFullscreen()|
// will only queue a task and return. This is indistinguishable from, e.g.,
// enqueueing a microtask to continue at step 9.
- ContinueRequestFullscreen(document, pending, request_type, resolver,
- true /* error */);
+ ContinueRequestFullscreen(document, pending, request_type, options,
+ resolver, true /* error */);
}
return promise;
@@ -693,13 +721,15 @@ void Fullscreen::DidResolveEnterFullscreenRequest(Document& document,
requests.swap(From(*document.domWindow()).pending_requests_);
for (const Member<PendingRequest>& request : requests) {
ContinueRequestFullscreen(document, *request->element(), request->type(),
- request->resolver(), !granted);
+ request->options(), request->resolver(),
+ !granted);
}
}
void Fullscreen::ContinueRequestFullscreen(Document& document,
Element& pending,
FullscreenRequestType request_type,
+ const FullscreenOptions* options,
ScriptPromiseResolver* resolver,
bool error) {
DCHECK(document.IsActive());
@@ -781,7 +811,7 @@ void Fullscreen::ContinueRequestFullscreen(Document& document,
// https://crbug.com/644695
// 13.4. Fullscreen |element| within |doc|.
- GoFullscreen(*element, request_type);
+ GoFullscreen(*element, request_type, options);
// 13.5. Append (fullscreenchange, |element|) to |doc|'s list of pending
// fullscreen events.
@@ -1061,13 +1091,15 @@ void Fullscreen::Trace(Visitor* visitor) const {
Fullscreen::PendingRequest::PendingRequest(Element* element,
FullscreenRequestType type,
+ const FullscreenOptions* options,
ScriptPromiseResolver* resolver)
- : element_(element), type_(type), resolver_(resolver) {}
+ : element_(element), type_(type), options_(options), resolver_(resolver) {}
Fullscreen::PendingRequest::~PendingRequest() = default;
void Fullscreen::PendingRequest::Trace(Visitor* visitor) const {
visitor->Trace(element_);
+ visitor->Trace(options_);
visitor->Trace(resolver_);
}
diff --git a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.h b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.h
index 0627cccb097..34c1d12d736 100644
--- a/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.h
+++ b/chromium/third_party/blink/renderer/core/fullscreen/fullscreen.h
@@ -59,7 +59,7 @@ class CORE_EXPORT Fullscreen final : public GarbageCollected<Fullscreen>,
static const char kSupplementName[];
explicit Fullscreen(LocalDOMWindow&);
- virtual ~Fullscreen();
+ ~Fullscreen() override;
static Element* FullscreenElementFrom(Document&);
static Element* FullscreenElementForBindingFrom(TreeScope&);
@@ -102,6 +102,7 @@ class CORE_EXPORT Fullscreen final : public GarbageCollected<Fullscreen>,
static void ContinueRequestFullscreen(Document&,
Element&,
FullscreenRequestType,
+ const FullscreenOptions*,
ScriptPromiseResolver* resolver,
bool error);
@@ -119,17 +120,20 @@ class CORE_EXPORT Fullscreen final : public GarbageCollected<Fullscreen>,
public:
PendingRequest(Element* element,
FullscreenRequestType type,
+ const FullscreenOptions* options,
ScriptPromiseResolver* resolver);
virtual ~PendingRequest();
virtual void Trace(Visitor* visitor) const;
Element* element() { return element_; }
FullscreenRequestType type() { return type_; }
+ const FullscreenOptions* options() { return options_; }
ScriptPromiseResolver* resolver() { return resolver_; }
private:
Member<Element> element_;
FullscreenRequestType type_;
+ Member<const FullscreenOptions> options_;
Member<ScriptPromiseResolver> resolver_;
DISALLOW_COPY_AND_ASSIGN(PendingRequest);
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_matrix.cc b/chromium/third_party/blink/renderer/core/geometry/dom_matrix.cc
index 6f251520acb..a20e8bdad2f 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_matrix.cc
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_matrix.cc
@@ -68,30 +68,26 @@ DOMMatrix* DOMMatrix::CreateForSerialization(double sequence[], int size) {
DOMMatrix* DOMMatrix::fromFloat32Array(NotShared<DOMFloat32Array> float32_array,
ExceptionState& exception_state) {
- if (float32_array.View()->length() != 6 &&
- float32_array.View()->length() != 16) {
+ if (float32_array->length() != 6 && float32_array->length() != 16) {
exception_state.ThrowTypeError(
"The sequence must contain 6 elements for a 2D matrix or 16 elements "
"for a 3D matrix.");
return nullptr;
}
return MakeGarbageCollected<DOMMatrix>(
- float32_array.View()->Data(),
- static_cast<int>(float32_array.View()->length()));
+ float32_array->Data(), static_cast<int>(float32_array->length()));
}
DOMMatrix* DOMMatrix::fromFloat64Array(NotShared<DOMFloat64Array> float64_array,
ExceptionState& exception_state) {
- if (float64_array.View()->length() != 6 &&
- float64_array.View()->length() != 16) {
+ if (float64_array->length() != 6 && float64_array->length() != 16) {
exception_state.ThrowTypeError(
"The sequence must contain 6 elements for a 2D matrix or 16 elements "
"for a 3D matrix.");
return nullptr;
}
return MakeGarbageCollected<DOMMatrix>(
- float64_array.View()->Data(),
- static_cast<int>(float64_array.View()->length()));
+ float64_array->Data(), static_cast<int>(float64_array->length()));
}
template <typename T>
@@ -297,7 +293,7 @@ DOMMatrix* DOMMatrix::invertSelf() {
if (is2d_) {
AffineTransform affine_transform = matrix_.ToAffineTransform();
if (affine_transform.IsInvertible()) {
- matrix_ = affine_transform.Inverse();
+ matrix_ = TransformationMatrix(affine_transform.Inverse());
return this;
}
} else {
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
index 2e45c433bb0..a27cba2c792 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
@@ -147,31 +147,27 @@ DOMMatrixReadOnly* DOMMatrixReadOnly::CreateForSerialization(double sequence[],
DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat32Array(
NotShared<DOMFloat32Array> float32_array,
ExceptionState& exception_state) {
- if (float32_array.View()->length() != 6 &&
- float32_array.View()->length() != 16) {
+ if (float32_array->length() != 6 && float32_array->length() != 16) {
exception_state.ThrowTypeError(
"The sequence must contain 6 elements for a 2D matrix or 16 elements a "
"for 3D matrix.");
return nullptr;
}
return MakeGarbageCollected<DOMMatrixReadOnly>(
- float32_array.View()->Data(),
- static_cast<int>(float32_array.View()->length()));
+ float32_array->Data(), static_cast<int>(float32_array->length()));
}
DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat64Array(
NotShared<DOMFloat64Array> float64_array,
ExceptionState& exception_state) {
- if (float64_array.View()->length() != 6 &&
- float64_array.View()->length() != 16) {
+ if (float64_array->length() != 6 && float64_array->length() != 16) {
exception_state.ThrowTypeError(
"The sequence must contain 6 elements for a 2D matrix or 16 elements "
"for a 3D matrix.");
return nullptr;
}
return MakeGarbageCollected<DOMMatrixReadOnly>(
- float64_array.View()->Data(),
- static_cast<int>(float64_array.View()->length()));
+ float64_array->Data(), static_cast<int>(float64_array->length()));
}
DOMMatrixReadOnly* DOMMatrixReadOnly::fromMatrix2D(
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_quad.cc b/chromium/third_party/blink/renderer/core/geometry/dom_quad.cc
index ea4bf8a1cb0..1cf4aa41c86 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_quad.cc
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_quad.cc
@@ -83,7 +83,7 @@ DOMQuad* DOMQuad::fromQuad(const DOMQuadInit* other) {
other->hasP1() ? other->p1() : DOMPointInit::Create(),
other->hasP2() ? other->p2() : DOMPointInit::Create(),
other->hasP3() ? other->p3() : DOMPointInit::Create(),
- other->hasP3() ? other->p4() : DOMPointInit::Create());
+ other->hasP4() ? other->p4() : DOMPointInit::Create());
}
DOMRect* DOMQuad::getBounds() {
diff --git a/chromium/third_party/blink/renderer/core/geometry/dom_rect.h b/chromium/third_party/blink/renderer/core/geometry/dom_rect.h
index 058c60a904e..c647bc4f1c0 100644
--- a/chromium/third_party/blink/renderer/core/geometry/dom_rect.h
+++ b/chromium/third_party/blink/renderer/core/geometry/dom_rect.h
@@ -5,7 +5,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_GEOMETRY_DOM_RECT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_GEOMETRY_DOM_RECT_H_
-#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/geometry/dom_rect_read_only.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
diff --git a/chromium/third_party/blink/renderer/core/html/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/DIR_METADATA
new file mode 100644
index 00000000000..b7acf25f76d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>HTML"
+}
+
+team_email: "dom-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/html/OWNERS b/chromium/third_party/blink/renderer/core/html/OWNERS
index 472b0c7cf86..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/core/html/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/OWNERS
@@ -1,2 +0,0 @@
-# TEAM: dom-dev@chromium.org
-# COMPONENT: Blink>HTML
diff --git a/chromium/third_party/blink/renderer/core/html/aria_properties.json5 b/chromium/third_party/blink/renderer/core/html/aria_properties.json5
index b57f304ddc0..496f9a32ea6 100644
--- a/chromium/third_party/blink/renderer/core/html/aria_properties.json5
+++ b/chromium/third_party/blink/renderer/core/html/aria_properties.json5
@@ -128,10 +128,16 @@
enum: ["ascending", "descending", "none", "other"],
type: "token"
},
+ {
+ name: "aria-touchpassthrough",
+ type: "boolean",
+ runtimeEnabled: "AriaTouchPassthrough"
+ },
{name: "aria-valuemax", type: "decimal"},
{name: "aria-valuemin", type: "decimal"},
{name: "aria-valuenow", type: "decimal"},
{name: "aria-valuetext", type: "string"},
+ {name: "aria-virtualcontent", type: "string"},
],
roles: [
{
diff --git a/chromium/third_party/blink/renderer/core/html/battery_savings.h b/chromium/third_party/blink/renderer/core/html/battery_savings.h
new file mode 100644
index 00000000000..5519b37da7a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/battery_savings.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_BATTERY_SAVINGS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_BATTERY_SAVINGS_H_
+
+namespace blink {
+
+// These are constants for the various keywords allowed for the battery-savings
+// meta element. For instance:
+//
+// <meta name="battery-savings" content="allow-reduced-framerate">
+// These constants are bits which can be combined.
+enum BatterySavings {
+ kAllowReducedFrameRate = 1 << 0,
+ kAllowReducedScriptSpeed = 1 << 1,
+};
+
+using BatterySavingsFlags = unsigned;
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_BATTERY_SAVINGS_H_
diff --git a/chromium/third_party/blink/renderer/core/html/build.gni b/chromium/third_party/blink/renderer/core/html/build.gni
index 2c41552f9d0..cc30e361483 100644
--- a/chromium/third_party/blink/renderer/core/html/build.gni
+++ b/chromium/third_party/blink/renderer/core/html/build.gni
@@ -7,6 +7,7 @@ blink_core_sources_html = [
"anchor_element_metrics.h",
"anchor_element_metrics_sender.cc",
"anchor_element_metrics_sender.h",
+ "battery_savings.h",
"canvas/canvas_async_blob_creator.cc",
"canvas/canvas_async_blob_creator.h",
"canvas/canvas_context_creation_attributes_core.cc",
@@ -32,6 +33,8 @@ blink_core_sources_html = [
"canvas/ukm_parameters.h",
"collection_items_cache.h",
"collection_type.h",
+ "conversion_measurement_parsing.cc",
+ "conversion_measurement_parsing.h",
"cross_origin_attribute.cc",
"cross_origin_attribute.h",
"custom/ce_reactions_scope.cc",
@@ -55,49 +58,10 @@ blink_core_sources_html = [
"custom/custom_element_registry.h",
"custom/custom_element_upgrade_sorter.cc",
"custom/custom_element_upgrade_sorter.h",
+ "custom/custom_state_set.cc",
+ "custom/custom_state_set.h",
"custom/element_internals.cc",
"custom/element_internals.h",
- "custom/v0_custom_element.cc",
- "custom/v0_custom_element.h",
- "custom/v0_custom_element_async_import_microtask_queue.cc",
- "custom/v0_custom_element_async_import_microtask_queue.h",
- "custom/v0_custom_element_callback_invocation.cc",
- "custom/v0_custom_element_callback_invocation.h",
- "custom/v0_custom_element_callback_queue.cc",
- "custom/v0_custom_element_callback_queue.h",
- "custom/v0_custom_element_definition.cc",
- "custom/v0_custom_element_definition.h",
- "custom/v0_custom_element_descriptor.h",
- "custom/v0_custom_element_descriptor_hash.h",
- "custom/v0_custom_element_exception.cc",
- "custom/v0_custom_element_exception.h",
- "custom/v0_custom_element_lifecycle_callbacks.h",
- "custom/v0_custom_element_microtask_dispatcher.cc",
- "custom/v0_custom_element_microtask_dispatcher.h",
- "custom/v0_custom_element_microtask_import_step.cc",
- "custom/v0_custom_element_microtask_import_step.h",
- "custom/v0_custom_element_microtask_queue_base.cc",
- "custom/v0_custom_element_microtask_queue_base.h",
- "custom/v0_custom_element_microtask_resolution_step.cc",
- "custom/v0_custom_element_microtask_resolution_step.h",
- "custom/v0_custom_element_microtask_run_queue.cc",
- "custom/v0_custom_element_microtask_run_queue.h",
- "custom/v0_custom_element_microtask_step.h",
- "custom/v0_custom_element_observer.cc",
- "custom/v0_custom_element_observer.h",
- "custom/v0_custom_element_processing_stack.cc",
- "custom/v0_custom_element_processing_stack.h",
- "custom/v0_custom_element_processing_step.h",
- "custom/v0_custom_element_registration_context.cc",
- "custom/v0_custom_element_registration_context.h",
- "custom/v0_custom_element_registry.cc",
- "custom/v0_custom_element_registry.h",
- "custom/v0_custom_element_scheduler.cc",
- "custom/v0_custom_element_scheduler.h",
- "custom/v0_custom_element_sync_microtask_queue.cc",
- "custom/v0_custom_element_sync_microtask_queue.h",
- "custom/v0_custom_element_upgrade_candidate_map.cc",
- "custom/v0_custom_element_upgrade_candidate_map.h",
"document_all_name_collection.cc",
"document_all_name_collection.h",
"document_name_collection.cc",
@@ -202,6 +166,8 @@ blink_core_sources_html = [
"forms/html_output_element.h",
"forms/html_select_element.cc",
"forms/html_select_element.h",
+ "forms/html_select_menu_element.cc",
+ "forms/html_select_menu_element.h",
"forms/html_text_area_element.cc",
"forms/html_text_area_element.h",
"forms/image_input_type.cc",
@@ -294,8 +260,6 @@ blink_core_sources_html = [
"html_br_element.h",
"html_collection.cc",
"html_collection.h",
- "html_content_element.cc",
- "html_content_element.h",
"html_data_element.cc",
"html_data_element.h",
"html_details_element.cc",
@@ -378,6 +342,8 @@ blink_core_sources_html = [
"html_picture_element.h",
"html_plugin_element.cc",
"html_plugin_element.h",
+ "html_popup_element.cc",
+ "html_popup_element.h",
"html_pre_element.cc",
"html_pre_element.h",
"html_progress_element.cc",
@@ -390,8 +356,6 @@ blink_core_sources_html = [
"html_ruby_element.h",
"html_script_element.cc",
"html_script_element.h",
- "html_shadow_element.cc",
- "html_shadow_element.h",
"html_slot_element.cc",
"html_slot_element.h",
"html_source_element.cc",
@@ -470,6 +434,8 @@ blink_core_sources_html = [
"list_item_ordinal.h",
"loading_attribute.cc",
"loading_attribute.h",
+ "media/audio_output_device_controller.cc",
+ "media/audio_output_device_controller.h",
"media/autoplay_policy.cc",
"media/autoplay_policy.h",
"media/autoplay_uma_helper.cc",
@@ -706,7 +672,6 @@ blink_core_tests_html = [
"forms/step_range_test.cc",
"forms/text_control_element_test.cc",
"forms/type_ahead_test.cc",
- "html_content_element_test.cc",
"html_dimension_test.cc",
"html_element_test.cc",
"html_embed_element_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/canvas/DIR_METADATA
new file mode 100644
index 00000000000..4ae95d48d73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/canvas/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Canvas"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/OWNERS b/chromium/third_party/blink/renderer/core/html/canvas/OWNERS
index 5ef87b1aa3f..1e563633b29 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/canvas/OWNERS
@@ -1,4 +1 @@
fserb@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index 3e078d42692..aae43a337bc 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -86,24 +86,23 @@ void RecordIdleTaskStatusHistogram(
void RecordInitiateEncodingTimeHistogram(ImageEncodingMimeType mime_type,
base::TimeDelta elapsed_time) {
- // TODO(crbug.com/983261) Change this to use UmaHistogramMicrosecondsTimes.
if (mime_type == kMimeTypePng) {
- UmaHistogramMicrosecondsTimesUnderTenMilliseconds(
- "Blink.Canvas.ToBlob.InitiateEncodingDelay.PNG", elapsed_time);
+ UmaHistogramMicrosecondsTimes(
+ "Blink.Canvas.ToBlob.InitialEncodingDelay.PNG", elapsed_time);
} else if (mime_type == kMimeTypeJpeg) {
- UmaHistogramMicrosecondsTimesUnderTenMilliseconds(
- "Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", elapsed_time);
+ UmaHistogramMicrosecondsTimes(
+ "Blink.Canvas.ToBlob.InitialEncodingDelay.JPEG", elapsed_time);
}
}
void RecordCompleteEncodingTimeHistogram(ImageEncodingMimeType mime_type,
base::TimeDelta elapsed_time) {
if (mime_type == kMimeTypePng) {
- UmaHistogramMicrosecondsTimesUnderTenMilliseconds(
- "Blink.Canvas.ToBlob.CompleteEncodingDelay.PNG", elapsed_time);
+ UmaHistogramMicrosecondsTimes("Blink.Canvas.ToBlob.TotalEncodingDelay.PNG",
+ elapsed_time);
} else if (mime_type == kMimeTypeJpeg) {
- UmaHistogramMicrosecondsTimesUnderTenMilliseconds(
- "Blink.Canvas.ToBlob.CompleteEncodingDelay.JPEG", elapsed_time);
+ UmaHistogramMicrosecondsTimes("Blink.Canvas.ToBlob.TotalEncodingDelay.JPEG",
+ elapsed_time);
}
}
@@ -205,12 +204,15 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
}
// For kHTMLCanvasToBlobCallback and kOffscreenCanvasConvertToBlobPromise
- // to-blob function types, we color convert to sRGB and do not tag the image
- // with any color space info.
+ // to-blob function types, we keep the color space of the image and save
+ // it in the info if color management is enabled; otherwise, we color convert
+ // to sRGB and do not tag the image with any color space info.
// For kHTMLCanvasConvertToBlobPromise to-blob function type, we color
// covnert to the requested color space and pixel format.
if (function_type_ != kHTMLCanvasConvertToBlobPromise) {
- if (skia_image->colorSpace()) {
+ bool isColorManagementEnabled =
+ RuntimeEnabledFeatures::CanvasColorManagementEnabled();
+ if (skia_image->colorSpace() && !isColorManagementEnabled) {
image_ = image_->ConvertToColorSpace(
SkColorSpace::MakeSRGB(),
GetColorTypeForConversion(skia_image->colorType()));
@@ -218,10 +220,10 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
}
if (skia_image->peekPixels(&src_data_)) {
- src_data_.setColorSpace(nullptr);
static_bitmap_image_loaded_ = true;
+ if (!isColorManagementEnabled)
+ src_data_.setColorSpace(nullptr);
}
- DCHECK(!src_data_.colorSpace());
} else {
sk_sp<SkColorSpace> blob_color_space =
BlobColorSpaceToSkColorSpace(encode_options_->colorSpace());
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
index b1954a1880b..c6fe16f9638 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
@@ -65,6 +65,7 @@ class CORE_EXPORT CanvasImageSource {
virtual bool IsSVGSource() const { return false; }
virtual bool IsImageBitmap() const { return false; }
virtual bool IsOffscreenCanvas() const { return false; }
+ virtual bool IsVideoFrame() const { return false; }
virtual FloatSize ElementSize(const FloatSize& default_object_size,
const RespectImageOrientationEnum) const = 0;
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
index e165fcf0f54..5906a3ac051 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
@@ -40,52 +40,8 @@ CanvasRenderingContext::CanvasRenderingContext(
CanvasRenderingContextHost* host,
const CanvasContextCreationAttributesCore& attrs)
: host_(host),
- color_params_(CanvasColorSpace::kSRGB,
- CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque),
- creation_attributes_(attrs) {
- if (creation_attributes_.pixel_format == kF16CanvasPixelFormatName)
- color_params_.SetCanvasPixelFormat(CanvasPixelFormat::kF16);
-
- if (creation_attributes_.color_space == kRec2020CanvasColorSpaceName)
- color_params_.SetCanvasColorSpace(CanvasColorSpace::kRec2020);
- else if (creation_attributes_.color_space == kP3CanvasColorSpaceName)
- color_params_.SetCanvasColorSpace(CanvasColorSpace::kP3);
-
- if (!creation_attributes_.alpha)
- color_params_.SetOpacityMode(kOpaque);
-
- // Make creation_attributes_ reflect the effective color_space and
- // pixel_format rather than the requested one.
- creation_attributes_.color_space = ColorSpaceAsString();
- creation_attributes_.pixel_format = PixelFormatAsString();
-}
-
-WTF::String CanvasRenderingContext::ColorSpaceAsString() const {
- switch (color_params_.ColorSpace()) {
- case CanvasColorSpace::kSRGB:
- return kSRGBCanvasColorSpaceName;
- case CanvasColorSpace::kRec2020:
- return kRec2020CanvasColorSpaceName;
- case CanvasColorSpace::kP3:
- return kP3CanvasColorSpaceName;
- };
- CHECK(false);
- return "";
-}
-
-WTF::String CanvasRenderingContext::PixelFormatAsString() const {
- switch (color_params_.PixelFormat()) {
- case CanvasPixelFormat::kRGBA8:
- return kRGBA8CanvasPixelFormatName;
- case CanvasPixelFormat::kF16:
- return kF16CanvasPixelFormatName;
- case CanvasPixelFormat::kBGRA8:
- return kBGRA8CanvasPixelFormatName;
- };
- CHECK(false);
- return "";
-}
+ color_params_(attrs.color_space, attrs.pixel_format, attrs.alpha),
+ creation_attributes_(attrs) {}
void CanvasRenderingContext::Dispose() {
StopListeningForDidProcessTask();
@@ -141,6 +97,22 @@ void CanvasRenderingContext::RecordUKMCanvasRenderingAPI(
}
}
+void CanvasRenderingContext::RecordUKMCanvasDrawnToRenderingAPI(
+ CanvasRenderingAPI canvasRenderingAPI) {
+ DCHECK(Host());
+ const auto& ukm_params = Host()->GetUkmParameters();
+ if (Host()->IsOffscreenCanvas()) {
+ ukm::builders::ClientRenderingAPI(ukm_params.source_id)
+ .SetOffscreenCanvas_RenderingContextDrawnTo(
+ static_cast<int>(canvasRenderingAPI))
+ .Record(ukm_params.ukm_recorder);
+ } else {
+ ukm::builders::ClientRenderingAPI(ukm_params.source_id)
+ .SetCanvas_RenderingContextDrawnTo(static_cast<int>(canvasRenderingAPI))
+ .Record(ukm_params.ukm_recorder);
+ }
+}
+
CanvasRenderingContext::ContextType CanvasRenderingContext::ContextTypeFromId(
const String& id) {
if (id == "2d")
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index cc030d990d2..ef4f222ccaf 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -46,14 +46,6 @@ class CanvasImageSource;
class HTMLCanvasElement;
class ImageBitmap;
-constexpr const char* kSRGBCanvasColorSpaceName = "srgb";
-constexpr const char* kRec2020CanvasColorSpaceName = "rec2020";
-constexpr const char* kP3CanvasColorSpaceName = "p3";
-
-constexpr const char* kRGBA8CanvasPixelFormatName = "uint8";
-constexpr const char* kBGRA8CanvasPixelFormatName = "uint8";
-constexpr const char* kF16CanvasPixelFormatName = "float16";
-
class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable,
public Thread::TaskObserver {
USING_PRE_FINALIZER(CanvasRenderingContext, Dispose);
@@ -90,16 +82,17 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable,
};
void RecordUKMCanvasRenderingAPI(CanvasRenderingAPI canvasRenderingAPI);
+ void RecordUKMCanvasDrawnToRenderingAPI(
+ CanvasRenderingAPI canvasRenderingAPI);
static ContextType ContextTypeFromId(const String& id);
static ContextType ResolveContextTypeAliases(ContextType);
CanvasRenderingContextHost* Host() const { return host_; }
- WTF::String ColorSpaceAsString() const;
- WTF::String PixelFormatAsString() const;
-
- const CanvasColorParams& ColorParams() const { return color_params_; }
+ const CanvasColorParams& CanvasRenderingContextColorParams() const {
+ return color_params_;
+ }
virtual scoped_refptr<StaticBitmapImage> GetImage() = 0;
virtual ContextType GetContextType() const = 0;
@@ -186,7 +179,7 @@ class CORE_EXPORT CanvasRenderingContext : public ScriptWrappable,
virtual bool Is3d() const { return false; }
virtual bool UsingSwapChain() const { return false; }
virtual void SetFilterQuality(SkFilterQuality) { NOTREACHED(); }
- virtual void Reshape(int width, int height) { NOTREACHED(); }
+ virtual void Reshape(int width, int height) {}
virtual void MarkLayerComposited() { NOTREACHED(); }
virtual sk_sp<SkData> PaintRenderingResultsToDataArray(SourceDrawingBuffer) {
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index 174e887bb27..fd548d85896 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -48,7 +48,7 @@ CanvasRenderingContextHost::CreateTransparentImage(const IntSize& size) const {
return nullptr;
CanvasColorParams color_params = CanvasColorParams();
if (RenderingContext())
- color_params = RenderingContext()->ColorParams();
+ color_params = RenderingContext()->CanvasRenderingContextColorParams();
SkImageInfo info = SkImageInfo::Make(
size.Width(), size.Height(), color_params.GetSkColorType(),
kPremul_SkAlphaType, color_params.GetSkColorSpace());
@@ -115,6 +115,8 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() {
: nullptr;
std::unique_ptr<CanvasResourceProvider> provider;
+ const CanvasResourceParams resource_params =
+ ColorParams().GetAsResourceParams();
if (SharedGpuContext::IsGpuCompositingEnabled() && LowLatencyEnabled()) {
// If LowLatency is enabled, we need a resource that is able to perform well
@@ -126,7 +128,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() {
// try a passthrough provider.
DCHECK(LowLatencyEnabled());
provider = CanvasResourceProvider::CreatePassThroughProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
SharedGpuContext::ContextProviderWrapper(), dispatcher,
RenderingContext()->IsOriginTopLeft());
}
@@ -141,7 +143,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() {
gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
}
provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
RenderingContext()->IsOriginTopLeft(), shared_image_usage_flags);
@@ -155,7 +157,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() {
shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
}
provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
RenderingContext()->IsOriginTopLeft(), shared_image_usage_flags);
@@ -166,12 +168,12 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider3D() {
// provider.
if (!provider) {
provider = CanvasResourceProvider::CreateSharedBitmapProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear, dispatcher);
}
if (!provider) {
provider = CanvasResourceProvider::CreateBitmapProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear);
}
@@ -193,6 +195,8 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
: nullptr;
std::unique_ptr<CanvasResourceProvider> provider;
+ const CanvasResourceParams resource_params =
+ ColorParams().GetAsResourceParams();
const bool use_gpu =
hint == RasterModeHint::kPreferGPU && ShouldAccelerate2dContext();
// It is important to not use the context's IsOriginTopLeft() here
@@ -205,7 +209,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
// SwapChain if possible.
if (base::FeatureList::IsEnabled(features::kLowLatencyCanvas2dSwapChain)) {
provider = CanvasResourceProvider::CreateSwapChainProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), dispatcher,
is_origin_top_left);
@@ -223,7 +227,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
}
provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
is_origin_top_left, shared_image_usage_flags);
@@ -236,7 +240,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled())
shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
is_origin_top_left, shared_image_usage_flags);
@@ -244,7 +248,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kCPU,
is_origin_top_left, shared_image_usage_flags);
@@ -255,12 +259,12 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
// provider.
if (!provider) {
provider = CanvasResourceProvider::CreateSharedBitmapProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear, dispatcher);
}
if (!provider) {
provider = CanvasResourceProvider::CreateBitmapProvider(
- Size(), FilterQuality(), ColorParams(),
+ Size(), FilterQuality(), resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear);
}
@@ -280,7 +284,7 @@ void CanvasRenderingContextHost::CreateCanvasResourceProvider2D(
CanvasColorParams CanvasRenderingContextHost::ColorParams() const {
if (RenderingContext())
- return RenderingContext()->ColorParams();
+ return RenderingContext()->CanvasRenderingContextColorParams();
return CanvasColorParams();
}
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 4489838b4ed..1e3ed7bc5c6 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -114,6 +114,10 @@ constexpr int kDefaultCanvasHeight = 150;
constexpr int kUndefinedQualityValue = -1.0;
constexpr int kMinimumAccelerated2dCanvasSize = 128 * 129;
+// A default size used for canvas memory allocation when canvas size is greater
+// than 2^20.
+constexpr uint32_t kMaximumCanvasSize = 2 << 20;
+
} // namespace
HTMLCanvasElement::HTMLCanvasElement(Document& document)
@@ -138,9 +142,10 @@ HTMLCanvasElement::~HTMLCanvasElement() {
}
void HTMLCanvasElement::Dispose() {
- if (OffscreenCanvasFrame()) {
- ReleaseOffscreenCanvasFrame();
- }
+ // We need to record metrics before we dispose of anything
+ if (context_)
+ UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider()));
+
// It's possible that the placeholder frame has been disposed but its ID still
// exists. Make sure that it gets unregistered here
UnregisterPlaceholderCanvas();
@@ -150,12 +155,8 @@ void HTMLCanvasElement::Dispose() {
DiscardResourceProvider();
if (context_) {
- UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider()));
- if (context_->Host()) {
- UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.IsComposited",
- context_->IsComposited());
+ if (context_->Host())
context_->DetachHost();
- }
context_ = nullptr;
}
@@ -286,9 +287,9 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
auto* old_contents_cc_layer = ContentsCcLayer();
auto* result = GetCanvasRenderingContextInternal(type, attributes);
+ Document& doc = GetDocument();
if (IdentifiabilityStudySettings::Get()->ShouldSample(
IdentifiableSurface::Type::kCanvasRenderingContext)) {
- Document& doc = GetDocument();
IdentifiabilityMetricBuilder(doc.UkmSourceID())
.Set(IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kCanvasRenderingContext,
@@ -296,6 +297,10 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContext(
!!result)
.Record(doc.UkmRecorder());
}
+ if (attributes.color_space != kSRGBCanvasColorSpaceName ||
+ attributes.pixel_format != kUint8CanvasPixelFormatName) {
+ UseCounter::Count(doc, WebFeature::kCanvasUseColorSpace);
+ }
if (ContentsCcLayer() != old_contents_cc_layer)
OnContentsCcLayerChanged();
@@ -377,10 +382,16 @@ CanvasRenderingContext* HTMLCanvasElement::GetCanvasRenderingContextInternal(
}
if (context_->CreationAttributes().desynchronized) {
- CreateLayer();
+ if (!CreateLayer())
+ return nullptr;
SetNeedsUnbufferedInputEvents(true);
frame_dispatcher_ = std::make_unique<CanvasResourceDispatcher>(
- nullptr, surface_layer_bridge_->GetFrameSinkId().client_id(),
+ nullptr,
+ GetPage()
+ ->GetPageScheduler()
+ ->GetAgentGroupScheduler()
+ .CompositorTaskRunner(),
+ surface_layer_bridge_->GetFrameSinkId().client_id(),
surface_layer_bridge_->GetFrameSinkId().sink_id(),
CanvasResourceDispatcher::kInvalidPlaceholderCanvasId, size_);
// We don't actually need the begin frame signal when in low latency mode,
@@ -469,6 +480,12 @@ void HTMLCanvasElement::DidDraw() {
void HTMLCanvasElement::PreFinalizeFrame() {
RecordCanvasSizeToUMA(size_);
+ // PreFinalizeFrame indicates the end of a script task that may have rendered
+ // into the canvas, now is a good time to unlock cache entries.
+ auto* resource_provider = ResourceProvider();
+ if (resource_provider)
+ resource_provider->ReleaseLockedImages();
+
// Low-latency 2d canvases produce their frames after the resource gets single
// buffered.
if (LowLatencyEnabled() && !dirty_rect_.IsEmpty() &&
@@ -1060,6 +1077,32 @@ void HTMLCanvasElement::toBlob(V8BlobCallback* callback,
}
}
+bool HTMLCanvasElement::IsPresentationAttribute(
+ const QualifiedName& name) const {
+ if (name == html_names::kWidthAttr || name == html_names::kHeightAttr)
+ return true;
+ return HTMLElement::IsPresentationAttribute(name);
+}
+
+void HTMLCanvasElement::CollectStyleForPresentationAttribute(
+ const QualifiedName& name,
+ const AtomicString& value,
+ MutableCSSPropertyValueSet* style) {
+ if (name == html_names::kWidthAttr) {
+ if (FastHasAttribute(html_names::kHeightAttr)) {
+ const AtomicString& height = FastGetAttribute(html_names::kHeightAttr);
+ ApplyAspectRatioToStyle(value, height, style);
+ }
+ } else if (name == html_names::kHeightAttr) {
+ if (FastHasAttribute(html_names::kWidthAttr)) {
+ const AtomicString& width = FastGetAttribute(html_names::kWidthAttr);
+ ApplyAspectRatioToStyle(width, value, style);
+ }
+ } else {
+ HTMLElement::CollectStyleForPresentationAttribute(name, value, style);
+ }
+}
+
void HTMLCanvasElement::AddListener(CanvasDrawListener* listener) {
listeners_.insert(listener);
}
@@ -1100,9 +1143,8 @@ bool HTMLCanvasElement::ShouldAccelerate() const {
return false;
// The command line flag --disable-accelerated-2d-canvas toggles this option
- if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) {
+ if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled())
return false;
- }
// Webview crashes with accelerated small canvases (crbug.com/1004304)
// Experimenting to see if this still causes crashes (crbug.com/1136603)
@@ -1393,7 +1435,7 @@ ScriptPromise HTMLCanvasElement::CreateImageBitmap(
void HTMLCanvasElement::SetOffscreenCanvasResource(
scoped_refptr<CanvasResource> image,
- unsigned resource_id) {
+ viz::ResourceId resource_id) {
OffscreenCanvasPlaceholder::SetOffscreenCanvasResource(std::move(image),
resource_id);
SetSize(OffscreenCanvasFrame()->Size());
@@ -1484,20 +1526,23 @@ String HTMLCanvasElement::GetIdFromControl(const Element* element) {
return String();
}
-void HTMLCanvasElement::CreateLayer() {
+bool HTMLCanvasElement::CreateLayer() {
DCHECK(!surface_layer_bridge_);
LocalFrame* frame = GetDocument().GetFrame();
// We do not design transferControlToOffscreen() for frame-less HTML canvas.
- if (frame) {
- surface_layer_bridge_ = std::make_unique<::blink::SurfaceLayerBridge>(
- frame->GetPage()->GetChromeClient().GetFrameSinkId(frame),
- ::blink::SurfaceLayerBridge::ContainsVideo::kNo, this,
- base::NullCallback());
- // Creates a placeholder layer first before Surface is created.
- surface_layer_bridge_->CreateSolidColorLayer();
- // This may cause the canvas to be composited.
- SetNeedsCompositingUpdate();
- }
+ if (!frame)
+ return false;
+
+ surface_layer_bridge_ = std::make_unique<::blink::SurfaceLayerBridge>(
+ frame->GetPage()->GetChromeClient().GetFrameSinkId(frame),
+ ::blink::SurfaceLayerBridge::ContainsVideo::kNo, this,
+ base::NullCallback());
+ // Creates a placeholder layer first before Surface is created.
+ surface_layer_bridge_->CreateSolidColorLayer();
+ // This may cause the canvas to be composited.
+ SetNeedsCompositingUpdate();
+
+ return true;
}
void HTMLCanvasElement::OnWebLayerUpdated() {
@@ -1539,12 +1584,15 @@ void HTMLCanvasElement::UpdateMemoryUsage() {
const int bytes_per_pixel = ColorParams().BytesPerPixel();
intptr_t gpu_memory_usage = 0;
+ uint32_t canvas_width = std::min(kMaximumCanvasSize, width());
+ uint32_t canvas_height = std::min(kMaximumCanvasSize, height());
+
if (gpu_buffer_count) {
// Switch from cpu mode to gpu mode
base::CheckedNumeric<intptr_t> checked_usage =
gpu_buffer_count * bytes_per_pixel;
- checked_usage *= width();
- checked_usage *= height();
+ checked_usage *= canvas_width;
+ checked_usage *= canvas_height;
gpu_memory_usage =
checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
}
@@ -1553,8 +1601,8 @@ void HTMLCanvasElement::UpdateMemoryUsage() {
// in all cases.
base::CheckedNumeric<intptr_t> checked_usage =
non_gpu_buffer_count * bytes_per_pixel;
- checked_usage *= width();
- checked_usage *= height();
+ checked_usage *= canvas_width;
+ checked_usage *= canvas_height;
checked_usage += gpu_memory_usage;
intptr_t externally_allocated_memory =
checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
@@ -1607,8 +1655,22 @@ void HTMLCanvasElement::ReplaceExisting2dLayerBridge(
// TODO(jochin): Consider using ResourceProvider()->RestoreBackBuffer() here
// to avoid all of this clip stack manipulation.
- if (image)
- canvas2d_bridge_->DrawFullImage(image->PaintImageForCurrentFrame());
+ if (image) {
+ auto paint_image = image->PaintImageForCurrentFrame();
+ if (!canvas2d_bridge_->IsAccelerated() && paint_image.IsTextureBacked()) {
+ // If new bridge is unaccelrated we must read back |paint_image| here.
+ // DrawFullImage will record the image and potentially raster on a worker
+ // thread, but texture backed PaintImages can't be used on a different
+ // thread.
+ auto sk_image = paint_image.GetSwSkImage();
+ auto content_id = paint_image.GetContentIdForFrame(0);
+ auto builder =
+ cc::PaintImageBuilder::WithProperties(std::move(paint_image))
+ .set_image(sk_image, content_id);
+ paint_image = builder.TakePaintImage();
+ }
+ canvas2d_bridge_->DrawFullImage(paint_image);
+ }
RestoreCanvasMatrixClipStack(canvas);
canvas2d_bridge_->DidRestoreCanvasMatrixClipStack(canvas);
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index 1d7efdc4ded..79de50a0338 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -141,9 +141,16 @@ class CORE_EXPORT HTMLCanvasElement final
return toBlob(callback, mime_type, ScriptValue(), exception_state);
}
+ bool IsPresentationAttribute(const QualifiedName&) const final;
+ void CollectStyleForPresentationAttribute(const QualifiedName&,
+ const AtomicString&,
+ MutableCSSPropertyValueSet*) final;
+
// Used for canvas capture.
void AddListener(CanvasDrawListener*);
void RemoveListener(CanvasDrawListener*);
+ // Derived from OffscreenCanvasPlaceholder.
+ bool HasCanvasCapture() const final { return !listeners_.IsEmpty(); }
// Used for rendering
void DidDraw(const FloatRect&) override;
@@ -234,7 +241,7 @@ class CORE_EXPORT HTMLCanvasElement final
// OffscreenCanvasPlaceholder implementation.
void SetOffscreenCanvasResource(scoped_refptr<CanvasResource>,
- unsigned resource_id) override;
+ viz::ResourceId resource_id) override;
void Trace(Visitor*) const override;
void SetResourceProviderForTesting(std::unique_ptr<CanvasResourceProvider>,
@@ -261,7 +268,7 @@ class CORE_EXPORT HTMLCanvasElement final
::blink::SurfaceLayerBridge* SurfaceLayerBridge() const {
return surface_layer_bridge_.get();
}
- void CreateLayer();
+ bool CreateLayer();
void DetachContext() override { context_ = nullptr; }
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
index 5e8683287c1..d2bbbae8bf8 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
@@ -34,137 +34,154 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/platform/graphics/color_behavior.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
#include "v8/include/v8.h"
namespace blink {
-// Please note that all the number "4" in the file means number of channels
-// required to describe a pixel, namely, red, green, blue and alpha.
-namespace {
-
-bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exception_state,
- DOMExceptionCode exception_code,
- const char* message) {
- if (exception_state)
- exception_state->ThrowDOMException(exception_code, message);
- return false;
-}
-
-} // namespace
-
-bool ImageData::ValidateConstructorArguments(
- const unsigned& param_flags,
- const IntSize* size,
- const unsigned& width,
- const unsigned& height,
- const NotShared<DOMArrayBufferView> data,
- const ImageDataColorSettings* color_settings,
- ExceptionState* exception_state) {
- // We accept all the combinations of colorSpace and storageFormat in an
- // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't
- // check the color settings in this function.
+ImageData* ImageData::ValidateAndCreate(
+ unsigned width,
+ base::Optional<unsigned> height,
+ base::Optional<NotShared<DOMArrayBufferView>> data,
+ const ImageDataSettings* input_settings,
+ ExceptionState& exception_state,
+ uint32_t flags) {
+ IntSize size;
+ if ((flags & RequireCanvasColorManagement &&
+ !RuntimeEnabledFeatures::CanvasColorManagementEnabled())) {
+ exception_state.ThrowTypeError("Overload resolution failed.");
+ return nullptr;
+ }
- if ((param_flags & kParamWidth) && !width) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
+ if (!width) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
"The source width is zero or not a number.");
+ return nullptr;
}
-
- if ((param_flags & kParamHeight) && !height) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The source height is zero or not a number.");
+ size.SetWidth(width);
+ if (height) {
+ if (!*height) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The source height is zero or not a number.");
+ return nullptr;
+ }
+ size.SetHeight(*height);
}
- if (param_flags & (kParamWidth | kParamHeight)) {
- base::CheckedNumeric<unsigned> data_size =
- ImageData::StorageFormatBytesPerPixel(
- kUint8ClampedArrayStorageFormatName);
- if (color_settings) {
- data_size = ImageData::StorageFormatBytesPerPixel(
- color_settings->storageFormat());
- }
- data_size *= width;
- data_size *= height;
- if (!data_size.IsValid()) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The requested image size exceeds the supported range.");
- }
+ // Populate the ImageDataSettings to use based on |input_settings|.
+ ImageDataSettings* settings = ImageDataSettings::Create();
+ if (input_settings) {
+ settings->setColorSpace(input_settings->colorSpace());
+ settings->setStorageFormat(input_settings->storageFormat());
+ }
- if (data_size.ValueOrDie() > v8::TypedArray::kMaxLength) {
- if (exception_state) {
- exception_state->ThrowRangeError(
- "Out of memory at ImageData creation.");
+ // Ensure the size does not overflow.
+ unsigned size_in_elements = 0;
+ {
+ // Please note that the number "4" in the means number of channels required
+ // to describe a pixel, namely, red, green, blue and alpha.
+ base::CheckedNumeric<unsigned> size_in_elements_checked = 4;
+ size_in_elements_checked *= size.Width();
+ size_in_elements_checked *= size.Height();
+ if (!(flags & ValidateAndCreateFlags::Context2DErrorMode)) {
+ if (!size_in_elements_checked.IsValid()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The requested image size exceeds the supported range.");
+ return nullptr;
}
- return false;
}
+ if (!size_in_elements_checked.IsValid() ||
+ size_in_elements_checked.ValueOrDie() > v8::TypedArray::kMaxLength) {
+ exception_state.ThrowRangeError("Out of memory at ImageData creation.");
+ return nullptr;
+ }
+ size_in_elements = size_in_elements_checked.ValueOrDie();
}
- unsigned data_length = 0;
- if (param_flags & kParamData) {
+ // If |data| is provided, ensure it is a reasonable format, and that it can
+ // work with |size|. Update |settings| to reflect |data|'s format.
+ if (data) {
DCHECK(data);
- if (data->GetType() != DOMArrayBufferView::ViewType::kTypeUint8Clamped &&
- data->GetType() != DOMArrayBufferView::ViewType::kTypeUint16 &&
- data->GetType() != DOMArrayBufferView::ViewType::kTypeFloat32) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kNotSupportedError,
- "The input data type is not supported.");
+ switch ((*data)->GetType()) {
+ case DOMArrayBufferView::ViewType::kTypeUint8Clamped:
+ settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ break;
+ case DOMArrayBufferView::ViewType::kTypeUint16:
+ settings->setStorageFormat(kUint16ArrayStorageFormatName);
+ break;
+ case DOMArrayBufferView::ViewType::kTypeFloat32:
+ settings->setStorageFormat(kFloat32ArrayStorageFormatName);
+ break;
+ default:
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "The input data type is not supported.");
+ return nullptr;
}
-
static_assert(
std::numeric_limits<unsigned>::max() >=
std::numeric_limits<uint32_t>::max(),
"We use UINT32_MAX as the upper bound of the input size and expect "
"that the result fits into an `unsigned`.");
- if (!base::CheckedNumeric<uint32_t>(data->byteLength())
- .AssignIfValid(&data_length)) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kNotSupportedError,
+
+ unsigned data_length_in_bytes = 0;
+ if (!base::CheckedNumeric<uint32_t>((*data)->byteLength())
+ .AssignIfValid(&data_length_in_bytes)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
"The input data is too large. The maximum size is 4294967295.");
+ return nullptr;
}
- if (!data_length) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kInvalidStateError,
- "The input data has zero elements.");
+ if (!data_length_in_bytes) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The input data has zero elements.");
+ return nullptr;
}
- data_length /= data->TypeSize();
- if (data_length % 4) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kInvalidStateError,
+
+ const unsigned data_length_in_elements =
+ data_length_in_bytes / (*data)->TypeSize();
+ if (data_length_in_elements % 4) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
"The input data length is not a multiple of 4.");
+ return nullptr;
}
- if ((param_flags & kParamWidth) && (data_length / 4) % width) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
+ const unsigned data_length_in_pixels = data_length_in_elements / 4;
+ if (data_length_in_pixels % width) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
"The input data length is not a multiple of (4 * width).");
+ return nullptr;
}
- if ((param_flags & kParamWidth) && (param_flags & kParamHeight) &&
- height != data_length / (4 * width))
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The input data length is not equal to (4 * width * height).");
+ const unsigned expected_height = data_length_in_pixels / width;
+ if (height) {
+ if (*height != expected_height) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The input data length is not equal to (4 * width * height).");
+ return nullptr;
+ }
+ } else {
+ size.SetHeight(expected_height);
+ }
}
- if (param_flags & kParamSize) {
- if (size->Width() <= 0 || size->Height() <= 0)
- return false;
- base::CheckedNumeric<unsigned> data_size = 4;
- data_size *= size->Width();
- data_size *= size->Height();
- if (!data_size.IsValid() ||
- data_size.ValueOrDie() > v8::TypedArray::kMaxLength)
- return false;
- if (param_flags & kParamData) {
- if (data_size.ValueOrDie() > data_length)
- return false;
- }
+ NotShared<DOMArrayBufferView> allocated_data;
+ if (!data) {
+ ImageDataStorageFormat storage_format =
+ GetImageDataStorageFormat(settings->storageFormat());
+ allocated_data = AllocateAndValidateDataArray(
+ size_in_elements, storage_format, &exception_state);
+ if (!allocated_data)
+ return nullptr;
}
- return true;
+ return MakeGarbageCollected<ImageData>(size, data ? *data : allocated_data,
+ settings);
}
NotShared<DOMArrayBufferView> ImageData::AllocateAndValidateDataArray(
@@ -204,333 +221,11 @@ NotShared<DOMArrayBufferView> ImageData::AllocateAndValidateDataArray(
return data_array;
}
-NotShared<DOMUint8ClampedArray> ImageData::AllocateAndValidateUint8ClampedArray(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMUint8ClampedArray> buffer_view;
- buffer_view = AllocateAndValidateDataArray(
- length, kUint8ClampedArrayStorageFormat, exception_state);
- return buffer_view;
-}
-
-NotShared<DOMUint16Array> ImageData::AllocateAndValidateUint16Array(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMUint16Array> buffer_view;
- buffer_view = AllocateAndValidateDataArray(length, kUint16ArrayStorageFormat,
- exception_state);
- return buffer_view;
-}
-
-NotShared<DOMFloat32Array> ImageData::AllocateAndValidateFloat32Array(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMFloat32Array> buffer_view;
- buffer_view = AllocateAndValidateDataArray(length, kFloat32ArrayStorageFormat,
- exception_state);
- return buffer_view;
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- const ImageDataColorSettings* color_settings) {
- if (!ValidateConstructorArguments(kParamSize, &size, 0, 0,
- NotShared<DOMArrayBufferView>(),
- color_settings))
- return nullptr;
- ImageDataStorageFormat storage_format = kUint8ClampedArrayStorageFormat;
- if (color_settings) {
- storage_format =
- ImageData::GetImageDataStorageFormat(color_settings->storageFormat());
- }
- NotShared<DOMArrayBufferView> data_array =
- AllocateAndValidateDataArray(4 * static_cast<unsigned>(size.Width()) *
- static_cast<unsigned>(size.Height()),
- storage_format);
- return data_array
- ? MakeGarbageCollected<ImageData>(size, data_array, color_settings)
- : nullptr;
-}
-
-ImageDataColorSettings* CanvasColorParamsToImageDataColorSettings(
- const CanvasColorParams& color_params) {
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- switch (color_params.ColorSpace()) {
- case CanvasColorSpace::kSRGB:
- color_settings->setColorSpace(kSRGBCanvasColorSpaceName);
- break;
- case CanvasColorSpace::kRec2020:
- color_settings->setColorSpace(kRec2020CanvasColorSpaceName);
- break;
- case CanvasColorSpace::kP3:
- color_settings->setColorSpace(kP3CanvasColorSpaceName);
- break;
- }
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
- if (color_params.PixelFormat() == CanvasPixelFormat::kF16)
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- return color_settings;
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- const CanvasColorParams& color_params) {
- ImageDataColorSettings* color_settings =
- CanvasColorParamsToImageDataColorSettings(color_params);
- return ImageData::Create(size, color_settings);
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- CanvasColorSpace color_space,
- ImageDataStorageFormat storage_format) {
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- switch (color_space) {
- case CanvasColorSpace::kSRGB:
- color_settings->setColorSpace(kSRGBCanvasColorSpaceName);
- break;
- case CanvasColorSpace::kRec2020:
- color_settings->setColorSpace(kRec2020CanvasColorSpaceName);
- break;
- case CanvasColorSpace::kP3:
- color_settings->setColorSpace(kP3CanvasColorSpaceName);
- break;
- }
-
- switch (storage_format) {
- case kUint8ClampedArrayStorageFormat:
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
- break;
- case kUint16ArrayStorageFormat:
- color_settings->setStorageFormat(kUint16ArrayStorageFormatName);
- break;
- case kFloat32ArrayStorageFormat:
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- break;
- }
-
- return ImageData::Create(size, color_settings);
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- NotShared<DOMArrayBufferView> data_array,
- const ImageDataColorSettings* color_settings) {
- if (!ImageData::ValidateConstructorArguments(
- kParamSize | kParamData, &size, 0, 0, data_array, color_settings))
- return nullptr;
- return MakeGarbageCollected<ImageData>(size, data_array, color_settings);
-}
-
-ImageData* ImageData::Create(scoped_refptr<StaticBitmapImage> image,
- AlphaDisposition alpha_disposition) {
- PaintImage paint_image = image->PaintImageForCurrentFrame();
- DCHECK(paint_image);
- SkImageInfo image_info = image->PaintImageForCurrentFrame().GetSkImageInfo();
- CanvasColorParams color_params(image_info);
- if (image_info.alphaType() != kOpaque_SkAlphaType) {
- if (alpha_disposition == kPremultiplyAlpha) {
- image_info = image_info.makeAlphaType(kPremul_SkAlphaType);
- } else if (alpha_disposition == kUnpremultiplyAlpha) {
- image_info = image_info.makeAlphaType(kUnpremul_SkAlphaType);
- }
- }
-
- ImageData* image_data = Create(image->Size(), color_params);
- if (!image_data)
- return nullptr;
-
- ImageDataArray data = image_data->data();
- SkColorType color_type = image_info.colorType();
- bool create_f32_image_data = (color_type == kRGBA_1010102_SkColorType ||
- color_type == kRGB_101010x_SkColorType ||
- color_type == kRGBA_F16_SkColorType ||
- color_type == kRGBA_F32_SkColorType);
-
- if (!create_f32_image_data) {
- if (color_type == kR16G16B16A16_unorm_SkColorType) {
- image_info = image_info.makeColorType(kR16G16B16A16_unorm_SkColorType);
- paint_image.readPixels(image_info, data.GetAsUint16Array()->Data(),
- image_info.minRowBytes(), 0, 0);
- } else {
- image_info = image_info.makeColorType(kRGBA_8888_SkColorType);
- paint_image.readPixels(image_info, data.GetAsUint8ClampedArray()->Data(),
- image_info.minRowBytes(), 0, 0);
- }
- } else {
- image_info = image_info.makeColorType(kRGBA_F32_SkColorType);
- paint_image.readPixels(image_info, data.GetAsFloat32Array()->Data(),
- image_info.minRowBytes(), 0, 0);
- }
- return image_data;
-}
-
-ImageData* ImageData::Create(unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamWidth | kParamHeight, nullptr, width, height,
- NotShared<DOMArrayBufferView>(), nullptr, &exception_state))
- return nullptr;
-
- NotShared<DOMUint8ClampedArray> byte_array =
- AllocateAndValidateUint8ClampedArray(
- ImageData::StorageFormatBytesPerPixel(
- kUint8ClampedArrayStorageFormat) *
- width * height,
- &exception_state);
- return byte_array ? MakeGarbageCollected<ImageData>(IntSize(width, height),
- byte_array)
- : nullptr;
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint8ClampedArray> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
-
- unsigned height = base::checked_cast<unsigned>(data->length()) / (width * 4);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint8ClampedArray> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint16Array> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
- unsigned height = base::checked_cast<unsigned>(data->length()) /
- (width * ImageData::StorageFormatBytesPerPixel(
- kUint16ArrayStorageFormatName));
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kUint16ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint16Array> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kUint16ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMFloat32Array> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
-
- unsigned height = base::checked_cast<unsigned>(data->length()) /
- (width * ImageData::StorageFormatBytesPerPixel(
- kFloat32ArrayStorageFormatName));
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kFloat32ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMFloat32Array> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kFloat32ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::CreateImageData(
- unsigned width,
- unsigned height,
- const ImageDataColorSettings* color_settings,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamWidth | kParamHeight, nullptr, width, height,
- NotShared<DOMArrayBufferView>(), color_settings, &exception_state))
- return nullptr;
-
- ImageDataStorageFormat storage_format =
- ImageData::GetImageDataStorageFormat(color_settings->storageFormat());
- NotShared<DOMArrayBufferView> buffer_view = AllocateAndValidateDataArray(
- 4 * width * height, storage_format, &exception_state);
-
- if (!buffer_view)
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), buffer_view,
- color_settings);
-}
-
-ImageData* ImageData::CreateImageData(ImageDataArray& data,
- unsigned width,
- unsigned height,
- ImageDataColorSettings* color_settings,
- ExceptionState& exception_state) {
- NotShared<DOMArrayBufferView> buffer_view;
-
- // When pixels data is provided, we need to override the storage format of
- // ImageDataColorSettings with the one that matches the data type of the
- // pixels.
- String storage_format_name;
-
- if (data.IsUint8ClampedArray()) {
- buffer_view = data.GetAsUint8ClampedArray();
- storage_format_name = kUint8ClampedArrayStorageFormatName;
- } else if (data.IsUint16Array()) {
- buffer_view = data.GetAsUint16Array();
- storage_format_name = kUint16ArrayStorageFormatName;
- } else if (data.IsFloat32Array()) {
- buffer_view = data.GetAsFloat32Array();
- storage_format_name = kFloat32ArrayStorageFormatName;
- } else {
- NOTREACHED();
- }
-
- if (color_settings->storageFormat() != storage_format_name)
- color_settings->setStorageFormat(storage_format_name);
-
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height,
- buffer_view, color_settings, &exception_state))
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), buffer_view,
- color_settings);
-}
-
// This function accepts size (0, 0) and always returns the ImageData in
// "srgb" color space and "uint8" storage format.
ImageData* ImageData::CreateForTest(const IntSize& size) {
base::CheckedNumeric<unsigned> data_size =
- ImageData::StorageFormatBytesPerPixel(kUint8ClampedArrayStorageFormat);
+ StorageFormatBytesPerPixel(kUint8ClampedArrayStorageFormat);
data_size *= size.Width();
data_size *= size.Height();
if (!data_size.IsValid() ||
@@ -547,65 +242,17 @@ ImageData* ImageData::CreateForTest(const IntSize& size) {
// This function is called from unit tests, and all the parameters are supposed
// to be validated on the call site.
-ImageData* ImageData::CreateForTest(
- const IntSize& size,
- NotShared<DOMArrayBufferView> buffer_view,
- const ImageDataColorSettings* color_settings) {
- return MakeGarbageCollected<ImageData>(size, buffer_view, color_settings);
-}
-
-// Crops ImageData to the intersect of its size and the given rectangle. If the
-// intersection is empty or it cannot create the cropped ImageData it returns
-// nullptr. This function leaves the source ImageData intact. When crop_rect
-// covers all the ImageData, a copy of the ImageData is returned.
-// TODO (zakerinasab): crbug.com/774484: As a rule of thumb ImageData belongs to
-// the user and its state should not change unless directly modified by the
-// user. Therefore, we should be able to remove the extra copy and return a
-// "cropped view" on the source ImageData object.
-ImageData* ImageData::CropRect(const IntRect& crop_rect, bool flip_y) {
- IntRect src_rect(IntPoint(), size_);
- const IntRect dst_rect = Intersection(src_rect, crop_rect);
- if (dst_rect.IsEmpty())
- return nullptr;
-
- unsigned data_size = 4 * dst_rect.Width() * dst_rect.Height();
- NotShared<DOMArrayBufferView> buffer_view = AllocateAndValidateDataArray(
- data_size,
- ImageData::GetImageDataStorageFormat(color_settings_->storageFormat()));
- if (!buffer_view)
- return nullptr;
-
- if (src_rect == dst_rect && !flip_y) {
- std::memcpy(buffer_view->BufferBase()->Data(), BufferBase()->Data(),
- data_size * buffer_view->TypeSize());
- } else {
- unsigned data_type_size =
- ImageData::StorageFormatBytesPerPixel(color_settings_->storageFormat());
- int src_index = (dst_rect.X() + dst_rect.Y() * src_rect.Width()) * 4;
- int dst_index = 0;
- if (flip_y)
- dst_index = (dst_rect.Height() - 1) * dst_rect.Width() * 4;
- int src_row_stride = src_rect.Width() * 4;
- int dst_row_stride = flip_y ? -dst_rect.Width() * 4 : dst_rect.Width() * 4;
- for (int i = 0; i < dst_rect.Height(); i++) {
- std::memcpy(static_cast<char*>(buffer_view->BufferBase()->Data()) +
- dst_index / 4 * data_type_size,
- static_cast<char*>(BufferBase()->Data()) +
- src_index / 4 * data_type_size,
- dst_rect.Width() * data_type_size);
- src_index += src_row_stride;
- dst_index += dst_row_stride;
- }
- }
- return MakeGarbageCollected<ImageData>(dst_rect.Size(), buffer_view,
- color_settings_);
+ImageData* ImageData::CreateForTest(const IntSize& size,
+ NotShared<DOMArrayBufferView> buffer_view,
+ const ImageDataSettings* settings) {
+ return MakeGarbageCollected<ImageData>(size, buffer_view, settings);
}
ScriptPromise ImageData::CreateImageBitmap(ScriptState* script_state,
base::Optional<IntRect> crop_rect,
const ImageBitmapOptions* options,
ExceptionState& exception_state) {
- if (BufferBase()->IsDetached()) {
+ if (IsBufferBaseDetached()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The source data has been detached.");
return ScriptPromise();
@@ -641,18 +288,6 @@ v8::Local<v8::Object> ImageData::AssociateWithWrapper(
return wrapper;
}
-CanvasColorSpace ImageData::GetCanvasColorSpace(
- const String& color_space_name) {
- if (color_space_name == kSRGBCanvasColorSpaceName)
- return CanvasColorSpace::kSRGB;
- if (color_space_name == kRec2020CanvasColorSpaceName)
- return CanvasColorSpace::kRec2020;
- if (color_space_name == kP3CanvasColorSpaceName)
- return CanvasColorSpace::kP3;
- NOTREACHED();
- return CanvasColorSpace::kSRGB;
-}
-
String ImageData::CanvasColorSpaceName(CanvasColorSpace color_space) {
switch (color_space) {
case CanvasColorSpace::kSRGB:
@@ -679,7 +314,13 @@ ImageDataStorageFormat ImageData::GetImageDataStorageFormat(
return kUint8ClampedArrayStorageFormat;
}
-ImageDataStorageFormat ImageData::GetImageDataStorageFormat() {
+CanvasColorSpace ImageData::GetCanvasColorSpace() const {
+ if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled())
+ return CanvasColorSpace::kSRGB;
+ return CanvasColorSpaceFromName(settings_->colorSpace());
+}
+
+ImageDataStorageFormat ImageData::GetImageDataStorageFormat() const {
if (data_u16_)
return kUint16ArrayStorageFormat;
if (data_f32_)
@@ -713,192 +354,38 @@ unsigned ImageData::StorageFormatBytesPerPixel(
return 1;
}
-NotShared<DOMArrayBufferView>
-ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- ArrayBufferContents& content,
- CanvasPixelFormat pixel_format,
- ImageDataStorageFormat storage_format) {
- if (!content.DataLength())
- return NotShared<DOMArrayBufferView>();
-
- if (pixel_format == CanvasColorParams::GetNativeCanvasPixelFormat() &&
- storage_format == kUint8ClampedArrayStorageFormat) {
- DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(content);
- return NotShared<DOMArrayBufferView>(DOMUint8ClampedArray::Create(
- array_buffer, 0, array_buffer->ByteLength()));
- }
-
- skcms_PixelFormat src_format = skcms_PixelFormat_RGBA_8888;
- unsigned num_pixels = content.DataLength() / 4;
- if (pixel_format == CanvasPixelFormat::kF16) {
- src_format = skcms_PixelFormat_RGBA_hhhh;
- num_pixels /= 2;
- }
- skcms_AlphaFormat alpha_format = skcms_AlphaFormat_Unpremul;
-
- if (storage_format == kUint8ClampedArrayStorageFormat) {
- NotShared<DOMUint8ClampedArray> u8_array =
- AllocateAndValidateUint8ClampedArray(num_pixels * 4);
- if (!u8_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, u8_array->Data(),
- skcms_PixelFormat_RGBA_8888, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return u8_array;
- }
-
- if (storage_format == kUint16ArrayStorageFormat) {
- NotShared<DOMUint16Array> u16_array =
- AllocateAndValidateUint16Array(num_pixels * 4);
- if (!u16_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, u16_array->Data(),
- skcms_PixelFormat_RGBA_16161616LE, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return u16_array;
- }
-
- NotShared<DOMFloat32Array> f32_array =
- AllocateAndValidateFloat32Array(num_pixels * 4);
- if (!f32_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, f32_array->Data(),
- skcms_PixelFormat_RGBA_ffff, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return f32_array;
-}
-
-DOMArrayBufferBase* ImageData::BufferBase() const {
+bool ImageData::IsBufferBaseDetached() const {
if (data_.IsUint8ClampedArray())
- return data_.GetAsUint8ClampedArray()->BufferBase();
+ return data_.GetAsUint8ClampedArray()->BufferBase()->IsDetached();
if (data_.IsUint16Array())
- return data_.GetAsUint16Array()->BufferBase();
+ return data_.GetAsUint16Array()->BufferBase()->IsDetached();
if (data_.IsFloat32Array())
- return data_.GetAsFloat32Array()->BufferBase();
- return nullptr;
-}
-
-CanvasColorParams ImageData::GetCanvasColorParams() {
- if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled())
- return CanvasColorParams();
- CanvasColorSpace color_space =
- ImageData::GetCanvasColorSpace(color_settings_->colorSpace());
- return CanvasColorParams(
- color_space,
- color_settings_->storageFormat() != kUint8ClampedArrayStorageFormatName
- ? CanvasPixelFormat::kF16
- : CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ return data_.GetAsFloat32Array()->BufferBase()->IsDetached();
+ return false;
}
-SkImageInfo ImageData::GetSkImageInfo() {
- SkColorType color_type = kN32_SkColorType;
- if (data_u16_) {
+SkPixmap ImageData::GetSkPixmap() const {
+ CHECK(!IsBufferBaseDetached());
+ SkColorType color_type = kRGBA_8888_SkColorType;
+ const void* data = nullptr;
+ if (data_.IsUint8ClampedArray()) {
+ color_type = kRGBA_8888_SkColorType;
+ data = data_.GetAsUint8ClampedArray()->Data();
+ } else if (data_.IsUint16Array()) {
color_type = kR16G16B16A16_unorm_SkColorType;
- } else if (data_f32_) {
+ data = data_.GetAsUint16Array()->Data();
+ } else if (data_.IsFloat32Array()) {
color_type = kRGBA_F32_SkColorType;
+ data = data_.GetAsFloat32Array()->Data();
}
- return SkImageInfo::Make(width(), height(), color_type,
- kUnpremul_SkAlphaType);
-}
-
-bool ImageData::ImageDataInCanvasColorSettings(
- CanvasColorSpace canvas_color_space,
- CanvasPixelFormat canvas_pixel_format,
- unsigned char* converted_pixels,
- DataU8ColorType u8_color_type,
- const IntRect* src_rect,
- const AlphaDisposition alpha_disposition) {
- if (data_.IsNull())
- return false;
-
- CanvasColorParams canvas_color_params =
- CanvasColorParams(canvas_color_space, canvas_pixel_format, kNonOpaque);
-
- unsigned char* src_data = static_cast<unsigned char*>(BufferBase()->Data());
-
- ImageDataStorageFormat storage_format = GetImageDataStorageFormat();
-
- skcms_PixelFormat src_pixel_format = skcms_PixelFormat_RGBA_8888;
- if (data_u16_)
- src_pixel_format = skcms_PixelFormat_RGBA_16161616LE;
- else if (data_f32_)
- src_pixel_format = skcms_PixelFormat_RGBA_ffff;
-
- skcms_PixelFormat dst_pixel_format = skcms_PixelFormat_RGBA_8888;
- if (canvas_pixel_format == CanvasPixelFormat::kF16) {
- dst_pixel_format = skcms_PixelFormat_RGBA_hhhh;
- }
-#if SK_PMCOLOR_BYTE_ORDER(B, G, R, A)
- else if (canvas_pixel_format ==
- CanvasColorParams::GetNativeCanvasPixelFormat() &&
- u8_color_type == kN32ColorType) {
- dst_pixel_format = skcms_PixelFormat_BGRA_8888;
- }
-#endif
-
- skcms_AlphaFormat src_alpha_format = skcms_AlphaFormat_Unpremul;
- skcms_AlphaFormat dst_alpha_format = skcms_AlphaFormat_Unpremul;
- if (alpha_disposition == kPremultiplyAlpha)
- dst_alpha_format = skcms_AlphaFormat_PremulAsEncoded;
-
- skcms_ICCProfile* src_profile_ptr = nullptr;
- skcms_ICCProfile* dst_profile_ptr = nullptr;
- skcms_ICCProfile src_profile, dst_profile;
- GetCanvasColorParams().GetSkColorSpace()->toProfile(&src_profile);
- canvas_color_params.GetSkColorSpace()->toProfile(&dst_profile);
- // If the profiles are similar, we better leave them as nullptr, since
- // skcms_Transform() only checks for profile pointer equality for the fast
- // path.
- if (!skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile)) {
- src_profile_ptr = &src_profile;
- dst_profile_ptr = &dst_profile;
- }
-
- const IntRect* crop_rect = nullptr;
- if (src_rect && *src_rect != IntRect(IntPoint(), Size()))
- crop_rect = src_rect;
-
- // If only a portion of ImageData is required for canvas, we run the transform
- // for every line.
- if (crop_rect) {
- unsigned bytes_per_pixel =
- ImageData::StorageFormatBytesPerPixel(storage_format);
- unsigned src_index =
- (crop_rect->X() + crop_rect->Y() * width()) * bytes_per_pixel;
- unsigned dst_index = 0;
- unsigned src_row_stride = width() * bytes_per_pixel;
- unsigned dst_row_stride =
- crop_rect->Width() * canvas_color_params.BytesPerPixel();
- bool data_transform_successful = true;
-
- for (int i = 0; data_transform_successful && i < crop_rect->Height(); i++) {
- data_transform_successful = skcms_Transform(
- src_data + src_index, src_pixel_format, src_alpha_format,
- src_profile_ptr, converted_pixels + dst_index, dst_pixel_format,
- dst_alpha_format, dst_profile_ptr, crop_rect->Width());
- DCHECK(data_transform_successful);
- src_index += src_row_stride;
- dst_index += dst_row_stride;
- }
- return data_transform_successful;
- }
-
- base::CheckedNumeric<uint32_t> area = size_.Area();
- if (!area.IsValid())
- return false;
- bool data_transform_successful =
- skcms_Transform(src_data, src_pixel_format, src_alpha_format,
- src_profile_ptr, converted_pixels, dst_pixel_format,
- dst_alpha_format, dst_profile_ptr, area.ValueOrDie());
- return data_transform_successful;
+ SkImageInfo info =
+ SkImageInfo::Make(width(), height(), color_type, kUnpremul_SkAlphaType,
+ CanvasColorSpaceToSkColorSpace(GetCanvasColorSpace()));
+ return SkPixmap(info, data, info.minRowBytes());
}
void ImageData::Trace(Visitor* visitor) const {
- visitor->Trace(color_settings_);
+ visitor->Trace(settings_);
visitor->Trace(data_);
visitor->Trace(data_u8_);
visitor->Trace(data_u16_);
@@ -908,8 +395,8 @@ void ImageData::Trace(Visitor* visitor) const {
ImageData::ImageData(const IntSize& size,
NotShared<DOMArrayBufferView> data,
- const ImageDataColorSettings* color_settings)
- : size_(size), color_settings_(ImageDataColorSettings::Create()) {
+ const ImageDataSettings* settings)
+ : size_(size), settings_(ImageDataSettings::Create()) {
DCHECK_GE(size.Width(), 0);
DCHECK_GE(size.Height(), 0);
DCHECK(data);
@@ -918,23 +405,17 @@ ImageData::ImageData(const IntSize& size,
data_u16_.Clear();
data_f32_.Clear();
- if (color_settings) {
- color_settings_->setColorSpace(color_settings->colorSpace());
- color_settings_->setStorageFormat(color_settings->storageFormat());
+ if (settings) {
+ settings_->setColorSpace(settings->colorSpace());
+ settings_->setStorageFormat(settings->storageFormat());
}
ImageDataStorageFormat storage_format =
- GetImageDataStorageFormat(color_settings_->storageFormat());
-
- // TODO (zakerinasab): crbug.com/779570
- // The default color space for ImageData with U16/F32 data should be
- // extended-srgb color space. It is temporarily set to linear-rgb, which is
- // not correct, but fixes crbug.com/779419.
-
+ GetImageDataStorageFormat(settings_->storageFormat());
switch (storage_format) {
case kUint8ClampedArrayStorageFormat:
- DCHECK(data->GetType() ==
- DOMArrayBufferView::ViewType::kTypeUint8Clamped);
+ DCHECK_EQ(data->GetType(),
+ DOMArrayBufferView::ViewType::kTypeUint8Clamped);
data_u8_ = data;
DCHECK(data_u8_);
data_.SetUint8ClampedArray(data_u8_);
@@ -944,7 +425,7 @@ ImageData::ImageData(const IntSize& size,
break;
case kUint16ArrayStorageFormat:
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint16);
+ DCHECK_EQ(data->GetType(), DOMArrayBufferView::ViewType::kTypeUint16);
data_u16_ = data;
DCHECK(data_u16_);
data_.SetUint16Array(data_u16_);
@@ -954,7 +435,7 @@ ImageData::ImageData(const IntSize& size,
break;
case kFloat32ArrayStorageFormat:
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeFloat32);
+ DCHECK_EQ(data->GetType(), DOMArrayBufferView::ViewType::kTypeFloat32);
data_f32_ = data;
DCHECK(data_f32_);
data_.SetFloat32Array(data_f32_);
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
index 66d026c6ff8..f6aad266f89 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.h
@@ -31,7 +31,7 @@
#include "base/numerics/checked_math.h"
#include "third_party/blink/renderer/bindings/core/v8/uint8_clamped_array_or_uint16_array_or_float32_array.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_image_data_color_settings.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_image_data_settings.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
@@ -53,13 +53,6 @@ class ImageBitmapOptions;
typedef Uint8ClampedArrayOrUint16ArrayOrFloat32Array ImageDataArray;
-enum ConstructorParams {
- kParamSize = 1,
- kParamWidth = 1 << 1,
- kParamHeight = 1 << 2,
- kParamData = 1 << 3,
-};
-
constexpr const char* kUint8ClampedArrayStorageFormatName = "uint8";
constexpr const char* kUint16ArrayStorageFormatName = "uint16";
constexpr const char* kFloat32ArrayStorageFormatName = "float32";
@@ -69,75 +62,130 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
DEFINE_WRAPPERTYPEINFO();
public:
- static ImageData* Create(const IntSize&,
- const ImageDataColorSettings* = nullptr);
- static ImageData* Create(const IntSize&, const CanvasColorParams&);
- static ImageData* Create(const IntSize&,
- CanvasColorSpace,
- ImageDataStorageFormat);
- static ImageData* Create(const IntSize&,
- NotShared<DOMArrayBufferView>,
- const ImageDataColorSettings* = nullptr);
- static ImageData* Create(scoped_refptr<StaticBitmapImage>,
- AlphaDisposition = kDontChangeAlpha);
-
- static ImageData* Create(unsigned width, unsigned height, ExceptionState&);
- static ImageData* Create(NotShared<DOMUint8ClampedArray>,
+ // Constructor that takes width, height, and an optional ImageDataSettings.
+ static ImageData* Create(unsigned width,
+ unsigned height,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, base::nullopt, nullptr,
+ exception_state);
+ }
+ static ImageData* Create(unsigned width,
+ unsigned height,
+ const ImageDataSettings* settings,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, base::nullopt, settings,
+ exception_state, RequireCanvasColorManagement);
+ }
+
+ // Constructor that takes Uint8ClampedArray, width, optional height, and
+ // optional ImageDataSettings.
+ static ImageData* Create(NotShared<DOMUint8ClampedArray> data,
unsigned width,
- ExceptionState&);
- static ImageData* Create(NotShared<DOMUint8ClampedArray>,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, base::nullopt, data, nullptr,
+ exception_state);
+ }
+ static ImageData* Create(NotShared<DOMUint8ClampedArray> data,
unsigned width,
unsigned height,
- ExceptionState&);
- static ImageData* Create(NotShared<DOMUint16Array>,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, nullptr, exception_state);
+ }
+ static ImageData* Create(NotShared<DOMUint8ClampedArray> data,
unsigned width,
- ExceptionState&);
- static ImageData* Create(NotShared<DOMUint16Array>,
+ unsigned height,
+ const ImageDataSettings* settings,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, settings, exception_state,
+ RequireCanvasColorManagement);
+ }
+
+ // Constructor that takes DOMUint16Array, width, optional height, and optional
+ // ImageDataSettings.
+ static ImageData* Create(NotShared<DOMUint16Array> data,
+ unsigned width,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, base::nullopt, data, nullptr,
+ exception_state, RequireCanvasColorManagement);
+ }
+ static ImageData* Create(NotShared<DOMUint16Array> data,
unsigned width,
unsigned height,
- ExceptionState&);
- static ImageData* Create(NotShared<DOMFloat32Array>,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, nullptr, exception_state,
+ RequireCanvasColorManagement);
+ }
+ static ImageData* Create(NotShared<DOMUint16Array> data,
unsigned width,
- ExceptionState&);
- static ImageData* Create(NotShared<DOMFloat32Array>,
+ unsigned height,
+ const ImageDataSettings* settings,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, settings, exception_state,
+ RequireCanvasColorManagement);
+ }
+
+ // Constructor that takes DOMFloat32Array, width, optional height, and
+ // optional ImageDataSettings.
+ static ImageData* Create(NotShared<DOMFloat32Array> data,
+ unsigned width,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, base::nullopt, data, nullptr,
+ exception_state, RequireCanvasColorManagement);
+ }
+ static ImageData* Create(NotShared<DOMFloat32Array> data,
unsigned width,
unsigned height,
- ExceptionState&);
-
- static ImageData* CreateImageData(unsigned width,
- unsigned height,
- const ImageDataColorSettings*,
- ExceptionState&);
- static ImageData* CreateImageData(ImageDataArray&,
- unsigned width,
- unsigned height,
- ImageDataColorSettings*,
- ExceptionState&);
-
- ImageDataColorSettings* getColorSettings() { return color_settings_; }
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, nullptr, exception_state,
+ RequireCanvasColorManagement);
+ }
+ static ImageData* Create(NotShared<DOMFloat32Array> data,
+ unsigned width,
+ unsigned height,
+ const ImageDataSettings* settings,
+ ExceptionState& exception_state) {
+ return ValidateAndCreate(width, height, data, settings, exception_state,
+ RequireCanvasColorManagement);
+ }
+
+ // ValidateAndCreate is the common path that all ImageData creation code
+ // should call directly. The other Create functions are to be called only by
+ // generated code.
+ enum ValidateAndCreateFlags {
+ None = 0x0,
+ // When a too-large ImageData is created using a constructor, it has
+ // historically thrown an IndexSizeError. When created through a 2D
+ // canvas, it has historically thrown a RangeError. This flag will
+ // trigger the RangeError path.
+ Context2DErrorMode = 0x1,
+ // Constructors in IDL files cannot specify RuntimeEnabled restrictions.
+ // This argument is passed by Create functions that should require that the
+ // CanvasColorManagement feature be enabled.
+ RequireCanvasColorManagement = 0x2,
+ };
+ static ImageData* ValidateAndCreate(
+ unsigned width,
+ base::Optional<unsigned> height,
+ base::Optional<NotShared<DOMArrayBufferView>> data,
+ const ImageDataSettings* settings,
+ ExceptionState& exception_state,
+ uint32_t flags = 0);
+
+ ImageDataSettings* getSettings() { return settings_; }
static ImageData* CreateForTest(const IntSize&);
static ImageData* CreateForTest(const IntSize&,
NotShared<DOMArrayBufferView>,
- const ImageDataColorSettings* = nullptr);
+ const ImageDataSettings* = nullptr);
ImageData(const IntSize&,
NotShared<DOMArrayBufferView>,
- const ImageDataColorSettings* = nullptr);
-
- ImageData* CropRect(const IntRect&, bool flip_y = false);
+ const ImageDataSettings* = nullptr);
- ImageDataStorageFormat GetImageDataStorageFormat();
- static CanvasColorSpace GetCanvasColorSpace(const String&);
static String CanvasColorSpaceName(CanvasColorSpace);
static ImageDataStorageFormat GetImageDataStorageFormat(const String&);
static unsigned StorageFormatBytesPerPixel(const String&);
static unsigned StorageFormatBytesPerPixel(ImageDataStorageFormat);
- static NotShared<DOMArrayBufferView>
- ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- ArrayBufferContents&,
- CanvasPixelFormat,
- ImageDataStorageFormat);
IntSize Size() const { return size_; }
int width() const { return size_.Width(); }
@@ -147,22 +195,12 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
const ImageDataArray& data() const { return data_; }
void data(ImageDataArray& result) { result = data_; }
- DOMArrayBufferBase* BufferBase() const;
- CanvasColorParams GetCanvasColorParams();
- SkImageInfo GetSkImageInfo();
-
- // DataU8ColorType param specifies if the converted pixels in uint8 pixel
- // format should respect the "native" 32bit ARGB format of Skia's blitters.
- // For example, if ImageDataInCanvasColorSettings() is called to fill an
- // ImageBuffer, kRGBAColorType should be used. If the converted pixels are
- // used to create an ImageBitmap, kN32ColorType should be used.
- bool ImageDataInCanvasColorSettings(
- CanvasColorSpace,
- CanvasPixelFormat,
- unsigned char* converted_pixels,
- DataU8ColorType,
- const IntRect* = nullptr,
- const AlphaDisposition = kUnpremultiplyAlpha);
+ bool IsBufferBaseDetached() const;
+ CanvasColorSpace GetCanvasColorSpace() const;
+ ImageDataStorageFormat GetImageDataStorageFormat() const;
+
+ // Return an SkPixmap that references this data directly.
+ SkPixmap GetSkPixmap() const;
// ImageBitmapSource implementation
IntSize BitmapSourceSize() const override { return size_; }
@@ -178,18 +216,9 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
const WrapperTypeInfo*,
v8::Local<v8::Object> wrapper) override;
- static bool ValidateConstructorArguments(
- const unsigned&,
- const IntSize* = nullptr,
- const unsigned& = 0,
- const unsigned& = 0,
- const NotShared<DOMArrayBufferView> = NotShared<DOMArrayBufferView>(),
- const ImageDataColorSettings* = nullptr,
- ExceptionState* = nullptr);
-
private:
IntSize size_;
- Member<ImageDataColorSettings> color_settings_;
+ Member<ImageDataSettings> settings_;
ImageDataArray data_;
NotShared<DOMUint8ClampedArray> data_u8_;
NotShared<DOMUint16Array> data_u16_;
@@ -199,18 +228,6 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
const unsigned&,
ImageDataStorageFormat,
ExceptionState* = nullptr);
-
- static NotShared<DOMUint8ClampedArray> AllocateAndValidateUint8ClampedArray(
- const unsigned&,
- ExceptionState* = nullptr);
-
- static NotShared<DOMUint16Array> AllocateAndValidateUint16Array(
- const unsigned&,
- ExceptionState* = nullptr);
-
- static NotShared<DOMFloat32Array> AllocateAndValidateFloat32Array(
- const unsigned&,
- ExceptionState* = nullptr);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl b/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl
index 2ec2035d6cb..07cb4737629 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.idl
@@ -35,9 +35,11 @@ typedef (Uint8ClampedArray or Uint16Array or Float32Array) ImageDataArray;
Exposed=(Window,Worker),
Serializable
] interface ImageData {
- [RaisesException] constructor(unsigned long sw, unsigned long sh);
- [RaisesException] constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh);
- [RuntimeEnabled=CanvasColorManagement] ImageDataColorSettings getColorSettings();
+ [RaisesException] constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings);
+ [RaisesException] constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings);
+ [RaisesException] constructor(Uint16Array data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings);
+ [RaisesException] constructor(Float32Array data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings);
+ [RuntimeEnabled=CanvasColorManagement] ImageDataSettings getSettings();
readonly attribute unsigned long width;
readonly attribute unsigned long height;
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data_color_settings.idl b/chromium/third_party/blink/renderer/core/html/canvas/image_data_color_settings.idl
deleted file mode 100644
index 917e0e182c8..00000000000
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data_color_settings.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/junov/CanvasColorSpace/blob/master/CanvasColorSpaceProposal.md#imageda
-
-enum CanvasColorSpace {
- "srgb", // default
- "rec2020",
- "p3",
-};
-
-enum ImageDataStorageFormat {
- "uint8", // default
- "uint16",
- "float32",
-};
-
-dictionary ImageDataColorSettings {
- CanvasColorSpace colorSpace = "srgb";
- ImageDataStorageFormat storageFormat = "uint8";
-};
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl b/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl
new file mode 100644
index 00000000000..ad08837ea08
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data_settings.idl
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/junov/CanvasColorSpace/blob/master/CanvasColorSpaceProposal.md#imageda
+
+enum CanvasColorSpace {
+ "srgb", // default
+ "rec2020",
+ "display-p3",
+};
+
+enum ImageDataStorageFormat {
+ "uint8", // default
+ "uint16",
+ "float32",
+};
+
+dictionary ImageDataSettings {
+ CanvasColorSpace colorSpace = "srgb";
+ ImageDataStorageFormat storageFormat = "uint8";
+};
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data_test.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_data_test.cc
index cddff59d6dd..13ca54e9456 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data_test.cc
@@ -27,501 +27,6 @@ TEST_F(ImageDataTest, CreateImageDataTooBig) {
}
}
-// This test verifies the correct behavior of ImageData member function used
-// to convert pixels data from canvas pixel format to image data storage
-// format. This function is used in BaseRenderingContext2D::getImageData.
-TEST_F(ImageDataTest,
- TestConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat) {
- // Source pixels in RGBA32
- unsigned char rgba32_pixels[] = {255, 0, 0, 255, // Red
- 0, 0, 0, 0, // Transparent
- 255, 192, 128, 64, // Decreasing values
- 93, 117, 205, 11}; // Random values
- const unsigned kNumColorComponents = 16;
- float f32_pixels[kNumColorComponents];
- for (unsigned i = 0; i < kNumColorComponents; i++)
- f32_pixels[i] = rgba32_pixels[i] / 255.0;
-
- const unsigned kNumPixels = kNumColorComponents / 4;
-
- // Source pixels in F16
- unsigned char f16_pixels[kNumColorComponents * 2];
- EXPECT_TRUE(skcms_Transform(f32_pixels, skcms_PixelFormat_RGBA_ffff,
- skcms_AlphaFormat_Unpremul, nullptr, f16_pixels,
- skcms_PixelFormat_RGBA_hhhh,
- skcms_AlphaFormat_Unpremul, nullptr, 4));
-
- // Source pixels in U16
- uint16_t u16_pixels[kNumColorComponents];
- for (unsigned i = 0; i < kNumColorComponents; i++)
- u16_pixels[i] = f32_pixels[i] * 65535.0;
-
- // Creating ArrayBufferContents objects. We need two buffers for RGBA32 data
- // because
- // CanvasPixelFormat::kRGBA8->kUint8ClampedArrayStorageFormat
- // consumes the input data parameter.
- ArrayBufferContents contents_rgba32(kNumColorComponents, 1,
- ArrayBufferContents::kNotShared,
- ArrayBufferContents::kDontInitialize);
- std::memcpy(contents_rgba32.Data(), rgba32_pixels, kNumColorComponents);
-
- ArrayBufferContents contents_rgba32_2;
- contents_rgba32.CopyTo(contents_rgba32_2);
-
- ArrayBufferContents contents_f16(kNumColorComponents * 2, 1,
- ArrayBufferContents::kNotShared,
- ArrayBufferContents::kDontInitialize);
- std::memcpy(contents_f16.Data(), f16_pixels, kNumColorComponents * 2);
-
- // Testing CanvasPixelFormat::kRGBA8->
- // kUint8ClampedArrayStorageFormat
- NotShared<DOMArrayBufferView> data(
- ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_rgba32, CanvasPixelFormat::kRGBA8,
- kUint8ClampedArrayStorageFormat));
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint8Clamped);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), rgba32_pixels, kNumPixels, kPixelFormat_8888,
- kAlphaUnmultiplied, kNoUnpremulRoundTripTolerance);
-
- // Testing CanvasPixelFormat::kRGBA8->
- // kUint16ArrayStorageFormat
- data = ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_rgba32_2, CanvasPixelFormat::kRGBA8, kUint16ArrayStorageFormat);
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint16);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), u16_pixels, kNumPixels, kPixelFormat_16161616,
- kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
- // Testing CanvasPixelFormat::kRGBA8 ->
- // kFloat32ArrayStorageFormat
- data = ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_rgba32_2, CanvasPixelFormat::kRGBA8, kFloat32ArrayStorageFormat);
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeFloat32);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), f32_pixels, kNumPixels, kPixelFormat_ffff,
- kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
-
- // Testing CanvasPixelFormat::kF16 -> kUint8ClampedArrayStorageFormat
- data = ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_f16, CanvasPixelFormat::kF16, kUint8ClampedArrayStorageFormat);
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint8Clamped);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), rgba32_pixels, kNumPixels, kPixelFormat_8888,
- kAlphaUnmultiplied, kNoUnpremulRoundTripTolerance);
-
- // Testing CanvasPixelFormat::kF16 -> kUint16ArrayStorageFormat
- data = ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_f16, CanvasPixelFormat::kF16, kUint16ArrayStorageFormat);
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint16);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), u16_pixels, kNumPixels, kPixelFormat_16161616,
- kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
-
- // Testing CanvasPixelFormat::kF16 -> kFloat32ArrayStorageFormat
- data = ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents_f16, CanvasPixelFormat::kF16, kFloat32ArrayStorageFormat);
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeFloat32);
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- data->BaseAddress(), f32_pixels, kNumPixels, kPixelFormat_ffff,
- kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
-}
-
-// This test verifies the correct behavior of ImageData member function used
-// to convert image data from image data storage format to canvas pixel format.
-// This function is used in BaseRenderingContext2D::putImageData.
-TEST_F(ImageDataTest, TestGetImageDataInCanvasColorSettings) {
- unsigned num_image_data_color_spaces = 3;
- CanvasColorSpace image_data_color_spaces[] = {
- CanvasColorSpace::kSRGB,
- CanvasColorSpace::kRec2020,
- CanvasColorSpace::kP3,
- };
-
- unsigned num_image_data_storage_formats = 3;
- ImageDataStorageFormat image_data_storage_formats[] = {
- kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat,
- kFloat32ArrayStorageFormat,
- };
-
- unsigned num_canvas_color_settings = 3;
- CanvasColorSpace canvas_color_spaces[] = {
- CanvasColorSpace::kSRGB,
- CanvasColorSpace::kSRGB,
- CanvasColorSpace::kRec2020,
- CanvasColorSpace::kP3,
- };
-
- CanvasPixelFormat canvas_pixel_formats[] = {
- CanvasPixelFormat::kRGBA8, CanvasPixelFormat::kF16,
- CanvasPixelFormat::kF16, CanvasPixelFormat::kF16,
- };
-
- // As cross checking the output of Skia color space covnersion API is not in
- // the scope of this unit test, we do turn-around tests here. To do so, we
- // create an ImageData with the selected color space and storage format,
- // convert it to the target canvas color space and pixel format by calling
- // ImageData::imageDataInCanvasColorSettings(), and then convert it back
- // to the source image data color space and Float32 storage format by calling
- // ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat().
- // We expect to get the same image data as we started with.
-
- // Source pixels in RGBA32, unpremul
- uint8_t u8_pixels[] = {255, 0, 0, 255, // Red
- 0, 0, 0, 0, // Transparent
- 255, 192, 128, 64, // Decreasing values
- 93, 117, 205, 11}; // Random values
- size_t data_length = 16;
-
- uint16_t* u16_pixels = new uint16_t[data_length];
- for (size_t i = 0; i < data_length; i++)
- u16_pixels[i] = u8_pixels[i] * 257;
-
- float* f32_pixels = new float[data_length];
- for (size_t i = 0; i < data_length; i++)
- f32_pixels[i] = u8_pixels[i] / 255.0;
-
- NotShared<DOMUint8ClampedArray> data_u8(
- DOMUint8ClampedArray::Create(u8_pixels, data_length));
- DCHECK(data_u8);
- EXPECT_EQ(data_length, data_u8->length());
- NotShared<DOMUint16Array> data_u16(
- DOMUint16Array::Create(u16_pixels, data_length));
- DCHECK(data_u16);
- EXPECT_EQ(data_length, data_u16->length());
- NotShared<DOMFloat32Array> data_f32(
- DOMFloat32Array::Create(f32_pixels, data_length));
- DCHECK(data_f32);
- EXPECT_EQ(data_length, data_f32->length());
-
- ImageData* image_data = nullptr;
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
-
- // At most two bytes are needed for output per color component.
- std::unique_ptr<uint8_t[]> pixels_converted_manually(
- new uint8_t[data_length * 2]());
- std::unique_ptr<uint8_t[]> pixels_converted_in_image_data(
- new uint8_t[data_length * 2]());
-
- // Loop through different possible combinations of image data color space and
- // storage formats and create the respective test image data objects.
- for (unsigned i = 0; i < num_image_data_color_spaces; i++) {
- color_settings->setColorSpace(
- ImageData::CanvasColorSpaceName(image_data_color_spaces[i]));
-
- for (unsigned j = 0; j < num_image_data_storage_formats; j++) {
- NotShared<DOMArrayBufferView> data_array;
- switch (image_data_storage_formats[j]) {
- case kUint8ClampedArrayStorageFormat:
- data_array = data_u8;
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
- break;
- case kUint16ArrayStorageFormat:
- data_array = data_u16;
- color_settings->setStorageFormat(kUint16ArrayStorageFormatName);
- break;
- case kFloat32ArrayStorageFormat:
- data_array = data_f32;
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- break;
- default:
- NOTREACHED();
- }
-
- image_data =
- ImageData::CreateForTest(IntSize(2, 2), data_array, color_settings);
-
- for (unsigned k = 0; k < num_canvas_color_settings; k++) {
- // Convert the original data used to create ImageData to the
- // canvas color space and canvas pixel format.
- EXPECT_TRUE(
- ColorCorrectionTestUtils::
- ConvertPixelsToColorSpaceAndPixelFormatForTest(
- data_array->BaseAddress(), data_length,
- image_data_color_spaces[i], image_data_storage_formats[j],
- canvas_color_spaces[k], canvas_pixel_formats[k],
- pixels_converted_manually, kPixelFormat_hhhh));
-
- // Convert the image data to the color settings of the canvas.
- EXPECT_TRUE(image_data->ImageDataInCanvasColorSettings(
- canvas_color_spaces[k], canvas_pixel_formats[k],
- pixels_converted_in_image_data.get(), kRGBAColorType));
-
- // Compare the converted pixels
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- pixels_converted_manually.get(),
- pixels_converted_in_image_data.get(),
- static_cast<int>(image_data->Size().Area()),
- (canvas_pixel_formats[k] == CanvasPixelFormat::kRGBA8)
- ? kPixelFormat_8888
- : kPixelFormat_hhhh,
- kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
- }
- }
- }
- delete[] u16_pixels;
- delete[] f32_pixels;
-}
-
-// This test examines ImageData::Create(StaticBitmapImage)
-TEST_F(ImageDataTest, TestCreateImageDataFromStaticBitmapImage) {
- const unsigned kNumColorComponents = 16;
- const unsigned kNumPixels = kNumColorComponents / 4;
- const unsigned kWidth = 2;
- const unsigned kHeight = 2;
-
- // Preparing source pixels
- uint8_t expected_u8_pixels_unpremul[] = {
- 255, 0, 0, 255, // Red
- 0, 0, 0, 0, // Transparent
- 255, 192, 128, 64, // Decreasing values
- 93, 117, 205, 41}; // Random values
-
- uint8_t expected_u8_pixels_premul[kNumColorComponents];
- uint16_t expected_f16_pixels_unpremul[kNumColorComponents];
- uint16_t expected_f16_pixels_premul[kNumColorComponents];
- float expected_f32_pixels_unpremul[kNumColorComponents];
- float expected_f32_pixels_premul[kNumColorComponents];
-
- auto prepareSourcePixels = [&expected_u8_pixels_unpremul, &kNumPixels](
- auto buffer, bool is_premul,
- auto pixel_format) {
- EXPECT_TRUE(skcms_Transform(
- expected_u8_pixels_unpremul, skcms_PixelFormat_RGBA_8888,
- skcms_AlphaFormat_Unpremul, nullptr, buffer, pixel_format,
- is_premul ? skcms_AlphaFormat_PremulAsEncoded
- : skcms_AlphaFormat_Unpremul,
- nullptr, kNumPixels));
- };
-
- prepareSourcePixels(expected_u8_pixels_premul, true,
- skcms_PixelFormat_RGBA_8888);
- prepareSourcePixels(expected_f16_pixels_unpremul, false,
- skcms_PixelFormat_RGBA_hhhh);
- prepareSourcePixels(expected_f16_pixels_premul, true,
- skcms_PixelFormat_RGBA_hhhh);
- prepareSourcePixels(expected_f32_pixels_unpremul, false,
- skcms_PixelFormat_RGBA_ffff);
- prepareSourcePixels(expected_f32_pixels_premul, true,
- skcms_PixelFormat_RGBA_ffff);
-
- auto contents_u8_premul =
- SkData::MakeWithoutCopy(expected_u8_pixels_premul, kNumColorComponents);
- auto contents_u8_unpremul =
- SkData::MakeWithoutCopy(expected_u8_pixels_unpremul, kNumColorComponents);
- auto contents_f16_premul = SkData::MakeWithoutCopy(expected_f16_pixels_premul,
- kNumColorComponents * 2);
- auto contents_f16_unpremul = SkData::MakeWithoutCopy(
- expected_f16_pixels_unpremul, kNumColorComponents * 2);
-
- // Preparing StaticBitmapImage objects
- auto info_u8_premul = SkImageInfo::Make(
- kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
- auto info_u8_unpremul = info_u8_premul.makeAlphaType(kUnpremul_SkAlphaType);
- auto info_f16_premul = info_u8_premul.makeColorType(kRGBA_F16_SkColorType)
- .makeColorSpace(SkColorSpace::MakeSRGBLinear());
- auto info_f16_unpremul = info_f16_premul.makeAlphaType(kUnpremul_SkAlphaType);
-
- auto image_u8_premul =
- StaticBitmapImage::Create(contents_u8_premul, info_u8_premul);
- auto image_u8_unpremul =
- StaticBitmapImage::Create(contents_u8_unpremul, info_u8_unpremul);
- auto image_f16_premul =
- StaticBitmapImage::Create(contents_f16_premul, info_f16_premul);
- auto image_f16_unpremul =
- StaticBitmapImage::Create(contents_f16_unpremul, info_f16_unpremul);
-
- // Creating ImageData objects
- ImageData* actual_image_data_u8[4];
- ImageData* actual_image_data_f32[4];
- // u8 premul
- actual_image_data_u8[0] = ImageData::Create(image_u8_premul);
- actual_image_data_u8[1] =
- ImageData::Create(image_u8_unpremul, kPremultiplyAlpha);
- // u8 unpremul
- actual_image_data_u8[2] = ImageData::Create(image_u8_unpremul);
- actual_image_data_u8[3] =
- ImageData::Create(image_u8_premul, kUnpremultiplyAlpha);
-
- // ImageData does not support half float storage. Therefore, ImageData
- // objects that are created from half-float backed StaticBitmapImage objects
- // will contain float 32 data items.
-
- // f32 premul
- actual_image_data_f32[0] = ImageData::Create(image_f16_premul);
- actual_image_data_f32[1] =
- ImageData::Create(image_f16_unpremul, kPremultiplyAlpha);
- // f32 unpremul
- actual_image_data_f32[2] = ImageData::Create(image_f16_unpremul);
- actual_image_data_f32[3] =
- ImageData::Create(image_f16_premul, kUnpremultiplyAlpha);
-
- // Associating expected color component arrays
- uint8_t* expected_pixel_arrays_u8[4] = {
- expected_u8_pixels_premul, expected_u8_pixels_premul,
- expected_u8_pixels_unpremul, expected_u8_pixels_unpremul};
- float* expected_pixel_arrays_f32[4] = {
- expected_f32_pixels_premul, expected_f32_pixels_premul,
- expected_f32_pixels_unpremul, expected_f32_pixels_unpremul};
-
- // Comparing ImageData with the source StaticBitmapImage
- for (unsigned i = 0; i < 4; i++) {
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- expected_pixel_arrays_u8[i],
- actual_image_data_u8[i]->BufferBase()->Data(), kNumPixels,
- kPixelFormat_8888, kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
- }
-
- for (unsigned i = 0; i < 4; i++) {
- ColorCorrectionTestUtils::CompareColorCorrectedPixels(
- expected_pixel_arrays_f32[i],
- actual_image_data_f32[i]->BufferBase()->Data(), kNumPixels,
- kPixelFormat_ffff, kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
- }
-}
-
-// This test examines ImageData::CropRect()
-TEST_F(ImageDataTest, TestCropRect) {
- const int num_image_data_storage_formats = 3;
- ImageDataStorageFormat image_data_storage_formats[] = {
- kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat,
- kFloat32ArrayStorageFormat,
- };
- String image_data_storage_format_names[] = {
- kUint8ClampedArrayStorageFormatName, kUint16ArrayStorageFormatName,
- kFloat32ArrayStorageFormatName,
- };
-
- // Source pixels
- unsigned width = 20;
- unsigned height = 20;
- size_t data_length = width * height * 4;
- uint8_t* u8_pixels = new uint8_t[data_length];
- uint16_t* u16_pixels = new uint16_t[data_length];
- float* f32_pixels = new float[data_length];
-
- // Test scenarios
- const int num_test_cases = 14;
- const IntRect crop_rects[14] = {
- IntRect(3, 4, 5, 6), IntRect(3, 4, 5, 6), IntRect(10, 10, 20, 20),
- IntRect(10, 10, 20, 20), IntRect(0, 0, 20, 20), IntRect(0, 0, 20, 20),
- IntRect(0, 0, 10, 10), IntRect(0, 0, 10, 10), IntRect(0, 0, 10, 0),
- IntRect(0, 0, 0, 10), IntRect(10, 0, 10, 10), IntRect(0, 10, 10, 10),
- IntRect(0, 5, 20, 15), IntRect(0, 5, 20, 15)};
- const bool crop_flips[14] = {true, false, true, false, true, false, true,
- false, false, false, false, false, true, false};
-
- // Fill the pixels with numbers related to their positions
- unsigned set_value = 0;
- unsigned expected_value = 0;
- float fexpected_value = 0;
- unsigned index = 0, row_index = 0;
- for (unsigned i = 0; i < height; i++)
- for (unsigned j = 0; j < width; j++)
- for (unsigned k = 0; k < 4; k++) {
- index = i * width * 4 + j * 4 + k;
- set_value = (i + 1) * (j + 1) * (k + 1);
- u8_pixels[index] = set_value % 255;
- u16_pixels[index] = (set_value * 257) % 65535;
- f32_pixels[index] = (set_value % 255) / 255.0f;
- }
-
- // Create ImageData objects
-
- NotShared<DOMUint8ClampedArray> data_u8(
- DOMUint8ClampedArray::Create(u8_pixels, data_length));
- DCHECK(data_u8);
- EXPECT_EQ(data_length, data_u8->length());
- NotShared<DOMUint16Array> data_u16(
- DOMUint16Array::Create(u16_pixels, data_length));
- DCHECK(data_u16);
- EXPECT_EQ(data_length, data_u16->length());
- NotShared<DOMFloat32Array> data_f32(
- DOMFloat32Array::Create(f32_pixels, data_length));
- DCHECK(data_f32);
- EXPECT_EQ(data_length, data_f32->length());
-
- ImageData* image_data = nullptr;
- ImageData* cropped_image_data = nullptr;
-
- bool test_passed = true;
- for (int i = 0; i < num_image_data_storage_formats; i++) {
- NotShared<DOMArrayBufferView> data_array;
- if (image_data_storage_formats[i] == kUint8ClampedArrayStorageFormat)
- data_array = data_u8;
- else if (image_data_storage_formats[i] == kUint16ArrayStorageFormat)
- data_array = data_u16;
- else
- data_array = data_f32;
-
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- color_settings->setStorageFormat(image_data_storage_format_names[i]);
- image_data = ImageData::CreateForTest(IntSize(width, height), data_array,
- color_settings);
- for (int j = 0; j < num_test_cases; j++) {
- // Test the size of the cropped image data
- IntRect src_rect(IntPoint(), image_data->Size());
- IntRect crop_rect = Intersection(src_rect, crop_rects[j]);
-
- cropped_image_data = image_data->CropRect(crop_rects[j], crop_flips[j]);
- if (crop_rect.IsEmpty()) {
- EXPECT_FALSE(cropped_image_data);
- continue;
- }
- EXPECT_TRUE(cropped_image_data->Size() == crop_rect.Size());
-
- // Test the content
- for (int k = 0; k < crop_rect.Height(); k++)
- for (int m = 0; m < crop_rect.Width(); m++)
- for (int n = 0; n < 4; n++) {
- row_index = crop_flips[j] ? (crop_rect.Height() - k - 1) : k;
- index =
- row_index * cropped_image_data->Size().Width() * 4 + m * 4 + n;
- expected_value =
- (k + crop_rect.Y() + 1) * (m + crop_rect.X() + 1) * (n + 1);
- if (image_data_storage_formats[i] ==
- kUint8ClampedArrayStorageFormat)
- expected_value %= 255;
- else if (image_data_storage_formats[i] == kUint16ArrayStorageFormat)
- expected_value = (expected_value * 257) % 65535;
- else
- fexpected_value = (expected_value % 255) / 255.0f;
-
- if (image_data_storage_formats[i] ==
- kUint8ClampedArrayStorageFormat) {
- if (cropped_image_data->data()
- .GetAsUint8ClampedArray()
- ->Data()[index] != expected_value) {
- test_passed = false;
- break;
- }
- } else if (image_data_storage_formats[i] ==
- kUint16ArrayStorageFormat) {
- if (cropped_image_data->data()
- .GetAsUint16Array()
- .View()
- ->Data()[index] != expected_value) {
- test_passed = false;
- break;
- }
- } else {
- if (cropped_image_data->data()
- .GetAsFloat32Array()
- .View()
- ->Data()[index] != fexpected_value) {
- test_passed = false;
- break;
- }
- }
- }
- EXPECT_TRUE(test_passed);
- }
- }
-
- delete[] u8_pixels;
- delete[] u16_pixels;
- delete[] f32_pixels;
-}
-
TEST_F(ImageDataTest, ImageDataTooBigToAllocateDoesNotCrash) {
ImageData* image_data = ImageData::CreateForTest(
IntSize(1, (v8::TypedArray::kMaxLength / 4) + 1));
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
index 33a77ea25c4..b3d0a644387 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.cc
@@ -120,6 +120,18 @@ IntSize ImageElementBase::BitmapSourceSize() const {
return image->IntrinsicSize(kDoNotRespectImageOrientation);
}
+static bool HasDimensionsForImage(SVGImage* svg_image,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions* options) {
+ if (!svg_image->ConcreteObjectSize(FloatSize()).IsEmpty())
+ return true;
+ if (crop_rect)
+ return true;
+ if (options->hasResizeWidth() && options->hasResizeHeight())
+ return true;
+ return false;
+}
+
ScriptPromise ImageElementBase::CreateImageBitmap(
ScriptState* script_state,
base::Optional<IntRect> crop_rect,
@@ -132,11 +144,20 @@ ScriptPromise ImageElementBase::CreateImageBitmap(
"No image can be retrieved from the provided element.");
return ScriptPromise();
}
- Image* image = image_content->GetImage();
- if (auto* svg_image = DynamicTo<SVGImage>(image)) {
- if (!svg_image->HasIntrinsicDimensions() &&
- (!crop_rect &&
- (!options->hasResizeWidth() || !options->hasResizeHeight()))) {
+ if (options->hasResizeWidth() && options->resizeWidth() == 0) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The resize width dimension is equal to 0.");
+ return ScriptPromise();
+ }
+ if (options->hasResizeHeight() && options->resizeHeight() == 0) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The resize width dimension is equal to 0.");
+ return ScriptPromise();
+ }
+ if (auto* svg_image = DynamicTo<SVGImage>(image_content->GetImage())) {
+ if (!HasDimensionsForImage(svg_image, crop_rect, options)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"The image element contains an SVG image without intrinsic "
@@ -170,9 +191,4 @@ Image::ImageDecodingMode ImageElementBase::GetDecodingModeForPainting(
return decoding_mode_;
}
-RespectImageOrientationEnum ImageElementBase::RespectImageOrientation() const {
- return LayoutObject::ShouldRespectImageOrientation(
- GetElement().GetLayoutObject());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
index 88f23ca7565..b88e837d1a9 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_element_base.h
@@ -60,11 +60,6 @@ class CORE_EXPORT ImageElementBase : public CanvasImageSource,
// Used with HTMLImageElement and SVGImageElement types.
Image::ImageDecodingMode GetDecodingModeForPainting(PaintImage::Id);
- // Return the image orientation setting from the layout object, if available.
- // In the absence of a layout object, kRespectImageOrientation will be
- // returned.
- RespectImageOrientationEnum RespectImageOrientation() const;
-
protected:
Image::ImageDecodingMode decoding_mode_ =
Image::ImageDecodingMode::kUnspecifiedDecode;
diff --git a/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc b/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc
new file mode 100644
index 00000000000..a2165c74e5e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc
@@ -0,0 +1,148 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/conversion_measurement_parsing.h"
+
+#include "base/time/time.h"
+#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_impression_params.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/frame.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/html_anchor_element.h"
+#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+
+namespace blink {
+
+namespace {
+
+base::Optional<WebImpression> GetImpression(
+ ExecutionContext* execution_context,
+ const String& impression_data_string,
+ const String& conversion_destination_string,
+ const base::Optional<String>& reporting_origin_string,
+ base::Optional<uint64_t> impression_expiry_milliseconds) {
+ if (!RuntimeEnabledFeatures::ConversionMeasurementEnabled(execution_context))
+ return base::nullopt;
+
+ if (!execution_context->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kConversionMeasurement)) {
+ String message =
+ "The 'conversion-measurement' feature policy must be enabled to "
+ "declare an impression.";
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kError, message));
+ return base::nullopt;
+ }
+
+ // Conversion measurement is only allowed when both the frame and the main
+ // frame (if different) have a secure origin.
+ LocalFrame* frame = nullptr;
+ if (auto* window = DynamicTo<LocalDOMWindow>(execution_context)) {
+ frame = window->GetFrame();
+ } else {
+ return base::nullopt;
+ }
+
+ const Frame& main_frame = frame->Tree().Top();
+ if (!main_frame.GetSecurityContext()
+ ->GetSecurityOrigin()
+ ->IsPotentiallyTrustworthy()) {
+ return base::nullopt;
+ }
+
+ if (!frame->IsMainFrame() && !frame->GetSecurityContext()
+ ->GetSecurityOrigin()
+ ->IsPotentiallyTrustworthy()) {
+ return base::nullopt;
+ }
+
+ scoped_refptr<const SecurityOrigin> conversion_destination =
+ SecurityOrigin::CreateFromString(conversion_destination_string);
+ if (!conversion_destination->IsPotentiallyTrustworthy())
+ return base::nullopt;
+
+ bool impression_data_is_valid = false;
+ uint64_t impression_data =
+ impression_data_string.ToUInt64Strict(&impression_data_is_valid);
+
+ // Provide a default of 0 if the impression data was not valid.
+ impression_data = impression_data_is_valid ? impression_data : 0UL;
+
+ // Reporting origin is an optional attribute. Reporting origins must be
+ // secure.
+ base::Optional<WebSecurityOrigin> reporting_origin;
+ if (reporting_origin_string) {
+ reporting_origin =
+ SecurityOrigin::CreateFromString(*reporting_origin_string);
+
+ if (!reporting_origin->IsPotentiallyTrustworthy())
+ return base::nullopt;
+ }
+
+ base::Optional<base::TimeDelta> expiry;
+ if (impression_expiry_milliseconds)
+ expiry = base::TimeDelta::FromMilliseconds(*impression_expiry_milliseconds);
+
+ UseCounter::Count(execution_context,
+ mojom::blink::WebFeature::kConversionAPIAll);
+ UseCounter::Count(execution_context,
+ mojom::blink::WebFeature::kImpressionRegistration);
+
+ return WebImpression{conversion_destination, reporting_origin,
+ impression_data, expiry};
+}
+
+} // namespace
+
+base::Optional<WebImpression> GetImpressionForAnchor(
+ HTMLAnchorElement* element) {
+ base::Optional<uint64_t> expiry;
+ if (element->hasAttribute(html_names::kImpressionexpiryAttr)) {
+ bool expiry_is_valid = false;
+ uint64_t expiry_milliseconds =
+ element->FastGetAttribute(html_names::kImpressionexpiryAttr)
+ .GetString()
+ .ToUInt64Strict(&expiry_is_valid);
+ if (expiry_is_valid)
+ expiry = expiry_milliseconds;
+ }
+
+ DCHECK(element->hasAttribute(html_names::kConversiondestinationAttr));
+ DCHECK(element->hasAttribute(html_names::kImpressiondataAttr));
+
+ return GetImpression(
+ element->GetExecutionContext(),
+ element->FastGetAttribute(html_names::kImpressiondataAttr).GetString(),
+ element->FastGetAttribute(html_names::kConversiondestinationAttr)
+ .GetString(),
+ element->hasAttribute(html_names::kReportingoriginAttr)
+ ? base::make_optional(
+ element->FastGetAttribute(html_names::kReportingoriginAttr)
+ .GetString())
+ : base::nullopt,
+ expiry);
+}
+
+base::Optional<WebImpression> GetImpressionForParams(
+ ExecutionContext* execution_context,
+ const ImpressionParams* params) {
+ return GetImpression(execution_context, params->impressionData(),
+ params->conversionDestination(),
+ params->hasReportingOrigin()
+ ? base::make_optional(params->reportingOrigin())
+ : base::nullopt,
+ params->hasImpressionExpiry()
+ ? base::make_optional(params->impressionExpiry())
+ : base::nullopt);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.h b/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.h
new file mode 100644
index 00000000000..82e4c04c632
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/conversion_measurement_parsing.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CONVERSION_MEASUREMENT_PARSING_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CONVERSION_MEASUREMENT_PARSING_H_
+
+#include <stdint.h>
+#include <memory>
+
+#include "base/optional.h"
+#include "third_party/blink/public/platform/web_impression.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class ExecutionContext;
+class HTMLAnchorElement;
+class ImpressionParams;
+
+// Returns the WebImpression struct with all data declared by impression
+// related attributes on |element|. If the impression attributes do not contain
+// allowed values, base::nullopt is returned.
+base::Optional<WebImpression> GetImpressionForAnchor(
+ HTMLAnchorElement* element);
+
+// Same as GetImpressionForAnchor(), but gets an impression specified by an
+// ImpressionParams dictionary associated with a window.open call.
+base::Optional<WebImpression> GetImpressionForParams(
+ ExecutionContext* execution_context,
+ const ImpressionParams* params);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CONVERSION_MEASUREMENT_PARSING_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
index 7e121c6c15a..88c244e0cd5 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element.cc
@@ -12,8 +12,6 @@
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_unknown_element.h"
#include "third_party/blink/renderer/core/html_element_factory.h"
@@ -144,8 +142,7 @@ HTMLElement* CustomElement::CreateCustomElement(Document& document,
document, tag_name, flags, g_null_atom));
}
-// Step 7 of https://dom.spec.whatwg.org/#concept-create-element in
-// addition to Custom Element V0 handling.
+// Step 7 of https://dom.spec.whatwg.org/#concept-create-element
template <CustomElement::CreateUUCheckLevel level>
Element* CustomElement::CreateUncustomizedOrUndefinedElementTemplate(
Document& document,
@@ -157,29 +154,11 @@ Element* CustomElement::CreateUncustomizedOrUndefinedElementTemplate(
DCHECK(ShouldCreateCustomElement(tag_name)) << tag_name;
}
- Element* element;
- if (RuntimeEnabledFeatures::CustomElementsV0Enabled()) {
- if (V0CustomElement::IsValidName(tag_name.LocalName()) &&
- document.RegistrationContext()) {
- element = document.RegistrationContext()->CreateCustomTagElement(
- document, tag_name);
- } else {
- element = document.CreateRawElement(tag_name, flags);
- if (level == kCheckAll && !is_value.IsNull()) {
- element->SetIsValue(is_value);
- if (flags.IsCustomElementsV0()) {
- V0CustomElementRegistrationContext::SetTypeExtension(element,
- is_value);
- }
- }
- }
- } else {
- // 7.1. Let interface be the element interface for localName and namespace.
- // 7.2. Set result to a new element that implements interface, with ...
- element = document.CreateRawElement(tag_name, flags);
- if (level == kCheckAll && !is_value.IsNull())
- element->SetIsValue(is_value);
- }
+ // 7.1. Let interface be the element interface for localName and namespace.
+ // 7.2. Set result to a new element that implements interface, with ...
+ Element* element = document.CreateRawElement(tag_name, flags);
+ if (level == kCheckAll && !is_value.IsNull())
+ element->SetIsValue(is_value);
// 7.3. If namespace is the HTML namespace, and either localName is a
// valid custom element name or is is non-null, then set result’s
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
index 404a9472907..87469ef7065 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
@@ -34,12 +34,11 @@ TEST(CustomElementDefinitionTest, upgrade_clearsReactionQueueOnFailure) {
<< "sanity check: this element should be ready to upgrade";
{
CEReactionsScope reactions;
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Unreached>(
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Unreached>(
"upgrade failure should clear the reaction queue"));
reactions.EnqueueToCurrentQueue(
- element, *MakeGarbageCollected<TestReaction>(commands));
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
ConstructorFails definition(CustomElementDescriptor("a-a", "a-a"));
definition.Upgrade(element);
}
@@ -53,12 +52,11 @@ TEST(CustomElementDefinitionTest,
EXPECT_EQ(CustomElementState::kUndefined, element.GetCustomElementState())
<< "sanity check: this element should be ready to upgrade";
ResetCustomElementReactionStackForTest reset_reaction_stack;
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Unreached>(
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Unreached>(
"upgrade failure should clear the reaction queue"));
reset_reaction_stack.Stack().EnqueueToBackupQueue(
- element, *MakeGarbageCollected<TestReaction>(commands));
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
ConstructorFails definition(CustomElementDescriptor("a-a", "a-a"));
definition.Upgrade(element);
EXPECT_EQ(CustomElementState::kFailed, element.GetCustomElementState())
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
index 1e78556eabe..6570895bbc8 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.cc
@@ -32,9 +32,8 @@ void CustomElementReactionQueue::InvokeReactions(Element& element) {
reactions_[index_++] = nullptr;
reaction->Invoke(element);
}
- // Unlike V0CustomElementsCallbackQueue, reactions are always
- // inserted by steps which bump the global element queue. This
- // means we do not need queue "owner" guards.
+ // Reactions are always inserted by steps which bump the global element queue.
+ // This means we do not need queue "owner" guards.
// https://html.spec.whatwg.org/C/#custom-element-reactions
Clear();
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
index 4f3c7506adf..7703104e3e7 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
@@ -18,10 +18,9 @@ TEST(CustomElementReactionQueueTest, invokeReactions_one) {
Vector<char> log;
CustomElementReactionQueue* queue =
MakeGarbageCollected<CustomElementReactionQueue>();
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
Element* test_element = CreateElement(AtomicString("my-element"));
queue->InvokeReactions(*test_element);
EXPECT_EQ(log, Vector<char>({'a'}))
@@ -33,22 +32,19 @@ TEST(CustomElementReactionQueueTest, invokeReactions_many) {
CustomElementReactionQueue* queue =
MakeGarbageCollected<CustomElementReactionQueue>();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('c', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('c', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
Element* test_element = CreateElement(AtomicString("my-element"));
queue->InvokeReactions(*test_element);
@@ -61,27 +57,24 @@ TEST(CustomElementReactionQueueTest, invokeReactions_recursive) {
CustomElementReactionQueue* queue =
MakeGarbageCollected<CustomElementReactionQueue>();
- HeapVector<Member<Command>>* third_commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- third_commands->push_back(MakeGarbageCollected<Log>('c', log));
- third_commands->push_back(MakeGarbageCollected<Recurse>(queue));
- CustomElementReaction* third =
- MakeGarbageCollected<TestReaction>(third_commands); // "Empty" recursion
+ HeapVector<Member<Command>> third_commands;
+ third_commands.push_back(MakeGarbageCollected<Log>('c', log));
+ third_commands.push_back(MakeGarbageCollected<Recurse>(queue));
+ CustomElementReaction* third = MakeGarbageCollected<TestReaction>(
+ std::move(third_commands)); // "Empty" recursion
- HeapVector<Member<Command>>* second_commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- second_commands->push_back(MakeGarbageCollected<Log>('b', log));
- second_commands->push_back(MakeGarbageCollected<Enqueue>(queue, third));
+ HeapVector<Member<Command>> second_commands;
+ second_commands.push_back(MakeGarbageCollected<Log>('b', log));
+ second_commands.push_back(MakeGarbageCollected<Enqueue>(queue, third));
CustomElementReaction* second = MakeGarbageCollected<TestReaction>(
- second_commands); // Unwinds one level of recursion
+ std::move(second_commands)); // Unwinds one level of recursion
- HeapVector<Member<Command>>* first_commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- first_commands->push_back(MakeGarbageCollected<Log>('a', log));
- first_commands->push_back(MakeGarbageCollected<Enqueue>(queue, second));
- first_commands->push_back(MakeGarbageCollected<Recurse>(queue));
+ HeapVector<Member<Command>> first_commands;
+ first_commands.push_back(MakeGarbageCollected<Log>('a', log));
+ first_commands.push_back(MakeGarbageCollected<Enqueue>(queue, second));
+ first_commands.push_back(MakeGarbageCollected<Recurse>(queue));
CustomElementReaction* first = MakeGarbageCollected<TestReaction>(
- first_commands); // Non-empty recursion
+ std::move(first_commands)); // Non-empty recursion
queue->Add(*first);
Element* test_element = CreateElement(AtomicString("my-element"));
@@ -96,24 +89,21 @@ TEST(CustomElementReactionQueueTest, clear_duringInvoke) {
MakeGarbageCollected<CustomElementReactionQueue>();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Call>(WTF::Bind(
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Call>(WTF::Bind(
[](CustomElementReactionQueue* queue, Element&) { queue->Clear(); },
WrapPersistent(queue))));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- queue->Add(*MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ queue->Add(*MakeGarbageCollected<TestReaction>(std::move(commands)));
}
Element* test_element = CreateElement(AtomicString("my-element"));
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
index b3a8d86dab5..a515720ba83 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
@@ -21,11 +21,11 @@ TEST(CustomElementReactionStackTest, one) {
CustomElementReactionStack* stack =
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
stack->PopInvokingReactions();
EXPECT_EQ(log, Vector<char>({'a'}))
@@ -39,18 +39,18 @@ TEST(CustomElementReactionStackTest, multipleElements) {
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->PopInvokingReactions();
@@ -64,11 +64,11 @@ TEST(CustomElementReactionStackTest, popTopEmpty) {
CustomElementReactionStack* stack =
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
stack->Push();
stack->PopInvokingReactions();
@@ -83,19 +83,19 @@ TEST(CustomElementReactionStackTest, popTop) {
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->PopInvokingReactions();
@@ -112,25 +112,23 @@ TEST(CustomElementReactionStackTest, requeueingDoesNotReorderElements) {
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(element,
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('z', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('z', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(element,
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ stack->EnqueueToCurrentQueue(
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->PopInvokingReactions();
@@ -147,33 +145,31 @@ TEST(CustomElementReactionStackTest, oneReactionQueuePerElement) {
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('a', log));
- stack->EnqueueToCurrentQueue(element,
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('a', log));
+ stack->EnqueueToCurrentQueue(
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('z', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('z', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->Push();
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('y', log));
- stack->EnqueueToCurrentQueue(*CreateElement("a"),
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('y', log));
+ stack->EnqueueToCurrentQueue(
+ *CreateElement("a"),
+ *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
{
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<Log>('b', log));
- stack->EnqueueToCurrentQueue(element,
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<Log>('b', log));
+ stack->EnqueueToCurrentQueue(
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->PopInvokingReactions();
@@ -219,15 +215,14 @@ TEST(CustomElementReactionStackTest, enqueueFromReaction) {
MakeGarbageCollected<CustomElementReactionStack>();
stack->Push();
{
- HeapVector<Member<Command>>* subcommands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- subcommands->push_back(MakeGarbageCollected<Log>('a', log));
- HeapVector<Member<Command>>* commands =
- MakeGarbageCollected<HeapVector<Member<Command>>>();
- commands->push_back(MakeGarbageCollected<EnqueueToStack>(
- stack, element, MakeGarbageCollected<TestReaction>(subcommands)));
- stack->EnqueueToCurrentQueue(element,
- *MakeGarbageCollected<TestReaction>(commands));
+ HeapVector<Member<Command>> subcommands;
+ subcommands.push_back(MakeGarbageCollected<Log>('a', log));
+ HeapVector<Member<Command>> commands;
+ commands.push_back(MakeGarbageCollected<EnqueueToStack>(
+ stack, element,
+ MakeGarbageCollected<TestReaction>(std::move(subcommands))));
+ stack->EnqueueToCurrentQueue(
+ element, *MakeGarbageCollected<TestReaction>(std::move(commands)));
}
stack->PopInvokingReactions();
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
index ee3a1291d03..a9417d1f27b 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_reaction_test_helpers.h
@@ -107,23 +107,23 @@ class Enqueue : public Command {
class TestReaction : public CustomElementReaction {
public:
- TestReaction(HeapVector<Member<Command>>* commands)
+ explicit TestReaction(HeapVector<Member<Command>>&& commands)
: CustomElementReaction(
*MakeGarbageCollected<TestCustomElementDefinition>(
CustomElementDescriptor("mock-element", "mock-element"))),
- commands_(commands) {}
+ commands_(std::move(commands)) {}
~TestReaction() override = default;
void Trace(Visitor* visitor) const override {
CustomElementReaction::Trace(visitor);
visitor->Trace(commands_);
}
void Invoke(Element& element) override {
- for (auto& command : *commands_)
+ for (auto& command : commands_)
command->Run(element);
}
private:
- Member<HeapVector<Member<Command>>> commands_;
+ HeapVector<Member<Command>> commands_;
DISALLOW_COPY_AND_ASSIGN(TestReaction);
};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
index 55380bb760c..29196fe5e89 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/core/html/custom/custom_element_descriptor.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
#include "third_party/blink/renderer/core/html_element_type_helpers.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
@@ -78,19 +77,12 @@ bool ThrowIfValidName(const AtomicString& name,
CustomElementRegistry::CustomElementRegistry(const LocalDOMWindow* owner)
: element_definition_is_running_(false),
owner_(owner),
- v0_(MakeGarbageCollected<V0RegistrySet>()),
upgrade_candidates_(MakeGarbageCollected<UpgradeCandidateMap>()),
- reaction_stack_(&CustomElementReactionStack::Current()) {
- Document* document = owner->document();
- if (V0CustomElementRegistrationContext* v0 =
- document ? document->RegistrationContext() : nullptr)
- Entangle(v0);
-}
+ reaction_stack_(&CustomElementReactionStack::Current()) {}
void CustomElementRegistry::Trace(Visitor* visitor) const {
visitor->Trace(definitions_);
visitor->Trace(owner_);
- visitor->Trace(v0_);
visitor->Trace(upgrade_candidates_);
visitor->Trace(when_defined_promise_map_);
visitor->Trace(reaction_stack_);
@@ -124,7 +116,7 @@ CustomElementDefinition* CustomElementRegistry::DefineInternal(
if (ThrowIfInvalidName(name, allow_embedder_names, exception_state))
return nullptr;
- if (NameIsDefined(name) || V0NameIsDefined(name)) {
+ if (NameIsDefined(name)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotSupportedError,
"the name \"" + name + "\" has already been used with this registry");
@@ -265,19 +257,6 @@ bool CustomElementRegistry::NameIsDefined(const AtomicString& name) const {
return name_id_map_.Contains(name);
}
-void CustomElementRegistry::Entangle(V0CustomElementRegistrationContext* v0) {
- v0_->insert(v0);
- v0->SetV1(this);
-}
-
-bool CustomElementRegistry::V0NameIsDefined(const AtomicString& name) {
- for (const auto& v0 : *v0_) {
- if (v0->NameIsDefined(name))
- return true;
- }
- return false;
-}
-
CustomElementDefinition* CustomElementRegistry::DefinitionForName(
const AtomicString& name) const {
return DefinitionForId(name_id_map_.at(name));
@@ -295,7 +274,7 @@ void CustomElementRegistry::AddCandidate(Element& candidate) {
if (!is.IsNull())
name = is;
}
- if (NameIsDefined(name) || V0NameIsDefined(name))
+ if (NameIsDefined(name))
return;
UpgradeCandidateMap::iterator it = upgrade_candidates_->find(name);
UpgradeCandidateSet* set;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
index 9f4d9ef6145..9f268126991 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.h
@@ -27,7 +27,6 @@ class LocalDOMWindow;
class ScriptPromiseResolver;
class ScriptState;
class ScriptValue;
-class V0CustomElementRegistrationContext;
class V8CustomElementConstructor;
class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
@@ -60,8 +59,6 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
ExceptionState&);
void upgrade(Node* root);
- void Entangle(V0CustomElementRegistrationContext*);
-
void Trace(Visitor*) const override;
private:
@@ -71,8 +68,6 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
const ElementDefinitionOptions*,
ExceptionState&);
- bool V0NameIsDefined(const AtomicString& name);
-
void CollectCandidates(const CustomElementDescriptor&,
HeapVector<Member<Element>>*);
@@ -86,10 +81,6 @@ class CORE_EXPORT CustomElementRegistry final : public ScriptWrappable {
Member<const LocalDOMWindow> owner_;
- using V0RegistrySet =
- HeapHashSet<WeakMember<V0CustomElementRegistrationContext>>;
- Member<V0RegistrySet> v0_;
-
using UpgradeCandidateSet = HeapHashSet<WeakMember<Element>>;
using UpgradeCandidateMap =
HeapHashMap<AtomicString, Member<UpgradeCandidateSet>>;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
index 144566b51d2..bb79bb06c8e 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_registry.idl
@@ -6,7 +6,7 @@
[Exposed=Window]
interface CustomElementRegistry {
- [CallWith=ScriptState, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=CustomElementRegistryDefine] void define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {});
+ [CallWith=ScriptState, CEReactions, RaisesException, MeasureAs=CustomElementRegistryDefine] void define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {});
any get(DOMString name);
[CallWith=ScriptState,RaisesException] Promise<void> whenDefined(DOMString name);
[CEReactions] void upgrade(Node root);
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_element_test.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_element_test.cc
index d28b73f5cbc..f82edbd61ac 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/custom_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_element_test.cc
@@ -165,16 +165,14 @@ TEST(CustomElementTest, StateByParser) {
struct {
const char* id;
CustomElementState state;
- Element::V0CustomElementState v0state;
} parser_data[] = {
- {"div", CustomElementState::kUncustomized, Element::kV0NotCustomElement},
- {"v1v0", CustomElementState::kUndefined, Element::kV0WaitingForUpgrade},
- {"v0", CustomElementState::kUncustomized, Element::kV0WaitingForUpgrade},
+ {"div", CustomElementState::kUncustomized},
+ {"v1v0", CustomElementState::kUndefined},
+ {"v0", CustomElementState::kUncustomized},
};
for (const auto& data : parser_data) {
Element* element = document.getElementById(data.id);
EXPECT_EQ(data.state, element->GetCustomElementState()) << data.id;
- EXPECT_EQ(data.v0state, element->GetV0CustomElementState()) << data.id;
}
}
@@ -182,35 +180,27 @@ TEST(CustomElementTest, StateByCreateElement) {
struct {
const char* name;
CustomElementState state;
- Element::V0CustomElementState v0state;
} create_element_data[] = {
- {"div", CustomElementState::kUncustomized, Element::kV0NotCustomElement},
- {"a-a", CustomElementState::kUndefined, Element::kV0WaitingForUpgrade},
- // TODO(pdr): <font-face> should be V0NotCustomElement as per the spec,
- // but was regressed to be V0WaitingForUpgrade in
- // http://crrev.com/656913006
- {"font-face", CustomElementState::kUncustomized,
- Element::kV0WaitingForUpgrade},
- {"_-X", CustomElementState::kUncustomized, Element::kV0WaitingForUpgrade},
+ {"div", CustomElementState::kUncustomized},
+ {"a-a", CustomElementState::kUndefined},
+ {"font-face", CustomElementState::kUncustomized},
+ {"_-X", CustomElementState::kUncustomized},
};
auto page_holder = std::make_unique<DummyPageHolder>();
Document& document = page_holder->GetDocument();
for (const auto& data : create_element_data) {
Element* element = document.CreateElementForBinding(data.name);
EXPECT_EQ(data.state, element->GetCustomElementState()) << data.name;
- EXPECT_EQ(data.v0state, element->GetV0CustomElementState()) << data.name;
element = document.createElementNS(html_names::xhtmlNamespaceURI, data.name,
ASSERT_NO_EXCEPTION);
EXPECT_EQ(data.state, element->GetCustomElementState()) << data.name;
- EXPECT_EQ(data.v0state, element->GetV0CustomElementState()) << data.name;
element = document.createElementNS(svg_names::kNamespaceURI, data.name,
ASSERT_NO_EXCEPTION);
EXPECT_EQ(CustomElementState::kUncustomized,
element->GetCustomElementState())
<< data.name;
- EXPECT_EQ(data.v0state, element->GetV0CustomElementState()) << data.name;
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.cc b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.cc
new file mode 100644
index 00000000000..0a17d3656ef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.cc
@@ -0,0 +1,123 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/custom/custom_state_set.h"
+
+#include "third_party/blink/renderer/core/css/css_selector.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_idioms.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+
+namespace blink {
+
+CustomStateSet::CustomStateSet(Element& element) : element_(element) {}
+
+void CustomStateSet::Trace(Visitor* visitor) const {
+ visitor->Trace(element_);
+ ScriptWrappable::Trace(visitor);
+}
+
+void CustomStateSet::add(const String& value, ExceptionState& exception_state) {
+ // https://wicg.github.io/custom-state-pseudo-class/#dom-customstateset-add
+
+ // 1. If value does not match to <dashed-ident>, then throw a "SyntaxError"
+ // DOMException.
+ if (!value.StartsWith("--")) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kSyntaxError,
+ "The specified value '" + value + "' must start with '--'.");
+ return;
+ }
+ for (wtf_size_t i = 2; i < value.length(); ++i) {
+ if (IsNameCodePoint(value[i]))
+ continue;
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kSyntaxError,
+ "The specified value '" + value +
+ "' must match to <dashed-ident> production. '" + value[i] +
+ "' is invalid.");
+ return;
+ }
+
+ // 2. Invoke the default add operation, which the setlike<DOMString> would
+ // have if CustomStateSet interface had no add(value) operation, with value
+ // argument.
+ set_.insert(value);
+
+ InvalidateStyle();
+}
+
+uint32_t CustomStateSet::size() const {
+ return set_.size();
+}
+
+void CustomStateSet::clearForBinding(ScriptState*, ExceptionState&) {
+ set_.clear();
+ InvalidateStyle();
+}
+
+bool CustomStateSet::deleteForBinding(ScriptState*,
+ const String& value,
+ ExceptionState&) {
+ auto iter = set_.find(value);
+ if (iter == set_.cend())
+ return false;
+ set_.erase(iter);
+ InvalidateStyle();
+ return true;
+}
+
+bool CustomStateSet::hasForBinding(ScriptState*,
+ const String& value,
+ ExceptionState&) const {
+ return Has(value);
+}
+
+bool CustomStateSet::Has(const String& value) const {
+ return set_.Contains(value);
+}
+
+class CustomStateIterationSource : public CustomStateSet::IterationSource {
+ public:
+ explicit CustomStateIterationSource(CustomStateSet& states)
+ : states_(states), iterator_(states.set_.begin()) {}
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(states_);
+ CustomStateSet::IterationSource::Trace(visitor);
+ }
+
+ bool Next(ScriptState*,
+ String& out_key,
+ String& out_value,
+ ExceptionState&) override {
+ if (iterator_ == states_->set_.end())
+ return false;
+ String value = *iterator_;
+ ++iterator_;
+ out_key = value;
+ out_value = value;
+ return true;
+ }
+
+ private:
+ Member<CustomStateSet> states_;
+ LinkedHashSet<String>::const_iterator iterator_;
+};
+
+CustomStateSet::IterationSource* CustomStateSet::StartIteration(
+ ScriptState*,
+ ExceptionState&) {
+ return MakeGarbageCollected<CustomStateIterationSource>(*this);
+}
+
+void CustomStateSet::InvalidateStyle() const {
+ // TOOD(tkent): The following line invalidates all of rulesets with any
+ // custom state pseudo classes though we should invalidate only rulesets
+ // with the updated state ideally. We can improve style resolution
+ // performance in documents with various custom state pseudo classes by
+ // having blink::InvalidationSet for each of states.
+ element_->PseudoStateChanged(CSSSelector::kPseudoState);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.h b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.h
new file mode 100644
index 00000000000..f1e37908c6a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.h
@@ -0,0 +1,47 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_STATE_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_STATE_SET_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/iterable.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class Element;
+
+// This class is an implementation of 'CustomStateSet' IDL interface.
+class CustomStateSet final : public ScriptWrappable,
+ public SetlikeIterable<String> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit CustomStateSet(Element& element);
+ void Trace(Visitor* visitor) const override;
+
+ // IDL bindings:
+ void add(const String& value, ExceptionState& exception_state);
+ uint32_t size() const;
+ void clearForBinding(ScriptState*, ExceptionState&);
+ bool deleteForBinding(ScriptState*, const String& value, ExceptionState&);
+ bool hasForBinding(ScriptState*, const String& value, ExceptionState&) const;
+
+ bool Has(const String& value) const;
+
+ private:
+ // blink::Iterable override:
+ IterationSource* StartIteration(ScriptState* state, ExceptionState&) override;
+
+ void InvalidateStyle() const;
+
+ Member<Element> element_;
+ LinkedHashSet<String> set_;
+
+ friend class CustomStateIterationSource;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_STATE_SET_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.idl b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.idl
new file mode 100644
index 00000000000..5d9abe0decf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/custom/custom_state_set.idl
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/custom-state-pseudo-class/#customstateset
+[
+ Exposed=Window,
+ RuntimeEnabled=CustomStatePseudoClass
+]
+interface CustomStateSet {
+ setlike<DOMString>;
+ [RaisesException] void add(DOMString key);
+};
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc b/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
index f579182ddd4..b0d64cbaf84 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.cc
@@ -6,11 +6,11 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_validity_state_flags.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
-#include "third_party/blink/renderer/core/dom/dom_token_list.h"
#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
#include "third_party/blink/renderer/core/fileapi/file.h"
#include "third_party/blink/renderer/core/html/custom/custom_element.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
+#include "third_party/blink/renderer/core/html/custom/custom_state_set.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
@@ -32,20 +32,6 @@ bool IsValidityStateFlagsValid(const ValidityStateFlags* flags) {
}
} // anonymous namespace
-class CustomStatesTokenList : public DOMTokenList {
- public:
- CustomStatesTokenList(Element& element)
- : DOMTokenList(element, g_null_name) {}
-
- AtomicString value() const override { return TokenSet().SerializeToString(); }
-
- void setValue(const AtomicString& new_value) override {
- DidUpdateAttributeValue(value(), new_value);
- // Should we have invalidation set for each of state tokens?
- GetElement().PseudoStateChanged(CSSSelector::kPseudoState);
- }
-};
-
ElementInternals::ElementInternals(HTMLElement& target) : target_(target) {
}
@@ -228,14 +214,14 @@ LabelsNodeList* ElementInternals::labels(ExceptionState& exception_state) {
return Target().labels();
}
-DOMTokenList* ElementInternals::states() {
+CustomStateSet* ElementInternals::states() {
if (!custom_states_)
- custom_states_ = MakeGarbageCollected<CustomStatesTokenList>(Target());
+ custom_states_ = MakeGarbageCollected<CustomStateSet>(Target());
return custom_states_;
}
bool ElementInternals::HasState(const AtomicString& state) const {
- return custom_states_ && custom_states_->contains(state);
+ return custom_states_ && custom_states_->Has(state);
}
ShadowRoot* ElementInternals::shadowRoot() const {
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.h b/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
index 695e1e8b2f0..ce10aa81441 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.h
@@ -14,7 +14,7 @@
namespace blink {
-class DOMTokenList;
+class CustomStateSet;
class HTMLElement;
class ValidityStateFlags;
@@ -50,7 +50,7 @@ class CORE_EXPORT ElementInternals : public ScriptWrappable,
bool checkValidity(ExceptionState& exception_state);
bool reportValidity(ExceptionState& exception_state);
LabelsNodeList* labels(ExceptionState& exception_state);
- DOMTokenList* states();
+ CustomStateSet* states();
bool HasState(const AtomicString& state) const;
@@ -107,7 +107,7 @@ class CORE_EXPORT ElementInternals : public ScriptWrappable,
Member<ValidityStateFlags> validity_flags_;
Member<Element> validation_anchor_;
- Member<DOMTokenList> custom_states_;
+ Member<CustomStateSet> custom_states_;
HashMap<QualifiedName, AtomicString> accessibility_semantics_map_;
diff --git a/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl b/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
index 8333dbd36f2..6140f3086b4 100644
--- a/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
+++ b/chromium/third_party/blink/renderer/core/html/custom/element_internals.idl
@@ -25,8 +25,9 @@ interface ElementInternals {
[RaisesException] readonly attribute NodeList labels;
// Custom state
- // https://github.com/w3c/webcomponents/blob/gh-pages/proposals/custom-states-and-state-pseudo-class.md
- [RuntimeEnabled=CustomStatePseudoClass] readonly attribute DOMTokenList states;
+ // https://wicg.github.io/custom-state-pseudo-class/#dom-elementinternals-states
+ [RuntimeEnabled=CustomStatePseudoClass, MeasureAs=ElementInternalsStates]
+ readonly attribute CustomStateSet states;
// Access to shadowRoot from custom elements. See crbug.com/1042130 and
// https://github.com/w3c/webcomponents/issues/871#issuecomment-672082936
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.cc
deleted file mode 100644
index 3b91ebaa6a9..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/mathml_names.h"
-#include "third_party/blink/renderer/core/svg_names.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-V0CustomElementMicrotaskImportStep* V0CustomElement::DidCreateImport(
- HTMLImportChild* import) {
- return V0CustomElementScheduler::ScheduleImport(import);
-}
-
-void V0CustomElement::DidFinishLoadingImport(Document& tree_root) {
- tree_root.CustomElementMicrotaskRunQueue()->RequestDispatchIfNeeded();
-}
-
-static inline bool IsValidNCName(const AtomicString& name) {
- if (kNotFound != name.find(':'))
- return false;
-
- if (!name.GetString().Is8Bit()) {
- const UChar32 c = name.Characters16()[0];
- // These characters comes under CombiningChar in NCName and according to
- // NCName only BaseChar and Ideodgraphic can come as first chars.
- // Also these characters come under Letter_Other in UnicodeData, thats
- // why they pass as valid document name.
- if (c == 0x0B83 || c == 0x0F88 || c == 0x0F89 || c == 0x0F8A || c == 0x0F8B)
- return false;
- }
-
- return Document::IsValidName(name.GetString());
-}
-
-bool V0CustomElement::IsValidName(const AtomicString& name) {
- if (kNotFound != name.find('-')) {
- DEFINE_STATIC_LOCAL(Vector<AtomicString>, reserved_names, ());
- if (reserved_names.IsEmpty()) {
- // FIXME(crbug.com/426605): We should be able to remove this.
- reserved_names.push_back(mathml_names::kAnnotationXmlTag.LocalName());
- }
-
- if (kNotFound == reserved_names.Find(name))
- return IsValidNCName(name);
- }
-
- return false;
-}
-
-void V0CustomElement::Define(Element* element,
- V0CustomElementDefinition* definition) {
- switch (element->GetV0CustomElementState()) {
- case Element::kV0NotCustomElement:
- case Element::kV0Upgraded:
- NOTREACHED();
- break;
-
- case Element::kV0WaitingForUpgrade:
- UseCounter::Count(
- element->GetDocument(),
- definition->Descriptor().IsTypeExtension()
- ? WebFeature::kV0CustomElementsCreateTypeExtensionElement
- : WebFeature::kV0CustomElementsCreateCustomTagElement);
- element->V0SetCustomElementDefinition(definition);
- V0CustomElementScheduler::ScheduleCallback(
- definition->Callbacks(), element,
- V0CustomElementLifecycleCallbacks::kCreatedCallback);
- break;
- }
-}
-
-void V0CustomElement::AttributeDidChange(Element* element,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) {
- DCHECK_EQ(element->GetV0CustomElementState(), Element::kV0Upgraded);
- V0CustomElementScheduler::ScheduleAttributeChangedCallback(
- element->GetV0CustomElementDefinition()->Callbacks(), element, name,
- old_value, new_value);
-}
-
-void V0CustomElement::DidAttach(Element* element, const Document& document) {
- DCHECK_EQ(element->GetV0CustomElementState(), Element::kV0Upgraded);
- if (!document.domWindow())
- return;
- V0CustomElementScheduler::ScheduleCallback(
- element->GetV0CustomElementDefinition()->Callbacks(), element,
- V0CustomElementLifecycleCallbacks::kAttachedCallback);
-}
-
-void V0CustomElement::DidDetach(Element* element, const Document& document) {
- DCHECK_EQ(element->GetV0CustomElementState(), Element::kV0Upgraded);
- if (!document.domWindow())
- return;
- V0CustomElementScheduler::ScheduleCallback(
- element->GetV0CustomElementDefinition()->Callbacks(), element,
- V0CustomElementLifecycleCallbacks::kDetachedCallback);
-}
-
-void V0CustomElement::WasDestroyed(Element* element) {
- switch (element->GetV0CustomElementState()) {
- case Element::kV0NotCustomElement:
- NOTREACHED();
- break;
-
- case Element::kV0WaitingForUpgrade:
- case Element::kV0Upgraded:
- V0CustomElementObserver::NotifyElementWasDestroyed(element);
- break;
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.h
deleted file mode 100644
index 0c3e255a3ae..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class V0CustomElementMicrotaskImportStep;
-class Document;
-class HTMLImportChild;
-
-class CORE_EXPORT V0CustomElement {
- STATIC_ONLY(V0CustomElement);
-
- public:
- static bool IsValidName(const AtomicString& name);
-
- // API to notify of document-level changes
- static V0CustomElementMicrotaskImportStep* DidCreateImport(HTMLImportChild*);
- static void DidFinishLoadingImport(Document& tree_root);
-
- // API for registration contexts
- static void Define(Element*, V0CustomElementDefinition*);
-
- // API for Element to kick off changes
-
- static void AttributeDidChange(Element*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value);
- static void DidAttach(Element*, const Document&);
- static void DidDetach(Element*, const Document&);
- static void WasDestroyed(Element*);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.cc
deleted file mode 100644
index 0a57915451e..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h"
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h"
-
-namespace blink {
-
-void V0CustomElementAsyncImportMicrotaskQueue::Enqueue(
- V0CustomElementMicrotaskStep* step) {
- queue_.push_back(step);
-}
-
-void V0CustomElementAsyncImportMicrotaskQueue::DoDispatch() {
- HeapVector<Member<V0CustomElementMicrotaskStep>> remaining;
-
- for (auto& step : queue_) {
- if (V0CustomElementMicrotaskStep::kProcessing == step->Process())
- remaining.push_back(step.Release());
- }
-
- queue_.swap(remaining);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h
deleted file mode 100644
index 5f64134f5fa..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2014 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_ASYNC_IMPORT_MICROTASK_QUEUE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_ASYNC_IMPORT_MICROTASK_QUEUE_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h"
-
-namespace blink {
-
-class V0CustomElementAsyncImportMicrotaskQueue
- : public V0CustomElementMicrotaskQueueBase {
- public:
- V0CustomElementAsyncImportMicrotaskQueue() = default;
-
- void Enqueue(V0CustomElementMicrotaskStep*);
-
- private:
- void DoDispatch() override;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_ASYNC_IMPORT_MICROTASK_QUEUE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc
deleted file mode 100644
index 47cb0add209..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-
-namespace blink {
-
-class AttachedDetachedInvocation final
- : public V0CustomElementCallbackInvocation {
- public:
- AttachedDetachedInvocation(
- V0CustomElementLifecycleCallbacks*,
- V0CustomElementLifecycleCallbacks::CallbackType which);
-
- private:
- void Dispatch(Element*) override;
-
- V0CustomElementLifecycleCallbacks::CallbackType which_;
-};
-
-AttachedDetachedInvocation::AttachedDetachedInvocation(
- V0CustomElementLifecycleCallbacks* callbacks,
- V0CustomElementLifecycleCallbacks::CallbackType which)
- : V0CustomElementCallbackInvocation(callbacks), which_(which) {
- DCHECK(which_ == V0CustomElementLifecycleCallbacks::kAttachedCallback ||
- which_ == V0CustomElementLifecycleCallbacks::kDetachedCallback);
-}
-
-void AttachedDetachedInvocation::Dispatch(Element* element) {
- switch (which_) {
- case V0CustomElementLifecycleCallbacks::kAttachedCallback:
- Callbacks()->Attached(element);
- break;
- case V0CustomElementLifecycleCallbacks::kDetachedCallback:
- Callbacks()->Detached(element);
- break;
- default:
- NOTREACHED();
- }
-}
-
-class AttributeChangedInvocation final
- : public V0CustomElementCallbackInvocation {
- public:
- AttributeChangedInvocation(V0CustomElementLifecycleCallbacks*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value);
-
- private:
- void Dispatch(Element*) override;
-
- AtomicString name_;
- AtomicString old_value_;
- AtomicString new_value_;
-};
-
-AttributeChangedInvocation::AttributeChangedInvocation(
- V0CustomElementLifecycleCallbacks* callbacks,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value)
- : V0CustomElementCallbackInvocation(callbacks),
- name_(name),
- old_value_(old_value),
- new_value_(new_value) {}
-
-void AttributeChangedInvocation::Dispatch(Element* element) {
- Callbacks()->AttributeChanged(element, name_, old_value_, new_value_);
-}
-
-class CreatedInvocation final : public V0CustomElementCallbackInvocation {
- public:
- explicit CreatedInvocation(V0CustomElementLifecycleCallbacks* callbacks)
- : V0CustomElementCallbackInvocation(callbacks) {}
-
- private:
- void Dispatch(Element*) override;
- bool IsCreatedCallback() const override { return true; }
-};
-
-void CreatedInvocation::Dispatch(Element* element) {
- if (element->isConnected() && element->GetDocument().domWindow())
- V0CustomElementScheduler::ScheduleCallback(
- Callbacks(), element,
- V0CustomElementLifecycleCallbacks::kAttachedCallback);
- Callbacks()->Created(element);
-}
-
-V0CustomElementCallbackInvocation*
-V0CustomElementCallbackInvocation::CreateInvocation(
- V0CustomElementLifecycleCallbacks* callbacks,
- V0CustomElementLifecycleCallbacks::CallbackType which) {
- switch (which) {
- case V0CustomElementLifecycleCallbacks::kCreatedCallback:
- return MakeGarbageCollected<CreatedInvocation>(callbacks);
-
- case V0CustomElementLifecycleCallbacks::kAttachedCallback:
- case V0CustomElementLifecycleCallbacks::kDetachedCallback:
- return MakeGarbageCollected<AttachedDetachedInvocation>(callbacks, which);
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-V0CustomElementCallbackInvocation*
-V0CustomElementCallbackInvocation::CreateAttributeChangedInvocation(
- V0CustomElementLifecycleCallbacks* callbacks,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) {
- return MakeGarbageCollected<AttributeChangedInvocation>(callbacks, name,
- old_value, new_value);
-}
-
-void V0CustomElementCallbackInvocation::Trace(Visitor* visitor) const {
- visitor->Trace(callbacks_);
- V0CustomElementProcessingStep::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h
deleted file mode 100644
index 3250a3a330e..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_INVOCATION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_INVOCATION_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-class V0CustomElementCallbackInvocation : public V0CustomElementProcessingStep {
- public:
- static V0CustomElementCallbackInvocation* CreateInvocation(
- V0CustomElementLifecycleCallbacks*,
- V0CustomElementLifecycleCallbacks::CallbackType);
- static V0CustomElementCallbackInvocation* CreateAttributeChangedInvocation(
- V0CustomElementLifecycleCallbacks*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value);
-
- protected:
- V0CustomElementCallbackInvocation(
- V0CustomElementLifecycleCallbacks* callbacks)
- : callbacks_(callbacks) {}
-
- V0CustomElementLifecycleCallbacks* Callbacks() { return callbacks_.Get(); }
-
- void Trace(Visitor*) const override;
-
- private:
- Member<V0CustomElementLifecycleCallbacks> callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementCallbackInvocation);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_INVOCATION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc
deleted file mode 100644
index 0a9718ddad8..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h"
-
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-
-namespace blink {
-
-V0CustomElementCallbackQueue::V0CustomElementCallbackQueue(Element* element)
- : element_(element), owner_(-1), index_(0), in_created_callback_(false) {}
-
-bool V0CustomElementCallbackQueue::ProcessInElementQueue(
- ElementQueueId caller) {
- DCHECK(!in_created_callback_);
- bool did_work = false;
-
- // Never run custom element callbacks in UA shadow roots since that would
- // leak the UA root and it's elements into the page.
- ShadowRoot* shadow_root = element_->ContainingShadowRoot();
- if (!shadow_root || !shadow_root->IsUserAgent()) {
- while (index_ < queue_.size() && Owner() == caller) {
- in_created_callback_ = queue_[index_]->IsCreatedCallback();
-
- // dispatch() may cause recursion which steals this callback
- // queue and reenters processInQueue. owner() == caller
- // detects this recursion and cedes processing.
- queue_[index_++]->Dispatch(element_.Get());
- in_created_callback_ = false;
- did_work = true;
- }
- }
-
- if (Owner() == caller && index_ == queue_.size()) {
- // This processInQueue exhausted the queue; shrink it.
- index_ = 0;
- queue_.resize(0);
- owner_ = -1;
- }
-
- return did_work;
-}
-
-void V0CustomElementCallbackQueue::Trace(Visitor* visitor) const {
- visitor->Trace(element_);
- visitor->Trace(queue_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h
deleted file mode 100644
index 22290f77bd3..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_QUEUE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_QUEUE_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-// FIXME: Rename this because it contains resolution and upgrade as
-// well as callbacks.
-class V0CustomElementCallbackQueue
- : public GarbageCollected<V0CustomElementCallbackQueue> {
- public:
- explicit V0CustomElementCallbackQueue(Element*);
-
- typedef int ElementQueueId;
- ElementQueueId Owner() const { return owner_; }
-
- void SetOwner(ElementQueueId new_owner) {
- // ElementCallbackQueues only migrate towards the top of the
- // processing stack.
- DCHECK_GE(new_owner, owner_);
- owner_ = new_owner;
- }
-
- bool ProcessInElementQueue(ElementQueueId);
-
- void Append(V0CustomElementProcessingStep* invocation) {
- queue_.push_back(invocation);
- }
- bool InCreatedCallback() const { return in_created_callback_; }
-
- void Trace(Visitor*) const;
-
- private:
- Member<Element> element_;
- HeapVector<Member<V0CustomElementProcessingStep>> queue_;
- ElementQueueId owner_;
- wtf_size_t index_;
- bool in_created_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementCallbackQueue);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_CALLBACK_QUEUE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc
deleted file mode 100644
index 1795303dde1..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
-
-namespace blink {
-
-V0CustomElementDefinition::V0CustomElementDefinition(
- const V0CustomElementDescriptor& descriptor,
- V0CustomElementLifecycleCallbacks* callbacks)
- : descriptor_(descriptor), callbacks_(callbacks) {}
-
-void V0CustomElementDefinition::Trace(Visitor* visitor) const {
- visitor->Trace(callbacks_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h
deleted file mode 100644
index a5af9378ace..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DEFINITION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DEFINITION_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-
-namespace blink {
-
-class V0CustomElementDefinition final
- : public GarbageCollected<V0CustomElementDefinition> {
- public:
- V0CustomElementDefinition(const V0CustomElementDescriptor&,
- V0CustomElementLifecycleCallbacks*);
-
- const V0CustomElementDescriptor& Descriptor() const { return descriptor_; }
- V0CustomElementLifecycleCallbacks* Callbacks() const {
- return callbacks_.Get();
- }
-
- void Trace(Visitor*) const;
-
- private:
- V0CustomElementDescriptor descriptor_;
- Member<V0CustomElementLifecycleCallbacks> callbacks_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DEFINITION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h
deleted file mode 100644
index dd98203b257..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DESCRIPTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DESCRIPTOR_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-struct V0CustomElementDescriptorHash;
-
-// A Custom Element descriptor is everything necessary to match a
-// Custom Element instance to a definition.
-class V0CustomElementDescriptor {
- DISALLOW_NEW();
-
- public:
- V0CustomElementDescriptor(const AtomicString& type,
- const AtomicString& namespace_uri,
- const AtomicString& local_name)
- : type_(type), namespace_uri_(namespace_uri), local_name_(local_name) {}
-
- V0CustomElementDescriptor() = default;
- ~V0CustomElementDescriptor() = default;
-
- // Specifies whether the custom element is in the HTML or SVG
- // namespace.
- const AtomicString& NamespaceURI() const { return namespace_uri_; }
-
- // The tag name.
- const AtomicString& LocalName() const { return local_name_; }
-
- // The name of the definition. For custom tags, this is the tag
- // name and the same as "localName". For type extensions, this is
- // the value of the "is" attribute.
- const AtomicString& GetType() const { return type_; }
-
- bool IsTypeExtension() const { return type_ != local_name_; }
-
- bool operator==(const V0CustomElementDescriptor& other) const {
- return type_ == other.type_ && local_name_ == other.local_name_ &&
- namespace_uri_ == other.namespace_uri_;
- }
-
- private:
- friend struct WTF::HashTraits<blink::V0CustomElementDescriptor>;
- AtomicString type_;
- AtomicString namespace_uri_;
- AtomicString local_name_;
-};
-
-} // namespace blink
-
-namespace WTF {
-
-template <>
-struct DefaultHash<blink::V0CustomElementDescriptor> {
- typedef blink::V0CustomElementDescriptorHash Hash;
-};
-
-} // namespace WTF
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DESCRIPTOR_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h
deleted file mode 100644
index 103ffc488a3..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DESCRIPTOR_HASH_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_DESCRIPTOR_HASH_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
-#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
-
-namespace blink {
-
-struct V0CustomElementDescriptorHash {
- STATIC_ONLY(V0CustomElementDescriptorHash);
- static unsigned GetHash(const V0CustomElementDescriptor& descriptor) {
- return WTF::HashInts(
- AtomicStringHash::GetHash(descriptor.GetType()),
- WTF::HashInts(AtomicStringHash::GetHash(descriptor.NamespaceURI()),
- AtomicStringHash::GetHash(descriptor.LocalName())));
- }
-
- static bool Equal(const V0CustomElementDescriptor& a,
- const V0CustomElementDescriptor& b) {
- return a == b;
- }
-
- static const bool safe_to_compare_to_empty_or_deleted = true;
-};
-
-} // namespace blink
-
-namespace WTF {
-
-template <>
-struct HashTraits<blink::V0CustomElementDescriptor>
- : SimpleClassHashTraits<blink::V0CustomElementDescriptor> {
- STATIC_ONLY(HashTraits);
- static const bool kEmptyValueIsZero =
- HashTraits<AtomicString>::kEmptyValueIsZero;
-
- static bool IsDeletedValue(const blink::V0CustomElementDescriptor& value) {
- return HashTraits<AtomicString>::IsDeletedValue(value.type_);
- }
-
- static void ConstructDeletedValue(blink::V0CustomElementDescriptor& slot,
- bool zero_value) {
- HashTraits<AtomicString>::ConstructDeletedValue(slot.type_, zero_value);
- }
-};
-
-} // namespace WTF
-
-#endif // V0CustomElementDescriptorHash
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.cc
deleted file mode 100644
index d321126ef9f..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h"
-
-#include "base/notreached.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-
-namespace blink {
-
-String V0CustomElementException::Preamble(const AtomicString& type) {
- return "Registration failed for type '" + type + "'. ";
-}
-
-void V0CustomElementException::ThrowException(Reason reason,
- const AtomicString& type,
- ExceptionState& exception_state) {
- switch (reason) {
- case kCannotRegisterFromExtension:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- Preamble(type) + "Elements cannot be registered from extensions.");
- return;
-
- case kConstructorPropertyNotConfigurable:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- Preamble(type) +
- "Prototype constructor property is not configurable.");
- return;
-
- case kContextDestroyedCheckingPrototype:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- Preamble(type) + "The context is no longer valid.");
- return;
-
- case kContextDestroyedCreatingCallbacks:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- Preamble(type) + "The context is no longer valid.");
- return;
-
- case kContextDestroyedRegisteringDefinition:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- Preamble(type) + "The context is no longer valid.");
- return;
-
- case kExtendsIsInvalidName:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- Preamble(type) +
- "The tag name specified in 'extends' is not a valid tag name.");
- return;
-
- case kExtendsIsCustomElementName:
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- Preamble(type) +
- "The tag name specified in "
- "'extends' is a custom element "
- "name. Use inheritance instead.");
- return;
-
- case kInvalidName:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kSyntaxError,
- Preamble(type) + "The type name is invalid.");
- return;
-
- case kPrototypeInUse:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- Preamble(type) +
- "The prototype is already in-use as "
- "an interface prototype object.");
- return;
-
- case kTypeAlreadyRegistered:
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- Preamble(type) + "A type with that name is already registered.");
- return;
- }
-
- NOTREACHED();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h
deleted file mode 100644
index 2727385ca95..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_EXCEPTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_EXCEPTION_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class ExceptionState;
-
-class V0CustomElementException {
- STATIC_ONLY(V0CustomElementException);
-
- public:
- enum Reason {
- kCannotRegisterFromExtension,
- kConstructorPropertyNotConfigurable,
- kContextDestroyedCheckingPrototype,
- kContextDestroyedCreatingCallbacks,
- kContextDestroyedRegisteringDefinition,
- kExtendsIsInvalidName,
- kExtendsIsCustomElementName,
- kInvalidName,
- kPrototypeInUse,
- kTypeAlreadyRegistered
- };
-
- static void ThrowException(Reason, const AtomicString& type, ExceptionState&);
-
- private:
- static String Preamble(const AtomicString& type);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_EXCEPTION_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h
deleted file mode 100644
index 06190fc0ea2..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-class Element;
-
-class V0CustomElementLifecycleCallbacks
- : public GarbageCollected<V0CustomElementLifecycleCallbacks> {
- public:
- virtual ~V0CustomElementLifecycleCallbacks() = default;
-
- enum CallbackType {
- kNone = 0,
- kCreatedCallback = 1 << 0,
- kAttachedCallback = 1 << 1,
- kDetachedCallback = 1 << 2,
- kAttributeChangedCallback = 1 << 3
- };
-
- bool HasCallback(CallbackType type) const { return callback_type_ & type; }
-
- virtual void Created(Element*) = 0;
- virtual void Attached(Element*) = 0;
- virtual void Detached(Element*) = 0;
- virtual void AttributeChanged(Element*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) = 0;
-
- virtual void Trace(Visitor* visitor) const {}
-
- protected:
- explicit V0CustomElementLifecycleCallbacks(CallbackType type)
- : callback_type_(type) {}
-
- private:
- CallbackType callback_type_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_LIFECYCLE_CALLBACKS_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc
deleted file mode 100644
index 1c781204b72..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h"
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-
-namespace blink {
-
-static const V0CustomElementCallbackQueue::ElementQueueId kMicrotaskQueueId = 0;
-
-V0CustomElementMicrotaskDispatcher::V0CustomElementMicrotaskDispatcher()
- : has_scheduled_microtask_(false), phase_(kQuiescent) {}
-
-V0CustomElementMicrotaskDispatcher&
-V0CustomElementMicrotaskDispatcher::Instance() {
- DEFINE_STATIC_LOCAL(
- Persistent<V0CustomElementMicrotaskDispatcher>, instance,
- (MakeGarbageCollected<V0CustomElementMicrotaskDispatcher>()));
- return *instance;
-}
-
-void V0CustomElementMicrotaskDispatcher::Enqueue(
- V0CustomElementCallbackQueue* queue) {
- EnsureMicrotaskScheduledForElementQueue();
- queue->SetOwner(kMicrotaskQueueId);
- elements_.push_back(queue);
-}
-
-void V0CustomElementMicrotaskDispatcher::
- EnsureMicrotaskScheduledForElementQueue() {
- DCHECK(phase_ == kQuiescent || phase_ == kResolving);
- EnsureMicrotaskScheduled();
-}
-
-void V0CustomElementMicrotaskDispatcher::EnsureMicrotaskScheduled() {
- if (!has_scheduled_microtask_) {
- Microtask::EnqueueMicrotask(WTF::Bind(&Dispatch));
- has_scheduled_microtask_ = true;
- }
-}
-
-void V0CustomElementMicrotaskDispatcher::Dispatch() {
- Instance().DoDispatch();
-}
-
-void V0CustomElementMicrotaskDispatcher::DoDispatch() {
- DCHECK(IsMainThread());
-
- DCHECK(phase_ == kQuiescent);
- DCHECK(has_scheduled_microtask_);
- has_scheduled_microtask_ = false;
-
- // Finishing microtask work deletes all
- // V0CustomElementCallbackQueues. Being in a callback delivery scope
- // implies those queues could still be in use.
- SECURITY_DCHECK(!V0CustomElementProcessingStack::InCallbackDeliveryScope());
-
- phase_ = kResolving;
-
- phase_ = kDispatchingCallbacks;
- for (const auto& element : elements_) {
- // Created callback may enqueue an attached callback.
- V0CustomElementProcessingStack::CallbackDeliveryScope scope;
- element->ProcessInElementQueue(kMicrotaskQueueId);
- }
-
- elements_.clear();
- V0CustomElementScheduler::MicrotaskDispatcherDidFinish();
- phase_ = kQuiescent;
-}
-
-void V0CustomElementMicrotaskDispatcher::Trace(Visitor* visitor) const {
- visitor->Trace(elements_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h
deleted file mode 100644
index 0eed206c421..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_DISPATCHER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_DISPATCHER_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class V0CustomElementCallbackQueue;
-
-class V0CustomElementMicrotaskDispatcher final
- : public GarbageCollected<V0CustomElementMicrotaskDispatcher> {
- public:
- static V0CustomElementMicrotaskDispatcher& Instance();
-
- V0CustomElementMicrotaskDispatcher();
-
- void Enqueue(V0CustomElementCallbackQueue*);
-
- bool ElementQueueIsEmpty() { return elements_.IsEmpty(); }
-
- void Trace(Visitor*) const;
-
- private:
- void EnsureMicrotaskScheduledForElementQueue();
- void EnsureMicrotaskScheduled();
-
- static void Dispatch();
- void DoDispatch();
-
- bool has_scheduled_microtask_;
- enum { kQuiescent, kResolving, kDispatchingCallbacks } phase_;
-
- HeapVector<Member<V0CustomElementCallbackQueue>> elements_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementMicrotaskDispatcher);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_DISPATCHER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc
deleted file mode 100644
index fcf21c00af0..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h"
-
-#include <stdio.h>
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
-#include "third_party/blink/renderer/core/html/imports/html_import_child.h"
-#include "third_party/blink/renderer/core/html/imports/html_import_loader.h"
-
-namespace blink {
-
-V0CustomElementMicrotaskImportStep::V0CustomElementMicrotaskImportStep(
- HTMLImportChild* import)
- : import_(import), queue_(import->Loader()->MicrotaskQueue()) {}
-
-V0CustomElementMicrotaskImportStep::~V0CustomElementMicrotaskImportStep() =
- default;
-
-void V0CustomElementMicrotaskImportStep::Invalidate() {
- queue_ = MakeGarbageCollected<V0CustomElementSyncMicrotaskQueue>();
- import_.Clear();
-}
-
-bool V0CustomElementMicrotaskImportStep::ShouldWaitForImport() const {
- return import_ && !import_->Loader()->IsDone();
-}
-
-void V0CustomElementMicrotaskImportStep::DidUpgradeAllCustomElements() {
- DCHECK(queue_);
- if (import_)
- import_->DidFinishUpgradingCustomElements();
-}
-
-V0CustomElementMicrotaskStep::Result
-V0CustomElementMicrotaskImportStep::Process() {
- queue_->Dispatch();
- if (!queue_->IsEmpty() || ShouldWaitForImport())
- return kProcessing;
-
- DidUpgradeAllCustomElements();
- return kFinishedProcessing;
-}
-
-void V0CustomElementMicrotaskImportStep::Trace(Visitor* visitor) const {
- visitor->Trace(import_);
- visitor->Trace(queue_);
- V0CustomElementMicrotaskStep::Trace(visitor);
-}
-
-#if !defined(NDEBUG)
-void V0CustomElementMicrotaskImportStep::Show(unsigned indent) {
- fprintf(stderr, "%*sImport(wait=%d sync=%d, url=%s)\n", indent, "",
- ShouldWaitForImport(), import_ && import_->IsSync(),
- import_ ? import_->Url().GetString().Utf8().c_str() : "null");
- queue_->Show(indent + 1);
-}
-#endif
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h
deleted file mode 100644
index 566af67cfb2..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_IMPORT_STEP_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_IMPORT_STEP_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class V0CustomElementSyncMicrotaskQueue;
-class HTMLImportChild;
-
-// Processes the Custom Elements in an HTML Import. This is a
-// composite step which processes the Custom Elements created by
-// parsing the import, and its sub-imports.
-//
-// This step blocks further Custom Element microtask processing if its
-// import isn't "ready" (finished parsing and running script.)
-class V0CustomElementMicrotaskImportStep final
- : public V0CustomElementMicrotaskStep {
- public:
- explicit V0CustomElementMicrotaskImportStep(HTMLImportChild*);
- ~V0CustomElementMicrotaskImportStep() override;
-
- // API for HTML Imports
- void Invalidate();
- void ImportDidFinishLoading();
-
- void Trace(Visitor*) const override;
-
- private:
- void DidUpgradeAllCustomElements();
- bool ShouldWaitForImport() const;
-
- // V0CustomElementMicrotaskStep
- Result Process() final;
-
-#if !defined(NDEBUG)
- void Show(unsigned indent) override;
-#endif
- WeakMember<HTMLImportChild> import_;
- Member<V0CustomElementSyncMicrotaskQueue> queue_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_IMPORT_STEP_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc
deleted file mode 100644
index 25efaad36df..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h"
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
-
-namespace blink {
-
-void V0CustomElementMicrotaskQueueBase::Dispatch() {
- CHECK(!in_dispatch_);
- in_dispatch_ = true;
- DoDispatch();
- in_dispatch_ = false;
-}
-
-void V0CustomElementMicrotaskQueueBase::Trace(Visitor* visitor) const {
- visitor->Trace(queue_);
-}
-
-#if !defined(NDEBUG)
-void V0CustomElementMicrotaskQueueBase::Show(unsigned indent) {
- for (const auto& step : queue_) {
- if (step)
- step->Show(indent);
- else
- fprintf(stderr, "%*snull\n", indent, "");
- }
-}
-#endif
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h
deleted file mode 100644
index da4c6f039b6..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_QUEUE_BASE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_QUEUE_BASE_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class V0CustomElementMicrotaskQueueBase
- : public GarbageCollected<V0CustomElementMicrotaskQueueBase> {
- public:
- virtual ~V0CustomElementMicrotaskQueueBase() = default;
-
- bool IsEmpty() const { return queue_.IsEmpty(); }
- void Dispatch();
-
- void Trace(Visitor*) const;
-
-#if !defined(NDEBUG)
- void Show(unsigned indent);
-#endif
-
- protected:
- V0CustomElementMicrotaskQueueBase() : in_dispatch_(false) {}
- virtual void DoDispatch() = 0;
-
- HeapVector<Member<V0CustomElementMicrotaskStep>> queue_;
- bool in_dispatch_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementMicrotaskQueueBase);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_QUEUE_BASE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
deleted file mode 100644
index f0a9f551f81..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h"
-
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
-
-namespace blink {
-
-V0CustomElementMicrotaskResolutionStep::V0CustomElementMicrotaskResolutionStep(
- V0CustomElementRegistrationContext* context,
- Element* element,
- const V0CustomElementDescriptor& descriptor)
- : context_(context), element_(element), descriptor_(descriptor) {}
-
-V0CustomElementMicrotaskResolutionStep::
- ~V0CustomElementMicrotaskResolutionStep() = default;
-
-V0CustomElementMicrotaskStep::Result
-V0CustomElementMicrotaskResolutionStep::Process() {
- context_->Resolve(element_.Get(), descriptor_);
- return V0CustomElementMicrotaskStep::kFinishedProcessing;
-}
-
-void V0CustomElementMicrotaskResolutionStep::Trace(Visitor* visitor) const {
- visitor->Trace(context_);
- visitor->Trace(element_);
- V0CustomElementMicrotaskStep::Trace(visitor);
-}
-
-#if !defined(NDEBUG)
-void V0CustomElementMicrotaskResolutionStep::Show(unsigned indent) {
- fprintf(stderr, "%*sResolution: ", indent, "");
- element_->outerHTML().Show();
-}
-#endif
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
deleted file mode 100644
index 5288b6f9562..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RESOLUTION_STEP_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RESOLUTION_STEP_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class V0CustomElementRegistrationContext;
-class Element;
-
-class V0CustomElementMicrotaskResolutionStep final
- : public V0CustomElementMicrotaskStep {
- public:
- V0CustomElementMicrotaskResolutionStep(V0CustomElementRegistrationContext*,
- Element*,
- const V0CustomElementDescriptor&);
- ~V0CustomElementMicrotaskResolutionStep() override;
-
- void Trace(Visitor*) const override;
-
- private:
- Result Process() override;
-
-#if !defined(NDEBUG)
- void Show(unsigned indent) override;
-#endif
-
- Member<V0CustomElementRegistrationContext> context_;
- Member<Element> element_;
- V0CustomElementDescriptor descriptor_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RESOLUTION_STEP_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc
deleted file mode 100644
index 20a96fef1b0..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h"
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_async_import_microtask_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
-#include "third_party/blink/renderer/core/html/imports/html_import_loader.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-
-namespace blink {
-
-V0CustomElementMicrotaskRunQueue::V0CustomElementMicrotaskRunQueue()
- : sync_queue_(MakeGarbageCollected<V0CustomElementSyncMicrotaskQueue>()),
- async_queue_(
- MakeGarbageCollected<V0CustomElementAsyncImportMicrotaskQueue>()),
- dispatch_is_pending_(false) {}
-
-void V0CustomElementMicrotaskRunQueue::Enqueue(
- HTMLImportLoader* parent_loader,
- V0CustomElementMicrotaskStep* step,
- bool import_is_sync) {
- if (import_is_sync) {
- if (parent_loader)
- parent_loader->MicrotaskQueue()->Enqueue(step);
- else
- sync_queue_->Enqueue(step);
- } else {
- async_queue_->Enqueue(step);
- }
-
- RequestDispatchIfNeeded();
-}
-
-void V0CustomElementMicrotaskRunQueue::RequestDispatchIfNeeded() {
- if (dispatch_is_pending_ || IsEmpty())
- return;
- Microtask::EnqueueMicrotask(WTF::Bind(
- &V0CustomElementMicrotaskRunQueue::Dispatch, WrapWeakPersistent(this)));
- dispatch_is_pending_ = true;
-}
-
-void V0CustomElementMicrotaskRunQueue::Trace(Visitor* visitor) const {
- visitor->Trace(sync_queue_);
- visitor->Trace(async_queue_);
-}
-
-void V0CustomElementMicrotaskRunQueue::Dispatch() {
- dispatch_is_pending_ = false;
- sync_queue_->Dispatch();
- if (sync_queue_->IsEmpty())
- async_queue_->Dispatch();
-}
-
-bool V0CustomElementMicrotaskRunQueue::IsEmpty() const {
- return sync_queue_->IsEmpty() && async_queue_->IsEmpty();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h
deleted file mode 100644
index d6e3a8a6d06..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RUN_QUEUE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RUN_QUEUE_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class V0CustomElementSyncMicrotaskQueue;
-class V0CustomElementAsyncImportMicrotaskQueue;
-class V0CustomElementMicrotaskStep;
-class HTMLImportLoader;
-
-class V0CustomElementMicrotaskRunQueue
- : public GarbageCollected<V0CustomElementMicrotaskRunQueue> {
- public:
- V0CustomElementMicrotaskRunQueue();
-
- void Enqueue(HTMLImportLoader* parent_loader,
- V0CustomElementMicrotaskStep*,
- bool import_is_sync);
- void RequestDispatchIfNeeded();
- bool IsEmpty() const;
-
- void Trace(Visitor*) const;
-
- private:
- void Dispatch();
-
- Member<V0CustomElementSyncMicrotaskQueue> sync_queue_;
- Member<V0CustomElementAsyncImportMicrotaskQueue> async_queue_;
- bool dispatch_is_pending_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_RUN_QUEUE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h
deleted file mode 100644
index 3da59d78f1e..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_step.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_STEP_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_STEP_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class V0CustomElementMicrotaskStep
- : public GarbageCollected<V0CustomElementMicrotaskStep> {
- public:
- V0CustomElementMicrotaskStep() = default;
- virtual ~V0CustomElementMicrotaskStep() = default;
-
- enum Result { kProcessing, kFinishedProcessing };
-
- virtual Result Process() = 0;
-
- virtual void Trace(Visitor* visitor) const {}
-
-#if !defined(NDEBUG)
- virtual void Show(unsigned indent) = 0;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementMicrotaskStep);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_MICROTASK_STEP_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc
deleted file mode 100644
index a450e7667cf..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h"
-
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-
-namespace blink {
-
-// Maps elements to the observer watching them. At most one per
-// element at a time.
-typedef HeapHashMap<WeakMember<Element>, Member<V0CustomElementObserver>>
- ElementObserverMap;
-
-static ElementObserverMap& ElementObservers() {
- DEFINE_STATIC_LOCAL(Persistent<ElementObserverMap>, map,
- (MakeGarbageCollected<ElementObserverMap>()));
- return *map;
-}
-
-void V0CustomElementObserver::NotifyElementWasDestroyed(Element* element) {
- ElementObserverMap::iterator it = ElementObservers().find(element);
- if (it == ElementObservers().end())
- return;
- it->value->ElementWasDestroyed(element);
-}
-
-void V0CustomElementObserver::Observe(Element* element) {
- ElementObserverMap::AddResult result =
- ElementObservers().insert(element, this);
- DCHECK(result.is_new_entry);
-}
-
-void V0CustomElementObserver::Unobserve(Element* element) {
- V0CustomElementObserver* observer = ElementObservers().Take(element);
- DCHECK_EQ(observer, this);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h
deleted file mode 100644
index c05ea7ddc78..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_OBSERVER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_OBSERVER_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-
-namespace blink {
-
-class Element;
-
-class V0CustomElementObserver
- : public GarbageCollected<V0CustomElementObserver> {
- public:
- virtual ~V0CustomElementObserver() = default;
-
- // API for CustomElement to kick off notifications
- static void NotifyElementWasDestroyed(Element*);
-
- virtual void Trace(Visitor* visitor) const {}
-
- protected:
- V0CustomElementObserver() = default;
-
- void Observe(Element*);
- void Unobserve(Element*);
-
- virtual void ElementWasDestroyed(Element* element) { Unobserve(element); }
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_OBSERVER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc
deleted file mode 100644
index 627a3773747..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-
-namespace blink {
-
-wtf_size_t V0CustomElementProcessingStack::element_queue_start_ = 0;
-
-// The base of the stack has a null sentinel value.
-wtf_size_t V0CustomElementProcessingStack::element_queue_end_ = kNumSentinels;
-
-V0CustomElementProcessingStack& V0CustomElementProcessingStack::Instance() {
- DEFINE_STATIC_LOCAL(Persistent<V0CustomElementProcessingStack>, instance,
- (MakeGarbageCollected<V0CustomElementProcessingStack>()));
- return *instance;
-}
-
-// Dispatches callbacks when popping the processing stack.
-void V0CustomElementProcessingStack::ProcessElementQueueAndPop() {
- Instance().ProcessElementQueueAndPop(element_queue_start_,
- element_queue_end_);
-}
-
-void V0CustomElementProcessingStack::ProcessElementQueueAndPop(wtf_size_t start,
- wtf_size_t end) {
- DCHECK(IsMainThread());
- V0CustomElementCallbackQueue::ElementQueueId this_queue =
- CurrentElementQueue();
-
- for (wtf_size_t i = start; i < end; ++i) {
- {
- // The created callback may schedule entered document
- // callbacks.
- CallbackDeliveryScope delivery_scope;
- flattened_processing_stack_[i]->ProcessInElementQueue(this_queue);
- }
-
- DCHECK_EQ(start, element_queue_start_);
- DCHECK_EQ(end, element_queue_end_);
- }
-
- // Pop the element queue from the processing stack
- flattened_processing_stack_.resize(start);
- element_queue_end_ = start;
-
- if (element_queue_start_ == kNumSentinels)
- V0CustomElementScheduler::CallbackDispatcherDidFinish();
-}
-
-void V0CustomElementProcessingStack::Enqueue(
- V0CustomElementCallbackQueue* callback_queue) {
- DCHECK(InCallbackDeliveryScope());
-
- if (callback_queue->Owner() == CurrentElementQueue())
- return;
-
- callback_queue->SetOwner(CurrentElementQueue());
-
- flattened_processing_stack_.push_back(callback_queue);
- ++element_queue_end_;
-}
-
-void V0CustomElementProcessingStack::Trace(Visitor* visitor) const {
- visitor->Trace(flattened_processing_stack_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h
deleted file mode 100644
index c932c36806d..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STACK_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STACK_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class CORE_EXPORT V0CustomElementProcessingStack
- : public GarbageCollected<V0CustomElementProcessingStack> {
- public:
- // This is stack allocated in many DOM callbacks. Make it cheap.
- class CallbackDeliveryScope {
- STACK_ALLOCATED();
-
- public:
- CallbackDeliveryScope() : saved_element_queue_start_(element_queue_start_) {
- element_queue_start_ = element_queue_end_;
- }
-
- ~CallbackDeliveryScope() {
- if (element_queue_start_ != element_queue_end_)
- ProcessElementQueueAndPop();
- element_queue_start_ = saved_element_queue_start_;
- }
-
- private:
- wtf_size_t saved_element_queue_start_;
- };
-
- static bool InCallbackDeliveryScope() { return element_queue_start_; }
-
- V0CustomElementProcessingStack() {
- // Add a null element as a sentinel. This makes it possible to
- // identify elements queued when there is no
- // CallbackDeliveryScope active. Also, if the processing stack
- // is popped when empty, this sentinel will cause a null deref
- // crash.
- V0CustomElementCallbackQueue* sentinel = nullptr;
- for (wtf_size_t i = 0; i < kNumSentinels; i++)
- flattened_processing_stack_.push_back(sentinel);
- DCHECK_EQ(element_queue_end_, flattened_processing_stack_.size());
- }
-
- static V0CustomElementProcessingStack& Instance();
- void Enqueue(V0CustomElementCallbackQueue*);
-
- void Trace(Visitor*) const;
-
- private:
- // The start of the element queue on the top of the processing
- // stack. An offset into Instance().flattened_processing_stack_.
- static wtf_size_t element_queue_start_;
-
- // The end of the element queue on the top of the processing
- // stack. A cache of Instance().flattened_processing_stack_.size().
- static wtf_size_t element_queue_end_;
-
- static V0CustomElementCallbackQueue::ElementQueueId CurrentElementQueue() {
- return V0CustomElementCallbackQueue::ElementQueueId(element_queue_start_);
- }
-
- static void ProcessElementQueueAndPop();
- void ProcessElementQueueAndPop(wtf_size_t start, wtf_size_t end);
-
- // The processing stack, flattened. Element queues lower in the
- // stack appear toward the head of the vector. The first element
- // is a null sentinel value.
- static const wtf_size_t kNumSentinels = 1;
- HeapVector<Member<V0CustomElementCallbackQueue>> flattened_processing_stack_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementProcessingStack);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STACK_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h
deleted file mode 100644
index 23ff9aa87bb..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_processing_step.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STEP_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STEP_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class V0CustomElementProcessingStep
- : public GarbageCollected<V0CustomElementProcessingStep> {
- public:
- V0CustomElementProcessingStep() = default;
-
- virtual ~V0CustomElementProcessingStep() = default;
- virtual void Dispatch(Element*) = 0;
- virtual bool IsCreatedCallback() const { return false; }
-
- virtual void Trace(Visitor* visitor) const {}
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementProcessingStep);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_PROCESSING_STEP_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
deleted file mode 100644
index 07ba6362261..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/html/html_unknown_element.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/svg/svg_unknown_element.h"
-#include "third_party/blink/renderer/core/svg_names.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-
-namespace blink {
-
-V0CustomElementRegistrationContext::V0CustomElementRegistrationContext()
- : candidates_(MakeGarbageCollected<V0CustomElementUpgradeCandidateMap>()) {}
-
-void V0CustomElementRegistrationContext::RegisterElement(
- Document* document,
- V0CustomElementConstructorBuilder* constructor_builder,
- const AtomicString& type,
- ExceptionState& exception_state) {
- V0CustomElementDefinition* definition = registry_.RegisterElement(
- document, constructor_builder, type, exception_state);
-
- if (!definition)
- return;
-
- // Upgrade elements that were waiting for this definition.
- V0CustomElementUpgradeCandidateMap::ElementSet* upgrade_candidates =
- candidates_->TakeUpgradeCandidatesFor(definition->Descriptor());
-
- if (!upgrade_candidates)
- return;
-
- for (const auto& candidate : *upgrade_candidates)
- V0CustomElement::Define(candidate, definition);
-}
-
-Element* V0CustomElementRegistrationContext::CreateCustomTagElement(
- Document& document,
- const QualifiedName& tag_name) {
- DCHECK(V0CustomElement::IsValidName(tag_name.LocalName()));
-
- Element* element;
-
- if (html_names::xhtmlNamespaceURI == tag_name.NamespaceURI()) {
- element = MakeGarbageCollected<HTMLElement>(tag_name, document);
- } else if (svg_names::kNamespaceURI == tag_name.NamespaceURI()) {
- element = MakeGarbageCollected<SVGUnknownElement>(tag_name, document);
- } else {
- // XML elements are not custom elements, so return early.
- return MakeGarbageCollected<Element>(tag_name, &document);
- }
-
- element->SetV0CustomElementState(Element::kV0WaitingForUpgrade);
- ResolveOrScheduleResolution(element, g_null_atom);
- return element;
-}
-
-void V0CustomElementRegistrationContext::DidGiveTypeExtension(
- Element* element,
- const AtomicString& type) {
- ResolveOrScheduleResolution(element, type);
-}
-
-void V0CustomElementRegistrationContext::ResolveOrScheduleResolution(
- Element* element,
- const AtomicString& type_extension) {
- // If an element has a custom tag name it takes precedence over
- // the "is" attribute (if any).
- const AtomicString& type = V0CustomElement::IsValidName(element->localName())
- ? element->localName()
- : type_extension;
- DCHECK(!type.IsNull());
-
- V0CustomElementDescriptor descriptor(type, element->namespaceURI(),
- element->localName());
- DCHECK_EQ(element->GetV0CustomElementState(), Element::kV0WaitingForUpgrade);
-
- V0CustomElementScheduler::ResolveOrScheduleResolution(this, element,
- descriptor);
-}
-
-void V0CustomElementRegistrationContext::Resolve(
- Element* element,
- const V0CustomElementDescriptor& descriptor) {
- V0CustomElementDefinition* definition = registry_.Find(descriptor);
- if (definition) {
- V0CustomElement::Define(element, definition);
- } else {
- DCHECK_EQ(element->GetV0CustomElementState(),
- Element::kV0WaitingForUpgrade);
- candidates_->Add(descriptor, element);
- }
-}
-
-void V0CustomElementRegistrationContext::SetIsAttributeAndTypeExtension(
- Element* element,
- const AtomicString& type) {
- DCHECK(element);
- DCHECK(!type.IsEmpty());
- element->setAttribute(html_names::kIsAttr, type);
- SetTypeExtension(element, type);
-}
-
-void V0CustomElementRegistrationContext::SetTypeExtension(
- Element* element,
- const AtomicString& type) {
- if (!element->IsHTMLElement() && !element->IsSVGElement())
- return;
-
- V0CustomElementRegistrationContext* context =
- element->GetDocument().RegistrationContext();
- if (!context)
- return;
-
- if (element->IsV0CustomElement()) {
- // This can happen if:
- // 1. The element has a custom tag, which takes precedence over
- // type extensions.
- // 2. Undoing a command (eg ReplaceNodeWithSpan) recycles an
- // element but tries to overwrite its attribute list.
- return;
- }
-
- // Custom tags take precedence over type extensions
- DCHECK(!V0CustomElement::IsValidName(element->localName()));
-
- if (!V0CustomElement::IsValidName(type))
- return;
-
- element->SetV0CustomElementState(Element::kV0WaitingForUpgrade);
- context->DidGiveTypeExtension(element,
- element->GetDocument().ConvertLocalName(type));
-}
-
-bool V0CustomElementRegistrationContext::NameIsDefined(
- const AtomicString& name) const {
- return registry_.NameIsDefined(name);
-}
-
-void V0CustomElementRegistrationContext::SetV1(
- const CustomElementRegistry* v1) {
- registry_.SetV1(v1);
-}
-
-void V0CustomElementRegistrationContext::Trace(Visitor* visitor) const {
- visitor->Trace(candidates_);
- visitor->Trace(registry_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
deleted file mode 100644
index 9e7baee49de..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRATION_CONTEXT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRATION_CONTEXT_H_
-
-#include "third_party/blink/renderer/core/dom/qualified_name.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-class CustomElementRegistry;
-
-class V0CustomElementRegistrationContext final
- : public GarbageCollected<V0CustomElementRegistrationContext> {
- public:
- V0CustomElementRegistrationContext();
- ~V0CustomElementRegistrationContext() = default;
- void DocumentWasDetached() { registry_.DocumentWasDetached(); }
-
- // Definitions
- void RegisterElement(Document*,
- V0CustomElementConstructorBuilder*,
- const AtomicString& type,
- ExceptionState&);
-
- Element* CreateCustomTagElement(Document&, const QualifiedName&);
- static void SetIsAttributeAndTypeExtension(Element*,
- const AtomicString& type);
- static void SetTypeExtension(Element*, const AtomicString& type);
-
- void Resolve(Element*, const V0CustomElementDescriptor&);
-
- bool NameIsDefined(const AtomicString& name) const;
- void SetV1(const CustomElementRegistry*);
-
- void Trace(Visitor*) const;
-
- // Instance creation
- void DidGiveTypeExtension(Element*, const AtomicString& type);
-
- private:
- void ResolveOrScheduleResolution(Element*,
- const AtomicString& type_extension);
-
- V0CustomElementRegistry registry_;
-
- // Element creation
- Member<V0CustomElementUpgradeCandidateMap> candidates_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRATION_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
deleted file mode 100644
index 9d4fb89945c..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_exception.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/svg_names.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-V0CustomElementDefinition* V0CustomElementRegistry::RegisterElement(
- Document* document,
- V0CustomElementConstructorBuilder* constructor_builder,
- const AtomicString& user_supplied_name,
- ExceptionState& exception_state) {
- AtomicString type = user_supplied_name.LowerASCII();
-
- if (!constructor_builder->IsFeatureAllowed()) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kCannotRegisterFromExtension, type,
- exception_state);
- return nullptr;
- }
-
- if (!V0CustomElement::IsValidName(type)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kInvalidName, type, exception_state);
- return nullptr;
- }
-
- if (registered_type_names_.Contains(type) || V1NameIsDefined(type)) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kTypeAlreadyRegistered, type,
- exception_state);
- return nullptr;
- }
-
- QualifiedName tag_name = QualifiedName::Null();
- if (!constructor_builder->ValidateOptions(type, tag_name, exception_state))
- return nullptr;
-
- DCHECK(tag_name.NamespaceURI() == html_names::xhtmlNamespaceURI ||
- tag_name.NamespaceURI() == svg_names::kNamespaceURI);
-
- DCHECK(!document_was_detached_);
-
- V0CustomElementLifecycleCallbacks* lifecycle_callbacks =
- constructor_builder->CreateCallbacks();
-
- // Consulting the constructor builder could execute script and
- // kill the document.
- if (document_was_detached_) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kContextDestroyedCreatingCallbacks, type,
- exception_state);
- return nullptr;
- }
-
- const V0CustomElementDescriptor descriptor(type, tag_name.NamespaceURI(),
- tag_name.LocalName());
- auto* definition = MakeGarbageCollected<V0CustomElementDefinition>(
- descriptor, lifecycle_callbacks);
-
- if (!constructor_builder->CreateConstructor(document, definition,
- exception_state))
- return nullptr;
-
- definitions_.insert(descriptor, definition);
- registered_type_names_.insert(descriptor.GetType());
-
- if (!constructor_builder->DidRegisterDefinition()) {
- V0CustomElementException::ThrowException(
- V0CustomElementException::kContextDestroyedRegisteringDefinition, type,
- exception_state);
- return nullptr;
- }
-
- if (tag_name.NamespaceURI() == svg_names::kNamespaceURI) {
- UseCounter::Count(document,
- WebFeature::kV0CustomElementsRegisterSVGElement);
- } else {
- UseCounter::Count(
- document, descriptor.IsTypeExtension()
- ? WebFeature::kV0CustomElementsRegisterHTMLTypeExtension
- : WebFeature::kV0CustomElementsRegisterHTMLCustomTag);
- }
-
- return definition;
-}
-
-V0CustomElementDefinition* V0CustomElementRegistry::Find(
- const V0CustomElementDescriptor& descriptor) const {
- return definitions_.at(descriptor);
-}
-
-bool V0CustomElementRegistry::NameIsDefined(const AtomicString& name) const {
- return registered_type_names_.Contains(name);
-}
-
-void V0CustomElementRegistry::SetV1(const CustomElementRegistry* v1) {
- DCHECK(!v1_.Get());
- v1_ = v1;
-}
-
-bool V0CustomElementRegistry::V1NameIsDefined(const AtomicString& name) const {
- return v1_.Get() && v1_->NameIsDefined(name);
-}
-
-void V0CustomElementRegistry::Trace(Visitor* visitor) const {
- visitor->Trace(definitions_);
- visitor->Trace(v1_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h
deleted file mode 100644
index 8f43354c6af..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRY_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRY_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_definition.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
-
-namespace blink {
-
-class CustomElementRegistry;
-class ExceptionState;
-class V0CustomElementConstructorBuilder;
-
-class V0CustomElementRegistry final {
- DISALLOW_NEW();
-
- public:
- void Trace(Visitor*) const;
- void DocumentWasDetached() { document_was_detached_ = true; }
-
- protected:
- friend class V0CustomElementRegistrationContext;
-
- V0CustomElementRegistry() : document_was_detached_(false) {}
-
- V0CustomElementDefinition* RegisterElement(
- Document*,
- V0CustomElementConstructorBuilder*,
- const AtomicString& name,
- ExceptionState&);
- V0CustomElementDefinition* Find(const V0CustomElementDescriptor&) const;
-
- bool NameIsDefined(const AtomicString& name) const;
- void SetV1(const CustomElementRegistry*);
-
- private:
- bool V1NameIsDefined(const AtomicString& name) const;
-
- typedef HeapHashMap<V0CustomElementDescriptor,
- Member<V0CustomElementDefinition>>
- DefinitionMap;
- DefinitionMap definitions_;
- HashSet<AtomicString> registered_type_names_;
- Member<const CustomElementRegistry> v1_;
- bool document_was_detached_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementRegistry);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_REGISTRY_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
deleted file mode 100644
index 91b860eba41..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_invocation.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_dispatcher.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
-#include "third_party/blink/renderer/core/html/imports/html_import_child.h"
-#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-
-namespace blink {
-
-// FIXME: Consider moving the element's callback queue to ElementRareData.
-typedef HeapHashMap<Member<Element>, Member<V0CustomElementCallbackQueue>>
- ElementCallbackQueueMap;
-
-static ElementCallbackQueueMap& CallbackQueues() {
- DEFINE_STATIC_LOCAL(Persistent<ElementCallbackQueueMap>, map,
- (MakeGarbageCollected<ElementCallbackQueueMap>()));
- return *map;
-}
-
-static V0CustomElementCallbackQueue& EnsureCallbackQueue(Element* element) {
- ElementCallbackQueueMap::ValueType* it =
- CallbackQueues().insert(element, nullptr).stored_value;
- if (!it->value)
- it->value = MakeGarbageCollected<V0CustomElementCallbackQueue>(element);
- return *it->value.Get();
-}
-
-// Finds or creates the callback queue for element.
-static V0CustomElementCallbackQueue& ScheduleCallbackQueue(Element* element) {
- V0CustomElementCallbackQueue& callback_queue = EnsureCallbackQueue(element);
- if (callback_queue.InCreatedCallback()) {
- // Don't move it. Authors use the createdCallback like a
- // constructor. By not moving it, the createdCallback
- // completes before any other callbacks are entered for this
- // element.
- return callback_queue;
- }
-
- if (V0CustomElementProcessingStack::InCallbackDeliveryScope()) {
- // The processing stack is active.
- V0CustomElementProcessingStack::Instance().Enqueue(&callback_queue);
- return callback_queue;
- }
-
- V0CustomElementMicrotaskDispatcher::Instance().Enqueue(&callback_queue);
- return callback_queue;
-}
-
-void V0CustomElementScheduler::ScheduleCallback(
- V0CustomElementLifecycleCallbacks* callbacks,
- Element* element,
- V0CustomElementLifecycleCallbacks::CallbackType type) {
- DCHECK(type != V0CustomElementLifecycleCallbacks::kAttributeChangedCallback);
-
- if (!callbacks->HasCallback(type))
- return;
-
- V0CustomElementCallbackQueue& queue = ScheduleCallbackQueue(element);
- queue.Append(
- V0CustomElementCallbackInvocation::CreateInvocation(callbacks, type));
-}
-
-void V0CustomElementScheduler::ScheduleAttributeChangedCallback(
- V0CustomElementLifecycleCallbacks* callbacks,
- Element* element,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value) {
- if (!callbacks->HasCallback(
- V0CustomElementLifecycleCallbacks::kAttributeChangedCallback))
- return;
-
- V0CustomElementCallbackQueue& queue = ScheduleCallbackQueue(element);
- queue.Append(
- V0CustomElementCallbackInvocation::CreateAttributeChangedInvocation(
- callbacks, name, old_value, new_value));
-}
-
-void V0CustomElementScheduler::ResolveOrScheduleResolution(
- V0CustomElementRegistrationContext* context,
- Element* element,
- const V0CustomElementDescriptor& descriptor) {
- if (V0CustomElementProcessingStack::InCallbackDeliveryScope()) {
- context->Resolve(element, descriptor);
- return;
- }
-
- Document& document = element->GetDocument();
- auto* step = MakeGarbageCollected<V0CustomElementMicrotaskResolutionStep>(
- context, element, descriptor);
- EnqueueMicrotaskStep(document, step);
-}
-
-V0CustomElementMicrotaskImportStep* V0CustomElementScheduler::ScheduleImport(
- HTMLImportChild* import) {
- DCHECK(!import->HasFinishedLoading());
- DCHECK(import->Parent());
-
- // Ownership of the new step is transferred to the parent
- // processing step, or the base queue.
- auto* step = MakeGarbageCollected<V0CustomElementMicrotaskImportStep>(import);
- V0CustomElementMicrotaskImportStep* raw_step = step;
- EnqueueMicrotaskStep(*(import->Parent()->GetDocument()), step,
- import->IsSync());
- return raw_step;
-}
-
-void V0CustomElementScheduler::EnqueueMicrotaskStep(
- Document& document,
- V0CustomElementMicrotaskStep* step,
- bool import_is_sync) {
- Document& tree_root = document.ImportsController()
- ? *(document.ImportsController()->TreeRoot())
- : document;
- tree_root.CustomElementMicrotaskRunQueue()->Enqueue(document.ImportLoader(),
- step, import_is_sync);
-}
-
-void V0CustomElementScheduler::CallbackDispatcherDidFinish() {
- if (V0CustomElementMicrotaskDispatcher::Instance().ElementQueueIsEmpty())
- CallbackQueues().clear();
-}
-
-void V0CustomElementScheduler::MicrotaskDispatcherDidFinish() {
- DCHECK(!V0CustomElementProcessingStack::InCallbackDeliveryScope());
- CallbackQueues().clear();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h
deleted file mode 100644
index 68e0e6e1588..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SCHEDULER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SCHEDULER_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_callback_queue.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_lifecycle_callbacks.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-class V0CustomElementDescriptor;
-class V0CustomElementMicrotaskImportStep;
-class V0CustomElementMicrotaskStep;
-class V0CustomElementRegistrationContext;
-class HTMLImportChild;
-
-class V0CustomElementScheduler final
- : public GarbageCollected<V0CustomElementScheduler> {
- public:
- static void ScheduleCallback(V0CustomElementLifecycleCallbacks*,
- Element*,
- V0CustomElementLifecycleCallbacks::CallbackType);
- static void ScheduleAttributeChangedCallback(
- V0CustomElementLifecycleCallbacks*,
- Element*,
- const AtomicString& name,
- const AtomicString& old_value,
- const AtomicString& new_value);
-
- static void ResolveOrScheduleResolution(V0CustomElementRegistrationContext*,
- Element*,
- const V0CustomElementDescriptor&);
- static V0CustomElementMicrotaskImportStep* ScheduleImport(HTMLImportChild*);
-
- static void MicrotaskDispatcherDidFinish();
- static void CallbackDispatcherDidFinish();
-
- private:
- V0CustomElementScheduler() = default;
-
- static void EnqueueMicrotaskStep(Document&,
- V0CustomElementMicrotaskStep*,
- bool import_is_sync = true);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SCHEDULER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.cc
deleted file mode 100644
index 8dab3026123..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
-
-namespace blink {
-
-void V0CustomElementSyncMicrotaskQueue::Enqueue(
- V0CustomElementMicrotaskStep* step) {
- queue_.push_back(step);
-}
-
-void V0CustomElementSyncMicrotaskQueue::DoDispatch() {
- unsigned i;
-
- for (i = 0; i < queue_.size(); ++i) {
- if (V0CustomElementMicrotaskStep::kProcessing == queue_[i]->Process())
- break;
- }
-
- queue_.EraseAt(0, i);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h
deleted file mode 100644
index 884033c6dde..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SYNC_MICROTASK_QUEUE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SYNC_MICROTASK_QUEUE_H_
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_queue_base.h"
-
-namespace blink {
-
-class V0CustomElementSyncMicrotaskQueue
- : public V0CustomElementMicrotaskQueueBase {
- public:
- V0CustomElementSyncMicrotaskQueue() = default;
-
- void Enqueue(V0CustomElementMicrotaskStep*);
-
- private:
- void DoDispatch() override;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_SYNC_MICROTASK_QUEUE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc
deleted file mode 100644
index 28c5c0fc581..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h"
-
-#include "third_party/blink/renderer/core/dom/element.h"
-
-namespace blink {
-
-V0CustomElementUpgradeCandidateMap::~V0CustomElementUpgradeCandidateMap() =
- default;
-
-void V0CustomElementUpgradeCandidateMap::Add(
- const V0CustomElementDescriptor& descriptor,
- Element* element) {
- Observe(element);
-
- UpgradeCandidateMap::AddResult result =
- upgrade_candidates_.insert(element, descriptor);
- DCHECK(result.is_new_entry);
-
- UnresolvedDefinitionMap::iterator it =
- unresolved_definitions_.find(descriptor);
- ElementSet* elements;
- if (it == unresolved_definitions_.end())
- elements = unresolved_definitions_
- .insert(descriptor, MakeGarbageCollected<ElementSet>())
- .stored_value->value.Get();
- else
- elements = it->value.Get();
- elements->insert(element);
-}
-
-void V0CustomElementUpgradeCandidateMap::ElementWasDestroyed(Element* element) {
- V0CustomElementObserver::ElementWasDestroyed(element);
- UpgradeCandidateMap::iterator candidate = upgrade_candidates_.find(element);
- SECURITY_DCHECK(candidate != upgrade_candidates_.end());
-
- UnresolvedDefinitionMap::iterator elements =
- unresolved_definitions_.find(candidate->value);
- SECURITY_DCHECK(elements != unresolved_definitions_.end());
- elements->value->erase(element);
- upgrade_candidates_.erase(candidate);
-}
-
-V0CustomElementUpgradeCandidateMap::ElementSet*
-V0CustomElementUpgradeCandidateMap::TakeUpgradeCandidatesFor(
- const V0CustomElementDescriptor& descriptor) {
- ElementSet* candidates = unresolved_definitions_.Take(descriptor);
-
- if (!candidates)
- return nullptr;
-
- for (const auto& candidate : *candidates) {
- Unobserve(candidate);
- upgrade_candidates_.erase(candidate);
- }
- return candidates;
-}
-
-void V0CustomElementUpgradeCandidateMap::Trace(Visitor* visitor) const {
- visitor->Trace(upgrade_candidates_);
- visitor->Trace(unresolved_definitions_);
- V0CustomElementObserver::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h b/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h
deleted file mode 100644
index ee0232f17cb..00000000000
--- a/chromium/third_party/blink/renderer/core/html/custom/v0_custom_element_upgrade_candidate_map.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_UPGRADE_CANDIDATE_MAP_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_UPGRADE_CANDIDATE_MAP_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_descriptor_hash.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_observer.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
-
-namespace blink {
-
-class V0CustomElementUpgradeCandidateMap final
- : public V0CustomElementObserver {
- public:
- V0CustomElementUpgradeCandidateMap() = default;
- ~V0CustomElementUpgradeCandidateMap() override;
-
- // API for V0CustomElementRegistrationContext to save and take candidates
-
- typedef HeapLinkedHashSet<WeakMember<Element>> ElementSet;
-
- void Add(const V0CustomElementDescriptor&, Element*);
- ElementSet* TakeUpgradeCandidatesFor(const V0CustomElementDescriptor&);
-
- void Trace(Visitor*) const override;
-
- private:
- void ElementWasDestroyed(Element*) override;
-
- typedef HeapHashMap<WeakMember<Element>, V0CustomElementDescriptor>
- UpgradeCandidateMap;
- UpgradeCandidateMap upgrade_candidates_;
-
- typedef HeapHashMap<V0CustomElementDescriptor, Member<ElementSet>>
- UnresolvedDefinitionMap;
- UnresolvedDefinitionMap unresolved_definitions_;
-
- DISALLOW_COPY_AND_ASSIGN(V0CustomElementUpgradeCandidateMap);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_V0_CUSTOM_ELEMENT_UPGRADE_CANDIDATE_MAP_H_
diff --git a/chromium/third_party/blink/renderer/core/html/forms/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/forms/DIR_METADATA
new file mode 100644
index 00000000000..a682370216c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Forms"
+}
+
+team_email: "dom-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/html/forms/OWNERS b/chromium/third_party/blink/renderer/core/html/forms/OWNERS
index cbe63714987..e69f3656a7f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/forms/OWNERS
@@ -1,6 +1,3 @@
keishi@chromium.org
tkent@chromium.org
masonfreed@chromium.org
-
-# TEAM: dom-dev@chromium.org
-# COMPONENT: Blink>Forms
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
index d13e518a241..b363ab086da 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/html/forms/base_checkable_input_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
@@ -87,11 +88,10 @@ bool BaseCheckableInputType::CanSetStringValue() const {
// FIXME: Could share this with KeyboardClickableInputTypeView and
// RangeInputType if we had a common base class.
-void BaseCheckableInputType::AccessKeyAction(bool send_mouse_events) {
- InputTypeView::AccessKeyAction(send_mouse_events);
-
- GetElement().DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+void BaseCheckableInputType::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
+ InputTypeView::AccessKeyAction(creation_scope);
+ GetElement().DispatchSimulatedClick(nullptr, creation_scope);
}
bool BaseCheckableInputType::MatchesDefaultPseudoClass() {
@@ -121,4 +121,8 @@ bool BaseCheckableInputType::IsCheckable() {
return true;
}
+void BaseCheckableInputType::HandleBlurEvent() {
+ GetElement().SetActive(false);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
index 0e225e11560..ffe004840d0 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_checkable_input_type.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_BASE_CHECKABLE_INPUT_TYPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_BASE_CHECKABLE_INPUT_TYPE_H_
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/input_type.h"
#include "third_party/blink/renderer/core/html/forms/input_type_view.h"
@@ -42,6 +43,8 @@ class BaseCheckableInputType : public InputType, public InputTypeView {
void Trace(Visitor*) const override;
using InputType::GetElement;
+ void HandleBlurEvent() override;
+
protected:
BaseCheckableInputType(HTMLInputElement& element)
: InputType(element),
@@ -59,7 +62,7 @@ class BaseCheckableInputType : public InputType, public InputTypeView {
void AppendToFormData(FormData&) const final;
void HandleKeypressEvent(KeyboardEvent&) final;
bool CanSetStringValue() const final;
- void AccessKeyAction(bool send_mouse_events) final;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) final;
bool MatchesDefaultPseudoClass() override;
ValueMode GetValueMode() const override;
void SetValue(const String&,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.cc
index 0f838dc1992..200b2bd5a07 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.cc
@@ -32,6 +32,11 @@
namespace blink {
+void BaseTextInputType::Trace(Visitor* visitor) const {
+ visitor->Trace(regexp_);
+ TextFieldInputType::Trace(visitor);
+}
+
BaseTextInputType::BaseTextInputType(HTMLInputElement& element)
: TextFieldInputType(element) {}
@@ -84,9 +89,9 @@ bool BaseTextInputType::PatternMismatch(const String& value) const {
if (raw_pattern.IsNull() || value.IsEmpty())
return false;
if (!regexp_ || pattern_for_regexp_ != raw_pattern) {
- std::unique_ptr<ScriptRegexp> raw_regexp(
- new ScriptRegexp(raw_pattern, kTextCaseSensitive, kMultilineDisabled,
- ScriptRegexp::UTF16));
+ ScriptRegexp* raw_regexp = MakeGarbageCollected<ScriptRegexp>(
+ raw_pattern, kTextCaseSensitive, kMultilineDisabled,
+ ScriptRegexp::UTF16);
if (!raw_regexp->IsValid()) {
GetElement().GetDocument().AddConsoleMessage(
MakeGarbageCollected<ConsoleMessage>(
@@ -95,13 +100,13 @@ bool BaseTextInputType::PatternMismatch(const String& value) const {
"Pattern attribute value " + raw_pattern +
" is not a valid regular expression: " +
raw_regexp->ExceptionMessage()));
- regexp_.reset(raw_regexp.release());
+ regexp_ = raw_regexp;
pattern_for_regexp_ = raw_pattern;
return false;
}
String pattern = "^(?:" + raw_pattern + ")$";
- regexp_.reset(new ScriptRegexp(pattern, kTextCaseSensitive,
- kMultilineDisabled, ScriptRegexp::UTF16));
+ regexp_ = MakeGarbageCollected<ScriptRegexp>(
+ pattern, kTextCaseSensitive, kMultilineDisabled, ScriptRegexp::UTF16);
pattern_for_regexp_ = raw_pattern;
} else if (!regexp_->IsValid()) {
return false;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.h
index 9e820805e02..f75ae74d42d 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/base_text_input_type.h
@@ -40,6 +40,9 @@ class ScriptRegexp;
// Base of email, password, search, tel, text, and URL types.
// They support maxlength, selection functions, and so on.
class BaseTextInputType : public TextFieldInputType {
+ public:
+ void Trace(Visitor* visitor) const override;
+
protected:
BaseTextInputType(HTMLInputElement&);
~BaseTextInputType() override;
@@ -57,7 +60,7 @@ class BaseTextInputType : public TextFieldInputType {
// regexp_ and pattern_for_regexp_ are mutable because they are kinds of
// cache.
- mutable std::unique_ptr<ScriptRegexp> regexp_;
+ mutable Member<ScriptRegexp> regexp_;
mutable AtomicString pattern_for_regexp_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
index 7259f28988f..5ecc350d9a4 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -571,10 +571,12 @@ void DateTimeEditElement::BlurByOwner() {
field->blur();
}
-scoped_refptr<ComputedStyle> DateTimeEditElement::CustomStyleForLayoutObject() {
- // FIXME: This is a kind of layout. We might want to introduce new
- // layoutObject.
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+scoped_refptr<ComputedStyle> DateTimeEditElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
+ // TODO(crbug.com/1181868): This is a kind of layout. We might want to
+ // introduce new LayoutObject.
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
float width = 0;
for (Node* child = FieldsWrapperElement()->firstChild(); child;
child = child->nextSibling()) {
@@ -594,6 +596,7 @@ scoped_refptr<ComputedStyle> DateTimeEditElement::CustomStyleForLayoutObject() {
}
}
style->SetWidth(Length::Fixed(ceilf(width)));
+ style->SetCustomStyleCallbackDependsOnFont();
return style;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
index c2e7ab39c6e..0fcacc50303 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
@@ -139,7 +139,8 @@ class DateTimeEditElement final : public HTMLDivElement,
void UpdateUIState();
// Element function.
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
bool IsDateTimeEditElement() const override;
// DateTimeFieldElement::FieldOwner functions.
diff --git a/chromium/third_party/blink/renderer/core/html/forms/email_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/email_input_type.cc
index 06aa0bf6f14..4e574dade6d 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/email_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/email_input_type.cc
@@ -57,9 +57,9 @@ static const int32_t kMaximumDomainNameLength = 255;
// Use the same option as in url/url_canon_icu.cc
static const int32_t kIdnaConversionOption = UIDNA_CHECK_BIDI;
-std::unique_ptr<ScriptRegexp> EmailInputType::CreateEmailRegexp() {
- return std::make_unique<ScriptRegexp>(kEmailPattern,
- kTextCaseUnicodeInsensitive);
+ScriptRegexp* EmailInputType::CreateEmailRegexp() {
+ return MakeGarbageCollected<ScriptRegexp>(kEmailPattern,
+ kTextCaseUnicodeInsensitive);
}
String EmailInputType::ConvertEmailAddressToASCII(const ScriptRegexp& regexp,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/email_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/email_input_type.h
index 41970a04320..77eeeabda73 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/email_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/email_input_type.h
@@ -44,7 +44,7 @@ class EmailInputType final : public BaseTextInputType {
const String&);
CORE_EXPORT static bool IsValidEmailAddress(const ScriptRegexp&,
const String&);
- CORE_EXPORT static std::unique_ptr<ScriptRegexp> CreateEmailRegexp();
+ CORE_EXPORT static ScriptRegexp* CreateEmailRegexp();
private:
void CountUsage() override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/email_input_type_test.cc b/chromium/third_party/blink/renderer/core/html/forms/email_input_type_test.cc
index b702e425cc4..6151a7379f8 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/email_input_type_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/email_input_type_test.cc
@@ -12,8 +12,7 @@ namespace blink {
namespace {
void ExpectToSucceed(const String& source) {
- std::unique_ptr<ScriptRegexp> email_regexp =
- EmailInputType::CreateEmailRegexp();
+ ScriptRegexp* email_regexp = EmailInputType::CreateEmailRegexp();
String result =
EmailInputType::ConvertEmailAddressToASCII(*email_regexp, source);
EXPECT_NE(source, result);
@@ -21,8 +20,7 @@ void ExpectToSucceed(const String& source) {
}
void ExpectToFail(const String& source) {
- std::unique_ptr<ScriptRegexp> email_regexp =
- EmailInputType::CreateEmailRegexp();
+ ScriptRegexp* email_regexp = EmailInputType::CreateEmailRegexp();
// Conversion failed. The resultant value might contains non-ASCII
// characters, and not a valid email address.
EXPECT_FALSE(EmailInputType::IsValidEmailAddress(
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
index 99a12ecbf9f..2ef63564e4f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
@@ -40,7 +40,7 @@
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
@@ -68,6 +68,7 @@ ExternalPopupMenu::~ExternalPopupMenu() = default;
void ExternalPopupMenu::Trace(Visitor* visitor) const {
visitor->Trace(owner_element_);
visitor->Trace(local_frame_);
+ visitor->Trace(dispatch_event_timer_);
visitor->Trace(receiver_);
PopupMenu::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
index 5965d566bbe..061b856044f 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/external_popup_menu.h
@@ -90,7 +90,7 @@ class CORE_EXPORT ExternalPopupMenu final
Member<HTMLSelectElement> owner_element_;
Member<LocalFrame> local_frame_;
std::unique_ptr<WebMouseEvent> synthetic_event_;
- TaskRunnerTimer<ExternalPopupMenu> dispatch_event_timer_;
+ HeapTaskRunnerTimer<ExternalPopupMenu> dispatch_event_timer_;
// The actual implementor of the show menu.
HeapMojoReceiver<mojom::blink::PopupMenuClient,
ExternalPopupMenu,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
index 76a13e9e3c5..02fd6492193 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/html/forms/hidden_input_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
@@ -73,7 +74,7 @@ LayoutObject* HiddenInputType::CreateLayoutObject(const ComputedStyle&,
return nullptr;
}
-void HiddenInputType::AccessKeyAction(bool) {}
+void HiddenInputType::AccessKeyAction(SimulatedClickCreationScope) {}
bool HiddenInputType::LayoutObjectIsNeeded() {
return false;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
index 0bcf41149b1..b251c6d3687 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/hidden_input_type.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HIDDEN_INPUT_TYPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HIDDEN_INPUT_TYPE_H_
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/input_type.h"
#include "third_party/blink/renderer/core/html/forms/input_type_view.h"
@@ -52,7 +53,7 @@ class HiddenInputType final : public InputType, private InputTypeView {
bool SupportsValidation() const override;
LayoutObject* CreateLayoutObject(const ComputedStyle&,
LegacyLayout) const override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
bool LayoutObjectIsNeeded() override;
ValueMode GetValueMode() const override;
bool IsInteractiveContent() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
index c0b6a74c6af..4ef91c54288 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/html/forms/html_button_element.h"
#include "third_party/blink/renderer/core/dom/attribute.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
@@ -154,11 +155,10 @@ void HTMLButtonElement::AppendToFormData(FormData& form_data) {
form_data.AppendFromElement(GetName(), Value());
}
-void HTMLButtonElement::AccessKeyAction(bool send_mouse_events) {
+void HTMLButtonElement::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
focus();
-
- DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+ DispatchSimulatedClick(nullptr, creation_scope);
}
bool HTMLButtonElement::IsURLAttribute(const Attribute& attribute) const {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
index c51020487ff..9326ef276be 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_button_element.h
@@ -24,6 +24,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_BUTTON_ELEMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_BUTTON_ELEMENT_H_
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
namespace blink {
@@ -67,7 +68,7 @@ class HTMLButtonElement final : public HTMLFormControlElement {
bool IsActivatedSubmit() const override;
void SetActivatedSubmit(bool flag) override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
bool IsURLAttribute(const Attribute&) const override;
bool CanStartSelection() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index b116574ff38..53c4cfbb6ea 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -135,10 +135,6 @@ LayoutBox* HTMLFieldSetElement::GetLayoutBoxForScrolling() const {
return HTMLFormControlElement::GetLayoutBoxForScrolling();
}
-bool HTMLFieldSetElement::TypeShouldForceLegacyLayout() const {
- return !RuntimeEnabledFeatures::LayoutNGFieldsetEnabled();
-}
-
HTMLLegendElement* HTMLFieldSetElement::Legend() const {
return Traversal<HTMLLegendElement>::FirstChild(*this);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.h
index b0538ed5af3..b5f62447fd1 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -48,7 +48,6 @@ class CORE_EXPORT HTMLFieldSetElement final : public HTMLFormControlElement {
bool SupportsFocus() const override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
LayoutBox* GetLayoutBoxForScrolling() const override;
- bool TypeShouldForceLegacyLayout() const final;
const AtomicString& FormControlType() const override;
bool RecalcWillValidate() const override { return false; }
bool MatchesValidityPseudoClasses() const final;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
index aa4293e67b7..ad8ea3f30e6 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_element.idl
@@ -28,9 +28,9 @@
[CEReactions, Reflect=accept_charset] attribute DOMString acceptCharset;
[CEReactions, URL] attribute USVString action;
[CEReactions, Reflect, ReflectOnly=("on","off"), ReflectMissing="on", ReflectInvalid="on"] attribute DOMString autocomplete;
- [CEReactions, CustomElementCallbacks] attribute DOMString enctype;
- [CEReactions, CustomElementCallbacks] attribute DOMString encoding;
- [CEReactions, CustomElementCallbacks] attribute DOMString method;
+ [CEReactions] attribute DOMString enctype;
+ [CEReactions] attribute DOMString encoding;
+ [CEReactions] attribute DOMString method;
[CEReactions, Reflect] attribute DOMString name;
[CEReactions, Reflect] attribute boolean noValidate;
[CEReactions, Reflect] attribute DOMString target;
@@ -43,7 +43,7 @@
[ImplementedAs=submitFromJavaScript] void submit();
[RaisesException] void requestSubmit(optional HTMLElement submitter);
- [CEReactions, CustomElementCallbacks] void reset();
+ [CEReactions] void reset();
boolean checkValidity();
boolean reportValidity();
};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
index 966621de256..ac733001009 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -41,10 +41,10 @@
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
#include "third_party/blink/renderer/core/events/before_text_inserted_event.h"
@@ -596,7 +596,7 @@ void HTMLInputElement::SubtreeHasChanged() {
input_type_view_->SubtreeHasChanged();
// When typing in an input field, childrenChanged is not called, so we need to
// force the directionality check.
- CalculateAndAdjustDirectionality();
+ CalculateAndAdjustAutoDirectionality(this);
}
const AtomicString& HTMLInputElement::FormControlType() const {
@@ -730,8 +730,9 @@ void HTMLInputElement::SetSelectionRangeForTesting(
TextControlElement::setSelectionRangeForBinding(start, end);
}
-void HTMLInputElement::AccessKeyAction(bool send_mouse_events) {
- input_type_view_->AccessKeyAction(send_mouse_events);
+void HTMLInputElement::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
+ input_type_view_->AccessKeyAction(creation_scope);
}
bool HTMLInputElement::IsPresentationAttribute(
@@ -759,11 +760,19 @@ void HTMLInputElement::CollectStyleForPresentationAttribute(
if (input_type_->ShouldRespectAlignAttribute())
ApplyAlignmentAttributeToStyle(value, style);
} else if (name == html_names::kWidthAttr) {
- if (input_type_->ShouldRespectHeightAndWidthAttributes())
+ if (input_type_->ShouldRespectHeightAndWidthAttributes()) {
AddHTMLLengthToStyle(style, CSSPropertyID::kWidth, value);
+ const AtomicString& height = FastGetAttribute(html_names::kHeightAttr);
+ if (height)
+ ApplyAspectRatioToStyle(value, height, style);
+ }
} else if (name == html_names::kHeightAttr) {
- if (input_type_->ShouldRespectHeightAndWidthAttributes())
+ if (input_type_->ShouldRespectHeightAndWidthAttributes()) {
AddHTMLLengthToStyle(style, CSSPropertyID::kHeight, value);
+ const AtomicString& width = FastGetAttribute(html_names::kWidthAttr);
+ if (width)
+ ApplyAspectRatioToStyle(width, value, style);
+ }
} else if (name == html_names::kBorderAttr &&
type() == input_type_names::kImage) { // FIXME: Remove type check.
ApplyBorderAttributeToStyle(value, style);
@@ -1127,8 +1136,12 @@ void HTMLInputElement::SetValueForUser(const String& value) {
}
void HTMLInputElement::SetSuggestedValue(const String& value) {
- if (!input_type_->CanSetSuggestedValue())
+ if (!input_type_->CanSetSuggestedValue()) {
+ // Clear the suggested value because it may have been set when
+ // `input_type_->CanSetSuggestedValue()` was true.
+ TextControlElement::SetSuggestedValue(String());
return;
+ }
needs_to_update_view_value_ = true;
TextControlElement::SetSuggestedValue(SanitizeValue(value));
SetNeedsStyleRecalc(
@@ -1849,7 +1862,7 @@ bool HTMLInputElement::SupportsPlaceholder() const {
}
void HTMLInputElement::UpdatePlaceholderText() {
- return input_type_view_->UpdatePlaceholderText();
+ return input_type_view_->UpdatePlaceholderText(!SuggestedValue().IsEmpty());
}
String HTMLInputElement::GetPlaceholderValue() const {
@@ -2043,8 +2056,10 @@ bool HTMLInputElement::IsInteractiveContent() const {
return input_type_->IsInteractiveContent();
}
-scoped_refptr<ComputedStyle> HTMLInputElement::CustomStyleForLayoutObject() {
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+scoped_refptr<ComputedStyle> HTMLInputElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
input_type_view_->CustomStyleForLayoutObject(*style);
return style;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
index 77a311d2b22..d4ed4d88a51 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/create_element_flags.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/file_chooser.h"
#include "third_party/blink/renderer/core/html/forms/step_range.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
@@ -388,7 +389,7 @@ class CORE_EXPORT HTMLInputElement
bool CanStartSelection() const final;
- void AccessKeyAction(bool send_mouse_events) final;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) final;
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const final;
@@ -446,7 +447,8 @@ class CORE_EXPORT HTMLInputElement
void AddToRadioButtonGroup();
void RemoveFromRadioButtonGroup();
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
void DidRecalcStyle(const StyleRecalcChange) override;
void MaybeReportPiiMetrics();
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
index 48bb6afc2a6..1fdc1e13bde 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_input_element.idl
@@ -40,37 +40,37 @@ enum SelectionMode { "select", "start", "end", "preserve" };
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=22682
attribute FileList? files;
[CEReactions] attribute DOMString formAction;
- [CEReactions, CustomElementCallbacks] attribute DOMString formEnctype;
- [CEReactions, CustomElementCallbacks] attribute DOMString formMethod;
+ [CEReactions] attribute DOMString formEnctype;
+ [CEReactions] attribute DOMString formMethod;
[CEReactions, Reflect] attribute boolean formNoValidate;
[CEReactions, Reflect] attribute DOMString formTarget;
- [CEReactions, CustomElementCallbacks] attribute unsigned long height;
+ [CEReactions] attribute unsigned long height;
attribute boolean indeterminate;
readonly attribute HTMLElement? list;
[CEReactions, Reflect] attribute DOMString max;
- [CEReactions, RaisesException=Setter, CustomElementCallbacks] attribute long maxLength;
+ [CEReactions, RaisesException=Setter] attribute long maxLength;
[CEReactions, Reflect] attribute DOMString min;
- [CEReactions, RaisesException=Setter, CustomElementCallbacks] attribute long minLength;
+ [CEReactions, RaisesException=Setter] attribute long minLength;
[CEReactions, Reflect] attribute boolean multiple;
[CEReactions, Reflect] attribute DOMString name;
[CEReactions, Reflect] attribute DOMString pattern;
[CEReactions, Reflect] attribute DOMString placeholder;
[CEReactions, Reflect] attribute boolean readOnly;
[CEReactions, Reflect] attribute boolean required;
- [CEReactions, RaisesException=Setter, CustomElementCallbacks] attribute unsigned long size;
+ [CEReactions, RaisesException=Setter] attribute unsigned long size;
[CEReactions, Reflect, URL] attribute DOMString src;
[CEReactions, Reflect] attribute DOMString step;
- [CEReactions, CustomElementCallbacks] attribute DOMString type;
- [CEReactions, Reflect=value, CustomElementCallbacks] attribute DOMString defaultValue;
- [CEReactions, RaisesException=Setter, CustomElementCallbacks] attribute [TreatNullAs=EmptyString] DOMString value;
- [CEReactions, RaisesException=Setter, CustomElementCallbacks, CallWith=ScriptState] attribute object? valueAsDate;
- [RaisesException=Setter, CustomElementCallbacks] attribute unrestricted double valueAsNumber;
+ [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect=value] attribute DOMString defaultValue;
+ [CEReactions, RaisesException=Setter] attribute [TreatNullAs=EmptyString] DOMString value;
+ [CEReactions, RaisesException=Setter, CallWith=ScriptState] attribute object? valueAsDate;
+ [RaisesException=Setter] attribute unrestricted double valueAsNumber;
// Note: The spec has valueLow and valueHigh for two-valued range controls.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=13154
- [CEReactions, CustomElementCallbacks] attribute unsigned long width;
+ [CEReactions] attribute unsigned long width;
- [RaisesException, CustomElementCallbacks] void stepUp(optional long n = 1);
- [RaisesException, CustomElementCallbacks] void stepDown(optional long n = 1);
+ [RaisesException] void stepUp(optional long n = 1);
+ [RaisesException] void stepDown(optional long n = 1);
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
index d8258f10792..1b30722decd 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
@@ -249,11 +250,12 @@ void HTMLLabelElement::focus(const FocusParams& params) {
}
}
-void HTMLLabelElement::AccessKeyAction(bool send_mouse_events) {
+void HTMLLabelElement::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
if (HTMLElement* element = control())
- element->AccessKeyAction(send_mouse_events);
+ element->AccessKeyAction(creation_scope);
else
- HTMLElement::AccessKeyAction(send_mouse_events);
+ HTMLElement::AccessKeyAction(creation_scope);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
index 3e4fc40bea2..b57b74cd805 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_label_element.h
@@ -25,6 +25,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_LABEL_ELEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
@@ -44,7 +45,7 @@ class CORE_EXPORT HTMLLabelElement final : public HTMLElement {
bool IsInInteractiveContent(Node*) const;
bool IsInteractiveContent() const override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
// Overridden to update the hover/active state of the corresponding control.
void SetActive(bool active) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
index ea0b9c965c0..7ee9f4c8339 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
@@ -96,8 +97,7 @@ void HTMLOptGroupElement::ChildrenChanged(const ChildrenChange& change) {
if (auto* option = DynamicTo<HTMLOptionElement>(change.sibling_changed))
select->OptionRemoved(*option);
} else if (change.type == ChildrenChangeType::kAllChildrenRemoved) {
- DCHECK(change.removed_nodes);
- for (Node* node : *change.removed_nodes) {
+ for (Node* node : change.removed_nodes) {
if (auto* option = DynamicTo<HTMLOptionElement>(node))
select->OptionRemoved(*option);
}
@@ -148,11 +148,14 @@ String HTMLOptGroupElement::DefaultToolTip() const {
return String();
}
-void HTMLOptGroupElement::AccessKeyAction(bool) {
+void HTMLOptGroupElement::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
HTMLSelectElement* select = OwnerSelectElement();
- // send to the parent to bring focus to the list box
+ // Send to the parent to bring focus to the list box.
+ // TODO(crbug.com/1176745): investigate why we don't care
+ // about creation scope.
if (select && !select->IsFocused())
- select->AccessKeyAction(false);
+ select->AccessKeyAction(SimulatedClickCreationScope::kFromUserAgent);
}
void HTMLOptGroupElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
index a03db9bb975..57a0fbf1043 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
@@ -25,6 +25,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_OPT_GROUP_ELEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
@@ -37,6 +38,7 @@ class CORE_EXPORT HTMLOptGroupElement final : public HTMLElement {
public:
explicit HTMLOptGroupElement(Document&);
+ ~HTMLOptGroupElement() override;
bool IsDisabledFormControl() const override;
String DefaultToolTip() const override;
@@ -49,13 +51,11 @@ class CORE_EXPORT HTMLOptGroupElement final : public HTMLElement {
static bool CanAssignToOptGroupSlot(const Node&);
private:
- ~HTMLOptGroupElement() override;
-
bool SupportsFocus() const override;
void ChildrenChanged(const ChildrenChange& change) override;
bool ChildrenChangedAllChildrenRemovedNeedsList() const override;
void ParseAttribute(const AttributeModificationParams&) override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
void DidAddUserAgentShadowRoot(ShadowRoot&) override;
bool MatchesEnabledPseudoClass() const override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_option_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_option_element.cc
index 2c22f9d040b..7575659e9c5 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_option_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_option_element.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_mutation_observer_init.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/mutation_observer.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
@@ -173,7 +174,8 @@ void HTMLOptionElement::setText(const String& text) {
select->setSelectedIndex(old_selected_index);
}
-void HTMLOptionElement::AccessKeyAction(bool) {
+void HTMLOptionElement::AccessKeyAction(SimulatedClickCreationScope) {
+ // TODO(crbug.com/1176745): why creation_scope arg is not used at all?
if (HTMLSelectElement* select = OwnerSelectElement())
select->SelectOptionByAccessKey(this);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_option_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_option_element.h
index 78a6f792afb..43c7f9df8ca 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_option_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_option_element.h
@@ -26,6 +26,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_OPTION_ELEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/html_element.h"
namespace blink {
@@ -54,6 +55,7 @@ class CORE_EXPORT HTMLOptionElement final : public HTMLElement {
ExceptionState&);
explicit HTMLOptionElement(Document&);
+ ~HTMLOptionElement() override;
void Trace(Visitor* visitor) const override;
// A text to be shown to users. The difference from |label()| is |label()|
@@ -112,13 +114,11 @@ class CORE_EXPORT HTMLOptionElement final : public HTMLElement {
void DidChangeTextContent();
private:
- ~HTMLOptionElement() override;
-
bool SupportsFocus() const override;
bool MatchesDefaultPseudoClass() const override;
bool MatchesEnabledPseudoClass() const override;
void ParseAttribute(const AttributeModificationParams&) override;
- void AccessKeyAction(bool) override;
+ void AccessKeyAction(SimulatedClickCreationScope) override;
void ChildrenChanged(const ChildrenChange&) override;
void DidAddUserAgentShadowRoot(ShadowRoot&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 87e0b394958..4c2afcc1526 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/core/dom/attribute.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
@@ -391,10 +392,10 @@ void HTMLSelectElement::OptionElementChildrenChanged(
}
}
-void HTMLSelectElement::AccessKeyAction(bool send_mouse_events) {
+void HTMLSelectElement::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
focus();
- DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+ DispatchSimulatedClick(nullptr, creation_scope);
}
Element* HTMLSelectElement::namedItem(const AtomicString& name) {
@@ -436,6 +437,8 @@ void HTMLSelectElement::SetOption(unsigned index,
// Finally add the new element.
EventQueueScope scope;
add(element, before, exception_state);
+ if (exception_state.HadException())
+ return;
if (diff >= 0 && option->Selected())
OptionSelectionStateChanged(option, true);
}
@@ -709,8 +712,7 @@ void HTMLSelectElement::ChildrenChanged(const ChildrenChange& change) {
OptionRemoved(child_option);
}
} else if (change.type == ChildrenChangeType::kAllChildrenRemoved) {
- DCHECK(change.removed_nodes);
- for (Node* node : *change.removed_nodes) {
+ for (Node* node : change.removed_nodes) {
if (auto* option = DynamicTo<HTMLOptionElement>(node)) {
OptionRemoved(*option);
} else if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(node)) {
@@ -1109,7 +1111,7 @@ void HTMLSelectElement::TypeAheadFind(const KeyboardEvent& event) {
void HTMLSelectElement::SelectOptionByAccessKey(HTMLOptionElement* option) {
// First bring into focus the list box.
if (!IsFocused())
- AccessKeyAction(false);
+ AccessKeyAction(SimulatedClickCreationScope::kFromUserAgent);
if (!option || option->OwnerSelectElement() != this)
return;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
index b9b87282849..807f104b7bf 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -30,6 +30,7 @@
#include "base/gtest_prod_util.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
#include "third_party/blink/renderer/core/html/forms/html_options_collection.h"
#include "third_party/blink/renderer/core/html/forms/option_list.h"
@@ -115,7 +116,7 @@ class CORE_EXPORT HTMLSelectElement final
// We prefer |optionList()| to |listItems()|.
const ListItems& GetListItems() const;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
void SelectOptionByAccessKey(HTMLOptionElement*);
void SetOption(unsigned index, HTMLOptionElement*, ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
new file mode 100644
index 00000000000..de7842ab649
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
@@ -0,0 +1,348 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/forms/html_select_menu_element.h"
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/html/forms/html_button_element.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/html/html_popup_element.h"
+#include "third_party/blink/renderer/core/html/html_slot_element.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+
+namespace blink {
+
+HTMLSelectMenuElement::HTMLSelectMenuElement(Document& document)
+ : HTMLElement(html_names::kSelectmenuTag, document) {
+ DCHECK(RuntimeEnabledFeatures::HTMLSelectMenuElementEnabled());
+ DCHECK(RuntimeEnabledFeatures::HTMLPopupElementEnabled());
+ UseCounter::Count(document, WebFeature::kSelectMenuElement);
+
+ // TODO(crbug.com/1121840) This should really be a user-agent shadow root.
+ // But, these don't support name-based assignment (see
+ // ShouldAssignToCustomSlot). Perhaps names-based slot assignment can be added
+ // to user-agent shadows? See crbug.com/1179356.
+ AttachShadowRootInternal(ShadowRootType::kClosed);
+
+ CreateShadowSubtree();
+}
+
+void HTMLSelectMenuElement::CreateShadowSubtree() {
+ DCHECK(IsShadowHost(this));
+
+ Document& document = this->GetDocument();
+
+ // TODO(crbug.com/1121840) Where to put the styles for the default elements in
+ // the shadow tree? We'd like to have them in the UA styles (html.css), but
+ // the -webkit pseudo-id selectors only work if this is a UA shadow DOM. We
+ // can't use a UA shadow DOMs because these don't currently support named
+ // slots. For now, just set the style attributes with raw inline strings, but
+ // we should be able to do something better than this. Probably the solution
+ // is to get named slots working in UA shadow DOM (crbug.com/1179356), and
+ // then we can switch to that and use the -webkit pseudo-id selectors.
+
+ auto* button_slot = MakeGarbageCollected<HTMLSlotElement>(document);
+ slotchange_listener_ =
+ MakeGarbageCollected<HTMLSelectMenuElement::SlotChangeEventListener>(
+ this);
+ button_slot->addEventListener(event_type_names::kSlotchange,
+ slotchange_listener_, false);
+ button_slot->setAttribute(html_names::kNameAttr, kButtonPartName);
+
+ button_part_ = MakeGarbageCollected<HTMLButtonElement>(document);
+ button_part_->setAttribute(html_names::kPartAttr, kButtonPartName);
+ button_part_->setAttribute(html_names::kStyleAttr,
+ R"CSS(
+ display: inline-flex;
+ align-items: center;
+ background-color: #ffffff;
+ padding: 0 0 0 3px;
+ border: 1px solid #767676;
+ border-radius: 2px;
+ cursor: default;
+ )CSS");
+ button_part_listener_ =
+ MakeGarbageCollected<HTMLSelectMenuElement::ButtonPartEventListener>(
+ this);
+ button_part_->addEventListener(event_type_names::kClick,
+ button_part_listener_, false);
+
+ selected_value_part_ = MakeGarbageCollected<HTMLDivElement>(document);
+ selected_value_part_->setAttribute(html_names::kPartAttr,
+ kSelectedValuePartName);
+
+ auto* button_icon = MakeGarbageCollected<HTMLDivElement>(document);
+ button_icon->setAttribute(html_names::kStyleAttr,
+ R"CSS(
+ background-image: url(
+ 'data:image/svg+xml,\
+ <svg width="20" height="14" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">\
+ <path d="M4 6 L10 12 L 16 6" stroke="WindowText" stroke-width="3" stroke-linejoin="round"/>\
+ </svg>');
+ background-origin: content-box;
+ background-repeat: no-repeat;
+ background-size: contain;
+ height: 1.0em;
+ margin-inline-start: 4px;
+ opacity: 1;
+ outline: none;
+ padding-bottom: 2px;
+ padding-inline-start: 3px;
+ padding-inline-end: 3px;
+ padding-top: 2px;
+ width: 1.2em;
+ )CSS");
+
+ auto* listbox_slot = MakeGarbageCollected<HTMLSlotElement>(document);
+ listbox_slot->addEventListener(event_type_names::kSlotchange,
+ slotchange_listener_, false);
+ listbox_slot->setAttribute(html_names::kNameAttr, kListboxPartName);
+
+ listbox_part_ = MakeGarbageCollected<HTMLPopupElement>(document);
+ listbox_part_->setAttribute(html_names::kPartAttr, kListboxPartName);
+
+ auto* options_slot = MakeGarbageCollected<HTMLSlotElement>(document);
+ options_slot->addEventListener(event_type_names::kSlotchange,
+ slotchange_listener_, false);
+
+ button_part_->AppendChild(selected_value_part_);
+ button_part_->AppendChild(button_icon);
+
+ button_slot->AppendChild(button_part_);
+
+ listbox_part_->appendChild(options_slot);
+ listbox_slot->appendChild(listbox_part_);
+
+ this->GetShadowRoot()->AppendChild(button_slot);
+ this->GetShadowRoot()->AppendChild(listbox_slot);
+
+ option_part_listener_ =
+ MakeGarbageCollected<HTMLSelectMenuElement::OptionPartEventListener>(
+ this);
+}
+
+String HTMLSelectMenuElement::value() const {
+ if (selected_option_) {
+ return selected_option_->innerText();
+ }
+ return "";
+}
+
+void HTMLSelectMenuElement::setValue(const String& value, bool send_events) {
+ // Find the option with innerText matching the given parameter and make it the
+ // current selection.
+ for (auto& option : option_parts_) {
+ if (option->innerText() == value) {
+ SetSelectedOption(option);
+ break;
+ }
+ }
+}
+
+bool HTMLSelectMenuElement::IsOpen() const {
+ // TODO(crbug.com/1121840) listbox_part_ can be null if
+ // the author has filled the listbox slot without including
+ // a replacement listbox part. Instead of null checks like this,
+ // we should consider refusing to render the control at all if
+ // either of the key parts (button or listbox) are missing.
+ return listbox_part_ != nullptr && listbox_part_->open();
+}
+
+void HTMLSelectMenuElement::Open() {
+ if (listbox_part_ != nullptr && !IsOpen()) {
+ listbox_part_->show();
+ }
+}
+
+void HTMLSelectMenuElement::Close() {
+ if (listbox_part_ != nullptr && IsOpen()) {
+ listbox_part_->hide();
+ }
+}
+
+void HTMLSelectMenuElement::UpdatePartElements() {
+ Element* new_button_part = nullptr;
+ Element* new_selected_value_part = nullptr;
+ HTMLPopupElement* new_listbox_part = nullptr;
+ HeapLinkedHashSet<Member<Element>> new_option_parts;
+
+ for (Node* node = FlatTreeTraversal::FirstChild(*this); node != nullptr;
+ node = FlatTreeTraversal::Next(*node, this)) {
+ // For all part types, if there are multiple candidates, choose the
+ // one that comes first in the flat tree traversal.
+
+ auto* element = DynamicTo<Element>(node);
+ if (element == nullptr) {
+ continue;
+ }
+
+ if (new_button_part == nullptr &&
+ element->getAttribute(html_names::kPartAttr) == kButtonPartName) {
+ new_button_part = element;
+ }
+
+ if (new_selected_value_part == nullptr &&
+ element->getAttribute(html_names::kPartAttr) ==
+ kSelectedValuePartName) {
+ new_selected_value_part = element;
+ }
+
+ if (new_listbox_part == nullptr &&
+ element->getAttribute(html_names::kPartAttr) == kListboxPartName) {
+ // TODO(crbug.com/1121840) Should we allow non-<popup> elements to be
+ // the listbox part? If so, how to manage open/closed state?
+ if (auto* popup_element = DynamicTo<HTMLPopupElement>(element)) {
+ new_listbox_part = popup_element;
+ } else {
+ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kRendering,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "Found non-<popup> element labeled as listbox under <selectmenu>, "
+ "but only a <popup> can be used for the <selectmenu>'s listbox "
+ "part."));
+ }
+ }
+
+ // The fact that this comes after the clauses for other parts
+ // means that an <option> element labeled as another part will
+ // be handled as the other part type. E.g. <option part="button">
+ // will be treated as a button.
+ // TODO(crbug.com/1121840) Only include options that are inside the
+ // listbox, or allow them to be anywhere in the <selectmenu>?
+ if (element->getAttribute(html_names::kPartAttr) == kOptionPartName ||
+ IsA<HTMLOptionElement>(element)) {
+ new_option_parts.insert(element);
+ }
+ }
+
+ if (button_part_ != new_button_part) {
+ if (button_part_) {
+ button_part_->removeEventListener(event_type_names::kClick,
+ button_part_listener_, false);
+ }
+ if (new_button_part) {
+ new_button_part->addEventListener(event_type_names::kClick,
+ button_part_listener_, false);
+ }
+ button_part_ = new_button_part;
+ }
+
+ selected_value_part_ = new_selected_value_part;
+
+ listbox_part_ = new_listbox_part;
+
+ bool updateSelectedOption = false;
+ for (auto& option : option_parts_) {
+ if (!new_option_parts.Contains(option)) {
+ option->removeEventListener(event_type_names::kClick,
+ option_part_listener_, false);
+
+ if (option == selected_option_) {
+ updateSelectedOption = true;
+ }
+
+ // TODO(crbug.com/1121840) Whenever we figure out how to set
+ // focusability properly (without using tabIndex), we should undo up
+ // those changes here for elements that are no longer option parts.
+ }
+ }
+
+ for (auto& option : new_option_parts) {
+ if (!option_parts_.Contains(option)) {
+ option->addEventListener(event_type_names::kClick, option_part_listener_,
+ false);
+
+ // TODO(crbug.com/1121840) We don't want to actually change the attribute,
+ // and if tabindex is already set we shouldn't override it. So we need to
+ // come up with something else here.
+ option->setTabIndex(-1);
+ }
+ }
+
+ option_parts_ = new_option_parts;
+ if (updateSelectedOption || selected_option_ == nullptr) {
+ // If the currently selected option was removed, or if
+ // we didn't have a selected option previously, change the
+ // selection to the first option part, if there is one.
+ SetSelectedOption(option_parts_.size() > 0 ? option_parts_.front()
+ : nullptr);
+ }
+}
+
+void HTMLSelectMenuElement::SetSelectedOption(Element* selected_option) {
+ if (selected_option_ == selected_option)
+ return;
+
+ selected_option_ = selected_option;
+ UpdateSelectedValuePartContents();
+}
+
+void HTMLSelectMenuElement::UpdateSelectedValuePartContents() {
+ // Null-check here because the selected-value part is optional; the author
+ // might replace the button contents and not provide a selected-value part if
+ // they want to show something in the button other than the current value of
+ // the <selectmenu>.
+ if (selected_value_part_) {
+ selected_value_part_->setTextContent(
+ selected_option_ ? selected_option_->innerText() : "");
+ }
+}
+
+void HTMLSelectMenuElement::ButtonPartEventListener::Invoke(ExecutionContext*,
+ Event* event) {
+ if (event->type() == event_type_names::kClick &&
+ !select_menu_element_->IsOpen()) {
+ select_menu_element_->Open();
+ }
+}
+
+void HTMLSelectMenuElement::OptionPartEventListener::Invoke(ExecutionContext*,
+ Event* event) {
+ if (event->type() == event_type_names::kClick) {
+ Element* target_element =
+ DynamicTo<Element>(event->currentTarget()->ToNode());
+ DCHECK(target_element);
+ DCHECK(select_menu_element_->option_parts_.Contains(target_element));
+ select_menu_element_->SetSelectedOption(target_element);
+ select_menu_element_->listbox_part_->hide();
+ }
+}
+
+void HTMLSelectMenuElement::SlotChangeEventListener::Invoke(ExecutionContext*,
+ Event* event) {
+ DCHECK_EQ(event->type(), event_type_names::kSlotchange);
+ // TODO(crbug.com/1121840) Slotchange doesn't fire when
+ // the children of slotted content change, so it isn't
+ // enough to do this here. We might need to set up mutation observers
+ // or something to watch for changes in addition or instead of the
+ // slotchange event.
+ // Also, if we want to match the select behavior, then we should be
+ // doing this update synchronously. See failing tests in
+ // external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-value.html
+ select_menu_element_->UpdatePartElements();
+}
+
+void HTMLSelectMenuElement::Trace(Visitor* visitor) const {
+ visitor->Trace(button_part_listener_);
+ visitor->Trace(option_part_listener_);
+ visitor->Trace(slotchange_listener_);
+ visitor->Trace(button_part_);
+ visitor->Trace(selected_value_part_);
+ visitor->Trace(listbox_part_);
+ visitor->Trace(option_parts_);
+ visitor->Trace(selected_option_);
+ HTMLElement::Trace(visitor);
+}
+
+constexpr char HTMLSelectMenuElement::kButtonPartName[];
+constexpr char HTMLSelectMenuElement::kSelectedValuePartName[];
+constexpr char HTMLSelectMenuElement::kListboxPartName[];
+constexpr char HTMLSelectMenuElement::kOptionPartName[];
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.h
new file mode 100644
index 00000000000..aa5d320997b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.h
@@ -0,0 +1,107 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_MENU_ELEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_MENU_ELEMENT_H_
+
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+
+namespace blink {
+
+class Document;
+
+// The HTMLSelectMenuElement implements the <selectmenu> HTML element.
+// The <selectmenu> element is similar to <select>, but allows site authors
+// freedom to customize the element's appearance and shadow DOM structure.
+// This feature is still under development, and is not part of the HTML
+// standard. It can be enabled by passing
+// --enable-blink-features=HTMLSelectMenuElement. See
+// https://groups.google.com/u/1/a/chromium.org/g/blink-dev/c/9TcfjaOs5zg/m/WAiv6WpUAAAJ
+// for more details.
+class HTMLSelectMenuElement final : public HTMLElement {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit HTMLSelectMenuElement(Document&);
+
+ String value() const;
+ void setValue(const String&, bool send_events = false);
+
+ bool IsOpen() const;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void CreateShadowSubtree();
+ void Open();
+ void Close();
+ void UpdatePartElements();
+ void SetSelectedOption(Element* selected_option);
+ void UpdateSelectedValuePartContents();
+
+ class ButtonPartEventListener : public NativeEventListener {
+ public:
+ explicit ButtonPartEventListener(HTMLSelectMenuElement* select_menu_element)
+ : select_menu_element_(select_menu_element) {}
+ void Invoke(ExecutionContext*, Event*) override;
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(select_menu_element_);
+ NativeEventListener::Trace(visitor);
+ }
+
+ private:
+ Member<HTMLSelectMenuElement> select_menu_element_;
+ };
+
+ class OptionPartEventListener : public NativeEventListener {
+ public:
+ explicit OptionPartEventListener(HTMLSelectMenuElement* select_menu_element)
+ : select_menu_element_(select_menu_element) {}
+ void Invoke(ExecutionContext*, Event*) override;
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(select_menu_element_);
+ NativeEventListener::Trace(visitor);
+ }
+
+ private:
+ Member<HTMLSelectMenuElement> select_menu_element_;
+ };
+
+ class SlotChangeEventListener : public NativeEventListener {
+ public:
+ explicit SlotChangeEventListener(HTMLSelectMenuElement* select_menu_element)
+ : select_menu_element_(select_menu_element) {}
+ void Invoke(ExecutionContext*, Event*) override;
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(select_menu_element_);
+ NativeEventListener::Trace(visitor);
+ }
+
+ private:
+ Member<HTMLSelectMenuElement> select_menu_element_;
+ };
+
+ static constexpr char kButtonPartName[] = "button";
+ static constexpr char kSelectedValuePartName[] = "selected-value";
+ static constexpr char kListboxPartName[] = "listbox";
+ static constexpr char kOptionPartName[] = "option";
+
+ Member<ButtonPartEventListener> button_part_listener_;
+ Member<OptionPartEventListener> option_part_listener_;
+ Member<SlotChangeEventListener> slotchange_listener_;
+
+ Member<Element> button_part_;
+ Member<Element> selected_value_part_;
+ Member<HTMLPopupElement> listbox_part_;
+ HeapLinkedHashSet<Member<Element>> option_parts_;
+ Member<Element> selected_option_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_MENU_ELEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.idl b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.idl
new file mode 100644
index 00000000000..b11883770f7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_select_menu_element.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[Exposed=Window,HTMLConstructor,RuntimeEnabled=HTMLSelectMenuElement]
+interface HTMLSelectMenuElement : HTMLElement {
+ attribute DOMString value;
+ // TODO(crbug.com/1121840) Fill this out.
+ // Open question: do we want to replicate the interface of
+ // <select> as closely as possible?
+ // Or should we try to improve, simplify, or extend it?
+};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
index 7cdf765f11f..0d857bc97f2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
@@ -357,7 +358,7 @@ void HTMLTextAreaElement::SubtreeHasChanged() {
// When typing in a textarea, childrenChanged is not called, so we need to
// force the directionality check.
- CalculateAndAdjustDirectionality();
+ CalculateAndAdjustAutoDirectionality(this);
DCHECK(GetDocument().IsActive());
GetDocument().GetPage()->GetChromeClient().DidChangeValueInTextField(*this);
@@ -617,7 +618,7 @@ bool HTMLTextAreaElement::IsValidValue(const String& candidate) const {
!TooShort(&candidate, kIgnoreDirtyFlag);
}
-void HTMLTextAreaElement::AccessKeyAction(bool) {
+void HTMLTextAreaElement::AccessKeyAction(SimulatedClickCreationScope) {
focus();
}
@@ -646,6 +647,7 @@ void HTMLTextAreaElement::SetPlaceholderVisibility(bool visible) {
void HTMLTextAreaElement::UpdatePlaceholderText() {
HTMLElement* placeholder = PlaceholderElement();
const String placeholder_text = GetPlaceholderValue();
+ const bool is_suggested_value = !SuggestedValue().IsEmpty();
if (placeholder_text.IsEmpty()) {
if (placeholder)
UserAgentShadowRoot()->RemoveChild(placeholder);
@@ -662,6 +664,12 @@ void HTMLTextAreaElement::UpdatePlaceholderText() {
IsPlaceholderVisible() ? CSSValueID::kBlock : CSSValueID::kNone, true);
UserAgentShadowRoot()->InsertBefore(placeholder, InnerEditorElement());
}
+ if (is_suggested_value) {
+ placeholder->SetInlineStyleProperty(CSSPropertyID::kUserSelect,
+ CSSValueID::kNone, true);
+ } else {
+ placeholder->RemoveInlineStyleProperty(CSSPropertyID::kUserSelect);
+ }
String normalized_value = placeholder_text;
// https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-placeholder
ReplaceCRWithNewLine(normalized_value);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
index e518140906a..bb301489f2b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/html_text_area_element.h
@@ -26,6 +26,7 @@
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
namespace blink {
@@ -128,7 +129,7 @@ class CORE_EXPORT HTMLTextAreaElement final : public TextControlElement {
void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
const FocusOptions*) override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
bool MatchesReadOnlyPseudoClass() const override;
bool MatchesReadWritePseudoClass() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/image_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/image_input_type.cc
index bf5ba5db832..6e5c35bab3b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/image_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/image_input_type.cc
@@ -188,7 +188,7 @@ unsigned ImageInputType::Height() const {
HTMLImageLoader* image_loader = GetElement().ImageLoader();
if (image_loader && image_loader->GetContent()) {
return image_loader->GetContent()
- ->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(nullptr))
+ ->IntrinsicSize(kRespectImageOrientation)
.Height();
}
}
@@ -214,7 +214,7 @@ unsigned ImageInputType::Width() const {
HTMLImageLoader* image_loader = GetElement().ImageLoader();
if (image_loader && image_loader->GetContent()) {
return image_loader->GetContent()
- ->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(nullptr))
+ ->IntrinsicSize(kRespectImageOrientation)
.Width();
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
index 8819c8304c4..25d3b0a20c7 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/core/html/forms/input_type_view.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -77,7 +78,7 @@ void InputTypeView::DispatchSimulatedClickIfActive(KeyboardEvent& event) const {
event.SetDefaultHandled();
}
-void InputTypeView::AccessKeyAction(bool) {
+void InputTypeView::AccessKeyAction(SimulatedClickCreationScope) {
GetElement().focus(FocusParams(SelectionBehaviorOnFocus::kReset,
mojom::blink::FocusType::kNone, nullptr));
}
@@ -188,7 +189,7 @@ bool InputTypeView::ShouldDrawCapsLockIndicator() const {
void InputTypeView::UpdateClearButtonVisibility() {}
-void InputTypeView::UpdatePlaceholderText() {}
+void InputTypeView::UpdatePlaceholderText(bool) {}
AXObject* InputTypeView::PopupRootAXObject() {
return nullptr;
@@ -202,7 +203,8 @@ FormControlState InputTypeView::SaveFormControlState() const {
}
void InputTypeView::RestoreFormControlState(const FormControlState& state) {
- GetElement().setValue(state[0]);
+ GetElement().setValue(state[0],
+ TextFieldEventBehavior::kDispatchInputAndChangeEvent);
}
bool InputTypeView::IsDraggedSlider() const {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
index f2a5ed488ab..ebe7aaa1d08 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/input_type_view.h
@@ -37,6 +37,7 @@
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -98,7 +99,7 @@ class CORE_EXPORT InputTypeView : public GarbageCollectedMixin {
mojom::blink::FocusType);
virtual void HandleBlurEvent();
virtual void HandleDOMActivateEvent(Event&);
- virtual void AccessKeyAction(bool send_mouse_events);
+ virtual void AccessKeyAction(SimulatedClickCreationScope creation_scope);
virtual void Blur();
void DispatchSimulatedClickIfActive(KeyboardEvent&) const;
@@ -135,7 +136,7 @@ class CORE_EXPORT InputTypeView : public GarbageCollectedMixin {
virtual void CapsLockStateMayHaveChanged();
virtual bool ShouldDrawCapsLockIndicator() const;
virtual void UpdateClearButtonVisibility();
- virtual void UpdatePlaceholderText();
+ virtual void UpdatePlaceholderText(bool is_suggested_value);
virtual AXObject* PopupRootAXObject();
virtual void EnsureFallbackContent() {}
virtual void EnsurePrimaryContent() {}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
index ec97640e577..b3a13907d2d 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -87,10 +87,11 @@ scoped_refptr<const ComputedStyle> StyleForHoveredScrollbarPart(
if (part == kNoPart)
return nullptr;
scrollbar->SetHoveredPart(part);
- scoped_refptr<const ComputedStyle> part_style = element.StyleForPseudoElement(
- PseudoElementStyleRequest(target_id, To<CustomScrollbar>(scrollbar),
- part),
- style);
+ scoped_refptr<const ComputedStyle> part_style =
+ element.UncachedStyleForPseudoElement(
+ PseudoElementStyleRequest(target_id, To<CustomScrollbar>(scrollbar),
+ part),
+ style);
return part_style;
}
@@ -99,7 +100,7 @@ scoped_refptr<const ComputedStyle> StyleForHoveredScrollbarPart(
class PopupMenuCSSFontSelector : public CSSFontSelector,
private FontSelectorClient {
public:
- PopupMenuCSSFontSelector(Document*, CSSFontSelector*);
+ PopupMenuCSSFontSelector(Document&, CSSFontSelector*);
~PopupMenuCSSFontSelector() override;
// We don't override willUseFontData() for now because the old PopupListBox
@@ -116,7 +117,7 @@ class PopupMenuCSSFontSelector : public CSSFontSelector,
};
PopupMenuCSSFontSelector::PopupMenuCSSFontSelector(
- Document* document,
+ Document& document,
CSSFontSelector* owner_font_selector)
: CSSFontSelector(document), owner_font_selector_(owner_font_selector) {
owner_font_selector_->RegisterForInvalidationCallbacks(this);
@@ -492,11 +493,11 @@ void InternalPopupMenu::AppendOwnerElementPseudoStyles(
PagePopupClient::AddString(target + "{ \n", data);
const CSSPropertyID serialize_targets[] = {
- CSSPropertyID::kDisplay, CSSPropertyID::kBackgroundColor,
- CSSPropertyID::kWidth, CSSPropertyID::kBorderBottom,
- CSSPropertyID::kBorderLeft, CSSPropertyID::kBorderRight,
- CSSPropertyID::kBorderTop, CSSPropertyID::kBorderRadius,
- CSSPropertyID::kBoxShadow};
+ CSSPropertyID::kDisplay, CSSPropertyID::kBackgroundColor,
+ CSSPropertyID::kWidth, CSSPropertyID::kBorderBottom,
+ CSSPropertyID::kBorderLeft, CSSPropertyID::kBorderRight,
+ CSSPropertyID::kBorderTop, CSSPropertyID::kBorderRadius,
+ CSSPropertyID::kBackgroundClip, CSSPropertyID::kBoxShadow};
for (CSSPropertyID id : serialize_targets) {
PagePopupClient::AddString(SerializeComputedStyleForProperty(style, id),
@@ -510,7 +511,7 @@ CSSFontSelector* InternalPopupMenu::CreateCSSFontSelector(
Document& popup_document) {
Document& owner_document = OwnerElement().GetDocument();
return MakeGarbageCollected<PopupMenuCSSFontSelector>(
- &popup_document, owner_document.GetStyleEngine().GetFontSelector());
+ popup_document, owner_document.GetStyleEngine().GetFontSelector());
}
void InternalPopupMenu::SetValueAndClosePopup(int num_value,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.cc b/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.cc
index ba8e4bb19f8..2392c425f74 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
@@ -67,10 +68,10 @@ void KeyboardClickableInputTypeView::HandleKeyupEvent(KeyboardEvent& event) {
// FIXME: Could share this with BaseCheckableInputType and RangeInputType if we
// had a common base class.
-void KeyboardClickableInputTypeView::AccessKeyAction(bool send_mouse_events) {
- InputTypeView::AccessKeyAction(send_mouse_events);
- GetElement().DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+void KeyboardClickableInputTypeView::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
+ InputTypeView::AccessKeyAction(creation_scope);
+ GetElement().DispatchSimulatedClick(nullptr, creation_scope);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h b/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h
index 4fd91a6a78f..e01fe106f07 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/keyboard_clickable_input_type_view.h
@@ -32,6 +32,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_KEYBOARD_CLICKABLE_INPUT_TYPE_VIEW_H_
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/input_type_view.h"
namespace blink {
@@ -46,7 +47,7 @@ class CORE_EXPORT KeyboardClickableInputTypeView : public InputTypeView {
void HandleKeydownEvent(KeyboardEvent&) override;
void HandleKeypressEvent(KeyboardEvent&) override;
void HandleKeyupEvent(KeyboardEvent&) override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc b/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
index f96b288b259..90e3bcb8088 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
@@ -16,8 +16,8 @@ MenuListInnerElement::MenuListInnerElement(Document& document)
SetHasCustomStyleCallbacks();
}
-scoped_refptr<ComputedStyle>
-MenuListInnerElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> MenuListInnerElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
const ComputedStyle& parent_style = OwnerShadowHost()->ComputedStyleRef();
scoped_refptr<ComputedStyle> style =
ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
diff --git a/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h b/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
index b3f7085cb59..0d8317af9c5 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
@@ -14,7 +14,8 @@ class MenuListInnerElement : public HTMLDivElement {
explicit MenuListInnerElement(Document& document);
private:
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc b/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
index 2ac6e83e0e6..1c2f3389f3e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
@@ -71,8 +71,8 @@ TEST(PasswordInputTypeTest, DidEditFieldEvent) {
TEST(PasswordInputTypeTest, DidEditFieldEventNotSentFromSecureContext) {
auto page_holder = std::make_unique<DummyPageHolder>(IntSize(2000, 2000));
page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("https://example.test")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("https://example.test")),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
MockInsecureInputService mock_service(page_holder->GetFrame());
diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
index 1cdacdcbfab..2a4bbe5c47c 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
@@ -163,14 +163,6 @@ void RadioButtonGroup::Remove(HTMLInputElement* button) {
// valid only if the group was invalid.
button->SetNeedsValidityCheck();
}
-
- // Send notification to update AX attributes for AXObjects which radiobutton
- // group has.
- if (!members_.IsEmpty()) {
- HTMLInputElement* input = members_.begin()->key;
- if (AXObjectCache* cache = input->GetDocument().ExistingAXObjectCache())
- cache->RadiobuttonRemovedFromGroup(input);
- }
}
void RadioButtonGroup::SetNeedsValidityCheckForAllButtons() {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
index c8b4880ee6a..0514ac5b6d8 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc
@@ -158,7 +158,7 @@ void RadioInputType::HandleKeydownEvent(KeyboardEvent& event) {
document.SetFocusedElement(
input_element, FocusParams(SelectionBehaviorOnFocus::kRestore,
mojom::blink::FocusType::kNone, nullptr));
- input_element->DispatchSimulatedClick(&event, kSendNoEvents);
+ input_element->DispatchSimulatedClick(&event);
event.SetDefaultHandled();
return;
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
index 5c3933f2150..f978b04e64b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
@@ -194,12 +195,8 @@ void RangeInputType::HandleKeydownEvent(KeyboardEvent& event) {
std::max((step_range.Maximum() - step_range.Minimum()) / 10, step);
TextDirection dir = TextDirection::kLtr;
- bool is_vertical = false;
if (GetElement().GetLayoutObject()) {
dir = ComputedTextDirection();
- ControlPart part =
- GetElement().GetLayoutObject()->Style()->EffectiveAppearance();
- is_vertical = part == kSliderVerticalPart;
}
Decimal new_value;
@@ -208,19 +205,17 @@ void RangeInputType::HandleKeydownEvent(KeyboardEvent& event) {
} else if (key == "ArrowDown") {
new_value = current - step;
} else if (key == "ArrowLeft") {
- new_value = (is_vertical || dir == TextDirection::kRtl) ? current + step
- : current - step;
+ new_value = dir == TextDirection::kRtl ? current + step : current - step;
} else if (key == "ArrowRight") {
- new_value = (is_vertical || dir == TextDirection::kRtl) ? current - step
- : current + step;
+ new_value = dir == TextDirection::kRtl ? current - step : current + step;
} else if (key == "PageUp") {
new_value = current + big_step;
} else if (key == "PageDown") {
new_value = current - big_step;
} else if (key == "Home") {
- new_value = is_vertical ? step_range.Maximum() : step_range.Minimum();
+ new_value = step_range.Minimum();
} else if (key == "End") {
- new_value = is_vertical ? step_range.Minimum() : step_range.Maximum();
+ new_value = step_range.Maximum();
} else {
return; // Did not match any key binding.
}
@@ -255,14 +250,6 @@ void RangeInputType::CreateShadowSubtree() {
GetElement().UserAgentShadowRoot()->AppendChild(container);
}
-bool RangeInputType::TypeShouldForceLegacyLayout() const {
- if (RuntimeEnabledFeatures::LayoutNGForControlsEnabled())
- return false;
- UseCounter::Count(GetElement().GetDocument(),
- WebFeature::kLegacyLayoutBySlider);
- return true;
-}
-
LayoutObject* RangeInputType::CreateLayoutObject(const ComputedStyle& style,
LegacyLayout legacy) const {
// TODO(crbug.com/1131352): input[type=range] should not use
@@ -283,11 +270,10 @@ String RangeInputType::Serialize(const Decimal& value) const {
// FIXME: Could share this with KeyboardClickableInputTypeView and
// BaseCheckableInputType if we had a common base class.
-void RangeInputType::AccessKeyAction(bool send_mouse_events) {
- InputTypeView::AccessKeyAction(send_mouse_events);
-
- GetElement().DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+void RangeInputType::AccessKeyAction(
+ SimulatedClickCreationScope creation_scope) {
+ InputTypeView::AccessKeyAction(creation_scope);
+ GetElement().DispatchSimulatedClick(nullptr, creation_scope);
}
void RangeInputType::SanitizeValueInResponseToMinOrMaxAttributeChange() {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
index 0c22a327616..2dc25f5ee34 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/range_input_type.h
@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_RANGE_INPUT_TYPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_RANGE_INPUT_TYPE_H_
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/input_type.h"
#include "third_party/blink/renderer/core/html/forms/input_type_view.h"
@@ -61,13 +62,12 @@ class RangeInputType final : public InputType, public InputTypeView {
bool IsSteppable() const override;
void HandleMouseDownEvent(MouseEvent&) override;
void HandleKeydownEvent(KeyboardEvent&) override;
- bool TypeShouldForceLegacyLayout() const override;
LayoutObject* CreateLayoutObject(const ComputedStyle&,
LegacyLayout) const override;
void CreateShadowSubtree() override;
Decimal ParseToNumber(const String&, const Decimal&) const override;
String Serialize(const Decimal&) const override;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
void SanitizeValueInResponseToMinOrMaxAttributeChange() override;
void StepAttributeChanged() override;
void WarnIfValueIsInvalid(const String&) const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.css b/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.css
index cb08889fcc1..401f06da483 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.css
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.css
@@ -211,6 +211,14 @@ channel-label {
format-toggler {
border: 1px solid WindowText;
}
+ format-toggler:hover,
+ input:hover {
+ border: 1px solid Highlight;
+ }
+ eye-dropper:hover {
+ border: 1px solid Highlight;
+ padding: 5px;
+ }
}
@media (prefers-color-scheme: dark) {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.js b/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.js
index b3ee0ad7ae4..e076b6332e8 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.js
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/color_picker.js
@@ -1789,6 +1789,7 @@ class ChannelValueContainer extends HTMLInputElement {
this.addEventListener('input', this.onValueChange_);
this.addEventListener('blur', this.onBlur_);
+ this.addEventListener('focus', this.onFocus_);
}
get channelValue() {
@@ -1851,13 +1852,12 @@ class ChannelValueContainer extends HTMLInputElement {
if (value) {
switch (this.colorChannel_) {
case ColorChannel.HEX:
- if (value.startsWith('#')) {
+ if (value.startsWith('#'))
value = value.substr(1).toLowerCase();
- if (value.match(/^[0-9a-f]+$/)) {
- // Ex. 'ffffff' => this.channelValue_ == 'ffffff'
- // Ex. 'ff' => this.channelValue_ == '0000ff'
- this.channelValue_ = ('000000' + value).slice(-6);
- }
+ if (value.match(/^[0-9a-f]+$/)) {
+ // Ex. 'ffffff' => this.channelValue_ == 'ffffff'
+ // Ex. 'ff' => this.channelValue_ == '0000ff'
+ this.channelValue_ = ('000000' + value).slice(-6);
}
break;
case ColorChannel.R:
@@ -1874,11 +1874,10 @@ class ChannelValueContainer extends HTMLInputElement {
break;
case ColorChannel.S:
case ColorChannel.L:
- if (value.endsWith('%')) {
+ if (value.endsWith('%'))
value = value.substring(0, value.length - 1);
- if (value.match(/^\d+$/) && (0 <= value) && (value <= 100)) {
- this.channelValue_ = Number(value);
- }
+ if (value.match(/^\d+$/) && (0 <= value) && (value <= 100)) {
+ this.channelValue_ = Number(value);
}
break;
}
@@ -1909,6 +1908,10 @@ class ChannelValueContainer extends HTMLInputElement {
break;
}
}
+
+ onFocus_ = () => {
+ this.select();
+ }
}
window.customElements.define(
'channel-value-container', ChannelValueContainer, {extends: 'input'});
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js b/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
index 1f936b10d3a..d292c47c997 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/listPicker.js
@@ -90,6 +90,7 @@ ListPicker.prototype._handleWindowMessage = function(event) {
if (window.updateData.type === 'update') {
this._config.baseStyle = window.updateData.baseStyle;
this._config.children = window.updateData.children;
+ const prev_children_count = this._selectElement.children.length;
this._update();
if (this._config.anchorRectInScreen.x !==
window.updateData.anchorRectInScreen.x ||
@@ -98,9 +99,10 @@ ListPicker.prototype._handleWindowMessage = function(event) {
this._config.anchorRectInScreen.width !==
window.updateData.anchorRectInScreen.width ||
this._config.anchorRectInScreen.height !==
- window.updateData.anchorRectInScreen.height) {
- this._config.anchorRectInScreen = window.updateData.anchorRectInScreen;
- this._fixWindowSize();
+ window.updateData.anchorRectInScreen.height ||
+ prev_children_count !== window.updateData.children.length) {
+ this._config.anchorRectInScreen = window.updateData.anchorRectInScreen;
+ this._fixWindowSize();
}
}
delete window.updateData;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/resources/validation_bubble.css b/chromium/third_party/blink/renderer/core/html/forms/resources/validation_bubble.css
index 2403a75d86b..c923e021aa1 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/resources/validation_bubble.css
+++ b/chromium/third_party/blink/renderer/core/html/forms/resources/validation_bubble.css
@@ -134,6 +134,7 @@
grid-column: 2;
margin-top: 3px;
margin-bottom: 4px;
+ white-space: pre-line;
}
#sub-message {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/search_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/search_input_type.cc
index e564c3261f6..914548d7304 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/search_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/search_input_type.cc
@@ -162,4 +162,9 @@ bool SearchInputType::SupportsInputModeAttribute() const {
return true;
}
+void SearchInputType::Trace(Visitor* visitor) const {
+ visitor->Trace(search_event_timer_);
+ BaseTextInputType::Trace(visitor);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/search_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/search_input_type.h
index dd1ff43512a..e9dccbf79ec 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/search_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/search_input_type.h
@@ -38,7 +38,9 @@ namespace blink {
class SearchInputType final : public BaseTextInputType {
public:
- SearchInputType(HTMLInputElement&);
+ explicit SearchInputType(HTMLInputElement&);
+
+ void Trace(Visitor*) const final;
private:
void CountUsage() override;
@@ -56,7 +58,7 @@ class SearchInputType final : public BaseTextInputType {
void StartSearchEventTimer();
void UpdateCancelButtonVisibility();
- TaskRunnerTimer<SearchInputType> search_event_timer_;
+ HeapTaskRunnerTimer<SearchInputType> search_event_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/select_type.cc b/chromium/third_party/blink/renderer/core/html/forms/select_type.cc
index 2197db39872..3a02df56a8e 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/select_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/select_type.cc
@@ -232,7 +232,7 @@ bool MenuListSelectType::DefaultEventHandler(const Event& event) {
->GetInputDeviceCapabilities()
->FiresTouchEvents(mouse_event->FromTouch());
select_->focus(FocusParams(SelectionBehaviorOnFocus::kRestore,
- mojom::blink::FocusType::kNone,
+ mojom::blink::FocusType::kMouse,
source_capabilities));
if (select_->GetLayoutObject() && !will_be_destroyed_ &&
!select_->IsDisabledFormControl()) {
diff --git a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
index 8fbea89e7c5..21676c674ac 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -287,11 +287,13 @@ const AtomicString& SliderThumbElement::ShadowPseudoId() const {
}
}
-scoped_refptr<ComputedStyle> SliderThumbElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> SliderThumbElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
Element* host = OwnerShadowHost();
DCHECK(host);
const ComputedStyle& host_style = host->ComputedStyleRef();
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
if (host_style.EffectiveAppearance() == kSliderVerticalPart)
style->SetEffectiveAppearance(kSliderThumbVerticalPart);
diff --git a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
index 069f438b7de..ff8635aacf2 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/slider_thumb_element.h
@@ -63,7 +63,8 @@ class SliderThumbElement final : public HTMLDivElement {
private:
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() final;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) final;
Element& CloneWithoutAttributesAndChildren(Document&) const override;
bool IsDisabledFormControl() const override;
bool MatchesReadOnlyPseudoClass() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
index fe31397f04d..b70a2b407a0 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.cc
@@ -223,6 +223,7 @@ bool SpinButtonElement::ShouldRespondToMouseEvents() {
void SpinButtonElement::Trace(Visitor* visitor) const {
visitor->Trace(spin_button_owner_);
+ visitor->Trace(repeating_timer_);
HTMLDivElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
index 482229a0f4c..b9828380e8b 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/spin_button_element.h
@@ -95,7 +95,7 @@ class CORE_EXPORT SpinButtonElement final : public HTMLDivElement,
bool capturing_;
UpDownState up_down_state_;
UpDownState press_starting_state_;
- TaskRunnerTimer<SpinButtonElement> repeating_timer_;
+ HeapTaskRunnerTimer<SpinButtonElement> repeating_timer_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_control_element.cc b/chromium/third_party/blink/renderer/core/html/forms/text_control_element.cc
index f06d2ab1bd7..4996197dee4 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -74,14 +74,13 @@ namespace {
Position GetNextSoftBreak(const NGOffsetMapping& mapping,
NGInlineCursor& cursor) {
while (cursor) {
- DCHECK(cursor.Current().IsLineBox()) << cursor.Current();
+ DCHECK(cursor.Current().IsLineBox()) << cursor;
const auto* break_token = cursor.Current().InlineBreakToken();
- DCHECK(break_token);
cursor.MoveToNextLine();
// We don't need to emit a LF for the last line.
if (!cursor)
return Position();
- if (!break_token->IsForcedBreak())
+ if (break_token && !break_token->IsForcedBreak())
return mapping.GetFirstPosition(break_token->TextOffset());
}
return Position();
@@ -780,7 +779,7 @@ void TextControlElement::SelectionChanged(bool user_triggered) {
return;
const SelectionInDOMTree& selection =
frame->Selection().GetSelectionInDOMTree();
- if (selection.Type() != kRangeSelection)
+ if (!selection.IsRange())
return;
DispatchEvent(*Event::CreateBubble(event_type_names::kSelect));
}
@@ -1047,10 +1046,8 @@ String TextControlElement::DirectionForFormData() const {
return dir_attribute_value;
if (EqualIgnoringASCIICase(dir_attribute_value, "auto")) {
- bool is_auto;
- TextDirection text_direction =
- element->DirectionalityIfhasDirAutoAttribute(is_auto);
- return text_direction == TextDirection::kRtl ? "rtl" : "ltr";
+ return element->CachedDirectionality() == TextDirection::kRtl ? "rtl"
+ : "ltr";
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_control_element.h b/chromium/third_party/blink/renderer/core/html/forms/text_control_element.h
index 3c96c9cbce1..5d65533faac 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_control_element.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_control_element.h
@@ -281,7 +281,7 @@ struct DowncastTraits<TextControlElement> {
TextControlElement* EnclosingTextControl(const Position&);
TextControlElement* EnclosingTextControl(const PositionInFlatTree&);
-TextControlElement* EnclosingTextControl(const Node*);
+CORE_EXPORT TextControlElement* EnclosingTextControl(const Node*);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
index 763660b3805..220dd750c83 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -45,8 +45,8 @@ EditingViewPortElement::EditingViewPortElement(Document& document)
setAttribute(html_names::kIdAttr, shadow_element_names::kIdEditingViewPort);
}
-scoped_refptr<ComputedStyle>
-EditingViewPortElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> EditingViewPortElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext&) {
// FXIME: Move these styles to html.css.
scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
@@ -134,7 +134,8 @@ LayoutObject* TextControlInnerEditorElement::CreateLayoutObject(
}
scoped_refptr<ComputedStyle>
-TextControlInnerEditorElement::CustomStyleForLayoutObject() {
+TextControlInnerEditorElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext&) {
scoped_refptr<ComputedStyle> inner_editor_style = CreateInnerEditorStyle();
// Using StyleAdjuster::adjustComputedStyle updates unwanted style. We'd like
// to apply only editing-related and alignment-related.
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
index 4be63f67adb..254b480c0f9 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
@@ -37,7 +37,8 @@ class EditingViewPortElement final : public HTMLDivElement {
explicit EditingViewPortElement(Document&);
protected:
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
private:
bool TypeShouldForceLegacyLayout() const final;
@@ -57,7 +58,8 @@ class TextControlInnerEditorElement final : public HTMLDivElement {
private:
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
bool TypeShouldForceLegacyLayout() const final;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
bool SupportsFocus() const override { return false; }
bool is_visible_ = true;
};
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
index c8606c31925..cea4e00d3d3 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -484,7 +484,7 @@ bool TextFieldInputType::ShouldRespectListAttribute() {
return true;
}
-void TextFieldInputType::UpdatePlaceholderText() {
+void TextFieldInputType::UpdatePlaceholderText(bool is_suggested_value) {
if (!SupportsPlaceholder())
return;
HTMLElement* placeholder = GetElement().PlaceholderElement();
@@ -512,6 +512,12 @@ void TextFieldInputType::UpdatePlaceholderText() {
previous->parentNode()->InsertBefore(placeholder, previous);
SECURITY_DCHECK(placeholder->parentNode() == previous->parentNode());
}
+ if (is_suggested_value) {
+ placeholder->SetInlineStyleProperty(CSSPropertyID::kUserSelect,
+ CSSValueID::kNone, true);
+ } else {
+ placeholder->RemoveInlineStyleProperty(CSSPropertyID::kUserSelect);
+ }
placeholder->setTextContent(placeholder_text);
}
diff --git a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
index 4f24cb60993..e1877045d29 100644
--- a/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
+++ b/chromium/third_party/blink/renderer/core/html/forms/text_field_input_type.h
@@ -88,7 +88,7 @@ class TextFieldInputType : public InputType,
bool ShouldSubmitImplicitly(const Event&) final;
bool ShouldRespectListAttribute() override;
void ListAttributeTargetChanged() override;
- void UpdatePlaceholderText() final;
+ void UpdatePlaceholderText(bool is_suggested_value) final;
void AppendToFormData(FormData&) const override;
void SubtreeHasChanged() final;
diff --git a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
index 81f0815d97e..b3ecda6a691 100644
--- a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -42,6 +42,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/anchor_element_metrics.h"
#include "third_party/blink/renderer/core/html/anchor_element_metrics_sender.h"
+#include "third_party/blink/renderer/core/html/conversion_measurement_parsing.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -204,7 +205,7 @@ bool HTMLAnchorElement::HasActivationBehavior() const {
}
void HTMLAnchorElement::SetActive(bool active) {
- if (HasEditableStyle(*this))
+ if (active && HasEditableStyle(*this))
return;
HTMLElement::SetActive(active);
@@ -262,11 +263,6 @@ void HTMLAnchorElement::ParseAttribute(
}
}
-void HTMLAnchorElement::AccessKeyAction(bool send_mouse_events) {
- DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
-}
-
bool HTMLAnchorElement::IsURLAttribute(const Attribute& attribute) const {
return attribute.GetName().LocalName() == html_names::kHrefAttr ||
HTMLElement::IsURLAttribute(attribute);
@@ -358,90 +354,6 @@ bool HTMLAnchorElement::HasImpression() const {
hasAttribute(html_names::kConversiondestinationAttr);
}
-base::Optional<WebImpression> HTMLAnchorElement::GetImpressionForNavigation()
- const {
- DCHECK(HasImpression());
-
- if (!RuntimeEnabledFeatures::ConversionMeasurementEnabled(
- GetExecutionContext()))
- return base::nullopt;
-
- if (!GetExecutionContext()->IsFeatureEnabled(
- mojom::blink::FeaturePolicyFeature::kConversionMeasurement)) {
- String message =
- "The 'conversion-measurement' feature policy must be enabled to "
- "declare an impression.";
- GetExecutionContext()->AddConsoleMessage(
- MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kOther,
- mojom::blink::ConsoleMessageLevel::kError, message));
- return base::nullopt;
- }
-
- // Conversion measurement is only allowed when both the frame and the main
- // frame (if different) have a secure origin.
- LocalFrame* frame = GetDocument().GetFrame();
- const Frame& main_frame = frame->Tree().Top();
- if (!main_frame.GetSecurityContext()
- ->GetSecurityOrigin()
- ->IsPotentiallyTrustworthy()) {
- return base::nullopt;
- }
- if (!frame->IsMainFrame() && !frame->GetSecurityContext()
- ->GetSecurityOrigin()
- ->IsPotentiallyTrustworthy()) {
- return base::nullopt;
- }
-
- const AtomicString& conversion_destination_string =
- FastGetAttribute(html_names::kConversiondestinationAttr);
- scoped_refptr<const SecurityOrigin> conversion_destination =
- SecurityOrigin::CreateFromString(conversion_destination_string);
- if (!conversion_destination->IsPotentiallyTrustworthy())
- return base::nullopt;
-
- bool impression_data_is_valid = false;
- uint64_t impression_data = FastGetAttribute(html_names::kImpressiondataAttr)
- .GetString()
- .HexToUInt64Strict(&impression_data_is_valid);
-
- // Provide a default of 0 if the impression data was not valid.
- impression_data = impression_data_is_valid ? impression_data : 0UL;
-
- // Reporting origin is an optional attribute. Reporting origins must be
- // secure.
- base::Optional<WebSecurityOrigin> reporting_origin;
- if (hasAttribute(html_names::kReportingoriginAttr)) {
- const AtomicString& reporting_origin_string =
- FastGetAttribute(html_names::kReportingoriginAttr);
- reporting_origin =
- SecurityOrigin::CreateFromString(reporting_origin_string);
-
- if (!reporting_origin->IsPotentiallyTrustworthy())
- return base::nullopt;
- }
-
- // Impression expiry is an optional attribute.
- base::Optional<base::TimeDelta> expiry;
- if (hasAttribute(html_names::kImpressionexpiryAttr)) {
- bool expiry_is_valid = false;
- uint64_t expiry_milliseconds =
- FastGetAttribute(html_names::kImpressionexpiryAttr)
- .GetString()
- .ToUInt64Strict(&expiry_is_valid);
- if (expiry_is_valid)
- expiry = base::TimeDelta::FromMilliseconds(expiry_milliseconds);
- }
-
- UseCounter::Count(GetExecutionContext(),
- mojom::blink::WebFeature::kConversionAPIAll);
- UseCounter::Count(GetExecutionContext(),
- mojom::blink::WebFeature::kImpressionRegistration);
-
- return WebImpression{conversion_destination, reporting_origin,
- impression_data, expiry};
-}
-
void HTMLAnchorElement::SendPings(const KURL& destination_url) const {
const AtomicString& ping_value = FastGetAttribute(html_names::kPingAttr);
if (ping_value.IsNull() || !GetDocument().GetSettings() ||
@@ -551,12 +463,28 @@ void HTMLAnchorElement::HandleClick(Event& event) {
}
frame_request.SetTriggeringEventInfo(
- event.isTrusted() ? TriggeringEventInfo::kFromTrustedEvent
- : TriggeringEventInfo::kFromUntrustedEvent);
+ event.isTrusted()
+ ? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
+ : mojom::blink::TriggeringEventInfo::kFromUntrustedEvent);
frame_request.SetInputStartTime(event.PlatformTimeStamp());
frame->MaybeLogAdClickNavigation();
+ if (request.HasUserGesture() && HasImpression()) {
+ // An impression must be attached prior to the
+ // FindOrCreateFrameForNavigation() call, as that call may result in
+ // performing a navigation if the call results in creating a new window with
+ // noopener set.
+ // At this time we don't know if the navigation will navigate a main frame
+ // or subframe. For example, a middle click on the anchor element will
+ // set `target_frame` to `frame`, but end up targeting a new window.
+ // Attach the impression regardless, the embedder will be able to drop
+ // impressions for subframe navigations.
+ base::Optional<WebImpression> impression = GetImpressionForAnchor(this);
+ if (impression)
+ frame_request.SetImpression(*impression);
+ }
+
Frame* target_frame =
frame->Tree().FindOrCreateFrameForNavigation(frame_request, target).frame;
@@ -571,14 +499,6 @@ void HTMLAnchorElement::HandleClick(Event& event) {
WebFeature::kHTMLAnchorElementHrefTranslateAttribute);
}
- // Only attach impressions for main frame navigations.
- if (target_frame && target_frame->IsMainFrame() && request.HasUserGesture() &&
- HasImpression()) {
- base::Optional<WebImpression> impression = GetImpressionForNavigation();
- if (impression)
- frame_request.SetImpression(*impression);
- }
-
if (target_frame)
target_frame->Navigate(frame_request, WebFrameLoadType::kStandard);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_anchor_element.h b/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
index e1478ded441..6b1a47372f2 100644
--- a/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_anchor_element.h
@@ -101,11 +101,6 @@ class CORE_EXPORT HTMLAnchorElement : public HTMLElement, public DOMURLUtils {
// determined by looking at the presence of required attributes.
bool HasImpression() const;
- // Returns the WebImpression struct with all data declared by impression
- // related attributes on |this|. If the impression attributes do not contain
- // allowed values, base::nullopt is returned.
- base::Optional<WebImpression> GetImpressionForNavigation() const;
-
void SendPings(const KURL& destination_url) const;
void Trace(Visitor*) const override;
@@ -122,7 +117,6 @@ class CORE_EXPORT HTMLAnchorElement : public HTMLElement, public DOMURLUtils {
void DefaultEventHandler(Event&) final;
bool HasActivationBehavior() const override;
void SetActive(bool active) final;
- void AccessKeyAction(bool send_mouse_events) final;
bool IsURLAttribute(const Attribute&) const final;
bool HasLegalLinkAttribute(const QualifiedName&) const final;
bool CanStartSelection() const final;
diff --git a/chromium/third_party/blink/renderer/core/html/html_area_element.h b/chromium/third_party/blink/renderer/core/html/html_area_element.h
index b51388818d9..863d4899300 100644
--- a/chromium/third_party/blink/renderer/core/html/html_area_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_area_element.h
@@ -39,6 +39,7 @@ class CORE_EXPORT HTMLAreaElement final : public HTMLAnchorElement {
public:
explicit HTMLAreaElement(Document&);
+ ~HTMLAreaElement() override;
bool IsDefault() const { return shape_ == kDefault; }
@@ -58,8 +59,6 @@ class CORE_EXPORT HTMLAreaElement final : public HTMLAnchorElement {
HTMLImageElement* ImageElement() const;
private:
- ~HTMLAreaElement() override;
-
void ParseAttribute(const AttributeModificationParams&) override;
bool IsKeyboardFocusable() const override;
bool IsMouseFocusable() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5 b/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
index 7c7b7942aa3..c25150bece7 100644
--- a/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/chromium/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -19,6 +19,7 @@
"allowfullscreen",
"allowpaymentrequest",
"alt",
+ "anchor",
"archive",
"as",
"async",
@@ -292,6 +293,7 @@
"sandbox",
"scheme",
"scope",
+ "scopes",
"scrollamount",
"scrolldelay",
"scrolling",
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element.cc b/chromium/third_party/blink/renderer/core/html/html_content_element.cc
deleted file mode 100644
index de6e6c716d1..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_content_element.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/html_content_element.h"
-
-#include "third_party/blink/renderer/core/css/parser/css_parser.h"
-#include "third_party/blink/renderer/core/css/selector_checker.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/qualified_name.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-HTMLContentElement::HTMLContentElement(Document& document)
- : V0InsertionPoint(html_names::kContentTag, document),
- should_parse_select_(false),
- is_valid_selector_(true) {
- UseCounter::Count(document, WebFeature::kHTMLContentElement);
-}
-
-HTMLContentElement::~HTMLContentElement() = default;
-
-void HTMLContentElement::Trace(Visitor* visitor) const {
- V0InsertionPoint::Trace(visitor);
-}
-
-void HTMLContentElement::ParseSelect() {
- DCHECK(should_parse_select_);
-
- selector_list_ = CSSParser::ParseSelector(
- MakeGarbageCollected<CSSParserContext>(GetDocument()), nullptr, select_);
- should_parse_select_ = false;
- is_valid_selector_ = ValidateSelect();
- if (!is_valid_selector_)
- selector_list_ = CSSSelectorList();
-}
-
-void HTMLContentElement::ParseAttribute(
- const AttributeModificationParams& params) {
- if (params.name == html_names::kSelectAttr) {
- if (ShadowRoot* root = ContainingShadowRoot()) {
- if (!root->IsV1())
- root->V0().WillAffectSelector();
- }
- should_parse_select_ = true;
- select_ = params.new_value;
- } else {
- V0InsertionPoint::ParseAttribute(params);
- }
-}
-
-static inline bool IncludesDisallowedPseudoClass(const CSSSelector& selector) {
- if (selector.GetPseudoType() == CSSSelector::kPseudoNot) {
- const CSSSelector* sub_selector = selector.SelectorList()->First();
- return sub_selector->Match() == CSSSelector::kPseudoClass;
- }
- return selector.Match() == CSSSelector::kPseudoClass;
-}
-
-bool HTMLContentElement::ValidateSelect() const {
- DCHECK(!should_parse_select_);
-
- if (select_.IsNull() || select_.IsEmpty())
- return true;
-
- if (!selector_list_.IsValid())
- return false;
-
- for (const CSSSelector* selector = selector_list_.First(); selector;
- selector = selector_list_.Next(*selector)) {
- if (!selector->IsCompound())
- return false;
- for (const CSSSelector* sub_selector = selector; sub_selector;
- sub_selector = sub_selector->TagHistory()) {
- if (IncludesDisallowedPseudoClass(*sub_selector))
- return false;
- }
- }
- return true;
-}
-
-// TODO(esprehn): element should really be const, but matching a selector is not
-// const for some SelectorCheckingModes (mainly ResolvingStyle) where it sets
-// dynamic restyle flags on elements.
-bool HTMLContentElement::MatchSelector(Element& element) const {
- SelectorChecker::Init init;
- init.mode = SelectorChecker::kQueryingRules;
- SelectorChecker checker(init);
- SelectorChecker::SelectorCheckingContext context(&element);
- for (const CSSSelector* selector = SelectorList().First(); selector;
- selector = CSSSelectorList::Next(*selector)) {
- context.selector = selector;
- if (checker.Match(context))
- return true;
- }
- return false;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element.h b/chromium/third_party/blink/renderer/core/html/html_content_element.h
deleted file mode 100644
index e57deb6040c..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_content_element.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_CONTENT_ELEMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_CONTENT_ELEMENT_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/css_selector_list.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class CORE_EXPORT HTMLContentElement final : public V0InsertionPoint {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- HTMLContentElement(Document&);
- ~HTMLContentElement() override;
-
- bool CanAffectSelector() const override { return true; }
-
- bool CanSelectNode(const HeapVector<Member<Node>, 32>& siblings,
- int nth) const;
-
- const CSSSelectorList& SelectorList() const;
- bool IsSelectValid() const;
-
- void Trace(Visitor*) const override;
-
- private:
- void ParseAttribute(const AttributeModificationParams&) override;
-
- bool ValidateSelect() const;
- void ParseSelect();
-
- bool MatchSelector(Element&) const;
-
- bool should_parse_select_;
- bool is_valid_selector_;
- AtomicString select_;
- CSSSelectorList selector_list_;
-};
-
-inline const CSSSelectorList& HTMLContentElement::SelectorList() const {
- if (should_parse_select_)
- const_cast<HTMLContentElement*>(this)->ParseSelect();
- return selector_list_;
-}
-
-inline bool HTMLContentElement::IsSelectValid() const {
- if (should_parse_select_)
- const_cast<HTMLContentElement*>(this)->ParseSelect();
- return is_valid_selector_;
-}
-
-inline bool HTMLContentElement::CanSelectNode(
- const HeapVector<Member<Node>, 32>& siblings,
- int nth) const {
- if (select_.IsNull() || select_.IsEmpty())
- return true;
- if (!IsSelectValid())
- return false;
- auto* element = DynamicTo<Element>(siblings[nth].Get());
- if (!element)
- return false;
- return MatchSelector(*element);
-}
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_CONTENT_ELEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element.idl b/chromium/third_party/blink/renderer/core/html/html_content_element.idl
deleted file mode 100644
index 609d07a68ac..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_content_element.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- */
-
-// https://w3c.github.io/webcomponents/spec/shadow/#the-content-element
-
-[
- Exposed=Window
-] interface HTMLContentElement : HTMLElement {
- [Reflect] attribute DOMString select;
- NodeList getDistributedNodes();
-};
diff --git a/chromium/third_party/blink/renderer/core/html/html_content_element_test.cc b/chromium/third_party/blink/renderer/core/html/html_content_element_test.cc
deleted file mode 100644
index bbae3818cb4..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_content_element_test.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/html/html_content_element.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/css/style_engine.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/node_computed_style.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
-
-namespace blink {
-
-class HTMLContentElementTest : public testing::Test {
- protected:
- void SetUp() final {
- dummy_page_holder_ = std::make_unique<DummyPageHolder>(IntSize(800, 600));
- }
- Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
-
- private:
- std::unique_ptr<DummyPageHolder> dummy_page_holder_;
-};
-
-TEST_F(HTMLContentElementTest, FallbackRecalcForReattach) {
- GetDocument().body()->setInnerHTML(R"HTML(
- <div id='host'></div>
- )HTML");
-
- Element* host = GetDocument().getElementById("host");
- ShadowRoot& root = host->CreateV0ShadowRootForTesting();
- GetDocument().View()->UpdateAllLifecyclePhasesForTest();
-
- auto* content = GetDocument().CreateRawElement(html_names::kContentTag);
- auto* fallback = GetDocument().CreateRawElement(html_names::kSpanTag);
- content->AppendChild(fallback);
- root.AppendChild(content);
-
- GetDocument().UpdateDistributionForLegacyDistributedNodes();
- GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
- GetDocument().GetStyleEngine().RecalcStyle();
-
- EXPECT_TRUE(fallback->GetComputedStyle());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_details_element.cc b/chromium/third_party/blink/renderer/core/html/html_details_element.cc
index 42c8395ef86..43a31f0925f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_details_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_details_element.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h"
+#include "third_party/blink/renderer/core/html/html_style_element.h"
#include "third_party/blink/renderer/core/html/html_summary_element.h"
#include "third_party/blink/renderer/core/html/shadow/details_marker_control.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
@@ -95,6 +96,22 @@ void HTMLDetailsElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
content_slot->SetInlineStyleProperty(CSSPropertyID::kDisplay,
CSSValueID::kNone);
root.AppendChild(content_slot);
+
+ if (RuntimeEnabledFeatures::SummaryListItemEnabled()) {
+ auto* default_summary_style = MakeGarbageCollected<HTMLStyleElement>(
+ GetDocument(), CreateElementFlags::ByCreateElement());
+ default_summary_style->setTextContent(R"CSS(
+:host summary {
+ display: list-item;
+ counter-increment: list-item 0;
+ list-style: disclosure-closed inside;
+}
+:host([open]) summary {
+ list-style-type: disclosure-open;
+}
+)CSS");
+ root.AppendChild(default_summary_style);
+ }
}
Element* HTMLDetailsElement::FindMainSummary() const {
@@ -134,6 +151,8 @@ void HTMLDetailsElement::ParseAttribute(
CSSValueID::kNone);
}
+ if (RuntimeEnabledFeatures::SummaryListItemEnabled())
+ return;
// Invalidate the LayoutDetailsMarker in order to turn the arrow signifying
// if the details element is open or closed.
Element* summary = FindMainSummary();
diff --git a/chromium/third_party/blink/renderer/core/html/html_dialog_element.cc b/chromium/third_party/blink/renderer/core/html/html_dialog_element.cc
index 4c6a5edac63..3882308da82 100644
--- a/chromium/third_party/blink/renderer/core/html/html_dialog_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_dialog_element.cc
@@ -149,6 +149,9 @@ void HTMLDialogElement::show() {
return;
SetBooleanAttribute(html_names::kOpenAttr, true);
+ // Showing a <dialog> should hide all open popups.
+ GetDocument().HideAllPopupsUntil(nullptr);
+
// The layout must be updated here because setFocusForDialog calls
// Element::isFocusable, which requires an up-to-date layout.
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
@@ -176,6 +179,9 @@ void HTMLDialogElement::showModal(ExceptionState& exception_state) {
WebFeature::kShowModalForElementInFullscreenStack);
}
+ // Showing a <dialog> should hide all open popups.
+ GetDocument().HideAllPopupsUntil(nullptr);
+
GetDocument().AddToTopLayer(this);
SetBooleanAttribute(html_names::kOpenAttr, true);
@@ -192,27 +198,9 @@ void HTMLDialogElement::showModal(ExceptionState& exception_state) {
void HTMLDialogElement::RemovedFrom(ContainerNode& insertion_point) {
HTMLElement::RemovedFrom(insertion_point);
-
- // TODO(671907): Calling UpdateDistributionForFlatTreeTraversal here is a
- // workaround for https://crbug.com/895511. This shouldn't be done during DOM
- // mutation. However, Shadow DOM v0 will be removed, at which point this call
- // can be removed.
- GetDocument().UpdateDistributionForFlatTreeTraversal();
-
InertSubtreesChanged(GetDocument());
}
-bool HTMLDialogElement::IsPresentationAttribute(
- const QualifiedName& name) const {
- // FIXME: Workaround for <https://bugs.webkit.org/show_bug.cgi?id=91058>:
- // modifying an attribute for which there is an attribute selector in html.css
- // sometimes does not trigger a style recalc.
- if (name == html_names::kOpenAttr)
- return true;
-
- return HTMLElement::IsPresentationAttribute(name);
-}
-
void HTMLDialogElement::DefaultEventHandler(Event& event) {
if (event.type() == event_type_names::kCancel) {
close();
diff --git a/chromium/third_party/blink/renderer/core/html/html_dialog_element.h b/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
index 8e6c8d8f9e6..605672be06b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_dialog_element.h
@@ -33,7 +33,6 @@ namespace blink {
class Document;
class ExceptionState;
-class QualifiedName;
class HTMLDialogElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
@@ -54,7 +53,6 @@ class HTMLDialogElement final : public HTMLElement {
}
private:
- bool IsPresentationAttribute(const QualifiedName&) const override;
void DefaultEventHandler(Event&) override;
void SetIsModal(bool is_modal);
diff --git a/chromium/third_party/blink/renderer/core/html/html_document.cc b/chromium/third_party/blink/renderer/core/html/html_document.cc
index bc709a11c85..fd08b664927 100644
--- a/chromium/third_party/blink/renderer/core/html/html_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_document.cc
@@ -82,8 +82,7 @@ Document* HTMLDocument::CloneDocumentWithoutChildren() const {
return MakeGarbageCollected<HTMLDocument>(
DocumentInit::Create()
.WithExecutionContext(GetExecutionContext())
- .WithURL(Url())
- .WithRegistrationContext(RegistrationContext()));
+ .WithURL(Url()));
}
// --------------------------------------------------------------------------
diff --git a/chromium/third_party/blink/renderer/core/html/html_element.cc b/chromium/third_party/blink/renderer/core/html/html_element.cc
index 47525bc3abe..af8ff43e6bf 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_element.cc
@@ -42,11 +42,14 @@
#include "third_party/blink/renderer/core/dom/element_rare_data.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/dom/slot_assignment.h"
+#include "third_party/blink/renderer/core/dom/slot_assignment_recalc_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
@@ -67,6 +70,7 @@
#include "third_party/blink/renderer/core/html/html_dimension.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/html/html_template_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
@@ -140,6 +144,36 @@ bool IsEditable(const Node& node) {
const WebFeature kNoWebFeature = static_cast<WebFeature>(0);
+HTMLElement* GetParentForDirectionality(HTMLElement* element,
+ bool& needs_slot_assignment_recalc) {
+ if (element->IsPseudoElement())
+ return DynamicTo<HTMLElement>(element->ParentOrShadowHostNode());
+
+ if (element->IsChildOfShadowHost()) {
+ ShadowRoot* root = element->ShadowRootOfParent();
+ if (!root || !root->HasSlotAssignment())
+ return nullptr;
+
+ if (root->NeedsSlotAssignmentRecalc()) {
+ needs_slot_assignment_recalc = true;
+ return nullptr;
+ }
+ }
+ if (auto* parent_slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(
+ element->parentElement())) {
+ ShadowRoot* root = parent_slot->ContainingShadowRoot();
+ if (root->NeedsSlotAssignmentRecalc()) {
+ needs_slot_assignment_recalc = true;
+ return nullptr;
+ }
+ }
+
+ // We should take care of all cases that would trigger a slot assignment
+ // recalc, and delay the check for later for a performance reason.
+ SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(element->GetDocument());
+ return DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*element));
+}
+
} // anonymous namespace
String HTMLElement::DebugNodeName() const {
@@ -711,6 +745,11 @@ void HTMLElement::AttributeChanged(const AttributeModificationParams& params) {
if (params.name == html_names::kHiddenAttr && !params.new_value.IsNull()) {
if (AdjustedFocusedElementInTreeScope() == this)
blur();
+ } else if (params.name == html_names::kSpellcheckAttr) {
+ if (GetDocument().GetFrame()) {
+ GetDocument().GetFrame()->GetSpellChecker().RespondToChangedEnablement(
+ *this, IsSpellCheckingEnabled());
+ }
} else if (params.name == html_names::kContenteditableAttr) {
if (GetDocument().GetFrame()) {
GetDocument()
@@ -1037,13 +1076,11 @@ void HTMLElement::setSpellcheck(bool enable) {
}
void HTMLElement::click() {
- DispatchSimulatedClick(nullptr, kSendNoEvents,
- SimulatedClickCreationScope::kFromScript);
+ DispatchSimulatedClick(nullptr, SimulatedClickCreationScope::kFromScript);
}
-void HTMLElement::AccessKeyAction(bool send_mouse_events) {
- DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+void HTMLElement::AccessKeyAction(SimulatedClickCreationScope creation_scope) {
+ DispatchSimulatedClick(nullptr, creation_scope);
}
String HTMLElement::title() const {
@@ -1122,12 +1159,23 @@ HTMLFormElement* HTMLElement::FindFormAncestor() const {
static inline bool ElementAffectsDirectionality(const Node* node) {
auto* html_element = DynamicTo<HTMLElement>(node);
return html_element && (IsA<HTMLBDIElement>(*html_element) ||
- html_element->FastHasAttribute(html_names::kDirAttr));
+ IsValidDirAttribute(html_element->FastGetAttribute(
+ html_names::kDirAttr)));
}
void HTMLElement::ChildrenChanged(const ChildrenChange& change) {
Element::ChildrenChanged(change);
- AdjustDirectionalityIfNeededAfterChildrenChanged(change);
+
+ if (GetDocument().IsDirAttributeDirty()) {
+ AdjustDirectionalityIfNeededAfterChildrenChanged(change);
+
+ if (change.IsChildInsertion() && !SelfOrAncestorHasDirAutoAttribute()) {
+ auto* element = DynamicTo<HTMLElement>(change.sibling_changed);
+ if (element && !element->NeedsInheritDirectionalityFromParent() &&
+ !ElementAffectsDirectionality(element))
+ element->UpdateDirectionalityAndDescendant(CachedDirectionality());
+ }
+ }
}
bool HTMLElement::HasDirectionAuto() const {
@@ -1138,20 +1186,13 @@ bool HTMLElement::HasDirectionAuto() const {
EqualIgnoringASCIICase(direction, "auto");
}
-TextDirection HTMLElement::DirectionalityIfhasDirAutoAttribute(
- bool& is_auto) const {
- is_auto = HasDirectionAuto();
- if (!is_auto)
- return TextDirection::kLtr;
- return Directionality();
-}
-
-TextDirection HTMLElement::Directionality() const {
+TextDirection HTMLElement::ResolveAutoDirectionality(bool& is_deferred,
+ Node* stay_within) const {
+ is_deferred = false;
if (auto* input_element = DynamicTo<HTMLInputElement>(*this)) {
bool has_strong_directionality;
- TextDirection text_direction = DetermineDirectionality(
- input_element->value(), &has_strong_directionality);
- return text_direction;
+ return DetermineDirectionality(input_element->value(),
+ &has_strong_directionality);
}
Node* node = FlatTreeTraversal::FirstChild(*this);
@@ -1163,16 +1204,28 @@ TextDirection HTMLElement::Directionality() const {
(element && element->IsTextControl()) ||
(element && element->ShadowPseudoId() ==
shadow_element_names::kPseudoInputPlaceholder)) {
- node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ node = FlatTreeTraversal::NextSkippingChildren(*node, stay_within);
continue;
}
+ if (auto* slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(node)) {
+ ShadowRoot* root = slot->ContainingShadowRoot();
+ // Defer to adjust the directionality to avoid recalcuating slot
+ // assignment in FlatTreeTraversal when updating slot.
+ // ResolveAutoDirectionality will be adjusted after recalculating its
+ // children.
+ if (root->NeedsSlotAssignmentRecalc()) {
+ is_deferred = true;
+ return TextDirection::kLtr;
+ }
+ }
+
// Skip elements with valid dir attribute
if (auto* element_node = DynamicTo<Element>(node)) {
AtomicString dir_attribute_value =
element_node->FastGetAttribute(html_names::kDirAttr);
if (IsValidDirAttribute(dir_attribute_value)) {
- node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ node = FlatTreeTraversal::NextSkippingChildren(*node, stay_within);
continue;
}
}
@@ -1184,46 +1237,55 @@ TextDirection HTMLElement::Directionality() const {
if (has_strong_directionality)
return text_direction;
}
- node = FlatTreeTraversal::Next(*node, this);
+ node = FlatTreeTraversal::Next(*node, stay_within);
}
return TextDirection::kLtr;
}
-bool HTMLElement::SelfOrAncestorHasDirAutoAttribute() const {
- // TODO(esprehn): Storing this state in the computed style is bad, we
- // should be able to answer questions about the shape of the DOM and the
- // text contained inside it without having style.
- if (const ComputedStyle* style = GetComputedStyle())
- return style->SelfOrAncestorHasDirAutoAttribute();
- return false;
-}
-
void HTMLElement::AdjustDirectionalityIfNeededAfterChildAttributeChanged(
Element* child) {
DCHECK(SelfOrAncestorHasDirAutoAttribute());
- const ComputedStyle* style = GetComputedStyle();
- if (style && style->Direction() != Directionality()) {
+ bool is_deferred;
+ TextDirection text_direction = ResolveAutoDirectionality(is_deferred, this);
+ if (CachedDirectionality() != text_direction && !is_deferred) {
+ SetCachedDirectionality(text_direction);
+
for (Element* element_to_adjust = this; element_to_adjust;
element_to_adjust =
FlatTreeTraversal::ParentElement(*element_to_adjust)) {
if (ElementAffectsDirectionality(element_to_adjust)) {
- element_to_adjust->SetNeedsStyleRecalc(
- kLocalStyleChange, StyleChangeReasonForTracing::Create(
- style_change_reason::kWritingModeChange));
+ DynamicTo<HTMLElement>(element_to_adjust)
+ ->UpdateDirectionalityAndDescendant(text_direction);
+
+ const ComputedStyle* style = GetComputedStyle();
+ if (style && style->Direction() != text_direction) {
+ element_to_adjust->SetNeedsStyleRecalc(
+ kLocalStyleChange, StyleChangeReasonForTracing::Create(
+ style_change_reason::kWritingModeChange));
+ }
return;
}
}
}
}
-void HTMLElement::CalculateAndAdjustDirectionality() {
- TextDirection text_direction = Directionality();
- const ComputedStyle* style = GetComputedStyle();
- if (style && style->Direction() != text_direction) {
- SetNeedsStyleRecalc(kLocalStyleChange,
- StyleChangeReasonForTracing::Create(
- style_change_reason::kWritingModeChange));
+bool HTMLElement::CalculateAndAdjustAutoDirectionality(Node* stay_within) {
+ bool is_deferred = false;
+ TextDirection text_direction =
+ ResolveAutoDirectionality(is_deferred, stay_within);
+ if (CachedDirectionality() != text_direction && !is_deferred) {
+ UpdateDirectionalityAndDescendant(text_direction);
+
+ const ComputedStyle* style = GetComputedStyle();
+ if (style && style->Direction() != text_direction) {
+ SetNeedsStyleRecalc(kLocalStyleChange,
+ StyleChangeReasonForTracing::Create(
+ style_change_reason::kWritingModeChange));
+ return true;
+ }
}
+
+ return false;
}
void HTMLElement::AdjustDirectionalityIfNeededAfterChildrenChanged(
@@ -1231,18 +1293,95 @@ void HTMLElement::AdjustDirectionalityIfNeededAfterChildrenChanged(
if (!SelfOrAncestorHasDirAutoAttribute())
return;
- UpdateDistributionForFlatTreeTraversal();
+ Node* stay_within = nullptr;
+ bool has_strong_directionality;
+ if (change.type == ChildrenChangeType::kTextChanged) {
+ TextDirection old_text_direction =
+ DetermineDirectionality(change.old_text, &has_strong_directionality);
+ auto* character_data = DynamicTo<CharacterData>(change.sibling_changed);
+ DCHECK(character_data);
+ TextDirection new_text_direction = DetermineDirectionality(
+ character_data->data(), &has_strong_directionality);
+ if (old_text_direction == new_text_direction)
+ return;
+ stay_within = change.sibling_changed;
+ } else if (change.IsChildInsertion()) {
+ if (change.sibling_changed->IsTextNode()) {
+ TextDirection new_text_direction =
+ DetermineDirectionality(change.sibling_changed->textContent(true),
+ &has_strong_directionality);
+ if (!has_strong_directionality ||
+ new_text_direction == CachedDirectionality())
+ return;
+ }
+ stay_within = change.sibling_changed;
+ }
+
+ UpdateDescendantHasDirAutoAttribute(true /* has_dir_auto */);
for (Element* element_to_adjust = this; element_to_adjust;
element_to_adjust =
FlatTreeTraversal::ParentElement(*element_to_adjust)) {
if (ElementAffectsDirectionality(element_to_adjust)) {
- To<HTMLElement>(element_to_adjust)->CalculateAndAdjustDirectionality();
+ if (To<HTMLElement>(element_to_adjust)
+ ->CalculateAndAdjustAutoDirectionality(
+ stay_within ? stay_within : element_to_adjust)) {
+ SetNeedsStyleRecalc(kLocalStyleChange,
+ StyleChangeReasonForTracing::Create(
+ style_change_reason::kPseudoClass));
+ }
+ if (RuntimeEnabledFeatures::CSSPseudoDirEnabled())
+ element_to_adjust->PseudoStateChanged(CSSSelector::kPseudoDir);
return;
}
}
}
+void HTMLElement::AdjustCandidateDirectionalityForSlot(
+ HeapHashSet<Member<HTMLElement>> candidate_set) {
+ HeapHashSet<Member<HTMLElement>> directionality_set;
+ // Transfer a candidate directionality set to |directionality_set| to avoid
+ // the tree walk to the duplicated parent node for the directionality.
+ for (auto& element : candidate_set) {
+ if (!element->SelfOrAncestorHasDirAutoAttribute()) {
+ auto* parent =
+ DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*element));
+ if (parent && !parent->NeedsInheritDirectionalityFromParent() &&
+ element->NeedsInheritDirectionalityFromParent()) {
+ element->UpdateDirectionalityAndDescendant(
+ parent->CachedDirectionality());
+ }
+ continue;
+ }
+
+ for (auto* element_to_adjust = element.Get(); element_to_adjust;
+ element_to_adjust = DynamicTo<HTMLElement>(
+ FlatTreeTraversal::ParentElement(*element_to_adjust))) {
+ if (ElementAffectsDirectionality(element_to_adjust)) {
+ directionality_set.insert(element_to_adjust);
+ continue;
+ }
+ }
+ }
+
+ for (auto& element : directionality_set) {
+ if (element->CalculateAndAdjustAutoDirectionality(element) &&
+ RuntimeEnabledFeatures::CSSPseudoDirEnabled()) {
+ element->SetNeedsStyleRecalc(kLocalStyleChange,
+ StyleChangeReasonForTracing::Create(
+ style_change_reason::kPseudoClass));
+ }
+ }
+}
+
+void HTMLElement::AddCandidateDirectionalityForSlot() {
+ ShadowRoot* root = ShadowRootOfParent();
+ if (!root || !root->HasSlotAssignment())
+ return;
+
+ root->GetSlotAssignment().GetCandidateDirectionality().insert(this);
+}
+
Node::InsertionNotificationRequest HTMLElement::InsertedInto(
ContainerNode& insertion_point) {
// Process the superclass first to ensure that `InActiveDocument()` is
@@ -1569,20 +1708,125 @@ Element* HTMLElement::unclosedOffsetParent() {
return layout_object->OffsetParent(this);
}
+void HTMLElement::UpdateDescendantHasDirAutoAttribute(bool has_dir_auto) {
+ Node* node = FlatTreeTraversal::FirstChild(*this);
+ while (node) {
+ if (auto* element = DynamicTo<Element>(node)) {
+ AtomicString dir_attribute_value =
+ element->FastGetAttribute(html_names::kDirAttr);
+ if (IsValidDirAttribute(dir_attribute_value)) {
+ node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ continue;
+ }
+
+ if (auto* slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(node)) {
+ ShadowRoot* root = slot->ContainingShadowRoot();
+ // Defer to adjust the directionality to avoid recalcuating slot
+ // assignment in FlatTreeTraversal when updating slot.
+ // Slot and its children will be updated after recalculating children.
+ if (root->NeedsSlotAssignmentRecalc()) {
+ root->SetNeedsDirAutoAttributeUpdate(true);
+ node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ continue;
+ }
+ }
+
+ if (!has_dir_auto) {
+ if (!element->SelfOrAncestorHasDirAutoAttribute()) {
+ node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ continue;
+ }
+ element->ClearSelfOrAncestorHasDirAutoAttribute();
+ } else {
+ if (element->SelfOrAncestorHasDirAutoAttribute()) {
+ node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ continue;
+ }
+ element->SetSelfOrAncestorHasDirAutoAttribute();
+ }
+ }
+ node = FlatTreeTraversal::Next(*node, this);
+ }
+}
+
+void HTMLElement::UpdateDirectionalityAndDescendant(TextDirection direction) {
+ SetCachedDirectionality(direction);
+ UpdateDescendantDirectionality(direction);
+}
+
+void HTMLElement::UpdateDescendantDirectionality(TextDirection direction) {
+ Node* node = FlatTreeTraversal::FirstChild(*this);
+ while (node) {
+ if (IsA<HTMLElement>(node)) {
+ if (ElementAffectsDirectionality(node) ||
+ node->CachedDirectionality() == direction) {
+ node = FlatTreeTraversal::NextSkippingChildren(*node, this);
+ continue;
+ }
+ node->SetCachedDirectionality(direction);
+ }
+ node = FlatTreeTraversal::Next(*node, this);
+ }
+}
+
void HTMLElement::OnDirAttrChanged(const AttributeModificationParams& params) {
// If an ancestor has dir=auto, and this node has the first character,
// changes to dir attribute may affect the ancestor.
- if (!CanParticipateInFlatTree())
+ if (!IsValidDirAttribute(params.old_value) &&
+ !IsValidDirAttribute(params.new_value))
return;
- UpdateDistributionForFlatTreeTraversal();
- auto* parent =
- DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*this));
- if (parent && parent->SelfOrAncestorHasDirAutoAttribute()) {
- parent->AdjustDirectionalityIfNeededAfterChildAttributeChanged(this);
+
+ GetDocument().SetDirAttributeDirty();
+
+ bool is_old_auto = SelfOrAncestorHasDirAutoAttribute();
+ bool is_new_auto = HasDirectionAuto();
+ bool needs_slot_assignment_recalc = false;
+ auto* parent = GetParentForDirectionality(this, needs_slot_assignment_recalc);
+ if (!is_old_auto || !is_new_auto) {
+ if (parent && parent->SelfOrAncestorHasDirAutoAttribute()) {
+ parent->AdjustDirectionalityIfNeededAfterChildAttributeChanged(this);
+ }
+ }
+
+ if (is_old_auto && !is_new_auto) {
+ ClearSelfOrAncestorHasDirAutoAttribute();
+ UpdateDescendantHasDirAutoAttribute(false /* has_dir_auto */);
+ } else if (!is_old_auto && is_new_auto) {
+ SetSelfOrAncestorHasDirAutoAttribute();
+ UpdateDescendantHasDirAutoAttribute(true /* has_dir_auto */);
+ }
+
+ if (is_new_auto) {
+ CalculateAndAdjustAutoDirectionality(this);
+ } else {
+ base::Optional<TextDirection> text_direction;
+ if (EqualIgnoringASCIICase(params.new_value, "ltr")) {
+ text_direction = TextDirection::kLtr;
+ } else if (EqualIgnoringASCIICase(params.new_value, "rtl")) {
+ text_direction = TextDirection::kRtl;
+ }
+
+ if (!text_direction.has_value()) {
+ if (parent) {
+ text_direction = parent->CachedDirectionality();
+ } else {
+ text_direction = TextDirection::kLtr;
+ }
+ }
+
+ if (needs_slot_assignment_recalc) {
+ SetNeedsInheritDirectionalityFromParent();
+ } else {
+ UpdateDirectionalityAndDescendant(*text_direction);
+ }
}
- if (EqualIgnoringASCIICase(params.new_value, "auto"))
- CalculateAndAdjustDirectionality();
+ if (RuntimeEnabledFeatures::CSSPseudoDirEnabled()) {
+ SetNeedsStyleRecalc(
+ kSubtreeStyleChange,
+ StyleChangeReasonForTracing::Create(style_change_reason::kPseudoClass));
+ PseudoStateChanged(CSSSelector::kPseudoDir);
+ }
}
void HTMLElement::OnFormAttrChanged(const AttributeModificationParams& params) {
@@ -1729,6 +1973,24 @@ void HTMLElement::FinishParsingChildren() {
EnsureElementInternals().TakeStateAndRestore();
}
+void HTMLElement::BeginParsingChildren() {
+ Element::BeginParsingChildren();
+
+ if (GetDocument().IsDirAttributeDirty()) {
+ if (HasDirectionAuto()) {
+ SetSelfOrAncestorHasDirAutoAttribute();
+ } else if (!ElementAffectsDirectionality(this)) {
+ bool needs_slot_assignment_recalc = false;
+ auto* parent =
+ GetParentForDirectionality(this, needs_slot_assignment_recalc);
+ if (needs_slot_assignment_recalc)
+ SetNeedsInheritDirectionalityFromParent();
+ else if (parent)
+ SetCachedDirectionality(parent->CachedDirectionality());
+ }
+ }
+}
+
} // namespace blink
#ifndef NDEBUG
diff --git a/chromium/third_party/blink/renderer/core/html/html_element.h b/chromium/third_party/blink/renderer/core/html/html_element.h
index 67e9e66e02f..fd1d50bcdfe 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_element.h
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/labels_node_list.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -96,7 +97,7 @@ class CORE_EXPORT HTMLElement : public Element {
void click();
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
bool ShouldSerializeEndTag() const;
@@ -105,7 +106,6 @@ class CORE_EXPORT HTMLElement : public Element {
HTMLFormElement* FindFormAncestor() const;
bool HasDirectionAuto() const;
- TextDirection DirectionalityIfhasDirAutoAttribute(bool& is_auto) const;
virtual bool IsHTMLBodyElement() const { return false; }
virtual bool IsHTMLFrameSetElement() const { return false; }
@@ -153,6 +153,14 @@ class CORE_EXPORT HTMLElement : public Element {
virtual FormAssociated* ToFormAssociatedOrNull() { return nullptr; }
bool IsFormAssociatedCustomElement() const;
+ void AddCandidateDirectionalityForSlot();
+ static void AdjustCandidateDirectionalityForSlot(
+ HeapHashSet<Member<HTMLElement>> candidate_set);
+ void UpdateDescendantHasDirAutoAttribute(bool has_dir_auto);
+ void UpdateDirectionalityAndDescendant(TextDirection direction);
+ void UpdateDescendantDirectionality(TextDirection direction);
+ void BeginParsingChildren() override;
+
protected:
enum AllowPercentage { kDontAllowPercentageValues, kAllowPercentageValues };
enum AllowZero { kDontAllowZeroValues, kAllowZeroValues };
@@ -185,7 +193,7 @@ class CORE_EXPORT HTMLElement : public Element {
unsigned ParseBorderWidthAttribute(const AtomicString&) const;
void ChildrenChanged(const ChildrenChange&) override;
- void CalculateAndAdjustDirectionality();
+ bool CalculateAndAdjustAutoDirectionality(Node* stay_within);
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode& insertion_point) override;
@@ -206,10 +214,11 @@ class CORE_EXPORT HTMLElement : public Element {
DocumentFragment* TextToFragment(const String&, ExceptionState&);
- bool SelfOrAncestorHasDirAutoAttribute() const;
void AdjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child);
- void AdjustDirectionalityIfNeededAfterChildrenChanged(const ChildrenChange&);
- TextDirection Directionality() const;
+ void AdjustDirectionalityIfNeededAfterChildrenChanged(
+ const ChildrenChange& change);
+ TextDirection ResolveAutoDirectionality(bool& is_deferred,
+ Node* stay_within) const;
TranslateAttributeMode GetTranslateAttributeMode() const;
diff --git a/chromium/third_party/blink/renderer/core/html/html_element.idl b/chromium/third_party/blink/renderer/core/html/html_element.idl
index 4f751fec935..d231c479383 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_element.idl
@@ -34,7 +34,7 @@
[RuntimeCallStatsCounter=HTMLElementClick] void click();
[CEReactions, RuntimeEnabled=InertAttribute, Reflect] attribute boolean inert;
[CEReactions, Reflect] attribute DOMString accessKey;
- [CEReactions, CustomElementCallbacks] attribute boolean draggable;
+ [CEReactions] attribute boolean draggable;
[CEReactions] attribute boolean spellcheck;
[Measure] attribute DOMString autocapitalize;
@@ -42,7 +42,7 @@
// HTMLElement includes ElementContentEditable
// https://html.spec.whatwg.org/C/#contenteditable
- [CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute DOMString contentEditable;
+ [CEReactions, RaisesException=Setter] attribute DOMString contentEditable;
[RuntimeEnabled=EnterKeyHintAttribute, CEReactions, Reflect, ReflectOnly=("enter","done","go","next","previous","search","send")] attribute DOMString enterKeyHint;
[ImplementedAs=isContentEditableForBinding] readonly attribute boolean isContentEditable;
[CEReactions, Reflect, ReflectOnly=("none","text","tel","url","email","numeric","decimal","search")] attribute DOMString inputMode;
@@ -65,8 +65,8 @@
[Affects=Nothing, SameObject, PerWorldBindings, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
// Non-standard APIs
- [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementInnerText] attribute ([TreatNullAs=EmptyString] DOMString or TrustedScript) innerText;
- [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementOuterText] attribute [TreatNullAs=EmptyString] DOMString outerText;
+ [Affects=Nothing, CEReactions, RaisesException=Setter, MeasureAs=HTMLElementInnerText] attribute ([TreatNullAs=EmptyString] DOMString or TrustedScript) innerText;
+ [Affects=Nothing, CEReactions, RaisesException=Setter, MeasureAs=HTMLElementOuterText] attribute [TreatNullAs=EmptyString] DOMString outerText;
};
HTMLElement includes GlobalEventHandlers;
diff --git a/chromium/third_party/blink/renderer/core/html/html_element_test.cc b/chromium/third_party/blink/renderer/core/html/html_element_test.cc
index a0f5c3cd5a0..b1552b3b260 100644
--- a/chromium/third_party/blink/renderer/core/html/html_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_element_test.cc
@@ -5,8 +5,10 @@
#include "third_party/blink/renderer/core/html/html_element.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
@@ -246,4 +248,18 @@ TEST_F(HTMLElementTest,
GetDocument().GetPage()->Animator().has_inline_style_mutation_for_test());
}
+TEST_F(HTMLElementTest, DirAutoByChildChanged) {
+ ScopedCSSPseudoDirForTest scoped_feature(false);
+
+ SetBodyInnerHTML("<div id='target' dir='auto'></div>");
+ auto* element = GetDocument().getElementById("target");
+ element->setTextContent(u"\u05D1");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(element->GetComputedStyle()->Direction(), TextDirection::kRtl);
+
+ element->RemoveChildren();
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(element->GetComputedStyle()->Direction(), TextDirection::kLtr);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_embed_element.cc b/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
index 0ea3c6f5107..35bc484d9c6 100644
--- a/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_embed_element.cc
@@ -126,6 +126,9 @@ void HTMLEmbedElement::ParseAttribute(
if (FastHasAttribute(html_names::kTypeAttr)) {
SetNeedsPluginUpdate(true);
ReattachOnPluginChangeIfNeeded();
+ } else {
+ UseCounter::Count(GetDocument(),
+ WebFeature::kEmbedElementWithoutTypeSrcChanged);
}
}
} else {
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 59fe1414910..cc54e54db47 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -20,7 +20,6 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
-#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
@@ -31,6 +30,7 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/events/current_input_event.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -54,6 +54,7 @@
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -84,7 +85,7 @@ bool DoesParentAllowLazyLoadingChildren(Document& document) {
return containing_frame_owner->ShouldLazyLoadChildren();
}
-bool IsFrameLazyLoadable(const ExecutionContext* context,
+bool IsFrameLazyLoadable(ExecutionContext* context,
const KURL& url,
bool is_loading_attr_lazy,
bool should_lazy_load_children) {
@@ -99,6 +100,11 @@ bool IsFrameLazyLoadable(const ExecutionContext* context,
if (!url.ProtocolIsInHTTPFamily())
return false;
+ // Do not lazyload frames when JavaScript is disabled, regardless of the
+ // `loading` attribute.
+ if (!context->CanExecuteScripts(kNotAboutToExecuteScript))
+ return false;
+
if (is_loading_attr_lazy)
return true;
@@ -198,6 +204,12 @@ void HTMLFrameOwnerElement::SetContentFrame(Frame& frame) {
DCHECK(!lazy_load_frame_observer_ ||
!lazy_load_frame_observer_->IsLazyLoadPending());
+ DCHECK_NE(content_frame_, &frame);
+ auto* resource_coordinator = RendererResourceCoordinator::Get();
+ if (content_frame_)
+ resource_coordinator->OnBeforeContentFrameDetached(*content_frame_, *this);
+ resource_coordinator->OnBeforeContentFrameAttached(frame, *this);
+
content_frame_ = &frame;
// Invalidate compositing inputs, because a remote frame child can cause the
@@ -226,6 +238,9 @@ void HTMLFrameOwnerElement::ClearContentFrame() {
CancelPendingLazyLoad();
DCHECK_EQ(content_frame_->Owner(), this);
+ RendererResourceCoordinator::Get()->OnBeforeContentFrameDetached(
+ *content_frame_, *this);
+
content_frame_ = nullptr;
for (ContainerNode* node = this; node; node = node->ParentOrShadowHostNode())
@@ -385,9 +400,6 @@ void HTMLFrameOwnerElement::FrameOwnerPropertiesChanged() {
}
void HTMLFrameOwnerElement::CSPAttributeChanged() {
- if (!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE))
- return;
-
// Don't notify about updates if ContentFrame() is null, for example when
// the subframe hasn't been created yet; or if we are in the middle of
// swapping one frame for another, in which case the final state
@@ -397,8 +409,14 @@ void HTMLFrameOwnerElement::CSPAttributeChanged() {
String fake_header =
"HTTP/1.1 200 OK\nContent-Security-Policy: " + RequiredCsp();
+ // ParseHeaders needs a url to resolve report endpoints and for matching the
+ // keyword 'self'. However, the csp attribute does not allow report
+ // endpoints. Moreover, in the csp attribute, 'self' should not match the
+ // owner's url, but rather the frame src url. This is taken care by the
+ // Content-Security-Policy Embedded Enforcement algorithm, implemented in the
+ // AncestorThrottle. That's why we pass an empty url here.
network::mojom::blink::ParsedHeadersPtr parsed_headers =
- ParseHeaders(fake_header, GetDocument().Url());
+ ParseHeaders(fake_header, KURL());
DCHECK_LE(parsed_headers->content_security_policy.size(), 1u);
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
index 158a4bcf59c..eda50e4275a 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -74,7 +74,7 @@ class CORE_EXPORT HTMLFrameOwnerElement : public HTMLElement,
return embedded_content_view_;
}
- void SetColorScheme(mojom::ColorScheme);
+ void SetColorScheme(mojom::blink::ColorScheme);
class PluginDisposeSuspendScope {
STACK_ALLOCATED();
@@ -118,7 +118,7 @@ class CORE_EXPORT HTMLFrameOwnerElement : public HTMLElement,
bool AllowFullscreen() const override { return false; }
bool AllowPaymentRequest() const override { return false; }
bool IsDisplayNone() const override { return !embedded_content_view_; }
- mojom::ColorScheme GetColorScheme() const override;
+ mojom::blink::ColorScheme GetColorScheme() const override;
AtomicString RequiredCsp() const override { return g_null_atom; }
bool ShouldLazyLoadChildren() const final;
@@ -138,9 +138,6 @@ class CORE_EXPORT HTMLFrameOwnerElement : public HTMLElement,
HTMLFrameOwnerElement(const QualifiedName& tag_name, Document&);
void SetSandboxFlags(network::mojom::blink::WebSandboxFlags);
- void SetAllowedToDownload(bool allowed) {
- frame_policy_.allowed_to_download = allowed;
- }
void SetDisallowDocumentAccesss(bool disallowed);
bool LoadOrRedirectSubframe(const KURL&,
diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
index bf337b75fd2..9017e5ff468 100644
--- a/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -262,7 +262,7 @@ void HTMLFrameSetElement::DefaultEventHandler(Event& evt) {
auto* mouse_event = DynamicTo<MouseEvent>(evt);
if (mouse_event && !noresize_ && GetLayoutObject() &&
GetLayoutObject()->IsFrameSet()) {
- if (ToLayoutFrameSet(GetLayoutObject())->UserResize(*mouse_event)) {
+ if (To<LayoutFrameSet>(GetLayoutObject())->UserResize(*mouse_event)) {
evt.SetDefaultHandled();
return;
}
@@ -281,8 +281,13 @@ Node::InsertionNotificationRequest HTMLFrameSetElement::InsertedInto(
}
void HTMLFrameSetElement::WillRecalcStyle(const StyleRecalcChange) {
if (NeedsStyleRecalc() && GetLayoutObject()) {
- GetLayoutObject()->SetNeedsLayoutAndFullPaintInvalidation(
- layout_invalidation_reason::kStyleChange);
+ if (GetForceReattachLayoutTree()) {
+ // Adding a frameset to the top layer for fullscreen forces a reattach.
+ SetNeedsReattachLayoutTree();
+ } else {
+ GetLayoutObject()->SetNeedsLayoutAndFullPaintInvalidation(
+ layout_invalidation_reason::kStyleChange);
+ }
ClearNeedsStyleRecalc();
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc b/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
index a36767291bc..5b800502911 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -39,8 +39,6 @@
#include "third_party/blink/renderer/core/feature_policy/iframe_policy.h"
#include "third_party/blink/renderer/core/fetch/trust_token_issuance_authorization.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
-#include "third_party/blink/renderer/core/frame/deprecation.h"
-#include "third_party/blink/renderer/core/frame/sandbox_flags.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/trust_token_attribute_parsing.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -154,8 +152,6 @@ void HTMLIFrameElement::ParseAttribute(
FrameOwnerPropertiesChanged();
} else if (name == html_names::kSandboxAttr) {
sandbox_->DidUpdateAttributeValue(params.old_value, value);
- bool feature_policy_for_sandbox =
- RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled();
network::mojom::blink::WebSandboxFlags current_flags =
network::mojom::blink::WebSandboxFlags::kNone;
@@ -178,29 +174,7 @@ void HTMLIFrameElement::ParseAttribute(
parsed.error_message)));
}
}
- SetAllowedToDownload(
- (current_flags & network::mojom::blink::WebSandboxFlags::kDownloads) ==
- network::mojom::blink::WebSandboxFlags::kNone);
- // With FeaturePolicyForSandbox, sandbox flags are represented as part of
- // the container policies. However, not all sandbox flags are yet converted
- // and for now the residue will stay around in the stored flags.
- // (see https://crbug.com/812381).
- network::mojom::blink::WebSandboxFlags sandbox_to_set = current_flags;
- sandbox_flags_converted_to_feature_policies_ =
- network::mojom::blink::WebSandboxFlags::kNone;
- if (feature_policy_for_sandbox &&
- current_flags != network::mojom::blink::WebSandboxFlags::kNone) {
- // Residue sandbox which will not be mapped to feature policies.
- sandbox_to_set =
- GetSandboxFlagsNotImplementedAsFeaturePolicy(current_flags);
- // The part of sandbox which will be mapped to feature policies.
- sandbox_flags_converted_to_feature_policies_ =
- current_flags & ~sandbox_to_set;
- }
- SetSandboxFlags(sandbox_to_set);
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled())
- UpdateContainerPolicy();
-
+ SetSandboxFlags(current_flags);
UseCounter::Count(GetDocument(), WebFeature::kSandboxViaIFrame);
} else if (name == html_names::kReferrerpolicyAttr) {
referrer_policy_ = network::mojom::ReferrerPolicy::kDefault;
@@ -233,35 +207,19 @@ void HTMLIFrameElement::ParseAttribute(
UpdateContainerPolicy();
}
} else if (name == html_names::kCspAttr) {
- if (base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE)) {
- if (value.Contains('\n') || value.Contains('\r') || value.Contains(',')) {
- required_csp_ = g_null_atom;
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kOther,
- mojom::blink::ConsoleMessageLevel::kError,
- "'csp' attribute is invalid: " + value));
- return;
- }
- if (required_csp_ != value) {
- required_csp_ = value;
- CSPAttributeChanged();
- UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute);
- }
- } else {
- if (!ContentSecurityPolicy::IsValidCSPAttr(
- value.GetString(), GetDocument().RequiredCSP().GetString())) {
- required_csp_ = g_null_atom;
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kOther,
- mojom::blink::ConsoleMessageLevel::kError,
- "'csp' attribute is not a valid policy: " + value));
- return;
- }
- if (required_csp_ != value) {
- required_csp_ = value;
- FrameOwnerPropertiesChanged();
- UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute);
- }
+ if (value && (value.Contains('\n') || value.Contains('\r') ||
+ !MatchesTheSerializedCSPGrammar(value.GetString()))) {
+ required_csp_ = g_null_atom;
+ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kError,
+ "'csp' attribute is invalid: " + value));
+ return;
+ }
+ if (required_csp_ != value) {
+ required_csp_ = value;
+ CSPAttributeChanged();
+ UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute);
}
} else if (name == html_names::kAllowAttr) {
if (allow_ != value) {
@@ -271,11 +229,6 @@ void HTMLIFrameElement::ParseAttribute(
UseCounter::Count(GetDocument(),
WebFeature::kFeaturePolicyAllowAttribute);
}
- if (value.Contains(',')) {
- Deprecation::CountDeprecation(
- GetDocument().GetExecutionContext(),
- WebFeature::kCommaSeparatorInAllowAttribute);
- }
}
} else if (name == html_names::kDisallowdocumentaccessAttr &&
RuntimeEnabledFeatures::DisallowDocumentAccessEnabled()) {
@@ -289,6 +242,7 @@ void HTMLIFrameElement::ParseAttribute(
UpdateRequiredPolicy();
}
} else if (name == html_names::kTrusttokenAttr) {
+ UseCounter::Count(GetDocument(), WebFeature::kTrustTokenIframe);
trust_token_ = value;
} else {
// Websites picked up a Chromium article that used this non-specified
@@ -369,32 +323,8 @@ ParsedFeaturePolicy HTMLIFrameElement::ConstructContainerPolicy() const {
ParsedFeaturePolicy container_policy = FeaturePolicyParser::ParseAttribute(
allow_, self_origin, src_origin, logger, GetExecutionContext());
- // Next, process sandbox flags. These all only take effect if a corresponding
- // policy does *not* exist in the allow attribute's value.
- if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
- // If the frame is sandboxed at all, then warn if feature policy attributes
- // will override the sandbox attributes.
- if ((sandbox_flags_converted_to_feature_policies_ &
- network::mojom::blink::WebSandboxFlags::kNavigation) !=
- network::mojom::blink::WebSandboxFlags::kNone) {
- for (const auto& pair : SandboxFlagsWithFeaturePolicies()) {
- if ((sandbox_flags_converted_to_feature_policies_ & pair.first) !=
- network::mojom::blink::WebSandboxFlags::kNone &&
- IsFeatureDeclared(pair.second, container_policy)) {
- logger.Warn(String::Format(
- "Allow and Sandbox attributes both mention '%s'. Allow will take "
- "precedence.",
- GetNameForFeature(pair.second).Utf8().c_str()));
- }
- }
- }
- ApplySandboxFlagsToParsedFeaturePolicy(
- sandbox_flags_converted_to_feature_policies_, container_policy);
- }
-
- // Finally, process the allow* attribuets. Like sandbox attributes, they only
- // take effect if the corresponding feature is not present in the allow
- // attribute's value.
+ // Process the allow* attributes. These only take effect if the corresponding
+ // feature is not present in the allow attribute's value.
// If allowfullscreen attribute is present and no fullscreen policy is set,
// enable the feature for all origins.
@@ -449,24 +379,8 @@ Node::InsertionNotificationRequest HTMLIFrameElement::InsertedInto(
HTMLFrameElementBase::InsertedInto(insertion_point);
auto* html_doc = DynamicTo<HTMLDocument>(GetDocument());
- if (html_doc && insertion_point.IsInDocumentTree()) {
+ if (html_doc && insertion_point.IsInDocumentTree())
html_doc->AddNamedItem(name_);
- if (!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE) &&
- !ContentSecurityPolicy::IsValidCSPAttr(
- required_csp_, GetDocument().RequiredCSP().GetString())) {
- if (!required_csp_.IsEmpty()) {
- GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kOther,
- mojom::ConsoleMessageLevel::kError,
- "'csp' attribute is not a valid policy: " + required_csp_));
- }
- if (required_csp_ != GetDocument().RequiredCSP()) {
- required_csp_ = GetDocument().RequiredCSP();
- FrameOwnerPropertiesChanged();
- UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute);
- }
- }
- }
LogAddElementIfIsolatedWorldAndInDocument("iframe", html_names::kSrcAttr);
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element.h b/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
index 7a27189bf89..0e1623f07bd 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element.h
@@ -61,11 +61,6 @@ class CORE_EXPORT HTMLIFrameElement final
return mojom::blink::FrameOwnerElementType::kIframe;
}
- network::mojom::blink::WebSandboxFlags
- sandbox_flags_converted_to_feature_policies() const {
- return sandbox_flags_converted_to_feature_policies_;
- }
-
private:
void SetCollapsed(bool) override;
@@ -107,12 +102,6 @@ class CORE_EXPORT HTMLIFrameElement final
bool collapsed_by_client_;
Member<HTMLIFrameElementSandbox> sandbox_;
Member<DOMFeaturePolicy> policy_;
- // This represents a subset of sandbox flags set through 'sandbox' attribute
- // that will be converted to feature policies as part of the container
- // policies.
- network::mojom::blink::WebSandboxFlags
- sandbox_flags_converted_to_feature_policies_ =
- network::mojom::blink::WebSandboxFlags::kNone;
network::mojom::ReferrerPolicy referrer_policy_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc b/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
index 2340322f86a..af5ae9b0320 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element_sandbox.cc
@@ -33,10 +33,6 @@ const char* const kSupportedSandboxTokens[] = {
constexpr char kStorageAccessAPISandboxToken[] =
"allow-storage-access-by-user-activation";
-// TODO(crbug.com/1042130): move this into |kSupportedSandboxTokens| when the
-// feature flag is enabled by default.
-constexpr char kDeclarativeShadowDom[] = "allow-declarative-shadow-dom";
-
bool IsTokenSupported(const AtomicString& token) {
for (const char* supported_token : kSupportedSandboxTokens) {
if (token == supported_token)
@@ -51,14 +47,6 @@ bool IsTokenSupported(const AtomicString& token) {
return true;
}
- // If Declarative Shadow DOM is enabled, allow the sandbox flag.
- // TODO(crbug.com/1145605): This won't work for origin trial enabled iframe
- // documents, because there's no ExecutionContext here.
- if (RuntimeEnabledFeatures::DeclarativeShadowDOMEnabledByRuntimeFlag() &&
- (token == kDeclarativeShadowDom)) {
- return true;
- }
-
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_iframe_element_test.cc b/chromium/third_party/blink/renderer/core/html/html_iframe_element_test.cc
index f7ed45ffef0..32d553b87a5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_iframe_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_iframe_element_test.cc
@@ -17,8 +17,6 @@
namespace blink {
-constexpr size_t expected_number_of_sandbox_features = 9;
-
class HTMLIFrameElementTest : public testing::Test {
public:
scoped_refptr<const SecurityOrigin> GetOriginForFeaturePolicy(
@@ -192,83 +190,6 @@ TEST_F(HTMLIFrameElementTest, AllowAttributeContainerPolicy) {
container_policy2[1].allowed_origins.begin()->Serialize());
}
-// Sandboxing an iframe should result in a container policy with an item for
-// each sandbox feature
-TEST_F(HTMLIFrameElementTest, SandboxAttributeContainerPolicy) {
- ASSERT_TRUE(RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled());
-
- frame_element_->setAttribute(html_names::kSandboxAttr, "");
- frame_element_->UpdateContainerPolicyForTests();
-
- const ParsedFeaturePolicy& container_policy =
- frame_element_->GetFramePolicy().container_policy;
-
- EXPECT_EQ(expected_number_of_sandbox_features, container_policy.size());
-}
-
-// Test that the allow attribute on a sandboxed frame results in a container
-// policy which is restricted to a unique origin.
-TEST_F(HTMLIFrameElementTest, CrossOriginSandboxAttributeContainerPolicy) {
- ASSERT_TRUE(RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled());
-
- frame_element_->setAttribute(html_names::kSrcAttr, "http://example.net/");
- frame_element_->setAttribute(html_names::kAllowAttr, "fullscreen");
- frame_element_->setAttribute(html_names::kSandboxAttr, "");
- frame_element_->UpdateContainerPolicyForTests();
-
- const ParsedFeaturePolicy& container_policy =
- frame_element_->GetFramePolicy().container_policy;
-
- EXPECT_EQ(expected_number_of_sandbox_features + 1, container_policy.size());
- const auto& container_policy_item =
- std::find_if(container_policy.begin(), container_policy.end(),
- [](const auto& declaration) {
- return declaration.feature ==
- mojom::blink::FeaturePolicyFeature::kFullscreen;
- });
- EXPECT_NE(container_policy_item, container_policy.end())
- << "Fullscreen feature not found in container policy";
-
- const ParsedFeaturePolicyDeclaration item = *container_policy_item;
- EXPECT_EQ(mojom::blink::FeaturePolicyFeature::kFullscreen, item.feature);
- EXPECT_FALSE(item.matches_all_origins);
- EXPECT_TRUE(item.matches_opaque_src);
- EXPECT_EQ(0UL, item.allowed_origins.size());
-}
-
-// Test that the allow attribute on a sandboxed frame with the allow-same-origin
-// flag results in a container policy which is restricted to the origin of the
-// containing document.
-TEST_F(HTMLIFrameElementTest, SameOriginSandboxAttributeContainerPolicy) {
- ASSERT_TRUE(RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled());
-
- frame_element_->setAttribute(html_names::kSrcAttr, "http://example.net/");
- frame_element_->setAttribute(html_names::kAllowAttr, "fullscreen");
- frame_element_->setAttribute(html_names::kSandboxAttr, "allow-same-origin");
- frame_element_->UpdateContainerPolicyForTests();
-
- const ParsedFeaturePolicy& container_policy =
- frame_element_->GetFramePolicy().container_policy;
-
- EXPECT_EQ(expected_number_of_sandbox_features + 1, container_policy.size());
- const auto& container_policy_item =
- std::find_if(container_policy.begin(), container_policy.end(),
- [](const auto& declaration) {
- return declaration.feature ==
- mojom::blink::FeaturePolicyFeature::kFullscreen;
- });
- EXPECT_NE(container_policy_item, container_policy.end())
- << "Fullscreen feature not found in container policy";
-
- const ParsedFeaturePolicyDeclaration item = *container_policy_item;
- EXPECT_EQ(mojom::blink::FeaturePolicyFeature::kFullscreen, item.feature);
- EXPECT_FALSE(item.matches_all_origins);
- EXPECT_FALSE(item.matches_opaque_src);
- EXPECT_EQ(1UL, item.allowed_origins.size());
- EXPECT_FALSE(item.allowed_origins.begin()->opaque());
- EXPECT_EQ("http://example.net", item.allowed_origins.begin()->Serialize());
-}
-
// Test the ConstructContainerPolicy method when no attributes are set on the
// iframe element.
TEST_F(HTMLIFrameElementTest, ConstructEmptyContainerPolicy) {
@@ -403,26 +324,4 @@ TEST_F(HTMLIFrameElementSimTest, AllowAttributeParsingError) {
<< ConsoleMessages().front();
}
-TEST_F(HTMLIFrameElementSimTest, CommaSeparatorIsDeprecated) {
- EXPECT_FALSE(
- GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
- WebFeature::kCommaSeparatorInAllowAttribute));
- SimRequest main_resource("https://example.com", "text/html");
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe
- allow="fullscreen, geolocation"></iframe>
- )");
-
- EXPECT_EQ(ConsoleMessages().size(), 1u)
- << "Comma separator in allow attribute should log a deprecation message "
- "to the console.";
- EXPECT_TRUE(ConsoleMessages().front().Contains("5740835259809792"))
- << "Console message should mention the chromestatus entry.";
-
- EXPECT_TRUE(
- GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
- WebFeature::kCommaSeparatorInAllowAttribute));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element.cc b/chromium/third_party/blink/renderer/core/html/html_image_element.cc
index 3ee7b73923c..2dd7e1dfd9b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element.cc
@@ -108,6 +108,7 @@ HTMLImageElement::HTMLImageElement(Document& document, bool created_by_parser)
!GetExecutionContext()->IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature::kUnsizedMedia)),
is_legacy_format_or_unoptimized_image_(false),
+ is_ad_related_(false),
referrer_policy_(network::mojom::ReferrerPolicy::kDefault) {
SetHasCustomStyleCallbacks();
}
@@ -197,6 +198,39 @@ void HTMLImageElement::CollectStyleForPresentationAttribute(
}
}
+void HTMLImageElement::CollectExtraStyleForPresentationAttribute(
+ MutableCSSPropertyValueSet* style) {
+ if (!source_)
+ return;
+
+ const AtomicString& width = source_->FastGetAttribute(html_names::kWidthAttr);
+ const AtomicString& height =
+ source_->FastGetAttribute(html_names::kHeightAttr);
+ if (!width && !height)
+ return;
+
+ if (width) {
+ AddHTMLLengthToStyle(style, CSSPropertyID::kWidth, width);
+ } else {
+ AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kWidth,
+ CSSValueID::kAuto);
+ }
+
+ if (height) {
+ AddHTMLLengthToStyle(style, CSSPropertyID::kHeight, height);
+ } else {
+ AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kHeight,
+ CSSValueID::kAuto);
+ }
+
+ if (width && height) {
+ ApplyAspectRatioToStyle(width, height, style);
+ } else {
+ AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kAspectRatio,
+ CSSValueID::kAuto);
+ }
+}
+
const AtomicString HTMLImageElement::ImageSourceURL() const {
return best_fit_image_url_.IsNull() ? FastGetAttribute(html_names::kSrcAttr)
: best_fit_image_url_;
@@ -343,6 +377,13 @@ String HTMLImageElement::AltText() const {
return FastGetAttribute(html_names::kTitleAttr);
}
+void HTMLImageElement::InvalidateAttributeMapping() {
+ EnsureUniqueElementData().SetPresentationAttributeStyleIsDirty(true);
+ SetNeedsStyleRecalc(kLocalStyleChange,
+ StyleChangeReasonForTracing::Create(
+ style_change_reason::kPictureSourceChanged));
+}
+
bool HTMLImageElement::SupportedImageType(
const String& type,
const HashSet<String>* disabled_image_types) {
@@ -461,6 +502,7 @@ Node::InsertionNotificationRequest HTMLImageElement::InsertedInto(
if (GetDocument().IsActive() && was_added_to_picture_parent) {
ImageCandidate candidate = FindBestFitImageFromPictureParent();
if (!candidate.IsEmpty()) {
+ InvalidateAttributeMapping();
SetBestFitURLAndDPRFromImageCandidate(candidate);
image_was_modified = true;
}
@@ -475,6 +517,7 @@ Node::InsertionNotificationRequest HTMLImageElement::InsertedInto(
}
void HTMLImageElement::RemovedFrom(ContainerNode& insertion_point) {
+ InvalidateAttributeMapping();
if (!form_ || NodeTraversal::HighestAncestorOrSelf(*form_.Get()) !=
NodeTraversal::HighestAncestorOrSelf(*this))
ResetFormOwner();
@@ -501,9 +544,7 @@ unsigned HTMLImageElement::width() {
// if the image is available, use its width
if (ImageResourceContent* image_content = GetImageLoader().GetContent()) {
- return image_content
- ->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(nullptr))
- .Width();
+ return image_content->IntrinsicSize(kRespectImageOrientation).Width();
}
}
@@ -525,9 +566,7 @@ unsigned HTMLImageElement::height() {
// if the image is available, use its height
if (ImageResourceContent* image_content = GetImageLoader().GetContent()) {
- return image_content
- ->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(nullptr))
- .Height();
+ return image_content->IntrinsicSize(kRespectImageOrientation).Height();
}
}
@@ -755,7 +794,10 @@ void HTMLImageElement::SelectSourceURL(
ImageLoader::UpdateFromElementBehavior behavior) {
if (!GetDocument().IsActive())
return;
+ // TODO(crbug.com/1175295): Remove this CHECK once the investigation is done.
+ CHECK(GetDocument().GetExecutionContext());
+ HTMLSourceElement* old_source = source_;
ImageCandidate candidate = FindBestFitImageFromPictureParent();
if (candidate.IsEmpty()) {
candidate = BestFitSourceForImageAttributes(
@@ -763,6 +805,8 @@ void HTMLImageElement::SelectSourceURL(
FastGetAttribute(html_names::kSrcAttr),
FastGetAttribute(html_names::kSrcsetAttr), &GetDocument());
}
+ if (old_source != source_)
+ InvalidateAttributeMapping();
AtomicString old_url = best_fit_image_url_;
SetBestFitURLAndDPRFromImageCandidate(candidate);
@@ -848,13 +892,15 @@ void HTMLImageElement::SetLayoutDisposition(
SetForceReattachLayoutTree();
}
-scoped_refptr<ComputedStyle> HTMLImageElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> HTMLImageElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
switch (layout_disposition_) {
case LayoutDisposition::kPrimaryContent: // Fall through.
case LayoutDisposition::kCollapsed:
- return OriginalStyleForLayoutObject();
+ return OriginalStyleForLayoutObject(style_recalc_context);
case LayoutDisposition::kFallbackContent: {
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
HTMLImageFallbackHelper::CustomStyleForAltText(*this, *style);
return style;
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_image_element.h b/chromium/third_party/blink/renderer/core/html/html_image_element.h
index 35dfdaacb76..3d6b773a7ff 100644
--- a/chromium/third_party/blink/renderer/core/html/html_image_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_image_element.h
@@ -181,6 +181,8 @@ class CORE_EXPORT HTMLImageElement final
void SetIsAdRelated() { is_ad_related_ = true; }
bool IsAdRelated() const override { return is_ad_related_; }
+ void InvalidateAttributeMapping();
+
static bool SupportedImageType(const String& type,
const HashSet<String>* disabled_image_types);
@@ -204,7 +206,8 @@ class CORE_EXPORT HTMLImageElement final
void DidMoveToNewDocument(Document& old_document) override;
void DidAddUserAgentShadowRoot(ShadowRoot&) override;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
private:
bool AreAuthorShadowsAllowed() const override { return false; }
@@ -215,6 +218,12 @@ class CORE_EXPORT HTMLImageElement final
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
+ // For mapping attributes from the <source> element, if any.
+ bool HasExtraStyleForPresentationAttribute() const override {
+ return source_;
+ }
+ void CollectExtraStyleForPresentationAttribute(
+ MutableCSSPropertyValueSet*) override;
void SetLayoutDisposition(LayoutDisposition, bool force_reattach = false);
void AttachLayoutTree(AttachContext&) override;
@@ -259,13 +268,12 @@ class CORE_EXPORT HTMLImageElement final
// policies. When any policy is violated, the image should be rendered as a
// placeholder image.
bool is_legacy_format_or_unoptimized_image_ : 1;
+ bool is_ad_related_ : 1;
network::mojom::ReferrerPolicy referrer_policy_;
std::unique_ptr<LazyLoadImageObserver::VisibleLoadTimeMetrics>
visible_load_time_metrics_;
-
- bool is_ad_related_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_li_element.cc b/chromium/third_party/blink/renderer/core/html/html_li_element.cc
index b69d9524afb..f1bab3c76ad 100644
--- a/chromium/third_party/blink/renderer/core/html/html_li_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_li_element.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/html/html_li_element.h"
+#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -41,26 +42,24 @@ bool HTMLLIElement::IsPresentationAttribute(const QualifiedName& name) const {
return HTMLElement::IsPresentationAttribute(name);
}
-CSSValueID ListTypeToCSSValueID(const AtomicString& value) {
+AtomicString ListTypeAttributeToStyleName(const AtomicString& value) {
if (value == "a")
- return CSSValueID::kLowerAlpha;
+ return "lower-alpha";
if (value == "A")
- return CSSValueID::kUpperAlpha;
+ return "upper-alpha";
if (value == "i")
- return CSSValueID::kLowerRoman;
+ return "lower-roman";
if (value == "I")
- return CSSValueID::kUpperRoman;
+ return "upper-roman";
if (value == "1")
- return CSSValueID::kDecimal;
+ return "decimal";
if (EqualIgnoringASCIICase(value, "disc"))
- return CSSValueID::kDisc;
+ return "disc";
if (EqualIgnoringASCIICase(value, "circle"))
- return CSSValueID::kCircle;
+ return "circle";
if (EqualIgnoringASCIICase(value, "square"))
- return CSSValueID::kSquare;
- if (EqualIgnoringASCIICase(value, "none"))
- return CSSValueID::kNone;
- return CSSValueID::kInvalid;
+ return "square";
+ return g_null_atom;
}
void HTMLLIElement::CollectStyleForPresentationAttribute(
@@ -68,10 +67,16 @@ void HTMLLIElement::CollectStyleForPresentationAttribute(
const AtomicString& value,
MutableCSSPropertyValueSet* style) {
if (name == html_names::kTypeAttr) {
- CSSValueID type_value = ListTypeToCSSValueID(value);
- if (IsValidCSSValueID(type_value)) {
+ if (EqualIgnoringASCIICase(value, "none")) {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, type_value);
+ style, CSSPropertyID::kListStyleType, CSSValueID::kNone);
+ } else {
+ AtomicString list_style_type_name = ListTypeAttributeToStyleName(value);
+ if (!list_style_type_name.IsNull()) {
+ AddPropertyToPresentationAttributeStyle(
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>(list_style_type_name));
+ }
}
} else {
HTMLElement::CollectStyleForPresentationAttribute(name, value, style);
@@ -91,7 +96,6 @@ void HTMLLIElement::AttachLayoutTree(AttachContext& context) {
HTMLElement::AttachLayoutTree(context);
if (ListItemOrdinal* ordinal = ListItemOrdinal::Get(*this)) {
- DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
ParseValue(FastGetAttribute(html_names::kValueAttr), ordinal);
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.cc b/chromium/third_party/blink/renderer/core/html/html_link_element.cc
index 9aee0c76a43..c4d2416e8c0 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.cc
@@ -25,6 +25,8 @@
#include "third_party/blink/renderer/core/html/html_link_element.h"
+#include <utility>
+
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_icon_sizes_parser.h"
#include "third_party/blink/public/platform/web_prescient_networking.h"
@@ -53,6 +55,23 @@
namespace blink {
+namespace {
+
+void ParseUrlsListValue(const AtomicString& value, HashSet<KURL>& url_hash) {
+ // Parse the attribute value as a space-separated list of urls
+ SpaceSplitString urls(value);
+ url_hash.clear();
+ url_hash.ReserveCapacityForSize(SafeCast<wtf_size_t>(urls.size()));
+ for (wtf_size_t i = 0; i < urls.size(); ++i) {
+ KURL url = LinkWebBundle::ParseResourceUrl(urls[i]);
+ if (url.IsValid()) {
+ url_hash.insert(std::move(url));
+ }
+ }
+}
+
+} // namespace
+
HTMLLinkElement::HTMLLinkElement(Document& document,
const CreateElementFlags flags)
: HTMLElement(html_names::kLinkTag, document),
@@ -64,6 +83,8 @@ HTMLLinkElement::HTMLLinkElement(Document& document,
resources_(
MakeGarbageCollected<DOMTokenList>(*this,
html_names::kResourcesAttr)),
+ scopes_(
+ MakeGarbageCollected<DOMTokenList>(*this, html_names::kScopesAttr)),
created_by_parser_(flags.IsCreatedByParser()) {}
HTMLLinkElement::~HTMLLinkElement() = default;
@@ -134,9 +155,6 @@ void HTMLLinkElement::ParseAttribute(
} else if (name == html_names::kMediaAttr) {
media_ = value.LowerASCII();
Process();
- } else if (name == html_names::kScopeAttr) {
- scope_ = value;
- Process();
} else if (name == html_names::kIntegrityAttr) {
integrity_ = value;
} else if (name == html_names::kImportanceAttr &&
@@ -145,21 +163,14 @@ void HTMLLinkElement::ParseAttribute(
UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
importance_ = value;
} else if (name == html_names::kResourcesAttr &&
- RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(
- GetExecutionContext())) {
+ LinkWebBundle::IsFeatureEnabled(GetExecutionContext())) {
resources_->DidUpdateAttributeValue(params.old_value, value);
-
- // Parse the attribute value as a space-separated list of urls
- SpaceSplitString urls(value);
- valid_resource_urls_.clear();
- valid_resource_urls_.ReserveCapacityForSize(
- SafeCast<wtf_size_t>(urls.size()));
- for (wtf_size_t i = 0; i < urls.size(); ++i) {
- KURL url = LinkWebBundle::ParseResourceUrl(urls[i]);
- if (url.IsValid()) {
- valid_resource_urls_.insert(std::move(url));
- }
- }
+ ParseUrlsListValue(value, valid_resource_urls_);
+ Process();
+ } else if (name == html_names::kScopesAttr &&
+ LinkWebBundle::IsFeatureEnabled(GetExecutionContext())) {
+ scopes_->DidUpdateAttributeValue(params.old_value, value);
+ ParseUrlsListValue(value, valid_scope_urls_);
Process();
} else if (name == html_names::kDisabledAttr) {
UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
@@ -220,9 +231,11 @@ bool HTMLLinkElement::LoadLink(const LinkLoadParameters& params) {
void HTMLLinkElement::LoadStylesheet(const LinkLoadParameters& params,
const WTF::TextEncoding& charset,
FetchParameters::DeferOption defer_option,
- ResourceClient* link_client) {
+ ResourceClient* link_client,
+ RenderBlockingBehavior render_blocking) {
return link_loader_->LoadStylesheet(params, localName(), charset,
- defer_option, GetDocument(), link_client);
+ defer_option, GetDocument(), link_client,
+ render_blocking);
}
LinkResource* HTMLLinkElement::LinkResourceToProcess() {
@@ -245,8 +258,7 @@ LinkResource* HTMLLinkElement::LinkResourceToProcess() {
link_ = MakeGarbageCollected<LinkImport>(this);
} else if (rel_attribute_.IsWebBundle()) {
// Only create a webbundle link when SubresourceWebBundles are enabled.
- if (!RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(
- GetExecutionContext())) {
+ if (!LinkWebBundle::IsFeatureEnabled(GetExecutionContext())) {
return nullptr;
}
link_ = MakeGarbageCollected<LinkWebBundle>(this);
@@ -363,23 +375,6 @@ void HTMLLinkElement::LinkLoadingErrored() {
DispatchEvent(*Event::Create(event_type_names::kError));
}
-void HTMLLinkElement::DidStartLinkPrerender() {
- DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderstart));
-}
-
-void HTMLLinkElement::DidStopLinkPrerender() {
- DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderstop));
-}
-
-void HTMLLinkElement::DidSendLoadForLinkPrerender() {
- DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderload));
-}
-
-void HTMLLinkElement::DidSendDOMContentLoadedForLinkPrerender() {
- DispatchEvent(
- *Event::Create(event_type_names::kWebkitprerenderdomcontentloaded));
-}
-
scoped_refptr<base::SingleThreadTaskRunner>
HTMLLinkElement::GetLoadingTaskRunner() {
return GetDocument().GetTaskRunner(TaskType::kNetworking);
@@ -414,10 +409,9 @@ void HTMLLinkElement::ScheduleEvent() {
.GetTaskRunner(TaskType::kDOMManipulation)
->PostTask(
FROM_HERE,
- WTF::Bind(&HTMLLinkElement::DispatchPendingEvent,
- WrapPersistent(this),
- WTF::Passed(std::make_unique<IncrementLoadEventDelayCount>(
- GetDocument()))));
+ WTF::Bind(
+ &HTMLLinkElement::DispatchPendingEvent, WrapPersistent(this),
+ std::make_unique<IncrementLoadEventDelayCount>(GetDocument())));
}
void HTMLLinkElement::StartLoadingDynamicSheet() {
@@ -481,12 +475,17 @@ DOMTokenList* HTMLLinkElement::resources() const {
return resources_.Get();
}
+DOMTokenList* HTMLLinkElement::scopes() const {
+ return scopes_.Get();
+}
+
void HTMLLinkElement::Trace(Visitor* visitor) const {
visitor->Trace(link_);
visitor->Trace(sizes_);
visitor->Trace(link_loader_);
visitor->Trace(rel_list_);
visitor->Trace(resources_);
+ visitor->Trace(scopes_);
HTMLElement::Trace(visitor);
LinkLoaderClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.h b/chromium/third_party/blink/renderer/core/html/html_link_element.h
index d7231b65599..4cd11864713 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.h
@@ -69,7 +69,6 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
DOMTokenList& relList() const {
return static_cast<DOMTokenList&>(*rel_list_);
}
- String Scope() const { return scope_; }
const AtomicString& GetType() const;
@@ -99,10 +98,12 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
// IDL method.
DOMTokenList* resources() const;
+ DOMTokenList* scopes() const;
const HashSet<KURL>& ValidResourceUrls() const {
return valid_resource_urls_;
}
+ const HashSet<KURL>& ValidScopeUrls() const { return valid_scope_urls_; }
void ScheduleEvent();
@@ -115,7 +116,8 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
void LoadStylesheet(const LinkLoadParameters&,
const WTF::TextEncoding&,
FetchParameters::DeferOption,
- ResourceClient*);
+ ResourceClient*,
+ RenderBlockingBehavior render_blocking);
bool IsAlternate() const {
// TODO(crbug.com/1087043): Remove this if() condition once the feature has
// landed and no compat issues are reported.
@@ -162,10 +164,6 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
// From LinkLoaderClient
void LinkLoaded() override;
void LinkLoadingErrored() override;
- void DidStartLinkPrerender() override;
- void DidStopLinkPrerender() override;
- void DidSendLoadForLinkPrerender() override;
- void DidSendDOMContentLoadedForLinkPrerender() override;
scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override;
Member<LinkResource> link_;
@@ -181,9 +179,10 @@ class CORE_EXPORT HTMLLinkElement final : public HTMLElement,
Vector<gfx::Size> icon_sizes_;
Member<RelList> rel_list_;
LinkRelAttribute rel_attribute_;
- String scope_;
Member<DOMTokenList> resources_;
HashSet<KURL> valid_resource_urls_;
+ Member<DOMTokenList> scopes_;
+ HashSet<KURL> valid_scope_urls_;
bool created_by_parser_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_link_element.idl b/chromium/third_party/blink/renderer/core/html/html_link_element.idl
index 80a95e7ac4c..5856df7c67b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_link_element.idl
@@ -58,5 +58,6 @@
// Subresource loading with Web Bundles
// https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md
// crbug.com/1082020
- [RuntimeEnabled=SubresourceWebBundles, PutForwards=value] readonly attribute DOMTokenList resources;
+ [RuntimeEnabled=SubresourceWebBundles, PutForwards=value, SecureContext] readonly attribute DOMTokenList resources;
+ [RuntimeEnabled=SubresourceWebBundles, PutForwards=value, SecureContext] readonly attribute DOMTokenList scopes;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_meta_element.cc b/chromium/third_party/blink/renderer/core/html/html_meta_element.cc
index fd0b909f61e..ac2d2fd38b3 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meta_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
#include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
namespace blink {
@@ -589,26 +590,17 @@ void HTMLMetaElement::ProcessContent() {
UseCounter::Count(&GetDocument(),
WebFeature::kHTMLMetaElementReferrerPolicyOutsideHead);
}
- bool comma_in_content_value = false;
- if (content_value.Contains(',')) {
- comma_in_content_value = true;
- UseCounter::Count(
- &GetDocument(),
- WebFeature::kHTMLMetaElementReferrerPolicyMultipleTokens);
- }
- GetExecutionContext()->ParseAndSetReferrerPolicy(
- content_value, true /* support legacy keywords */,
- /*from_meta_tag_with_list_of_policies=*/
- comma_in_content_value);
+ GetExecutionContext()->ParseAndSetReferrerPolicy(content_value,
+ kPolicySourceMetaTag);
if (base::FeatureList::IsEnabled(blink::features::kPolicyContainer)) {
LocalFrame* frame = GetDocument().GetFrame();
// If frame is null, this document is not attached to a frame, hence it
- // has no Policy Container, so we ignore the next step. This function will
+ // has no PolicyContainer, so we ignore the next step. This function will
// run again anyway, should this document or this element be attached to a
// frame.
if (frame) {
- GetDocument().GetFrame()->GetPolicyContainer()->UpdateReferrerPolicy(
+ frame->GetPolicyContainer()->UpdateReferrerPolicy(
GetExecutionContext()->GetReferrerPolicy());
}
}
@@ -649,4 +641,4 @@ const AtomicString& HTMLMetaElement::HttpEquiv() const {
const AtomicString& HTMLMetaElement::GetName() const {
return FastGetAttribute(html_names::kNameAttr);
}
-}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_meta_element_test.cc b/chromium/third_party/blink/renderer/core/html/html_meta_element_test.cc
index f2ac9d6711d..c317a16fdde 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meta_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_meta_element_test.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
@@ -244,12 +245,21 @@ TEST_F(HTMLMetaElementTest, ColorSchemeForcedDarkeningAndMQ) {
}
TEST_F(HTMLMetaElementTest, ReferrerPolicyWithoutContent) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kPolicyContainer);
+
+ MockPolicyContainerHost policy_container_host;
+ GetFrame().SetPolicyContainer(std::make_unique<PolicyContainer>(
+ policy_container_host.BindNewEndpointAndPassDedicatedRemote(),
+ mojom::blink::PolicyContainerPolicies::New()));
+ EXPECT_CALL(policy_container_host,
+ SetReferrerPolicy(network::mojom::ReferrerPolicy::kStrictOrigin));
+
GetDocument().head()->setInnerHTML(R"HTML(
<meta name="referrer" content="strict-origin">
<meta name="referrer" >
)HTML");
- EXPECT_EQ(network::mojom::ReferrerPolicy::kStrictOrigin,
- GetDocument().GetReferrerPolicy());
+ policy_container_host.FlushForTesting();
}
TEST_F(HTMLMetaElementTest, ReferrerPolicyUpdatesPolicyContainer) {
@@ -262,7 +272,7 @@ TEST_F(HTMLMetaElementTest, ReferrerPolicyUpdatesPolicyContainer) {
policy_container_host.BindNewEndpointAndPassDedicatedRemote();
auto policy_container = std::make_unique<PolicyContainer>(
std::move(stub_policy_container_remote),
- mojom::blink::PolicyContainerDocumentPolicies::New());
+ mojom::blink::PolicyContainerPolicies::New());
GetFrame().SetPolicyContainer(std::move(policy_container));
EXPECT_CALL(policy_container_host,
diff --git a/chromium/third_party/blink/renderer/core/html/html_meter_element.h b/chromium/third_party/blink/renderer/core/html/html_meter_element.h
index 620f2cbf7fc..ab6ddfc4294 100644
--- a/chromium/third_party/blink/renderer/core/html/html_meter_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_meter_element.h
@@ -33,6 +33,7 @@ class CORE_EXPORT HTMLMeterElement final : public HTMLElement {
public:
explicit HTMLMeterElement(Document&);
+ ~HTMLMeterElement() override;
enum GaugeRegion {
kGaugeRegionOptimum,
@@ -66,8 +67,6 @@ class CORE_EXPORT HTMLMeterElement final : public HTMLElement {
void Trace(Visitor*) const override;
private:
- ~HTMLMeterElement() override;
-
bool AreAuthorShadowsAllowed() const override { return false; }
bool IsLabelable() const override { return true; }
diff --git a/chromium/third_party/blink/renderer/core/html/html_no_embed_element.cc b/chromium/third_party/blink/renderer/core/html/html_no_embed_element.cc
index 3f453f98bd9..691a6d389a7 100644
--- a/chromium/third_party/blink/renderer/core/html/html_no_embed_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_no_embed_element.cc
@@ -42,8 +42,7 @@ HTMLNoEmbedElement::HTMLNoEmbedElement(Document& document)
bool HTMLNoEmbedElement::LayoutObjectIsNeeded(
const ComputedStyle& style) const {
- if (GetDocument().GetFrame()->Loader().AllowPlugins(
- kNotAboutToInstantiatePlugin))
+ if (GetDocument().GetFrame()->Loader().AllowPlugins())
return false;
return Element::LayoutObjectIsNeeded(style);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_object_element.cc b/chromium/third_party/blink/renderer/core/html/html_object_element.cc
index 142d13904fd..2f29f9134c5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_object_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_object_element.cc
@@ -55,8 +55,6 @@ HTMLObjectElement::HTMLObjectElement(Document& document,
EnsureUserAgentShadowRoot();
}
-inline HTMLObjectElement::~HTMLObjectElement() = default;
-
void HTMLObjectElement::Trace(Visitor* visitor) const {
ListedElement::Trace(visitor);
HTMLPlugInElement::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/html_object_element.h b/chromium/third_party/blink/renderer/core/html/html_object_element.h
index 23a896a7065..45065ee7121 100644
--- a/chromium/third_party/blink/renderer/core/html/html_object_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_object_element.h
@@ -44,7 +44,7 @@ class CORE_EXPORT HTMLObjectElement final : public HTMLPlugInElement,
public:
HTMLObjectElement(Document&, const CreateElementFlags);
- ~HTMLObjectElement() override;
+ ~HTMLObjectElement() override = default;
void Trace(Visitor*) const override;
// Returns attributes that should be checked against Trusted Types
diff --git a/chromium/third_party/blink/renderer/core/html/html_olist_element.cc b/chromium/third_party/blink/renderer/core/html/html_olist_element.cc
index 48581eb8040..ad05ff09971 100644
--- a/chromium/third_party/blink/renderer/core/html/html_olist_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_olist_element.cc
@@ -22,8 +22,8 @@
#include "third_party/blink/renderer/core/html/html_olist_element.h"
+#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
-#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/html/list_item_ordinal.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -54,19 +54,24 @@ void HTMLOListElement::CollectStyleForPresentationAttribute(
if (name == html_names::kTypeAttr) {
if (value == "a") {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kLowerAlpha);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("lower-alpha"));
} else if (value == "A") {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kUpperAlpha);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("upper-alpha"));
} else if (value == "i") {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kLowerRoman);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("lower-roman"));
} else if (value == "I") {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kUpperRoman);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("upper-roman"));
} else if (value == "1") {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kDecimal);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("decimal"));
}
} else {
HTMLElement::CollectStyleForPresentationAttribute(name, value, style);
@@ -102,7 +107,6 @@ void HTMLOListElement::setStart(int start) {
void HTMLOListElement::UpdateItemValues() {
if (!GetLayoutObject())
return;
- UpdateDistributionForFlatTreeTraversal();
ListItemOrdinal::InvalidateAllItemsForOrderedList(this);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_or_foreign_element.idl b/chromium/third_party/blink/renderer/core/html/html_or_foreign_element.idl
index a49710e81fa..486da823b35 100644
--- a/chromium/third_party/blink/renderer/core/html/html_or_foreign_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_or_foreign_element.idl
@@ -10,7 +10,7 @@ interface mixin HTMLOrForeignElement {
[CEReactions] attribute DOMString nonce;
[CEReactions, Reflect] attribute boolean autofocus;
- [Affects=Nothing, CEReactions, CustomElementCallbacks] attribute long tabIndex;
+ [Affects=Nothing, CEReactions] attribute long tabIndex;
void focus(optional FocusOptions options = {});
void blur();
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_picture_element.cc b/chromium/third_party/blink/renderer/core/html/html_picture_element.cc
index d6a71246fe7..8b96d350041 100644
--- a/chromium/third_party/blink/renderer/core/html/html_picture_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_picture_element.cc
@@ -27,6 +27,15 @@ void HTMLPictureElement::SourceOrMediaChanged() {
}
}
+void HTMLPictureElement::SourceAttributeChanged() {
+ for (HTMLImageElement* image_element =
+ Traversal<HTMLImageElement>::FirstChild(*this);
+ image_element; image_element = Traversal<HTMLImageElement>::NextSibling(
+ *image_element)) {
+ image_element->InvalidateAttributeMapping();
+ }
+}
+
void HTMLPictureElement::RemoveListenerFromSourceChildren() {
for (HTMLSourceElement* source_element =
Traversal<HTMLSourceElement>::FirstChild(*this);
diff --git a/chromium/third_party/blink/renderer/core/html/html_picture_element.h b/chromium/third_party/blink/renderer/core/html/html_picture_element.h
index 65fe13e7cf7..48dee7b5f39 100644
--- a/chromium/third_party/blink/renderer/core/html/html_picture_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_picture_element.h
@@ -16,6 +16,7 @@ class HTMLPictureElement final : public HTMLElement {
explicit HTMLPictureElement(Document&);
void SourceOrMediaChanged();
+ void SourceAttributeChanged();
void RemoveListenerFromSourceChildren();
void AddListenerToSourceChildren();
diff --git a/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc b/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
index 675f683a392..02f9782ab4f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -132,7 +132,7 @@ HTMLPlugInElement::HTMLPlugInElement(
if (auto* context = doc.GetExecutionContext()) {
context->GetScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kContainsPlugins,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
}
@@ -646,7 +646,7 @@ bool HTMLPlugInElement::LoadPlugin(const KURL& url,
return false;
LocalFrame* frame = GetDocument().GetFrame();
- if (!frame->Loader().AllowPlugins(kAboutToInstantiatePlugin))
+ if (!frame->Loader().AllowPlugins())
return false;
auto* layout_object = GetLayoutEmbeddedObject();
@@ -712,8 +712,7 @@ bool HTMLPlugInElement::AllowedToLoadObject(const KURL& url,
AtomicString declared_mime_type = FastGetAttribute(html_names::kTypeAttr);
auto* csp = GetExecutionContext()->GetContentSecurityPolicy();
- if (!csp->AllowObjectFromSource(url) ||
- !csp->AllowPluginType(mime_type, declared_mime_type, url)) {
+ if (!csp->AllowObjectFromSource(url)) {
if (auto* layout_object = GetLayoutEmbeddedObject()) {
plugin_is_available_ = false;
layout_object->SetPluginAvailability(
@@ -799,8 +798,10 @@ void HTMLPlugInElement::UpdateServiceTypeIfEmpty() {
}
}
-scoped_refptr<ComputedStyle> HTMLPlugInElement::CustomStyleForLayoutObject() {
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+scoped_refptr<ComputedStyle> HTMLPlugInElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
if (IsImageType() && !GetLayoutObject() && style &&
LayoutObjectIsNeeded(*style)) {
if (!image_loader_)
diff --git a/chromium/third_party/blink/renderer/core/html/html_plugin_element.h b/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
index 7fb6e7bb01a..3512c61bf42 100644
--- a/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -172,7 +172,8 @@ class CORE_EXPORT HTMLPlugInElement
bool IsFocusableStyle() const final;
bool IsKeyboardFocusable() const final;
void DidAddUserAgentShadowRoot(ShadowRoot&) final;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() final;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) final;
// HTMLElement overrides:
bool HasCustomFocusLogic() const override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_popup_element.cc b/chromium/third_party/blink/renderer/core/html/html_popup_element.cc
new file mode 100644
index 00000000000..c7654c925f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/html_popup_element.cc
@@ -0,0 +1,148 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/html_popup_element.h"
+
+#include "third_party/blink/renderer/core/css/style_change_reason.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+
+namespace blink {
+
+HTMLPopupElement::HTMLPopupElement(Document& document)
+ : HTMLElement(html_names::kPopupTag, document), open_(false) {
+ DCHECK(RuntimeEnabledFeatures::HTMLPopupElementEnabled());
+ UseCounter::Count(document, WebFeature::kPopupElement);
+}
+
+
+void HTMLPopupElement::MarkStyleDirty() {
+ SetNeedsStyleRecalc(kLocalStyleChange,
+ StyleChangeReasonForTracing::Create(
+ style_change_reason::kPopupVisibilityChange));
+}
+
+bool HTMLPopupElement::open() const {
+ return open_;
+}
+
+void HTMLPopupElement::hide() {
+ if (!open_)
+ return;
+ GetDocument().HideAllPopupsUntil(this);
+ PopPopupElement(this);
+ open_ = false;
+ PseudoStateChanged(CSSSelector::kPseudoPopupOpen);
+ MarkStyleDirty();
+ ScheduleHideEvent();
+}
+
+void HTMLPopupElement::ScheduleHideEvent() {
+ Event* event = Event::Create(event_type_names::kHide);
+ event->SetTarget(this);
+ GetDocument().EnqueueAnimationFrameEvent(event);
+}
+
+void HTMLPopupElement::show() {
+ if (open_ || !isConnected())
+ return;
+
+ // Only hide popups up to the anchor element's nearest shadow-including
+ // ancestor popup element.
+ HTMLPopupElement* parent_popup = nullptr;
+ if (Element* anchor = AnchorElement()) {
+ for (Node* ancestor = anchor; ancestor;
+ ancestor = ancestor->ParentOrShadowHostNode()) {
+ if (HTMLPopupElement* ancestor_popup =
+ DynamicTo<HTMLPopupElement>(ancestor)) {
+ parent_popup = ancestor_popup;
+ break;
+ }
+ }
+ }
+ GetDocument().HideAllPopupsUntil(parent_popup);
+ open_ = true;
+ PseudoStateChanged(CSSSelector::kPseudoPopupOpen);
+ PushNewPopupElement(this);
+ MarkStyleDirty();
+}
+
+void HTMLPopupElement::PushNewPopupElement(HTMLPopupElement* popup) {
+ auto& stack = GetDocument().PopupElementStack();
+ DCHECK(!stack.Contains(popup));
+ stack.push_back(popup);
+ GetDocument().AddToTopLayer(popup);
+}
+
+void HTMLPopupElement::PopPopupElement(HTMLPopupElement* popup) {
+ auto& stack = GetDocument().PopupElementStack();
+ DCHECK(stack.back() == popup);
+ stack.pop_back();
+ GetDocument().RemoveFromTopLayer(popup);
+}
+
+HTMLPopupElement* HTMLPopupElement::TopmostPopupElement() {
+ auto& stack = GetDocument().PopupElementStack();
+ return stack.IsEmpty() ? nullptr : stack.back();
+}
+
+Element* HTMLPopupElement::AnchorElement() const {
+ const AtomicString& anchor_id = FastGetAttribute(html_names::kAnchorAttr);
+ if (anchor_id.IsNull())
+ return nullptr;
+ if (!IsInTreeScope())
+ return nullptr;
+ if (Element* anchor = GetTreeScope().getElementById(anchor_id))
+ return anchor;
+ return nullptr;
+}
+
+void HTMLPopupElement::HandleLightDismiss(const Event& event) {
+ auto* target_node = event.target()->ToNode();
+ if (!target_node)
+ return;
+ auto& document = target_node->GetDocument();
+ DCHECK(document.PopupShowing());
+ const AtomicString& event_type = event.type();
+ if (event_type == event_type_names::kClick) {
+ // We need to walk up from the clicked element to see if there
+ // is a parent popup, or the anchor for a popup. There can be
+ // multiple popups for a single anchor element, but we will
+ // stop on any of them. Therefore, just store the popup that
+ // is highest (last) on the popup stack for each anchor.
+ HeapHashMap<Member<const Element>, Member<const HTMLPopupElement>> anchors;
+ for (auto popup : document.PopupElementStack()) {
+ if (auto* anchor = popup->AnchorElement()) {
+ anchors.Set(anchor, popup);
+ }
+ }
+ const HTMLPopupElement* closest_popup_parent = nullptr;
+ for (Node* current_node = target_node; current_node;
+ current_node = current_node->parentNode()) {
+ if (auto* popup = DynamicTo<HTMLPopupElement>(current_node)) {
+ closest_popup_parent = popup;
+ break;
+ }
+ Element* current_element = DynamicTo<Element>(current_node);
+ if (current_element && anchors.Contains(current_element)) {
+ closest_popup_parent = anchors.at(current_element);
+ break;
+ }
+ }
+ document.HideAllPopupsUntil(closest_popup_parent);
+ } else if (event_type == event_type_names::kKeydown) {
+ const KeyboardEvent* key_event = DynamicTo<KeyboardEvent>(event);
+ if (key_event && key_event->key() == "Escape") {
+ // Escape key just pops the topmost <popup> off the stack.
+ document.HideTopmostPopupElement();
+ }
+ } else if (event_type == event_type_names::kScroll) {
+ // Close all popups upon scroll.
+ document.HideAllPopupsUntil(nullptr);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_popup_element.h b/chromium/third_party/blink/renderer/core/html/html_popup_element.h
new file mode 100644
index 00000000000..f374a7c4d92
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/html_popup_element.h
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_POPUP_ELEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_POPUP_ELEMENT_H_
+
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+
+namespace blink {
+
+class Document;
+
+// The HTMLPopupElement implements the <popup> HTML element. The popup element
+// can be used to construct a topmost popup dialog. This feature is still
+// under development, and is not part of the HTML standard. It can be enabled
+// by passing --enable-blink-features=HTMLPopupElement. See
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md
+// for more details.
+class HTMLPopupElement final : public HTMLElement {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit HTMLPopupElement(Document&);
+
+ bool open() const;
+ void hide();
+ void show();
+
+ Element* AnchorElement() const;
+
+ static void HandleLightDismiss(const Event&);
+
+ private:
+ void ScheduleHideEvent();
+ void MarkStyleDirty();
+
+ void PushNewPopupElement(HTMLPopupElement*);
+ void PopPopupElement(HTMLPopupElement*);
+ HTMLPopupElement* TopmostPopupElement();
+
+ bool open_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_POPUP_ELEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/html_popup_element.idl b/chromium/third_party/blink/renderer/core/html/html_popup_element.idl
new file mode 100644
index 00000000000..06d07b8a955
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/html_popup_element.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md
+[Exposed=Window,HTMLConstructor,RuntimeEnabled=HTMLPopupElement]
+interface HTMLPopupElement : HTMLElement {
+ [CEReactions] readonly attribute boolean open;
+ [CEReactions, Measure] void show();
+ [CEReactions, Measure] void hide();
+};
diff --git a/chromium/third_party/blink/renderer/core/html/html_progress_element.h b/chromium/third_party/blink/renderer/core/html/html_progress_element.h
index 61bce3bfc06..756bf256eaa 100644
--- a/chromium/third_party/blink/renderer/core/html/html_progress_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_progress_element.h
@@ -37,6 +37,7 @@ class CORE_EXPORT HTMLProgressElement final : public HTMLElement {
static const double kInvalidPosition;
explicit HTMLProgressElement(Document&);
+ ~HTMLProgressElement() override;
double value() const;
void setValue(double);
@@ -51,8 +52,6 @@ class CORE_EXPORT HTMLProgressElement final : public HTMLElement {
void Trace(Visitor*) const override;
private:
- ~HTMLProgressElement() override;
-
bool AreAuthorShadowsAllowed() const override { return false; }
bool ShouldAppearIndeterminate() const override;
bool IsLabelable() const override { return true; }
diff --git a/chromium/third_party/blink/renderer/core/html/html_script_element.cc b/chromium/third_party/blink/renderer/core/html/html_script_element.cc
index 692566bb50f..f6afbac3ed5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_script_element.cc
@@ -107,9 +107,10 @@ void HTMLScriptElement::ParseAttribute(
Node::InsertionNotificationRequest HTMLScriptElement::InsertedInto(
ContainerNode& insertion_point) {
if (insertion_point.isConnected() && HasSourceAttribute() &&
- !ScriptLoader::IsValidScriptTypeAndLanguage(
+ ScriptLoader::GetScriptTypeAtPrepare(
TypeAttributeValue(), LanguageAttributeValue(),
- ScriptLoader::kDisallowLegacyTypeInTypeAttribute)) {
+ ScriptLoader::kDisallowLegacyTypeInTypeAttribute) ==
+ ScriptLoader::ScriptTypeAtPrepare::kInvalid) {
UseCounter::Count(GetDocument(),
WebFeature::kScriptElementWithInvalidTypeHasSrc);
}
@@ -294,7 +295,7 @@ void HTMLScriptElement::DispatchErrorEvent() {
void HTMLScriptElement::SetScriptElementForBinding(
HTMLScriptElementOrSVGScriptElement& element) {
- if (!IsInV1ShadowTree())
+ if (!IsInShadowTree())
element.SetHTMLScriptElement(this);
}
diff --git a/chromium/third_party/blink/renderer/core/html/html_shadow_element.cc b/chromium/third_party/blink/renderer/core/html/html_shadow_element.cc
deleted file mode 100644
index 7f91cb8cda8..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_shadow_element.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/html/html_shadow_element.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-class Document;
-
-HTMLShadowElement::HTMLShadowElement(Document& document)
- : V0InsertionPoint(html_names::kShadowTag, document) {
- UseCounter::Count(document, WebFeature::kHTMLShadowElement);
-}
-
-HTMLShadowElement::~HTMLShadowElement() = default;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/html_shadow_element.h b/chromium/third_party/blink/renderer/core/html/html_shadow_element.h
deleted file mode 100644
index b804cf41f5f..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_shadow_element.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_SHADOW_ELEMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_SHADOW_ELEMENT_H_
-
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-
-namespace blink {
-
-class HTMLShadowElement final : public V0InsertionPoint {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit HTMLShadowElement(Document&);
- ~HTMLShadowElement() override;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_SHADOW_ELEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/html/html_shadow_element.idl b/chromium/third_party/blink/renderer/core/html/html_shadow_element.idl
deleted file mode 100644
index 1939442db51..00000000000
--- a/chromium/third_party/blink/renderer/core/html/html_shadow_element.idl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// https://w3c.github.io/webcomponents/spec/shadow/#the-shadow-element
-
-[
- Exposed=Window
-] interface HTMLShadowElement : HTMLElement {
- NodeList getDistributedNodes();
-};
diff --git a/chromium/third_party/blink/renderer/core/html/html_slot_element.cc b/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
index 2981d044c68..4044a4ae761 100644
--- a/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -224,7 +224,7 @@ void HTMLSlotElement::assign(HeapVector<Member<Node>> nodes,
if (candidates_changed) {
assigned_nodes_candidates_.Swap(candidates);
- ContainingShadowRoot()->GetSlotAssignment().SetNeedsAssignmentRecalc();
+ SetShadowRootNeedsAssignmentRecalc();
DidSlotChange(SlotChangeType::kSignalSlotChangeEvent);
}
}
@@ -357,9 +357,20 @@ void HTMLSlotElement::AttachLayoutTree(AttachContext& context) {
void HTMLSlotElement::DetachLayoutTree(bool performing_reattach) {
if (SupportsAssignment()) {
+ auto* host = OwnerShadowHost();
const HeapVector<Member<Node>>& flat_tree_children = assigned_nodes_;
for (auto& node : flat_tree_children) {
- if (node->GetDocument() == GetDocument())
+ // Don't detach the assigned node if the node is no longer a child of the
+ // host.
+ //
+ // 1. It's no long a direct flat-tree child of this slot.
+ // 2. It was already detached when removed from the host.
+ // 3. It might already have been inserted in a different part of the DOM,
+ // or a new document tree and been attached.
+ // 4. It might have been marked style-dirty in its new location and
+ // calling DetachLayoutTree here would have incorrectly cleared those
+ // dirty bits.
+ if (host == node->parentNode())
node->DetachLayoutTree(performing_reattach);
}
}
@@ -382,7 +393,7 @@ void HTMLSlotElement::AttributeChanged(
const AttributeModificationParams& params) {
if (params.name == html_names::kNameAttr) {
if (ShadowRoot* root = ContainingShadowRoot()) {
- if (root->IsV1() && params.old_value != params.new_value) {
+ if (params.old_value != params.new_value) {
root->GetSlotAssignment().DidRenameSlot(
NormalizeSlotName(params.old_value), *this);
}
@@ -397,7 +408,6 @@ Node::InsertionNotificationRequest HTMLSlotElement::InsertedInto(
if (SupportsAssignment()) {
ShadowRoot* root = ContainingShadowRoot();
DCHECK(root);
- DCHECK(root->IsV1());
if (root == insertion_point.ContainingShadowRoot()) {
// This slot is inserted into the same tree of |insertion_point|
root->DidAddSlot(*this);
@@ -420,13 +430,14 @@ void HTMLSlotElement::RemovedFrom(ContainerNode& insertion_point) {
// `removedFrom` is called after the node is removed from the tree.
// That means:
// 1. If this slot is still in a tree scope, it means the slot has been in a
- // shadow tree. An inclusive shadow-including ancestor of the shadow host was
- // originally removed from its parent.
+ // shadow tree. An inclusive shadow-including ancestor of the shadow host
+ // was originally removed from its parent. See slot s2 below.
// 2. Or (this slot is not in a tree scope), this slot's inclusive
- // ancestor was orginally removed from its parent (== insertion point). This
- // slot and the originally removed node was in the same tree before removal.
+ // ancestor was orginally removed from its parent (== insertion point).
+ // This slot and the originally removed node was in the same tree before
+ // removal. See slot s1 below.
- // For exmaple, given the following trees, (srN: = shadow root, sN: = slot)
+ // For example, given the following trees, (srN: = shadow root, sN: = slot)
// a
// |- b --sr1
// |- c |--d
@@ -455,7 +466,7 @@ void HTMLSlotElement::RemovedFrom(ContainerNode& insertion_point) {
// We don't need to clear |assigned_nodes_| here. That's an important
// optimization.
}
- } else if (insertion_point.IsInV1ShadowTree()) {
+ } else if (insertion_point.IsInShadowTree()) {
// This slot was in a shadow tree and got disconnected from the shadow tree.
// In the above example, (this slot == s1), (insertion point == d)
// and (insertion_point->ContainingShadowRoot == sr1).
@@ -470,12 +481,13 @@ void HTMLSlotElement::RemovedFrom(ContainerNode& insertion_point) {
}
void HTMLSlotElement::RecalcStyleForSlotChildren(
- const StyleRecalcChange change) {
+ const StyleRecalcChange change,
+ const StyleRecalcContext& style_recalc_context) {
for (auto& node : flat_tree_children_) {
if (!change.TraverseChild(*node))
continue;
if (auto* element = DynamicTo<Element>(node.Get()))
- element->RecalcStyle(change);
+ element->RecalcStyle(change, style_recalc_context);
else if (auto* text_node = DynamicTo<Text>(node.Get()))
text_node->RecalcTextStyle(change);
}
@@ -568,7 +580,7 @@ void HTMLSlotElement::DidSlotChangeAfterRemovedFromShadowTree() {
void HTMLSlotElement::DidSlotChangeAfterRenaming() {
DCHECK(SupportsAssignment());
EnqueueSlotChangeEvent();
- SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc();
+ SetShadowRootNeedsAssignmentRecalc();
CheckSlotChange(SlotChangeType::kSuppressSlotChangeEvent);
}
@@ -682,8 +694,7 @@ void HTMLSlotElement::NotifySlottedNodesOfFlatTreeChangeNaive(
}
}
-void HTMLSlotElement::
- SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc() {
+void HTMLSlotElement::SetShadowRootNeedsAssignmentRecalc() {
ContainingShadowRoot()->GetSlotAssignment().SetNeedsAssignmentRecalc();
}
@@ -691,7 +702,7 @@ void HTMLSlotElement::DidSlotChange(SlotChangeType slot_change_type) {
DCHECK(SupportsAssignment());
if (slot_change_type == SlotChangeType::kSignalSlotChangeEvent)
EnqueueSlotChangeEvent();
- SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc();
+ SetShadowRootNeedsAssignmentRecalc();
// Check slotchange recursively since this slotchange may cause another
// slotchange.
CheckSlotChange(SlotChangeType::kSuppressSlotChangeEvent);
@@ -701,7 +712,7 @@ void HTMLSlotElement::CheckFallbackAfterInsertedIntoShadowTree() {
DCHECK(SupportsAssignment());
if (HasSlotableChild()) {
// We use kSuppress here because a slotchange event shouldn't be
- // dispatched if a slot being inserted don't get any assigned
+ // dispatched if a slot being inserted doesn't get any assigned
// node, but has a slotable child, according to DOM Standard.
DidSlotChange(SlotChangeType::kSuppressSlotChangeEvent);
}
@@ -740,14 +751,19 @@ void HTMLSlotElement::EnqueueSlotChangeEvent() {
bool HTMLSlotElement::HasAssignedNodesSlow() const {
ShadowRoot* root = ContainingShadowRoot();
- DCHECK(root);
- DCHECK(root->IsV1());
+ DCHECK(root) << "This should only be called on slots inside a shadow tree";
SlotAssignment& assignment = root->GetSlotAssignment();
if (assignment.FindSlotByName(GetName()) != this)
return false;
return assignment.FindHostChildBySlotName(GetName());
}
+void HTMLSlotElement::ChildrenChanged(const ChildrenChange& change) {
+ HTMLElement::ChildrenChanged(change);
+ if (SupportsAssignment())
+ SetShadowRootNeedsAssignmentRecalc();
+}
+
void HTMLSlotElement::Trace(Visitor* visitor) const {
visitor->Trace(assigned_nodes_);
visitor->Trace(flat_tree_children_);
diff --git a/chromium/third_party/blink/renderer/core/html/html_slot_element.h b/chromium/third_party/blink/renderer/core/html/html_slot_element.h
index 2e0b527ac04..ee2e2b5be9e 100644
--- a/chromium/third_party/blink/renderer/core/html/html_slot_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_slot_element.h
@@ -91,7 +91,7 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
// dirty. e.g. To detect a slotchange event in DOM mutations.
bool HasAssignedNodesSlow() const;
- bool SupportsAssignment() const { return IsInV1ShadowTree(); }
+ bool SupportsAssignment() const { return IsInShadowTree(); }
void CheckFallbackAfterInsertedIntoShadowTree();
void CheckFallbackAfterRemovedFromShadowTree();
@@ -104,7 +104,8 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
static AtomicString NormalizeSlotName(const AtomicString&);
- void RecalcStyleForSlotChildren(const StyleRecalcChange);
+ void RecalcStyleForSlotChildren(const StyleRecalcChange,
+ const StyleRecalcContext&);
// For User-Agent Shadow DOM
static const AtomicString& UserAgentCustomAssignSlotName();
@@ -124,6 +125,8 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
InsertionNotificationRequest InsertedInto(ContainerNode&) final;
void RemovedFrom(ContainerNode&) final;
+ void ChildrenChanged(const ChildrenChange&) override;
+
void EnqueueSlotChangeEvent();
bool HasSlotableChild() const;
@@ -138,7 +141,7 @@ class CORE_EXPORT HTMLSlotElement final : public HTMLElement {
const HeapVector<Member<Node>>& old_slotted,
const HeapVector<Member<Node>>& new_slotted);
- void SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc();
+ void SetShadowRootNeedsAssignmentRecalc();
bool CheckNodesValidity(HeapVector<Member<Node>> nodes, ExceptionState&);
// SlotAssignnment:recalc runs in tree order. Update to assigned order.
diff --git a/chromium/third_party/blink/renderer/core/html/html_source_element.cc b/chromium/third_party/blink/renderer/core/html/html_source_element.cc
index b3e2f46957b..c2765fb2553 100644
--- a/chromium/third_party/blink/renderer/core/html/html_source_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_source_element.cc
@@ -161,6 +161,17 @@ bool HTMLSourceElement::MediaQueryMatches() const {
return media_query_list_->matches();
}
+void HTMLSourceElement::AttributeChanged(
+ const AttributeModificationParams& params) {
+ const QualifiedName& name = params.name;
+ if (name == html_names::kWidthAttr || name == html_names::kHeightAttr) {
+ if (auto* picture = DynamicTo<HTMLPictureElement>(parentElement()))
+ picture->SourceAttributeChanged();
+ }
+
+ HTMLElement::AttributeChanged(params);
+}
+
bool HTMLSourceElement::IsURLAttribute(const Attribute& attribute) const {
return attribute.GetName() == html_names::kSrcAttr ||
HTMLElement::IsURLAttribute(attribute);
diff --git a/chromium/third_party/blink/renderer/core/html/html_source_element.h b/chromium/third_party/blink/renderer/core/html/html_source_element.h
index 2c461edcaf6..83fafd8759b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_source_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_source_element.h
@@ -62,6 +62,7 @@ class HTMLSourceElement final : public HTMLElement {
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
+ void AttributeChanged(const AttributeModificationParams&) override;
bool IsURLAttribute(const Attribute&) const override;
void ParseAttribute(const AttributeModificationParams&) override;
diff --git a/chromium/third_party/blink/renderer/core/html/html_source_element.idl b/chromium/third_party/blink/renderer/core/html/html_source_element.idl
index 1e122bbc18b..88adafc43d8 100644
--- a/chromium/third_party/blink/renderer/core/html/html_source_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/html_source_element.idl
@@ -35,4 +35,6 @@
[CEReactions, Reflect] attribute USVString srcset;
[CEReactions, Reflect] attribute DOMString sizes;
[CEReactions, Reflect] attribute DOMString media;
+ [CEReactions, Reflect] attribute unsigned long width;
+ [CEReactions, Reflect] attribute unsigned long height;
};
diff --git a/chromium/third_party/blink/renderer/core/html/html_style_element.cc b/chromium/third_party/blink/renderer/core/html/html_style_element.cc
index 1fb65d80835..031497fbd7b 100644
--- a/chromium/third_party/blink/renderer/core/html/html_style_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_style_element.cc
@@ -49,7 +49,7 @@ void HTMLStyleElement::ParseAttribute(
GetDocument().IsActive() && sheet_) {
sheet_->SetMediaQueries(
MediaQuerySet::Create(params.new_value, GetExecutionContext()));
- GetDocument().GetStyleEngine().MediaQueriesChangedInScope(GetTreeScope());
+ GetDocument().GetStyleEngine().SetNeedsActiveStyleUpdate(GetTreeScope());
} else if (params.name == html_names::kTypeAttr) {
HTMLElement::ParseAttribute(params);
StyleElement::ChildrenChanged(*this);
@@ -129,11 +129,10 @@ void HTMLStyleElement::NotifyLoadedSheetAndAllCriticalSubresources(
.GetTaskRunner(TaskType::kNetworking)
->PostTask(
FROM_HERE,
- WTF::Bind(&HTMLStyleElement::DispatchPendingEvent,
- WrapPersistent(this),
- WTF::Passed(std::make_unique<IncrementLoadEventDelayCount>(
- GetDocument())),
- is_load_event));
+ WTF::Bind(
+ &HTMLStyleElement::DispatchPendingEvent, WrapPersistent(this),
+ std::make_unique<IncrementLoadEventDelayCount>(GetDocument()),
+ is_load_event));
}
bool HTMLStyleElement::disabled() const {
diff --git a/chromium/third_party/blink/renderer/core/html/html_summary_element.cc b/chromium/third_party/blink/renderer/core/html/html_summary_element.cc
index aa9c582e7ea..953846bcf79 100644
--- a/chromium/third_party/blink/renderer/core/html/html_summary_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_summary_element.cc
@@ -38,8 +38,10 @@ namespace blink {
HTMLSummaryElement::HTMLSummaryElement(Document& document)
: HTMLElement(html_names::kSummaryTag, document) {
- SetHasCustomStyleCallbacks();
- EnsureUserAgentShadowRoot();
+ if (!RuntimeEnabledFeatures::SummaryListItemEnabled()) {
+ SetHasCustomStyleCallbacks();
+ EnsureUserAgentShadowRoot();
+ }
}
LayoutObject* HTMLSummaryElement::CreateLayoutObject(const ComputedStyle& style,
@@ -57,6 +59,7 @@ LayoutObject* HTMLSummaryElement::CreateLayoutObject(const ComputedStyle& style,
}
void HTMLSummaryElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
+ DCHECK(!RuntimeEnabledFeatures::SummaryListItemEnabled());
auto* marker_control =
MakeGarbageCollected<DetailsMarkerControl>(GetDocument());
marker_control->SetIdAttribute(shadow_element_names::kIdDetailsMarker);
@@ -73,6 +76,7 @@ HTMLDetailsElement* HTMLSummaryElement::DetailsElement() const {
}
Element* HTMLSummaryElement::MarkerControl() {
+ DCHECK(!RuntimeEnabledFeatures::SummaryListItemEnabled());
return EnsureUserAgentShadowRoot().getElementById(
shadow_element_names::kIdDetailsMarker);
}
@@ -161,6 +165,7 @@ bool HTMLSummaryElement::WillRespondToMouseClickEvents() {
}
void HTMLSummaryElement::WillRecalcStyle(const StyleRecalcChange) {
+ DCHECK(!RuntimeEnabledFeatures::SummaryListItemEnabled());
if (GetForceReattachLayoutTree() && IsMainSummary()) {
if (Element* marker = MarkerControl()) {
marker->SetNeedsStyleRecalc(
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_col_element.cc b/chromium/third_party/blink/renderer/core/html/html_table_col_element.cc
index 4ccc1ed2c2f..911cddebf40 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_col_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_table_col_element.cc
@@ -71,7 +71,7 @@ void HTMLTableColElement::ParseAttribute(
} else if (params.name == html_names::kWidthAttr) {
if (!params.new_value.IsEmpty()) {
if (GetLayoutObject() && GetLayoutObject()->IsLayoutTableCol()) {
- LayoutTableCol* col = ToLayoutTableCol(GetLayoutObject());
+ auto* col = To<LayoutBox>(GetLayoutObject());
int new_width = Width().ToInt();
if (new_width != col->Size().Width()) {
col->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
diff --git a/chromium/third_party/blink/renderer/core/html/html_table_element.h b/chromium/third_party/blink/renderer/core/html/html_table_element.h
index 7cfaf43a8a5..57c7834c2e5 100644
--- a/chromium/third_party/blink/renderer/core/html/html_table_element.h
+++ b/chromium/third_party/blink/renderer/core/html/html_table_element.h
@@ -42,6 +42,7 @@ class CORE_EXPORT HTMLTableElement final : public HTMLElement {
public:
explicit HTMLTableElement(Document&);
+ ~HTMLTableElement() override;
HTMLTableCaptionElement* caption() const;
void setCaption(HTMLTableCaptionElement*, ExceptionState&);
@@ -76,8 +77,6 @@ class CORE_EXPORT HTMLTableElement final : public HTMLElement {
void Trace(Visitor*) const override;
private:
- ~HTMLTableElement() override;
-
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const override;
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/html/html_tag_names.json5 b/chromium/third_party/blink/renderer/core/html/html_tag_names.json5
index b85be229135..bd31d2feb6f 100644
--- a/chromium/third_party/blink/renderer/core/html/html_tag_names.json5
+++ b/chromium/third_party/blink/renderer/core/html/html_tag_names.json5
@@ -113,10 +113,6 @@
interfaceName: "HTMLUnknownElement",
},
{
- name: "content",
- interfaceName: "HTMLContentElement",
- },
- {
name: "data",
interfaceName: "HTMLDataElement",
},
@@ -342,10 +338,6 @@
interfaceHeaderDir: "third_party/blink/renderer/core/html/forms",
},
{
- name: "shadow",
- interfaceName: "HTMLShadowElement",
- },
- {
name: "p",
interfaceName: "HTMLParagraphElement",
},
@@ -359,6 +351,11 @@
interfaceName: "HTMLElement",
},
{
+ name: "popup",
+ interfaceName: "HTMLPopupElement",
+ runtimeEnabled: "HTMLPopupElement",
+ },
+ {
name: "portal",
interfaceName: "HTMLPortalElement",
interfaceHeaderDir: "third_party/blink/renderer/core/html/portal",
@@ -419,6 +416,12 @@
interfaceHeaderDir: "third_party/blink/renderer/core/html/forms",
},
{
+ name: "selectmenu",
+ interfaceName: "HTMLSelectMenuElement",
+ runtimeEnabled: "HTMLSelectMenuElement",
+ interfaceHeaderDir: "third_party/blink/renderer/core/html/forms",
+ },
+ {
name: "slot",
interfaceName: "HTMLSlotElement",
},
diff --git a/chromium/third_party/blink/renderer/core/html/html_ulist_element.cc b/chromium/third_party/blink/renderer/core/html/html_ulist_element.cc
index bf0d71a2525..2eba42ecc53 100644
--- a/chromium/third_party/blink/renderer/core/html/html_ulist_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_ulist_element.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/html/html_ulist_element.h"
+#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/html_names.h"
@@ -45,13 +46,16 @@ void HTMLUListElement::CollectStyleForPresentationAttribute(
if (name == html_names::kTypeAttr) {
if (EqualIgnoringASCIICase(value, "disc")) {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kDisc);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("disc"));
} else if (EqualIgnoringASCIICase(value, "circle")) {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kCircle);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("circle"));
} else if (EqualIgnoringASCIICase(value, "square")) {
AddPropertyToPresentationAttributeStyle(
- style, CSSPropertyID::kListStyleType, CSSValueID::kSquare);
+ style, CSSPropertyID::kListStyleType,
+ *MakeGarbageCollected<CSSCustomIdentValue>("square"));
} else if (EqualIgnoringASCIICase(value, "none")) {
AddPropertyToPresentationAttributeStyle(
style, CSSPropertyID::kListStyleType, CSSValueID::kNone);
diff --git a/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc b/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
index 797ff5d125b..0b4d0a6a273 100644
--- a/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_view_source_document.cc
@@ -24,8 +24,15 @@
#include "third_party/blink/renderer/core/html/html_view_source_document.h"
+#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/core/css/css_value_id_mappings.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/events/mouse_event.h"
+#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
#include "third_party/blink/renderer/core/html/html_base_element.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
@@ -41,9 +48,32 @@
#include "third_party/blink/renderer/core/html/parser/html_view_source_parser.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
+class ViewSourceEventListener : public NativeEventListener {
+ public:
+ ViewSourceEventListener(HTMLTableElement* table, HTMLInputElement* checkbox)
+ : table_(table), checkbox_(checkbox) {}
+
+ void Invoke(ExecutionContext*, Event* event) override {
+ DCHECK_EQ(event->type(), event_type_names::kChange);
+ table_->setAttribute(html_names::kClassAttr,
+ checkbox_->checked() ? "line-wrap" : "");
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(table_);
+ visitor->Trace(checkbox_);
+ NativeEventListener::Trace(visitor);
+ }
+
+ private:
+ Member<HTMLTableElement> table_;
+ Member<HTMLInputElement> checkbox_;
+};
+
HTMLViewSourceDocument::HTMLViewSourceDocument(const DocumentInit& initializer)
: HTMLDocument(initializer), type_(initializer.GetMimeType()) {
SetIsViewSource(true);
@@ -76,6 +106,34 @@ void HTMLViewSourceDocument::CreateContainingTable() {
table->ParserAppendChild(tbody_);
current_ = tbody_;
line_number_ = 0;
+
+ // Create a checkbox to control line wrapping.
+ auto* checkbox =
+ MakeGarbageCollected<HTMLInputElement>(*this, CreateElementFlags());
+ checkbox->setAttribute(html_names::kTypeAttr, "checkbox");
+ checkbox->addEventListener(
+ event_type_names::kChange,
+ MakeGarbageCollected<ViewSourceEventListener>(table, checkbox),
+ /*use_capture=*/false);
+ auto* label = MakeGarbageCollected<HTMLLabelElement>(*this);
+ label->ParserAppendChild(
+ Text::Create(*this, WTF::AtomicString(Locale::DefaultLocale().QueryString(
+ IDS_VIEW_SOURCE_LINE_WRAP))));
+ label->setAttribute(html_names::kClassAttr, "line-wrap-control");
+ label->ParserAppendChild(checkbox);
+ // Add the checkbox to a form with autocomplete=off, to avoid form
+ // restoration from changing the value of the checkbox.
+ auto* form = MakeGarbageCollected<HTMLFormElement>(*this);
+ form->setAttribute(html_names::kAutocompleteAttr, "off");
+ form->ParserAppendChild(label);
+ auto* tr = MakeGarbageCollected<HTMLTableRowElement>(*this);
+ auto* td =
+ MakeGarbageCollected<HTMLTableCellElement>(html_names::kTdTag, *this);
+ td->setAttribute(html_names::kColspanAttr, "2");
+ td->setAttribute(html_names::kClassAttr, "line-wrap-cell");
+ td->ParserAppendChild(form);
+ tr->ParserAppendChild(td);
+ tbody_->ParserAppendChild(tr);
}
void HTMLViewSourceDocument::AddSource(const String& source, HTMLToken& token) {
diff --git a/chromium/third_party/blink/renderer/core/html/html_view_source_document_test.cc b/chromium/third_party/blink/renderer/core/html/html_view_source_document_test.cc
index 81106688b61..5a507e73c2d 100644
--- a/chromium/third_party/blink/renderer/core/html/html_view_source_document_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/html_view_source_document_test.cc
@@ -39,7 +39,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource1) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-doctype\">&lt;!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML "
@@ -92,7 +96,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource2) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-tag\">&lt;script&gt;</span></td></tr><tr><td "
@@ -144,7 +152,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource3) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-tag\">&lt;head&gt;</span><span class=\"html-tag\">&lt;base "
@@ -209,7 +221,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource4) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-tag\">&lt;HEAD&gt;</span><span class=\"html-tag\">&lt;BASE "
@@ -277,7 +293,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource5) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"><br></td></tr><tr><td "
"class=\"line-number\" value=\"3\"></td><td "
@@ -309,8 +329,12 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource6) {
std::string expected_beginning(
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td class=\"line-content\"> "
- " ");
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\">"
+ "</td><td class=\"line-content\"> ");
std::string expected_ending(
" <span class=\"html-tag\">&lt;b&gt;</span>A<span "
"class=\"html-tag\">&lt;/b&gt;</span> <span "
@@ -325,7 +349,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource7) {
EXPECT_EQ(GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\">1234567<span "
"class=\"html-end-of-file\"></span></td></tr></tbody></table></"
"body></html>");
@@ -347,7 +375,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource8) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form></td></tr>"
+ "<tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-doctype\">&lt;!DOCTYPE html&gt;</span></td></tr><tr><td "
@@ -414,7 +446,11 @@ TEST_F(HTMLViewSourceDocumentTest, ViewSource9) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> <span "
"class=\"html-doctype\">&lt;!DOCTYPE html&gt;</span></td></tr><tr><td "
@@ -445,7 +481,11 @@ TEST_F(HTMLViewSourceDocumentTest, IncompleteToken) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td><td "
"class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
"value=\"2\"></td><td class=\"line-content\"> Incomplete token "
"test</td></tr><tr><td class=\"line-number\" value=\"3\"></td><td "
@@ -467,7 +507,12 @@ TEST_F(HTMLViewSourceDocumentTest, UnfinishedTextarea) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td class=\"line-content\"><span "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td>"
+ "<td class=\"line-content\"><span "
"class=\"html-tag\">&lt;textarea&gt;</span>foobar in "
"textarea</td></tr><tr><td class=\"line-number\" value=\"2\"></td><td "
"class=\"line-content\"> <span "
@@ -482,7 +527,12 @@ TEST_F(HTMLViewSourceDocumentTest, UnfinishedScript) {
GetDocument().documentElement()->outerHTML(),
"<html><head></head><body><div "
"class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
- "class=\"line-number\" value=\"1\"></td><td class=\"line-content\"><span "
+ "colspan=\"2\" class=\"line-wrap-cell\"><form "
+ "autocomplete=\"off\"><label "
+ "class=\"line-wrap-control\"><input "
+ "type=\"checkbox\"></label></form>"
+ "</td></tr><tr><td class=\"line-number\" value=\"1\"></td>"
+ "<td class=\"line-content\"><span "
"class=\"html-tag\">&lt;script&gt;</span>foobar in "
"script</td></tr><tr><td class=\"line-number\" value=\"2\"></td><td "
"class=\"line-content\"> <span "
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
index ac7aad3cf3d..bffd533d270 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.cc
@@ -33,9 +33,6 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css/style_sheet_list.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_import_step.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
#include "third_party/blink/renderer/core/html/imports/html_import_child_client.h"
#include "third_party/blink/renderer/core/html/imports/html_import_loader.h"
#include "third_party/blink/renderer/core/html/imports/html_import_tree_root.h"
@@ -64,12 +61,10 @@ void HTMLImportChild::OwnerInserted() {
}
void HTMLImportChild::DidShareLoader() {
- CreateCustomElementMicrotaskStepIfNeeded();
StateWillChange();
}
void HTMLImportChild::DidStartLoading() {
- CreateCustomElementMicrotaskStepIfNeeded();
}
void HTMLImportChild::DidFinish() {
@@ -79,16 +74,13 @@ void HTMLImportChild::DidFinish() {
void HTMLImportChild::DidFinishLoading() {
StateWillChange();
- V0CustomElement::DidFinishLoadingImport(*(Root()->GetDocument()));
}
void HTMLImportChild::DidFinishUpgradingCustomElements() {
StateWillChange();
- custom_element_microtask_step_.Clear();
}
void HTMLImportChild::Dispose() {
- InvalidateCustomElementMicrotaskStep();
if (Parent())
Parent()->RemoveChild(this);
@@ -118,26 +110,10 @@ void HTMLImportChild::StateDidChange() {
DidFinish();
}
-void HTMLImportChild::InvalidateCustomElementMicrotaskStep() {
- if (!custom_element_microtask_step_)
- return;
- custom_element_microtask_step_->Invalidate();
- custom_element_microtask_step_.Clear();
-}
-
-void HTMLImportChild::CreateCustomElementMicrotaskStepIfNeeded() {
- DCHECK(!custom_element_microtask_step_);
-
- if (!HasFinishedLoading() && !FormsCycle()) {
- custom_element_microtask_step_ = V0CustomElement::DidCreateImport(this);
- }
-}
-
bool HTMLImportChild::HasFinishedLoading() const {
DCHECK(loader_);
- return loader_->IsDone() && loader_->MicrotaskQueue()->IsEmpty() &&
- !custom_element_microtask_step_;
+ return loader_->IsDone();
}
HTMLImportLoader* HTMLImportChild::Loader() const {
@@ -168,14 +144,11 @@ void HTMLImportChild::Normalize() {
for (HTMLImportChild* child = ToHTMLImportChild(FirstChild()); child;
child = ToHTMLImportChild(child->Next())) {
- if (child->FormsCycle())
- child->InvalidateCustomElementMicrotaskStep();
child->Normalize();
}
}
void HTMLImportChild::Trace(Visitor* visitor) const {
- visitor->Trace(custom_element_microtask_step_);
visitor->Trace(loader_);
visitor->Trace(client_);
HTMLImport::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
index 7ba5533b9e5..016723d0fbf 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_child.h
@@ -37,7 +37,6 @@
namespace blink {
-class V0CustomElementMicrotaskImportStep;
class HTMLImportLoader;
class HTMLImportChildClient;
class HTMLLinkElement;
@@ -83,7 +82,6 @@ class HTMLImportChild final : public HTMLImport {
void InvalidateCustomElementMicrotaskStep();
KURL url_;
- WeakMember<V0CustomElementMicrotaskImportStep> custom_element_microtask_step_;
Member<HTMLImportLoader> loader_;
Member<HTMLImportChildClient> client_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
index 71e96eca7be..1a4f6f31d9e 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.cc
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "third_party/blink/renderer/core/dom/document_parser.h"
-#include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/imports/html_import_child.h"
#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
@@ -44,10 +43,7 @@
namespace blink {
HTMLImportLoader::HTMLImportLoader(HTMLImportsController* controller)
- : controller_(controller),
- state_(kStateLoading),
- microtask_queue_(
- MakeGarbageCollected<V0CustomElementSyncMicrotaskQueue>()) {}
+ : controller_(controller), state_(kStateLoading) {}
HTMLImportLoader::~HTMLImportLoader() = default;
@@ -101,7 +97,6 @@ HTMLImportLoader::State HTMLImportLoader::StartWritingAndParsing(
DocumentInit::Create()
.WithImportsController(controller_)
.WithExecutionContext(tree_root->GetExecutionContext())
- .WithRegistrationContext(tree_root->RegistrationContext())
.WithURL(response.CurrentRequestUrl()));
document_->OpenForNavigation(
RuntimeEnabledFeatures::ForceSynchronousHTMLParsingEnabled()
@@ -202,15 +197,10 @@ bool HTMLImportLoader::ShouldBlockScriptExecution() const {
return FirstImport()->GetState().ShouldBlockScriptExecution();
}
-V0CustomElementSyncMicrotaskQueue* HTMLImportLoader::MicrotaskQueue() const {
- return microtask_queue_;
-}
-
void HTMLImportLoader::Trace(Visitor* visitor) const {
visitor->Trace(controller_);
visitor->Trace(imports_);
visitor->Trace(document_);
- visitor->Trace(microtask_queue_);
DocumentParserClient::Trace(visitor);
RawResourceClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
index 5bde9c7458d..27e4d7e1a6b 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_loader.h
@@ -39,7 +39,6 @@
namespace blink {
-class V0CustomElementSyncMicrotaskQueue;
class Document;
class HTMLImportChild;
class HTMLImportsController;
@@ -83,8 +82,6 @@ class HTMLImportLoader final : public GarbageCollected<HTMLImportLoader>,
// loading. Called by Document::DidRemoveAllPendingStylesheets.
void DidRemoveAllPendingStylesheets();
- V0CustomElementSyncMicrotaskQueue* MicrotaskQueue() const;
-
void Trace(Visitor*) const override;
private:
@@ -113,7 +110,6 @@ class HTMLImportLoader final : public GarbageCollected<HTMLImportLoader>,
HeapVector<Member<HTMLImportChild>> imports_;
State state_;
Member<Document> document_;
- Member<V0CustomElementSyncMicrotaskQueue> microtask_queue_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
index f21358abc74..7e139f33f83 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.cc
@@ -79,6 +79,7 @@ void HTMLImportTreeRoot::RecalcTimerFired(TimerBase*) {
void HTMLImportTreeRoot::Trace(Visitor* visitor) const {
visitor->Trace(document_);
+ visitor->Trace(recalc_timer_);
visitor->Trace(imports_);
HTMLImport::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
index 02a484bcae1..c3ede3da15c 100644
--- a/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
+++ b/chromium/third_party/blink/renderer/core/html/imports/html_import_tree_root.h
@@ -42,7 +42,7 @@ class HTMLImportTreeRoot final : public HTMLImport, public NameClient {
void RecalcTimerFired(TimerBase*);
Member<Document> document_;
- TaskRunnerTimer<HTMLImportTreeRoot> recalc_timer_;
+ HeapTaskRunnerTimer<HTMLImportTreeRoot> recalc_timer_;
// List of import which has been loaded or being loaded.
typedef HeapVector<Member<HTMLImportChild>> ImportList;
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
index 02d907ee889..1128a3ff94a 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.cc
@@ -23,7 +23,6 @@
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -254,9 +253,9 @@ void LazyLoadFrameObserver::RecordMetricsOnVisibilityChanged(
if (time_when_first_load_finished_.is_null() &&
!is_initially_above_the_fold_) {
// Note: If the WebEffectiveConnectionType enum ever gets out of sync with
- // net::EffectiveConnectionType, then this will have to be updated to record
- // the sample in terms of net::EffectiveConnectionType instead of
- // WebEffectiveConnectionType.
+ // mojom::blink::EffectiveConnectionType, then this will have to be updated
+ // to record the sample in terms of mojom::blink::EffectiveConnectionType
+ // instead of WebEffectiveConnectionType.
UMA_HISTOGRAM_ENUMERATION(
"Blink.VisibleBeforeLoaded.LazyLoadEligibleFrames.BelowTheFold",
GetNetworkStateNotifier().EffectiveType());
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
index d27af3e6c0d..32ba218265b 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_frame_observer.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.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/heap/visitor.h"
namespace blink {
@@ -18,7 +19,6 @@ class IntersectionObserver;
class IntersectionObserverEntry;
class HTMLFrameOwnerElement;
class ResourceRequestHead;
-class Visitor;
class LazyLoadFrameObserver final
: public GarbageCollected<LazyLoadFrameObserver> {
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
index ecdfd944ccf..61b2779fffc 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
@@ -311,9 +311,9 @@ void LazyLoadImageObserver::OnVisibilityChanged(
visible_load_time_metrics.time_when_first_visible = base::TimeTicks::Now();
if (visible_load_time_metrics.time_when_first_load_finished.is_null()) {
// Note: If the WebEffectiveConnectionType enum ever gets out of sync
- // with net::EffectiveConnectionType, then both the AboveTheFold and
- // BelowTheFold histograms here will have to be updated to record the
- // sample in terms of net::EffectiveConnectionType instead of
+ // with mojom::blink::EffectiveConnectionType, then both the AboveTheFold
+ // and BelowTheFold histograms here will have to be updated to record the
+ // sample in terms of mojom::blink::EffectiveConnectionType instead of
// WebEffectiveConnectionType.
if (visible_load_time_metrics.is_initially_intersecting) {
UMA_HISTOGRAM_ENUMERATION(
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.h b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.h
index 5d236775714..7f19c88202a 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.h
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.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/heap/visitor.h"
namespace blink {
@@ -16,7 +17,6 @@ class Element;
class HTMLImageElement;
class IntersectionObserver;
class IntersectionObserverEntry;
-class Visitor;
class LazyLoadImageObserver final
: public GarbageCollected<LazyLoadImageObserver> {
diff --git a/chromium/third_party/blink/renderer/core/html/link_style.cc b/chromium/third_party/blink/renderer/core/html/link_style.cc
index b5da461825b..6b9590207c7 100644
--- a/chromium/third_party/blink/renderer/core/html/link_style.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_style.cc
@@ -38,19 +38,13 @@ LinkStyle::LinkStyle(HTMLLinkElement* owner)
: LinkResource(owner),
disabled_state_(kUnset),
pending_sheet_type_(kNone),
+ render_blocking_behavior_(RenderBlockingBehavior::kUnset),
loading_(false),
fired_load_(false),
loaded_sheet_(false) {}
LinkStyle::~LinkStyle() = default;
-enum StyleSheetCacheStatus {
- kStyleSheetNewEntry,
- kStyleSheetInDiskCache,
- kStyleSheetInMemoryCache,
- kStyleSheetCacheStatusCount,
-};
-
void LinkStyle::NotifyFinished(Resource* resource) {
if (!owner_->isConnected()) {
// While the stylesheet is asynchronously loading, the owner can be
@@ -63,7 +57,7 @@ void LinkStyle::NotifyFinished(Resource* resource) {
return;
}
- CSSStyleSheetResource* cached_style_sheet = ToCSSStyleSheetResource(resource);
+ auto* cached_style_sheet = To<CSSStyleSheetResource>(resource);
// See the comment in pending_script.cc about why this check is necessary
// here, instead of in the resource fetcher. https://crbug.com/500701.
if ((!cached_style_sheet->ErrorOccurred() &&
@@ -88,7 +82,9 @@ void LinkStyle::NotifyFinished(Resource* resource) {
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
GetDocument(), cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetResponse().IsCorsSameOrigin(),
- cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding());
+ Referrer(cached_style_sheet->GetResponse().ResponseUrl(),
+ cached_style_sheet->GetReferrerPolicy()),
+ cached_style_sheet->Encoding());
if (cached_style_sheet->GetResourceRequest().IsAdResource()) {
parser_context->SetIsAdRelated();
}
@@ -105,6 +101,7 @@ void LinkStyle::NotifyFinished(Resource* resource) {
loading_ = false;
parsed_sheet->CheckLoaded();
+ parsed_sheet->SetRenderBlocking(render_blocking_behavior_);
return;
}
@@ -121,6 +118,7 @@ void LinkStyle::NotifyFinished(Resource* resource) {
if (owner_->IsInDocumentTree())
SetSheetTitle(owner_->title());
+ style_sheet->SetRenderBlocking(render_blocking_behavior_);
style_sheet->ParseAuthorStyleSheet(cached_style_sheet);
loading_ = false;
@@ -286,20 +284,31 @@ LinkStyle::LoadReturnValue LinkStyle::LoadStylesheetIfNeeded(
media_query_matches = evaluator.Eval(*media);
}
+ bool is_in_body = owner_->IsDescendantOf(owner_->GetDocument().body());
+
// Don't hold up layout tree construction and script execution on
// stylesheets that are not needed for the layout at the moment.
- bool blocking = media_query_matches && !owner_->IsAlternate() &&
- owner_->IsCreatedByParser();
- AddPendingSheet(blocking ? kBlocking : kNonBlocking);
+ bool critical_style = media_query_matches && !owner_->IsAlternate();
+ bool render_blocking = critical_style && owner_->IsCreatedByParser();
+
+ AddPendingSheet(render_blocking ? kBlocking : kNonBlocking);
// Load stylesheets that are not needed for the layout immediately with low
// priority. When the link element is created by scripts, load the
// stylesheets asynchronously but in high priority.
FetchParameters::DeferOption defer_option =
- !media_query_matches || owner_->IsAlternate() ? FetchParameters::kLazyLoad
- : FetchParameters::kNoDefer;
-
- owner_->LoadStylesheet(params, charset, defer_option, this);
+ !critical_style ? FetchParameters::kLazyLoad : FetchParameters::kNoDefer;
+
+ render_blocking_behavior_ =
+ !critical_style
+ ? RenderBlockingBehavior::kNonBlocking
+ : (render_blocking
+ ? (is_in_body ? RenderBlockingBehavior::kInBodyParserBlocking
+ : RenderBlockingBehavior::kBlocking)
+ : RenderBlockingBehavior::kNonBlockingDynamic);
+
+ owner_->LoadStylesheet(params, charset, defer_option, this,
+ render_blocking_behavior_);
if (loading_ && !GetResource()) {
// Fetch() synchronous failure case.
diff --git a/chromium/third_party/blink/renderer/core/html/link_style.h b/chromium/third_party/blink/renderer/core/html/link_style.h
index 6175160db76..06c5b3bb55b 100644
--- a/chromium/third_party/blink/renderer/core/html/link_style.h
+++ b/chromium/third_party/blink/renderer/core/html/link_style.h
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/html/link_resource.h"
#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -75,6 +74,7 @@ class LinkStyle final : public LinkResource, ResourceClient {
Member<CSSStyleSheet> sheet_;
DisabledState disabled_state_;
PendingSheetType pending_sheet_type_;
+ RenderBlockingBehavior render_blocking_behavior_;
StyleEngineContext style_engine_context_;
bool explicitly_enabled_;
bool loading_;
diff --git a/chromium/third_party/blink/renderer/core/html/link_web_bundle.cc b/chromium/third_party/blink/renderer/core/html/link_web_bundle.cc
index a23b873e304..2524815ff95 100644
--- a/chromium/third_party/blink/renderer/core/html/link_web_bundle.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_web_bundle.cc
@@ -4,12 +4,15 @@
#include "third_party/blink/renderer/core/html/link_web_bundle.h"
+#include "base/unguessable_token.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.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/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
@@ -18,40 +21,54 @@
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
-#include "third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
-// WebBundleLoader is responsible for loading a WebBundle resource.
class WebBundleLoader : public GarbageCollected<WebBundleLoader>,
- public ThreadableLoaderClient {
+ public ThreadableLoaderClient,
+ public network::mojom::WebBundleHandle {
public:
WebBundleLoader(LinkWebBundle& link_web_bundle,
Document& document,
- const KURL& url)
+ const KURL& url,
+ CrossOriginAttributeValue cross_origin_attribute_value)
: link_web_bundle_(&link_web_bundle),
url_(url),
- security_origin_(SecurityOrigin::Create(url)) {
- blink::CrossVariantMojoReceiver<
- network::mojom::URLLoaderFactoryInterfaceBase>
- receiver(loader_factory_.BindNewPipeAndPassReceiver());
- document.GetFrame()
- ->Client()
- ->GetWebFrame()
- ->Client()
- ->MaybeProxyURLLoaderFactory(&receiver);
- pending_factory_receiver_ = std::move(receiver);
-
+ security_origin_(SecurityOrigin::Create(url)),
+ web_bundle_token_(base::UnguessableToken::Create()) {
ResourceRequest request(url);
request.SetUseStreamOnResponse(true);
// TODO(crbug.com/1082020): Revisit these once the fetch and process the
// linked resource algorithm [1] for <link rel=webbundle> is defined.
// [1]
// https://html.spec.whatwg.org/multipage/semantics.html#fetch-and-process-the-linked-resource
- request.SetRequestContext(mojom::blink::RequestContextType::SUBRESOURCE);
+ request.SetRequestContext(
+ mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE);
+
+ // https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md#requests-mode-and-credentials-mode
request.SetMode(network::mojom::blink::RequestMode::kCors);
- request.SetCredentialsMode(network::mojom::blink::CredentialsMode::kOmit);
+ switch (cross_origin_attribute_value) {
+ case kCrossOriginAttributeNotSet:
+ case kCrossOriginAttributeAnonymous:
+ request.SetCredentialsMode(
+ network::mojom::CredentialsMode::kSameOrigin);
+ break;
+ case kCrossOriginAttributeUseCredentials:
+ request.SetCredentialsMode(network::mojom::CredentialsMode::kInclude);
+ break;
+ }
+ request.SetRequestDestination(
+ network::mojom::RequestDestination::kWebBundle);
+ request.SetPriority(ResourceLoadPriority::kHigh);
+
+ mojo::PendingRemote<network::mojom::WebBundleHandle> web_bundle_handle;
+ web_bundle_handles_.Add(this,
+ web_bundle_handle.InitWithNewPipeAndPassReceiver());
+ request.SetWebBundleTokenParams(ResourceRequestHead::WebBundleTokenParams(
+ url_, web_bundle_token_, std::move(web_bundle_handle)));
ExecutionContext* execution_context = document.GetExecutionContext();
ResourceLoaderOptions resource_loader_options(
@@ -70,70 +87,64 @@ class WebBundleLoader : public GarbageCollected<WebBundleLoader>,
bool HasLoaded() const { return !failed_; }
- mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
- GetURLLoaderFactory() {
- mojo::PendingRemote<network::mojom::blink::URLLoaderFactory> factory_clone;
- loader_factory_->Clone(factory_clone.InitWithNewPipeAndPassReceiver());
- return factory_clone;
- }
-
// ThreadableLoaderClient
- void DidReceiveResponse(uint64_t, const ResourceResponse& response) override {
- if (!cors::IsOkStatus(response.HttpStatusCode()))
- failed_ = true;
- // TODO(crbug.com/1082020): Check response headers, as spec'ed in
- // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-serving-constraints.
- }
-
void DidStartLoadingResponseBody(BytesConsumer& consumer) override {
- DCHECK(pending_factory_receiver_);
- CreateWebBundleSubresourceLoaderFactory(
- std::move(pending_factory_receiver_), consumer.DrainAsDataPipe(),
- ConvertToBaseRepeatingCallback(
- CrossThreadBindRepeating(&WebBundleLoader::OnWebBundleError,
- WrapCrossThreadWeakPersistent(this))));
+ // Drain |consumer| so that DidFinishLoading is surely called later.
+ consumer.DrainAsDataPipe();
}
-
- void DidFinishLoading(uint64_t) override { link_web_bundle_->NotifyLoaded(); }
void DidFail(const ResourceError&) override { DidFailInternal(); }
void DidFailRedirectCheck() override { DidFailInternal(); }
+ // network::mojom::WebBundleHandle
+ void Clone(mojo::PendingReceiver<network::mojom::WebBundleHandle> receiver)
+ override {
+ web_bundle_handles_.Add(this, std::move(receiver));
+ }
+ void OnWebBundleError(network::mojom::WebBundleErrorType type,
+ const std::string& message) override {
+ link_web_bundle_->OnWebBundleError(url_.ElidedString() + ": " +
+ message.c_str());
+ }
+ void OnWebBundleLoadFinished(bool success) override {
+ if (failed_)
+ return;
+ failed_ = !success;
+ link_web_bundle_->NotifyLoaded();
+ }
+
const KURL& url() const { return url_; }
scoped_refptr<SecurityOrigin> GetSecurityOrigin() const {
return security_origin_;
}
+ const base::UnguessableToken& WebBundleToken() const {
+ return web_bundle_token_;
+ }
private:
void DidFailInternal() {
- if (pending_factory_receiver_) {
- // If we haven't create a WebBundleSubresourceLoaderFactory, create it
- // with an empty bundle body so that requests to
- // |pending_factory_receiver_| are processed (and fail).
- CreateWebBundleSubresourceLoaderFactory(
- std::move(pending_factory_receiver_),
- mojo::ScopedDataPipeConsumerHandle(), base::DoNothing());
- }
+ if (failed_)
+ return;
failed_ = true;
link_web_bundle_->NotifyLoaded();
}
- void OnWebBundleError(WebBundleErrorType type, const String& message) {
- // TODO(crbug.com/1082020): Dispatch "error" event on metadata parse error.
- // Simply setting |failed_| here does not work because DidFinishLoading()
- // may already be called.
- link_web_bundle_->OnWebBundleError(url_.ElidedString() + ": " + message);
- }
-
Member<LinkWebBundle> link_web_bundle_;
Member<ThreadableLoader> loader_;
- mojo::Remote<network::mojom::blink::URLLoaderFactory> loader_factory_;
- mojo::PendingReceiver<network::mojom::blink::URLLoaderFactory>
- pending_factory_receiver_;
bool failed_ = false;
KURL url_;
scoped_refptr<SecurityOrigin> security_origin_;
+ base::UnguessableToken web_bundle_token_;
+ // we need ReceiverSet here because WebBundleHandle is cloned when
+ // ResourceRequest is copied.
+ mojo::ReceiverSet<network::mojom::WebBundleHandle> web_bundle_handles_;
};
+// static
+bool LinkWebBundle::IsFeatureEnabled(const ExecutionContext* context) {
+ return context && context->IsSecureContext() &&
+ RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(context);
+}
+
LinkWebBundle::LinkWebBundle(HTMLLinkElement* owner) : LinkResource(owner) {
UseCounter::Count(owner_->GetDocument().GetExecutionContext(),
WebFeature::kSubresourceWebBundles);
@@ -172,9 +183,32 @@ void LinkWebBundle::Process() {
if (!resource_fetcher)
return;
+ // We don't support crossorigin= attribute's dynamic change. It seems
+ // other types of link elements doesn't support that too. See
+ // HTMLlinkElement::ParseAttribute, which doesn't call Process() for
+ // crossorigin= attribute change.
if (!bundle_loader_ || bundle_loader_->url() != owner_->Href()) {
+ if (resource_fetcher->ShouldBeLoadedFromWebBundle(owner_->Href())) {
+ // This can happen when a requested bundle is a nested bundle.
+ //
+ // clang-format off
+ // Example:
+ // <link rel="webbundle" href=".../nested-main.wbn" resources=".../nested-sub.wbn">
+ // <link rel="webbundle" href=".../nested-sub.wbn" resources="...">
+ // clang-format on
+ if (bundle_loader_) {
+ resource_fetcher->RemoveSubresourceWebBundle(*this);
+ bundle_loader_ = nullptr;
+ }
+ NotifyLoaded();
+ OnWebBundleError("A nested bundle is not supported: " +
+ owner_->Href().ElidedString());
+ return;
+ }
bundle_loader_ = MakeGarbageCollected<WebBundleLoader>(
- *this, owner_->GetDocument(), owner_->Href());
+ *this, owner_->GetDocument(), owner_->Href(),
+ GetCrossOriginAttributeValue(
+ owner_->FastGetAttribute(html_names::kCrossoriginAttr)));
}
resource_fetcher->AddSubresourceWebBundle(*this);
@@ -199,8 +233,12 @@ void LinkWebBundle::OwnerRemoved() {
}
bool LinkWebBundle::CanHandleRequest(const KURL& url) const {
- if (!owner_ || !owner_->ValidResourceUrls().Contains(url))
+ if (!url.IsValid())
+ return false;
+ if (!ResourcesOrScopesMatch(url))
return false;
+ if (url.Protocol() == "urn")
+ return true;
DCHECK(bundle_loader_);
if (!bundle_loader_->GetSecurityOrigin()->IsSameOriginWith(
SecurityOrigin::Create(url).get())) {
@@ -220,10 +258,16 @@ bool LinkWebBundle::CanHandleRequest(const KURL& url) const {
return true;
}
-mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
-LinkWebBundle::GetURLLoaderFactory() {
- DCHECK(bundle_loader_);
- return bundle_loader_->GetURLLoaderFactory();
+bool LinkWebBundle::ResourcesOrScopesMatch(const KURL& url) const {
+ if (!owner_)
+ return false;
+ if (owner_->ValidResourceUrls().Contains(url))
+ return true;
+ for (const auto& scope : owner_->ValidScopeUrls()) {
+ if (url.GetString().StartsWith(scope.GetString()))
+ return true;
+ }
+ return false;
}
String LinkWebBundle::GetCacheIdentifier() const {
@@ -231,6 +275,16 @@ String LinkWebBundle::GetCacheIdentifier() const {
return bundle_loader_->url().GetString();
}
+const KURL& LinkWebBundle::GetBundleUrl() const {
+ DCHECK(bundle_loader_);
+ return bundle_loader_->url();
+}
+
+const base::UnguessableToken& LinkWebBundle::WebBundleToken() const {
+ DCHECK(bundle_loader_);
+ return bundle_loader_->WebBundleToken();
+}
+
// static
KURL LinkWebBundle::ParseResourceUrl(const AtomicString& str) {
// The implementation is almost copy and paste from ParseExchangeURL() defined
@@ -246,10 +300,10 @@ KURL LinkWebBundle::ParseResourceUrl(const AtomicString& str) {
!url.Pass().IsEmpty())
return KURL();
- // For now, we allow only http: and https: schemes in Web Bundle URLs.
+ // For now, we allow only http:, https: and urn: schemes in Web Bundle URLs.
// TODO(crbug.com/966753): Revisit this once
// https://github.com/WICG/webpackage/issues/468 is resolved.
- if (!url.ProtocolIsInHTTPFamily())
+ if (!url.ProtocolIsInHTTPFamily() && !url.ProtocolIs("urn"))
return KURL();
return url;
diff --git a/chromium/third_party/blink/renderer/core/html/link_web_bundle.h b/chromium/third_party/blink/renderer/core/html/link_web_bundle.h
index dcfa286be4c..303cd6cdb1a 100644
--- a/chromium/third_party/blink/renderer/core/html/link_web_bundle.h
+++ b/chromium/third_party/blink/renderer/core/html/link_web_bundle.h
@@ -12,6 +12,10 @@
#include "third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+namespace base {
+class UnguessableToken;
+}
+
namespace blink {
class WebBundleLoader;
@@ -22,6 +26,8 @@ class WebBundleLoader;
class CORE_EXPORT LinkWebBundle final : public LinkResource,
public SubresourceWebBundle {
public:
+ static bool IsFeatureEnabled(const ExecutionContext*);
+
explicit LinkWebBundle(HTMLLinkElement* owner);
~LinkWebBundle() override;
@@ -41,9 +47,9 @@ class CORE_EXPORT LinkWebBundle final : public LinkResource,
// SubresourceWebBundle overrides:
bool CanHandleRequest(const KURL& url) const override;
- mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
- GetURLLoaderFactory() override;
String GetCacheIdentifier() const override;
+ const KURL& GetBundleUrl() const override;
+ const base::UnguessableToken& WebBundleToken() const override;
// Parse the given |str| as a url. If |str| doesn't meet the criteria which
// WebBundles specification requires, this returns invalid empty KURL as an
@@ -53,6 +59,8 @@ class CORE_EXPORT LinkWebBundle final : public LinkResource,
static KURL ParseResourceUrl(const AtomicString& str);
private:
+ bool ResourcesOrScopesMatch(const KURL& url) const;
+
Member<WebBundleLoader> bundle_loader_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/link_web_bundle_test.cc b/chromium/third_party/blink/renderer/core/html/link_web_bundle_test.cc
index 2d22d4bd180..32ac196e7bb 100644
--- a/chromium/third_party/blink/renderer/core/html/link_web_bundle_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/link_web_bundle_test.cc
@@ -7,6 +7,8 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_token_list.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
namespace blink {
@@ -18,7 +20,9 @@ void TestParseResourceUrl(const AtomicString& url, bool is_valid) {
} // namespace
-TEST(LinkWebBundleTest, ParseResourceUrl) {
+class LinkWebBundleTest : public SimTest {};
+
+TEST_F(LinkWebBundleTest, ParseResourceUrl) {
TestParseResourceUrl("https://test.example.com/", true);
TestParseResourceUrl("http://test.example.com/", true);
TestParseResourceUrl("https://user@test.example.com/", false);
@@ -28,10 +32,13 @@ TEST(LinkWebBundleTest, ParseResourceUrl) {
TestParseResourceUrl("file:///test.html", false);
}
-TEST(LinkWebBundleTest, ResourcesAttribute) {
- auto* document = Document::CreateForTest();
- auto* link =
- MakeGarbageCollected<HTMLLinkElement>(*document, CreateElementFlags());
+TEST_F(LinkWebBundleTest, ResourcesAttribute) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete("<!DOCTYPE html>");
+
+ auto* link = MakeGarbageCollected<HTMLLinkElement>(GetDocument(),
+ CreateElementFlags());
DOMTokenList* resources = link->resources();
EXPECT_EQ(g_null_atom, resources->value());
diff --git a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
index 1fb038cc305..1317bbda431 100644
--- a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
+++ b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.cc
@@ -4,8 +4,9 @@
#include "third_party/blink/renderer/core/html/list_item_ordinal.h"
-#include "base/numerics/clamped_math.h"
+#include "base/numerics/safe_conversions.h"
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/html/html_olist_element.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
@@ -74,7 +75,6 @@ ListItemOrdinal::NodeAndOrdinal ListItemOrdinal::NextListItem(
const Node* current = item ? item : list_node;
DCHECK(current);
- DCHECK(!current->GetDocument().ChildNeedsDistributionRecalc());
current = LayoutTreeBuilderTraversal::Next(*current, list_node);
while (current) {
@@ -102,7 +102,6 @@ ListItemOrdinal::NodeAndOrdinal ListItemOrdinal::PreviousListItem(
const Node* item) {
const Node* current = item;
DCHECK(current);
- DCHECK(!current->GetDocument().ChildNeedsDistributionRecalc());
for (current = LayoutTreeBuilderTraversal::Previous(*current, list_node);
current && current != list_node;
current = LayoutTreeBuilderTraversal::Previous(*current, list_node)) {
@@ -145,19 +144,27 @@ int ListItemOrdinal::CalcValue(const Node& item_node) const {
Node* list = EnclosingList(&item_node);
auto* o_list_element = DynamicTo<HTMLOListElement>(list);
- int value_step = 1;
- if (o_list_element && o_list_element->IsReversed())
- value_step = -1;
+ const bool is_reversed = o_list_element && o_list_element->IsReversed();
+ int value_step = is_reversed ? -1 : 1;
+ if (const auto* style = item_node.GetComputedStyle()) {
+ const auto directives =
+ style->GetCounterDirectives(AtomicString("list-item"));
+ if (directives.IsSet())
+ return directives.CombinedValue();
+ if (directives.IsIncrement())
+ value_step = directives.CombinedValue();
+ }
+ int64_t base_value = 0;
// FIXME: This recurses to a possible depth of the length of the list.
// That's not good -- we need to change this to an iterative algorithm.
- if (NodeAndOrdinal previous = PreviousListItem(list, &item_node))
- return base::ClampAdd(previous.ordinal->Value(*previous.node), value_step);
-
- if (o_list_element)
- return o_list_element->StartConsideringItemCount();
-
- return 1;
+ if (NodeAndOrdinal previous = PreviousListItem(list, &item_node)) {
+ base_value = previous.ordinal->Value(*previous.node);
+ } else if (o_list_element) {
+ base_value = o_list_element->StartConsideringItemCount();
+ base_value += (is_reversed ? 1 : -1);
+ }
+ return base::saturated_cast<int>(base_value + value_step);
}
int ListItemOrdinal::Value(const Node& item_node) const {
@@ -249,10 +256,8 @@ void ListItemOrdinal::InvalidateAllItemsForOrderedList(
// TODO(layout-dev): We should use layout tree traversal instead of flat tree
// traversal to invalidate ordinal number cache since lite items in unassigned
// slots don't have cached value. See http://crbug.com/844277 for details.
-void ListItemOrdinal::ItemInsertedOrRemoved(
- const LayoutObject* layout_list_item) {
- // If distribution recalc is needed, updateListMarkerNumber will be re-invoked
- // after distribution is calculated.
+void ListItemOrdinal::ItemUpdated(const LayoutObject* layout_list_item,
+ UpdateType type) {
const Node* item_node = layout_list_item->GetNode();
if (item_node->GetDocument().IsSlotAssignmentOrLegacyDistributionDirty())
return;
@@ -264,7 +269,8 @@ void ListItemOrdinal::ItemInsertedOrRemoved(
bool is_list_reversed = false;
if (auto* o_list_element = DynamicTo<HTMLOListElement>(list_node)) {
- o_list_element->ItemCountChanged();
+ if (type == kInsertedOrRemoved)
+ o_list_element->ItemCountChanged();
is_list_reversed = o_list_element->IsReversed();
}
@@ -276,7 +282,22 @@ void ListItemOrdinal::ItemInsertedOrRemoved(
if (list_node->NeedsReattachLayoutTree())
return;
+ if (type == kCounterStyle) {
+ ListItemOrdinal* ordinal = Get(*item_node);
+ DCHECK(ordinal);
+ ordinal->InvalidateSelf(*item_node);
+ }
InvalidateOrdinalsAfter(is_list_reversed, list_node, item_node);
}
+void ListItemOrdinal::ItemInsertedOrRemoved(
+ const LayoutObject* layout_list_item) {
+ ItemUpdated(layout_list_item, kInsertedOrRemoved);
+}
+
+void ListItemOrdinal::ItemCounterStyleUpdated(
+ const LayoutObject& layout_list_item) {
+ ItemUpdated(&layout_list_item, kCounterStyle);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.h b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.h
index 01d3cafd768..1042afaf1c2 100644
--- a/chromium/third_party/blink/renderer/core/html/list_item_ordinal.h
+++ b/chromium/third_party/blink/renderer/core/html/list_item_ordinal.h
@@ -51,6 +51,8 @@ class CORE_EXPORT ListItemOrdinal {
// Invalidate items that are affected by an insertion or a removal.
static void ItemInsertedOrRemoved(const LayoutObject*);
+ // Invalidate items that are affected by counter style update.
+ static void ItemCounterStyleUpdated(const LayoutObject&);
private:
enum ValueType { kNeedsUpdate, kUpdated, kExplicit };
@@ -82,6 +84,8 @@ class CORE_EXPORT ListItemOrdinal {
static void InvalidateOrdinalsAfter(bool is_reversed,
const Node* list_node,
const Node* item_node);
+ enum UpdateType { kInsertedOrRemoved, kCounterStyle };
+ static void ItemUpdated(const LayoutObject*, UpdateType type);
mutable int value_ = 0;
mutable unsigned type_ : 2; // ValueType
diff --git a/chromium/third_party/blink/renderer/core/html/media/DEPS b/chromium/third_party/blink/renderer/core/html/media/DEPS
index 18abf950027..a8906ade4a0 100644
--- a/chromium/third_party/blink/renderer/core/html/media/DEPS
+++ b/chromium/third_party/blink/renderer/core/html/media/DEPS
@@ -1,4 +1,14 @@
include_rules = [
"+media/base/logging_override_if_enabled.h",
+ "+media/base/media_content_type.h",
"+media/base/media_switches.h",
+ "+media/base/video_frame.h",
+ "+media/mojo/mojom/media_player.mojom-blink.h",
]
+
+specific_include_rules = {
+ # Tests need to wait to check mojo messages are correctly sent.
+ "html_media_element_test\.cc": [
+ "+base/run_loop.h",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/core/html/media/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/media/DIR_METADATA
new file mode 100644
index 00000000000..33fee42126b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Media"
+}
+
+team_email: "media-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/html/media/OWNERS b/chromium/third_party/blink/renderer/core/html/media/OWNERS
index 3d20d5d3962..2d282460822 100644
--- a/chromium/third_party/blink/renderer/core/html/media/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/media/OWNERS
@@ -1,4 +1 @@
mlamouri@chromium.org
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media
diff --git a/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.cc b/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.cc
new file mode 100644
index 00000000000..3a762f42161
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/media/audio_output_device_controller.h"
+
+namespace blink {
+
+// static
+const char AudioOutputDeviceController::kSupplementName[] =
+ "AudioOutputDeviceController";
+
+// static
+AudioOutputDeviceController* AudioOutputDeviceController::From(
+ HTMLMediaElement& element) {
+ return Supplement<HTMLMediaElement>::From<AudioOutputDeviceController>(
+ element);
+}
+
+void AudioOutputDeviceController::Trace(Visitor* visitor) const {
+ Supplement<HTMLMediaElement>::Trace(visitor);
+}
+
+AudioOutputDeviceController::AudioOutputDeviceController(
+ HTMLMediaElement& element)
+ : Supplement<HTMLMediaElement>(element) {}
+
+// static
+void AudioOutputDeviceController::ProvideTo(
+ HTMLMediaElement& element,
+ AudioOutputDeviceController* controller) {
+ Supplement<HTMLMediaElement>::ProvideTo(element, controller);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.h b/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.h
new file mode 100644
index 00000000000..1bbb2e76906
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/media/audio_output_device_controller.h
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_AUDIO_OUTPUT_DEVICE_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_AUDIO_OUTPUT_DEVICE_CONTROLLER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class CORE_EXPORT AudioOutputDeviceController
+ : public Supplement<HTMLMediaElement> {
+ public:
+ static const char kSupplementName[];
+
+ static AudioOutputDeviceController* From(HTMLMediaElement&);
+
+ virtual void SetSinkId(const String&) = 0;
+
+ void Trace(Visitor*) const override;
+
+ protected:
+ explicit AudioOutputDeviceController(HTMLMediaElement&);
+
+ // To be called by the implementation to register itself.
+ static void ProvideTo(HTMLMediaElement&, AudioOutputDeviceController*);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_MEDIA_AUDIO_OUTPUT_DEVICE_CONTROLLER_H_
diff --git a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index 98169739f2d..c5aaff6418f 100644
--- a/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -323,7 +323,9 @@ String AutoplayPolicy::GetPlayErrorMessage() const {
}
bool AutoplayPolicy::WasAutoplayInitiated() const {
- DCHECK(autoplay_initiated_.has_value());
+ if (!autoplay_initiated_.has_value())
+ return false;
+
return *autoplay_initiated_;
}
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
index 4ab449a7ca0..d5aefd079bf 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -36,11 +36,14 @@
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "media/base/logging_override_if_enabled.h"
+#include "media/base/media_content_type.h"
#include "media/base/media_switches.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.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/widget/screen_info.h"
+#include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-shared.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream.h"
#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h"
#include "third_party/blink/public/platform/platform.h"
@@ -53,6 +56,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/core_initializer.h"
+#include "third_party/blink/renderer/core/core_probes_inl.h"
#include "third_party/blink/renderer/core/css/media_list.h"
#include "third_party/blink/renderer/core/dom/attribute.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -68,9 +72,11 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/html_source_element.h"
+#include "third_party/blink/renderer/core/html/media/audio_output_device_controller.h"
#include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
#include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h"
#include "third_party/blink/renderer/core/html/media/media_controls.h"
@@ -531,7 +537,10 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
remote_playback_client_(nullptr),
media_controls_(nullptr),
controls_list_(MakeGarbageCollected<HTMLMediaElementControlsList>(this)),
- lazy_load_intersection_observer_(nullptr) {
+ lazy_load_intersection_observer_(nullptr),
+ media_player_host_remote_(GetExecutionContext()),
+ media_player_observer_remote_set_(GetExecutionContext()),
+ media_player_receiver_set_(this, GetExecutionContext()) {
DVLOG(1) << "HTMLMediaElement(" << *this << ")";
LocalFrame* frame = document.GetFrame();
@@ -1319,6 +1328,17 @@ void HTMLMediaElement::StartPlayerLoad() {
OnWebMediaPlayerCreated();
+ // Setup the communication channels between the renderer and browser processes
+ // via the MediaPlayer and MediaPlayerObserver mojo interfaces.
+ DCHECK(media_player_receiver_set_.empty());
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>
+ media_player_remote;
+ BindMediaPlayerReceiver(
+ media_player_remote.InitWithNewEndpointAndPassReceiver());
+
+ GetMediaPlayerHostRemote().OnMediaPlayerAdded(
+ std::move(media_player_remote), web_media_player_->GetDelegateId());
+
if (GetLayoutObject())
GetLayoutObject()->SetShouldDoFullPaintInvalidation();
// Make sure if we create/re-create the WebMediaPlayer that we update our
@@ -1334,7 +1354,11 @@ void HTMLMediaElement::StartPlayerLoad() {
web_media_player_->RequestRemotePlaybackDisabled(
FastHasAttribute(html_names::kDisableremoteplaybackAttr));
- auto load_timing = web_media_player_->Load(GetLoadType(), source, CorsMode());
+ bool is_cache_disabled = false;
+ probe::IsCacheDisabled(GetDocument().GetExecutionContext(),
+ &is_cache_disabled);
+ auto load_timing = web_media_player_->Load(GetLoadType(), source, CorsMode(),
+ is_cache_disabled);
if (load_timing == WebMediaPlayer::LoadTiming::kDeferred) {
// Deferred media loading is not part of the spec, but intuition is that
// this should not hold up the Window's "load" event (similar to user
@@ -1443,6 +1467,18 @@ bool HTMLMediaElement::PausedWhenVisible() const {
!GetWebMediaPlayer()->PausedWhenHidden();
}
+void HTMLMediaElement::DidAudioOutputSinkChanged(
+ const String& hashed_device_id) {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnAudioOutputSinkChanged(hashed_device_id);
+}
+
+void HTMLMediaElement::AddMediaPlayerObserverForTesting(
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerObserver>
+ observer) {
+ AddMediaPlayerObserver(std::move(observer));
+}
+
bool HTMLMediaElement::TextTracksAreReady() const {
// 4.8.12.11.1 Text track model
// ...
@@ -1928,6 +1964,8 @@ void HTMLMediaElement::SetReadyState(ReadyState state) {
jumped = true;
}
+ web_media_player_->SetAutoplayInitiated(true);
+
UpdateLayoutObject();
}
@@ -3438,11 +3476,6 @@ void HTMLMediaElement::DurationChanged(double duration, bool request_seek) {
Seek(duration);
}
-void HTMLMediaElement::RequestSeek(double time) {
- // The player is the source of this seek request.
- setCurrentTime(time);
-}
-
bool HTMLMediaElement::HasRemoteRoutes() const {
// TODO(mlamouri): used by MediaControlsPainter; should be refactored out.
return RemotePlaybackClient() &&
@@ -3644,7 +3677,13 @@ void HTMLMediaElement::
if (web_media_player_) {
audio_source_provider_.Wrap(nullptr);
web_media_player_.reset();
+
+ // The lifetime of the mojo endpoints are tied to the WebMediaPlayer's, so
+ // we need to reset those as well.
+ media_player_receiver_set_.Clear();
+ media_player_observer_remote_set_.Clear();
}
+ OnWebMediaPlayerCleared();
}
void HTMLMediaElement::ClearMediaPlayer() {
@@ -4082,13 +4121,33 @@ bool HTMLMediaElement::IsInteractiveContent() const {
return FastHasAttribute(html_names::kControlsAttr);
}
+void HTMLMediaElement::BindMediaPlayerReceiver(
+ mojo::PendingAssociatedReceiver<media::mojom::blink::MediaPlayer>
+ receiver) {
+ mojo::ReceiverId receiver_id = media_player_receiver_set_.Add(
+ std::move(receiver),
+ GetDocument().GetTaskRunner(TaskType::kInternalMedia));
+
+ media_player_receiver_set_.set_disconnect_handler(WTF::BindRepeating(
+ [](HTMLMediaElement* html_media_element, mojo::ReceiverId receiver_id) {
+ html_media_element->media_player_receiver_set_.Remove(receiver_id);
+ },
+ WrapWeakPersistent(this), receiver_id));
+}
+
void HTMLMediaElement::Trace(Visitor* visitor) const {
visitor->Trace(audio_source_node_);
+ visitor->Trace(load_timer_);
+ visitor->Trace(progress_event_timer_);
+ visitor->Trace(playback_progress_timer_);
+ visitor->Trace(audio_tracks_timer_);
+ visitor->Trace(removed_from_document_timer_);
visitor->Trace(played_time_ranges_);
visitor->Trace(async_event_queue_);
visitor->Trace(error_);
visitor->Trace(current_source_node_);
visitor->Trace(next_child_node_to_consider_);
+ visitor->Trace(deferred_load_timer_);
visitor->Trace(media_source_tracer_);
visitor->Trace(audio_tracks_);
visitor->Trace(video_tracks_);
@@ -4104,6 +4163,9 @@ void HTMLMediaElement::Trace(Visitor* visitor) const {
visitor->Trace(media_controls_);
visitor->Trace(controls_list_);
visitor->Trace(lazy_load_intersection_observer_);
+ visitor->Trace(media_player_host_remote_);
+ visitor->Trace(media_player_observer_remote_set_);
+ visitor->Trace(media_player_receiver_set_);
Supplementable<HTMLMediaElement>::Trace(visitor);
HTMLElement::Trace(visitor);
ExecutionContextLifecycleStateObserver::Trace(visitor);
@@ -4247,7 +4309,10 @@ void HTMLMediaElement::OnRemovedFromDocumentTimerFired(TimerBase*) {
if (InActiveDocument())
return;
- PauseInternal();
+ // Video should not pause when playing in Picture-in-Picture and subsequently
+ // removed from the Document.
+ if (!PictureInPictureController::IsElementInPictureInPicture(this))
+ PauseInternal();
}
void HTMLMediaElement::AudioSourceProviderImpl::Wrap(
@@ -4335,17 +4400,142 @@ bool HTMLMediaElement::WasAutoplayInitiated() {
return autoplay_policy_->WasAutoplayInitiated();
}
+void HTMLMediaElement::ResumePlayback() {
+ autoplay_policy_->EnsureAutoplayInitiatedSet();
+ PlayInternal();
+}
+
+void HTMLMediaElement::PausePlayback() {
+ PauseInternal();
+}
+
+void HTMLMediaElement::DidPlayerStartPlaying() {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnMediaPlaying();
+}
+
+void HTMLMediaElement::DidPlayerPaused(bool stream_ended) {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnMediaPaused(stream_ended);
+}
+
+void HTMLMediaElement::DidPlayerMutedStatusChange(bool muted) {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnMutedStatusChanged(muted);
+}
+
+void HTMLMediaElement::DidMediaMetadataChange(
+ bool has_audio,
+ bool has_video,
+ media::MediaContentType media_content_type) {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnMediaMetadataChanged(has_audio, has_video, media_content_type);
+}
+
+void HTMLMediaElement::DidPlayerMediaPositionStateChange(
+ double playback_rate,
+ base::TimeDelta duration,
+ base::TimeDelta position) {
+ for (auto& observer : media_player_observer_remote_set_) {
+ observer->OnMediaPositionStateChanged(
+ media_session::mojom::blink::MediaPosition::New(
+ playback_rate, duration, position, base::TimeTicks::Now()));
+ }
+}
+
+void HTMLMediaElement::DidDisableAudioOutputSinkChanges() {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnAudioOutputSinkChangingDisabled();
+}
+
+void HTMLMediaElement::DidPlayerSizeChange(const gfx::Size& size) {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnMediaSizeChanged(size);
+}
+
+void HTMLMediaElement::DidBufferUnderflow() {
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnBufferUnderflow();
+}
+
+void HTMLMediaElement::DidSeek() {
+ // Send the seek updates to the browser process only once per second.
+ if (last_seek_update_time_.is_null() ||
+ (base::TimeTicks::Now() - last_seek_update_time_ >=
+ base::TimeDelta::FromSeconds(1))) {
+ last_seek_update_time_ = base::TimeTicks::Now();
+ for (auto& observer : media_player_observer_remote_set_)
+ observer->OnSeek();
+ }
+}
+
+media::mojom::blink::MediaPlayerHost&
+HTMLMediaElement::GetMediaPlayerHostRemote() {
+ // It is an error to call this before having access to the document's frame.
+ DCHECK(GetDocument().GetFrame());
+ if (!media_player_host_remote_.is_bound()) {
+ GetDocument()
+ .GetFrame()
+ ->GetRemoteNavigationAssociatedInterfaces()
+ ->GetInterface(media_player_host_remote_.BindNewEndpointAndPassReceiver(
+ GetDocument().GetTaskRunner(TaskType::kInternalMedia)));
+ }
+ return *media_player_host_remote_.get();
+}
+
+void HTMLMediaElement::AddMediaPlayerObserver(
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerObserver>
+ observer) {
+ media_player_observer_remote_set_.Add(
+ std::move(observer),
+ GetDocument().GetTaskRunner(TaskType::kInternalMedia));
+
+ media_player_observer_remote_set_.set_disconnect_handler(WTF::BindRepeating(
+ [](HTMLMediaElement* html_media_element,
+ mojo::RemoteSetElementId remote_id) {
+ html_media_element->media_player_observer_remote_set_.Remove(remote_id);
+ },
+ WrapWeakPersistent(this)));
+}
+
void HTMLMediaElement::RequestPlay() {
+ LocalFrame* frame = GetDocument().GetFrame();
+ if (frame) {
+ LocalFrame::NotifyUserActivation(
+ frame, mojom::blink::UserActivationNotificationType::kInteraction);
+ }
autoplay_policy_->EnsureAutoplayInitiatedSet();
PlayInternal();
}
-void HTMLMediaElement::RequestPause() {
+void HTMLMediaElement::RequestPause(bool triggered_by_user) {
+ if (triggered_by_user) {
+ LocalFrame* frame = GetDocument().GetFrame();
+ if (frame) {
+ LocalFrame::NotifyUserActivation(
+ frame, mojom::blink::UserActivationNotificationType::kInteraction);
+ }
+ }
PauseInternal();
}
-void HTMLMediaElement::RequestMuted(bool muted) {
- setMuted(muted);
+void HTMLMediaElement::RequestSeekForward(base::TimeDelta seek_time) {
+ double seconds = seek_time.InSecondsF();
+ DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
+ setCurrentTime(currentTime() + seconds);
+}
+
+void HTMLMediaElement::RequestSeekBackward(base::TimeDelta seek_time) {
+ double seconds = seek_time.InSecondsF();
+ DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
+ setCurrentTime(currentTime() - seconds);
+}
+
+void HTMLMediaElement::SetAudioSinkId(const String& sink_id) {
+ auto* audio_output_controller = AudioOutputDeviceController::From(*this);
+ DCHECK(audio_output_controller);
+
+ audio_output_controller->SetSinkId(sink_id);
}
bool HTMLMediaElement::MediaShouldBeOpaque() const {
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element.h b/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
index 8d1149fc950..0424d5d2b8e 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -30,7 +30,9 @@
#include <memory>
#include "base/optional.h"
+#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
+#include "media/mojo/mojom/media_player.mojom-blink.h"
#include "third_party/blink/public/common/media/display_type.h"
#include "third_party/blink/public/platform/web_media_player_client.h"
#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
@@ -44,16 +46,24 @@
#include "third_party/blink/renderer/platform/audio/audio_source_provider.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/media/web_audio_source_provider_client.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace cc {
class Layer;
}
+namespace media {
+enum class MediaContentType;
+} // namespace media
+
namespace blink {
class AudioSourceProviderClient;
@@ -88,6 +98,7 @@ class CORE_EXPORT HTMLMediaElement
public Supplementable<HTMLMediaElement>,
public ActiveScriptWrappable<HTMLMediaElement>,
public ExecutionContextLifecycleStateObserver,
+ public media::mojom::blink::MediaPlayer,
private WebMediaPlayerClient {
DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(HTMLMediaElement, Dispose);
@@ -113,6 +124,12 @@ class CORE_EXPORT HTMLMediaElement
// for the given document.
static void OnMediaControlsEnabledChange(Document*);
+ // Binds |pending_receiver| and adds it to |media_player_receiver_set_|. Also
+ // called from other Blink classes (e.g. PictureInPictureControllerImpl).
+ void BindMediaPlayerReceiver(
+ mojo::PendingAssociatedReceiver<media::mojom::blink::MediaPlayer>
+ pending_receiver);
+
void Trace(Visitor*) const override;
WebMediaPlayer* GetWebMediaPlayer() const { return web_media_player_.get(); }
@@ -336,8 +353,15 @@ class CORE_EXPORT HTMLMediaElement
// becomes visible again.
bool PausedWhenVisible() const;
+ void DidAudioOutputSinkChanged(const String& hashed_device_id);
+
void SetCcLayerForTesting(cc::Layer* layer) { SetCcLayer(layer); }
+ // Required by tests set mock receivers to check that messages are delivered.
+ void AddMediaPlayerObserverForTesting(
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerObserver>
+ observer);
+
bool IsShowPosterFlagSet() const { return show_poster_flag_; }
protected:
@@ -348,6 +372,15 @@ class CORE_EXPORT HTMLMediaElement
~HTMLMediaElement() override;
void Dispose();
+ // Returns a constant reference to the HeapMojoAssociatedRemoteSet holding all
+ // the bound remotes for the media::mojom::blink::MediaPlayerObserver
+ // interface. Needed to allow sending messages directly from
+ // HTMLMediaElement's subclasses.
+ const HeapMojoAssociatedRemoteSet<media::mojom::blink::MediaPlayerObserver>&
+ GetMediaPlayerObserverRemoteSet() {
+ return media_player_observer_remote_set_;
+ }
+
void ParseAttribute(const AttributeModificationParams&) override;
void FinishParsingChildren() final;
bool IsURLAttribute(const Attribute&) const override;
@@ -369,14 +402,16 @@ class CORE_EXPORT HTMLMediaElement
// Called after the creation of |web_media_player_|.
virtual void OnWebMediaPlayerCreated() {}
+ virtual void OnWebMediaPlayerCleared() {}
void UpdateLayoutObject();
private:
// Friend class for testing.
friend class ContextMenuControllerTest;
- friend class VideoWakeLockTest;
+ friend class HTMLMediaElementTest;
friend class PictureInPictureControllerTest;
+ friend class VideoWakeLockTest;
bool HasPendingActivityInternal() const;
@@ -433,7 +468,6 @@ class CORE_EXPORT HTMLMediaElement
void AddTextTrack(WebInbandTextTrack*) final;
void RemoveTextTrack(WebInbandTextTrack*) final;
void MediaSourceOpened(WebMediaSource*) final;
- void RequestSeek(double) final;
void RemotePlaybackCompatibilityChanged(const WebURL&,
bool is_compatible) final;
void OnBecamePersistentVideo(bool) override {}
@@ -450,11 +484,39 @@ class CORE_EXPORT HTMLMediaElement
gfx::ColorSpace TargetColorSpace() override;
bool WasAutoplayInitiated() override;
bool IsInAutoPIP() const override { return false; }
- void RequestPlay() final;
- void RequestPause() final;
- void RequestMuted(bool muted) final;
+ void ResumePlayback() final;
+ void PausePlayback() final;
+ void DidPlayerStartPlaying() override;
+ void DidPlayerPaused(bool stream_ended) override;
+ void DidPlayerMutedStatusChange(bool muted) override;
+ void DidMediaMetadataChange(
+ bool has_audio,
+ bool has_video,
+ media::MediaContentType media_content_type) override;
+ void DidPlayerMediaPositionStateChange(double playback_rate,
+ base::TimeDelta duration,
+ base::TimeDelta position) override;
+ void DidDisableAudioOutputSinkChanges() override;
+ void DidPlayerSizeChange(const gfx::Size& size) override;
+ void DidBufferUnderflow() override;
+ void DidSeek() override;
+
+ // Returns a reference to the mojo remote for the MediaPlayerHost interface,
+ // requesting it first from the BrowserInterfaceBroker if needed. It is an
+ // error to call this method before having access to the document's frame.
+ media::mojom::blink::MediaPlayerHost& GetMediaPlayerHostRemote();
+
+ // media::mojom::MediaPlayer implementation.
+ void AddMediaPlayerObserver(
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayerObserver>
+ observer) override;
+ void RequestPlay() override;
+ void RequestPause(bool triggered_by_user) override;
+ void RequestSeekForward(base::TimeDelta seek_time) override;
+ void RequestSeekBackward(base::TimeDelta seek_time) override;
void RequestEnterPictureInPicture() override {}
void RequestExitPictureInPicture() override {}
+ void SetAudioSinkId(const String&) override;
void LoadTimerFired(TimerBase*);
void ProgressEventTimerFired(TimerBase*);
@@ -571,11 +633,11 @@ class CORE_EXPORT HTMLMediaElement
Features GetFeatures() override;
- TaskRunnerTimer<HTMLMediaElement> load_timer_;
- TaskRunnerTimer<HTMLMediaElement> progress_event_timer_;
- TaskRunnerTimer<HTMLMediaElement> playback_progress_timer_;
- TaskRunnerTimer<HTMLMediaElement> audio_tracks_timer_;
- TaskRunnerTimer<HTMLMediaElement> removed_from_document_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> load_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> progress_event_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> playback_progress_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> audio_tracks_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> removed_from_document_timer_;
Member<TimeRanges> played_time_ranges_;
Member<EventQueue> async_event_queue_;
@@ -632,7 +694,7 @@ class CORE_EXPORT HTMLMediaElement
kExecuteOnStopDelayingLoadEventTask
};
DeferredLoadState deferred_load_state_;
- TaskRunnerTimer<HTMLMediaElement> deferred_load_timer_;
+ HeapTaskRunnerTimer<HTMLMediaElement> deferred_load_timer_;
std::unique_ptr<WebMediaPlayer> web_media_player_;
cc::Layer* cc_layer_;
@@ -685,6 +747,9 @@ class CORE_EXPORT HTMLMediaElement
// playback raters other than 1.0.
bool preserves_pitch_ = true;
+ // Keeps track of when the player seek event was sent to the browser process.
+ base::TimeTicks last_seek_update_time_;
+
Member<AudioTrackList> audio_tracks_;
Member<VideoTrackList> video_tracks_;
Member<TextTrackList> text_tracks_;
@@ -771,6 +836,22 @@ class CORE_EXPORT HTMLMediaElement
Member<HTMLMediaElementControlsList> controls_list_;
Member<IntersectionObserver> lazy_load_intersection_observer_;
+
+ HeapMojoAssociatedRemote<media::mojom::blink::MediaPlayerHost>
+ media_player_host_remote_;
+
+ // Multiple objects outside of the renderer process can register as observers,
+ // so we need to store the remotes in a set here.
+ HeapMojoAssociatedRemoteSet<media::mojom::blink::MediaPlayerObserver>
+ media_player_observer_remote_set_;
+
+ // A receiver set is needed here as there will be different objects in the
+ // browser communicating with this object. This is done this way to avoid
+ // routing everything through a single class (e.g. RFHI) and to keep this
+ // logic contained inside MediaPlayer-related classes.
+ HeapMojoAssociatedReceiverSet<media::mojom::blink::MediaPlayer,
+ HTMLMediaElement>
+ media_player_receiver_set_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index f1e5dba46ed..0c4ad27a6be 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -4,7 +4,10 @@
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "base/run_loop.h"
#include "base/test/gtest_util.h"
+#include "media/base/media_content_type.h"
+#include "media/mojo/mojom/media_player.mojom-blink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/autoplay/autoplay.mojom-blink.h"
@@ -26,6 +29,7 @@
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "ui/gfx/geometry/size.h"
using ::testing::_;
using ::testing::AnyNumber;
@@ -50,11 +54,12 @@ class MockWebMediaPlayer : public EmptyWebMediaPlayer {
MOCK_METHOD1(SetLatencyHint, void(double));
MOCK_METHOD1(EnabledAudioTracksChanged, void(const WebVector<TrackId>&));
MOCK_METHOD1(SelectedVideoTrackChanged, void(TrackId*));
- MOCK_METHOD3(
+ MOCK_METHOD4(
Load,
WebMediaPlayer::LoadTiming(LoadType load_type,
const blink::WebMediaPlayerSource& source,
- CorsMode cors_mode));
+ CorsMode cors_mode,
+ bool is_cache_disabled));
MOCK_CONST_METHOD0(DidLazyLoad, bool());
MOCK_METHOD0(GetSrcAfterRedirects, GURL());
@@ -77,6 +82,122 @@ class WebMediaStubLocalFrameClient : public EmptyLocalFrameClient {
std::unique_ptr<WebMediaPlayer> player_;
};
+// Helper class that provides an implementation of the MediaPlayerObserver mojo
+// interface to allow checking that messages sent over mojo are received with
+// the right values in the other end.
+//
+// Note this relies on HTMLMediaElement::AddMediaPlayerObserverForTesting() to
+// provide the HTMLMediaElement instance owned by the test with a valid mojo
+// remote, that will be bound to the mojo receiver provided by this class
+// instead of the real one used in production that would be owned by
+// MediaSessionController instead.
+class MockMediaPlayerObserverReceiverForTesting
+ : public media::mojom::blink::MediaPlayerObserver {
+ public:
+ struct OnMetadataChangedResult {
+ bool has_audio;
+ bool has_video;
+ media::MediaContentType media_content_type;
+ };
+
+ explicit MockMediaPlayerObserverReceiverForTesting(
+ HTMLMediaElement* html_media_element) {
+ // Bind the remote to the receiver, so that we can intercept incoming
+ // messages sent via the different methods that use the remote.
+ html_media_element->AddMediaPlayerObserverForTesting(
+ receiver_.BindNewEndpointAndPassDedicatedRemote());
+ }
+
+ // Needs to be called from tests after invoking a method from the MediaPlayer
+ // mojo interface, so that we have enough time to process the message.
+ void WaitUntilReceivedMessage() {
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+
+ // media::mojom::blink::MediaPlayerObserver implementation.
+ void OnMediaPlaying() override {
+ received_media_playing_ = true;
+ run_loop_->Quit();
+ }
+
+ void OnMediaPaused(bool stream_ended) override {
+ received_media_paused_stream_ended_ = stream_ended;
+ run_loop_->Quit();
+ }
+
+ void OnMutedStatusChanged(bool muted) override {
+ received_muted_status_type_ = muted;
+ run_loop_->Quit();
+ }
+
+ void OnMediaMetadataChanged(bool has_audio,
+ bool has_video,
+ media::MediaContentType content_type) override {
+ // struct OnMetadataChangedResult result{has_audio, has_video,
+ // content_type};
+ received_metadata_changed_result_ =
+ OnMetadataChangedResult{has_audio, has_video, content_type};
+ run_loop_->Quit();
+ }
+
+ void OnMediaPositionStateChanged(
+ ::media_session::mojom::blink::MediaPositionPtr) override {}
+
+ void OnMediaEffectivelyFullscreenChanged(
+ blink::WebFullscreenVideoStatus status) override {}
+
+ void OnMediaSizeChanged(const gfx::Size& size) override {
+ received_media_size_ = size;
+ run_loop_->Quit();
+ }
+
+ void OnPictureInPictureAvailabilityChanged(bool available) override {}
+
+ void OnAudioOutputSinkChanged(const WTF::String& hashed_device_id) override {}
+
+ void OnAudioOutputSinkChangingDisabled() override {}
+
+ void OnBufferUnderflow() override {
+ received_buffer_underflow_ = true;
+ run_loop_->Quit();
+ }
+
+ void OnSeek() override {}
+
+ // Getters used from HTMLMediaElementTest.
+ bool received_media_playing() const { return received_media_playing_; }
+
+ const base::Optional<bool>& received_media_paused_stream_ended() const {
+ return received_media_paused_stream_ended_;
+ }
+
+ const base::Optional<bool>& received_muted_status() const {
+ return received_muted_status_type_;
+ }
+
+ const base::Optional<OnMetadataChangedResult>&
+ received_metadata_changed_result() const {
+ return received_metadata_changed_result_;
+ }
+
+ gfx::Size received_media_size() const { return received_media_size_; }
+
+ bool received_buffer_underflow() const { return received_buffer_underflow_; }
+
+ private:
+ std::unique_ptr<base::RunLoop> run_loop_;
+ mojo::AssociatedReceiver<media::mojom::blink::MediaPlayerObserver> receiver_{
+ this};
+ bool received_media_playing_{false};
+ base::Optional<bool> received_media_paused_stream_ended_;
+ base::Optional<bool> received_muted_status_type_;
+ base::Optional<OnMetadataChangedResult> received_metadata_changed_result_;
+ gfx::Size received_media_size_{0, 0};
+ bool received_buffer_underflow_{false};
+};
+
enum class MediaTestParam { kAudio, kVideo };
} // namespace
@@ -96,7 +217,7 @@ class HTMLMediaElementTest : public testing::TestWithParam<MediaTestParam> {
EXPECT_CALL(*mock_media_player, HasVideo()).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_media_player, Duration()).WillRepeatedly(Return(1.0));
EXPECT_CALL(*mock_media_player, CurrentTime()).WillRepeatedly(Return(0));
- EXPECT_CALL(*mock_media_player, Load(_, _, _))
+ EXPECT_CALL(*mock_media_player, Load(_, _, _, _))
.Times(AnyNumber())
.WillRepeatedly(Return(WebMediaPlayer::LoadTiming::kImmediate));
EXPECT_CALL(*mock_media_player, DidLazyLoad).WillRepeatedly(Return(false));
@@ -118,6 +239,9 @@ class HTMLMediaElementTest : public testing::TestWithParam<MediaTestParam> {
media_ = MakeGarbageCollected<HTMLVideoElement>(
dummy_page_holder_->GetDocument());
}
+
+ media_player_observer_receiver_ =
+ std::make_unique<MockMediaPlayerObserverReceiverForTesting>(Media());
}
HTMLMediaElement* Media() const { return media_.Get(); }
@@ -161,12 +285,81 @@ class HTMLMediaElementTest : public testing::TestWithParam<MediaTestParam> {
return dummy_page_holder_->GetFrame().DomWindow();
}
+ protected:
+ // Helpers to call MediaPlayerObserver mojo methods and check their results.
+ void NotifyMediaPlaying() {
+ media_->DidPlayerStartPlaying();
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageMediaPlaying() {
+ return media_player_observer_receiver_->received_media_playing();
+ }
+
+ void NotifyMediaPaused(bool stream_ended) {
+ media_->DidPlayerPaused(stream_ended);
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageMediaPaused(bool stream_ended) {
+ return media_player_observer_receiver_
+ ->received_media_paused_stream_ended() == stream_ended;
+ }
+
+ void NotifyMutedStatusChange(bool muted) {
+ media_->DidPlayerMutedStatusChange(muted);
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageMutedStatusChange(bool muted) {
+ return media_player_observer_receiver_->received_muted_status() == muted;
+ }
+
+ void NotifyMediaMetadataChanged(bool has_audio,
+ bool has_video,
+ media::MediaContentType media_content_type) {
+ media_->DidMediaMetadataChange(has_audio, has_video, media_content_type);
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageMediaMetadataChanged(
+ bool has_audio,
+ bool has_video,
+ media::MediaContentType media_content_type) {
+ const auto& result =
+ media_player_observer_receiver_->received_metadata_changed_result();
+ return result->has_audio == has_audio && result->has_video == has_video &&
+ result->media_content_type == media_content_type;
+ }
+
+ void NotifyMediaSizeChange(const gfx::Size& size) {
+ media_->DidPlayerSizeChange(size);
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageMediaSizeChange(const gfx::Size& size) {
+ return media_player_observer_receiver_->received_media_size() == size;
+ }
+
+ void NotifyBufferUnderflowEvent() {
+ media_->DidBufferUnderflow();
+ media_player_observer_receiver_->WaitUntilReceivedMessage();
+ }
+
+ bool ReceivedMessageBufferUnderflowEvent() {
+ return media_player_observer_receiver_->received_buffer_underflow();
+ }
+
private:
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
Persistent<HTMLMediaElement> media_;
// Owned by WebMediaStubLocalFrameClient.
MockWebMediaPlayer* media_player_;
+
+ // Used to check that mojo messages are received in the other end.
+ std::unique_ptr<MockMediaPlayerObserverReceiverForTesting>
+ media_player_observer_receiver_;
};
INSTANTIATE_TEST_SUITE_P(Audio,
@@ -466,7 +659,7 @@ TEST_P(HTMLMediaElementTest,
// WebMediaPlayer will signal that it will defer loading to some later time.
testing::Mock::VerifyAndClearExpectations(MockMediaPlayer());
- EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _))
+ EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _, _))
.WillOnce(Return(WebMediaPlayer::LoadTiming::kDeferred));
// Window's 'load' event starts out "delayed".
@@ -484,7 +677,7 @@ TEST_P(HTMLMediaElementTest, ImmediateMediaPlayerLoadDoesDelayWindowLoadEvent) {
Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
// WebMediaPlayer will signal that it will do the load immediately.
- EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _))
+ EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _, _))
.WillOnce(Return(WebMediaPlayer::LoadTiming::kImmediate));
// Window's 'load' event starts out "delayed".
@@ -552,7 +745,9 @@ TEST_P(HTMLMediaElementTest, GcMarkingNoAllocWebTimeRanges) {
ThreadState::NoAllocationScope no_allocation_scope(thread_state);
EXPECT_FALSE(thread_state->IsAllocationAllowed());
// Use of TimeRanges is not allowed during GC marking (crbug.com/970150)
- EXPECT_DCHECK_DEATH(MakeGarbageCollected<TimeRanges>(0, 0));
+#if DCHECK_IS_ON()
+ EXPECT_DEATH_IF_SUPPORTED(MakeGarbageCollected<TimeRanges>(0, 0), "");
+#endif // DCHECK_IS_ON()
// Instead of using TimeRanges, WebTimeRanges can be used without GC
Vector<WebTimeRanges> ranges;
ranges.emplace_back();
@@ -793,4 +988,54 @@ TEST_P(HTMLMediaElementTest, ShowPosterFlag_FalseAfterPlayBeforeReady) {
EXPECT_FALSE(Media()->IsShowPosterFlagSet());
}
+TEST_P(HTMLMediaElementTest, SendMediaPlayingToObserver) {
+ NotifyMediaPlaying();
+ EXPECT_TRUE(ReceivedMessageMediaPlaying());
+}
+
+TEST_P(HTMLMediaElementTest, SendMediaPausedToObserver) {
+ NotifyMediaPaused(true);
+ EXPECT_TRUE(ReceivedMessageMediaPaused(true));
+
+ NotifyMediaPaused(false);
+ EXPECT_TRUE(ReceivedMessageMediaPaused(false));
+}
+
+TEST_P(HTMLMediaElementTest, SendMutedStatusChangeToObserver) {
+ NotifyMutedStatusChange(true);
+ EXPECT_TRUE(ReceivedMessageMutedStatusChange(true));
+
+ NotifyMutedStatusChange(false);
+ EXPECT_TRUE(ReceivedMessageMutedStatusChange(false));
+}
+
+TEST_P(HTMLMediaElementTest, SendMediaMetadataChangedToObserver) {
+ bool has_audio = false;
+ bool has_video = true;
+ media::MediaContentType media_content_type =
+ media::MediaContentType::Transient;
+
+ NotifyMediaMetadataChanged(has_audio, has_video, media_content_type);
+ EXPECT_TRUE(ReceivedMessageMediaMetadataChanged(has_audio, has_video,
+ media_content_type));
+ // Change values and test again.
+ has_audio = true;
+ has_video = false;
+ media_content_type = media::MediaContentType::OneShot;
+ NotifyMediaMetadataChanged(has_audio, has_video, media_content_type);
+ EXPECT_TRUE(ReceivedMessageMediaMetadataChanged(has_audio, has_video,
+ media_content_type));
+}
+
+TEST_P(HTMLMediaElementTest, SendMediaSizeChangeToObserver) {
+ const gfx::Size kTestMediaSizeChangedValue(16, 9);
+ NotifyMediaSizeChange(kTestMediaSizeChangedValue);
+ EXPECT_TRUE(ReceivedMessageMediaSizeChange(kTestMediaSizeChangedValue));
+}
+
+TEST_P(HTMLMediaElementTest, SendBufferOverflowToObserver) {
+ NotifyBufferUnderflowEvent();
+ EXPECT_TRUE(ReceivedMessageBufferUnderflowEvent());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
index da233001ac4..550f35b0b75 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -30,6 +30,7 @@
#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "cc/paint/paint_canvas.h"
+#include "media/base/video_frame.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_fullscreen_options.h"
@@ -57,9 +58,10 @@
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.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/web_test_support.h"
@@ -177,12 +179,19 @@ void HTMLVideoElement::CollectStyleForPresentationAttribute(
const QualifiedName& name,
const AtomicString& value,
MutableCSSPropertyValueSet* style) {
- if (name == html_names::kWidthAttr)
+ if (name == html_names::kWidthAttr) {
AddHTMLLengthToStyle(style, CSSPropertyID::kWidth, value);
- else if (name == html_names::kHeightAttr)
+ const AtomicString& height = FastGetAttribute(html_names::kHeightAttr);
+ if (height)
+ ApplyAspectRatioToStyle(value, height, style);
+ } else if (name == html_names::kHeightAttr) {
AddHTMLLengthToStyle(style, CSSPropertyID::kHeight, value);
- else
+ const AtomicString& width = FastGetAttribute(html_names::kWidthAttr);
+ if (width)
+ ApplyAspectRatioToStyle(width, value, style);
+ } else {
HTMLMediaElement::CollectStyleForPresentationAttribute(name, value, style);
+ }
}
bool HTMLVideoElement::IsPresentationAttribute(
@@ -259,8 +268,8 @@ void HTMLVideoElement::UpdatePictureInPictureAvailability() {
if (!web_media_player_)
return;
- web_media_player_->OnPictureInPictureAvailabilityChanged(
- SupportsPictureInPicture());
+ for (auto& observer : GetMediaPlayerObserverRemoteSet())
+ observer->OnPictureInPictureAvailabilityChanged(SupportsPictureInPicture());
}
// TODO(zqzhang): this callback could be used to hide native controls instead of
@@ -358,12 +367,20 @@ void HTMLVideoElement::OnLoadFinished() {
UpdatePictureInPictureAvailability();
}
-void HTMLVideoElement::PaintCurrentFrame(
- cc::PaintCanvas* canvas,
- const IntRect& dest_rect,
- const PaintFlags* flags,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) const {
+void HTMLVideoElement::RequestEnterPictureInPicture() {
+ PictureInPictureController::From(GetDocument())
+ .EnterPictureInPicture(this, nullptr /* promise */,
+ nullptr /* options */);
+}
+
+void HTMLVideoElement::RequestExitPictureInPicture() {
+ PictureInPictureController::From(GetDocument())
+ .ExitPictureInPicture(this, nullptr);
+}
+
+void HTMLVideoElement::PaintCurrentFrame(cc::PaintCanvas* canvas,
+ const IntRect& dest_rect,
+ const PaintFlags* flags) const {
if (!GetWebMediaPlayer())
return;
@@ -376,81 +393,7 @@ void HTMLVideoElement::PaintCurrentFrame(
media_flags.setBlendMode(SkBlendMode::kSrc);
}
- GetWebMediaPlayer()->Paint(canvas, dest_rect, media_flags,
- already_uploaded_id, out_metadata);
-}
-
-bool HTMLVideoElement::CopyVideoTextureToPlatformTexture(
- gpu::gles2::GLES2Interface* gl,
- GLenum target,
- GLuint texture,
- GLenum internal_format,
- GLenum format,
- GLenum type,
- GLint level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
- if (!GetWebMediaPlayer())
- return false;
-
- return GetWebMediaPlayer()->CopyVideoTextureToPlatformTexture(
- gl, target, texture, internal_format, format, type, level,
- premultiply_alpha, flip_y, already_uploaded_id, out_metadata);
-}
-
-bool HTMLVideoElement::CopyVideoYUVDataToPlatformTexture(
- gpu::gles2::GLES2Interface* gl,
- GLenum target,
- GLuint texture,
- GLenum internal_format,
- GLenum format,
- GLenum type,
- GLint level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
- if (!GetWebMediaPlayer())
- return false;
-
- return GetWebMediaPlayer()->CopyVideoYUVDataToPlatformTexture(
- gl, target, texture, internal_format, format, type, level,
- premultiply_alpha, flip_y, already_uploaded_id, out_metadata);
-}
-
-bool HTMLVideoElement::TexImageImpl(
- WebMediaPlayer::TexImageFunctionID function_id,
- GLenum target,
- gpu::gles2::GLES2Interface* gl,
- GLuint texture,
- GLint level,
- GLint internalformat,
- GLenum format,
- GLenum type,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- bool flip_y,
- bool premultiply_alpha) {
- if (!GetWebMediaPlayer())
- return false;
- return GetWebMediaPlayer()->TexImageImpl(
- function_id, target, gl, texture, level, internalformat, format, type,
- xoffset, yoffset, zoffset, flip_y, premultiply_alpha);
-}
-
-bool HTMLVideoElement::PrepareVideoFrameForWebGL(
- gpu::gles2::GLES2Interface* gl,
- GLenum target,
- GLuint texture,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
- if (!GetWebMediaPlayer())
- return false;
- return GetWebMediaPlayer()->PrepareVideoFrameForWebGL(
- gl, target, texture, already_uploaded_id, out_metadata);
+ GetWebMediaPlayer()->Paint(canvas, dest_rect, media_flags);
}
bool HTMLVideoElement::HasAvailableVideoFrame() const {
@@ -565,28 +508,53 @@ KURL HTMLVideoElement::PosterImageURL() const {
return GetDocument().CompleteURL(url);
}
-scoped_refptr<Image> HTMLVideoElement::GetSourceImageForCanvas(
- SourceImageStatus* status,
- const FloatSize&) {
- if (!HasAvailableVideoFrame()) {
- *status = kInvalidSourceImageStatus;
- return nullptr;
+bool HTMLVideoElement::IsDefaultPosterImageURL() const {
+ return ImageSourceURL() == default_poster_url_;
+}
+
+scoped_refptr<StaticBitmapImage> HTMLVideoElement::CreateStaticBitmapImage(
+ bool allow_accelerated_images) {
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+ scoped_refptr<media::VideoFrame> media_video_frame;
+ if (auto* wmp = GetWebMediaPlayer()) {
+ media_video_frame = wmp->GetCurrentFrame();
+ video_renderer = wmp->GetPaintCanvasVideoRenderer();
}
- IntSize intrinsic_size(videoWidth(), videoHeight());
- // TODO(fserb): this should not be default software.
- std::unique_ptr<CanvasResourceProvider> resource_provider =
- CanvasResourceProvider::CreateBitmapProvider(
- intrinsic_size, kLow_SkFilterQuality, CanvasColorParams(),
- CanvasResourceProvider::ShouldInitialize::kNo);
- if (!resource_provider) {
- *status = kInvalidSourceImageStatus;
+ if (!media_video_frame || !video_renderer)
return nullptr;
+
+ const auto intrinsic_size = IntSize(media_video_frame->natural_size());
+ if (!resource_provider_ ||
+ allow_accelerated_images != resource_provider_->IsAccelerated() ||
+ intrinsic_size != resource_provider_->Size()) {
+ viz::RasterContextProvider* raster_context_provider = nullptr;
+ if (allow_accelerated_images) {
+ if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
+ if (auto* context_provider = wrapper->ContextProvider())
+ raster_context_provider = context_provider->RasterContextProvider();
+ }
+ }
+ // Providing a null |raster_context_provider| creates a software provider.
+ resource_provider_ = CreateResourceProviderForVideoFrame(
+ intrinsic_size, raster_context_provider);
+ if (!resource_provider_)
+ return nullptr;
}
- PaintCurrentFrame(resource_provider->Canvas(),
- IntRect(IntPoint(0, 0), intrinsic_size), nullptr);
- scoped_refptr<Image> snapshot = resource_provider->Snapshot();
+ const auto dest_rect = gfx::Rect(media_video_frame->natural_size());
+ auto image = CreateImageFromVideoFrame(std::move(media_video_frame),
+ /*allow_zero_copy_images=*/true,
+ resource_provider_.get(),
+ video_renderer, dest_rect);
+ image->SetOriginClean(!WouldTaintOrigin());
+ return image;
+}
+
+scoped_refptr<Image> HTMLVideoElement::GetSourceImageForCanvas(
+ SourceImageStatus* status,
+ const FloatSize&) {
+ scoped_refptr<Image> snapshot = CreateStaticBitmapImage();
if (!snapshot) {
*status = kInvalidSourceImageStatus;
return nullptr;
@@ -672,17 +640,6 @@ bool HTMLVideoElement::IsInAutoPIP() const {
return is_auto_picture_in_picture_;
}
-void HTMLVideoElement::RequestEnterPictureInPicture() {
- PictureInPictureController::From(GetDocument())
- .EnterPictureInPicture(this, nullptr /* promise */,
- nullptr /* options */);
-}
-
-void HTMLVideoElement::RequestExitPictureInPicture() {
- PictureInPictureController::From(GetDocument())
- .ExitPictureInPicture(this, nullptr);
-}
-
void HTMLVideoElement::OnPictureInPictureStateChange() {
if (GetDisplayType() != DisplayType::kPictureInPicture || IsInAutoPIP()) {
return;
@@ -726,6 +683,9 @@ void HTMLVideoElement::SetIsEffectivelyFullscreen(
is_effectively_fullscreen_ =
status != blink::WebFullscreenVideoStatus::kNotEffectivelyFullscreen;
if (GetWebMediaPlayer()) {
+ for (auto& observer : GetMediaPlayerObserverRemoteSet())
+ observer->OnMediaEffectivelyFullscreenChanged(status);
+
GetWebMediaPlayer()->SetIsEffectivelyFullscreen(status);
GetWebMediaPlayer()->OnDisplayTypeChanged(GetDisplayType());
}
@@ -780,6 +740,13 @@ void HTMLVideoElement::OnWebMediaPlayerCreated() {
}
}
+void HTMLVideoElement::OnWebMediaPlayerCleared() {
+ if (RuntimeEnabledFeatures::RequestVideoFrameCallbackEnabled()) {
+ if (auto* vfc_requester = VideoFrameCallbackRequester::From(*this))
+ vfc_requester->OnWebMediaPlayerCleared();
+ }
+}
+
void HTMLVideoElement::AttributeChanged(
const AttributeModificationParams& params) {
HTMLElement::AttributeChanged(params);
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element.h b/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
index 0c87312aff6..a7af2fc68c0 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -33,20 +33,16 @@
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/khronos/GLES2/gl2.h"
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
namespace blink {
class ImageBitmapOptions;
class IntersectionObserverEntry;
class MediaCustomControlsFullscreenDetector;
class MediaRemotingInterstitial;
class PictureInPictureInterstitial;
+class StaticBitmapImage;
class VideoWakeLock;
class CORE_EXPORT HTMLVideoElement final
@@ -93,68 +89,26 @@ class CORE_EXPORT HTMLVideoElement final
// Used by canvas to gain raw pixel access
//
// PaintFlags is optional. If unspecified, its blend mode defaults to kSrc.
- void PaintCurrentFrame(
- cc::PaintCanvas*,
- const IntRect&,
- const cc::PaintFlags*,
- int already_uploaded_id = kNoAlreadyUploadedFrame,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata = nullptr) const;
-
- // Used by WebGL to do GPU-GPU texture copy if possible.
- bool CopyVideoTextureToPlatformTexture(
- gpu::gles2::GLES2Interface*,
- GLenum target,
- GLuint texture,
- GLenum internal_format,
- GLenum format,
- GLenum type,
- GLint level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata);
-
- // Used by WebGL to do YUV-RGB, CPU-GPU texture copy if possible.
- bool CopyVideoYUVDataToPlatformTexture(
- gpu::gles2::GLES2Interface*,
- GLenum target,
- GLuint texture,
- GLenum internal_format,
- GLenum format,
- GLenum type,
- GLint level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata);
-
- // Used by WebGL to do CPU-GPU texture upload if possible.
- bool TexImageImpl(WebMediaPlayer::TexImageFunctionID,
- GLenum target,
- gpu::gles2::GLES2Interface*,
- GLuint texture,
- GLint level,
- GLint internalformat,
- GLenum format,
- GLenum type,
- GLint xoffset,
- GLint yoffset,
- GLint zoffset,
- bool flip_y,
- bool premultiply_alpha);
-
- // Used by WebGL to do GPU_GPU texture sharing if possible.
- bool PrepareVideoFrameForWebGL(
- gpu::gles2::GLES2Interface*,
- GLenum target,
- GLuint texture,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata);
+ void PaintCurrentFrame(cc::PaintCanvas*,
+ const IntRect&,
+ const cc::PaintFlags*) const;
bool HasAvailableVideoFrame() const;
KURL PosterImageURL() const override;
+ // Returns whether the current poster image URL is the default for the
+ // document.
+ // TODO(1190335): Remove this once default poster image URL is removed.
+ bool IsDefaultPosterImageURL() const;
+
+ // Helper for GetSourceImageForCanvas() and other external callers who want a
+ // StaticBitmapImage of the current VideoFrame. If |allow_accelerated_images|
+ // is set to false a software backed CanvasResourceProvider will be used to
+ // produce the StaticBitmapImage.
+ scoped_refptr<StaticBitmapImage> CreateStaticBitmapImage(
+ bool allow_accelerated_images = true);
+
// CanvasImageSource implementation
scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
const FloatSize&) override;
@@ -188,8 +142,6 @@ class CORE_EXPORT HTMLVideoElement final
void MediaRemotingStopped(int error_code) final;
DisplayType GetDisplayType() const final;
bool IsInAutoPIP() const final;
- void RequestEnterPictureInPicture() final;
- void RequestExitPictureInPicture() final;
void OnPictureInPictureStateChange() final;
// Used by the PictureInPictureController as callback when the video element
@@ -208,6 +160,7 @@ class CORE_EXPORT HTMLVideoElement final
RegisteredEventListener&) override;
void OnWebMediaPlayerCreated() final;
+ void OnWebMediaPlayerCleared() final;
void AttributeChanged(const AttributeModificationParams& params) override;
@@ -236,6 +189,12 @@ class CORE_EXPORT HTMLVideoElement final
void OnPlay() final;
void OnLoadStarted() final;
void OnLoadFinished() final;
+
+ // Video-specific overrides for part of the media::mojom::MediaPlayer
+ // interface, fully implemented in the parent class HTMLMediaElement.
+ void RequestEnterPictureInPicture() final;
+ void RequestExitPictureInPicture() final;
+
void DidMoveToNewDocument(Document& old_document) override;
void UpdatePictureInPictureAvailability();
@@ -276,6 +235,10 @@ class CORE_EXPORT HTMLVideoElement final
// True, if the video element occupies most of the viewport.
bool mostly_filling_viewport_ : 1;
+
+ // Used to fulfill blink::Image requests (CreateImage(),
+ // GetSourceImageForCanvas(), etc). Created on demand.
+ std::unique_ptr<CanvasResourceProvider> resource_provider_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
index 54643ff90e1..1e345abb5e4 100644
--- a/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/public/common/media/display_type.h"
#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/media/html_media_test_helper.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
@@ -202,4 +203,31 @@ TEST_F(HTMLVideoElementTest, AutoPIPExitPIPTest) {
test::RunPendingTasks();
}
+// TODO(1190335): Remove this once we no longer support "default poster image"
+// Blink embedders (such as Webview) can set the default poster image for a
+// video using `blink::Settings`. In some cases we still need to distinguish
+// between a "real" poster image and the default poster image.
+TEST_F(HTMLVideoElementTest, DefaultPosterImage) {
+ String const kDefaultPosterImage = "http://www.example.com/foo.jpg";
+
+ // Override the default poster image
+ GetDocument().GetSettings()->SetDefaultVideoPosterURL(kDefaultPosterImage);
+
+ // Need to create a new video element, since
+ // `HTMLVideoElement::default_poster_url_` is set upon construction.
+ auto* video = MakeGarbageCollected<HTMLVideoElement>(GetDocument());
+ GetDocument().body()->appendChild(video);
+
+ // Assert that video element (without an explicitly set poster image url) has
+ // the same poster image URL as what we just set.
+ EXPECT_TRUE(video->IsDefaultPosterImageURL());
+ EXPECT_EQ(kDefaultPosterImage, video->PosterImageURL());
+
+ // Set the poster image of the video to something
+ video->setAttribute(html_names::kPosterAttr,
+ "http://www.example.com/bar.jpg");
+ EXPECT_FALSE(video->IsDefaultPosterImageURL());
+ EXPECT_NE(kDefaultPosterImage, video->PosterImageURL());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
index 8fa88c6d7e9..920ea2e042d 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
@@ -155,6 +155,7 @@ void MediaRemotingInterstitial::OnPosterImageChanged() {
}
void MediaRemotingInterstitial::Trace(Visitor* visitor) const {
+ visitor->Trace(toggle_interstitial_timer_);
visitor->Trace(video_element_);
visitor->Trace(background_image_);
visitor->Trace(cast_icon_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
index 8ccf4baa726..466719bd4ea 100644
--- a/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
+++ b/chromium/third_party/blink/renderer/core/html/media/media_remoting_interstitial.h
@@ -65,7 +65,7 @@ class MediaRemotingInterstitial final : public HTMLDivElement {
};
State state_ = HIDDEN;
- TaskRunnerTimer<MediaRemotingInterstitial> toggle_interstitial_timer_;
+ HeapTaskRunnerTimer<MediaRemotingInterstitial> toggle_interstitial_timer_;
Member<HTMLVideoElement> video_element_;
Member<HTMLImageElement> background_image_;
Member<HTMLDivElement> cast_icon_;
diff --git a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
index 5627a70f441..da2d1feb143 100644
--- a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
@@ -175,6 +175,7 @@ void PictureInPictureInterstitial::OnPosterImageChanged() {
void PictureInPictureInterstitial::Trace(Visitor* visitor) const {
visitor->Trace(resize_observer_);
+ visitor->Trace(interstitial_timer_);
visitor->Trace(video_element_);
visitor->Trace(background_image_);
visitor->Trace(message_element_);
diff --git a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
index 85aae77812d..397804aaf04 100644
--- a/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
+++ b/chromium/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.h
@@ -61,7 +61,7 @@ class PictureInPictureInterstitial final : public HTMLDivElement {
// necessary.
Member<ResizeObserver> resize_observer_;
- TaskRunnerTimer<PictureInPictureInterstitial> interstitial_timer_;
+ HeapTaskRunnerTimer<PictureInPictureInterstitial> interstitial_timer_;
Member<HTMLVideoElement> video_element_;
Member<HTMLImageElement> background_image_;
Member<HTMLDivElement> message_element_;
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc b/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
index 51b1214a909..93fb7c565c9 100644
--- a/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
@@ -53,12 +53,14 @@ class VideoAutoFullscreenFrameHost : public FakeLocalFrameHost {
class VideoAutoFullscreenFrameClient
: public frame_test_helpers::TestWebFrameClient {
public:
- WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
- WebMediaPlayerClient*,
- blink::MediaInspectorContext*,
- WebMediaPlayerEncryptedMediaClient*,
- WebContentDecryptionModule*,
- const WebString& sink_id) final {
+ WebMediaPlayer* CreateMediaPlayer(
+ const WebMediaPlayerSource&,
+ WebMediaPlayerClient*,
+ blink::MediaInspectorContext*,
+ WebMediaPlayerEncryptedMediaClient*,
+ WebContentDecryptionModule*,
+ const WebString& sink_id,
+ const cc::LayerTreeSettings& settings) final {
return new EmptyWebMediaPlayer();
}
};
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_frame_callback_requester.h b/chromium/third_party/blink/renderer/core/html/media/video_frame_callback_requester.h
index e47484cfefa..0a411483aff 100644
--- a/chromium/third_party/blink/renderer/core/html/media/video_frame_callback_requester.h
+++ b/chromium/third_party/blink/renderer/core/html/media/video_frame_callback_requester.h
@@ -28,6 +28,7 @@ class CORE_EXPORT VideoFrameCallbackRequester
void Trace(Visitor*) const override;
virtual void OnWebMediaPlayerCreated() = 0;
+ virtual void OnWebMediaPlayerCleared() = 0;
virtual void OnRequestVideoFrameCallback() = 0;
protected:
diff --git a/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
index 62f79d46479..623c2851bdd 100644
--- a/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/core/html/media/video_wake_lock.h"
#include "cc/layers/layer.h"
+#include "media/mojo/mojom/media_player.mojom-blink.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -63,6 +65,7 @@ class VideoWakeLockPictureInPictureService
void StartSession(
uint32_t,
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>,
const base::Optional<viz::SurfaceId>&,
const gfx::Size&,
bool,
diff --git a/chromium/third_party/blink/renderer/core/html/parser/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/parser/DIR_METADATA
new file mode 100644
index 00000000000..18fa0a67843
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/parser/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>HTML>Parser"
+}
+
+team_email: "loading-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/html/parser/OWNERS b/chromium/third_party/blink/renderer/core/html/parser/OWNERS
index 2812e39384d..c0b826f5f62 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/parser/OWNERS
@@ -2,6 +2,3 @@ csharrison@chromium.org
kouhei@chromium.org
masonfreed@chromium.org
yoavweiss@chromium.org
-
-# TEAM: loading-dev@chromium.org
-# COMPONENT: Blink>HTML>Parser
diff --git a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
index 6bc906f027b..0e429069e9c 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/background_html_parser.cc
@@ -186,7 +186,7 @@ void BackgroundHTMLParser::MarkEndOfFile() {
}
void BackgroundHTMLParser::PumpTokenizer() {
- TRACE_EVENT0("loading", "BackgroundHTMLParser::pumpTokenizer");
+ TRACE_EVENT0("loading", "BackgroundHTMLParser::PumpTokenizer");
HTMLTreeBuilderSimulator::SimulatedToken simulated_token =
HTMLTreeBuilderSimulator::kOtherToken;
@@ -245,9 +245,6 @@ void BackgroundHTMLParser::EnqueueTokenizedChunk() {
return;
auto chunk = std::make_unique<HTMLDocumentParser::TokenizedChunk>();
- TRACE_EVENT_WITH_FLOW0("blink,loading",
- "BackgroundHTMLParser::sendTokensToMainThread",
- chunk.get(), TRACE_EVENT_FLAG_FLOW_OUT);
chunk->preloads.swap(pending_preloads_);
if (viewport_description_.has_value())
diff --git a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc
index a521cfe2a91..99f25715af3 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc
@@ -47,13 +47,16 @@ void CSSPreloadScanner::Reset() {
}
template <typename Char>
-void CSSPreloadScanner::ScanCommon(const Char* begin,
- const Char* end,
- const SegmentedString& source,
- PreloadRequestStream& requests,
- const KURL& predicted_base_element_url) {
+void CSSPreloadScanner::ScanCommon(
+ const Char* begin,
+ const Char* end,
+ const SegmentedString& source,
+ PreloadRequestStream& requests,
+ const KURL& predicted_base_element_url,
+ const PreloadRequest::ExclusionInfo* exclusion_info) {
requests_ = &requests;
predicted_base_element_url_ = &predicted_base_element_url;
+ exclusion_info_ = exclusion_info;
for (const Char* it = begin; it != end && state_ != kDoneParsingImportRules;
++it)
@@ -64,29 +67,34 @@ void CSSPreloadScanner::ScanCommon(const Char* begin,
requests_ = nullptr;
predicted_base_element_url_ = nullptr;
+ exclusion_info_ = nullptr;
}
-void CSSPreloadScanner::Scan(const HTMLToken::DataVector& data,
- const SegmentedString& source,
- PreloadRequestStream& requests,
- const KURL& predicted_base_element_url) {
+void CSSPreloadScanner::Scan(
+ const HTMLToken::DataVector& data,
+ const SegmentedString& source,
+ PreloadRequestStream& requests,
+ const KURL& predicted_base_element_url,
+ const PreloadRequest::ExclusionInfo* exclusion_info) {
ScanCommon(data.data(), data.data() + data.size(), source, requests,
- predicted_base_element_url);
+ predicted_base_element_url, exclusion_info);
}
-void CSSPreloadScanner::Scan(const String& tag_name,
- const SegmentedString& source,
- PreloadRequestStream& requests,
- const KURL& predicted_base_element_url) {
+void CSSPreloadScanner::Scan(
+ const String& tag_name,
+ const SegmentedString& source,
+ PreloadRequestStream& requests,
+ const KURL& predicted_base_element_url,
+ const PreloadRequest::ExclusionInfo* exclusion_info) {
if (tag_name.Is8Bit()) {
const LChar* begin = tag_name.Characters8();
ScanCommon(begin, begin + tag_name.length(), source, requests,
- predicted_base_element_url);
+ predicted_base_element_url, exclusion_info);
return;
}
const UChar* begin = tag_name.Characters16();
ScanCommon(begin, begin + tag_name.length(), source, requests,
- predicted_base_element_url);
+ predicted_base_element_url, exclusion_info);
}
void CSSPreloadScanner::SetReferrerPolicy(
@@ -252,7 +260,7 @@ void CSSPreloadScanner::EmitRule(const SegmentedString& source) {
fetch_initiator_type_names::kCSS, position, url,
*predicted_base_element_url_, ResourceType::kCSSStyleSheet,
referrer_policy_, PreloadRequest::kBaseUrlIsReferrer,
- ResourceFetcher::kImageNotImageSet);
+ ResourceFetcher::kImageNotImageSet, exclusion_info_);
if (request) {
// FIXME: Should this be including the charset in the preload request?
requests_->push_back(std::move(request));
diff --git a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.h b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.h
index c937d06520d..fc8019935da 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/css_preload_scanner.h
@@ -48,11 +48,13 @@ class CSSPreloadScanner {
void Scan(const HTMLToken::DataVector&,
const SegmentedString&,
PreloadRequestStream&,
- const KURL&);
+ const KURL&,
+ const PreloadRequest::ExclusionInfo*);
void Scan(const String&,
const SegmentedString&,
PreloadRequestStream&,
- const KURL&);
+ const KURL&,
+ const PreloadRequest::ExclusionInfo*);
void SetReferrerPolicy(network::mojom::ReferrerPolicy);
@@ -75,7 +77,8 @@ class CSSPreloadScanner {
const Char* end,
const SegmentedString&,
PreloadRequestStream&,
- const KURL&);
+ const KURL&,
+ const PreloadRequest::ExclusionInfo*);
inline void Tokenize(UChar, const SegmentedString&);
void EmitRule(const SegmentedString&);
@@ -92,6 +95,7 @@ class CSSPreloadScanner {
// Below members only non-null during scan()
PreloadRequestStream* requests_ = nullptr;
const KURL* predicted_base_element_url_ = nullptr;
+ const PreloadRequest::ExclusionInfo* exclusion_info_;
DISALLOW_COPY_AND_ASSIGN(CSSPreloadScanner);
};
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
index 870c7f51762..5c1866b4730 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_construction_site.cc
@@ -803,8 +803,6 @@ void HTMLConstructionSite::InsertTextNode(const StringView& string,
if (ShouldFosterParent())
FindFosterSite(dummy_task);
- // TODO(crbug.com/1070669): This can likely be removed, because it is already
- // handled in Insert().
if (auto* template_element =
DynamicTo<HTMLTemplateElement>(*dummy_task.parent)) {
// If the Document was detached in the middle of parsing, the template
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 3a26bd51713..bcb138e4437 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -89,6 +89,7 @@ constexpr int kDefaultMaxTokenizationBudget = 250;
class EndIfDelayedForbiddenScope;
class ShouldCompleteScope;
+class AttemptToEndForbiddenScope;
// This class encapsulates the internal state needed for synchronous foreground
// HTML parsing (e.g. if HTMLDocumentParser::PumpTokenizer yields, this class
@@ -97,6 +98,7 @@ class HTMLDocumentParserState
: public GarbageCollected<HTMLDocumentParserState> {
friend EndIfDelayedForbiddenScope;
friend ShouldCompleteScope;
+ friend AttemptToEndForbiddenScope;
public:
// Keeps track of whether the parser needs to complete tokenization work,
@@ -131,7 +133,10 @@ class HTMLDocumentParserState
meta_csp_state_(MetaCSPTokenState::kNotSeen),
mode_(mode),
end_if_delayed_forbidden_(0),
- should_complete_(0) {}
+ should_complete_(0),
+ should_attempt_to_end_on_eof_(0),
+ needs_link_header_dispatch_(true),
+ have_seen_first_byte_(false) {}
void Trace(Visitor* v) const {}
@@ -153,6 +158,27 @@ class HTMLDocumentParserState
}
}
+ bool NeedsLinkHeaderPreloadsDispatch() const {
+ return needs_link_header_dispatch_;
+ }
+ void DispatchedLinkHeaderPreloads() { needs_link_header_dispatch_ = false; }
+
+ bool HaveSeenFirstByte() const { return have_seen_first_byte_; }
+ void SetHaveSeenFirstByte() { have_seen_first_byte_ = true; }
+
+ // Keeps track of whether Document::Finish has been called whilst parsing
+ // asynchronously. ShouldAttemptToEndOnEOF() means that the parser should
+ // close when there's no more input.
+ bool ShouldAttemptToEndOnEOF() const {
+ return should_attempt_to_end_on_eof_ > 0;
+ }
+ void SetAttemptToEndOnEOF() {
+ // This method should only be called from ::Finish.
+ should_attempt_to_end_on_eof_++;
+ // Should only ever call ::Finish once.
+ DCHECK(should_attempt_to_end_on_eof_ < 2);
+ }
+
bool ShouldEndIfDelayed() const { return end_if_delayed_forbidden_ == 0; }
bool ShouldComplete() const {
return should_complete_ || GetMode() != kAllowDeferredParsing;
@@ -185,6 +211,11 @@ class HTMLDocumentParserState
DCHECK_GE(end_if_delayed_forbidden_, 0);
}
+ void EnterAttemptToEndForbidden() {
+ DCHECK(should_attempt_to_end_on_eof_ > 0);
+ should_attempt_to_end_on_eof_ = 0;
+ }
+
void EnterShouldComplete() { should_complete_++; }
void ExitShouldComplete() {
should_complete_--;
@@ -196,6 +227,11 @@ class HTMLDocumentParserState
ParserSynchronizationPolicy mode_;
int end_if_delayed_forbidden_;
int should_complete_;
+ // Set to non-zero if Document::Finish has been called and we're operating
+ // asynchronously.
+ int should_attempt_to_end_on_eof_;
+ bool needs_link_header_dispatch_;
+ bool have_seen_first_byte_;
};
class EndIfDelayedForbiddenScope {
@@ -212,6 +248,19 @@ class EndIfDelayedForbiddenScope {
HTMLDocumentParserState* state_;
};
+class AttemptToEndForbiddenScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit AttemptToEndForbiddenScope(HTMLDocumentParserState* state)
+ : state_(state) {
+ state_->EnterAttemptToEndForbidden();
+ }
+
+ private:
+ HTMLDocumentParserState* state_;
+};
+
class ShouldCompleteScope {
STACK_ALLOCATED();
@@ -283,36 +332,42 @@ class ScopedYieldTimer {
};
HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document,
- ParserSynchronizationPolicy sync_policy)
- : HTMLDocumentParser(document, kAllowScriptingContent, sync_policy) {
+ ParserSynchronizationPolicy sync_policy,
+ ParserPrefetchPolicy prefetch_policy)
+ : HTMLDocumentParser(document,
+ kAllowScriptingContent,
+ sync_policy,
+ prefetch_policy) {
script_runner_ =
HTMLParserScriptRunner::Create(ReentryPermit(), &document, this);
// Allow declarative shadow DOM for the document parser, if not explicitly
// disabled.
- bool allow_shadow_root = document.GetDeclarativeShadowRootAllowState() !=
- Document::DeclarativeShadowRootAllowState::kDeny;
+ bool include_shadow_roots = document.GetDeclarativeShadowRootAllowState() !=
+ Document::DeclarativeShadowRootAllowState::kDeny;
tree_builder_ = MakeGarbageCollected<HTMLTreeBuilder>(
- this, document, kAllowScriptingContent, options_, allow_shadow_root);
+ this, document, kAllowScriptingContent, options_, include_shadow_roots);
}
HTMLDocumentParser::HTMLDocumentParser(
DocumentFragment* fragment,
Element* context_element,
- ParserContentPolicy parser_content_policy)
+ ParserContentPolicy parser_content_policy,
+ ParserPrefetchPolicy parser_prefetch_policy)
: HTMLDocumentParser(fragment->GetDocument(),
parser_content_policy,
- kForceSynchronousParsing) {
+ kForceSynchronousParsing,
+ parser_prefetch_policy) {
// Allow declarative shadow DOM for the fragment parser only if explicitly
// enabled.
- bool allow_shadow_root =
+ bool include_shadow_roots =
fragment->GetDocument().GetDeclarativeShadowRootAllowState() ==
Document::DeclarativeShadowRootAllowState::kAllow;
// No script_runner_ in fragment parser.
tree_builder_ = MakeGarbageCollected<HTMLTreeBuilder>(
this, fragment, context_element, parser_content_policy, options_,
- allow_shadow_root);
+ include_shadow_roots);
// For now document fragment parsing never reports errors.
bool report_errors = false;
@@ -331,7 +386,8 @@ int GetMaxTokenizationBudget() {
HTMLDocumentParser::HTMLDocumentParser(Document& document,
ParserContentPolicy content_policy,
- ParserSynchronizationPolicy sync_policy)
+ ParserSynchronizationPolicy sync_policy,
+ ParserPrefetchPolicy prefetch_policy)
: ScriptableDocumentParser(document, content_policy),
options_(&document),
reentry_permit_(HTMLParserReentryPermit::Create()),
@@ -400,7 +456,8 @@ HTMLDocumentParser::HTMLDocumentParser(Document& document,
!document.IsPrefetchOnly())
return;
- preloader_ = MakeGarbageCollected<HTMLResourcePreloader>(document);
+ if (prefetch_policy == kAllowPrefetching)
+ preloader_ = MakeGarbageCollected<HTMLResourcePreloader>(document);
}
HTMLDocumentParser::~HTMLDocumentParser() = default;
@@ -552,6 +609,10 @@ void HTMLDocumentParser::PumpTokenizerIfPossible() {
if (yielded) {
DCHECK(!task_runner_state_->ShouldComplete());
SchedulePumpTokenizer();
+ } else if (task_runner_state_->ShouldAttemptToEndOnEOF()) {
+ // Fall into this branch if ::Finish has been previously called and we've
+ // just finished asynchronously parsing everything.
+ AttemptToEnd();
} else if (task_runner_state_->ShouldEndIfDelayed()) {
// If we did not exceed the budget or parsed everything there was to
// parse, check if we should complete the document.
@@ -596,17 +657,20 @@ void HTMLDocumentParser::RunScriptsForPausedTreeBuilder() {
CheckIfBlockingStylesheetAdded();
}
-bool HTMLDocumentParser::CanTakeNextToken() {
+HTMLDocumentParser::NextTokenStatus HTMLDocumentParser::CanTakeNextToken() {
if (IsStopped())
- return false;
+ return NoTokens;
// If we're paused waiting for a script, we try to execute scripts before
// continuing.
- if (tree_builder_->HasParserBlockingScript())
+ auto ret = HaveTokens;
+ if (tree_builder_->HasParserBlockingScript()) {
RunScriptsForPausedTreeBuilder();
+ ret = HaveTokensAfterScript;
+ }
if (IsStopped() || IsPaused())
- return false;
- return true;
+ return NoTokens;
+ return ret;
}
void HTMLDocumentParser::EnqueueTokenizedChunk(
@@ -775,9 +839,8 @@ void HTMLDocumentParser::DiscardSpeculationsAndResumeFrom(
DCHECK(checkpoint->unparsed_input.IsSafeToSendToAnotherThread());
loading_task_runner_->PostTask(
- FROM_HERE,
- WTF::Bind(&BackgroundHTMLParser::ResumeFrom, background_parser_,
- WTF::Passed(std::move(checkpoint))));
+ FROM_HERE, WTF::Bind(&BackgroundHTMLParser::ResumeFrom,
+ background_parser_, std::move(checkpoint)));
}
size_t HTMLDocumentParser::ProcessTokenizedChunkFromBackgroundParser(
@@ -959,7 +1022,22 @@ bool HTMLDocumentParser::PumpTokenizer() {
bool should_yield = false;
int budget = max_tokenization_budget_;
- while (CanTakeNextToken() && !should_yield) {
+ while (!should_yield) {
+ const auto next_token_status = CanTakeNextToken();
+ if (next_token_status == NoTokens) {
+ // No tokens left to process in this pump, so break
+ break;
+ } else if (next_token_status == HaveTokensAfterScript &&
+ task_runner_state_->HaveExitedHeader()) {
+ // Just executed a parser-blocking script in the body (which is usually
+ // very expensive), so expire the budget, yield, and permit paint if
+ // needed.
+ budget = 0;
+ if (!should_run_until_completion) {
+ should_yield = true;
+ break;
+ }
+ }
{
RUNTIME_CALL_TIMER_SCOPE(
V8PerIsolateData::MainThreadIsolate(),
@@ -1226,31 +1304,29 @@ void HTMLDocumentParser::Append(const String& input_source) {
return;
preload_scanner_->AppendToEnd(source);
- ScanAndPreload(preload_scanner_.get());
+ if (preloader_) {
+ // TODO(Richard.Townsend@arm.com): add test coverage of this branch.
+ // The crash in crbug.com/1166786 indicates that text documents are being
+ // speculatively prefetched.
+ ScanAndPreload(preload_scanner_.get());
+ }
// Return after the preload scanner, do not actually parse the document.
return;
}
- if (preload_scanner_) {
- if (input_.Current().IsEmpty() && !IsPaused()) {
- // We have parsed until the end of the current input and so are now
- // moving ahead of the preload scanner. Clear the scanner so we know to
- // scan starting from the current input point if we block again.
- preload_scanner_.reset();
- } else {
- preload_scanner_->AppendToEnd(source);
- if (preloader_) {
- if (!task_runner_state_->IsSynchronous() || IsPaused()) {
- // Should scan and preload if the parser's paused and operating
- // synchronously, or if the parser's operating in an asynchronous
- // mode.
- ScanAndPreload(preload_scanner_.get());
- }
- }
+ if (preload_scanner_ && preloader_) {
+ preload_scanner_->AppendToEnd(source);
+ if (task_runner_state_->GetMode() == kAllowDeferredParsing &&
+ (IsPaused() || !task_runner_state_->HaveSeenFirstByte())) {
+ // Should scan and preload if the parser's paused waiting for a resource,
+ // or if we're starting a document for the first time (we want to at least
+ // prefetch anything that's in the <head> section).
+ ScanAndPreload(preload_scanner_.get());
}
}
input_.AppendToEnd(source);
+ task_runner_state_->SetHaveSeenFirstByte();
if (InPumpSession()) {
// We've gotten data off the network in a nested write. We don't want to
@@ -1306,7 +1382,11 @@ void HTMLDocumentParser::AttemptToEnd() {
// an external script to load, we can't finish parsing quite yet.
TRACE_EVENT1("blink", "HTMLDocumentParser::AttemptToEnd", "parser",
(void*)this);
-
+ DCHECK(task_runner_state_->ShouldAttemptToEndOnEOF());
+ AttemptToEndForbiddenScope should_not_attempt_to_end(task_runner_state_);
+ // We should only be in this state once after calling Finish.
+ // If there are pending scripts, future control flow should pass to
+ // EndIfDelayed.
if (ShouldDelayEnd()) {
end_was_delayed_ = true;
return;
@@ -1367,10 +1447,11 @@ void HTMLDocumentParser::Finish() {
if (!input_.HaveSeenEndOfFile())
input_.MarkEndOfFile();
+ // If there's any deferred work remaining, signal that we
+ // want to end the document once all work's complete.
+ task_runner_state_->SetAttemptToEndOnEOF();
if (task_runner_state_->IsScheduled() && !GetDocument()->IsPrefetchOnly()) {
- // If there's any deferred work remaining, synchronously pump the tokenizer
- // one last time to make sure that everything's added to the document.
- PumpTokenizerIfPossible();
+ return;
}
AttemptToEnd();
@@ -1595,7 +1676,7 @@ void HTMLDocumentParser::AppendBytes(const char* data, size_t length) {
loading_task_runner_->PostTask(
FROM_HERE,
WTF::Bind(&BackgroundHTMLParser::AppendRawBytesFromMainThread,
- background_parser_, WTF::Passed(std::move(buffer))));
+ background_parser_, std::move(buffer)));
return;
}
@@ -1634,7 +1715,7 @@ void HTMLDocumentParser::SetDecoder(
if (have_background_parser_) {
loading_task_runner_->PostTask(
FROM_HERE, WTF::Bind(&BackgroundHTMLParser::SetDecoder,
- background_parser_, WTF::Passed(TakeDecoder())));
+ background_parser_, TakeDecoder()));
}
}
@@ -1672,8 +1753,38 @@ void HTMLDocumentParser::ScanAndPreload(HTMLPreloadScanner* scanner) {
TRACE_EVENT0("blink", "HTMLDocumentParser::ScanAndPreload");
DCHECK(preloader_);
bool seen_csp_meta_tag = false;
- PreloadRequestStream requests = scanner->Scan(
- GetDocument()->ValidBaseElementURL(), nullptr, seen_csp_meta_tag);
+ base::Optional<ViewportDescription> viewport_description;
+ PreloadRequestStream requests =
+ scanner->Scan(GetDocument()->ValidBaseElementURL(), &viewport_description,
+ seen_csp_meta_tag);
+ // Make sure that the viewport is up-to-date, so that the correct viewport
+ // dimensions will be fed to the background parser and preload scanner.
+ if (GetDocument()->Loader() &&
+ task_runner_state_->GetMode() == kAllowDeferredParsing) {
+ if (viewport_description.has_value()) {
+ GetDocument()->GetStyleEngine().UpdateViewport();
+ }
+ if (task_runner_state_->NeedsLinkHeaderPreloadsDispatch()) {
+ if (GetDocument()->Loader()->GetPrefetchedSignedExchangeManager()) {
+ TRACE_EVENT0("blink",
+ "HTMLDocumentParser::DispatchSignedExchangeManager");
+ // Link header preloads for prefetched signed exchanges won't be started
+ // until StartPrefetchedLinkHeaderPreloads() is called. See the header
+ // comment of PrefetchedSignedExchangeManager.
+ GetDocument()
+ ->Loader()
+ ->GetPrefetchedSignedExchangeManager()
+ ->StartPrefetchedLinkHeaderPreloads();
+ } else {
+ TRACE_EVENT0("blink", "HTMLDocumentParser::DispatchLinkHeaderPreloads");
+ GetDocument()->Loader()->DispatchLinkHeaderPreloads(
+ base::OptionalOrNullptr(viewport_description),
+ PreloadHelper::kOnlyLoadMedia);
+ }
+ task_runner_state_->DispatchedLinkHeaderPreloads();
+ }
+ }
+
task_runner_state_->SetSeenCSPMetaTag(seen_csp_meta_tag);
for (auto& request : requests) {
queued_preloads_.push_back(std::move(request));
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
index cac43e4b796..97ebb884b7f 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -67,6 +67,13 @@ class HTMLResourcePreloader;
class HTMLTreeBuilder;
class HTMLDocumentParserState;
+enum ParserPrefetchPolicy {
+ // Indicates that prefetches/preloads should happen for this document type.
+ kAllowPrefetching,
+ // Indicates that prefetches are forbidden for this document type.
+ kDisallowPrefetching
+};
+
// TODO(https://crbug.com/1049898): These are only exposed to make it possible
// to delete an expired histogram. The test should be rewritten to test at a
// different level, so it won't have to make assertions about internal state.
@@ -78,10 +85,13 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser,
USING_PRE_FINALIZER(HTMLDocumentParser, Dispose);
public:
- HTMLDocumentParser(HTMLDocument&, ParserSynchronizationPolicy);
+ HTMLDocumentParser(HTMLDocument&,
+ ParserSynchronizationPolicy,
+ ParserPrefetchPolicy prefetch_policy = kAllowPrefetching);
HTMLDocumentParser(DocumentFragment*,
Element* context_element,
- ParserContentPolicy);
+ ParserContentPolicy,
+ ParserPrefetchPolicy prefetch_policy = kAllowPrefetching);
~HTMLDocumentParser() override;
void Trace(Visitor*) const override;
@@ -156,7 +166,10 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser,
private:
HTMLDocumentParser(Document&,
ParserContentPolicy,
- ParserSynchronizationPolicy);
+ ParserSynchronizationPolicy,
+ ParserPrefetchPolicy);
+
+ enum NextTokenStatus { NoTokens, HaveTokens, HaveTokensAfterScript };
// DocumentParser
void Detach() final;
@@ -194,7 +207,7 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser,
bool*);
void PumpPendingSpeculations();
- bool CanTakeNextToken();
+ NextTokenStatus CanTakeNextToken();
bool PumpTokenizer();
void PumpTokenizerIfPossible();
void DeferredPumpTokenizerIfPossible();
@@ -228,7 +241,7 @@ class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser,
std::unique_ptr<HTMLPreloadScanner> CreatePreloadScanner(
TokenPreloadScanner::ScannerType);
- // Let the given HTMLPreloadScanner scan the input it has, and then preloads
+ // Let the given HTMLPreloadScanner scan the input it has, and then preload
// resources using the resulting PreloadRequests and |preloader_|.
void ScanAndPreload(HTMLPreloadScanner*);
void FetchQueuedPreloads();
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
index e699b87eb66..6724f0702f4 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_document_parser_test.cc
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder_builder.h"
-#include "third_party/blink/renderer/core/loader/prerenderer_client.h"
+#include "third_party/blink/renderer/core/loader/no_state_prefetch_client.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -18,10 +18,11 @@ namespace blink {
namespace {
-class MockPrerendererClient : public PrerendererClient {
+class MockNoStatePrefetchClient : public NoStatePrefetchClient {
public:
- MockPrerendererClient(Page& page, bool is_prefetch_only)
- : PrerendererClient(page, nullptr), is_prefetch_only_(is_prefetch_only) {}
+ MockNoStatePrefetchClient(Page& page, bool is_prefetch_only)
+ : NoStatePrefetchClient(page, nullptr),
+ is_prefetch_only_(is_prefetch_only) {}
private:
bool IsPrefetchOnly() override { return is_prefetch_only_; }
@@ -117,9 +118,9 @@ TEST_P(HTMLDocumentParserTest, HasNoPendingWorkAfterDetach) {
TEST_P(HTMLDocumentParserTest, AppendPrefetch) {
auto& document = To<HTMLDocument>(GetDocument());
- ProvidePrerendererClientTo(
- *document.GetPage(),
- MakeGarbageCollected<MockPrerendererClient>(*document.GetPage(), true));
+ ProvideNoStatePrefetchClientTo(
+ *document.GetPage(), MakeGarbageCollected<MockNoStatePrefetchClient>(
+ *document.GetPage(), true));
EXPECT_TRUE(document.IsPrefetchOnly());
HTMLDocumentParser* parser = CreateParser(document);
@@ -151,7 +152,8 @@ TEST_P(HTMLDocumentParserTest, AppendNoPrefetch) {
// The bytes are forwarded to the tokenizer.
HTMLParserScriptRunnerHost* script_runner_host =
parser->AsHTMLParserScriptRunnerHostForTesting();
- EXPECT_FALSE(script_runner_host->HasPreloadScanner());
+ EXPECT_EQ(script_runner_host->HasPreloadScanner(),
+ testing::get<0>(GetParam()) == kAllowDeferredParsing);
EXPECT_EQ(HTMLTokenizer::kTagNameState, parser->Tokenizer()->GetState());
// Cancel any pending work to make sure that RuntimeFeatures DCHECKs do not
// fire.
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc
index 7f797d2b3f9..5b9871da14c 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_parser_metrics_test.cc
@@ -16,9 +16,7 @@ namespace blink {
class HTMLParserMetricsTest : public testing::Test {
public:
- HTMLParserMetricsTest() {
- helper_.Initialize(nullptr, nullptr, nullptr, nullptr);
- }
+ HTMLParserMetricsTest() { helper_.Initialize(nullptr, nullptr, nullptr); }
~HTMLParserMetricsTest() override = default;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index 39dd6aaa788..b3427793dfd 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -47,6 +47,7 @@
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/html_meta_element.h"
#include "third_party/blink/renderer/core/html/link_rel_attribute.h"
+#include "third_party/blink/renderer/core/html/link_web_bundle.h"
#include "third_party/blink/renderer/core/html/loading_attribute.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h"
@@ -69,20 +70,22 @@
namespace blink {
-static bool Match(const StringImpl* impl, const QualifiedName& q_name) {
+namespace {
+
+bool Match(const StringImpl* impl, const QualifiedName& q_name) {
return impl == q_name.LocalName().Impl();
}
-static bool Match(const AtomicString& name, const QualifiedName& q_name) {
+bool Match(const AtomicString& name, const QualifiedName& q_name) {
DCHECK(IsMainThread());
return q_name.LocalName() == name;
}
-static bool Match(const String& name, const QualifiedName& q_name) {
+bool Match(const String& name, const QualifiedName& q_name) {
return ThreadSafeMatch(name, q_name);
}
-static const StringImpl* TagImplFor(const HTMLToken::DataVector& data) {
+const StringImpl* TagImplFor(const HTMLToken::DataVector& data) {
AtomicString tag_name(data);
const StringImpl* result = tag_name.Impl();
if (result->IsStatic())
@@ -90,14 +93,14 @@ static const StringImpl* TagImplFor(const HTMLToken::DataVector& data) {
return nullptr;
}
-static const StringImpl* TagImplFor(const String& tag_name) {
+const StringImpl* TagImplFor(const String& tag_name) {
const StringImpl* result = tag_name.Impl();
if (result->IsStatic())
return result;
return nullptr;
}
-static String InitiatorFor(const StringImpl* tag_impl) {
+String InitiatorFor(const StringImpl* tag_impl) {
DCHECK(tag_impl);
if (Match(tag_impl, html_names::kImgTag))
return html_names::kImgTag.LocalName();
@@ -113,8 +116,8 @@ static String InitiatorFor(const StringImpl* tag_impl) {
return g_empty_string;
}
-static bool MediaAttributeMatches(const MediaValuesCached& media_values,
- const String& attribute_value) {
+bool MediaAttributeMatches(const MediaValuesCached& media_values,
+ const String& attribute_value) {
// Since this is for preload scanning only, ExecutionContext-based origin
// trials for media queries are not needed.
scoped_refptr<MediaQuerySet> media_queries =
@@ -123,6 +126,20 @@ static bool MediaAttributeMatches(const MediaValuesCached& media_values,
return media_query_evaluator.Eval(*media_queries);
}
+void ParseWebBundleUrlsAndFillHash(const AtomicString& value,
+ HashSet<KURL>& url_hash) {
+ // Parse the attribute value as a space-separated list of urls
+ SpaceSplitString urls(value);
+ for (wtf_size_t i = 0; i < urls.size(); ++i) {
+ KURL url = LinkWebBundle::ParseResourceUrl(urls[i]);
+ if (url.IsValid()) {
+ url_hash.insert(std::move(url));
+ }
+ }
+}
+
+} // namespace
+
class TokenPreloadScanner::StartTagScanner {
STACK_ALLOCATED();
@@ -139,6 +156,7 @@ class TokenPreloadScanner::StartTagScanner {
link_is_preload_(false),
link_is_modulepreload_(false),
link_is_import_(false),
+ link_is_webbundle_(false),
matched_(true),
input_is_image_(false),
nomodule_attribute_value_(false),
@@ -152,6 +170,7 @@ class TokenPreloadScanner::StartTagScanner {
referrer_policy_set_(false),
referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
integrity_attr_set_(false),
+ is_async_(false),
integrity_features_(features),
loading_attr_value_(LoadingAttributeValue::kAuto),
width_attr_dimension_type_(
@@ -226,12 +245,32 @@ class TokenPreloadScanner::StartTagScanner {
}
}
+ bool MaybeUpdateExclusionInfo(
+ const KURL& document_url,
+ scoped_refptr<const PreloadRequest::ExclusionInfo>& exclusion_info) {
+ if (!IsLinkRelWebBundle())
+ return false;
+ HashSet<KURL> scopes;
+ HashSet<KURL> resources;
+ if (exclusion_info) {
+ scopes = exclusion_info->scopes();
+ resources = exclusion_info->resources();
+ }
+ ParseWebBundleUrlsAndFillHash(scopes_attribute_value_, scopes);
+ ParseWebBundleUrlsAndFillHash(resources_attribute_value_, resources);
+ exclusion_info = base::MakeRefCounted<PreloadRequest::ExclusionInfo>(
+ document_url, std::move(scopes), std::move(resources));
+ return true;
+ }
+
std::unique_ptr<PreloadRequest> CreatePreloadRequest(
const KURL& predicted_base_url,
const SegmentedString& source,
const ClientHintsPreferences& client_hints_preferences,
const PictureData& picture_data,
- const CachedDocumentParameters& document_parameters) {
+ const CachedDocumentParameters& document_parameters,
+ const PreloadRequest::ExclusionInfo* exclusion_info,
+ bool treat_links_as_in_body) {
PreloadRequest::RequestType request_type =
PreloadRequest::kRequestTypePreload;
base::Optional<ResourceType> type;
@@ -283,13 +322,15 @@ class TokenPreloadScanner::StartTagScanner {
auto request = PreloadRequest::CreateIfNeeded(
InitiatorFor(tag_impl_), position, url_to_load_, predicted_base_url,
type.value(), referrer_policy, PreloadRequest::kDocumentIsReferrer,
- is_image_set, resource_width, client_hints_preferences, request_type);
+ is_image_set, exclusion_info, resource_width, client_hints_preferences,
+ request_type);
if (!request)
return nullptr;
- if ((Match(tag_impl_, html_names::kScriptTag) &&
- type_attribute_value_ == "module") ||
- IsLinkRelModulePreload()) {
+ bool is_module = (type_attribute_value_ == "module");
+ bool is_script = Match(tag_impl_, html_names::kScriptTag);
+ if ((is_script && is_module) || IsLinkRelModulePreload()) {
+ is_module = true;
request->SetScriptType(mojom::blink::ScriptType::kModule);
}
@@ -299,6 +340,22 @@ class TokenPreloadScanner::StartTagScanner {
request->SetCharset(Charset());
request->SetDefer(defer_);
+ RenderBlockingBehavior render_blocking_behavior =
+ RenderBlockingBehavior::kUnset;
+ if (is_script && (is_module || defer_ == FetchParameters::kLazyLoad)) {
+ render_blocking_behavior =
+ is_async_ ? RenderBlockingBehavior::kPotentiallyBlocking
+ : RenderBlockingBehavior::kNonBlocking;
+ } else if (is_script || type == ResourceType::kCSSStyleSheet) {
+ // CSS here is render blocking, as non blocking doesn't get preloaded.
+ // JS here is a blocking one, as others would've been caught by the
+ // previous condition.
+ render_blocking_behavior =
+ treat_links_as_in_body ? RenderBlockingBehavior::kInBodyParserBlocking
+ : RenderBlockingBehavior::kBlocking;
+ }
+ request->SetRenderBlockingBehavior(render_blocking_behavior);
+
if (type == ResourceType::kImage && Match(tag_impl_, html_names::kImgTag) &&
IsLazyLoadImageDeferable(document_parameters)) {
return nullptr;
@@ -332,6 +389,7 @@ class TokenPreloadScanner::StartTagScanner {
} else if (Match(attribute_name, html_names::kNonceAttr)) {
SetNonce(attribute_value);
} else if (Match(attribute_name, html_names::kAsyncAttr)) {
+ is_async_ = true;
SetDefer(FetchParameters::kLazyLoad);
} else if (Match(attribute_name, html_names::kDeferAttr)) {
SetDefer(FetchParameters::kLazyLoad);
@@ -437,6 +495,7 @@ class TokenPreloadScanner::StartTagScanner {
link_is_preload_ = rel.IsLinkPreload();
link_is_modulepreload_ = rel.IsModulePreload();
link_is_import_ = rel.IsImport();
+ link_is_webbundle_ = rel.IsWebBundle();
} else if (Match(attribute_name, html_names::kMediaAttr)) {
matched_ &= MediaAttributeMatches(*media_values_, attribute_value);
} else if (Match(attribute_name, html_names::kCrossoriginAttr)) {
@@ -467,6 +526,10 @@ class TokenPreloadScanner::StartTagScanner {
Match(attribute_name, html_names::kImportanceAttr) &&
priority_hints_origin_trial_enabled_) {
SetImportance(attribute_value);
+ } else if (Match(attribute_name, html_names::kScopesAttr)) {
+ scopes_attribute_value_ = AtomicString(attribute_value);
+ } else if (Match(attribute_name, html_names::kResourcesAttr)) {
+ resources_attribute_value_ = AtomicString(attribute_value);
}
}
@@ -630,6 +693,10 @@ class TokenPreloadScanner::StartTagScanner {
!url_to_load_.IsEmpty();
}
+ bool IsLinkRelWebBundle() const {
+ return Match(tag_impl_, html_names::kLinkTag) && link_is_webbundle_;
+ }
+
bool ShouldPreloadLink(base::Optional<ResourceType>& type) const {
if (link_is_style_sheet_) {
return type_attribute_value_.IsEmpty() ||
@@ -669,21 +736,24 @@ class TokenPreloadScanner::StartTagScanner {
if (Match(tag_impl_, html_names::kInputTag) && !input_is_image_)
return false;
if (Match(tag_impl_, html_names::kScriptTag)) {
- mojom::blink::ScriptType script_type = mojom::blink::ScriptType::kClassic;
- bool is_import_map = false;
- if (!ScriptLoader::IsValidScriptTypeAndLanguage(
+ ScriptLoader::ScriptTypeAtPrepare script_type =
+ ScriptLoader::GetScriptTypeAtPrepare(
type_attribute_value_, language_attribute_value_,
- ScriptLoader::kAllowLegacyTypeInTypeAttribute, &script_type,
- &is_import_map)) {
- return false;
- }
- if (is_import_map) {
- // External import maps are not yet supported. https://crbug.com/922212
- return false;
- }
- if (ScriptLoader::BlockForNoModule(script_type,
- nomodule_attribute_value_)) {
- return false;
+ ScriptLoader::kAllowLegacyTypeInTypeAttribute);
+ switch (script_type) {
+ case ScriptLoader::ScriptTypeAtPrepare::kInvalid:
+ return false;
+
+ case ScriptLoader::ScriptTypeAtPrepare::kImportMap:
+ // TODO(crbug.com/922212): External import maps are not yet supported.
+ return false;
+
+ case ScriptLoader::ScriptTypeAtPrepare::kClassic:
+ case ScriptLoader::ScriptTypeAtPrepare::kModule:
+ if (ScriptLoader::BlockForNoModule(script_type,
+ nomodule_attribute_value_)) {
+ return false;
+ }
}
}
return true;
@@ -717,7 +787,7 @@ class TokenPreloadScanner::StartTagScanner {
void SetDefer(FetchParameters::DeferOption defer) { defer_ = defer; }
- bool Defer() const { return defer_; }
+ bool Defer() const { return defer_ != FetchParameters::kNoDefer; }
const StringImpl* tag_impl_;
String url_to_load_;
@@ -728,6 +798,7 @@ class TokenPreloadScanner::StartTagScanner {
bool link_is_preload_;
bool link_is_modulepreload_;
bool link_is_import_;
+ bool link_is_webbundle_;
bool matched_;
bool input_is_image_;
String img_src_url_;
@@ -735,6 +806,8 @@ class TokenPreloadScanner::StartTagScanner {
String as_attribute_value_;
String type_attribute_value_;
String language_attribute_value_;
+ AtomicString scopes_attribute_value_;
+ AtomicString resources_attribute_value_;
bool nomodule_attribute_value_;
float source_size_;
bool source_size_set_;
@@ -747,6 +820,7 @@ class TokenPreloadScanner::StartTagScanner {
bool referrer_policy_set_;
network::mojom::ReferrerPolicy referrer_policy_;
bool integrity_attr_set_;
+ bool is_async_;
IntegrityMetadataSet integrity_metadata_;
SubresourceIntegrity::IntegrityFeatures integrity_features_;
LoadingAttributeValue loading_attr_value_;
@@ -769,6 +843,8 @@ TokenPreloadScanner::TokenPreloadScanner(
in_style_(false),
in_picture_(false),
in_script_(false),
+ seen_body_(false),
+ seen_img_(false),
template_count_(0),
document_parameters_(std::move(document_parameters)),
media_values_(
@@ -787,7 +863,8 @@ TokenPreloadScanner::~TokenPreloadScanner() = default;
TokenPreloadScannerCheckpoint TokenPreloadScanner::CreateCheckpoint() {
TokenPreloadScannerCheckpoint checkpoint = checkpoints_.size();
checkpoints_.push_back(Checkpoint(predicted_base_element_url_, in_style_,
- in_script_, template_count_));
+ in_script_, template_count_,
+ exclusion_info_));
return checkpoint;
}
@@ -799,6 +876,7 @@ void TokenPreloadScanner::RewindTo(
predicted_base_element_url_ = checkpoint.predicted_base_element_url;
in_style_ = checkpoint.in_style;
template_count_ = checkpoint.template_count;
+ exclusion_info_ = checkpoint.exclusion_info;
did_rewind_ = true;
in_script_ = checkpoint.in_script;
@@ -903,7 +981,7 @@ void TokenPreloadScanner::ScanCommon(
case HTMLToken::kCharacter: {
if (in_style_) {
css_scanner_.Scan(token.Data(), source, requests,
- predicted_base_element_url_);
+ predicted_base_element_url_, exclusion_info_.get());
}
return;
}
@@ -931,13 +1009,13 @@ void TokenPreloadScanner::ScanCommon(
return;
}
case HTMLToken::kStartTag: {
- if (template_count_)
- return;
const StringImpl* tag_impl = TagImplFor(token.Data());
if (Match(tag_impl, html_names::kTemplateTag)) {
++template_count_;
return;
}
+ if (template_count_)
+ return;
if (Match(tag_impl, html_names::kStyleTag)) {
in_style_ = true;
return;
@@ -978,7 +1056,11 @@ void TokenPreloadScanner::ScanCommon(
media_values_.Get(), &css_scanner_, viewport);
}
- if (Match(tag_impl, html_names::kPictureTag)) {
+ if (Match(tag_impl, html_names::kBodyTag)) {
+ seen_body_ = true;
+ } else if (Match(tag_impl, html_names::kImgTag)) {
+ seen_img_ = true;
+ } else if (Match(tag_impl, html_names::kPictureTag)) {
in_picture_ = true;
picture_data_ = PictureData();
return;
@@ -995,6 +1077,13 @@ void TokenPreloadScanner::ScanCommon(
scanner_type_, priority_hints_origin_trial_enabled_,
&document_parameters_->disabled_image_types);
scanner.ProcessAttributes(token.Attributes());
+
+ if (scanner.MaybeUpdateExclusionInfo(document_url_, exclusion_info_)) {
+ // This means the tag is <link rel=webbundle>. We don't preload the
+ // web bundle request.
+ return;
+ }
+
// TODO(yoav): ViewportWidth is currently racy and might be zero in some
// cases, at least in tests. That problem will go away once
// ParseHTMLOnMainThread lands and MediaValuesCached is eliminated.
@@ -1002,7 +1091,8 @@ void TokenPreloadScanner::ScanCommon(
scanner.HandlePictureSourceURL(picture_data_);
std::unique_ptr<PreloadRequest> request = scanner.CreatePreloadRequest(
predicted_base_element_url_, source, client_hints_preferences_,
- picture_data_, *document_parameters_);
+ picture_data_, *document_parameters_, exclusion_info_.get(),
+ seen_img_ || seen_body_);
if (request) {
requests.push_back(std::move(request));
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
index abcff2db478..f0a57694aa2 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner.h
@@ -119,19 +119,23 @@ class TokenPreloadScanner {
void UpdatePredictedBaseURL(const Token&);
struct Checkpoint {
- Checkpoint(const KURL& predicted_base_element_url,
- bool in_style,
- bool in_script,
- size_t template_count)
+ Checkpoint(
+ const KURL& predicted_base_element_url,
+ bool in_style,
+ bool in_script,
+ size_t template_count,
+ scoped_refptr<const PreloadRequest::ExclusionInfo> exclusion_info)
: predicted_base_element_url(predicted_base_element_url),
in_style(in_style),
in_script(in_script),
- template_count(template_count) {}
+ template_count(template_count),
+ exclusion_info(std::move(exclusion_info)) {}
KURL predicted_base_element_url;
bool in_style;
bool in_script;
size_t template_count;
+ scoped_refptr<const PreloadRequest::ExclusionInfo> exclusion_info;
};
struct PictureData {
@@ -145,9 +149,12 @@ class TokenPreloadScanner {
CSSPreloadScanner css_scanner_;
const KURL document_url_;
KURL predicted_base_element_url_;
+ scoped_refptr<const PreloadRequest::ExclusionInfo> exclusion_info_;
bool in_style_;
bool in_picture_;
bool in_script_;
+ bool seen_body_;
+ bool seen_img_;
PictureData picture_data_;
size_t template_count_;
std::unique_ptr<CachedDocumentParameters> document_parameters_;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
index d75792bdf0b..82c51b5c430 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/parser/html_document_parser.h"
@@ -56,7 +57,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
media_data.device_pixel_ratio = 2.0;
media_data.color_bits_per_component = 24;
media_data.monochrome_bits_per_component = 0;
- media_data.primary_pointer_type = ui::POINTER_TYPE_FINE;
+ media_data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
media_data.default_font_size = 16;
media_data.three_d_enabled = true;
media_data.media_type = media_type_names::kScreen;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index 63a23ad4bfc..4bd6fb08d90 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -232,7 +232,7 @@ class HTMLPreloadScannerTest : public PageTestBase {
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
- data.primary_pointer_type = ui::POINTER_TYPE_FINE;
+ data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType;
data.default_font_size = 16;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
@@ -1488,4 +1488,32 @@ TEST_F(HTMLPreloadScannerTest, CSSImportWithSemicolonInUrl) {
Test(test);
}
+// https://crbug.com/1181291
+TEST_F(HTMLPreloadScannerTest, TemplateInteractions) {
+ PreloadScannerTestCase test_cases[] = {
+ {"http://example.test", "<template><img src='bla.gif'></template>",
+ nullptr, "http://example.test/", ResourceType::kImage, 0},
+ {"http://example.test",
+ "<template><template><img src='bla.gif'></template></template>", nullptr,
+ "http://example.test/", ResourceType::kImage, 0},
+ {"http://example.test",
+ "<template><template></template><img src='bla.gif'></template>", nullptr,
+ "http://example.test/", ResourceType::kImage, 0},
+ {"http://example.test",
+ "<template><template></template><script "
+ "src='test.js'></script></template>",
+ nullptr, "http://example.test/", ResourceType::kScript, 0},
+ {"http://example.test",
+ "<template><template></template><link rel=preload as=fetch "
+ "href=bla></template>",
+ nullptr, "http://example.test/", ResourceType::kRaw, 0},
+ {"http://example.test",
+ "<template><template></template><link rel='stylesheet' href='sheet.css' "
+ "type='text/css'></template>",
+ nullptr, "http://example.test/", ResourceType::kCSSStyleSheet, 0},
+ };
+ for (const auto& test : test_cases)
+ Test(test);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
index 4b5fa934609..afb03ba1a3d 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
@@ -59,8 +59,8 @@ class HTMLResourcePreloaderTest : public PageTestBase {
String(), TextPosition(), test_case.url, KURL(test_case.base_url),
ResourceType::kImage, network::mojom::ReferrerPolicy(),
PreloadRequest::kDocumentIsReferrer, ResourceFetcher::kImageNotImageSet,
- FetchParameters::ResourceWidth(), ClientHintsPreferences(),
- PreloadRequest::kRequestTypePreconnect);
+ nullptr /* exclusion_info */, FetchParameters::ResourceWidth(),
+ ClientHintsPreferences(), PreloadRequest::kRequestTypePreconnect);
DCHECK(preload_request);
if (test_case.is_cors)
preload_request->SetCrossOrigin(kCrossOriginAttributeAnonymous);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 77abc99de36..4f7b9218954 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -233,13 +233,13 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser,
Document& document,
ParserContentPolicy parser_content_policy,
const HTMLParserOptions& options,
- bool allow_shadow_root)
+ bool include_shadow_roots)
: frameset_ok_(true),
tree_(parser->ReentryPermit(), document, parser_content_policy),
insertion_mode_(kInitialMode),
original_insertion_mode_(kInitialMode),
should_skip_leading_newline_(false),
- allow_shadow_root_(allow_shadow_root),
+ include_shadow_roots_(include_shadow_roots),
parser_(parser),
script_to_process_start_position_(UninitializedPositionValue1()),
options_(options) {}
@@ -249,12 +249,12 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser,
Element* context_element,
ParserContentPolicy parser_content_policy,
const HTMLParserOptions& options,
- bool allow_shadow_root)
+ bool include_shadow_roots)
: HTMLTreeBuilder(parser,
fragment->GetDocument(),
parser_content_policy,
options,
- allow_shadow_root) {
+ include_shadow_roots) {
DCHECK(IsMainThread());
DCHECK(context_element);
tree_.InitFragmentParsing(fragment, context_element);
@@ -898,33 +898,50 @@ void HTMLTreeBuilder::ProcessStartTagForInBody(AtomicHTMLToken* token) {
tree_.InsertHTMLElement(token);
}
+namespace {
+DeclarativeShadowRootType DeclarativeShadowRootTypeFromToken(
+ AtomicHTMLToken* token,
+ const Document& document,
+ bool include_shadow_roots) {
+ if (!RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
+ document.GetExecutionContext())) {
+ return DeclarativeShadowRootType::kNone;
+ }
+ Attribute* type_attribute =
+ token->GetAttributeItem(html_names::kShadowrootAttr);
+ if (!type_attribute)
+ return DeclarativeShadowRootType::kNone;
+
+ if (!include_shadow_roots) {
+ document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "Found declarative shadowroot attribute on a template, but declarative "
+ "Shadow DOM has not been enabled by includeShadowRoots."));
+ return DeclarativeShadowRootType::kNone;
+ }
+
+ String shadow_mode = type_attribute->Value();
+ if (EqualIgnoringASCIICase(shadow_mode, "open"))
+ return DeclarativeShadowRootType::kOpen;
+ if (EqualIgnoringASCIICase(shadow_mode, "closed"))
+ return DeclarativeShadowRootType::kClosed;
+
+ document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kOther,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "Invalid declarative shadowroot attribute value \"" + shadow_mode +
+ "\". Valid values include \"open\" and \"closed\"."));
+ return DeclarativeShadowRootType::kNone;
+}
+} // namespace
+
void HTMLTreeBuilder::ProcessTemplateStartTag(AtomicHTMLToken* token) {
tree_.ActiveFormattingElements()->AppendMarker();
-
- DeclarativeShadowRootType declarative_shadow_root_type(
- DeclarativeShadowRootType::kNone);
- if (RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
- tree_.CurrentNode()->GetExecutionContext()) &&
- allow_shadow_root_) {
- if (Attribute* type_attribute =
- token->GetAttributeItem(html_names::kShadowrootAttr)) {
- String shadow_mode = type_attribute->Value();
- if (EqualIgnoringASCIICase(shadow_mode, "open")) {
- declarative_shadow_root_type = DeclarativeShadowRootType::kOpen;
- } else if (EqualIgnoringASCIICase(shadow_mode, "closed")) {
- declarative_shadow_root_type = DeclarativeShadowRootType::kClosed;
- } else {
- tree_.OwnerDocumentForCurrentNode().AddConsoleMessage(
- MakeGarbageCollected<ConsoleMessage>(
- mojom::blink::ConsoleMessageSource::kOther,
- mojom::blink::ConsoleMessageLevel::kWarning,
- "Invalid declarative shadowroot attribute value \"" +
- shadow_mode +
- "\". Valid values include \"open\" and \"closed\"."));
- }
- }
- }
- tree_.InsertHTMLTemplateElement(token, declarative_shadow_root_type);
+ tree_.InsertHTMLTemplateElement(
+ token,
+ DeclarativeShadowRootTypeFromToken(
+ token, tree_.OwnerDocumentForCurrentNode(), include_shadow_roots_));
frameset_ok_ = false;
template_insertion_modes_.push_back(kTemplateContentsMode);
SetInsertionMode(kTemplateContentsMode);
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
index ee8ff98b952..38135b60775 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder.h
@@ -55,13 +55,13 @@ class HTMLTreeBuilder final : public GarbageCollected<HTMLTreeBuilder> {
Document&,
ParserContentPolicy,
const HTMLParserOptions&,
- bool allow_shadow_root);
+ bool include_shadow_roots);
HTMLTreeBuilder(HTMLDocumentParser*,
DocumentFragment*,
Element* context_element,
ParserContentPolicy,
const HTMLParserOptions&,
- bool allow_shadow_root);
+ bool include_shadow_roots);
~HTMLTreeBuilder();
void Trace(Visitor*) const;
@@ -248,7 +248,7 @@ class HTMLTreeBuilder final : public GarbageCollected<HTMLTreeBuilder> {
bool should_skip_leading_newline_;
- const bool allow_shadow_root_;
+ const bool include_shadow_roots_;
// We access parser because HTML5 spec requires that we be able to change the
// state of the tokenizer from within parser actions. We also need it to track
diff --git a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
index ea11a426b6c..b0f1fa862b1 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
@@ -171,9 +171,10 @@ HTMLTreeBuilderSimulator::SimulatedToken HTMLTreeBuilderSimulator::Simulate(
language_attribute_value = item->Value();
}
- if (ScriptLoader::IsValidScriptTypeAndLanguage(
+ if (ScriptLoader::GetScriptTypeAtPrepare(
type_attribute_value, language_attribute_value,
- ScriptLoader::kAllowLegacyTypeInTypeAttribute)) {
+ ScriptLoader::kAllowLegacyTypeInTypeAttribute) !=
+ ScriptLoader::ScriptTypeAtPrepare::kInvalid) {
simulated_token = kValidScriptStart;
}
} else if (ThreadSafeMatch(tag_name, html_names::kLinkTag)) {
diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
index 8318f626709..73c57ab7c84 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -23,6 +23,30 @@
namespace blink {
+PreloadRequest::ExclusionInfo::ExclusionInfo(const KURL& document_url,
+ HashSet<KURL> scopes,
+ HashSet<KURL> resources)
+ : document_url_(document_url),
+ scopes_(std::move(scopes)),
+ resources_(std::move(resources)) {}
+
+PreloadRequest::ExclusionInfo::~ExclusionInfo() = default;
+
+bool PreloadRequest::ExclusionInfo::ShouldExclude(
+ const KURL& base_url,
+ const String& resource_url) const {
+ if (resources_.IsEmpty() && scopes_.IsEmpty())
+ return false;
+ KURL url = KURL(base_url.IsEmpty() ? document_url_ : base_url, resource_url);
+ if (resources_.Contains(url))
+ return true;
+ for (const auto& scope : scopes_) {
+ if (url.GetString().StartsWith(scope.GetString()))
+ return true;
+ }
+ return false;
+}
+
KURL PreloadRequest::CompleteURL(Document* document) {
if (!base_url_.IsEmpty())
return document->CompleteURLWithOverride(resource_url_, base_url_);
@@ -39,6 +63,7 @@ std::unique_ptr<PreloadRequest> PreloadRequest::CreateIfNeeded(
const network::mojom::ReferrerPolicy referrer_policy,
ReferrerSource referrer_source,
ResourceFetcher::IsImageSet is_image_set,
+ const ExclusionInfo* exclusion_info,
const FetchParameters::ResourceWidth& resource_width,
const ClientHintsPreferences& client_hints_preferences,
RequestType request_type) {
@@ -50,6 +75,10 @@ std::unique_ptr<PreloadRequest> PreloadRequest::CreateIfNeeded(
ProtocolIs(resource_url, "data")) {
return nullptr;
}
+
+ if (exclusion_info && exclusion_info->ShouldExclude(base_url, resource_url))
+ return nullptr;
+
return base::WrapUnique(new PreloadRequest(
initiator_name, initiator_position, resource_url, base_url, resource_type,
resource_width, client_hints_preferences, request_type, referrer_policy,
@@ -100,6 +129,7 @@ Resource* PreloadRequest::Start(Document* document) {
DCHECK_EQ(resource_type_, ResourceType::kScript);
params.SetCrossOriginAccessControl(
origin, ScriptLoader::ModuleScriptCredentialsMode(cross_origin_));
+ params.SetModuleScript();
} else if (cross_origin_ != kCrossOriginAttributeNotSet) {
params.SetCrossOriginAccessControl(origin, cross_origin_);
}
@@ -132,10 +162,11 @@ Resource* PreloadRequest::Start(Document* document) {
params.SetSpeculativePreloadType(speculative_preload_type);
if (resource_type_ == ResourceType::kScript) {
- MaybeDisallowFetchForDocWrittenScript(params, *document);
// We intentionally ignore the returned value, because we don't resend
// the async request to the blocked script here.
+ MaybeDisallowFetchForDocWrittenScript(params, *document);
}
+ params.SetRenderBlockingBehavior(render_blocking_behavior_);
return PreloadHelper::StartPreload(resource_type_, params, *document);
}
diff --git a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
index bb277995bb5..8f0d11c50f5 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
+++ b/chromium/third_party/blink/renderer/core/html/parser/preload_request.h
@@ -31,6 +31,31 @@ class CORE_EXPORT PreloadRequest {
USING_FAST_MALLOC(PreloadRequest);
public:
+ class CORE_EXPORT ExclusionInfo : public RefCounted<ExclusionInfo> {
+ USING_FAST_MALLOC(ExclusionInfo);
+
+ public:
+ ExclusionInfo(const KURL& document_url,
+ HashSet<KURL> scopes,
+ HashSet<KURL> resources);
+ virtual ~ExclusionInfo();
+
+ // Disallow copy and assign.
+ ExclusionInfo(const ExclusionInfo&) = delete;
+ ExclusionInfo& operator=(const ExclusionInfo&) = delete;
+
+ const KURL& document_url() const { return document_url_; }
+ const HashSet<KURL>& scopes() const { return scopes_; }
+ const HashSet<KURL>& resources() const { return resources_; }
+
+ bool ShouldExclude(const KURL& base_url, const String& resource_url) const;
+
+ private:
+ const KURL document_url_;
+ const HashSet<KURL> scopes_;
+ const HashSet<KURL> resources_;
+ };
+
enum RequestType {
kRequestTypePreload,
kRequestTypePreconnect,
@@ -48,6 +73,7 @@ class CORE_EXPORT PreloadRequest {
const network::mojom::ReferrerPolicy referrer_policy,
ReferrerSource referrer_source,
ResourceFetcher::IsImageSet is_image_set,
+ const ExclusionInfo* exclusion_info,
const FetchParameters::ResourceWidth& resource_width =
FetchParameters::ResourceWidth(),
const ClientHintsPreferences& client_hints_preferences =
@@ -113,6 +139,11 @@ class CORE_EXPORT PreloadRequest {
return is_image_set_ == ResourceFetcher::kImageIsImageSet;
}
+ void SetRenderBlockingBehavior(
+ RenderBlockingBehavior render_blocking_behavior) {
+ render_blocking_behavior_ = render_blocking_behavior;
+ }
+
private:
PreloadRequest(const String& initiator_name,
const TextPosition& initiator_position,
@@ -162,6 +193,8 @@ class CORE_EXPORT PreloadRequest {
const network::mojom::ReferrerPolicy referrer_policy_;
const ReferrerSource referrer_source_;
IntegrityMetadataSet integrity_metadata_;
+ RenderBlockingBehavior render_blocking_behavior_ =
+ RenderBlockingBehavior::kUnset;
bool from_insertion_scanner_;
const ResourceFetcher::IsImageSet is_image_set_;
bool is_lazy_load_image_enabled_;
diff --git a/chromium/third_party/blink/renderer/core/html/parser/text_document_parser.cc b/chromium/third_party/blink/renderer/core/html/parser/text_document_parser.cc
index 173287e38a1..9b87078dbf6 100644
--- a/chromium/third_party/blink/renderer/core/html/parser/text_document_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/parser/text_document_parser.cc
@@ -32,7 +32,7 @@ namespace blink {
TextDocumentParser::TextDocumentParser(HTMLDocument& document,
ParserSynchronizationPolicy sync_policy)
- : HTMLDocumentParser(document, sync_policy),
+ : HTMLDocumentParser(document, sync_policy, kDisallowPrefetching),
have_inserted_fake_pre_element_(false) {}
TextDocumentParser::~TextDocumentParser() = default;
diff --git a/chromium/third_party/blink/renderer/core/html/plugin_document.cc b/chromium/third_party/blink/renderer/core/html/plugin_document.cc
index b6b83eb6fb9..bee0df0123a 100644
--- a/chromium/third_party/blink/renderer/core/html/plugin_document.cc
+++ b/chromium/third_party/blink/renderer/core/html/plugin_document.cc
@@ -95,8 +95,7 @@ void PluginDocumentParser::CreateDocumentStructure() {
return;
// FIXME: Why does this check settings?
- if (!frame->GetSettings() ||
- !frame->Loader().AllowPlugins(kNotAboutToInstantiatePlugin))
+ if (!frame->GetSettings() || !frame->Loader().AllowPlugins())
return;
auto* root_element = MakeGarbageCollected<HTMLHtmlElement>(*GetDocument());
@@ -190,7 +189,7 @@ PluginDocument::PluginDocument(const DocumentInit& initializer)
LockCompatibilityMode();
GetExecutionContext()->GetScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kContainsPlugins,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
DocumentParser* PluginDocument::CreateParser() {
diff --git a/chromium/third_party/blink/renderer/core/html/portal/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/portal/DIR_METADATA
new file mode 100644
index 00000000000..1e4fe50104b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/portal/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Portals"
+}
diff --git a/chromium/third_party/blink/renderer/core/html/portal/OWNERS b/chromium/third_party/blink/renderer/core/html/portal/OWNERS
index 5ca25353465..15decd27f75 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/portal/OWNERS
@@ -2,5 +2,3 @@ adithyas@chromium.org
jbroman@chromium.org
lfg@chromium.org
mcnee@chromium.org
-
-# COMPONENT: Blink>Portals
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
index 5116a6911ec..b554a4c9021 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.cc
@@ -63,7 +63,7 @@ HTMLPortalElement::HTMLPortalElement(
feature_handle_for_scheduler_(
document.GetExecutionContext()->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kPortal,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
if (remote_portal) {
DCHECK(portal_token);
was_just_adopted_ = true;
@@ -335,19 +335,7 @@ ScriptPromise HTMLPortalElement::activate(ScriptState* script_state,
void HTMLPortalElement::postMessage(ScriptState* script_state,
const ScriptValue& message,
- const String& target_origin,
- const HeapVector<ScriptValue>& transfer,
- ExceptionState& exception_state) {
- WindowPostMessageOptions* options = WindowPostMessageOptions::Create();
- options->setTargetOrigin(target_origin);
- if (!transfer.IsEmpty())
- options->setTransfer(transfer);
- postMessage(script_state, message, options, exception_state);
-}
-
-void HTMLPortalElement::postMessage(ScriptState* script_state,
- const ScriptValue& message,
- const WindowPostMessageOptions* options,
+ const PostMessageOptions* options,
ExceptionState& exception_state) {
if (!CheckPortalsEnabledOrThrow(exception_state) || !GetExecutionContext())
return;
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
index a2c1d190da5..37e6bab3729 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.h
@@ -23,6 +23,7 @@ namespace blink {
class Document;
class PortalActivateOptions;
class PortalContents;
+class PostMessageOptions;
class ScriptState;
// The HTMLPortalElement implements the <portal> HTML element. The portal
@@ -54,12 +55,7 @@ class CORE_EXPORT HTMLPortalElement : public HTMLFrameOwnerElement {
ScriptPromise activate(ScriptState*, PortalActivateOptions*, ExceptionState&);
void postMessage(ScriptState* script_state,
const ScriptValue& message,
- const String& target_origin,
- const HeapVector<ScriptValue>& transfer,
- ExceptionState& exception_state);
- void postMessage(ScriptState* script_state,
- const ScriptValue& message,
- const WindowPostMessageOptions* options,
+ const PostMessageOptions* options,
ExceptionState& exception_state);
EventListener* onmessage();
void setOnmessage(EventListener* listener);
diff --git a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
index 2a0d7a796b8..132f816161a 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
+++ b/chromium/third_party/blink/renderer/core/html/portal/html_portal_element.idl
@@ -10,9 +10,7 @@ interface HTMLPortalElement : HTMLElement {
[CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
[CallWith=ScriptState, RaisesException, Measure] Promise<void> activate(optional PortalActivateOptions options = {});
- [CallWith=ScriptState, RaisesException, Measure] void postMessage(any message, USVString targetOrigin,
- optional sequence<object> transfer = []);
- [CallWith=ScriptState, RaisesException, Measure] void postMessage(any message, optional WindowPostMessageOptions options = {});
+ [CallWith=ScriptState, RaisesException, Measure] void postMessage(any message, optional PostMessageOptions options = {});
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
diff --git a/chromium/third_party/blink/renderer/core/html/portal/portal_host.cc b/chromium/third_party/blink/renderer/core/html/portal/portal_host.cc
index 38bf87a7de9..69e423f1cfc 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/portal_host.cc
+++ b/chromium/third_party/blink/renderer/core/html/portal/portal_host.cc
@@ -60,19 +60,7 @@ void PortalHost::OnPortalActivated() {
void PortalHost::postMessage(ScriptState* script_state,
const ScriptValue& message,
- const String& target_origin,
- HeapVector<ScriptValue>& transfer,
- ExceptionState& exception_state) {
- WindowPostMessageOptions* options = WindowPostMessageOptions::Create();
- options->setTargetOrigin(target_origin);
- if (!transfer.IsEmpty())
- options->setTransfer(transfer);
- postMessage(script_state, message, options, exception_state);
-}
-
-void PortalHost::postMessage(ScriptState* script_state,
- const ScriptValue& message,
- const WindowPostMessageOptions* options,
+ const PostMessageOptions* options,
ExceptionState& exception_state) {
if (!DOMWindowPortalHost::ShouldExposePortalHost(*GetSupplementable())) {
exception_state.ThrowDOMException(
diff --git a/chromium/third_party/blink/renderer/core/html/portal/portal_host.h b/chromium/third_party/blink/renderer/core/html/portal/portal_host.h
index 0db0aaa8fa5..fa40d4aef79 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/portal_host.h
+++ b/chromium/third_party/blink/renderer/core/html/portal/portal_host.h
@@ -18,7 +18,7 @@ class ExecutionContext;
class LocalDOMWindow;
class ScriptValue;
class SecurityOrigin;
-class WindowPostMessageOptions;
+class PostMessageOptions;
class CORE_EXPORT PortalHost : public EventTargetWithInlineData,
public Supplement<LocalDOMWindow> {
@@ -43,12 +43,7 @@ class CORE_EXPORT PortalHost : public EventTargetWithInlineData,
// idl implementation
void postMessage(ScriptState* script_state,
const ScriptValue& message,
- const String& target_origin,
- HeapVector<ScriptValue>& transfer,
- ExceptionState& exception_state);
- void postMessage(ScriptState* script_state,
- const ScriptValue& message,
- const WindowPostMessageOptions* options,
+ const PostMessageOptions* options,
ExceptionState& exception_state);
EventListener* onmessage();
void setOnmessage(EventListener* listener);
diff --git a/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl b/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl
index df5205486cd..14a3694ba8e 100644
--- a/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl
+++ b/chromium/third_party/blink/renderer/core/html/portal/portal_host.idl
@@ -6,10 +6,8 @@
[Exposed=Window, RuntimeEnabled=Portals]
interface PortalHost : EventTarget {
- [RaisesException, CallWith=ScriptState, Measure] void postMessage(any message, USVString targetOrigin,
- optional sequence<object> transfer = []);
[RaisesException, CallWith=ScriptState, Measure] void postMessage(any message,
- optional WindowPostMessageOptions options = {});
+ optional PostMessageOptions options = {});
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
diff --git a/chromium/third_party/blink/renderer/core/html/rel_list.cc b/chromium/third_party/blink/renderer/core/html/rel_list.cc
index 6b70a346592..47061caf65a 100644
--- a/chromium/third_party/blink/renderer/core/html/rel_list.cc
+++ b/chromium/third_party/blink/renderer/core/html/rel_list.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/html/link_web_bundle.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -54,8 +55,7 @@ bool RelList::ValidateTokenValue(const AtomicString& token_value,
token_value == "allowed-alt-sxg") {
return true;
}
- if (RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(
- GetElement().GetExecutionContext()) &&
+ if (LinkWebBundle::IsFeatureEnabled(GetElement().GetExecutionContext()) &&
token_value == "webbundle") {
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/html/resources/android.css b/chromium/third_party/blink/renderer/core/html/resources/android.css
index b6ee01f4569..de2953abe98 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/android.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/android.css
@@ -56,7 +56,7 @@ input[type="month" i],
input[type="time" i],
input[type="week" i] {
align-items: center;
- -webkit-appearance: menulist; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
background-color: ButtonFace;
border: 1px solid #a9a9a9;
display: -webkit-inline-flex;
diff --git a/chromium/third_party/blink/renderer/core/html/resources/controls_refresh.css b/chromium/third_party/blink/renderer/core/html/resources/controls_refresh.css
index 4f2dc364099..1fb64c41d0c 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/controls_refresh.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/controls_refresh.css
@@ -22,16 +22,16 @@ textarea {
border-color: -internal-light-dark(#767676, #858585);
}
-a:-webkit-any-link:focus {
+a:-webkit-any-link:focus-visible {
outline-offset: 1px;
}
-input:focus, textarea:focus, select:focus {
+input:focus-visible, textarea:focus-visible, select:focus-visible {
outline-offset: 0;
}
-input[type="checkbox" i]:focus,
-input[type="radio" i]:focus {
+input[type="checkbox" i]:focus-visible,
+input[type="radio" i]:focus-visible {
outline-offset: 2px;
}
@@ -55,6 +55,7 @@ textarea:disabled {
input:disabled,
textarea:disabled {
background-color: -internal-light-dark(rgba(239, 239, 239, 0.3), rgba(59, 59, 59, 0.3));
+ color: -internal-light-dark(default, rgba(255, 255, 255, 0.6));
}
select:disabled {
@@ -80,7 +81,7 @@ input[type="file" i]:disabled::-webkit-file-upload-button,
button:disabled {
background-color: -internal-light-dark(rgba(239, 239, 239, 0.3), rgba(19, 1, 1, 0.3));
border-color: -internal-light-dark(rgba(118, 118, 118, 0.3), rgba(195, 195, 195, 0.3));
- color: -internal-light-dark(rgba(16, 16, 16, 0.3), white);
+ color: -internal-light-dark(rgba(16, 16, 16, 0.3), rgba(255, 255, 255, 0.3));
}
input[type="password" i]::-internal-reveal {
@@ -162,10 +163,10 @@ input[type="week" i]::-webkit-calendar-picker-indicator {
width: 1.2em;
}
-input[type="date" i]::-webkit-calendar-picker-indicator:focus,
-input[type="datetime-local" i]::-webkit-calendar-picker-indicator:focus,
-input[type="month" i]::-webkit-calendar-picker-indicator:focus,
-input[type="week" i]::-webkit-calendar-picker-indicator:focus {
+input[type="date" i]::-webkit-calendar-picker-indicator:focus-visible,
+input[type="datetime-local" i]::-webkit-calendar-picker-indicator:focus-visible,
+input[type="month" i]::-webkit-calendar-picker-indicator:focus-visible,
+input[type="week" i]::-webkit-calendar-picker-indicator:focus-visible {
outline: solid 2px -webkit-focus-ring-color;
outline-offset: -2px;
}
@@ -186,7 +187,7 @@ input[type="time" i]::-webkit-calendar-picker-indicator {
width: 1.05em;
}
-input[type="time" i]::-webkit-calendar-picker-indicator:focus {
+input[type="time" i]::-webkit-calendar-picker-indicator:focus-visible {
outline: solid 2px -webkit-focus-ring-color;
outline-offset: -2px;
}
@@ -235,15 +236,15 @@ select:-internal-list-box option:checked:disabled:hover {
color: -internal-light-dark(gray, #aaa) !important;
}
-input::-webkit-datetime-edit-ampm-field:focus,
-input::-webkit-datetime-edit-day-field:focus,
-input::-webkit-datetime-edit-hour-field:focus,
-input::-webkit-datetime-edit-millisecond-field:focus,
-input::-webkit-datetime-edit-minute-field:focus,
-input::-webkit-datetime-edit-month-field:focus,
-input::-webkit-datetime-edit-second-field:focus,
-input::-webkit-datetime-edit-week-field:focus,
-input::-webkit-datetime-edit-year-field:focus {
+input::-webkit-datetime-edit-ampm-field:focus-visible,
+input::-webkit-datetime-edit-day-field:focus-visible,
+input::-webkit-datetime-edit-hour-field:focus-visible,
+input::-webkit-datetime-edit-millisecond-field:focus-visible,
+input::-webkit-datetime-edit-minute-field:focus-visible,
+input::-webkit-datetime-edit-month-field:focus-visible,
+input::-webkit-datetime-edit-second-field:focus-visible,
+input::-webkit-datetime-edit-week-field:focus-visible,
+input::-webkit-datetime-edit-year-field:focus-visible {
background-color: -internal-light-dark(highlight, #99C8FF);
color: -internal-light-dark(highlighttext, #000000);
outline: none;
@@ -259,4 +260,4 @@ input::-webkit-datetime-edit-millisecond-field[disabled],
input::-webkit-datetime-edit-minute-field[disabled],
input::-webkit-datetime-edit-second-field[disabled] {
color: -internal-light-dark(GrayText, #000000);
-} \ No newline at end of file
+}
diff --git a/chromium/third_party/blink/renderer/core/html/resources/forced_colors.css b/chromium/third_party/blink/renderer/core/html/resources/forced_colors.css
index b2124b35f89..ce30cebc8c4 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/forced_colors.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/forced_colors.css
@@ -15,37 +15,38 @@
*/
@media ua-forced-colors {
- html {
- color: CanvasText;
- fill: currentColor;
- }
-
- :focus {
- outline-color: Highlight;
+ :focus-visible {
+ -internal-forced-outline-color: Highlight;
}
a:link,
a:-webkit-any-link:active {
- color: LinkText;
+ -internal-forced-color: LinkText;
}
a:visited {
- color: VisitedText;
+ -internal-forced-color: VisitedText;
}
fieldset {
- border-color: CanvasText;
+ -internal-forced-border-color: CanvasText;
+ }
+
+ mark {
+ -internal-forced-background-color: yellow;
+ -internal-forced-color: black;
}
::placeholder {
- color: GrayText;
+ -internal-forced-color: GrayText;
}
input,
textarea {
background-color: Canvas;
- border-color: ButtonText;
- color: CanvasText;
+ -internal-forced-background-color: Canvas;
+ -internal-forced-border-color: ButtonText;
+ -internal-forced-color: CanvasText;
}
input:hover,
@@ -53,7 +54,7 @@
input[type="file"]:hover::-webkit-file-upload-button,
input:focus,
textarea:focus {
- border-color: Highlight;
+ -internal-forced-border-color: Highlight;
}
input[type="text"]:disabled,
@@ -70,27 +71,30 @@
input[type="datetime-local"]:disabled,
textarea:disabled {
background-color: ButtonFace;
- border-color: GrayText;
- color: GrayText;
+ -internal-forced-background-color: ButtonFace;
+ -internal-forced-border-color: GrayText;
+ -internal-forced-color: GrayText;
}
input::-webkit-calendar-picker-indicator {
background-color: ButtonFace;
- color: ButtonText;
- }
-
- input::-webkit-datetime-edit-ampm-field:focus,
- input::-webkit-datetime-edit-day-field:focus,
- input::-webkit-datetime-edit-hour-field:focus,
- input::-webkit-datetime-edit-millisecond-field:focus,
- input::-webkit-datetime-edit-minute-field:focus,
- input::-webkit-datetime-edit-month-field:focus,
- input::-webkit-datetime-edit-second-field:focus,
- input::-webkit-datetime-edit-week-field:focus,
- input::-webkit-datetime-edit-year-field:focus {
+ -internal-forced-background-color: ButtonFace;
+ -internal-forced-color: ButtonText;
+ }
+
+ input::-webkit-datetime-edit-ampm-field:focus-visible,
+ input::-webkit-datetime-edit-day-field:focus-visible,
+ input::-webkit-datetime-edit-hour-field:focus-visible,
+ input::-webkit-datetime-edit-millisecond-field:focus-visible,
+ input::-webkit-datetime-edit-minute-field:focus-visible,
+ input::-webkit-datetime-edit-month-field:focus-visible,
+ input::-webkit-datetime-edit-second-field:focus-visible,
+ input::-webkit-datetime-edit-week-field:focus-visible,
+ input::-webkit-datetime-edit-year-field:focus-visible {
background-color: Highlight;
- color: HighlightText;
outline: none;
+ -internal-forced-background-color: Highlight;
+ -internal-forced-color: HighlightText;
}
input[type="color"]:disabled {
@@ -110,9 +114,10 @@
input[type="submit"],
input[type="reset"],
input[type="file"]::-webkit-file-upload-button {
- border-color: ButtonText;
background-color: ButtonFace;
- color: ButtonText;
+ -internal-forced-background-color: ButtonFace;
+ -internal-forced-border-color: ButtonText;
+ -internal-forced-color: ButtonText;
}
button:hover,
@@ -123,25 +128,26 @@
input[type="button"]:focus,
input[type="submit"]:focus,
input[type="reset"]:focus {
- border-color: Highlight;
+ -internal-forced-border-color: Highlight;
}
button:disabled,
input[type="button"]:disabled,
input[type="submit"]:disabled,
input[type="reset"]:disabled {
- border-color: GrayText;
- color: GrayText;
+ -internal-forced-border-color: GrayText;
+ -internal-forced-color: GrayText;
}
/* same color as hyperlinks */
details summary {
- color: LinkText;
+ -internal-forced-color: LinkText;
}
select:-internal-list-box {
background-color: Canvas !important;
- border-color: ButtonText;
+ -internal-forced-background-color: Canvas !important;
+ -internal-forced-border-color: ButtonText;
}
/* option disabled */
@@ -150,6 +156,7 @@
select:-internal-list-box:disabled option,
select:-internal-list-box:disabled option:hover {
background-color: Canvas !important;
+ -internal-forced-background-color: Canvas !important;
color: GrayText !important;
}
@@ -185,51 +192,57 @@
select {
background-color: Canvas;
- border-color: CanvasText;
- color: CanvasText;
+ -internal-forced-background-color: Canvas;
+ -internal-forced-border-color: CanvasText;
+ -internal-forced-color: CanvasText;
}
select:not(:-internal-list-box) {
background-color: Canvas;
+ -internal-forced-background-color: Canvas;
}
select:hover {
- border-color: Highlight;
+ -internal-forced-border-color: Highlight;
}
select:focus {
- border-color: Highlight;
+ -internal-forced-border-color: Highlight;
}
select:disabled {
- border-color: GrayText;
- color: GrayText;
opacity: 1;
+ -internal-forced-border-color: GrayText;
+ -internal-forced-color: GrayText;
}
meter::-webkit-meter-bar {
background-color: ButtonFace;
- border-color: CanvasText;
+ -internal-forced-background-color: ButtonFace;
+ -internal-forced-border-color: CanvasText;
}
meter::-webkit-meter-even-less-good-value,
meter::-webkit-meter-optimum-value,
meter::-webkit-meter-suboptimum-value {
background-color: Highlight;
+ -internal-forced-background-color: Highlight;
}
input:-internal-autofill-previewed,
textarea:-internal-autofill-previewed,
select:-internal-autofill-previewed {
- color: CanvasText !important;
background-color: Canvas !important;
+ -internal-forced-background-color: Canvas !important;
+ -internal-forced-color: CanvasText !important;
}
input:-internal-autofill-selected,
textarea:-internal-autofill-selected,
select:-internal-autofill-selected {
- color: CanvasText !important;
background-color: Canvas !important;
+ -internal-forced-background-color: Canvas !important;
+ -internal-forced-color: CanvasText !important;
}
}
diff --git a/chromium/third_party/blink/renderer/core/html/resources/html.css b/chromium/third_party/blink/renderer/core/html/resources/html.css
index da6f733ac6f..c98a0f6c11b 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/html.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/html.css
@@ -150,6 +150,32 @@ video {
object-fit: contain;
}
+video:-webkit-full-page-media {
+ margin: auto;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+audio:not([controls]) {
+ display: none !important;
+}
+
+/** TODO(crbug.com/985623): Remove these hard-coded audio tag size.
+ * This fixed audio tag width/height leads to fail the wpt tests below.
+ * crbug.com/955170 external/wpt/css/css-contain/contain-size-replaced-003a.html
+ * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003b.html
+ * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003c.html
+ */
+audio {
+ width: 300px;
+ height: 54px;
+}
+
/* heading elements */
h1 {
@@ -424,7 +450,7 @@ input[type="hidden" i] {
}
input {
- -webkit-appearance: textfield; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
padding: 1px;
background-color: -internal-light-dark(white, black);
border: 2px inset;
@@ -433,7 +459,7 @@ input {
}
input[type="search" i] {
- -webkit-appearance: searchfield; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
box-sizing: border-box;
}
@@ -500,7 +526,7 @@ select {
}
textarea {
- -webkit-appearance: textarea; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
background-color: -internal-light-dark(white, black);
border: 1px solid;
column-count: initial !important;
@@ -557,7 +583,7 @@ input[type="password" i]::-internal-input-suggested {
}
input[type="hidden" i], input[type="image" i], input[type="file" i] {
- -webkit-appearance: initial; /* AutoAppearanceFor() should match to this. */
+ appearance: none;
padding: initial;
background-color: initial;
border: initial;
@@ -582,7 +608,7 @@ input[type="image" i] {
input:-internal-autofill-previewed,
textarea:-internal-autofill-previewed,
select:-internal-autofill-previewed {
- -webkit-appearance:menulist-button;
+ appearance: menulist-button;
background-color: #E8F0FE !important;
background-image:none !important;
color: -internal-light-dark(black, white) !important;
@@ -591,7 +617,7 @@ select:-internal-autofill-previewed {
input:-internal-autofill-selected,
textarea:-internal-autofill-selected,
select:-internal-autofill-selected {
- -webkit-appearance:menulist-button;
+ appearance: menulist-button;
background-color: #E8F0FE !important;
background-image:none !important;
color: -internal-light-dark(black, white) !important;
@@ -633,7 +659,7 @@ input[type="button" i], input[type="submit" i], input[type="reset" i], input[typ
}
input[type="range" i] {
- -webkit-appearance: slider-horizontal; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
padding: initial;
border: initial;
margin: 2px;
@@ -755,7 +781,7 @@ input[type="color" i]::-webkit-color-swatch {
}
input[type="color" i][list] {
- -webkit-appearance: menulist; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
width: 88px;
height: 23px
}
@@ -812,7 +838,7 @@ input[readonly]::-webkit-calendar-picker-indicator {
}
select {
- -webkit-appearance: menulist; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
box-sizing: border-box;
align-items: center;
border: 1px solid;
@@ -828,7 +854,7 @@ select:not(:-internal-list-box) {
}
select:-internal-list-box {
- -webkit-appearance: listbox; /* AutoAppearanceFor() should match to this. */
+ appearance: auto;
align-items: flex-start;
border: 1px inset gray;
border-radius: initial;
@@ -847,7 +873,7 @@ option {
font-weight: normal;
display: block;
padding: 0 2px 1px 2px;
- white-space: pre;
+ white-space: nowrap;
min-height: 1.2em;
}
@@ -885,11 +911,24 @@ select:-internal-list-box hr {
margin-block-end: 0;
}
-select:-internal-list-box:focus option:-internal-multi-select-focus {
+select:-internal-list-box:focus-visible option:-internal-multi-select-focus {
outline: auto 1px -webkit-focus-ring-color;
outline-offset: -1px;
}
+/* selectmenu */
+
+/* TODO(crbug.com/1121840) It's deliberate for now that this provides styles
+for <option> but not other element types with part="option". Could this
+be a mechanism for allowing authors to specify their own styles for
+option parts by using e.g. <div part="option">, while authors that
+want the default styles can instead just use <option>? */
+selectmenu option:hover {
+ background-color: lightgray;
+ cursor: default;
+ user-select: none;
+}
+
output {
display: inline;
}
@@ -1053,31 +1092,31 @@ nobr {
box-shadow: none !important
}
-:focus {
+:focus-visible {
outline: auto 1px -webkit-focus-ring-color
}
-html:focus, body:focus {
+html:focus-visible, body:focus-visible {
outline: none
}
-embed:focus, iframe:focus, object:focus {
+embed:focus-visible, iframe:focus-visible, object:focus-visible {
outline: none
}
-input:focus, textarea:focus, select:focus {
+input:focus-visible, textarea:focus-visible, select:focus-visible {
outline-offset: -2px
}
-input[type="button" i]:focus,
-input[type="checkbox" i]:focus,
-input[type="file" i]:focus,
-input[type="hidden" i]:focus,
-input[type="image" i]:focus,
-input[type="radio" i]:focus,
-input[type="reset" i]:focus,
-input[type="submit" i]:focus,
-input[type="file" i]:focus::-webkit-file-upload-button {
+input[type="button" i]:focus-visible,
+input[type="checkbox" i]:focus-visible,
+input[type="file" i]:focus-visible,
+input[type="hidden" i]:focus-visible,
+input[type="image" i]:focus-visible,
+input[type="radio" i]:focus-visible,
+input[type="reset" i]:focus-visible,
+input[type="submit" i]:focus-visible,
+input[type="file" i]:focus-visible::-webkit-file-upload-button {
outline-offset: 0
}
@@ -1204,6 +1243,26 @@ dialog::backdrop {
background: rgba(0,0,0,0.1)
}
+popup:not(:-internal-popup-open) {
+ display: none !important;
+}
+popup {
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ /* The rest here is copied from dialog, perhaps these shouldn't
+ apply to popup. At least the background color is nice, because
+ it obscures the backdrop. And the foreground color/border
+ help to set off the popup from the rest of the page. */
+ width: fit-content;
+ height: fit-content;
+ border: 1px solid;
+ padding: 1em;
+ background: -internal-light-dark(white, black);
+ color: -internal-light-dark(black, white);
+}
+
slot {
display: contents;
}
diff --git a/chromium/third_party/blink/renderer/core/html/resources/images/time_icon.svg b/chromium/third_party/blink/renderer/core/html/resources/images/time_icon.svg
index 71a94c0ba2c..d9c2206df46 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/images/time_icon.svg
+++ b/chromium/third_party/blink/renderer/core/html/resources/images/time_icon.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24"><path fill="WindowText" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path d="M0 0h24v24H0z" fill="none"/><path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24"><path fill="WindowText" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path d="M0 0h24v24H0z" fill="none"/><path fill="WindowText" d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg> \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/html/resources/input_multiple_fields.css b/chromium/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
index d0591f61232..a42f7837204 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
@@ -56,7 +56,7 @@ input::-webkit-datetime-edit-year-field {
padding: 1px;
}
-/* Remove focus ring from fields and use highlight color */
+/* Use highlight color. */
input::-webkit-datetime-edit-ampm-field:focus,
input::-webkit-datetime-edit-day-field:focus,
input::-webkit-datetime-edit-hour-field:focus,
@@ -68,7 +68,6 @@ input::-webkit-datetime-edit-week-field:focus,
input::-webkit-datetime-edit-year-field:focus {
background-color: highlight;
color: highlighttext;
- outline: none;
}
input::-webkit-datetime-edit-year-field[disabled],
diff --git a/chromium/third_party/blink/renderer/core/html/resources/mac.css b/chromium/third_party/blink/renderer/core/html/resources/mac.css
index 1e1677ba858..bcf5cfa0ea1 100644
--- a/chromium/third_party/blink/renderer/core/html/resources/mac.css
+++ b/chromium/third_party/blink/renderer/core/html/resources/mac.css
@@ -42,6 +42,6 @@ button {
box-shadow: none !important
}
-:focus {
+:focus-visible {
outline: auto 5px -webkit-focus-ring-color
}
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
index f1cea3811d9..7cd7a66e29c 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.cc
@@ -44,9 +44,10 @@ HTMLProgressElement* ProgressShadowElement::ProgressElement() const {
return To<HTMLProgressElement>(OwnerShadowHost());
}
-scoped_refptr<ComputedStyle>
-ProgressShadowElement::CustomStyleForLayoutObject() {
- scoped_refptr<ComputedStyle> style = OriginalStyleForLayoutObject();
+scoped_refptr<ComputedStyle> ProgressShadowElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
+ scoped_refptr<ComputedStyle> style =
+ OriginalStyleForLayoutObject(style_recalc_context);
const ComputedStyle* progress_style = ProgressElement()->GetComputedStyle();
DCHECK(progress_style);
if (progress_style->HasEffectiveAppearance())
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
index aab050ec608..3f5c1f9a234 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
+++ b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element.h
@@ -45,7 +45,8 @@ class ProgressShadowElement : public HTMLDivElement {
private:
HTMLProgressElement* ProgressElement() const;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
index a9e1e36542b..4e8c0ec11f5 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
@@ -44,7 +44,8 @@ TEST_F(ProgressShadowElementTest, LayoutObjectIsNeeded) {
GetDocument().GetStyleEngine().RecalcStyle();
EXPECT_TRUE(shadow_element->GetComputedStyle());
- scoped_refptr<ComputedStyle> style = shadow_element->StyleForLayoutObject();
+ scoped_refptr<ComputedStyle> style =
+ shadow_element->StyleForLayoutObject(StyleRecalcContext());
EXPECT_TRUE(shadow_element->LayoutObjectIsNeeded(*style));
}
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_names.json5 b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_names.json5
index e97b4ca6d03..daebf310885 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_names.json5
+++ b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_names.json5
@@ -53,7 +53,7 @@
Symbol: "kIdSearchClearButton",
},
{
- name: "passwrod-reveal",
+ name: "password-reveal",
Symbol: "kIdPasswordRevealButton",
},
{
@@ -90,6 +90,10 @@
Symbol: "kPseudoInputPlaceholder",
},
{
+ name: "-webkit-file-upload-button",
+ Symbol: "kPseudoFileUploadButton",
+ },
+ {
name: "-internal-input-suggested",
Symbol: "kPseudoInternalInputSuggested",
},
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.cc b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.cc
index 27b11ad59f8..805cadfa6f0 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.cc
+++ b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.cc
@@ -28,6 +28,16 @@ bool IsSliderThumb(const Node* node) {
shadow_pseudo == shadow_element_names::kPseudoSliderThumb;
}
+bool IsTextControlContainer(const Node* node) {
+ const auto* element = DynamicTo<Element>(node);
+ if (!element || !element->IsInUserAgentShadowRoot())
+ return false;
+ if (!IsTextControl(element->OwnerShadowHost()))
+ return false;
+ return element->GetIdAttribute() ==
+ shadow_element_names::kIdTextFieldContainer;
+}
+
bool IsTextControlPlaceholder(const Node* node) {
const auto* element = DynamicTo<Element>(node);
if (!element || !element->IsInUserAgentShadowRoot())
diff --git a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.h b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.h
index 8be28138276..44d9635df2b 100644
--- a/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.h
+++ b/chromium/third_party/blink/renderer/core/html/shadow/shadow_element_utils.h
@@ -12,6 +12,7 @@ class Node;
bool IsSliderContainer(const Element& elmenet);
bool IsSliderThumb(const Node* node);
+bool IsTextControlContainer(const Node* node);
bool IsTextControlPlaceholder(const Node* node);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/subresource_redirect_test.cc b/chromium/third_party/blink/renderer/core/html/subresource_redirect_test.cc
index 8be019cdb05..8fa652c3c01 100644
--- a/chromium/third_party/blink/renderer/core/html/subresource_redirect_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/subresource_redirect_test.cc
@@ -4,11 +4,13 @@
#include <tuple>
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/style_image.h"
@@ -57,17 +59,52 @@ class SubresourceRedirectSimTest
GetDocument().UpdateStyleAndLayoutTree();
}
+ // Loads the main page resource and then loads the given image in the page.
+ void LoadMainResourceAndImage(const String& html_body,
+ const String& img_url) {
+ SimRequest image_resource(img_url, "image/png");
+ LoadMainResource(html_body);
+
+ if (!is_lazyload_image_enabled())
+ image_resource.Complete(ReadTestImage());
+
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+
+ if (is_lazyload_image_enabled()) {
+ // Scroll down until the image is visible.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 10000), mojom::blink::ScrollType::kProgrammatic);
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+ image_resource.Complete(ReadTestImage());
+ }
+ }
+
+ // Verifies previews state for the fetched request URL.
+ void VerifySubresourceRedirectPreviewsState(
+ const String& url,
+ bool is_subresource_redirect_allowed) {
+ PreviewsState previews_state = GetDocument()
+ .Fetcher()
+ ->CachedResource(KURL(url))
+ ->GetResourceRequest()
+ .GetPreviewsState();
+ EXPECT_EQ(is_subresource_redirect_allowed,
+ (previews_state & PreviewsTypes::kSubresourceRedirectOn) != 0);
+ }
+
ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test_;
ScopedAutomaticLazyImageLoadingForTest
scoped_automatic_lazy_image_loading_for_test_;
base::test::ScopedFeatureList scoped_feature_list_;
+ base::HistogramTester histogram_tester_;
};
// This test verifies subresource redirect previews state based on different
// states of SaveData, LazyLoad, SubresourceRedirect features.
TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) {
- SimRequest image_resource("https://example.com/img.png", "image/png");
- LoadMainResource(R"HTML(
+ LoadMainResourceAndImage(R"HTML(
<style>
#deferred_image {
height:200px;
@@ -76,33 +113,159 @@ TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) {
</style>
<div style='height:10000px;'></div>
<div id="deferred_image"></div>
- )HTML");
+ )HTML",
+ "https://example.com/img.png");
- if (!is_lazyload_image_enabled())
- image_resource.Complete(ReadTestImage());
-
- Compositor().BeginFrame();
- test::RunPendingTasks();
+ // Subresource redirect previews bit should be set only if SaveData and
+ // SubresourceRedirect feature are enabled.
+ VerifySubresourceRedirectPreviewsState(
+ "https://example.com/img.png",
+ is_save_data_enabled() && is_subresource_redirect_enabled());
+}
- if (is_lazyload_image_enabled()) {
- // Scroll down until the background image is visible.
- GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 10000), mojom::blink::ScrollType::kProgrammatic);
- Compositor().BeginFrame();
- test::RunPendingTasks();
- image_resource.Complete(ReadTestImage());
- }
+TEST_P(SubresourceRedirectSimTest, ImgElement) {
+ LoadMainResourceAndImage(R"HTML(
+ <body>
+ <img src='https://example.com/img.png' loading='lazy'/>
+ </body>
+ )HTML",
+ "https://example.com/img.png");
- PreviewsState previews_state =
- GetDocument()
- .Fetcher()
- ->CachedResource(KURL("https://example.com/img.png"))
- ->GetResourceRequest()
- .GetPreviewsState();
// Subresource redirect previews bit should be set only if SaveData and
// SubresourceRedirect feature are enabled.
- EXPECT_EQ(is_save_data_enabled() && is_subresource_redirect_enabled(),
- (previews_state & PreviewsTypes::kSubresourceRedirectOn) != 0);
+ VerifySubresourceRedirectPreviewsState(
+ "https://example.com/img.png",
+ is_save_data_enabled() && is_subresource_redirect_enabled());
+
+ histogram_tester_.ExpectTotalCount("SubresourceRedirect.Blink.Ineligibility",
+ 0);
+}
+
+TEST_P(SubresourceRedirectSimTest, JavascriptCreatedSameOriginImage) {
+ LoadMainResourceAndImage(R"HTML(
+ <body>
+ <div></div>
+ <script>
+ var img = document.createElement("img");
+ img.loading = 'lazy';
+ img.src = 'https://example.com/img.png';
+ document.getElementsByTagName('div')[0].appendChild(img);
+ </script>
+ </body>
+ )HTML",
+ "https://example.com/img.png");
+
+ VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
+
+ if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
+ histogram_tester_.ExpectUniqueSample(
+ "SubresourceRedirect.Blink.Ineligibility",
+ BlinkSubresourceRedirectIneligibility::kJavascriptCreatedSameOrigin,
+ is_lazyload_image_enabled() ? 2 : 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SubresourceRedirect.Blink.Ineligibility", 0);
+ }
+}
+
+TEST_P(SubresourceRedirectSimTest, JavascriptCreatedCrossOriginImage) {
+ LoadMainResourceAndImage(R"HTML(
+ <body>
+ <div></div>
+ <script>
+ var img = document.createElement("img");
+ img.loading = 'lazy';
+ img.src = 'https://differentorigin.com/img.png';
+ document.getElementsByTagName('div')[0].appendChild(img);
+ </script>
+ </body>
+ )HTML",
+ "https://differentorigin.com/img.png");
+
+ VerifySubresourceRedirectPreviewsState("https://differentorigin.com/img.png",
+ false);
+
+ if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
+ histogram_tester_.ExpectUniqueSample(
+ "SubresourceRedirect.Blink.Ineligibility",
+ BlinkSubresourceRedirectIneligibility::kJavascriptCreatedCrossOrigin,
+ is_lazyload_image_enabled() ? 2 : 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SubresourceRedirect.Blink.Ineligibility", 0);
+ }
+}
+
+TEST_P(SubresourceRedirectSimTest, ImgElementWithCrossOriginAttribute) {
+ LoadMainResourceAndImage(R"HTML(
+ <body>
+ <img src='https://example.com/img.png' loading='lazy' crossorigin='anonymous'/>
+ </body>
+ )HTML",
+ "https://example.com/img.png");
+
+ VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
+
+ if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
+ histogram_tester_.ExpectUniqueSample(
+ "SubresourceRedirect.Blink.Ineligibility",
+ BlinkSubresourceRedirectIneligibility::kCrossOriginAttributeSet,
+ is_lazyload_image_enabled() ? 2 : 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SubresourceRedirect.Blink.Ineligibility", 0);
+ }
+}
+
+TEST_P(SubresourceRedirectSimTest,
+ RestrictedByContentSecurityPolicyDefaultSrc) {
+ LoadMainResourceAndImage(R"HTML(
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
+ </head>
+ <body>
+ <img src='https://example.com/img.png' loading='lazy'/>
+ </body>
+ )HTML",
+ "https://example.com/img.png");
+
+ VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
+
+ if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
+ histogram_tester_.ExpectUniqueSample(
+ "SubresourceRedirect.Blink.Ineligibility",
+ BlinkSubresourceRedirectIneligibility::
+ kContentSecurityPolicyDefaultSrcRestricted,
+ is_lazyload_image_enabled() ? 2 : 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SubresourceRedirect.Blink.Ineligibility", 0);
+ }
+}
+
+TEST_P(SubresourceRedirectSimTest, RestrictedByContentSecurityPolicyImgSrc) {
+ LoadMainResourceAndImage(R"HTML(
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="img-src 'self'">
+ </head>
+ <body>
+ <img src='https://example.com/img.png' loading='lazy'/>
+ </body>
+ )HTML",
+ "https://example.com/img.png");
+
+ VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
+
+ if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
+ histogram_tester_.ExpectUniqueSample(
+ "SubresourceRedirect.Blink.Ineligibility",
+ BlinkSubresourceRedirectIneligibility::
+ kContentSecurityPolicyImgSrcRestricted,
+ is_lazyload_image_enabled() ? 2 : 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SubresourceRedirect.Blink.Ineligibility", 0);
+ }
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/chromium/third_party/blink/renderer/core/html/track/DIR_METADATA b/chromium/third_party/blink/renderer/core/html/track/DIR_METADATA
new file mode 100644
index 00000000000..ea2b83774ac
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/html/track/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Media>Track"
+}
diff --git a/chromium/third_party/blink/renderer/core/html/track/OWNERS b/chromium/third_party/blink/renderer/core/html/track/OWNERS
index 05096386007..068ec2721b0 100644
--- a/chromium/third_party/blink/renderer/core/html/track/OWNERS
+++ b/chromium/third_party/blink/renderer/core/html/track/OWNERS
@@ -1,5 +1,3 @@
foolip@chromium.org
fs@opera.com
srirama.m@samsung.com
-
-# COMPONENT: Blink>Media>Track
diff --git a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
index a8c2f0b4542..171ad5b8c19 100644
--- a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.cc
@@ -422,7 +422,7 @@ CueTimeline::IgnoreUpdateScope CueTimeline::BeginIgnoreUpdateScope() {
return scope;
}
-void CueTimeline::EndIgnoreUpdateScope(util::PassKey<IgnoreUpdateScope>,
+void CueTimeline::EndIgnoreUpdateScope(base::PassKey<IgnoreUpdateScope>,
IgnoreUpdateScope const& scope) {
DCHECK(ignore_update_);
--ignore_update_;
@@ -543,6 +543,8 @@ void CueTimeline::DidMoveToNewDocument(Document& /*old_document*/) {
void CueTimeline::Trace(Visitor* visitor) const {
visitor->Trace(media_element_);
+ visitor->Trace(cue_event_timer_);
+ visitor->Trace(cue_timestamp_event_timer_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
index e84973bc7ca..dad9ce9f138 100644
--- a/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
+++ b/chromium/third_party/blink/renderer/core/html/track/cue_timeline.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_CUE_TIMELINE_H_
#include "base/optional.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/html/track/text_track_cue.h"
#include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -39,7 +39,7 @@ class CueTimeline final : public GarbageCollected<CueTimeline> {
public:
~IgnoreUpdateScope() {
DCHECK(cue_timeline_);
- cue_timeline_->EndIgnoreUpdateScope(util::PassKey<IgnoreUpdateScope>(),
+ cue_timeline_->EndIgnoreUpdateScope(base::PassKey<IgnoreUpdateScope>(),
*this);
}
@@ -68,7 +68,7 @@ class CueTimeline final : public GarbageCollected<CueTimeline> {
bool InsideIgnoreUpdateScope() const { return ignore_update_ > 0; }
IgnoreUpdateScope BeginIgnoreUpdateScope();
- void EndIgnoreUpdateScope(util::PassKey<IgnoreUpdateScope>,
+ void EndIgnoreUpdateScope(base::PassKey<IgnoreUpdateScope>,
IgnoreUpdateScope const& scope);
void DidMoveToNewDocument(Document& old_document);
@@ -100,11 +100,11 @@ class CueTimeline final : public GarbageCollected<CueTimeline> {
// Timer data for cue events (start, end)
base::Optional<double> next_cue_event_;
- TaskRunnerTimer<CueTimeline> cue_event_timer_;
+ HeapTaskRunnerTimer<CueTimeline> cue_event_timer_;
// Timer data for cue timestamps
// https://w3c.github.io/webvtt/#ref-for-webvtt-timestamp-6
- TaskRunnerTimer<CueTimeline> cue_timestamp_event_timer_;
+ HeapTaskRunnerTimer<CueTimeline> cue_timestamp_event_timer_;
int ignore_update_;
bool update_requested_while_ignoring_;
diff --git a/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc b/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
index 248c3ebb6da..0dd80f19dcf 100644
--- a/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/html_track_element.cc
@@ -343,6 +343,7 @@ HTMLMediaElement* HTMLTrackElement::MediaElement() const {
void HTMLTrackElement::Trace(Visitor* visitor) const {
visitor->Trace(track_);
visitor->Trace(loader_);
+ visitor->Trace(load_timer_);
HTMLElement::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/html_track_element.h b/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
index c3f391ae30a..9c207bbb083 100644
--- a/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
+++ b/chromium/third_party/blink/renderer/core/html/track/html_track_element.h
@@ -42,6 +42,7 @@ class HTMLTrackElement final : public HTMLElement,
public:
explicit HTMLTrackElement(Document&);
+ ~HTMLTrackElement() override;
const AtomicString& kind();
void setKind(const AtomicString&);
@@ -55,8 +56,6 @@ class HTMLTrackElement final : public HTMLElement,
void Trace(Visitor*) const override;
private:
- ~HTMLTrackElement() override;
-
void ParseAttribute(const AttributeModificationParams&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
@@ -83,7 +82,7 @@ class HTMLTrackElement final : public HTMLElement,
Member<LoadableTextTrack> track_;
Member<TextTrackLoader> loader_;
- TaskRunnerTimer<HTMLTrackElement> load_timer_;
+ HeapTaskRunnerTimer<HTMLTrackElement> load_timer_;
KURL url_;
};
diff --git a/chromium/third_party/blink/renderer/core/html/track/track_base.h b/chromium/third_party/blink/renderer/core/html/track/track_base.h
index 055fe6e79db..70e673ed75f 100644
--- a/chromium/third_party/blink/renderer/core/html/track/track_base.h
+++ b/chromium/third_party/blink/renderer/core/html/track/track_base.h
@@ -70,10 +70,6 @@ class CORE_EXPORT TrackBase : public Supplementable<TrackBase> {
Member<HTMLMediaElement> media_element_;
};
-#define DEFINE_TRACK_TYPE_CASTS(thisType, predicate) \
- DEFINE_TYPE_CASTS(thisType, TrackBase, track, track->GetType() == predicate, \
- track.GetType() == predicate)
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_TRACK_BASE_H_
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
index 727caa18bac..351917da340 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
@@ -244,9 +244,8 @@ VTTParser::ParseState VTTParser::CollectRegionSettings(const String& line) {
VTTParser::ParseState VTTParser::CollectStyleSheet(const String& line) {
if (line.IsEmpty() || line.Contains("-->")) {
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
- *document_, NullURL(), true /* origin_clean */,
- document_->GetReferrerPolicy(), UTF8Encoding(),
- CSSParserContext::kLiveProfile,
+ *document_, NullURL(), true /* origin_clean */, Referrer(),
+ UTF8Encoding(), CSSParserContext::kLiveProfile,
ResourceFetchRestriction::kOnlyDataUrls);
auto* style_sheet_contents =
MakeGarbageCollected<StyleSheetContents>(parser_context);
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
index d551daa9dea..8ff5c053965 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.cc
@@ -422,6 +422,7 @@ void VTTRegion::ScrollTimerFired(TimerBase*) {
void VTTRegion::Trace(Visitor* visitor) const {
visitor->Trace(cue_container_);
visitor->Trace(region_display_tree_);
+ visitor->Trace(scroll_timer_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
index 87dadf7ad56..04a0ea0e3f9 100644
--- a/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
+++ b/chromium/third_party/blink/renderer/core/html/track/vtt/vtt_region.h
@@ -132,7 +132,7 @@ class VTTRegion final : public ScriptWrappable {
// soon as the animation for rolling out one line has finished, but
// currently it is used also for non-scrolling regions to use a single
// code path.
- TaskRunnerTimer<VTTRegion> scroll_timer_;
+ HeapTaskRunnerTimer<VTTRegion> scroll_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/DIR_METADATA b/chromium/third_party/blink/renderer/core/imagebitmap/DIR_METADATA
new file mode 100644
index 00000000000..4ae95d48d73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Canvas"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/OWNERS b/chromium/third_party/blink/renderer/core/imagebitmap/OWNERS
index 5ef87b1aa3f..1e563633b29 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/OWNERS
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/OWNERS
@@ -1,4 +1 @@
fserb@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/build.gni b/chromium/third_party/blink/renderer/core/imagebitmap/build.gni
index 3fe0219b58d..befd5f704b1 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/build.gni
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/build.gni
@@ -5,8 +5,6 @@
blink_core_sources_imagebitmap = [
"image_bitmap.cc",
"image_bitmap.h",
- "image_bitmap_factories.cc",
- "image_bitmap_factories.h",
"image_bitmap_source.cc",
"image_bitmap_source.h",
]
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 922ddfc1556..b5a1eedb59e 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -14,6 +14,7 @@
#include "gpu/config/gpu_feature_info.h"
#include "skia/ext/legacy_display_globals.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/web_media_player.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/canvas/image_data.h"
@@ -28,6 +29,7 @@
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
@@ -37,14 +39,12 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSwizzle.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
namespace blink {
constexpr const char* kImageOrientationFlipY = "flipY";
constexpr const char* kImageBitmapOptionNone = "none";
constexpr const char* kImageBitmapOptionDefault = "default";
-constexpr const char* kImageBitmapPixelFormatUint8Name = "uint8";
constexpr const char* kImageBitmapOptionPremultiply = "premultiply";
constexpr const char* kImageBitmapOptionResizeQualityHigh = "high";
constexpr const char* kImageBitmapOptionResizeQualityMedium = "medium";
@@ -80,9 +80,6 @@ ImageBitmap::ParsedOptions ParseOptions(const ImageBitmapOptions* options,
DCHECK(options->imageOrientation() == kImageBitmapOptionNone);
}
- if (options->imagePixelFormat() == kImageBitmapPixelFormatUint8Name)
- parsed_options.pixel_format = kImageBitmapPixelFormat_Uint8;
-
if (options->premultiplyAlpha() == kImageBitmapOptionNone) {
parsed_options.premultiply_alpha = false;
} else {
@@ -93,7 +90,6 @@ ImageBitmap::ParsedOptions ParseOptions(const ImageBitmapOptions* options,
parsed_options.has_color_space_conversion =
(options->colorSpaceConversion() != kImageBitmapOptionNone);
- parsed_options.color_params.SetCanvasColorSpace(CanvasColorSpace::kSRGB);
if (options->colorSpaceConversion() != kImageBitmapOptionNone &&
options->colorSpaceConversion() != kImageBitmapOptionDefault) {
NOTREACHED()
@@ -148,11 +144,11 @@ ImageBitmap::ParsedOptions ParseOptions(const ImageBitmapOptions* options,
// The function dstBufferSizeHasOverflow() is being called at the beginning of
// each ImageBitmap() constructor, which makes sure that doing
// width * height * bytesPerPixel will never overflow unsigned.
+// This function assumes that the pixel format is N32.
bool DstBufferSizeHasOverflow(const ImageBitmap::ParsedOptions& options) {
base::CheckedNumeric<unsigned> total_bytes = options.crop_rect.Width();
total_bytes *= options.crop_rect.Height();
- total_bytes *=
- SkColorTypeBytesPerPixel(options.color_params.GetSkColorType());
+ total_bytes *= SkColorTypeBytesPerPixel(kN32_SkColorType);
if (!total_bytes.IsValid())
return true;
@@ -160,8 +156,7 @@ bool DstBufferSizeHasOverflow(const ImageBitmap::ParsedOptions& options) {
return false;
total_bytes = options.resize_width;
total_bytes *= options.resize_height;
- total_bytes *=
- SkColorTypeBytesPerPixel(options.color_params.GetSkColorType());
+ total_bytes *= SkColorTypeBytesPerPixel(kN32_SkColorType);
if (!total_bytes.IsValid())
return true;
@@ -211,11 +206,6 @@ Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input,
return dst_buffer;
}
-Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input) {
- SkImageInfo info = GetSkImageInfo(input);
- return CopyImageData(std::move(input), info, false);
-}
-
static inline bool ShouldAvoidPremul(
const ImageBitmap::ParsedOptions& options) {
return options.source_is_unpremul && !options.premultiply_alpha;
@@ -227,7 +217,9 @@ std::unique_ptr<CanvasResourceProvider> CreateProvider(
const scoped_refptr<StaticBitmapImage>& source_image,
bool fallback_to_software) {
IntSize size(info.width(), info.height());
- CanvasColorParams color_params(info);
+
+ const SkFilterQuality filter_quality = kLow_SkFilterQuality;
+ const CanvasResourceParams resource_params(info);
if (context_provider) {
uint32_t usage_flags =
@@ -235,7 +227,7 @@ std::unique_ptr<CanvasResourceProvider> CreateProvider(
->SharedImageInterface()
->UsageForMailbox(source_image->GetMailboxHolder().mailbox);
auto resource_provider = CanvasResourceProvider::CreateSharedImageProvider(
- size, kLow_SkFilterQuality, color_params,
+ size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kNo, context_provider,
RasterMode::kGPU, source_image->IsOriginTopLeft(), usage_flags);
if (resource_provider)
@@ -246,41 +238,10 @@ std::unique_ptr<CanvasResourceProvider> CreateProvider(
}
return CanvasResourceProvider::CreateBitmapProvider(
- size, kLow_SkFilterQuality, color_params,
+ size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kNo);
}
-std::unique_ptr<CanvasResourceProvider> CreateProviderForVideoElement(
- HTMLVideoElement* video,
- const ImageBitmapOptions* options) {
- // TODO(crbug.com/1098445): ImageBitmap resize test case failed when
- // quality equals to "low" and "medium". Need further investigate to
- // enable gpu backed imageBitmap with resize options.
- if (!SharedGpuContext::ContextProviderWrapper() ||
- SharedGpuContext::ContextProviderWrapper()
- ->ContextProvider()
- ->GetGpuFeatureInfo()
- .IsWorkaroundEnabled(DISABLE_IMAGEBITMAP_FROM_VIDEO_USING_GPU) ||
- options->hasResizeWidth() || options->hasResizeHeight()) {
- return CanvasResourceProvider::CreateBitmapProvider(
- IntSize(video->videoWidth(), video->videoHeight()),
- kLow_SkFilterQuality, CanvasColorParams(),
- CanvasResourceProvider::ShouldInitialize::kCallClear);
- }
-
- uint32_t shared_image_usage_flags = gpu::SHARED_IMAGE_USAGE_DISPLAY;
-
- return CanvasResourceProvider::CreateSharedImageProvider(
- IntSize(video->videoWidth(), video->videoHeight()), kLow_SkFilterQuality,
- CanvasColorParams(CanvasColorSpace::kSRGB,
- CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque), // Default canvas settings,
- CanvasResourceProvider::ShouldInitialize::kCallClear,
- SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
- false, // Origin of GL texture is bottom left on screen
- shared_image_usage_flags);
-}
-
scoped_refptr<StaticBitmapImage> FlipImageVertically(
scoped_refptr<StaticBitmapImage> input,
const ImageBitmap::ParsedOptions& parsed_options) {
@@ -334,7 +295,8 @@ scoped_refptr<StaticBitmapImage> FlipImageVertically(
canvas->translate(0, -input->height());
cc::PaintFlags paint;
paint.setBlendMode(SkBlendMode::kSrc);
- canvas->drawImage(input->PaintImageForCurrentFrame(), 0, 0, &paint);
+ canvas->drawImage(input->PaintImageForCurrentFrame(), 0, 0,
+ SkSamplingOptions(), &paint);
return resource_provider->Snapshot(input->CurrentFrameOrientation());
}
@@ -366,7 +328,7 @@ scoped_refptr<StaticBitmapImage> GetImageWithAlphaDisposition(
cc::PaintFlags paint;
paint.setBlendMode(SkBlendMode::kSrc);
resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(),
- 0, 0, &paint);
+ 0, 0, SkSamplingOptions(), &paint);
return resource_provider->Snapshot(image->CurrentFrameOrientation());
}
@@ -403,14 +365,16 @@ scoped_refptr<StaticBitmapImage> ScaleImage(
CreateProvider(image->ContextProviderWrapper(), image_info, image,
false /* fallback_to_software */);
if (resource_provider) {
+ SkSamplingOptions sampling(parsed_options.resize_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear);
cc::PaintFlags paint;
- paint.setFilterQuality(parsed_options.resize_quality);
+ paint.setBlendMode(SkBlendMode::kSrc);
resource_provider->Canvas()->drawImageRect(
image->PaintImageForCurrentFrame(),
SkRect::MakeWH(src_image_info.width(), src_image_info.height()),
SkRect::MakeWH(parsed_options.resize_width,
parsed_options.resize_height),
- &paint, SkCanvas::kStrict_SrcRectConstraint);
+ sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
return resource_provider->Snapshot(image->CurrentFrameOrientation());
}
}
@@ -428,7 +392,12 @@ scoped_refptr<StaticBitmapImage> ScaleImage(
SkPixmap resized_pixmap(image_info, image_pixels->data(),
image_info.minRowBytes());
auto sk_image = image->PaintImageForCurrentFrame().GetSwSkImage();
- sk_image->scalePixels(resized_pixmap, parsed_options.resize_quality);
+ if (!sk_image)
+ return nullptr;
+ sk_image->scalePixels(
+ resized_pixmap,
+ SkSamplingOptions(parsed_options.resize_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear));
// Tag the resized Pixmap with the correct color space.
resized_pixmap.setColorSpace(GetSkImageInfo(image).refColorSpace());
@@ -444,7 +413,7 @@ scoped_refptr<StaticBitmapImage> ScaleImage(
scoped_refptr<StaticBitmapImage> ApplyColorSpaceConversion(
scoped_refptr<StaticBitmapImage>&& image,
ImageBitmap::ParsedOptions& options) {
- sk_sp<SkColorSpace> color_space = options.color_params.GetSkColorSpace();
+ sk_sp<SkColorSpace> color_space = SkColorSpace::MakeSRGB();
SkColorType color_type =
image->IsTextureBacked() ? kRGBA_8888_SkColorType : kN32_SkColorType;
SkImageInfo src_image_info =
@@ -460,8 +429,7 @@ scoped_refptr<StaticBitmapImage> MakeBlankImage(
const ImageBitmap::ParsedOptions& parsed_options) {
SkImageInfo info = SkImageInfo::Make(
parsed_options.crop_rect.Width(), parsed_options.crop_rect.Height(),
- parsed_options.color_params.GetSkColorType(), kPremul_SkAlphaType,
- parsed_options.color_params.GetSkColorSpace());
+ kN32_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
if (parsed_options.should_scale_input) {
info =
info.makeWH(parsed_options.resize_width, parsed_options.resize_height);
@@ -472,27 +440,6 @@ scoped_refptr<StaticBitmapImage> MakeBlankImage(
return UnacceleratedStaticBitmapImage::Create(surface->makeImageSnapshot());
}
-scoped_refptr<StaticBitmapImage> GetImageWithPixelFormat(
- scoped_refptr<StaticBitmapImage>&& image,
- ImageBitmapPixelFormat pixel_format) {
- if (pixel_format == kImageBitmapPixelFormat_Default)
- return std::move(image);
- // If the the image is not half float backed, default and uint8 image bitmap
- // pixel formats result in the same uint8 backed image bitmap.
- SkImageInfo image_info = image->PaintImageForCurrentFrame().GetSkImageInfo();
- if (image_info.colorType() != kRGBA_F16_SkColorType)
- return std::move(image);
-
- auto skia_image = image->PaintImageForCurrentFrame().GetSwSkImage();
- SkImageInfo target_info = image_info.makeColorType(kN32_SkColorType);
- SkBitmap target_bitmap;
- target_bitmap.allocPixels(target_info);
- bool read_successful = skia_image->readPixels(target_bitmap.pixmap(), 0, 0);
- DCHECK(read_successful);
- return UnacceleratedStaticBitmapImage::Create(
- SkImage::MakeFromBitmap(target_bitmap));
-}
-
static scoped_refptr<StaticBitmapImage> CropImageAndApplyColorSpaceConversion(
scoped_refptr<StaticBitmapImage>&& image,
ImageBitmap::ParsedOptions& parsed_options) {
@@ -517,13 +464,15 @@ static scoped_refptr<StaticBitmapImage> CropImageAndApplyColorSpaceConversion(
true /* fallback_to_software*/);
if (!resource_provider)
return nullptr;
+ cc::PaintCanvas* canvas = resource_provider->Canvas();
cc::PaintFlags paint;
- resource_provider->Canvas()->drawImageRect(
- paint_image,
- SkRect::MakeXYWH(src_rect.X(), src_rect.Y(), src_rect.Width(),
- src_rect.Height()),
- SkRect::MakeWH(src_rect.Width(), src_rect.Height()), &paint,
- SkCanvas::kStrict_SrcRectConstraint);
+ paint.setBlendMode(SkBlendMode::kSrc);
+ canvas->drawImageRect(paint_image,
+ SkRect::MakeXYWH(src_rect.X(), src_rect.Y(),
+ src_rect.Width(), src_rect.Height()),
+ SkRect::MakeWH(src_rect.Width(), src_rect.Height()),
+ SkSamplingOptions(), &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
result = resource_provider->Snapshot(image->CurrentFrameOrientation());
}
@@ -563,10 +512,6 @@ static scoped_refptr<StaticBitmapImage> CropImageAndApplyColorSpaceConversion(
if (!result)
return nullptr;
- // convert pixel format if needed
- result =
- GetImageWithPixelFormat(std::move(result), parsed_options.pixel_format);
-
// resize if up-scaling
if (up_scaling) {
result = ScaleImage(std::move(result), parsed_options);
@@ -666,17 +611,15 @@ ImageBitmap::ImageBitmap(HTMLVideoElement* video,
if (DstBufferSizeHasOverflow(parsed_options))
return;
- std::unique_ptr<CanvasResourceProvider> resource_provider =
- CreateProviderForVideoElement(video, options);
-
- if (!resource_provider)
+ // TODO(crbug.com/1181329): ImageBitmap resize test case failed when
+ // quality equals to "low" and "medium". Need further investigate to
+ // enable gpu backed imageBitmap with resize options.
+ const bool allow_accelerated_images =
+ !options->hasResizeWidth() && !options->hasResizeHeight();
+ auto input = video->CreateStaticBitmapImage(allow_accelerated_images);
+ if (!input)
return;
- video->PaintCurrentFrame(
- resource_provider->Canvas(),
- IntRect(IntPoint(), IntSize(video->videoWidth(), video->videoHeight())),
- nullptr);
- scoped_refptr<StaticBitmapImage> input = resource_provider->Snapshot();
image_ =
CropImageAndApplyColorSpaceConversion(std::move(input), parsed_options);
if (!image_)
@@ -739,18 +682,8 @@ ImageBitmap::ImageBitmap(OffscreenCanvas* offscreen_canvas,
UpdateImageBitmapMemoryUsage();
}
-ImageBitmap::ImageBitmap(const void* pixel_data,
- uint32_t width,
- uint32_t height,
- bool is_image_bitmap_premultiplied,
- bool is_image_bitmap_origin_clean,
- const CanvasColorParams& color_params) {
- SkImageInfo info =
- SkImageInfo::Make(width, height, color_params.GetSkColorType(),
- is_image_bitmap_premultiplied ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType,
- color_params.GetSkColorSpace());
- SkPixmap pixmap(info, pixel_data, info.bytesPerPixel() * width);
+ImageBitmap::ImageBitmap(const SkPixmap& pixmap,
+ bool is_image_bitmap_origin_clean) {
sk_sp<SkImage> raster_copy = SkImage::MakeRasterCopy(pixmap);
if (!raster_copy)
return;
@@ -784,32 +717,24 @@ ImageBitmap::ImageBitmap(ImageData* data,
}
// Copy / color convert the pixels
- size_t image_pixels_size;
- if (!base::CheckMul(parsed_options.color_params.BytesPerPixel(),
- static_cast<unsigned>(src_rect.Width()),
- static_cast<unsigned>(src_rect.Height()))
- .AssignIfValid(&image_pixels_size)) {
+ SkImageInfo info = SkImageInfo::Make(
+ src_rect.Width(), src_rect.Height(), kN32_SkColorType,
+ parsed_options.premultiply_alpha ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType,
+ SkColorSpace::MakeSRGB());
+ size_t image_pixels_size = info.computeMinByteSize();
+ if (SkImageInfo::ByteSizeOverflowed(image_pixels_size))
return;
- }
sk_sp<SkData> image_pixels = TryAllocateSkData(image_pixels_size);
if (!image_pixels)
return;
- if (!data->ImageDataInCanvasColorSettings(
- parsed_options.color_params.ColorSpace(),
- parsed_options.color_params.PixelFormat(),
- static_cast<unsigned char*>(image_pixels->writable_data()),
- kN32ColorType, &src_rect,
- parsed_options.premultiply_alpha ? kPremultiplyAlpha
- : kUnpremultiplyAlpha))
+ if (!data->GetSkPixmap().readPixels(info, image_pixels->writable_data(),
+ info.minRowBytes(), src_rect.X(),
+ src_rect.Y())) {
return;
+ }
// Create Image object
- SkImageInfo info = SkImageInfo::Make(
- src_rect.Width(), src_rect.Height(),
- parsed_options.color_params.GetSkColorType(),
- parsed_options.premultiply_alpha ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType,
- parsed_options.color_params.GetSkColorSpace());
image_ = StaticBitmapImage::Create(std::move(image_pixels), info);
if (!image_)
return;
@@ -1030,7 +955,7 @@ ScriptPromise ImageBitmap::CreateAsync(ImageElementBase* image,
SVGImageForContainer::Create(To<SVGImage>(input.get()),
FloatSize(input_rect.Size()), 1, NullURL())
->Draw(canvas, cc::PaintFlags(), FloatRect(draw_dst_rect),
- FloatRect(draw_src_rect),
+ FloatRect(draw_src_rect), SkSamplingOptions(),
// The following will all be ignored.
kRespectImageOrientation, Image::kDoNotClampImageToSourceRect,
Image::kSyncDecode);
@@ -1039,14 +964,13 @@ ScriptPromise ImageBitmap::CreateAsync(ImageElementBase* image,
std::unique_ptr<ParsedOptions> passed_parsed_options =
std::make_unique<ParsedOptions>(parsed_options);
worker_pool::PostTask(
- FROM_HERE,
- CrossThreadBindOnce(
- &RasterizeImageOnBackgroundThread, std::move(paint_record),
- draw_dst_rect, Thread::MainThread()->GetTaskRunner(),
- CrossThreadBindOnce(&ResolvePromiseOnOriginalThread,
- WrapCrossThreadPersistent(resolver),
- !image->WouldTaintOrigin(),
- WTF::Passed(std::move(passed_parsed_options)))));
+ FROM_HERE, CrossThreadBindOnce(
+ &RasterizeImageOnBackgroundThread, std::move(paint_record),
+ draw_dst_rect, Thread::MainThread()->GetTaskRunner(),
+ CrossThreadBindOnce(&ResolvePromiseOnOriginalThread,
+ WrapCrossThreadPersistent(resolver),
+ !image->WouldTaintOrigin(),
+ std::move(passed_parsed_options))));
return promise;
}
@@ -1064,28 +988,13 @@ ImageBitmap* ImageBitmap::Take(ScriptPromiseResolver*, sk_sp<SkImage> image) {
UnacceleratedStaticBitmapImage::Create(std::move(image)));
}
-CanvasColorParams ImageBitmap::GetCanvasColorParams() {
- return CanvasColorParams(GetSkImageInfo(image_));
-}
-
-Vector<uint8_t> ImageBitmap::CopyBitmapData(AlphaDisposition alpha_op,
- DataU8ColorType u8_color_type) {
- DCHECK(alpha_op != kDontChangeAlpha);
- SkImageInfo info = GetSkImageInfo(image_);
- auto color_type = info.colorType();
- if (color_type == kN32_SkColorType && u8_color_type == kRGBAColorType)
- color_type = kRGBA_8888_SkColorType;
- // Note that width() and height() here apply EXIF orientation
- info =
- SkImageInfo::Make(width(), height(), color_type,
- (alpha_op == kPremultiplyAlpha) ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType,
- info.refColorSpace());
- return CopyImageData(image_, info, true);
+SkImageInfo ImageBitmap::GetBitmapSkImageInfo() const {
+ return GetSkImageInfo(image_);
}
-Vector<uint8_t> ImageBitmap::CopyBitmapData() {
- return CopyImageData(image_);
+Vector<uint8_t> ImageBitmap::CopyBitmapData(const SkImageInfo& info,
+ bool apply_orientation) {
+ return CopyImageData(image_, info, apply_orientation);
}
unsigned ImageBitmap::width() const {
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
index ebe1676d8a2..f17313e911b 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
@@ -30,11 +30,6 @@ class ImageElementBase;
class ImageDecoder;
class OffscreenCanvas;
-enum ImageBitmapPixelFormat {
- kImageBitmapPixelFormat_Default,
- kImageBitmapPixelFormat_Uint8,
-};
-
class CORE_EXPORT ImageBitmap final : public ScriptWrappable,
public CanvasImageSource,
public ImageBitmapSource {
@@ -72,25 +67,23 @@ class CORE_EXPORT ImageBitmap final : public ScriptWrappable,
base::Optional<IntRect>,
const ImageBitmapOptions* = ImageBitmapOptions::Create());
// This constructor may called by structured-cloning an ImageBitmap.
- // isImageBitmapPremultiplied indicates whether the original ImageBitmap is
- // premultiplied or not.
// isImageBitmapOriginClean indicates whether the original ImageBitmap is
// origin clean or not.
- ImageBitmap(const void* pixel_data,
- uint32_t width,
- uint32_t height,
- bool is_image_bitmap_premultiplied,
- bool is_image_bitmap_origin_clean,
- const CanvasColorParams&);
+ ImageBitmap(const SkPixmap& pixmap, bool is_image_bitmap_origin_clean);
// Type and helper function required by CallbackPromiseAdapter:
using WebType = sk_sp<SkImage>;
static ImageBitmap* Take(ScriptPromiseResolver*, sk_sp<SkImage>);
scoped_refptr<StaticBitmapImage> BitmapImage() const { return image_; }
- Vector<uint8_t> CopyBitmapData();
- Vector<uint8_t> CopyBitmapData(AlphaDisposition,
- DataU8ColorType = kRGBAColorType);
+
+ // Retrieve the SkImageInfo that best represents BitmapImage().
+ SkImageInfo GetBitmapSkImageInfo() const;
+
+ // When apply_orientation is true this method will orient the data according
+ // to the source's EXIF information.
+ Vector<uint8_t> CopyBitmapData(const SkImageInfo& info,
+ bool apply_orientation);
unsigned width() const;
unsigned height() const;
IntSize Size() const;
@@ -103,8 +96,6 @@ class CORE_EXPORT ImageBitmap final : public ScriptWrappable,
~ImageBitmap() override;
- CanvasColorParams GetCanvasColorParams();
-
// CanvasImageSource implementation
scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
const FloatSize&) override;
@@ -130,9 +121,7 @@ class CORE_EXPORT ImageBitmap final : public ScriptWrappable,
unsigned resize_width = 0;
unsigned resize_height = 0;
IntRect crop_rect;
- ImageBitmapPixelFormat pixel_format = kImageBitmapPixelFormat_Default;
SkFilterQuality resize_quality = kLow_SkFilterQuality;
- CanvasColorParams color_params;
};
private:
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
deleted file mode 100644
index 7a711a5a5df..00000000000
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/location.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_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/fileapi/blob.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
-#include "third_party/blink/renderer/core/html/canvas/image_data.h"
-#include "third_party/blink/renderer/core/html/html_image_element.h"
-#include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
-#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
-#include "third_party/blink/renderer/core/svg/svg_image_element.h"
-#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-namespace {
-// This enum is used in a UMA histogram.
-enum CreateImageBitmapSource {
- kCreateImageBitmapSourceBlob = 0,
- kCreateImageBitmapSourceImageBitmap = 1,
- kCreateImageBitmapSourceImageData = 2,
- kCreateImageBitmapSourceHTMLCanvasElement = 3,
- kCreateImageBitmapSourceHTMLImageElement = 4,
- kCreateImageBitmapSourceHTMLVideoElement = 5,
- kCreateImageBitmapSourceOffscreenCanvas = 6,
- kCreateImageBitmapSourceSVGImageElement = 7,
- kMaxValue = kCreateImageBitmapSourceSVGImageElement,
-};
-
-} // namespace
-
-static inline ImageBitmapSource* ToImageBitmapSourceInternal(
- const ImageBitmapSourceUnion& value,
- const ImageBitmapOptions* options,
- bool has_crop_rect) {
- if (value.IsHTMLVideoElement()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceHTMLVideoElement);
- return value.GetAsHTMLVideoElement();
- }
- if (value.IsHTMLImageElement()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceHTMLImageElement);
- return value.GetAsHTMLImageElement();
- }
- if (value.IsSVGImageElement()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceSVGImageElement);
- return value.GetAsSVGImageElement();
- }
- if (value.IsHTMLCanvasElement()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceHTMLCanvasElement);
- return value.GetAsHTMLCanvasElement();
- }
- if (value.IsBlob()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceBlob);
- return value.GetAsBlob();
- }
- if (value.IsImageData()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceImageData);
- return value.GetAsImageData();
- }
- if (value.IsImageBitmap()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceImageBitmap);
- return value.GetAsImageBitmap();
- }
- if (value.IsOffscreenCanvas()) {
- UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
- kCreateImageBitmapSourceOffscreenCanvas);
- return value.GetAsOffscreenCanvas();
- }
- NOTREACHED();
- return nullptr;
-}
-
-ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob(
- ScriptState* script_state,
- ImageBitmapSource* bitmap_source,
- base::Optional<IntRect> crop_rect,
- const ImageBitmapOptions* options) {
- DCHECK(script_state->ContextIsValid());
- ImageBitmapFactories& factory = From(*ExecutionContext::From(script_state));
- ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::Create(
- factory, crop_rect, options, script_state);
- factory.AddLoader(loader);
- loader->LoadBlobAsync(static_cast<Blob*>(bitmap_source));
- return loader->Promise();
-}
-
-ScriptPromise ImageBitmapFactories::CreateImageBitmap(
- ScriptState* script_state,
- const ImageBitmapSourceUnion& bitmap_source,
- const ImageBitmapOptions* options,
- ExceptionState& exception_state) {
- WebFeature feature = WebFeature::kCreateImageBitmap;
- UseCounter::Count(ExecutionContext::From(script_state), feature);
- ImageBitmapSource* bitmap_source_internal =
- ToImageBitmapSourceInternal(bitmap_source, options, false);
- if (!bitmap_source_internal)
- return ScriptPromise();
- return CreateImageBitmap(script_state, bitmap_source_internal,
- base::Optional<IntRect>(), options, exception_state);
-}
-
-ScriptPromise ImageBitmapFactories::CreateImageBitmap(
- ScriptState* script_state,
- const ImageBitmapSourceUnion& bitmap_source,
- int sx,
- int sy,
- int sw,
- int sh,
- const ImageBitmapOptions* options,
- ExceptionState& exception_state) {
- WebFeature feature = WebFeature::kCreateImageBitmap;
- UseCounter::Count(ExecutionContext::From(script_state), feature);
- ImageBitmapSource* bitmap_source_internal =
- ToImageBitmapSourceInternal(bitmap_source, options, true);
- if (!bitmap_source_internal)
- return ScriptPromise();
- base::Optional<IntRect> crop_rect = IntRect(sx, sy, sw, sh);
- return CreateImageBitmap(script_state, bitmap_source_internal, crop_rect,
- options, exception_state);
-}
-
-ScriptPromise ImageBitmapFactories::CreateImageBitmap(
- ScriptState* script_state,
- ImageBitmapSource* bitmap_source,
- base::Optional<IntRect> crop_rect,
- const ImageBitmapOptions* options,
- ExceptionState& exception_state) {
- if (crop_rect && (crop_rect->Width() == 0 || crop_rect->Height() == 0)) {
- exception_state.ThrowRangeError(String::Format(
- "The crop rect %s is 0.", crop_rect->Width() ? "height" : "width"));
- return ScriptPromise();
- }
-
- if (bitmap_source->IsBlob()) {
- return CreateImageBitmapFromBlob(script_state, bitmap_source, crop_rect,
- options);
- }
-
- if (bitmap_source->BitmapSourceSize().Width() == 0 ||
- bitmap_source->BitmapSourceSize().Height() == 0) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- String::Format(
- "The source image %s is 0.",
- bitmap_source->BitmapSourceSize().Width() ? "height" : "width"));
- return ScriptPromise();
- }
-
- return bitmap_source->CreateImageBitmap(script_state, crop_rect, options,
- exception_state);
-}
-
-const char ImageBitmapFactories::kSupplementName[] = "ImageBitmapFactories";
-
-ImageBitmapFactories& ImageBitmapFactories::From(ExecutionContext& context) {
- ImageBitmapFactories* supplement =
- Supplement<ExecutionContext>::From<ImageBitmapFactories>(context);
- if (!supplement) {
- supplement = MakeGarbageCollected<ImageBitmapFactories>();
- Supplement<ExecutionContext>::ProvideTo(context, supplement);
- }
- return *supplement;
-}
-
-void ImageBitmapFactories::AddLoader(ImageBitmapLoader* loader) {
- pending_loaders_.insert(loader);
-}
-
-void ImageBitmapFactories::DidFinishLoading(ImageBitmapLoader* loader) {
- DCHECK(pending_loaders_.Contains(loader));
- pending_loaders_.erase(loader);
-}
-
-void ImageBitmapFactories::Trace(Visitor* visitor) const {
- visitor->Trace(pending_loaders_);
- Supplement<ExecutionContext>::Trace(visitor);
-}
-
-ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(
- ImageBitmapFactories& factory,
- base::Optional<IntRect> crop_rect,
- ScriptState* script_state,
- const ImageBitmapOptions* options)
- : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
- loader_(std::make_unique<FileReaderLoader>(
- FileReaderLoader::kReadAsArrayBuffer,
- this,
- GetExecutionContext()->GetTaskRunner(TaskType::kFileReading))),
- factory_(&factory),
- resolver_(MakeGarbageCollected<ScriptPromiseResolver>(script_state)),
- crop_rect_(crop_rect),
- options_(options) {}
-
-void ImageBitmapFactories::ImageBitmapLoader::LoadBlobAsync(Blob* blob) {
- loader_->Start(blob->GetBlobDataHandle());
-}
-
-ImageBitmapFactories::ImageBitmapLoader::~ImageBitmapLoader() {
- DCHECK(!loader_);
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::RejectPromise(
- ImageBitmapRejectionReason reason) {
- switch (reason) {
- case kUndecodableImageBitmapRejectionReason:
- resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The source image could not be decoded."));
- break;
- case kAllocationFailureImageBitmapRejectionReason:
- resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The ImageBitmap could not be allocated."));
- break;
- default:
- NOTREACHED();
- }
- loader_.reset();
- factory_->DidFinishLoading(this);
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::ContextDestroyed() {
- if (loader_)
- factory_->DidFinishLoading(this);
- loader_.reset();
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() {
- auto contents = loader_->TakeContents();
- loader_.reset();
- if (!contents.IsValid()) {
- RejectPromise(kAllocationFailureImageBitmapRejectionReason);
- return;
- }
- ScheduleAsyncImageBitmapDecoding(std::move(contents));
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) {
- RejectPromise(kUndecodableImageBitmapRejectionReason);
-}
-
-namespace {
-void DecodeImageOnDecoderThread(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- ArrayBufferContents contents,
- ImageDecoder::AlphaOption alpha_option,
- ColorBehavior color_behavior,
- WTF::CrossThreadOnceFunction<
- void(sk_sp<SkImage>, const ImageOrientationEnum)> result_callback) {
- const bool data_complete = true;
- std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
- SegmentReader::CreateFromSkData(
- SkData::MakeWithoutCopy(contents.Data(), contents.DataLength())),
- data_complete, alpha_option, ImageDecoder::kDefaultBitDepth,
- color_behavior);
- sk_sp<SkImage> frame;
- ImageOrientationEnum orientation = ImageOrientationEnum::kDefault;
- if (decoder) {
- orientation = decoder->Orientation().Orientation();
- frame = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
- }
- PostCrossThreadTask(*task_runner, FROM_HERE,
- CrossThreadBindOnce(std::move(result_callback),
- std::move(frame), orientation));
-}
-} // namespace
-
-void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding(
- ArrayBufferContents contents) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- Thread::Current()->GetTaskRunner();
- ImageDecoder::AlphaOption alpha_option =
- options_->premultiplyAlpha() != "none"
- ? ImageDecoder::AlphaOption::kAlphaPremultiplied
- : ImageDecoder::AlphaOption::kAlphaNotPremultiplied;
- ColorBehavior color_behavior = options_->colorSpaceConversion() == "none"
- ? ColorBehavior::Ignore()
- : ColorBehavior::Tag();
- worker_pool::PostTask(
- FROM_HERE,
- CrossThreadBindOnce(
- DecodeImageOnDecoderThread, std::move(task_runner),
- std::move(contents), alpha_option, color_behavior,
- CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader::
- ResolvePromiseOnOriginalThread,
- WrapCrossThreadWeakPersistent(this))));
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::ResolvePromiseOnOriginalThread(
- sk_sp<SkImage> frame,
- const ImageOrientationEnum orientation) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!frame) {
- RejectPromise(kUndecodableImageBitmapRejectionReason);
- return;
- }
- DCHECK(frame->width());
- DCHECK(frame->height());
- scoped_refptr<StaticBitmapImage> image =
- UnacceleratedStaticBitmapImage::Create(std::move(frame), orientation);
-
- image->SetOriginClean(true);
- auto* image_bitmap =
- MakeGarbageCollected<ImageBitmap>(image, crop_rect_, options_);
- if (image_bitmap && image_bitmap->BitmapImage()) {
- resolver_->Resolve(image_bitmap);
- } else {
- RejectPromise(kAllocationFailureImageBitmapRejectionReason);
- return;
- }
- factory_->DidFinishLoading(this);
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::Trace(Visitor* visitor) const {
- ExecutionContextLifecycleObserver::Trace(visitor);
- visitor->Trace(factory_);
- visitor->Trace(resolver_);
- visitor->Trace(options_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
deleted file mode 100644
index 1c056ee1388..00000000000
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
-
-#include <memory>
-
-#include "base/single_thread_task_runner.h"
-#include "third_party/blink/renderer/bindings/core/v8/image_bitmap_source.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
-#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
-#include "third_party/blink/renderer/core/frame/window_or_worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/name_client.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/geometry/int_rect.h"
-#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-
-class SkImage;
-
-namespace blink {
-
-class Blob;
-class ExecutionContext;
-class ImageBitmapSource;
-
-class CORE_EXPORT ImageBitmapFactories final
- : public GarbageCollected<ImageBitmapFactories>,
- public Supplement<ExecutionContext>,
- public NameClient {
- public:
- static const char kSupplementName[];
-
- static ScriptPromise CreateImageBitmap(ScriptState*,
- const ImageBitmapSourceUnion&,
- const ImageBitmapOptions*,
- ExceptionState&);
- static ScriptPromise CreateImageBitmap(ScriptState*,
- const ImageBitmapSourceUnion&,
- int sx,
- int sy,
- int sw,
- int sh,
- const ImageBitmapOptions*,
- ExceptionState&);
- static ScriptPromise CreateImageBitmap(ScriptState*,
- ImageBitmapSource*,
- base::Optional<IntRect> crop_rect,
- const ImageBitmapOptions*,
- ExceptionState&);
-
- virtual ~ImageBitmapFactories() = default;
-
- void Trace(Visitor*) const override;
- const char* NameInHeapSnapshot() const override {
- return "ImageBitmapLoader";
- }
-
- private:
- class ImageBitmapLoader final : public GarbageCollected<ImageBitmapLoader>,
- public ExecutionContextLifecycleObserver,
- public FileReaderLoaderClient {
- public:
- static ImageBitmapLoader* Create(ImageBitmapFactories& factory,
- base::Optional<IntRect> crop_rect,
- const ImageBitmapOptions* options,
- ScriptState* script_state) {
- return MakeGarbageCollected<ImageBitmapLoader>(factory, crop_rect,
- script_state, options);
- }
-
- ImageBitmapLoader(ImageBitmapFactories&,
- base::Optional<IntRect> crop_rect,
- ScriptState*,
- const ImageBitmapOptions*);
-
- void LoadBlobAsync(Blob*);
- ScriptPromise Promise() { return resolver_->Promise(); }
-
- void Trace(Visitor*) const override;
-
- ~ImageBitmapLoader() override;
-
- private:
- SEQUENCE_CHECKER(sequence_checker_);
-
- enum ImageBitmapRejectionReason {
- kUndecodableImageBitmapRejectionReason,
- kAllocationFailureImageBitmapRejectionReason,
- };
-
- void RejectPromise(ImageBitmapRejectionReason);
-
- void ScheduleAsyncImageBitmapDecoding(ArrayBufferContents);
- void ResolvePromiseOnOriginalThread(sk_sp<SkImage>,
- const ImageOrientationEnum);
-
- // ExecutionContextLifecycleObserver
- void ContextDestroyed() override;
-
- // FileReaderLoaderClient
- void DidStartLoading() override {}
- void DidReceiveData() override {}
- void DidFinishLoading() override;
- void DidFail(FileErrorCode) override;
-
- std::unique_ptr<FileReaderLoader> loader_;
- Member<ImageBitmapFactories> factory_;
- Member<ScriptPromiseResolver> resolver_;
- base::Optional<IntRect> crop_rect_;
- Member<const ImageBitmapOptions> options_;
- };
-
- static ImageBitmapFactories& From(ExecutionContext&);
- static ScriptPromise CreateImageBitmapFromBlob(
- ScriptState*,
- ImageBitmapSource*,
- base::Optional<IntRect> crop_rect,
- const ImageBitmapOptions*);
-
- void AddLoader(ImageBitmapLoader*);
- void DidFinishLoading(ImageBitmapLoader*);
-
- HeapHashSet<Member<ImageBitmapLoader>> pending_loaders_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_options.idl b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_options.idl
index e88342cb8e2..1e8f776467b 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_options.idl
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_options.idl
@@ -5,13 +5,11 @@
// https://html.spec.whatwg.org/C/#imagebitmapoptions
enum ImageOrientation { "none", "flipY" };
-enum ImageBitmapPixelFormat { "default", "uint8" };
enum PremultiplyAlpha { "none", "premultiply", "default" };
enum ColorSpaceConversion { "none", "default" };
enum ResizeQuality { "pixelated", "low", "medium", "high" };
dictionary ImageBitmapOptions {
ImageOrientation imageOrientation = "none";
- [RuntimeEnabled=CanvasColorManagement] ImageBitmapPixelFormat imagePixelFormat = "default";
PremultiplyAlpha premultiplyAlpha = "default";
ColorSpaceConversion colorSpaceConversion = "default";
[EnforceRange] unsigned long resizeWidth;
diff --git a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index c8a7697a43d..0853b9f9ea0 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -253,9 +253,9 @@ static void TestImageBitmapTextureBacked(
TEST_F(ImageBitmapTest, AvoidGPUReadback) {
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper =
SharedGpuContext::ContextProviderWrapper();
- CanvasColorParams color_params;
+ CanvasResourceParams resource_params;
auto resource_provider = CanvasResourceProvider::CreateSharedImageProvider(
- IntSize(100, 100), kLow_SkFilterQuality, color_params,
+ IntSize(100, 100), kLow_SkFilterQuality, resource_params,
CanvasResourceProvider::ShouldInitialize::kNo, context_provider_wrapper,
RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
diff --git a/chromium/third_party/blink/renderer/core/input/boundary_event_dispatcher.cc b/chromium/third_party/blink/renderer/core/input/boundary_event_dispatcher.cc
index 5f349b19d55..905a0509e22 100644
--- a/chromium/third_party/blink/renderer/core/input/boundary_event_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/core/input/boundary_event_dispatcher.cc
@@ -18,7 +18,6 @@ void BuildAncestorChain(EventTarget* target,
return;
Node* target_node = target->ToNode();
DCHECK(target_node);
- target_node->UpdateDistributionForFlatTreeTraversal();
// Index 0 element in the ancestors arrays will be the corresponding
// target. So the root of their document will be their last element.
for (Node* node = target_node; node; node = FlatTreeTraversal::Parent(*node))
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler.cc b/chromium/third_party/blink/renderer/core/input/event_handler.cc
index 92990159fea..3a5eb0ef45f 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler.cc
+++ b/chromium/third_party/blink/renderer/core/input/event_handler.cc
@@ -116,6 +116,7 @@
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-blink.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
namespace blink {
@@ -250,6 +251,8 @@ EventHandler::EventHandler(LocalFrame& frame)
void EventHandler::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(selection_controller_);
+ visitor->Trace(hover_timer_);
+ visitor->Trace(cursor_update_timer_);
visitor->Trace(capturing_mouse_events_element_);
visitor->Trace(capturing_subframe_element_);
visitor->Trace(last_mouse_move_event_subframe_);
@@ -263,6 +266,7 @@ void EventHandler::Trace(Visitor* visitor) const {
visitor->Trace(keyboard_event_manager_);
visitor->Trace(pointer_event_manager_);
visitor->Trace(gesture_manager_);
+ visitor->Trace(active_interval_timer_);
visitor->Trace(last_deferred_tap_element_);
}
@@ -299,8 +303,10 @@ void EventHandler::StartMiddleClickAutoscroll(LayoutObject* layout_object) {
AutoscrollController* controller = scroll_manager_->GetAutoscrollController();
if (!controller)
return;
+
LayoutBox* scrollable = LayoutBox::FindAutoscrollable(
layout_object, /*is_middle_click_autoscroll*/ true);
+
controller->StartMiddleClickAutoscroll(
layout_object->GetFrame(), scrollable,
LastKnownMousePositionInRootFrame(),
@@ -2304,8 +2310,9 @@ void EventHandler::DefaultKeyboardEventHandler(KeyboardEvent* event) {
event, mouse_event_manager_->MousePressNode());
}
-void EventHandler::DragSourceEndedAt(const WebMouseEvent& event,
- DragOperation operation) {
+void EventHandler::DragSourceEndedAt(
+ const WebMouseEvent& event,
+ ui::mojom::blink::DragOperation operation) {
// Asides from routing the event to the correct frame, the hit test is also an
// opportunity for Layer to update the :hover and :active pseudoclasses.
HitTestRequest request(HitTestRequest::kRelease |
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler.h b/chromium/third_party/blink/renderer/core/input/event_handler.h
index cc38da94528..4a3787334ba 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler.h
+++ b/chromium/third_party/blink/renderer/core/input/event_handler.h
@@ -30,7 +30,6 @@
#include "base/optional.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_menu_source_type.h"
-#include "third_party/blink/public/common/page/drag_operation.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -53,6 +52,7 @@
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h"
namespace blink {
@@ -238,7 +238,7 @@ class CORE_EXPORT EventHandler final : public GarbageCollected<EventHandler> {
TextEventInputType = kTextEventInputKeyboard);
void DefaultTextInputEventHandler(TextEvent*);
- void DragSourceEndedAt(const WebMouseEvent&, DragOperation);
+ void DragSourceEndedAt(const WebMouseEvent&, ui::mojom::blink::DragOperation);
void CapsLockStateMayHaveChanged(); // Only called by FrameSelection
@@ -380,12 +380,12 @@ class CORE_EXPORT EventHandler final : public GarbageCollected<EventHandler> {
const Member<SelectionController> selection_controller_;
// TODO(lanwei): Remove the below timers for updating hover and cursor.
- TaskRunnerTimer<EventHandler> hover_timer_;
+ HeapTaskRunnerTimer<EventHandler> hover_timer_;
// TODO(rbyers): Mouse cursor update is page-wide, not per-frame. Page-wide
// state should move out of EventHandler to a new PageEventHandler class.
// crbug.com/449649
- TaskRunnerTimer<EventHandler> cursor_update_timer_;
+ HeapTaskRunnerTimer<EventHandler> cursor_update_timer_;
Member<Element> capturing_mouse_events_element_;
// |capturing_subframe_element_| has similar functionality as
@@ -416,7 +416,7 @@ class CORE_EXPORT EventHandler final : public GarbageCollected<EventHandler> {
double max_mouse_moved_duration_;
- TaskRunnerTimer<EventHandler> active_interval_timer_;
+ HeapTaskRunnerTimer<EventHandler> active_interval_timer_;
// last_show_press_timestamp_ prevents the active state rewrited by
// following events too soon (less than 0.15s). It is ok we only record
diff --git a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
index 1d0175cb1ac..7c3c4c001b3 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -29,7 +29,7 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
@@ -52,6 +52,7 @@
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-blink.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
@@ -1006,7 +1007,7 @@ TEST_F(EventHandlerTest, dragEndInNewDrag) {
WebInputEvent::kNoModifiers, base::TimeTicks::Now());
mouse_up_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().DragSourceEndedAt(
- mouse_up_event, kDragOperationNone);
+ mouse_up_event, ui::mojom::blink::DragOperation::kNone);
// This test passes if it doesn't crash.
}
@@ -1191,7 +1192,7 @@ TEST_F(EventHandlerSimTest, MouseUpOffScrollbarGeneratesScrollEnd) {
)HTML");
Compositor().BeginFrame();
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
// PageTestBase sizes the page to 800x600. Click on the scrollbar
// track, move off, then release the mouse and verify that GestureScrollEnd
@@ -1213,13 +1214,15 @@ TEST_F(EventHandlerSimTest, MouseUpOffScrollbarGeneratesScrollEnd) {
// Mouse down on the scrollbar track should have generated GSB/GSU.
if (scrollbar_theme_allows_hit_test) {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 2u);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents()[0]->Event().GetType(),
- WebInputEvent::Type::kGestureScrollBegin);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents()[1]->Event().GetType(),
- WebInputEvent::Type::kGestureScrollUpdate);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 2u);
+ EXPECT_EQ(
+ GetWebFrameWidget().GetInjectedScrollEvents()[0]->Event().GetType(),
+ WebInputEvent::Type::kGestureScrollBegin);
+ EXPECT_EQ(
+ GetWebFrameWidget().GetInjectedScrollEvents()[1]->Event().GetType(),
+ WebInputEvent::Type::kGestureScrollUpdate);
} else {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
}
const gfx::PointF middle_of_page(100, 100);
@@ -1233,9 +1236,9 @@ TEST_F(EventHandlerSimTest, MouseUpOffScrollbarGeneratesScrollEnd) {
// Mouse move should not have generated any gestures.
if (scrollbar_theme_allows_hit_test) {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 2u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 2u);
} else {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
}
WebMouseEvent mouse_up(WebInputEvent::Type::kMouseUp, middle_of_page,
@@ -1246,11 +1249,12 @@ TEST_F(EventHandlerSimTest, MouseUpOffScrollbarGeneratesScrollEnd) {
// Mouse up must generate GestureScrollEnd.
if (scrollbar_theme_allows_hit_test) {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 3u);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents()[2]->Event().GetType(),
- WebInputEvent::Type::kGestureScrollEnd);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 3u);
+ EXPECT_EQ(
+ GetWebFrameWidget().GetInjectedScrollEvents()[2]->Event().GetType(),
+ WebInputEvent::Type::kGestureScrollEnd);
} else {
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
}
}
@@ -1266,7 +1270,7 @@ TEST_F(EventHandlerSimTest, MouseUpOnlyOnScrollbar) {
Compositor().BeginFrame();
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
// Mouse down on the page, the move the mouse to the scrollbar and release.
// Validate that we don't inject a ScrollEnd (since no ScrollBegin was
@@ -1281,7 +1285,7 @@ TEST_F(EventHandlerSimTest, MouseUpOnlyOnScrollbar) {
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(mouse_down);
// Mouse down on the page should not generate scroll gestures.
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
const gfx::PointF scrollbar_forward_track(795, 560);
WebMouseEvent mouse_move(WebInputEvent::Type::kMouseMove,
@@ -1293,7 +1297,7 @@ TEST_F(EventHandlerSimTest, MouseUpOnlyOnScrollbar) {
mouse_move, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
// Mouse move should not have generated any gestures.
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
WebMouseEvent mouse_up(WebInputEvent::Type::kMouseUp, scrollbar_forward_track,
scrollbar_forward_track,
@@ -1303,7 +1307,7 @@ TEST_F(EventHandlerSimTest, MouseUpOnlyOnScrollbar) {
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(mouse_up);
// Mouse up should not have generated any gestures.
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
}
TEST_F(EventHandlerSimTest, RightClickNoGestures) {
@@ -1318,7 +1322,7 @@ TEST_F(EventHandlerSimTest, RightClickNoGestures) {
Compositor().BeginFrame();
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
// PageTestBase sizes the page to 800x600. Right click on the scrollbar
// track, and release the mouse and verify that no gesture events are
@@ -1332,7 +1336,7 @@ TEST_F(EventHandlerSimTest, RightClickNoGestures) {
mouse_down.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(mouse_down);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
WebMouseEvent mouse_up(WebInputEvent::Type::kMouseUp, scrollbar_forward_track,
scrollbar_forward_track,
@@ -1341,7 +1345,7 @@ TEST_F(EventHandlerSimTest, RightClickNoGestures) {
mouse_up.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(mouse_up);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
}
// https://crbug.com/976557 tracks the fix for re-enabling this test on Mac.
@@ -1391,7 +1395,7 @@ TEST_F(EventHandlerSimTest, MAYBE_GestureTapWithScrollSnaps) {
Compositor().BeginFrame();
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 0u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 0u);
// Only run this test if scrollbars are hit-testable (they are not on
// Android).
@@ -1408,10 +1412,10 @@ TEST_F(EventHandlerSimTest, MAYBE_GestureTapWithScrollSnaps) {
TapEventBuilder tap(scrollbar_forward_track, 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(tap);
- EXPECT_EQ(WebWidgetClient().GetInjectedScrollEvents().size(), 3u);
+ EXPECT_EQ(GetWebFrameWidget().GetInjectedScrollEvents().size(), 3u);
const Vector<std::unique_ptr<blink::WebCoalescedInputEvent>>& data =
- WebWidgetClient().GetInjectedScrollEvents();
+ GetWebFrameWidget().GetInjectedScrollEvents();
EXPECT_EQ(data[0]->Event().GetType(),
WebInputEvent::Type::kGestureScrollBegin);
EXPECT_EQ(data[1]->Event().GetType(),
diff --git a/chromium/third_party/blink/renderer/core/input/event_handling_util.h b/chromium/third_party/blink/renderer/core/input/event_handling_util.h
index d4fc1774319..f8d4cbb955a 100644
--- a/chromium/third_party/blink/renderer/core/input/event_handling_util.h
+++ b/chromium/third_party/blink/renderer/core/input/event_handling_util.h
@@ -41,8 +41,8 @@ bool IsInDocument(EventTarget*);
ContainerNode* ParentForClickEvent(const Node&);
ContainerNode* ParentForClickEventInteractiveElementSensitive(const Node&);
-PhysicalOffset ContentPointFromRootFrame(LocalFrame*,
- const FloatPoint& point_in_root_frame);
+CORE_EXPORT PhysicalOffset
+ContentPointFromRootFrame(LocalFrame*, const FloatPoint& point_in_root_frame);
MouseEventWithHitTestResults PerformMouseEventHitTest(LocalFrame*,
const HitTestRequest&,
diff --git a/chromium/third_party/blink/renderer/core/input/gesture_manager.cc b/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
index 1b411703806..82f81db669f 100644
--- a/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -298,13 +298,6 @@ WebInputEventResult GestureManager::HandleGestureTap(
WebInputEventResult click_event_result = WebInputEventResult::kNotHandled;
if (tapped_element) {
if (current_hit_test.InnerNode()) {
- // Updates distribution because a mouseup (or mousedown) event listener
- // can make the tree dirty at dispatchMouseEvent() invocation above.
- // Unless distribution is updated, commonAncestor would hit DCHECK. Both
- // tappedNonTextNode and currentHitTest.innerNode()) don't need to be
- // updated because commonAncestor() will exit early if their documents are
- // different.
- tapped_element->UpdateDistributionForFlatTreeTraversal();
Node* click_target_node = current_hit_test.InnerNode()->CommonAncestor(
*tapped_element, event_handling_util::ParentForClickEvent);
auto* click_target_element = DynamicTo<Element>(click_target_node);
diff --git a/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc b/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
index 5e2b15810f6..2978aac3cfd 100644
--- a/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/ime_on_focus_test.cc
@@ -22,27 +22,6 @@ using blink::url_test_helpers::RegisterMockedURLLoadFromBase;
namespace blink {
-class ImeRequestTrackingWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
- public:
- ImeRequestTrackingWebWidgetClient() : virtual_keyboard_request_count_(0) {}
-
- // WebWidgetClient methods
- void TextInputStateChanged(
- ui::mojom::blink::TextInputStatePtr state) override {
- if (state->show_ime_if_needed)
- ++virtual_keyboard_request_count_;
- }
-
- // Local methds
- void Reset() { virtual_keyboard_request_count_ = 0; }
-
- int VirtualKeyboardRequestCount() { return virtual_keyboard_request_count_; }
-
- private:
- int virtual_keyboard_request_count_;
-};
-
class ImeOnFocusTest : public testing::Test {
public:
ImeOnFocusTest() : base_url_("http://www.test.com/") {}
@@ -55,7 +34,7 @@ class ImeOnFocusTest : public testing::Test {
void SendGestureTap(WebViewImpl*, IntPoint);
void Focus(const AtomicString& element);
void RunImeOnFocusTest(String file_name,
- int,
+ size_t,
IntPoint tap_point = IntPoint(-1, -1),
const AtomicString& focus_element = g_null_atom,
String frame = "");
@@ -89,25 +68,24 @@ void ImeOnFocusTest::Focus(const AtomicString& element) {
void ImeOnFocusTest::RunImeOnFocusTest(
String file_name,
- int expected_virtual_keyboard_request_count,
+ size_t expected_virtual_keyboard_request_count,
IntPoint tap_point,
const AtomicString& focus_element,
String frame) {
- ImeRequestTrackingWebWidgetClient client;
RegisterMockedURLLoadFromBase(WebString(base_url_), test::CoreTestDataPath(),
WebString(file_name));
- WebViewImpl* web_view =
- web_view_helper_.Initialize(nullptr, nullptr, &client);
+ WebViewImpl* web_view = web_view_helper_.Initialize();
web_view->MainFrameViewWidget()->Resize(gfx::Size(800, 1200));
LoadFrame(web_view->MainFrameImpl(), base_url_.Utf8() + file_name.Utf8());
document_ = web_view_helper_.GetWebView()
->MainFrameImpl()
->GetDocument()
.Unwrap<Document>();
-
+ frame_test_helpers::TestWebFrameWidgetHost& widget_host =
+ web_view_helper_.GetMainFrameWidget()->WidgetHost();
if (!focus_element.IsNull())
Focus(focus_element);
- EXPECT_EQ(0, client.VirtualKeyboardRequestCount());
+ EXPECT_EQ(0u, widget_host.VirtualKeyboardRequestCount());
if (tap_point.X() >= 0 && tap_point.Y() >= 0)
SendGestureTap(web_view, tap_point);
@@ -124,12 +102,12 @@ void ImeOnFocusTest::RunImeOnFocusTest(
Focus(focus_element);
RunPendingTasks();
if (expected_virtual_keyboard_request_count == 0) {
- EXPECT_EQ(0, client.VirtualKeyboardRequestCount());
+ EXPECT_EQ(0u, widget_host.VirtualKeyboardRequestCount());
} else {
// Some builds (Aura, android) request the virtual keyboard on
// gesture tap.
EXPECT_LE(expected_virtual_keyboard_request_count,
- client.VirtualKeyboardRequestCount());
+ widget_host.VirtualKeyboardRequestCount());
}
web_view_helper_.Reset();
diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
index 9776ad8aa09..e48d5ee78ff 100644
--- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -6,11 +6,13 @@
#include <memory>
+#include "base/i18n/uchar.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/editor.h"
@@ -162,14 +164,14 @@ bool KeyboardEventManager::HandleAccessKey(const WebKeyboardEvent& evt) {
if ((evt.GetModifiers() & (WebKeyboardEvent::kKeyModifiers &
~WebInputEvent::kShiftKey)) != kAccessKeyModifiers)
return false;
- String key = String(evt.unmodified_text);
+ String key = String(base::i18n::ToUCharPtr(evt.unmodified_text));
Element* elem =
frame_->GetDocument()->GetElementByAccessKey(key.DeprecatedLower());
if (!elem)
return false;
elem->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
mojom::blink::FocusType::kAccessKey, nullptr));
- elem->AccessKeyAction(false);
+ elem->AccessKeyAction(SimulatedClickCreationScope::kFromUserAgent);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
index 5756c46b044..05a71a20c26 100644
--- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h
@@ -17,6 +17,7 @@ namespace blink {
class KeyboardEvent;
class LocalFrame;
+class Node;
class ScrollManager;
class WebKeyboardEvent;
diff --git a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
index ef2b67ac3e1..042bb65b4cd 100644
--- a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
namespace blink {
@@ -370,8 +371,6 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
const bool should_dispatch_click_event =
click_count_ > 0 && !context_menu_event && mouse_down_element_ &&
mouse_release_target &&
- mouse_release_target->CanParticipateInFlatTree() &&
- mouse_down_element_->CanParticipateInFlatTree() &&
mouse_down_element_->isConnected();
if (!should_dispatch_click_event)
return WebInputEventResult::kNotHandled;
@@ -383,11 +382,6 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
old_click_target_node = click_target_node;
} else if (mouse_down_element_->GetDocument() ==
mouse_release_target->GetDocument()) {
- // Updates distribution because a 'mouseup' event listener can make the
- // tree dirty at dispatchMouseEvent() invocation above.
- // Unless distribution is updated, commonAncestor would hit ASSERT.
- mouse_down_element_->UpdateDistributionForFlatTreeTraversal();
- mouse_release_target->UpdateDistributionForFlatTreeTraversal();
click_target_node = mouse_release_target->CommonAncestor(
*mouse_down_element_, event_handling_util::ParentForClickEvent);
@@ -403,8 +397,7 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
click_target_node != old_click_target_node);
const bool click_element_still_in_flat_tree =
- (click_element_ && click_element_->CanParticipateInFlatTree() &&
- click_element_->isConnected());
+ (click_element_ && click_element_->isConnected());
UMA_HISTOGRAM_BOOLEAN("Event.ClickNotFiredDueToDomManipulation",
!click_element_still_in_flat_tree);
DCHECK_EQ(click_element_ == mouse_down_element_,
@@ -718,6 +711,12 @@ WebInputEventResult MouseEventManager::HandleMousePressEvent(
if (single_click)
FocusDocumentView();
+ // |SelectionController| calls |PositionForPoint()| which requires
+ // |kPrePaintClean|. |FocusDocumentView| above is the last possible
+ // modifications before we call |SelectionController|.
+ if (LocalFrameView* frame_view = frame_->View())
+ frame_view->UpdateLifecycleToPrePaintClean(DocumentUpdateReason::kInput);
+
Node* inner_node = event.InnerNode();
mouse_press_node_ = inner_node;
@@ -858,6 +857,11 @@ WebInputEventResult MouseEventManager::HandleMouseDraggedEvent(
return WebInputEventResult::kNotHandled;
}
+ // |SelectionController| calls |PositionForPoint()| which requires
+ // |kPrePaintClean|.
+ if (LocalFrameView* frame_view = frame_->View())
+ frame_view->UpdateLifecycleToPrePaintClean(DocumentUpdateReason::kInput);
+
mouse_down_may_start_drag_ = false;
frame_->GetEventHandler().GetSelectionController().HandleMouseDraggedEvent(
@@ -1097,8 +1101,9 @@ void MouseEventManager::ClearDragDataTransfer() {
}
}
-void MouseEventManager::DragSourceEndedAt(const WebMouseEvent& event,
- DragOperation operation) {
+void MouseEventManager::DragSourceEndedAt(
+ const WebMouseEvent& event,
+ ui::mojom::blink::DragOperation operation) {
if (GetDragState().drag_src_) {
GetDragState().drag_data_transfer_->SetDestinationOperation(operation);
// The return value is ignored because dragend is not cancelable.
diff --git a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
index 4a7004ad6f1..9f75785af31 100644
--- a/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/mouse_event_manager.h
@@ -6,15 +6,14 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_MOUSE_EVENT_MANAGER_H_
#include "third_party/blink/public/common/input/web_mouse_event.h"
-#include "third_party/blink/public/common/page/drag_operation.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/synchronous_mutation_observer.h"
#include "third_party/blink/renderer/core/input/boundary_event_dispatcher.h"
-// #include "third_party/blink/renderer/core/page/drag_actions.h"
#include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h"
namespace blink {
@@ -109,7 +108,7 @@ class CORE_EXPORT MouseEventManager final
// drag heuristics.
void ClearDragHeuristicState();
- void DragSourceEndedAt(const WebMouseEvent&, DragOperation);
+ void DragSourceEndedAt(const WebMouseEvent&, ui::mojom::blink::DragOperation);
void UpdateSelectionForMouseDrag();
diff --git a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
index 228c54ce965..467743ef4fa 100644
--- a/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -565,19 +565,21 @@ WebInputEventResult PointerEventManager::HandlePointerEvent(
target = ComputePointerEventTarget(event).target_element;
}
+ PointerEvent* pointer_event =
+ pointer_event_factory_.Create(event, coalesced_events, predicted_events,
+ frame_->GetDocument()->domWindow());
+ // The conditional return below is deliberately placed after the Create()
+ // call above because of some side-effects of Create() (in particular
+ // SetLastPosition()) is needed even with the early return below. See
+ // crbug.com/1066544.
+ //
// Sometimes the Browser process tags events with kRelativeMotionEvent.
- // For e.g. during pointer lock, it recenters cursor by warping so that
- // cursor does not hit the screen boundary.
- // Those fake events should not be forwarded to the DOM.
- // The conditional return here is deliberately placed after the Create()
- // call above because of some side-effects of Create() is still needed
- // (in particular SetLastPosition(), see crbug.com/1066544)
+ // E.g. during pointer lock, it recenters cursor by warping so that cursor
+ // does not hit the screen boundary. Those fake events should not be
+ // forwarded to the DOM.
if (event.GetModifiers() & WebInputEvent::Modifiers::kRelativeMotionEvent)
return WebInputEventResult::kHandledSuppressed;
- PointerEvent* pointer_event =
- pointer_event_factory_.Create(event, coalesced_events, predicted_events,
- frame_->GetDocument()->domWindow());
if (pointer_event) {
// TODO(crbug.com/1141595): We should handle this case further upstream.
DispatchPointerEvent(target, pointer_event);
diff --git a/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc b/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
index 7532cb61043..fafa81c7277 100644
--- a/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/pointer_event_manager_test.cc
@@ -489,6 +489,66 @@ TEST_F(PointerEventManagerTest, PointerRawUpdateMovements) {
ASSERT_EQ(callback->last_movement_y_, 3);
}
+TEST_F(PointerEventManagerTest, PointerRawUpdateWithRelativeMotionEvent) {
+ ScopedConsolidatedMovementXYForTest scoped_feature(true);
+
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(
+ "<body style='padding:0px; width:400px; height:400px;'></body>");
+
+ PointerEventCoordinateListenerCallback* callback =
+ PointerEventCoordinateListenerCallback::Create();
+ GetDocument().body()->addEventListener(event_type_names::kPointerrawupdate,
+ callback);
+
+ // Initial movement_x/y are both 0.
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
+ CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate,
+ WebPointerProperties::PointerType::kMouse,
+ gfx::PointF(350, 350), gfx::PointF(350, 350), 10,
+ 10),
+ {}, {}, ui::LatencyInfo()));
+ ASSERT_EQ(callback->last_movement_x_, 0);
+ ASSERT_EQ(callback->last_movement_y_, 0);
+
+ // After moving the mouse by (+40,+20), movement_x/y have same deltas.
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
+ CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate,
+ WebPointerProperties::PointerType::kMouse,
+ gfx::PointF(390, 370), gfx::PointF(390, 370), 10,
+ 10),
+ {}, {}, ui::LatencyInfo()));
+ ASSERT_EQ(callback->last_movement_x_, 40);
+ ASSERT_EQ(callback->last_movement_y_, 20);
+
+ // A relative motion event to pull the mouse pointer back towards the center
+ // is not exposed to JS, so the event handler is not called and the cached
+ // coordinates remain unchanged.
+ std::unique_ptr<WebInputEvent> synthetic_event = CreateTestPointerEvent(
+ WebInputEvent::Type::kPointerRawUpdate,
+ WebPointerProperties::PointerType::kMouse, gfx::PointF(200, 200),
+ gfx::PointF(200, 200), 10, 10);
+ synthetic_event->SetModifiers(WebInputEvent::Modifiers::kRelativeMotionEvent);
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
+ std::move(synthetic_event), {}, {}, ui::LatencyInfo()));
+ ASSERT_EQ(callback->last_movement_x_, 40);
+ ASSERT_EQ(callback->last_movement_y_, 20);
+
+ // After moving the mouse by (+15,-10) from the last unexposed event,
+ // movement_x/y have deltas from the last event, not the deltas from the last
+ // exposed event.
+ WebView().MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(
+ CreateTestPointerEvent(WebInputEvent::Type::kPointerRawUpdate,
+ WebPointerProperties::PointerType::kMouse,
+ gfx::PointF(215, 190), gfx::PointF(215, 190), 10,
+ 10),
+ {}, {}, ui::LatencyInfo()));
+ ASSERT_EQ(callback->last_movement_x_, 15);
+ ASSERT_EQ(callback->last_movement_y_, -10);
+}
+
TEST_F(PointerEventManagerTest, PointerUnadjustedMovement) {
WebView().MainFrameViewWidget()->Resize(gfx::Size(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
diff --git a/chromium/third_party/blink/renderer/core/input/scroll_manager.cc b/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
index 9e97ed5bfe4..5d6c7704925 100644
--- a/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/chromium/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -33,8 +33,8 @@
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
#include "third_party/blink/renderer/core/scroll/scroll_customization.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/widget/input/input_metrics.h"
namespace blink {
namespace {
@@ -133,8 +133,20 @@ AutoscrollController* ScrollManager::GetAutoscrollController() const {
return nullptr;
}
-static bool CanPropagate(const ScrollState& scroll_state, const Node& node) {
- ScrollableArea* scrollable_area = node.GetLayoutBox()->GetScrollableArea();
+ScrollPropagationDirection ScrollManager::ComputePropagationDirection(
+ const ScrollState& scroll_state) {
+ if (scroll_state.deltaXHint() == 0 && scroll_state.deltaYHint() != 0)
+ return ScrollPropagationDirection::kVertical;
+ if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() == 0)
+ return ScrollPropagationDirection::kHorizontal;
+ if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() != 0)
+ return ScrollPropagationDirection::kBoth;
+ return ScrollPropagationDirection::kNone;
+}
+
+bool ScrollManager::CanPropagate(const LayoutBox* layout_box,
+ ScrollPropagationDirection direction) {
+ ScrollableArea* scrollable_area = layout_box->GetScrollableArea();
if (!scrollable_area)
return true;
@@ -142,54 +154,106 @@ static bool CanPropagate(const ScrollState& scroll_state, const Node& node) {
!scrollable_area->UserInputScrollable(kVerticalScrollbar))
return true;
- return (scroll_state.deltaXHint() == 0 ||
- node.GetComputedStyle()->OverscrollBehaviorX() ==
- EOverscrollBehavior::kAuto) &&
- (scroll_state.deltaYHint() == 0 ||
- node.GetComputedStyle()->OverscrollBehaviorY() ==
- EOverscrollBehavior::kAuto);
+ switch (direction) {
+ case ScrollPropagationDirection::kBoth:
+ return ((layout_box->StyleRef().OverscrollBehaviorX() ==
+ EOverscrollBehavior::kAuto) &&
+ (layout_box->StyleRef().OverscrollBehaviorY() ==
+ EOverscrollBehavior::kAuto));
+ case ScrollPropagationDirection::kVertical:
+ return layout_box->StyleRef().OverscrollBehaviorY() ==
+ EOverscrollBehavior::kAuto;
+ case ScrollPropagationDirection::kHorizontal:
+ return layout_box->StyleRef().OverscrollBehaviorX() ==
+ EOverscrollBehavior::kAuto;
+ case ScrollPropagationDirection::kNone:
+ return true;
+ default:
+ NOTREACHED();
+ }
}
void ScrollManager::RecomputeScrollChain(const Node& start_node,
const ScrollState& scroll_state,
- Deque<DOMNodeId>& scroll_chain) {
+ Deque<DOMNodeId>& scroll_chain,
+ bool is_autoscroll) {
DCHECK(scroll_chain.IsEmpty());
scroll_chain.clear();
DCHECK(start_node.GetLayoutObject());
- LayoutBox* cur_box = start_node.GetLayoutObject()->EnclosingBox();
- // Scrolling propagates along the containing block chain and ends at the
- // RootScroller node. The RootScroller node will have a custom applyScroll
- // callback that performs scrolling as well as associated "root" actions like
- // browser control movement and overscroll glow.
- while (cur_box) {
- Node* cur_node = cur_box->GetNode();
-
- if (cur_node) {
- if (CanScroll(scroll_state, *cur_node))
- scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+ if (is_autoscroll) {
+ // Propagate the autoscroll along the layout object chain, and
+ // append only the first node which is able to consume the scroll delta.
+ // The scroll node is computed differently to regular scrolls in order to
+ // maintain consistency with the autoscroll controller.
+ LayoutBox* autoscrollable = LayoutBox::FindAutoscrollable(
+ start_node.GetLayoutObject(), is_autoscroll);
+ if (autoscrollable) {
+ Node* cur_node = autoscrollable->GetNode();
+ LayoutObject* layout_object = cur_node->GetLayoutObject();
+ while (layout_object &&
+ !CanScroll(scroll_state, *cur_node, is_autoscroll)) {
+ ScrollPropagationDirection direction =
+ ComputePropagationDirection(scroll_state);
+
+ if (!CanPropagate(cur_node->GetLayoutBox(), direction))
+ break;
+
+ if (!layout_object->Parent() &&
+ layout_object->GetNode() == layout_object->GetDocument() &&
+ layout_object->GetDocument().LocalOwner()) {
+ layout_object =
+ layout_object->GetDocument().LocalOwner()->GetLayoutObject();
+ } else {
+ layout_object = layout_object->Parent();
+ }
+ LayoutBox* new_autoscrollable =
+ LayoutBox::FindAutoscrollable(layout_object, is_autoscroll);
+ if (new_autoscrollable)
+ cur_node = new_autoscrollable->GetNode();
+ }
+ scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+ }
+ } else {
+ LayoutBox* cur_box = start_node.GetLayoutObject()->EnclosingBox();
- if (cur_node->IsEffectiveRootScroller())
- break;
+ // Scrolling propagates along the containing block chain and ends at the
+ // RootScroller node. The RootScroller node will have a custom applyScroll
+ // callback that performs scrolling as well as associated "root" actions
+ // like browser control movement and overscroll glow.
+ while (cur_box) {
+ Node* cur_node = cur_box->GetNode();
- if (!CanPropagate(scroll_state, *cur_node)) {
- // We should add the first node with non-auto overscroll-behavior to
- // the scroll chain regardlessly, as it's the only node we can latch to.
- if (scroll_chain.empty() ||
- scroll_chain.front() != DOMNodeIds::IdForNode(cur_node)) {
+ if (cur_node) {
+ if (CanScroll(scroll_state, *cur_node, /* for_autoscroll */ false))
scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+
+ if (cur_node->IsEffectiveRootScroller())
+ break;
+
+ ScrollPropagationDirection direction =
+ ComputePropagationDirection(scroll_state);
+ if (!CanPropagate(cur_node->GetLayoutBox(), direction)) {
+ // We should add the first node with non-auto overscroll-behavior to
+ // the scroll chain regardlessly, as it's the only node we can latch
+ // to.
+ if (scroll_chain.empty() ||
+ scroll_chain.front() != DOMNodeIds::IdForNode(cur_node)) {
+ scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+ }
+ break;
}
- break;
}
- }
- cur_box = cur_box->ContainingBlock();
+ cur_box = cur_box->ContainingBlock();
+ }
}
}
bool ScrollManager::CanScroll(const ScrollState& scroll_state,
- const Node& current_node) {
+ const Node& current_node,
+ bool for_autoscroll) {
LayoutBox* scrolling_box = current_node.GetLayoutBox();
if (auto* element = DynamicTo<Element>(current_node))
scrolling_box = element->GetLayoutBoxForScrolling();
@@ -198,8 +262,9 @@ bool ScrollManager::CanScroll(const ScrollState& scroll_state,
// We need to always add the global root scroller even if it isn't scrollable
// since we can always pinch-zoom and scroll as well as for overscroll
- // effects.
- if (scrolling_box->IsGlobalRootScroller())
+ // effects. If autoscrolling, ignore this condition because we latch on
+ // to the deepest autoscrollable node.
+ if (scrolling_box->IsGlobalRootScroller() && !for_autoscroll)
return true;
// If this is the main LayoutView, and it's not the root scroller, that means
@@ -207,9 +272,10 @@ bool ScrollManager::CanScroll(const ScrollState& scroll_state,
// scroll the LayoutView should cause panning of the visual viewport as well
// so ensure it gets added to the scroll chain. See LTHI::ApplyScroll for the
// equivalent behavior in CC. Node::NativeApplyScroll contains a special
- // handler for this case.
+ // handler for this case. If autoscrolling, ignore this condition because we
+ // latch on to the deepest autoscrollable node.
if (IsA<LayoutView>(scrolling_box) &&
- current_node.GetDocument().GetFrame()->IsMainFrame()) {
+ current_node.GetDocument().GetFrame()->IsMainFrame() && !for_autoscroll) {
return true;
}
@@ -273,7 +339,8 @@ bool ScrollManager::LogicalScroll(mojom::blink::ScrollDirection direction,
std::make_unique<ScrollStateData>();
auto* scroll_state =
MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
- RecomputeScrollChain(*node, *scroll_state, scroll_chain);
+ RecomputeScrollChain(*node, *scroll_state, scroll_chain,
+ /* is_autoscroll */ false);
while (!scroll_chain.IsEmpty()) {
Node* scroll_chain_node = DOMNodeIds::NodeForId(scroll_chain.TakeLast());
@@ -384,16 +451,16 @@ void ScrollManager::CustomizedScroll(ScrollState& scroll_state) {
scroll_state.distributeToScrollChainDescendant();
}
-void ScrollManager::ComputeScrollRelatedMetrics(
- uint32_t* non_composited_main_thread_scrolling_reasons) {
+uint32_t ScrollManager::GetNonCompositedMainThreadScrollingReasons() const {
// When scrolling on the main thread, the scrollableArea may or may not be
// composited. Either way, we have recorded either the reasons stored in
// its layer or the reason NonFastScrollableRegion from the compositor
// side. Here we record scrolls that occurred on main thread due to a
// non-composited scroller.
if (!scroll_gesture_handling_node_->GetLayoutObject())
- return;
+ return 0;
+ uint32_t non_composited_main_thread_scrolling_reasons = 0;
for (auto* cur_box =
scroll_gesture_handling_node_->GetLayoutObject()->EnclosingBox();
cur_box; cur_box = cur_box->ContainingBlock()) {
@@ -405,42 +472,22 @@ void ScrollManager::ComputeScrollRelatedMetrics(
// TODO(bokan): This DCHECK is occasionally tripped. See crbug.com/944706.
// DCHECK(!scrollable_area->UsesCompositedScrolling() ||
// !scrollable_area->GetNonCompositedMainThreadScrollingReasons());
- *non_composited_main_thread_scrolling_reasons |=
+ non_composited_main_thread_scrolling_reasons |=
scrollable_area->GetNonCompositedMainThreadScrollingReasons();
}
+ return non_composited_main_thread_scrolling_reasons;
}
-void ScrollManager::RecordScrollRelatedMetrics(const WebGestureDevice device) {
+void ScrollManager::RecordScrollRelatedMetrics(WebGestureDevice device) const {
if (device != WebGestureDevice::kTouchpad &&
device != WebGestureDevice::kTouchscreen) {
return;
}
- uint32_t non_composited_main_thread_scrolling_reasons = 0;
- ComputeScrollRelatedMetrics(&non_composited_main_thread_scrolling_reasons);
-
- if (non_composited_main_thread_scrolling_reasons) {
- DCHECK(cc::MainThreadScrollingReason::HasNonCompositedScrollReasons(
- non_composited_main_thread_scrolling_reasons));
- uint32_t main_thread_scrolling_reason_enum_max =
- cc::MainThreadScrollingReason::kMainThreadScrollingReasonCount + 1;
- for (uint32_t i = cc::MainThreadScrollingReason::kNonCompositedReasonsFirst;
- i <= cc::MainThreadScrollingReason::kNonCompositedReasonsLast; ++i) {
- unsigned val = 1 << i;
- if (non_composited_main_thread_scrolling_reasons & val) {
- if (device == WebGestureDevice::kTouchscreen) {
- DEFINE_STATIC_LOCAL(EnumerationHistogram, touch_histogram,
- ("Renderer4.MainThreadGestureScrollReason",
- main_thread_scrolling_reason_enum_max));
- touch_histogram.Count(i + 1);
- } else {
- DEFINE_STATIC_LOCAL(EnumerationHistogram, wheel_histogram,
- ("Renderer4.MainThreadWheelScrollReason",
- main_thread_scrolling_reason_enum_max));
- wheel_histogram.Count(i + 1);
- }
- }
- }
+ if (uint32_t non_composited_main_thread_scrolling_reasons =
+ GetNonCompositedMainThreadScrollingReasons()) {
+ RecordScrollReasonsMetric(device,
+ non_composited_main_thread_scrolling_reasons);
}
}
@@ -497,21 +544,11 @@ WebInputEventResult ScrollManager::HandleGestureScrollBegin(
delta_consumed_for_scroll_sequence_;
auto* scroll_state =
MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
- // For middle click autoscroll, only scrollable area for
- // |scroll_gesture_handling_node_| should receive and handle all scroll
- // events. It should not bubble up to the ancestor.
- if (gesture_event.SourceDevice() == WebGestureDevice::kSyntheticAutoscroll) {
- LayoutBox* scrollable = LayoutBox::FindAutoscrollable(
- scroll_gesture_handling_node_->GetLayoutObject(),
- /*is_middle_click_autoscroll*/ true);
- if (scrollable) {
- Node* scrollable_node = scrollable->GetNode();
- current_scroll_chain_.push_back(DOMNodeIds::IdForNode(scrollable_node));
- }
- } else {
- RecomputeScrollChain(*scroll_gesture_handling_node_.Get(), *scroll_state,
- current_scroll_chain_);
- }
+
+ RecomputeScrollChain(
+ *scroll_gesture_handling_node_.Get(), *scroll_state,
+ current_scroll_chain_,
+ gesture_event.SourceDevice() == WebGestureDevice::kSyntheticAutoscroll);
TRACE_EVENT_INSTANT1("input", "Computed Scroll Chain",
TRACE_EVENT_SCOPE_THREAD, "length",
@@ -628,6 +665,9 @@ WebInputEventResult ScrollManager::HandleGestureScrollUpdate(
scroll_state_data->from_user_input = true;
scroll_state_data->delta_consumed_for_scroll_sequence =
delta_consumed_for_scroll_sequence_;
+ // Scrollbar interactions trigger scroll snap depending on the scrollbar part.
+ if (gesture_event.SourceDevice() == WebGestureDevice::kScrollbar)
+ AdjustForSnapAtScrollUpdate(gesture_event, scroll_state_data.get());
auto* scroll_state =
MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
if (previous_gesture_scrolled_node_) {
@@ -673,6 +713,50 @@ WebInputEventResult ScrollManager::HandleGestureScrollUpdate(
return WebInputEventResult::kNotHandled;
}
+void ScrollManager::AdjustForSnapAtScrollUpdate(
+ const WebGestureEvent& gesture_event,
+ ScrollStateData* scroll_state_data) {
+ // Scrollbar interactions outside of the scroll thumb behave like logical
+ // scrolls with respect to scroll snap behavior.
+ // Scrollbar arrows trigger scroll by line, whereas the scrollbar track
+ // triggers scroll by page.
+ DCHECK(gesture_event.SourceDevice() == WebGestureDevice::kScrollbar);
+ ui::ScrollGranularity granularity = gesture_event.DeltaUnits();
+ if (granularity != ui::ScrollGranularity::kScrollByLine &&
+ granularity != ui::ScrollGranularity::kScrollByPage) {
+ return;
+ }
+
+ Node* node = scroll_gesture_handling_node_;
+ ScrollableArea* scrollable_area = nullptr;
+ if (node && node->GetLayoutObject()) {
+ LayoutBox* layout_box = node->GetLayoutBox();
+ if (!layout_box)
+ return;
+ scrollable_area = ScrollableArea::GetForScrolling(layout_box);
+ }
+
+ if (!scrollable_area)
+ return;
+
+ FloatPoint current_position = scrollable_area->ScrollPosition();
+ std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+ cc::SnapSelectionStrategy::CreateForDirection(
+ gfx::ScrollOffset(current_position.X(), current_position.Y()),
+ gfx::ScrollOffset(scroll_state_data->delta_x,
+ scroll_state_data->delta_y),
+ RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
+
+ base::Optional<FloatPoint> snap_point =
+ scrollable_area->GetSnapPositionAndSetTarget(*strategy);
+ if (!snap_point)
+ return;
+
+ scroll_state_data->delta_x = (snap_point->X() - current_position.X());
+ scroll_state_data->delta_y = (snap_point->Y() - current_position.Y());
+ scroll_state_data->delta_granularity = ui::ScrollGranularity::kScrollByPixel;
+}
+
// This method is used as a ScrollCallback which requires a void return. Since
// this call to HandleGestureScrollEnd is async, we can just ignore the return
// value.
diff --git a/chromium/third_party/blink/renderer/core/input/scroll_manager.h b/chromium/third_party/blink/renderer/core/input/scroll_manager.h
index dd372e742e7..9093aeb280a 100644
--- a/chromium/third_party/blink/renderer/core/input/scroll_manager.h
+++ b/chromium/third_party/blink/renderer/core/input/scroll_manager.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
+#include "third_party/blink/renderer/core/page/scrolling/scroll_state.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
@@ -34,6 +35,10 @@ class Scrollbar;
class ScrollState;
class WebGestureEvent;
+// Scroll directions used to check whether propagation is possible in a given
+// direction. Used in CanPropagate.
+enum class ScrollPropagationDirection { kHorizontal, kVertical, kBoth, kNone };
+
// This class takes care of scrolling and resizing and the related states. The
// user action that causes scrolling or resizing is determined in other *Manager
// classes and they call into this class for doing the work.
@@ -108,6 +113,13 @@ class CORE_EXPORT ScrollManager : public GarbageCollected<ScrollManager>,
void AnimateSnapFling(base::TimeTicks monotonic_time);
+ // Determines whether the scroll-chain should be propagated upwards given a
+ // scroll direction.
+ static bool CanPropagate(const LayoutBox* layout_box,
+ ScrollPropagationDirection direction);
+ static ScrollPropagationDirection ComputePropagationDirection(
+ const ScrollState&);
+
private:
Node* NodeTargetForScrollableAreaElementId(
CompositorElementId scrollable_area_element_id) const;
@@ -133,13 +145,14 @@ class CORE_EXPORT ScrollManager : public GarbageCollected<ScrollManager>,
void RecomputeScrollChain(const Node& start_node,
const ScrollState&,
- Deque<DOMNodeId>& scroll_chain);
- bool CanScroll(const ScrollState&, const Node& current_node);
+ Deque<DOMNodeId>& scroll_chain,
+ bool is_autoscroll);
+ bool CanScroll(const ScrollState&,
+ const Node& current_node,
+ bool for_autoscroll);
- // scroller_size is set only when scrolling non root scroller.
- void ComputeScrollRelatedMetrics(
- uint32_t* non_composited_main_thread_scrolling_reasons);
- void RecordScrollRelatedMetrics(const WebGestureDevice);
+ uint32_t GetNonCompositedMainThreadScrollingReasons() const;
+ void RecordScrollRelatedMetrics(WebGestureDevice) const;
WebGestureEvent SynthesizeGestureScrollBegin(
const WebGestureEvent& update_event);
@@ -147,6 +160,9 @@ class CORE_EXPORT ScrollManager : public GarbageCollected<ScrollManager>,
bool SnapAtGestureScrollEnd(const WebGestureEvent& end_event,
base::ScopedClosureRunner callback);
+ void AdjustForSnapAtScrollUpdate(const WebGestureEvent& gesture_event,
+ ScrollStateData* scroll_state_data);
+
void NotifyScrollPhaseBeginForCustomizedScroll(const ScrollState&);
void NotifyScrollPhaseEndForCustomizedScroll();
diff --git a/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc b/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
index 5a46ce8a6df..1ac1311cdd8 100644
--- a/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/scroll_snap_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/input/scroll_manager.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
diff --git a/chromium/third_party/blink/renderer/core/input/touch_action_test.cc b/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
index fed147d05e5..01665f1a048 100644
--- a/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
+++ b/chromium/third_party/blink/renderer/core/input/touch_action_test.cc
@@ -37,7 +37,6 @@
#include "third_party/blink/public/web/web_hit_test_result.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_view_client.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -85,17 +84,19 @@ class TouchActionWidgetInputHandlerHost
TouchAction action_ = TouchAction::kAuto;
};
-class TouchActionTrackingWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
+class TouchActionTrackingWebFrameWidget
+ : public frame_test_helpers::TestWebFrameWidget {
public:
- TouchActionTrackingWebWidgetClient() = default;
+ template <typename... Args>
+ explicit TouchActionTrackingWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {}
+ // frame_test_helpers::TestWebFrameWidget overrides.
frame_test_helpers::TestWidgetInputHandlerHost* GetInputHandlerHost()
override {
return &input_handler_host_;
}
- // Local methods
void Reset() { input_handler_host_.ResetTouchAction(); }
int TouchActionSetCount() { return input_handler_host_.action_set_count(); }
@@ -108,7 +109,11 @@ class TouchActionTrackingWebWidgetClient
class TouchActionTest : public testing::Test {
public:
- TouchActionTest() : base_url_("http://www.test.com/") {
+ TouchActionTest()
+ : base_url_("http://www.test.com/"),
+ web_view_helper_(base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ TouchActionTrackingWebFrameWidget>)) {
// TODO(crbug.com/751425): We should use the mock functionality
// via |web_view_helper_|.
url_test_helpers::RegisterMockedURLLoadFromBase(
@@ -135,18 +140,14 @@ class TouchActionTest : public testing::Test {
void RunShadowDOMTest(String file);
void RunIFrameTest(String file);
void SendTouchEvent(WebView*, WebInputEvent::Type, IntPoint client_point);
- WebViewImpl* SetupTest(String file, TouchActionTrackingWebWidgetClient*);
- void RunTestOnTree(ContainerNode* root,
- WebView*,
- TouchActionTrackingWebWidgetClient&);
+ WebViewImpl* SetupTest(String file);
+ void RunTestOnTree(ContainerNode* root, WebView*);
String base_url_;
frame_test_helpers::WebViewHelper web_view_helper_;
};
void TouchActionTest::RunTouchActionTest(String file) {
- TouchActionTrackingWebWidgetClient client;
-
// runTouchActionTest() loads a document in a frame, setting up a
// nested run loop. Should any Oilpan GC happen while it is in
// effect, the implicit assumption that we're outside any event
@@ -157,20 +158,18 @@ void TouchActionTest::RunTouchActionTest(String file) {
// turn them into persistent, stack allocated references. This
// workaround is sufficient to handle this artificial test
// scenario.
- WebViewImpl* web_view = SetupTest(file, &client);
+ WebViewImpl* web_view = SetupTest(file);
Persistent<Document> document =
static_cast<Document*>(web_view->MainFrameImpl()->GetDocument());
- RunTestOnTree(document.Get(), web_view, client);
+ RunTestOnTree(document.Get(), web_view);
// Explicitly reset to break dependency on locally scoped client.
web_view_helper_.Reset();
}
void TouchActionTest::RunShadowDOMTest(String file) {
- TouchActionTrackingWebWidgetClient client;
-
- WebViewImpl* web_view = SetupTest(file, &client);
+ WebViewImpl* web_view = SetupTest(file);
DummyExceptionStateForTesting es;
@@ -185,20 +184,18 @@ void TouchActionTest::RunShadowDOMTest(String file) {
for (unsigned index = 0; index < host_nodes->length(); index++) {
ShadowRoot* shadow_root = host_nodes->item(index)->OpenShadowRoot();
- RunTestOnTree(shadow_root, web_view, client);
+ RunTestOnTree(shadow_root, web_view);
}
// Projections show up in the main document.
- RunTestOnTree(document.Get(), web_view, client);
+ RunTestOnTree(document.Get(), web_view);
// Explicitly reset to break dependency on locally scoped client.
web_view_helper_.Reset();
}
void TouchActionTest::RunIFrameTest(String file) {
- TouchActionTrackingWebWidgetClient client;
-
- WebViewImpl* web_view = SetupTest(file, &client);
+ WebViewImpl* web_view = SetupTest(file);
WebFrame* cur_frame = web_view->MainFrame()->FirstChild();
ASSERT_TRUE(cur_frame);
@@ -207,23 +204,21 @@ void TouchActionTest::RunIFrameTest(String file) {
// references.
Persistent<Document> content_doc =
static_cast<Document*>(cur_frame->ToWebLocalFrame()->GetDocument());
- RunTestOnTree(content_doc.Get(), web_view, client);
+ RunTestOnTree(content_doc.Get(), web_view);
}
// Explicitly reset to break dependency on locally scoped client.
web_view_helper_.Reset();
}
-WebViewImpl* TouchActionTest::SetupTest(
- String file,
- TouchActionTrackingWebWidgetClient* client) {
+WebViewImpl* TouchActionTest::SetupTest(String file) {
// TODO(crbug.com/751425): We should use the mock functionality
// via |web_view_helper_|.
url_test_helpers::RegisterMockedURLLoadFromBase(
WebString(base_url_), test::CoreTestDataPath(), WebString(file));
// Note that JavaScript must be enabled for shadow DOM tests.
WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(
- base_url_.Utf8() + file.Utf8(), nullptr, nullptr, client);
+ base_url_.Utf8() + file.Utf8(), nullptr, nullptr);
// Set size to enable hit testing, and avoid line wrapping for consistency
// with browser.
@@ -255,10 +250,7 @@ IntRect WindowClipRect(const LocalFrameView& frame_view) {
return EnclosingIntRect(clip_rect);
}
-void TouchActionTest::RunTestOnTree(
- ContainerNode* root,
- WebView* web_view,
- TouchActionTrackingWebWidgetClient& client) {
+void TouchActionTest::RunTestOnTree(ContainerNode* root, WebView* web_view) {
// Find all elements to test the touch-action of in the document.
DummyExceptionStateForTesting es;
@@ -365,31 +357,35 @@ void TouchActionTest::RunTestOnTree(
SendTouchEvent(web_view, WebInputEvent::Type::kPointerDown, window_point);
RunPendingTasks();
+ TouchActionTrackingWebFrameWidget* widget =
+ static_cast<TouchActionTrackingWebFrameWidget*>(
+ web_view->MainFrameWidget());
+
AtomicString expected_action = element->getAttribute("expected-action");
// Should have received exactly one touch action, even for auto.
- EXPECT_EQ(1, client.TouchActionSetCount()) << failure_context_pos;
- if (client.TouchActionSetCount()) {
+ EXPECT_EQ(1, widget->TouchActionSetCount()) << failure_context_pos;
+ if (widget->TouchActionSetCount()) {
if (expected_action == "auto") {
- EXPECT_EQ(TouchAction::kAuto, client.LastTouchAction())
+ EXPECT_EQ(TouchAction::kAuto, widget->LastTouchAction())
<< failure_context_pos;
} else if (expected_action == "none") {
- EXPECT_EQ(TouchAction::kNone, client.LastTouchAction())
+ EXPECT_EQ(TouchAction::kNone, widget->LastTouchAction())
<< failure_context_pos;
} else if (expected_action == "pan-x") {
- EXPECT_EQ(TouchAction::kPanX, client.LastTouchAction() &
+ EXPECT_EQ(TouchAction::kPanX, widget->LastTouchAction() &
~TouchAction::kInternalPanXScrolls)
<< failure_context_pos;
} else if (expected_action == "pan-y") {
- EXPECT_EQ(TouchAction::kPanY, client.LastTouchAction())
+ EXPECT_EQ(TouchAction::kPanY, widget->LastTouchAction())
<< failure_context_pos;
} else if (expected_action == "pan-x-y") {
- EXPECT_EQ(TouchAction::kPan, client.LastTouchAction() &
+ EXPECT_EQ(TouchAction::kPan, widget->LastTouchAction() &
~TouchAction::kInternalPanXScrolls)
<< failure_context_pos;
} else if (expected_action == "manipulation") {
EXPECT_EQ(
TouchAction::kManipulation,
- client.LastTouchAction() & ~TouchAction::kInternalPanXScrolls)
+ widget->LastTouchAction() & ~TouchAction::kInternalPanXScrolls)
<< failure_context_pos;
} else {
FAIL() << "Unrecognized expected-action " << expected_action << " "
@@ -398,10 +394,10 @@ void TouchActionTest::RunTestOnTree(
}
// Reset webview touch state.
- client.Reset();
+ widget->Reset();
SendTouchEvent(web_view, WebInputEvent::Type::kPointerCancel,
window_point);
- EXPECT_EQ(0, client.TouchActionSetCount());
+ EXPECT_EQ(0, widget->TouchActionSetCount());
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/BUILD.gn b/chromium/third_party/blink/renderer/core/inspector/BUILD.gn
index 19432a829ff..ae8bfda8024 100644
--- a/chromium/third_party/blink/renderer/core/inspector/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/inspector/BUILD.gn
@@ -77,6 +77,8 @@ inspector_protocol_generate("protocol_sources") {
"inspector/protocol/Page.h",
"inspector/protocol/Performance.cpp",
"inspector/protocol/Performance.h",
+ "inspector/protocol/PerformanceTimeline.cpp",
+ "inspector/protocol/PerformanceTimeline.h",
"inspector/protocol/Protocol.cpp",
"inspector/protocol/Protocol.h",
"inspector/protocol/Runtime.h",
diff --git a/chromium/third_party/blink/renderer/core/inspector/DEPS b/chromium/third_party/blink/renderer/core/inspector/DEPS
index c3873bb1d22..5dc7127faf2 100644
--- a/chromium/third_party/blink/renderer/core/inspector/DEPS
+++ b/chromium/third_party/blink/renderer/core/inspector/DEPS
@@ -23,4 +23,10 @@ specific_include_rules = {
"inspector_emulation_agent_test.cc": [
"+media/media_buildflags.h",
],
+ "inspector_contrast.cc": [
+ "+ui/gfx/color_utils.h",
+ ],
+ "inspector_contrast.h": [
+ "+cc/base/rtree.h",
+ ],
} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/inspector/DIR_METADATA b/chromium/third_party/blink/renderer/core/inspector/DIR_METADATA
new file mode 100644
index 00000000000..d78c6509dc6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform>DevTools"
+}
diff --git a/chromium/third_party/blink/renderer/core/inspector/OWNERS b/chromium/third_party/blink/renderer/core/inspector/OWNERS
index 00f97c75693..5bb4a10314e 100644
--- a/chromium/third_party/blink/renderer/core/inspector/OWNERS
+++ b/chromium/third_party/blink/renderer/core/inspector/OWNERS
@@ -1,3 +1,4 @@
+alexrudenko@chromium.org
alph@chromium.org
caseq@chromium.org
dgozman@chromium.org
@@ -5,5 +6,3 @@ petermarshall@chromium.org
pfeldman@chromium.org
sigurds@chromium.org
yangguo@chromium.org
-
-# COMPONENT: Platform>DevTools
diff --git a/chromium/third_party/blink/renderer/core/inspector/build.gni b/chromium/third_party/blink/renderer/core/inspector/build.gni
index 24ccbed7df8..2649136bccb 100644
--- a/chromium/third_party/blink/renderer/core/inspector/build.gni
+++ b/chromium/third_party/blink/renderer/core/inspector/build.gni
@@ -77,6 +77,8 @@ blink_core_sources_inspector = [
"inspector_page_agent.h",
"inspector_performance_agent.cc",
"inspector_performance_agent.h",
+ "inspector_performance_timeline_agent.cc",
+ "inspector_performance_timeline_agent.h",
"inspector_resource_container.cc",
"inspector_resource_container.h",
"inspector_resource_content_loader.cc",
@@ -85,6 +87,8 @@ blink_core_sources_inspector = [
"inspector_session_state.h",
"inspector_style_resolver.cc",
"inspector_style_resolver.h",
+ "inspector_contrast.cc",
+ "inspector_contrast.h",
"inspector_style_sheet.cc",
"inspector_style_sheet.h",
"inspector_task_runner.cc",
@@ -99,6 +103,7 @@ blink_core_sources_inspector = [
"main_thread_debugger.h",
"network_resources_data.cc",
"network_resources_data.h",
+ "node_content_visibility_state.h",
"request_debug_header_scope.cc",
"request_debug_header_scope.h",
"resolve_node.cc",
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
index 6448c8fdd7e..2a4756e475d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -68,10 +68,8 @@ DevToolsEmulator::DevToolsEmulator(WebViewImpl* web_view)
is_overlay_scrollbars_enabled_(false),
is_orientation_event_enabled_(false),
is_mobile_layout_theme_enabled_(false),
- original_default_minimum_page_scale_factor_(0),
- original_default_maximum_page_scale_factor_(0),
embedder_text_autosizing_enabled_(
- web_view->GetPage()->GetSettings().TextAutosizingEnabled()),
+ web_view->GetPage()->GetSettings().GetTextAutosizingEnabled()),
embedder_device_scale_adjustment_(
web_view->GetPage()->GetSettings().GetDeviceScaleAdjustment()),
embedder_prefer_compositing_to_lcd_text_enabled_(
@@ -94,6 +92,14 @@ DevToolsEmulator::DevToolsEmulator(WebViewImpl* web_view)
web_view->GetPage()
->GetSettings()
.GetMainFrameResizesAreOrientationChanges()),
+ embedder_min_page_scale_(web_view->DefaultMinimumPageScaleFactor()),
+ embedder_max_page_scale_(web_view->DefaultMaximumPageScaleFactor()),
+ embedder_shrink_viewport_content_(
+ web_view->GetPage()->GetSettings().GetShrinksViewportContentToFit()),
+ embedder_viewport_enabled_(
+ web_view->GetPage()->GetSettings().GetViewportEnabled()),
+ embedder_viewport_meta_enabled_(
+ web_view->GetPage()->GetSettings().GetViewportMetaEnabled()),
touch_event_emulation_enabled_(false),
double_tap_to_zoom_enabled_(false),
original_max_touch_points_(0),
@@ -193,13 +199,54 @@ void DevToolsEmulator::SetMainFrameResizesAreOrientationChanges(bool value) {
}
}
+void DevToolsEmulator::SetDefaultPageScaleLimits(float min_scale,
+ float max_scale) {
+ embedder_min_page_scale_ = min_scale;
+ embedder_max_page_scale_ = max_scale;
+ bool emulate_mobile_enabled =
+ device_metrics_enabled_ && emulate_mobile_enabled_;
+ if (!emulate_mobile_enabled) {
+ web_view_->GetPage()->SetDefaultPageScaleLimits(min_scale, max_scale);
+ }
+}
+
+void DevToolsEmulator::SetShrinksViewportContentToFit(
+ bool shrink_viewport_content) {
+ embedder_shrink_viewport_content_ = shrink_viewport_content;
+ bool emulate_mobile_enabled =
+ device_metrics_enabled_ && emulate_mobile_enabled_;
+ if (!emulate_mobile_enabled) {
+ web_view_->GetPage()->GetSettings().SetShrinksViewportContentToFit(
+ shrink_viewport_content);
+ }
+}
+
+void DevToolsEmulator::SetViewportEnabled(bool enabled) {
+ embedder_viewport_enabled_ = enabled;
+ bool emulate_mobile_enabled =
+ device_metrics_enabled_ && emulate_mobile_enabled_;
+ if (!emulate_mobile_enabled) {
+ web_view_->GetPage()->GetSettings().SetViewportEnabled(enabled);
+ }
+}
+
+void DevToolsEmulator::SetViewportMetaEnabled(bool enabled) {
+ embedder_viewport_meta_enabled_ = enabled;
+ bool emulate_mobile_enabled =
+ device_metrics_enabled_ && emulate_mobile_enabled_;
+ if (!emulate_mobile_enabled) {
+ web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(enabled);
+ }
+}
+
void DevToolsEmulator::SetAvailablePointerTypes(int types) {
embedder_available_pointer_types_ = types;
if (!touch_event_emulation_enabled_)
web_view_->GetPage()->GetSettings().SetAvailablePointerTypes(types);
}
-void DevToolsEmulator::SetPrimaryPointerType(ui::PointerType pointer_type) {
+void DevToolsEmulator::SetPrimaryPointerType(
+ mojom::blink::PointerType pointer_type) {
embedder_primary_pointer_type_ = pointer_type;
if (!touch_event_emulation_enabled_)
web_view_->GetPage()->GetSettings().SetPrimaryPointerType(pointer_type);
@@ -211,7 +258,7 @@ void DevToolsEmulator::SetAvailableHoverTypes(int types) {
web_view_->GetPage()->GetSettings().SetAvailableHoverTypes(types);
}
-void DevToolsEmulator::SetPrimaryHoverType(ui::HoverType hover_type) {
+void DevToolsEmulator::SetPrimaryHoverType(mojom::blink::HoverType hover_type) {
embedder_primary_hover_type_ = hover_type;
if (!touch_event_emulation_enabled_)
web_view_->GetPage()->GetSettings().SetPrimaryHoverType(hover_type);
@@ -306,7 +353,7 @@ void DevToolsEmulator::EnableMobileEmulation() {
web_view_->GetPage()->GetSettings().SetViewportEnabled(true);
web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(true);
web_view_->GetPage()->GetVisualViewport().InitializeScrollbars();
- web_view_->GetSettings()->SetShrinksViewportContentToFit(true);
+ web_view_->GetPage()->GetSettings().SetShrinksViewportContentToFit(true);
web_view_->GetPage()->GetSettings().SetTextAutosizingEnabled(true);
web_view_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled(
true);
@@ -314,12 +361,7 @@ void DevToolsEmulator::EnableMobileEmulation() {
web_view_->GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges(
true);
web_view_->SetZoomFactorOverride(1);
-
- original_default_minimum_page_scale_factor_ =
- web_view_->DefaultMinimumPageScaleFactor();
- original_default_maximum_page_scale_factor_ =
- web_view_->DefaultMaximumPageScaleFactor();
- web_view_->SetDefaultPageScaleLimits(0.25f, 5);
+ web_view_->GetPage()->SetDefaultPageScaleLimits(0.25f, 5);
// TODO(wjmaclean): Update all local frames in the WebView's frame tree, not
// just a local main frame.
@@ -339,10 +381,13 @@ void DevToolsEmulator::DisableMobileEmulation() {
ComputedStyle::InvalidateInitialStyle();
Page::PlatformColorsChanged();
web_view_->GetPage()->GetSettings().SetForceAndroidOverlayScrollbar(false);
- web_view_->GetPage()->GetSettings().SetViewportEnabled(false);
- web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(false);
+ web_view_->GetPage()->GetSettings().SetViewportEnabled(
+ embedder_viewport_enabled_);
+ web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(
+ embedder_viewport_meta_enabled_);
web_view_->GetPage()->GetVisualViewport().InitializeScrollbars();
- web_view_->GetSettings()->SetShrinksViewportContentToFit(false);
+ web_view_->GetSettings()->SetShrinksViewportContentToFit(
+ embedder_shrink_viewport_content_);
web_view_->GetPage()->GetSettings().SetTextAutosizingEnabled(
embedder_text_autosizing_enabled_);
web_view_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled(
@@ -354,10 +399,9 @@ void DevToolsEmulator::DisableMobileEmulation() {
web_view_->GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges(
embedder_main_frame_resizes_are_orientation_changes_);
web_view_->SetZoomFactorOverride(0);
+ web_view_->GetPage()->SetDefaultPageScaleLimits(embedder_min_page_scale_,
+ embedder_max_page_scale_);
emulate_mobile_enabled_ = false;
- web_view_->SetDefaultPageScaleLimits(
- original_default_minimum_page_scale_factor_,
- original_default_maximum_page_scale_factor_);
// MainFrameImpl() could be null during cleanup or remote <-> local swap.
if (web_view_->MainFrameImpl())
web_view_->MainFrameImpl()->GetFrameView()->UpdateLayout();
@@ -431,10 +475,10 @@ void DevToolsEmulator::OverrideVisibleRect(
if (!viewport_override_ || !frame)
return;
- FloatSize scaled_viewport_size(viewport_size);
- scaled_viewport_size.Scale(1. / viewport_override_->scale);
+ // Don't apply viewport_override_->scale because all coordinates here are
+ // under the same scale.
IntRect visible_rect_in_document = EnclosingIntRect(
- FloatRect(viewport_override_->position, scaled_viewport_size));
+ FloatRect(viewport_override_->position, FloatSize(viewport_size)));
*visible_rect_in_frame =
frame->GetFrameView()->DocumentToFrame(visible_rect_in_document);
}
@@ -456,13 +500,17 @@ void DevToolsEmulator::SetTouchEventEmulationEnabled(bool enabled,
web_view_->GetPage()->GetSettings().SetMaxTouchPoints(
enabled ? max_touch_points : original_max_touch_points_);
web_view_->GetPage()->GetSettings().SetAvailablePointerTypes(
- enabled ? ui::POINTER_TYPE_COARSE : embedder_available_pointer_types_);
+ enabled ? static_cast<int>(mojom::blink::PointerType::kPointerCoarseType)
+ : embedder_available_pointer_types_);
web_view_->GetPage()->GetSettings().SetPrimaryPointerType(
- enabled ? ui::POINTER_TYPE_COARSE : embedder_primary_pointer_type_);
+ enabled ? mojom::blink::PointerType::kPointerCoarseType
+ : embedder_primary_pointer_type_);
web_view_->GetPage()->GetSettings().SetAvailableHoverTypes(
- enabled ? ui::HOVER_TYPE_NONE : embedder_available_hover_types_);
+ enabled ? static_cast<int>(mojom::blink::HoverType::kHoverNone)
+ : embedder_available_hover_types_);
web_view_->GetPage()->GetSettings().SetPrimaryHoverType(
- enabled ? ui::HOVER_TYPE_NONE : embedder_primary_hover_type_);
+ enabled ? mojom::blink::HoverType::kHoverNone
+ : embedder_primary_hover_type_);
WebLocalFrameImpl* frame = web_view_->MainFrameImpl();
if (enabled && frame)
frame->GetFrame()->GetEventHandler().ClearMouseEventManager();
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
index 5472b949320..dffd741446c 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "ui/base/pointer/pointer_device.h"
namespace gfx {
class PointF;
@@ -42,10 +41,14 @@ class CORE_EXPORT DevToolsEmulator final
void SetDoubleTapToZoomEnabled(bool);
bool DoubleTapToZoomEnabled() const;
void SetAvailablePointerTypes(int);
- void SetPrimaryPointerType(ui::PointerType);
+ void SetPrimaryPointerType(mojom::blink::PointerType);
void SetAvailableHoverTypes(int);
- void SetPrimaryHoverType(ui::HoverType);
+ void SetPrimaryHoverType(mojom::blink::HoverType);
void SetMainFrameResizesAreOrientationChanges(bool);
+ void SetDefaultPageScaleLimits(float min_scale, float max_scale);
+ void SetShrinksViewportContentToFit(bool shrink_viewport_content);
+ void SetViewportEnabled(bool);
+ void SetViewportMetaEnabled(bool);
// Enables and/or sets the parameters for emulation. Returns the emulation
// transform to be used as a result.
@@ -117,18 +120,21 @@ class CORE_EXPORT DevToolsEmulator final
bool is_overlay_scrollbars_enabled_;
bool is_orientation_event_enabled_;
bool is_mobile_layout_theme_enabled_;
- float original_default_minimum_page_scale_factor_;
- float original_default_maximum_page_scale_factor_;
bool embedder_text_autosizing_enabled_;
float embedder_device_scale_adjustment_;
bool embedder_prefer_compositing_to_lcd_text_enabled_;
mojom::blink::ViewportStyle embedder_viewport_style_;
bool embedder_plugins_enabled_;
int embedder_available_pointer_types_;
- ui::PointerType embedder_primary_pointer_type_;
+ mojom::blink::PointerType embedder_primary_pointer_type_;
int embedder_available_hover_types_;
- ui::HoverType embedder_primary_hover_type_;
+ mojom::blink::HoverType embedder_primary_hover_type_;
bool embedder_main_frame_resizes_are_orientation_changes_;
+ float embedder_min_page_scale_;
+ float embedder_max_page_scale_;
+ bool embedder_shrink_viewport_content_;
+ bool embedder_viewport_enabled_;
+ bool embedder_viewport_meta_enabled_;
bool touch_event_emulation_enabled_;
bool double_tap_to_zoom_enabled_;
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
index e045e807404..eff71ef13a5 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.cc
@@ -29,7 +29,7 @@
#include "third_party/blink/renderer/core/inspector/dev_tools_host.h"
-#include "third_party/blink/public/web/web_menu_item_info.h"
+#include "third_party/blink/public/common/context_menu_data/menu_item_info.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_script_runner.h"
@@ -62,7 +62,7 @@ namespace blink {
class FrontendMenuProvider final : public ContextMenuProvider {
public:
FrontendMenuProvider(DevToolsHost* devtools_host,
- WebVector<WebMenuItemInfo> items)
+ WebVector<MenuItemInfo> items)
: devtools_host_(devtools_host), items_(std::move(items)) {}
~FrontendMenuProvider() override {
// Verify that this menu provider has been detached.
@@ -85,7 +85,7 @@ class FrontendMenuProvider final : public ContextMenuProvider {
items_.Clear();
}
- WebVector<WebMenuItemInfo> PopulateContextMenu() override {
+ WebVector<MenuItemInfo> PopulateContextMenu() override {
return std::move(items_);
}
@@ -98,7 +98,7 @@ class FrontendMenuProvider final : public ContextMenuProvider {
private:
Member<DevToolsHost> devtools_host_;
- WebVector<WebMenuItemInfo> items_;
+ WebVector<MenuItemInfo> items_;
};
DevToolsHost::DevToolsHost(InspectorFrontendClient* client,
@@ -192,7 +192,7 @@ void DevToolsHost::sendMessageToEmbedder(const String& message) {
void DevToolsHost::ShowContextMenu(LocalFrame* target_frame,
float x,
float y,
- WebVector<WebMenuItemInfo> items) {
+ WebVector<MenuItemInfo> items) {
DCHECK(frontend_frame_);
auto* menu_provider =
MakeGarbageCollected<FrontendMenuProvider>(this, std::move(items));
diff --git a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
index ac3e6010e27..9e9906df545 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
+++ b/chromium/third_party/blink/renderer/core/inspector/dev_tools_host.h
@@ -40,7 +40,7 @@ namespace blink {
class FrontendMenuProvider;
class InspectorFrontendClient;
class LocalFrame;
-struct WebMenuItemInfo;
+struct MenuItemInfo;
class CORE_EXPORT DevToolsHost final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -61,7 +61,7 @@ class CORE_EXPORT DevToolsHost final : public ScriptWrappable {
void ShowContextMenu(LocalFrame* target_frame,
float x,
float y,
- WebVector<WebMenuItemInfo> items);
+ WebVector<MenuItemInfo> items);
void sendMessageToEmbedder(const String& message);
bool isHostedMode();
diff --git a/chromium/third_party/blink/renderer/core/inspector/devtools_session.cc b/chromium/third_party/blink/renderer/core/inspector/devtools_session.cc
index 0608c4defc6..242653b4e72 100644
--- a/chromium/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -58,10 +58,10 @@ class DevToolsSession::IOSession : public mojom::blink::DevToolsSession {
: io_task_runner_(io_task_runner),
inspector_task_runner_(inspector_task_runner),
session_(std::move(session)) {
- PostCrossThreadTask(*io_task_runner, FROM_HERE,
- CrossThreadBindOnce(&IOSession::BindInterface,
- CrossThreadUnretained(this),
- WTF::Passed(std::move(receiver))));
+ PostCrossThreadTask(
+ *io_task_runner, FROM_HERE,
+ CrossThreadBindOnce(&IOSession::BindInterface,
+ CrossThreadUnretained(this), std::move(receiver)));
}
~IOSession() override = default;
diff --git a/chromium/third_party/blink/renderer/core/inspector/dom_traversal_utils.cc b/chromium/third_party/blink/renderer/core/inspector/dom_traversal_utils.cc
index 71a752e0ed9..1bfdfb57ceb 100644
--- a/chromium/third_party/blink/renderer/core/inspector/dom_traversal_utils.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/dom_traversal_utils.cc
@@ -11,12 +11,8 @@ Node* FirstChild(const Node& node, bool include_user_agent_shadow_tree) {
DCHECK(include_user_agent_shadow_tree || !node.IsInUserAgentShadowRoot());
if (!include_user_agent_shadow_tree) {
ShadowRoot* shadow_root = node.GetShadowRoot();
- if (shadow_root && shadow_root->GetType() == ShadowRootType::kUserAgent) {
- Node* child = node.firstChild();
- while (child && !child->CanParticipateInFlatTree())
- child = child->nextSibling();
- return child;
- }
+ if (shadow_root && shadow_root->GetType() == ShadowRootType::kUserAgent)
+ return node.firstChild();
}
return FlatTreeTraversal::FirstChild(node);
}
@@ -33,10 +29,7 @@ Node* NextSibling(const Node& node, bool include_user_agent_shadow_tree) {
if (node.ParentElementShadowRoot() &&
node.ParentElementShadowRoot()->GetType() ==
ShadowRootType::kUserAgent) {
- Node* sibling = node.nextSibling();
- while (sibling && !sibling->CanParticipateInFlatTree())
- sibling = sibling->nextSibling();
- return sibling;
+ return node.nextSibling();
}
}
return FlatTreeTraversal::NextSibling(node);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspect_tools.cc b/chromium/third_party/blink/renderer/core/inspector/inspect_tools.cc
index 9e222755a7b..937955cb02f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspect_tools.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
+#include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -44,12 +45,14 @@ InspectorHighlightContrastInfo FetchContrast(Node* node) {
Vector<Color> bgcolors;
String font_size;
String font_weight;
+ float text_opacity = 1.0f;
InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &font_size,
- &font_weight);
+ &font_weight, &text_opacity);
if (bgcolors.size() == 1) {
result.font_size = font_size;
result.font_weight = font_weight;
result.background_color = bgcolors[0];
+ result.text_opacity = text_opacity;
}
return result;
}
@@ -98,6 +101,38 @@ Node* HoveredNodeForEvent(LocalFrame* frame,
ignore_pointer_events_none);
}
+bool IsSelfLocked(Node* node) {
+ auto* element = DynamicTo<Element>(node);
+ if (!element)
+ return false;
+
+ auto* context = element->GetDisplayLockContext();
+ if (!context)
+ return false;
+
+ return context->IsLocked();
+}
+
+NodeContentVisibilityState DetermineSelfContentVisibilityState(Node* node) {
+ return IsSelfLocked(node) ? NodeContentVisibilityState::kIsLocked
+ : NodeContentVisibilityState::kNone;
+}
+
+std::pair<Node*, NodeContentVisibilityState> DetermineContentVisibilityState(
+ Node* node) {
+ DCHECK(node);
+ std::pair<Node*, NodeContentVisibilityState> result;
+ if (auto* locked_ancestor =
+ DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
+ result.first = locked_ancestor;
+ result.second = NodeContentVisibilityState::kIsLockedAncestor;
+ } else {
+ result.first = node;
+ result.second = DetermineSelfContentVisibilityState(node);
+ }
+ return result;
+}
+
} // namespace
// SearchingForNodeTool --------------------------------------------------------
@@ -141,7 +176,8 @@ void SearchingForNodeTool::Draw(float scale) {
node->GetDocument().GetFrame();
overlay_->EnsureAXContext(node);
InspectorHighlight highlight(node, *highlight_config_, contrast_info_,
- append_element_info, false, is_locked_ancestor_);
+ append_element_info, false,
+ content_visibility_state_);
if (event_target_node_) {
highlight.AppendEventTargetQuads(event_target_node_.Get(),
*highlight_config_);
@@ -157,7 +193,8 @@ bool SearchingForNodeTool::HandleInputEvent(LocalFrameView* frame_view,
const WebInputEvent& input_event,
bool* swallow_next_mouse_up) {
if (input_event.GetType() == WebInputEvent::Type::kGestureScrollBegin ||
- input_event.GetType() == WebInputEvent::Type::kGestureScrollUpdate) {
+ input_event.GetType() == WebInputEvent::Type::kGestureScrollUpdate ||
+ input_event.GetType() == WebInputEvent::Type::kMouseLeave) {
hovered_node_.Clear();
event_target_node_.Clear();
overlay_->ScheduleUpdate();
@@ -188,15 +225,8 @@ bool SearchingForNodeTool::HandleMouseMove(const WebMouseEvent& event) {
if (!node)
return true;
- // If |node| is in a display locked subtree, highlight the highest locked
- // element instead.
- if (Node* locked_ancestor =
- DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
- node = locked_ancestor;
- is_locked_ancestor_ = true;
- } else {
- is_locked_ancestor_ = false;
- }
+ std::tie(node, content_visibility_state_) =
+ DetermineContentVisibilityState(node);
if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node)) {
if (!IsA<LocalFrame>(frame_owner->ContentFrame())) {
@@ -208,6 +238,7 @@ bool SearchingForNodeTool::HandleMouseMove(const WebMouseEvent& event) {
}
// Store values for the highlight.
+ bool hovered_node_changed = node != hovered_node_;
hovered_node_ = node;
event_target_node_ = (event.GetModifiers() & WebInputEvent::kShiftKey)
? HoveredNodeForEvent(frame, event, false)
@@ -218,7 +249,8 @@ bool SearchingForNodeTool::HandleMouseMove(const WebMouseEvent& event) {
(WebInputEvent::kControlKey | WebInputEvent::kMetaKey);
contrast_info_ = FetchContrast(node);
- NodeHighlightRequested(node);
+ if (hovered_node_changed)
+ NodeHighlightRequested(node);
return true;
}
@@ -308,13 +340,8 @@ NodeHighlightTool::NodeHighlightTool(
: InspectTool(overlay, frontend),
selector_list_(selector_list),
highlight_config_(std::move(highlight_config)) {
- if (Node* locked_ancestor =
- DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
- is_locked_ancestor_ = true;
- node_ = locked_ancestor;
- } else {
- node_ = node;
- }
+ std::tie(node_, content_visibility_state_) =
+ DetermineContentVisibilityState(node);
contrast_info_ = FetchContrast(node_);
}
@@ -374,10 +401,12 @@ void NodeHighlightTool::DrawMatchingSelector() {
// Skip elements in locked subtrees.
if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*element))
continue;
+ NodeContentVisibilityState content_visibility_state =
+ DetermineSelfContentVisibilityState(element);
InspectorHighlight highlight(element, *highlight_config_, contrast_info_,
false /* append_element_info */,
false /* append_distance_info */,
- false /* is_locked_ancestor */);
+ content_visibility_state);
overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
}
}
@@ -394,35 +423,45 @@ NodeHighlightTool::GetNodeInspectorHighlightAsJson(
overlay_->EnsureAXContext(node_.Get());
InspectorHighlight highlight(node_.Get(), *highlight_config_, contrast_info_,
append_element_info, append_distance_info,
- is_locked_ancestor_);
+ content_visibility_state_);
return highlight.AsProtocolValue();
}
// GridHighlightTool -----------------------------------------------------------
-String GridHighlightTool::GetOverlayName() {
- return OverlayNames::OVERLAY_HIGHLIGHT_GRID;
+String PersistentTool::GetOverlayName() {
+ return OverlayNames::OVERLAY_PERSISTENT;
}
-void GridHighlightTool::AddGridConfig(
- Node* node,
- std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config) {
- grid_node_highlights_.emplace_back(
- std::make_pair(node, std::move(grid_highlight_config)));
+bool PersistentTool::IsEmpty() {
+ return !grid_node_highlights_.size() && !flex_container_configs_.size();
+}
+
+void PersistentTool::SetGridConfigs(
+ Vector<std::pair<Member<Node>,
+ std::unique_ptr<InspectorGridHighlightConfig>>> configs) {
+ grid_node_highlights_ = std::move(configs);
+}
+
+void PersistentTool::SetFlexContainerConfigs(
+ Vector<std::pair<Member<Node>,
+ std::unique_ptr<InspectorFlexContainerHighlightConfig>>>
+ configs) {
+ flex_container_configs_ = std::move(configs);
}
-bool GridHighlightTool::ForwardEventsToOverlay() {
+bool PersistentTool::ForwardEventsToOverlay() {
return false;
}
-bool GridHighlightTool::HideOnHideHighlight() {
+bool PersistentTool::HideOnHideHighlight() {
return false;
}
-bool GridHighlightTool::HideOnMouseMove() {
+bool PersistentTool::HideOnMouseMove() {
return false;
}
-void GridHighlightTool::Draw(float scale) {
+void PersistentTool::Draw(float scale) {
for (auto& entry : grid_node_highlights_) {
std::unique_ptr<protocol::Value> highlight =
InspectorGridHighlight(entry.first.Get(), *(entry.second));
@@ -430,10 +469,18 @@ void GridHighlightTool::Draw(float scale) {
continue;
overlay_->EvaluateInOverlay("drawGridHighlight", std::move(highlight));
}
+ for (auto& entry : flex_container_configs_) {
+ std::unique_ptr<protocol::Value> highlight =
+ InspectorFlexContainerHighlight(entry.first.Get(), *(entry.second));
+ if (!highlight)
+ continue;
+ overlay_->EvaluateInOverlay("drawFlexContainerHighlight",
+ std::move(highlight));
+ }
}
std::unique_ptr<protocol::DictionaryValue>
-GridHighlightTool::GetGridInspectorHighlightsAsJson() const {
+PersistentTool::GetGridInspectorHighlightsAsJson() const {
std::unique_ptr<protocol::ListValue> highlights =
protocol::ListValue::create();
for (auto& entry : grid_node_highlights_) {
@@ -460,12 +507,7 @@ SourceOrderTool::SourceOrderTool(
std::unique_ptr<InspectorSourceOrderConfig> source_order_config)
: InspectTool(overlay, frontend),
source_order_config_(std::move(source_order_config)) {
- if (Node* locked_ancestor =
- DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
- node_ = locked_ancestor;
- } else {
- node_ = node;
- }
+ node_ = DetermineContentVisibilityState(node).first;
}
String SourceOrderTool::GetOverlayName() {
@@ -562,12 +604,7 @@ bool NearbyDistanceTool::HandleMouseMove(const WebMouseEvent& event) {
return false;
}
}
-
- // If |node| is in a display locked subtree, highlight the highest locked
- // element instead.
- if (Node* locked_ancestor =
- DisplayLockUtilities::HighestLockedExclusiveAncestor(*node))
- node = locked_ancestor;
+ node = DetermineContentVisibilityState(node).first;
// Store values for the highlight.
hovered_node_ = node;
@@ -583,10 +620,11 @@ void NearbyDistanceTool::Draw(float scale) {
if (!node)
return;
overlay_->EnsureAXContext(node);
+ auto content_visibility_state = DetermineSelfContentVisibilityState(node);
InspectorHighlight highlight(
node, InspectorHighlight::DefaultConfig(),
InspectorHighlightContrastInfo(), false /* append_element_info */,
- true /* append_distance_info */, false /* is_locked_ancestor */);
+ true /* append_distance_info */, content_visibility_state);
overlay_->EvaluateInOverlay("drawDistances", highlight.AsProtocolValue());
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspect_tools.h b/chromium/third_party/blink/renderer/core/inspector/inspect_tools.h
index c1c9705b118..bd16149f25f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspect_tools.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspect_tools.h
@@ -6,9 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECT_TOOLS_H_
#include <vector>
+
#include <v8-inspector.h>
#include "base/macros.h"
#include "third_party/blink/renderer/core/inspector/inspector_overlay_agent.h"
+#include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
namespace blink {
@@ -25,6 +27,8 @@ class SearchingForNodeTool : public InspectTool {
bool ua_shadow,
const std::vector<uint8_t>& highlight_config);
+ void Trace(Visitor* visitor) const override;
+
private:
bool HandleInputEvent(LocalFrameView* frame_view,
const WebInputEvent& input_event,
@@ -36,13 +40,15 @@ class SearchingForNodeTool : public InspectTool {
bool HandlePointerEvent(const WebPointerEvent&) override;
void Draw(float scale) override;
void NodeHighlightRequested(Node*);
- void Trace(Visitor* visitor) const override;
bool SupportsPersistentOverlays() override;
String GetOverlayName() override;
Member<InspectorDOMAgent> dom_agent_;
bool ua_shadow_;
- bool is_locked_ancestor_ = false;
+
+ NodeContentVisibilityState content_visibility_state_ =
+ NodeContentVisibilityState::kNone;
+
Member<Node> hovered_node_;
Member<Node> event_target_node_;
std::unique_ptr<InspectorHighlightConfig> highlight_config_;
@@ -86,6 +92,8 @@ class NodeHighlightTool : public InspectTool {
bool append_element_info,
bool append_distance_info) const;
+ void Trace(Visitor* visitor) const override;
+
private:
bool ForwardEventsToOverlay() override;
bool SupportsPersistentOverlays() override;
@@ -94,10 +102,10 @@ class NodeHighlightTool : public InspectTool {
void Draw(float scale) override;
void DrawNode();
void DrawMatchingSelector();
- void Trace(Visitor* visitor) const override;
String GetOverlayName() override;
- bool is_locked_ancestor_ = false;
+ NodeContentVisibilityState content_visibility_state_ =
+ NodeContentVisibilityState::kNone;
Member<Node> node_;
String selector_list_;
std::unique_ptr<InspectorHighlightConfig> highlight_config_;
@@ -117,13 +125,14 @@ class SourceOrderTool : public InspectTool {
std::unique_ptr<protocol::DictionaryValue>
GetNodeInspectorSourceOrderHighlightAsJson() const;
+ void Trace(Visitor* visitor) const override;
+
private:
bool HideOnHideHighlight() override;
bool HideOnMouseMove() override;
void Draw(float scale) override;
void DrawNode(Node* node, int source_order_position);
void DrawParentNode();
- void Trace(Visitor* visitor) const override;
String GetOverlayName() override;
Member<Node> node_;
@@ -133,14 +142,19 @@ class SourceOrderTool : public InspectTool {
// -----------------------------------------------------------------------------
-class GridHighlightTool : public InspectTool {
+using GirdConfigs = Vector<
+ std::pair<Member<Node>, std::unique_ptr<InspectorGridHighlightConfig>>>;
+using FlexContainerConfigs =
+ Vector<std::pair<Member<Node>,
+ std::unique_ptr<InspectorFlexContainerHighlightConfig>>>;
+class PersistentTool : public InspectTool {
using InspectTool::InspectTool;
public:
void Draw(float scale) override;
- void AddGridConfig(
- Node* node,
- std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config);
+ bool IsEmpty();
+ void SetGridConfigs(GirdConfigs);
+ void SetFlexContainerConfigs(FlexContainerConfigs);
std::unique_ptr<protocol::DictionaryValue> GetGridInspectorHighlightsAsJson()
const;
@@ -151,23 +165,25 @@ class GridHighlightTool : public InspectTool {
bool HideOnHideHighlight() override;
String GetOverlayName() override;
- Vector<std::pair<Member<Node>, std::unique_ptr<InspectorGridHighlightConfig>>>
- grid_node_highlights_;
- DISALLOW_COPY_AND_ASSIGN(GridHighlightTool);
+ GirdConfigs grid_node_highlights_;
+ FlexContainerConfigs flex_container_configs_;
+ DISALLOW_COPY_AND_ASSIGN(PersistentTool);
};
// -----------------------------------------------------------------------------
class NearbyDistanceTool : public InspectTool {
- using InspectTool::InspectTool;
+ public:
+ void Trace(Visitor* visitor) const override;
private:
+ using InspectTool::InspectTool;
+
bool HandleMouseDown(const WebMouseEvent& event,
bool* swallow_next_mouse_up) override;
bool HandleMouseMove(const WebMouseEvent& event) override;
bool HandleMouseUp(const WebMouseEvent& event) override;
void Draw(float scale) override;
- void Trace(Visitor* visitor) const override;
String GetOverlayName() override;
Member<Node> hovered_node_;
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
index e54b1ce1d13..ed385497346 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
@@ -185,6 +185,13 @@ InspectorAnimationAgent::BuildObjectForAnimation(blink::Animation& animation) {
String id = String::Number(animation.SequenceNumber());
id_to_animation_.Set(id, &animation);
+ double current_time = Timing::NullValue();
+ base::Optional<AnimationTimeDelta> animation_current_time =
+ animation.CurrentTimeInternal();
+ if (animation_current_time) {
+ current_time = animation_current_time.value().InMillisecondsF();
+ }
+
std::unique_ptr<protocol::Animation::Animation> animation_object =
protocol::Animation::Animation::create()
.setId(id)
@@ -193,7 +200,7 @@ InspectorAnimationAgent::BuildObjectForAnimation(blink::Animation& animation) {
.setPlayState(animation.PlayStateString())
.setPlaybackRate(animation.playbackRate())
.setStartTime(NormalizedStartTime(animation))
- .setCurrentTime(animation.currentTime().value_or(Timing::NullValue()))
+ .setCurrentTime(current_time)
.setType(animation_type)
.build();
if (animation_type != AnimationType::WebAnimation)
@@ -224,17 +231,26 @@ Response InspectorAnimationAgent::getCurrentTime(const String& id,
if (id_to_animation_clone_.at(id))
animation = id_to_animation_clone_.at(id);
+ *current_time = Timing::NullValue();
if (animation->Paused() || !animation->timeline()->IsActive()) {
- *current_time = animation->currentTime().value_or(Timing::NullValue());
+ base::Optional<AnimationTimeDelta> animation_current_time =
+ animation->CurrentTimeInternal();
+ if (animation_current_time) {
+ *current_time = animation_current_time.value().InMillisecondsF();
+ }
} else {
// Use startTime where possible since currentTime is limited.
- base::Optional<double> timeline_time =
- animation->timeline()->CurrentTimeMilliseconds();
- // TODO(crbug.com/916117): Handle NaN values for scroll linked animations.
- *current_time =
- timeline_time ? timeline_time.value() -
- animation->startTime().value_or(Timing::NullValue())
- : Timing::NullValue();
+ base::Optional<AnimationTimeDelta> animation_start_time =
+ animation->StartTimeInternal();
+ if (animation_start_time) {
+ base::Optional<AnimationTimeDelta> timeline_time =
+ animation->timeline()->CurrentTime();
+ // TODO(crbug.com/916117): Handle NaN values for scroll linked animations.
+ if (timeline_time) {
+ *current_time = timeline_time.value().InMillisecondsF() -
+ animation_start_time.value().InMillisecondsF();
+ }
+ }
}
return Response::Success();
}
@@ -252,20 +268,23 @@ Response InspectorAnimationAgent::setPaused(
return Response::ServerError("Failed to clone detached animation");
if (paused && !clone->Paused()) {
// Ensure we restore a current time if the animation is limited.
- double current_time = 0;
+ base::Optional<AnimationTimeDelta> current_time;
if (!clone->timeline()->IsActive()) {
- current_time = clone->currentTime().value_or(Timing::NullValue());
+ current_time = clone->CurrentTimeInternal();
} else {
- base::Optional<double> timeline_time =
- clone->timeline()->CurrentTimeMilliseconds();
- // TODO(crbug.com/916117): Handle NaN values.
- current_time =
- timeline_time ? timeline_time.value() -
- clone->startTime().value_or(Timing::NullValue())
- : Timing::NullValue();
+ base::Optional<AnimationTimeDelta> start_time =
+ clone->StartTimeInternal();
+ if (start_time) {
+ base::Optional<AnimationTimeDelta> timeline_time =
+ clone->timeline()->CurrentTime();
+ // TODO(crbug.com/916117): Handle NaN values.
+ if (timeline_time) {
+ current_time = timeline_time.value() - start_time.value();
+ }
+ }
}
clone->pause();
- clone->setCurrentTime(current_time);
+ clone->SetCurrentTimeInternal(current_time.value());
} else if (!paused && clone->Paused()) {
clone->Unpause();
}
@@ -312,7 +331,9 @@ blink::Animation* InspectorAnimationAgent::AnimationClone(
id_to_animation_clone_.Set(id, clone);
id_to_animation_.Set(String::Number(clone->SequenceNumber()), clone);
clone->play();
- clone->setStartTime(animation->startTime().value_or(Timing::NullValue()));
+ CSSNumberish start_time;
+ animation->startTime(start_time);
+ clone->setStartTime(start_time);
animation->SetEffectSuppressed(true);
}
@@ -332,7 +353,8 @@ Response InspectorAnimationAgent::seekAnimations(
return Response::ServerError("Failed to clone a detached animation.");
if (!clone->Paused())
clone->play();
- clone->setCurrentTime(current_time);
+ clone->SetCurrentTimeInternal(
+ AnimationTimeDelta::FromMillisecondsD(current_time));
}
return Response::Success();
}
@@ -512,7 +534,12 @@ DocumentTimeline& InspectorAnimationAgent::ReferenceTimeline() {
double InspectorAnimationAgent::NormalizedStartTime(
blink::Animation& animation) {
- double time_ms = animation.startTime().value_or(Timing::NullValue());
+ double time_ms = Timing::NullValue();
+ base::Optional<AnimationTimeDelta> start_time = animation.StartTimeInternal();
+ if (start_time) {
+ time_ms = start_time.value().InMillisecondsF();
+ }
+
auto* document_timeline = DynamicTo<DocumentTimeline>(animation.timeline());
if (document_timeline) {
if (ReferenceTimeline().PlaybackRate() == 0) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
index a1717fda6c0..233632b95ff 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
@@ -8,12 +8,16 @@
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/web/web_image.h"
+#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
+#include "third_party/blink/renderer/core/dom/dom_token_list.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/inspector/inspector_issue.h"
#include "third_party/blink/renderer/core/inspector/inspector_issue_storage.h"
#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
+#include "third_party/blink/renderer/core/inspector/protocol/Audits.h"
#include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
-
namespace blink {
using protocol::Maybe;
@@ -64,19 +68,55 @@ bool EncodeAsImage(char* body,
return image_to_encode->EncodeImage(mime_type, quality, output);
}
+mojom::blink::InspectorIssueInfoPtr CreateLowTextContrastIssue(
+ const ContrastInfo& info) {
+ Element* element = info.element;
+ auto low_text_contrast_details = mojom::blink::LowTextContrastIssue::New();
+
+ StringBuilder sb;
+ auto element_id = element->getAttribute("id").LowerASCII();
+ sb.Append(element->nodeName().LowerASCII());
+ if (!element_id.IsEmpty()) {
+ sb.Append("#");
+ sb.Append(element_id);
+ }
+ for (unsigned i = 0; i < element->classList().length(); i++) {
+ sb.Append(".");
+ sb.Append(element->classList().item(i));
+ }
+
+ low_text_contrast_details->threshold_aa = info.threshold_aa;
+ low_text_contrast_details->threshold_aaa = info.threshold_aaa;
+ low_text_contrast_details->font_size = info.font_size;
+ low_text_contrast_details->font_weight = info.font_weight;
+ low_text_contrast_details->violating_node_id = DOMNodeIds::IdForNode(element);
+ low_text_contrast_details->violating_node_selector = sb.ToString();
+ low_text_contrast_details->contrast_ratio = info.contrast_ratio;
+
+ auto details = mojom::blink::InspectorIssueDetails::New();
+ details->low_text_contrast_details = std::move(low_text_contrast_details);
+
+ return mojom::blink::InspectorIssueInfo::New(
+ mojom::blink::InspectorIssueCode::kLowTextContrastIssue,
+ std::move(details));
+}
+
} // namespace
void InspectorAuditsAgent::Trace(Visitor* visitor) const {
visitor->Trace(network_agent_);
visitor->Trace(inspector_issue_storage_);
+ visitor->Trace(inspected_frames_);
InspectorBaseAgent::Trace(visitor);
}
InspectorAuditsAgent::InspectorAuditsAgent(InspectorNetworkAgent* network_agent,
- InspectorIssueStorage* storage)
+ InspectorIssueStorage* storage,
+ InspectedFrames* inspected_frames)
: inspector_issue_storage_(storage),
enabled_(&agent_state_, false),
- network_agent_(network_agent) {}
+ network_agent_(network_agent),
+ inspected_frames_(inspected_frames) {}
InspectorAuditsAgent::~InspectorAuditsAgent() = default;
@@ -120,6 +160,32 @@ protocol::Response InspectorAuditsAgent::getEncodedResponse(
return Response::Success();
}
+void InspectorAuditsAgent::CheckContrastForDocument(Document* document,
+ bool report_aaa) {
+ InspectorContrast contrast(document);
+ Vector<std::pair<Element*, mojom::blink::InspectorIssueInfoPtr>> issues;
+ unsigned max_elements = 100;
+ for (ContrastInfo info :
+ contrast.GetElementsWithContrastIssues(report_aaa, max_elements)) {
+ InspectorIssueAdded(
+ InspectorIssue::Create(CreateLowTextContrastIssue(info)));
+ }
+}
+
+Response InspectorAuditsAgent::checkContrast(protocol::Maybe<bool> report_aaa) {
+ if (!inspected_frames_)
+ return Response::ServerError("Inspected frames are not available");
+
+ auto* main_window = inspected_frames_->Root()->DomWindow();
+ if (!main_window)
+ return Response::ServerError("Document is not available");
+
+ CheckContrastForDocument(main_window->document(),
+ report_aaa.fromMaybe(false));
+
+ return Response::Success();
+}
+
Response InspectorAuditsAgent::enable() {
if (enabled_.Get()) {
return Response::Success();
@@ -192,6 +258,16 @@ blink::protocol::String InspectorIssueCodeValue(
case mojom::blink::InspectorIssueCode::kContentSecurityPolicyIssue:
return protocol::Audits::InspectorIssueCodeEnum::
ContentSecurityPolicyIssue;
+ case mojom::blink::InspectorIssueCode::kSharedArrayBufferIssue:
+ return protocol::Audits::InspectorIssueCodeEnum::SharedArrayBufferIssue;
+ case mojom::blink::InspectorIssueCode::kTrustedWebActivityIssue:
+ CHECK(false);
+ return "";
+ case mojom::blink::InspectorIssueCode::kHeavyAdIssue:
+ CHECK(false);
+ return "";
+ case mojom::blink::InspectorIssueCode::kLowTextContrastIssue:
+ return protocol::Audits::InspectorIssueCodeEnum::LowTextContrastIssue;
}
}
@@ -364,6 +440,8 @@ protocol::String BuildMixedContentResourceType(
return protocol::Audits::MixedContentResourceTypeEnum::Stylesheet;
case blink::mojom::blink::RequestContextType::SUBRESOURCE:
return protocol::Audits::MixedContentResourceTypeEnum::Resource;
+ case blink::mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE:
+ return protocol::Audits::MixedContentResourceTypeEnum::Resource;
case blink::mojom::blink::RequestContextType::TRACK:
return protocol::Audits::MixedContentResourceTypeEnum::Track;
case blink::mojom::blink::RequestContextType::UNSPECIFIED:
@@ -426,6 +504,29 @@ protocol::String BuildViolationType(
}
}
+protocol::String BuildSABIssueType(
+ blink::mojom::blink::SharedArrayBufferIssueType type) {
+ switch (type) {
+ case blink::mojom::blink::SharedArrayBufferIssueType::kTransferIssue:
+ return protocol::Audits::SharedArrayBufferIssueTypeEnum::TransferIssue;
+ case blink::mojom::blink::SharedArrayBufferIssueType::kCreationIssue:
+ return protocol::Audits::SharedArrayBufferIssueTypeEnum::CreationIssue;
+ }
+}
+
+std::unique_ptr<protocol::Audits::SourceCodeLocation> BuildAffectedLocation(
+ const blink::mojom::blink::AffectedLocationPtr& affected_location) {
+ auto protocol_affected_location =
+ protocol::Audits::SourceCodeLocation::create()
+ .setUrl(affected_location->url)
+ .setColumnNumber(affected_location->column)
+ .setLineNumber(affected_location->line)
+ .build();
+ if (!affected_location->script_id.IsEmpty())
+ protocol_affected_location->setScriptId(affected_location->script_id);
+ return protocol_affected_location;
+}
+
} // namespace
void InspectorAuditsAgent::InspectorIssueAdded(InspectorIssue* issue) {
@@ -505,19 +606,41 @@ void InspectorAuditsAgent::InspectorIssueAdded(InspectorIssue* issue) {
}
if (d->frame_ancestor)
cspDetails.setFrameAncestor(BuildAffectedFrame(d->frame_ancestor));
- if (d->source_location) {
- auto source_location = protocol::Audits::SourceCodeLocation::create()
- .setUrl(d->source_location->url)
- .setColumnNumber(d->source_location->column)
- .setLineNumber(d->source_location->line)
- .build();
- cspDetails.setSourceCodeLocation(std::move(source_location));
+ if (d->affected_location) {
+ cspDetails.setSourceCodeLocation(
+ BuildAffectedLocation(d->affected_location));
}
if (d->violating_node_id)
cspDetails.setViolatingNodeId(d->violating_node_id);
issueDetails.setContentSecurityPolicyIssueDetails(cspDetails.build());
}
+ if (issue->Details()->sab_issue_details) {
+ const auto* d = issue->Details()->sab_issue_details.get();
+ auto details =
+ protocol::Audits::SharedArrayBufferIssueDetails::create()
+ .setIsWarning(d->is_warning)
+ .setType(BuildSABIssueType(d->type))
+ .setSourceCodeLocation(BuildAffectedLocation(d->affected_location))
+ .build();
+ issueDetails.setSharedArrayBufferIssueDetails(std::move(details));
+ }
+
+ if (issue->Details()->low_text_contrast_details) {
+ const auto* d = issue->Details()->low_text_contrast_details.get();
+ auto lowContrastDetails =
+ protocol::Audits::LowTextContrastIssueDetails::create()
+ .setThresholdAA(d->threshold_aa)
+ .setThresholdAAA(d->threshold_aaa)
+ .setFontSize(d->font_size)
+ .setFontWeight(d->font_weight)
+ .setContrastRatio(d->contrast_ratio)
+ .setViolatingNodeSelector(d->violating_node_selector)
+ .setViolatingNodeId(d->violating_node_id)
+ .build();
+ issueDetails.setLowTextContrastIssueDetails(std::move(lowContrastDetails));
+ }
+
auto inspector_issue = protocol::Audits::InspectorIssue::create()
.setCode(InspectorIssueCodeValue(issue->Code()))
.setDetails(issueDetails.build())
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
index 586a3919e36..53ea3e7d3f6 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_audits_agent.h
@@ -7,7 +7,10 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_contrast.h"
#include "third_party/blink/renderer/core/inspector/protocol/Audits.h"
namespace blink {
@@ -18,7 +21,9 @@ class InspectorIssueStorage;
class CORE_EXPORT InspectorAuditsAgent final
: public InspectorBaseAgent<protocol::Audits::Metainfo> {
public:
- explicit InspectorAuditsAgent(InspectorNetworkAgent*, InspectorIssueStorage*);
+ explicit InspectorAuditsAgent(InspectorNetworkAgent*,
+ InspectorIssueStorage*,
+ InspectedFrames*);
~InspectorAuditsAgent() override;
void Trace(Visitor*) const override;
@@ -28,6 +33,7 @@ class CORE_EXPORT InspectorAuditsAgent final
// Protocol methods.
protocol::Response enable() override;
protocol::Response disable() override;
+ protocol::Response checkContrast(protocol::Maybe<bool> report_aaa) override;
void Restore() override;
@@ -42,9 +48,12 @@ class CORE_EXPORT InspectorAuditsAgent final
private:
void InnerEnable();
+ void CheckContrastForDocument(Document* document, bool report_aaa);
+
Member<InspectorIssueStorage> inspector_issue_storage_;
InspectorAgentState::Boolean enabled_;
Member<InspectorNetworkAgent> network_agent_;
+ Member<InspectedFrames> inspected_frames_;
DISALLOW_COPY_AND_ASSIGN(InspectorAuditsAgent);
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.cc
new file mode 100644
index 00000000000..308723287b0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.cc
@@ -0,0 +1,406 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_contrast.h"
+
+#include "third_party/blink/renderer/core/css/css_color_value.h"
+#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
+#include "third_party/blink/renderer/core/css/css_gradient_value.h"
+#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/html_embed_element.h"
+#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/style/style_generated_image.h"
+#include "ui/gfx/color_utils.h"
+
+namespace blink {
+
+namespace {
+
+bool NodeIsElementWithLayoutObject(Node* node) {
+ if (auto* element = DynamicTo<Element>(node)) {
+ if (element->GetLayoutObject())
+ return true;
+ }
+ return false;
+}
+
+// Blends the colors from the given gradient with the existing colors.
+void BlendWithColorsFromGradient(cssvalue::CSSGradientValue* gradient,
+ Vector<Color>& colors,
+ bool& found_non_transparent_color,
+ bool& found_opaque_color,
+ const LayoutObject& layout_object) {
+ const Document& document = layout_object.GetDocument();
+ const ComputedStyle& style = layout_object.StyleRef();
+
+ Vector<Color> stop_colors = gradient->GetStopColors(document, style);
+ if (colors.IsEmpty()) {
+ colors.AppendRange(stop_colors.begin(), stop_colors.end());
+ } else {
+ if (colors.size() > 1) {
+ // Gradient on gradient is too complicated, bail out.
+ colors.clear();
+ return;
+ }
+
+ Color existing_color = colors.front();
+ colors.clear();
+ for (auto stop_color : stop_colors) {
+ found_non_transparent_color =
+ found_non_transparent_color || (stop_color.Alpha() != 0);
+ colors.push_back(existing_color.Blend(stop_color));
+ }
+ }
+ found_opaque_color =
+ found_opaque_color || gradient->KnownToBeOpaque(document, style);
+}
+
+// Gets the colors from an image style, if one exists and it is a gradient.
+void AddColorsFromImageStyle(const ComputedStyle& style,
+ const LayoutObject& layout_object,
+ Vector<Color>& colors,
+ bool& found_opaque_color,
+ bool& found_non_transparent_color) {
+ const FillLayer& background_layers = style.BackgroundLayers();
+ if (!background_layers.AnyLayerHasImage())
+ return;
+
+ StyleImage* style_image = background_layers.GetImage();
+ // hasImage() does not always indicate that this is non-null
+ if (!style_image)
+ return;
+
+ if (!style_image->IsGeneratedImage()) {
+ // Make no assertions about the colors in non-generated images
+ colors.clear();
+ found_opaque_color = false;
+ return;
+ }
+
+ StyleGeneratedImage* gen_image = To<StyleGeneratedImage>(style_image);
+ CSSValue* image_css = gen_image->CssValue();
+ if (auto* gradient = DynamicTo<cssvalue::CSSGradientValue>(image_css)) {
+ BlendWithColorsFromGradient(gradient, colors, found_non_transparent_color,
+ found_opaque_color, layout_object);
+ }
+}
+
+PhysicalRect GetNodeRect(Node* node) {
+ PhysicalRect rect = node->BoundingBox();
+ Document* document = &node->GetDocument();
+ while (!document->IsInMainFrame()) {
+ HTMLFrameOwnerElement* owner_element = document->LocalOwner();
+ if (!owner_element)
+ break;
+ rect.offset.left += owner_element->BoundingBox().offset.left;
+ rect.offset.top += owner_element->BoundingBox().offset.top;
+ document = &owner_element->GetDocument();
+ }
+ return rect;
+}
+
+} // namespace
+
+InspectorContrast::InspectorContrast(Document* document) {
+ if (!document->IsInMainFrame()) {
+ // If document is in a frame, use the top level document to collect nodes
+ // for all frames.
+ for (HTMLFrameOwnerElement* owner_element = document->LocalOwner();
+ owner_element;
+ owner_element = owner_element->GetDocument().LocalOwner()) {
+ document = &owner_element->GetDocument();
+ }
+ }
+
+ document_ = document;
+}
+
+void InspectorContrast::CollectNodesAndBuildRTreeIfNeeded() {
+ TRACE_EVENT0("devtools.contrast",
+ "InspectorContrast::CollectNodesAndBuildRTreeIfNeeded");
+
+ if (rtree_built_)
+ return;
+
+ LocalFrame* frame = document_->GetFrame();
+ if (!frame)
+ return;
+ LayoutView* layout_view = frame->ContentLayoutObject();
+ if (!layout_view)
+ return;
+
+ if (!layout_view->GetFrameView()->UpdateLifecycleToPrePaintClean(
+ DocumentUpdateReason::kInspector)) {
+ return;
+ }
+
+ InspectorDOMAgent::CollectNodes(
+ document_, INT_MAX, true,
+ WTF::BindRepeating(&NodeIsElementWithLayoutObject), &elements_);
+ SortElementsByPaintOrder(elements_, document_);
+ rtree_.Build(
+ elements_,
+ [](const HeapVector<Member<Node>>& items, size_t index) {
+ return PixelSnappedIntRect(GetNodeRect(items[index]));
+ },
+ [](const HeapVector<Member<Node>>& items, size_t index) {
+ return items[index];
+ });
+
+ rtree_built_ = true;
+}
+
+std::vector<ContrastInfo> InspectorContrast::GetElementsWithContrastIssues(
+ bool report_aaa,
+ size_t max_elements = 0) {
+ TRACE_EVENT0("devtools.contrast",
+ "InspectorContrast::GetElementsWithContrastIssues");
+ CollectNodesAndBuildRTreeIfNeeded();
+ std::vector<ContrastInfo> result;
+ for (Node* node : elements_) {
+ auto info = GetContrast(To<Element>(node));
+ if (info.able_to_compute_contrast &&
+ ((info.contrast_ratio < info.threshold_aa) ||
+ (info.contrast_ratio < info.threshold_aaa && report_aaa))) {
+ result.push_back(std::move(info));
+ if (max_elements && result.size() >= max_elements)
+ return result;
+ }
+ }
+ return result;
+}
+
+static bool IsLargeFont(const TextInfo& text_info) {
+ String font_size_css = text_info.font_size;
+ String font_weight = text_info.font_weight;
+ // font_size_css always has 'px' appended at the end;
+ String font_size_str = font_size_css.Substring(0, font_size_css.length() - 2);
+ double font_size_px = font_size_str.ToDouble();
+ double font_size_pt = font_size_px * 72 / 96;
+ bool is_bold = font_weight == "bold" || font_weight == "bolder" ||
+ font_weight == "600" || font_weight == "700" ||
+ font_weight == "800" || font_weight == "900";
+ if (is_bold) {
+ return font_size_pt >= 14;
+ }
+ return font_size_pt >= 18;
+}
+
+ContrastInfo InspectorContrast::GetContrast(Element* top_element) {
+ TRACE_EVENT0("devtools.contrast", "InspectorContrast::GetContrast");
+
+ ContrastInfo result;
+
+ auto* text_node = DynamicTo<Text>(top_element->firstChild());
+ if (!text_node || text_node->nextSibling())
+ return result;
+
+ const String& text = text_node->data().StripWhiteSpace();
+ if (text.IsEmpty())
+ return result;
+
+ const LayoutObject* layout_object = top_element->GetLayoutObject();
+ const CSSValue* text_color_value = ComputedStyleUtils::ComputedPropertyValue(
+ CSSProperty::Get(CSSPropertyID::kColor), layout_object->StyleRef());
+ if (!text_color_value->IsColorValue())
+ return result;
+
+ float text_opacity = 1.0f;
+ Vector<Color> bgcolors = GetBackgroundColors(top_element, &text_opacity);
+ // TODO(crbug/1174511): Compute contrast only if the element has a single
+ // color background to be consistent with the current UI. In the future, we
+ // should return a range of contrast values.
+ if (bgcolors.size() != 1)
+ return result;
+
+ Color text_color =
+ static_cast<const cssvalue::CSSColorValue*>(text_color_value)->Value();
+
+ text_color = text_color.CombineWithAlpha(text_opacity);
+
+ float contrast_ratio = color_utils::GetContrastRatio(
+ SkColor(bgcolors.at(0).Blend(text_color)), SkColor(bgcolors.at(0)));
+
+ auto text_info = GetTextInfo(top_element);
+ bool is_large_font = IsLargeFont(text_info);
+
+ result.able_to_compute_contrast = true;
+ result.contrast_ratio = contrast_ratio;
+ result.threshold_aa = is_large_font ? 3.0 : 4.5;
+ result.threshold_aaa = is_large_font ? 4.5 : 7.0;
+ result.font_size = text_info.font_size;
+ result.font_weight = text_info.font_weight;
+ result.element = top_element;
+
+ return result;
+}
+
+TextInfo InspectorContrast::GetTextInfo(Element* element) {
+ TextInfo info;
+ auto* computed_style_info =
+ MakeGarbageCollected<CSSComputedStyleDeclaration>(element, true);
+ const CSSValue* font_size =
+ computed_style_info->GetPropertyCSSValue(CSSPropertyID::kFontSize);
+ if (font_size)
+ info.font_size = font_size->CssText();
+ const CSSValue* font_weight =
+ computed_style_info->GetPropertyCSSValue(CSSPropertyID::kFontWeight);
+ if (font_weight)
+ info.font_weight = font_weight->CssText();
+ return info;
+}
+
+Vector<Color> InspectorContrast::GetBackgroundColors(Element* element,
+ float* text_opacity) {
+ Vector<Color> colors;
+ // TODO: only support the single text child node here.
+ // Follow up with a larger fix post-merge.
+ auto* text_node = DynamicTo<Text>(element->firstChild());
+ if (!text_node || element->firstChild()->nextSibling()) {
+ return colors;
+ }
+
+ PhysicalRect content_bounds = GetNodeRect(text_node);
+ LocalFrameView* view = text_node->GetDocument().View();
+ if (!view)
+ return colors;
+
+ // Start with the "default" page color (typically white).
+ colors.push_back(view->BaseBackgroundColor());
+
+ GetColorsFromRect(content_bounds, text_node->GetDocument(), element, colors,
+ text_opacity);
+
+ return colors;
+}
+
+// Get the elements which overlap the given rectangle.
+std::vector<Member<Node>> InspectorContrast::ElementsFromRect(
+ const PhysicalRect& rect,
+ Document& document) {
+ CollectNodesAndBuildRTreeIfNeeded();
+ std::vector<Member<Node>> overlapping_elements;
+ rtree_.Search(PixelSnappedIntRect(rect), &overlapping_elements);
+ return overlapping_elements;
+}
+
+bool InspectorContrast::GetColorsFromRect(PhysicalRect rect,
+ Document& document,
+ Element* top_element,
+ Vector<Color>& colors,
+ float* text_opacity) {
+ std::vector<Member<Node>> elements_under_rect =
+ ElementsFromRect(rect, document);
+
+ bool found_opaque_color = false;
+ bool found_top_element = false;
+
+ *text_opacity = 1.0f;
+
+ for (auto e = elements_under_rect.begin();
+ !found_top_element && e != elements_under_rect.end(); ++e) {
+ const Element* element = To<Element>(e->Get());
+ if (element == top_element)
+ found_top_element = true;
+
+ const LayoutObject* layout_object = element->GetLayoutObject();
+
+ if (IsA<HTMLCanvasElement>(element) || IsA<HTMLEmbedElement>(element) ||
+ IsA<HTMLImageElement>(element) || IsA<HTMLObjectElement>(element) ||
+ IsA<HTMLPictureElement>(element) || element->IsSVGElement() ||
+ IsA<HTMLVideoElement>(element)) {
+ colors.clear();
+ found_opaque_color = false;
+ continue;
+ }
+
+ const ComputedStyle* style = layout_object->Style();
+ if (!style)
+ continue;
+
+ // If background elements are hidden, ignore their background colors.
+ if (element != top_element && style->Visibility() == EVisibility::kHidden)
+ continue;
+
+ Color background_color =
+ style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
+
+ // Opacity applies to the entire element so mix it with the alpha channel.
+ if (style->HasOpacity()) {
+ background_color = background_color.CombineWithAlpha(
+ background_color.Alpha() / 255 * style->Opacity());
+ // If the background element is the ancestor of the top element or is the
+ // top element, the opacity affects the text color of the top element.
+ if (element == top_element ||
+ FlatTreeTraversal::IsDescendantOf(*top_element, *element)) {
+ *text_opacity *= style->Opacity();
+ }
+ }
+
+ bool found_non_transparent_color = false;
+ if (background_color.Alpha() != 0) {
+ found_non_transparent_color = true;
+ if (background_color.HasAlpha()) {
+ if (colors.IsEmpty()) {
+ colors.push_back(background_color);
+ } else {
+ for (auto& color : colors)
+ color = color.Blend(background_color);
+ }
+ } else {
+ colors.clear();
+ colors.push_back(background_color);
+ found_opaque_color = true;
+ }
+ }
+
+ AddColorsFromImageStyle(*style, *layout_object, colors, found_opaque_color,
+ found_non_transparent_color);
+
+ bool contains = found_top_element || GetNodeRect(e->Get()).Contains(rect);
+ if (!contains && found_non_transparent_color) {
+ // Only return colors if some opaque element covers up this one.
+ colors.clear();
+ found_opaque_color = false;
+ }
+ }
+ return found_opaque_color;
+}
+
+// Sorts unsorted_elements in place, first painted go first.
+void InspectorContrast::SortElementsByPaintOrder(
+ HeapVector<Member<Node>>& unsorted_elements,
+ Document* document) {
+ std::unique_ptr<InspectorDOMSnapshotAgent::PaintOrderMap> paint_layer_tree =
+ InspectorDOMSnapshotAgent::BuildPaintLayerTree(document);
+
+ std::stable_sort(
+ unsorted_elements.begin(), unsorted_elements.end(),
+ [&paint_layer_tree = paint_layer_tree](Node* a, Node* b) {
+ const LayoutObject* a_layout = To<Element>(a)->GetLayoutObject();
+ const LayoutObject* b_layout = To<Element>(b)->GetLayoutObject();
+ int a_order = 0;
+ int b_order = 0;
+
+ auto a_item = paint_layer_tree->find(a_layout->PaintingLayer());
+ if (a_item != paint_layer_tree->end())
+ a_order = a_item->value;
+
+ auto b_item = paint_layer_tree->find(b_layout->PaintingLayer());
+ if (b_item != paint_layer_tree->end())
+ b_order = b_item->value;
+
+ return a_order < b_order;
+ });
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.h b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.h
new file mode 100644
index 00000000000..ac8db30e6b1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast.h
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_CONTRAST_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_CONTRAST_H_
+
+#include "cc/base/rtree.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+
+namespace blink {
+
+struct CORE_EXPORT ContrastInfo {
+ STACK_ALLOCATED();
+
+ public:
+ Element* element;
+ bool able_to_compute_contrast = false;
+ float threshold_aa;
+ float threshold_aaa;
+ float contrast_ratio;
+ String font_size;
+ String font_weight;
+};
+
+struct CORE_EXPORT TextInfo {
+ STACK_ALLOCATED();
+
+ public:
+ String font_size;
+ String font_weight;
+};
+
+// Calculates the contrast of elements in a document.
+class CORE_EXPORT InspectorContrast {
+ STACK_ALLOCATED();
+
+ public:
+ explicit InspectorContrast(Document*);
+ ContrastInfo GetContrast(Element*);
+ std::vector<ContrastInfo> GetElementsWithContrastIssues(bool report_aaa,
+ size_t max_elements);
+ Vector<Color> GetBackgroundColors(Element*, float* text_opacity);
+ TextInfo GetTextInfo(Element*);
+
+ private:
+ void SortElementsByPaintOrder(HeapVector<Member<Node>>&, Document*);
+ std::vector<Member<Node>> ElementsFromRect(const PhysicalRect& rect,
+ Document& document);
+ bool GetColorsFromRect(PhysicalRect rect,
+ Document& document,
+ Element* top_element,
+ Vector<Color>& colors,
+ float* text_opacity);
+ void CollectNodesAndBuildRTreeIfNeeded();
+
+ cc::RTree<Member<Node>> rtree_;
+ HeapVector<Member<Node>> elements_;
+ Document* document_;
+ bool rtree_built_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_CONTRAST_H_
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_contrast_test.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast_test.cc
new file mode 100644
index 00000000000..01b16f1ddbd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_contrast_test.cc
@@ -0,0 +1,212 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_contrast.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+
+namespace blink {
+
+class InspectorContrastTest : public testing::Test {
+ protected:
+ void SetUp() override;
+
+ Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
+
+ private:
+ std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+};
+
+void InspectorContrastTest::SetUp() {
+ dummy_page_holder_ = std::make_unique<DummyPageHolder>(IntSize(800, 600));
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColors) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="target" style="color: white; background-color: red;">
+ test
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#ff0000", colors.at(0).Serialized());
+ EXPECT_EQ(1.0f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsNoText) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <!-- No text -->
+ <div class="testCase noText">
+ <div class="layer">
+ <p id="target"></p>
+ </div>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(0u, colors.size());
+ EXPECT_EQ(1.0f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsBgOpacity) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div style="position: relative">
+ <div style="position: absolute; width: 100px; height: 100px; background-color: black; opacity: 0.1;"></div>
+ <div id="target" style="position: absolute; width: 100px; height: 100px; color: black;">test</div>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#e5e5e5", colors.at(0).Serialized());
+ EXPECT_EQ(1.0f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsBgOpacityParent) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div style="background-color: black; opacity: 0.1;">
+ <div id="target" style="color: black;">test</div>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#e5e5e5", colors.at(0).Serialized());
+ EXPECT_EQ(0.1f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsElementWithOpacity) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="target" style="opacity: 0.1; color: black;">test</div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#ffffff", colors.at(0).Serialized());
+ EXPECT_EQ(0.1f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsBgHidden) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div style="position: relative">
+ <div style="position: absolute; width: 100px; height: 100px; background-color: black; visibility: hidden;"></div>
+ <div id="target" style="position: absolute; width: 100px; height: 100px; color: black;">test</div>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#ffffff", colors.at(0).Serialized());
+ EXPECT_EQ(1.0f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetBackgroundColorsWithOpacity) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div style="background-color: rgba(0,0,0,0.75);">
+ <div style="background-color: rgba(0,0,0,0.75);">
+ <div id="target" style="color: white; background-color: rgba(0,0,0,0.75);">
+ test
+ </div>
+ </div>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ Element* target = GetDocument().getElementById("target");
+ InspectorContrast contrast(&GetDocument());
+ float fg_opacity = 1.0f;
+ Vector<Color> colors = contrast.GetBackgroundColors(target, &fg_opacity);
+ EXPECT_EQ(1u, colors.size());
+ EXPECT_EQ("#040404", colors.at(0).Serialized());
+ EXPECT_EQ(1.0f, fg_opacity);
+}
+
+TEST_F(InspectorContrastTest, GetContrast) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="target1" style="color: red; background-color: red;">
+ test
+ </div>
+ <div id="target2" style="color: hsla(200,0%,0%,0.701960784313725); background-color: white;">
+ test
+ </div>
+ <div id="target3" style="color: black; opacity: 0.1;">
+ test
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ InspectorContrast contrast(&GetDocument());
+ ContrastInfo contrast_info_1 =
+ contrast.GetContrast(GetDocument().getElementById("target1"));
+ EXPECT_EQ(true, contrast_info_1.able_to_compute_contrast);
+ EXPECT_EQ(4.5, contrast_info_1.threshold_aa);
+ EXPECT_EQ(7.0, contrast_info_1.threshold_aaa);
+ EXPECT_FLOAT_EQ(1, contrast_info_1.contrast_ratio);
+ ContrastInfo contrast_info_2 =
+ contrast.GetContrast(GetDocument().getElementById("target3"));
+ EXPECT_EQ(true, contrast_info_2.able_to_compute_contrast);
+ EXPECT_EQ(4.5, contrast_info_2.threshold_aa);
+ EXPECT_EQ(7.0, contrast_info_2.threshold_aaa);
+ EXPECT_NEAR(1.25, contrast_info_2.contrast_ratio, 0.01);
+}
+
+TEST_F(InspectorContrastTest, GetContrastEmptyNodes) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="target1" style="color: red; background-color: red;"> </div>
+ <div id="target2" style="color: red; background-color: red;"></div>
+ <div id="target3" style="color: red; background-color: red;">
+
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ InspectorContrast contrast(&GetDocument());
+ ContrastInfo contrast_info_1 =
+ contrast.GetContrast(GetDocument().getElementById("target1"));
+ EXPECT_EQ(false, contrast_info_1.able_to_compute_contrast);
+ ContrastInfo contrast_info_2 =
+ contrast.GetContrast(GetDocument().getElementById("target2"));
+ EXPECT_EQ(false, contrast_info_2.able_to_compute_contrast);
+ ContrastInfo contrast_info_3 =
+ contrast.GetContrast(GetDocument().getElementById("target3"));
+ EXPECT_EQ(false, contrast_info_3.able_to_compute_contrast);
+}
+
+TEST_F(InspectorContrastTest, GetContrastMultipleNodes) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <div id="target1" style="color: red; background-color: red;">
+ A <i>B</i>
+ </div>
+ )HTML");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ InspectorContrast contrast(&GetDocument());
+ ContrastInfo contrast_info_1 =
+ contrast.GetContrast(GetDocument().getElementById("target1"));
+ EXPECT_EQ(false, contrast_info_1.able_to_compute_contrast);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index f1332a8f0ac..dac49270e0d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -25,6 +25,8 @@
#include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
+#include <utility>
+
#include "base/macros.h"
#include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
#include "third_party/blink/renderer/core/css/css_color_value.h"
@@ -77,6 +79,7 @@
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/inspector/inspector_contrast.h"
#include "third_party/blink/renderer/core/inspector/inspector_history.h"
#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_resource_container.h"
@@ -91,7 +94,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/style_generated_image.h"
#include "third_party/blink/renderer/core/style/style_image.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
@@ -160,168 +162,6 @@ HeapVector<Member<CSSStyleRule>> FilterDuplicateRules(
return uniq_rules;
}
-// Get the elements which overlap the given rectangle.
-HeapVector<Member<Element>> ElementsFromRect(const PhysicalRect& rect,
- Document& document) {
- HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive |
- HitTestRequest::kListBased |
- HitTestRequest::kPenetratingList |
- HitTestRequest::kIgnoreClipping);
-
- HitTestLocation location(rect);
- HitTestResult result(request, location);
- document.GetFrame()->ContentLayoutObject()->HitTest(location, result);
- HeapVector<Member<Element>> elements;
- Node* previous_node = nullptr;
- for (const auto& hit_test_result_node : result.ListBasedTestResult()) {
- Node* node = hit_test_result_node.Get();
- if (!node || node->IsDocumentNode())
- continue;
- if (node->IsPseudoElement() || node->IsTextNode())
- node = node->ParentOrShadowHostNode();
- auto* element = DynamicTo<Element>(node);
- if (!node || node == previous_node || !element)
- continue;
- elements.push_back(element);
- previous_node = node;
- }
- return elements;
-}
-
-// Blends the colors from the given gradient with the existing colors.
-void BlendWithColorsFromGradient(cssvalue::CSSGradientValue* gradient,
- Vector<Color>& colors,
- bool& found_non_transparent_color,
- bool& found_opaque_color,
- const LayoutObject& layout_object) {
- const Document& document = layout_object.GetDocument();
- const ComputedStyle& style = layout_object.StyleRef();
-
- Vector<Color> stop_colors = gradient->GetStopColors(document, style);
- if (colors.IsEmpty()) {
- colors.AppendRange(stop_colors.begin(), stop_colors.end());
- } else {
- if (colors.size() > 1) {
- // Gradient on gradient is too complicated, bail out.
- colors.clear();
- return;
- }
-
- Color existing_color = colors.front();
- colors.clear();
- for (auto stop_color : stop_colors) {
- found_non_transparent_color =
- found_non_transparent_color || (stop_color.Alpha() != 0);
- colors.push_back(existing_color.Blend(stop_color));
- }
- }
- found_opaque_color =
- found_opaque_color || gradient->KnownToBeOpaque(document, style);
-}
-
-// Gets the colors from an image style, if one exists and it is a gradient.
-void AddColorsFromImageStyle(const ComputedStyle& style,
- Vector<Color>& colors,
- bool& found_opaque_color,
- bool& found_non_transparent_color,
- const LayoutObject& layout_object) {
- const FillLayer& background_layers = style.BackgroundLayers();
- if (!background_layers.AnyLayerHasImage())
- return;
-
- StyleImage* style_image = background_layers.GetImage();
- // hasImage() does not always indicate that this is non-null
- if (!style_image)
- return;
-
- if (!style_image->IsGeneratedImage()) {
- // Make no assertions about the colors in non-generated images
- colors.clear();
- found_opaque_color = false;
- return;
- }
-
- StyleGeneratedImage* gen_image = To<StyleGeneratedImage>(style_image);
- CSSValue* image_css = gen_image->CssValue();
- if (auto* gradient = DynamicTo<cssvalue::CSSGradientValue>(image_css)) {
- BlendWithColorsFromGradient(gradient, colors, found_non_transparent_color,
- found_opaque_color, layout_object);
- }
-}
-
-// Get the background colors behind the given rect in the given document, by
-// walking up all the elements returned by a hit test (but not going beyond
-// |topElement|) covering the area of the rect, and blending their background
-// colors.
-bool GetColorsFromRect(PhysicalRect rect,
- Document& document,
- Element* top_element,
- Vector<Color>& colors) {
- HeapVector<Member<Element>> elements_under_rect =
- ElementsFromRect(rect, document);
-
- bool found_opaque_color = false;
- bool found_top_element = false;
-
- for (auto e = elements_under_rect.rbegin();
- !found_top_element && e != elements_under_rect.rend(); ++e) {
- const Element* element = *e;
- if (element == top_element)
- found_top_element = true;
-
- const LayoutObject* layout_object = element->GetLayoutObject();
- if (!layout_object)
- continue;
-
- if (IsA<HTMLCanvasElement>(element) || IsA<HTMLEmbedElement>(element) ||
- IsA<HTMLImageElement>(element) || IsA<HTMLObjectElement>(element) ||
- IsA<HTMLPictureElement>(element) || element->IsSVGElement() ||
- IsA<HTMLVideoElement>(element)) {
- colors.clear();
- found_opaque_color = false;
- continue;
- }
-
- const ComputedStyle* style = layout_object->Style();
- if (!style)
- continue;
-
- Color background_color =
- style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
- bool found_non_transparent_color = false;
- if (background_color.Alpha() != 0) {
- found_non_transparent_color = true;
- if (colors.IsEmpty()) {
- if (!background_color.HasAlpha())
- found_opaque_color = true;
- colors.push_back(background_color);
- } else {
- if (!background_color.HasAlpha()) {
- colors.clear();
- colors.push_back(background_color);
- found_opaque_color = true;
- } else {
- for (wtf_size_t i = 0; i < colors.size(); i++)
- colors[i] = colors[i].Blend(background_color);
- found_opaque_color =
- found_opaque_color || background_color.HasAlpha();
- }
- }
- }
-
- AddColorsFromImageStyle(*style, colors, found_opaque_color,
- found_non_transparent_color, *layout_object);
-
- bool contains = found_top_element || element->BoundingBox().Contains(rect);
- if (!contains && found_non_transparent_color) {
- // Only return colors if some opaque element covers up this one.
- colors.clear();
- found_opaque_color = false;
- }
- }
- return found_opaque_color;
-}
-
void CollectPlatformFontsFromRunFontDataList(
const Vector<ShapeResult::RunFontData>& run_font_data_list,
HashCountedSet<std::pair<int, String>>* font_stats) {
@@ -349,7 +189,8 @@ enum ForcePseudoClassFlags {
kPseudoActive = 1 << 2,
kPseudoVisited = 1 << 3,
kPseudoFocusWithin = 1 << 4,
- kPseudoFocusVisible = 1 << 5
+ kPseudoFocusVisible = 1 << 5,
+ kPseudoTarget = 1 << 6,
};
static unsigned ComputePseudoClassMask(
@@ -359,6 +200,7 @@ static unsigned ComputePseudoClassMask(
DEFINE_STATIC_LOCAL(String, focus, ("focus"));
DEFINE_STATIC_LOCAL(String, focusVisible, ("focus-visible"));
DEFINE_STATIC_LOCAL(String, focusWithin, ("focus-within"));
+ DEFINE_STATIC_LOCAL(String, target, ("target"));
DEFINE_STATIC_LOCAL(String, visited, ("visited"));
if (!pseudo_class_array || pseudo_class_array->empty())
return kPseudoNone;
@@ -375,6 +217,8 @@ static unsigned ComputePseudoClassMask(
result |= kPseudoFocusVisible;
else if (pseudo_class == focusWithin)
result |= kPseudoFocusWithin;
+ else if (pseudo_class == target)
+ result |= kPseudoTarget;
else if (pseudo_class == visited)
result |= kPseudoVisited;
}
@@ -732,7 +576,7 @@ void InspectorCSSAgent::enable(std::unique_ptr<EnableCallback> prp_callback) {
resource_content_loader_->EnsureResourcesContentLoaded(
resource_content_loader_client_id_,
WTF::Bind(&InspectorCSSAgent::ResourceContentLoaded, WrapPersistent(this),
- WTF::Passed(std::move(prp_callback))));
+ std::move(prp_callback)));
}
void InspectorCSSAgent::ResourceContentLoaded(
@@ -960,6 +804,9 @@ void InspectorCSSAgent::ForcePseudoState(Element* element,
case CSSSelector::kPseudoHover:
force = forced_pseudo_state & kPseudoHover;
break;
+ case CSSSelector::kPseudoTarget:
+ force = forced_pseudo_state & kPseudoTarget;
+ break;
case CSSSelector::kPseudoVisited:
force = forced_pseudo_state & kPseudoVisited;
break;
@@ -1201,7 +1048,7 @@ Response InspectorCSSAgent::getComputedStyleForNode(
protocol::Array<protocol::CSS::CSSComputedStyleProperty>>();
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property_class =
- CSSProperty::Get(resolveCSSPropertyID(property_id));
+ CSSProperty::Get(ResolveCSSPropertyID(property_id));
if (!property_class.IsWebExposed(node->GetExecutionContext()) ||
property_class.IsShorthand() || !property_class.IsProperty())
continue;
@@ -2465,7 +2312,9 @@ Response InspectorCSSAgent::getBackgroundColors(
Vector<Color> bgcolors;
String fs;
String fw;
- InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &fs, &fw);
+ float text_opacity = 1.0f;
+ InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &fs, &fw,
+ &text_opacity);
if (bgcolors.size()) {
*background_colors = std::make_unique<protocol::Array<String>>();
@@ -2485,51 +2334,13 @@ Response InspectorCSSAgent::getBackgroundColors(
void InspectorCSSAgent::GetBackgroundColors(Element* element,
Vector<Color>* colors,
String* computed_font_size,
- String* computed_font_weight) {
- // TODO: only support the single text child node here.
- // Follow up with a larger fix post-merge.
- auto* text_node = DynamicTo<Text>(element->firstChild());
- if (!text_node || element->firstChild()->nextSibling()) {
- return;
- }
-
- PhysicalRect content_bounds = text_node->BoundingBox();
- LocalFrameView* view = text_node->GetDocument().View();
- if (!view)
- return;
-
- Document& document = text_node->GetDocument();
- bool is_main_frame = document.IsInMainFrame();
- bool found_opaque_color = false;
- if (is_main_frame) {
- // Start with the "default" page color (typically white).
- Color base_background_color = view->BaseBackgroundColor();
- colors->push_back(view->BaseBackgroundColor());
- found_opaque_color = !base_background_color.HasAlpha();
- }
-
- found_opaque_color = GetColorsFromRect(
- content_bounds, text_node->GetDocument(), element, *colors);
-
- if (!found_opaque_color && !is_main_frame) {
- for (HTMLFrameOwnerElement* owner_element = document.LocalOwner();
- !found_opaque_color && owner_element;
- owner_element = owner_element->GetDocument().LocalOwner()) {
- found_opaque_color = GetColorsFromRect(
- content_bounds, owner_element->GetDocument(), nullptr, *colors);
- }
- }
-
- auto* computed_style_info =
- MakeGarbageCollected<CSSComputedStyleDeclaration>(element, true);
- const CSSValue* font_size =
- computed_style_info->GetPropertyCSSValue(CSSPropertyID::kFontSize);
- if (font_size)
- *computed_font_size = font_size->CssText();
- const CSSValue* font_weight =
- computed_style_info->GetPropertyCSSValue(CSSPropertyID::kFontWeight);
- if (font_weight)
- *computed_font_weight = font_weight->CssText();
+ String* computed_font_weight,
+ float* text_opacity) {
+ InspectorContrast contrast(&element->GetDocument());
+ *colors = contrast.GetBackgroundColors(element, text_opacity);
+ auto text_info = contrast.GetTextInfo(element);
+ *computed_font_size = text_info.font_size;
+ *computed_font_weight = text_info.font_weight;
}
void InspectorCSSAgent::SetCoverageEnabled(bool enabled) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
index 14eeeb7caa7..adbfc092abf 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_css_agent.h
@@ -105,7 +105,8 @@ class CORE_EXPORT InspectorCSSAgent final
static void GetBackgroundColors(Element* element,
Vector<Color>* background_colors,
String* computed_font_size,
- String* computed_font_weight);
+ String* computed_font_weight,
+ float* text_opacity);
InspectorCSSAgent(InspectorDOMAgent*,
InspectedFrames*,
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index 8e805798fd4..b8d77a1a6f3 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -50,10 +50,8 @@
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/dom/text.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/dom/xml_document.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
#include "third_party/blink/renderer/core/frame/frame.h"
@@ -116,7 +114,7 @@ class InspectorRevalidateDOMTask final
private:
Member<InspectorDOMAgent> dom_agent_;
- TaskRunnerTimer<InspectorRevalidateDOMTask> timer_;
+ HeapTaskRunnerTimer<InspectorRevalidateDOMTask> timer_;
HeapHashSet<Member<Element>> style_attr_invalidated_elements_;
};
@@ -148,6 +146,7 @@ void InspectorRevalidateDOMTask::OnTimer(TimerBase*) {
void InspectorRevalidateDOMTask::Trace(Visitor* visitor) const {
visitor->Trace(dom_agent_);
visitor->Trace(style_attr_invalidated_elements_);
+ visitor->Trace(timer_);
}
Response InspectorDOMAgent::ToResponse(ExceptionState& exception_state) {
@@ -182,6 +181,10 @@ protocol::DOM::PseudoType InspectorDOMAgent::ProtocolPseudoElementType(
return protocol::DOM::PseudoTypeEnum::Selection;
case kPseudoIdTargetText:
return protocol::DOM::PseudoTypeEnum::TargetText;
+ case kPseudoIdSpellingError:
+ return protocol::DOM::PseudoTypeEnum::SpellingError;
+ case kPseudoIdGrammarError:
+ return protocol::DOM::PseudoTypeEnum::GrammarError;
case kPseudoIdFirstLineInherited:
return protocol::DOM::PseudoTypeEnum::FirstLineInherited;
case kPseudoIdScrollbar:
@@ -1540,7 +1543,6 @@ protocol::DOM::ShadowRootType InspectorDOMAgent::GetShadowRootType(
switch (shadow_root->GetType()) {
case ShadowRootType::kUserAgent:
return protocol::DOM::ShadowRootTypeEnum::UserAgent;
- case ShadowRootType::V0:
case ShadowRootType::kOpen:
return protocol::DOM::ShadowRootTypeEnum::Open;
case ShadowRootType::kClosed:
@@ -1653,11 +1655,6 @@ std::unique_ptr<protocol::DOM::Node> InspectorDOMAgent::BuildObjectForNode(
force_push_children = true;
}
- if (auto* insertion_point = DynamicTo<V0InsertionPoint>(element)) {
- value->setDistributedNodes(
- BuildArrayForDistributedNodes(insertion_point));
- force_push_children = true;
- }
if (auto* slot = DynamicTo<HTMLSlotElement>(*element)) {
if (node->IsInShadowTree()) {
value->setDistributedNodes(BuildDistributedNodesForSlot(slot));
@@ -1779,28 +1776,6 @@ InspectorDOMAgent::BuildArrayForPseudoElements(Element* element,
}
std::unique_ptr<protocol::Array<protocol::DOM::BackendNode>>
-InspectorDOMAgent::BuildArrayForDistributedNodes(
- V0InsertionPoint* insertion_point) {
- auto distributed_nodes =
- std::make_unique<protocol::Array<protocol::DOM::BackendNode>>();
- for (wtf_size_t i = 0; i < insertion_point->DistributedNodesSize(); ++i) {
- Node* distributed_node = insertion_point->DistributedNodeAt(i);
- if (IsWhitespace(distributed_node))
- continue;
-
- std::unique_ptr<protocol::DOM::BackendNode> backend_node =
- protocol::DOM::BackendNode::create()
- .setNodeType(distributed_node->getNodeType())
- .setNodeName(distributed_node->nodeName())
- .setBackendNodeId(
- IdentifiersFactory::IntIdForNode(distributed_node))
- .build();
- distributed_nodes->emplace_back(std::move(backend_node));
- }
- return distributed_nodes;
-}
-
-std::unique_ptr<protocol::Array<protocol::DOM::BackendNode>>
InspectorDOMAgent::BuildDistributedNodesForSlot(HTMLSlotElement* slot_element) {
// TODO(hayato): In Shadow DOM v1, the concept of distributed nodes should
// not be used anymore. DistributedNodes should be replaced with
@@ -2123,25 +2098,6 @@ void InspectorDOMAgent::WillPopShadowRoot(Element* host, ShadowRoot* root) {
GetFrontend()->shadowRootPopped(host_id, root_id);
}
-void InspectorDOMAgent::DidPerformElementShadowDistribution(
- Element* shadow_host) {
- int shadow_host_id = document_node_to_id_map_->at(shadow_host);
- if (!shadow_host_id)
- return;
-
- if (ShadowRoot* root = shadow_host->GetShadowRoot()) {
- const HeapVector<Member<V0InsertionPoint>>& insertion_points =
- root->V0().DescendantInsertionPoints();
- for (const auto& it : insertion_points) {
- V0InsertionPoint* insertion_point = it.Get();
- int insertion_point_id = document_node_to_id_map_->at(insertion_point);
- if (insertion_point_id)
- GetFrontend()->distributedNodesUpdated(
- insertion_point_id, BuildArrayForDistributedNodes(insertion_point));
- }
- }
-}
-
void InspectorDOMAgent::DidPerformSlotDistribution(
HTMLSlotElement* slot_element) {
int insertion_point_id = document_node_to_id_map_->at(slot_element);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
index 3e951470ee0..47356db13d3 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
@@ -60,7 +60,6 @@ class FloatQuad;
class HTMLFrameOwnerElement;
class HTMLPortalElement;
class HTMLSlotElement;
-class V0InsertionPoint;
class InspectedFrames;
class InspectorHistory;
class Node;
@@ -272,7 +271,6 @@ class CORE_EXPORT InspectorDOMAgent final
void DidInvalidateStyleAttr(Node*);
void DidPushShadowRoot(Element* host, ShadowRoot*);
void WillPopShadowRoot(Element* host, ShadowRoot*);
- void DidPerformElementShadowDistribution(Element*);
void DidPerformSlotDistribution(HTMLSlotElement*);
void FrameDocumentUpdated(LocalFrame*);
void FrameOwnerContentUpdated(LocalFrame*, HTMLFrameOwnerElement*);
@@ -364,8 +362,6 @@ class CORE_EXPORT InspectorDOMAgent final
std::unique_ptr<protocol::Array<protocol::DOM::Node>>
BuildArrayForPseudoElements(Element*, NodeToIdMap* nodes_map);
std::unique_ptr<protocol::Array<protocol::DOM::BackendNode>>
- BuildArrayForDistributedNodes(V0InsertionPoint*);
- std::unique_ptr<protocol::Array<protocol::DOM::BackendNode>>
BuildDistributedNodesForSlot(HTMLSlotElement*);
Node* NodeForPath(const String& path);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
index 087618b75d8..20c93e0dddb 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
#include "third_party/blink/renderer/core/inspector/resolve_node.h"
@@ -45,7 +46,6 @@
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/inspector_protocol/crdtp/json.h"
-
using crdtp::SpanFrom;
using crdtp::json::ConvertCBORToJSON;
@@ -209,7 +209,8 @@ InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent(
enabled_(&agent_state_, /*default_value=*/false),
pause_on_all_xhrs_(&agent_state_, /*default_value=*/false),
xhr_breakpoints_(&agent_state_, /*default_value=*/false),
- event_listener_breakpoints_(&agent_state_, /*default_value*/ false) {}
+ event_listener_breakpoints_(&agent_state_, /*default_value*/ false),
+ csp_violation_breakpoints_(&agent_state_, /*default_value*/ false) {}
InspectorDOMDebuggerAgent::~InspectorDOMDebuggerAgent() = default;
@@ -340,7 +341,39 @@ static String DomTypeName(int type) {
default:
break;
}
- return "";
+ return WTF::g_empty_string;
+}
+
+bool IsValidViolationType(const String& violationString) {
+ if (violationString ==
+ protocol::DOMDebugger::CSPViolationTypeEnum::TrustedtypeSinkViolation) {
+ return true;
+ }
+ if (violationString ==
+ protocol::DOMDebugger::CSPViolationTypeEnum::TrustedtypePolicyViolation) {
+ return true;
+ }
+ return false;
+}
+
+Response InspectorDOMDebuggerAgent::setBreakOnCSPViolation(
+ std::unique_ptr<protocol::Array<String>> violationTypes) {
+ csp_violation_breakpoints_.Clear();
+ if (violationTypes->empty()) {
+ DidRemoveBreakpoint();
+ return Response::Success();
+ }
+ for (const auto& violationString : *violationTypes) {
+ if (IsValidViolationType(violationString)) {
+ csp_violation_breakpoints_.Set(violationString, true);
+ } else {
+ csp_violation_breakpoints_.Clear();
+ DidRemoveBreakpoint();
+ return Response::InvalidParams("Invalid violation type");
+ }
+ }
+ DidAddBreakpoint();
+ return Response::Success();
}
Response InspectorDOMDebuggerAgent::setDOMBreakpoint(
@@ -707,7 +740,7 @@ Response InspectorDOMDebuggerAgent::removeXHRBreakpoint(const String& url) {
// Returns the breakpoint url if a match is found, or WTF::String().
String InspectorDOMDebuggerAgent::MatchXHRBreakpoints(const String& url) const {
if (pause_on_all_xhrs_.Get())
- return "";
+ return WTF::g_empty_string;
for (const WTF::String& breakpoint : xhr_breakpoints_.Keys()) {
if (url.Contains(breakpoint))
return breakpoint;
@@ -748,6 +781,8 @@ void InspectorDOMDebuggerAgent::DidAddBreakpoint() {
void InspectorDOMDebuggerAgent::DidRemoveBreakpoint() {
if (!dom_breakpoints_.IsEmpty())
return;
+ if (!csp_violation_breakpoints_.IsEmpty())
+ return;
if (!event_listener_breakpoints_.IsEmpty())
return;
if (!xhr_breakpoints_.IsEmpty())
@@ -793,4 +828,39 @@ void InspectorDOMDebuggerAgent::DidSuspendAudioContext() {
true);
}
+String ViolationTypeToString(
+ const ContentSecurityPolicy::ContentSecurityPolicyViolationType type) {
+ switch (type) {
+ case ContentSecurityPolicy::ContentSecurityPolicyViolationType::
+ kTrustedTypesSinkViolation:
+ return protocol::DOMDebugger::CSPViolationTypeEnum::
+ TrustedtypeSinkViolation;
+ case ContentSecurityPolicy::ContentSecurityPolicyViolationType::
+ kTrustedTypesPolicyViolation:
+ return protocol::DOMDebugger::CSPViolationTypeEnum::
+ TrustedtypePolicyViolation;
+ default:
+ return WTF::g_empty_string;
+ }
+}
+
+void InspectorDOMDebuggerAgent::OnContentSecurityPolicyViolation(
+ const ContentSecurityPolicy::ContentSecurityPolicyViolationType
+ violationType) {
+ auto violationString = ViolationTypeToString(violationType);
+ if (!csp_violation_breakpoints_.Get(violationString))
+ return;
+
+ std::unique_ptr<protocol::DictionaryValue> event_data =
+ protocol::DictionaryValue::create();
+ event_data->setString("violationType", violationString);
+ std::vector<uint8_t> json;
+ ConvertCBORToJSON(SpanFrom(event_data->Serialize()), &json);
+ v8_inspector::StringView json_view(json.data(), json.size());
+ auto listener = ToV8InspectorStringView(
+ v8_inspector::protocol::Debugger::API::Paused::ReasonEnum::CSPViolation);
+
+ v8_session_->breakProgram(listener, json_view);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h
index 7ea3296e52e..c822806948a 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h
@@ -34,6 +34,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_info.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/DOMDebugger.h"
@@ -69,6 +70,8 @@ class CORE_EXPORT InspectorDOMDebuggerAgent final
~InspectorDOMDebuggerAgent() override;
void Trace(Visitor*) const override;
+ protocol::Response setBreakOnCSPViolation(
+ std::unique_ptr<protocol::Array<String>> violationTypes) override;
// DOMDebugger API for frontend
protocol::Response setDOMBreakpoint(int node_id, const String& type) override;
protocol::Response removeDOMBreakpoint(int node_id,
@@ -114,6 +117,8 @@ class CORE_EXPORT InspectorDOMDebuggerAgent final
void DidCloseAudioContext();
void DidResumeAudioContext();
void DidSuspendAudioContext();
+ void OnContentSecurityPolicyViolation(
+ const ContentSecurityPolicy::ContentSecurityPolicyViolationType);
protocol::Response disable() override;
void Restore() override;
@@ -177,6 +182,7 @@ class CORE_EXPORT InspectorDOMDebuggerAgent final
InspectorAgentState::Boolean pause_on_all_xhrs_;
InspectorAgentState::BooleanMap xhr_breakpoints_;
InspectorAgentState::BooleanMap event_listener_breakpoints_;
+ InspectorAgentState::BooleanMap csp_violation_breakpoints_;
DISALLOW_COPY_AND_ASSIGN(InspectorDOMDebuggerAgent);
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
index 4f9894ede77..fd5b8da5a0e 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
@@ -132,7 +132,7 @@ class DOMTreeIterator {
const bool skip_shadow_root =
current_->GetShadowRoot() && current_->GetShadowRoot()->IsUserAgent();
if (Node* first_child = skip_shadow_root
- ? FirstFlatTreeSibling(current_->firstChild())
+ ? current_->firstChild()
: FlatTreeTraversal::FirstChild(*current_)) {
current_ = first_child;
path_to_current_node_.push_back(next_node_id);
@@ -144,7 +144,7 @@ class DOMTreeIterator {
current_->ParentElementShadowRoot() &&
current_->ParentElementShadowRoot()->IsUserAgent();
if (Node* node = in_ua_shadow_tree
- ? FirstFlatTreeSibling(current_->nextSibling())
+ ? current_->nextSibling()
: FlatTreeTraversal::NextSibling(*current_)) {
path_to_current_node_.back() = next_node_id;
current_ = node;
@@ -166,11 +166,6 @@ class DOMTreeIterator {
}
private:
- static Node* FirstFlatTreeSibling(Node* node) {
- while (node && !node->CanParticipateInFlatTree())
- node = node->nextSibling();
- return node;
- }
Node* current_;
WTF::Vector<int> path_to_current_node_;
};
@@ -297,10 +292,10 @@ protocol::Response InspectorDOMSnapshotAgent::captureSnapshot(
// Resolve all property names to CSSProperty references.
for (String& property_name : *computed_styles) {
const CSSPropertyID id =
- unresolvedCSSPropertyID(main_window, property_name);
+ UnresolvedCSSPropertyID(main_window, property_name);
if (id == CSSPropertyID::kInvalid || id == CSSPropertyID::kVariable)
return Response::InvalidParams("invalid CSS property");
- const auto& property = CSSProperty::Get(resolveCSSPropertyID(id));
+ const auto& property = CSSProperty::Get(ResolveCSSPropertyID(id));
css_property_filter_->push_back(&property);
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
index 1d61e2dbaa5..483c7aa64c1 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -48,8 +48,9 @@ InspectorEmulationAgent::InspectorEmulationAgent(
navigator_platform_override_(&agent_state_,
/*default_value=*/WTF::String()),
user_agent_override_(&agent_state_, /*default_value=*/WTF::String()),
- serialized_ua_metadata_override_(&agent_state_,
- /*default_value=*/WTF::String()),
+ serialized_ua_metadata_override_(
+ &agent_state_,
+ /*default_value=*/std::vector<uint8_t>()),
accept_language_override_(&agent_state_,
/*default_value=*/WTF::String()),
locale_override_(&agent_state_, /*default_value=*/WTF::String()),
@@ -74,14 +75,15 @@ void InspectorEmulationAgent::Restore() {
// Since serialized_ua_metadata_override_ can't directly be converted back
// to appropriate protocol message, we initially pass null and decode it
// directly.
- WTF::String save_serialized_ua_metadata_override =
+ std::vector<uint8_t> save_serialized_ua_metadata_override =
serialized_ua_metadata_override_.Get();
setUserAgentOverride(
user_agent_override_.Get(), accept_language_override_.Get(),
navigator_platform_override_.Get(),
protocol::Maybe<protocol::Emulation::UserAgentMetadata>());
- ua_metadata_override_ = blink::UserAgentMetadata::Demarshal(
- save_serialized_ua_metadata_override.Latin1());
+ ua_metadata_override_ = blink::UserAgentMetadata::Demarshal(std::string(
+ reinterpret_cast<char*>(save_serialized_ua_metadata_override.data()),
+ save_serialized_ua_metadata_override.size()));
serialized_ua_metadata_override_.Set(save_serialized_ua_metadata_override);
if (!locale_override_.Get().IsEmpty())
@@ -452,7 +454,7 @@ void InspectorEmulationAgent::FrameStartedLoading(LocalFrame*) {
AtomicString InspectorEmulationAgent::OverrideAcceptImageHeader(
const HashSet<String>* disabled_image_types) {
- String header(ImageAcceptHeader());
+ String header(kImageAcceptHeader);
for (String type : *disabled_image_types) {
// The header string is expected to be like
// `image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8` and is
@@ -587,24 +589,37 @@ Response InspectorEmulationAgent::setUserAgentOverride(
}
if (ua_metadata_override.isJust()) {
+ blink::UserAgentMetadata default_ua_metadata =
+ Platform::Current()->UserAgentMetadata();
+
if (user_agent.IsEmpty()) {
ua_metadata_override_ = base::nullopt;
- serialized_ua_metadata_override_.Set(WTF::String());
+ serialized_ua_metadata_override_.Set(std::vector<uint8_t>());
return Response::InvalidParams(
"Can't specify UserAgentMetadata but no UA string");
}
std::unique_ptr<protocol::Emulation::UserAgentMetadata> ua_metadata =
ua_metadata_override.takeJust();
ua_metadata_override_.emplace();
- if (ua_metadata->getBrands()) {
- for (const auto& bv : *ua_metadata->getBrands()) {
+ if (ua_metadata->hasBrands()) {
+ for (const auto& bv : *ua_metadata->getBrands(nullptr)) {
blink::UserAgentBrandVersion out_bv;
out_bv.brand = bv->getBrand().Ascii();
out_bv.major_version = bv->getVersion().Ascii();
ua_metadata_override_->brand_version_list.push_back(std::move(out_bv));
}
+ } else {
+ ua_metadata_override_->brand_version_list =
+ std::move(default_ua_metadata.brand_version_list);
+ }
+
+ if (ua_metadata->hasFullVersion()) {
+ ua_metadata_override_->full_version =
+ ua_metadata->getFullVersion("").Ascii();
+ } else {
+ ua_metadata_override_->full_version =
+ std::move(default_ua_metadata.full_version);
}
- ua_metadata_override_->full_version = ua_metadata->getFullVersion().Ascii();
ua_metadata_override_->platform = ua_metadata->getPlatform().Ascii();
ua_metadata_override_->platform_version =
ua_metadata->getPlatformVersion().Ascii();
@@ -619,8 +634,10 @@ Response InspectorEmulationAgent::setUserAgentOverride(
std::string marshalled =
blink::UserAgentMetadata::Marshal(ua_metadata_override_)
.value_or(std::string());
- serialized_ua_metadata_override_.Set(
- WTF::String(marshalled.data(), marshalled.size()));
+ std::vector<uint8_t> marshalled_as_bytes;
+ marshalled_as_bytes.insert(marshalled_as_bytes.end(), marshalled.begin(),
+ marshalled.end());
+ serialized_ua_metadata_override_.Set(std::move(marshalled_as_bytes));
return Response::Success();
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h
index 55d459346cf..0c18731ee59 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h
@@ -145,7 +145,7 @@ class CORE_EXPORT InspectorEmulationAgent final
InspectorAgentState::String emulated_vision_deficiency_;
InspectorAgentState::String navigator_platform_override_;
InspectorAgentState::String user_agent_override_;
- InspectorAgentState::String serialized_ua_metadata_override_;
+ InspectorAgentState::Bytes serialized_ua_metadata_override_;
base::Optional<blink::UserAgentMetadata> ua_metadata_override_;
InspectorAgentState::String accept_language_override_;
InspectorAgentState::String locale_override_;
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent_test.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent_test.cc
index fe7f81c0aba..d65aa6e1e4c 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent_test.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_emulation_agent_test.cc
@@ -6,44 +6,39 @@
#include "media/media_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
namespace blink {
class InspectorEmulationAgentTest : public testing::Test {};
TEST_F(InspectorEmulationAgentTest, ModifiesAcceptHeader) {
- String expected_default =
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+ const char kExpectedDefault[] =
+ "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
+ const char kExpectedNoWebp[] =
+ "image/avif,image/apng,image/svg+xml,image/*,*/*;q=0.8";
+#else
+ const char kExpectedDefault[] =
"image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- String expected_no_webp = "image/apng,image/svg+xml,image/*,*/*;q=0.8";
- String expected_no_webp_and_avif =
+ const char kExpectedNoWebp[] = "image/apng,image/svg+xml,image/*,*/*;q=0.8";
+#endif
+ const char kExpectedNoWebpAndAvif[] =
"image/apng,image/svg+xml,image/*,*/*;q=0.8";
- String expected_no_avif =
+ const char kExpectedNoAvif[] =
"image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
-#if BUILDFLAG(ENABLE_AV1_DECODER)
- bool avif_enabled = base::FeatureList::IsEnabled(features::kAVIF);
- if (avif_enabled) {
- expected_default =
- "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- expected_no_webp = "image/avif,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- expected_no_webp_and_avif = "image/apng,image/svg+xml,image/*,*/*;q=0.8";
- expected_no_avif = "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- }
-#endif
-
HashSet<String> disabled_types;
EXPECT_EQ(InspectorEmulationAgent::OverrideAcceptImageHeader(&disabled_types),
- expected_default);
+ kExpectedDefault);
disabled_types.insert("image/webp");
EXPECT_EQ(InspectorEmulationAgent::OverrideAcceptImageHeader(&disabled_types),
- expected_no_webp);
+ kExpectedNoWebp);
disabled_types.insert("image/avif");
EXPECT_EQ(InspectorEmulationAgent::OverrideAcceptImageHeader(&disabled_types),
- expected_no_webp_and_avif);
+ kExpectedNoWebpAndAvif);
disabled_types.erase("image/webp");
EXPECT_EQ(InspectorEmulationAgent::OverrideAcceptImageHeader(&disabled_types),
- expected_no_avif);
+ kExpectedNoAvif);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index b3da4b8d539..d67f74c3071 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
#include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
+#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_value.h"
@@ -19,6 +20,8 @@
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/inspector/dom_traversal_utils.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
+#include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
+#include "third_party/blink/renderer/core/inspector/protocol/Overlay.h"
#include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
@@ -27,6 +30,7 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -229,9 +233,26 @@ String ToHEXA(const Color& color) {
color.Blue(), color.Alpha());
}
+namespace ContrastAlgorithmEnum = protocol::Overlay::ContrastAlgorithmEnum;
+
+String ContrastAlgorithmToString(const ContrastAlgorithm& contrast_algorithm) {
+ // It reuses the protocol string constants to avoid duplicating the string
+ // values. These string values are sent to the overlay code that is expected
+ // to handle them properly.
+ switch (contrast_algorithm) {
+ case ContrastAlgorithm::AA:
+ return ContrastAlgorithmEnum::Aa;
+ case ContrastAlgorithm::AAA:
+ return ContrastAlgorithmEnum::Aaa;
+ case ContrastAlgorithm::APCA:
+ return ContrastAlgorithmEnum::Apca;
+ }
+}
+
void AppendStyleInfo(Node* node,
protocol::DictionaryValue* element_info,
- const InspectorHighlightContrastInfo& node_contrast) {
+ const InspectorHighlightContrastInfo& node_contrast,
+ const ContrastAlgorithm& contrast_algorithm) {
std::unique_ptr<protocol::DictionaryValue> computed_style =
protocol::DictionaryValue::create();
CSSComputedStyleDeclaration* style =
@@ -276,6 +297,9 @@ void AppendStyleInfo(Node* node,
contrast->setString("fontWeight", node_contrast.font_weight);
contrast->setString("backgroundColor",
ToHEXA(node_contrast.background_color));
+ contrast->setString("contrastAlgorithm",
+ ContrastAlgorithmToString(contrast_algorithm));
+ contrast->setDouble("textOpacity", node_contrast.text_opacity);
element_info->setValue("contrast", std::move(contrast));
}
}
@@ -324,9 +348,12 @@ std::unique_ptr<protocol::DictionaryValue> BuildElementInfo(Element* element) {
// layoutObject the getBoundingClientRect() data in the tooltip
// to be consistent with the rulers (see http://crbug.com/262338).
- DOMRect* bounding_box = element->getBoundingClientRect();
- element_info->setString("nodeWidth", String::Number(bounding_box->width()));
- element_info->setString("nodeHeight", String::Number(bounding_box->height()));
+
+ DCHECK(element->GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kLayoutClean);
+ FloatRect bounding_box = element->GetBoundingClientRectNoLifecycleUpdate();
+ element_info->setString("nodeWidth", String::Number(bounding_box.Width()));
+ element_info->setString("nodeHeight", String::Number(bounding_box.Height()));
element_info->setBoolean("isKeyboardFocusable",
element->IsKeyboardFocusable());
@@ -354,17 +381,35 @@ std::unique_ptr<protocol::DictionaryValue> BuildTextNodeInfo(Text* text_node) {
}
void AppendLineStyleConfig(
- const std::unique_ptr<LineStyle>& line_style,
+ const base::Optional<LineStyle>& line_style,
std::unique_ptr<protocol::DictionaryValue>& parent_config,
String line_name) {
- if (line_style && line_style->color != Color::kTransparent) {
- std::unique_ptr<protocol::DictionaryValue> config =
- protocol::DictionaryValue::create();
- config->setString("color", line_style->color.Serialized());
- config->setString("pattern", line_style->pattern);
+ if (!line_style || line_style->IsTransparent()) {
+ return;
+ }
+
+ std::unique_ptr<protocol::DictionaryValue> config =
+ protocol::DictionaryValue::create();
+ config->setString("color", line_style->color.Serialized());
+ config->setString("pattern", line_style->pattern);
+
+ parent_config->setValue(line_name, std::move(config));
+}
- parent_config->setValue(line_name, std::move(config));
+void AppendBoxStyleConfig(
+ const base::Optional<BoxStyle>& box_style,
+ std::unique_ptr<protocol::DictionaryValue>& parent_config,
+ String box_name) {
+ if (!box_style || box_style->IsTransparent()) {
+ return;
}
+
+ std::unique_ptr<protocol::DictionaryValue> config =
+ protocol::DictionaryValue::create();
+ config->setString("fillColor", box_style->fill_color.Serialized());
+ config->setString("hatchColor", box_style->hatch_color.Serialized());
+
+ parent_config->setValue(box_name, std::move(config));
}
std::unique_ptr<protocol::DictionaryValue>
@@ -380,6 +425,32 @@ BuildFlexContainerHighlightConfigInfo(
AppendLineStyleConfig(flex_config.item_separator, flex_config_info,
"itemSeparator");
+ AppendBoxStyleConfig(flex_config.main_distributed_space, flex_config_info,
+ "mainDistributedSpace");
+ AppendBoxStyleConfig(flex_config.cross_distributed_space, flex_config_info,
+ "crossDistributedSpace");
+ AppendBoxStyleConfig(flex_config.row_gap_space, flex_config_info,
+ "rowGapSpace");
+ AppendBoxStyleConfig(flex_config.column_gap_space, flex_config_info,
+ "columnGapSpace");
+ AppendLineStyleConfig(flex_config.cross_alignment, flex_config_info,
+ "crossAlignment");
+
+ return flex_config_info;
+}
+
+std::unique_ptr<protocol::DictionaryValue> BuildFlexItemHighlightConfigInfo(
+ const InspectorFlexItemHighlightConfig& flex_config) {
+ std::unique_ptr<protocol::DictionaryValue> flex_config_info =
+ protocol::DictionaryValue::create();
+
+ AppendBoxStyleConfig(flex_config.base_size_box, flex_config_info,
+ "baseSizeBox");
+ AppendLineStyleConfig(flex_config.base_size_border, flex_config_info,
+ "baseSizeBorder");
+ AppendLineStyleConfig(flex_config.flexibility_arrow, flex_config_info,
+ "flexibilityArrow");
+
return flex_config_info;
}
@@ -476,13 +547,14 @@ PhysicalOffset LocalToAbsolutePoint(Node* node,
PhysicalOffset local,
float scale) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
- FloatPoint local_in_frame = FramePointToViewport(
- node->GetDocument().View(), FloatPoint(local.left, local.top));
- PhysicalOffset abs_number_pos = layout_grid->LocalToAbsolutePoint(
- PhysicalOffset::FromFloatPointRound(local_in_frame));
- abs_number_pos.Scale(scale);
- return abs_number_pos;
+ auto* layout_grid = To<LayoutGrid>(layout_object);
+ PhysicalOffset abs_point = layout_grid->LocalToAbsolutePoint(local);
+ FloatPoint abs_point_in_viewport = FramePointToViewport(
+ node->GetDocument().View(), FloatPoint(abs_point.left, abs_point.top));
+ PhysicalOffset scaled_abs_point =
+ PhysicalOffset::FromFloatPointRound(abs_point_in_viewport);
+ scaled_abs_point.Scale(scale);
+ return scaled_abs_point;
}
std::unique_ptr<protocol::DictionaryValue> BuildPosition(
@@ -501,7 +573,7 @@ std::unique_ptr<protocol::ListValue> BuildGridTrackSizes(
LayoutUnit gap,
const Vector<String>* authored_values) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
bool is_rtl = direction == kForColumns &&
!layout_grid->StyleRef().IsLeftToRightDirection();
@@ -545,7 +617,7 @@ std::unique_ptr<protocol::ListValue> BuildGridPositiveLineNumberPositions(
GridTrackSizingDirection direction,
float scale) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
bool is_rtl = direction == kForColumns &&
!layout_grid->StyleRef().IsLeftToRightDirection();
@@ -588,7 +660,7 @@ std::unique_ptr<protocol::ListValue> BuildGridNegativeLineNumberPositions(
GridTrackSizingDirection direction,
float scale) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
bool is_rtl = direction == kForColumns &&
!layout_grid->StyleRef().IsLeftToRightDirection();
@@ -638,10 +710,21 @@ std::unique_ptr<protocol::ListValue> BuildGridNegativeLineNumberPositions(
return number_positions;
}
+bool IsLayoutNGFlexibleBox(const LayoutObject& layout_object) {
+ return layout_object.StyleRef().IsDisplayFlexibleBox() &&
+ layout_object.IsLayoutNGFlexibleBox();
+}
+
+bool IsLayoutNGFlexItem(const LayoutObject& layout_object) {
+ return !layout_object.GetNode()->IsDocumentNode() &&
+ IsLayoutNGFlexibleBox(*layout_object.Parent()) &&
+ To<LayoutBox>(layout_object).IsFlexItemIncludingNG();
+}
+
std::unique_ptr<protocol::DictionaryValue> BuildAreaNamePaths(Node* node,
float scale) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
LocalFrameView* containing_view = node->GetDocument().View();
bool is_rtl = !layout_grid->StyleRef().IsLeftToRightDirection();
@@ -697,7 +780,7 @@ std::unique_ptr<protocol::ListValue> BuildGridLineNames(
GridTrackSizingDirection direction,
float scale) {
LayoutObject* layout_object = node->GetLayoutObject();
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
bool is_rtl = direction == kForColumns &&
!layout_grid->StyleRef().IsLeftToRightDirection();
@@ -830,14 +913,17 @@ bool IsHorizontalFlex(LayoutObject* layout_flex) {
layout_flex->StyleRef().ResolvedIsColumnFlexDirection();
}
-Vector<Vector<PhysicalRect>> GetFlexLinesAndItems(LayoutBox* layout_box,
- bool is_horizontal) {
- Vector<Vector<PhysicalRect>> flex_lines;
+Vector<Vector<std::pair<PhysicalRect, float>>> GetFlexLinesAndItems(
+ LayoutBox* layout_box,
+ bool is_horizontal,
+ bool is_reverse) {
+ Vector<Vector<std::pair<PhysicalRect, float>>> flex_lines;
// Flex containers can't get fragmented yet, but this may change in the
// future.
for (const auto& fragment : layout_box->PhysicalFragments()) {
LayoutUnit progression;
+
for (const auto& child : fragment.Children()) {
const NGPhysicalFragment* child_fragment = child.get();
if (!child_fragment || child_fragment->IsOutOfFlowPositioned())
@@ -848,6 +934,14 @@ Vector<Vector<PhysicalRect>> GetFlexLinesAndItems(LayoutBox* layout_box,
const LayoutObject* object = child_fragment->GetLayoutObject();
const auto* box = To<LayoutBox>(object);
+
+ LayoutUnit baseline =
+ NGBoxFragment(box->StyleRef().GetWritingDirection(),
+ *To<NGPhysicalBoxFragment>(child_fragment))
+ .BaselineOrSynthesize();
+ float adjusted_baseline = AdjustForAbsoluteZoom::AdjustFloat(
+ baseline + box->MarginTop(), box->StyleRef());
+
PhysicalRect item_rect =
PhysicalRect(fragment_offset.left - box->MarginLeft(),
fragment_offset.top - box->MarginTop(),
@@ -858,29 +952,35 @@ Vector<Vector<PhysicalRect>> GetFlexLinesAndItems(LayoutBox* layout_box,
LayoutUnit item_end = is_horizontal ? item_rect.X() + item_rect.Width()
: item_rect.Y() + item_rect.Height();
- if (flex_lines.IsEmpty() || item_start < progression) {
+ if (flex_lines.IsEmpty() ||
+ (is_reverse ? item_end > progression : item_start < progression)) {
flex_lines.emplace_back();
}
- flex_lines.back().push_back(item_rect);
+ flex_lines.back().push_back(std::make_pair(item_rect, adjusted_baseline));
- progression = item_end;
+ progression = is_reverse ? item_start : item_end;
}
}
return flex_lines;
}
-std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
+std::unique_ptr<protocol::DictionaryValue> BuildFlexContainerInfo(
Node* node,
const InspectorFlexContainerHighlightConfig&
flex_container_highlight_config,
float scale) {
+ CSSComputedStyleDeclaration* style =
+ MakeGarbageCollected<CSSComputedStyleDeclaration>(node, true);
LocalFrameView* containing_view = node->GetDocument().View();
LayoutObject* layout_object = node->GetLayoutObject();
auto* layout_box = To<LayoutBox>(layout_object);
DCHECK(layout_object);
bool is_horizontal = IsHorizontalFlex(layout_object);
+ bool is_reverse =
+ layout_object->StyleRef().ResolvedIsRowReverseFlexDirection() ||
+ layout_object->StyleRef().ResolvedIsColumnReverseFlexDirection();
std::unique_ptr<protocol::DictionaryValue> flex_info =
protocol::DictionaryValue::create();
@@ -893,23 +993,30 @@ std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
container_builder.AppendPath(QuadToPath(content_quad), scale);
// Gather all flex items, sorted by flex line.
- Vector<Vector<PhysicalRect>> flex_lines =
- GetFlexLinesAndItems(layout_box, is_horizontal);
+ Vector<Vector<std::pair<PhysicalRect, float>>> flex_lines =
+ GetFlexLinesAndItems(layout_box, is_horizontal, is_reverse);
- // Send the offset information for each item to the frontend.
+ // We send a list of flex lines, each containing a list of flex items, with
+ // their baselines, to the frontend.
std::unique_ptr<protocol::ListValue> lines_info =
protocol::ListValue::create();
for (auto line : flex_lines) {
std::unique_ptr<protocol::ListValue> items_info =
protocol::ListValue::create();
- for (auto item_rect : line) {
+ for (auto item_data : line) {
+ std::unique_ptr<protocol::DictionaryValue> item_info =
+ protocol::DictionaryValue::create();
+
FloatQuad item_margin_quad =
- layout_object->LocalRectToAbsoluteQuad(item_rect);
+ layout_object->LocalRectToAbsoluteQuad(item_data.first);
FrameQuadToViewport(containing_view, item_margin_quad);
PathBuilder item_builder;
item_builder.AppendPath(QuadToPath(item_margin_quad), scale);
- items_info->pushValue(item_builder.Release());
+ item_info->setValue("itemBorder", item_builder.Release());
+ item_info->setDouble("baseline", item_data.second);
+
+ items_info->pushValue(std::move(item_info));
}
lines_info->pushValue(std::move(items_info));
}
@@ -917,6 +1024,29 @@ std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
flex_info->setValue("containerBorder", container_builder.Release());
flex_info->setArray("lines", std::move(lines_info));
flex_info->setBoolean("isHorizontalFlow", is_horizontal);
+ flex_info->setBoolean("isReverse", is_reverse);
+ flex_info->setString(
+ "alignItemsStyle",
+ style->GetPropertyCSSValue(CSSPropertyID::kAlignItems)->CssText());
+
+ double row_gap_value = 0;
+ const CSSValue* row_gap = style->GetPropertyCSSValue(CSSPropertyID::kRowGap);
+ if (row_gap->IsNumericLiteralValue()) {
+ row_gap_value = To<CSSNumericLiteralValue>(row_gap)->DoubleValue();
+ }
+
+ double column_gap_value = 0;
+ const CSSValue* column_gap =
+ style->GetPropertyCSSValue(CSSPropertyID::kColumnGap);
+ if (column_gap->IsNumericLiteralValue()) {
+ column_gap_value = To<CSSNumericLiteralValue>(column_gap)->DoubleValue();
+ }
+
+ flex_info->setDouble("mainGap",
+ is_horizontal ? column_gap_value : row_gap_value);
+ flex_info->setDouble("crossGap",
+ is_horizontal ? row_gap_value : column_gap_value);
+
flex_info->setValue(
"flexContainerHighlightConfig",
BuildFlexContainerHighlightConfigInfo(flex_container_highlight_config));
@@ -924,6 +1054,40 @@ std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
return flex_info;
}
+std::unique_ptr<protocol::DictionaryValue> BuildFlexItemInfo(
+ Node* node,
+ const InspectorFlexItemHighlightConfig& flex_item_highlight_config,
+ float scale) {
+ std::unique_ptr<protocol::DictionaryValue> flex_info =
+ protocol::DictionaryValue::create();
+
+ LayoutObject* layout_object = node->GetLayoutObject();
+ bool is_horizontal = IsHorizontalFlex(layout_object->Parent());
+ Length base_size = Length::Auto();
+
+ const Length& flex_basis = layout_object->StyleRef().FlexBasis();
+ const Length& size = is_horizontal ? layout_object->StyleRef().Width()
+ : layout_object->StyleRef().Height();
+
+ if (flex_basis.IsFixed()) {
+ base_size = flex_basis;
+ } else if (flex_basis.IsAuto() && size.IsFixed()) {
+ base_size = size;
+ }
+
+ // For now, we only care about the cases where we can know the base size.
+ if (base_size.IsSpecified()) {
+ flex_info->setDouble("baseSize", base_size.Pixels() * scale);
+ flex_info->setBoolean("isHorizontalFlow", is_horizontal);
+
+ flex_info->setValue(
+ "flexItemHighlightConfig",
+ BuildFlexItemHighlightConfigInfo(flex_item_highlight_config));
+ }
+
+ return flex_info;
+}
+
std::unique_ptr<protocol::DictionaryValue> BuildGridInfo(
Node* node,
const InspectorGridHighlightConfig& grid_highlight_config,
@@ -932,7 +1096,7 @@ std::unique_ptr<protocol::DictionaryValue> BuildGridInfo(
LocalFrameView* containing_view = node->GetDocument().View();
LayoutObject* layout_object = node->GetLayoutObject();
DCHECK(layout_object);
- LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
+ auto* layout_grid = To<LayoutGrid>(layout_object);
std::unique_ptr<protocol::DictionaryValue> grid_info =
protocol::DictionaryValue::create();
@@ -1190,6 +1354,8 @@ InspectorSourceOrderConfig::InspectorSourceOrderConfig() = default;
LineStyle::LineStyle() = default;
+BoxStyle::BoxStyle() = default;
+
InspectorGridHighlightConfig::InspectorGridHighlightConfig()
: show_grid_extension_lines(false),
grid_border_dash(false),
@@ -1204,6 +1370,8 @@ InspectorGridHighlightConfig::InspectorGridHighlightConfig()
InspectorFlexContainerHighlightConfig::InspectorFlexContainerHighlightConfig() =
default;
+InspectorFlexItemHighlightConfig::InspectorFlexItemHighlightConfig() = default;
+
InspectorHighlightBase::InspectorHighlightBase(float scale)
: highlight_paths_(protocol::ListValue::create()), scale_(scale) {}
@@ -1364,7 +1532,7 @@ InspectorHighlight::InspectorHighlight(
const InspectorHighlightContrastInfo& node_contrast,
bool append_element_info,
bool append_distance_info,
- bool is_locked_ancestor)
+ NodeContentVisibilityState content_visibility_state)
: InspectorHighlightBase(node),
show_rulers_(highlight_config.show_rulers),
show_extension_lines_(highlight_config.show_extension_lines),
@@ -1378,15 +1546,27 @@ InspectorHighlight::InspectorHighlight(
element_info_ = BuildElementInfo(element);
else if (append_element_info && text_node)
element_info_ = BuildTextNodeInfo(text_node);
- if (element_info_ && highlight_config.show_styles)
- AppendStyleInfo(node, element_info_.get(), node_contrast);
+ if (element_info_ && highlight_config.show_styles) {
+ AppendStyleInfo(node, element_info_.get(), node_contrast,
+ highlight_config.contrast_algorithm);
+ }
- if (element_info_ && is_locked_ancestor)
- element_info_->setString("isLockedAncestor", "true");
if (element_info_) {
+ switch (content_visibility_state) {
+ case NodeContentVisibilityState::kNone:
+ break;
+ case NodeContentVisibilityState::kIsLocked:
+ element_info_->setBoolean("isLocked", true);
+ break;
+ case NodeContentVisibilityState::kIsLockedAncestor:
+ element_info_->setBoolean("isLockedAncestor", true);
+ break;
+ }
+
element_info_->setBoolean("showAccessibilityInfo",
show_accessibility_info_);
}
+
if (append_distance_info)
AppendDistanceInfo(node);
}
@@ -1410,7 +1590,7 @@ void InspectorHighlight::AppendDistanceInfo(Node* node) {
for (size_t i = 0; i < style->length(); ++i) {
AtomicString name(style->item(i));
const CSSValue* value = style->GetPropertyCSSValue(
- cssPropertyID(node->GetExecutionContext(), name));
+ CssPropertyID(node->GetExecutionContext(), name));
if (!value)
continue;
if (value->IsColorValue()) {
@@ -1555,6 +1735,7 @@ void InspectorHighlight::AppendNodeHighlight(
if (highlight_config.css_grid != Color::kTransparent ||
highlight_config.grid_highlight_config) {
grid_info_ = protocol::ListValue::create();
+ // TODO(crbug.com/1045599): Implement |BuildGridInfo| for GridNG.
if (layout_object->IsLayoutGrid()) {
grid_info_->pushValue(
BuildGridInfo(node, highlight_config, scale_, true));
@@ -1562,15 +1743,22 @@ void InspectorHighlight::AppendNodeHighlight(
}
if (highlight_config.flex_container_highlight_config) {
- flex_info_ = protocol::ListValue::create();
+ flex_container_info_ = protocol::ListValue::create();
// Some objects are flexible boxes even though display:flex is not set, we
// need to avoid those.
- if (layout_object->StyleRef().IsDisplayFlexibleBox() &&
- layout_object->IsFlexibleBoxIncludingNG()) {
- flex_info_->pushValue(BuildFlexInfo(
+ if (IsLayoutNGFlexibleBox(*layout_object)) {
+ flex_container_info_->pushValue(BuildFlexContainerInfo(
node, *(highlight_config.flex_container_highlight_config), scale_));
}
}
+
+ if (highlight_config.flex_item_highlight_config) {
+ flex_item_info_ = protocol::ListValue::create();
+ if (IsLayoutNGFlexItem(*layout_object)) {
+ flex_item_info_->pushValue(BuildFlexItemInfo(
+ node, *(highlight_config.flex_item_highlight_config), scale_));
+ }
+ }
}
std::unique_ptr<protocol::DictionaryValue> InspectorHighlight::AsProtocolValue()
@@ -1616,8 +1804,10 @@ std::unique_ptr<protocol::DictionaryValue> InspectorHighlight::AsProtocolValue()
object->setValue("elementInfo", element_info_->clone());
if (grid_info_ && grid_info_->size() > 0)
object->setValue("gridInfo", grid_info_->clone());
- if (flex_info_ && flex_info_->size() > 0)
- object->setValue("flexInfo", flex_info_->clone());
+ if (flex_container_info_ && flex_container_info_->size() > 0)
+ object->setValue("flexInfo", flex_container_info_->clone());
+ if (flex_item_info_ && flex_item_info_->size() > 0)
+ object->setValue("flexItemInfo", flex_item_info_->clone());
return object;
}
@@ -1762,6 +1952,28 @@ std::unique_ptr<protocol::DictionaryValue> InspectorGridHighlight(
return grid_info;
}
+std::unique_ptr<protocol::DictionaryValue> InspectorFlexContainerHighlight(
+ Node* node,
+ const InspectorFlexContainerHighlightConfig& config) {
+ if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
+ // Skip if node is part of display locked tree.
+ return nullptr;
+ }
+
+ LocalFrameView* frame_view = node->GetDocument().View();
+ if (!frame_view)
+ return nullptr;
+
+ float scale = 1.f / frame_view->GetChromeClient()->WindowToViewportScalar(
+ &frame_view->GetFrame(), 1.f);
+ LayoutObject* layout_object = node->GetLayoutObject();
+ if (!layout_object || !IsLayoutNGFlexibleBox(*layout_object)) {
+ return nullptr;
+ }
+
+ return BuildFlexContainerInfo(node, config, scale);
+}
+
// static
InspectorHighlightConfig InspectorHighlight::DefaultConfig() {
InspectorHighlightConfig config;
@@ -1784,6 +1996,9 @@ InspectorHighlightConfig InspectorHighlight::DefaultConfig() {
config.flex_container_highlight_config =
std::make_unique<InspectorFlexContainerHighlightConfig>(
InspectorHighlight::DefaultFlexContainerConfig());
+ config.flex_item_highlight_config =
+ std::make_unique<InspectorFlexItemHighlightConfig>(
+ InspectorHighlight::DefaultFlexItemConfig());
return config;
}
@@ -1816,11 +2031,33 @@ InspectorFlexContainerHighlightConfig
InspectorHighlight::DefaultFlexContainerConfig() {
InspectorFlexContainerHighlightConfig config;
config.container_border =
- std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
config.line_separator =
- std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
config.item_separator =
- std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ config.main_distributed_space =
+ base::Optional<BoxStyle>(InspectorHighlight::DefaultBoxStyle());
+ config.cross_distributed_space =
+ base::Optional<BoxStyle>(InspectorHighlight::DefaultBoxStyle());
+ config.row_gap_space =
+ base::Optional<BoxStyle>(InspectorHighlight::DefaultBoxStyle());
+ config.column_gap_space =
+ base::Optional<BoxStyle>(InspectorHighlight::DefaultBoxStyle());
+ config.cross_alignment =
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ return config;
+}
+
+// static
+InspectorFlexItemHighlightConfig InspectorHighlight::DefaultFlexItemConfig() {
+ InspectorFlexItemHighlightConfig config;
+ config.base_size_box =
+ base::Optional<BoxStyle>(InspectorHighlight::DefaultBoxStyle());
+ config.base_size_border =
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
+ config.flexibility_arrow =
+ base::Optional<LineStyle>(InspectorHighlight::DefaultLineStyle());
return config;
}
@@ -1832,4 +2069,12 @@ LineStyle InspectorHighlight::DefaultLineStyle() {
return style;
}
+// static
+BoxStyle InspectorHighlight::DefaultBoxStyle() {
+ BoxStyle style;
+ style.fill_color = Color(255, 0, 0, 0);
+ style.hatch_color = Color(255, 0, 0, 0);
+ return style;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
index 7ac8537abfb..92311360ea5 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_highlight.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
+#include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
#include "third_party/blink/renderer/core/inspector/protocol/DOM.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
@@ -18,6 +19,7 @@ namespace blink {
class Color;
enum class ColorFormat { RGB, HEX, HSL };
+enum class ContrastAlgorithm { AA, AAA, APCA };
struct CORE_EXPORT LineStyle {
USING_FAST_MALLOC(LineStyle);
@@ -25,10 +27,27 @@ struct CORE_EXPORT LineStyle {
public:
LineStyle();
+ bool IsTransparent() const { return color == Color::kTransparent; }
+
Color color;
String pattern;
};
+struct CORE_EXPORT BoxStyle {
+ USING_FAST_MALLOC(BoxStyle);
+
+ public:
+ BoxStyle();
+
+ bool IsTransparent() const {
+ return fill_color == Color::kTransparent &&
+ hatch_color == Color::kTransparent;
+ }
+
+ Color fill_color;
+ Color hatch_color;
+};
+
struct CORE_EXPORT InspectorSourceOrderConfig {
USING_FAST_MALLOC(InspectorSourceOrderConfig);
@@ -72,9 +91,26 @@ struct CORE_EXPORT InspectorFlexContainerHighlightConfig {
public:
InspectorFlexContainerHighlightConfig();
- std::unique_ptr<LineStyle> container_border;
- std::unique_ptr<LineStyle> line_separator;
- std::unique_ptr<LineStyle> item_separator;
+ base::Optional<LineStyle> container_border;
+ base::Optional<LineStyle> line_separator;
+ base::Optional<LineStyle> item_separator;
+
+ base::Optional<BoxStyle> main_distributed_space;
+ base::Optional<BoxStyle> cross_distributed_space;
+ base::Optional<BoxStyle> row_gap_space;
+ base::Optional<BoxStyle> column_gap_space;
+ base::Optional<LineStyle> cross_alignment;
+};
+
+struct CORE_EXPORT InspectorFlexItemHighlightConfig {
+ USING_FAST_MALLOC(InspectorFlexItemHighlightConfig);
+
+ public:
+ InspectorFlexItemHighlightConfig();
+
+ base::Optional<BoxStyle> base_size_box;
+ base::Optional<LineStyle> base_size_border;
+ base::Optional<LineStyle> flexibility_arrow;
};
struct CORE_EXPORT InspectorHighlightConfig {
@@ -100,17 +136,20 @@ struct CORE_EXPORT InspectorHighlightConfig {
bool show_accessibility_info;
String selector_list;
- ColorFormat color_format;
+ ColorFormat color_format = ColorFormat::HEX;
+ ContrastAlgorithm contrast_algorithm = ContrastAlgorithm::AA;
std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config;
std::unique_ptr<InspectorFlexContainerHighlightConfig>
flex_container_highlight_config;
+ std::unique_ptr<InspectorFlexItemHighlightConfig> flex_item_highlight_config;
};
struct InspectorHighlightContrastInfo {
Color background_color;
String font_size;
String font_weight;
+ float text_opacity;
};
class InspectorHighlightBase {
@@ -160,7 +199,7 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
const InspectorHighlightContrastInfo&,
bool append_element_info,
bool append_distance_info,
- bool is_locked_ancestor);
+ NodeContentVisibilityState content_visibility_state);
explicit InspectorHighlight(float scale);
~InspectorHighlight();
@@ -173,6 +212,7 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
static InspectorHighlightConfig DefaultConfig();
static InspectorGridHighlightConfig DefaultGridConfig();
static InspectorFlexContainerHighlightConfig DefaultFlexContainerConfig();
+ static InspectorFlexItemHighlightConfig DefaultFlexItemConfig();
void AppendEventTargetQuads(Node* event_target_node,
const InspectorHighlightConfig&);
std::unique_ptr<protocol::DictionaryValue> AsProtocolValue() const override;
@@ -189,6 +229,7 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
void AddLayoutBoxToDistanceInfo(LayoutObject* layout_object);
static LineStyle DefaultLineStyle();
+ static BoxStyle DefaultBoxStyle();
std::unique_ptr<protocol::Array<protocol::Array<double>>> boxes_;
std::unique_ptr<protocol::DictionaryValue> computed_style_;
@@ -196,7 +237,8 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
std::unique_ptr<protocol::DictionaryValue> distance_info_;
std::unique_ptr<protocol::DictionaryValue> element_info_;
std::unique_ptr<protocol::ListValue> grid_info_;
- std::unique_ptr<protocol::ListValue> flex_info_;
+ std::unique_ptr<protocol::ListValue> flex_container_info_;
+ std::unique_ptr<protocol::ListValue> flex_item_info_;
bool show_rulers_;
bool show_extension_lines_;
bool show_accessibility_info_;
@@ -207,6 +249,10 @@ std::unique_ptr<protocol::DictionaryValue> InspectorGridHighlight(
Node*,
const InspectorGridHighlightConfig& config);
+std::unique_ptr<protocol::DictionaryValue> InspectorFlexContainerHighlight(
+ Node* node,
+ const InspectorFlexContainerHighlightConfig& config);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_HIGHLIGHT_H_
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_io_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_io_agent.h
index d8726c72de2..61a5a96117d 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_io_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_io_agent.h
@@ -25,10 +25,9 @@ class CORE_EXPORT InspectorIOAgent final
: public InspectorBaseAgent<protocol::IO::Metainfo> {
public:
InspectorIOAgent(v8::Isolate*, v8_inspector::V8InspectorSession*);
-
- private:
~InspectorIOAgent() override;
+ private:
void Restore() override {}
// Called from the front-end.
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.cc
index 77acdfa2bb8..4993ce62e62 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.cc
@@ -81,7 +81,7 @@ std::unique_ptr<protocol::Array<To>> ConvertVector(const Vector<From>& from) {
} // namespace
InspectorMediaAgent::InspectorMediaAgent(InspectedFrames* inspected_frames)
- : local_frame_(inspected_frames->Root()),
+ : frame_(inspected_frames->Root()),
enabled_(&agent_state_, /*default_value = */ false) {}
InspectorMediaAgent::~InspectorMediaAgent() = default;
@@ -95,8 +95,8 @@ void InspectorMediaAgent::Restore() {
void InspectorMediaAgent::RegisterAgent() {
instrumenting_agents_->AddInspectorMediaAgent(this);
auto* cache = MediaInspectorContextImpl::From(
- *local_frame_->DomWindow()->GetExecutionContext());
- Vector<WebString> players = cache->AllPlayerIds();
+ *frame_->DomWindow()->GetExecutionContext());
+ Vector<WebString> players = cache->AllPlayerIdsAndMarkSent();
PlayersCreated(players);
for (const auto& player_id : players) {
const auto& media_player = cache->MediaPlayerFromId(player_id);
@@ -165,7 +165,7 @@ void InspectorMediaAgent::PlayersCreated(const Vector<WebString>& player_ids) {
}
void InspectorMediaAgent::Trace(Visitor* visitor) const {
- visitor->Trace(local_frame_);
+ visitor->Trace(frame_);
InspectorBaseAgent::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.h
index 830a3b994de..f15aaa04f7e 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_media_agent.h
@@ -46,7 +46,7 @@ class CORE_EXPORT InspectorMediaAgent final
private:
void RegisterAgent();
- Member<LocalFrame> local_frame_;
+ Member<LocalFrame> frame_;
InspectorAgentState::Boolean enabled_;
DISALLOW_COPY_AND_ASSIGN(InspectorMediaAgent);
};
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
index 0223f9b4ca4..a7ff21b43a6 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc
@@ -49,11 +49,11 @@ void MediaInspectorContextImpl::Trace(Visitor* visitor) const {
visitor->Trace(players_);
}
-Vector<WebString> MediaInspectorContextImpl::AllPlayerIds() {
+Vector<WebString> MediaInspectorContextImpl::AllPlayerIdsAndMarkSent() {
Vector<WebString> existing_players;
- existing_players.ReserveCapacity(players_.size());
- for (const auto& player_id : players_.Keys())
- existing_players.push_back(player_id);
+ const auto& keys = players_.Keys();
+ existing_players.AppendRange(keys.begin(), keys.end());
+ unsent_players_.clear();
return existing_players;
}
@@ -69,16 +69,100 @@ WebString MediaInspectorContextImpl::CreatePlayer() {
String::FromUTF8(base::UnguessableToken::Create().ToString());
players_.insert(next_player_id, MakeGarbageCollected<MediaPlayer>());
probe::PlayersCreated(GetSupplementable(), {next_player_id});
+ if (!GetSupplementable()->GetProbeSink()->HasInspectorMediaAgents())
+ unsent_players_.push_back(next_player_id);
return next_player_id;
}
+void MediaInspectorContextImpl::RemovePlayer(const WebString& playerId) {
+ const auto& player = players_.Take(playerId);
+ if (player) {
+ total_event_count_ -=
+ player->errors.size() + player->events.size() + player->messages.size();
+ DCHECK_GE(total_event_count_, 0);
+ }
+}
+
+void MediaInspectorContextImpl::TrimPlayer(const WebString& playerId) {
+ MediaPlayer* player = players_.Take(playerId);
+ wtf_size_t overage = total_event_count_ - kMaxCachedPlayerEvents;
+
+ wtf_size_t excess = std::min<wtf_size_t>(overage, player->events.size());
+ player->events.EraseAt(0, excess);
+ total_event_count_ -= excess;
+ overage -= excess;
+
+ excess = std::min(overage, player->messages.size());
+ player->messages.EraseAt(0, excess);
+ total_event_count_ -= excess;
+ overage -= excess;
+
+ excess = std::min(overage, player->errors.size());
+ player->errors.EraseAt(0, excess);
+ total_event_count_ -= excess;
+ overage -= excess;
+
+ players_.insert(playerId, player);
+}
+
+void MediaInspectorContextImpl::CullPlayers(const WebString& prefer_keep) {
+ // Erase all the dead players, but only erase the required number of others.
+ for (const auto& playerId : dead_players_)
+ RemovePlayer(playerId);
+ dead_players_.clear();
+
+ while (!expendable_players_.IsEmpty()) {
+ if (total_event_count_ <= kMaxCachedPlayerEvents)
+ return;
+ RemovePlayer(expendable_players_.back());
+ expendable_players_.pop_back();
+ }
+
+ while (!unsent_players_.IsEmpty()) {
+ if (total_event_count_ <= kMaxCachedPlayerEvents)
+ return;
+ RemovePlayer(unsent_players_.back());
+ unsent_players_.pop_back();
+ }
+
+ // TODO(tmathmeyer) keep last event time stamps for players to remove the
+ // most stale one.
+ while (players_.size() > 1) {
+ if (total_event_count_ <= kMaxCachedPlayerEvents)
+ return;
+ auto iterator = players_.begin();
+ // Make sure not to delete the item that is preferred to keep.
+ if (WTF::String(prefer_keep) == iterator->key)
+ ++iterator;
+ RemovePlayer(iterator->key);
+ }
+
+ // When there is only one player, selectively remove the oldest events.
+ if (players_.size() == 1 && total_event_count_ > kMaxCachedPlayerEvents)
+ TrimPlayer(players_.begin()->key);
+}
+
+void MediaInspectorContextImpl::DestroyPlayer(const WebString& playerId) {
+ if (unsent_players_.Contains(String(playerId))) {
+ // unsent players become dead when destroyed.
+ unsent_players_.EraseAt(unsent_players_.Find(String(playerId)));
+ dead_players_.push_back(playerId);
+ } else {
+ expendable_players_.push_back(playerId);
+ }
+}
+
// Convert public version of event to protocol version, and send it.
void MediaInspectorContextImpl::NotifyPlayerErrors(
WebString playerId,
const InspectorPlayerErrors& errors) {
const auto& player = players_.find(playerId);
- DCHECK_NE(player, players_.end());
- player->value->errors.AppendRange(errors.begin(), errors.end());
+ if (player != players_.end()) {
+ player->value->errors.AppendRange(errors.begin(), errors.end());
+ total_event_count_ += errors.size();
+ if (total_event_count_ > kMaxCachedPlayerEvents)
+ CullPlayers(playerId);
+ }
Vector<InspectorPlayerError> vector =
Iter2Vector<InspectorPlayerError>(errors);
@@ -89,8 +173,12 @@ void MediaInspectorContextImpl::NotifyPlayerEvents(
WebString playerId,
const InspectorPlayerEvents& events) {
const auto& player = players_.find(playerId);
- DCHECK_NE(player, players_.end());
- player->value->events.AppendRange(events.begin(), events.end());
+ if (player != players_.end()) {
+ player->value->events.AppendRange(events.begin(), events.end());
+ total_event_count_ += events.size();
+ if (total_event_count_ > kMaxCachedPlayerEvents)
+ CullPlayers(playerId);
+ }
Vector<InspectorPlayerEvent> vector =
Iter2Vector<InspectorPlayerEvent>(events);
@@ -101,9 +189,10 @@ void MediaInspectorContextImpl::SetPlayerProperties(
WebString playerId,
const InspectorPlayerProperties& props) {
const auto& player = players_.find(playerId);
- DCHECK_NE(player, players_.end());
- for (const auto& property : props)
- player->value->properties.insert(property.name, property);
+ if (player != players_.end()) {
+ for (const auto& property : props)
+ player->value->properties.insert(property.name, property);
+ }
Vector<InspectorPlayerProperty> vector =
Iter2Vector<InspectorPlayerProperty>(props);
@@ -114,12 +203,21 @@ void MediaInspectorContextImpl::NotifyPlayerMessages(
WebString playerId,
const InspectorPlayerMessages& messages) {
const auto& player = players_.find(playerId);
- DCHECK_NE(player, players_.end());
- player->value->messages.AppendRange(messages.begin(), messages.end());
+ if (player != players_.end()) {
+ player->value->messages.AppendRange(messages.begin(), messages.end());
+ total_event_count_ += messages.size();
+ if (total_event_count_ > kMaxCachedPlayerEvents)
+ CullPlayers(playerId);
+ }
Vector<InspectorPlayerMessage> vector =
Iter2Vector<InspectorPlayerMessage>(messages);
probe::PlayerMessagesLogged(GetSupplementable(), playerId, vector);
}
+HeapHashMap<String, Member<MediaPlayer>>*
+MediaInspectorContextImpl::GetPlayersForTesting() {
+ return &players_;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.h b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.h
index ff5b740d5bf..6fe4613cb17 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_MEDIA_CONTEXT_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_MEDIA_CONTEXT_IMPL_H_
+#include "build/build_config.h"
#include "third_party/blink/public/web/web_media_inspector.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -13,6 +14,13 @@
namespace blink {
+#if defined(OS_ANDROID)
+// Players are cached per tab.
+constexpr int kMaxCachedPlayerEvents = 128;
+#else
+constexpr int kMaxCachedPlayerEvents = 512;
+#endif
+
class ExecutionContext;
struct MediaPlayer final : public GarbageCollected<MediaPlayer> {
@@ -38,6 +46,8 @@ class CORE_EXPORT MediaInspectorContextImpl final
// MediaInspectorContext methods.
WebString CreatePlayer() override;
+ void DestroyPlayer(const WebString& playerId) override;
+
void NotifyPlayerErrors(WebString playerId,
const InspectorPlayerErrors&) override;
void NotifyPlayerEvents(WebString playerId,
@@ -50,11 +60,37 @@ class CORE_EXPORT MediaInspectorContextImpl final
// GarbageCollected methods.
void Trace(Visitor*) const override;
- Vector<WebString> AllPlayerIds();
+ Vector<WebString> AllPlayerIdsAndMarkSent();
const MediaPlayer& MediaPlayerFromId(const WebString&);
+ HeapHashMap<String, Member<MediaPlayer>>* GetPlayersForTesting();
+ int GetTotalEventCountForTesting() { return total_event_count_; }
+
private:
+ // When a player is added, its ID is stored in |unsent_players_| if no
+ // connections are open. When an unsent player is destroyed, its ID is moved
+ // to |dead_players_| and is first to be deleted if there is memory pressure.
+ // If it has already been sent when it is destroyed, it gets moved to
+ // |expendable_players_|, which is the second group of players to be deleted
+ // on memory pressure.
+
+ // If there are no dead or expendable players when it's time to start removing
+ // players, then a player from |unsent_players_| will be removed. As a last
+ // resort, remaining unended, already-sent players will be removed from
+ // |players_| until the total event size is within the limit.
+
+ // All events will be sent to any open clients regardless of players existing
+ // because the clients can handle dead players and may have their own cache.
+ void CullPlayers(const WebString& prefer_keep);
+ void TrimPlayer(const WebString& playerId);
+ void RemovePlayer(const WebString& playerId);
+
HeapHashMap<String, Member<MediaPlayer>> players_;
+ Vector<String> unsent_players_;
+ Vector<String> dead_players_;
+ Vector<String> expendable_players_;
+
+ int total_event_count_ = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl_unittest.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl_unittest.cc
new file mode 100644
index 00000000000..e23ca6b0d21
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_media_context_impl_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_media_context_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/core/testing/null_execution_context.h"
+
+namespace blink {
+namespace {
+
+class InspectorMediaContextImplTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ dummy_page_holder_ =
+ std::make_unique<DummyPageHolder>(IntSize(), nullptr, nullptr);
+ impl = MediaInspectorContextImpl::From(
+ *dummy_page_holder_->GetFrame().DomWindow());
+ }
+
+ InspectorPlayerEvents MakeEvents(size_t ev_count) {
+ InspectorPlayerEvents to_add;
+ while (ev_count-- > 0) {
+ blink::InspectorPlayerEvent ev = {base::TimeTicks::Now(), "foo"};
+ to_add.emplace_back(std::move(ev));
+ }
+ return to_add;
+ }
+
+ Persistent<MediaInspectorContextImpl> impl;
+ std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+};
+
+TEST_F(InspectorMediaContextImplTest, CanCreatePlayerAndAddEvents) {
+ auto id = impl->CreatePlayer();
+ auto* players = impl->GetPlayersForTesting();
+ EXPECT_EQ(players->size(), 1u);
+ EXPECT_TRUE(players->at(id)->errors.IsEmpty());
+ EXPECT_TRUE(players->at(id)->events.IsEmpty());
+ EXPECT_TRUE(players->at(id)->messages.IsEmpty());
+ EXPECT_TRUE(players->at(id)->properties.IsEmpty());
+
+ impl->NotifyPlayerEvents(id, MakeEvents(10));
+ EXPECT_EQ(players->at(id)->events.size(), wtf_size_t{10});
+}
+
+TEST_F(InspectorMediaContextImplTest, KillsPlayersInCorrectOrder) {
+ auto alive_player_id = impl->CreatePlayer();
+ auto expendable_player_id = impl->CreatePlayer();
+ // Also marks the alive / expendable players as sent.
+ ASSERT_EQ(impl->AllPlayerIdsAndMarkSent().size(), wtf_size_t{2});
+
+ // These are created, but unsent.
+ auto dead_player_id = impl->CreatePlayer();
+ auto unsent_player_id = impl->CreatePlayer();
+
+ // check that there are 4.
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{4});
+
+ // mark these as dead to get them into their respective states.
+ impl->DestroyPlayer(dead_player_id);
+ impl->DestroyPlayer(expendable_player_id);
+
+ // check that there are still 4.
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{4});
+
+ // Almost fill up the total cache size.
+ impl->NotifyPlayerEvents(dead_player_id, MakeEvents(10));
+ impl->NotifyPlayerEvents(unsent_player_id, MakeEvents(10));
+ impl->NotifyPlayerEvents(expendable_player_id, MakeEvents(10));
+ impl->NotifyPlayerEvents(alive_player_id,
+ MakeEvents(kMaxCachedPlayerEvents - 32));
+
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents - 2);
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{4});
+
+ // If we keep adding events to the alive player in groups of 10, it should
+ // delete the other players in the order: dead, expendable, unsent.
+ impl->NotifyPlayerEvents(alive_player_id, MakeEvents(10));
+
+ // The number of events remains unchanged, players at 3, and no dead id.
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents - 2);
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{3});
+ EXPECT_FALSE(impl->GetPlayersForTesting()->Contains(dead_player_id));
+
+ // Kill the expendable player.
+ impl->NotifyPlayerEvents(alive_player_id, MakeEvents(10));
+
+ // The number of events remains unchanged, players at 2, and no expendable id.
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents - 2);
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{2});
+ EXPECT_FALSE(impl->GetPlayersForTesting()->Contains(expendable_player_id));
+
+ // Kill the unsent player.
+ impl->NotifyPlayerEvents(alive_player_id, MakeEvents(10));
+
+ // The number of events remains unchanged, players at 1, and no unsent id.
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents - 2);
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{1});
+ EXPECT_FALSE(impl->GetPlayersForTesting()->Contains(unsent_player_id));
+
+ // Overflow the the cache and start trimming events.
+ impl->NotifyPlayerEvents(alive_player_id, MakeEvents(10));
+
+ // The number of events remains unchanged, players at 1, and no unsent id.
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents);
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{1});
+ EXPECT_TRUE(impl->GetPlayersForTesting()->Contains(alive_player_id));
+}
+
+TEST_F(InspectorMediaContextImplTest, OkToSendForDeadPlayers) {
+ auto player_1 = impl->CreatePlayer();
+ auto player_2 = impl->CreatePlayer();
+ ASSERT_EQ(impl->AllPlayerIdsAndMarkSent().size(), wtf_size_t{2});
+
+ // This should evict player1.
+ impl->NotifyPlayerEvents(player_1, MakeEvents(kMaxCachedPlayerEvents - 1));
+ impl->NotifyPlayerEvents(player_2, MakeEvents(10));
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{1});
+ EXPECT_FALSE(impl->GetPlayersForTesting()->Contains(player_1));
+
+ // Sending events to an evicted player shouldn't cause the cache size to
+ // increase, or any new evictions to happen.
+ impl->NotifyPlayerEvents(player_1, MakeEvents(kMaxCachedPlayerEvents - 1));
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{1});
+ EXPECT_FALSE(impl->GetPlayersForTesting()->Contains(player_1));
+}
+
+TEST_F(InspectorMediaContextImplTest, TrimLastRemainingPlayer) {
+ auto player_1 = impl->CreatePlayer();
+ ASSERT_EQ(impl->AllPlayerIdsAndMarkSent().size(), wtf_size_t{1});
+
+ impl->NotifyPlayerEvents(player_1, MakeEvents(kMaxCachedPlayerEvents - 1));
+ impl->NotifyPlayerEvents(player_1, MakeEvents(kMaxCachedPlayerEvents - 1));
+ EXPECT_EQ(impl->GetPlayersForTesting()->size(), wtf_size_t{1});
+ EXPECT_TRUE(impl->GetPlayersForTesting()->Contains(player_1));
+ EXPECT_EQ(impl->GetTotalEventCountForTesting(), kMaxCachedPlayerEvents);
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 0f4a5bc0de5..01b59279f19 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -46,10 +46,10 @@
#include "services/network/public/mojom/websocket.mojom-blink.h"
#include "third_party/blink/public/common/loader/referrer_utils.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_effective_connection_type.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -78,6 +78,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
+#include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -322,14 +323,15 @@ KURL UrlWithoutFragment(const KURL& url) {
return result;
}
-String MixedContentTypeForContextType(WebMixedContentContextType context_type) {
+String MixedContentTypeForContextType(
+ mojom::blink::MixedContentContextType context_type) {
switch (context_type) {
- case WebMixedContentContextType::kNotMixedContent:
+ case mojom::blink::MixedContentContextType::kNotMixedContent:
return protocol::Security::MixedContentTypeEnum::None;
- case WebMixedContentContextType::kBlockable:
+ case mojom::blink::MixedContentContextType::kBlockable:
return protocol::Security::MixedContentTypeEnum::Blockable;
- case WebMixedContentContextType::kOptionallyBlockable:
- case WebMixedContentContextType::kShouldBeBlockable:
+ case mojom::blink::MixedContentContextType::kOptionallyBlockable:
+ case mojom::blink::MixedContentContextType::kShouldBeBlockable:
return protocol::Security::MixedContentTypeEnum::OptionallyBlockable;
}
@@ -370,8 +372,6 @@ String BuildBlockedReason(ResourceRequestBlockedReason reason) {
case ResourceRequestBlockedReason::kContentType:
return protocol::Network::BlockedReasonEnum::ContentType;
case ResourceRequestBlockedReason::kOther:
- case ResourceRequestBlockedReason::
- kBlockedByExtensionCrbug1128174Investigation:
return protocol::Network::BlockedReasonEnum::Other;
case ResourceRequestBlockedReason::kCollapsedByClient:
return protocol::Network::BlockedReasonEnum::CollapsedByClient;
@@ -390,6 +390,11 @@ String BuildBlockedReason(ResourceRequestBlockedReason reason) {
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
case blink::ResourceRequestBlockedReason::kCorpNotSameSite:
return protocol::Network::BlockedReasonEnum::CorpNotSameSite;
+ case ResourceRequestBlockedReason::kConversionRequest:
+ // This is actually never reached, as the conversion request
+ // is marked as successful and no blocking reason is reported.
+ NOTREACHED();
+ return protocol::Network::BlockedReasonEnum::Other;
}
NOTREACHED();
return protocol::Network::BlockedReasonEnum::Other;
@@ -529,13 +534,8 @@ String GetReferrerPolicy(network::mojom::ReferrerPolicy policy) {
case network::mojom::ReferrerPolicy::kAlways:
return protocol::Network::Request::ReferrerPolicyEnum::UnsafeUrl;
case network::mojom::ReferrerPolicy::kDefault:
- if (ReferrerUtils::IsReducedReferrerGranularityEnabled()) {
- return protocol::Network::Request::ReferrerPolicyEnum::
- StrictOriginWhenCrossOrigin;
- } else {
- return protocol::Network::Request::ReferrerPolicyEnum::
- NoReferrerWhenDowngrade;
- }
+ return protocol::Network::Request::ReferrerPolicyEnum::
+ StrictOriginWhenCrossOrigin;
case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
return protocol::Network::Request::ReferrerPolicyEnum::
NoReferrerWhenDowngrade;
@@ -985,6 +985,19 @@ void InspectorNetworkAgent::DidBlockRequest(
ResourceResponse(), initiator_info, type);
String request_id = IdentifiersFactory::RequestId(loader, identifier);
+
+ // Conversion Measurement API triggers recording of conversions
+ // as redirects to a `/.well-known/register-conversion` url.
+ // The redirect request is not actually executed
+ // but stored internally and then aborted. As the redirect is blocked using
+ // the ResourceRequestBlockedReason::kConversionRequest even when everything
+ // worked out fine, we mark the request as successful, as to not confuse devs.
+ if (reason == ResourceRequestBlockedReason::kConversionRequest) {
+ GetFrontend()->loadingFinished(
+ request_id, base::TimeTicks::Now().since_origin().InSecondsF(), 0);
+ return;
+ }
+
String protocol_reason = BuildBlockedReason(reason);
GetFrontend()->loadingFailed(
request_id, base::TimeTicks::Now().since_origin().InSecondsF(),
@@ -1028,10 +1041,14 @@ void InspectorNetworkAgent::WillSendRequestInternal(
resources_data_->ResourceCreated(request_id, loader_id, request.Url(),
post_data);
- if (initiator_info.name == fetch_initiator_type_names::kXmlhttprequest)
+ if (initiator_info.name == fetch_initiator_type_names::kXmlhttprequest) {
type = InspectorPageAgent::kXHRResource;
- else if (initiator_info.name == fetch_initiator_type_names::kFetch)
+ } else if (initiator_info.name == fetch_initiator_type_names::kFetch) {
type = InspectorPageAgent::kFetchResource;
+ } else if (initiator_info.name == fetch_initiator_type_names::kBeacon ||
+ initiator_info.name == fetch_initiator_type_names::kPing) {
+ type = InspectorPageAgent::kPingResource;
+ }
if (pending_request_type_)
type = *pending_request_type_;
@@ -1193,7 +1210,8 @@ void InspectorNetworkAgent::WillSendRequest(
const ResourceRequest& request,
const ResourceResponse& redirect_response,
const FetchInitiatorInfo& initiator_info,
- ResourceType resource_type) {
+ ResourceType resource_type,
+ RenderBlockingBehavior render_blocking_behavior) {
// Ignore the request initiated internally.
if (initiator_info.name == fetch_initiator_type_names::kInternal)
return;
@@ -1235,7 +1253,8 @@ void InspectorNetworkAgent::DidReceiveResourceResponse(
saved_type == InspectorPageAgent::kXHRResource ||
saved_type == InspectorPageAgent::kDocumentResource ||
saved_type == InspectorPageAgent::kFetchResource ||
- saved_type == InspectorPageAgent::kEventSourceResource) {
+ saved_type == InspectorPageAgent::kEventSourceResource ||
+ saved_type == InspectorPageAgent::kPingResource) {
type = saved_type;
}
@@ -1681,6 +1700,46 @@ void InspectorNetworkAgent::DidReceiveWebSocketMessageError(
base::TimeTicks::Now().since_origin().InSecondsF(), error_message);
}
+void InspectorNetworkAgent::WebTransportCreated(
+ ExecutionContext* execution_context,
+ uint64_t transport_id,
+ const KURL& request_url) {
+ std::unique_ptr<v8_inspector::protocol::Runtime::API::StackTrace>
+ current_stack_trace =
+ SourceLocation::Capture(execution_context)->BuildInspectorObject();
+ if (!current_stack_trace) {
+ GetFrontend()->webTransportCreated(
+ IdentifiersFactory::SubresourceRequestId(transport_id),
+ UrlWithoutFragment(request_url).GetString(),
+ base::TimeTicks::Now().since_origin().InSecondsF());
+ return;
+ }
+
+ std::unique_ptr<protocol::Network::Initiator> initiator_object =
+ protocol::Network::Initiator::create()
+ .setType(protocol::Network::Initiator::TypeEnum::Script)
+ .build();
+ initiator_object->setStack(std::move(current_stack_trace));
+ GetFrontend()->webTransportCreated(
+ IdentifiersFactory::SubresourceRequestId(transport_id),
+ UrlWithoutFragment(request_url).GetString(),
+ base::TimeTicks::Now().since_origin().InSecondsF(),
+ std::move(initiator_object));
+}
+
+void InspectorNetworkAgent::WebTransportConnectionEstablished(
+ uint64_t transport_id) {
+ GetFrontend()->webTransportConnectionEstablished(
+ IdentifiersFactory::SubresourceRequestId(transport_id),
+ base::TimeTicks::Now().since_origin().InSecondsF());
+}
+
+void InspectorNetworkAgent::WebTransportClosed(uint64_t transport_id) {
+ GetFrontend()->webTransportClosed(
+ IdentifiersFactory::SubresourceRequestId(transport_id),
+ base::TimeTicks::Now().since_origin().InSecondsF());
+}
+
Response InspectorNetworkAgent::enable(Maybe<int> total_buffer_size,
Maybe<int> resource_buffer_size,
Maybe<int> max_post_data_size) {
@@ -1759,8 +1818,7 @@ void InspectorNetworkAgent::GetResponseBodyBlob(
InspectorFileReaderLoaderClient* client = new InspectorFileReaderLoaderClient(
blob, context->GetTaskRunner(TaskType::kFileReading),
WTF::Bind(ResponseBodyFileReaderLoaderDone, resource_data->MimeType(),
- resource_data->TextEncodingName(),
- WTF::Passed(std::move(callback))));
+ resource_data->TextEncodingName(), std::move(callback)));
client->Start();
}
@@ -2116,4 +2174,9 @@ ExecutionContext* InspectorNetworkAgent::GetTargetExecutionContext() const {
return inspected_frames_->Root()->DomWindow();
}
+void InspectorNetworkAgent::IsCacheDisabled(bool* is_cache_disabled) const {
+ if (cache_disabled_.Get())
+ *is_cache_disabled = true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
index 6b2507344dc..c844fb40a1a 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_network_agent.h
@@ -64,6 +64,7 @@ class LocalFrame;
class HTTPHeaderMap;
class KURL;
class NetworkResourcesData;
+enum class RenderBlockingBehavior : uint8_t;
class Resource;
class ResourceError;
class ResourceResponse;
@@ -106,7 +107,8 @@ class CORE_EXPORT InspectorNetworkAgent final
const ResourceRequest&,
const ResourceResponse& redirect_response,
const FetchInitiatorInfo&,
- ResourceType);
+ ResourceType,
+ RenderBlockingBehavior);
void WillSendNavigationRequest(uint64_t identifier,
DocumentLoader*,
const KURL&,
@@ -196,7 +198,15 @@ class CORE_EXPORT InspectorNetworkAgent final
const char* payload,
size_t payload_length);
void DidReceiveWebSocketMessageError(uint64_t identifier, const String&);
+
+ void WebTransportCreated(ExecutionContext*,
+ uint64_t transport_id,
+ const KURL& request_url);
+ void WebTransportConnectionEstablished(uint64_t transport_id);
+ void WebTransportClosed(uint64_t transport_id);
+
void SetDevToolsIds(ResourceRequest& request, const FetchInitiatorInfo&);
+ void IsCacheDisabled(bool* is_cache_disabled) const;
// Called from frontend
protocol::Response enable(Maybe<int> total_buffer_size,
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index 45b8f3a62bc..ebc89ebbed4 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -35,11 +35,11 @@
#include "base/auto_reset.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/resources/grit/inspector_overlay_resources_map.h"
-#include "third_party/blink/public/web/web_widget_client.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_inspector_overlay_host.h"
@@ -56,7 +56,7 @@
#include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -111,7 +111,7 @@ bool ParseQuad(std::unique_ptr<protocol::Array<double>> quad_array,
// OverlayNames ----------------------------------------------------------------
const char* OverlayNames::OVERLAY_HIGHLIGHT = "highlight";
-const char* OverlayNames::OVERLAY_HIGHLIGHT_GRID = "highlightGrid";
+const char* OverlayNames::OVERLAY_PERSISTENT = "persistent";
const char* OverlayNames::OVERLAY_SOURCE_ORDER = "sourceOrder";
const char* OverlayNames::OVERLAY_DISTANCES = "distances";
const char* OverlayNames::OVERLAY_VIEWPORT_SIZE = "viewportSize";
@@ -280,7 +280,7 @@ class InspectorOverlayAgent::InspectorPageOverlayDelegate final
// The overlay frame is has a standalone paint property tree. Paint it in
// its root space into a paint record, then draw the record into the proper
// target space in the overlaid frame.
- PaintRecordBuilder paint_record_builder(nullptr, &graphics_context);
+ PaintRecordBuilder paint_record_builder(graphics_context);
overlay_->OverlayMainFrame()->View()->PaintOutsideOfLifecycle(
paint_record_builder.Context(), kGlobalPaintNormalPhase);
graphics_context.DrawRecord(paint_record_builder.EndRecording());
@@ -295,7 +295,9 @@ class InspectorOverlayAgent::InspectorPageOverlayDelegate final
private:
// cc::ContentLayerClient implementation
- gfx::Rect PaintableRegion() override { return gfx::Rect(layer_->bounds()); }
+ gfx::Rect PaintableRegion() const override {
+ return gfx::Rect(layer_->bounds());
+ }
bool FillsBoundsCompletely() const override { return false; }
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() override {
@@ -360,6 +362,9 @@ InspectorOverlayAgent::InspectorOverlayAgent(
v8_session_(v8_session),
dom_agent_(dom_agent),
swallow_next_mouse_up_(false),
+ original_layer_tree_debug_state_(
+ std::make_unique<cc::LayerTreeDebugState>(
+ GetFrame()->GetWidgetForLocalRoot()->GetLayerTreeDebugState())),
backend_node_id_to_inspect_(0),
enabled_(&agent_state_, false),
show_ad_highlights_(&agent_state_, false),
@@ -369,6 +374,7 @@ InspectorOverlayAgent::InspectorOverlayAgent(
show_layout_shift_regions_(&agent_state_, false),
show_scroll_bottleneck_rects_(&agent_state_, false),
show_hit_test_borders_(&agent_state_, false),
+ show_web_vitals_(&agent_state_, false),
show_size_on_resize_(&agent_state_, false),
paused_in_debugger_message_(&agent_state_, String()),
inspect_mode_(&agent_state_, protocol::Overlay::InspectModeEnum::None),
@@ -384,6 +390,7 @@ void InspectorOverlayAgent::Trace(Visitor* visitor) const {
visitor->Trace(overlay_page_);
visitor->Trace(overlay_chrome_client_);
visitor->Trace(overlay_host_);
+ visitor->Trace(resize_timer_);
visitor->Trace(dom_agent_);
visitor->Trace(inspect_tool_);
visitor->Trace(persistent_tool_);
@@ -435,16 +442,14 @@ void InspectorOverlayAgent::EnsureAXContext(Node* node) {
Response InspectorOverlayAgent::disable() {
enabled_.Clear();
setShowAdHighlights(false);
- setShowDebugBorders(false);
- setShowFPSCounter(false);
- setShowPaintRects(false);
- setShowLayoutShiftRegions(false);
- setShowScrollBottleneckRects(false);
- setShowHitTestBorders(false);
setShowViewportSizeOnResize(false);
paused_in_debugger_message_.Clear();
inspect_mode_.Set(protocol::Overlay::InspectModeEnum::None);
inspect_mode_protocol_config_.Set(std::vector<uint8_t>());
+
+ GetFrame()->GetWidgetForLocalRoot()->SetLayerTreeDebugState(
+ *original_layer_tree_debug_state_);
+
if (overlay_page_) {
overlay_page_->WillBeDestroyed();
overlay_page_.Clear();
@@ -475,18 +480,13 @@ Response InspectorOverlayAgent::setShowDebugBorders(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- if (show)
- debug_state.show_debug_borders.set();
- else
- debug_state.show_debug_borders.reset();
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ if (show)
+ debug_state.show_debug_borders.set();
+ else
+ debug_state.show_debug_borders.reset();
+ widget->SetLayerTreeDebugState(debug_state);
return Response::Success();
}
@@ -497,15 +497,10 @@ Response InspectorOverlayAgent::setShowFPSCounter(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- debug_state.show_fps_counter = show;
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_fps_counter = show;
+ widget->SetLayerTreeDebugState(debug_state);
return Response::Success();
}
@@ -516,15 +511,10 @@ Response InspectorOverlayAgent::setShowPaintRects(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- debug_state.show_paint_rects = show;
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_paint_rects = show;
+ widget->SetLayerTreeDebugState(debug_state);
if (!show && frame_impl_->GetFrameView())
frame_impl_->GetFrameView()->Invalidate();
return Response::Success();
@@ -537,15 +527,10 @@ Response InspectorOverlayAgent::setShowLayoutShiftRegions(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- debug_state.show_layout_shift_regions = show;
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_layout_shift_regions = show;
+ widget->SetLayerTreeDebugState(debug_state);
if (!show && frame_impl_->GetFrameView())
frame_impl_->GetFrameView()->Invalidate();
@@ -559,18 +544,13 @@ Response InspectorOverlayAgent::setShowScrollBottleneckRects(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- debug_state.show_touch_event_handler_rects = show;
- debug_state.show_wheel_event_handler_rects = show;
- debug_state.show_non_fast_scrollable_rects = show;
- debug_state.show_main_thread_scrolling_reason_rects = show;
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_touch_event_handler_rects = show;
+ debug_state.show_wheel_event_handler_rects = show;
+ debug_state.show_non_fast_scrollable_rects = show;
+ debug_state.show_main_thread_scrolling_reason_rects = show;
+ widget->SetLayerTreeDebugState(debug_state);
return Response::Success();
}
@@ -582,15 +562,10 @@ Response InspectorOverlayAgent::setShowHitTestBorders(bool show) {
if (!response.IsSuccess())
return response;
}
- WebFrameWidget* widget = frame_impl_->LocalRoot()->FrameWidget();
- WebFrameWidgetBase* widget_impl = static_cast<WebFrameWidgetBase*>(widget);
- // While a frame is being detached the inspector will shutdown and
- // turn off debug overlays, but the WebFrameWidget is already gone.
- if (widget_impl) {
- cc::LayerTreeDebugState debug_state = widget_impl->GetLayerTreeDebugState();
- debug_state.show_hit_test_borders = show;
- widget_impl->SetLayerTreeDebugState(debug_state);
- }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_hit_test_borders = show;
+ widget->SetLayerTreeDebugState(debug_state);
return Response::Success();
}
@@ -599,6 +574,20 @@ Response InspectorOverlayAgent::setShowViewportSizeOnResize(bool show) {
return Response::Success();
}
+Response InspectorOverlayAgent::setShowWebVitals(bool show) {
+ show_web_vitals_.Set(show);
+ if (show) {
+ Response response = CompositingEnabled();
+ if (!response.IsSuccess())
+ return response;
+ }
+ FrameWidget* widget = GetFrame()->GetWidgetForLocalRoot();
+ cc::LayerTreeDebugState debug_state = widget->GetLayerTreeDebugState();
+ debug_state.show_web_vital_metrics = show;
+ widget->SetLayerTreeDebugState(debug_state);
+ return Response::Success();
+}
+
Response InspectorOverlayAgent::setPausedInDebuggerMessage(
Maybe<String> message) {
paused_in_debugger_message_.Set(message.fromMaybe(String()));
@@ -706,24 +695,56 @@ Response InspectorOverlayAgent::highlightNode(
Response InspectorOverlayAgent::setShowGridOverlays(
std::unique_ptr<protocol::Array<protocol::Overlay::GridNodeHighlightConfig>>
grid_node_highlight_configs) {
- persistent_tool_ = nullptr;
+ if (!persistent_tool_) {
+ persistent_tool_ =
+ MakeGarbageCollected<PersistentTool>(this, GetFrontend());
+ }
- if (grid_node_highlight_configs->size()) {
- GridHighlightTool* grid_tool =
- MakeGarbageCollected<GridHighlightTool>(this, GetFrontend());
- for (std::unique_ptr<protocol::Overlay::GridNodeHighlightConfig>& config :
- *grid_node_highlight_configs) {
- Node* node = nullptr;
- Response response = dom_agent_->AssertNode(config->getNodeId(), node);
- if (!response.IsSuccess())
- return response;
- grid_tool->AddGridConfig(node,
- InspectorOverlayAgent::ToGridHighlightConfig(
- config->getGridHighlightConfig()));
- }
- persistent_tool_ = grid_tool;
+ Vector<std::pair<Member<Node>, std::unique_ptr<InspectorGridHighlightConfig>>>
+ configs;
+ for (std::unique_ptr<protocol::Overlay::GridNodeHighlightConfig>& config :
+ *grid_node_highlight_configs) {
+ Node* node = nullptr;
+ Response response = dom_agent_->AssertNode(config->getNodeId(), node);
+ if (!response.IsSuccess())
+ return response;
+ configs.push_back(
+ std::make_pair(node, InspectorOverlayAgent::ToGridHighlightConfig(
+ config->getGridHighlightConfig())));
+ }
+
+ persistent_tool_->SetGridConfigs(std::move(configs));
+
+ PickTheRightTool();
+
+ return Response::Success();
+}
+
+Response InspectorOverlayAgent::setShowFlexOverlays(
+ std::unique_ptr<protocol::Array<protocol::Overlay::FlexNodeHighlightConfig>>
+ flex_node_highlight_configs) {
+ if (!persistent_tool_) {
+ persistent_tool_ =
+ MakeGarbageCollected<PersistentTool>(this, GetFrontend());
+ }
+
+ Vector<std::pair<Member<Node>,
+ std::unique_ptr<InspectorFlexContainerHighlightConfig>>>
+ configs;
+
+ for (std::unique_ptr<protocol::Overlay::FlexNodeHighlightConfig>& config :
+ *flex_node_highlight_configs) {
+ Node* node = nullptr;
+ Response response = dom_agent_->AssertNode(config->getNodeId(), node);
+ if (!response.IsSuccess())
+ return response;
+ configs.push_back(std::make_pair(
+ node, InspectorOverlayAgent::ToFlexContainerHighlightConfig(
+ config->getFlexContainerHighlightConfig())));
}
+ persistent_tool_->SetFlexContainerConfigs(std::move(configs));
+
PickTheRightTool();
return Response::Success();
@@ -810,6 +831,8 @@ Response InspectorOverlayAgent::getHighlightObjectForTest(
config->color_format = ColorFormat::HEX;
}
+ node->GetDocument().EnsurePaintLocationDataValidForNode(
+ node, DocumentUpdateReason::kInspector);
NodeHighlightTool tool(this, GetFrontend(), node, "" /* selector_list */,
std::move(config));
*result = tool.GetNodeInspectorHighlightAsJson(
@@ -820,17 +843,20 @@ Response InspectorOverlayAgent::getHighlightObjectForTest(
Response InspectorOverlayAgent::getGridHighlightObjectsForTest(
std::unique_ptr<protocol::Array<int>> node_ids,
std::unique_ptr<protocol::DictionaryValue>* highlights) {
- GridHighlightTool grid_highlight_tool(this, GetFrontend());
+ PersistentTool persistent_tool(this, GetFrontend());
+ Vector<std::pair<Member<Node>, std::unique_ptr<InspectorGridHighlightConfig>>>
+ configs;
for (const int node_id : *node_ids) {
Node* node = nullptr;
Response response = dom_agent_->AssertNode(node_id, node);
if (!response.IsSuccess())
return response;
- grid_highlight_tool.AddGridConfig(
- node, std::make_unique<InspectorGridHighlightConfig>(
- InspectorHighlight::DefaultGridConfig()));
+ configs.push_back(
+ std::make_pair(node, std::make_unique<InspectorGridHighlightConfig>(
+ InspectorHighlight::DefaultGridConfig())));
}
- *highlights = grid_highlight_tool.GetGridInspectorHighlightsAsJson();
+ persistent_tool.SetGridConfigs(std::move(configs));
+ *highlights = persistent_tool.GetGridInspectorHighlightsAsJson();
return Response::Success();
}
@@ -882,6 +908,10 @@ void InspectorOverlayAgent::DispatchBufferedTouchEvents() {
OverlayMainFrame()->GetEventHandler().DispatchBufferedTouchEvents();
}
+void InspectorOverlayAgent::SetPageIsScrolling(bool is_scrolling) {
+ is_page_scrolling_ = is_scrolling;
+}
+
WebInputEventResult InspectorOverlayAgent::HandleInputEvent(
const WebInputEvent& input_event) {
if (!enabled_.Get())
@@ -1009,9 +1039,13 @@ void InspectorOverlayAgent::PaintOverlayPage() {
float scale = WindowToViewportScale();
if (inspect_tool_) {
- inspect_tool_->Draw(scale);
- if (persistent_tool_ && inspect_tool_->SupportsPersistentOverlays())
+ // Skip drawing persistent_tool_ on page scroll.
+ if (!(inspect_tool_ == persistent_tool_ && is_page_scrolling_))
+ inspect_tool_->Draw(scale);
+ if (persistent_tool_ && inspect_tool_->SupportsPersistentOverlays() &&
+ !is_page_scrolling_) {
persistent_tool_->Draw(scale);
+ }
}
if (hinge_)
@@ -1050,7 +1084,8 @@ void InspectorOverlayAgent::LoadOverlayPageResource() {
overlay_chrome_client_ = MakeGarbageCollected<InspectorOverlayChromeClient>(
GetFrame()->GetPage()->GetChromeClient(), *this);
page_clients.chrome_client = overlay_chrome_client_.Get();
- overlay_page_ = Page::CreateNonOrdinary(page_clients);
+ overlay_page_ = Page::CreateNonOrdinary(
+ page_clients, *GetFrame()->GetFrameScheduler()->GetAgentGroupScheduler());
overlay_host_ = MakeGarbageCollected<InspectorOverlayHost>(this);
Settings& settings = GetFrame()->GetPage()->GetSettings();
@@ -1081,8 +1116,8 @@ void InspectorOverlayAgent::LoadOverlayPageResource() {
(MakeGarbageCollected<EmptyLocalFrameClient>()));
auto* frame = MakeGarbageCollected<LocalFrame>(
dummy_local_frame_client, *overlay_page_, nullptr, nullptr, nullptr,
- FrameInsertType::kInsertInConstructor, base::UnguessableToken::Create(),
- nullptr, nullptr, /* policy_container */ nullptr);
+ FrameInsertType::kInsertInConstructor, LocalFrameToken(), nullptr,
+ nullptr, /* policy_container */ nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame));
frame->Init(nullptr);
frame->View()->SetCanHaveScrollbars(false);
@@ -1171,7 +1206,7 @@ void InspectorOverlayAgent::EvaluateInOverlay(const String& method,
")",
ScriptSourceLocationType::kInspector))
->RunScript(To<LocalFrame>(OverlayMainFrame())->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
}
void InspectorOverlayAgent::EvaluateInOverlay(
@@ -1190,7 +1225,7 @@ void InspectorOverlayAgent::EvaluateInOverlay(
")",
ScriptSourceLocationType::kInspector))
->RunScript(To<LocalFrame>(OverlayMainFrame())->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
}
String InspectorOverlayAgent::EvaluateInOverlayForTest(const String& script) {
@@ -1201,7 +1236,7 @@ String InspectorOverlayAgent::EvaluateInOverlayForTest(const String& script) {
ScriptSourceCode(script, ScriptSourceLocationType::kInspector))
->RunScriptAndReturnValue(
To<LocalFrame>(OverlayMainFrame())->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
return ToCoreStringWithUndefinedOrNullCheck(string);
}
@@ -1300,6 +1335,9 @@ Response InspectorOverlayAgent::setInspectMode(
void InspectorOverlayAgent::PickTheRightTool() {
InspectTool* inspect_tool = nullptr;
+ if (persistent_tool_ && persistent_tool_->IsEmpty())
+ persistent_tool_ = nullptr;
+
String inspect_mode = inspect_mode_.Get();
if (inspect_mode == protocol::Overlay::InspectModeEnum::SearchForNode ||
inspect_mode ==
@@ -1495,16 +1533,47 @@ InspectorOverlayAgent::ToFlexContainerHighlightConfig(
highlight_config->item_separator =
InspectorOverlayAgent::ToLineStyle(config->getItemSeparator(nullptr));
+ highlight_config->main_distributed_space = InspectorOverlayAgent::ToBoxStyle(
+ config->getMainDistributedSpace(nullptr));
+ highlight_config->cross_distributed_space = InspectorOverlayAgent::ToBoxStyle(
+ config->getCrossDistributedSpace(nullptr));
+ highlight_config->row_gap_space =
+ InspectorOverlayAgent::ToBoxStyle(config->getRowGapSpace(nullptr));
+ highlight_config->column_gap_space =
+ InspectorOverlayAgent::ToBoxStyle(config->getColumnGapSpace(nullptr));
+ highlight_config->cross_alignment =
+ InspectorOverlayAgent::ToLineStyle(config->getCrossAlignment(nullptr));
+
return highlight_config;
}
// static
-std::unique_ptr<LineStyle> InspectorOverlayAgent::ToLineStyle(
- protocol::Overlay::LineStyle* config) {
+std::unique_ptr<InspectorFlexItemHighlightConfig>
+InspectorOverlayAgent::ToFlexItemHighlightConfig(
+ protocol::Overlay::FlexItemHighlightConfig* config) {
if (!config) {
return nullptr;
}
- std::unique_ptr<LineStyle> line_style = std::make_unique<LineStyle>();
+ std::unique_ptr<InspectorFlexItemHighlightConfig> highlight_config =
+ std::make_unique<InspectorFlexItemHighlightConfig>();
+
+ highlight_config->base_size_box =
+ InspectorOverlayAgent::ToBoxStyle(config->getBaseSizeBox(nullptr));
+ highlight_config->base_size_border =
+ InspectorOverlayAgent::ToLineStyle(config->getBaseSizeBorder(nullptr));
+ highlight_config->flexibility_arrow =
+ InspectorOverlayAgent::ToLineStyle(config->getFlexibilityArrow(nullptr));
+
+ return highlight_config;
+}
+
+// static
+base::Optional<LineStyle> InspectorOverlayAgent::ToLineStyle(
+ protocol::Overlay::LineStyle* config) {
+ if (!config) {
+ return base::nullopt;
+ }
+ base::Optional<LineStyle> line_style = LineStyle();
line_style->color = InspectorDOMAgent::ParseColor(config->getColor(nullptr));
line_style->pattern = config->getPattern("solid");
@@ -1512,6 +1581,32 @@ std::unique_ptr<LineStyle> InspectorOverlayAgent::ToLineStyle(
}
// static
+base::Optional<BoxStyle> InspectorOverlayAgent::ToBoxStyle(
+ protocol::Overlay::BoxStyle* config) {
+ if (!config) {
+ return base::nullopt;
+ }
+ base::Optional<BoxStyle> box_style = BoxStyle();
+ box_style->fill_color =
+ InspectorDOMAgent::ParseColor(config->getFillColor(nullptr));
+ box_style->hatch_color =
+ InspectorDOMAgent::ParseColor(config->getHatchColor(nullptr));
+
+ return box_style;
+}
+
+ContrastAlgorithm GetContrastAlgorithm(const String& contrast_algorithm) {
+ namespace ContrastAlgorithmEnum = protocol::Overlay::ContrastAlgorithmEnum;
+ if (contrast_algorithm == ContrastAlgorithmEnum::Aaa) {
+ return ContrastAlgorithm::AAA;
+ } else if (contrast_algorithm == ContrastAlgorithmEnum::Apca) {
+ return ContrastAlgorithm::APCA;
+ } else {
+ return ContrastAlgorithm::AA;
+ }
+}
+
+// static
std::unique_ptr<InspectorHighlightConfig>
InspectorOverlayAgent::ToHighlightConfig(
protocol::Overlay::HighlightConfig* config) {
@@ -1552,6 +1647,10 @@ InspectorOverlayAgent::ToHighlightConfig(
highlight_config->color_format = ColorFormat::HEX;
}
+ namespace ContrastAlgorithmEnum = protocol::Overlay::ContrastAlgorithmEnum;
+ highlight_config->contrast_algorithm = GetContrastAlgorithm(
+ config->getContrastAlgorithm(ContrastAlgorithmEnum::Aa));
+
highlight_config->grid_highlight_config =
InspectorOverlayAgent::ToGridHighlightConfig(
config->getGridHighlightConfig(nullptr));
@@ -1559,6 +1658,11 @@ InspectorOverlayAgent::ToHighlightConfig(
highlight_config->flex_container_highlight_config =
InspectorOverlayAgent::ToFlexContainerHighlightConfig(
config->getFlexContainerHighlightConfig(nullptr));
+
+ highlight_config->flex_item_highlight_config =
+ InspectorOverlayAgent::ToFlexItemHighlightConfig(
+ config->getFlexItemHighlightConfig(nullptr));
+
return highlight_config;
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index 0a2bb507cf2..bc94c21d292 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -53,6 +53,7 @@
namespace cc {
class Layer;
+class LayerTreeDebugState;
}
namespace blink {
@@ -72,7 +73,7 @@ class WebLocalFrameImpl;
class WebPointerEvent;
class InspectorOverlayAgent;
-class GridHighlightTool;
+class PersistentTool;
using OverlayFrontend = protocol::Overlay::Metainfo::FrontendClass;
@@ -80,7 +81,7 @@ using OverlayFrontend = protocol::Overlay::Metainfo::FrontendClass;
class OverlayNames {
public:
static const char* OVERLAY_HIGHLIGHT;
- static const char* OVERLAY_HIGHLIGHT_GRID;
+ static const char* OVERLAY_PERSISTENT;
static const char* OVERLAY_SOURCE_ORDER;
static const char* OVERLAY_DISTANCES;
static const char* OVERLAY_VIEWPORT_SIZE;
@@ -148,7 +149,10 @@ class CORE_EXPORT InspectorOverlayAgent final
static std::unique_ptr<InspectorFlexContainerHighlightConfig>
ToFlexContainerHighlightConfig(
protocol::Overlay::FlexContainerHighlightConfig*);
- static std::unique_ptr<LineStyle> ToLineStyle(protocol::Overlay::LineStyle*);
+ static std::unique_ptr<InspectorFlexItemHighlightConfig>
+ ToFlexItemHighlightConfig(protocol::Overlay::FlexItemHighlightConfig*);
+ static base::Optional<LineStyle> ToLineStyle(protocol::Overlay::LineStyle*);
+ static base::Optional<BoxStyle> ToBoxStyle(protocol::Overlay::BoxStyle*);
static std::unique_ptr<InspectorHighlightConfig> ToHighlightConfig(
protocol::Overlay::HighlightConfig*);
InspectorOverlayAgent(WebLocalFrameImpl*,
@@ -168,6 +172,7 @@ class CORE_EXPORT InspectorOverlayAgent final
protocol::Response setShowFPSCounter(bool) override;
protocol::Response setShowScrollBottleneckRects(bool) override;
protocol::Response setShowHitTestBorders(bool) override;
+ protocol::Response setShowWebVitals(bool) override;
protocol::Response setShowViewportSizeOnResize(bool) override;
protocol::Response setPausedInDebuggerMessage(
protocol::Maybe<String>) override;
@@ -220,6 +225,10 @@ class CORE_EXPORT InspectorOverlayAgent final
std::unique_ptr<
protocol::Array<protocol::Overlay::GridNodeHighlightConfig>>
grid_node_highlight_configs) override;
+ protocol::Response setShowFlexOverlays(
+ std::unique_ptr<
+ protocol::Array<protocol::Overlay::FlexNodeHighlightConfig>>
+ flex_node_highlight_configs) override;
// InspectorBaseAgent overrides.
void Restore() override;
@@ -228,6 +237,7 @@ class CORE_EXPORT InspectorOverlayAgent final
void Inspect(Node*);
void EnsureAXContext(Node*);
void DispatchBufferedTouchEvents();
+ void SetPageIsScrolling(bool is_scrolling);
WebInputEventResult HandleInputEvent(const WebInputEvent&);
WebInputEventResult HandleInputEventInOverlay(const WebInputEvent&);
void PageLayoutInvalidated(bool resized);
@@ -285,19 +295,22 @@ class CORE_EXPORT InspectorOverlayAgent final
Member<InspectorOverlayChromeClient> overlay_chrome_client_;
Member<InspectorOverlayHost> overlay_host_;
bool resize_timer_active_;
- TaskRunnerTimer<InspectorOverlayAgent> resize_timer_;
+ HeapTaskRunnerTimer<InspectorOverlayAgent> resize_timer_;
bool disposed_;
v8_inspector::V8InspectorSession* v8_session_;
Member<InspectorDOMAgent> dom_agent_;
std::unique_ptr<FrameOverlay> frame_overlay_;
Member<InspectTool> inspect_tool_;
- Member<GridHighlightTool> persistent_tool_;
+ Member<PersistentTool> persistent_tool_;
Member<Hinge> hinge_;
// The agent needs to keep AXContext because it enables caching of
// a11y attributes shown in the inspector overlay.
HeapHashMap<WeakMember<Document>, std::unique_ptr<AXContext>>
document_to_ax_context_;
bool swallow_next_mouse_up_;
+ bool is_page_scrolling_ = false;
+ std::unique_ptr<cc::LayerTreeDebugState> original_layer_tree_debug_state_;
+
DOMNodeId backend_node_id_to_inspect_;
InspectorAgentState::Boolean enabled_;
InspectorAgentState::Boolean show_ad_highlights_;
@@ -307,6 +320,7 @@ class CORE_EXPORT InspectorOverlayAgent final
InspectorAgentState::Boolean show_layout_shift_regions_;
InspectorAgentState::Boolean show_scroll_bottleneck_rects_;
InspectorAgentState::Boolean show_hit_test_borders_;
+ InspectorAgentState::Boolean show_web_vitals_;
InspectorAgentState::Boolean show_size_on_resize_;
InspectorAgentState::String paused_in_debugger_message_;
InspectorAgentState::String inspect_mode_;
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 9876247dbf1..e45ddcb1f7f 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
#include <memory>
+#include <utility>
#include "base/containers/span.h"
#include "build/build_config.h"
@@ -42,6 +43,7 @@
#include "third_party/blink/renderer/core/dom/document_timing.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/execution_context/agent.h"
+#include "third_party/blink/renderer/core/feature_policy/feature_policy_devtools_support.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/local_frame_client.h"
@@ -377,13 +379,13 @@ bool InspectorPageAgent::CachedResourceContent(const Resource* cached_resource,
switch (cached_resource->GetType()) {
case blink::ResourceType::kCSSStyleSheet:
MaybeEncodeTextContent(
- ToCSSStyleSheetResource(cached_resource)
+ To<CSSStyleSheetResource>(cached_resource)
->SheetText(nullptr, CSSStyleSheetResource::MIMETypeCheck::kLax),
cached_resource->ResourceBuffer(), result, base64_encoded);
return true;
case blink::ResourceType::kScript:
MaybeEncodeTextContent(
- ToScriptResource(cached_resource)->TextForInspector(),
+ To<ScriptResource>(cached_resource)->TextForInspector(),
cached_resource->ResourceBuffer(), result, base64_encoded);
return true;
default:
@@ -428,6 +430,8 @@ String InspectorPageAgent::ResourceTypeJson(
return protocol::Network::ResourceTypeEnum::Manifest;
case kSignedExchangeResource:
return protocol::Network::ResourceTypeEnum::SignedExchange;
+ case kPingResource:
+ return protocol::Network::ResourceTypeEnum::Ping;
case kOtherResource:
return protocol::Network::ResourceTypeEnum::Other;
}
@@ -772,8 +776,7 @@ void InspectorPageAgent::getResourceContent(
resource_content_loader_client_id_,
WTF::Bind(
&InspectorPageAgent::GetResourceContentAfterResourcesContentLoaded,
- WrapPersistent(this), frame_id, url,
- WTF::Passed(std::move(callback))));
+ WrapPersistent(this), frame_id, url, std::move(callback)));
}
void InspectorPageAgent::SearchContentAfterResourcesContentLoaded(
@@ -824,8 +827,7 @@ void InspectorPageAgent::searchInResource(
WTF::Bind(&InspectorPageAgent::SearchContentAfterResourcesContentLoaded,
WrapPersistent(this), frame_id, url, query,
optional_case_sensitive.fromMaybe(false),
- optional_is_regex.fromMaybe(false),
- WTF::Passed(std::move(callback))));
+ optional_is_regex.fromMaybe(false), std::move(callback)));
}
Response InspectorPageAgent::setBypassCSP(bool enabled) {
@@ -835,6 +837,76 @@ Response InspectorPageAgent::setBypassCSP(bool enabled) {
return Response::Success();
}
+namespace {
+
+std::unique_ptr<protocol::Page::PermissionsPolicyBlockLocator>
+CreatePermissionsPolicyBlockLocator(
+ const blink::FeaturePolicyBlockLocator& locator) {
+ protocol::Page::PermissionsPolicyBlockReason reason;
+ switch (locator.reason) {
+ case blink::FeaturePolicyBlockReason::kHeader:
+ reason = protocol::Page::PermissionsPolicyBlockReasonEnum::Header;
+ break;
+ case blink::FeaturePolicyBlockReason::kIframeAttribute:
+ reason =
+ protocol::Page::PermissionsPolicyBlockReasonEnum::IframeAttribute;
+ break;
+ }
+
+ return protocol::Page::PermissionsPolicyBlockLocator::create()
+ .setFrameId(locator.frame_id)
+ .setBlockReason(reason)
+ .build();
+}
+} // namespace
+
+Response InspectorPageAgent::getPermissionsPolicyState(
+ const String& frame_id,
+ std::unique_ptr<
+ protocol::Array<protocol::Page::PermissionsPolicyFeatureState>>*
+ states) {
+ LocalFrame* frame =
+ IdentifiersFactory::FrameById(inspected_frames_, frame_id);
+
+ if (!frame)
+ return Response::ServerError("No frame for given id found in this target");
+
+ const blink::FeaturePolicy* feature_policy =
+ frame->GetSecurityContext()->GetFeaturePolicy();
+
+ if (!feature_policy)
+ return Response::ServerError("Frame not ready");
+
+ auto feature_states = std::make_unique<
+ protocol::Array<protocol::Page::PermissionsPolicyFeatureState>>();
+
+ for (const auto& entry : blink::GetDefaultFeatureNameMap()) {
+ const String& feature_name = entry.key;
+ const mojom::blink::FeaturePolicyFeature feature = entry.value;
+
+ if (blink::DisabledByOriginTrial(feature_name, frame->DomWindow()))
+ continue;
+
+ base::Optional<blink::FeaturePolicyBlockLocator> locator =
+ blink::TraceFeaturePolicyBlockSource(frame, feature);
+
+ std::unique_ptr<protocol::Page::PermissionsPolicyFeatureState>
+ feature_state =
+ protocol::Page::PermissionsPolicyFeatureState::create()
+ .setFeature(blink::PermissionsPolicyFeatureToProtocol(feature))
+ .setAllowed(!locator.has_value())
+ .build();
+
+ if (locator.has_value())
+ feature_state->setLocator(CreatePermissionsPolicyBlockLocator(*locator));
+
+ feature_states->push_back(std::move(feature_state));
+ }
+
+ *states = std::move(feature_states);
+ return Response::Success();
+}
+
Response InspectorPageAgent::setDocumentContent(const String& frame_id,
const String& html) {
LocalFrame* frame =
@@ -898,7 +970,7 @@ void InspectorPageAgent::DidClearDocumentOfWindowObject(LocalFrame* frame) {
if (world_name.IsEmpty()) {
ClassicScript::CreateUnspecifiedScript(ScriptSourceCode(source))
->RunScript(frame->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
continue;
}
@@ -919,7 +991,7 @@ void InspectorPageAgent::DidClearDocumentOfWindowObject(LocalFrame* frame) {
ClassicScript::CreateUnspecifiedScript(
ScriptSourceCode(script_to_evaluate_on_load_once_))
->RunScript(frame->DomWindow(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
}
}
@@ -947,6 +1019,13 @@ void InspectorPageAgent::WillCommitLoad(LocalFrame*, DocumentLoader* loader) {
GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame()));
}
+void InspectorPageAgent::DidOpenDocument(LocalFrame* frame,
+ DocumentLoader* loader) {
+ GetFrontend()->documentOpened(BuildObjectForFrame(loader->GetFrame()));
+ LifecycleEvent(frame, loader, "init",
+ base::TimeTicks::Now().since_origin().InSecondsF());
+}
+
void InspectorPageAgent::FrameAttachedToParent(LocalFrame* frame) {
Frame* parent_frame = frame->Tree().Parent();
std::unique_ptr<SourceLocation> location =
@@ -1124,6 +1203,7 @@ CreateGatedAPIFeaturesArray(LocalDOMWindow* window) {
// and performance.profile() once they are gated/available, respectively.
return features;
}
+
} // namespace
std::unique_ptr<protocol::Page::Frame> InspectorPageAgent::BuildObjectForFrame(
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
index faeb95d448f..a256ce80265 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -84,6 +84,7 @@ class CORE_EXPORT InspectorPageAgent final
kWebSocketResource,
kManifestResource,
kSignedExchangeResource,
+ kPingResource,
kOtherResource
};
@@ -141,6 +142,12 @@ class CORE_EXPORT InspectorPageAgent final
const String& html) override;
protocol::Response setBypassCSP(bool enabled) override;
+ protocol::Response getPermissionsPolicyState(
+ const String& frame_id,
+ std::unique_ptr<
+ protocol::Array<protocol::Page::PermissionsPolicyFeatureState>>*)
+ override;
+
protocol::Response startScreencast(Maybe<String> format,
Maybe<int> quality,
Maybe<int> max_width,
@@ -175,6 +182,7 @@ class CORE_EXPORT InspectorPageAgent final
void DomContentLoadedEventFired(LocalFrame*);
void LoadEventFired(LocalFrame*);
void WillCommitLoad(LocalFrame*, DocumentLoader*);
+ void DidOpenDocument(LocalFrame*, DocumentLoader*);
void FrameAttachedToParent(LocalFrame*);
void FrameDetachedFromParent(LocalFrame*, FrameDetachType);
void FrameStartedLoading(LocalFrame*);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc
new file mode 100644
index 00000000000..64df06b5574
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc
@@ -0,0 +1,218 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h"
+
+#include <utility>
+
+#include "build/build_config.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.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/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
+#include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
+#include "third_party/blink/renderer/core/timing/layout_shift.h"
+#include "third_party/blink/renderer/core/timing/layout_shift_attribution.h"
+#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
+
+namespace blink {
+
+namespace {
+
+constexpr PerformanceEntryType kSupportedTypes =
+ PerformanceEntry::EntryType::kLargestContentfulPaint |
+ PerformanceEntry::EntryType::kLayoutShift;
+
+double ToProtocolTime(DOMHighResTimeStamp timeOrigin,
+ DOMHighResTimeStamp time) {
+ return time ? ConvertDOMHighResTimeStampToSeconds(timeOrigin + time) : 0.0;
+}
+
+std::unique_ptr<protocol::PerformanceTimeline::LargestContentfulPaint>
+BuildEventDetails(const LargestContentfulPaint& lcp,
+ DOMHighResTimeStamp timeOrigin) {
+ auto result = protocol::PerformanceTimeline::LargestContentfulPaint::create()
+ .setRenderTime(ToProtocolTime(timeOrigin, lcp.renderTime()))
+ .setLoadTime(ToProtocolTime(timeOrigin, lcp.loadTime()))
+ .setSize(lcp.size())
+ .build();
+ if (!lcp.id().IsEmpty())
+ result->setElementId(lcp.id());
+ if (Element* element = lcp.element())
+ result->setNodeId(IdentifiersFactory::IntIdForNode(element));
+ if (!lcp.url().IsEmpty())
+ result->setUrl(lcp.url());
+ return result;
+}
+
+std::unique_ptr<protocol::DOM::Rect> BuildRect(DOMRectReadOnly* rect) {
+ return protocol::DOM::Rect::create()
+ .setX(rect->x())
+ .setY(rect->y())
+ .setWidth(rect->width())
+ .setHeight(rect->height())
+ .build();
+}
+
+std::unique_ptr<
+ protocol::Array<protocol::PerformanceTimeline::LayoutShiftAttribution>>
+BuildLayoutShiftAttributions(const LayoutShift::AttributionList& attributions) {
+ auto result = std::make_unique<
+ protocol::Array<protocol::PerformanceTimeline::LayoutShiftAttribution>>();
+ for (const auto& attr : attributions) {
+ auto entry = protocol::PerformanceTimeline::LayoutShiftAttribution::create()
+ .setPreviousRect(BuildRect(attr->previousRect()))
+ .setCurrentRect(BuildRect(attr->currentRect()))
+ .build();
+ if (Node* node = attr->rawNodeForInspector())
+ entry->setNodeId(IdentifiersFactory::IntIdForNode(node));
+ result->push_back(std::move(entry));
+ }
+ return result;
+}
+
+std::unique_ptr<protocol::PerformanceTimeline::LayoutShift> BuildEventDetails(
+ const LayoutShift& ls,
+ DOMHighResTimeStamp timeOrigin) {
+ auto result =
+ protocol::PerformanceTimeline::LayoutShift::create()
+ .setValue(ls.value())
+ .setHadRecentInput(ls.hadRecentInput())
+ .setLastInputTime(ToProtocolTime(timeOrigin, ls.lastInputTime()))
+ .setSources(BuildLayoutShiftAttributions(ls.sources()))
+ .build();
+ return result;
+}
+
+std::unique_ptr<protocol::PerformanceTimeline::TimelineEvent>
+BuildProtocolEvent(String frame_id,
+ DOMHighResTimeStamp timeOrigin,
+ PerformanceEntry* entry) {
+ auto result = protocol::PerformanceTimeline::TimelineEvent::create()
+ .setFrameId(frame_id)
+ .setType(entry->entryType())
+ .setName(entry->name())
+ // TODO(caseq): entry time is clamped; consider exposing an
+ // unclamped time.
+ .setTime(ToProtocolTime(timeOrigin, entry->startTime()))
+ .build();
+ if (entry->duration())
+ result->setDuration(ConvertDOMHighResTimeStampToSeconds(entry->duration()));
+ if (auto* lcp = DynamicTo<LargestContentfulPaint>(entry))
+ result->setLcpDetails(BuildEventDetails(*lcp, timeOrigin));
+ else if (auto* ls = DynamicTo<LayoutShift>(entry))
+ result->setLayoutShiftDetails(BuildEventDetails(*ls, timeOrigin));
+ return result;
+}
+
+} // namespace
+
+using protocol::Response;
+
+InspectorPerformanceTimelineAgent::InspectorPerformanceTimelineAgent(
+ InspectedFrames* inspected_frames)
+ : inspected_frames_(inspected_frames),
+ enabled_types_(&agent_state_, /*default_value=*/false) {}
+
+InspectorPerformanceTimelineAgent::~InspectorPerformanceTimelineAgent() =
+ default;
+
+void InspectorPerformanceTimelineAgent::Trace(Visitor* visitor) const {
+ visitor->Trace(inspected_frames_);
+ InspectorBaseAgent<protocol::PerformanceTimeline::Metainfo>::Trace(visitor);
+}
+
+void InspectorPerformanceTimelineAgent::Restore() {
+ if (IsEnabled())
+ InnerEnable();
+}
+
+void InspectorPerformanceTimelineAgent::InnerEnable() {
+ DCHECK(IsEnabled());
+ instrumenting_agents_->AddInspectorPerformanceTimelineAgent(this);
+}
+
+void InspectorPerformanceTimelineAgent::PerformanceEntryAdded(
+ ExecutionContext* context,
+ PerformanceEntry* entry) {
+ if (!(entry->EntryTypeEnum() & enabled_types_.Get()))
+ return;
+ String frame_id;
+ Performance* performance = nullptr;
+ if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+ frame_id = IdentifiersFactory::FrameId(window->GetFrame());
+ performance = DOMWindowPerformance::performance(*window);
+ } else if (auto* global_scope = DynamicTo<WorkerGlobalScope>(context)) {
+ performance = WorkerGlobalScopePerformance::performance(*global_scope);
+ } else {
+ NOTREACHED() << "Unexpected subtype of ExecutionContext";
+ }
+ GetFrontend()->timelineEventAdded(
+ BuildProtocolEvent(frame_id, performance->timeOrigin(), entry));
+}
+
+protocol::Response InspectorPerformanceTimelineAgent::enable(
+ std::unique_ptr<protocol::Array<String>> entry_types) {
+ EventsVector buffered_events;
+
+ const int old_types = enabled_types_.Get();
+ PerformanceEntryType new_types = 0;
+ for (const auto& type_str : *entry_types) {
+ AtomicString type_atomic(type_str);
+ PerformanceEntryType type_enum =
+ PerformanceEntry::ToEntryTypeEnum(type_atomic);
+ if (type_enum == PerformanceEntry::EntryType::kInvalid ||
+ (type_enum & kSupportedTypes) != type_enum) {
+ return Response::InvalidParams("Unknown or unsupported entry type");
+ }
+
+ // Gather buffered entries for types that haven't been enabled previously
+ // (but disregard duplicate type specifiers).
+ if (!(old_types & type_enum) && !(new_types & type_enum))
+ CollectEntries(type_atomic, &buffered_events);
+ new_types |= type_enum;
+ }
+ enabled_types_.Set(new_types);
+ if (!old_types != !new_types) {
+ if (!new_types)
+ return disable();
+ InnerEnable();
+ }
+ for (auto& event : buffered_events)
+ GetFrontend()->timelineEventAdded(std::move(event));
+
+ return Response::Success();
+}
+
+protocol::Response InspectorPerformanceTimelineAgent::disable() {
+ enabled_types_.Clear();
+ instrumenting_agents_->RemoveInspectorPerformanceTimelineAgent(this);
+ return Response::Success();
+}
+
+bool InspectorPerformanceTimelineAgent::IsEnabled() const {
+ return !!enabled_types_.Get();
+}
+
+void InspectorPerformanceTimelineAgent::CollectEntries(AtomicString type,
+ EventsVector* events) {
+ for (LocalFrame* frame : *inspected_frames_) {
+ String frame_id = IdentifiersFactory::FrameId(frame);
+ LocalDOMWindow* window = frame->DomWindow();
+ if (!window)
+ continue;
+ WindowPerformance* performance = DOMWindowPerformance::performance(*window);
+ for (Member<PerformanceEntry> entry :
+ performance->getBufferedEntriesByType(type)) {
+ events->push_back(
+ BuildProtocolEvent(frame_id, performance->timeOrigin(), entry));
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h b/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h
new file mode 100644
index 00000000000..94c106d2b30
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/task/sequence_manager/task_time_observer.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
+#include "third_party/blink/renderer/core/inspector/protocol/PerformanceTimeline.h"
+
+namespace blink {
+
+class ExecutionContext;
+class InspectedFrames;
+class PerformanceEntry;
+
+class CORE_EXPORT InspectorPerformanceTimelineAgent final
+ : public InspectorBaseAgent<protocol::PerformanceTimeline::Metainfo> {
+ public:
+ explicit InspectorPerformanceTimelineAgent(InspectedFrames*);
+ ~InspectorPerformanceTimelineAgent() override;
+
+ // PerformanceTimeline probes implementation.
+ void PerformanceEntryAdded(ExecutionContext*, PerformanceEntry*);
+
+ void Trace(Visitor*) const override;
+
+ private:
+ // Performance protocol domain implementation.
+ protocol::Response enable(
+ std::unique_ptr<protocol::Array<String>> event_types) override;
+ protocol::Response disable() override;
+ void Restore() override;
+
+ void InnerEnable();
+ bool IsEnabled() const;
+
+ using EventsVector =
+ protocol::Array<protocol::PerformanceTimeline::TimelineEvent>;
+ void CollectEntries(AtomicString type, EventsVector* events);
+
+ Member<InspectedFrames> inspected_frames_;
+ InspectorAgentState::Integer enabled_types_;
+ DISALLOW_COPY_AND_ASSIGN(InspectorPerformanceTimelineAgent);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json b/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
index 99fc5eb5213..2efe99a33bd 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
@@ -82,6 +82,9 @@
"domain": "Performance"
},
{
+ "domain": "PerformanceTimeline"
+ },
+ {
"domain": "Emulation",
"include": ["forceViewport", "resetViewport", "resetPageScaleFactor", "setPageScaleFactor", "setScriptExecutionDisabled", "setTouchEmulationEnabled",
"setEmulatedMedia", "setEmulatedVisionDeficiency", "setCPUThrottlingRate", "setVirtualTimePolicy", "setTimezoneOverride", "setNavigatorOverrides", "setDefaultBackgroundColorOverride", "setDeviceMetricsOverride", "clearDeviceMetricsOverride",
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
index 4bbc3b032b6..7ee0a9519de 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
@@ -25,6 +25,14 @@
namespace blink {
+namespace {
+
+bool ShouldSkipFetchingUrl(const KURL& url) {
+ return !url.IsValid() || url.IsAboutBlankURL() || url.IsAboutSrcdocURL();
+}
+
+} // namespace
+
// NOTE: While this is a RawResourceClient, it loads both raw and css stylesheet
// resources. Stylesheets can only safely use a RawResourceClient because it has
// no custom interface and simply uses the base ResourceClient.
@@ -105,7 +113,7 @@ void InspectorResourceContentLoader::Start() {
scoped_refptr<const DOMWrapperWorld> world =
document->GetExecutionContext()->GetCurrentWorld();
- if (!resource_request.Url().GetString().IsEmpty()) {
+ if (!ShouldSkipFetchingUrl(resource_request.Url())) {
urls_to_fetch.insert(resource_request.Url().GetString());
ResourceLoaderOptions options(world);
options.initiator_info.name = fetch_initiator_type_names::kInternal;
@@ -124,7 +132,7 @@ void InspectorResourceContentLoader::Start() {
if (style_sheet->IsInline() || !style_sheet->Contents()->LoadCompleted())
continue;
String url = style_sheet->href();
- if (url.IsEmpty() || urls_to_fetch.Contains(url))
+ if (ShouldSkipFetchingUrl(KURL(url)) || urls_to_fetch.Contains(url))
continue;
urls_to_fetch.insert(url);
ResourceRequest style_sheet_resource_request(url);
@@ -148,8 +156,10 @@ void InspectorResourceContentLoader::Start() {
// TODO (alexrudenko): This code duplicates the code in manifest_manager.cc
// and manifest_fetcher.cc. Move it to a shared place.
HTMLLinkElement* link_element = document->LinkManifest();
- if (link_element) {
- auto link = link_element->Href();
+ KURL link;
+ if (link_element)
+ link = link_element->Href();
+ if (!ShouldSkipFetchingUrl(link)) {
auto use_credentials = EqualIgnoringASCIICase(
link_element->FastGetAttribute(html_names::kCrossoriginAttr),
"use-credentials");
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.cc
index b1e28c70af2..c7b3803a7e3 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state.cc
@@ -128,7 +128,7 @@ void InspectorAgentState::Serialize(const WTF::String& v,
bool InspectorAgentState::Deserialize(span<uint8_t> in, WTF::String* v) {
CBORTokenizer tokenizer(in);
if (tokenizer.TokenTag() == CBORTokenTag::STRING8) {
- *v = WTF::String(
+ *v = WTF::String::FromUTF8(
reinterpret_cast<const char*>(tokenizer.GetString8().data()),
static_cast<size_t>(tokenizer.GetString8().size()));
return true;
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
index 9b632b8b80d..99dccbf98fc 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
@@ -82,10 +82,14 @@ TEST(InspectorSessionStateTest, SimpleFields) {
simple_agent.counter_.Set(311);
simple_agent.bytes_.Set({0xde, 0xad, 0xbe, 0xef});
+ // Test that Latin1 is handled properly
+ simple_agent.message_.Set("\xC7 cedilla");
+
EXPECT_EQ(true, simple_agent.enabled_.Get());
EXPECT_EQ(11.0, simple_agent.field1_.Get());
EXPECT_EQ(42.0, simple_agent.multiplier_.Get());
EXPECT_EQ(311, simple_agent.counter_.Get());
+ EXPECT_EQ("\xC7 cedilla", simple_agent.message_.Get());
EXPECT_THAT(simple_agent.bytes_.Get(), ElementsAre(0xde, 0xad, 0xbe, 0xef));
// Now send the updates back to the browser session.
@@ -101,6 +105,7 @@ TEST(InspectorSessionStateTest, SimpleFields) {
EXPECT_EQ(11.0, simple_agent.field1_.Get());
EXPECT_EQ(42.0, simple_agent.multiplier_.Get());
EXPECT_EQ(311, simple_agent.counter_.Get());
+ EXPECT_EQ("\xC7 cedilla", simple_agent.message_.Get());
EXPECT_THAT(simple_agent.bytes_.Get(), ElementsAre(0xde, 0xad, 0xbe, 0xef));
simple_agent.enabled_.Set(false);
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
index 2999c84ade5..464f53c0685 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
@@ -1565,7 +1565,8 @@ InspectorStyleSheet::BuildObjectForStyleSheetInfo() {
std::unique_ptr<protocol::Array<protocol::CSS::Value>>
InspectorStyleSheet::SelectorsFromSource(CSSRuleSourceData* source_data,
const String& sheet_text) {
- ScriptRegexp comment("/\\*[^]*?\\*/", kTextCaseSensitive, kMultilineEnabled);
+ auto* comment = MakeGarbageCollected<ScriptRegexp>(
+ "/\\*[^]*?\\*/", kTextCaseSensitive, kMultilineEnabled);
auto result = std::make_unique<protocol::Array<protocol::CSS::Value>>();
const Vector<SourceRange>& ranges = source_data->selector_ranges;
for (wtf_size_t i = 0, size = ranges.size(); i < size; ++i) {
@@ -1576,7 +1577,7 @@ InspectorStyleSheet::SelectorsFromSource(CSSRuleSourceData* source_data,
// meaningful parts.
int match_length;
int offset = 0;
- while ((offset = comment.Match(selector, offset, &match_length)) >= 0)
+ while ((offset = comment->Match(selector, offset, &match_length)) >= 0)
selector.replace(offset, match_length, "");
std::unique_ptr<protocol::CSS::Value> simple_selector =
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index 26d7b214fad..e2988783258 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -113,6 +113,25 @@ void SetCallStack(TracedValue* value) {
v8::CpuProfiler::CollectSample(v8::Isolate::GetCurrent());
}
+void SetCallStack(perfetto::TracedDictionary& dict) {
+ static const unsigned char* trace_category_enabled = nullptr;
+ WTF_ANNOTATE_BENIGN_RACE(&trace_category_enabled, "trace_event category");
+ if (!trace_category_enabled) {
+ trace_category_enabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"));
+ }
+ if (!*trace_category_enabled)
+ return;
+ // The CPU profiler stack trace does not include call site line numbers.
+ // So we collect the top frame with SourceLocation::capture() to get the
+ // binding call site info.
+ auto source_location = SourceLocation::Capture();
+ if (source_location->HasStackTrace()) {
+ dict.Add("stackTrace", source_location);
+ }
+ v8::CpuProfiler::CollectSample(v8::Isolate::GetCurrent());
+}
+
void InspectorTraceEvents::WillSendRequest(
uint64_t identifier,
DocumentLoader* loader,
@@ -120,12 +139,12 @@ void InspectorTraceEvents::WillSendRequest(
const ResourceRequest& request,
const ResourceResponse& redirect_response,
const FetchInitiatorInfo&,
- ResourceType) {
+ ResourceType,
+ RenderBlockingBehavior render_blocking_behavior) {
LocalFrame* frame = loader ? loader->GetFrame() : nullptr;
- TRACE_EVENT_INSTANT1(
- "devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD,
- "data",
- inspector_send_request_event::Data(loader, identifier, frame, request));
+ DEVTOOLS_TIMELINE_TRACE_EVENT_INSTANT(
+ "ResourceSendRequest", inspector_send_request_event::Data, loader,
+ identifier, frame, request, render_blocking_behavior);
}
void InspectorTraceEvents::WillSendNavigationRequest(
@@ -299,6 +318,7 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) {
DEFINE_STRING_MAPPING(PseudoEnabled)
DEFINE_STRING_MAPPING(PseudoFullPageMedia)
DEFINE_STRING_MAPPING(PseudoDefault)
+ DEFINE_STRING_MAPPING(PseudoDir)
DEFINE_STRING_MAPPING(PseudoDisabled)
DEFINE_STRING_MAPPING(PseudoOptional)
DEFINE_STRING_MAPPING(PseudoPlaceholderShown)
@@ -316,6 +336,7 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) {
DEFINE_STRING_MAPPING(PseudoLang)
DEFINE_STRING_MAPPING(PseudoNot)
DEFINE_STRING_MAPPING(PseudoPlaceholder)
+ DEFINE_STRING_MAPPING(PseudoFileSelectorButton)
DEFINE_STRING_MAPPING(PseudoResizer)
DEFINE_STRING_MAPPING(PseudoRoot)
DEFINE_STRING_MAPPING(PseudoScope)
@@ -351,12 +372,9 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) {
DEFINE_STRING_MAPPING(PseudoCue)
DEFINE_STRING_MAPPING(PseudoFutureCue)
DEFINE_STRING_MAPPING(PseudoPastCue)
- DEFINE_STRING_MAPPING(PseudoUnresolved)
DEFINE_STRING_MAPPING(PseudoDefined)
- DEFINE_STRING_MAPPING(PseudoContent)
DEFINE_STRING_MAPPING(PseudoHost)
DEFINE_STRING_MAPPING(PseudoHostContext)
- DEFINE_STRING_MAPPING(PseudoShadow)
DEFINE_STRING_MAPPING(PseudoSlotted)
DEFINE_STRING_MAPPING(PseudoSpatialNavigationFocus)
DEFINE_STRING_MAPPING(PseudoSpatialNavigationInterest)
@@ -364,12 +382,15 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) {
DEFINE_STRING_MAPPING(PseudoIsHtml)
DEFINE_STRING_MAPPING(PseudoListBox)
DEFINE_STRING_MAPPING(PseudoMultiSelectFocus)
+ DEFINE_STRING_MAPPING(PseudoPopupOpen)
DEFINE_STRING_MAPPING(PseudoHostHasAppearance)
DEFINE_STRING_MAPPING(PseudoVideoPersistent)
DEFINE_STRING_MAPPING(PseudoVideoPersistentAncestor)
DEFINE_STRING_MAPPING(PseudoXrOverlay)
DEFINE_STRING_MAPPING(PseudoTargetText)
DEFINE_STRING_MAPPING(PseudoModal)
+ DEFINE_STRING_MAPPING(PseudoSpellingError)
+ DEFINE_STRING_MAPPING(PseudoGrammarError)
#undef DEFINE_STRING_MAPPING
}
@@ -434,6 +455,8 @@ const char* NotStreamedReasonString(ScriptStreamer::NotStreamingReason reason) {
return "no data pipe received";
case ScriptStreamer::NotStreamingReason::kDisabledByFeatureList:
return "streaming disabled from the feature list";
+ case ScriptStreamer::NotStreamingReason::kNonJavascriptModule:
+ return "not a javascript module";
case ScriptStreamer::NotStreamingReason::kLoadingCancelled:
return "loading was cancelled";
case ScriptStreamer::NotStreamingReason::kDidntTryToStartStreaming:
@@ -714,6 +737,7 @@ const char kFullscreen[] = "Fullscreen change";
const char kChildChanged[] = "Child changed";
const char kListValueChange[] = "List value change";
const char kListStyleTypeChange[] = "List style type change";
+const char kCounterStyleChange[] = "Counter style change";
const char kImageChanged[] = "Image changed";
const char kLineBoxesChanged[] = "Line boxes changed";
const char kSliderValueChanged[] = "Slider value changed";
@@ -733,6 +757,7 @@ const char kTextControlChanged[] = "Text control changed";
const char kSvgChanged[] = "SVG changed";
const char kScrollbarChanged[] = "Scrollbar changed";
const char kDisplayLock[] = "Display lock";
+const char kCanvasFormattedTextRunChange[] = "CanvasFormattedText runs changed";
} // namespace layout_invalidation_reason
std::unique_ptr<TracedValue> inspector_layout_invalidation_tracking_event::Data(
@@ -760,22 +785,47 @@ std::unique_ptr<TracedValue> inspector_change_resource_priority_event::Data(
return value;
}
-std::unique_ptr<TracedValue> inspector_send_request_event::Data(
+void inspector_send_request_event::Data(
+ perfetto::TracedValue context,
DocumentLoader* loader,
uint64_t identifier,
LocalFrame* frame,
- const ResourceRequest& request) {
- auto value = std::make_unique<TracedValue>();
- value->SetString("requestId",
- IdentifiersFactory::RequestId(loader, identifier));
- value->SetString("frame", IdentifiersFactory::FrameId(frame));
- value->SetString("url", request.Url().GetString());
- value->SetString("requestMethod", request.HttpMethod());
+ const ResourceRequest& request,
+ RenderBlockingBehavior render_blocking_behavior) {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("requestId", IdentifiersFactory::RequestId(loader, identifier));
+ dict.Add("frame", IdentifiersFactory::FrameId(frame));
+ dict.Add("url", request.Url().GetString());
+ dict.Add("requestMethod", request.HttpMethod());
+ String render_blocking_string;
+ switch (render_blocking_behavior) {
+ case RenderBlockingBehavior::kUnset:
+ break;
+ case RenderBlockingBehavior::kBlocking:
+ render_blocking_string = "blocking";
+ break;
+ case RenderBlockingBehavior::kNonBlocking:
+ render_blocking_string = "non_blocking";
+ break;
+ case RenderBlockingBehavior::kNonBlockingDynamic:
+ render_blocking_string = "dynamically_injected_non_blocking";
+ break;
+ case RenderBlockingBehavior::kInBodyParserBlocking:
+ render_blocking_string = "in_body_parser_blocking";
+ break;
+ case RenderBlockingBehavior::kPotentiallyBlocking:
+ render_blocking_string = "potentially_blocking";
+ break;
+ default:
+ NOTREACHED();
+ }
+ if (!render_blocking_string.IsNull()) {
+ dict.Add("renderBlocking", render_blocking_string);
+ }
const char* priority = ResourcePriorityString(request.Priority());
if (priority)
- value->SetString("priority", priority);
- SetCallStack(value.get());
- return value;
+ dict.Add("priority", priority);
+ SetCallStack(dict);
}
std::unique_ptr<TracedValue> inspector_send_navigation_request_event::Data(
diff --git a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
index 87e71d568a2..fb22e553b89 100644
--- a/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
+++ b/chromium/third_party/blink/renderer/core/inspector/inspector_trace_events.h
@@ -64,6 +64,7 @@ class LocalFrameView;
class Node;
struct PhysicalRect;
class QualifiedName;
+enum class RenderBlockingBehavior : uint8_t;
class Resource;
class ResourceError;
class ResourceRequest;
@@ -91,7 +92,8 @@ class CORE_EXPORT InspectorTraceEvents
const ResourceRequest&,
const ResourceResponse& redirect_response,
const FetchInitiatorInfo&,
- ResourceType);
+ ResourceType,
+ RenderBlockingBehavior);
void WillSendNavigationRequest(uint64_t identifier,
DocumentLoader*,
const KURL&,
@@ -138,6 +140,13 @@ class CORE_EXPORT InspectorTraceEvents
DISALLOW_COPY_AND_ASSIGN(InspectorTraceEvents);
};
+#define DEVTOOLS_TIMELINE_TRACE_EVENT_INSTANT(event_name, function_name, ...) \
+ TRACE_EVENT_INSTANT1("devtools.timeline", event_name, \
+ TRACE_EVENT_SCOPE_THREAD, "data", \
+ [&](perfetto::TracedValue ctx) { \
+ function_name(std::move(ctx), __VA_ARGS__); \
+ })
+
namespace inspector_layout_event {
std::unique_ptr<TracedValue> BeginData(LocalFrameView*);
std::unique_ptr<TracedValue> EndData(LayoutObject* root_for_this_layout);
@@ -238,6 +247,7 @@ extern const char kFullscreen[];
extern const char kChildChanged[];
extern const char kListValueChange[];
extern const char kListStyleTypeChange[];
+extern const char kCounterStyleChange[];
extern const char kImageChanged[];
extern const char kLineBoxesChanged[];
extern const char kSliderValueChanged[];
@@ -259,6 +269,7 @@ extern const char kTextControlChanged[];
extern const char kSvgChanged[];
extern const char kScrollbarChanged[];
extern const char kDisplayLock[];
+extern CORE_EXPORT const char kCanvasFormattedTextRunChange[];
} // namespace layout_invalidation_reason
// LayoutInvalidationReasonForTracing is strictly for tracing. Blink logic must
@@ -277,10 +288,12 @@ std::unique_ptr<TracedValue> Data(DocumentLoader*,
}
namespace inspector_send_request_event {
-std::unique_ptr<TracedValue> Data(DocumentLoader*,
- uint64_t identifier,
- LocalFrame*,
- const ResourceRequest&);
+void Data(perfetto::TracedValue context,
+ DocumentLoader*,
+ uint64_t identifier,
+ LocalFrame*,
+ const ResourceRequest&,
+ RenderBlockingBehavior);
}
namespace inspector_send_navigation_request_event {
diff --git a/chromium/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc b/chromium/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
index 8fa9faad6a7..2e48c1e7d00 100644
--- a/chromium/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
@@ -125,7 +125,7 @@ Response LegacyDOMSnapshotAgent::GetSnapshot(
// Look up the CSSPropertyIDs for each entry in |style_filter|.
for (const String& entry : *style_filter) {
CSSPropertyID property_id =
- cssPropertyID(document->GetExecutionContext(), entry);
+ CssPropertyID(document->GetExecutionContext(), entry);
if (property_id == CSSPropertyID::kInvalid)
continue;
css_property_filter_->emplace_back(entry, property_id);
diff --git a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
index 99b030ac6be..d36df061d6e 100644
--- a/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/network_resources_data.cc
@@ -121,8 +121,8 @@ size_t NetworkResourcesData::ResourceData::EvictContent() {
void NetworkResourcesData::ResourceData::SetResource(
const Resource* cached_resource) {
cached_resource_ = cached_resource;
- if (cached_resource && cached_resource->GetType() == ResourceType::kFont)
- ToFontResource(cached_resource)->AddClearDataObserver(this);
+ if (const auto* font_resource = DynamicTo<FontResource>(cached_resource))
+ font_resource->AddClearDataObserver(this);
}
void NetworkResourcesData::ResourceData::ProcessCustomWeakness(
diff --git a/chromium/third_party/blink/renderer/core/inspector/node_content_visibility_state.h b/chromium/third_party/blink/renderer/core/inspector/node_content_visibility_state.h
new file mode 100644
index 00000000000..1006ad148d6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/inspector/node_content_visibility_state.h
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_NODE_CONTENT_VISIBILITY_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_NODE_CONTENT_VISIBILITY_STATE_H_
+
+// The state of content visibility:
+// - kNone means that the node has no content-visibility interactions
+// - kIsLocked means that the node is itself locked and is skipping its
+// contents. However, the node is not in a subtree of a locked element.
+// - kIsLockedAncestor means that the initial node was in a locked subtree
+// so we instead are showing this ancestor.
+enum class NodeContentVisibilityState { kNone, kIsLocked, kIsLockedAncestor };
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_NODE_CONTENT_VISIBILITY_STATE_H_
diff --git a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
index db878a62dbc..bb4c3af1eaf 100644
--- a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.cc
@@ -6,6 +6,8 @@
#include <memory>
+#include "base/rand_util.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_binding_for_core.h"
@@ -24,6 +26,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_html.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script_url.h"
+#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h"
@@ -206,6 +209,43 @@ ThreadDebugger::descriptionForValueSubtype(v8::Local<v8::Context> context,
TrustedScriptURL* trusted_script_url =
V8TrustedScriptURL::ToImplWithTypeCheck(isolate_, value);
return ToV8InspectorStringBuffer(trusted_script_url->toString());
+ } else if (V8Node::HasInstance(value, isolate_)) {
+ Node* node = V8Node::ToImplWithTypeCheck(isolate_, value);
+ StringBuilder description;
+ switch (node->getNodeType()) {
+ case Node::kElementNode: {
+ const auto* element = To<blink::Element>(node);
+ description.Append(element->TagQName().ToString());
+
+ const AtomicString& id = element->GetIdAttribute();
+ if (!id.IsEmpty()) {
+ description.Append('#');
+ description.Append(id);
+ }
+ if (element->HasClass()) {
+ auto element_class_names = element->ClassNames();
+ auto n_classes = element_class_names.size();
+ for (unsigned i = 0; i < n_classes; ++i) {
+ description.Append('.');
+ description.Append(element_class_names[i]);
+ }
+ }
+ break;
+ }
+ case Node::kDocumentTypeNode: {
+ description.Append("<!DOCTYPE ");
+ description.Append(node->nodeName());
+ description.Append('>');
+ break;
+ }
+ default: {
+ description.Append(node->nodeName());
+ break;
+ }
+ }
+ DCHECK(description.length());
+
+ return ToV8InspectorStringBuffer(description.ToString());
}
return nullptr;
}
@@ -533,6 +573,12 @@ void ThreadDebugger::cancelTimer(void* data) {
}
}
+int64_t ThreadDebugger::generateUniqueId() {
+ int64_t result;
+ base::RandBytes(&result, sizeof result);
+ return result;
+}
+
void ThreadDebugger::OnTimer(TimerBase* timer) {
for (wtf_size_t index = 0; index < timers_.size(); ++index) {
if (timers_[index].get() == timer) {
diff --git a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.h b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.h
index 11d594b24bc..8b3019f0c68 100644
--- a/chromium/third_party/blink/renderer/core/inspector/thread_debugger.h
+++ b/chromium/third_party/blink/renderer/core/inspector/thread_debugger.h
@@ -98,6 +98,7 @@ class CORE_EXPORT ThreadDebugger : public v8_inspector::V8InspectorClient,
v8_inspector::V8InspectorClient::TimerCallback,
void* data) override;
void cancelTimer(void* data) override;
+ int64_t generateUniqueId() override;
void OnTimer(TimerBase*);
diff --git a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
index bfbc89b6495..214adc5d003 100644
--- a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
+++ b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -74,7 +74,13 @@ WorkerInspectorController::WorkerInspectorController(
: debugger_(debugger),
thread_(thread),
inspected_frames_(nullptr),
- probe_sink_(MakeGarbageCollected<CoreProbeSink>()) {
+ probe_sink_(MakeGarbageCollected<CoreProbeSink>()),
+ worker_thread_id_(base::PlatformThread::CurrentId()) {
+ // The constructor must run on the backing thread of |thread|. Otherwise, it
+ // would be incorrect to initialize |worker_thread_id_| with the current
+ // thread id.
+ DCHECK(thread->IsCurrentThread());
+
probe_sink_->AddInspectorIssueReporter(
MakeGarbageCollected<InspectorIssueReporter>(
thread->GetInspectorIssueStorage()));
@@ -83,7 +89,6 @@ WorkerInspectorController::WorkerInspectorController(
worker_devtools_token_ = devtools_params->devtools_worker_token;
parent_devtools_token_ = thread->GlobalScope()->GetParentDevToolsToken();
url_ = url;
- worker_thread_id_ = thread->GetPlatformThreadId();
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
Platform::Current()->GetIOTaskRunner();
if (!parent_devtools_token_.is_empty() && io_task_runner) {
@@ -120,7 +125,7 @@ void WorkerInspectorController::AttachSession(DevToolsSession* session,
session->Append(network_agent);
session->Append(MakeGarbageCollected<InspectorEmulationAgent>(nullptr));
session->Append(MakeGarbageCollected<InspectorAuditsAgent>(
- network_agent, thread_->GetInspectorIssueStorage()));
+ network_agent, thread_->GetInspectorIssueStorage(), nullptr));
}
++session_count_;
}
diff --git a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.h b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
index f6372dc9af3..4473f86f3b7 100644
--- a/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
+++ b/chromium/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
@@ -109,7 +109,7 @@ class WorkerInspectorController final
base::UnguessableToken worker_devtools_token_;
base::UnguessableToken parent_devtools_token_;
KURL url_;
- PlatformThreadId worker_thread_id_;
+ const PlatformThreadId worker_thread_id_;
DISALLOW_COPY_AND_ASSIGN(WorkerInspectorController);
};
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
index 67167416443..11fb86673e6 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
@@ -26,7 +26,7 @@ namespace {
// Return true if ancestor is in the containing block chain above descendant.
bool IsContainingBlockChainDescendant(const LayoutObject* descendant,
const LayoutObject* ancestor) {
- if (!ancestor || !descendant)
+ if (!ancestor || !descendant || ancestor == descendant)
return false;
LocalFrame* ancestor_frame = ancestor->GetDocument().GetFrame();
LocalFrame* descendant_frame = descendant->GetDocument().GetFrame();
@@ -97,24 +97,41 @@ PhysicalRect InitializeRootRect(const LayoutObject* root,
return result;
}
-// Return the bounding box of target in target's own coordinate system
-PhysicalRect InitializeTargetRect(const LayoutObject* target,
- unsigned flags,
- const Vector<Length>& margin,
- const LayoutObject* root) {
- PhysicalRect result;
+PhysicalRect GetBoxBounds(const LayoutBox* box, bool use_overflow_clip_edge) {
+ PhysicalRect bounds = PhysicalRect(box->BorderBoundingBox());
+ // OverflowClipMargin() should only apply if clipping occurs on both axis.
+ if (use_overflow_clip_edge && box->ShouldClipOverflowAlongBothAxis() &&
+ box->StyleRef().OverflowClipMargin() != LayoutUnit()) {
+ // OverflowClipRect() may be smaller than BorderBoundingBox().
+ bounds.Unite(box->OverflowClipRect(PhysicalOffset()));
+ }
+ return bounds;
+}
+
+// Return the bounding box of target in target's own coordinate system, also
+// return a bool indicating whether the target rect before margin application
+// was empty.
+std::pair<PhysicalRect, bool> InitializeTargetRect(const LayoutObject* target,
+ unsigned flags,
+ const Vector<Length>& margin,
+ const LayoutObject* root) {
+ std::pair<PhysicalRect, bool> result;
if ((flags & IntersectionGeometry::kShouldUseReplacedContentRect) &&
target->IsLayoutEmbeddedContent()) {
- result = To<LayoutEmbeddedContent>(target)->ReplacedContentRect();
+ result.first = To<LayoutEmbeddedContent>(target)->ReplacedContentRect();
} else if (target->IsBox()) {
- result = PhysicalRect(To<LayoutBox>(target)->BorderBoundingBox());
+ result.first =
+ GetBoxBounds(To<LayoutBox>(target),
+ (flags & IntersectionGeometry::kUseOverflowClipEdge) ==
+ IntersectionGeometry::kUseOverflowClipEdge);
} else if (target->IsLayoutInline()) {
- result = target->AbsoluteToLocalRect(
+ result.first = target->AbsoluteToLocalRect(
PhysicalRect::EnclosingRect(target->AbsoluteBoundingBoxFloatRect()));
} else {
- result = To<LayoutText>(target)->PhysicalLinesBoundingBox();
+ result.first = To<LayoutText>(target)->PhysicalLinesBoundingBox();
}
- ApplyMargin(result, margin, root->StyleRef().EffectiveZoom(),
+ result.second = result.first.IsEmpty();
+ ApplyMargin(result.first, margin, root->StyleRef().EffectiveZoom(),
InitializeRootRect(root, {} /* margin */));
return result;
}
@@ -159,8 +176,9 @@ LayoutObject* GetTargetLayoutObject(const Element& target_element) {
if (!target || (!target->IsBoxModelObject() && !target->IsText()))
return nullptr;
// If the target is inside a locked subtree, it isn't ever visible.
- if (UNLIKELY(DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
- target_element))) {
+ if (UNLIKELY(target->GetFrameView()->IsDisplayLocked() ||
+ DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
+ target_element))) {
return nullptr;
}
@@ -182,7 +200,8 @@ static const unsigned kConstructorFlagsMask =
IntersectionGeometry::kShouldTrackFractionOfRoot |
IntersectionGeometry::kShouldUseReplacedContentRect |
IntersectionGeometry::kShouldConvertToCSSPixels |
- IntersectionGeometry::kShouldUseCachedRects;
+ IntersectionGeometry::kShouldUseCachedRects |
+ IntersectionGeometry::kUseOverflowClipEdge;
} // namespace
@@ -221,10 +240,10 @@ const LayoutObject* IntersectionGeometry::GetRootLayoutObjectForTarget(
root = To<Document>(root_node)->GetLayoutView();
} else {
root = root_node->GetLayoutObject();
- if (target && check_containing_block_chain &&
- !IsContainingBlockChainDescendant(target, root)) {
- root = nullptr;
- }
+ }
+ if (target && check_containing_block_chain &&
+ !IsContainingBlockChainDescendant(target, root)) {
+ root = nullptr;
}
return root;
}
@@ -293,22 +312,30 @@ void IntersectionGeometry::ComputeGeometry(const RootGeometry& root_geometry,
// root_rect_ is in root's coordinate system
// The coordinate system for unclipped_intersection_rect_ depends on whether
// or not we can use previously cached geometry...
+ bool pre_margin_target_rect_is_empty;
if (ShouldUseCachedRects()) {
target_rect_ = cached_rects->local_target_rect;
+ pre_margin_target_rect_is_empty =
+ cached_rects->pre_margin_target_rect_is_empty;
+
// The cached intersection rect has already been mapped/clipped up to the
// root, except that the root's scroll offset and overflow clip have not
// been applied.
unclipped_intersection_rect_ =
cached_rects->unscrolled_unclipped_intersection_rect;
} else {
- target_rect_ = InitializeTargetRect(target, flags_, target_margin, root);
+ std::tie(target_rect_, pre_margin_target_rect_is_empty) =
+ InitializeTargetRect(target, flags_, target_margin, root);
// We have to map/clip target_rect_ up to the root, so we begin with the
// intersection rect in target's coordinate system. After ClipToRoot, it
// will be in root's coordinate system.
unclipped_intersection_rect_ = target_rect_;
}
- if (cached_rects)
+ if (cached_rects) {
cached_rects->local_target_rect = target_rect_;
+ cached_rects->pre_margin_target_rect_is_empty =
+ pre_margin_target_rect_is_empty;
+ }
root_rect_ = root_geometry.local_root_rect;
bool does_intersect =
@@ -398,7 +425,18 @@ void IntersectionGeometry::ComputeGeometry(const RootGeometry& root_geometry,
if (does_intersect) {
const PhysicalRect& comparison_rect =
ShouldTrackFractionOfRoot() ? root_rect_ : target_rect_;
- if (comparison_rect.IsEmpty()) {
+ // Note that if we are checking whether target is empty, we have to consider
+ // the fact that we might have padded the rect with a target margin. If we
+ // did, `pre_margin_target_rect_is_empty` would be true. Use this
+ // information to force the rect to be empty for the purposes of this
+ // computation. Note that it could also be the case that the rect started as
+ // non-empty and was transformed to be empty. In this case, we rely on
+ // target_rect_.IsEmpty() to be true, so we need to check the rect itself as
+ // well.
+ // In the fraction of root case, we can just check the comparison rect.
+ bool empty_override =
+ !ShouldTrackFractionOfRoot() && pre_margin_target_rect_is_empty;
+ if (comparison_rect.IsEmpty() || empty_override) {
intersection_ratio_ = 1;
} else {
const PhysicalSize& intersection_size = intersection_rect_.size;
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h
index 59a41662cb3..660514a8e83 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h
@@ -36,10 +36,13 @@ class CORE_EXPORT IntersectionGeometry {
kShouldUseReplacedContentRect = 1 << 3,
kShouldConvertToCSSPixels = 1 << 4,
kShouldUseCachedRects = 1 << 5,
+ // Applies to boxes. If true, OverflowClipRect() is used if necessary
+ // instead of BorderBoundingBox().
+ kUseOverflowClipEdge = 1 << 6,
// These flags will be computed
- kRootIsImplicit = 1 << 6,
- kIsVisible = 1 << 7
+ kRootIsImplicit = 1 << 7,
+ kIsVisible = 1 << 8
};
struct RootGeometry {
@@ -63,6 +66,8 @@ class CORE_EXPORT IntersectionGeometry {
// True iff unscrolled_unclipped_intersection_rect actually intersects the
// root, as defined by edge-inclusive intersection rules.
bool does_intersect;
+ // True iff the target rect before any margins were applied was empty
+ bool pre_margin_target_rect_is_empty;
// Invalidation flag
bool valid;
};
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
index 1ca7b064c8b..9da5dbd6755 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -105,13 +105,15 @@ bool IntersectionObservation::ShouldCompute(unsigned flags) {
return false;
// If we're processing post-layout deliveries only and we don't have a
- // post-layout delivery observer, then return early.
- if (flags & kPostLayoutDeliveryOnly) {
- if (Observer()->GetDeliveryBehavior() !=
- IntersectionObserver::kDeliverDuringPostLayoutSteps) {
- return false;
- }
- }
+ // post-layout delivery observer, then return early. Likewise, return if we
+ // need to compute non-post-layout-delivery observations but the observer
+ // behavior is post-layout.
+ bool post_layout_delivery_only = flags & kPostLayoutDeliveryOnly;
+ bool is_post_layout_delivery_observer =
+ Observer()->GetDeliveryBehavior() ==
+ IntersectionObserver::kDeliverDuringPostLayoutSteps;
+ if (post_layout_delivery_only != is_post_layout_delivery_observer)
+ return false;
if (flags &
(observer_->RootIsImplicit() ? kImplicitRootObserversNeedUpdate
@@ -198,6 +200,8 @@ unsigned IntersectionObservation::GetIntersectionGeometryFlags(
geometry_flags |= IntersectionGeometry::kShouldTrackFractionOfRoot;
if (CanUseCachedRects())
geometry_flags |= IntersectionGeometry::kShouldUseCachedRects;
+ if (Observer()->UseOverflowClipEdge())
+ geometry_flags |= IntersectionGeometry::kUseOverflowClipEdge;
return geometry_flags;
}
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.h b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.h
index ccf7ba4ec06..308a555bb47 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.h
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observation.h
@@ -46,6 +46,8 @@ class CORE_EXPORT IntersectionObservation final
// If this bit is set, we only process intersection observations that
// require post-layout delivery.
kPostLayoutDeliveryOnly = 1 << 5,
+ // If this is set, the overflow clip edge is used.
+ kUseOverflowClipEdge = 1 << 6,
};
IntersectionObservation(IntersectionObserver&, Element&);
@@ -87,7 +89,7 @@ class CORE_EXPORT IntersectionObservation final
unsigned last_is_visible_ : 1;
unsigned needs_update_ : 1;
unsigned last_threshold_index_ : 30;
- static const unsigned kMaxThresholdIndex = (unsigned)0x40000000;
+ static const unsigned kMaxThresholdIndex = static_cast<unsigned>(0x40000000);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
index 3f75b6ea3bc..16227057273 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -208,7 +208,7 @@ IntersectionObserver* IntersectionObserver::Create(
return MakeGarbageCollected<IntersectionObserver>(
delegate, root, margin, thresholds, kFractionOfTarget, delay,
- track_visibility, false, kApplyMarginToRoot);
+ track_visibility, false, kApplyMarginToRoot, false);
}
IntersectionObserver* IntersectionObserver::Create(
@@ -238,6 +238,7 @@ IntersectionObserver* IntersectionObserver::Create(
bool track_visibility,
bool always_report_root_bounds,
MarginTarget margin_target,
+ bool use_overflow_clip_edge,
ExceptionState& exception_state) {
IntersectionObserverDelegateImpl* intersection_observer_delegate =
MakeGarbageCollected<IntersectionObserverDelegateImpl>(
@@ -245,7 +246,8 @@ IntersectionObserver* IntersectionObserver::Create(
behavior);
return MakeGarbageCollected<IntersectionObserver>(
*intersection_observer_delegate, nullptr, margin, thresholds, semantics,
- delay, track_visibility, always_report_root_bounds, margin_target);
+ delay, track_visibility, always_report_root_bounds, margin_target,
+ use_overflow_clip_edge);
}
IntersectionObserver::IntersectionObserver(
@@ -257,7 +259,8 @@ IntersectionObserver::IntersectionObserver(
DOMHighResTimeStamp delay,
bool track_visibility,
bool always_report_root_bounds,
- MarginTarget margin_target)
+ MarginTarget margin_target,
+ bool use_overflow_clip_edge)
: ExecutionContextClient(delegate.GetExecutionContext()),
delegate_(&delegate),
root_(root),
@@ -270,7 +273,8 @@ IntersectionObserver::IntersectionObserver(
track_fraction_of_root_(semantics == kFractionOfRoot),
always_report_root_bounds_(always_report_root_bounds),
needs_delivery_(0),
- can_use_cached_rects_(0) {
+ can_use_cached_rects_(0),
+ use_overflow_clip_edge_(use_overflow_clip_edge) {
switch (margin.size()) {
case 0:
break;
@@ -323,10 +327,7 @@ bool IntersectionObserver::RootIsValid() const {
void IntersectionObserver::observe(Element* target,
ExceptionState& exception_state) {
- if (!RootIsValid())
- return;
-
- if (!target || root() == target)
+ if (!RootIsValid() || !target)
return;
if (target->EnsureIntersectionObserverData().GetObservationFor(*this))
@@ -358,7 +359,9 @@ void IntersectionObserver::observe(Element* target,
observation->ComputeIntersection(
IntersectionObservation::kImplicitRootObserversNeedUpdate |
IntersectionObservation::kExplicitRootObserversNeedUpdate |
- IntersectionObservation::kIgnoreDelay);
+ IntersectionObservation::kIgnoreDelay |
+ (use_overflow_clip_edge_ ? IntersectionObservation::kUseOverflowClipEdge
+ : 0));
}
}
@@ -445,11 +448,19 @@ bool IntersectionObserver::ComputeIntersections(unsigned flags) {
return false;
// If we're processing post-layout deliveries only and we're not a post-layout
- // delivery observer, then return early.
- if (flags & IntersectionObservation::kPostLayoutDeliveryOnly) {
- if (GetDeliveryBehavior() != kDeliverDuringPostLayoutSteps)
- return false;
- }
+ // delivery observer, then return early. Likewise, return if we need to
+ // compute non-post-layout-delivery observations but the observer behavior is
+ // post-layout.
+ bool post_layout_delivery_only =
+ flags & IntersectionObservation::kPostLayoutDeliveryOnly;
+ bool is_post_layout_delivery_observer =
+ GetDeliveryBehavior() ==
+ IntersectionObserver::kDeliverDuringPostLayoutSteps;
+ if (post_layout_delivery_only != is_post_layout_delivery_observer)
+ return false;
+
+ if (use_overflow_clip_edge_)
+ flags |= IntersectionObservation::kUseOverflowClipEdge;
IntersectionGeometry::RootGeometry root_geometry(
IntersectionGeometry::GetRootLayoutObjectForTarget(root(), nullptr,
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
index f8307d239b1..222c30f6f32 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
@@ -98,6 +98,8 @@ class CORE_EXPORT IntersectionObserver final
// the given |callback|. |thresholds| should be in the range [0,1], and are
// interpreted according to the given |semantics|. |delay| specifies the
// minimum period between change notifications.
+ // `use_overflow_clip_edge` indicates whether the overflow clip edge
+ // should be used instead of the bounding box if appropriate.
static IntersectionObserver* Create(
const Vector<Length>& margin,
const Vector<float>& thresholds,
@@ -110,6 +112,7 @@ class CORE_EXPORT IntersectionObserver final
bool track_visbility = false,
bool always_report_root_bounds = false,
MarginTarget margin_target = kApplyMarginToRoot,
+ bool use_overflow_clip_edge = false,
ExceptionState& = ASSERT_NO_EXCEPTION);
static void ResumeSuspendedObservers();
@@ -122,7 +125,8 @@ class CORE_EXPORT IntersectionObserver final
DOMHighResTimeStamp delay,
bool track_visibility,
bool always_report_root_bounds,
- MarginTarget margin_target);
+ MarginTarget margin_target,
+ bool use_overflow_clip_edge);
// API methods.
void observe(Element*, ExceptionState& = ASSERT_NO_EXCEPTION);
@@ -175,6 +179,8 @@ class CORE_EXPORT IntersectionObserver final
bool CanUseCachedRects() const { return can_use_cached_rects_; }
void InvalidateCachedRects() { can_use_cached_rects_ = 0; }
+ bool UseOverflowClipEdge() const { return use_overflow_clip_edge_ == 1; }
+
// ScriptWrappable override:
bool HasPendingActivity() const override;
@@ -203,6 +209,7 @@ class CORE_EXPORT IntersectionObserver final
unsigned always_report_root_bounds_ : 1;
unsigned needs_delivery_ : 1;
unsigned can_use_cached_rects_ : 1;
+ unsigned use_overflow_clip_edge_ : 1;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
index d134e21471e..5e1bd67748f 100644
--- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/intersection_observer_test_helper.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -30,57 +31,6 @@
namespace blink {
-namespace {
-
-class TestIntersectionObserverDelegate : public IntersectionObserverDelegate {
- public:
- TestIntersectionObserverDelegate(Document& document)
- : document_(document), call_count_(0) {}
- // TODO(szager): Add tests for the synchronous delivery code path. There is
- // already some indirect coverage by unit tests exercising features that rely
- // on it, but we should have some direct coverage in here.
- LocalFrameUkmAggregator::MetricId GetUkmMetricId() const override {
- return LocalFrameUkmAggregator::kJavascriptIntersectionObserver;
- }
- IntersectionObserver::DeliveryBehavior GetDeliveryBehavior() const override {
- return IntersectionObserver::kPostTaskToDeliver;
- }
- void Deliver(const HeapVector<Member<IntersectionObserverEntry>>& entries,
- IntersectionObserver&) override {
- call_count_++;
- entries_.AppendVector(entries);
- }
- ExecutionContext* GetExecutionContext() const override {
- return document_->GetExecutionContext();
- }
- int CallCount() const { return call_count_; }
- int EntryCount() const { return entries_.size(); }
- const IntersectionObserverEntry* LastEntry() const { return entries_.back(); }
- void Clear() {
- entries_.clear();
- call_count_ = 0;
- }
- PhysicalRect LastIntersectionRect() const {
- if (entries_.IsEmpty())
- return PhysicalRect();
- const IntersectionGeometry& geometry = entries_.back()->GetGeometry();
- return geometry.IntersectionRect();
- }
-
- void Trace(Visitor* visitor) const override {
- IntersectionObserverDelegate::Trace(visitor);
- visitor->Trace(document_);
- visitor->Trace(entries_);
- }
-
- private:
- Member<Document> document_;
- HeapVector<Member<IntersectionObserverEntry>> entries_;
- int call_count_;
-};
-
-} // namespace
-
class IntersectionObserverTest : public SimTest {};
class IntersectionObserverV2Test : public IntersectionObserverTest {
@@ -239,7 +189,8 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
*target_observer_delegate, nullptr, Vector<Length>(),
Vector<float>{kExpectedFractionOfTarget / 2},
IntersectionObserver::kFractionOfTarget, 0, false, false,
- IntersectionObserver::kApplyMarginToRoot);
+ IntersectionObserver::kApplyMarginToRoot,
+ /* use_overflow_clip_edge */ false);
DummyExceptionStateForTesting exception_state;
target_observer->observe(target, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -251,7 +202,8 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
*root_observer_delegate, nullptr, Vector<Length>(),
Vector<float>{kExpectedFractionOfRoot / 2},
IntersectionObserver::kFractionOfRoot, 0, false, false,
- IntersectionObserver::kApplyMarginToRoot);
+ IntersectionObserver::kApplyMarginToRoot,
+ /* use_overflow_clip_edge */ false);
root_observer->observe(target, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -272,6 +224,56 @@ TEST_F(IntersectionObserverTest, ReportsFractionOfTargetOrRoot) {
root_observer_delegate->LastEntry()->intersectionRatio(), 1e-6);
}
+TEST_F(IntersectionObserverTest, TargetRectIsEmptyAfterMapping) {
+ // Place a 100x100 target element in the middle of a 200x200 main frame.
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(200, 200));
+ SimRequest main_resource("https://example.com/", "text/html");
+ LoadURL("https://example.com/");
+ main_resource.Complete(R"HTML(
+ <style>
+ .clipper {
+ transform: rotatey(90deg);
+ }
+ .container {
+ overflow: hidden;
+ }
+ #target {
+ width: 10px;
+ height: 10px;
+ }
+ </style>
+ <div class=clipper>
+ <div class=container>
+ <div id=target></div>
+ </div>
+ </div>
+ )HTML");
+
+ Element* target = GetDocument().getElementById("target");
+ ASSERT_TRUE(target);
+
+ TestIntersectionObserverDelegate* target_observer_delegate =
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
+ IntersectionObserver* target_observer =
+ MakeGarbageCollected<IntersectionObserver>(
+ *target_observer_delegate, nullptr, Vector<Length>(),
+ Vector<float>{std::numeric_limits<float>::min()},
+ IntersectionObserver::kFractionOfTarget, 0, false, false,
+ IntersectionObserver::kApplyMarginToRoot,
+ /* use_overflow_clip_edge */ false);
+ DummyExceptionStateForTesting exception_state;
+ target_observer->observe(target, exception_state);
+ ASSERT_FALSE(exception_state.HadException());
+
+ Compositor().BeginFrame();
+ test::RunPendingTasks();
+ ASSERT_FALSE(Compositor().NeedsBeginFrame());
+
+ EXPECT_EQ(target_observer_delegate->CallCount(), 1);
+ EXPECT_EQ(target_observer_delegate->EntryCount(), 1);
+ EXPECT_TRUE(target_observer_delegate->LastEntry()->isIntersecting());
+}
+
TEST_F(IntersectionObserverTest, ResumePostsTask) {
WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
SimRequest main_resource("https://example.com/", "text/html");
@@ -980,7 +982,8 @@ TEST_F(IntersectionObserverTest, ApplyMarginToTarget) {
*root_margin_delegate, nullptr, Vector<Length>{Length::Fixed(10)},
Vector<float>{std::numeric_limits<float>::min()},
IntersectionObserver::kFractionOfTarget, 0, false, false,
- IntersectionObserver::kApplyMarginToRoot);
+ IntersectionObserver::kApplyMarginToRoot,
+ /* use_overflow_clip_edge */ false);
DummyExceptionStateForTesting exception_state;
root_margin_observer->observe(target, exception_state);
@@ -994,7 +997,8 @@ TEST_F(IntersectionObserverTest, ApplyMarginToTarget) {
*target_margin_delegate, nullptr, Vector<Length>{Length::Fixed(10)},
Vector<float>{std::numeric_limits<float>::min()},
IntersectionObserver::kFractionOfTarget, 0, false, false,
- IntersectionObserver::kApplyMarginToTarget);
+ IntersectionObserver::kApplyMarginToTarget,
+ /* use_overflow_clip_edge */ false);
target_margin_observer->observe(target, exception_state);
ASSERT_FALSE(exception_state.HadException());
@@ -1047,7 +1051,8 @@ TEST_F(IntersectionObserverTest, TargetMarginPercentResolvesAgainstRoot) {
*target_margin_delegate, nullptr, Vector<Length>{Length::Percent(10)},
Vector<float>{std::numeric_limits<float>::min()},
IntersectionObserver::kFractionOfTarget, 0, false, false,
- IntersectionObserver::kApplyMarginToTarget);
+ IntersectionObserver::kApplyMarginToTarget,
+ /* use_overflow_clip_edge */ false);
DummyExceptionStateForTesting exception_state;
target_margin_observer->observe(target, exception_state);
diff --git a/chromium/third_party/blink/renderer/core/layout/DIR_METADATA b/chromium/third_party/blink/renderer/core/layout/DIR_METADATA
new file mode 100644
index 00000000000..3611c38fad3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Layout"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/layout/OWNERS b/chromium/third_party/blink/renderer/core/layout/OWNERS
index 66fa6013e00..ddf235e82c9 100644
--- a/chromium/third_party/blink/renderer/core/layout/OWNERS
+++ b/chromium/third_party/blink/renderer/core/layout/OWNERS
@@ -10,6 +10,3 @@ svillar@igalia.com
tkent@chromium.org
wangxianzhu@chromium.org
xiaochengh@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
diff --git a/chromium/third_party/blink/renderer/core/layout/api/line_layout_item.h b/chromium/third_party/blink/renderer/core/layout/api/line_layout_item.h
index 03165f66d80..8ac02ae1ef0 100644
--- a/chromium/third_party/blink/renderer/core/layout/api/line_layout_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/api/line_layout_item.h
@@ -229,9 +229,18 @@ class LineLayoutItem {
layout_object_->SetAncestorLineBoxDirty();
}
- int CaretMinOffset() const { return layout_object_->CaretMinOffset(); }
-
- int CaretMaxOffset() const { return layout_object_->CaretMaxOffset(); }
+ // TODO(yosin): We should not use |CaretMaxOffset()|, because this function
+ // may be used for creating invalid pointer, e.g. <hr>@1.
+ int CaretMaxOffset() const {
+ if (layout_object_->IsAtomicInlineLevel()) {
+ if (Node* const node = layout_object_->GetNode())
+ return std::max(1u, GetNode()->CountChildren());
+ return 1;
+ }
+ if (layout_object_->IsHR())
+ return 1;
+ return 0;
+ }
bool HasFlippedBlocksWritingMode() const {
return layout_object_->HasFlippedBlocksWritingMode();
@@ -273,6 +282,14 @@ class LineLayoutItem {
return layout_object_->CreatePositionWithAffinity(offset, affinity);
}
+ PositionWithAffinity PositionAfterThis() const {
+ return layout_object_->PositionAfterThis();
+ }
+
+ PositionWithAffinity PositionBeforeThis() const {
+ return layout_object_->PositionBeforeThis();
+ }
+
LineLayoutItem PreviousInPreOrder(const LayoutObject* stay_within) const {
return LineLayoutItem(layout_object_->PreviousInPreOrder(stay_within));
}
@@ -331,7 +348,6 @@ class LineLayoutItem {
#endif
- protected:
LayoutObject* GetLayoutObject() { return layout_object_; }
const LayoutObject* GetLayoutObject() const { return layout_object_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/box_layout_extra_input.h b/chromium/third_party/blink/renderer/core/layout/box_layout_extra_input.h
index 0fd51ae4091..d3ad120bd29 100644
--- a/chromium/third_party/blink/renderer/core/layout/box_layout_extra_input.h
+++ b/chromium/third_party/blink/renderer/core/layout/box_layout_extra_input.h
@@ -33,6 +33,10 @@ struct BoxLayoutExtraInput {
// purposes of percent block-size resolution.
bool is_override_block_size_definite = true;
+ // If an 'auto' inline/block-size should stretch to the available size.
+ bool stretch_inline_size_if_auto = false;
+ bool stretch_block_size_if_auto = false;
+
// Available inline size. https://drafts.csswg.org/css-sizing/#available
LayoutUnit available_inline_size;
diff --git a/chromium/third_party/blink/renderer/core/layout/build.gni b/chromium/third_party/blink/renderer/core/layout/build.gni
index b9d43102db7..a4388a1da06 100644
--- a/chromium/third_party/blink/renderer/core/layout/build.gni
+++ b/chromium/third_party/blink/renderer/core/layout/build.gni
@@ -46,6 +46,7 @@ blink_core_sources_layout = [
"fragmentainer_iterator.h",
"fragmentation_context.h",
"generated_children.h",
+ "geometry/axis.h",
"geometry/box_sides.h",
"geometry/logical_offset.cc",
"geometry/logical_offset.h",
@@ -358,8 +359,6 @@ blink_core_sources_layout = [
"ng/inline/ng_inline_child_layout_context.h",
"ng/inline/ng_inline_cursor.cc",
"ng/inline/ng_inline_cursor.h",
- "ng/inline/ng_inline_fragment_traversal.cc",
- "ng/inline/ng_inline_fragment_traversal.h",
"ng/inline/ng_inline_item.cc",
"ng/inline/ng_inline_item.h",
"ng/inline/ng_inline_item_result.cc",
@@ -390,12 +389,8 @@ blink_core_sources_layout = [
"ng/inline/ng_offset_mapping_builder.h",
"ng/inline/ng_physical_line_box_fragment.cc",
"ng/inline/ng_physical_line_box_fragment.h",
- "ng/inline/ng_physical_text_fragment.cc",
- "ng/inline/ng_physical_text_fragment.h",
"ng/inline/ng_ruby_utils.cc",
"ng/inline/ng_ruby_utils.h",
- "ng/inline/ng_text_fragment_builder.cc",
- "ng/inline/ng_text_fragment_builder.h",
"ng/inline/ng_text_offset.cc",
"ng/inline/ng_text_offset.h",
"ng/inline/ng_text_type.h",
@@ -529,6 +524,8 @@ blink_core_sources_layout = [
"ng/ng_positioned_float.h",
"ng/ng_relative_utils.cc",
"ng/ng_relative_utils.h",
+ "ng/ng_replaced_layout_algorithm.cc",
+ "ng/ng_replaced_layout_algorithm.h",
"ng/ng_simplified_layout_algorithm.cc",
"ng/ng_simplified_layout_algorithm.h",
"ng/ng_simplified_oof_layout_algorithm.cc",
@@ -674,10 +671,6 @@ blink_core_sources_layout = [
"svg/svg_marker_data.h",
"svg/svg_resources.cc",
"svg/svg_resources.h",
- "svg/svg_resources_cache.cc",
- "svg/svg_resources_cache.h",
- "svg/svg_resources_cycle_solver.cc",
- "svg/svg_resources_cycle_solver.h",
"svg/svg_text_chunk_builder.cc",
"svg/svg_text_chunk_builder.h",
"svg/svg_text_fragment.h",
diff --git a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
index 86b09888652..ae011564e85 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
@@ -146,7 +146,7 @@ CustomScrollbar::GetScrollbarPseudoElementStyle(ScrollbarPart part_type,
return nullptr;
const ComputedStyle* source_style = element->GetLayoutObject()->Style();
scoped_refptr<const ComputedStyle> part_style =
- element->StyleForPseudoElement(
+ element->UncachedStyleForPseudoElement(
PseudoElementStyleRequest(pseudo_id, this, part_type), source_style);
if (!part_style)
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 756a99fcdf5..9b6b9c23955 100644
--- a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -268,7 +268,7 @@ void FlexItem::ComputeStretchedSize() {
cross_axis_size_ = box_->ConstrainLogicalHeightByMinMax(
stretched_size, box_->IntrinsicContentLogicalHeight());
} else if (!MainAxisIsInlineAxis() && style_.LogicalWidth().IsAuto()) {
- const LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box_->Parent());
+ const auto* flexbox = To<LayoutFlexibleBox>(box_->Parent());
cross_axis_size_ = box_->ConstrainLogicalWidthByMinMax(
stretched_size, flexbox->CrossAxisContentExtent(), flexbox);
}
@@ -589,17 +589,18 @@ void FlexLine::ComputeLineItemsPosition(LayoutUnit main_axis_start_offset,
LayoutUnit FlexLayoutAlgorithm::GapBetweenItems(
const ComputedStyle& style,
LogicalSize percent_resolution_sizes) {
- DCHECK_GE(percent_resolution_sizes.inline_size, 0);
if (IsColumnFlow(style)) {
if (const base::Optional<Length>& row_gap = style.RowGap()) {
return MinimumValueForLength(
- *row_gap, percent_resolution_sizes.block_size.ClampNegativeToZero());
+ *row_gap,
+ percent_resolution_sizes.block_size.ClampIndefiniteToZero());
}
return LayoutUnit();
}
if (const base::Optional<Length>& column_gap = style.ColumnGap()) {
- return MinimumValueForLength(*column_gap,
- percent_resolution_sizes.inline_size);
+ return MinimumValueForLength(
+ *column_gap,
+ percent_resolution_sizes.inline_size.ClampIndefiniteToZero());
}
return LayoutUnit();
}
@@ -608,17 +609,18 @@ LayoutUnit FlexLayoutAlgorithm::GapBetweenItems(
LayoutUnit FlexLayoutAlgorithm::GapBetweenLines(
const ComputedStyle& style,
LogicalSize percent_resolution_sizes) {
- DCHECK_GE(percent_resolution_sizes.inline_size, 0);
if (!IsColumnFlow(style)) {
if (const base::Optional<Length>& row_gap = style.RowGap()) {
return MinimumValueForLength(
- *row_gap, percent_resolution_sizes.block_size.ClampNegativeToZero());
+ *row_gap,
+ percent_resolution_sizes.block_size.ClampIndefiniteToZero());
}
return LayoutUnit();
}
if (const base::Optional<Length>& column_gap = style.ColumnGap()) {
- return MinimumValueForLength(*column_gap,
- percent_resolution_sizes.inline_size);
+ return MinimumValueForLength(
+ *column_gap,
+ percent_resolution_sizes.inline_size.ClampIndefiniteToZero());
}
return LayoutUnit();
}
@@ -773,13 +775,8 @@ LayoutUnit FlexLayoutAlgorithm::IntrinsicContentBlockSize() const {
if (IsColumnFlow()) {
LayoutUnit max_size;
- for (const FlexLine& line : flex_lines_) {
- // Subtract main_axis_offset to remove border/padding
- max_size =
- std::max(line.main_axis_extent_ - line.sum_justify_adjustments_ -
- line.main_axis_offset_,
- max_size);
- }
+ for (const FlexLine& line : flex_lines_)
+ max_size = std::max(line.sum_hypothetical_main_size_, max_size);
return max_size;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/floating_objects.h b/chromium/third_party/blink/renderer/core/layout/floating_objects.h
index 4057c8679f9..87e106244ea 100644
--- a/chromium/third_party/blink/renderer/core/layout/floating_objects.h
+++ b/chromium/third_party/blink/renderer/core/layout/floating_objects.h
@@ -26,7 +26,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_FLOATING_OBJECTS_H_
#include <memory>
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
@@ -146,7 +146,7 @@ class FloatingObject {
RootInlineBox* OriginatingLine() const { return originating_line_; }
void SetOriginatingLine(RootInlineBox* line) { originating_line_ = line; }
- using PassKey = util::PassKey<FloatingObject>;
+ using PassKey = base::PassKey<FloatingObject>;
FloatingObject(PassKey, LayoutBox*, Type);
FloatingObject(PassKey,
LayoutBox*,
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/axis.h b/chromium/third_party/blink/renderer/core/layout/geometry/axis.h
new file mode 100644
index 00000000000..d0646156fa1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/axis.h
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_AXIS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_AXIS_H_
+
+#include "base/types/strong_alias.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
+
+namespace blink {
+
+enum {
+ kLogicalAxisNone = 0,
+ kLogicalAxisInline = 1 << 0,
+ kLogicalAxisBlock = 1 << 1,
+ kLogicalAxisBoth = kLogicalAxisInline | kLogicalAxisBlock
+};
+
+enum {
+ kPhysicalAxisNone = 0,
+ kPhysicalAxisHorizontal = 1 << 0,
+ kPhysicalAxisVertical = 1 << 1,
+ kPhysicalAxisBoth = kPhysicalAxisHorizontal | kPhysicalAxisVertical
+};
+
+using PhysicalAxes = base::StrongAlias<class PhysicalAxesTag, uint8_t>;
+using LogicalAxes = base::StrongAlias<class LogicalAxesTag, uint8_t>;
+
+inline PhysicalAxes ToPhysicalAxes(LogicalAxes logical, WritingMode mode) {
+ if (IsHorizontalWritingMode(mode))
+ return PhysicalAxes(logical.value());
+ if (logical == LogicalAxes(kLogicalAxisInline))
+ return PhysicalAxes(kPhysicalAxisVertical);
+ if (logical == LogicalAxes(kLogicalAxisBlock))
+ return PhysicalAxes(kPhysicalAxisHorizontal);
+ return PhysicalAxes(logical.value());
+}
+
+inline LogicalAxes operator|(LogicalAxes a, LogicalAxes b) {
+ return LogicalAxes(a.value() | b.value());
+}
+
+inline LogicalAxes& operator|=(LogicalAxes& a, LogicalAxes b) {
+ a.value() |= b.value();
+ return a;
+}
+
+inline LogicalAxes operator&(LogicalAxes a, LogicalAxes b) {
+ return LogicalAxes(a.value() & b.value());
+}
+
+inline LogicalAxes operator&=(LogicalAxes& a, LogicalAxes b) {
+ a.value() &= b.value();
+ return a;
+}
+
+inline PhysicalAxes operator|(PhysicalAxes a, PhysicalAxes b) {
+ return PhysicalAxes(a.value() | b.value());
+}
+
+inline PhysicalAxes& operator|=(PhysicalAxes& a, PhysicalAxes b) {
+ a.value() |= b.value();
+ return a;
+}
+
+inline PhysicalAxes operator&(PhysicalAxes a, PhysicalAxes b) {
+ return PhysicalAxes(a.value() & b.value());
+}
+
+inline PhysicalAxes operator&=(PhysicalAxes& a, PhysicalAxes b) {
+ a.value() &= b.value();
+ return a;
+}
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_AXIS_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/axis_test.cc b/chromium/third_party/blink/renderer/core/layout/geometry/axis_test.cc
new file mode 100644
index 00000000000..cf68abff5b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/axis_test.cc
@@ -0,0 +1,129 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/geometry/axis.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(AxisTest, LogicalAxesOperators) {
+ // operator |
+ EXPECT_EQ(LogicalAxes(kLogicalAxisNone),
+ (LogicalAxes(kLogicalAxisNone) | LogicalAxes(kLogicalAxisNone)));
+ EXPECT_EQ(LogicalAxes(kLogicalAxisInline),
+ (LogicalAxes(kLogicalAxisNone) | LogicalAxes(kLogicalAxisInline)));
+ EXPECT_EQ(LogicalAxes(kLogicalAxisBoth),
+ (LogicalAxes(kLogicalAxisInline) | LogicalAxes(kLogicalAxisBlock)));
+
+ // operator |=
+ {
+ LogicalAxes axes(kLogicalAxisNone);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisNone), axes);
+ axes |= LogicalAxes(kLogicalAxisInline);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisInline), axes);
+ axes |= LogicalAxes(kLogicalAxisBlock);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisBoth), axes);
+ }
+
+ // operator &
+ EXPECT_EQ(LogicalAxes(kLogicalAxisNone),
+ (LogicalAxes(kLogicalAxisBoth) & LogicalAxes(kLogicalAxisNone)));
+ EXPECT_EQ(LogicalAxes(kLogicalAxisInline), (LogicalAxes(kLogicalAxisInline) &
+ LogicalAxes(kLogicalAxisInline)));
+ EXPECT_EQ(LogicalAxes(kLogicalAxisInline),
+ (LogicalAxes(kLogicalAxisBoth) & LogicalAxes(kLogicalAxisInline)));
+ EXPECT_EQ(LogicalAxes(kLogicalAxisNone),
+ (LogicalAxes(kLogicalAxisBlock) & LogicalAxes(kLogicalAxisInline)));
+
+ // operator &=
+ {
+ LogicalAxes axes(kLogicalAxisBoth);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisBoth), axes);
+ axes &= LogicalAxes(kLogicalAxisInline);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisInline), axes);
+ axes &= LogicalAxes(kLogicalAxisBlock);
+ EXPECT_EQ(LogicalAxes(kLogicalAxisNone), axes);
+ }
+}
+
+TEST(AxisTest, PhysicalAxesOperators) {
+ // operator |
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone), (PhysicalAxes(kPhysicalAxisNone) |
+ PhysicalAxes(kPhysicalAxisNone)));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal),
+ (PhysicalAxes(kPhysicalAxisNone) |
+ PhysicalAxes(kPhysicalAxisHorizontal)));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisBoth),
+ (PhysicalAxes(kPhysicalAxisHorizontal) |
+ PhysicalAxes(kPhysicalAxisVertical)));
+
+ // operator |=
+ {
+ PhysicalAxes axes(kPhysicalAxisNone);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone), axes);
+ axes |= PhysicalAxes(kPhysicalAxisHorizontal);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal), axes);
+ axes |= PhysicalAxes(kPhysicalAxisVertical);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisBoth), axes);
+ }
+
+ // operator &
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone), (PhysicalAxes(kPhysicalAxisBoth) &
+ PhysicalAxes(kPhysicalAxisNone)));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal),
+ (PhysicalAxes(kPhysicalAxisHorizontal) &
+ PhysicalAxes(kPhysicalAxisHorizontal)));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal),
+ (PhysicalAxes(kPhysicalAxisBoth) &
+ PhysicalAxes(kPhysicalAxisHorizontal)));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone),
+ (PhysicalAxes(kPhysicalAxisVertical) &
+ PhysicalAxes(kPhysicalAxisHorizontal)));
+
+ // operator &=
+ {
+ PhysicalAxes axes(kPhysicalAxisBoth);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisBoth), axes);
+ axes &= PhysicalAxes(kPhysicalAxisHorizontal);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal), axes);
+ axes &= PhysicalAxes(kPhysicalAxisVertical);
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone), axes);
+ }
+}
+
+TEST(AxisTest, ToPhysicalAxes) {
+ ASSERT_TRUE(IsHorizontalWritingMode(WritingMode::kHorizontalTb));
+ ASSERT_FALSE(IsHorizontalWritingMode(WritingMode::kVerticalRl));
+
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisNone),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisNone),
+ WritingMode::kHorizontalTb));
+ EXPECT_EQ(
+ PhysicalAxes(kPhysicalAxisNone),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisNone), WritingMode::kVerticalRl));
+
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisBoth),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisBoth),
+ WritingMode::kHorizontalTb));
+ EXPECT_EQ(
+ PhysicalAxes(kPhysicalAxisBoth),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisBoth), WritingMode::kVerticalRl));
+
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisHorizontal),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisInline),
+ WritingMode::kHorizontalTb));
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisVertical),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisInline),
+ WritingMode::kVerticalRl));
+
+ EXPECT_EQ(PhysicalAxes(kPhysicalAxisVertical),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisBlock),
+ WritingMode::kHorizontalTb));
+ EXPECT_EQ(
+ PhysicalAxes(kPhysicalAxisHorizontal),
+ ToPhysicalAxes(LogicalAxes(kLogicalAxisBlock), WritingMode::kVerticalRl));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/logical_size.h b/chromium/third_party/blink/renderer/core/layout/geometry/logical_size.h
index 8cc331db2bc..30e7a19be2e 100644
--- a/chromium/third_party/blink/renderer/core/layout/geometry/logical_size.h
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/logical_size.h
@@ -15,9 +15,6 @@ namespace blink {
struct LogicalOffset;
-// TODO(wangxianzhu): Make it a constexpr when LayoutUnit allows it.
-#define kIndefiniteSize LayoutUnit(-1)
-
// LogicalSize is the size of rect (typically a fragment) in the logical
// coordinate system.
// For more information about physical and logical coordinate systems, see:
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.cc b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
index c68f096e051..3a749050d74 100644
--- a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
@@ -13,6 +13,20 @@
namespace blink {
+PhysicalSize PhysicalRect::DistanceAsSize(PhysicalOffset target) const {
+ target -= offset;
+ PhysicalSize distance;
+ if (target.left < 0)
+ distance.width = -target.left;
+ else if (target.left > size.width)
+ distance.width = target.left - size.width;
+ if (target.top < 0)
+ distance.height = -target.top;
+ else if (target.top > size.height)
+ distance.height = target.top - size.height;
+ return distance;
+}
+
bool PhysicalRect::Contains(const PhysicalRect& other) const {
return offset.left <= other.offset.left && offset.top <= other.offset.top &&
Right() >= other.Right() && Bottom() >= other.Bottom();
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
index 6bce618a0ee..e37c5dbf9ce 100644
--- a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
@@ -78,6 +78,10 @@ struct CORE_EXPORT PhysicalRect {
}
bool operator!=(const PhysicalRect& other) const { return !(*this == other); }
+ // Returns the distance to |target| in horizontal and vertical directions.
+ // Each distance is zero if |this| contains |target| in that direction.
+ PhysicalSize DistanceAsSize(PhysicalOffset target) const;
+
bool Contains(const PhysicalRect&) const;
bool Contains(LayoutUnit px, LayoutUnit py) const {
return px >= offset.left && px < Right() && py >= offset.top &&
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_test.cc b/chromium/third_party/blink/renderer/core/layout/grid_test.cc
index cb69e83b89f..6fb262c64eb 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_test.cc
@@ -15,7 +15,7 @@ namespace {
class GridTest : public RenderingTest {
protected:
LayoutGrid* GetGridByElementId(const char* id) {
- return ToLayoutGrid(GetLayoutObjectByElementId(id));
+ return To<LayoutGrid>(GetLayoutObjectByElementId(id));
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
index a43e6b18679..0c5eb2eaa24 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -383,6 +383,8 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MinContentForChild(
// FIXME: It's unclear if we should return the intrinsic width or the
// preferred width.
// See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
+ if (child.NeedsPreferredWidthsRecalculation())
+ child.SetIntrinsicLogicalWidthsDirty();
return child.PreferredLogicalWidths().min_size +
GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
child) +
@@ -407,6 +409,8 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MaxContentForChild(
// FIXME: It's unclear if we should return the intrinsic width or the
// preferred width.
// See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
+ if (child.NeedsPreferredWidthsRecalculation())
+ child.SetIntrinsicLogicalWidthsDirty();
return child.PreferredLogicalWidths().max_size +
GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
child) +
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
index 89485ad3b73..1a8f35dae41 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -76,7 +76,6 @@ HitTestResult::HitTestResult(const HitTestResult& other)
local_point_(other.LocalPoint()),
inner_url_element_(other.URLElement()),
scrollbar_(other.GetScrollbar()),
- box_fragment_(other.box_fragment_),
is_over_embedded_content_view_(other.IsOverEmbeddedContentView()),
canvas_region_id_(other.CanvasRegionId()) {
// Only copy the NodeSet in case of list hit test.
@@ -104,7 +103,6 @@ bool HitTestResult::EqualForCacheability(const HitTestResult& other) const {
local_point_ == other.LocalPoint() &&
inner_url_element_ == other.URLElement() &&
scrollbar_ == other.GetScrollbar() &&
- box_fragment_ == other.box_fragment_ &&
is_over_embedded_content_view_ == other.IsOverEmbeddedContentView();
}
@@ -122,7 +120,6 @@ void HitTestResult::PopulateFromCachedResult(const HitTestResult& other) {
local_point_ = other.LocalPoint();
inner_url_element_ = other.URLElement();
scrollbar_ = other.GetScrollbar();
- box_fragment_ = other.box_fragment_;
is_over_embedded_content_view_ = other.IsOverEmbeddedContentView();
cacheable_ = other.cacheable_;
@@ -149,20 +146,28 @@ void HitTestResult::SetNodeAndPosition(
Node* node,
scoped_refptr<const NGPhysicalBoxFragment> box_fragment,
const PhysicalOffset& position) {
- SetBoxFragment(std::move(box_fragment));
- SetNodeAndPosition(node, position);
+ if (box_fragment) {
+ local_point_ = position + box_fragment->OffsetFromOwnerLayoutBox();
+ } else {
+ local_point_ = position;
+ }
+ SetInnerNode(node);
}
-void HitTestResult::SetBoxFragment(
- scoped_refptr<const NGPhysicalBoxFragment> box_fragment) {
- DCHECK(!box_fragment || !box_fragment->IsInlineBox());
- box_fragment_ = std::move(box_fragment);
+void HitTestResult::OverrideNodeAndPosition(Node* node,
+ PhysicalOffset position) {
+ local_point_ = position;
+ SetInnerNode(node);
}
PositionWithAffinity HitTestResult::GetPosition() const {
- if (!inner_possibly_pseudo_node_)
+ const Node* node = inner_possibly_pseudo_node_;
+ if (!node)
return PositionWithAffinity();
- LayoutObject* layout_object = GetLayoutObject();
+ // |LayoutObject::PositionForPoint()| requires |kPrePaintClean|.
+ DCHECK_GE(node->GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ LayoutObject* layout_object = node->GetLayoutObject();
if (!layout_object)
return PositionWithAffinity();
@@ -173,23 +178,44 @@ PositionWithAffinity HitTestResult::GetPosition() const {
// the node as the position. This is because we don't paint contents of the
// element. Furthermore, any caret adjustments below can access layout-dirty
// state in the subtree of this object.
- if (layout_object->ChildPaintBlockedByDisplayLock()) {
- return PositionWithAffinity(Position(*inner_node_, 0),
- TextAffinity::kDefault);
- }
+ if (layout_object->ChildPaintBlockedByDisplayLock())
+ return PositionWithAffinity(Position(*node, 0), TextAffinity::kDefault);
- if (inner_possibly_pseudo_node_->IsPseudoElement() &&
- inner_possibly_pseudo_node_->GetPseudoId() == kPseudoIdBefore) {
- return PositionWithAffinity(MostForwardCaretPosition(
- Position(inner_node_, PositionAnchorType::kBeforeChildren)));
+ if (node->IsPseudoElement() && node->GetPseudoId() == kPseudoIdBefore) {
+ return PositionWithAffinity(
+ MostForwardCaretPosition(Position::FirstPositionInNode(*inner_node_)));
}
- if (box_fragment_ && NGPhysicalBoxFragment::SupportsPositionForPoint())
- return box_fragment_->PositionForPoint(LocalPoint());
+
return layout_object->PositionForPoint(LocalPoint());
}
-LayoutObject* HitTestResult::GetLayoutObject() const {
- return inner_node_ ? inner_node_->GetLayoutObject() : nullptr;
+PositionWithAffinity HitTestResult::GetPositionForInnerNodeOrImageMapImage()
+ const {
+ Node* node = InnerPossiblyPseudoNode();
+ if (node && !node->IsPseudoElement())
+ node = InnerNodeOrImageMapImage();
+ if (!node)
+ return PositionWithAffinity();
+ // |LayoutObject::PositionForPoint()| requires |kPrePaintClean|.
+ DCHECK_GE(node->GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ LayoutObject* layout_object = node->GetLayoutObject();
+ if (!layout_object)
+ return PositionWithAffinity();
+ // We should never have a layout object that is within a locked subtree.
+ CHECK(!DisplayLockUtilities::NearestLockedExclusiveAncestor(*layout_object));
+
+ // If the layout object is blocked by display lock, we return the beginning of
+ // the node as the position. This is because we don't paint contents of the
+ // element. Furthermore, any caret adjustments below can access layout-dirty
+ // state in the subtree of this object.
+ if (layout_object->ChildPaintBlockedByDisplayLock())
+ return PositionWithAffinity(Position(*node, 0), TextAffinity::kDefault);
+
+ PositionWithAffinity position = layout_object->PositionForPoint(LocalPoint());
+ if (position.IsNull())
+ return PositionWithAffinity(FirstPositionInOrBeforeNode(*node));
+ return position;
}
void HitTestResult::SetToShadowHostIfInRestrictedShadowRoot() {
@@ -207,11 +233,13 @@ void HitTestResult::SetToShadowHostIfInRestrictedShadowRoot() {
IsA<SVGUseElement>(containing_shadow_root->host()))) {
shadow_host = &containing_shadow_root->host();
containing_shadow_root = shadow_host->ContainingShadowRoot();
- SetInnerNode(node->OwnerShadowHost());
+ // TODO(layout-dev): Not updating local_point_ here seems like a mistake?
+ OverrideNodeAndPosition(node->OwnerShadowHost(), local_point_);
}
+ // TODO(layout-dev): Not updating local_point_ here seems like a mistake?
if (shadow_host)
- SetInnerNode(shadow_host);
+ OverrideNodeAndPosition(shadow_host, local_point_);
}
CompositorElementId HitTestResult::GetScrollableContainer() const {
@@ -266,7 +294,6 @@ void HitTestResult::SetInnerNode(Node* n) {
inner_possibly_pseudo_node_ = nullptr;
inner_node_ = nullptr;
inner_element_ = nullptr;
- box_fragment_ = nullptr;
return;
}
@@ -286,23 +313,6 @@ void HitTestResult::SetInnerNode(Node* n) {
}
}
- if (NGPhysicalBoxFragment::SupportsPositionForPoint()) {
- if (const LayoutBox* layout_box = n->GetLayoutBox()) {
- // Fragmentation-aware code will set the correct box fragment on its own,
- // but sometimes we enter legacy layout code when hit-testing, e.g. for
- // replaced content. In such cases we need to set it here.
- if (box_fragment_) {
- DCHECK(!box_fragment_->GetLayoutObject() ||
- layout_box == box_fragment_->GetLayoutObject());
- } else if (layout_box->PhysicalFragmentCount() > 0) {
- // If we set the fragment on our own, make sure that there's only one of
- // them, since there's no way for us to pick the right one here.
- DCHECK_EQ(layout_box->PhysicalFragmentCount(), 1u);
- box_fragment_ = layout_box->GetPhysicalFragment(0);
- }
- }
- }
-
inner_possibly_pseudo_node_ = n;
if (auto* pseudo_element = DynamicTo<PseudoElement>(n))
n = pseudo_element->InnerNodeForHitTesting();
@@ -353,8 +363,6 @@ String HitTestResult::Title(TextDirection& dir) const {
// Find the title in the nearest enclosing DOM node.
// For <area> tags in image maps, walk the tree for the <area>, not the <img>
// using it.
- if (inner_node_.Get())
- inner_node_->UpdateDistributionForFlatTreeTraversal();
for (Node* title_node = inner_node_.Get(); title_node;
title_node = FlatTreeTraversal::Parent(*title_node)) {
if (auto* element = DynamicTo<Element>(title_node)) {
@@ -384,12 +392,14 @@ const AtomicString& HitTestResult::AltDisplayString() const {
}
Image* HitTestResult::GetImage() const {
- Node* inner_node_or_image_map_image = InnerNodeOrImageMapImage();
- if (!inner_node_or_image_map_image)
+ return GetImage(InnerNodeOrImageMapImage());
+}
+
+Image* HitTestResult::GetImage(const Node* node) {
+ if (!node)
return nullptr;
- LayoutObject* layout_object =
- inner_node_or_image_map_image->GetLayoutObject();
+ LayoutObject* layout_object = node->GetLayoutObject();
if (layout_object && layout_object->IsImage()) {
auto* image = To<LayoutImage>(layout_object);
if (image->CachedImage() && !image->CachedImage()->ErrorOccurred())
@@ -408,9 +418,8 @@ IntRect HitTestResult::ImageRect() const {
.EnclosingBoundingBox();
}
-KURL HitTestResult::AbsoluteImageURL() const {
- Node* inner_node_or_image_map_image = InnerNodeOrImageMapImage();
- if (!inner_node_or_image_map_image)
+KURL HitTestResult::AbsoluteImageURL(const Node* node) {
+ if (!node)
return KURL();
AtomicString url_string;
@@ -418,25 +427,26 @@ KURL HitTestResult::AbsoluteImageURL() const {
// even if they don't have a LayoutImage (e.g. because the image didn't load
// and we are using an alt container). For other elements we don't create alt
// containers so ensure they contain a loaded image.
- auto* html_input_element =
- DynamicTo<HTMLInputElement>(inner_node_or_image_map_image);
- if (IsA<HTMLImageElement>(*inner_node_or_image_map_image) ||
+ auto* html_input_element = DynamicTo<HTMLInputElement>(node);
+ if (IsA<HTMLImageElement>(*node) ||
(html_input_element &&
html_input_element->type() == input_type_names::kImage))
- url_string = To<Element>(*inner_node_or_image_map_image).ImageSourceURL();
- else if ((inner_node_or_image_map_image->GetLayoutObject() &&
- inner_node_or_image_map_image->GetLayoutObject()->IsImage()) &&
- (IsA<HTMLEmbedElement>(*inner_node_or_image_map_image) ||
- IsA<HTMLObjectElement>(*inner_node_or_image_map_image) ||
- IsA<SVGImageElement>(*inner_node_or_image_map_image)))
- url_string = To<Element>(*inner_node_or_image_map_image).ImageSourceURL();
+ url_string = To<Element>(*node).ImageSourceURL();
+ else if ((node->GetLayoutObject() && node->GetLayoutObject()->IsImage()) &&
+ (IsA<HTMLEmbedElement>(*node) || IsA<HTMLObjectElement>(*node) ||
+ IsA<SVGImageElement>(*node)))
+ url_string = To<Element>(*node).ImageSourceURL();
if (url_string.IsEmpty())
return KURL();
- return inner_node_or_image_map_image->GetDocument().CompleteURL(
+ return node->GetDocument().CompleteURL(
StripLeadingAndTrailingHTMLSpaces(url_string));
}
+KURL HitTestResult::AbsoluteImageURL() const {
+ return AbsoluteImageURL(InnerNodeOrImageMapImage());
+}
+
KURL HitTestResult::AbsoluteMediaURL() const {
if (HTMLMediaElement* media_elt = MediaElement())
return media_elt->currentSrc();
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
index c9588a679da..4a61ec20a64 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
@@ -47,7 +47,6 @@ class KURL;
class MediaStreamDescriptor;
class NGPhysicalBoxFragment;
class Node;
-class LayoutObject;
class Region;
class Scrollbar;
struct PhysicalOffset;
@@ -114,7 +113,8 @@ class CORE_EXPORT HitTestResult {
}
LocalFrame* InnerNodeFrame() const;
- // The hit-tested point in the coordinates of the inner node.
+ // The hit-tested point in the coordinates of the
+ // |inner_possibly_pseudo_node_|.
const PhysicalOffset& LocalPoint() const { return local_point_; }
void SetNodeAndPosition(Node* node, const PhysicalOffset& p) {
local_point_ = p;
@@ -124,17 +124,15 @@ class CORE_EXPORT HitTestResult {
scoped_refptr<const NGPhysicalBoxFragment>,
const PhysicalOffset&);
- // Set the box fragment to be associated with the inner node. If the inner
- // node is text or non-atomic inline content, this will be a fragment
- // generated by the containing block of the inner node. In all other cases, it
- // will be a fragment generated by the inner node itself.
- void SetBoxFragment(scoped_refptr<const NGPhysicalBoxFragment>);
- const NGPhysicalBoxFragment* BoxFragment() const {
- return box_fragment_.get();
- }
+ // Override an inner node previously set. The new node needs to be monolithic
+ // (or at least only consist of one fragment).
+ //
+ // TODO(layout-dev): Figure out if we really need this. Why can't we just
+ // hit-test correctly in the first place instead?
+ void OverrideNodeAndPosition(Node*, PhysicalOffset);
PositionWithAffinity GetPosition() const;
- LayoutObject* GetLayoutObject() const;
+ PositionWithAffinity GetPositionForInnerNodeOrImageMapImage() const;
void SetToShadowHostIfInRestrictedShadowRoot();
@@ -152,8 +150,10 @@ class CORE_EXPORT HitTestResult {
bool IsSelected(const HitTestLocation& location) const;
String Title(TextDirection&) const;
const AtomicString& AltDisplayString() const;
+ static Image* GetImage(const Node* node);
Image* GetImage() const;
IntRect ImageRect() const;
+ static KURL AbsoluteImageURL(const Node* node);
KURL AbsoluteImageURL() const;
KURL AbsoluteMediaURL() const;
MediaStreamDescriptor* GetMediaStreamDescriptor() const;
@@ -212,14 +212,14 @@ class CORE_EXPORT HitTestResult {
// FIXME: Nothing changes this to a value different from m_hitTestLocation!
// The hit-tested point in innerNode frame coordinates.
PhysicalOffset point_in_inner_node_frame_;
- // A point in the local coordinate space of m_innerNode's layoutObject.Allows
+ // A point in the local coordinate space of |inner_possibly_pseudo_node_|'s
+ // layoutObject, or its containing block when it is an inline object. Allows
// us to efficiently determine where inside the layoutObject we hit on
// subsequent operations.
PhysicalOffset local_point_;
// For non-URL, this is the enclosing that triggers navigation.
Member<Element> inner_url_element_;
Member<Scrollbar> scrollbar_;
- scoped_refptr<const NGPhysicalBoxFragment> box_fragment_;
// Returns true if we are over a EmbeddedContentView (and not in the
// border/padding area of a LayoutEmbeddedContent for example).
bool is_over_embedded_content_view_;
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_testing_test.cc b/chromium/third_party/blink/renderer/core/layout/hit_testing_test.cc
index 76f912f9095..958da2c32c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_testing_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_testing_test.cc
@@ -2,9 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/metrics/histogram_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -30,46 +36,6 @@ class HitTestingTest : public RenderingTest {
}
};
-// http://crbug.com/1043471
-TEST_F(HitTestingTest, PseudoElementAfter) {
- LoadAhem();
- InsertStyleElement(
- "body { margin: 0px; font: 10px/10px Ahem; }"
- "#cd::after { content: 'XYZ'; margin-left: 100px; }");
- SetBodyInnerHTML("<div id=ab>ab<span id=cd>cd</span></div>");
- const auto& text_ab = *To<Text>(GetElementById("ab")->firstChild());
- const auto& text_cd = *To<Text>(GetElementById("cd")->lastChild());
-
- EXPECT_EQ(PositionWithAffinity(Position(text_ab, 0)),
- HitTest(PhysicalOffset(5, 5)));
- // Because of hit testing at "b", position should be |kDownstream|.
- EXPECT_EQ(PositionWithAffinity(Position(text_ab, 1),
- LayoutNGEnabled() ? TextAffinity::kDownstream
- : TextAffinity::kUpstream),
- HitTest(PhysicalOffset(15, 5)));
- EXPECT_EQ(PositionWithAffinity(Position(text_cd, 0)),
- HitTest(PhysicalOffset(25, 5)));
- // Because of hit testing at "d", position should be |kDownstream|.
- EXPECT_EQ(PositionWithAffinity(Position(text_cd, 1),
- LayoutNGEnabled() ? TextAffinity::kDownstream
- : TextAffinity::kUpstream),
- HitTest(PhysicalOffset(35, 5)));
- // Because of hit testing at right of <span cd>, result position should be
- // |kUpstream|.
- EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
- LayoutNGEnabled() ? TextAffinity::kUpstream
- : TextAffinity::kDownstream),
- HitTest(PhysicalOffset(45, 5)));
- EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
- LayoutNGEnabled() ? TextAffinity::kUpstream
- : TextAffinity::kDownstream),
- HitTest(PhysicalOffset(55, 5)));
- EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
- LayoutNGEnabled() ? TextAffinity::kUpstream
- : TextAffinity::kDownstream),
- HitTest(PhysicalOffset(65, 5)));
-}
-
TEST_F(HitTestingTest, OcclusionHitTest) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -137,4 +103,74 @@ TEST_F(HitTestingTest, OcclusionHitTestWithClipPath) {
EXPECT_EQ(result.InnerNode(), occluder);
}
+// crbug.com/1153037
+TEST_F(HitTestingTest, LegacyInputElementInFragmentTraversal) {
+ ScopedLayoutNGFragmentTraversalForTest fragment_traversal_feature(true);
+ ScopedEditingNGForTest editing_feature(false);
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin:100px; }
+ </style>
+ <input id="target">
+ )HTML");
+
+ const HitTestRequest hit_request(HitTestRequest::kActive);
+ const HitTestLocation hit_location(PhysicalOffset(110, 110));
+ HitTestResult hit_result(hit_request, hit_location);
+ ASSERT_TRUE(GetLayoutView().HitTest(hit_location, hit_result));
+ ASSERT_TRUE(hit_result.InnerNode());
+ const auto* layout_object = hit_result.InnerNode()->GetLayoutObject();
+ ASSERT_TRUE(layout_object);
+
+ // In this test we'll use the legacy layout engine for form controls, so the
+ // INPUT element will generate a LayoutTextControl with an inner editable
+ // LayoutBlockFlow child. We'll hit-test by traversing the fragment tree
+ // (rather than the LayoutObject tree). We should hit the inner
+ // LayoutBlockFlow. Since it is a legacy object and it is also laid out by a
+ // legacy parent, it will not generate any NG fragments. Check that we hit the
+ // right node, and that the hit-testing code hasn't incorrectly set an NG
+ // fragment from an ancestor.
+
+ ASSERT_EQ(layout_object->Parent()->GetNode(),
+ GetDocument().getElementById("target"));
+}
+
+TEST_F(HitTestingTest, ScrolledInline) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font-size: 50px;
+ line-height: 1;
+ }
+ #scroller {
+ width: 400px;
+ height: 5em;
+ overflow: scroll;
+ white-space: pre;
+ }
+ </style>
+ <div id="scroller">line1
+line2
+line3
+line4
+line5
+line6
+line7
+line8
+line9</div>
+ )HTML");
+
+ // Scroll #scroller by 2 lines. "line3" should be at the top.
+ Element* scroller = GetElementById("scroller");
+ scroller->setScrollTop(100);
+
+ const auto& text = *To<Text>(GetElementById("scroller")->firstChild());
+
+ // Expect to hit test position 12 (beginning of line3).
+ EXPECT_EQ(PositionWithAffinity(Position(text, 12)),
+ HitTest(PhysicalOffset(5, 5)));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout-shift-tracker-old-paint-offset.md b/chromium/third_party/blink/renderer/core/layout/layout-shift-tracker-old-paint-offset.md
new file mode 100644
index 00000000000..69a8fa38f50
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout-shift-tracker-old-paint-offset.md
@@ -0,0 +1,76 @@
+# Explanation of `old_paint_offset` adjustment for
+`LayoutShiftTracker::NotifyBoxPrePaint()`
+
+Suppose from the layout shift root (see
+[PaintPropertyTreeBuilder](../paint/paint_property_tree_builder.h) for the
+definition) to a LayoutObject, there are transform nodes:
+```
+ {Troot, T1, T2, ... Tn}
+```
+where T1, T2, ... Tn are all 2d translations including
+* `PaintOffsetTranslation`s
+* `Transform`s with 2d translation matrixes
+* `ScrollTranslation`
+
+The location of the LayoutObject in the layout shift root can be calculated
+from:
+* the paint offset,
+* `acc_2d = sum(2d-offset(Ti), i=1..n)`
+
+We can calculate the old location and the new location in the layout shift
+root:
+```
+ old_location = old_paint_offset + old_acc_2d
+ new_location = new_paint_offset + new_acc_2d
+```
+
+`LayoutShiftTracker` then could use `old_location`, `new_location` to check
+if the object has shifted within the layout shift root. Then it could map
+`old_location` and `new_location` from the layout shift root's property tree
+state to the viewport's property tree state to get the old and new location
+in viewport, then check if the object has shifted in viewport. This would
+need `PaintInvalidator` to pass the following parameters to
+`LayoutShiftTracker`:
+* `old_location`
+* `new_location`
+* property tree state of the layout shift root [^1]
+
+[^1] Changes of paint properties above the layout shift root are ignored
+ intentionally because
+ * It's hard to track such changes.
+ * Some of such changes (e.g. 3d transform) should be ignored according to
+ the spec.
+ * Layout shift of the root itself should have already been reported, so
+ the descendants just need to report their shift relative to the layout
+ shift root.
+
+However, the above set of parameters requires `PaintInvalidator` to track
+all of them. To reduce the amount of data to track, `PaintInvalidator` passes
+the following parameters instead [2]:
+* `adjusted_old_paint_offset = old_paint_offset - acc_2d_delta`
+* `new_paint_offset`
+* property tree state of the current object
+most of which can be gotten from the current context except `acc_2d_delta`.
+Then `LayoutShiftTracker` can use `adjusted_old_paint_offset` and
+`new_paint_offset` instead of `old_location` and `new_location` to check if
+the object has shifted within the layout shift root because
+```
+ new_location - old_location == new_paint_offset - adjusted_old_paint_offset
+```
+and it can map `adjusted_old_paint_offset` and `new_paint_offset` from the
+current paint property tree state of the object to the viewport, as if there
+were old paint property tree state below the layout shift root because the
+changes of paint properties below the layout shift root is accounted in
+`adjusted_old_paint_offset`.
+
+[^2] Actually `PaintInvalidator` also passes the following parameters:
+ * `translation_delta`
+ * `scroll_delta`
+ so that `LayoutShiftTracker` can check shift by ignoring (or not) 2d
+ translation and scroll changes below the layout shift root.
+ See [the explainer](https://github.com/WICG/layout-instability#transform-changes)
+ for why we ignore transform and scroll changes by default. However,
+ in case that a layout shift is countered by a transform change and/or a
+ scroll change making the element not visually move, we should ignore the
+ shift. These situations require `LayoutShiftTracker` to determine shift
+ by both including and not including the transform/scroll changes.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.cc b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
index 9080b5dd051..3ae16fd2a08 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
@@ -251,8 +251,12 @@ void LayoutBlock::UpdateFromStyle() {
NOT_DESTROYED();
LayoutBox::UpdateFromStyle();
- bool should_clip_overflow = !StyleRef().IsOverflowVisibleAlongBothAxes() &&
- AllowsNonVisibleOverflow();
+ // OverflowClipMargin() is only set if overflow is 'clip' along both axis, or
+ // 'contain: paint'. The later implies clipping along both axis.
+ bool should_clip_overflow =
+ (!StyleRef().IsOverflowVisibleAlongBothAxes() ||
+ StyleRef().OverflowClipMargin() != LayoutUnit()) &&
+ AllowsNonVisibleOverflow();
if (should_clip_overflow != HasNonVisibleOverflow()) {
if (GetScrollableArea())
GetScrollableArea()->InvalidateAllStickyConstraints();
@@ -293,7 +297,7 @@ void LayoutBlock::AddChildBeforeDescendant(LayoutObject* new_child,
if (new_child->IsInline() ||
(new_child->IsFloatingOrOutOfFlowPositioned() &&
(StyleRef().IsDeprecatedFlexboxUsingFlexLayout() ||
- (!IsFlexibleBoxIncludingNG() && !IsLayoutGrid()))) ||
+ (!IsFlexibleBoxIncludingNG() && !IsLayoutGridIncludingNG()))) ||
before_descendant->Parent()->SlowFirstChild() != before_descendant) {
before_descendant_container->AddChild(new_child, before_descendant);
} else {
@@ -337,7 +341,7 @@ void LayoutBlock::AddChild(LayoutObject* new_child,
if (new_child->IsInline() ||
(new_child->IsFloatingOrOutOfFlowPositioned() &&
(StyleRef().IsDeprecatedFlexboxUsingFlexLayout() ||
- (!IsFlexibleBoxIncludingNG() && !IsLayoutGrid())))) {
+ (!IsFlexibleBoxIncludingNG() && !IsLayoutGridIncludingNG())))) {
// If we're inserting an inline child but all of our children are blocks,
// then we have to make sure it is put into an anomyous block box. We try to
// use an existing anonymous box if possible, otherwise a new one is created
@@ -384,7 +388,7 @@ void LayoutBlock::RemoveLeftoverAnonymousBlock(LayoutBlock* child) {
// LayoutGrid keeps track of its children, we must notify it about changes in
// the tree.
if (child->Parent()->IsLayoutGrid())
- ToLayoutGrid(child->Parent())->DirtyGrid();
+ To<LayoutGrid>(child->Parent())->DirtyGrid();
// Now remove the leftover anonymous block from the tree, and destroy it.
// We'll rip it out manually from the tree before destroying it, because we
@@ -490,6 +494,21 @@ void LayoutBlock::AddLayoutOverflowFromChildren() {
AddLayoutOverflowFromBlockChildren();
}
+OverflowClipAxes LayoutBlock::ComputeOverflowClipAxes() const {
+ const OverflowClipAxes layout_box_clip_axes =
+ LayoutBox::ComputeOverflowClipAxes();
+ if (layout_box_clip_axes != kNoOverflowClip)
+ return layout_box_clip_axes;
+ if (!HasNonVisibleOverflow())
+ return kNoOverflowClip;
+ if (IsScrollContainer())
+ return kOverflowClipBothAxis;
+ return (StyleRef().OverflowX() == EOverflow::kVisible ? kNoOverflowClip
+ : kOverflowClipX) |
+ (StyleRef().OverflowY() == EOverflow::kVisible ? kNoOverflowClip
+ : kOverflowClipY);
+}
+
void LayoutBlock::ComputeVisualOverflow(bool) {
NOT_DESTROYED();
DCHECK(!SelfNeedsLayout());
@@ -546,8 +565,6 @@ void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
}
}
}
-
- ApplyOverflowClipToLayoutOverflowRect();
}
void LayoutBlock::AddVisualOverflowFromBlockChildren() {
@@ -948,7 +965,7 @@ void LayoutBlock::LayoutPositionedObject(LayoutBox* positioned_object,
LayoutFlexibleBox::SetStaticPositionForChildInFlexNGContainer(
*positioned_object, To<LayoutBlock>(parent))) ||
(parent->IsFlexibleBox() &&
- ToLayoutFlexibleBox(parent)->SetStaticPositionForPositionedLayout(
+ To<LayoutFlexibleBox>(parent)->SetStaticPositionForPositionedLayout(
*positioned_object))) {
// The static position of an abspos child of a flexbox depends on its size
// (for example, they can be centered). So we may have to reposition the
@@ -1047,9 +1064,7 @@ void LayoutBlock::RemovePositionedObject(LayoutBox* o) {
bool LayoutBlock::IsAnonymousNGFieldsetContentWrapper() const {
NOT_DESTROYED();
- if (!RuntimeEnabledFeatures::LayoutNGFieldsetEnabled() || !Parent())
- return false;
- return Parent()->IsLayoutNGFieldset();
+ return Parent() && Parent()->IsLayoutNGFieldset();
}
void LayoutBlock::InvalidatePaint(
@@ -1320,15 +1335,20 @@ Position LayoutBlock::PositionForBox(InlineBox* box, bool start) const {
if (!box)
return Position();
- if (!box->GetLineLayoutItem().NonPseudoNode())
- return Position::EditingPositionOf(
- NonPseudoNode(), start ? CaretMinOffset() : CaretMaxOffset());
+ Node* const node = box->GetLineLayoutItem().NonPseudoNode();
+ if (!node) {
+ if (!NonPseudoNode())
+ return Position();
+ if (start)
+ return Position::FirstPositionInOrBeforeNode(*NonPseudoNode());
+ return Position::LastPositionInOrAfterNode(*NonPseudoNode());
+ }
- if (!box->IsInlineTextBox())
- return Position::EditingPositionOf(
- box->GetLineLayoutItem().NonPseudoNode(),
- start ? box->GetLineLayoutItem().CaretMinOffset()
- : box->GetLineLayoutItem().CaretMaxOffset());
+ if (!box->IsInlineTextBox()) {
+ if (start)
+ return Position::FirstPositionInOrBeforeNode(*node);
+ return Position::LastPositionInOrAfterNode(*node);
+ }
auto* text_box = To<InlineTextBox>(box);
return Position::EditingPositionOf(
@@ -1384,10 +1404,14 @@ PositionWithAffinity LayoutBlock::PositionForPointRespectingEditingBoundaries(
LayoutUnit logical_left = IsHorizontalWritingMode()
? point_in_child_coordinates.left
: point_in_child_coordinates.top;
- if (logical_left < child_middle)
- return ancestor->CreatePositionWithAffinity(child_node->NodeIndex());
- return ancestor->CreatePositionWithAffinity(child_node->NodeIndex() + 1,
- TextAffinity::kUpstream);
+ if (logical_left < child_middle) {
+ if (IsUserSelectContain(*ancestor->NonPseudoNode()))
+ return ancestor->PositionBeforeThis();
+ return child.PositionBeforeThis();
+ }
+ if (IsUserSelectContain(*ancestor->NonPseudoNode()))
+ return ancestor->PositionAfterThis();
+ return child.PositionAfterThis();
}
PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel(
@@ -1398,13 +1422,13 @@ PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel(
point.ConvertToLogical({StyleRef().GetWritingMode(), ResolvedDirection()},
PhysicalSize(Size()), PhysicalSize());
if (logical_offset.inline_offset < 0)
- return CreatePositionWithAffinity(CaretMinOffset());
+ return FirstPositionInOrBeforeThis();
if (logical_offset.inline_offset >= LogicalWidth())
- return CreatePositionWithAffinity(CaretMaxOffset());
+ return LastPositionInOrAfterThis();
if (logical_offset.block_offset < 0)
- return CreatePositionWithAffinity(CaretMinOffset());
+ return FirstPositionInOrBeforeThis();
if (logical_offset.block_offset >= LogicalHeight())
- return CreatePositionWithAffinity(CaretMaxOffset());
+ return LastPositionInOrAfterThis();
return PositionWithAffinity();
}
@@ -1417,17 +1441,10 @@ static inline bool IsChildHitTestCandidate(LayoutBox* box) {
PositionWithAffinity LayoutBlock::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
-
- if (IsLayoutNGObject() && PhysicalFragmentCount() &&
- NGPhysicalBoxFragment::SupportsPositionForPoint()) {
- // Layout engine boundary. Enter NG PositionForPoint(). Assert
- // that we're not block-fragmented here.
- DCHECK_EQ(PhysicalFragmentCount(), 1u);
- return GetPhysicalFragment(0)->PositionForPoint(point);
- }
-
- if (IsTable())
- return LayoutBox::PositionForPoint(point);
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsLayoutNGObject() || GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
if (IsAtomicInlineLevel()) {
PositionWithAffinity position =
@@ -1436,6 +1453,14 @@ PositionWithAffinity LayoutBlock::PositionForPoint(
return position;
}
+ if (IsLayoutNGObject() && PhysicalFragmentCount() &&
+ RuntimeEnabledFeatures::LayoutNGFullPositionForPointEnabled()) {
+ return PositionForPointInFragments(point);
+ }
+
+ if (IsTable())
+ return LayoutBox::PositionForPoint(point);
+
PhysicalOffset point_in_contents = point;
OffsetForContents(point_in_contents);
LayoutPoint point_in_logical_contents = FlipForWritingMode(point_in_contents);
@@ -1592,6 +1617,10 @@ MinMaxSizes LayoutBlock::PreferredLogicalWidths() const {
sizes.max_size = LayoutUnit(sizes.max_size.Ceil());
}
+ if (IsLayoutNGMixin() && IsTable()) {
+ sizes.Encompass(IntrinsicLogicalWidths().min_size);
+ }
+
return sizes;
}
@@ -2451,7 +2480,7 @@ LayoutUnit LayoutBlock::AvailableLogicalHeightForPercentageComputation() const {
LayoutUnit stretched_flex_height(-1);
if (IsFlexItem()) {
- const LayoutFlexibleBox* flex_box = ToLayoutFlexibleBox(Parent());
+ const auto* flex_box = To<LayoutFlexibleBox>(Parent());
if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*this))
stretched_flex_height = OverrideContentLogicalHeight();
} else if (HasOverrideLogicalHeight() && IsOverrideLogicalHeightDefinite()) {
@@ -2475,8 +2504,8 @@ LayoutUnit LayoutBlock::AvailableLogicalHeightForPercentageComputation() const {
BorderBefore() + ComputedCSSPaddingBefore(),
BorderAfter() + ComputedCSSPaddingAfter());
available_height = BlockSizeFromAspectRatio(
- border_padding, StyleRef().LogicalAspectRatio(), StyleRef().BoxSizing(),
- LogicalWidth());
+ border_padding, StyleRef().LogicalAspectRatio(),
+ StyleRef().BoxSizingForAspectRatio(), LogicalWidth());
} else if (style.LogicalHeight().IsPercentOrCalc() &&
!is_out_of_flow_positioned_with_specified_height) {
LayoutUnit height_with_scrollbar =
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.h b/chromium/third_party/blink/renderer/core/layout/layout_block.h
index d9895cc1e13..8fb01a95b19 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.h
@@ -507,6 +507,7 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
void AddLayoutOverflowFromBlockChildren();
protected:
+ OverflowClipAxes ComputeOverflowClipAxes() const override;
virtual void ComputeVisualOverflow(
bool recompute_floats);
virtual void ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 6eec838866b..eab40a2a3b3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -38,7 +38,6 @@
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/html/html_dialog_element.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
@@ -66,7 +65,6 @@
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
#include "third_party/blink/renderer/core/page/named_pages_mapper.h"
#include "third_party/blink/renderer/core/paint/block_flow_paint_invalidator.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -143,12 +141,8 @@ class MarginInfo {
void SetDeterminedMarginBeforeQuirk(bool b) {
determined_margin_before_quirk_ = b;
}
- void SetPositiveMargin(LayoutUnit p) {
- positive_margin_ = p;
- }
- void SetNegativeMargin(LayoutUnit n) {
- negative_margin_ = n;
- }
+ void SetPositiveMargin(LayoutUnit p) { positive_margin_ = p; }
+ void SetNegativeMargin(LayoutUnit n) { negative_margin_ = n; }
void SetPositiveMarginIfLarger(LayoutUnit p) {
if (p > positive_margin_)
positive_margin_ = p;
@@ -749,8 +743,6 @@ void LayoutBlockFlow::MarkDescendantsWithFloatsForLayoutIfNeeded(
LayoutUnit new_logical_top,
LayoutUnit previous_float_logical_bottom) {
NOT_DESTROYED();
- // TODO(mstensho): rework the code to return early when there is no need for
- // marking, instead of this |markDescendantsWithFloats| flag.
bool mark_descendants_with_floats = false;
if (new_logical_top != child.LogicalTop() &&
!child.CreatesNewFormattingContext() && child.ContainsFloats()) {
@@ -794,9 +786,6 @@ bool LayoutBlockFlow::PositionAndLayoutOnceIfNeeded(
*child_block_flow, new_logical_top, previous_float_logical_bottom);
}
- // TODO(mstensho): A writing mode root is one thing, but we should be able
- // to skip anything that establishes a new block formatting context here.
- // Their floats don't affect us.
if (!child_block_flow->IsWritingModeRoot() &&
child_block_flow->ContainsFloats()) {
// Only do this if the child actually contains floats, so that we don't
@@ -1253,18 +1242,6 @@ static bool ShouldSetStrutOnBlock(const LayoutBlockFlow& block,
void LayoutBlockFlow::AdjustLinePositionForPagination(RootInlineBox& line_box,
LayoutUnit& delta) {
NOT_DESTROYED();
- // TODO(mstensho): Pay attention to line overflow. It should be painted in the
- // same column as the rest of the line, possibly overflowing the column. We
- // currently only allow overflow above the first column. We clip at all other
- // column boundaries, and that's how it has to be for now. The paint we have
- // to do when a column has overflow has to be special.
- // We need to exclude content that paints in a previous column (and content
- // that paints in the following column).
- //
- // FIXME: Another problem with simply moving lines is that the available line
- // width may change (because of floats). Technically if the location we move
- // the line to has a different line width than our old position, then we need
- // to dirty the line and all following lines.
LayoutUnit logical_offset = line_box.LineTopWithLeading();
LayoutUnit line_height = line_box.LineBottomWithLeading() - logical_offset;
logical_offset += delta;
@@ -1298,10 +1275,6 @@ void LayoutBlockFlow::AdjustLinePositionForPagination(RootInlineBox& line_box,
} else if (line_height > page_logical_height) {
// Too tall to fit in one page / column. Give up. Don't push to the next
// page / column.
- // TODO(mstensho): Get rid of this. This is just utter weirdness, but the
- // other browsers also do something slightly similar, although in much
- // more specific cases than we do here, and printing Google Docs depends
- // on it.
PaginatedContentWasLaidOut(logical_offset + line_height);
return;
}
@@ -2355,11 +2328,6 @@ LayoutUnit LayoutBlockFlow::ApplyForcedBreak(LayoutUnit logical_offset,
NOT_DESTROYED();
if (!IsForcedFragmentainerBreakValue(break_value))
return logical_offset;
- // TODO(mstensho): honor breakValue. There are different types of forced
- // breaks. We currently just assume that we want to break to the top of the
- // next fragmentainer of the fragmentation context we're in. However, we may
- // want to find the next left or right page - even if we're inside a multicol
- // container when printing.
if (!IsPageLogicalHeightKnown()) {
// Page height is still unknown, so we cannot insert forced breaks.
return logical_offset;
@@ -2470,12 +2438,6 @@ void LayoutBlockFlow::AddLayoutOverflowFromFloats() {
}
}
-void LayoutBlockFlow::SetPaintFragment(
- const NGBlockBreakToken*,
- scoped_refptr<const NGPhysicalFragment>) {
- NOT_DESTROYED();
-}
-
void LayoutBlockFlow::ComputeVisualOverflow(bool recompute_floats) {
NOT_DESTROYED();
DCHECK(!SelfNeedsLayout());
@@ -2554,12 +2516,6 @@ void LayoutBlockFlow::DeleteLineBoxTree() {
floating_objects_->ClearLineBoxTreePointers();
line_boxes_.DeleteLineBoxTree();
-
- // This function is called when children are moved to different parent. Clear
- // NGPaintFragment now, because clearing NGPaintFragment clears associations
- // between LayoutObject and NGPaintFragment. It needs to happen before moved
- // children are laid out and associated.
- SetPaintFragment(nullptr, nullptr);
}
int LayoutBlockFlow::LineCount(
@@ -2607,15 +2563,6 @@ LayoutUnit LayoutBlockFlow::FirstLineBoxBaseline() const {
return FirstLineBox()->LogicalTop() +
font_data->GetFontMetrics().Ascent(FirstRootBox()->BaselineType());
}
- if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- NGBoxFragment box_fragment(
- StyleRef().GetWritingDirection(),
- To<NGPhysicalBoxFragment>(paint_fragment->PhysicalFragment()));
- if (const base::Optional<LayoutUnit> baseline = box_fragment.Baseline())
- return *baseline;
- }
- }
return EmptyLineBaseline(IsHorizontalWritingMode() ? kHorizontalLine
: kVerticalLine);
}
@@ -4306,16 +4253,10 @@ bool LayoutBlockFlow::AllowsPaginationStrut() const {
// struts and handle them. We handle floats and regular in-flow children, and
// that's all. We could handle this in other layout modes as well (and even
// for out-of-flow children), but currently we don't.
- // TODO(mstensho): But we *should*.
if (IsOutOfFlowPositioned())
return false;
if (IsLayoutFlowThread()) {
// Don't let the strut escape the fragmentation context and get lost.
- // TODO(mstensho): If we're in a nested fragmentation context, we should
- // ideally convert and propagate the strut to the outer fragmentation
- // context, so that the inner one is fully pushed to the next outer
- // fragmentainer, instead of taking up unusable space in the previous one.
- // But currently we have no mechanism in place to handle this.
return false;
}
const auto* containing_block_flow =
@@ -4605,13 +4546,7 @@ void LayoutBlockFlow::RecalcInlineChildrenVisualOverflow() {
NOT_DESTROYED();
DCHECK(ChildrenInline());
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- paint_fragment->RecalcInlineChildrenInkOverflow();
- return;
- }
-
- if (PhysicalFragmentCount() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (PhysicalFragmentCount()) {
for (const NGPhysicalBoxFragment& fragment : PhysicalFragments()) {
if (const NGFragmentItems* items = fragment.Items()) {
NGInlineCursor cursor(fragment, *items);
@@ -4659,31 +4594,13 @@ void LayoutBlockFlow::RecalcFloatingDescendantsVisualOverflow(
}
PositionWithAffinity LayoutBlockFlow::PositionForPoint(
- const LayoutObject& offset_parent,
- const PhysicalOffset& offset) const {
- NOT_DESTROYED();
- // Currently this function is called only from an inline child of this
- // |LayoutBlockFlow|.
- DCHECK(offset_parent.IsInline());
- DCHECK(offset_parent.IsDescendantOf(this));
- DCHECK(ChildrenInline());
-
- // For inline children, the offset is relative to its containing
- // |LayoutBlockFlow|. If this is scrolling, convert the content offset to the
- // offset of this |LayoutBlockFlow|.
- if (IsScrollContainer()) {
- PhysicalOffset offset_in_this = offset;
- offset_in_this -= PhysicalOffset(PixelSnappedScrolledContentOffset());
- return PositionForPoint(offset_in_this);
- }
-
- // Otherwise no covnersion is needed.
- return PositionForPoint(offset);
-}
-
-PositionWithAffinity LayoutBlockFlow::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsLayoutNGObject() || GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
+
if (IsAtomicInlineLevel()) {
PositionWithAffinity position =
PositionForPointIfOutsideAtomicInlineLevel(point);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
index bbc790aa529..d374f4c4f8d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -58,10 +58,8 @@ class LayoutMultiColumnFlowThread;
class LayoutMultiColumnSpannerPlaceholder;
class LayoutRubyRun;
class MarginInfo;
-class NGBlockBreakToken;
class NGOffsetMapping;
class NGPhysicalContainerFragment;
-class NGPhysicalFragment;
struct NGInlineNodeData;
@@ -480,8 +478,7 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
void RecalcInlineChildrenVisualOverflow();
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
- PositionWithAffinity PositionForPoint(const LayoutObject& offset_parent,
- const PhysicalOffset& offset) const;
+
bool ShouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom() const;
LayoutUnit LowestFloatLogicalBottom(EClear = EClear::kBoth) const;
@@ -524,8 +521,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
return false;
}
virtual void WillCollectInlines() { NOT_DESTROYED(); }
- virtual void SetPaintFragment(const NGBlockBreakToken*,
- scoped_refptr<const NGPhysicalFragment>);
#if DCHECK_IS_ON()
void ShowLineTreeAndMark(const InlineBox* = nullptr,
@@ -1008,7 +1003,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
// LayoutRubyBase objects need to be able to split and merge, moving their
// children around (calling makeChildrenNonInline).
- // TODO(mstensho): Try to get rid of this friendship.
friend class LayoutRubyBase;
// FIXME-BLOCKFLOW: These methods have implementations in
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
index 9c921d1dff4..860c749fac1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -42,7 +42,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h"
#include "third_party/blink/renderer/core/layout/vertical_position_cache.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
#include "third_party/blink/renderer/platform/text/character.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -336,7 +335,7 @@ RootInlineBox* LayoutBlockFlow::ConstructLine(BidiRunList<BidiRun>& bidi_runs,
if (box->IsInlineTextBox()) {
if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
- cache->InlineTextBoxesUpdated(r->line_layout_item_);
+ cache->InlineTextBoxesUpdated(r->line_layout_item_.GetLayoutObject());
}
}
@@ -2198,6 +2197,10 @@ RootInlineBox* LayoutBlockFlow::DetermineStartPosition(
// If we have no dirty lines, then last is just the last root box.
last = curr ? curr->PrevRootBox() : LastRootBox();
+#if DCHECK_IS_ON()
+ if (last && last->LineBreakObj().GetLayoutObject())
+ last->LineBreakObj().GetLayoutObject()->CheckIsNotDestroyed();
+#endif
}
unsigned num_clean_floats = 0;
@@ -2422,17 +2425,7 @@ void LayoutBlockFlow::AddVisualOverflowFromInlineChildren() {
DCHECK(!NeedsLayout());
DCHECK(!ChildPrePaintBlockedByDisplayLock());
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- for (const NGPaintFragment* child : paint_fragment->Children()) {
- if (child->HasSelfPaintingLayer())
- continue;
- PhysicalRect child_rect = child->InkOverflow();
- if (!child_rect.IsEmpty()) {
- child_rect.offset += child->Offset();
- AddContentsVisualOverflow(child_rect);
- }
- }
- } else if (PhysicalFragmentCount()) {
+ if (PhysicalFragmentCount()) {
// TODO(crbug.com/1144203): This should compute in the stitched coordinate
// system, but overflows in the block direction is converted to the inline
// direction in the multicol container. Just unite overflows in the inline
@@ -2447,7 +2440,7 @@ void LayoutBlockFlow::AddVisualOverflowFromInlineChildren() {
continue;
PhysicalRect child_rect = child->InkOverflow();
if (!child_rect.IsEmpty()) {
- child_rect.offset += child->OffsetInContainerBlock();
+ child_rect.offset += child->OffsetInContainerFragment();
AddContentsVisualOverflow(child_rect);
}
}
@@ -2476,13 +2469,14 @@ void LayoutBlockFlow::AddVisualOverflowFromInlineChildren() {
if (!IsInlineWithOutlineAndContinuation(o))
continue;
+ const ComputedStyle& style = o.StyleRef();
Vector<PhysicalRect> outline_rects;
To<LayoutInline>(o).AddOutlineRectsForContinuations(
outline_rects, PhysicalOffset(),
- o.OutlineRectsShouldIncludeBlockVisualOverflow());
+ style.OutlineRectsShouldIncludeBlockVisualOverflow());
if (!outline_rects.IsEmpty()) {
PhysicalRect outline_bounds = UnionRect(outline_rects);
- outline_bounds.Inflate(LayoutUnit(o.StyleRef().OutlineOutsetExtent()));
+ outline_bounds.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
outline_bounds_of_all_continuations.Unite(outline_bounds);
}
}
@@ -2510,7 +2504,7 @@ void LayoutBlockFlow::AddLayoutOverflowFromInlineChildren() {
continue;
const NGFragmentItem& child = *cursor.CurrentItem();
LogicalRect logical_rect =
- fragment->ConvertChildToLogical(child.RectInContainerBlock());
+ fragment->ConvertChildToLogical(child.RectInContainerFragment());
logical_rect.size.inline_size += 1;
AddLayoutOverflow(
fragment->ConvertChildToPhysical(logical_rect).ToLayoutRect());
@@ -2837,11 +2831,6 @@ void LayoutBlockFlow::SetShouldDoFullPaintInvalidationForFirstLine() {
NOT_DESTROYED();
DCHECK(ChildrenInline());
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- paint_fragment->SetShouldDoFullPaintInvalidationForFirstLine();
- return;
- }
-
const auto fragments = PhysicalFragments();
if (!fragments.IsEmpty()) {
DCHECK(!FirstRootBox());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
index 8db18c67f2f..786f4a10fe7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
@@ -32,7 +32,6 @@
#include "cc/input/scroll_snap_data.h"
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -96,7 +95,6 @@
#include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
@@ -338,9 +336,12 @@ void CheckDidAddFragment(const LayoutBox& box,
if (new_fragment.HasItems())
DCHECK(box.ChildrenInline());
+ wtf_size_t index = 0;
for (const NGPhysicalBoxFragment& fragment : box.PhysicalFragments()) {
+ DCHECK_EQ(fragment.IsFirstForNode(), index == 0);
if (const NGFragmentItems* fragment_items = fragment.Items())
fragment_items->CheckAllItemsAreValid();
+ ++index;
}
}
#else
@@ -435,10 +436,7 @@ void LayoutBox::WillBeDestroyed() {
ShapeOutsideInfo::RemoveInfo(*this);
if (!DocumentBeingDestroyed()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (NGPaintFragment* first_inline_fragment = FirstInlineFragment())
- first_inline_fragment->LayoutObjectWillBeDestroyed();
- } else if (FirstInlineFragmentItemIndex()) {
+ if (FirstInlineFragmentItemIndex()) {
NGFragmentItems::LayoutObjectWillBeDestroyed(*this);
ClearFirstInlineFragmentItemIndex();
}
@@ -534,7 +532,6 @@ void LayoutBox::StyleWillChange(StyleDifference diff,
layout_invalidation_reason::kStyleChange);
if (IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
FirstInlineFragmentItemIndex()) {
// Out of flow are not part of |NGFragmentItems|, and that further
// changes including destruction cannot be tracked. Mark it is moved
@@ -729,6 +726,8 @@ void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange(
void LayoutBox::UpdateGridPositionAfterStyleChange(
const ComputedStyle* old_style) {
NOT_DESTROYED();
+ // TODO(crbug.com/1045599): Implement similar logic for GridNG (trigger full
+ // layout).
if (!old_style || !Parent() || !Parent()->IsLayoutGrid())
return;
@@ -748,7 +747,7 @@ void LayoutBox::UpdateGridPositionAfterStyleChange(
// It should be possible to not dirty the grid in some cases (like moving an
// explicitly placed grid item).
// For now, it's more simple to just always recompute the grid.
- ToLayoutGrid(Parent())->DirtyGrid();
+ To<LayoutGrid>(Parent())->DirtyGrid();
}
void LayoutBox::UpdateScrollSnapMappingAfterStyleChange(
@@ -836,8 +835,7 @@ void LayoutBox::LayoutSubtreeRoot() {
// If this box has an associated layout-result, rebuild the spine of the
// fragment-tree to ensure consistency.
- if (PhysicalFragmentCount() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (PhysicalFragmentCount()) {
LayoutBlock* cb = ContainingBlock();
while (NGBlockNode::CanUseNewLayout(*cb) && !cb->NeedsLayout()) {
// Create and set a new identical results.
@@ -1282,8 +1280,10 @@ LayoutUnit LayoutBox::ConstrainLogicalWidthByMinMax(
// If we have an aspect-ratio, check if we need to apply min-width: auto.
Length min_length = style_to_use.LogicalMinWidth();
- if (!style_to_use.AspectRatio().IsAuto() &&
- style_to_use.LogicalWidth().IsAuto() && min_length.IsAuto() &&
+ if (!style_to_use.AspectRatio().IsAuto() && min_length.IsAuto() &&
+ (style_to_use.LogicalWidth().IsAuto() ||
+ style_to_use.LogicalWidth().IsMinContent() ||
+ style_to_use.LogicalWidth().IsMaxContent()) &&
style_to_use.OverflowInlineDirection() == EOverflow::kVisible) {
// Make sure we actually used the aspect ratio.
if (ShouldComputeLogicalWidthFromAspectRatio())
@@ -1516,11 +1516,13 @@ MinMaxSizes LayoutBox::ComputeMinMaxLogicalWidthFromAspectRatio() const {
MinMaxSizes transferred_min_max = {LayoutUnit(), LayoutUnit::Max()};
if (block_min_max.min_size > LayoutUnit()) {
transferred_min_max.min_size = InlineSizeFromAspectRatio(
- border_padding, ratio, StyleRef().BoxSizing(), block_min_max.min_size);
+ border_padding, ratio, StyleRef().BoxSizingForAspectRatio(),
+ block_min_max.min_size);
}
if (block_min_max.max_size != LayoutUnit::Max()) {
transferred_min_max.max_size = InlineSizeFromAspectRatio(
- border_padding, ratio, StyleRef().BoxSizing(), block_min_max.max_size);
+ border_padding, ratio, StyleRef().BoxSizingForAspectRatio(),
+ block_min_max.max_size);
}
// Minimum size wins over maximum size.
transferred_min_max.max_size =
@@ -1556,14 +1558,16 @@ bool LayoutBox::HasScrollbarGutters(ScrollbarOrientation orientation) const {
NGPhysicalBoxStrut LayoutBox::ComputeScrollbarsInternal(
ShouldClampToContentBox clamp_to_content_box,
- OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
+ OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,
+ ShouldIncludeScrollbarGutter include_scrollbar_gutter) const {
NOT_DESTROYED();
NGPhysicalBoxStrut scrollbars;
PaintLayerScrollableArea* scrollable_area = GetScrollableArea();
if (!scrollable_area)
return scrollbars;
- if (HasScrollbarGutters(kVerticalScrollbar)) {
+ if (include_scrollbar_gutter == kIncludeScrollbarGutter &&
+ HasScrollbarGutters(kVerticalScrollbar)) {
LayoutUnit gutter_size =
LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
kVerticalScrollbar, /* should_include_overlay_thickness */ true));
@@ -1584,7 +1588,8 @@ NGPhysicalBoxStrut LayoutBox::ComputeScrollbarsInternal(
overlay_scrollbar_clip_behavior));
}
- if (HasScrollbarGutters(kHorizontalScrollbar)) {
+ if (include_scrollbar_gutter == kIncludeScrollbarGutter &&
+ HasScrollbarGutters(kHorizontalScrollbar)) {
LayoutUnit gutter_size =
LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
kHorizontalScrollbar, /* should_include_overlay_thickness */ true));
@@ -2043,6 +2048,16 @@ bool LayoutBox::IsOverrideLogicalHeightDefinite() const {
return extra_input_ && extra_input_->is_override_block_size_definite;
}
+bool LayoutBox::StretchInlineSizeIfAuto() const {
+ NOT_DESTROYED();
+ return extra_input_ && extra_input_->stretch_inline_size_if_auto;
+}
+
+bool LayoutBox::StretchBlockSizeIfAuto() const {
+ NOT_DESTROYED();
+ return extra_input_ && extra_input_->stretch_block_size_if_auto;
+}
+
bool LayoutBox::HasOverrideLogicalHeight() const {
NOT_DESTROYED();
if (extra_input_ && extra_input_->override_block_size)
@@ -2692,6 +2707,10 @@ void LayoutBox::SizeChanged() {
// object for paint invalidation.
if (!NeedsLayout())
SetShouldCheckForPaintInvalidation();
+ // In flipped blocks writing mode, our children can change physical location,
+ // but their flipped location remains the same.
+ if (HasFlippedBlocksWritingMode())
+ SetSubtreeShouldCheckForPaintInvalidation();
}
bool LayoutBox::IntersectsVisibleViewport() const {
@@ -2811,8 +2830,13 @@ PhysicalRect LayoutBox::OverflowClipRect(
}
}
- if (IsScrollContainer())
- ExcludeScrollbars(clip_rect, overlay_scrollbar_clip_behavior);
+ if (IsScrollContainer()) {
+ // The additional gutters created by scrollbar-gutter don't occlude the
+ // content underneath, so they should not be clipped out here.
+ // See https://crbug.com/710214
+ ExcludeScrollbars(clip_rect, overlay_scrollbar_clip_behavior,
+ kExcludeScrollbarGutter);
+ }
auto* input = DynamicTo<HTMLInputElement>(GetNode());
if (UNLIKELY(input)) {
@@ -2845,13 +2869,15 @@ bool LayoutBox::HasControlClip() const {
void LayoutBox::ExcludeScrollbars(
PhysicalRect& rect,
- OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
+ OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,
+ ShouldIncludeScrollbarGutter include_scrollbar_gutter) const {
NOT_DESTROYED();
if (CanSkipComputeScrollbars())
return;
NGPhysicalBoxStrut scrollbars = ComputeScrollbarsInternal(
- kDoNotClampToContentBox, overlay_scrollbar_clip_behavior);
+ kDoNotClampToContentBox, overlay_scrollbar_clip_behavior,
+ include_scrollbar_gutter);
rect.offset.top += scrollbars.top;
rect.offset.left += scrollbars.left;
rect.size.width -= scrollbars.HorizontalSum();
@@ -3107,51 +3133,32 @@ bool LayoutBox::HasInlineFragments() const {
NOT_DESTROYED();
if (!IsInLayoutNGInlineFormattingContext())
return inline_box_wrapper_;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return first_paint_fragment_;
return first_fragment_item_index_;
}
-void LayoutBox::SetFirstInlineFragment(NGPaintFragment* fragment) {
- NOT_DESTROYED();
- CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- first_paint_fragment_ = fragment;
-}
-
void LayoutBox::ClearFirstInlineFragmentItemIndex() {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
first_fragment_item_index_ = 0u;
}
void LayoutBox::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
first_fragment_item_index_ = index;
}
void LayoutBox::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
NOT_DESTROYED();
- if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- SetFirstInlineFragment(nullptr);
- } else {
- ClearFirstInlineFragmentItemIndex();
- }
- } else {
+ if (IsInLayoutNGInlineFormattingContext())
+ ClearFirstInlineFragmentItemIndex();
+ else
DeleteLineBoxWrapper();
- }
- // Because |first_paint_fragment_| and |inline_box_wrapper_| are union, when
- // one is deleted, the other should be initialized to nullptr.
- DCHECK(new_value ? (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()
- ? !first_fragment_item_index_
- : !first_paint_fragment_)
- : !inline_box_wrapper_);
+ // Because |first_fragment_item_index_| and |inline_box_wrapper_| are union,
+ // when one is deleted, the other should be initialized to nullptr.
+ DCHECK(new_value ? !first_fragment_item_index_ : !inline_box_wrapper_);
}
bool LayoutBox::NGPhysicalFragmentList::HasFragmentItems() const {
@@ -3162,6 +3169,22 @@ bool LayoutBox::NGPhysicalFragmentList::HasFragmentItems() const {
return false;
}
+wtf_size_t LayoutBox::NGPhysicalFragmentList::IndexOf(
+ const NGPhysicalBoxFragment& fragment) const {
+ wtf_size_t index = 0;
+ for (const scoped_refptr<const NGLayoutResult>& result : layout_results_) {
+ if (&result->PhysicalFragment() == &fragment)
+ return index;
+ ++index;
+ }
+ return kNotFound;
+}
+
+bool LayoutBox::NGPhysicalFragmentList::Contains(
+ const NGPhysicalBoxFragment& fragment) const {
+ return IndexOf(fragment) != kNotFound;
+}
+
void LayoutBox::SetCachedLayoutResult(
scoped_refptr<const NGLayoutResult> result) {
NOT_DESTROYED();
@@ -3200,7 +3223,11 @@ void LayoutBox::AddLayoutResult(scoped_refptr<const NGLayoutResult> result,
return;
}
- DCHECK_EQ(index, layout_results_.size());
+ DCHECK(index == layout_results_.size() || index == kNotFound);
+ AddLayoutResult(std::move(result));
+}
+
+void LayoutBox::AddLayoutResult(scoped_refptr<const NGLayoutResult> result) {
const auto& fragment = To<NGPhysicalBoxFragment>(result->PhysicalFragment());
layout_results_.push_back(std::move(result));
CheckDidAddFragment(*this, fragment);
@@ -3246,6 +3273,21 @@ void LayoutBox::ReplaceLayoutResult(scoped_refptr<const NGLayoutResult> result,
NGFragmentItems::FinalizeAfterLayout(layout_results_);
}
+void LayoutBox::ReplaceLayoutResult(scoped_refptr<const NGLayoutResult> result,
+ const NGPhysicalBoxFragment& old_fragment) {
+ DCHECK_EQ(this, old_fragment.OwnerLayoutBox());
+ DCHECK_EQ(result->PhysicalFragment().GetSelfOrContainerLayoutObject(),
+ old_fragment.GetSelfOrContainerLayoutObject());
+ // TODO(kojii): |IndexOf| is O(n). Consider if we can avoid this.
+ const wtf_size_t index = PhysicalFragments().IndexOf(old_fragment);
+ if (index != kNotFound) {
+ ReplaceLayoutResult(std::move(result), index);
+ return;
+ }
+ NOTREACHED();
+ AddLayoutResult(std::move(result));
+}
+
void LayoutBox::ClearLayoutResults() {
NOT_DESTROYED();
if (measure_result_)
@@ -3346,7 +3388,7 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
// necessarily be marked for layout, since we don't detect that anything in
// there has changed (and detecting that would be more expensive). So just
// refuse to hit the cache, so that we force re-layout.
- if (UNLIKELY(IsAnonymous() && Parent()->IsLayoutNGFieldset()))
+ if (UNLIKELY(IsAnonymous() && Parent() && Parent()->IsLayoutNGFieldset()))
return nullptr;
DCHECK_EQ(cached_layout_result->Status(), NGLayoutResult::kSuccess);
@@ -3381,9 +3423,6 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
// If something needs "simplified" layout within a linebox, (e.g. an
// atomic-inline) we miss the cache.
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return nullptr;
-
// Check if some of line boxes are reusable.
// Only for the layout cache slot. Measure has several special
@@ -3508,14 +3547,15 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
// dirty layout bit(s). Note that we may be here because we are display locked
// and have cached a locked layout result. In that case, this function will
// not clear the child dirty bits.
- ClearNeedsLayout();
+ if (NeedsLayout())
+ ClearNeedsLayout();
- // Optimization: TableConstraintSpaceData can be large, and it is shared
+ // Optimization: NGTableConstraintSpaceData can be large, and it is shared
// between all the rows in a table. Make constraint space table data for
// reused row fragment be identical to the one used by other row fragments.
if (IsTableRow() && IsLayoutNGMixin()) {
- const_cast<NGConstraintSpace&>(old_space).ReplaceTableConstraintSpaceData(
- *new_space.TableData());
+ const_cast<NGConstraintSpace&>(old_space).ReplaceTableRowData(
+ *new_space.TableData(), new_space.TableRowIndex());
}
// OOF-positioned nodes have to two-tier cache. The additional cache check
@@ -4053,9 +4093,9 @@ bool LayoutBox::ComputeLogicalWidthFromAspectRatio(
BorderEnd() + ComputedCSSPaddingEnd(),
BorderBefore() + ComputedCSSPaddingBefore(),
BorderAfter() + ComputedCSSPaddingAfter());
- LayoutUnit logical_width =
- InlineSizeFromAspectRatio(border_padding, StyleRef().LogicalAspectRatio(),
- StyleRef().BoxSizing(), logical_height_for_ar);
+ LayoutUnit logical_width = InlineSizeFromAspectRatio(
+ border_padding, StyleRef().LogicalAspectRatio(),
+ StyleRef().BoxSizingForAspectRatio(), logical_height_for_ar);
*out_logical_width = ConstrainLogicalWidthByMinMax(
logical_width, container_width_in_inline_direction, ContainingBlock(),
/* allow_intrinsic */ false);
@@ -4118,12 +4158,14 @@ void LayoutBox::ComputeLogicalWidth(
ContainerWidthInInlineDirection();
LayoutBlock* cb = ContainingBlock();
- if (StyleRef().LogicalWidth().IsAuto() && !treat_as_replaced &&
- ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
- /* we're good */
- } else if (treat_as_replaced) {
+ if (treat_as_replaced) {
computed_values.extent_ =
ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth();
+ } else if (StyleRef().LogicalWidth().IsAuto() &&
+ (!IsGridItem() || !HasStretchedLogicalWidth() ||
+ !HasStretchedLogicalHeight()) &&
+ ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
+ /* we're good */
} else {
LayoutUnit preferred_width = ComputeLogicalWidthUsing(
kMainOrPreferredSize, style_to_use.LogicalWidth(),
@@ -4145,7 +4187,8 @@ void LayoutBox::ComputeLogicalWidth(
(computed_values.extent_ + computed_values.margins_.start_ +
computed_values.margins_.end_) &&
!IsFloating() && !IsInline() &&
- !cb->IsFlexibleBoxIncludingDeprecatedAndNG() && !cb->IsLayoutGrid()) {
+ !cb->IsFlexibleBoxIncludingDeprecatedAndNG() &&
+ !cb->IsLayoutGridIncludingNG()) {
LayoutUnit new_margin_total =
container_logical_width - computed_values.extent_;
bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
@@ -4360,6 +4403,33 @@ bool LayoutBox::HasStretchedLogicalWidth() const {
.GetPosition() == ItemPosition::kStretch;
}
+// TODO (lajava) Can/Should we move this inside specific layout classes (flex.
+// grid)? Can we refactor columnFlexItemHasStretchAlignment logic?
+bool LayoutBox::HasStretchedLogicalHeight() const {
+ NOT_DESTROYED();
+ const ComputedStyle& style = StyleRef();
+ if (!style.LogicalHeight().IsAuto() || style.MarginBefore().IsAuto() ||
+ style.MarginAfter().IsAuto())
+ return false;
+ LayoutBlock* cb = ContainingBlock();
+ if (!cb) {
+ // We are evaluating align-self/justify-self, which default to 'normal' for
+ // the root element. The 'normal' value behaves like 'start' except for
+ // Flexbox Items, which obviously should have a container.
+ return false;
+ }
+ if (cb->IsHorizontalWritingMode() != IsHorizontalWritingMode()) {
+ return style
+ .ResolvedJustifySelf(cb->SelfAlignmentNormalBehavior(this),
+ cb->Style())
+ .GetPosition() == ItemPosition::kStretch;
+ }
+ return style
+ .ResolvedAlignSelf(cb->SelfAlignmentNormalBehavior(this),
+ cb->Style())
+ .GetPosition() == ItemPosition::kStretch;
+}
+
bool LayoutBox::SizesLogicalWidthToFitContent(
const Length& logical_width) const {
NOT_DESTROYED();
@@ -4638,13 +4708,12 @@ void LayoutBox::ComputeLogicalHeight(
}
bool check_min_max_height = false;
- bool compute_size_as_replaced = ShouldComputeSizeAsReplaced();
// The parent box is flexing us, so it has increased or decreased our
// height. We have to grab our cached flexible height.
if (HasOverrideLogicalHeight()) {
h = Length::Fixed(OverrideLogicalHeight());
- } else if (compute_size_as_replaced) {
+ } else if (ShouldComputeSizeAsReplaced()) {
h = Length::Fixed(ComputeReplacedLogicalHeight() +
BorderAndPaddingLogicalHeight());
} else {
@@ -4654,15 +4723,14 @@ void LayoutBox::ComputeLogicalHeight(
LayoutUnit height_result;
if (check_min_max_height) {
- if (!compute_size_as_replaced &&
- ShouldComputeLogicalHeightFromAspectRatio()) {
+ if (ShouldComputeLogicalHeightFromAspectRatio()) {
NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
BorderEnd() + ComputedCSSPaddingEnd(),
BorderBefore() + ComputedCSSPaddingBefore(),
BorderAfter() + ComputedCSSPaddingAfter());
height_result = BlockSizeFromAspectRatio(
border_padding, StyleRef().LogicalAspectRatio(),
- StyleRef().BoxSizing(), LogicalWidth());
+ StyleRef().BoxSizingForAspectRatio(), LogicalWidth());
} else {
height_result = ComputeLogicalHeightUsing(
kMainOrPreferredSize, h,
@@ -4782,7 +4850,8 @@ LayoutUnit LayoutBox::ComputeIntrinsicLogicalContentHeightUsing(
logical_height_length.IsMaxContent() ||
logical_height_length.IsMinIntrinsic() ||
logical_height_length.IsFitContent()) {
- if (IsAtomicInlineLevel() && !IsFlexibleBoxIncludingNG() && !IsLayoutGrid())
+ if (IsAtomicInlineLevel() && !IsFlexibleBoxIncludingNG() &&
+ !IsLayoutGridIncludingNG())
return IntrinsicSize().Height();
return intrinsic_content_height;
}
@@ -4882,7 +4951,7 @@ bool LayoutBox::SkipContainingBlockForPercentHeightCalculation(
return !containing_block->IsTableCell() &&
!containing_block->IsOutOfFlowPositioned() &&
!containing_block->HasOverridePercentageResolutionBlockSize() &&
- !containing_block->IsLayoutGrid() &&
+ !containing_block->IsLayoutGridIncludingNG() &&
!containing_block->IsFlexibleBoxIncludingDeprecatedAndNG() &&
!containing_block->IsLayoutNGCustom();
}
@@ -4969,7 +5038,8 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPercentageResolution(
if (available_height == -1)
return available_height;
- available_height -= root_margin_border_padding_height;
+ available_height = std::max(
+ available_height - root_margin_border_padding_height, LayoutUnit());
// LayoutNG already includes padding in
// OverrideContainingBlockContentLogicalHeight so we only need to add it here
@@ -5005,8 +5075,8 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
// at the child's computed height.
bool subtract_border_and_padding =
IsTable() ||
- (!RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
- cb->IsTableCell() && !skipped_auto_height_containing_block &&
+ (!RuntimeEnabledFeatures::LayoutNGEnabled() && cb->IsTableCell() &&
+ !skipped_auto_height_containing_block &&
cb->HasOverrideLogicalHeight() &&
StyleRef().BoxSizing() == EBoxSizing::kContentBox);
if (subtract_border_and_padding) {
@@ -5048,12 +5118,15 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthRespectingMinMaxWidth(
LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
SizeType size_type,
- const Length& logical_width) const {
+ Length logical_width) const {
NOT_DESTROYED();
DCHECK(size_type == kMinSize || size_type == kMainOrPreferredSize ||
!logical_width.IsAuto());
if (size_type == kMinSize && logical_width.IsAuto())
return AdjustContentBoxLogicalWidthForBoxSizing(LayoutUnit());
+ if (size_type == kMainOrPreferredSize && logical_width.IsAuto() &&
+ StretchInlineSizeIfAuto())
+ logical_width = Length::FillAvailable();
switch (logical_width.GetType()) {
case Length::kFixed:
@@ -5176,12 +5249,15 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightRespectingMinMaxHeight(
LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
SizeType size_type,
- const Length& logical_height) const {
+ Length logical_height) const {
NOT_DESTROYED();
DCHECK(size_type == kMinSize || size_type == kMainOrPreferredSize ||
!logical_height.IsAuto());
if (size_type == kMinSize && logical_height.IsAuto())
return AdjustContentBoxLogicalHeightForBoxSizing(LayoutUnit());
+ if (size_type == kMainOrPreferredSize && logical_height.IsAuto() &&
+ StretchBlockSizeIfAuto())
+ logical_height = Length::FillAvailable();
switch (logical_height.GetType()) {
case Length::kFixed:
@@ -5203,8 +5279,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
if (block) {
block->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
if (block->IsFlexItem()) {
- const LayoutFlexibleBox* flex_box =
- ToLayoutFlexibleBox(block->Parent());
+ const auto* flex_box = To<LayoutFlexibleBox>(block->Parent());
if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*block))
stretched_height = block->OverrideContentLogicalHeight();
} else if (block->IsGridItem() && block->HasOverrideLogicalHeight() &&
@@ -5236,8 +5311,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
while (!IsA<LayoutView>(cb) &&
(cb->StyleRef().LogicalHeight().IsAuto() ||
cb->StyleRef().LogicalHeight().IsPercentOrCalc())) {
- if (!RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
- cb->IsTableCell()) {
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled() && cb->IsTableCell()) {
// Don't let table cells squeeze percent-height replaced elements
// <http://bugs.webkit.org/show_bug.cgi?id=15359>
available_height =
@@ -5253,7 +5327,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
}
return AdjustContentBoxLogicalHeightForBoxSizing(
- (RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
+ (RuntimeEnabledFeatures::LayoutNGEnabled() &&
available_height == kIndefiniteSize)
? IntrinsicLogicalHeight()
: ValueForLength(logical_height, available_height));
@@ -5320,7 +5394,7 @@ LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
if (IsFlexItemIncludingNG()) {
if (IsFlexItem()) {
- const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ const auto& flex_box = To<LayoutFlexibleBox>(*Parent());
if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this))
return OverrideContentLogicalHeight();
} else if (HasOverrideContainingBlockContentLogicalWidth() &&
@@ -5345,9 +5419,9 @@ LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
BorderEnd() + ComputedCSSPaddingEnd(),
BorderBefore() + ComputedCSSPaddingBefore(),
BorderAfter() + ComputedCSSPaddingAfter());
- return BlockSizeFromAspectRatio(border_padding,
- StyleRef().LogicalAspectRatio(),
- StyleRef().BoxSizing(), LogicalWidth());
+ return BlockSizeFromAspectRatio(
+ border_padding, StyleRef().LogicalAspectRatio(),
+ StyleRef().BoxSizingForAspectRatio(), LogicalWidth());
}
if (h.IsPercentOrCalc() && IsOutOfFlowPositioned()) {
@@ -6338,7 +6412,7 @@ void LayoutBox::ComputePositionedLogicalHeightUsing(
BorderAfter() + ComputedCSSPaddingAfter());
resolved_logical_height = BlockSizeFromAspectRatio(
border_padding, StyleRef().LogicalAspectRatio(),
- StyleRef().BoxSizing(), LogicalWidth());
+ StyleRef().BoxSizingForAspectRatio(), LogicalWidth());
resolved_logical_height = std::max(
LayoutUnit(), resolved_logical_height - borders_plus_padding);
} else {
@@ -6546,23 +6620,25 @@ LayoutRect LayoutBox::LocalCaretRect(
PositionWithAffinity LayoutBox::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsLayoutNGObject() || GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
+
// no children...return this layout object's element, if there is one, and
// offset 0
LayoutObject* first_child = SlowFirstChild();
if (!first_child)
- return CreatePositionWithAffinity(
- NonPseudoNode() ? FirstPositionInOrBeforeNode(*NonPseudoNode())
- : Position());
+ return FirstPositionInOrBeforeThis();
if (IsTable() && NonPseudoNode()) {
- const Node& node = *NonPseudoNode();
LayoutUnit x_in_block_direction = FlipForWritingMode(point.left);
if (x_in_block_direction < 0 || x_in_block_direction > Size().Width() ||
point.top < 0 || point.top > Size().Height()) {
if (x_in_block_direction <= Size().Width() / 2) {
- return CreatePositionWithAffinity(FirstPositionInOrBeforeNode(node));
+ return FirstPositionInOrBeforeThis();
}
- return CreatePositionWithAffinity(LastPositionInOrAfterNode(node));
+ return LastPositionInOrAfterThis();
}
}
@@ -6644,9 +6720,45 @@ PositionWithAffinity LayoutBox::PositionForPoint(
return closest_layout_object->PositionForPoint(
adjusted_point - closest_layout_object->PhysicalLocation());
}
- return CreatePositionWithAffinity(
- NonPseudoNode() ? FirstPositionInOrBeforeNode(*NonPseudoNode())
- : Position());
+ return FirstPositionInOrBeforeThis();
+}
+
+PositionWithAffinity LayoutBox::PositionForPointInFragments(
+ const PhysicalOffset& target) const {
+ NOT_DESTROYED();
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ DCHECK_GT(PhysicalFragmentCount(), 0u);
+
+ if (PhysicalFragmentCount() == 1) {
+ const NGPhysicalBoxFragment* fragment = GetPhysicalFragment(0);
+ return fragment->PositionForPoint(target);
+ }
+
+ // When |this| is block fragmented, find the closest fragment.
+ const NGPhysicalBoxFragment* closest_fragment = nullptr;
+ PhysicalOffset closest_fragment_offset;
+ NGLink closest_link;
+ LayoutUnit shortest_square_distance = LayoutUnit::Max();
+ for (const NGPhysicalBoxFragment& fragment : PhysicalFragments()) {
+ // If |fragment| contains |target|, call its |PositionForPoint|.
+ const PhysicalOffset fragment_offset = fragment.OffsetFromOwnerLayoutBox();
+ const PhysicalSize distance =
+ PhysicalRect(fragment_offset, fragment.Size()).DistanceAsSize(target);
+ if (distance.IsZero())
+ return fragment.PositionForPoint(target - fragment_offset);
+
+ // Otherwise find the closest fragment.
+ const LayoutUnit square_distance =
+ distance.width * distance.width + distance.height * distance.height;
+ if (square_distance < shortest_square_distance) {
+ shortest_square_distance = square_distance;
+ closest_fragment = &fragment;
+ closest_fragment_offset = fragment_offset;
+ }
+ }
+ DCHECK(closest_fragment);
+ return closest_fragment->PositionForPoint(target - closest_fragment_offset);
}
DISABLE_CFI_PERF
@@ -6723,8 +6835,6 @@ void LayoutBox::UpdateFragmentationInfoForChild(LayoutBox& child) {
bool LayoutBox::ChildNeedsRelayoutForPagination(const LayoutBox& child) const {
NOT_DESTROYED();
- // TODO(mstensho): Should try to get this to work for floats too, instead of
- // just marking and bailing here.
if (child.IsFloating())
return true;
const LayoutFlowThread* flow_thread = child.FlowThreadContainingBlock();
@@ -6829,7 +6939,7 @@ LayoutRectOutsets LayoutBox::ComputeVisualEffectOverflowOutsets() {
if (style.HasOutline()) {
Vector<PhysicalRect> outline_rects = OutlineRects(
- PhysicalOffset(), OutlineRectsShouldIncludeBlockVisualOverflow());
+ PhysicalOffset(), style.OutlineRectsShouldIncludeBlockVisualOverflow());
PhysicalRect rect = UnionRect(outline_rects);
bool outline_affected = rect.size != PhysicalSizeToBeNoop(Size());
SetOutlineMayBeAffectedByDescendants(outline_affected);
@@ -7201,17 +7311,6 @@ PaintLayer* LayoutBox::EnclosingFloatPaintingLayer() const {
return nullptr;
}
-const LayoutBlock& LayoutBox::EnclosingScrollportBox() const {
- NOT_DESTROYED();
- const LayoutBlock* ancestor = ContainingBlock();
- for (; ancestor; ancestor = ancestor->ContainingBlock()) {
- if (ancestor->IsScrollContainer())
- return *ancestor;
- }
- NOTREACHED();
- return *ancestor;
-}
-
LayoutRect LayoutBox::LogicalVisualOverflowRectForPropagation() const {
NOT_DESTROYED();
LayoutRect rect = VisualOverflowRectForPropagation();
@@ -7256,7 +7355,23 @@ LayoutRect LayoutBox::LayoutOverflowRectForPropagation(
if (!ShouldApplyLayoutContainment() &&
(!ShouldClipOverflowAlongBothAxis() ||
StyleRef().OverflowClipMargin() != LayoutUnit())) {
- rect.Unite(LayoutOverflowRect());
+ LayoutRect overflow = LayoutOverflowRect();
+ if (HasNonVisibleOverflow()) {
+ const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
+ const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
+ LayoutRect clip_rect = rect;
+ if (overflow_clip_margin != LayoutUnit()) {
+ // overflow_clip_margin should only be set if 'overflow' is 'clip' along
+ // both axis.
+ DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
+ clip_rect.Contract(BorderBoxOutsets());
+ clip_rect.Inflate(overflow_clip_margin);
+ overflow.Intersect(clip_rect);
+ } else {
+ ApplyOverflowClip(overflow_clip_axes, clip_rect, overflow);
+ }
+ }
+ rect.Unite(overflow);
}
bool has_transform = HasLayer() && Layer()->Transform();
@@ -7769,44 +7884,11 @@ PhysicalRect LayoutBox::DebugRect() const {
return PhysicalRect(PhysicalLocation(), Size());
}
-void LayoutBox::ApplyOverflowClipToLayoutOverflowRect() {
- NOT_DESTROYED();
- if (!HasNonVisibleOverflow() || IsScrollContainer() ||
- !LayoutOverflowIsSet()) {
- return;
- }
-
- const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
- if (overflow_clip_axes == kNoOverflowClip)
- return;
-
- LayoutRect no_overflow_rect = NoOverflowRect();
- LayoutRect overflow_rect = overflow_->layout_overflow->LayoutOverflowRect();
- const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
- if (overflow_clip_margin != LayoutUnit()) {
- // overflow_clip_margin should only be set if 'overflow' is 'clip' along
- // both axis.
- DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
- no_overflow_rect.Inflate(overflow_clip_margin);
- overflow_rect.Intersect(no_overflow_rect);
- } else {
- ApplyOverflowClip(overflow_clip_axes, no_overflow_rect, overflow_rect);
- }
- overflow_->layout_overflow->SetLayoutOverflow(overflow_rect);
-}
-
OverflowClipAxes LayoutBox::ComputeOverflowClipAxes() const {
NOT_DESTROYED();
- if (ShouldApplyPaintContainment() || HasControlClip())
- return kOverflowClipBothAxis;
- if (!HasNonVisibleOverflow())
- return kNoOverflowClip;
- if (IsScrollContainer())
- return kOverflowClipBothAxis;
- return (StyleRef().OverflowX() == EOverflow::kVisible ? kNoOverflowClip
- : kOverflowClipX) |
- (StyleRef().OverflowY() == EOverflow::kVisible ? kNoOverflowClip
- : kOverflowClipY);
+ return (ShouldApplyPaintContainment() || HasControlClip())
+ ? kOverflowClipBothAxis
+ : kNoOverflowClip;
}
void LayoutBox::MutableForPainting::SavePreviousOverflowData() {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.h b/chromium/third_party/blink/renderer/core/layout/layout_box.h
index 4f40dbb112d..9eceba36f30 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.h
@@ -68,6 +68,11 @@ enum ShouldComputePreferred { kComputeActual, kComputePreferred };
enum ShouldClampToContentBox { kDoNotClampToContentBox, kClampToContentBox };
+enum ShouldIncludeScrollbarGutter {
+ kExcludeScrollbarGutter,
+ kIncludeScrollbarGutter
+};
+
using SnapAreaSet = HashSet<LayoutBox*>;
struct LayoutBoxRareData final : public GarbageCollected<LayoutBoxRareData> {
@@ -1010,6 +1015,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutUnit OverrideLogicalHeight() const;
LayoutUnit OverrideLogicalWidth() const;
bool IsOverrideLogicalHeightDefinite() const;
+ bool StretchInlineSizeIfAuto() const;
+ bool StretchBlockSizeIfAuto() const;
bool HasOverrideLogicalHeight() const;
bool HasOverrideLogicalWidth() const;
void SetOverrideLogicalHeight(LayoutUnit);
@@ -1165,8 +1172,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void DeleteLineBoxWrapper();
bool HasInlineFragments() const final;
- NGPaintFragment* FirstInlineFragment() const final;
- void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
void ClearFirstInlineFragmentItemIndex() final;
void SetFirstInlineFragmentItemIndex(wtf_size_t) final;
@@ -1178,8 +1183,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// Store one layout result (with its physical fragment) at the specified
// index, and delete all entries following it.
void AddLayoutResult(scoped_refptr<const NGLayoutResult>, wtf_size_t index);
+ void AddLayoutResult(scoped_refptr<const NGLayoutResult>);
void ReplaceLayoutResult(scoped_refptr<const NGLayoutResult>,
wtf_size_t index);
+ void ReplaceLayoutResult(scoped_refptr<const NGLayoutResult>,
+ const NGPhysicalBoxFragment& old_fragment);
void ShrinkLayoutResults(wtf_size_t results_to_keep);
void ClearLayoutResults();
@@ -1217,6 +1225,9 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool HasFragmentItems() const;
+ wtf_size_t IndexOf(const NGPhysicalBoxFragment& fragment) const;
+ bool Contains(const NGPhysicalBoxFragment& fragment) const;
+
class CORE_EXPORT Iterator : public std::iterator<std::forward_iterator_tag,
NGPhysicalBoxFragment> {
public:
@@ -1400,13 +1411,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
SizeType,
const Length& height,
LayoutUnit intrinsic_content_height) const;
- LayoutUnit ComputeReplacedLogicalWidthUsing(SizeType,
- const Length& width) const;
+ LayoutUnit ComputeReplacedLogicalWidthUsing(SizeType, Length width) const;
LayoutUnit ComputeReplacedLogicalWidthRespectingMinMaxWidth(
LayoutUnit logical_width,
ShouldComputePreferred = kComputeActual) const;
- LayoutUnit ComputeReplacedLogicalHeightUsing(SizeType,
- const Length& height) const;
+ LayoutUnit ComputeReplacedLogicalHeightUsing(SizeType, Length height) const;
LayoutUnit ComputeReplacedLogicalHeightRespectingMinMaxHeight(
LayoutUnit logical_height) const;
@@ -1608,13 +1617,12 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LogicalExtentComputedValues&);
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
+ PositionWithAffinity PositionForPointInFragments(const PhysicalOffset&) const;
void RemoveFloatingOrPositionedChildFromBlockLists();
PaintLayer* EnclosingFloatPaintingLayer() const;
- const LayoutBlock& EnclosingScrollportBox() const;
-
virtual LayoutUnit FirstLineBoxBaseline() const {
NOT_DESTROYED();
return LayoutUnit(-1);
@@ -1674,15 +1682,14 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
return !IsInline() && !IsOutOfFlowPositioned() && Parent();
}
- bool IsGridItemIncludingNG() const {
- NOT_DESTROYED();
- return IsGridItem() || (Parent() && Parent()->IsLayoutNGGrid());
- }
-
bool IsGridItem() const {
NOT_DESTROYED();
return Parent() && Parent()->IsLayoutGrid();
}
+ bool IsGridItemIncludingNG() const {
+ NOT_DESTROYED();
+ return Parent() && Parent()->IsLayoutGridIncludingNG();
+ }
bool IsMathItem() const {
NOT_DESTROYED();
@@ -2063,11 +2070,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
protected:
~LayoutBox() override;
- // Applies 'overflow:clip' as necessary to the accumulated layout overflow.
- // During layout overflow is accumulated, once all the overflow has been
- // accumulated 'overflow:clip' is then applied.
- void ApplyOverflowClipToLayoutOverflowRect();
-
virtual OverflowClipAxes ComputeOverflowClipAxes() const;
void WillBeDestroyed() override;
@@ -2121,10 +2123,12 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool ColumnFlexItemHasStretchAlignment() const;
bool IsStretchingColumnFlexItem() const;
bool HasStretchedLogicalWidth() const;
+ bool HasStretchedLogicalHeight() const;
void ExcludeScrollbars(
PhysicalRect&,
- OverlayScrollbarClipBehavior = kIgnoreOverlayScrollbarSize) const;
+ OverlayScrollbarClipBehavior = kIgnoreOverlayScrollbarSize,
+ ShouldIncludeScrollbarGutter = kIncludeScrollbarGutter) const;
LayoutUnit ContainingBlockLogicalWidthForPositioned(
const LayoutBoxModelObject* containing_block,
@@ -2177,7 +2181,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
NOT_DESTROYED();
return ChildrenInline() && PhysicalFragments().HasFragmentItems();
}
-
inline bool LayoutOverflowIsSet() const {
NOT_DESTROYED();
return overflow_ && overflow_->layout_overflow;
@@ -2281,7 +2284,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool HasScrollbarGutters(ScrollbarOrientation orientation) const;
NGPhysicalBoxStrut ComputeScrollbarsInternal(
ShouldClampToContentBox = kDoNotClampToContentBox,
- OverlayScrollbarClipBehavior = kIgnoreOverlayScrollbarSize) const;
+ OverlayScrollbarClipBehavior = kIgnoreOverlayScrollbarSize,
+ ShouldIncludeScrollbarGutter = kIncludeScrollbarGutter) const;
LayoutUnit FlipForWritingModeInternal(
LayoutUnit position,
@@ -2360,10 +2364,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// The inline box containing this LayoutBox, for atomic inline elements.
// Valid only when !IsInLayoutNGInlineFormattingContext().
InlineBox* inline_box_wrapper_;
- // The first fragment of the inline box containing this LayoutBox, for
- // atomic inline elements. Valid only when
- // IsInLayoutNGInlineFormattingContext().
- NGPaintFragment* first_paint_fragment_;
// The index of the first fragment item associated with this object in
// |NGFragmentItems::Items()|. Zero means there are no such item.
// Valid only when IsInLayoutNGInlineFormattingContext().
@@ -2453,19 +2453,9 @@ inline void LayoutBox::SetInlineBoxWrapper(InlineBox* box_wrapper) {
inline_box_wrapper_ = box_wrapper;
}
-inline NGPaintFragment* LayoutBox::FirstInlineFragment() const {
- if (!IsInLayoutNGInlineFormattingContext())
- return nullptr;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return first_paint_fragment_;
- NOTREACHED();
- return nullptr;
-}
-
inline wtf_size_t LayoutBox::FirstInlineFragmentItemIndex() const {
if (!IsInLayoutNGInlineFormattingContext())
return 0u;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
return first_fragment_item_index_;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 769436251af..19d37b9d5dd 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -70,7 +70,7 @@ PaintLayer* FindFirstStickyBetween(LayoutObject* from, LayoutObject* to) {
maybe_sticky_ancestor =
maybe_sticky_ancestor->IsLayoutInline()
? maybe_sticky_ancestor->Container()
- : To<LayoutBox>(maybe_sticky_ancestor)->LocationContainer();
+ : To<LayoutBox>(maybe_sticky_ancestor)->StickyContainer();
}
return nullptr;
}
@@ -156,7 +156,8 @@ LayoutBoxModelObject::ComputeBackgroundPaintLocationIfComposited() const {
// Solid color layers with an effective background clip of the padding box
// can be treated as local.
if (!layer->GetImage() && !layer->Next() &&
- ResolveColor(GetCSSPropertyBackgroundColor()).Alpha() > 0) {
+ ResolveColor(GetCSSPropertyBackgroundColor()).Alpha() > 0 &&
+ StyleRef().IsScrollbarGutterAuto()) {
EFillBox clip = layer->Clip();
if (clip == EFillBox::kPadding)
continue;
@@ -326,11 +327,6 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
CreateLayerAfterStyleChange();
}
} else if (Layer() && Layer()->Parent()) {
- PaintLayer* parent_layer = Layer()->Parent();
- // Either a transform wasn't specified or the object doesn't support
- // transforms, so just null out the bit.
- SetHasTransformRelatedProperty(false);
- SetHasReflection(false);
Layer()->UpdateFilters(old_style, StyleRef());
Layer()->UpdateBackdropFilters(old_style, StyleRef());
Layer()->UpdateClipPath(old_style, StyleRef());
@@ -343,10 +339,6 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kStyleChange);
}
- if (!NeedsLayout()) {
- // FIXME: We should call a specialized version of this function.
- parent_layer->UpdateLayerPositionsAfterLayout();
- }
}
bool can_contain_fixed = CanContainFixedPositionObjects();
@@ -449,36 +441,20 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
bool old_style_is_sticky =
old_style && old_style->HasStickyConstrainedPosition();
- if (new_style_is_sticky != old_style_is_sticky) {
- if (new_style_is_sticky) {
- // During compositing inputs update we'll have the scroll ancestor
- // without having to walk up the tree and can compute the sticky
- // position constraints then.
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
-
- // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
- // invalidate the scroll paint property subtree for this so main thread
- // scroll reasons are recomputed.
- } else {
- // This may get re-added to viewport constrained objects if the object
- // went from sticky to fixed.
- frame_view->RemoveViewportConstrainedObject(
- *this, LocalFrameView::ViewportConstrainedType::kSticky);
-
- // Remove sticky constraints for this layer.
- if (Layer()) {
- if (const PaintLayer* ancestor_scroll_container_layer =
- Layer()->AncestorScrollContainerLayer()) {
- if (PaintLayerScrollableArea* scrollable_area =
- ancestor_scroll_container_layer->GetScrollableArea())
- scrollable_area->InvalidateStickyConstraintsFor(Layer());
- }
+ if (old_style_is_sticky && !new_style_is_sticky) {
+ // This may get re-added to viewport constrained objects if the object
+ // went from sticky to fixed.
+ frame_view->RemoveViewportConstrainedObject(
+ *this, LocalFrameView::ViewportConstrainedType::kSticky);
+
+ // Remove sticky constraints for this layer.
+ if (Layer()) {
+ if (const PaintLayer* ancestor_scroll_container_layer =
+ Layer()->AncestorScrollContainerLayer()) {
+ if (PaintLayerScrollableArea* scrollable_area =
+ ancestor_scroll_container_layer->GetScrollableArea())
+ scrollable_area->InvalidateStickyConstraintsFor(Layer());
}
-
- // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
- // invalidate the scroll paint property subtree for this so main thread
- // scroll reasons are recomputed.
}
}
@@ -533,6 +509,9 @@ void LayoutBoxModelObject::InvalidateStickyConstraints() {
NOT_DESTROYED();
PaintLayer* enclosing = EnclosingLayer();
+ if (!enclosing)
+ return;
+
if (PaintLayerScrollableArea* scrollable_area =
enclosing->GetScrollableArea()) {
scrollable_area->InvalidateAllStickyConstraints();
@@ -660,8 +639,7 @@ void LayoutBoxModelObject::RecalcVisualOverflow() {
// |PaintLayer| calls this function when |HasSelfPaintingLayer|. When |this|
// is an inline box or an atomic inline, its ink overflow is stored in
// |NGFragmentItem| in the inline formatting context.
- if (IsInline() && IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (IsInline() && IsInLayoutNGInlineFormattingContext()) {
DCHECK(HasSelfPaintingLayer());
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
@@ -758,7 +736,7 @@ bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
}
if (this_box && this_box->IsFlexItemIncludingNG()) {
if (this_box->IsFlexItem()) {
- const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ const auto& flex_box = To<LayoutFlexibleBox>(*Parent());
if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
return false;
} else if (this_box->GetCachedLayoutResult()) {
@@ -777,11 +755,8 @@ bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
}
if (this_box && this_box->IsGridItem() &&
this_box->HasOverrideContainingBlockContentLogicalHeight()) {
- if (RuntimeEnabledFeatures::TableCellNewPercentsEnabled()) {
- return this_box->OverrideContainingBlockContentLogicalHeight() ==
- kIndefiniteSize;
- }
- return false;
+ return this_box->OverrideContainingBlockContentLogicalHeight() ==
+ kIndefiniteSize;
}
if (this_box && this_box->IsCustomItem() &&
(this_box->HasOverrideContainingBlockContentLogicalHeight() ||
@@ -947,6 +922,10 @@ PhysicalOffset LayoutBoxModelObject::RelativePositionOffset() const {
return offset;
}
+LayoutBlock* LayoutBoxModelObject::StickyContainer() const {
+ return ContainingBlock();
+}
+
void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
NOT_DESTROYED();
DCHECK(StyleRef().HasStickyConstrainedPosition());
@@ -955,13 +934,16 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
StickyPositionScrollingConstraints constraints;
PhysicalOffset skipped_containers_offset;
- LayoutBlock* containing_block = ContainingBlock();
+ LayoutBlock* sticky_container = StickyContainer();
// The location container for boxes is not always the containing block.
LayoutObject* location_container =
IsLayoutInline() ? Container() : To<LayoutBox>(this)->LocationContainer();
- // Skip anonymous containing blocks.
- while (containing_block->IsAnonymous()) {
- containing_block = containing_block->ContainingBlock();
+ // Skip anonymous containing blocks except for anonymous fieldset content box.
+ while (sticky_container->IsAnonymous()) {
+ if (sticky_container->Parent() &&
+ sticky_container->Parent()->IsLayoutNGFieldset())
+ break;
+ sticky_container = sticky_container->ContainingBlock();
}
// The sticky position constraint rects should be independent of the current
@@ -971,29 +953,29 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
MapCoordinatesFlags flags =
kIgnoreTransforms | kIgnoreScrollOffset | kIgnoreStickyOffset;
skipped_containers_offset = location_container->LocalToAncestorPoint(
- PhysicalOffset(), containing_block, flags);
+ PhysicalOffset(), sticky_container, flags);
auto& scroll_ancestor =
To<LayoutBox>(Layer()->AncestorScrollContainerLayer()->GetLayoutObject());
LayoutUnit max_container_width =
- IsA<LayoutView>(containing_block)
- ? containing_block->LogicalWidth()
- : containing_block->ContainingBlockLogicalWidthForContent();
+ IsA<LayoutView>(sticky_container)
+ ? sticky_container->LogicalWidth()
+ : sticky_container->ContainingBlockLogicalWidthForContent();
// Sticky positioned element ignore any override logical width on the
// containing block, as they don't call containingBlockLogicalWidthForContent.
// It's unclear whether this is totally fine.
// Compute the container-relative area within which the sticky element is
// allowed to move.
- LayoutUnit max_width = containing_block->AvailableLogicalWidth();
+ LayoutUnit max_width = sticky_container->AvailableLogicalWidth();
// Map the containing block to the inner corner of the scroll ancestor without
// transforms.
PhysicalRect scroll_container_relative_padding_box_rect(
- containing_block->LayoutOverflowRect());
- if (containing_block != &scroll_ancestor) {
- PhysicalRect local_rect = containing_block->PhysicalPaddingBoxRect();
+ sticky_container->LayoutOverflowRect());
+ if (sticky_container != &scroll_ancestor) {
+ PhysicalRect local_rect = sticky_container->PhysicalPaddingBoxRect();
scroll_container_relative_padding_box_rect =
- containing_block->LocalToAncestorRect(local_rect, &scroll_ancestor,
+ sticky_container->LocalToAncestorRect(local_rect, &scroll_ancestor,
flags);
}
@@ -1012,16 +994,16 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
// It is an open issue whether the margin should collapse.
// See https://www.w3.org/TR/css-position-3/#sticky-pos
scroll_container_relative_containing_block_rect.ContractEdges(
- MinimumValueForLength(containing_block->StyleRef().PaddingTop(),
+ MinimumValueForLength(sticky_container->StyleRef().PaddingTop(),
max_container_width) +
MinimumValueForLength(StyleRef().MarginTop(), max_width),
- MinimumValueForLength(containing_block->StyleRef().PaddingRight(),
+ MinimumValueForLength(sticky_container->StyleRef().PaddingRight(),
max_container_width) +
MinimumValueForLength(StyleRef().MarginRight(), max_width),
- MinimumValueForLength(containing_block->StyleRef().PaddingBottom(),
+ MinimumValueForLength(sticky_container->StyleRef().PaddingBottom(),
max_container_width) +
MinimumValueForLength(StyleRef().MarginBottom(), max_width),
- MinimumValueForLength(containing_block->StyleRef().PaddingLeft(),
+ MinimumValueForLength(sticky_container->StyleRef().PaddingLeft(),
max_container_width) +
MinimumValueForLength(StyleRef().MarginLeft(), max_width));
@@ -1033,7 +1015,7 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
sticky_box_rect = To<LayoutInline>(this)->PhysicalLinesBoundingBox();
} else {
sticky_box_rect =
- containing_block->FlipForWritingMode(To<LayoutBox>(this)->FrameRect());
+ sticky_container->FlipForWritingMode(To<LayoutBox>(this)->FrameRect());
}
PhysicalOffset sticky_location =
sticky_box_rect.offset + skipped_containers_offset;
@@ -1043,8 +1025,8 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
// within the scroll ancestor if the container is not our scroll ancestor. If
// the container is our scroll ancestor, we also need to remove the border
// box because we want the position from within the scroller border.
- PhysicalOffset container_border_offset(containing_block->BorderLeft(),
- containing_block->BorderTop());
+ PhysicalOffset container_border_offset(sticky_container->BorderLeft(),
+ sticky_container->BorderTop());
sticky_location -= container_border_offset;
constraints.scroll_container_relative_sticky_box_rect = PhysicalRect(
scroll_container_relative_padding_box_rect.offset + sticky_location,
@@ -1057,12 +1039,12 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
// The respective search ranges are [container, containingBlock) and
// [containingBlock, scrollAncestor).
constraints.nearest_sticky_layer_shifting_sticky_box =
- FindFirstStickyBetween(location_container, containing_block);
+ FindFirstStickyBetween(location_container, sticky_container);
// We cannot use |scrollAncestor| here as it disregards the root
// ancestorOverflowLayer(), which we should include.
constraints.nearest_sticky_layer_shifting_containing_block =
FindFirstStickyBetween(
- containing_block,
+ sticky_container,
&Layer()->AncestorScrollContainerLayer()->GetLayoutObject());
// We skip the right or top sticky offset if there is not enough space to
@@ -1126,32 +1108,6 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
scrollable_area->AddStickyConstraints(Layer(), constraints);
}
-bool LayoutBoxModelObject::IsSlowRepaintConstrainedObject() const {
- NOT_DESTROYED();
- if (!HasLayer() || (StyleRef().GetPosition() != EPosition::kFixed &&
- StyleRef().GetPosition() != EPosition::kSticky)) {
- return false;
- }
-
- PaintLayer* layer = Layer();
-
- // Whether the Layer sticks to the viewport is a tree-depenent
- // property and our viewportConstrainedObjects collection is maintained
- // with only LayoutObject-level information.
- if (!layer->FixedToViewport() && !layer->SticksToScroller())
- return false;
-
- // If the whole subtree is invisible, there's no reason to scroll on
- // the main thread because we don't need to generate invalidations
- // for invisible content.
- if (layer->SubtreeIsInvisible())
- return false;
-
- // We're only smart enough to scroll viewport-constrainted objects
- // in the compositor if they are directly composited.
- return !layer->CanBeCompositedForDirectReasons();
-}
-
PhysicalRect LayoutBoxModelObject::ComputeStickyConstrainingRect() const {
NOT_DESTROYED();
LayoutBox* scroll_container_box =
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
index 8621cdaa5d1..710706436b2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -149,7 +149,7 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
PhysicalRect ComputeStickyConstrainingRect() const;
void UpdateStickyPositionConstraints() const;
PhysicalOffset StickyPositionOffset() const;
- bool IsSlowRepaintConstrainedObject() const;
+ virtual LayoutBlock* StickyContainer() const;
PhysicalOffset OffsetForInFlowPosition() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
index e77e3ef7bf1..2bd36c37b8d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
@@ -402,16 +402,9 @@ TEST_F(LayoutBoxModelObjectTest, StickyPositionConstraintInvalidation) {
.at(sticky->Layer())
.scroll_container_relative_sticky_box_rect.X());
To<HTMLElement>(target->GetNode())->classList().Add("hide");
+ // After updating layout we should have the updated position.
GetDocument().View()->UpdateLifecycleToLayoutClean(
DocumentUpdateReason::kTest);
- // Layout should invalidate the sticky constraints of the sticky element and
- // mark it as needing a compositing inputs update.
- EXPECT_FALSE(
- scrollable_area->GetStickyConstraintsMap().Contains(sticky->Layer()));
- EXPECT_TRUE(sticky->Layer()->NeedsCompositingInputsUpdate());
-
- // After updating compositing inputs we should have the updated position.
- UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(50.f, scrollable_area->GetStickyConstraintsMap()
.at(sticky->Layer())
.scroll_container_relative_sticky_box_rect.X());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
index 8c93cff9309..3db749c17e3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -286,7 +286,10 @@ TEST_P(LayoutBoxTest, LocationContainer) {
EXPECT_EQ(body, table->LocationContainer());
EXPECT_EQ(table, tbody->LocationContainer());
EXPECT_EQ(tbody, row->LocationContainer());
- EXPECT_EQ(tbody, cell->LocationContainer());
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(row, cell->LocationContainer());
+ else
+ EXPECT_EQ(tbody, cell->LocationContainer());
}
TEST_P(LayoutBoxTest, TopLeftLocationFlipped) {
@@ -333,14 +336,22 @@ TEST_P(LayoutBoxTest, TableRowCellTopLeftLocationFlipped) {
const LayoutBox* cell1 = GetLayoutBoxByElementId("cell1");
EXPECT_EQ(LayoutPoint(0, 0), cell1->Location());
- EXPECT_EQ(PhysicalOffset(300, 0), cell1->PhysicalLocation());
+ // TablesNG cells are container is row, Legacy is section.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(PhysicalOffset(0, 0), cell1->PhysicalLocation());
+ else
+ EXPECT_EQ(PhysicalOffset(300, 0), cell1->PhysicalLocation());
const LayoutBox* row2 = GetLayoutBoxByElementId("row2");
EXPECT_EQ(LayoutPoint(100, 0), row2->Location());
EXPECT_EQ(PhysicalOffset(0, 0), row2->PhysicalLocation());
const LayoutBox* cell2 = GetLayoutBoxByElementId("cell2");
- EXPECT_EQ(LayoutPoint(100, 0), cell2->Location());
+ // TablesNG cells are container is row, Legacy is section.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(LayoutPoint(0, 0), cell2->Location());
+ else
+ EXPECT_EQ(LayoutPoint(100, 0), cell2->Location());
EXPECT_EQ(PhysicalOffset(0, 0), cell2->PhysicalLocation());
}
@@ -513,6 +524,7 @@ TEST_P(LayoutBoxTest, VisualOverflowRectWithOverflowClipMargin) {
SetBodyInnerHTML(R"HTML(
<style>
.parent { width: 100px; height: 50px; overflow: clip; }
+ .parent2 { width: 100px; height: 50px; contain: paint; }
.child { width: 110px; height: 55px; }
</style>
<div id="clip1" style="overflow-clip-margin: 4px" class="parent">
@@ -521,6 +533,9 @@ TEST_P(LayoutBoxTest, VisualOverflowRectWithOverflowClipMargin) {
<div id="clip2" style="overflow-clip-margin: 11px" class="parent">
<div class="child"></div>
</div>
+ <div id="clip3" style="overflow-clip-margin: 11px" class="parent2">
+ <div class="child"></div>
+ </div>
)HTML");
LayoutBox* clip1 = GetLayoutBoxByElementId("clip1");
@@ -532,12 +547,18 @@ TEST_P(LayoutBoxTest, VisualOverflowRectWithOverflowClipMargin) {
EXPECT_FALSE(clip2->IsScrollContainer());
EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis());
EXPECT_EQ(LayoutRect(0, 0, 110, 55), clip2->VisualOverflowRect());
+
+ LayoutBox* clip3 = GetLayoutBoxByElementId("clip3");
+ EXPECT_FALSE(clip3->IsScrollContainer());
+ EXPECT_TRUE(clip3->ShouldClipOverflowAlongBothAxis());
+ EXPECT_EQ(LayoutRect(0, 0, 110, 55), clip3->VisualOverflowRect());
}
TEST_P(LayoutBoxTest, LayoutOverflowRectWithOverflowClipMargin) {
SetBodyInnerHTML(R"HTML(
<style>
.parent { width: 100px; height: 50px; overflow: clip; }
+ .parent2 { width: 100px; height: 50px; contain: paint; }
.child { position: relative; top: -5px; left: -6px; width: 110px;
height: 112px; }
</style>
@@ -547,17 +568,28 @@ TEST_P(LayoutBoxTest, LayoutOverflowRectWithOverflowClipMargin) {
<div id="clip2" style="overflow-clip-margin: 10px" class="parent">
<div class="child"></div>
</div>
+ <div id="clip3" style="overflow-clip-margin: 10px" class="parent2">
+ <div class="child"></div>
+ </div>
)HTML");
LayoutBox* clip1 = GetLayoutBoxByElementId("clip1");
EXPECT_FALSE(clip1->IsScrollContainer());
EXPECT_TRUE(clip1->ShouldClipOverflowAlongBothAxis());
- EXPECT_EQ(LayoutRect(-4, -4, 108, 58), clip1->LayoutOverflowRect());
+ EXPECT_EQ(LayoutRect(-4, -4, 108, 58),
+ clip1->LayoutOverflowRectForPropagation(clip1->Parent()));
LayoutBox* clip2 = GetLayoutBoxByElementId("clip2");
EXPECT_FALSE(clip2->IsScrollContainer());
EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis());
- EXPECT_EQ(LayoutRect(-6, -5, 110, 65), clip2->LayoutOverflowRect());
+ EXPECT_EQ(LayoutRect(-6, -5, 110, 65),
+ clip2->LayoutOverflowRectForPropagation(clip2->Parent()));
+
+ LayoutBox* clip3 = GetLayoutBoxByElementId("clip3");
+ EXPECT_FALSE(clip3->IsScrollContainer());
+ EXPECT_TRUE(clip3->ShouldClipOverflowAlongBothAxis());
+ EXPECT_EQ(LayoutRect(-6, -5, 110, 65),
+ clip3->LayoutOverflowRectForPropagation(clip3->Parent()));
}
TEST_P(LayoutBoxTest, ContentsVisualOverflowPropagation) {
@@ -1662,4 +1694,33 @@ TEST_P(LayoutBoxTest, PartialInvalidationRect) {
EXPECT_EQ(IntRect(), display_item_client->PartialInvalidationVisualRect());
}
+TEST_P(LayoutBoxTest, HasReflection) {
+ SetBodyInnerHTML(R"HTML(
+ <style>* { -webkit-box-reflect: above; }</style>
+ <table id="table">
+ <colgroup id="colgroup">
+ <col id="col">
+ </colgroup>
+ <tr id="tr"><td id="td">TD</td></tr>
+ </table>
+ <svg id="svg">
+ <text id="svg-text">SVG text</text>
+ </svg>
+ )HTML");
+
+ auto check_has_layer_and_reflection = [&](const char* element_id,
+ bool expected) {
+ auto* object = GetLayoutObjectByElementId(element_id);
+ EXPECT_EQ(expected, object->HasLayer()) << element_id;
+ EXPECT_EQ(expected, object->HasReflection()) << element_id;
+ };
+ check_has_layer_and_reflection("table", true);
+ check_has_layer_and_reflection("tr", true);
+ check_has_layer_and_reflection("colgroup", false);
+ check_has_layer_and_reflection("col", false);
+ check_has_layer_and_reflection("td", true);
+ check_has_layer_and_reflection("svg", true);
+ check_has_layer_and_reflection("svg-text", false);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_br.cc b/chromium/third_party/blink/renderer/core/layout/layout_br.cc
index cb96635ea09..0f929027f03 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_br.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_br.cc
@@ -62,7 +62,12 @@ int LayoutBR::CaretMaxOffset() const {
PositionWithAffinity LayoutBR::PositionForPoint(const PhysicalOffset&) const {
NOT_DESTROYED();
- return CreatePositionWithAffinity(0);
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsInLayoutNGInlineFormattingContext() ||
+ GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
+ return PositionBeforeThis();
}
Position LayoutBR::PositionForCaretOffset(unsigned offset) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_counter.cc b/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
index c0728b90898..e373855985d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -24,6 +24,8 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/numerics/clamped_math.h"
+#include "third_party/blink/renderer/core/css/counter_style.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -203,8 +205,8 @@ bool PlanCounter(LayoutObject& object,
return true;
}
if (auto* olist = DynamicTo<HTMLOListElement>(*e)) {
- value =
- olist->StartConsideringItemCount() + (olist->IsReversed() ? 1 : -1);
+ value = base::ClampAdd(olist->StartConsideringItemCount(),
+ olist->IsReversed() ? 1 : -1);
type_mask = CounterNode::kResetType;
return true;
}
@@ -480,10 +482,21 @@ CounterNode* MakeCounterNodeIfNeeded(LayoutObject& object,
return new_node.get();
}
+String GenerateCounterText(const CounterStyle* counter_style,
+ EListStyleType deprecated_list_style_type,
+ int value) {
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ if (!counter_style)
+ return g_empty_string;
+ return counter_style->GenerateRepresentation(value);
+ }
+ return list_marker_text::GetText(deprecated_list_style_type, value);
+}
+
} // namespace
LayoutCounter::LayoutCounter(PseudoElement& pseudo,
- const CounterContent& counter)
+ const CounterContentData& counter)
: LayoutText(nullptr, StringImpl::empty_),
counter_(counter),
counter_node_(nullptr),
@@ -513,7 +526,7 @@ scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
// Find a container on which to create the counter if one needs creating.
LayoutObject* container = Parent();
- bool should_create_counter = counter_.Separator().IsNull();
+ bool should_create_counter = counter_->Separator().IsNull();
// Optimization: the only reason we need a proper container is if we might not
// need to create a counter (in which case, we navigate container's
// ancestors), or if we don't have a counter_node_ (in which case we need to
@@ -550,7 +563,7 @@ scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
if (style.ContainsStyle())
break;
const CounterDirectives directives =
- style.GetCounterDirectives(counter_.Identifier());
+ style.GetCounterDirectives(counter_->Identifier());
if (directives.IsDefined()) {
should_create_counter = true;
break;
@@ -563,7 +576,7 @@ scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
// as the child, without needing to create a counter on `this`. If we don't
// have such an ancestor, we need to create a `counter_node_` on `this`.
if (auto* node = CounterNode::AncestorNodeAcrossStyleContainment(
- *this, counter_.Identifier())) {
+ *this, counter_->Identifier())) {
child = node;
} else {
should_create_counter = true;
@@ -572,7 +585,7 @@ scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
if (should_create_counter) {
if (!counter_node_) {
- MakeCounterNodeIfNeeded(*container, counter_.Identifier(), true)
+ MakeCounterNodeIfNeeded(*container, counter_->Identifier(), true)
->AddLayoutObject(const_cast<LayoutCounter*>(this));
DCHECK(counter_node_);
}
@@ -584,20 +597,33 @@ scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
DCHECK(child);
int value = ValueForText(child);
- String text = list_marker_text::GetText(counter_.ListStyle(), value);
+ const CounterStyle* counter_style = nullptr;
+ EListStyleType list_style = EListStyleType::kNone;
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ // Note: CSS3 spec doesn't allow 'none' but CSS2.1 allows it. We currently
+ // allow it for backward compatibility.
+ // See https://github.com/w3c/csswg-drafts/issues/5795 for details.
+ if (counter_->ListStyle() != "none") {
+ counter_style =
+ &GetDocument().GetStyleEngine().FindCounterStyleAcrossScopes(
+ counter_->ListStyle(), counter_->GetTreeScope());
+ }
+ } else {
+ list_style = counter_->ToDeprecatedListStyleTypeEnum();
+ }
+ String text = GenerateCounterText(counter_style, list_style, value);
// If the separator exists, we need to append all of the parent values as well,
// including the ones that cross the style containment boundary.
- if (!counter_.Separator().IsNull()) {
+ if (!counter_->Separator().IsNull()) {
if (!child->ActsAsReset())
- child = child->ParentCrossingStyleContainment(counter_.Identifier());
+ child = child->ParentCrossingStyleContainment(counter_->Identifier());
bool next_result_uses_parent_value = !child->Parent();
while (CounterNode* parent =
- child->ParentCrossingStyleContainment(counter_.Identifier())) {
- text = list_marker_text::GetText(counter_.ListStyle(),
- next_result_uses_parent_value
- ? ValueForText(parent)
- : child->CountInParent()) +
- counter_.Separator() + text;
+ child->ParentCrossingStyleContainment(counter_->Identifier())) {
+ int next_value = next_result_uses_parent_value ? ValueForText(parent)
+ : child->CountInParent();
+ text = GenerateCounterText(counter_style, list_style, next_value) +
+ counter_->Separator() + text;
child = parent;
next_result_uses_parent_value = !child->Parent();
}
@@ -648,7 +674,7 @@ void LayoutCounter::DestroyCounterNodes(LayoutObject& owner) {
maps.erase(maps_iterator);
owner.SetHasCounterNodeMap(false);
if (owner.View())
- owner.View()->SetNeedsCounterUpdate();
+ owner.View()->SetNeedsMarkerOrCounterUpdate();
}
void LayoutCounter::DestroyCounterNode(LayoutObject& owner,
@@ -765,6 +791,8 @@ void LayoutCounter::LayoutObjectSubtreeAttached(LayoutObject* layout_object) {
void LayoutCounter::LayoutObjectStyleChanged(LayoutObject& layout_object,
const ComputedStyle* old_style,
const ComputedStyle& new_style) {
+ if (layout_object.IsListItemIncludingNG())
+ ListItemOrdinal::ItemCounterStyleUpdated(layout_object);
Node* node = layout_object.GeneratingNode();
if (!node || node->NeedsReattachLayoutTree())
return; // cannot have generated content or if it can have, it will be
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_counter.h b/chromium/third_party/blink/renderer/core/layout/layout_counter.h
index b5911b64730..6e1114db96f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_counter.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_counter.h
@@ -23,7 +23,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_COUNTER_H_
#include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/core/style/counter_content.h"
+#include "third_party/blink/renderer/core/style/content_data.h"
namespace blink {
@@ -52,7 +52,7 @@ using CounterMap = HashMap<AtomicString, scoped_refptr<CounterNode>>;
// LayoutCounter during their lifetime (see the static functions below).
class LayoutCounter final : public LayoutText {
public:
- LayoutCounter(PseudoElement&, const CounterContent&);
+ LayoutCounter(PseudoElement&, const CounterContentData&);
~LayoutCounter() override;
// These functions are static so that any LayoutObject can call them.
@@ -91,7 +91,7 @@ class LayoutCounter final : public LayoutText {
// changes.
void Invalidate();
- CounterContent counter_;
+ Persistent<const CounterContentData> counter_;
CounterNode* counter_node_;
LayoutCounter* next_for_same_counter_;
friend class CounterNode;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.cc
index 5e9899def7a..de7309d5ac3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.cc
@@ -31,20 +31,21 @@ namespace blink {
LayoutDetailsMarker::LayoutDetailsMarker(Element* element)
: LayoutBlockFlow(element) {}
-LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation() const {
- NOT_DESTROYED();
+LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation(
+ const ComputedStyle& style,
+ bool is_open) {
// TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported.
- const auto mode = StyleRef().GetWritingMode();
+ const auto mode = style.GetWritingMode();
DCHECK(mode != WritingMode::kSidewaysRl && mode != WritingMode::kSidewaysLr);
- if (IsOpen()) {
- if (mode == WritingMode::kHorizontalTb)
+ if (is_open) {
+ if (blink::IsHorizontalWritingMode(mode))
return kDown;
- return (mode == WritingMode::kVerticalRl) ? kLeft : kRight;
+ return IsFlippedBlocksWritingMode(mode) ? kLeft : kRight;
}
- if (mode == WritingMode::kHorizontalTb)
- return StyleRef().IsLeftToRightDirection() ? kRight : kLeft;
- return StyleRef().IsLeftToRightDirection() ? kDown : kUp;
+ if (blink::IsHorizontalWritingMode(mode))
+ return style.IsLeftToRightDirection() ? kRight : kLeft;
+ return style.IsLeftToRightDirection() ? kDown : kUp;
}
void LayoutDetailsMarker::Paint(const PaintInfo& paint_info) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
index fd7d461b53d..79871fcbd39 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
@@ -31,7 +31,8 @@ class LayoutDetailsMarker final : public LayoutBlockFlow {
enum Orientation { kUp, kDown, kLeft, kRight };
- Orientation GetOrientation() const;
+ static Orientation GetOrientation(const ComputedStyle& style, bool is_open);
+ bool IsOpen() const;
bool CreatesNewFormattingContext() const override {
NOT_DESTROYED();
@@ -50,8 +51,6 @@ class LayoutDetailsMarker final : public LayoutBlockFlow {
LayoutBlockFlow::IsOfType(type);
}
void Paint(const PaintInfo&) const override;
-
- bool IsOpen() const;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index 48baf99592e..4c3dc956612 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -61,10 +61,8 @@ void LayoutEmbeddedContent::Release() {
void LayoutEmbeddedContent::WillBeDestroyed() {
NOT_DESTROYED();
- if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) {
- cache->ChildrenChanged(Parent());
+ if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
cache->Remove(this);
- }
if (auto* frame_owner = GetFrameOwnerElement())
frame_owner->SetEmbeddedContentView(nullptr);
@@ -142,11 +140,15 @@ PaintLayerType LayoutEmbeddedContent::LayerTypeRequired() const {
return kForcedPaintLayer;
}
-bool LayoutEmbeddedContent::ContentDocumentIsCompositing() const {
+bool LayoutEmbeddedContent::ContentDocumentContainsGraphicsLayer() const {
NOT_DESTROYED();
+ // This method must use the same logic as GraphicsLayerTreeBuilder: if
+ // an iframe is throttled, we look for the existence of a root graphics layer,
+ // even if the compositing state information is stale.
if (PaintLayerCompositor* inner_compositor =
PaintLayerCompositor::FrameContentsCompositor(*this)) {
- return inner_compositor->StaleInCompositingMode();
+ DisableCompositingQueryAsserts compositing_disabler;
+ return inner_compositor->RootGraphicsLayer();
}
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
index ee3c7328bda..b39d9738b10 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
@@ -44,7 +44,7 @@ class CORE_EXPORT LayoutEmbeddedContent : public LayoutReplaced {
explicit LayoutEmbeddedContent(HTMLFrameOwnerElement*);
~LayoutEmbeddedContent() override;
- bool ContentDocumentIsCompositing() const;
+ bool ContentDocumentContainsGraphicsLayer() const;
bool NodeAtPoint(HitTestResult&,
const HitTestLocation&,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
index 3b56d1bb4c9..c48da9405ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -145,18 +145,16 @@ LayoutObject* LayoutFieldset::LayoutSpecialExcludedChild(bool relayout_children,
LayoutBox* LayoutFieldset::FindInFlowLegend(const LayoutBlock& fieldset) {
DCHECK(fieldset.IsFieldset() || fieldset.IsLayoutNGFieldset());
const LayoutBlock* parent = &fieldset;
- if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
- if (fieldset.IsLayoutNGFieldset()) {
- // If there is a rendered legend, it will be found inside the anonymous
- // fieldset wrapper.
- parent = To<LayoutBlock>(fieldset.FirstChild());
- if (!parent)
- return nullptr;
- // If the anonymous fieldset wrapper is a multi-column, the rendered
- // legend will be found inside the multi-column flow thread.
- if (parent->FirstChild() && parent->FirstChild()->IsLayoutFlowThread())
- parent = To<LayoutBlock>(parent->FirstChild());
- }
+ if (fieldset.IsLayoutNGFieldset()) {
+ // If there is a rendered legend, it will be found inside the anonymous
+ // fieldset wrapper.
+ parent = To<LayoutBlock>(fieldset.FirstChild());
+ if (!parent)
+ return nullptr;
+ // If the anonymous fieldset wrapper is a multi-column, the rendered
+ // legend will be found inside the multi-column flow thread.
+ if (parent->FirstChild() && parent->FirstChild()->IsLayoutFlowThread())
+ parent = To<LayoutBlock>(parent->FirstChild());
}
for (LayoutObject* legend = parent->FirstChild(); legend;
legend = legend->NextSibling()) {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
index c9b6d03daad..ff49cd996b9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
@@ -33,8 +33,6 @@
namespace blink {
-const int kButtonShadowHeight = 2;
-
LayoutFileUploadControl::LayoutFileUploadControl(Element* input)
: LayoutBlockFlow(input) {
DCHECK_EQ(To<HTMLInputElement>(input)->type(), input_type_names::kFile);
@@ -88,17 +86,4 @@ String LayoutFileUploadControl::FileTextValue() const {
return StringTruncator::CenterTruncate(text, width, StyleRef().GetFont());
}
-// Override to allow effective clip rect to be bigger than the padding box
-// because of kButtonShadowHeight.
-PhysicalRect LayoutFileUploadControl::OverflowClipRect(
- const PhysicalOffset& additional_offset,
- OverlayScrollbarClipBehavior) const {
- NOT_DESTROYED();
- PhysicalRect rect(additional_offset, Size());
- rect.Expand(BorderInsets());
- rect.offset.top -= LayoutUnit(kButtonShadowHeight);
- rect.size.height += LayoutUnit(kButtonShadowHeight) * 2;
- return rect;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
index 9f67eea22c9..2d1080505a4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
@@ -23,7 +23,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/platform/graphics/overlay_scrollbar_clip_behavior.h"
namespace blink {
@@ -47,9 +46,6 @@ class CORE_EXPORT LayoutFileUploadControl final : public LayoutBlockFlow {
HTMLInputElement* UploadButton() const;
- PhysicalRect OverflowClipRect(const PhysicalOffset&,
- OverlayScrollbarClipBehavior) const override;
-
static const int kAfterButtonSpacing = 4;
const char* GetName() const override {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index a62de70a892..eaf36a9aa1f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -809,7 +809,9 @@ bool LayoutFlexibleBox::UseChildAspectRatio(const LayoutBox& child) const {
LayoutUnit LayoutFlexibleBox::ComputeMainSizeFromAspectRatioUsing(
const LayoutBox& child,
- const Length& cross_size_length) const {
+ const Length& cross_size_length,
+ LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const {
NOT_DESTROYED();
DCHECK(HasAspectRatio(child));
@@ -826,17 +828,22 @@ LayoutUnit LayoutFlexibleBox::ComputeMainSizeFromAspectRatioUsing(
LayoutSize aspect_ratio = child.IntrinsicSize();
EAspectRatioType ar_type = child.StyleRef().AspectRatio().GetType();
+ LayoutUnit border_and_padding;
if (ar_type == EAspectRatioType::kRatio ||
(ar_type == EAspectRatioType::kAutoAndRatio && aspect_ratio.IsEmpty())) {
FloatSize int_ratio = child.StyleRef().AspectRatio().GetRatio();
aspect_ratio = LayoutSize{int_ratio.Width(), int_ratio.Height()};
+ if (child.StyleRef().BoxSizingForAspectRatio() == EBoxSizing::kContentBox) {
+ cross_size -= cross_axis_border_and_padding;
+ border_and_padding = main_axis_border_and_padding;
+ }
}
double ratio =
aspect_ratio.Width().ToFloat() / aspect_ratio.Height().ToFloat();
// TODO(cbiesinger): box sizing?
if (IsHorizontalFlow())
- return LayoutUnit(cross_size * ratio);
- return LayoutUnit(cross_size / ratio);
+ return LayoutUnit(cross_size * ratio) + border_and_padding;
+ return LayoutUnit(cross_size / ratio) + border_and_padding;
}
void LayoutFlexibleBox::SetFlowAwareLocationForChild(
@@ -970,6 +977,7 @@ DISABLE_CFI_PERF
LayoutUnit LayoutFlexibleBox::ComputeInnerFlexBaseSizeForChild(
LayoutBox& child,
LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding,
ChildLayoutType child_layout_type) {
NOT_DESTROYED();
if (child.IsImage() || IsA<LayoutVideo>(child) || child.IsCanvas())
@@ -993,9 +1001,12 @@ LayoutUnit LayoutFlexibleBox::ComputeInnerFlexBaseSizeForChild(
const Length& cross_size_length = IsHorizontalFlow()
? child.StyleRef().Height()
: child.StyleRef().Width();
- LayoutUnit result =
- ComputeMainSizeFromAspectRatioUsing(child, cross_size_length);
- result = AdjustChildSizeForAspectRatioCrossAxisMinAndMax(child, result);
+ LayoutUnit result = ComputeMainSizeFromAspectRatioUsing(
+ child, cross_size_length, main_axis_border_and_padding,
+ cross_axis_border_and_padding);
+ result = AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+ child, result, main_axis_border_and_padding,
+ cross_axis_border_and_padding);
return result - main_axis_border_and_padding;
}
@@ -1153,7 +1164,8 @@ DISABLE_CFI_PERF
MinMaxSizes LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
const FlexLayoutAlgorithm& algorithm,
const LayoutBox& child,
- LayoutUnit border_and_padding) const {
+ LayoutUnit border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const {
NOT_DESTROYED();
MinMaxSizes sizes{LayoutUnit(), LayoutUnit::Max()};
@@ -1179,9 +1191,11 @@ MinMaxSizes LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
LayoutUnit content_size = ComputeMainAxisExtentForChild(
child, kMinSize, Length::MinContent(), border_and_padding);
DCHECK_GE(content_size, LayoutUnit());
- if (HasAspectRatio(child) && child.IntrinsicSize().Height() > 0)
- content_size =
- AdjustChildSizeForAspectRatioCrossAxisMinAndMax(child, content_size);
+ if (HasAspectRatio(child) && child.IntrinsicSize().Height() > 0) {
+ content_size = AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+ child, content_size, border_and_padding,
+ cross_axis_border_and_padding);
+ }
if (child.IsTable() && !IsColumnFlow()) {
// Avoid resolving minimum size to something narrower than the minimum
// preferred logical width of the table.
@@ -1205,10 +1219,12 @@ MinMaxSizes LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
const Length& cross_size_length = IsHorizontalFlow()
? child.StyleRef().Height()
: child.StyleRef().Width();
- LayoutUnit transferred_size =
- ComputeMainSizeFromAspectRatioUsing(child, cross_size_length);
+ LayoutUnit transferred_size = ComputeMainSizeFromAspectRatioUsing(
+ child, cross_size_length, border_and_padding,
+ cross_axis_border_and_padding);
transferred_size = AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
- child, transferred_size);
+ child, transferred_size, border_and_padding,
+ cross_axis_border_and_padding);
sizes.min_size = std::min(transferred_size, content_size);
} else {
sizes.min_size = content_size;
@@ -1264,7 +1280,9 @@ bool LayoutFlexibleBox::UseOverrideLogicalHeightForPerentageResolution(
LayoutUnit LayoutFlexibleBox::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
const LayoutBox& child,
- LayoutUnit child_size) const {
+ LayoutUnit child_size,
+ LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const {
NOT_DESTROYED();
const Length& cross_min = IsHorizontalFlow() ? child.StyleRef().MinHeight()
: child.StyleRef().MinWidth();
@@ -1272,14 +1290,16 @@ LayoutUnit LayoutFlexibleBox::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
: child.StyleRef().MaxWidth();
if (CrossAxisLengthIsDefinite(child, cross_max)) {
- LayoutUnit max_value =
- ComputeMainSizeFromAspectRatioUsing(child, cross_max);
+ LayoutUnit max_value = ComputeMainSizeFromAspectRatioUsing(
+ child, cross_max, main_axis_border_and_padding,
+ cross_axis_border_and_padding);
child_size = std::min(max_value, child_size);
}
if (CrossAxisLengthIsDefinite(child, cross_min)) {
- LayoutUnit min_value =
- ComputeMainSizeFromAspectRatioUsing(child, cross_min);
+ LayoutUnit min_value = ComputeMainSizeFromAspectRatioUsing(
+ child, cross_min, main_axis_border_and_padding,
+ cross_axis_border_and_padding);
child_size = std::max(min_value, child_size);
}
@@ -1330,10 +1350,10 @@ void LayoutFlexibleBox::ConstructAndAppendFlexItem(
: child.BorderAndPaddingWidth();
LayoutUnit child_inner_flex_base_size = ComputeInnerFlexBaseSizeForChild(
- child, main_axis_border_padding, layout_type);
+ child, main_axis_border_padding, cross_axis_border_padding, layout_type);
- MinMaxSizes sizes = ComputeMinAndMaxSizesForChild(*algorithm, child,
- main_axis_border_padding);
+ MinMaxSizes sizes = ComputeMinAndMaxSizesForChild(
+ *algorithm, child, main_axis_border_padding, cross_axis_border_padding);
NGPhysicalBoxStrut physical_margins(child.MarginTop(), child.MarginRight(),
child.MarginBottom(), child.MarginLeft());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
index 0e582321335..3caa818bac9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -166,11 +166,14 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
bool UseChildAspectRatio(const LayoutBox& child) const;
LayoutUnit ComputeMainSizeFromAspectRatioUsing(
const LayoutBox& child,
- const Length& cross_size_length) const;
+ const Length& cross_size_length,
+ LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const;
void SetFlowAwareLocationForChild(LayoutBox& child, const LayoutPoint&);
LayoutUnit ComputeInnerFlexBaseSizeForChild(
LayoutBox& child,
LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding,
ChildLayoutType = kLayoutIfNeeded);
void ResetAlignmentForChild(LayoutBox& child, LayoutUnit);
bool MainAxisLengthIsDefinite(const LayoutBox& child,
@@ -197,10 +200,13 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
MinMaxSizes ComputeMinAndMaxSizesForChild(
const FlexLayoutAlgorithm& algorithm,
const LayoutBox& child,
- LayoutUnit border_and_padding) const;
+ LayoutUnit border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const;
LayoutUnit AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
const LayoutBox& child,
- LayoutUnit child_size) const;
+ LayoutUnit child_size,
+ LayoutUnit main_axis_border_and_padding,
+ LayoutUnit cross_axis_border_and_padding) const;
void ConstructAndAppendFlexItem(FlexLayoutAlgorithm* algorithm,
LayoutBox& child,
ChildLayoutType);
@@ -248,7 +254,12 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
bool in_layout_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFlexibleBox, IsFlexibleBox());
+template <>
+struct DowncastTraits<LayoutFlexibleBox> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsFlexibleBox();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame.cc b/chromium/third_party/blink/renderer/core/layout/layout_frame.cc
index 994ef3e17b5..f96064fddb4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame.cc
@@ -62,7 +62,7 @@ void LayoutFrame::ImageChanged(WrappedImagePtr image, CanDeferInvalidation) {
void LayoutFrame::UpdateFromElement() {
NOT_DESTROYED();
if (Parent() && Parent()->IsFrameSet())
- ToLayoutFrameSet(Parent())->NotifyFrameEdgeInfoChanged();
+ To<LayoutFrameSet>(Parent())->NotifyFrameEdgeInfoChanged();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame.h b/chromium/third_party/blink/renderer/core/layout/layout_frame.h
index 39d4b9ded34..e56594414c9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame.h
@@ -52,7 +52,10 @@ class LayoutFrame final : public LayoutEmbeddedContent {
void UpdateFromElement() override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFrame, IsFrame());
+template <>
+struct DowncastTraits<LayoutFrame> {
+ static bool AllowFrom(const LayoutObject& object) { return object.IsFrame(); }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 1834a9f5abc..d26607e7b67 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -338,9 +338,9 @@ void LayoutFrameSet::ComputeEdgeInfo() {
for (size_t c = 0; c < cols; ++c) {
FrameEdgeInfo edge_info;
if (child->IsFrameSet())
- edge_info = ToLayoutFrameSet(child)->EdgeInfo();
+ edge_info = To<LayoutFrameSet>(child)->EdgeInfo();
else
- edge_info = ToLayoutFrame(child)->EdgeInfo();
+ edge_info = To<LayoutFrame>(child)->EdgeInfo();
FillFromEdgeInfo(edge_info, r, c);
child = child->NextSibling();
if (!child)
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
index 9fa9204ed9d..a0406768a1d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -159,7 +159,10 @@ class LayoutFrameSet final : public LayoutBox {
}
MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
NOT_DESTROYED();
- return MinMaxSizes();
+ MinMaxSizes sizes;
+ LayoutUnit scrollbar_thickness = ComputeLogicalScrollbars().InlineSum();
+ sizes += BorderAndPaddingLogicalWidth() + scrollbar_thickness;
+ return sizes;
}
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
@@ -186,7 +189,12 @@ class LayoutFrameSet final : public LayoutBox {
bool is_resizing_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFrameSet, IsFrameSet());
+template <>
+struct DowncastTraits<LayoutFrameSet> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsFrameSet();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_grid.h b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
index 30dceeed49b..e85ee16893e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
@@ -331,7 +331,12 @@ class LayoutGrid final : public LayoutBlock {
base::Optional<bool> has_definite_logical_height_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutGrid, IsLayoutGrid());
+template <>
+struct DowncastTraits<LayoutGrid> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsLayoutGrid();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
index f74de0c5d35..c53e348cac2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -68,6 +69,23 @@ void LayoutHTMLCanvas::CanvasSizeChanged() {
SetNeedsLayout(layout_invalidation_reason::kSizeChanged);
}
+bool LayoutHTMLCanvas::DrawsBackgroundOntoContentLayer() const {
+ auto* canvas = To<HTMLCanvasElement>(GetNode());
+ if (canvas->SurfaceLayerBridge())
+ return false;
+ CanvasRenderingContext* context = canvas->RenderingContext();
+ if (!context || !context->IsComposited() || !context->CcLayer())
+ return false;
+ if (StyleRef().HasBoxDecorations() || StyleRef().HasBackgroundImage())
+ return false;
+ // If there is no background, there is nothing to support.
+ if (!StyleRef().HasBackground())
+ return true;
+ // Simple background that is contained within the contents rect.
+ return ReplacedContentRect().Contains(
+ PhysicalBackgroundRect(kBackgroundClipRect));
+}
+
void LayoutHTMLCanvas::InvalidatePaint(
const PaintInvalidatorContext& context) const {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
index a7f8e575eb3..f2f37357544 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
@@ -46,6 +46,8 @@ class CORE_EXPORT LayoutHTMLCanvas final : public LayoutReplaced {
void CanvasSizeChanged();
+ bool DrawsBackgroundOntoContentLayer() const final;
+
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
const char* GetName() const override {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
index b964f9ff32b..f0bdc8d7dca 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
@@ -155,24 +155,17 @@ void LayoutImage::UpdateIntrinsicSizeIfNeeded(const LayoutSize& new_size) {
bool LayoutImage::NeedsLayoutOnIntrinsicSizeChange() const {
NOT_DESTROYED();
- // If the actual area occupied by the image has changed and it is not
- // constrained by style then a layout is required.
- bool image_size_is_constrained =
- StyleRef().LogicalWidth().IsSpecified() &&
- StyleRef().LogicalHeight().IsSpecified() &&
- !HasAutoHeightOrContainingBlockWithAutoHeight(
- kDontRegisterPercentageDescendant);
- if (!image_size_is_constrained)
- return true;
// Flex layout algorithm uses the intrinsic image width/height even if
// width/height are specified.
if (IsFlexItemIncludingNG())
return true;
- // FIXME: We only need to recompute the containing block's preferred size if
- // the containing block's size depends on the image's size (i.e., the
- // container uses shrink-to-fit sizing). There's no easy way to detect that
- // shrink-to-fit is needed, always force a layout.
- return HasRelativeLogicalWidth();
+
+ const auto& style = StyleRef();
+ bool is_fixed_sized =
+ style.LogicalWidth().IsFixed() && style.LogicalHeight().IsFixed() &&
+ (style.LogicalMinWidth().IsFixed() || style.LogicalMinWidth().IsAuto()) &&
+ (style.LogicalMaxWidth().IsFixed() || style.LogicalMaxWidth().IsNone());
+ return !is_fixed_sized;
}
void LayoutImage::InvalidatePaintAndMarkForLayoutIfNeeded(
@@ -330,7 +323,7 @@ bool LayoutImage::NodeAtPoint(HitTestResult& result,
bool LayoutImage::HasOverriddenIntrinsicSize() const {
NOT_DESTROYED();
- if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+ if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled())
return false;
auto* image_element = DynamicTo<HTMLImageElement>(GetNode());
return image_element && image_element->IsDefaultIntrinsicSize();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
index 4a332548f49..62774f0f89e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
@@ -95,6 +95,15 @@ bool LayoutImageResource::HasIntrinsicSize() const {
return !cached_image_ || cached_image_->GetImage()->HasIntrinsicSize();
}
+RespectImageOrientationEnum LayoutImageResource::ImageOrientation() const {
+ DCHECK(cached_image_);
+ // Always respect the orientation of opaque origin images to avoid leaking
+ // image data. Otherwise pull orientation from the layout object's style.
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(layout_object_);
+ return cached_image_->ForceOrientationIfNecessary(respect_orientation);
+}
+
FloatSize LayoutImageResource::ImageSize(float multiplier) const {
if (!cached_image_)
return FloatSize();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
index 05bc56a06bd..b5c425ff23c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
@@ -69,6 +69,7 @@ class CORE_EXPORT LayoutImageResource
// Default size is effective when this is LayoutImageResourceStyleImage.
virtual FloatSize ImageSizeWithDefaultSize(float multiplier,
const FloatSize&) const;
+ virtual RespectImageOrientationEnum ImageOrientation() const;
virtual WrappedImagePtr ImagePtr() const { return cached_image_.Get(); }
virtual void Trace(Visitor* visitor) const { visitor->Trace(cached_image_); }
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
index 575f1c53752..ac6e978e7cc 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
@@ -86,6 +86,16 @@ FloatSize LayoutImageResourceStyleImage::ImageSizeWithDefaultSize(
layout_object_->GetDocument(), multiplier, default_size,
LayoutObject::ShouldRespectImageOrientation(layout_object_));
}
+
+RespectImageOrientationEnum LayoutImageResourceStyleImage::ImageOrientation()
+ const {
+ // Always respect the orientation of opaque origin images to avoid leaking
+ // image data. Otherwise pull orientation from the layout object's style.
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(layout_object_);
+ return style_image_->ForceOrientationIfNecessary(respect_orientation);
+}
+
void LayoutImageResourceStyleImage::Trace(Visitor* visitor) const {
visitor->Trace(style_image_);
LayoutImageResource::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
index 93c5e6fabbe..ef6931c857b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
@@ -53,6 +53,7 @@ class LayoutImageResourceStyleImage final : public LayoutImageResource {
FloatSize ImageSize(float multiplier) const override;
FloatSize ImageSizeWithDefaultSize(float multiplier,
const FloatSize&) const override;
+ RespectImageOrientationEnum ImageOrientation() const override;
WrappedImagePtr ImagePtr() const override { return style_image_->Data(); }
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
index 25f5a42e56d..9d6d73f479d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -38,7 +38,6 @@
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -46,7 +45,6 @@
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/inline_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
@@ -57,16 +55,6 @@ namespace blink {
namespace {
-// TODO(layout-dev): Once we generate fragment for all inline element, we should
-// use |LayoutObject::EnclosingBlockFlowFragment()|.
-// TODO(crbug.com/1061423): Shouldn't assume that there's only one fragment.
-const NGPhysicalBoxFragment* ContainingBlockFlowFragmentOf(
- const LayoutInline& node) {
- if (!RuntimeEnabledFeatures::LayoutNGEnabled())
- return nullptr;
- return node.ContainingBlockFlowFragment();
-}
-
// TODO(xiaochengh): Deduplicate with a similar function in ng_paint_fragment.cc
// ::before, ::after and ::first-letter can be hit test targets.
bool CanBeHitTestTargetPseudoNodeStyle(const ComputedStyle& style) {
@@ -140,10 +128,7 @@ void LayoutInline::WillBeDestroyed() {
} else {
if (Parent())
Parent()->DirtyLinesFromChangedChild(this);
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (NGPaintFragment* first_inline_fragment = FirstInlineFragment())
- first_inline_fragment->LayoutObjectWillBeDestroyed();
- } else if (FirstInlineFragmentItemIndex()) {
+ if (FirstInlineFragmentItemIndex()) {
NGFragmentItems::LayoutObjectWillBeDestroyed(*this);
ClearFirstInlineFragmentItemIndex();
}
@@ -161,55 +146,36 @@ void LayoutInline::DeleteLineBoxes() {
MutableLineBoxes()->DeleteLineBoxes();
}
-void LayoutInline::SetFirstInlineFragment(NGPaintFragment* fragment) {
- NOT_DESTROYED();
- CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- first_paint_fragment_ = fragment;
-}
-
void LayoutInline::ClearFirstInlineFragmentItemIndex() {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
first_fragment_item_index_ = 0u;
}
void LayoutInline::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
first_fragment_item_index_ = index;
}
bool LayoutInline::HasInlineFragments() const {
NOT_DESTROYED();
- if (!IsInLayoutNGInlineFormattingContext())
- return FirstLineBox();
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return first_paint_fragment_;
- return first_fragment_item_index_;
+ if (IsInLayoutNGInlineFormattingContext())
+ return first_fragment_item_index_;
+ return FirstLineBox();
}
void LayoutInline::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
NOT_DESTROYED();
- if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- SetFirstInlineFragment(nullptr);
- } else {
- ClearFirstInlineFragmentItemIndex();
- }
- } else {
+ if (IsInLayoutNGInlineFormattingContext())
+ ClearFirstInlineFragmentItemIndex();
+ else
DeleteLineBoxes();
- }
- // Because |first_paint_fragment_| and |line_boxes_| are union, when one is
- // deleted, the other should be initialized to nullptr.
- DCHECK(new_value ? (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()
- ? !first_fragment_item_index_
- : !first_paint_fragment_)
- : !line_boxes_.First());
+ // Because |first_fragment_item_index_| and |line_boxes_| are union, when one
+ // is deleted, the other should be initialized to nullptr.
+ DCHECK(new_value ? !first_fragment_item_index_ : !line_boxes_.First());
}
LayoutInline* LayoutInline::InlineElementContinuation() const {
@@ -492,7 +458,7 @@ LayoutRect LayoutInline::LocalCaretRect(
cursor.MoveTo(*this);
if (cursor) {
caret_rect.MoveBy(
- cursor.Current().OffsetInContainerBlock().ToLayoutPoint());
+ cursor.Current().OffsetInContainerFragment().ToLayoutPoint());
}
}
@@ -843,15 +809,6 @@ void LayoutInline::CollectLineBoxRects(
const PhysicalRectCollector& yield) const {
NOT_DESTROYED();
if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- const auto* box_fragment = ContainingBlockFlowFragmentOf(*this);
- if (!box_fragment)
- return;
- for (const auto& fragment :
- NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this))
- yield(fragment.RectInContainerBox());
- return;
- }
NGInlineCursor cursor;
cursor.MoveToIncludingCulledInline(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject())
@@ -1126,25 +1083,12 @@ bool LayoutInline::NodeAtPoint(HitTestResult& result,
// inline may not start in the first fragment generated for the inline
// formatting context.
if (target_fragment_idx != -1)
- target_fragment_idx += cursor.CurrentContainerFragmentIndex();
+ target_fragment_idx += cursor.ContainerFragmentIndex();
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
if (target_fragment_idx != -1 &&
- wtf_size_t(target_fragment_idx) !=
- cursor.CurrentContainerFragmentIndex())
- continue;
- if (const NGPaintFragment* paint_fragment =
- cursor.Current().PaintFragment()) {
- // NGBoxFragmentPainter::NodeAtPoint() takes an offset that is
- // accumulated up to the fragment itself. Compute this offset.
- const PhysicalOffset child_offset =
- accumulated_offset + paint_fragment->OffsetInContainerBlock();
- if (NGBoxFragmentPainter(*paint_fragment)
- .NodeAtPoint(result, hit_test_location, child_offset,
- hit_test_action))
- return true;
+ wtf_size_t(target_fragment_idx) != cursor.ContainerFragmentIndex())
continue;
- }
DCHECK(cursor.Current().Item());
const NGFragmentItem& item = *cursor.Current().Item();
const NGPhysicalBoxFragment* box_fragment = item.BoxFragment();
@@ -1152,15 +1096,10 @@ bool LayoutInline::NodeAtPoint(HitTestResult& result,
// NGBoxFragmentPainter::NodeAtPoint() takes an offset that is accumulated
// up to the fragment itself. Compute this offset.
const PhysicalOffset child_offset =
- accumulated_offset + item.OffsetInContainerBlock();
+ accumulated_offset + item.OffsetInContainerFragment();
if (NGBoxFragmentPainter(cursor, item, *box_fragment)
.NodeAtPoint(result, hit_test_location, child_offset,
accumulated_offset, hit_test_action)) {
- // TODO(layout-dev): Make this work with block fragmentation. We should
- // ideally store the containing box fragment in the hit-test result
- // here, but doing that might prevent us from finding the right fragment
- // item later on in PositionForPoint(), if the inline has been offset
- // from its static position.
return true;
}
}
@@ -1202,7 +1141,7 @@ bool LayoutInline::HitTestCulledInline(HitTestResult& result,
NGInlineCursor cursor(*parent_cursor);
cursor.MoveToIncludingCulledInline(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject())
- yield(cursor.Current().RectInContainerBlock());
+ yield(cursor.Current().RectInContainerFragment());
} else {
DCHECK(!ContainingNGBlockFlow());
CollectCulledLineBoxRects(yield);
@@ -1235,7 +1174,7 @@ PositionWithAffinity LayoutInline::PositionForPoint(
}
if (const LayoutBlockFlow* ng_block_flow = ContainingNGBlockFlow())
- return ng_block_flow->PositionForPoint(*this, point);
+ return ng_block_flow->PositionForPoint(point);
DCHECK(CanUseInlineBox(*this));
@@ -1256,7 +1195,7 @@ PhysicalRect LayoutInline::PhysicalLinesBoundingBox() const {
cursor.MoveToIncludingCulledInline(*this);
PhysicalRect bounding_box;
for (; cursor; cursor.MoveToNextForSameLayoutObject())
- bounding_box.UniteIfNonZero(cursor.Current().RectInContainerBlock());
+ bounding_box.UniteIfNonZero(cursor.Current().RectInContainerFragment());
return bounding_box;
}
@@ -1409,7 +1348,7 @@ PhysicalRect LayoutInline::LinesVisualOverflowBoundingBox() const {
cursor.MoveToIncludingCulledInline(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
PhysicalRect child_rect = cursor.Current().InkOverflow();
- child_rect.offset += cursor.Current().OffsetInContainerBlock();
+ child_rect.offset += cursor.Current().OffsetInContainerFragment();
result.Unite(child_rect);
}
return result;
@@ -1466,11 +1405,7 @@ PhysicalRect LayoutInline::LocalVisualRectIgnoringVisibility() const {
NOT_DESTROYED();
if (IsInLayoutNGInlineFormattingContext()) {
DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return NGFragmentItem::LocalVisualRectFor(*this);
-
- if (const auto& visual_rect = NGPaintFragment::LocalVisualRectFor(*this))
- return *visual_rect;
+ return NGFragmentItem::LocalVisualRectFor(*this);
}
// If we don't create line boxes, we don't have any invalidations to do.
@@ -1485,7 +1420,8 @@ PhysicalRect LayoutInline::LocalVisualRectIgnoringVisibility() const {
PhysicalRect LayoutInline::PhysicalVisualOverflowRect() const {
NOT_DESTROYED();
PhysicalRect overflow_rect = LinesVisualOverflowBoundingBox();
- LayoutUnit outline_outset(StyleRef().OutlineOutsetExtent());
+ const ComputedStyle& style = StyleRef();
+ LayoutUnit outline_outset(style.OutlineOutsetExtent());
if (outline_outset) {
Vector<PhysicalRect> rects;
if (GetDocument().InNoQuirksMode()) {
@@ -1494,14 +1430,14 @@ PhysicalRect LayoutInline::PhysicalVisualOverflowRect() const {
// rects for children and continuations.
AddOutlineRectsForChildrenAndContinuations(
rects, PhysicalOffset(),
- OutlineRectsShouldIncludeBlockVisualOverflow());
+ style.OutlineRectsShouldIncludeBlockVisualOverflow());
} else {
// In non-standard mode, because the difference in
// LayoutBlock::minLineHeightForReplacedObject(),
// linesVisualOverflowBoundingBox() may not cover outline rects of lines
// containing replaced objects.
AddOutlineRects(rects, PhysicalOffset(),
- OutlineRectsShouldIncludeBlockVisualOverflow());
+ style.OutlineRectsShouldIncludeBlockVisualOverflow());
}
if (!rects.IsEmpty()) {
PhysicalRect outline_rect = UnionRect(rects);
@@ -1524,7 +1460,7 @@ PhysicalRect LayoutInline::ReferenceBoxForClipPath() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
if (cursor)
- return cursor.Current().RectInContainerBlock();
+ return cursor.Current().RectInContainerFragment();
}
if (const InlineFlowBox* flow_box = FirstLineBox())
return FlipForWritingMode(flow_box->FrameRect());
@@ -1683,12 +1619,8 @@ void LayoutInline::DirtyLinesFromChangedChild(
MarkingBehavior marking_behavior) {
NOT_DESTROYED();
if (IsInLayoutNGInlineFormattingContext()) {
- if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
- if (const LayoutBlockFlow* container = FragmentItemsContainer())
- NGFragmentItems::DirtyLinesFromChangedChild(*child, *container);
- return;
- }
- SetAncestorLineBoxDirty();
+ if (const LayoutBlockFlow* container = FragmentItemsContainer())
+ NGFragmentItems::DirtyLinesFromChangedChild(*child, *container);
return;
}
MutableLineBoxes()->DirtyLinesFromChangedChild(
@@ -1887,16 +1819,6 @@ void LayoutInline::InvalidateDisplayItemClients(
if (IsInLayoutNGInlineFormattingContext()) {
if (!ShouldCreateBoxFragment())
return;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- NGInlineCursor cursor;
- for (cursor.MoveTo(*this); cursor;
- cursor.MoveToNextForSameLayoutObject()) {
- DCHECK_EQ(cursor.Current().GetLayoutObject(), this);
- paint_invalidator.InvalidateDisplayItemClient(
- *cursor.Current().GetDisplayItemClient(), invalidation_reason);
- }
- return;
- }
#if DCHECK_IS_ON()
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.h b/chromium/third_party/blink/renderer/core/layout/layout_inline.h
index 09869f8e344..6bf6b23c15f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.h
@@ -35,7 +35,6 @@ namespace blink {
class LayoutBlockFlow;
class NGInlineCursor;
-class NGPaintFragment;
// LayoutInline is the LayoutObject associated with display: inline.
// This is called an "inline box" in CSS 2.1.
@@ -187,8 +186,6 @@ class CORE_EXPORT LayoutInline : public LayoutBoxModelObject {
}
bool HasInlineFragments() const final;
- NGPaintFragment* FirstInlineFragment() const final;
- void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
void ClearFirstInlineFragmentItemIndex() final;
void SetFirstInlineFragmentItemIndex(wtf_size_t) final;
@@ -454,9 +451,6 @@ class CORE_EXPORT LayoutInline : public LayoutBoxModelObject {
// <i>Hello<br>world.</i> will have two <i> line boxes.
// Valid only when !IsInLayoutNGInlineFormattingContext().
LineBoxList line_boxes_;
- // The first fragment of inline boxes associated with this object.
- // Valid only when IsInLayoutNGInlineFormattingContext().
- NGPaintFragment* first_paint_fragment_;
// The index of the first fragment item associated with this object in
// |NGFragmentItems::Items()|. Zero means there are no such item.
// Valid only when IsInLayoutNGInlineFormattingContext().
@@ -469,21 +463,9 @@ inline LineBoxList* LayoutInline::MutableLineBoxes() {
return &line_boxes_;
}
-inline NGPaintFragment* LayoutInline::FirstInlineFragment() const {
- if (!IsInLayoutNGInlineFormattingContext())
- return nullptr;
- // TODO(yosin): Once we replace all usage of |FirstInlineFragment()| to
- // |NGInlineCursor|, we should change this to |DCHECK()|.
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return nullptr;
- return first_paint_fragment_;
-}
-
inline wtf_size_t LayoutInline::FirstInlineFragmentItemIndex() const {
if (!IsInLayoutNGInlineFormattingContext())
return 0u;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
return first_fragment_item_index_;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
index d087de53d9a..0d5766c7e16 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/core/html/html_olist_element.h"
#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_outside_list_marker.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/list_marker.h"
#include "third_party/blink/renderer/core/paint/list_item_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -43,6 +44,14 @@ LayoutListItem::LayoutListItem(Element* element)
SetConsumesSubtreeChangeNotification();
RegisterSubtreeChangeListenerOnDescendants(true);
+ View()->AddLayoutListItem();
+}
+
+void LayoutListItem::WillBeDestroyed() {
+ NOT_DESTROYED();
+ if (View())
+ View()->RemoveLayoutListItem();
+ LayoutBlockFlow::WillBeDestroyed();
}
void LayoutListItem::StyleDidChange(StyleDifference diff,
@@ -51,7 +60,7 @@ void LayoutListItem::StyleDidChange(StyleDifference diff,
LayoutBlockFlow::StyleDidChange(diff, old_style);
StyleImage* current_image = StyleRef().ListStyleImage();
- if (StyleRef().ListStyleType() != EListStyleType::kNone ||
+ if (StyleRef().GetListStyleType() ||
(current_image && !current_image->ErrorOccurred())) {
NotifyOfSubtreeChange();
}
@@ -69,15 +78,44 @@ void LayoutListItem::StyleDidChange(StyleDifference diff,
else
list_marker->UpdateMarkerContentIfNeeded(*marker);
- if (old_style && (old_style->ListStyleType() != StyleRef().ListStyleType() ||
- (StyleRef().ListStyleType() == EListStyleType::kString &&
- old_style->ListStyleStringValue() !=
- StyleRef().ListStyleStringValue()))) {
- if (legacy_marker)
- legacy_marker->ListStyleTypeChanged();
- else
- list_marker->ListStyleTypeChanged(*marker);
+ if (old_style) {
+ const ListStyleTypeData* old_list_style_type =
+ old_style->GetListStyleType();
+ const ListStyleTypeData* new_list_style_type =
+ StyleRef().GetListStyleType();
+ if (old_list_style_type != new_list_style_type &&
+ (!old_list_style_type || !new_list_style_type ||
+ *old_list_style_type != *new_list_style_type)) {
+ if (legacy_marker)
+ legacy_marker->ListStyleTypeChanged();
+ else
+ list_marker->ListStyleTypeChanged(*marker);
+ }
+ }
+}
+
+void LayoutListItem::UpdateCounterStyle() {
+ NOT_DESTROYED();
+
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled())
+ return;
+
+ if (!StyleRef().GetListStyleType() ||
+ StyleRef().GetListStyleType()->IsCounterStyleReferenceValid(
+ GetDocument())) {
+ return;
+ }
+
+ LayoutObject* marker = Marker();
+ if (!marker)
+ return;
+
+ if (auto* legacy_marker = DynamicTo<LayoutListMarker>(marker)) {
+ legacy_marker->CounterStyleChanged();
+ return;
}
+
+ ListMarker::Get(marker)->CounterStyleChanged(*marker);
}
void LayoutListItem::InsertedIntoTree() {
@@ -598,7 +636,7 @@ void LayoutListItem::UpdateOverflow() {
layout_block_object->AddLayoutOverflow(marker_rect);
}
- if (object->HasNonVisibleOverflow())
+ if (object->ShouldClipOverflowAlongBothAxis())
break;
if (object->HasSelfPaintingLayer())
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
index a7fdeeaa797..d5e56c347c1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
@@ -58,6 +58,8 @@ class LayoutListItem final : public LayoutBlockFlow {
void UpdateMarkerTextIfNeeded();
+ void UpdateCounterStyle();
+
private:
bool IsOfType(LayoutObjectType type) const override {
NOT_DESTROYED();
@@ -82,6 +84,8 @@ class LayoutListItem final : public LayoutBlockFlow {
void AddLayoutOverflowFromChildren() override;
+ void WillBeDestroyed() override;
+
void AlignMarkerInBlockDirection();
bool PrepareForBlockDirectionAlign(const LayoutObject*);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
index bf18eb649c6..4cbdc402ae4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -25,15 +25,18 @@
#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
+#include "third_party/blink/renderer/core/css/counter_style.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
#include "third_party/blink/renderer/core/layout/list_marker.h"
#include "third_party/blink/renderer/core/layout/list_marker_text.h"
#include "third_party/blink/renderer/core/paint/list_marker_painter.h"
+#include "third_party/blink/renderer/core/style/list_style_type_data.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
namespace blink {
+class HTMLLIElement;
LayoutListMarker::LayoutListMarker(Element* element) : LayoutBox(element) {
DCHECK(ListItem());
@@ -84,6 +87,14 @@ void LayoutListMarker::ListStyleTypeChanged() {
layout_invalidation_reason::kListStyleTypeChange);
}
+void LayoutListMarker::CounterStyleChanged() {
+ NOT_DESTROYED();
+ if (IsImage())
+ return;
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kCounterStyleChange);
+}
+
void LayoutListMarker::UpdateMarkerImageIfNeeded(StyleImage* image) {
NOT_DESTROYED();
if (image_ != image) {
@@ -174,12 +185,20 @@ void LayoutListMarker::UpdateContent() {
case ListMarker::ListStyleCategory::kNone:
break;
case ListMarker::ListStyleCategory::kSymbol:
- text_ = list_marker_text::GetText(StyleRef().ListStyleType(),
- 0); // value is ignored for these types
+ // value is ignored for these types
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ text_ = GetCounterStyle().GenerateRepresentation(0);
+ } else {
+ text_ = list_marker_text::GetText(StyleRef().ListStyleType(), 0);
+ }
break;
case ListMarker::ListStyleCategory::kLanguage:
- text_ = list_marker_text::GetText(StyleRef().ListStyleType(),
- ListItem()->Value());
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ text_ = GetCounterStyle().GenerateRepresentation(ListItem()->Value());
+ } else {
+ text_ = list_marker_text::GetText(StyleRef().ListStyleType(),
+ ListItem()->Value());
+ }
break;
case ListMarker::ListStyleCategory::kStaticString:
text_ = StyleRef().ListStyleStringValue();
@@ -191,9 +210,20 @@ String LayoutListMarker::TextAlternative() const {
NOT_DESTROYED();
if (GetListStyleCategory() == ListMarker::ListStyleCategory::kStaticString)
return text_;
+
+ // Return prefix, marker text and then suffix even in RTL, reflecting speech
+ // order.
+
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ if (GetListStyleCategory() == ListMarker::ListStyleCategory::kNone)
+ return "";
+
+ const CounterStyle& counter_style = GetCounterStyle();
+ return counter_style.GetPrefix() + text_ + counter_style.GetSuffix();
+ }
+
UChar suffix =
list_marker_text::Suffix(StyleRef().ListStyleType(), ListItem()->Value());
- // Return suffix after the marker text, even in RTL, reflecting speech order.
return text_ + suffix + ' ';
}
@@ -209,6 +239,18 @@ LayoutUnit LayoutListMarker::GetWidthOfText(
// Don't add a suffix.
return item_width;
}
+
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ // This doesn't seem correct, e.g., ligatures. We don't fix it since it's
+ // legacy layout.
+ const CounterStyle& counter_style = GetCounterStyle();
+ if (counter_style.GetPrefix())
+ item_width += LayoutUnit(font.Width(TextRun(counter_style.GetPrefix())));
+ if (counter_style.GetSuffix())
+ item_width += LayoutUnit(font.Width(TextRun(counter_style.GetSuffix())));
+ return item_width;
+ }
+
// TODO(wkorman): Look into constructing a text run for both text and suffix
// and painting them together.
UChar suffix[2] = {
@@ -261,11 +303,11 @@ void LayoutListMarker::UpdateMargins(LayoutUnit marker_inline_size) {
const ComputedStyle& style = StyleRef();
const ComputedStyle& list_item_style = ListItem()->StyleRef();
if (IsInside()) {
- std::tie(margin_start, margin_end) =
- ListMarker::InlineMarginsForInside(style, list_item_style);
+ std::tie(margin_start, margin_end) = ListMarker::InlineMarginsForInside(
+ GetDocument(), style, list_item_style);
} else {
std::tie(margin_start, margin_end) = ListMarker::InlineMarginsForOutside(
- style, list_item_style, marker_inline_size);
+ GetDocument(), style, list_item_style, marker_inline_size);
}
SetMarginStart(margin_start);
@@ -304,7 +346,15 @@ LayoutUnit LayoutListMarker::BaselinePosition(
ListMarker::ListStyleCategory LayoutListMarker::GetListStyleCategory() const {
NOT_DESTROYED();
- return ListMarker::GetListStyleCategory(StyleRef().ListStyleType());
+ return ListMarker::GetListStyleCategory(GetDocument(), StyleRef());
+}
+
+const CounterStyle& LayoutListMarker::GetCounterStyle() const {
+ NOT_DESTROYED();
+ const ListStyleTypeData* list_style_data = StyleRef().GetListStyleType();
+ DCHECK(list_style_data);
+ DCHECK(list_style_data->IsCounterStyle());
+ return list_style_data->GetCounterStyle(GetDocument());
}
bool LayoutListMarker::IsInside() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
index 2877305e9d8..6042c09d530 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
@@ -51,6 +51,7 @@ class CORE_EXPORT LayoutListMarker final : public LayoutBox {
String TextAlternative() const;
ListMarker::ListStyleCategory GetListStyleCategory() const;
+ const CounterStyle& GetCounterStyle() const;
bool IsInside() const;
@@ -116,6 +117,7 @@ class CORE_EXPORT LayoutListMarker final : public LayoutBox {
void UpdateMarkerImageIfNeeded(StyleImage* image);
void ListStyleTypeChanged();
+ void CounterStyleChanged();
String text_;
Persistent<StyleImage> image_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_marker_test.cc
new file mode 100644
index 00000000000..716031f9f8e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
+
+#include "third_party/blink/renderer/core/layout/layout_list_item.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class LayoutListMarkerTest : public RenderingTest,
+ private ScopedLayoutNGForTest {
+ public:
+ // LayoutListMarker is for legacy layout only
+ LayoutListMarkerTest() : ScopedLayoutNGForTest(false) {}
+};
+
+// https://crbug.com/1167174
+TEST_F(LayoutListMarkerTest, ListStyleTypeNoneTextAlternative) {
+ ScopedCSSAtRuleCounterStyleForTest scope(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ li {
+ list-style-type: none;
+ list-style-image: linear-gradient(black, white);
+ }
+ </style>
+ <ul>
+ <li id="target">foo</li>
+ </ul>
+ )HTML");
+
+ Element* target = GetElementById("target");
+ LayoutObject* marker =
+ ListMarker::MarkerFromListItem(target->GetLayoutObject());
+
+ // Should not crash
+ EXPECT_EQ("", To<LayoutListMarker>(marker)->TextAlternative());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index 58a3617ff9e..cae64cfbdbb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -734,13 +734,8 @@ LayoutMultiColumnSet* LayoutMultiColumnFlowThread::PendingColumnSetForNG()
void LayoutMultiColumnFlowThread::AppendNewFragmentainerGroupFromNG() {
NOT_DESTROYED();
- // TODO(mstensho): This nullptr check shouldn't be here, but we need it for
- // now. If we have no column set at this point, something has gone wrong, but
- // NG nested column balancing sometimes acts up when doubly nested (or more),
- // making the legacy write-back machinery call FinishLayoutFromNG()
- // prematurely. See e.g. fast/multicol/client-rect-nested.html
- if (last_set_worked_on_)
- last_set_worked_on_->AppendNewFragmentainerGroup();
+ DCHECK(last_set_worked_on_);
+ last_set_worked_on_->AppendNewFragmentainerGroup();
}
void LayoutMultiColumnFlowThread::SetCurrentColumnBlockSizeFromNG(
@@ -1521,9 +1516,6 @@ void LayoutMultiColumnFlowThread::UpdateLayout() {
// will generate additional columns and pages to hold that overflow,
// since people do write bad content like <body style="height:0px"> in
// multi-column layouts.
- // TODO(mstensho): Once we support nested multicol, adding in overflow
- // here may result in the need for creating additional rows, since there
- // may not be enough space remaining in the currently last row.
LayoutRect layout_rect = LayoutOverflowRect();
LayoutUnit logical_bottom_in_flow_thread =
IsHorizontalWritingMode() ? layout_rect.MaxY() : layout_rect.MaxX();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index 89d18892612..19bcf0a6317 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -58,7 +58,6 @@ unsigned LayoutMultiColumnSet::FragmentainerGroupIndexAtFlowThreadOffset(
DCHECK_GT(fragmentainer_groups_.size(), 0u);
if (flow_thread_offset <= 0)
return 0;
- // TODO(mstensho): Introduce an interval tree or similar to speed up this.
for (unsigned index = 0; index < fragmentainer_groups_.size(); index++) {
const auto& row = fragmentainer_groups_[index];
if (rule == kAssociateWithLatterPage) {
@@ -204,8 +203,6 @@ LayoutUnit LayoutMultiColumnSet::NextLogicalTopForUnbreakableContent(
content_logical_height);
// There's a likelihood for subsequent rows to be taller than the first one.
- // TODO(mstensho): if we're doubly nested (e.g. multicol in multicol in
- // multicol), we need to look beyond the first row here.
const MultiColumnFragmentainerGroup& first_row = FirstFragmentainerGroup();
LayoutUnit first_row_logical_bottom_in_flow_thread =
first_row.LogicalTopInFlowThread() +
@@ -500,6 +497,8 @@ void LayoutMultiColumnSet::ComputeLogicalHeight(
PositionWithAffinity LayoutMultiColumnSet::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
LayoutPoint flipped_point = FlipForWritingMode(point);
// Convert the visual point to a flow thread point.
const MultiColumnFragmentainerGroup& row =
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
index 81ff71381b6..cbe6c572de7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
@@ -59,6 +59,7 @@
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
+#include "third_party/blink/renderer/core/html/html_summary_element.h"
#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
#include "third_party/blink/renderer/core/html/html_table_element.h"
#include "third_party/blink/renderer/core/html/image_document.h"
@@ -89,14 +90,13 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
+#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h"
+#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -159,6 +159,18 @@ LayoutObject* FindAncestorByPredicate(const LayoutObject* descendant,
skip_info->Update(*legend_parent);
object = legend_parent;
}
+ } else if (UNLIKELY(object->IsColumnSpanAll())) {
+ // The containing block chain goes directly from the column spanner to the
+ // multi-column container.
+ const auto* multicol_container =
+ object->SpannerPlaceholder()->MultiColumnBlockFlow();
+ if (multicol_container->IsLayoutNGObject()) {
+ while (object->Parent() != multicol_container) {
+ object = object->Parent();
+ if (skip_info)
+ skip_info->Update(*object);
+ }
+ }
}
}
return nullptr;
@@ -292,11 +304,7 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
return LayoutObjectFactory::CreateBlockForLineClamp(*element, style,
legacy);
}
- if (RuntimeEnabledFeatures::LayoutNGWebkitBoxEnabled())
- return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy);
- UseCounter::Count(element->GetDocument(),
- WebFeature::kLegacyLayoutByFlexBox);
- return new LayoutFlexibleBox(element);
+ return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy);
case EDisplay::kFlex:
case EDisplay::kInlineFlex:
UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox);
@@ -427,7 +435,9 @@ void LayoutObject::AssertClearedPaintInvalidationFlags() const {
// no paint effects (only white-space, for instance).
if ((IsText() && IsLayoutNGObject()) ||
// and culled inline boxes too.
- (IsInLayoutNGInlineFormattingContext() && IsLayoutInline()))
+ (IsInLayoutNGInlineFormattingContext() && IsLayoutInline()) ||
+ // TablesNG columns are also not visited.
+ (IsLayoutTableCol() && IsLayoutNGObject()))
return;
ShowLayoutTreeForThis();
NOTREACHED();
@@ -439,7 +449,8 @@ DISABLE_CFI_PERF
void LayoutObject::AddChild(LayoutObject* new_child,
LayoutObject* before_child) {
NOT_DESTROYED();
- DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()));
+ DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()) ||
+ IsLayoutNGObjectForCanvasFormattedText());
LayoutObjectChildList* children = VirtualChildren();
DCHECK(children);
@@ -457,7 +468,8 @@ void LayoutObject::AddChild(LayoutObject* new_child,
!after_child->IsBeforeContent()) {
table = after_child;
} else {
- table = LayoutObjectFactory::CreateAnonymousTableWithParent(*this);
+ table = LayoutObjectFactory::CreateAnonymousTableWithParent(
+ *this, !new_child->IsLayoutNGObject());
children->InsertChildNode(this, table, before_child);
}
table->AddChild(new_child);
@@ -472,7 +484,8 @@ void LayoutObject::AddChild(LayoutObject* new_child,
void LayoutObject::RemoveChild(LayoutObject* old_child) {
NOT_DESTROYED();
- DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()));
+ DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()) ||
+ IsLayoutNGObjectForCanvasFormattedText());
LayoutObjectChildList* children = VirtualChildren();
DCHECK(children);
@@ -574,7 +587,7 @@ bool LayoutObject::HasClipRelatedProperty() const {
// CSS clip-path/mask/filter induces a stacking context and applies inherited
// clip to that stacking context, while resetting clip for descendants. This
// special behavior is already handled elsewhere.
- if (HasClip() || HasNonVisibleOverflow())
+ if (HasClip() || ShouldClipOverflowAlongEitherAxis())
return true;
// Paint containment establishes isolation which creates clip isolation nodes.
// Style & Layout containment also establish isolation (see
@@ -597,20 +610,37 @@ bool LayoutObject::IsRenderedLegendInternal() const {
// We may not be inserted into the tree yet.
if (!parent)
return false;
- if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
- // If there is a rendered legend, it will be found inside the anonymous
- // fieldset wrapper. If the anonymous fieldset wrapper is a multi-column,
- // the rendered legend will be found inside the multi-column flow thread.
- if (parent->IsLayoutFlowThread())
- parent = parent->Parent();
- if (parent->IsAnonymous() && parent->Parent()->IsLayoutNGFieldset())
- parent = parent->Parent();
- }
+
+ // If there is a rendered legend, it will be found inside the anonymous
+ // fieldset wrapper. If the anonymous fieldset wrapper is a multi-column,
+ // the rendered legend will be found inside the multi-column flow thread.
+ if (parent->IsLayoutFlowThread())
+ parent = parent->Parent();
+ if (parent->IsAnonymous() && parent->Parent()->IsLayoutNGFieldset())
+ parent = parent->Parent();
+
const auto* parent_layout_block = DynamicTo<LayoutBlock>(parent);
return parent_layout_block && IsA<HTMLFieldSetElement>(parent->GetNode()) &&
LayoutFieldset::FindInFlowLegend(*parent_layout_block) == this;
}
+bool LayoutObject::IsListMarkerForSummary() const {
+ if (!IsListMarkerIncludingAll())
+ return false;
+ if (const auto* summary =
+ DynamicTo<HTMLSummaryElement>(Parent()->GetNode())) {
+ if (!summary->IsMainSummary())
+ return false;
+ if (ListMarker::GetListStyleCategory(GetDocument(), StyleRef()) !=
+ ListMarker::ListStyleCategory::kSymbol)
+ return false;
+ const AtomicString& name =
+ StyleRef().GetListStyleType()->GetCounterStyleName();
+ return name == "disclosure-open" || name == "disclosure-closed";
+ }
+ return false;
+}
+
LayoutObject* LayoutObject::NextInPreOrderAfterChildren() const {
NOT_DESTROYED();
LayoutObject* o = NextSibling();
@@ -833,14 +863,15 @@ PaintLayer* LayoutObject::PaintingLayer() const {
auto FindContainer = [](const LayoutObject& object) -> const LayoutObject* {
if (object.IsRenderedLegend())
return LayoutFieldset::FindLegendContainingBlock(To<LayoutBox>(object));
- // Use ContainingBlock() instead of ParentCrossingFrames() for floating
- // objects to omit any self-painting layers of inline objects that don't
- // paint the floating object. This is only needed for inline-level floats
- // not managed by LayoutNG. LayoutNG floats are painted by the correct
- // painting layer.
+ // Use ContainingBlock() instead of Parent() for floating objects to omit
+ // any self-painting layers of inline objects that don't paint the floating
+ // object. This is only needed for inline-level floats not managed by
+ // LayoutNG. LayoutNG floats are painted by the correct painting layer.
if (object.IsFloating() && !object.IsInLayoutNGInlineFormattingContext())
return object.ContainingBlock();
- return object.ParentCrossingFrames();
+ if (IsA<LayoutView>(object))
+ return object.GetFrame()->OwnerLayoutObject();
+ return object.Parent();
};
for (const LayoutObject* current = this; current;
@@ -931,17 +962,6 @@ LayoutBlockFlow* LayoutObject::ContainingNGBlockFlow() const {
return nullptr;
}
-const NGPhysicalBoxFragment* LayoutObject::ContainingBlockFlowFragment() const {
- NOT_DESTROYED();
- DCHECK(IsInline() || IsText());
- LayoutBlockFlow* const block_flow = ContainingNGBlockFlow();
- if (!block_flow || !block_flow->ChildrenInline())
- return nullptr;
- // TODO(kojii): CurrentFragment isn't always available after layout clean.
- // Investigate why.
- return block_flow->CurrentFragment();
-}
-
bool LayoutObject::IsFirstInlineFragmentSafe() const {
NOT_DESTROYED();
DCHECK(IsInline());
@@ -971,8 +991,6 @@ LayoutFlowThread* LayoutObject::LocateFlowThreadContainingBlock() const {
// See if we have the thread cached because we're in the middle of layout.
if (LayoutView* view = View()) {
if (LayoutState* layout_state = view->GetLayoutState()) {
- // TODO(mstensho): We should really just return whatever
- // layoutState->flowThread() returns here, also if the value is nullptr.
if (LayoutFlowThread* flow_thread = layout_state->FlowThread())
return flow_thread;
}
@@ -1033,12 +1051,17 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
// In LayoutNG, if box has any OOF descendants, they are propagated to
// parent. Therefore, we must mark parent chain for layout.
- if (const NGLayoutResult* layouot_result =
+ if (const NGLayoutResult* layout_result =
layout_box->GetCachedLayoutResult()) {
- if (layouot_result->PhysicalFragment()
- .HasOutOfFlowPositionedDescendants())
+ if (layout_result->PhysicalFragment().HasOutOfFlowPositionedDescendants())
return false;
}
+
+ // A box which doesn't establish a new formating context can pass a whole
+ // bunch of state (floats, margins) to an arbitrary sibling, causing that
+ // sibling to position/size differently.
+ if (!layout_box->CreatesNewFormattingContext())
+ return false;
}
if (object->ShouldApplyLayoutContainment() &&
@@ -1062,7 +1085,7 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
if (object->IsTextControlIncludingNG())
return true;
- if (!object->HasNonVisibleOverflow())
+ if (!object->ShouldClipOverflowAlongBothAxis())
return false;
// Scrollbar parts can be removed during layout. Avoid the complexity of
@@ -1162,11 +1185,13 @@ void LayoutObject::MarkContainerChainForLayout(bool schedule_relayout,
// Note that if the last element we processed was blocked by a display lock,
// and the reason we're propagating a change is that a subtree needed layout
- // (ie self doesn't need layout), then we can return and stop the dirty bit
- // propagation. Note that it's not enough to check |object|, since the
- // element that is actually locked needs its child bits set properly, we
- // need to go one more iteration after that.
- if (!last->SelfNeedsLayout() && last->ChildLayoutBlockedByDisplayLock()) {
+ // (ie |last| doesn't need either self layout or positioned movement
+ // layout), then we can return and stop the dirty bit propagation. Note that
+ // it's not enough to check |object|, since the element that is actually
+ // locked needs its child bits set properly, we need to go one more
+ // iteration after that.
+ if (!last->SelfNeedsLayout() && !last->NeedsPositionedMovementLayout() &&
+ last->ChildLayoutBlockedByDisplayLock()) {
return;
}
@@ -1295,9 +1320,7 @@ bool LayoutObject::IsFontFallbackValid() const {
void LayoutObject::InvalidateSubtreeLayoutForFontUpdates() {
NOT_DESTROYED();
- if (!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled() ||
- !IsFontFallbackValid()) {
+ if (!IsFontFallbackValid()) {
SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kFontsChanged);
}
@@ -1337,13 +1360,25 @@ inline void LayoutObject::InvalidateContainerIntrinsicLogicalWidths() {
// In order to avoid pathological behavior when inlines are deeply nested, we
// do include them in the chain that we mark dirty (even though they're kind
// of irrelevant).
- LayoutObject* o = IsTableCell() ? ContainingBlock() : Container();
+ auto IntrinsicContainer = [](const LayoutObject* current) -> LayoutObject* {
+ // Table cell intrinsic logical-widths are queried directly from a <table>
+ // rather than from their parents (sections or rows). Skip these when
+ // invalidating.
+ if (current->IsTableCell()) {
+ if (current->IsTableCellLegacy())
+ return current->ContainingBlock();
+ else
+ return To<LayoutNGTableCell>(current)->Table();
+ }
+ return current->Container();
+ };
+
+ LayoutObject* o = IntrinsicContainer(this);
while (o &&
(!o->IntrinsicLogicalWidthsDirty() || NGKeepInvalidatingBeyond(o))) {
// Don't invalidate the outermost object of an unrooted subtree. That object
// will be invalidated when the subtree is added to the document.
- LayoutObject* container =
- o->IsTableCell() ? o->ContainingBlock() : o->Container();
+ LayoutObject* container = IntrinsicContainer(o);
if (!container && !IsA<LayoutView>(o))
break;
@@ -1393,6 +1428,16 @@ const LayoutBlock* LayoutObject::InclusiveContainingBlock() const {
return layout_block ? layout_block : ContainingBlock();
}
+const LayoutBlock* LayoutObject::EnclosingScrollportBox() const {
+ NOT_DESTROYED();
+ const LayoutBlock* ancestor = ContainingBlock();
+ for (; ancestor; ancestor = ancestor->ContainingBlock()) {
+ if (ancestor->IsScrollContainer())
+ return ancestor;
+ }
+ return ancestor;
+}
+
LayoutBlock* LayoutObject::ContainingBlock(AncestorSkipInfo* skip_info) const {
NOT_DESTROYED();
if (!IsTextOrSVGChild()) {
@@ -2097,6 +2142,31 @@ const ComputedStyle& LayoutObject::SlowEffectiveStyle(
return StyleRef();
}
+const ComputedStyle* LayoutObject::SlowStyleForContinuationOutline() const {
+ NOT_DESTROYED();
+ // Fail fast using bitfields is done in |StyleForContinuationOutline|.
+ DCHECK(IsAnonymous() && !IsInline());
+ const auto* block_flow = DynamicTo<LayoutBlockFlow>(this);
+ if (!block_flow)
+ return nullptr;
+
+ // Check ancestors of the continuation in case nested inline boxes; e.g.
+ // <span style="outline: auto">
+ // <span>
+ // <div>block</div>
+ // </span>
+ // </span>
+ for (const LayoutObject* continuation = block_flow->Continuation();
+ UNLIKELY(continuation && continuation->IsLayoutInline());
+ continuation = continuation->Parent()) {
+ const ComputedStyle& style = continuation->StyleRef();
+ if (style.OutlineStyleIsAuto() &&
+ NGOutlineUtils::HasPaintedOutline(style, continuation->GetNode()))
+ return &style;
+ }
+ return nullptr;
+}
+
// Called when an object that was floating or positioned becomes a normal flow
// object again. We have to make sure the layout tree updates as needed to
// accommodate the new normal flow object.
@@ -2141,8 +2211,8 @@ StyleDifference LayoutObject::AdjustStyleDifference(
// underlines). MathML elements are not skipped either as some of them
// do special painting (e.g. fraction bar).
(IsText() && !IsBR() && To<LayoutText>(this)->HasInlineFragments()) ||
- (IsSVG() && StyleRef().SvgStyle().IsFillColorCurrentColor()) ||
- (IsSVG() && StyleRef().SvgStyle().IsStrokeColorCurrentColor()) ||
+ (IsSVG() && StyleRef().IsFillColorCurrentColor()) ||
+ (IsSVG() && StyleRef().IsStrokeColorCurrentColor()) ||
IsListMarkerForNormalContent() || IsDetailsMarker() || IsMathML())
diff.SetNeedsPaintInvalidation();
}
@@ -2333,9 +2403,8 @@ void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
}
if (diff.NeedsRecomputeVisualOverflow()) {
- if (!(IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) &&
- !IsLayoutNGObject() && !IsLayoutBlock() && !NeedsLayout()) {
+ if (!IsInLayoutNGInlineFormattingContext() && !IsLayoutNGObject() &&
+ !IsLayoutBlock() && !NeedsLayout()) {
// TODO(crbug.com/1128199): This is still needed because
// RecalcVisualOverflow() does not actually compute the visual overflow
// for inline elements (legacy layout). However in LayoutNG
@@ -2344,8 +2413,7 @@ void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kStyleChange);
} else {
- if (IsInLayoutNGInlineFormattingContext() && !NeedsLayout() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (IsInLayoutNGInlineFormattingContext() && !NeedsLayout()) {
if (auto* text = DynamicTo<LayoutText>(this))
text->InvalidateVisualOverflow();
}
@@ -2536,6 +2604,8 @@ void LayoutObject::StyleWillChange(StyleDifference diff,
// tree.
if (PaintLayer* layer = EnclosingLayer())
layer->DirtyVisibleContentStatus();
+ if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
+ cache->ChildrenChanged(this);
}
if (IsFloating() &&
@@ -2634,7 +2704,7 @@ void LayoutObject::SetScrollAnchorDisablingStyleChangedOnAncestor() {
Element* viewport_defining_element = GetDocument().ViewportDefiningElement();
while (object) {
auto* block = DynamicTo<LayoutBlock>(object);
- if (block && (block->HasNonVisibleOverflow() ||
+ if (block && (block->IsScrollContainer() ||
block->GetNode() == viewport_defining_element)) {
block->SetScrollAnchorDisablingStyleChanged(true);
return;
@@ -2952,7 +3022,7 @@ void LayoutObject::CheckCounterChanges(const ComputedStyle* old_style,
return;
}
LayoutCounter::LayoutObjectStyleChanged(*this, old_style, *new_style);
- View()->SetNeedsCounterUpdate();
+ View()->SetNeedsMarkerOrCounterUpdate();
}
PhysicalRect LayoutObject::ViewRect() const {
@@ -2998,8 +3068,22 @@ void LayoutObject::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
if (!container)
return;
+ bool should_ignore_scroll_offset = false;
+ if (mode & kIgnoreScrollOffset) {
+ should_ignore_scroll_offset = true;
+ } else if (mode & kIgnoreScrollOffsetOfAncestor) {
+ if (container == ancestor) {
+ should_ignore_scroll_offset = true;
+ } else if (!ancestor && container == View() &&
+ (!(mode & kTraverseDocumentBoundaries) ||
+ !GetFrame()->OwnerLayoutObject())) {
+ should_ignore_scroll_offset = true;
+ }
+ }
+
PhysicalOffset container_offset =
- OffsetFromContainer(container, mode & kIgnoreScrollOffset);
+ OffsetFromContainer(container, should_ignore_scroll_offset);
+
// TODO(smcgruer): This is inefficient. Instead we should avoid including
// offsetForInFlowPosition in offsetFromContainer when ignoring sticky.
if (mode & kIgnoreStickyOffset && IsStickyPositioned()) {
@@ -3185,14 +3269,15 @@ bool LayoutObject::LocalToAncestorRectFastPath(
MapCoordinatesFlags mode,
PhysicalRect& result) const {
NOT_DESTROYED();
- if (!(mode & kUseGeometryMapperMode))
+ MapCoordinatesFlags supported_mode =
+ kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor;
+ if (mode != supported_mode)
return false;
- // No other modes are supported.
- if (mode & (~kUseGeometryMapperMode))
+
+ if (ancestor && ancestor != View())
return false;
- if (!ancestor)
- ancestor = View();
+ ancestor = View();
if (ancestor == this)
return true;
@@ -3217,7 +3302,7 @@ bool LayoutObject::LocalToAncestorRectFastPath(
if (property_container != ancestor) {
GeometryMapper::SourceToDestinationRect(
container_properties.Transform(),
- ancestor->FirstFragment().LocalBorderBoxProperties().Transform(),
+ ancestor->FirstFragment().ContentsProperties().Transform(),
mapping_rect);
}
mapping_rect.Move(-FloatSize(ancestor->FirstFragment().PaintOffset()));
@@ -3385,10 +3470,11 @@ RespectImageOrientationEnum LayoutObject::ShouldRespectImageOrientation(
LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
NOT_DESTROYED();
- // TODO(mstensho): Get rid of this. Nobody should call this method with those
- // flags already set.
+
+#if DCHECK_IS_ON()
if (skip_info)
- skip_info->ResetOutput();
+ skip_info->AssertClean();
+#endif
if (IsTextOrSVGChild())
return Parent();
@@ -3420,13 +3506,6 @@ LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
return Parent();
}
-inline LayoutObject* LayoutObject::ParentCrossingFrames() const {
- NOT_DESTROYED();
- if (IsA<LayoutView>(this))
- return GetFrame()->OwnerLayoutObject();
- return Parent();
-}
-
inline void LayoutObject::ClearLayoutRootIfNeeded() const {
NOT_DESTROYED();
if (LocalFrameView* view = GetFrameView()) {
@@ -3448,17 +3527,8 @@ void LayoutObject::WillBeDestroyed() {
frame->GetPage()->GetAutoscrollController().StopAutoscrollIfNeeded(this);
}
- // For accessibility management, notify the parent of the imminent change to
- // its child set.
- // We do it now, before remove(), while the parent pointer is still available.
- if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
- cache->ChildrenChanged(Parent());
-
Remove();
- // The remove() call above may invoke axObjectCache()->childrenChanged() on
- // the parent, which may require the AX layout object for this layoutObject.
- // So we remove the AX layout object now, after the layoutObject is removed.
if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
cache->Remove(this);
@@ -3530,7 +3600,7 @@ void LayoutObject::InsertedIntoTree() {
// |FirstInlineFragment()| should be cleared. |LayoutObjectChildList| does
// this, just check here for all new objects in the tree.
- DCHECK_EQ(FirstInlineFragment(), nullptr);
+ DCHECK(!HasInlineFragments());
if (Parent()->ChildrenInline())
Parent()->DirtyLinesFromChangedChild(this);
@@ -3629,19 +3699,25 @@ void LayoutObject::SetNeedsPaintPropertyUpdatePreservingCachedRects() {
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
bitfields_.SetNeedsPaintPropertyUpdate(true);
- for (auto* ancestor = ParentCrossingFrames();
+ if (Parent())
+ Parent()->SetDescendantNeedsPaintPropertyUpdate();
+}
+
+void LayoutObject::SetDescendantNeedsPaintPropertyUpdate() {
+ NOT_DESTROYED();
+ for (auto* ancestor = this;
ancestor && !ancestor->DescendantNeedsPaintPropertyUpdate();
- ancestor = ancestor->ParentCrossingFrames()) {
+ ancestor = ancestor->Parent()) {
ancestor->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true);
}
}
-void LayoutObject::SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling() {
+void LayoutObject::ForceAllAncestorsNeedPaintPropertyUpdate() {
NOT_DESTROYED();
- LayoutObject* ancestor = ParentCrossingFrames();
+ LayoutObject* ancestor = Parent();
while (ancestor) {
ancestor->SetNeedsPaintPropertyUpdate();
- ancestor = ancestor->ParentCrossingFrames();
+ ancestor = ancestor->Parent();
}
}
@@ -3705,10 +3781,10 @@ void LayoutObject::DestroyAndCleanupAnonymousWrappers() {
}
LayoutObject* destroy_root = this;
- for (LayoutObject *destroy_root_parent = destroy_root->Parent();
+ for (LayoutObject* destroy_root_parent = destroy_root->Parent();
destroy_root_parent && destroy_root_parent->IsAnonymous();
destroy_root = destroy_root_parent,
- destroy_root_parent = destroy_root_parent->Parent()) {
+ destroy_root_parent = destroy_root_parent->Parent()) {
// Anonymous block continuations are tracked and destroyed elsewhere (see
// the bottom of LayoutBlockFlow::RemoveChild)
auto* destroy_root_parent_block =
@@ -3768,7 +3844,11 @@ void LayoutObject::DeleteThis() {
PositionWithAffinity LayoutObject::PositionForPoint(
const PhysicalOffset&) const {
NOT_DESTROYED();
- return CreatePositionWithAffinity(CaretMinOffset());
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsLayoutNGObject() || GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
+ return CreatePositionWithAffinity(0);
}
CompositingState LayoutObject::GetCompositingState() const {
@@ -3888,7 +3968,7 @@ const ComputedStyle* LayoutObject::FirstLineStyleWithoutFallback() const {
// https://github.com/w3c/csswg-drafts/issues/4506
if (IsMarkerContent())
return nullptr;
- if (IsBeforeOrAfterContent() || IsText()) {
+ if (IsText()) {
if (!Parent())
return nullptr;
return Parent()->FirstLineStyleWithoutFallback();
@@ -3966,10 +4046,11 @@ scoped_refptr<ComputedStyle> LayoutObject::GetUncachedPseudoElementStyle(
Element* element = Traversal<Element>::FirstAncestorOrSelf(*GetNode());
if (!element)
return nullptr;
- if (element->IsPseudoElement())
+ if (element->IsPseudoElement() &&
+ request.pseudo_id != kPseudoIdFirstLineInherited)
return nullptr;
- return element->StyleForPseudoElement(request, parent_style);
+ return element->UncachedStyleForPseudoElement(request, parent_style);
}
void LayoutObject::AddAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) {
@@ -4035,20 +4116,6 @@ bool LayoutObject::IsOutsideListMarker() const {
IsOutsideListMarkerForCustomContent();
}
-int LayoutObject::CaretMinOffset() const {
- NOT_DESTROYED();
- return 0;
-}
-
-int LayoutObject::CaretMaxOffset() const {
- NOT_DESTROYED();
- if (IsAtomicInlineLevel())
- return GetNode() ? std::max(1U, GetNode()->CountChildren()) : 1;
- if (IsHR())
- return 1;
- return 0;
-}
-
bool LayoutObject::IsInert() const {
NOT_DESTROYED();
const LayoutObject* layout_object = this;
@@ -4146,27 +4213,15 @@ PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
NOT_DESTROYED();
// If this is a non-anonymous layoutObject in an editable area, then it's
// simple.
- if (Node* node = NonPseudoNode()) {
- if (!HasEditableStyle(*node)) {
- // If it can be found, we prefer a visually equivalent position that is
- // editable.
- // TODO(layout-dev): Once we fix callers of |CreatePositionWithAffinity()|
- // we should use |Position| constructor. See http://crbug.com/827923
- const Position position =
- Position::CreateWithoutValidationDeprecated(*node, offset);
- Position candidate =
- MostForwardCaretPosition(position, kCanCrossEditingBoundary);
- if (HasEditableStyle(*candidate.AnchorNode()))
- return PositionWithAffinity(candidate, affinity);
- candidate = MostBackwardCaretPosition(position, kCanCrossEditingBoundary);
- if (HasEditableStyle(*candidate.AnchorNode()))
- return PositionWithAffinity(candidate, affinity);
- }
- // FIXME: Eliminate legacy editing positions
- return PositionWithAffinity(Position::EditingPositionOf(node, offset),
- affinity);
- }
+ Node* const node = NonPseudoNode();
+ if (!node)
+ return FindPosition();
+ return AdjustForEditingBoundary(
+ PositionWithAffinity(Position(node, offset), affinity));
+}
+PositionWithAffinity LayoutObject::FindPosition() const {
+ NOT_DESTROYED();
// We don't want to cross the boundary between editable and non-editable
// regions of the document, but that is either impossible or at least
// extremely unlikely in any normal case because we stop as soon as we
@@ -4204,20 +4259,38 @@ PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
return PositionWithAffinity();
}
-PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
- int offset) const {
+PositionWithAffinity LayoutObject::FirstPositionInOrBeforeThis() const {
NOT_DESTROYED();
- return CreatePositionWithAffinity(offset, TextAffinity::kDownstream);
+ if (Node* node = NonPseudoNode())
+ return AdjustForEditingBoundary(FirstPositionInOrBeforeNode(*node));
+ return FindPosition();
}
-PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
- const Position& position) const {
+PositionWithAffinity LayoutObject::LastPositionInOrAfterThis() const {
NOT_DESTROYED();
- if (position.IsNotNull())
- return PositionWithAffinity(position);
+ if (Node* node = NonPseudoNode())
+ return AdjustForEditingBoundary(LastPositionInOrAfterNode(*node));
+ return FindPosition();
+}
- DCHECK(!NonPseudoNode());
- return CreatePositionWithAffinity(0);
+PositionWithAffinity LayoutObject::PositionAfterThis() const {
+ NOT_DESTROYED();
+ if (Node* node = NonPseudoNode())
+ return AdjustForEditingBoundary(Position::AfterNode(*node));
+ return FindPosition();
+}
+
+PositionWithAffinity LayoutObject::PositionBeforeThis() const {
+ NOT_DESTROYED();
+ if (Node* node = NonPseudoNode())
+ return AdjustForEditingBoundary(Position::BeforeNode(*node));
+ return FindPosition();
+}
+
+PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
+ int offset) const {
+ NOT_DESTROYED();
+ return CreatePositionWithAffinity(offset, TextAffinity::kDownstream);
}
CursorDirective LayoutObject::GetCursor(const PhysicalOffset&,
@@ -4239,10 +4312,9 @@ void LayoutObject::SetNeedsBoundariesUpdate() {
NOT_DESTROYED();
if (IsSVGChild()) {
// The boundaries affect mask clip.
- auto* resources = SVGResourcesCache::CachedResourcesForLayoutObject(*this);
- if (resources && resources->Masker())
+ if (StyleRef().MaskerResource())
SetNeedsPaintPropertyUpdate();
- if (resources && resources->Clipper())
+ if (StyleRef().HasClipPath())
InvalidateClipPathCache();
}
if (LayoutObject* layout_object = Parent())
@@ -4277,19 +4349,6 @@ bool LayoutObject::IsRelayoutBoundary() const {
return ObjectIsRelayoutBoundary(this);
}
-inline void LayoutObject::SetShouldCheckGeometryForPaintInvalidation() {
- NOT_DESTROYED();
- DCHECK(ShouldCheckForPaintInvalidation());
- bitfields_.SetShouldCheckGeometryForPaintInvalidation(true);
- for (auto* ancestor = ParentCrossingFrames();
- ancestor &&
- !ancestor->DescendantShouldCheckGeometryForPaintInvalidation();
- ancestor = ancestor->ParentCrossingFrames()) {
- ancestor->bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(
- true);
- }
-}
-
void LayoutObject::SetShouldInvalidateSelection() {
NOT_DESTROYED();
bitfields_.SetShouldInvalidateSelection(true);
@@ -4299,8 +4358,8 @@ void LayoutObject::SetShouldInvalidateSelection() {
void LayoutObject::SetShouldDoFullPaintInvalidation(
PaintInvalidationReason reason) {
NOT_DESTROYED();
+ SetShouldCheckForPaintInvalidation();
SetShouldDoFullPaintInvalidationWithoutGeometryChange(reason);
- SetShouldCheckGeometryForPaintInvalidation();
}
static PaintInvalidationReason DocumentLifecycleBasedPaintInvalidationReason(
@@ -4340,8 +4399,22 @@ void LayoutObject::
void LayoutObject::SetShouldCheckForPaintInvalidation() {
NOT_DESTROYED();
- SetShouldCheckForPaintInvalidationWithoutGeometryChange();
- SetShouldCheckGeometryForPaintInvalidation();
+ if (ShouldCheckGeometryForPaintInvalidation()) {
+ DCHECK(ShouldCheckForPaintInvalidation());
+ return;
+ }
+ GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
+
+ bitfields_.SetShouldCheckForPaintInvalidation(true);
+ bitfields_.SetShouldCheckGeometryForPaintInvalidation(true);
+ for (LayoutObject* ancestor = Parent();
+ ancestor &&
+ !ancestor->DescendantShouldCheckGeometryForPaintInvalidation();
+ ancestor = ancestor->Parent()) {
+ ancestor->bitfields_.SetShouldCheckForPaintInvalidation(true);
+ ancestor->bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(
+ true);
+ }
}
void LayoutObject::SetShouldCheckForPaintInvalidationWithoutGeometryChange() {
@@ -4351,10 +4424,10 @@ void LayoutObject::SetShouldCheckForPaintInvalidationWithoutGeometryChange() {
GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
bitfields_.SetShouldCheckForPaintInvalidation(true);
- for (LayoutObject* parent = ParentCrossingFrames();
- parent && !parent->ShouldCheckForPaintInvalidation();
- parent = parent->ParentCrossingFrames()) {
- parent->bitfields_.SetShouldCheckForPaintInvalidation(true);
+ for (LayoutObject* ancestor = Parent();
+ ancestor && !ancestor->ShouldCheckForPaintInvalidation();
+ ancestor = ancestor->Parent()) {
+ ancestor->bitfields_.SetShouldCheckForPaintInvalidation(true);
}
}
@@ -4468,7 +4541,8 @@ void LayoutObject::ClearPaintFlags() {
}
bool LayoutObject::IsAllowedToModifyLayoutTreeStructure(Document& document) {
- return document.Lifecycle().StateAllowsLayoutTreeMutations();
+ return document.Lifecycle().StateAllowsLayoutTreeMutations() ||
+ document.GetStyleEngine().InContainerQueryStyleRecalc();
}
void LayoutObject::SetSubtreeShouldDoFullPaintInvalidation(
@@ -4536,13 +4610,18 @@ void LayoutObject::MarkEffectiveAllowedTouchActionChanged() {
return;
}
- LayoutObject* obj = ParentCrossingFrames();
+ if (Parent())
+ Parent()->MarkDescendantEffectiveAllowedTouchActionChanged();
+}
+
+void LayoutObject::MarkDescendantEffectiveAllowedTouchActionChanged() {
+ LayoutObject* obj = this;
while (obj && !obj->DescendantEffectiveAllowedTouchActionChanged()) {
obj->bitfields_.SetDescendantEffectiveAllowedTouchActionChanged(true);
if (obj->ChildPrePaintBlockedByDisplayLock())
break;
- obj = obj->ParentCrossingFrames();
+ obj = obj->Parent();
}
}
@@ -4557,13 +4636,18 @@ void LayoutObject::MarkBlockingWheelEventHandlerChanged() {
return;
}
- LayoutObject* obj = ParentCrossingFrames();
+ if (Parent())
+ Parent()->MarkDescendantBlockingWheelEventHandlerChanged();
+}
+
+void LayoutObject::MarkDescendantBlockingWheelEventHandlerChanged() {
+ LayoutObject* obj = this;
while (obj && !obj->DescendantBlockingWheelEventHandlerChanged()) {
obj->bitfields_.SetDescendantBlockingWheelEventHandlerChanged(true);
if (obj->ChildPrePaintBlockedByDisplayLock())
break;
- obj = obj->ParentCrossingFrames();
+ obj = obj->Parent();
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.h b/chromium/third_party/blink/renderer/core/layout/layout_object.h
index 23a1003cb3c..ab615ff0c03 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.h
@@ -87,8 +87,6 @@ class LayoutNGTableSectionInterface;
class LayoutNGTableCellInterface;
class LayoutView;
class LocalFrameView;
-class NGPaintFragment;
-class NGPhysicalBoxFragment;
class PaintLayer;
class PseudoElementStyleRequest;
struct PaintInfo;
@@ -151,7 +149,7 @@ const int kShowTreeCharacterOffset = 39;
// exclude certain functions like ~SVGImage() from this rule. This is allowed
// when a Persistent is guaranteeing to keep the LayoutObject alive for that GC
// cycle.
-class AllowDestroyingLayoutObjectInFinalizerScope {
+class CORE_EXPORT AllowDestroyingLayoutObjectInFinalizerScope {
STACK_ALLOCATED();
public:
@@ -304,11 +302,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// Should be added at the beginning of every method to ensure we are not
// accessing a LayoutObject after the Desroy() call.
#if DCHECK_IS_ON()
-// TODO(keishi): Implement once LayoutObject is made GarbageCollected.
-#define NOT_DESTROYED() ((void)0)
+ ALWAYS_INLINE void CheckIsNotDestroyed() const { DCHECK(!is_destroyed_); }
#else
-#define NOT_DESTROYED() ((void)0)
+ ALWAYS_INLINE void CheckIsNotDestroyed() const {}
#endif
+#define NOT_DESTROYED() CheckIsNotDestroyed()
// Returns the name of the layout object.
virtual const char* GetName() const = 0;
@@ -336,9 +334,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// Hide DisplayItemClient's methods whose names are too generic for
// LayoutObjects. Should use LayoutObject's methods instead.
+ using DisplayItemClient::GetPaintInvalidationReason;
using DisplayItemClient::Invalidate;
using DisplayItemClient::IsValid;
- using DisplayItemClient::GetPaintInvalidationReason;
DOMNodeId OwnerNodeId() const final;
@@ -454,13 +452,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// LayoutNG context.
LayoutBlockFlow* ContainingNGBlockFlow() const;
- // Returns |NGPhysicalBoxFragment| for |ContainingNGBlockFlow()| or nullptr
- // otherwise.
- //
- // TODO(crbug.com/1061423): Remove this method. We shouldn't assume
- // that there's only one fragment.
- const NGPhysicalBoxFragment* ContainingBlockFlowFragment() const;
-
// Function to return our enclosing flow thread if we are contained inside
// one. This function follows the containing block chain.
LayoutFlowThread* FlowThreadContainingBlock() const {
@@ -607,12 +598,25 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return ShouldApplyLayoutContainment(StyleRef());
}
- inline bool ShouldApplySizeContainment() const {
+ inline bool IsEligibleForSizeContainment() const {
NOT_DESTROYED();
- return StyleRef().ContainsSize() &&
- (!IsInline() || IsAtomicInlineLevel()) && !IsRubyText() &&
+ return (!IsInline() || IsAtomicInlineLevel()) && !IsRubyText() &&
(!IsTablePart() || IsTableCaption()) && !IsTable();
}
+ inline bool ShouldApplySizeContainment() const {
+ NOT_DESTROYED();
+ return StyleRef().ContainsSize() && IsEligibleForSizeContainment();
+ }
+ inline bool ShouldApplyInlineSizeContainment() const {
+ NOT_DESTROYED();
+ return (StyleRef().ContainsInlineSize() || StyleRef().ContainsSize()) &&
+ IsEligibleForSizeContainment();
+ }
+ inline bool ShouldApplyBlockSizeContainment() const {
+ NOT_DESTROYED();
+ return (StyleRef().ContainsBlockSize() || StyleRef().ContainsSize()) &&
+ IsEligibleForSizeContainment();
+ }
inline bool ShouldApplyStyleContainment() const {
NOT_DESTROYED();
return StyleRef().ContainsStyle();
@@ -626,6 +630,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return ShouldApplyPaintContainment() && ShouldApplyLayoutContainment() &&
ShouldApplySizeContainment();
}
+ inline bool IsContainerForContainerQueries() const {
+ NOT_DESTROYED();
+ return ShouldApplyLayoutContainment() &&
+ (ShouldApplyInlineSizeContainment() ||
+ ShouldApplyBlockSizeContainment());
+ }
inline bool IsStackingContext() const {
NOT_DESTROYED();
@@ -842,10 +852,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
return IsOfType(kLayoutObjectTableCol);
}
- bool IsLayoutNGTableCol() const {
- NOT_DESTROYED();
- return IsOfType(kLayoutObjectNGTableCol);
- }
bool IsListItem() const {
NOT_DESTROYED();
return IsOfType(kLayoutObjectListItem);
@@ -898,6 +904,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
return IsOfType(kLayoutObjectGrid);
}
+ bool IsLayoutGridIncludingNG() const {
+ NOT_DESTROYED();
+ return IsOfType(kLayoutObjectGrid) || IsOfType(kLayoutObjectNGGrid);
+ }
bool IsLayoutIFrame() const {
NOT_DESTROYED();
return IsOfType(kLayoutObjectIFrame);
@@ -1259,10 +1269,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// SVGGraphicsElement::getBBox().
// NOTE: Markers are not specifically ignored here by SVG 1.1 spec, but we
// ignore them since stroke-width is ignored (and marker size can depend on
- // stroke-width). objectBoundingBox is returned local coordinates.
+ // stroke-width). objectBoundingBox is returned in local coordinates and
+ // always unzoomed.
// The name objectBoundingBox is taken from the SVG 1.1 spec.
virtual FloatRect ObjectBoundingBox() const;
- virtual FloatRect StrokeBoundingBox() const;
// Returns the smallest rectangle enclosing all of the painted content
// respecting clipping, masking, filters, opacity, stroke-width and markers.
@@ -1272,6 +1282,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// coordinate space is the viewport space.
virtual FloatRect VisualRectInLocalSVGCoordinates() const;
+ // Like VisualRectInLocalSVGCoordinates() but does not include visual overflow
+ // (name is misleading). May be zoomed (currently only for <foreignObject>,
+ // which represents this via its LocalToSVGParentTransform()).
+ virtual FloatRect StrokeBoundingBox() const;
+
// This returns the transform applying to the local SVG coordinate space,
// which combines the CSS transform properties and animation motion transform.
// See SVGElement::calculateTransform().
@@ -1325,6 +1340,15 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
return nullptr;
}
+ // Returns the |ComputedStyle| to use for painting outlines. When |this| is
+ // a block in a continuation-chain, it may need to paint outlines if its
+ // ancestor inline boxes in the DOM tree has outlines.
+ const ComputedStyle* StyleForContinuationOutline() const {
+ NOT_DESTROYED();
+ if (UNLIKELY(IsAnonymous() && !IsInline()))
+ return SlowStyleForContinuationOutline();
+ return nullptr;
+ }
bool IsFloating() const {
NOT_DESTROYED();
@@ -1611,7 +1635,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
// Not returning StyleRef().HasTransformRelatedProperty() because some objects
- // ignore the transform-related styles (e.g. LayoutInline, LayoutSVGBlock).
+ // ignore the transform-related styles (e.g., LayoutInline).
bool HasTransformRelatedProperty() const {
NOT_DESTROYED();
return bitfields_.HasTransformRelatedProperty();
@@ -1626,7 +1650,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
bool HasClipPath() const {
NOT_DESTROYED();
- return StyleRef().ClipPath();
+ return StyleRef().HasClipPath();
}
bool HasHiddenBackface() const {
NOT_DESTROYED();
@@ -1700,6 +1724,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsRenderedLegendInternal() const;
+ // Returns true if this object represents ::marker for the first SUMMARY
+ // child of a DETAILS, and list-style-type is disclosure-*.
+ bool IsListMarkerForSummary() const;
+
// The pseudo element style can be cached or uncached. Use the cached method
// if the pseudo element doesn't respect any pseudo classes (and therefore
// has no concept of changing state). The cached pseudo style always inherits
@@ -1798,12 +1826,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
filter_skipped_ = true;
}
- // TODO(mstensho): Get rid of this. It's just a temporary thing to retain
- // old behavior in LayoutObject::container().
- void ResetOutput() {
- ancestor_skipped_ = false;
- filter_skipped_ = false;
+#if DCHECK_IS_ON()
+ void AssertClean() {
+ DCHECK(!ancestor_skipped_);
+ DCHECK(!filter_skipped_);
}
+#endif
bool AncestorSkipped() const { return ancestor_skipped_; }
bool FilterSkipped() const {
@@ -1964,13 +1992,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// LayoutInline that's contained by a legacy LayoutBlockFlow).
inline bool CanTraversePhysicalFragments() const;
- // Returns the associated |NGPaintFragment|. When this is not a |nullptr|,
- // this is the root of an inline formatting context, laid out by LayoutNG.
- virtual const NGPaintFragment* PaintFragment() const {
- NOT_DESTROYED();
- return nullptr;
- }
-
// Return true if |this| produces one or more inline fragments, including
// whitespace-only text fragments.
virtual bool HasInlineFragments() const {
@@ -1983,11 +2004,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// layout-clean. crbug.com/963103
bool IsFirstInlineFragmentSafe() const;
void SetIsInLayoutNGInlineFormattingContext(bool);
- virtual NGPaintFragment* FirstInlineFragment() const {
- NOT_DESTROYED();
- return nullptr;
- }
- virtual void SetFirstInlineFragment(NGPaintFragment*) { NOT_DESTROYED(); }
virtual wtf_size_t FirstInlineFragmentItemIndex() const {
NOT_DESTROYED();
return 0u;
@@ -2168,7 +2184,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
PositionWithAffinity CreatePositionWithAffinity(int offset,
TextAffinity) const;
PositionWithAffinity CreatePositionWithAffinity(int offset) const;
- PositionWithAffinity CreatePositionWithAffinity(const Position&) const;
+ PositionWithAffinity FindPosition() const;
+ PositionWithAffinity FirstPositionInOrBeforeThis() const;
+ PositionWithAffinity LastPositionInOrAfterThis() const;
+ PositionWithAffinity PositionAfterThis() const;
+ PositionWithAffinity PositionBeforeThis() const;
virtual void DirtyLinesFromChangedChild(
LayoutObject*,
@@ -2232,6 +2252,8 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
const LayoutBlock* InclusiveContainingBlock() const;
+ const LayoutBlock* EnclosingScrollportBox() const;
+
bool CanContainAbsolutePositionObjects() const {
NOT_DESTROYED();
return style_->CanContainAbsolutePositionObjects() ||
@@ -2614,13 +2636,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsSelectable() const;
/**
- * Returns the local coordinates of the caret within this layout object.
- * @param caretOffset zero-based offset determining position within the
+ * Returns the local coordinates of the caret within this layout object.
+ * @param caretOffset zero-based offset determining position within the
* layout object.
- * @param extraWidthToEndOfLine optional out arg to give extra width to end
+ * @param extraWidthToEndOfLine optional out arg to give extra width to end
* of line -
- * useful for character range rect computations
- */
+ * useful for character range rect computations
+ */
virtual LayoutRect LocalCaretRect(
const InlineBox*,
int caret_offset,
@@ -2717,9 +2739,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return false;
}
- virtual int CaretMinOffset() const;
- virtual int CaretMaxOffset() const;
-
// ImageResourceObserver override.
void ImageChanged(ImageResourceContent*, CanDeferInvalidation) final;
void ImageChanged(WrappedImagePtr, CanDeferInvalidation) override {
@@ -2799,17 +2818,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
}
- // For history and compatibility reasons, we draw outline:auto (for focus
- // rings) and normal style outline differently.
- // Focus rings enclose block visual overflows (of line boxes and descendants),
- // while normal outlines don't.
- NGOutlineType OutlineRectsShouldIncludeBlockVisualOverflow() const {
- NOT_DESTROYED();
- return StyleRef().OutlineStyleIsAuto()
- ? NGOutlineType::kIncludeBlockVisualOverflow
- : NGOutlineType::kDontIncludeBlockVisualOverflow;
- }
-
// Only public for LayoutNG.
void SetContainsInlineWithOutlineAndContinuation(bool b) {
NOT_DESTROYED();
@@ -2868,7 +2876,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
return bitfields_.ShouldCheckForPaintInvalidation();
}
+ // Sets both ShouldCheckForPaintInvalidation() and
+ // ShouldCheckGeometryForPaintInvalidation(). Though the setter and the getter
+ // are asymmetric, this prevents callers from accidentally missing the
+ // geometry checking flag.
void SetShouldCheckForPaintInvalidation();
+ // Sets ShouldCheckForPaintInvalidation() only. PaintInvalidator won't require
+ // paint property tree update or other geometry related updates.
void SetShouldCheckForPaintInvalidationWithoutGeometryChange();
bool SubtreeShouldCheckForPaintInvalidation() const {
@@ -2995,6 +3009,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// mark all ancestors as having a descendant that changed. This will cause a
// PrePaint tree walk to update effective allowed touch action.
void MarkEffectiveAllowedTouchActionChanged();
+ void MarkDescendantEffectiveAllowedTouchActionChanged();
bool EffectiveAllowedTouchActionChanged() const {
NOT_DESTROYED();
return bitfields_.EffectiveAllowedTouchActionChanged();
@@ -3017,6 +3032,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// mark all ancestors as having a descendant that changed. This will cause a
// PrePaint tree walk to update blocking wheel event handler state.
void MarkBlockingWheelEventHandlerChanged();
+ void MarkDescendantBlockingWheelEventHandlerChanged();
bool BlockingWheelEventHandlerChanged() const {
// TODO(https://crbug.com/841364): This block is optimized to avoid costly
// checks for kWheelEventRegions. It will be simplified once
@@ -3121,6 +3137,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
layout_object_.SetShouldSkipNextLayoutShiftTracking(b);
}
+ void SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(bool b) {
+ layout_object_
+ .SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(b);
+ }
+
FragmentData& FirstFragment() { return layout_object_.fragment_; }
void EnsureId() { layout_object_.fragment_.EnsureId(); }
@@ -3161,6 +3182,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// descendant needing a paint property update too.
void SetNeedsPaintPropertyUpdate();
void SetNeedsPaintPropertyUpdatePreservingCachedRects();
+ void SetDescendantNeedsPaintPropertyUpdate();
bool NeedsPaintPropertyUpdate() const {
NOT_DESTROYED();
return bitfields_.NeedsPaintPropertyUpdate();
@@ -3180,9 +3202,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
NOT_DESTROYED();
return bitfields_.DescendantNeedsPaintPropertyUpdate();
}
- // Main thread scrolling reasons require fully updating paint propeties of all
- // ancestors (see: ScrollPaintPropertyNode.h).
- void SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
+ // Called when some change needs paint property update of all ancestors (not
+ // crossing frame boundaries).
+ void ForceAllAncestorsNeedPaintPropertyUpdate();
void SetIsScrollAnchorObject() {
NOT_DESTROYED();
@@ -3316,6 +3338,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetIsLayoutNGObjectForListMarkerImage(b);
}
+ bool IsLayoutNGObjectForCanvasFormattedText() const {
+ return bitfields_.IsLayoutNGObjectForCanvasFormattedText();
+ }
+ void SetIsLayoutNGObjectForCanvasFormattedText(bool b) {
+ bitfields_.SetIsLayoutNGObjectForCanvasFormattedText(b);
+ }
+
bool PreviousVisibilityVisible() const {
NOT_DESTROYED();
return bitfields_.PreviousVisibilityVisible();
@@ -3339,6 +3368,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetShouldSkipNextLayoutShiftTracking(b);
}
+ bool ShouldAssumePaintOffsetTranslationForLayoutShiftTracking() const {
+ return bitfields_
+ .ShouldAssumePaintOffsetTranslationForLayoutShiftTracking();
+ }
+ void SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(bool b) {
+ bitfields_.SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(b);
+ }
+
protected:
// Identifiers for each of LayoutObject subclasses.
// The identifier name for blink::LayoutFoo should be kLayoutObjectFoo.
@@ -3377,7 +3414,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
kLayoutObjectNGMixin,
kLayoutObjectNGOutsideListMarker,
kLayoutObjectNGProgress,
- kLayoutObjectNGTableCol,
kLayoutObjectNGText,
kLayoutObjectNGTextControlMultiLine,
kLayoutObjectNGTextControlSingleLine,
@@ -3605,8 +3641,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
inline void MarkContainerChainForOverflowRecalcIfNeeded(
bool mark_container_chain_layout_overflow_recalc);
- inline void SetShouldCheckGeometryForPaintInvalidation();
-
inline void InvalidateContainerIntrinsicLogicalWidths();
const LayoutBoxModelObject* EnclosingDirectlyCompositableContainer() const;
@@ -3614,6 +3648,8 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
LayoutFlowThread* LocateFlowThreadContainingBlock() const;
void RemoveFromLayoutFlowThreadRecursive(LayoutFlowThread*);
+ const ComputedStyle* SlowStyleForContinuationOutline() const;
+
StyleDifference AdjustStyleDifference(StyleDifference) const;
#if DCHECK_IS_ON()
@@ -3627,10 +3663,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
static bool IsAllowedToModifyLayoutTreeStructure(Document&);
- // Returns the parent LayoutObject, or nullptr. This has a special case for
- // LayoutView to return the owning LayoutObject in the containing frame.
- inline LayoutObject* ParentCrossingFrames() const;
-
void UpdateImageObservers(const ComputedStyle* old_style,
const ComputedStyle* new_style);
void UpdateFirstLineImageObservers(const ComputedStyle* new_style);
@@ -3773,7 +3805,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
is_layout_ng_object_for_list_marker_image_(false),
is_table_column_constraints_dirty_(false),
transform_affects_vector_effect_(false),
+ is_layout_ng_object_for_canvas_formatted_text(false),
should_skip_next_layout_shift_tracking_(true),
+ should_assume_paint_offset_translation_for_layout_shift_tracking_(
+ false),
positioned_state_(kIsStaticallyPositioned),
selection_state_(static_cast<unsigned>(SelectionState::kNone)),
subtree_paint_property_update_reasons_(
@@ -4087,12 +4122,23 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// included).
ADD_BOOLEAN_BITFIELD(transform_affects_vector_effect_,
TransformAffectsVectorEffect);
+ ADD_BOOLEAN_BITFIELD(is_layout_ng_object_for_canvas_formatted_text,
+ IsLayoutNGObjectForCanvasFormattedText);
// Whether to skip layout shift tracking in the next paint invalidation.
// See PaintInvalidator::UpdateLayoutShiftTracking().
ADD_BOOLEAN_BITFIELD(should_skip_next_layout_shift_tracking_,
ShouldSkipNextLayoutShiftTracking);
+ // Whether, on the next time PaintPropertyTreeBuilder builds for this
+ // object, it should be assumed it had the same paint offset transform last
+ // time as it has this time. This is used when layout reattach loses the
+ // information from the previous frame; this bit stores that information
+ // to inform the next frame for layout shift tracking.
+ ADD_BOOLEAN_BITFIELD(
+ should_assume_paint_offset_translation_for_layout_shift_tracking_,
+ ShouldAssumePaintOffsetTranslationForLayoutShiftTracking);
+
private:
// This is the cached 'position' value of this object
// (see ComputedStyle::position).
@@ -4149,9 +4195,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
break;
}
}
- void ClearPositionedState() {
- positioned_state_ = kIsStaticallyPositioned;
- }
+ void ClearPositionedState() { positioned_state_ = kIsStaticallyPositioned; }
ALWAYS_INLINE SelectionState GetSelectionState() const {
return static_cast<SelectionState>(selection_state_);
@@ -4292,13 +4336,16 @@ inline bool LayoutObject::CanTraversePhysicalFragments() const {
if (!IsInLayoutNGInlineFormattingContext())
return false;
}
- // Bail if we have an NGPaintFragment. NGPaintFragment will be removed, and we
- // will not attempt to add support for them here.
- if (PaintFragment())
+ // The NG paint system currently doesn't support replaced content.
+ if (IsLayoutReplaced())
return false;
// The NG paint system currently doesn't support table-cells.
if (IsTableCellLegacy())
return false;
+ // Text controls have some logic in the layout objects that will be missed if
+ // we traverse the fragment tree when hit-testing.
+ if (IsTextControlIncludingNG())
+ return false;
return true;
}
@@ -4441,10 +4488,6 @@ CORE_EXPORT const LayoutObject* AssociatedLayoutObjectOf(
CORE_EXPORT std::ostream& operator<<(std::ostream&, const LayoutObject*);
CORE_EXPORT std::ostream& operator<<(std::ostream&, const LayoutObject&);
-#define DEFINE_LAYOUT_OBJECT_TYPE_CASTS(thisType, predicate) \
- DEFINE_TYPE_CASTS(thisType, LayoutObject, object, object->predicate, \
- object.predicate)
-
bool IsMenuList(const LayoutObject* object);
CORE_EXPORT bool IsListBox(const LayoutObject* object);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
index 0a4fb050729..aeb6040af81 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
namespace blink {
@@ -59,19 +58,12 @@ void InvalidateInlineItems(LayoutObject* object) {
}
}
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // This LayoutObject is not technically destroyed, but further access should
- // be prohibited when moved to different parent as if it were destroyed.
- if (object->FirstInlineFragmentItemIndex()) {
- if (auto* text = DynamicTo<LayoutText>(object))
- text->DetachAbstractInlineTextBoxesIfNeeded();
- NGFragmentItems::LayoutObjectWillBeMoved(*object);
- }
- } else if (NGPaintFragment* fragment = object->FirstInlineFragment()) {
- // This LayoutObject is not technically destroyed, but further access should
- // be prohibited when moved to different parent as if it were destroyed.
- fragment->LayoutObjectWillBeDestroyed();
- object->SetFirstInlineFragment(nullptr);
+ // This LayoutObject is not technically destroyed, but further access should
+ // be prohibited when moved to different parent as if it were destroyed.
+ if (object->FirstInlineFragmentItemIndex()) {
+ if (auto* text = DynamicTo<LayoutText>(object))
+ text->DetachAbstractInlineTextBoxesIfNeeded();
+ NGFragmentItems::LayoutObjectWillBeMoved(*object);
}
object->SetIsInLayoutNGInlineFormattingContext(false);
}
@@ -131,8 +123,7 @@ LayoutObject* LayoutObjectChildList::RemoveChildNode(
if (old_child->IsInLayoutNGInlineFormattingContext()) {
owner->SetChildNeedsCollectInlines();
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- InvalidateInlineItems(old_child);
+ InvalidateInlineItems(old_child);
}
}
@@ -188,8 +179,7 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
return;
}
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
- !owner->DocumentBeingDestroyed() &&
+ if (!owner->DocumentBeingDestroyed() &&
new_child->IsInLayoutNGInlineFormattingContext()) {
InvalidateInlineItems(new_child);
}
@@ -245,6 +235,9 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
if (owner->ForceLegacyLayout() && !new_child->IsLayoutNGObject())
new_child->SetForceLegacyLayout();
+ // Mark the ancestor chain for paint invalidation checking.
+ owner->SetShouldCheckForPaintInvalidation();
+
new_child->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kAddedToLayout);
if (new_child->IsOutOfFlowPositioned() &&
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
index d67ea5ad9d3..9f810d0d1a0 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -250,11 +250,8 @@ LayoutObject* LayoutObjectFactory::CreateButton(Node& node,
LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node,
const ComputedStyle& style,
LegacyLayout legacy) {
- bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGFieldsetEnabled();
- if (disable_ng_for_type)
- UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByFieldSet);
return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(
- node, style, legacy, disable_ng_for_type);
+ node, style, legacy);
}
LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl(
@@ -351,13 +348,15 @@ LayoutObject* LayoutObjectFactory::CreateRubyText(Node* node,
}
LayoutBox* LayoutObjectFactory::CreateAnonymousTableWithParent(
- const LayoutObject& parent) {
+ const LayoutObject& parent,
+ bool child_forces_legacy) {
scoped_refptr<ComputedStyle> new_style =
ComputedStyle::CreateAnonymousStyleWithDisplay(
parent.StyleRef(),
parent.IsLayoutInline() ? EDisplay::kInlineTable : EDisplay::kTable);
- LegacyLayout legacy =
- parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
+ LegacyLayout legacy = parent.ForceLegacyLayout() || child_forces_legacy
+ ? LegacyLayout::kForce
+ : LegacyLayout::kAuto;
LayoutBlock* new_table =
CreateTable(parent.GetDocument(), *new_style, legacy);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
index a1ed82d5119..dfd5a5d88ec 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -104,7 +104,11 @@ class LayoutObjectFactory {
// Anonoymous creation methods
- static LayoutBox* CreateAnonymousTableWithParent(const LayoutObject& parent);
+ // |child_forces_legacy| true if creating parents boxes for legacy child.
+ // Table must match child's type.
+ static LayoutBox* CreateAnonymousTableWithParent(
+ const LayoutObject& parent,
+ bool child_forces_legacy = false);
static LayoutBox* CreateAnonymousTableSectionWithParent(
const LayoutObject& parent);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
index 7dbf51f7e54..c5d16f1bb0e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -1413,7 +1413,8 @@ TEST_F(LayoutObjectTest, LocalToAncestorRectFastPath) {
PhysicalRect result;
EXPECT_TRUE(target->LocalToAncestorRectFastPath(
- rect, nullptr, kUseGeometryMapperMode, result));
+ rect, nullptr, kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor,
+ result));
EXPECT_EQ(PhysicalRect(50, 25, 10, 10), result);
// Compare with non-fast path.
EXPECT_EQ(PhysicalRect(50, 25, 10, 10),
@@ -1430,6 +1431,8 @@ TEST_F(LayoutObjectTest, LocalToAncestorRectFastPath) {
EXPECT_FALSE(target->LocalToAncestorRectFastPath(
rect, nullptr, kIgnoreScrollOffset, result));
EXPECT_FALSE(target->LocalToAncestorRectFastPath(
+ rect, nullptr, kIgnoreScrollOffsetOfAncestor, result));
+ EXPECT_FALSE(target->LocalToAncestorRectFastPath(
rect, nullptr, kApplyRemoteMainFrameTransform, result));
EXPECT_EQ(PhysicalRect(50, 25, 10, 10),
@@ -1439,17 +1442,17 @@ TEST_F(LayoutObjectTest, LocalToAncestorRectFastPath) {
LayoutObject* ancestor2 = GetLayoutObjectByElementId("ancestor2");
PhysicalRect result2;
- EXPECT_TRUE(target2->LocalToAncestorRectFastPath(
- rect, To<LayoutBoxModelObject>(ancestor2), kUseGeometryMapperMode,
- result2));
- EXPECT_EQ(PhysicalRect(75, 15, 10, 10), result2);
+ EXPECT_FALSE(target2->LocalToAncestorRectFastPath(
+ rect, To<LayoutBoxModelObject>(ancestor2),
+ kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor, result2));
EXPECT_EQ(
PhysicalRect(75, 15, 10, 10),
target2->LocalToAncestorRect(rect, To<LayoutBoxModelObject>(ancestor2)));
// Compare with non-fast path.
EXPECT_TRUE(target2->LocalToAncestorRectFastPath(
- rect, nullptr, kUseGeometryMapperMode, result2));
+ rect, nullptr, kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor,
+ result2));
// 25 instead of 15, because #target is 10px high.
EXPECT_EQ(PhysicalRect(75, 25, 10, 10), result2);
@@ -1457,4 +1460,132 @@ TEST_F(LayoutObjectTest, LocalToAncestorRectFastPath) {
target2->LocalToAncestorRect(rect, nullptr));
}
+TEST_F(LayoutObjectTest, LocalToAncestoRectIgnoreAncestorScroll) {
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div id=ancestor style="overflow:scroll; width: 100px; height: 100px">
+ <div style="height: 2000px"></div>
+ <div id="target" style="width: 100px; height: 100px"></div>
+ </div>
+ )HTML");
+
+ LayoutObject* target = GetLayoutObjectByElementId("target");
+ LayoutBoxModelObject* ancestor =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("ancestor"));
+ ancestor->GetScrollableArea()->ScrollBy(ScrollOffset(0, 100),
+ mojom::blink::ScrollType::kUser);
+ UpdateAllLifecyclePhasesForTest();
+
+ PhysicalRect rect(0, 0, 100, 100);
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor,
+ kIgnoreScrollOffsetOfAncestor));
+
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor, kIgnoreScrollOffset));
+
+ EXPECT_EQ(PhysicalRect(0, 1900, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor, 0));
+}
+
+TEST_F(LayoutObjectTest, LocalToAncestoRectViewIgnoreAncestorScroll) {
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div style="height: 2000px"></div>
+ <div id="target" style="width: 100px; height: 100px"></div>
+ )HTML");
+
+ LayoutObject* target = GetLayoutObjectByElementId("target");
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 100), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
+
+ PhysicalRect rect(0, 0, 100, 100);
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr,
+ kIgnoreScrollOffsetOfAncestor));
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(
+ rect, nullptr,
+ kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor));
+
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr, kIgnoreScrollOffset));
+
+ EXPECT_EQ(PhysicalRect(0, 1900, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr, 0));
+}
+
+TEST_F(LayoutObjectTest,
+ LocalToAncestoRectIgnoreAncestorScrollIntermediateScroller) {
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div id=ancestor style="overflow:scroll; width: 100px; height: 100px">
+ <div id=intermediate style="overflow:scroll; width: 100px; height: 100px">
+ <div style="height: 2000px"></div>
+ <div id="target" style="width: 100px; height: 100px"></div>
+ </div>
+ <div style="height: 2000px"></div>
+ </div>
+ )HTML");
+
+ LayoutObject* target = GetLayoutObjectByElementId("target");
+ LayoutBoxModelObject* ancestor =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("ancestor"));
+ LayoutBoxModelObject* intermediate =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("intermediate"));
+ ancestor->GetScrollableArea()->ScrollBy(ScrollOffset(0, 100),
+ mojom::blink::ScrollType::kUser);
+ intermediate->GetScrollableArea()->ScrollBy(ScrollOffset(0, 100),
+ mojom::blink::ScrollType::kUser);
+ UpdateAllLifecyclePhasesForTest();
+
+ PhysicalRect rect(0, 0, 100, 100);
+ EXPECT_EQ(PhysicalRect(0, 1900, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor,
+ kIgnoreScrollOffsetOfAncestor));
+
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor, kIgnoreScrollOffset));
+
+ EXPECT_EQ(PhysicalRect(0, 1800, 100, 100),
+ target->LocalToAncestorRect(rect, ancestor, 0));
+}
+
+TEST_F(LayoutObjectTest,
+ LocalToAncestoRectViewIgnoreAncestorScrollIntermediateScroller) {
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div id=intermediate style="overflow:scroll; width: 100px; height: 100px">
+ <div style="height: 2000px"></div>
+ <div id="target" style="width: 100px; height: 100px"></div>
+ </div>
+ <div style="height: 2000px"></div>
+ )HTML");
+
+ LayoutObject* target = GetLayoutObjectByElementId("target");
+ LayoutBoxModelObject* intermediate =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("intermediate"));
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 100), mojom::blink::ScrollType::kProgrammatic);
+ intermediate->GetScrollableArea()->ScrollBy(ScrollOffset(0, 100),
+ mojom::blink::ScrollType::kUser);
+ UpdateAllLifecyclePhasesForTest();
+
+ PhysicalRect rect(0, 0, 100, 100);
+ EXPECT_EQ(PhysicalRect(0, 1900, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr,
+ kIgnoreScrollOffsetOfAncestor));
+ EXPECT_EQ(PhysicalRect(0, 1900, 100, 100),
+ target->LocalToAncestorRect(
+ rect, nullptr,
+ kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor));
+
+ EXPECT_EQ(PhysicalRect(0, 2000, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr, kIgnoreScrollOffset));
+
+ EXPECT_EQ(PhysicalRect(0, 1800, 100, 100),
+ target->LocalToAncestorRect(rect, nullptr, 0));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc
index 14718111823..3aa27266d49 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc
@@ -40,7 +40,7 @@ void LayoutOutsideListMarker::UpdateMargins() {
LayoutUnit margin_start;
LayoutUnit margin_end;
std::tie(margin_start, margin_end) = ListMarker::InlineMarginsForOutside(
- StyleRef(), list_marker_.ListItem(*this)->StyleRef(),
+ GetDocument(), StyleRef(), list_marker_.ListItem(*this)->StyleRef(),
PreferredLogicalWidths().min_size);
SetMarginStart(margin_start);
SetMarginEnd(margin_end);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
index 0f56c2e53b5..beedfdb3449 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -35,8 +35,8 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/replaced_painter.h"
@@ -133,13 +133,12 @@ void LayoutReplaced::Paint(const PaintInfo& paint_info) const {
bool LayoutReplaced::HasReplacedLogicalHeight() const {
NOT_DESTROYED();
if (StyleRef().LogicalHeight().IsAuto())
- return false;
+ return StretchBlockSizeIfAuto();
- if (RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
- StyleRef().LogicalHeight().IsFixed())
+ if (StyleRef().LogicalHeight().IsFixed())
return true;
- if (StyleRef().LogicalHeight().IsSpecified()) {
+ if (StyleRef().LogicalHeight().IsPercentOrCalc()) {
if (HasAutoHeightOrContainingBlockWithAutoHeight())
return false;
return true;
@@ -713,6 +712,8 @@ void LayoutReplaced::ComputeIntrinsicSizingInfo(
aspect_ratio.GetRatio().Width());
intrinsic_sizing_info.aspect_ratio.SetHeight(
aspect_ratio.GetRatio().Height());
+ if (!IsHorizontalWritingMode())
+ intrinsic_sizing_info.Transpose();
}
if (aspect_ratio.GetType() == EAspectRatioType::kRatio)
return;
@@ -726,18 +727,6 @@ void LayoutReplaced::ComputeIntrinsicSizingInfo(
intrinsic_sizing_info.aspect_ratio = intrinsic_sizing_info.size;
}
-static inline LayoutUnit ResolveWidthForRatio(LayoutUnit height,
- const FloatSize& aspect_ratio) {
- return LayoutUnit(height.ToDouble() * aspect_ratio.Width() /
- aspect_ratio.Height());
-}
-
-static inline LayoutUnit ResolveHeightForRatio(LayoutUnit width,
- const FloatSize& aspect_ratio) {
- return LayoutUnit(width.ToDouble() * aspect_ratio.Height() /
- aspect_ratio.Width());
-}
-
LayoutUnit LayoutReplaced::ComputeConstrainedLogicalWidth(
ShouldComputePreferred should_compute_preferred) const {
NOT_DESTROYED();
@@ -766,7 +755,7 @@ LayoutUnit LayoutReplaced::ComputeConstrainedLogicalWidth(
LayoutUnit LayoutReplaced::ComputeReplacedLogicalWidth(
ShouldComputePreferred should_compute_preferred) const {
NOT_DESTROYED();
- if (!StyleRef().LogicalWidth().IsAuto()) {
+ if (!StyleRef().LogicalWidth().IsAuto() || StretchInlineSizeIfAuto()) {
return ComputeReplacedLogicalWidthRespectingMinMaxWidth(
ComputeReplacedLogicalWidthUsing(kMainOrPreferredSize,
StyleRef().LogicalWidth()),
@@ -782,7 +771,8 @@ LayoutUnit LayoutReplaced::ComputeReplacedLogicalWidth(
ConstrainIntrinsicSizeToMinMax(intrinsic_sizing_info);
if (StyleRef().LogicalWidth().IsAuto()) {
- bool computed_height_is_auto = StyleRef().LogicalHeight().IsAuto();
+ bool computed_height_is_auto =
+ StyleRef().LogicalHeight().IsAuto() && !StretchBlockSizeIfAuto();
// If 'height' and 'width' both have computed values of 'auto' and the
// element also has an intrinsic width, then that intrinsic width is the
@@ -807,9 +797,22 @@ LayoutUnit LayoutReplaced::ComputeReplacedLogicalWidth(
: ComputeConstrainedLogicalWidth(should_compute_preferred);
LayoutUnit logical_height =
ComputeReplacedLogicalHeight(estimated_used_width);
+ NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
+ BorderEnd() + ComputedCSSPaddingEnd(),
+ BorderBefore() + ComputedCSSPaddingBefore(),
+ BorderAfter() + ComputedCSSPaddingAfter());
+ // Because ComputeReplacedLogicalHeight returns a content size, we need
+ // to add border + padding for InlineSizeFromAspectRatio.
+ EBoxSizing box_sizing = EBoxSizing::kContentBox;
+ logical_height += border_padding.BlockSum();
+ if (StyleRef().AspectRatio().GetType() == EAspectRatioType::kRatio)
+ box_sizing = StyleRef().BoxSizing();
+ double aspect_ratio = intrinsic_sizing_info.aspect_ratio.Width() /
+ intrinsic_sizing_info.aspect_ratio.Height();
return ComputeReplacedLogicalWidthRespectingMinMaxWidth(
- ResolveWidthForRatio(logical_height,
- intrinsic_sizing_info.aspect_ratio),
+ InlineSizeFromAspectRatio(border_padding, aspect_ratio, box_sizing,
+ logical_height) -
+ border_padding.InlineSum(),
should_compute_preferred);
}
@@ -883,8 +886,22 @@ LayoutUnit LayoutReplaced::ComputeReplacedLogicalHeight(
if (!intrinsic_sizing_info.aspect_ratio.IsEmpty()) {
LayoutUnit used_width =
estimated_used_width ? estimated_used_width : AvailableLogicalWidth();
+ NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
+ BorderEnd() + ComputedCSSPaddingEnd(),
+ BorderBefore() + ComputedCSSPaddingBefore(),
+ BorderAfter() + ComputedCSSPaddingAfter());
+ // Because used_size contains a content size, we need
+ // to add border + padding for BlockSizeFromAspectRatio.
+ EBoxSizing box_sizing = EBoxSizing::kContentBox;
+ used_width += border_padding.InlineSum();
+ if (StyleRef().AspectRatio().GetType() == EAspectRatioType::kRatio)
+ box_sizing = StyleRef().BoxSizing();
+ double aspect_ratio = intrinsic_sizing_info.aspect_ratio.Height() /
+ intrinsic_sizing_info.aspect_ratio.Width();
return ComputeReplacedLogicalHeightRespectingMinMaxHeight(
- ResolveHeightForRatio(used_width, intrinsic_sizing_info.aspect_ratio));
+ BlockSizeFromAspectRatio(border_padding, aspect_ratio, box_sizing,
+ used_width) -
+ border_padding.BlockSum());
}
// Otherwise, if 'height' has a computed value of 'auto', and the element has
@@ -972,9 +989,9 @@ static std::pair<LayoutUnit, LayoutUnit> SelectionTopAndBottom(
const ComputedStyle& line_style = line_box.Current().Style();
const auto writing_direction = line_style.GetWritingDirection();
const WritingModeConverter converter(writing_direction,
- line_box.BoxFragment().Size());
+ line_box.ContainerFragment().Size());
const LogicalRect logical_rect =
- converter.ToLogical(line_box.Current().RectInContainerBlock());
+ converter.ToLogical(line_box.Current().RectInContainerFragment());
return {logical_rect.offset.block_offset, logical_rect.BlockEndOffset()};
}
@@ -989,6 +1006,7 @@ static std::pair<LayoutUnit, LayoutUnit> SelectionTopAndBottom(
PositionWithAffinity LayoutReplaced::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+
LayoutUnit top;
LayoutUnit bottom;
std::tie(top, bottom) = SelectionTopAndBottom(*this);
@@ -1003,20 +1021,18 @@ PositionWithAffinity LayoutReplaced::PositionForPoint(
: flipped_point_in_container.Y();
if (block_direction_position < top)
- return CreatePositionWithAffinity(
- CaretMinOffset()); // coordinates are above
+ return PositionBeforeThis(); // coordinates are above
if (block_direction_position >= bottom)
- return CreatePositionWithAffinity(
- CaretMaxOffset()); // coordinates are below
+ return PositionBeforeThis(); // coordinates are below
if (GetNode()) {
const bool is_at_left_side =
line_direction_position <= LogicalLeft() + (LogicalWidth() / 2);
const bool is_at_start = is_at_left_side == IsLtr(ResolvedDirection());
- // TODO(crbug.com/827923): Stop creating positions using int offsets on
- // non-text nodes.
- return CreatePositionWithAffinity(is_at_start ? 0 : 1);
+ if (is_at_start)
+ return PositionBeforeThis();
+ return PositionAfterThis();
}
return LayoutBox::PositionForPoint(point);
@@ -1034,7 +1050,7 @@ PhysicalRect LayoutReplaced::LocalSelectionVisualRect() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject())
- rect.Unite(ComputeLocalSelectionRectForReplaced(cursor));
+ rect.Unite(cursor.CurrentLocalSelectionRectForReplaced());
return rect;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
index 8afe092e201..b16142b93f9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -81,6 +81,7 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
NOT_DESTROYED();
return false;
}
+ virtual bool DrawsBackgroundOntoContentLayer() const { return false; }
virtual void PaintReplaced(const PaintInfo&,
const PhysicalOffset& paint_offset) const {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index 3470de8f97f..560b7f61f2b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -7,6 +7,7 @@
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/layer_tree_host.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_pointer_event.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -94,9 +95,9 @@ bool EqualWithinMovementThreshold(const FloatPoint& a,
fabs(a.Y() - b.Y()) < threshold_physical_px;
}
-bool SmallerThanRegionGranularity(const PhysicalRect& rect) {
- // The region uses integer coordinates, so the rects are snapped to
- // pixel boundaries. Ignore rects smaller than half a pixel.
+bool SmallerThanRegionGranularity(const LayoutRect& rect) {
+ // Normally we paint by snapping to whole pixels, so rects smaller than half
+ // a pixel may be invisible.
return rect.Width() < 0.5 || rect.Height() < 0.5;
}
@@ -125,12 +126,14 @@ void RegionToTracedValue(const LayoutShiftRegion& region, TracedValue& value) {
value.EndArray();
}
-#if DCHECK_IS_ON()
bool ShouldLog(const LocalFrame& frame) {
+ if (!VLOG_IS_ON(1))
+ return false;
+
+ DCHECK(frame.GetDocument());
const String& url = frame.GetDocument()->Url().GetString();
return !url.StartsWith("devtools:");
}
-#endif
} // namespace
@@ -139,7 +142,9 @@ LayoutShiftTracker::LayoutShiftTracker(LocalFrameView* frame_view)
// This eliminates noise from the private Page object created by
// SVGImage::DataChanged.
is_active_(
- !frame_view_->GetFrame().GetChromeClient().IsSVGImageChromeClient()),
+ !frame_view->GetFrame().GetChromeClient().IsSVGImageChromeClient()),
+ enable_m90_improvements_(
+ base::FeatureList::IsEnabled(features::kCLSM90Improvements)),
score_(0.0),
weighted_score_(0.0),
timer_(frame_view->GetFrame().GetTaskRunner(TaskType::kInternalDefault),
@@ -154,36 +159,56 @@ bool LayoutShiftTracker::NeedsToTrack(const LayoutObject& object) const {
if (!is_active_)
return false;
+ if (object.GetDocument().IsPrintingOrPaintingPreview())
+ return false;
+
// SVG elements don't participate in the normal layout algorithms and are
// more likely to be used for animations.
if (object.IsSVGChild())
return false;
- if (object.IsText())
- return !object.IsBR() && ContainingBlockScope::top_;
+ if (object.StyleRef().Visibility() != EVisibility::kVisible)
+ return false;
+
+ if (object.IsText()) {
+ if (!ContainingBlockScope::top_)
+ return false;
+ if (object.IsBR())
+ return false;
+ if (enable_m90_improvements_) {
+ if (To<LayoutText>(object).ContainsOnlyWhitespaceOrNbsp() ==
+ OnlyWhitespaceOrNbsp::kYes)
+ return false;
+ if (object.StyleRef().GetFont().ShouldSkipDrawing())
+ return false;
+ }
+ return true;
+ }
if (!object.IsBox())
return false;
- if (auto* display_lock_context = object.GetDisplayLockContext()) {
+ const auto& box = To<LayoutBox>(object);
+ if (SmallerThanRegionGranularity(box.VisualOverflowRect()))
+ return false;
+
+ if (auto* display_lock_context = box.GetDisplayLockContext()) {
if (display_lock_context->IsAuto() && display_lock_context->IsLocked())
return false;
}
// Don't report shift of anonymous objects. Will report the children because
// we want report real DOM nodes.
- if (object.IsAnonymous())
- return false;
-
- if (object.StyleRef().Visibility() != EVisibility::kVisible)
+ if (box.IsAnonymous())
return false;
// Ignore sticky-positioned objects that move on scroll.
// TODO(skobes): Find a way to detect when these objects shift.
- if (object.IsStickyPositioned())
+ if (box.IsStickyPositioned())
return false;
- if (object.IsLayoutView())
+ // A LayoutView can't move by itself.
+ if (box.IsLayoutView())
return false;
if (Element* element = DynamicTo<Element>(object.GetNode())) {
@@ -191,6 +216,17 @@ bool LayoutShiftTracker::NeedsToTrack(const LayoutObject& object) const {
return false;
}
+ if (enable_m90_improvements_ && box.IsLayoutBlock()) {
+ // Just check the simplest case. For more complex cases, we should suggest
+ // the developer to use visibility:hidden.
+ if (To<LayoutBlock>(box).FirstChild())
+ return true;
+ if (box.HasBoxDecorationBackground() || box.GetScrollableArea() ||
+ box.StyleRef().HasVisualOverflowingEffect())
+ return true;
+ return false;
+ }
+
return true;
}
@@ -200,6 +236,8 @@ void LayoutShiftTracker::ObjectShifted(
const PhysicalRect& old_rect,
const PhysicalRect& new_rect,
const FloatPoint& old_starting_point,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_delta,
const FloatPoint& new_starting_point) {
// The caller should ensure these conditions.
DCHECK(!old_rect.IsEmpty());
@@ -208,18 +246,43 @@ void LayoutShiftTracker::ObjectShifted(
float threshold_physical_px =
kMovementThreshold * object.StyleRef().EffectiveZoom();
- if (EqualWithinMovementThreshold(old_starting_point, new_starting_point,
- threshold_physical_px))
- return;
+ if (enable_m90_improvements_) {
+ // Check shift of starting point, including 2d-translation and scroll
+ // deltas.
+ if (EqualWithinMovementThreshold(old_starting_point, new_starting_point,
+ threshold_physical_px))
+ return;
+
+ // Check shift of 2d-translation-indifferent starting point.
+ if (!translation_delta.IsZero() &&
+ EqualWithinMovementThreshold(old_starting_point + translation_delta,
+ new_starting_point, threshold_physical_px))
+ return;
+
+ // Check shift of scroll-indifferent starting point.
+ if (!scroll_delta.IsZero() &&
+ EqualWithinMovementThreshold(old_starting_point + scroll_delta,
+ new_starting_point, threshold_physical_px))
+ return;
+ }
- if (SmallerThanRegionGranularity(old_rect) &&
- SmallerThanRegionGranularity(new_rect))
+ // Check shift of 2d-translation-and-scroll-indifferent starting point.
+ FloatSize translation_and_scroll_delta = scroll_delta + translation_delta;
+ if (!translation_and_scroll_delta.IsZero() &&
+ EqualWithinMovementThreshold(
+ old_starting_point + translation_and_scroll_delta, new_starting_point,
+ threshold_physical_px))
return;
const auto& root_state =
object.View()->FirstFragment().LocalBorderBoxProperties();
FloatClipRect clip_rect =
GeometryMapper::LocalToAncestorClipRect(property_tree_state, root_state);
+ if (frame_view_->GetFrame().IsMainFrame()) {
+ // Apply the visual viewport clip.
+ clip_rect.Intersect(FloatClipRect(
+ frame_view_->GetPage()->GetVisualViewport().VisibleRect()));
+ }
// If the clip region is empty, then the resulting layout shift isn't visible
// in the viewport so ignore it.
@@ -228,8 +291,11 @@ void LayoutShiftTracker::ObjectShifted(
auto transform = GeometryMapper::SourceToDestinationProjection(
property_tree_state.Transform(), root_state.Transform());
- FloatPoint old_starting_point_in_root =
- transform.MapPoint(old_starting_point);
+ // TODO(crbug.com/1187979): Shift by |scroll_delta| to keep backward
+ // compatibility in https://crrev.com/c/2754969. See the bug for details.
+ FloatPoint old_starting_point_in_root = transform.MapPoint(
+ old_starting_point +
+ (enable_m90_improvements_ ? scroll_delta : translation_and_scroll_delta));
FloatPoint new_starting_point_in_root =
transform.MapPoint(new_starting_point);
@@ -238,9 +304,11 @@ void LayoutShiftTracker::ObjectShifted(
threshold_physical_px))
return;
- if (EqualWithinMovementThreshold(
- old_starting_point_in_root + frame_scroll_delta_,
- new_starting_point_in_root, threshold_physical_px)) {
+ if (enable_m90_improvements_) {
+ DCHECK(frame_scroll_delta_.IsZero());
+ } else if (EqualWithinMovementThreshold(
+ old_starting_point_in_root + frame_scroll_delta_,
+ new_starting_point_in_root, threshold_physical_px)) {
// TODO(skobes): Checking frame_scroll_delta_ is an imperfect solution to
// allowing counterscrolled layout shifts. Ideally, we would map old_rect
// to viewport coordinates using the previous frame's scroll tree.
@@ -248,6 +316,10 @@ void LayoutShiftTracker::ObjectShifted(
}
FloatRect old_rect_in_root(old_rect);
+ // TODO(crbug.com/1187979): Shift by |scroll_delta| to keep backward
+ // compatibility in https://crrev.com/c/2754969. See the bug for details.
+ old_rect_in_root.Move(
+ enable_m90_improvements_ ? scroll_delta : translation_and_scroll_delta);
transform.MapRect(old_rect_in_root);
FloatRect new_rect_in_root(new_rect);
transform.MapRect(new_rect_in_root);
@@ -259,27 +331,46 @@ void LayoutShiftTracker::ObjectShifted(
if (visible_old_rect.IsEmpty() && visible_new_rect.IsEmpty())
return;
+ // If the object moved from or to out of view, ignore the shift if it's in
+ // the inline direction only.
+ if (enable_m90_improvements_ &&
+ (visible_old_rect.IsEmpty() || visible_new_rect.IsEmpty())) {
+ FloatPoint old_inline_direction_indifferent_starting_point_in_root =
+ old_starting_point_in_root;
+ if (object.IsHorizontalWritingMode()) {
+ old_inline_direction_indifferent_starting_point_in_root.SetX(
+ new_starting_point_in_root.X());
+ } else {
+ old_inline_direction_indifferent_starting_point_in_root.SetY(
+ new_starting_point_in_root.Y());
+ }
+ if (EqualWithinMovementThreshold(
+ old_inline_direction_indifferent_starting_point_in_root,
+ new_starting_point_in_root, threshold_physical_px)) {
+ return;
+ }
+ }
+
// Compute move distance based on unclipped rects, to accurately determine how
// much the element moved.
float move_distance =
GetMoveDistance(old_starting_point_in_root, new_starting_point_in_root);
frame_max_distance_ = std::max(frame_max_distance_, move_distance);
-#if DCHECK_IS_ON()
LocalFrame& frame = frame_view_->GetFrame();
if (ShouldLog(frame)) {
- DVLOG(2) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
- << frame.GetDocument()->Url() << ", " << object << " moved from "
- << old_rect_in_root << " to " << new_rect_in_root
- << " (visible from " << visible_old_rect << " to "
- << visible_new_rect << ")";
+ VLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
+ << frame.GetDocument()->Url() << ", " << object << " moved from "
+ << old_rect_in_root << " to " << new_rect_in_root
+ << " (visible from " << visible_old_rect << " to "
+ << visible_new_rect << ")";
if (old_starting_point_in_root != old_rect_in_root.Location() ||
- new_starting_point_in_root != new_rect_in_root.Location()) {
- DVLOG(2) << " (starting point from " << old_starting_point_in_root
- << " to " << new_starting_point_in_root << ")";
+ new_starting_point_in_root != new_rect_in_root.Location() ||
+ !translation_delta.IsZero() || !scroll_delta.IsZero()) {
+ VLOG(1) << " (starting point from " << old_starting_point_in_root
+ << " to " << new_starting_point_in_root << ")";
}
}
-#endif
region_.AddRect(visible_old_rect);
region_.AddRect(visible_new_rect);
@@ -345,10 +436,13 @@ void LayoutShiftTracker::NotifyBoxPrePaint(
const PhysicalRect& old_rect,
const PhysicalRect& new_rect,
const PhysicalOffset& old_paint_offset,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_delta,
const PhysicalOffset& new_paint_offset) {
DCHECK(NeedsToTrack(box));
ObjectShifted(box, property_tree_state, old_rect, new_rect,
StartingPoint(old_paint_offset, box, box.PreviousSize()),
+ translation_delta, scroll_delta,
StartingPoint(new_paint_offset, box, box.Size()));
}
@@ -358,6 +452,8 @@ void LayoutShiftTracker::NotifyTextPrePaint(
const LogicalOffset& old_starting_point,
const LogicalOffset& new_starting_point,
const PhysicalOffset& old_paint_offset,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_delta,
const PhysicalOffset& new_paint_offset,
LayoutUnit logical_height) {
DCHECK(NeedsToTrack(text));
@@ -386,8 +482,8 @@ void LayoutShiftTracker::NotifyTextPrePaint(
return;
ObjectShifted(text, property_tree_state, old_rect, new_rect,
- FloatPoint(old_physical_starting_point),
- FloatPoint(new_physical_starting_point));
+ FloatPoint(old_physical_starting_point), translation_delta,
+ scroll_delta, FloatPoint(new_physical_starting_point));
}
double LayoutShiftTracker::SubframeWeightingFactor() const {
@@ -415,7 +511,7 @@ double LayoutShiftTracker::SubframeWeightingFactor() const {
main_frame_size.Area();
}
-void LayoutShiftTracker::NotifyPrePaintFinished() {
+void LayoutShiftTracker::NotifyPrePaintFinishedInternal() {
if (!is_active_)
return;
if (region_.IsEmpty())
@@ -440,15 +536,13 @@ void LayoutShiftTracker::NotifyPrePaintFinished() {
overall_max_distance_ = std::max(overall_max_distance_, frame_max_distance_);
-#if DCHECK_IS_ON()
LocalFrame& frame = frame_view_->GetFrame();
if (ShouldLog(frame)) {
- DVLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
- << frame.GetDocument()->Url() << ", viewport was "
- << (impact_fraction * 100) << "% impacted with distance fraction "
- << move_distance_factor;
+ VLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
+ << frame.GetDocument()->Url() << ", viewport was "
+ << (impact_fraction * 100) << "% impacted with distance fraction "
+ << move_distance_factor;
}
-#endif
if (pointerdown_pending_data_.saw_pointerdown) {
pointerdown_pending_data_.score_delta += score_delta;
@@ -459,8 +553,13 @@ void LayoutShiftTracker::NotifyPrePaintFinished() {
if (!region_.IsEmpty())
SetLayoutShiftRects(region_.GetRects());
- region_.Reset();
+}
+
+void LayoutShiftTracker::NotifyPrePaintFinished() {
+ NotifyPrePaintFinishedInternal();
+ // Reset accumulated state.
+ region_.Reset();
frame_max_distance_ = 0.0;
frame_scroll_delta_ = ScrollOffset();
attributions_.fill(Attribution());
@@ -487,11 +586,7 @@ void LayoutShiftTracker::SubmitPerformanceEntry(double score_delta,
WindowPerformance* performance = DOMWindowPerformance::performance(*window);
DCHECK(performance);
- double input_timestamp =
- most_recent_input_timestamp_initialized_
- ? performance->MonotonicTimeToDOMHighResTimeStamp(
- most_recent_input_timestamp_)
- : 0.0;
+ double input_timestamp = LastInputTimestamp();
LayoutShift* entry =
LayoutShift::Create(performance->now(), score_delta, had_recent_input,
input_timestamp, CreateAttributionList());
@@ -515,19 +610,18 @@ void LayoutShiftTracker::ReportShift(double score_delta,
SubmitPerformanceEntry(score_delta, had_recent_input);
- TRACE_EVENT_INSTANT2("loading", "LayoutShift", TRACE_EVENT_SCOPE_THREAD,
- "data", PerFrameTraceData(score_delta, had_recent_input),
- "frame", ToTraceValue(&frame));
+ TRACE_EVENT_INSTANT2(
+ "loading", "LayoutShift", TRACE_EVENT_SCOPE_THREAD, "data",
+ PerFrameTraceData(score_delta, weighted_score_delta, had_recent_input),
+ "frame", ToTraceValue(&frame));
-#if DCHECK_IS_ON()
if (ShouldLog(frame)) {
- DVLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
- << frame.GetDocument()->Url().GetString() << ", layout shift of "
- << score_delta
- << (had_recent_input ? " excluded by recent input" : " reported")
- << "; cumulative score is " << score_;
+ VLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ")
+ << frame.GetDocument()->Url().GetString() << ", layout shift of "
+ << score_delta
+ << (had_recent_input ? " excluded by recent input" : " reported")
+ << "; cumulative score is " << score_;
}
-#endif
}
void LayoutShiftTracker::NotifyInput(const WebInputEvent& event) {
@@ -579,11 +673,14 @@ void LayoutShiftTracker::UpdateInputTimestamp(base::TimeTicks timestamp) {
} else if (timestamp > most_recent_input_timestamp_) {
most_recent_input_timestamp_ = timestamp;
}
+ LocalFrame& frame = frame_view_->GetFrame();
+ frame.Client()->DidObserveInputForLayoutShiftTracking(timestamp);
}
void LayoutShiftTracker::NotifyScroll(mojom::blink::ScrollType scroll_type,
ScrollOffset delta) {
- frame_scroll_delta_ += delta;
+ if (!enable_m90_improvements_)
+ frame_scroll_delta_ += delta;
// Only set observed_input_or_scroll_ for user-initiated scrolls, and not
// other scrolls such as hash fragment navigations.
@@ -593,28 +690,50 @@ void LayoutShiftTracker::NotifyScroll(mojom::blink::ScrollType scroll_type,
}
void LayoutShiftTracker::NotifyViewportSizeChanged() {
- // This cancels any previously scheduled task from the same timer.
- timer_.StartOneShot(kTimerDelay, FROM_HERE);
- UpdateInputTimestamp(base::TimeTicks::Now());
+ UpdateTimerAndInputTimestamp();
}
void LayoutShiftTracker::NotifyFindInPageInput() {
+ UpdateTimerAndInputTimestamp();
+}
+
+void LayoutShiftTracker::NotifyChangeEvent() {
+ UpdateTimerAndInputTimestamp();
+}
+
+void LayoutShiftTracker::UpdateTimerAndInputTimestamp() {
// This cancels any previously scheduled task from the same timer.
timer_.StartOneShot(kTimerDelay, FROM_HERE);
UpdateInputTimestamp(base::TimeTicks::Now());
}
+double LayoutShiftTracker::LastInputTimestamp() const {
+ LocalDOMWindow* window = frame_view_->GetFrame().DomWindow();
+ if (!window)
+ return 0.0;
+ WindowPerformance* performance = DOMWindowPerformance::performance(*window);
+ DCHECK(performance);
+
+ return most_recent_input_timestamp_initialized_
+ ? performance->MonotonicTimeToDOMHighResTimeStamp(
+ most_recent_input_timestamp_)
+ : 0.0;
+}
+
std::unique_ptr<TracedValue> LayoutShiftTracker::PerFrameTraceData(
double score_delta,
+ double weighted_score_delta,
bool input_detected) const {
auto value = std::make_unique<TracedValue>();
value->SetDouble("score", score_delta);
+ value->SetDouble("weighted_score_delta", weighted_score_delta);
value->SetDouble("cumulative_score", score_);
value->SetDouble("overall_max_distance", overall_max_distance_);
value->SetDouble("frame_max_distance", frame_max_distance_);
RegionToTracedValue(region_, *value);
value->SetBoolean("is_main_frame", frame_view_->GetFrame().IsMainFrame());
value->SetBoolean("had_recent_input", input_detected);
+ value->SetDouble("last_input_timestamp", LastInputTimestamp());
AttributionsToTracedValue(*value);
return value;
}
@@ -666,6 +785,7 @@ void LayoutShiftTracker::SetLayoutShiftRects(const Vector<IntRect>& int_rects) {
void LayoutShiftTracker::Trace(Visitor* visitor) const {
visitor->Trace(frame_view_);
+ visitor->Trace(timer_);
}
ReattachHookScope::ReattachHookScope(const Node& node) : outer_(top_) {
@@ -693,8 +813,11 @@ void ReattachHookScope::NotifyDetach(const Node& node) {
PhysicalRect visual_overflow_rect = box.PreviousPhysicalVisualOverflowRect();
if (visual_overflow_rect.IsEmpty() && box.PreviousSize().IsEmpty())
return;
+ bool has_paint_offset_transform = false;
+ if (auto* properties = fragment.PaintProperties())
+ has_paint_offset_transform = properties->PaintOffsetTranslation();
map.Set(&node, Geometry{fragment.PaintOffset(), box.PreviousSize(),
- visual_overflow_rect});
+ visual_overflow_rect, has_paint_offset_transform});
}
void ReattachHookScope::NotifyAttach(const Node& node) {
@@ -716,6 +839,8 @@ void ReattachHookScope::NotifyAttach(const Node& node) {
iter->value.paint_offset, iter->value.size,
iter->value.visual_overflow_rect);
layout_object->SetShouldSkipNextLayoutShiftTracking(false);
+ layout_object->SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(
+ iter->value.has_paint_offset_translation);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
index 61c343f6841..c3d6c106e19 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
@@ -46,11 +46,19 @@ class CORE_EXPORT LayoutShiftTracker final
// |old_rect| and |old_paint_offset| so that we can calculate the correct old
// visual representation and old starting point in the initial containing
// block and the viewport with the new property tree state in most cases.
+ // The adjustment should include the deltas of 2d translations and scrolls,
+ // and LayoutShiftTracker can determine stability by including (by default)
+ // or excluding |translation_delta| and/or |scroll_delta|.
+ //
+ // See renderer/core/layout/layout-shift-tracker-old-paint-offset.md for
+ // more details about |old_paint_offset|.
void NotifyBoxPrePaint(const LayoutBox& box,
const PropertyTreeStateOrAlias& property_tree_state,
const PhysicalRect& old_rect,
const PhysicalRect& new_rect,
const PhysicalOffset& old_paint_offset,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_delta,
const PhysicalOffset& new_paint_offset);
void NotifyTextPrePaint(const LayoutText& text,
@@ -58,6 +66,8 @@ class CORE_EXPORT LayoutShiftTracker final
const LogicalOffset& old_starting_point,
const LogicalOffset& new_starting_point,
const PhysicalOffset& old_paint_offset,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_delta,
const PhysicalOffset& new_paint_offset,
const LayoutUnit logical_height);
@@ -66,6 +76,7 @@ class CORE_EXPORT LayoutShiftTracker final
void NotifyScroll(mojom::blink::ScrollType, ScrollOffset delta);
void NotifyViewportSizeChanged();
void NotifyFindInPageInput();
+ void NotifyChangeEvent();
bool IsActive() const { return is_active_; }
double Score() const { return score_; }
double WeightedScore() const { return weighted_score_; }
@@ -99,6 +110,7 @@ class CORE_EXPORT LayoutShiftTracker final
PhysicalOffset paint_offset;
LayoutSize size;
PhysicalRect visual_overflow_rect;
+ bool has_paint_offset_translation;
};
HeapHashMap<Member<const Node>, Geometry> geometries_before_detach_;
};
@@ -145,11 +157,14 @@ class CORE_EXPORT LayoutShiftTracker final
const PhysicalRect& old_rect,
const PhysicalRect& new_rect,
const FloatPoint& old_starting_point,
+ const FloatSize& translation_delta,
+ const FloatSize& scroll_offset_delta,
const FloatPoint& new_starting_point);
void ReportShift(double score_delta, double weighted_score_delta);
void TimerFired(TimerBase*) {}
std::unique_ptr<TracedValue> PerFrameTraceData(double score_delta,
+ double weighted_score_delta,
bool input_detected) const;
void AttributionsToTracedValue(TracedValue&) const;
double SubframeWeightingFactor() const;
@@ -157,9 +172,13 @@ class CORE_EXPORT LayoutShiftTracker final
void UpdateInputTimestamp(base::TimeTicks timestamp);
LayoutShift::AttributionList CreateAttributionList() const;
void SubmitPerformanceEntry(double score_delta, bool input_detected) const;
+ void NotifyPrePaintFinishedInternal();
+ double LastInputTimestamp() const;
+ void UpdateTimerAndInputTimestamp();
Member<LocalFrameView> frame_view_;
bool is_active_;
+ bool enable_m90_improvements_;
// The document cumulative layout shift (DCLS) score for this LocalFrame,
// unweighted, with move distance applied.
@@ -193,7 +212,7 @@ class CORE_EXPORT LayoutShiftTracker final
// Tracks the short period after an input event during which we ignore shifts
// for the purpose of cumulative scoring, and report them to the web perf API
// with hadRecentInput == true.
- TaskRunnerTimer<LayoutShiftTracker> timer_;
+ HeapTaskRunnerTimer<LayoutShiftTracker> timer_;
// The maximum distance any layout object has moved in the current animation
// frame.
@@ -204,6 +223,7 @@ class CORE_EXPORT LayoutShiftTracker final
float overall_max_distance_;
// Sum of all scroll deltas that occurred in the current animation frame.
+ // TODO(wangxianzhu): Remove when enabling CLSM90Improvements permanently.
ScrollOffset frame_scroll_delta_;
// Whether either a user input or document scroll have been observed during
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
index 659e109bb13..4154b126e23 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
@@ -5,8 +5,11 @@
#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
+#include "third_party/blink/renderer/core/dom/dom_token_list.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
@@ -40,7 +43,7 @@ class LayoutShiftTrackerTest : public RenderingTest {
TEST_F(LayoutShiftTrackerTest, IgnoreAfterInput) {
SetBodyInnerHTML(R"HTML(
<style>
- #j { position: relative; width: 300px; height: 100px; }
+ #j { position: relative; width: 300px; height: 100px; background: blue; }
</style>
<div id='j'></div>
)HTML");
@@ -67,7 +70,7 @@ TEST_F(LayoutShiftTrackerTest, CompositedShiftBeforeFirstPaint) {
.hide { display: none; }
.tr { will-change: transform; }
body { margin: 0; }
- div { height: 100px; }
+ div { height: 100px; background: blue; }
</style>
<div id="container">
<div id="A">A</div>
@@ -97,6 +100,28 @@ TEST_F(LayoutShiftTrackerTest, IgnoreSVG) {
EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
}
+TEST_F(LayoutShiftTrackerTest, IgnoreAfterChangeEvent) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #j { position: relative; width: 300px; height: 100px; background: blue; }
+ </style>
+ <div id='j'></div>
+ <select id="sel" onchange="shift()">
+ <option value="0">0</option>
+ <option value="1">1</option>
+ </select>
+ )HTML");
+ auto* select = To<HTMLSelectElement>(GetDocument().getElementById("sel"));
+ DCHECK(select);
+ select->focus();
+ select->SelectOptionByPopup(1);
+ GetDocument().getElementById("j")->setAttribute(html_names::kStyleAttr,
+ AtomicString("top: 60px"));
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
+}
+
class LayoutShiftTrackerSimTest : public SimTest {
protected:
void SetUp() override {
@@ -121,7 +146,7 @@ TEST_F(LayoutShiftTrackerSimTest, SubframeWeighting) {
child_resource.Complete(R"HTML(
<style>
- #j { position: relative; width: 300px; height: 100px; }
+ #j { position: relative; width: 300px; height: 100px; background: blue; }
</style>
<div id='j'></div>
)HTML");
@@ -401,7 +426,7 @@ TEST_F(LayoutShiftTrackerTest, ContentVisibilityAutoFirstPaint) {
}
</style>
<div id=target class=auto>
- <div style="width: 100px; height: 100px"></div>
+ <div style="width: 100px; height: 100px; background: blue"></div>
</div>
)HTML");
auto* target = To<LayoutBox>(GetLayoutObjectByElementId("target"));
@@ -424,7 +449,7 @@ TEST_F(LayoutShiftTrackerTest,
}
</style>
<div id=target class=auto style="position: relative; top: 100000px">
- <div style="width: 100px; height: 100px"></div>
+ <div style="width: 100px; height: 100px; background: blue"></div>
</div>
)HTML");
auto* target = To<LayoutBox>(GetLayoutObjectByElementId("target"));
@@ -459,7 +484,7 @@ TEST_F(LayoutShiftTrackerTest, ContentVisibilityHiddenFirstPaint) {
}
</style>
<div id=target class=auto>
- <div style="width: 100px; height: 100px"></div>
+ <div style="width: 100px; height: 100px; background: blue"></div>
</div>
)HTML");
auto* target = To<LayoutBox>(GetLayoutObjectByElementId("target"));
@@ -479,6 +504,7 @@ TEST_F(LayoutShiftTrackerTest, ContentVisibilityAutoResize) {
}
.contained {
height: 100px;
+ background: blue;
}
</style>
<div class=auto><div class=contained></div></div>
@@ -503,10 +529,10 @@ TEST_F(LayoutShiftTrackerTest,
}
</style>
<div id=onscreen class=auto>
- <div style="width: 100px; height: 100px"></div>
+ <div style="width: 100px; height: 100px; background: blue"></div>
</div>
<div id=offscreen class=auto style="position: relative; top: 100000px">
- <div style="width: 100px; height: 100px"></div>
+ <div style="width: 100px; height: 100px; background: blue"></div>
</div>
)HTML");
auto* offscreen = To<LayoutBox>(GetLayoutObjectByElementId("offscreen"));
@@ -569,7 +595,7 @@ TEST_F(LayoutShiftTrackerTest, NestedFixedPos) {
SetBodyInnerHTML(R"HTML(
<div id=parent style="position: fixed; top: 0; left: -100%; width: 100%">
<div id=target style="position: fixed; top: 0; width: 100%; height: 100%;
- left: 0"></div>
+ left: 0"; background: blue></div>
</div>
<div style="height: 5000px"></div>
</div>
@@ -585,4 +611,186 @@ TEST_F(LayoutShiftTrackerTest, NestedFixedPos) {
EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
}
+TEST_F(LayoutShiftTrackerTest, ClipByVisualViewport) {
+ SetHtmlInnerHTML(R"HTML(
+ <meta name="viewport" content="width=200, initial-scale=2">
+ <style>
+ #target {
+ position: absolute;
+ top: 0;
+ left: 150px;
+ width: 200px;
+ height: 200px;
+ background: blue;
+ }
+ </style>
+ <div id=target></div>
+ )HTML");
+
+ GetDocument().GetPage()->GetVisualViewport().SetSize(IntSize(200, 500));
+ GetDocument().GetPage()->GetVisualViewport().SetLocation(FloatPoint(0, 100));
+ UpdateAllLifecyclePhasesForTest();
+ // The visual viewport.
+ EXPECT_EQ(IntRect(0, 100, 200, 500),
+ GetDocument().View()->GetScrollableArea()->VisibleContentRect());
+ // The layout viewport .
+ EXPECT_EQ(IntRect(0, 0, 800, 600),
+ GetDocument().View()->LayoutViewport()->VisibleContentRect());
+ EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
+
+ GetDocument().getElementById("target")->setAttribute(html_names::kStyleAttr,
+ "top: 100px");
+ UpdateAllLifecyclePhasesForTest();
+ // 50.0: visible width
+ // 100.0 + 100.0: visible height + vertical shift
+ // 200.0 * 500.0: visual viewport area
+ // 100.0 / 500.0: shift distance fraction
+ EXPECT_FLOAT_EQ(50.0 * (100.0 + 100.0) / (200.0 * 500.0) * (100.0 / 500.0),
+ GetLayoutShiftTracker().Score());
+}
+
+TEST_F(LayoutShiftTrackerTest, ScrollThenCauseScrollAnchoring) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .big {
+ width: 100px;
+ height: 500px;
+ background: blue;
+ }
+ .small {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+ <div class=big id=target></div>
+ <div class=big></div>
+ <div class=big></div>
+ <div class=big></div>
+ <div class=big></div>
+ <div class=big></div>
+ )HTML");
+ auto* target_element = GetDocument().getElementById("target");
+
+ // Scroll the window which accumulates a scroll in the layout shift tracker.
+ GetDocument().domWindow()->scrollBy(0, 1000);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
+
+ target_element->classList().Remove("big");
+ target_element->classList().Add("small");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
+
+ target_element->classList().Remove("small");
+ target_element->classList().Add("big");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
+}
+
+TEST_F(LayoutShiftTrackerTest, NeedsToTrack) {
+ SetBodyInnerHTML(R"HTML(
+ <style>* { width: 50px; height: 50px; }</style>
+ <div id="tiny" style="width: 0.3px; height: 0.3px; background: blue"></div>
+ <div id="sticky" style="background: blue; position: sticky"></div>
+
+ <!-- block with decoration -->
+ <div id="scroll" style="overflow: scroll"></div>
+ <div id="background" style="background: blue"></div>
+ <div id="border" style="border: 1px solid black"></div>
+ <div id="outline" style="outline: 1px solid black"></div>
+ <div id="shadow" style="box-shadow: 2px 2px black"></div>
+
+ <!-- block with block children, some invisible -->
+ <div id="hidden-parent">
+ <div id="hidden" style="background: blue; visibility: hidden">
+ <div id="visible-under-hidden"
+ style="background:blue; visibility: visible"></div>
+ </div>
+ </div>
+
+ <!-- block with inline children, some invisible -->
+ <div id="empty-parent">
+ <div id="empty"></div>
+ </div>
+ <div id="text-block">Text</div>
+ <br id="br">
+
+ <svg id="svg">
+ <rect id="svg-rect" width="10" height="10" fill="green">
+ </svg>
+
+ <!-- replaced, special blocks, etc. -->
+ <video id="video"></video>
+ <img id="img">
+ <textarea id="textarea">Text</textarea>
+ <input id="text-input" type="text">
+ <input id="file" type="file">
+ <input id="radio" type="radio">
+ <progress id="progress"></progress>
+ <ul>
+ <li id="li"></li>
+ </ul>
+ <hr id="hr">
+ )HTML");
+
+ const auto& tracker = GetLayoutShiftTracker();
+ EXPECT_FALSE(tracker.NeedsToTrack(GetLayoutView()));
+ EXPECT_FALSE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("tiny")));
+ EXPECT_FALSE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("sticky")));
+
+ // Blocks with decorations.
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("scroll")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("background")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("border")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("outline")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("shadow")));
+
+ // Blocks with block children, some invisible. We don't check descendants for
+ // visibility. Just assume there are visible descendants.
+ EXPECT_TRUE(
+ tracker.NeedsToTrack(*GetLayoutObjectByElementId("empty-parent")));
+ EXPECT_FALSE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("empty")));
+ EXPECT_TRUE(
+ tracker.NeedsToTrack(*GetLayoutObjectByElementId("hidden-parent")));
+ EXPECT_FALSE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("hidden")));
+ EXPECT_TRUE(tracker.NeedsToTrack(
+ *GetLayoutObjectByElementId("visible-under-hidden")));
+
+ // Blocks with inline children, some invisible. We don't check descendants for
+ // visibility. Just assume there are visible descendants.
+ auto* text_block = To<LayoutBlock>(GetLayoutObjectByElementId("text-block"));
+ EXPECT_TRUE(tracker.NeedsToTrack(*text_block));
+ // No ContainingBlockScope.
+ EXPECT_FALSE(tracker.NeedsToTrack(*text_block->FirstChild()));
+ {
+ LayoutShiftTracker::ContainingBlockScope scope(
+ PhysicalSize(1, 2), PhysicalSize(2, 3), PhysicalRect(1, 2, 3, 4),
+ PhysicalRect(2, 3, 4, 5));
+ EXPECT_TRUE(tracker.NeedsToTrack(*text_block->FirstChild()));
+ }
+ auto* br = GetLayoutObjectByElementId("br");
+ EXPECT_FALSE(tracker.NeedsToTrack(*br));
+ EXPECT_TRUE(br->Parent()->IsAnonymous());
+ EXPECT_FALSE(tracker.NeedsToTrack(*br->Parent()));
+
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("svg")));
+ // We don't track SVG children.
+ EXPECT_FALSE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("svg-rect")));
+
+ // Replaced, special blocks, etc.
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("video")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("img")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("textarea")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("text-input")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("file")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("radio")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("progress")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("li")));
+ EXPECT_TRUE(tracker.NeedsToTrack(*GetLayoutObjectByElementId("hr")));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.cc b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
index 0fda8879716..7216241b30e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
@@ -1267,7 +1267,7 @@ LayoutTableCol* LayoutTable::FirstColumn() const {
for (LayoutObject* child = FirstChild(); child;
child = child->NextSibling()) {
if (child->IsLayoutTableCol())
- return ToLayoutTableCol(child);
+ return To<LayoutTableCol>(child);
}
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.h b/chromium/third_party/blink/renderer/core/layout/layout_table.h
index 255f2d7b8fd..7720de0b493 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.h
@@ -676,7 +676,9 @@ inline LayoutTableSection* LayoutTable::TopSection() const {
// To<LayoutTable>() helper.
template <>
struct DowncastTraits<LayoutTable> {
- static bool AllowFrom(const LayoutObject& object) { return object.IsTable(); }
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsTable() && !object.IsLayoutNGObject();
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
index 27a46da2941..e30bc902da2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -443,7 +443,7 @@ OverflowClipAxes LayoutTableCell::ComputeOverflowClipAxes() const {
NOT_DESTROYED();
if (IsSpanningCollapsedRow() || IsSpanningCollapsedColumn())
return kOverflowClipBothAxis;
- return LayoutBox::ComputeOverflowClipAxes();
+ return LayoutBlockFlow::ComputeOverflowClipAxes();
}
LayoutUnit LayoutTableCell::CellBaselinePosition() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
index 702fe2ca2dc..b78f54a2dbb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
@@ -133,7 +133,7 @@ LayoutTableCol* LayoutTableCol::EnclosingColumnGroup() const {
if (!Parent()->IsLayoutTableCol())
return nullptr;
- LayoutTableCol* parent_column_group = ToLayoutTableCol(Parent());
+ auto* parent_column_group = To<LayoutTableCol>(Parent());
DCHECK(parent_column_group->IsTableColumnGroup());
DCHECK(IsTableColumn());
return parent_column_group;
@@ -144,7 +144,7 @@ LayoutTableCol* LayoutTableCol::NextColumn() const {
// If |this| is a column-group, the next column is the colgroup's first child
// column.
if (LayoutObject* first_child = FirstChild())
- return ToLayoutTableCol(first_child);
+ return To<LayoutTableCol>(first_child);
// Otherwise it's the next column along.
LayoutObject* next = NextSibling();
@@ -157,7 +157,7 @@ LayoutTableCol* LayoutTableCol::NextColumn() const {
for (; next && !next->IsLayoutTableCol(); next = next->NextSibling()) {
}
- return ToLayoutTableCol(next);
+ return To<LayoutTableCol>(next);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_col.h b/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
index f43776fa8c7..8e6074b7c91 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
@@ -127,7 +127,12 @@ class LayoutTableCol final : public LayoutTableBoxComponent {
unsigned span_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTableCol, IsLayoutTableCol());
+template <>
+struct DowncastTraits<LayoutTableCol> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsLayoutTableCol() && !object.IsLayoutNGObject();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_col_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_col_test.cc
index 0a648fd98f9..bcbe489eb6b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_col_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_col_test.cc
@@ -20,7 +20,15 @@ TEST_F(LayoutTableColTest, LocalVisualRect) {
</table>
)HTML");
- EXPECT_TRUE(GetLayoutObjectByElementId("col1")->LocalVisualRect().IsEmpty());
+ // TablesNG hidden columns get geometry, because they paint their background
+ // into cells.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_FALSE(
+ GetLayoutObjectByElementId("col1")->LocalVisualRect().IsEmpty());
+ } else {
+ EXPECT_TRUE(
+ GetLayoutObjectByElementId("col1")->LocalVisualRect().IsEmpty());
+ }
EXPECT_TRUE(GetLayoutObjectByElementId("col2")->LocalVisualRect().IsEmpty());
EXPECT_TRUE(GetLayoutObjectByElementId("col3")->LocalVisualRect().IsEmpty());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
index 494a2f3646c..8a2acfdf94f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
@@ -228,7 +228,7 @@ class CORE_EXPORT LayoutTableRow final : public LayoutTableBoxComponent,
template <>
struct DowncastTraits<LayoutTableRow> {
static bool AllowFrom(const LayoutObject& object) {
- return object.IsTableRow();
+ return object.IsTableRow() && !object.IsLayoutNGObject();
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_row_test.cc
index 4d5dd5baa07..2b5664346b9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row_test.cc
@@ -143,16 +143,32 @@ TEST_F(LayoutTableRowTest, VisualOverflow) {
)HTML");
auto* row1 = GetRowByElementId("row1");
- EXPECT_EQ(LayoutRect(120, 0, 210, 320), row1->ContentsVisualOverflowRect());
- EXPECT_EQ(LayoutRect(0, 0, 450, 320), row1->SelfVisualOverflowRect());
-
+ // TablesNG row geometry does not include border spacing. Legacy does.
+ // All row geometry expectations are different.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(LayoutRect(110, 0, 210, 320), row1->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 430, 320), row1->SelfVisualOverflowRect());
+ } else {
+ EXPECT_EQ(LayoutRect(120, 0, 210, 320), row1->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 450, 320), row1->SelfVisualOverflowRect());
+ }
auto* row2 = GetRowByElementId("row2");
- EXPECT_EQ(LayoutRect(0, -10, 440, 220), row2->ContentsVisualOverflowRect());
- EXPECT_EQ(LayoutRect(0, 0, 450, 210), row2->SelfVisualOverflowRect());
-
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(LayoutRect(-10, -10, 440, 220),
+ row2->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 430, 210), row2->SelfVisualOverflowRect());
+ } else {
+ EXPECT_EQ(LayoutRect(0, -10, 440, 220), row2->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 450, 210), row2->SelfVisualOverflowRect());
+ }
auto* row3 = GetRowByElementId("row3");
- EXPECT_EQ(LayoutRect(), row3->ContentsVisualOverflowRect());
- EXPECT_EQ(LayoutRect(0, 0, 450, 100), row3->SelfVisualOverflowRect());
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(LayoutRect(), row3->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 430, 100), row3->SelfVisualOverflowRect());
+ } else {
+ EXPECT_EQ(LayoutRect(), row3->ContentsVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 450, 100), row3->SelfVisualOverflowRect());
+ }
}
TEST_F(LayoutTableRowTest, VisualOverflowWithCollapsedBorders) {
@@ -173,17 +189,29 @@ TEST_F(LayoutTableRowTest, VisualOverflowWithCollapsedBorders) {
auto* row = GetRowByElementId("row");
- // The row's self visual overflow covers the collapsed borders.
LayoutRect expected_self_visual_overflow = row->BorderBoxRect();
- expected_self_visual_overflow.ExpandEdges(LayoutUnit(1), LayoutUnit(8),
- LayoutUnit(5), LayoutUnit(0));
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ // Row's visual overflow does not include collapsed borders.
+ // They are painted by the table.
+ } else {
+ // The row's self visual overflow covers the collapsed borders.
+ expected_self_visual_overflow.ExpandEdges(LayoutUnit(1), LayoutUnit(8),
+ LayoutUnit(5), LayoutUnit(0));
+ }
EXPECT_EQ(expected_self_visual_overflow, row->SelfVisualOverflowRect());
- // The row's visual overflow covers self visual overflow and visual overflows
- // of all cells.
LayoutRect expected_visual_overflow = row->BorderBoxRect();
- expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(8),
- LayoutUnit(5), LayoutUnit(3));
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ // Row's visual overflow does not include collapsed borders.
+ // It does include visual overflow of all cells.
+ expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(0),
+ LayoutUnit(3), LayoutUnit(3));
+ } else {
+ // The row's visual overflow covers self visual overflow and visual
+ // overflows of all cells.
+ expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(8),
+ LayoutUnit(5), LayoutUnit(3));
+ }
EXPECT_EQ(expected_visual_overflow, row->VisualOverflowRect());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
index 1851331f540..5d96a9f30fc 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -446,7 +446,7 @@ void LayoutTableSection::DistributeWholeExtraRowSpanHeightToPercentRows(
row_pos_[row + 1] += accumulated_position_increase;
}
- DCHECK(!round(remainder)) << "remainder was " << remainder;
+ DCHECK_LT(remainder, 2.0) << "remainder was " << remainder;
extra_row_spanning_height -= accumulated_position_increase;
}
@@ -477,7 +477,7 @@ void LayoutTableSection::DistributeExtraRowSpanHeightToAutoRows(
row_pos_[row + 1] += accumulated_position_increase;
}
- DCHECK(!round(remainder)) << "remainder was " << remainder;
+ DCHECK_LT(remainder, 2.0) << "remainder was " << remainder;
extra_row_spanning_height -= accumulated_position_increase;
}
@@ -509,7 +509,7 @@ void LayoutTableSection::DistributeExtraRowSpanHeightToRemainingRows(
row_pos_[row + 1] += accumulated_position_increase;
}
- DCHECK(!round(remainder)) << "remainder was " << remainder;
+ DCHECK_LT(remainder, 2.0) << "remainder was " << remainder;
extra_row_spanning_height -= accumulated_position_increase;
}
@@ -779,7 +779,7 @@ void LayoutTableSection::DistributeRowSpanHeightToRows(
spanning_rows_height.row_height);
}
- DCHECK(!extra_row_spanning_height);
+ DCHECK_LT(abs(extra_row_spanning_height), 2);
// Getting total changed height in the table
extra_height_to_propagate =
@@ -1227,7 +1227,8 @@ void LayoutTableSection::LayoutRows() {
if (LayoutTableRow* next_row_object = grid_[r + 1].row)
row_logical_height -= next_row_object->PaginationStrut();
}
- DCHECK_GE(row_logical_height, 0);
+ // crbug.com/1175700
+ row_logical_height = std::max(row_logical_height, LayoutUnit());
row->SetLogicalHeight(row_logical_height);
row->UpdateAfterLayout();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
index 82438585b17..3ffbae560a9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
@@ -564,7 +564,7 @@ class CORE_EXPORT LayoutTableSection final
template <>
struct DowncastTraits<LayoutTableSection> {
static bool AllowFrom(const LayoutObject& object) {
- return object.IsTableSection();
+ return object.IsTableSection() && !object.IsLayoutNGObject();
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
index 5d2c7938d09..a1b5e4de6de 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section_test.cc
@@ -14,11 +14,14 @@ namespace {
class LayoutTableSectionTest : public RenderingTest {
protected:
LayoutTableSection* GetSectionByElementId(const char* id) {
- // TODO(958381) Needs to TableNG compatible with
- // LayoutNGTableSectionInterface.
+ DCHECK(!RuntimeEnabledFeatures::LayoutNGTableEnabled());
return To<LayoutTableSection>(GetLayoutObjectByElementId(id));
}
+ LayoutBox* GetSectionByElementIdAsBox(const char* id) {
+ return To<LayoutBox>(GetLayoutObjectByElementId(id));
+ }
+
LayoutTableSection* CreateSection(unsigned rows, unsigned columns) {
auto* table = GetDocument().CreateRawElement(html_names::kTableTag);
GetDocument().body()->appendChild(table);
@@ -48,7 +51,7 @@ TEST_F(LayoutTableSectionTest,
</table>
)HTML");
- auto* section = GetSectionByElementId("section");
+ auto* section = GetSectionByElementIdAsBox("section");
EXPECT_TRUE(section);
EXPECT_FALSE(
section->BackgroundIsKnownToBeOpaqueInRect(PhysicalRect(0, 0, 1, 1)));
@@ -63,7 +66,7 @@ TEST_F(LayoutTableSectionTest, BackgroundIsKnownToBeOpaqueWithBorderSpacing) {
</table>
)HTML");
- auto* section = GetSectionByElementId("section");
+ auto* section = GetSectionByElementIdAsBox("section");
EXPECT_TRUE(section);
EXPECT_FALSE(
section->BackgroundIsKnownToBeOpaqueInRect(PhysicalRect(0, 0, 1, 1)));
@@ -79,7 +82,7 @@ TEST_F(LayoutTableSectionTest, BackgroundIsKnownToBeOpaqueWithEmptyCell) {
</table>
)HTML");
- auto* section = GetSectionByElementId("section");
+ auto* section = GetSectionByElementIdAsBox("section");
EXPECT_TRUE(section);
EXPECT_FALSE(
section->BackgroundIsKnownToBeOpaqueInRect(PhysicalRect(0, 0, 1, 1)));
@@ -316,7 +319,7 @@ TEST_F(LayoutTableSectionTest, VisualOverflowWithCollapsedBorders) {
</table>
)HTML");
- auto* section = GetSectionByElementId("section");
+ auto* section = GetSectionByElementIdAsBox("section");
// The section's self visual overflow doesn't cover the collapsed borders.
EXPECT_EQ(section->BorderBoxRect(), section->SelfVisualOverflowRect());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
index 1a1850e01fb..d83883d77c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
@@ -13,9 +13,11 @@ namespace {
class LayoutTableTest : public RenderingTest {
protected:
- // TODO(958381) Make these tests TableNG compatible.
- LayoutTable* GetTableByElementId(const char* id) {
- return To<LayoutTable>(GetLayoutObjectByElementId(id));
+ LayoutBlock* GetTableByElementId(const char* id) {
+ return To<LayoutBlock>(GetLayoutObjectByElementId(id));
+ }
+ LayoutNGTableInterface* GetTableInterfaceByElementId(const char* id) {
+ return ToInterface<LayoutNGTableInterface>(GetLayoutObjectByElementId(id));
}
};
@@ -78,9 +80,16 @@ TEST_F(LayoutTableTest, OverflowWithCollapsedBorders) {
LayoutUnit(0), LayoutUnit(10));
EXPECT_EQ(expected_self_visual_overflow,
table->PhysicalSelfVisualOverflowRect());
- // For this table, its layout overflow equals self visual overflow.
- EXPECT_EQ(expected_self_visual_overflow, table->PhysicalLayoutOverflowRect());
-
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(table->PhysicalContentBoxRect(),
+ table->PhysicalLayoutOverflowRect());
+ } else {
+ // In Legacy, visual overflow incorrectly does not include borders
+ // that extend beyond table boundaries.
+ // For this table, its layout overflow equals self visual overflow.
+ EXPECT_EQ(expected_self_visual_overflow,
+ table->PhysicalLayoutOverflowRect());
+ }
// The table's visual overflow covers self visual overflow and content visual
// overflows.
auto expected_visual_overflow = table->PhysicalContentBoxRect();
@@ -131,14 +140,25 @@ TEST_F(LayoutTableTest, CollapsedBorders) {
// Cells have wider borders.
auto* table3 = GetTableByElementId("table3");
- // Cell E's border-top won.
- EXPECT_EQ(7, table3->BorderBefore());
- // Cell H's border-bottom won.
- EXPECT_EQ(20, table3->BorderAfter());
- // Cell E's border-left won.
- EXPECT_EQ(10, table3->BorderStart());
- // Cell F's border-bottom won.
- EXPECT_EQ(13, table3->BorderEnd());
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ // Cell E's border-top won.
+ EXPECT_EQ(LayoutUnit(7.5), table3->BorderBefore());
+ // Cell H's border-bottom won.
+ EXPECT_EQ(20, table3->BorderAfter());
+ // Cell E's border-left won.
+ EXPECT_EQ(LayoutUnit(10.5), table3->BorderStart());
+ // Cell F's border-bottom won.
+ EXPECT_EQ(LayoutUnit(12.5), table3->BorderEnd());
+ } else {
+ // Cell E's border-top won.
+ EXPECT_EQ(7, table3->BorderBefore());
+ // Cell H's border-bottom won.
+ EXPECT_EQ(20, table3->BorderAfter());
+ // Cell E's border-left won.
+ EXPECT_EQ(10, table3->BorderStart());
+ // Cell F's border-bottom won.
+ EXPECT_EQ(13, table3->BorderEnd());
+ }
}
TEST_F(LayoutTableTest, CollapsedBordersWithCol) {
@@ -222,7 +242,11 @@ TEST_F(LayoutTableTest, WidthPercentagesExceedHundred) {
// Table width should be TableLayoutAlgorithm::kMaxTableWidth
auto* table = GetTableByElementId("onlyTable");
- EXPECT_EQ(1000000, table->OffsetWidth());
+ // TablesNG will grow up to LayoutUnit::Max()
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(2000000, table->OffsetWidth());
+ else
+ EXPECT_EQ(1000000, table->OffsetWidth());
}
TEST_F(LayoutTableTest, CloseToMaxWidth) {
@@ -272,23 +296,22 @@ TEST_F(LayoutTableTest, OutOfOrderHeadAndBody) {
<thead id='head'></thead>
<table>
)HTML");
- auto* table = GetTableByElementId("table");
+ auto* table = GetTableInterfaceByElementId("table");
EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("head"))
- ->ToLayoutObject(),
- table->TopSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->TopNonEmptySection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->BottomSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->BottomNonEmptySection());
+ GetLayoutObjectByElementId("head")),
+ table->TopSectionInterface());
+ // TablesNG does not implement these APIs. They are only used by Legacy.
+ if (!RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("body")),
+ table->TopNonEmptySectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("body")),
+ table->BottomSectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("body")),
+ table->BottomNonEmptySectionInterface());
+ }
}
TEST_F(LayoutTableTest, OutOfOrderFootAndBody) {
@@ -298,23 +321,22 @@ TEST_F(LayoutTableTest, OutOfOrderFootAndBody) {
<tbody id='body'><tr><td>Body</td></tr></tbody>
<table>
)HTML");
- auto* table = GetTableByElementId("table");
+ auto* table = GetTableInterfaceByElementId("table");
EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->TopSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->TopNonEmptySection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("foot"))
- ->ToLayoutObject(),
- table->BottomSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("body"))
- ->ToLayoutObject(),
- table->BottomNonEmptySection());
+ GetLayoutObjectByElementId("body")),
+ table->TopSectionInterface());
+ // TablesNG does not implement these APIs. They are only used by Legacy.
+ if (!RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("body")),
+ table->TopNonEmptySectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("foot")),
+ table->BottomSectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("body")),
+ table->BottomNonEmptySectionInterface());
+ }
}
TEST_F(LayoutTableTest, OutOfOrderHeadFootAndBody) {
@@ -325,23 +347,22 @@ TEST_F(LayoutTableTest, OutOfOrderHeadFootAndBody) {
<tbody id='body'><tr><td>Body</td></tr></tbody>
<table>
)HTML");
- auto* table = GetTableByElementId("table");
+ auto* table = GetTableInterfaceByElementId("table");
EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("head"))
- ->ToLayoutObject(),
- table->TopSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("head"))
- ->ToLayoutObject(),
- table->TopNonEmptySection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("foot"))
- ->ToLayoutObject(),
- table->BottomSection());
- EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
- GetLayoutObjectByElementId("foot"))
- ->ToLayoutObject(),
- table->BottomNonEmptySection());
+ GetLayoutObjectByElementId("head")),
+ table->TopSectionInterface());
+ // TablesNG does not implement these APIs. They are only used by Legacy.
+ if (!RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("head")),
+ table->TopNonEmptySectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("foot")),
+ table->BottomSectionInterface());
+ EXPECT_EQ(ToInterface<LayoutNGTableSectionInterface>(
+ GetLayoutObjectByElementId("foot")),
+ table->BottomNonEmptySectionInterface());
+ }
}
TEST_F(LayoutTableTest, VisualOverflowCleared) {
@@ -362,6 +383,10 @@ TEST_F(LayoutTableTest, VisualOverflowCleared) {
}
TEST_F(LayoutTableTest, HasNonCollapsedBorderDecoration) {
+ // TablesNG does not support DirtiedRowsAndEffectiveColumns.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ return;
+
SetBodyInnerHTML("<table id='table'></table>");
auto* table = GetTableByElementId("table");
EXPECT_FALSE(table->HasNonCollapsedBorderDecoration());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
index 12dfd14f1d0..f694b87da32 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
@@ -59,12 +59,9 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
#include "third_party/blink/renderer/platform/fonts/character_range.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -173,14 +170,10 @@ LayoutText::LayoutText(Node* node, scoped_refptr<StringImpl> str)
LayoutText::~LayoutText() {
#if DCHECK_IS_ON()
- if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- DCHECK(!first_paint_fragment_);
- else
- DCHECK(!first_fragment_item_index_);
- } else {
+ if (IsInLayoutNGInlineFormattingContext())
+ DCHECK(!first_fragment_item_index_);
+ else
text_boxes_.AssertIsEmpty();
- }
#endif
}
@@ -195,6 +188,18 @@ LayoutText* LayoutText::CreateEmptyAnonymous(
return text;
}
+LayoutText* LayoutText::CreateAnonymous(
+ Document& doc,
+ scoped_refptr<const ComputedStyle> style,
+ scoped_refptr<StringImpl> text,
+ LegacyLayout legacy) {
+ LayoutText* layout_text =
+ LayoutObjectFactory::CreateText(nullptr, std::move(text), legacy);
+ layout_text->SetDocumentForAnonymous(&doc);
+ layout_text->SetStyle(std::move(style));
+ return layout_text;
+}
+
bool LayoutText::IsWordBreak() const {
NOT_DESTROYED();
return false;
@@ -252,26 +257,15 @@ void LayoutText::RemoveAndDestroyTextBoxes() {
} else {
if (Parent())
Parent()->DirtyLinesFromChangedChild(this);
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (FirstInlineFragmentItemIndex()) {
- DetachAbstractInlineTextBoxesIfNeeded();
- NGFragmentItems::LayoutObjectWillBeDestroyed(*this);
- ClearFirstInlineFragmentItemIndex();
- }
- } else if (NGPaintFragment* first_inline_fragment =
- FirstInlineFragment()) {
- first_inline_fragment->LayoutObjectWillBeDestroyed();
- SetFirstInlineFragment(nullptr);
+ if (FirstInlineFragmentItemIndex()) {
+ DetachAbstractInlineTextBoxesIfNeeded();
+ NGFragmentItems::LayoutObjectWillBeDestroyed(*this);
+ ClearFirstInlineFragmentItemIndex();
}
}
- } else if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (FirstInlineFragmentItemIndex()) {
- DetachAbstractInlineTextBoxesIfNeeded();
- ClearFirstInlineFragmentItemIndex();
- }
- } else if (NGPaintFragment* first_inline_fragment = FirstInlineFragment()) {
- // Still do this to clear the global hash map in NGAbstractInlineTextBox.
- SetFirstInlineFragment(nullptr);
+ } else if (FirstInlineFragmentItemIndex()) {
+ DetachAbstractInlineTextBoxesIfNeeded();
+ ClearFirstInlineFragmentItemIndex();
}
DeleteTextBoxes();
}
@@ -323,11 +317,6 @@ void LayoutText::DetachAbstractInlineTextBoxes() {
// NGAbstractInlineTextBox for them.
DCHECK(has_abstract_inline_text_box_);
has_abstract_inline_text_box_ = false;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- for (NGPaintFragment* fragment : NGPaintFragment::InlineFragmentsFor(this))
- NGAbstractInlineTextBox::WillDestroy(fragment);
- return;
- }
// TODO(yosin): Make sure we call this function within valid containg block
// of |this|.
NGInlineCursor cursor;
@@ -335,18 +324,9 @@ void LayoutText::DetachAbstractInlineTextBoxes() {
NGAbstractInlineTextBox::WillDestroy(cursor);
}
-void LayoutText::SetFirstInlineFragment(NGPaintFragment* first_fragment) {
- NOT_DESTROYED();
- CHECK(IsInLayoutNGInlineFormattingContext());
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- DetachAbstractInlineTextBoxesIfNeeded();
- first_paint_fragment_ = first_fragment;
-}
-
void LayoutText::ClearFirstInlineFragmentItemIndex() {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DetachAbstractInlineTextBoxesIfNeeded();
first_fragment_item_index_ = 0u;
}
@@ -355,7 +335,6 @@ void LayoutText::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
NOT_DESTROYED();
CHECK(IsInLayoutNGInlineFormattingContext());
// TODO(yosin): Call |NGAbstractInlineTextBox::WillDestroy()|.
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
DetachAbstractInlineTextBoxesIfNeeded();
first_fragment_item_index_ = index;
@@ -363,22 +342,14 @@ void LayoutText::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
void LayoutText::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
NOT_DESTROYED();
- if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- SetFirstInlineFragment(nullptr);
- } else {
- ClearFirstInlineFragmentItemIndex();
- }
- } else {
+ if (IsInLayoutNGInlineFormattingContext())
+ ClearFirstInlineFragmentItemIndex();
+ else
DeleteTextBoxes();
- }
// Because |first_paint_fragment_| and |text_boxes_| are union, when one is
// deleted, the other should be initialized to nullptr.
- DCHECK(new_value ? (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()
- ? !first_fragment_item_index_
- : !first_paint_fragment_)
- : !text_boxes_.First());
+ DCHECK(new_value ? !first_fragment_item_index_ : !text_boxes_.First());
// Because there are no inline boxes associated to this text, we should not
// have abstract inline text boxes too.
@@ -397,9 +368,9 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
- // TODO(yosin): We should introduce
- // |NGPhysicalTextFragment::IsTruncated()| to skip them instead of using
- // |IsHiddenForPaint()| with ordering of fragments.
+ // TODO(yosin): We should introduce |NGFragmentItem::IsTruncated()| to
+ // skip them instead of using |IsHiddenForPaint()| with ordering of
+ // fragments.
if (cursor.Current().IsHiddenForPaint()) {
in_hidden_for_paint = true;
} else if (in_hidden_for_paint) {
@@ -433,7 +404,8 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
// Compute rect of the legacy text box.
LayoutRect rect =
cursor.CurrentLocalRect(clamped_start, clamped_end).ToLayoutRect();
- rect.MoveBy(cursor.Current().OffsetInContainerBlock().ToLayoutPoint());
+ rect.MoveBy(
+ cursor.Current().OffsetInContainerFragment().ToLayoutPoint());
// Compute start of the legacy text box.
if (unit.AssociatedNode()) {
@@ -465,12 +437,8 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
bool LayoutText::HasInlineFragments() const {
NOT_DESTROYED();
- if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return first_paint_fragment_;
+ if (IsInLayoutNGInlineFormattingContext())
return first_fragment_item_index_;
- }
-
return FirstTextBox();
}
@@ -482,8 +450,20 @@ scoped_refptr<StringImpl> LayoutText::OriginalText() const {
String LayoutText::PlainText() const {
NOT_DESTROYED();
- if (GetNode())
+ if (GetNode()) {
+ if (const NGOffsetMapping* mapping = GetNGOffsetMapping()) {
+ StringBuilder result;
+ for (const NGOffsetMappingUnit& unit :
+ mapping->GetMappingUnitsForNode(*GetNode())) {
+ result.Append(
+ StringView(mapping->GetText(), unit.TextContentStart(),
+ unit.TextContentEnd() - unit.TextContentStart()));
+ }
+ return result.ToString();
+ }
+ // TODO(crbug.com/591099): Remove this branch when legacy layout is removed.
return blink::PlainText(EphemeralRange::RangeOfContents(*GetNode()));
+ }
// FIXME: this is just a stopgap until TextIterator is adapted to support
// generated text.
@@ -570,7 +550,7 @@ void LayoutText::CollectLineBoxRects(const PhysicalRectCollector& yield,
if (cursor.Current().IsHiddenForPaint())
continue;
}
- yield(cursor.Current().RectInContainerBlock());
+ yield(cursor.Current().RectInContainerFragment());
}
return;
}
@@ -862,17 +842,39 @@ CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(
PositionWithAffinity LayoutText::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+ // NG codepath requires |kPrePaintClean|.
+ // |SelectionModifier| calls this only in legacy codepath.
+ DCHECK(!IsLayoutNGObject() || GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kPrePaintClean);
+
if (IsInLayoutNGInlineFormattingContext()) {
// Because of Texts in "position:relative" can be outside of line box, we
// attempt to find a fragment containing |point|.
// See All/LayoutViewHitTestTest.HitTestHorizontal/* and
// All/LayoutViewHitTestTest.HitTestVerticalRL/*
NGInlineCursor cursor;
- for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
- if (!EnclosingIntRect(cursor.Current().RectInContainerBlock())
- .Contains(FlooredIntPoint(point)))
+ cursor.MoveTo(*this);
+ const LayoutBlockFlow* containing_block_flow = cursor.GetLayoutBlockFlow();
+ DCHECK(containing_block_flow);
+ PhysicalOffset point_in_contents = point;
+ if (containing_block_flow->IsScrollContainer()) {
+ point_in_contents += PhysicalOffset(
+ containing_block_flow->PixelSnappedScrolledContentOffset());
+ }
+ const NGPhysicalBoxFragment* container_fragment = nullptr;
+ PhysicalOffset point_in_container_fragment;
+ for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+ DCHECK(&cursor.ContainerFragment());
+ if (container_fragment != &cursor.ContainerFragment()) {
+ container_fragment = &cursor.ContainerFragment();
+ point_in_container_fragment =
+ point_in_contents - container_fragment->OffsetFromOwnerLayoutBox();
+ }
+ if (!EnclosingIntRect(cursor.Current().RectInContainerFragment())
+ .Contains(FlooredIntPoint(point_in_container_fragment)))
continue;
- if (auto position_with_affinity = cursor.PositionForPointInChild(point)) {
+ if (auto position_with_affinity =
+ cursor.PositionForPointInChild(point_in_container_fragment)) {
// Note: Due by Bidi adjustment, |position| isn't relative to this.
const Position& position = position_with_affinity.GetPosition();
DCHECK(position.IsOffsetInAnchor()) << position;
@@ -883,7 +885,7 @@ PositionWithAffinity LayoutText::PositionForPoint(
}
}
// Try for leading and trailing spaces between lines.
- return ContainingNGBlockFlow()->PositionForPoint(*this, point);
+ return containing_block_flow->PositionForPoint(point);
}
DCHECK(CanUseInlineBox(*this));
@@ -1727,7 +1729,7 @@ PhysicalOffset LayoutText::FirstLineBoxTopLeft() const {
return PhysicalOffset();
NGInlineCursor cursor;
cursor.MoveTo(*this);
- return cursor ? cursor.Current().OffsetInContainerBlock()
+ return cursor ? cursor.Current().OffsetInContainerFragment()
: PhysicalOffset();
}
if (const auto* text_box = FirstTextBox()) {
@@ -1750,10 +1752,11 @@ void LayoutText::LogicalStartingPointAndHeight(
cursor.MoveTo(*this);
if (!cursor)
return;
- PhysicalOffset physical_offset = cursor.Current().OffsetInContainerBlock();
+ PhysicalOffset physical_offset =
+ cursor.Current().OffsetInContainerFragment();
if (StyleRef().GetWritingDirection().IsHorizontalLtr()) {
cursor.MoveToLastForSameLayoutObject();
- logical_height = cursor.Current().RectInContainerBlock().Bottom() -
+ logical_height = cursor.Current().RectInContainerFragment().Bottom() -
physical_offset.top;
logical_starting_point = {physical_offset.left, physical_offset.top};
return;
@@ -1762,7 +1765,8 @@ void LayoutText::LogicalStartingPointAndHeight(
logical_starting_point = physical_offset.ConvertToLogical(
StyleRef().GetWritingDirection(), outer_size, cursor.Current().Size());
cursor.MoveToLastForSameLayoutObject();
- PhysicalRect last_physical_rect = cursor.Current().RectInContainerBlock();
+ PhysicalRect last_physical_rect =
+ cursor.Current().RectInContainerFragment();
LogicalOffset logical_ending_point =
WritingModeConverter(StyleRef().GetWritingDirection(), outer_size)
.ToLogical(last_physical_rect)
@@ -1778,6 +1782,35 @@ void LayoutText::LogicalStartingPointAndHeight(
}
}
+LayoutUnit LayoutText::PhysicalAreaSize() const {
+ NOT_DESTROYED();
+ // This is not accurate when |this| starts or ends at the middle of a line,
+ // but we prefer performance over accuracy.
+ if (IsInLayoutNGInlineFormattingContext()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ if (!cursor)
+ return LayoutUnit(0);
+ PhysicalRect rect = cursor.Current().RectInContainerFragment();
+ cursor.MoveToLastForSameLayoutObject();
+ rect.Unite(cursor.Current().RectInContainerFragment());
+ return rect.Width() * rect.Height();
+ }
+
+ if (const auto* first_text_box = FirstTextBox()) {
+ if (const auto* last_text_box = LastTextBox()) {
+ LayoutUnit width =
+ std::max(first_text_box->LogicalRight(),
+ last_text_box->LogicalRight()) -
+ std::min(first_text_box->LogicalLeft(), last_text_box->LogicalLeft());
+ LayoutUnit height =
+ last_text_box->LogicalBottom() - first_text_box->LogicalTop();
+ return width * height;
+ }
+ }
+ return LayoutUnit(0);
+}
+
bool LayoutText::CanOptimizeSetText() const {
NOT_DESTROYED();
// If we have only one line of text and "contain: layout size" we can avoid
@@ -2107,11 +2140,8 @@ void LayoutText::TextDidChangeWithoutInvalidation() {
void LayoutText::InvalidateSubtreeLayoutForFontUpdates() {
NOT_DESTROYED();
- if (RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled() &&
- IsFontFallbackValid()) {
+ if (IsFontFallbackValid())
return;
- }
known_to_have_no_overflow_and_no_fallback_fonts_ = false;
valid_ng_items_ = false;
@@ -2254,12 +2284,7 @@ PhysicalRect LayoutText::PhysicalVisualOverflowRect() const {
NOT_DESTROYED();
if (IsInLayoutNGInlineFormattingContext()) {
DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return NGFragmentItem::LocalVisualRectFor(*this);
-
- if (base::Optional<PhysicalRect> rect =
- NGPaintFragment::LocalVisualRectFor(*this))
- return *rect;
+ return NGFragmentItem::LocalVisualRectFor(*this);
}
if (!FirstTextBox())
@@ -2329,8 +2354,8 @@ PhysicalRect LayoutText::LocalSelectionVisualRect() const {
frame_selection.ComputeLayoutSelectionStatus(cursor);
if (status.start == status.end)
continue;
- PhysicalRect item_rect = ComputeLocalSelectionRectForText(cursor, status);
- item_rect.offset += cursor.Current().OffsetInContainerBlock();
+ PhysicalRect item_rect = cursor.CurrentLocalSelectionRectForText(status);
+ item_rect.offset += cursor.Current().OffsetInContainerFragment();
rect.Unite(item_rect);
}
return rect;
@@ -2351,8 +2376,7 @@ PhysicalRect LayoutText::LocalSelectionVisualRect() const {
}
void LayoutText::InvalidateVisualOverflow() {
- DCHECK(IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DCHECK(IsInLayoutNGInlineFormattingContext());
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
cursor.Current()->GetMutableForPainting().InvalidateInkOverflow();
@@ -2671,15 +2695,6 @@ void LayoutText::InvalidateDisplayItemClients(
invalidator.InvalidateDisplayItemClient(*selection_client, reason);
if (IsInLayoutNGInlineFormattingContext()) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- NGInlineCursor cursor;
- for (cursor.MoveTo(*this); cursor;
- cursor.MoveToNextForSameLayoutObject()) {
- invalidator.InvalidateDisplayItemClient(
- *cursor.Current().GetDisplayItemClient(), reason);
- }
- return;
- }
#if DCHECK_IS_ON()
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
@@ -2699,8 +2714,7 @@ const DisplayItemClient* LayoutText::GetSelectionDisplayItemClient() const {
NOT_DESTROYED();
if (!IsSelected())
return nullptr;
- if (IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (IsInLayoutNGInlineFormattingContext()) {
if (const auto* client = GetSelectionDisplayItemClientMap().at(this))
return client;
return GetSelectionDisplayItemClientMap()
@@ -2774,8 +2788,7 @@ void LayoutText::RecalcVisualOverflow() {
// |RecalcVisualOverflow| for each layer, and the containing |LayoutObject|
// should recalculate its |NGFragmentItem|s without traversing descendant
// |LayoutObject|s.
- if (IsInline() && IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ if (IsInline() && IsInLayoutNGInlineFormattingContext())
NOTREACHED();
LayoutObject::RecalcVisualOverflow();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text.h b/chromium/third_party/blink/renderer/core/layout/layout_text.h
index 77343115a29..978b67c5776 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.h
@@ -86,6 +86,11 @@ class CORE_EXPORT LayoutText : public LayoutObject {
scoped_refptr<const ComputedStyle>,
LegacyLayout);
+ static LayoutText* CreateAnonymous(Document&,
+ scoped_refptr<const ComputedStyle>,
+ scoped_refptr<StringImpl>,
+ LegacyLayout legacy);
+
const char* GetName() const override {
NOT_DESTROYED();
return "LayoutText";
@@ -104,8 +109,6 @@ class CORE_EXPORT LayoutText : public LayoutObject {
void RemoveTextBox(InlineTextBox*);
bool HasInlineFragments() const final;
- NGPaintFragment* FirstInlineFragment() const final;
- void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
void ClearFirstInlineFragmentItemIndex() final;
void SetFirstInlineFragmentItemIndex(wtf_size_t) final;
@@ -297,8 +300,8 @@ class CORE_EXPORT LayoutText : public LayoutObject {
bool IsBeforeNonCollapsedCharacter(unsigned) const;
bool IsAfterNonCollapsedCharacter(unsigned) const;
- int CaretMinOffset() const override;
- int CaretMaxOffset() const override;
+ virtual int CaretMinOffset() const;
+ virtual int CaretMaxOffset() const;
unsigned ResolvedTextLength() const;
// True if any character remains after CSS white-space collapsing.
@@ -411,6 +414,9 @@ class CORE_EXPORT LayoutText : public LayoutObject {
void LogicalStartingPointAndHeight(LogicalOffset& logical_starting_point,
LayoutUnit& logical_height) const;
+ // Returns the size of area occupied by this LayoutText.
+ LayoutUnit PhysicalAreaSize() const;
+
// For LayoutShiftTracker. Saves the value of LogicalStartingPoint() value
// during the previous paint invalidation.
LogicalOffset PreviousLogicalStartingPoint() const {
@@ -582,9 +588,6 @@ class CORE_EXPORT LayoutText : public LayoutObject {
// Read the LINE BOXES OWNERSHIP section in the class header comment.
// Valid only when !IsInLayoutNGInlineFormattingContext().
InlineTextBoxList text_boxes_;
- // The first fragment of text boxes associated with this object.
- // Valid only when IsInLayoutNGInlineFormattingContext().
- NGPaintFragment* first_paint_fragment_;
// The index of the first fragment item associated with this object in
// |NGFragmentItems::Items()|. Zero means there are no such item.
// Valid only when IsInLayoutNGInlineFormattingContext().
@@ -597,19 +600,9 @@ inline InlineTextBoxList& LayoutText::MutableTextBoxes() {
return text_boxes_;
}
-inline NGPaintFragment* LayoutText::FirstInlineFragment() const {
- if (!IsInLayoutNGInlineFormattingContext())
- return nullptr;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return first_paint_fragment_;
- NOTREACHED();
- return nullptr;
-}
-
inline wtf_size_t LayoutText::FirstInlineFragmentItemIndex() const {
if (!IsInLayoutNGInlineFormattingContext())
return 0u;
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
return first_fragment_item_index_;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
index 57cd8eb217f..126e71ca962 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -78,7 +78,7 @@ void LayoutTextControl::StyleDidChange(HTMLElement* inner_editor,
}
// The inner editor element uses the LayoutTextControl's ::selection style
- // (see: GetUncachedSelectionStyle in SelectionPaintingUtils.cpp) so ensure
+ // (see: HighlightPseudoStyle in highlight_painting_utils.cc) so ensure
// the inner editor selection is invalidated anytime style changes and a
// ::selection style is or was present on LayoutTextControl.
if (new_style.HasPseudoElementStyle(kPseudoIdSelection) ||
@@ -101,7 +101,6 @@ void LayoutTextControl::HitInnerEditorElement(
HitTestResult& result,
const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset) {
- NOT_DESTROYED();
if (!inner_editor.GetLayoutObject())
return;
@@ -109,7 +108,7 @@ void LayoutTextControl::HitInnerEditorElement(
hit_test_location.Point() - accumulated_offset -
inner_editor.GetLayoutObject()->LocalToAncestorPoint(PhysicalOffset(),
&box);
- result.SetNodeAndPosition(&inner_editor, local_point);
+ result.OverrideNodeAndPosition(&inner_editor, local_point);
}
static const char* const kFontFamiliesWithInvalidCharWidth[] = {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
index cb8cc1f0ca6..e23db67a5ff 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
@@ -424,8 +424,8 @@ TEST_P(ParameterizedLayoutTextFragmentTest, SetTextWithFirstLetter) {
->IsRemainingTextLayoutObject());
ASSERT_TRUE(letter_a.GetLayoutObject()->GetFirstLetterPart());
EXPECT_EQ("a", letter_a.GetLayoutObject()->GetFirstLetterPart()->GetText());
- EXPECT_TRUE(letter_x.GetLayoutObject()->IsTextFragment());
- EXPECT_FALSE(letter_x.GetLayoutObject()->GetFirstLetterPart());
+ EXPECT_FALSE(letter_x.GetLayoutObject())
+ << "We don't have layout text for empty Text node.";
// Make <div>"x" "a"</div>
letter_x.setTextContent("x");
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
index 36571d8b569..014f95f596b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -23,7 +23,6 @@
#include "build/build_config.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
@@ -293,6 +292,26 @@ void LayoutTheme::AdjustStyle(const Element* e, ComputedStyle& style) {
}
String LayoutTheme::ExtraDefaultStyleSheet() {
+ if (RuntimeEnabledFeatures::SummaryListItemEnabled()) {
+ // https://html.spec.whatwg.org/C/#the-details-and-summary-elements
+ // The specification doesn't have |details >| and |:first-of-type|.
+ // We add them because:
+ // - We had provided |summary { display: block }| for a long time,
+ // there are sites using <summary> without details, and they
+ // expect that <summary> is not a list-item.
+ // - Firefox does so.
+ return String(R"CSS(
+details > summary:first-of-type {
+ display: list-item;
+ counter-increment: list-item 0;
+ list-style: disclosure-closed inside;
+}
+
+details[open] > summary:first-of-type {
+ list-style-type: disclosure-open;
+}
+)CSS");
+ }
return g_empty_string;
}
@@ -729,7 +748,8 @@ void LayoutTheme::SetCustomFocusRingColor(const Color& c) {
has_custom_focus_ring_color_ = true;
}
-Color LayoutTheme::FocusRingColor() const {
+Color LayoutTheme::FocusRingColor(
+ mojom::blink::ColorScheme color_scheme) const {
return has_custom_focus_ring_color_ ? custom_focus_ring_color_
: GetTheme().PlatformFocusRingColor();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme.h b/chromium/third_party/blink/renderer/core/layout/layout_theme.h
index 927f9f0084d..8126ea79ac5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.h
@@ -128,7 +128,7 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
bool in_forced_colors_mode,
mojom::blink::ColorScheme color_scheme) const;
- virtual Color FocusRingColor() const;
+ virtual Color FocusRingColor(mojom::blink::ColorScheme color_scheme) const;
virtual Color PlatformFocusRingColor() const { return Color(0, 0, 0); }
void SetCustomFocusRingColor(const Color&);
static Color TapHighlightColor();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_android.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme_android.cc
index 1c2b807ea23..0a82087b899 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_android.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_android.cc
@@ -32,4 +32,20 @@ input[type="range" i]:-internal-has-datalist::-webkit-slider-container {
})CSS";
}
+Color LayoutThemeAndroid::PlatformActiveSelectionBackgroundColor(
+ mojom::blink::ColorScheme color_scheme) const {
+ return color_scheme == mojom::blink::ColorScheme::kDark
+ ? 0xFF99C8FF
+ : LayoutThemeMobile::PlatformActiveSelectionBackgroundColor(
+ color_scheme);
+}
+
+Color LayoutThemeAndroid::PlatformActiveSelectionForegroundColor(
+ mojom::blink::ColorScheme color_scheme) const {
+ return color_scheme == mojom::blink::ColorScheme::kDark
+ ? 0xFF3B3B3B
+ : LayoutThemeMobile::PlatformActiveSelectionForegroundColor(
+ color_scheme);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_android.h b/chromium/third_party/blink/renderer/core/layout/layout_theme_android.h
index bb597bb3454..ed6a72b4f0d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_android.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_android.h
@@ -14,6 +14,10 @@ class LayoutThemeAndroid final : public LayoutThemeMobile {
static scoped_refptr<LayoutTheme> Create();
bool DelegatesMenuListRendering() const override { return true; }
String ExtraDefaultStyleSheet() override;
+ Color PlatformActiveSelectionBackgroundColor(
+ mojom::blink::ColorScheme color_scheme) const override;
+ Color PlatformActiveSelectionForegroundColor(
+ mojom::blink::ColorScheme color_scheme) const override;
private:
~LayoutThemeAndroid() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
index 61bbb5cda6d..40d35d46d2a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
@@ -45,7 +45,7 @@ class LayoutThemeMac final : public LayoutThemeDefault {
mojom::blink::ColorScheme color_scheme) const override;
Color PlatformSpellingMarkerUnderlineColor() const override;
Color PlatformGrammarMarkerUnderlineColor() const override;
- Color FocusRingColor() const override;
+ Color FocusRingColor(mojom::blink::ColorScheme color_scheme) const override;
String DisplayNameForFile(const File& file) const override;
bool PopsMenuByArrowKeys() const override { return true; }
bool PopsMenuByReturnKey() const override { return false; }
@@ -55,6 +55,7 @@ class LayoutThemeMac final : public LayoutThemeDefault {
// Controls color values returned from FocusRingColor().
bool UsesTestModeFocusRingColor() const;
bool IsAccentColorCustomized(mojom::blink::ColorScheme color_scheme) const;
+ Color GetCustomFocusRingColor(mojom::blink::ColorScheme color_scheme) const;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
index ae933729dc7..5c402b8f93c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -96,22 +96,30 @@ bool LayoutThemeMac::IsAccentColorCustomized(
return true;
}
-Color LayoutThemeMac::FocusRingColor() const {
- static const RGBA32 kDefaultFocusRingColor = 0xFF101010;
+Color LayoutThemeMac::GetCustomFocusRingColor(
+ mojom::blink::ColorScheme color_scheme) const {
+ return color_scheme == mojom::blink::ColorScheme::kDark
+ ? SkColorSetRGB(0x99, 0xC8, 0xFF)
+ : LayoutTheme::GetCustomFocusRingColor();
+}
+
+Color LayoutThemeMac::FocusRingColor(
+ mojom::blink::ColorScheme color_scheme) const {
+ static const RGBA32 kDefaultFocusRingColorLight = 0xFF101010;
+ static const RGBA32 kDefaultFocusRingColorDark = 0xFF99C8FF;
if (UsesTestModeFocusRingColor()) {
- return HasCustomFocusRingColor() ? GetCustomFocusRingColor()
- : kDefaultFocusRingColor;
+ return HasCustomFocusRingColor()
+ ? GetCustomFocusRingColor(color_scheme)
+ : color_scheme == mojom::blink::ColorScheme::kDark
+ ? kDefaultFocusRingColorDark
+ : kDefaultFocusRingColorLight;
}
- if (ui::NativeTheme::GetInstanceForWeb()->UsesHighContrastColors()) {
+ if (ui::NativeTheme::GetInstanceForWeb()->UserHasContrastPreference()) {
// When high contrast is enabled, #101010 should be used.
return Color(0xFF101010);
}
- // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
- mojom::blink::ColorScheme color_scheme =
- ComputedStyle::InitialStyle().UsedColorScheme();
-
SkColor keyboard_focus_indicator = SkColor(
GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator, color_scheme));
Color focus_ring =
@@ -123,7 +131,7 @@ Color LayoutThemeMac::FocusRingColor() const {
// Use the custom focus ring color when the system accent color wasn't
// changed.
if (!IsAccentColorCustomized(color_scheme))
- return GetCustomFocusRingColor();
+ return GetCustomFocusRingColor(color_scheme);
return focus_ring;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index a84ae32eb78..6075c988de8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -235,7 +235,8 @@ void LayoutTreeAsText::WriteLayoutObject(WTF::TextStream& ts,
if (o.IsDetailsMarker()) {
ts << ": ";
- switch (To<LayoutDetailsMarker>(o).GetOrientation()) {
+ const auto& marker = To<LayoutDetailsMarker>(o);
+ switch (marker.GetOrientation(marker.StyleRef(), marker.IsOpen())) {
case LayoutDetailsMarker::kLeft:
ts << "left";
break;
@@ -447,27 +448,13 @@ static void WriteTextFragment(WTF::TextStream& ts,
static void WriteTextFragment(WTF::TextStream& ts,
const NGInlineCursor& cursor) {
- if (const NGPaintFragment* const paint_fragment =
- cursor.CurrentPaintFragment()) {
- const auto* physical_text_fragment =
- DynamicTo<NGPhysicalTextFragment>(paint_fragment->PhysicalFragment());
- if (!physical_text_fragment)
- return;
- const NGFragment fragment(paint_fragment->Style().GetWritingDirection(),
- *physical_text_fragment);
- WriteTextFragment(ts, paint_fragment->GetLayoutObject(),
- paint_fragment->RectInContainerBlock(),
- paint_fragment->Style(), physical_text_fragment->Text(),
- fragment.InlineSize());
- return;
- }
DCHECK(cursor.CurrentItem());
const NGFragmentItem& item = *cursor.CurrentItem();
DCHECK(item.Type() == NGFragmentItem::kText ||
item.Type() == NGFragmentItem::kGeneratedText);
const LayoutUnit inline_size =
item.IsHorizontal() ? item.Size().width : item.Size().height;
- WriteTextFragment(ts, item.GetLayoutObject(), item.RectInContainerBlock(),
+ WriteTextFragment(ts, item.GetLayoutObject(), item.RectInContainerFragment(),
item.Style(), item.Text(cursor.Items()), inline_size);
}
@@ -492,6 +479,11 @@ static void WritePaintProperties(WTF::TextStream& ts,
ts << " state=(" << fragment->LocalBorderBoxProperties().ToString()
<< ")";
}
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ ts << " cull_rect=(" << fragment->GetCullRect().ToString()
+ << ") contents_cull_rect=("
+ << fragment->GetContentsCullRect().ToString() << ")";
+ }
ts << "\n";
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_video.cc b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
index 7692f6b6410..163d86dd4c4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
@@ -80,7 +80,7 @@ LayoutSize LayoutVideo::CalculateIntrinsicSize(float scale) {
HTMLVideoElement* video = VideoElement();
DCHECK(video);
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
+ if (RuntimeEnabledFeatures::ExperimentalPoliciesEnabled()) {
if (video->IsDefaultIntrinsicSize()) {
LayoutSize size = DefaultSize();
size.Scale(scale);
@@ -88,31 +88,38 @@ LayoutSize LayoutVideo::CalculateIntrinsicSize(float scale) {
}
}
- // Spec text from 4.8.6
- //
- // The intrinsic width of a video element's playback area is the intrinsic
- // width of the video resource, if that is available; otherwise it is the
- // intrinsic width of the poster frame, if that is available; otherwise it is
- // 300 CSS pixels.
- //
- // The intrinsic height of a video element's playback area is the intrinsic
- // height of the video resource, if that is available; otherwise it is the
- // intrinsic height of the poster frame, if that is available; otherwise it is
- // 150 CSS pixels.
- WebMediaPlayer* web_media_player = MediaElement()->GetWebMediaPlayer();
- if (web_media_player &&
- video->getReadyState() >= HTMLVideoElement::kHaveMetadata) {
- IntSize size(web_media_player->NaturalSize());
- if (!size.IsEmpty()) {
- LayoutSize layoutSize = LayoutSize(size);
- layoutSize.Scale(scale);
- return layoutSize;
- }
+ auto display_mode = GetDisplayMode();
+
+ // Special case: If the poster image is the "default poster image", we should
+ // NOT use that for calculating intrinsic size.
+ // TODO(1190335): Remove this once default poster image is removed
+ if (display_mode == kPoster && video->IsDefaultPosterImageURL()) {
+ display_mode = kVideo;
}
- if (video->IsShowPosterFlagSet() && !cached_image_size_.IsEmpty() &&
- !ImageResource()->ErrorOccurred())
- return cached_image_size_;
+ switch (display_mode) {
+ // This implements the intrinsic width/height calculation from:
+ // https://html.spec.whatwg.org/#the-video-element:dimension-attributes:~:text=The%20intrinsic%20width%20of%20a%20video%20element's%20playback%20area
+ // If the video playback area is currently represented by the poster image,
+ // the intrinsic width and height are that of the poster image.
+ case kPoster:
+ if (!cached_image_size_.IsEmpty() && !ImageResource()->ErrorOccurred()) {
+ return cached_image_size_;
+ }
+ break;
+
+ // Otherwise, the intrinsic width is that of the video.
+ case kVideo:
+ if (const auto* player = MediaElement()->GetWebMediaPlayer()) {
+ IntSize size(player->NaturalSize());
+ if (!size.IsEmpty()) {
+ LayoutSize layout_size = LayoutSize(size);
+ layout_size.Scale(scale);
+ return layout_size;
+ }
+ }
+ break;
+ }
LayoutSize size = DefaultSize();
size.Scale(scale);
@@ -139,12 +146,18 @@ void LayoutVideo::ImageChanged(WrappedImagePtr new_image,
LayoutVideo::DisplayMode LayoutVideo::GetDisplayMode() const {
NOT_DESTROYED();
- if (!VideoElement()->IsShowPosterFlagSet() ||
- VideoElement()->PosterImageURL().IsEmpty()) {
- return kVideo;
- } else {
+
+ const auto* video = VideoElement();
+ // If the show-poster-flag is set (or there is no video frame to display) AND
+ // there is a poster image, display that.
+ if ((video->IsShowPosterFlagSet() || !video->HasAvailableVideoFrame()) &&
+ !video->PosterImageURL().IsEmpty()) {
return kPoster;
}
+ // Otherwise, try displaying a video frame.
+ else {
+ return kVideo;
+ }
}
void LayoutVideo::PaintReplaced(const PaintInfo& paint_info,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_video_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_video_test.cc
index 9033efc261c..7d2e7ea0f70 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/layout_video.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -26,7 +27,9 @@ class LayoutVideoTest : public RenderingTest {
UnacceleratedStaticBitmapImage::Create(image).get());
// Set image to video
- auto* layout_image = (LayoutImage*)GetLayoutObjectByElementId(id);
+ auto* video = To<HTMLVideoElement>(GetElementById(id));
+ auto* layout_image = To<LayoutImage>(video->GetLayoutObject());
+ video->setAttribute(html_names::kPosterAttr, "http://example.com/foo.jpg");
layout_image->ImageResource()->SetImageResource(image_content);
}
};
@@ -42,7 +45,7 @@ TEST_F(LayoutVideoTest, PosterSizeWithNormal) {
CreateAndSetImage("video", 10, 10);
UpdateAllLifecyclePhasesForTest();
- int width = ((LayoutBox*)GetLayoutObjectByElementId("video"))
+ int width = To<LayoutBox>(GetLayoutObjectByElementId("video"))
->AbsoluteBoundingBoxRect()
.Width();
EXPECT_EQ(width, 10);
@@ -59,10 +62,56 @@ TEST_F(LayoutVideoTest, PosterSizeWithZoom) {
CreateAndSetImage("video", 10, 10);
UpdateAllLifecyclePhasesForTest();
- int width = ((LayoutBox*)GetLayoutObjectByElementId("video"))
+ int width = To<LayoutBox>(GetLayoutObjectByElementId("video"))
->AbsoluteBoundingBoxRect()
.Width();
EXPECT_EQ(width, 15);
}
+TEST_F(LayoutVideoTest, PosterSizeAfterPlay) {
+ SetBodyInnerHTML(R"HTML(
+ <video id='video' src='http://example.com/foo.mp4' />
+ )HTML");
+
+ CreateAndSetImage("video", 10, 10);
+ UpdateAllLifecyclePhasesForTest();
+ auto* video = To<HTMLVideoElement>(GetElementById("video"));
+
+ // Try playing the video (should stall without a real source)
+ video->Play();
+ EXPECT_FALSE(video->IsShowPosterFlagSet());
+ EXPECT_FALSE(video->HasAvailableVideoFrame());
+
+ // Width should still be that of the poster image, NOT the default video
+ // element width
+ int width = To<LayoutBox>(GetLayoutObjectByElementId("video"))
+ ->AbsoluteBoundingBoxRect()
+ .Width();
+ EXPECT_EQ(width, 10);
+}
+
+// TODO(1190335): Remove this once "default poster image" is not longer
+// supported. Blink embedders (such as Webview) can set the default poster image
+// for a video using `blink::Settings`. The default poster image should not be
+// used to affect the layout of a video, even when a normal poster image would.
+TEST_F(LayoutVideoTest, DefaultPosterImageSize) {
+ // Override the default poster image
+ GetDocument().GetSettings()->SetDefaultVideoPosterURL(
+ "https://www.example.com/foo.jpg");
+
+ SetBodyInnerHTML(R"HTML(
+ <video id='video' src='http://example.com/foo.mp4' />
+ )HTML");
+
+ // Pretend we loaded the poster
+ CreateAndSetImage("video", 10, 10);
+
+ // Width should be the default video width, NOT poster image width
+ int width = To<LayoutBox>(GetLayoutObjectByElementId("video"))
+ ->AbsoluteBoundingBoxRect()
+ .Width();
+ EXPECT_NE(width, 10);
+ EXPECT_EQ(width, LayoutVideo::kDefaultWidth);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.cc b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
index a82a587e5a6..74d67faff5f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
@@ -43,6 +43,8 @@
#include "third_party/blink/renderer/core/layout/layout_counter.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
+#include "third_party/blink/renderer/core/layout/layout_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/view_fragmentation_context.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -628,8 +630,15 @@ PhysicalRect LayoutView::ViewRect() const {
NOT_DESTROYED();
if (ShouldUsePrintingLayout())
return PhysicalRect(PhysicalOffset(), Size());
- if (frame_view_)
- return PhysicalRect(PhysicalOffset(), PhysicalSize(frame_view_->Size()));
+ if (frame_view_) {
+ IntRect view_rect(IntPoint(), frame_view_->Size());
+ auto& frame = frame_view_->GetFrame();
+ if (frame.IsMainFrame()) {
+ frame.GetChromeClient().OverrideVisibleRectForMainFrame(frame,
+ &view_rect);
+ }
+ return PhysicalRect(view_rect);
+ }
return PhysicalRect();
}
@@ -643,7 +652,7 @@ PhysicalRect LayoutView::OverflowClipRect(
overlay_scrollbar_clip_behavior);
}
- rect.offset = location;
+ rect.offset += location;
if (IsScrollContainer())
ExcludeScrollbars(rect, overlay_scrollbar_clip_behavior);
@@ -695,8 +704,8 @@ void LayoutView::CalculateScrollbarModes(
RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
- if (document.IsCapturingLayout()) {
- // When capturing layout (e.g. printing), frame-level scrollbars are never
+ if (document.IsPrintingOrPaintingPreview()) {
+ // When printing or painting preview, frame-level scrollbars are never
// displayed.
// TODO(szager): Figure out the right behavior when printing an overflowing
// iframe. https://bugs.chromium.org/p/chromium/issues/detail?id=777528
@@ -944,28 +953,30 @@ CompositingReasons LayoutView::AdditionalCompositingReasons() const {
NOT_DESTROYED();
// TODO(lfg): Audit for portals
const LocalFrame& frame = frame_view_->GetFrame();
- if (frame.OwnerLayoutObject() &&
- base::FeatureList::IsEnabled(
- blink::features::kCompositeCrossOriginIframes) &&
- frame.IsCrossOriginToParentFrame()) {
+ if (frame.OwnerLayoutObject() && frame.IsCrossOriginToParentFrame())
return CompositingReason::kIFrame;
- }
return CompositingReason::kNone;
}
-void LayoutView::UpdateCounters() {
+void LayoutView::UpdateMarkersAndCountersAfterStyleChange() {
NOT_DESTROYED();
- if (!needs_counter_update_)
+ if (!needs_marker_counter_update_)
return;
- needs_counter_update_ = false;
- if (!HasLayoutCounters())
+ needs_marker_counter_update_ = false;
+ if (!HasLayoutCounters() && !HasLayoutListItems())
return;
for (LayoutObject* layout_object = this; layout_object;
layout_object = layout_object->NextInPreOrder()) {
- if (auto* counter = DynamicTo<LayoutCounter>(layout_object))
+ if (auto* list_item = DynamicTo<LayoutListItem>(layout_object)) {
+ list_item->UpdateCounterStyle();
+ } else if (auto* ng_list_item =
+ DynamicTo<LayoutNGListItem>(layout_object)) {
+ ng_list_item->UpdateCounterStyle();
+ } else if (auto* counter = DynamicTo<LayoutCounter>(layout_object)) {
counter->UpdateCounter();
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.h b/chromium/third_party/blink/renderer/core/layout/layout_view.h
index 51d607f59b1..e26a474b2f5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.h
@@ -246,11 +246,12 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
// FIXME: This is a work around because the current implementation of counters
// requires walking the entire tree repeatedly and most pages don't actually
// use either feature so we shouldn't take the performance hit when not
- // needed. Long term we should rewrite the counter and quotes code.
+ // needed. Long term we should rewrite the counter code.
+ // TODO(xiaochengh): Or do we keep it as is?
void AddLayoutCounter() {
NOT_DESTROYED();
layout_counter_count_++;
- SetNeedsCounterUpdate();
+ SetNeedsMarkerOrCounterUpdate();
}
void RemoveLayoutCounter() {
NOT_DESTROYED();
@@ -261,11 +262,26 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
NOT_DESTROYED();
return layout_counter_count_;
}
- void SetNeedsCounterUpdate() {
+ void AddLayoutListItem() {
NOT_DESTROYED();
- needs_counter_update_ = true;
+ layout_list_item_count_++;
+ // No need to traverse and update markers at this point. We need it only
+ // when @counter-style rules are changed.
}
- void UpdateCounters();
+ void RemoveLayoutListItem() {
+ NOT_DESTROYED();
+ DCHECK_GT(layout_list_item_count_, 0u);
+ layout_list_item_count_--;
+ }
+ bool HasLayoutListItems() {
+ NOT_DESTROYED();
+ return layout_list_item_count_;
+ }
+ void SetNeedsMarkerOrCounterUpdate() {
+ NOT_DESTROYED();
+ needs_marker_counter_update_ = true;
+ }
+ void UpdateMarkersAndCountersAfterStyleChange();
bool BackgroundIsKnownToBeOpaqueInRect(
const PhysicalRect& local_rect) const override;
@@ -378,8 +394,9 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
scoped_refptr<IntervalArena> interval_arena_;
LayoutQuote* layout_quote_head_;
- unsigned layout_counter_count_;
- bool needs_counter_update_ = false;
+ unsigned layout_counter_count_ = 0;
+ unsigned layout_list_item_count_ = 0;
+ bool needs_marker_counter_update_ = false;
unsigned hit_test_count_;
unsigned hit_test_cache_hits_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
index 24f0fdde98a..1ee52224a0f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
@@ -149,6 +149,15 @@ class LayoutViewHitTestTest : public testing::WithParamInterface<HitTestConfig>,
GetFrame().GetSettings()->SetEditingBehaviorType(
GetParam().editing_behavior);
}
+
+ PositionWithAffinity HitTest(int left, int top) {
+ const HitTestRequest hit_request(HitTestRequest::kActive);
+ const HitTestLocation hit_location(PhysicalOffset(left, top));
+ HitTestResult hit_result(hit_request, hit_location);
+ if (!GetLayoutView().HitTest(hit_location, hit_result))
+ return PositionWithAffinity();
+ return hit_result.GetPosition();
+ }
};
INSTANTIATE_TEST_SUITE_P(
@@ -168,6 +177,338 @@ INSTANTIATE_TEST_SUITE_P(
HitTestConfig{true, mojom::EditingBehavior::kEditingAndroidBehavior},
HitTestConfig{true, mojom::EditingBehavior::kEditingChromeOSBehavior}));
+TEST_P(LayoutViewHitTestTest, EmptySpan) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 50px; }"
+ "b { border: solid 5px green; }");
+ SetBodyInnerHTML("<div id=target>AB<b></b></div>");
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild());
+ const auto after_ab =
+ PositionWithAffinity(Position(ab, 2), TextAffinity::kUpstream);
+
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(10, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(after_ab, HitTest(20, 5));
+ EXPECT_EQ(after_ab, HitTest(25, 5));
+ EXPECT_EQ(after_ab, HitTest(30, 5));
+ EXPECT_EQ(after_ab, HitTest(35, 5));
+ EXPECT_EQ(after_ab, HitTest(40, 5));
+ EXPECT_EQ(after_ab, HitTest(45, 5));
+ EXPECT_EQ(after_ab, HitTest(50, 5));
+ EXPECT_EQ(after_ab, HitTest(55, 5));
+}
+
+// http://crbug.com/1171070
+// See also, FloatLeft*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatLeftLeft) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 70px; }"
+ ".float { float: left; margin-right: 10px; }");
+ SetBodyInnerHTML("<div id=target><div class=float>ab</div>xy</div>");
+ // NGFragmentItem
+ // [0] kLine (30,0)x(20,10)
+ // [1] kBox/Floating (0,0)x(20,10)
+ // [2] kText "xy" (30,0)x(20,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild()->firstChild());
+ auto& xy = *To<Text>(target.lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(55, 5));
+}
+
+// http://crbug.com/1171070
+// See also, FloatLeft*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatLeftMiddle) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 70px; }"
+ ".float { float: left; margin-right: 10px; }");
+ SetBodyInnerHTML("<div id=target>x<div class=float>ab</div>y</div>");
+ // NGFragmentItem
+ // [0] kLine (30,0)x(20,10)
+ // [1] kText "x" (30,0)x(10,10)
+ // [1] kBox/Floating (0,0)x(20,10)
+ // [2] kText "y" (40,0)x(10,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild()->nextSibling()->firstChild());
+ auto& x = *To<Text>(target.firstChild());
+ auto& y = *To<Text>(target.lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 0)), HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 0)), HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(55, 5));
+}
+
+// http://crbug.com/1171070
+// See also, FloatLeft*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatLeftRight) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 70px; }"
+ ".float { float: left; margin-right: 10px; }");
+ SetBodyInnerHTML("<div id=target>xy<div class=float>ab</div></div>");
+ // NGFragmentItem
+ // [0] kLine (30,0)x(20,10)
+ // [1] kText "xy" (30,0)x(20,10)
+ // [2] kBox/Floating (0,0)x(20,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.lastChild()->firstChild());
+ auto& xy = *To<Text>(target.firstChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(55, 5));
+}
+
+// http://crbug.com/1171070
+// See also, FloatRight*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatRightLeft) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 50px; }"
+ ".float { float: right; }");
+ SetBodyInnerHTML("<div id=target>xy<div class=float>ab</div></div>");
+ // NGFragmentItem
+ // [0] kLine (0,0)x(20,10)
+ // [1] kBox/Floating (30,0)x(20,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.lastChild()->firstChild());
+ auto& xy = *To<Text>(target.firstChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(20, 5))
+ << "at right of 'xy'";
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(25, 5))
+ << "right of 'xy'";
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(30, 5))
+ << "inside float";
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(35, 5))
+ << "inside float";
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(40, 5))
+ << "inside float";
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(45, 5))
+ << "inside float";
+
+ // |HitTestResult| holds <body>.
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(50, 5))
+ << "at right side of float";
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(55, 5))
+ << "right of float";
+}
+
+// http://crbug.com/1171070
+// See also, FloatRight*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatRightMiddle) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 50px; }"
+ ".float { float: right; }");
+ SetBodyInnerHTML("<div id=target>x<div class=float>ab</div>y</div>");
+ // NGFragmentItem
+ // [0] kLine (0,0)x(20,10)
+ // [1] kText "x" (0,0)x(10,10)
+ // [2] kBox/Floating (30,0)x(20,10)
+ // [3] kText "y" (10,0)x(10,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild()->nextSibling()->firstChild());
+ auto& x = *To<Text>(target.firstChild());
+ auto& y = *To<Text>(target.lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(x, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 0)), HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(y, 1), TextAffinity::kUpstream),
+ HitTest(55, 5));
+}
+
+// http://crbug.com/1171070
+// See also, FloatRight*, DOM order of "float" should not affect hit testing.
+TEST_P(LayoutViewHitTestTest, FloatRightRight) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 50px; }"
+ ".float { float: right; }");
+ SetBodyInnerHTML("<div id=target><div class=float>ab</div>xy</div>");
+ // [0] kLine (0,0)x(20,10)
+ // [1] kBox/Floating (30,0)x(20,10)
+ // [2] kText "xy" (0,0)x(20,10)
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild()->firstChild());
+ auto& xy = *To<Text>(target.lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(55, 5));
+}
+
+TEST_P(LayoutViewHitTestTest, PositionAbsolute) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#target { width: 70px; }"
+ ".abspos { position: absolute; left: 40px; top: 0px; }");
+ SetBodyInnerHTML("<div id=target><div class=abspos>ab</div>xy</div>");
+ // NGFragmentItem
+ // [0] kLine (0,0)x(20,10)
+ // [2] kText "xy" (30,0)x(20,10)
+ // Note: position:absolute isn't in NGFragmentItems of #target.
+ auto& target = *GetElementById("target");
+ auto& ab = *To<Text>(target.firstChild()->firstChild());
+ auto& xy = *To<Text>(target.lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(0, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 0)), HitTest(5, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(20, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(25, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(30, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(35, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(40, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 0)), HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(50, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(55, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(60, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(xy, 2), TextAffinity::kUpstream),
+ HitTest(65, 5));
+}
+
TEST_P(LayoutViewHitTestTest, HitTestHorizontal) {
LoadAhem();
SetBodyInnerHTML(R"HTML(
@@ -614,4 +955,91 @@ TEST_P(LayoutViewHitTestTest, HitTestVerticalRLRoot) {
result.GetPosition());
}
+// http://crbug.com/1164974
+TEST_P(LayoutViewHitTestTest, PseudoElementAfterBlock) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/15px Ahem; }"
+ "p::after { content: 'XY' }");
+ SetBodyInnerHTML("<div><p id=target>ab</p></div>");
+ const auto& text_ab = *To<Text>(GetElementById("target")->firstChild());
+ // In legacy layout, this position comes from |LayoutBlock::PositionBox()|
+ // for mac/unix, or |LayoutObject::FindPosition()| on android/windows.
+ const auto expected = PositionWithAffinity(
+ IsAndroidOrWindowsEditingBehavior() ? Position(text_ab, 2)
+ : Position(text_ab, 0),
+ LayoutNG() && IsAndroidOrWindowsEditingBehavior()
+ ? TextAffinity::kUpstream
+ : TextAffinity::kDownstream);
+
+ EXPECT_EQ(expected, HitTest(20, 5)) << "after ab";
+ EXPECT_EQ(expected, HitTest(25, 5)) << "at X";
+ EXPECT_EQ(expected, HitTest(35, 5)) << "at Y";
+ EXPECT_EQ(expected, HitTest(40, 5)) << "after Y";
+ EXPECT_EQ(expected, HitTest(50, 5)) << "after XY";
+}
+
+// http://crbug.com/1043471
+TEST_P(LayoutViewHitTestTest, PseudoElementAfterInline) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/10px Ahem; }"
+ "#cd::after { content: 'XYZ'; margin-left: 100px; }");
+ SetBodyInnerHTML("<div id=ab>ab<span id=cd>cd</span></div>");
+ const auto& text_ab = *To<Text>(GetElementById("ab")->firstChild());
+ const auto& text_cd = *To<Text>(GetElementById("cd")->lastChild());
+
+ EXPECT_EQ(PositionWithAffinity(Position(text_ab, 0)), HitTest(5, 5));
+ // Because of hit testing at "b", position should be |kDownstream|.
+ EXPECT_EQ(PositionWithAffinity(Position(text_ab, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(15, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(text_cd, 0)), HitTest(25, 5));
+ // Because of hit testing at "d", position should be |kDownstream|.
+ EXPECT_EQ(PositionWithAffinity(Position(text_cd, 1),
+ LayoutNG() ? TextAffinity::kDownstream
+ : TextAffinity::kUpstream),
+ HitTest(35, 5));
+ // Because of hit testing at right of <span cd>, result position should be
+ // |kUpstream|.
+ EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
+ LayoutNG() ? TextAffinity::kUpstream
+ : TextAffinity::kDownstream),
+ HitTest(45, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
+ LayoutNG() ? TextAffinity::kUpstream
+ : TextAffinity::kDownstream),
+ HitTest(55, 5));
+ EXPECT_EQ(PositionWithAffinity(Position(text_cd, 2),
+ LayoutNG() ? TextAffinity::kUpstream
+ : TextAffinity::kDownstream),
+ HitTest(65, 5));
+}
+
+TEST_P(LayoutViewHitTestTest, PseudoElementAfterBlockWithMargin) {
+ LoadAhem();
+ InsertStyleElement(
+ "body { margin: 0px; font: 10px/15px Ahem; }"
+ "p::after { content: 'XY'; margin-left: 10px;}");
+ SetBodyInnerHTML("<div><p id=target>ab</p></div>");
+ const auto& text_ab = *To<Text>(GetElementById("target")->firstChild());
+ // In legacy layout, this position comes from |LayoutBlock::PositionBox()|
+ // for mac/unix, or |LayoutObject::FindPosition()| on android/windows.
+ const auto expected = PositionWithAffinity(
+ IsAndroidOrWindowsEditingBehavior() ? Position(text_ab, 2)
+ : Position(text_ab, 0),
+ LayoutNG() && IsAndroidOrWindowsEditingBehavior()
+ ? TextAffinity::kUpstream
+ : TextAffinity::kDownstream);
+
+ EXPECT_EQ(expected, HitTest(20, 5)) << "after ab";
+ EXPECT_EQ(expected, HitTest(25, 5)) << "at margin-left";
+ EXPECT_EQ(expected, HitTest(30, 5)) << "before X";
+ EXPECT_EQ(expected, HitTest(35, 5)) << "at X";
+ EXPECT_EQ(expected, HitTest(45, 5)) << "at Y";
+ EXPECT_EQ(expected, HitTest(50, 5)) << "after Y";
+ EXPECT_EQ(expected, HitTest(55, 5)) << "after XY";
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
index 58258904b29..468c744d0e5 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
@@ -112,10 +112,8 @@ LegacyAbstractInlineTextBox::~LegacyAbstractInlineTextBox() {
void AbstractInlineTextBox::Detach() {
DCHECK(GetLineLayoutItem());
- if (Node* node = GetNode()) {
- if (AXObjectCache* cache = node->GetDocument().ExistingAXObjectCache())
- cache->Remove(this);
- }
+ if (AXObjectCache* cache = ExistingAXObjectCache())
+ cache->Remove(this);
line_layout_item_ = LineLayoutText(nullptr);
}
@@ -227,6 +225,18 @@ Node* AbstractInlineTextBox::GetNode() const {
return GetLineLayoutItem().GetNode();
}
+LayoutObject* AbstractInlineTextBox::GetLayoutObject() const {
+ if (!GetLineLayoutItem())
+ return nullptr;
+ return GetLineLayoutItem().GetLayoutObject();
+}
+
+AXObjectCache* AbstractInlineTextBox::ExistingAXObjectCache() const {
+ if (LayoutObject* layout_object = GetLayoutObject())
+ return layout_object->GetDocument().ExistingAXObjectCache();
+ return nullptr;
+}
+
void LegacyAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
if (!inline_text_box_)
return;
diff --git a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
index 90756e17f29..a77dd37c893 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
@@ -74,6 +74,8 @@ class CORE_EXPORT AbstractInlineTextBox
virtual unsigned TextOffsetInFormattingContext(unsigned) const = 0;
virtual Direction GetDirection() const = 0;
Node* GetNode() const;
+ LayoutObject* GetLayoutObject() const;
+ AXObjectCache* ExistingAXObjectCache() const;
virtual void CharacterWidths(Vector<float>&) const = 0;
void GetWordBoundaries(Vector<WordBoundaries>&) const;
virtual String GetText() const = 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index 64aec99c4a2..01443a3064a 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -207,6 +207,7 @@ class BreakingContext {
bool ignoring_spaces_;
bool current_character_is_space_;
bool is_space_or_other_space_separator_;
+ bool previous_is_space_or_other_space_separator_;
bool previous_character_is_space_;
bool has_former_opportunity_;
unsigned current_start_offset_; // initial offset for the current text
@@ -1077,11 +1078,10 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
UChar last_character = layout_text_info_.line_break_iterator_.LastCharacter();
UChar second_to_last_character =
layout_text_info_.line_break_iterator_.SecondToLastCharacter();
- bool previous_is_space_or_other_space_separator = false;
for (; current_.Offset() < layout_text.TextLength();
current_.FastIncrementInTextNode()) {
previous_character_is_space_ = current_character_is_space_;
- previous_is_space_or_other_space_separator =
+ previous_is_space_or_other_space_separator_ =
is_space_or_other_space_separator_;
UChar c = current_.Current();
SetCurrentCharacterIsSpace(c);
@@ -1145,7 +1145,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
}
PrepareForNextCharacter(layout_text, prohibit_break_inside,
- previous_is_space_or_other_space_separator);
+ previous_is_space_or_other_space_separator_);
at_start_ = false;
NextCharacter(c, last_character, second_to_last_character);
continue;
@@ -1185,7 +1185,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
// We keep track of the total width contributed by trailing space as we
// often want to exclude it when determining
// if a run fits on a line.
- if (collapse_white_space_ && previous_is_space_or_other_space_separator &&
+ if (collapse_white_space_ && previous_is_space_or_other_space_separator_ &&
is_space_or_other_space_separator_ && last_width_measurement)
width_.SetTrailingWhitespaceWidth(last_width_measurement);
@@ -1250,9 +1250,9 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
if (CanBreakAtWhitespace(
break_words, word_measurement, stopped_ignoring_spaces, char_width,
hyphenated, disable_soft_hyphen, hyphen_width, between_words,
- mid_word_break, can_break_mid_word, previous_character_is_space_,
- last_width_measurement, layout_text, font, apply_word_spacing,
- word_spacing))
+ mid_word_break, can_break_mid_word,
+ previous_is_space_or_other_space_separator_, last_width_measurement,
+ layout_text, font, apply_word_spacing, word_spacing))
return false;
// If there is a hard-break available at this whitespace position then take
@@ -1304,7 +1304,7 @@ inline bool BreakingContext::HandleText(WordMeasurements& word_measurements,
}
PrepareForNextCharacter(layout_text, prohibit_break_inside,
- previous_is_space_or_other_space_separator);
+ previous_is_space_or_other_space_separator_);
at_start_ = false;
is_line_empty = line_info_.IsEmpty();
NextCharacter(c, last_character, second_to_last_character);
@@ -1461,7 +1461,7 @@ inline void BreakingContext::TrailingSpacesHang(bool can_break_mid_word) {
DCHECK(curr_ws_ == EWhiteSpace::kBreakSpaces);
// Avoid breaking before the first white-space after a word if there is a
// breaking opportunity before.
- if (has_former_opportunity_ && !previous_character_is_space_)
+ if (has_former_opportunity_ && !previous_is_space_or_other_space_separator_)
return;
line_break_.MoveTo(current_.GetLineLayoutItem(), current_.Offset(),
@@ -1469,7 +1469,7 @@ inline void BreakingContext::TrailingSpacesHang(bool can_break_mid_word) {
// Avoid breaking before the first white-space after a word, unless
// overflow-wrap or word-break allow to.
- if (!previous_character_is_space_ && !can_break_mid_word)
+ if (!previous_is_space_or_other_space_separator_ && !can_break_mid_word)
line_break_.Increment();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc b/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
index 4c4642cd885..51891cf041f 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
@@ -191,7 +191,7 @@ LayoutUnit InlineBox::LineHeight() const {
}
int InlineBox::CaretMinOffset() const {
- return GetLineLayoutItem().CaretMinOffset();
+ return 0;
}
int InlineBox::CaretMaxOffset() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_iterator.h b/chromium/third_party/blink/renderer/core/layout/line/inline_iterator.h
index ef198a493ca..4818a9cc227 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_iterator.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_iterator.h
@@ -614,9 +614,7 @@ inline bool InlineBidiResolver::NeedsTrailingSpace(BidiRunList<BidiRun>& runs) {
return true;
const ComputedStyle& style =
runs.LogicallyLastRun()->line_layout_item_.StyleRef();
- if (style.BreakOnlyAfterWhiteSpace() && style.AutoWrap())
- return true;
- return false;
+ return style.NeedsTrailingSpace();
}
static inline bool IsIsolatedInline(LineLayoutItem object) {
diff --git a/chromium/third_party/blink/renderer/core/layout/line/line_box_list.cc b/chromium/third_party/blink/renderer/core/layout/line/line_box_list.cc
index 9d9d861f00c..ed929849f72 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/line_box_list.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/line_box_list.cc
@@ -359,14 +359,32 @@ void LineBoxList::DirtyLinesFromChangedChild(LineLayoutItem container,
// findNextLineBreak. findNextLineBreak, despite the name, actually returns
// the first LayoutObject after the BR. <rdar://problem/3849947> "Typing
// after pasting line does not appear until after window resize."
- if (RootInlineBox* prev_root_box = box->PrevRootBox())
+ if (RootInlineBox* prev_root_box = box->PrevRootBox()) {
prev_root_box->MarkDirty();
+#if DCHECK_IS_ON()
+ for (; prev_root_box; prev_root_box = prev_root_box->PrevRootBox()) {
+ DCHECK(prev_root_box->IsDirty() ||
+ prev_root_box->LineBreakObj() != child);
+ }
+#endif
+ }
// If |child| or any of its immediately previous siblings with culled
// lineboxes is the object after a line-break in |box| or the linebox after
// it then that means |child| actually sits on the linebox after |box| (or
// is its line-break object) and so we need to dirty it as well.
- if (RootInlineBox* next_root_box = box->NextRootBox())
+ if (RootInlineBox* next_root_box = box->NextRootBox()) {
next_root_box->MarkDirty();
+
+ next_root_box = next_root_box->NextRootBox();
+ if (next_root_box && next_root_box->LineBreakObj() == child)
+ next_root_box->MarkDirty();
+#if DCHECK_IS_ON()
+ for (; next_root_box; next_root_box = next_root_box->NextRootBox()) {
+ DCHECK(next_root_box->IsDirty() ||
+ next_root_box->LineBreakObj() != child);
+ }
+#endif
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/list_marker.cc b/chromium/third_party/blink/renderer/core/layout/list_marker.cc
index 7662e71dec1..b1bdfb3cf4a 100644
--- a/chromium/third_party/blink/renderer/core/layout/list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/list_marker.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/list_marker.h"
+#include "third_party/blink/renderer/core/css/counter_style.h"
#include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
#include "third_party/blink/renderer/core/layout/layout_inside_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
@@ -13,6 +14,7 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
+#include "third_party/blink/renderer/core/style/list_style_type_data.h"
namespace blink {
@@ -23,6 +25,18 @@ const int kCMarkerPaddingPx = 7;
// Recommended UA margin for list markers.
const int kCUAMarkerMarginEm = 1;
+// 'closure-*' have 0.4em margin for compatibility with
+// ::-webkit-details-marker.
+const float kClosureMarkerMarginEm = 0.4f;
+
+namespace {
+
+LayoutUnit DisclosureSymbolSize(const ComputedStyle& style) {
+ return LayoutUnit(style.SpecifiedFontSize() * style.EffectiveZoom() * 0.66);
+}
+
+} // namespace
+
ListMarker::ListMarker() : marker_text_type_(kNotText) {}
const ListMarker* ListMarker::Get(const LayoutObject* marker) {
@@ -79,8 +93,7 @@ int ListMarker::ListItemValue(const LayoutObject& list_item) const {
return 0;
}
-// If the value of ListStyleType changed, we need to the marker text has been
-// updated.
+// If the value of ListStyleType changed, we need to update the marker text.
void ListMarker::ListStyleTypeChanged(LayoutObject& marker) {
DCHECK_EQ(Get(&marker), this);
if (marker_text_type_ == kNotText || marker_text_type_ == kUnresolved)
@@ -91,6 +104,18 @@ void ListMarker::ListStyleTypeChanged(LayoutObject& marker) {
layout_invalidation_reason::kListStyleTypeChange);
}
+// If the @counter-style in use has changed, we need to update the marker text.
+void ListMarker::CounterStyleChanged(LayoutObject& marker) {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+ DCHECK_EQ(Get(&marker), this);
+ if (marker_text_type_ == kNotText || marker_text_type_ == kUnresolved)
+ return;
+
+ marker_text_type_ = kUnresolved;
+ marker.SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kCounterStyleChange);
+}
+
void ListMarker::OrdinalValueChanged(LayoutObject& marker) {
DCHECK_EQ(Get(&marker), this);
if (marker_text_type_ == kOrdinalValue) {
@@ -105,7 +130,8 @@ void ListMarker::UpdateMarkerText(LayoutObject& marker, LayoutText* text) {
DCHECK(text);
DCHECK_EQ(marker_text_type_, kUnresolved);
StringBuilder marker_text_builder;
- marker_text_type_ = MarkerText(marker, &marker_text_builder, kWithSuffix);
+ marker_text_type_ =
+ MarkerText(marker, &marker_text_builder, kWithPrefixSuffix);
text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl());
DCHECK_NE(marker_text_type_, kNotText);
DCHECK_NE(marker_text_type_, kUnresolved);
@@ -124,31 +150,50 @@ ListMarker::MarkerTextType ListMarker::MarkerText(
if (!marker.StyleRef().ContentBehavesAsNormal())
return kNotText;
if (IsMarkerImage(marker)) {
- if (format == kWithSuffix)
+ if (format == kWithPrefixSuffix)
text->Append(' ');
return kNotText;
}
LayoutObject* list_item = ListItem(marker);
const ComputedStyle& style = list_item->StyleRef();
- switch (GetListStyleCategory(style.ListStyleType())) {
+ switch (GetListStyleCategory(marker.GetDocument(), style)) {
case ListStyleCategory::kNone:
return kNotText;
case ListStyleCategory::kStaticString:
text->Append(style.ListStyleStringValue());
return kStatic;
case ListStyleCategory::kSymbol:
- // value is ignored for these types
- text->Append(list_marker_text::GetText(style.ListStyleType(), 0));
- if (format == kWithSuffix)
- text->Append(' ');
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ const CounterStyle& counter_style =
+ GetCounterStyle(marker.GetDocument(), style);
+ if (format == kWithPrefixSuffix)
+ text->Append(counter_style.GetPrefix());
+ text->Append(counter_style.GenerateRepresentation(0));
+ if (format == kWithPrefixSuffix)
+ text->Append(counter_style.GetSuffix());
+ } else {
+ text->Append(list_marker_text::GetText(style.ListStyleType(), 0));
+ if (format == kWithPrefixSuffix)
+ text->Append(' ');
+ }
return kSymbolValue;
case ListStyleCategory::kLanguage: {
int value = ListItemValue(*list_item);
- text->Append(list_marker_text::GetText(style.ListStyleType(), value));
- if (format == kWithSuffix) {
- text->Append(list_marker_text::Suffix(style.ListStyleType(), value));
- text->Append(' ');
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ const CounterStyle& counter_style =
+ GetCounterStyle(marker.GetDocument(), style);
+ if (format == kWithPrefixSuffix)
+ text->Append(counter_style.GetPrefix());
+ text->Append(counter_style.GenerateRepresentation(value));
+ if (format == kWithPrefixSuffix)
+ text->Append(counter_style.GetSuffix());
+ } else {
+ text->Append(list_marker_text::GetText(style.ListStyleType(), value));
+ if (format == kWithPrefixSuffix) {
+ text->Append(list_marker_text::Suffix(style.ListStyleType(), value));
+ text->Append(' ');
+ }
}
return kOrdinalValue;
}
@@ -160,14 +205,14 @@ ListMarker::MarkerTextType ListMarker::MarkerText(
String ListMarker::MarkerTextWithSuffix(const LayoutObject& marker) const {
DCHECK_EQ(Get(&marker), this);
StringBuilder text;
- MarkerText(marker, &text, kWithSuffix);
+ MarkerText(marker, &text, kWithPrefixSuffix);
return text.ToString();
}
String ListMarker::MarkerTextWithoutSuffix(const LayoutObject& marker) const {
DCHECK_EQ(Get(&marker), this);
StringBuilder text;
- MarkerText(marker, &text, kWithoutSuffix);
+ MarkerText(marker, &text, kWithoutPrefixSuffix);
return text.ToString();
}
@@ -231,7 +276,7 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) {
return;
}
- if (style.ListStyleType() == EListStyleType::kNone) {
+ if (!style.GetListStyleType()) {
marker_text_type_ = kNotText;
return;
}
@@ -281,20 +326,31 @@ LayoutUnit ListMarker::WidthOfSymbol(const ComputedStyle& style) {
DCHECK(font_data);
if (!font_data)
return LayoutUnit();
+ const AtomicString& name = style.GetListStyleType()->GetCounterStyleName();
+ if (name == "disclosure-open" || name == "disclosure-closed")
+ return DisclosureSymbolSize(style);
return LayoutUnit((font_data->GetFontMetrics().Ascent() * 2 / 3 + 1) / 2 + 2);
}
std::pair<LayoutUnit, LayoutUnit> ListMarker::InlineMarginsForInside(
+ Document& document,
const ComputedStyle& marker_style,
const ComputedStyle& list_item_style) {
if (!marker_style.ContentBehavesAsNormal())
return {};
if (list_item_style.GeneratesMarkerImage())
return {LayoutUnit(), LayoutUnit(kCMarkerPaddingPx)};
- switch (GetListStyleCategory(list_item_style.ListStyleType())) {
- case ListStyleCategory::kSymbol:
+ switch (GetListStyleCategory(document, list_item_style)) {
+ case ListStyleCategory::kSymbol: {
+ const AtomicString& name =
+ list_item_style.GetListStyleType()->GetCounterStyleName();
+ if (name == "disclosure-open" || name == "disclosure-closed") {
+ return {LayoutUnit(), LayoutUnit(kClosureMarkerMarginEm *
+ marker_style.SpecifiedFontSize())};
+ }
return {LayoutUnit(-1),
LayoutUnit(kCUAMarkerMarginEm * marker_style.ComputedFontSize())};
+ }
default:
break;
}
@@ -302,6 +358,7 @@ std::pair<LayoutUnit, LayoutUnit> ListMarker::InlineMarginsForInside(
}
std::pair<LayoutUnit, LayoutUnit> ListMarker::InlineMarginsForOutside(
+ Document& document,
const ComputedStyle& marker_style,
const ComputedStyle& list_item_style,
LayoutUnit marker_inline_size) {
@@ -313,7 +370,7 @@ std::pair<LayoutUnit, LayoutUnit> ListMarker::InlineMarginsForOutside(
margin_start = -marker_inline_size - kCMarkerPaddingPx;
margin_end = LayoutUnit(kCMarkerPaddingPx);
} else {
- switch (GetListStyleCategory(list_item_style.ListStyleType())) {
+ switch (GetListStyleCategory(document, list_item_style)) {
case ListStyleCategory::kNone:
break;
case ListStyleCategory::kSymbol: {
@@ -322,8 +379,13 @@ std::pair<LayoutUnit, LayoutUnit> ListMarker::InlineMarginsForOutside(
if (!font_data)
return {};
const FontMetrics& font_metrics = font_data->GetFontMetrics();
- int offset = font_metrics.Ascent() * 2 / 3;
- margin_start = LayoutUnit(-offset - kCMarkerPaddingPx - 1);
+ const AtomicString& name =
+ list_item_style.GetListStyleType()->GetCounterStyleName();
+ LayoutUnit offset =
+ (name == "disclosure-open" || name == "disclosure-closed")
+ ? DisclosureSymbolSize(marker_style)
+ : LayoutUnit(font_metrics.Ascent() * 2 / 3);
+ margin_start = -offset - kCMarkerPaddingPx - 1;
margin_end = offset + kCMarkerPaddingPx + 1 - marker_inline_size;
break;
}
@@ -346,10 +408,17 @@ LayoutRect ListMarker::RelativeSymbolMarkerRect(const ComputedStyle& style,
// TODO(wkorman): Review and clean up/document the calculations below.
// http://crbug.com/543193
const FontMetrics& font_metrics = font_data->GetFontMetrics();
- int ascent = font_metrics.Ascent();
- int bullet_width = (ascent * 2 / 3 + 1) / 2;
- relative_rect = LayoutRect(1, 3 * (ascent - ascent * 2 / 3) / 2, bullet_width,
- bullet_width);
+ const int ascent = font_metrics.Ascent();
+ const AtomicString& name = style.GetListStyleType()->GetCounterStyleName();
+ if (name == "disclosure-open" || name == "disclosure-closed") {
+ LayoutUnit marker_size = DisclosureSymbolSize(style);
+ relative_rect = LayoutRect(LayoutUnit(), ascent - marker_size, marker_size,
+ marker_size);
+ } else {
+ int bullet_width = (ascent * 2 / 3 + 1) / 2;
+ relative_rect = LayoutRect(1, 3 * (ascent - ascent * 2 / 3) / 2,
+ bullet_width, bullet_width);
+ }
if (!style.IsHorizontalWritingMode()) {
relative_rect = relative_rect.TransposedRect();
relative_rect.SetX(width - relative_rect.X() - relative_rect.Width());
@@ -357,8 +426,30 @@ LayoutRect ListMarker::RelativeSymbolMarkerRect(const ComputedStyle& style,
return relative_rect;
}
+const CounterStyle& ListMarker::GetCounterStyle(Document& document,
+ const ComputedStyle& style) {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+ DCHECK(style.GetListStyleType());
+ DCHECK(style.GetListStyleType()->IsCounterStyle());
+ return style.GetListStyleType()->GetCounterStyle(document);
+}
+
ListMarker::ListStyleCategory ListMarker::GetListStyleCategory(
- EListStyleType type) {
+ Document& document,
+ const ComputedStyle& style) {
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ const ListStyleTypeData* list_style = style.GetListStyleType();
+ if (!list_style)
+ return ListStyleCategory::kNone;
+ if (list_style->IsString())
+ return ListStyleCategory::kStaticString;
+ DCHECK(list_style->IsCounterStyle());
+ return GetCounterStyle(document, style).IsPredefinedSymbolMarker()
+ ? ListStyleCategory::kSymbol
+ : ListStyleCategory::kLanguage;
+ }
+
+ EListStyleType type = style.ListStyleType();
switch (type) {
case EListStyleType::kNone:
return ListStyleCategory::kNone;
@@ -367,6 +458,8 @@ ListMarker::ListStyleCategory ListMarker::GetListStyleCategory(
case EListStyleType::kDisc:
case EListStyleType::kCircle:
case EListStyleType::kSquare:
+ case EListStyleType::kDisclosureOpen:
+ case EListStyleType::kDisclosureClosed:
return ListStyleCategory::kSymbol;
case EListStyleType::kArabicIndic:
case EListStyleType::kArmenian:
diff --git a/chromium/third_party/blink/renderer/core/layout/list_marker.h b/chromium/third_party/blink/renderer/core/layout/list_marker.h
index 9763ed1193e..e9ed1b36e48 100644
--- a/chromium/third_party/blink/renderer/core/layout/list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/list_marker.h
@@ -10,6 +10,7 @@
namespace blink {
+class CounterStyle;
class LayoutListItem;
class LayoutNGListItem;
class LayoutText;
@@ -50,9 +51,11 @@ class CORE_EXPORT ListMarker {
// Compute inline margins for 'list-style-position: inside' and 'outside'.
static std::pair<LayoutUnit, LayoutUnit> InlineMarginsForInside(
+ Document&,
const ComputedStyle& marker_style,
const ComputedStyle& list_item_style);
static std::pair<LayoutUnit, LayoutUnit> InlineMarginsForOutside(
+ Document&,
const ComputedStyle& marker_style,
const ComputedStyle& list_item_style,
LayoutUnit marker_inline_size);
@@ -66,10 +69,13 @@ class CORE_EXPORT ListMarker {
// Returns the list's style as one of a reduced high level categorical set of
// styles.
- static ListStyleCategory GetListStyleCategory(EListStyleType);
+ static ListStyleCategory GetListStyleCategory(Document&,
+ const ComputedStyle&);
+
+ static const CounterStyle& GetCounterStyle(Document&, const ComputedStyle&);
private:
- enum MarkerTextFormat { kWithSuffix, kWithoutSuffix };
+ enum MarkerTextFormat { kWithPrefixSuffix, kWithoutPrefixSuffix };
enum MarkerTextType {
kNotText, // The marker doesn't have a LayoutText, either because it has
// not been created yet or because 'list-style-type' is 'none',
@@ -88,6 +94,7 @@ class CORE_EXPORT ListMarker {
void ListStyleTypeChanged(LayoutObject&);
void OrdinalValueChanged(LayoutObject&);
+ void CounterStyleChanged(LayoutObject&);
int ListItemValue(const LayoutObject&) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/list_marker_test.cc b/chromium/third_party/blink/renderer/core/layout/list_marker_test.cc
new file mode 100644
index 00000000000..aa70c9ab7b5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/list_marker_test.cc
@@ -0,0 +1,312 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/list_marker.h"
+
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
+
+namespace blink {
+
+// We don't test legacy layout because it's deprecated, and we don't want to
+// complicate the test with the legacy LayoutListMarker here.
+class ListMarkerTest : public NGLayoutTest {
+ protected:
+ LayoutObject* GetMarker(const char* list_item_id) {
+ LayoutNGListItem* list_item =
+ To<LayoutNGListItem>(GetLayoutObjectByElementId(list_item_id));
+ return list_item->Marker();
+ }
+
+ LayoutObject* GetMarker(TreeScope& scope, const char* list_item_id) {
+ Element* list_item = scope.getElementById(list_item_id);
+ return To<LayoutNGListItem>(list_item->GetLayoutObject())->Marker();
+ }
+
+ String GetMarkerText(TreeScope& scope, const char* list_item_id) {
+ return To<LayoutText>(GetMarker(scope, list_item_id)->SlowFirstChild())
+ ->GetText();
+ }
+
+ String GetMarkerText(const char* list_item_id) {
+ return GetMarkerText(GetDocument(), list_item_id);
+ }
+
+ void AddCounterStyle(const AtomicString& name, const String& descriptors) {
+ StringBuilder declaration;
+ declaration.Append("@counter-style ");
+ declaration.Append(name);
+ declaration.Append("{");
+ declaration.Append(descriptors);
+ declaration.Append("}");
+ Element* sheet = GetDocument().CreateElementForBinding("style");
+ sheet->setInnerHTML(declaration.ToString());
+ GetDocument().body()->appendChild(sheet);
+ }
+};
+
+TEST_F(ListMarkerTest, AddCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: W X Y Z;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="foo" style="list-style-type: foo"></li>
+ <li id="bar" style="list-style-type: bar"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+ EXPECT_EQ("3. ", GetMarkerText("bar"));
+
+ // Add @counter-style 'bar'. Should not affect 'decimal' and 'foo'.
+ AddCounterStyle("bar", "system: fixed; symbols: A B C;");
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_FALSE(GetMarker("foo")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("bar")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+ EXPECT_EQ("C. ", GetMarkerText("bar"));
+}
+
+TEST_F(ListMarkerTest, RemoveCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style id="foo-sheet">
+ @counter-style foo {
+ system: fixed;
+ symbols: W X Y Z;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="foo" style="list-style-type: foo"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+
+ // Remove @counter-style 'foo'. Should not affect 'decimal'.
+ GetElementById("foo-sheet")->remove();
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("foo")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("2. ", GetMarkerText("foo"));
+}
+
+TEST_F(ListMarkerTest, OverridePredefinedCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="upper-roman" style="list-style-type: upper-roman"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("II. ", GetMarkerText("upper-roman"));
+
+ // Override 'upper-roman'. Should not affect 'decimal'.
+ AddCounterStyle("upper-roman", "system: fixed; symbols: A B C;");
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("upper-roman")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("B. ", GetMarkerText("upper-roman"));
+}
+
+TEST_F(ListMarkerTest, RemoveOverrideOfPredefinedCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style id="to-remove">
+ @counter-style upper-roman {
+ system: fixed;
+ symbols: A B C;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="upper-roman" style="list-style-type: upper-roman"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("B. ", GetMarkerText("upper-roman"));
+
+ // Remove override of 'upper-roman'. Should not affect 'decimal'.
+ GetElementById("to-remove")->remove();
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("upper-roman")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("II. ", GetMarkerText("upper-roman"));
+}
+
+TEST_F(ListMarkerTest, OverrideSameScopeCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: W X Y Z;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="foo" style="list-style-type: foo"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+
+ // Override 'foo'. Should not affect 'decimal'.
+ AddCounterStyle("foo", "system: fixed; symbols: A B C;");
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("foo")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("B. ", GetMarkerText("foo"));
+}
+
+TEST_F(ListMarkerTest, RemoveOverrideOfSameScopeCounterStyle) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: W X Y Z;
+ }
+ </style>
+ <style id="to-remove">
+ @counter-style foo {
+ system: fixed;
+ symbols: A B C;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="foo" style="list-style-type: foo"></li>
+ </ol>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("B. ", GetMarkerText("foo"));
+
+ // Remove the override of 'foo'. Should not affect 'decimal'.
+ GetElementById("to-remove")->remove();
+ GetDocument().UpdateStyleAndLayoutTree();
+
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_TRUE(GetMarker("foo")->NeedsLayout());
+
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+}
+
+TEST_F(ListMarkerTest, ModifyShadowDOMWithOwnCounterStyles) {
+ GetDocument().body()->setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: W X Y Z;
+ }
+ </style>
+ <ol>
+ <li id="decimal" style="list-style-type: decimal"></li>
+ <li id="foo" style="list-style-type: foo"></li>
+ </ol>
+ <div id="host1"></div>
+ <div id="host2"></div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+
+ // Attach a shadow tree with counter styles. Shouldn't affect anything outside
+ ShadowRoot& shadow1 =
+ GetElementById("host1")->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow1.setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: A B C;
+ }
+ </style>
+ <ol>
+ <li id="shadow-foo" style="list-style-type: foo"></li>
+ </ol>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_FALSE(GetMarker("foo")->NeedsLayout());
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+ EXPECT_EQ("A. ", GetMarkerText(shadow1, "shadow-foo"));
+
+ // Attach another shadow tree with counter styles. Shouldn't affect anything
+ // outside.
+ ShadowRoot& shadow2 =
+ GetElementById("host2")->AttachShadowRootInternal(ShadowRootType::kOpen);
+ shadow2.setInnerHTML(R"HTML(
+ <style>
+ @counter-style foo {
+ system: fixed;
+ symbols: D E F;
+ }
+ </style>
+ <ol>
+ <li id="shadow-foo" style="list-style-type: foo"></li>
+ </ol>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_FALSE(GetMarker("foo")->NeedsLayout());
+ EXPECT_FALSE(GetMarker(shadow1, "shadow-foo")->NeedsLayout());
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+ EXPECT_EQ("A. ", GetMarkerText(shadow1, "shadow-foo"));
+ EXPECT_EQ("D. ", GetMarkerText(shadow2, "shadow-foo"));
+
+ // Remove one of the shadow trees. Shouldn't affect anything outside.
+ GetElementById("host1")->remove();
+ GetDocument().UpdateStyleAndLayoutTree();
+ EXPECT_FALSE(GetMarker("decimal")->NeedsLayout());
+ EXPECT_FALSE(GetMarker("foo")->NeedsLayout());
+ EXPECT_FALSE(GetMarker(shadow2, "shadow-foo")->NeedsLayout());
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ("1. ", GetMarkerText("decimal"));
+ EXPECT_EQ("X. ", GetMarkerText("foo"));
+ EXPECT_EQ("D. ", GetMarkerText(shadow2, "shadow-foo"));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/list_marker_text.cc b/chromium/third_party/blink/renderer/core/layout/list_marker_text.cc
index 174c83ee69c..0fff3c31e7b 100644
--- a/chromium/third_party/blink/renderer/core/layout/list_marker_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/list_marker_text.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/layout/list_marker_text.h"
#include "third_party/blink/renderer/core/layout/text_run_constructor.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -178,18 +179,31 @@ static String ToHebrew(int number) {
DCHECK_GE(number, 0);
DCHECK_LE(number, 999999);
+ Vector<UChar> letters;
+
if (number == 0) {
static const UChar kHebrewZero[3] = {0x05E1, 0x05E4, 0x05D0};
- return String(kHebrewZero, 3);
+ letters.Append(kHebrewZero, 3);
+ } else {
+ if (number > 999) {
+ ToHebrewUnder1000(number / 1000, letters);
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled())
+ letters.push_front(kHebrewPunctuationGereshCharacter);
+ else
+ letters.push_front('\'');
+ number = number % 1000;
+ }
+ ToHebrewUnder1000(number, letters);
}
- Vector<UChar> letters;
- if (number > 999) {
- ToHebrewUnder1000(number / 1000, letters);
- letters.push_front('\'');
- number = number % 1000;
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ // Since Hebrew is RTL, legacy implementation generates letters in the
+ // reversed ordering, which is actually wrong because characters in a String
+ // should always be in the logical ordering. We re-reverse it so that the
+ // output ordering is correct.
+ std::reverse(letters.begin(), letters.end());
}
- ToHebrewUnder1000(number, letters);
+
return String(letters);
}
@@ -461,6 +475,8 @@ static EListStyleType EffectiveListMarkerType(EListStyleType type, int count) {
case EListStyleType::kDecimal:
case EListStyleType::kDevanagari:
case EListStyleType::kDisc:
+ case EListStyleType::kDisclosureClosed:
+ case EListStyleType::kDisclosureOpen:
case EListStyleType::kGujarati:
case EListStyleType::kGurmukhi:
case EListStyleType::kKannada:
@@ -535,6 +551,8 @@ UChar Suffix(EListStyleType type, int count) {
switch (effective_type) {
case EListStyleType::kCircle:
case EListStyleType::kDisc:
+ case EListStyleType::kDisclosureClosed:
+ case EListStyleType::kDisclosureOpen:
case EListStyleType::kNone:
case EListStyleType::kSquare:
return ' ';
@@ -616,6 +634,14 @@ String GetText(EListStyleType type, int count) {
return String(&kWhiteBulletCharacter, 1);
case EListStyleType::kDisc:
return String(&kBulletCharacter, 1);
+
+ // TODO(layout-dev): Text for disclosure-* should not depend on physical
+ // shape?
+ case EListStyleType::kDisclosureClosed:
+ return String(&kBlackRightPointingSmallTriangle, 1);
+ case EListStyleType::kDisclosureOpen:
+ return String(&kBlackDownPointingSmallTriangle, 1);
+
case EListStyleType::kSquare:
// The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE
// instead, but I think this looks better.
diff --git a/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h b/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
index aec3f6ac9c1..9bd8bd9f21c 100644
--- a/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
+++ b/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
@@ -32,6 +32,9 @@ enum MapCoordinatesMode {
// This flag is not implemented in all methods that take a MapCoordinatesMode
// parameter; see particular methods for more details.
kUseGeometryMapperMode = 1 << 7,
+
+ // Ignore the scroll offset of the mapped-to ancestor.
+ kIgnoreScrollOffsetOfAncestor = 1 << 8,
};
typedef unsigned MapCoordinatesFlags;
diff --git a/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc b/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
index 046f67ba238..16d81d5062f 100644
--- a/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
@@ -1313,7 +1313,13 @@ TEST_F(MapCoordinatesTest, Table) {
LayoutBox* tr = td->ParentBox();
ASSERT_TRUE(tr->IsTableRow());
mapped_point = MapLocalToAncestor(td, tr, PhysicalOffset(2, 47));
- EXPECT_EQ(PhysicalOffset(126, 47), mapped_point);
+ // TablesNG and Legacy row inline starts differ:
+ // TablesNG inline start does not include border-spacing,
+ // Legacy does.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(PhysicalOffset(116, 47), mapped_point);
+ else
+ EXPECT_EQ(PhysicalOffset(126, 47), mapped_point);
mapped_point = MapAncestorToLocal(td, tr, mapped_point);
EXPECT_EQ(PhysicalOffset(2, 47), mapped_point);
@@ -1327,7 +1333,11 @@ TEST_F(MapCoordinatesTest, Table) {
LayoutBox* table = tbody->ParentBox();
ASSERT_TRUE(table->IsTable());
mapped_point = MapLocalToAncestor(tbody, table, PhysicalOffset(126, 161));
- EXPECT_EQ(PhysicalOffset(131, 290), mapped_point);
+ // TablesNG and Legacy row inline starts differ.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ EXPECT_EQ(PhysicalOffset(141, 290), mapped_point);
+ else
+ EXPECT_EQ(PhysicalOffset(131, 290), mapped_point);
mapped_point = MapAncestorToLocal(tbody, table, mapped_point);
EXPECT_EQ(PhysicalOffset(126, 161), mapped_point);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/DIR_METADATA b/chromium/third_party/blink/renderer/core/layout/ng/DIR_METADATA
new file mode 100644
index 00000000000..3611c38fad3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Layout"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/OWNERS b/chromium/third_party/blink/renderer/core/layout/ng/OWNERS
index 5957a04bb71..f5863748001 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/OWNERS
+++ b/chromium/third_party/blink/renderer/core/layout/ng/OWNERS
@@ -2,7 +2,5 @@ cbiesinger@chromium.org
ikilpatrick@chromium.org
atotic@chromium.org
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
# emeritus:
# eae@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA b/chromium/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA
new file mode 100644
index 00000000000..3611c38fad3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Layout"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/OWNERS b/chromium/third_party/blink/renderer/core/layout/ng/custom/OWNERS
index e814a6993ef..bed855fcc9c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/OWNERS
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/OWNERS
@@ -1,5 +1,2 @@
ikilpatrick@chromium.org
kojii@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
index eb297944b1f..998e7bd4ff1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
@@ -131,10 +131,8 @@ void CustomLayoutWorkTask::RunLayoutFragmentTask(
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(percentage_size);
builder.SetReplacedPercentageResolutionSize(percentage_size);
- builder.SetIsShrinkToFit(child.Style().LogicalWidth().IsAuto());
builder.SetIsFixedInlineSize(is_fixed_inline_size);
builder.SetIsFixedBlockSize(is_fixed_block_size);
- builder.SetNeedsBaseline(true);
if (child.IsLayoutNGCustom())
builder.SetCustomLayoutData(std::move(constraint_data_));
auto space = builder.ToConstraintSpace();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
index 965a5dee050..a948b79df7d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
@@ -42,7 +42,7 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
window->Url(), mojom::blink::ScriptType::kModule, global_scope_name,
window->UserAgent(), frame->Client()->UserAgentMetadata(),
frame->Client()->CreateWorkerFetchContext(),
- window->GetContentSecurityPolicy()->Headers(),
+ mojo::Clone(window->GetContentSecurityPolicy()->GetParsedPolicies()),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(),
nullptr /* worker_clients */,
@@ -52,7 +52,8 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
mojom::blink::V8CacheOptions::kDefault, module_responses_map,
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken(),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken(),
window->CrossOriginIsolatedCapability());
global_scope_ = LayoutWorkletGlobalScope::Create(
frame, std::move(creation_params), *reporting_proxy_,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
index 3217da14a4b..42953a69f09 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
@@ -58,10 +58,8 @@ class LayoutWorkletTest : public PageTestBase, public ParametrizedModuleTest {
EXPECT_TRUE(script_state);
KURL js_url("https://example.com/worklet.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- script_state->GetIsolate(), source_code, js_url, js_url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ script_state->GetIsolate(), source_code, js_url);
EXPECT_FALSE(module.IsEmpty());
ScriptValue exception =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
index 2058d3c3d51..928a8bea4cf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_intrinsic_sizes_result_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
#include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
@@ -48,11 +49,19 @@ MinMaxSizesResult NGCustomLayoutAlgorithm::ComputeMinMaxSizes(
bool depends_on_percentage_block_size = false;
IntrinsicSizesResultOptions* intrinsic_sizes_result_options = nullptr;
- if (!instance->IntrinsicSizes(
- ConstraintSpace(), document, Node(),
- container_builder_.InitialBorderBoxSize(), BorderScrollbarPadding(),
- input.percentage_resolution_block_size, &scope,
- &intrinsic_sizes_result_options, &depends_on_percentage_block_size)) {
+ LogicalSize border_box_size{
+ container_builder_.InlineSize(),
+ ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), BorderPadding(),
+ CalculateDefaultBlockSize(ConstraintSpace(), Node(),
+ BorderScrollbarPadding()),
+ container_builder_.InlineSize(),
+ Node().ShouldBeConsideredAsReplaced())};
+ if (!instance->IntrinsicSizes(ConstraintSpace(), document, Node(),
+ border_box_size, BorderScrollbarPadding(),
+ input.percentage_resolution_block_size, &scope,
+ &intrinsic_sizes_result_options,
+ &depends_on_percentage_block_size)) {
// TODO(ikilpatrick): Report this error to the developer.
return FallbackMinMaxSizes(input);
}
@@ -67,7 +76,7 @@ MinMaxSizesResult NGCustomLayoutAlgorithm::ComputeMinMaxSizes(
sizes.min_size.ClampNegativeToZero();
sizes.max_size.ClampNegativeToZero();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
@@ -94,8 +103,15 @@ scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
FragmentResultOptions* fragment_result_options = nullptr;
scoped_refptr<SerializedScriptValue> fragment_result_data;
- if (!instance->Layout(ConstraintSpace(), document, Node(),
- container_builder_.InitialBorderBoxSize(),
+ LogicalSize border_box_size{
+ container_builder_.InlineSize(),
+ ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), BorderPadding(),
+ CalculateDefaultBlockSize(ConstraintSpace(), Node(),
+ BorderScrollbarPadding()),
+ container_builder_.InlineSize(),
+ Node().ShouldBeConsideredAsReplaced())};
+ if (!instance->Layout(ConstraintSpace(), document, Node(), border_box_size,
BorderScrollbarPadding(), &scope,
fragment_result_options, &fragment_result_data)) {
// TODO(ikilpatrick): Report this error to the developer.
@@ -152,7 +168,8 @@ scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
LayoutUnit::FromDoubleRound(fragment_result_options->autoBlockSize()));
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), auto_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
if (fragment_result_options->hasBaseline()) {
LayoutUnit baseline =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
index 3f0960775d2..35bf9de8986 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
@@ -103,8 +103,8 @@ void CollectSolidEdges(
bool Intersects(const NGLayoutOpportunity& opportunity,
const NGBfcOffset& offset,
const LayoutUnit inline_size) {
- return opportunity.rect.LineEndOffset() > offset.line_offset &&
- opportunity.rect.LineStartOffset() <
+ return opportunity.rect.LineEndOffset() >= offset.line_offset &&
+ opportunity.rect.LineStartOffset() <=
offset.line_offset + inline_size &&
opportunity.rect.BlockEndOffset() > offset.block_offset;
}
@@ -379,8 +379,8 @@ void NGExclusionSpaceInternal::DerivedGeometry::Add(
// In the above example the "NEW" exclusion *doesn't* overlap with the
// above drawn shelf, and a new opportunity hasn't been created.
bool is_overlapping =
- exclusion.rect.LineStartOffset() < shelf.line_right &&
- exclusion.rect.LineEndOffset() > shelf.line_left;
+ exclusion.rect.LineStartOffset() <= shelf.line_right &&
+ exclusion.rect.LineEndOffset() >= shelf.line_left;
// Insert a closed-off layout opportunity if needed.
if (has_solid_edges && is_overlapping) {
@@ -448,8 +448,22 @@ void NGExclusionSpaceInternal::DerivedGeometry::Add(
if (exclusion.shape_data)
shelf.has_shape_exclusions = true;
- // Just in case the shelf has a negative inline-size.
- shelf.line_right = std::max(shelf.line_left, shelf.line_right);
+ // A shelf can be completely closed off and not needed anymore. For
+ // example:
+ //
+ // 0 1 2 3 4 5 6 7 8
+ // 0 +---+X----------X
+ // |xxx|
+ // 10 |xxx|
+ // +---+
+ // 20
+ // +-----------+
+ // 30 |NEW (right)|
+ // +-----------+
+ //
+ // In the above example "NEW (right)" will have shrunk the shelf such
+ // that line_right will now be smaller than line_left.
+ bool is_closed_off = shelf.line_left > shelf.line_right;
// We can end up in a situation where a shelf is the same as the
// previous one. For example:
@@ -469,7 +483,7 @@ void NGExclusionSpaceInternal::DerivedGeometry::Add(
bool is_same_as_previous =
(i > 0) && shelf.line_left == shelves_[i - 1].line_left &&
shelf.line_right == shelves_[i - 1].line_right;
- if (is_same_as_previous) {
+ if (is_closed_off || is_same_as_previous) {
shelves_.EraseAt(i);
--i;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
index 377c48f62d3..64689e3a652 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
@@ -126,14 +126,12 @@ TEST(NGExclusionSpaceTest, TwoExclusions) {
/* offset */ {LayoutUnit(), LayoutUnit()},
/* available_size */ LayoutUnit(400));
- EXPECT_EQ(4u, opportunites.size());
+ EXPECT_EQ(3u, opportunites.size());
TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(150), LayoutUnit()),
NGBfcOffset(LayoutUnit(400), LayoutUnit(75)));
- TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(150), LayoutUnit()),
- NGBfcOffset(LayoutUnit(150), LayoutUnit::Max()));
- TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(), LayoutUnit(75)),
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(), LayoutUnit(75)),
NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
- TEST_OPPORTUNITY(opportunites[3], NGBfcOffset(LayoutUnit(), LayoutUnit(150)),
+ TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(), LayoutUnit(150)),
NGBfcOffset(LayoutUnit(400), LayoutUnit::Max()));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index d4bf83aa10d..13fcd16f332 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_button.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
@@ -35,14 +36,15 @@ NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(
: NGLayoutAlgorithm(params),
is_column_(Style().ResolvedIsColumnFlexDirection()),
is_horizontal_flow_(FlexLayoutAlgorithm::IsHorizontalFlow(Style())),
- is_cross_size_definite_(IsContainerCrossSizeDefinite()) {
- border_box_size_ = container_builder_.InitialBorderBoxSize();
- child_percentage_size_ = CalculateChildPercentageSize(
- ConstraintSpace(), Node(), ChildAvailableSize());
-
- algorithm_.emplace(&Style(), MainAxisContentExtent(LayoutUnit::Max()),
- child_percentage_size_, &Node().GetDocument());
-}
+ is_cross_size_definite_(IsContainerCrossSizeDefinite()),
+ child_percentage_size_(
+ CalculateChildPercentageSize(ConstraintSpace(),
+ Node(),
+ ChildAvailableSize())),
+ algorithm_(&Style(),
+ MainAxisContentExtent(LayoutUnit::Max()),
+ child_percentage_size_,
+ &Node().GetDocument()) {}
bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(
const NGBlockNode& child) const {
@@ -52,7 +54,7 @@ bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(
LayoutUnit NGFlexLayoutAlgorithm::MainAxisContentExtent(
LayoutUnit sum_hypothetical_main_size) const {
- if (Style().ResolvedIsColumnFlexDirection()) {
+ if (is_column_) {
// Even though we only pass border_padding in the third parameter, the
// return value includes scrollbar, so subtract scrollbar to get content
// size.
@@ -65,7 +67,8 @@ LayoutUnit NGFlexLayoutAlgorithm::MainAxisContentExtent(
ConstraintSpace(), Style(), BorderPadding(),
sum_hypothetical_main_size.ClampNegativeToZero() +
border_scrollbar_padding,
- border_box_size_.inline_size) -
+ container_builder_.InlineSize(),
+ Node().ShouldBeConsideredAsReplaced()) -
border_scrollbar_padding;
}
return ChildAvailableSize().inline_size;
@@ -163,33 +166,15 @@ void NGFlexLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode child) {
bool NGFlexLayoutAlgorithm::IsColumnContainerMainSizeDefinite() const {
DCHECK(is_column_);
- // If this flex container is also a flex item, it might have a definite size
- // imposed on it by its parent flex container.
- // We can't rely on BlockLengthUnresolvable for this case because that
- // considers Auto as unresolvable even when the block size is fixed and
- // definite.
- if (ConstraintSpace().IsFixedBlockSize() &&
- !ConstraintSpace().IsFixedBlockSizeIndefinite())
- return true;
- Length main_size = Style().LogicalHeight();
- return !BlockLengthUnresolvable(ConstraintSpace(), main_size,
- LengthResolvePhase::kLayout);
+ return ChildAvailableSize().block_size != kIndefiniteSize;
}
bool NGFlexLayoutAlgorithm::IsContainerCrossSizeDefinite() const {
// A column flexbox's cross axis is an inline size, so is definite.
if (is_column_)
return true;
- // If this flex container is also a flex item, it might have a definite size
- // imposed on it by its parent flex container.
- // TODO(dgrogan): Removing this check doesn't cause any tests to fail. Remove
- // it if unneeded or add a test that needs it.
- if (ConstraintSpace().IsFixedBlockSize() &&
- !ConstraintSpace().IsFixedBlockSizeIndefinite())
- return true;
- return !BlockLengthUnresolvable(ConstraintSpace(), Style().LogicalHeight(),
- LengthResolvePhase::kLayout);
+ return ChildAvailableSize().block_size != kIndefiniteSize;
}
bool NGFlexLayoutAlgorithm::DoesItemStretch(const NGBlockNode& child) const {
@@ -217,8 +202,7 @@ bool NGFlexLayoutAlgorithm::IsItemFlexBasisDefinite(
"support.";
if (!is_column_)
return true;
- return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), flex_basis,
- LengthResolvePhase::kLayout);
+ return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), flex_basis);
}
// This behavior is under discussion: the item's pre-flexing main size
@@ -240,8 +224,7 @@ bool NGFlexLayoutAlgorithm::IsItemMainSizeDefinite(
// space for flex-basis is sufficient, even though it has some unnecessary
// stuff (ShrinkToFit and fixed cross sizes).
return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child),
- child.Style().LogicalHeight(),
- LengthResolvePhase::kLayout);
+ child.Style().LogicalHeight());
}
bool NGFlexLayoutAlgorithm::IsItemCrossAxisLengthDefinite(
@@ -255,8 +238,7 @@ bool NGFlexLayoutAlgorithm::IsItemCrossAxisLengthDefinite(
if (!MainAxisIsInlineAxis(child))
return true;
// If we get here, cross axis is block axis.
- return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), length,
- LengthResolvePhase::kLayout);
+ return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), length);
}
bool NGFlexLayoutAlgorithm::DoesItemCrossSizeComputeToAuto(
@@ -267,48 +249,17 @@ bool NGFlexLayoutAlgorithm::DoesItemCrossSizeComputeToAuto(
return child_style.Width().IsAuto();
}
-// This function is used to handle two requirements from the spec.
-// (1) Calculating flex base size; case 3E at
-// https://drafts.csswg.org/css-flexbox/#algo-main-item : If a cross size is
-// needed to determine the main size (e.g. when the flex item’s main size is
-// in its block axis) and the flex item’s cross size is auto and not
-// definite, in this calculation use fit-content as the flex item’s cross size.
-// The flex base size is the item’s resulting main size.
-// (2) Cross size determination after main size has been calculated.
-// https://drafts.csswg.org/css-flexbox/#algo-cross-item : Determine the
-// hypothetical cross size of each item by performing layout with the used main
-// size and the available space, treating auto as fit-content.
-bool NGFlexLayoutAlgorithm::ShouldItemShrinkToFit(
- const NGBlockNode& child) const {
- if (MainAxisIsInlineAxis(child)) {
- // In this case, the cross size is in the item's block axis. The item's
- // block size is never needed to determine its inline size so don't use
- // fit-content.
- return false;
- }
- if (!child.Style().LogicalWidth().IsAuto()) {
- DCHECK(!DoesItemCrossSizeComputeToAuto(child));
- // The cross size (item's inline size) is already specified, so don't use
- // fit-content.
- return false;
- }
- DCHECK(DoesItemCrossSizeComputeToAuto(child));
- // If execution reaches here, the item's inline size is its cross size and
- // computes to auto. In that situation, we only don't use fit-content if the
- // item qualifies for the first case in
- // https://drafts.csswg.org/css-flexbox/#definite-sizes :
- // 1. If a single-line flex container has a definite cross size, the outer
- // cross size of any stretched flex items is the flex container’s inner cross
- // size (clamped to the flex item’s min and max cross size) and is considered
- // definite.
- if (WillChildCrossSizeBeContainerCrossSize(child))
- return false;
- return true;
+bool NGFlexLayoutAlgorithm::AspectRatioProvidesMainSize(
+ const NGBlockNode& child,
+ const Length& cross_axis_length) const {
+ return child.HasAspectRatio() &&
+ (IsItemCrossAxisLengthDefinite(child, cross_axis_length) ||
+ WillChildCrossSizeBeContainerCrossSize(child));
}
bool NGFlexLayoutAlgorithm::WillChildCrossSizeBeContainerCrossSize(
const NGBlockNode& child) const {
- return !algorithm_->IsMultiline() && is_cross_size_definite_ &&
+ return !algorithm_.IsMultiline() && is_cross_size_definite_ &&
DoesItemStretch(child);
}
@@ -331,22 +282,8 @@ double NGFlexLayoutAlgorithm::GetMainOverCrossAspectRatio(
return ratio;
}
-LayoutUnit NGFlexLayoutAlgorithm::CalculateFixedCrossSize(
- const MinMaxSizes& cross_axis_min_max,
- const NGBoxStrut& margins) const {
- if (!is_column_)
- DCHECK_NE(ChildAvailableSize().block_size, kIndefiniteSize);
- LayoutUnit available_size = is_column_ ? ChildAvailableSize().inline_size
- : ChildAvailableSize().block_size;
- LayoutUnit margin_sum = is_column_ ? margins.InlineSum() : margins.BlockSum();
- return cross_axis_min_max.ClampSizeToMinAndMax(available_size - margin_sum);
-}
-
NGConstraintSpace NGFlexLayoutAlgorithm::BuildSpaceForIntrinsicBlockSize(
- const NGBlockNode& flex_item,
- const NGPhysicalBoxStrut& physical_margins = NGPhysicalBoxStrut(),
- const MinMaxSizes& cross_axis_min_max = MinMaxSizes{
- kIndefiniteSize, kIndefiniteSize}) const {
+ const NGBlockNode& flex_item) const {
const ComputedStyle& child_style = flex_item.Style();
NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
child_style.GetWritingDirection(),
@@ -355,36 +292,22 @@ NGConstraintSpace NGFlexLayoutAlgorithm::BuildSpaceForIntrinsicBlockSize(
space_builder.SetCacheSlot(NGCacheSlot::kMeasure);
space_builder.SetIsPaintedAtomically(true);
- NGBoxStrut margins = physical_margins.ConvertToLogical(
- ConstraintSpace().GetWritingDirection());
- LogicalSize child_available_size = ChildAvailableSize();
- if (ShouldItemShrinkToFit(flex_item)) {
- space_builder.SetIsShrinkToFit(true);
- } else if (cross_axis_min_max.min_size != kIndefiniteSize &&
- WillChildCrossSizeBeContainerCrossSize(flex_item)) {
- LayoutUnit cross_size =
- CalculateFixedCrossSize(cross_axis_min_max, margins);
- if (is_column_) {
- space_builder.SetIsFixedInlineSize(true);
- child_available_size.inline_size = cross_size;
- } else {
- space_builder.SetIsFixedBlockSize(true);
- child_available_size.block_size = cross_size;
- }
+ if (WillChildCrossSizeBeContainerCrossSize(flex_item)) {
+ if (is_column_)
+ space_builder.SetStretchInlineSizeIfAuto(true);
+ else
+ space_builder.SetStretchBlockSizeIfAuto(true);
}
- space_builder.SetNeedsBaseline(
- ConstraintSpace().NeedsBaseline() ||
- FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
- ItemPosition::kBaseline);
-
// For determining the intrinsic block-size we make %-block-sizes resolve
// against an indefinite size.
LogicalSize child_percentage_size = child_percentage_size_;
- if (is_column_)
+ if (is_column_) {
child_percentage_size.block_size = kIndefiniteSize;
+ space_builder.SetIsFixedBlockSizeIndefinite(true);
+ }
- space_builder.SetAvailableSize(child_available_size);
+ space_builder.SetAvailableSize(ChildAvailableSize());
space_builder.SetPercentageResolutionSize(child_percentage_size);
// TODO(dgrogan): The SetReplacedPercentageResolutionSize calls in this file
// may be untested. Write a test or determine why they're unnecessary.
@@ -572,6 +495,9 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
is_horizontal_flow_ ? physical_border_padding.VerticalSum()
: physical_border_padding.HorizontalSum();
+ const Length& cross_axis_length =
+ is_horizontal_flow_ ? child.Style().Height() : child.Style().Width();
+
base::Optional<MinMaxSizesResult> min_max_sizes;
auto MinMaxSizesFunc = [&](MinMaxSizesType type) -> MinMaxSizesResult {
if (!min_max_sizes) {
@@ -602,34 +528,29 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- MinMaxSizesFunc, max_property_in_main_axis,
- LengthResolvePhase::kLayout);
+ MinMaxSizesFunc, max_property_in_main_axis);
min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- max_property_in_cross_axis, LengthResolvePhase::kLayout);
+ max_property_in_cross_axis);
min_max_sizes_in_cross_axis_direction.min_size = ResolveMinBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- min_property_in_cross_axis, LengthResolvePhase::kLayout);
+ min_property_in_cross_axis);
} else {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- max_property_in_main_axis, LengthResolvePhase::kLayout);
+ max_property_in_main_axis);
min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- MinMaxSizesFunc, max_property_in_cross_axis,
- LengthResolvePhase::kLayout);
+ MinMaxSizesFunc, max_property_in_cross_axis);
min_max_sizes_in_cross_axis_direction.min_size = ResolveMinInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- MinMaxSizesFunc, min_property_in_cross_axis,
- LengthResolvePhase::kLayout);
+ MinMaxSizesFunc, min_property_in_cross_axis);
}
base::Optional<LayoutUnit> calculated_intrinsic_block_size;
auto IntrinsicBlockSizeFunc = [&]() -> LayoutUnit {
if (!calculated_intrinsic_block_size) {
- NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(
- child, physical_child_margins,
- min_max_sizes_in_cross_axis_direction);
+ NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(child);
scoped_refptr<const NGLayoutResult> layout_result =
child.Layout(child_space, /* break_token */ nullptr);
calculated_intrinsic_block_size = layout_result->IntrinsicBlockSize();
@@ -637,6 +558,33 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
return *calculated_intrinsic_block_size;
};
+ auto ComputeTransferredMainSize = [&]() -> LayoutUnit {
+ DCHECK_NE(IsItemCrossAxisLengthDefinite(child, cross_axis_length),
+ WillChildCrossSizeBeContainerCrossSize(child));
+ LayoutUnit cross_size;
+ Length cross_axis_length_to_resolve = cross_axis_length;
+ if (WillChildCrossSizeBeContainerCrossSize(child))
+ cross_axis_length_to_resolve = Length::FillAvailable();
+ if (MainAxisIsInlineAxis(child)) {
+ cross_size = ResolveMainBlockLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ cross_axis_length_to_resolve, kIndefiniteSize);
+ } else {
+ cross_size = ResolveMainInlineLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, cross_axis_length_to_resolve);
+ }
+ DCHECK_GE(cross_size, LayoutUnit());
+ cross_size = min_max_sizes_in_cross_axis_direction.ClampSizeToMinAndMax(
+ cross_size);
+ // TODO(dgrogan): This isn't right for non-replaced aspect-ratio items
+ // with box-sizing: border-box, but it's what existing code does. Fix in a
+ // follow-up CL by reusing something from ng_length_utils.
+ return LayoutUnit((cross_size - cross_axis_border_padding) *
+ GetMainOverCrossAspectRatio(child) +
+ main_axis_border_padding);
+ };
+
// The logic that calculates flex_base_border_box assumes that the used
// value of the flex-basis property is either definite or 'content'.
LayoutUnit flex_base_border_box;
@@ -661,45 +609,11 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// This block means that the used flex-basis is 'content'. In here we
// implement parts B,C,D,E of 9.2.3
// https://drafts.csswg.org/css-flexbox/#algo-main-item
- const Length& cross_axis_length =
- is_horizontal_flow_ ? child.Style().Height() : child.Style().Width();
- // This check should use HasAspectRatio() instead of Style().
- // AspectRatio(), but to avoid introducing a behavior change we only
- // do this for the aspect-ratio property for now until FlexNG ships.
- bool use_container_cross_size_for_aspect_ratio =
- (!child.Style().AspectRatio().IsAuto() ||
- (child.HasAspectRatio() &&
- RuntimeEnabledFeatures::FlexAspectRatioEnabled())) &&
- WillChildCrossSizeBeContainerCrossSize(child);
- if (use_container_cross_size_for_aspect_ratio ||
- (child.HasAspectRatio() &&
- (IsItemCrossAxisLengthDefinite(child, cross_axis_length)))) {
+ if (AspectRatioProvidesMainSize(child, cross_axis_length)) {
// This is Part B of 9.2.3
// https://drafts.csswg.org/css-flexbox/#algo-main-item It requires that
// the item has a definite cross size.
- LayoutUnit cross_size;
- if (use_container_cross_size_for_aspect_ratio) {
- NGBoxStrut margins = physical_child_margins.ConvertToLogical(
- ConstraintSpace().GetWritingDirection());
- cross_size = CalculateFixedCrossSize(
- min_max_sizes_in_cross_axis_direction, margins);
- } else if (MainAxisIsInlineAxis(child)) {
- cross_size = ResolveMainBlockLength(
- flex_basis_space, child_style,
- border_padding_in_child_writing_mode, cross_axis_length,
- kIndefiniteSize, LengthResolvePhase::kLayout);
- } else {
- cross_size =
- ResolveMainInlineLength(flex_basis_space, child_style,
- border_padding_in_child_writing_mode,
- MinMaxSizesFunc, cross_axis_length);
- }
- cross_size = min_max_sizes_in_cross_axis_direction.ClampSizeToMinAndMax(
- cross_size);
- flex_base_border_box =
- LayoutUnit((cross_size - cross_axis_border_padding) *
- GetMainOverCrossAspectRatio(child) +
- main_axis_border_padding);
+ flex_base_border_box = ComputeTransferredMainSize();
} else if (MainAxisIsInlineAxis(child)) {
// We're now in parts C, D, and E for what are usually (horizontal-tb
// containers AND children) row flex containers. I _think_ the C and D
@@ -710,43 +624,33 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// MinMaxSizesFunc(MinMaxSizesType::kContent).sizes.max_size below, so
// they don't need to use
// ComputeIntrinsicInlineSizeForAspectRatioElement.
- // Also, ComputeIntrinsicInlineSizeForAspectRatioElement DCHECKs for
- // non-replaced items.
if (child.HasAspectRatio() && child.IsReplaced()) {
- if (RuntimeEnabledFeatures::FlexAspectRatioEnabled()) {
- // Legacy uses child.PreferredLogicalWidths() for this case, which
- // is not exactly correct.
- // ComputeIntrinsicInlineSizeForAspectRatioElement would honor the
- // definite block size parameter by multipying it by the aspect
- // ratio, but if control flow reaches here, we know we don't have a
- // definite inline size. If we did, we would have fallen into the
- // "part B" section above, not this "part C, D, E" section.
- flex_base_border_box =
- ComputeIntrinsicInlineSizeForAspectRatioElement(
- child, flex_basis_space, /* definite_block_size */
- base::nullopt, min_max_sizes_in_cross_axis_direction);
- } else {
- MinMaxSizesInput input(child_percentage_size_.block_size,
- MinMaxSizesType::kContent);
- flex_base_border_box =
- ComputeMinAndMaxContentContribution(Style(), child, input)
- .sizes.max_size;
- }
+ // Legacy uses child.PreferredLogicalWidths() for this case, which is
+ // not exactly correct.
+ // ComputeIntrinsicInlineSizeForAspectRatioElement would honor the
+ // definite block size parameter by multipying it by the aspect ratio,
+ // but if control flow reaches here, we know we don't have a definite
+ // inline size. If we did, we would have fallen into the "part B"
+ // section above, not this "part C, D, E" section.
+ flex_base_border_box =
+ ComputeIntrinsicInlineSizeForAspectRatioElement(
+ child, flex_basis_space, /* definite_block_size */
+ base::nullopt, min_max_sizes_in_cross_axis_direction);
} else {
flex_base_border_box =
MinMaxSizesFunc(MinMaxSizesType::kContent).sizes.max_size;
}
} else {
// Parts C, D, and E for what are usually column flex containers.
- if (child.HasAspectRatio() && child.IsReplaced() &&
- RuntimeEnabledFeatures::FlexAspectRatioEnabled()) {
+ if (child.HasAspectRatio() && child.IsReplaced()) {
// Legacy uses the post-layout size for this case, which isn't always
// correct.
- // ComputeIntrinsicBlockSizeForAspectRatioElement would honor the
- // definite inline size parameter by multipying it by the aspect
- // ratio, but if control flow reaches here, we know we don't have a
- // definite inline size. If we did, we would have fallen into the
- // "part B" section above, not this "part C, D, E" section.
+ // With regard to |base::nullopt| in the next line:
+ // ComputeIntrinsicBlockSizeForAspectRatioElement would honor a
+ // definite inline size by multipying it by the aspect ratio, but if
+ // control flow reaches here, we know we don't have a definite inline
+ // size. If we did, we would have fallen into the "part B" section
+ // above, not this "part C, D, E" section.
flex_base_border_box = ComputeIntrinsicBlockSizeForAspectRatioElement(
child, flex_basis_space, base::nullopt /* definite_inline_size */,
min_max_sizes_in_cross_axis_direction);
@@ -765,8 +669,7 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// flex basis is in child's block direction.
flex_base_border_box = ResolveMainBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- length_to_resolve, IntrinsicBlockSizeFunc,
- LengthResolvePhase::kLayout);
+ length_to_resolve, IntrinsicBlockSizeFunc);
}
}
@@ -780,20 +683,17 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
const Length& min = is_horizontal_flow_ ? child.Style().MinWidth()
: child.Style().MinHeight();
- if (algorithm_->ShouldApplyMinSizeAutoForChild(*child.GetLayoutBox())) {
+ if (algorithm_.ShouldApplyMinSizeAutoForChild(*child.GetLayoutBox())) {
LayoutUnit content_size_suggestion;
if (MainAxisIsInlineAxis(child)) {
- if (child.IsReplaced() && child.HasAspectRatio() &&
- RuntimeEnabledFeatures::FlexAspectRatioEnabled()) {
+ if (child.IsReplaced() && child.HasAspectRatio()) {
base::Optional<LayoutUnit> definite_block_size;
if (!BlockLengthUnresolvable(flex_basis_space,
- child_style.LogicalHeight(),
- LengthResolvePhase::kLayout)) {
+ child_style.LogicalHeight())) {
definite_block_size = ResolveMainBlockLength(
flex_basis_space, child_style,
border_padding_in_child_writing_mode,
- child_style.LogicalHeight(), IntrinsicBlockSizeFunc,
- LengthResolvePhase::kLayout);
+ child_style.LogicalHeight(), IntrinsicBlockSizeFunc);
}
content_size_suggestion =
@@ -807,8 +707,7 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
} else {
LayoutUnit intrinsic_block_size;
if (child.IsReplaced()) {
- if (child.HasAspectRatio() &&
- RuntimeEnabledFeatures::FlexAspectRatioEnabled()) {
+ if (child.HasAspectRatio()) {
base::Optional<LayoutUnit> definite_inline_size;
if (!child_style.LogicalWidth().IsAuto()) {
definite_inline_size = ResolveMainInlineLength(
@@ -821,6 +720,9 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
child, flex_basis_space, definite_inline_size,
min_max_sizes_in_cross_axis_direction);
} else {
+ // This code block is needed to make
+ // flex-aspect-ratio-img-column-017.html pass, but the test may be
+ // wrong. https://github.com/web-platform-tests/wpt/issues/27653
base::Optional<LayoutUnit> computed_inline_size;
base::Optional<LayoutUnit> computed_block_size;
child.IntrinsicSize(&computed_inline_size, &computed_block_size);
@@ -861,52 +763,17 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
specified_length_in_main_axis);
}
} else if (!BlockLengthUnresolvable(flex_basis_space,
- specified_length_in_main_axis,
- LengthResolvePhase::kLayout)) {
+ specified_length_in_main_axis)) {
specified_size_suggestion = ResolveMainBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- specified_length_in_main_axis, IntrinsicBlockSizeFunc,
- LengthResolvePhase::kLayout);
+ specified_length_in_main_axis, IntrinsicBlockSizeFunc);
DCHECK_NE(specified_size_suggestion, kIndefiniteSize);
}
LayoutUnit transferred_size_suggestion = LayoutUnit::Max();
if (specified_size_suggestion == LayoutUnit::Max() &&
- child.HasAspectRatio()) {
- LayoutUnit cross_axis_size(kIndefiniteSize);
- const Length& cross_axis_length =
- is_horizontal_flow_ ? child_style.Height() : child_style.Width();
- if (IsItemCrossAxisLengthDefinite(child, cross_axis_length)) {
- // This entire IsItemCrossAxisLengthDefinite block may be unnecessary
- // after enabling RuntimeEnabledFeatures::FlexAspectRatioEnabled().
- if (MainAxisIsInlineAxis(child)) {
- cross_axis_size = ResolveMainBlockLength(
- flex_basis_space, child_style,
- border_padding_in_child_writing_mode, cross_axis_length,
- kIndefiniteSize, LengthResolvePhase::kLayout);
- DCHECK_NE(cross_axis_size, kIndefiniteSize);
- } else {
- cross_axis_size =
- ResolveMainInlineLength(flex_basis_space, child_style,
- border_padding_in_child_writing_mode,
- MinMaxSizesFunc, cross_axis_length);
- }
- } else if (WillChildCrossSizeBeContainerCrossSize(child) &&
- RuntimeEnabledFeatures::FlexAspectRatioEnabled()) {
- NGBoxStrut margins = physical_child_margins.ConvertToLogical(
- ConstraintSpace().GetWritingDirection());
- cross_axis_size = CalculateFixedCrossSize(
- min_max_sizes_in_cross_axis_direction, margins);
- }
- if (cross_axis_size != kIndefiniteSize) {
- double ratio = GetMainOverCrossAspectRatio(child);
- transferred_size_suggestion = LayoutUnit(
- main_axis_border_padding +
- ratio *
- (min_max_sizes_in_cross_axis_direction.ClampSizeToMinAndMax(
- cross_axis_size) -
- cross_axis_border_padding));
- }
+ AspectRatioProvidesMainSize(child, cross_axis_length)) {
+ transferred_size_suggestion = ComputeTransferredMainSize();
}
DCHECK(specified_size_suggestion == LayoutUnit::Max() ||
@@ -919,11 +786,11 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
} else if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.min_size = ResolveMinInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
- MinMaxSizesFunc, min, LengthResolvePhase::kLayout);
+ MinMaxSizesFunc, min);
} else {
- min_max_sizes_in_main_axis_direction.min_size = ResolveMinBlockLength(
- flex_basis_space, child_style, border_padding_in_child_writing_mode,
- min, LengthResolvePhase::kLayout);
+ min_max_sizes_in_main_axis_direction.min_size =
+ ResolveMinBlockLength(flex_basis_space, child_style,
+ border_padding_in_child_writing_mode, min);
}
// Flex needs to never give a table a flexed main size that is less than its
// min-content size, so floor min-width by min-content size.
@@ -962,12 +829,12 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
NGBoxStrut scrollbars = ComputeScrollbarsForNonAnonymous(child);
algorithm_
- ->emplace_back(nullptr, child.Style(), flex_base_content_size,
- min_max_sizes_in_main_axis_direction,
- min_max_sizes_in_cross_axis_direction,
- main_axis_border_padding, cross_axis_border_padding,
- physical_child_margins, scrollbars,
- min_max_sizes.has_value())
+ .emplace_back(nullptr, child.Style(), flex_base_content_size,
+ min_max_sizes_in_main_axis_direction,
+ min_max_sizes_in_cross_axis_direction,
+ main_axis_border_padding, cross_axis_border_padding,
+ physical_child_margins, scrollbars,
+ min_max_sizes.has_value())
.ng_input_node_ = child;
}
}
@@ -1065,8 +932,8 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
main_axis_end_offset = BorderScrollbarPadding().inline_end;
}
FlexLine* line;
- while (
- (line = algorithm_->ComputeNextFlexLine(border_box_size_.inline_size))) {
+ while ((
+ line = algorithm_.ComputeNextFlexLine(container_builder_.InlineSize()))) {
line->SetContainerMainInnerSize(
MainAxisContentExtent(line->sum_hypothetical_main_size_));
line->FreezeInflexibleItems();
@@ -1085,11 +952,8 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
space_builder.SetIsPaintedAtomically(true);
LogicalSize available_size;
- NGBoxStrut margins = flex_item.physical_margins_.ConvertToLogical(
- ConstraintSpace().GetWritingDirection());
LayoutUnit fixed_aspect_ratio_cross_size = kIndefiniteSize;
- if (RuntimeEnabledFeatures::FlexAspectRatioEnabled() &&
- flex_item.ng_input_node_.HasAspectRatio() &&
+ if (flex_item.ng_input_node_.HasAspectRatio() &&
flex_item.ng_input_node_.IsReplaced()) {
// This code derives the cross axis size from the flexed main size and
// the aspect ratio. We can delete this code when
@@ -1104,8 +968,7 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
// the |WillChildCrossSizeBeContainerCrossSize| calls below.
if (cross_axis_length.IsAuto() ||
(MainAxisIsInlineAxis(flex_item.ng_input_node_) &&
- BlockLengthUnresolvable(flex_basis_space, cross_axis_length,
- LengthResolvePhase::kLayout))) {
+ BlockLengthUnresolvable(flex_basis_space, cross_axis_length))) {
fixed_aspect_ratio_cross_size =
flex_item.min_max_cross_sizes_->ClampSizeToMinAndMax(
flex_item.cross_axis_border_padding_ +
@@ -1120,9 +983,7 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
flex_item.main_axis_border_padding_;
space_builder.SetIsFixedBlockSize(true);
if (WillChildCrossSizeBeContainerCrossSize(flex_item.ng_input_node_)) {
- space_builder.SetIsFixedInlineSize(true);
- available_size.inline_size = CalculateFixedCrossSize(
- flex_item.min_max_cross_sizes_.value(), margins);
+ space_builder.SetStretchInlineSizeIfAuto(true);
} else if (fixed_aspect_ratio_cross_size != kIndefiniteSize) {
space_builder.SetIsFixedInlineSize(true);
available_size.inline_size = fixed_aspect_ratio_cross_size;
@@ -1141,9 +1002,7 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
available_size.block_size = ChildAvailableSize().block_size;
space_builder.SetIsFixedInlineSize(true);
if (WillChildCrossSizeBeContainerCrossSize(flex_item.ng_input_node_)) {
- space_builder.SetIsFixedBlockSize(true);
- available_size.block_size = CalculateFixedCrossSize(
- flex_item.min_max_cross_sizes_.value(), margins);
+ space_builder.SetStretchBlockSizeIfAuto(true);
} else if (fixed_aspect_ratio_cross_size != kIndefiniteSize) {
space_builder.SetIsFixedBlockSize(true);
available_size.block_size = fixed_aspect_ratio_cross_size;
@@ -1160,22 +1019,10 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
}
}
- space_builder.SetNeedsBaseline(
- ConstraintSpace().NeedsBaseline() ||
- FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
- ItemPosition::kBaseline);
-
space_builder.SetAvailableSize(available_size);
space_builder.SetPercentageResolutionSize(child_percentage_size_);
space_builder.SetReplacedPercentageResolutionSize(child_percentage_size_);
- // https://drafts.csswg.org/css-flexbox/#algo-cross-item
- // Determine the hypothetical cross size of each item by performing layout
- // with the used main size and the available space, treating auto as
- // fit-content.
- if (ShouldItemShrinkToFit(flex_item.ng_input_node_))
- space_builder.SetIsShrinkToFit(true);
-
// For a button child, we need the baseline type same as the container's
// baseline type for UseCounter. For example, if the container's display
// property is 'inline-block', we need the last-line baseline of the
@@ -1205,10 +1052,10 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
LayoutUnit intrinsic_block_size = BorderScrollbarPadding().BlockSum();
- if (algorithm_->FlexLines().IsEmpty() && Node().HasLineIfEmpty()) {
+ if (algorithm_.FlexLines().IsEmpty() && Node().HasLineIfEmpty()) {
intrinsic_block_size += Node().GetLayoutBox()->LogicalHeightForEmptyLine();
} else {
- intrinsic_block_size += algorithm_->IntrinsicContentBlockSize();
+ intrinsic_block_size += algorithm_.IntrinsicContentBlockSize();
}
intrinsic_block_size =
@@ -1216,7 +1063,7 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::LayoutInternal() {
BorderScrollbarPadding(), intrinsic_block_size);
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
- border_box_size_.inline_size);
+ container_builder_.InlineSize(), Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -1252,11 +1099,6 @@ void NGFlexLayoutAlgorithm::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
}
}
- space_builder.SetNeedsBaseline(
- ConstraintSpace().NeedsBaseline() ||
- FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
- ItemPosition::kBaseline);
-
space_builder.SetAvailableSize(available_size);
space_builder.SetPercentageResolutionSize(child_percentage_size_);
space_builder.SetReplacedPercentageResolutionSize(child_percentage_size_);
@@ -1268,7 +1110,7 @@ void NGFlexLayoutAlgorithm::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
}
bool NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
- Vector<FlexLine>& line_contexts = algorithm_->FlexLines();
+ Vector<FlexLine>& line_contexts = algorithm_.FlexLines();
const LayoutUnit cross_axis_start_edge =
line_contexts.IsEmpty() ? LayoutUnit()
: line_contexts[0].cross_axis_offset_;
@@ -1280,24 +1122,24 @@ bool NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
if (is_column_)
std::swap(final_content_main_size, final_content_cross_size);
- if (!algorithm_->IsMultiline() && !line_contexts.IsEmpty())
+ if (!algorithm_.IsMultiline() && !line_contexts.IsEmpty())
line_contexts[0].cross_axis_extent_ = final_content_cross_size;
- algorithm_->AlignFlexLines(final_content_cross_size);
+ algorithm_.AlignFlexLines(final_content_cross_size);
- algorithm_->AlignChildren();
+ algorithm_.AlignChildren();
if (Style().FlexWrap() == EFlexWrap::kWrapReverse) {
// flex-wrap: wrap-reverse reverses the order of the lines in the container;
// FlipForWrapReverse recalculates each item's cross axis position. We have
// to do that after AlignChildren sets an initial cross axis position.
- algorithm_->FlipForWrapReverse(cross_axis_start_edge,
- final_content_cross_size);
+ algorithm_.FlipForWrapReverse(cross_axis_start_edge,
+ final_content_cross_size);
}
if (Style().ResolvedIsColumnReverseFlexDirection()) {
- algorithm_->LayoutColumnReverse(final_content_main_size,
- BorderScrollbarPadding().block_start);
+ algorithm_.LayoutColumnReverse(final_content_main_size,
+ BorderScrollbarPadding().block_start);
}
base::Optional<LayoutUnit> fallback_baseline;
@@ -1496,7 +1338,7 @@ MinMaxSizesResult NGFlexLayoutAlgorithm::ComputeMinMaxSizes(
sizes.max_size = std::max(sizes.max_size, child_result.sizes.max_size);
} else {
sizes.max_size += child_result.sizes.max_size;
- if (algorithm_->IsMultiline()) {
+ if (algorithm_.IsMultiline()) {
sizes.min_size = std::max(sizes.min_size, child_result.sizes.min_size);
} else {
sizes.min_size += child_result.sizes.min_size;
@@ -1505,9 +1347,9 @@ MinMaxSizesResult NGFlexLayoutAlgorithm::ComputeMinMaxSizes(
}
if (!is_column_) {
LayoutUnit gap_inline_size =
- (number_of_items - 1) * algorithm_->gap_between_items_;
+ (number_of_items - 1) * algorithm_.gap_between_items_;
sizes.max_size += gap_inline_size;
- if (!algorithm_->IsMultiline()) {
+ if (!algorithm_.IsMultiline()) {
sizes.min_size += gap_inline_size;
}
}
@@ -1517,7 +1359,7 @@ MinMaxSizesResult NGFlexLayoutAlgorithm::ComputeMinMaxSizes(
// intrinsic width. Make sure that we never return a negative width.
sizes.Encompass(LayoutUnit());
sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
index b572d9da8de..e2fcc8719c0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
@@ -35,7 +35,8 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
bool IsItemMainSizeDefinite(const NGBlockNode& child) const;
bool IsItemCrossAxisLengthDefinite(const NGBlockNode& child,
const Length& length) const;
- bool ShouldItemShrinkToFit(const NGBlockNode& child) const;
+ bool AspectRatioProvidesMainSize(const NGBlockNode& child,
+ const Length& cross_axis_length) const;
double GetMainOverCrossAspectRatio(const NGBlockNode& child) const;
bool DoesItemStretch(const NGBlockNode& child) const;
// This implements the first of the additional scenarios where a flex item
@@ -53,14 +54,9 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
bool IsColumnContainerMainSizeDefinite() const;
bool IsContainerCrossSizeDefinite() const;
- LayoutUnit CalculateFixedCrossSize(const MinMaxSizes& cross_axis_min_max,
- const NGBoxStrut& margins) const;
-
NGConstraintSpace BuildSpaceForFlexBasis(const NGBlockNode& flex_item) const;
NGConstraintSpace BuildSpaceForIntrinsicBlockSize(
- const NGBlockNode& flex_item,
- const NGPhysicalBoxStrut& physical_margins,
- const MinMaxSizes& cross_axis) const;
+ const NGBlockNode& flex_item) const;
void ConstructAndAppendFlexItems();
void ApplyStretchAlignmentToChild(FlexItem& flex_item);
bool GiveLinesAndItemsFinalPositionAndSize();
@@ -85,10 +81,10 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
const bool is_column_;
const bool is_horizontal_flow_;
const bool is_cross_size_definite_;
+ const LogicalSize child_percentage_size_;
+
bool ignore_child_scrollbar_changes_ = false;
- LogicalSize border_box_size_;
- LogicalSize child_percentage_size_;
- base::Optional<FlexLayoutAlgorithm> algorithm_;
+ FlexLayoutAlgorithm algorithm_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index 17c33c2c46c..737cac9c685 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -6,122 +6,240 @@
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
-#include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
namespace blink {
NGGridLayoutAlgorithm::NGGridLayoutAlgorithm(
const NGLayoutAlgorithmParams& params)
- : NGLayoutAlgorithm(params),
- state_(GridLayoutAlgorithmState::kMeasuringItems) {
+ : NGLayoutAlgorithm(params) {
DCHECK(params.space.IsNewFormattingContext());
DCHECK(!params.break_token);
border_box_size_ = container_builder_.InitialBorderBoxSize();
- child_percentage_size_ = CalculateChildPercentageSize(
- ConstraintSpace(), Node(), ChildAvailableSize());
+
+ // At various stages of this algorithm we need to know if the grid
+ // available-size. If it is initially indefinite, we need to know the min/max
+ // sizes as well. Initialize all these to the same value.
+ grid_available_size_ = grid_min_available_size_ = grid_max_available_size_ =
+ ChildAvailableSize();
+
+ // Next if our inline-size is indefinite, compute the min/max inline-sizes.
+ if (grid_available_size_.inline_size == kIndefiniteSize) {
+ const LayoutUnit border_scrollbar_padding =
+ BorderScrollbarPadding().InlineSum();
+ const MinMaxSizes sizes = ComputeMinMaxInlineSizes(
+ ConstraintSpace(), Style(), container_builder_.BorderPadding(),
+ [&border_scrollbar_padding](MinMaxSizesType) -> MinMaxSizesResult {
+ // If we've reached here we are inside the ComputeMinMaxSizes pass,
+ // and also have something like "min-width: min-content". This is
+ // cyclic. Just return the border/scrollbar/padding as our
+ // "intrinsic" size.
+ return MinMaxSizesResult(
+ {border_scrollbar_padding, border_scrollbar_padding},
+ /* depends_on_percentage_block_size */ false);
+ });
+
+ grid_min_available_size_.inline_size =
+ (sizes.min_size - border_scrollbar_padding).ClampNegativeToZero();
+ grid_max_available_size_.inline_size =
+ (sizes.max_size == LayoutUnit::Max())
+ ? sizes.max_size
+ : (sizes.max_size - border_scrollbar_padding).ClampNegativeToZero();
+ }
+
+ // And similar for the min/max block-sizes.
+ if (grid_available_size_.block_size == kIndefiniteSize) {
+ const LayoutUnit border_scrollbar_padding =
+ BorderScrollbarPadding().BlockSum();
+ const MinMaxSizes sizes = ComputeMinMaxBlockSizes(
+ ConstraintSpace(), Style(), container_builder_.BorderPadding(),
+ kIndefiniteSize);
+
+ grid_min_available_size_.block_size =
+ (sizes.min_size - border_scrollbar_padding).ClampNegativeToZero();
+ grid_max_available_size_.block_size =
+ (sizes.max_size == LayoutUnit::Max())
+ ? sizes.max_size
+ : (sizes.max_size - border_scrollbar_padding).ClampNegativeToZero();
+ }
}
scoped_refptr<const NGLayoutResult> NGGridLayoutAlgorithm::Layout() {
- // Proceed by algorithm state, as some scenarios will involve a non-linear
- // path through these steps (e.g. skipping or redoing some of them).
- while (state_ != GridLayoutAlgorithmState::kCompletedLayout) {
- switch (state_) {
- case GridLayoutAlgorithmState::kMeasuringItems: {
- SetSpecifiedTracks();
- DetermineExplicitTrackStarts();
- ConstructAndAppendGridItems();
-
- // TODO(janewman): Split placement into its own GridLayoutAlgorithmState
- NGGridPlacement(
- automatic_row_repetitions_, automatic_column_repetitions_,
- explicit_row_start_, explicit_column_start_,
- Style().IsGridAutoFlowAlgorithmSparse()
- ? NGGridPlacement::PackingBehavior::kSparse
- : NGGridPlacement::PackingBehavior::kDense,
- AutoFlowDirection(), Style(),
- AutoFlowDirection() == kForRows ? column_count_ : row_count_,
- block_row_track_collection_, block_column_track_collection_,
- grid_items_)
- .RunAutoPlacementAlgorithm();
-
- block_column_track_collection_.FinalizeRanges();
- block_row_track_collection_.FinalizeRanges();
-
- DCHECK_NE(child_percentage_size_.inline_size, kIndefiniteSize);
- algorithm_column_track_collection_ =
- NGGridLayoutAlgorithmTrackCollection(
- block_column_track_collection_,
- /* is_content_box_size_indefinite */ false);
-
- bool is_content_box_block_size_indefinite =
- child_percentage_size_.block_size == kIndefiniteSize;
- algorithm_row_track_collection_ = NGGridLayoutAlgorithmTrackCollection(
- block_row_track_collection_, is_content_box_block_size_indefinite);
-
- CacheItemSetIndices();
- state_ = GridLayoutAlgorithmState::kResolvingInlineSize;
- break;
- }
+ // Measure items.
+ GridItems grid_items;
+ Vector<GridItemData> out_of_flow_items;
+ ConstructAndAppendGridItems(&grid_items, &out_of_flow_items);
+
+ NGGridLayoutAlgorithmTrackCollection column_track_collection;
+ NGGridLayoutAlgorithmTrackCollection row_track_collection;
+ NGGridPlacement grid_placement(Style(),
+ ComputeAutomaticRepetitions(kForColumns),
+ ComputeAutomaticRepetitions(kForRows));
+
+ BuildAlgorithmTrackCollections(&grid_items, &column_track_collection,
+ &row_track_collection, &grid_placement);
+
+ // Cache track span properties for grid items.
+ CacheGridItemsTrackSpanProperties(column_track_collection, &grid_items);
+ CacheGridItemsTrackSpanProperties(row_track_collection, &grid_items);
+
+ // We perform the track sizing algorithm using two methods. First
+ // |InitializeTrackSizes|, which we need to get an initial column and row set
+ // geometry. Then |ComputeUsedTrackSizes|, to finalize the sizing algorithm
+ // for both dimensions.
+ GridGeometry grid_geometry = {InitializeTrackSizes(&column_track_collection),
+ InitializeTrackSizes(&row_track_collection)};
+
+ // Cache set indices for grid items.
+ for (auto& grid_item : grid_items.item_data) {
+ grid_item.SetIndices(column_track_collection);
+ grid_item.SetIndices(row_track_collection);
+ }
- case GridLayoutAlgorithmState::kResolvingInlineSize:
- ComputeUsedTrackSizes(GridTrackSizingDirection::kForColumns);
- state_ = GridLayoutAlgorithmState::kResolvingBlockSize;
- break;
+ // Resolve inline size.
+ ComputeUsedTrackSizes(SizingConstraint::kLayout, grid_geometry,
+ &column_track_collection, &grid_items);
+
+ // Determine the final (used) column set geometry.
+ grid_geometry.column_geometry = ComputeSetGeometry(
+ column_track_collection, grid_available_size_.inline_size);
+
+ // Resolve block size.
+ ComputeUsedTrackSizes(SizingConstraint::kLayout, grid_geometry,
+ &row_track_collection, &grid_items);
+
+ // Determine the final (used) row set geometry.
+ grid_geometry.row_geometry =
+ ComputeSetGeometry(row_track_collection, grid_available_size_.block_size);
+
+ // Intrinsic block size is based on the final row offset. Because gutters are
+ // included in row offsets, subtract out the final gutter (if there is one).
+ LayoutUnit final_gutter = (grid_geometry.row_geometry.sets.size() == 1)
+ ? LayoutUnit()
+ : grid_geometry.row_geometry.gutter_size;
+ LayoutUnit intrinsic_block_size =
+ grid_geometry.row_geometry.sets.back().offset - final_gutter +
+ BorderScrollbarPadding().block_end;
- case GridLayoutAlgorithmState::kResolvingBlockSize:
- ComputeUsedTrackSizes(GridTrackSizingDirection::kForRows);
- state_ = GridLayoutAlgorithmState::kPlacingGridItems;
- break;
+ intrinsic_block_size =
+ ClampIntrinsicBlockSize(ConstraintSpace(), Node(),
+ BorderScrollbarPadding(), intrinsic_block_size);
+
+ LayoutUnit block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
+ border_box_size_.inline_size, Node().ShouldBeConsideredAsReplaced());
+
+ // If we had an indefinite available block-size, we now need to re-calculate
+ // our grid-gap, and alignment using our new block-size.
+ if (grid_available_size_.block_size == kIndefiniteSize) {
+ const LayoutUnit resolved_available_block_size =
+ (block_size - BorderScrollbarPadding().BlockSum())
+ .ClampNegativeToZero();
+
+ grid_geometry.row_geometry =
+ ComputeSetGeometry(row_track_collection, resolved_available_block_size);
+ }
- case GridLayoutAlgorithmState::kPlacingGridItems:
- PlaceGridItems();
- state_ = GridLayoutAlgorithmState::kCompletedLayout;
- break;
+ PlaceGridItems(grid_items, grid_geometry, block_size);
- case GridLayoutAlgorithmState::kCompletedLayout:
- NOTREACHED();
- break;
- }
+ PlaceOutOfFlowDescendants(column_track_collection, row_track_collection,
+ grid_geometry, grid_placement, block_size);
+
+ for (auto& out_of_flow_item : out_of_flow_items) {
+ out_of_flow_item.SetIndices(column_track_collection, &grid_placement);
+ out_of_flow_item.SetIndices(row_track_collection, &grid_placement);
}
- intrinsic_block_size_ =
- ClampIntrinsicBlockSize(ConstraintSpace(), Node(),
- BorderScrollbarPadding(), intrinsic_block_size_);
- container_builder_.SetIntrinsicBlockSize(intrinsic_block_size_);
+ PlaceOutOfFlowItems(out_of_flow_items, grid_geometry, block_size);
- LayoutUnit block_size = ComputeBlockSizeForFragment(
- ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size_,
- border_box_size_.inline_size);
+ container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
return container_builder_.ToBoxFragment();
}
-MinMaxSizesResult NGGridLayoutAlgorithm::ComputeMinMaxSizes(
- const MinMaxSizesInput& input) const {
- return {MinMaxSizes(), /* depends_on_percentage_block_size */ true};
-}
+namespace {
-const NGGridLayoutAlgorithmTrackCollection&
-NGGridLayoutAlgorithm::ColumnTrackCollection() const {
- return algorithm_column_track_collection_;
+LayoutUnit ComputeTotalTrackSize(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const LayoutUnit grid_gap) {
+ LayoutUnit total_track_size;
+ for (auto set_iterator = track_collection.GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ const auto& set = set_iterator.CurrentSet();
+ total_track_size += set.BaseSize() + set.TrackCount() * grid_gap;
+ }
+ // Clamp to zero to avoid a negative |grid_gap| when there are no tracks.
+ total_track_size -= grid_gap;
+ return total_track_size.ClampNegativeToZero();
}
-const NGGridLayoutAlgorithmTrackCollection&
-NGGridLayoutAlgorithm::RowTrackCollection() const {
- return algorithm_row_track_collection_;
-}
+} // namespace
-NGGridLayoutAlgorithm::GridItemData::GridItemData(const NGBlockNode node)
- : node(node) {}
+MinMaxSizesResult NGGridLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ // TODO(janewman): Handle the cases typically done via:
+ // CalculateMinMaxSizesIgnoringChildren.
+
+ // Measure items.
+ GridItems grid_items;
+ ConstructAndAppendGridItems(&grid_items);
+
+ NGGridLayoutAlgorithmTrackCollection column_track_collection_for_min_size;
+ NGGridLayoutAlgorithmTrackCollection row_track_collection;
+ NGGridPlacement grid_placement(Style(),
+ ComputeAutomaticRepetitions(kForColumns),
+ ComputeAutomaticRepetitions(kForRows));
+
+ BuildAlgorithmTrackCollections(&grid_items,
+ &column_track_collection_for_min_size,
+ &row_track_collection, &grid_placement);
+
+ // Cache track span properties for grid items.
+ CacheGridItemsTrackSpanProperties(column_track_collection_for_min_size,
+ &grid_items);
+
+ // Cache set indices for grid items.
+ for (auto& grid_item : grid_items) {
+ grid_item.SetIndices(column_track_collection_for_min_size);
+ grid_item.SetIndices(row_track_collection);
+ }
-AutoPlacementType NGGridLayoutAlgorithm::GridItemData::AutoPlacement(
+ GridGeometry grid_geometry = {
+ InitializeTrackSizes(&column_track_collection_for_min_size),
+ InitializeTrackSizes(&row_track_collection)};
+
+ // Before the track sizing algorithm, create a copy of the column collection;
+ // one will be used to compute the min size and the other for the max size.
+ NGGridLayoutAlgorithmTrackCollection column_track_collection_for_max_size =
+ column_track_collection_for_min_size;
+
+ // Resolve inline size under a 'min-content' constraint.
+ ComputeUsedTrackSizes(SizingConstraint::kMinContent, grid_geometry,
+ &column_track_collection_for_min_size, &grid_items);
+ // Resolve inline size under a 'max-content' constraint.
+ ComputeUsedTrackSizes(SizingConstraint::kMaxContent, grid_geometry,
+ &column_track_collection_for_max_size, &grid_items);
+
+ const LayoutUnit grid_gap = GridGap(kForColumns);
+ MinMaxSizes sizes{
+ ComputeTotalTrackSize(column_track_collection_for_min_size, grid_gap),
+ ComputeTotalTrackSize(column_track_collection_for_max_size, grid_gap)};
+
+ // TODO(janewman): Confirm that |input.percentage_resolution_block_size|
+ // isn't used within grid layout.
+ sizes += BorderScrollbarPadding().InlineSum();
+ return MinMaxSizesResult(sizes, /* depends_on_percentage_block_size */ false);
+}
+
+NGGridLayoutAlgorithm::AutoPlacementType
+NGGridLayoutAlgorithm::GridItemData::AutoPlacement(
GridTrackSizingDirection flow_direction) const {
bool is_major_indefinite = Span(flow_direction).IsIndefinite();
bool is_minor_indefinite =
@@ -138,12 +256,26 @@ AutoPlacementType NGGridLayoutAlgorithm::GridItemData::AutoPlacement(
return AutoPlacementType::kNotNeeded;
}
+const GridSpan& NGGridLayoutAlgorithm::GridItemData::Span(
+ GridTrackSizingDirection track_direction) const {
+ return (track_direction == kForColumns) ? resolved_position.columns
+ : resolved_position.rows;
+}
+
+void NGGridLayoutAlgorithm::GridItemData::SetSpan(
+ const GridSpan& span,
+ GridTrackSizingDirection track_direction) {
+ if (track_direction == kForColumns)
+ resolved_position.columns = span;
+ else
+ resolved_position.rows = span;
+}
+
wtf_size_t NGGridLayoutAlgorithm::GridItemData::StartLine(
GridTrackSizingDirection track_direction) const {
const GridSpan& span = (track_direction == kForColumns)
? resolved_position.columns
: resolved_position.rows;
- DCHECK(span.IsTranslatedDefinite());
return span.StartLine();
}
@@ -152,7 +284,6 @@ wtf_size_t NGGridLayoutAlgorithm::GridItemData::EndLine(
const GridSpan& span = (track_direction == kForColumns)
? resolved_position.columns
: resolved_position.rows;
- DCHECK(span.IsTranslatedDefinite());
return span.EndLine();
}
@@ -161,139 +292,438 @@ wtf_size_t NGGridLayoutAlgorithm::GridItemData::SpanSize(
const GridSpan& span = (track_direction == kForColumns)
? resolved_position.columns
: resolved_position.rows;
- DCHECK(span.IsTranslatedDefinite());
return span.IntegerSpan();
}
-const GridSpan& NGGridLayoutAlgorithm::GridItemData::Span(
+const TrackSpanProperties&
+NGGridLayoutAlgorithm::GridItemData::GetTrackSpanProperties(
GridTrackSizingDirection track_direction) const {
- return (track_direction == kForColumns) ? resolved_position.columns
- : resolved_position.rows;
+ return track_direction == kForColumns ? column_span_properties
+ : row_span_properties;
}
-void NGGridLayoutAlgorithm::GridItemData::SetSpan(
- const GridSpan& span,
+void NGGridLayoutAlgorithm::GridItemData::SetTrackSpanProperty(
+ TrackSpanProperties::PropertyId property,
GridTrackSizingDirection track_direction) {
- switch (track_direction) {
- case kForColumns:
- resolved_position.columns = span;
- break;
- case kForRows:
- resolved_position.rows = span;
- break;
- }
+ if (track_direction == kForColumns)
+ column_span_properties.SetProperty(property);
+ else
+ row_span_properties.SetProperty(property);
}
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::Iterator(
- Vector<wtf_size_t>::const_iterator current_index,
- Vector<GridItemData>* grid_items)
- : current_index_(current_index), grid_items_(grid_items) {}
-
-bool NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator!=(
- const Iterator& other) const {
- return grid_items_ != other.grid_items_ ||
- current_index_ != other.current_index_;
+bool NGGridLayoutAlgorithm::GridItemData::IsSpanningFlexibleTrack(
+ GridTrackSizingDirection track_direction) const {
+ return GetTrackSpanProperties(track_direction)
+ .HasProperty(TrackSpanProperties::kHasFlexibleTrack);
}
-NGGridLayoutAlgorithm::GridItemData*
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator->() {
- DCHECK_LT(*current_index_, grid_items_->size());
- return &(grid_items_->at(*current_index_));
+bool NGGridLayoutAlgorithm::GridItemData::IsSpanningIntrinsicTrack(
+ GridTrackSizingDirection track_direction) const {
+ return GetTrackSpanProperties(track_direction)
+ .HasProperty(TrackSpanProperties::kHasIntrinsicTrack);
}
-NGGridLayoutAlgorithm::GridItemData&
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator*() {
- DCHECK_LT(*current_index_, grid_items_->size());
- return grid_items_->at(*current_index_);
-}
+NGGridLayoutAlgorithm::ItemSetIndices
+NGGridLayoutAlgorithm::GridItemData::SetIndices(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const NGGridPlacement* grid_placement) {
+ const GridTrackSizingDirection track_direction = track_collection.Direction();
+
+ // If the set indices are already computed, we can just return them.
+ base::Optional<ItemSetIndices>& cached_set_indices =
+ (track_direction == kForColumns) ? column_set_indices : row_set_indices;
+ if (cached_set_indices.has_value())
+ return cached_set_indices.value();
+
+ // We only calculate the indexes if:
+ // 1. The item is in flow (it is a grid item) or
+ // 2. The item is out of flow, but the line was not defined as 'auto' and
+ // the line is within the bounds of the grid, since an out of flow item
+ // cannot create grid lines.
+ wtf_size_t start_line, end_line;
+ if (item_type == ItemType::kInGridFlow) {
+ start_line = StartLine(track_direction);
+ end_line = EndLine(track_direction);
+
+ DCHECK_NE(start_line, kNotFound);
+ DCHECK_NE(end_line, kNotFound);
+ } else {
+ DCHECK(grid_placement);
+ grid_placement->ResolveOutOfFlowItemGridLines(
+ track_collection, node.Style(), &start_line, &end_line);
+ }
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator&
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator++() {
- ++current_index_;
- return *this;
-}
+ // TODO(ansollano): An out of flow item can have an index that is in the
+ // middle of a range. Correctly handle this case.
+ ItemSetIndices set_indices;
+ if (start_line != kNotFound) {
+ DCHECK(track_collection.IsGridLineWithinImplicitGrid(start_line));
+ // If a start line of an out of flow item is the last line of the grid, then
+ // the |set_indices.begin| is the number of sets in the collection.
+ if (track_collection.EndLineOfImplicitGrid() == start_line) {
+ DCHECK_EQ(item_type, ItemType::kOutOfFlow);
+ set_indices.begin = track_collection.SetCount();
+ } else {
+ wtf_size_t first_spanned_range =
+ track_collection.RangeIndexFromTrackNumber(start_line);
+ set_indices.begin =
+ track_collection.RangeStartingSetIndex(first_spanned_range);
+ }
+ }
-NGGridLayoutAlgorithm::ReorderedGridItems::ReorderedGridItems(
- const Vector<wtf_size_t>& reordered_item_indices,
- Vector<GridItemData>& grid_items)
- : reordered_item_indices_(reordered_item_indices),
- grid_items_(grid_items) {}
+ if (end_line != kNotFound) {
+ DCHECK(track_collection.IsGridLineWithinImplicitGrid(end_line));
+ // If an end line of an out of flow item is the first line of the grid, then
+ // the |set_indices.end| is 0.
+ if (!end_line) {
+ DCHECK_EQ(item_type, ItemType::kOutOfFlow);
+ set_indices.end = 0;
+ } else {
+ wtf_size_t last_spanned_range =
+ track_collection.RangeIndexFromTrackNumber(end_line - 1);
+ set_indices.end =
+ track_collection.RangeStartingSetIndex(last_spanned_range) +
+ track_collection.RangeSetCount(last_spanned_range);
+ }
+ }
+
+#if DCHECK_IS_ON()
+ if (set_indices.begin != kNotFound && set_indices.end != kNotFound) {
+ DCHECK_LE(set_indices.end, track_collection.SetCount());
+ DCHECK_LT(set_indices.begin, set_indices.end);
+ } else if (set_indices.begin != kNotFound) {
+ DCHECK_LE(set_indices.begin, track_collection.SetCount());
+ } else if (set_indices.end != kNotFound) {
+ DCHECK_LE(set_indices.end, track_collection.SetCount());
+ }
+#endif
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator
-NGGridLayoutAlgorithm::ReorderedGridItems::begin() {
- return Iterator(reordered_item_indices_.begin(), &grid_items_);
+ cached_set_indices = set_indices;
+ return set_indices;
}
-NGGridLayoutAlgorithm::ReorderedGridItems::Iterator
-NGGridLayoutAlgorithm::ReorderedGridItems::end() {
- return Iterator(reordered_item_indices_.end(), &grid_items_);
+NGGridLayoutAlgorithm::GridItems::Iterator
+NGGridLayoutAlgorithm::GridItems::begin() {
+ return Iterator(&item_data, reordered_item_indices.begin());
}
-NGGridLayoutAlgorithm::ReorderedGridItems
-NGGridLayoutAlgorithm::GetReorderedGridItems() {
- return ReorderedGridItems(reordered_item_indices_, grid_items_);
+NGGridLayoutAlgorithm::GridItems::Iterator
+NGGridLayoutAlgorithm::GridItems::end() {
+ return Iterator(&item_data, reordered_item_indices.end());
}
-NGGridLayoutAlgorithmTrackCollection& NGGridLayoutAlgorithm::TrackCollection(
- GridTrackSizingDirection track_direction) {
- return (track_direction == kForColumns) ? algorithm_column_track_collection_
- : algorithm_row_track_collection_;
+void NGGridLayoutAlgorithm::GridItems::Append(
+ const GridItemData& new_item_data) {
+ reordered_item_indices.push_back(item_data.size());
+ item_data.emplace_back(new_item_data);
}
-NGGridLayoutAlgorithmTrackCollection::SetIterator
-NGGridLayoutAlgorithm::GetSetIteratorForItem(
- const GridItemData& item,
- GridTrackSizingDirection track_direction) {
- auto& track_collection = TrackCollection(track_direction);
- return track_collection.GetSetIterator(
- (track_direction == kForColumns) ? item.columns_begin_set_index
- : item.rows_begin_set_index,
- (track_direction == kForColumns) ? item.columns_end_set_index
- : item.rows_end_set_index);
+bool NGGridLayoutAlgorithm::GridItems::IsEmpty() const {
+ return item_data.IsEmpty();
}
+namespace {
+
+// TODO(ethavar): Consider doing this in-place, as it's not used more than once.
+// Returns an iterator for every |NGGridSet| contained within an item's span in
+// the relevant track collection.
+NGGridLayoutAlgorithmTrackCollection::SetIterator GetSetIteratorForItem(
+ NGGridLayoutAlgorithm::GridItemData& item,
+ NGGridLayoutAlgorithmTrackCollection& track_collection) {
+ NGGridLayoutAlgorithm::ItemSetIndices set_indices =
+ item.SetIndices(track_collection);
+ return track_collection.GetSetIterator(set_indices.begin, set_indices.end);
+}
+
+} // namespace
+
// TODO(ethavar): Current implementation of this method simply returns the
// preferred size of the grid item in the relevant direction. We should follow
-// the definitions from https://drafts.csswg.org/css-grid-1/#algo-spanning-items
+// the definitions from https://drafts.csswg.org/css-grid-2/#algo-spanning-items
// (i.e. compute minimum, min-content, and max-content contributions).
LayoutUnit NGGridLayoutAlgorithm::ContributionSizeForGridItem(
+ const GridGeometry& grid_geometry,
const GridItemData& grid_item,
GridTrackSizingDirection track_direction,
- NGGridItemContributionType contribution_type) const {
- const ComputedStyle& grid_item_style = grid_item.node.Style();
- GridTrackSizingDirection grid_item_track_direction = track_direction;
-
- bool is_orthogonal_grid_item = Style().IsHorizontalWritingMode() ==
- grid_item_style.IsHorizontalWritingMode();
- if (is_orthogonal_grid_item) {
- grid_item_track_direction =
- (track_direction == kForColumns) ? kForRows : kForColumns;
+ GridItemContributionType contribution_type) const {
+ const NGBlockNode& node = grid_item.node;
+ const ComputedStyle& item_style = node.Style();
+
+ // TODO(ikilpatrick): We'll need to record if any child used an indefinite
+ // size for its contribution, such that we can then do the 2nd pass on the
+ // track-sizing algorithm.
+ LogicalRect unused;
+ const NGConstraintSpace space = CreateConstraintSpace(
+ grid_geometry, grid_item, NGCacheSlot::kMeasure, &unused);
+
+ bool is_parallel_with_track_direction =
+ (track_direction == kForColumns) ==
+ IsParallelWritingMode(Style().GetWritingMode(),
+ item_style.GetWritingMode());
+
+ auto MinMaxContentSizes = [&]() -> MinMaxSizes {
+ DCHECK(is_parallel_with_track_direction);
+ // TODO(ikilpatrick): kIndefiniteSize is incorrect for the %-block-size.
+ // We'll want to determine this using the base or used track-sizes instead.
+ // This should match the %-resolution sizes we use for layout during
+ // measuring.
+ MinMaxSizesInput input(kIndefiniteSize, MinMaxSizesType::kContent);
+ return ComputeMinAndMaxContentContributionForSelf(node, input).sizes;
+ };
+
+ // This function will determine the correct block-size of a grid-item.
+ // TODO(ikilpatrick): This should try and skip layout when possible. Notes:
+ // - We'll need to do a full layout for tables.
+ // - We'll need special logic for replaced elements.
+ // - We'll need to respect the aspect-ratio when appropriate.
+ auto BlockSize = [&]() -> LayoutUnit {
+ DCHECK(!is_parallel_with_track_direction);
+ scoped_refptr<const NGLayoutResult> result = node.Layout(space);
+ // We want to return the block-size in the *child's* writing-mode.
+ return NGFragment(item_style.GetWritingDirection(),
+ result->PhysicalFragment())
+ .BlockSize();
+ };
+
+ LayoutUnit contribution;
+ switch (contribution_type) {
+ case GridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForIntrinsicMaximums:
+ if (is_parallel_with_track_direction)
+ contribution = MinMaxContentSizes().min_size;
+ else
+ contribution = BlockSize();
+ break;
+ case GridItemContributionType::kForIntrinsicMinimums: {
+ // TODO(ikilpatrick): All of the below is incorrect for replaced elements.
+
+ const Length& main_length = is_parallel_with_track_direction
+ ? item_style.LogicalWidth()
+ : item_style.LogicalHeight();
+
+ // We could be clever is and make this an if-stmt, but each type has
+ // subtle consequences. This forces us in the future when we add a new
+ // length type to consider what the best thing is for grid.
+ switch (main_length.GetType()) {
+ case Length::kAuto:
+ case Length::kFitContent:
+ case Length::kFillAvailable:
+ case Length::kPercent:
+ case Length::kCalculated: {
+ // All of the above lengths are considered auto if we are querying a
+ // minimum contribution. They all require definite track-sizes to
+ // determine their final size.
+
+ // Scroll containers are "compressible", and we only consider their
+ // min-size when determining their contribution.
+ if (item_style.IsScrollContainer()) {
+ const NGBoxStrut border_padding =
+ ComputeBorders(space, node) + ComputePadding(space, item_style);
+
+ // TODO(ikilpatrick): This block needs to respect the aspect-ratio,
+ // and apply the transferred min/max sizes when appropriate. We do
+ // this sometimes elsewhere so should unify and simplify this code.
+ if (is_parallel_with_track_direction) {
+ auto MinMaxSizesFunc =
+ [&](MinMaxSizesType type) -> MinMaxSizesResult {
+ // TODO(ikilpatrick): Again, kIndefiniteSize here is incorrect,
+ // and needs to use the base or resolved track sizes.
+ MinMaxSizesInput input(kIndefiniteSize, type);
+ return node.ComputeMinMaxSizes(item_style.GetWritingMode(),
+ input, &space);
+ };
+
+ contribution = ResolveMinInlineLength(
+ space, item_style, border_padding, MinMaxSizesFunc,
+ item_style.LogicalMinWidth());
+ } else {
+ contribution =
+ ResolveMinBlockLength(space, item_style, border_padding,
+ item_style.LogicalMinHeight());
+ }
+ break;
+ }
+
+ if (is_parallel_with_track_direction)
+ contribution = MinMaxContentSizes().min_size;
+ else
+ contribution = BlockSize();
+ break;
+ }
+ case Length::kMinContent:
+ case Length::kMaxContent:
+ case Length::kFixed: {
+ // All of the above lengths are "definite" (non-auto), and don't need
+ // the special min-size treatment above. (They will all end up being
+ // the specified size).
+ if (is_parallel_with_track_direction) {
+ // TODO(ikilpatrick): This is incorrect for replaced elements.
+ const NGBoxStrut border_padding =
+ ComputeBorders(space, node) + ComputePadding(space, item_style);
+ contribution =
+ ComputeInlineSizeForFragment(space, node, border_padding);
+ } else {
+ contribution = BlockSize();
+ }
+ break;
+ }
+ case Length::kMinIntrinsic:
+ case Length::kDeviceWidth:
+ case Length::kDeviceHeight:
+ case Length::kExtendToZoom:
+ case Length::kNone:
+ NOTREACHED();
+ break;
+ }
+ break;
+ }
+ case GridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForMaxContentMaximums:
+ if (is_parallel_with_track_direction)
+ contribution = MinMaxContentSizes().max_size;
+ else
+ contribution = BlockSize();
+ break;
+ case GridItemContributionType::kForFreeSpace:
+ NOTREACHED() << "|kForFreeSpace| should only be used to distribute extra "
+ "space in maximize tracks and stretch auto tracks steps.";
+ break;
}
- Length length = (grid_item_track_direction == kForColumns)
- ? grid_item_style.LogicalWidth()
- : grid_item_style.LogicalHeight();
- return length.IsFixed() ? MinimumValueForLength(length, kIndefiniteSize)
- : LayoutUnit();
+ DCHECK_NE(contribution, kIndefiniteSize);
+ return contribution + ((track_direction == kForColumns)
+ ? grid_item.margins.InlineSum()
+ : grid_item.margins.BlockSum());
}
-void NGGridLayoutAlgorithm::ConstructAndAppendGridItems() {
+void NGGridLayoutAlgorithm::ConstructAndAppendGridItems(
+ GridItems* grid_items,
+ Vector<GridItemData>* out_of_flow_items) const {
+ DCHECK(grid_items);
NGGridChildIterator iterator(Node());
for (NGBlockNode child = iterator.NextChild(); child;
child = iterator.NextChild()) {
- GridItemData grid_item = MeasureGridItem(child);
- // Store out-of-flow items separately, as they do not contribute to track
- // sizing or auto placement.
- if (child.IsOutOfFlowPositioned())
- out_of_flow_items_.emplace_back(grid_item);
- else
- grid_items_.emplace_back(grid_item);
+ GridItemData grid_item(MeasureGridItem(child));
+ // If |out_of_flow_items| is provided, store out-of-flow items separately,
+ // as they do not contribute to track sizing or auto-placement.
+ if (grid_item.item_type == ItemType::kInGridFlow)
+ grid_items->Append(grid_item);
+ else if (out_of_flow_items)
+ out_of_flow_items->emplace_back(grid_item);
+ }
+}
+
+// https://drafts.csswg.org/css-grid-2/#auto-repeat
+wtf_size_t NGGridLayoutAlgorithm::ComputeAutomaticRepetitions(
+ GridTrackSizingDirection track_direction) const {
+ const NGGridTrackList& track_list =
+ (track_direction == kForColumns)
+ ? Style().GridTemplateColumns().NGTrackList()
+ : Style().GridTemplateRows().NGTrackList();
+ if (!track_list.HasAutoRepeater())
+ return 0;
+
+ LayoutUnit available_size = (track_direction == kForColumns)
+ ? grid_available_size_.inline_size
+ : grid_available_size_.block_size;
+ LayoutUnit max_available_size = available_size;
+
+ if (available_size == kIndefiniteSize) {
+ max_available_size = (track_direction == kForColumns)
+ ? grid_max_available_size_.inline_size
+ : grid_max_available_size_.block_size;
+ available_size = (track_direction == kForColumns)
+ ? grid_min_available_size_.inline_size
+ : grid_min_available_size_.block_size;
}
- // Fill grid item indices vector in document order.
- reordered_item_indices_.ReserveInitialCapacity(grid_items_.size());
- for (wtf_size_t i = 0; i < grid_items_.size(); ++i)
- reordered_item_indices_.push_back(i);
+ const LayoutUnit grid_gap = GridGap(track_direction, available_size);
+
+ LayoutUnit auto_repeater_size;
+ LayoutUnit non_auto_specified_size;
+ for (wtf_size_t repeater_index = 0;
+ repeater_index < track_list.RepeaterCount(); ++repeater_index) {
+ const wtf_size_t repeater_track_count =
+ track_list.RepeatSize(repeater_index);
+ LayoutUnit repeater_size;
+ for (wtf_size_t track_index = 0; track_index < repeater_track_count;
+ ++track_index) {
+ const GridTrackSize& track_size =
+ track_list.RepeatTrackSize(repeater_index, track_index);
+ base::Optional<LayoutUnit> fixed_min_track_breadth;
+ base::Optional<LayoutUnit> fixed_max_track_breadth;
+ if (track_size.HasFixedMaxTrackBreadth()) {
+ fixed_max_track_breadth = MinimumValueForLength(
+ track_size.MaxTrackBreadth().length(), available_size);
+ }
+ if (track_size.HasFixedMinTrackBreadth()) {
+ fixed_min_track_breadth = MinimumValueForLength(
+ track_size.MinTrackBreadth().length(), available_size);
+ }
+ LayoutUnit track_contribution;
+ if (fixed_max_track_breadth && fixed_min_track_breadth) {
+ track_contribution =
+ std::max(*fixed_max_track_breadth, *fixed_min_track_breadth);
+ } else if (fixed_max_track_breadth) {
+ track_contribution = *fixed_max_track_breadth;
+ } else if (fixed_min_track_breadth) {
+ track_contribution = *fixed_min_track_breadth;
+ }
+
+ // For the purpose of finding the number of auto-repeated tracks in a
+ // standalone axis, the UA must floor the track size to a UA-specified
+ // value to avoid division by zero. It is suggested that this floor be
+ // 1px.
+ if (track_list.RepeatType(repeater_index) !=
+ NGGridTrackRepeater::kNoAutoRepeat) {
+ track_contribution = std::max(LayoutUnit(1), track_contribution);
+ }
+
+ repeater_size += track_contribution + grid_gap;
+ }
+ if (track_list.RepeatType(repeater_index) ==
+ NGGridTrackRepeater::kNoAutoRepeat) {
+ non_auto_specified_size +=
+ repeater_size * track_list.RepeatCount(repeater_index, 0);
+ } else {
+ DCHECK_EQ(0, auto_repeater_size);
+ auto_repeater_size = repeater_size;
+ }
+ }
+
+ DCHECK_GT(auto_repeater_size, 0);
+
+ // We can compute the number of repetitions by satisfying the expression
+ // below. Notice that we subtract an extra |grid_gap| since it was included
+ // in the contribution for the last set in the collection.
+ // available_size =
+ // (repetitions * auto_repeater_size) +
+ // non_auto_specified_size - grid_gap
+ //
+ // Solving for repetitions we have:
+ // repetitions =
+ // available_size - (non_auto_specified_size - grid_gap) /
+ // auto_repeater_size
+ non_auto_specified_size -= grid_gap;
+
+ // First we want to allow as many repetitions as possible, up to the max
+ // available-size. Only do this if we have a definite max-size.
+ // If a definite available-size was provided, |max_available_size| will be
+ // set to that value.
+ if (max_available_size != LayoutUnit::Max()) {
+ // Use floor to ensure that the auto repeater sizes goes under the max
+ // available-size.
+ const int count = FloorToInt(
+ (max_available_size - non_auto_specified_size) / auto_repeater_size);
+ return (count <= 0) ? 1u : count;
+ }
+
+ // Next, consider the min available-size, which was already used to floor
+ // |available_size|. Use ceil to ensure that the auto repeater size goes
+ // above this min available-size.
+ const int count = CeilToInt((available_size - non_auto_specified_size) /
+ auto_repeater_size);
+ return (count <= 0) ? 1u : count;
}
namespace {
@@ -392,32 +822,14 @@ AxisEdge AxisEdgeFromItemPosition(const ComputedStyle& container_style,
} // namespace
NGGridLayoutAlgorithm::GridItemData NGGridLayoutAlgorithm::MeasureGridItem(
- const NGBlockNode node) {
+ const NGBlockNode node) const {
const auto& container_style = Style();
// Before we take track sizing into account for column width contributions,
// have all child inline and min/max sizes measured for content-based width
// resolution.
GridItemData grid_item(node);
- const ComputedStyle& child_style = node.Style();
- bool is_orthogonal_flow_root = !IsParallelWritingMode(
- ConstraintSpace().GetWritingMode(), child_style.GetWritingMode());
- NGConstraintSpace constraint_space = BuildSpaceForGridItem(node);
-
- // Children with orthogonal writing modes require a full layout pass to
- // determine inline size.
- if (is_orthogonal_flow_root) {
- scoped_refptr<const NGLayoutResult> result = node.Layout(constraint_space);
- grid_item.inline_size = NGFragment(ConstraintSpace().GetWritingDirection(),
- result->PhysicalFragment())
- .InlineSize();
- } else {
- NGBoxStrut border_padding_in_child_writing_mode =
- ComputeBorders(constraint_space, node) +
- ComputePadding(constraint_space, child_style);
- grid_item.inline_size = ComputeInlineSizeForFragment(
- constraint_space, node, border_padding_in_child_writing_mode);
- }
+ const ComputedStyle& item_style = node.Style();
const ItemPosition normal_behaviour =
node.IsReplaced() ? ItemPosition::kStart : ItemPosition::kStretch;
@@ -426,218 +838,213 @@ NGGridLayoutAlgorithm::GridItemData NGGridLayoutAlgorithm::MeasureGridItem(
// know if it stretches ahead of time to correctly determine any block-axis
// contribution).
grid_item.inline_axis_alignment = AxisEdgeFromItemPosition(
- container_style, child_style,
- child_style.ResolvedJustifySelf(normal_behaviour, &container_style)
+ container_style, item_style,
+ item_style.ResolvedJustifySelf(normal_behaviour, &container_style)
.GetPosition(),
/* is_inline_axis */ true, &grid_item.is_inline_axis_stretched);
grid_item.block_axis_alignment = AxisEdgeFromItemPosition(
- container_style, child_style,
- child_style.ResolvedAlignSelf(normal_behaviour, &container_style)
+ container_style, item_style,
+ item_style.ResolvedAlignSelf(normal_behaviour, &container_style)
.GetPosition(),
/* is_inline_axis */ false, &grid_item.is_block_axis_stretched);
+ // TODO(ikilpatrick): This is likely incorrect for margins in the
+ // ComputeMinMaxSizes phase.
grid_item.margins =
- ComputeMarginsFor(constraint_space, child_style, ConstraintSpace());
- grid_item.min_max_sizes =
- node.ComputeMinMaxSizes(
- ConstraintSpace().GetWritingMode(),
- MinMaxSizesInput(child_percentage_size_.block_size,
- MinMaxSizesType::kContent),
- &constraint_space)
- .sizes;
- return grid_item;
-}
+ ComputePhysicalMargins(item_style, ChildAvailableSize().inline_size)
+ .ConvertToLogical(ConstraintSpace().GetWritingDirection());
-NGConstraintSpace NGGridLayoutAlgorithm::BuildSpaceForGridItem(
- const NGBlockNode node) const {
- const auto& style = node.Style();
- NGConstraintSpaceBuilder builder(ConstraintSpace(),
- style.GetWritingDirection(),
- /* is_new_fc */ true);
- SetOrthogonalFallbackInlineSizeIfNeeded(Style(), node, &builder);
- builder.SetCacheSlot(NGCacheSlot::kMeasure);
- builder.SetIsPaintedAtomically(true);
- builder.SetAvailableSize(ChildAvailableSize());
- builder.SetPercentageResolutionSize(child_percentage_size_);
- builder.SetIsShrinkToFit(style.LogicalWidth().IsAuto());
- return builder.ToConstraintSpace();
+ grid_item.item_type = node.IsOutOfFlowPositioned() ? ItemType::kOutOfFlow
+ : ItemType::kInGridFlow;
+
+ return grid_item;
}
-void NGGridLayoutAlgorithm::SetSpecifiedTracks() {
+void NGGridLayoutAlgorithm::BuildBlockTrackCollections(
+ GridItems* grid_items,
+ NGGridBlockTrackCollection* column_track_collection,
+ NGGridBlockTrackCollection* row_track_collection,
+ NGGridPlacement* grid_placement) const {
+ DCHECK(grid_items);
+ DCHECK(column_track_collection);
+ DCHECK(row_track_collection);
+ DCHECK(grid_placement);
const ComputedStyle& grid_style = Style();
- // TODO(kschmi): Auto track repeat count should be based on the number of
- // children, rather than specified auto-column/track. Temporarily assign them
- // to zero here to avoid DCHECK's until we implement this logic.
- automatic_column_repetitions_ = 0;
- automatic_row_repetitions_ = 0;
-
- // TODO(janewman): We need to implement calculation for track auto repeat
- // count so this can be used outside of testing.
- block_column_track_collection_.SetSpecifiedTracks(
- &grid_style.GridTemplateColumns().NGTrackList(),
- &grid_style.GridAutoColumns().NGTrackList(),
- automatic_column_repetitions_);
-
- block_row_track_collection_.SetSpecifiedTracks(
- &grid_style.GridTemplateRows().NGTrackList(),
- &grid_style.GridAutoRows().NGTrackList(), automatic_row_repetitions_);
+
+ auto BuildBlockTrackCollection =
+ [&](NGGridBlockTrackCollection* track_collection) {
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+ const wtf_size_t start_offset =
+ grid_placement->StartOffset(track_direction);
+
+ const NGGridTrackList& template_track_list =
+ (track_direction == kForColumns)
+ ? grid_style.GridTemplateColumns().NGTrackList()
+ : grid_style.GridTemplateRows().NGTrackList();
+ const NGGridTrackList& auto_track_list =
+ (track_direction == kForColumns)
+ ? grid_style.GridAutoColumns().NGTrackList()
+ : grid_style.GridAutoRows().NGTrackList();
+
+ track_collection->SetSpecifiedTracks(
+ &template_track_list, &auto_track_list, start_offset,
+ grid_placement->AutoRepetitions(track_collection->Direction()));
+ EnsureTrackCoverageForGridItems(*grid_items, track_collection);
+ track_collection->FinalizeRanges(start_offset);
+ };
+
+ grid_placement->RunAutoPlacementAlgorithm(grid_items);
+ BuildBlockTrackCollection(column_track_collection);
+ BuildBlockTrackCollection(row_track_collection);
}
-void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts() {
- DCHECK_EQ(0u, explicit_column_start_);
- DCHECK_EQ(0u, explicit_row_start_);
- DCHECK_EQ(0u, column_count_);
- DCHECK_EQ(0u, row_count_);
+void NGGridLayoutAlgorithm::BuildAlgorithmTrackCollections(
+ GridItems* grid_items,
+ NGGridLayoutAlgorithmTrackCollection* column_track_collection,
+ NGGridLayoutAlgorithmTrackCollection* row_track_collection,
+ NGGridPlacement* grid_placement) const {
+ DCHECK(grid_items);
+ DCHECK(column_track_collection);
+ DCHECK(row_track_collection);
+ DCHECK(grid_placement);
+
+ // Build block track collections.
+ NGGridBlockTrackCollection column_block_track_collection(kForColumns);
+ NGGridBlockTrackCollection row_block_track_collection(kForRows);
+ BuildBlockTrackCollections(grid_items, &column_block_track_collection,
+ &row_block_track_collection, grid_placement);
+
+ // Build algorithm track collections from the block track collections.
+ *column_track_collection = NGGridLayoutAlgorithmTrackCollection(
+ column_block_track_collection,
+ grid_available_size_.inline_size == kIndefiniteSize);
+
+ *row_track_collection = NGGridLayoutAlgorithmTrackCollection(
+ row_block_track_collection,
+ grid_available_size_.block_size == kIndefiniteSize);
+}
- NGGridChildIterator iterator(Node());
- for (NGBlockNode child = iterator.NextChild(); child;
- child = iterator.NextChild()) {
- GridSpan column_span = GridPositionsResolver::ResolveGridPositionsFromStyle(
- Style(), child.Style(), kForColumns,
- AutoRepeatCountForDirection(kForColumns));
- GridSpan row_span = GridPositionsResolver::ResolveGridPositionsFromStyle(
- Style(), child.Style(), kForRows,
- AutoRepeatCountForDirection(kForRows));
- if (!column_span.IsIndefinite()) {
- explicit_column_start_ = std::max<int>(
- explicit_column_start_, -column_span.UntranslatedStartLine());
- column_count_ =
- std::max<int>(column_count_, column_span.UntranslatedEndLine());
- } else {
- column_count_ = std::max<int>(
- column_count_, GridPositionsResolver::SpanSizeForAutoPlacedItem(
- child.Style(), kForColumns));
- }
- if (!row_span.IsIndefinite()) {
- explicit_row_start_ =
- std::max<int>(explicit_row_start_, -row_span.UntranslatedStartLine());
- row_count_ = std::max<int>(row_count_, row_span.UntranslatedEndLine());
- } else {
- row_count_ = std::max<int>(
- row_count_, GridPositionsResolver::SpanSizeForAutoPlacedItem(
- child.Style(), kForRows));
- }
+void NGGridLayoutAlgorithm::EnsureTrackCoverageForGridItems(
+ const GridItems& grid_items,
+ NGGridBlockTrackCollection* track_collection) const {
+ DCHECK(track_collection);
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+ for (const auto& grid_item : grid_items.item_data) {
+ track_collection->EnsureTrackCoverage(grid_item.StartLine(track_direction),
+ grid_item.SpanSize(track_direction));
}
}
-void NGGridLayoutAlgorithm::CacheItemSetIndices() {
- auto CacheItemSetIndices = [this](GridTrackSizingDirection track_direction) {
- const auto& track_collection = TrackCollection(track_direction);
- for (GridItemData& item : grid_items_) {
- wtf_size_t first_spanned_range =
- track_collection.RangeIndexFromTrackNumber(
- item.StartLine(track_direction));
- wtf_size_t last_spanned_range =
- track_collection.RangeIndexFromTrackNumber(
- item.EndLine(track_direction) - 1);
-
- DCHECK_LE(first_spanned_range, last_spanned_range);
- wtf_size_t begin_set_index =
- track_collection.RangeStartingSetIndex(first_spanned_range);
- wtf_size_t end_set_index =
- track_collection.RangeStartingSetIndex(last_spanned_range) +
- track_collection.RangeSetCount(last_spanned_range);
-
- DCHECK_LE(begin_set_index, end_set_index);
- DCHECK_LE(end_set_index, track_collection.SetCount());
-
- if (track_direction == kForColumns) {
- item.columns_begin_set_index = begin_set_index;
- item.columns_end_set_index = end_set_index;
- } else {
- item.rows_begin_set_index = begin_set_index;
- item.rows_end_set_index = end_set_index;
- }
- }
- };
- CacheItemSetIndices(kForColumns);
- CacheItemSetIndices(kForRows);
-}
+void NGGridLayoutAlgorithm::CacheGridItemsTrackSpanProperties(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ GridItems* grid_items) const {
+ DCHECK(grid_items);
+ const GridTrackSizingDirection track_direction = track_collection.Direction();
-void NGGridLayoutAlgorithm::DetermineGridItemsSpanningIntrinsicOrFlexTracks(
- GridTrackSizingDirection track_direction) {
- auto CompareGridItemsByStartLine =
- [this, track_direction](wtf_size_t index_a, wtf_size_t index_b) -> bool {
- return grid_items_[index_a].StartLine(track_direction) <
- grid_items_[index_b].StartLine(track_direction);
+ auto CompareGridItemsByStartLine = [grid_items, track_direction](
+ wtf_size_t a, wtf_size_t b) -> bool {
+ return grid_items->item_data[a].StartLine(track_direction) <
+ grid_items->item_data[b].StartLine(track_direction);
};
- std::sort(reordered_item_indices_.begin(), reordered_item_indices_.end(),
+ std::sort(grid_items->reordered_item_indices.begin(),
+ grid_items->reordered_item_indices.end(),
CompareGridItemsByStartLine);
- // At this point we have the grid items sorted by their start line in the
- // respective direction; this is important since we'll process both, the
- // ranges in the track collection and the grid items, incrementally.
- const auto& track_collection = TrackCollection(track_direction);
- auto range_spanning_flex_track_iterator = track_collection.RangeIterator();
- auto range_spanning_intrinsic_track_iterator =
- track_collection.RangeIterator();
-
- for (GridItemData& grid_item : GetReorderedGridItems()) {
- // We want to find the first range in the collection that:
- // - Spans tracks located AFTER the start line of the current grid item;
- // this can be done by checking that the last track number of the current
- // range is NOT less than the current grid item's start line. Furthermore,
- // since grid items are sorted by start line, if at any point a range is
- // located BEFORE the current grid item's start line, the same range will
- // also be located BEFORE any subsequent item's start line.
- // - Contains a track with an intrinsic/flexible sizing function.
- while (!range_spanning_intrinsic_track_iterator.IsAtEnd() &&
- (range_spanning_intrinsic_track_iterator.RangeTrackEnd() <
- grid_item.StartLine(track_direction) ||
- !track_collection.IsRangeSpanningIntrinsicTrack(
- range_spanning_intrinsic_track_iterator.RangeIndex()))) {
- range_spanning_intrinsic_track_iterator.MoveToNextRange();
- }
- while (!range_spanning_flex_track_iterator.IsAtEnd() &&
- (range_spanning_flex_track_iterator.RangeTrackEnd() <
- grid_item.StartLine(track_direction) ||
- !track_collection.IsRangeSpanningFlexTrack(
- range_spanning_flex_track_iterator.RangeIndex()))) {
- range_spanning_flex_track_iterator.MoveToNextRange();
- }
-
- // Notice that, from the way we build the ranges of a track collection (see
- // |NGGridBlockTrackCollection::EnsureTrackCoverage|), any given range must
- // either be completely contained or excluded from a grid item's span. Thus,
- // if the current range's last track is also located BEFORE the item's end
- // line, then this range, including the intrinsic/flexible track it spans,
- // is completely contained within this grid item's boundaries.
- // Otherwise, this and any subsequent range are excluded from this item's
- // span, meaning that it does not span an intrinsic/flexible track.
- grid_item.is_spanning_intrinsic_track =
- !range_spanning_intrinsic_track_iterator.IsAtEnd() &&
- range_spanning_intrinsic_track_iterator.RangeTrackEnd() <
- grid_item.EndLine(track_direction);
- grid_item.is_spanning_flex_track =
- !range_spanning_flex_track_iterator.IsAtEnd() &&
- range_spanning_flex_track_iterator.RangeTrackEnd() <
- grid_item.EndLine(track_direction);
- }
+ auto CacheTrackSpanPropertyForAllGridItems =
+ [&](TrackSpanProperties::PropertyId property) {
+ // At this point we have the grid items sorted by their start line in
+ // the respective direction; this is important since we'll process both,
+ // the ranges in the track collection and the grid items, incrementally.
+ auto range_iterator = track_collection.RangeIterator();
+
+ for (auto& grid_item : *grid_items) {
+ // We want to find the first range in the collection that:
+ // - Spans tracks located AFTER the start line of the current grid
+ // item; this can be done by checking that the last track number of
+ // the current range is NOT less than the current grid item's start
+ // line. Furthermore, since grid items are sorted by start line, if
+ // at any point a range is located BEFORE the current grid item's
+ // start line, the same range will also be located BEFORE any
+ // subsequent item's start line.
+ // - Contains a track that fulfills the specified property.
+ while (!range_iterator.IsAtEnd() &&
+ (range_iterator.RangeTrackEnd() <
+ grid_item.StartLine(track_direction) ||
+ !track_collection.RangeHasTrackSpanProperty(
+ range_iterator.RangeIndex(), property))) {
+ range_iterator.MoveToNextRange();
+ }
+
+ // Since we discarded every range in the track collection, any
+ // following grid item cannot fulfill the property.
+ if (range_iterator.IsAtEnd())
+ break;
+
+ // Notice that, from the way we build the ranges of a track collection
+ // (see |NGGridBlockTrackCollection::EnsureTrackCoverage|), any given
+ // range must either be completely contained or excluded from a grid
+ // item's span. Thus, if the current range's last track is also
+ // located BEFORE the item's end line, then this range, including a
+ // track that fulfills the specified property, is completely contained
+ // within this item's boundaries. Otherwise, this and every subsequent
+ // range are excluded from the grid item's span, meaning that such
+ // item cannot satisfy the property we are looking for.
+ if (range_iterator.RangeTrackEnd() <
+ grid_item.EndLine(track_direction)) {
+ grid_item.SetTrackSpanProperty(property, track_direction);
+ }
+ }
+ };
+
+ CacheTrackSpanPropertyForAllGridItems(TrackSpanProperties::kHasFlexibleTrack);
+ CacheTrackSpanPropertyForAllGridItems(
+ TrackSpanProperties::kHasIntrinsicTrack);
}
-// https://drafts.csswg.org/css-grid-1/#algo-track-sizing
-void NGGridLayoutAlgorithm::ComputeUsedTrackSizes(
- GridTrackSizingDirection track_direction) {
- auto& track_collection = TrackCollection(track_direction);
- LayoutUnit content_box_size = (track_direction == kForColumns)
- ? child_percentage_size_.inline_size
- : child_percentage_size_.block_size;
+// https://drafts.csswg.org/css-grid-2/#algo-init
+NGGridLayoutAlgorithm::SetGeometry NGGridLayoutAlgorithm::InitializeTrackSizes(
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const {
+ DCHECK(track_collection);
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+ LayoutUnit available_size = (track_direction == kForColumns)
+ ? grid_available_size_.inline_size
+ : grid_available_size_.block_size;
+
+ LayoutUnit set_offset = (track_direction == kForColumns)
+ ? BorderScrollbarPadding().inline_start
+ : BorderScrollbarPadding().block_start;
+ wtf_size_t last_indefinite_index = kNotFound;
+ wtf_size_t index = 0u;
+ Vector<SetOffsetData> sets;
+ sets.ReserveInitialCapacity(track_collection->SetCount() + 1);
+ sets.emplace_back(set_offset, last_indefinite_index);
- // 1. Initialize track sizes (https://drafts.csswg.org/css-grid-1/#algo-init).
- for (auto set_iterator = track_collection.GetSetIterator();
+ const LayoutUnit grid_gap = GridGap(track_direction);
+
+ for (auto set_iterator = track_collection->GetSetIterator();
!set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
- NGGridSet& current_set = set_iterator.CurrentSet();
+ auto& current_set = set_iterator.CurrentSet();
const GridTrackSize& track_size = current_set.TrackSize();
+ if (track_size.IsFitContent()) {
+ // Indefinite lengths cannot occur, as they must be normalized to 'auto'.
+ DCHECK(!track_size.FitContentTrackBreadth().HasPercentage() ||
+ available_size != kIndefiniteSize);
+ current_set.SetFitContentLimit(MinimumValueForLength(
+ track_size.FitContentTrackBreadth().length(), available_size));
+ }
+
if (track_size.HasFixedMinTrackBreadth()) {
- // Indefinite lengths cannot occur, as they’re treated as 'auto'.
DCHECK(!track_size.MinTrackBreadth().HasPercentage() ||
- content_box_size != kIndefiniteSize);
+ available_size != kIndefiniteSize);
// A fixed sizing function: Resolve to an absolute length and use that
// size as the track’s initial base size.
LayoutUnit fixed_min_breadth = MinimumValueForLength(
- track_size.MinTrackBreadth().length(), content_box_size);
+ track_size.MinTrackBreadth().length(), available_size);
current_set.SetBaseSize(fixed_min_breadth * current_set.TrackCount());
} else {
// An intrinsic sizing function: Use an initial base size of zero.
@@ -649,125 +1056,178 @@ void NGGridLayoutAlgorithm::ComputeUsedTrackSizes(
// an intrinsic or flexible sizing function needs no further resolution.
if (track_size.HasFixedMaxTrackBreadth()) {
DCHECK(!track_size.MaxTrackBreadth().HasPercentage() ||
- content_box_size != kIndefiniteSize);
+ available_size != kIndefiniteSize);
// A fixed sizing function: Resolve to an absolute length and use that
// size as the track’s initial growth limit; if the growth limit is less
// than the base size, increase the growth limit to match the base size.
LayoutUnit fixed_max_breadth = MinimumValueForLength(
- track_size.MaxTrackBreadth().length(), content_box_size);
+ track_size.MaxTrackBreadth().length(), available_size);
current_set.SetGrowthLimit(
std::max(current_set.BaseSize(),
fixed_max_breadth * current_set.TrackCount()));
}
+
+ DCHECK_NE(track_size.GetType(), kLengthTrackSizing);
+
+ // TODO(ikilpatrick): If all of are our row tracks are "inflexible" (they
+ // all have fixed min/max track breadths which are the same), we need to
+ // also apply 'align-content' upfront to ensure that orthogonal children
+ // have the correct available-size given.
+
+ // For the purposes of our "base" row set geometry, we only use any fixed
+ // max-track breadth. We use this for sizing any orthogonal, (or
+ // %-block-size) children.
+ if (track_direction == kForRows && track_size.HasFixedMaxTrackBreadth()) {
+ set_offset +=
+ current_set.GrowthLimit() + current_set.TrackCount() * grid_gap;
+ } else {
+ last_indefinite_index = index;
+ }
+
+ sets.emplace_back(set_offset, last_indefinite_index);
+ ++index;
}
+ return {sets, grid_gap};
+}
+
+// https://drafts.csswg.org/css-grid-2/#algo-track-sizing
+void NGGridLayoutAlgorithm::ComputeUsedTrackSizes(
+ SizingConstraint sizing_constraint,
+ const GridGeometry& grid_geometry,
+ NGGridLayoutAlgorithmTrackCollection* track_collection,
+ GridItems* grid_items) const {
+ DCHECK(track_collection);
+ DCHECK(grid_items);
+
// 2. Resolve intrinsic track sizing functions to absolute lengths.
- DetermineGridItemsSpanningIntrinsicOrFlexTracks(track_direction);
- ResolveIntrinsicTrackSizes(track_direction);
+ ResolveIntrinsicTrackSizes(grid_geometry, track_collection, grid_items);
+
+ // 3. If the free space is positive, distribute it equally to the base sizes
+ // of all tracks, freezing tracks as they reach their growth limits (and
+ // continuing to grow the unfrozen tracks as needed).
+ MaximizeTracks(sizing_constraint, track_collection);
+
+ // TODO(janewman): 4. Expand Flexible Tracks
+
+ // 5. Stretch 'auto' Tracks
+ StretchAutoTracks(sizing_constraint, track_collection);
}
// Helpers for the track sizing algorithm.
namespace {
+using GridItemContributionType =
+ NGGridLayoutAlgorithm::GridItemContributionType;
+using GridSetVector = Vector<NGGridSet*, 16>;
+
+LayoutUnit DefiniteGrowthLimit(const NGGridSet& set) {
+ LayoutUnit growth_limit = set.GrowthLimit();
+ // For infinite growth limits, substitute the track’s base size.
+ return (growth_limit == kIndefiniteSize) ? set.BaseSize() : growth_limit;
+}
+
// Returns the corresponding size to be increased by accommodating a grid item's
// contribution; for intrinsic min track sizing functions, return the base size.
// For intrinsic max track sizing functions, return the growth limit.
-static LayoutUnit AffectedSizeForContribution(
+LayoutUnit AffectedSizeForContribution(
const NGGridSet& set,
- NGGridItemContributionType contribution_type) {
+ GridItemContributionType contribution_type) {
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
- case NGGridItemContributionType::kForContentBasedMinimums:
- case NGGridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForMaxContentMinimums:
return set.BaseSize();
- case NGGridItemContributionType::kForIntrinsicMaximums:
- case NGGridItemContributionType::kForMaxContentMaximums:
- LayoutUnit growth_limit = set.GrowthLimit();
- // For infinite growth limits, substitute with the track's base size.
- if (growth_limit == kIndefiniteSize)
- return set.BaseSize();
- return growth_limit;
+ case GridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForMaxContentMaximums:
+ return DefiniteGrowthLimit(set);
+ case GridItemContributionType::kForFreeSpace:
+ NOTREACHED();
+ return LayoutUnit();
}
}
-static void GrowAffectedSizeByPlannedIncrease(
+void GrowAffectedSizeByPlannedIncrease(
NGGridSet& set,
- NGGridItemContributionType contribution_type) {
+ GridItemContributionType contribution_type) {
+ bool did_growth_limit_become_finite = false;
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
- case NGGridItemContributionType::kForContentBasedMinimums:
- case NGGridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForMaxContentMinimums:
set.SetBaseSize(set.BaseSize() + set.PlannedIncrease());
break;
- case NGGridItemContributionType::kForIntrinsicMaximums:
- case NGGridItemContributionType::kForMaxContentMaximums:
- LayoutUnit growth_limit = set.GrowthLimit();
- // If the affected size to grow is an infinite growth limit, set it to the
- // track's base size plus the planned increase.
- if (growth_limit == kIndefiniteSize)
- set.SetGrowthLimit(set.BaseSize() + set.PlannedIncrease());
- else
- set.SetGrowthLimit(growth_limit + set.PlannedIncrease());
+ case GridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForMaxContentMaximums:
+ did_growth_limit_become_finite = (set.GrowthLimit() == kIndefiniteSize);
+ set.SetGrowthLimit(DefiniteGrowthLimit(set) + set.PlannedIncrease());
+ break;
+ case GridItemContributionType::kForFreeSpace:
+ NOTREACHED();
break;
}
+
+ // Mark any tracks whose growth limit changed from infinite to finite in this
+ // step as infinitely growable for the next step.
+ if (contribution_type == GridItemContributionType::kForIntrinsicMaximums)
+ set.SetInfinitelyGrowable(did_growth_limit_become_finite);
+ else
+ set.SetInfinitelyGrowable(false);
}
// Returns true if a set should increase its used size according to the steps in
-// https://drafts.csswg.org/css-grid-1/#algo-spanning-items; false otherwise.
-static bool IsContributionAppliedToSet(
- const NGGridSet& set,
- NGGridItemContributionType contribution_type) {
+// https://drafts.csswg.org/css-grid-2/#algo-spanning-items; false otherwise.
+bool IsContributionAppliedToSet(const NGGridSet& set,
+ GridItemContributionType contribution_type) {
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForIntrinsicMinimums:
return set.TrackSize().HasIntrinsicMinTrackBreadth();
- case NGGridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
return set.TrackSize().HasMinOrMaxContentMinTrackBreadth();
- case NGGridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForMaxContentMinimums:
// TODO(ethavar): Check if the grid container is being sized under a
// 'max-content' constraint to consider 'auto' min track sizing functions,
- // see https://drafts.csswg.org/css-grid-1/#track-size-max-content-min.
+ // see https://drafts.csswg.org/css-grid-2/#track-size-max-content-min.
return set.TrackSize().HasMaxContentMinTrackBreadth();
- case NGGridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForIntrinsicMaximums:
return set.TrackSize().HasIntrinsicMaxTrackBreadth();
- case NGGridItemContributionType::kForMaxContentMaximums:
+ case GridItemContributionType::kForMaxContentMaximums:
return set.TrackSize().HasMaxContentOrAutoMaxTrackBreadth();
+ case GridItemContributionType::kForFreeSpace:
+ return true;
}
}
-// https://drafts.csswg.org/css-grid-1/#extra-space
+// https://drafts.csswg.org/css-grid-2/#extra-space
// Returns true if a set's used size should be consider to grow beyond its limit
// (see the "Distribute space beyond limits" section); otherwise, false.
// Note that we will deliberately return false in cases where we don't have a
// collection of tracks different than "all affected tracks".
-static bool ShouldUsedSizeGrowBeyondLimit(
- const NGGridSet& set,
- NGGridItemContributionType contribution_type) {
- // This function assumes that we already determined that extra space
- // distribution will be applied to the specified set.
- DCHECK(IsContributionAppliedToSet(set, contribution_type));
-
+bool ShouldUsedSizeGrowBeyondLimit(const NGGridSet& set,
+ GridItemContributionType contribution_type) {
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
- case NGGridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
return set.TrackSize().HasIntrinsicMaxTrackBreadth();
- case NGGridItemContributionType::kForMaxContentMinimums:
- return set.TrackSize().HasMaxContentMaxTrackBreadth();
- case NGGridItemContributionType::kForIntrinsicMaximums:
- case NGGridItemContributionType::kForMaxContentMaximums:
+ case GridItemContributionType::kForMaxContentMinimums:
+ return set.TrackSize().HasMaxContentOrAutoMaxTrackBreadth();
+ case GridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForMaxContentMaximums:
+ case GridItemContributionType::kForFreeSpace:
return false;
}
}
-static bool IsDistributionForGrowthLimits(
- NGGridItemContributionType contribution_type) {
+bool IsDistributionForGrowthLimits(GridItemContributionType contribution_type) {
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
- case NGGridItemContributionType::kForContentBasedMinimums:
- case NGGridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForMaxContentMinimums:
+ case GridItemContributionType::kForFreeSpace:
return false;
- case NGGridItemContributionType::kForIntrinsicMaximums:
- case NGGridItemContributionType::kForMaxContentMaximums:
+ case GridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForMaxContentMaximums:
return true;
}
}
@@ -777,21 +1237,21 @@ enum class InfinitelyGrowableBehavior { kEnforce, kIgnore };
// We define growth potential = limit - affected size; for base sizes, the limit
// is its growth limit. For growth limits, the limit is infinity if it is marked
// as "infinitely growable", and equal to the growth limit otherwise.
-static LayoutUnit GrowthPotentialForSet(
+LayoutUnit GrowthPotentialForSet(
const NGGridSet& set,
- NGGridItemContributionType contribution_type,
+ GridItemContributionType contribution_type,
InfinitelyGrowableBehavior infinitely_growable_behavior =
InfinitelyGrowableBehavior::kEnforce) {
switch (contribution_type) {
- case NGGridItemContributionType::kForIntrinsicMinimums:
- case NGGridItemContributionType::kForContentBasedMinimums:
- case NGGridItemContributionType::kForMaxContentMinimums: {
+ case GridItemContributionType::kForIntrinsicMinimums:
+ case GridItemContributionType::kForContentBasedMinimums:
+ case GridItemContributionType::kForMaxContentMinimums: {
LayoutUnit growth_limit = set.GrowthLimit();
return (growth_limit == kIndefiniteSize) ? kIndefiniteSize
: growth_limit - set.BaseSize();
}
- case NGGridItemContributionType::kForIntrinsicMaximums:
- case NGGridItemContributionType::kForMaxContentMaximums: {
+ case GridItemContributionType::kForIntrinsicMaximums:
+ case GridItemContributionType::kForMaxContentMaximums: {
if (infinitely_growable_behavior ==
InfinitelyGrowableBehavior::kEnforce &&
!set.IsInfinitelyGrowable()) {
@@ -800,9 +1260,7 @@ static LayoutUnit GrowthPotentialForSet(
return LayoutUnit();
}
- LayoutUnit growth_limit = set.GrowthLimit();
LayoutUnit fit_content_limit = set.FitContentLimit();
- DCHECK(growth_limit >= 0 || growth_limit == kIndefiniteSize);
DCHECK(fit_content_limit >= 0 || fit_content_limit == kIndefiniteSize);
// The max track sizing function of a 'fit-content' track is treated as
@@ -810,41 +1268,76 @@ static LayoutUnit GrowthPotentialForSet(
// argument, after which it is treated as having a fixed sizing function
// of that argument (with a growth potential of zero).
if (fit_content_limit != kIndefiniteSize) {
- LayoutUnit growth_potential = (growth_limit != kIndefiniteSize)
- ? fit_content_limit - growth_limit
- : fit_content_limit;
+ LayoutUnit growth_potential =
+ fit_content_limit - DefiniteGrowthLimit(set);
return growth_potential.ClampNegativeToZero();
}
// Otherwise, this set has infinite growth potential.
return kIndefiniteSize;
}
+ case GridItemContributionType::kForFreeSpace: {
+ LayoutUnit growth_limit = set.GrowthLimit();
+ DCHECK_NE(growth_limit, kIndefiniteSize);
+ return growth_limit - set.BaseSize();
+ }
}
}
-} // namespace
-
-// Follow the definitions from https://drafts.csswg.org/css-grid-1/#extra-space;
+// Follow the definitions from https://drafts.csswg.org/css-grid-2/#extra-space;
// notice that this method replaces the notion of "tracks" with "sets".
-void NGGridLayoutAlgorithm::DistributeExtraSpaceToSets(
+void DistributeExtraSpaceToSets(
LayoutUnit extra_space,
- NGGridItemContributionType contribution_type,
- NGGridSetVector* sets_to_grow,
- NGGridSetVector* sets_to_grow_beyond_limit) {
- DCHECK(sets_to_grow && extra_space >= 0);
- if (!extra_space)
+ bool is_equal_distribution,
+ GridItemContributionType contribution_type,
+ GridSetVector* sets_to_grow,
+ GridSetVector* sets_to_grow_beyond_limit = nullptr) {
+ DCHECK(extra_space && sets_to_grow);
+
+ if (extra_space == kIndefiniteSize) {
+ // Infinite extra space should only happen when distributing free space at
+ // the maximize tracks step; in such case, we can simplify this method by
+ // "filling" every track base size up to their growth limit.
+ DCHECK_EQ(contribution_type, GridItemContributionType::kForFreeSpace);
+ for (NGGridSet* set : *sets_to_grow) {
+ set->SetItemIncurredIncrease(
+ GrowthPotentialForSet(*set, contribution_type));
+ }
return;
+ }
+ DCHECK_GT(extra_space, 0);
#if DCHECK_IS_ON()
if (IsDistributionForGrowthLimits(contribution_type))
DCHECK_EQ(sets_to_grow, sets_to_grow_beyond_limit);
#endif
- wtf_size_t total_track_count = 0;
+ auto ShareRatio =
+ [&is_equal_distribution](const NGGridSet& set) -> wtf_size_t {
+ if (is_equal_distribution)
+ return set.TrackCount();
+
+ // From https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items:
+ // If the sum of the flexible sizing functions of all flexible tracks
+ // spanned by the item is greater than zero, distributing space to such
+ // tracks according to the ratios of their flexible sizing functions
+ // rather than distributing space equally.
+ //
+ // Since we will use the flex factor to compute proportions out of a
+ // |LayoutUnit|, let the class round the floating point value.
+ DCHECK(set.TrackSize().HasFlexMaxTrackBreadth());
+ LayoutUnit flex_factor = LayoutUnit::FromDoubleRound(
+ set.TrackSize().MaxTrackBreadth().Flex() * set.TrackCount());
+ return flex_factor.RawValue();
+ };
+
+ wtf_size_t share_ratio_sum = 0;
+ wtf_size_t growable_track_count = 0;
for (NGGridSet* set : *sets_to_grow) {
set->SetItemIncurredIncrease(LayoutUnit());
+ share_ratio_sum += ShareRatio(*set);
- // From the first note in https://drafts.csswg.org/css-grid-1/#extra-space:
- // - If the affected size was a growth limit and the track is not marked
+ // From the first note in https://drafts.csswg.org/css-grid-2/#extra-space:
+ // If the affected size was a growth limit and the track is not marked
// "infinitely growable", then each item-incurred increase will be zero.
//
// When distributing space to growth limits, we need to increase each track
@@ -854,14 +1347,28 @@ void NGGridLayoutAlgorithm::DistributeExtraSpaceToSets(
//
// We can correctly resolve every scenario by doing a single sort of
// |sets_to_grow|, purposely ignoring the "infinitely growable" flag, then
- // filtering out which sets count toward the total track count at each step;
- // for base sizes this is not required, but if there are no tracks with
- // growth potential > 0, we can optimize by not sorting the sets.
- LayoutUnit growth_potential =
- GrowthPotentialForSet(*set, contribution_type);
- DCHECK(growth_potential >= 0 || growth_potential == kIndefiniteSize);
- if (growth_potential)
- total_track_count += set->TrackCount();
+ // filtering out sets that won't take a share of the extra space at each
+ // step; for base sizes this is not required, but if there are no tracks
+ // with growth potential > 0, we can optimize by not sorting the sets.
+ if (GrowthPotentialForSet(*set, contribution_type))
+ growable_track_count += set->TrackCount();
+ }
+
+ // If the sum of share ratios is zero, default to distribute equally.
+ if (!share_ratio_sum)
+ is_equal_distribution = true;
+
+ if (is_equal_distribution) {
+ // Distribute space equally among tracks with growth potential > 0.
+ share_ratio_sum = growable_track_count;
+ } else {
+ // Otherwise, distribute space according to their flex factors; compute
+ // |share_ratio_sum| now filtering out sets with no growth potential.
+ share_ratio_sum = 0;
+ for (NGGridSet* set : *sets_to_grow) {
+ if (GrowthPotentialForSet(*set, contribution_type))
+ share_ratio_sum += ShareRatio(*set);
+ }
}
// We will sort the tracks by growth potential in non-decreasing order to
@@ -872,7 +1379,8 @@ void NGGridLayoutAlgorithm::DistributeExtraSpaceToSets(
// will be that with the least growth potential. Otherwise, if tracks in such
// group does not reach their limit, every upcoming track with greater growth
// potential must be able to increase its size by the same amount.
- if (total_track_count || IsDistributionForGrowthLimits(contribution_type)) {
+ if (growable_track_count ||
+ IsDistributionForGrowthLimits(contribution_type)) {
auto CompareSetsByGrowthPotential = [contribution_type](NGGridSet* set_a,
NGGridSet* set_b) {
LayoutUnit growth_potential_a = GrowthPotentialForSet(
@@ -894,97 +1402,128 @@ void NGGridLayoutAlgorithm::DistributeExtraSpaceToSets(
CompareSetsByGrowthPotential);
}
- auto ClampSize = [](LayoutUnit& size, LayoutUnit limit) {
- size = (limit != kIndefiniteSize) ? std::min(size, limit) : size;
+ auto ExtraSpaceShare = [&extra_space, &ShareRatio, &share_ratio_sum](
+ const NGGridSet& set,
+ LayoutUnit growth_potential) -> LayoutUnit {
+ DCHECK(growth_potential >= 0 || growth_potential == kIndefiniteSize);
+
+ // If this set won't take a share of the extra space, e.g. it has zero
+ // growth potential or the remaining share ratio sum is zero, exit early so
+ // that this set's share ratio is filtered out of |share_ratio_sum|.
+ if (!share_ratio_sum || !growth_potential)
+ return LayoutUnit();
+
+ wtf_size_t set_share_ratio = ShareRatio(set);
+ DCHECK_LE(set_share_ratio, share_ratio_sum);
+
+ LayoutUnit extra_space_share =
+ (extra_space * set_share_ratio) / share_ratio_sum;
+ if (growth_potential != kIndefiniteSize)
+ extra_space_share = std::min(extra_space_share, growth_potential);
+ DCHECK_LE(extra_space_share, extra_space);
+
+ share_ratio_sum -= set_share_ratio;
+ extra_space -= extra_space_share;
+ return extra_space_share;
};
// Distribute space up to limits:
// - For base sizes, grow the base size up to the growth limit.
// - For growth limits, the only case where a growth limit should grow at
- // this step is when the set has already been marked "infinitely growable".
+ // this step is when its set has already been marked "infinitely growable".
// Increase the growth limit up to the 'fit-content' argument (if any); note
// that these arguments could prevent this step to fulfill the entirety of
// the extra space and further distribution would be needed.
- if (total_track_count) {
- for (NGGridSet* set : *sets_to_grow) {
- LayoutUnit growth_potential =
- GrowthPotentialForSet(*set, contribution_type);
-
- if (growth_potential) {
- wtf_size_t set_track_count = set->TrackCount();
- LayoutUnit extra_space_share =
- (extra_space * set_track_count) / total_track_count;
- DCHECK_GE(extra_space_share, 0);
-
- ClampSize(extra_space_share, growth_potential);
- set->SetItemIncurredIncrease(extra_space_share);
-
- total_track_count -= set_track_count;
- extra_space -= extra_space_share;
- DCHECK_GE(total_track_count, 0u);
- DCHECK_GE(extra_space, 0);
- }
- }
+ for (NGGridSet* set : *sets_to_grow) {
+ set->SetItemIncurredIncrease(
+ ExtraSpaceShare(*set, GrowthPotentialForSet(*set, contribution_type)));
}
// Distribute space beyond limits:
// - For base sizes, every affected track can grow indefinitely.
// - For growth limits, grow tracks up to their 'fit-content' argument.
if (sets_to_grow_beyond_limit && extra_space) {
- total_track_count = 0;
- for (NGGridSet* set : *sets_to_grow_beyond_limit)
- total_track_count += set->TrackCount();
-
+#if DCHECK_IS_ON()
+ // We expect |sets_to_grow_beyond_limit| to be ordered by growth potential
+ // for the following section of the algorithm to work.
+ //
+ // For base sizes, since going beyond limits should only happen after we
+ // grow every track up to their growth limits, it should be easy to see that
+ // every growth potential is now zero, so they're already ordered.
+ //
+ // Now let's consider growth limits: we forced the sets to be sorted by
+ // growth potential ignoring the "infinitely growable" flag, meaning that
+ // ultimately they will be sorted by remaining space to their 'fit-content'
+ // parameter (if it exists, infinite otherwise). If we ended up here, we
+ // must have filled the sets marked as "infinitely growable" up to their
+ // 'fit-content' parameter; therefore, if we only consider sets with
+ // remaining space to their 'fit-content' limit in the following
+ // distribution step, they should still be ordered.
+ LayoutUnit previous_growable_potential;
for (NGGridSet* set : *sets_to_grow_beyond_limit) {
- wtf_size_t set_track_count = set->TrackCount();
- LayoutUnit extra_space_share =
- (extra_space * set_track_count) / total_track_count;
- DCHECK_GE(extra_space_share, 0);
-
- // Ignore the "infinitely growable" flag and grow all affected tracks.
- if (IsDistributionForGrowthLimits(contribution_type)) {
- LayoutUnit growth_potential = GrowthPotentialForSet(
- *set, contribution_type, InfinitelyGrowableBehavior::kIgnore);
- ClampSize(extra_space_share, growth_potential);
+ LayoutUnit growth_potential = GrowthPotentialForSet(
+ *set, contribution_type, InfinitelyGrowableBehavior::kIgnore);
+ if (growth_potential) {
+ if (previous_growable_potential == kIndefiniteSize) {
+ DCHECK_EQ(growth_potential, kIndefiniteSize);
+ } else {
+ DCHECK(growth_potential >= previous_growable_potential ||
+ growth_potential == kIndefiniteSize);
+ }
+ previous_growable_potential = growth_potential;
}
- set->SetItemIncurredIncrease(set->ItemIncurredIncrease() +
- extra_space_share);
-
- total_track_count -= set_track_count;
- extra_space -= extra_space_share;
- DCHECK_GE(total_track_count, 0u);
- DCHECK_GE(extra_space, 0);
}
- }
+#endif
- // For each affected track, if the track's item-incurred increase is larger
- // than its planned increase, set the planned increase to that value.
- for (NGGridSet* set : *sets_to_grow) {
- set->SetPlannedIncrease(
- std::max(set->ItemIncurredIncrease(), set->PlannedIncrease()));
+ auto BeyondLimitsGrowthPotential =
+ [contribution_type](const NGGridSet& set) -> LayoutUnit {
+ // For growth limits, ignore the "infinitely growable" flag and grow all
+ // affected tracks up to their 'fit-content' argument (note that
+ // |GrowthPotentialForSet| already accounts for it).
+ return !IsDistributionForGrowthLimits(contribution_type)
+ ? kIndefiniteSize
+ : GrowthPotentialForSet(set, contribution_type,
+ InfinitelyGrowableBehavior::kIgnore);
+ };
+
+ share_ratio_sum = 0;
+ for (NGGridSet* set : *sets_to_grow_beyond_limit) {
+ if (BeyondLimitsGrowthPotential(*set))
+ share_ratio_sum += ShareRatio(*set);
+ }
+ for (NGGridSet* set : *sets_to_grow_beyond_limit) {
+ set->SetItemIncurredIncrease(
+ set->ItemIncurredIncrease() +
+ ExtraSpaceShare(*set, BeyondLimitsGrowthPotential(*set)));
+ }
}
}
+} // namespace
+
void NGGridLayoutAlgorithm::IncreaseTrackSizesToAccommodateGridItems(
- GridTrackSizingDirection track_direction,
- ReorderedGridItems::Iterator group_begin,
- ReorderedGridItems::Iterator group_end,
- NGGridItemContributionType contribution_type) {
- auto& track_collection = TrackCollection(track_direction);
- for (auto set_iterator = track_collection.GetSetIterator();
+ const GridGeometry& grid_geometry,
+ GridItems::Iterator group_begin,
+ GridItems::Iterator group_end,
+ const bool is_group_spanning_flex_track,
+ GridItemContributionType contribution_type,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const {
+ DCHECK(track_collection);
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+
+ for (auto set_iterator = track_collection->GetSetIterator();
!set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
set_iterator.CurrentSet().SetPlannedIncrease(LayoutUnit());
}
- NGGridSetVector sets_to_grow;
- NGGridSetVector sets_to_grow_beyond_limit;
+ GridSetVector sets_to_grow;
+ GridSetVector sets_to_grow_beyond_limit;
for (auto grid_item = group_begin; grid_item != group_end; ++grid_item) {
- // TODO(ethavar): Remove the |IsOutOfFlowPositioned| condition once the
- // out-of-flow items are stored separately.
- if (!grid_item->is_spanning_intrinsic_track ||
- grid_item->node.IsOutOfFlowPositioned()) {
- // Don't consider items not spanning intrinsic tracks in this step;
- // absolute positioned items don't affect track sizing.
+ // When the grid items of this group are not spanning a flexible track, we
+ // can skip the current item if it doesn't span an intrinsic track.
+ if (!grid_item->IsSpanningIntrinsicTrack(track_direction) &&
+ !is_group_spanning_flex_track) {
continue;
}
@@ -996,12 +1535,22 @@ void NGGridLayoutAlgorithm::IncreaseTrackSizesToAccommodateGridItems(
// know our block size.
LayoutUnit spanned_tracks_size =
GridGap(track_direction) * (grid_item->SpanSize(track_direction) - 1);
- for (auto set_iterator = GetSetIteratorForItem(*grid_item, track_direction);
+
+ for (auto set_iterator =
+ GetSetIteratorForItem(*grid_item, *track_collection);
!set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
NGGridSet& current_set = set_iterator.CurrentSet();
-
spanned_tracks_size +=
AffectedSizeForContribution(current_set, contribution_type);
+
+ // From https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items:
+ // Distributing space only to flexible tracks (i.e. treating all other
+ // tracks as having a fixed sizing function).
+ if (is_group_spanning_flex_track &&
+ !current_set.TrackSize().HasFlexMaxTrackBreadth()) {
+ continue;
+ }
+
if (IsContributionAppliedToSet(current_set, contribution_type)) {
sets_to_grow.push_back(&current_set);
if (ShouldUsedSizeGrowBeyondLimit(current_set, contribution_type))
@@ -1017,25 +1566,43 @@ void NGGridLayoutAlgorithm::IncreaseTrackSizesToAccommodateGridItems(
// remaining size contribution. For infinite growth limits, substitute with
// the track's base size. This is the space to distribute, floor it at zero.
LayoutUnit extra_space = ContributionSizeForGridItem(
- *grid_item, track_direction, contribution_type);
+ grid_geometry, *grid_item, track_direction, contribution_type);
extra_space -= spanned_tracks_size;
+ if (extra_space <= 0)
+ continue;
+
DistributeExtraSpaceToSets(
- extra_space.ClampNegativeToZero(), contribution_type, &sets_to_grow,
+ extra_space.ClampNegativeToZero(),
+ /* is_equal_distribution = */ !is_group_spanning_flex_track,
+ contribution_type, &sets_to_grow,
sets_to_grow_beyond_limit.IsEmpty() ? &sets_to_grow
: &sets_to_grow_beyond_limit);
+
+ // For each affected track, if the track's item-incurred increase is larger
+ // than its planned increase, set the planned increase to that value.
+ for (NGGridSet* set : sets_to_grow) {
+ set->SetPlannedIncrease(
+ std::max(set->ItemIncurredIncrease(), set->PlannedIncrease()));
+ }
}
- for (auto set_iterator = track_collection.GetSetIterator();
+ for (auto set_iterator = track_collection->GetSetIterator();
!set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
GrowAffectedSizeByPlannedIncrease(set_iterator.CurrentSet(),
contribution_type);
}
}
-// https://drafts.csswg.org/css-grid-1/#algo-content
+// https://drafts.csswg.org/css-grid-2/#algo-content
void NGGridLayoutAlgorithm::ResolveIntrinsicTrackSizes(
- GridTrackSizingDirection track_direction) {
+ const GridGeometry& grid_geometry,
+ NGGridLayoutAlgorithmTrackCollection* track_collection,
+ GridItems* grid_items) const {
+ DCHECK(track_collection && grid_items);
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+
// Reorder grid items to process them as follows:
// - First, consider items spanning a single non-flexible track.
// - Next, consider items with span size of 2 not spanning a flexible track.
@@ -1043,125 +1610,385 @@ void NGGridLayoutAlgorithm::ResolveIntrinsicTrackSizes(
// not spanning a flexible track have been considered.
// - Finally, consider all items spanning a flexible track.
auto CompareGridItemsForIntrinsicTrackResolution =
- [this, track_direction](wtf_size_t index_a, wtf_size_t index_b) -> bool {
- if (grid_items_[index_a].is_spanning_flex_track ||
- grid_items_[index_b].is_spanning_flex_track) {
+ [grid_items, track_direction](wtf_size_t a, wtf_size_t b) -> bool {
+ if (grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction) ||
+ grid_items->item_data[b].IsSpanningFlexibleTrack(track_direction)) {
// Ignore span sizes if one of the items spans a track with a flexible
// sizing function; items not spanning such tracks should come first.
- return !grid_items_[index_a].is_spanning_flex_track;
+ return !grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction);
}
- return grid_items_[index_a].SpanSize(track_direction) <
- grid_items_[index_b].SpanSize(track_direction);
+ return grid_items->item_data[a].SpanSize(track_direction) <
+ grid_items->item_data[b].SpanSize(track_direction);
};
- std::sort(reordered_item_indices_.begin(), reordered_item_indices_.end(),
+ std::sort(grid_items->reordered_item_indices.begin(),
+ grid_items->reordered_item_indices.end(),
CompareGridItemsForIntrinsicTrackResolution);
// First, process the items that don't span a flexible track.
- ReorderedGridItems grid_items = GetReorderedGridItems();
- ReorderedGridItems::Iterator current_group_begin = grid_items.begin();
-
- while (current_group_begin != grid_items.end() &&
- !current_group_begin->is_spanning_flex_track) {
+ auto current_group_begin = grid_items->begin();
+ while (current_group_begin != grid_items->end() &&
+ !current_group_begin->IsSpanningFlexibleTrack(track_direction)) {
// Each iteration considers all items with the same span size.
wtf_size_t current_group_span_size =
current_group_begin->SpanSize(track_direction);
- ReorderedGridItems::Iterator current_group_end = current_group_begin;
+
+ auto current_group_end = current_group_begin;
do {
- DCHECK(!current_group_end->is_spanning_flex_track);
+ DCHECK(!current_group_end->IsSpanningFlexibleTrack(track_direction));
++current_group_end;
- } while (current_group_end != grid_items.end() &&
- !current_group_end->is_spanning_flex_track &&
+ } while (current_group_end != grid_items->end() &&
+ !current_group_end->IsSpanningFlexibleTrack(track_direction) &&
current_group_end->SpanSize(track_direction) ==
current_group_span_size);
IncreaseTrackSizesToAccommodateGridItems(
- track_direction, current_group_begin, current_group_end,
- NGGridItemContributionType::kForIntrinsicMinimums);
+ grid_geometry, current_group_begin, current_group_end,
+ /* is_group_spanning_flex_track */ false,
+ GridItemContributionType::kForIntrinsicMinimums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, current_group_end,
+ /* is_group_spanning_flex_track */ false,
+ GridItemContributionType::kForContentBasedMinimums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, current_group_end,
+ /* is_group_spanning_flex_track */ false,
+ GridItemContributionType::kForMaxContentMinimums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, current_group_end,
+ /* is_group_spanning_flex_track */ false,
+ GridItemContributionType::kForIntrinsicMaximums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, current_group_end,
+ /* is_group_spanning_flex_track */ false,
+ GridItemContributionType::kForMaxContentMaximums, track_collection);
- // TODO(ethavar): Add remaining stages, mark infinitely growable sets...
+ // Move to the next group with greater span size.
current_group_begin = current_group_end;
}
- // TODO(ethavar): drafts.csswg.org/css-grid-1/#algo-spanning-flex-items
- // Repeat the previous step instead considering (together, rather than grouped
- // by span) all items that do span a track with a flexible sizing function.
-}
+ // From https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items:
+ // Increase sizes to accommodate spanning items crossing flexible tracks:
+ // Next, repeat the previous step instead considering (together, rather than
+ // grouped by span size) all items that do span a track with a flexible
+ // sizing function...
+#if DCHECK_IS_ON()
+ // Every grid item of the remaining group should span a flexible track.
+ for (auto it = current_group_begin; it != grid_items->end(); ++it)
+ DCHECK(it->IsSpanningFlexibleTrack(track_direction));
+#endif
+
+ // Now, process items spanning flexible tracks (if any).
+ if (current_group_begin != grid_items->end()) {
+ // We can safely skip contributions for maximums since a <flex> definition
+ // does not have an intrinsic max track sizing function.
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, grid_items->end(),
+ /* is_group_spanning_flex_track */ true,
+ GridItemContributionType::kForIntrinsicMinimums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, grid_items->end(),
+ /* is_group_spanning_flex_track */ true,
+ GridItemContributionType::kForContentBasedMinimums, track_collection);
+ IncreaseTrackSizesToAccommodateGridItems(
+ grid_geometry, current_group_begin, grid_items->end(),
+ /* is_group_spanning_flex_track */ true,
+ GridItemContributionType::kForMaxContentMinimums, track_collection);
+ }
-void NGGridLayoutAlgorithm::SetAutomaticTrackRepetitionsForTesting(
- wtf_size_t auto_column,
- wtf_size_t auto_row) {
- automatic_column_repetitions_ = auto_column;
- automatic_row_repetitions_ = auto_row;
+ // If any track still has an infinite growth limit (i.e. it had no items
+ // placed in it), set its growth limit to its base size.
+ for (auto set_iterator = track_collection->GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ auto& set = set_iterator.CurrentSet();
+ if (set.GrowthLimit() == kIndefiniteSize)
+ set.SetGrowthLimit(set.BaseSize());
+ }
}
-wtf_size_t NGGridLayoutAlgorithm::AutoRepeatCountForDirection(
- GridTrackSizingDirection track_direction) const {
- return (track_direction == kForColumns) ? automatic_column_repetitions_
- : automatic_row_repetitions_;
+// https://drafts.csswg.org/css-grid-2/#algo-grow-tracks
+void NGGridLayoutAlgorithm::MaximizeTracks(
+ SizingConstraint sizing_constraint,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const {
+ const LayoutUnit free_space =
+ DetermineFreeSpace(sizing_constraint, *track_collection);
+ if (!free_space)
+ return;
+
+ GridSetVector sets_to_grow;
+ sets_to_grow.ReserveInitialCapacity(track_collection->SetCount());
+ for (auto set_iterator = track_collection->GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ sets_to_grow.push_back(&set_iterator.CurrentSet());
+ }
+
+ DistributeExtraSpaceToSets(free_space, /* is_equal_distribution */ true,
+ GridItemContributionType::kForFreeSpace,
+ &sets_to_grow);
+
+ for (auto set_iterator = track_collection->GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ auto& set = set_iterator.CurrentSet();
+ set.SetBaseSize(set.BaseSize() + set.ItemIncurredIncrease());
+ }
+
+ // TODO(ethavar): If this would cause the grid to be larger than the grid
+ // container’s inner size as limited by its 'max-width/height', then redo this
+ // step, treating the available grid space as equal to the grid container’s
+ // inner size when it’s sized to its 'max-width/height'.
}
-GridTrackSizingDirection NGGridLayoutAlgorithm::AutoFlowDirection() const {
- return Style().IsGridAutoFlowDirectionRow() ? kForRows : kForColumns;
+// https://drafts.csswg.org/css-grid-2/#algo-stretch
+void NGGridLayoutAlgorithm::StretchAutoTracks(
+ SizingConstraint sizing_constraint,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const {
+ const GridTrackSizingDirection track_direction =
+ track_collection->Direction();
+
+ // Stretching auto tracks should only occur if we have a "stretch" (or
+ // default) content distribution.
+ const auto& content_alignment = (track_direction == kForColumns)
+ ? Style().JustifyContent()
+ : Style().AlignContent();
+ bool has_stretch_distribution =
+ content_alignment.Distribution() == ContentDistributionType::kStretch ||
+ (content_alignment.GetPosition() == ContentPosition::kNormal &&
+ content_alignment.Distribution() == ContentDistributionType::kDefault);
+ if (!has_stretch_distribution)
+ return;
+
+ LayoutUnit free_space =
+ DetermineFreeSpace(sizing_constraint, *track_collection);
+
+ // If the free space is indefinite, but the grid container has a definite
+ // min-width/height, use that size to calculate the free space for this step
+ // instead.
+ if (free_space == kIndefiniteSize) {
+ free_space = (track_direction == kForColumns)
+ ? grid_min_available_size_.inline_size
+ : grid_min_available_size_.block_size;
+ DCHECK_NE(free_space, kIndefiniteSize);
+ free_space -= ComputeTotalTrackSize(*track_collection,
+ GridGap(track_direction, free_space));
+ }
+
+ if (free_space <= 0)
+ return;
+
+ // Expand tracks that have an 'auto' max track sizing function by dividing any
+ // remaining positive, definite free space equally amongst them.
+ GridSetVector sets_to_grow;
+ for (auto set_iterator = track_collection->GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ auto& set = set_iterator.CurrentSet();
+ if (set.TrackSize().HasAutoMaxTrackBreadth())
+ sets_to_grow.push_back(&set);
+ }
+
+ if (sets_to_grow.IsEmpty())
+ return;
+
+ DistributeExtraSpaceToSets(free_space, /* is_equal_distribution */ true,
+ GridItemContributionType::kForFreeSpace,
+ &sets_to_grow, &sets_to_grow);
+
+ for (auto set_iterator = track_collection->GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ auto& set = set_iterator.CurrentSet();
+ set.SetBaseSize(set.BaseSize() + set.ItemIncurredIncrease());
+ }
}
-void NGGridLayoutAlgorithm::PlaceGridItems() {
- LayoutUnit column_grid_gap =
- GridGap(kForColumns, ChildAvailableSize().inline_size);
- LayoutUnit row_grid_gap = GridGap(kForRows, ChildAvailableSize().block_size);
- Vector<LayoutUnit> column_set_offsets =
- ComputeSetOffsets(kForColumns, column_grid_gap);
- Vector<LayoutUnit> row_set_offsets =
- ComputeSetOffsets(kForRows, row_grid_gap);
-
- // Store the total size of row definitions as the intrinsic block size.
- intrinsic_block_size_ =
- row_set_offsets.back() -
- (row_set_offsets.size() == 1 ? LayoutUnit() : row_grid_gap) +
- BorderScrollbarPadding().block_end;
+namespace {
+
+// Contains the information about where the grid tracks start, and the
+// gutter-size between them, taking into account the content alignment
+// properties.
+struct TrackAlignmentGeometry {
+ LayoutUnit start_offset;
+ LayoutUnit gutter_size;
+};
+
+TrackAlignmentGeometry ComputeTrackAlignmentGeometry(
+ const ComputedStyle& style,
+ const StyleContentAlignmentData& content_alignment,
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ LayoutUnit available_size,
+ LayoutUnit start_border_scrollbar_padding,
+ LayoutUnit grid_gap) {
+ // Determining the free-space is typically unnecessary, i.e. if there is
+ // default alignment. Only compute this on-demand.
+ auto FreeSpace = [&track_collection, &available_size,
+ &grid_gap]() -> LayoutUnit {
+ return available_size - ComputeTotalTrackSize(track_collection, grid_gap);
+ };
+
+ // The default alignment, perform adjustments on top of this.
+ TrackAlignmentGeometry geometry = {start_border_scrollbar_padding, grid_gap};
+
+ // If we have an indefinite |available_size| we can't perform any alignment,
+ // just return the default alignment.
+ if (available_size == kIndefiniteSize)
+ return geometry;
+
+ // TODO(ikilpatrick): 'space-between', 'space-around', and 'space-evenly' all
+ // divide by the free-space, and may have a non-zero modulo. Investigate if
+ // this should be distributed between the tracks.
+ switch (content_alignment.Distribution()) {
+ case ContentDistributionType::kSpaceBetween: {
+ // Default behavior for 'space-between' is to start align content.
+ const wtf_size_t track_count = track_collection.EndLineOfImplicitGrid();
+ const LayoutUnit free_space = FreeSpace();
+ if (track_count < 2 || free_space < LayoutUnit())
+ return geometry;
+
+ geometry.gutter_size += free_space / (track_count - 1);
+ return geometry;
+ }
+ case ContentDistributionType::kSpaceAround: {
+ // Default behaviour for 'space-around' is to center content.
+ const wtf_size_t track_count = track_collection.EndLineOfImplicitGrid();
+ const LayoutUnit free_space = FreeSpace();
+ if (track_count < 1 || free_space < LayoutUnit()) {
+ geometry.start_offset += free_space / 2;
+ return geometry;
+ }
+
+ LayoutUnit track_space = free_space / track_count;
+ geometry.start_offset += track_space / 2;
+ geometry.gutter_size += track_space;
+ return geometry;
+ }
+ case ContentDistributionType::kSpaceEvenly: {
+ // Default behaviour for 'space-evenly' is to center content.
+ const wtf_size_t track_count = track_collection.EndLineOfImplicitGrid();
+ const LayoutUnit free_space = FreeSpace();
+ if (free_space < LayoutUnit()) {
+ geometry.start_offset += free_space / 2;
+ return geometry;
+ }
- // If the row gap is percent or calc, it should be computed now that the
- // intrinsic size is known. However, the gap should not be added to the
- // intrinsic block size.
- if (IsRowGridGapUnresolvable(ChildAvailableSize().block_size)) {
- row_grid_gap = GridGap(kForRows, intrinsic_block_size_);
- row_set_offsets = ComputeSetOffsets(kForRows, row_grid_gap);
+ LayoutUnit track_space = free_space / (track_count + 1);
+ geometry.start_offset += track_space;
+ geometry.gutter_size += track_space;
+ return geometry;
+ }
+ case ContentDistributionType::kStretch:
+ case ContentDistributionType::kDefault:
+ break;
}
- for (GridItemData& grid_item : grid_items_) {
- wtf_size_t column_start_index = grid_item.columns_begin_set_index;
- wtf_size_t column_end_index = grid_item.columns_end_set_index;
- wtf_size_t row_start_index = grid_item.rows_begin_set_index;
- wtf_size_t row_end_index = grid_item.rows_end_set_index;
-
- DCHECK_LT(column_start_index, column_end_index);
- DCHECK_LT(row_start_index, row_end_index);
- DCHECK_LT(column_end_index, column_set_offsets.size());
- DCHECK_LT(row_end_index, row_set_offsets.size());
-
- LogicalOffset offset = {column_set_offsets[column_start_index],
- row_set_offsets[row_start_index]};
-
- // Inline and block sizes can be deduced from the delta between the inline
- // offset and the cumulated offset at the given item's end indices. The
- // cumulated offset's calculation includes the grid gap between and after
- // the spanned tracks. The latter is not needed, so it is subtracted.
- LogicalSize size = {
- column_set_offsets[column_end_index] - offset.inline_offset -
- column_grid_gap,
- row_set_offsets[row_end_index] - offset.block_offset - row_grid_gap};
- DCHECK_GE(size.inline_size, 0);
- DCHECK_GE(size.block_size, 0);
-
- PlaceGridItem(grid_item, offset, size);
+ switch (content_alignment.GetPosition()) {
+ case ContentPosition::kLeft: {
+ DCHECK(track_collection.IsForColumns());
+ if (IsLtr(style.Direction()))
+ return geometry;
+
+ geometry.start_offset += FreeSpace();
+ return geometry;
+ }
+ case ContentPosition::kRight: {
+ DCHECK(track_collection.IsForColumns());
+ if (IsRtl(style.Direction()))
+ return geometry;
+
+ geometry.start_offset += FreeSpace();
+ return geometry;
+ break;
+ }
+ case ContentPosition::kCenter: {
+ geometry.start_offset += FreeSpace() / 2;
+ return geometry;
+ }
+ case ContentPosition::kEnd:
+ case ContentPosition::kFlexEnd: {
+ geometry.start_offset += FreeSpace();
+ return geometry;
+ }
+ case ContentPosition::kStart:
+ case ContentPosition::kFlexStart:
+ case ContentPosition::kNormal:
+ case ContentPosition::kBaseline:
+ case ContentPosition::kLastBaseline:
+ return geometry;
}
+}
+
+} // namespace
- for (GridItemData& out_of_flow_item : out_of_flow_items_) {
- // TODO(ansollan): Look up offsets based on specified row/column for
- // absolutely-positioned items, as described in
- // https://drafts.csswg.org/css-grid-1/#abspos, and pass the correct static
- // positioned offset in.
- container_builder_.AddOutOfFlowChildCandidate(out_of_flow_item.node,
- LogicalOffset());
+// Calculates the offsets for all sets.
+NGGridLayoutAlgorithm::SetGeometry NGGridLayoutAlgorithm::ComputeSetGeometry(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const LayoutUnit available_size) const {
+ const TrackAlignmentGeometry track_alignment_geometry =
+ track_collection.IsForColumns()
+ ? ComputeTrackAlignmentGeometry(Style(), Style().JustifyContent(),
+ track_collection, available_size,
+ BorderScrollbarPadding().inline_start,
+ GridGap(kForColumns, available_size))
+ : ComputeTrackAlignmentGeometry(Style(), Style().AlignContent(),
+ track_collection, available_size,
+ BorderScrollbarPadding().block_start,
+ GridGap(kForRows, available_size));
+
+ LayoutUnit set_offset = track_alignment_geometry.start_offset;
+ Vector<SetOffsetData> sets;
+ sets.ReserveInitialCapacity(track_collection.SetCount() + 1);
+ sets.emplace_back(set_offset, /* last_indefinite_index */ kNotFound);
+
+ for (auto set_iterator = track_collection.GetSetIterator();
+ !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
+ const auto& set = set_iterator.CurrentSet();
+ set_offset += set.BaseSize() +
+ set.TrackCount() * track_alignment_geometry.gutter_size;
+ sets.emplace_back(set_offset, /* last_indefinite_index */ kNotFound);
+ }
+ return {sets, track_alignment_geometry.gutter_size};
+}
+
+LayoutUnit NGGridLayoutAlgorithm::GridGap(
+ GridTrackSizingDirection track_direction,
+ LayoutUnit available_size) const {
+ const base::Optional<Length>& gap =
+ track_direction == kForColumns ? Style().ColumnGap() : Style().RowGap();
+
+ if (!gap)
+ return LayoutUnit();
+
+ // TODO(ansollan): Update behavior based on outcome of working group
+ // discussions. See https://github.com/w3c/csswg-drafts/issues/5566.
+ if (available_size == kIndefiniteSize)
+ available_size = LayoutUnit();
+
+ return MinimumValueForLength(*gap, available_size);
+}
+
+// TODO(ikilpatrick): Determine if other uses of this method need to respect
+// |grid_min_available_size_| similar to |StretchAutoTracks|.
+LayoutUnit NGGridLayoutAlgorithm::DetermineFreeSpace(
+ SizingConstraint sizing_constraint,
+ const NGGridLayoutAlgorithmTrackCollection& track_collection) const {
+ switch (sizing_constraint) {
+ case SizingConstraint::kLayout: {
+ const GridTrackSizingDirection track_direction =
+ track_collection.Direction();
+ LayoutUnit free_space = (track_direction == kForColumns)
+ ? grid_available_size_.inline_size
+ : grid_available_size_.block_size;
+ if (free_space != kIndefiniteSize) {
+ free_space -= ComputeTotalTrackSize(
+ track_collection, GridGap(track_direction, free_space));
+ // If tracks consume more space than the grid container has available,
+ // clamp the free space to zero as there's no more room left to grow.
+ free_space = free_space.ClampNegativeToZero();
+ }
+ return free_space;
+ }
+ case SizingConstraint::kMaxContent:
+ // If sizing under a max-content constraint, the free space is infinite.
+ return kIndefiniteSize;
+ case SizingConstraint::kMinContent:
+ // If sizing under a min-content constraint, the free space is zero.
+ return LayoutUnit();
}
}
@@ -1177,97 +2004,301 @@ LayoutUnit AlignmentOffset(LayoutUnit container_size,
case AxisEdge::kStart:
return margin_start;
case AxisEdge::kCenter:
- return (container_size - size - margin_start - margin_end) / 2;
+ return (container_size - size + margin_start - margin_end) / 2;
case AxisEdge::kEnd:
return container_size - margin_end - size;
case AxisEdge::kBaseline:
- // TODO(ikilpatrick): Implement baseline alignment.
+ // TODO(kschmi): Implement baseline alignment.
return margin_start;
}
NOTREACHED();
return LayoutUnit();
}
+void AlignmentOffsetForOutOfFlow(
+ const AxisEdge inline_axis_edge,
+ const AxisEdge block_axis_edge,
+ const LogicalSize container_size,
+ NGLogicalStaticPosition::InlineEdge* inline_edge,
+ NGLogicalStaticPosition::BlockEdge* block_edge,
+ LogicalOffset* offset) {
+ using InlineEdge = NGLogicalStaticPosition::InlineEdge;
+ using BlockEdge = NGLogicalStaticPosition::BlockEdge;
+
+ switch (inline_axis_edge) {
+ case AxisEdge::kStart:
+ *inline_edge = InlineEdge::kInlineStart;
+ break;
+ case AxisEdge::kCenter:
+ *inline_edge = InlineEdge::kInlineCenter;
+ offset->inline_offset += container_size.inline_size / 2;
+ break;
+ default:
+ *inline_edge = InlineEdge::kInlineEnd;
+ offset->inline_offset += container_size.inline_size;
+ break;
+ }
+
+ switch (block_axis_edge) {
+ case AxisEdge::kStart:
+ *block_edge = BlockEdge::kBlockStart;
+ break;
+ case AxisEdge::kCenter:
+ *block_edge = BlockEdge::kBlockCenter;
+ offset->block_offset += container_size.block_size / 2;
+ break;
+ default:
+ *block_edge = BlockEdge::kBlockEnd;
+ offset->block_offset += container_size.block_size;
+ break;
+ }
+}
+
} // namespace
-void NGGridLayoutAlgorithm::PlaceGridItem(const GridItemData& grid_item,
- LogicalOffset offset,
- LogicalSize size) {
- const auto& item_style = grid_item.node.Style();
+const NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpace(
+ const GridGeometry& grid_geometry,
+ const GridItemData& grid_item,
+ NGCacheSlot cache_slot,
+ LogicalRect* rect) const {
+ DCHECK(rect);
+
+ ComputeOffsetAndSize(grid_item, grid_geometry.column_geometry, kForColumns,
+ kIndefiniteSize, &rect->offset.inline_offset,
+ &rect->size.inline_size);
+ ComputeOffsetAndSize(grid_item, grid_geometry.row_geometry, kForRows,
+ kIndefiniteSize, &rect->offset.block_offset,
+ &rect->size.block_size);
+
NGConstraintSpaceBuilder builder(ConstraintSpace(),
- item_style.GetWritingDirection(),
+ grid_item.node.Style().GetWritingDirection(),
/* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), grid_item.node, &builder);
+ builder.SetCacheSlot(cache_slot);
builder.SetIsPaintedAtomically(true);
- builder.SetAvailableSize(size);
- builder.SetPercentageResolutionSize(size);
-
- // TODO(ikilpatrick): We need a slightly different constraint space API now.
- // Instead of a "shrink-to-fit" bit, we should have a "is-stretched" bit to
- // indicate if 'auto' should stretch to fill the available space. This should
- // apply to both the inline, and block axis. E.g.
- // IsInlineSizeStretched / IsBlockSizeStretched or similar.
- builder.SetIsFixedBlockSize(item_style.LogicalHeight().IsAuto() &&
- grid_item.is_block_axis_stretched);
- builder.SetIsShrinkToFit(item_style.LogicalWidth().IsAuto() &&
- !grid_item.is_inline_axis_stretched);
-
- scoped_refptr<const NGLayoutResult> result =
- grid_item.node.Layout(builder.ToConstraintSpace());
- const auto& physical_fragment = result->PhysicalFragment();
-
- // Apply the grid-item's alignment (if any).
- NGFragment fragment(ConstraintSpace().GetWritingDirection(),
- physical_fragment);
- offset += LogicalOffset(
- AlignmentOffset(size.inline_size, fragment.InlineSize(),
- grid_item.margins.inline_start,
- grid_item.margins.inline_end,
- grid_item.inline_axis_alignment),
- AlignmentOffset(
- size.block_size, fragment.BlockSize(), grid_item.margins.block_start,
- grid_item.margins.block_end, grid_item.block_axis_alignment));
-
- container_builder_.AddChild(physical_fragment, offset);
+ builder.SetAvailableSize(rect->size);
+ builder.SetPercentageResolutionSize(rect->size);
+ builder.SetStretchInlineSizeIfAuto(grid_item.is_inline_axis_stretched &&
+ rect->size.inline_size != kIndefiniteSize);
+ builder.SetStretchBlockSizeIfAuto(grid_item.is_block_axis_stretched &&
+ rect->size.block_size != kIndefiniteSize);
+ return builder.ToConstraintSpace();
}
-LayoutUnit NGGridLayoutAlgorithm::GridGap(
- GridTrackSizingDirection track_direction,
- LayoutUnit available_size) {
- const base::Optional<Length>& gap =
- track_direction == kForColumns ? Style().ColumnGap() : Style().RowGap();
+void NGGridLayoutAlgorithm::PlaceGridItems(const GridItems& grid_items,
+ const GridGeometry& grid_geometry,
+ LayoutUnit block_size) {
+ // |grid_items| is in DOM order to ensure proper painting order, but
+ // determining the grid's baseline is prioritized based on grid order. The
+ // baseline of the grid is determined by the first grid item with baseline
+ // alignment in the first row. If no items have baseline alignment, fall back
+ // to the first item in row-major order.
+ struct PositionAndBaseline {
+ PositionAndBaseline(const GridArea& resolved_position, LayoutUnit baseline)
+ : resolved_position(resolved_position), baseline(baseline) {}
+ GridArea resolved_position;
+ LayoutUnit baseline;
+ };
+ base::Optional<PositionAndBaseline> alignment_baseline;
+ base::Optional<PositionAndBaseline> fallback_baseline;
+
+ for (const auto& grid_item : grid_items.item_data) {
+ DCHECK(grid_item.column_set_indices.has_value());
+ DCHECK(grid_item.row_set_indices.has_value());
+
+ LogicalRect containing_grid_area;
+ const NGConstraintSpace space = CreateConstraintSpace(
+ grid_geometry, grid_item, NGCacheSlot::kLayout, &containing_grid_area);
+
+ scoped_refptr<const NGLayoutResult> result = grid_item.node.Layout(space);
+ const auto& physical_fragment =
+ To<NGPhysicalBoxFragment>(result->PhysicalFragment());
+
+ // Apply the grid-item's alignment (if any).
+ NGBoxFragment fragment(ConstraintSpace().GetWritingDirection(),
+ physical_fragment);
+ containing_grid_area.offset += LogicalOffset(
+ AlignmentOffset(containing_grid_area.size.inline_size,
+ fragment.InlineSize(), grid_item.margins.inline_start,
+ grid_item.margins.inline_end,
+ grid_item.inline_axis_alignment),
+ AlignmentOffset(containing_grid_area.size.block_size,
+ fragment.BlockSize(), grid_item.margins.block_start,
+ grid_item.margins.block_end,
+ grid_item.block_axis_alignment));
+
+ container_builder_.AddChild(physical_fragment, containing_grid_area.offset);
+
+ // Compares GridArea objects in row-major grid order for baseline
+ // precedence. Returns 'true' if |a| < |b| and 'false' otherwise.
+ auto IsBeforeInGridOrder = [&](const GridArea& a,
+ const GridArea& b) -> bool {
+ return (a.rows < b.rows) || (a.rows == b.rows && (a.columns < b.columns));
+ };
- // TODO(ansollan): Update behavior based on outcome of working group
- // discussions. See https://github.com/w3c/csswg-drafts/issues/5566.
- if (!gap || IsRowGridGapUnresolvable(available_size))
- return LayoutUnit();
- return MinimumValueForLength(*gap, available_size);
+ LayoutUnit baseline = fragment.BaselineOrSynthesize() +
+ containing_grid_area.offset.block_offset;
+ if (grid_item.block_axis_alignment == AxisEdge::kBaseline) {
+ if (!alignment_baseline ||
+ IsBeforeInGridOrder(grid_item.resolved_position,
+ alignment_baseline->resolved_position)) {
+ alignment_baseline.emplace(grid_item.resolved_position, baseline);
+ }
+ } else if (!fallback_baseline ||
+ IsBeforeInGridOrder(grid_item.resolved_position,
+ fallback_baseline->resolved_position)) {
+ fallback_baseline.emplace(grid_item.resolved_position, baseline);
+ }
+ }
+
+ // Propagate the baseline from the appropriate child.
+ // TODO(kschmi): Synthesize baseline from alignment context if no grid items.
+ if (!grid_items.IsEmpty()) {
+ if (alignment_baseline &&
+ (!fallback_baseline || alignment_baseline->resolved_position.rows <=
+ fallback_baseline->resolved_position.rows)) {
+ container_builder_.SetBaseline(alignment_baseline->baseline);
+ } else {
+ DCHECK(fallback_baseline);
+ container_builder_.SetBaseline(fallback_baseline->baseline);
+ }
+ }
}
-Vector<LayoutUnit> NGGridLayoutAlgorithm::ComputeSetOffsets(
- GridTrackSizingDirection track_direction,
- LayoutUnit grid_gap) {
- LayoutUnit set_offset = track_direction == kForColumns
- ? BorderScrollbarPadding().inline_start
- : BorderScrollbarPadding().block_start;
- Vector<LayoutUnit> set_offsets = {set_offset};
- auto& track_collection = (track_direction == kForColumns)
- ? algorithm_column_track_collection_
- : algorithm_row_track_collection_;
- set_offsets.ReserveCapacity(track_collection.SetCount() + 1);
- for (auto set_iterator = track_collection.GetSetIterator();
- !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) {
- const auto& set = set_iterator.CurrentSet();
- set_offset += set.BaseSize() + set.TrackCount() * grid_gap;
- set_offsets.push_back(set_offset);
+void NGGridLayoutAlgorithm::PlaceOutOfFlowItems(
+ const Vector<GridItemData>& out_of_flow_items,
+ const GridGeometry& grid_geometry,
+ LayoutUnit block_size) {
+ for (const GridItemData& out_of_flow_item : out_of_flow_items) {
+ DCHECK(out_of_flow_item.column_set_indices.has_value());
+ DCHECK(out_of_flow_item.row_set_indices.has_value());
+
+ LogicalRect containing_block_rect = ComputeContainingGridAreaRect(
+ grid_geometry, out_of_flow_item, block_size);
+ NGLogicalStaticPosition::InlineEdge inline_edge;
+ NGLogicalStaticPosition::BlockEdge block_edge;
+ LogicalOffset child_offset = containing_block_rect.offset;
+ AlignmentOffsetForOutOfFlow(out_of_flow_item.inline_axis_alignment,
+ out_of_flow_item.block_axis_alignment,
+ containing_block_rect.size, &inline_edge,
+ &block_edge, &child_offset);
+
+ container_builder_.AddOutOfFlowChildCandidate(
+ out_of_flow_item.node, child_offset, inline_edge, block_edge,
+ /* needs_block_offset_adjustment */ false, containing_block_rect);
+ }
+}
+
+void NGGridLayoutAlgorithm::PlaceOutOfFlowDescendants(
+ const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+ const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+ const GridGeometry& grid_geometry,
+ const NGGridPlacement& grid_placement,
+ LayoutUnit block_size) {
+ // At this point, we'll have a list of OOF candidates from any inflow children
+ // of the grid (which have been propagated up). These might have an assigned
+ // 'grid-area', so we need to assign their correct 'containing block rect'.
+ Vector<NGLogicalOutOfFlowPositionedNode>* out_of_flow_descendants =
+ container_builder_.MutableOutOfFlowPositionedCandidates();
+ DCHECK(out_of_flow_descendants);
+
+ for (auto& out_of_flow_descendant : *out_of_flow_descendants) {
+ // TODO(ansollan): We don't need all parameters from |GridItemData| for out
+ // of flow items. Implement a reduced version in |MeasureGridItem| or only
+ // fill what is needed here.
+ GridItemData out_of_flow_item =
+ MeasureGridItem(out_of_flow_descendant.node);
+
+ out_of_flow_item.SetIndices(column_track_collection, &grid_placement);
+ out_of_flow_item.SetIndices(row_track_collection, &grid_placement);
+
+ out_of_flow_descendant.containing_block_rect =
+ ComputeContainingGridAreaRect(grid_geometry, out_of_flow_item,
+ block_size);
}
- return set_offsets;
}
-bool NGGridLayoutAlgorithm::IsRowGridGapUnresolvable(
- LayoutUnit available_size) {
- const base::Optional<Length>& row_gap = Style().RowGap();
- return row_gap && row_gap->IsPercentOrCalc() &&
- available_size == kIndefiniteSize;
+LogicalRect NGGridLayoutAlgorithm::ComputeContainingGridAreaRect(
+ const GridGeometry& grid_geometry,
+ const GridItemData& item,
+ LayoutUnit block_size) {
+ LogicalRect rect;
+ ComputeOffsetAndSize(item, grid_geometry.column_geometry, kForColumns,
+ block_size, &rect.offset.inline_offset,
+ &rect.size.inline_size);
+ ComputeOffsetAndSize(item, grid_geometry.row_geometry, kForRows, block_size,
+ &rect.offset.block_offset, &rect.size.block_size);
+ return rect;
+}
+
+void NGGridLayoutAlgorithm::ComputeOffsetAndSize(
+ const GridItemData& item,
+ const SetGeometry& set_geometry,
+ const GridTrackSizingDirection track_direction,
+ LayoutUnit block_size,
+ LayoutUnit* start_offset,
+ LayoutUnit* size) const {
+ wtf_size_t start_index, end_index;
+ LayoutUnit border;
+ // The default padding box value of the |size| will only be used in out of
+ // flow items in which both the start line and end line are defined as 'auto'.
+ if (track_direction == kForColumns) {
+ start_index = item.column_set_indices->begin;
+ end_index = item.column_set_indices->end;
+ border = container_builder_.Borders().inline_start;
+ *size =
+ border_box_size_.inline_size - container_builder_.Borders().InlineSum();
+ } else {
+ start_index = item.row_set_indices->begin;
+ end_index = item.row_set_indices->end;
+ border = container_builder_.Borders().block_start;
+ *size = border_box_size_.block_size == kIndefiniteSize
+ ? block_size
+ : border_box_size_.block_size;
+ *size -= container_builder_.Borders().BlockSum();
+ }
+ *start_offset = border;
+ LayoutUnit end_offset = border;
+ // If the start line is defined, the size is calculated by subtracting the
+ // offset at start index. Additionally, the start border is removed from the
+ // cumulated offset because it was already accounted for in the previous value
+ // of the size.
+ if (start_index != kNotFound) {
+ *start_offset = set_geometry.sets[start_index].offset;
+ *size -= (*start_offset - end_offset);
+ }
+ // If the end line is defined, the offset (which can be the offset at the
+ // start index or the start border) and the added grid gap after the spanned
+ // tracks are subtracted from the offset at the end index.
+ if (end_index != kNotFound) {
+ // If we are measuring a grid-item we might not yet have determined the
+ // final (used) sizes for all of out sets. |last_indefinite_index| is used
+ // to track what sets have indefinite/definite sizes.
+ //
+ // |last_indefinite_index| is the last set seen which was indefinite. If
+ // our |start_index| is greater than this, all the sets between this and
+ // our |end_index| are definite.
+ const wtf_size_t last_indefinite_index =
+ set_geometry.sets[end_index].last_indefinite_index;
+ end_offset = set_geometry.sets[end_index].offset;
+ if (last_indefinite_index == kNotFound ||
+ start_index > last_indefinite_index) {
+ *size = end_offset - *start_offset - set_geometry.gutter_size;
+ } else {
+ *size = kIndefiniteSize;
+ }
+ }
+
+#if DCHECK_IS_ON()
+ if (start_index != kNotFound && end_index != kNotFound) {
+ DCHECK_LT(start_index, end_index);
+ DCHECK_LT(end_index, set_geometry.sets.size());
+ DCHECK(*size >= 0 || *size == kIndefiniteSize);
+ } else {
+ // Only out of flow items can have an undefined ('auto') value for the start
+ // and/or end |set_indices|.
+ DCHECK_EQ(item.item_type, ItemType::kOutOfFlow);
+ }
+#endif
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
index df08a06fff1..155c823f515 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -14,28 +14,36 @@
namespace blink {
-// This enum corresponds to each step used to accommodate grid items across
-// intrinsic tracks according to their min and max track sizing functions, as
-// defined in https://drafts.csswg.org/css-grid-1/#algo-spanning-items.
-enum class NGGridItemContributionType {
- kForIntrinsicMinimums,
- kForContentBasedMinimums,
- kForMaxContentMinimums,
- kForIntrinsicMaximums,
- kForMaxContentMaximums
-};
-
-enum class AutoPlacementType { kNotNeeded, kMajor, kMinor, kBoth };
+class NGGridPlacement;
class CORE_EXPORT NGGridLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
NGBoxFragmentBuilder,
NGBlockBreakToken> {
public:
+ enum class AutoPlacementType { kNotNeeded, kMajor, kMinor, kBoth };
enum class AxisEdge { kStart, kCenter, kEnd, kBaseline };
+ enum class ItemType { kInGridFlow, kOutOfFlow };
+
+ // This enum corresponds to each step used to accommodate grid items across
+ // intrinsic tracks according to their min and max track sizing functions, as
+ // defined in https://drafts.csswg.org/css-grid-2/#algo-spanning-items.
+ enum class GridItemContributionType {
+ kForIntrinsicMinimums,
+ kForContentBasedMinimums,
+ kForMaxContentMinimums,
+ kForIntrinsicMaximums,
+ kForMaxContentMaximums,
+ kForFreeSpace
+ };
- struct GridItemData {
- explicit GridItemData(const NGBlockNode node);
+ struct ItemSetIndices {
+ wtf_size_t begin = kNotFound;
+ wtf_size_t end = kNotFound;
+ };
+
+ struct CORE_EXPORT GridItemData {
+ explicit GridItemData(const NGBlockNode node) : node(node) {}
AutoPlacementType AutoPlacement(
GridTrackSizingDirection flow_direction) const;
@@ -47,183 +55,289 @@ class CORE_EXPORT NGGridLayoutAlgorithm
wtf_size_t EndLine(GridTrackSizingDirection track_direction) const;
wtf_size_t SpanSize(GridTrackSizingDirection track_direction) const;
+ const TrackSpanProperties& GetTrackSpanProperties(
+ GridTrackSizingDirection track_direction) const;
+ void SetTrackSpanProperty(TrackSpanProperties::PropertyId property,
+ GridTrackSizingDirection track_direction);
+
+ bool IsSpanningFlexibleTrack(
+ GridTrackSizingDirection track_direction) const;
+ bool IsSpanningIntrinsicTrack(
+ GridTrackSizingDirection track_direction) const;
+
+ // For this item and track direction, computes and stores the pair of
+ // indices "begin" and "end" such that the item spans every set from the
+ // respective collection's |sets_| with an index in the range [begin, end).
+ // |grid_placement| is used to resolve the grid lines of out of flow items
+ // and it has a default nullptr value for grid items.
+ ItemSetIndices SetIndices(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const NGGridPlacement* grid_placement = nullptr);
+
const NGBlockNode node;
GridArea resolved_position;
NGBoxStrut margins;
- LayoutUnit inline_size;
- MinMaxSizes min_max_sizes;
-
- // These fields are used to determine the sets this item spans in the
- // respective track collection; see |CacheItemSetIndices|.
- wtf_size_t columns_begin_set_index;
- wtf_size_t columns_end_set_index;
- wtf_size_t rows_begin_set_index;
- wtf_size_t rows_end_set_index;
AxisEdge inline_axis_alignment;
AxisEdge block_axis_alignment;
+ ItemType item_type;
+
bool is_inline_axis_stretched;
bool is_block_axis_stretched;
- bool is_spanning_flex_track : 1;
- bool is_spanning_intrinsic_track : 1;
- };
-
- explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+ TrackSpanProperties column_span_properties;
+ TrackSpanProperties row_span_properties;
- scoped_refptr<const NGLayoutResult> Layout() override;
-
- MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
-
- const NGGridLayoutAlgorithmTrackCollection& ColumnTrackCollection() const;
- const NGGridLayoutAlgorithmTrackCollection& RowTrackCollection() const;
-
- private:
- using NGGridSetVector = Vector<NGGridSet*, 16>;
-
- friend class NGGridLayoutAlgorithmTest;
-
- enum class GridLayoutAlgorithmState {
- kMeasuringItems,
- kResolvingInlineSize,
- kResolvingBlockSize,
- kPlacingGridItems,
- kCompletedLayout
+ // These fields are used to determine the sets this item spans in the
+ // respective track collection; see |SetIndices|. We use optional since some
+ // scenarios don't require to compute the indices at all.
+ base::Optional<ItemSetIndices> column_set_indices;
+ base::Optional<ItemSetIndices> row_set_indices;
};
- class ReorderedGridItems {
- public:
+ struct CORE_EXPORT GridItems {
class Iterator
: public std::iterator<std::input_iterator_tag, GridItemData> {
public:
- Iterator(Vector<wtf_size_t>::const_iterator current_index,
- Vector<GridItemData>* grid_items);
-
- bool operator!=(const Iterator& other) const;
- GridItemData* operator->();
- GridItemData& operator*();
- Iterator& operator++();
+ Iterator(Vector<GridItemData>* item_data,
+ Vector<wtf_size_t>::const_iterator current_index)
+ : item_data_(item_data), current_index_(current_index) {
+ DCHECK(item_data_);
+ }
+
+ bool operator!=(const Iterator& other) const {
+ return current_index_ != other.current_index_ ||
+ item_data_ != other.item_data_;
+ }
+
+ Iterator& operator++() {
+ ++current_index_;
+ return *this;
+ }
+
+ GridItemData* operator->() {
+ DCHECK(current_index_ && *current_index_ < item_data_->size());
+ return &(item_data_->at(*current_index_));
+ }
+
+ GridItemData& operator*() {
+ DCHECK(current_index_ && *current_index_ < item_data_->size());
+ return item_data_->at(*current_index_);
+ }
private:
+ Vector<GridItemData>* item_data_;
Vector<wtf_size_t>::const_iterator current_index_;
- Vector<GridItemData>* grid_items_;
};
- ReorderedGridItems(const Vector<wtf_size_t>& reordered_item_indices,
- Vector<GridItemData>& grid_items);
Iterator begin();
Iterator end();
- private:
- const Vector<wtf_size_t>& reordered_item_indices_;
- Vector<GridItemData>& grid_items_;
+ void Append(const GridItemData& new_item_data);
+
+ bool IsEmpty() const;
+
+ // Grid items are appended to |item_data_| in the same order provided by
+ // |NGGridChildIterator|, which iterates over its children in order-modified
+ // document order; we want to keep such order since auto-placement and
+ // painting order rely on it later in the algorithm.
+ Vector<GridItemData> item_data;
+ Vector<wtf_size_t> reordered_item_indices;
};
- ReorderedGridItems GetReorderedGridItems();
- NGGridLayoutAlgorithmTrackCollection& TrackCollection(
- GridTrackSizingDirection track_direction);
+ // See |SetGeometry|.
+ struct SetOffsetData {
+ SetOffsetData(LayoutUnit offset, wtf_size_t last_indefinite_index)
+ : offset(offset), last_indefinite_index(last_indefinite_index) {}
+ LayoutUnit offset;
+ wtf_size_t last_indefinite_index;
+ };
+
+ // Represents the offsets for the sets, and the gutter-size.
+ //
+ // Initially we only know some of the set sizes - others will be indefinite.
+ // To represent this we store both the offset for the set, and the last index
+ // where there was an indefinite set (or kNotFound if everything so far has
+ // been definite). This allows us to get the appropriate size if a grid item
+ // spans only fixed tracks, but will allow us to return an indefinite size if
+ // it spans any indefinite set.
+ //
+ // As an example:
+ // grid-template-rows: auto auto 100px 100px auto 100px;
+ //
+ // Results in:
+ // | auto | auto | 100 | 100 | auto | 100 |
+ // [{0, kNotFound}, {0, 0}, {0, 1}, {100, 1}, {200, 1}, {200, 4}, {300, 4}]
+ //
+ // Various queries (start/end refer to the grid lines):
+ // start: 0, end: 1 -> indefinite as:
+ // "start <= sets[end].last_indefinite_index"
+ // start: 1, end: 3 -> indefinite as:
+ // "start <= sets[end].last_indefinite_index"
+ // start: 2, end: 4 -> 200px
+ // start: 5, end: 6 -> 100px
+ // start: 3, end: 5 -> indefinite as:
+ // "start <= sets[end].last_indefinite_index"
+ struct SetGeometry {
+ Vector<SetOffsetData> sets;
+ LayoutUnit gutter_size;
+ };
+
+ // Typically we pass around both the column, and row geometry together.
+ struct GridGeometry {
+ SetGeometry column_geometry;
+ SetGeometry row_geometry;
+ };
+
+ explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+
+ scoped_refptr<const NGLayoutResult> Layout() override;
+ MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
+
+ private:
+ friend class NGGridLayoutAlgorithmTest;
- // Returns an iterator for every |NGGridSet| contained within an item's span
- // in the relevant track collection.
- NGGridLayoutAlgorithmTrackCollection::SetIterator GetSetIteratorForItem(
- const GridItemData& item,
- GridTrackSizingDirection track_direction);
+ enum class SizingConstraint { kLayout, kMinContent, kMaxContent };
// Returns the size that a grid item will distribute across the tracks with an
// intrinsic sizing function it spans in the relevant track direction.
LayoutUnit ContributionSizeForGridItem(
+ const GridGeometry& grid_geometry,
const GridItemData& grid_item,
GridTrackSizingDirection track_direction,
- NGGridItemContributionType contribution_type) const;
-
- void ConstructAndAppendGridItems();
- GridItemData MeasureGridItem(const NGBlockNode node);
- NGConstraintSpace BuildSpaceForGridItem(const NGBlockNode node) const;
-
- // Sets the specified tracks for row and column track lists.
- void SetSpecifiedTracks();
- // Determines the explicit column and row track starts.
- void DetermineExplicitTrackStarts();
-
- // For every item and track direction, computes and stores the pair of indices
- // "begin" and "end" such that the item spans every set from the respective
- // collection's |sets_| with an index in the range [begin, end).
- void CacheItemSetIndices();
- // For every grid item, determines if it spans a track with an intrinsic or
- // flexible sizing function and caches the answer in its |GridItemData|.
- void DetermineGridItemsSpanningIntrinsicOrFlexTracks(
- GridTrackSizingDirection track_direction);
+ GridItemContributionType contribution_type) const;
+
+ wtf_size_t ComputeAutomaticRepetitions(
+ GridTrackSizingDirection track_direction) const;
+
+ void ConstructAndAppendGridItems(
+ GridItems* grid_items,
+ Vector<GridItemData>* out_of_flow_items = nullptr) const;
+ GridItemData MeasureGridItem(const NGBlockNode node) const;
+
+ void BuildBlockTrackCollections(
+ GridItems* grid_items,
+ NGGridBlockTrackCollection* column_track_collection,
+ NGGridBlockTrackCollection* row_track_collection,
+ NGGridPlacement* grid_placement) const;
+
+ void BuildAlgorithmTrackCollections(
+ GridItems* grid_items,
+ NGGridLayoutAlgorithmTrackCollection* column_track_collection,
+ NGGridLayoutAlgorithmTrackCollection* row_track_collection,
+ NGGridPlacement* grid_placement) const;
+
+ // Ensure coverage in block collection after grid items have been placed.
+ void EnsureTrackCoverageForGridItems(
+ const GridItems& grid_items,
+ NGGridBlockTrackCollection* track_collection) const;
+
+ // For every grid item, caches properties of the track sizing functions it
+ // spans (i.e. whether an item spans intrinsic or flexible tracks).
+ void CacheGridItemsTrackSpanProperties(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ GridItems* grid_items) const;
+
+ // Initializes the given track collection, and returns the base set geometry.
+ SetGeometry InitializeTrackSizes(
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const;
// Calculates from the min and max track sizing functions the used track size.
- void ComputeUsedTrackSizes(GridTrackSizingDirection track_direction);
+ void ComputeUsedTrackSizes(
+ SizingConstraint sizing_constraint,
+ const GridGeometry& grid_geometry,
+ NGGridLayoutAlgorithmTrackCollection* track_collection,
+ GridItems* grid_items) const;
// These methods implement the steps of the algorithm for intrinsic track size
- // resolution defined in https://drafts.csswg.org/css-grid-1/#algo-content.
- void ResolveIntrinsicTrackSizes(GridTrackSizingDirection track_direction);
+ // resolution defined in https://drafts.csswg.org/css-grid-2/#algo-content.
+ void ResolveIntrinsicTrackSizes(
+ const GridGeometry& grid_geometry,
+ NGGridLayoutAlgorithmTrackCollection* track_collection,
+ GridItems* grid_items) const;
+
void IncreaseTrackSizesToAccommodateGridItems(
- GridTrackSizingDirection track_direction,
- ReorderedGridItems::Iterator group_begin,
- ReorderedGridItems::Iterator group_end,
- NGGridItemContributionType contribution_type);
- void DistributeExtraSpaceToSets(LayoutUnit extra_space,
- NGGridItemContributionType contribution_type,
- NGGridSetVector* sets_to_grow,
- NGGridSetVector* sets_to_grow_beyond_limit);
-
- // Allows a test to set the value for automatic track repetition.
- void SetAutomaticTrackRepetitionsForTesting(wtf_size_t auto_column,
- wtf_size_t auto_row);
- wtf_size_t AutoRepeatCountForDirection(
- GridTrackSizingDirection track_direction) const;
+ const GridGeometry& grid_geometry,
+ GridItems::Iterator group_begin,
+ GridItems::Iterator group_end,
+ const bool is_group_spanning_flex_track,
+ GridItemContributionType contribution_type,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const;
- // Lays out and computes inline and block offsets for grid items.
- void PlaceGridItems();
+ void MaximizeTracks(
+ SizingConstraint sizing_constraint,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const;
- // Lays out |grid_item| based on the offsets and sizes provided.
- void PlaceGridItem(const GridItemData& grid_item,
- LogicalOffset offset,
- LogicalSize size);
+ void StretchAutoTracks(
+ SizingConstraint sizing_constraint,
+ NGGridLayoutAlgorithmTrackCollection* track_collection) const;
+
+ SetGeometry ComputeSetGeometry(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const LayoutUnit available_size) const;
// Gets the row or column gap of the grid.
LayoutUnit GridGap(GridTrackSizingDirection track_direction,
- LayoutUnit available_size = kIndefiniteSize);
+ LayoutUnit available_size = kIndefiniteSize) const;
- // Calculates inline and block offsets for all tracks.
- Vector<LayoutUnit> ComputeSetOffsets(GridTrackSizingDirection track_direction,
- LayoutUnit grid_gap);
+ LayoutUnit DetermineFreeSpace(
+ SizingConstraint sizing_constraint,
+ const NGGridLayoutAlgorithmTrackCollection& track_collection) const;
- // Tests whether the row gap is unresolvable based on its type and the
- // available size.
- bool IsRowGridGapUnresolvable(LayoutUnit available_size);
+ const NGConstraintSpace CreateConstraintSpace(
+ const GridGeometry& grid_geometry,
+ const GridItemData& grid_item,
+ NGCacheSlot cache_slot,
+ LogicalRect* rect) const;
+
+ // Layout the |grid_items| based on the offsets provided.
+ void PlaceGridItems(const GridItems& grid_items,
+ const GridGeometry& grid_geometry,
+ LayoutUnit block_size);
+
+ // Computes the static position, grid area and its offset of out of flow
+ // elements in the grid.
+ void PlaceOutOfFlowItems(const Vector<GridItemData>& out_of_flow_items,
+ const GridGeometry& grid_geometry,
+ LayoutUnit block_size);
+
+ // Gets the out of flow descendants from the container builder and computes
+ // their containing block rect.
+ void PlaceOutOfFlowDescendants(
+ const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+ const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+ const GridGeometry& grid_geometry,
+ const NGGridPlacement& grid_placement,
+ LayoutUnit block_size);
+
+ // Helper method to compute the containing grid area for grid items or the
+ // containing block rect for out of flow elements.
+ LogicalRect ComputeContainingGridAreaRect(const GridGeometry& grid_geometry,
+ const GridItemData& item,
+ LayoutUnit block_size);
+
+ // Helper method that computes the offset and size of an item.
+ void ComputeOffsetAndSize(const GridItemData& item,
+ const SetGeometry& set_geometry,
+ const GridTrackSizingDirection track_direction,
+ LayoutUnit block_size,
+ LayoutUnit* start_offset,
+ LayoutUnit* size) const;
+
+ // Determines the position of the out of flow item's container.
+ void DeterminePositionOfOutOfFlowContainer(
+ Vector<GridItemData>* out_of_flow_items,
+ const GridTrackSizingDirection track_direction) const;
GridTrackSizingDirection AutoFlowDirection() const;
- GridLayoutAlgorithmState state_;
LogicalSize border_box_size_;
- LogicalSize child_percentage_size_;
- LayoutUnit intrinsic_block_size_;
-
- Vector<GridItemData> grid_items_;
- Vector<GridItemData> out_of_flow_items_;
- Vector<wtf_size_t> reordered_item_indices_;
-
- NGGridBlockTrackCollection block_column_track_collection_;
- NGGridBlockTrackCollection block_row_track_collection_;
-
- NGGridLayoutAlgorithmTrackCollection algorithm_column_track_collection_;
- NGGridLayoutAlgorithmTrackCollection algorithm_row_track_collection_;
-
- wtf_size_t explicit_column_start_ = 0;
- wtf_size_t explicit_row_start_ = 0;
- wtf_size_t column_count_ = 0;
- wtf_size_t row_count_ = 0;
- wtf_size_t automatic_column_repetitions_ =
- NGGridBlockTrackCollection::kInvalidRangeIndex;
- wtf_size_t automatic_row_repetitions_ =
- NGGridBlockTrackCollection::kInvalidRangeIndex;
+ LogicalSize grid_available_size_;
+ LogicalSize grid_min_available_size_;
+ LogicalSize grid_max_available_size_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
index 201b3679adc..33321feb730 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h"
#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
+
namespace {
#define EXPECT_RANGE(expected_start, expected_count, iterator) \
EXPECT_EQ(expected_count, iterator.RepeatCount()); \
@@ -27,6 +29,7 @@ namespace {
EXPECT_EQ(area.rows.StartLine(), expected_row_start); \
EXPECT_EQ(area.rows.EndLine(), expected_row_end);
} // namespace
+
class NGGridLayoutAlgorithmTest
: public NGBaseLayoutAlgorithmTest,
private ScopedLayoutNGGridForTest,
@@ -36,90 +39,105 @@ class NGGridLayoutAlgorithmTest
: ScopedLayoutNGGridForTest(true),
ScopedLayoutNGBlockFragmentationForTest(true) {}
- void SetUp() override {
- NGBaseLayoutAlgorithmTest::SetUp();
- style_ = ComputedStyle::Create();
+ void SetUp() override { NGBaseLayoutAlgorithmTest::SetUp(); }
+
+ void BuildGridItemsAndTrackCollections(
+ const NGGridLayoutAlgorithm& algorithm) {
+ // Measure items.
+ algorithm.ConstructAndAppendGridItems(&grid_items_, &out_of_flow_items_);
+
+ NGGridPlacement grid_placement(
+ algorithm.Style(), algorithm.ComputeAutomaticRepetitions(kForColumns),
+ algorithm.ComputeAutomaticRepetitions(kForRows));
+
+ algorithm.BuildAlgorithmTrackCollections(
+ &grid_items_, &column_track_collection_, &row_track_collection_,
+ &grid_placement);
+
+ // Cache track span properties for grid items.
+ algorithm.CacheGridItemsTrackSpanProperties(column_track_collection_,
+ &grid_items_);
+ algorithm.CacheGridItemsTrackSpanProperties(row_track_collection_,
+ &grid_items_);
+
+ for (auto& grid_item : grid_items_) {
+ grid_item.SetIndices(column_track_collection_);
+ grid_item.SetIndices(row_track_collection_);
+ }
+
+ grid_geometry_ = {algorithm.InitializeTrackSizes(&column_track_collection_),
+ algorithm.InitializeTrackSizes(&row_track_collection_)};
+
+ // Resolve inline size.
+ algorithm.ComputeUsedTrackSizes(
+ NGGridLayoutAlgorithm::SizingConstraint::kLayout, grid_geometry_,
+ &column_track_collection_, &grid_items_);
+ // Resolve block size.
+ algorithm.ComputeUsedTrackSizes(
+ NGGridLayoutAlgorithm::SizingConstraint::kLayout, grid_geometry_,
+ &row_track_collection_, &grid_items_);
}
- // Helper methods to access private data on NGGridLayoutAlgorithm. This class
- // is a friend of NGGridLayoutAlgorithm but the individual tests are not.
- wtf_size_t GridItemCount(const NGGridLayoutAlgorithm& algorithm) {
- return algorithm.grid_items_.size();
+ NGGridLayoutAlgorithmTrackCollection& TrackCollection(
+ GridTrackSizingDirection track_direction) {
+ return (track_direction == kForColumns) ? column_track_collection_
+ : row_track_collection_;
}
- Vector<LayoutUnit> GridItemInlineSizes(
- const NGGridLayoutAlgorithm& algorithm) {
- Vector<LayoutUnit> results;
- for (const auto& item : algorithm.grid_items_) {
- results.push_back(item.inline_size);
- }
- return results;
+ LayoutUnit BaseRowSizeForChild(const NGGridLayoutAlgorithm& algorithm,
+ wtf_size_t index) {
+ LayoutUnit offset, size;
+ algorithm.ComputeOffsetAndSize(grid_items_.item_data[index],
+ grid_geometry_.row_geometry, kForRows,
+ kIndefiniteSize, &offset, &size);
+ return size;
}
+ // Helper methods to access private data on NGGridLayoutAlgorithm. This class
+ // is a friend of NGGridLayoutAlgorithm but the individual tests are not.
+ wtf_size_t GridItemCount() { return grid_items_.item_data.size(); }
+
Vector<LayoutUnit> GridItemInlineMarginSum(
const NGGridLayoutAlgorithm& algorithm) {
Vector<LayoutUnit> results;
- for (const auto& item : algorithm.grid_items_) {
+ for (const auto& item : grid_items_.item_data)
results.push_back(item.margins.InlineSum());
- }
- return results;
- }
-
- Vector<MinMaxSizes> GridItemMinMaxSizes(
- const NGGridLayoutAlgorithm& algorithm) {
- Vector<MinMaxSizes> results;
- for (const auto& item : algorithm.grid_items_) {
- results.push_back(item.min_max_sizes);
- }
return results;
}
Vector<GridArea> GridItemGridAreas(const NGGridLayoutAlgorithm& algorithm) {
Vector<GridArea> results;
- for (const auto& item : algorithm.grid_items_) {
+ for (const auto& item : grid_items_.item_data)
results.push_back(item.resolved_position);
- }
return results;
}
- void DetermineGridItemsSpanningIntrinsicOrFlexTracks(
- NGGridLayoutAlgorithm& algorithm,
- GridTrackSizingDirection track_direction) {
- algorithm.DetermineGridItemsSpanningIntrinsicOrFlexTracks(track_direction);
- }
-
- Vector<wtf_size_t> GridItemsSpanningIntrinsicTrack(
- const NGGridLayoutAlgorithm& algorithm) {
+ Vector<wtf_size_t> GridItemsWithColumnSpanProperty(
+ const NGGridLayoutAlgorithm& algorithm,
+ TrackSpanProperties::PropertyId property) {
Vector<wtf_size_t> results;
- for (wtf_size_t i = 0; i < algorithm.grid_items_.size(); ++i) {
- if (algorithm.grid_items_[i].is_spanning_intrinsic_track)
+ for (wtf_size_t i = 0; i < GridItemCount(); ++i) {
+ if (grid_items_.item_data[i].column_span_properties.HasProperty(property))
results.push_back(i);
}
return results;
}
- Vector<wtf_size_t> GridItemsSpanningFlexTrack(
- const NGGridLayoutAlgorithm& algorithm) {
+ Vector<wtf_size_t> GridItemsWithRowSpanProperty(
+ const NGGridLayoutAlgorithm& algorithm,
+ TrackSpanProperties::PropertyId property) {
Vector<wtf_size_t> results;
- for (wtf_size_t i = 0; i < algorithm.grid_items_.size(); ++i) {
- if (algorithm.grid_items_[i].is_spanning_flex_track)
+ for (wtf_size_t i = 0; i < GridItemCount(); ++i) {
+ if (grid_items_.item_data[i].row_span_properties.HasProperty(property))
results.push_back(i);
}
return results;
}
- void SetAutoTrackRepeat(NGGridLayoutAlgorithm& algorithm,
- wtf_size_t auto_column,
- wtf_size_t auto_row) {
- algorithm.SetAutomaticTrackRepetitionsForTesting(auto_column, auto_row);
- }
-
Vector<LayoutUnit> BaseSizes(NGGridLayoutAlgorithm& algorithm,
GridTrackSizingDirection track_direction) {
NGGridLayoutAlgorithmTrackCollection& collection =
- (track_direction == kForColumns)
- ? algorithm.algorithm_column_track_collection_
- : algorithm.algorithm_row_track_collection_;
+ TrackCollection(track_direction);
Vector<LayoutUnit> base_sizes;
for (auto set_iterator = collection.GetSetIterator();
@@ -132,9 +150,7 @@ class NGGridLayoutAlgorithmTest
Vector<LayoutUnit> GrowthLimits(NGGridLayoutAlgorithm& algorithm,
GridTrackSizingDirection track_direction) {
NGGridLayoutAlgorithmTrackCollection& collection =
- (track_direction == kForColumns)
- ? algorithm.algorithm_column_track_collection_
- : algorithm.algorithm_row_track_collection_;
+ TrackCollection(track_direction);
Vector<LayoutUnit> growth_limits;
for (auto set_iterator = collection.GetSetIterator();
@@ -167,10 +183,59 @@ class NGGridLayoutAlgorithmTest
return fragment->DumpFragmentTree(flags);
}
- scoped_refptr<ComputedStyle> style_;
+ NGGridLayoutAlgorithm::GridItems grid_items_;
+ Vector<NGGridLayoutAlgorithm::GridItemData> out_of_flow_items_;
+
+ NGGridLayoutAlgorithmTrackCollection column_track_collection_;
+ NGGridLayoutAlgorithmTrackCollection row_track_collection_;
+
+ NGGridLayoutAlgorithm::GridGeometry grid_geometry_;
};
-TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) {
+TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmBaseSetSizes) {
+ if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
+ return;
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #grid1 {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px;
+ grid-template-rows: auto auto 100px 100px auto 100px;
+ }
+ </style>
+ <div id="grid1">
+ <div style="grid-row: 1/2;"></div>
+ <div style="grid-row: 2/4;"></div>
+ <div style="grid-row: 3/5;"></div>
+ <div style="grid-row: 6/7;"></div>
+ <div style="grid-row: 4/6;"></div>
+ </div>
+ )HTML");
+
+ NGBlockNode node(GetLayoutBoxByElementId("grid1"));
+
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ {WritingMode::kHorizontalTb, TextDirection::kLtr},
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
+
+ NGFragmentGeometry fragment_geometry =
+ CalculateInitialFragmentGeometry(space, node);
+
+ NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(BaseRowSizeForChild(algorithm, 0), kIndefiniteSize);
+ EXPECT_EQ(BaseRowSizeForChild(algorithm, 1), kIndefiniteSize);
+ EXPECT_EQ(BaseRowSizeForChild(algorithm, 2), LayoutUnit(210));
+ EXPECT_EQ(BaseRowSizeForChild(algorithm, 3), LayoutUnit(100));
+ EXPECT_EQ(BaseRowSizeForChild(algorithm, 4), kIndefiniteSize);
+}
+
+// Flaky; see https://crbug.com/1146112 for suggestions on fixing.
+TEST_F(NGGridLayoutAlgorithmTest, DISABLED_NGGridLayoutAlgorithmMeasuring) {
if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
return;
@@ -301,54 +366,30 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(200), LayoutUnit(200)), false, true);
+ LogicalSize(LayoutUnit(200), LayoutUnit(200)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 9U);
-
- Vector<LayoutUnit> actual_inline_sizes = GridItemInlineSizes(algorithm);
- EXPECT_EQ(GridItemCount(algorithm), actual_inline_sizes.size());
-
- LayoutUnit expected_inline_sizes[] = {
- LayoutUnit(50), LayoutUnit(116), LayoutUnit(100),
- LayoutUnit(100), LayoutUnit(300), LayoutUnit(100),
- LayoutUnit(400), LayoutUnit(100), LayoutUnit(10)};
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 9U);
Vector<LayoutUnit> actual_inline_margin_sums =
GridItemInlineMarginSum(algorithm);
- EXPECT_EQ(GridItemCount(algorithm), actual_inline_margin_sums.size());
+ EXPECT_EQ(GridItemCount(), actual_inline_margin_sums.size());
LayoutUnit expected_inline_margin_sums[] = {
LayoutUnit(100), LayoutUnit(30), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
LayoutUnit(10), LayoutUnit(100), LayoutUnit(0)};
- Vector<MinMaxSizes> actual_min_max_sizes = GridItemMinMaxSizes(algorithm);
- EXPECT_EQ(GridItemCount(algorithm), actual_min_max_sizes.size());
-
- MinMaxSizes expected_min_max_sizes[] = {
- {LayoutUnit(40), LayoutUnit(60)}, {LayoutUnit(116), LayoutUnit(116)},
- {LayoutUnit(40), LayoutUnit(60)}, {LayoutUnit(100), LayoutUnit(100)},
- {LayoutUnit(300), LayoutUnit(300)}, {LayoutUnit(300), LayoutUnit(300)},
- {LayoutUnit(300), LayoutUnit(300)}, {LayoutUnit(100), LayoutUnit(100)},
- {LayoutUnit(40), LayoutUnit(40)}};
-
- for (size_t i = 0; i < GridItemCount(algorithm); ++i) {
- EXPECT_EQ(actual_inline_sizes[i], expected_inline_sizes[i])
- << " index: " << i;
+ for (size_t i = 0; i < GridItemCount(); ++i) {
EXPECT_EQ(actual_inline_margin_sums[i], expected_inline_margin_sums[i])
<< " index: " << i;
- EXPECT_EQ(actual_min_max_sizes[i].min_size,
- expected_min_max_sizes[i].min_size)
- << " index: " << i;
- EXPECT_EQ(actual_min_max_sizes[i].max_size,
- expected_min_max_sizes[i].max_size)
- << " index: " << i;
}
}
@@ -376,25 +417,27 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRanges) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 999u, row_iterator);
EXPECT_FALSE(row_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 1u, column_iterator);
@@ -431,19 +474,20 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesWithAutoRepeater) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- SetAutoTrackRepeat(algorithm, 3, 3);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 19u, row_iterator);
@@ -455,7 +499,7 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesWithAutoRepeater) {
EXPECT_FALSE(row_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
@@ -471,6 +515,8 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesWithAutoRepeater) {
EXPECT_RANGE(4u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
EXPECT_RANGE(5u, 1u, column_iterator);
+ EXPECT_TRUE(column_iterator.MoveToNextRange());
+ EXPECT_RANGE(6u, 1u, column_iterator);
EXPECT_FALSE(column_iterator.MoveToNextRange());
}
@@ -516,18 +562,20 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicit) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
@@ -538,7 +586,7 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicit) {
EXPECT_FALSE(column_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
@@ -585,19 +633,20 @@ TEST_F(NGGridLayoutAlgorithmTest,
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- SetAutoTrackRepeat(algorithm, 0, 0);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
@@ -605,7 +654,7 @@ TEST_F(NGGridLayoutAlgorithmTest,
EXPECT_FALSE(column_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
@@ -651,19 +700,20 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicitAutoRows) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- SetAutoTrackRepeat(algorithm, 0, 0);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
@@ -674,7 +724,7 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicitAutoRows) {
EXPECT_FALSE(column_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
@@ -709,19 +759,20 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicitMixed) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true);
+ LogicalSize(LayoutUnit(100), LayoutUnit(100)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- SetAutoTrackRepeat(algorithm, 0, 0);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 5U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 5U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
@@ -729,7 +780,7 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicitMixed) {
EXPECT_FALSE(column_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
@@ -796,15 +847,17 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmAutoGridPositions) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(500), LayoutUnit(500)), false, true);
+ LogicalSize(LayoutUnit(500), LayoutUnit(500)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 4U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 4U);
Vector<GridArea> grid_positions = GridItemGridAreas(algorithm);
ASSERT_EQ(grid_positions.size(), 4U);
@@ -923,15 +976,17 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmAutoDense) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(500), LayoutUnit(500)), false, true);
+ LogicalSize(LayoutUnit(500), LayoutUnit(500)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 16U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 16U);
Vector<GridArea> grid_positions = GridItemGridAreas(algorithm);
ASSERT_EQ(grid_positions.size(), 16U);
@@ -1006,25 +1061,27 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmGridPositions) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(500), LayoutUnit(500)), false, true);
+ LogicalSize(LayoutUnit(500), LayoutUnit(500)),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- EXPECT_EQ(GridItemCount(algorithm), 0U);
- algorithm.Layout();
- EXPECT_EQ(GridItemCount(algorithm), 3U);
+ EXPECT_EQ(GridItemCount(), 0U);
+ BuildGridItemsAndTrackCollections(algorithm);
+ EXPECT_EQ(GridItemCount(), 3U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
- &algorithm.ColumnTrackCollection(), 0u);
+ &TrackCollection(kForColumns), 0u);
EXPECT_RANGE(0u, 1u, column_iterator);
EXPECT_TRUE(column_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 1u, column_iterator);
EXPECT_FALSE(column_iterator.MoveToNextRange());
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
- &algorithm.RowTrackCollection(), 0u);
+ &TrackCollection(kForRows), 0u);
EXPECT_RANGE(0u, 1u, row_iterator);
EXPECT_TRUE(row_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 2u, row_iterator);
@@ -1057,12 +1114,14 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmResolveFixedTrackSizes) {
NGBlockNode node(GetLayoutBoxByElementId("grid"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), kIndefiniteSize), false, true);
+ LogicalSize(LayoutUnit(100), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- algorithm.Layout();
+ BuildGridItemsAndTrackCollections(algorithm);
Vector<LayoutUnit> expected_column_base_sizes = {
LayoutUnit(25), LayoutUnit(60), LayoutUnit(15)};
@@ -1079,8 +1138,8 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmResolveFixedTrackSizes) {
for (wtf_size_t i = 0; i < growth_limits.size(); ++i)
EXPECT_EQ(expected_column_growth_limits[i], growth_limits[i]);
- Vector<LayoutUnit> expected_row_base_sizes = {LayoutUnit(0), LayoutUnit(50),
- LayoutUnit(40)};
+ Vector<LayoutUnit> expected_row_base_sizes = {LayoutUnit(80), LayoutUnit(50),
+ LayoutUnit(70)};
Vector<LayoutUnit> expected_row_growth_limits = {
LayoutUnit(100), LayoutUnit(50), LayoutUnit(70)};
@@ -1135,40 +1194,46 @@ TEST_F(NGGridLayoutAlgorithmTest,
NGBlockNode node(GetLayoutBoxByElementId("grid"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), kIndefiniteSize), false, true);
+ LogicalSize(LayoutUnit(100), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
- algorithm.Layout();
+ BuildGridItemsAndTrackCollections(algorithm);
- DetermineGridItemsSpanningIntrinsicOrFlexTracks(algorithm, kForColumns);
+ // Test grid items spanning intrinsic/flexible columns.
Vector<wtf_size_t> expected_grid_items_spanning_intrinsic_track = {0, 1, 3};
Vector<wtf_size_t> expected_grid_items_spanning_flex_track = {1};
- Vector<wtf_size_t> actual_items = GridItemsSpanningIntrinsicTrack(algorithm);
+ Vector<wtf_size_t> actual_items = GridItemsWithColumnSpanProperty(
+ algorithm, TrackSpanProperties::kHasIntrinsicTrack);
EXPECT_EQ(expected_grid_items_spanning_intrinsic_track.size(),
actual_items.size());
for (wtf_size_t i = 0; i < actual_items.size(); ++i)
EXPECT_EQ(expected_grid_items_spanning_intrinsic_track[i], actual_items[i]);
- actual_items = GridItemsSpanningFlexTrack(algorithm);
+ actual_items = GridItemsWithColumnSpanProperty(
+ algorithm, TrackSpanProperties::kHasFlexibleTrack);
EXPECT_EQ(expected_grid_items_spanning_flex_track.size(),
actual_items.size());
for (wtf_size_t i = 0; i < actual_items.size(); ++i)
EXPECT_EQ(expected_grid_items_spanning_flex_track[i], actual_items[i]);
- DetermineGridItemsSpanningIntrinsicOrFlexTracks(algorithm, kForRows);
+ // Test grid items spanning intrinsic/flexible rows.
expected_grid_items_spanning_intrinsic_track = {1, 2, 3};
expected_grid_items_spanning_flex_track = {2};
- actual_items = GridItemsSpanningIntrinsicTrack(algorithm);
+ actual_items = GridItemsWithRowSpanProperty(
+ algorithm, TrackSpanProperties::kHasIntrinsicTrack);
EXPECT_EQ(expected_grid_items_spanning_intrinsic_track.size(),
actual_items.size());
for (wtf_size_t i = 0; i < actual_items.size(); ++i)
EXPECT_EQ(expected_grid_items_spanning_intrinsic_track[i], actual_items[i]);
- actual_items = GridItemsSpanningFlexTrack(algorithm);
+ actual_items = GridItemsWithRowSpanProperty(
+ algorithm, TrackSpanProperties::kHasFlexibleTrack);
EXPECT_EQ(expected_grid_items_spanning_flex_track.size(),
actual_items.size());
for (wtf_size_t i = 0; i < actual_items.size(); ++i)
@@ -1535,13 +1600,8 @@ TEST_F(NGGridLayoutAlgorithmTest, AutoSizedGridWithPercentageGap) {
if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
return;
- LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
- body {
- font: 10px/1 Ahem;
- }
-
#grid {
display: grid;
width: auto;
@@ -1648,76 +1708,145 @@ TEST_F(NGGridLayoutAlgorithmTest, ItemsSizeWithGap) {
EXPECT_EQ(expectation, dump);
}
-TEST_F(NGGridLayoutAlgorithmTest, OutOfFlowGridItems) {
+TEST_F(NGGridLayoutAlgorithmTest, PositionedOutOfFlowItems) {
if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
return;
- LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
- body {
- font: 10px/1 Ahem;
- }
-
#grid {
display: grid;
- width: 100px;
- height: 300px;
- grid-auto-columns: 100px;
- grid-auto-rows: 100px;
+ grid: 100px 100px 100px / 100px 100px 100px;
+ width: 300px;
+ height: auto;
+ background-color: gray;
+ padding: 5px;
+ border: 5px solid black;
position: relative;
}
- .grid_item {
- width: 100px;
- height: 100px;
- background-color: gray;
+ .absolute {
+ position: absolute;
+ width: 50px;
+ height: 50px;
}
- #cell2 {
- position: absolute;
- left: 25%;
- top: 10%;
- width: 100px;
- height: 100px;
- background-color: blue;
+ .item {
+ background-color: gainsboro;
}
- #cell4 {
- position: absolute;
- top: 150px;
- left: 25px;
- width: 100%;
- height: 35%;
- background-color: yellow;
+ #firstItem {
+ background: magenta;
+ grid-column-start: 2;
+ grid-column-end: 3;
+ grid-row-start: 2;
+ grid-row-end: 3;
+ align-self: center;
+ justify-self: end;
+ }
+
+ #secondItem {
+ background: cyan;
+ grid-column-start: auto;
+ grid-column-end: 2;
+ grid-row-start: 3;
+ grid-row-end: auto;
+ bottom: 30px;
+ }
+
+ #thirdItem {
+ background: yellow;
+ left: 200px;
+ }
+
+ #fourthItem {
+ background: lime;
+ grid-column-start: 5;
+ grid-column-end: 6;
+ }
+
+ #fifthItem {
+ grid-column-start: auto;
+ grid-column-end: 1;
+ grid-row-start: 2;
+ grid-row-end: 3;
+ background-color: hotpink;
+ }
+
+ #sixthItem {
+ grid-column-start: 4;
+ grid-column-end: auto;
+ grid-row-start: 2;
+ grid-row-end: 3;
+ background-color: purple;
+ }
+
+ #seventhItem {
+ grid-column: -5 / 1;
+ grid-row: 3 / -1;
+ background-color: darkgreen;
+ }
+
+ .descendant {
+ background: blue;
+ grid-column: 3;
+ grid-row: 3;
+ }
+
+ #positioned {
+ left: 0;
+ top: 0;
}
</style>
<div id="wrapper">
<div id="grid">
- <div class="grid_item" style="background: orange;">1</div>
- <div id="cell2">2</div>
- <div class="grid_item" style="background: green;">3</div>
- <div id="cell4">4</div>
- <div class="grid_item" style="background: blueviolet;">5</div>
+ <div class="absolute" id="firstItem"></div>
+ <div class="absolute" id="secondItem"></div>
+ <div class="absolute" id="thirdItem"></div>
+ <div class="absolute" id="fourthItem"></div>
+ <div class="absolute" id="fifthItem"></div>
+ <div class="absolute" id="sixthItem"></div>
+ <div class="absolute" id="seventhItem"></div>
+ <div class="item">
+ <div class="absolute descendant"></div>
+ </div>
+ <div class="item">
+ <div class="absolute descendant" id="positioned"></div>
+ </div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("wrapper"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
- offset:unplaced size:1000x300
- offset:0,0 size:100x300
- offset:0,0 size:100x100
- offset:0,0 size:10x10
- offset:0,100 size:100x100
- offset:0,0 size:10x10
- offset:0,200 size:100x100
- offset:0,0 size:10x10
- offset:25,30 size:100x100
- offset:0,0 size:10x10
- offset:25,150 size:100x105
- offset:0,0 size:10x10
+ offset:unplaced size:1000x320
+ offset:0,0 size:320x320
+ offset:10,10 size:100x100
+ offset:110,10 size:100x100
+ offset:210,10 size:100x100
+ offset:10,110 size:100x100
+ offset:110,110 size:100x100
+ offset:210,110 size:100x100
+ offset:10,210 size:100x100
+ offset:110,210 size:100x100
+ offset:210,210 size:100x100
+ offset:10,10 size:50x50
+ offset:210,210 size:50x50
+ offset:160,135 size:50x50
+ offset:5,235 size:50x50
+ offset:205,5 size:50x50
+ offset:5,5 size:50x50
+ offset:5,110 size:50x50
+ offset:310,110 size:50x50
+ offset:5,210 size:50x50
)DUMP";
EXPECT_EQ(expectation, dump);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
index e19c2b258c6..1faf3ba45cd 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
@@ -7,234 +7,276 @@
namespace blink {
-NGGridPlacement::NGGridPlacement(
- const wtf_size_t row_auto_repeat,
- const wtf_size_t column_auto_repeat,
- const wtf_size_t row_explicit_start,
- const wtf_size_t column_explicit_start,
- const PackingBehavior packing_behavior,
- const GridTrackSizingDirection major_direction,
- const ComputedStyle& grid_style,
- wtf_size_t minor_max_end_line,
- NGGridBlockTrackCollection& row_collection,
- NGGridBlockTrackCollection& column_collection,
- Vector<NGGridLayoutAlgorithm::GridItemData>& items)
- : row_auto_repeat_(row_auto_repeat),
- column_auto_repeat_(column_auto_repeat),
- row_explicit_start_(row_explicit_start),
- column_explicit_start_(column_explicit_start),
- packing_behavior_(packing_behavior),
- major_direction_(major_direction),
- minor_direction_(major_direction == kForRows ? kForColumns : kForRows),
- grid_style_(grid_style),
- minor_max_end_line_(minor_max_end_line),
- row_collection_(row_collection),
- column_collection_(column_collection),
- items_(items)
-
-{
- placement_cursor_major = ExplicitStart(major_direction_);
- placement_cursor_minor = ExplicitStart(minor_direction_);
-}
+NGGridPlacement::NGGridPlacement(const ComputedStyle& grid_style,
+ const wtf_size_t column_auto_repetitions,
+ const wtf_size_t row_auto_repetitions)
+ : grid_style_(grid_style),
+ packing_behavior_(grid_style.IsGridAutoFlowAlgorithmSparse()
+ ? PackingBehavior::kSparse
+ : PackingBehavior::kDense),
+ // The major direction is the one specified in the 'grid-auto-flow'
+ // property (row or column), the minor direction is its opposite.
+ major_direction_(grid_style.IsGridAutoFlowDirectionRow() ? kForRows
+ : kForColumns),
+ minor_direction_(grid_style.IsGridAutoFlowDirectionRow() ? kForColumns
+ : kForRows),
+ column_auto_repeat_track_count_(
+ grid_style.GridTemplateColumns().NGTrackList().AutoRepeatSize() *
+ column_auto_repetitions),
+ row_auto_repeat_track_count_(
+ grid_style.GridTemplateRows().NGTrackList().AutoRepeatSize() *
+ row_auto_repetitions),
+ column_auto_repetitions_(column_auto_repetitions),
+ row_auto_repetitions_(row_auto_repetitions) {}
// https://drafts.csswg.org/css-grid/#auto-placement-algo
-void NGGridPlacement::RunAutoPlacementAlgorithm() {
- // Step 1. Position anything that’s not auto-positioned, if no items need
- // auto positioning, then we are done.
- if (!PlaceNonAutoGridItems())
+void NGGridPlacement::RunAutoPlacementAlgorithm(GridItems* grid_items) {
+ DCHECK(grid_items);
+ minor_max_end_line_ = (minor_direction_ == kForColumns)
+ ? GridPositionsResolver::ExplicitGridColumnCount(
+ grid_style_, column_auto_repeat_track_count_)
+ : GridPositionsResolver::ExplicitGridRowCount(
+ grid_style_, row_auto_repeat_track_count_);
+
+ // We need these variables in order to use |GridPositionsResolver|.
+ column_start_offset_ = DetermineTrackStartOffset(*grid_items, kForColumns);
+ row_start_offset_ = DetermineTrackStartOffset(*grid_items, kForRows);
+
+ // Step 1. Position anything that’s not auto-placed; if no items need
+ // auto-placement, then we are done.
+ if (!PlaceNonAutoGridItems(grid_items))
return;
// Step 2. Process the items locked to the major axis.
- PlaceGridItemsLockedToMajorAxis();
+ PlaceGridItemsLockedToMajorAxis(grid_items);
// Step 3. Determine the number of minor tracks in the implicit grid.
- starting_minor_line_ = ExplicitStart(minor_direction_);
- ending_minor_line_ = std::max(
- minor_max_end_line_,
- starting_minor_line_ +
- BlockCollection(minor_direction_).ExplicitTracks().TotalTrackCount());
+ // This is already accomplished within the |PlaceNonAutoGridItems| and
+ // |PlaceGridItemsLockedToMajorAxis| methods; nothing else to do here.
// Step 4. Position remaining grid items.
- for (NGGridLayoutAlgorithm::GridItemData* grid_item :
- items_not_locked_to_major_axis_) {
- DCHECK(grid_item);
- const AutoPlacementType item_placement_type =
- grid_item->AutoPlacement(major_direction_);
- if (item_placement_type == AutoPlacementType::kMajor) {
- PlaceAutoMajorAxisGridItem(*grid_item);
- } else if (item_placement_type == AutoPlacementType::kBoth) {
- PlaceAutoBothAxisGridItem(*grid_item);
+ AutoPlacementCursor placement_cursor;
+ for (GridItemData& grid_item : grid_items->item_data) {
+ switch (grid_item.AutoPlacement(major_direction_)) {
+ case AutoPlacementType::kBoth:
+ PlaceAutoBothAxisGridItem(&grid_item, &placement_cursor, *grid_items);
+ break;
+ case AutoPlacementType::kMajor:
+ PlaceAutoMajorAxisGridItem(&grid_item, &placement_cursor, *grid_items);
+ break;
+ case AutoPlacementType::kMinor:
+ NOTREACHED() << "Minor axis placement should've already occurred.";
+ break;
+ case AutoPlacementType::kNotNeeded:
+ break;
+ }
+ }
+}
+
+wtf_size_t NGGridPlacement::DetermineTrackStartOffset(
+ const GridItems& grid_items,
+ GridTrackSizingDirection track_direction) const {
+ wtf_size_t track_start_offset = 0;
+
+ for (const auto& grid_item : grid_items.item_data) {
+ GridSpan grid_item_span =
+ GridPositionsResolver::ResolveGridPositionsFromStyle(
+ grid_style_, grid_item.node.Style(), track_direction,
+ AutoRepeatTrackCount(track_direction));
+
+ if (!grid_item_span.IsIndefinite()) {
+ DCHECK(grid_item_span.IsUntranslatedDefinite());
+ track_start_offset = std::max<int>(
+ track_start_offset, -grid_item_span.UntranslatedStartLine());
}
}
+ return track_start_offset;
}
-bool NGGridPlacement::PlaceNonAutoGridItems() {
- for (NGGridLayoutAlgorithm::GridItemData& grid_item : items_) {
+bool NGGridPlacement::PlaceNonAutoGridItems(GridItems* grid_items) {
+ DCHECK(grid_items);
+ bool has_auto_placed_items = false;
+
+ for (GridItemData& grid_item : grid_items->item_data) {
bool has_definite_major_placement =
- PlaceGridItem(major_direction_, grid_item);
+ PlaceGridItem(&grid_item, major_direction_);
bool has_definite_minor_placement =
- PlaceGridItem(minor_direction_, grid_item);
+ PlaceGridItem(&grid_item, minor_direction_);
- // If the item has definite positions on both axis then no auto placement is
- // needed.
- if (has_definite_major_placement && has_definite_minor_placement)
- continue;
-
- if (has_definite_major_placement)
- items_locked_to_major_axis_.push_back(&grid_item);
- else
- items_not_locked_to_major_axis_.push_back(&grid_item);
+ if (has_definite_minor_placement) {
+ minor_max_end_line_ =
+ std::max(minor_max_end_line_, grid_item.EndLine(minor_direction_));
+ } else {
+ has_auto_placed_items = true;
+ minor_max_end_line_ = std::max<wtf_size_t>(
+ minor_max_end_line_, GridPositionsResolver::SpanSizeForAutoPlacedItem(
+ grid_item.node.Style(), minor_direction_));
+ }
+ has_auto_placed_items |= !has_definite_major_placement;
}
- return !items_locked_to_major_axis_.IsEmpty() ||
- !items_not_locked_to_major_axis_.IsEmpty();
+ return has_auto_placed_items;
}
-void NGGridPlacement::PlaceGridItemsLockedToMajorAxis() {
- // Mapping between the major axis tracks (rows or columns) and the last
- // auto-placed item's position inserted on that track. This is needed to
- // implement "sparse" packing for items locked to a given track.
- // See https://drafts.csswg.org/css-grid/#auto-placement-algo
+void NGGridPlacement::PlaceGridItemsLockedToMajorAxis(GridItems* grid_items) {
+ DCHECK(grid_items);
+
+ // Mapping between the major axis tracks and the last auto-placed item's end
+ // line inserted on that track. This is needed to implement "sparse" packing
+ // for grid items locked to a given major axis track.
+ // See https://drafts.csswg.org/css-grid/#auto-placement-algo.
HashMap<wtf_size_t, wtf_size_t> minor_cursors;
- for (NGGridLayoutAlgorithm::GridItemData* grid_item :
- items_locked_to_major_axis_) {
- DCHECK(grid_item);
- DCHECK_EQ(grid_item->AutoPlacement(major_direction_),
- AutoPlacementType::kMinor);
+
+ for (GridItemData& grid_item : grid_items->item_data) {
+ // Only consider grid items that require minor axis auto-placement.
+ if (grid_item.AutoPlacement(major_direction_) != AutoPlacementType::kMinor)
+ continue;
+
wtf_size_t minor_start;
- if (packing_behavior_ == PackingBehavior::kSparse &&
- minor_cursors.Contains(grid_item->StartLine(major_direction_) + 1)) {
- minor_start =
- minor_cursors.at(grid_item->StartLine(major_direction_) + 1);
+ if (HasSparsePacking() &&
+ minor_cursors.Contains(grid_item.StartLine(major_direction_) + 1)) {
+ minor_start = minor_cursors.at(grid_item.StartLine(major_direction_) + 1);
} else {
- minor_start = ExplicitStart(minor_direction_);
+ minor_start = 0;
}
wtf_size_t minor_span_size =
- GridPositionsResolver::SpanSizeForAutoPlacedItem(
- grid_item->node.Style(), minor_direction_);
- while (DoesItemOverlap(grid_item->StartLine(major_direction_),
- grid_item->EndLine(major_direction_), minor_start,
- minor_start + minor_span_size)) {
- minor_start++;
+ GridPositionsResolver::SpanSizeForAutoPlacedItem(grid_item.node.Style(),
+ minor_direction_);
+ while (DoesItemOverlap(grid_item.StartLine(major_direction_),
+ grid_item.EndLine(major_direction_), minor_start,
+ minor_start + minor_span_size, *grid_items)) {
+ ++minor_start;
}
+
wtf_size_t minor_end = minor_start + minor_span_size;
- if (packing_behavior_ == PackingBehavior::kSparse) {
- minor_cursors.Set(grid_item->StartLine(major_direction_) + 1,
- minor_start);
- }
- minor_max_end_line_ = std::max<wtf_size_t>(minor_max_end_line_, minor_end);
+ if (HasSparsePacking())
+ minor_cursors.Set(grid_item.StartLine(major_direction_) + 1, minor_end);
+ minor_max_end_line_ = std::max(minor_max_end_line_, minor_end);
- // Update placement and ensure track coverage.
- UpdatePlacementAndEnsureTrackCoverage(
- GridSpan::TranslatedDefiniteGridSpan(minor_start, minor_end),
- minor_direction_, *grid_item);
- }
+ // Update grid item placement for minor axis.
+ GridSpan grid_item_span =
+ GridSpan::TranslatedDefiniteGridSpan(minor_start, minor_end);
+ grid_item.SetSpan(grid_item_span, minor_direction_);
}
+}
void NGGridPlacement::PlaceAutoMajorAxisGridItem(
- NGGridLayoutAlgorithm::GridItemData& grid_item) {
- wtf_size_t major_span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
- grid_item.node.Style(), major_direction_);
- switch (packing_behavior_) {
- case PackingBehavior::kSparse:
- // Set the minor position of the cursor to the grid item’s minor starting
- // line. If this is less than the previous column position of the cursor,
- // increment the major position by 1.
- if (grid_item.StartLine(minor_direction_) < placement_cursor_minor) {
- placement_cursor_major++;
- }
- break;
- case PackingBehavior::kDense:
- placement_cursor_major = ExplicitStart(major_direction_);
- break;
+ GridItemData* grid_item,
+ AutoPlacementCursor* placement_cursor,
+ const GridItems& grid_items) {
+ DCHECK(grid_item);
+
+ if (HasSparsePacking()) {
+ // For sparse packing, set the minor position of the cursor to the grid
+ // item’s minor starting line. If this is less than the previous column
+ // position of the cursor, increment the major position by 1.
+ if (grid_item->StartLine(minor_direction_) <
+ placement_cursor->minor_position) {
+ ++placement_cursor->major_position;
+ }
+ } else {
+ // Otherwise, for dense packing, reset the auto-placement cursor's major
+ // position to the start-most major line in the implicit grid.
+ placement_cursor->major_position = 0;
}
- placement_cursor_minor = grid_item.StartLine(minor_direction_);
- // Increment the cursor’s major position until a value is found where the grid
- // item does not overlap any occupied grid cells
- while (DoesItemOverlap(placement_cursor_major,
- placement_cursor_major + major_span_size,
- grid_item.StartLine(minor_direction_),
- grid_item.EndLine(minor_direction_))) {
- placement_cursor_major++;
+ placement_cursor->minor_position = grid_item->StartLine(minor_direction_);
+ wtf_size_t major_span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
+ grid_item->node.Style(), major_direction_);
+
+ // Increment the cursor’s major position until a value is found where the
+ // grid item does not overlap any occupied grid cells
+ while (DoesItemOverlap(placement_cursor->major_position,
+ placement_cursor->major_position + major_span_size,
+ grid_item->StartLine(minor_direction_),
+ grid_item->EndLine(minor_direction_), grid_items)) {
+ ++placement_cursor->major_position;
}
- // Update item and track placement.
- UpdatePlacementAndEnsureTrackCoverage(
- GridSpan::TranslatedDefiniteGridSpan(
- placement_cursor_major, placement_cursor_major + major_span_size),
- major_direction_, grid_item);
+ // Update grid item placement for major axis.
+ GridSpan grid_item_span = GridSpan::TranslatedDefiniteGridSpan(
+ placement_cursor->major_position,
+ placement_cursor->major_position + major_span_size);
+ grid_item->SetSpan(grid_item_span, major_direction_);
}
void NGGridPlacement::PlaceAutoBothAxisGridItem(
- NGGridLayoutAlgorithm::GridItemData& grid_item) {
- if (packing_behavior_ == PackingBehavior::kDense) {
- // Set the cursor’s major and minor positions to start-most row and column
- // lines in the implicit grid.
- placement_cursor_major = ExplicitStart(major_direction_);
- placement_cursor_minor = ExplicitStart(minor_direction_);
+ GridItemData* grid_item,
+ AutoPlacementCursor* placement_cursor,
+ const GridItems& grid_items) {
+ DCHECK(grid_item);
+
+ // For dense packing, set the cursor’s major and minor positions to the
+ // start-most row and column lines in the implicit grid.
+ if (!HasSparsePacking()) {
+ placement_cursor->major_position = 0;
+ placement_cursor->minor_position = 0;
}
+
wtf_size_t major_span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
- grid_item.node.Style(), major_direction_);
+ grid_item->node.Style(), major_direction_);
wtf_size_t minor_span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
- grid_item.node.Style(), minor_direction_);
+ grid_item->node.Style(), minor_direction_);
+
// Check to see if there would be overlap if this item was placed at the
// cursor. If overlap exists, increment minor position until no conflict
// exists or the item would overflow the minor axis.
- while (DoesItemOverlap(
- placement_cursor_major, placement_cursor_major + major_span_size,
- placement_cursor_minor, placement_cursor_minor + minor_span_size)) {
- placement_cursor_minor++;
- if (placement_cursor_minor + minor_span_size > ending_minor_line_) {
+ while (DoesItemOverlap(placement_cursor->major_position,
+ placement_cursor->major_position + major_span_size,
+ placement_cursor->minor_position,
+ placement_cursor->minor_position + minor_span_size,
+ grid_items)) {
+ ++placement_cursor->minor_position;
+ if (placement_cursor->minor_position + minor_span_size >
+ minor_max_end_line_) {
// If the cursor overflows the minor axis, increment cursor on the major
// axis and start from the beginning.
- placement_cursor_major++;
- placement_cursor_minor = starting_minor_line_;
+ ++placement_cursor->major_position;
+ placement_cursor->minor_position = 0;
}
}
- UpdatePlacementAndEnsureTrackCoverage(
- GridSpan::TranslatedDefiniteGridSpan(
- placement_cursor_major, placement_cursor_major + major_span_size),
- major_direction_, grid_item);
- UpdatePlacementAndEnsureTrackCoverage(
- GridSpan::TranslatedDefiniteGridSpan(
- placement_cursor_minor, placement_cursor_minor + minor_span_size),
- minor_direction_, grid_item);
+ // Update grid item placement for both axis.
+ GridSpan grid_item_span = GridSpan::TranslatedDefiniteGridSpan(
+ placement_cursor->major_position,
+ placement_cursor->major_position + major_span_size);
+ grid_item->SetSpan(grid_item_span, major_direction_);
+
+ grid_item_span = GridSpan::TranslatedDefiniteGridSpan(
+ placement_cursor->minor_position,
+ placement_cursor->minor_position + minor_span_size);
+ grid_item->SetSpan(grid_item_span, minor_direction_);
}
bool NGGridPlacement::PlaceGridItem(
- GridTrackSizingDirection direction,
- NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& grid_item) {
+ GridItemData* grid_item,
+ GridTrackSizingDirection track_direction) const {
+ DCHECK(grid_item);
GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
- grid_style_, grid_item.node.Style(), direction, AutoRepeat(direction));
- // Indefinite positions are resolved with the auto placement algorithm.
- if (span.IsIndefinite())
+ grid_style_, grid_item->node.Style(), track_direction,
+ AutoRepeatTrackCount(track_direction));
+
+ if (span.IsIndefinite()) {
+ DCHECK(grid_item->Span(track_direction).IsIndefinite());
return false;
+ }
- span.Translate(ExplicitStart(direction));
- UpdatePlacementAndEnsureTrackCoverage(span, direction, grid_item);
+ DCHECK(span.IsUntranslatedDefinite());
+ span.Translate(StartOffset(track_direction));
+ grid_item->SetSpan(span, track_direction);
return true;
}
-void NGGridPlacement::UpdatePlacementAndEnsureTrackCoverage(
- GridSpan span,
- GridTrackSizingDirection track_direction,
- NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& grid_item) {
- grid_item.SetSpan(span, track_direction);
- BlockCollection(track_direction)
- .EnsureTrackCoverage(span.StartLine(), span.IntegerSpan());
-}
-
bool NGGridPlacement::DoesItemOverlap(wtf_size_t major_start,
wtf_size_t major_end,
wtf_size_t minor_start,
- wtf_size_t minor_end) const {
+ wtf_size_t minor_end,
+ const GridItems& grid_items) const {
DCHECK_LE(major_start, major_end);
DCHECK_LE(minor_start, minor_end);
// TODO(janewman): Implement smarter collision detection, iterating over all
// items is not ideal and has large performance implications.
- for (const NGGridLayoutAlgorithm::GridItemData& grid_item : items_) {
+ for (const auto& grid_item : grid_items.item_data) {
if (grid_item.Span(major_direction_).IsIndefinite())
continue;
// Only test against definite positions.
@@ -261,31 +303,82 @@ bool NGGridPlacement::DoesItemOverlap(wtf_size_t major_start,
return false;
}
-wtf_size_t NGGridPlacement::AutoRepeat(GridTrackSizingDirection direction) {
- switch (direction) {
- case kForRows:
- return row_auto_repeat_;
- case kForColumns:
- return column_auto_repeat_;
- }
+wtf_size_t NGGridPlacement::AutoRepetitions(
+ GridTrackSizingDirection track_direction) const {
+ return (track_direction == kForColumns) ? column_auto_repetitions_
+ : row_auto_repetitions_;
}
-wtf_size_t NGGridPlacement::ExplicitStart(GridTrackSizingDirection direction) {
- switch (direction) {
- case kForRows:
- return row_explicit_start_;
- case kForColumns:
- return column_explicit_start_;
- }
+wtf_size_t NGGridPlacement::StartOffset(
+ GridTrackSizingDirection track_direction) const {
+ return (track_direction == kForColumns) ? column_start_offset_
+ : row_start_offset_;
+}
+
+wtf_size_t NGGridPlacement::AutoRepeatTrackCount(
+ GridTrackSizingDirection track_direction) const {
+ return (track_direction == kForColumns) ? column_auto_repeat_track_count_
+ : row_auto_repeat_track_count_;
}
-NGGridBlockTrackCollection& NGGridPlacement::BlockCollection(
- GridTrackSizingDirection direction) {
- switch (direction) {
- case kForRows:
- return row_collection_;
- case kForColumns:
- return column_collection_;
+bool NGGridPlacement::HasSparsePacking() const {
+ return packing_behavior_ == PackingBehavior::kSparse;
+}
+
+namespace {
+
+bool IsStartLineAuto(const GridTrackSizingDirection track_direction,
+ const ComputedStyle& out_of_flow_item_style) {
+ return (track_direction == kForColumns)
+ ? out_of_flow_item_style.GridColumnStart().IsAuto()
+ : out_of_flow_item_style.GridRowStart().IsAuto();
+}
+
+bool IsEndLineAuto(const GridTrackSizingDirection track_direction,
+ const ComputedStyle& out_of_flow_item_style) {
+ return (track_direction == kForColumns)
+ ? out_of_flow_item_style.GridColumnEnd().IsAuto()
+ : out_of_flow_item_style.GridRowEnd().IsAuto();
+}
+
+} // namespace
+
+void NGGridPlacement::ResolveOutOfFlowItemGridLines(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const ComputedStyle& out_of_flow_item_style,
+ wtf_size_t* start_line,
+ wtf_size_t* end_line) const {
+ DCHECK(start_line);
+ DCHECK(end_line);
+
+ const GridTrackSizingDirection track_direction = track_collection.Direction();
+ GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
+ grid_style_, out_of_flow_item_style, track_direction,
+ AutoRepeatTrackCount(track_direction));
+
+ if (span.IsIndefinite()) {
+ *start_line = kNotFound;
+ *end_line = kNotFound;
+ return;
+ }
+
+ wtf_size_t start_offset = StartOffset(track_direction);
+ int span_start_line = span.UntranslatedStartLine() + start_offset;
+ int span_end_line = span.UntranslatedEndLine() + start_offset;
+
+ if (span_start_line < 0 ||
+ IsStartLineAuto(track_direction, out_of_flow_item_style) ||
+ !track_collection.IsGridLineWithinImplicitGrid(span_start_line)) {
+ *start_line = kNotFound;
+ } else {
+ *start_line = span_start_line;
+ }
+ if (span_end_line < 0 ||
+ IsEndLineAuto(track_direction, out_of_flow_item_style) ||
+ !track_collection.IsGridLineWithinImplicitGrid(span_end_line)) {
+ *end_line = kNotFound;
+ } else {
+ *end_line = span_end_line;
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h
index c0fe4bff271..c779c7d96bb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h
@@ -19,84 +19,86 @@ class CORE_EXPORT NGGridPlacement {
public:
enum class PackingBehavior { kSparse, kDense };
- explicit NGGridPlacement(const wtf_size_t row_auto_repeat,
- const wtf_size_t column_auto_repeat,
- const wtf_size_t row_explicit_start,
- const wtf_size_t column_explicit_start,
- const PackingBehavior packing_behavior,
- const GridTrackSizingDirection major_direction,
- const ComputedStyle& grid_style,
- wtf_size_t minor_max_end_line,
- NGGridBlockTrackCollection& row_collection,
- NGGridBlockTrackCollection& column_collection,
- Vector<NGGridLayoutAlgorithm::GridItemData>& items);
- void RunAutoPlacementAlgorithm();
+
+ using GridItems = NGGridLayoutAlgorithm::GridItems;
+ using GridItemData = NGGridLayoutAlgorithm::GridItemData;
+ using AutoPlacementType = NGGridLayoutAlgorithm::AutoPlacementType;
+
+ NGGridPlacement(const ComputedStyle& grid_style,
+ const wtf_size_t column_auto_repetitions,
+ const wtf_size_t row_auto_repetitions);
+
+ void RunAutoPlacementAlgorithm(GridItems* grid_items);
+ // Helper function to resolve start and end lines of out of flow items.
+ void ResolveOutOfFlowItemGridLines(
+ const NGGridLayoutAlgorithmTrackCollection& track_collection,
+ const ComputedStyle& out_of_flow_item_style,
+ wtf_size_t* start_line,
+ wtf_size_t* end_line) const;
+
+ wtf_size_t AutoRepetitions(GridTrackSizingDirection track_direction) const;
+ wtf_size_t StartOffset(GridTrackSizingDirection track_direction) const;
private:
- // Place non auto-positioned items and determine what items need auto
- // placement, if any do, this returns true.
- bool PlaceNonAutoGridItems();
- // Place items that have a definite position on the major axis but need auto
- // placement on the minor axis.
- void PlaceGridItemsLockedToMajorAxis();
- // Place item that has a definite position on the minor axis but need auto
- // placement on the major axis.
- void PlaceAutoMajorAxisGridItem(
- NGGridLayoutAlgorithm::GridItemData& item_data);
- // Place items that need automatic placement on both the major and minor axis.
- void PlaceAutoBothAxisGridItem(
- NGGridLayoutAlgorithm::GridItemData& item_data);
- // Places a grid item if it has a definite position in the given direction,
- // returns true if item was able to be positioned, false if item needs auto
- // positioning in the given direction.
- bool PlaceGridItem(
- GridTrackSizingDirection grid_direction,
- NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& item_data);
-
- void UpdatePlacementAndEnsureTrackCoverage(
- GridSpan span,
- GridTrackSizingDirection track_direction,
- NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& item_data);
+ struct AutoPlacementCursor {
+ wtf_size_t major_position{0};
+ wtf_size_t minor_position{0};
+ };
+
+ // Compute the track start offset from the grid items positioned at negative
+ // indices.
+ wtf_size_t DetermineTrackStartOffset(
+ const GridItems& grid_items,
+ GridTrackSizingDirection track_direction) const;
+
+ // Place non auto-positioned elements from |grid_items|; returns true if any
+ // item needs to resolve an automatic position. Otherwise, false.
+ bool PlaceNonAutoGridItems(GridItems* grid_items);
+ // Place elements from |grid_items| that have a definite position on the major
+ // axis but need auto-placement on the minor axis.
+ void PlaceGridItemsLockedToMajorAxis(GridItems* grid_items);
+ // Place an item that has a definite position on the minor axis but need
+ // auto-placement on the major axis.
+ void PlaceAutoMajorAxisGridItem(GridItemData* grid_item,
+ AutoPlacementCursor* placement_cursor,
+ const GridItems& grid_items);
+ // Place an item that needs auto-placement on both the major and minor axis.
+ void PlaceAutoBothAxisGridItem(GridItemData* grid_item,
+ AutoPlacementCursor* placement_cursor,
+ const GridItems& grid_items);
+
+ // Places a grid item; returns true if it has a definite position in the given
+ // direction, false if the item needs auto-placement.
+ bool PlaceGridItem(GridItemData* grid_item,
+ GridTrackSizingDirection track_direction) const;
// Returns true if the given placement would overlap with a placed item.
bool DoesItemOverlap(wtf_size_t major_start,
wtf_size_t major_end,
wtf_size_t minor_start,
- wtf_size_t minor_end) const;
+ wtf_size_t minor_end,
+ const GridItems& grid_items) const;
+
+ wtf_size_t AutoRepeatTrackCount(
+ GridTrackSizingDirection track_direction) const;
+ bool HasSparsePacking() const;
- wtf_size_t AutoRepeat(GridTrackSizingDirection direction);
- wtf_size_t ExplicitStart(GridTrackSizingDirection direction);
- NGGridBlockTrackCollection& BlockCollection(
- GridTrackSizingDirection direction);
+ // Used to resolve positions using |GridPositionsResolver|.
+ const ComputedStyle& grid_style_;
- const wtf_size_t row_auto_repeat_;
- const wtf_size_t column_auto_repeat_;
- const wtf_size_t row_explicit_start_;
- const wtf_size_t column_explicit_start_;
const PackingBehavior packing_behavior_;
const GridTrackSizingDirection major_direction_;
const GridTrackSizingDirection minor_direction_;
- // Used to resolve positions using GridPositionsResolver.
- const ComputedStyle& grid_style_;
+ const wtf_size_t column_auto_repeat_track_count_;
+ const wtf_size_t row_auto_repeat_track_count_;
+ const wtf_size_t column_auto_repetitions_;
+ const wtf_size_t row_auto_repetitions_;
- // Keeps track of the biggest minor end line among items with an explicit
- // major line.
- wtf_size_t minor_max_end_line_ = 0;
-
- NGGridBlockTrackCollection& row_collection_;
- NGGridBlockTrackCollection& column_collection_;
- Vector<NGGridLayoutAlgorithm::GridItemData>& items_;
-
- wtf_size_t starting_minor_line_ = 0;
- wtf_size_t ending_minor_line_ = 0;
- wtf_size_t placement_cursor_major;
- wtf_size_t placement_cursor_minor;
- // Subset of |items_| containing items that have a definite position on the
- // major axis.
- Vector<NGGridLayoutAlgorithm::GridItemData*> items_locked_to_major_axis_;
- // Subset of |items_| containing items that do not have a definite position on
- // the major axis.
- Vector<NGGridLayoutAlgorithm::GridItemData*> items_not_locked_to_major_axis_;
+ wtf_size_t minor_max_end_line_;
+ wtf_size_t column_start_offset_;
+ wtf_size_t row_start_offset_;
};
+
} // namespace blink
+
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_PLACEMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
index 5976eb70f40..16c77b1c731 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
@@ -19,9 +19,8 @@ wtf_size_t NGGridTrackCollectionBase::RangeIndexFromTrackNumber(
// We can't look for a range in a collection with no ranges.
DCHECK_NE(upper, 0u);
// We don't expect a |track_number| outside of the bounds of the collection.
- DCHECK_NE(track_number, kInvalidRangeIndex);
DCHECK_LT(track_number,
- RangeTrackNumber(upper - 1u) + RangeTrackCount(upper - 1u));
+ RangeTrackNumber(upper - 1) + RangeTrackCount(upper - 1));
// Do a binary search on the tracks.
wtf_size_t range = upper - lower;
@@ -45,7 +44,6 @@ wtf_size_t NGGridTrackCollectionBase::RangeIndexFromTrackNumber(
range = upper - lower;
}
}
-
return lower;
}
@@ -136,31 +134,53 @@ bool NGGridTrackCollectionBase::RangeRepeatIterator::SetRangeIndex(
return true;
}
+bool NGGridBlockTrackCollection::Range::IsImplicit() const {
+ return properties.HasProperty(TrackSpanProperties::kIsImplicit);
+}
+
+bool NGGridBlockTrackCollection::Range::IsCollapsed() const {
+ return properties.HasProperty(TrackSpanProperties::kIsCollapsed);
+}
+
+void NGGridBlockTrackCollection::Range::SetIsImplicit() {
+ properties.SetProperty(TrackSpanProperties::kIsImplicit);
+}
+
+void NGGridBlockTrackCollection::Range::SetIsCollapsed() {
+ properties.SetProperty(TrackSpanProperties::kIsCollapsed);
+}
+
+NGGridBlockTrackCollection::NGGridBlockTrackCollection(
+ GridTrackSizingDirection direction)
+ : direction_(direction) {}
+
void NGGridBlockTrackCollection::SetSpecifiedTracks(
const NGGridTrackList* explicit_tracks,
const NGGridTrackList* implicit_tracks,
+ wtf_size_t start_offset,
wtf_size_t auto_repeat_count) {
DCHECK_NE(nullptr, explicit_tracks);
DCHECK_NE(nullptr, implicit_tracks);
// The implicit track list should have only one repeater, if any.
DCHECK_LE(implicit_tracks->RepeaterCount(), 1u);
- DCHECK_NE(NGGridTrackCollectionBase::kInvalidRangeIndex, auto_repeat_count);
+ DCHECK_NE(kInvalidRangeIndex, auto_repeat_count);
+
explicit_tracks_ = explicit_tracks;
implicit_tracks_ = implicit_tracks;
auto_repeat_count_ = auto_repeat_count;
const wtf_size_t repeater_count = explicit_tracks_->RepeaterCount();
- wtf_size_t total_track_count = 0;
+ wtf_size_t current_repeater_start_line = start_offset;
for (wtf_size_t i = 0; i < repeater_count; ++i) {
wtf_size_t repeater_track_count =
explicit_tracks_->RepeatCount(i, auto_repeat_count_) *
explicit_tracks_->RepeatSize(i);
- if (repeater_track_count != 0) {
- starting_tracks_.push_back(total_track_count);
- ending_tracks_.push_back(total_track_count + repeater_track_count);
- }
- total_track_count += repeater_track_count;
+ DCHECK_NE(repeater_track_count, 0u);
+
+ start_lines_.push_back(current_repeater_start_line);
+ current_repeater_start_line += repeater_track_count;
+ end_lines_.push_back(current_repeater_start_line);
}
}
@@ -169,138 +189,167 @@ void NGGridBlockTrackCollection::EnsureTrackCoverage(wtf_size_t track_number,
DCHECK_NE(kInvalidRangeIndex, track_number);
DCHECK_NE(kInvalidRangeIndex, span_length);
track_indices_need_sort_ = true;
- starting_tracks_.push_back(track_number);
- ending_tracks_.push_back(track_number + span_length);
+ start_lines_.push_back(track_number);
+ end_lines_.push_back(track_number + span_length);
}
-void NGGridBlockTrackCollection::FinalizeRanges() {
- ranges_.clear();
-
+void NGGridBlockTrackCollection::FinalizeRanges(wtf_size_t start_offset) {
// Sort start and ending tracks from low to high.
if (track_indices_need_sort_) {
- std::stable_sort(starting_tracks_.begin(), starting_tracks_.end());
- std::stable_sort(ending_tracks_.begin(), ending_tracks_.end());
+ std::sort(start_lines_.begin(), start_lines_.end());
+ std::sort(end_lines_.begin(), end_lines_.end());
}
+ ranges_.clear();
- wtf_size_t current_range_track_start = 0u;
-
- // Indices into the starting and ending track vectors.
- wtf_size_t starting_tracks_index = 0u;
- wtf_size_t ending_tracks_index = 0u;
+ bool is_in_auto_fit_range = false;
+ wtf_size_t current_range_start = 0u;
+ wtf_size_t open_items_or_repeaters = 0u;
+ wtf_size_t current_explicit_grid_line = start_offset;
+ wtf_size_t current_explicit_repeater_index = kInvalidRangeIndex;
+ wtf_size_t explicit_repeater_count = explicit_tracks_->RepeaterCount();
- wtf_size_t repeater_index = kInvalidRangeIndex;
- wtf_size_t repeater_track_start = kInvalidRangeIndex;
- wtf_size_t next_repeater_track_start = 0u;
- wtf_size_t current_repeater_track_count = 0u;
+ // If the explicit grid is not empty, |start_offset| is the translated index
+ // of the first track in |explicit_tracks_|; otherwise, the next repeater
+ // does not exist, fallback to |kInvalidRangeIndex|.
+ wtf_size_t next_explicit_repeater_start =
+ explicit_repeater_count ? start_offset : kInvalidRangeIndex;
- wtf_size_t total_repeater_count = explicit_tracks_->RepeaterCount();
- wtf_size_t open_items_or_repeaters = 0u;
- bool is_in_auto_fit_range = false;
+ // Index of the start/end line we are currently processing.
+ wtf_size_t start_line_index = 0u;
+ wtf_size_t end_line_index = 0u;
while (true) {
// Identify starting tracks index.
- while (starting_tracks_index < starting_tracks_.size() &&
- current_range_track_start >=
- starting_tracks_[starting_tracks_index]) {
- ++starting_tracks_index;
+ while (start_line_index < start_lines_.size() &&
+ current_range_start >= start_lines_[start_line_index]) {
+ ++start_line_index;
++open_items_or_repeaters;
}
// Identify ending tracks index.
- while (ending_tracks_index < ending_tracks_.size() &&
- current_range_track_start >= ending_tracks_[ending_tracks_index]) {
- ++ending_tracks_index;
+ while (end_line_index < end_lines_.size() &&
+ current_range_start >= end_lines_[end_line_index]) {
+ ++end_line_index;
--open_items_or_repeaters;
DCHECK_GE(open_items_or_repeaters, 0u);
}
// Identify ending tracks index.
- if (ending_tracks_index >= ending_tracks_.size()) {
+ if (end_line_index >= end_lines_.size()) {
+#if DCHECK_IS_ON()
DCHECK_EQ(open_items_or_repeaters, 0u);
+ // If we exhausted the end indices, then we must have already exhausted
+ // the repeaters, or are located at the end of the last repeater.
+ if (current_explicit_repeater_index != kInvalidRangeIndex) {
+ DCHECK_EQ(current_explicit_repeater_index, explicit_repeater_count - 1);
+ DCHECK_EQ(current_range_start, next_explicit_repeater_start);
+ }
+#endif
break;
}
// Determine the next starting and ending track index.
- wtf_size_t next_starting_track = kInvalidRangeIndex;
- if (starting_tracks_index < starting_tracks_.size())
- next_starting_track = starting_tracks_[starting_tracks_index];
- wtf_size_t next_ending_track = ending_tracks_[ending_tracks_index];
-
- // Move |next_repeater_track_start| to the start of the next repeater, if
- // needed.
- while (current_range_track_start == next_repeater_track_start) {
- if (++repeater_index == total_repeater_count) {
- repeater_index = kInvalidRangeIndex;
- repeater_track_start = next_repeater_track_start;
+ wtf_size_t next_start_line = (start_line_index < start_lines_.size())
+ ? start_lines_[start_line_index]
+ : kInvalidRangeIndex;
+ wtf_size_t next_end_line = end_lines_[end_line_index];
+
+ // Move to the start of the next explicit repeater.
+ while (current_range_start == next_explicit_repeater_start) {
+ current_explicit_grid_line = next_explicit_repeater_start;
+
+ // No next repeater, break and use implicit grid tracks.
+ if (++current_explicit_repeater_index == explicit_repeater_count) {
+ current_explicit_repeater_index = kInvalidRangeIndex;
is_in_auto_fit_range = false;
break;
}
- is_in_auto_fit_range = explicit_tracks_->RepeatType(repeater_index) ==
- NGGridTrackRepeater::RepeatType::kAutoFit;
- current_repeater_track_count =
- explicit_tracks_->RepeatCount(repeater_index, auto_repeat_count_) *
- explicit_tracks_->RepeatSize(repeater_index);
- repeater_track_start = next_repeater_track_start;
- next_repeater_track_start += current_repeater_track_count;
+ is_in_auto_fit_range =
+ explicit_tracks_->RepeatType(current_explicit_repeater_index) ==
+ NGGridTrackRepeater::RepeatType::kAutoFit;
+ next_explicit_repeater_start +=
+ explicit_tracks_->RepeatSize(current_explicit_repeater_index) *
+ explicit_tracks_->RepeatCount(current_explicit_repeater_index,
+ auto_repeat_count_);
}
// Determine track number and count of the range.
Range range;
- range.starting_track_number = current_range_track_start;
- DCHECK(next_starting_track != kInvalidRangeIndex ||
- next_ending_track < next_starting_track);
- range.track_count = std::min(next_ending_track, next_starting_track) -
- current_range_track_start;
+ range.starting_track_number = current_range_start;
+ DCHECK(next_start_line != kInvalidRangeIndex ||
+ next_end_line < next_start_line);
+ range.track_count =
+ std::min(next_start_line, next_end_line) - current_range_start;
+ DCHECK_GT(range.track_count, 0u);
// Compute repeater index and offset.
- if (repeater_index == kInvalidRangeIndex) {
- range.is_implicit_range = true;
- if (implicit_tracks_->RepeaterCount() == 0) {
- // No specified implicit tracks, use auto tracks.
+ if (current_explicit_repeater_index != kInvalidRangeIndex) {
+ // This range is contained within a repeater of the explicit grid; at this
+ // point, |current_explicit_grid_line| should be set to the start line of
+ // such repeater.
+ range.repeater_index = current_explicit_repeater_index;
+ range.repeater_offset =
+ (current_range_start - current_explicit_grid_line) %
+ explicit_tracks_->RepeatSize(current_explicit_repeater_index);
+ } else {
+ range.SetIsImplicit();
+ if (implicit_tracks_->RepeaterCount() == 0u) {
+ // No specified implicit grid tracks, use 'auto'.
range.repeater_index = kInvalidRangeIndex;
- range.repeater_offset = 0;
+ range.repeater_offset = 0u;
} else {
- // Use implicit tracks.
- range.repeater_index = 0;
+ // Otherwise, use the only repeater for implicit grid tracks.
+ // There are 2 scenarios we want to cover here:
+ // 1. At this point, we should not have reached any explicit repeater,
+ // since |current_explicit_grid_line| was initialized as the start
+ // line of the first explicit repeater (e.g. |start_offset|), it can
+ // be used to determine the offset of ranges preceding the explicit
+ // grid; the last implicit grid track before the explicit grid
+ // receives the last specified size, and so on backwards.
+ //
+ // 2. This range is located after any repeater in |explicit_tracks_|,
+ // meaning it was defined with indices beyond the explicit grid.
+ // We should have set |current_explicit_grid_line| to the last line
+ // of the explicit grid at this point, use it to compute the offset of
+ // following implicit tracks; the first track after the explicit grid
+ // receives the first specified size, and so on forwards.
+ //
+ // Note that for both scenarios we can use the following formula:
+ // (current_range_start - current_explicit_grid_line) %
+ // implicit_repeater_size
+ // The expression below is equivalent, but uses some modular arithmetic
+ // properties to avoid |wtf_size_t| underflow in scenario 1.
+ range.repeater_index = 0u;
+ wtf_size_t implicit_repeater_size = implicit_tracks_->RepeatSize(0u);
range.repeater_offset =
- current_range_track_start - repeater_track_start;
+ (current_range_start + implicit_repeater_size -
+ current_explicit_grid_line % implicit_repeater_size) %
+ implicit_repeater_size;
}
- } else {
- range.is_implicit_range = false;
- range.repeater_index = repeater_index;
- range.repeater_offset = current_range_track_start - repeater_track_start;
}
- range.is_collapsed = is_in_auto_fit_range && open_items_or_repeaters == 1u;
- current_range_track_start += range.track_count;
- ranges_.push_back(range);
+ if (is_in_auto_fit_range && open_items_or_repeaters == 1u)
+ range.SetIsCollapsed();
+ current_range_start += range.track_count;
+ ranges_.emplace_back(std::move(range));
}
-#if DCHECK_IS_ON()
- while (repeater_index != kInvalidRangeIndex &&
- repeater_index < total_repeater_count - 1u) {
- ++repeater_index;
- DCHECK_EQ(0u, explicit_tracks_->RepeatSize(repeater_index));
- }
-#endif
- DCHECK_EQ(starting_tracks_index, starting_tracks_.size());
- DCHECK_EQ(ending_tracks_index, starting_tracks_.size());
- DCHECK(repeater_index == total_repeater_count - 1u ||
- repeater_index == kInvalidRangeIndex);
- starting_tracks_.clear();
- ending_tracks_.clear();
+ // We must have exhausted all start and end indices.
+ DCHECK_EQ(start_line_index, start_lines_.size());
+ DCHECK_EQ(end_line_index, start_lines_.size());
+
+ start_lines_.clear();
+ end_lines_.clear();
}
-const NGGridBlockTrackCollection::Range&
-NGGridBlockTrackCollection::RangeAtRangeIndex(wtf_size_t range_index) const {
+bool NGGridBlockTrackCollection::IsRangeImplicit(wtf_size_t range_index) const {
DCHECK_LT(range_index, ranges_.size());
- return ranges_[range_index];
+ return ranges_[range_index].IsImplicit();
}
const NGGridBlockTrackCollection::Range&
-NGGridBlockTrackCollection::RangeAtTrackNumber(wtf_size_t track_number) const {
- wtf_size_t range_index = RangeIndexFromTrackNumber(track_number);
+NGGridBlockTrackCollection::RangeAtRangeIndex(wtf_size_t range_index) const {
DCHECK_LT(range_index, ranges_.size());
return ranges_[range_index];
}
@@ -326,15 +375,15 @@ String NGGridBlockTrackCollection::ToString() const {
}
builder.Append("], [Starting: {");
- for (wtf_size_t i = 0; i < starting_tracks_.size(); ++i) {
- builder.AppendNumber<wtf_size_t>(starting_tracks_[i]);
- if (i + 1 != starting_tracks_.size())
+ for (wtf_size_t i = 0; i < start_lines_.size(); ++i) {
+ builder.AppendNumber<wtf_size_t>(start_lines_[i]);
+ if (i + 1 != start_lines_.size())
builder.Append(", ");
}
builder.Append("} ], [Ending: {");
- for (wtf_size_t i = 0; i < ending_tracks_.size(); ++i) {
- builder.AppendNumber<wtf_size_t>(ending_tracks_[i]);
- if (i + 1 != ending_tracks_.size())
+ for (wtf_size_t i = 0; i < end_lines_.size(); ++i) {
+ builder.AppendNumber<wtf_size_t>(end_lines_[i]);
+ if (i + 1 != end_lines_.size())
builder.Append(", ");
}
builder.Append("} ] ");
@@ -368,23 +417,21 @@ wtf_size_t NGGridBlockTrackCollection::RangeTrackCount(
bool NGGridBlockTrackCollection::IsRangeCollapsed(
wtf_size_t range_index) const {
DCHECK_LT(range_index, RangeCount());
- return ranges_[range_index].is_collapsed;
+ return ranges_[range_index].IsCollapsed();
}
wtf_size_t NGGridBlockTrackCollection::RangeCount() const {
return ranges_.size();
}
-// Default track size for a set with no specified track definition should be
-// 'auto', but we will normalize it directly as 'minmax(auto, max-content)'.
NGGridSet::NGGridSet(wtf_size_t track_count, bool is_collapsed)
: track_count_(track_count),
- track_size_(Length::Auto(), Length::MaxContent()),
+ track_size_(Length::Auto(), Length::Auto()),
growth_limit_(kIndefiniteSize),
fit_content_limit_(kIndefiniteSize),
is_infinitely_growable_(false) {
if (is_collapsed) {
- // From https://drafts.csswg.org/css-grid-1/#collapsed-track: "A collapsed
+ // From https://drafts.csswg.org/css-grid-2/#collapsed-track: "A collapsed
// track is treated as having a fixed track sizing function of '0px'".
track_size_ = GridTrackSize(Length::Fixed(), Length::Fixed());
}
@@ -409,7 +456,7 @@ NGGridSet::NGGridSet(wtf_size_t track_count,
}
} else {
// Normalize |track_size_| into a |kMinMaxTrackSizing| type; follow the
- // definitions from https://drafts.csswg.org/css-grid-1/#algo-terms.
+ // definitions from https://drafts.csswg.org/css-grid-2/#algo-terms.
bool is_unresolvable_percentage_min_function =
is_content_box_size_indefinite &&
track_size_.MinTrackBreadth().HasPercentage();
@@ -427,7 +474,7 @@ NGGridSet::NGGridSet(wtf_size_t track_count,
GridLength normalized_max_track_sizing_function =
(is_unresolvable_percentage_max_function ||
track_size_.HasAutoMaxTrackBreadth())
- ? Length::MaxContent()
+ ? Length::Auto()
: track_size_.MaxTrackBreadth();
track_size_ = GridTrackSize(normalized_min_track_sizing_function,
@@ -479,44 +526,22 @@ NGGridLayoutAlgorithmTrackCollection::Range::Range(
: starting_track_number(block_track_range.starting_track_number),
track_count(block_track_range.track_count),
starting_set_index(starting_set_index),
- is_collapsed(block_track_range.is_collapsed) {}
-
-NGGridLayoutAlgorithmTrackCollection::SetIterator::SetIterator(
- NGGridLayoutAlgorithmTrackCollection* collection,
- wtf_size_t begin_set_index,
- wtf_size_t end_set_index)
- : collection_(collection),
- current_set_index_(begin_set_index),
- end_set_index_(end_set_index) {
- DCHECK(collection_);
- DCHECK_LE(current_set_index_, end_set_index_);
-}
-
-bool NGGridLayoutAlgorithmTrackCollection::SetIterator::IsAtEnd() const {
- DCHECK_LE(current_set_index_, end_set_index_);
- return current_set_index_ == end_set_index_;
-}
+ properties(block_track_range.properties) {}
-bool NGGridLayoutAlgorithmTrackCollection::SetIterator::MoveToNextSet() {
- current_set_index_ = std::min(current_set_index_ + 1, end_set_index_);
- return current_set_index_ < end_set_index_;
-}
-
-NGGridSet& NGGridLayoutAlgorithmTrackCollection::SetIterator::CurrentSet()
- const {
- DCHECK_LT(current_set_index_, end_set_index_);
- return collection_->SetAt(current_set_index_);
+bool NGGridLayoutAlgorithmTrackCollection::Range::IsCollapsed() const {
+ return properties.HasProperty(TrackSpanProperties::kIsCollapsed);
}
NGGridLayoutAlgorithmTrackCollection::NGGridLayoutAlgorithmTrackCollection(
const NGGridBlockTrackCollection& block_track_collection,
- bool is_content_box_size_indefinite) {
+ bool is_content_box_size_indefinite)
+ : direction_(block_track_collection.Direction()) {
for (auto range_iterator = block_track_collection.RangeIterator();
!range_iterator.IsAtEnd(); range_iterator.MoveToNextRange()) {
const NGGridBlockTrackCollection::Range& block_track_range =
block_track_collection.RangeAtRangeIndex(range_iterator.RangeIndex());
AppendTrackRange(block_track_range,
- block_track_range.is_implicit_range
+ block_track_range.IsImplicit()
? block_track_collection.ImplicitTracks()
: block_track_collection.ExplicitTracks(),
is_content_box_size_indefinite);
@@ -529,27 +554,28 @@ void NGGridLayoutAlgorithmTrackCollection::AppendTrackRange(
bool is_content_box_size_indefinite) {
Range new_range(block_track_range, /* starting_set_index */ sets_.size());
- if (block_track_range.is_collapsed ||
+ if (block_track_range.IsCollapsed() ||
block_track_range.repeater_index == kInvalidRangeIndex) {
#if DCHECK_IS_ON()
// If there are no specified repeaters for this range, it must be implicit.
if (block_track_range.repeater_index == kInvalidRangeIndex)
- DCHECK(block_track_range.is_implicit_range);
+ DCHECK(block_track_range.IsImplicit());
#endif
// Append a single element for the entire range's set.
new_range.set_count = 1;
sets_.emplace_back(block_track_range.track_count,
- block_track_range.is_collapsed);
+ block_track_range.IsCollapsed());
} else {
- wtf_size_t repeater_size =
+ wtf_size_t current_repeater_size =
specified_track_list.RepeatSize(block_track_range.repeater_index);
+ DCHECK_LT(block_track_range.repeater_offset, current_repeater_size);
// The number of different set elements in this range is the number of track
// definitions from |NGGridBlockTrackCollection| range's repeater clamped by
// the range's total track count if it's less than the repeater's size.
new_range.set_count =
- std::min(repeater_size, block_track_range.track_count);
+ std::min(current_repeater_size, block_track_range.track_count);
DCHECK_GT(new_range.set_count, 0u);
// The following two variables help compute how many tracks a set element
@@ -560,17 +586,19 @@ void NGGridLayoutAlgorithmTrackCollection::AppendTrackRange(
// 1. |floor_set_track_count| is the number of times we would return to the
// range's repeater offset, meaning that every definition in the repeater's
// track list appears at least that many times within the range.
- wtf_size_t floor_set_track_count = new_range.track_count / repeater_size;
+ wtf_size_t floor_set_track_count =
+ new_range.track_count / current_repeater_size;
// 2. The remaining track count would not complete another iteration over
// the entire repeater; this means that the first |remaining_track_count|
// definitions appear one more time in the range.
- wtf_size_t remaining_track_count = new_range.track_count % repeater_size;
+ wtf_size_t remaining_track_count =
+ new_range.track_count % current_repeater_size;
for (wtf_size_t i = 0; i < new_range.set_count; ++i) {
wtf_size_t set_track_count =
floor_set_track_count + ((i < remaining_track_count) ? 1 : 0);
wtf_size_t set_repeater_offset =
- (block_track_range.repeater_offset + i) % repeater_size;
+ (block_track_range.repeater_offset + i) % current_repeater_size;
const GridTrackSize& set_track_size =
specified_track_list.RepeatTrackSize(block_track_range.repeater_index,
set_repeater_offset);
@@ -579,42 +607,75 @@ void NGGridLayoutAlgorithmTrackCollection::AppendTrackRange(
}
}
- // Cache if this range contains an intrinsic or flexible track.
- new_range.is_spanning_flex_track = false;
- new_range.is_spanning_intrinsic_track = false;
+ // Cache this range's track span properties.
+ bool is_range_spanning_flexible_track = false;
+ bool is_range_spanning_intrinsic_track = false;
+
for (wtf_size_t i = 0; i < new_range.set_count; ++i) {
const NGGridSet& set = sets_[new_range.starting_set_index + i];
- // From https://drafts.csswg.org/css-grid-1/#algo-terms, a <flex> minimum
+ // From https://drafts.csswg.org/css-grid-2/#algo-terms, a <flex> minimum
// sizing function shouldn't happen as it would be normalized to 'auto'.
DCHECK(!set.TrackSize().HasFlexMinTrackBreadth());
- new_range.is_spanning_flex_track |=
+ is_range_spanning_flexible_track |=
set.TrackSize().HasFlexMaxTrackBreadth();
- new_range.is_spanning_intrinsic_track |=
+ is_range_spanning_intrinsic_track |=
set.TrackSize().HasIntrinsicMinTrackBreadth() ||
set.TrackSize().HasIntrinsicMaxTrackBreadth();
}
+
+ if (is_range_spanning_flexible_track)
+ new_range.properties.SetProperty(TrackSpanProperties::kHasFlexibleTrack);
+ if (is_range_spanning_intrinsic_track)
+ new_range.properties.SetProperty(TrackSpanProperties::kHasIntrinsicTrack);
ranges_.push_back(new_range);
}
+wtf_size_t NGGridLayoutAlgorithmTrackCollection::EndLineOfImplicitGrid() const {
+ wtf_size_t last_range_index = RangeCount() - 1;
+ return RangeTrackNumber(last_range_index) + RangeTrackCount(last_range_index);
+}
+
+bool NGGridLayoutAlgorithmTrackCollection::IsGridLineWithinImplicitGrid(
+ wtf_size_t grid_line) const {
+ DCHECK_NE(grid_line, kInvalidRangeIndex);
+ return grid_line <= EndLineOfImplicitGrid();
+}
+
NGGridSet& NGGridLayoutAlgorithmTrackCollection::SetAt(wtf_size_t set_index) {
DCHECK_LT(set_index, SetCount());
return sets_[set_index];
}
+const NGGridSet& NGGridLayoutAlgorithmTrackCollection::SetAt(
+ wtf_size_t set_index) const {
+ DCHECK_LT(set_index, SetCount());
+ return sets_[set_index];
+}
+
NGGridLayoutAlgorithmTrackCollection::SetIterator
NGGridLayoutAlgorithmTrackCollection::GetSetIterator() {
return SetIterator(this, 0u, SetCount());
}
+NGGridLayoutAlgorithmTrackCollection::ConstSetIterator
+NGGridLayoutAlgorithmTrackCollection::GetSetIterator() const {
+ return ConstSetIterator(this, 0u, SetCount());
+}
+
NGGridLayoutAlgorithmTrackCollection::SetIterator
NGGridLayoutAlgorithmTrackCollection::GetSetIterator(wtf_size_t begin_set_index,
wtf_size_t end_set_index) {
- DCHECK_LE(end_set_index, SetCount());
- DCHECK_LE(begin_set_index, end_set_index);
return SetIterator(this, begin_set_index, end_set_index);
}
+NGGridLayoutAlgorithmTrackCollection::ConstSetIterator
+NGGridLayoutAlgorithmTrackCollection::GetSetIterator(
+ wtf_size_t begin_set_index,
+ wtf_size_t end_set_index) const {
+ return ConstSetIterator(this, begin_set_index, end_set_index);
+}
+
wtf_size_t NGGridLayoutAlgorithmTrackCollection::RangeSetCount(
wtf_size_t range_index) const {
DCHECK_LT(range_index, RangeCount());
@@ -627,16 +688,11 @@ wtf_size_t NGGridLayoutAlgorithmTrackCollection::RangeStartingSetIndex(
return ranges_[range_index].starting_set_index;
}
-bool NGGridLayoutAlgorithmTrackCollection::IsRangeSpanningIntrinsicTrack(
- wtf_size_t range_index) const {
- DCHECK_LT(range_index, RangeCount());
- return ranges_[range_index].is_spanning_intrinsic_track;
-}
-
-bool NGGridLayoutAlgorithmTrackCollection::IsRangeSpanningFlexTrack(
- wtf_size_t range_index) const {
+bool NGGridLayoutAlgorithmTrackCollection::RangeHasTrackSpanProperty(
+ wtf_size_t range_index,
+ TrackSpanProperties::PropertyId property_id) const {
DCHECK_LT(range_index, RangeCount());
- return ranges_[range_index].is_spanning_flex_track;
+ return ranges_[range_index].properties.HasProperty(property_id);
}
wtf_size_t NGGridLayoutAlgorithmTrackCollection::RangeTrackNumber(
@@ -654,7 +710,7 @@ wtf_size_t NGGridLayoutAlgorithmTrackCollection::RangeTrackCount(
bool NGGridLayoutAlgorithmTrackCollection::IsRangeCollapsed(
wtf_size_t range_index) const {
DCHECK_LT(range_index, RangeCount());
- return ranges_[range_index].is_collapsed;
+ return ranges_[range_index].IsCollapsed();
}
wtf_size_t NGGridLayoutAlgorithmTrackCollection::RangeCount() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
index aa0791fed10..42e2240dc32 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
@@ -58,49 +58,72 @@ class CORE_EXPORT NGGridTrackCollectionBase {
protected:
// Returns the first track number of a range.
virtual wtf_size_t RangeTrackNumber(wtf_size_t range_index) const = 0;
-
// Returns the number of tracks in a range.
virtual wtf_size_t RangeTrackCount(wtf_size_t range_index) const = 0;
-
// Returns true if the range at the given index is collapsed.
virtual bool IsRangeCollapsed(wtf_size_t range_index) const = 0;
-
// Returns the number of track ranges in the collection.
virtual wtf_size_t RangeCount() const = 0;
};
+struct CORE_EXPORT TrackSpanProperties {
+ public:
+ enum PropertyId : unsigned {
+ kNone = 0,
+ kHasIntrinsicTrack = 1 << 0,
+ kHasFlexibleTrack = 1 << 1,
+ kHasAutoMinimumTrack = 1 << 2,
+ kIsCollapsed = 1 << 3,
+ kIsImplicit = 1 << 4
+ };
+
+ inline bool HasProperty(PropertyId id) const { return bitmask_ & id; }
+ inline void SetProperty(PropertyId id) { bitmask_ |= id; }
+
+ private:
+ uint8_t bitmask_{kNone};
+};
+
class CORE_EXPORT NGGridBlockTrackCollection
: public NGGridTrackCollectionBase {
public:
struct Range {
+ bool IsImplicit() const;
+ bool IsCollapsed() const;
+
+ void SetIsImplicit();
+ void SetIsCollapsed();
+
wtf_size_t starting_track_number;
wtf_size_t track_count;
wtf_size_t repeater_index;
wtf_size_t repeater_offset;
-
- bool is_implicit_range : 1;
- bool is_collapsed : 1;
+ TrackSpanProperties properties;
};
+ explicit NGGridBlockTrackCollection(
+ GridTrackSizingDirection track_direction = kForColumns);
+
// Sets the specified, implicit tracks, along with a given auto repeat value.
void SetSpecifiedTracks(const NGGridTrackList* explicit_tracks,
const NGGridTrackList* implicit_tracks,
+ wtf_size_t start_offset,
wtf_size_t auto_repeat_count);
// Ensures that after FinalizeRanges is called, a range will start at the
// |track_number|, and a range will end at |track_number| + |span_length|
void EnsureTrackCoverage(wtf_size_t track_number, wtf_size_t span_length);
-
// Build the collection of ranges based on information provided by
// SetSpecifiedTracks and EnsureTrackCoverage.
- void FinalizeRanges();
- // Returns the range at the given range index.
+ void FinalizeRanges(wtf_size_t start_offset);
+
+ bool IsRangeImplicit(wtf_size_t range_index) const;
const Range& RangeAtRangeIndex(wtf_size_t range_index) const;
- // Returns the range at the given track.
- const Range& RangeAtTrackNumber(wtf_size_t track_number) const;
+
+ GridTrackSizingDirection Direction() const { return direction_; }
+ bool IsForColumns() const { return direction_ == kForColumns; }
const NGGridTrackList& ExplicitTracks() const;
const NGGridTrackList& ImplicitTracks() const;
-
String ToString() const;
protected:
@@ -117,6 +140,7 @@ class CORE_EXPORT NGGridBlockTrackCollection
wtf_size_t ImplicitRepeatSize() const;
bool track_indices_need_sort_ = false;
+ GridTrackSizingDirection direction_;
wtf_size_t auto_repeat_count_ = 0;
// Stores the specified and implicit tracks specified by SetSpecifiedTracks.
@@ -125,8 +149,8 @@ class CORE_EXPORT NGGridBlockTrackCollection
// Starting and ending tracks mark where ranges will start and end.
// Once the ranges have been built in FinalizeRanges, these are cleared.
- Vector<wtf_size_t> starting_tracks_;
- Vector<wtf_size_t> ending_tracks_;
+ Vector<wtf_size_t> start_lines_;
+ Vector<wtf_size_t> end_lines_;
Vector<Range> ranges_;
};
@@ -170,7 +194,7 @@ class CORE_EXPORT NGGridSet {
public:
NGGridSet(wtf_size_t track_count, bool is_collapsed);
// |is_content_box_size_indefinite| is used to normalize percentage track
- // sizing functions; from https://drafts.csswg.org/css-grid-1/#track-sizes:
+ // sizing functions; from https://drafts.csswg.org/css-grid-2/#track-sizes:
// "If the size of the grid container depends on the size of its tracks,
// then the <percentage> must be treated as 'auto'".
NGGridSet(wtf_size_t track_count,
@@ -192,6 +216,9 @@ class CORE_EXPORT NGGridSet {
void SetPlannedIncrease(LayoutUnit planned_increase) {
planned_increase_ = planned_increase;
}
+ void SetFitContentLimit(LayoutUnit fit_content_limit) {
+ fit_content_limit_ = fit_content_limit;
+ }
void SetItemIncurredIncrease(LayoutUnit item_incurred_increase) {
item_incurred_increase_ = item_incurred_increase;
}
@@ -223,33 +250,60 @@ class CORE_EXPORT NGGridLayoutAlgorithmTrackCollection
Range(const NGGridBlockTrackCollection::Range& block_track_range,
wtf_size_t starting_set_index);
+ bool IsCollapsed() const;
+
wtf_size_t starting_track_number;
wtf_size_t track_count;
wtf_size_t starting_set_index;
wtf_size_t set_count;
-
- bool is_spanning_intrinsic_track : 1;
- bool is_spanning_flex_track : 1;
- bool is_collapsed : 1;
+ TrackSpanProperties properties;
};
- // Note that this iterator can alter any set's data.
- class CORE_EXPORT SetIterator {
+ template <bool is_const>
+ class CORE_EXPORT SetIteratorBase {
public:
- SetIterator(NGGridLayoutAlgorithmTrackCollection* collection,
- wtf_size_t begin_set_index,
- wtf_size_t end_set_index);
-
- bool IsAtEnd() const;
- bool MoveToNextSet();
- NGGridSet& CurrentSet() const;
+ using TrackCollectionPtr =
+ typename std::conditional<is_const,
+ const NGGridLayoutAlgorithmTrackCollection*,
+ NGGridLayoutAlgorithmTrackCollection*>::type;
+ using NGGridSetRef =
+ typename std::conditional<is_const, const NGGridSet&, NGGridSet&>::type;
+
+ SetIteratorBase(TrackCollectionPtr track_collection,
+ wtf_size_t begin_set_index,
+ wtf_size_t end_set_index)
+ : track_collection_(track_collection),
+ current_set_index_(begin_set_index),
+ end_set_index_(end_set_index) {
+ DCHECK(track_collection_);
+ DCHECK_LE(current_set_index_, end_set_index_);
+ DCHECK_LE(end_set_index_, track_collection_->SetCount());
+ }
+
+ bool IsAtEnd() const {
+ DCHECK_LE(current_set_index_, end_set_index_);
+ return current_set_index_ == end_set_index_;
+ }
+
+ bool MoveToNextSet() {
+ current_set_index_ = std::min(current_set_index_ + 1, end_set_index_);
+ return current_set_index_ < end_set_index_;
+ }
+
+ NGGridSetRef CurrentSet() const {
+ DCHECK_LT(current_set_index_, end_set_index_);
+ return track_collection_->SetAt(current_set_index_);
+ }
private:
- NGGridLayoutAlgorithmTrackCollection* collection_;
+ TrackCollectionPtr track_collection_;
wtf_size_t current_set_index_;
wtf_size_t end_set_index_;
};
+ typedef SetIteratorBase<false> SetIterator;
+ typedef SetIteratorBase<true> ConstSetIterator;
+
NGGridLayoutAlgorithmTrackCollection() = default;
// |is_content_box_size_indefinite| is used to normalize percentage track
// sizing functions (see the constructor for |NGGridSet|).
@@ -257,24 +311,35 @@ class CORE_EXPORT NGGridLayoutAlgorithmTrackCollection
const NGGridBlockTrackCollection& block_track_collection,
bool is_content_box_size_indefinite);
+ wtf_size_t EndLineOfImplicitGrid() const;
+ bool IsGridLineWithinImplicitGrid(wtf_size_t grid_line) const;
+
// Returns the number of sets in the collection.
wtf_size_t SetCount() const;
// Returns a reference to the set located at position |set_index|.
NGGridSet& SetAt(wtf_size_t set_index);
+ const NGGridSet& SetAt(wtf_size_t set_index) const;
// Returns an iterator for all the sets contained in this collection.
SetIterator GetSetIterator();
+ ConstSetIterator GetSetIterator() const;
// Returns an iterator for every set in this collection's |sets_| located at
// an index in the interval [begin_set_index, end_set_index).
SetIterator GetSetIterator(wtf_size_t begin_set_index,
wtf_size_t end_set_index);
+ ConstSetIterator GetSetIterator(wtf_size_t begin_set_index,
+ wtf_size_t end_set_index) const;
wtf_size_t RangeSetCount(wtf_size_t range_index) const;
wtf_size_t RangeStartingSetIndex(wtf_size_t range_index) const;
- // Returns true if the range contains a set with an intrinsic sizing function.
- bool IsRangeSpanningIntrinsicTrack(wtf_size_t range_index) const;
- // Returns true if the range contains a set with a flexible sizing function.
- bool IsRangeSpanningFlexTrack(wtf_size_t range_index) const;
+ // Returns true if the specified property has been set in the track span
+ // properties bitmask of the range at position |range_index|.
+ bool RangeHasTrackSpanProperty(
+ wtf_size_t range_index,
+ TrackSpanProperties::PropertyId property_id) const;
+
+ GridTrackSizingDirection Direction() const { return direction_; }
+ bool IsForColumns() const { return direction_ == kForColumns; }
protected:
// NGGridTrackCollectionBase overrides.
@@ -289,6 +354,8 @@ class CORE_EXPORT NGGridLayoutAlgorithmTrackCollection
const NGGridTrackList& specified_track_list,
bool is_content_box_size_indefinite);
+ GridTrackSizingDirection direction_;
+
Vector<Range> ranges_;
// A vector of every set element that compose the entire collection's ranges;
// track definitions from the same set are stored in consecutive positions,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection_test.cc
index 8819b00330b..18fa8cc5f51 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection_test.cc
@@ -192,8 +192,10 @@ TEST_F(NGGridTrackCollectionTest, TestNGGridBlockTrackCollection) {
CreateTrackSizes(3), NGGridTrackRepeater::RepeatType::kAutoFill));
ASSERT_EQ(2u, explicit_tracks.RepeaterCount());
NGGridBlockTrackCollection block_collection;
- block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks, 3);
- block_collection.FinalizeRanges();
+ block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
+ /* auto_repeat_count */ 3);
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridTrackCollectionBase::RangeRepeatIterator iterator(&block_collection,
0u);
@@ -213,8 +215,10 @@ TEST_F(NGGridTrackCollectionTest, TestNGGridBlockTrackCollectionCollapsed) {
ASSERT_TRUE(explicit_tracks.AddRepeater(CreateTrackSizes(3), 7));
ASSERT_EQ(3u, explicit_tracks.RepeaterCount());
NGGridBlockTrackCollection block_collection;
- block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks, 3);
- block_collection.FinalizeRanges();
+ block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
+ /* auto_repeat_count */ 3);
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridTrackCollectionBase::RangeRepeatIterator iterator(&block_collection,
0u);
@@ -240,29 +244,31 @@ TEST_F(NGGridTrackCollectionTest, TestNGGridBlockTrackCollectionImplicit) {
ASSERT_TRUE(implicit_tracks.AddRepeater(CreateTrackSizes(8), 2));
NGGridBlockTrackCollection block_collection;
- block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks, 3);
+ block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
+ /* auto_repeat_count */ 3);
block_collection.EnsureTrackCoverage(3, 40);
block_collection.EnsureTrackCoverage(3, 40);
- block_collection.FinalizeRanges();
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridTrackCollectionBase::RangeRepeatIterator iterator(&block_collection,
0u);
EXPECT_RANGE(0u, 3u, iterator);
- EXPECT_FALSE(block_collection.RangeAtTrackNumber(0u).is_implicit_range);
+ EXPECT_FALSE(block_collection.IsRangeImplicit(iterator.RangeIndex()));
EXPECT_TRUE(iterator.MoveToNextRange());
EXPECT_RANGE(3u, 5u, iterator);
- EXPECT_FALSE(block_collection.RangeAtTrackNumber(3).is_implicit_range);
+ EXPECT_FALSE(block_collection.IsRangeImplicit(iterator.RangeIndex()));
EXPECT_TRUE(iterator.MoveToNextRange());
EXPECT_RANGE(8u, 9u, iterator);
- EXPECT_FALSE(block_collection.RangeAtTrackNumber(11).is_implicit_range);
+ EXPECT_FALSE(block_collection.IsRangeImplicit(iterator.RangeIndex()));
EXPECT_TRUE(iterator.MoveToNextRange());
- EXPECT_FALSE(block_collection.RangeAtTrackNumber(20).is_implicit_range);
+ EXPECT_FALSE(block_collection.IsRangeImplicit(iterator.RangeIndex()));
EXPECT_RANGE(17u, 21u, iterator);
EXPECT_TRUE(iterator.MoveToNextRange());
- EXPECT_TRUE(block_collection.RangeAtTrackNumber(40).is_implicit_range);
+ EXPECT_TRUE(block_collection.IsRangeImplicit(iterator.RangeIndex()));
EXPECT_RANGE(38u, 5u, iterator);
EXPECT_FALSE(iterator.MoveToNextRange());
@@ -285,20 +291,19 @@ TEST_F(NGGridTrackCollectionTest, TestNGGridSetTrackSizeNormalization) {
};
// auto
- TestTrackSizeNormalization(
- GridTrackSize(Length::Auto()),
- GridTrackSize(Length::Auto(), Length::MaxContent()),
- GridTrackSize(Length::Auto(), Length::MaxContent()));
+ TestTrackSizeNormalization(GridTrackSize(Length::Auto()),
+ GridTrackSize(Length::Auto(), Length::Auto()),
+ GridTrackSize(Length::Auto(), Length::Auto()));
// 10%
TestTrackSizeNormalization(
GridTrackSize(Length::Percent(10)),
GridTrackSize(Length::Percent(10), Length::Percent(10)),
- GridTrackSize(Length::Auto(), Length::MaxContent()));
+ GridTrackSize(Length::Auto(), Length::Auto()));
// minmax(50px, 20%)
TestTrackSizeNormalization(
GridTrackSize(Length::Fixed(50), Length::Percent(20)),
GridTrackSize(Length::Fixed(50), Length::Percent(20)),
- GridTrackSize(Length::Fixed(50), Length::MaxContent()));
+ GridTrackSize(Length::Fixed(50), Length::Auto()));
// min-content
TestTrackSizeNormalization(
GridTrackSize(Length::MinContent()),
@@ -336,8 +341,9 @@ TEST_F(NGGridTrackCollectionTest,
NGGridBlockTrackCollection block_collection;
block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
/* auto_repeat_count */ 0);
- block_collection.FinalizeRanges();
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridLayoutAlgorithmTrackCollection algorithm_collection(
block_collection, /* is_content_box_size_defined */ false);
@@ -390,12 +396,13 @@ TEST_F(NGGridTrackCollectionTest,
NGGridBlockTrackCollection block_collection;
block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
/* auto_repeat_count */ 5);
block_collection.EnsureTrackCoverage(2, 4);
block_collection.EnsureTrackCoverage(12, 4);
block_collection.EnsureTrackCoverage(17, 3);
block_collection.EnsureTrackCoverage(22, 5);
- block_collection.FinalizeRanges();
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridLayoutAlgorithmTrackCollection algorithm_collection(
block_collection, /* is_content_box_size_defined */ false);
@@ -508,10 +515,11 @@ TEST_F(NGGridTrackCollectionTest,
NGGridBlockTrackCollection block_collection;
block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
/* auto_repeat_count */ 0);
block_collection.EnsureTrackCoverage(2, 13);
block_collection.EnsureTrackCoverage(23, 2);
- block_collection.FinalizeRanges();
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridLayoutAlgorithmTrackCollection algorithm_collection(
block_collection, /* is_content_box_size_defined */ false);
@@ -583,10 +591,11 @@ TEST_F(NGGridTrackCollectionTest,
NGGridBlockTrackCollection block_collection;
block_collection.SetSpecifiedTracks(&explicit_tracks, &implicit_tracks,
+ /* start_offset */ 0,
/* auto_repeat_count */ 0);
block_collection.EnsureTrackCoverage(1, 2);
block_collection.EnsureTrackCoverage(7, 4);
- block_collection.FinalizeRanges();
+ block_collection.FinalizeRanges(/* start_offset */ 0);
NGGridLayoutAlgorithmTrackCollection algorithm_collection(
block_collection, /* is_content_box_size_defined */ false);
@@ -599,10 +608,10 @@ TEST_F(NGGridTrackCollectionTest,
EXPECT_SET(GridTrackSize(Length::MinContent()), 1u, set_iterator);
EXPECT_FALSE(set_iterator.MoveToNextSet());
wtf_size_t current_range_index = range_iterator.RangeIndex();
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningIntrinsicTrack(current_range_index));
- EXPECT_FALSE(
- algorithm_collection.IsRangeSpanningFlexTrack(current_range_index));
+ EXPECT_FALSE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasFlexibleTrack));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasIntrinsicTrack));
EXPECT_TRUE(range_iterator.MoveToNextRange());
EXPECT_RANGE(1u, 2u, range_iterator);
@@ -613,10 +622,10 @@ TEST_F(NGGridTrackCollectionTest,
EXPECT_SET(GridTrackSize(Length::Fixed(2)), 1u, set_iterator);
EXPECT_FALSE(set_iterator.MoveToNextSet());
current_range_index = range_iterator.RangeIndex();
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningIntrinsicTrack(current_range_index));
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningFlexTrack(current_range_index));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasFlexibleTrack));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasIntrinsicTrack));
EXPECT_TRUE(range_iterator.MoveToNextRange());
EXPECT_RANGE(3u, 4u, range_iterator);
@@ -631,10 +640,10 @@ TEST_F(NGGridTrackCollectionTest,
EXPECT_SET(GridTrackSize(Length::Fixed(2)), 1u, set_iterator);
EXPECT_FALSE(set_iterator.MoveToNextSet());
current_range_index = range_iterator.RangeIndex();
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningIntrinsicTrack(current_range_index));
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningFlexTrack(current_range_index));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasFlexibleTrack));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasIntrinsicTrack));
EXPECT_TRUE(range_iterator.MoveToNextRange());
EXPECT_RANGE(7u, 1u, range_iterator);
@@ -643,10 +652,10 @@ TEST_F(NGGridTrackCollectionTest,
EXPECT_SET(GridTrackSize(Length::Fixed(3)), 1u, set_iterator);
EXPECT_FALSE(set_iterator.MoveToNextSet());
current_range_index = range_iterator.RangeIndex();
- EXPECT_FALSE(
- algorithm_collection.IsRangeSpanningIntrinsicTrack(current_range_index));
- EXPECT_FALSE(
- algorithm_collection.IsRangeSpanningFlexTrack(current_range_index));
+ EXPECT_FALSE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasFlexibleTrack));
+ EXPECT_FALSE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasIntrinsicTrack));
EXPECT_TRUE(range_iterator.MoveToNextRange());
EXPECT_RANGE(8u, 3u, range_iterator);
@@ -655,10 +664,10 @@ TEST_F(NGGridTrackCollectionTest,
EXPECT_SET(GridTrackSize(Length::Auto()), 3u, set_iterator);
EXPECT_FALSE(set_iterator.MoveToNextSet());
current_range_index = range_iterator.RangeIndex();
- EXPECT_TRUE(
- algorithm_collection.IsRangeSpanningIntrinsicTrack(current_range_index));
- EXPECT_FALSE(
- algorithm_collection.IsRangeSpanningFlexTrack(current_range_index));
+ EXPECT_FALSE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasFlexibleTrack));
+ EXPECT_TRUE(algorithm_collection.RangeHasTrackSpanProperty(
+ current_range_index, TrackSpanProperties::kHasIntrinsicTrack));
EXPECT_FALSE(range_iterator.MoveToNextRange());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md b/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
index 765cf9268a9..7dbc96b9e1a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/README.md
@@ -356,6 +356,8 @@ In a bird's‐eye view, it consists of two parts:
This is part of the Line Box Construction phase above.
+Initial design doc: [Using ICU BiDi in LayoutNG](https://docs.google.com/document/d/182H1Sj_FCEHcl6eC69J4KcIc5m3ohSzgo297KYB0S_c/edit?usp=sharing)
+
### Interface for Editing ###
[NGOffsetMapping] provides functions for converting between offsets in the text
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
index 5d3f5e36df7..6ea54e234ea 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -9,10 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
#include "third_party/blink/renderer/platform/fonts/character_range.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
@@ -21,20 +17,16 @@ namespace blink {
namespace {
-// Mapping from NGFragmentItem/NGPaintFragment to NGAbstractInlineTextBox
-// TODO(yosin): Once we get rid of |NGPaintFragment|, we should not use
-// template class for |NGAbstractInlineTextBoxCache|.
-template <typename Fragment>
class NGAbstractInlineTextBoxCache final {
public:
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
- const Fragment& fragment) {
+ const NGFragmentItem& fragment) {
if (!s_instance_)
s_instance_ = new NGAbstractInlineTextBoxCache();
return s_instance_->GetOrCreateInternal(fragment);
}
- static void WillDestroy(const Fragment* fragment) {
+ static void WillDestroy(const NGFragmentItem* fragment) {
if (!s_instance_)
return;
s_instance_->WillDestroyInternal(fragment);
@@ -42,7 +34,7 @@ class NGAbstractInlineTextBoxCache final {
private:
scoped_refptr<AbstractInlineTextBox> GetOrCreateInternal(
- const Fragment& fragment) {
+ const NGFragmentItem& fragment) {
const auto it = map_.find(&fragment);
auto* const layout_text = To<LayoutText>(fragment.GetMutableLayoutObject());
if (it != map_.end()) {
@@ -56,7 +48,7 @@ class NGAbstractInlineTextBoxCache final {
return obj;
}
- void WillDestroyInternal(const Fragment* fragment) {
+ void WillDestroyInternal(const NGFragmentItem* fragment) {
const auto it = map_.find(fragment);
if (it == map_.end())
return;
@@ -66,51 +58,29 @@ class NGAbstractInlineTextBoxCache final {
static NGAbstractInlineTextBoxCache* s_instance_;
- HashMap<const Fragment*, scoped_refptr<AbstractInlineTextBox>> map_;
+ HashMap<const NGFragmentItem*, scoped_refptr<AbstractInlineTextBox>> map_;
};
-template <typename Fragment>
-NGAbstractInlineTextBoxCache<Fragment>*
- NGAbstractInlineTextBoxCache<Fragment>::s_instance_ = nullptr;
+NGAbstractInlineTextBoxCache* NGAbstractInlineTextBoxCache::s_instance_ =
+ nullptr;
} // namespace
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::GetOrCreate(
const NGInlineCursor& cursor) {
- if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
- return NGAbstractInlineTextBoxCache<NGPaintFragment>::GetOrCreate(
- *paint_fragment);
- }
if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) {
- return NGAbstractInlineTextBoxCache<NGFragmentItem>::GetOrCreate(
- *fragment_item);
+ return NGAbstractInlineTextBoxCache::GetOrCreate(*fragment_item);
}
return nullptr;
}
void NGAbstractInlineTextBox::WillDestroy(const NGInlineCursor& cursor) {
- if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
- return NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy(
- paint_fragment);
- }
if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) {
- return NGAbstractInlineTextBoxCache<NGFragmentItem>::WillDestroy(
- fragment_item);
+ return NGAbstractInlineTextBoxCache::WillDestroy(fragment_item);
}
NOTREACHED();
}
-void NGAbstractInlineTextBox::WillDestroy(const NGPaintFragment* fragment) {
- NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy(fragment);
-}
-
-NGAbstractInlineTextBox::NGAbstractInlineTextBox(
- LineLayoutText line_layout_item,
- const NGPaintFragment& fragment)
- : AbstractInlineTextBox(line_layout_item), fragment_(&fragment) {
- DCHECK(fragment_->PhysicalFragment().IsText()) << fragment_;
-}
-
NGAbstractInlineTextBox::NGAbstractInlineTextBox(
LineLayoutText line_layout_item,
const NGFragmentItem& fragment_item)
@@ -119,26 +89,30 @@ NGAbstractInlineTextBox::NGAbstractInlineTextBox(
}
NGAbstractInlineTextBox::~NGAbstractInlineTextBox() {
- DCHECK(!fragment_);
+ DCHECK(!fragment_item_);
}
void NGAbstractInlineTextBox::Detach() {
- if (Node* const node = GetNode()) {
- if (AXObjectCache* cache = node->GetDocument().ExistingAXObjectCache())
- cache->InlineTextBoxesUpdated(GetLineLayoutItem());
- }
+ LayoutObject* prev_layout_object = GetLayoutObject();
+ AXObjectCache* cache = ExistingAXObjectCache();
+
AbstractInlineTextBox::Detach();
- fragment_ = nullptr;
+ DCHECK(!GetLayoutObject());
+
+ fragment_item_ = nullptr;
+
+ if (cache) {
+ prev_layout_object->CheckIsNotDestroyed();
+ DCHECK(IsA<LayoutText>(prev_layout_object));
+ cache->InlineTextBoxesUpdated(prev_layout_object);
+ }
}
NGInlineCursor NGAbstractInlineTextBox::GetCursor() const {
if (!fragment_item_)
return NGInlineCursor();
NGInlineCursor cursor;
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- cursor.MoveTo(*fragment_item_);
- else
- cursor.MoveTo(*fragment_);
+ cursor.MoveTo(*fragment_item_);
DCHECK(!cursor.Current().GetLayoutObject()->NeedsLayout());
return cursor;
}
@@ -156,10 +130,6 @@ String NGAbstractInlineTextBox::GetTextContent() const {
const NGInlineCursor& cursor = GetCursor();
if (cursor.Current().IsLayoutGeneratedText())
return cursor.Current().Text(cursor).ToString();
- if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
- return To<NGPhysicalTextFragment>(paint_fragment->PhysicalFragment())
- .TextContent();
- }
return cursor.Items().Text(cursor.Current().UsesFirstLineStyle());
}
@@ -178,10 +148,9 @@ bool NGAbstractInlineTextBox::NeedsTrailingSpace() const {
if (text_content[end_offset] != ' ')
return false;
const NGInlineBreakToken* break_token = line_box.Current().InlineBreakToken();
- DCHECK(break_token);
// TODO(yosin): We should support OOF fragments between |fragment_| and
// break token.
- if (break_token->TextOffset() != end_offset + 1)
+ if (break_token && break_token->TextOffset() != end_offset + 1)
return false;
// Check a character in text content after |fragment_| comes from same
// layout text of |fragment_|.
@@ -218,7 +187,7 @@ LayoutRect NGAbstractInlineTextBox::LocalBounds() const {
const NGInlineCursor& cursor = GetCursor();
if (!cursor)
return LayoutRect();
- return cursor.Current().RectInContainerBlock().ToLayoutRect();
+ return cursor.Current().RectInContainerFragment().ToLayoutRect();
}
unsigned NGAbstractInlineTextBox::Len() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
index dd0f528d75c..aaed36436d9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
@@ -11,25 +11,21 @@ namespace blink {
class NGFragmentItem;
class NGInlineCursor;
-class NGPaintFragment;
// The implementation of |AbstractInlineTextBox| for LayoutNG.
// See also |LegacyAbstractInlineTextBox| for legacy layout.
class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
private:
// Returns existing or newly created |NGAbstractInlineTextBox|.
- // * |cursor| should be attached to |NGPhysicalTextFragment|.
+ // * |cursor| should be attached to a text item.
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
const NGInlineCursor& cursor);
static void WillDestroy(const NGInlineCursor& cursor);
- static void WillDestroy(const NGPaintFragment* fragment);
friend class LayoutText;
public:
NGAbstractInlineTextBox(LineLayoutText line_layout_item,
- const NGPaintFragment& fragment);
- NGAbstractInlineTextBox(LineLayoutText line_layout_item,
const NGFragmentItem& fragment);
~NGAbstractInlineTextBox() final;
@@ -55,10 +51,7 @@ class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
bool IsLineBreak() const final;
bool NeedsTrailingSpace() const final;
- union {
- const NGPaintFragment* fragment_;
- const NGFragmentItem* fragment_item_;
- };
+ const NGFragmentItem* fragment_item_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
index f2314916600..8749f279043 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -13,9 +13,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
namespace blink {
@@ -112,6 +109,15 @@ CaretPositionResolution TryResolveCaretPositionInTextFragment(
if (offset < start_offset &&
!mapping.HasBidiControlCharactersOnly(offset, start_offset))
return CaretPositionResolution();
+ if (affinity == TextAffinity::kUpstream && offset == current_offset.end + 1 &&
+ cursor.Current().Style().NeedsTrailingSpace() &&
+ cursor.Current().Style().IsCollapsibleWhiteSpace(
+ mapping.GetText()[offset - 1])) {
+ // |offset| is after soft line wrap, e.g. "abc |xyz".
+ // See http://crbug.com/1183269 and |AdjustForSoftLineWrap()|
+ return {ResolutionType::kResolved,
+ {cursor, NGCaretPositionType::kAtTextOffset, offset - 1}};
+ }
if (offset > current_offset.end &&
!mapping.HasBidiControlCharactersOnly(end_offset, offset))
return CaretPositionResolution();
@@ -316,9 +322,14 @@ NGCaretPosition ComputeNGCaretPosition(
const base::Optional<unsigned> maybe_offset =
mapping->GetTextContentOffset(position);
if (!maybe_offset.has_value()) {
- // TODO(xiaochengh): Investigate if we reach here.
- NOTREACHED();
- return NGCaretPosition();
+ // We can reach here with empty text nodes.
+ if (auto* data = DynamicTo<Text>(position.AnchorNode())) {
+ DCHECK_EQ(data->length(), 0u);
+ } else {
+ // TODO(xiaochengh): Investigate if we reach here.
+ NOTREACHED();
+ return NGCaretPosition();
+ }
}
const LayoutText* const layout_text =
@@ -327,9 +338,19 @@ NGCaretPosition ComputeNGCaretPosition(
*position.AnchorNode(), position.OffsetInContainerNode()))
: nullptr;
- const unsigned offset = *maybe_offset;
+ const unsigned offset = maybe_offset.value_or(0);
const TextAffinity affinity = position_with_affinity.Affinity();
- return ComputeNGCaretPosition(*context, offset, affinity, layout_text);
+ // For upstream position, we use offset before ZWS to distinguish downstream
+ // and upstream position when line breaking before ZWS.
+ // " Zabc" where "Z" represents zero-width-space.
+ // See AccessibilitySelectionTest.FromCurrentSelectionInTextareaWithAffinity
+ const unsigned adjusted_offset =
+ affinity == TextAffinity::kUpstream && offset &&
+ mapping->GetText()[offset - 1] == kZeroWidthSpaceCharacter
+ ? offset - 1
+ : offset;
+ return ComputeNGCaretPosition(*context, adjusted_offset, affinity,
+ layout_text);
}
Position NGCaretPosition::ToPositionInDOMTree() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
index 1326d5ffa10..c5102e727b2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
@@ -30,6 +30,9 @@ struct NGCaretPosition {
STACK_ALLOCATED();
public:
+ explicit operator bool() const { return IsNotNull(); }
+
+ bool IsNotNull() const { return cursor.IsNotNull(); }
bool IsNull() const { return cursor.IsNull(); }
Position ToPositionInDOMTree() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
index e7651f7436e..5416b97e1f2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
@@ -289,6 +289,94 @@ TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) {
fragment_d, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
}
+TEST_F(NGCaretPositionTest, GeneratedZeroWidthSpace) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 4ch; white-space: pre-wrap;");
+ // We have ZWS before "abc" due by "pre-wrap".
+ // text content is
+ // [0..3] " "
+ // [4] ZWS
+ // [5..8] "abcd"
+ SetBodyInnerHTML("<p id=t> abcd</p>");
+ const Text& text = To<Text>(*GetElementById("t")->firstChild());
+ const Position after_zws(text, 4); // before "a".
+
+ NGInlineCursor cursor;
+ cursor.MoveTo(*text.GetLayoutObject());
+
+ ASSERT_EQ(NGTextOffset(0, 4), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(after_zws, TextAffinity::kUpstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(4));
+
+ cursor.MoveToNextForSameLayoutObject();
+ ASSERT_EQ(NGTextOffset(5, 9), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(after_zws, TextAffinity::kDownstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(5));
+}
+
+// http://crbug.com/1183269
+// See also NGCaretPositionTest.CaretPositionAtSoftLineWrap
+TEST_F(NGCaretPositionTest, SoftLineWrap) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 4ch;");
+ // Note: "contenteditable" adds
+ // line-break: after-white-space;
+ // overflow-wrap: break-word;
+ SetBodyInnerHTML("<p id=t contenteditable>abc xyz</p>");
+ const Text& text = To<Text>(*GetElementById("t")->firstChild());
+ const Position before_xyz(text, 4); // before "w".
+
+ NGInlineCursor cursor;
+ cursor.MoveTo(*text.GetLayoutObject());
+
+ // Note: upstream/downstream before "xyz" are in different line.
+
+ ASSERT_EQ(NGTextOffset(0, 3), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(before_xyz, TextAffinity::kUpstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(3));
+
+ cursor.MoveToNextForSameLayoutObject();
+ ASSERT_EQ(NGTextOffset(4, 7), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(before_xyz, TextAffinity::kDownstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(4));
+}
+
+TEST_F(NGCaretPositionTest, ZeroWidthSpace) {
+ LoadAhem();
+ InsertStyleElement(
+ "p { font: 10px/1 Ahem; }"
+ "p { width: 4ch;");
+ // dom and text content is
+ // [0..3] "abcd"
+ // [4] ZWS
+ // [5..8] "wxyz"
+ SetBodyInnerHTML("<p id=t>abcd&#x200B;wxyz</p>");
+ const Text& text = To<Text>(*GetElementById("t")->firstChild());
+ const Position after_zws(text, 5); // before "w".
+
+ NGInlineCursor cursor;
+ cursor.MoveTo(*text.GetLayoutObject());
+
+ ASSERT_EQ(NGTextOffset(0, 5), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(after_zws, TextAffinity::kUpstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(4));
+
+ cursor.MoveToNextForSameLayoutObject();
+ ASSERT_EQ(NGTextOffset(5, 9), cursor.Current().TextOffset());
+ TEST_CARET(blink::ComputeNGCaretPosition(
+ PositionWithAffinity(after_zws, TextAffinity::kDownstream)),
+ cursor, kAtTextOffset, base::Optional<unsigned>(5));
+}
+
TEST_F(NGCaretPositionTest, InlineBlockBeforeContent) {
SetInlineFormattingContext(
"t",
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
index 32f2ecf46bc..393a2e03c09 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
@@ -22,8 +22,8 @@ PhysicalRect ComputeLocalCaretRectByBoxSide(const NGInlineCursor& cursor,
line_box.MoveToContainingLine();
DCHECK(line_box);
const PhysicalOffset offset_to_line_box =
- cursor.Current().OffsetInContainerBlock() -
- line_box.Current().OffsetInContainerBlock();
+ cursor.Current().OffsetInContainerFragment() -
+ line_box.Current().OffsetInContainerFragment();
LayoutUnit caret_height = is_horizontal ? line_box.Current().Size().height
: line_box.Current().Size().width;
LayoutUnit caret_top =
@@ -100,20 +100,18 @@ PhysicalRect ComputeLocalCaretRectAtTextOffset(const NGInlineCursor& cursor,
// Adjust the location to be relative to the inline formatting context.
PhysicalOffset caret_location = PhysicalOffset(caret_left, caret_top) +
- cursor.Current().OffsetInContainerBlock();
+ cursor.Current().OffsetInContainerFragment();
const PhysicalSize caret_size(caret_width, caret_height);
- const NGPhysicalBoxFragment& fragment = cursor.BoxFragment();
+ const NGPhysicalBoxFragment& fragment = cursor.ContainerFragment();
NGInlineCursor line_box(cursor);
line_box.MoveToContainingLine();
const PhysicalOffset line_box_offset =
- line_box.Current().OffsetInContainerBlock();
+ line_box.Current().OffsetInContainerFragment();
const PhysicalRect line_box_rect(line_box_offset, line_box.Current().Size());
- const NGInlineBreakToken& break_token =
- *line_box.Current().InlineBreakToken();
- const bool is_last_line =
- break_token.IsFinished() || break_token.IsForcedBreak();
+ const NGInlineBreakToken* break_token = line_box.Current().InlineBreakToken();
+ const bool is_last_line = !break_token || break_token->IsForcedBreak();
const ComputedStyle& block_style = fragment.Style();
bool should_align_caret_right =
ShouldAlignCaretRight(block_style.GetTextAlign(is_last_line),
@@ -151,6 +149,8 @@ PhysicalRect ComputeLocalCaretRectAtTextOffset(const NGInlineCursor& cursor,
return PhysicalRect(caret_location, caret_size);
}
+} // namespace
+
LocalCaretRect ComputeLocalCaretRect(const NGCaretPosition& caret_position) {
if (caret_position.IsNull())
return LocalCaretRect();
@@ -192,24 +192,13 @@ LocalCaretRect ComputeLocalSelectionRect(
PhysicalRect rect = caret_rect.rect;
if (caret_position.cursor.Current().Style().IsHorizontalWritingMode()) {
- rect.SetY(line_box.Current().OffsetInContainerBlock().top);
+ rect.SetY(line_box.Current().OffsetInContainerFragment().top);
rect.SetHeight(line_box.Current().Size().height);
} else {
- rect.SetX(line_box.Current().OffsetInContainerBlock().left);
+ rect.SetX(line_box.Current().OffsetInContainerFragment().left);
rect.SetHeight(line_box.Current().Size().width);
}
return {caret_rect.layout_object, rect};
}
-} // namespace
-
-LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity& position) {
- return ComputeLocalCaretRect(ComputeNGCaretPosition(position));
-}
-
-LocalCaretRect ComputeNGLocalSelectionRect(
- const PositionWithAffinity& position) {
- return ComputeLocalSelectionRect(ComputeNGCaretPosition(position));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
index 47db5da2c0b..f962ccc6a15 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
@@ -13,17 +13,14 @@ namespace blink {
// This file provides utility functions for computing caret rect in LayoutNG.
struct LocalCaretRect;
+struct NGCaretPosition;
-// Given a position with affinity, returns the caret rect if the position is
-// laid out with LayoutNG, and a caret can be placed at the position with the
-// given affinity. The caret rect location is local to the containing inline
-// formatting context.
-CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity&);
+// Given a position, returns the caret rect.
+LocalCaretRect ComputeLocalCaretRect(const NGCaretPosition&);
// Almost the same as ComputeNGLocalCaretRect, except that the returned rect
// is adjusted to span the containing line box in the block direction.
-CORE_EXPORT LocalCaretRect
-ComputeNGLocalSelectionRect(const PositionWithAffinity&);
+LocalCaretRect ComputeLocalSelectionRect(const NGCaretPosition&);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index 4aea0228f19..1e24ddad785 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
namespace blink {
@@ -34,34 +35,6 @@ ASSERT_SIZE(NGFragmentItem, SameSizeAsNGFragmentItem);
} // namespace
-NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text)
- : layout_object_(text.GetLayoutObject()),
- text_({text.TextShapeResult(), text.TextOffset()}),
- rect_({PhysicalOffset(), text.Size()}),
- type_(kText),
- sub_type_(static_cast<unsigned>(text.TextType())),
- style_variant_(static_cast<unsigned>(text.StyleVariant())),
- is_hidden_for_paint_(text.IsHiddenForPaint()),
- text_direction_(static_cast<unsigned>(text.ResolvedDirection())),
- ink_overflow_type_(NGInkOverflow::kNotSet),
- is_dirty_(false),
- is_last_for_node_(true) {
-#if DCHECK_IS_ON()
- if (text_.shape_result) {
- DCHECK_EQ(text_.shape_result->StartIndex(), StartOffset());
- DCHECK_EQ(text_.shape_result->EndIndex(), EndOffset());
- }
-#endif
- if (text.TextType() == NGTextType::kLayoutGenerated) {
- type_ = kGeneratedText;
- // Note: Because of |text_| and |generated_text_| are in same union and
- // we initialize |text_| instead of |generated_text_|, we should construct
- // |generated_text_.text_| instead copying, |generated_text_.text = ...|.
- new (&generated_text_.text) String(text.Text().ToString());
- }
- DCHECK(!IsFormattingContextRoot());
-}
-
NGFragmentItem::NGFragmentItem(
const NGInlineItem& inline_item,
scoped_refptr<const ShapeResultView> shape_result,
@@ -90,32 +63,46 @@ NGFragmentItem::NGFragmentItem(
}
NGFragmentItem::NGFragmentItem(
- const NGInlineItem& inline_item,
+ const LayoutObject& layout_object,
+ NGTextType text_type,
+ NGStyleVariant style_variant,
+ TextDirection direction,
scoped_refptr<const ShapeResultView> shape_result,
const String& text_content,
const PhysicalSize& size,
bool is_hidden_for_paint)
- : layout_object_(inline_item.GetLayoutObject()),
+ : layout_object_(&layout_object),
generated_text_({std::move(shape_result), text_content}),
rect_({PhysicalOffset(), size}),
type_(kGeneratedText),
- sub_type_(static_cast<unsigned>(inline_item.TextType())),
- style_variant_(static_cast<unsigned>(inline_item.StyleVariant())),
+ sub_type_(static_cast<unsigned>(text_type)),
+ style_variant_(static_cast<unsigned>(style_variant)),
is_hidden_for_paint_(is_hidden_for_paint),
- text_direction_(static_cast<unsigned>(inline_item.Direction())),
+ text_direction_(static_cast<unsigned>(direction)),
ink_overflow_type_(NGInkOverflow::kNotSet),
is_dirty_(false),
is_last_for_node_(true) {
-#if DCHECK_IS_ON()
- if (text_.shape_result) {
- DCHECK_EQ(text_.shape_result->StartIndex(), StartOffset());
- DCHECK_EQ(text_.shape_result->EndIndex(), EndOffset());
- }
-#endif
- DCHECK_EQ(TextType(), NGTextType::kLayoutGenerated);
+ DCHECK(layout_object_);
+ DCHECK_EQ(TextShapeResult()->StartIndex(), StartOffset());
+ DCHECK_EQ(TextShapeResult()->EndIndex(), EndOffset());
DCHECK(!IsFormattingContextRoot());
}
+NGFragmentItem::NGFragmentItem(
+ const NGInlineItem& inline_item,
+ scoped_refptr<const ShapeResultView> shape_result,
+ const String& text_content,
+ const PhysicalSize& size,
+ bool is_hidden_for_paint)
+ : NGFragmentItem(*inline_item.GetLayoutObject(),
+ inline_item.TextType(),
+ inline_item.StyleVariant(),
+ inline_item.Direction(),
+ std::move(shape_result),
+ text_content,
+ size,
+ is_hidden_for_paint) {}
+
NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line)
: layout_object_(line.ContainerLayoutObject()),
line_({&line, /* descendants_count */ 1}),
@@ -150,11 +137,6 @@ NGFragmentItem::NGFragmentItem(NGLogicalLineItem&& line_item,
WritingMode writing_mode) {
DCHECK(line_item.CanCreateFragmentItem());
- if (line_item.text_fragment) {
- new (this) NGFragmentItem(*line_item.text_fragment);
- return;
- }
-
if (line_item.inline_item) {
if (UNLIKELY(line_item.text_content)) {
new (this) NGFragmentItem(
@@ -180,6 +162,17 @@ NGFragmentItem::NGFragmentItem(NGLogicalLineItem&& line_item,
return;
}
+ if (line_item.layout_object) {
+ const TextDirection direction = line_item.shape_result->Direction();
+ new (this) NGFragmentItem(
+ *line_item.layout_object, NGTextType::kLayoutGenerated,
+ line_item.style_variant, direction, std::move(line_item.shape_result),
+ line_item.text_content,
+ ToPhysicalSize(line_item.MarginSize(), writing_mode),
+ line_item.is_hidden_for_paint);
+ return;
+ }
+
// CanCreateFragmentItem()
NOTREACHED();
CHECK(false);
@@ -484,7 +477,6 @@ String NGFragmentItem::ToString() const {
PhysicalRect NGFragmentItem::LocalVisualRectFor(
const LayoutObject& layout_object) {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
PhysicalRect visual_rect;
@@ -496,7 +488,7 @@ PhysicalRect NGFragmentItem::LocalVisualRectFor(
if (UNLIKELY(item.IsHiddenForPaint()))
continue;
PhysicalRect child_visual_rect = item.SelfInkOverflow();
- child_visual_rect.offset += item.OffsetInContainerBlock();
+ child_visual_rect.offset += item.OffsetInContainerFragment();
visual_rect.Unite(child_visual_rect);
}
return visual_rect;
@@ -526,7 +518,7 @@ PhysicalRect NGFragmentItem::RecalcInkOverflowForCursor(
PhysicalRect child_rect;
item->GetMutableForPainting().RecalcInkOverflow(*cursor, &child_rect);
if (!child_rect.IsEmpty()) {
- child_rect.offset += item->OffsetInContainerBlock();
+ child_rect.offset += item->OffsetInContainerFragment();
contents_ink_overflow.Unite(child_rect);
}
}
@@ -584,7 +576,7 @@ void NGFragmentItem::RecalcInkOverflow(
// |contents_rect| is relative to the inline formatting context. Make it
// relative to |this|.
- contents_rect.offset -= OffsetInContainerBlock();
+ contents_rect.offset -= OffsetInContainerFragment();
if (Type() == kLine) {
// Line boxes don't have self overflow. Compute content overflow only.
@@ -612,6 +604,85 @@ void NGFragmentItem::SetDeltaToNextForSameLayoutObject(wtf_size_t delta) const {
delta_to_next_for_same_layout_object_ = delta;
}
+// Compute the inline position from text offset, in logical coordinate relative
+// to this fragment.
+LayoutUnit NGFragmentItem::InlinePositionForOffset(
+ StringView text,
+ unsigned offset,
+ LayoutUnit (*round_function)(float),
+ AdjustMidCluster adjust_mid_cluster) const {
+ DCHECK_GE(offset, StartOffset());
+ DCHECK_LE(offset, EndOffset());
+ DCHECK_EQ(text.length(), TextLength());
+
+ offset -= StartOffset();
+ if (TextShapeResult()) {
+ // TODO(layout-dev): Move caret position out of ShapeResult and into a
+ // separate support class that can take a ShapeResult or ShapeResultView.
+ // Allows for better code separation and avoids the extra copy below.
+ return round_function(
+ TextShapeResult()->CreateShapeResult()->CaretPositionForOffset(
+ offset, text, adjust_mid_cluster));
+ }
+
+ // This fragment is a flow control because otherwise ShapeResult exists.
+ DCHECK(IsFlowControl());
+ DCHECK_EQ(1u, text.length());
+ if (!offset || UNLIKELY(IsRtl(Style().Direction())))
+ return LayoutUnit();
+ return IsHorizontal() ? Size().width : Size().height;
+}
+
+LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text,
+ unsigned offset) const {
+ return InlinePositionForOffset(text, offset, LayoutUnit::FromFloatRound,
+ AdjustMidCluster::kToEnd);
+}
+
+std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets(
+ StringView text,
+ unsigned start_offset,
+ unsigned end_offset) const {
+ DCHECK_LE(start_offset, EndOffset());
+ DCHECK_GE(start_offset, StartOffset());
+ DCHECK_LE(end_offset, EndOffset());
+
+ const LayoutUnit start_position =
+ InlinePositionForOffset(text, start_offset, LayoutUnit::FromFloatFloor,
+ AdjustMidCluster::kToStart);
+ const LayoutUnit end_position = InlinePositionForOffset(
+ text, end_offset, LayoutUnit::FromFloatCeil, AdjustMidCluster::kToEnd);
+
+ // Swap positions if RTL.
+ return (UNLIKELY(start_position > end_position))
+ ? std::make_pair(end_position, start_position)
+ : std::make_pair(start_position, end_position);
+}
+
+PhysicalRect NGFragmentItem::LocalRect(StringView text,
+ unsigned start_offset,
+ unsigned end_offset) const {
+ if (start_offset == StartOffset() && end_offset == EndOffset())
+ return LocalRect();
+ LayoutUnit start_position, end_position;
+ std::tie(start_position, end_position) =
+ LineLeftAndRightForOffsets(text, start_offset, end_offset);
+ const LayoutUnit inline_size = end_position - start_position;
+ switch (GetWritingMode()) {
+ case WritingMode::kHorizontalTb:
+ return {start_position, LayoutUnit(), inline_size, Size().height};
+ case WritingMode::kVerticalRl:
+ case WritingMode::kVerticalLr:
+ case WritingMode::kSidewaysRl:
+ return {LayoutUnit(), start_position, Size().width, inline_size};
+ case WritingMode::kSidewaysLr:
+ return {LayoutUnit(), Size().height - end_position, Size().width,
+ inline_size};
+ }
+ NOTREACHED();
+ return {};
+}
+
PositionWithAffinity NGFragmentItem::PositionForPointInText(
const PhysicalOffset& point,
const NGInlineCursor& cursor) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
index 96457d5a29b..795317f9378 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_type.h"
#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -20,7 +21,6 @@ namespace blink {
class NGFragmentItems;
class NGInlineBreakToken;
-class NGPhysicalTextFragment;
struct NGTextFragmentPaintInfo;
struct NGLogicalLineItem;
@@ -70,9 +70,6 @@ class CORE_EXPORT NGFragmentItem {
// Create appropriate type for |line_item|.
NGFragmentItem(NGLogicalLineItem&& line_item, WritingMode writing_mode);
- // Create a text item.
- // TODO(kojii): Should be able to create without once creating fragments.
- explicit NGFragmentItem(const NGPhysicalTextFragment& text);
// Create a box item.
NGFragmentItem(const NGPhysicalBoxFragment& box,
TextDirection resolved_direction);
@@ -160,8 +157,10 @@ class CORE_EXPORT NGFragmentItem {
}
void SetDeltaToNextForSameLayoutObject(wtf_size_t delta) const;
- const PhysicalRect& RectInContainerBlock() const { return rect_; }
- const PhysicalOffset& OffsetInContainerBlock() const { return rect_.offset; }
+ const PhysicalRect& RectInContainerFragment() const { return rect_; }
+ const PhysicalOffset& OffsetInContainerFragment() const {
+ return rect_.offset;
+ }
const PhysicalSize& Size() const { return rect_.size; }
PhysicalRect LocalRect() const { return {PhysicalOffset(), Size()}; }
void SetOffset(const PhysicalOffset& offset) { rect_.offset = offset; }
@@ -402,6 +401,14 @@ class CORE_EXPORT NGFragmentItem {
const String& text_content,
const PhysicalSize& size,
bool is_hidden_for_paint);
+ NGFragmentItem(const LayoutObject& layout_object,
+ NGTextType text_type,
+ NGStyleVariant style_variant,
+ TextDirection direction,
+ scoped_refptr<const ShapeResultView> shape_result,
+ const String& text_content,
+ const PhysicalSize& size,
+ bool is_hidden_for_paint);
NGInkOverflow::Type InkOverflowType() const {
return static_cast<NGInkOverflow::Type>(ink_overflow_type_);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
index c1cdf0bb595..a7b3e72b40e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
@@ -21,12 +21,9 @@ namespace blink {
// We enable LayoutNGFragmentTraversal here, so that we get the "first/last for
// node" bits set as appropriate.
class NGFragmentItemTest : public NGLayoutTest,
- ScopedLayoutNGFragmentItemForTest,
ScopedLayoutNGFragmentTraversalForTest {
public:
- NGFragmentItemTest()
- : ScopedLayoutNGFragmentItemForTest(true),
- ScopedLayoutNGFragmentTraversalForTest(true) {}
+ NGFragmentItemTest() : ScopedLayoutNGFragmentTraversalForTest(true) {}
void ForceLayout() { RunDocumentLifecycle(); }
@@ -175,14 +172,14 @@ TEST_F(NGFragmentItemTest, BasicText) {
const NGFragmentItem& text1 = *items_for_text[0];
EXPECT_EQ(text1.Type(), NGFragmentItem::kText);
EXPECT_EQ(text1.GetLayoutObject(), layout_text);
- EXPECT_EQ(text1.OffsetInContainerBlock(), PhysicalOffset());
+ EXPECT_EQ(text1.OffsetInContainerFragment(), PhysicalOffset());
EXPECT_TRUE(text1.IsFirstForNode());
EXPECT_FALSE(text1.IsLastForNode());
const NGFragmentItem& text2 = *items_for_text[1];
EXPECT_EQ(text2.Type(), NGFragmentItem::kText);
EXPECT_EQ(text2.GetLayoutObject(), layout_text);
- EXPECT_EQ(text2.OffsetInContainerBlock(), PhysicalOffset(0, 10));
+ EXPECT_EQ(text2.OffsetInContainerFragment(), PhysicalOffset(0, 10));
EXPECT_FALSE(text2.IsFirstForNode());
EXPECT_TRUE(text2.IsLastForNode());
}
@@ -282,12 +279,12 @@ TEST_F(NGFragmentItemTest, BasicInlineBox) {
EXPECT_TRUE(items_for_span1[0]->IsFirstForNode());
EXPECT_FALSE(items_for_span1[0]->IsLastForNode());
EXPECT_EQ(PhysicalOffset(40, 0),
- items_for_span1[0]->OffsetInContainerBlock());
+ items_for_span1[0]->OffsetInContainerFragment());
EXPECT_EQ(PhysicalRect(0, 0, 40, 10), items_for_span1[0]->InkOverflow());
EXPECT_FALSE(items_for_span1[1]->IsFirstForNode());
EXPECT_TRUE(items_for_span1[1]->IsLastForNode());
EXPECT_EQ(PhysicalOffset(0, 10),
- items_for_span1[1]->OffsetInContainerBlock());
+ items_for_span1[1]->OffsetInContainerFragment());
EXPECT_EQ(PhysicalRect(0, 0, 40, 10), items_for_span1[1]->InkOverflow());
// "span2" doesn't wrap, produces only one fragment.
@@ -298,7 +295,7 @@ TEST_F(NGFragmentItemTest, BasicInlineBox) {
EXPECT_TRUE(items_for_span2[0]->IsFirstForNode());
EXPECT_TRUE(items_for_span2[0]->IsLastForNode());
EXPECT_EQ(PhysicalOffset(0, 20),
- items_for_span2[0]->OffsetInContainerBlock());
+ items_for_span2[0]->OffsetInContainerFragment());
EXPECT_EQ(PhysicalRect(0, 0, 80, 10), items_for_span2[0]->InkOverflow());
}
@@ -796,4 +793,27 @@ TEST_F(NGFragmentItemTest, MarkLineBoxesDirtyInsideInlineBlock) {
TestFirstDirtyLineIndex("container", 0);
}
+// This test creates various types of |NGFragmentItem| to check "natvis" (Native
+// DebugVisualizers) for Windows Visual Studio.
+TEST_F(NGFragmentItemTest, Disabled_DebugVisualizers) {
+ SetBodyInnerHTML(R"HTML(
+ <div id=container>
+ text
+ <span style="display: inline-block"></span>
+ </div>
+ )HTML");
+ auto* container =
+ To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
+ NGInlineCursor cursor(*container);
+ cursor.MoveToFirstLine();
+ const NGFragmentItem* line = cursor.Current().Item();
+ EXPECT_NE(line, nullptr);
+ cursor.MoveToNext();
+ const NGFragmentItem* text = cursor.Current().Item();
+ EXPECT_NE(text, nullptr);
+ cursor.MoveToNext();
+ const NGFragmentItem* box = cursor.Current().Item();
+ EXPECT_NE(box, nullptr);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
index b5956a798f7..08790532978 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
@@ -240,9 +240,7 @@ const NGFragmentItem* NGFragmentItems::EndOfReusableItems(
// partial. Remove the last fragment if it is the end of the
// fragmentation to do so, but we should figure out how to setup the
// states without doing this.
- const NGBreakToken* break_token = line_box_fragment->BreakToken();
- DCHECK(break_token);
- if (break_token->IsFinished())
+ if (!line_box_fragment->BreakToken())
return &item;
last_line_start = &item;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
index de7782fd77b..38d9deae3e0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
@@ -246,7 +246,7 @@ NGFragmentItemsBuilder::AddPreviousItems(
DCHECK(!item.IsDirty());
const LogicalOffset item_offset =
- converter.ToLogical(item.OffsetInContainerBlock(), item.Size());
+ converter.ToLogical(item.OffsetInContainerFragment(), item.Size());
if (item.Type() == NGFragmentItem::kLine) {
DCHECK(item.LineBoxFragment());
@@ -255,7 +255,7 @@ NGFragmentItemsBuilder::AddPreviousItems(
const NGPhysicalLineBoxFragment* line_fragment = item.LineBoxFragment();
const NGInlineBreakToken* break_token =
To<NGInlineBreakToken>(line_fragment->BreakToken());
- DCHECK(!break_token->IsFinished());
+ DCHECK(break_token);
const NGInlineItemsData* current_items_data;
if (UNLIKELY(break_token->UseFirstLineStyle()))
current_items_data = &node_.ItemsData(true);
@@ -276,7 +276,7 @@ NGFragmentItemsBuilder::AddPreviousItems(
}
items_.emplace_back(item_offset, item);
- const PhysicalRect line_box_bounds = item.RectInContainerBlock();
+ const PhysicalRect line_box_bounds = item.RectInContainerFragment();
line_converter.SetOuterSize(line_box_bounds.size);
for (NGInlineCursor line = cursor.CursorForDescendants(); line;
line.MoveToNext()) {
@@ -284,7 +284,7 @@ NGFragmentItemsBuilder::AddPreviousItems(
DCHECK(line_child.CanReuse());
items_.emplace_back(
line_converter.ToLogical(
- line_child.OffsetInContainerBlock() - line_box_bounds.offset,
+ line_child.OffsetInContainerFragment() - line_box_bounds.offset,
line_child.Size()),
line_child);
}
@@ -302,7 +302,6 @@ NGFragmentItemsBuilder::AddPreviousItems(
DCHECK_LE(items_.size(), estimated_size);
if (end_item && last_break_token) {
- DCHECK(!last_break_token->IsFinished());
DCHECK_GT(line_count, 0u);
DCHECK(!max_lines || line_count <= max_lines);
return AddPreviousItemsResult{last_break_token, used_block_size, line_count,
@@ -341,7 +340,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) {
unsigned descendants_count = item->DescendantsCount();
DCHECK(descendants_count);
if (descendants_count) {
- const PhysicalRect line_box_bounds = item->RectInContainerBlock();
+ const PhysicalRect line_box_bounds = item->RectInContainerFragment();
line_converter.SetOuterSize(line_box_bounds.size);
while (--descendants_count) {
++iter;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder_test.cc
index e4818069205..69cbb87e8df 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder_test.cc
@@ -17,11 +17,7 @@ using testing::ElementsAre;
namespace blink {
-class NGFragmentItemsBuilderTest : public NGLayoutTest,
- ScopedLayoutNGFragmentItemForTest {
- public:
- NGFragmentItemsBuilderTest() : ScopedLayoutNGFragmentItemForTest(true) {}
-};
+class NGFragmentItemsBuilderTest : public NGLayoutTest {};
TEST_F(NGFragmentItemsBuilderTest, MultipleLogicalLineItems) {
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index e95eb12862c..b257014513c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -8,8 +8,6 @@
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
@@ -681,28 +679,15 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
continue;
}
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // Propagate any OOF-positioned descendants from any atomic-inlines, etc.
- if (child.layout_result) {
- box.PropagateChildData(child.layout_result->PhysicalFragment(),
- child.rect.offset - rect.offset);
- }
-
- // |NGFragmentItems| has a flat list of all descendants, except
- // OOF-positioned descendants.
- // We still create a |NGPhysicalBoxFragment|, but don't add children to
- // it and keep them in the flat list.
- continue;
- }
-
+ // Propagate any OOF-positioned descendants from any atomic-inlines, etc.
if (child.layout_result) {
- box.AddChild(child.layout_result->PhysicalFragment(),
- child.rect.offset - rect.offset);
- child.layout_result.reset();
- } else if (child.text_fragment) {
- box.AddChild(std::move(child.text_fragment),
- child.rect.offset - rect.offset);
+ box.PropagateChildData(child.layout_result->PhysicalFragment(),
+ child.rect.offset - rect.offset);
}
+
+ // |NGFragmentItems| has a flat list of all descendants, except
+ // OOF-positioned descendants. We still create a |NGPhysicalBoxFragment|,
+ // but don't add children to it and keep them in the flat list.
}
// Inline boxes that produce DisplayItemClient should do full paint
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
index 1542c1ae46a..e97cebd882e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
@@ -27,18 +27,13 @@ NGInlineBreakToken::NGInlineBreakToken(
unsigned item_index,
unsigned text_offset,
unsigned flags /* NGInlineBreakTokenFlags */)
- : NGBreakToken(kInlineBreakToken, kUnfinished, node),
+ : NGBreakToken(kInlineBreakToken, node),
style_(style),
item_index_(item_index),
text_offset_(text_offset) {
flags_ = flags;
}
-NGInlineBreakToken::NGInlineBreakToken(PassKey key, NGLayoutInputNode node)
- : NGBreakToken(kInlineBreakToken, kFinished, node),
- item_index_(0),
- text_offset_(0) {}
-
NGInlineBreakToken::~NGInlineBreakToken() = default;
#if DCHECK_IS_ON()
@@ -46,12 +41,10 @@ NGInlineBreakToken::~NGInlineBreakToken() = default;
String NGInlineBreakToken::ToString() const {
StringBuilder string_builder;
string_builder.Append(NGBreakToken::ToString());
- if (!IsFinished()) {
- string_builder.Append(
- String::Format(" index:%u offset:%u", ItemIndex(), TextOffset()));
- if (IsForcedBreak())
- string_builder.Append(" forced");
- }
+ string_builder.Append(
+ String::Format(" index:%u offset:%u", ItemIndex(), TextOffset()));
+ if (IsForcedBreak())
+ string_builder.Append(" forced");
return string_builder.ToString();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
index b3d0d769f56..0b6552cbe47 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
@@ -36,48 +36,35 @@ class CORE_EXPORT NGInlineBreakToken final : public NGBreakToken {
PassKey(), node, style, item_index, text_offset, flags));
}
- // Creates a break token for a node which cannot produce any more fragments.
- static scoped_refptr<NGInlineBreakToken> Create(NGLayoutInputNode node) {
- return base::AdoptRef(new NGInlineBreakToken(PassKey(), node));
- }
-
~NGInlineBreakToken() override;
// The style at the end of this break token. The next line should start with
// this style.
- const ComputedStyle* Style() const {
- DCHECK(!IsFinished());
- return style_.get();
- }
+ const ComputedStyle* Style() const { return style_.get(); }
unsigned ItemIndex() const {
- DCHECK(!IsFinished());
return item_index_;
}
unsigned TextOffset() const {
- DCHECK(!IsFinished());
return text_offset_;
}
bool UseFirstLineStyle() const {
- DCHECK(!IsFinished());
return flags_ & kUseFirstLineStyle;
}
bool IsForcedBreak() const {
- DCHECK(!IsFinished());
return flags_ & kIsForcedBreak;
}
// True if the current position has open tags that has `box-decoration-break:
// clone`. They should be cloned to the start of the next line.
bool HasClonedBoxDecorations() const {
- DCHECK(!IsFinished());
return flags_ & kHasClonedBoxDecorations;
}
- using PassKey = util::PassKey<NGInlineBreakToken>;
+ using PassKey = base::PassKey<NGInlineBreakToken>;
NGInlineBreakToken(PassKey,
NGInlineNode node,
const ComputedStyle*,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index 4665e1e0f48..15b18bf1dc5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -12,10 +12,9 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
namespace blink {
+class HTMLBRElement;
namespace {
@@ -23,10 +22,87 @@ bool IsBidiControl(StringView string) {
return string.length() == 1 && Character::IsBidiControl(string[0]);
}
+LogicalRect ExpandedSelectionRectForSoftLineBreakIfNeeded(
+ const LogicalRect& rect,
+ const NGInlineCursor& cursor,
+ const LayoutSelectionStatus& selection_status) {
+ // Expand paint rect if selection covers multiple lines and
+ // this fragment is at the end of line.
+ if (selection_status.line_break == SelectSoftLineBreak::kNotSelected)
+ return rect;
+ const LayoutBlockFlow* const layout_block_flow = cursor.GetLayoutBlockFlow();
+ if (layout_block_flow && layout_block_flow->ShouldTruncateOverflowingText())
+ return rect;
+ // Copy from InlineTextBoxPainter::PaintSelection.
+ const LayoutUnit space_width(cursor.Current().Style().GetFont().SpaceWidth());
+ return {rect.offset,
+ {rect.size.inline_size + space_width, rect.size.block_size}};
+}
+
+// Expands selection height so that the selection rect fills entire line.
+LogicalRect ExpandSelectionRectToLineHeight(
+ const LogicalRect& rect,
+ const LogicalRect& line_logical_rect) {
+ // Unite the rect only in the block direction.
+ const LayoutUnit selection_top =
+ std::min(rect.offset.block_offset, line_logical_rect.offset.block_offset);
+ const LayoutUnit selection_bottom =
+ std::max(rect.BlockEndOffset(), line_logical_rect.BlockEndOffset());
+ return {{rect.offset.inline_offset, selection_top},
+ {rect.size.inline_size, selection_bottom - selection_top}};
+}
+
+LogicalRect ExpandSelectionRectToLineHeight(const LogicalRect& rect,
+ const NGInlineCursor& cursor) {
+ NGInlineCursor line(cursor);
+ line.MoveToContainingLine();
+ const PhysicalRect line_physical_rect(
+ line.Current().OffsetInContainerFragment() -
+ cursor.Current().OffsetInContainerFragment(),
+ line.Current().Size());
+ return ExpandSelectionRectToLineHeight(
+ rect, cursor.Current().ConvertChildToLogical(line_physical_rect));
+}
+
+bool IsLastBRInPage(const LayoutObject& layout_object) {
+ return layout_object.IsBR() && !layout_object.NextInPreOrder();
+}
+
+bool ShouldIgnoreForPositionForPoint(const NGFragmentItem& item) {
+ switch (item.Type()) {
+ case NGFragmentItem::kBox:
+ if (auto* box_fragment = item.BoxFragment()) {
+ if (box_fragment->IsInlineBox()) {
+ // We ignore inline box to avoid to call |PositionForPointInChild()|
+ // with empty inline box, e.g. <div>ab<b></b></div>.
+ // // All/LayoutViewHitTestTest.EmptySpan needs this.
+ return true;
+ }
+ // Skip pseudo element ::before/::after
+ // All/LayoutViewHitTestTest.PseudoElementAfter* needs this.
+ return !item.GetLayoutObject()->NonPseudoNode();
+ }
+ // Skip virtually "culled" inline box, e.g. <span>foo</span>
+ // "editing/selection/shift-click.html" reaches here.
+ DCHECK(item.GetLayoutObject()->IsLayoutInline()) << item;
+ return true;
+ case NGFragmentItem::kGeneratedText:
+ return true;
+ case NGFragmentItem::kText:
+ // Returns true when |item.GetLayoutObject().IsStyleGenerated()|.
+ // All/LayoutViewHitTestTest.PseudoElementAfter* needs this.
+ return item.IsGeneratedText();
+ case NGFragmentItem::kLine:
+ NOTREACHED();
+ break;
+ }
+ return false;
+}
+
} // namespace
inline void NGInlineCursor::MoveToItem(const ItemsSpan::iterator& iter) {
- DCHECK(IsItemCursor());
+ DCHECK(HasRoot());
DCHECK(iter >= items_.begin() && iter <= items_.end());
if (iter != items_.end()) {
current_.Set(iter);
@@ -52,13 +128,6 @@ void NGInlineCursor::SetRoot(const NGPhysicalBoxFragment& box_fragment,
SetRoot(box_fragment, items, items.Items());
}
-void NGInlineCursor::SetRoot(const NGPaintFragment& root_paint_fragment) {
- DCHECK(&root_paint_fragment);
- DCHECK(!HasRoot());
- root_paint_fragment_ = &root_paint_fragment;
- current_.paint_fragment_ = root_paint_fragment.FirstChild();
-}
-
bool NGInlineCursor::TrySetRootFragmentItems() {
DCHECK(root_block_flow_);
DCHECK(!fragment_items_ || fragment_items_->Equals(items_));
@@ -86,11 +155,6 @@ void NGInlineCursor::SetRoot(const LayoutBlockFlow& block_flow) {
return;
}
- if (const NGPaintFragment* paint_fragment = block_flow.PaintFragment()) {
- SetRoot(*paint_fragment);
- return;
- }
-
// We reach here in case of |ScrollANchor::NotifyBeforeLayout()| via
// |LayoutText::PhysicalLinesBoundingBox()|
// See external/wpt/css/css-scroll-anchoring/wrapped-text.html
@@ -116,20 +180,12 @@ NGInlineCursor::NGInlineCursor(const NGPhysicalBoxFragment& box_fragment) {
SetRoot(box_fragment, *items);
}
-NGInlineCursor::NGInlineCursor(const NGPaintFragment& root_paint_fragment) {
- SetRoot(root_paint_fragment);
-}
-
NGInlineCursor::NGInlineCursor(const NGInlineBackwardCursor& backward_cursor)
: NGInlineCursor(backward_cursor.cursor_) {
MoveTo(backward_cursor.Current());
}
bool NGInlineCursor::operator==(const NGInlineCursor& other) const {
- if (root_paint_fragment_) {
- return root_paint_fragment_ == other.root_paint_fragment_ &&
- current_.paint_fragment_ == other.current_.paint_fragment_;
- }
if (current_.item_ != other.current_.item_)
return false;
DCHECK_EQ(items_.data(), other.items_.data());
@@ -140,23 +196,8 @@ bool NGInlineCursor::operator==(const NGInlineCursor& other) const {
}
const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
- if (IsPaintFragmentCursor()) {
- // |root_paint_fragment_| is either |LayoutBlockFlow| or |LayoutInline|.
- const NGPhysicalFragment& physical_fragment =
- root_paint_fragment_->PhysicalFragment();
- const LayoutObject* layout_object =
- physical_fragment.IsLineBox()
- ? To<NGPhysicalLineBoxFragment>(physical_fragment)
- .ContainerLayoutObject()
- : physical_fragment.GetLayoutObject();
- if (const LayoutBlockFlow* block_flow =
- DynamicTo<LayoutBlockFlow>(layout_object))
- return block_flow;
- DCHECK(layout_object->IsLayoutInline());
- return layout_object->ContainingNGBlockFlow();
- }
- if (IsItemCursor()) {
- DCHECK(root_box_fragment_);
+ DCHECK_EQ(HasRoot(), !!root_box_fragment_);
+ if (root_box_fragment_) {
const LayoutObject* layout_object =
root_box_fragment_->GetSelfOrContainerLayoutObject();
DCHECK(layout_object);
@@ -168,8 +209,6 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
}
bool NGInlineCursorPosition::HasChildren() const {
- if (paint_fragment_)
- return paint_fragment_->FirstChild();
if (item_)
return item_->HasChildren();
NOTREACHED();
@@ -177,8 +216,6 @@ bool NGInlineCursorPosition::HasChildren() const {
}
NGInlineCursor NGInlineCursor::CursorForDescendants() const {
- if (current_.paint_fragment_)
- return NGInlineCursor(*current_.paint_fragment_);
if (current_.item_) {
unsigned descendants_count = current_.item_->DescendantsCount();
if (descendants_count > 1) {
@@ -195,10 +232,6 @@ NGInlineCursor NGInlineCursor::CursorForDescendants() const {
}
void NGInlineCursor::ExpandRootToContainingBlock() {
- if (root_paint_fragment_) {
- root_paint_fragment_ = root_paint_fragment_->Root();
- return;
- }
if (fragment_items_) {
const unsigned index_diff = items_.data() - fragment_items_->Items().data();
DCHECK_LT(index_diff, fragment_items_->Items().size());
@@ -214,71 +247,7 @@ void NGInlineCursor::ExpandRootToContainingBlock() {
bool NGInlineCursorPosition::HasSoftWrapToNextLine() const {
DCHECK(IsLineBox());
const NGInlineBreakToken* break_token = InlineBreakToken();
- DCHECK(break_token);
- return !break_token->IsFinished() && !break_token->IsForcedBreak();
-}
-
-bool NGInlineCursorPosition::IsInlineBox() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsInlineBox();
- if (item_)
- return item_->IsInlineBox();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsAtomicInline() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsAtomicInline();
- if (item_)
- return item_->IsAtomicInline();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsEllipsis() const {
- if (paint_fragment_)
- return paint_fragment_->IsEllipsis();
- if (item_)
- return item_->IsEllipsis();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsGeneratedText() const {
- if (paint_fragment_) {
- if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- paint_fragment_->PhysicalFragment()))
- return text_fragment->IsGeneratedText();
- return false;
- }
- if (item_)
- return item_->IsGeneratedText();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsLayoutGeneratedText() const {
- if (paint_fragment_) {
- if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- paint_fragment_->PhysicalFragment())) {
- return text_fragment->TextType() == NGTextType::kLayoutGenerated;
- }
- return false;
- }
- if (item_)
- return item_->Type() == NGFragmentItem::kGeneratedText;
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsHiddenForPaint() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsHiddenForPaint();
- if (item_)
- return item_->IsHiddenForPaint();
- NOTREACHED();
- return false;
+ return break_token && !break_token->IsForcedBreak();
}
bool NGInlineCursorPosition::IsInlineLeaf() const {
@@ -291,6 +260,32 @@ bool NGInlineCursorPosition::IsInlineLeaf() const {
return !IsListMarker();
}
+bool NGInlineCursorPosition::IsPartOfCulledInlineBox(
+ const LayoutInline& layout_inline) const {
+ DCHECK(!layout_inline.ShouldCreateBoxFragment());
+ DCHECK(*this);
+ const LayoutObject* const layout_object = GetLayoutObject();
+ // We use |IsInline()| to exclude floating and out-of-flow objects.
+ if (!layout_object || !layout_object->IsInline() ||
+ layout_object->IsAtomicInlineLevel())
+ return false;
+ DCHECK(!layout_object->IsFloatingOrOutOfFlowPositioned());
+ DCHECK(!BoxFragment() || !BoxFragment()->IsFormattingContextRoot());
+ for (const LayoutObject* parent = layout_object->Parent(); parent;
+ parent = parent->Parent()) {
+ // Children of culled inline should be included.
+ if (parent == &layout_inline)
+ return true;
+ // Grand children should be included only if children are also culled.
+ if (const auto* parent_layout_inline = DynamicTo<LayoutInline>(parent)) {
+ if (!parent_layout_inline->ShouldCreateBoxFragment())
+ continue;
+ }
+ return false;
+ }
+ return false;
+}
+
bool NGInlineCursor::IsLastLineInInlineBlock() const {
DCHECK(Current().IsLineBox());
if (!GetLayoutBlockFlow()->IsAtomicInlineLevel())
@@ -306,37 +301,6 @@ bool NGInlineCursor::IsLastLineInInlineBlock() const {
}
}
-bool NGInlineCursorPosition::IsLineBreak() const {
- if (paint_fragment_) {
- if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- paint_fragment_->PhysicalFragment()))
- return text_fragment->IsLineBreak();
- return false;
- }
- if (item_)
- return IsText() && item_->IsLineBreak();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsListMarker() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsListMarker();
- if (item_)
- return item_->IsListMarker();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsText() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsText();
- if (item_)
- return item_->IsText();
- NOTREACHED();
- return false;
-}
-
bool NGInlineCursor::IsBeforeSoftLineBreak() const {
if (Current().IsLineBreak())
return false;
@@ -365,8 +329,6 @@ bool NGInlineCursor::IsBeforeSoftLineBreak() const {
}
bool NGInlineCursorPosition::CanHaveChildren() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsContainer();
if (item_) {
return item_->Type() == NGFragmentItem::kLine ||
(item_->Type() == NGFragmentItem::kBox && !item_->IsAtomicInline());
@@ -375,33 +337,8 @@ bool NGInlineCursorPosition::CanHaveChildren() const {
return false;
}
-bool NGInlineCursorPosition::IsEmptyLineBox() const {
- DCHECK(IsLineBox());
- if (paint_fragment_) {
- return To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
- .IsEmptyLineBox();
- }
- if (item_)
- return item_->IsEmptyLineBox();
- NOTREACHED();
- return false;
-}
-
-bool NGInlineCursorPosition::IsLineBox() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().IsLineBox();
- if (item_)
- return item_->Type() == NGFragmentItem::kLine;
- NOTREACHED();
- return false;
-}
-
TextDirection NGInlineCursorPosition::BaseDirection() const {
DCHECK(IsLineBox());
- if (paint_fragment_) {
- return To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
- .BaseDirection();
- }
if (item_)
return item_->BaseDirection();
NOTREACHED();
@@ -452,26 +389,6 @@ UBiDiLevel NGInlineCursorPosition::BidiLevel() const {
return 0;
}
-const NGPhysicalBoxFragment* NGInlineCursorPosition::BoxFragment() const {
- if (paint_fragment_) {
- return DynamicTo<NGPhysicalBoxFragment>(
- &paint_fragment_->PhysicalFragment());
- }
- if (item_)
- return item_->BoxFragment();
- NOTREACHED();
- return nullptr;
-}
-
-const DisplayItemClient* NGInlineCursorPosition::GetDisplayItemClient() const {
- if (paint_fragment_)
- return paint_fragment_;
- if (item_)
- return item_->GetDisplayItemClient();
- NOTREACHED();
- return nullptr;
-}
-
const DisplayItemClient* NGInlineCursorPosition::GetSelectionDisplayItemClient()
const {
if (const auto* client = GetLayoutObject()->GetSelectionDisplayItemClient())
@@ -479,94 +396,12 @@ const DisplayItemClient* NGInlineCursorPosition::GetSelectionDisplayItemClient()
return GetDisplayItemClient();
}
-wtf_size_t NGInlineCursorPosition::FragmentId() const {
- if (paint_fragment_)
- return 0;
- DCHECK(item_);
- return item_->FragmentId();
-}
-
-const NGInlineBreakToken* NGInlineCursorPosition::InlineBreakToken() const {
- DCHECK(IsLineBox());
- if (paint_fragment_) {
- return To<NGInlineBreakToken>(
- To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
- .BreakToken());
- }
- DCHECK(item_);
- return item_->InlineBreakToken();
-}
-
-const LayoutObject* NGInlineCursorPosition::GetLayoutObject() const {
- if (paint_fragment_)
- return paint_fragment_->GetLayoutObject();
- if (item_)
- return item_->GetLayoutObject();
- NOTREACHED();
- return nullptr;
-}
-
-LayoutObject* NGInlineCursorPosition::GetMutableLayoutObject() const {
- if (paint_fragment_)
- return paint_fragment_->GetMutableLayoutObject();
- if (item_)
- return item_->GetMutableLayoutObject();
- NOTREACHED();
- return nullptr;
-}
-
const Node* NGInlineCursorPosition::GetNode() const {
if (const LayoutObject* layout_object = GetLayoutObject())
return layout_object->GetNode();
return nullptr;
}
-const PhysicalRect NGInlineCursorPosition::InkOverflow() const {
- if (paint_fragment_)
- return paint_fragment_->InkOverflow();
- if (item_)
- return item_->InkOverflow();
- NOTREACHED();
- return PhysicalRect();
-}
-
-const PhysicalOffset NGInlineCursorPosition::OffsetInContainerBlock() const {
- if (paint_fragment_)
- return paint_fragment_->OffsetInContainerBlock();
- if (item_)
- return item_->OffsetInContainerBlock();
- NOTREACHED();
- return PhysicalOffset();
-}
-
-const PhysicalSize NGInlineCursorPosition::Size() const {
- if (paint_fragment_)
- return paint_fragment_->Size();
- if (item_)
- return item_->Size();
- NOTREACHED();
- return PhysicalSize();
-}
-
-const PhysicalRect NGInlineCursorPosition::RectInContainerBlock() const {
- if (paint_fragment_) {
- return {paint_fragment_->OffsetInContainerBlock(), paint_fragment_->Size()};
- }
- if (item_)
- return item_->RectInContainerBlock();
- NOTREACHED();
- return PhysicalRect();
-}
-
-const PhysicalRect NGInlineCursorPosition::SelfInkOverflow() const {
- if (paint_fragment_)
- return paint_fragment_->SelfInkOverflow();
- if (item_)
- return item_->SelfInkOverflow();
- NOTREACHED();
- return PhysicalRect();
-}
-
void NGInlineCursorPosition::RecalcInkOverflow(
const NGInlineCursor& cursor) const {
DCHECK(item_);
@@ -576,76 +411,18 @@ void NGInlineCursorPosition::RecalcInkOverflow(
&self_and_contents_rect);
}
-TextDirection NGInlineCursorPosition::ResolvedDirection() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().ResolvedDirection();
- if (item_)
- return item_->ResolvedDirection();
- NOTREACHED();
- return TextDirection::kLtr;
-}
-
-const ComputedStyle& NGInlineCursorPosition::Style() const {
- if (paint_fragment_)
- return paint_fragment_->Style();
- return item_->Style();
-}
-
-NGStyleVariant NGInlineCursorPosition::StyleVariant() const {
- if (paint_fragment_)
- return paint_fragment_->PhysicalFragment().StyleVariant();
- return item_->StyleVariant();
-}
-
-bool NGInlineCursorPosition::UsesFirstLineStyle() const {
- return StyleVariant() == NGStyleVariant::kFirstLine;
-}
-
-NGTextOffset NGInlineCursorPosition::TextOffset() const {
- if (paint_fragment_) {
- const auto& text_fragment =
- To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment());
- return text_fragment.TextOffset();
- }
- if (item_)
- return item_->TextOffset();
- NOTREACHED();
- return {};
-}
-
StringView NGInlineCursorPosition::Text(const NGInlineCursor& cursor) const {
DCHECK(IsText());
cursor.CheckValid(*this);
- if (paint_fragment_) {
- return To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment())
- .Text();
- }
if (item_)
return item_->Text(cursor.Items());
NOTREACHED();
return "";
}
-const ShapeResultView* NGInlineCursorPosition::TextShapeResult() const {
- DCHECK(IsText());
- if (paint_fragment_) {
- return To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment())
- .TextShapeResult();
- }
- if (item_)
- return item_->TextShapeResult();
- NOTREACHED();
- return nullptr;
-}
-
PhysicalRect NGInlineCursor::CurrentLocalRect(unsigned start_offset,
unsigned end_offset) const {
DCHECK(Current().IsText());
- if (current_.paint_fragment_) {
- return To<NGPhysicalTextFragment>(
- current_.paint_fragment_->PhysicalFragment())
- .LocalRect(start_offset, end_offset);
- }
if (current_.item_) {
return current_.item_->LocalRect(current_.item_->Text(*fragment_items_),
start_offset, end_offset);
@@ -654,13 +431,50 @@ PhysicalRect NGInlineCursor::CurrentLocalRect(unsigned start_offset,
return PhysicalRect();
}
+PhysicalRect NGInlineCursor::CurrentLocalSelectionRectForText(
+ const LayoutSelectionStatus& selection_status) const {
+ const PhysicalRect selection_rect =
+ CurrentLocalRect(selection_status.start, selection_status.end);
+ LogicalRect logical_rect = Current().ConvertChildToLogical(selection_rect);
+ // Let LocalRect for line break have a space width to paint line break
+ // when it is only character in a line or only selected in a line.
+ if (selection_status.start != selection_status.end &&
+ Current().IsLineBreak() &&
+ // This is for old compatible that old doesn't paint last br in a page.
+ !IsLastBRInPage(*Current().GetLayoutObject())) {
+ DCHECK(!logical_rect.size.inline_size);
+ logical_rect.size.inline_size =
+ LayoutUnit(Current().Style().GetFont().SpaceWidth());
+ }
+ const LogicalRect line_break_extended_rect =
+ Current().IsLineBreak() ? logical_rect
+ : ExpandedSelectionRectForSoftLineBreakIfNeeded(
+ logical_rect, *this, selection_status);
+ const LogicalRect line_height_expanded_rect =
+ ExpandSelectionRectToLineHeight(line_break_extended_rect, *this);
+ const PhysicalRect physical_rect =
+ Current().ConvertChildToPhysical(line_height_expanded_rect);
+ return physical_rect;
+}
+
+PhysicalRect NGInlineCursor::CurrentLocalSelectionRectForReplaced() const {
+ DCHECK(Current().GetLayoutObject()->IsLayoutReplaced());
+ const PhysicalRect selection_rect = PhysicalRect({}, Current().Size());
+ LogicalRect logical_rect = Current().ConvertChildToLogical(selection_rect);
+ const LogicalRect line_height_expanded_rect =
+ ExpandSelectionRectToLineHeight(logical_rect, *this);
+ const PhysicalRect physical_rect =
+ Current().ConvertChildToPhysical(line_height_expanded_rect);
+ return physical_rect;
+}
+
PhysicalRect NGInlineCursor::CurrentRectInBlockFlow() const {
- PhysicalRect rect = Current().RectInContainerBlock();
+ PhysicalRect rect = Current().RectInContainerFragment();
// We'll now convert the offset from being relative to the containing fragment
// to being relative to the containing LayoutBlockFlow. For writing modes that
// don't flip the block direction, this is easy: just add the block-size
// consumed in previous fragments.
- auto writing_direction = BoxFragment().Style().GetWritingDirection();
+ auto writing_direction = ContainerFragment().Style().GetWritingDirection();
switch (writing_direction.GetWritingMode()) {
default:
rect.offset.top += previously_consumed_block_size_;
@@ -677,9 +491,9 @@ PhysicalRect NGInlineCursor::CurrentRectInBlockFlow() const {
const LayoutBlock* containing_block =
Current().GetLayoutObject()->ContainingBlock();
DCHECK_EQ(containing_block->StyleRef().GetWritingDirection(),
- BoxFragment().Style().GetWritingDirection());
+ ContainerFragment().Style().GetWritingDirection());
LogicalOffset logical_offset = rect.offset.ConvertToLogical(
- writing_direction, BoxFragment().Size(), rect.size);
+ writing_direction, ContainerFragment().Size(), rect.size);
LogicalOffset logical_offset_in_flow_thread(
logical_offset.inline_offset,
logical_offset.block_offset + previously_consumed_block_size_);
@@ -693,11 +507,6 @@ PhysicalRect NGInlineCursor::CurrentRectInBlockFlow() const {
LayoutUnit NGInlineCursor::InlinePositionForOffset(unsigned offset) const {
DCHECK(Current().IsText());
- if (current_.paint_fragment_) {
- return To<NGPhysicalTextFragment>(
- current_.paint_fragment_->PhysicalFragment())
- .InlinePositionForOffset(offset);
- }
if (current_.item_) {
return current_.item_->InlinePositionForOffset(
current_.item_->Text(*fragment_items_), offset);
@@ -723,7 +532,7 @@ PhysicalRect NGInlineCursorPosition::ConvertChildToPhysical(
PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
const PhysicalOffset& point,
const NGPhysicalBoxFragment& container) {
- DCHECK(IsItemCursor());
+ DCHECK(HasRoot());
const auto writing_direction = container.Style().GetWritingDirection();
const PhysicalSize& container_size = container.Size();
const LayoutUnit point_block_offset =
@@ -750,12 +559,12 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
if (!CursorForDescendants().TryToMoveToFirstInlineLeafChild()) {
// editing/selection/last-empty-inline.html requires this to skip
// empty <span> with padding.
- MoveToNextItemSkippingChildren();
+ MoveToNextSkippingChildren();
continue;
}
// Try to resolve if |point| falls in a line box in block direction.
const LayoutUnit child_block_offset =
- child_item->OffsetInContainerBlock()
+ child_item->OffsetInContainerFragment()
.ConvertToLogical(writing_direction, container_size,
child_item->Size())
.block_offset;
@@ -764,7 +573,7 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
closest_line_before_block_offset = child_block_offset;
closest_line_before = Current();
}
- MoveToNextItemSkippingChildren();
+ MoveToNextSkippingChildren();
continue;
}
@@ -779,18 +588,18 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
closest_line_after_block_offset = child_block_end_offset;
closest_line_after = Current();
}
- MoveToNextItemSkippingChildren();
+ MoveToNextSkippingChildren();
continue;
}
if (const PositionWithAffinity child_position =
PositionForPointInInlineBox(point))
return child_position;
- MoveToNextItemSkippingChildren();
+ MoveToNextSkippingChildren();
continue;
}
DCHECK_NE(child_item->Type(), NGFragmentItem::kText);
- MoveToNextItem();
+ MoveToNext();
}
// At here, |point| is not inside any line in |this|:
@@ -841,10 +650,6 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
const PhysicalOffset& point) const {
- if (const NGPaintFragment* paint_fragment = CurrentPaintFragment()) {
- DCHECK(paint_fragment->PhysicalFragment().IsLineBox());
- return paint_fragment->PositionForPoint(point);
- }
const NGFragmentItem* container = CurrentItem();
DCHECK(container);
DCHECK(container->Type() == NGFragmentItem::kLine ||
@@ -872,19 +677,16 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
for (; descendants; descendants.MoveToNext()) {
const NGFragmentItem* child_item = descendants.CurrentItem();
DCHECK(child_item);
- if (child_item->Type() == NGFragmentItem::kBox &&
- !child_item->BoxFragment()) {
- // Skip virtually "culled" inline box, e.g. <span>foo</span>
- // "editing/selection/shift-click.html" reaches here.
- DCHECK(child_item->GetLayoutObject()->IsLayoutInline()) << child_item;
+ if (ShouldIgnoreForPositionForPoint(*child_item))
continue;
- }
const LayoutUnit child_inline_offset =
- child_item->OffsetInContainerBlock()
+ child_item->OffsetInContainerFragment()
.ConvertToLogical(writing_direction, container_size,
child_item->Size())
.inline_offset;
if (point_inline_offset < child_inline_offset) {
+ if (child_item->IsFloating())
+ continue;
if (child_inline_offset < closest_child_after_inline_offset) {
closest_child_after_inline_offset = child_inline_offset;
closest_child_after = descendants.Current();
@@ -896,7 +698,9 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
child_item->Size()
.ConvertToLogical(writing_direction.GetWritingMode())
.inline_size;
- if (point_inline_offset > child_inline_end_offset) {
+ if (point_inline_offset >= child_inline_end_offset) {
+ if (child_item->IsFloating())
+ continue;
if (child_inline_end_offset > closest_child_before_inline_offset) {
closest_child_before_inline_offset = child_inline_end_offset;
closest_child_before = descendants.Current();
@@ -904,17 +708,25 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
continue;
}
+ // |point_inline_offset| is in |child_item|.
if (const PositionWithAffinity child_position =
descendants.PositionForPointInChild(point))
return child_position;
}
+ // Note: We don't snap a point before/after of "float" to "float",
+ // |closest_child_after| and |closest_child_before| can not be a box for
+ // "float".
+ // Note: Float boxes are appeared in |NGFragmentItems| as DOM order, so,
+ // "float:right" can be placed anywhere instead of at end of items.
+ // See LayoutViewHitTest.Float{Left,Right}*
if (closest_child_after) {
descendants.MoveTo(closest_child_after);
if (const PositionWithAffinity child_position =
descendants.PositionForPointInChild(point))
return child_position;
if (closest_child_after->BoxFragment()) {
+ DCHECK(!closest_child_after->IsFloating());
// Hit test at left of "12"[1] and after "cd"[2] reache here.
// "<span dir="rtl">12<b>&#x05E7;&#x05D0;43</b></span>ab"
// [1] "editing/selection/caret-at-bidi-boundary.html"
@@ -931,6 +743,7 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
descendants.PositionForPointInChild(point))
return child_position;
if (closest_child_before->BoxFragment()) {
+ DCHECK(!closest_child_before->IsFloating());
// LayoutViewHitTest.HitTestHorizontal "Top-right corner (outside) of div"
// reach here.
if (const PositionWithAffinity child_position =
@@ -944,17 +757,12 @@ PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
PositionWithAffinity NGInlineCursor::PositionForPointInChild(
const PhysicalOffset& point_in_container) const {
- if (auto* paint_fragment = CurrentPaintFragment()) {
- const PhysicalOffset point_in_child =
- point_in_container - paint_fragment->OffsetInContainerBlock();
- return paint_fragment->PositionForPoint(point_in_child);
- }
DCHECK(CurrentItem());
const NGFragmentItem& child_item = *CurrentItem();
switch (child_item.Type()) {
case NGFragmentItem::kText:
return child_item.PositionForPointInText(
- point_in_container - child_item.OffsetInContainerBlock(), *this);
+ point_in_container - child_item.OffsetInContainerFragment(), *this);
case NGFragmentItem::kGeneratedText:
break;
case NGFragmentItem::kBox:
@@ -966,7 +774,7 @@ PositionWithAffinity NGInlineCursor::PositionForPointInChild(
// Example: <b style="display:inline-block"><div>b</div></b>
// [1] NGInlineCursorTest.PositionForPointInChildBlockChildren
return child_item.GetLayoutObject()->PositionForPoint(
- point_in_container - child_item.OffsetInContainerBlock());
+ point_in_container - child_item.OffsetInContainerFragment());
}
} else {
// |LayoutInline| used to be culled.
@@ -983,9 +791,9 @@ PositionWithAffinity NGInlineCursor::PositionForPointInChild(
PositionWithAffinity NGInlineCursor::PositionForPointInText(
unsigned text_offset) const {
DCHECK(Current().IsText()) << this;
- if (IsItemCursor())
- return CurrentItem()->PositionForPointInText(text_offset, *this);
- return CurrentPaintFragment()->PositionForPointInText(text_offset);
+ if (HasRoot())
+ return Current()->PositionForPointInText(text_offset, *this);
+ return PositionWithAffinity();
}
PositionWithAffinity NGInlineCursor::PositionForStartOfLine() const {
@@ -1042,7 +850,7 @@ void NGInlineCursor::MoveTo(const NGInlineCursorPosition& position) {
}
inline wtf_size_t NGInlineCursor::SpanBeginItemIndex() const {
- DCHECK(IsItemCursor());
+ DCHECK(HasRoot());
DCHECK(!items_.empty());
DCHECK(fragment_items_->IsSubSpan(items_));
const wtf_size_t delta = items_.data() - fragment_items_->Items().data();
@@ -1051,7 +859,7 @@ inline wtf_size_t NGInlineCursor::SpanBeginItemIndex() const {
}
inline wtf_size_t NGInlineCursor::SpanIndexFromItemIndex(unsigned index) const {
- DCHECK(IsItemCursor());
+ DCHECK(HasRoot());
DCHECK(!items_.empty());
DCHECK(fragment_items_->IsSubSpan(items_));
if (items_.data() == fragment_items_->Items().data())
@@ -1063,7 +871,6 @@ inline wtf_size_t NGInlineCursor::SpanIndexFromItemIndex(unsigned index) const {
}
void NGInlineCursor::MoveTo(const NGFragmentItem& fragment_item) {
- DCHECK(!root_paint_fragment_ && !current_.paint_fragment_);
MoveTo(*fragment_item.GetLayoutObject());
while (IsNotNull()) {
if (CurrentItem() == &fragment_item)
@@ -1074,14 +881,10 @@ void NGInlineCursor::MoveTo(const NGFragmentItem& fragment_item) {
}
void NGInlineCursor::MoveTo(const NGInlineCursor& cursor) {
- if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
- MoveTo(*paint_fragment);
- return;
- }
if (cursor.current_.item_) {
if (!fragment_items_)
SetRoot(*cursor.root_box_fragment_, *cursor.fragment_items_);
- // Note: We use address instead of iterato because we can't compare
+ // Note: We use address instead of iterator because we can't compare
// iterators in different span. See |base::CheckedContiguousIterator<T>|.
const ptrdiff_t index = &*cursor.current_.item_iter_ - &*items_.begin();
DCHECK_GE(index, 0);
@@ -1092,52 +895,24 @@ void NGInlineCursor::MoveTo(const NGInlineCursor& cursor) {
*this = cursor;
}
-void NGInlineCursor::MoveTo(const NGPaintFragment& paint_fragment) {
- DCHECK(!fragment_items_);
- if (!root_paint_fragment_)
- root_paint_fragment_ = paint_fragment.Root();
- DCHECK(root_paint_fragment_);
- DCHECK(paint_fragment.IsDescendantOfNotSelf(*root_paint_fragment_))
- << paint_fragment << " " << root_paint_fragment_;
- current_.paint_fragment_ = &paint_fragment;
-}
-
-void NGInlineCursor::MoveTo(const NGPaintFragment* paint_fragment) {
- if (paint_fragment) {
- MoveTo(*paint_fragment);
- return;
- }
- MakeNull();
-}
-
void NGInlineCursor::MoveToContainingLine() {
DCHECK(!Current().IsLineBox());
- if (current_.paint_fragment_) {
- current_.paint_fragment_ = current_.paint_fragment_->ContainerLineBox();
- return;
- }
if (current_.item_) {
while (current_.item_ && !Current().IsLineBox())
- MoveToPreviousItem();
+ MoveToPrevious();
return;
}
NOTREACHED();
}
bool NGInlineCursor::IsAtFirst() const {
- if (const NGPaintFragment* paint_fragment = Current().PaintFragment())
- return paint_fragment == root_paint_fragment_->FirstChild();
if (const NGFragmentItem* item = Current().Item())
return item == &items_.front();
return false;
}
void NGInlineCursor::MoveToFirst() {
- if (root_paint_fragment_) {
- current_.paint_fragment_ = root_paint_fragment_->FirstChild();
- return;
- }
- if (IsItemCursor()) {
+ if (HasRoot()) {
MoveToItem(items_.begin());
return;
}
@@ -1151,11 +926,7 @@ void NGInlineCursor::MoveToFirstChild() {
}
void NGInlineCursor::MoveToFirstLine() {
- if (root_paint_fragment_) {
- MoveTo(root_paint_fragment_->FirstLineBox());
- return;
- }
- if (IsItemCursor()) {
+ if (HasRoot()) {
auto iter = std::find_if(
items_.begin(), items_.end(),
[](const auto& item) { return item.Type() == NGFragmentItem::kLine; });
@@ -1194,6 +965,12 @@ void NGInlineCursor::MoveToFirstNonPseudoLeaf() {
// <p dir=rtl>&#x202B;xyz ABC.&#x202C;</p>
// See "editing/selection/home-end.html".
DCHECK(!cursor.Current().IsLayoutGeneratedText()) << cursor;
+ if (cursor.Current().IsLineBreak()) {
+ // We ignore line break character, e.g. newline with white-space:pre,
+ // like |MoveToLastNonPseudoLeaf()| as consistency.
+ // See |ParameterizedVisibleUnitsLineTest.EndOfLineWithWhiteSpacePre|
+ continue;
+ }
*this = cursor;
return;
}
@@ -1212,7 +989,7 @@ void NGInlineCursor::MoveToLastChild() {
}
void NGInlineCursor::MoveToLastLine() {
- DCHECK(IsItemCursor());
+ DCHECK(HasRoot());
auto iter = std::find_if(
items_.rbegin(), items_.rend(),
[](const auto& item) { return item.Type() == NGFragmentItem::kLine; });
@@ -1275,11 +1052,6 @@ void NGInlineCursor::MoveToLastNonPseudoLeaf() {
}
*this = last_leaf;
}
-void NGInlineCursor::MoveToNext() {
- if (root_paint_fragment_)
- return MoveToNextPaintFragment();
- MoveToNextItem();
-}
void NGInlineCursor::MoveToNextInlineLeaf() {
if (Current() && Current().IsInlineLeaf())
@@ -1311,32 +1083,15 @@ void NGInlineCursor::MoveToNextInlineLeafOnLine() {
void NGInlineCursor::MoveToNextLine() {
DCHECK(Current().IsLineBox());
- if (current_.paint_fragment_) {
- if (auto* paint_fragment = current_.paint_fragment_->NextSibling())
- return MoveTo(*paint_fragment);
- return MakeNull();
- }
if (current_.item_) {
do {
- MoveToNextItem();
+ MoveToNext();
} while (Current() && !Current().IsLineBox());
return;
}
NOTREACHED();
}
-void NGInlineCursor::MoveToNextSkippingChildren() {
- if (root_paint_fragment_)
- return MoveToNextPaintFragmentSkippingChildren();
- MoveToNextItemSkippingChildren();
-}
-
-void NGInlineCursor::MoveToPrevious() {
- if (root_paint_fragment_)
- return MoveToPreviousPaintFragment();
- MoveToPreviousItem();
-}
-
void NGInlineCursor::MoveToPreviousInlineLeaf() {
if (Current() && Current().IsInlineLeaf())
MoveToPrevious();
@@ -1367,15 +1122,9 @@ void NGInlineCursor::MoveToPreviousInlineLeafOnLine() {
void NGInlineCursor::MoveToPreviousLine() {
// Note: List marker is sibling of line box.
DCHECK(Current().IsLineBox());
- if (current_.paint_fragment_) {
- do {
- MoveToPreviousSiblingPaintFragment();
- } while (Current() && !Current().IsLineBox());
- return;
- }
if (current_.item_) {
do {
- MoveToPreviousItem();
+ MoveToPrevious();
} while (Current() && !Current().IsLineBox());
return;
}
@@ -1385,10 +1134,6 @@ void NGInlineCursor::MoveToPreviousLine() {
bool NGInlineCursor::TryToMoveToFirstChild() {
if (!Current().HasChildren())
return false;
- if (root_paint_fragment_) {
- MoveTo(*current_.paint_fragment_->FirstChild());
- return true;
- }
MoveToItem(current_.item_iter_ + 1);
return true;
}
@@ -1405,12 +1150,8 @@ bool NGInlineCursor::TryToMoveToFirstInlineLeafChild() {
bool NGInlineCursor::TryToMoveToLastChild() {
if (!Current().HasChildren())
return false;
- if (root_paint_fragment_) {
- MoveTo(current_.paint_fragment_->Children().back());
- return true;
- }
const auto end = current_.item_iter_ + CurrentItem()->DescendantsCount();
- MoveToNextItem(); // Move to the first child.
+ MoveToNext(); // Move to the first child.
DCHECK(!IsNull());
while (true) {
ItemsSpan::iterator previous = Current().item_iter_;
@@ -1424,8 +1165,8 @@ bool NGInlineCursor::TryToMoveToLastChild() {
return true;
}
-void NGInlineCursor::MoveToNextItem() {
- DCHECK(IsItemCursor());
+void NGInlineCursor::MoveToNext() {
+ DCHECK(HasRoot());
if (UNLIKELY(!current_.item_))
return;
DCHECK(current_.item_iter_ != items_.end());
@@ -1436,19 +1177,19 @@ void NGInlineCursor::MoveToNextItem() {
MakeNull();
}
-void NGInlineCursor::MoveToNextItemSkippingChildren() {
- DCHECK(IsItemCursor());
+void NGInlineCursor::MoveToNextSkippingChildren() {
+ DCHECK(HasRoot());
if (UNLIKELY(!current_.item_))
return;
// If the current item has |DescendantsCount|, add it to move to the next
// sibling, skipping all children and their descendants.
if (wtf_size_t descendants_count = current_.item_->DescendantsCount())
return MoveToItem(current_.item_iter_ + descendants_count);
- return MoveToNextItem();
+ return MoveToNext();
}
-void NGInlineCursor::MoveToPreviousItem() {
- DCHECK(IsItemCursor());
+void NGInlineCursor::MoveToPrevious() {
+ DCHECK(HasRoot());
if (UNLIKELY(!current_.item_))
return;
if (current_.item_iter_ == items_.begin())
@@ -1457,71 +1198,8 @@ void NGInlineCursor::MoveToPreviousItem() {
current_.item_ = &*current_.item_iter_;
}
-void NGInlineCursor::MoveToParentPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- const NGPaintFragment* parent = current_.paint_fragment_->Parent();
- if (parent && parent != root_paint_fragment_) {
- current_.paint_fragment_ = parent;
- return;
- }
- current_.paint_fragment_ = nullptr;
-}
-
-void NGInlineCursor::MoveToNextPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- if (const NGPaintFragment* child = current_.paint_fragment_->FirstChild()) {
- current_.paint_fragment_ = child;
- return;
- }
- MoveToNextPaintFragmentSkippingChildren();
-}
-
-void NGInlineCursor::MoveToNextSiblingPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- if (const NGPaintFragment* next = current_.paint_fragment_->NextSibling()) {
- current_.paint_fragment_ = next;
- return;
- }
- current_.paint_fragment_ = nullptr;
-}
-
-void NGInlineCursor::MoveToNextPaintFragmentSkippingChildren() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- while (current_.paint_fragment_) {
- if (const NGPaintFragment* next = current_.paint_fragment_->NextSibling()) {
- current_.paint_fragment_ = next;
- return;
- }
- MoveToParentPaintFragment();
- }
-}
-
-void NGInlineCursor::MoveToPreviousPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- const NGPaintFragment* const parent = current_.paint_fragment_->Parent();
- MoveToPreviousSiblingPaintFragment();
- if (current_.paint_fragment_) {
- while (TryToMoveToLastChild())
- continue;
- return;
- }
- current_.paint_fragment_ = parent == root_paint_fragment_ ? nullptr : parent;
-}
-
-void NGInlineCursor::MoveToPreviousSiblingPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
- const NGPaintFragment* const current = current_.paint_fragment_;
- current_.paint_fragment_ = nullptr;
- for (auto* sibling : current->Parent()->Children()) {
- if (sibling == current)
- return;
- current_.paint_fragment_ = sibling;
- }
- NOTREACHED();
-}
-
void NGInlineCursor::MoveToFirstIncludingFragmentainer() {
- if (!fragment_index_ || IsPaintFragmentCursor()) {
+ if (!fragment_index_) {
MoveToFirst();
return;
}
@@ -1571,45 +1249,6 @@ void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
return;
}
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // If this cursor is rootless, find the root of the inline formatting
- // context.
- if (!HasRoot()) {
- const LayoutBlockFlow& root = *layout_object.ContainingNGBlockFlow();
- DCHECK(&root);
- SetRoot(root);
- if (!HasRoot()) {
- const auto fragments =
- NGPaintFragment::InlineFragmentsFor(&layout_object);
- if (!fragments.IsInLayoutNGInlineFormattingContext() ||
- fragments.IsEmpty())
- return MakeNull();
- // external/wpt/css/css-scroll-anchoring/text-anchor-in-vertical-rl.html
- // reaches here.
- root_paint_fragment_ = fragments.front().Root();
- }
- DCHECK(HasRoot());
- }
-
- const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_object);
- if (!fragments.IsEmpty()) {
- // If |this| is IFC root, just move to the first fragment.
- if (!root_paint_fragment_->Parent()) {
- DCHECK(fragments.front().IsDescendantOfNotSelf(*root_paint_fragment_));
- MoveTo(fragments.front());
- return;
- }
- // If |this| is limited, find the first fragment in the range.
- for (const auto* fragment : fragments) {
- if (fragment->IsDescendantOfNotSelf(*root_paint_fragment_)) {
- MoveTo(*fragment);
- return;
- }
- }
- }
- return MakeNull();
- }
-
// If this cursor is rootless, find the root of the inline formatting context.
bool is_descendants_cursor = false;
if (!HasRoot()) {
@@ -1713,50 +1352,32 @@ void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
}
void NGInlineCursor::MoveToNextForSameLayoutObjectExceptCulledInline() {
- if (current_.paint_fragment_) {
- if (auto* paint_fragment =
- current_.paint_fragment_->NextForSameLayoutObject()) {
- if (!root_paint_fragment_->Parent()) {
- // |paint_fragment| can be in another fragment tree rooted by
- // |root_paint_fragment_|, e.g. "multicol-span-all-restyle-002.html"
- root_paint_fragment_ = paint_fragment->Root();
- MoveTo(*paint_fragment);
- return;
- }
- // If |this| is limited, make sure the result is in the range.
- if (paint_fragment->IsDescendantOfNotSelf(*root_paint_fragment_)) {
- MoveTo(*paint_fragment);
+ if (!Current())
+ return;
+ if (wtf_size_t delta = current_.item_->DeltaToNextForSameLayoutObject()) {
+ while (true) {
+ // Return if the next index is in the current range.
+ const wtf_size_t delta_to_end = items_.end() - current_.item_iter_;
+ if (delta < delta_to_end) {
+ MoveToItem(current_.item_iter_ + delta);
return;
}
- }
- return MakeNull();
- }
- if (current_.item_) {
- if (wtf_size_t delta = current_.item_->DeltaToNextForSameLayoutObject()) {
- while (true) {
- // Return if the next index is in the current range.
- const wtf_size_t delta_to_end = items_.end() - current_.item_iter_;
- if (delta < delta_to_end) {
- MoveToItem(current_.item_iter_ + delta);
- return;
- }
- // |this| is |IsDescendantsCursor| and the next item is out of the
- // specified range, or the next item is in following fragmentainers.
- if (!CanMoveAcrossFragmentainer())
- break;
+ // |this| is |IsDescendantsCursor| and the next item is out of the
+ // specified range, or the next item is in following fragmentainers.
+ if (!CanMoveAcrossFragmentainer())
+ break;
- MoveToNextFragmentainer();
- if (!Current()) {
- NOTREACHED();
- break;
- }
- DCHECK_GE(delta, delta_to_end);
- delta -= delta_to_end;
+ MoveToNextFragmentainer();
+ if (!Current()) {
+ NOTREACHED();
+ break;
}
+ DCHECK_GE(delta, delta_to_end);
+ delta -= delta_to_end;
}
- MakeNull();
}
+ MakeNull();
}
void NGInlineCursor::MoveToLastForSameLayoutObject() {
@@ -1806,15 +1427,23 @@ const LayoutObject* NGInlineCursor::CulledInlineTraversal::Find(
return nullptr;
}
+void NGInlineCursor::CulledInlineTraversal::SetUseFragmentTree(
+ const LayoutInline& layout_inline) {
+ layout_inline_ = &layout_inline;
+ use_fragment_tree_ = true;
+}
+
const LayoutObject* NGInlineCursor::CulledInlineTraversal::MoveToFirstFor(
const LayoutInline& layout_inline) {
layout_inline_ = &layout_inline;
+ use_fragment_tree_ = false;
current_object_ = Find(layout_inline.FirstChild());
return current_object_;
}
const LayoutObject* NGInlineCursor::CulledInlineTraversal::MoveToNext() {
- DCHECK(current_object_);
+ if (!current_object_)
+ return nullptr;
current_object_ =
Find(current_object_->NextInPreOrderAfterChildren(layout_inline_));
return current_object_;
@@ -1822,6 +1451,19 @@ const LayoutObject* NGInlineCursor::CulledInlineTraversal::MoveToNext() {
void NGInlineCursor::MoveToFirstForCulledInline(
const LayoutInline& layout_inline) {
+ // When |this| is a descendant cursor, |this| may be limited to a very small
+ // subset of the |LayoutObject| descendants, and that traversing
+ // |LayoutObject| descendants is much more expensive. Prefer checking every
+ // fragment in that case.
+ if (IsDescendantsCursor()) {
+ culled_inline_.SetUseFragmentTree(layout_inline);
+ DCHECK(!CanMoveAcrossFragmentainer());
+ MoveToFirst();
+ while (Current() && !Current().IsPartOfCulledInlineBox(layout_inline))
+ MoveToNext();
+ return;
+ }
+
if (const LayoutObject* layout_object =
culled_inline_.MoveToFirstFor(layout_inline)) {
MoveTo(*layout_object);
@@ -1833,6 +1475,16 @@ void NGInlineCursor::MoveToFirstForCulledInline(
void NGInlineCursor::MoveToNextForCulledInline() {
DCHECK(culled_inline_);
+ if (culled_inline_.UseFragmentTree()) {
+ const LayoutInline* layout_inline = culled_inline_.GetLayoutInline();
+ DCHECK(layout_inline);
+ DCHECK(!CanMoveAcrossFragmentainer());
+ do {
+ MoveToNext();
+ } while (Current() && !Current().IsPartOfCulledInlineBox(*layout_inline));
+ return;
+ }
+
MoveToNextForSameLayoutObjectExceptCulledInline();
// If we're at the end of fragments for the current |LayoutObject| that
// contributes to the current culled inline, find the next |LayoutObject|.
@@ -1895,19 +1547,7 @@ void NGInlineCursor::MoveToNextForSameLayoutObject() {
//
NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
: cursor_(cursor) {
- if (cursor.root_paint_fragment_) {
- DCHECK(!cursor.CurrentPaintFragment() ||
- cursor.CurrentPaintFragment()->Parent()->FirstChild() ==
- cursor.CurrentPaintFragment());
- for (NGInlineCursor sibling(cursor); sibling;
- sibling.MoveToNextSiblingPaintFragment())
- sibling_paint_fragments_.push_back(sibling.CurrentPaintFragment());
- current_index_ = sibling_paint_fragments_.size();
- if (current_index_)
- current_.paint_fragment_ = sibling_paint_fragments_[--current_index_];
- return;
- }
- if (cursor.IsItemCursor()) {
+ if (cursor.HasRoot()) {
DCHECK(!cursor || cursor.items_.begin() == cursor.Current().item_iter_);
for (NGInlineCursor sibling(cursor); sibling;
sibling.MoveToNextSkippingChildren())
@@ -1921,8 +1561,6 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
}
NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
- if (const NGPaintFragment* current_paint_fragment = Current().PaintFragment())
- return NGInlineCursor(*current_paint_fragment);
if (current_.item_) {
NGInlineCursor cursor(cursor_);
cursor.MoveToItem(sibling_item_iterators_[current_index_]);
@@ -1934,28 +1572,19 @@ NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
void NGInlineBackwardCursor::MoveToPreviousSibling() {
if (current_index_) {
- if (current_.paint_fragment_) {
- current_.paint_fragment_ = sibling_paint_fragments_[--current_index_];
- return;
- }
if (current_.item_) {
current_.Set(sibling_item_iterators_[--current_index_]);
return;
}
NOTREACHED();
}
- current_.paint_fragment_ = nullptr;
- current_.item_ = nullptr;
+ current_.Clear();
}
std::ostream& operator<<(std::ostream& ostream, const NGInlineCursor& cursor) {
- if (cursor.IsNull())
+ if (!cursor)
return ostream << "NGInlineCursor()";
- if (cursor.IsPaintFragmentCursor()) {
- return ostream << "NGInlineCursor(" << *cursor.CurrentPaintFragment()
- << ")";
- }
- DCHECK(cursor.IsItemCursor());
+ DCHECK(cursor.HasRoot());
return ostream << "NGInlineCursor(" << *cursor.CurrentItem() << ")";
}
@@ -1967,12 +1596,9 @@ std::ostream& operator<<(std::ostream& ostream, const NGInlineCursor* cursor) {
#if DCHECK_IS_ON()
void NGInlineCursor::CheckValid(const NGInlineCursorPosition& position) const {
- if (position.PaintFragment()) {
- DCHECK(root_paint_fragment_);
- DCHECK(
- position.PaintFragment()->IsDescendantOfNotSelf(*root_paint_fragment_));
- } else if (position.Item()) {
- DCHECK(IsItemCursor());
+ if (position.Item()) {
+ DCHECK(HasRoot());
+ DCHECK_EQ(position.item_, &*position.item_iter_);
const unsigned index = position.item_iter_ - items_.begin();
DCHECK_LT(index, items_.size());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
index ef3c5943afb..965ca903096 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -10,6 +10,7 @@
#include "base/containers/span.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
@@ -29,7 +30,6 @@ class NGFragmentItems;
class NGInlineBackwardCursor;
class NGInlineBreakToken;
class NGInlineCursor;
-class NGPaintFragment;
class NGPhysicalBoxFragment;
class Node;
class ShapeResultView;
@@ -46,72 +46,86 @@ class CORE_EXPORT NGInlineCursorPosition {
public:
using ItemsSpan = NGFragmentItems::Span;
- const NGPaintFragment* PaintFragment() const { return paint_fragment_; }
const NGFragmentItem* Item() const { return item_; }
const NGFragmentItem* operator->() const { return item_; }
const NGFragmentItem& operator*() const { return *item_; }
- operator bool() const { return paint_fragment_ || item_; }
+ explicit operator bool() const { return item_; }
bool operator==(const NGInlineCursorPosition& other) const {
- return paint_fragment_ == other.paint_fragment_ && item_ == other.item_;
+ return item_ == other.item_;
}
bool operator!=(const NGInlineCursorPosition& other) const {
return !operator==(other);
}
// True if the current position is a text. It is error to call at end.
- bool IsText() const;
+ bool IsText() const { return item_->IsText(); }
// True if the current position is a generatd text. It is error to call at
// end. This includes both style-generated (e.g., `content` property, see
// |IsStyleGenerated()|) and layout-generated (hyphens and ellipsis, see
// |IsLayoutGeneratedText()|.)
- bool IsGeneratedText() const;
+ bool IsGeneratedText() const { return item_->IsGeneratedText(); }
// True if fragment is layout-generated (hyphens and ellipsis.)
- bool IsLayoutGeneratedText() const;
+ bool IsLayoutGeneratedText() const {
+ return item_->Type() == NGFragmentItem::kGeneratedText;
+ }
// True if the current position is a line break. It is error to call at end.
- bool IsLineBreak() const;
+ bool IsLineBreak() const { return IsText() && item_->IsLineBreak(); }
// True if the current position is an ellipsis. It is error to call at end.
- bool IsEllipsis() const;
+ bool IsEllipsis() const { return item_->IsEllipsis(); }
// True if the current position is a line box. It is error to call at end.
- bool IsLineBox() const;
+ bool IsLineBox() const { return item_->Type() == NGFragmentItem::kLine; }
// True if the current position is an empty line box. It is error to call
// other then line box.
- bool IsEmptyLineBox() const;
+ bool IsEmptyLineBox() const { return item_->IsEmptyLineBox(); }
// True if the current position is an inline box. It is error to call at end.
- bool IsInlineBox() const;
+ bool IsInlineBox() const { return item_->IsInlineBox(); }
// True if the current position is an atomic inline. It is error to call at
// end.
- bool IsAtomicInline() const;
+ bool IsAtomicInline() const { return item_->IsAtomicInline(); }
// True if the current position is a list marker.
- bool IsListMarker() const;
+ bool IsListMarker() const { return item_->IsListMarker(); }
+
+ // True if the current position is a box for "float"
+ bool IsFloating() const { return item_->IsFloating(); }
// True if the current position is hidden for paint. It is error to call at
// end.
- bool IsHiddenForPaint() const;
+ bool IsHiddenForPaint() const { return item_->IsHiddenForPaint(); }
// |ComputedStyle| and related functions.
- NGStyleVariant StyleVariant() const;
- bool UsesFirstLineStyle() const;
- const ComputedStyle& Style() const;
+ NGStyleVariant StyleVariant() const { return item_->StyleVariant(); }
+ bool UsesFirstLineStyle() const {
+ return StyleVariant() == NGStyleVariant::kFirstLine;
+ }
+ const ComputedStyle& Style() const { return item_->Style(); }
// Functions to get corresponding objects for this position.
- const NGPhysicalBoxFragment* BoxFragment() const;
- const LayoutObject* GetLayoutObject() const;
- LayoutObject* GetMutableLayoutObject() const;
+ const NGPhysicalBoxFragment* BoxFragment() const {
+ return item_->BoxFragment();
+ }
+ const LayoutObject* GetLayoutObject() const {
+ return item_->GetLayoutObject();
+ }
+ LayoutObject* GetMutableLayoutObject() const {
+ return item_->GetMutableLayoutObject();
+ }
const Node* GetNode() const;
- const DisplayItemClient* GetDisplayItemClient() const;
+ const DisplayItemClient* GetDisplayItemClient() const {
+ return item_->GetDisplayItemClient();
+ }
const DisplayItemClient* GetSelectionDisplayItemClient() const;
- wtf_size_t FragmentId() const;
+ wtf_size_t FragmentId() const { return item_->FragmentId(); }
// True if fragment at the current position can have children.
bool CanHaveChildren() const;
@@ -120,23 +134,31 @@ class CORE_EXPORT NGInlineCursorPosition {
bool HasChildren() const;
// Returns break token for line box. It is error to call other than line box.
- const NGInlineBreakToken* InlineBreakToken() const;
+ const NGInlineBreakToken* InlineBreakToken() const {
+ return item_->InlineBreakToken();
+ }
// The offset relative to the root of the inline formatting context.
- const PhysicalRect RectInContainerBlock() const;
- const PhysicalOffset OffsetInContainerBlock() const;
- const PhysicalSize Size() const;
+ const PhysicalRect RectInContainerFragment() const {
+ return item_->RectInContainerFragment();
+ }
+ const PhysicalOffset OffsetInContainerFragment() const {
+ return item_->OffsetInContainerFragment();
+ }
+ const PhysicalSize Size() const { return item_->Size(); }
// InkOverflow of itself, including contents if they contribute to the ink
// overflow of this object (e.g. when not clipped,) in the local coordinate.
- const PhysicalRect InkOverflow() const;
- const PhysicalRect SelfInkOverflow() const;
+ const PhysicalRect InkOverflow() const { return item_->InkOverflow(); }
+ const PhysicalRect SelfInkOverflow() const {
+ return item_->SelfInkOverflow();
+ }
void RecalcInkOverflow(const NGInlineCursor& cursor) const;
// Returns start/end of offset in text content of current text fragment.
// It is error when this cursor doesn't point to text fragment.
- NGTextOffset TextOffset() const;
+ NGTextOffset TextOffset() const { return item_->TextOffset(); }
unsigned TextStartOffset() const { return TextOffset().start; }
unsigned TextEndOffset() const { return TextOffset().end; }
@@ -146,7 +168,9 @@ class CORE_EXPORT NGInlineCursorPosition {
// Returns |ShapeResultView| of the current position. It is error to call
// other than text.
- const ShapeResultView* TextShapeResult() const;
+ const ShapeResultView* TextShapeResult() const {
+ return item_->TextShapeResult();
+ }
// Returns bidi level of current position. It is error to call other than
// text and atomic inline. It is also error to call |IsGeneratedTextType()|.
@@ -154,7 +178,7 @@ class CORE_EXPORT NGInlineCursorPosition {
// Returns text direction of current text or atomic inline. It is error to
// call at other than text or atomic inline. Note: <span> doesn't have
// reserved direction.
- TextDirection ResolvedDirection() const;
+ TextDirection ResolvedDirection() const { return item_->ResolvedDirection(); }
// Returns text direction of current line. It is error to call at other than
// line.
TextDirection BaseDirection() const;
@@ -181,20 +205,17 @@ class CORE_EXPORT NGInlineCursorPosition {
private:
void Set(const ItemsSpan::iterator& iter) {
- DCHECK(!paint_fragment_);
item_iter_ = iter;
item_ = &*iter;
}
void Clear() {
- paint_fragment_ = nullptr;
item_ = nullptr;
}
// True if current position is part of culled inline box |layout_inline|.
bool IsPartOfCulledInlineBox(const LayoutInline& layout_inline) const;
- const NGPaintFragment* paint_fragment_ = nullptr;
const NGFragmentItem* item_ = nullptr;
ItemsSpan::iterator item_iter_;
@@ -206,9 +227,6 @@ class CORE_EXPORT NGInlineCursorPosition {
//
// When constructed, the initial position is empty. Call |MoveToNext()| to move
// to the first fragment.
-//
-// TODO(kojii): |NGPaintFragment| should be gone when |NGPaintFragment| is
-// deprecated and all its uses are removed.
class CORE_EXPORT NGInlineCursor {
STACK_ALLOCATED();
@@ -219,7 +237,6 @@ class CORE_EXPORT NGInlineCursor {
explicit NGInlineCursor(const NGPhysicalBoxFragment& box_fragment);
NGInlineCursor(const NGPhysicalBoxFragment& box_fragment,
const NGFragmentItems& items);
- explicit NGInlineCursor(const NGPaintFragment& root_paint_fragment);
explicit NGInlineCursor(const NGInlineBackwardCursor& backward_cursor);
NGInlineCursor(const NGInlineCursor& other) = default;
@@ -233,12 +250,9 @@ class CORE_EXPORT NGInlineCursor {
return !operator==(other);
}
- bool IsItemCursor() const { return fragment_items_; }
- bool IsPaintFragmentCursor() const { return root_paint_fragment_; }
-
// True if this cursor has the root to traverse. Only the default constructor
// creates a cursor without the root.
- bool HasRoot() const { return IsItemCursor() || IsPaintFragmentCursor(); }
+ bool HasRoot() const { return fragment_items_; }
const NGFragmentItems& Items() const {
DCHECK(fragment_items_);
@@ -246,19 +260,19 @@ class CORE_EXPORT NGInlineCursor {
}
// Returns the |NGPhysicalBoxFragment| that owns |Items|.
- const NGPhysicalBoxFragment& BoxFragment() const {
+ const NGPhysicalBoxFragment& ContainerFragment() const {
DCHECK(root_box_fragment_);
return *root_box_fragment_;
}
+ // Return the index of the current physical box fragment of the containing
+ // block. An inline formatting context may be block fragmented.
+ wtf_size_t ContainerFragmentIndex() const { return fragment_index_; }
+
// Returns the |LayoutBlockFlow| containing this cursor.
// When |this| is a column box, returns the multicol container.
const LayoutBlockFlow* GetLayoutBlockFlow() const;
- // Return the index of the current physical box fragment of the containing
- // block. An inline formatting context may be block fragmented.
- wtf_size_t CurrentContainerFragmentIndex() const { return fragment_index_; }
-
//
// Functions to query the current position.
//
@@ -267,8 +281,8 @@ class CORE_EXPORT NGInlineCursor {
// Returns true if cursor is out of fragment tree, e.g. before first fragment
// or after last fragment in tree.
bool IsNull() const { return !Current(); }
- bool IsNotNull() const { return Current(); }
- operator bool() const { return Current(); }
+ bool IsNotNull() const { return !!Current(); }
+ explicit operator bool() const { return !!Current(); }
// True if |Current()| is at the first fragment. See |MoveToFirst()|.
bool IsAtFirst() const;
@@ -290,9 +304,6 @@ class CORE_EXPORT NGInlineCursor {
// |Current*| functions return an object for the current position.
const NGFragmentItem* CurrentItem() const { return Current().Item(); }
- const NGPaintFragment* CurrentPaintFragment() const {
- return Current().PaintFragment();
- }
LayoutObject* CurrentMutableLayoutObject() const {
return Current().GetMutableLayoutObject();
}
@@ -306,6 +317,9 @@ class CORE_EXPORT NGInlineCursor {
// |CurrentTextEndOffset()|. It is error to call other than text.
PhysicalRect CurrentLocalRect(unsigned start_offset,
unsigned end_offset) const;
+ PhysicalRect CurrentLocalSelectionRectForText(
+ const LayoutSelectionStatus& selection_status) const;
+ PhysicalRect CurrentLocalSelectionRectForReplaced() const;
// Return a rectangle (or just an offset) relatively to containing
// LayoutBlockFlow, as if all the container fragments were stitched together
@@ -320,8 +334,8 @@ class CORE_EXPORT NGInlineCursor {
// first column, and the last three lines will end up in the second column. So
// we get two box fragments generated for #container - one for each column.
//
- // The offsets returned from these methods will be (OffsetInContainerBlock()
- // values in parentheses):
+ // The offsets returned from these methods will be
+ // (OffsetInContainerFragment() values in parentheses):
//
// line1: 0,0 (0,0)
// line2: 0,20 (0,20)
@@ -334,8 +348,8 @@ class CORE_EXPORT NGInlineCursor {
// engine to calculate offsets relatively to some ancestor.
PhysicalRect CurrentRectInBlockFlow() const;
PhysicalOffset CurrentOffsetInBlockFlow() const {
- DCHECK_EQ(Current().OffsetInContainerBlock(),
- Current().RectInContainerBlock().offset);
+ DCHECK_EQ(Current().OffsetInContainerFragment(),
+ Current().RectInContainerFragment().offset);
return CurrentRectInBlockFlow().offset;
}
@@ -385,10 +399,6 @@ class CORE_EXPORT NGInlineCursor {
// should be part of |this| cursor.
void MoveTo(const NGInlineCursor& cursor);
- // Move the current posint at |paint_fragment|.
- void MoveTo(const NGPaintFragment& paint_fragment);
- void MoveTo(const NGPaintFragment* paint_fragment);
-
// Move to containing line box. It is error if the current position is line.
void MoveToContainingLine();
@@ -480,6 +490,8 @@ class CORE_EXPORT NGInlineCursor {
// fragmentainers. Use following functions when moving to different
// fragmentainers.
+ bool IsBlockFragmented() const { return max_fragment_index_ > 0; }
+
// Move to the first item of the first fragmentainer.
void MoveToFirstIncludingFragmentainer();
@@ -528,12 +540,10 @@ class CORE_EXPORT NGInlineCursor {
bool IsDescendantsCursor() const {
if (fragment_items_)
return !fragment_items_->Equals(items_);
- if (root_paint_fragment_)
- return root_paint_fragment_->Parent();
return false;
}
bool CanMoveAcrossFragmentainer() const {
- return root_block_flow_ && IsItemCursor() && !IsDescendantsCursor();
+ return root_block_flow_ && HasRoot() && !IsDescendantsCursor();
}
// True if the current position is a last line in inline block. It is error
@@ -556,23 +566,12 @@ class CORE_EXPORT NGInlineCursor {
void SetRoot(const NGPhysicalBoxFragment& box_fragment,
const NGFragmentItems& fragment_items,
ItemsSpan items);
- void SetRoot(const NGPaintFragment& root_paint_fragment);
void SetRoot(const LayoutBlockFlow& block_flow);
bool SetRoot(const LayoutBlockFlow& block_flow, wtf_size_t fragment_index);
bool TrySetRootFragmentItems();
void MoveToItem(const ItemsSpan::iterator& iter);
- void MoveToNextItem();
- void MoveToNextItemSkippingChildren();
- void MoveToPreviousItem();
-
- void MoveToParentPaintFragment();
- void MoveToNextPaintFragment();
- void MoveToNextSiblingPaintFragment();
- void MoveToNextPaintFragmentSkippingChildren();
- void MoveToPreviousPaintFragment();
- void MoveToPreviousSiblingPaintFragment();
void SlowMoveToFirstFor(const LayoutObject& layout_object);
void SlowMoveToNextForSameLayoutObject(const LayoutObject& layout_object);
@@ -589,8 +588,13 @@ class CORE_EXPORT NGInlineCursor {
public:
CulledInlineTraversal() = default;
- explicit operator bool() const { return current_object_; }
- void Reset() { current_object_ = nullptr; }
+ const LayoutInline* GetLayoutInline() const { return layout_inline_; }
+
+ explicit operator bool() const { return layout_inline_; }
+ void Reset() { layout_inline_ = nullptr; }
+
+ bool UseFragmentTree() const { return use_fragment_tree_; }
+ void SetUseFragmentTree(const LayoutInline& layout_inline);
// Returns first/next |LayoutObject| that contribute to |layout_inline|.
const LayoutObject* MoveToFirstFor(const LayoutInline& layout_inline);
@@ -601,6 +605,7 @@ class CORE_EXPORT NGInlineCursor {
const LayoutObject* current_object_ = nullptr;
const LayoutInline* layout_inline_ = nullptr;
+ bool use_fragment_tree_ = false;
};
void MoveToFirstForCulledInline(const LayoutInline& layout_inline);
@@ -615,7 +620,6 @@ class CORE_EXPORT NGInlineCursor {
ItemsSpan items_;
const NGFragmentItems* fragment_items_ = nullptr;
const NGPhysicalBoxFragment* root_box_fragment_ = nullptr;
- const NGPaintFragment* root_paint_fragment_ = nullptr;
CulledInlineTraversal culled_inline_;
@@ -643,16 +647,19 @@ class CORE_EXPORT NGInlineBackwardCursor {
explicit NGInlineBackwardCursor(const NGInlineCursor& cursor);
const NGInlineCursorPosition& Current() const { return current_; }
- operator bool() const { return Current(); }
+ explicit operator bool() const { return !!Current(); }
NGInlineCursor CursorForDescendants() const;
void MoveToPreviousSibling();
+ const NGPhysicalBoxFragment& ContainerFragment() const {
+ return cursor_.ContainerFragment();
+ }
+
private:
NGInlineCursorPosition current_;
const NGInlineCursor& cursor_;
- Vector<const NGPaintFragment*, 16> sibling_paint_fragments_;
Vector<NGInlineCursor::ItemsSpan::iterator, 16> sibling_item_iterators_;
wtf_size_t current_index_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
index cb8d0476d8a..2c2c748eb5f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
@@ -53,11 +53,7 @@ Vector<String> LayoutObjectToDebugStringList(NGInlineCursor cursor) {
}
class NGInlineCursorTest : public NGLayoutTest,
- private ScopedLayoutNGFragmentItemForTest,
public testing::WithParamInterface<bool> {
- public:
- NGInlineCursorTest() : ScopedLayoutNGFragmentItemForTest(GetParam()) {}
-
protected:
NGInlineCursor SetupCursor(const String& html) {
SetBodyInnerHTML(html);
@@ -84,20 +80,7 @@ class NGInlineCursorTest : public NGLayoutTest,
// Test |MoveToNextSibling| and |NGInlineBackwardCursor| return the same
// instances, except that the order is reversed.
void TestPrevoiusSibling(const NGInlineCursor& start) {
- if (start.IsPaintFragmentCursor()) {
- Vector<const NGPaintFragment*> forwards;
- for (NGInlineCursor cursor(start); cursor;
- cursor.MoveToNextSkippingChildren())
- forwards.push_back(cursor.CurrentPaintFragment());
- Vector<const NGPaintFragment*> backwards;
- for (NGInlineBackwardCursor cursor(start); cursor;
- cursor.MoveToPreviousSibling())
- backwards.push_back(cursor.Current().PaintFragment());
- backwards.Reverse();
- EXPECT_THAT(backwards, forwards);
- return;
- }
- DCHECK(start.IsItemCursor());
+ DCHECK(start.HasRoot());
Vector<const NGFragmentItem*> forwards;
for (NGInlineCursor cursor(start); cursor;
cursor.MoveToNextSkippingChildren())
@@ -769,12 +752,12 @@ TEST_P(NGInlineCursorTest, PositionForPointInChildHorizontalLTR) {
const auto& text = *To<Text>(GetElementById("root")->firstChild());
ASSERT_TRUE(cursor.Current().IsLineBox());
EXPECT_EQ(PhysicalRect(PhysicalOffset(10, 10), PhysicalSize(20, 20)),
- cursor.Current().RectInContainerBlock());
+ cursor.Current().RectInContainerFragment());
cursor.MoveTo(*text.GetLayoutObject());
EXPECT_EQ(PhysicalRect(PhysicalOffset(10, 15), PhysicalSize(20, 10)),
- cursor.Current().RectInContainerBlock());
- const PhysicalOffset left_top = cursor.Current().OffsetInContainerBlock();
+ cursor.Current().RectInContainerFragment());
+ const PhysicalOffset left_top = cursor.Current().OffsetInContainerFragment();
EXPECT_EQ(PositionWithAffinity(Position(text, 0)),
cursor.PositionForPointInChild(left_top + PhysicalOffset(-5, 0)));
@@ -806,12 +789,12 @@ TEST_P(NGInlineCursorTest, PositionForPointInChildHorizontalRTL) {
*To<Text>(GetElementById("root")->firstChild()->firstChild());
ASSERT_TRUE(cursor.Current().IsLineBox());
EXPECT_EQ(PhysicalRect(PhysicalOffset(754, 10), PhysicalSize(20, 20)),
- cursor.Current().RectInContainerBlock());
+ cursor.Current().RectInContainerFragment());
cursor.MoveTo(*text.GetLayoutObject());
EXPECT_EQ(PhysicalRect(PhysicalOffset(754, 15), PhysicalSize(20, 10)),
- cursor.Current().RectInContainerBlock());
- const PhysicalOffset left_top = cursor.Current().OffsetInContainerBlock();
+ cursor.Current().RectInContainerFragment());
+ const PhysicalOffset left_top = cursor.Current().OffsetInContainerFragment();
EXPECT_EQ(PositionWithAffinity(Position(text, 2), TextAffinity::kUpstream),
cursor.PositionForPointInChild(left_top + PhysicalOffset(-5, 0)));
@@ -842,12 +825,12 @@ TEST_P(NGInlineCursorTest, PositionForPointInChildVerticalLTR) {
const auto& text = *To<Text>(GetElementById("root")->firstChild());
ASSERT_TRUE(cursor.Current().IsLineBox());
EXPECT_EQ(PhysicalRect(PhysicalOffset(10, 10), PhysicalSize(20, 20)),
- cursor.Current().RectInContainerBlock());
+ cursor.Current().RectInContainerFragment());
cursor.MoveTo(*text.GetLayoutObject());
EXPECT_EQ(PhysicalRect(PhysicalOffset(15, 10), PhysicalSize(10, 20)),
- cursor.Current().RectInContainerBlock());
- const PhysicalOffset left_top = cursor.Current().OffsetInContainerBlock();
+ cursor.Current().RectInContainerFragment());
+ const PhysicalOffset left_top = cursor.Current().OffsetInContainerFragment();
EXPECT_EQ(PositionWithAffinity(Position(text, 0)),
cursor.PositionForPointInChild(left_top + PhysicalOffset(0, -5)));
@@ -879,12 +862,12 @@ TEST_P(NGInlineCursorTest, PositionForPointInChildVerticalRTL) {
*To<Text>(GetElementById("root")->firstChild()->firstChild());
ASSERT_TRUE(cursor.Current().IsLineBox());
EXPECT_EQ(PhysicalRect(PhysicalOffset(10, 10), PhysicalSize(20, 20)),
- cursor.Current().RectInContainerBlock());
+ cursor.Current().RectInContainerFragment());
cursor.MoveTo(*text.GetLayoutObject());
EXPECT_EQ(PhysicalRect(PhysicalOffset(15, 10), PhysicalSize(10, 20)),
- cursor.Current().RectInContainerBlock());
- const PhysicalOffset left_top = cursor.Current().OffsetInContainerBlock();
+ cursor.Current().RectInContainerFragment());
+ const PhysicalOffset left_top = cursor.Current().OffsetInContainerFragment();
EXPECT_EQ(PositionWithAffinity(Position(text, 2), TextAffinity::kUpstream),
cursor.PositionForPointInChild(left_top + PhysicalOffset(0, -5)));
@@ -910,7 +893,7 @@ TEST_P(NGInlineCursorTest, PositionForPointInChildBlockChildren) {
SetupCursor("<div id=root>a<b id=target><div>x</div></b></div>");
const Element& target = *GetElementById("target");
cursor.MoveTo(*target.GetLayoutObject());
- EXPECT_EQ(PositionWithAffinity(Position(target, 0)),
+ EXPECT_EQ(PositionWithAffinity(Position::FirstPositionInNode(target)),
cursor.PositionForPointInChild(PhysicalOffset()));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
deleted file mode 100644
index b9641ae0c5f..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
-
-#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-
-namespace blink {
-
-namespace {
-
-using Result = NGPhysicalFragmentWithOffset;
-
-class NGPhysicalFragmentCollectorBase {
- STACK_ALLOCATED();
-
- public:
- virtual Vector<Result> CollectFrom(const NGPhysicalFragment&) = 0;
- NGPhysicalFragmentCollectorBase(const NGPhysicalFragmentCollectorBase&) =
- delete;
- NGPhysicalFragmentCollectorBase& operator=(
- const NGPhysicalFragmentCollectorBase&) = delete;
-
- protected:
- explicit NGPhysicalFragmentCollectorBase() = default;
-
- virtual void Visit() = 0;
-
- const NGPhysicalFragment& GetFragment() const { return *current_fragment_; }
- void SetShouldStopTraversing() { should_stop_traversing_ = true; }
- bool HasStoppedTraversing() const { return should_stop_traversing_; }
-
- void Emit() {
- results_.push_back(Result{current_fragment_, current_offset_to_root_});
- }
-
- // Visits and collets fragments in the subtree rooted at |fragment|.
- // |fragment| itself is not visited.
- Vector<Result> CollectExclusivelyFrom(const NGPhysicalFragment& fragment) {
- current_fragment_ = &fragment;
- root_fragment_ = &fragment;
- VisitChildren();
- return std::move(results_);
- }
-
- // Visits and collets fragments in the subtree rooted at |fragment|.
- // |fragment| itself is visited.
- Vector<Result> CollectInclusivelyFrom(const NGPhysicalFragment& fragment) {
- current_fragment_ = &fragment;
- root_fragment_ = &fragment;
- Visit();
- return std::move(results_);
- }
-
- void VisitChildren() {
- if (should_stop_traversing_)
- return;
-
- const NGPhysicalFragment& fragment = *current_fragment_;
- if (!fragment.IsContainer())
- return;
-
- // Traverse descendants unless the fragment is laid out separately from the
- // inline layout algorithm.
- if (&fragment != root_fragment_ && fragment.IsFormattingContextRoot())
- return;
-
- DCHECK(fragment.IsContainer());
- DCHECK(fragment.IsInline() || fragment.IsLineBox() ||
- (fragment.IsBlockFlow() &&
- To<NGPhysicalBoxFragment>(fragment).IsInlineFormattingContext()));
-
- for (const auto& child :
- To<NGPhysicalContainerFragment>(fragment).Children()) {
- base::AutoReset<PhysicalOffset> offset_resetter(
- &current_offset_to_root_, current_offset_to_root_ + child.Offset());
- base::AutoReset<const NGPhysicalFragment*> fragment_resetter(
- &current_fragment_, child.get());
- Visit();
-
- if (should_stop_traversing_)
- return;
- }
- }
-
- private:
- const NGPhysicalFragment* root_fragment_ = nullptr;
- const NGPhysicalFragment* current_fragment_ = nullptr;
- PhysicalOffset current_offset_to_root_;
- Vector<Result> results_;
- bool should_stop_traversing_ = false;
-};
-
-// The visitor emitting all visited fragments.
-class DescendantCollector final : public NGPhysicalFragmentCollectorBase {
- STACK_ALLOCATED();
-
- public:
- DescendantCollector() = default;
- DescendantCollector(const DescendantCollector&) = delete;
- DescendantCollector& operator=(const DescendantCollector&) = delete;
-
- Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final {
- return CollectExclusivelyFrom(fragment);
- }
-
- private:
- void Visit() final {
- Emit();
- VisitChildren();
- }
-};
-
-// The visitor emitting fragments generated from the given LayoutInline,
-// supporting culled inline.
-// Note: Since we apply culled inline per line, we have a fragment for
-// LayoutInline in second line but not in first line in
-// "t0803-c5502-imrgn-r-01-b-ag.html".
-class LayoutInlineCollector final : public NGPhysicalFragmentCollectorBase {
- STACK_ALLOCATED();
-
- public:
- explicit LayoutInlineCollector(const LayoutInline& container) {
- CollectInclusiveDescendants(container);
- }
- LayoutInlineCollector(const LayoutInlineCollector&) = delete;
- LayoutInlineCollector& operator=(const LayoutInlineCollector&) = delete;
-
- Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final {
- return CollectExclusivelyFrom(fragment);
- }
-
- private:
- void Visit() final {
- if (!GetFragment().IsLineBox() &&
- inclusive_descendants_.Contains(GetFragment().GetLayoutObject())) {
- Emit();
- return;
- }
- VisitChildren();
- }
-
- void CollectInclusiveDescendants(const LayoutInline& container) {
- inclusive_descendants_.insert(&container);
- for (const LayoutObject* node = container.FirstChild(); node;
- node = node->NextSibling()) {
- if (node->IsFloatingOrOutOfFlowPositioned())
- continue;
- if (node->IsBox() || node->IsText()) {
- inclusive_descendants_.insert(node);
- continue;
- }
- if (!node->IsLayoutInline())
- continue;
- CollectInclusiveDescendants(To<LayoutInline>(*node));
- }
- }
-
- HashSet<const LayoutObject*> inclusive_descendants_;
-};
-
-} // namespace
-
-// static
-Vector<Result> NGInlineFragmentTraversal::SelfFragmentsOf(
- const NGPhysicalContainerFragment& container,
- const LayoutObject* layout_object) {
- if (const auto* layout_inline = DynamicTo<LayoutInline>(layout_object)) {
- // TODO(crbug.com/874361): Stop partial culling of inline boxes, so that we
- // can simply check existence of paint fragments below.
- if (!layout_inline->HasSelfPaintingLayer()) {
- return LayoutInlineCollector(To<LayoutInline>(*layout_object))
- .CollectFrom(container);
- }
- }
- Vector<Result> result;
- for (const NGPaintFragment* fragment :
- NGPaintFragment::InlineFragmentsFor(layout_object)) {
- result.push_back(Result{&fragment->PhysicalFragment(),
- fragment->OffsetInContainerBlock()});
- }
- return result;
-}
-
-// static
-Vector<Result> NGInlineFragmentTraversal::DescendantsOf(
- const NGPhysicalContainerFragment& container) {
- return DescendantCollector().CollectFrom(container);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h
deleted file mode 100644
index 19b7c4ef6f7..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class NGPhysicalContainerFragment;
-
-// Utility class for traversing the physical fragment tree.
-class CORE_EXPORT NGInlineFragmentTraversal {
- STATIC_ONLY(NGInlineFragmentTraversal);
-
- public:
- // Returns list of descendants in preorder. Offsets are relative to
- // specified fragment.
- static Vector<NGPhysicalFragmentWithOffset> DescendantsOf(
- const NGPhysicalContainerFragment&);
-
- // Returns list of inline fragments produced from the specified LayoutObject.
- // The search is restricted in the subtree of |container|.
- // Note: When |target| is a LayoutInline, some/all of its own box fragments
- // may be absent from the fragment tree, in which case the nearest box/text
- // descendant fragments are returned.
- // Note 2: Most callers should use the enclosing block flow fragment of
- // |target| as |container|. The only exception is
- // LayoutInline::HitTestCulledInline().
- // TODO(xiaochengh): As |container| is redundant in most cases, split this
- // function into two variants that takes/omits |container|.
- static Vector<NGPhysicalFragmentWithOffset> SelfFragmentsOf(
- const NGPhysicalContainerFragment& container,
- const LayoutObject* target);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc
deleted file mode 100644
index 5201d8d2824..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-
-namespace blink {
-
-class NGInlineFragmentTraversalTest : public NGLayoutTest {
- public:
- NGInlineFragmentTraversalTest() : NGLayoutTest() {}
-
- protected:
- const NGPhysicalBoxFragment& GetRootFragmentById(const char* id) const {
- const Element* element = GetElementById(id);
- DCHECK(element) << id;
- const LayoutObject* layout_object = element->GetLayoutObject();
- DCHECK(layout_object) << element;
- DCHECK(layout_object->IsLayoutBlockFlow()) << element;
- DCHECK(To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0))
- << element;
- return *To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0);
- }
-};
-
-#define EXPECT_NEXT_BOX(iter, id) \
- { \
- const auto& current = *iter++; \
- EXPECT_TRUE(current.fragment->IsBox()) << current.fragment->ToString(); \
- EXPECT_EQ(GetLayoutObjectByElementId(id), \
- current.fragment->GetLayoutObject()); \
- }
-
-#define EXPECT_NEXT_LINE_BOX(iter) \
- { \
- const auto& current = *iter++; \
- EXPECT_TRUE(current.fragment->IsLineBox()) \
- << current.fragment->ToString(); \
- }
-
-#define EXPECT_NEXT_TEXT(iter, content) \
- { \
- const auto& current = *iter++; \
- EXPECT_TRUE(current.fragment->IsText()) << current.fragment->ToString(); \
- EXPECT_EQ(content, \
- To<NGPhysicalTextFragment>(current.fragment.get())->Text()); \
- }
-
-TEST_F(NGInlineFragmentTraversalTest, DescendantsOf) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // NGFragmentItem doesn't use |NGInlineFragmentTraversal|.
- return;
- }
- SetBodyInnerHTML(
- "<style>* { border: 1px solid}</style>"
- "<div id=t>foo<b id=b>bar</b><br>baz</div>");
- const auto descendants =
- NGInlineFragmentTraversal::DescendantsOf(GetRootFragmentById("t"));
- auto* iter = descendants.begin();
-
- EXPECT_NEXT_LINE_BOX(iter);
- EXPECT_NEXT_TEXT(iter, "foo");
- EXPECT_NEXT_BOX(iter, "b");
- EXPECT_NEXT_TEXT(iter, "bar");
- EXPECT_NEXT_TEXT(iter, "\n");
- EXPECT_NEXT_LINE_BOX(iter);
- EXPECT_NEXT_TEXT(iter, "baz");
- EXPECT_EQ(iter, descendants.end());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
index 2e759623317..8ecda5b72c7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index c674ad24abb..762ed695cd6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
namespace blink {
+class HTMLAreaElement;
// Returns true if items builder is used for other than offset mapping.
template <typename OffsetMappingBuilder>
@@ -1095,8 +1096,7 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::EnterBlock(
kPopDirectionalFormattingCharacter);
}
- if (style->Display() == EDisplay::kListItem &&
- style->ListStyleType() != EListStyleType::kNone) {
+ if (style->Display() == EDisplay::kListItem && style->GetListStyleType()) {
is_empty_inline_ = false;
is_block_level_ = false;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index bc7b2fa4c48..f13847d417e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -18,9 +18,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
@@ -345,12 +343,6 @@ void NGInlineLayoutAlgorithm::CreateLine(
}
}
- if (has_logical_text_items &&
- !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- line_box->CreateTextFragments(ConstraintSpace().GetWritingMode(),
- line_info->ItemsData().text_content);
- }
-
// Negative margins can make the position negative, but the inline size is
// always positive or 0.
inline_size = inline_size.ClampNegativeToZero();
@@ -395,14 +387,6 @@ void NGInlineLayoutAlgorithm::CreateLine(
// Apply any relative positioned offsets to any boxes (and their children).
box_states_->ApplyRelativePositioning(ConstraintSpace(), line_box);
- NGAnnotationMetrics annotation_metrics;
- if (Node().HasRuby() &&
- !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- annotation_metrics = ComputeAnnotationOverflow(*line_box, line_box_metrics,
- -line_box_metrics.ascent,
- line_info->LineStyle());
- }
-
// Create box fragments if needed. After this point forward, |line_box| is a
// tree structure.
// The individual children don't move position within the |line_box|, rather
@@ -431,44 +415,51 @@ void NGInlineLayoutAlgorithm::CreateLine(
// the line box to the line top.
line_box->MoveInBlockDirection(line_box_metrics.ascent);
- if (Node().HasRuby() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- annotation_metrics = ComputeAnnotationOverflow(
+ LayoutUnit block_offset = line_info->BfcOffset().block_offset;
+ if (Node().HasRuby()) {
+ NGAnnotationMetrics annotation_metrics = ComputeAnnotationOverflow(
*line_box, line_box_metrics, LayoutUnit(), line_info->LineStyle());
- }
- LayoutUnit annotation_overflow_block_start;
- LayoutUnit annotation_overflow_block_end;
- LayoutUnit annotation_space_block_start;
- LayoutUnit annotation_space_block_end;
- if (!IsFlippedLinesWritingMode(line_info->LineStyle().GetWritingMode())) {
- annotation_overflow_block_start = annotation_metrics.overflow_over;
- annotation_overflow_block_end = annotation_metrics.overflow_under;
- annotation_space_block_start = annotation_metrics.space_over;
- annotation_space_block_end = annotation_metrics.space_under;
- } else {
- annotation_overflow_block_start = annotation_metrics.overflow_under;
- annotation_overflow_block_end = annotation_metrics.overflow_over;
- annotation_space_block_start = annotation_metrics.space_under;
- annotation_space_block_end = annotation_metrics.space_over;
- }
+ LayoutUnit annotation_overflow_block_start;
+ LayoutUnit annotation_overflow_block_end;
+ LayoutUnit annotation_space_block_start;
+ LayoutUnit annotation_space_block_end;
+ if (!IsFlippedLinesWritingMode(line_info->LineStyle().GetWritingMode())) {
+ annotation_overflow_block_start = annotation_metrics.overflow_over;
+ annotation_overflow_block_end = annotation_metrics.overflow_under;
+ annotation_space_block_start = annotation_metrics.space_over;
+ annotation_space_block_end = annotation_metrics.space_under;
+ } else {
+ annotation_overflow_block_start = annotation_metrics.overflow_under;
+ annotation_overflow_block_end = annotation_metrics.overflow_over;
+ annotation_space_block_start = annotation_metrics.space_under;
+ annotation_space_block_end = annotation_metrics.space_over;
+ }
- LayoutUnit block_offset_shift = annotation_overflow_block_start;
- // If the previous line has block-end annotation overflow and this line has
- // block-start annotation space, shift up the block offset of this line.
- if (ConstraintSpace().BlockStartAnnotationSpace() < LayoutUnit() &&
- annotation_space_block_start) {
- const LayoutUnit overflow = -ConstraintSpace().BlockStartAnnotationSpace();
- block_offset_shift = -std::min(annotation_space_block_start, overflow);
- }
+ LayoutUnit block_offset_shift = annotation_overflow_block_start;
+ // If the previous line has block-end annotation overflow and this line has
+ // block-start annotation space, shift up the block offset of this line.
+ if (ConstraintSpace().BlockStartAnnotationSpace() < LayoutUnit() &&
+ annotation_space_block_start) {
+ const LayoutUnit overflow =
+ -ConstraintSpace().BlockStartAnnotationSpace();
+ block_offset_shift = -std::min(annotation_space_block_start, overflow);
+ }
+
+ // If this line has block-start annotation overflow and the previous line
+ // has block-end annotation space, borrow the block-end space of the
+ // previous line and shift down the block offset by |overflow - space|.
+ if (annotation_overflow_block_start &&
+ ConstraintSpace().BlockStartAnnotationSpace() > LayoutUnit()) {
+ block_offset_shift = (annotation_overflow_block_start -
+ ConstraintSpace().BlockStartAnnotationSpace())
+ .ClampNegativeToZero();
+ }
+ block_offset += block_offset_shift;
- // If this line has block-start annotation overflow and the previous line has
- // block-end annotation space, borrow the block-end space of the previous line
- // and shift down the block offset by |overflow - space|.
- if (annotation_overflow_block_start &&
- ConstraintSpace().BlockStartAnnotationSpace() > LayoutUnit()) {
- block_offset_shift = (annotation_overflow_block_start -
- ConstraintSpace().BlockStartAnnotationSpace())
- .ClampNegativeToZero();
+ if (annotation_overflow_block_end)
+ container_builder_.SetAnnotationOverflow(annotation_overflow_block_end);
+ else if (annotation_space_block_end)
+ container_builder_.SetBlockEndAnnotationSpace(annotation_space_block_end);
}
if (line_info->UseFirstLineStyle())
@@ -476,12 +467,7 @@ void NGInlineLayoutAlgorithm::CreateLine(
container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.SetInlineSize(inline_size);
container_builder_.SetMetrics(line_box_metrics);
- container_builder_.SetBfcBlockOffset(line_info->BfcOffset().block_offset +
- block_offset_shift);
- if (annotation_overflow_block_end)
- container_builder_.SetAnnotationOverflow(annotation_overflow_block_end);
- else if (annotation_space_block_end)
- container_builder_.SetBlockEndAnnotationSpace(annotation_space_block_end);
+ container_builder_.SetBfcBlockOffset(block_offset);
}
void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item,
@@ -769,9 +755,6 @@ void NGInlineLayoutAlgorithm::PlaceRelativePositionedItems(
const auto* physical_fragment = child.PhysicalFragment();
if (!physical_fragment)
continue;
- if (physical_fragment->IsText())
- continue;
-
child.rect.offset += ComputeRelativeOffsetForInline(
ConstraintSpace(), physical_fragment->Style());
}
@@ -1140,20 +1123,13 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
CHECK(is_line_created);
container_builder_.SetExclusionSpace(std::move(exclusion_space));
- if (items_builder) {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- container_builder_.PropagateChildrenData(*line_box);
- scoped_refptr<const NGLayoutResult> layout_result =
- container_builder_.ToLineBoxFragment();
- items_builder->AssociateLogicalLineItems(line_box,
- layout_result->PhysicalFragment());
- return layout_result;
- }
-
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- container_builder_.AddChildren(*line_box);
- container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants();
- return container_builder_.ToLineBoxFragment();
+ DCHECK(items_builder);
+ container_builder_.PropagateChildrenData(*line_box);
+ scoped_refptr<const NGLayoutResult> layout_result =
+ container_builder_.ToLineBoxFragment();
+ items_builder->AssociateLogicalLineItems(line_box,
+ layout_result->PhysicalFragment());
+ return layout_result;
}
// This positions any "leading" floats within the given exclusion space.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
index 24cd2072eb7..9548c89a8b7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -54,7 +54,7 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override {
NOTREACHED();
- return {MinMaxSizes(), true};
+ return MinMaxSizesResult();
}
private:
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
index a1e36bbb549..4e87c6c3cf8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -12,12 +12,10 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
namespace blink {
namespace {
@@ -58,26 +56,24 @@ TEST_F(NGInlineLayoutAlgorithmTest, BreakToken) {
block_flow->Style()->GetWritingDirection());
NGFragmentItemsBuilder items_builder(inline_node,
container_builder.GetWritingDirection());
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- container_builder.SetItemsBuilder(&items_builder);
- context.SetItemsBuilder(&items_builder);
- }
+ container_builder.SetItemsBuilder(&items_builder);
+ context.SetItemsBuilder(&items_builder);
scoped_refptr<const NGLayoutResult> layout_result =
inline_node.Layout(constraint_space, nullptr, &context);
const auto& line1 = layout_result->PhysicalFragment();
- EXPECT_FALSE(line1.BreakToken()->IsFinished());
+ EXPECT_TRUE(line1.BreakToken());
// Perform 2nd layout with the break token from the 1st line.
scoped_refptr<const NGLayoutResult> layout_result2 =
inline_node.Layout(constraint_space, line1.BreakToken(), &context);
const auto& line2 = layout_result2->PhysicalFragment();
- EXPECT_FALSE(line2.BreakToken()->IsFinished());
+ EXPECT_TRUE(line2.BreakToken());
// Perform 3rd layout with the break token from the 2nd line.
scoped_refptr<const NGLayoutResult> layout_result3 =
inline_node.Layout(constraint_space, line2.BreakToken(), &context);
const auto& line3 = layout_result3->PhysicalFragment();
- EXPECT_TRUE(line3.BreakToken()->IsFinished());
+ EXPECT_FALSE(line3.BreakToken());
}
// This test ensures box fragments are generated when necessary, even when the
@@ -229,7 +225,7 @@ TEST_F(NGInlineLayoutAlgorithmTest, MAYBE_VerticalAlignBottomReplaced) {
EXPECT_EQ(LayoutUnit(96), cursor.Current().Size().height);
cursor.MoveToNext();
ASSERT_TRUE(cursor);
- EXPECT_EQ(LayoutUnit(0), cursor.Current().OffsetInContainerBlock().top)
+ EXPECT_EQ(LayoutUnit(0), cursor.Current().OffsetInContainerFragment().top)
<< "Offset top of <img> should be zero.";
}
@@ -451,11 +447,8 @@ TEST_F(NGInlineLayoutAlgorithmTest, InkOverflow) {
)HTML");
auto* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
- const NGPaintFragment* paint_fragment = block_flow->PaintFragment();
const NGPhysicalBoxFragment& box_fragment =
*block_flow->GetPhysicalFragment(0);
- if (paint_fragment)
- ASSERT_EQ(&paint_fragment->PhysicalFragment(), &box_fragment);
EXPECT_EQ(LayoutUnit(10), box_fragment.Size().height);
NGInlineCursor cursor(*block_flow);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index fc36566ab1b..19059a7873c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
#include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h"
@@ -416,10 +415,22 @@ inline bool ShouldBreakShapingAfterBox(const NGInlineItem& item,
}
inline bool NeedsShaping(const NGInlineItem& item) {
- return item.Type() == NGInlineItem::kText && !item.TextShapeResult() &&
- // Text item with length==0 exists to maintain LayoutObject states such
- // as ClearNeedsLayout, but not needed to shape.
- item.Length();
+ if (item.Type() != NGInlineItem::kText)
+ return false;
+ // Text item with length==0 exists to maintain LayoutObject states such as
+ // ClearNeedsLayout, but not needed to shape.
+ if (!item.Length())
+ return false;
+ const ShapeResult* shape_result = item.TextShapeResult();
+ if (!shape_result)
+ return true;
+ // |StartOffset| is usually safe-to-break, but it is not when we shape across
+ // elements and split the |ShapeResult|. Such |ShapeResult| is not safe to
+ // reuse.
+ DCHECK_EQ(item.StartOffset(), shape_result->StartIndex());
+ if (!shape_result->IsStartSafeToBreak())
+ return true;
+ return false;
}
// Determine if reshape is needed for ::first-line style.
@@ -862,7 +873,8 @@ const NGInlineNodeData& NGInlineNode::EnsureData() const {
}
const NGOffsetMapping* NGInlineNode::ComputeOffsetMappingIfNeeded() const {
- DCHECK(!GetLayoutBlockFlow()->GetDocument().NeedsLayoutTreeUpdate());
+ DCHECK(!GetLayoutBlockFlow()->GetDocument().NeedsLayoutTreeUpdate() ||
+ GetLayoutBlockFlow()->IsLayoutNGObjectForCanvasFormattedText());
NGInlineNodeData* data = MutableData();
if (!data->offset_mapping) {
@@ -877,7 +889,8 @@ const NGOffsetMapping* NGInlineNode::ComputeOffsetMappingIfNeeded() const {
void NGInlineNode::ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
NGInlineNodeData* data) {
DCHECK(!data->offset_mapping);
- DCHECK(!layout_block_flow->GetDocument().NeedsLayoutTreeUpdate());
+ DCHECK(!layout_block_flow->GetDocument().NeedsLayoutTreeUpdate() ||
+ layout_block_flow->IsLayoutNGObjectForCanvasFormattedText());
// TODO(xiaochengh): ComputeOffsetMappingIfNeeded() discards the
// NGInlineItems and text content built by |builder|, because they are
@@ -898,7 +911,6 @@ void NGInlineNode::ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
data->text_content = builder.ToString();
} else {
DCHECK(layout_block_flow->IsLayoutNGMixin());
- DCHECK_EQ(data->text_content, builder.ToString());
}
// TODO(xiaochengh): This doesn't compute offset mapping correctly when
@@ -1396,56 +1408,6 @@ void NGInlineNode::AssociateItemsWithInlines(NGInlineNodeData* data) const {
}
}
-void NGInlineNode::ClearAssociatedFragments(
- const NGPhysicalFragment& fragment,
- const NGBlockBreakToken* block_break_token) {
- auto* block_flow = To<LayoutBlockFlow>(fragment.GetMutableLayoutObject());
- if (!block_flow->ChildrenInline())
- return;
- DCHECK(AreNGBlockFlowChildrenInline(block_flow));
- NGInlineNode node = NGInlineNode(block_flow);
-
- DCHECK(node.IsPrepareLayoutFinished());
- const Vector<NGInlineItem>& items = node.MaybeDirtyData().items;
-
- unsigned start_index;
- if (!block_break_token) {
- start_index = 0;
- } else {
- // TODO(kojii): Not fully supported, need more logic when the block is
- // fragmented, because one inline LayoutObject may span across
- // fragmentainers.
- // TODO(kojii): Not sure if using |block_break_token->InputNode()| is
- // correct for multicol. Should verify and somehow get NGInlineNode from it.
- // Also change |InlineBreakTokenFor| to receive NGInlineNode instead of
- // NGLayoutInputNode once this is done.
- const NGInlineBreakToken* inline_break_token =
- block_break_token->InlineBreakTokenFor(block_break_token->InputNode());
- // TODO(kojii): This needs to investigate in what case this happens. It's
- // probably wrong to create NGPaintFragment when there's no inline break
- // token.
- if (!inline_break_token)
- return;
- start_index = inline_break_token->ItemIndex();
- }
-
- LayoutObject* last_object = nullptr;
- for (unsigned i = start_index; i < items.size(); i++) {
- const NGInlineItem& item = items[i];
- if (item.Type() == NGInlineItem::kFloating ||
- item.Type() == NGInlineItem::kOutOfFlowPositioned) {
- // These items are not associated and that no need to clear.
- DCHECK(!item.GetLayoutObject()->FirstInlineFragment());
- continue;
- }
- LayoutObject* object = item.GetLayoutObject();
- if (!object || object == last_object)
- continue;
- object->SetFirstInlineFragment(nullptr);
- last_object = object;
- }
-}
-
scoped_refptr<const NGLayoutResult> NGInlineNode::Layout(
const NGConstraintSpace& constraint_space,
const NGBreakToken* break_token,
@@ -1455,27 +1417,7 @@ scoped_refptr<const NGLayoutResult> NGInlineNode::Layout(
const auto* inline_break_token = To<NGInlineBreakToken>(break_token);
NGInlineLayoutAlgorithm algorithm(*this, constraint_space, inline_break_token,
context);
- auto layout_result = algorithm.Layout();
-
-#if defined(OS_ANDROID)
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // Cached position data is crucial for line breaking performance and is
- // preserved across layouts to speed up subsequent layout passes due to
- // reflow, page zoom, window resize, etc. On Android though reflows are less
- // common, page zoom isn't used (instead uses pinch-zoom), and the window
- // typically can't be resized (apart from rotation). To reduce memory usage
- // discard the cached position data after layout.
- // TODO(crbug.com/1042604): FragmentItem should save memory enough to re-
- // enable the position cache.
- NGInlineNodeData* data = MutableData();
- for (auto& item : data->items) {
- if (item.shape_result_)
- item.shape_result_->DiscardPositionData();
- }
- }
-#endif // defined(OS_ANDROID)
-
- return layout_result;
+ return algorithm.Layout();
}
namespace {
@@ -1835,7 +1777,7 @@ MinMaxSizesResult NGInlineNode::ComputeMinMaxSizes(
// Negative text-indent can make min > max. Ensure min is the minimum size.
sizes.min_size = std::min(sizes.min_size, sizes.max_size);
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
bool NGInlineNode::UseFirstLineStyle() const {
@@ -1861,6 +1803,10 @@ bool NGInlineNode::ShouldReportLetterSpacingUseCounterForTesting(
block_flow);
}
+bool NGInlineNode::NeedsShapingForTesting(const NGInlineItem& item) {
+ return NeedsShaping(item);
+}
+
String NGInlineNode::ToString() const {
return "NGInlineNode";
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index 4a498aff546..61ec42cffb5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -9,13 +9,11 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-class NGBlockBreakToken;
class NGConstraintSpace;
class NGInlineChildLayoutContext;
class NGInlineNodeLegacy;
@@ -53,8 +51,6 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
LayoutBlockFlow* block_flow = GetLayoutBlockFlow();
block_flow->ResetNGInlineNodeData();
DCHECK(!IsPrepareLayoutFinished());
- // There shouldn't be paint fragment if NGInlineNodeData does not exist.
- block_flow->SetPaintFragment(nullptr, nullptr);
}
const NGInlineItemsData& ItemsData(bool is_first_line) const {
@@ -75,12 +71,6 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// needed.
static String TextContentForStickyImagesQuirk(const NGInlineItemsData&);
- // Clear associated fragments for LayoutObjects.
- // They are associated when NGPaintFragment is constructed, but when clearing,
- // NGInlineItem provides easier and faster logic.
- static void ClearAssociatedFragments(const NGPhysicalFragment& fragment,
- const NGBlockBreakToken* break_token);
-
// Returns true if we don't need to collect inline items after replacing
// |layout_text| after deleting replacing subtext from |offset| to |length|
// |new_text| is new text of |layout_text|.
@@ -137,6 +127,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
LayoutUnit float_inline_max_size_with_margin;
};
+ static bool NeedsShapingForTesting(const NGInlineItem& item);
+
protected:
FRIEND_TEST_ALL_PREFIXES(NGInlineNodeTest, SegmentBidiChangeSetsNeedsLayout);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 67e3626c860..c15455a5ecf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -14,14 +14,12 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/svg_names.h"
@@ -82,16 +80,10 @@ class NGInlineNodeForTest : public NGInlineNode {
class NGInlineNodeTest : public NGLayoutTest {
protected:
- void SetUp() override {
- NGLayoutTest::SetUp();
- style_ = ComputedStyle::Create();
- }
-
void SetupHtml(const char* id, String html) {
SetBodyInnerHTML(html);
layout_block_flow_ = To<LayoutNGBlockFlow>(GetLayoutObjectByElementId(id));
layout_object_ = layout_block_flow_->FirstChild();
- style_ = layout_object_ ? layout_object_->Style() : nullptr;
}
void UseLayoutObjectAndAhem() {
@@ -160,7 +152,6 @@ class NGInlineNodeTest : public NGLayoutTest {
EXPECT_FALSE(expected);
}
- scoped_refptr<const ComputedStyle> style_;
LayoutNGBlockFlow* layout_block_flow_ = nullptr;
LayoutObject* layout_object_ = nullptr;
FontCachePurgePreventer purge_preventer_;
@@ -691,14 +682,12 @@ TEST_P(StyleChangeTest, NeedsCollectInlinesOnStyle) {
EXPECT_FALSE(previous->GetLayoutObject()->NeedsCollectInlines());
EXPECT_FALSE(next->GetLayoutObject()->NeedsCollectInlines());
- if (data.is_line_dirty &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (data.is_line_dirty) {
TestAnyItemsAreDirty(*To<LayoutBlockFlow>(container->GetLayoutObject()),
*data.is_line_dirty);
}
- if (data.invalidate_ink_overflow &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (data.invalidate_ink_overflow) {
const LayoutObject* parent_layout_object = parent->GetLayoutObject();
for (const LayoutObject* child = parent_layout_object->SlowFirstChild();
child; child = child->NextInPreOrder(parent_layout_object)) {
@@ -886,12 +875,7 @@ TEST_F(NGInlineNodeTest, CollectInlinesShouldNotClearFirstInlineFragment) {
// Running |CollectInlines| should not clear |FirstInlineFragment|.
LayoutObject* first_child = container->firstChild()->GetLayoutObject();
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // TODO(yosin): We should use |FirstInlineItemFragmentIndex()| once we
- // implement it.
- } else {
- EXPECT_NE(first_child->FirstInlineFragment(), nullptr);
- }
+ EXPECT_TRUE(first_child->HasInlineFragments());
}
TEST_F(NGInlineNodeTest, SegmentBidiChangeSetsNeedsLayout) {
@@ -1136,8 +1120,6 @@ TEST_F(NGInlineNodeTest, ClearFirstInlineFragmentOnSplitFlow) {
NGInlineCursor before_split;
before_split.MoveTo(*text->GetLayoutObject());
EXPECT_TRUE(before_split);
- scoped_refptr<const NGPaintFragment> text_fragment_before_split =
- before_split.Current().PaintFragment();
// Append <div> to <span>. causing SplitFlow().
Element* outer_span = GetElementById("outer_span");
@@ -1160,10 +1142,6 @@ TEST_F(NGInlineNodeTest, ClearFirstInlineFragmentOnSplitFlow) {
NGInlineCursor after_layout;
after_layout.MoveTo(*text->GetLayoutObject());
EXPECT_TRUE(after_layout);
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- EXPECT_NE(text_fragment_before_split.get(),
- after_layout.Current().PaintFragment());
- }
// Check it is the one owned by the new root inline formatting context.
LayoutBlock* anonymous_block =
@@ -1175,10 +1153,6 @@ TEST_F(NGInlineNodeTest, ClearFirstInlineFragmentOnSplitFlow) {
EXPECT_TRUE(anonymous_block_cursor);
EXPECT_EQ(anonymous_block_cursor.Current().GetLayoutObject(),
text->GetLayoutObject());
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- EXPECT_EQ(anonymous_block_cursor.Current().PaintFragment(),
- after_layout.Current().PaintFragment());
- }
}
TEST_F(NGInlineNodeTest, AddChildToSVGRoot) {
@@ -1389,6 +1363,58 @@ TEST_F(NGInlineNodeTest, ReusingRTLAsLTR) {
TEST_ITEM_OFFSET_DIR(Items()[2], 10u, 10u, TextDirection::kLtr);
}
+TEST_F(NGInlineNodeTest, ReuseFirstNonSafe) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ p {
+ font-size: 50px;
+ }
+ </style>
+ <p id="p">
+ <span>A</span>V
+ </p>
+ )HTML");
+ auto* block_flow = To<LayoutNGBlockFlow>(GetLayoutObjectByElementId("p"));
+ const NGInlineNodeData* data = block_flow->GetNGInlineNodeData();
+ ASSERT_TRUE(data);
+ const Vector<NGInlineItem>& items = data->items;
+
+ // We shape "AV" together, which usually has kerning between "A" and "V", then
+ // split the |ShapeResult| to two |NGInlineItem|s. The |NGInlineItem| for "V"
+ // is not safe to reuse even if its style does not change.
+ const NGInlineItem& item_v = items[3];
+ EXPECT_EQ(item_v.Type(), NGInlineItem::kText);
+ EXPECT_EQ(
+ StringView(data->text_content, item_v.StartOffset(), item_v.Length()),
+ "V");
+ EXPECT_TRUE(NGInlineNode::NeedsShapingForTesting(item_v));
+}
+
+TEST_F(NGInlineNodeTest, ReuseFirstNonSafeRtl) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ p {
+ font-size: 50px;
+ unicode-bidi: bidi-override;
+ direction: rtl;
+ }
+ </style>
+ <p id="p">
+ <span>A</span>V
+ </p>
+ )HTML");
+ auto* block_flow = To<LayoutNGBlockFlow>(GetLayoutObjectByElementId("p"));
+ const NGInlineNodeData* data = block_flow->GetNGInlineNodeData();
+ ASSERT_TRUE(data);
+ const Vector<NGInlineItem>& items = data->items;
+ const NGInlineItem& item_v = items[4];
+ EXPECT_EQ(item_v.Type(), NGInlineItem::kText);
+ EXPECT_EQ(
+ StringView(data->text_content, item_v.StartOffset(), item_v.Length()),
+ "V");
+ EXPECT_TRUE(NGInlineNode::NeedsShapingForTesting(item_v));
+}
+
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterFalse) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em; text-align: center">
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 98d10b680be..91a90d02e4f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -21,7 +20,7 @@ namespace blink {
void NGLineBoxFragmentBuilder::Reset() {
children_.Shrink(0);
child_break_tokens_.Shrink(0);
- inline_break_tokens_.Shrink(0);
+ last_inline_break_token_ = nullptr;
oof_positioned_candidates_.Shrink(0);
unpositioned_list_marker_ = NGUnpositionedListMarker();
@@ -46,32 +45,11 @@ void NGLineBoxFragmentBuilder::AddChild(
AddChildInternal(&child, child_offset);
}
-void NGLineBoxFragmentBuilder::AddChildren(NGLogicalLineItems& children) {
- children_.ReserveCapacity(children.size());
-
- for (auto& child : children) {
- if (child.layout_result) {
- DCHECK(!child.text_fragment);
- AddChild(child.layout_result->PhysicalFragment(), child.Offset());
- child.layout_result.reset();
- } else if (child.text_fragment) {
- AddChild(std::move(child.text_fragment), child.Offset());
- DCHECK(!child.text_fragment);
- } else if (child.out_of_flow_positioned_box) {
- AddOutOfFlowInlineChildCandidate(
- NGBlockNode(To<LayoutBox>(child.out_of_flow_positioned_box)),
- child.Offset(), child.container_direction);
- child.out_of_flow_positioned_box = nullptr;
- }
- }
-}
-
void NGLineBoxFragmentBuilder::PropagateChildrenData(
NGLogicalLineItems& children) {
for (unsigned index = 0; index < children.size(); ++index) {
auto& child = children[index];
if (child.layout_result) {
- DCHECK(!child.text_fragment);
PropagateChildData(child.layout_result->PhysicalFragment(),
child.Offset());
@@ -98,9 +76,6 @@ scoped_refptr<const NGLayoutResult>
NGLineBoxFragmentBuilder::ToLineBoxFragment() {
writing_direction_.SetWritingMode(ToLineWritingMode(GetWritingMode()));
- if (!break_token_)
- break_token_ = NGInlineBreakToken::Create(node_);
-
scoped_refptr<const NGPhysicalLineBoxFragment> fragment =
NGPhysicalLineBoxFragment::Create(this);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index af710f71625..bf4aca76d67 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
@@ -68,21 +67,13 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
}
// Set the break token for the fragment to build.
- // A finished break token will be attached if not set.
+ // Is nullptr if we didn't break.
void SetBreakToken(scoped_refptr<NGInlineBreakToken> break_token) {
break_token_ = std::move(break_token);
}
- void AddChild(scoped_refptr<const NGPhysicalTextFragment> child,
- const LogicalOffset& offset) {
- AddChildInternal(child, offset);
- }
-
void AddChild(const NGPhysicalContainerFragment&, const LogicalOffset&);
- // Add all items in ChildList. Skips null Child if any.
- void AddChildren(NGLogicalLineItems&);
-
// Propagate data in |ChildList| without adding them to this builder. When
// adding children as fragment items, they appear in the container, but there
// are some data that should be propagated through line box fragments.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 5f5264bd049..354b3dacc13 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
@@ -935,7 +934,7 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
// TODO(crbug.com/1003742): We should use |result.is_overflow| here. For now,
// use |inline_size| because some tests rely on this behavior.
- return inline_size <= available_width ? kSuccess : kOverflow;
+ return inline_size <= available_width_with_hyphens ? kSuccess : kOverflow;
}
// Breaks the text item at the previous break opportunity from
@@ -1421,6 +1420,10 @@ void NGLineBreaker::HandleControlItem(const NGInlineItem& item,
HandleCloseTag(next_item, line_info);
continue;
}
+ if (next_item.Type() == NGInlineItem::kText && !next_item.Length()) {
+ HandleEmptyText(next_item, line_info);
+ continue;
+ }
break;
}
@@ -2282,10 +2285,8 @@ const ComputedStyle& NGLineBreaker::ComputeCurrentStyle(
}
// Use the style at the beginning of the line if no items are available.
- if (break_token_) {
- DCHECK(break_token_->Style());
+ if (break_token_ && break_token_->Style())
return *break_token_->Style();
- }
return line_info->LineStyle();
}
@@ -2382,7 +2383,7 @@ scoped_refptr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken(
const Vector<NGInlineItem>& items = Items();
DCHECK_LE(item_index_, items.size());
if (item_index_ >= items.size())
- return NGInlineBreakToken::Create(node_);
+ return nullptr;
return NGInlineBreakToken::Create(
node_, current_style_.get(), item_index_, offset_,
(is_after_forced_break_ ? NGInlineBreakToken::kIsForcedBreak : 0) |
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 6fcf09f66f9..2f12a09fc93 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -63,7 +63,7 @@ class NGLineBreakerTest : public NGLayoutTest {
NGExclusionSpace exclusion_space;
NGPositionedFloatVector leading_floats;
NGLineLayoutOpportunity line_opportunity(available_width);
- while (!break_token || !break_token->IsFinished()) {
+ do {
NGLineInfo line_info;
NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, space,
line_opportunity, leading_floats, 0u,
@@ -85,7 +85,7 @@ class NGLineBreakerTest : public NGLayoutTest {
}
lines.push_back(std::make_pair(ToString(line_info.Results(), node),
line_info.Results().back().item_index));
- }
+ } while (break_token);
return lines;
}
@@ -605,6 +605,38 @@ TEST_F(NGLineBreakerTest, SplitTextZero) {
EXPECT_EQ("ab", lines[1].first);
}
+TEST_F(NGLineBreakerTest, ForcedBreakFollowedByCloseTag) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <div id="container">
+ <div><span>line<br></span></div>
+ <div>
+ <span>line<br></span>
+ </div>
+ <div>
+ <span>
+ line<br>
+ </span>
+ </div>
+ <div>
+ <span>line<br> </span>
+ </div>
+ <div>
+ <span>line<br> </span>&#32;&#32;
+ </div>
+ </div>
+ )HTML");
+ const LayoutObject* container = GetLayoutObjectByElementId("container");
+ for (const LayoutObject* child = container->SlowFirstChild(); child;
+ child = child->NextSibling()) {
+ NGInlineCursor cursor(*To<LayoutBlockFlow>(child));
+ wtf_size_t line_count = 0;
+ for (cursor.MoveToFirstLine(); cursor; cursor.MoveToNextLine())
+ ++line_count;
+ EXPECT_EQ(line_count, 1u);
+ }
+}
+
TEST_F(NGLineBreakerTest, TableCellWidthCalculationQuirkOutOfFlow) {
NGInlineNode node = CreateInlineNode(R"HTML(
<style>
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
index e51cbcc56de..cfe7c9988b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
@@ -18,13 +17,13 @@ namespace blink {
namespace {
bool IsLeftMostOffset(const ShapeResult& shape_result, unsigned offset) {
- if (shape_result.Rtl())
+ if (shape_result.IsRtl())
return offset == shape_result.NumCharacters();
return offset == 0;
}
bool IsRightMostOffset(const ShapeResult& shape_result, unsigned offset) {
- if (shape_result.Rtl())
+ if (shape_result.IsRtl())
return offset == 0;
return offset == shape_result.NumCharacters();
}
@@ -63,7 +62,7 @@ LayoutUnit NGLineTruncator::PlaceEllipsisNextTo(
NGLogicalLineItem* ellipsized_child) {
// Create the ellipsis, associating it with the ellipsized child.
DCHECK(ellipsized_child->HasInFlowFragment());
- LayoutObject* ellipsized_layout_object =
+ const LayoutObject* ellipsized_layout_object =
ellipsized_child->GetMutableLayoutObject();
DCHECK(ellipsized_layout_object);
DCHECK(ellipsized_layout_object->IsInline());
@@ -85,14 +84,12 @@ LayoutUnit NGLineTruncator::PlaceEllipsisNextTo(
DCHECK(ellipsis_text_);
DCHECK(ellipsis_shape_result_.get());
- NGTextFragmentBuilder builder(line_style_->GetWritingMode());
- builder.SetText(ellipsized_layout_object, ellipsis_text_, &EllipsisStyle(),
- NGStyleVariant::kEllipsis, std::move(ellipsis_shape_result_),
- {ellipsis_width_, ellipsis_metrics.LineHeight()});
line_box->AddChild(
- builder.ToTextFragment(),
- LogicalOffset{ellipsis_inline_offset, -ellipsis_metrics.ascent},
- ellipsis_width_, 0);
+ *ellipsized_layout_object, NGStyleVariant::kEllipsis,
+ std::move(ellipsis_shape_result_), ellipsis_text_,
+ LogicalRect(ellipsis_inline_offset, -ellipsis_metrics.ascent,
+ ellipsis_width_, ellipsis_metrics.LineHeight()),
+ /* bidi_level */ 0);
return ellipsis_inline_offset;
}
@@ -115,7 +112,7 @@ wtf_size_t NGLineTruncator::AddTruncatedChild(
return kDidNotAddChild;
text_offset =
shape_result->OffsetToFit(shape_result->PositionForOffset(
- IsRtl(edge) == shape_result->Rtl()
+ IsRtl(edge) == shape_result->IsRtl()
? 1
: shape_result->NumCharacters() - 1),
edge);
@@ -130,9 +127,6 @@ wtf_size_t NGLineTruncator::AddTruncatedChild(
LayoutUnit NGLineTruncator::TruncateLine(LayoutUnit line_width,
NGLogicalLineItems* line_box,
NGInlineLayoutStateStack* box_states) {
- DCHECK(std::all_of(line_box->begin(), line_box->end(),
- [](const auto& item) { return !item.text_fragment; }));
-
// Shape the ellipsis and compute its inline size.
SetupEllipsis();
@@ -250,6 +244,10 @@ LayoutUnit NGLineTruncator::TruncateLineInTheMiddle(
// |line_width| and/or InlineOffset() might be saturated.
if (line_width <= item.InlineOffset())
return line_width;
+ // We can do nothing if the right-side static item sticks out to the both
+ // sides.
+ if (item.InlineOffset() < 0)
+ return line_width;
static_width_right =
line_width - item.InlineOffset() + item.margin_line_left;
}
@@ -404,11 +402,6 @@ LayoutUnit NGLineTruncator::TruncateLineInTheMiddle(
void NGLineTruncator::HideChild(NGLogicalLineItem* child) {
DCHECK(child->HasInFlowFragment());
- if (const NGPhysicalTextFragment* text = child->text_fragment.get()) {
- child->text_fragment = text->CloneAsHiddenForPaint();
- return;
- }
-
if (const NGLayoutResult* layout_result = child->layout_result.get()) {
// Need to propagate OOF descendants in this inline-block child.
const auto& fragment =
@@ -493,7 +486,6 @@ bool NGLineTruncator::TruncateChild(
const NGLogicalLineItem& child,
base::Optional<NGLogicalLineItem>* truncated_child) {
DCHECK(truncated_child && !*truncated_child);
- DCHECK(!child.text_fragment);
// If the space is not enough, try the next child.
if (space_for_child <= 0 && !is_first_child)
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc
index 0223281fce9..dcd82490e62 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
namespace blink {
@@ -26,8 +25,8 @@ LayoutObject* NGLogicalLineItem::GetMutableLayoutObject() const {
}
const Node* NGLogicalLineItem::GetNode() const {
- if (const LayoutObject* layout_object = GetLayoutObject())
- return layout_object->GetNode();
+ if (const LayoutObject* object = GetLayoutObject())
+ return object->GetNode();
return nullptr;
}
@@ -39,31 +38,20 @@ const ComputedStyle* NGLogicalLineItem::Style() const {
return nullptr;
}
-void NGLogicalLineItems::CreateTextFragments(WritingMode writing_mode,
- const String& text_content) {
- NGTextFragmentBuilder text_builder(writing_mode);
- for (auto& child : *this) {
- if (const NGInlineItem* inline_item = child.inline_item) {
- if (UNLIKELY(child.text_content)) {
- // Create a generated text fragmment.
- text_builder.SetText(inline_item->GetLayoutObject(), child.text_content,
- inline_item->Style(), inline_item->StyleVariant(),
- std::move(child.shape_result), child.MarginSize());
- } else {
- // Create a regular text fragmment.
- DCHECK((inline_item->Type() == NGInlineItem::kText &&
- (inline_item->TextType() == NGTextType::kNormal ||
- inline_item->TextType() == NGTextType::kSymbolMarker)) ||
- inline_item->Type() == NGInlineItem::kControl);
- text_builder.SetItem(text_content, *inline_item,
- std::move(child.shape_result), child.text_offset,
- child.MarginSize());
- }
- text_builder.SetIsHiddenForPaint(child.is_hidden_for_paint);
- DCHECK(!child.text_fragment);
- child.text_fragment = text_builder.ToTextFragment();
- }
- }
+std::ostream& operator<<(std::ostream& stream, const NGLogicalLineItem& item) {
+ stream << "NGLogicalLineItem(";
+ if (item.IsPlaceholder())
+ stream << " placeholder";
+ stream << " inline_size=" << item.inline_size;
+ if (item.inline_item)
+ stream << " " << item.inline_item->ToString().Utf8().c_str();
+ if (item.PhysicalFragment())
+ stream << " Fragment=" << *item.PhysicalFragment();
+ if (item.GetLayoutObject())
+ stream << " LayoutObject=" << *item.GetLayoutObject();
+ stream << ")";
+ // Feel free to add more information.
+ return stream;
}
NGLogicalLineItem* NGLogicalLineItems::FirstInFlowChild() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h
index 13b22998b58..3a604e48c46 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h
@@ -8,8 +8,9 @@
#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
@@ -77,6 +78,7 @@ struct NGLogicalLineItem {
rect(LayoutUnit(), block_offset, LayoutUnit(), text_height),
inline_size(inline_size),
bidi_level(bidi_level) {}
+ // Create a generated text.
NGLogicalLineItem(const NGInlineItem& inline_item,
scoped_refptr<const ShapeResultView> shape_result,
const String& text_content,
@@ -92,6 +94,23 @@ struct NGLogicalLineItem {
rect(LayoutUnit(), block_offset, LayoutUnit(), text_height),
inline_size(inline_size),
bidi_level(bidi_level) {}
+ // Create an ellipsis item. Ellipsis is a generated text, but does not have
+ // corresponding |NGInlineItem| as it is generated by layout.
+ NGLogicalLineItem(const LayoutObject& layout_object,
+ NGStyleVariant style_variant,
+ scoped_refptr<const ShapeResultView> shape_result,
+ const String& text_content,
+ const LogicalRect& rect,
+ UBiDiLevel bidi_level)
+ : shape_result(std::move(shape_result)),
+ text_offset(
+ {this->shape_result->StartIndex(), this->shape_result->EndIndex()}),
+ text_content(text_content),
+ layout_object(&layout_object),
+ style_variant(style_variant),
+ rect(rect),
+ inline_size(rect.size.inline_size),
+ bidi_level(bidi_level) {}
NGLogicalLineItem(const NGLogicalLineItem& source_item,
scoped_refptr<const ShapeResultView> shape_result,
const NGTextOffset& text_offset)
@@ -102,22 +121,6 @@ struct NGLogicalLineItem {
rect(source_item.rect),
inline_size(this->shape_result->SnappedWidth()),
bidi_level(source_item.bidi_level) {}
- NGLogicalLineItem(scoped_refptr<const NGPhysicalTextFragment> fragment,
- LogicalOffset offset,
- LayoutUnit inline_size,
- UBiDiLevel bidi_level)
- : text_fragment(std::move(fragment)),
- rect(offset, LogicalSize()),
- inline_size(inline_size),
- bidi_level(bidi_level) {}
- NGLogicalLineItem(scoped_refptr<const NGPhysicalTextFragment> fragment,
- LayoutUnit block_offset,
- LayoutUnit inline_size,
- UBiDiLevel bidi_level)
- : text_fragment(std::move(fragment)),
- rect(LayoutUnit(), block_offset, LayoutUnit(), LayoutUnit()),
- inline_size(inline_size),
- bidi_level(bidi_level) {}
// Create an out-of-flow positioned object.
NGLogicalLineItem(LayoutObject* out_of_flow_positioned_box,
UBiDiLevel bidi_level,
@@ -140,11 +143,11 @@ struct NGLogicalLineItem {
return layout_result && layout_result->PhysicalFragment().IsInlineBox();
}
bool HasInFlowFragment() const {
- return text_fragment || inline_item ||
+ return inline_item ||
(layout_result && !layout_result->PhysicalFragment().IsFloating());
}
bool HasInFlowOrFloatingFragment() const {
- return text_fragment || inline_item || layout_result;
+ return inline_item || layout_result || layout_object;
}
bool HasOutOfFlowFragment() const { return out_of_flow_positioned_box; }
bool HasFragment() const {
@@ -162,10 +165,8 @@ struct NGLogicalLineItem {
// Skip all inline boxes. Fragments for inline boxes maybe created earlier
// if they have no children.
if (layout_result) {
- const LayoutObject* layout_object =
- layout_result->PhysicalFragment().GetLayoutObject();
- DCHECK(layout_object);
- if (layout_object->IsLayoutInline())
+ DCHECK(layout_result->PhysicalFragment().GetLayoutObject());
+ if (layout_result->PhysicalFragment().GetLayoutObject()->IsLayoutInline())
return true;
}
return false;
@@ -178,10 +179,10 @@ struct NGLogicalLineItem {
const LogicalSize& Size() const { return rect.size; }
LogicalSize MarginSize() const { return {inline_size, Size().block_size}; }
- const NGPhysicalFragment* PhysicalFragment() const {
+ const NGPhysicalContainerFragment* PhysicalFragment() const {
if (layout_result)
return &layout_result->PhysicalFragment();
- return text_fragment.get();
+ return nullptr;
}
const LayoutObject* GetLayoutObject() const;
LayoutObject* GetMutableLayoutObject() const;
@@ -199,9 +200,9 @@ struct NGLogicalLineItem {
}
scoped_refptr<const NGLayoutResult> layout_result;
- scoped_refptr<const NGPhysicalTextFragment> text_fragment;
// Data to create a text fragment from.
+ // |inline_item| is null only for ellipsis items.
const NGInlineItem* inline_item = nullptr;
scoped_refptr<const ShapeResultView> shape_result;
NGTextOffset text_offset;
@@ -209,6 +210,12 @@ struct NGLogicalLineItem {
// Data to create a generated text fragment.
String text_content;
+ // Ellipsis does not have |NGInlineItem|, but built from |LayoutObject| and
+ // |NGStyleVariant|.
+ const LayoutObject* layout_object = nullptr;
+ // Used only when |layout_object_| is not null.
+ NGStyleVariant style_variant = NGStyleVariant::kStandard;
+
LayoutObject* out_of_flow_positioned_box = nullptr;
LayoutObject* unpositioned_float = nullptr;
// The offset of the border box, initially in this child coordinate system.
@@ -237,6 +244,9 @@ struct NGLogicalLineItem {
bool is_hidden_for_paint = false;
};
+CORE_EXPORT std::ostream& operator<<(std::ostream& stream,
+ const NGLogicalLineItem& item);
+
// A vector of Child.
// Unlike the fragment builder, chlidren are mutable.
// Callers can add to the fragment builder in a batch once finalized.
@@ -300,10 +310,6 @@ class NGLogicalLineItems {
void MoveInBlockDirection(LayoutUnit);
void MoveInBlockDirection(LayoutUnit, unsigned start, unsigned end);
- // Create |NGPhysicalTextFragment| for all text children.
- void CreateTextFragments(WritingMode writing_mode,
- const String& text_content);
-
private:
void WillInsertChild(unsigned index);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
index 75ec76e27a0..1d7022f867a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
@@ -332,6 +332,7 @@ NGOffsetMapping::UnitVector NGOffsetMapping::GetMappingUnitsForDOMRange(
});
UnitVector result;
+ result.ReserveCapacity(result_end - result_begin);
for (const auto& unit : base::make_span(result_begin, result_end)) {
// If the unit isn't fully within the range, create a new unit that's
// within the range.
@@ -368,7 +369,7 @@ NGOffsetMapping::GetMappingUnitsForLayoutObject(
[&layout_object](const NGOffsetMappingUnit& unit) {
return unit.GetLayoutObject() == layout_object;
});
- DCHECK_NE(begin, units_.end());
+ CHECK_NE(begin, units_.end());
const auto* end =
std::find_if(std::next(begin), units_.end(),
[&layout_object](const NGOffsetMappingUnit& unit) {
@@ -500,7 +501,7 @@ Position NGOffsetMapping::GetFirstPosition(unsigned offset) const {
[](const NGOffsetMappingUnit& unit, unsigned offset) {
return unit.TextContentEnd() < offset;
});
- DCHECK_NE(result, units_.end());
+ CHECK_NE(result, units_.end());
// Skip CSS generated content, e.g. "content" property in ::before/::after.
while (!result->AssociatedNode()) {
result = std::next(result);
@@ -552,7 +553,7 @@ const NGOffsetMappingUnit* NGOffsetMapping::GetLastMappingUnit(
[](unsigned offset, const NGOffsetMappingUnit& unit) {
return offset < unit.TextContentStart();
});
- DCHECK_NE(result, units_.begin());
+ CHECK_NE(result, units_.begin());
result = std::prev(result);
if (result->TextContentEnd() < offset)
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
index 651cc8e199b..1785a2a6dfe 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
@@ -93,17 +93,11 @@ class NGOffsetMappingTest : public NGLayoutTest {
static const auto kCollapsed = NGOffsetMappingUnitType::kCollapsed;
static const auto kIdentity = NGOffsetMappingUnitType::kIdentity;
- void SetUp() override {
- NGLayoutTest::SetUp();
- style_ = ComputedStyle::Create();
- }
-
void SetupHtml(const char* id, String html) {
SetBodyInnerHTML(html);
layout_block_flow_ = To<LayoutBlockFlow>(GetLayoutObjectByElementId(id));
DCHECK(layout_block_flow_->IsLayoutNGMixin());
layout_object_ = layout_block_flow_->FirstChild();
- style_ = layout_object_->Style();
}
const NGOffsetMapping& GetOffsetMapping() const {
@@ -235,7 +229,6 @@ class NGOffsetMappingTest : public NGLayoutTest {
return GetOffsetMapping().GetLastPosition(offset);
}
- scoped_refptr<const ComputedStyle> style_;
LayoutBlockFlow* layout_block_flow_ = nullptr;
LayoutObject* layout_object_ = nullptr;
FontCachePurgePreventer purge_preventer_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index eac391fb224..36ee4f676d9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -120,7 +119,6 @@ PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflowForLine(
const NGFragmentItem& line,
const NGInlineCursor& cursor,
TextHeightType height_type) const {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_EQ(&line, cursor.CurrentItem());
DCHECK_EQ(line.LineBoxFragment(), this);
@@ -132,15 +130,15 @@ PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflowForLine(
// Make sure we include the inline-size of the line-box in the overflow.
// Note, the bottom half-leading should not be included. crbug.com/996847
const WritingMode container_writing_mode = container_style.GetWritingMode();
- AddInlineSizeToOverflow(line.RectInContainerBlock(), container_writing_mode,
- &overflow);
+ AddInlineSizeToOverflow(line.RectInContainerFragment(),
+ container_writing_mode, &overflow);
return overflow;
}
bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const {
- const auto& break_token = To<NGInlineBreakToken>(*BreakToken());
- return !break_token.IsFinished() && !break_token.IsForcedBreak();
+ const auto* break_token = To<NGInlineBreakToken>(BreakToken());
+ return break_token && !break_token->IsForcedBreak();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
index 491852b63e2..f46530c6e9d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -31,7 +31,7 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
static scoped_refptr<const NGPhysicalLineBoxFragment> Create(
NGLineBoxFragmentBuilder* builder);
- using PassKey = util::PassKey<NGPhysicalLineBoxFragment>;
+ using PassKey = base::PassKey<NGPhysicalLineBoxFragment>;
NGPhysicalLineBoxFragment(PassKey, NGLineBoxFragmentBuilder* builder);
~NGPhysicalLineBoxFragment() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
index 86cada3f732..667f5788fe4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
@@ -4,8 +4,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -22,18 +21,10 @@ class NGPhysicalLineBoxFragmentTest : public NGLayoutTest {
const LayoutObject* layout_object = container->GetLayoutObject();
DCHECK(layout_object) << container;
DCHECK(layout_object->IsLayoutBlockFlow()) << container;
- const NGPhysicalBoxFragment* root_fragment =
- To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0);
- DCHECK(root_fragment) << container;
-
+ NGInlineCursor cursor(*To<LayoutBlockFlow>(layout_object));
Vector<const NGPhysicalLineBoxFragment*> lines;
- for (const auto& child :
- NGInlineFragmentTraversal::DescendantsOf(*root_fragment)) {
- if (const NGPhysicalLineBoxFragment* line =
- DynamicTo<NGPhysicalLineBoxFragment>(child.fragment.get())) {
- lines.push_back(line);
- }
- }
+ for (cursor.MoveToFirstLine(); cursor; cursor.MoveToNextLine())
+ lines.push_back(cursor.Current()->LineBoxFragment());
return lines;
}
@@ -45,9 +36,6 @@ class NGPhysicalLineBoxFragmentTest : public NGLayoutTest {
}
};
-#define EXPECT_TEXT_FRAGMENT(text, fragment) \
- { EXPECT_EQ(text, To<NGPhysicalTextFragment>(fragment)->Text().ToString()); }
-
#define EXPECT_BOX_FRAGMENT(id, fragment) \
{ \
EXPECT_TRUE(fragment); \
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
deleted file mode 100644
index 268b91ef68b..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-
-#include "third_party/blink/renderer/core/dom/node.h"
-#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
-#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
-#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
-#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
-
-namespace blink {
-
-namespace {
-
-struct SameSizeAsNGPhysicalTextFragment : NGPhysicalFragment {
- void* pointers[3];
- unsigned offsets[2];
-};
-
-ASSERT_SIZE(NGPhysicalTextFragment, SameSizeAsNGPhysicalTextFragment);
-
-} // anonymous namespace
-
-NGPhysicalTextFragment::NGPhysicalTextFragment(NGTextFragmentBuilder* builder)
- : NGPhysicalFragment(builder,
- kFragmentText,
- static_cast<unsigned>(builder->text_type_)),
- text_(builder->text_),
- text_offset_(builder->text_offset_),
- shape_result_(std::move(builder->shape_result_)) {
- DCHECK(shape_result_ || IsFlowControl()) << *this;
- base_or_resolved_direction_ =
- static_cast<unsigned>(builder->ResolvedDirection());
- ink_overflow_computed_ = false;
-}
-
-bool NGPhysicalTextFragment::IsGeneratedText() const {
- if (UNLIKELY(TextType() == NGTextType::kLayoutGenerated))
- return true;
- return GetLayoutObject()->IsStyleGenerated();
-}
-
-LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
- unsigned offset,
- LayoutUnit (*round_function)(float),
- AdjustMidCluster adjust_mid_cluster) const {
- return NGFragmentItem(*this).InlinePositionForOffset(
- Text(), offset, round_function, adjust_mid_cluster);
-}
-
-// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
-// "ng_fragment_item.cc"
-// Compute the inline position from text offset, in logical coordinate relative
-// to this fragment.
-LayoutUnit NGFragmentItem::InlinePositionForOffset(
- StringView text,
- unsigned offset,
- LayoutUnit (*round_function)(float),
- AdjustMidCluster adjust_mid_cluster) const {
- DCHECK_GE(offset, StartOffset());
- DCHECK_LE(offset, EndOffset());
- DCHECK_EQ(text.length(), TextLength());
-
- offset -= StartOffset();
- if (TextShapeResult()) {
- // TODO(layout-dev): Move caret position out of ShapeResult and into a
- // separate support class that can take a ShapeResult or ShapeResultView.
- // Allows for better code separation and avoids the extra copy below.
- return round_function(
- TextShapeResult()->CreateShapeResult()->CaretPositionForOffset(
- offset, text, adjust_mid_cluster));
- }
-
- // This fragment is a flow control because otherwise ShapeResult exists.
- DCHECK(IsFlowControl());
- DCHECK_EQ(1u, text.length());
- if (!offset || UNLIKELY(IsRtl(Style().Direction())))
- return LayoutUnit();
- return IsHorizontal() ? Size().width : Size().height;
-}
-
-// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
-// "ng_fragment_item.cc"
-LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text,
- unsigned offset) const {
- return InlinePositionForOffset(text, offset, LayoutUnit::FromFloatRound,
- AdjustMidCluster::kToEnd);
-}
-
-LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
- unsigned offset) const {
- return NGFragmentItem(*this).InlinePositionForOffset(Text(), offset);
-}
-
-std::pair<LayoutUnit, LayoutUnit>
-NGPhysicalTextFragment::LineLeftAndRightForOffsets(unsigned start_offset,
- unsigned end_offset) const {
- return NGFragmentItem(*this).LineLeftAndRightForOffsets(Text(), start_offset,
- end_offset);
-}
-
-// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
-// "ng_fragment_item.cc"
-std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets(
- StringView text,
- unsigned start_offset,
- unsigned end_offset) const {
- DCHECK_LE(start_offset, EndOffset());
- DCHECK_GE(start_offset, StartOffset());
- DCHECK_LE(end_offset, EndOffset());
-
- const LayoutUnit start_position =
- InlinePositionForOffset(text, start_offset, LayoutUnit::FromFloatFloor,
- AdjustMidCluster::kToStart);
- const LayoutUnit end_position = InlinePositionForOffset(
- text, end_offset, LayoutUnit::FromFloatCeil, AdjustMidCluster::kToEnd);
-
- // Swap positions if RTL.
- return (UNLIKELY(start_position > end_position))
- ? std::make_pair(end_position, start_position)
- : std::make_pair(start_position, end_position);
-}
-
-PhysicalRect NGPhysicalTextFragment::LocalRect(unsigned start_offset,
- unsigned end_offset) const {
- return NGFragmentItem(*this).LocalRect(Text(), start_offset, end_offset);
-}
-
-// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
-// "ng_fragment_item.cc"
-PhysicalRect NGFragmentItem::LocalRect(StringView text,
- unsigned start_offset,
- unsigned end_offset) const {
- if (start_offset == StartOffset() && end_offset == EndOffset())
- return LocalRect();
- LayoutUnit start_position, end_position;
- std::tie(start_position, end_position) =
- LineLeftAndRightForOffsets(text, start_offset, end_offset);
- const LayoutUnit inline_size = end_position - start_position;
- switch (GetWritingMode()) {
- case WritingMode::kHorizontalTb:
- return {start_position, LayoutUnit(), inline_size, Size().height};
- case WritingMode::kVerticalRl:
- case WritingMode::kVerticalLr:
- case WritingMode::kSidewaysRl:
- return {LayoutUnit(), start_position, Size().width, inline_size};
- case WritingMode::kSidewaysLr:
- return {LayoutUnit(), Size().height - end_position, Size().width,
- inline_size};
- }
- NOTREACHED();
- return {};
-}
-
-PhysicalRect NGPhysicalTextFragment::SelfInkOverflow() const {
- if (!ink_overflow_computed_)
- ComputeSelfInkOverflow();
- if (ink_overflow_)
- return ink_overflow_->ink_overflow;
- return LocalRect();
-}
-
-void NGPhysicalTextFragment::ComputeSelfInkOverflow() const {
- ink_overflow_computed_ = true;
-
- if (UNLIKELY(!shape_result_)) {
- ink_overflow_ = nullptr;
- return;
- }
-
- base::Optional<PhysicalRect> ink_overflow =
- NGInkOverflow::ComputeTextInkOverflow(PaintInfo(), Style(), Size());
- if (!ink_overflow) {
- ink_overflow_.reset();
- return;
- }
- if (ink_overflow_)
- ink_overflow_->ink_overflow = *ink_overflow;
- else
- ink_overflow_ = std::make_unique<NGSingleInkOverflow>(*ink_overflow);
-}
-
-scoped_refptr<const NGPhysicalTextFragment>
-NGPhysicalTextFragment::CloneAsHiddenForPaint() const {
- NGTextFragmentBuilder builder(*this);
- builder.SetIsHiddenForPaint(true);
- return builder.ToTextFragment();
-}
-
-unsigned NGPhysicalTextFragment::TextOffsetForPoint(
- const PhysicalOffset& point) const {
- const ComputedStyle& style = Style();
- const LayoutUnit& point_in_line_direction =
- style.IsHorizontalWritingMode() ? point.left : point.top;
- if (const ShapeResultView* shape_result = TextShapeResult()) {
- // TODO(layout-dev): Move caret logic out of ShapeResult into separate
- // support class for code health and to avoid this copy.
- return shape_result->CreateShapeResult()->CaretOffsetForHitTest(
- point_in_line_direction.ToFloat(), Text(), BreakGlyphs) +
- StartOffset();
- }
-
- // Flow control fragments such as forced line break, tabulation, soft-wrap
- // opportunities, etc. do not have ShapeResult.
- DCHECK(IsFlowControl());
-
- // Zero-inline-size objects such as newline always return the start offset.
- LogicalSize size = Size().ConvertToLogical(style.GetWritingMode());
- if (!size.inline_size)
- return StartOffset();
-
- // Sized objects such as tabulation returns the next offset if the given point
- // is on the right half.
- LayoutUnit inline_offset = IsLtr(ResolvedDirection())
- ? point_in_line_direction
- : size.inline_size - point_in_line_direction;
- DCHECK_EQ(1u, TextLength());
- return inline_offset <= size.inline_size / 2 ? StartOffset() : EndOffset();
-}
-
-UBiDiLevel NGPhysicalTextFragment::BidiLevel() const {
- // TODO(xiaochengh): Make the implementation more efficient with, e.g.,
- // binary search and/or LayoutNGText::InlineItems().
- const auto& items = InlineItemsOfContainingBlock();
- const NGInlineItem* containing_item = std::find_if(
- items.begin(), items.end(), [this](const NGInlineItem& item) {
- return item.StartOffset() <= StartOffset() &&
- item.EndOffset() >= EndOffset();
- });
- DCHECK(containing_item);
- DCHECK_NE(containing_item, items.end());
- return containing_item->BidiLevel();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h
deleted file mode 100644
index 7684f681188..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_type.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class NGTextFragmentBuilder;
-class NGPhysicalTextFragment;
-struct PhysicalRect;
-
-enum class AdjustMidCluster;
-
-class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
- public:
- NGPhysicalTextFragment(NGTextFragmentBuilder*);
-
- NGTextType TextType() const { return static_cast<NGTextType>(sub_type_); }
- // Returns true if the text is generated (from, e.g., list marker,
- // pseudo-element, ...) instead of from a DOM text node.
- bool IsGeneratedText() const;
- // True if this is a forced line break.
- bool IsLineBreak() const {
- return TextType() == NGTextType::kForcedLineBreak;
- }
- // True if this is not for painting; i.e., a forced line break, a tabulation,
- // or a soft-wrap opportunity.
- bool IsFlowControl() const {
- return IsLineBreak() || TextType() == NGTextType::kFlowControl;
- }
- // True if this is an ellpisis generated by `text-overflow: ellipsis`.
- bool IsEllipsis() const {
- return StyleVariant() == NGStyleVariant::kEllipsis;
- }
-
- bool IsSymbolMarker() const {
- return TextType() == NGTextType::kSymbolMarker;
- }
-
- const String& TextContent() const { return text_; }
-
- // ShapeResult may be nullptr if |IsFlowControl()|.
- const ShapeResultView* TextShapeResult() const { return shape_result_.get(); }
-
- // Start/end offset to the text of the block container.
- const NGTextOffset& TextOffset() const { return text_offset_; }
- unsigned StartOffset() const { return text_offset_.start; }
- unsigned EndOffset() const { return text_offset_.end; }
- unsigned TextLength() const { return text_offset_.Length(); }
- StringView Text() const {
- return StringView(text_, text_offset_.start, TextLength());
- }
-
- WritingMode GetWritingMode() const { return Style().GetWritingMode(); }
- bool IsHorizontal() const {
- return IsHorizontalWritingMode(GetWritingMode());
- }
-
- // Compute the inline position from text offset, in logical coordinate
- // relative to this fragment.
- LayoutUnit InlinePositionForOffset(unsigned offset) const;
-
- // The layout box of text in (start, end) range in local coordinate.
- // Start and end offsets must be between StartOffset() and EndOffset().
- PhysicalRect LocalRect(unsigned start_offset, unsigned end_offset) const;
- using NGPhysicalFragment::LocalRect;
-
- // The visual bounding box that includes glpyh bounding box and CSS
- // properties, in local coordinates.
- PhysicalRect SelfInkOverflow() const;
-
- scoped_refptr<const NGPhysicalTextFragment> CloneAsHiddenForPaint() const;
-
- scoped_refptr<const NGPhysicalFragment> CloneWithoutOffset() const;
-
- NGTextFragmentPaintInfo PaintInfo() const {
- return NGTextFragmentPaintInfo{text_, StartOffset(), EndOffset(),
- TextShapeResult()};
- }
-
- // Returns the text offset in the fragment placed closest to the given point.
- unsigned TextOffsetForPoint(const PhysicalOffset&) const;
-
- UBiDiLevel BidiLevel() const;
- TextDirection ResolvedDirection() const {
- return static_cast<TextDirection>(base_or_resolved_direction_);
- }
-
- // Compute line-relative coordinates for given offsets, this is not
- // flow-relative:
- // https://drafts.csswg.org/css-writing-modes-3/#line-directions
- std::pair<LayoutUnit, LayoutUnit> LineLeftAndRightForOffsets(
- unsigned start_offset,
- unsigned end_offset) const;
-
- private:
- LayoutUnit InlinePositionForOffset(unsigned offset,
- LayoutUnit (*round)(float),
- AdjustMidCluster) const;
-
- void ComputeSelfInkOverflow() const;
-
- // The text of NGInlineNode; i.e., of a parent block. The text for this
- // fragment is a substring(start_offset_, end_offset_) of this string.
- const String text_;
-
- // Start and end offset of the parent block text.
- const NGTextOffset text_offset_;
- const scoped_refptr<const ShapeResultView> shape_result_;
-
- // Fragments are immutable but allow certain expensive data, specifically ink
- // overflow, to be cached as long as it is guaranteed to always recompute to
- // the same value.
- mutable std::unique_ptr<NGSingleInkOverflow> ink_overflow_;
-
- friend class NGTextFragmentBuilder;
-};
-
-template <>
-struct DowncastTraits<NGPhysicalTextFragment> {
- static bool AllowFrom(const NGPhysicalFragment& fragment) {
- return fragment.IsText();
- }
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
deleted file mode 100644
index 6850dafe3ea..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-
-#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-
-namespace blink {
-
-class NGPhysicalTextFragmentTest : public NGLayoutTest {
- public:
- NGPhysicalTextFragmentTest() : NGLayoutTest() {}
-
- protected:
- Vector<scoped_refptr<const NGPhysicalTextFragment>>
- CollectTextFragmentsInContainer(const char* container_id) {
- const Element* container = GetElementById(container_id);
- DCHECK(container) << container_id;
- const LayoutObject* layout_object = container->GetLayoutObject();
- DCHECK(layout_object) << container;
- DCHECK(layout_object->IsLayoutBlockFlow()) << container;
- const auto* root_fragment =
- To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0);
- DCHECK(root_fragment) << container;
-
- Vector<scoped_refptr<const NGPhysicalTextFragment>> result;
- for (const auto& child :
- NGInlineFragmentTraversal::DescendantsOf(*root_fragment)) {
- if (auto* text_child_fragment =
- DynamicTo<NGPhysicalTextFragment>(child.fragment.get()))
- result.push_back(text_child_fragment);
- }
- return result;
- }
-
- static std::string GetText(const NGPhysicalTextFragment& fragment) {
- return fragment.Text().ToString().Utf8();
- }
-};
-
-TEST_F(NGPhysicalTextFragmentTest, LocalRect) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- div {
- font: 10px/1 Ahem;
- width: 5em;
- }
- </style>
- <div id=container>01234 67890</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(2u, text_fragments.size());
- EXPECT_EQ(PhysicalRect(20, 0, 20, 10), text_fragments[1]->LocalRect(8, 10));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- div {
- font: 10px/1 Ahem;
- width: 10em;
- direction: rtl;
- unicode-bidi: bidi-override;
- }
- </style>
- <div id=container>0123456789 123456789</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(2u, text_fragments.size());
- // The 2nd line starts at 12, because the div has a bidi-control.
- EXPECT_EQ(12u, text_fragments[1]->StartOffset());
- // TODO(layout-dev): Investigate whether this is correct.
- // EXPECT_EQ(PhysicalRect(50, 0, 20, 10),
- // text_fragments[1]->LocalRect(14, 16));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- div {
- font: 10px/1 Ahem;
- height: 5em;
- writing-mode: vertical-lr;
- }
- </style>
- <div id=container>01234 67890</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(2u, text_fragments.size());
- EXPECT_EQ(PhysicalRect(0, 20, 10, 20), text_fragments[1]->LocalRect(8, 10));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- div {
- font: 10px/1 Ahem;
- height: 5em;
- writing-mode: vertical-rl;
- }
- </style>
- <div id=container>01234 67890</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(2u, text_fragments.size());
- EXPECT_EQ(PhysicalRect(0, 20, 10, 20), text_fragments[1]->LocalRect(8, 10));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML("<div id=div>text</div>");
-
- auto text_fragments = CollectTextFragmentsInContainer("div");
- ASSERT_EQ(1u, text_fragments.size());
-
- const NGPhysicalTextFragment& text = *text_fragments[0];
- EXPECT_FALSE(text.IsGeneratedText());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, FirstLetterIsNotAnonymousText) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML(
- "<style>::first-letter {color:red}</style>"
- "<div id=div>text</div>");
-
- auto text_fragments = CollectTextFragmentsInContainer("div");
- ASSERT_EQ(2u, text_fragments.size());
-
- const NGPhysicalTextFragment& first_letter = *text_fragments[0];
- const NGPhysicalTextFragment& remaining_text = *text_fragments[1];
- EXPECT_FALSE(first_letter.IsGeneratedText());
- EXPECT_FALSE(remaining_text.IsGeneratedText());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, BeforeAndAfterAreAnonymousText) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML(
- "<style>::before{content:'x'} ::after{content:'x'}</style>"
- "<div id=div>text</div>");
-
- auto text_fragments = CollectTextFragmentsInContainer("div");
- ASSERT_EQ(3u, text_fragments.size());
-
- const NGPhysicalTextFragment& before = *text_fragments[0];
- const NGPhysicalTextFragment& text = *text_fragments[1];
- const NGPhysicalTextFragment& after = *text_fragments[2];
- EXPECT_TRUE(before.IsGeneratedText());
- EXPECT_FALSE(text.IsGeneratedText());
- EXPECT_TRUE(after.IsGeneratedText());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, Ellipsis) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- #sample {
- font: 10px/1 Ahem;
- overflow: hidden;
- text-overflow: ellipsis;
- width: 4ch;
- }
- </style>
- <p id="sample">abcdef</p>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("sample");
- ASSERT_EQ(3u, text_fragments.size());
-
- const NGPhysicalTextFragment& hidden = *text_fragments[0];
- const NGPhysicalTextFragment& truncated = *text_fragments[1];
- const NGPhysicalTextFragment& ellipsis = *text_fragments[2];
-
- EXPECT_EQ(NGTextType::kNormal, hidden.TextType());
- EXPECT_FALSE(hidden.IsGeneratedText());
- EXPECT_TRUE(hidden.IsHiddenForPaint());
- EXPECT_EQ(u8"abcdef", GetText(hidden));
-
- EXPECT_EQ(NGTextType::kNormal, truncated.TextType());
- EXPECT_FALSE(truncated.IsGeneratedText());
- EXPECT_FALSE(truncated.IsHiddenForPaint());
- EXPECT_EQ(u8"abc", GetText(truncated));
-
- EXPECT_EQ(NGTextType::kLayoutGenerated, ellipsis.TextType());
- EXPECT_TRUE(ellipsis.IsGeneratedText());
- EXPECT_FALSE(ellipsis.IsHiddenForPaint());
- EXPECT_EQ(u8"\u2026", GetText(ellipsis));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, ListMarkerIsGeneratedText) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML(
- "<ol style='list-style-position:inside'>"
- "<li id=list>text</li>"
- "</ol>");
-
- auto text_fragments = CollectTextFragmentsInContainer("list");
- ASSERT_EQ(2u, text_fragments.size());
-
- const NGPhysicalTextFragment& marker = *text_fragments[0];
- const NGPhysicalTextFragment& text = *text_fragments[1];
- EXPECT_TRUE(marker.IsGeneratedText());
- EXPECT_FALSE(text.IsGeneratedText());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, SoftHyphen) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- #sample {
- font: 10px/1 Ahem;
- width: 3ch;
- }
- </style>
- <p id="sample">abc&shy;def</p>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("sample");
- ASSERT_EQ(3u, text_fragments.size());
-
- const NGPhysicalTextFragment& abc = *text_fragments[0];
- const NGPhysicalTextFragment& shy = *text_fragments[1];
- const NGPhysicalTextFragment& def = *text_fragments[2];
- EXPECT_EQ(NGTextType::kNormal, abc.TextType());
- // Note: ShapeResult::RunInfo.width_ == 0 for U+00AD
- EXPECT_EQ(u8"abc\u00AD", GetText(abc));
- EXPECT_EQ(NGTextType::kLayoutGenerated, shy.TextType());
- // Note: |ComputedStyle::HyphenString()| returns "-" or U+2010 based on
- // glyph availability.
- if (GetText(shy) != "-")
- EXPECT_EQ(u8"\u2010", GetText(shy));
- EXPECT_EQ(NGTextType::kNormal, def.TextType());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, QuotationMarksAreAnonymousText) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML("<div id=div><q>text</q></div>");
-
- auto text_fragments = CollectTextFragmentsInContainer("div");
- ASSERT_EQ(3u, text_fragments.size());
-
- const NGPhysicalTextFragment& open_quote = *text_fragments[0];
- const NGPhysicalTextFragment& text = *text_fragments[1];
- const NGPhysicalTextFragment& closed_quote = *text_fragments[2];
- EXPECT_TRUE(open_quote.IsGeneratedText());
- EXPECT_FALSE(text.IsGeneratedText());
- EXPECT_TRUE(closed_quote.IsGeneratedText());
-}
-
-TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulation) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- #container {
- white-space: pre;
- font-family: Ahem;
- font-size: 10px;
- tab-size: 8;
- }
- </style>
- <div id="container">&#09;</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(1u, text_fragments.size());
- const NGPhysicalTextFragment& text = *text_fragments[0];
- EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(), LayoutUnit()}));
- EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(39), LayoutUnit()}));
- EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(41), LayoutUnit()}));
- EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(80), LayoutUnit()}));
-}
-
-TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulationRtl) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <style>
- #container {
- white-space: pre;
- font-family: Ahem;
- font-size: 10px;
- tab-size: 8;
- }
- </style>
- <div id="container" dir="rtl">&#09;</div>
- )HTML");
- auto text_fragments = CollectTextFragmentsInContainer("container");
- ASSERT_EQ(1u, text_fragments.size());
- const NGPhysicalTextFragment& text = *text_fragments[0];
- EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(), LayoutUnit()}));
- EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(39), LayoutUnit()}));
- EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(41), LayoutUnit()}));
- EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(80), LayoutUnit()}));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
index 093c5a644a5..cdd44f295a6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
@@ -249,12 +249,10 @@ NGAnnotationMetrics ComputeAnnotationOverflow(
continue;
LayoutUnit item_over = item.BlockOffset();
LayoutUnit item_under = item.BlockEndOffset();
- if (item.text_fragment || item.shape_result) {
+ if (item.shape_result) {
if (const auto* style = item.Style()) {
std::tie(item_over, item_under) = AdjustTextOverUnderOffsetsForEmHeight(
- item_over, item_under, *style,
- item.text_fragment ? *item.text_fragment->TextShapeResult()
- : *item.shape_result);
+ item_over, item_under, *style, *item.shape_result);
}
} else {
const auto* fragment = item.PhysicalFragment();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc
deleted file mode 100644
index 8f970762857..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
-
-#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
-
-namespace blink {
-
-NGTextFragmentBuilder::NGTextFragmentBuilder(
- const NGPhysicalTextFragment& fragment)
- : NGFragmentBuilder(fragment),
- text_(fragment.text_),
- text_offset_(fragment.TextOffset()),
- shape_result_(fragment.TextShapeResult()),
- text_type_(fragment.TextType()) {}
-
-void NGTextFragmentBuilder::SetItem(
- const String& text_content,
- const NGInlineItem& item,
- scoped_refptr<const ShapeResultView> shape_result,
- const NGTextOffset& text_offset,
- const LogicalSize& size) {
- DCHECK_NE(item.TextType(), NGTextType::kLayoutGenerated)
- << "Please use SetText() instead.";
- DCHECK(item.Style());
-
- text_type_ = item.TextType();
- text_ = text_content;
- text_offset_ = text_offset;
- resolved_direction_ = item.Direction();
- SetStyle(item.Style(), item.StyleVariant());
- size_ = size;
- shape_result_ = std::move(shape_result);
- layout_object_ = item.GetLayoutObject();
-}
-
-void NGTextFragmentBuilder::SetText(
- LayoutObject* layout_object,
- const String& text,
- scoped_refptr<const ComputedStyle> style,
- NGStyleVariant style_variant,
- scoped_refptr<const ShapeResultView> shape_result,
- const LogicalSize& size) {
- DCHECK(layout_object);
- DCHECK(style);
- DCHECK(shape_result);
-
- text_type_ = NGTextType::kLayoutGenerated;
- text_ = text;
- text_offset_ = {shape_result->StartIndex(), shape_result->EndIndex()};
- resolved_direction_ = shape_result->Direction();
- SetStyle(style, style_variant);
- size_ = size;
- shape_result_ = std::move(shape_result);
- layout_object_ = layout_object;
-}
-
-scoped_refptr<const NGPhysicalTextFragment>
-NGTextFragmentBuilder::ToTextFragment() {
- scoped_refptr<const NGPhysicalTextFragment> fragment =
- base::AdoptRef(new NGPhysicalTextFragment(this));
- return fragment;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h
deleted file mode 100644
index 7e90f264e2f..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_
-
-#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class LayoutObject;
-class ShapeResultView;
-
-class CORE_EXPORT NGTextFragmentBuilder final : public NGFragmentBuilder {
- STACK_ALLOCATED();
-
- public:
- explicit NGTextFragmentBuilder(WritingMode writing_mode)
- : NGFragmentBuilder({writing_mode, TextDirection::kLtr}) {}
-
- NGTextFragmentBuilder(const NGPhysicalTextFragment& fragment);
-
- TextDirection ResolvedDirection() const { return resolved_direction_; }
-
- // NOTE: Takes ownership of the shape result within the item result.
- void SetItem(const String& text_content,
- const NGInlineItem& inline_item,
- scoped_refptr<const ShapeResultView> shape_result,
- const NGTextOffset& text_offset,
- const LogicalSize& size);
-
- // Set text for generated text, e.g. hyphen and ellipsis.
- void SetText(LayoutObject*,
- const String& text,
- scoped_refptr<const ComputedStyle>,
- NGStyleVariant style_variant,
- scoped_refptr<const ShapeResultView>,
- const LogicalSize& size);
-
- // Creates the fragment. Can only be called once.
- scoped_refptr<const NGPhysicalTextFragment> ToTextFragment();
-
- private:
- String text_;
- NGTextOffset text_offset_;
- scoped_refptr<const ShapeResultView> shape_result_;
-
- NGTextType text_type_ = NGTextType::kNormal;
-
- // Set from |NGInlineItem| by |SetItem()|.
- TextDirection resolved_direction_ = TextDirection::kLtr;
-
- friend class NGPhysicalTextFragment;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index 00825c38fca..7c942eb88ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
namespace blink {
@@ -108,13 +107,6 @@ void LayoutNGBlockFlowMixin<Base>::AddOutlineRects(
Vector<PhysicalRect>& rects,
const PhysicalOffset& additional_offset,
NGOutlineType include_block_overflows) const {
- if (PaintFragment()) {
- To<NGPhysicalBoxFragment>(PaintFragment()->PhysicalFragment())
- .AddSelfOutlineRects(additional_offset, include_block_overflows,
- &rects);
- return;
- }
-
// TODO(crbug.com/1145048): Currently |NGBoxPhysicalFragment| does not support
// NG block fragmentation. Fallback to the legacy code path.
if (Base::PhysicalFragmentCount() == 1) {
@@ -191,63 +183,6 @@ LayoutUnit LayoutNGBlockFlowMixin<Base>::InlineBlockBaseline(
}
template <typename Base>
-void LayoutNGBlockFlowMixin<Base>::SetPaintFragment(
- const NGBlockBreakToken* break_token,
- scoped_refptr<const NGPhysicalFragment> fragment) {
- DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
-
- if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()))
- return;
-
- scoped_refptr<NGPaintFragment>* current =
- NGPaintFragment::Find(&paint_fragment_, break_token);
- DCHECK(current);
- if (fragment) {
- *current = NGPaintFragment::Create(std::move(fragment), break_token,
- std::move(*current));
- // |NGPaintFragment::Create()| calls |SlowSetPaintingLayerNeedsRepaint()|.
- } else if (*current) {
- DCHECK_EQ(this, (*current)->GetLayoutObject());
- // TODO(kojii): Pass break_token for LayoutObject that spans across block
- // fragmentation boundaries.
- (*current)->ClearAssociationWithLayoutObject();
- *current = nullptr;
- ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
- }
-}
-
-template <typename Base>
-void LayoutNGBlockFlowMixin<Base>::Paint(const PaintInfo& paint_info) const {
- // Avoid painting dirty objects because descendants maybe already destroyed.
- if (UNLIKELY(Base::NeedsLayout() &&
- !Base::ChildLayoutBlockedByDisplayLock())) {
- NOTREACHED();
- return;
- }
-
- if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- if (fragment->HasItems()) {
- NGBoxFragmentPainter(*fragment).Paint(paint_info);
- return;
- }
- }
- }
-
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- NGBoxFragmentPainter(*paint_fragment).Paint(paint_info);
- return;
- }
-
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- NGBoxFragmentPainter(*fragment).Paint(paint_info);
- return;
- }
-
- Base::Paint(paint_info);
-}
-
-template <typename Base>
bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
HitTestResult& result,
const HitTestLocation& hit_test_location,
@@ -264,28 +199,16 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
if (!Base::MayIntersect(result, hit_test_location, accumulated_offset))
return false;
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- if (Base::IsInSelfHitTestingPhase(action) && Base::IsScrollContainer() &&
- Base::HitTestOverflowControl(result, hit_test_location,
- accumulated_offset))
- return true;
-
- return NGBoxFragmentPainter(*paint_fragment)
- .NodeAtPoint(result, hit_test_location, accumulated_offset, action);
- }
-
- if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
- if (Base::PhysicalFragmentCount()) {
- const NGPhysicalBoxFragment* fragment = Base::GetPhysicalFragment(0);
- DCHECK(fragment);
- if (fragment->HasItems() ||
- // Check descendants of this fragment because floats may be in the
- // |NGFragmentItems| of the descendants.
- (action == kHitTestFloat &&
- fragment->HasFloatingDescendantsForPaint())) {
- return NGBoxFragmentPainter(*fragment).NodeAtPoint(
- result, hit_test_location, accumulated_offset, action);
- }
+ if (Base::PhysicalFragmentCount()) {
+ const NGPhysicalBoxFragment* fragment = Base::GetPhysicalFragment(0);
+ DCHECK(fragment);
+ if (fragment->HasItems() ||
+ // Check descendants of this fragment because floats may be in the
+ // |NGFragmentItems| of the descendants.
+ (action == kHitTestFloat &&
+ fragment->HasFloatingDescendantsForPaint())) {
+ return NGBoxFragmentPainter(*fragment).NodeAtPoint(
+ result, hit_test_location, accumulated_offset, action);
}
}
@@ -296,6 +219,9 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
template <typename Base>
PositionWithAffinity LayoutNGBlockFlowMixin<Base>::PositionForPoint(
const PhysicalOffset& point) const {
+ DCHECK_GE(Base::GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+
if (Base::IsAtomicInlineLevel()) {
const PositionWithAffinity atomic_inline_position =
Base::PositionForPointIfOutsideAtomicInlineLevel(point);
@@ -306,17 +232,8 @@ PositionWithAffinity LayoutNGBlockFlowMixin<Base>::PositionForPoint(
if (!Base::ChildrenInline())
return LayoutBlock::PositionForPoint(point);
- if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- // The given offset is relative to this |LayoutBlockFlow|. Convert to the
- // contents offset.
- PhysicalOffset point_in_contents = point;
- Base::OffsetForContents(point_in_contents);
- if (const PositionWithAffinity position =
- paint_fragment->PositionForPoint(point_in_contents))
- return AdjustForEditingBoundary(position);
- } else if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- return fragment->PositionForPoint(point);
- }
+ if (Base::PhysicalFragmentCount())
+ return Base::PositionForPointInFragments(point);
return Base::CreatePositionWithAffinity(0);
}
@@ -330,8 +247,7 @@ void LayoutNGBlockFlowMixin<Base>::DirtyLinesFromChangedChild(
// We need to dirty line box fragments only if the child is once laid out in
// LayoutNG inline formatting context. New objects are handled in
// NGInlineNode::MarkLineBoxesDirty().
- if (child->IsInLayoutNGInlineFormattingContext() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ if (child->IsInLayoutNGInlineFormattingContext())
NGFragmentItems::DirtyLinesFromChangedChild(*child, *this);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
index 967ef9dd983..f9eb20efccb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
@@ -21,8 +21,6 @@
namespace blink {
enum class NGBaselineAlgorithmType;
-class NGPaintFragment;
-class NGPhysicalFragment;
struct NGInlineNodeData;
// This mixin holds code shared between LayoutNG subclasses of LayoutBlockFlow.
@@ -41,8 +39,6 @@ class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
LayoutUnit FirstLineBoxBaseline() const final;
LayoutUnit InlineBlockBaseline(LineDirectionMode) const final;
- void Paint(const PaintInfo&) const override;
-
bool NodeAtPoint(HitTestResult&,
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
@@ -50,18 +46,6 @@ class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
- const NGPaintFragment* PaintFragment() const final {
- // TODO(layout-dev) crbug.com/963103
- // Safer option here is to return nullptr only if
- // Lifecycle > DocumentLifecycle::kAfterPerformLayout, but this breaks
- // some layout tests.
- if (Base::NeedsLayout())
- return nullptr;
- return paint_fragment_.get();
- }
- void SetPaintFragment(const NGBlockBreakToken*,
- scoped_refptr<const NGPhysicalFragment>) final;
-
using LayoutNGMixin<Base>::CurrentFragment;
protected:
@@ -81,7 +65,6 @@ class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
void UpdateNGBlockLayout();
std::unique_ptr<NGInlineNodeData> ng_inline_node_data_;
- scoped_refptr<NGPaintFragment> paint_fragment_;
friend class NGBaseLayoutAlgorithmTest;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 9e60515c149..ec323be34f8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -36,6 +36,14 @@ LayoutNGMixin<Base>::~LayoutNGMixin() = default;
template <typename Base>
void LayoutNGMixin<Base>::Paint(const PaintInfo& paint_info) const {
+ // When |this| is NG block fragmented, the painter should traverse fragments
+ // instead of |LayoutObject|, because this function cannot handle block
+ // fragmented objects. We can come here only when |this| cannot traverse
+ // fragments, or the parent is legacy.
+ DCHECK(!Base::CanTraversePhysicalFragments() ||
+ !Base::Parent()->CanTraversePhysicalFragments());
+ DCHECK_LE(Base::PhysicalFragmentCount(), 1u);
+
// Avoid painting dirty objects because descendants maybe already destroyed.
if (UNLIKELY(Base::NeedsLayout() &&
!Base::ChildLayoutBlockedByDisplayLock())) {
@@ -43,8 +51,15 @@ void LayoutNGMixin<Base>::Paint(const PaintInfo& paint_info) const {
return;
}
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment())
+ if (Base::PhysicalFragmentCount()) {
+ const NGPhysicalBoxFragment* fragment = Base::GetPhysicalFragment(0);
+ DCHECK(fragment);
NGBoxFragmentPainter(*fragment).Paint(paint_info);
+ return;
+ }
+
+ NOTREACHED();
+ Base::Paint(paint_info);
}
template <typename Base>
@@ -52,8 +67,14 @@ bool LayoutNGMixin<Base>::NodeAtPoint(HitTestResult& result,
const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- DCHECK_EQ(Base::PhysicalFragmentCount(), 1u);
+ // See |Paint()|.
+ DCHECK(!Base::CanTraversePhysicalFragments() ||
+ !Base::Parent()->CanTraversePhysicalFragments());
+ DCHECK_LE(Base::PhysicalFragmentCount(), 1u);
+
+ if (Base::PhysicalFragmentCount()) {
+ const NGPhysicalBoxFragment* fragment = Base::GetPhysicalFragment(0);
+ DCHECK(fragment);
return NGBoxFragmentPainter(*fragment).NodeAtPoint(
result, hit_test_location, accumulated_offset, action);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
index 2cf1279bff9..213d9ca11b7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
@@ -20,7 +20,9 @@ bool LayoutNGInsideListMarker::IsOfType(LayoutObjectType type) const {
PositionWithAffinity LayoutNGInsideListMarker::PositionForPoint(
const PhysicalOffset&) const {
NOT_DESTROYED();
- return CreatePositionWithAffinity(0);
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ return PositionBeforeThis();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
index 04f8e789603..3969e5137af 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/list_marker.h"
namespace blink {
@@ -14,6 +15,14 @@ LayoutNGListItem::LayoutNGListItem(Element* element)
SetConsumesSubtreeChangeNotification();
RegisterSubtreeChangeListenerOnDescendants(true);
+ View()->AddLayoutListItem();
+}
+
+void LayoutNGListItem::WillBeDestroyed() {
+ NOT_DESTROYED();
+ if (View())
+ View()->RemoveLayoutListItem();
+ LayoutNGBlockFlow::WillBeDestroyed();
}
bool LayoutNGListItem::IsOfType(LayoutObjectType type) const {
@@ -43,11 +52,34 @@ void LayoutNGListItem::StyleDidChange(StyleDifference diff,
list_marker->UpdateMarkerContentIfNeeded(*marker);
- if (old_style && (old_style->ListStyleType() != StyleRef().ListStyleType() ||
- (StyleRef().ListStyleType() == EListStyleType::kString &&
- old_style->ListStyleStringValue() !=
- StyleRef().ListStyleStringValue())))
- list_marker->ListStyleTypeChanged(*marker);
+ if (old_style) {
+ const ListStyleTypeData* old_list_style_type =
+ old_style->GetListStyleType();
+ const ListStyleTypeData* new_list_style_type =
+ StyleRef().GetListStyleType();
+ if (old_list_style_type != new_list_style_type &&
+ (!old_list_style_type || !new_list_style_type ||
+ *old_list_style_type != *new_list_style_type))
+ list_marker->ListStyleTypeChanged(*marker);
+ }
+}
+
+void LayoutNGListItem::UpdateCounterStyle() {
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled())
+ return;
+
+ if (!StyleRef().GetListStyleType() ||
+ StyleRef().GetListStyleType()->IsCounterStyleReferenceValid(
+ GetDocument())) {
+ return;
+ }
+
+ LayoutObject* marker = Marker();
+ ListMarker* list_marker = ListMarker::Get(marker);
+ if (!list_marker)
+ return;
+
+ list_marker->CounterStyleChanged(*marker);
}
void LayoutNGListItem::OrdinalValueChanged() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
index 02ddf45ea7b..ebef26d1a2f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
@@ -26,6 +26,7 @@ class CORE_EXPORT LayoutNGListItem final : public LayoutNGBlockFlow {
}
void UpdateMarkerTextIfNeeded();
+ void UpdateCounterStyle();
void OrdinalValueChanged();
void WillCollectInlines() override;
@@ -41,6 +42,7 @@ class CORE_EXPORT LayoutNGListItem final : public LayoutNGBlockFlow {
void WillBeRemovedFromTree() override;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void SubtreeDidChange() final;
+ void WillBeDestroyed() override;
ListItemOrdinal ordinal_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc
index 4507904c341..15a3c0a3018 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc
@@ -7,6 +7,8 @@
#include "third_party/blink/renderer/core/layout/layout_text.h"
namespace blink {
+class HTMLUListElement;
+class HTMLOListElement;
LayoutNGOutsideListMarker::LayoutNGOutsideListMarker(Element* element)
: LayoutNGBlockFlowMixin<LayoutBlockFlow>(element) {}
@@ -35,7 +37,9 @@ bool LayoutNGOutsideListMarker::NeedsOccupyWholeLine() const {
PositionWithAffinity LayoutNGOutsideListMarker::PositionForPoint(
const PhysicalOffset&) const {
- return CreatePositionWithAffinity(0);
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ return PositionBeforeThis();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
index 68b2cca9c37..345fb6f1c9f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
@@ -32,8 +32,8 @@ LayoutUnit NGUnpositionedListMarker::InlineOffset(
LayoutObject* list_item =
marker_layout_object_->Marker().ListItem(*marker_layout_object_);
auto margins = ListMarker::InlineMarginsForOutside(
- marker_layout_object_->StyleRef(), list_item->StyleRef(),
- marker_inline_size);
+ list_item->GetDocument(), marker_layout_object_->StyleRef(),
+ list_item->StyleRef(), marker_inline_size);
return margins.first;
}
@@ -65,7 +65,7 @@ base::Optional<LayoutUnit> NGUnpositionedListMarker::ContentAlignmentBaseline(
// If this child is an empty line-box, the list marker should be aligned
// with the next non-empty line box produced. (This can occur with floats
// producing empty line-boxes).
- if (line_box.IsEmptyLineBox() && !line_box.BreakToken()->IsFinished())
+ if (line_box.IsEmptyLineBox() && line_box.BreakToken())
return base::nullopt;
return line_box.Metrics().ascent;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc
index fb8c3661b41..27a17a9503b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc
@@ -258,7 +258,8 @@ scoped_refptr<const NGLayoutResult> NGMathFractionLayoutAlgorithm::Layout() {
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), total_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(total_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -292,7 +293,7 @@ MinMaxSizesResult NGMathFractionLayoutAlgorithm::ComputeMinMaxSizes(
}
sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
index 6585de1b7a9..46c2de4942d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
@@ -33,11 +33,8 @@ NGConstraintSpace CreateConstraintSpaceForMathChild(
space_builder.SetPercentageResolutionSize(child_available_size);
space_builder.SetReplacedPercentageResolutionSize(child_available_size);
- space_builder.SetIsShrinkToFit(child_style.LogicalWidth().IsAuto());
-
// TODO(crbug.com/1124301): add target stretch sizes.
// TODO(crbug.com/1125137): add ink metrics.
- space_builder.SetNeedsBaseline(true);
return space_builder.ToConstraintSpace();
}
@@ -82,13 +79,15 @@ inline bool IsValidMultiscript(const NGBlockNode& node) {
if (!child || IsPrescriptDelimiter(child))
return false;
bool number_of_scripts_is_even = true;
+ bool prescript_delimiter_found = false;
while (child) {
child = To<NGBlockNode>(NextSiblingInFlow(child));
if (!child)
continue;
if (IsPrescriptDelimiter(child)) {
- if (!number_of_scripts_is_even)
+ if (!number_of_scripts_is_even || prescript_delimiter_found)
return false;
+ prescript_delimiter_found = true;
continue;
}
number_of_scripts_is_even = !number_of_scripts_is_even;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc
index e757ce0e85e..9d41f9c6b37 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc
@@ -81,7 +81,8 @@ scoped_refptr<const NGLayoutResult> NGMathOperatorLayoutAlgorithm::Layout() {
LayoutUnit intrinsic_block_size = ascent + descent;
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetBaseline(ascent);
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -101,9 +102,9 @@ MinMaxSizesResult NGMathOperatorLayoutAlgorithm::ComputeMinMaxSizes(
float operator_target_size = DisplayOperatorMinHeight(Style());
shaper.Shape(&Style().GetFont(), operator_target_size, &metrics);
sizes.Encompass(LayoutUnit(metrics.advance));
- sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, /* depends_on_percentage_block_size */ false};
+ sizes += BorderScrollbarPadding().InlineSum();
+ return MinMaxSizesResult(sizes, /* depends_on_percentage_block_size */ false);
}
UChar32 NGMathOperatorLayoutAlgorithm::GetBaseCodePoint() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_padded_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_padded_layout_algorithm.cc
index 5a2a0221ae0..a695c148849 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_padded_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_padded_layout_algorithm.cc
@@ -120,9 +120,6 @@ MinMaxSizesResult NGMathPaddedLayoutAlgorithm::ComputeMinMaxSizes(
Node(), BorderScrollbarPadding()))
return *result;
- MinMaxSizes sizes;
- bool depends_on_percentage_block_size = false;
- sizes += BorderScrollbarPadding().InlineSum();
NGBlockNode content = nullptr;
GatherChildren(&content);
@@ -131,11 +128,14 @@ MinMaxSizesResult NGMathPaddedLayoutAlgorithm::ComputeMinMaxSizes(
ComputeMinAndMaxContentContribution(Style(), content, input);
NGBoxStrut content_margins = ComputeMinMaxMargins(Style(), content);
content_result.sizes += content_margins.InlineSum();
- depends_on_percentage_block_size |=
+
+ bool depends_on_percentage_block_size =
content_result.depends_on_percentage_block_size;
+ MinMaxSizes sizes;
sizes += content_result.sizes;
- return {sizes, depends_on_percentage_block_size};
+ sizes += BorderScrollbarPadding().InlineSum();
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_radical_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_radical_layout_algorithm.cc
index 8872d76f284..76080b123d5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_radical_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_radical_layout_algorithm.cc
@@ -183,7 +183,8 @@ scoped_refptr<const NGLayoutResult> NGMathRadicalLayoutAlgorithm::Layout() {
auto total_block_size = ascent + descent + BorderScrollbarPadding().block_end;
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), total_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(total_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -233,9 +234,9 @@ MinMaxSizesResult NGMathRadicalLayoutAlgorithm::ComputeMinMaxSizes(
base_result.depends_on_percentage_block_size;
sizes += base_result.sizes;
}
- sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ sizes += BorderScrollbarPadding().InlineSum();
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc
index 7b2427de6fe..cd187391497 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc
@@ -145,7 +145,7 @@ scoped_refptr<const NGLayoutResult> NGMathRowLayoutAlgorithm::Layout() {
auto block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(),
max_row_size.block_size + BorderScrollbarPadding().BlockSum(),
- border_box_size.inline_size);
+ border_box_size.inline_size, Node().ShouldBeConsideredAsReplaced());
container_builder_.SetFragmentsTotalBlockSize(block_size);
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
@@ -188,8 +188,7 @@ MinMaxSizesResult NGMathRowLayoutAlgorithm::ComputeMinMaxSizes(
DCHECK_LE(sizes.min_size, sizes.max_size);
sizes += BorderScrollbarPadding().InlineSum();
-
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
index 56a9d5efaf1..8f7858616b5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
@@ -148,7 +148,7 @@ void NGMathScriptsLayoutAlgorithm::GatherChildren(
// The structure of mmultiscripts is specified here:
// https://mathml-refresh.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts
if (IsPrescriptDelimiter(block_child)) {
- if (!number_of_scripts_is_even || *first_prescript_index > 0) {
+ if (!number_of_scripts_is_even || *prescripts) {
NOTREACHED();
return;
}
@@ -397,7 +397,8 @@ scoped_refptr<const NGLayoutResult> NGMathScriptsLayoutAlgorithm::Layout() {
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -423,9 +424,9 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
MinMaxSizes sizes;
bool depends_on_percentage_block_size = false;
- ChildAndMetrics base_metrics = LayoutAndGetMetrics(base);
- LayoutUnit base_italic_correction = std::min(
- base_metrics.inline_size, base_metrics.result->MathItalicCorrection());
+ // TODO(layout-dev): Determine the italic-correction without calling layout
+ // within ComputeMinMaxSizes, (or setup in an interoperable constraint-space).
+ LayoutUnit base_italic_correction;
MinMaxSizesResult base_result =
ComputeMinAndMaxContentContribution(Style(), base, child_input);
base_result.sizes += ComputeMinMaxMargins(Style(), base).InlineSum();
@@ -489,9 +490,9 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
break;
}
}
- sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ sizes += BorderScrollbarPadding().InlineSum();
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc
index 7626e29c6a1..5f526b33682 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc
@@ -22,7 +22,8 @@ scoped_refptr<const NGLayoutResult> NGMathSpaceLayoutAlgorithm::Layout() {
LayoutUnit intrinsic_block_size = BorderScrollbarPadding().BlockSum();
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -41,8 +42,7 @@ MinMaxSizesResult NGMathSpaceLayoutAlgorithm::ComputeMinMaxSizes(
MinMaxSizes sizes;
sizes += BorderScrollbarPadding().InlineSum();
-
- return {sizes, /* depends_on_percentage_block_size */ false};
+ return MinMaxSizesResult(sizes, /* depends_on_percentage_block_size */ false);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_under_over_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_under_over_layout_algorithm.cc
index 7e78c350eb9..5e94a811c18 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_under_over_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_under_over_layout_algorithm.cc
@@ -313,9 +313,9 @@ scoped_refptr<const NGLayoutResult> NGMathUnderOverLayoutAlgorithm::Layout() {
block_offset += BorderScrollbarPadding().block_end;
- LayoutUnit block_size =
- ComputeBlockSizeForFragment(ConstraintSpace(), Style(), BorderPadding(),
- block_offset, border_box_size.inline_size);
+ LayoutUnit block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), BorderPadding(), block_offset,
+ border_box_size.inline_size, Node().ShouldBeConsideredAsReplaced());
container_builder_.SetIntrinsicBlockSize(block_offset);
container_builder_.SetFragmentsTotalBlockSize(block_size);
@@ -352,7 +352,7 @@ MinMaxSizesResult NGMathUnderOverLayoutAlgorithm::ComputeMinMaxSizes(
}
sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
index 78daafa72d3..0af4cce59cc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
@@ -387,19 +387,18 @@ void ComputeOutOfFlowInlineDimensions(
min_inline_length = Length::MinIntrinsic();
min_size_minmax = minmax_intrinsic_sizes_for_ar;
}
- LayoutUnit min_inline_size =
- ResolveMinInlineLength(space, style, border_padding, min_size_minmax,
- min_inline_length, LengthResolvePhase::kLayout);
- LayoutUnit max_inline_size = ResolveMaxInlineLength(
- space, style, border_padding, minmax_content_sizes,
- style.LogicalMaxWidth(), LengthResolvePhase::kLayout);
+ LayoutUnit min_inline_size = ResolveMinInlineLength(
+ space, style, border_padding, min_size_minmax, min_inline_length);
+ LayoutUnit max_inline_size =
+ ResolveMaxInlineLength(space, style, border_padding, minmax_content_sizes,
+ style.LogicalMaxWidth());
// This implements the transferred min/max sizes per
// https://drafts.csswg.org/css-sizing-4/#aspect-ratio
if (!style.AspectRatio().IsAuto() &&
dimensions->size.block_size == kIndefiniteSize) {
- MinMaxSizes sizes = ComputeMinMaxInlineSizesFromAspectRatio(
- space, style, border_padding, LengthResolvePhase::kLayout);
+ MinMaxSizes sizes =
+ ComputeMinMaxInlineSizesFromAspectRatio(space, style, border_padding);
min_inline_size = std::max(sizes.min_size, min_inline_size);
max_inline_size = std::min(sizes.max_size, max_inline_size);
}
@@ -465,11 +464,9 @@ void ComputeOutOfFlowBlockDimensions(
child_block_size.value_or(kIndefiniteSize);
LayoutUnit min_block_size = ResolveMinBlockLength(
- space, style, border_padding, style.LogicalMinHeight(),
- LengthResolvePhase::kLayout);
+ space, style, border_padding, style.LogicalMinHeight());
LayoutUnit max_block_size = ResolveMaxBlockLength(
- space, style, border_padding, style.LogicalMaxHeight(),
- LengthResolvePhase::kLayout);
+ space, style, border_padding, style.LogicalMaxHeight());
// Tables are never allowed to go below their "auto" block-size.
const bool is_table = node.IsTable();
@@ -478,9 +475,9 @@ void ComputeOutOfFlowBlockDimensions(
base::Optional<LayoutUnit> block_size;
if (!style.LogicalHeight().IsAuto()) {
- block_size = ResolveMainBlockLength(
- space, style, border_padding, style.LogicalHeight(),
- child_block_size_or_indefinite, LengthResolvePhase::kLayout);
+ block_size = ResolveMainBlockLength(space, style, border_padding,
+ style.LogicalHeight(),
+ child_block_size_or_indefinite);
} else if (replaced_size.has_value()) {
block_size = replaced_size->block_size;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
index 8933024366f..b6a1bd173f1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
@@ -113,7 +113,7 @@ const NGPhysicalBoxFragment* FragmentChildIterator::NextChild(
NGConstraintSpace ConstructBlockLayoutTestConstraintSpace(
WritingDirectionMode writing_direction,
LogicalSize size,
- bool shrink_to_fit,
+ bool stretch_inline_size_if_auto,
bool is_new_formatting_context,
LayoutUnit fragmentainer_space_available) {
NGFragmentationType block_fragmentation =
@@ -126,7 +126,7 @@ NGConstraintSpace ConstructBlockLayoutTestConstraintSpace(
is_new_formatting_context);
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
- builder.SetIsShrinkToFit(shrink_to_fit);
+ builder.SetStretchInlineSizeIfAuto(stretch_inline_size_if_auto);
builder.SetFragmentainerBlockSize(fragmentainer_space_available);
builder.SetFragmentationType(block_fragmentation);
return builder.ToConstraintSpace();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
index 4e3f0a65674..6421b750759 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
@@ -76,7 +76,7 @@ class FragmentChildIterator {
NGConstraintSpace ConstructBlockLayoutTestConstraintSpace(
WritingDirectionMode writing_direction,
LogicalSize size,
- bool shrink_to_fit = false,
+ bool stretch_inline_size_if_auto = true,
bool is_new_formatting_context = false,
LayoutUnit fragmentainer_space_available = kIndefiniteSize);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
index bc055b11e6a..05939263886 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
@@ -36,7 +36,7 @@ scoped_refptr<NGBlockBreakToken> NGBlockBreakToken::Create(
NGBlockBreakToken::NGBlockBreakToken(PassKey key,
const NGBoxFragmentBuilder& builder)
- : NGBreakToken(kBlockBreakToken, kUnfinished, builder.node_),
+ : NGBreakToken(kBlockBreakToken, builder.node_),
consumed_block_size_(builder.consumed_block_size_),
sequence_number_(builder.sequence_number_),
num_children_(builder.child_break_tokens_.size()) {
@@ -51,7 +51,7 @@ NGBlockBreakToken::NGBlockBreakToken(PassKey key,
}
NGBlockBreakToken::NGBlockBreakToken(PassKey key, NGLayoutInputNode node)
- : NGBreakToken(kBlockBreakToken, kUnfinished, node), num_children_(0) {}
+ : NGBreakToken(kBlockBreakToken, node), num_children_(0) {}
const NGInlineBreakToken* NGBlockBreakToken::InlineBreakTokenFor(
const NGLayoutInputNode& node) const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
index 3c2ad95bca9..a5c0f9628d8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
@@ -124,7 +124,7 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
String ToString() const override;
#endif
- using PassKey = util::PassKey<NGBlockBreakToken>;
+ using PassKey = base::PassKey<NGBlockBreakToken>;
// Must only be called from Create(), because it assumes that enough space
// has been allocated in the flexible array to store the children.
@@ -132,6 +132,33 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
explicit NGBlockBreakToken(PassKey, NGLayoutInputNode node);
+ // This exposes a mutable part of the break token for |NGOutOfFlowLayoutPart|.
+ class MutableForOutOfFlow final {
+ STACK_ALLOCATED();
+
+ protected:
+ friend class NGOutOfFlowLayoutPart;
+ // Replace the child break token at the provided |index|.
+ void ReplaceChildBreakToken(const NGBreakToken* child_break_token,
+ wtf_size_t index) {
+ DCHECK_LT(index, break_token_->num_children_);
+ break_token_->child_break_tokens_[index]->Release();
+ break_token_->child_break_tokens_[index] = child_break_token;
+ break_token_->child_break_tokens_[index]->AddRef();
+ }
+
+ private:
+ friend class NGBlockBreakToken;
+ explicit MutableForOutOfFlow(const NGBlockBreakToken* break_token)
+ : break_token_(const_cast<NGBlockBreakToken*>(break_token)) {}
+
+ NGBlockBreakToken* break_token_;
+ };
+
+ MutableForOutOfFlow GetMutableForOutOfFlow() const {
+ return MutableForOutOfFlow(this);
+ }
+
private:
LayoutUnit consumed_block_size_;
unsigned sequence_number_ = 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.cc
index 45639605bb3..2b597d2b5e2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.cc
@@ -18,12 +18,12 @@ NGBlockChildIterator::NGBlockChildIterator(NGLayoutInputNode first_child,
NGBlockChildIterator::Entry NGBlockChildIterator::NextChild(
const NGInlineBreakToken* previous_inline_break_token) {
const NGBreakToken* child_break_token = nullptr;
- if (previous_inline_break_token &&
- !previous_inline_break_token->IsFinished()) {
+ if (previous_inline_break_token) {
return Entry(previous_inline_break_token->InputNode(),
previous_inline_break_token);
}
+ bool next_is_from_break_token = false;
if (break_token_) {
// If we're resuming layout after a fragmentainer break, we'll first resume
// the children that fragmented earlier (represented by one break token
@@ -32,29 +32,33 @@ NGBlockChildIterator::Entry NGBlockChildIterator::NextChild(
while (child_token_idx_ < child_break_tokens.size()) {
child_break_token = child_break_tokens[child_token_idx_++];
- // While it never happens to blocks, line boxes may produce break tokens
- // even if we're finished. And those we just ignore.
- if (!child_break_token->IsFinished())
- break;
+ break;
}
- // If there are no break tokens left to resume, the iterator machinery (see
- // further below) will just continue at the next sibling. The last break
- // token would be the last node that got fragmented. However, there may be
- // parallel flows caused by visible overflow, established by descendants of
- // our children, and these may go on, fragmentainer after fragmentainer,
- // even if we're done with our direct children. When this happens, we need
- // to prevent the machinery from continuing iterating, if we're already done
- // with those siblings.
- if (!child_break_token && break_token_->HasSeenAllChildren())
+
+ next_is_from_break_token = child_token_idx_ < child_break_tokens.size();
+
+ if (child_break_token) {
+ // If we have a child break token to resume at, that's the source of
+ // truth.
+ child_ = child_break_token->InputNode();
+ } else if (break_token_->HasSeenAllChildren()) {
+ // If there are no break tokens left to resume, the iterator machinery
+ // (see further below) will by default just continue at the next sibling.
+ // The last break token would be the last node that previously got
+ // fragmented. However, there may be parallel flows caused by visible
+ // overflow, established by descendants of our children, and these may go
+ // on, fragmentainer after fragmentainer, even if we're done with our
+ // direct children. When this happens, we need to prevent the machinery
+ // from continuing iterating, if we're already done with those siblings.
child_ = nullptr;
+ }
}
- // If we have a child break token to resume at, that's the source of truth.
- if (child_break_token)
- child_ = child_break_token->InputNode();
-
NGLayoutInputNode child = child_;
- if (child_)
+
+ // Unless we're going to grab the next child off a break token, we'll use the
+ // next sibling of the current child. Prepare it now.
+ if (child_ && !next_is_from_break_token)
child_ = child_.NextSibling();
return Entry(child, child_break_token);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index ee59511a998..d70553f10a1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
@@ -375,14 +374,14 @@ MinMaxSizesResult NGBlockLayoutAlgorithm::ComputeMinMaxSizes(
DCHECK_LE(sizes.min_size, sizes.max_size) << Node().ToString();
sizes += BorderScrollbarPadding().InlineSum();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
LogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
const NGFragment& fragment,
LayoutUnit child_bfc_line_offset,
const base::Optional<LayoutUnit>& child_bfc_block_offset) {
- LayoutUnit inline_size = container_builder_.Size().inline_size;
+ LayoutUnit inline_size = container_builder_.InlineSize();
TextDirection direction = ConstraintSpace().Direction();
if (child_bfc_block_offset && container_builder_.BfcBlockOffset()) {
@@ -430,8 +429,6 @@ NOINLINE scoped_refptr<const NGLayoutResult>
NGBlockLayoutAlgorithm::LayoutWithInlineChildLayoutContext(
const NGLayoutInputNode& first_child) {
NGInlineChildLayoutContext context;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return Layout(&context);
return LayoutWithItemsBuilder(To<NGInlineNode>(first_child), &context);
}
@@ -883,7 +880,7 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::FinishLayout(
border_box_size.block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(),
previously_consumed_block_size + intrinsic_block_size_,
- border_box_size.inline_size);
+ border_box_size.inline_size, Node().ShouldBeConsideredAsReplaced());
container_builder_.SetFragmentsTotalBlockSize(border_box_size.block_size);
// If our BFC block-offset is still unknown, we check:
@@ -905,8 +902,7 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::FinishLayout(
// - The block-size differs from the intrinsic size.
// - The parent has computed block-size != auto.
if (border_box_size.block_size != intrinsic_block_size_ ||
- !BlockLengthUnresolvable(ConstraintSpace(), Style().LogicalHeight(),
- LengthResolvePhase::kLayout)) {
+ !BlockLengthUnresolvable(ConstraintSpace(), Style().LogicalHeight())) {
end_margin_strut = NGMarginStrut();
}
}
@@ -981,7 +977,6 @@ bool NGBlockLayoutAlgorithm::TryReuseFragmentsFromCache(
NGInlineNode inline_node,
NGPreviousInflowPosition* previous_inflow_position,
scoped_refptr<const NGInlineBreakToken>* inline_break_token_out) {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(previous_result_);
DCHECK(!inline_node.IsEmptyInline());
DCHECK(container_builder_.BfcBlockOffset());
@@ -1050,6 +1045,20 @@ bool NGBlockLayoutAlgorithm::TryReuseFragmentsFromCache(
void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(
const NGPreviousInflowPosition& previous_inflow_position,
NGBlockNode child) {
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ // Forced breaks cannot be specified directly on out-of-flow positioned
+ // elements, but if the preceding block has a forced break after, we need to
+ // break before it. Note that we really only need to do this if block-start
+ // offset is auto (but it's harmless to do it also when it's non-auto).
+ EBreakBetween break_between =
+ container_builder_.JoinedBreakBetweenValue(EBreakBetween::kAuto);
+ if (IsForcedBreakValue(ConstraintSpace(), break_between)) {
+ container_builder_.AddBreakBeforeChild(child, kBreakAppealPerfect,
+ /* is_forced_break*/ true);
+ return;
+ }
+ }
+
DCHECK(child.IsOutOfFlowPositioned());
LogicalOffset static_offset = {BorderScrollbarPadding().inline_start,
previous_inflow_position.logical_block_offset};
@@ -1138,11 +1147,6 @@ void NGBlockLayoutAlgorithm::HandleFloat(
NGPositionedFloat positioned_float =
PositionFloat(&unpositioned_float, &exclusion_space_);
- const NGLayoutResult& layout_result = *positioned_float.layout_result;
-
- // TODO(mstensho): Handle abortions caused by block fragmentation.
- DCHECK_EQ(layout_result.Status(), NGLayoutResult::kSuccess);
-
if (positioned_float.need_break_before) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
LayoutUnit fragmentainer_block_offset =
@@ -1159,6 +1163,8 @@ void NGBlockLayoutAlgorithm::HandleFloat(
return;
}
+ DCHECK_EQ(positioned_float.layout_result->Status(), NGLayoutResult::kSuccess);
+
// TODO(mstensho): There should be a class A breakpoint between a float and
// another float, and also between a float and an in-flow block.
@@ -1174,7 +1180,7 @@ void NGBlockLayoutAlgorithm::HandleFloat(
LogicalOffset logical_offset = LogicalFromBfcOffsets(
positioned_float.bfc_offset, bfc_offset, float_inline_size,
- container_builder_.Size().inline_size, ConstraintSpace().Direction());
+ container_builder_.InlineSize(), ConstraintSpace().Direction());
container_builder_.AddResult(*positioned_float.layout_result, logical_offset);
}
@@ -1372,7 +1378,7 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleNewFormattingContext(
LogicalOffset logical_offset = LogicalFromBfcOffsets(
child_bfc_offset, ContainerBfcOffset(), fragment.InlineSize(),
- container_builder_.Size().inline_size, ConstraintSpace().Direction());
+ container_builder_.InlineSize(), ConstraintSpace().Direction());
if (!PositionOrPropagateListMarker(*layout_result, &logical_offset,
previous_inflow_position))
@@ -1387,7 +1393,8 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleNewFormattingContext(
ConstraintSpace(), Node(), BorderScrollbarPadding(), bsp_block_sum);
block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
block_size -= bsp_block_sum;
logical_offset =
CenterBlockChild(logical_offset, block_size, fragment.BlockSize());
@@ -1587,8 +1594,7 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleInflow(
is_non_empty_inline = !child_inline_node->IsEmptyInline();
// Add reusable line boxes from |previous_result_| if any.
- if (is_non_empty_inline && !child_break_token && previous_result_ &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (is_non_empty_inline && !child_break_token && previous_result_) {
if (!ResolveBfcBlockOffset(previous_inflow_position))
return NGLayoutResult::kBfcBlockOffsetResolved;
DCHECK(container_builder_.BfcBlockOffset());
@@ -2115,6 +2121,26 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
margin_strut.Append(child_data.margins.block_end, is_quirky);
SetSubtreeModifiedMarginStrutIfNeeded(&child.Style().MarginAfter());
+ if (UNLIKELY(ConstraintSpace().HasBlockFragmentation())) {
+ // If the child broke inside, don't apply any trailing margin, since it's
+ // only to be applied to the last fragment that's not in a parallel flow
+ // (due to overflow). While trailing margins are normally truncated at
+ // fragmentainer boundaries, so that whether or not we add such margins
+ // doesn't really make much of a difference, this isn't the case in the
+ // initial column balancing pass.
+ if (const auto* physical_fragment = DynamicTo<NGPhysicalBoxFragment>(
+ &layout_result.PhysicalFragment())) {
+ if (const auto* token =
+ To<NGBlockBreakToken>(physical_fragment->BreakToken())) {
+ // TODO(mstensho): Don't apply the margin to all overflowing fragments
+ // (if any). It should only be applied after the fragment where we
+ // reached the block-end of the node.
+ if (!token->IsAtBlockEnd())
+ margin_strut = NGMarginStrut();
+ }
+ }
+ }
+
// This flag is subtle, but in order to determine our size correctly we need
// to check if our last child is self-collapsing, and it was affected by
// clearance *or* an adjoining self-collapsing sibling was affected by
@@ -2271,15 +2297,34 @@ bool NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
}
if (container_builder_.IsFragmentainerBoxType()) {
- // We're building fragmentainers. Just copy the block-size from the
- // constraint space. Calculating the size the regular way would cause some
- // problems with overflow. For one, we don't want to produce a break token
- // if there's no child content that requires it.
+ // We're building fragmentainers. Finish fragmentation on our own, since
+ // special-rules apply.
LayoutUnit consumed_block_size =
BreakToken() ? BreakToken()->ConsumedBlockSize() : LayoutUnit();
- LayoutUnit block_size = ConstraintSpace().FragmentainerBlockSize();
- container_builder_.SetFragmentBlockSize(block_size);
- container_builder_.SetConsumedBlockSize(consumed_block_size + block_size);
+ if (ConstraintSpace().HasKnownFragmentainerBlockSize()) {
+ // Just copy the block-size from the constraint space. Calculating the
+ // size the regular way would cause some problems with overflow. For one,
+ // we don't want to produce a break token if there's no child content that
+ // requires it. When we lay out, we use FragmentainerCapacity(), so this
+ // is what we need to add to consumed block-size for the next break
+ // token. The fragment block-size itself will be based directly on the
+ // fragmentainer size from the constraint space, though.
+ container_builder_.SetFragmentBlockSize(
+ ConstraintSpace().FragmentainerBlockSize());
+ container_builder_.SetConsumedBlockSize(
+ consumed_block_size + FragmentainerCapacity(ConstraintSpace()));
+ } else {
+ // When we are in the initial column balancing pass, use the block-size
+ // calculated by the algorithm. Since any previously consumed block-size
+ // is already baked in (in order to correctly honor specified block-size
+ // (which makes sense to everyone but fragmentainers)), we need to extract
+ // it again now.
+ LayoutUnit fragments_total_block_size =
+ container_builder_.FragmentsTotalBlockSize();
+ container_builder_.SetFragmentBlockSize(fragments_total_block_size -
+ consumed_block_size);
+ container_builder_.SetConsumedBlockSize(fragments_total_block_size);
+ }
return true;
}
@@ -2485,6 +2530,7 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
/* is_new_fc */ false);
builder.SetAvailableSize(ChildAvailableSize());
builder.SetPercentageResolutionSize(child_percentage_size_);
+ builder.SetStretchInlineSizeIfAuto(true);
NGConstraintSpace space = builder.ToConstraintSpace();
NGBoxStrut child_border_padding =
@@ -2519,12 +2565,12 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
is_new_fc);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), child, &builder);
- if (!IsParallelWritingMode(ConstraintSpace().GetWritingMode(),
- child_writing_direction.GetWritingMode()))
- builder.SetIsShrinkToFit(child_style.LogicalWidth().IsAuto());
- if (child_style.LogicalWidth().IsAuto() &&
- child.GetLayoutBox()->AutoWidthShouldFitContent())
- builder.SetIsShrinkToFit(true);
+ if (IsParallelWritingMode(ConstraintSpace().GetWritingMode(),
+ child_writing_direction.GetWritingMode())) {
+ if (!child.GetLayoutBox()->AutoWidthShouldFitContent() &&
+ !child.IsReplaced() && !child.IsTable())
+ builder.SetStretchInlineSizeIfAuto(true);
+ }
builder.SetAvailableSize(child_available_size);
builder.SetPercentageResolutionSize(child_percentage_size_);
@@ -2600,8 +2646,6 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
clearance_offset = std::max(clearance_offset, child_clearance_offset);
// |PositionListMarker()| requires a baseline.
- builder.SetNeedsBaseline(ConstraintSpace().NeedsBaseline() ||
- container_builder_.UnpositionedListMarker());
builder.SetBaselineAlgorithmType(ConstraintSpace().BaselineAlgorithmType());
}
builder.SetClearanceOffset(clearance_offset);
@@ -2674,6 +2718,13 @@ void NGBlockLayoutAlgorithm::PropagateBaselineFromChild(
return;
}
+ // When computing the baseline for an inline-block, table's don't contribute
+ // to any baselines.
+ if (child.IsTableNG() && ConstraintSpace().BaselineAlgorithmType() !=
+ NGBaselineAlgorithmType::kFirstLine) {
+ return;
+ }
+
NGBoxFragment fragment(ConstraintSpace().GetWritingDirection(),
To<NGPhysicalBoxFragment>(child));
@@ -2896,10 +2947,10 @@ void NGBlockLayoutAlgorithm::HandleRubyText(NGBlockNode ruby_text_child) {
NGConstraintSpaceBuilder builder(ConstraintSpace(),
rt_style.GetWritingDirection(), true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), ruby_text_child, &builder);
- if (!IsParallelWritingMode(Style().GetWritingMode(),
- rt_style.GetWritingMode()))
- builder.SetIsShrinkToFit(rt_style.LogicalWidth().IsAuto());
builder.SetAvailableSize(ChildAvailableSize());
+ if (IsParallelWritingMode(ConstraintSpace().GetWritingMode(),
+ rt_style.GetWritingMode()))
+ builder.SetStretchInlineSizeIfAuto(true);
scoped_refptr<const NGLayoutResult> result =
ruby_text_child.Layout(builder.ToConstraintSpace(), break_token.get());
@@ -2984,12 +3035,30 @@ void NGBlockLayoutAlgorithm::HandleTextControlPlaceholder(
const NGPreviousInflowPosition& previous_inflow_position) {
DCHECK(Node().IsTextControl()) << Node().GetLayoutBox();
+ LogicalSize available_size = ChildAvailableSize();
+ // The placeholder should have the width same as "editing-view-port" element,
+ // which is the first grandchild of the text control.
+ if (container_builder_.Children().size() > 0) {
+ const NGPhysicalFragment& child =
+ *container_builder_.Children()[0].fragment;
+ if (child.IsTextControlContainer()) {
+ const auto& grand_children =
+ To<NGPhysicalContainerFragment>(child).PostLayoutChildren();
+ const auto begin = grand_children.begin();
+ if (begin != grand_children.end()) {
+ NGFragment grand_child_fragment(ConstraintSpace().GetWritingDirection(),
+ *begin->fragment);
+ available_size.inline_size = grand_child_fragment.InlineSize();
+ }
+ }
+ }
+
const bool is_new_fc = placeholder.CreatesNewFormattingContext();
const NGConstraintSpace space = CreateConstraintSpaceForChild(
placeholder,
ComputeChildData(previous_inflow_position, placeholder,
/* child_break_token */ nullptr, is_new_fc),
- ChildAvailableSize(), is_new_fc);
+ available_size, is_new_fc);
scoped_refptr<const NGLayoutResult> result = placeholder.Layout(space);
LogicalOffset offset = BorderScrollbarPadding().StartOffset();
@@ -3004,8 +3073,11 @@ void NGBlockLayoutAlgorithm::HandleTextControlPlaceholder(
// We should apply FirstBaseline() of the placeholder fragment because the
// placeholder might have the 'overflow' property, and its LastBaseline()
// might be the block-end margin.
- offset.block_offset =
- *container_builder_.Baseline() - *fragment.FirstBaseline();
+ // |fragment| has no FirstBaseline() if it consists of only white-spaces.
+ if (fragment.FirstBaseline().has_value()) {
+ offset.block_offset =
+ *container_builder_.Baseline() - *fragment.FirstBaseline();
+ }
container_builder_.AddResult(*result, offset);
// This function doesn't update previous_inflow_position. Other children in
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 32c22ff4f54..ded2845c057 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -230,7 +230,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, PercentageBlockSizeQuirkDescendantsCaching) {
/* is_new_formatting_context */ false);
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
- builder.SetNeedsBaseline(true);
+ builder.SetStretchInlineSizeIfAuto(true);
return builder.ToConstraintSpace();
};
@@ -297,7 +297,6 @@ TEST_F(NGBlockLayoutAlgorithmTest, LineOffsetCaching) {
/* is_new_formatting_context */ false);
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
- builder.SetNeedsBaseline(true);
builder.SetBfcOffset(bfc_offset);
return builder.ToConstraintSpace();
};
@@ -1653,7 +1652,8 @@ TEST_F(NGBlockLayoutAlgorithmTest, ShrinkToFit) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(100), kIndefiniteSize), true);
+ LogicalSize(LayoutUnit(100), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ false);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(container, space);
@@ -1802,7 +1802,8 @@ TEST_F(NGBlockLayoutAlgorithmTest, NoFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
// We should only have one 150x200 fragment with no fragmentation.
@@ -1830,13 +1831,14 @@ TEST_F(NGBlockLayoutAlgorithmTest, SimpleFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
fragment = RunBlockLayoutAlgorithm(node, space, fragment->BreakToken());
EXPECT_EQ(PhysicalSize(150, 100), fragment->Size());
@@ -1873,13 +1875,14 @@ TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
FragmentChildIterator iterator(To<NGPhysicalBoxFragment>(fragment.get()));
PhysicalOffset offset;
@@ -1938,13 +1941,14 @@ TEST_F(NGBlockLayoutAlgorithmTest,
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
FragmentChildIterator iterator(To<NGPhysicalBoxFragment>(fragment.get()));
PhysicalOffset offset;
@@ -2001,13 +2005,14 @@ TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentationSmallHeight) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 70), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
FragmentChildIterator iterator(To<NGPhysicalBoxFragment>(fragment.get()));
PhysicalOffset offset;
@@ -2067,13 +2072,14 @@ TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationParallelFlows) {
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 50), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
FragmentChildIterator iterator(To<NGPhysicalBoxFragment>(fragment.get()));
@@ -2090,7 +2096,8 @@ TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationParallelFlows) {
space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
fragment = RunBlockLayoutAlgorithm(node, space, fragment->BreakToken());
@@ -2145,8 +2152,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationOrthogonalFlows) {
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false, true,
- kFragmentainerSpaceAvailable);
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true, kFragmentainerSpaceAvailable);
AdvanceToLayoutPhase();
@@ -2195,13 +2203,14 @@ TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationZeroHeight) {
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
EXPECT_EQ(PhysicalSize(150, 50), fragment->Size());
- ASSERT_FALSE(fragment->BreakToken()->IsFinished());
+ EXPECT_TRUE(fragment->BreakToken());
FragmentChildIterator iterator(To<NGPhysicalBoxFragment>(fragment.get()));
const auto* child = iterator.NextChild();
@@ -2215,7 +2224,8 @@ TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationZeroHeight) {
space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
fragment = RunBlockLayoutAlgorithm(node, space, fragment->BreakToken());
@@ -2355,7 +2365,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, ZeroBlockSizeAboveEdge) {
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false, true);
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
@@ -2393,7 +2405,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, NewFcFirstChildIsZeroBlockSize) {
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false, true);
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
+ /* is_new_formatting_context */ true);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
RunBlockLayoutAlgorithm(node, space);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 2a38769bbe2..537498c95df 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -55,6 +55,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
@@ -176,6 +177,9 @@ NOINLINE void DetermineAlgorithmAndRun(const NGLayoutAlgorithmParams& params,
} else if (box.IsLayoutNGGrid() &&
RuntimeEnabledFeatures::LayoutNGGridEnabled()) {
CreateAlgorithmAndRun<NGGridLayoutAlgorithm>(params, callback);
+ } else if (box.IsLayoutImage()) {
+ DCHECK(RuntimeEnabledFeatures::LayoutNGReplacedEnabled());
+ CreateAlgorithmAndRun<NGReplacedLayoutAlgorithm>(params, callback);
} else if (box.IsLayoutNGFieldset()) {
CreateAlgorithmAndRun<NGFieldsetLayoutAlgorithm>(params, callback);
// If there's a legacy layout box, we can only do block fragmentation if
@@ -219,19 +223,21 @@ NGConstraintSpace CreateConstraintSpaceForMinMax(
NGConstraintSpaceBuilder builder(node.Style().GetWritingMode(),
node.Style().GetWritingDirection(),
node.CreatesNewFormattingContext());
- builder.SetAvailableSize(LogicalSize());
+ builder.SetAvailableSize({kIndefiniteSize, kIndefiniteSize});
builder.SetPercentageResolutionSize(
- {LayoutUnit(), input.percentage_resolution_block_size});
+ {kIndefiniteSize, input.percentage_resolution_block_size});
return builder.ToConstraintSpace();
}
LayoutUnit CalculateAvailableInlineSizeForLegacy(
const LayoutBox& box,
const NGConstraintSpace& space) {
- if (box.ShouldComputeSizeAsReplaced())
- return space.ReplacedPercentageResolutionInlineSize();
+ if (box.ShouldComputeSizeAsReplaced()) {
+ return space.ReplacedPercentageResolutionInlineSize()
+ .ClampIndefiniteToZero();
+ }
- return space.PercentageResolutionInlineSize();
+ return space.PercentageResolutionInlineSize().ClampIndefiniteToZero();
}
LayoutUnit CalculateAvailableBlockSizeForLegacy(
@@ -283,6 +289,10 @@ void SetupBoxLayoutExtraInput(const NGConstraintSpace& space,
input->is_override_block_size_definite =
!space.IsFixedBlockSizeIndefinite();
}
+ input->stretch_inline_size_if_auto = space.StretchInlineSizeIfAuto();
+ input->stretch_block_size_if_auto =
+ space.StretchBlockSizeIfAuto() &&
+ space.AvailableSize().block_size != kIndefiniteSize;
}
bool CanUseCachedIntrinsicInlineSizes(const MinMaxSizesInput& input,
@@ -316,6 +326,14 @@ bool CanUseCachedIntrinsicInlineSizes(const MinMaxSizesInput& input,
constraint_space.TableCellBorders())
return false;
+ // We may have something like:
+ // "grid-template-columns: repeat(auto-fill, 50px); min-width: 50%;"
+ // In this specific case our min/max sizes are now dependent on what
+ // "min-width" resolves to - which is unique to grid.
+ if (node.IsGrid() && (style.LogicalMinWidth().IsPercentOrCalc() ||
+ style.LogicalMaxWidth().IsPercentOrCalc()))
+ return false;
+
return true;
}
@@ -430,6 +448,18 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
CalculateInitialFragmentGeometry(constraint_space, *this);
}
+ if (RuntimeEnabledFeatures::CSSContainerQueriesEnabled() &&
+ IsContainerForContainerQueries()) {
+ if (auto* element = DynamicTo<Element>(GetDOMNode())) {
+ LogicalSize available_size = CalculateChildAvailableSize(
+ constraint_space, *this, fragment_geometry->border_box_size,
+ fragment_geometry->border + fragment_geometry->padding);
+ LogicalAxes contained_axes = ContainedAxes();
+ GetDocument().GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(
+ *element, available_size, contained_axes);
+ }
+ }
+
TextAutosizer::NGLayoutScope text_autosizer_layout_scope(
box_, fragment_geometry->border_box_size.inline_size);
@@ -532,20 +562,6 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
UpdateShapeOutsideInfoIfNeeded(
*layout_result, constraint_space.PercentageResolutionInlineSize());
-#if DCHECK_IS_ON()
- // DCHECK can only be turned on for LayoutNGTable because it
- // fails with Legacy table implementation.
- if (RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
- layout_result->Status() == NGLayoutResult::kSuccess) {
- LogicalSize size =
- layout_result->PhysicalFragment().Size().ConvertToLogical(
- constraint_space.GetWritingMode());
- if (constraint_space.IsFixedInlineSize())
- DCHECK_EQ(size.inline_size, constraint_space.AvailableSize().inline_size);
- if (constraint_space.IsFixedBlockSize())
- DCHECK_EQ(size.block_size, constraint_space.AvailableSize().block_size);
- }
-#endif
return layout_result;
}
@@ -701,20 +717,12 @@ void NGBlockNode::FinishLayout(
}
if (has_inline_children) {
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- CopyFragmentDataToLayoutBoxForInlineChildren(
- physical_fragment, physical_fragment.Size().width,
- Style().IsFlippedBlocksWritingMode());
- block_flow->SetPaintFragment(break_token, &physical_fragment);
- } else if (items) {
+ if (items)
CopyFragmentItemsToLayoutBox(physical_fragment, *items, break_token);
- }
} else {
- // We still need to clear paint fragments in case it had inline children,
- // and thus had NGPaintFragment.
+ // We still need to clear |NGInlineNodeData| in case it had inline
+ // children.
block_flow->ClearNGInlineNodeData();
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- block_flow->SetPaintFragment(break_token, nullptr);
}
} else {
DCHECK(!physical_fragment.HasItems());
@@ -746,8 +754,9 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
// of the layout phase.
// TODO(ikilpatrick): Remove this check.
if (!box_->GetFrameView()->IsInPerformLayout()) {
- sizes = ComputeMinMaxSizesFromLegacy(input);
- return {sizes, /* depends_on_percentage_block_size */ false};
+ sizes = ComputeMinMaxSizesFromLegacy(input, *constraint_space);
+ return MinMaxSizesResult(sizes,
+ /* depends_on_percentage_block_size */ false);
}
DCHECK(constraint_space);
@@ -757,7 +766,8 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
sizes = NGFragment({container_writing_mode, TextDirection::kLtr},
layout_result->PhysicalFragment())
.InlineSize();
- return {sizes, /* depends_on_percentage_block_size */ false};
+ return MinMaxSizesResult(sizes,
+ /* depends_on_percentage_block_size */ false);
}
// Synthesize a zero space if not provided.
@@ -774,15 +784,16 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
block_size = input.percentage_resolution_block_size;
}
- NGFragmentGeometry fragment_geometry =
+ const NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this);
- NGBoxStrut border_padding =
+ const NGBoxStrut border_padding =
fragment_geometry.border + fragment_geometry.padding;
LayoutUnit size_from_ar = ComputeInlineSizeFromAspectRatio(
- *constraint_space, Style(), border_padding, block_size);
+ *constraint_space, Style(), border_padding,
+ ShouldBeConsideredAsReplaced(), block_size);
if (size_from_ar != kIndefiniteSize) {
- return {{size_from_ar, size_from_ar},
- Style().LogicalHeight().IsPercentOrCalc()};
+ return MinMaxSizesResult({size_from_ar, size_from_ar},
+ Style().LogicalHeight().IsPercentOrCalc());
}
}
@@ -801,10 +812,10 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
: box_->IntrinsicLogicalWidths(input.type);
bool depends_on_percentage_block_size =
box_->IntrinsicLogicalWidthsDependsOnPercentageBlockSize();
- return {sizes, depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, depends_on_percentage_block_size);
}
- NGFragmentGeometry fragment_geometry =
+ const NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this);
// Calculate the %-block-size for our children up front. This allows us to
@@ -814,7 +825,7 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
bool uses_input_percentage_block_size = false;
LayoutUnit child_percentage_resolution_block_size =
CalculateChildPercentageBlockSizeForMinMax(
- *constraint_space, *this, border_padding,
+ *constraint_space, *this, border_padding, fragment_geometry.scrollbar,
input.percentage_resolution_block_size,
&uses_input_percentage_block_size);
@@ -829,13 +840,13 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
MinMaxSizes sizes = box_->IsTable() && !box_->IsLayoutNGMixin()
? box_->PreferredLogicalWidths()
: box_->IntrinsicLogicalWidths(input.type);
- return {sizes, cache_depends_on_percentage_block_size};
+ return MinMaxSizesResult(sizes, cache_depends_on_percentage_block_size);
}
box_->SetIntrinsicLogicalWidthsDirty();
if (!CanUseNewLayout()) {
- MinMaxSizes sizes = ComputeMinMaxSizesFromLegacy(input);
+ MinMaxSizes sizes = ComputeMinMaxSizesFromLegacy(input, *constraint_space);
// Update the cache bits for this legacy root (but not the intrinsic
// inline-sizes themselves).
@@ -845,7 +856,7 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
/* child_depends_on_percentage_block_size */ true,
/* sizes */ nullptr);
- return {sizes, uses_input_percentage_block_size};
+ return MinMaxSizesResult(sizes, uses_input_percentage_block_size);
}
// Copy the input, and set the new %-block-size.
@@ -865,14 +876,12 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
result.depends_on_percentage_block_size;
if (!Style().AspectRatio().IsAuto() &&
- BlockLengthUnresolvable(*constraint_space, Style().LogicalHeight(),
- LengthResolvePhase::kLayout)) {
+ BlockLengthUnresolvable(*constraint_space, Style().LogicalHeight())) {
// If the block size will be computed from the aspect ratio, we need
// to take the max-block-size into account.
// https://drafts.csswg.org/css-sizing-4/#aspect-ratio
MinMaxSizes min_max = ComputeMinMaxInlineSizesFromAspectRatio(
- *constraint_space, Style(), border_padding,
- LengthResolvePhase::kIntrinsic);
+ *constraint_space, Style(), border_padding);
result.sizes.min_size = min_max.ClampSizeToMinAndMax(result.sizes.min_size);
result.sizes.max_size = min_max.ClampSizeToMinAndMax(result.sizes.max_size);
depends_on_percentage_block_size =
@@ -898,13 +907,10 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
}
MinMaxSizes NGBlockNode::ComputeMinMaxSizesFromLegacy(
- const MinMaxSizesInput& input) const {
- bool needs_size_reset = false;
- if (!box_->HasOverrideContainingBlockContentLogicalHeight()) {
- box_->SetOverrideContainingBlockContentLogicalHeight(
- input.percentage_resolution_block_size);
- needs_size_reset = true;
- }
+ const MinMaxSizesInput& input,
+ const NGConstraintSpace& space) const {
+ BoxLayoutExtraInput extra_input(*box_);
+ SetupBoxLayoutExtraInput(space, *box_, &extra_input);
// Tables don't calculate their min/max content contribution the same way as
// other layout nodes. This is because width/min-width/etc have a different
@@ -915,9 +921,6 @@ MinMaxSizes NGBlockNode::ComputeMinMaxSizesFromLegacy(
? box_->PreferredLogicalWidths()
: box_->IntrinsicLogicalWidths(input.type);
- if (needs_size_reset)
- box_->ClearOverrideContainingBlockContentSize();
-
return sizes;
}
@@ -998,7 +1001,9 @@ bool NGBlockNode::CanUseNewLayout(const LayoutBox& box) {
DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
if (box.ForceLegacyLayout())
return false;
- return box.IsLayoutNGMixin();
+ return box.IsLayoutNGMixin() ||
+ (box.IsLayoutImage() && !box.IsMedia() &&
+ RuntimeEnabledFeatures::LayoutNGReplacedEnabled());
}
bool NGBlockNode::CanUseNewLayout() const {
@@ -1079,8 +1084,24 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
// child layout.
if (!ChildLayoutBlockedByDisplayLock()) {
if (UNLIKELY(flow_thread)) {
- PlaceChildrenInFlowThread(flow_thread, constraint_space,
- physical_fragment, previous_break_token);
+ // Hold off writing legacy data for the entire multicol container until
+ // done with the last fragment (we may have multiple if nested within
+ // another fragmentation context). This way we'll get everything in order.
+ // We'd otherwise mess up in complex cases of nested column balancing. The
+ // column layout algorithms may retry layout for a given fragment, which
+ // would confuse the code that writes back to legacy objects, so that we
+ // wouldn't always update column sets or establish fragmentainer groups
+ // correctly.
+ if (is_last_fragment) {
+ const NGBlockBreakToken* incoming_break_token = nullptr;
+ for (const NGPhysicalBoxFragment& multicol_fragment :
+ box_->PhysicalFragments()) {
+ PlaceChildrenInFlowThread(flow_thread, constraint_space,
+ multicol_fragment, incoming_break_token);
+ incoming_break_token =
+ To<NGBlockBreakToken>(multicol_fragment.BreakToken());
+ }
+ }
} else {
PlaceChildrenInLayoutBox(physical_fragment, previous_break_token);
}
@@ -1100,6 +1121,10 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
// Issue full invalidation, in case the number of column rules have
// changed.
needs_full_invalidation = true;
+ } else if (block->StyleForContinuationOutline()) {
+ // When this is a block-in-inline created by |SplineInlines|, we may need
+ // to paint outlines for this. See |NGBoxFragmentPainter|.
+ needs_full_invalidation = true;
}
block->SetNeedsOverflowRecalc(
@@ -1235,7 +1260,14 @@ void NGBlockNode::PlaceChildrenInFlowThread(
const auto& child_fragment = To<NGPhysicalBoxFragment>(*child);
const auto* child_box = To<LayoutBox>(child_fragment.GetLayoutObject());
if (child_box && child_box != box_) {
- DCHECK(child_box->IsColumnSpanAll());
+ if (!child_box->IsColumnSpanAll()) {
+ // TODO(almaher): In order for legacy tree operations to work properly,
+ // we need to CopyChildFragmentPosition(). We should probably also
+ // update the LayoutBox size at the last fragment of an OOF node.
+ // (See comments in CL:2597769).
+ DCHECK(child_box->IsOutOfFlowPositioned());
+ continue;
+ }
CopyChildFragmentPosition(child_fragment, child.offset,
physical_fragment);
LayoutBox* placeholder = child_box->SpannerPlaceholder();
@@ -1266,6 +1298,8 @@ void NGBlockNode::PlaceChildrenInFlowThread(
DCHECK(!child_box);
LogicalSize logical_size = converter.ToLogical(child_fragment.Size());
+ logical_size.block_size =
+ ClampedToValidFragmentainerCapacity(logical_size.block_size);
if (has_processed_first_column_in_flow_thread) {
// Non-uniform fragmentainer widths not supported by legacy layout.
@@ -1359,62 +1393,10 @@ void NGBlockNode::CopyChildFragmentPosition(
layout_box->SetLocationAndUpdateOverflowControlsIfNeeded(point);
}
-// For inline children, NG painters handles fragments directly, but there are
-// some cases where we need to copy data to the LayoutObject tree. This function
-// handles such cases.
-void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
- const NGPhysicalContainerFragment& container,
- LayoutUnit initial_container_width,
- bool initial_container_is_flipped,
- PhysicalOffset offset) const {
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
- for (const auto& child : container.Children()) {
- if (child->IsContainer()) {
- PhysicalOffset child_offset = offset + child.Offset();
-
- // Replaced elements and inline blocks need Location() set relative to
- // their block container.
- LayoutObject* layout_object = child->GetMutableLayoutObject();
- if (layout_object && layout_object->IsBox()) {
- auto& layout_box = To<LayoutBox>(*layout_object);
- PhysicalOffset maybe_flipped_offset = child_offset;
- if (initial_container_is_flipped) {
- maybe_flipped_offset.left = initial_container_width -
- child->Size().width -
- maybe_flipped_offset.left;
- }
- layout_box.SetLocationAndUpdateOverflowControlsIfNeeded(
- maybe_flipped_offset.ToLayoutPoint());
- }
-
- // Legacy compatibility. This flag is used in paint layer for
- // invalidation.
- if (layout_object && layout_object->IsLayoutInline() &&
- layout_object->StyleRef().HasOutline() &&
- !layout_object->IsElementContinuation() &&
- To<LayoutInline>(layout_object)->Continuation()) {
- box_->SetContainsInlineWithOutlineAndContinuation(true);
- }
-
- // The Location() of inline LayoutObject is relative to the
- // LayoutBlockFlow. If |child| establishes a new block formatting context,
- // it also creates another inline formatting context. Do not copy to its
- // descendants in this case.
- if (!child->IsFormattingContextRoot()) {
- CopyFragmentDataToLayoutBoxForInlineChildren(
- To<NGPhysicalContainerFragment>(*child), initial_container_width,
- initial_container_is_flipped, child_offset);
- }
- }
- }
-}
-
void NGBlockNode::CopyFragmentItemsToLayoutBox(
const NGPhysicalBoxFragment& container,
const NGFragmentItems& items,
const NGBlockBreakToken* previous_break_token) const {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
-
LayoutUnit previously_consumed_block_size;
if (previous_break_token)
previously_consumed_block_size = previous_break_token->ConsumedBlockSize();
@@ -1428,7 +1410,7 @@ void NGBlockNode::CopyFragmentItemsToLayoutBox(
continue;
if (auto* layout_box = DynamicTo<LayoutBox>(layout_object)) {
PhysicalOffset maybe_flipped_offset =
- cursor.Current().OffsetInContainerBlock();
+ cursor.Current().OffsetInContainerFragment();
if (initial_container_is_flipped) {
maybe_flipped_offset.left = container.Size().width -
child->Size().width -
@@ -1569,10 +1551,8 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::LayoutAtomicInline(
builder.SetIsPaintedAtomically(true);
builder.SetUseFirstLineStyle(use_first_line_style);
- builder.SetNeedsBaseline(true);
builder.SetBaselineAlgorithmType(baseline_algorithm_type);
- builder.SetIsShrinkToFit(Style().LogicalWidth().IsAuto());
builder.SetAvailableSize(parent_constraint_space.AvailableSize());
builder.SetPercentageResolutionSize(
parent_constraint_space.PercentageResolutionSize());
@@ -1720,14 +1700,6 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::RunSimplifiedLayout(
void NGBlockNode::CopyBaselinesFromLegacyLayout(
const NGConstraintSpace& constraint_space,
NGBoxFragmentBuilder* builder) const {
- // As the calls to query baselines from legacy layout are potentially
- // expensive we only ask for them if needed.
- // TODO(layout-dev): Once we have flexbox, and editing switched over to
- // LayoutNG we should be able to safely remove this flag without a
- // performance penalty.
- if (!constraint_space.NeedsBaseline())
- return;
-
switch (constraint_space.BaselineAlgorithmType()) {
case NGBaselineAlgorithmType::kFirstLine: {
LayoutUnit position = box_->FirstLineBoxBaseline();
@@ -1822,4 +1794,16 @@ void NGBlockNode::AddColumnResult(
GetFlowThread(To<LayoutBlockFlow>(box_))->AddLayoutResult(result, index);
}
+void NGBlockNode::AddColumnResult(
+ scoped_refptr<const NGLayoutResult> result) const {
+ GetFlowThread(To<LayoutBlockFlow>(box_))->AddLayoutResult(std::move(result));
+}
+
+void NGBlockNode::ReplaceColumnResult(
+ scoped_refptr<const NGLayoutResult> result,
+ const NGPhysicalBoxFragment& old_fragment) const {
+ GetFlowThread(To<LayoutBlockFlow>(box_))
+ ->ReplaceLayoutResult(std::move(result), old_fragment);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index dae795cc327..e16f9e3a0b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -21,7 +21,7 @@ class NGEarlyBreak;
class NGFragmentItems;
class NGLayoutResult;
class NGPhysicalBoxFragment;
-class NGPhysicalContainerFragment;
+class NGPhysicalFragment;
struct NGBoxStrut;
struct NGLayoutAlgorithmParams;
@@ -88,7 +88,8 @@ class CORE_EXPORT NGBlockNode : public NGLayoutInputNode {
const MinMaxSizesInput&,
const NGConstraintSpace* = nullptr) const;
- MinMaxSizes ComputeMinMaxSizesFromLegacy(const MinMaxSizesInput&) const;
+ MinMaxSizes ComputeMinMaxSizesFromLegacy(const MinMaxSizesInput&,
+ const NGConstraintSpace&) const;
NGLayoutInputNode FirstChild() const;
@@ -175,6 +176,11 @@ class CORE_EXPORT NGBlockNode : public NGLayoutInputNode {
// somewhere.
void AddColumnResult(scoped_refptr<const NGLayoutResult>,
const NGBlockBreakToken* incoming_break_token) const;
+ // Add a column layout result to this node.
+ void AddColumnResult(scoped_refptr<const NGLayoutResult>) const;
+ // Replace an existing column layout result with a new one.
+ void ReplaceColumnResult(scoped_refptr<const NGLayoutResult>,
+ const NGPhysicalBoxFragment& old_fragment) const;
static bool CanUseNewLayout(const LayoutBox&);
bool CanUseNewLayout() const;
@@ -220,11 +226,6 @@ class CORE_EXPORT NGBlockNode : public NGLayoutInputNode {
const NGPhysicalBoxFragment& container,
const NGFragmentItems& items,
const NGBlockBreakToken* previous_break_token) const;
- void CopyFragmentDataToLayoutBoxForInlineChildren(
- const NGPhysicalContainerFragment& container,
- LayoutUnit initial_container_width,
- bool initial_container_is_flipped,
- PhysicalOffset offset = {}) const;
void PlaceChildrenInLayoutBox(
const NGPhysicalBoxFragment&,
const NGBlockBreakToken* previous_break_token) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
index 99c18297122..e2366838164 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -68,6 +67,15 @@ class CORE_EXPORT NGBoxFragment final : public NGFragment {
To<NGPhysicalBoxFragment>(physical_fragment_);
return physical_box_fragment.Padding().ConvertToLogical(writing_direction_);
}
+
+ bool HasDescendantsForTablePart() const {
+ const NGPhysicalBoxFragment& box_fragment =
+ To<NGPhysicalBoxFragment>(physical_fragment_);
+ DCHECK(physical_fragment_.IsTableNGPart() || box_fragment.IsTableNGCell());
+ return !box_fragment.Children().empty() ||
+ box_fragment.HasOutOfFlowPositionedFragmentainerDescendants() ||
+ box_fragment.HasOutOfFlowPositionedDescendants();
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 6778ceecbf3..b7ebe92b550 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
@@ -19,7 +18,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
namespace blink {
@@ -30,55 +28,6 @@ namespace {
using LineBoxPair = std::pair<const NGPhysicalLineBoxFragment*,
const NGPhysicalLineBoxFragment*>;
-void GatherInlineContainerFragmentsFromLinebox(
- NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map,
- HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map,
- const NGPhysicalLineBoxFragment& linebox,
- const PhysicalOffset linebox_offset) {
- for (const auto& descendant :
- NGInlineFragmentTraversal::DescendantsOf(linebox)) {
- if (!descendant.fragment->IsBox())
- continue;
- const LayoutObject* key = descendant.fragment->GetLayoutObject();
- // Key for inline is the continuation root if it exists.
- if (key->IsLayoutInline() && key->GetNode())
- key = key->ContinuationRoot();
- auto it = inline_containing_block_map->find(key);
- if (it == inline_containing_block_map->end()) {
- // Default case, not one of the blocks we are looking for.
- continue;
- }
- base::Optional<NGBoxFragmentBuilder::InlineContainingBlockGeometry>&
- containing_block_geometry = it->value;
- LineBoxPair& containing_lineboxes =
- containing_linebox_map->insert(key, LineBoxPair{nullptr, nullptr})
- .stored_value->value;
- DCHECK(containing_block_geometry.has_value() ||
- !containing_lineboxes.first);
-
- // |DescendantsOf| returns the offset from the given fragment. Since
- // we give it the line box, need to add the |linebox_offset|.
- PhysicalRect fragment_rect(
- linebox_offset + descendant.offset_to_container_box,
- descendant.fragment->Size());
- if (containing_lineboxes.first == &linebox) {
- containing_block_geometry->start_fragment_union_rect.Unite(fragment_rect);
- } else if (!containing_lineboxes.first) {
- containing_lineboxes.first = &linebox;
- containing_block_geometry =
- NGBoxFragmentBuilder::InlineContainingBlockGeometry{fragment_rect,
- PhysicalRect()};
- }
- // Skip fragments within an empty line boxes for the end fragment.
- if (containing_lineboxes.second == &linebox) {
- containing_block_geometry->end_fragment_union_rect.Unite(fragment_rect);
- } else if (!containing_lineboxes.second || !linebox.IsEmptyLineBox()) {
- containing_lineboxes.second = &linebox;
- containing_block_geometry->end_fragment_union_rect = fragment_rect;
- }
- }
-}
-
template <class Items>
void GatherInlineContainerFragmentsFromItems(
const Items& items,
@@ -117,7 +66,7 @@ void GatherInlineContainerFragmentsFromItems(
DCHECK(containing_block_geometry.has_value() ||
!containing_lineboxes.first);
- PhysicalRect fragment_rect = item->RectInContainerBlock();
+ PhysicalRect fragment_rect = item->RectInContainerFragment();
fragment_rect.offset += box_offset;
if (containing_lineboxes.first == linebox) {
// Unite the start rect with the fragment's rect.
@@ -150,8 +99,18 @@ void NGBoxFragmentBuilder::AddBreakBeforeChild(
NGLayoutInputNode child,
base::Optional<NGBreakAppeal> appeal,
bool is_forced_break) {
- if (appeal)
+ if (appeal) {
break_appeal_ = *appeal;
+ // If we're violating any orphans / widows or
+ // break-{after,before,inside}:avoid requests, remember this. If we're
+ // balancing columns, we may be able to stretch the columns to resolve the
+ // situation. Note that we should consider handling kBreakAppealLastResort
+ // as well here, but that's currently causing trouble for large leading
+ // margins, which would cause taller columns than desirable in some cases.
+ if (break_appeal_ == kBreakAppealViolatingBreakAvoid ||
+ break_appeal_ == kBreakAppealViolatingOrphansAndWidows)
+ has_violating_break_ = true;
+ }
if (is_forced_break) {
SetHasForcedBreak();
// A forced break is considered to always have perfect appeal; they should
@@ -167,15 +126,35 @@ void NGBoxFragmentBuilder::AddBreakBeforeChild(
has_float_break_inside_ = child.IsFloating();
if (auto* child_inline_node = DynamicTo<NGInlineNode>(child)) {
- if (inline_break_tokens_.IsEmpty()) {
- // In some cases we may want to break before the first line, as a last
- // resort. We need a break token for that as well, so that the machinery
- // will understand that we should resume at the beginning of the inline
- // formatting context, rather than concluding that we're done with the
- // whole thing.
- inline_break_tokens_.push_back(NGInlineBreakToken::Create(
+ if (!last_inline_break_token_) {
+ // In some cases we may want to break before the first line in the
+ // fragment. This happens if there's a tall float before the line, or, as
+ // a last resort, when there are no better breakpoints to choose from, and
+ // we're out of space. When laying out, we store the inline break token
+ // from the last line added to the builder, but if we haven't added any
+ // lines at all, we are still going to need a break token, so that the we
+ // can tell where to resume in the inline formatting context in the next
+ // fragmentainer.
+
+ if (previous_break_token_) {
+ // If there's an incoming break token, see if it has a child inline
+ // break token, and use that one. We may be past floats or lines that
+ // were laid out in earlier fragments.
+ const auto& child_tokens = previous_break_token_->ChildBreakTokens();
+ if (child_tokens.size()) {
+ // If there is an inline break token, it will always be the last
+ // child.
+ last_inline_break_token_ =
+ DynamicTo<NGInlineBreakToken>(child_tokens.back());
+ if (last_inline_break_token_)
+ return;
+ }
+ }
+
+ // We're at the beginning of the inline formatting context.
+ last_inline_break_token_ = NGInlineBreakToken::Create(
*child_inline_node, /* style */ nullptr, /* item_index */ 0,
- /* text_offset */ 0, NGInlineBreakToken::kDefault));
+ /* text_offset */ 0, NGInlineBreakToken::kDefault);
}
return;
}
@@ -413,9 +392,8 @@ void NGBoxFragmentBuilder::PropagateBreak(
const auto& child_fragment =
To<NGPhysicalBoxFragment>(child_layout_result.PhysicalFragment());
if (const auto* token = child_fragment.BreakToken()) {
- if (!token->IsFinished() &&
- (!token->IsBlockType() ||
- !To<NGBlockBreakToken>(token)->IsAtBlockEnd())) {
+ if (!token->IsBlockType() ||
+ !To<NGBlockBreakToken>(token)->IsAtBlockEnd()) {
if (child_fragment.IsFloating())
has_float_break_inside_ = true;
else if (!child_fragment.IsOutOfFlowPositioned())
@@ -431,6 +409,9 @@ void NGBoxFragmentBuilder::PropagateBreak(
} else {
PropagateSpaceShortage(child_layout_result.MinimalSpaceShortage());
}
+
+ if (!is_fragmentation_context_root_)
+ has_violating_break_ |= child_layout_result.HasViolatingBreak();
}
scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::ToBoxFragment(
@@ -448,12 +429,8 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::ToBoxFragment(
#endif
if (UNLIKELY(node_ && has_block_fragmentation_)) {
- if (!inline_break_tokens_.IsEmpty()) {
- if (auto token = inline_break_tokens_.back()) {
- if (!token->IsFinished())
- child_break_tokens_.push_back(std::move(token));
- }
- }
+ if (last_inline_break_token_)
+ child_break_tokens_.push_back(std::move(last_inline_break_token_));
if (DidBreakSelf() || HasChildBreakInside())
break_token_ = NGBlockBreakToken::Create(*this);
}
@@ -485,8 +462,7 @@ LogicalOffset NGBoxFragmentBuilder::GetChildOffset(
if (const NGFragmentItemsBuilder* items_builder = items_builder_) {
if (auto offset = items_builder->LogicalOffsetFor(*object))
return *offset;
- NOTREACHED();
- return LogicalOffset();
+ // Out-of-flow objects may be in |FragmentItems| or in |children_|.
}
for (const auto& child : children_) {
@@ -514,62 +490,6 @@ LogicalOffset NGBoxFragmentBuilder::GetChildOffset(
return LogicalOffset();
}
-void NGBoxFragmentBuilder::ComputeInlineContainerGeometryFromFragmentTree(
- InlineContainingBlockMap* inline_containing_block_map) {
- if (inline_containing_block_map->IsEmpty())
- return;
-
- // This function has detailed knowledge of inline fragment tree structure,
- // and will break if this changes.
- DCHECK_GE(InlineSize(), LayoutUnit());
- DCHECK_GE(FragmentBlockSize(), LayoutUnit());
-#if DCHECK_IS_ON()
- // Make sure all entries are continuation root.
- for (const auto& entry : *inline_containing_block_map)
- DCHECK_EQ(entry.key, entry.key->ContinuationRoot());
-#endif
-
- HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map;
- for (const auto& child : children_) {
- if (child.fragment->IsLineBox()) {
- const auto& linebox = To<NGPhysicalLineBoxFragment>(*child.fragment);
- const PhysicalOffset linebox_offset = child.offset.ConvertToPhysical(
- GetWritingDirection(), ToPhysicalSize(Size(), GetWritingMode()),
- linebox.Size());
- GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
- &containing_linebox_map,
- linebox, linebox_offset);
- } else if (child.fragment->IsBox()) {
- const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
- bool is_anonymous_container =
- box_fragment.GetLayoutObject() &&
- box_fragment.GetLayoutObject()->IsAnonymousBlock();
- if (!is_anonymous_container)
- continue;
- // If child is an anonymous container, this might be a special case of
- // split inlines. The inline container fragments might be inside
- // anonymous boxes. To find inline container fragments, traverse
- // lineboxes inside anonymous box.
- // For more on this special case, see "css container is an inline, with
- // inline splitting" comment in NGOutOfFlowLayoutPart::LayoutDescendant.
- const PhysicalOffset box_offset = child.offset.ConvertToPhysical(
- GetWritingDirection(), ToPhysicalSize(Size(), GetWritingMode()),
- box_fragment.Size());
-
- // Traverse lineboxes of anonymous box.
- for (const auto& box_child : box_fragment.Children()) {
- if (box_child->IsLineBox()) {
- const auto& linebox = To<NGPhysicalLineBoxFragment>(*box_child);
- const PhysicalOffset linebox_offset = box_child.Offset() + box_offset;
- GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
- &containing_linebox_map,
- linebox, linebox_offset);
- }
- }
- }
- }
-}
-
void NGBoxFragmentBuilder::ComputeInlineContainerGeometry(
InlineContainingBlockMap* inline_containing_block_map) {
if (inline_containing_block_map->IsEmpty())
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 660c535a86a..cff902e2568 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -118,6 +118,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
#if DCHECK_IS_ON()
if (has_block_fragmentation_)
DCHECK(block_size_is_for_all_fragments_);
+ DCHECK(size_.block_size != kIndefiniteSize);
#endif
return size_.block_size;
}
@@ -137,6 +138,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
#if DCHECK_IS_ON()
if (has_block_fragmentation_)
DCHECK(!block_size_is_for_all_fragments_);
+ DCHECK(size_.block_size != kIndefiniteSize);
#endif
return size_.block_size;
}
@@ -201,11 +203,6 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// descendants, propagating fragmentainer breaks, and more.
void AddResult(const NGLayoutResult&, const LogicalOffset);
- void AddChild(scoped_refptr<const NGPhysicalTextFragment> child,
- const LogicalOffset& offset) {
- AddChildInternal(child, offset);
- }
-
void AddChild(const NGPhysicalContainerFragment&,
const LogicalOffset&,
const LayoutInline* inline_container = nullptr,
@@ -267,8 +264,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
return true;
// Inline nodes produce a "finished" trailing break token even if we don't
// need to block-fragment.
- return !inline_break_tokens_.IsEmpty() &&
- !inline_break_tokens_.back()->IsFinished();
+ return last_inline_break_token_.get();
}
// Return true if we need to break before or inside any in-flow child that
@@ -344,7 +340,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
EBreakBetween JoinedBreakBetweenValue(EBreakBetween break_before) const;
// Return the number of line boxes laid out.
- int LineCount() const { return inline_break_tokens_.size(); }
+ int LineCount() const { return line_count_; }
// Set when we have iterated over all the children. This means that all
// children have been fully laid out, or have break tokens. No more children
@@ -486,7 +482,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
table_grid_rect_ = table_grid_rect;
}
- void SetTableColumnGeometry(
+ void SetTableColumnGeometries(
const NGTableFragmentData::ColumnGeometries& table_column_geometries) {
table_column_geometries_ = table_column_geometries;
}
@@ -537,8 +533,6 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// Computes the geometry required for any inline containing blocks.
// |inline_containing_block_map| is a map whose keys specify which inline
// containing block geometry is required.
- void ComputeInlineContainerGeometryFromFragmentTree(
- InlineContainingBlockMap* inline_containing_block_map);
void ComputeInlineContainerGeometry(
InlineContainingBlockMap* inline_containing_block_map);
@@ -594,6 +588,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
bool is_math_fraction_ = false;
bool is_math_operator_ = false;
bool is_at_block_end_ = false;
+ bool has_violating_break_ = false;
LayoutUnit consumed_block_size_;
LayoutUnit block_offset_for_additional_columns_;
unsigned sequence_number_ = 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
index 0bee3136a0b..7ed2aea83c7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.cc
@@ -51,8 +51,6 @@ String NGBreakToken::ToString() const {
string_builder.Append("(");
string_builder.Append(InputNode().ToString());
string_builder.Append(")");
- if (IsFinished())
- string_builder.Append(" finished");
return string_builder.ToString();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
index 8ff0cd622f9..9cea3648102 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_break_token.h
@@ -16,9 +16,8 @@ namespace blink {
// A break token is a continuation token for layout. A single layout input node
// can have multiple fragments asssociated with it.
//
-// Each fragment has a break token which can be used to determine if a layout
-// input node has finished producing fragments (aka. is "exhausted" of
-// fragments), and optionally used to produce the next fragment in the chain.
+// Each fragment whose node needs to resume layout in a future fragmentainer
+// (column, line, etc.) will have a break token associated with it.
//
// See CSS Fragmentation (https://drafts.csswg.org/css-break/) for a detailed
// description of different types of breaks which can occur in CSS.
@@ -28,7 +27,6 @@ namespace blink {
//
// NGLayoutInputNode* node = ...;
// NGPhysicalFragment* fragment = node->Layout(space);
-// DCHECK(!fragment->BreakToken()->IsFinished());
// NGPhysicalFragment* fragment2 = node->Layout(space, fragment->BreakToken());
//
// The break token should encapsulate enough information to "resume" the layout.
@@ -47,11 +45,6 @@ class CORE_EXPORT NGBreakToken : public RefCounted<NGBreakToken> {
bool IsBlockType() const { return Type() == kBlockBreakToken; }
bool IsInlineType() const { return Type() == kInlineBreakToken; }
- enum NGBreakTokenStatus { kUnfinished, kFinished };
-
- // Whether the layout node cannot produce any more fragments.
- bool IsFinished() const { return status_ == kFinished; }
-
// Returns the node associated with this break token. A break token cannot be
// used with any other node.
NGLayoutInputNode InputNode() const {
@@ -70,11 +63,9 @@ class CORE_EXPORT NGBreakToken : public RefCounted<NGBreakToken> {
protected:
NGBreakToken(NGBreakTokenType type,
- NGBreakTokenStatus status,
NGLayoutInputNode node)
: box_(node.GetLayoutBox()),
type_(type),
- status_(status),
flags_(0),
is_break_before_(false),
is_forced_break_(false),
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index 680b9c5bc5a..c616e80ace2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -26,9 +26,11 @@ LayoutUnit CalculateColumnContentBlockSize(
const NGPhysicalContainerFragment& fragment,
WritingDirectionMode writing_direction) {
WritingModeConverter converter(writing_direction, fragment.Size());
- // TODO(mstensho): Once LayoutNG is capable of calculating overflow on its
- // own, we should probably just move over to relying on that machinery,
- // instead of doing all this on our own.
+ // Note that what we're doing here is almost the same as what we do when
+ // calculating overflow, with at least one important difference: If the
+ // inline-size of a fragment is 0, the overflow rectangle becomes empty, even
+ // if the fragment's block-size is non-zero. This is correct for overflow
+ // handling, but it would be wrong for column balancing.
LayoutUnit total_size;
for (const auto& child : fragment.Children()) {
LayoutUnit size = converter.ToLogical(child->Size()).block_size;
@@ -284,7 +286,7 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(),
previously_consumed_block_size + intrinsic_block_size_,
- border_box_size.inline_size);
+ border_box_size.inline_size, Node().ShouldBeConsideredAsReplaced());
container_builder_.SetFragmentsTotalBlockSize(block_size);
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size_);
@@ -297,6 +299,13 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
FinishFragmentation(Node(), ConstraintSpace(), BorderPadding().block_end,
FragmentainerSpaceAtBfcStart(ConstraintSpace()),
&container_builder_);
+
+ // OOF positioned elements inside a nested fragmentation context are laid
+ // out at the outermost context. If this multicol has OOF positioned
+ // elements pending layout, store its node for later use.
+ if (container_builder_.HasOutOfFlowFragmentainerDescendants()) {
+ container_builder_.AddMulticolWithPendingOOFs(Node());
+ }
}
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
@@ -490,22 +499,11 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
column_size.block_size = column_size.block_size.ClampNegativeToZero();
}
- // We balance if block-size is unconstrained, or when we're explicitly told
- // to. Note that the block-size may be constrained by outer fragmentation
- // contexts, not just by a block-size specified on this multicol container.
- bool balance_columns = Style().GetColumnFill() == EColumnFill::kBalance ||
- (column_size.block_size == kIndefiniteSize &&
- !is_constrained_by_outer_fragmentation_context_);
-
- if (balance_columns) {
- column_size.block_size =
- CalculateBalancedColumnBlockSize(column_size, next_column_token);
- }
-
- bool needs_more_fragments_in_outer = false;
+ bool may_resume_in_next_outer_fragmentainer = false;
bool zero_outer_space_left = false;
+ LayoutUnit available_outer_space = kIndefiniteSize;
if (is_constrained_by_outer_fragmentation_context_) {
- LayoutUnit available_outer_space =
+ available_outer_space =
FragmentainerSpaceAtBfcStart(ConstraintSpace()) - intrinsic_block_size_;
if (available_outer_space <= LayoutUnit()) {
@@ -521,17 +519,34 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
zero_outer_space_left = true;
}
- // Check if we can fit everything (that's remaining), block-wise, within the
- // current outer fragmentainer. If we can't, we need to adjust the block
- // size, and allow the multicol container to continue in a subsequent outer
- // fragmentainer. Note that we also need to handle indefinite block-size,
- // because that may happen in a nested multicol container with auto
- // block-size and column balancing disabled.
+ // Determine if we should resume layout in the next outer fragmentation
+ // context if we run out of space in the current one. This is always the
+ // thing to do except when block-size is non-auto and short enough to fit in
+ // the current outer fragmentainer. In such cases we'll allow inner columns
+ // to overflow its outer fragmentainer (since the inner multicol is too
+ // short to reach the outer fragmentation line).
+ if (column_size.block_size == kIndefiniteSize ||
+ column_size.block_size > available_outer_space)
+ may_resume_in_next_outer_fragmentainer = true;
+ }
+
+ // We balance if block-size is unconstrained, or when we're explicitly told
+ // to. Note that the block-size may be constrained by outer fragmentation
+ // contexts, not just by a block-size specified on this multicol container.
+ bool balance_columns = Style().GetColumnFill() == EColumnFill::kBalance ||
+ (column_size.block_size == kIndefiniteSize &&
+ !is_constrained_by_outer_fragmentation_context_);
+
+ if (balance_columns) {
+ column_size.block_size =
+ CalculateBalancedColumnBlockSize(column_size, next_column_token);
+ } else if (available_outer_space != kIndefiniteSize) {
+ // Finally, resolve any remaining auto block-size, and make sure that we
+ // don't take up more space than there's room for in the outer fragmentation
+ // context.
if (column_size.block_size > available_outer_space ||
- column_size.block_size == kIndefiniteSize) {
+ column_size.block_size == kIndefiniteSize)
column_size.block_size = available_outer_space;
- needs_more_fragments_in_outer = true;
- }
}
DCHECK_GE(column_size.block_size, LayoutUnit());
@@ -563,6 +578,7 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
bool allow_discard_start_margin =
column_break_token && !column_break_token->IsCausedByColumnSpanner();
+ bool has_violating_break = false;
LayoutUnit column_inline_offset(BorderScrollbarPadding().inline_start);
int actual_column_count = 0;
@@ -603,6 +619,7 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
if (result->HasForcedBreak())
forced_break_count++;
+ has_violating_break |= result->HasViolatingBreak();
column_inline_offset += column_inline_progression_;
if (result->ColumnSpanner())
@@ -621,7 +638,7 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
// multicol container fits block-wise in the current outer fragmentainer.
if (ConstraintSpace().HasBlockFragmentation() && column_break_token &&
actual_column_count >= used_column_count_ &&
- needs_more_fragments_in_outer) {
+ may_resume_in_next_outer_fragmentainer) {
// We cannot keep any of this if we have zero space left. Then we need
// to resume in the next outer fragmentainer.
if (zero_outer_space_left)
@@ -634,10 +651,6 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
allow_discard_start_margin = true;
} while (column_break_token);
- // TODO(mstensho): Nested column balancing.
- if (container_builder_.DidBreakSelf())
- break;
-
if (!balance_columns) {
if (result->ColumnSpanner()) {
// We always have to balance columns preceding a spanner, so if we
@@ -657,12 +670,16 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
// We're balancing columns. Check if the column block-size that we laid out
// with was satisfactory. If not, stretch and retry, if possible.
//
- // If we overflowed (actual column count larger than what we have room for),
- // see if we're able to stretch them. We can only stretch the columns if we
- // have at least one column that could take more content.
- //
- // If we didn't exceed used column-count, we're done.
- if (actual_column_count <= used_column_count_)
+ // If we didn't break at any undesirable location and actual column count
+ // wasn't larger than what we have room for, we're done IF we're also out of
+ // content (no break token; in nested multicol situations there are cases
+ // where we only allow as many columns as we have room for, as additional
+ // columns normally need to continue in the next outer fragmentainer). If we
+ // have made the columns tall enough to bump into a spanner, it also means
+ // we need to stop to lay out the spanner(s), and resume column layout
+ // afterwards.
+ if (!has_violating_break && actual_column_count <= used_column_count_ &&
+ (!column_break_token || result->ColumnSpanner()))
break;
// We're in a situation where we'd like to stretch the columns, but then we
@@ -676,23 +693,22 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
if (actual_column_count <= forced_break_count + 1)
break;
- // TODO(mstensho): Handle this situation also when we're inside another
- // balanced multicol container, rather than bailing (which we do now, to
- // avoid infinite loops). If we exhaust the inner column-count in such
- // cases, that piece of information may have to be propagated to the outer
- // multicol, and instead stretch there (not here). We have no such mechanism
- // in place yet.
- if (ConstraintSpace().IsInsideBalancedColumns())
- break;
-
LayoutUnit new_column_block_size =
StretchColumnBlockSize(minimal_space_shortage, column_size.block_size);
// Give up if we cannot get taller columns. The multicol container may have
// a specified block-size preventing taller columns, for instance.
DCHECK_GE(new_column_block_size, column_size.block_size);
- if (new_column_block_size <= column_size.block_size)
+ if (new_column_block_size <= column_size.block_size) {
+ if (ConstraintSpace().IsInsideBalancedColumns()) {
+ // If we're doing nested column balancing, propagate any space shortage
+ // to the outer multicol container, so that the outer multicol container
+ // can attempt to stretch, so that this inner one may fit as well.
+ if (!container_builder_.IsInitialColumnBalancingPass())
+ container_builder_.PropagateSpaceShortage(minimal_space_shortage);
+ }
break;
+ }
// Remove column fragments and re-attempt layout with taller columns.
new_columns.clear();
@@ -910,7 +926,7 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
// First split into content runs at explicit (forced) breaks.
ContentRuns content_runs;
scoped_refptr<const NGBlockBreakToken> break_token = child_break_token;
- LayoutUnit tallest_unbreakable_block_size;
+ tallest_unbreakable_block_size_ = LayoutUnit();
do {
NGBlockLayoutAlgorithm balancing_algorithm(
{Node(), fragment_geometry, space, break_token.get()});
@@ -924,10 +940,30 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
To<NGPhysicalBoxFragment>(result->PhysicalFragment());
LayoutUnit column_block_size =
CalculateColumnContentBlockSize(fragment, space.GetWritingDirection());
+
+ // Encompass the block-size of the (single-strip column) fragment, to
+ // account for any trailing margins. We let them affect the column
+ // block-size, for compatibility reasons, if nothing else. The initial
+ // column balancing pass (i.e. here) is our opportunity to do that fairly
+ // easily. But note that this doesn't guarantee that no margins will ever
+ // get truncated. To avoid that we'd need to add some sort of mechanism that
+ // is invoked in *every* column balancing layout pass, where we'd
+ // essentially have to treat every margin as unbreakable (which kind of
+ // sounds both bad and difficult).
+ //
+ // We might want to revisit this approach, if it's worth it: Maybe it's
+ // better to not make any room at all for margins that might end up getting
+ // truncated. After all, they don't really require any space, so what we're
+ // doing currently might be seen as unnecessary (and slightly unpredictable)
+ // column over-stretching.
+ NGFragment logical_fragment(ConstraintSpace().GetWritingDirection(),
+ fragment);
+ column_block_size =
+ std::max(column_block_size, logical_fragment.BlockSize());
content_runs.emplace_back(column_block_size);
- tallest_unbreakable_block_size = std::max(
- tallest_unbreakable_block_size, result->TallestUnbreakableBlockSize());
+ tallest_unbreakable_block_size_ = std::max(
+ tallest_unbreakable_block_size_, result->TallestUnbreakableBlockSize());
// Stop when we reach a spanner. That's where this row of columns will end.
if (result->ColumnSpanner())
@@ -952,7 +988,7 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
// initial balancing pass, so it also wants to know the largest unbreakable
// block-size.
container_builder_.PropagateTallestUnbreakableBlockSize(
- tallest_unbreakable_block_size);
+ tallest_unbreakable_block_size_);
}
// We now have an estimated minimal block-size for the columns. Roughly
@@ -961,12 +997,10 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
// though, since there will typically be unbreakable pieces of content, such
// as replaced content, lines of text, and other things. We need to actually
// lay out into columns to figure out if they are tall enough or not (and
- // stretch and retry if not). Also honor {,min-,max-}{height,width} properties
- // before returning.
- LayoutUnit block_size = std::max(content_runs.TallestColumnBlockSize(),
- tallest_unbreakable_block_size);
-
- return ConstrainColumnBlockSize(block_size);
+ // stretch and retry if not). Also honor {,min-,max-}block-size properties
+ // before returning, and also try to not become shorter than the tallest piece
+ // of unbreakable content.
+ return ConstrainColumnBlockSize(content_runs.TallestColumnBlockSize());
}
LayoutUnit NGColumnLayoutAlgorithm::StretchColumnBlockSize(
@@ -981,14 +1015,25 @@ LayoutUnit NGColumnLayoutAlgorithm::StretchColumnBlockSize(
// container.
LayoutUnit NGColumnLayoutAlgorithm::ConstrainColumnBlockSize(
LayoutUnit size) const {
- // The {,max-}{height,width} properties are specified on the multicol
+ if (is_constrained_by_outer_fragmentation_context_) {
+ // Don't become too tall to fit in the outer fragmentation context.
+ LayoutUnit available_outer_space =
+ FragmentainerSpaceAtBfcStart(ConstraintSpace()) - intrinsic_block_size_;
+ DCHECK_GE(available_outer_space, LayoutUnit());
+ size = std::min(size, available_outer_space);
+ }
+
+ // But avoid becoming shorter than the tallest piece of unbreakable content.
+ size = std::max(size, tallest_unbreakable_block_size_);
+
+ // The {,min-,max-}block-size properties are specified on the multicol
// container, but here we're calculating the column block sizes inside the
// multicol container, which isn't exactly the same. We may shrink the column
- // block size here, but we'll never stretch it, because the value passed is
+ // block size here, but we'll never stretch them, because the value passed is
// the perfect balanced block size. Making it taller would only disrupt the
// balanced output, for no reason. The only thing we need to worry about here
// is to not overflow the multicol container.
-
+ //
// First of all we need to convert the size to a value that can be compared
// against the resolved properties on the multicol container. That means that
// we have to convert the value from content-box to border-box.
@@ -997,16 +1042,21 @@ LayoutUnit NGColumnLayoutAlgorithm::ConstrainColumnBlockSize(
const ComputedStyle& style = Style();
LayoutUnit max = ResolveMaxBlockLength(
- ConstraintSpace(), style, BorderPadding(), style.LogicalMaxHeight(),
- LengthResolvePhase::kLayout);
- LayoutUnit extent = ResolveMainBlockLength(
- ConstraintSpace(), style, BorderPadding(), style.LogicalHeight(),
- kIndefiniteSize, LengthResolvePhase::kLayout);
- if (extent != kIndefiniteSize) {
- // A specified height/width will just constrain the maximum length.
- max = std::min(max, extent);
+ ConstraintSpace(), style, BorderPadding(), style.LogicalMaxHeight());
+ LayoutUnit extent = kIndefiniteSize;
+ if (!style.LogicalHeight().IsAuto()) {
+ extent = ResolveMainBlockLength(ConstraintSpace(), style, BorderPadding(),
+ style.LogicalHeight(), kIndefiniteSize);
+ // A specified block-size will just constrain the maximum length.
+ if (extent != kIndefiniteSize)
+ max = std::min(max, extent);
}
+ // A specified min-block-size may increase the maximum length.
+ LayoutUnit min = ResolveMinBlockLength(
+ ConstraintSpace(), style, BorderPadding(), style.LogicalMinHeight());
+ max = std::max(max, min);
+
// If this multicol container is nested inside another fragmentation
// context, we need to subtract the space consumed in previous fragments.
if (BreakToken())
@@ -1046,6 +1096,7 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForBalancing(
ConstraintSpace(), Style().GetWritingDirection(), /* is_new_fc */ true);
space_builder.SetFragmentationType(kFragmentColumn);
space_builder.SetAvailableSize({column_size.inline_size, kIndefiniteSize});
+ space_builder.SetStretchInlineSizeIfAuto(true);
space_builder.SetPercentageResolutionSize(ColumnPercentageResolutionSize());
space_builder.SetIsAnonymous(true);
space_builder.SetIsInColumnBfc();
@@ -1060,9 +1111,9 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForSpanner(
NGConstraintSpaceBuilder space_builder(
ConstraintSpace(), Style().GetWritingDirection(), /* is_new_fc */ true);
space_builder.SetAvailableSize(ChildAvailableSize());
+ space_builder.SetStretchInlineSizeIfAuto(true);
space_builder.SetPercentageResolutionSize(ChildAvailableSize());
- space_builder.SetNeedsBaseline(ConstraintSpace().NeedsBaseline());
space_builder.SetBaselineAlgorithmType(
ConstraintSpace().BaselineAlgorithmType());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index 116963ed3e1..10521632669 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -100,6 +100,7 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
LayoutUnit column_inline_progression_;
LayoutUnit column_block_size_;
LayoutUnit intrinsic_block_size_;
+ LayoutUnit tallest_unbreakable_block_size_;
bool is_constrained_by_outer_fragmentation_context_ = false;
// This will be set during (outer) block fragmentation once we've processed
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index f1dea0c48ca..f8f45dee232 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -21,11 +21,6 @@ class NGColumnLayoutAlgorithmTest
NGColumnLayoutAlgorithmTest()
: ScopedLayoutNGBlockFragmentationForTest(true) {}
- void SetUp() override {
- NGBaseLayoutAlgorithmTest::SetUp();
- style_ = ComputedStyle::Create();
- }
-
scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
Element* element) {
NGBlockNode container(element->GetLayoutBox());
@@ -48,8 +43,6 @@ class NGColumnLayoutAlgorithmTest
auto fragment = RunBlockLayoutAlgorithm(element);
return DumpFragmentTree(fragment.get());
}
-
- scoped_refptr<ComputedStyle> style_;
};
TEST_F(NGColumnLayoutAlgorithmTest, EmptyMulticol) {
@@ -367,7 +360,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ZeroHeight) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x0
offset:0,0 size:320x0
- offset:0,0 size:100x1
+ offset:0,0 size:100x0
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -394,15 +387,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, ZeroHeightWithContent) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x0
offset:0,0 size:320x0
- offset:0,0 size:100x1
+ offset:0,0 size:100x0
offset:0,0 size:20x1
- offset:110,0 size:100x1
+ offset:110,0 size:100x0
offset:0,0 size:20x1
- offset:220,0 size:100x1
+ offset:220,0 size:100x0
offset:0,0 size:20x1
- offset:330,0 size:100x1
+ offset:330,0 size:100x0
offset:0,0 size:20x1
- offset:440,0 size:100x1
+ offset:440,0 size:100x0
offset:0,0 size:20x1
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -3049,7 +3042,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingEmpty) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x0
offset:0,0 size:320x0
- offset:0,0 size:100x1
+ offset:0,0 size:100x0
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3074,7 +3067,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingEmptyBlock) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x0
offset:0,0 size:320x0
- offset:0,0 size:100x1
+ offset:0,0 size:100x0
offset:0,0 size:20x0
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -3165,7 +3158,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLineInNestedSpanner) {
offset:0,0 size:320x20
offset:0,0 size:100x20
offset:0,0 size:100x20
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:100x20
offset:0,0 size:0x20
)DUMP";
@@ -4223,7 +4216,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, NestedZeroHeightAtOuterBoundary) {
offset:0,0 size:100x100
offset:0,0 size:11x100
offset:0,100 size:100x0
- offset:0,0 size:45x1
+ offset:0,0 size:45x0
offset:0,0 size:22x0
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -4317,7 +4310,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, NestedWithTallSpanner) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:45x1
+ offset:0,0 size:45x0
offset:0,0 size:22x100
offset:110,0 size:100x100
offset:0,0 size:100x35
@@ -4605,7 +4598,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerAtStart) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x86
offset:0,0 size:322x86
- offset:1,1 size:100x1
+ offset:1,1 size:100x0
offset:1,1 size:320x44
offset:1,45 size:100x40
offset:0,0 size:100x20
@@ -4680,7 +4673,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerAlone) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x46
offset:0,0 size:322x46
- offset:1,1 size:100x1
+ offset:1,1 size:100x0
offset:1,1 size:320x44
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -4712,10 +4705,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerInBlock) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x46
offset:0,0 size:322x46
- offset:1,1 size:100x1
+ offset:1,1 size:100x0
offset:0,0 size:11x0
offset:1,1 size:320x44
- offset:1,45 size:100x1
+ offset:1,45 size:100x0
offset:0,0 size:11x0
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -4749,7 +4742,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerWithSiblingsInBlock) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x86
offset:0,0 size:322x86
- offset:1,1 size:100x1
+ offset:1,1 size:100x0
offset:0,0 size:11x0
offset:1,1 size:320x44
offset:1,45 size:100x40
@@ -4792,7 +4785,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerInBlockWithSiblings) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x86
offset:0,0 size:322x86
- offset:1,1 size:100x1
+ offset:1,1 size:100x0
offset:0,0 size:11x0
offset:1,1 size:320x44
offset:1,45 size:100x40
@@ -4831,7 +4824,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerMargins) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x130
offset:0,0 size:320x130
- offset:0,0 size:100x1
+ offset:0,0 size:100x0
offset:10,10 size:33x10
offset:0,30 size:100x20
offset:0,0 size:100x20
@@ -4868,7 +4861,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerMarginsRtl) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x130
offset:0,0 size:320x130
- offset:220,0 size:100x1
+ offset:220,0 size:100x0
offset:277,10 size:33x10
offset:220,30 size:100x20
offset:0,0 size:100x20
@@ -4987,7 +4980,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideSpannerWithMargins) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,10 size:33x90
offset:110,0 size:100x100
offset:0,0 size:100x40
@@ -5213,7 +5206,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:110,0 size:100x100
offset:0,0 size:100x40
@@ -5246,7 +5239,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners2) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:110,0 size:100x100
offset:0,0 size:100x40
@@ -5283,7 +5276,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners3) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:0,0 size:33x10
offset:0,10 size:44x10
@@ -5322,7 +5315,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners4) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:110,0 size:100x100
offset:0,0 size:100x40
@@ -5358,7 +5351,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners5) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:110,0 size:100x100
offset:0,0 size:100x50
@@ -5392,7 +5385,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x60
offset:110,0 size:100x100
offset:0,0 size:100x60
@@ -5427,7 +5420,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners2) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x60
offset:110,0 size:100x100
offset:0,0 size:100x60
@@ -5463,7 +5456,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:55x40
offset:110,0 size:100x100
offset:0,0 size:100x100
@@ -5504,7 +5497,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners2) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:11x100
offset:0,0 size:22x20
offset:0,20 size:33x20
@@ -5554,7 +5547,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners3) {
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
- offset:0,0 size:50x1
+ offset:0,0 size:50x0
offset:0,0 size:11x100
offset:0,0 size:0x20
offset:0,20 size:0x20
@@ -5645,7 +5638,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, SpannerAsMulticol) {
offset:0,0 size:320x50
offset:0,0 size:100x50
offset:0,0 size:100x50
- offset:0,0 size:45x1
+ offset:0,0 size:45x0
offset:0,0 size:100x50
offset:0,0 size:45x50
offset:0,0 size:131x20
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 5acde7966a8..84d94b3bf99 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -63,7 +63,7 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
// The flexbox-specific behavior is in addition to regular definite-ness, so
// if the flex item would normally have a definite height it should keep it.
fixed_block_is_definite =
- ToLayoutFlexibleBox(block.Parent())
+ To<LayoutFlexibleBox>(block.Parent())
->UseOverrideLogicalHeightForPerentageResolution(block) ||
block.HasDefiniteLogicalHeight();
}
@@ -79,7 +79,6 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
if (!block.IsWritingModeRoot() || block.IsGridItem()) {
// We don't know if the parent layout will require our baseline, so always
// request it.
- builder.SetNeedsBaseline(true);
builder.SetBaselineAlgorithmType(block.IsInline() &&
block.IsAtomicInlineLevel()
? NGBaselineAlgorithmType::kInlineBlock
@@ -98,7 +97,7 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
!cell_style.LogicalHeight().IsAuto() ||
!table_style.LogicalHeight().IsAuto());
const LayoutBlock& cell_block = To<LayoutBlock>(*cell.ToLayoutObject());
- if (RuntimeEnabledFeatures::TableCellNewPercentsEnabled() && fixed_block) {
+ if (fixed_block) {
fixed_block_is_definite = cell_block.HasDefiniteLogicalHeight() ||
!table_style.LogicalHeight().IsAuto();
}
@@ -125,9 +124,8 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
builder.SetIsFixedInlineSize(fixed_inline);
builder.SetIsFixedBlockSize(fixed_block);
builder.SetIsFixedBlockSizeIndefinite(!fixed_block_is_definite);
- builder.SetIsShrinkToFit(
- style.LogicalWidth().IsAuto() &&
- block.SizesLogicalWidthToFitContent(style.LogicalWidth()));
+ builder.SetStretchInlineSizeIfAuto(
+ !block.SizesLogicalWidthToFitContent(style.LogicalWidth()));
return builder.ToConstraintSpace();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 59abe0ba4f8..64701ed5382 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -96,9 +96,8 @@ class CORE_EXPORT NGConstraintSpace final {
kRareDataPercentage
};
- // To ensure that the bfc_offset_, rare_data_ union doesn't get polluted,
- // always initialize the bfc_offset_.
- NGConstraintSpace() : bfc_offset_() {}
+ NGConstraintSpace()
+ : NGConstraintSpace({WritingMode::kHorizontalTb, TextDirection::kLtr}) {}
NGConstraintSpace(const NGConstraintSpace& other)
: available_size_(other.available_size_),
@@ -337,6 +336,15 @@ class CORE_EXPORT NGConstraintSpace final {
return HasRareData() ? rare_data_->TableSectionIndex() : kNotFound;
}
+ // If we're block-fragmented AND the fragmentainer block-size is known, return
+ // the total block-size of the fragmentainer that is to be created. This value
+ // is inherited by descendant constraint spaces, as long as we don't enter
+ // anything monolithic, or establish a nested fragmentation context. Note that
+ // the value returned here is the actual size that will be set on the physical
+ // fragment representing the fragmentainer, and 0 is an allowed value, even if
+ // the fragmentation spec requires us to fit at least 1px of content in each
+ // fragmentainer. See the utility function FragmentainerCapacity() for more
+ // details.
LayoutUnit FragmentainerBlockSize() const {
return HasRareData() ? rare_data_->fragmentainer_block_size
: kIndefiniteSize;
@@ -412,12 +420,6 @@ class CORE_EXPORT NGConstraintSpace final {
return bitfields_.ancestor_has_clearance_past_adjoining_floats;
}
- // Returns if the parent layout needs the baseline from this layout.
- //
- // This bit is only used for skipping querying baseline information from
- // legacy layout.
- bool NeedsBaseline() const { return bitfields_.needs_baseline; }
-
// How the baseline for the fragment should be calculated, see documentation
// for |NGBaselineAlgorithmType|.
NGBaselineAlgorithmType BaselineAlgorithmType() const {
@@ -441,14 +443,30 @@ class CORE_EXPORT NGConstraintSpace final {
bool IsFixedBlockSize() const { return bitfields_.is_fixed_block_size; }
- // Whether a fixed block-size should be considered indefinite.
+ // Whether the block size should be considered indefinite.
+ // The constraint space can have any of the combinations:
+ // (1) !IsFixedBlockSize && !IsFixedBlockSizeIndefinite -- default. no special
+ // handling needed.
+ // (2) !IsFixedBlockSize && IsFixedBlockSizeIndefinite -- Treat your height as
+ // indefinite.
+ // (3) IsFixedBlockSize && !IsFixedBlockSizeIndefinite -- You must be this
+ // size and your children can resolve % block size against it.
+ // (4) IsFixedBlockSize && IsFixedBlockSizeIndefinite -- You must be this
+ // size but your children canNOT resolve % block size against it.
+ // TODO(dgrogan): This method needs a new name now that #2 above exists.
+ // Either IsBlockSizeIndefinite or ForceBlockSizeToIndefinite.
bool IsFixedBlockSizeIndefinite() const {
return bitfields_.is_fixed_block_size_indefinite;
}
- // Whether an auto inline-size should be interpreted as shrink-to-fit
- // (ie. fit-content). This is used for inline-block, floats, etc.
- bool IsShrinkToFit() const { return bitfields_.is_shrink_to_fit; }
+ // Return true if the respective size property when 'auto' should stretch to
+ // consume the available space. If false, it behaves as "shrink-to-fit".
+ bool StretchInlineSizeIfAuto() const {
+ return bitfields_.stretch_inline_size_if_auto;
+ }
+ bool StretchBlockSizeIfAuto() const {
+ return bitfields_.stretch_block_size_if_auto;
+ }
bool IsPaintedAtomically() const { return bitfields_.is_painted_atomically; }
@@ -636,10 +654,17 @@ class CORE_EXPORT NGConstraintSpace final {
return other.rare_data_->IsInitialForMaySkipLayout();
}
- // Returns true if the size constraints (shrink-to-fit, fixed-inline-size)
- // are equal.
- bool AreSizeConstraintsEqual(const NGConstraintSpace& other) const {
- return bitfields_.AreSizeConstraintsEqual(other.bitfields_);
+ // Returns true if the size constraints (stretch-block-size,
+ // fixed-inline-size) are equal.
+ bool AreInlineSizeConstraintsEqual(const NGConstraintSpace& other) const {
+ return bitfields_.AreInlineSizeConstraintsEqual(other.bitfields_);
+ }
+ bool AreBlockSizeConstraintsEqual(const NGConstraintSpace& other) const {
+ if (!bitfields_.AreBlockSizeConstraintsEqual(other.bitfields_))
+ return false;
+ if (!HasRareData() && !other.HasRareData())
+ return true;
+ return TableCellAlignmentBaseline() == other.TableCellAlignmentBaseline();
}
bool AreSizesEqual(const NGConstraintSpace& other) const {
@@ -685,10 +710,10 @@ class CORE_EXPORT NGConstraintSpace final {
return true;
}
- void ReplaceTableConstraintSpaceData(
- const NGTableConstraintSpaceData& table_data) {
+ void ReplaceTableRowData(const NGTableConstraintSpaceData& table_data,
+ const wtf_size_t row_index) {
DCHECK(HasRareData());
- rare_data_->ReplaceTableConstraintSpaceData(table_data);
+ rare_data_->ReplaceTableRowData(table_data, row_index);
}
String ToString() const;
@@ -1004,30 +1029,33 @@ class CORE_EXPORT NGConstraintSpace final {
EnsureTableSectionData()->section_index = section_index;
}
- void ReplaceTableConstraintSpaceData(
- const NGTableConstraintSpaceData& table_data) {
+ void ReplaceTableRowData(const NGTableConstraintSpaceData& table_data,
+ wtf_size_t row_index) {
DCHECK_EQ(data_union_type, kTableRowData);
- DCHECK(table_data.IsTableSpecificDataEqual(
- *(EnsureTableRowData()->table_data)));
- EnsureTableRowData()->table_data = &table_data;
+ DCHECK(
+ table_data.IsTableSpecificDataEqual(*(table_row_data_.table_data)));
+ DCHECK(table_data.MaySkipRowLayout(*table_row_data_.table_data, row_index,
+ table_row_data_.row_index));
+ table_row_data_.table_data = &table_data;
+ table_row_data_.row_index = row_index;
}
const NGTableConstraintSpaceData* TableData() {
if (data_union_type == kTableRowData)
- return EnsureTableRowData()->table_data.get();
+ return table_row_data_.table_data.get();
if (data_union_type == kTableSectionData)
- return EnsureTableSectionData()->table_data.get();
+ return table_section_data_.table_data.get();
return nullptr;
}
- wtf_size_t TableRowIndex() {
- return data_union_type == kTableRowData ? EnsureTableRowData()->row_index
+ wtf_size_t TableRowIndex() const {
+ return data_union_type == kTableRowData ? table_row_data_.row_index
: kNotFound;
}
- wtf_size_t TableSectionIndex() {
+ wtf_size_t TableSectionIndex() const {
return data_union_type == kTableSectionData
- ? EnsureTableSectionData()->section_index
+ ? table_section_data_.section_index
: kNotFound;
}
@@ -1141,7 +1169,8 @@ class CORE_EXPORT NGConstraintSpace final {
struct TableRowData {
bool MaySkipLayout(const TableRowData& other) const {
return table_data->IsTableSpecificDataEqual(*other.table_data) &&
- table_data->MaySkipRowLayout(*other.table_data, row_index);
+ table_data->MaySkipRowLayout(*other.table_data, row_index,
+ other.row_index);
}
bool IsInitialForMaySkipLayout() const {
return !table_data && row_index == kNotFound;
@@ -1154,8 +1183,8 @@ class CORE_EXPORT NGConstraintSpace final {
struct TableSectionData {
bool MaySkipLayout(const TableSectionData& other) const {
return table_data->IsTableSpecificDataEqual(*other.table_data) &&
- table_data->MaySkipSectionLayout(*other.table_data,
- section_index);
+ table_data->MaySkipSectionLayout(
+ *other.table_data, section_index, other.section_index);
}
bool IsInitialForMaySkipLayout() const {
return !table_data && section_index == kNotFound;
@@ -1282,11 +1311,11 @@ class CORE_EXPORT NGConstraintSpace final {
is_painted_atomically(false),
use_first_line_style(false),
ancestor_has_clearance_past_adjoining_floats(false),
- needs_baseline(false),
baseline_algorithm_type(
static_cast<unsigned>(NGBaselineAlgorithmType::kFirstLine)),
cache_slot(static_cast<unsigned>(NGCacheSlot::kLayout)),
- is_shrink_to_fit(false),
+ stretch_inline_size_if_auto(false),
+ stretch_block_size_if_auto(false),
is_fixed_inline_size(false),
is_fixed_block_size(false),
is_fixed_block_size_indefinite(false),
@@ -1311,13 +1340,15 @@ class CORE_EXPORT NGConstraintSpace final {
use_first_line_style == other.use_first_line_style &&
ancestor_has_clearance_past_adjoining_floats ==
other.ancestor_has_clearance_past_adjoining_floats &&
- needs_baseline == other.needs_baseline &&
baseline_algorithm_type == other.baseline_algorithm_type;
}
- bool AreSizeConstraintsEqual(const Bitfields& other) const {
- return is_shrink_to_fit == other.is_shrink_to_fit &&
- is_fixed_inline_size == other.is_fixed_inline_size &&
+ bool AreInlineSizeConstraintsEqual(const Bitfields& other) const {
+ return stretch_inline_size_if_auto == other.stretch_inline_size_if_auto &&
+ is_fixed_inline_size == other.is_fixed_inline_size;
+ }
+ bool AreBlockSizeConstraintsEqual(const Bitfields& other) const {
+ return stretch_block_size_if_auto == other.stretch_block_size_if_auto &&
is_fixed_block_size == other.is_fixed_block_size &&
is_fixed_block_size_indefinite ==
other.is_fixed_block_size_indefinite &&
@@ -1341,13 +1372,13 @@ class CORE_EXPORT NGConstraintSpace final {
unsigned use_first_line_style : 1;
unsigned ancestor_has_clearance_past_adjoining_floats : 1;
- unsigned needs_baseline : 1;
unsigned baseline_algorithm_type : 1;
unsigned cache_slot : 1;
// Size constraints.
- unsigned is_shrink_to_fit : 1;
+ unsigned stretch_inline_size_if_auto : 1;
+ unsigned stretch_block_size_if_auto : 1;
unsigned is_fixed_inline_size : 1;
unsigned is_fixed_block_size : 1;
unsigned is_fixed_block_size_indefinite : 1;
@@ -1358,8 +1389,12 @@ class CORE_EXPORT NGConstraintSpace final {
unsigned replaced_percentage_block_storage : 2; // NGPercentageStorage
};
+ // To ensure that the bfc_offset_, rare_data_ union doesn't get polluted,
+ // always initialize the bfc_offset_.
explicit NGConstraintSpace(WritingDirectionMode writing_direction)
- : bfc_offset_(), bitfields_(writing_direction) {}
+ : available_size_(kIndefiniteSize, kIndefiniteSize),
+ bfc_offset_(),
+ bitfields_(writing_direction) {}
inline bool HasRareData() const { return bitfields_.has_rare_data; }
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index bb175d6c6c5..818ed92a98f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -140,7 +140,19 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
space_.bitfields_.is_fixed_block_size_indefinite = b;
}
- void SetIsShrinkToFit(bool b) { space_.bitfields_.is_shrink_to_fit = b; }
+ void SetStretchInlineSizeIfAuto(bool b) {
+ if (LIKELY(is_in_parallel_flow_))
+ space_.bitfields_.stretch_inline_size_if_auto = b;
+ else
+ space_.bitfields_.stretch_block_size_if_auto = b;
+ }
+
+ void SetStretchBlockSizeIfAuto(bool b) {
+ if (LIKELY(is_in_parallel_flow_))
+ space_.bitfields_.stretch_block_size_if_auto = b;
+ else
+ space_.bitfields_.stretch_inline_size_if_auto = b;
+ }
void SetIsPaintedAtomically(bool b) {
space_.bitfields_.is_painted_atomically = b;
@@ -205,8 +217,6 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
space_.bitfields_.ancestor_has_clearance_past_adjoining_floats = true;
}
- void SetNeedsBaseline(bool b) { space_.bitfields_.needs_baseline = b; }
-
void SetBaselineAlgorithmType(NGBaselineAlgorithmType type) {
space_.bitfields_.baseline_algorithm_type = static_cast<unsigned>(type);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 208e74fa630..2bb3a983115 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -61,37 +61,7 @@ void NGContainerFragmentBuilder::PropagateChildData(
new_inline_container);
}
- if (const NGPhysicalBoxFragment* fragment =
- DynamicTo<NGPhysicalBoxFragment>(&child)) {
- if (fragment->HasOutOfFlowPositionedFragmentainerDescendants()) {
- const auto& out_of_flow_fragmentainer_descendants =
- fragment->OutOfFlowPositionedFragmentainerDescendants();
- const WritingModeConverter empty_outer_size(GetWritingDirection(),
- PhysicalSize());
- for (const auto& descendant : out_of_flow_fragmentainer_descendants) {
- const NGPhysicalContainerFragment* containing_block_fragment =
- descendant.containing_block_fragment.get();
- if (!containing_block_fragment)
- containing_block_fragment = fragment;
-
- LogicalOffset containing_block_offset = converter.ToLogical(
- descendant.containing_block_offset, PhysicalSize());
- if (!child.IsFragmentainerBox())
- containing_block_offset.block_offset += child_offset.block_offset;
- if (IsBlockFragmentationContextRoot()) {
- containing_block_offset.block_offset +=
- fragmentainer_consumed_block_size_;
- }
-
- NGLogicalStaticPosition static_position =
- descendant.static_position.ConvertToLogical(empty_outer_size);
- oof_positioned_fragmentainer_descendants_.emplace_back(
- descendant.node, static_position, descendant.inline_container,
- /* needs_block_offset_adjustment */ false, containing_block_offset,
- containing_block_fragment);
- }
- }
- }
+ PropagateOOFPositionedInfo(child, child_offset);
// We only need to report if inflow or floating elements depend on the
// percentage resolution block-size. OOF-positioned children resolve their
@@ -142,22 +112,20 @@ void NGContainerFragmentBuilder::PropagateChildData(
// as they should only escape a fragmentation context at the discretion of the
// fragmentation context.
if (has_block_fragmentation_ && !child.IsFragmentainerBox()) {
- if (const NGBreakToken* child_break_token = child.BreakToken()) {
- switch (child.Type()) {
- case NGPhysicalFragment::kFragmentBox:
+ const NGBreakToken* child_break_token = child.BreakToken();
+ switch (child.Type()) {
+ case NGPhysicalFragment::kFragmentBox:
+ if (child_break_token)
child_break_tokens_.push_back(child_break_token);
- break;
- case NGPhysicalFragment::kFragmentLineBox:
- // NGInlineNode produces multiple line boxes in an anonymous box. We
- // won't know up front which line box to insert a fragment break
- // before (due to widows), so keep them all until we know.
- inline_break_tokens_.push_back(child_break_token);
- break;
- case NGPhysicalFragment::kFragmentText:
- default:
- NOTREACHED();
- break;
- }
+ break;
+ case NGPhysicalFragment::kFragmentLineBox:
+ // We only care about the break token from the last line box added. This
+ // is where we'll resume if we decide to block-fragment. Note that
+ // child_break_token is nullptr if this is the last line to be generated
+ // from the node.
+ last_inline_break_token_ = To<NGInlineBreakToken>(child_break_token);
+ line_count_++;
+ break;
}
}
@@ -200,7 +168,8 @@ void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
const LogicalOffset& child_offset,
NGLogicalStaticPosition::InlineEdge inline_edge,
NGLogicalStaticPosition::BlockEdge block_edge,
- bool needs_block_offset_adjustment) {
+ bool needs_block_offset_adjustment,
+ const base::Optional<LogicalRect> containing_block_rect) {
DCHECK(child);
// If an OOF-positioned candidate has a static-position which uses a
@@ -213,7 +182,9 @@ void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
oof_positioned_candidates_.emplace_back(
child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
- /* inline_container */ nullptr, needs_block_offset_adjustment);
+ /* inline_container */ nullptr, needs_block_offset_adjustment,
+ /* containing_block_offset */ LogicalOffset(),
+ /* containing_block_fragment */ nullptr, containing_block_rect);
}
void NGContainerFragmentBuilder::AddOutOfFlowInlineChildCandidate(
@@ -269,6 +240,18 @@ void NGContainerFragmentBuilder::SwapOutOfFlowPositionedCandidates(
has_oof_candidate_that_needs_block_offset_adjustment_ = false;
}
+void NGContainerFragmentBuilder::AddMulticolWithPendingOOFs(
+ const NGBlockNode& multicol) {
+ DCHECK(To<LayoutBlockFlow>(multicol.GetLayoutBox())->MultiColumnFlowThread());
+ multicols_with_pending_oofs_.insert(multicol.GetLayoutBox());
+}
+
+void NGContainerFragmentBuilder::SwapMulticolsWithPendingOOFs(
+ MulticolCollection* multicols_with_pending_oofs) {
+ DCHECK(multicols_with_pending_oofs->IsEmpty());
+ std::swap(multicols_with_pending_oofs_, *multicols_with_pending_oofs);
+}
+
void NGContainerFragmentBuilder::SwapOutOfFlowFragmentainerDescendants(
Vector<NGLogicalOutOfFlowPositionedNode>* descendants) {
DCHECK(descendants->IsEmpty());
@@ -276,6 +259,12 @@ void NGContainerFragmentBuilder::SwapOutOfFlowFragmentainerDescendants(
std::swap(oof_positioned_fragmentainer_descendants_, *descendants);
}
+void NGContainerFragmentBuilder::ClearOutOfFlowFragmentainerDescendants() {
+ if (!HasOutOfFlowFragmentainerDescendants())
+ return;
+ oof_positioned_fragmentainer_descendants_.clear();
+}
+
void NGContainerFragmentBuilder::
MoveOutOfFlowDescendantCandidatesToDescendants() {
DCHECK(oof_positioned_descendants_.IsEmpty());
@@ -303,6 +292,62 @@ void NGContainerFragmentBuilder::
}
}
+void NGContainerFragmentBuilder::PropagateOOFPositionedInfo(
+ const NGPhysicalContainerFragment& fragment,
+ LogicalOffset offset) {
+ const NGPhysicalBoxFragment* box_fragment =
+ DynamicTo<NGPhysicalBoxFragment>(&fragment);
+ if (!box_fragment)
+ return;
+
+ if (box_fragment->HasMulticolsWithPendingOOFs()) {
+ const auto& multicols_with_pending_oofs =
+ box_fragment->MulticolsWithPendingOOFs();
+ for (LayoutBox* multicol : multicols_with_pending_oofs)
+ AddMulticolWithPendingOOFs(NGBlockNode(multicol));
+ }
+
+ // If we find a multicol with OOF positioned fragmentainer descendants,
+ // then that multicol is an inner multicol with pending OOFs. Those OOFs
+ // will be laid out inside the inner multicol when we reach the outermost
+ // fragmentation context, so we should not propagate those OOFs up the tree
+ // any further.
+ if (!box_fragment->HasOutOfFlowPositionedFragmentainerDescendants() ||
+ box_fragment->IsFragmentationContextRoot()) {
+ return;
+ }
+
+ const WritingModeConverter converter(GetWritingDirection(), fragment.Size());
+ const auto& out_of_flow_fragmentainer_descendants =
+ box_fragment->OutOfFlowPositionedFragmentainerDescendants();
+ for (const auto& descendant : out_of_flow_fragmentainer_descendants) {
+ const NGPhysicalContainerFragment* containing_block_fragment =
+ descendant.containing_block_fragment.get();
+ if (!containing_block_fragment)
+ containing_block_fragment = box_fragment;
+
+ LogicalOffset containing_block_offset = converter.ToLogical(
+ descendant.containing_block_offset, containing_block_fragment->Size());
+ if (!fragment.IsFragmentainerBox())
+ containing_block_offset.block_offset += offset.block_offset;
+ if (IsBlockFragmentationContextRoot()) {
+ containing_block_offset.block_offset +=
+ fragmentainer_consumed_block_size_;
+ }
+
+ // The static position should remain relative to its containing block
+ // fragment.
+ const WritingModeConverter containing_block_converter(
+ GetWritingDirection(), containing_block_fragment->Size());
+ NGLogicalStaticPosition static_position =
+ descendant.static_position.ConvertToLogical(containing_block_converter);
+ AddOutOfFlowFragmentainerDescendant(
+ {descendant.node, static_position, descendant.inline_container,
+ /* needs_block_offset_adjustment */ false, containing_block_offset,
+ containing_block_fragment});
+ }
+}
+
#if DCHECK_IS_ON()
String NGContainerFragmentBuilder::ToString() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 557b849d500..840563243fd 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h"
#include "third_party/blink/renderer/core/layout/ng/ng_early_break.h"
@@ -27,6 +26,7 @@
namespace blink {
class NGExclusionSpace;
+class NGInlineBreakToken;
class NGPhysicalFragment;
class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
@@ -45,6 +45,7 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
scoped_refptr<const NGPhysicalFragment> fragment;
};
typedef Vector<ChildWithOffset, 4> ChildrenVector;
+ using MulticolCollection = HashSet<LayoutBox*>;
LayoutUnit BfcLineOffset() const { return bfc_line_offset_; }
void SetBfcLineOffset(LayoutUnit bfc_line_offset) {
@@ -111,7 +112,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
NGLogicalStaticPosition::InlineEdge =
NGLogicalStaticPosition::kInlineStart,
NGLogicalStaticPosition::BlockEdge = NGLogicalStaticPosition::kBlockStart,
- bool needs_block_offset_adjustment = true);
+ bool needs_block_offset_adjustment = true,
+ const base::Optional<LogicalRect> containing_block_rect = base::nullopt);
// This should only be used for inline-level OOF-positioned nodes.
// |inline_container_direction| is the current text direction for determining
@@ -127,12 +129,24 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
void AddOutOfFlowDescendant(
const NGLogicalOutOfFlowPositionedNode& descendant);
+ // Out-of-flow positioned elements inside a nested fragmentation context
+ // are laid out once they've reached the outermost fragmentation context.
+ // However, once at the outer context, they will get laid out inside the
+ // inner multicol in which their containing block resides. Thus, we need to
+ // store such inner multicols for later use.
+ void AddMulticolWithPendingOOFs(const NGBlockNode& multicol);
+
void SwapOutOfFlowPositionedCandidates(
Vector<NGLogicalOutOfFlowPositionedNode>* candidates);
void SwapOutOfFlowFragmentainerDescendants(
Vector<NGLogicalOutOfFlowPositionedNode>* descendants);
+ void SwapMulticolsWithPendingOOFs(
+ MulticolCollection* multicols_with_pending_oofs);
+
+ void ClearOutOfFlowFragmentainerDescendants();
+
bool HasOutOfFlowPositionedCandidates() const {
return !oof_positioned_candidates_.IsEmpty();
}
@@ -141,6 +155,15 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
return !oof_positioned_fragmentainer_descendants_.IsEmpty();
}
+ bool HasMulticolsWithPendingOOFs() const {
+ return !multicols_with_pending_oofs_.IsEmpty();
+ }
+
+ Vector<NGLogicalOutOfFlowPositionedNode>*
+ MutableOutOfFlowPositionedCandidates() {
+ return &oof_positioned_candidates_;
+ }
+
// This method should only be used within the inline layout algorithm. It is
// used to convert all OOF-positioned candidates to descendants.
//
@@ -150,6 +173,14 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
// block layout algorithm, to perform the final OOF layout and positioning.
void MoveOutOfFlowDescendantCandidatesToDescendants();
+ // Propagate the OOF descendants from a fragment to the builder. Since the OOF
+ // descendants on the fragment are NGPhysicalOutOfFlowPositionedNodes, we
+ // first have to create NGLogicalOutOfFlowPositionedNodes copies before
+ // appending them to our list of descendants.
+ // In addition, propagate any inner multicols with pending OOF descendants.
+ void PropagateOOFPositionedInfo(const NGPhysicalContainerFragment& fragment,
+ LogicalOffset offset);
+
void SetIsSelfCollapsing() { is_self_collapsing_ = true; }
void SetIsPushedByFloats() { is_pushed_by_floats_ = true; }
@@ -237,6 +268,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
oof_positioned_fragmentainer_descendants_;
Vector<NGLogicalOutOfFlowPositionedNode> oof_positioned_descendants_;
+ MulticolCollection multicols_with_pending_oofs_;
+
NGUnpositionedListMarker unpositioned_list_marker_;
ChildrenVector children_;
@@ -244,7 +277,7 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
// Only used by the NGBoxFragmentBuilder subclass, but defined here to avoid
// a virtual function call.
NGBreakTokenVector child_break_tokens_;
- NGBreakTokenVector inline_break_tokens_;
+ scoped_refptr<const NGInlineBreakToken> last_inline_break_token_;
scoped_refptr<const NGEarlyBreak> early_break_;
NGBreakAppeal break_appeal_ = kBreakAppealLastResort;
@@ -258,6 +291,10 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
// OOF nodes.
LayoutUnit fragmentainer_consumed_block_size_;
+ // The number of line boxes added to the builder. Only updated if we're
+ // performing block fragmentation.
+ int line_count_ = 0;
+
NGAdjoiningObjectTypes adjoining_object_types_ = kAdjoiningNone;
bool has_adjoining_object_descendants_ = false;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index c0da5d7f25d..35af6bd3ca0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -95,10 +95,10 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
intrinsic_block_size_ + borders_.block_end);
// Recompute the block-axis size now that we know our content size.
- border_box_size_.block_size =
- ComputeBlockSizeForFragment(ConstraintSpace(), Style(), BorderPadding(),
- intrinsic_block_size_ + consumed_block_size_,
- border_box_size_.inline_size);
+ border_box_size_.block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), BorderPadding(),
+ intrinsic_block_size_ + consumed_block_size_,
+ border_box_size_.inline_size, Node().ShouldBeConsideredAsReplaced());
// The above computation utility knows nothing about fieldset weirdness. The
// legend may eat from the available content box block size. Make room for
@@ -106,7 +106,7 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
// Note that in size containment, we have to consider sizing as if we have no
// contents, with the conjecture being that legend is part of the contents.
// Thus, only do this adjustment if we do not contain size.
- if (!Node().ShouldApplySizeContainment()) {
+ if (!Node().ShouldApplyBlockSizeContainment()) {
// Similar to how we add the consumed block size to the intrinsic
// block size when calculating border_box_size_.block_size, we also need to
// do so when the fieldset is adjusted to encompass the legend.
@@ -174,7 +174,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutChildren() {
LayoutLegend(legend);
// The legend may eat from the available content box block size. Calculate
// the minimum block size needed to encompass the legend.
- if (!Node().ShouldApplySizeContainment() &&
+ if (!Node().ShouldApplyBlockSizeContainment() &&
!IsResumingLayout(content_break_token.get())) {
minimum_border_box_block_size_ =
intrinsic_block_size_ + padding_.BlockSum() + borders_.block_end;
@@ -246,7 +246,7 @@ void NGFieldsetLayoutAlgorithm::LayoutLegend(NGBlockNode& legend) {
scoped_refptr<const NGLayoutResult> result =
legend.Layout(legend_space, BreakToken());
- // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ // Legends are monolithic, so abortions are not expected.
DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
const auto& physical_fragment = result->PhysicalFragment();
@@ -328,9 +328,9 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
// - The intrinsic block-size of the content is larger than the
// max-block-size.
if (adjusted_padding_box_size.block_size == kIndefiniteSize) {
- LayoutUnit max_content_block_size = ResolveMaxBlockLength(
- ConstraintSpace(), Style(), BorderPadding(), Style().LogicalMaxHeight(),
- LengthResolvePhase::kLayout);
+ LayoutUnit max_content_block_size =
+ ResolveMaxBlockLength(ConstraintSpace(), Style(), BorderPadding(),
+ Style().LogicalMaxHeight());
if (max_content_block_size != LayoutUnit::Max()) {
max_content_block_size -= BorderPadding().BlockSum();
@@ -350,9 +350,6 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
NGCacheSlot::kLayout);
auto result = fieldset_content.Layout(child_space, content_break_token.get());
- // TODO(layout-dev): Handle abortions caused by block fragmentation.
- DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
-
NGBreakStatus break_status = NGBreakStatus::kContinue;
if (ConstraintSpace().HasBlockFragmentation()) {
bool has_container_separation = is_legend_past_border_;
@@ -367,6 +364,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
}
if (break_status == NGBreakStatus::kContinue) {
+ DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
LogicalOffset offset(borders_.inline_start, intrinsic_block_size_);
container_builder_.AddResult(*result, offset);
intrinsic_block_size_ +=
@@ -388,8 +386,8 @@ MinMaxSizesResult NGFieldsetLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizesInput& input) const {
MinMaxSizesResult result;
- bool apply_size_containment = Node().ShouldApplySizeContainment();
- if (apply_size_containment) {
+ bool has_inline_size_containment = Node().ShouldApplyInlineSizeContainment();
+ if (has_inline_size_containment) {
// Size containment does not consider the legend for sizing.
base::Optional<MinMaxSizesResult> result_without_children =
CalculateMinMaxSizesIgnoringChildren(Node(), BorderScrollbarPadding());
@@ -408,7 +406,7 @@ MinMaxSizesResult NGFieldsetLayoutAlgorithm::ComputeMinMaxSizes(
result.sizes += ComputePadding(ConstraintSpace(), Style()).InlineSum();
// Size containment does not consider the content for sizing.
- if (!apply_size_containment) {
+ if (!has_inline_size_containment) {
if (NGBlockNode content = Node().GetFieldsetContent()) {
MinMaxSizesResult content_result =
ComputeMinAndMaxContentContribution(Style(), content, input);
@@ -436,7 +434,6 @@ NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForLegend(
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(percentage_size);
- builder.SetIsShrinkToFit(legend.Style().LogicalWidth().IsAuto());
return builder.ToConstraintSpace();
}
@@ -452,6 +449,7 @@ NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForFieldsetContent(
/* is_new_fc */ true);
builder.SetCacheSlot(slot);
builder.SetAvailableSize(padding_box_size);
+ builder.SetStretchInlineSizeIfAuto(true);
// We pass the container's PercentageResolutionSize because percentage
// padding for the fieldset content should be computed as they are in
// the container.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
index 888e3614009..2d0c3cb2e4b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -15,16 +15,10 @@ namespace {
class NGFieldsetLayoutAlgorithmTest
: public NGBaseLayoutAlgorithmTest,
- private ScopedLayoutNGFieldsetForTest,
private ScopedLayoutNGBlockFragmentationForTest {
protected:
NGFieldsetLayoutAlgorithmTest()
- : ScopedLayoutNGFieldsetForTest(true),
- ScopedLayoutNGBlockFragmentationForTest(true) {}
- void SetUp() override {
- NGBaseLayoutAlgorithmTest::SetUp();
- style_ = ComputedStyle::Create();
- }
+ : ScopedLayoutNGBlockFragmentationForTest(true) {}
scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
Element* element) {
@@ -38,7 +32,8 @@ class NGFieldsetLayoutAlgorithmTest
MinMaxSizes RunComputeMinMaxSizes(NGBlockNode node) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(), LayoutUnit()), false,
+ LogicalSize(LayoutUnit(), LayoutUnit()),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext());
NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(space, node);
@@ -68,8 +63,6 @@ class NGFieldsetLayoutAlgorithmTest
auto fragment = RunBlockLayoutAlgorithm(element);
return DumpFragmentTree(fragment.get());
}
-
- scoped_refptr<ComputedStyle> style_;
};
TEST_F(NGFieldsetLayoutAlgorithmTest, Empty) {
@@ -467,7 +460,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetPaddingWithLegend) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext());
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -566,7 +560,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
// We should only have one 176x126 fragment with no fragmentation.
@@ -592,7 +587,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, SimpleFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -626,7 +622,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FragmentationNoPadding) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -672,7 +669,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -734,7 +732,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -796,7 +795,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -845,7 +845,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -898,7 +899,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -963,7 +965,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1020,7 +1023,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1077,7 +1081,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest,
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1130,7 +1135,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, OverflowedLegend) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1175,7 +1181,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, OverflowedFieldsetContent) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1242,7 +1249,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1294,7 +1302,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoidTallBlock) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1357,7 +1366,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1411,7 +1421,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakBeforeAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1465,7 +1476,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakBeforeAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1519,7 +1531,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakAfterAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1574,7 +1587,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakAfterAvoid) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1629,7 +1643,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MarginBottomPastEndOfFragmentainer) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1676,7 +1691,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, SmallLegendLargeBorderFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1732,7 +1748,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, SmallerLegendLargeBorderFragmentation) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1793,7 +1810,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, SmallerLegendLargeBorderFragmentation2) {
NGBlockNode node(GetLayoutBoxByElementId("container"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
@@ -1841,7 +1859,8 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, SmallerLegendLargeBorderWithBreak) {
NGBlockNode node(GetLayoutBoxByElementId("fieldset"));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
{WritingMode::kHorizontalTb, TextDirection::kLtr},
- LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+ /* stretch_inline_size_if_auto */ true,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
index 83051eb2a91..315c3f2acb0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
@@ -89,7 +90,6 @@ NGConstraintSpace CreateConstraintSpaceForFloat(
builder.SetPercentageResolutionSize(unpositioned_float.percentage_size);
builder.SetReplacedPercentageResolutionSize(
unpositioned_float.replaced_percentage_size);
- builder.SetIsShrinkToFit(style.LogicalWidth().IsAuto());
return builder.ToConstraintSpace();
}
@@ -263,6 +263,14 @@ NGPositionedFloat PositionFloat(NGUnpositionedFloat* unpositioned_float,
layout_result = node.Layout(space, unpositioned_float->token.get());
+ if (layout_result->Status() != NGLayoutResult::kSuccess) {
+ DCHECK_EQ(layout_result->Status(),
+ NGLayoutResult::kOutOfFragmentainerSpace);
+ need_break_before = true;
+ return NGPositionedFloat(std::move(layout_result), NGBfcOffset(),
+ need_break_before);
+ }
+
// If we knew the right block-offset up front, we're done.
if (!optimistically_placed)
break;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index a5a288562e7..fe47c293049 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/text/writing_direction_mode.h"
@@ -45,8 +46,14 @@ class CORE_EXPORT NGFragmentBuilder {
TextDirection Direction() const { return writing_direction_.Direction(); }
LayoutUnit InlineSize() const { return size_.inline_size; }
- LayoutUnit BlockSize() const { return size_.block_size; }
- const LogicalSize& Size() const { return size_; }
+ LayoutUnit BlockSize() const {
+ DCHECK(size_.block_size != kIndefiniteSize);
+ return size_.block_size;
+ }
+ const LogicalSize& Size() const {
+ DCHECK(size_.block_size != kIndefiniteSize);
+ return size_;
+ }
void SetBlockSize(LayoutUnit block_size) { size_.block_size = block_size; }
void SetIsHiddenForPaint(bool value) { is_hidden_for_paint_ = value; }
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
index aa65979b0da..5805a43450a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
@@ -18,7 +18,6 @@ NGFragmentChildIterator::NGFragmentChildIterator(
: parent_fragment_(&parent),
parent_break_token_(parent_break_token),
is_fragmentation_context_root_(parent.IsFragmentationContextRoot()) {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
current_.link_.fragment = nullptr;
if (parent_break_token)
child_break_tokens_ = parent_break_token->ChildBreakTokens();
@@ -100,8 +99,7 @@ void NGFragmentChildIterator::UpdateSelfFromFragment(
if (layout_object &&
layout_object !=
current_.block_break_token_->InputNode().GetLayoutBox()) {
- DCHECK(current_.link_.fragment->IsColumnSpanAll() ||
- current_.block_break_token_->InputNode().IsOutOfFlowPositioned());
+ DCHECK(current_.link_.fragment->IsColumnSpanAll());
current_.break_token_for_fragmentainer_only_ = true;
} else {
current_.break_token_for_fragmentainer_only_ = false;
@@ -125,6 +123,27 @@ void NGFragmentChildIterator::UpdateSelfFromFragment(
DCHECK(previous_fragment->IsRenderedLegend() ||
previous_fragment->IsColumnSpanAll());
}
+ } else if (current_.link_.fragment->IsOutOfFlowPositioned() &&
+ !To<NGPhysicalBoxFragment>(current_.link_.fragment)
+ ->IsFirstForNode()) {
+ // If an out-of-flow positioned element fragments beyond the last existing
+ // fragmentainer in a nested fragmentation context, instead of creating a
+ // new fragmentainer to hold it, we add it to the last existing
+ // fragmentainer at the correct inline offset. Therefore, in order to find
+ // the corrcet incoming break token in such cases, we must look for any
+ // previous fragments inside |children| that were created by the same node.
+ current_.block_break_token_ = nullptr;
+ const auto* layout_object = current_.link_.fragment->GetLayoutObject();
+ DCHECK(layout_object);
+ for (wtf_size_t index = child_fragment_idx_; index > 0; index--) {
+ const auto* child_fragment = children[index - 1].fragment;
+ if (layout_object == child_fragment->GetLayoutObject()) {
+ current_.block_break_token_ = To<NGBlockBreakToken>(
+ To<NGPhysicalBoxFragment>(child_fragment)->BreakToken());
+ current_.break_token_for_fragmentainer_only_ = false;
+ break;
+ }
+ }
} else {
current_.block_break_token_ = nullptr;
}
@@ -156,7 +175,7 @@ void NGFragmentChildIterator::UpdateSelfFromCursor() {
current_.link_.fragment = nullptr;
return;
}
- current_.link_ = {item->BoxFragment(), item->OffsetInContainerBlock()};
+ current_.link_ = {item->BoxFragment(), item->OffsetInContainerFragment()};
}
void NGFragmentChildIterator::SkipToBoxFragment() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
index 7f6f18384f1..68de9194146 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
@@ -12,12 +12,10 @@ namespace {
class NGFragmentChildIteratorTest
: public NGBaseLayoutAlgorithmTest,
- private ScopedLayoutNGBlockFragmentationForTest,
- private ScopedLayoutNGFragmentItemForTest {
+ private ScopedLayoutNGBlockFragmentationForTest {
protected:
NGFragmentChildIteratorTest()
- : ScopedLayoutNGBlockFragmentationForTest(true),
- ScopedLayoutNGFragmentItemForTest(true) {}
+ : ScopedLayoutNGBlockFragmentationForTest(true) {}
scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
Element* element) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc
index d55339a29a2..bad31c5eb14 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc
@@ -280,5 +280,108 @@ TEST_F(NGFragmentationTest, InkOverflowInline) {
PhysicalRect(0, 0, 210, 15));
}
+TEST_F(NGFragmentationTest, OffsetFromOwnerLayoutBoxColumnBox) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #columns {
+ column-width: 100px;
+ column-gap: 10px;
+ column-fill: auto;
+ width: 320px;
+ height: 500px;
+ }
+ </style>
+ <div id="columns" style="background: blue">
+ <div id="block" style="height: 1500px"></div>
+ </div>
+ )HTML");
+ const auto* columns = GetLayoutBoxByElementId("columns");
+ const auto* flow_thread = To<LayoutBox>(columns->SlowFirstChild());
+ EXPECT_EQ(flow_thread->PhysicalFragmentCount(), 3u);
+ const NGPhysicalBoxFragment* fragment0 = flow_thread->GetPhysicalFragment(0);
+ EXPECT_EQ(fragment0->OffsetFromOwnerLayoutBox(), PhysicalOffset());
+ const NGPhysicalBoxFragment* fragment1 = flow_thread->GetPhysicalFragment(1);
+ EXPECT_EQ(fragment1->OffsetFromOwnerLayoutBox(), PhysicalOffset(110, 0));
+ const NGPhysicalBoxFragment* fragment2 = flow_thread->GetPhysicalFragment(2);
+ EXPECT_EQ(fragment2->OffsetFromOwnerLayoutBox(), PhysicalOffset(220, 0));
+
+ // Check running another layout does not crash.
+ GetElementById("block")->appendChild(GetDocument().createTextNode("a"));
+ RunDocumentLifecycle();
+}
+
+TEST_F(NGFragmentationTest, OffsetFromOwnerLayoutBoxFloat) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #columns {
+ column-width: 100px;
+ column-gap: 10px;
+ column-fill: auto;
+ width: 320px;
+ height: 500px;
+ }
+ #float {
+ float: left;
+ width: 50px;
+ height: 500px;
+ background: orange;
+ }
+ </style>
+ <div id="columns" style="background: blue">
+ <!-- A spacer to make `target` start at 2nd column. -->
+ <div style="height: 800px"></div>
+ <div id="float"></div>
+ Text
+ </div>
+ )HTML");
+ const auto* target = GetLayoutBoxByElementId("float");
+ EXPECT_EQ(target->PhysicalFragmentCount(), 2u);
+ const NGPhysicalBoxFragment* fragment0 = target->GetPhysicalFragment(0);
+ EXPECT_EQ(fragment0->OffsetFromOwnerLayoutBox(), PhysicalOffset());
+ const NGPhysicalBoxFragment* fragment1 = target->GetPhysicalFragment(1);
+ EXPECT_EQ(fragment1->OffsetFromOwnerLayoutBox(), PhysicalOffset(110, -300));
+}
+
+TEST_F(NGFragmentationTest, OffsetFromOwnerLayoutBoxNested) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ html, body {
+ margin: 0;
+ }
+ #outer-columns {
+ column-width: 100px;
+ column-gap: 10px;
+ column-fill: auto;
+ width: 320px;
+ height: 500px;
+ }
+ #inner-columns {
+ column-width: 45px;
+ column-gap: 10px;
+ column-fill: auto;
+ width: 100px;
+ height: 800px;
+ }
+ </style>
+ <div id="outer-columns" style="background: blue">
+ <!-- A spacer to make `inner-columns` start at 2nd column. -->
+ <div style="height: 700px"></div>
+ <div id="inner-columns" style="height: 800px; background: purple">
+ <!-- A spacer to make `target` start at 2nd column. -->
+ <div style="height: 400px"></div>
+ <div id="target" style="background: orange; height: 1000px"></div>
+ </div>
+ </div>
+ )HTML");
+ const auto* target = GetLayoutBoxByElementId("target");
+ EXPECT_EQ(target->PhysicalFragmentCount(), 3u);
+ const NGPhysicalBoxFragment* fragment0 = target->GetPhysicalFragment(0);
+ EXPECT_EQ(fragment0->OffsetFromOwnerLayoutBox(), PhysicalOffset());
+ const NGPhysicalBoxFragment* fragment1 = target->GetPhysicalFragment(1);
+ EXPECT_EQ(fragment1->OffsetFromOwnerLayoutBox(), PhysicalOffset(55, -300));
+ const NGPhysicalBoxFragment* fragment2 = target->GetPhysicalFragment(2);
+ EXPECT_EQ(fragment2->OffsetFromOwnerLayoutBox(), PhysicalOffset(110, -300));
+}
+
} // anonymous namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index d9744c6979d..0c8cf27fb54 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -224,7 +224,8 @@ bool IsNodeFullyGrown(NGBlockNode node,
// constrained. If it doesn't affect the block size, it means that the node
// cannot grow any further.
LayoutUnit max_block_size = ComputeBlockSizeForFragment(
- space, node.Style(), border_padding, LayoutUnit::Max(), inline_size);
+ space, node.Style(), border_padding, LayoutUnit::Max(), inline_size,
+ node.ShouldBeConsideredAsReplaced());
DCHECK_GE(max_block_size, current_total_block_size);
return max_block_size == current_total_block_size;
}
@@ -594,12 +595,12 @@ bool MovePastBreakpoint(const NGConstraintSpace& space,
DynamicTo<NGBlockBreakToken>(physical_fragment.BreakToken());
LayoutUnit space_left =
- space.FragmentainerBlockSize() - fragmentainer_block_offset;
+ FragmentainerCapacity(space) - fragmentainer_block_offset;
// If we haven't used any space at all in the fragmentainer yet, we cannot
// break before this child, or there'd be no progress. We'd risk creating an
// infinite number of fragmentainers without putting any content into them.
- bool refuse_break_before = space_left >= space.FragmentainerBlockSize();
+ bool refuse_break_before = space_left >= FragmentainerCapacity(space);
// If the child starts past the end of the fragmentainer (probably due to a
// block-start margin), we must break before it.
@@ -639,38 +640,20 @@ bool MovePastBreakpoint(const NGConstraintSpace& space,
builder->SetBreakAppeal(appeal_inside);
return true;
}
- } else {
- bool need_break;
- if (refuse_break_before) {
- need_break = false;
- } else if (child.IsMonolithic()) {
- // If the monolithic piece of content (e.g. a line, or block-level
- // replaced content) doesn't fit, we need a break.
- need_break = fragment.BlockSize() > space_left;
- } else {
- // If the block-offset is past the fragmentainer boundary (or exactly at
- // the boundary), no part of the fragment is going to fit in the current
- // fragmentainer. Fragments may be pushed past the fragmentainer boundary
- // by margins. We shouldn't break before a zero-size block that's exactly
- // at a fragmentainer boundary, though.
- need_break = space_left < LayoutUnit() ||
- (space_left == LayoutUnit() && fragment.BlockSize());
- }
-
- if (!need_break) {
- if (child.IsBlock() && builder) {
- // If this doesn't happen, though, we're tentatively not going to break
- // before or inside this child, but we'll check the appeal of breaking
- // there anyway. It may be the best breakpoint we'll ever find. (Note
- // that we only do this for block children, since, when it comes to
- // inline layout, we first need to lay out all the line boxes, so that
- // we know what do to in order to honor orphans and widows, if at all
- // possible.)
- UpdateEarlyBreakAtBlockChild(space, To<NGBlockNode>(child),
- layout_result, appeal_before, builder);
- }
- return true;
+ } else if (refuse_break_before || fragment.BlockSize() <= space_left) {
+ // The child either fits, or we are not allowed to break. So we can move
+ // past this breakpoint.
+ if (child.IsBlock() && builder) {
+ // We're tentatively not going to break before or inside this child, but
+ // we'll check the appeal of breaking there anyway. It may be the best
+ // breakpoint we'll ever find. (Note that we only do this for block
+ // children, since, when it comes to inline layout, we first need to lay
+ // out all the line boxes, so that we know what do to in order to honor
+ // orphans and widows, if at all possible.)
+ UpdateEarlyBreakAtBlockChild(space, To<NGBlockNode>(child), layout_result,
+ appeal_before, builder);
}
+ return true;
}
// We don't want to break inside, so we should attempt to break before.
@@ -743,15 +726,9 @@ NGConstraintSpace CreateConstraintSpaceForColumns(
parent_space, parent_space.GetWritingDirection(), /* is_new_fc */ true);
space_builder.SetAvailableSize(column_size);
space_builder.SetPercentageResolutionSize(percentage_resolution_size);
-
- // To ensure progression, we need something larger than 0 here. The spec
- // actually says that fragmentainers have to accept at least 1px of content.
- // See https://www.w3.org/TR/css-break-3/#breaking-rules
- LayoutUnit column_block_size =
- std::max(column_size.block_size, LayoutUnit(1));
-
+ space_builder.SetStretchInlineSizeIfAuto(true);
space_builder.SetFragmentationType(kFragmentColumn);
- space_builder.SetFragmentainerBlockSize(column_block_size);
+ space_builder.SetFragmentainerBlockSize(column_size.block_size);
space_builder.SetIsAnonymous(true);
space_builder.SetIsInColumnBfc();
if (balance_columns)
@@ -765,10 +742,33 @@ NGConstraintSpace CreateConstraintSpaceForColumns(
space_builder.SetDiscardingMarginStrut();
}
- space_builder.SetNeedsBaseline(parent_space.NeedsBaseline());
space_builder.SetBaselineAlgorithmType(parent_space.BaselineAlgorithmType());
return space_builder.ToConstraintSpace();
}
+NGBoxFragmentBuilder CreateContainerBuilderForMulticol(
+ const NGBlockNode& multicol,
+ const NGConstraintSpace& space,
+ const NGFragmentGeometry& fragment_geometry) {
+ const ComputedStyle* style = &multicol.Style();
+ NGBoxFragmentBuilder multicol_container_builder(multicol, style, &space,
+ style->GetWritingDirection());
+ multicol_container_builder.SetIsNewFormattingContext(true);
+ multicol_container_builder.SetInitialFragmentGeometry(fragment_geometry);
+ multicol_container_builder.SetIsBlockFragmentationContextRoot();
+
+ return multicol_container_builder;
+}
+
+NGConstraintSpace CreateConstraintSpaceForMulticol(
+ const NGBlockNode& multicol) {
+ WritingDirectionMode writing_direction_mode =
+ multicol.Style().GetWritingDirection();
+ NGConstraintSpaceBuilder space_builder(
+ writing_direction_mode.GetWritingMode(), writing_direction_mode,
+ /* is_new_fc */ true);
+ return space_builder.ToConstraintSpace();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index b85b17aee49..fff17dbb5ed 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -66,6 +66,25 @@ NGBreakAppeal CalculateBreakAppealInside(const NGConstraintSpace& space,
NGBlockNode child,
const NGLayoutResult&);
+// To ensure content progression, we need fragmentainers to hold something
+// larger than 0. The spec says that fragmentainers have to accept at least 1px
+// of content. See https://www.w3.org/TR/css-break-3/#breaking-rules
+inline LayoutUnit ClampedToValidFragmentainerCapacity(LayoutUnit length) {
+ return std::max(length, LayoutUnit(1));
+}
+
+// Return the fragmentainer block-size to use during layout. This is normally
+// the same as the block-size we'll give to the fragment itself, but in order to
+// ensure content progression, we need fragmentainers to hold something larger
+// than 0 (even if the final fragentainer size may very well be 0). The spec
+// says that fragmentainers have to accept at least 1px of content. See
+// https://www.w3.org/TR/css-break-3/#breaking-rules
+inline LayoutUnit FragmentainerCapacity(const NGConstraintSpace& space) {
+ if (!space.HasKnownFragmentainerBlockSize())
+ return kIndefiniteSize;
+ return ClampedToValidFragmentainerCapacity(space.FragmentainerBlockSize());
+}
+
// Return the block space that was available in the current fragmentainer at the
// start of the current block formatting context. Note that if the start of the
// current block formatting context is in a previous fragmentainer, the size of
@@ -75,7 +94,7 @@ NGBreakAppeal CalculateBreakAppealInside(const NGConstraintSpace& space,
inline LayoutUnit FragmentainerSpaceAtBfcStart(const NGConstraintSpace& space) {
if (!space.HasKnownFragmentainerBlockSize())
return kIndefiniteSize;
- return space.FragmentainerBlockSize() - space.FragmentainerOffsetAtBfc();
+ return FragmentainerCapacity(space) - space.FragmentainerOffsetAtBfc();
}
// Adjust margins to take fragmentation into account. Leading/trailing block
@@ -266,6 +285,13 @@ NGConstraintSpace CreateConstraintSpaceForColumns(
bool allow_discard_start_margin,
bool balance_columns);
+// Calculate the container builder and constraint space for a multicol.
+NGBoxFragmentBuilder CreateContainerBuilderForMulticol(
+ const NGBlockNode& multicol,
+ const NGConstraintSpace& space,
+ const NGFragmentGeometry& fragment_geometry);
+NGConstraintSpace CreateConstraintSpaceForMulticol(const NGBlockNode& multicol);
+
// Return the adjusted child margin to be applied at the end of a fragment.
// Margins should collapse with the fragmentainer boundary. |bfc_block_offset|
// is the BFC offset where the margin should be applied (i.e. after the
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index bde68b28da2..0d82846a2a0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -138,10 +138,6 @@ PhysicalSize NGLayoutInputNode::InitialContainingBlockSize() const {
return PhysicalSize(icb_size);
}
-const NGPaintFragment* NGLayoutInputNode::PaintFragment() const {
- return GetLayoutBox()->PaintFragment();
-}
-
String NGLayoutInputNode::ToString() const {
auto* inline_node = DynamicTo<NGInlineNode>(this);
return inline_node ? inline_node->ToString()
@@ -180,6 +176,7 @@ void NGLayoutInputNode::GetOverrideIntrinsicSize(
*computed_block_size = default_block_size;
}
+ // TODO(mstensho): Update for contain:inline-size / contain:block-size.
if (ShouldApplySizeContainment()) {
if (!*computed_inline_size)
*computed_inline_size = LayoutUnit();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index 1a1296d8524..1df8c5b2488 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
+#include "third_party/blink/renderer/core/layout/geometry/axis.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
@@ -23,7 +24,6 @@ class Document;
class LayoutObject;
class LayoutBox;
class NGConstraintSpace;
-class NGPaintFragment;
struct MinMaxSizes;
struct PhysicalSize;
@@ -56,6 +56,11 @@ struct MinMaxSizesInput {
// min/max sizes, and if this calculation will change if the
// |MinMaxSizesInput::percentage_resolution_block_size| value changes.
struct MinMaxSizesResult {
+ MinMaxSizesResult() = default;
+ MinMaxSizesResult(MinMaxSizes sizes, bool depends_on_percentage_block_size)
+ : sizes(sizes),
+ depends_on_percentage_block_size(depends_on_percentage_block_size) {}
+
MinMaxSizes sizes;
bool depends_on_percentage_block_size = false;
};
@@ -112,6 +117,7 @@ class CORE_EXPORT NGLayoutInputNode {
bool IsFlexibleBox() const {
return IsBlock() && box_->IsFlexibleBoxIncludingNG();
}
+ bool IsGrid() const { return IsBlock() && box_->IsLayoutGridIncludingNG(); }
bool ShouldBeConsideredAsReplaced() const {
return box_->ShouldBeConsideredAsReplaced();
}
@@ -237,6 +243,29 @@ class CORE_EXPORT NGLayoutInputNode {
bool ShouldApplySizeContainment() const {
return box_->ShouldApplySizeContainment();
}
+ // Return true if we should apply at least inline-size containment
+ // (i.e. "contain" is "size" or "inline-size").
+ bool ShouldApplyInlineSizeContainment() const {
+ return box_->ShouldApplyInlineSizeContainment();
+ }
+ // Return true if we should apply at least block-size containment
+ // (i.e. "contain" is "size" or "block-size").
+ bool ShouldApplyBlockSizeContainment() const {
+ return box_->ShouldApplyBlockSizeContainment();
+ }
+
+ bool IsContainerForContainerQueries() const {
+ return box_->IsContainerForContainerQueries();
+ }
+
+ LogicalAxes ContainedAxes() const {
+ LogicalAxes axes(kLogicalAxisNone);
+ if (ShouldApplyInlineSizeContainment())
+ axes |= LogicalAxes(kLogicalAxisInline);
+ if (ShouldApplyBlockSizeContainment())
+ axes |= LogicalAxes(kLogicalAxisBlock);
+ return axes;
+ }
// CSS defines certain cases to synthesize inline block baselines from box.
// See comments in UseLogicalBottomMarginEdgeForInlineBlockBaseline().
@@ -277,16 +306,19 @@ class CORE_EXPORT NGLayoutInputNode {
return box_->ChildLayoutBlockedByDisplayLock();
}
- // Returns the first NGPaintFragment for this node. When block fragmentation
- // occurs, there will be multiple NGPaintFragment for a node.
- const NGPaintFragment* PaintFragment() const;
-
CustomLayoutChild* GetCustomLayoutChild() const {
// TODO(ikilpatrick): Support NGInlineNode.
DCHECK(IsBlock());
return box_->GetCustomLayoutChild();
}
+ // Return whether we can directly traverse fragments generated from this node
+ // (for painting, hit-testing and other layout read operations). If false is
+ // returned, we need to traverse the layout object tree instead.
+ bool CanTraversePhysicalFragments() const {
+ return box_->CanTraversePhysicalFragments();
+ }
+
String ToString() const;
explicit operator bool() const { return box_ != nullptr; }
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
index db87551c1ef..755df23d17d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
@@ -91,29 +91,6 @@ NGLayoutOverflowCalculator::NGLayoutOverflowCalculator(
const PhysicalRect NGLayoutOverflowCalculator::Result(
const base::Optional<PhysicalRect> inflow_bounds) {
- // Adjust the layout-overflow if we have "overflow: clip" present.
- if (!is_scroll_container_ && has_non_visible_overflow_) {
- const OverflowClipAxes overflow_clip_axes = node_.GetOverflowClipAxes();
- const LayoutUnit overflow_clip_margin = node_.Style().OverflowClipMargin();
- if (overflow_clip_margin != LayoutUnit()) {
- // overflow_clip_margin should only be set if 'overflow' is 'clip' along
- // both axis.
- DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
- PhysicalRect expanded_padding_rect = padding_rect_;
- expanded_padding_rect.Inflate(overflow_clip_margin);
- layout_overflow_.Intersect(expanded_padding_rect);
- } else {
- if (overflow_clip_axes & kOverflowClipX) {
- layout_overflow_.offset.left = padding_rect_.offset.left;
- layout_overflow_.size.width = padding_rect_.size.width;
- }
- if (overflow_clip_axes & kOverflowClipY) {
- layout_overflow_.offset.top = padding_rect_.offset.top;
- layout_overflow_.size.height = padding_rect_.size.height;
- }
- }
- }
-
if (!inflow_bounds || !is_scroll_container_)
return layout_overflow_;
@@ -177,7 +154,7 @@ void NGLayoutOverflowCalculator::AddItemsInternal(const Items& items) {
for (const auto& item : items) {
if (const auto* line_box = item->LineBoxFragment()) {
has_hanging = line_box->HasHanging();
- line_rect = item->RectInContainerBlock();
+ line_rect = item->RectInContainerFragment();
if (line_rect.IsEmpty())
continue;
@@ -195,7 +172,7 @@ void NGLayoutOverflowCalculator::AddItemsInternal(const Items& items) {
}
if (item->IsText()) {
- PhysicalRect child_overflow = item->RectInContainerBlock();
+ PhysicalRect child_overflow = item->RectInContainerFragment();
// Adjust the text's overflow if the line-box has hanging.
if (UNLIKELY(has_hanging))
@@ -209,7 +186,7 @@ void NGLayoutOverflowCalculator::AddItemsInternal(const Items& items) {
// Use the default box-fragment overflow logic.
PhysicalRect child_overflow =
LayoutOverflowForPropagation(*child_box_fragment);
- child_overflow.offset += item->OffsetInContainerBlock();
+ child_overflow.offset += item->OffsetInContainerFragment();
// Only inline-boxes (not atomic-inlines) should be adjusted if the
// line-box has hanging.
@@ -281,14 +258,38 @@ PhysicalRect NGLayoutOverflowCalculator::LayoutOverflowForPropagation(
if (!child_fragment.IsCSSBox())
return child_fragment.LayoutOverflow();
- // Children with overflow clip (e.g. a scrollable child) don't propagate any
- // layout overflow.
PhysicalRect overflow = {{}, child_fragment.Size()};
+ const auto& child_style = child_fragment.Style();
if (!child_fragment.ShouldApplyLayoutContainment() &&
(!child_fragment.ShouldClipOverflowAlongBothAxis() ||
- child_fragment.Style().OverflowClipMargin() != LayoutUnit()) &&
- !child_fragment.IsInlineBox())
- overflow.UniteEvenIfEmpty(child_fragment.LayoutOverflow());
+ child_style.OverflowClipMargin() != LayoutUnit()) &&
+ !child_fragment.IsInlineBox()) {
+ PhysicalRect child_overflow = child_fragment.LayoutOverflow();
+ if (child_fragment.HasNonVisibleOverflow()) {
+ const OverflowClipAxes overflow_clip_axes =
+ child_fragment.GetOverflowClipAxes();
+ const LayoutUnit overflow_clip_margin = child_style.OverflowClipMargin();
+ if (overflow_clip_margin != LayoutUnit()) {
+ // overflow_clip_margin should only be set if 'overflow' is 'clip' along
+ // both axis.
+ DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
+ PhysicalRect child_padding_rect({}, child_fragment.Size());
+ child_padding_rect.Contract(child_fragment.Borders());
+ child_padding_rect.Inflate(overflow_clip_margin);
+ child_overflow.Intersect(child_padding_rect);
+ } else {
+ if (overflow_clip_axes & kOverflowClipX) {
+ child_overflow.offset.left = LayoutUnit();
+ child_overflow.size.width = child_fragment.Size().width;
+ }
+ if (overflow_clip_axes & kOverflowClipY) {
+ child_overflow.offset.top = LayoutUnit();
+ child_overflow.size.height = child_fragment.Size().height;
+ }
+ }
+ }
+ overflow.UniteEvenIfEmpty(child_overflow);
+ }
// Apply any transforms to the overflow.
if (base::Optional<TransformationMatrix> transform =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index 05d0a4e335b..fce19442662 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -95,6 +95,8 @@ NGLayoutResult::NGLayoutResult(
rare_data->minimal_space_shortage = builder->minimal_space_shortage_;
}
+ rare_data->has_violating_break = builder->has_violating_break_;
+
if (builder->column_spanner_)
rare_data->column_spanner = builder->column_spanner_;
@@ -319,6 +321,7 @@ void NGLayoutResult::CheckSameForSimplifiedLayout(
DCHECK(EndMarginStrut() == other.EndMarginStrut());
DCHECK_EQ(MinimalSpaceShortage(), other.MinimalSpaceShortage());
+ DCHECK_EQ(TableColumnCount(), other.TableColumnCount());
DCHECK_EQ(bitfields_.has_forced_break, other.bitfields_.has_forced_break);
DCHECK_EQ(bitfields_.is_self_collapsing, other.bitfields_.is_self_collapsing);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index c7f1563350a..1f4ce1e3933 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -204,6 +204,13 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return rare_data_->tallest_unbreakable_block_size;
}
+ // Return true if we weren't able to honor all break avoidance hints requested
+ // by break-{after,before,inside}:avoid or orphans / widows. This is used for
+ // column balancing.
+ bool HasViolatingBreak() const {
+ return HasRareData() && rare_data_->has_violating_break;
+ }
+
// Return whether this result is single-use only (true), or if it is allowed
// to be involved in cache hits in future layout passes (false).
// For example, this happens when a block is fragmented, since we don't yet
@@ -334,7 +341,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
bool check_same_block_size = true) const;
#endif
- using NGBoxFragmentBuilderPassKey = util::PassKey<NGBoxFragmentBuilder>;
+ using NGBoxFragmentBuilderPassKey = base::PassKey<NGBoxFragmentBuilder>;
// This constructor is for a non-success status.
NGLayoutResult(NGBoxFragmentBuilderPassKey, EStatus, NGBoxFragmentBuilder*);
// This constructor requires a non-null fragment and sets a success status.
@@ -343,7 +350,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGBoxFragmentBuilder*);
using NGLineBoxFragmentBuilderPassKey =
- util::PassKey<NGLineBoxFragmentBuilder>;
+ base::PassKey<NGLineBoxFragmentBuilder>;
// This constructor requires a non-null fragment and sets a success status.
NGLayoutResult(
NGLineBoxFragmentBuilderPassKey,
@@ -425,6 +432,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
LayoutUnit annotation_overflow;
LayoutUnit block_end_annotation_space;
bool is_single_use = false;
+ bool has_violating_break = false;
int lines_until_clamp = 0;
wtf_size_t table_column_count_ = 0;
base::Optional<MathData> math_layout_data_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
index 1b2ff304181..d906508c05b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
@@ -101,20 +101,30 @@ TEST_F(NGLayoutResultCachingTest, HitDifferentBFCOffset) {
/* offset */ {LayoutUnit(), LayoutUnit()},
/* available_inline_size */ LayoutUnit(100));
- EXPECT_EQ(opportunities.size(), 3u);
+ EXPECT_EQ(opportunities.size(), 4u);
+
+ // This first opportunity is superfluous, but harmless. It isn't needed for
+ // correct positioning, but having it in the opportunity list shouldn't
+ // trigger any bad behaviour (if something doesn't fit, in this case it'll
+ // proceed to the next layout opportunity).
EXPECT_EQ(opportunities[0].rect.start_offset,
NGBfcOffset(LayoutUnit(50), LayoutUnit()));
EXPECT_EQ(opportunities[0].rect.end_offset,
- NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
+ NGBfcOffset(LayoutUnit(100), LayoutUnit(45)));
EXPECT_EQ(opportunities[1].rect.start_offset,
- NGBfcOffset(LayoutUnit(), LayoutUnit(20)));
+ NGBfcOffset(LayoutUnit(50), LayoutUnit()));
EXPECT_EQ(opportunities[1].rect.end_offset,
- NGBfcOffset(LayoutUnit(100), LayoutUnit(45)));
+ NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
EXPECT_EQ(opportunities[2].rect.start_offset,
- NGBfcOffset(LayoutUnit(), LayoutUnit(65)));
+ NGBfcOffset(LayoutUnit(), LayoutUnit(20)));
EXPECT_EQ(opportunities[2].rect.end_offset,
+ NGBfcOffset(LayoutUnit(100), LayoutUnit(45)));
+
+ EXPECT_EQ(opportunities[3].rect.start_offset,
+ NGBfcOffset(LayoutUnit(), LayoutUnit(65)));
+ EXPECT_EQ(opportunities[3].rect.end_offset,
NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
}
@@ -1673,6 +1683,29 @@ TEST_F(NGLayoutResultCachingTest, HitFlexLegacyGrid) {
EXPECT_NE(result.get(), nullptr);
}
+TEST_F(NGLayoutResultCachingTest, HitFlexDefiniteChange) {
+ SetBodyInnerHTML(R"HTML(
+ <div style="display: flex; flex-direction: column;">
+ <div style="height: 200px;" id=target1>
+ <div style="height: 100px"></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* target1 = To<LayoutBlock>(GetLayoutObjectByElementId("target1"));
+
+ scoped_refptr<const NGLayoutResult> result1 =
+ target1->GetCachedLayoutResult();
+ scoped_refptr<const NGLayoutResult> measure1 =
+ target1->GetCachedMeasureResult();
+ EXPECT_EQ(measure1->IntrinsicBlockSize(), 100);
+ EXPECT_EQ(result1->PhysicalFragment().Size().height, 200);
+
+ EXPECT_EQ(result1->GetConstraintSpaceForCaching().CacheSlot(),
+ NGCacheSlot::kMeasure);
+ EXPECT_EQ(result1.get(), measure1.get());
+}
+
TEST_F(NGLayoutResultCachingTest, HitOrthogonalRoot) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -1836,5 +1869,204 @@ TEST_F(NGLayoutResultCachingTest, MissTableCellBaselineAlignment) {
EXPECT_NE(result.get(), measure.get());
}
+TEST_F(NGLayoutResultCachingTest, MissTablePercent) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .bfc { display: flow-root; width: 100px; }
+ table { height: 100%; }
+ caption { height: 50px; }
+ </style>
+ <div class="bfc" style="height: 50px;">
+ <table id="test">
+ <caption></caption>
+ <td></td>
+ </table>
+ </div>
+ <div class="bfc" style="height: 100px;">
+ <table id="src">
+ <caption></caption>
+ <td></td>
+ </table>
+ </div>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, HitTableRowAdd) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tr><td>a</td><td>b</td></tr>
+ <tr id="test"><td>text</td><td>more text</td></tr>
+ </table>
+ <table>
+ <tr id="src"><td>text</td><td>more text</td></tr>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, MissTableRowAdd) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tr><td>longwordhere</td><td>b</td></tr>
+ <tr id="test"><td>text</td><td>more text</td></tr>
+ </table>
+ <table>
+ <tr id="src"><td>text</td><td>more text</td></tr>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, HitTableRowRemove) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tr id="test"><td>text</td><td>more text</td></tr>
+ </table>
+ <table>
+ <tr><td>a</td><td>b</td></tr>
+ <tr id="src"><td>text</td><td>more text</td></tr>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, MissTableRowRemove) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tr id="test"><td>text</td><td>more text</td></tr>
+ </table>
+ <table>
+ <tr><td>longwordhere</td><td>b</td></tr>
+ <tr id="src"><td>text</td><td>more text</td></tr>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, HitTableSectionAdd) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tbody><tr><td>a</td><td>b</td></tr></tbody>
+ <tbody id="test"><tr><td>text</td><td>more text</td></tr></tbody>
+ </table>
+ <table>
+ <tbody id="src"><tr><td>text</td><td>more text</td></tr></tbody>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, HitTableSectionRemove) {
+ ScopedLayoutNGTableForTest table_ng(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <table>
+ <tbody id="test"><tr><td>text</td><td>more text</td></tr></tbody>
+ </table>
+ <table>
+ <tbody><tr><td>a</td><td>b</td></tr></tbody>
+ <tbody id="src"><tr><td>text</td><td>more text</td></tr></tbody>
+ </table>
+ )HTML");
+
+ auto* test = To<LayoutBlock>(GetLayoutObjectByElementId("test"));
+ auto* src = To<LayoutBlock>(GetLayoutObjectByElementId("src"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ const NGConstraintSpace& space =
+ src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
index 9a4f20dd242..6aec1c797aa 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -27,11 +27,8 @@ inline bool InlineLengthMayChange(const ComputedStyle& style,
const NGConstraintSpace& new_space,
const NGConstraintSpace& old_space,
const NGLayoutResult& layout_result) {
- DCHECK_EQ(new_space.IsShrinkToFit(), old_space.IsShrinkToFit());
-#if DCHECK_IS_ON()
- if (type == LengthResolveType::kMainSize && new_space.IsShrinkToFit())
- DCHECK(length.IsAuto());
-#endif
+ DCHECK_EQ(new_space.StretchInlineSizeIfAuto(),
+ old_space.StretchInlineSizeIfAuto());
bool is_unspecified =
(length.IsAuto() && type != LengthResolveType::kMinSize) ||
@@ -63,7 +60,10 @@ inline bool InlineLengthMayChange(const ComputedStyle& style,
inline bool BlockLengthMayChange(const Length& length,
const NGConstraintSpace& new_space,
const NGConstraintSpace& old_space) {
- if (length.IsFillAvailable()) {
+ DCHECK_EQ(new_space.StretchBlockSizeIfAuto(),
+ old_space.StretchBlockSizeIfAuto());
+ if (length.IsFillAvailable() ||
+ (length.IsAuto() && new_space.StretchBlockSizeIfAuto())) {
if (new_space.AvailableSize().block_size !=
old_space.AvailableSize().block_size)
return true;
@@ -72,6 +72,46 @@ inline bool BlockLengthMayChange(const Length& length,
return false;
}
+bool BlockSizeMayChange(const NGBlockNode& node,
+ const NGConstraintSpace& new_space,
+ const NGConstraintSpace& old_space,
+ const NGLayoutResult& layout_result) {
+ DCHECK_EQ(new_space.IsFixedBlockSize(), old_space.IsFixedBlockSize());
+ DCHECK_EQ(new_space.IsFixedBlockSizeIndefinite(),
+ old_space.IsFixedBlockSizeIndefinite());
+ DCHECK_EQ(new_space.StretchBlockSizeIfAuto(),
+ old_space.StretchBlockSizeIfAuto());
+ DCHECK_EQ(new_space.TableCellChildLayoutMode(),
+ old_space.TableCellChildLayoutMode());
+
+ if (node.IsQuirkyAndFillsViewport())
+ return true;
+
+ if (new_space.IsFixedBlockSize()) {
+ if (new_space.AvailableSize().block_size !=
+ old_space.AvailableSize().block_size)
+ return true;
+ } else {
+ const ComputedStyle& style = node.Style();
+ if (BlockLengthMayChange(style.LogicalHeight(), new_space, old_space) ||
+ BlockLengthMayChange(style.LogicalMinHeight(), new_space, old_space) ||
+ BlockLengthMayChange(style.LogicalMaxHeight(), new_space, old_space))
+ return true;
+ // We only need to check if the PercentageResolutionBlockSizes match if the
+ // layout result has explicitly marked itself as dependent.
+ if (layout_result.PhysicalFragment().DependsOnPercentageBlockSize()) {
+ if (new_space.PercentageResolutionBlockSize() !=
+ old_space.PercentageResolutionBlockSize())
+ return true;
+ if (new_space.ReplacedPercentageResolutionBlockSize() !=
+ old_space.ReplacedPercentageResolutionBlockSize())
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Return true if it's possible (but not necessarily guaranteed) that the new
// constraint space will give a different size compared to the old one, when
// computed style and child content remain unchanged.
@@ -79,16 +119,9 @@ bool SizeMayChange(const NGBlockNode& node,
const NGConstraintSpace& new_space,
const NGConstraintSpace& old_space,
const NGLayoutResult& layout_result) {
- if (node.IsQuirkyAndFillsViewport())
- return true;
-
DCHECK_EQ(new_space.IsFixedInlineSize(), old_space.IsFixedInlineSize());
- DCHECK_EQ(new_space.IsFixedBlockSize(), old_space.IsFixedBlockSize());
- DCHECK_EQ(new_space.IsFixedBlockSizeIndefinite(),
- old_space.IsFixedBlockSizeIndefinite());
- DCHECK_EQ(new_space.IsShrinkToFit(), old_space.IsShrinkToFit());
- DCHECK_EQ(new_space.TableCellChildLayoutMode(),
- old_space.TableCellChildLayoutMode());
+ DCHECK_EQ(new_space.StretchInlineSizeIfAuto(),
+ old_space.StretchInlineSizeIfAuto());
const ComputedStyle& style = node.Style();
@@ -119,27 +152,6 @@ bool SizeMayChange(const NGBlockNode& node,
return true;
}
- if (new_space.IsFixedBlockSize()) {
- if (new_space.AvailableSize().block_size !=
- old_space.AvailableSize().block_size)
- return true;
- } else {
- if (BlockLengthMayChange(style.LogicalHeight(), new_space, old_space) ||
- BlockLengthMayChange(style.LogicalMinHeight(), new_space, old_space) ||
- BlockLengthMayChange(style.LogicalMaxHeight(), new_space, old_space))
- return true;
- // We only need to check if the PercentageResolutionBlockSizes match if the
- // layout result has explicitly marked itself as dependent.
- if (layout_result.PhysicalFragment().DependsOnPercentageBlockSize()) {
- if (new_space.PercentageResolutionBlockSize() !=
- old_space.PercentageResolutionBlockSize())
- return true;
- if (new_space.ReplacedPercentageResolutionBlockSize() !=
- old_space.ReplacedPercentageResolutionBlockSize())
- return true;
- }
- }
-
if (style.MayHavePadding() &&
new_space.PercentageResolutionInlineSize() !=
old_space.PercentageResolutionInlineSize()) {
@@ -152,7 +164,7 @@ bool SizeMayChange(const NGBlockNode& node,
return true;
}
- return false;
+ return BlockSizeMayChange(node, new_space, old_space, layout_result);
}
// Given the pre-computed |fragment_geometry| calcuates the
@@ -178,9 +190,28 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
if (fragment_geometry.border_box_size.inline_size != fragment.InlineSize())
return NGLayoutCacheStatus::kNeedsLayout;
+ if (style.MayHavePadding() && fragment_geometry.padding != fragment.Padding())
+ return NGLayoutCacheStatus::kNeedsLayout;
+
+ // Tables are special - we can't determine the final block-size ahead of time
+ // (or based on the previous intrinsic size).
+ // Instead if the block-size *may* change, force a layout. If we definitely
+ // know the block-size won't change (the size constraints haven't changed) we
+ // can hit the cache.
+ //
+ // *NOTE* - any logic below this branch shouldn't apply to tables.
+ if (node.IsTable()) {
+ if (!new_space.AreBlockSizeConstraintsEqual(old_space) ||
+ BlockSizeMayChange(node, new_space, old_space, layout_result))
+ return NGLayoutCacheStatus::kNeedsLayout;
+ return NGLayoutCacheStatus::kHit;
+ }
+
LayoutUnit block_size = fragment_geometry.border_box_size.block_size;
bool is_initial_block_size_indefinite = block_size == kIndefiniteSize;
if (is_initial_block_size_indefinite) {
+ LayoutUnit intrinsic_block_size = layout_result.IntrinsicBlockSize();
+
if (node.IsFlexibleBox()) {
// Flex-boxes can have their children calculate their size based in their
// parent's final block-size. E.g.
@@ -198,8 +229,8 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// </div>
//
// If the previous |layout_result| was produced by a space which had a
- // fixed block-size we can't use |NGLayoutResult::IntrinsicBlockSize()|,
- // and need to layout.
+ // fixed block-size we can't use |intrinsic_block_size| for determining
+ // the new block-size.
//
// TODO(ikilpatrick): Similar to %-block-size descendants we could store
// a bit on the |NGLayoutResult| which indicates if it had a child which
@@ -209,7 +240,7 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// TODO(ikilaptrick): This may occur for other layout modes, e.g.
// grid/custom-layout/etc.
if (old_space.IsFixedBlockSize())
- return NGLayoutCacheStatus::kNeedsLayout;
+ intrinsic_block_size = kIndefiniteSize;
// The intrinsic size of flex-boxes can depend on the %-block-size. This
// occurs when:
@@ -217,21 +248,23 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// - A row flex-box has "height: 100%" (or similar) and children which
// stretch to this size.
//
- // Due to this we can't use cached |NGLayoutResult::IntrinsicBlockSize|
- // value, as the following |block_size| calculation would be incorrect.
+ // Due to this we can't use the |intrinsic_block_size| value, as the
+ // following |block_size| calculation would be incorrect.
// TODO(dgrogan): We can hit the cache here for row flexboxes when they
// don't have stretchy children.
- if (physical_fragment.DependsOnPercentageBlockSize()) {
- if (new_space.PercentageResolutionBlockSize() !=
- old_space.PercentageResolutionBlockSize())
- return NGLayoutCacheStatus::kNeedsLayout;
- }
+ if (physical_fragment.DependsOnPercentageBlockSize() &&
+ new_space.PercentageResolutionBlockSize() !=
+ old_space.PercentageResolutionBlockSize())
+ intrinsic_block_size = kIndefiniteSize;
}
block_size = ComputeBlockSizeForFragment(
new_space, style, fragment_geometry.border + fragment_geometry.padding,
- layout_result.IntrinsicBlockSize(),
- fragment_geometry.border_box_size.inline_size);
+ intrinsic_block_size, fragment_geometry.border_box_size.inline_size,
+ node.ShouldBeConsideredAsReplaced());
+
+ if (block_size == kIndefiniteSize)
+ return NGLayoutCacheStatus::kNeedsLayout;
}
bool is_block_size_equal = block_size == fragment.BlockSize();
@@ -271,17 +304,12 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// percentages against a fixed block-size.
// We miss the cache if the %-resolution block-size changes from indefinite
// to definite (or visa-versa).
- bool is_new_initial_block_size_indefinite =
- new_space.IsFixedBlockSize() ? new_space.IsFixedBlockSizeIndefinite()
- : is_initial_block_size_indefinite;
bool is_old_initial_block_size_indefinite =
- old_space.IsFixedBlockSize()
- ? old_space.IsFixedBlockSizeIndefinite()
- : layout_result.IsInitialBlockSizeIndefinite();
+ layout_result.IsInitialBlockSizeIndefinite();
if (is_old_initial_block_size_indefinite !=
- is_new_initial_block_size_indefinite)
+ is_initial_block_size_indefinite)
return NGLayoutCacheStatus::kNeedsLayout;
// %-block-size children of table-cells have different behaviour if they
@@ -294,10 +322,10 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// If our initial block-size is definite, we know that if we change our
// block-size we'll affect any descendant that depends on the resulting
// percentage block-size.
- if (!is_block_size_equal && !is_new_initial_block_size_indefinite)
+ if (!is_block_size_equal && !is_initial_block_size_indefinite)
return NGLayoutCacheStatus::kNeedsLayout;
- DCHECK(is_block_size_equal || is_new_initial_block_size_indefinite);
+ DCHECK(is_block_size_equal || is_initial_block_size_indefinite);
// At this point we know that either we have the same block-size for our
// fragment, or our initial block-size was indefinite.
@@ -310,7 +338,7 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// As we only care about the quirks-mode %-block-size behaviour we remove
// this false-positive by checking if we have an initial indefinite
// block-size.
- if (is_new_initial_block_size_indefinite &&
+ if (is_initial_block_size_indefinite &&
physical_fragment.DependsOnPercentageBlockSize()) {
DCHECK(is_old_initial_block_size_indefinite);
if (new_space.PercentageResolutionBlockSize() !=
@@ -322,9 +350,6 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
}
}
- if (style.MayHavePadding() && fragment_geometry.padding != fragment.Padding())
- return NGLayoutCacheStatus::kNeedsLayout;
-
// Table-cells with vertical alignment might shift their contents if the
// block-size changes.
if (new_space.IsTableCell()) {
@@ -380,6 +405,7 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// If we've reached here we know that we can potentially "stretch"/"shrink"
// ourselves without affecting any of our children.
// In that case we may be able to perform "simplified" layout.
+ DCHECK(!node.IsTable());
return is_block_size_equal ? NGLayoutCacheStatus::kHit
: NGLayoutCacheStatus::kNeedsSimplifiedLayout;
}
@@ -390,7 +416,7 @@ bool IntrinsicSizeWillChange(
const NGConstraintSpace& new_space,
base::Optional<NGFragmentGeometry>* fragment_geometry) {
const ComputedStyle& style = node.Style();
- if (!new_space.IsShrinkToFit() && !NeedMinMaxSize(style))
+ if (new_space.StretchInlineSizeIfAuto() && !NeedMinMaxSize(style))
return false;
if (!*fragment_geometry)
@@ -421,7 +447,8 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatus(
if (!new_space.MaySkipLayout(old_space))
return NGLayoutCacheStatus::kNeedsLayout;
- if (new_space.AreSizeConstraintsEqual(old_space)) {
+ if (new_space.AreInlineSizeConstraintsEqual(old_space) &&
+ new_space.AreBlockSizeConstraintsEqual(old_space)) {
// It is possible that our intrinsic size has changed, check for that here.
// TODO(cbiesinger): Investigate why this check doesn't apply to
// |MaySkipLegacyLayout|.
@@ -457,7 +484,10 @@ bool MaySkipLegacyLayout(const NGBlockNode& node,
if (!new_space.MaySkipLayout(old_space))
return false;
- if (!new_space.AreSizeConstraintsEqual(old_space))
+ if (!new_space.AreInlineSizeConstraintsEqual(old_space))
+ return false;
+
+ if (!new_space.AreBlockSizeConstraintsEqual(old_space))
return false;
if (new_space.AreSizesEqual(old_space))
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 30b98b3f886..aad01cecba1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include "base/optional.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
@@ -59,10 +60,13 @@ inline EBlockAlignment BlockAlignment(const ComputedStyle& style,
// Check if we shouldn't resolve a percentage/calc()/-webkit-fill-available
// if we are in the intrinsic sizes phase.
-bool InlineLengthUnresolvable(const Length& length, LengthResolvePhase phase) {
- if (phase == LengthResolvePhase::kIntrinsic &&
- (length.IsPercentOrCalc() || length.IsFillAvailable()))
- return true;
+bool InlineLengthUnresolvable(const NGConstraintSpace& constraint_space,
+ const Length& length) {
+ if (length.IsPercentOrCalc())
+ return constraint_space.PercentageResolutionInlineSize() == kIndefiniteSize;
+
+ if (length.IsFillAvailable())
+ return constraint_space.AvailableSize().inline_size == kIndefiniteSize;
return false;
}
@@ -72,15 +76,11 @@ bool InlineLengthUnresolvable(const Length& length, LengthResolvePhase phase) {
bool BlockLengthUnresolvable(
const NGConstraintSpace& constraint_space,
const Length& length,
- LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max) {
if (length.IsAuto() || length.IsMinContent() || length.IsMaxContent() ||
length.IsMinIntrinsic() || length.IsFitContent() || length.IsNone())
return true;
if (length.IsPercentOrCalc()) {
- if (phase == LengthResolvePhase::kIntrinsic)
- return true;
-
LayoutUnit percentage_resolution_block_size =
opt_percentage_resolution_block_size_for_min_max
? *opt_percentage_resolution_block_size_for_min_max
@@ -88,10 +88,8 @@ bool BlockLengthUnresolvable(
return percentage_resolution_block_size == kIndefiniteSize;
}
- if (length.IsFillAvailable()) {
- return phase == LengthResolvePhase::kIntrinsic ||
- constraint_space.AvailableSize().block_size == kIndefiniteSize;
- }
+ if (length.IsFillAvailable())
+ return constraint_space.AvailableSize().block_size == kIndefiniteSize;
return false;
}
@@ -102,13 +100,11 @@ LayoutUnit ResolveInlineLengthInternal(
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSizes>& min_max_sizes,
const Length& length) {
- DCHECK_GE(constraint_space.AvailableSize().inline_size, LayoutUnit());
- DCHECK_GE(constraint_space.PercentageResolutionInlineSize(), LayoutUnit());
DCHECK_EQ(constraint_space.GetWritingMode(), style.GetWritingMode());
switch (length.GetType()) {
- case Length::kAuto:
case Length::kFillAvailable: {
+ DCHECK_GE(constraint_space.AvailableSize().inline_size, LayoutUnit());
LayoutUnit content_size = constraint_space.AvailableSize().inline_size;
NGBoxStrut margins = ComputeMarginsForSelf(constraint_space, style);
return std::max(border_padding.InlineSum(),
@@ -119,13 +115,14 @@ LayoutUnit ResolveInlineLengthInternal(
case Length::kCalculated: {
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionInlineSize();
+ DCHECK(length.IsFixed() || percentage_resolution_size != kIndefiniteSize);
LayoutUnit value =
MinimumValueForLength(length, percentage_resolution_size);
- if (style.BoxSizing() == EBoxSizing::kContentBox) {
- value += border_padding.InlineSum();
- } else {
+
+ if (style.BoxSizing() == EBoxSizing::kBorderBox)
value = std::max(border_padding.InlineSum(), value);
- }
+ else
+ value += border_padding.InlineSum();
return value;
}
case Length::kMinContent:
@@ -135,13 +132,15 @@ LayoutUnit ResolveInlineLengthInternal(
DCHECK(min_max_sizes.has_value());
LayoutUnit available_size = constraint_space.AvailableSize().inline_size;
LayoutUnit value;
- if (length.IsMinContent() || length.IsMinIntrinsic()) {
+ // TODO(ikilpatrick): The |IsFitContent()| might not be correct for a
+ // max-size, e.g. "max-width: fit-content".
+ if (length.IsMinContent() || length.IsMinIntrinsic() ||
+ (length.IsFitContent() && available_size == kIndefiniteSize)) {
value = min_max_sizes->min_size;
- } else if (length.IsMaxContent() || available_size == LayoutUnit::Max()) {
- // If the available space is infinite, fit-content resolves to
- // max-content. See css-sizing section 2.1.
+ } else if (length.IsMaxContent()) {
value = min_max_sizes->max_size;
} else {
+ DCHECK_GE(available_size, LayoutUnit());
NGBoxStrut margins = ComputeMarginsForSelf(constraint_space, style);
LayoutUnit fill_available =
std::max(LayoutUnit(), available_size - margins.InlineSum());
@@ -154,6 +153,7 @@ LayoutUnit ResolveInlineLengthInternal(
case Length::kExtendToZoom:
NOTREACHED() << "These should only be used for viewport definitions";
FALLTHROUGH;
+ case Length::kAuto:
case Length::kNone:
default:
NOTREACHED();
@@ -167,42 +167,37 @@ LayoutUnit ResolveBlockLengthInternal(
const NGBoxStrut& border_padding,
const Length& length,
LayoutUnit intrinsic_size,
+ LayoutUnit available_block_size_adjustment,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max) {
DCHECK_EQ(constraint_space.GetWritingMode(), style.GetWritingMode());
switch (length.GetType()) {
case Length::kFillAvailable: {
- LayoutUnit content_size = constraint_space.AvailableSize().block_size;
+ DCHECK_GE(constraint_space.AvailableSize().block_size, LayoutUnit());
+ LayoutUnit available_size = (constraint_space.AvailableSize().block_size -
+ available_block_size_adjustment)
+ .ClampNegativeToZero();
NGBoxStrut margins = ComputeMarginsForSelf(constraint_space, style);
return std::max(border_padding.BlockSum(),
- content_size - margins.BlockSum());
+ available_size - margins.BlockSum());
}
case Length::kPercent:
case Length::kFixed:
case Length::kCalculated: {
- LayoutUnit percentage_resolution_block_size =
+ LayoutUnit percentage_resolution_size =
opt_percentage_resolution_block_size_for_min_max
? *opt_percentage_resolution_block_size_for_min_max
: constraint_space.PercentageResolutionBlockSize();
+ DCHECK(length.IsFixed() || percentage_resolution_size != kIndefiniteSize);
LayoutUnit value =
- MinimumValueForLength(length, percentage_resolution_block_size);
-
- // Percentage-sized children of table cells, in the table "layout" phase,
- // pretend they have box-sizing: border-box.
- // TODO(crbug.com/285744): FF/Edge don't do this. Determine if there
- // would be compat issues for matching their behavior.
- if (style.BoxSizing() == EBoxSizing::kBorderBox ||
- (!RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
- length.IsPercentOrCalc() &&
- constraint_space.TableCellChildLayoutMode() ==
- NGTableCellChildLayoutMode::kLayout)) {
+ MinimumValueForLength(length, percentage_resolution_size);
+
+ if (style.BoxSizing() == EBoxSizing::kBorderBox)
value = std::max(border_padding.BlockSum(), value);
- } else {
+ else
value += border_padding.BlockSum();
- }
return value;
}
- case Length::kAuto:
case Length::kMinContent:
case Length::kMaxContent:
case Length::kMinIntrinsic:
@@ -212,7 +207,7 @@ LayoutUnit ResolveBlockLengthInternal(
// border and padding. We cannot check for this if we are
// block-fragmented, though, because then the block-start border/padding
// may be in a different fragmentainer than the block-end border/padding.
- if (intrinsic_size != LayoutUnit(-1) &&
+ if (intrinsic_size != kIndefiniteSize &&
!constraint_space.HasBlockFragmentation())
DCHECK_GE(intrinsic_size, border_padding.BlockSum());
#endif // DCHECK_IS_ON()
@@ -222,6 +217,7 @@ LayoutUnit ResolveBlockLengthInternal(
case Length::kExtendToZoom:
NOTREACHED() << "These should only be used for viewport definitions";
FALLTHROUGH;
+ case Length::kAuto:
case Length::kNone:
default:
NOTREACHED();
@@ -229,42 +225,58 @@ LayoutUnit ResolveBlockLengthInternal(
}
}
+// logical_aspect_ratio is inline_size / block_size.
LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
- const LogicalSize& aspect_ratio,
+ double logical_aspect_ratio,
EBoxSizing box_sizing,
LayoutUnit block_size) {
// TODO(dgrogan/ikilpatrick): These calculations might need to be done in
// integer space, in a potential BoundedMultiplyAndDivide(LayoutUnit,
// LayoutUnit, LayoutUnit) function.
if (box_sizing == EBoxSizing::kBorderBox) {
- return LayoutUnit::FromDoubleRound(block_size *
- aspect_ratio.inline_size.ToDouble() /
- aspect_ratio.block_size.ToDouble());
+ return LayoutUnit::FromDoubleRound(block_size * logical_aspect_ratio);
}
return LayoutUnit::FromDoubleRound((block_size - border_padding.BlockSum()) *
- aspect_ratio.inline_size.ToDouble() /
- aspect_ratio.block_size.ToDouble()) +
+ logical_aspect_ratio) +
border_padding.InlineSum();
}
+LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
+ const LogicalSize& aspect_ratio,
+ EBoxSizing box_sizing,
+ LayoutUnit block_size) {
+ return InlineSizeFromAspectRatio(
+ border_padding,
+ aspect_ratio.inline_size.ToDouble() / aspect_ratio.block_size.ToDouble(),
+ box_sizing, block_size);
+}
+
+// logical_aspect_ratio is block_size / inline_size.
LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
- const LogicalSize& aspect_ratio,
+ double logical_aspect_ratio,
EBoxSizing box_sizing,
LayoutUnit inline_size) {
if (box_sizing == EBoxSizing::kBorderBox) {
- return LayoutUnit::FromDoubleRound(inline_size *
- aspect_ratio.block_size.ToDouble() /
- aspect_ratio.inline_size.ToDouble());
+ return LayoutUnit::FromDoubleRound(inline_size * logical_aspect_ratio);
}
return LayoutUnit::FromDoubleRound(
(inline_size - border_padding.InlineSum()) *
- aspect_ratio.block_size.ToDouble() /
- aspect_ratio.inline_size.ToDouble()) +
+ logical_aspect_ratio) +
border_padding.BlockSum();
}
+LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
+ const LogicalSize& aspect_ratio,
+ EBoxSizing box_sizing,
+ LayoutUnit inline_size) {
+ return BlockSizeFromAspectRatio(
+ border_padding,
+ aspect_ratio.block_size.ToDouble() / aspect_ratio.inline_size.ToDouble(),
+ box_sizing, inline_size);
+}
+
namespace {
template <typename MinMaxSizesFunc>
@@ -273,13 +285,14 @@ MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
const NGBlockNode& child,
const MinMaxSizesFunc& min_max_sizes_func) {
const ComputedStyle& style = child.Style();
- WritingMode child_writing_mode = style.GetWritingMode();
- // Synthesize a zero-sized constraint space for resolving sizes against.
- NGConstraintSpace space =
+ const WritingMode child_writing_mode = style.GetWritingMode();
+
+ // Synthesize an indefinite space for resolving sizes against.
+ const NGConstraintSpace space =
NGConstraintSpaceBuilder(child_writing_mode, style.GetWritingDirection(),
/* is_new_fc */ false)
.ToConstraintSpace();
- NGBoxStrut border_padding =
+ const NGBoxStrut border_padding =
ComputeBorders(space, child) + ComputePadding(space, style);
MinMaxSizesResult result;
@@ -295,7 +308,8 @@ MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
MinMaxSizes sizes;
sizes = ResolveMainInlineLength(space, style, border_padding,
min_max_sizes_func, inline_size);
- result = {sizes, /* depends_on_percentage_block_size */ false};
+ result = MinMaxSizesResult(sizes,
+ /* depends_on_percentage_block_size */ false);
} else {
auto IntrinsicBlockSizeFunc = [&]() -> LayoutUnit {
return min_max_sizes_func(inline_size.IsMinIntrinsic()
@@ -305,9 +319,9 @@ MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
};
MinMaxSizes sizes;
sizes = ResolveMainBlockLength(space, style, border_padding, inline_size,
- IntrinsicBlockSizeFunc,
- LengthResolvePhase::kIntrinsic);
- result = {sizes, /* depends_on_percentage_block_size */ false};
+ IntrinsicBlockSizeFunc);
+ result = MinMaxSizesResult(sizes,
+ /* depends_on_percentage_block_size */ false);
}
}
@@ -316,12 +330,10 @@ MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
: style.MaxHeight();
LayoutUnit max;
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- max =
- ResolveMaxInlineLength(space, style, border_padding, min_max_sizes_func,
- max_length, LengthResolvePhase::kIntrinsic);
+ max = ResolveMaxInlineLength(space, style, border_padding,
+ min_max_sizes_func, max_length);
} else {
- max = ResolveMaxBlockLength(space, style, border_padding, max_length,
- LengthResolvePhase::kIntrinsic);
+ max = ResolveMaxBlockLength(space, style, border_padding, max_length);
}
result.sizes.Constrain(max);
@@ -330,32 +342,53 @@ MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
: style.MinHeight();
LayoutUnit min;
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- min =
- ResolveMinInlineLength(space, style, border_padding, min_max_sizes_func,
- min_length, LengthResolvePhase::kIntrinsic);
+ min = ResolveMinInlineLength(space, style, border_padding,
+ min_max_sizes_func, min_length);
} else {
- min = ResolveMinBlockLength(space, style, border_padding, min_length,
- LengthResolvePhase::kIntrinsic);
+ min = ResolveMinBlockLength(space, style, border_padding, min_length);
}
result.sizes.Encompass(min);
+ // Tables need to apply one final constraint. They are never allowed to go
+ // below their min-intrinsic size (even if they have an inline-size, etc).
+ if (child.IsNGTable()) {
+ result.sizes.Encompass(
+ min_max_sizes_func(MinMaxSizesType::kIntrinsic).sizes.min_size);
+ }
+
return result;
}
-} // namespace
-
-MinMaxSizes ComputeMinAndMaxContentContributionForTest(
- WritingMode parent_writing_mode,
+// Currently this simply sets the correct override sizes for the replaced
+// element, and lets legacy layout do the result.
+MinMaxSizesResult ComputeMinAndMaxContentContributionForReplaced(
const NGBlockNode& child,
- const MinMaxSizes& min_max_sizes) {
- auto MinMaxSizesFunc = [&](MinMaxSizesType) -> MinMaxSizesResult {
- return {min_max_sizes, false};
- };
- return ComputeMinAndMaxContentContributionInternal(parent_writing_mode, child,
- MinMaxSizesFunc)
- .sizes;
+ const MinMaxSizesInput& input) {
+ const ComputedStyle& child_style = child.Style();
+ LayoutBox* box = child.GetLayoutBox();
+ bool needs_size_reset = false;
+ if (!box->HasOverrideContainingBlockContentLogicalHeight()) {
+ box->SetOverrideContainingBlockContentLogicalHeight(
+ input.percentage_resolution_block_size);
+ needs_size_reset = true;
+ }
+
+ MinMaxSizes result = box->PreferredLogicalWidths();
+
+ if (needs_size_reset)
+ box->ClearOverrideContainingBlockContentSize();
+
+ // Replaced elements which have a percentage block-size use the
+ // |MinMaxSizesInput::percentage_resolution_block_size| field.
+ bool depends_on_percentage_block_size =
+ child_style.LogicalMinHeight().IsPercentOrCalc() ||
+ child_style.LogicalHeight().IsPercentOrCalc() ||
+ child_style.LogicalMaxHeight().IsPercentOrCalc();
+ return MinMaxSizesResult(result, depends_on_percentage_block_size);
}
+} // namespace
+
MinMaxSizesResult ComputeMinAndMaxContentContribution(
const ComputedStyle& parent_style,
const NGBlockNode& child,
@@ -365,35 +398,12 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution(
WritingMode child_writing_mode = child_style.GetWritingMode();
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- // Tables are special; even if a width is specified, they may end up being
- // sized different. So we just always let the table code handle this.
- if (child.IsTable())
+ // Legacy tables are special - always let the legacy table code handle this.
+ if (child.IsTable() && !child.IsNGTable())
return child.ComputeMinMaxSizes(parent_writing_mode, input, nullptr);
- // Replaced elements may size themselves using aspect ratios and block
- // sizes, so we pass that on as well.
- if (child.IsReplaced()) {
- LayoutBox* box = child.GetLayoutBox();
- bool needs_size_reset = false;
- if (!box->HasOverrideContainingBlockContentLogicalHeight()) {
- box->SetOverrideContainingBlockContentLogicalHeight(
- input.percentage_resolution_block_size);
- needs_size_reset = true;
- }
-
- MinMaxSizes result = box->PreferredLogicalWidths();
-
- if (needs_size_reset)
- box->ClearOverrideContainingBlockContentSize();
-
- // Replaced elements which have a percentage block-size use the
- // |MinMaxSizesInput::percentage_resolution_block_size| field.
- bool depends_on_percentage_block_size =
- child_style.LogicalMinHeight().IsPercentOrCalc() ||
- child_style.LogicalHeight().IsPercentOrCalc() ||
- child_style.LogicalMaxHeight().IsPercentOrCalc();
- return {result, depends_on_percentage_block_size};
- }
+ if (child.IsReplaced())
+ return ComputeMinAndMaxContentContributionForReplaced(child, input);
}
auto MinMaxSizesFunc = [&](MinMaxSizesType type) -> MinMaxSizesResult {
@@ -416,10 +426,48 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution(
MinMaxSizesFunc);
}
-LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace& space,
- const ComputedStyle& style,
- const NGBoxStrut& border_padding,
- LayoutUnit block_size) {
+MinMaxSizesResult ComputeMinAndMaxContentContributionForSelf(
+ const NGBlockNode& child,
+ const MinMaxSizesInput& input) {
+ const ComputedStyle& child_style = child.Style();
+ WritingMode writing_mode = child_style.GetWritingMode();
+
+ // Legacy tables are special - always let the legacy table code handle this.
+ if (child.IsTable() && !child.IsNGTable())
+ return child.ComputeMinMaxSizes(writing_mode, input, nullptr);
+
+ if (child.IsReplaced())
+ return ComputeMinAndMaxContentContributionForReplaced(child, input);
+
+ auto MinMaxSizesFunc = [&](MinMaxSizesType type) -> MinMaxSizesResult {
+ MinMaxSizesInput input_copy(input);
+ input_copy.type = type;
+ return child.ComputeMinMaxSizes(writing_mode, input_copy);
+ };
+
+ return ComputeMinAndMaxContentContributionInternal(writing_mode, child,
+ MinMaxSizesFunc);
+}
+
+MinMaxSizes ComputeMinAndMaxContentContributionForTest(
+ WritingMode parent_writing_mode,
+ const NGBlockNode& child,
+ const MinMaxSizes& min_max_sizes) {
+ auto MinMaxSizesFunc = [&](MinMaxSizesType) -> MinMaxSizesResult {
+ return MinMaxSizesResult(min_max_sizes,
+ /* depends_on_percentage_block_size */ false);
+ };
+ return ComputeMinAndMaxContentContributionInternal(parent_writing_mode, child,
+ MinMaxSizesFunc)
+ .sizes;
+}
+
+LayoutUnit ComputeInlineSizeFromAspectRatio(
+ const NGConstraintSpace& space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ bool should_be_considered_as_replaced,
+ LayoutUnit block_size) {
if (LIKELY(style.AspectRatio().IsAuto()))
return kIndefiniteSize;
@@ -429,94 +477,118 @@ LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace& space,
} else if (!style.LogicalHeight().IsAuto()) {
DCHECK(!style.HasOutOfFlowPosition())
<< "OOF should pass in a block size";
- block_size = ComputeBlockSizeForFragment(space, style, border_padding,
- kIndefiniteSize, base::nullopt);
+ block_size = ComputeBlockSizeForFragment(
+ space, style, border_padding, kIndefiniteSize, base::nullopt,
+ should_be_considered_as_replaced);
}
if (block_size == kIndefiniteSize)
return kIndefiniteSize;
}
// Check if we can get an inline size using the aspect ratio.
return InlineSizeFromAspectRatio(border_padding, style.LogicalAspectRatio(),
- style.BoxSizing(), block_size);
+ style.BoxSizingForAspectRatio(), block_size);
}
-LayoutUnit ComputeInlineSizeForFragment(
+namespace {
+
+LayoutUnit ComputeInlineSizeForFragmentInternal(
const NGConstraintSpace& space,
NGLayoutInputNode node,
const NGBoxStrut& border_padding,
- const MinMaxSizes* override_min_max_sizes_for_test) {
- if (space.IsFixedInlineSize() || space.IsAnonymous())
- return space.AvailableSize().inline_size;
- if (node.IsNGTable())
- return To<NGTableNode>(node).ComputeTableInlineSize(space, border_padding);
-
- const ComputedStyle& style = node.Style();
- Length logical_width = style.LogicalWidth();
+ const MinMaxSizes* override_min_max_sizes) {
auto MinMaxSizesFunc = [&](MinMaxSizesType type) -> MinMaxSizesResult {
- if (override_min_max_sizes_for_test)
- return {*override_min_max_sizes_for_test, false};
+ if (override_min_max_sizes) {
+ return MinMaxSizesResult(*override_min_max_sizes,
+ /* depends_on_percentage_block_size */ false);
+ }
MinMaxSizesInput input(space.PercentageResolutionBlockSize(), type);
return node.ComputeMinMaxSizes(space.GetWritingMode(), input, &space);
};
+ const ComputedStyle& style = node.Style();
+ Length logical_width = style.LogicalWidth();
Length min_length = style.LogicalMinWidth();
- // TODO(cbiesinger): Audit callers of ResolveMainInlineLength to see
- // whether they need to respect aspect ratio and consider adding a helper
- // function for that.
+
+ // TODO(ikilpatrick): If we are stretching in both the inline-axis, and
+ // block-axis, we shouldn't apply the aspect-ratio.
+ // TODO(cbiesinger): Should the if also check !node.IsReplaced()?
LayoutUnit extent = kIndefiniteSize;
- if (!style.AspectRatio().IsAuto() && logical_width.IsAuto())
- extent = ComputeInlineSizeFromAspectRatio(space, style, border_padding);
- if (UNLIKELY(extent != kIndefiniteSize)) {
- // This means we successfully applied aspect-ratio and now need to check
- // if we need to apply the implied minimum size:
- // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
- if (style.OverflowInlineDirection() == EOverflow::kVisible &&
- min_length.IsAuto()) {
- min_length = Length::MinIntrinsic();
+ if (!style.AspectRatio().IsAuto()) {
+ if (logical_width.IsAuto() || logical_width.IsMinContent() ||
+ logical_width.IsMaxContent()) {
+ extent = ComputeInlineSizeFromAspectRatio(
+ space, style, border_padding, node.ShouldBeConsideredAsReplaced());
+ }
+ if (UNLIKELY(extent != kIndefiniteSize)) {
+ // This means we successfully applied aspect-ratio and now need to check
+ // if we need to apply the implied minimum size:
+ // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
+ if (style.OverflowInlineDirection() == EOverflow::kVisible &&
+ min_length.IsAuto())
+ min_length = Length::MinIntrinsic();
+ }
+ }
+
+ if (LIKELY(extent == kIndefiniteSize)) {
+ if (logical_width.IsAuto()) {
+ logical_width = space.StretchInlineSizeIfAuto() ? Length::FillAvailable()
+ : Length::FitContent();
}
- } else {
- if (logical_width.IsAuto() && space.IsShrinkToFit())
- logical_width = Length::FitContent();
extent = ResolveMainInlineLength(space, style, border_padding,
MinMaxSizesFunc, logical_width);
}
- // This implements the transferred min/max sizes per
- // https://drafts.csswg.org/css-sizing-4/#aspect-ratio
- if (!style.AspectRatio().IsAuto() &&
- BlockLengthUnresolvable(space, style.LogicalHeight(),
- LengthResolvePhase::kLayout)) {
- MinMaxSizes transferred_min_max = ComputeMinMaxInlineSizesFromAspectRatio(
- space, style, border_padding, LengthResolvePhase::kLayout);
- extent = transferred_min_max.ClampSizeToMinAndMax(extent);
- }
+ const MinMaxSizes min_max_sizes = ComputeMinMaxInlineSizes(
+ space, style, border_padding, MinMaxSizesFunc, &min_length);
+ return min_max_sizes.ClampSizeToMinAndMax(extent);
+}
- MinMaxSizes min_max{
- ResolveMinInlineLength(space, style, border_padding, MinMaxSizesFunc,
- min_length, LengthResolvePhase::kLayout),
- ResolveMaxInlineLength(space, style, border_padding, MinMaxSizesFunc,
- style.LogicalMaxWidth(),
- LengthResolvePhase::kLayout)};
- return min_max.ClampSizeToMinAndMax(extent);
+} // namespace
+
+LayoutUnit ComputeInlineSizeForFragment(
+ const NGConstraintSpace& space,
+ NGLayoutInputNode node,
+ const NGBoxStrut& border_padding,
+ const MinMaxSizes* override_min_max_sizes_for_test) {
+ if (space.IsFixedInlineSize() || space.IsAnonymous())
+ return space.AvailableSize().inline_size;
+
+ if (node.IsNGTable())
+ return To<NGTableNode>(node).ComputeTableInlineSize(space, border_padding);
+
+ return ComputeInlineSizeForFragmentInternal(space, node, border_padding,
+ override_min_max_sizes_for_test);
+}
+
+LayoutUnit ComputeUsedInlineSizeForTableFragment(
+ const NGConstraintSpace& space,
+ NGLayoutInputNode node,
+ const NGBoxStrut& border_padding,
+ const MinMaxSizes& table_grid_min_max_sizes) {
+ DCHECK(!space.IsFixedInlineSize());
+ return ComputeInlineSizeForFragmentInternal(space, node, border_padding,
+ &table_grid_min_max_sizes);
}
-MinMaxSizes ComputeMinMaxBlockSize(
+MinMaxSizes ComputeMinMaxBlockSizes(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
LayoutUnit intrinsic_size,
+ LayoutUnit available_block_size_adjustment,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max) {
- MinMaxSizes result;
- result.min_size = ResolveMinBlockLength(
- constraint_space, style, border_padding, style.LogicalMinHeight(),
- LengthResolvePhase::kLayout,
- opt_percentage_resolution_block_size_for_min_max);
- result.max_size = ResolveMaxBlockLength(
- constraint_space, style, border_padding, style.LogicalMaxHeight(),
- LengthResolvePhase::kLayout,
- opt_percentage_resolution_block_size_for_min_max);
- return result;
+ MinMaxSizes sizes = {
+ ResolveMinBlockLength(constraint_space, style, border_padding,
+ style.LogicalMinHeight(),
+ available_block_size_adjustment,
+ opt_percentage_resolution_block_size_for_min_max),
+ ResolveMaxBlockLength(constraint_space, style, border_padding,
+ style.LogicalMaxHeight(),
+ available_block_size_adjustment,
+ opt_percentage_resolution_block_size_for_min_max)};
+ sizes.max_size = std::max(sizes.max_size, sizes.min_size);
+ return sizes;
}
MinMaxSizes ComputeTransferredMinMaxInlineSizes(
@@ -542,8 +614,7 @@ MinMaxSizes ComputeTransferredMinMaxInlineSizes(
MinMaxSizes ComputeMinMaxInlineSizesFromAspectRatio(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
- const NGBoxStrut& border_padding,
- LengthResolvePhase phase) {
+ const NGBoxStrut& border_padding) {
DCHECK(!style.AspectRatio().IsAuto());
// The spec requires us to clamp these by the specified size (it calls it the
@@ -556,27 +627,30 @@ MinMaxSizes ComputeMinMaxInlineSizesFromAspectRatio(
LogicalSize ratio = style.LogicalAspectRatio();
MinMaxSizes block_min_max =
- ComputeMinMaxBlockSize(constraint_space, style, border_padding,
- /* intrinsic_size */ kIndefiniteSize);
- return ComputeTransferredMinMaxInlineSizes(ratio, block_min_max,
- border_padding, style.BoxSizing());
+ ComputeMinMaxBlockSizes(constraint_space, style, border_padding,
+ /* intrinsic_size */ kIndefiniteSize);
+ return ComputeTransferredMinMaxInlineSizes(
+ ratio, block_min_max, border_padding, style.BoxSizingForAspectRatio());
}
namespace {
// Computes the block-size for a fragment, ignoring the fixed block-size if set.
LayoutUnit ComputeBlockSizeForFragmentInternal(
- const NGConstraintSpace& constraint_space,
+ const NGConstraintSpace& space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
LayoutUnit intrinsic_size,
base::Optional<LayoutUnit> inline_size,
+ bool should_be_considered_as_replaced,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
- MinMaxSizes min_max = ComputeMinMaxBlockSize(
- constraint_space, style, border_padding, intrinsic_size,
- opt_percentage_resolution_block_size_for_min_max);
- const Length& logical_height = style.LogicalHeight();
+ MinMaxSizes min_max =
+ ComputeMinMaxBlockSizes(space, style, border_padding, intrinsic_size,
+ available_block_size_adjustment,
+ opt_percentage_resolution_block_size_for_min_max);
+ Length logical_height = style.LogicalHeight();
// Scrollable percentage-sized children of table cells, in the table
// "measure" phase contribute nothing to the row height measurement.
// See: https://drafts.csswg.org/css-tables-3/#row-layout
@@ -589,26 +663,30 @@ LayoutUnit ComputeBlockSizeForFragmentInternal(
// things to consider, would be checking the row and row-group, and also other
// properties, such as {min,max}-block-size.
if (logical_height.IsPercentOrCalc() &&
- constraint_space.TableCellChildLayoutMode() ==
+ space.TableCellChildLayoutMode() ==
NGTableCellChildLayoutMode::kMeasureRestricted &&
+ !should_be_considered_as_replaced &&
(style.OverflowBlockDirection() == EOverflow::kAuto ||
style.OverflowBlockDirection() == EOverflow::kScroll))
return min_max.min_size;
+ if (logical_height.IsAuto()) {
+ logical_height = space.StretchBlockSizeIfAuto() ? Length::FillAvailable()
+ : Length::FitContent();
+ }
// TODO(cbiesinger): Audit callers of ResolveMainBlockLength to see whether
// they need to respect aspect ratio.
- LayoutUnit extent = ResolveMainBlockLength(
- constraint_space, style, border_padding, logical_height, intrinsic_size,
- LengthResolvePhase::kLayout,
- opt_percentage_resolution_block_size_for_min_max);
+ LayoutUnit extent =
+ ResolveMainBlockLength(space, style, border_padding, logical_height,
+ intrinsic_size, available_block_size_adjustment,
+ opt_percentage_resolution_block_size_for_min_max);
if (UNLIKELY(!style.AspectRatio().IsAuto() && inline_size &&
BlockLengthUnresolvable(
- constraint_space, logical_height,
- LengthResolvePhase::kLayout,
+ space, logical_height,
opt_percentage_resolution_block_size_for_min_max))) {
extent =
BlockSizeFromAspectRatio(border_padding, style.LogicalAspectRatio(),
- style.BoxSizing(), *inline_size);
+ style.BoxSizingForAspectRatio(), *inline_size);
// Apply the automatic minimum size for aspect ratio:
// https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
// We also check for LayoutUnit::Max() because flexbox uses that as a
@@ -635,12 +713,21 @@ LayoutUnit ComputeBlockSizeForFragment(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
LayoutUnit intrinsic_size,
- base::Optional<LayoutUnit> inline_size) {
+ base::Optional<LayoutUnit> inline_size,
+ bool should_be_considered_as_replaced,
+ LayoutUnit available_block_size_adjustment) {
+ // The |available_block_size_adjustment| should only be used for <table>s.
+ DCHECK(available_block_size_adjustment == LayoutUnit() ||
+ style.IsDisplayTableBox());
+
if (constraint_space.IsLegacyTableCell() && intrinsic_size != kIndefiniteSize)
return intrinsic_size;
- if (constraint_space.IsFixedBlockSize())
- return constraint_space.AvailableSize().block_size;
+ if (constraint_space.IsFixedBlockSize()) {
+ return (constraint_space.AvailableSize().block_size -
+ available_block_size_adjustment)
+ .ClampNegativeToZero();
+ }
if (constraint_space.IsTableCell() && !constraint_space.IsLegacyTableCell() &&
intrinsic_size != kIndefiniteSize)
@@ -650,7 +737,8 @@ LayoutUnit ComputeBlockSizeForFragment(
return intrinsic_size;
return ComputeBlockSizeForFragmentInternal(
- constraint_space, style, border_padding, intrinsic_size, inline_size);
+ constraint_space, style, border_padding, intrinsic_size, inline_size,
+ should_be_considered_as_replaced, available_block_size_adjustment);
}
// Computes size for a replaced element.
@@ -667,33 +755,53 @@ void ComputeReplacedSize(const NGBlockNode& node,
NGBoxStrut border_padding =
ComputeBorders(space, node) + ComputePadding(space, style);
- LayoutUnit inline_min = ResolveMinInlineLength(
- space, style, border_padding, child_min_max_sizes,
- style.LogicalMinWidth(), LengthResolvePhase::kLayout);
- LayoutUnit inline_max = ResolveMaxInlineLength(
- space, style, border_padding, child_min_max_sizes,
- style.LogicalMaxWidth(), LengthResolvePhase::kLayout);
+ LayoutUnit inline_min =
+ ResolveMinInlineLength(space, style, border_padding, child_min_max_sizes,
+ style.LogicalMinWidth());
+ LayoutUnit inline_max =
+ ResolveMaxInlineLength(space, style, border_padding, child_min_max_sizes,
+ style.LogicalMaxWidth());
LayoutUnit block_min = ResolveMinBlockLength(space, style, border_padding,
- style.LogicalMinHeight(),
- LengthResolvePhase::kLayout);
+ style.LogicalMinHeight());
LayoutUnit block_max = ResolveMaxBlockLength(space, style, border_padding,
- style.LogicalMaxHeight(),
- LengthResolvePhase::kLayout);
+ style.LogicalMaxHeight());
const Length& inline_length = style.LogicalWidth();
const Length& block_length = style.LogicalHeight();
base::Optional<LayoutUnit> replaced_inline;
- if (!inline_length.IsAuto()) {
- replaced_inline = ResolveMainInlineLength(
- space, style, border_padding, child_min_max_sizes, inline_length);
+ if (space.IsFixedInlineSize()) {
+ replaced_inline = space.AvailableSize().inline_size;
+ DCHECK_GE(*replaced_inline, 0);
+ } else if (!inline_length.IsAuto() || space.StretchInlineSizeIfAuto()) {
+ Length inline_length_to_resolve = inline_length;
+ if (inline_length_to_resolve.IsAuto()) {
+ // TODO(dgrogan): This code block (and its corresponding block version
+ // below) didn't make any tests pass when written so it may be unnecessary
+ // or untested. Check again when launching ReplacedNG.
+ DCHECK(space.StretchInlineSizeIfAuto());
+ DCHECK(space.AvailableSize().inline_size != kIndefiniteSize);
+ inline_length_to_resolve = Length::FillAvailable();
+ }
+ replaced_inline =
+ ResolveMainInlineLength(space, style, border_padding,
+ child_min_max_sizes, inline_length_to_resolve);
replaced_inline =
ConstrainByMinMax(*replaced_inline, inline_min, inline_max);
}
base::Optional<LayoutUnit> replaced_block;
- if (!block_length.IsAuto()) {
- replaced_block = ResolveMainBlockLength(
- space, style, border_padding, block_length,
- space.AvailableSize().block_size, LengthResolvePhase::kLayout);
+ if (space.IsFixedBlockSize()) {
+ replaced_block = space.AvailableSize().block_size;
+ DCHECK_GE(*replaced_block, 0);
+ } else if (!block_length.IsAuto() || space.StretchBlockSizeIfAuto()) {
+ Length block_length_to_resolve = block_length;
+ if (block_length_to_resolve.IsAuto()) {
+ DCHECK(space.StretchBlockSizeIfAuto());
+ DCHECK(space.AvailableSize().block_size != kIndefiniteSize);
+ block_length_to_resolve = Length::FillAvailable();
+ }
+ replaced_block = ResolveMainBlockLength(space, style, border_padding,
+ block_length_to_resolve,
+ space.AvailableSize().block_size);
replaced_block = ConstrainByMinMax(*replaced_block, block_min, block_max);
}
if (replaced_inline && replaced_block) {
@@ -832,7 +940,6 @@ void ComputeReplacedSize(const NGBlockNode& node,
}
}
out_replaced_size->emplace(*replaced_inline, *replaced_block);
- return;
}
int ResolveUsedColumnCount(int computed_count,
@@ -896,12 +1003,25 @@ LayoutUnit ResolveUsedColumnGap(LayoutUnit available_size,
return LayoutUnit(style.GetFontDescription().ComputedPixelSize());
}
+LayoutUnit ColumnInlineProgression(LayoutUnit available_size,
+ const ComputedStyle& style) {
+ LayoutUnit column_inline_size =
+ ResolveUsedColumnInlineSize(available_size, style);
+ return column_inline_size + ResolveUsedColumnGap(available_size, style);
+}
+
NGPhysicalBoxStrut ComputePhysicalMargins(
const ComputedStyle& style,
LayoutUnit percentage_resolution_size) {
if (!style.MayHaveMargin())
return NGPhysicalBoxStrut();
+ // This function may be called for determining intrinsic margins, clamp
+ // indefinite %-sizes to zero. See:
+ // https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution
+ percentage_resolution_size =
+ percentage_resolution_size.ClampIndefiniteToZero();
+
return {
MinimumValueForLength(style.MarginTop(), percentage_resolution_size),
MinimumValueForLength(style.MarginRight(), percentage_resolution_size),
@@ -1016,15 +1136,20 @@ NGBoxStrut ComputePadding(const NGConstraintSpace& constraint_space,
return NGBoxStrut();
}
+ // This function may be called for determining intrinsic padding, clamp
+ // indefinite %-sizes to zero. See:
+ // https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution
LayoutUnit percentage_resolution_size =
- constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+ constraint_space.PercentageResolutionInlineSizeForParentWritingMode()
+ .ClampIndefiniteToZero();
NGBoxStrut padding = {
MinimumValueForLength(style.PaddingStart(), percentage_resolution_size),
MinimumValueForLength(style.PaddingEnd(), percentage_resolution_size),
MinimumValueForLength(style.PaddingBefore(), percentage_resolution_size),
MinimumValueForLength(style.PaddingAfter(), percentage_resolution_size)};
- if (style.Display() == EDisplay::kTableCell) {
+ if (!RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
+ style.Display() == EDisplay::kTableCell) {
// Compatibility hack to mach legacy layout. Legacy layout floors padding on
// the block sides, but not on the inline sides. o.O
padding.block_start = LayoutUnit(padding.block_start.Floor());
@@ -1118,8 +1243,6 @@ LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
}
}
-namespace {
-
// Calculates default content size for html and body elements in quirks mode.
// Returns |kIndefiniteSize| in all other cases.
LayoutUnit CalculateDefaultBlockSize(
@@ -1137,6 +1260,25 @@ LayoutUnit CalculateDefaultBlockSize(
return kIndefiniteSize;
}
+namespace {
+
+// Calculates default content size for html and body elements in quirks mode.
+// Returns |kIndefiniteSize| in all other cases.
+LayoutUnit ComputeInitialBlockSizeForFragment(
+ const NGConstraintSpace& space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ LayoutUnit intrinsic_size,
+ base::Optional<LayoutUnit> inline_size) {
+ if (space.IsFixedBlockSizeIndefinite())
+ return intrinsic_size;
+ // <html> and <body> should not be considered as replaced.
+ const bool should_be_considered_as_replaced = false;
+ return ComputeBlockSizeForFragment(space, style, border_padding,
+ intrinsic_size, inline_size,
+ should_be_considered_as_replaced);
+}
+
// Clamp the inline size of the scrollbar, unless it's larger than the inline
// size of the content box, in which case we'll return that instead. Scrollbar
// handling is quite bad in such situations, and this method here is just to
@@ -1162,6 +1304,7 @@ bool ClampScrollbarToContentBox(NGBoxStrut* scrollbars,
NGFragmentGeometry CalculateInitialFragmentGeometry(
const NGConstraintSpace& constraint_space,
const NGBlockNode& node) {
+ DCHECK(node.CanUseNewLayout());
const ComputedStyle& style = node.Style();
NGBoxStrut border = ComputeBorders(constraint_space, node);
NGBoxStrut padding = ComputePadding(constraint_space, style);
@@ -1183,13 +1326,49 @@ NGFragmentGeometry CalculateInitialFragmentGeometry(
node.GetLayoutBox()->ComputePercentageLogicalHeight(Length::Percent(0));
}
+ if (node.IsReplaced()) {
+ LogicalSize border_box_size;
+ MinMaxSizesInput min_max_input(
+ constraint_space.ReplacedPercentageResolutionBlockSize(),
+ MinMaxSizesType::kIntrinsic);
+ MinMaxSizes intrinsic_min_max_sizes =
+ node.ComputeMinMaxSizes(constraint_space.GetWritingMode(),
+ min_max_input)
+ .sizes;
+ base::Optional<LogicalSize> replaced_size;
+ base::Optional<LogicalSize> aspect_ratio;
+ ComputeReplacedSize(node, constraint_space, intrinsic_min_max_sizes,
+ &replaced_size, &aspect_ratio);
+ bool has_aspect_ratio_without_intrinsic_size =
+ !replaced_size && aspect_ratio && !aspect_ratio->IsEmpty();
+ if (has_aspect_ratio_without_intrinsic_size) {
+ // TODO(dgrogan): This doesn't obey min/max-width or transferred
+ // min/max-height or margins. Maybe use ResolveInlineLength with
+ // fill-available, then clamp with ComputeMinMaxInlineSizes after adapting
+ // it for Replaced elements. Or use ComputeInlineSizeForFragment with a
+ // ConstraintSpace with StretchInlineSizeIfAuto.
+ DCHECK_GE(constraint_space.AvailableSize().inline_size, LayoutUnit());
+ border_box_size.inline_size =
+ std::max(constraint_space.AvailableSize().inline_size,
+ border_padding.InlineSum());
+ border_box_size.block_size = BlockSizeFromAspectRatio(
+ border_padding, *aspect_ratio, EBoxSizing::kContentBox,
+ border_box_size.inline_size);
+ } else {
+ DCHECK(replaced_size.has_value())
+ << "Images should have at least one of aspect_ratio or replaced_size";
+ border_box_size = *replaced_size;
+ }
+ return {border_box_size, border, scrollbar, padding};
+ }
+
LayoutUnit default_block_size = CalculateDefaultBlockSize(
constraint_space, node, border_scrollbar_padding);
LayoutUnit inline_size =
ComputeInlineSizeForFragment(constraint_space, node, border_padding);
- LogicalSize border_box_size(
- inline_size,
- ComputeBlockSizeForFragment(constraint_space, style, border_padding,
+ LogicalSize border_box_size(inline_size,
+ ComputeInitialBlockSizeForFragment(
+ constraint_space, style, border_padding,
default_block_size, inline_size));
if (UNLIKELY(border_box_size.inline_size <
@@ -1206,11 +1385,14 @@ NGFragmentGeometry CalculateInitialMinMaxFragmentGeometry(
const NGConstraintSpace& constraint_space,
const NGBlockNode& node) {
const ComputedStyle& style = node.Style();
+ // TODO(ikilpatrick): Investigate if we should bring in the block-size logic
+ // from CalculateChildPercentageBlockSizeForMinMax here.
+ LogicalSize border_box_size = {kIndefiniteSize, kIndefiniteSize};
NGBoxStrut border = ComputeBorders(constraint_space, node);
NGBoxStrut padding = ComputePadding(constraint_space, style);
NGBoxStrut scrollbar = ComputeScrollbars(constraint_space, node);
- return {/* border_box_size */ LogicalSize(), border, scrollbar, padding};
+ return {border_box_size, border, scrollbar, padding};
}
LogicalSize ShrinkLogicalSize(LogicalSize size, const NGBoxStrut& insets) {
@@ -1251,7 +1433,6 @@ LogicalSize AdjustChildPercentageSize(const NGConstraintSpace& space,
// Flex items may have a fixed block-size, but children shouldn't resolve
// their percentages against this.
if (space.IsFixedBlockSizeIndefinite()) {
- DCHECK(space.IsFixedBlockSize());
DCHECK(node.IsFlexItem() || space.IsTableCell());
child_percentage_size.block_size = kIndefiniteSize;
return child_percentage_size;
@@ -1325,7 +1506,7 @@ LogicalSize CalculateReplacedChildPercentageSize(
if (space.IsTableCell() && style.LogicalHeight().IsFixed()) {
LayoutUnit block_size = ComputeBlockSizeForFragmentInternal(
space, style, border_padding, kIndefiniteSize /* intrinsic_size */,
- base::nullopt /* inline_size */);
+ base::nullopt /* inline_size */, node.ShouldBeConsideredAsReplaced());
DCHECK_NE(block_size, kIndefiniteSize);
return {child_available_size.inline_size,
(block_size - border_scrollbar_padding.BlockSum())
@@ -1341,36 +1522,46 @@ LayoutUnit CalculateChildPercentageBlockSizeForMinMax(
const NGConstraintSpace& space,
const NGBlockNode node,
const NGBoxStrut& border_padding,
+ const NGBoxStrut& scrollbar,
LayoutUnit input_percentage_block_size,
bool* uses_input_percentage_block_size) {
*uses_input_percentage_block_size = false;
// Anonymous block or spaces should pass the percent size straight through.
- // If this node is OOF-positioned, our size was pre-calculated and we should
- // pass this through to our children.
- if (space.IsAnonymous() || node.IsAnonymousBlock() ||
- node.IsOutOfFlowPositioned()) {
+ if (space.IsAnonymous() || node.IsAnonymousBlock()) {
*uses_input_percentage_block_size = true;
return input_percentage_block_size;
}
const ComputedStyle& style = node.Style();
- LayoutUnit block_size = ComputeBlockSizeForFragmentInternal(
- space, style, border_padding,
- CalculateDefaultBlockSize(space, node, border_padding), base::nullopt,
- &input_percentage_block_size);
-
- if (style.LogicalMinHeight().IsPercentOrCalc() ||
- style.LogicalHeight().IsPercentOrCalc() ||
- style.LogicalMaxHeight().IsPercentOrCalc())
+ const NGBoxStrut& border_scrollbar_padding = border_padding + scrollbar;
+ LayoutUnit block_size;
+
+ if (node.IsOutOfFlowPositioned()) {
+ // If this node is OOF-positioned, our size was pre-calculated.
+ block_size = input_percentage_block_size;
*uses_input_percentage_block_size = true;
+ } else {
+ block_size = ComputeBlockSizeForFragmentInternal(
+ space, style, border_padding,
+ CalculateDefaultBlockSize(space, node, border_scrollbar_padding),
+ /* inline_size */ base::nullopt, node.ShouldBeConsideredAsReplaced(),
+ /* available_block_size_adjustment */ LayoutUnit(),
+ &input_percentage_block_size);
+
+ if (style.LogicalMinHeight().IsPercentOrCalc() ||
+ style.LogicalHeight().IsPercentOrCalc() ||
+ style.LogicalMaxHeight().IsPercentOrCalc())
+ *uses_input_percentage_block_size = true;
+ }
LayoutUnit child_percentage_block_size =
block_size == kIndefiniteSize
? kIndefiniteSize
- : (block_size - border_padding.BlockSum()).ClampNegativeToZero();
+ : (block_size - border_scrollbar_padding.BlockSum())
+ .ClampNegativeToZero();
- // For OOF-positioned nodes, use the parent (containing-block) size.
+ // In quirks mode some 'auto' block-size nodes pass the %-block-size through.
if (child_percentage_block_size == kIndefiniteSize &&
node.UseParentPercentageResolutionBlockSizeForChildren()) {
*uses_input_percentage_block_size = true;
@@ -1386,6 +1577,8 @@ LayoutUnit ClampIntrinsicBlockSize(
const NGBoxStrut& border_scrollbar_padding,
LayoutUnit current_intrinsic_block_size,
base::Optional<LayoutUnit> body_margin_block_sum) {
+ // Tables don't respect size containment, or apply the "fill viewport" quirk.
+ DCHECK(!node.IsTable());
const ComputedStyle& style = node.Style();
// Apply the "fills viewport" quirk if needed.
@@ -1419,7 +1612,7 @@ LayoutUnit ClampIntrinsicBlockSize(
// If we have size containment, we ignore child contributions to intrinsic
// sizing.
- if (node.ShouldApplySizeContainment())
+ if (node.ShouldApplyBlockSizeContainment())
return border_scrollbar_padding.BlockSum();
return current_intrinsic_block_size;
}
@@ -1451,7 +1644,7 @@ base::Optional<MinMaxSizesResult> CalculateMinMaxSizesIgnoringChildren(
// Size contained elements don't consider children for intrinsic sizing.
// Also, if we don't have children, we can determine the size immediately.
- if (node.ShouldApplySizeContainment() || !node.FirstChild()) {
+ if (node.ShouldApplyInlineSizeContainment() || !node.FirstChild()) {
return MinMaxSizesResult{sizes,
/* depends_on_percentage_block_size */ false};
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index ebb5f07e5e7..3b4694b6ae6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -27,17 +27,16 @@ class NGConstraintSpace;
class NGBlockNode;
class NGLayoutInputNode;
-// LengthResolvePhase indicates what type of layout pass we are currently in.
-// This changes how lengths are resolved. kIntrinsic must be used during the
-// intrinsic sizes pass, and kLayout must be used during the layout pass.
-enum class LengthResolvePhase { kIntrinsic, kLayout };
-
inline bool NeedMinMaxSize(const ComputedStyle& style) {
return style.LogicalWidth().IsContentOrIntrinsic() ||
style.LogicalMinWidth().IsContentOrIntrinsic() ||
style.LogicalMaxWidth().IsContentOrIntrinsic();
}
+LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
+ double logical_aspect_ratio,
+ EBoxSizing box_sizing,
+ LayoutUnit block_size);
CORE_EXPORT LayoutUnit
InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio,
@@ -45,19 +44,23 @@ InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
LayoutUnit block_size);
LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
+ double logical_aspect_ratio,
+ EBoxSizing box_sizing,
+ LayoutUnit inline_size);
+LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio,
EBoxSizing box_sizing,
LayoutUnit inline_size);
// Returns if the given |Length| is unresolvable, e.g. the length is %-based
-// during the intrinsic phase. For block lengths we also consider 'auto',
-// 'min-content', 'max-content', 'fit-content' and 'none' (for max-block-size)
-// as unresolvable.
-CORE_EXPORT bool InlineLengthUnresolvable(const Length&, LengthResolvePhase);
+// and resolving against an indefinite size. For block lengths we also consider
+// 'auto', 'min-content', 'max-content', 'fit-content' and 'none' (for
+// max-block-size) as unresolvable.
+CORE_EXPORT bool InlineLengthUnresolvable(const NGConstraintSpace&,
+ const Length&);
CORE_EXPORT bool BlockLengthUnresolvable(
const NGConstraintSpace&,
const Length&,
- LengthResolvePhase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr);
@@ -83,6 +86,7 @@ CORE_EXPORT LayoutUnit ResolveBlockLengthInternal(
const NGBoxStrut& border_padding,
const Length&,
LayoutUnit intrinsic_size,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr);
@@ -93,9 +97,9 @@ inline LayoutUnit ResolveMinInlineLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const MinMaxSizesFunc& min_max_sizes_func,
- const Length& length,
- LengthResolvePhase phase) {
- if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
+ const Length& length) {
+ if (LIKELY(length.IsAuto() ||
+ InlineLengthUnresolvable(constraint_space, length)))
return border_padding.InlineSum();
base::Optional<MinMaxSizes> min_max_sizes;
@@ -116,9 +120,9 @@ inline LayoutUnit ResolveMinInlineLength<base::Optional<MinMaxSizes>>(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSizes>& min_max_sizes,
- const Length& length,
- LengthResolvePhase phase) {
- if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
+ const Length& length) {
+ if (LIKELY(length.IsAuto() ||
+ InlineLengthUnresolvable(constraint_space, length)))
return border_padding.InlineSum();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
@@ -132,9 +136,9 @@ inline LayoutUnit ResolveMaxInlineLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const MinMaxSizesFunc& min_max_sizes_func,
- const Length& length,
- LengthResolvePhase phase) {
- if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
+ const Length& length) {
+ if (LIKELY(length.IsNone() ||
+ InlineLengthUnresolvable(constraint_space, length)))
return LayoutUnit::Max();
base::Optional<MinMaxSizes> min_max_sizes;
@@ -155,9 +159,9 @@ inline LayoutUnit ResolveMaxInlineLength<base::Optional<MinMaxSizes>>(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSizes>& min_max_sizes,
- const Length& length,
- LengthResolvePhase phase) {
- if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
+ const Length& length) {
+ if (LIKELY(length.IsNone() ||
+ InlineLengthUnresolvable(constraint_space, length)))
return LayoutUnit::Max();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
@@ -172,6 +176,7 @@ inline LayoutUnit ResolveMainInlineLength(
const NGBoxStrut& border_padding,
const MinMaxSizesFunc& min_max_sizes_func,
const Length& length) {
+ DCHECK(!length.IsAuto());
base::Optional<MinMaxSizes> min_max_sizes;
if (length.IsContentOrIntrinsic()) {
min_max_sizes =
@@ -191,6 +196,7 @@ inline LayoutUnit ResolveMainInlineLength<base::Optional<MinMaxSizes>>(
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSizes>& min_max_sizes,
const Length& length) {
+ DCHECK(!length.IsAuto());
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_max_sizes, length);
}
@@ -201,16 +207,17 @@ inline LayoutUnit ResolveMinBlockLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
- LengthResolvePhase phase,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(BlockLengthUnresolvable(
- constraint_space, length, phase,
+ constraint_space, length,
opt_percentage_resolution_block_size_for_min_max)))
return border_padding.BlockSum();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, kIndefiniteSize,
+ available_block_size_adjustment,
opt_percentage_resolution_block_size_for_min_max);
}
@@ -220,16 +227,17 @@ inline LayoutUnit ResolveMaxBlockLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
- LengthResolvePhase phase,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(BlockLengthUnresolvable(
- constraint_space, length, phase,
+ constraint_space, length,
opt_percentage_resolution_block_size_for_min_max)))
return LayoutUnit::Max();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, kIndefiniteSize,
+ available_block_size_adjustment,
opt_percentage_resolution_block_size_for_min_max);
}
@@ -240,17 +248,19 @@ inline LayoutUnit ResolveMainBlockLength(
const NGBoxStrut& border_padding,
const Length& length,
LayoutUnit intrinsic_size,
- LengthResolvePhase phase,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
+ DCHECK(!length.IsAuto());
if (UNLIKELY((length.IsPercentOrCalc() || length.IsFillAvailable()) &&
BlockLengthUnresolvable(
- constraint_space, length, phase,
+ constraint_space, length,
opt_percentage_resolution_block_size_for_min_max)))
return intrinsic_size;
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, intrinsic_size,
+ available_block_size_adjustment,
opt_percentage_resolution_block_size_for_min_max);
}
@@ -261,43 +271,38 @@ inline LayoutUnit ResolveMainBlockLength(
const NGBoxStrut& border_padding,
const Length& length,
const IntrinsicBlockSizeFunc& intrinsic_block_size_func,
- LengthResolvePhase phase,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
+ DCHECK(!length.IsAuto());
if (UNLIKELY((length.IsPercentOrCalc() || length.IsFillAvailable()) &&
BlockLengthUnresolvable(
- constraint_space, length, phase,
+ constraint_space, length,
opt_percentage_resolution_block_size_for_min_max)))
return intrinsic_block_size_func();
LayoutUnit intrinsic_block_size = kIndefiniteSize;
- if (length.IsAutoOrContentOrIntrinsic())
+ if (length.IsContentOrIntrinsic())
intrinsic_block_size = intrinsic_block_size_func();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, intrinsic_block_size,
+ available_block_size_adjustment,
opt_percentage_resolution_block_size_for_min_max);
}
-// For the given style and min/max content sizes, computes the min and max
-// content contribution (https://drafts.csswg.org/css-sizing/#contributions).
+// For the given |child|, computes the min and max content contribution
+// (https://drafts.csswg.org/css-sizing/#contributions).
+//
// This is similar to ComputeInlineSizeForFragment except that it does not
// require a constraint space (percentage sizes as well as auto margins compute
-// to zero) and that an auto inline size resolves to the respective min/max
-// content size.
-// Also, the min/max contribution does include the inline margins as well.
-// Because content contributions are commonly needed by a block's parent,
-// we also take a writing mode here so we can compute this in the parent's
-// coordinate system.
-CORE_EXPORT MinMaxSizes
-ComputeMinAndMaxContentContributionForTest(WritingMode writing_mode,
- const NGBlockNode&,
- const MinMaxSizes&);
-
-// A version of ComputeMinAndMaxContentContribution that does not require you
-// to compute the min/max content size of the child. Instead, this function
-// will compute it if necessary.
-// |child| is the node of which to compute the min/max content contribution.
+// to zero) and an auto inline-size resolves to the respective min/max content
+// size.
+//
+// Additoinally, the min/max contribution includes the inline margins. Because
+// content contributions are commonly needed by a block's parent, we also take
+// a writing-mode here so we can compute this in the parent's coordinate system.
+//
// Note that if the writing mode of the child is orthogonal to that of the
// parent, we'll still return the inline min/max contribution in the writing
// mode of the parent (i.e. typically something based on the preferred *block*
@@ -307,12 +312,26 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution(
const NGBlockNode& child,
const MinMaxSizesInput&);
+// Similar to |ComputeMinAndMaxContentContribution| but ignores the parent
+// writing-mode, and instead computes the contribution relative to |child|'s
+// own writing-mode.
+MinMaxSizesResult ComputeMinAndMaxContentContributionForSelf(
+ const NGBlockNode& child,
+ const MinMaxSizesInput&);
+
+// Used for unit-tests.
+CORE_EXPORT MinMaxSizes
+ComputeMinAndMaxContentContributionForTest(WritingMode writing_mode,
+ const NGBlockNode&,
+ const MinMaxSizes&);
+
// Computes the min-block-size and max-block-size values for a node.
-MinMaxSizes ComputeMinMaxBlockSize(
+MinMaxSizes ComputeMinMaxBlockSizes(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
LayoutUnit intrinsic_size,
+ LayoutUnit available_block_size_adjustment = LayoutUnit(),
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr);
@@ -330,8 +349,7 @@ MinMaxSizes ComputeTransferredMinMaxInlineSizes(
MinMaxSizes ComputeMinMaxInlineSizesFromAspectRatio(
const NGConstraintSpace&,
const ComputedStyle&,
- const NGBoxStrut& border_padding,
- LengthResolvePhase);
+ const NGBoxStrut& border_padding);
// Tries to compute the inline size of a node from its block size and
// aspect ratio. If there is no aspect ratio or the block size is indefinite,
@@ -343,8 +361,38 @@ LayoutUnit ComputeInlineSizeFromAspectRatio(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
+ bool should_be_considered_as_replaced,
LayoutUnit block_size = kIndefiniteSize);
+template <typename MinMaxSizesFunc>
+MinMaxSizes ComputeMinMaxInlineSizes(const NGConstraintSpace& space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ const MinMaxSizesFunc& min_max_sizes_func,
+ const Length* opt_min_length = nullptr) {
+ const Length& min_length =
+ opt_min_length ? *opt_min_length : style.LogicalMinWidth();
+ MinMaxSizes sizes = {
+ ResolveMinInlineLength(space, style, border_padding, min_max_sizes_func,
+ min_length),
+ ResolveMaxInlineLength(space, style, border_padding, min_max_sizes_func,
+ style.LogicalMaxWidth())};
+
+ // This implements the transferred min/max sizes per:
+ // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers
+ if (!style.AspectRatio().IsAuto() &&
+ BlockLengthUnresolvable(space, style.LogicalHeight())) {
+ MinMaxSizes transferred_sizes =
+ ComputeMinMaxInlineSizesFromAspectRatio(space, style, border_padding);
+ sizes.min_size = std::max(
+ sizes.min_size, std::min(transferred_sizes.min_size, sizes.max_size));
+ sizes.max_size = std::min(sizes.max_size, transferred_sizes.max_size);
+ }
+
+ sizes.max_size = std::max(sizes.max_size, sizes.min_size);
+ return sizes;
+}
+
// Returns inline size of the node's border box by resolving the computed value
// in style.logicalWidth (Length) to a layout unit, adding border and padding,
// then constraining the result by the resolved min logical width and max
@@ -357,25 +405,45 @@ CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment(
const NGBoxStrut& border_padding,
const MinMaxSizes* override_min_max_sizes_for_test = nullptr);
+// Similar to |ComputeInlineSizeForFragment| but for determining the "used"
+// inline-size for a table fragment. See:
+// https://drafts.csswg.org/css-tables-3/#used-width-of-table
+CORE_EXPORT LayoutUnit ComputeUsedInlineSizeForTableFragment(
+ const NGConstraintSpace& space,
+ NGLayoutInputNode node,
+ const NGBoxStrut& border_padding,
+ const MinMaxSizes& table_grid_min_max_sizes);
+
// Same as ComputeInlineSizeForFragment, but uses height instead of width.
// |inline_size| is necessary to compute the block size when an aspect ratio
// is in use.
+// |available_block_size_adjustment| is needed for <table> layout. When a table
+// is under an extrinsic constraint (being stretched by its parent, or forced
+// to a fixed block-size), we need to subtract the block-size of all the
+// <caption>s from the available block-size.
+CORE_EXPORT LayoutUnit ComputeBlockSizeForFragment(
+ const NGConstraintSpace&,
+ const ComputedStyle&,
+ const NGBoxStrut& border_padding,
+ LayoutUnit intrinsic_size,
+ base::Optional<LayoutUnit> inline_size,
+ bool should_be_considered_as_replaced,
+ LayoutUnit available_block_size_adjustment = LayoutUnit());
+
+// Calculates default content size for html and body elements in quirks mode.
+// Returns |kIndefiniteSize| in all other cases.
CORE_EXPORT LayoutUnit
-ComputeBlockSizeForFragment(const NGConstraintSpace&,
- const ComputedStyle&,
- const NGBoxStrut& border_padding,
- LayoutUnit intrinsic_size,
- base::Optional<LayoutUnit> inline_size);
+CalculateDefaultBlockSize(const NGConstraintSpace& space,
+ const NGBlockNode& node,
+ const NGBoxStrut& border_scrollbar_padding);
// Intrinsic size for replaced elements is computed as:
// - |out_replaced_size| intrinsic size of the element. It might have no value.
// - |out_aspect_ratio| only set if out_replaced_size is empty.
// If out_replaced_size is not empty, that is the aspect ratio.
-// This routine will return one of the following:
-// - out_replaced_size, and no out_aspect_ratio
-// - out_aspect_ratio, and no out_replaced_size
-// - neither out_aspect_ratio, nor out_replaced_size
-// SVG elements can return any of the three options above.
+// This routine will return precisely one of |out_replaced_size| and
+// |out_aspect_ratio|. If |out_aspect_ratio| is filled in, both inline and block
+// componenents will be non-zero.
CORE_EXPORT void ComputeReplacedSize(
const NGBlockNode&,
const NGConstraintSpace&,
@@ -405,6 +473,8 @@ CORE_EXPORT LayoutUnit ResolveUsedColumnInlineSize(LayoutUnit available_size,
CORE_EXPORT LayoutUnit ResolveUsedColumnGap(LayoutUnit available_size,
const ComputedStyle&);
+CORE_EXPORT LayoutUnit ColumnInlineProgression(LayoutUnit available_size,
+ const ComputedStyle&);
// Compute physical margins.
CORE_EXPORT NGPhysicalBoxStrut
ComputePhysicalMargins(const ComputedStyle&,
@@ -473,6 +543,7 @@ inline NGLineBoxStrut ComputeLineMarginsForVisualContainer(
}
// Compute margins for a child during the min-max size calculation.
+// TODO(ikilpatrick): Replace this function with ComputeMarginsFor.
CORE_EXPORT NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
NGLayoutInputNode child);
@@ -590,6 +661,7 @@ LayoutUnit CalculateChildPercentageBlockSizeForMinMax(
const NGConstraintSpace& constraint_space,
const NGBlockNode node,
const NGBoxStrut& border_padding,
+ const NGBoxStrut& scrollbar,
LayoutUnit input_percentage_block_size,
bool* uses_input_percentage_block_size);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
index c37167764c2..fde75580529 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
@@ -31,6 +31,7 @@ static NGConstraintSpace ConstructConstraintSpace(
/* is_new_fc */ false);
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
+ builder.SetStretchInlineSizeIfAuto(true);
builder.SetIsFixedInlineSize(fixed_inline);
builder.SetIsFixedBlockSize(fixed_block);
return builder.ToConstraintSpace();
@@ -42,8 +43,8 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveMainInlineLength(
const Length& length,
- const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
- NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt,
+ NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300)) {
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
@@ -53,26 +54,24 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveMinInlineLength(
const Length& length,
- LengthResolvePhase phase = LengthResolvePhase::kLayout,
- const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
- NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt,
+ NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300)) {
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
- return ::blink::ResolveMinInlineLength(
- constraint_space, *style_, border_padding, sizes, length, phase);
+ return ::blink::ResolveMinInlineLength(constraint_space, *style_,
+ border_padding, sizes, length);
}
LayoutUnit ResolveMaxInlineLength(
const Length& length,
- LengthResolvePhase phase = LengthResolvePhase::kLayout,
- const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
- NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt,
+ NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300)) {
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
- return ::blink::ResolveMaxInlineLength(
- constraint_space, *style_, border_padding, sizes, length, phase);
+ return ::blink::ResolveMaxInlineLength(constraint_space, *style_,
+ border_padding, sizes, length);
}
LayoutUnit ResolveMainBlockLength(const Length& length,
@@ -81,9 +80,8 @@ class NGLengthUtilsTest : public testing::Test {
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
- return ::blink::ResolveMainBlockLength(constraint_space, *style_,
- border_padding, length, content_size,
- LengthResolvePhase::kLayout);
+ return ::blink::ResolveMainBlockLength(
+ constraint_space, *style_, border_padding, length, content_size);
}
scoped_refptr<ComputedStyle> style_;
@@ -121,26 +119,18 @@ class NGLengthUtilsTestWithNode : public NGLayoutTest {
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
return ::blink::ComputeBlockSizeForFragment(
- constraint_space, *style_, border_padding, content_size, inline_size);
+ constraint_space, *style_, border_padding, content_size, inline_size,
+ body->ShouldBeConsideredAsReplaced());
}
scoped_refptr<ComputedStyle> style_;
};
-TEST_F(NGLengthUtilsTest, testResolveInlineLength) {
+TEST_F(NGLengthUtilsTest, TestResolveInlineLength) {
EXPECT_EQ(LayoutUnit(60), ResolveMainInlineLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveMainInlineLength(Length::Fixed(150)));
- EXPECT_EQ(LayoutUnit(0), ResolveMinInlineLength(
- Length::Auto(), LengthResolvePhase::kIntrinsic));
- EXPECT_EQ(LayoutUnit(200), ResolveMainInlineLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(200), ResolveMainInlineLength(Length::FillAvailable()));
- EXPECT_EQ(LayoutUnit::Max(),
- ResolveMaxInlineLength(Length::Percent(30),
- LengthResolvePhase::kIntrinsic));
- EXPECT_EQ(LayoutUnit::Max(),
- ResolveMaxInlineLength(Length::FillAvailable(),
- LengthResolvePhase::kIntrinsic));
MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
@@ -160,16 +150,24 @@ TEST_F(NGLengthUtilsTest, testResolveInlineLength) {
#endif
}
-TEST_F(NGLengthUtilsTest, testResolveBlockLength) {
+TEST_F(NGLengthUtilsTest, TestIndefiniteResolveInlineLength) {
+ const NGConstraintSpace space = ConstructConstraintSpace(-1, -1);
+
+ EXPECT_EQ(LayoutUnit(0),
+ ResolveMinInlineLength(Length::Auto(), base::nullopt, space));
+ EXPECT_EQ(LayoutUnit::Max(),
+ ResolveMaxInlineLength(Length::Percent(30), base::nullopt, space));
+ EXPECT_EQ(LayoutUnit::Max(), ResolveMaxInlineLength(Length::FillAvailable(),
+ base::nullopt, space));
+}
+
+TEST_F(NGLengthUtilsTest, TestResolveBlockLength) {
EXPECT_EQ(LayoutUnit(90), ResolveMainBlockLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveMainBlockLength(Length::Fixed(150)));
- EXPECT_EQ(LayoutUnit(0), ResolveMainBlockLength(Length::Auto()));
- EXPECT_EQ(LayoutUnit(300), ResolveMainBlockLength(Length::FillAvailable()));
-
EXPECT_EQ(LayoutUnit(300), ResolveMainBlockLength(Length::FillAvailable()));
}
-TEST_F(NGLengthUtilsTestWithNode, testComputeContentContribution) {
+TEST_F(NGLengthUtilsTestWithNode, TestComputeContentContribution) {
MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
@@ -261,7 +259,7 @@ TEST_F(NGLengthUtilsTestWithNode, testComputeContentContribution) {
style_->GetWritingMode(), node, sizes));
}
-TEST_F(NGLengthUtilsTestWithNode, testComputeInlineSizeForFragment) {
+TEST_F(NGLengthUtilsTestWithNode, TestComputeInlineSizeForFragment) {
MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
@@ -332,7 +330,7 @@ TEST_F(NGLengthUtilsTestWithNode, testComputeInlineSizeForFragment) {
ComputeInlineSizeForFragment(constraint_space, sizes));
}
-TEST_F(NGLengthUtilsTestWithNode, testComputeBlockSizeForFragment) {
+TEST_F(NGLengthUtilsTestWithNode, TestComputeBlockSizeForFragment) {
style_->SetLogicalHeight(Length::Percent(30));
EXPECT_EQ(LayoutUnit(90), ComputeBlockSizeForFragment());
@@ -412,7 +410,7 @@ TEST_F(NGLengthUtilsTestWithNode, testComputeBlockSizeForFragment) {
// TODO(layout-ng): test {min,max}-content on max-height.
}
-TEST_F(NGLengthUtilsTestWithNode, testIndefinitePercentages) {
+TEST_F(NGLengthUtilsTestWithNode, TestIndefinitePercentages) {
style_->SetMinHeight(Length::Fixed(20));
style_->SetHeight(Length::Percent(20));
@@ -427,7 +425,7 @@ TEST_F(NGLengthUtilsTestWithNode, testIndefinitePercentages) {
LayoutUnit(120)));
}
-TEST_F(NGLengthUtilsTest, testMargins) {
+TEST_F(NGLengthUtilsTest, TestMargins) {
style_->SetMarginTop(Length::Percent(10));
style_->SetMarginRight(Length::Fixed(52));
style_->SetMarginBottom(Length::Auto());
@@ -444,7 +442,7 @@ TEST_F(NGLengthUtilsTest, testMargins) {
EXPECT_EQ(LayoutUnit(22), margins.left);
}
-TEST_F(NGLengthUtilsTest, testBorders) {
+TEST_F(NGLengthUtilsTest, TestBorders) {
style_->SetBorderTopWidth(1);
style_->SetBorderRightWidth(2);
style_->SetBorderBottomWidth(3);
@@ -463,7 +461,7 @@ TEST_F(NGLengthUtilsTest, testBorders) {
EXPECT_EQ(LayoutUnit(1), borders.inline_start);
}
-TEST_F(NGLengthUtilsTest, testPadding) {
+TEST_F(NGLengthUtilsTest, TestPadding) {
style_->SetPaddingTop(Length::Percent(10));
style_->SetPaddingRight(Length::Fixed(52));
style_->SetPaddingBottom(Length::Auto());
@@ -481,7 +479,7 @@ TEST_F(NGLengthUtilsTest, testPadding) {
EXPECT_EQ(LayoutUnit(20), padding.inline_start);
}
-TEST_F(NGLengthUtilsTest, testAutoMargins) {
+TEST_F(NGLengthUtilsTest, TestAutoMargins) {
style_->SetMarginRight(Length::Auto());
style_->SetMarginLeft(Length::Auto());
@@ -551,7 +549,7 @@ int GetUsedColumnCount(int computed_column_count,
LayoutUnit(available_inline_size));
}
-TEST_F(NGLengthUtilsTest, testColumnWidthAndCount) {
+TEST_F(NGLengthUtilsTest, TestColumnWidthAndCount) {
EXPECT_EQ(100, GetUsedColumnWidth(0, 100, 0, 300));
EXPECT_EQ(3, GetUsedColumnCount(0, 100, 0, 300));
EXPECT_EQ(150, GetUsedColumnWidth(0, 101, 0, 300));
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 83273c21fe2..442a448d9ad 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -92,7 +92,9 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
container_node.IsFixedContainer(),
container_node.Style(),
container_space,
- container_builder) {}
+ container_builder) {
+ can_traverse_fragments_ = container_node.CanTraversePhysicalFragments();
+}
NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
bool is_absolute_container,
@@ -103,6 +105,7 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
base::Optional<LogicalSize> initial_containing_block_fixed_size)
: container_builder_(container_builder),
writing_mode_(container_style.GetWritingMode()),
+ default_writing_direction_(container_style.GetWritingDirection()),
is_absolute_container_(is_absolute_container),
is_fixed_container_(is_fixed_container),
has_block_fragmentation_(container_space.HasBlockFragmentation()) {
@@ -111,32 +114,49 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
->HasPositionedObjects())
return;
- default_containing_block_.writing_direction =
- container_style.GetWritingDirection();
+ default_containing_block_info_for_absolute_.writing_direction =
+ default_writing_direction_;
+ default_containing_block_info_for_fixed_.writing_direction =
+ default_writing_direction_;
const NGBoxStrut border_scrollbar =
container_builder->Borders() + container_builder->Scrollbar();
allow_first_tier_oof_cache_ = border_scrollbar.IsEmpty();
- default_containing_block_.content_size_for_absolute =
+ default_containing_block_info_for_absolute_.rect.size =
ShrinkLogicalSize(container_builder_->Size(), border_scrollbar);
- default_containing_block_.content_size_for_fixed =
+ default_containing_block_info_for_fixed_.rect.size =
initial_containing_block_fixed_size
? *initial_containing_block_fixed_size
- : default_containing_block_.content_size_for_absolute;
-
- default_containing_block_.container_offset = LogicalOffset(
- border_scrollbar.inline_start, border_scrollbar.block_start);
+ : default_containing_block_info_for_absolute_.rect.size;
+ LogicalOffset container_offset = {border_scrollbar.inline_start,
+ border_scrollbar.block_start};
+ default_containing_block_info_for_absolute_.rect.offset = container_offset;
+ default_containing_block_info_for_fixed_.rect.offset = container_offset;
}
void NGOutOfFlowLayoutPart::Run(const LayoutBox* only_layout) {
if (container_builder_->IsBlockFragmentationContextRoot() &&
- !has_block_fragmentation_ &&
- container_builder_->HasOutOfFlowFragmentainerDescendants()) {
- Vector<NGLogicalOutOfFlowPositionedNode> fragmentainer_descendants;
- container_builder_->SwapOutOfFlowFragmentainerDescendants(
- &fragmentainer_descendants);
-
- if (!fragmentainer_descendants.IsEmpty())
- LayoutFragmentainerDescendants(&fragmentainer_descendants);
+ !has_block_fragmentation_) {
+ if (container_builder_->HasOutOfFlowFragmentainerDescendants()) {
+ Vector<NGLogicalOutOfFlowPositionedNode> fragmentainer_descendants;
+ container_builder_->SwapOutOfFlowFragmentainerDescendants(
+ &fragmentainer_descendants);
+ DCHECK(!fragmentainer_descendants.IsEmpty());
+ LayoutUnit column_inline_progression = ColumnInlineProgression(
+ container_builder_->ChildAvailableSize().inline_size,
+ container_builder_->Style());
+ LayoutFragmentainerDescendants(&fragmentainer_descendants,
+ column_inline_progression);
+ }
+
+ if (container_builder_->HasMulticolsWithPendingOOFs()) {
+ NGContainerFragmentBuilder::MulticolCollection
+ multicols_with_pending_oofs;
+ container_builder_->SwapMulticolsWithPendingOOFs(
+ &multicols_with_pending_oofs);
+ DCHECK(!multicols_with_pending_oofs.IsEmpty());
+ for (LayoutBox* multicol : multicols_with_pending_oofs)
+ LayoutOOFsInMulticol(NGBlockNode(multicol));
+ }
}
const LayoutObject* current_container = container_builder_->GetLayoutObject();
@@ -253,7 +273,7 @@ bool NGOutOfFlowLayoutPart::SweepLegacyCandidates(
// TODO(layout-dev): Remove this once LayoutFlexibleBox is removed.
LayoutBox* layout_box = To<LayoutBox>(legacy_object);
if (layout_box->Parent()->IsFlexibleBox()) {
- LayoutFlexibleBox* parent = ToLayoutFlexibleBox(layout_box->Parent());
+ auto* parent = To<LayoutFlexibleBox>(layout_box->Parent());
if (parent->SetStaticPositionForPositionedLayout(*layout_box)) {
NGLogicalOutOfFlowPositionedNode candidate((NGBlockNode(layout_box)),
NGLogicalStaticPosition());
@@ -285,14 +305,16 @@ bool NGOutOfFlowLayoutPart::SweepLegacyCandidates(
// When fragmenting, the ContainingBlockInfo is not stored ahead of time and
// must be generated on demand. The reason being that during fragmentation, we
// wait to place positioned nodes until they've reached the fragmentation
-// context root. In such cases, we cannot use |default_containing_block_| since
-// the fragmentation root is not the containing block of the positioned nodes.
-// Rather, we must generate their ContainingBlockInfo based on the provided
-// |containing_block_fragment|.
-const NGOutOfFlowLayoutPart::ContainingBlockInfo&
+// context root. In such cases, we cannot use default |ContainingBlockInfo|
+// since the fragmentation root is not the containing block of the positioned
+// nodes. Rather, we must generate their ContainingBlockInfo based on the
+// provided |containing_block_fragment|.
+const NGOutOfFlowLayoutPart::ContainingBlockInfo
NGOutOfFlowLayoutPart::GetContainingBlockInfo(
const NGLogicalOutOfFlowPositionedNode& candidate,
const NGPhysicalContainerFragment* containing_block_fragment) {
+ if (candidate.containing_block_rect)
+ return {default_writing_direction_, *candidate.containing_block_rect};
if (candidate.inline_container) {
const auto it = containing_blocks_map_.find(candidate.inline_container);
DCHECK(it != containing_blocks_map_.end());
@@ -325,14 +347,17 @@ NGOutOfFlowLayoutPart::GetContainingBlockInfo(
LogicalOffset(border.inline_start, border.block_start);
container_offset += candidate.containing_block_offset;
- ContainingBlockInfo containing_block_info{writing_direction, content_size,
- content_size, container_offset};
+ ContainingBlockInfo containing_block_info{
+ writing_direction, LogicalRect(container_offset, content_size)};
return containing_blocks_map_
.insert(containing_block, containing_block_info)
.stored_value->value;
}
- return default_containing_block_;
+
+ return candidate.node.Style().GetPosition() == EPosition::kAbsolute
+ ? default_containing_block_info_for_absolute_
+ : default_containing_block_info_for_fixed_;
}
void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
@@ -349,13 +374,8 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
}
// Fetch the inline start/end fragment geometry.
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- container_builder_->ComputeInlineContainerGeometry(
- &inline_container_fragments);
- } else {
- container_builder_->ComputeInlineContainerGeometryFromFragmentTree(
- &inline_container_fragments);
- }
+ container_builder_->ComputeInlineContainerGeometry(
+ &inline_container_fragments);
LogicalSize container_builder_size = container_builder_->Size();
PhysicalSize container_builder_physical_size =
@@ -420,7 +440,7 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
DCHECK(inline_cb_style);
const auto container_writing_direction =
- default_containing_block_.writing_direction;
+ default_containing_block_info_for_absolute_.writing_direction;
const auto inline_writing_direction =
inline_cb_style->GetWritingDirection();
NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
@@ -478,8 +498,8 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
containing_blocks_map_.insert(
block_info.key,
- ContainingBlockInfo{inline_writing_direction, inline_cb_size,
- inline_cb_size, container_offset});
+ ContainingBlockInfo{inline_writing_direction,
+ LogicalRect(container_offset, inline_cb_size)});
}
}
@@ -545,15 +565,13 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutCandidate(
node.GetLayoutBox()->ContainingBlock()) ||
node.GetLayoutBox()->ContainingBlock()->IsTable());
- const auto default_writing_direction =
- default_containing_block_.writing_direction;
- const ContainingBlockInfo& container_info = GetContainingBlockInfo(candidate);
+ const ContainingBlockInfo container_info = GetContainingBlockInfo(candidate);
const ComputedStyle& candidate_style = node.Style();
const auto candidate_writing_direction =
candidate_style.GetWritingDirection();
- LogicalSize container_content_size =
- container_info.ContentSize(candidate_style.GetPosition());
+ LogicalSize container_content_size = container_info.rect.size;
+
PhysicalSize container_physical_content_size =
ToPhysicalSize(container_content_size, writing_mode_);
@@ -580,12 +598,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutCandidate(
// container's border-box). ng_absolute_utils expects the static position to
// be relative to the container's padding-box.
NGLogicalStaticPosition static_position = candidate.static_position;
- static_position.offset -= container_info.container_offset;
+ static_position.offset -= container_info.rect.offset;
NGLogicalStaticPosition candidate_static_position =
static_position
.ConvertToPhysical(
- {default_writing_direction, container_physical_content_size})
+ {default_writing_direction_, container_physical_content_size})
.ConvertToLogical(
{candidate_writing_direction, container_physical_content_size});
@@ -602,7 +620,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutCandidate(
scoped_refptr<const NGLayoutResult> layout_result =
Layout(node, candidate_constraint_space, candidate_static_position,
container_physical_content_size, container_info,
- default_writing_direction, only_layout);
+ default_writing_direction_, only_layout);
if (!freeze_scrollbars.has_value()) {
// Since out-of-flow positioning sets up a constraint space with fixed
@@ -626,8 +644,144 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutCandidate(
} while (true);
}
+// TODO(almaher): Look into moving this to NGColumnLayoutAlgorithm instead.
+void NGOutOfFlowLayoutPart::LayoutOOFsInMulticol(const NGBlockNode& multicol) {
+ Vector<NGLogicalOutOfFlowPositionedNode> oof_nodes_to_layout;
+ Vector<MulticolChildInfo> multicol_children;
+ const NGBlockBreakToken* previous_column_break_token = nullptr;
+ LayoutUnit column_inline_progression = kIndefiniteSize;
+
+ NGConstraintSpace multicol_constraint_space =
+ CreateConstraintSpaceForMulticol(multicol);
+ NGFragmentGeometry fragment_geometry =
+ CalculateInitialFragmentGeometry(multicol_constraint_space, multicol);
+ NGBoxFragmentBuilder multicol_container_builder =
+ CreateContainerBuilderForMulticol(multicol, multicol_constraint_space,
+ fragment_geometry);
+
+ // Accumulate all of the pending OOF positioned nodes that are stored inside
+ // |multicol|.
+ for (auto& multicol_fragment : multicol.GetLayoutBox()->PhysicalFragments()) {
+ const NGPhysicalBoxFragment* multicol_box_fragment =
+ To<NGPhysicalBoxFragment>(&multicol_fragment);
+
+ const ComputedStyle& style = multicol_box_fragment->Style();
+ WritingDirectionMode writing_direction = style.GetWritingDirection();
+ const WritingModeConverter converter(writing_direction,
+ multicol_box_fragment->Size());
+ const NGBlockBreakToken* current_column_break_token =
+ previous_column_break_token;
+ wtf_size_t current_column_index = 0;
+
+ if (column_inline_progression == kIndefiniteSize) {
+ // TODO(almaher): This should eventually include scrollbar, as well.
+ NGBoxStrut border_padding =
+ multicol_box_fragment->Borders().ConvertToLogical(writing_direction) +
+ multicol_box_fragment->Padding().ConvertToLogical(writing_direction);
+ LayoutUnit available_inline_size =
+ multicol_box_fragment->Size()
+ .ConvertToLogical(writing_direction.GetWritingMode())
+ .inline_size -
+ border_padding.InlineSum();
+ column_inline_progression =
+ ColumnInlineProgression(available_inline_size, style);
+ }
+
+ // Collect the children of the multicol fragments.
+ for (auto& child :
+ multicol_box_fragment->GetMutableChildrenForOutOfFlow().Children()) {
+ const auto* fragment = To<NGPhysicalContainerFragment>(child.get());
+ LogicalOffset offset =
+ converter.ToLogical(child.Offset(), fragment->Size());
+ if (fragment->IsFragmentainerBox()) {
+ current_column_break_token =
+ To<NGBlockBreakToken>(fragment->BreakToken());
+ current_column_index = multicol_children.size();
+ }
+
+ multicol_container_builder.AddChild(*fragment, offset);
+ multicol_children.emplace_back(MulticolChildInfo(&child));
+ }
+
+ // If a column fragment is updated with OOF children, we may need to update
+ // the reference to its break token in its parent's break token. There
+ // should be at most one column break token per parent break token
+ // (representing the last column laid out in that fragment). Thus, search
+ // for |current_column_break_token| in |multicol_box_fragment|'s list of
+ // child break tokens and update the stored MulticolChildInfo if found.
+ const NGBlockBreakToken* break_token =
+ To<NGBlockBreakToken>(multicol_box_fragment->BreakToken());
+ if (break_token && break_token->ChildBreakTokens().size()) {
+ // If there is a column break token, it will be the last item in its
+ // parent's list of break tokens.
+ const auto children = break_token->ChildBreakTokens();
+ const NGBlockBreakToken* child_token =
+ To<NGBlockBreakToken>(children[children.size() - 1]);
+ if (child_token == current_column_break_token) {
+ MulticolChildInfo& child_info = multicol_children[current_column_index];
+ child_info.parent_break_token = break_token;
+ }
+ }
+
+ // Convert the OOF fragmentainer descendants to the logical coordinate space
+ // and store the resulting nodes inside |oof_nodes_to_layout|.
+ for (const auto& descendant :
+ multicol_box_fragment->OutOfFlowPositionedFragmentainerDescendants()) {
+ const NGPhysicalContainerFragment* containing_block_fragment =
+ descendant.containing_block_fragment.get();
+ LogicalOffset containing_block_offset =
+ converter.ToLogical(descendant.containing_block_offset,
+ containing_block_fragment->Size());
+
+ // The containing block offset should be the offset from the top of the
+ // inner multicol to the start of the containing block (as if all of the
+ // columns are placed one on top of the other). When propagating OOFs
+ // in a nested fragmentation context, we miss the block contribution
+ // from columns in previous outer fragmentainers. Add the block size
+ // for such columns here to account for this.
+ if (previous_column_break_token) {
+ containing_block_offset.block_offset +=
+ previous_column_break_token->ConsumedBlockSize();
+ }
+
+ // The static position should remain relative to its containing block
+ // fragment.
+ const WritingModeConverter containing_block_converter(
+ writing_direction, containing_block_fragment->Size());
+ NGLogicalStaticPosition static_position =
+ descendant.static_position.ConvertToLogical(
+ containing_block_converter);
+
+ NGLogicalOutOfFlowPositionedNode node = {
+ descendant.node,
+ static_position,
+ descendant.inline_container,
+ /* needs_block_offset_adjustment */ false,
+ containing_block_offset,
+ containing_block_fragment};
+ oof_nodes_to_layout.push_back(node);
+ }
+ previous_column_break_token = current_column_break_token;
+ }
+ DCHECK(!oof_nodes_to_layout.IsEmpty());
+
+ // Clear out any OOF fragmentainer descendants that had been re-propagated
+ // when setting up |multicol_container_builder|.
+ // TODO(almaher): Avoid adding the descendants again to begin with.
+ multicol_container_builder.ClearOutOfFlowFragmentainerDescendants();
+
+ // Layout the OOF positioned elements inside the inner multicol.
+ NGOutOfFlowLayoutPart(multicol, multicol_constraint_space,
+ &multicol_container_builder)
+ .LayoutFragmentainerDescendants(
+ &oof_nodes_to_layout, column_inline_progression, &multicol_children);
+}
+
void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendants(
- Vector<NGLogicalOutOfFlowPositionedNode>* descendants) {
+ Vector<NGLogicalOutOfFlowPositionedNode>* descendants,
+ LayoutUnit column_inline_progression,
+ Vector<MulticolChildInfo>* multicol_children) {
+ nested_fragmentation_context_ = multicol_children;
original_column_block_size_ =
ShrinkLogicalSize(container_builder_->InitialBorderBoxSize(),
container_builder_->BorderScrollbarPadding())
@@ -635,27 +789,38 @@ void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendants(
while (descendants->size() > 0) {
for (auto& descendant : *descendants) {
- LayoutFragmentainerDescendant(descendant);
+ scoped_refptr<const NGLayoutResult> result =
+ LayoutFragmentainerDescendant(descendant);
+ // TODO(almaher): Handle nested OOFs and inner multicols with pending OOFs
+ // in the case of nested fragmentation.
+ container_builder_->PropagateOOFPositionedInfo(
+ result->PhysicalFragment(), result->OutOfFlowPositionedOffset());
}
- // Sweep any descendants that might have been added.
- // This happens when an absolute container has a fixed child.
+ // Sweep any descendants that might have been bubbled up from the fragment
+ // to the |container_builder_|. This happens when we have nested absolute
+ // position elements.
descendants->Shrink(0);
container_builder_->SwapOutOfFlowFragmentainerDescendants(descendants);
}
// Add all of the descendant layout results as children to the fragment at
// the associated index.
- for (const auto& descendant_result : fragmentainer_descendant_results_) {
- // We don't allow keys of 0, so shift the index back by 1 when adding to the
- // fragmentainer.
- wtf_size_t index = descendant_result.key - 1;
- const Vector<scoped_refptr<const NGLayoutResult>>& results =
- descendant_result.value;
- AddOOFResultsToFragmentainer(results, index);
+ wtf_size_t index = 0;
+ while (!fragmentainer_descendant_results_.IsEmpty()) {
+ // We don't allow keys of 0, so shift the index by 1.
+ auto it = fragmentainer_descendant_results_.find(index + 1);
+ if (it != fragmentainer_descendant_results_.end()) {
+ Vector<scoped_refptr<const NGLayoutResult>>& results = it->value;
+ AddOOFResultsToFragmentainer(results, index, column_inline_progression,
+ multicol_children);
+ fragmentainer_descendant_results_.erase(it);
+ }
+ index++;
}
}
-void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant(
+scoped_refptr<const NGLayoutResult>
+NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant(
const NGLogicalOutOfFlowPositionedNode& descendant) {
NGBlockNode node = descendant.node;
const NGPhysicalContainerFragment* containing_block_fragment =
@@ -665,7 +830,7 @@ void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant(
containing_block_fragment->GetLayoutObject() ==
node.GetLayoutBox()->ContainingBlock());
- const ContainingBlockInfo& container_info =
+ const ContainingBlockInfo container_info =
GetContainingBlockInfo(descendant, containing_block_fragment);
const auto default_writing_direction =
containing_block_fragment->Style().GetWritingDirection();
@@ -673,19 +838,18 @@ void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant(
const auto descendant_writing_direction =
descendant_style.GetWritingDirection();
- LogicalSize container_content_size =
- container_info.ContentSize(descendant_style.GetPosition());
+ LogicalSize container_content_size = container_info.rect.size;
PhysicalSize container_physical_content_size = ToPhysicalSize(
container_content_size, default_writing_direction.GetWritingMode());
// Adjust the |static_position| (which is currently relative to the default
// container's border-box). ng_absolute_utils expects the static position to
// be relative to the container's padding-box. Since
- // |container_info.container_offset| is relative to its fragmentainer in this
+ // |container_info.rect.offset| is relative to its fragmentainer in this
// case, we also need to adjust the offset to account for this.
NGLogicalStaticPosition static_position = descendant.static_position;
static_position.offset -=
- container_info.container_offset - descendant.containing_block_offset;
+ container_info.rect.offset - descendant.containing_block_offset;
NGLogicalStaticPosition descendant_static_position =
static_position
@@ -702,10 +866,10 @@ void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant(
builder.SetPercentageResolutionSize(container_content_size);
NGConstraintSpace descendant_constraint_space = builder.ToConstraintSpace();
- Layout(node, descendant_constraint_space, descendant_static_position,
- container_physical_content_size, container_info,
- default_writing_direction, /* only_layout */ nullptr,
- /* is_fragmentainer_descendant */ true);
+ return Layout(node, descendant_constraint_space, descendant_static_position,
+ container_physical_content_size, container_info,
+ default_writing_direction, /* only_layout */ nullptr,
+ /* is_fragmentainer_descendant */ true);
}
scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
@@ -792,15 +956,17 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
if (is_replaced) {
ComputeReplacedSize(node, candidate_constraint_space, min_max_sizes,
&replaced_size, &aspect_ratio);
- has_aspect_ratio_without_intrinsic_size =
- !replaced_size && aspect_ratio && !aspect_ratio->IsEmpty();
+ DCHECK(replaced_size.has_value() != aspect_ratio.has_value());
+ has_aspect_ratio_without_intrinsic_size = aspect_ratio.has_value();
// If we only have aspect ratio, and no replaced size, intrinsic size
// defaults to 300x150. min_max_sizes gets computed from the intrinsic size.
// We reset the min_max_sizes because spec says that OOF-positioned size
// should not be constrained by intrinsic size in this case.
// https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
- if (has_aspect_ratio_without_intrinsic_size)
+ if (has_aspect_ratio_without_intrinsic_size) {
min_max_sizes = MinMaxSizes{LayoutUnit(), LayoutUnit::NearlyMax()};
+ DCHECK(!aspect_ratio->IsEmpty()) << *aspect_ratio;
+ }
} else if (!candidate_style.AspectRatio().IsAuto()) {
has_aspect_ratio_without_intrinsic_size = true;
aspect_ratio = node.GetAspectRatio();
@@ -839,15 +1005,14 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
node_dimensions.size.inline_size));
}
- // TODO(almaher): Handle fragmentation separately for the case where
- // |absolute_needs_child_block_size| is true.
if (absolute_needs_child_block_size) {
DCHECK(!has_computed_block_dimensions);
layout_result = GenerateFragment(
node, container_content_size_in_candidate_writing_mode, block_estimate,
node_dimensions, /* block_offset */ LayoutUnit(),
/* break_token */ nullptr,
- /* fragmentainer_constraint_space */ nullptr);
+ /* fragmentainer_constraint_space */ nullptr,
+ /* should_use_fixed_block_size */ false);
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK(layout_result->Status() != NGLayoutResult::kOutOfFragmentainerSpace);
@@ -867,6 +1032,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
container_writing_direction, &node_dimensions);
has_computed_block_dimensions = true;
}
+ block_estimate = node_dimensions.size.block_size;
// Calculate the offsets.
NGBoxStrut inset =
@@ -875,7 +1041,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// |inset| is relative to the container's padding-box. Convert this to being
// relative to the default container's border-box.
- LogicalOffset offset = container_info.container_offset;
+ LogicalOffset offset = container_info.rect.offset;
offset.inline_offset += inset.inline_start;
offset.block_offset += inset.block_start;
@@ -887,10 +1053,10 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
DCHECK_GT(num_children, 0u);
ComputeStartFragmentIndexAndRelativeOffset(
container_info, default_writing_direction.GetWritingMode(),
- &start_index, &offset);
+ *block_estimate, &start_index, &offset);
}
- if (!only_layout) {
+ if (!only_layout && !can_traverse_fragments_) {
// Special case: oof css container is a split inline.
// When css container spans multiple anonymous blocks, its dimensions can
// only be computed by a block that is an ancestor of all fragments
@@ -939,6 +1105,10 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
}
}
+ // Reset the |layout_result| computed earlier to allow fragmentation in the
+ // next layout pass, if needed.
+ if (is_fragmentainer_descendant)
+ layout_result = nullptr;
const NGBlockBreakToken* break_token = nullptr;
do {
if (break_token) {
@@ -955,18 +1125,21 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
offset.block_offset = LayoutUnit();
}
- // Skip this step if we produced a fragment when estimating the
- // block-size.
+ // Skip this step if we produced a fragment that can be reused when
+ // estimating the block-size.
if (!layout_result) {
- block_estimate = node_dimensions.size.block_size;
- const NGConstraintSpace* fragmentainer_constraint_space =
- is_fragmentainer_descendant
- ? &GetFragmentainerConstraintSpace(start_index)
- : nullptr;
+ const NGConstraintSpace* fragmentainer_constraint_space = nullptr;
+ bool should_use_fixed_block_size = !!block_estimate;
+ if (is_fragmentainer_descendant) {
+ fragmentainer_constraint_space =
+ &GetFragmentainerConstraintSpace(start_index);
+ should_use_fixed_block_size &= !absolute_needs_child_block_size;
+ }
+
layout_result = GenerateFragment(
node, container_content_size_in_candidate_writing_mode,
block_estimate, node_dimensions, offset.block_offset, break_token,
- fragmentainer_constraint_space);
+ fragmentainer_constraint_space, should_use_fixed_block_size);
}
// TODO(layout-dev): Handle abortions caused by block fragmentation.
@@ -1001,6 +1174,10 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
bool NGOutOfFlowLayoutPart::IsContainingBlockForCandidate(
const NGLogicalOutOfFlowPositionedNode& candidate) {
+ // Column boxes are not allowed to be containing blocks.
+ if (container_builder_->IsFragmentainerBoxType())
+ return false;
+
EPosition position = candidate.node.Style().GetPosition();
// Candidates whose containing block is inline are always positioned inside
@@ -1027,7 +1204,8 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
const NGLogicalOutOfFlowDimensions& node_dimensions,
const LayoutUnit block_offset,
const NGBlockBreakToken* break_token,
- const NGConstraintSpace* fragmentainer_constraint_space) {
+ const NGConstraintSpace* fragmentainer_constraint_space,
+ bool should_use_fixed_block_size) {
const auto& style = node.Style();
LayoutUnit inline_size = node_dimensions.size.inline_size;
@@ -1045,7 +1223,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
builder.SetPercentageResolutionSize(
container_content_size_in_candidate_writing_mode);
builder.SetIsFixedInlineSize(true);
- if (block_estimate)
+ if (should_use_fixed_block_size)
builder.SetIsFixedBlockSize(true);
if (fragmentainer_constraint_space) {
SetupSpaceBuilderForFragmentation(*fragmentainer_constraint_space, node,
@@ -1059,16 +1237,30 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
void NGOutOfFlowLayoutPart::AddOOFResultsToFragmentainer(
const Vector<scoped_refptr<const NGLayoutResult>>& results,
- wtf_size_t index) {
+ wtf_size_t index,
+ LayoutUnit column_inline_progression,
+ Vector<MulticolChildInfo>* multicol_children) {
wtf_size_t num_children = container_builder_->Children().size();
bool is_new_fragment = index >= num_children;
+ // If an OOF positioned element is in a nested context, and it fragments
+ // beyond the last fragmentainer, we don't create a new column for it.
+ // Rather, we will add it to the last existing fragmentainter at the
+ // correct inline offset.
+ bool create_new_fragment = is_new_fragment && !nested_fragmentation_context_;
+ bool add_to_last_fragment = is_new_fragment && nested_fragmentation_context_;
+
+ wtf_size_t num_new_fragmentainers;
+ if (is_new_fragment)
+ num_new_fragmentainers = index - num_children + 1;
+
// If |index| is greater than the number of current children, we need to add
// empty column fragments at all of the indexes leading up to |index|.
- if (index > num_children) {
+ if (create_new_fragment) {
const Vector<scoped_refptr<const NGLayoutResult>> empty_results;
while (index > num_children) {
- AddOOFResultsToFragmentainer(empty_results, /*index */ num_children);
+ AddOOFResultsToFragmentainer(empty_results, /*index */ num_children,
+ column_inline_progression);
num_children++;
}
DCHECK_EQ(index, container_builder_->Children().size());
@@ -1107,16 +1299,24 @@ void NGOutOfFlowLayoutPart::AddOOFResultsToFragmentainer(
// |algorithm| corresponds to the "mutable copy" of our original
// fragmentainer. As long as this "copy" hasn't been laid out via
// NGSimplifiedOOFLayoutAlgorithm::Layout, we can append new items to it.
- NGSimplifiedOOFLayoutAlgorithm algorithm(params, fragment, is_new_fragment);
+ NGSimplifiedOOFLayoutAlgorithm algorithm(params, fragment,
+ create_new_fragment);
for (const auto& result : results) {
- // TODO(bebeaudr): Is the offset returned by OutOfFlowPositionedOffset the
- // one to use?
- algorithm.AppendOutOfFlowResult(result,
- result->OutOfFlowPositionedOffset());
+ // If we are adding the result to the last fragmentainer rather than
+ // creating a new fragmentainer to hold it, adjust the inline offset as if
+ // we had created a new fragmentainer.
+ if (add_to_last_fragment) {
+ LogicalOffset oof_offset = result->OutOfFlowPositionedOffset();
+ oof_offset.inline_offset +=
+ column_inline_progression * num_new_fragmentainers;
+ result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(
+ oof_offset, allow_first_tier_oof_cache_);
+ }
+ algorithm.AppendOutOfFlowResult(result);
}
- if (is_new_fragment) {
+ if (create_new_fragment) {
LogicalOffset offset;
if (index != num_children - 1 && !container_builder_->Children()[index + 1]
.fragment->IsFragmentainerBox()) {
@@ -1131,25 +1331,35 @@ void NGOutOfFlowLayoutPart::AddOOFResultsToFragmentainer(
// TODO(almaher): Include trailing spanner margin.
offset.block_offset += spanner_size.block_size;
} else {
- // Calculate the column inline progression in order to calculate the
- // inline offset of any newly added column fragments.
- if (column_inline_progression_ == kIndefiniteSize) {
- LayoutUnit available_size =
- container_builder_->ChildAvailableSize().inline_size;
- const ComputedStyle& style = container_builder_->Style();
- LayoutUnit column_inline_size =
- ResolveUsedColumnInlineSize(available_size, style);
- column_inline_progression_ =
- column_inline_size + ResolveUsedColumnGap(available_size, style);
- }
offset = fragmentainer.offset;
- offset.inline_offset += column_inline_progression_;
+ offset.inline_offset += column_inline_progression;
}
- container_builder_->AddChild(algorithm.Layout()->PhysicalFragment(),
- offset);
+ scoped_refptr<const NGLayoutResult> new_result = algorithm.Layout();
+ node.AddColumnResult(new_result);
+ container_builder_->AddChild(new_result->PhysicalFragment(), offset);
} else {
- container_builder_->ReplaceChild(
- index, algorithm.Layout()->PhysicalFragment(), fragmentainer.offset);
+ scoped_refptr<const NGLayoutResult> new_result = algorithm.Layout();
+ node.ReplaceColumnResult(new_result, fragment);
+ const NGPhysicalContainerFragment* new_fragment =
+ &new_result->PhysicalFragment();
+ container_builder_->ReplaceChild(index, *new_fragment,
+ fragmentainer.offset);
+
+ if (nested_fragmentation_context_) {
+ // We are in a nested fragmentation context. Replace the column entry
+ // and break token directly in the existing multicol fragment.
+ DCHECK(multicol_children);
+ MulticolChildInfo& column_info = (*multicol_children)[index];
+ if (auto* parent_break_token = column_info.parent_break_token) {
+ DCHECK_GT(parent_break_token->ChildBreakTokens().size(), 0u);
+ parent_break_token->GetMutableForOutOfFlow().ReplaceChildBreakToken(
+ new_fragment->BreakToken(),
+ parent_break_token->ChildBreakTokens().size() - 1);
+ }
+ column_info.mutable_link->fragment->Release();
+ new (&column_info.mutable_link->fragment)
+ scoped_refptr<const NGPhysicalFragment>(std::move(new_fragment));
+ }
}
}
@@ -1195,7 +1405,8 @@ const NGConstraintSpace& NGOutOfFlowLayoutPart::GetFragmentainerConstraintSpace(
// If we are a new fragment and are separated from other columns by a
// spanner, compute the correct column block size to use.
- if (is_new_fragment && index != num_children - 1 &&
+ if (is_new_fragment && !nested_fragmentation_context_ &&
+ index != num_children - 1 &&
original_column_block_size_ != kIndefiniteSize &&
!container_builder_->Children()[index + 1]
.fragment->IsFragmentainerBox()) {
@@ -1241,6 +1452,7 @@ void NGOutOfFlowLayoutPart::AddOOFResultToFragmentainerResults(
void NGOutOfFlowLayoutPart::ComputeStartFragmentIndexAndRelativeOffset(
const ContainingBlockInfo& container_info,
WritingMode default_writing_mode,
+ LayoutUnit block_estimate,
wtf_size_t* start_index,
LogicalOffset* offset) const {
wtf_size_t child_index = 0;
@@ -1257,9 +1469,20 @@ void NGOutOfFlowLayoutPart::ComputeStartFragmentIndexAndRelativeOffset(
fragmentainer_block_size = child.fragment->Size()
.ConvertToLogical(default_writing_mode)
.block_size;
+ fragmentainer_block_size =
+ ClampedToValidFragmentainerCapacity(fragmentainer_block_size);
current_max_block_size += fragmentainer_block_size;
- if (offset->block_offset < current_max_block_size) {
+ // Edge case: an abspos with an height of 0 positioned exactly at the
+ // |current_max_block_size| won't be fragmented, so no break token will be
+ // produced - as we'd expect. However, the break token is used to compute
+ // the |fragmentainer_consumed_block_size_| stored on the
+ // |container_builder_| when we have a nested abspos. Because we use that
+ // value to position the nested abspos, its start offset would be off by
+ // exactly one fragmentainer block size.
+ if (offset->block_offset < current_max_block_size ||
+ (offset->block_offset == current_max_block_size &&
+ block_estimate == 0)) {
*start_index = child_index;
offset->block_offset -= used_block_size;
return;
@@ -1274,13 +1497,15 @@ void NGOutOfFlowLayoutPart::ComputeStartFragmentIndexAndRelativeOffset(
// If we are a new fragment and are separated from other columns by a
// spanner, compute the correct fragmentainer_block_size.
- if (original_column_block_size_ != kIndefiniteSize &&
+ if (!nested_fragmentation_context_ &&
+ original_column_block_size_ != kIndefiniteSize &&
!container_builder_->Children()[child_index - 1]
.fragment->IsFragmentainerBox()) {
fragmentainer_block_size =
original_column_block_size_ -
container_builder_->BlockOffsetForAdditionalColumns();
- fragmentainer_block_size = fragmentainer_block_size.ClampNegativeToZero();
+ fragmentainer_block_size =
+ ClampedToValidFragmentainerCapacity(fragmentainer_block_size);
}
wtf_size_t additional_fragment_count =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index 0136cf24862..0e8fbe870fb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "base/optional.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
@@ -25,6 +26,7 @@ class NGBlockNode;
class NGBoxFragmentBuilder;
class NGLayoutResult;
class NGPhysicalContainerFragment;
+struct NGLink;
struct NGLogicalOutOfFlowPositionedNode;
// Helper class for positioning of out-of-flow blocks.
@@ -80,23 +82,30 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
// The writing direction of the container.
WritingDirectionMode writing_direction = {WritingMode::kHorizontalTb,
TextDirection::kLtr};
- // Logical in containing block coordinates.
- LogicalSize content_size_for_absolute;
- // Content size for fixed is different for the ICB.
- LogicalSize content_size_for_fixed;
-
- // Offset of the container's padding-box.
- LogicalOffset container_offset;
-
- LogicalSize ContentSize(EPosition position) const {
- return position == EPosition::kAbsolute ? content_size_for_absolute
- : content_size_for_fixed;
- }
+ // Size and offset of the container.
+ LogicalRect rect;
+ };
+
+ // TODO(almaher): Move this to the multicol algorithm in upcoming refactor.
+ // This stores the information needed to update a multicol child inside an
+ // existing multicol fragment. This is used during nested fragmentation of an
+ // OOF positioned element.
+ struct MulticolChildInfo {
+ // The mutable link of a multicol child.
+ NGLink* mutable_link;
+
+ // The multicol break token that stores a reference to |mutable_link|'s
+ // break token in its list of child break tokens.
+ const NGBlockBreakToken* parent_break_token;
+
+ explicit MulticolChildInfo(NGLink* mutable_link,
+ NGBlockBreakToken* parent_break_token = nullptr)
+ : mutable_link(mutable_link), parent_break_token(parent_break_token) {}
};
bool SweepLegacyCandidates(HashSet<const LayoutObject*>* placed_objects);
- const ContainingBlockInfo& GetContainingBlockInfo(
+ const ContainingBlockInfo GetContainingBlockInfo(
const NGLogicalOutOfFlowPositionedNode&,
const NGPhysicalContainerFragment* = nullptr);
@@ -111,10 +120,18 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
const NGLogicalOutOfFlowPositionedNode&,
const LayoutBox* only_layout);
+ void LayoutOOFsInMulticol(const NGBlockNode& multicol);
+
+ // Layout the OOF nodes that are descendants of a fragmentation context root.
+ // |multicol_children| holds the children of an inner multicol if
+ // we are laying out OOF elements inside a nested fragmentation context.
void LayoutFragmentainerDescendants(
- Vector<NGLogicalOutOfFlowPositionedNode>* descendants);
+ Vector<NGLogicalOutOfFlowPositionedNode>* descendants,
+ LayoutUnit column_inline_progression,
+ Vector<MulticolChildInfo>* multicol_children = nullptr);
- void LayoutFragmentainerDescendant(const NGLogicalOutOfFlowPositionedNode&);
+ scoped_refptr<const NGLayoutResult> LayoutFragmentainerDescendant(
+ const NGLogicalOutOfFlowPositionedNode&);
scoped_refptr<const NGLayoutResult> Layout(
NGBlockNode,
@@ -135,10 +152,13 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
const NGLogicalOutOfFlowDimensions& node_dimensions,
const LayoutUnit block_offset,
const NGBlockBreakToken* break_token,
- const NGConstraintSpace* fragmentainer_constraint_space);
+ const NGConstraintSpace* fragmentainer_constraint_space,
+ bool should_use_fixed_block_size);
void AddOOFResultsToFragmentainer(
const Vector<scoped_refptr<const NGLayoutResult>>& results,
- wtf_size_t index);
+ wtf_size_t index,
+ LayoutUnit column_inline_progression,
+ Vector<MulticolChildInfo>* multicol_children = nullptr);
const NGConstraintSpace& GetFragmentainerConstraintSpace(wtf_size_t index);
void AddOOFResultToFragmentainerResults(
const scoped_refptr<const NGLayoutResult> result,
@@ -146,11 +166,13 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
void ComputeStartFragmentIndexAndRelativeOffset(
const ContainingBlockInfo& container_info,
WritingMode default_writing_mode,
+ LayoutUnit block_estimate,
wtf_size_t* start_index,
LogicalOffset* offset) const;
NGBoxFragmentBuilder* container_builder_;
- ContainingBlockInfo default_containing_block_;
+ ContainingBlockInfo default_containing_block_info_for_absolute_;
+ ContainingBlockInfo default_containing_block_info_for_fixed_;
HashMap<const LayoutObject*, ContainingBlockInfo> containing_blocks_map_;
HashMap<wtf_size_t, NGConstraintSpace> fragmentainer_constraint_space_map_;
// Map of fragmentainer indexes to a list of descendant layout results to
@@ -158,7 +180,7 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
HashMap<wtf_size_t, Vector<scoped_refptr<const NGLayoutResult>>>
fragmentainer_descendant_results_;
const WritingMode writing_mode_;
- LayoutUnit column_inline_progression_ = kIndefiniteSize;
+ const WritingDirectionMode default_writing_direction_;
// The block size of the multi-column (before adjustment for spanners, etc.)
// This is used to calculate the column size of any newly added proxy
// fragments when handling fragmentation for abspos elements.
@@ -167,6 +189,8 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
bool is_fixed_container_;
bool allow_first_tier_oof_cache_;
bool has_block_fragmentation_;
+ bool can_traverse_fragments_ = false;
+ bool nested_fragmentation_context_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index 239d73cbc95..7418bb509f6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -569,10 +569,8 @@ TEST_F(NGOutOfFlowLayoutPartTest, ChildBreakAfterAvoid) {
// Tests that a positioned element with a negative top property moves the OOF
// node to the previous fragmentainer and spans 3 columns.
-// TODO(bebeaudr): Figure out why this is crashing. https://crbug.com/1117625.
-TEST_F(
- NGOutOfFlowLayoutPartTest,
- DISABLED_PositionedFragmentationWithNegativeTopPropertyAndNewEmptyColumn) {
+TEST_F(NGOutOfFlowLayoutPartTest,
+ PositionedFragmentationWithNegativeTopPropertyAndNewEmptyColumn) {
SetBodyInnerHTML(
R"HTML(
<style>
@@ -588,7 +586,7 @@ TEST_F(
</style>
<div id="container">
<div id="multicol">
- <div class="rel" style="height: 60px; width: 32px;"></div>
+ <div style="height: 60px; width: 32px;"></div>
<div class="rel">
<div class="abs"></div>
</div>
@@ -605,8 +603,8 @@ TEST_F(
offset:0,20 size:5x20
offset:508,0 size:492x40
offset:0,0 size:32x20
- offset:0,20 size:30x0
offset:0,0 size:5x40
+ offset:0,20 size:30x0
offset:1016,0 size:492x40
offset:0,0 size:5x20
)DUMP";
@@ -728,7 +726,7 @@ TEST_F(NGOutOfFlowLayoutPartTest, PositionedFragmentationAndColumnSpanners) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x40
offset:0,0 size:1000x40
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:30x0
offset:0,0 size:1000x0
offset:0,0 size:492x30
@@ -777,7 +775,7 @@ TEST_F(NGOutOfFlowLayoutPartTest, PositionedFragmentationWithNestedSpanner) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x40
offset:0,0 size:1000x40
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:30x0
offset:0,0 size:1000x0
offset:0,0 size:492x40
@@ -824,7 +822,7 @@ TEST_F(NGOutOfFlowLayoutPartTest, PositionedFragmentationWithNestedSpanners) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x40
offset:0,0 size:1000x40
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:1000x0
offset:0,0 size:492x10
offset:0,0 size:30x10
@@ -844,11 +842,9 @@ TEST_F(NGOutOfFlowLayoutPartTest, PositionedFragmentationWithNestedSpanners) {
EXPECT_EQ(expectation, dump);
}
-// Tests that column spanners are used as the containing block for abspos
-// elements nested inside of a spanner.
-// TODO(almaher): Abspos elements nested in a spanner are never getting laid
-// out.
-TEST_F(NGOutOfFlowLayoutPartTest, DISABLED_AbsposInSpanner) {
+// Tests that abspos elements bubble up to their containing block when nested
+// inside of a spanner.
+TEST_F(NGOutOfFlowLayoutPartTest, AbsposInSpanner) {
SetBodyInnerHTML(
R"HTML(
<style>
@@ -856,17 +852,74 @@ TEST_F(NGOutOfFlowLayoutPartTest, DISABLED_AbsposInSpanner) {
column-count:2; column-fill:auto; column-gap:16px; height:40px;
}
.rel {
- position: relative; width:30px;
+ position: relative;
+ }
+ .abs {
+ position:absolute; width:5px; height:50px; top:5px;
+ }
+ </style>
+ <div id="container">
+ <div class="rel" style="width:50px;">
+ <div id="multicol">
+ <div class="rel" style="width:30px;">
+ <div style="width:10px; height:30px;"></div>
+ <div>
+ <div style="column-span:all;">
+ <div class="abs"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ String dump = DumpFragmentTree(GetElementById("container"));
+
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x40
+ offset:0,0 size:50x40
+ offset:0,0 size:50x40
+ offset:0,0 size:17x15
+ offset:0,0 size:30x15
+ offset:0,0 size:10x15
+ offset:33,0 size:17x15
+ offset:0,0 size:30x15
+ offset:0,0 size:10x15
+ offset:0,15 size:30x0
+ offset:0,15 size:50x0
+ offset:0,15 size:17x25
+ offset:0,0 size:30x0
+ offset:0,0 size:30x0
+ offset:0,5 size:5x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that abspos elements bubble up to their containing block when nested
+// inside of a spanner and get the correct static position.
+TEST_F(NGOutOfFlowLayoutPartTest, AbsposInSpannerStaticPos) {
+ SetBodyInnerHTML(
+ R"HTML(
+ <style>
+ #multicol {
+ column-count:2; column-fill:auto; column-gap:16px; height:40px;
+ }
+ .rel {
+ position: relative;
}
.abs {
position:absolute; width:5px; height:50px;
}
</style>
<div id="container">
- <div id="multicol">
- <div class="rel">
- <div style="column-span:all;">
- <div class="abs"></div>
+ <div class="rel" style="width:50px;">
+ <div id="multicol">
+ <div class="rel" style="width:30px;">
+ <div style="width:10px; height:30px;"></div>
+ <div style="column-span:all; margin-top:5px;">
+ <div style="width:20px; height:5px;"></div>
+ <div class="abs"></div>
+ </div>
</div>
</div>
</div>
@@ -876,13 +929,19 @@ TEST_F(NGOutOfFlowLayoutPartTest, DISABLED_AbsposInSpanner) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x40
- offset:0,0 size:1000x40
- offset:0,0 size:492x1
- offset:0,0 size:30x0
- offset:0,0 size:1000x0
- offset:0,0 size:5x50
- offset:0,0 size:492x40
- offset:0,0 size:30x0
+ offset:0,0 size:50x40
+ offset:0,0 size:50x40
+ offset:0,0 size:17x15
+ offset:0,0 size:30x15
+ offset:0,0 size:10x15
+ offset:33,0 size:17x15
+ offset:0,0 size:30x15
+ offset:0,0 size:10x15
+ offset:0,20 size:50x5
+ offset:0,0 size:20x5
+ offset:0,25 size:17x15
+ offset:0,0 size:30x0
+ offset:0,25 size:5x50
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1069,17 +1128,17 @@ TEST_F(NGOutOfFlowLayoutPartTest,
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x0
offset:0,0 size:1000x0
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:30x0
offset:0,0 size:5x1
offset:0,0 size:1000x0
offset:0,0 size:1000x0
offset:0,0 size:1000x0
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:5x1
- offset:508,0 size:492x1
+ offset:508,0 size:492x0
offset:0,0 size:5x1
- offset:1016,0 size:492x1
+ offset:1016,0 size:492x0
offset:0,0 size:5x1
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -1118,7 +1177,7 @@ TEST_F(NGOutOfFlowLayoutPartTest, AbsposFragWithSpannerAndNewEmptyColumns) {
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x40
offset:0,0 size:1000x40
- offset:0,0 size:492x1
+ offset:0,0 size:492x0
offset:0,0 size:30x0
offset:0,0 size:1000x0
offset:0,0 size:1000x0
@@ -1246,7 +1305,7 @@ TEST_F(NGOutOfFlowLayoutPartTest,
}
// Fragmented OOF element inside a nested multi-column.
-TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentation) {
+TEST_F(NGOutOfFlowLayoutPartTest, SimpleAbsposNestedFragmentation) {
SetBodyInnerHTML(
R"HTML(
<style>
@@ -1254,10 +1313,10 @@ TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentation) {
columns:2; column-fill:auto; column-gap:0px;
}
.rel {
- position: relative; width:55px;
+ position: relative; width:55px; height:80px;
}
.abs {
- position:absolute; top:0px; bottom:0px; width:5px;
+ position:absolute; top:0px; width:5px; height:80px;
}
</style>
<div id="container">
@@ -1266,7 +1325,6 @@ TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentation) {
<div class="multicol" id="inner">
<div class="rel">
<div class="abs"></div>
- <div style="height:250px; width:25px;"></div>
</div>
</div>
</div>
@@ -1274,9 +1332,6 @@ TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentation) {
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
- // TODO(almaher): There should be two abspos fragments with height 60 in the
- // first outer column, and two with height 100/30 in the second outer column.
- // There should not be a third outer column.
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:1000x100
@@ -1285,25 +1340,172 @@ TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentation) {
offset:0,40 size:500x60
offset:0,0 size:250x60
offset:0,0 size:55x60
- offset:0,0 size:25x60
+ offset:0,0 size:5x60
offset:250,0 size:250x60
- offset:0,0 size:55x60
- offset:0,0 size:25x60
- offset:0,40 size:5x60
- offset:500,0 size:500x100
- offset:0,0 size:500x100
- offset:0,0 size:250x100
- offset:0,0 size:55x100
- offset:0,0 size:25x100
- offset:250,0 size:250x100
- offset:0,0 size:55x30
- offset:0,0 size:25x30
- offset:0,0 size:5x100
- offset:1000,0 size:500x100
- offset:0,0 size:5x90
+ offset:0,0 size:55x20
+ offset:0,0 size:5x20
)DUMP";
EXPECT_EQ(expectation, dump);
}
+// Fragmented OOF element inside a nested multi-column with new columns.
+TEST_F(NGOutOfFlowLayoutPartTest, AbsposNestedFragmentationNewColumns) {
+ SetBodyInnerHTML(
+ R"HTML(
+ <style>
+ .multicol {
+ columns:2; column-fill:auto; column-gap:0px;
+ }
+ #inner {
+ column-gap:16px; height:40px; padding:10px;
+ }
+ .rel {
+ position: relative; width:55px; height:20px;
+ }
+ .abs {
+ position:absolute; top:0px; width:5px; height:40px;
+ }
+ </style>
+ <div id="container">
+ <div class="multicol" id="outer" style="height:100px;">
+ <div style="height:40px; width:40px;"></div>
+ <div class="multicol" id="inner">
+ <div class="rel">
+ <div class="abs"></div>
+ </div>
+ <div style="column-span:all;"></div>
+ <div style="column-span:all;"></div>
+ <div style="column-span:all;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ String dump = DumpFragmentTree(GetElementById("container"));
+
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:1000x100
+ offset:0,0 size:500x100
+ offset:0,0 size:40x40
+ offset:0,40 size:500x60
+ offset:10,10 size:232x10
+ offset:0,0 size:55x10
+ offset:0,0 size:5x10
+ offset:258,10 size:232x10
+ offset:0,0 size:55x10
+ offset:0,0 size:5x10
+ offset:248,0 size:5x10
+ offset:496,0 size:5x10
+ offset:10,20 size:480x0
+ offset:10,20 size:480x0
+ offset:10,20 size:480x0
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// TODO(almaher): Figure out why this is hitting a DCHECK in
+// AssertClearedPaintInvalidationFlags.
+//
+// Fragmented OOF element inside a nested multi-column starting at a
+// fragmentainer index beyond the last existing fragmentainer.
+TEST_F(NGOutOfFlowLayoutPartTest,
+ DISABLED_AbsposNestedFragmentationNewEmptyColumns) {
+ SetBodyInnerHTML(
+ R"HTML(
+ <style>
+ .multicol {
+ columns:2; column-fill:auto; column-gap:0px;
+ }
+ .rel {
+ position: relative; width:55px; height:80px;
+ }
+ .abs {
+ position:absolute; top:120px; width:5px; height:120px;
+ }
+ </style>
+ <div id="container">
+ <div class="multicol" id="outer" style="height:100px;">
+ <div style="height:40px; width:40px;"></div>
+ <div class="multicol" id="inner" style="column-gap:16px;">
+ <div class="rel">
+ <div class="abs"></div>
+ </div>
+ <div style="column-span:all;"></div>
+ <div style="column-span:all;"></div>
+ <div style="column-span:all;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ String dump = DumpFragmentTree(GetElementById("container"));
+
+ // TODO(almaher): The OOFs are added out of order due to how ordering is
+ // currently handled in NGSimplifiedOOFLayoutAlgorithm.
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:1000x100
+ offset:0,0 size:500x100
+ offset:0,0 size:40x40
+ offset:0,40 size:500x40
+ offset:0,0 size:242x40
+ offset:0,0 size:55x40
+ offset:258,0 size:242x40
+ offset:0,0 size:55x40
+ offset:774,0 size:5x40
+ offset:1032,0 size:5x40
+ offset:516,0 size:5x40
+ offset:0,40 size:500x0
+ offset:0,40 size:500x0
+ offset:0,40 size:500x0
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Fragmented OOF with `height: auto` and positioned with the bottom property.
+TEST_F(NGOutOfFlowLayoutPartTest,
+ PositionedFragmentationWithBottomPropertyAndHeightAuto) {
+ SetBodyInnerHTML(
+ R"HTML(
+ <style>
+ #multicol {
+ column-count:2; column-fill:auto; column-gap:16px; height:40px;
+ }
+ .rel {
+ position:relative; height:60px; width:32px;
+ }
+ .abs {
+ position:absolute; bottom:0; width:5px; height:auto;
+ }
+ </style>
+ <div id="container">
+ <div id="multicol">
+ <div class="rel">
+ <div class="abs">
+ <div style="width: 2px; height: 10px"></div>
+ <div style="width: 3px; height: 20px"></div>
+ <div style="width: 4px; height: 10px"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ String dump = DumpFragmentTree(GetElementById("container"));
+
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x40
+ offset:0,0 size:1000x40
+ offset:0,0 size:492x40
+ offset:0,0 size:32x40
+ offset:0,20 size:5x20
+ offset:0,0 size:2x10
+ offset:0,10 size:3x10
+ offset:508,0 size:492x40
+ offset:0,0 size:32x20
+ offset:0,0 size:5x20
+ offset:0,0 size:3x10
+ offset:0,10 size:4x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
index c1ff1621bba..bfba553d242 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
@@ -73,6 +73,7 @@ struct NGLogicalOutOfFlowPositionedNode {
bool needs_block_offset_adjustment;
LogicalOffset containing_block_offset;
scoped_refptr<const NGPhysicalContainerFragment> containing_block_fragment;
+ base::Optional<LogicalRect> containing_block_rect;
NGLogicalOutOfFlowPositionedNode(
NGBlockNode node,
@@ -81,13 +82,15 @@ struct NGLogicalOutOfFlowPositionedNode {
bool needs_block_offset_adjustment = false,
LogicalOffset containing_block_offset = LogicalOffset(),
scoped_refptr<const NGPhysicalContainerFragment>
- containing_block_fragment = nullptr)
+ containing_block_fragment = nullptr,
+ const base::Optional<LogicalRect> containing_block_rect = base::nullopt)
: node(node),
static_position(static_position),
inline_container(inline_container),
needs_block_offset_adjustment(needs_block_offset_adjustment),
containing_block_offset(containing_block_offset),
- containing_block_fragment(std::move(containing_block_fragment)) {
+ containing_block_fragment(std::move(containing_block_fragment)),
+ containing_block_rect(containing_block_rect) {
DCHECK(!inline_container ||
inline_container == inline_container->ContinuationRoot());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
index 805794074b6..f407db10b78 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
@@ -21,32 +21,4 @@ bool NGOutlineUtils::HasPaintedOutline(const ComputedStyle& style,
return true;
}
-bool NGOutlineUtils::ShouldPaintOutline(
- const NGPhysicalBoxFragment& physical_fragment) {
- if (!physical_fragment.IsInlineBox())
- return true;
- const LayoutObject* layout_object = physical_fragment.GetLayoutObject();
- DCHECK(layout_object);
- DCHECK(layout_object->IsLayoutInline());
-
- // A |LayoutInline| can be split across multiple objects. The first fragment
- // produced should paint the outline for *all* fragments.
- if (layout_object->IsElementContinuation()) {
- // If the |LayoutInline|'s continuation-root generated a fragment, we
- // shouldn't paint the outline.
- DCHECK(layout_object->ContinuationRoot());
- NGInlineCursor cursor;
- cursor.MoveTo(*layout_object->ContinuationRoot());
- if (cursor)
- return false;
- }
-
- // The first fragment paints all outlines. Check if this is the first fragment
- // for the |layout_object|.
- NGInlineCursor cursor;
- cursor.MoveTo(*layout_object);
- DCHECK(cursor);
- return cursor.Current().BoxFragment() == &physical_fragment;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h
index 39d3852b796..d17db79170d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h
@@ -12,19 +12,12 @@ namespace blink {
class ComputedStyle;
class Node;
-class NGPhysicalBoxFragment;
class CORE_EXPORT NGOutlineUtils {
STATIC_ONLY(NGOutlineUtils);
public:
static bool HasPaintedOutline(const ComputedStyle& style, const Node* node);
-
- // Returns true if this fragment should paint an outline.
- //
- // Specifically a |LayoutInline| can be split across multiple flows. The
- // first fragment produced should paint the outline for *all* fragments.
- static bool ShouldPaintOutline(const NGPhysicalBoxFragment&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
index 7219ad5e110..681b56cc494 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
@@ -58,7 +58,8 @@ scoped_refptr<const NGLayoutResult> NGPageLayoutAlgorithm::Layout() {
// Compute the block-axis size now that we know our content size.
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
container_builder_.SetFragmentsTotalBlockSize(block_size);
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
@@ -83,6 +84,7 @@ NGConstraintSpace NGPageLayoutAlgorithm::CreateConstraintSpaceForPages(
ConstraintSpace(), Style().GetWritingDirection(), /* is_new_fc */ true);
space_builder.SetAvailableSize(page_size);
space_builder.SetPercentageResolutionSize(page_size);
+ space_builder.SetStretchInlineSizeIfAuto(true);
// TODO(mstensho): Handle auto block size.
space_builder.SetFragmentationType(kFragmentPage);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index 8dde837c121..9795013bde1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
@@ -103,6 +102,7 @@ scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
bool has_rare_data =
builder->mathml_paint_info_ ||
!builder->oof_positioned_fragmentainer_descendants_.IsEmpty() ||
+ !builder->multicols_with_pending_oofs_.IsEmpty() ||
builder->table_grid_rect_ || builder->table_column_geometries_ ||
builder->table_collapsed_borders_ ||
builder->table_collapsed_borders_geometry_ ||
@@ -327,6 +327,10 @@ NGPhysicalBoxFragment::RareData::RareData(NGBoxFragmentBuilder* builder,
: PhysicalSize()),
descendant.containing_block_fragment);
}
+ if (builder->HasMulticolsWithPendingOOFs()) {
+ multicols_with_pending_oofs =
+ std::move(builder->multicols_with_pending_oofs_);
+ }
if (builder->table_grid_rect_)
table_grid_rect = *builder->table_grid_rect_;
if (builder->table_column_geometries_)
@@ -344,6 +348,7 @@ NGPhysicalBoxFragment::RareData::RareData(NGBoxFragmentBuilder* builder,
NGPhysicalBoxFragment::RareData::RareData(const RareData& other)
: oof_positioned_fragmentainer_descendants(
other.oof_positioned_fragmentainer_descendants),
+ multicols_with_pending_oofs(other.multicols_with_pending_oofs),
mathml_paint_info(other.mathml_paint_info
? new NGMathMLPaintInfo(*other.mathml_paint_info)
: nullptr),
@@ -370,6 +375,62 @@ NGPhysicalBoxFragment::CloneAsHiddenForPaint() const {
return builder.ToBoxFragment();
}
+const LayoutBox* NGPhysicalBoxFragment::OwnerLayoutBox() const {
+ const LayoutBox* owner_box =
+ DynamicTo<LayoutBox>(GetSelfOrContainerLayoutObject());
+ DCHECK(owner_box);
+ if (UNLIKELY(IsColumnBox())) {
+ owner_box = To<LayoutBox>(owner_box->SlowFirstChild());
+ DCHECK(owner_box && owner_box->IsLayoutFlowThread());
+ }
+ // Check |this| and the |LayoutBox| that produced it are in sync.
+ DCHECK(owner_box->PhysicalFragments().Contains(*this));
+ DCHECK_EQ(IsFirstForNode(), this == owner_box->GetPhysicalFragment(0));
+ return owner_box;
+}
+
+LayoutBox* NGPhysicalBoxFragment::MutableOwnerLayoutBox() const {
+ return const_cast<LayoutBox*>(OwnerLayoutBox());
+}
+
+PhysicalOffset NGPhysicalBoxFragment::OffsetFromOwnerLayoutBox() const {
+ // This function uses |FragmentData|, so must be |kPrePaintClean|.
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+
+ const LayoutBox* owner_box = OwnerLayoutBox();
+ DCHECK(owner_box);
+ DCHECK(owner_box->PhysicalFragments().Contains(*this));
+ if (owner_box->PhysicalFragmentCount() <= 1)
+ return PhysicalOffset();
+
+ // When LTR, compute the offset from the first fragment. The first fragment is
+ // at the left top of the |LayoutBox| regardless of the writing mode.
+ const auto* containing_block = owner_box->ContainingBlock();
+ const ComputedStyle& containing_block_style = containing_block->StyleRef();
+ if (IsLtr(containing_block_style.Direction())) {
+ DCHECK_EQ(IsFirstForNode(), this == owner_box->GetPhysicalFragment(0));
+ if (IsFirstForNode())
+ return PhysicalOffset();
+
+ const FragmentData* fragment_data =
+ owner_box->FragmentDataFromPhysicalFragment(*this);
+ DCHECK(fragment_data);
+ const FragmentData& first_fragment_data = owner_box->FirstFragment();
+ // All |FragmentData| for an NG block fragmented |LayoutObject| should be in
+ // the same transform node that their |PaintOffset()| are in the same
+ // coordinate system.
+ return fragment_data->PaintOffset() - first_fragment_data.PaintOffset();
+ }
+
+ // When RTL, compute the offset from the last fragment.
+ const FragmentData* fragment_data =
+ owner_box->FragmentDataFromPhysicalFragment(*this);
+ DCHECK(fragment_data);
+ const FragmentData& last_fragment_data = fragment_data->LastFragment();
+ return fragment_data->PaintOffset() - last_fragment_data.PaintOffset();
+}
+
const NGPhysicalBoxFragment* NGPhysicalBoxFragment::PostLayout() const {
const auto* layout_object = GetSelfOrContainerLayoutObject();
if (UNLIKELY(!layout_object)) {
@@ -523,7 +584,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
rect.offset.ConvertToLogical(writing_direction, container.Size(),
rect.size) +
rect.size.ConvertToLogical(writing_direction.GetWritingMode());
- return rect_logical_end.inline_offset > border_inline_start &&
+ return rect_logical_end.inline_offset > border_inline_start ||
rect_logical_end.block_offset > border_block_start;
}
@@ -559,7 +620,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
DCHECK_EQ(&child, cursor.CurrentItem());
DCHECK_EQ(child.Type(), NGFragmentItem::kLine);
if (padding_strut)
- AddLineBoxRect(child.RectInContainerBlock());
+ AddLineBoxRect(child.RectInContainerFragment());
const NGPhysicalLineBoxFragment* line_box = child.LineBoxFragment();
DCHECK(line_box);
PhysicalRect child_scrollable_overflow =
@@ -609,7 +670,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
item->PostLayoutBoxFragment()) {
if (child_box->IsFloatingOrOutOfFlowPositioned()) {
context.AddFloatingOrOutOfFlowPositionedChild(
- *child_box, item->OffsetInContainerBlock());
+ *child_box, item->OffsetInContainerFragment());
}
}
}
@@ -653,28 +714,58 @@ PhysicalSize NGPhysicalBoxFragment::ScrollSize() const {
return {box->ScrollWidth(), box->ScrollHeight()};
}
+const NGPhysicalBoxFragment*
+NGPhysicalBoxFragment::InlineContainerFragmentIfOutlineOwner() const {
+ DCHECK(IsInlineBox());
+ // In order to compute united outlines, collect all rectangles of inline
+ // fragments for |LayoutInline| if |this| is the first inline fragment.
+ // Otherwise return none.
+ const LayoutObject* layout_object = GetLayoutObject();
+ DCHECK(layout_object);
+ DCHECK(layout_object->IsLayoutInline());
+ NGInlineCursor cursor;
+ cursor.MoveTo(*layout_object);
+ DCHECK(cursor);
+ if (cursor.Current().BoxFragment() == this)
+ return &cursor.ContainerFragment();
+ if (!cursor.IsBlockFragmented())
+ return nullptr;
+
+ // When |LayoutInline| is block fragmented, unite rectangles for each block
+ // fragment. To do this, return |true| if |this| is the first inline fragment
+ // of a block fragment.
+ for (wtf_size_t previous_fragment_index = cursor.ContainerFragmentIndex();;) {
+ cursor.MoveToNextForSameLayoutObject();
+ DCHECK(cursor);
+ const wtf_size_t fragment_index = cursor.ContainerFragmentIndex();
+ if (cursor.Current().BoxFragment() == this) {
+ if (fragment_index != previous_fragment_index)
+ return &cursor.ContainerFragment();
+ return nullptr;
+ }
+ previous_fragment_index = fragment_index;
+ }
+}
+
PhysicalRect NGPhysicalBoxFragment::ComputeSelfInkOverflow() const {
DCHECK_EQ(PostLayout(), this);
CheckCanUpdateInkOverflow();
const ComputedStyle& style = Style();
- PhysicalRect ink_overflow({}, Size().ToLayoutSize());
+ if (!style.HasVisualOverflowingEffect())
+ return LocalRect();
DCHECK(GetLayoutObject());
- if (style.HasVisualOverflowingEffect()) {
- ink_overflow.Expand(style.BoxDecorationOutsets());
- if (NGOutlineUtils::HasPaintedOutline(style,
- GetLayoutObject()->GetNode()) &&
- NGOutlineUtils::ShouldPaintOutline(*this)) {
- Vector<PhysicalRect> outline_rects;
- // The result rects are in coordinates of this object's border box.
- AddSelfOutlineRects(
- PhysicalOffset(),
- GetLayoutObject()->OutlineRectsShouldIncludeBlockVisualOverflow(),
- &outline_rects);
- PhysicalRect rect = UnionRect(outline_rects);
- rect.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
- ink_overflow.Unite(rect);
- }
+ PhysicalRect ink_overflow(LocalRect());
+ ink_overflow.Expand(style.BoxDecorationOutsets());
+ if (NGOutlineUtils::HasPaintedOutline(style, GetNode()) && IsOutlineOwner()) {
+ Vector<PhysicalRect> outline_rects;
+ // The result rects are in coordinates of this object's border box.
+ AddSelfOutlineRects(PhysicalOffset(),
+ style.OutlineRectsShouldIncludeBlockVisualOverflow(),
+ &outline_rects);
+ PhysicalRect rect = UnionRect(outline_rects);
+ rect.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
+ ink_overflow.Unite(rect);
}
return ink_overflow;
}
@@ -683,33 +774,31 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
Vector<PhysicalRect>* outline_rects) const {
+ AddOutlineRects(additional_offset, outline_type,
+ /* container_relative */ false, outline_rects);
+}
+
+void NGPhysicalBoxFragment::AddOutlineRects(
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ Vector<PhysicalRect>* outline_rects) const {
+ AddOutlineRects(additional_offset, outline_type,
+ /* container_relative */ true, outline_rects);
+}
+
+void NGPhysicalBoxFragment::AddOutlineRects(
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ bool inline_container_relative,
+ Vector<PhysicalRect>* outline_rects) const {
DCHECK_EQ(PostLayout(), this);
- if (!NGOutlineUtils::ShouldPaintOutline(*this))
- return;
if (IsInlineBox()) {
- const LayoutObject* layout_object = GetLayoutObject();
- DCHECK(layout_object);
- DCHECK(layout_object->IsLayoutInline());
- Vector<PhysicalRect> blockflow_outline_rects =
- layout_object->OutlineRects(PhysicalOffset(), outline_type);
- // The rectangles returned are offset from the containing block. We need the
- // offset from this fragment.
- if (blockflow_outline_rects.size() > 0) {
- PhysicalOffset first_fragment_offset = blockflow_outline_rects[0].offset;
- PhysicalOffset corrected_offset =
- additional_offset - first_fragment_offset;
- for (auto& outline : blockflow_outline_rects) {
- // Skip if both width and height are zero. Containing blocks in empty
- // linebox is one such case.
- if (outline.size.IsZero())
- continue;
- outline.Move(corrected_offset);
- outline_rects->push_back(outline);
- }
- }
+ AddOutlineRectsForInlineBox(additional_offset, outline_type,
+ inline_container_relative, outline_rects);
return;
}
+ DCHECK(IsOutlineOwner());
// For anonymous blocks, the children add outline rects.
if (!IsAnonymousBlock())
@@ -739,6 +828,67 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
// LayoutBlockFlow::AddOutlineRects?
}
+void NGPhysicalBoxFragment::AddOutlineRectsForInlineBox(
+ PhysicalOffset additional_offset,
+ NGOutlineType outline_type,
+ bool container_relative,
+ Vector<PhysicalRect>* rects) const {
+ DCHECK_EQ(PostLayout(), this);
+ DCHECK(IsInlineBox());
+
+ const NGPhysicalBoxFragment* container =
+ InlineContainerFragmentIfOutlineOwner();
+ if (!container)
+ return;
+
+ // In order to compute united outlines, collect all rectangles of inline
+ // fragments for |LayoutInline| if |this| is the first inline fragment.
+ // Otherwise return none.
+ //
+ // When |LayoutInline| is block fragmented, unite rectangles for each block
+ // fragment.
+ DCHECK(GetLayoutObject());
+ DCHECK(GetLayoutObject()->IsLayoutInline());
+ const auto* layout_object = To<LayoutInline>(GetLayoutObject());
+ const wtf_size_t initial_rects_size = rects->size();
+ NGInlineCursor cursor(*container);
+ cursor.MoveTo(*layout_object);
+ DCHECK(cursor);
+#if DCHECK_IS_ON()
+ bool has_this_fragment = false;
+#endif
+ for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+ const NGInlineCursorPosition& current = cursor.Current();
+#if DCHECK_IS_ON()
+ has_this_fragment = has_this_fragment || current.BoxFragment() == this;
+#endif
+ if (!current.Size().IsZero())
+ rects->push_back(current.RectInContainerFragment());
+
+ // Add descendants if any, in the container-relative coordinate.
+ if (!current.HasChildren())
+ continue;
+ NGInlineCursor descendants = cursor.CursorForDescendants();
+ AddOutlineRectsForCursor(rects, PhysicalOffset(), outline_type,
+ layout_object, &descendants);
+ }
+#if DCHECK_IS_ON()
+ DCHECK(has_this_fragment);
+#endif
+ DCHECK_GE(rects->size(), initial_rects_size);
+ if (rects->size() <= initial_rects_size)
+ return;
+
+ // Adjust the rectangles using |additional_offset| and |container_relative|.
+ if (!container_relative)
+ additional_offset -= (*rects)[initial_rects_size].offset;
+ if (additional_offset.IsZero())
+ return;
+ for (PhysicalRect& rect :
+ base::make_span(rects->begin() + initial_rects_size, rects->end()))
+ rect.offset += additional_offset;
+}
+
PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
PhysicalOffset point) const {
if (layout_object_->IsBox() && !layout_object_->IsLayoutNGObject()) {
@@ -757,8 +907,14 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
return layout_object_->CreatePositionWithAffinity(0);
}
+ if (!RuntimeEnabledFeatures::LayoutNGFullPositionForPointEnabled()) {
+ DCHECK(layout_object_->ChildrenInline());
+ return layout_object_->CreatePositionWithAffinity(0);
+ }
+
NGLink closest_child = {nullptr};
LayoutUnit shortest_distance = LayoutUnit::Max();
+ bool found_hit_test_candidate = false;
const PhysicalSize pixel_size(LayoutUnit(1), LayoutUnit(1));
PhysicalRect point_rect(point, pixel_size);
@@ -773,8 +929,18 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
// direction (column rows and spanners).
for (const NGLink& child : Children()) {
const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
- if (!IsHitTestCandidate(box_fragment))
- continue;
+ bool is_hit_test_candidate = IsHitTestCandidate(box_fragment);
+ if (!is_hit_test_candidate) {
+ if (found_hit_test_candidate)
+ continue;
+ // We prefer valid hit-test candidates, but if there are no such children,
+ // we'll lower our requirements somewhat. The exact reasoning behind the
+ // details here is unknown, but it is something that evolved during
+ // WebKit's early years.
+ if (box_fragment.Style().Visibility() != EVisibility::kVisible ||
+ (box_fragment.Children().empty() && !box_fragment.IsBlockFlow()))
+ continue;
+ }
PhysicalRect child_rect(child.offset, child->Size());
LayoutUnit horizontal_distance;
@@ -797,10 +963,13 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
const LayoutUnit distance = horizontal_distance * horizontal_distance +
vertical_distance * vertical_distance;
- if (shortest_distance > distance) {
- // This child is closer to the point than any previous child.
+ if (shortest_distance > distance ||
+ (is_hit_test_candidate && !found_hit_test_candidate)) {
+ // This child is either closer to the point than any previous child, or
+ // this is the first child that is an actual hit-test candidate.
shortest_distance = distance;
closest_child = child;
+ found_hit_test_candidate = is_hit_test_candidate;
}
}
@@ -808,7 +977,7 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
return layout_object_->CreatePositionWithAffinity(0);
const auto& child = To<NGPhysicalBoxFragment>(*closest_child);
- Node* child_node = child_node = child.NonPseudoNode();
+ Node* child_node = child.NonPseudoNode();
PhysicalOffset point_in_child = point - closest_child.offset;
if (!child.IsCSSBox() || !child_node)
return child.PositionForPoint(point_in_child);
@@ -835,9 +1004,8 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
LogicalSize child_logical_size = converter.ToLogical(child.Size());
LayoutUnit child_middle = child_logical_size.inline_size / 2;
if (logical_point_in_child.inline_offset < child_middle)
- return layout_object_->CreatePositionWithAffinity(child_node->NodeIndex());
- return layout_object_->CreatePositionWithAffinity(child_node->NodeIndex() + 1,
- TextAffinity::kUpstream);
+ return child.GetLayoutObject()->PositionBeforeThis();
+ return child.GetLayoutObject()->PositionAfterThis();
}
UBiDiLevel NGPhysicalBoxFragment::BidiLevel() const {
@@ -926,11 +1094,26 @@ void NGPhysicalBoxFragment::CheckSameForSimplifiedLayout(
.UseBlockEndMarginEdgeForInlineBlockBaseline());
}
- // TODO(atotic,ikilpatrick): Enable DCHECKs for:
- // - TableGridRect()
- // - TableColumnGeometries()
- // - TableCollapsedBorders()
- // - TableCollapsedBordersGeometry()
+ if (IsTableNG()) {
+ DCHECK_EQ(TableGridRect(), other.TableGridRect());
+
+ if (TableColumnGeometries()) {
+ DCHECK(other.TableColumnGeometries());
+ DCHECK(*TableColumnGeometries() == *other.TableColumnGeometries());
+ } else {
+ DCHECK(!other.TableColumnGeometries());
+ }
+
+ DCHECK_EQ(TableCollapsedBorders(), other.TableCollapsedBorders());
+
+ if (TableCollapsedBordersGeometry()) {
+ DCHECK(other.TableCollapsedBordersGeometry());
+ TableCollapsedBordersGeometry()->CheckSameForSimplifiedLayout(
+ *other.TableCollapsedBordersGeometry());
+ } else {
+ DCHECK(!other.TableCollapsedBordersGeometry());
+ }
+ }
if (IsTableNGCell())
DCHECK_EQ(TableCellColumnIndex(), other.TableCellColumnIndex());
@@ -972,23 +1155,21 @@ void NGPhysicalBoxFragment::CheckIntegrity() const {
if (layout_object_ && layout_object_->ChildPaintBlockedByDisplayLock())
return;
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
- if (has_line_boxes)
- DCHECK(HasItems());
- } else {
- DCHECK_EQ(HasItems(), has_line_boxes);
- }
+ if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
+ if (has_line_boxes)
+ DCHECK(HasItems());
+ } else {
+ DCHECK_EQ(HasItems(), has_line_boxes);
+ }
- if (has_line_boxes) {
- DCHECK(!has_inlines);
- DCHECK(!has_inflow_blocks);
- // The following objects should be in the items, not in the tree. One
- // exception is that floats may occur as regular fragments in the tree
- // after a fragmentainer break.
- DCHECK(!has_floats || !IsFirstForNode());
- DCHECK(!has_list_markers);
- }
+ if (has_line_boxes) {
+ DCHECK(!has_inlines);
+ DCHECK(!has_inflow_blocks);
+ // The following objects should be in the items, not in the tree. One
+ // exception is that floats may occur as regular fragments in the tree
+ // after a fragmentainer break.
+ DCHECK(!has_floats || !IsFirstForNode());
+ DCHECK(!has_list_markers);
}
}
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index 66a71afd81c..87f90b9a69e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -34,7 +34,8 @@ class CORE_EXPORT NGPhysicalBoxFragment final
const base::Optional<PhysicalRect>
updated_layout_overflow = base::nullopt);
- using PassKey = util::PassKey<NGPhysicalBoxFragment>;
+ using MulticolCollection = NGContainerFragmentBuilder::MulticolCollection;
+ using PassKey = base::PassKey<NGPhysicalBoxFragment>;
NGPhysicalBoxFragment(PassKey,
NGBoxFragmentBuilder* builder,
bool has_layout_overflow,
@@ -98,11 +99,7 @@ class CORE_EXPORT NGPhysicalBoxFragment final
const NGTableFragmentData::CollapsedBordersGeometry*
TableCollapsedBordersGeometry() const {
- auto& table_collapsed_borders_geometry =
- ComputeRareDataAddress()->table_collapsed_borders_geometry;
- if (!table_collapsed_borders_geometry)
- return nullptr;
- return table_collapsed_borders_geometry.get();
+ return ComputeRareDataAddress()->table_collapsed_borders_geometry.get();
}
wtf_size_t TableCellColumnIndex() const {
@@ -158,6 +155,20 @@ class CORE_EXPORT NGPhysicalBoxFragment final
return {descendants.data(), descendants.size()};
}
+ bool HasMulticolsWithPendingOOFs() const {
+ if (!has_rare_data_)
+ return false;
+
+ return !ComputeRareDataAddress()->multicols_with_pending_oofs.IsEmpty();
+ }
+
+ MulticolCollection MulticolsWithPendingOOFs() const {
+ if (!has_rare_data_)
+ return MulticolCollection();
+ return const_cast<MulticolCollection&>(
+ ComputeRareDataAddress()->multicols_with_pending_oofs);
+ }
+
NGPixelSnappedPhysicalBoxStrut PixelSnappedPadding() const {
if (!has_padding_)
return NGPixelSnappedPhysicalBoxStrut();
@@ -195,9 +206,23 @@ class CORE_EXPORT NGPhysicalBoxFragment final
return is_inline_formatting_context_;
}
+ // The |LayoutBox| whose |PhysicalFragments()| contains |this|. This is
+ // different from |GetLayoutObject()| if |this.IsColumnBox()|.
+ const LayoutBox* OwnerLayoutBox() const;
+ LayoutBox* MutableOwnerLayoutBox() const;
+
+ // Returns the offset in the |OwnerLayoutBox| coordinate system.
+ PhysicalOffset OffsetFromOwnerLayoutBox() const;
+
PhysicalRect ScrollableOverflow(TextHeightType height_type) const;
PhysicalRect ScrollableOverflowFromChildren(TextHeightType height_type) const;
+ OverflowClipAxes GetOverflowClipAxes() const {
+ if (const auto* layout_object = GetLayoutObject())
+ return layout_object->GetOverflowClipAxes();
+ return kNoOverflowClip;
+ }
+
// TODO(layout-dev): These three methods delegate to legacy layout for now,
// update them to use LayoutNG based overflow information from the fragment
// and change them to use NG geometry types once LayoutNG supports overflow.
@@ -224,11 +249,32 @@ class CORE_EXPORT NGPhysicalBoxFragment final
const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset) const;
+ // In order to paint united outline rectangles, the "owner" fragment paints
+ // outlines for non-owner fragments.
+ bool IsOutlineOwner() const {
+ return !IsInlineBox() || InlineContainerFragmentIfOutlineOwner();
+ }
+ const NGPhysicalBoxFragment* InlineContainerFragmentIfOutlineOwner() const;
+
+ // Returns the |ComputedStyle| to use for painting outlines. When |this| is
+ // a block in a continuation-chain, it may need to paint outlines if its
+ // ancestor inline boxes in the DOM tree has outlines.
+ const ComputedStyle* StyleForContinuationOutline() const {
+ if (const auto* layout_object = GetLayoutObject())
+ return layout_object->StyleForContinuationOutline();
+ return nullptr;
+ }
+
// Fragment offset is this fragment's offset from parent.
// Needed to compensate for LayoutInline Legacy code offsets.
void AddSelfOutlineRects(const PhysicalOffset& additional_offset,
NGOutlineType include_block_overflows,
Vector<PhysicalRect>* outline_rects) const;
+ // Same as |AddSelfOutlineRects|, except when |this.IsInlineBox()|, in which
+ // case the coordinate system is relative to the inline formatting context.
+ void AddOutlineRects(const PhysicalOffset& additional_offset,
+ NGOutlineType include_block_overflows,
+ Vector<PhysicalRect>* outline_rects) const;
PositionWithAffinity PositionForPoint(PhysicalOffset) const;
@@ -267,12 +313,6 @@ class CORE_EXPORT NGPhysicalBoxFragment final
return *ComputeRareDataAddress()->mathml_paint_info;
}
- // Temporary while stabilizing PositionForPoint support in
- // NGPhysicalBoxFragment.
- static bool SupportsPositionForPoint() {
- return RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled();
- }
-
private:
static size_t ByteSize(wtf_size_t num_fragment_items,
wtf_size_t num_children,
@@ -288,6 +328,7 @@ class CORE_EXPORT NGPhysicalBoxFragment final
Vector<NGPhysicalOutOfFlowPositionedNode>
oof_positioned_fragmentainer_descendants;
+ MulticolCollection multicols_with_pending_oofs;
const std::unique_ptr<const NGMathMLPaintInfo> mathml_paint_info;
// TablesNG rare data.
@@ -347,6 +388,15 @@ class CORE_EXPORT NGPhysicalBoxFragment final
: reinterpret_cast<RareData*>(address);
}
+ void AddOutlineRects(const PhysicalOffset& additional_offset,
+ NGOutlineType include_block_overflows,
+ bool inline_container_relative,
+ Vector<PhysicalRect>* outline_rects) const;
+ void AddOutlineRectsForInlineBox(PhysicalOffset additional_offset,
+ NGOutlineType include_block_overflows,
+ bool inline_container_relative,
+ Vector<PhysicalRect>* outline_rects) const;
+
#if DCHECK_IS_ON()
void CheckIntegrity() const;
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index c41013e4049..57095760c03 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
@@ -140,36 +139,9 @@ void NGPhysicalContainerFragment::AddOutlineRectsForNormalChildren(
if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(this)) {
DCHECK_EQ(box->PostLayout(), box);
if (const NGFragmentItems* items = box->Items()) {
- for (NGInlineCursor cursor(*box, *items); cursor; cursor.MoveToNext()) {
- DCHECK(cursor.Current().Item());
- const NGFragmentItem& item = *cursor.Current().Item();
- if (UNLIKELY(item.IsLayoutObjectDestroyedOrMoved()))
- continue;
- if (item.Type() == NGFragmentItem::kLine) {
- AddOutlineRectsForDescendant(
- {item.LineBoxFragment(), item.OffsetInContainerBlock()},
- outline_rects, additional_offset, outline_type, containing_block);
- continue;
- }
- if (item.IsText()) {
- if (outline_type == NGOutlineType::kDontIncludeBlockVisualOverflow)
- continue;
- outline_rects->push_back(
- PhysicalRect(additional_offset + item.OffsetInContainerBlock(),
- item.Size().ToLayoutSize()));
- continue;
- }
- if (item.Type() == NGFragmentItem::kBox) {
- if (const NGPhysicalBoxFragment* child_box =
- item.PostLayoutBoxFragment()) {
- DCHECK(!child_box->IsOutOfFlowPositioned());
- AddOutlineRectsForDescendant(
- {child_box, item.OffsetInContainerBlock()}, outline_rects,
- additional_offset, outline_type, containing_block);
- }
- continue;
- }
- }
+ NGInlineCursor cursor(*box, *items);
+ AddOutlineRectsForCursor(outline_rects, additional_offset, outline_type,
+ containing_block, &cursor);
// Don't add |Children()|. If |this| has |NGFragmentItems|, children are
// either line box, which we already handled in items, or OOF, which we
// should ignore.
@@ -205,6 +177,44 @@ void NGPhysicalContainerFragment::AddOutlineRectsForNormalChildren(
}
}
+void NGPhysicalContainerFragment::AddOutlineRectsForCursor(
+ Vector<PhysicalRect>* outline_rects,
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ const LayoutBoxModelObject* containing_block,
+ NGInlineCursor* cursor) const {
+ for (; *cursor; cursor->MoveToNext()) {
+ DCHECK(cursor->Current().Item());
+ const NGFragmentItem& item = *cursor->Current().Item();
+ if (UNLIKELY(item.IsLayoutObjectDestroyedOrMoved()))
+ continue;
+ if (item.Type() == NGFragmentItem::kLine) {
+ AddOutlineRectsForDescendant(
+ {item.LineBoxFragment(), item.OffsetInContainerFragment()},
+ outline_rects, additional_offset, outline_type, containing_block);
+ continue;
+ }
+ if (item.IsText()) {
+ if (outline_type == NGOutlineType::kDontIncludeBlockVisualOverflow)
+ continue;
+ outline_rects->push_back(
+ PhysicalRect(additional_offset + item.OffsetInContainerFragment(),
+ item.Size().ToLayoutSize()));
+ continue;
+ }
+ if (item.Type() == NGFragmentItem::kBox) {
+ if (const NGPhysicalBoxFragment* child_box =
+ item.PostLayoutBoxFragment()) {
+ DCHECK(!child_box->IsOutOfFlowPositioned());
+ AddOutlineRectsForDescendant(
+ {child_box, item.OffsetInContainerFragment()}, outline_rects,
+ additional_offset, outline_type, containing_block);
+ }
+ continue;
+ }
+ }
+}
+
void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
const NGPhysicalBoxFragment& container,
const ComputedStyle& container_style,
@@ -213,7 +223,6 @@ void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
const NGInlineCursor& cursor,
TextHeightType height_type,
PhysicalRect* overflow) const {
- DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(IsLineBox() || IsInlineBox());
DCHECK(cursor.Current().Item() &&
(cursor.Current().Item()->BoxFragment() == this ||
@@ -229,14 +238,14 @@ void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
continue;
}
if (item->IsText()) {
- PhysicalRect child_scroll_overflow = item->RectInContainerBlock();
+ PhysicalRect child_scroll_overflow = item->RectInContainerFragment();
if (height_type == TextHeightType::kEmHeight) {
child_scroll_overflow = AdjustTextRectForEmHeight(
child_scroll_overflow, item->Style(), item->TextShapeResult(),
container_writing_mode);
}
if (UNLIKELY(has_hanging)) {
- AdjustScrollableOverflowForHanging(line.RectInContainerBlock(),
+ AdjustScrollableOverflowForHanging(line.RectInContainerFragment(),
container_writing_mode,
&child_scroll_overflow);
}
@@ -250,7 +259,7 @@ void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
PhysicalRect child_scroll_overflow;
if (height_type == TextHeightType::kNormalHeight ||
(child_box->BoxType() != kInlineBox && !IsRubyBox()))
- child_scroll_overflow = item->RectInContainerBlock();
+ child_scroll_overflow = item->RectInContainerFragment();
if (child_box->IsInlineBox()) {
child_box->AddScrollableOverflowForInlineChild(
container, container_style, line, has_hanging, descendants,
@@ -258,14 +267,14 @@ void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
child_box->AdjustScrollableOverflowForPropagation(
container, height_type, &child_scroll_overflow);
if (UNLIKELY(has_hanging)) {
- AdjustScrollableOverflowForHanging(line.RectInContainerBlock(),
+ AdjustScrollableOverflowForHanging(line.RectInContainerFragment(),
container_writing_mode,
&child_scroll_overflow);
}
} else {
child_scroll_overflow =
child_box->ScrollableOverflowForPropagation(container, height_type);
- child_scroll_overflow.offset += item->OffsetInContainerBlock();
+ child_scroll_overflow.offset += item->OffsetInContainerFragment();
}
overflow->Unite(child_scroll_overflow);
descendants.MoveToNextSkippingChildren();
@@ -308,7 +317,7 @@ void NGPhysicalContainerFragment::AddOutlineRectsForDescendant(
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block) const {
DCHECK(!descendant->IsLayoutObjectDestroyedOrMoved());
- if (descendant->IsText() || descendant->IsListMarker())
+ if (descendant->IsListMarker())
return;
if (const auto* descendant_box =
@@ -322,8 +331,8 @@ void NGPhysicalContainerFragment::AddOutlineRectsForDescendant(
if (descendant_box->HasLayer()) {
DCHECK(descendant_layout_object);
Vector<PhysicalRect> layer_outline_rects;
- descendant_box->AddSelfOutlineRects(PhysicalOffset(), outline_type,
- &layer_outline_rects);
+ descendant_box->AddOutlineRects(PhysicalOffset(), outline_type,
+ &layer_outline_rects);
// Don't pass additional_offset because LocalToAncestorRects will itself
// apply it.
@@ -349,7 +358,7 @@ void NGPhysicalContainerFragment::AddOutlineRectsForDescendant(
// for its line box which cover the line boxes of this LayoutInline. So
// the LayoutInline needs to add rects for children and continuations
// only.
- if (NGOutlineUtils::ShouldPaintOutline(*descendant_box)) {
+ if (descendant_box->IsOutlineOwner()) {
// We don't pass additional_offset here because the function requires
// additional_offset to be the offset from the containing block.
descendant_layout_inline->AddOutlineRectsForChildrenAndContinuations(
@@ -367,20 +376,6 @@ void NGPhysicalContainerFragment::AddOutlineRectsForDescendant(
if (!descendant_line_box->Size().IsEmpty()) {
outline_rects->emplace_back(additional_offset + descendant.Offset(),
descendant_line_box->Size().ToLayoutSize());
- } else if (descendant_line_box->Children().empty()) {
- // Special-case for when the first continuation does not generate
- // fragments. NGInlineLayoutAlgorithm suppresses box fragments when the
- // line is "empty". When there is a continuation from the LayoutInline,
- // the suppression makes such continuation not reachable. Check the
- // continuation from LayoutInline in such case.
- DCHECK(GetLayoutObject());
- if (auto* first_layout_inline =
- DynamicTo<LayoutInline>(GetLayoutObject()->SlowFirstChild())) {
- if (!first_layout_inline->IsElementContinuation()) {
- first_layout_inline->AddOutlineRectsForChildrenAndContinuations(
- *outline_rects, additional_offset, outline_type);
- }
- }
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index fcc71f19d62..921533ed3d7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -147,6 +147,29 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
oof_positioned_descendants_->size()};
}
+ // This exposes a mutable part of the fragment for |NGOutOfFlowLayoutPart|.
+ class MutableChildrenForOutOfFlow final {
+ STACK_ALLOCATED();
+
+ protected:
+ friend class NGOutOfFlowLayoutPart;
+ base::span<NGLink> Children() const {
+ return base::make_span(buffer_, num_children_);
+ }
+
+ private:
+ friend class NGPhysicalContainerFragment;
+ MutableChildrenForOutOfFlow(const NGLink* buffer, wtf_size_t num_children)
+ : buffer_(const_cast<NGLink*>(buffer)), num_children_(num_children) {}
+
+ NGLink* buffer_;
+ wtf_size_t num_children_;
+ };
+
+ MutableChildrenForOutOfFlow GetMutableChildrenForOutOfFlow() const {
+ return MutableChildrenForOutOfFlow(buffer_, num_children_);
+ }
+
protected:
// block_or_line_writing_mode is used for converting the child offsets.
NGPhysicalContainerFragment(NGContainerFragmentBuilder*,
@@ -178,6 +201,11 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block) const;
+ void AddOutlineRectsForCursor(Vector<PhysicalRect>* outline_rects,
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ const LayoutBoxModelObject* containing_block,
+ NGInlineCursor* cursor) const;
void AddOutlineRectsForDescendant(
const NGLink& descendant,
Vector<PhysicalRect>* rects,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 140c2e65179..d712565fcf8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
@@ -104,6 +103,7 @@ class FragmentTreeDumper {
bool has_content = false;
if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(fragment)) {
+ const LayoutObject* layout_object = box->GetLayoutObject();
if (flags_ & NGPhysicalFragment::DumpType) {
builder_->Append("Box");
String box_type = StringForBoxType(*fragment);
@@ -122,11 +122,10 @@ class FragmentTreeDumper {
}
has_content = AppendOffsetAndSize(fragment, fragment_offset, has_content);
- if (flags_ & NGPhysicalFragment::DumpNodeName &&
- fragment->GetLayoutObject()) {
+ if (flags_ & NGPhysicalFragment::DumpNodeName && layout_object) {
if (has_content)
builder_->Append(" ");
- builder_->Append(fragment->GetLayoutObject()->DebugName());
+ builder_->Append(layout_object->DebugName());
}
builder_->Append("\n");
@@ -139,6 +138,12 @@ class FragmentTreeDumper {
}
}
if (flags_ & NGPhysicalFragment::DumpSubtree) {
+ if (flags_ & NGPhysicalFragment::DumpLegacyDescendants &&
+ layout_object && !layout_object->IsLayoutNGObject()) {
+ DCHECK(box->Children().empty());
+ AppendLegacySubtree(*layout_object, indent);
+ return;
+ }
for (auto& child : box->Children()) {
if (has_fragment_items && child->IsLineBox())
continue;
@@ -164,24 +169,6 @@ class FragmentTreeDumper {
}
}
- if (const auto* text = DynamicTo<NGPhysicalTextFragment>(fragment)) {
- if (flags_ & NGPhysicalFragment::DumpType) {
- builder_->Append("Text");
- has_content = true;
- }
- has_content = AppendOffsetAndSize(fragment, fragment_offset, has_content);
-
- if (flags_ & NGPhysicalFragment::DumpTextOffsets) {
- if (has_content)
- builder_->Append(' ');
- builder_->AppendFormat("start: %u end: %u", text->StartOffset(),
- text->EndOffset());
- has_content = true;
- }
- builder_->Append("\n");
- return;
- }
-
if (flags_ & NGPhysicalFragment::DumpType) {
builder_->Append("Unknown fragment type");
has_content = true;
@@ -190,13 +177,49 @@ class FragmentTreeDumper {
builder_->Append("\n");
}
+ void AppendLegacySubtree(const LayoutObject& layout_object,
+ unsigned indent = 0) {
+ for (const LayoutObject* descendant = &layout_object; descendant;) {
+ if (!descendant->IsLayoutNGObject()) {
+ if (const auto* block = DynamicTo<LayoutBlock>(descendant)) {
+ if (const auto* positioned_descendants = block->PositionedObjects()) {
+ for (const auto* positioned_object : *positioned_descendants) {
+ if (positioned_object->IsLayoutNGObject())
+ AppendNGRootInLegacySubtree(*positioned_object, indent);
+ else
+ AppendLegacySubtree(*positioned_object, indent);
+ }
+ }
+ }
+ if (descendant->IsOutOfFlowPositioned() && descendant != &layout_object)
+ descendant = descendant->NextInPreOrderAfterChildren(&layout_object);
+ else
+ descendant = descendant->NextInPreOrder(&layout_object);
+ continue;
+ }
+ AppendNGRootInLegacySubtree(*descendant, indent);
+ descendant = descendant->NextInPreOrderAfterChildren(&layout_object);
+ }
+ }
+
+ void AppendNGRootInLegacySubtree(const LayoutObject& layout_object,
+ unsigned indent) {
+ if (flags_ & NGPhysicalFragment::DumpHeaderText) {
+ AppendIndentation(indent + 2);
+ builder_->Append("(NG fragment root inside legacy subtree:)\n");
+ }
+ const LayoutBox& box_descendant = To<LayoutBox>(layout_object);
+ DCHECK_EQ(box_descendant.PhysicalFragmentCount(), 1u);
+ Append(box_descendant.GetPhysicalFragment(0), base::nullopt, indent + 4);
+ }
+
private:
void Append(NGInlineCursor* cursor, unsigned indent) {
for (; *cursor; cursor->MoveToNextSkippingChildren()) {
const NGInlineCursorPosition& current = cursor->Current();
if (const NGPhysicalBoxFragment* box = current.BoxFragment()) {
if (!box->IsInlineBox()) {
- Append(box, current.OffsetInContainerBlock(), indent);
+ Append(box, current.OffsetInContainerFragment(), indent);
continue;
}
}
@@ -209,7 +232,7 @@ class FragmentTreeDumper {
if (flags_ & NGPhysicalFragment::DumpOffset) {
builder_->Append(" offset:");
- builder_->Append(current.OffsetInContainerBlock().ToString());
+ builder_->Append(current.OffsetInContainerFragment().ToString());
}
if (flags_ & NGPhysicalFragment::DumpSize) {
builder_->Append(" size:");
@@ -350,8 +373,7 @@ NGPhysicalFragment::NGPhysicalFragment(const NGPhysicalFragment& other)
is_painted_atomically_(other.is_painted_atomically_),
has_collapsed_borders_(other.has_collapsed_borders_),
has_baseline_(other.has_baseline_),
- has_last_baseline_(other.has_last_baseline_),
- ink_overflow_computed_(other.ink_overflow_computed_) {
+ has_last_baseline_(other.has_last_baseline_) {
CHECK(layout_object_);
}
@@ -364,15 +386,9 @@ void NGPhysicalFragment::Destroy() const {
case kFragmentBox:
delete static_cast<const NGPhysicalBoxFragment*>(this);
break;
- case kFragmentText:
- delete static_cast<const NGPhysicalTextFragment*>(this);
- break;
case kFragmentLineBox:
delete static_cast<const NGPhysicalLineBoxFragment*>(this);
break;
- default:
- NOTREACHED();
- break;
}
}
@@ -380,6 +396,10 @@ bool NGPhysicalFragment::IsBlockFlow() const {
return !IsLineBox() && layout_object_->IsLayoutBlockFlow();
}
+bool NGPhysicalFragment::IsTextControlContainer() const {
+ return blink::IsTextControlContainer(layout_object_->GetNode());
+}
+
bool NGPhysicalFragment::IsTextControlPlaceholder() const {
return blink::IsTextControlPlaceholder(layout_object_->GetNode());
}
@@ -449,21 +469,6 @@ void NGPhysicalFragment::CheckType() const {
DCHECK_EQ(IsAtomicInline(), layout_object_->IsInline() &&
layout_object_->IsAtomicInlineLevel());
break;
- case kFragmentText:
- if (To<NGPhysicalTextFragment>(this)->IsGeneratedText()) {
- // Ellipsis has the truncated in-flow LayoutObject.
- DCHECK(layout_object_->IsText() ||
- (layout_object_->IsInline() &&
- layout_object_->IsAtomicInlineLevel()) ||
- layout_object_->IsLayoutInline());
- } else {
- DCHECK(layout_object_->IsText());
- }
- DCHECK(!IsFloating());
- DCHECK(!IsOutOfFlowPositioned());
- DCHECK(!IsInlineBox());
- DCHECK(!IsAtomicInline());
- break;
case kFragmentLineBox:
DCHECK(layout_object_->IsLayoutBlockFlow());
DCHECK(!IsFloating());
@@ -490,13 +495,6 @@ PhysicalRect NGPhysicalFragment::ScrollableOverflow(
switch (Type()) {
case kFragmentBox:
return To<NGPhysicalBoxFragment>(*this).ScrollableOverflow(height_type);
- case kFragmentText:
- if (height_type == TextHeightType::kNormalHeight)
- return {{}, Size()};
- return AdjustTextRectForEmHeight(
- LocalRect(), Style(),
- To<NGPhysicalTextFragment>(this)->TextShapeResult(),
- container.Style().GetWritingMode());
case kFragmentLineBox:
NOTREACHED()
<< "You must call NGLineBoxFragment::ScrollableOverflow explicitly.";
@@ -571,8 +569,6 @@ bool NGPhysicalFragment::InsideBlockingWheelEventHandler() const {
UBiDiLevel NGPhysicalFragment::BidiLevel() const {
switch (Type()) {
- case kFragmentText:
- return To<NGPhysicalTextFragment>(*this).BidiLevel();
case kFragmentBox:
return To<NGPhysicalBoxFragment>(*this).BidiLevel();
case kFragmentLineBox:
@@ -584,8 +580,6 @@ UBiDiLevel NGPhysicalFragment::BidiLevel() const {
TextDirection NGPhysicalFragment::ResolvedDirection() const {
switch (Type()) {
- case kFragmentText:
- return To<NGPhysicalTextFragment>(*this).ResolvedDirection();
case kFragmentBox:
DCHECK(IsInline() && IsAtomicInline());
// TODO(xiaochengh): Store direction in |base_direction_| flag.
@@ -634,14 +628,6 @@ String NGPhysicalFragment::ToString() const {
output.AppendFormat(", BoxType: '%s'",
StringForBoxType(*this).Ascii().c_str());
break;
- case kFragmentText: {
- const auto& text = To<NGPhysicalTextFragment>(*this);
- output.AppendFormat(", TextType: %u, Text: (%u,%u) \"", text.TextType(),
- text.StartOffset(), text.EndOffset());
- output.Append(text.Text());
- output.Append("\"");
- break;
- }
case kFragmentLineBox:
break;
}
@@ -660,11 +646,34 @@ String NGPhysicalFragment::DumpFragmentTree(
return string_builder.ToString();
}
+String NGPhysicalFragment::DumpFragmentTree(const LayoutObject& root,
+ DumpFlags flags) {
+ if (root.IsLayoutNGObject()) {
+ const LayoutBox& root_box = To<LayoutBox>(root);
+ DCHECK_EQ(root_box.PhysicalFragmentCount(), 1u);
+ return root_box.GetPhysicalFragment(0)->DumpFragmentTree(flags);
+ }
+ StringBuilder string_builder;
+ if (flags & DumpHeaderText) {
+ string_builder.Append(
+ ".:: LayoutNG Physical Fragment Tree at legacy root ");
+ string_builder.Append(root.DebugName());
+ string_builder.Append(" ::.\n");
+ }
+ FragmentTreeDumper(&string_builder, flags).AppendLegacySubtree(root);
+ return string_builder.ToString();
+}
+
#if DCHECK_IS_ON()
void NGPhysicalFragment::ShowFragmentTree() const {
DumpFlags dump_flags = DumpAll;
LOG(INFO) << "\n" << DumpFragmentTree(dump_flags).Utf8();
}
+
+void NGPhysicalFragment::ShowFragmentTree(const LayoutObject& root) {
+ DumpFlags dump_flags = DumpAll;
+ LOG(INFO) << "\n" << DumpFragmentTree(root, dump_flags).Utf8();
+}
#endif
PhysicalRect NGPhysicalFragmentWithOffset::RectInContainerBox() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 9791325b41b..1fadada77a3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -49,8 +49,7 @@ class CORE_EXPORT NGPhysicalFragment
public:
enum NGFragmentType {
kFragmentBox = 0,
- kFragmentText = 1,
- kFragmentLineBox = 2,
+ kFragmentLineBox = 1,
// When adding new values, make sure the bit size of |type_| is large
// enough to store.
};
@@ -82,7 +81,6 @@ class CORE_EXPORT NGPhysicalFragment
Type() == NGFragmentType::kFragmentLineBox;
}
bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; }
- bool IsText() const { return Type() == NGFragmentType::kFragmentText; }
bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; }
// Returns the box type of this fragment.
@@ -110,9 +108,7 @@ class CORE_EXPORT NGPhysicalFragment
return IsBox() && BoxType() == NGBoxType::kAtomicInline;
}
// True if this fragment is in-flow in an inline formatting context.
- bool IsInline() const {
- return IsText() || IsInlineBox() || IsAtomicInline();
- }
+ bool IsInline() const { return IsInlineBox() || IsAtomicInline(); }
bool IsFloating() const {
return IsBox() && BoxType() == NGBoxType::kFloating;
}
@@ -162,7 +158,9 @@ class CORE_EXPORT NGPhysicalFragment
bool IsTableNGPart() const { return is_table_ng_part_; }
- bool IsTable() const { return IsBox() && layout_object_->IsTable(); }
+ bool IsTableNG() const {
+ return IsTableNGPart() && layout_object_->IsTable();
+ }
bool IsTableNGRow() const {
return IsTableNGPart() && layout_object_->IsTableRow();
@@ -177,6 +175,7 @@ class CORE_EXPORT NGPhysicalFragment
!layout_object_->IsTableCellLegacy();
}
+ bool IsTextControlContainer() const;
bool IsTextControlPlaceholder() const;
// Return true if this fragment is a container established by a fieldset
@@ -448,6 +447,7 @@ class CORE_EXPORT NGPhysicalFragment
DumpSelfPainting = 0x80,
DumpNodeName = 0x100,
DumpItems = 0x200,
+ DumpLegacyDescendants = 0x400,
DumpAll = -1
};
typedef int DumpFlags;
@@ -456,8 +456,11 @@ class CORE_EXPORT NGPhysicalFragment
base::Optional<PhysicalOffset> = base::nullopt,
unsigned indent = 2) const;
+ static String DumpFragmentTree(const LayoutObject& root, DumpFlags);
+
#if DCHECK_IS_ON()
void ShowFragmentTree() const;
+ static void ShowFragmentTree(const LayoutObject& root);
#endif
protected:
@@ -506,7 +509,7 @@ class CORE_EXPORT NGPhysicalFragment
LayoutObject* layout_object_;
const PhysicalSize size_;
- const unsigned type_ : 2; // NGFragmentType
+ const unsigned type_ : 1; // NGFragmentType
const unsigned sub_type_ : 3; // NGBoxType, NGTextType, or NGLineBoxType
const unsigned style_variant_ : 2; // NGStyleVariant
const unsigned is_hidden_for_paint_ : 1;
@@ -526,10 +529,6 @@ class CORE_EXPORT NGPhysicalFragment
unsigned has_baseline_ : 1;
unsigned has_last_baseline_ : 1;
- // The following bitfields are only to be used by NGPhysicalTextFragment
- // (it's defined here to save memory, since that class has no bitfields).
- mutable unsigned ink_overflow_computed_ : 1;
-
// Note: We've used 32-bit bit field. If you need more bits, please think to
// share bit fields, or put them before layout_object_ to fill the gap after
// RefCounted on 64-bit systems.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment_test.cc
new file mode 100644
index 00000000000..544d2ffa3b2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment_test.cc
@@ -0,0 +1,185 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
+
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+class NGPhysicalFragmentTest : public NGLayoutTest {
+ public:
+ String DumpAll() const {
+ return NGPhysicalFragment::DumpFragmentTree(*GetDocument().GetLayoutView(),
+ NGPhysicalFragment::DumpAll);
+ }
+};
+
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeBasic) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="block"></div>
+ )HTML");
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x8 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+ Box (block-flow) offset:0,0 size:784x0 LayoutNGBlockFlow DIV id='block'
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// LayoutView is the containing block of an absolutely positioned descendant.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithAbspos) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="abs" style="position:absolute;"></div>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (out-of-flow-positioned block-flow)(self paint) offset:unplaced size:0x0 LayoutNGBlockFlow (positioned) DIV id='abs'
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x8 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// An NG object is the containing block of an absolutely positioned descendant.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithAbsposInRelpos) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="rel" style="position:relative;">
+ <div id="abs" style="position:absolute; left:10px; top:20px;"></div>
+ </div>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x8 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+ Box (block-flow)(self paint) offset:0,0 size:784x0 LayoutNGBlockFlow (relative positioned) DIV id='rel'
+ Box (out-of-flow-positioned block-flow)(self paint) offset:10,20 size:0x0 LayoutNGBlockFlow (positioned) DIV id='abs'
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// A legacy table is the containing block of an absolutely positioned
+// descendant.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithTableWithAbspos) {
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <table style="position:relative;">
+ <td>
+ <div id="abs" style="position:absolute; left:10px; top:20px;"></div>
+ <div id="inflow">
+ <div id="inflowchild"></div>
+ </div>
+ </td>
+ </table>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x22 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x6 LayoutNGBlockFlow BODY
+ Box (block-flow-root legacy-layout-root)(self paint) offset:0,0 size:6x6 LayoutTable (relative positioned) TABLE
+ (NG fragment root inside legacy subtree:)
+ Box (out-of-flow-positioned block-flow)(self paint) offset:unplaced size:0x0 LayoutNGBlockFlow (positioned) DIV id='abs'
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow) offset:unplaced size:2x2 LayoutNGTableCell TD
+ Box (block-flow) offset:1,1 size:0x0 LayoutNGBlockFlow DIV id='inflow'
+ Box (block-flow) offset:0,0 size:0x0 LayoutNGBlockFlow DIV id='inflowchild'
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// LayoutView is the containing block of an absolutely positioned legacy
+// table. The table has no fragment, so it won't show up in the fragment dump.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithAbsposTable) {
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <div id="abs" style="display:table; position:absolute;"></div>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x8 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// LayoutView is the containing block of an absolutely positioned legacy table
+// with a child. The table has no fragment, so it won't show up in the fragment
+// dump, but its NG descendants will.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithAbsposTableWithChild) {
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <div id="abs" style="display:table; position:absolute;">
+ <div id="child"></div>
+ </div>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow) offset:unplaced size:0x0 LayoutNGTableCell (anonymous)
+ Box (block-flow) offset:0,0 size:0x0 LayoutNGBlockFlow DIV id='child'
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x8 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// A legacy grid with another legacy grid inside, and some NG objects, too.
+TEST_F(NGPhysicalFragmentTest, DumpFragmentTreeWithGrid) {
+ if (RuntimeEnabledFeatures::LayoutNGGridEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <div id="outer-grid" style="display:grid;">
+ <div id="grid-as-item" style="display:grid;">
+ <div id="inner-grid-item">
+ <div id="foo"></div>
+ </div>
+ </div>
+ <div id="block-container-item">
+ <div id="bar"></div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpAll();
+ String expectation =
+ R"DUMP(.:: LayoutNG Physical Fragment Tree at legacy root LayoutView #document ::.
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow)(self paint) offset:unplaced size:800x16 LayoutNGBlockFlow HTML
+ Box (block-flow) offset:8,8 size:784x0 LayoutNGBlockFlow BODY
+ Box (block-flow-root legacy-layout-root) offset:0,0 size:784x0 LayoutGrid DIV id='outer-grid'
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow) offset:unplaced size:784x0 LayoutNGBlockFlow DIV id='inner-grid-item'
+ Box (block-flow) offset:0,0 size:784x0 LayoutNGBlockFlow DIV id='foo'
+ (NG fragment root inside legacy subtree:)
+ Box (block-flow-root block-flow) offset:unplaced size:784x0 LayoutNGBlockFlow DIV id='block-container-item'
+ Box (block-flow) offset:0,0 size:784x0 LayoutNGBlockFlow DIV id='bar'
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
index 1257d23f984..f930dec9012 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.h
@@ -7,13 +7,14 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
namespace blink {
-class ComputedStyle;
class NGConstraintSpace;
-class NGPhysicalBoxFragment;
// Implements relative positioning:
// https://www.w3.org/TR/css-position-3/#rel-pos
@@ -32,6 +33,22 @@ CORE_EXPORT LogicalOffset
ComputeRelativeOffsetForInline(const NGConstraintSpace& space,
const ComputedStyle& child_style);
+// Un-apply any offset caused by relative positioning. When re-using a previous
+// fragment's offset (from the cache), we need to convert from "paint offset" to
+// "layout offset" before re-adding the fragment, in order to get overflow
+// calculation right.
+inline void RemoveRelativeOffset(const NGBoxFragmentBuilder& builder,
+ const NGPhysicalFragment& fragment,
+ LogicalOffset* offset) {
+ if (fragment.Style().GetPosition() != EPosition::kRelative)
+ return;
+ if (const auto* box_fragment = DynamicTo<NGPhysicalBoxFragment>(&fragment)) {
+ *offset -= ComputeRelativeOffsetForBoxFragment(
+ *box_fragment, builder.GetWritingDirection(),
+ builder.ChildAvailableSize());
+ }
+}
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_RELATIVE_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.cc
new file mode 100644
index 00000000000..3677440d619
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.cc
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_replaced.h"
+
+namespace blink {
+
+NGReplacedLayoutAlgorithm::NGReplacedLayoutAlgorithm(
+ const NGLayoutAlgorithmParams& params)
+ : NGLayoutAlgorithm(params),
+ // TODO(dgrogan): Use something from NGLayoutInputNode instead of
+ // accessing LayoutBox directly.
+ natural_size_(PhysicalSize(Node().GetLayoutBox()->IntrinsicSize())
+ .ConvertToLogical(Style().GetWritingMode())) {}
+
+scoped_refptr<const NGLayoutResult> NGReplacedLayoutAlgorithm::Layout() {
+ DCHECK(!BreakToken());
+ // Set this as a legacy root so that legacy painters are used.
+ container_builder_.SetIsLegacyLayoutRoot();
+
+ // TODO(dgrogan): |natural_size_.block_size| is frequently not the correct
+ // intrinsic block size. Move |ComputeIntrinsicBlockSizeForAspectRatioElement|
+ // from NGFlexLayoutAlgorithm to ng_length_utils and call it here.
+ LayoutUnit intrinsic_block_size = natural_size_.block_size;
+ container_builder_.SetIntrinsicBlockSize(intrinsic_block_size +
+ BorderPadding().BlockSum());
+
+ return container_builder_.ToBoxFragment();
+}
+
+// TODO(dgrogan): |natural_size_.inline_size| is frequently not the correct
+// intrinsic inline size. Move NGFlexLayoutAlgorithm's
+// |ComputeIntrinsicInlineSizeForAspectRatioElement| to here.
+MinMaxSizesResult NGReplacedLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& child_input) const {
+ MinMaxSizes sizes({natural_size_.inline_size, natural_size_.inline_size});
+ sizes += BorderScrollbarPadding().InlineSum();
+ return {sizes, false};
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.h
new file mode 100644
index 00000000000..dd296ec825f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_replaced_layout_algorithm.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_CORE_LAYOUT_NG_NG_REPLACED_LAYOUT_ALGORITHM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_REPLACED_LAYOUT_ALGORITHM_H_
+
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+
+namespace blink {
+
+class NGBlockNode;
+class NGBlockBreakToken;
+
+class CORE_EXPORT NGReplacedLayoutAlgorithm
+ : public NGLayoutAlgorithm<NGBlockNode,
+ NGBoxFragmentBuilder,
+ NGBlockBreakToken> {
+ public:
+ explicit NGReplacedLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+
+ MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
+ scoped_refptr<const NGLayoutResult> Layout() override;
+
+ private:
+ const LogicalSize natural_size_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_REPLACED_LAYOUT_ALGORITHM_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index cb99a6758eb..d33adfb5c12 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -27,10 +27,7 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
: NGLayoutAlgorithm(params),
previous_result_(result),
writing_direction_(Style().GetWritingDirection()) {
- // Currently this only supports block-flow layout due to the static-position
- // calculations. If support for other layout types is added this logic will
- // need to be changed.
- bool is_block_flow = Node().IsBlockFlow();
+ const bool is_block_flow = Node().IsBlockFlow();
const NGPhysicalBoxFragment& physical_fragment =
To<NGPhysicalBoxFragment>(result.PhysicalFragment());
@@ -71,8 +68,8 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
container_builder_.SetLastBaseline(*physical_fragment.LastBaseline());
if (ConstraintSpace().IsTableCell()) {
- if (physical_fragment.HasCollapsedBorders())
- container_builder_.SetHasCollapsedBorders(true);
+ container_builder_.SetHasCollapsedBorders(
+ physical_fragment.HasCollapsedBorders());
if (!ConstraintSpace().IsLegacyTableCell()) {
container_builder_.SetTableCellColumnIndex(
@@ -114,11 +111,28 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
container_builder_.SetCustomLayoutData(result.CustomLayoutData());
}
- // TODO(atotic,ikilpatrick): Copy across table related data for table,
- // table-row, table-section.
- DCHECK(!physical_fragment.IsTable());
- DCHECK(!physical_fragment.IsTableNGRow());
- DCHECK(!physical_fragment.IsTableNGSection());
+ if (physical_fragment.IsTableNG()) {
+ container_builder_.SetTableColumnCount(result.TableColumnCount());
+ container_builder_.SetTableGridRect(physical_fragment.TableGridRect());
+
+ container_builder_.SetHasCollapsedBorders(
+ physical_fragment.HasCollapsedBorders());
+
+ if (const auto* table_column_geometries =
+ physical_fragment.TableColumnGeometries())
+ container_builder_.SetTableColumnGeometries(*table_column_geometries);
+
+ if (const auto* table_collapsed_borders =
+ physical_fragment.TableCollapsedBorders())
+ container_builder_.SetTableCollapsedBorders(*table_collapsed_borders);
+
+ if (const auto* table_collapsed_borders_geometry =
+ physical_fragment.TableCollapsedBordersGeometry()) {
+ container_builder_.SetTableCollapsedBordersGeometry(
+ std::make_unique<NGTableFragmentData::CollapsedBordersGeometry>(
+ *table_collapsed_borders_geometry));
+ }
+ }
if (physical_fragment.IsHiddenForPaint())
container_builder_.SetIsHiddenForPaint(true);
@@ -133,7 +147,8 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
LayoutUnit new_block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), result.IntrinsicBlockSize(),
- container_builder_.InitialBorderBoxSize().inline_size);
+ container_builder_.InitialBorderBoxSize().inline_size,
+ Node().ShouldBeConsideredAsReplaced());
// Only block-flow is allowed to change its block-size during "simplified"
// layout, all other layout types must remain the same size.
@@ -142,7 +157,11 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
} else {
LayoutUnit old_block_size =
NGFragment(writing_direction_, physical_fragment).BlockSize();
- DCHECK_EQ(old_block_size, new_block_size);
+#if DCHECK_IS_ON()
+ // Tables don't respect the typical block-sizing rules.
+ if (!physical_fragment.IsTableNG())
+ DCHECK_EQ(old_block_size, new_block_size);
+#endif
container_builder_.SetFragmentBlockSize(old_block_size);
}
@@ -213,13 +232,11 @@ scoped_refptr<const NGLayoutResult> NGSimplifiedLayoutAlgorithm::Layout() {
// We add both items and line-box fragments for existing mechanisms to work.
// We may revisit this in future. See also |NGBoxFragmentBuilder::AddResult|.
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (const NGFragmentItems* previous_items = previous_fragment.Items()) {
- auto* items_builder = container_builder_.ItemsBuilder();
- DCHECK(items_builder);
- DCHECK_EQ(items_builder->GetWritingDirection(), writing_direction_);
- items_builder->AddPreviousItems(previous_fragment, *previous_items);
- }
+ if (const NGFragmentItems* previous_items = previous_fragment.Items()) {
+ auto* items_builder = container_builder_.ItemsBuilder();
+ DCHECK(items_builder);
+ DCHECK_EQ(items_builder->GetWritingDirection(), writing_direction_);
+ items_builder->AddPreviousItems(previous_fragment, *previous_items);
}
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
@@ -259,14 +276,7 @@ void NGSimplifiedLayoutAlgorithm::AddChildFragment(
previous_physical_container_size_)
.ToLogical(old_fragment.Offset(), new_fragment.Size());
- // Un-apply the relative position offset.
- if (const auto* box_child = DynamicTo<NGPhysicalBoxFragment>(*old_fragment)) {
- if (box_child->Style().GetPosition() == EPosition::kRelative) {
- child_offset -= ComputeRelativeOffsetForBoxFragment(
- *box_child, ConstraintSpace().GetWritingDirection(),
- container_builder_.ChildAvailableSize());
- }
- }
+ RemoveRelativeOffset(container_builder_, *old_fragment, &child_offset);
// Add the new fragment to the builder.
container_builder_.AddChild(new_fragment, child_offset,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h
index e7fd9fdea21..b4996867696 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h
@@ -45,7 +45,7 @@ class CORE_EXPORT NGSimplifiedLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override {
NOTREACHED();
- return {MinMaxSizes(), /* depends_on_percentage_block_size */ true};
+ return MinMaxSizesResult();
}
NOINLINE scoped_refptr<const NGLayoutResult> LayoutWithItemsBuilder();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.cc
index d72a4df41fc..4c0508edde6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
namespace blink {
@@ -26,45 +27,105 @@ NGSimplifiedOOFLayoutAlgorithm::NGSimplifiedOOFLayoutAlgorithm(
params.space.FragmentainerBlockSize());
// Don't apply children to new fragments.
- if (is_new_fragment)
+ if (is_new_fragment) {
+ children_ = {};
+ iterator_ = children_.end();
+ container_builder_.SetIsFirstForNode(false);
return;
+ }
+
+ container_builder_.SetIsFirstForNode(fragment.IsFirstForNode());
// We need the previous physical container size to calculate the position of
// any child fragments.
previous_physical_container_size_ = fragment.Size();
- // The OOF fragments need to be added after the already existing child
- // fragments. Add them now so they are added before we append the OOF results.
- for (const auto& child_link : fragment.Children()) {
- AddChildFragment(child_link,
- *To<NGPhysicalContainerFragment>(child_link.get()));
+ // The OOF fragments need to be added in a particular order that matches the
+ // order of break tokens. Here's a list of rules to follow , in order:
+ // 1. If there are any already appended fragments that are a continuation of
+ // layout (i.e. they are the Nth fragment of a layout box, where N > 1),
+ // they should be appended before anything else.
+ // 2. If we're trying to append a fragment that is a continuation of layout
+ // for an OOF node (from AppendOutOfFlowResult), add it after the fragments
+ // added in step 1.
+ // 3. Add the remaining children that were not appended during step 1.
+ // 4. Add the OOF fragments that were not a continuation of layout, the ones
+ // that weren't appended in step 2.
+ children_ = fragment.Children();
+ iterator_ = children_.begin();
+
+ while (iterator_ != children_.end()) {
+ const auto& child_link = *iterator_;
+ const auto* child_fragment = To<NGPhysicalBoxFragment>(child_link.get());
+ if (!child_fragment->IsFirstForNode()) {
+ AddChildFragment(child_link);
+ iterator_++;
+ } else {
+ // We can break here because fragments that are a continuation of layout
+ // are always the first children of a physical fragment.
+ break;
+ }
}
}
scoped_refptr<const NGLayoutResult> NGSimplifiedOOFLayoutAlgorithm::Layout() {
+ // There might not be any children to append, whether it's because we are in a
+ // new fragmentainer or because they have all been added in Step 1.
+ if (iterator_ != children_.end()) {
+ // Step 3: Add the remaining children that were not added in step 1.
+ while (iterator_ != children_.end()) {
+ const auto& child_link = *iterator_;
+ const auto* child_fragment = To<NGPhysicalBoxFragment>(child_link.get());
+ DCHECK(child_fragment->IsFirstForNode());
+ AddChildFragment(child_link);
+ iterator_++;
+ }
+
+ // Step 4: Add the OOF fragments that aren't a continuation of layout.
+ for (auto result : remaining_oof_results_) {
+ container_builder_.AddResult(*result,
+ result->OutOfFlowPositionedOffset());
+ }
+ }
return container_builder_.ToBoxFragment();
}
void NGSimplifiedOOFLayoutAlgorithm::AppendOutOfFlowResult(
- scoped_refptr<const NGLayoutResult> result,
- LogicalOffset offset) {
- // Add the new result to the builder.
- container_builder_.AddResult(*result, offset);
+ scoped_refptr<const NGLayoutResult> result) {
+ // Add the new result directly to the builder when the fragment of the result
+ // to append is not the first fragment of its corresponding layout box,
+ // meaning that it's positioned directly at the start of the fragmentainer.
+ // This ensures that we keep the fragments and the break tokens in order.
+ //
+ // Also add the result directly to the builder if there are no more children
+ // to append. This can happen when all children have been added in Step 1 or
+ // when we are in a new fragmentainer since a new fragmentainer doesn't have
+ // any child.
+ if (iterator_ == children_.end() ||
+ !To<NGPhysicalBoxFragment>(result->PhysicalFragment()).IsFirstForNode()) {
+ // Step 2: Add the fragments that are a continuation of layout directly to
+ // the builder.
+ container_builder_.AddResult(*result, result->OutOfFlowPositionedOffset());
+ return;
+ }
+ // Since there is no previous break token associated with the first fragment
+ // of a fragmented OOF element, we cannot append this result before any other
+ // children of this fragmentainer. Keep the order by adding it after.
+ remaining_oof_results_.push_back(result);
}
-void NGSimplifiedOOFLayoutAlgorithm::AddChildFragment(
- const NGLink& old_fragment,
- const NGPhysicalContainerFragment& new_fragment) {
- DCHECK_EQ(old_fragment->Size(), new_fragment.Size());
-
+void NGSimplifiedOOFLayoutAlgorithm::AddChildFragment(const NGLink& child) {
+ const auto* fragment = To<NGPhysicalContainerFragment>(child.get());
// Determine the previous position in the logical coordinate system.
LogicalOffset child_offset =
WritingModeConverter(writing_direction_,
previous_physical_container_size_)
- .ToLogical(old_fragment.Offset(), new_fragment.Size());
+ .ToLogical(child.Offset(), fragment->Size());
+
+ RemoveRelativeOffset(container_builder_, *fragment, &child_offset);
- // Add the new fragment to the builder.
- container_builder_.AddChild(new_fragment, child_offset);
+ // Add the fragment to the builder.
+ container_builder_.AddChild(*fragment, child_offset);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.h
index 7c2672d3d91..fefde89955f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_oof_layout_algorithm.h
@@ -13,7 +13,6 @@
namespace blink {
struct NGLink;
-class NGPhysicalContainerFragment;
// This is more a copy-and-append algorithm than a layout algorithm.
// This algorithm will only run when we are trying to add OOF-positioned
@@ -32,18 +31,20 @@ class CORE_EXPORT NGSimplifiedOOFLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override {
NOTREACHED();
- return {MinMaxSizes(), /* depends_on_percentage_block_size */ true};
+ return MinMaxSizesResult();
}
- void AppendOutOfFlowResult(scoped_refptr<const NGLayoutResult> child,
- LogicalOffset offset);
+ void AppendOutOfFlowResult(scoped_refptr<const NGLayoutResult> child);
private:
- void AddChildFragment(const NGLink& old_fragment,
- const NGPhysicalContainerFragment& new_fragment);
+ void AddChildFragment(const NGLink& old_fragment);
const WritingDirectionMode writing_direction_;
PhysicalSize previous_physical_container_size_;
+
+ Vector<scoped_refptr<const NGLayoutResult>> remaining_oof_results_;
+ base::span<const NGLink> children_;
+ base::span<const NGLink>::iterator iterator_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
index c61bd84eae7..cbea9657185 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
@@ -43,7 +43,6 @@ NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
builder.SetPercentageResolutionSize(
{kIndefiniteSize, input.percentage_resolution_block_size});
builder.SetReplacedPercentageResolutionSize(indefinite_size);
- builder.SetIsShrinkToFit(child.Style().LogicalWidth().IsAuto());
return builder.ToConstraintSpace();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
index 2606614b302..910ad2efea2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
@@ -46,6 +46,11 @@ wtf_size_t LayoutNGTable::ColumnCount() const {
return cached_layout_result->TableColumnCount();
}
+bool LayoutNGTable::HasCollapsedBorders() const {
+ NOT_DESTROYED();
+ return cached_table_borders_ && cached_table_borders_->IsCollapsed();
+}
+
void LayoutNGTable::SetCachedTableBorders(
scoped_refptr<const NGTableBorders> table_borders) {
NOT_DESTROYED();
@@ -77,16 +82,36 @@ void LayoutNGTable::SetCachedTableColumnConstraints(
void LayoutNGTable::GridBordersChanged() {
NOT_DESTROYED();
InvalidateCachedTableBorders();
- // If borders change, table fragment must be regenerated.
- if (StyleRef().BorderCollapse() == EBorderCollapse::kCollapse)
+ if (StyleRef().BorderCollapse() == EBorderCollapse::kCollapse) {
+ SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+ PaintInvalidationReason::kStyle);
+ // If borders change, table fragment must be regenerated.
SetNeedsLayout(layout_invalidation_reason::kTableChanged);
+ }
}
void LayoutNGTable::TableGridStructureChanged() {
NOT_DESTROYED();
+ // Callers must ensure table layout gets invalidated.
InvalidateCachedTableBorders();
}
+bool LayoutNGTable::HasBackgroundForPaint() const {
+ NOT_DESTROYED();
+ if (StyleRef().HasBackground())
+ return true;
+ DCHECK_GT(PhysicalFragmentCount(), 0u);
+ const NGTableFragmentData::ColumnGeometries* column_geometries =
+ GetPhysicalFragment(0)->TableColumnGeometries();
+ if (column_geometries) {
+ for (const auto& column_geometry : *column_geometries) {
+ if (column_geometry.node.Style().HasBackground())
+ return true;
+ }
+ }
+ return false;
+}
+
void LayoutNGTable::UpdateBlockLayout(bool relayout_children) {
NOT_DESTROYED();
LayoutAnalyzer::BlockScope analyzer(*this);
@@ -101,6 +126,10 @@ void LayoutNGTable::UpdateBlockLayout(bool relayout_children) {
void LayoutNGTable::AddChild(LayoutObject* child, LayoutObject* before_child) {
NOT_DESTROYED();
TableGridStructureChanged();
+ // Only TablesNG table parts are allowed.
+ DCHECK(child->IsLayoutNGObject() ||
+ (!child->IsTableCaption() && !child->IsLayoutTableCol() &&
+ !child->IsTableSection()));
bool wrap_in_anonymous_section = !child->IsTableCaption() &&
!child->IsLayoutTableCol() &&
!child->IsTableSection();
@@ -225,17 +254,23 @@ void LayoutNGTable::AddVisualEffectOverflow() {
if (const NGPhysicalBoxFragment* fragment = GetPhysicalFragment(0)) {
DCHECK_EQ(PhysicalFragmentCount(), 1u);
// Table's collapsed borders contribute to visual overflow.
- // Table border side can be composed of multiple border segments.
- // Inline visual overflow uses size of the largest border segment.
- // Block visual overflow uses size of first border segment.
+ // In the inline direction, table's border box does not include
+ // visual border width (largest border), but does include
+ // layout border width (border of first cell).
+ // Expands border box to include visual border width.
if (const NGTableBorders* collapsed_borders =
fragment->TableCollapsedBorders()) {
PhysicalRect borders_overflow = PhysicalBorderBoxRect();
NGBoxStrut table_borders = collapsed_borders->TableBorder();
auto visual_inline_strut =
collapsed_borders->GetCollapsedBorderVisualInlineStrut();
- table_borders.inline_start = visual_inline_strut.first;
- table_borders.inline_end = visual_inline_strut.second;
+ // Expand by difference between visual and layout border width.
+ table_borders.inline_start =
+ visual_inline_strut.first - table_borders.inline_start;
+ table_borders.inline_end =
+ visual_inline_strut.second - table_borders.inline_end;
+ table_borders.block_start = LayoutUnit();
+ table_borders.block_end = LayoutUnit();
borders_overflow.Expand(
table_borders.ConvertToPhysical(StyleRef().GetWritingDirection()));
AddSelfVisualOverflow(borders_overflow);
@@ -299,6 +334,34 @@ LayoutUnit LayoutNGTable::BorderBottom() const {
return LayoutNGMixin<LayoutBlock>::BorderBottom();
}
+LayoutUnit LayoutNGTable::PaddingTop() const {
+ NOT_DESTROYED();
+ if (ShouldCollapseBorders())
+ return LayoutUnit();
+ return LayoutNGMixin<LayoutBlock>::PaddingTop();
+}
+
+LayoutUnit LayoutNGTable::PaddingBottom() const {
+ NOT_DESTROYED();
+ if (ShouldCollapseBorders())
+ return LayoutUnit();
+ return LayoutNGMixin<LayoutBlock>::PaddingBottom();
+}
+
+LayoutUnit LayoutNGTable::PaddingLeft() const {
+ NOT_DESTROYED();
+ if (ShouldCollapseBorders())
+ return LayoutUnit();
+ return LayoutNGMixin<LayoutBlock>::PaddingLeft();
+}
+
+LayoutUnit LayoutNGTable::PaddingRight() const {
+ NOT_DESTROYED();
+ if (ShouldCollapseBorders())
+ return LayoutUnit();
+ return LayoutNGMixin<LayoutBlock>::PaddingRight();
+}
+
LayoutRectOutsets LayoutNGTable::BorderBoxOutsets() const {
NOT_DESTROYED();
// DCHECK(cached_table_borders_.get())
@@ -310,6 +373,28 @@ LayoutRectOutsets LayoutNGTable::BorderBoxOutsets() const {
return LayoutRectOutsets();
}
+// Effective column index is index of columns with mergeable
+// columns skipped. Used in a11y.
+unsigned LayoutNGTable::AbsoluteColumnToEffectiveColumn(
+ unsigned absolute_column_index) const {
+ NOT_DESTROYED();
+ if (!cached_table_columns_) {
+ NOTREACHED();
+ return absolute_column_index;
+ }
+ unsigned effective_column_index = 0;
+ unsigned column_count = cached_table_columns_.get()->data.size();
+ for (unsigned current_column_index = 0; current_column_index < column_count;
+ ++current_column_index) {
+ if (current_column_index != 0 &&
+ !cached_table_columns_.get()->data[current_column_index].is_mergeable)
+ ++effective_column_index;
+ if (current_column_index == absolute_column_index)
+ return effective_column_index;
+ }
+ return effective_column_index;
+}
+
bool LayoutNGTable::IsFirstCell(const LayoutNGTableCellInterface& cell) const {
NOT_DESTROYED();
const LayoutNGTableRowInterface* row = cell.RowInterface();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
index 9dee22e0183..0bce95d4ed8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
@@ -66,6 +66,10 @@ class CORE_EXPORT LayoutNGTable : public LayoutNGMixin<LayoutBlock>,
// might have changed.
void TableGridStructureChanged();
+ // Table paints column backgrounds.
+ // Returns true if table, or columns' style.HasBackground().
+ bool HasBackgroundForPaint() const;
+
// LayoutBlock methods start.
const char* GetName() const override {
@@ -96,8 +100,22 @@ class CORE_EXPORT LayoutNGTable : public LayoutNGMixin<LayoutBlock>,
LayoutUnit BorderRight() const override;
+ // The collapsing border model disallows paddings on table.
+ // See http://www.w3.org/TR/CSS2/tables.html#collapsing-borders.
+ LayoutUnit PaddingTop() const override;
+
+ LayoutUnit PaddingBottom() const override;
+
+ LayoutUnit PaddingLeft() const override;
+
+ LayoutUnit PaddingRight() const override;
+
LayoutRectOutsets BorderBoxOutsets() const override;
+ // TODO(1151101)
+ // ClientLeft/Top are incorrect for tables, but cannot be fixed
+ // by subclassing ClientLeft/Top.
+
PhysicalRect OverflowClipRect(const PhysicalOffset&,
OverlayScrollbarClipBehavior) const override;
@@ -108,6 +126,17 @@ class CORE_EXPORT LayoutNGTable : public LayoutNGMixin<LayoutBlock>,
return false;
}
+ // Whether a table has opaque foreground depends on many factors, e.g. border
+ // spacing, missing cells, etc. For simplicity, just conservatively assume
+ // foreground of all tables are not opaque.
+ // Copied from LayoutTable.
+ bool ForegroundIsKnownToBeOpaqueInRect(
+ const PhysicalRect& local_rect,
+ unsigned max_depth_to_test) const override {
+ NOT_DESTROYED();
+ return false;
+ }
+
// LayoutBlock methods end.
// LayoutNGTableInterface methods start.
@@ -133,11 +162,7 @@ class CORE_EXPORT LayoutNGTable : public LayoutNGMixin<LayoutBlock>,
return StyleRef().BorderCollapse() == EBorderCollapse::kCollapse;
}
- // Used in table painting for invalidation. Should not be needed by NG.
- bool HasCollapsedBorders() const final {
- NOTREACHED();
- return false;
- }
+ bool HasCollapsedBorders() const final;
bool HasColElements() const final {
NOTREACHED();
@@ -158,20 +183,14 @@ class CORE_EXPORT LayoutNGTable : public LayoutNGMixin<LayoutBlock>,
return ShouldCollapseBorders() ? 0 : StyleRef().VerticalBorderSpacing();
}
- // Legacy had a concept of colspan column compression. This is a legacy
- // method to map between absolute and compressed columns.
- // Because NG does not compress columns, absolute and effective are the same.
unsigned AbsoluteColumnToEffectiveColumn(
- unsigned absolute_column_index) const final {
- NOT_DESTROYED();
- return absolute_column_index;
- }
+ unsigned absolute_column_index) const final;
- // Legacy caches sections. Might not be needed by NG.
- void RecalcSectionsIfNeeded() const final { NOTIMPLEMENTED(); }
+ // NG does not need this method. Sections are not cached.
+ void RecalcSectionsIfNeeded() const final {}
- // Legacy caches sections. Might not be needed by NG.
- void ForceSectionsRecalc() final { NOTIMPLEMENTED(); }
+ // Not used by NG. Legacy caches sections.
+ void ForceSectionsRecalc() final { NOT_DESTROYED(); }
// Used in paint for printing. Should not be needed by NG.
LayoutUnit RowOffsetFromRepeatingFooter() const final {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h
index ab444cfb134..7d8a907e54d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h
@@ -12,6 +12,7 @@
namespace blink {
class LayoutNGTableInterface;
+class NGPhysicalFragment;
class CORE_EXPORT LayoutNGTableCaption final
: public LayoutNGBlockFlowMixin<LayoutTableCaption> {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
index 85d4c23a661..2968a2022ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.h"
namespace blink {
@@ -37,8 +38,13 @@ void LayoutNGTableCell::InvalidateLayoutResultCacheAfterMeasure() const {
LayoutRectOutsets LayoutNGTableCell::BorderBoxOutsets() const {
NOT_DESTROYED();
- DCHECK_GE(PhysicalFragmentCount(), 0u);
- return GetPhysicalFragment(0)->Borders().ToLayoutRectOutsets();
+ // TODO(1061423) This function should not be called before layout.
+ // ScrollAnchor::Examine does. Example trigger:
+ // ScrollTimelineTest.TimelineInvalidationWhenScrollerDisplayPropertyChanges
+ // DCHECK_GE(PhysicalFragmentCount(), 0u);
+ if (PhysicalFragmentCount() > 0)
+ return GetPhysicalFragment(0)->Borders().ToLayoutRectOutsets();
+ return LayoutNGBlockFlowMixin<LayoutBlockFlow>::BorderBoxOutsets();
}
LayoutUnit LayoutNGTableCell::BorderTop() const {
@@ -115,12 +121,21 @@ void LayoutNGTableCell::StyleDidChange(StyleDifference diff,
LayoutNGBlockFlowMixin<LayoutBlockFlow>::StyleDidChange(diff, old_style);
}
+void LayoutNGTableCell::WillBeRemovedFromTree() {
+ NOT_DESTROYED();
+ if (LayoutNGTable* table = Table())
+ table->TableGridStructureChanged();
+ LayoutNGMixin<LayoutBlockFlow>::WillBeRemovedFromTree();
+}
+
void LayoutNGTableCell::ColSpanOrRowSpanChanged() {
NOT_DESTROYED();
- // TODO(atotic) Invalidate layout?
UpdateColAndRowSpanFlags();
- if (LayoutNGTable* table = Table())
+ if (LayoutNGTable* table = Table()) {
+ table->SetNeedsLayoutAndIntrinsicWidthsRecalc(
+ layout_invalidation_reason::kTableChanged);
table->TableGridStructureChanged();
+ }
}
LayoutBox* LayoutNGTableCell::CreateAnonymousBoxWithSameTypeAs(
@@ -129,6 +144,17 @@ LayoutBox* LayoutNGTableCell::CreateAnonymousBoxWithSameTypeAs(
return LayoutObjectFactory::CreateAnonymousTableCellWithParent(*parent);
}
+LayoutBlock* LayoutNGTableCell::StickyContainer() const {
+ NOT_DESTROYED();
+ return Table();
+}
+
+void LayoutNGTableCell::InvalidatePaint(
+ const PaintInvalidatorContext& context) const {
+ NOT_DESTROYED();
+ NGTableCellPaintInvalidator(*this, context).InvalidatePaint();
+}
+
bool LayoutNGTableCell::BackgroundIsKnownToBeOpaqueInRect(
const PhysicalRect& local_rect) const {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h
index a3e638bc05b..66f9c1a73c7 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h
@@ -69,6 +69,8 @@ class CORE_EXPORT LayoutNGTableCell
void StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) final;
+ void WillBeRemovedFromTree() override;
+
// TODO(atotic) Remove "New" from name.
// Currently, LayoutNGTableCellLegacy is named LayoutNGTableCell for test
// compat.
@@ -87,6 +89,10 @@ class CORE_EXPORT LayoutNGTableCell
LayoutBox* CreateAnonymousBoxWithSameTypeAs(
const LayoutObject* parent) const override;
+ LayoutBlock* StickyContainer() const override;
+
+ void InvalidatePaint(const PaintInvalidatorContext&) const override;
+
// LayoutBlockFlow methods end.
// LayoutNGTableCellInterface methods start.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
index da8e67de7fd..4b9d4cda8cf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
@@ -36,7 +36,7 @@ void LayoutNGTableColumn::StyleDidChange(StyleDifference diff,
}
}
}
- LayoutBoxModelObject::StyleDidChange(diff, old_style);
+ LayoutBox::StyleDidChange(diff, old_style);
}
void LayoutNGTableColumn::ImageChanged(WrappedImagePtr, CanDeferInvalidation) {
@@ -47,6 +47,22 @@ void LayoutNGTableColumn::ImageChanged(WrappedImagePtr, CanDeferInvalidation) {
}
}
+void LayoutNGTableColumn::InsertedIntoTree() {
+ NOT_DESTROYED();
+ LayoutBox::InsertedIntoTree();
+ DCHECK(Table());
+ if (StyleRef().HasBackground())
+ Table()->SetBackgroundNeedsFullPaintInvalidation();
+}
+
+void LayoutNGTableColumn::WillBeRemovedFromTree() {
+ NOT_DESTROYED();
+ LayoutBox::WillBeRemovedFromTree();
+ DCHECK(Table());
+ if (StyleRef().HasBackground())
+ Table()->SetBackgroundNeedsFullPaintInvalidation();
+}
+
bool LayoutNGTableColumn::IsChildAllowed(LayoutObject* child,
const ComputedStyle& style) const {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
index a1831292439..f0f56ccd725 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
@@ -57,6 +57,10 @@ class CORE_EXPORT LayoutNGTableColumn : public LayoutBox {
void ImageChanged(WrappedImagePtr, CanDeferInvalidation) final;
+ void InsertedIntoTree() override;
+
+ void WillBeRemovedFromTree() override;
+
bool VisualRectRespectsVisibility() const final {
NOT_DESTROYED();
return false;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
index 98fe9be615d..02aed9710c8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
@@ -86,6 +86,13 @@ void LayoutNGTableRow::RemoveChild(LayoutObject* child) {
LayoutNGMixin<LayoutBlock>::RemoveChild(child);
}
+void LayoutNGTableRow::WillBeRemovedFromTree() {
+ NOT_DESTROYED();
+ if (LayoutNGTable* table = Table())
+ table->TableGridStructureChanged();
+ LayoutNGMixin<LayoutBlock>::WillBeRemovedFromTree();
+}
+
void LayoutNGTableRow::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
NOT_DESTROYED();
@@ -105,6 +112,11 @@ LayoutBox* LayoutNGTableRow::CreateAnonymousBoxWithSameTypeAs(
return LayoutObjectFactory::CreateAnonymousTableRowWithParent(*parent);
}
+LayoutBlock* LayoutNGTableRow::StickyContainer() const {
+ NOT_DESTROYED();
+ return Table();
+}
+
// This is necessary because TableRow paints beyond border box if it contains
// rowspanned cells.
void LayoutNGTableRow::AddVisualOverflowFromBlockChildren() {
@@ -122,6 +134,15 @@ void LayoutNGTableRow::AddVisualOverflowFromBlockChildren() {
}
}
+PositionWithAffinity LayoutNGTableRow::PositionForPoint(
+ const PhysicalOffset& offset) const {
+ NOT_DESTROYED();
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+ // LayoutBlock::PositionForPoint is wrong for rows.
+ return LayoutBox::PositionForPoint(offset);
+}
+
unsigned LayoutNGTableRow::RowIndex() const {
NOT_DESTROYED();
unsigned index = 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h
index 3e24e3815a0..4fd22a2bdf2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h
@@ -40,16 +40,26 @@ class CORE_EXPORT LayoutNGTableRow : public LayoutNGMixin<LayoutBlock>,
void RemoveChild(LayoutObject*) override;
+ void WillBeRemovedFromTree() override;
+
void StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) override;
LayoutBox* CreateAnonymousBoxWithSameTypeAs(
const LayoutObject* parent) const override;
+ LayoutBlock* StickyContainer() const override;
+
// Whether a row has opaque background depends on many factors, e.g. border
// spacing, border collapsing, missing cells, etc.
// For simplicity, just conservatively assume all table rows are not opaque.
// Copied from Legacy's LayoutTableRow
+ bool ForegroundIsKnownToBeOpaqueInRect(const PhysicalRect&,
+ unsigned) const override {
+ NOT_DESTROYED();
+ return false;
+ }
+
bool BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect&) const override {
NOT_DESTROYED();
return false;
@@ -67,6 +77,8 @@ class CORE_EXPORT LayoutNGTableRow : public LayoutNGMixin<LayoutBlock>,
return false;
}
+ PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
+
// LayoutBlock methods end.
// LayoutNGTableRowInterface methods start.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
index ad4dfba9498..e675fd2bc15 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
@@ -16,12 +16,7 @@ LayoutNGTableSection::LayoutNGTableSection(Element* element)
bool LayoutNGTableSection::IsEmpty() const {
NOT_DESTROYED();
- for (LayoutObject* child = FirstChild(); child;
- child = child->NextSibling()) {
- if (!To<LayoutNGTableRow>(child)->IsEmpty())
- return false;
- }
- return true;
+ return !FirstChild();
}
LayoutNGTable* LayoutNGTableSection::Table() const {
@@ -87,6 +82,13 @@ void LayoutNGTableSection::RemoveChild(LayoutObject* child) {
LayoutNGMixin<LayoutBlock>::RemoveChild(child);
}
+void LayoutNGTableSection::WillBeRemovedFromTree() {
+ NOT_DESTROYED();
+ if (LayoutNGTable* table = Table())
+ table->TableGridStructureChanged();
+ LayoutNGMixin<LayoutBlock>::WillBeRemovedFromTree();
+}
+
void LayoutNGTableSection::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
NOT_DESTROYED();
@@ -130,7 +132,12 @@ LayoutNGTableRowInterface* LayoutNGTableSection::LastRowInterface() const {
// behaviour is correct. Consider removing these methods.
unsigned LayoutNGTableSection::NumEffectiveColumns() const {
NOT_DESTROYED();
- return To<LayoutNGTable>(TableInterface()->ToLayoutObject())->ColumnCount();
+ const LayoutNGTable* table = Table();
+ DCHECK(table);
+ wtf_size_t column_count = table->ColumnCount();
+ if (column_count == 0)
+ return 0;
+ return table->AbsoluteColumnToEffectiveColumn(column_count - 1) + 1;
}
// TODO(crbug.com/1079133): Used by AXLayoutObject::IsDataTable/ColumnCount,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h
index abc4f94c2d6..a80d5599b7a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h
@@ -39,6 +39,8 @@ class CORE_EXPORT LayoutNGTableSection : public LayoutNGMixin<LayoutBlock>,
void RemoveChild(LayoutObject*) override;
+ void WillBeRemovedFromTree() override;
+
void StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) override;
@@ -50,6 +52,16 @@ class CORE_EXPORT LayoutNGTableSection : public LayoutNGMixin<LayoutBlock>,
return false;
}
+ // Whether a section has opaque background depends on many factors, e.g.
+ // border spacing, border collapsing, missing cells, etc. For simplicity,
+ // just conservatively assume all table sections are not opaque.
+ // Copied from LayoutTableSection,
+ bool ForegroundIsKnownToBeOpaqueInRect(const PhysicalRect&,
+ unsigned) const override {
+ NOT_DESTROYED();
+ return false;
+ }
+
bool BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect&) const override {
NOT_DESTROYED();
return false;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
index bebd174f4f3..12c20eefe14 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
@@ -197,7 +197,6 @@ scoped_refptr<NGTableBorders> NGTableBorders::ComputeTableBorders(
wtf_size_t box_order = 0;
wtf_size_t table_column_count = 0;
wtf_size_t table_row_index = 0;
-
// Mark cell borders.
bool found_multispan_cells = false;
for (const NGBlockNode section : grouped_children) {
@@ -209,11 +208,6 @@ scoped_refptr<NGTableBorders> NGTableBorders::ComputeTableBorders(
for (NGBlockNode cell = To<NGBlockNode>(row.FirstChild()); cell;
cell = To<NGBlockNode>(cell.NextSibling())) {
tabulator.FindNextFreeColumn();
- // https://stackoverflow.com/questions/18758373/why-do-the-css-property-border-collapse-and-empty-cells-conflict
- if (hide_empty_cells && !To<NGBlockNode>(cell).FirstChild()) {
- tabulator.ProcessCell(cell);
- continue;
- }
wtf_size_t cell_colspan = cell.TableCellColspan();
found_multispan_cells |=
cell.TableCellRowspan() > 1 || cell_colspan > 1;
@@ -224,6 +218,11 @@ scoped_refptr<NGTableBorders> NGTableBorders::ComputeTableBorders(
table_column_count, NGTableAlgorithmHelpers::ComputeMaxColumn(
tabulator.CurrentColumn(), cell_colspan,
table.Style().IsFixedTableLayout()));
+ // https://stackoverflow.com/questions/18758373/why-do-the-css-property-border-collapse-and-empty-cells-conflict
+ if (hide_empty_cells && !To<NGBlockNode>(cell).FirstChild()) {
+ tabulator.ProcessCell(cell);
+ continue;
+ }
if (!found_multispan_cells) {
table_borders->MergeBorders(
table_row_index, tabulator.CurrentColumn(),
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h
index fb6613cdb57..3872dee5f68 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h
@@ -40,11 +40,13 @@ class NGTableConstraintSpaceData
struct Section {
Section(wtf_size_t start_row_index, wtf_size_t rowspan)
: start_row_index(start_row_index), rowspan(rowspan) {}
- bool operator==(const Section& other) const {
- return start_row_index == other.start_row_index &&
- rowspan == other.rowspan;
+
+ bool MaySkipLayout(const Section& other) const {
+ // We don't compare |start_row_index| as this is allowed to change.
+ return rowspan == other.rowspan;
}
- wtf_size_t start_row_index; // first section row in table grid.
+
+ wtf_size_t start_row_index; // First section row in table grid.
wtf_size_t rowspan;
};
@@ -63,15 +65,16 @@ class NGTableConstraintSpaceData
has_baseline_aligned_percentage_block_size_descendants(
has_baseline_aligned_percentage_block_size_descendants),
is_collapsed(is_collapsed) {}
- bool operator==(const Row& other) const {
+
+ bool MaySkipLayout(const Row& other) const {
+ // We don't compare |start_cell_index| as this is allowed to change.
return baseline == other.baseline && block_size == other.block_size &&
- start_cell_index == other.start_cell_index &&
cell_count == other.cell_count &&
has_baseline_aligned_percentage_block_size_descendants ==
other.has_baseline_aligned_percentage_block_size_descendants &&
is_collapsed == other.is_collapsed;
}
- bool operator!=(const Row& other) const { return !(*this == other); }
+
LayoutUnit baseline;
LayoutUnit block_size;
wtf_size_t start_cell_index;
@@ -93,6 +96,7 @@ class NGTableConstraintSpaceData
bool operator==(const Cell& other) const {
return border_box_borders == other.border_box_borders &&
block_size == other.block_size &&
+ start_column == other.start_column &&
is_constrained == other.is_constrained;
}
bool operator!=(const Cell& other) const { return !(*this == other); }
@@ -115,34 +119,67 @@ class NGTableConstraintSpaceData
}
bool MaySkipRowLayout(const NGTableConstraintSpaceData& other,
- wtf_size_t row_index) const {
- if (other.rows.size() <= row_index)
- return false;
- if (rows[row_index] != other.rows[row_index])
+ wtf_size_t new_row_index,
+ wtf_size_t old_row_index) const {
+ DCHECK_LT(new_row_index, rows.size());
+ DCHECK_LT(old_row_index, other.rows.size());
+
+ const Row& new_row = rows[new_row_index];
+ const Row& old_row = other.rows[old_row_index];
+ if (!new_row.MaySkipLayout(old_row))
return false;
- DCHECK_LT(row_index, rows.size());
- wtf_size_t end_index =
- rows[row_index].start_cell_index + rows[row_index].cell_count;
- for (wtf_size_t cell_index = rows[row_index].start_cell_index;
- cell_index < end_index; ++cell_index) {
- if (cells[cell_index] != other.cells[cell_index])
+
+ DCHECK_EQ(new_row.cell_count, old_row.cell_count);
+
+ const wtf_size_t new_start_cell_index = new_row.start_cell_index;
+ const wtf_size_t old_start_cell_index = old_row.start_cell_index;
+
+ const wtf_size_t new_end_cell_index =
+ new_start_cell_index + new_row.cell_count;
+ const wtf_size_t old_end_cell_index =
+ old_start_cell_index + old_row.cell_count;
+
+ for (wtf_size_t new_cell_index = new_start_cell_index,
+ old_cell_index = old_start_cell_index;
+ new_cell_index < new_end_cell_index &&
+ old_cell_index < old_end_cell_index;
+ ++new_cell_index, ++old_cell_index) {
+ if (cells[new_cell_index] != other.cells[old_cell_index])
return false;
}
+
return true;
}
bool MaySkipSectionLayout(const NGTableConstraintSpaceData& other,
- wtf_size_t section_index) const {
- if (other.sections.size() <= section_index)
+ wtf_size_t new_section_index,
+ wtf_size_t old_section_index) const {
+ DCHECK_LE(new_section_index, sections.size());
+ DCHECK_LE(old_section_index, other.sections.size());
+
+ const Section& new_section = sections[new_section_index];
+ const Section& old_section = other.sections[old_section_index];
+ if (!new_section.MaySkipLayout(old_section))
return false;
- DCHECK_LT(section_index, sections.size());
- wtf_size_t end_index = sections[section_index].start_row_index +
- sections[section_index].rowspan;
- for (wtf_size_t row_index = sections[section_index].start_row_index;
- row_index < end_index; ++row_index) {
- if (!MaySkipRowLayout(other, row_index))
+
+ DCHECK_EQ(new_section.rowspan, old_section.rowspan);
+
+ const wtf_size_t new_start_row_index = new_section.start_row_index;
+ const wtf_size_t old_start_row_index = old_section.start_row_index;
+
+ const wtf_size_t new_end_row_index =
+ new_start_row_index + new_section.rowspan;
+ const wtf_size_t old_end_row_index =
+ old_start_row_index + old_section.rowspan;
+
+ for (wtf_size_t new_row_index = new_start_row_index,
+ old_row_index = old_start_row_index;
+ new_row_index < new_end_row_index && old_row_index < old_end_row_index;
+ ++new_row_index, ++old_row_index) {
+ if (!MaySkipRowLayout(other, new_row_index, old_row_index))
return false;
}
+
return true;
}
@@ -163,13 +200,13 @@ class NGTableConstraintSpaceData
} // namespace blink
-WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(
blink::NGTableConstraintSpaceData::ColumnLocation)
WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
blink::NGTableConstraintSpaceData::Section)
-WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(
blink::NGTableConstraintSpaceData::Row)
-WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(
blink::NGTableConstraintSpaceData::Cell)
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_NG_TABLE_CONSTRAINT_SPACE_DATA_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h
index 08f34ce4e89..a4be953ae6f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h
@@ -41,6 +41,14 @@ class NGTableFragmentData {
struct CollapsedBordersGeometry {
Vector<LayoutUnit> columns; // Column offsets from table grid border.
Vector<LayoutUnit> rows; // Row offsets from table grid border.
+
+#if DCHECK_IS_ON()
+ void CheckSameForSimplifiedLayout(
+ const CollapsedBordersGeometry& other) const {
+ DCHECK(columns == other.columns);
+ DCHECK(rows == other.rows);
+ }
+#endif
};
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
index 6e635dd7501..1b76c2c5479 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -31,20 +31,6 @@ namespace blink {
namespace {
-// TODO(atotic, ikilpatrick)
-// Copy of ShouldScaleColumnsForParent from table_layout_algorithm_auto.cc
-// The real fix would be for containers to understand that
-// Table max really means: max should be trimmed to available inline size.
-bool ShouldIgnorePercentagesForMinMax(const LayoutBox& table) {
- return false;
-}
-
-// Another MinMax variant of ShouldIgnorePercentagesForMinMax
-// This one is only for flexbox/grid. CSS size should be ignored.
-bool ShouldIgnoreCssSizesForMinMax(const LayoutBlock& table) {
- return false;
-}
-
NGTableTypes::Caption ComputeCaptionConstraint(
const ComputedStyle& table_style,
const NGTableGroupedChildren& grouped_children) {
@@ -69,51 +55,19 @@ LayoutUnit ComputeUndistributableTableSpace(
const NGTableTypes::Columns& column_constraints,
LayoutUnit inline_table_border_padding,
LayoutUnit inline_border_spacing) {
- unsigned inline_space_count = 2 + (column_constraints.data.size() > 1
- ? column_constraints.data.size() - 1
- : 0);
- return inline_table_border_padding +
- inline_space_count * inline_border_spacing;
-}
-
-void ComputeTableCssInlineSizes(
- const ComputedStyle& table_style,
- const NGConstraintSpace& constraint_space,
- const NGBoxStrut& table_border_padding,
- const MinMaxSizes& grid_min_max,
- LayoutUnit* table_css_min_inline_size,
- base::Optional<LayoutUnit>* table_css_inline_size,
- base::Optional<LayoutUnit>* table_css_max_inline_size) {
- const Length& table_min_length = table_style.LogicalMinWidth();
- *table_css_min_inline_size =
- table_min_length.IsSpecified()
- ? ResolveMinInlineLength<base::Optional<MinMaxSizes>>(
- constraint_space, table_style, table_border_padding,
- base::nullopt, table_min_length, LengthResolvePhase::kLayout)
- : LayoutUnit();
-
- // Compute standard "used width of a table".
- const Length& table_length = table_style.LogicalWidth();
- if (!table_length.IsAuto()) {
- *table_css_inline_size = ResolveMainInlineLength(
- constraint_space, table_style, table_border_padding,
- [grid_min_max](MinMaxSizesType) {
- return MinMaxSizesResult{
- grid_min_max,
- /* depends_on_percentage_block_size */ false};
- },
- table_length);
+ unsigned inline_space_count = 2;
+ bool is_first_column = true;
+ for (const NGTableTypes::Column& column : column_constraints.data) {
+ if (!column.is_mergeable) {
+ if (is_first_column)
+ is_first_column = false;
+ else
+ inline_space_count++;
+ }
}
- const Length& table_max_length = table_style.LogicalMaxWidth();
- if (table_max_length.IsSpecified()) {
- *table_css_max_inline_size =
- ResolveMaxInlineLength<base::Optional<MinMaxSizes>>(
- constraint_space, table_style, table_border_padding, base::nullopt,
- table_max_length, LengthResolvePhase::kLayout);
- *table_css_max_inline_size =
- std::max(**table_css_max_inline_size, *table_css_min_inline_size);
- }
+ return inline_table_border_padding +
+ inline_space_count * inline_border_spacing;
}
// Empty table sizes have been a source of many inconsistencies
@@ -145,7 +99,7 @@ LayoutUnit ComputeEmptyTableInlineSize(
// standard: https://www.w3.org/TR/css-tables-3/#computing-the-table-width
LayoutUnit ComputeAssignableTableInlineSize(
- const NGBlockNode& table,
+ const NGTableNode& table,
const NGConstraintSpace& space,
const NGTableTypes::Columns& column_constraints,
const NGTableTypes::Caption& caption_constraint,
@@ -156,45 +110,27 @@ LayoutUnit ComputeAssignableTableInlineSize(
return (space.AvailableSize().inline_size - undistributable_space)
.ClampNegativeToZero();
}
- MinMaxSizes grid_min_max = NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
- column_constraints, undistributable_space, is_fixed_layout,
- /* containing_block_expects_minmax_without_percentages */ false,
- /* skip_collapsed_columns */ false);
-
- LayoutUnit table_css_min_inline_size;
- base::Optional<LayoutUnit> table_css_inline_size;
- base::Optional<LayoutUnit> table_css_max_inline_size;
- ComputeTableCssInlineSizes(table.Style(), space, table_border_padding,
- grid_min_max, &table_css_min_inline_size,
- &table_css_inline_size,
- &table_css_max_inline_size);
-
- LayoutUnit table_min_inline_size =
- std::max({table_css_min_inline_size, caption_constraint.min_size,
- grid_min_max.min_size});
+
+ const MinMaxSizes grid_min_max =
+ NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ table, column_constraints, undistributable_space, is_fixed_layout,
+ /* is_layout_pass */ true,
+ /* skip_collapsed_columns */ false);
// Standard: "used width of the table".
- LayoutUnit used_inline_size_of_the_table;
- if (table_css_inline_size) {
- used_inline_size_of_the_table = *table_css_inline_size;
- } else {
- NGBoxStrut margins = ComputeMarginsForSelf(space, table.Style());
- used_inline_size_of_the_table =
- std::min(grid_min_max.max_size,
- (space.AvailableSize().inline_size - margins.InlineSum())
- .ClampNegativeToZero());
- }
- if (table_css_max_inline_size) {
- used_inline_size_of_the_table =
- std::min(used_inline_size_of_the_table, *table_css_max_inline_size);
- }
- used_inline_size_of_the_table =
- std::max(used_inline_size_of_the_table, table_min_inline_size);
+ LayoutUnit used_table_inline_size = ComputeUsedInlineSizeForTableFragment(
+ space, table, table_border_padding, grid_min_max);
+
+ // Don't allow the inline-size to go below the grid, or caption min-size.
+ used_table_inline_size =
+ std::max({used_table_inline_size, caption_constraint.min_size,
+ grid_min_max.min_size});
// Standard: The assignable table width is the "used width of the table"
// minus the total horizontal border spacing.
- LayoutUnit assignable_table_inline_size =
- used_inline_size_of_the_table - undistributable_space;
+ const LayoutUnit assignable_table_inline_size =
+ used_table_inline_size - undistributable_space;
+ DCHECK_GE(assignable_table_inline_size, LayoutUnit());
return assignable_table_inline_size;
}
@@ -218,7 +154,13 @@ void ComputeLocationsFromColumns(
*has_collapsed_columns =
*has_collapsed_columns || column_constraint.is_collapsed;
column_location.offset = column_offset;
- if (shrink_collapsed && column_constraint.is_collapsed) {
+ if (column_constraints.data[i].is_mergeable &&
+ (column_sizes[i] == kIndefiniteSize ||
+ column_sizes[i] == LayoutUnit())) {
+ // Empty mergeable columns are treated as collapsed.
+ column_location.size = LayoutUnit();
+ column_location.is_collapsed = true;
+ } else if (shrink_collapsed && column_constraint.is_collapsed) {
column_location.is_collapsed = true;
column_location.size = LayoutUnit();
} else {
@@ -230,7 +172,7 @@ void ComputeLocationsFromColumns(
}
}
-scoped_refptr<NGTableConstraintSpaceData> CreateConstraintSpaceData(
+scoped_refptr<const NGTableConstraintSpaceData> CreateConstraintSpaceData(
const ComputedStyle& style,
const NGTableTypes::ColumnLocations& column_locations,
const NGTableTypes::Sections& sections,
@@ -309,19 +251,15 @@ class ColumnGeometriesBuilder {
wtf_size_t span) {
wtf_size_t end_column_index = start_column_index + span - 1;
DCHECK_LE(end_column_index, column_locations.size() - 1);
- LayoutUnit column_width = column_locations[end_column_index].offset +
- column_locations[end_column_index].size -
- column_locations[start_column_index].offset;
- col.GetLayoutBox()->SetLogicalWidth(column_width);
+ LayoutUnit column_inline_size = column_locations[end_column_index].offset +
+ column_locations[end_column_index].size -
+ column_locations[start_column_index].offset;
+ col.GetLayoutBox()->SetLogicalWidth(column_inline_size);
col.GetLayoutBox()->SetLogicalHeight(table_grid_block_size);
- for (unsigned i = 0; i < span; ++i) {
- wtf_size_t current_column_index = start_column_index + i;
- column_geometries.emplace_back(
- current_column_index, /* span */ 1,
- column_locations[current_column_index].offset -
- border_spacing.inline_size,
- column_locations[current_column_index].size, col);
- }
+ column_geometries.emplace_back(start_column_index, span,
+ column_locations[start_column_index].offset -
+ border_spacing.inline_size,
+ column_inline_size, col);
}
void EnterColgroup(const NGLayoutInputNode& colgroup,
@@ -333,28 +271,16 @@ class ColumnGeometriesBuilder {
bool has_children) {
if (span == 0)
return;
- if (has_children) {
- wtf_size_t last_column_index = start_column_index + span - 1;
- LayoutUnit colgroup_size = column_locations[last_column_index].offset +
- column_locations[last_column_index].size -
- column_locations[start_column_index].offset;
- colgroup.GetLayoutBox()->SetLogicalWidth(colgroup_size);
- colgroup.GetLayoutBox()->SetLogicalHeight(table_grid_block_size);
- column_geometries.emplace_back(
- start_column_index, span,
- column_locations[start_column_index].offset -
- border_spacing.inline_size,
- colgroup_size, colgroup);
- } else {
- for (unsigned i = 0; i < span; ++i) {
- wtf_size_t current_column_index = start_column_index + i;
- column_geometries.emplace_back(
- current_column_index, /* span */ 1,
- column_locations[current_column_index].offset -
- border_spacing.inline_size,
- column_locations[current_column_index].size, colgroup);
- }
- }
+ wtf_size_t last_column_index = start_column_index + span - 1;
+ LayoutUnit colgroup_size = column_locations[last_column_index].offset +
+ column_locations[last_column_index].size -
+ column_locations[start_column_index].offset;
+ colgroup.GetLayoutBox()->SetLogicalWidth(colgroup_size);
+ colgroup.GetLayoutBox()->SetLogicalHeight(table_grid_block_size);
+ column_geometries.emplace_back(start_column_index, span,
+ column_locations[start_column_index].offset -
+ border_spacing.inline_size,
+ colgroup_size, colgroup);
}
void Sort() {
@@ -368,6 +294,8 @@ class ColumnGeometriesBuilder {
return a.start_column < b.start_column;
}
if (a.node.IsTableColgroup()) {
+ if (b.node.IsTableColgroup())
+ return a.start_column < b.start_column;
if (a.start_column <= b.start_column &&
(a.start_column + a.span) > b.start_column) {
return true;
@@ -454,24 +382,15 @@ LayoutUnit NGTableLayoutAlgorithm::ComputeTableInlineSize(
ComputeLocationsFromColumns(
*column_constraints, column_sizes, border_spacing.inline_size,
/* collapse_columns */ true, &column_locations, &has_collapsed_columns);
- return ComputeTableSizeFromColumns(column_locations, table_border_padding,
- border_spacing);
+ return std::max(ComputeTableSizeFromColumns(
+ column_locations, table_border_padding, border_spacing),
+ caption_constraint.min_size);
}
scoped_refptr<const NGLayoutResult> NGTableLayoutAlgorithm::Layout() {
DCHECK(!BreakToken());
- const bool is_fixed_layout = Style().IsFixedTableLayout();
-
- // TODO(atotic) review autosizer usage in TablesNG.
- // Legacy has:
- // LayoutTable::UpdateLayout
- // TextAutosizer::LayoutScope
- // TableLayoutAlgorithmAuto::ComputeIntrinsicLogicalWidths
- // TextAutosizer::TableLayoutScope
- base::Optional<TextAutosizer::TableLayoutScope> text_autosizer;
- if (!is_fixed_layout)
- text_autosizer.emplace(To<LayoutNGTable>(Node().GetLayoutBox()));
+ const bool is_fixed_layout = Style().IsFixedTableLayout();
const LogicalSize border_spacing = Style().TableBorderSpacing();
NGTableGroupedChildren grouped_children(Node());
const scoped_refptr<const NGTableBorders> table_borders =
@@ -524,14 +443,24 @@ scoped_refptr<const NGLayoutResult> NGTableLayoutAlgorithm::Layout() {
column_locations, border_padding, border_spacing);
}
+ // Before we can determine the block-size of the sections/rows, we need to
+ // layout all of our captions.
+ //
+ // The block-size taken by the captions, *subtracts* from the available
+ // block-size given to the table-grid.
+ Vector<CaptionResult> captions;
+ LayoutUnit captions_block_size;
+ ComputeCaptionFragments(grouped_children, container_builder_.InlineSize(),
+ captions, captions_block_size);
+
NGTableTypes::Rows rows;
NGTableTypes::CellBlockConstraints cell_block_constraints;
NGTableTypes::Sections sections;
LayoutUnit minimal_table_grid_block_size;
ComputeRows(table_inline_size_before_collapse - border_padding.InlineSum(),
grouped_children, column_locations, *table_borders,
- border_spacing, border_padding, is_fixed_layout, &rows,
- &cell_block_constraints, &sections,
+ border_spacing, border_padding, captions_block_size,
+ is_fixed_layout, &rows, &cell_block_constraints, &sections,
&minimal_table_grid_block_size);
if (has_collapsed_columns) {
@@ -540,35 +469,43 @@ scoped_refptr<const NGLayoutResult> NGTableLayoutAlgorithm::Layout() {
/* shrink_collapsed */ true, &column_locations, &has_collapsed_columns);
}
#if DCHECK_IS_ON()
- LayoutUnit table_inline_size;
- if (has_collapsed_columns) {
- table_inline_size = ComputeTableSizeFromColumns(
- column_locations, border_padding, border_spacing);
- table_inline_size =
- std::max(table_inline_size, caption_constraint.min_size);
+ if (!has_collapsed_columns) {
+ // Colums define table whose inline size equals InitialFragmentGeometry.
+ DCHECK_EQ(table_inline_size_before_collapse,
+ container_builder_.InlineSize());
+ } else if (ConstraintSpace().IsFixedInlineSize()) {
+ // Collapsed columns + fixed inline size: columns define table whose
+ // inline size is less or equal InitialFragmentGeometry.
+ LayoutUnit table_inline_size =
+ std::max(ComputeTableSizeFromColumns(column_locations, border_padding,
+ border_spacing),
+ caption_constraint.min_size);
+ DCHECK_LE(table_inline_size, container_builder_.InlineSize());
} else {
- table_inline_size = table_inline_size_before_collapse;
+ LayoutUnit table_inline_size =
+ std::max(ComputeTableSizeFromColumns(column_locations, border_padding,
+ border_spacing),
+ caption_constraint.min_size);
+ DCHECK_EQ(table_inline_size, container_builder_.InlineSize());
}
- DCHECK_EQ(table_inline_size, container_builder_.InlineSize());
#endif
- return GenerateFragment(
- container_builder_.InlineSize(), minimal_table_grid_block_size,
- grouped_children, column_locations, rows, cell_block_constraints,
- sections, *table_borders, is_grid_empty ? LogicalSize() : border_spacing);
+ return GenerateFragment(container_builder_.InlineSize(),
+ minimal_table_grid_block_size, grouped_children,
+ column_locations, rows, cell_block_constraints,
+ sections, captions, *table_borders,
+ is_grid_empty ? LogicalSize() : border_spacing);
}
MinMaxSizesResult NGTableLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizesInput& input) const {
- LayoutNGTable* layout_table = To<LayoutNGTable>(Node().GetLayoutBox());
const bool is_fixed_layout = Style().IsFixedTableLayout();
// Tables need autosizer.
base::Optional<TextAutosizer::TableLayoutScope> text_autosizer;
if (!is_fixed_layout)
- text_autosizer.emplace(layout_table);
+ text_autosizer.emplace(To<LayoutNGTable>(Node().GetLayoutBox()));
const LogicalSize border_spacing = Style().TableBorderSpacing();
- const auto table_writing_direction = Style().GetWritingDirection();
NGTableGroupedChildren grouped_children(Node());
const scoped_refptr<const NGTableBorders> table_borders =
Node().GetTableBorders();
@@ -585,66 +522,17 @@ MinMaxSizesResult NGTableLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizes grid_min_max =
NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
- *column_constraints, undistributable_space, is_fixed_layout,
- ShouldIgnorePercentagesForMinMax(*layout_table),
- /* skip_collapsed_columns */ true);
+ Node(), *column_constraints, undistributable_space, is_fixed_layout,
+ /* is_layout_pass */ false,
+ /* skip_collapsed_columns */ false);
MinMaxSizes min_max{
std::max(grid_min_max.min_size, caption_constraint.min_size),
std::max(grid_min_max.max_size, caption_constraint.min_size)};
- if (ShouldIgnoreCssSizesForMinMax(*layout_table)) {
- return MinMaxSizesResult{min_max,
- /* depends_on_percentage_block_size */ false};
- }
-
- NGConstraintSpaceBuilder min_space_builder(
- ConstraintSpace(), table_writing_direction, /* is_new_fc */ true);
- min_space_builder.SetAvailableSize({LayoutUnit(), kIndefiniteSize});
- LayoutUnit min_measure_table_css_min_inline_size;
- base::Optional<LayoutUnit> min_measure_table_css_inline_size;
- base::Optional<LayoutUnit> measure_table_css_max_inline_size;
-
- ComputeTableCssInlineSizes(
- Style(), min_space_builder.ToConstraintSpace(), border_padding,
- grid_min_max, &min_measure_table_css_min_inline_size,
- &min_measure_table_css_inline_size, &measure_table_css_max_inline_size);
-
- // Table min/max sizes are unusual in how the specified sizes affects them.
- // If table_css_inline_size is defined:
- // min_max_sizes is std::max(
- // table_css_inline_size,
- // grid_min_max.min_size,
- // caption_constraint.min_size)
- // (min_size and max_size are the same value).
- //
- // If table_css_inline_size is not defined:
- // min_max_sizes.min_size is std::max(
- // grid_min_max.min_size, caption_constraint.min_size)
- // min_max_sizes.max_size is std::max(
- // grid_min_max.max_size, caption_constraint.min_size)
- if (min_measure_table_css_inline_size) {
- NGConstraintSpaceBuilder max_space_builder(
- ConstraintSpace(), table_writing_direction, /* is_new_fc */ true);
- max_space_builder.SetAvailableSize(
- {grid_min_max.max_size, kIndefiniteSize});
- LayoutUnit max_measure_table_css_min_inline_size;
- base::Optional<LayoutUnit> max_measure_table_css_inline_size;
- ComputeTableCssInlineSizes(
- Style(), max_space_builder.ToConstraintSpace(), border_padding,
- grid_min_max, &max_measure_table_css_min_inline_size,
- &max_measure_table_css_inline_size, &measure_table_css_max_inline_size);
- // Compute minimum.
- min_max.min_size =
- std::max({min_max.min_size, min_measure_table_css_min_inline_size,
- *min_measure_table_css_inline_size});
- // Compute maximum.
- min_max.max_size =
- std::max({max_measure_table_css_min_inline_size,
- *max_measure_table_css_inline_size, grid_min_max.min_size,
- caption_constraint.min_size});
- if (is_fixed_layout && Style().LogicalWidth().IsPercentOrCalc())
- min_max.max_size = NGTableTypes::kTableMaxInlineSize;
+ if (is_fixed_layout && Style().LogicalWidth().IsPercentOrCalc() &&
+ Node().AllowsInfiniteMaxInlineSize()) {
+ min_max.max_size = NGTableTypes::kTableMaxInlineSize;
}
DCHECK_LE(min_max.min_size, min_max.max_size);
return MinMaxSizesResult{min_max,
@@ -658,6 +546,7 @@ void NGTableLayoutAlgorithm::ComputeRows(
const NGTableBorders& table_borders,
const LogicalSize& border_spacing,
const NGBoxStrut& table_border_padding,
+ const LayoutUnit captions_block_size,
bool is_fixed,
NGTableTypes::Rows* rows,
NGTableTypes::CellBlockConstraints* cell_block_constraints,
@@ -666,35 +555,36 @@ void NGTableLayoutAlgorithm::ComputeRows(
DCHECK_EQ(rows->size(), 0u);
DCHECK_EQ(cell_block_constraints->size(), 0u);
- // Initially resolve the table's block-size with an indefinite size.
- LayoutUnit css_table_block_size = ComputeBlockSizeForFragment(
- ConstraintSpace(), Style(), table_border_padding, kIndefiniteSize,
- table_grid_inline_size);
-
const bool is_table_block_size_specified = !Style().LogicalHeight().IsAuto();
LayoutUnit total_table_block_size;
wtf_size_t section_index = 0;
- for (const NGBlockNode& section : grouped_children) {
+ for (auto it = grouped_children.begin(); it != grouped_children.end(); ++it) {
NGTableAlgorithmUtils::ComputeSectionMinimumRowBlockSizes(
- section, table_grid_inline_size, is_table_block_size_specified,
+ *it, table_grid_inline_size, is_table_block_size_specified,
column_locations, table_borders, border_spacing.block_size,
- section_index++, sections, rows, cell_block_constraints);
+ section_index++, it.TreatAsTBody(), sections, rows,
+ cell_block_constraints);
total_table_block_size += sections->back().block_size;
}
- // Re-resolve the block-size if we have a min block-size which is resolvable.
- // We'll redistribute sections/rows into this space.
- if (!BlockLengthUnresolvable(ConstraintSpace(), Style().LogicalMinHeight(),
- LengthResolvePhase::kLayout)) {
- css_table_block_size = ComputeBlockSizeForFragment(
- ConstraintSpace(), Style(), table_border_padding,
- table_border_padding.BlockSum(), table_grid_inline_size);
- }
-
- // In quirks mode, empty tables ignore css block size.
- bool is_empty_quirks_mode_table =
+ // If we can correctly resolve our min-block-size we want to distribute
+ // sections/rows into this space. Pass a definite intrinsic block-size into
+ // |ComputeBlockSizeForFragment| to force it to resolve.
+ const LayoutUnit intrinsic_block_size =
+ BlockLengthUnresolvable(ConstraintSpace(), Style().LogicalMinHeight())
+ ? kIndefiniteSize
+ : table_border_padding.BlockSum();
+
+ const LayoutUnit css_table_block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), table_border_padding, intrinsic_block_size,
+ table_grid_inline_size, Node().ShouldBeConsideredAsReplaced(),
+ /* available_block_size_adjustment */ captions_block_size);
+
+ // In quirks mode, empty tables ignore any specified block-size.
+ const bool is_empty_quirks_mode_table =
Node().GetDocument().InQuirksMode() &&
grouped_children.begin() == grouped_children.end();
+
// Redistribute CSS table block size if necessary.
if (css_table_block_size != kIndefiniteSize && !is_empty_quirks_mode_table) {
*minimal_table_grid_block_size = css_table_block_size;
@@ -729,8 +619,6 @@ void NGTableLayoutAlgorithm::ComputeTableSpecificFragmentData(
const PhysicalRect& table_grid_rect,
const LogicalSize& border_spacing,
const LayoutUnit table_grid_block_size) {
- // TODO(atotic) SetHasNonCollapsedBorderDecoration should be a fragment
- // property, not a flag on LayoutObject.
container_builder_.SetTableGridRect(table_grid_rect);
container_builder_.SetTableColumnCount(column_locations.size());
container_builder_.SetHasCollapsedBorders(table_borders.IsCollapsed());
@@ -741,7 +629,7 @@ void NGTableLayoutAlgorithm::ComputeTableSpecificFragmentData(
VisitLayoutNGTableColumn(grouped_children.columns, column_locations.size(),
&geometry_builder);
geometry_builder.Sort();
- container_builder_.SetTableColumnGeometry(
+ container_builder_.SetTableColumnGeometries(
geometry_builder.column_geometries);
}
// Collapsed borders.
@@ -754,6 +642,7 @@ void NGTableLayoutAlgorithm::ComputeTableSpecificFragmentData(
fragment_borders_geometry->columns.push_back(column.offset +
grid_inline_start);
}
+ DCHECK_NE(column_locations.size(), 0u);
fragment_borders_geometry->columns.push_back(
column_locations.back().offset + column_locations.back().size +
grid_inline_start);
@@ -769,16 +658,14 @@ void NGTableLayoutAlgorithm::ComputeTableSpecificFragmentData(
}
}
-void NGTableLayoutAlgorithm::GenerateCaptionFragments(
+void NGTableLayoutAlgorithm::ComputeCaptionFragments(
const NGTableGroupedChildren& grouped_children,
const LayoutUnit table_inline_size,
- ECaptionSide caption_side,
- LayoutUnit* table_block_offset) {
+ Vector<CaptionResult>& captions,
+ LayoutUnit& captions_block_size) {
const LogicalSize available_size = {table_inline_size, kIndefiniteSize};
for (NGBlockNode caption : grouped_children.captions) {
const auto& caption_style = caption.Style();
- if (caption_style.CaptionSide() != caption_side)
- continue;
NGConstraintSpaceBuilder builder(ConstraintSpace(),
caption_style.GetWritingDirection(),
@@ -786,6 +673,7 @@ void NGTableLayoutAlgorithm::GenerateCaptionFragments(
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), caption, &builder);
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(available_size);
+ builder.SetStretchInlineSizeIfAuto(true);
NGConstraintSpace caption_constraint_space = builder.ToConstraintSpace();
scoped_refptr<const NGLayoutResult> caption_result =
@@ -796,14 +684,10 @@ void NGTableLayoutAlgorithm::GenerateCaptionFragments(
caption_style, ConstraintSpace());
ResolveInlineMargins(caption_style, Style(), table_inline_size,
fragment.InlineSize(), &margins);
- caption.StoreMargins(
- margins.ConvertToPhysical(ConstraintSpace().GetWritingDirection()));
- *table_block_offset += margins.block_start;
- container_builder_.AddResult(
- *caption_result,
- LogicalOffset(margins.inline_start, *table_block_offset));
- *table_block_offset += fragment.BlockSize() + margins.block_end;
+ captions.push_back(
+ CaptionResult{caption, std::move(caption_result), margins});
+ captions_block_size += fragment.BlockSize() + margins.BlockSum();
}
}
@@ -827,38 +711,60 @@ scoped_refptr<const NGLayoutResult> NGTableLayoutAlgorithm::GenerateFragment(
const NGTableTypes::Rows& rows,
const NGTableTypes::CellBlockConstraints& cell_block_constraints,
const NGTableTypes::Sections& sections,
+ const Vector<CaptionResult>& captions,
const NGTableBorders& table_borders,
const LogicalSize& border_spacing) {
const auto table_writing_direction = Style().GetWritingDirection();
- scoped_refptr<NGTableConstraintSpaceData> constraint_space_data =
+ scoped_refptr<const NGTableConstraintSpaceData> constraint_space_data =
CreateConstraintSpaceData(Style(), column_locations, sections, rows,
cell_block_constraints, table_inline_size,
border_spacing);
const NGBoxStrut border_padding = container_builder_.BorderPadding();
- LayoutUnit table_block_end;
+ LayoutUnit block_offset;
- // Top caption fragments.
- GenerateCaptionFragments(grouped_children, table_inline_size,
- ECaptionSide::kTop, &table_block_end);
+ auto AddCaptionResult = [&](const auto& caption,
+ LayoutUnit* block_offset) -> void {
+ NGBlockNode node = caption.node;
+ node.StoreMargins(
+ caption.margins.ConvertToPhysical(table_writing_direction));
+
+ *block_offset += caption.margins.block_start;
+ container_builder_.AddResult(
+ *caption.layout_result,
+ LogicalOffset(caption.margins.inline_start, *block_offset));
+
+ *block_offset += NGFragment(table_writing_direction,
+ caption.layout_result->PhysicalFragment())
+ .BlockSize() +
+ caption.margins.block_end;
+ };
+
+ // Add all the top captions.
+ for (const auto& caption : captions) {
+ if (caption.node.Style().CaptionSide() == ECaptionSide::kTop)
+ AddCaptionResult(caption, &block_offset);
+ }
// Section setup.
- const LogicalSize section_available_size{table_inline_size -
- border_padding.InlineSum() -
- border_spacing.inline_size * 2,
- kIndefiniteSize};
- DCHECK_GE(section_available_size.inline_size, LayoutUnit());
+ const LayoutUnit section_available_inline_size =
+ (table_inline_size - border_padding.InlineSum() -
+ border_spacing.inline_size * 2)
+ .ClampNegativeToZero();
+
auto CreateSectionConstraintSpace = [&table_writing_direction,
- &section_available_size,
- &constraint_space_data](
- wtf_size_t section_index) {
+ &section_available_inline_size,
+ &constraint_space_data,
+ &sections](wtf_size_t section_index) {
NGConstraintSpaceBuilder section_space_builder(
table_writing_direction.GetWritingMode(), table_writing_direction,
/* is_new_fc */ true);
- section_space_builder.SetAvailableSize(section_available_size);
+ section_space_builder.SetAvailableSize(
+ {section_available_inline_size, sections[section_index].block_size});
section_space_builder.SetIsFixedInlineSize(true);
- section_space_builder.SetPercentageResolutionSize(section_available_size);
- section_space_builder.SetNeedsBaseline(true);
+ section_space_builder.SetIsFixedBlockSize(true);
+ section_space_builder.SetPercentageResolutionSize(
+ {section_available_inline_size, kIndefiniteSize});
section_space_builder.SetTableSectionData(constraint_space_data,
section_index);
return section_space_builder.ToConstraintSpace();
@@ -868,50 +774,56 @@ scoped_refptr<const NGLayoutResult> NGTableLayoutAlgorithm::GenerateFragment(
LogicalOffset section_offset;
section_offset.inline_offset =
border_padding.inline_start + border_spacing.inline_size;
- section_offset.block_offset = table_block_end + border_padding.block_start;
+ section_offset.block_offset = block_offset + border_padding.block_start;
base::Optional<LayoutUnit> table_baseline;
wtf_size_t section_index = 0;
- bool has_section = false;
+ bool needs_end_border_spacing = false;
for (NGBlockNode section : grouped_children) {
scoped_refptr<const NGLayoutResult> section_result =
section.Layout(CreateSectionConstraintSpace(section_index++));
const NGPhysicalBoxFragment& physical_fragment =
To<NGPhysicalBoxFragment>(section_result->PhysicalFragment());
NGBoxFragment fragment(table_writing_direction, physical_fragment);
- if (fragment.BlockSize() != LayoutUnit() || !has_section)
+ if (fragment.HasDescendantsForTablePart()) {
section_offset.block_offset += border_spacing.block_size;
+ needs_end_border_spacing = true;
+ }
container_builder_.AddResult(*section_result, section_offset);
if (!table_baseline) {
if (const auto& section_baseline = fragment.Baseline())
table_baseline = *section_baseline + section_offset.block_offset;
}
section_offset.block_offset += fragment.BlockSize();
- has_section = true;
}
- if (has_section)
+ if (needs_end_border_spacing)
section_offset.block_offset += border_spacing.block_size;
LayoutUnit column_block_size =
section_offset.block_offset - border_padding.block_start;
- if (has_section)
+ if (needs_end_border_spacing)
column_block_size -= border_spacing.block_size * 2;
- LayoutUnit grid_block_size = std::max(
- section_offset.block_offset - table_block_end + border_padding.block_end,
- minimal_table_grid_block_size);
- LogicalRect table_grid_rect(LayoutUnit(), table_block_end,
- container_builder_.InlineSize(), grid_block_size);
- table_block_end += grid_block_size;
- GenerateCaptionFragments(grouped_children, table_inline_size,
- ECaptionSide::kBottom, &table_block_end);
+ const LayoutUnit grid_block_size = std::max(
+ section_offset.block_offset - block_offset + border_padding.block_end,
+ minimal_table_grid_block_size);
+ const LogicalRect table_grid_rect(LayoutUnit(), block_offset,
+ container_builder_.InlineSize(),
+ grid_block_size);
+ block_offset += grid_block_size;
+
+ // Add all the bottom captions.
+ for (const auto& caption : captions) {
+ if (caption.node.Style().CaptionSide() == ECaptionSide::kBottom)
+ AddCaptionResult(caption, &block_offset);
+ }
if (ConstraintSpace().IsFixedBlockSize()) {
container_builder_.SetFragmentBlockSize(
ConstraintSpace().AvailableSize().block_size);
} else {
- container_builder_.SetFragmentBlockSize(table_block_end);
+ container_builder_.SetFragmentBlockSize(block_offset);
}
- container_builder_.SetIntrinsicBlockSize(table_block_end);
+ container_builder_.SetIntrinsicBlockSize(block_offset);
const WritingModeConverter grid_converter(
Style().GetWritingDirection(),
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.h
index 60682fd159e..a525aeb7c83 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.h
@@ -38,16 +38,26 @@ class CORE_EXPORT NGTableLayoutAlgorithm
const NGTableBorders& table_borders,
const LogicalSize& border_spacing,
const NGBoxStrut& table_border_padding,
+ const LayoutUnit captions_block_size,
bool is_fixed_layout,
NGTableTypes::Rows* rows,
NGTableTypes::CellBlockConstraints* cell_block_constraints,
NGTableTypes::Sections* sections,
LayoutUnit* minimal_table_grid_block_size);
- void GenerateCaptionFragments(const NGTableGroupedChildren& grouped_children,
- LayoutUnit table_inline_size,
- ECaptionSide caption_side,
- LayoutUnit* table_block_offset);
+ // In order to correctly determine the available block-size given to the
+ // table-grid, we need to layout all the captions ahead of time. This struct
+ // stores the necessary information to add them to the fragment later.
+ struct CaptionResult {
+ NGBlockNode node;
+ scoped_refptr<const NGLayoutResult> layout_result;
+ const NGBoxStrut margins;
+ };
+
+ void ComputeCaptionFragments(const NGTableGroupedChildren& grouped_children,
+ LayoutUnit table_inline_size,
+ Vector<CaptionResult>& captions,
+ LayoutUnit& captions_block_size);
void ComputeTableSpecificFragmentData(
const NGTableGroupedChildren& grouped_children,
@@ -66,6 +76,7 @@ class CORE_EXPORT NGTableLayoutAlgorithm
const NGTableTypes::Rows& rows,
const NGTableTypes::CellBlockConstraints& cell_block_constraints,
const NGTableTypes::Sections& sections,
+ const Vector<CaptionResult>& captions,
const NGTableBorders& table_borders,
const LogicalSize& border_spacing);
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
index e1f6ceb2d0f..d7e735e271a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/table/ng_table_node.h"
namespace blink {
@@ -21,7 +22,6 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
unsigned percent_columns_count = 0;
unsigned fixed_columns_count = 0;
unsigned auto_columns_count = 0;
-
// What guesses mean is described in table specification.
// https://www.w3.org/TR/css-tables-3/#width-distribution-algorithm
enum { kMinGuess, kPercentageGuess, kSpecifiedGuess, kMaxGuess, kAboveMax };
@@ -37,7 +37,10 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
all_columns_count++;
DCHECK(column->min_inline_size);
DCHECK(column->max_inline_size);
- if (column->percent) {
+
+ if (column->is_mergeable) {
+ ; // Mergeable columns are ignored.
+ } else if (column->percent) {
percent_columns_count++;
total_percent += *column->percent;
LayoutUnit percent_inline_size =
@@ -91,6 +94,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
*computed_size = column->min_inline_size.value_or(LayoutUnit());
}
} break;
@@ -105,6 +110,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* last_computed_size = nullptr;
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
if (column->percent) {
last_computed_size = computed_size;
LayoutUnit percent_inline_size =
@@ -143,6 +150,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
if (column->percent) {
*computed_size = column->ResolvePercentInlineSize(target_inline_size);
} else if (column->is_constrained) {
@@ -189,6 +198,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
if (column->percent) {
*computed_size = column->ResolvePercentInlineSize(target_inline_size);
} else if (column->is_constrained || is_exact_match) {
@@ -225,6 +236,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
if (column->percent) {
*computed_size =
column->ResolvePercentInlineSize(target_inline_size);
@@ -255,6 +268,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
if (column->percent) {
*computed_size =
column->ResolvePercentInlineSize(target_inline_size);
@@ -285,6 +300,8 @@ Vector<LayoutUnit> DistributeInlineSizeToComputedInlineSizeAuto(
LayoutUnit* computed_size = computed_sizes.begin();
for (const NGTableTypes::Column* column = start_column;
column != end_column; ++column, ++computed_size) {
+ if (column->is_mergeable)
+ continue;
DCHECK(column->percent);
last_computed_size = computed_size;
if (total_percent > 0.0f) {
@@ -446,18 +463,32 @@ void DistributeColspanCellToColumnsFixed(
NGTableTypes::Column* end_column = start_column + colspan_cell.span;
DCHECK_NE(start_column, end_column);
+ // Inline sizes for redistribution exclude border spacing.
+ LayoutUnit total_inner_border_spacing;
+ unsigned effective_span = 0;
+ bool is_first_column = true;
+ for (NGTableTypes::Column* column = start_column; column != end_column;
+ ++column) {
+ if (column->is_mergeable)
+ continue;
+ ++effective_span;
+ if (!is_first_column)
+ total_inner_border_spacing += inline_border_spacing;
+ else
+ is_first_column = false;
+ }
LayoutUnit colspan_cell_min_inline_size;
LayoutUnit colspan_cell_max_inline_size;
// Colspanned cells only distribute min inline size if constrained.
if (colspan_cell.cell_inline_constraint.is_constrained) {
colspan_cell_min_inline_size =
(colspan_cell.cell_inline_constraint.min_inline_size -
- (colspan_cell.span - 1) * inline_border_spacing)
+ total_inner_border_spacing)
.ClampNegativeToZero();
}
colspan_cell_max_inline_size =
(colspan_cell.cell_inline_constraint.max_inline_size -
- (colspan_cell.span - 1) * inline_border_spacing)
+ total_inner_border_spacing)
.ClampNegativeToZero();
// Distribute min/max/percentage evenly between all cells.
@@ -467,18 +498,19 @@ void DistributeColspanCellToColumnsFixed(
colspan_cell.cell_inline_constraint.percent.value_or(0.0f);
LayoutUnit new_min_size = LayoutUnit(colspan_cell_min_inline_size /
- static_cast<float>(colspan_cell.span));
+ static_cast<float>(effective_span));
LayoutUnit new_max_size = LayoutUnit(colspan_cell_max_inline_size /
- static_cast<float>(colspan_cell.span));
+ static_cast<float>(effective_span));
base::Optional<float> new_percent;
if (colspan_cell.cell_inline_constraint.percent) {
- new_percent =
- *colspan_cell.cell_inline_constraint.percent / colspan_cell.span;
+ new_percent = *colspan_cell.cell_inline_constraint.percent / effective_span;
}
NGTableTypes::Column* last_column;
for (NGTableTypes::Column* column = start_column; column < end_column;
++column) {
+ if (column->is_mergeable)
+ continue;
last_column = column;
rounding_error_min_inline_size -= new_min_size;
rounding_error_max_inline_size -= new_max_size;
@@ -520,13 +552,25 @@ void DistributeColspanCellToColumnsAuto(
NGTableTypes::Column* end_column = start_column + effective_span;
// Inline sizes for redistribution exclude border spacing.
+ LayoutUnit total_inner_border_spacing;
+ bool is_first_column = true;
+ for (NGTableTypes::Column* column = start_column; column != end_column;
+ ++column) {
+ if (!column->is_mergeable) {
+ if (!is_first_column)
+ total_inner_border_spacing += inline_border_spacing;
+ else
+ is_first_column = false;
+ }
+ }
+
LayoutUnit colspan_cell_min_inline_size =
(colspan_cell.cell_inline_constraint.min_inline_size -
- (effective_span - 1) * inline_border_spacing)
+ total_inner_border_spacing)
.ClampNegativeToZero();
LayoutUnit colspan_cell_max_inline_size =
(colspan_cell.cell_inline_constraint.max_inline_size -
- (effective_span - 1) * inline_border_spacing)
+ total_inner_border_spacing)
.ClampNegativeToZero();
base::Optional<float> colspan_cell_percent =
colspan_cell.cell_inline_constraint.percent;
@@ -543,6 +587,8 @@ void DistributeColspanCellToColumnsAuto(
column->max_inline_size = LayoutUnit();
if (!column->min_inline_size)
column->min_inline_size = LayoutUnit();
+ if (column->is_mergeable)
+ continue;
all_columns_count++;
if (column->percent) {
percent_columns_count++;
@@ -558,7 +604,7 @@ void DistributeColspanCellToColumnsAuto(
// max_inline_size.
for (NGTableTypes::Column* column = start_column; column != end_column;
++column) {
- if (column->percent)
+ if (column->percent || column->is_mergeable)
continue;
float column_percent;
if (nonpercent_columns_max_inline_size != LayoutUnit()) {
@@ -608,6 +654,10 @@ void DistributeColspanCellToColumnsAuto(
}
}
+// Handles distribution of excess block size from: table, sections,
+// rows, and rowspanned cells, to rows.
+// Rowspanned cells distribute with slight differences from
+// general distribution algorithm.
void DistributeExcessBlockSizeToRows(
const wtf_size_t start_row_index,
const wtf_size_t row_count,
@@ -627,7 +677,7 @@ void DistributeExcessBlockSizeToRows(
std::next(rows->begin(), start_row_index + row_count);
auto RowBlockSizeDeficit = [&percentage_resolution_block_size](
- NGTableTypes::Row* row) {
+ const NGTableTypes::Row* row) {
if (percentage_resolution_block_size == kIndefiniteSize)
return LayoutUnit();
DCHECK(row->percent);
@@ -637,7 +687,7 @@ void DistributeExcessBlockSizeToRows(
};
auto IsUnconstrainedNonEmptyRow =
- [&percentage_resolution_block_size](NGTableTypes::Row* row) {
+ [&percentage_resolution_block_size](const NGTableTypes::Row* row) {
if (row->block_size == LayoutUnit())
return false;
if (row->percent && percentage_resolution_block_size == kIndefiniteSize)
@@ -646,17 +696,24 @@ void DistributeExcessBlockSizeToRows(
};
auto IsRowWithOriginatingRowspan =
- [&start_row, &desired_block_size_is_rowspan](NGTableTypes::Row* row) {
+ [&start_row,
+ &desired_block_size_is_rowspan](const NGTableTypes::Row* row) {
// Rowspans are treated specially only during rowspan distribution.
return desired_block_size_is_rowspan && row != start_row &&
row->has_rowspan_start;
};
+ auto IsEmptyRow = [](const NGTableTypes::Row* row) {
+ return row->block_size == LayoutUnit() &&
+ (!row->percent || *row->percent == 0);
+ };
+
unsigned percent_rows_with_deficit_count = 0;
unsigned rows_with_originating_rowspan = 0;
unsigned unconstrained_non_empty_row_count = 0;
unsigned constrained_non_empty_row_count = 0;
unsigned empty_row_count = 0;
+ unsigned unconstrained_empty_row_count = 0;
LayoutUnit total_block_size;
LayoutUnit percentage_block_size_deficit;
@@ -677,11 +734,14 @@ void DistributeExcessBlockSizeToRows(
if (IsUnconstrainedNonEmptyRow(row)) {
unconstrained_non_empty_row_count++;
unconstrained_non_empty_row_block_size += row->block_size;
- } else if (row->is_constrained && row->block_size != LayoutUnit()) {
+ } else if (row->is_constrained && !IsEmptyRow(row)) {
constrained_non_empty_row_count++;
}
- if (row->block_size == LayoutUnit())
+ if (IsEmptyRow(row)) {
empty_row_count++;
+ if (!row->is_constrained)
+ unconstrained_empty_row_count++;
+ }
}
LayoutUnit distributable_block_size =
@@ -753,14 +813,14 @@ void DistributeExcessBlockSizeToRows(
}
// Step 4: Empty row distribution
- // Table distributes evenly between all rows.
- // If there are any empty rows except start row, last row takes all the
- // excess block size.
+ // At this point all rows are empty and/or constrained.
if (empty_row_count > 0) {
if (desired_block_size_is_rowspan) {
NGTableTypes::Row* last_row = nullptr;
NGTableTypes::Row* row = start_row;
- if (empty_row_count != row_count) // skip initial row.
+ // Rowspan distribution skips initial empty row if possible,
+ // and distributes everything to the last empty row.
+ if (empty_row_count != row_count)
++row;
for (; row != end_row; ++row) {
if (row->block_size != LayoutUnit())
@@ -774,23 +834,29 @@ void DistributeExcessBlockSizeToRows(
} else if (empty_row_count == row_count ||
(empty_row_count + constrained_non_empty_row_count ==
row_count)) {
- // Grow empty rows if one of these is true:
+ // Grow empty rows if either of these is true:
// - all rows are empty.
// - non-empty rows are all constrained.
- // Different browsers disagree on when to grow empty rows.
- NGTableTypes::Row* last_row;
+ NGTableTypes::Row* last_row = nullptr;
LayoutUnit remaining_deficit = distributable_block_size;
+ // If there are constrained and unconstrained empty rows,
+ // only unconstrained rows grow.
+ bool grow_only_unconstrained = unconstrained_empty_row_count > 0;
+ unsigned growing_rows_count = grow_only_unconstrained
+ ? unconstrained_empty_row_count
+ : empty_row_count;
for (NGTableTypes::Row* row = start_row; row != end_row; ++row) {
if (row->block_size != LayoutUnit())
continue;
+ if (grow_only_unconstrained && row->is_constrained)
+ continue;
last_row = row;
- // Table block size distributes equally, while rowspan distributes to
- // last row.
LayoutUnit delta =
- LayoutUnit(distributable_block_size.ToFloat() / empty_row_count);
+ LayoutUnit(distributable_block_size.ToFloat() / growing_rows_count);
row->block_size = delta;
remaining_deficit -= delta;
}
+ DCHECK(last_row);
last_row->block_size += remaining_deficit;
return;
}
@@ -816,12 +882,13 @@ void DistributeExcessBlockSizeToRows(
} // namespace
MinMaxSizes NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ const NGTableNode& node,
const NGTableTypes::Columns& column_constraints,
LayoutUnit undistributable_space,
bool is_fixed_layout,
- bool containing_block_expects_minmax_without_percentages,
+ bool is_layout_pass,
bool skip_collapsed_columns) {
- MinMaxSizes minmax;
+ MinMaxSizes min_max;
// https://www.w3.org/TR/css-tables-3/#computing-the-table-width
// Compute standard GRID_MIN/GRID_MAX. They are sum of column_constraints.
//
@@ -840,9 +907,9 @@ MinMaxSizes NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
// T% * MINSUM + M = MINSUM.
// Minimum total size estimate based on column's min_inline_size and percent.
- LayoutUnit percent_maxsize_estimate;
+ LayoutUnit percent_max_size_estimate;
// Sum of max_inline_sizes of non-percentage columns.
- LayoutUnit non_percent_maxsize_sum;
+ LayoutUnit non_percent_max_size_sum;
float percent_sum = 0;
for (const NGTableTypes::Column& column : column_constraints.data) {
if (skip_collapsed_columns && column.is_collapsed)
@@ -851,50 +918,49 @@ MinMaxSizes NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
// In fixed layout, constrained cells minimum inline size is their
// maximum.
if (is_fixed_layout && column.IsFixed()) {
- minmax.min_size += *column.max_inline_size;
+ min_max.min_size += *column.max_inline_size;
} else {
- minmax.min_size += *column.min_inline_size;
+ min_max.min_size += *column.min_inline_size;
}
- if (column.percent) {
- if (*column.max_inline_size > LayoutUnit() && *column.percent > 0) {
+ if (column.percent && *column.percent > 0) {
+ if (*column.max_inline_size > LayoutUnit()) {
LayoutUnit estimate = LayoutUnit(
100 / *column.percent *
(*column.max_inline_size - column.percent_border_padding));
- percent_maxsize_estimate =
- std::max(percent_maxsize_estimate, estimate);
+ percent_max_size_estimate =
+ std::max(percent_max_size_estimate, estimate);
}
} else {
- non_percent_maxsize_sum += *column.max_inline_size;
+ non_percent_max_size_sum += *column.max_inline_size;
}
}
if (column.max_inline_size)
- minmax.max_size += *column.max_inline_size;
+ min_max.max_size += *column.max_inline_size;
if (column.percent)
percent_sum += *column.percent;
}
DCHECK_LE(percent_sum, 100.0f);
- // Table max inline size constraint can be computed from:
- // total column percentage combined with max_inline_size of nonpercent
- // columns.
- if (percent_sum > 0 && !containing_block_expects_minmax_without_percentages) {
+ // Table max inline size constraint can be computed from the total column
+ // percentage combined with max_inline_size of non-percent columns.
+ if (percent_sum > 0 && node.AllowColumnPercentages(is_layout_pass)) {
LayoutUnit size_from_percent_and_fixed;
DCHECK_GE(percent_sum, 0.0f);
- if (non_percent_maxsize_sum != LayoutUnit()) {
+ if (non_percent_max_size_sum != LayoutUnit()) {
if (percent_sum == 100.0f) {
size_from_percent_and_fixed = NGTableTypes::kTableMaxInlineSize;
} else {
size_from_percent_and_fixed =
- LayoutUnit((100 / (100 - percent_sum)) * non_percent_maxsize_sum);
+ LayoutUnit((100 / (100 - percent_sum)) * non_percent_max_size_sum);
}
}
- minmax.max_size = std::max(minmax.max_size, size_from_percent_and_fixed);
- minmax.max_size = std::max(minmax.max_size, percent_maxsize_estimate);
+ min_max.max_size = std::max(min_max.max_size, size_from_percent_and_fixed);
+ min_max.max_size = std::max(min_max.max_size, percent_max_size_estimate);
}
- minmax.max_size = std::max(minmax.min_size, minmax.max_size);
- minmax += undistributable_space;
- return minmax;
+ min_max.max_size = std::max(min_max.min_size, min_max.max_size);
+ min_max += undistributable_space;
+ return min_max;
}
void NGTableAlgorithmHelpers::DistributeColspanCellsToColumns(
@@ -1101,7 +1167,7 @@ void NGTableAlgorithmHelpers::DistributeTableBlockSizeToSections(
group_index = 0;
LayoutUnit remaining_deficit = excess_block_size;
- NGTableTypes::Section* last_section;
+ NGTableTypes::Section* last_section = nullptr;
for (NGTableTypes::Section& section : *sections) {
if (group_index == 2 && !is_group_2(section))
continue;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h
index cf41e4a5f61..1213933e849 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h
@@ -10,6 +10,8 @@
namespace blink {
+class NGTableNode;
+
// Table size distribution algorithms.
class CORE_EXPORT NGTableAlgorithmHelpers {
public:
@@ -24,17 +26,14 @@ class CORE_EXPORT NGTableAlgorithmHelpers {
return current_column + 1;
}
- // Flex/grid containing blocks need Table minmax size to be computed without
- // using percentages.
- // |containing_block_expects_minmax_without_percentages| is used to do
- // this.
// |undistributable_space| is size of space not occupied by cells
// (borders, border spacing).
static MinMaxSizes ComputeGridInlineMinMax(
+ const NGTableNode& node,
const NGTableTypes::Columns& column_constraints,
LayoutUnit undistributable_space,
bool is_fixed_layout,
- bool containing_block_expects_minmax_without_percentages,
+ bool is_layout_pass,
bool skip_collapsed_columns);
static void DistributeColspanCellsToColumns(
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc
index 117d5a2ad3a..cc9c95a178b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc
@@ -5,12 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/ng/table/ng_table_node.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
-class NGTableAlgorithmHelpersTest : public testing::Test {
- void SetUp() override {}
-
+class NGTableAlgorithmHelpersTest : public RenderingTest {
public:
NGTableTypes::Column MakeColumn(int min_width,
int max_width,
@@ -21,7 +21,9 @@ class NGTableAlgorithmHelpersTest : public testing::Test {
percent,
/* border_padding */ LayoutUnit(),
is_constrained,
- /* is_collapsed */ false};
+ /* is_collapsed */ false,
+ /* is_table_fixed */ false,
+ /* is_mergeable */ false};
}
NGTableTypes::Row MakeRow(int block_size,
@@ -155,16 +157,16 @@ TEST_F(NGTableAlgorithmHelpersTest, DistributeColspanAutoExactMaxSize) {
column_constraints->data.Shrink(0);
column_constraints->data.push_back(
NGTableTypes::Column{LayoutUnit(0), column_widths[0], base::nullopt,
- LayoutUnit(), false, false});
+ LayoutUnit(), false, false, false, false});
column_constraints->data.push_back(
NGTableTypes::Column{LayoutUnit(3.33333), column_widths[1], base::nullopt,
- LayoutUnit(), false, false});
+ LayoutUnit(), false, false, false, false});
column_constraints->data.push_back(
NGTableTypes::Column{LayoutUnit(3.33333), column_widths[2], base::nullopt,
- LayoutUnit(), false, false});
+ LayoutUnit(), false, false, false, false});
column_constraints->data.push_back(
NGTableTypes::Column{LayoutUnit(0), column_widths[3], base::nullopt,
- LayoutUnit(), false, false});
+ LayoutUnit(), false, false, false, false});
LayoutUnit assignable_table_inline_size =
column_widths[0] + column_widths[1] + column_widths[2] + column_widths[3];
@@ -178,13 +180,20 @@ TEST_F(NGTableAlgorithmHelpersTest, DistributeColspanAutoExactMaxSize) {
EXPECT_EQ(column_sizes[3], column_widths[3]);
}
-TEST_F(NGTableAlgorithmHelpersTest, ComputeGridInlineMinmax) {
+TEST_F(NGTableAlgorithmHelpersTest, ComputeGridInlineMinMax) {
+ SetBodyInnerHTML(R"HTML(
+ <div style="display: flex;">
+ <table id=target></table>
+ <div>
+ )HTML");
+ NGTableNode node(To<LayoutBox>(GetLayoutObjectByElementId("target")));
+
scoped_refptr<NGTableTypes::Columns> column_constraints =
base::MakeRefCounted<NGTableTypes::Columns>();
LayoutUnit undistributable_space;
bool is_fixed_layout = false;
- bool containing_block_expects_minmax_without_percentages = false;
+ bool is_layout_pass = true;
bool skip_collapsed_columns = false;
// No percentages, just sums up min/max.
@@ -192,10 +201,9 @@ TEST_F(NGTableAlgorithmHelpersTest, ComputeGridInlineMinmax) {
column_constraints->data.push_back(MakeColumn(20, 200));
column_constraints->data.push_back(MakeColumn(30, 300));
- MinMaxSizes minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinmax(
- *column_constraints, undistributable_space, is_fixed_layout,
- containing_block_expects_minmax_without_percentages,
- skip_collapsed_columns);
+ MinMaxSizes minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ node, *column_constraints, undistributable_space, is_fixed_layout,
+ is_layout_pass, skip_collapsed_columns);
EXPECT_EQ(minmax.min_size, LayoutUnit(60));
EXPECT_EQ(minmax.max_size, LayoutUnit(600));
@@ -205,33 +213,29 @@ TEST_F(NGTableAlgorithmHelpersTest, ComputeGridInlineMinmax) {
column_constraints->data.push_back(MakeColumn(10, 99, 10));
column_constraints->data.push_back(MakeColumn(10, 10));
column_constraints->data.push_back(MakeColumn(10, 10));
- minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinmax(
- *column_constraints, undistributable_space, is_fixed_layout,
- containing_block_expects_minmax_without_percentages,
- skip_collapsed_columns);
+ minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ node, *column_constraints, undistributable_space, is_fixed_layout,
+ is_layout_pass, skip_collapsed_columns);
EXPECT_EQ(minmax.min_size, LayoutUnit(30));
EXPECT_EQ(minmax.max_size, LayoutUnit(990));
- // Without percent, minmax ignores percent
- containing_block_expects_minmax_without_percentages = true;
- minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinmax(
- *column_constraints, undistributable_space, is_fixed_layout,
- containing_block_expects_minmax_without_percentages,
- skip_collapsed_columns);
+ is_layout_pass = false;
+ minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ node, *column_constraints, undistributable_space, is_fixed_layout,
+ is_layout_pass, skip_collapsed_columns);
EXPECT_EQ(minmax.min_size, LayoutUnit(30));
EXPECT_EQ(minmax.max_size, LayoutUnit(119));
// Percentage: total percentage of 20%, and non-percent width of 800 =>
// table max size of 800 + (20% * 800/80%) = 1000
- containing_block_expects_minmax_without_percentages = false;
+ is_layout_pass = true;
column_constraints->data.Shrink(0);
column_constraints->data.push_back(MakeColumn(10, 100, 10));
column_constraints->data.push_back(MakeColumn(10, 10, 10));
column_constraints->data.push_back(MakeColumn(10, 800));
- minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinmax(
- *column_constraints, undistributable_space, is_fixed_layout,
- containing_block_expects_minmax_without_percentages,
- skip_collapsed_columns);
+ minmax = NGTableAlgorithmHelpers::ComputeGridInlineMinMax(
+ node, *column_constraints, undistributable_space, is_fixed_layout,
+ is_layout_pass, skip_collapsed_columns);
EXPECT_EQ(minmax.min_size, LayoutUnit(30));
EXPECT_EQ(minmax.max_size, LayoutUnit(1000));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc
index aea92d5ccbf..3c80c8775fa 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/geometry/calculation_value.h"
namespace blink {
@@ -51,8 +52,15 @@ inline void InlineSizesFromStyle(
if (*min_inline_size)
*max_inline_size = std::max(**min_inline_size, **max_inline_size);
}
- if (length.IsPercent())
+ if (length.IsPercent()) {
*percentage_inline_size = length.Percent();
+ } else if (length.IsCalculated() &&
+ !length.GetCalculationValue().IsExpression()) {
+ // crbug.com/1154376 Style engine should handle %+0px case automatically.
+ PixelsAndPercent pixels_and_percent = length.GetPixelsAndPercent();
+ if (pixels_and_percent.pixels == 0.0f)
+ *percentage_inline_size = pixels_and_percent.percent;
+ }
if (*percentage_inline_size && max_length.IsPercent()) {
*percentage_inline_size =
@@ -70,7 +78,8 @@ constexpr LayoutUnit NGTableTypes::kTableMaxInlineSize;
// "outer min-content and outer max-content widths for colgroups"
NGTableTypes::Column NGTableTypes::CreateColumn(
const ComputedStyle& style,
- base::Optional<LayoutUnit> default_inline_size) {
+ base::Optional<LayoutUnit> default_inline_size,
+ bool is_table_fixed) {
base::Optional<LayoutUnit> inline_size;
base::Optional<LayoutUnit> min_inline_size;
base::Optional<LayoutUnit> max_inline_size;
@@ -78,6 +87,7 @@ NGTableTypes::Column NGTableTypes::CreateColumn(
InlineSizesFromStyle(style, /* inline_border_padding */ LayoutUnit(),
/* is_parallel */ true, &inline_size, &min_inline_size,
&max_inline_size, &percentage_inline_size);
+ bool is_mergeable;
if (!inline_size)
inline_size = default_inline_size;
if (min_inline_size && inline_size)
@@ -86,12 +96,16 @@ NGTableTypes::Column NGTableTypes::CreateColumn(
if (percentage_inline_size && *percentage_inline_size == 0.0f)
percentage_inline_size.reset();
bool is_collapsed = style.Visibility() == EVisibility::kCollapse;
- return Column{min_inline_size.value_or(LayoutUnit()),
- inline_size,
+ if (is_table_fixed) {
+ is_mergeable = false;
+ } else {
+ is_mergeable = (inline_size.value_or(LayoutUnit()) == LayoutUnit()) &&
+ (percentage_inline_size.value_or(0.0f) == 0.0f);
+ }
+ return Column(min_inline_size.value_or(LayoutUnit()), inline_size,
percentage_inline_size,
- LayoutUnit() /* percent_border_padding */,
- is_constrained,
- is_collapsed};
+ LayoutUnit() /* percent_border_padding */, is_constrained,
+ is_collapsed, is_table_fixed, is_mergeable);
}
// Implements https://www.w3.org/TR/css-tables-3/#computing-cell-measures
@@ -134,8 +148,7 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint(
builder.SetOrthogonalFallbackInlineSize(
IsHorizontalWritingMode(table_writing_mode) ? icb_size.height
: icb_size.width);
-
- builder.SetIsShrinkToFit(style.LogicalWidth().IsAuto());
+ builder.SetAvailableSize({kIndefiniteSize, kIndefiniteSize});
}
NGConstraintSpace space = builder.ToConstraintSpace();
// It'd be nice to avoid computing minmax if not needed, but the criteria
@@ -199,7 +212,8 @@ NGTableTypes::Section NGTableTypes::CreateSection(
const NGLayoutInputNode& section,
wtf_size_t start_row,
wtf_size_t rows,
- LayoutUnit block_size) {
+ LayoutUnit block_size,
+ bool treat_as_tbody) {
const Length& section_css_block_size = section.Style().LogicalHeight();
// TODO(crbug.com/1105272): Decide what to do with |Length::IsCalculated()|.
bool is_constrained =
@@ -207,14 +221,12 @@ NGTableTypes::Section NGTableTypes::CreateSection(
base::Optional<float> percent;
if (section_css_block_size.IsPercent())
percent = section_css_block_size.Percent();
- bool is_tbody =
- section.GetDOMNode()->HasTagName(html_names::kTbodyTag);
return Section{start_row,
rows,
block_size,
percent,
is_constrained,
- is_tbody,
+ treat_as_tbody,
/* needs_redistribution */ false};
}
@@ -267,8 +279,6 @@ void NGTableTypes::CellInlineConstraint::Encompass(
max_inline_size = std::max(min_inline_size, other.max_inline_size);
}
is_constrained = is_constrained || other.is_constrained;
- max_inline_size = std::max(max_inline_size, other.max_inline_size);
- percent = std::max(percent, other.percent);
if (other.percent > percent) {
percent = other.percent;
percent_border_padding = other.percent_border_padding;
@@ -280,6 +290,11 @@ void NGTableTypes::Column::Encompass(
if (!cell)
return;
+ // Constrained columns in fixed tables take precedence over cells.
+ if (is_constrained && is_table_fixed)
+ return;
+ if (!is_table_fixed)
+ is_mergeable = false;
if (min_inline_size) {
if (min_inline_size < cell->min_inline_size) {
min_inline_size = cell->min_inline_size;
@@ -308,7 +323,8 @@ void NGTableTypes::Column::Encompass(
is_constrained |= cell->is_constrained;
}
-NGTableGroupedChildren::NGTableGroupedChildren(const NGBlockNode& table) {
+NGTableGroupedChildren::NGTableGroupedChildren(const NGBlockNode& table)
+ : header(NGBlockNode(nullptr)), footer(NGBlockNode(nullptr)) {
for (NGLayoutInputNode child = table.FirstChild(); child;
child = child.NextSibling()) {
NGBlockNode block_child = To<NGBlockNode>(child);
@@ -321,13 +337,19 @@ NGTableGroupedChildren::NGTableGroupedChildren(const NGBlockNode& table) {
columns.push_back(block_child);
break;
case EDisplay::kTableHeaderGroup:
- headers.push_back(block_child);
+ if (!header)
+ header = block_child;
+ else
+ bodies.push_back(block_child);
break;
case EDisplay::kTableRowGroup:
bodies.push_back(block_child);
break;
case EDisplay::kTableFooterGroup:
- footers.push_back(block_child);
+ if (!footer)
+ footer = block_child;
+ else
+ bodies.push_back(block_child);
break;
default:
NOTREACHED() << "unexpected table child";
@@ -347,30 +369,57 @@ NGTableGroupedChildrenIterator NGTableGroupedChildren::end() const {
NGTableGroupedChildrenIterator::NGTableGroupedChildrenIterator(
const NGTableGroupedChildren& grouped_children,
bool is_end)
- : grouped_children_(grouped_children), current_vector_(nullptr) {
+ : grouped_children_(grouped_children) {
if (is_end) {
- current_vector_ = &grouped_children_.footers;
- current_iterator_ = current_vector_->end();
+ current_section_ = kEnd;
return;
}
+ current_section_ = kNone;
AdvanceToNonEmptySection();
}
NGTableGroupedChildrenIterator& NGTableGroupedChildrenIterator::operator++() {
- ++current_iterator_;
- if (current_iterator_ == current_vector_->end())
- AdvanceToNonEmptySection();
+ switch (current_section_) {
+ case kHead:
+ case kFoot:
+ AdvanceToNonEmptySection();
+ break;
+ case kBody:
+ ++body_iterator_;
+ if (body_iterator_ == grouped_children_.bodies.end())
+ AdvanceToNonEmptySection();
+ break;
+ case kEnd:
+ break;
+ case kNone:
+ NOTREACHED();
+ break;
+ }
return *this;
}
NGBlockNode NGTableGroupedChildrenIterator::operator*() const {
- return *current_iterator_;
+ switch (current_section_) {
+ case kHead:
+ return grouped_children_.header;
+ case kFoot:
+ return grouped_children_.footer;
+ case kBody:
+ return *body_iterator_;
+ case kEnd:
+ case kNone:
+ NOTREACHED();
+ return NGBlockNode(nullptr);
+ }
}
bool NGTableGroupedChildrenIterator::operator==(
const NGTableGroupedChildrenIterator& rhs) const {
- return rhs.current_vector_ == current_vector_ &&
- rhs.current_iterator_ == current_iterator_;
+ if (current_section_ != rhs.current_section_)
+ return false;
+ if (current_section_ == kBody)
+ return rhs.body_iterator_ == body_iterator_;
+ return true;
}
bool NGTableGroupedChildrenIterator::operator!=(
@@ -379,19 +428,29 @@ bool NGTableGroupedChildrenIterator::operator!=(
}
void NGTableGroupedChildrenIterator::AdvanceToNonEmptySection() {
- if (current_vector_ == &grouped_children_.footers)
- return;
- if (!current_vector_) {
- current_vector_ = &grouped_children_.headers;
- } else if (current_vector_ == &grouped_children_.headers) {
- current_vector_ = &grouped_children_.bodies;
- } else if (current_vector_ == &grouped_children_.bodies) {
- current_vector_ = &grouped_children_.footers;
- }
- current_iterator_ = current_vector_->begin();
- // If new group is empty, recursively advance.
- if (current_iterator_ == current_vector_->end()) {
- AdvanceToNonEmptySection();
+ switch (current_section_) {
+ case kNone:
+ current_section_ = kHead;
+ if (!grouped_children_.header)
+ AdvanceToNonEmptySection();
+ break;
+ case kHead:
+ current_section_ = kBody;
+ body_iterator_ = grouped_children_.bodies.begin();
+ if (body_iterator_ == grouped_children_.bodies.end())
+ AdvanceToNonEmptySection();
+ break;
+ case kBody:
+ current_section_ = kFoot;
+ if (!grouped_children_.footer)
+ AdvanceToNonEmptySection();
+ break;
+ case kFoot:
+ current_section_ = kEnd;
+ break;
+ case kEnd:
+ NOTREACHED();
+ break;
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h
index e63d160801d..b892c3f2014 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h
@@ -9,6 +9,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -56,6 +57,23 @@ class CORE_EXPORT NGTableTypes {
// Constraint for a column.
struct Column {
DISALLOW_NEW();
+ Column(const base::Optional<LayoutUnit>& min_inline_size,
+ const base::Optional<LayoutUnit>& max_inline_size,
+ const base::Optional<float>& percent,
+ LayoutUnit percent_border_padding,
+ bool is_constrained,
+ bool is_collapsed,
+ bool is_table_fixed,
+ bool is_mergeable)
+ : min_inline_size(min_inline_size),
+ max_inline_size(max_inline_size),
+ percent(percent),
+ percent_border_padding(percent_border_padding),
+ is_constrained(is_constrained),
+ is_collapsed(is_collapsed),
+ is_table_fixed(is_table_fixed),
+ is_mergeable(is_mergeable) {}
+ Column() = default;
// These members are initialized from <col> and <colgroup>, then they
// accumulate data from |CellInlineConstraint|s.
base::Optional<LayoutUnit> min_inline_size;
@@ -66,6 +84,8 @@ class CORE_EXPORT NGTableTypes {
// True if any cell for this column is constrained.
bool is_constrained = false;
bool is_collapsed = false;
+ bool is_table_fixed = false;
+ bool is_mergeable = false;
void Encompass(const base::Optional<NGTableTypes::CellInlineConstraint>&);
LayoutUnit ResolvePercentInlineSize(
@@ -180,7 +200,8 @@ class CORE_EXPORT NGTableTypes {
};
static Column CreateColumn(const ComputedStyle&,
- base::Optional<LayoutUnit> default_inline_size);
+ base::Optional<LayoutUnit> default_inline_size,
+ bool is_table_fixed);
static CellInlineConstraint CreateCellInlineConstraint(
const NGBlockNode&,
@@ -193,7 +214,8 @@ class CORE_EXPORT NGTableTypes {
static Section CreateSection(const NGLayoutInputNode&,
wtf_size_t start_row,
wtf_size_t rowspan,
- LayoutUnit block_size);
+ LayoutUnit block_size,
+ bool treat_as_tbody);
static CellBlockConstraint CreateCellBlockConstraint(
const NGLayoutInputNode&,
@@ -237,9 +259,9 @@ struct NGTableGroupedChildren {
Vector<NGBlockNode> captions; // CAPTION
Vector<NGBlockNode> columns; // COLGROUP, COL
- Vector<NGBlockNode> headers; // THEAD
- Vector<NGBlockNode> bodies; // TBODY
- Vector<NGBlockNode> footers; // TFOOT
+ NGBlockNode header; // first THEAD
+ Vector<NGBlockNode> bodies; // TBODY/multiple THEAD/TFOOT
+ NGBlockNode footer; // first TFOOT
// Default iterators iterate over tbody-like (THEAD/TBODY/TFOOT) elements.
NGTableGroupedChildrenIterator begin() const;
@@ -249,6 +271,8 @@ struct NGTableGroupedChildren {
// Iterates table's sections in order:
// thead, tbody, tfoot
class NGTableGroupedChildrenIterator {
+ enum CurrentSection { kNone, kHead, kBody, kFoot, kEnd };
+
public:
explicit NGTableGroupedChildrenIterator(
const NGTableGroupedChildren& grouped_children,
@@ -258,12 +282,14 @@ class NGTableGroupedChildrenIterator {
NGBlockNode operator*() const;
bool operator==(const NGTableGroupedChildrenIterator& rhs) const;
bool operator!=(const NGTableGroupedChildrenIterator& rhs) const;
+ // True if section should be treated as tbody
+ bool TreatAsTBody() const { return current_section_ == kBody; }
private:
void AdvanceToNonEmptySection();
const NGTableGroupedChildren& grouped_children_;
- const Vector<NGBlockNode>* current_vector_;
- Vector<NGBlockNode>::const_iterator current_iterator_;
+ Vector<NGBlockNode>::const_iterator body_iterator_;
+ CurrentSection current_section_{kNone};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc
index ddf04a7f5aa..22a29c1b457 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc
@@ -24,6 +24,55 @@ namespace blink {
namespace {
+// Mergeable columns cannot be distributed to.
+// Make at least one spanned column is distributable.
+void EnsureDistributableColumnExists(
+ wtf_size_t start_column_index,
+ wtf_size_t span,
+ NGTableTypes::Columns* column_constraints) {
+ if (span == 0)
+ return;
+ DCHECK_LT(start_column_index, column_constraints->data.size());
+ wtf_size_t effective_span =
+ std::min(span, column_constraints->data.size() - start_column_index);
+ if (effective_span == 0)
+ return;
+ NGTableTypes::Column* start_column =
+ &column_constraints->data[start_column_index];
+ NGTableTypes::Column* end_column = start_column + effective_span;
+
+ NGTableTypes::Column* first_mergeable_column = nullptr;
+ for (NGTableTypes::Column* column = start_column; column != end_column;
+ ++column) {
+ if (!column->is_collapsed) {
+ if (!column->is_mergeable) {
+ // Found non-collapsed, non mergeable column, nothing to do.
+ return;
+ } else if (!first_mergeable_column) {
+ // Found first non-collapsed, mergeable column.
+ first_mergeable_column = column;
+ }
+ }
+ }
+ // The interesting problem being solved here is interaction between
+ // collapsed and mergeable columns.
+ // All columns that are created by colspanned cell are mergeable by
+ // default. Without collapsing, the first column would always be
+ // marked as !mergeable.
+ // What to do if the first column collapses? If that was the only
+ // non-mergeable column, the entire cell would merge into first column,
+ // and collapse.
+ // To prevent "whole cell hidden if 1st cell is collapsed",
+ // we try to make first non-collapsed column mergeable.
+ // If all columns collapse, first cell is marked as meargable.
+ if (first_mergeable_column) {
+ // Some columns were not collapsed, mark first as mergeable.
+ first_mergeable_column->is_mergeable = false;
+ } else {
+ start_column->is_mergeable = false;
+ }
+}
+
// Applies cell/wide cell constraints to columns.
// Guarantees columns min/max widths have non-empty values.
void ApplyCellConstraintsToColumnConstraints(
@@ -32,7 +81,37 @@ void ApplyCellConstraintsToColumnConstraints(
bool is_fixed_layout,
NGTableTypes::ColspanCells* colspan_cell_constraints,
NGTableTypes::Columns* column_constraints) {
- column_constraints->data.resize(cell_constraints.size());
+ // Satisfy prerequisites for cell merging:
+
+ if (column_constraints->data.size() < cell_constraints.size()) {
+ // Column constraint must exist for each cell.
+ NGTableTypes::Column default_column;
+ default_column.is_table_fixed = is_fixed_layout;
+ default_column.is_mergeable = !is_fixed_layout;
+ wtf_size_t column_count =
+ cell_constraints.size() - column_constraints->data.size();
+ // Must loop because WTF::Vector does not support resize with default value.
+ for (wtf_size_t i = 0; i < column_count; ++i)
+ column_constraints->data.push_back(default_column);
+ DCHECK_EQ(column_constraints->data.size(), cell_constraints.size());
+
+ } else if (column_constraints->data.size() > cell_constraints.size()) {
+ // Trim mergeable columns off the end.
+ wtf_size_t last_non_merged_column = column_constraints->data.size() - 1;
+ while (last_non_merged_column + 1 > cell_constraints.size() &&
+ column_constraints->data[last_non_merged_column].is_mergeable) {
+ --last_non_merged_column;
+ }
+ column_constraints->data.resize(last_non_merged_column + 1);
+ DCHECK_GE(column_constraints->data.size(), cell_constraints.size());
+ }
+ // Make sure there exists a non-mergeable column for each colspanned cell.
+ for (const NGTableTypes::ColspanCell& colspan_cell :
+ *colspan_cell_constraints) {
+ EnsureDistributableColumnExists(colspan_cell.start_column,
+ colspan_cell.span, column_constraints);
+ }
+
// Distribute cell constraints to column constraints.
for (wtf_size_t i = 0; i < cell_constraints.size(); ++i) {
column_constraints->data[i].Encompass(cell_constraints[i]);
@@ -52,14 +131,16 @@ void ApplyCellConstraintsToColumnConstraints(
*colspan_cell_constraints, inline_border_spacing, is_fixed_layout,
column_constraints);
- // Clamp column percentages. Standard: "100% minus the sum of the intrinsic
- // percentage width of all prior columns in the table."
+ // Column total percentage inline-size is clamped to 100%.
+ // Auto tables: max(0, 100% minus the sum of percentages of all
+ // prior columns in the table)
+ // Fixed tables: scale all percentage columns so that total percentage
+ // is 100%.
float total_percentage = 0;
for (NGTableTypes::Column& column : column_constraints->data) {
if (column.percent) {
- if (*column.percent + total_percentage > 100.0) {
+ if (!is_fixed_layout && (*column.percent + total_percentage > 100.0))
column.percent = 100 - total_percentage;
- }
total_percentage += *column.percent;
}
// A column may have no min/max inline-sizes if there are no cells in this
@@ -67,6 +148,13 @@ void ApplyCellConstraintsToColumnConstraints(
column.min_inline_size = column.min_inline_size.value_or(LayoutUnit());
column.max_inline_size = column.max_inline_size.value_or(LayoutUnit());
}
+
+ if (is_fixed_layout && total_percentage > 100.0) {
+ for (NGTableTypes::Column& column : column_constraints->data) {
+ if (column.percent)
+ column.percent = *column.percent * 100 / total_percentage;
+ }
+ }
}
NGTableTypes::Row ComputeMinimumRowBlockSize(
@@ -93,6 +181,7 @@ NGTableTypes::Row ComputeMinimumRowBlockSize(
wtf_size_t start_column_index,
const NGBoxStrut& cell_borders) {
const wtf_size_t start_column = start_column_index;
+ DCHECK_LT(start_column, column_locations.size());
const wtf_size_t end_column =
std::min(start_column + cell.TableCellColspan() - 1,
column_locations.size() - 1);
@@ -243,10 +332,12 @@ class ColumnConstraintsBuilder {
wtf_size_t span) {
// COL creates SPAN constraints. Its width is col css width, or enclosing
// colgroup css width.
- NGTableTypes::Column col_constraint = NGTableTypes::CreateColumn(
- column.Style(), !is_fixed_layout_ && colgroup_constraint_
- ? colgroup_constraint_->max_inline_size
- : base::nullopt);
+ NGTableTypes::Column col_constraint =
+ NGTableTypes::CreateColumn(column.Style(),
+ !is_fixed_layout_ && colgroup_constraint_
+ ? colgroup_constraint_->max_inline_size
+ : base::nullopt,
+ is_fixed_layout_);
for (wtf_size_t i = 0; i < span; ++i)
column_constraints_->data.push_back(col_constraint);
column.GetLayoutBox()->ClearNeedsLayout();
@@ -254,8 +345,8 @@ class ColumnConstraintsBuilder {
void EnterColgroup(const NGLayoutInputNode& colgroup,
wtf_size_t start_column_index) {
- colgroup_constraint_ =
- NGTableTypes::CreateColumn(colgroup.Style(), base::nullopt);
+ colgroup_constraint_ = NGTableTypes::CreateColumn(
+ colgroup.Style(), base::nullopt, is_fixed_layout_);
}
void LeaveColgroup(const NGLayoutInputNode& colgroup,
@@ -387,7 +478,6 @@ NGConstraintSpace NGTableAlgorithmUtils::CreateTableCellConstraintSpace(
builder.SetOrthogonalFallbackInlineSize(
table_writing_direction.IsHorizontal() ? icb_size.height
: icb_size.width);
- builder.SetIsShrinkToFit(cell.Style().LogicalWidth().IsAuto());
}
builder.SetAvailableSize(cell_size);
@@ -411,7 +501,6 @@ NGConstraintSpace NGTableAlgorithmUtils::CreateTableCellConstraintSpace(
builder.SetIsTableCellWithCollapsedBorders(has_collapsed_borders);
builder.SetHideTableCellIfEmpty(
!has_collapsed_borders && cell_style.EmptyCells() == EEmptyCells::kHide);
- builder.SetNeedsBaseline(true);
builder.SetCacheSlot(cache_slot);
return builder.ToConstraintSpace();
@@ -464,6 +553,7 @@ void NGTableAlgorithmUtils::ComputeSectionMinimumRowBlockSizes(
const NGTableBorders& table_borders,
const LayoutUnit block_border_spacing,
wtf_size_t section_index,
+ bool treat_section_as_tbody,
NGTableTypes::Sections* sections,
NGTableTypes::Rows* rows,
NGTableTypes::CellBlockConstraints* cell_block_constraints) {
@@ -527,8 +617,9 @@ void NGTableAlgorithmUtils::ComputeSectionMinimumRowBlockSizes(
section_block_size = section_fixed_block_size;
}
}
- sections->push_back(NGTableTypes::CreateSection(
- section, start_row, current_row - start_row, section_block_size));
+ sections->push_back(
+ NGTableTypes::CreateSection(section, start_row, current_row - start_row,
+ section_block_size, treat_section_as_tbody));
}
void NGColspanCellTabulator::StartRow() {
@@ -544,6 +635,11 @@ void NGColspanCellTabulator::EndRow() {
else
++i;
}
+ std::sort(colspanned_cells_.begin(), colspanned_cells_.end(),
+ [](const NGColspanCellTabulator::Cell& a,
+ const NGColspanCellTabulator::Cell& b) {
+ return a.column_start < b.column_start;
+ });
}
// Advance current column to position not occupied by colspanned cells.
@@ -570,7 +666,8 @@ void NGRowBaselineTabulator::ProcessCell(
const bool is_baseline_aligned,
const bool is_parallel,
const bool descendant_depends_on_percentage_block_size) {
- if (is_parallel && is_baseline_aligned) {
+ if (is_parallel && is_baseline_aligned &&
+ fragment.HasDescendantsForTablePart()) {
max_cell_baseline_depends_on_percentage_block_descendant_ |=
descendant_depends_on_percentage_block_size;
const LayoutUnit cell_baseline = fragment.FirstBaselineOrSynthesize();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h
index e1ea7fde64e..521845a4ab6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h
@@ -61,6 +61,7 @@ class NGTableAlgorithmUtils {
const NGTableBorders& table_borders,
const LayoutUnit block_border_spacing,
wtf_size_t section_index,
+ bool treat_section_as_tbody,
NGTableTypes::Sections* sections,
NGTableTypes::Rows* rows,
NGTableTypes::CellBlockConstraints* cell_block_constraints);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
index 18b8ccd5d2b..ed0458c9a52 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
@@ -46,4 +46,38 @@ LayoutUnit NGTableNode::ComputeTableInlineSize(
border_padding);
}
+bool NGTableNode::AllowColumnPercentages(bool is_layout_pass) const {
+ if (Style().LogicalWidth().IsMaxContent())
+ return false;
+ if (is_layout_pass)
+ return true;
+ // TODO(layout-dev): This function breaks the rule of "no tree-walks".
+ // However for this specific case it adds a lot of overhead for little gain.
+ // In the future, we could have a bit on a LayoutObject which indicates if we
+ // should allow column percentages, and maintain this when adding/removing
+ // from the tree.
+ const LayoutBlock* block = box_->ContainingBlock();
+ while (!block->IsLayoutView()) {
+ if (block->IsTableCell() || block->IsFlexibleBoxIncludingNG() ||
+ block->IsLayoutGridIncludingNG())
+ return false;
+
+ block = block->ContainingBlock();
+ }
+ return true;
+}
+
+// True if table's intrinsic max size can be infinite.
+// Infinite intrinsic sizes are ok inside block layout, but cannot work
+// inside flex and grid layouts.
+bool NGTableNode::AllowsInfiniteMaxInlineSize() const {
+ const LayoutBlock* block = box_->ContainingBlock();
+ while (!block->IsLayoutView()) {
+ if (block->IsFlexibleBoxIncludingNG() || block->IsLayoutGridIncludingNG())
+ return false;
+ block = block->ContainingBlock();
+ }
+ return true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
index 01a7eff7997..950263cfb67 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
@@ -27,6 +27,19 @@ class CORE_EXPORT NGTableNode final : public NGBlockNode {
LayoutUnit ComputeTableInlineSize(const NGConstraintSpace&,
const NGBoxStrut& border_padding) const;
+
+ // Tables are special in that their max intrinsic-size can be "infinite"
+ // (they should consume as much space as possible). However a lot of layout
+ // modes (flex/grid) don't deal well with "infinite" max intrinsic-size, so
+ // we disable this behaviour whenever we are an arbitrary descendant of one
+ // of these layout modes.
+ //
+ // TODO(layout-dev): This isn't ideal, as we may have a fixed inline-size
+ // parent where an "infinite" size would be fine.
+ bool AllowColumnPercentages(bool is_layout_pass) const;
+
+ // True if table's intrinsic max size can be infinite.
+ bool AllowsInfiniteMaxInlineSize() const;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
index f4ac3ec7608..4e294d227ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
@@ -50,12 +50,12 @@ scoped_refptr<const NGLayoutResult> NGTableSectionLayoutAlgorithm::Layout() {
table_data.table_writing_direction.GetWritingMode(),
table_data.table_writing_direction,
/* is_new_fc */ true);
- row_space_builder.SetAvailableSize(
- {container_builder_.InlineSize(), kIndefiniteSize});
+ row_space_builder.SetAvailableSize({container_builder_.InlineSize(),
+ table_data.rows[row_index].block_size});
row_space_builder.SetIsFixedInlineSize(true);
+ row_space_builder.SetIsFixedBlockSize(true);
row_space_builder.SetPercentageResolutionSize(
{container_builder_.InlineSize(), kIndefiniteSize});
- row_space_builder.SetNeedsBaseline(true);
row_space_builder.SetTableRowData(&table_data, row_index);
NGConstraintSpace row_space = row_space_builder.ToConstraintSpace();
scoped_refptr<const NGLayoutResult> row_result = row.Layout(row_space);
diff --git a/chromium/third_party/blink/renderer/core/layout/overflow_model.h b/chromium/third_party/blink/renderer/core/layout/overflow_model.h
index 5e700d36405..da33cc8696d 100644
--- a/chromium/third_party/blink/renderer/core/layout/overflow_model.h
+++ b/chromium/third_party/blink/renderer/core/layout/overflow_model.h
@@ -167,7 +167,6 @@ class BoxLayoutOverflowModel {
BoxLayoutOverflowModel& operator=(const BoxLayoutOverflowModel&) = delete;
const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; }
- void SetLayoutOverflow(const LayoutRect& rect) { layout_overflow_ = rect; }
void AddLayoutOverflow(const LayoutRect& rect) {
UniteLayoutOverflowRect(layout_overflow_, rect);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
index 330000ca8ce..0494502f815 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -577,11 +577,6 @@ void ScrollAnchor::Adjust() {
// This minimizes redundant calls to findAnchor.
// TODO(skobes): add UMA metric for this.
ClearSelf();
-
- DEFINE_STATIC_LOCAL(EnumerationHistogram, suppressed_by_sanaclap_histogram,
- ("Layout.ScrollAnchor.SuppressedBySanaclap", 2));
- suppressed_by_sanaclap_histogram.Count(1);
-
return;
}
@@ -589,10 +584,6 @@ void ScrollAnchor::Adjust() {
scroller_->GetScrollOffset() + FloatSize(adjustment),
mojom::blink::ScrollType::kAnchoring);
- // Update UMA metric.
- DEFINE_STATIC_LOCAL(EnumerationHistogram, adjusted_offset_histogram,
- ("Layout.ScrollAnchor.AdjustedScrollOffset", 2));
- adjusted_offset_histogram.Count(1);
UseCounter::Count(ScrollerLayoutBox(scroller_)->GetDocument(),
WebFeature::kScrollAnchored);
}
@@ -603,8 +594,6 @@ bool ScrollAnchor::RestoreAnchor(const SerializedAnchor& serialized_anchor) {
}
SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Layout.ScrollAnchor.TimeToRestoreAnchor");
- DEFINE_STATIC_LOCAL(EnumerationHistogram, restoration_status_histogram,
- ("Layout.ScrollAnchor.RestorationStatus", kStatusCount));
if (anchor_object_ && serialized_anchor.selector == saved_selector_) {
return true;
@@ -629,12 +618,10 @@ bool ScrollAnchor::RestoreAnchor(const SerializedAnchor& serialized_anchor) {
AtomicString(serialized_anchor.selector), exception_state);
if (exception_state.HadException()) {
- restoration_status_histogram.Count(kFailedBadSelector);
return false;
}
if (found_elements->length() < 1) {
- restoration_status_histogram.Count(kFailedNoMatches);
return false;
}
@@ -679,16 +666,22 @@ bool ScrollAnchor::RestoreAnchor(const SerializedAnchor& serialized_anchor) {
}
saved_selector_ = serialized_anchor.selector;
- restoration_status_histogram.Count(kSuccess);
-
return true;
}
- restoration_status_histogram.Count(kFailedNoValidMatches);
return false;
}
const SerializedAnchor ScrollAnchor::GetSerializedAnchor() {
+ if (auto* scroller_box = ScrollerLayoutBox(scroller_)) {
+ // This method may be called to find a serialized anchor on a document which
+ // needs a lifecycle update. Computing offsets below may currently compute
+ // style for ::first-line. If that is done with dirty active stylesheets, we
+ // may have null pointer crash as style computation assumes active sheets
+ // are up to date. Update active style if necessary here.
+ scroller_box->GetDocument().GetStyleEngine().UpdateActiveStyle();
+ }
+
// It's safe to return saved_selector_ before checking anchor_object_, since
// clearing anchor_object_ also clears saved_selector_.
if (!saved_selector_.IsEmpty()) {
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
index cabe85bba1f..7fdc92e1859 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
@@ -13,6 +13,7 @@
namespace blink {
class LayoutObject;
+class Node;
class ScrollableArea;
static const int kMaxSerializedSelectorLength = 500;
@@ -82,16 +83,6 @@ class CORE_EXPORT ScrollAnchor final {
// Only meaningful if anchorObject() is non-null.
Corner GetCorner() const { return corner_; }
- // This enum must remain in sync with the corresponding enum in enums.xml.
- enum RestorationStatus {
- kSuccess = 0,
- kFailedNoMatches,
- kFailedNoValidMatches,
- kFailedBadSelector,
- kStatusCount // Special value used to count the number of enum values; not
- // to be used as an actual status. Add new values above.
- };
-
// Attempt to restore |serialized_anchor| by scrolling to the element
// identified by its selector, adjusting by its relative_offset.
bool RestoreAnchor(const SerializedAnchor&);
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index 0be2891eb94..85e852dc020 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/scroll_anchor.h"
+#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
@@ -19,7 +20,6 @@
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -141,7 +141,7 @@ INSTANTIATE_TEST_SUITE_P(All, ScrollAnchorTest, testing::Bool());
// TODO(ymalik): Currently, this should be the first test in the file to avoid
// failure when running with other tests. Dig into this more and fix.
TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
- HistogramTester histogram_tester;
+ base::HistogramTester histogram_tester;
SetBodyInnerHTML(R"HTML(
<style> body { height: 1000px } div { height: 100px } </style>
<div id='block1'>abc</div>
@@ -153,15 +153,10 @@ TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
// Scroll position not adjusted, metric not updated.
ScrollLayoutViewport(ScrollOffset(0, 150));
- histogram_tester.ExpectTotalCount("Layout.ScrollAnchor.AdjustedScrollOffset",
- 0);
histogram_tester.ExpectTotalCount(
"Layout.ScrollAnchor.TimeToComputeAnchorNodeSelector", 0);
- // Height changed, verify metric updated once.
SetHeight(GetDocument().getElementById("block1"), 200);
- histogram_tester.ExpectUniqueSample(
- "Layout.ScrollAnchor.AdjustedScrollOffset", 1, 1);
EXPECT_EQ(250, viewport->ScrollOffsetInt().Height());
EXPECT_EQ(GetDocument().getElementById("block2")->GetLayoutObject(),
@@ -180,18 +175,10 @@ TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
SerializedAnchor bad_anchor("##foobar", LayoutPoint(0, 0));
EXPECT_FALSE(GetScrollAnchor(LayoutViewport()).RestoreAnchor(bad_anchor));
- histogram_tester.ExpectBucketCount("Layout.ScrollAnchor.RestorationStatus",
- ScrollAnchor::kFailedBadSelector, 1);
-
SerializedAnchor bad_anchor2("#bl", LayoutPoint(0, 0));
EXPECT_FALSE(GetScrollAnchor(LayoutViewport()).RestoreAnchor(bad_anchor2));
- histogram_tester.ExpectBucketCount("Layout.ScrollAnchor.RestorationStatus",
- ScrollAnchor::kFailedNoMatches, 1);
-
SerializedAnchor bad_anchor3("script", LayoutPoint(0, -1000));
EXPECT_FALSE(GetScrollAnchor(LayoutViewport()).RestoreAnchor(bad_anchor3));
- histogram_tester.ExpectBucketCount("Layout.ScrollAnchor.RestorationStatus",
- ScrollAnchor::kFailedNoValidMatches, 1);
SerializedAnchor serialized_anchor("#block1", LayoutPoint(0, 0));
EXPECT_TRUE(
@@ -199,8 +186,6 @@ TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
histogram_tester.ExpectTotalCount("Layout.ScrollAnchor.TimeToRestoreAnchor",
4);
- histogram_tester.ExpectBucketCount("Layout.ScrollAnchor.RestorationStatus",
- ScrollAnchor::kSuccess, 1);
}
// TODO(skobes): Convert this to web-platform-tests when visual viewport API is
diff --git a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 4c6da7d0ddf..dc6d073cfee 100644
--- a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -2878,7 +2878,7 @@ TEST_F(ScrollbarsTestWithVirtualTimer,
// Verify that the scrollbar autopress timer requested some scrolls via
// gestures. The button was pressed for 2 seconds and the timer fires
// every 250ms - we should have at least 7 injected gesture updates.
- EXPECT_GT(WebWidgetClient().GetInjectedScrollEvents().size(), 6u);
+ EXPECT_GT(GetWebFrameWidget().GetInjectedScrollEvents().size(), 6u);
}
class ScrollbarTrackMarginsTest : public ScrollbarsTest {
@@ -3594,4 +3594,83 @@ TEST_F(ScrollbarsTest, ScrollbarGutterWithVerticalTextAndOverlayScrollbars) {
box_always_both_scrollbars);
}
+// Test the additional gutter created by the "both" keyword of scrollbar-gutter.
+TEST_F(ScrollbarsTest, ScrollbarGutterBothKeywordWithClassicScrollbars) {
+ // This test requires that scrollbars take up space.
+ ENABLE_OVERLAY_SCROLLBARS(false);
+
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #container {
+ scrollbar-gutter: always both;
+ width: 200px;
+ height: 200px;
+ overflow: auto;
+ writing-mode: horizontal-tb;
+ direction: ltr;
+ }
+ #content {
+ width: 100%;
+ height: 300px;
+ }
+ </style>
+ <div id="container">
+ <div id="content">
+ </div>
+ )HTML");
+ Compositor().BeginFrame();
+
+ Document& document = GetDocument();
+ Element* container = document.getElementById("container");
+
+ auto* scrollable_container = GetScrollableArea(*container);
+ scrollable_container->SetScrollbarsHiddenForTesting(false);
+
+ if (WebView().GetPage()->GetScrollbarTheme().AllowsHitTest()) {
+ // Scrollbar on the right side.
+ HitTestResult hit_test_result = HitTest(195, 5);
+ EXPECT_EQ(hit_test_result.InnerElement(), container);
+ EXPECT_TRUE(hit_test_result.GetScrollbar());
+ EXPECT_TRUE(hit_test_result.GetScrollbar()->Enabled());
+
+ // Empty gutter on the left side, where the events will take place.
+ hit_test_result = HitTest(5, 5);
+ EXPECT_EQ(hit_test_result.InnerElement(), container);
+ EXPECT_FALSE(hit_test_result.GetScrollbar());
+ }
+
+ EXPECT_EQ(container->scrollTop(), 0);
+
+ // Scroll down.
+ WebView().MainFrameViewWidget()->HandleInputEvent(
+ GenerateWheelGestureEvent(WebInputEvent::Type::kGestureScrollBegin,
+ IntPoint(5, 5), ScrollOffset(0, -100)));
+ WebView().MainFrameViewWidget()->HandleInputEvent(
+ GenerateWheelGestureEvent(WebInputEvent::Type::kGestureScrollUpdate,
+ IntPoint(5, 5), ScrollOffset(0, -100)));
+ WebView().MainFrameViewWidget()->HandleInputEvent(GenerateWheelGestureEvent(
+ WebInputEvent::Type::kGestureScrollEnd, IntPoint(5, 5)));
+
+ EXPECT_EQ(container->scrollTop(), 100);
+
+ // Scroll up.
+ WebView().MainFrameViewWidget()->HandleInputEvent(
+ GenerateWheelGestureEvent(WebInputEvent::Type::kGestureScrollBegin,
+ IntPoint(5, 5), ScrollOffset(0, 100)));
+ WebView().MainFrameViewWidget()->HandleInputEvent(
+ GenerateWheelGestureEvent(WebInputEvent::Type::kGestureScrollUpdate,
+ IntPoint(5, 5), ScrollOffset(0, 100)));
+ WebView().MainFrameViewWidget()->HandleInputEvent(GenerateWheelGestureEvent(
+ WebInputEvent::Type::kGestureScrollEnd, IntPoint(195, 5)));
+
+ EXPECT_EQ(container->scrollTop(), 0);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc b/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
index 085ccb41551..ace00d2eab0 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
@@ -239,13 +239,31 @@ static bool ExtractImageData(Image* image,
if (!image)
return false;
- CanvasColorParams color_params;
- SkImageInfo info = SkImageInfo::Make(
- image_size.Width(), image_size.Height(), color_params.GetSkColorType(),
- color_params.GetSkAlphaType(), color_params.GetSkColorSpace());
- sk_sp<SkSurface> surface =
- SkSurface::MakeRaster(info, color_params.GetSkSurfaceProps());
+ // Compute the SkImageInfo for the output.
+ SkImageInfo dst_info = SkImageInfo::Make(
+ image_size.Width(), image_size.Height(), kN32_SkColorType,
+ kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
+
+ // Populate |contents| with newly allocated and zero-initialized data, big
+ // enough for |dst_info|.
+ size_t dst_size_bytes = dst_info.computeMinByteSize();
+ {
+ if (SkImageInfo::ByteSizeOverflowed(dst_size_bytes) ||
+ dst_size_bytes > v8::TypedArray::kMaxLength) {
+ return false;
+ }
+ ArrayBufferContents result(dst_size_bytes, 1,
+ ArrayBufferContents::kNotShared,
+ ArrayBufferContents::kZeroInitialize);
+ if (result.DataLength() != dst_size_bytes)
+ return false;
+ result.Transfer(contents);
+ }
+ // Set |surface| to draw directly to |contents|.
+ const SkSurfaceProps disable_lcd_props(0, kUnknown_SkPixelGeometry);
+ sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
+ dst_info, contents.Data(), dst_info.minRowBytes(), &disable_lcd_props);
if (!surface)
return false;
@@ -258,28 +276,10 @@ static bool ExtractImageData(Image* image,
IntRect image_dest_rect(IntPoint(), image_size);
SkiaPaintCanvas canvas(surface->getCanvas());
canvas.clear(SK_ColorTRANSPARENT);
-
image->Draw(&canvas, flags, FloatRect(image_dest_rect), image_source_rect,
- respect_orientation, Image::kDoNotClampImageToSourceRect,
- Image::kSyncDecode);
-
- size_t size_in_bytes;
- if (!StaticBitmapImage::GetSizeInBytes(image_dest_rect, color_params)
- .AssignIfValid(&size_in_bytes) ||
- size_in_bytes > v8::TypedArray::kMaxLength) {
- return false;
- }
- ArrayBufferContents result(size_in_bytes, 1, ArrayBufferContents::kNotShared,
- ArrayBufferContents::kZeroInitialize);
- if (result.DataLength() != size_in_bytes)
- return false;
- result.Transfer(contents);
-
- return StaticBitmapImage::CopyToByteArray(
- UnacceleratedStaticBitmapImage::Create(surface->makeImageSnapshot()),
- base::span<uint8_t>(reinterpret_cast<uint8_t*>(contents.Data()),
- contents.DataLength()),
- image_dest_rect, color_params);
+ SkSamplingOptions(), respect_orientation,
+ Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
+ return true;
}
static std::unique_ptr<RasterShapeIntervals> ExtractIntervalsFromImageData(
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 619a6ee3299..1f8a3f27900 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -190,10 +190,14 @@ std::unique_ptr<Shape> ShapeOutsideInfo::CreateShapeForImage(
WritingMode writing_mode,
float margin) const {
DCHECK(!style_image->IsPendingImage());
+
+ RespectImageOrientationEnum respect_orientation =
+ style_image->ForceOrientationIfNecessary(
+ LayoutObject::ShouldRespectImageOrientation(layout_box_));
+
const LayoutSize& image_size = RoundedLayoutSize(style_image->ImageSize(
layout_box_->GetDocument(), layout_box_->StyleRef().EffectiveZoom(),
- FloatSize(reference_box_logical_size_),
- LayoutObject::ShouldRespectImageOrientation(layout_box_)));
+ FloatSize(reference_box_logical_size_), respect_orientation));
const LayoutRect& margin_rect =
GetShapeImageMarginRect(*layout_box_, reference_box_logical_size_);
@@ -206,9 +210,9 @@ std::unique_ptr<Shape> ShapeOutsideInfo::CreateShapeForImage(
style_image->GetImage(*layout_box_, layout_box_->GetDocument(),
layout_box_->StyleRef(), FloatSize(image_size));
- return Shape::CreateRasterShape(
- image.get(), shape_image_threshold, image_rect, margin_rect, writing_mode,
- margin, LayoutObject::ShouldRespectImageOrientation(layout_box_));
+ return Shape::CreateRasterShape(image.get(), shape_image_threshold,
+ image_rect, margin_rect, writing_mode, margin,
+ respect_orientation);
}
const Shape& ShapeOutsideInfo::ComputedShape() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/DIR_METADATA b/chromium/third_party/blink/renderer/core/layout/svg/DIR_METADATA
new file mode 100644
index 00000000000..20ba44d55bc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/svg/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>SVG"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/OWNERS b/chromium/third_party/blink/renderer/core/layout/svg/OWNERS
index 8db19674eda..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/OWNERS
+++ b/chromium/third_party/blink/renderer/core/layout/svg/OWNERS
@@ -1,2 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>SVG \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
index b40b222b548..91a9779c18e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
@@ -24,10 +24,10 @@
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
#include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
@@ -47,7 +47,6 @@ SVGElement* LayoutSVGBlock::GetElement() const {
void LayoutSVGBlock::WillBeDestroyed() {
NOT_DESTROYED();
- SVGResourcesCache::RemoveResources(*this);
SVGResources::ClearClipPathFilterMask(*GetElement(), Style());
LayoutBlockFlow::WillBeDestroyed();
}
@@ -57,7 +56,7 @@ void LayoutSVGBlock::InsertedIntoTree() {
LayoutBlockFlow::InsertedIntoTree();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::AddResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
CompositingReason::kNone) {
@@ -69,7 +68,7 @@ void LayoutSVGBlock::WillBeRemovedFromTree() {
NOT_DESTROYED();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::RemoveResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
LayoutBlockFlow::WillBeRemovedFromTree();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
@@ -120,6 +119,11 @@ void LayoutSVGBlock::StyleDidChange(StyleDifference diff,
NOT_DESTROYED();
LayoutBlock::StyleDidChange(diff, old_style);
+ // |HasTransformRelatedProperty| is used for compositing so ensure it was
+ // correctly set by the call to |StyleDidChange|.
+ DCHECK_EQ(HasTransformRelatedProperty(),
+ StyleRef().HasTransformRelatedProperty());
+
transform_uses_reference_box_ =
TransformHelper::DependsOnReferenceBox(StyleRef());
@@ -141,10 +145,8 @@ void LayoutSVGBlock::StyleDidChange(StyleDifference diff,
}
if (diff.CompositingReasonsChanged())
SVGLayoutSupport::NotifySVGRootOfChangedCompositingReasons(this);
- if (diff.HasDifference()) {
- SVGResourcesCache::UpdateResources(*this);
- LayoutSVGResourceContainer::StyleDidChange(*this, diff);
- }
+ if (diff.HasDifference())
+ LayoutSVGResourceContainer::StyleChanged(*this, diff);
}
void LayoutSVGBlock::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index 5272c6ef96b..a006624f923 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_container_painter.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
index e9b6cda61b5..fd413794d54 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
@@ -84,20 +84,18 @@ void LayoutSVGEllipse::CalculateRadiiAndCenter() {
DCHECK(GetElement());
SVGLengthContext length_context(GetElement());
const ComputedStyle& style = StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- center_ =
- length_context.ResolveLengthPair(svg_style.Cx(), svg_style.Cy(), style);
+ center_ = length_context.ResolveLengthPair(style.Cx(), style.Cy(), style);
if (IsA<SVGCircleElement>(*GetElement())) {
- float radius = length_context.ValueForLength(svg_style.R(), style,
- SVGLengthMode::kOther);
+ float radius =
+ length_context.ValueForLength(style.R(), style, SVGLengthMode::kOther);
radii_ = FloatSize(radius, radius);
} else {
- radii_ = ToFloatSize(length_context.ResolveLengthPair(
- svg_style.Rx(), svg_style.Ry(), style));
- if (svg_style.Rx().IsAuto())
+ radii_ = ToFloatSize(
+ length_context.ResolveLengthPair(style.Rx(), style.Ry(), style));
+ if (style.Rx().IsAuto())
radii_.SetWidth(radii_.Height());
- else if (svg_style.Ry().IsAuto())
+ else if (style.Ry().IsAuto())
radii_.SetHeight(radii_.Width());
}
}
@@ -138,8 +136,7 @@ bool LayoutSVGEllipse::ShapeDependentFillContains(
bool LayoutSVGEllipse::HasContinuousStroke() const {
NOT_DESTROYED();
- const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
- return svg_style.StrokeDashArray()->data.IsEmpty();
+ return !StyleRef().HasDashArray();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
index 084a0a1a4e5..cbd8f303a55 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
@@ -61,21 +61,19 @@ void LayoutSVGFilterPrimitive::StyleDidChange(StyleDifference diff,
if (!old_style)
return;
auto& element = To<SVGFilterPrimitiveStandardAttributes>(*GetNode());
- const SVGComputedStyle& new_style = StyleRef().SvgStyle();
+ const ComputedStyle& style = StyleRef();
if (IsA<SVGFEFloodElement>(element) || IsA<SVGFEDropShadowElement>(element)) {
CheckForColorChange(element, svg_names::kFloodColorAttr, diff,
- old_style->SvgStyle().FloodColor(),
- new_style.FloodColor());
- if (new_style.FloodOpacity() != old_style->SvgStyle().FloodOpacity())
+ old_style->FloodColor(), style.FloodColor());
+ if (style.FloodOpacity() != old_style->FloodOpacity())
element.PrimitiveAttributeChanged(svg_names::kFloodOpacityAttr);
} else if (IsA<SVGFEDiffuseLightingElement>(element) ||
IsA<SVGFESpecularLightingElement>(element)) {
CheckForColorChange(element, svg_names::kLightingColorAttr, diff,
- old_style->SvgStyle().LightingColor(),
- new_style.LightingColor());
+ old_style->LightingColor(), style.LightingColor());
}
- if (new_style.ColorInterpolationFilters() !=
- old_style->SvgStyle().ColorInterpolationFilters()) {
+ if (style.ColorInterpolationFilters() !=
+ old_style->ColorInterpolationFilters()) {
element.PrimitiveAttributeChanged(
svg_names::kColorInterpolationFiltersAttr);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index 564823aa30b..56474033c9e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -106,11 +106,10 @@ void LayoutSVGForeignObject::UpdateLayout() {
// zoom.
SVGLengthContext length_context(foreign);
const ComputedStyle& style = StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- viewport_ = FloatRect(
- length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
- ToFloatSize(length_context.ResolveLengthPair(style.Width(),
- style.Height(), style)));
+ viewport_ =
+ FloatRect(length_context.ResolveLengthPair(style.X(), style.Y(), style),
+ ToFloatSize(length_context.ResolveLengthPair(
+ style.Width(), style.Height(), style)));
// Use the zoomed version of the viewport as the location, because we will
// interpose a transform that "unzooms" the effective zoom to let the children
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
index 2cddf75b004..e35a3367316 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
@@ -72,7 +72,7 @@ class LayoutSVGForeignObject final : public LayoutSVGBlock {
}
FloatRect StrokeBoundingBox() const override {
NOT_DESTROYED();
- return ObjectBoundingBox();
+ return VisualRectInLocalSVGCoordinates();
}
FloatRect VisualRectInLocalSVGCoordinates() const override {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
index ecbe99c3222..40ddbbfd5e3 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
@@ -387,4 +387,25 @@ TEST_F(LayoutSVGForeignObjectTest, HitTestUnderScrollingAncestor) {
EXPECT_EQ(PhysicalOffset(450, 450), result.PointInInnerNodeFrame());
}
+TEST_F(LayoutSVGForeignObjectTest, BBoxPropagationZoomed) {
+ GetFrame().SetPageZoomFactor(2);
+ SetBodyInnerHTML(R"HTML(
+ <svg>
+ <g>
+ <foreignObject x="6" y="5" width="100" height="50" id="target"/>
+ </g>
+ </svg>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ const auto& target = *GetLayoutObjectByElementId("target");
+ ASSERT_EQ(target.StyleRef().EffectiveZoom(), 2);
+
+ EXPECT_EQ(target.ObjectBoundingBox(), FloatRect(6, 5, 100, 50));
+ EXPECT_EQ(target.StrokeBoundingBox(), FloatRect(12, 10, 200, 100));
+ const auto& parent_g = *target.Parent();
+ EXPECT_EQ(parent_g.ObjectBoundingBox(), FloatRect(6, 5, 100, 50));
+ EXPECT_EQ(parent_g.StrokeBoundingBox(), FloatRect(6, 5, 100, 50));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index 8c9640212df..d6bb5f60613 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -35,7 +35,6 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
@@ -85,7 +84,7 @@ static float ResolveHeightForRatio(float width,
bool LayoutSVGImage::HasOverriddenIntrinsicSize() const {
NOT_DESTROYED();
- if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+ if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled())
return false;
auto* svg_image_element = DynamicTo<SVGImageElement>(GetElement());
return svg_image_element && svg_image_element->IsDefaultIntrinsicSize();
@@ -142,11 +141,10 @@ bool LayoutSVGImage::UpdateBoundingBox() {
SVGLengthContext length_context(GetElement());
const ComputedStyle& style = StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- object_bounding_box_ = FloatRect(
- length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
- ToFloatSize(length_context.ResolveLengthPair(style.Width(),
- style.Height(), style)));
+ object_bounding_box_ =
+ FloatRect(length_context.ResolveLengthPair(style.X(), style.Y(), style),
+ ToFloatSize(length_context.ResolveLengthPair(
+ style.Width(), style.Height(), style)));
if (style.Width().IsAuto() || style.Height().IsAuto())
object_bounding_box_.SetSize(CalculateObjectSize());
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
index 2a9d1d78b05..076d97bcaf3 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
@@ -22,11 +22,11 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
#include "third_party/blink/renderer/core/svg/svg_a_element.h"
@@ -117,7 +117,6 @@ void LayoutSVGInline::AbsoluteQuads(Vector<FloatQuad>& quads,
void LayoutSVGInline::WillBeDestroyed() {
NOT_DESTROYED();
- SVGResourcesCache::RemoveResources(*this);
SVGResources::ClearClipPathFilterMask(To<SVGElement>(*GetNode()), Style());
SVGResources::ClearPaints(To<SVGElement>(*GetNode()), Style());
LayoutInline::WillBeDestroyed();
@@ -139,10 +138,8 @@ void LayoutSVGInline::StyleDidChange(StyleDifference diff,
return;
if (diff.CompositingReasonsChanged())
SVGLayoutSupport::NotifySVGRootOfChangedCompositingReasons(this);
- if (diff.HasDifference()) {
- SVGResourcesCache::UpdateResources(*this);
- LayoutSVGResourceContainer::StyleDidChange(*this, diff);
- }
+ if (diff.HasDifference())
+ LayoutSVGResourceContainer::StyleChanged(*this, diff);
}
void LayoutSVGInline::AddChild(LayoutObject* child,
@@ -165,7 +162,7 @@ void LayoutSVGInline::InsertedIntoTree() {
LayoutInline::InsertedIntoTree();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::AddResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
CompositingReason::kNone) {
@@ -177,7 +174,7 @@ void LayoutSVGInline::WillBeRemovedFromTree() {
NOT_DESTROYED();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::RemoveResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
LayoutInline::WillBeRemovedFromTree();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
index 5ae85eb7898..a536f6a37a2 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
@@ -28,10 +28,12 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/platform/fonts/character_range.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/text/bidi_character_run.h"
#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
@@ -62,6 +64,9 @@ void LayoutSVGInlineText::TextDidChange() {
LayoutText::TextDidChange();
LayoutSVGText::NotifySubtreeStructureChanged(
this, layout_invalidation_reason::kTextChanged);
+
+ if (StyleRef().UserModify() != EUserModify::kReadOnly)
+ UseCounter::Count(GetDocument(), WebFeature::kSVGTextEdited);
}
void LayoutSVGInlineText::StyleDidChange(StyleDifference diff,
@@ -92,9 +97,7 @@ void LayoutSVGInlineText::StyleDidChange(StyleDifference diff,
void LayoutSVGInlineText::InvalidateSubtreeLayoutForFontUpdates() {
NOT_DESTROYED();
- if (!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled() ||
- !IsFontFallbackValid()) {
+ if (!IsFontFallbackValid()) {
if (LayoutSVGText* text_layout_object =
LayoutSVGText::LocateLayoutSVGTextAncestor(this)) {
text_layout_object->SetNeedsTextMetricsUpdate();
@@ -172,6 +175,8 @@ bool LayoutSVGInlineText::CharacterStartsNewTextChunk(int position) const {
PositionWithAffinity LayoutSVGInlineText::PositionForPoint(
const PhysicalOffset& point) const {
NOT_DESTROYED();
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
if (!HasInlineFragments() || !TextLength())
return CreatePositionWithAffinity(0);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
index 96f0ef37969..fba14ab0a22 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
@@ -32,9 +32,9 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_container.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
@@ -108,7 +108,6 @@ FloatRect LayoutSVGModelObject::LocalBoundingBoxRectForAccessibility() const {
void LayoutSVGModelObject::WillBeDestroyed() {
NOT_DESTROYED();
- SVGResourcesCache::RemoveResources(*this);
SVGResources::ClearClipPathFilterMask(*GetElement(), Style());
LayoutObject::WillBeDestroyed();
}
@@ -147,6 +146,8 @@ void LayoutSVGModelObject::StyleDidChange(StyleDifference diff,
SetNeedsTransformUpdate();
}
+ SetHasTransformRelatedProperty(StyleRef().HasTransformRelatedProperty());
+
SVGResources::UpdateClipPathFilterMask(*GetElement(), old_style, StyleRef());
if (!Parent())
@@ -159,10 +160,8 @@ void LayoutSVGModelObject::StyleDidChange(StyleDifference diff,
}
if (diff.CompositingReasonsChanged())
SVGLayoutSupport::NotifySVGRootOfChangedCompositingReasons(this);
- if (diff.HasDifference()) {
- SVGResourcesCache::UpdateResources(*this);
- LayoutSVGResourceContainer::StyleDidChange(*this, diff);
- }
+ if (diff.HasDifference())
+ LayoutSVGResourceContainer::StyleChanged(*this, diff);
}
void LayoutSVGModelObject::InsertedIntoTree() {
@@ -170,7 +169,7 @@ void LayoutSVGModelObject::InsertedIntoTree() {
LayoutObject::InsertedIntoTree();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::AddResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
CompositingReason::kNone) {
@@ -182,7 +181,7 @@ void LayoutSVGModelObject::WillBeRemovedFromTree() {
NOT_DESTROYED();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::RemoveResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
LayoutObject::WillBeRemovedFromTree();
if (CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(*this) !=
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
index 05acc083698..50755dfa267 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
@@ -29,14 +29,26 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
namespace blink {
+namespace {
+
+bool SupportsMarkers(const SVGGeometryElement& element) {
+ return element.HasTagName(svg_names::kLineTag) ||
+ element.HasTagName(svg_names::kPathTag) ||
+ element.HasTagName(svg_names::kPolygonTag) ||
+ element.HasTagName(svg_names::kPolylineTag);
+}
+
+} // namespace
+
LayoutSVGPath::LayoutSVGPath(SVGGeometryElement* node)
// <line> elements have no joins and thus needn't care about miters.
- : LayoutSVGShape(node, IsA<SVGLineElement>(node) ? kNoMiters : kComplex) {}
+ : LayoutSVGShape(node, IsA<SVGLineElement>(node) ? kNoMiters : kComplex) {
+ DCHECK(SupportsMarkers(*node));
+}
LayoutSVGPath::~LayoutSVGPath() = default;
@@ -63,25 +75,25 @@ const StylePath* LayoutSVGPath::GetStylePath() const {
NOT_DESTROYED();
if (!IsA<SVGPathElement>(*GetElement()))
return nullptr;
- return StyleRef().SvgStyle().D();
+ return StyleRef().D();
}
void LayoutSVGPath::UpdateMarkers() {
NOT_DESTROYED();
marker_positions_.clear();
- if (!StyleRef().SvgStyle().HasMarkers() ||
- !SVGResources::SupportsMarkers(*To<SVGGraphicsElement>(GetElement())))
+ const ComputedStyle& style = StyleRef();
+ if (!style.HasMarkers())
return;
-
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(*this);
- if (!resources)
+ SVGElementResourceClient* client = SVGResources::GetClient(*this);
+ if (!client)
return;
-
- LayoutSVGResourceMarker* marker_start = resources->MarkerStart();
- LayoutSVGResourceMarker* marker_mid = resources->MarkerMid();
- LayoutSVGResourceMarker* marker_end = resources->MarkerEnd();
+ auto* marker_start = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerStartResource());
+ auto* marker_mid = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerMidResource());
+ auto* marker_end = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerEndResource());
if (!(marker_start || marker_mid || marker_end))
return;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
index 6e0f91f7493..2d31b55bc7e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
@@ -55,7 +55,6 @@ void LayoutSVGRect::UpdateShapeFromElement() {
if (bounding_box_size.Width() < 0 || bounding_box_size.Height() < 0)
return;
- const SVGComputedStyle& svg_style = style.SvgStyle();
// Spec: "A value of zero disables rendering of the element."
if (!bounding_box_size.IsEmpty()) {
// Fallback to LayoutSVGShape and path-based hit detection if the rect
@@ -68,8 +67,8 @@ void LayoutSVGRect::UpdateShapeFromElement() {
use_path_fallback_ = true;
return;
}
- FloatPoint radii(length_context.ResolveLengthPair(svg_style.Rx(),
- svg_style.Ry(), style));
+ FloatPoint radii(
+ length_context.ResolveLengthPair(style.Rx(), style.Ry(), style));
if (radii.X() > 0 || radii.Y() > 0 || !DefinitelyHasSimpleStroke()) {
CreatePath();
use_path_fallback_ = true;
@@ -79,9 +78,9 @@ void LayoutSVGRect::UpdateShapeFromElement() {
if (!use_path_fallback_)
ClearPath();
- fill_bounding_box_ = FloatRect(
- length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
- bounding_box_size);
+ fill_bounding_box_ =
+ FloatRect(length_context.ResolveLengthPair(style.X(), style.Y(), style),
+ bounding_box_size);
stroke_bounding_box_ = CalculateStrokeBoundingBox();
}
@@ -124,7 +123,7 @@ bool LayoutSVGRect::ShapeDependentFillContains(const HitTestLocation& location,
// Returns true if the stroke is continuous and definitely uses miter joins.
bool LayoutSVGRect::DefinitelyHasSimpleStroke() const {
NOT_DESTROYED();
- const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
+ const ComputedStyle& style = StyleRef();
// The four angles of a rect are 90 degrees. Using the formula at:
// http://www.w3.org/TR/SVG/painting.html#StrokeMiterlimitProperty
@@ -142,9 +141,8 @@ bool LayoutSVGRect::DefinitelyHasSimpleStroke() const {
// miterlimits, the join style used might not be correct (e.g. a miterlimit
// of 1.4142135 should result in bevel joins, but may be drawn using miter
// joins).
- return svg_style.StrokeDashArray()->data.IsEmpty() &&
- svg_style.JoinStyle() == kMiterJoin &&
- svg_style.StrokeMiterLimit() >= 1.5;
+ return !style.HasDashArray() && style.JoinStyle() == kMiterJoin &&
+ style.StrokeMiterLimit() >= 1.5;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
index ecd2c309c4d..dd4b65c4363 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h"
@@ -44,7 +45,7 @@ enum class ClipStrategy { kNone, kMask, kPath };
ClipStrategy ModifyStrategyForClipPath(const ComputedStyle& style,
ClipStrategy strategy) {
// If the shape in the clip-path gets clipped too then fallback to masking.
- if (strategy != ClipStrategy::kPath || !style.ClipPath())
+ if (strategy != ClipStrategy::kPath || !style.HasClipPath())
return strategy;
return ClipStrategy::kMask;
}
@@ -116,8 +117,7 @@ void LayoutSVGResourceClipper::RemoveAllClientsFromCache() {
clip_content_path_.Clear();
cached_paint_record_.reset();
local_clip_bounds_ = FloatRect();
- MarkAllClientsForInvalidation(SVGResourceClient::kClipCacheInvalidation |
- SVGResourceClient::kPaintInvalidation);
+ MarkAllClientsForInvalidation(kClipCacheInvalidation | kPaintInvalidation);
}
base::Optional<Path> LayoutSVGResourceClipper::AsPath() {
@@ -131,7 +131,7 @@ base::Optional<Path> LayoutSVGResourceClipper::AsPath() {
clip_content_path_validity_ = kClipContentPathInvalid;
// If the current clip-path gets clipped itself, we have to fallback to
// masking.
- if (StyleRef().ClipPath())
+ if (StyleRef().HasClipPath())
return base::nullopt;
unsigned op_count = 0;
@@ -177,14 +177,14 @@ sk_sp<const PaintRecord> LayoutSVGResourceClipper::CreatePaintRecord() {
if (cached_paint_record_)
return cached_paint_record_;
- PaintRecordBuilder builder(nullptr, nullptr);
+ PaintRecordBuilder builder;
// Switch to a paint behavior where all children of this <clipPath> will be
// laid out using special constraints:
// - fill-opacity/stroke-opacity/opacity set to 1
// - masker/filter not applied when laying out the children
// - fill is set to the initial fill paint server (solid, black)
// - stroke is set to the initial stroke paint server (none)
- PaintInfo info(builder.Context(), LayoutRect::InfiniteIntRect(),
+ PaintInfo info(builder.Context(), CullRect::Infinite(),
PaintPhase::kForeground, kGlobalPaintNormalPhase,
kPaintLayerPaintingRenderingClipPathAsMask |
kPaintLayerPaintingRenderingResourceSubtree);
@@ -278,21 +278,27 @@ FloatRect LayoutSVGResourceClipper::ResourceBoundingBox(
return CalculateClipTransform(reference_box).MapRect(local_clip_bounds_);
}
-void LayoutSVGResourceClipper::StyleDidChange(StyleDifference diff,
- const ComputedStyle* old_style) {
+bool LayoutSVGResourceClipper::FindCycleFromSelf() const {
NOT_DESTROYED();
- LayoutSVGResourceContainer::StyleDidChange(diff, old_style);
- if (diff.TransformChanged()) {
- MarkAllClientsForInvalidation(SVGResourceClient::kClipCacheInvalidation |
- SVGResourceClient::kPaintInvalidation);
+ // Check nested clip-path.
+ if (auto* reference_clip =
+ DynamicTo<ReferenceClipPathOperation>(StyleRef().ClipPath())) {
+ // The resource can be null if the reference is external but external
+ // references are not allowed.
+ if (SVGResource* resource = reference_clip->Resource()) {
+ if (resource->FindCycle(*SVGResources::GetClient(*this)))
+ return true;
+ }
}
+ return LayoutSVGResourceContainer::FindCycleFromSelf();
}
-void LayoutSVGResourceClipper::WillBeDestroyed() {
+void LayoutSVGResourceClipper::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
NOT_DESTROYED();
- MarkAllClientsForInvalidation(SVGResourceClient::kClipCacheInvalidation |
- SVGResourceClient::kPaintInvalidation);
- LayoutSVGResourceContainer::WillBeDestroyed();
+ LayoutSVGResourceContainer::StyleDidChange(diff, old_style);
+ if (diff.TransformChanged())
+ MarkAllClientsForInvalidation(kClipCacheInvalidation | kPaintInvalidation);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
index ac57a415f09..ba47410f316 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
@@ -57,12 +57,11 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
base::Optional<Path> AsPath();
sk_sp<const PaintRecord> CreatePaintRecord();
- protected:
+ private:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
- void WillBeDestroyed() override;
- private:
void CalculateLocalClipBounds();
+ bool FindCycleFromSelf() const override;
// Cache of the clip path when using path clipping.
enum ClipContentPathValidity {
@@ -79,17 +78,28 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
FloatRect local_clip_bounds_;
};
-DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceClipper,
- kClipperResourceType);
+template <>
+struct DowncastTraits<LayoutSVGResourceClipper> {
+ static bool AllowFrom(const LayoutSVGResourceContainer& container) {
+ return container.ResourceType() == kClipperResourceType;
+ }
+};
inline LayoutSVGResourceClipper* GetSVGResourceAsType(
+ SVGResourceClient& client,
+ const ReferenceClipPathOperation& reference_clip) {
+ return GetSVGResourceAsType<LayoutSVGResourceClipper>(
+ client, reference_clip.Resource());
+}
+
+inline LayoutSVGResourceClipper* GetSVGResourceAsType(
+ SVGResourceClient& client,
const ClipPathOperation* clip_path_operation) {
const auto* reference_clip =
DynamicTo<ReferenceClipPathOperation>(clip_path_operation);
if (!reference_clip)
return nullptr;
- return GetSVGResourceAsType<LayoutSVGResourceClipper>(
- reference_clip->Resource());
+ return GetSVGResourceAsType(client, *reference_clip);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
index d460812a14e..1cb3a737d58 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
@@ -20,8 +20,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
+#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
@@ -55,13 +54,24 @@ void LayoutSVGResourceContainer::UpdateLayout() {
ClearInvalidationMask();
}
+void LayoutSVGResourceContainer::InvalidateClientsIfActiveResource() {
+ NOT_DESTROYED();
+ // If this is the 'active' resource (the first element with the specified 'id'
+ // in tree order), notify any clients that they need to reevaluate the
+ // resource's contents.
+ const LocalSVGResource* resource = ResourceForContainer(*this);
+ if (!resource || resource->Target() != GetElement())
+ return;
+ // Pass all available flags. This may be performing unnecessary invalidations
+ // in some cases.
+ MarkAllClientsForInvalidation(kInvalidateAll);
+}
+
void LayoutSVGResourceContainer::WillBeDestroyed() {
NOT_DESTROYED();
- LayoutSVGHiddenContainer::WillBeDestroyed();
// The resource is being torn down.
- // TODO(fs): Remove this when SVGResources is gone.
- if (LocalSVGResource* resource = ResourceForContainer(*this))
- resource->NotifyResourceDestroyed(*this);
+ InvalidateClientsIfActiveResource();
+ LayoutSVGHiddenContainer::WillBeDestroyed();
}
void LayoutSVGResourceContainer::StyleDidChange(
@@ -69,54 +79,75 @@ void LayoutSVGResourceContainer::StyleDidChange(
const ComputedStyle* old_style) {
NOT_DESTROYED();
LayoutSVGHiddenContainer::StyleDidChange(diff, old_style);
- // The resource has been attached. Notify any pending clients that
- // they can now try to add themselves as clients to the resource.
- // TODO(fs): Remove this when SVGResources is gone.
if (old_style)
return;
- if (LocalSVGResource* resource = ResourceForContainer(*this))
- resource->NotifyResourceAttached(*this);
+ // The resource has been attached.
+ InvalidateClientsIfActiveResource();
}
-bool LayoutSVGResourceContainer::FindCycle(
- SVGResourcesCycleSolver& solver) const {
+bool LayoutSVGResourceContainer::FindCycle() const {
NOT_DESTROYED();
- if (solver.IsKnownAcyclic(this))
- return false;
- SVGResourcesCycleSolver::Scope scope(solver);
- if (!scope.Enter(this) || FindCycleFromSelf(solver))
- return true;
- solver.AddAcyclicSubgraph(this);
- return false;
+ return FindCycleFromSelf();
+}
+
+static HeapVector<Member<SVGResource>> CollectResources(
+ const LayoutObject& layout_object) {
+ const ComputedStyle& style = layout_object.StyleRef();
+ HeapVector<Member<SVGResource>> resources;
+ if (auto* reference_clip =
+ DynamicTo<ReferenceClipPathOperation>(style.ClipPath())) {
+ resources.push_back(reference_clip->Resource());
+ }
+ for (const auto& operation : style.Filter().Operations()) {
+ if (auto* reference_operation =
+ DynamicTo<ReferenceFilterOperation>(*operation))
+ resources.push_back(reference_operation->Resource());
+ }
+ if (auto* masker = style.MaskerResource())
+ resources.push_back(masker->Resource());
+ if (auto* marker = style.MarkerStartResource())
+ resources.push_back(marker->Resource());
+ if (auto* marker = style.MarkerMidResource())
+ resources.push_back(marker->Resource());
+ if (auto* marker = style.MarkerEndResource())
+ resources.push_back(marker->Resource());
+ if (auto* paint_resource = style.FillPaint().Resource())
+ resources.push_back(paint_resource->Resource());
+ if (auto* paint_resource = style.StrokePaint().Resource())
+ resources.push_back(paint_resource->Resource());
+ return resources;
}
bool LayoutSVGResourceContainer::FindCycleInResources(
- SVGResourcesCycleSolver& solver,
const LayoutObject& layout_object) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- if (!resources)
+ if (!layout_object.IsSVG() || layout_object.IsText())
+ return false;
+ SVGResourceClient* client = SVGResources::GetClient(layout_object);
+ // Without an associated client, we will not reference any resources.
+ if (!client)
return false;
// Fetch all the referenced resources.
- HashSet<LayoutSVGResourceContainer*> local_resources;
- resources->BuildSetOfResources(local_resources);
+ HeapVector<Member<SVGResource>> resources = CollectResources(layout_object);
// This performs a depth-first search for a back-edge in all the
// (potentially disjoint) graphs formed by the referenced resources.
- for (auto* local_resource : local_resources) {
- if (local_resource->FindCycle(solver))
+ for (const auto& local_resource : resources) {
+ // The resource can be null if the reference is external but external
+ // references are not allowed.
+ if (local_resource && local_resource->FindCycle(*client))
return true;
}
return false;
}
-bool LayoutSVGResourceContainer::FindCycleFromSelf(
- SVGResourcesCycleSolver& solver) const {
+bool LayoutSVGResourceContainer::FindCycleFromSelf() const {
NOT_DESTROYED();
- return FindCycleInSubtree(solver, *this);
+ // Resources don't generally apply to other resources, so require
+ // the specific cases that do (like <clipPath>) to implement an
+ // override.
+ return FindCycleInDescendants(*this);
}
bool LayoutSVGResourceContainer::FindCycleInDescendants(
- SVGResourcesCycleSolver& solver,
const LayoutObject& root) {
LayoutObject* node = root.SlowFirstChild();
while (node) {
@@ -126,7 +157,7 @@ bool LayoutSVGResourceContainer::FindCycleInDescendants(
node = node->NextInPreOrderAfterChildren(&root);
continue;
}
- if (FindCycleInResources(solver, *node))
+ if (FindCycleInResources(*node))
return true;
node = node->NextInPreOrder(&root);
}
@@ -134,11 +165,10 @@ bool LayoutSVGResourceContainer::FindCycleInDescendants(
}
bool LayoutSVGResourceContainer::FindCycleInSubtree(
- SVGResourcesCycleSolver& solver,
const LayoutObject& root) {
- if (FindCycleInResources(solver, root))
+ if (FindCycleInResources(root))
return true;
- return FindCycleInDescendants(solver, root);
+ return FindCycleInDescendants(root);
}
void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
@@ -159,7 +189,7 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
is_invalidating_ = true;
// Invalidate clients registered via an SVGResource.
- resource->NotifyContentChanged(invalidation_mask);
+ resource->NotifyContentChanged();
is_invalidating_ = false;
}
@@ -168,9 +198,6 @@ void LayoutSVGResourceContainer::InvalidateCacheAndMarkForLayout(
LayoutInvalidationReasonForTracing reason,
SubtreeLayoutScope* layout_scope) {
NOT_DESTROYED();
- if (SelfNeedsLayout())
- return;
-
SetNeedsLayoutAndFullPaintInvalidation(reason, kMarkContainerChain,
layout_scope);
@@ -242,8 +269,8 @@ static inline bool IsLayoutObjectOfResourceContainer(
return false;
}
-void LayoutSVGResourceContainer::StyleDidChange(LayoutObject& object,
- StyleDifference diff) {
+void LayoutSVGResourceContainer::StyleChanged(LayoutObject& object,
+ StyleDifference diff) {
// If this LayoutObject is the child of a resource container and
// it requires repainting because of changes to CSS properties
// such as 'visibility', upgrade to invalidate layout.
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
index 817835577a9..ccc4632ac62 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
@@ -27,8 +27,6 @@
namespace blink {
-class SVGResourcesCycleSolver;
-
enum LayoutSVGResourceType {
kMaskerResourceType,
kMarkerResourceType,
@@ -73,12 +71,12 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
SubtreeLayoutScope* = nullptr);
void InvalidateCacheAndMarkForLayout(SubtreeLayoutScope* = nullptr);
- bool FindCycle(SVGResourcesCycleSolver&) const;
+ bool FindCycle() const;
static void MarkForLayoutAndParentResourceInvalidation(
LayoutObject&,
bool needs_layout = true);
- static void StyleDidChange(LayoutObject&, StyleDifference);
+ static void StyleChanged(LayoutObject&, StyleDifference);
void ClearInvalidationMask() {
NOT_DESTROYED();
@@ -86,22 +84,37 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
}
protected:
+ typedef unsigned InvalidationModeMask;
+
+ // When adding modes, make sure we don't overflow
+ // |completed_invalidation_mask_|.
+ enum InvalidationMode {
+ kLayoutInvalidation = 1 << 0,
+ kBoundariesInvalidation = 1 << 1,
+ kPaintInvalidation = 1 << 2,
+ kPaintPropertiesInvalidation = 1 << 3,
+ kClipCacheInvalidation = 1 << 4,
+ kFilterCacheInvalidation = 1 << 5,
+ kInvalidateAll = kLayoutInvalidation | kBoundariesInvalidation |
+ kPaintInvalidation | kPaintPropertiesInvalidation |
+ kClipCacheInvalidation | kFilterCacheInvalidation,
+ };
+
// Used from RemoveAllClientsFromCache methods.
void MarkAllClientsForInvalidation(InvalidationModeMask);
- virtual bool FindCycleFromSelf(SVGResourcesCycleSolver&) const;
- static bool FindCycleInDescendants(SVGResourcesCycleSolver&,
- const LayoutObject& root);
- static bool FindCycleInResources(SVGResourcesCycleSolver&,
- const LayoutObject& object);
- static bool FindCycleInSubtree(SVGResourcesCycleSolver&,
- const LayoutObject& root);
+ virtual bool FindCycleFromSelf() const;
+ static bool FindCycleInDescendants(const LayoutObject& root);
+ static bool FindCycleInResources(const LayoutObject& object);
+ static bool FindCycleInSubtree(const LayoutObject& root);
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void WillBeDestroyed() override;
private:
- // Track global (markAllClientsForInvalidation) invalidations to avoid
+ void InvalidateClientsIfActiveResource();
+
+ // Track global (MarkAllClientsForInvalidation) invalidations to avoid
// redundant crawls.
unsigned completed_invalidations_mask_ : 8;
@@ -116,21 +129,18 @@ struct DowncastTraits<LayoutSVGResourceContainer> {
}
};
-#define DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(thisType, typeName) \
- DEFINE_TYPE_CASTS(thisType, LayoutSVGResourceContainer, resource, \
- resource->ResourceType() == typeName, \
- resource.ResourceType() == typeName)
-
template <typename ContainerType>
inline bool IsResourceOfType(const LayoutSVGResourceContainer* container) {
return container->ResourceType() == ContainerType::kResourceType;
}
template <typename ContainerType>
-inline ContainerType* GetSVGResourceAsType(const SVGResource* resource) {
+inline ContainerType* GetSVGResourceAsType(SVGResourceClient& client,
+ const SVGResource* resource) {
if (!resource)
return nullptr;
- if (LayoutSVGResourceContainer* container = resource->ResourceContainer()) {
+ if (LayoutSVGResourceContainer* container =
+ resource->ResourceContainer(client)) {
if (IsResourceOfType<ContainerType>(container))
return static_cast<ContainerType*>(container);
}
@@ -139,10 +149,12 @@ inline ContainerType* GetSVGResourceAsType(const SVGResource* resource) {
template <typename ContainerType>
inline ContainerType* GetSVGResourceAsType(
+ SVGResourceClient& client,
const StyleSVGResource* style_resource) {
if (!style_resource)
return nullptr;
- return GetSVGResourceAsType<ContainerType>(style_resource->Resource());
+ return GetSVGResourceAsType<ContainerType>(client,
+ style_resource->Resource());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
index 831555e5d35..01b56c759fc 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
@@ -44,8 +44,7 @@ bool LayoutSVGResourceFilter::IsChildAllowed(LayoutObject* child,
void LayoutSVGResourceFilter::RemoveAllClientsFromCache() {
NOT_DESTROYED();
- MarkAllClientsForInvalidation(SVGResourceClient::kPaintInvalidation |
- SVGResourceClient::kFilterCacheInvalidation);
+ MarkAllClientsForInvalidation(kPaintInvalidation | kFilterCacheInvalidation);
}
FloatRect LayoutSVGResourceFilter::ResourceBoundingBox(
@@ -68,8 +67,7 @@ SVGUnitTypes::SVGUnitType LayoutSVGResourceFilter::PrimitiveUnits() const {
->CurrentEnumValue();
}
-bool LayoutSVGResourceFilter::FindCycleFromSelf(
- SVGResourcesCycleSolver& solver) const {
+bool LayoutSVGResourceFilter::FindCycleFromSelf() const {
NOT_DESTROYED();
// Traverse and check all <feImage> 'href' element references.
for (auto& feimage_element :
@@ -80,24 +78,10 @@ bool LayoutSVGResourceFilter::FindCycleFromSelf(
const LayoutObject* target_layout_object = target->GetLayoutObject();
if (!target_layout_object)
continue;
- if (FindCycleInSubtree(solver, *target_layout_object))
+ if (FindCycleInSubtree(*target_layout_object))
return true;
}
return false;
}
-LayoutSVGResourceFilter* GetFilterResourceForSVG(const ComputedStyle& style) {
- if (!style.HasFilter())
- return nullptr;
- const FilterOperations& operations = style.Filter();
- if (operations.size() != 1)
- return nullptr;
- const auto* reference_filter =
- DynamicTo<ReferenceFilterOperation>(*operations.at(0));
- if (!reference_filter)
- return nullptr;
- return GetSVGResourceAsType<LayoutSVGResourceFilter>(
- reference_filter->Resource());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
index 9d91cf3bf11..62deb48f245 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
@@ -57,15 +57,15 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
}
private:
- bool FindCycleFromSelf(SVGResourcesCycleSolver&) const override;
+ bool FindCycleFromSelf() const override;
};
-// Get the LayoutSVGResourceFilter from the 'filter' property iff the 'filter'
-// is a single url(...) reference.
-LayoutSVGResourceFilter* GetFilterResourceForSVG(const ComputedStyle&);
-
-DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceFilter,
- kFilterResourceType);
+template <>
+struct DowncastTraits<LayoutSVGResourceFilter> {
+ static bool AllowFrom(const LayoutSVGResourceContainer& container) {
+ return container.ResourceType() == kFilterResourceType;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
index 4ed09da0d4e..5876f8c3bc5 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
@@ -47,7 +47,7 @@ void LayoutSVGResourceGradient::RemoveAllClientsFromCache() {
gradient_map_->clear();
should_collect_gradient_attributes_ = true;
To<SVGGradientElement>(*GetElement()).InvalidateDependentGradients();
- MarkAllClientsForInvalidation(SVGResourceClient::kPaintInvalidation);
+ MarkAllClientsForInvalidation(kPaintInvalidation);
}
bool LayoutSVGResourceGradient::RemoveClientFromCache(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
index 6d0a4e58dc3..f5842370cc0 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
@@ -55,8 +55,7 @@ void LayoutSVGResourceMarker::UpdateLayout() {
void LayoutSVGResourceMarker::RemoveAllClientsFromCache() {
NOT_DESTROYED();
- MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
- SVGResourceClient::kBoundariesInvalidation);
+ MarkAllClientsForInvalidation(kLayoutInvalidation | kBoundariesInvalidation);
}
FloatRect LayoutSVGResourceMarker::MarkerBoundaries(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
index 0a4523986b0..c364852832e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
@@ -83,8 +83,12 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer {
bool is_in_layout_;
};
-DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceMarker,
- kMarkerResourceType);
+template <>
+struct DowncastTraits<LayoutSVGResourceMarker> {
+ static bool AllowFrom(const LayoutSVGResourceContainer& container) {
+ return container.ResourceType() == kMarkerResourceType;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
index 763eeed908a..f8f04a77ec0 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -41,9 +41,8 @@ LayoutSVGResourceMasker::~LayoutSVGResourceMasker() = default;
void LayoutSVGResourceMasker::RemoveAllClientsFromCache() {
NOT_DESTROYED();
cached_paint_record_.reset();
- MarkAllClientsForInvalidation(
- SVGResourceClient::kPaintPropertiesInvalidation |
- SVGResourceClient::kPaintInvalidation);
+ MarkAllClientsForInvalidation(kPaintPropertiesInvalidation |
+ kPaintInvalidation);
}
sk_sp<const PaintRecord> LayoutSVGResourceMasker::CreatePaintRecord(
@@ -54,10 +53,10 @@ sk_sp<const PaintRecord> LayoutSVGResourceMasker::CreatePaintRecord(
return cached_paint_record_;
SubtreeContentTransformScope content_transform_scope(content_transformation);
- PaintRecordBuilder builder(nullptr, &context);
+ PaintRecordBuilder builder(context);
ColorFilter mask_content_filter =
- StyleRef().SvgStyle().ColorInterpolation() == CI_LINEARRGB
+ StyleRef().ColorInterpolation() == EColorInterpolation::kLinearrgb
? kColorFilterSRGBToLinearRGB
: kColorFilterNone;
builder.Context().SetColorFilter(mask_content_filter);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
index fa22491a79c..86ff367713e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
@@ -62,8 +62,12 @@ class LayoutSVGResourceMasker final : public LayoutSVGResourceContainer {
sk_sp<const PaintRecord> cached_paint_record_;
};
-DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceMasker,
- kMaskerResourceType);
+template <>
+struct DowncastTraits<LayoutSVGResourceMasker> {
+ static bool AllowFrom(const LayoutSVGResourceContainer& container) {
+ return container.ResourceType() == kMaskerResourceType;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
index 702601e603c..1edd62a9f10 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
@@ -26,7 +26,6 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
#include "third_party/blink/renderer/core/svg/svg_fit_to_view_box.h"
#include "third_party/blink/renderer/core/svg/svg_pattern_element.h"
@@ -57,7 +56,25 @@ void LayoutSVGResourcePattern::RemoveAllClientsFromCache() {
NOT_DESTROYED();
pattern_map_->clear();
should_collect_pattern_attributes_ = true;
- MarkAllClientsForInvalidation(SVGResourceClient::kPaintInvalidation);
+ To<SVGPatternElement>(*GetElement()).InvalidateDependentPatterns();
+ MarkAllClientsForInvalidation(kPaintInvalidation);
+}
+
+void LayoutSVGResourcePattern::WillBeDestroyed() {
+ NOT_DESTROYED();
+ To<SVGPatternElement>(*GetElement()).InvalidateDependentPatterns();
+ LayoutSVGResourcePaintServer::WillBeDestroyed();
+}
+
+void LayoutSVGResourcePattern::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
+ NOT_DESTROYED();
+ LayoutSVGResourcePaintServer::StyleDidChange(diff, old_style);
+ if (old_style)
+ return;
+ // The resource has been attached, any linked <pattern> may need to
+ // re-evaluate its attributes.
+ To<SVGPatternElement>(*GetElement()).InvalidateDependentPatterns();
}
bool LayoutSVGResourcePattern::RemoveClientFromCache(
@@ -70,11 +87,7 @@ bool LayoutSVGResourcePattern::RemoveClientFromCache(
return true;
}
-std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
- const FloatRect& object_bounding_box) {
- NOT_DESTROYED();
- auto pattern_data = std::make_unique<PatternData>();
-
+const PatternAttributes& LayoutSVGResourcePattern::EnsureAttributes() const {
DCHECK(GetElement());
// Validate pattern DOM state before building the actual pattern. This should
// avoid tearing down the pattern we're currently working on. Preferably the
@@ -82,11 +95,33 @@ std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
if (should_collect_pattern_attributes_) {
attributes_wrapper_->Set(PatternAttributes());
auto* pattern_element = To<SVGPatternElement>(GetElement());
- pattern_element->CollectPatternAttributes(MutableAttributes());
+ pattern_element->CollectPatternAttributes(
+ attributes_wrapper_->Attributes());
should_collect_pattern_attributes_ = false;
}
+ return Attributes();
+}
+
+bool LayoutSVGResourcePattern::FindCycleFromSelf() const {
+ NOT_DESTROYED();
+ const PatternAttributes& attributes = EnsureAttributes();
+ const SVGPatternElement* content_element = attributes.PatternContentElement();
+ if (!content_element)
+ return false;
+ const LayoutObject* content_object = content_element->GetLayoutObject();
+ DCHECK(content_object);
+ return FindCycleInDescendants(*content_object);
+}
+
+std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
+ const FloatRect& object_bounding_box) {
+ NOT_DESTROYED();
+ auto pattern_data = std::make_unique<PatternData>();
- const PatternAttributes& attributes = Attributes();
+ const PatternAttributes& attributes = EnsureAttributes();
+ // If there's no content disable rendering of the pattern.
+ if (!attributes.PatternContentElement())
+ return pattern_data;
// Spec: When the geometry of the applicable element has no width or height
// and objectBoundingBox is specified, then the given effect (e.g. a gradient
@@ -96,10 +131,6 @@ std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
object_bounding_box.IsEmpty())
return pattern_data;
- // If there's no content disable rendering of the pattern.
- if (!attributes.PatternContentElement())
- return pattern_data;
-
// Compute tile metrics.
FloatRect tile_bounds = SVGLengthContext::ResolveRectangle(
GetElement(), attributes.PatternUnits(), object_bounding_box,
@@ -161,34 +192,6 @@ bool LayoutSVGResourcePattern::ApplyShader(
return true;
}
-const LayoutSVGResourceContainer*
-LayoutSVGResourcePattern::ResolveContentElement() const {
- NOT_DESTROYED();
- DCHECK(Attributes().PatternContentElement());
- auto* expected_layout_object = To<LayoutSVGResourceContainer>(
- Attributes().PatternContentElement()->GetLayoutObject());
- // No content inheritance - avoid walking the inheritance chain.
- if (this == expected_layout_object)
- return this;
- // Walk the inheritance chain on the LayoutObject-side. If we reach the
- // expected LayoutObject, all is fine. If we don't, there's a cycle that
- // the cycle resolver did break, and the resource will be content-less.
- const LayoutSVGResourceContainer* content_layout_object = this;
- while (SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(
- *content_layout_object)) {
- LayoutSVGResourceContainer* linked_resource = resources->LinkedResource();
- if (!linked_resource)
- break;
- if (linked_resource == expected_layout_object)
- return expected_layout_object;
- content_layout_object = linked_resource;
- }
- // There was a cycle, just use this resource as the "content resource" even
- // though it will be empty (have no children).
- return this;
-}
-
sk_sp<PaintRecord> LayoutSVGResourcePattern::AsPaintRecord(
const FloatSize& size,
const AffineTransform& tile_transform) const {
@@ -201,8 +204,8 @@ sk_sp<PaintRecord> LayoutSVGResourcePattern::AsPaintRecord(
content_transform = tile_transform;
FloatRect bounds(FloatPoint(), size);
- const LayoutSVGResourceContainer* pattern_layout_object =
- ResolveContentElement();
+ const auto* pattern_layout_object = To<LayoutSVGResourceContainer>(
+ Attributes().PatternContentElement()->GetLayoutObject());
DCHECK(pattern_layout_object);
DCHECK(!pattern_layout_object->NeedsLayout());
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
index 4566993fe3d..62288372428 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
@@ -59,24 +59,23 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
}
private:
+ void WillBeDestroyed() override;
+ void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
+
+ bool FindCycleFromSelf() const override;
std::unique_ptr<PatternData> BuildPatternData(
const FloatRect& object_bounding_box);
sk_sp<PaintRecord> AsPaintRecord(const FloatSize&,
const AffineTransform&) const;
- const LayoutSVGResourceContainer* ResolveContentElement() const;
-
- bool should_collect_pattern_attributes_ : 1;
+ mutable bool should_collect_pattern_attributes_ : 1;
Persistent<PatternAttributesWrapper> attributes_wrapper_;
- PatternAttributes& MutableAttributes() {
- NOT_DESTROYED();
- return attributes_wrapper_->Attributes();
- }
const PatternAttributes& Attributes() const {
NOT_DESTROYED();
return attributes_wrapper_->Attributes();
}
+ const PatternAttributes& EnsureAttributes() const;
// FIXME: we can almost do away with this per-object map, but not quite: the
// tile size can be relative to the client bounding box, and it gets captured
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
index 847b442868d..5e88e2a0913 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
@@ -74,8 +74,12 @@ class LayoutSVGResourceRadialGradient final : public LayoutSVGResourceGradient {
}
};
-DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceRadialGradient,
- kRadialGradientResourceType);
+template <>
+struct DowncastTraits<LayoutSVGResourceRadialGradient> {
+ static bool AllowFrom(const LayoutSVGResourceContainer& container) {
+ return container.ResourceType() == kRadialGradientResourceType;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 64b8efc6855..0eee003a1c3 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -317,7 +316,6 @@ void LayoutSVGRoot::PaintReplaced(const PaintInfo& paint_info,
void LayoutSVGRoot::WillBeDestroyed() {
NOT_DESTROYED();
- SVGResourcesCache::RemoveResources(*this);
SVGResources::ClearClipPathFilterMask(To<SVGSVGElement>(*GetNode()), Style());
LayoutReplaced::WillBeDestroyed();
}
@@ -375,10 +373,8 @@ void LayoutSVGRoot::StyleDidChange(StyleDifference diff,
old_style, StyleRef());
if (!Parent())
return;
- if (diff.HasDifference()) {
- SVGResourcesCache::UpdateResources(*this);
- LayoutSVGResourceContainer::StyleDidChange(*this, diff);
- }
+ if (diff.HasDifference())
+ LayoutSVGResourceContainer::StyleChanged(*this, diff);
}
bool LayoutSVGRoot::IsChildAllowed(LayoutObject* child,
@@ -441,7 +437,7 @@ void LayoutSVGRoot::InsertedIntoTree() {
LayoutReplaced::InsertedIntoTree();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::AddResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
}
@@ -449,7 +445,7 @@ void LayoutSVGRoot::WillBeRemovedFromTree() {
NOT_DESTROYED();
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this,
false);
- if (SVGResourcesCache::RemoveResources(*this))
+ if (StyleRef().HasSVGEffect())
SetNeedsPaintPropertyUpdate();
LayoutReplaced::WillBeRemovedFromTree();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index caa30086ba6..75f469bde77 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -74,10 +74,6 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
needs_boundaries_or_transform_update_ = true;
}
- LayoutSize ContainerSize() const {
- NOT_DESTROYED();
- return container_size_;
- }
void SetContainerSize(const LayoutSize& container_size) {
NOT_DESTROYED();
// SVGImage::draw() does a view layout prior to painting,
@@ -119,7 +115,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
NOT_DESTROYED();
if (ShouldApplyViewportClip())
return kOverflowClipBothAxis;
- return LayoutBox::ComputeOverflowClipAxes();
+ return LayoutReplaced::ComputeOverflowClipAxes();
}
LayoutRect ComputeContentsVisualOverflow() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 812e89bfeff..4e3d2e5564e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -30,13 +30,12 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
#include "third_party/blink/renderer/core/layout/pointer_events_hit_rules.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
-#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
#include "third_party/blink/renderer/core/paint/svg_shape_painter.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
@@ -77,10 +76,9 @@ void LayoutSVGShape::StyleDidChange(StyleDifference diff,
// couple of additional properties that *won't* cause a layout, but are
// significant enough to require invalidating the cache.
if (!diff.NeedsFullLayout() && old_style && stroke_path_cache_) {
- const auto& old_svg_style = old_style->SvgStyle();
- const auto& svg_style = StyleRef().SvgStyle();
- if (old_svg_style.StrokeDashOffset() != svg_style.StrokeDashOffset() ||
- *old_svg_style.StrokeDashArray() != *svg_style.StrokeDashArray()) {
+ const ComputedStyle& style = StyleRef();
+ if (old_style->StrokeDashOffset() != style.StrokeDashOffset() ||
+ *old_style->StrokeDashArray() != *style.StrokeDashArray()) {
stroke_path_cache_.reset();
}
}
@@ -114,7 +112,7 @@ void LayoutSVGShape::CreatePath() {
float LayoutSVGShape::DashScaleFactor() const {
NOT_DESTROYED();
- if (StyleRef().SvgStyle().StrokeDashArray()->data.IsEmpty())
+ if (!StyleRef().HasDashArray())
return 1;
return To<SVGGeometryElement>(*GetElement()).PathLengthScaleFactor();
}
@@ -122,7 +120,7 @@ float LayoutSVGShape::DashScaleFactor() const {
void LayoutSVGShape::UpdateShapeFromElement() {
NOT_DESTROYED();
CreatePath();
- fill_bounding_box_ = GetPath().BoundingRect();
+ fill_bounding_box_ = GetPath().TightBoundingRect();
if (HasNonScalingStroke()) {
// NonScalingStrokeTransform may depend on LocalTransform which in turn may
@@ -136,11 +134,11 @@ void LayoutSVGShape::UpdateShapeFromElement() {
namespace {
-bool HasMiterJoinStyle(const SVGComputedStyle& svg_style) {
- return svg_style.JoinStyle() == kMiterJoin;
+bool HasMiterJoinStyle(const ComputedStyle& style) {
+ return style.JoinStyle() == kMiterJoin;
}
-bool HasSquareCapStyle(const SVGComputedStyle& svg_style) {
- return svg_style.CapStyle() == kSquareCap;
+bool HasSquareCapStyle(const ComputedStyle& style) {
+ return style.CapStyle() == kSquareCap;
}
} // namespace
@@ -160,14 +158,14 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
float delta = stroke_width / 2;
if (geometry_class_ != kSimple) {
- const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
- if (geometry_class_ != kNoMiters && HasMiterJoinStyle(svg_style)) {
- const float miter = svg_style.StrokeMiterLimit();
- if (miter < M_SQRT2 && HasSquareCapStyle(svg_style))
+ const ComputedStyle& style = StyleRef();
+ if (geometry_class_ != kNoMiters && HasMiterJoinStyle(style)) {
+ const float miter = style.StrokeMiterLimit();
+ if (miter < M_SQRT2 && HasSquareCapStyle(style))
delta *= M_SQRT2;
else
delta *= std::max(miter, 1.0f);
- } else if (HasSquareCapStyle(svg_style)) {
+ } else if (HasSquareCapStyle(style)) {
delta *= M_SQRT2;
}
}
@@ -177,7 +175,7 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
NOT_DESTROYED();
- if (StyleRef().SvgStyle().HasStroke())
+ if (StyleRef().HasStroke())
return stroke_bounding_box_;
return ApproximateStrokeBoundingBox(fill_bounding_box_);
}
@@ -228,22 +226,14 @@ bool LayoutSVGShape::ShapeDependentFillContains(
return GetPath().Contains(location.TransformedPoint(), fill_rule);
}
-static bool HasPaintServer(const LayoutObject& layout_object,
- const ComputedStyle& style,
- LayoutSVGResourceMode resource_mode) {
- const bool apply_to_fill = resource_mode == kApplyToFillMode;
- const SVGComputedStyle& svg_style = style.SvgStyle();
- const SVGPaint& paint =
- apply_to_fill ? svg_style.FillPaint() : svg_style.StrokePaint();
+static bool HasPaintServer(const LayoutObject& object, const SVGPaint& paint) {
if (paint.HasColor())
return true;
if (paint.HasUrl()) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- if (resources) {
- if (apply_to_fill ? resources->Fill() : resources->Stroke())
- return true;
- }
+ SVGResourceClient* client = SVGResources::GetClient(object);
+ if (GetSVGResourceAsType<LayoutSVGResourcePaintServer>(*client,
+ paint.Resource()))
+ return true;
}
return false;
}
@@ -255,7 +245,7 @@ bool LayoutSVGShape::FillContains(const HitTestLocation& location,
if (!fill_bounding_box_.Contains(location.TransformedPoint()))
return false;
- if (requires_fill && !HasPaintServer(*this, StyleRef(), kApplyToFillMode))
+ if (requires_fill && !HasPaintServer(*this, StyleRef().FillPaint()))
return false;
return ShapeDependentFillContains(location, fill_rule);
@@ -265,14 +255,14 @@ bool LayoutSVGShape::StrokeContains(const HitTestLocation& location,
bool requires_stroke) {
NOT_DESTROYED();
// "A zero value causes no stroke to be painted."
- if (StyleRef().SvgStyle().StrokeWidth().IsZero())
+ if (StyleRef().StrokeWidth().IsZero())
return false;
if (requires_stroke) {
if (!StrokeBoundingBox().Contains(location.TransformedPoint()))
return false;
- if (!HasPaintServer(*this, StyleRef(), kApplyToStrokeMode))
+ if (!HasPaintServer(*this, StyleRef().StrokePaint()))
return false;
} else {
if (!HitTestStrokeBoundingBox().Contains(location.TransformedPoint()))
@@ -431,16 +421,15 @@ bool LayoutSVGShape::HitTestShape(const HitTestRequest& request,
return true;
// TODO(chrishtr): support rect-based intersections in the cases below.
- const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
+ const ComputedStyle& style = StyleRef();
if (hit_rules.can_hit_stroke &&
- (svg_style.HasStroke() || !hit_rules.require_stroke) &&
+ (style.HasStroke() || !hit_rules.require_stroke) &&
StrokeContains(local_location, hit_rules.require_stroke))
return true;
- WindRule fill_rule = svg_style.FillRule();
+ WindRule fill_rule = style.FillRule();
if (request.SvgClipContent())
- fill_rule = svg_style.ClipRule();
- if (hit_rules.can_hit_fill &&
- (svg_style.HasFill() || !hit_rules.require_fill) &&
+ fill_rule = style.ClipRule();
+ if (hit_rules.can_hit_fill && (style.HasFill() || !hit_rules.require_fill) &&
FillContains(local_location, hit_rules.require_fill, fill_rule))
return true;
return false;
@@ -448,7 +437,7 @@ bool LayoutSVGShape::HitTestShape(const HitTestRequest& request,
FloatRect LayoutSVGShape::CalculateStrokeBoundingBox() const {
NOT_DESTROYED();
- if (!StyleRef().SvgStyle().HasStroke() || IsShapeEmpty())
+ if (!StyleRef().HasStroke() || IsShapeEmpty())
return fill_bounding_box_;
if (HasNonScalingStroke())
return CalculateNonScalingStrokeBoundingBox();
@@ -458,7 +447,7 @@ FloatRect LayoutSVGShape::CalculateStrokeBoundingBox() const {
FloatRect LayoutSVGShape::CalculateNonScalingStrokeBoundingBox() const {
NOT_DESTROYED();
DCHECK(path_);
- DCHECK(StyleRef().SvgStyle().HasStroke());
+ DCHECK(StyleRef().HasStroke());
DCHECK(HasNonScalingStroke());
FloatRect stroke_bounding_box = fill_bounding_box_;
@@ -477,7 +466,7 @@ FloatRect LayoutSVGShape::CalculateNonScalingStrokeBoundingBox() const {
float LayoutSVGShape::StrokeWidth() const {
NOT_DESTROYED();
SVGLengthContext length_context(GetElement());
- return length_context.ValueForLength(StyleRef().SvgStyle().StrokeWidth());
+ return length_context.ValueForLength(StyleRef().StrokeWidth());
}
float LayoutSVGShape::StrokeWidthForMarkerUnits() const {
@@ -506,8 +495,9 @@ LayoutSVGShapeRareData& LayoutSVGShape::EnsureRareData() const {
RasterEffectOutset LayoutSVGShape::VisualRectOutsetForRasterEffects() const {
NOT_DESTROYED();
// Account for raster expansions due to SVG stroke hairline raster effects.
- if (StyleRef().SvgStyle().HasVisibleStroke()) {
- if (StyleRef().SvgStyle().CapStyle() != kButtCap)
+ const ComputedStyle& style = StyleRef();
+ if (style.HasVisibleStroke()) {
+ if (style.CapStyle() != kButtCap)
return RasterEffectOutset::kWholePixel;
return RasterEffectOutset::kHalfPixel;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index 4ee4c921805..c20fde87e52 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -95,7 +95,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
bool HasNonScalingStroke() const {
NOT_DESTROYED();
- return StyleRef().SvgStyle().VectorEffect() == VE_NON_SCALING_STROKE;
+ return StyleRef().VectorEffect() == EVectorEffect::kNonScalingStroke;
}
const Path& NonScalingStrokePath() const {
NOT_DESTROYED();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index e930abf97bc..fa4a56c9f2b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
#include "third_party/blink/renderer/core/layout/hit_test_request.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
@@ -46,6 +47,7 @@
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/core/svg/svg_text_element.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
namespace blink {
@@ -130,6 +132,9 @@ void LayoutSVGText::SubtreeStructureChanged(
SetNeedsTextMetricsUpdate();
// TODO(fs): Restore the passing of |reason| here.
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this);
+
+ if (StyleRef().UserModify() != EUserModify::kReadOnly)
+ UseCounter::Count(GetDocument(), WebFeature::kSVGTextEdited);
}
void LayoutSVGText::NotifySubtreeStructureChanged(
@@ -162,7 +167,7 @@ static inline void CheckDescendantTextNodeConsistency(
}
void LayoutSVGText::UpdateTransformAffectsVectorEffect() {
- if (StyleRef().SvgStyle().VectorEffect() == VE_NON_SCALING_STROKE) {
+ if (StyleRef().VectorEffect() == EVectorEffect::kNonScalingStroke) {
SetTransformAffectsVectorEffect(true);
return;
}
@@ -170,9 +175,8 @@ void LayoutSVGText::UpdateTransformAffectsVectorEffect() {
SetTransformAffectsVectorEffect(false);
for (LayoutObject* descendant = FirstChild(); descendant;
descendant = descendant->NextInPreOrder(this)) {
- if (descendant->IsSVGInline() &&
- descendant->StyleRef().SvgStyle().VectorEffect() ==
- VE_NON_SCALING_STROKE) {
+ if (descendant->IsSVGInline() && descendant->StyleRef().VectorEffect() ==
+ EVectorEffect::kNonScalingStroke) {
SetTransformAffectsVectorEffect(true);
break;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
index b6573a49fa0..d4711705a10 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
@@ -36,8 +36,7 @@ PathPositionMapper::PathPositionMapper(const Path& path,
PathPositionMapper::PositionType PathPositionMapper::PointAndNormalAtLength(
float length,
- FloatPoint& point,
- float& angle) {
+ PointAndTangent& point_and_tangent) {
if (length < 0)
return kBeforePath;
if (length > path_length_)
@@ -45,7 +44,7 @@ PathPositionMapper::PositionType PathPositionMapper::PointAndNormalAtLength(
DCHECK_GE(length, 0);
DCHECK_LE(length, path_length_);
- position_calculator_.PointAndNormalAtLength(length, point, angle);
+ point_and_tangent = position_calculator_.PointAndNormalAtLength(length);
return kOnPath;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
index 6661f6dcf99..8ddf0bbe575 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
@@ -28,6 +28,8 @@
namespace blink {
+struct PointAndTangent;
+
// This class maps a 1D location in the "path space"; [0, path length] to a
// (2D) point on the path and provides the normal (angle from the x-axis) for
// said point.
@@ -44,7 +46,7 @@ class PathPositionMapper {
kBeforePath,
kAfterPath,
};
- PositionType PointAndNormalAtLength(float length, FloatPoint&, float& angle);
+ PositionType PointAndNormalAtLength(float length, PointAndTangent&);
float length() const { return path_length_; }
float StartOffset() const { return path_start_offset_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc
index 0f3944437e7..96b6b63d832 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc
@@ -91,10 +91,9 @@ SVGTransformChange LayoutSVGTransformableContainer::CalculateLocalTransform(
// attributes.
if (IsA<SVGUseElement>(element)) {
const ComputedStyle& style = StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
SVGLengthContext length_context(element);
FloatSize translation(ToFloatSize(
- length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style)));
+ length_context.ResolveLengthPair(style.X(), style.Y(), style)));
// TODO(fs): Signal this on style update instead.
if (translation != additional_translation_)
SetNeedsTransformUpdate();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
index c6d0e3a9808..7c21b485574 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
@@ -313,9 +313,9 @@ bool SVGInlineTextBox::NodeAtPoint(HitTestResult& result,
return false;
if (hit_rules.can_hit_bounding_box ||
(hit_rules.can_hit_stroke &&
- (style.SvgStyle().HasStroke() || !hit_rules.require_stroke)) ||
+ (style.HasStroke() || !hit_rules.require_stroke)) ||
(hit_rules.can_hit_fill &&
- (style.SvgStyle().HasFill() || !hit_rules.require_fill))) {
+ (style.HasFill() || !hit_rules.require_fill))) {
// Currently SVGInlineTextBox doesn't flip in blocks direction.
PhysicalRect rect{PhysicalOffset(Location()), PhysicalSize(Size())};
rect.Move(accumulated_offset);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_content_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
index b1cf4989da0..642e615b065 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
@@ -12,20 +12,22 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
namespace blink {
static void LayoutMarkerResourcesIfNeeded(LayoutObject& layout_object) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- if (!resources)
+ SVGElementResourceClient* client = SVGResources::GetClient(layout_object);
+ if (!client)
return;
- if (LayoutSVGResourceMarker* marker = resources->MarkerStart())
+ const ComputedStyle& style = layout_object.StyleRef();
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerStartResource()))
marker->LayoutIfNeeded();
- if (LayoutSVGResourceMarker* marker = resources->MarkerMid())
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerMidResource()))
marker->LayoutIfNeeded();
- if (LayoutSVGResourceMarker* marker = resources->MarkerEnd())
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerEndResource()))
marker->LayoutIfNeeded();
}
@@ -141,6 +143,16 @@ static bool HasValidBoundingBoxForContainer(const LayoutObject& object) {
return false;
}
+static FloatRect ObjectBoundsForPropagation(const LayoutObject& object) {
+ FloatRect bounds = object.ObjectBoundingBox();
+ // The local-to-parent transform for <foreignObject> contains a zoom inverse,
+ // so we need to apply zoom to the bounding box that we use for propagation to
+ // be in the correct coordinate space.
+ if (IsA<LayoutSVGForeignObject>(object))
+ bounds.Scale(object.StyleRef().EffectiveZoom());
+ return bounds;
+}
+
bool SVGContentContainer::UpdateBoundingBoxes(bool& object_bounding_box_valid) {
object_bounding_box_valid = false;
@@ -152,8 +164,9 @@ bool SVGContentContainer::UpdateBoundingBoxes(bool& object_bounding_box_valid) {
if (!HasValidBoundingBoxForContainer(*current))
continue;
const AffineTransform& transform = current->LocalToSVGParentTransform();
- UpdateObjectBoundingBox(object_bounding_box, object_bounding_box_valid,
- transform.MapRect(current->ObjectBoundingBox()));
+ UpdateObjectBoundingBox(
+ object_bounding_box, object_bounding_box_valid,
+ transform.MapRect(ObjectBoundsForPropagation(*current)));
stroke_bounding_box.Unite(transform.MapRect(current->StrokeBoundingBox()));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_hit_test_perftest.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_hit_test_perftest.cc
new file mode 100644
index 00000000000..837043fdb0d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_hit_test_perftest.cc
@@ -0,0 +1,132 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "base/timer/lap_timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_result_reporter.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
+#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/input/event_handling_util.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
+#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+namespace {
+
+constexpr int kLaps = 5000;
+constexpr int kWarmupLaps = 5;
+constexpr char kMetricCallsPerSecondRunsPerS[] = "calls_per_second";
+constexpr float kSvgWidth = 800.0f;
+constexpr float kSvgHeight = 600.0f;
+
+class SvgHitTestPerfTest : public RenderingTest {
+ public:
+ perf_test::PerfResultReporter SetUpReporter(const std::string& story) {
+ perf_test::PerfResultReporter reporter("SvgHitTestPerfTest.", story);
+ reporter.RegisterImportantMetric(kMetricCallsPerSecondRunsPerS, "runs/s");
+ return reporter;
+ }
+
+ void SetupSvgHitTest() {
+ constexpr size_t num_rows = 10;
+ constexpr size_t num_columns = 10;
+ constexpr size_t num_group_nodes_per_leaf = 100;
+ constexpr float row_stride = kSvgHeight / num_rows;
+ constexpr float column_stride = kSvgWidth / num_rows;
+
+ WTF::StringBuilder html;
+ html.AppendFormat(
+ "<svg width='%.2f' height='%.2f' viewBox='0 0 %.2f %.2f' "
+ "style='cursor: auto;'>",
+ kSvgWidth, kSvgHeight, kSvgWidth, kSvgHeight);
+
+ for (size_t row = 0; row < num_rows; ++row) {
+ for (size_t column = 0; column < num_columns; ++column) {
+ for (size_t i = 0; i < num_group_nodes_per_leaf; ++i)
+ html.Append("<g>");
+
+ html.AppendFormat(
+ "<rect id='leaf_%zu' x='%.2f' y='%.2f' width='%.2f' height='%.2f' "
+ "/>",
+ column * row, column * column_stride, row * row_stride,
+ column_stride, row_stride);
+
+ for (size_t i = 0; i < num_group_nodes_per_leaf; ++i)
+ html.Append("</g>");
+ }
+ }
+
+ html.Append("</svg>");
+
+ SetBodyInnerHTML(html.ToString());
+ }
+
+ void RunTest(const std::string& story,
+ base::RepeatingCallback<void()> test_case) {
+ base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps);
+ for (int i = 0; i < kLaps + kWarmupLaps; ++i) {
+ test_case.Run();
+ timer.NextLap();
+ }
+
+ auto reporter = SetUpReporter(story);
+ reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond());
+ }
+};
+
+} // namespace
+
+TEST_F(SvgHitTestPerfTest, HandleMouseMoveEvent) {
+ SetupSvgHitTest();
+
+ EventHandler& event_handler = GetDocument().GetFrame()->GetEventHandler();
+
+ RunTest("HandleMouseMoveEvent",
+ WTF::BindRepeating(
+ [](EventHandler& event_handler) {
+ WebMouseEvent mouse_move_event(
+ WebMouseEvent::Type::kMouseMove, gfx::PointF(1, 1),
+ gfx::PointF(1, 1), WebPointerProperties::Button::kNoButton,
+ 0, WebInputEvent::Modifiers::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests());
+ mouse_move_event.SetFrameScale(1);
+ event_handler.HandleMouseMoveEvent(mouse_move_event,
+ Vector<WebMouseEvent>(),
+ Vector<WebMouseEvent>());
+ },
+ std::ref(event_handler)));
+}
+
+TEST_F(SvgHitTestPerfTest, IntersectsClipPath) {
+ SetupSvgHitTest();
+ LayoutObject* leaf_0_layout_object = GetLayoutObjectByElementId("leaf_0");
+ ASSERT_NE(leaf_0_layout_object, nullptr);
+ LayoutObject* container = leaf_0_layout_object->Parent();
+
+ PhysicalOffset document_point =
+ event_handling_util::ContentPointFromRootFrame(GetDocument().GetFrame(),
+ FloatPoint(1, 1));
+
+ TransformedHitTestLocation local_location(
+ HitTestLocation(document_point), container->LocalToSVGParentTransform());
+ ASSERT_TRUE(local_location);
+
+ FloatRect object_bounding_box = container->ObjectBoundingBox();
+
+ RunTest(
+ "IntersectsClipPath",
+ WTF::BindRepeating(
+ [](const LayoutObject* container, FloatRect& container_bounding_box,
+ TransformedHitTestLocation& local_location) {
+ SVGLayoutSupport::IntersectsClipPath(
+ *container, container_bounding_box, *local_location);
+ },
+ WTF::Unretained(container), std::ref(object_bounding_box),
+ std::ref(local_location)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index 424bcc76c1e..55a998599ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -33,7 +33,6 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
@@ -210,10 +209,11 @@ const LayoutObject* SVGLayoutSupport::PushMappingToContainer(
if (parent->IsSVGRoot()) {
TransformationMatrix matrix(
To<LayoutSVGRoot>(parent)->LocalToBorderBoxTransform());
- matrix.Multiply(object->LocalToSVGParentTransform());
+ matrix.Multiply(TransformationMatrix(object->LocalToSVGParentTransform()));
geometry_map.Push(object, matrix);
} else {
- geometry_map.Push(object, object->LocalToSVGParentTransform());
+ geometry_map.Push(
+ object, TransformationMatrix(object->LocalToSVGParentTransform()));
}
return parent;
@@ -262,13 +262,15 @@ void SVGLayoutSupport::AdjustWithClipPathAndMask(
const LayoutObject& layout_object,
const FloatRect& object_bounding_box,
FloatRect& visual_rect) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- if (!resources)
+ SVGResourceClient* client = SVGResources::GetClient(layout_object);
+ if (!client)
return;
- if (LayoutSVGResourceClipper* clipper = resources->Clipper())
+ const ComputedStyle& style = layout_object.StyleRef();
+ if (LayoutSVGResourceClipper* clipper =
+ GetSVGResourceAsType(*client, style.ClipPath()))
visual_rect.Intersect(clipper->ResourceBoundingBox(object_bounding_box));
- if (LayoutSVGResourceMasker* masker = resources->Masker())
+ if (auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, style.MaskerResource()))
visual_rect.Intersect(masker->ResourceBoundingBox(object_bounding_box, 1));
}
@@ -277,13 +279,13 @@ FloatRect SVGLayoutSupport::ExtendTextBBoxWithStroke(
const FloatRect& text_bounds) {
DCHECK(layout_object.IsSVGText() || layout_object.IsSVGInline());
FloatRect bounds = text_bounds;
- const SVGComputedStyle& svg_style = layout_object.StyleRef().SvgStyle();
- if (svg_style.HasStroke()) {
+ const ComputedStyle& style = layout_object.StyleRef();
+ if (style.HasStroke()) {
SVGLengthContext length_context(To<SVGElement>(layout_object.GetNode()));
// TODO(fs): This approximation doesn't appear to be conservative enough
// since while text (usually?) won't have caps it could have joins and thus
// miters.
- bounds.Inflate(length_context.ValueForLength(svg_style.StrokeWidth()));
+ bounds.Inflate(length_context.ValueForLength(style.StrokeWidth()));
}
return bounds;
}
@@ -311,11 +313,10 @@ bool SVGLayoutSupport::IntersectsClipPath(const LayoutObject& object,
.Contains(location.TransformedPoint());
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(object);
- if (!resources || !resources->Clipper())
- return true;
- return resources->Clipper()->HitTestClipContent(reference_box, location);
+ SVGResourceClient* client = SVGResources::GetClient(object);
+ auto* clipper = GetSVGResourceAsType(
+ *client, To<ReferenceClipPathOperation>(*clip_path_operation));
+ return !clipper || clipper->HitTestClipContent(reference_box, location);
}
DashArray SVGLayoutSupport::ResolveSVGDashArray(
@@ -335,19 +336,16 @@ void SVGLayoutSupport::ApplyStrokeStyleToStrokeData(StrokeData& stroke_data,
DCHECK(object.GetNode());
DCHECK(object.GetNode()->IsSVGElement());
- const SVGComputedStyle& svg_style = style.SvgStyle();
-
SVGLengthContext length_context(To<SVGElement>(object.GetNode()));
- stroke_data.SetThickness(
- length_context.ValueForLength(svg_style.StrokeWidth()));
- stroke_data.SetLineCap(svg_style.CapStyle());
- stroke_data.SetLineJoin(svg_style.JoinStyle());
- stroke_data.SetMiterLimit(svg_style.StrokeMiterLimit());
+ stroke_data.SetThickness(length_context.ValueForLength(style.StrokeWidth()));
+ stroke_data.SetLineCap(style.CapStyle());
+ stroke_data.SetLineJoin(style.JoinStyle());
+ stroke_data.SetMiterLimit(style.StrokeMiterLimit());
DashArray dash_array =
- ResolveSVGDashArray(*svg_style.StrokeDashArray(), style, length_context);
+ ResolveSVGDashArray(*style.StrokeDashArray(), style, length_context);
float dash_offset =
- length_context.ValueForLength(svg_style.StrokeDashOffset(), style);
+ length_context.ValueForLength(style.StrokeDashOffset(), style);
// Apply scaling from 'pathLength'.
if (dash_scale_factor != 1) {
DCHECK_GE(dash_scale_factor, 0);
@@ -368,7 +366,7 @@ bool SVGLayoutSupport::IsLayoutableTextNode(const LayoutObject* object) {
bool SVGLayoutSupport::WillIsolateBlendingDescendantsForStyle(
const ComputedStyle& style) {
return style.HasGroupingProperty(style.BoxReflect()) ||
- style.SvgStyle().HasMasker();
+ style.MaskerResource();
}
bool SVGLayoutSupport::WillIsolateBlendingDescendantsForObject(
@@ -381,11 +379,8 @@ bool SVGLayoutSupport::WillIsolateBlendingDescendantsForObject(
}
bool SVGLayoutSupport::IsIsolationRequired(const LayoutObject* object) {
- if (SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(*object)) {
- if (resources->Masker())
- return true;
- }
+ if (object->StyleRef().MaskerResource())
+ return true;
return WillIsolateBlendingDescendantsForObject(object) &&
object->HasNonIsolatedBlendingDescendants();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
index 73ca72328e0..a4244f4edbb 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
@@ -25,7 +25,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_LAYOUT_SUPPORT_H_
#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
#include "third_party/blink/renderer/platform/graphics/dash_array.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
index 719b019ece8..84b56bff4b5 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -47,7 +47,6 @@
#include "third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
@@ -129,16 +128,6 @@ static void WriteNameAndQuotedValue(WTF::TextStream& ts,
ts << " [" << name << "=\"" << value << "\"]";
}
-static void WriteQuotedSVGResource(WTF::TextStream& ts,
- const char* name,
- const StyleSVGResource* value,
- TreeScope& tree_scope) {
- DCHECK(value);
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- value->Url(), tree_scope);
- WriteNameAndQuotedValue(ts, name, id);
-}
-
template <typename ValueType>
static void WriteIfNotDefault(WTF::TextStream& ts,
const char* name,
@@ -233,7 +222,8 @@ static WTF::TextStream& operator<<(WTF::TextStream& ts,
static void WriteSVGPaintingResource(WTF::TextStream& ts,
const SVGResource& resource) {
- const LayoutSVGResourceContainer* container = resource.ResourceContainer();
+ const LayoutSVGResourceContainer* container =
+ resource.ResourceContainerNoCycleCheck();
DCHECK(container);
switch (container->ResourceType()) {
case kPatternResourceType:
@@ -252,40 +242,27 @@ static void WriteSVGPaintingResource(WTF::TextStream& ts,
ts << " [id=\"" << resource.Target()->GetIdAttribute() << "\"]";
}
-static base::Optional<Color> ResolveColor(const ComputedStyle& style,
- const SVGPaint& paint,
- const SVGPaint& visited_paint) {
- if (!paint.HasColor())
- return base::nullopt;
- Color color = style.ResolvedColor(paint.GetColor());
- if (style.InsideLink() != EInsideLink::kInsideVisitedLink)
- return color;
- // FIXME: This code doesn't support the uri component of the visited link
- // paint, https://bugs.webkit.org/show_bug.cgi?id=70006
- if (!visited_paint.HasColor())
- return color;
- const Color& visited_color = style.ResolvedColor(visited_paint.GetColor());
- return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
- color.Alpha());
-}
-
static bool WriteSVGPaint(WTF::TextStream& ts,
- const ComputedStyle& style,
+ const LayoutObject& object,
const SVGPaint& paint,
- const SVGPaint& visited_paint,
+ const CSSProperty& property,
const char* paint_name) {
TextStreamSeparator s(" ");
+ const ComputedStyle& style = object.StyleRef();
if (const StyleSVGResource* resource = paint.Resource()) {
const SVGResource* paint_resource = resource->Resource();
- if (GetSVGResourceAsType<LayoutSVGResourcePaintServer>(paint_resource)) {
+ SVGResourceClient* client = SVGResources::GetClient(object);
+ if (GetSVGResourceAsType<LayoutSVGResourcePaintServer>(*client,
+ paint_resource)) {
ts << " [" << paint_name << "={" << s;
WriteSVGPaintingResource(ts, *paint_resource);
return true;
}
}
- if (base::Optional<Color> color = ResolveColor(style, paint, visited_paint)) {
+ if (paint.HasColor()) {
+ Color color = style.VisitedDependentColor(property);
ts << " [" << paint_name << "={" << s;
- ts << "[type=SOLID] [color=" << *color << "]";
+ ts << "[type=SOLID] [color=" << color << "]";
return true;
}
return false;
@@ -293,7 +270,6 @@ static bool WriteSVGPaint(WTF::TextStream& ts,
static void WriteStyle(WTF::TextStream& ts, const LayoutObject& object) {
const ComputedStyle& style = object.StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
if (!object.LocalSVGTransform().IsIdentity())
WriteNameValuePair(ts, "transform", object.LocalSVGTransform());
@@ -303,23 +279,22 @@ static void WriteStyle(WTF::TextStream& ts, const LayoutObject& object) {
WriteIfNotDefault(ts, "opacity", style.Opacity(),
ComputedStyleInitialValues::InitialOpacity());
if (object.IsSVGShape()) {
- if (WriteSVGPaint(ts, style, svg_style.StrokePaint(),
- svg_style.InternalVisitedStrokePaint(), "stroke")) {
+ if (WriteSVGPaint(ts, object, style.StrokePaint(), GetCSSPropertyStroke(),
+ "stroke")) {
const LayoutSVGShape& shape = static_cast<const LayoutSVGShape&>(object);
DCHECK(shape.GetElement());
SVGLengthContext length_context(shape.GetElement());
double dash_offset =
- length_context.ValueForLength(svg_style.StrokeDashOffset(), style);
- double stroke_width =
- length_context.ValueForLength(svg_style.StrokeWidth());
+ length_context.ValueForLength(style.StrokeDashOffset(), style);
+ double stroke_width = length_context.ValueForLength(style.StrokeWidth());
DashArray dash_array = SVGLayoutSupport::ResolveSVGDashArray(
- *svg_style.StrokeDashArray(), style, length_context);
+ *style.StrokeDashArray(), style, length_context);
- WriteIfNotDefault(ts, "opacity", svg_style.StrokeOpacity(), 1.0f);
+ WriteIfNotDefault(ts, "opacity", style.StrokeOpacity(), 1.0f);
WriteIfNotDefault(ts, "stroke width", stroke_width, 1.0);
- WriteIfNotDefault(ts, "miter limit", svg_style.StrokeMiterLimit(), 4.0f);
- WriteIfNotDefault(ts, "line cap", svg_style.CapStyle(), kButtCap);
- WriteIfNotDefault(ts, "line join", svg_style.JoinStyle(), kMiterJoin);
+ WriteIfNotDefault(ts, "miter limit", style.StrokeMiterLimit(), 4.0f);
+ WriteIfNotDefault(ts, "line cap", style.CapStyle(), kButtCap);
+ WriteIfNotDefault(ts, "line join", style.JoinStyle(), kMiterJoin);
WriteIfNotDefault(ts, "dash offset", dash_offset, 0.0);
if (!dash_array.IsEmpty())
WriteNameValuePair(ts, "dash array", dash_array);
@@ -327,21 +302,21 @@ static void WriteStyle(WTF::TextStream& ts, const LayoutObject& object) {
ts << "}]";
}
- if (WriteSVGPaint(ts, style, svg_style.FillPaint(),
- svg_style.InternalVisitedFillPaint(), "fill")) {
- WriteIfNotDefault(ts, "opacity", svg_style.FillOpacity(), 1.0f);
- WriteIfNotDefault(ts, "fill rule", svg_style.FillRule(), RULE_NONZERO);
+ if (WriteSVGPaint(ts, object, style.FillPaint(), GetCSSPropertyFill(),
+ "fill")) {
+ WriteIfNotDefault(ts, "opacity", style.FillOpacity(), 1.0f);
+ WriteIfNotDefault(ts, "fill rule", style.FillRule(), RULE_NONZERO);
ts << "}]";
}
- WriteIfNotDefault(ts, "clip rule", svg_style.ClipRule(), RULE_NONZERO);
+ WriteIfNotDefault(ts, "clip rule", style.ClipRule(), RULE_NONZERO);
}
TreeScope& tree_scope = object.GetDocument();
- WriteSVGResourceIfNotNull(ts, "start marker", svg_style.MarkerStartResource(),
+ WriteSVGResourceIfNotNull(ts, "start marker", style.MarkerStartResource(),
tree_scope);
- WriteSVGResourceIfNotNull(ts, "middle marker", svg_style.MarkerMidResource(),
+ WriteSVGResourceIfNotNull(ts, "middle marker", style.MarkerMidResource(),
tree_scope);
- WriteSVGResourceIfNotNull(ts, "end marker", svg_style.MarkerEndResource(),
+ WriteSVGResourceIfNotNull(ts, "end marker", style.MarkerEndResource(),
tree_scope);
}
@@ -360,14 +335,13 @@ static WTF::TextStream& operator<<(WTF::TextStream& ts,
DCHECK(svg_element);
SVGLengthContext length_context(svg_element);
const ComputedStyle& style = shape.StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
if (IsA<SVGRectElement>(*svg_element)) {
- WriteNameValuePair(ts, "x",
- length_context.ValueForLength(svg_style.X(), style,
- SVGLengthMode::kWidth));
+ WriteNameValuePair(
+ ts, "x",
+ length_context.ValueForLength(style.X(), style, SVGLengthMode::kWidth));
WriteNameValuePair(ts, "y",
- length_context.ValueForLength(svg_style.Y(), style,
+ length_context.ValueForLength(style.Y(), style,
SVGLengthMode::kHeight));
WriteNameValuePair(ts, "width",
length_context.ValueForLength(style.Width(), style,
@@ -386,34 +360,33 @@ static WTF::TextStream& operator<<(WTF::TextStream& ts,
element->y2()->CurrentValue()->Value(length_context));
} else if (IsA<SVGEllipseElement>(*svg_element)) {
WriteNameValuePair(ts, "cx",
- length_context.ValueForLength(svg_style.Cx(), style,
+ length_context.ValueForLength(style.Cx(), style,
SVGLengthMode::kWidth));
WriteNameValuePair(ts, "cy",
- length_context.ValueForLength(svg_style.Cy(), style,
+ length_context.ValueForLength(style.Cy(), style,
SVGLengthMode::kHeight));
WriteNameValuePair(ts, "rx",
- length_context.ValueForLength(svg_style.Rx(), style,
+ length_context.ValueForLength(style.Rx(), style,
SVGLengthMode::kWidth));
WriteNameValuePair(ts, "ry",
- length_context.ValueForLength(svg_style.Ry(), style,
+ length_context.ValueForLength(style.Ry(), style,
SVGLengthMode::kHeight));
} else if (IsA<SVGCircleElement>(*svg_element)) {
WriteNameValuePair(ts, "cx",
- length_context.ValueForLength(svg_style.Cx(), style,
+ length_context.ValueForLength(style.Cx(), style,
SVGLengthMode::kWidth));
WriteNameValuePair(ts, "cy",
- length_context.ValueForLength(svg_style.Cy(), style,
+ length_context.ValueForLength(style.Cy(), style,
SVGLengthMode::kHeight));
- WriteNameValuePair(ts, "r",
- length_context.ValueForLength(svg_style.R(), style,
- SVGLengthMode::kOther));
+ WriteNameValuePair(
+ ts, "r",
+ length_context.ValueForLength(style.R(), style, SVGLengthMode::kOther));
} else if (auto* svg_poly_element = DynamicTo<SVGPolyElement>(svg_element)) {
WriteNameAndQuotedValue(
ts, "points",
svg_poly_element->Points()->CurrentValue()->ValueAsString());
} else if (IsA<SVGPathElement>(*svg_element)) {
- const StylePath& path =
- svg_style.D() ? *svg_style.D() : *StylePath::EmptyPath();
+ const StylePath& path = style.D() ? *style.D() : *StylePath::EmptyPath();
WriteNameAndQuotedValue(
ts, "data",
BuildStringFromByteStream(path.ByteStream(), kNoTransformation));
@@ -458,7 +431,7 @@ static inline void WriteSVGInlineTextBox(WTF::TextStream& ts,
LineLayoutSVGInlineText text_line_layout =
LineLayoutSVGInlineText(text_box->GetLineLayoutItem());
- const SVGComputedStyle& svg_style = text_line_layout.StyleRef().SvgStyle();
+ const ComputedStyle& style = text_line_layout.StyleRef();
String text = text_box->GetLineLayoutItem().GetText();
unsigned fragments_size = fragments.size();
@@ -472,15 +445,14 @@ static inline void WriteSVGInlineTextBox(WTF::TextStream& ts,
// FIXME: Remove this hack, once the new text layout engine is completly
// landed. We want to preserve the old web test results for now.
ts << "chunk 1 ";
- ETextAnchor anchor = svg_style.TextAnchor();
- bool is_vertical_text =
- !text_line_layout.StyleRef().IsHorizontalWritingMode();
- if (anchor == TA_MIDDLE) {
+ ETextAnchor anchor = style.TextAnchor();
+ bool is_vertical_text = !style.IsHorizontalWritingMode();
+ if (anchor == ETextAnchor::kMiddle) {
ts << "(middle anchor";
if (is_vertical_text)
ts << ", vertical";
ts << ") ";
- } else if (anchor == TA_END) {
+ } else if (anchor == ETextAnchor::kEnd) {
ts << "(end anchor";
if (is_vertical_text)
ts << ", vertical";
@@ -576,12 +548,12 @@ void WriteSVGResourceContainer(WTF::TextStream& ts,
DCHECK(resource);
if (resource->ResourceType() == kMaskerResourceType) {
- LayoutSVGResourceMasker* masker = ToLayoutSVGResourceMasker(resource);
+ auto* masker = To<LayoutSVGResourceMasker>(resource);
WriteNameValuePair(ts, "maskUnits", masker->MaskUnits());
WriteNameValuePair(ts, "maskContentUnits", masker->MaskContentUnits());
ts << "\n";
} else if (resource->ResourceType() == kFilterResourceType) {
- LayoutSVGResourceFilter* filter = ToLayoutSVGResourceFilter(resource);
+ auto* filter = To<LayoutSVGResourceFilter>(resource);
WriteNameValuePair(ts, "filterUnits", filter->FilterUnits());
WriteNameValuePair(ts, "primitiveUnits", filter->PrimitiveUnits());
ts << "\n";
@@ -596,10 +568,10 @@ void WriteSVGResourceContainer(WTF::TextStream& ts,
last_effect->ExternalRepresentation(ts, indent + 1);
} else if (resource->ResourceType() == kClipperResourceType) {
WriteNameValuePair(ts, "clipPathUnits",
- ToLayoutSVGResourceClipper(resource)->ClipPathUnits());
+ To<LayoutSVGResourceClipper>(resource)->ClipPathUnits());
ts << "\n";
} else if (resource->ResourceType() == kMarkerResourceType) {
- LayoutSVGResourceMarker* marker = ToLayoutSVGResourceMarker(resource);
+ auto* marker = To<LayoutSVGResourceMarker>(resource);
WriteNameValuePair(ts, "markerUnits", marker->MarkerUnits());
ts << " [ref at " << marker->ReferencePoint() << "]";
ts << " [angle=";
@@ -643,8 +615,7 @@ void WriteSVGResourceContainer(WTF::TextStream& ts,
ts << " [start=" << gradient->StartPoint(attributes)
<< "] [end=" << gradient->EndPoint(attributes) << "]\n";
} else if (resource->ResourceType() == kRadialGradientResourceType) {
- LayoutSVGResourceRadialGradient* gradient =
- ToLayoutSVGResourceRadialGradient(resource);
+ auto* gradient = To<LayoutSVGResourceRadialGradient>(resource);
// Dump final results that are used for layout. No use in asking
// SVGGradientElement for its gradientUnits(), as it may link to other
@@ -709,7 +680,6 @@ void WriteSVGInlineText(WTF::TextStream& ts,
WriteStandardPrefix(ts, text, indent);
WritePositionAndStyle(ts, text);
ts << "\n";
- WriteResources(ts, text, indent);
WriteSVGInlineTextBoxes(ts, text, indent);
}
@@ -728,53 +698,80 @@ void Write(WTF::TextStream& ts, const LayoutSVGShape& shape, int indent) {
WriteResources(ts, shape, indent);
}
+// Get the LayoutSVGResourceFilter from the 'filter' property iff the 'filter'
+// is a single url(...) reference.
+static LayoutSVGResourceFilter* GetFilterResourceForSVG(
+ SVGResourceClient& client,
+ const ComputedStyle& style) {
+ if (!style.HasFilter())
+ return nullptr;
+ const FilterOperations& operations = style.Filter();
+ if (operations.size() != 1)
+ return nullptr;
+ const auto* reference_filter =
+ DynamicTo<ReferenceFilterOperation>(*operations.at(0));
+ if (!reference_filter)
+ return nullptr;
+ return GetSVGResourceAsType<LayoutSVGResourceFilter>(
+ client, reference_filter->Resource());
+}
+
+static void WriteSVGResourceReferencePrefix(
+ WTF::TextStream& ts,
+ const char* resource_name,
+ const LayoutSVGResourceContainer* resource_object,
+ const AtomicString& url,
+ const TreeScope& tree_scope,
+ int indent) {
+ AtomicString id =
+ SVGURIReference::FragmentIdentifierFromIRIString(url, tree_scope);
+ WriteIndent(ts, indent);
+ ts << " ";
+ WriteNameAndQuotedValue(ts, resource_name, id);
+ ts << " ";
+ WriteStandardPrefix(ts, *resource_object, 0);
+}
+
void WriteResources(WTF::TextStream& ts,
const LayoutObject& object,
int indent) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(object);
- if (!resources)
- return;
const FloatRect reference_box = object.ObjectBoundingBox();
const ComputedStyle& style = object.StyleRef();
TreeScope& tree_scope = object.GetDocument();
- if (LayoutSVGResourceMasker* masker = resources->Masker()) {
- WriteIndent(ts, indent);
- ts << " ";
- WriteQuotedSVGResource(ts, "masker", style.SvgStyle().MaskerResource(),
- tree_scope);
- ts << " ";
- WriteStandardPrefix(ts, *masker, 0);
+ SVGResourceClient* client = SVGResources::GetClient(object);
+ if (!client)
+ return;
+ if (auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, style.MaskerResource())) {
+ WriteSVGResourceReferencePrefix(ts, "masker", masker,
+ style.MaskerResource()->Url(), tree_scope,
+ indent);
ts << " " << masker->ResourceBoundingBox(reference_box, 1) << "\n";
}
- if (LayoutSVGResourceClipper* clipper = resources->Clipper()) {
- DCHECK(style.ClipPath());
- DCHECK_EQ(style.ClipPath()->GetType(), ClipPathOperation::REFERENCE);
- const ReferenceClipPathOperation& clip_path_reference =
- To<ReferenceClipPathOperation>(*style.ClipPath());
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- clip_path_reference.Url(), tree_scope);
- WriteIndent(ts, indent);
- ts << " ";
- WriteNameAndQuotedValue(ts, "clipPath", id);
- ts << " ";
- WriteStandardPrefix(ts, *clipper, 0);
- ts << " " << clipper->ResourceBoundingBox(reference_box) << "\n";
+ if (const ClipPathOperation* clip_path = style.ClipPath()) {
+ if (LayoutSVGResourceClipper* clipper =
+ GetSVGResourceAsType(*client, clip_path)) {
+ DCHECK_EQ(clip_path->GetType(), ClipPathOperation::REFERENCE);
+ const auto& clip_path_reference =
+ To<ReferenceClipPathOperation>(*clip_path);
+ WriteSVGResourceReferencePrefix(ts, "clipPath", clipper,
+ clip_path_reference.Url(), tree_scope,
+ indent);
+ ts << " " << clipper->ResourceBoundingBox(reference_box) << "\n";
+ }
}
- if (LayoutSVGResourceFilter* filter = GetFilterResourceForSVG(style)) {
+ // TODO(fs): Only handles the single url(...) case. Do we care?
+ if (LayoutSVGResourceFilter* filter =
+ GetFilterResourceForSVG(*client, style)) {
DCHECK(style.HasFilter());
DCHECK_EQ(style.Filter().size(), 1u);
const FilterOperation& filter_operation = *style.Filter().at(0);
DCHECK_EQ(filter_operation.GetType(), FilterOperation::REFERENCE);
const auto& reference_filter_operation =
To<ReferenceFilterOperation>(filter_operation);
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- reference_filter_operation.Url(), tree_scope);
- WriteIndent(ts, indent);
- ts << " ";
- WriteNameAndQuotedValue(ts, "filter", id);
- ts << " ";
- WriteStandardPrefix(ts, *filter, 0);
+ WriteSVGResourceReferencePrefix(ts, "filter", filter,
+ reference_filter_operation.Url(),
+ tree_scope, indent);
ts << " " << filter->ResourceBoundingBox(reference_box) << "\n";
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index 988c1c9b70c..31f880fb4ad 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -19,41 +19,25 @@
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include <memory>
-#include <utility>
-
+#include "base/ranges/algorithm.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h"
-#include "third_party/blink/renderer/core/svg/svg_pattern_element.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
-#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
-#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
-#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter_effect.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/graphics/filters/source_graphic.h"
-#if DCHECK_IS_ON()
-#include <stdio.h>
-#endif
-
namespace blink {
-SVGResources::SVGResources() : linked_resource_(nullptr) {}
-
SVGElementResourceClient* SVGResources::GetClient(const LayoutObject& object) {
return To<SVGElement>(object.GetNode())->GetSVGResourceClient();
}
@@ -79,451 +63,6 @@ FloatRect SVGResources::ReferenceBoxForEffects(
return obb_layout_object->ObjectBoundingBox();
}
-static HashSet<AtomicString>& ClipperFilterMaskerTags() {
- DEFINE_STATIC_LOCAL(
- HashSet<AtomicString>, tag_list,
- ({
- // "container elements":
- // http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
- // "graphics elements" :
- // http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
- svg_names::kATag.LocalName(), svg_names::kCircleTag.LocalName(),
- svg_names::kEllipseTag.LocalName(), svg_names::kGTag.LocalName(),
- svg_names::kImageTag.LocalName(), svg_names::kLineTag.LocalName(),
- svg_names::kMarkerTag.LocalName(), svg_names::kMaskTag.LocalName(),
- svg_names::kPathTag.LocalName(), svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(), svg_names::kRectTag.LocalName(),
- svg_names::kSVGTag.LocalName(), svg_names::kTextTag.LocalName(),
- svg_names::kUseTag.LocalName(),
- // Not listed in the definitions is the clipPath element, the SVG spec
- // says though:
- // The "clipPath" element or any of its children can specify property
- // "clip-path".
- // So we have to add kClipPathTag here, otherwhise clip-path on
- // clipPath will fail. (Already mailed SVG WG, waiting for a solution)
- svg_names::kClipPathTag.LocalName(),
- // Not listed in the definitions are the text content elements, though
- // filter/clipper/masker on tspan/text/.. is allowed.
- // (Already mailed SVG WG, waiting for a solution)
- svg_names::kTextPathTag.LocalName(), svg_names::kTSpanTag.LocalName(),
- // Not listed in the definitions is the foreignObject element, but
- // clip-path is a supported attribute.
- svg_names::kForeignObjectTag.LocalName(),
- // Elements that we ignore, as it doesn't make any sense.
- // defs, pattern, switch (FIXME: Mail SVG WG about these)
- // symbol (is converted to a svg element, when referenced by use, we
- // can safely ignore it.)
- }));
- return tag_list;
-}
-
-bool SVGResources::SupportsMarkers(const SVGElement& element) {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list,
- ({
- svg_names::kLineTag.LocalName(),
- svg_names::kPathTag.LocalName(),
- svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(),
- }));
- return tag_list.Contains(element.localName());
-}
-
-static HashSet<AtomicString>& FillAndStrokeTags() {
- DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list,
- ({
- svg_names::kCircleTag.LocalName(),
- svg_names::kEllipseTag.LocalName(),
- svg_names::kLineTag.LocalName(),
- svg_names::kPathTag.LocalName(),
- svg_names::kPolygonTag.LocalName(),
- svg_names::kPolylineTag.LocalName(),
- svg_names::kRectTag.LocalName(),
- svg_names::kTextTag.LocalName(),
- svg_names::kTextPathTag.LocalName(),
- svg_names::kTSpanTag.LocalName(),
- }));
- return tag_list;
-}
-
-bool SVGResources::HasResourceData() const {
- return clipper_filter_masker_data_ || marker_data_ || fill_stroke_data_ ||
- linked_resource_;
-}
-
-static inline SVGResources& EnsureResources(
- std::unique_ptr<SVGResources>& resources) {
- if (!resources)
- resources = std::make_unique<SVGResources>();
-
- return *resources.get();
-}
-
-std::unique_ptr<SVGResources> SVGResources::BuildResources(
- const LayoutObject& object,
- const ComputedStyle& computed_style) {
- Node* node = object.GetNode();
- DCHECK(node);
- SECURITY_DCHECK(node->IsSVGElement());
-
- auto& element = To<SVGElement>(*node);
-
- const AtomicString& tag_name = element.localName();
- DCHECK(!tag_name.IsNull());
-
- const SVGComputedStyle& style = computed_style.SvgStyle();
-
- std::unique_ptr<SVGResources> resources;
- if (ClipperFilterMaskerTags().Contains(tag_name)) {
- if (computed_style.ClipPath() && !object.IsSVGRoot()) {
- if (LayoutSVGResourceClipper* clipper =
- GetSVGResourceAsType(computed_style.ClipPath())) {
- EnsureResources(resources).SetClipper(clipper);
- }
- }
-
- if (computed_style.HasFilter() && !object.IsSVGRoot()) {
- if (LayoutSVGResourceFilter* filter =
- GetFilterResourceForSVG(computed_style)) {
- EnsureResources(resources).SetFilter(filter);
- }
- }
-
- if (auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
- style.MaskerResource())) {
- EnsureResources(resources).SetMasker(masker);
- }
- }
-
- if (style.HasMarkers() && SupportsMarkers(element)) {
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerStartResource())) {
- EnsureResources(resources).SetMarkerStart(marker);
- }
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerMidResource())) {
- EnsureResources(resources).SetMarkerMid(marker);
- }
- if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
- style.MarkerEndResource())) {
- EnsureResources(resources).SetMarkerEnd(marker);
- }
- }
-
- if (FillAndStrokeTags().Contains(tag_name)) {
- if (auto* paint_resource =
- GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
- style.FillPaint().Resource())) {
- EnsureResources(resources).SetFill(paint_resource);
- }
-
- if (auto* paint_resource =
- GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
- style.StrokePaint().Resource())) {
- EnsureResources(resources).SetStroke(paint_resource);
- }
- }
-
- if (auto* pattern = DynamicTo<SVGPatternElement>(element)) {
- const SVGPatternElement* directly_referenced_pattern =
- pattern->ReferencedElement();
- if (directly_referenced_pattern) {
- EnsureResources(resources).SetLinkedResource(
- DynamicTo<LayoutSVGResourceContainer>(
- directly_referenced_pattern->GetLayoutObject()));
- }
- }
-
- return (!resources || !resources->HasResourceData()) ? nullptr
- : std::move(resources);
-}
-
-void SVGResources::ResourceDestroyed(LayoutSVGResourceContainer* resource) {
- DCHECK(resource);
- if (!HasResourceData())
- return;
-
- if (linked_resource_ == resource) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- linked_resource_->RemoveAllClientsFromCache();
- linked_resource_ = nullptr;
- return;
- }
-
- switch (resource->ResourceType()) {
- case kMaskerResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->masker == resource)
- clipper_filter_masker_data_->masker = nullptr;
- break;
- case kMarkerResourceType:
- if (!marker_data_)
- break;
- if (marker_data_->marker_start == resource)
- marker_data_->marker_start = nullptr;
- if (marker_data_->marker_mid == resource)
- marker_data_->marker_mid = nullptr;
- if (marker_data_->marker_end == resource)
- marker_data_->marker_end = nullptr;
- break;
- case kPatternResourceType:
- case kLinearGradientResourceType:
- case kRadialGradientResourceType:
- if (!fill_stroke_data_)
- break;
- if (fill_stroke_data_->fill == resource)
- fill_stroke_data_->fill = nullptr;
- if (fill_stroke_data_->stroke == resource)
- fill_stroke_data_->stroke = nullptr;
- break;
- case kFilterResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->filter == resource)
- clipper_filter_masker_data_->filter = nullptr;
- break;
- case kClipperResourceType:
- if (!clipper_filter_masker_data_)
- break;
- if (clipper_filter_masker_data_->clipper == resource)
- clipper_filter_masker_data_->clipper = nullptr;
- break;
- default:
- NOTREACHED();
- }
-}
-
-void SVGResources::ClearReferencesTo(LayoutSVGResourceContainer* resource) {
- DCHECK(resource);
- if (linked_resource_ == resource) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- linked_resource_ = nullptr;
- return;
- }
-
- switch (resource->ResourceType()) {
- case kMaskerResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->masker, resource);
- clipper_filter_masker_data_->masker = nullptr;
- break;
- case kMarkerResourceType:
- DCHECK(marker_data_);
- DCHECK(resource == MarkerStart() || resource == MarkerMid() ||
- resource == MarkerEnd());
- if (marker_data_->marker_start == resource)
- marker_data_->marker_start = nullptr;
- if (marker_data_->marker_mid == resource)
- marker_data_->marker_mid = nullptr;
- if (marker_data_->marker_end == resource)
- marker_data_->marker_end = nullptr;
- break;
- case kPatternResourceType:
- case kLinearGradientResourceType:
- case kRadialGradientResourceType:
- DCHECK(fill_stroke_data_);
- DCHECK(resource == Fill() || resource == Stroke());
- if (fill_stroke_data_->fill == resource)
- fill_stroke_data_->fill = nullptr;
- if (fill_stroke_data_->stroke == resource)
- fill_stroke_data_->stroke = nullptr;
- break;
- case kFilterResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->filter, resource);
- clipper_filter_masker_data_->filter = nullptr;
- break;
- case kClipperResourceType:
- DCHECK(clipper_filter_masker_data_);
- DCHECK_EQ(clipper_filter_masker_data_->clipper, resource);
- clipper_filter_masker_data_->clipper = nullptr;
- break;
- default:
- NOTREACHED();
- }
-}
-
-void SVGResources::BuildSetOfResources(
- HashSet<LayoutSVGResourceContainer*>& set) {
- if (!HasResourceData())
- return;
-
- if (linked_resource_) {
- DCHECK(!clipper_filter_masker_data_);
- DCHECK(!marker_data_);
- DCHECK(!fill_stroke_data_);
- set.insert(linked_resource_);
- return;
- }
-
- if (clipper_filter_masker_data_) {
- if (clipper_filter_masker_data_->clipper)
- set.insert(clipper_filter_masker_data_->clipper);
- if (clipper_filter_masker_data_->filter)
- set.insert(clipper_filter_masker_data_->filter);
- if (clipper_filter_masker_data_->masker)
- set.insert(clipper_filter_masker_data_->masker);
- }
-
- if (marker_data_) {
- if (marker_data_->marker_start)
- set.insert(marker_data_->marker_start);
- if (marker_data_->marker_mid)
- set.insert(marker_data_->marker_mid);
- if (marker_data_->marker_end)
- set.insert(marker_data_->marker_end);
- }
-
- if (fill_stroke_data_) {
- if (fill_stroke_data_->fill)
- set.insert(fill_stroke_data_->fill);
- if (fill_stroke_data_->stroke)
- set.insert(fill_stroke_data_->stroke);
- }
-}
-
-void SVGResources::SetClipper(LayoutSVGResourceClipper* clipper) {
- DCHECK(clipper);
- DCHECK_EQ(clipper->ResourceType(), kClipperResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->clipper = clipper;
-}
-
-void SVGResources::SetFilter(LayoutSVGResourceFilter* filter) {
- DCHECK(filter);
- DCHECK_EQ(filter->ResourceType(), kFilterResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->filter = filter;
-}
-
-void SVGResources::SetMarkerStart(LayoutSVGResourceMarker* marker_start) {
- DCHECK(marker_start);
- DCHECK_EQ(marker_start->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_start = marker_start;
-}
-
-void SVGResources::SetMarkerMid(LayoutSVGResourceMarker* marker_mid) {
- DCHECK(marker_mid);
- DCHECK_EQ(marker_mid->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_mid = marker_mid;
-}
-
-void SVGResources::SetMarkerEnd(LayoutSVGResourceMarker* marker_end) {
- DCHECK(marker_end);
- DCHECK_EQ(marker_end->ResourceType(), kMarkerResourceType);
-
- if (!marker_data_)
- marker_data_ = std::make_unique<MarkerData>();
-
- marker_data_->marker_end = marker_end;
-}
-
-void SVGResources::SetMasker(LayoutSVGResourceMasker* masker) {
- DCHECK(masker);
- DCHECK_EQ(masker->ResourceType(), kMaskerResourceType);
-
- if (!clipper_filter_masker_data_)
- clipper_filter_masker_data_ = std::make_unique<ClipperFilterMaskerData>();
-
- clipper_filter_masker_data_->masker = masker;
-}
-
-void SVGResources::SetFill(LayoutSVGResourcePaintServer* fill) {
- DCHECK(fill);
-
- if (!fill_stroke_data_)
- fill_stroke_data_ = std::make_unique<FillStrokeData>();
-
- fill_stroke_data_->fill = fill;
-}
-
-void SVGResources::SetStroke(LayoutSVGResourcePaintServer* stroke) {
- DCHECK(stroke);
-
- if (!fill_stroke_data_)
- fill_stroke_data_ = std::make_unique<FillStrokeData>();
-
- fill_stroke_data_->stroke = stroke;
-}
-
-void SVGResources::SetLinkedResource(
- LayoutSVGResourceContainer* linked_resource) {
- if (!linked_resource)
- return;
-
- linked_resource_ = linked_resource;
-}
-
-#if DCHECK_IS_ON()
-void SVGResources::Dump(const LayoutObject* object) {
- DCHECK(object);
- DCHECK(object->GetNode());
-
- fprintf(stderr, "-> this=%p, SVGResources(layoutObject=%p, node=%p)\n", this,
- object, object->GetNode());
- fprintf(stderr, " | DOM Tree:\n");
- fprintf(stderr, "%s",
- object->GetNode()->ToTreeStringForThis().Utf8().c_str());
-
- fprintf(stderr, "\n | List of resources:\n");
- if (clipper_filter_masker_data_) {
- if (LayoutSVGResourceClipper* clipper =
- clipper_filter_masker_data_->clipper)
- fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper,
- clipper->GetElement());
- if (LayoutSVGResourceFilter* filter = clipper_filter_masker_data_->filter)
- fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter,
- filter->GetElement());
- if (LayoutSVGResourceMasker* masker = clipper_filter_masker_data_->masker)
- fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker,
- masker->GetElement());
- }
-
- if (marker_data_) {
- if (LayoutSVGResourceMarker* marker_start = marker_data_->marker_start)
- fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", marker_start,
- marker_start->GetElement());
- if (LayoutSVGResourceMarker* marker_mid = marker_data_->marker_mid)
- fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", marker_mid,
- marker_mid->GetElement());
- if (LayoutSVGResourceMarker* marker_end = marker_data_->marker_end)
- fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", marker_end,
- marker_end->GetElement());
- }
-
- if (fill_stroke_data_) {
- if (LayoutSVGResourcePaintServer* fill = fill_stroke_data_->fill)
- fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill,
- fill->GetElement());
- if (LayoutSVGResourcePaintServer* stroke = fill_stroke_data_->stroke)
- fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke,
- stroke->GetElement());
- }
-
- if (linked_resource_)
- fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", linked_resource_,
- linked_resource_->GetElement());
-}
-#endif
-
void SVGResources::UpdateClipPathFilterMask(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
@@ -543,7 +82,7 @@ void SVGResources::UpdateClipPathFilterMask(SVGElement& element,
layout_object->SetNeedsPaintPropertyUpdate();
client.MarkFilterDataDirty();
}
- if (StyleSVGResource* masker_resource = style.SvgStyle().MaskerResource())
+ if (StyleSVGResource* masker_resource = style.MaskerResource())
masker_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearClipPathFilterMask(element, old_style);
@@ -563,7 +102,7 @@ void SVGResources::ClearClipPathFilterMask(SVGElement& element,
style->Filter().RemoveClient(*client);
client->InvalidateFilterData();
}
- if (StyleSVGResource* masker_resource = style->SvgStyle().MaskerResource())
+ if (StyleSVGResource* masker_resource = style->MaskerResource())
masker_resource->RemoveClient(*client);
}
@@ -571,10 +110,9 @@ void SVGResources::UpdatePaints(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
const bool had_client = element.GetSVGResourceClient();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- if (StyleSVGResource* paint_resource = svg_style.FillPaint().Resource())
+ if (StyleSVGResource* paint_resource = style.FillPaint().Resource())
paint_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* paint_resource = svg_style.StrokePaint().Resource())
+ if (StyleSVGResource* paint_resource = style.StrokePaint().Resource())
paint_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearPaints(element, old_style);
@@ -587,10 +125,9 @@ void SVGResources::ClearPaints(SVGElement& element,
SVGResourceClient* client = element.GetSVGResourceClient();
if (!client)
return;
- const SVGComputedStyle& old_svg_style = style->SvgStyle();
- if (StyleSVGResource* paint_resource = old_svg_style.FillPaint().Resource())
+ if (StyleSVGResource* paint_resource = style->FillPaint().Resource())
paint_resource->RemoveClient(*client);
- if (StyleSVGResource* paint_resource = old_svg_style.StrokePaint().Resource())
+ if (StyleSVGResource* paint_resource = style->StrokePaint().Resource())
paint_resource->RemoveClient(*client);
}
@@ -598,12 +135,11 @@ void SVGResources::UpdateMarkers(SVGElement& element,
const ComputedStyle* old_style,
const ComputedStyle& style) {
const bool had_client = element.GetSVGResourceClient();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- if (StyleSVGResource* marker_resource = svg_style.MarkerStartResource())
+ if (StyleSVGResource* marker_resource = style.MarkerStartResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* marker_resource = svg_style.MarkerMidResource())
+ if (StyleSVGResource* marker_resource = style.MarkerMidResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
- if (StyleSVGResource* marker_resource = svg_style.MarkerEndResource())
+ if (StyleSVGResource* marker_resource = style.MarkerEndResource())
marker_resource->AddClient(element.EnsureSVGResourceClient());
if (had_client)
ClearMarkers(element, old_style);
@@ -616,58 +152,93 @@ void SVGResources::ClearMarkers(SVGElement& element,
SVGResourceClient* client = element.GetSVGResourceClient();
if (!client)
return;
- const SVGComputedStyle& old_svg_style = style->SvgStyle();
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerStartResource())
+ if (StyleSVGResource* marker_resource = style->MarkerStartResource())
marker_resource->RemoveClient(*client);
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerMidResource())
+ if (StyleSVGResource* marker_resource = style->MarkerMidResource())
marker_resource->RemoveClient(*client);
- if (StyleSVGResource* marker_resource = old_svg_style.MarkerEndResource())
+ if (StyleSVGResource* marker_resource = style->MarkerEndResource())
marker_resource->RemoveClient(*client);
}
-sk_sp<PaintFilter> FilterData::BuildPaintFilter() {
- return paint_filter_builder::Build(last_effect_, kInterpolationSpaceSRGB);
-}
+class SVGElementResourceClient::FilterData final
+ : public GarbageCollected<SVGElementResourceClient::FilterData> {
+ public:
+ FilterData(FilterEffect* last_effect, SVGFilterGraphNodeMap* node_map)
+ : last_effect_(last_effect), node_map_(node_map) {}
-bool FilterData::Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
- const QualifiedName& attribute) {
- if (FilterEffect* effect = node_map_->EffectForElement(primitive)) {
- if (!primitive.SetFilterEffectAttribute(effect, attribute))
- return false; // No change
- node_map_->InvalidateDependentEffects(effect);
+ sk_sp<PaintFilter> BuildPaintFilter() {
+ return paint_filter_builder::Build(last_effect_, kInterpolationSpaceSRGB);
}
- return true;
-}
-void FilterData::Trace(Visitor* visitor) const {
- visitor->Trace(last_effect_);
- visitor->Trace(node_map_);
-}
+ // Perform a finegrained invalidation of the filter chain for the
+ // specified filter primitive and attribute. Returns false if no
+ // further invalidation is required, otherwise true.
+ bool Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute) {
+ if (FilterEffect* effect = node_map_->EffectForElement(primitive)) {
+ if (!primitive.SetFilterEffectAttribute(effect, attribute))
+ return false; // No change
+ node_map_->InvalidateDependentEffects(effect);
+ }
+ return true;
+ }
-void FilterData::Dispose() {
- node_map_ = nullptr;
- if (last_effect_)
- last_effect_->DisposeImageFiltersRecursive();
- last_effect_ = nullptr;
-}
+ void Dispose() {
+ node_map_ = nullptr;
+ if (last_effect_)
+ last_effect_->DisposeImageFiltersRecursive();
+ last_effect_ = nullptr;
+ }
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(last_effect_);
+ visitor->Trace(node_map_);
+ }
+
+ private:
+ Member<FilterEffect> last_effect_;
+ Member<SVGFilterGraphNodeMap> node_map_;
+};
SVGElementResourceClient::SVGElementResourceClient(SVGElement* element)
: element_(element), filter_data_dirty_(false) {}
-void SVGElementResourceClient::ResourceContentChanged(
- InvalidationModeMask invalidation_mask) {
+namespace {
+
+template <typename ContainerType>
+bool ContainsResource(const ContainerType* container, SVGResource* resource) {
+ return container && container->Resource() == resource;
+}
+
+bool ContainsResource(const FilterOperations& operations,
+ SVGResource* resource) {
+ return base::ranges::any_of(
+ operations.Operations(), [resource](const FilterOperation* operation) {
+ return ContainsResource(DynamicTo<ReferenceFilterOperation>(operation),
+ resource);
+ });
+}
+
+} // namespace
+
+void SVGElementResourceClient::ResourceContentChanged(SVGResource* resource) {
LayoutObject* layout_object = element_->GetLayoutObject();
if (!layout_object)
return;
- if (layout_object->IsSVGResourceContainer()) {
- To<LayoutSVGResourceContainer>(layout_object)->RemoveAllClientsFromCache();
- return;
- }
- if (invalidation_mask & SVGResourceClient::kFilterCacheInvalidation)
+ const ComputedStyle& style = layout_object->StyleRef();
+ if (style.HasFilter() && ContainsResource(style.Filter(), resource)) {
InvalidateFilterData();
+ layout_object->SetShouldDoFullPaintInvalidation();
+ }
+
+ if (auto* container = DynamicTo<LayoutSVGResourceContainer>(layout_object)) {
+ container->RemoveAllClientsFromCache();
+ return;
+ }
- if (invalidation_mask & SVGResourceClient::kPaintInvalidation) {
+ if (ContainsResource(style.FillPaint().Resource(), resource) ||
+ ContainsResource(style.StrokePaint().Resource(), resource)) {
// Since LayoutSVGInlineTexts don't have SVGResources (they use their
// parent's), they will not be notified of changes to paint servers. So
// if the client is one that could have a LayoutSVGInlineText use a
@@ -677,48 +248,34 @@ void SVGElementResourceClient::ResourceContentChanged(
PaintInvalidationReason::kSVGResource);
}
- if (invalidation_mask & SVGResourceClient::kClipCacheInvalidation)
+ bool needs_layout = false;
+ if (ContainsResource(style.MarkerStartResource(), resource) ||
+ ContainsResource(style.MarkerMidResource(), resource) ||
+ ContainsResource(style.MarkerEndResource(), resource)) {
+ needs_layout = true;
+ layout_object->SetNeedsBoundariesUpdate();
+ }
+
+ const auto* clip_reference =
+ DynamicTo<ReferenceClipPathOperation>(style.ClipPath());
+ if (ContainsResource(clip_reference, resource)) {
+ // TODO(fs): "Downgrade" to non-subtree?
+ layout_object->SetSubtreeShouldDoFullPaintInvalidation();
layout_object->InvalidateClipPathCache();
+ }
- // Invalidate paint properties to update effects if any.
- if (invalidation_mask & SVGResourceClient::kPaintPropertiesInvalidation)
+ if (ContainsResource(style.MaskerResource(), resource)) {
+ // TODO(fs): "Downgrade" to non-subtree?
+ layout_object->SetSubtreeShouldDoFullPaintInvalidation();
layout_object->SetNeedsPaintPropertyUpdate();
+ }
- if (invalidation_mask & SVGResourceClient::kBoundariesInvalidation)
- layout_object->SetNeedsBoundariesUpdate();
-
- bool needs_layout =
- invalidation_mask & SVGResourceClient::kLayoutInvalidation;
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
*layout_object, needs_layout);
}
-void SVGElementResourceClient::ResourceElementChanged() {
- LayoutObject* layout_object = element_->GetLayoutObject();
- if (!layout_object)
- return;
- // TODO(fs): If the resource element (for a filter) doesn't actually change
- // we don't need to perform the associated invalidations.
- InvalidateFilterData();
- if (layout_object->Parent()) {
- SVGResourcesCache::UpdateResources(*layout_object);
- LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
- *layout_object, true);
- }
-}
-
-void SVGElementResourceClient::ResourceDestroyed(
- LayoutSVGResourceContainer* resource) {
- LayoutObject* layout_object = element_->GetLayoutObject();
- if (!layout_object)
- return;
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(*layout_object);
- if (resources)
- resources->ResourceDestroyed(resource);
-}
-
void SVGElementResourceClient::FilterPrimitiveChanged(
+ SVGResource* resource,
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
if (filter_data_ && !filter_data_->Invalidate(primitive, attribute))
@@ -730,7 +287,8 @@ void SVGElementResourceClient::FilterPrimitiveChanged(
MarkFilterDataDirty();
}
-static FilterData* CreateFilterDataWithNodeMap(
+SVGElementResourceClient::FilterData*
+SVGElementResourceClient::CreateFilterDataWithNodeMap(
FilterEffectBuilder& builder,
const ReferenceFilterOperation& reference_filter) {
auto* node_map = MakeGarbageCollected<SVGFilterGraphNodeMap>();
@@ -751,19 +309,35 @@ void SVGElementResourceClient::UpdateFilterData(
if (!operations.IsEmpty() && !filter_data_dirty_ &&
reference_box == operations.ReferenceBox())
return;
- if (!filter_data_ && GetFilterResourceForSVG(object.StyleRef())) {
- FilterEffectBuilder builder(reference_box, 1);
- filter_data_ = CreateFilterDataWithNodeMap(
- builder,
- To<ReferenceFilterOperation>(*object.StyleRef().Filter().at(0)));
- }
- operations.Clear();
- if (filter_data_) {
- operations.AppendReferenceFilter(filter_data_->BuildPaintFilter());
+ const ComputedStyle& style = object.StyleRef();
+ FilterEffectBuilder builder(reference_box, 1);
+ builder.SetShorthandScale(1 / style.EffectiveZoom());
+ const FilterOperations& filter = style.Filter();
+ // If the filter is a single 'url(...)' reference we can optimize some
+ // mutations to the referenced filter chain by tracking the filter
+ // dependencies and only perform partial invalidations of the filter chain.
+ const bool is_single_reference_filter =
+ filter.size() == 1 && IsA<ReferenceFilterOperation>(*filter.at(0));
+ if (is_single_reference_filter) {
+ if (!filter_data_) {
+ filter_data_ = CreateFilterDataWithNodeMap(
+ builder, To<ReferenceFilterOperation>(*filter.at(0)));
+ }
+ operations.Clear();
+ if (filter_data_) {
+ operations.AppendReferenceFilter(filter_data_->BuildPaintFilter());
+ } else {
+ // Filter construction failed. Create a filter chain that yields
+ // transparent black.
+ operations.AppendOpacityFilter(0);
+ }
} else {
- // Filter construction failed. Create a filter chain that yields
- // transparent black.
- operations.AppendOpacityFilter(0);
+ // Drop any existing filter data since the filter is no longer
+ // cacheable.
+ if (FilterData* filter_data = filter_data_.Release())
+ filter_data->Dispose();
+
+ operations = builder.BuildFilterOperations(filter);
}
operations.SetReferenceBox(reference_box);
filter_data_dirty_ = false;
@@ -794,34 +368,37 @@ void SVGElementResourceClient::Trace(Visitor* visitor) const {
}
SVGResourceInvalidator::SVGResourceInvalidator(LayoutObject& object)
- : resources_(SVGResourcesCache::CachedResourcesForLayoutObject(object)),
- object_(object) {}
+ : object_(object) {}
void SVGResourceInvalidator::InvalidateEffects() {
- if (!resources_)
- return;
- if (resources_->Filter())
- SVGResources::GetClient(object_)->InvalidateFilterData();
- if (resources_->Clipper()) {
+ const ComputedStyle& style = object_.StyleRef();
+ if (style.HasFilter()) {
+ if (SVGElementResourceClient* client = SVGResources::GetClient(object_))
+ client->InvalidateFilterData();
+ }
+ if (style.HasClipPath()) {
object_.SetShouldDoFullPaintInvalidation();
object_.InvalidateClipPathCache();
}
- if (resources_->Masker()) {
+ if (style.MaskerResource()) {
object_.SetShouldDoFullPaintInvalidation();
object_.SetNeedsPaintPropertyUpdate();
}
}
void SVGResourceInvalidator::InvalidatePaints() {
- if (!resources_)
+ SVGElementResourceClient* client = SVGResources::GetClient(object_);
+ if (!client)
return;
bool needs_invalidation = false;
- SVGElementResourceClient* client = SVGResources::GetClient(object_);
- if (LayoutSVGResourcePaintServer* fill = resources_->Fill()) {
+ const ComputedStyle& style = object_.StyleRef();
+ if (auto* fill = GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ *client, style.FillPaint().Resource())) {
fill->RemoveClientFromCache(*client);
needs_invalidation = true;
}
- if (LayoutSVGResourcePaintServer* stroke = resources_->Stroke()) {
+ if (auto* stroke = GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ *client, style.StrokePaint().Resource())) {
stroke->RemoveClientFromCache(*client);
needs_invalidation = true;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
index 34c7ca8f159..a04e420041f 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
@@ -20,43 +20,30 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_H_
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
+class CompositorFilterOperations;
class ComputedStyle;
-class FilterEffect;
+class FilterEffectBuilder;
class LayoutObject;
-class LayoutSVGResourceClipper;
-class LayoutSVGResourceFilter;
-class LayoutSVGResourceMarker;
-class LayoutSVGResourceMasker;
-class LayoutSVGResourcePaintServer;
+class ReferenceFilterOperation;
class SVGElement;
class SVGElementResourceClient;
-class SVGFilterGraphNodeMap;
// Holds a set of resources associated with a LayoutObject
class SVGResources {
- USING_FAST_MALLOC(SVGResources);
+ STATIC_ONLY(SVGResources);
public:
- SVGResources();
- SVGResources(const SVGResources&) = delete;
- SVGResources& operator=(const SVGResources&) = delete;
-
static SVGElementResourceClient* GetClient(const LayoutObject&);
static FloatRect ReferenceBoxForEffects(const LayoutObject&);
- static std::unique_ptr<SVGResources> BuildResources(const LayoutObject&,
- const ComputedStyle&);
-
static void UpdateClipPathFilterMask(SVGElement&,
const ComputedStyle* old_style,
const ComputedStyle&);
@@ -69,145 +56,6 @@ class SVGResources {
const ComputedStyle* old_style,
const ComputedStyle&);
static void ClearMarkers(SVGElement&, const ComputedStyle*);
-
- static bool SupportsMarkers(const SVGElement&);
-
- // Ordinary resources
- LayoutSVGResourceClipper* Clipper() const {
- return clipper_filter_masker_data_ ? clipper_filter_masker_data_->clipper
- : nullptr;
- }
- LayoutSVGResourceMarker* MarkerStart() const {
- return marker_data_ ? marker_data_->marker_start : nullptr;
- }
- LayoutSVGResourceMarker* MarkerMid() const {
- return marker_data_ ? marker_data_->marker_mid : nullptr;
- }
- LayoutSVGResourceMarker* MarkerEnd() const {
- return marker_data_ ? marker_data_->marker_end : nullptr;
- }
- LayoutSVGResourceMasker* Masker() const {
- return clipper_filter_masker_data_ ? clipper_filter_masker_data_->masker
- : nullptr;
- }
-
- LayoutSVGResourceFilter* Filter() const {
- if (clipper_filter_masker_data_)
- return clipper_filter_masker_data_->filter;
- return nullptr;
- }
-
- bool HasClipOrMaskOrFilter() const { return !!clipper_filter_masker_data_; }
-
- // Paint servers
- LayoutSVGResourcePaintServer* Fill() const {
- return fill_stroke_data_ ? fill_stroke_data_->fill : nullptr;
- }
- LayoutSVGResourcePaintServer* Stroke() const {
- return fill_stroke_data_ ? fill_stroke_data_->stroke : nullptr;
- }
-
- // Chainable resources - linked through xlink:href
- LayoutSVGResourceContainer* LinkedResource() const {
- return linked_resource_;
- }
-
- void BuildSetOfResources(HashSet<LayoutSVGResourceContainer*>&);
-
- // Methods operating on all cached resources
- void ResourceDestroyed(LayoutSVGResourceContainer*);
- void ClearReferencesTo(LayoutSVGResourceContainer*);
-
-#if DCHECK_IS_ON()
- void Dump(const LayoutObject*);
-#endif
-
- private:
- bool HasResourceData() const;
-
- void SetClipper(LayoutSVGResourceClipper*);
- void SetFilter(LayoutSVGResourceFilter*);
- void SetMarkerStart(LayoutSVGResourceMarker*);
- void SetMarkerMid(LayoutSVGResourceMarker*);
- void SetMarkerEnd(LayoutSVGResourceMarker*);
- void SetMasker(LayoutSVGResourceMasker*);
- void SetFill(LayoutSVGResourcePaintServer*);
- void SetStroke(LayoutSVGResourcePaintServer*);
- void SetLinkedResource(LayoutSVGResourceContainer*);
-
- // From SVG 1.1 2nd Edition
- // clipper: 'container elements' and 'graphics elements'
- // filter: 'container elements' and 'graphics elements'
- // masker: 'container elements' and 'graphics elements'
- // -> a, circle, defs, ellipse, glyph, g, image, line, marker, mask,
- // missing-glyph, path, pattern, polygon, polyline, rect, svg, switch, symbol,
- // text, use
- struct ClipperFilterMaskerData {
- USING_FAST_MALLOC(ClipperFilterMaskerData);
-
- public:
- ClipperFilterMaskerData()
- : clipper(nullptr), filter(nullptr), masker(nullptr) {}
-
- LayoutSVGResourceClipper* clipper;
- LayoutSVGResourceFilter* filter;
- LayoutSVGResourceMasker* masker;
- };
-
- // From SVG 1.1 2nd Edition
- // marker: line, path, polygon, polyline
- struct MarkerData {
- USING_FAST_MALLOC(MarkerData);
-
- public:
- MarkerData()
- : marker_start(nullptr), marker_mid(nullptr), marker_end(nullptr) {}
-
- LayoutSVGResourceMarker* marker_start;
- LayoutSVGResourceMarker* marker_mid;
- LayoutSVGResourceMarker* marker_end;
- };
-
- // From SVG 1.1 2nd Edition
- // fill: 'shapes' and 'text content elements'
- // stroke: 'shapes' and 'text content elements'
- // -> circle, ellipse, line, path, polygon, polyline, rect, text, textPath,
- // tspan
- struct FillStrokeData {
- USING_FAST_MALLOC(FillStrokeData);
-
- public:
- FillStrokeData() : fill(nullptr), stroke(nullptr) {}
-
- LayoutSVGResourcePaintServer* fill;
- LayoutSVGResourcePaintServer* stroke;
- };
-
- std::unique_ptr<ClipperFilterMaskerData> clipper_filter_masker_data_;
- std::unique_ptr<MarkerData> marker_data_;
- std::unique_ptr<FillStrokeData> fill_stroke_data_;
- LayoutSVGResourceContainer* linked_resource_;
-};
-
-class FilterData final : public GarbageCollected<FilterData> {
- public:
- FilterData(FilterEffect* last_effect, SVGFilterGraphNodeMap* node_map)
- : last_effect_(last_effect), node_map_(node_map) {}
-
- sk_sp<PaintFilter> BuildPaintFilter();
- // Perform a finegrained invalidation of the filter chain for the
- // specified filter primitive and attribute. Returns false if no
- // further invalidation is required, otherwise true.
- bool Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
- const QualifiedName& attribute);
-
- void Dispose();
-
- void Trace(Visitor*) const;
-
- private:
- Member<FilterEffect> last_effect_;
- Member<SVGFilterGraphNodeMap> node_map_;
};
class SVGElementResourceClient final
@@ -216,11 +64,10 @@ class SVGElementResourceClient final
public:
explicit SVGElementResourceClient(SVGElement*);
- void ResourceContentChanged(InvalidationModeMask) override;
- void ResourceElementChanged() override;
- void ResourceDestroyed(LayoutSVGResourceContainer*) override;
+ void ResourceContentChanged(SVGResource*) override;
- void FilterPrimitiveChanged(SVGFilterPrimitiveStandardAttributes& primitive,
+ void FilterPrimitiveChanged(SVGResource*,
+ SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) override;
void UpdateFilterData(CompositorFilterOperations&);
@@ -230,6 +77,12 @@ class SVGElementResourceClient final
void Trace(Visitor*) const override;
private:
+ class FilterData;
+
+ static FilterData* CreateFilterDataWithNodeMap(
+ FilterEffectBuilder&,
+ const ReferenceFilterOperation&);
+
Member<SVGElement> element_;
Member<FilterData> filter_data_;
bool filter_data_dirty_;
@@ -250,7 +103,6 @@ class SVGResourceInvalidator {
void InvalidatePaints();
private:
- const SVGResources* resources_;
LayoutObject& object_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
deleted file mode 100644
index b81f929c0a7..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
-
-#include <memory>
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
-#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
-
-namespace blink {
-
-SVGResourcesCache::SVGResourcesCache() = default;
-
-SVGResourcesCache::~SVGResourcesCache() = default;
-
-bool SVGResourcesCache::AddResourcesFromLayoutObject(
- LayoutObject& object,
- const ComputedStyle& style) {
- DCHECK(!cache_.Contains(&object));
-
- // Build a list of all resources associated with the passed LayoutObject.
- std::unique_ptr<SVGResources> new_resources =
- SVGResources::BuildResources(object, style);
- if (!new_resources)
- return false;
-
- // Put object in cache.
- SVGResources* resources =
- cache_.Set(&object, std::move(new_resources)).stored_value->value.get();
-
- // Run cycle-detection _afterwards_, so self-references can be caught as well.
- HashSet<LayoutSVGResourceContainer*> resource_set;
- resources->BuildSetOfResources(resource_set);
-
- SVGResourcesCycleSolver solver;
- for (auto* resource_container : resource_set) {
- if (resource_container->FindCycle(solver))
- resources->ClearReferencesTo(resource_container);
- }
- return true;
-}
-
-bool SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
- std::unique_ptr<SVGResources> resources = cache_.Take(&object);
- return !!resources;
-}
-
-bool SVGResourcesCache::UpdateResourcesFromLayoutObject(
- LayoutObject& object,
- const ComputedStyle& new_style) {
- bool did_update = RemoveResourcesFromLayoutObject(object);
- did_update |= AddResourcesFromLayoutObject(object, new_style);
- return did_update;
-}
-
-static inline SVGResourcesCache& ResourcesCache(Document& document) {
- return document.AccessSVGExtensions().ResourcesCache();
-}
-
-SVGResources* SVGResourcesCache::CachedResourcesForLayoutObject(
- const LayoutObject& layout_object) {
- return ResourcesCache(layout_object.GetDocument()).cache_.at(&layout_object);
-}
-
-static inline bool LayoutObjectCanHaveResources(
- const LayoutObject& layout_object) {
- return layout_object.GetNode() && layout_object.GetNode()->IsSVGElement() &&
- !layout_object.IsSVGInlineText();
-}
-
-bool SVGResourcesCache::AddResources(LayoutObject& layout_object) {
- DCHECK(LayoutObjectCanHaveResources(layout_object));
- SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
- return cache.AddResourcesFromLayoutObject(layout_object,
- layout_object.StyleRef());
-}
-
-bool SVGResourcesCache::RemoveResources(LayoutObject& layout_object) {
- DCHECK(LayoutObjectCanHaveResources(layout_object));
- SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
- return cache.RemoveResourcesFromLayoutObject(layout_object);
-}
-
-bool SVGResourcesCache::UpdateResources(LayoutObject& layout_object) {
- DCHECK(LayoutObjectCanHaveResources(layout_object));
- SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
- return cache.UpdateResourcesFromLayoutObject(layout_object,
- layout_object.StyleRef());
-}
-
-SVGResourcesCache::TemporaryStyleScope::TemporaryStyleScope(
- LayoutObject& layout_object,
- const ComputedStyle& style,
- const ComputedStyle& temporary_style)
- : layout_object_(layout_object),
- original_style_(style),
- temporary_style_(temporary_style),
- styles_are_equal_(style == temporary_style) {
- if (styles_are_equal_)
- return;
- DCHECK(LayoutObjectCanHaveResources(layout_object_));
- auto& element = To<SVGElement>(*layout_object_.GetNode());
- SVGResources::UpdatePaints(element, nullptr, temporary_style_);
- SwitchTo(temporary_style);
-}
-
-SVGResourcesCache::TemporaryStyleScope::~TemporaryStyleScope() {
- if (styles_are_equal_)
- return;
- auto& element = To<SVGElement>(*layout_object_.GetNode());
- SVGResources::ClearPaints(element, &temporary_style_);
- SwitchTo(original_style_);
-}
-
-void SVGResourcesCache::TemporaryStyleScope::SwitchTo(
- const ComputedStyle& style) {
- DCHECK(!styles_are_equal_);
- SVGResourcesCache& cache = ResourcesCache(layout_object_.GetDocument());
- cache.UpdateResourcesFromLayoutObject(layout_object_, style);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
deleted file mode 100644
index 3a10d8fdf67..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CACHE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CACHE_H_
-
-#include <memory>
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-
-namespace blink {
-
-class LayoutObject;
-class ComputedStyle;
-class SVGResources;
-
-class SVGResourcesCache {
- USING_FAST_MALLOC(SVGResourcesCache);
-
- public:
- SVGResourcesCache();
- SVGResourcesCache(const SVGResourcesCache&) = delete;
- SVGResourcesCache& operator=(const SVGResourcesCache&) = delete;
- ~SVGResourcesCache();
-
- static SVGResources* CachedResourcesForLayoutObject(const LayoutObject&);
-
- // Called when an SVG LayoutObject has been added to the tree.
- // Returns true if an SVGResources object was created.
- static bool AddResources(LayoutObject&);
-
- // Called when an SVG LayoutObject has been removed from the tree.
- // Returns true if an SVGResources object was destroyed.
- static bool RemoveResources(LayoutObject&);
-
- // Called when the target element of a resource referenced by the
- // LayoutObject may have changed and we need to recreate the
- // associated SVGResources object.
- static bool UpdateResources(LayoutObject&);
-
- class TemporaryStyleScope {
- STACK_ALLOCATED();
-
- public:
- TemporaryStyleScope(LayoutObject&,
- const ComputedStyle& original_style,
- const ComputedStyle& temporary_style);
- TemporaryStyleScope(const TemporaryStyleScope&) = delete;
- TemporaryStyleScope& operator=(const TemporaryStyleScope) = delete;
- ~TemporaryStyleScope();
-
- private:
- void SwitchTo(const ComputedStyle&);
-
- LayoutObject& layout_object_;
- const ComputedStyle& original_style_;
- const ComputedStyle& temporary_style_;
- const bool styles_are_equal_;
- };
-
- private:
- bool AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
- bool RemoveResourcesFromLayoutObject(LayoutObject&);
- bool UpdateResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
-
- typedef HashMap<const LayoutObject*, std::unique_ptr<SVGResources>> CacheMap;
- CacheMap cache_;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc
deleted file mode 100644
index 5ede5cc597b..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
-
-namespace blink {
-
-SVGResourcesCycleSolver::SVGResourcesCycleSolver() = default;
-
-SVGResourcesCycleSolver::~SVGResourcesCycleSolver() = default;
-
-bool SVGResourcesCycleSolver::IsKnownAcyclic(
- const LayoutSVGResourceContainer* resource) const {
- return dag_cache_.Contains(resource);
-}
-
-void SVGResourcesCycleSolver::AddAcyclicSubgraph(
- const LayoutSVGResourceContainer* resource) {
- dag_cache_.insert(resource);
-}
-
-bool SVGResourcesCycleSolver::EnterResource(
- const LayoutSVGResourceContainer* resource) {
- return active_resources_.insert(resource).is_new_entry;
-}
-
-void SVGResourcesCycleSolver::LeaveResource(
- const LayoutSVGResourceContainer* resource) {
- active_resources_.erase(resource);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
deleted file mode 100644
index c634748b4f9..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CYCLE_SOLVER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CYCLE_SOLVER_H_
-
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-
-namespace blink {
-
-// This class traverses the graph formed by SVGResources of
-// LayoutObjects, maintaining the active path as LayoutObjects are
-// visited. It also maintains a cache of sub-graphs that has already
-// been visited and that does not contain any cycles.
-class SVGResourcesCycleSolver {
- STACK_ALLOCATED();
-
- public:
- SVGResourcesCycleSolver();
- SVGResourcesCycleSolver(const SVGResourcesCycleSolver&) = delete;
- SVGResourcesCycleSolver& operator=(const SVGResourcesCycleSolver&) = delete;
- ~SVGResourcesCycleSolver();
-
- bool IsKnownAcyclic(const LayoutSVGResourceContainer*) const;
- void AddAcyclicSubgraph(const LayoutSVGResourceContainer*);
-
- class Scope {
- STACK_ALLOCATED();
-
- public:
- Scope(SVGResourcesCycleSolver& solver)
- : solver_(solver), resource_(nullptr) {}
- ~Scope() {
- if (resource_)
- solver_.LeaveResource(resource_);
- }
-
- bool Enter(const LayoutSVGResourceContainer* resource) {
- if (!solver_.EnterResource(resource))
- return false;
- resource_ = resource;
- return true;
- }
-
- private:
- SVGResourcesCycleSolver& solver_;
- const LayoutSVGResourceContainer* resource_;
- };
-
- private:
- bool EnterResource(const LayoutSVGResourceContainer*);
- void LeaveResource(const LayoutSVGResourceContainer*);
-
- using ResourceSet = HashSet<const LayoutSVGResourceContainer*>;
- ResourceSet active_resources_;
- ResourceSet dag_cache_;
-};
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
index f097849e613..56e7fcd0142 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
@@ -29,15 +29,15 @@ namespace blink {
float CalculateTextAnchorShift(const ComputedStyle& style, float length) {
bool is_ltr = style.IsLeftToRightDirection();
- switch (style.SvgStyle().TextAnchor()) {
+ switch (style.TextAnchor()) {
default:
NOTREACHED();
FALLTHROUGH;
- case TA_START:
+ case ETextAnchor::kStart:
return is_ltr ? 0 : -length;
- case TA_MIDDLE:
+ case ETextAnchor::kMiddle:
return -length / 2;
- case TA_END:
+ case ETextAnchor::kEnd:
return is_ltr ? -length : 0;
}
}
@@ -46,15 +46,15 @@ namespace {
bool NeedsTextAnchorAdjustment(const ComputedStyle& style) {
bool is_ltr = style.IsLeftToRightDirection();
- switch (style.SvgStyle().TextAnchor()) {
+ switch (style.TextAnchor()) {
default:
NOTREACHED();
FALLTHROUGH;
- case TA_START:
+ case ETextAnchor::kStart:
return !is_ltr;
- case TA_MIDDLE:
+ case ETextAnchor::kMiddle:
return true;
- case TA_END:
+ case ETextAnchor::kEnd:
return is_ltr;
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
index 8dcef8d0088..9219680e27c 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
@@ -441,8 +441,7 @@ void SVGTextLayoutEngine::LayoutTextOnLineOrPath(
float spacing = spacing_layout.CalculateCSSSpacing(current_character);
FloatPoint text_path_shift;
- float angle = 0;
- FloatPoint position;
+ PointAndTangent position;
if (in_path_layout_) {
float scaled_glyph_advance = glyph_advance * text_path_scaling_;
// Setup translations that move to the glyph midpoint.
@@ -460,7 +459,7 @@ void SVGTextLayoutEngine::LayoutTextOnLineOrPath(
spacing * text_path_scaling_;
PathPositionMapper::PositionType position_type =
- text_path_->PointAndNormalAtLength(text_path_offset, position, angle);
+ text_path_->PointAndNormalAtLength(text_path_offset, position);
// Skip character, if we're before the path.
if (position_type == PathPositionMapper::kBeforePath) {
@@ -473,24 +472,26 @@ void SVGTextLayoutEngine::LayoutTextOnLineOrPath(
if (position_type == PathPositionMapper::kAfterPath)
break;
- text_position_ = position;
+ text_position_ = position.point;
// For vertical text on path, the actual angle has to be rotated 90
// degrees anti-clockwise, not the orientation angle!
if (is_vertical_text_)
- angle -= 90;
+ position.tangent_in_degrees -= 90;
} else {
- position = text_position_;
- position += baseline_shift;
+ position.point = text_position_;
+ position.point += baseline_shift;
}
if (data.HasRotate())
- angle += data.rotate;
+ position.tangent_in_degrees += data.rotate;
// Determine whether we have to start a new fragment.
bool should_start_new_fragment =
- needs_fragment_per_glyph || has_relative_position || angle ||
- angle != last_angle || apply_spacing_to_next_character;
+ needs_fragment_per_glyph || has_relative_position ||
+ position.tangent_in_degrees ||
+ position.tangent_in_degrees != last_angle ||
+ apply_spacing_to_next_character;
// If we already started a fragment, close it now.
if (did_start_text_fragment && should_start_new_fragment) {
@@ -508,16 +509,17 @@ void SVGTextLayoutEngine::LayoutTextOnLineOrPath(
visual_metrics_iterator_.CharacterOffset();
current_text_fragment_.metrics_list_offset =
visual_metrics_iterator_.MetricsListOffset();
- current_text_fragment_.x = position.X();
- current_text_fragment_.y = position.Y();
+ current_text_fragment_.x = position.point.X();
+ current_text_fragment_.y = position.point.Y();
// Build fragment transformation.
- if (angle)
- current_text_fragment_.transform.Rotate(angle);
+ if (position.tangent_in_degrees)
+ current_text_fragment_.transform.Rotate(position.tangent_in_degrees);
- if (text_path_shift.X() || text_path_shift.Y())
+ if (text_path_shift.X() || text_path_shift.Y()) {
current_text_fragment_.transform.Translate(text_path_shift.X(),
text_path_shift.Y());
+ }
// For vertical text, always rotate by 90 degrees regardless of
// fontOrientation.
@@ -543,7 +545,7 @@ void SVGTextLayoutEngine::LayoutTextOnLineOrPath(
AdvanceToNextLogicalCharacter(logical_metrics);
visual_metrics_iterator_.Next();
- last_angle = angle;
+ last_angle = position.tangent_in_degrees;
}
if (!did_start_text_fragment)
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
index c7824b10958..7caee875243 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
@@ -19,7 +19,6 @@
#include "third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
@@ -33,21 +32,20 @@ SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font,
float SVGTextLayoutEngineBaseline::CalculateBaselineShift(
const ComputedStyle& style) const {
- const SVGComputedStyle& svg_style = style.SvgStyle();
const SimpleFontData* font_data = font_.PrimaryFont();
DCHECK(font_data);
if (!font_data)
return 0;
DCHECK(effective_zoom_);
- switch (svg_style.BaselineShift()) {
- case BS_LENGTH:
+ switch (style.BaselineShiftType()) {
+ case EBaselineShiftType::kLength:
return SVGLengthContext::ValueForLength(
- svg_style.BaselineShiftValue(), style,
+ style.BaselineShift(), style,
font_.GetFontDescription().ComputedPixelSize() / effective_zoom_);
- case BS_SUB:
+ case EBaselineShiftType::kSub:
return -font_data->GetFontMetrics().FloatHeight() / 2 / effective_zoom_;
- case BS_SUPER:
+ case EBaselineShiftType::kSuper:
return font_data->GetFontMetrics().FloatHeight() / 2 / effective_zoom_;
default:
NOTREACHED();
@@ -62,49 +60,47 @@ SVGTextLayoutEngineBaseline::DominantBaselineToAlignmentBaseline(
DCHECK(text_line_layout);
DCHECK(text_line_layout.Style());
- const SVGComputedStyle& style = text_line_layout.StyleRef().SvgStyle();
-
- EDominantBaseline baseline = style.DominantBaseline();
- if (baseline == DB_AUTO) {
+ EDominantBaseline baseline = text_line_layout.StyleRef().DominantBaseline();
+ if (baseline == EDominantBaseline::kAuto) {
if (is_vertical_text)
- baseline = DB_CENTRAL;
+ baseline = EDominantBaseline::kCentral;
else
- baseline = DB_ALPHABETIC;
+ baseline = EDominantBaseline::kAlphabetic;
}
switch (baseline) {
- case DB_USE_SCRIPT:
+ case EDominantBaseline::kUseScript:
// TODO(fs): The dominant-baseline and the baseline-table components
// are set by determining the predominant script of the character data
// content.
- return AB_ALPHABETIC;
- case DB_NO_CHANGE:
+ return EAlignmentBaseline::kAlphabetic;
+ case EDominantBaseline::kNoChange:
DCHECK(text_line_layout.Parent());
return DominantBaselineToAlignmentBaseline(is_vertical_text,
text_line_layout.Parent());
- case DB_RESET_SIZE:
+ case EDominantBaseline::kResetSize:
DCHECK(text_line_layout.Parent());
return DominantBaselineToAlignmentBaseline(is_vertical_text,
text_line_layout.Parent());
- case DB_IDEOGRAPHIC:
- return AB_IDEOGRAPHIC;
- case DB_ALPHABETIC:
- return AB_ALPHABETIC;
- case DB_HANGING:
- return AB_HANGING;
- case DB_MATHEMATICAL:
- return AB_MATHEMATICAL;
- case DB_CENTRAL:
- return AB_CENTRAL;
- case DB_MIDDLE:
- return AB_MIDDLE;
- case DB_TEXT_AFTER_EDGE:
- return AB_TEXT_AFTER_EDGE;
- case DB_TEXT_BEFORE_EDGE:
- return AB_TEXT_BEFORE_EDGE;
+ case EDominantBaseline::kIdeographic:
+ return EAlignmentBaseline::kIdeographic;
+ case EDominantBaseline::kAlphabetic:
+ return EAlignmentBaseline::kAlphabetic;
+ case EDominantBaseline::kHanging:
+ return EAlignmentBaseline::kHanging;
+ case EDominantBaseline::kMathematical:
+ return EAlignmentBaseline::kMathematical;
+ case EDominantBaseline::kCentral:
+ return EAlignmentBaseline::kCentral;
+ case EDominantBaseline::kMiddle:
+ return EAlignmentBaseline::kMiddle;
+ case EDominantBaseline::kTextAfterEdge:
+ return EAlignmentBaseline::kTextAfterEdge;
+ case EDominantBaseline::kTextBeforeEdge:
+ return EAlignmentBaseline::kTextBeforeEdge;
default:
NOTREACHED();
- return AB_AUTO;
+ return EAlignmentBaseline::kAuto;
}
}
@@ -118,13 +114,13 @@ float SVGTextLayoutEngineBaseline::CalculateAlignmentBaselineShift(
LineLayoutItem text_line_layout_parent = text_line_layout.Parent();
DCHECK(text_line_layout_parent);
- EAlignmentBaseline baseline =
- text_line_layout.StyleRef().SvgStyle().AlignmentBaseline();
- if (baseline == AB_AUTO || baseline == AB_BASELINE) {
+ EAlignmentBaseline baseline = text_line_layout.StyleRef().AlignmentBaseline();
+ if (baseline == EAlignmentBaseline::kAuto ||
+ baseline == EAlignmentBaseline::kBaseline) {
baseline = DominantBaselineToAlignmentBaseline(is_vertical_text,
text_line_layout_parent);
- DCHECK_NE(baseline, AB_AUTO);
- DCHECK_NE(baseline, AB_BASELINE);
+ DCHECK_NE(baseline, EAlignmentBaseline::kAuto);
+ DCHECK_NE(baseline, EAlignmentBaseline::kBaseline);
}
const SimpleFontData* font_data = font_.PrimaryFont();
@@ -139,24 +135,24 @@ float SVGTextLayoutEngineBaseline::CalculateAlignmentBaselineShift(
// Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
switch (baseline) {
- case AB_BEFORE_EDGE:
- case AB_TEXT_BEFORE_EDGE:
+ case EAlignmentBaseline::kBeforeEdge:
+ case EAlignmentBaseline::kTextBeforeEdge:
return ascent;
- case AB_MIDDLE:
+ case EAlignmentBaseline::kMiddle:
return xheight / 2;
- case AB_CENTRAL:
+ case EAlignmentBaseline::kCentral:
return (ascent - descent) / 2;
- case AB_AFTER_EDGE:
- case AB_TEXT_AFTER_EDGE:
- case AB_IDEOGRAPHIC:
+ case EAlignmentBaseline::kAfterEdge:
+ case EAlignmentBaseline::kTextAfterEdge:
+ case EAlignmentBaseline::kIdeographic:
return -descent;
- case AB_ALPHABETIC:
+ case EAlignmentBaseline::kAlphabetic:
return 0;
- case AB_HANGING:
+ case EAlignmentBaseline::kHanging:
return ascent * 8 / 10.f;
- case AB_MATHEMATICAL:
+ case EAlignmentBaseline::kMathematical:
return ascent / 2;
- case AB_BASELINE:
+ case EAlignmentBaseline::kBaseline:
default:
NOTREACHED();
return 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h
index c5679aa6866..c2916d60249 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h
@@ -21,7 +21,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_BASELINE_H_
#include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h b/chromium/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h
index 07cfec0e896..17f0fcc21a3 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORMED_HIT_TEST_LOCATION_H_
#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
namespace blink {
@@ -17,7 +18,7 @@ class AffineTransform;
//
// Encapsulates logic to avoid creating/copying the HitTestLocation for example
// if the AffineTransform is the identity.
-class TransformedHitTestLocation {
+class CORE_EXPORT TransformedHitTestLocation {
DISALLOW_NEW();
public:
diff --git a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index c16273ceed3..a0586d130e4 100644
--- a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -54,7 +54,7 @@ void TableLayoutAlgorithmAuto::RecalcColumn(unsigned eff_col) {
// we need to clear their dirty bits so that if we call
// setPreferredWidthsDirty(true) on a col or one of its descendants, we'll
// mark it's ancestors as dirty.
- ToLayoutTableCol(child)->ClearIntrinsicLogicalWidthsDirtyBits();
+ To<LayoutTableCol>(child)->ClearIntrinsicLogicalWidthsDirtyBits();
} else if (child->IsTableSection()) {
LayoutTableSection* section = To<LayoutTableSection>(child);
unsigned num_rows = section->NumRows();
@@ -241,7 +241,7 @@ static bool ShouldScaleColumnsForParent(LayoutTable* table) {
const bool is_deprecated_webkit_box =
cb->StyleRef().IsDeprecatedWebkitBox();
if ((!is_deprecated_webkit_box && cb->IsFlexibleBoxIncludingNG()) ||
- cb->IsLayoutGrid()) {
+ cb->IsLayoutGridIncludingNG()) {
return false;
}
cb = cb->ContainingBlock();
@@ -472,9 +472,9 @@ int TableLayoutAlgorithmAuto::CalcEffectiveLogicalWidth() {
// adjust table max width if needed
if (cell_logical_width.IsPercentOrCalc()) {
- if (total_percent > cell_logical_width.Percent() ||
+ if (total_percent >= cell_logical_width.Percent() ||
all_cols_are_percent) {
- // can't satify this condition, treat as variable
+ // can't satisfy this condition, treat as variable
cell_logical_width = Length();
} else {
max_logical_width =
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
index 10936b71db2..c37fd88699b 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -621,7 +621,7 @@ void TextAutosizer::UpdatePageInfo() {
PageInfo previous_page_info(page_info_);
page_info_.setting_enabled_ =
- document_->GetSettings()->TextAutosizingEnabled();
+ document_->GetSettings()->GetTextAutosizingEnabled();
if (!page_info_.setting_enabled_ || document_->Printing()) {
page_info_.page_needs_autosizing_ = false;
@@ -638,7 +638,7 @@ void TextAutosizer::UpdatePageInfo() {
} else {
LocalFrame& main_frame = To<LocalFrame>(frame);
IntSize frame_size =
- document_->GetSettings()->TextAutosizingWindowSizeOverride();
+ document_->GetSettings()->GetTextAutosizingWindowSizeOverride();
if (frame_size.IsEmpty())
frame_size = WindowSize();
diff --git a/chromium/third_party/blink/renderer/core/layout/web_font_rendering_win.cc b/chromium/third_party/blink/renderer/core/layout/web_font_rendering_win.cc
index 108d583bd5d..3af0d63942d 100644
--- a/chromium/third_party/blink/renderer/core/layout/web_font_rendering_win.cc
+++ b/chromium/third_party/blink/renderer/core/layout/web_font_rendering_win.cc
@@ -19,19 +19,19 @@ void WebFontRendering::AddSideloadedFontForTesting(sk_sp<SkTypeface> typeface) {
}
// static
-void WebFontRendering::SetMenuFontMetrics(const wchar_t* family_name,
+void WebFontRendering::SetMenuFontMetrics(const WebString& family_name,
int32_t font_height) {
FontCache::SetMenuFontMetrics(family_name, font_height);
}
// static
-void WebFontRendering::SetSmallCaptionFontMetrics(const wchar_t* family_name,
+void WebFontRendering::SetSmallCaptionFontMetrics(const WebString& family_name,
int32_t font_height) {
FontCache::SetSmallCaptionFontMetrics(family_name, font_height);
}
// static
-void WebFontRendering::SetStatusFontMetrics(const wchar_t* family_name,
+void WebFontRendering::SetStatusFontMetrics(const WebString& family_name,
int32_t font_height) {
FontCache::SetStatusFontMetrics(family_name, font_height);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/DEPS b/chromium/third_party/blink/renderer/core/loader/DEPS
index 39227699fb8..37e638c13f9 100644
--- a/chromium/third_party/blink/renderer/core/loader/DEPS
+++ b/chromium/third_party/blink/renderer/core/loader/DEPS
@@ -3,6 +3,9 @@ specific_include_rules = {
"+media/media_buildflags.h",
"+net/http/http_request_headers.h"
],
+ "empty_clients.cc" : [
+ "+components/viz/common/surfaces/local_surface_id.h"
+ ],
"progress_tracker_test.cc" : [
"+base/run_loop.h"
],
diff --git a/chromium/third_party/blink/renderer/core/loader/DIR_METADATA b/chromium/third_party/blink/renderer/core/loader/DIR_METADATA
new file mode 100644
index 00000000000..af30f87d55c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Loader"
+}
+
+team_email: "loading-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/loader/OWNERS b/chromium/third_party/blink/renderer/core/loader/OWNERS
index b875f73196a..31602500852 100644
--- a/chromium/third_party/blink/renderer/core/loader/OWNERS
+++ b/chromium/third_party/blink/renderer/core/loader/OWNERS
@@ -1,6 +1,3 @@
japhet@chromium.org
mkwst@chromium.org
yhirano@chromium.org
-
-# TEAM: loading-dev@chromium.org
-# COMPONENT: Blink>Loader
diff --git a/chromium/third_party/blink/renderer/core/loader/address_space_feature.cc b/chromium/third_party/blink/renderer/core/loader/address_space_feature.cc
index 4078004bafe..68a86a5bca5 100644
--- a/chromium/third_party/blink/renderer/core/loader/address_space_feature.cc
+++ b/chromium/third_party/blink/renderer/core/loader/address_space_feature.cc
@@ -30,71 +30,188 @@
#include "third_party/blink/renderer/core/loader/address_space_feature.h"
+#include <tuple>
+
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-forward.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/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+
namespace blink {
+namespace {
using AddressSpace = network::mojom::blink::IPAddressSpace;
using Feature = mojom::blink::WebFeature;
-// Returns the kAddressSpaceLocal* WebFeature enum value corresponding to the
-// given client loading a resource from the local address space, if any.
-base::Optional<Feature> AddressSpaceLocalFeature(
- AddressSpace client_address_space,
- bool client_is_secure_context) {
- switch (client_address_space) {
- case AddressSpace::kUnknown:
- return client_is_secure_context
- ? Feature::kAddressSpaceLocalEmbeddedInUnknownSecureContext
- : Feature::kAddressSpaceLocalEmbeddedInUnknownNonSecureContext;
- case AddressSpace::kPublic:
- return client_is_secure_context
- ? Feature::kAddressSpaceLocalEmbeddedInPublicSecureContext
- : Feature::kAddressSpaceLocalEmbeddedInPublicNonSecureContext;
- case AddressSpace::kPrivate:
- return client_is_secure_context
- ? Feature::kAddressSpaceLocalEmbeddedInPrivateSecureContext
- : Feature::kAddressSpaceLocalEmbeddedInPrivateNonSecureContext;
- case AddressSpace::kLocal:
- return base::nullopt; // Local to local is fine, we do not track it.
+// A key in |kFeatureMap|.
+//
+// Mirrors the arguments to |AddressSpaceFeature()| except for |fetch_type|.
+struct FeatureKey {
+ AddressSpace client_address_space;
+ bool client_is_secure_context;
+ AddressSpace response_address_space;
+};
+
+// FeatureKey instances are comparable for equality.
+bool operator==(const FeatureKey& lhs, const FeatureKey& rhs) {
+ return std::tie(lhs.client_address_space, lhs.client_is_secure_context,
+ lhs.response_address_space) ==
+ std::tie(rhs.client_address_space, rhs.client_is_secure_context,
+ rhs.response_address_space);
+}
+
+// An entry in |kFeatureMap|.
+//
+// A single key maps to features for all |fetch_type| values. We could instead
+// have two maps, one for subresources and one for navigations, but they would
+// have the exact same set of keys. Hence it is simpler to have a single map.
+struct FeatureEntry {
+ // The key to this entry.
+ FeatureKey key;
+
+ // The corresponding feature for |kSubresource| fetch types.
+ Feature subresource_feature;
+
+ // The corresponding feature for |kNavigation| fetch types.
+ Feature navigation_feature;
+};
+
+constexpr bool kNonSecureContext = false;
+constexpr bool kSecureContext = true;
+
+constexpr struct FeatureEntry kFeatureMap[] = {
+ {
+ {AddressSpace::kPrivate, kNonSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateNonSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePrivateNonSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kPrivate, kSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePrivateSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kPublic, kNonSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePublicNonSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kPublic, kSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpacePublicSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePublicSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kPublic, kNonSecureContext, AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedPrivate,
+ Feature::kAddressSpacePublicNonSecureContextNavigatedToPrivate,
+ },
+ {
+ {AddressSpace::kPublic, kSecureContext, AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicSecureContextEmbeddedPrivate,
+ Feature::kAddressSpacePublicSecureContextNavigatedToPrivate,
+ },
+ {
+ {AddressSpace::kUnknown, kNonSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal,
+ Feature::kAddressSpaceUnknownNonSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kUnknown, kSecureContext, AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownSecureContextEmbeddedLocal,
+ Feature::kAddressSpaceUnknownSecureContextNavigatedToLocal,
+ },
+ {
+ {AddressSpace::kUnknown, kNonSecureContext, AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate,
+ Feature::kAddressSpaceUnknownNonSecureContextNavigatedToPrivate,
+ },
+ {
+ {AddressSpace::kUnknown, kSecureContext, AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownSecureContextEmbeddedPrivate,
+ Feature::kAddressSpaceUnknownSecureContextNavigatedToPrivate,
+ },
+};
+
+// Attempts to find an entry matching |key| in |kFeatureMap|.
+// Returns a pointer to the entry if successful, nullptr otherwise.
+const FeatureEntry* FindFeatureEntry(const FeatureKey& key) {
+ for (const FeatureEntry& entry : kFeatureMap) {
+ if (key == entry.key) {
+ return &entry;
+ }
}
+ return nullptr;
}
-// Returns the kAddressSpacePrivate* WebFeature enum value corresponding to the
-// given client loading a resource from the private address space, if any.
-base::Optional<Feature> AddressSpacePrivateFeature(
- AddressSpace client_address_space,
- bool client_is_secure_context) {
- switch (client_address_space) {
- case AddressSpace::kUnknown:
- return client_is_secure_context
- ? Feature::kAddressSpacePrivateEmbeddedInUnknownSecureContext
- : Feature::
- kAddressSpacePrivateEmbeddedInUnknownNonSecureContext;
- case AddressSpace::kPublic:
- return client_is_secure_context
- ? Feature::kAddressSpacePrivateEmbeddedInPublicSecureContext
- : Feature::
- kAddressSpacePrivateEmbeddedInPublicNonSecureContext;
- case AddressSpace::kPrivate:
- case AddressSpace::kLocal:
- // Private or local to local is fine, we do not track it.
- return base::nullopt;
+// The list of features which should be reported as deprecated.
+constexpr Feature kDeprecatedFeatures[] = {
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate,
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedPrivate,
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedLocal,
+ Feature::kAddressSpacePrivateNonSecureContextEmbeddedLocal,
+};
+
+// Returns whether |feature| is deprecated.
+bool IsDeprecated(Feature feature) {
+ for (Feature entry : kDeprecatedFeatures) {
+ if (feature == entry) {
+ return true;
+ }
}
+ return false;
}
+} // namespace
+
base::Optional<Feature> AddressSpaceFeature(
+ FetchType fetch_type,
AddressSpace client_address_space,
bool client_is_secure_context,
- AddressSpace resource_address_space) {
- switch (resource_address_space) {
- case AddressSpace::kUnknown:
- case AddressSpace::kPublic:
- return base::nullopt;
- case AddressSpace::kPrivate:
- return AddressSpacePrivateFeature(client_address_space,
- client_is_secure_context);
- case AddressSpace::kLocal:
- return AddressSpaceLocalFeature(client_address_space,
- client_is_secure_context);
+ AddressSpace response_address_space) {
+ FeatureKey key;
+ key.client_address_space = client_address_space;
+ key.client_is_secure_context = client_is_secure_context;
+ key.response_address_space = response_address_space;
+
+ const FeatureEntry* entry = FindFeatureEntry(key);
+ if (!entry) {
+ return base::nullopt;
+ }
+
+ switch (fetch_type) {
+ case FetchType::kSubresource:
+ return entry->subresource_feature;
+ case FetchType::kNavigation:
+ return entry->navigation_feature;
+ }
+}
+
+void RecordAddressSpaceFeature(FetchType fetch_type,
+ LocalFrame* client_frame,
+ const ResourceResponse& response) {
+ if (!client_frame) {
+ return;
+ }
+
+ LocalDOMWindow* window = client_frame->DomWindow();
+ base::Optional<WebFeature> feature =
+ AddressSpaceFeature(fetch_type, window->AddressSpace(),
+ window->IsSecureContext(), response.AddressSpace());
+ if (!feature.has_value()) {
+ return;
+ }
+
+ // This WebFeature encompasses all private network requests.
+ UseCounter::Count(window,
+ WebFeature::kMixedContentPrivateHostnameInPublicHostname);
+
+ if (IsDeprecated(*feature)) {
+ Deprecation::CountDeprecation(window, *feature);
+ } else {
+ UseCounter::Count(window, *feature);
}
}
diff --git a/chromium/third_party/blink/renderer/core/loader/address_space_feature.h b/chromium/third_party/blink/renderer/core/loader/address_space_feature.h
index 249ed5c3508..d7fd01a24ee 100644
--- a/chromium/third_party/blink/renderer/core/loader/address_space_feature.h
+++ b/chromium/third_party/blink/renderer/core/loader/address_space_feature.h
@@ -38,9 +38,23 @@
namespace blink {
+class LocalFrame;
+class ResourceResponse;
+
+// Describes a type of fetch for the purposes of categorizing feature use.
+enum class FetchType {
+ // A document fetching a subresource (image, script, etc.).
+ kSubresource,
+
+ // A navigation from one document to the next.
+ kNavigation,
+};
+
// Returns the kAddressSpace* WebFeature enum value corresponding to a client
-// in |client_address_space| loading a resource from |resource_address_space|,
-// if any.
+// in |client_address_space| fetching data from |response_address_space|, if
+// any.
+//
+// |fetch_type| describes the fetch itself.
//
// |client_is_secure_context| specifies whether the client execution context is
// a secure context, as defined in
@@ -49,9 +63,19 @@ namespace blink {
// Returns nullopt if the load is not a private network request, as defined in
// https://wicg.github.io/cors-rfc1918/#private-network-request.
base::Optional<mojom::blink::WebFeature> CORE_EXPORT AddressSpaceFeature(
+ FetchType fetch_type,
network::mojom::blink::IPAddressSpace client_address_space,
bool client_is_secure_context,
- network::mojom::blink::IPAddressSpace resource_address_space);
+ network::mojom::blink::IPAddressSpace response_address_space);
+
+// Increments the correct kAddressSpace* WebFeature UseCounter corresponding to
+// the given |client_frame| performing a fetch of type |fetch_type| and
+// receiving the given |response|.
+//
+// Does nothing if |client_frame| is nullptr.
+void RecordAddressSpaceFeature(FetchType fetch_type,
+ LocalFrame* client_frame,
+ const ResourceResponse& response);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/address_space_feature_test.cc b/chromium/third_party/blink/renderer/core/loader/address_space_feature_test.cc
index 5328637e909..e2ecc1b1e4b 100644
--- a/chromium/third_party/blink/renderer/core/loader/address_space_feature_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/address_space_feature_test.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/loader/address_space_feature.h"
#include <iosfwd>
+#include <string>
#include <vector>
#include "services/network/public/cpp/ip_address_space_util.h"
@@ -42,6 +43,24 @@ namespace {
using AddressSpace = network::mojom::blink::IPAddressSpace;
using Feature = mojom::blink::WebFeature;
+constexpr FetchType kAllFetchTypes[]{
+ FetchType::kSubresource,
+ FetchType::kNavigation,
+};
+
+std::string FetchTypeToString(FetchType type) {
+ switch (type) {
+ case FetchType::kSubresource:
+ return "FetchType::kSubresource";
+ case FetchType::kNavigation:
+ return "FetchType::kNavigation";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, FetchType type) {
+ return out << FetchTypeToString(type);
+}
+
constexpr AddressSpace kAllAddressSpaces[] = {
AddressSpace::kUnknown,
AddressSpace::kPublic,
@@ -51,6 +70,7 @@ constexpr AddressSpace kAllAddressSpaces[] = {
// Encapsulates arguments to AddressSpaceFeature.
struct Input {
+ FetchType fetch_type;
AddressSpace client_address_space;
bool client_is_secure_context;
AddressSpace resource_address_space;
@@ -58,14 +78,16 @@ struct Input {
// Convenience for HasMappedFeature().
bool operator==(const Input& lhs, const Input& rhs) {
- return lhs.client_address_space == rhs.client_address_space &&
+ return lhs.fetch_type == rhs.fetch_type &&
+ lhs.client_address_space == rhs.client_address_space &&
lhs.client_is_secure_context == rhs.client_is_secure_context &&
lhs.resource_address_space == rhs.resource_address_space;
}
// Allows use of Input arguments to SCOPED_TRACE().
std::ostream& operator<<(std::ostream& out, const Input& input) {
- return out << "Input{ client_address_space: " << input.client_address_space
+ return out << "Input{ fetch_type: " << input.fetch_type
+ << ", client_address_space: " << input.client_address_space
<< ", client_is_secure_context: " << input.client_is_secure_context
<< ", resource_address_space: " << input.resource_address_space
<< " }";
@@ -74,23 +96,27 @@ std::ostream& operator<<(std::ostream& out, const Input& input) {
// Returns all possible Input values.
std::vector<Input> AllInputs() {
std::vector<Input> result;
- for (AddressSpace client_address_space : kAllAddressSpaces) {
- for (bool client_is_secure_context : {false, true}) {
- for (AddressSpace resource_address_space : kAllAddressSpaces) {
- result.push_back({
- client_address_space,
- client_is_secure_context,
- resource_address_space,
- });
+
+ for (FetchType fetch_type : kAllFetchTypes) {
+ for (AddressSpace client_address_space : kAllAddressSpaces) {
+ for (bool client_is_secure_context : {false, true}) {
+ for (AddressSpace resource_address_space : kAllAddressSpaces) {
+ result.push_back({
+ fetch_type,
+ client_address_space,
+ client_is_secure_context,
+ resource_address_space,
+ });
+ }
}
}
}
return result;
}
-// Convenience: calls AddressSpaceFeature() on input's components.
+// Convenience: calls AddressSpaceFeatureForSubresource() on input's components.
base::Optional<Feature> AddressSpaceFeatureForInput(const Input& input) {
- return AddressSpaceFeature(input.client_address_space,
+ return AddressSpaceFeature(input.fetch_type, input.client_address_space,
input.client_is_secure_context,
input.resource_address_space);
}
@@ -104,44 +130,104 @@ struct FeatureMapping {
// The list of all features and their mapped inputs.
constexpr FeatureMapping kFeatureMappings[] = {
{
- {AddressSpace::kUnknown, false, AddressSpace::kPrivate},
- Feature::kAddressSpacePrivateEmbeddedInUnknownNonSecureContext,
+ {FetchType::kSubresource, AddressSpace::kUnknown, false,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedPrivate,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kUnknown, true,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownSecureContextEmbeddedPrivate,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kUnknown, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownNonSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kUnknown, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPublic, false,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedPrivate,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPublic, true,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicSecureContextEmbeddedPrivate,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPublic, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePublicNonSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPublic, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePublicSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPrivate, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateNonSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kSubresource, AddressSpace::kPrivate, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateSecureContextEmbeddedLocal,
+ },
+ {
+ {FetchType::kNavigation, AddressSpace::kUnknown, false,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownNonSecureContextNavigatedToPrivate,
},
{
- {AddressSpace::kUnknown, true, AddressSpace::kPrivate},
- Feature::kAddressSpacePrivateEmbeddedInUnknownSecureContext,
+ {FetchType::kNavigation, AddressSpace::kUnknown, true,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpaceUnknownSecureContextNavigatedToPrivate,
},
{
- {AddressSpace::kUnknown, false, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInUnknownNonSecureContext,
+ {FetchType::kNavigation, AddressSpace::kUnknown, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownNonSecureContextNavigatedToLocal,
},
{
- {AddressSpace::kUnknown, true, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInUnknownSecureContext,
+ {FetchType::kNavigation, AddressSpace::kUnknown, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpaceUnknownSecureContextNavigatedToLocal,
},
{
- {AddressSpace::kPublic, false, AddressSpace::kPrivate},
- Feature::kAddressSpacePrivateEmbeddedInPublicNonSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPublic, false,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicNonSecureContextNavigatedToPrivate,
},
{
- {AddressSpace::kPublic, true, AddressSpace::kPrivate},
- Feature::kAddressSpacePrivateEmbeddedInPublicSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPublic, true,
+ AddressSpace::kPrivate},
+ Feature::kAddressSpacePublicSecureContextNavigatedToPrivate,
},
{
- {AddressSpace::kPublic, false, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInPublicNonSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPublic, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePublicNonSecureContextNavigatedToLocal,
},
{
- {AddressSpace::kPublic, true, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInPublicSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPublic, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePublicSecureContextNavigatedToLocal,
},
{
- {AddressSpace::kPrivate, false, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInPrivateNonSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPrivate, false,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateNonSecureContextNavigatedToLocal,
},
{
- {AddressSpace::kPrivate, true, AddressSpace::kLocal},
- Feature::kAddressSpaceLocalEmbeddedInPrivateSecureContext,
+ {FetchType::kNavigation, AddressSpace::kPrivate, true,
+ AddressSpace::kLocal},
+ Feature::kAddressSpacePrivateSecureContextNavigatedToLocal,
},
};
@@ -177,8 +263,8 @@ TEST(AddressSpaceFeatureTest, ReturnsFeatureIffResourceLessPublic) {
}
}
-// This test verifies that AddressSpaceFeature() maps inputs to features as
-// declared in kFeatureMappings.
+// This test verifies that AddressSpaceFeatureForX() maps inputs to
+// features as declared in kFeatureMappings.
TEST(AddressSpaceFeatureTest, MapsAllFeaturesCorrectly) {
for (const FeatureMapping& mapping : kFeatureMappings) {
SCOPED_TRACE(mapping.input);
@@ -191,7 +277,7 @@ TEST(AddressSpaceFeatureTest, MapsAllFeaturesCorrectly) {
}
// This test verifies that all inputs that yield a Feature when run through
-// AddressSpaceFeature() are included in kFeatureMappings.
+// AddressSpaceFeatureForX() are included in kFeatureMappings.
TEST(AddressSpaceFeatureTest, FeatureMappingsAreComplete) {
for (const Input& input : AllInputs()) {
SCOPED_TRACE(input);
diff --git a/chromium/third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.cc b/chromium/third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.cc
index 4d32e0a9597..4083ba24c8b 100644
--- a/chromium/third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.cc
+++ b/chromium/third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.cc
@@ -6,14 +6,12 @@
#include "media/media_buildflags.h"
#include "net/http/http_request_headers.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/web_package/signed_exchange_consts.h"
#include "third_party/blink/public/common/web_package/web_package_request_matcher.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/link_header.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
@@ -31,19 +29,13 @@ constexpr char kAllowedAltSxg[] = "allowed-alt-sxg";
const char kDefaultAcceptHeader[] = "*/*";
const char kStylesheetAcceptHeader[] = "text/css,*/*;q=0.1";
-const char* ImageAcceptHeader() {
- static constexpr char kImageAcceptHeaderWithAvif[] =
- "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- static constexpr size_t kOffset = sizeof("image/avif,") - 1;
#if BUILDFLAG(ENABLE_AV1_DECODER)
- static const char* header = base::FeatureList::IsEnabled(features::kAVIF)
- ? kImageAcceptHeaderWithAvif
- : kImageAcceptHeaderWithAvif + kOffset;
+constexpr char kImageAcceptHeader[] =
+ "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
#else
- static const char* header = kImageAcceptHeaderWithAvif + kOffset;
+constexpr char kImageAcceptHeader[] =
+ "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
#endif
- return header;
-}
using AlternateSignedExchangeMachingKey =
std::pair<String /* anchor */,
@@ -148,7 +140,7 @@ AlternateSignedExchangeResourceInfo::FindMatchingEntry(
if (resource_type == ResourceType::kCSSStyleSheet) {
accept_header = kStylesheetAcceptHeader;
} else if (resource_type == ResourceType::kImage) {
- accept_header = ImageAcceptHeader();
+ accept_header = kImageAcceptHeader;
}
return FindMatchingEntry(url, accept_header, languages);
}
@@ -162,7 +154,7 @@ AlternateSignedExchangeResourceInfo::FindMatchingEntry(
if (request_context == mojom::blink::RequestContextType::STYLE) {
accept_header = kStylesheetAcceptHeader;
} else if (request_context == mojom::blink::RequestContextType::IMAGE) {
- accept_header = ImageAcceptHeader();
+ accept_header = kImageAcceptHeader;
}
return FindMatchingEntry(url, accept_header, languages);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/DIR_METADATA b/chromium/third_party/blink/renderer/core/loader/appcache/DIR_METADATA
new file mode 100644
index 00000000000..df95601e367
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Storage>AppCache"
+}
+
+team_email: "storage-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/OWNERS b/chromium/third_party/blink/renderer/core/loader/appcache/OWNERS
index 602a916a8b4..97ff3f4cb94 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/OWNERS
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/OWNERS
@@ -1,4 +1 @@
file://content/browser/appcache/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>AppCache \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
index 3580a09a9bf..0d011b49c17 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
@@ -64,12 +64,8 @@ const char* const kEventNames[] = {"Checking", "Error", "NoUpdate",
ApplicationCacheHost::ApplicationCacheHost(
const BrowserInterfaceBrokerProxy& interface_broker_proxy,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- ContextLifecycleNotifier* notifier)
- : backend_host_(notifier),
- receiver_(this, notifier),
- backend_remote_(notifier),
- task_runner_(std::move(task_runner)),
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)),
interface_broker_proxy_(interface_broker_proxy) {}
ApplicationCacheHost::~ApplicationCacheHost() = default;
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
index aa23aeb9fd7..9481bfba486 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
@@ -41,7 +41,6 @@
#include "third_party/blink/public/mojom/appcache/appcache_info.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
@@ -59,8 +58,7 @@ class CORE_EXPORT ApplicationCacheHost
public:
ApplicationCacheHost(
const BrowserInterfaceBrokerProxy& interface_broker_proxy,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- ContextLifecycleNotifier* notifier);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~ApplicationCacheHost() override;
virtual void Detach();
@@ -114,9 +112,9 @@ class CORE_EXPORT ApplicationCacheHost
virtual void Trace(Visitor*) const;
protected:
- HeapMojoRemote<mojom::blink::AppCacheHost,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- backend_host_;
+ // ApplicationCacheHost will be instantiated before ExecutionContext becomes
+ // available. So we can't supply ExecutionContext to HeapMojoRemote.
+ HeapMojoRemote<mojom::blink::AppCacheHost> backend_host_{nullptr};
mojom::blink::AppCacheStatus status_ =
mojom::blink::AppCacheStatus::APPCACHE_STATUS_UNCACHED;
@@ -134,13 +132,13 @@ class CORE_EXPORT ApplicationCacheHost
void GetAssociatedCacheInfo(CacheInfo* info);
- HeapMojoReceiver<mojom::blink::AppCacheFrontend,
- ApplicationCacheHost,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- receiver_;
- HeapMojoRemote<mojom::blink::AppCacheBackend,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- backend_remote_;
+ // ApplicationCacheHost will be instantiated before ExecutionContext becomes
+ // available. So we can't supply ExecutionContext to HeapMojoReceiver.
+ HeapMojoReceiver<mojom::blink::AppCacheFrontend, ApplicationCacheHost>
+ receiver_{this, nullptr};
+ // ApplicationCacheHost will be instantiated before ExecutionContext becomes
+ // available. So we can't supply ExecutionContext to HeapMojoRemote.
+ HeapMojoRemote<mojom::blink::AppCacheBackend> backend_remote_{nullptr};
base::UnguessableToken host_id_;
mojom::blink::AppCacheInfo cache_info_;
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.cc b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.cc
index 389536619b4..0e0f290b2f4 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.cc
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.cc
@@ -47,9 +47,7 @@ ApplicationCacheHostForFrame::ApplicationCacheHostForFrame(
const BrowserInterfaceBrokerProxy& interface_broker_proxy,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const base::UnguessableToken& appcache_host_id)
- : ApplicationCacheHost(interface_broker_proxy,
- std::move(task_runner),
- document_loader->GetFrame()->DomWindow()),
+ : ApplicationCacheHost(interface_broker_proxy, std::move(task_runner)),
local_frame_(document_loader->GetFrame()),
document_loader_(document_loader) {
// PlzNavigate: The browser passes the ID to be used.
@@ -136,11 +134,8 @@ void ApplicationCacheHostForFrame::SetSubresourceFactory(
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
url_loader_factory) {
auto pending_factories = std::make_unique<PendingURLLoaderFactoryBundle>();
- // |PassPipe()| invalidates all state, so capture |version()| first.
- uint32_t version = url_loader_factory.version();
pending_factories->pending_appcache_factory() =
- mojo::PendingRemote<network::mojom::URLLoaderFactory>(
- url_loader_factory.PassPipe(), version);
+ ToCrossVariantMojoType(std::move(url_loader_factory));
local_frame_->Client()->UpdateSubresourceFactory(
std::move(pending_factories));
}
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.cc b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.cc
index f046a63cf23..9cb4e9fea3b 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.cc
@@ -9,11 +9,8 @@ namespace blink {
ApplicationCacheHostForWorker::ApplicationCacheHostForWorker(
const base::UnguessableToken& appcache_host_id,
const BrowserInterfaceBrokerProxy& interface_broker_proxy,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- ContextLifecycleNotifier* notifier)
- : ApplicationCacheHost(interface_broker_proxy,
- std::move(task_runner),
- notifier) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : ApplicationCacheHost(interface_broker_proxy, std::move(task_runner)) {
SetHostID(appcache_host_id ? appcache_host_id
: base::UnguessableToken::Create());
BindBackend();
diff --git a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.h b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.h
index ff6327933f2..5a51ec72a97 100644
--- a/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.h
+++ b/chromium/third_party/blink/renderer/core/loader/appcache/application_cache_host_for_worker.h
@@ -14,8 +14,7 @@ class ApplicationCacheHostForWorker final : public ApplicationCacheHost {
ApplicationCacheHostForWorker(
const base::UnguessableToken& appcache_host_id,
const BrowserInterfaceBrokerProxy& interface_broker_proxy,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- ContextLifecycleNotifier* notifier);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~ApplicationCacheHostForWorker() override;
};
diff --git a/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.cc b/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.cc
new file mode 100644
index 00000000000..985a4c7435b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.cc
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h"
+
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+
+namespace blink {
+
+void BackForwardCacheLoaderHelperForFrame::EvictFromBackForwardCache(
+ mojom::blink::RendererEvictionReason reason) {
+ if (!frame_)
+ return;
+ frame_->EvictFromBackForwardCache(reason);
+}
+
+void BackForwardCacheLoaderHelperForFrame::DidBufferLoadWhileInBackForwardCache(
+ size_t num_bytes) {
+ if (!frame_)
+ return;
+ frame_->DidBufferLoadWhileInBackForwardCache(num_bytes);
+}
+
+bool BackForwardCacheLoaderHelperForFrame::
+ CanContinueBufferingWhileInBackForwardCache() const {
+ if (!frame_)
+ return false;
+ return frame_->CanContinueBufferingWhileInBackForwardCache();
+}
+
+void BackForwardCacheLoaderHelperForFrame::Detach() {
+ frame_ = nullptr;
+}
+
+void BackForwardCacheLoaderHelperForFrame::Trace(Visitor* visitor) const {
+ visitor->Trace(frame_);
+ BackForwardCacheLoaderHelper::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h b/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h
new file mode 100644
index 00000000000..547d1600986
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BACK_FORWARD_CACHE_LOADER_HELPER_FOR_FRAME_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BACK_FORWARD_CACHE_LOADER_HELPER_FOR_FRAME_H_
+
+#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
+
+namespace blink {
+
+class LocalFrame;
+
+class BackForwardCacheLoaderHelperForFrame
+ : public BackForwardCacheLoaderHelper {
+ public:
+ explicit BackForwardCacheLoaderHelperForFrame(LocalFrame& frame)
+ : frame_(&frame) {}
+
+ void EvictFromBackForwardCache(
+ mojom::blink::RendererEvictionReason reason) override;
+ void DidBufferLoadWhileInBackForwardCache(size_t num_bytes) override;
+ bool CanContinueBufferingWhileInBackForwardCache() const override;
+ void Detach() override;
+ void Trace(Visitor*) const override;
+
+ private:
+ WeakMember<LocalFrame> frame_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BACK_FORWARD_CACHE_LOADER_HELPER_FOR_FRAME_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
index f0be0f5ecee..96beedf1085 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -4,7 +4,11 @@
#include "third_party/blink/renderer/core/loader/base_fetch_context.h"
+#include "net/http/structured_headers.h"
#include "services/network/public/cpp/request_mode.h"
+#include "third_party/blink/public/common/client_hints/client_hints.h"
+#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
+#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
@@ -13,8 +17,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
-#include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
+#include "third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -24,9 +27,26 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
+#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
+namespace {
+
+// Simple function to add quotes to make headers strings.
+const AtomicString SerializeHeaderString(std::string str) {
+ std::string output;
+ if (!str.empty()) {
+ output = net::structured_headers::SerializeItem(
+ net::structured_headers::Item(str))
+ .value_or(std::string());
+ }
+
+ return AtomicString(output.c_str());
+}
+
+} // namespace
+
namespace blink {
base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest(
@@ -47,17 +67,41 @@ base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest(
return blocked_reason;
}
+base::Optional<ResourceRequestBlockedReason>
+BaseFetchContext::CanRequestBasedOnSubresourceFilterOnly(
+ ResourceType type,
+ const ResourceRequest& resource_request,
+ const KURL& url,
+ const ResourceLoaderOptions& options,
+ ReportingDisposition reporting_disposition,
+ const base::Optional<ResourceRequest::RedirectInfo>& redirect_info) const {
+ auto* subresource_filter = GetSubresourceFilter();
+ if (subresource_filter && type != ResourceType::kImportResource &&
+ !subresource_filter->AllowLoad(url, resource_request.GetRequestContext(),
+ reporting_disposition)) {
+ if (reporting_disposition == ReportingDisposition::kReport) {
+ DispatchDidBlockRequest(resource_request, options.initiator_info,
+ ResourceRequestBlockedReason::kSubresourceFilter,
+ type);
+ }
+ return ResourceRequestBlockedReason::kSubresourceFilter;
+ }
+
+ return base::nullopt;
+}
+
bool BaseFetchContext::CalculateIfAdSubresource(
- const ResourceRequest& request,
+ const ResourceRequestHead& request,
+ const base::Optional<KURL>& alias_url,
ResourceType type,
const FetchInitiatorInfo& initiator_info) {
- // A base class should override this is they have more signals than just the
- // SubresourceFilter.
+ // A derived class should override this if they have more signals than just
+ // the SubresourceFilter.
SubresourceFilter* filter = GetSubresourceFilter();
+ const KURL& url = alias_url ? alias_url.value() : request.Url();
return request.IsAdResource() ||
- (filter &&
- filter->IsAdResource(request.Url(), request.GetRequestContext()));
+ (filter && filter->IsAdResource(url, request.GetRequestContext()));
}
bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting(
@@ -67,6 +111,229 @@ bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting(
return false;
}
+void BaseFetchContext::AddClientHintsIfNecessary(
+ const ClientHintsPreferences& hints_preferences,
+ const url::Origin& resource_origin,
+ bool is_1p_origin,
+ base::Optional<UserAgentMetadata> ua,
+ const FeaturePolicy* policy,
+ const base::Optional<ClientHintImageInfo>& image_info,
+ const base::Optional<WTF::AtomicString>& lang,
+ ResourceRequest& request) {
+ // If the feature is enabled, then client hints are allowed only on secure
+ // URLs.
+ if (!ClientHintsPreferences::IsClientHintsAllowed(request.Url()))
+ return;
+
+ // Sec-CH-UA is special: we always send the header to all origins that are
+ // eligible for client hints (e.g. secure transport, JavaScript enabled).
+ //
+ // https://github.com/WICG/ua-client-hints
+ //
+ // One exception, however, is that a custom UA is sometimes set without
+ // specifying accomponying client hints, in which case we disable sending
+ // them.
+ if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua) {
+ // ShouldSendClientHint is called to make sure UA is controlled by
+ // FeaturePolicy.
+ if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
+ resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUA,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUA)],
+ ua->SerializeBrandVersionList().c_str());
+ }
+
+ // We also send Sec-CH-UA-Mobile to all hints. It is a one-bit header
+ // identifying if the browser has opted for a "mobile" experience
+ // Formatted using the "sh-boolean" format from:
+ // https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html#boolean
+ // ShouldSendClientHint is called to make sure it's controlled by
+ // FeaturePolicy.
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAMobile,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAMobile)],
+ ua->mobile ? "?1" : "?0");
+ }
+ }
+
+ // If the frame is detached, then don't send any hints other than UA.
+ if (!policy)
+ return;
+
+ if (!RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled() &&
+ !base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty) &&
+ !is_1p_origin) {
+ // No client hints for 3p origins.
+ return;
+ }
+
+ // The next 4 hints should be enabled if we're allowing legacy hints to third
+ // parties, or if FeaturePolicy delegation says they are allowed.
+ if (ShouldSendClientHint(
+ ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kDeviceMemory,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ "Device-Memory",
+ AtomicString(String::Number(
+ ApproximatedDeviceMemory::GetApproximatedDeviceMemory())));
+ }
+
+ // These hints only make sense if the image info is available
+ if (image_info) {
+ if (ShouldSendClientHint(ClientHintsMode::kLegacy, policy, resource_origin,
+ is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kDpr,
+ hints_preferences)) {
+ request.SetHttpHeaderField("DPR",
+ AtomicString(String::Number(image_info->dpr)));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kViewportWidth,
+ hints_preferences) &&
+ image_info->viewport_width) {
+ request.SetHttpHeaderField(
+ "Viewport-Width",
+ AtomicString(String::Number(image_info->viewport_width.value())));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kResourceWidth,
+ hints_preferences)) {
+ if (image_info->resource_width.is_set) {
+ float physical_width =
+ image_info->resource_width.width * image_info->dpr;
+ request.SetHttpHeaderField(
+ "Width", AtomicString(String::Number(ceil(physical_width))));
+ }
+ }
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kRtt, hints_preferences)) {
+ base::Optional<base::TimeDelta> http_rtt =
+ GetNetworkStateNotifier().GetWebHoldbackHttpRtt();
+ if (!http_rtt) {
+ http_rtt = GetNetworkStateNotifier().HttpRtt();
+ }
+
+ uint32_t rtt =
+ GetNetworkStateNotifier().RoundRtt(request.Url().Host(), http_rtt);
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kRtt)],
+ AtomicString(String::Number(rtt)));
+ }
+
+ if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
+ is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kDownlink,
+ hints_preferences)) {
+ base::Optional<double> throughput_mbps =
+ GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps();
+ if (!throughput_mbps) {
+ throughput_mbps = GetNetworkStateNotifier().DownlinkThroughputMbps();
+ }
+
+ double mbps = GetNetworkStateNotifier().RoundMbps(request.Url().Host(),
+ throughput_mbps);
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kDownlink)],
+ AtomicString(String::Number(mbps)));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kEct, hints_preferences)) {
+ base::Optional<WebEffectiveConnectionType> holdback_ect =
+ GetNetworkStateNotifier().GetWebHoldbackEffectiveType();
+ if (!holdback_ect)
+ holdback_ect = GetNetworkStateNotifier().EffectiveType();
+
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kEct)],
+ AtomicString(NetworkStateNotifier::EffectiveConnectionTypeToString(
+ holdback_ect.value())));
+ }
+
+ if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
+ is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kLang,
+ hints_preferences) &&
+ lang) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kLang)],
+ lang.value());
+ }
+
+ // Only send User Agent hints if the info is available
+ if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua) {
+ if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
+ resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAArch,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAArch)],
+ SerializeHeaderString(ua->architecture));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAPlatform,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAPlatform)],
+ SerializeHeaderString(ua->platform));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAPlatformVersion,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAPlatformVersion)],
+ SerializeHeaderString(ua->platform_version));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAModel,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAModel)],
+ SerializeHeaderString(ua->model));
+ }
+
+ if (ShouldSendClientHint(
+ ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
+ network::mojom::blink::WebClientHintsType::kUAFullVersion,
+ hints_preferences)) {
+ request.SetHttpHeaderField(
+ blink::kClientHintsHeaderMapping[static_cast<size_t>(
+ network::mojom::blink::WebClientHintsType::kUAFullVersion)],
+ SerializeHeaderString(ua->full_version));
+ }
+ }
+}
+
void BaseFetchContext::PrintAccessDeniedMessage(const KURL& url) const {
if (url.IsNull())
return;
@@ -119,7 +386,7 @@ BaseFetchContext::CheckCSPForRequestInternal(
return base::nullopt;
}
- const ContentSecurityPolicy* csp =
+ ContentSecurityPolicy* csp =
GetContentSecurityPolicyForWorld(options.world_for_csp.get());
if (csp &&
!csp->AllowRequest(request_context, request_destination, url,
@@ -254,16 +521,9 @@ BaseFetchContext::CanRequestInternal(
return ResourceRequestBlockedReason::kOther;
}
- // Loading of a subresource may be blocked by previews resource loading hints.
- if (GetPreviewsResourceLoadingHints() &&
- !GetPreviewsResourceLoadingHints()->AllowLoad(
- type, url, resource_request.Priority())) {
- return ResourceRequestBlockedReason::kOther;
- }
-
if (SendConversionRequestInsteadOfRedirecting(url, redirect_info,
reporting_disposition)) {
- return ResourceRequestBlockedReason::kOther;
+ return ResourceRequestBlockedReason::kConversionRequest;
}
// Let the client have the final say into whether or not the load should
@@ -278,6 +538,33 @@ BaseFetchContext::CanRequestInternal(
return base::nullopt;
}
+bool BaseFetchContext::ShouldSendClientHint(
+ ClientHintsMode mode,
+ const FeaturePolicy* policy,
+ const url::Origin& resource_origin,
+ bool is_1p_origin,
+ network::mojom::blink::WebClientHintsType type,
+ const ClientHintsPreferences& hints_preferences) const {
+ bool origin_ok;
+
+ if (mode == ClientHintsMode::kLegacy &&
+ base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty)) {
+ origin_ok = true;
+ } else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
+ origin_ok =
+ (policy && policy->IsFeatureEnabledForOrigin(
+ kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
+ resource_origin));
+ } else {
+ origin_ok = is_1p_origin;
+ }
+
+ if (!origin_ok)
+ return false;
+
+ return IsClientHintSentByDefault(type) || hints_preferences.ShouldSend(type);
+}
+
void BaseFetchContext::AddBackForwardCacheExperimentHTTPHeaderIfNeeded(
ExecutionContext* context,
ResourceRequest& request) {
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
index 135719df797..5d75bc33d26 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context.h
@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "net/cookies/site_for_cookies.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
+#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -24,12 +25,19 @@ class ConsoleMessage;
class DOMWrapperWorld;
class DetachableResourceFetcherProperties;
class KURL;
-class PreviewsResourceLoadingHints;
class SecurityOrigin;
class SubresourceFilter;
class WebSocketHandshakeThrottle;
-// A core-level implementaiton of FetchContext that does not depend on
+// This is information for client hints that only make sense when attached to a
+// frame
+struct ClientHintImageInfo {
+ float dpr;
+ FetchParameters::ResourceWidth resource_width;
+ base::Optional<int> viewport_width;
+};
+
+// A core-level implementation of FetchContext that does not depend on
// Frame. This class provides basic default implementation for some methods.
class CORE_EXPORT BaseFetchContext : public FetchContext {
public:
@@ -40,6 +48,14 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const ResourceLoaderOptions&,
ReportingDisposition,
const base::Optional<ResourceRequest::RedirectInfo>&) const override;
+ base::Optional<ResourceRequestBlockedReason>
+ CanRequestBasedOnSubresourceFilterOnly(
+ ResourceType,
+ const ResourceRequest&,
+ const KURL&,
+ const ResourceLoaderOptions&,
+ ReportingDisposition,
+ const base::Optional<ResourceRequest::RedirectInfo>&) const override;
base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest(
mojom::blink::RequestContextType,
network::mojom::RequestDestination request_destination,
@@ -64,14 +80,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
virtual scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const = 0;
virtual SubresourceFilter* GetSubresourceFilter() const = 0;
- virtual PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
- const = 0;
virtual bool ShouldBlockWebSocketByMixedContentCheck(const KURL&) const = 0;
virtual std::unique_ptr<WebSocketHandshakeThrottle>
CreateWebSocketHandshakeThrottle() = 0;
+ // If the optional `alias_url` is non-null, it will be used to perform the
+ // check in place of `resource_request.Url()`, e.g. in the case of DNS
+ // aliases.
bool CalculateIfAdSubresource(
- const ResourceRequest& resource_request,
+ const ResourceRequestHead& resource_request,
+ const base::Optional<KURL>& alias_url,
ResourceType type,
const FetchInitiatorInfo& initiator_info) override;
@@ -83,6 +101,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const base::Optional<ResourceRequest::RedirectInfo>& redirect_info,
ReportingDisposition reporting_disposition) const;
+ void AddClientHintsIfNecessary(
+ const ClientHintsPreferences& hints_preferences,
+ const url::Origin& resource_origin,
+ bool is_1p_origin,
+ base::Optional<UserAgentMetadata> ua,
+ const FeaturePolicy* policy,
+ const base::Optional<ClientHintImageInfo>& image_info,
+ const base::Optional<WTF::AtomicString>& lang,
+ ResourceRequest& request);
+
protected:
explicit BaseFetchContext(
const DetachableResourceFetcherProperties& properties)
@@ -99,7 +127,7 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const FetchInitiatorInfo&,
ResourceRequestBlockedReason,
ResourceType) const = 0;
- virtual const ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
+ virtual ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const = 0;
virtual bool IsSVGImageChromeClient() const = 0;
@@ -113,7 +141,7 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const KURL&) const = 0;
virtual const KURL& Url() const = 0;
virtual const SecurityOrigin* GetParentSecurityOrigin() const = 0;
- virtual const ContentSecurityPolicy* GetContentSecurityPolicy() const = 0;
+ virtual ContentSecurityPolicy* GetContentSecurityPolicy() const = 0;
// TODO(yhirano): Remove this.
virtual void AddConsoleMessage(ConsoleMessage*) const = 0;
@@ -146,6 +174,14 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const KURL& url_before_redirects,
ResourceRequest::RedirectStatus redirect_status,
ContentSecurityPolicy::CheckHeaderType) const;
+
+ enum class ClientHintsMode { kLegacy, kStandard };
+ bool ShouldSendClientHint(ClientHintsMode mode,
+ const FeaturePolicy*,
+ const url::Origin&,
+ bool is_1p_origin,
+ network::mojom::blink::WebClientHintsType,
+ const ClientHintsPreferences&) const;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc b/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
index 38300322610..ca8cf565463 100644
--- a/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/base_fetch_context_test.cc
@@ -63,10 +63,6 @@ class MockBaseFetchContext final : public BaseFetchContext {
}
bool AllowScriptFromSource(const KURL&) const override { return false; }
SubresourceFilter* GetSubresourceFilter() const override { return nullptr; }
- PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
- const override {
- return nullptr;
- }
bool ShouldBlockRequestByInspector(const KURL&) const override {
return false;
}
@@ -74,7 +70,7 @@ class MockBaseFetchContext final : public BaseFetchContext {
const FetchInitiatorInfo&,
ResourceRequestBlockedReason,
ResourceType) const override {}
- const ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
+ ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const override {
return GetContentSecurityPolicy();
}
@@ -105,7 +101,7 @@ class MockBaseFetchContext final : public BaseFetchContext {
const SecurityOrigin* GetParentSecurityOrigin() const override {
return nullptr;
}
- const ContentSecurityPolicy* GetContentSecurityPolicy() const override {
+ ContentSecurityPolicy* GetContentSecurityPolicy() const override {
return execution_context_->GetContentSecurityPolicy();
}
void AddConsoleMessage(ConsoleMessage*) const override {}
@@ -123,6 +119,10 @@ class MockBaseFetchContext final : public BaseFetchContext {
class BaseFetchContextTest : public testing::Test {
protected:
+ ~BaseFetchContextTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
+
void SetUp() override {
execution_context_ = MakeGarbageCollected<NullExecutionContext>();
static_cast<NullExecutionContext*>(execution_context_.Get())
@@ -139,7 +139,8 @@ class BaseFetchContextTest : public testing::Test {
properties, fetch_context_,
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- MakeGarbageCollected<TestLoaderFactory>(), execution_context_));
+ MakeGarbageCollected<TestLoaderFactory>(), execution_context_,
+ nullptr /* back_forward_cache_loader_helper */));
}
const FetchClientSettingsObject& GetFetchClientSettingsObject() const {
@@ -160,9 +161,11 @@ TEST_F(BaseFetchContextTest, CanRequest) {
ContentSecurityPolicy* policy =
execution_context_->GetContentSecurityPolicy();
policy->DidReceiveHeader("script-src https://foo.test",
+ *(execution_context_->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
policy->DidReceiveHeader("script-src https://bar.test",
+ *(execution_context_->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kReport,
network::mojom::ContentSecurityPolicySource::kHTTP);
@@ -185,9 +188,11 @@ TEST_F(BaseFetchContextTest, CheckCSPForRequest) {
ContentSecurityPolicy* policy =
execution_context_->GetContentSecurityPolicy();
policy->DidReceiveHeader("script-src https://foo.test",
+ *(execution_context_->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
policy->DidReceiveHeader("script-src https://bar.test",
+ *(execution_context_->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kReport,
network::mojom::ContentSecurityPolicySource::kHTTP);
@@ -301,6 +306,7 @@ TEST_F(BaseFetchContextTest, UACSSTest_BypassCSP) {
ContentSecurityPolicy* policy =
execution_context_->GetContentSecurityPolicy();
policy->DidReceiveHeader("default-src 'self'",
+ *(execution_context_->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
diff --git a/chromium/third_party/blink/renderer/core/loader/build.gni b/chromium/third_party/blink/renderer/core/loader/build.gni
index c99a873720d..8271762986b 100644
--- a/chromium/third_party/blink/renderer/core/loader/build.gni
+++ b/chromium/third_party/blink/renderer/core/loader/build.gni
@@ -15,6 +15,8 @@ blink_core_sources_loader = [
"appcache/application_cache_host_for_frame.h",
"appcache/application_cache_host_for_worker.cc",
"appcache/application_cache_host_for_worker.h",
+ "back_forward_cache_loader_helper_for_frame.cc",
+ "back_forward_cache_loader_helper_for_frame.h",
"base_fetch_context.cc",
"base_fetch_context.h",
"cookie_jar.cc",
@@ -31,6 +33,8 @@ blink_core_sources_loader = [
"font_preload_manager.h",
"form_submission.cc",
"form_submission.h",
+ "frame_client_hints_preferences_context.cc",
+ "frame_client_hints_preferences_context.h",
"frame_fetch_context.cc",
"frame_fetch_context.h",
"frame_load_request.cc",
@@ -48,6 +52,8 @@ blink_core_sources_loader = [
"http_refresh_scheduler.h",
"idleness_detector.cc",
"idleness_detector.h",
+ "subresource_redirect_util.cc",
+ "subresource_redirect_util.h",
"image_loader.cc",
"image_loader.h",
"importance_attribute.cc",
@@ -73,6 +79,7 @@ blink_core_sources_loader = [
"modulescript/document_module_script_fetcher.h",
"modulescript/installed_service_worker_module_script_fetcher.cc",
"modulescript/installed_service_worker_module_script_fetcher.h",
+ "modulescript/module_script_creation_params.cc",
"modulescript/module_script_creation_params.h",
"modulescript/module_script_fetch_request.h",
"modulescript/module_script_fetcher.cc",
@@ -92,21 +99,16 @@ blink_core_sources_loader = [
"modulescript/worklet_module_script_fetcher.h",
"navigation_policy.cc",
"navigation_policy.h",
+ "no_state_prefetch_client.cc",
+ "no_state_prefetch_client.h",
"ping_loader.cc",
"ping_loader.h",
"prefetched_signed_exchange_manager.cc",
"prefetched_signed_exchange_manager.h",
"preload_helper.cc",
"preload_helper.h",
- "prerenderer_client.cc",
- "prerenderer_client.h",
- "previews_resource_loading_hints.cc",
- "previews_resource_loading_hints.h",
- "private/frame_client_hints_preferences_context.cc",
- "private/frame_client_hints_preferences_context.h",
- "private/prerender_client.h",
- "private/prerender_handle.cc",
- "private/prerender_handle.h",
+ "prerender_handle.cc",
+ "prerender_handle.h",
"progress_tracker.cc",
"progress_tracker.h",
"resource/css_style_sheet_resource.cc",
diff --git a/chromium/third_party/blink/renderer/core/loader/document_load_timing.cc b/chromium/third_party/blink/renderer/core/loader/document_load_timing.cc
index 60996694441..024758372ad 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_load_timing.cc
+++ b/chromium/third_party/blink/renderer/core/loader/document_load_timing.cc
@@ -33,13 +33,14 @@
#include "third_party/blink/renderer/core/loader/document_loader.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/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
DocumentLoadTiming::DocumentLoadTiming(DocumentLoader& document_loader)
: redirect_count_(0),
has_cross_origin_redirect_(false),
- has_same_origin_as_previous_document_(false),
+ can_request_from_previous_document_(false),
clock_(base::DefaultClock::GetInstance()),
tick_clock_(base::DefaultTickClock::GetInstance()),
document_loader_(document_loader) {}
@@ -114,20 +115,20 @@ void DocumentLoadTiming::MarkNavigationStart() {
navigation_start_ = reference_monotonic_time_;
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
"blink.user_timing", "navigationStart", navigation_start_, "frame",
- ToTraceValue(GetFrame()), "data", GetNavigationStartTracingData());
+ ToTraceValue(GetFrame()), "data", [&](perfetto::TracedValue ctx) {
+ WriteNavigationStartDataIntoTracedValue(std::move(ctx));
+ });
NotifyDocumentTimingChanged();
}
-std::unique_ptr<TracedValue> DocumentLoadTiming::GetNavigationStartTracingData()
- const {
- auto data = std::make_unique<TracedValue>();
- data->SetString("documentLoaderURL",
- document_loader_ ? document_loader_->Url().GetString() : "");
- data->SetBoolean("isLoadingMainFrame",
- GetFrame() ? GetFrame()->IsMainFrame() : false);
- data->SetString("navigationId",
- IdentifiersFactory::LoaderId(document_loader_));
- return data;
+void DocumentLoadTiming::WriteNavigationStartDataIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("documentLoaderURL",
+ document_loader_ ? document_loader_->Url().GetString() : "");
+ dict.Add("isLoadingMainFrame",
+ GetFrame() ? GetFrame()->IsMainFrame() : false);
+ dict.Add("navigationId", IdentifiersFactory::LoaderId(document_loader_));
}
void DocumentLoadTiming::SetNavigationStart(base::TimeTicks navigation_start) {
@@ -138,7 +139,9 @@ void DocumentLoadTiming::SetNavigationStart(base::TimeTicks navigation_start) {
navigation_start_ = navigation_start;
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
"blink.user_timing", "navigationStart", navigation_start_, "frame",
- ToTraceValue(GetFrame()), "data", GetNavigationStartTracingData());
+ ToTraceValue(GetFrame()), "data", [&](perfetto::TracedValue context) {
+ WriteNavigationStartDataIntoTracedValue(std::move(context));
+ });
// The reference times are adjusted based on the embedder's navigationStart.
DCHECK(!reference_monotonic_time_.is_null());
@@ -249,4 +252,12 @@ void DocumentLoadTiming::MarkRedirectEnd() {
NotifyDocumentTimingChanged();
}
+void DocumentLoadTiming::MarkCommitNavigationEnd() {
+ commit_navigation_end_ = tick_clock_->NowTicks();
+ TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "commitNavigationEnd",
+ commit_navigation_end_, "frame",
+ ToTraceValue(GetFrame()));
+ NotifyDocumentTimingChanged();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/document_load_timing.h b/chromium/third_party/blink/renderer/core/loader/document_load_timing.h
index d108e016b99..12277ada1b2 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_load_timing.h
+++ b/chromium/third_party/blink/renderer/core/loader/document_load_timing.h
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
class Clock;
@@ -55,6 +56,7 @@ class CORE_EXPORT DocumentLoadTiming final {
void MarkNavigationStart();
void SetNavigationStart(base::TimeTicks);
void MarkBackForwardCacheRestoreNavigationStart(base::TimeTicks);
+ void MarkCommitNavigationEnd();
void SetInputStart(base::TimeTicks);
@@ -77,8 +79,8 @@ class CORE_EXPORT DocumentLoadTiming final {
void MarkLoadEventStart();
void MarkLoadEventEnd();
- void SetHasSameOriginAsPreviousDocument(bool value) {
- has_same_origin_as_previous_document_ = value;
+ void SetCanRequestFromPreviousDocument(bool value) {
+ can_request_from_previous_document_ = value;
}
base::TimeTicks InputStart() const { return input_start_; }
@@ -87,6 +89,7 @@ class CORE_EXPORT DocumentLoadTiming final {
const {
return bfcache_restore_navigation_starts_;
}
+ base::TimeTicks CommitNavigationEnd() const { return commit_navigation_end_; }
base::TimeTicks UnloadEventStart() const { return unload_event_start_; }
base::TimeTicks UnloadEventEnd() const { return unload_event_end_; }
base::TimeTicks RedirectStart() const { return redirect_start_; }
@@ -97,8 +100,8 @@ class CORE_EXPORT DocumentLoadTiming final {
base::TimeTicks LoadEventStart() const { return load_event_start_; }
base::TimeTicks LoadEventEnd() const { return load_event_end_; }
bool HasCrossOriginRedirect() const { return has_cross_origin_redirect_; }
- bool HasSameOriginAsPreviousDocument() const {
- return has_same_origin_as_previous_document_;
+ bool CanRequestFromPreviousDocument() const {
+ return can_request_from_previous_document_;
}
base::TimeTicks ReferenceMonotonicTime() const {
@@ -115,12 +118,14 @@ class CORE_EXPORT DocumentLoadTiming final {
void NotifyDocumentTimingChanged();
void EnsureReferenceTimesSet();
LocalFrame* GetFrame() const;
- std::unique_ptr<TracedValue> GetNavigationStartTracingData() const;
+ void WriteNavigationStartDataIntoTracedValue(
+ perfetto::TracedValue context) const;
base::TimeTicks reference_monotonic_time_;
base::TimeDelta reference_wall_time_;
base::TimeTicks input_start_;
base::TimeTicks navigation_start_;
+ base::TimeTicks commit_navigation_end_;
WTF::Vector<base::TimeTicks> bfcache_restore_navigation_starts_;
base::TimeTicks unload_event_start_;
base::TimeTicks unload_event_end_;
@@ -132,7 +137,7 @@ class CORE_EXPORT DocumentLoadTiming final {
base::TimeTicks load_event_start_;
base::TimeTicks load_event_end_;
bool has_cross_origin_redirect_;
- bool has_same_origin_as_previous_document_;
+ bool can_request_from_previous_document_;
const base::Clock* clock_;
const base::TickClock* tick_clock_;
diff --git a/chromium/third_party/blink/renderer/core/loader/document_loader.cc b/chromium/third_party/blink/renderer/core/loader/document_loader.cc
index 71dc068d2c2..e773f04ee2f 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/document_loader.cc
@@ -68,16 +68,16 @@
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
+#include "third_party/blink/renderer/core/loader/address_space_feature.h"
#include "third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
+#include "third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h"
#include "third_party/blink/renderer/core/loader/frame_fetch_context.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/loader/idleness_detector.h"
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
-#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.h"
#include "third_party/blink/renderer/core/loader/preload_helper.h"
-#include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
#include "third_party/blink/renderer/core/loader/progress_tracker.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
@@ -136,6 +136,19 @@ Vector<OriginTrialFeature> CopyInitiatorOriginTrials(
return result;
}
+WebVector<int> CopyInitiatorOriginTrials(
+ const Vector<OriginTrialFeature>& initiator_origin_trial_features) {
+ WebVector<int> result;
+ for (auto feature : initiator_origin_trial_features) {
+ // Convert from OriginTrialFeature to int. These values are passed between
+ // blink navigations. OriginTrialFeature isn't visible outside of blink (and
+ // doesn't need to be) so the values are transferred outside of blink as
+ // ints and casted to OriginTrialFeature once being processed in blink.
+ result.emplace_back(static_cast<int>(feature));
+ }
+ return result;
+}
+
Vector<String> CopyForceEnabledOriginTrials(
const WebVector<WebString>& force_enabled_origin_trials) {
Vector<String> result;
@@ -146,11 +159,110 @@ Vector<String> CopyForceEnabledOriginTrials(
return result;
}
+WebVector<WebString> CopyForceEnabledOriginTrials(
+ const Vector<String>& force_enabled_origin_trials) {
+ WebVector<String> result;
+ for (const auto& trial : force_enabled_origin_trials)
+ result.emplace_back(trial);
+ return result;
+}
+
bool IsPagePopupRunningInWebTest(LocalFrame* frame) {
return frame && frame->GetPage()->GetChromeClient().IsPopup() &&
WebTestSupport::IsRunningWebTest();
}
+struct SameSizeAsDocumentLoader
+ : public GarbageCollected<SameSizeAsDocumentLoader>,
+ public UseCounter,
+ public WebNavigationBodyLoader::Client {
+ Vector<KURL> redirect_chain;
+ Member<MHTMLArchive> archive;
+ std::unique_ptr<WebNavigationParams> params;
+ KURL url;
+ AtomicString http_method;
+ Referrer referrer;
+ scoped_refptr<EncodedFormData> http_body;
+ AtomicString http_content_type;
+ PreviewsState previews_state;
+ base::Optional<WebOriginPolicy> origin_policy;
+ scoped_refptr<const SecurityOrigin> requestor_origin;
+ KURL unreachable_url;
+ KURL pre_redirect_url_for_failed_navigations;
+ std::unique_ptr<WebNavigationBodyLoader> body_loader;
+ bool grant_load_local_resources;
+ base::Optional<blink::mojom::FetchCacheMode> force_fetch_cache_mode;
+ FramePolicy frame_policy;
+ Member<LocalFrame> frame;
+ Member<HistoryItem> history_item;
+ Member<DocumentParser> parser;
+ Member<SubresourceFilter> subresource_filter;
+ KURL original_url;
+ Referrer original_referrer;
+ ResourceResponse response;
+ WebFrameLoadType load_type;
+ bool is_client_redirect;
+ bool replaces_current_history_item;
+ bool data_received;
+ bool is_error_page_for_failed_navigation;
+ Member<ContentSecurityPolicy> content_security_policy;
+ mojo::Remote<mojom::blink::ContentSecurityNotifier> content_security_notifier;
+ scoped_refptr<SecurityOrigin> origin_to_commit;
+ WebNavigationType navigation_type;
+ DocumentLoadTiming document_load_timing;
+ base::TimeTicks time_of_last_data_received;
+ Member<ApplicationCacheHostForFrame> application_cache_host;
+ std::unique_ptr<WebServiceWorkerNetworkProvider>
+ service_worker_network_provider;
+ DocumentPolicy::ParsedDocumentPolicy document_policy;
+ bool was_blocked_by_document_policy;
+ Vector<PolicyParserMessageBuffer::Message> document_policy_parsing_messages;
+ ClientHintsPreferences client_hints_preferences;
+ DocumentLoader::InitialScrollState initial_scroll_state;
+ DocumentLoader::State state;
+ int parser_blocked_count;
+ bool finish_loading_when_parser_resumed;
+ bool in_commit_data;
+ scoped_refptr<SharedBuffer> data_buffer;
+ base::UnguessableToken devtools_navigation_token;
+ WebURLLoader::DeferType defers_loading;
+ bool last_navigation_had_transient_user_activation;
+ bool had_sticky_activation;
+ bool is_browser_initiated;
+ bool is_prerendering;
+ bool is_same_origin_navigation;
+ bool has_text_fragment_token;
+ bool was_discarded;
+ bool listing_ftp_directory;
+ bool loading_main_document_from_mhtml_archive;
+ bool loading_srcdoc;
+ bool loading_url_as_empty_document;
+ CommitReason commit_reason;
+ uint64_t main_resource_identifier;
+ scoped_refptr<ResourceTimingInfo> navigation_timing_info;
+ bool report_timing_info_to_parent;
+ WebScopedVirtualTimePauser virtual_time_pauser;
+ Member<SourceKeyedCachedMetadataHandler> cached_metadata_handler;
+ Member<PrefetchedSignedExchangeManager> prefetched_signed_exchange_manager;
+ const KURL web_bundle_physical_url;
+ const KURL web_bundle_claimed_url;
+ ukm::SourceId ukm_source_id;
+ UseCounterHelper use_counter;
+ Dactyloscoper dactyloscoper;
+ const base::TickClock* clock;
+ const Vector<OriginTrialFeature> initiator_origin_trial_features;
+ const Vector<String> force_enabled_origin_trials;
+ bool navigation_scroll_allowed;
+ bool origin_agent_cluster;
+ bool is_cross_browsing_context_group_navigation;
+};
+
+// Asserts size of DocumentLoader, so that whenever a new attribute is added to
+// DocumentLoader, the assert will fail. When hitting this assert failure,
+// please ensure that the attribute is copied correctly (if appropriate) in
+// DocumentLoader::CreateWebNavigationParamsToCloneDocument().
+ASSERT_SIZE(DocumentLoader, SameSizeAsDocumentLoader);
+
} // namespace
DocumentLoader::DocumentLoader(
@@ -170,7 +282,8 @@ DocumentLoader::DocumentLoader(
origin_policy_(params_->origin_policy),
requestor_origin_(params_->requestor_origin),
unreachable_url_(params_->unreachable_url),
- ip_address_space_(params_->ip_address_space),
+ pre_redirect_url_for_failed_navigations_(
+ params_->pre_redirect_url_for_failed_navigations),
grant_load_local_resources_(params_->grant_load_local_resources),
force_fetch_cache_mode_(params_->force_fetch_cache_mode),
frame_policy_(params_->frame_policy.value_or(FramePolicy())),
@@ -197,12 +310,14 @@ DocumentLoader::DocumentLoader(
load_type_ == WebFrameLoadType::kReplaceCurrentItem &&
(!frame_->Loader().Opener() || !url_.IsEmpty())),
data_received_(false),
+ is_error_page_for_failed_navigation_(
+ SchemeRegistry::ShouldTreatURLSchemeAsError(
+ response_.ResponseUrl().Protocol())),
// The input CSP is null when the CSP check done in the FrameLoader failed
content_security_policy_(
content_security_policy
? content_security_policy
: MakeGarbageCollected<ContentSecurityPolicy>()),
- was_blocked_by_csp_(!content_security_policy),
// Loading the document was blocked by the CSP check. Pretend that this
// was an empty document instead and don't reuse the original URL. More
// details in: https://crbug.com/622385.
@@ -214,13 +329,9 @@ DocumentLoader::DocumentLoader(
// Note: this doesn't use |url_| for the origin calculation, because
// redirects are not yet accounted for (this happens later in
// StartLoadingInternal).
- origin_to_commit_(
- was_blocked_by_csp_
- ? blink::SecurityOrigin::Create(response_.CurrentRequestUrl())
- ->DeriveNewOpaqueOrigin()
- : params_->origin_to_commit.IsNull()
- ? nullptr
- : params_->origin_to_commit.Get()->IsolatedCopy()),
+ origin_to_commit_(params_->origin_to_commit.IsNull()
+ ? nullptr
+ : params_->origin_to_commit.Get()->IsolatedCopy()),
navigation_type_(navigation_type),
document_load_timing_(*this),
service_worker_network_provider_(
@@ -230,11 +341,11 @@ DocumentLoader::DocumentLoader(
in_commit_data_(false),
data_buffer_(SharedBuffer::Create()),
devtools_navigation_token_(params_->devtools_navigation_token),
+ last_navigation_had_transient_user_activation_(
+ params_->had_transient_user_activation),
had_sticky_activation_(params_->is_user_activated),
- had_transient_activation_(
- LocalFrame::HasTransientUserActivation(frame_) ||
- params_->had_transient_activation),
is_browser_initiated_(params_->is_browser_initiated),
+ is_prerendering_(params_->is_prerendering),
was_discarded_(params_->was_discarded),
loading_srcdoc_(url_.IsAboutSrcdocURL()),
loading_url_as_empty_document_(!params_->is_static_data &&
@@ -248,7 +359,7 @@ DocumentLoader::DocumentLoader(
CopyInitiatorOriginTrials(params_->initiator_origin_trial_features)),
force_enabled_origin_trials_(
CopyForceEnabledOriginTrials(params_->force_enabled_origin_trials)),
- origin_isolated_(params_->origin_isolated),
+ origin_agent_cluster_(params_->origin_agent_cluster),
is_cross_browsing_context_group_navigation_(
params_->is_cross_browsing_context_group_navigation) {
DCHECK(frame_);
@@ -296,11 +407,14 @@ DocumentLoader::DocumentLoader(
}
// The document URL needs to be added to the head of the list as that is
- // where the redirects originated.
+ // where the redirects originated. Note that this is currently broken if we
+ // don't reuse the RenderFrame (e.g. cross-site navigations) - this will
+ // result in an empty URL or about:blank in that case.
+ // TODO(https://crbug.com/1171210): Fix this.
if (is_client_redirect_)
redirect_chain_.push_back(frame_->GetDocument()->Url());
- if (was_blocked_by_csp_ || was_blocked_by_document_policy_)
+ if (was_blocked_by_document_policy_)
ReplaceWithEmptyDocument();
if (commit_reason_ != CommitReason::kInitialization)
@@ -310,6 +424,70 @@ DocumentLoader::DocumentLoader(
DCHECK(history_item_);
}
+std::unique_ptr<WebNavigationParams>
+DocumentLoader::CreateWebNavigationParamsToCloneDocument() {
+ // From the browser process point of view, committing the result of evaluating
+ // a javascript URL or an XSLT document are all a no-op. Since we will use the
+ // resulting |params| to create a clone of this DocumentLoader, many
+ // attributes of DocumentLoader should be copied/inherited to the new
+ // DocumentLoader's WebNavigationParams. The current heuristic is largely
+ // based on copying fields that are populated in the DocumentLoader
+ // constructor. Some exclusions:
+ // |history_item_| is set in SetHistoryItemStateForCommit().
+ // |original_url_| will use the newly committed URL.
+ // |response_| will use the newly committed response.
+ // |load_type_| will use default kStandard value.
+ // |replaces_current_history_item_| will be false.
+ // |feature_policy_| and |document_policy_| are set in CommitNavigation(),
+ // with the sandbox flags set in CalculateSandboxFlags().
+ // |is_client_redirect_| and |redirect_chain_| are not copied since future
+ // same-document navigations will clear the redirect chain anyways.
+ // |archive_| and other states might need to be copied, but we need to add
+ // fields to WebNavigationParams and create WebMHTMLArchive, etc.
+ // TODO(https://crbug.com/1151954): Copy |archive_| and other attributes.
+ auto params = std::make_unique<WebNavigationParams>();
+ LocalDOMWindow* window = frame_->DomWindow();
+ params->url = window->Url();
+ params->unreachable_url = unreachable_url_;
+ params->referrer = referrer_.referrer;
+ // All the security properties of the document must be preserved. Note that
+ // sandbox flags and various policies are copied separately during commit in
+ // CommitNavigation() and CalculateSandboxFlags().
+ params->origin_to_commit = window->GetSecurityOrigin();
+ params->origin_agent_cluster = origin_agent_cluster_;
+ params->grant_load_local_resources = grant_load_local_resources_;
+ // Various attributes that relates to the last "real" navigation that is known
+ // by the browser must be carried over.
+ params->http_method = http_method_;
+ params->http_status_code = GetResponse().HttpStatusCode();
+ params->http_body = http_body_;
+ params->pre_redirect_url_for_failed_navigations =
+ pre_redirect_url_for_failed_navigations_;
+ params->force_fetch_cache_mode = force_fetch_cache_mode_;
+ params->service_worker_network_provider =
+ std::move(service_worker_network_provider_);
+ params->devtools_navigation_token = devtools_navigation_token_;
+ params->is_user_activated = had_sticky_activation_;
+ params->had_transient_user_activation =
+ last_navigation_had_transient_user_activation_;
+ params->is_browser_initiated = is_browser_initiated_;
+ params->is_prerendering = is_prerendering_;
+ params->was_discarded = was_discarded_;
+ params->web_bundle_physical_url = web_bundle_physical_url_;
+ params->web_bundle_claimed_url = web_bundle_claimed_url_;
+ params->document_ukm_source_id = ukm_source_id_;
+ params->is_cross_browsing_context_group_navigation =
+ is_cross_browsing_context_group_navigation_;
+ params->has_text_fragment_token = has_text_fragment_token_;
+ params->previews_state = previews_state_;
+ // Origin trials must still work on the cloned document.
+ params->initiator_origin_trial_features =
+ CopyInitiatorOriginTrials(initiator_origin_trial_features_);
+ params->force_enabled_origin_trials =
+ CopyForceEnabledOriginTrials(force_enabled_origin_trials_);
+ return params;
+}
+
FrameLoader& DocumentLoader::GetFrameLoader() const {
DCHECK(frame_);
return frame_->Loader();
@@ -338,7 +516,6 @@ void DocumentLoader::Trace(Visitor* visitor) const {
visitor->Trace(history_item_);
visitor->Trace(parser_);
visitor->Trace(subresource_filter_);
- visitor->Trace(resource_loading_hints_);
visitor->Trace(document_load_timing_);
visitor->Trace(application_cache_host_);
visitor->Trace(content_security_policy_);
@@ -456,6 +633,16 @@ static SinglePageAppNavigationType CategorizeSinglePageAppNavigation(
return kSPANavTypeSameDocumentBackwardOrForward;
}
+void DocumentLoader::RunURLAndHistoryUpdateSteps(
+ const KURL& new_url,
+ scoped_refptr<SerializedScriptValue> data,
+ mojom::blink::ScrollRestorationType scroll_restoration_type,
+ WebFrameLoadType type) {
+ UpdateForSameDocumentNavigation(new_url, kSameDocumentNavigationHistoryApi,
+ std::move(data), scroll_restoration_type,
+ type, true);
+}
+
void DocumentLoader::UpdateForSameDocumentNavigation(
const KURL& new_url,
SameDocumentNavigationSource same_document_navigation_source,
@@ -488,7 +675,11 @@ void DocumentLoader::UpdateForSameDocumentNavigation(
original_url_ = new_url;
url_ = new_url;
replaces_current_history_item_ = type != WebFrameLoadType::kStandard;
- if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
+ bool is_history_api_navigation =
+ (same_document_navigation_source == kSameDocumentNavigationHistoryApi);
+ if (is_history_api_navigation) {
+ // See spec:
+ // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
http_method_ = http_names::kGET;
http_body_ = nullptr;
}
@@ -507,13 +698,13 @@ void DocumentLoader::UpdateForSameDocumentNavigation(
same_document_navigation_source);
}
- SetHistoryItemStateForCommit(
- history_item_.Get(), type,
- same_document_navigation_source == kSameDocumentNavigationHistoryApi
- ? HistoryNavigationType::kHistoryApi
- : HistoryNavigationType::kFragment);
+ SetHistoryItemStateForCommit(history_item_.Get(), type,
+ is_history_api_navigation
+ ? HistoryNavigationType::kHistoryApi
+ : HistoryNavigationType::kFragment,
+ CommitReason::kRegular);
history_item_->SetDocumentState(frame_->GetDocument()->GetDocumentState());
- if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
+ if (is_history_api_navigation) {
history_item_->SetStateObject(std::move(data));
history_item_->SetScrollRestorationType(scroll_restoration_type);
}
@@ -523,7 +714,8 @@ void DocumentLoader::UpdateForSameDocumentNavigation(
FrameScheduler::NavigationType::kSameDocument);
GetLocalFrameClient().DidFinishSameDocumentNavigation(
- history_item_.Get(), commit_type, is_content_initiated);
+ history_item_.Get(), commit_type, is_content_initiated,
+ is_history_api_navigation);
probe::DidNavigateWithinDocument(frame_);
if (!was_loading) {
GetLocalFrameClient().DidStopLoading();
@@ -538,7 +730,19 @@ const KURL& DocumentLoader::UrlForHistory() const {
void DocumentLoader::SetHistoryItemStateForCommit(
HistoryItem* old_item,
WebFrameLoadType load_type,
- HistoryNavigationType navigation_type) {
+ HistoryNavigationType navigation_type,
+ CommitReason commit_reason) {
+ if (old_item && (commit_reason == CommitReason::kJavascriptUrl ||
+ commit_reason == CommitReason::kXSLT)) {
+ // If this is a javascript: URL or XSLT commit and we already have a
+ // HistoryItem, we should reuse it, because even though the Document and
+ // DocumentLoader changed, all other state (URL, origin, history, etc.)
+ // should stay the same.
+ history_item_ = old_item;
+ return;
+ }
+ DCHECK_NE(commit_reason, CommitReason::kXSLT);
+
if (!history_item_ || !IsBackForwardLoadType(load_type))
history_item_ = MakeGarbageCollected<HistoryItem>();
@@ -647,7 +851,7 @@ void DocumentLoader::BodyLoadingFinished(
probe::ToCoreProbeSink(GetFrame()), main_resource_identifier_, this,
completion_time, total_encoded_data_length, total_decoded_body_length,
should_report_corb_blocking);
- if (response_.IsHTTP()) {
+ if (response_.IsHTTP() || is_error_page_for_failed_navigation_) {
// The response is being copied here to pass the Encoded and Decoded
// sizes.
// TODO(yoav): copy the sizes info directly.
@@ -758,7 +962,14 @@ void DocumentLoader::FinishedLoading(base::TimeTicks finish_time) {
}
}
-void DocumentLoader::HandleRedirect(const KURL& current_request_url) {
+void DocumentLoader::HandleRedirect(
+ WebNavigationParams::RedirectInfo& redirect) {
+ ResourceResponse redirect_response =
+ redirect.redirect_response.ToResourceResponse();
+ const KURL& url_before_redirect = redirect_response.CurrentRequestUrl();
+ url_ = redirect.new_url;
+ const KURL& url_after_redirect = url_;
+
// Browser process should have already checked that redirecting url is
// allowed to display content from the target origin.
// When the referrer page is in an unsigned Web Bundle file in local
@@ -767,12 +978,35 @@ void DocumentLoader::HandleRedirect(const KURL& current_request_url) {
// to the file's URL (file:///tmp/a.wbn?https://example.com/page.html). In
// this case, CanDisplay() returns false, and web_bundle_claimed_url must not
// be null.
- CHECK(SecurityOrigin::Create(current_request_url)->CanDisplay(url_) ||
+ CHECK(SecurityOrigin::Create(url_before_redirect)
+ ->CanDisplay(url_after_redirect) ||
!params_->web_bundle_claimed_url.IsNull());
+ // Update the HTTP method of this document to the method used by the redirect.
+ AtomicString new_http_method = redirect.new_http_method;
+ if (http_method_ != new_http_method) {
+ http_body_ = nullptr;
+ http_content_type_ = g_null_atom;
+ http_method_ = new_http_method;
+ }
+
+ if (redirect.new_referrer.IsEmpty()) {
+ referrer_ = Referrer(Referrer::NoReferrer(), redirect.new_referrer_policy);
+ } else {
+ referrer_ = Referrer(redirect.new_referrer, redirect.new_referrer_policy);
+ }
+
+ // TODO(dgozman): check whether clearing origin policy is intended behavior.
+ origin_policy_ = base::nullopt;
+ probe::WillSendNavigationRequest(
+ probe::ToCoreProbeSink(GetFrame()), main_resource_identifier_, this,
+ url_after_redirect, http_method_, http_body_.get());
+
+ navigation_timing_info_->AddRedirect(redirect_response, url_after_redirect);
+
DCHECK(!GetTiming().FetchStart().is_null());
- redirect_chain_.push_back(url_);
- GetTiming().AddRedirect(current_request_url, url_);
+ redirect_chain_.push_back(url_after_redirect);
+ GetTiming().AddRedirect(url_before_redirect, url_after_redirect);
}
bool DocumentLoader::ShouldReportTimingInfoToParent() {
@@ -914,6 +1148,7 @@ mojom::CommitResult DocumentLoader::CommitSameDocumentNavigation(
WebFrameLoadType frame_load_type,
HistoryItem* history_item,
ClientRedirectPolicy client_redirect_policy,
+ bool has_transient_user_activation,
LocalDOMWindow* origin_window,
bool has_event,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
@@ -924,17 +1159,25 @@ mojom::CommitResult DocumentLoader::CommitSameDocumentNavigation(
page->HistoryNavigationVirtualTimePauser().UnpauseVirtualTime();
if (!frame_->IsNavigationAllowed())
- return mojom::CommitResult::Aborted;
+ return mojom::blink::CommitResult::Aborted;
+
+ if (frame_->GetDocument()->IsFrameSet()) {
+ // Navigations in a frameset are always cross-document. Renderer-initiated
+ // navigations in a frameset will be deferred to the browser, and all
+ // renderer-initiated navigations are treated as cross-document. So this one
+ // must have been browser-initiated, where it was not aware that the
+ // document is a frameset. In that case we just restart the navigation,
+ // making it cross-document. This gives a consistent outcome for all
+ // navigations in a frameset.
+ return mojom::blink::CommitResult::RestartCrossDocument;
+ }
if (!IsBackForwardLoadType(frame_load_type)) {
// In the case of non-history navigations, check that this is a
- // same-document navigation. If not, the navigation should restart as a
- // cross-document navigation.
- if (!url.HasFragmentIdentifier() ||
- !EqualIgnoringFragmentIdentifier(frame_->GetDocument()->Url(), url) ||
- frame_->GetDocument()->IsFrameSet()) {
- return mojom::CommitResult::RestartCrossDocument;
- }
+ // same-document navigation. The browser should not send invalid
+ // same-document navigations.
+ CHECK(url.HasFragmentIdentifier());
+ CHECK(EqualIgnoringFragmentIdentifier(frame_->GetDocument()->Url(), url));
}
// If the requesting document is cross-origin, perform the navigation
@@ -948,11 +1191,13 @@ mojom::CommitResult DocumentLoader::CommitSameDocumentNavigation(
WTF::Bind(&DocumentLoader::CommitSameDocumentNavigationInternal,
WrapWeakPersistent(this), url, frame_load_type,
WrapPersistent(history_item), client_redirect_policy,
- !!origin_window, has_event, std::move(extra_data)));
+ has_transient_user_activation, !!origin_window, has_event,
+ std::move(extra_data)));
} else {
- CommitSameDocumentNavigationInternal(url, frame_load_type, history_item,
- client_redirect_policy, origin_window,
- has_event, std::move(extra_data));
+ CommitSameDocumentNavigationInternal(
+ url, frame_load_type, history_item, client_redirect_policy,
+ has_transient_user_activation, origin_window, has_event,
+ std::move(extra_data));
}
return mojom::CommitResult::Ok;
}
@@ -962,6 +1207,7 @@ void DocumentLoader::CommitSameDocumentNavigationInternal(
WebFrameLoadType frame_load_type,
HistoryItem* history_item,
ClientRedirectPolicy client_redirect,
+ bool has_transient_user_activation,
bool is_content_initiated,
bool has_event,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
@@ -1001,6 +1247,10 @@ void DocumentLoader::CommitSameDocumentNavigationInternal(
}
is_client_redirect_ =
client_redirect == ClientRedirectPolicy::kClientRedirect;
+
+ last_navigation_had_transient_user_activation_ =
+ has_transient_user_activation;
+
bool same_item_sequence_number =
history_item_ && history_item &&
history_item_->ItemSequenceNumber() == history_item->ItemSequenceNumber();
@@ -1187,31 +1437,8 @@ void DocumentLoader::StartLoadingInternal() {
main_resource_identifier_, this, url_,
http_method_, http_body_.get());
- for (size_t i = 0; i < params_->redirects.size(); ++i) {
- WebNavigationParams::RedirectInfo& redirect = params_->redirects[i];
- url_ = redirect.new_url;
- AtomicString new_http_method = redirect.new_http_method;
- if (http_method_ != new_http_method) {
- http_body_ = nullptr;
- http_content_type_ = g_null_atom;
- http_method_ = new_http_method;
- }
- if (redirect.new_referrer.IsEmpty()) {
- referrer_ =
- Referrer(Referrer::NoReferrer(), redirect.new_referrer_policy);
- } else {
- referrer_ = Referrer(redirect.new_referrer, redirect.new_referrer_policy);
- }
-
- // TODO(dgozman): check whether clearing origin policy is intended behavior.
- origin_policy_ = base::nullopt;
- probe::WillSendNavigationRequest(probe::ToCoreProbeSink(GetFrame()),
- main_resource_identifier_, this, url_,
- http_method_, http_body_.get());
- ResourceResponse redirect_response =
- redirect.redirect_response.ToResourceResponse();
- navigation_timing_info_->AddRedirect(redirect_response, url_);
- HandleRedirect(redirect_response.CurrentRequestUrl());
+ for (WebNavigationParams::RedirectInfo& redirect : params_->redirects) {
+ HandleRedirect(redirect);
}
if (!frame_->IsMainFrame()) {
@@ -1219,7 +1446,7 @@ void DocumentLoader::StartLoadingInternal() {
//
// TODO(crbug.com/1129326): Revisit this when we have a coherent story for
// top-level navigations.
- MixedContentChecker::CheckMixedPrivatePublic(frame_, response_);
+ RecordAddressSpaceFeature(FetchType::kNavigation, frame_, response_);
}
ApplyClientHintsConfig(params_->enabled_client_hints);
@@ -1229,13 +1456,6 @@ void DocumentLoader::StartLoadingInternal() {
PreloadHelper::kDoNotLoadResources, PreloadHelper::kLoadAll,
nullptr /* viewport_description */, nullptr /* alternate_resource_info */,
nullptr /* recursive_prefetch_token */);
- if (!frame_->IsMainFrame() && response_.HasMajorCertificateErrors()) {
- MixedContentChecker::HandleCertificateError(
- response_, mojom::blink::RequestContextType::HYPERLINK,
- MixedContentChecker::DecideCheckModeForPlugin(
- GetFrame()->GetSettings()),
- GetContentSecurityNotifier());
- }
GetFrameLoader().Progress().IncrementProgress(main_resource_identifier_,
response_);
probe::DidReceiveResourceResponse(probe::ToCoreProbeSink(GetFrame()),
@@ -1406,12 +1626,12 @@ void DocumentLoader::DidCommitNavigation() {
if (response_.CacheControlContainsNoCache()) {
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kMainResourceHasCacheControlNoCache,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
if (response_.CacheControlContainsNoStore()) {
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kMainResourceHasCacheControlNoStore,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
// When a new navigation commits in the frame, subresource loading should be
@@ -1435,16 +1655,22 @@ void DocumentLoader::DidCommitNavigation() {
// Report legacy TLS versions after Page::DidCommitLoad, because the latter
// clears the console.
if (response_.IsLegacyTLSVersion()) {
- GetFrameLoader().ReportLegacyTLSVersion(
- response_.CurrentRequestUrl(), false /* is_subresource */,
- frame_->IsAdSubframe() || frame_->IsAdRoot());
+ GetFrameLoader().ReportLegacyTLSVersion(response_.CurrentRequestUrl(),
+ false /* is_subresource */,
+ frame_->IsAdSubframe());
}
}
network::mojom::blink::WebSandboxFlags DocumentLoader::CalculateSandboxFlags() {
- auto sandbox_flags = GetFrameLoader().GetForcedSandboxFlags() |
- content_security_policy_->GetSandboxMask() |
- frame_policy_.sandbox_flags;
+ // The snapshot of the FramePolicy taken, when the navigation started. This
+ // contains the sandbox of the parent/opener and also the sandbox of the
+ // iframe element owning this new document.
+ auto sandbox_flags = frame_policy_.sandbox_flags;
+
+ // The new document's response can further restrict sandbox using the
+ // Content-Security-Policy: sandbox directive:
+ sandbox_flags |= content_security_policy_->GetSandboxMask();
+
if (archive_) {
// The URL of a Document loaded from a MHTML archive is controlled by
// the Content-Location header. This would allow UXSS, since
@@ -1458,8 +1684,11 @@ network::mojom::blink::WebSandboxFlags DocumentLoader::CalculateSandboxFlags() {
~(network::mojom::blink::WebSandboxFlags::kPopups |
network::mojom::blink::WebSandboxFlags::
kPropagatesToAuxiliaryBrowsingContexts));
- } else if (commit_reason_ == CommitReason::kXSLT) {
- // An XSLT document inherits sandbox flags from the document that create it.
+ } else if (commit_reason_ == CommitReason::kXSLT ||
+ commit_reason_ == CommitReason::kJavascriptUrl) {
+ // An XSLT document inherits sandbox flags from the document that create it,
+ // while javascript: URL document reuses the previous document's sandbox
+ // flags.
sandbox_flags |= frame_->DomWindow()->GetSandboxFlags();
}
return sandbox_flags;
@@ -1482,14 +1711,25 @@ scoped_refptr<SecurityOrigin> DocumentLoader::CalculateOrigin(
auto* owner_context = frame_->PagePopupOwner()->GetExecutionContext();
origin = owner_context->GetSecurityOrigin()->IsolatedCopy();
} else if (owner_document && owner_document->domWindow()) {
+ // Prefer taking `origin` from `owner_document` if one is available - this
+ // will correctly inherit/alias `SecurityOrigin::domain_` from the
+ // `owner_document` (note that the
+ // `SecurityOrigin::CreateWithReferenceOrigin` fallback below A) doesn't
+ // preserve `domain_` via `url::Origin` and B) doesn't alias the origin /
+ // `domain_` - changes in the "about:blank" document do not affect the
+ // initiator document).
origin = owner_document->domWindow()->GetMutableSecurityOrigin();
} else {
// Otherwise, create an origin that propagates precursor information
// as needed. For non-opaque origins, this creates a standard tuple
// origin, but for opaque origins, it creates an origin with the
// initiator origin as the precursor.
- origin = SecurityOrigin::CreateWithReferenceOrigin(url_,
- requestor_origin_.get());
+ scoped_refptr<const SecurityOrigin> precursor = requestor_origin_;
+ // For urn: resources served from WebBundles, use the Bundle's origin
+ // as the precursor.
+ if (url_.ProtocolIs("urn") && response_.WebBundleURL().IsValid())
+ precursor = SecurityOrigin::Create(response_.WebBundleURL());
+ origin = SecurityOrigin::CreateWithReferenceOrigin(url_, precursor.get());
}
if ((sandbox_flags & network::mojom::blink::WebSandboxFlags::kOrigin) !=
@@ -1551,7 +1791,8 @@ bool ShouldReuseDOMWindow(LocalDOMWindow* window,
}
WindowAgent* GetWindowAgentForOrigin(LocalFrame* frame,
- SecurityOrigin* origin) {
+ SecurityOrigin* origin,
+ bool is_origin_keyed) {
// TODO(keishi): Also check if AllowUniversalAccessFromFileURLs might
// dynamically change.
bool has_potential_universal_access_privilege =
@@ -1559,13 +1800,38 @@ WindowAgent* GetWindowAgentForOrigin(LocalFrame* frame,
frame->GetSettings()->GetAllowUniversalAccessFromFileURLs();
return frame->window_agent_factory().GetAgentForOrigin(
has_potential_universal_access_privilege,
- V8PerIsolateData::MainThreadIsolate(), origin);
+ V8PerIsolateData::MainThreadIsolate(), origin, is_origin_keyed);
+}
+
+// Inheriting cases use their agent's "is origin-keyed" value, which is set
+// by whatever they're inheriting from.
+//
+// javascript: URLs use the calling page as their Url() value, so we need to
+// include them explicitly.
+bool ShouldInheritExplicitOriginKeying(const KURL& url, CommitReason reason) {
+ return Document::ShouldInheritSecurityOriginFromOwner(url) ||
+ reason == CommitReason::kJavascriptUrl;
}
void DocumentLoader::InitializeWindow(Document* owner_document) {
+ // Provisional frames shouldn't be doing anything other than act as a
+ // placeholder. Enforce a strict sandbox and ensure a unique opaque origin.
+ // TODO(dcheng): Actually enforce strict sandbox flags for provisional frame.
+ // For some reason, doing so breaks some random devtools tests.
auto sandbox_flags = CalculateSandboxFlags();
- auto security_origin = CalculateOrigin(owner_document, sandbox_flags);
-
+ auto security_origin = frame_->IsProvisional()
+ ? SecurityOrigin::CreateUniqueOpaque()
+ : CalculateOrigin(owner_document, sandbox_flags);
+
+ bool origin_agent_cluster = origin_agent_cluster_;
+ if (ShouldInheritExplicitOriginKeying(Url(), commit_reason_) &&
+ owner_document && owner_document->domWindow()) {
+ // Since we're inheriting the owner document's origin, we should also use
+ // its OriginAgentCluster (OAC) in determining which WindowAgent to use,
+ // overriding the OAC value sent in the commit params.
+ origin_agent_cluster =
+ owner_document->domWindow()->GetAgent()->IsExplicitlyOriginKeyed();
+ }
// In some rare cases, we'll re-use a LocalDOMWindow for a new Document. For
// example, when a script calls window.open("..."), the browser gives
// JavaScript a window synchronously but kicks off the load in the window
@@ -1575,7 +1841,8 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
// LocalDOMWindow to the Document that results from the network load. See also
// Document::IsSecureTransitionTo.
if (!ShouldReuseDOMWindow(frame_->DomWindow(), security_origin.get())) {
- auto* agent = GetWindowAgentForOrigin(frame_.Get(), security_origin.get());
+ auto* agent = GetWindowAgentForOrigin(frame_.Get(), security_origin.get(),
+ origin_agent_cluster);
frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_, agent));
if (origin_policy_.has_value()) {
@@ -1588,21 +1855,13 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
frame_->DomWindow()->SetOriginPolicyIds(ids);
}
- // Inheriting cases use their agent's origin-isolated value, which is set by
- // whatever they're inheriting from.
- //
- // javascript: URLs use the calling page as their Url() value, so we need to
- // exclude them explicitly.
- //
// TODO(https://crbug.com/1111897): This call is likely to happen happen
// multiple times per agent, since navigations can happen multiple times per
// agent. This is subpar. Currently a DCHECK guards against it happening
// multiple times *with different values*, but ideally we would use a better
// architecture.
- if (!Document::ShouldInheritSecurityOriginFromOwner(Url()) &&
- commit_reason_ != CommitReason::kJavascriptUrl) {
- agent->SetIsOriginIsolated(origin_isolated_);
- }
+ if (!ShouldInheritExplicitOriginKeying(Url(), commit_reason_))
+ agent->SetIsExplicitlyOriginKeyed(origin_agent_cluster_);
} else {
if (frame_->GetSettings()->GetShouldReuseGlobalForUnownedMainFrame() &&
frame_->IsMainFrame()) {
@@ -1610,8 +1869,8 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
// window to be reused, we should not inherit the initial empty document's
// Agent, which was a universal access Agent.
// This happens only in android webview.
- frame_->DomWindow()->ResetWindowAgent(
- GetWindowAgentForOrigin(frame_.Get(), security_origin.get()));
+ frame_->DomWindow()->ResetWindowAgent(GetWindowAgentForOrigin(
+ frame_.Get(), security_origin.get(), origin_agent_cluster));
}
frame_->DomWindow()->ClearForReuse();
}
@@ -1623,7 +1882,7 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
SecurityContext& security_context = frame_->DomWindow()->GetSecurityContext();
security_context.SetContentSecurityPolicy(content_security_policy_.Get());
- security_context.ApplySandboxFlags(sandbox_flags);
+ security_context.SetSandboxFlags(sandbox_flags);
// Conceptually, SecurityOrigin doesn't have to be initialized after sandbox
// flags are applied, but there's a UseCounter in SetSecurityOrigin() that
// wants to inspect sandbox flags.
@@ -1639,21 +1898,20 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
for (auto to_upgrade : parent_context->InsecureNavigationsToUpgrade())
security_context.AddInsecureNavigationUpgrade(to_upgrade);
}
- frame_->DomWindow()->SetAddressSpace(ip_address_space_);
if (base::FeatureList::IsEnabled(blink::features::kPolicyContainer)) {
- // SVG image documents go throught this but don't have a PolicyContainer, so
- // ignore them.
- if (frame_->GetPolicyContainer()) {
- frame_->DomWindow()->SetReferrerPolicy(
- frame_->GetPolicyContainer()->GetReferrerPolicy(), false);
- }
+ frame_->DomWindow()->SetReferrerPolicy(
+ frame_->GetPolicyContainer()->GetReferrerPolicy());
+ frame_->DomWindow()->SetAddressSpace(
+ frame_->GetPolicyContainer()->GetIPAddressSpace());
}
+
String referrer_policy_header =
response_.HttpHeaderField(http_names::kReferrerPolicy);
if (!referrer_policy_header.IsNull()) {
CountUse(WebFeature::kReferrerPolicyHeader);
- frame_->DomWindow()->ParseAndSetReferrerPolicy(referrer_policy_header);
+ frame_->DomWindow()->ParseAndSetReferrerPolicy(referrer_policy_header,
+ kPolicySourceHttpHeader);
if (base::FeatureList::IsEnabled(blink::features::kPolicyContainer)) {
if (frame_->GetPolicyContainer()) {
frame_->GetPolicyContainer()->UpdateReferrerPolicy(
@@ -1674,49 +1932,75 @@ void DocumentLoader::CommitNavigation() {
// inherit an aliased security context.
Document* owner_document = nullptr;
- // TODO(dcheng): This differs from the behavior of both IE and Firefox: the
- // origin is inherited from the document that loaded the URL.
+ // Calculate `owner_document` from which the committing navigation should
+ // inherit the cookie URL and inherit/alias the SecurityOrigin.
if (Document::ShouldInheritSecurityOriginFromOwner(Url())) {
+ // Base `owner_frame` on parent-or-opener heuristic.
Frame* owner_frame = frame_->Tree().Parent();
- if (!owner_frame)
+ if (!owner_frame && !url_.IsAboutSrcdocURL())
owner_frame = frame_->Loader().Opener();
- if (auto* owner_local_frame = DynamicTo<LocalFrame>(owner_frame))
- owner_document = owner_local_frame->GetDocument();
- }
-
- // Re-validate Document Policy feature before installing the new document.
- if (!RuntimeEnabledFeatures::DocumentPolicyEnabled(
- owner_document ? owner_document->GetExecutionContext() : nullptr)) {
- document_policy_ = DocumentPolicy::ParsedDocumentPolicy{};
- }
- if (document_policy_.feature_state.contains(
- mojom::blink::DocumentPolicyFeature::kForceLoadAtTop)) {
- navigation_scroll_allowed_ = !(
- document_policy_
- .feature_state[mojom::blink::DocumentPolicyFeature::kForceLoadAtTop]
- .BoolValue());
+ // `owner_document` has to come from a local frame and
+ // 1) for "about:srcdoc" has to be the parent
+ // 2) for other cases ("about:blank" and initial empty document) has to be
+ // the initiator/requestor of the navigation - see:
+ // https://html.spec.whatwg.org/multipage/browsers.html#determining-the-origin
+ // The parent-or-owner heuristic above might not find the actual initiator
+ // of the navigation in the 2nd case (e.g. see the
+ // SameSiteSiblingToAboutBlank_CrossSiteTop testcase). To limit (but not
+ // eliminate :-/) incorrect cases we require that `owner_document`'s origin
+ // is same origin with `requestor_origin`.
+ //
+ // TODO(https://crbug.com/1176291): Improve heuristics for finding the
+ // correct initiator, to properly inherit/alias `document.domain` in more
+ // cases.
+ auto* owner_local_frame = DynamicTo<LocalFrame>(owner_frame);
+ if (owner_local_frame &&
+ (url_.IsAboutSrcdocURL() || !requestor_origin_ ||
+ owner_local_frame->GetSecurityContext()
+ ->GetSecurityOrigin()
+ ->IsSameOriginWith(requestor_origin_.get()))) {
+ owner_document = owner_local_frame->GetDocument();
+ }
}
LocalDOMWindow* previous_window = frame_->DomWindow();
InitializeWindow(owner_document);
SecurityContextInit security_init(frame_->DomWindow());
- // FeaturePolicy and DocumentPolicy require SecurityOrigin and origin trials
- // to be initialized.
- // TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy.
- security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_,
- frame_policy_);
- // |document_policy_| is parsed in document loader because it is
- // compared with |frame_policy.required_document_policy| to decide
- // whether to block the document load or not.
- // |report_only_document_policy| does not block the page load. Its
- // initialization is delayed to
- // SecurityContextInit::InitializeDocumentPolicy(), similar to
- // |report_only_feature_policy|.
- security_init.ApplyDocumentPolicy(
- document_policy_,
- response_.HttpHeaderField(http_names::kDocumentPolicyReportOnly));
+
+ // The document constructed by XSLTProcessor and ScriptController should
+ // inherit Feature Policy and Document Policy from the previous Document.
+ // Note: In XSLT commit and JavaScript commit, |response_| no longer holds
+ // header fields. Going through regular initialization will cause empty policy
+ // even if there is header on xml document.
+ if (commit_reason_ == CommitReason::kXSLT ||
+ commit_reason_ == CommitReason::kJavascriptUrl) {
+ DCHECK(response_.HttpHeaderField(http_names::kFeaturePolicy).IsEmpty());
+ DCHECK(response_.HttpHeaderField(http_names::kPermissionsPolicy).IsEmpty());
+ DCHECK(response_.HttpHeaderField(http_names::kDocumentPolicy).IsEmpty());
+ security_init.InitFeaturePolicyFrom(previous_window->GetSecurityContext());
+ security_init.InitDocumentPolicyFrom(previous_window->GetSecurityContext());
+ } else {
+ // FeaturePolicy and DocumentPolicy require SecurityOrigin and origin trials
+ // to be initialized.
+ // TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy.
+ security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_,
+ frame_policy_);
+ // |document_policy_| is parsed in document loader because it is
+ // compared with |frame_policy.required_document_policy| to decide
+ // whether to block the document load or not.
+ // |report_only_document_policy| does not block the page load. Its
+ // initialization is delayed to
+ // SecurityContextInit::InitializeDocumentPolicy(), similar to
+ // |report_only_feature_policy|.
+ security_init.ApplyDocumentPolicy(
+ document_policy_,
+ response_.HttpHeaderField(http_names::kDocumentPolicyReportOnly));
+ }
+
+ navigation_scroll_allowed_ = !frame_->DomWindow()->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kForceLoadAtTop);
WillCommitNavigation();
@@ -1725,10 +2009,10 @@ void DocumentLoader::CommitNavigation() {
.WithWindow(frame_->DomWindow(), owner_document)
.ForInitialEmptyDocument(commit_reason_ ==
CommitReason::kInitialization)
+ .ForPrerendering(is_prerendering_)
.WithURL(Url())
.WithTypeFrom(MimeType())
.WithSrcdocDocument(loading_srcdoc_)
- .WithNewRegistrationContext()
.WithWebBundleClaimedUrl(web_bundle_claimed_url_)
.WithUkmSourceId(ukm_source_id_));
@@ -1818,23 +2102,31 @@ void DocumentLoader::CommitNavigation() {
document->SetDeferredCompositorCommitIsAllowed(false);
}
- if (response_.IsHTTP() && navigation_timing_info_) {
+ if ((response_.IsHTTP() || is_error_page_for_failed_navigation_) &&
+ navigation_timing_info_) {
// The response is being copied here to pass the ServerTiming info.
// TODO(yoav): copy the ServerTiming info directly.
navigation_timing_info_->SetFinalResponse(response_);
+ // Make sure we're properly reporting error documents.
+ if (is_error_page_for_failed_navigation_) {
+ navigation_timing_info_->SetInitialURL(
+ pre_redirect_url_for_failed_navigations_);
+ }
}
{
// Notify the browser process about the commit.
FrameNavigationDisabler navigation_disabler(*frame_);
if (commit_reason_ == CommitReason::kInitialization) {
- GetLocalFrameClient().DidCreateInitialEmptyDocument();
+ // There's no observers yet so nothing to notify.
} else if (IsJavaScriptURLOrXSLTCommit()) {
GetLocalFrameClient().DidCommitDocumentReplacementNavigation(this);
} else {
GetLocalFrameClient().DispatchDidCommitLoad(
history_item_.Get(), LoadTypeToCommitType(load_type_),
- previous_window != frame_->DomWindow());
+ previous_window != frame_->DomWindow(),
+ frame_->DomWindow()->GetSandboxFlags(),
+ security_init.FeaturePolicyHeader(), document_policy_.feature_state);
}
// TODO(dgozman): make DidCreateScriptContext notification call currently
// triggered by installing new document happen here, after commit.
@@ -1848,13 +2140,6 @@ void DocumentLoader::CommitNavigation() {
page->HistoryNavigationVirtualTimePauser().UnpauseVirtualTime();
}
- // FeaturePolicy is reset in the browser process on commit, so this needs to
- // be initialized and replicated to the browser process after commit messages
- // are sent.
- GetLocalFrameClient().DidSetFramePolicyHeaders(
- frame_->DomWindow()->GetSandboxFlags(),
- security_init.FeaturePolicyHeader(), document_policy_.feature_state);
-
// Load the document if needed.
StartLoadingResponse();
}
@@ -1890,7 +2175,7 @@ void DocumentLoader::CreateParserPostCommit() {
window->GetOriginTrialContext()->AddForceEnabledTrials(
force_enabled_origin_trials_);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enable Auto Picture-in-Picture feature for the built-in Chrome OS Video
// Player app.
const url::Origin origin = window->GetSecurityOrigin()->ToUrlOrigin();
@@ -1994,8 +2279,10 @@ void DocumentLoader::RecordUseCountersForCommit() {
CountUse(
WebFeature::kCertificateTransparencyNonCompliantResourceInSubframe);
}
- if (RuntimeEnabledFeatures::ForceLoadAtTopEnabled(frame_->DomWindow()))
+ if (frame_->DomWindow()->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kForceLoadAtTop)) {
CountUse(WebFeature::kForceLoadAtTop);
+ }
if (response_.IsSignedExchangeInnerResponse()) {
CountUse(WebFeature::kSignedExchangeInnerResponse);
@@ -2017,16 +2304,6 @@ void DocumentLoader::RecordUseCountersForCommit() {
}
void DocumentLoader::RecordConsoleMessagesForCommit() {
- // Log if the document was blocked by CSP checks now that the new Document has
- // been created and console messages will be properly displayed.
- if (was_blocked_by_csp_) {
- ConsoleError("Refused to display '" +
- response_.CurrentRequestUrl().ElidedString() +
- "' because it has not opted into the following policy "
- "required by its embedder: '" +
- GetFrameLoader().RequiredCSP() + "'.");
- }
-
if (was_blocked_by_document_policy_) {
// TODO(chenleihu): Add which document policy violated in error string,
// instead of just displaying serialized required document policy.
@@ -2052,7 +2329,6 @@ void DocumentLoader::ReportPreviewsIntervention() const {
return;
// Verify that certain types are not on main frame requests.
- DCHECK_NE(PreviewsTypes::kClientLoFiAutoReload, previews_state_);
DCHECK_NE(PreviewsTypes::kSubresourceRedirectOn, previews_state_);
static_assert(PreviewsTypes::kPreviewsStateLast ==
diff --git a/chromium/third_party/blink/renderer/core/loader/document_loader.h b/chromium/third_party/blink/renderer/core/loader/document_loader.h
index b20febe36b5..c4f628f194a 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/document_loader.h
@@ -63,7 +63,6 @@
#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
#include "third_party/blink/renderer/core/loader/navigation_policy.h"
#include "third_party/blink/renderer/core/loader/preload_helper.h"
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
@@ -115,6 +114,12 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
std::unique_ptr<WebNavigationParams> navigation_params);
~DocumentLoader() override;
+ // Returns WebNavigationParams that can be used to clone DocumentLoader. Used
+ // for javascript: URL and XSLT commits, where we want to create a new
+ // Document but keep most of the property of the current DocumentLoader.
+ std::unique_ptr<WebNavigationParams>
+ CreateWebNavigationParamsToCloneDocument();
+
static bool WillLoadUrlAsEmpty(const KURL&);
LocalFrame* GetFrame() const { return frame_; }
@@ -136,15 +141,12 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
SubresourceFilter* GetSubresourceFilter() const {
return subresource_filter_.Get();
}
- void SetPreviewsResourceLoadingHints(
- PreviewsResourceLoadingHints* resource_loading_hints) {
- resource_loading_hints_ = resource_loading_hints;
- }
- PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints() const {
- return resource_loading_hints_;
- }
+ // TODO(dcheng, japhet): Some day, Document::Url() will always match
+ // DocumentLoader::Url(), and one of them will be removed. Today is not that
+ // day though.
const KURL& Url() const;
+
const KURL& UrlForHistory() const;
const AtomicString& HttpMethod() const;
const Referrer& GetReferrer() const;
@@ -155,12 +157,21 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
void DidChangePerformanceTiming();
void DidObserveInputDelay(base::TimeDelta input_delay);
void DidObserveLoadingBehavior(LoadingBehaviorFlag);
+
+ // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
+ void RunURLAndHistoryUpdateSteps(
+ const KURL&,
+ scoped_refptr<SerializedScriptValue>,
+ mojom::blink::ScrollRestorationType =
+ mojom::blink::ScrollRestorationType::kAuto,
+ WebFrameLoadType = WebFrameLoadType::kReplaceCurrentItem);
void UpdateForSameDocumentNavigation(const KURL&,
SameDocumentNavigationSource,
scoped_refptr<SerializedScriptValue>,
mojom::blink::ScrollRestorationType,
WebFrameLoadType,
bool is_content_initiated);
+
const ResourceResponse& GetResponse() const { return response_; }
bool IsClientRedirect() const { return is_client_redirect_; }
bool ReplacesCurrentHistoryItem() const {
@@ -201,6 +212,7 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
WebFrameLoadType,
HistoryItem*,
ClientRedirectPolicy,
+ bool has_transient_user_activation,
LocalDOMWindow* origin_window,
bool has_event,
std::unique_ptr<WebDocumentLoader::ExtraData>);
@@ -225,6 +237,8 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
};
InitialScrollState& GetInitialScrollState() { return initial_scroll_state_; }
+ enum State { kNotStarted, kProvisional, kCommitted, kSentDidFinishLoad };
+
void DispatchLinkHeaderPreloads(const ViewportDescription*,
PreloadHelper::MediaPreloadPolicy);
@@ -278,7 +292,9 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
void SetCommitReason(CommitReason reason) { commit_reason_ = reason; }
- bool HadTransientActivation() const { return had_transient_activation_; }
+ bool LastNavigationHadTransientUserActivation() const {
+ return last_navigation_had_transient_user_activation_;
+ }
// Whether the navigation originated from the browser process. Note: history
// navigation is always considered to be browser initiated, even if the
@@ -287,11 +303,6 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
bool IsSameOriginNavigation() const { return is_same_origin_navigation_; }
- // TODO(dcheng, japhet): Some day, Document::Url() will always match
- // DocumentLoader::Url(), and one of them will be removed. Today is not that
- // day though.
- void UpdateUrlForDocumentOpen(const KURL& url) { url_ = url; }
-
enum class HistoryNavigationType {
kDifferentDocument,
kFragment,
@@ -300,7 +311,8 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
void SetHistoryItemStateForCommit(HistoryItem* old_item,
WebFrameLoadType,
- HistoryNavigationType);
+ HistoryNavigationType,
+ CommitReason commit_reason);
mojo::PendingReceiver<mojom::blink::WorkerTimingContainer>
TakePendingWorkerTimingReceiver(int request_id);
@@ -320,6 +332,9 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
// to ensure the token can only be used to invoke a single text fragment.
bool ConsumeTextFragmentToken();
+ // Returns whether the load request was initiated for prerendering.
+ bool IsPrerendering() const { return is_prerendering_; }
+
protected:
Vector<KURL> redirect_chain_;
@@ -368,6 +383,7 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
WebFrameLoadType,
HistoryItem*,
ClientRedirectPolicy,
+ bool has_transient_user_activation,
bool is_content_initiated,
bool has_event,
std::unique_ptr<WebDocumentLoader::ExtraData>);
@@ -390,7 +406,9 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
void FinishedLoading(base::TimeTicks finish_time);
void CancelLoadAfterCSPDenied(const ResourceResponse&);
- void HandleRedirect(const KURL& current_request_url);
+ // Process a redirect to update the redirect chain, current URL, referrer,
+ // etc.
+ void HandleRedirect(WebNavigationParams::RedirectInfo& redirect);
void HandleResponse();
void InitializeEmptyResponse();
@@ -449,9 +467,8 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
base::Optional<WebOriginPolicy> origin_policy_;
const scoped_refptr<const SecurityOrigin> requestor_origin_;
const KURL unreachable_url_;
+ const KURL pre_redirect_url_for_failed_navigations_;
std::unique_ptr<WebNavigationBodyLoader> body_loader_;
- const network::mojom::IPAddressSpace ip_address_space_ =
- network::mojom::IPAddressSpace::kUnknown;
const bool grant_load_local_resources_ = false;
const base::Optional<blink::mojom::FetchCacheMode> force_fetch_cache_mode_;
const FramePolicy frame_policy_;
@@ -467,9 +484,6 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
Member<SubresourceFilter> subresource_filter_;
- // Stores the resource loading hints for this document.
- Member<PreviewsResourceLoadingHints> resource_loading_hints_;
-
// A reference to actual request's url and referrer used to
// inititate this load.
KURL original_url_;
@@ -482,9 +496,9 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
bool is_client_redirect_;
bool replaces_current_history_item_;
bool data_received_;
+ const bool is_error_page_for_failed_navigation_;
const Member<ContentSecurityPolicy> content_security_policy_;
- const bool was_blocked_by_csp_;
mojo::Remote<mojom::blink::ContentSecurityNotifier>
content_security_notifier_;
@@ -507,7 +521,6 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
ClientHintsPreferences client_hints_preferences_;
InitialScrollState initial_scroll_state_;
- enum State { kNotStarted, kProvisional, kCommitted, kSentDidFinishLoad };
State state_;
// Used to block the parser.
@@ -522,14 +535,19 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
WebURLLoader::DeferType defers_loading_ =
WebURLLoader::DeferType::kNotDeferred;
+ // Whether the last navigation (cross-document or same-document) that
+ // committed in this DocumentLoader had transient activation.
+ bool last_navigation_had_transient_user_activation_ = false;
+
// Whether this load request comes with a sitcky user activation.
const bool had_sticky_activation_ = false;
- // Whether this load request had a user activation when created.
- const bool had_transient_activation_ = false;
// Whether this load request was initiated by the browser.
const bool is_browser_initiated_ = false;
+ // Whether this load request was initiated for prerendering.
+ const bool is_prerendering_ = false;
+
// Whether this load request was initiated by the same origin.
bool is_same_origin_navigation_ = false;
@@ -578,7 +596,7 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
// Whether the document can be scrolled on load
bool navigation_scroll_allowed_ = true;
- bool origin_isolated_ = false;
+ bool origin_agent_cluster_ = false;
// Whether this load request is cross browsing context group.
bool is_cross_browsing_context_group_navigation_ = false;
diff --git a/chromium/third_party/blink/renderer/core/loader/document_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/document_loader_test.cc
index 2ed5db73954..17ad6ed08bf 100644
--- a/chromium/third_party/blink/renderer/core/loader/document_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/document_loader_test.cc
@@ -10,8 +10,6 @@
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-shared.h"
-#include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
@@ -262,449 +260,6 @@ TEST_F(DocumentLoaderSimTest, FramePolicyIntegrityOnNavigationCommit) {
EXPECT_TRUE(child_window->IsFeatureEnabled(
blink::mojom::blink::FeaturePolicyFeature::kPayment));
}
-// When runtime feature DocumentPolicy is not enabled, specifying
-// Document-Policy, Require-Document-Policy and policy attribute
-// should have no effect, i.e.
-// document load should not be blocked even if the required policy and incoming
-// policy are incompatible and calling
-// |Document::IsFeatureEnabled(DocumentPolicyFeature...)| should always return
-// true.
-TEST_F(DocumentLoaderSimTest, DocumentPolicyNoEffectWhenFlagNotSet) {
- blink::ScopedDocumentPolicyForTest sdp(false);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(false);
-
- SimRequest::Params main_params;
- main_params.response_http_headers = {
- {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
-
- SimRequest::Params iframe_params;
- iframe_params.response_http_headers = {
- {"Document-Policy", "lossless-images-max-bpp=1.1"}};
-
- SimRequest main_resource("https://example.com", "text/html", main_params);
- SimRequest iframe_resource("https://example.com/foo.html", "text/html",
- iframe_params);
-
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe
- src="https://example.com/foo.html"
- policy="lossless-images-max-bpp=1.0">
- </iframe>
- )");
-
- iframe_resource.Finish();
- auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
- auto* child_window = child_frame->GetFrame()->DomWindow();
- auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
- child_frame->Client())
- ->ConsoleMessages();
-
- // Should not receive a console error message caused by document policy
- // violation blocking document load.
- EXPECT_TRUE(console_messages.IsEmpty());
-
- EXPECT_EQ(child_window->Url(), KURL("https://example.com/foo.html"));
-
- EXPECT_FALSE(child_window->document()->IsUseCounted(
- mojom::WebFeature::kDocumentPolicyCausedPageUnload));
-
- // lossless-images-max-bpp should be set to inf in main document, i.e. allow
- // all values.
- EXPECT_TRUE(Window().IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(2.0)));
- EXPECT_TRUE(Window().IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(1.0)));
-
- // lossless-images-max-bpp should be set to inf in child document, i.e. allow
- // all values.
- EXPECT_TRUE(child_window->IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(2.0)));
- EXPECT_TRUE(child_window->IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(1.0)));
-}
-
-// When runtime feature DocumentPolicyNegotiation is not enabled, specifying
-// Require-Document-Policy HTTP header and policy attribute on iframe should
-// have no effect, i.e. document load should not be blocked even if the required
-// policy and incoming policy are incompatible. Document-Policy header should
-// function as normal.
-TEST_F(DocumentLoaderSimTest, DocumentPolicyNegotiationNoEffectWhenFlagNotSet) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(false);
-
- SimRequest::Params main_params;
- main_params.response_http_headers = {
- {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
-
- SimRequest::Params iframe_params;
- iframe_params.response_http_headers = {
- {"Document-Policy", "lossless-images-max-bpp=1.1"}};
-
- SimRequest main_resource("https://example.com", "text/html", main_params);
- SimRequest iframe_resource("https://example.com/foo.html", "text/html",
- iframe_params);
-
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe
- src="https://example.com/foo.html"
- policy="lossless-images-max-bpp=1.0">
- </iframe>
- )");
-
- iframe_resource.Finish();
- auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
- auto* child_window = child_frame->GetFrame()->DomWindow();
- auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
- child_frame->Client())
- ->ConsoleMessages();
-
- // Should not receive a console error message caused by document policy
- // violation blocking document load.
- EXPECT_TRUE(console_messages.IsEmpty());
-
- EXPECT_EQ(child_window->Url(), KURL("https://example.com/foo.html"));
-
- EXPECT_FALSE(child_window->document()->IsUseCounted(
- mojom::WebFeature::kDocumentPolicyCausedPageUnload));
-
- // lossless-images-max-bpp should be set to inf in main document, i.e. allow
- // all values.
- EXPECT_TRUE(Window().IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(2.0)));
- EXPECT_TRUE(Window().IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(1.0)));
-
- // lossless-images-max-bpp should be set to 1.1 in child document.
- EXPECT_FALSE(child_window->IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(2.0)));
- EXPECT_TRUE(child_window->IsFeatureEnabled(
- mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
- PolicyValue::CreateDecDouble(1.0)));
-}
-
-TEST_F(DocumentLoaderSimTest, ReportDocumentPolicyHeaderParsingError) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- SimRequest::Params params;
- params.response_http_headers = {{"Document-Policy", "bad-feature-name"}};
- SimRequest main_resource("https://example.com", "text/html", params);
- LoadURL("https://example.com");
- main_resource.Finish();
-
- EXPECT_EQ(ConsoleMessages().size(), 1u);
- EXPECT_TRUE(
- ConsoleMessages().front().StartsWith("Document-Policy HTTP header:"));
-}
-
-TEST_F(DocumentLoaderSimTest, ReportRequireDocumentPolicyHeaderParsingError) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- SimRequest::Params params;
- params.response_http_headers = {
- {"Require-Document-Policy", "bad-feature-name"}};
- SimRequest main_resource("https://example.com", "text/html", params);
- LoadURL("https://example.com");
- main_resource.Finish();
-
- EXPECT_EQ(ConsoleMessages().size(), 1u);
- EXPECT_TRUE(ConsoleMessages().front().StartsWith(
- "Require-Document-Policy HTTP header:"));
-}
-
-TEST_F(DocumentLoaderSimTest, ReportErrorWhenDocumentPolicyIncompatible) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
- SimRequest::Params params;
- params.response_http_headers = {
- {"Document-Policy", "lossless-images-max-bpp=1.1"}};
-
- SimRequest main_resource("https://example.com", "text/html");
- SimRequest iframe_resource("https://example.com/foo.html", "text/html",
- params);
-
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe
- src="https://example.com/foo.html"
- policy="lossless-images-max-bpp=1.0">
- </iframe>
- )");
-
- // When blocked by document policy, the document should be filled in with an
- // empty response, with Finish called on |navigation_body_loader| already.
- // If Finish was not called on the loader, because the document was not
- // blocked, this test will fail by crashing here.
- iframe_resource.Finish(true /* body_loader_finished */);
-
- auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
- auto* child_document = child_frame->GetFrame()->GetDocument();
-
- // Should console log a error message.
- auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
- child_frame->Client())
- ->ConsoleMessages();
-
- ASSERT_EQ(console_messages.size(), 1u);
- EXPECT_TRUE(console_messages.front().Contains("document policy"));
-
- // Should replace the document's origin with an opaque origin.
- EXPECT_EQ(child_document->Url(), SecurityOrigin::UrlWithUniqueOpaqueOrigin());
-
- EXPECT_TRUE(child_document->IsUseCounted(
- mojom::WebFeature::kDocumentPolicyCausedPageUnload));
-}
-
-// HTTP header Require-Document-Policy should only take effect on subtree of
-// current document, but not on current document.
-TEST_F(DocumentLoaderSimTest,
- RequireDocumentPolicyHeaderShouldNotAffectCurrentDocument) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
- SimRequest::Params params;
- params.response_http_headers = {
- {"Require-Document-Policy", "lossless-images-max-bpp=1.0"},
- {"Document-Policy", "lossless-images-max-bpp=1.1"}};
-
- SimRequest main_resource("https://example.com", "text/html", params);
- LoadURL("https://example.com");
- // If document is blocked by document policy because of incompatible document
- // policy, this test will fail by crashing here.
- main_resource.Finish();
-}
-
-TEST_F(DocumentLoaderSimTest, DocumentPolicyHeaderHistogramTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- HistogramTester histogram_tester;
-
- SimRequest::Params params;
- params.response_http_headers = {
- {"Document-Policy",
- "font-display-late-swap, lossless-images-max-bpp=1.1"}};
-
- SimRequest main_resource("https://example.com", "text/html", params);
- LoadURL("https://example.com");
- main_resource.Finish();
-
- histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Header",
- 2);
- histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Header",
- 1 /* kFontDisplay */, 1);
- histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Header",
- 2 /* kUnoptimizedLosslessImages */, 1);
-}
-
-TEST_F(DocumentLoaderSimTest, DocumentPolicyPolicyAttributeHistogramTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
- HistogramTester histogram_tester;
-
- SimRequest main_resource("https://example.com", "text/html");
- LoadURL("https://example.com");
-
- // Same feature should only be reported once in a document despite its
- // occurrence.
- main_resource.Complete(R"(
- <iframe policy="font-display-late-swap"></iframe>
- <iframe policy="font-display-late-swap=?0"></iframe>
- <iframe
- policy="font-display-late-swap, lossless-images-max-bpp=1.1">
- </iframe>
- )");
-
- histogram_tester.ExpectTotalCount(
- "Blink.UseCounter.DocumentPolicy.PolicyAttribute", 2);
- histogram_tester.ExpectBucketCount(
- "Blink.UseCounter.DocumentPolicy.PolicyAttribute", 1 /* kFontDisplay */,
- 1);
- histogram_tester.ExpectBucketCount(
- "Blink.UseCounter.DocumentPolicy.PolicyAttribute",
- 2 /* kUnoptimizedLosslessImages */, 1);
-}
-
-TEST_F(DocumentLoaderSimTest, DocumentPolicyEnforcedReportHistogramTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- HistogramTester histogram_tester;
-
- SimRequest main_resource("https://example.com", "text/html");
- LoadURL("https://example.com");
- main_resource.Finish();
-
- Window().ReportDocumentPolicyViolation(
- mojom::blink::DocumentPolicyFeature::kFontDisplay,
- mojom::blink::PolicyDisposition::kEnforce,
- "first font display violation");
-
- histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
- 1);
- histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Enforced",
- 1 /* kFontDisplay */, 1);
-
- // Multiple reports should be recorded multiple times.
- Window().ReportDocumentPolicyViolation(
- mojom::blink::DocumentPolicyFeature::kFontDisplay,
- mojom::blink::PolicyDisposition::kEnforce,
- "second font display violation");
-
- histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
- 2);
- histogram_tester.ExpectBucketCount("Blink.UseCounter.DocumentPolicy.Enforced",
- 1 /* kFontDisplay */, 2);
-}
-
-TEST_F(DocumentLoaderSimTest, DocumentPolicyReportOnlyReportHistogramTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- HistogramTester histogram_tester;
-
- SimRequest::Params params;
- params.response_http_headers = {
- {"Document-Policy-Report-Only", "font-display-late-swap"}};
- SimRequest main_resource("https://example.com", "text/html", params);
-
- LoadURL("https://example.com");
- main_resource.Finish();
-
- Window().ReportDocumentPolicyViolation(
- mojom::blink::DocumentPolicyFeature::kFontDisplay,
- mojom::blink::PolicyDisposition::kReport, "first font display violation");
-
- histogram_tester.ExpectTotalCount(
- "Blink.UseCounter.DocumentPolicy.ReportOnly", 1);
- histogram_tester.ExpectBucketCount(
- "Blink.UseCounter.DocumentPolicy.ReportOnly", 1 /* kFontDisplay */, 1);
-
- // Multiple reports should be recorded multiple times.
- Window().ReportDocumentPolicyViolation(
- mojom::blink::DocumentPolicyFeature::kFontDisplay,
- mojom::blink::PolicyDisposition::kReport,
- "second font display violation");
-
- histogram_tester.ExpectTotalCount(
- "Blink.UseCounter.DocumentPolicy.ReportOnly", 2);
- histogram_tester.ExpectBucketCount(
- "Blink.UseCounter.DocumentPolicy.ReportOnly", 1 /* kFontDisplay */, 2);
-}
-
-class DocumentPolicyHeaderUseCounterTest
- : public DocumentLoaderSimTest,
- public testing::WithParamInterface<std::tuple<bool, bool, bool>> {};
-
-TEST_P(DocumentPolicyHeaderUseCounterTest, ShouldObserveUseCounterUpdate) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
-
- bool has_document_policy_header, has_report_only_header, has_require_header;
- std::tie(has_document_policy_header, has_report_only_header,
- has_require_header) = GetParam();
-
- SimRequest::Params params;
- if (has_document_policy_header) {
- params.response_http_headers.insert("Document-Policy",
- "lossless-images-max-bpp=1.0");
- }
- if (has_report_only_header) {
- params.response_http_headers.insert("Document-Policy-Report-Only",
- "lossless-images-max-bpp=1.0");
- }
- if (has_require_header) {
- params.response_http_headers.insert("Require-Document-Policy",
- "lossless-images-max-bpp=1.0");
- }
- SimRequest main_resource("https://example.com", "text/html", params);
- LoadURL("https://example.com");
- main_resource.Complete();
-
- EXPECT_EQ(
- GetDocument().IsUseCounted(mojom::WebFeature::kDocumentPolicyHeader),
- has_document_policy_header);
- EXPECT_EQ(GetDocument().IsUseCounted(
- mojom::WebFeature::kDocumentPolicyReportOnlyHeader),
- has_report_only_header);
- EXPECT_EQ(GetDocument().IsUseCounted(
- mojom::WebFeature::kRequireDocumentPolicyHeader),
- has_require_header);
-}
-
-INSTANTIATE_TEST_SUITE_P(DocumentPolicyHeaderValues,
- DocumentPolicyHeaderUseCounterTest,
- ::testing::Combine(::testing::Bool(),
- ::testing::Bool(),
- ::testing::Bool()));
-
-TEST_F(DocumentLoaderSimTest,
- DocumentPolicyIframePolicyAttributeUseCounterTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
- SimRequest main_resource("https://example.com", "text/html");
- SimRequest::Params iframe_params;
- iframe_params.response_http_headers = {
- {"Document-Policy", "lossless-images-max-bpp=1.0"}};
- SimRequest iframe_resource("https://example.com/foo.html", "text/html",
- iframe_params);
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe
- src="https://example.com/foo.html"
- policy="lossless-images-max-bpp=1.0"
- ></iframe>
- )");
- iframe_resource.Finish();
-
- EXPECT_TRUE(GetDocument().IsUseCounted(
- mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
- EXPECT_FALSE(
- GetDocument().IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
-
- auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
- auto* child_document = child_frame->GetFrame()->GetDocument();
-
- EXPECT_FALSE(child_document->IsUseCounted(
- mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
- EXPECT_TRUE(
- child_document->IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
-}
-
-TEST_F(DocumentLoaderSimTest, RequiredDocumentPolicyUseCounterTest) {
- blink::ScopedDocumentPolicyForTest sdp(true);
- blink::ScopedDocumentPolicyNegotiationForTest sdpn(true);
-
- SimRequest::Params main_frame_params;
- main_frame_params.response_http_headers = {
- {"Require-Document-Policy", "lossless-images-max-bpp=1.0"}};
- SimRequest main_resource("https://example.com", "text/html",
- main_frame_params);
-
- SimRequest::Params iframe_params;
- iframe_params.response_http_headers = {
- {"Document-Policy", "lossless-images-max-bpp=1.0"}};
- SimRequest iframe_resource("https://example.com/foo.html", "text/html",
- iframe_params);
-
- LoadURL("https://example.com");
- main_resource.Complete(R"(
- <iframe src="https://example.com/foo.html"></iframe>
- )");
- iframe_resource.Finish();
-
- EXPECT_FALSE(GetDocument().IsUseCounted(
- mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
- EXPECT_FALSE(
- GetDocument().IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
-
- auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
- auto* child_document = child_frame->GetFrame()->GetDocument();
-
- EXPECT_FALSE(child_document->IsUseCounted(
- mojom::WebFeature::kDocumentPolicyIframePolicyAttribute));
- EXPECT_TRUE(
- child_document->IsUseCounted(mojom::WebFeature::kRequiredDocumentPolicy));
-}
TEST_F(DocumentLoaderTest, CommitsDeferredOnSameOriginNavigation) {
const KURL& requestor_url =
@@ -715,8 +270,8 @@ TEST_F(DocumentLoaderTest, CommitsDeferredOnSameOriginNavigation) {
const KURL& same_origin_url =
KURL(NullURL(), "https://www.example.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- same_origin_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), same_origin_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -734,8 +289,8 @@ TEST_F(DocumentLoaderTest, CommitsNotDeferredOnDifferentOriginNavigation) {
const KURL& other_origin_url =
KURL(NullURL(), "https://www.another.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- other_origin_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), other_origin_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -757,8 +312,8 @@ TEST_F(DocumentLoaderTest,
const KURL& other_origin_url =
KURL(NullURL(), "https://www.another.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- other_origin_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), other_origin_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -776,8 +331,8 @@ TEST_F(DocumentLoaderTest, CommitsNotDeferredOnDifferentPortNavigation) {
const KURL& different_port_url =
KURL(NullURL(), "https://www.example.com:8080/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- different_port_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), different_port_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -799,8 +354,8 @@ TEST_F(DocumentLoaderTest,
const KURL& different_port_url =
KURL(NullURL(), "https://www.example.com:8080/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- different_port_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), different_port_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -817,8 +372,8 @@ TEST_F(DocumentLoaderTest, CommitsNotDeferredOnDataURLNavigation) {
const KURL& data_url = KURL(NullURL(), "data:,Hello%2C%20World!");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- data_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), data_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -839,8 +394,8 @@ TEST_F(DocumentLoaderTest,
const KURL& data_url = KURL(NullURL(), "data:,Hello%2C%20World!");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- data_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), data_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -858,8 +413,8 @@ TEST_F(DocumentLoaderTest, SameOriginNavigation) {
const KURL& same_origin_url =
KURL(NullURL(), "https://www.example.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- same_origin_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), same_origin_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
@@ -878,8 +433,8 @@ TEST_F(DocumentLoaderTest, CrossOriginNavigation) {
const KURL& other_origin_url =
KURL(NullURL(), "https://www.another.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- other_origin_url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), other_origin_url);
params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
diff --git a/chromium/third_party/blink/renderer/core/loader/empty_clients.cc b/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
index ea24fab5fd7..0ff7964e214 100644
--- a/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/chromium/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -29,6 +29,7 @@
#include <memory>
#include "cc/layers/layer.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
@@ -97,7 +98,7 @@ void EmptyLocalFrameClient::BeginNavigation(
NavigationPolicy,
WebFrameLoadType,
bool,
- TriggeringEventInfo,
+ mojom::blink::TriggeringEventInfo,
HTMLFormElement*,
network::mojom::CSPDisposition,
mojo::PendingRemote<mojom::blink::BlobURLToken>,
@@ -105,9 +106,10 @@ void EmptyLocalFrameClient::BeginNavigation(
const String&,
const base::Optional<WebImpression>&,
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp,
- network::mojom::blink::CSPSourcePtr initiator_csp_self,
network::mojom::IPAddressSpace,
- mojo::PendingRemote<mojom::blink::NavigationInitiator>) {}
+ mojo::PendingRemote<mojom::blink::NavigationInitiator>,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>) {}
void EmptyLocalFrameClient::DispatchWillSendSubmitEvent(HTMLFormElement*) {}
@@ -184,6 +186,4 @@ EmptyLocalFrameClient::CreateServiceWorkerProvider() {
return nullptr;
}
-EmptyRemoteFrameClient::EmptyRemoteFrameClient() = default;
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/empty_clients.h b/chromium/third_party/blink/renderer/core/loader/empty_clients.h
index ab15a135d87..e0e8f47dd69 100644
--- a/chromium/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/chromium/third_party/blink/renderer/core/loader/empty_clients.h
@@ -86,6 +86,7 @@ namespace blink {
class CORE_EXPORT EmptyChromeClient : public ChromeClient {
public:
+ EmptyChromeClient() = default;
~EmptyChromeClient() override = default;
// ChromeClient implementation.
@@ -97,7 +98,7 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
void DidFocusPage() override {}
bool CanTakeFocus(mojom::blink::FocusType) override { return false; }
void TakeFocus(mojom::blink::FocusType) override {}
- void Show(const base::UnguessableToken& opener_frame_token,
+ void Show(const blink::LocalFrameToken& opener_frame_token,
NavigationPolicy navigation_policy,
const IntRect& initial_rect,
bool user_gesture) override {}
@@ -118,8 +119,10 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
const SkBitmap& drag_image,
const gfx::Point& drag_image_offset) override {}
bool AcceptsLoadDrops() const override { return true; }
- bool ShouldReportDetailedMessageForSource(LocalFrame&,
- const String&) override {
+ bool ShouldReportDetailedMessageForSourceAndSeverity(
+ LocalFrame&,
+ mojom::blink::ConsoleMessageLevel,
+ const String&) override {
return false;
}
void AddMessageToConsole(LocalFrame*,
@@ -139,7 +142,6 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
const AtomicString&,
const WebWindowFeatures&,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
bool& consumed_user_gesture) override {
return nullptr;
@@ -174,7 +176,9 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
float WindowToViewportScalar(LocalFrame*, const float s) const override {
return s;
}
- ScreenInfo GetScreenInfo(LocalFrame&) const override { return ScreenInfo(); }
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return empty_screen_info_;
+ }
void ContentsSizeChanged(LocalFrame*, const IntSize&) const override {}
void ShowMouseOverURL(const HitTestResult&) override {}
void SetToolTip(LocalFrame&, const String&, TextDirection) override {}
@@ -221,7 +225,10 @@ class CORE_EXPORT EmptyChromeClient : public ChromeClient {
void InstallSupplements(LocalFrame&) override {}
void MainFrameScrollOffsetChanged(LocalFrame& main_frame) const override {}
void BatterySavingsChanged(LocalFrame& main_frame,
- WebBatterySavingsFlags savings) override {}
+ BatterySavingsFlags savings) override {}
+
+ private:
+ const ScreenInfo empty_screen_info_ = {};
};
class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
@@ -243,9 +250,14 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
void DispatchDidHandleOnloadEvents() override {}
void DispatchDidReceiveTitle(const String&) override {}
- void DispatchDidCommitLoad(HistoryItem*,
- WebHistoryCommitType,
- bool) override {}
+ void DispatchDidCommitLoad(
+ HistoryItem* item,
+ WebHistoryCommitType commit_type,
+ bool should_reset_browser_interface_broker,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const blink::ParsedFeaturePolicy& feature_policy_header,
+ const blink::DocumentPolicyFeatureState& document_policy_header)
+ override {}
void DispatchDidFailLoad(const ResourceError&,
WebHistoryCommitType) override {}
void DispatchDidFinishDocumentLoad() override {}
@@ -260,7 +272,7 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
NavigationPolicy,
WebFrameLoadType,
bool,
- TriggeringEventInfo,
+ mojom::blink::TriggeringEventInfo,
HTMLFormElement*,
network::mojom::CSPDisposition,
mojo::PendingRemote<mojom::blink::BlobURLToken>,
@@ -269,9 +281,11 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
const base::Optional<WebImpression>&,
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
initiator_csp,
- network::mojom::blink::CSPSourcePtr initiator_self_source,
network::mojom::IPAddressSpace,
- mojo::PendingRemote<mojom::blink::NavigationInitiator>) override;
+ mojo::PendingRemote<mojom::blink::NavigationInitiator>,
+ const LocalFrameToken* initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>)
+ override;
void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
@@ -320,7 +334,6 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
HTMLMediaElement&) override;
- void DidCreateInitialEmptyDocument() override {}
void DidCommitDocumentReplacementNavigation(DocumentLoader*) override {}
void DispatchDidClearWindowObjectInMainWorld() override {}
void DocumentElementAvailable() override {}
@@ -394,37 +407,6 @@ class EmptySpellCheckPanelHostClient : public WebSpellCheckPanelHostClient {
DISALLOW_COPY_AND_ASSIGN(EmptySpellCheckPanelHostClient);
};
-class CORE_EXPORT EmptyRemoteFrameClient : public RemoteFrameClient {
- public:
- EmptyRemoteFrameClient();
-
- // RemoteFrameClient implementation.
- void Navigate(const ResourceRequest&,
- blink::WebLocalFrame* initiator_frame,
- bool should_replace_current_entry,
- bool is_opener_navigation,
- bool initiator_frame_has_download_sandbox_flag,
- bool initiator_frame_is_ad,
- mojo::PendingRemote<mojom::blink::BlobURLToken>,
- const base::Optional<WebImpression>&) override {}
- unsigned BackForwardLength() override { return 0; }
- void FrameRectsChanged(const IntRect& local_frame_rect,
- const IntRect& transformed_frame_rect) override {}
- void SynchronizeVisualProperties() override {}
- AssociatedInterfaceProvider* GetRemoteAssociatedInterfaces() override {
- return AssociatedInterfaceProvider::GetEmptyAssociatedInterfaceProvider();
- }
-
- // FrameClient implementation.
- bool InShadowTree() const override { return false; }
- void Detached(FrameDetachType) override {}
- base::UnguessableToken GetDevToolsFrameToken() const override {
- return base::UnguessableToken::Create();
- }
-
- DISALLOW_COPY_AND_ASSIGN(EmptyRemoteFrameClient);
-};
-
CORE_EXPORT void FillWithEmptyClients(Page::PageClients&);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/font_preload_manager.cc b/chromium/third_party/blink/renderer/core/loader/font_preload_manager.cc
index 82f44589e43..6e462577816 100644
--- a/chromium/third_party/blink/renderer/core/loader/font_preload_manager.cc
+++ b/chromium/third_party/blink/renderer/core/loader/font_preload_manager.cc
@@ -199,8 +199,9 @@ void FontPreloadManager::DisableTimeoutForTest() {
}
void FontPreloadManager::Trace(Visitor* visitor) const {
- visitor->Trace(finish_observers_);
visitor->Trace(document_);
+ visitor->Trace(finish_observers_);
+ visitor->Trace(render_delay_timer_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/font_preload_manager.h b/chromium/third_party/blink/renderer/core/loader/font_preload_manager.h
index 631f0f95e7e..0b53a890b82 100644
--- a/chromium/third_party/blink/renderer/core/loader/font_preload_manager.h
+++ b/chromium/third_party/blink/renderer/core/loader/font_preload_manager.h
@@ -75,7 +75,7 @@ class CORE_EXPORT FontPreloadManager final
unsigned imperative_font_loading_count_ = 0;
- TaskRunnerTimer<FontPreloadManager> render_delay_timer_;
+ HeapTaskRunnerTimer<FontPreloadManager> render_delay_timer_;
base::TimeDelta render_delay_timeout_;
State state_ = State::kInitial;
diff --git a/chromium/third_party/blink/renderer/core/loader/form_submission.cc b/chromium/third_party/blink/renderer/core/loader/form_submission.cc
index 8383a91207a..1b379c881be 100644
--- a/chromium/third_party/blink/renderer/core/loader/form_submission.cc
+++ b/chromium/third_party/blink/renderer/core/loader/form_submission.cc
@@ -152,12 +152,15 @@ inline FormSubmission::FormSubmission(
scoped_refptr<EncodedFormData> data,
const Event* event,
NavigationPolicy navigation_policy,
- TriggeringEventInfo triggering_event_info,
+ mojom::blink::TriggeringEventInfo triggering_event_info,
ClientNavigationReason reason,
std::unique_ptr<ResourceRequest> resource_request,
Frame* target_frame,
WebFrameLoadType load_type,
- LocalDOMWindow* origin_window)
+ LocalDOMWindow* origin_window,
+ const LocalFrameToken& initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle)
: method_(method),
action_(action),
target_(target),
@@ -170,7 +173,10 @@ inline FormSubmission::FormSubmission(
resource_request_(std::move(resource_request)),
target_frame_(target_frame),
load_type_(load_type),
- origin_window_(origin_window) {}
+ origin_window_(origin_window),
+ initiator_frame_token_(initiator_frame_token),
+ initiator_policy_container_keep_alive_handle_(
+ std::move(initiator_policy_container_keep_alive_handle)) {}
inline FormSubmission::FormSubmission(const String& result)
: method_(kDialogMethod), result_(result) {}
@@ -291,15 +297,16 @@ FormSubmission* FormSubmission::Create(HTMLFormElement* form,
resource_request->SetHasUserGesture(
LocalFrame::HasTransientUserActivation(form->GetDocument().GetFrame()));
- TriggeringEventInfo triggering_event_info;
+ mojom::blink::TriggeringEventInfo triggering_event_info;
if (event) {
- triggering_event_info = event->isTrusted()
- ? TriggeringEventInfo::kFromTrustedEvent
- : TriggeringEventInfo::kFromUntrustedEvent;
+ triggering_event_info =
+ event->isTrusted()
+ ? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
+ : mojom::blink::TriggeringEventInfo::kFromUntrustedEvent;
if (event->UnderlyingEvent())
event = event->UnderlyingEvent();
} else {
- triggering_event_info = TriggeringEventInfo::kNotFromEvent;
+ triggering_event_info = mojom::blink::TriggeringEventInfo::kNotFromEvent;
}
FrameLoadRequest frame_request(form->GetDocument().domWindow(),
@@ -327,7 +334,12 @@ FormSubmission* FormSubmission::Create(HTMLFormElement* form,
encoding_type, form, std::move(form_data), event,
frame_request.GetNavigationPolicy(), triggering_event_info, reason,
std::move(resource_request), target_frame, load_type,
- form->GetDocument().domWindow());
+ form->GetDocument().domWindow(),
+ form->GetDocument().GetFrame()->GetLocalFrameToken(),
+ form->GetDocument()
+ .GetFrame()
+ ->GetPolicyContainer()
+ ->IssueKeepAliveHandle());
}
void FormSubmission::Trace(Visitor* visitor) const {
@@ -349,6 +361,9 @@ void FormSubmission::Navigate() {
frame_request.SetClientRedirectReason(reason_);
frame_request.SetForm(form_);
frame_request.SetTriggeringEventInfo(triggering_event_info_);
+ frame_request.SetInitiatorFrameToken(initiator_frame_token_);
+ frame_request.SetInitiatorPolicyContainerKeepAliveHandle(
+ std::move(initiator_policy_container_keep_alive_handle_));
if (target_frame_ && !target_frame_->GetPage())
return;
diff --git a/chromium/third_party/blink/renderer/core/loader/form_submission.h b/chromium/third_party/blink/renderer/core/loader/form_submission.h
index 83a43042cab..b15e0680d87 100644
--- a/chromium/third_party/blink/renderer/core/loader/form_submission.h
+++ b/chromium/third_party/blink/renderer/core/loader/form_submission.h
@@ -32,7 +32,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FORM_SUBMISSION_H_
#include "base/macros.h"
-#include "third_party/blink/public/common/navigation/triggering_event_info.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink-forward.h"
#include "third_party/blink/public/web/web_frame_load_type.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/navigation_policy.h"
@@ -100,20 +101,24 @@ class FormSubmission final : public GarbageCollected<FormSubmission> {
const Event*,
HTMLFormControlElement* submit_button);
- FormSubmission(SubmitMethod,
- const KURL& action,
- const AtomicString& target,
- const AtomicString& content_type,
- HTMLFormElement*,
- scoped_refptr<EncodedFormData>,
- const Event*,
- NavigationPolicy navigation_policy,
- TriggeringEventInfo triggering_event_info,
- ClientNavigationReason reason,
- std::unique_ptr<ResourceRequest> resource_request,
- Frame* target_frame,
- WebFrameLoadType load_type,
- LocalDOMWindow* origin_window);
+ FormSubmission(
+ SubmitMethod,
+ const KURL& action,
+ const AtomicString& target,
+ const AtomicString& content_type,
+ HTMLFormElement*,
+ scoped_refptr<EncodedFormData>,
+ const Event*,
+ NavigationPolicy navigation_policy,
+ mojom::blink::TriggeringEventInfo triggering_event_info,
+ ClientNavigationReason reason,
+ std::unique_ptr<ResourceRequest> resource_request,
+ Frame* target_frame,
+ WebFrameLoadType load_type,
+ LocalDOMWindow* origin_window,
+ const LocalFrameToken& initiator_frame_token,
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle);
// FormSubmission for DialogMethod
explicit FormSubmission(const String& result);
@@ -141,13 +146,20 @@ class FormSubmission final : public GarbageCollected<FormSubmission> {
Member<HTMLFormElement> form_;
scoped_refptr<EncodedFormData> form_data_;
NavigationPolicy navigation_policy_;
- TriggeringEventInfo triggering_event_info_;
+ mojom::blink::TriggeringEventInfo triggering_event_info_;
String result_;
ClientNavigationReason reason_;
std::unique_ptr<ResourceRequest> resource_request_;
Member<Frame> target_frame_;
WebFrameLoadType load_type_;
Member<LocalDOMWindow> origin_window_;
+ LocalFrameToken initiator_frame_token_;
+
+ // Since form submissions are scheduled asynchronously, we need to keep a
+ // handle to the initiator PolicyContainerHost. This ensures that it remains
+ // available in the browser until we create the NavigationRequest.
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.cc b/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.cc
new file mode 100644
index 00000000000..7ffc2114742
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.cc
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+
+namespace blink {
+
+namespace {
+
+// Mapping from WebClientHintsType to WebFeature. The ordering should match the
+// ordering of enums in WebClientHintsType.
+static constexpr WebFeature kWebFeatureMapping[] = {
+ WebFeature::kClientHintsDeviceMemory,
+ WebFeature::kClientHintsDPR,
+ WebFeature::kClientHintsResourceWidth,
+ WebFeature::kClientHintsViewportWidth,
+ WebFeature::kClientHintsRtt,
+ WebFeature::kClientHintsDownlink,
+ WebFeature::kClientHintsEct,
+ WebFeature::kClientHintsLang,
+ WebFeature::kClientHintsUA,
+ WebFeature::kClientHintsUAArch,
+ WebFeature::kClientHintsUAPlatform,
+ WebFeature::kClientHintsUAModel,
+ WebFeature::kClientHintsUAMobile,
+ WebFeature::kClientHintsUAFullVersion,
+ WebFeature::kClientHintsUAPlatformVersion,
+};
+
+static_assert(static_cast<int>(network::mojom::WebClientHintsType::kMaxValue) +
+ 1 ==
+ base::size(kWebFeatureMapping),
+ "unhandled client hint type");
+
+} // namespace
+
+FrameClientHintsPreferencesContext::FrameClientHintsPreferencesContext(
+ LocalFrame* frame)
+ : frame_(frame) {}
+
+void FrameClientHintsPreferencesContext::CountClientHints(
+ network::mojom::WebClientHintsType type) {
+ UseCounter::Count(*frame_->GetDocument(),
+ kWebFeatureMapping[static_cast<int32_t>(type)]);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h b/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h
new file mode 100644
index 00000000000..4be4bc4a6af
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
+
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class LocalFrame;
+
+class FrameClientHintsPreferencesContext final
+ : public ClientHintsPreferences::Context {
+ STACK_ALLOCATED();
+
+ public:
+ explicit FrameClientHintsPreferencesContext(LocalFrame*);
+
+ void CountClientHints(network::mojom::WebClientHintsType) override;
+
+ private:
+ LocalFrame* frame_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index fd7c4f76901..aae9937df4d 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -75,6 +75,7 @@
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
+#include "third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_for_frame.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/loader/frame_resource_fetcher_properties.h"
@@ -178,31 +179,20 @@ mojom::FetchCacheMode DetermineFrameCacheMode(Frame* frame) {
return mojom::FetchCacheMode::kDefault;
}
-// Simple function to add quotes to make headers strings.
-const AtomicString SerializeHeaderString(std::string str) {
- std::string output;
- if (!str.empty()) {
- output = net::structured_headers::SerializeItem(
- net::structured_headers::Item(str))
- .value_or(std::string());
- }
-
- return AtomicString(output.c_str());
-}
-
} // namespace
struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> {
FrozenState(const KURL& url,
scoped_refptr<const SecurityOrigin> parent_security_origin,
- const ContentSecurityPolicy* content_security_policy,
+ ContentSecurityPolicy* content_security_policy,
net::SiteForCookies site_for_cookies,
scoped_refptr<const SecurityOrigin> top_frame_origin,
const ClientHintsPreferences& client_hints_preferences,
float device_pixel_ratio,
const String& user_agent,
const base::Optional<UserAgentMetadata>& user_agent_metadata,
- bool is_svg_image_chrome_client)
+ bool is_svg_image_chrome_client,
+ bool is_prerendering)
: url(url),
parent_security_origin(std::move(parent_security_origin)),
content_security_policy(content_security_policy),
@@ -212,11 +202,12 @@ struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> {
device_pixel_ratio(device_pixel_ratio),
user_agent(user_agent),
user_agent_metadata(user_agent_metadata),
- is_svg_image_chrome_client(is_svg_image_chrome_client) {}
+ is_svg_image_chrome_client(is_svg_image_chrome_client),
+ is_prerendering(is_prerendering) {}
const KURL url;
const scoped_refptr<const SecurityOrigin> parent_security_origin;
- const Member<const ContentSecurityPolicy> content_security_policy;
+ const Member<ContentSecurityPolicy> content_security_policy;
const net::SiteForCookies site_for_cookies;
const scoped_refptr<const SecurityOrigin> top_frame_origin;
const ClientHintsPreferences client_hints_preferences;
@@ -224,6 +215,7 @@ struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> {
const String user_agent;
const base::Optional<UserAgentMetadata> user_agent_metadata;
const bool is_svg_image_chrome_client;
+ const bool is_prerendering;
void Trace(Visitor* visitor) const {
visitor->Trace(content_security_policy);
@@ -244,7 +236,8 @@ ResourceFetcher* FrameFetchContext::CreateFetcherForCommittedDocument(
frame->GetTaskRunner(TaskType::kNetworking),
frame->GetTaskRunner(TaskType::kNetworkingUnfreezable),
MakeGarbageCollected<LoaderFactoryForFrame>(loader, *frame->DomWindow()),
- frame->DomWindow());
+ frame->DomWindow(),
+ MakeGarbageCollected<BackForwardCacheLoaderHelperForFrame>(*frame));
init.use_counter =
MakeGarbageCollected<DetachableUseCounter>(frame->DomWindow());
init.console_logger = MakeGarbageCollected<DetachableConsoleLogger>(
@@ -296,13 +289,6 @@ SubresourceFilter* FrameFetchContext::GetSubresourceFilter() const {
return document_loader_->GetSubresourceFilter();
}
-PreviewsResourceLoadingHints*
-FrameFetchContext::GetPreviewsResourceLoadingHints() const {
- if (GetResourceFetcherProperties().IsDetached())
- return nullptr;
- return document_loader_->GetPreviewsResourceLoadingHints();
-}
-
PreviewsState FrameFetchContext::previews_state() const {
if (GetResourceFetcherProperties().IsDetached())
return PreviewsTypes::kPreviewsUnspecified;
@@ -438,9 +424,6 @@ void FrameFetchContext::ModifyRequestForCSP(ResourceRequest& resource_request) {
if (GetResourceFetcherProperties().IsDetached())
return;
- // Record the latest requiredCSP value that will be used when sending this
- // request.
- GetFrame()->Loader().RecordLatestRequiredCSP();
GetFrame()->Loader().ModifyRequestForCSP(
resource_request,
&GetResourceFetcherProperties().GetFetchClientSettingsObject(),
@@ -473,214 +456,42 @@ void FrameFetchContext::AddClientHintsIfNecessary(
SecurityOrigin::Create(request.Url())->ToUrlOrigin();
bool is_1p_origin = IsFirstPartyOrigin(request.Url());
- // Sec-CH-UA is special: we always send the header to all origins that are
- // eligible for client hints (e.g. secure transport, JavaScript enabled).
- //
- // https://github.com/WICG/ua-client-hints
- //
- // One exception, however, is that a custom UA is sometimes set without
- // specifying accomponying client hints, in which case we disable sending
- // them.
base::Optional<UserAgentMetadata> ua = GetUserAgentMetadata();
- if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua.has_value()) {
- // ShouldSendClientHint is called to make sure UA is controlled by
- // FeaturePolicy.
- if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
- resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUA,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUA)],
- ua->SerializeBrandVersionList().c_str());
- }
-
- // We also send Sec-CH-UA-Mobile to all hints. It is a one-bit header
- // identifying if the browser has opted for a "mobile" experience
- // Formatted using the "sh-boolean" format from:
- // https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html#boolean
- // ShouldSendClientHint is called to make sure it's controlled by
- // FeaturePolicy.
- if (ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAMobile,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAMobile)],
- ua->mobile ? "?1" : "?0");
- }
- }
-
- // If the frame is detached, then don't send any hints other than UA.
- if (!policy)
- return;
-
-
- if (!RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled() &&
- !base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty) &&
- !is_1p_origin) {
- // No client hints for 3p origins.
- return;
- }
-
- // The next 4 hints should be enabled if we're allowing legacy hints to third
- // parties, or if FeaturePolicy delegation says they are allowed.
- if (ShouldSendClientHint(
- ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kDeviceMemory,
- hints_preferences)) {
- request.SetHttpHeaderField(
- "Device-Memory",
- AtomicString(String::Number(
- ApproximatedDeviceMemory::GetApproximatedDeviceMemory())));
- }
-
- float dpr = GetDevicePixelRatio();
- if (ShouldSendClientHint(
- ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kDpr, hints_preferences)) {
- request.SetHttpHeaderField("DPR", AtomicString(String::Number(dpr)));
- }
-
- if (ShouldSendClientHint(
- ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kViewportWidth,
- hints_preferences) &&
- !GetResourceFetcherProperties().IsDetached() && GetFrame()->View()) {
- request.SetHttpHeaderField(
- "Viewport-Width",
- AtomicString(String::Number(GetFrame()->View()->ViewportWidth())));
- }
-
- if (ShouldSendClientHint(
- ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kResourceWidth,
- hints_preferences)) {
- if (resource_width.is_set) {
- float physical_width = resource_width.width * dpr;
- request.SetHttpHeaderField(
- "Width", AtomicString(String::Number(ceil(physical_width))));
- }
- }
-
- if (ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kRtt, hints_preferences)) {
- base::Optional<base::TimeDelta> http_rtt =
- GetNetworkStateNotifier().GetWebHoldbackHttpRtt();
- if (!http_rtt) {
- http_rtt = GetNetworkStateNotifier().HttpRtt();
- }
-
- uint32_t rtt =
- GetNetworkStateNotifier().RoundRtt(request.Url().Host(), http_rtt);
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kRtt)],
- AtomicString(String::Number(rtt)));
- }
-
- if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
- is_1p_origin,
- network::mojom::blink::WebClientHintsType::kDownlink,
- hints_preferences)) {
- base::Optional<double> throughput_mbps =
- GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps();
- if (!throughput_mbps) {
- throughput_mbps = GetNetworkStateNotifier().DownlinkThroughputMbps();
- }
-
- double mbps = GetNetworkStateNotifier().RoundMbps(request.Url().Host(),
- throughput_mbps);
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kDownlink)],
- AtomicString(String::Number(mbps)));
- }
- if (ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kEct, hints_preferences)) {
- base::Optional<WebEffectiveConnectionType> holdback_ect =
- GetNetworkStateNotifier().GetWebHoldbackEffectiveType();
- if (!holdback_ect)
- holdback_ect = GetNetworkStateNotifier().EffectiveType();
-
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kEct)],
- AtomicString(NetworkStateNotifier::EffectiveConnectionTypeToString(
- holdback_ect.value())));
- }
+ base::Optional<ClientHintImageInfo> image_info;
+ base::Optional<WTF::AtomicString> lang;
- if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
- is_1p_origin,
- network::mojom::blink::WebClientHintsType::kLang,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kLang)],
- GetFrame()
- ->DomWindow()
- ->navigator()
- ->SerializeLanguagesForClientHintHeader());
- }
+ if (document_) { // Only get frame info if the frame is not detached
+ image_info = ClientHintImageInfo();
+ image_info->dpr = GetDevicePixelRatio();
+ image_info->resource_width = resource_width;
+ if (!GetResourceFetcherProperties().IsDetached() && GetFrame()->View())
+ image_info->viewport_width = GetFrame()->View()->ViewportWidth();
- if (ua.has_value() &&
- ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
- is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAArch,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAArch)],
- SerializeHeaderString(ua->architecture));
- }
+ lang = GetFrame()
+ ->DomWindow()
+ ->navigator()
+ ->SerializeLanguagesForClientHintHeader();
- if (ua.has_value() &&
- ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAPlatform,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAPlatform)],
- SerializeHeaderString(ua->platform));
+ // TODO(crbug.com/1151050): |SerializeLanguagesForClientHintHeader| getter
+ // affects later calls if there is a DevTools override. The following blink
+ // test fails unless set to "dirty" to manually reset languages:
+ //
+ // http/tests/inspector-protocol/emulation/emulation-user-agent-override.js
+ GetFrame()->DomWindow()->navigator()->SetLanguagesDirty();
}
- if (ua.has_value() &&
- ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAPlatformVersion,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAPlatformVersion)],
- SerializeHeaderString(ua->platform_version));
- }
-
- if (ua.has_value() &&
- ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
- is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAModel,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAModel)],
- SerializeHeaderString(ua->model));
- }
+ // |hints_preferences| is used only in case of the preload scanner;
+ // GetClientHintsPreferences() has things parsed for this document
+ // by browser (from accept-ch header on this response or previously persisted)
+ // with renderer-parsed http-equiv merged in.
+ ClientHintsPreferences prefs;
+ prefs.CombineWith(hints_preferences);
+ prefs.CombineWith(GetClientHintsPreferences());
- if (ua.has_value() &&
- ShouldSendClientHint(
- ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
- network::mojom::blink::WebClientHintsType::kUAFullVersion,
- hints_preferences)) {
- request.SetHttpHeaderField(
- blink::kClientHintsHeaderMapping[static_cast<size_t>(
- network::mojom::blink::WebClientHintsType::kUAFullVersion)],
- SerializeHeaderString(ua->full_version));
- }
+ BaseFetchContext::AddClientHintsIfNecessary(prefs, resource_origin,
+ is_1p_origin, ua, policy,
+ image_info, lang, request);
}
void FrameFetchContext::PopulateResourceRequest(
@@ -704,6 +515,12 @@ void FrameFetchContext::PopulateResourceRequest(
request.AddHttpHeaderField("CSP", "active");
}
+bool FrameFetchContext::IsPrerendering() const {
+ if (GetResourceFetcherProperties().IsDetached())
+ return frozen_state_->is_prerendering;
+ return document_->IsPrerendering();
+}
+
void FrameFetchContext::SetFirstPartyCookie(ResourceRequest& request) {
// Set the first party for cookies url if it has not been set yet (new
// requests). This value will be updated during redirects, consistent with
@@ -761,8 +578,7 @@ void FrameFetchContext::DispatchDidBlockRequest(
fetch_initiator_info, blocked_reason, resource_type);
}
-const ContentSecurityPolicy*
-FrameFetchContext::GetContentSecurityPolicyForWorld(
+ContentSecurityPolicy* FrameFetchContext::GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const {
if (GetResourceFetcherProperties().IsDetached())
return frozen_state_->content_security_policy;
@@ -807,7 +623,7 @@ FrameFetchContext::CreateWebSocketHandshakeThrottle() {
}
if (!GetFrame())
return nullptr;
- return WebFrame::FromFrame(GetFrame())
+ return WebFrame::FromCoreFrame(GetFrame())
->ToWebLocalFrame()
->Client()
->CreateWebSocketHandshakeThrottle();
@@ -880,8 +696,7 @@ const SecurityOrigin* FrameFetchContext::GetParentSecurityOrigin() const {
return parent->GetSecurityContext()->GetSecurityOrigin();
}
-const ContentSecurityPolicy* FrameFetchContext::GetContentSecurityPolicy()
- const {
+ContentSecurityPolicy* FrameFetchContext::GetContentSecurityPolicy() const {
if (GetResourceFetcherProperties().IsDetached())
return frozen_state_->content_security_policy;
return document_->domWindow()->GetContentSecurityPolicy();
@@ -941,39 +756,6 @@ float FrameFetchContext::GetDevicePixelRatio() const {
return document_->DevicePixelRatio();
}
-bool FrameFetchContext::ShouldSendClientHint(
- ClientHintsMode mode,
- const FeaturePolicy* policy,
- const url::Origin& resource_origin,
- bool is_1p_origin,
- network::mojom::blink::WebClientHintsType type,
- const ClientHintsPreferences& hints_preferences) const {
- bool origin_ok;
-
- if (mode == ClientHintsMode::kLegacy &&
- base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty)) {
- origin_ok = true;
- } else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
- origin_ok =
- (policy && policy->IsFeatureEnabledForOrigin(
- kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
- resource_origin));
- } else {
- origin_ok = is_1p_origin;
- }
-
- if (!origin_ok)
- return false;
-
- // |hints_preferences| is used only in case of the preload scanner;
- // GetClientHintsPreferences() has things parsed for this document
- // by browser (from accept-ch header on this response or previously persisted)
- // with renderer-parsed http-equiv merged in.
- return IsClientHintSentByDefault(type) ||
- GetClientHintsPreferences().ShouldSend(type) ||
- hints_preferences.ShouldSend(type);
-}
-
FetchContext* FrameFetchContext::Detach() {
if (GetResourceFetcherProperties().IsDetached())
return this;
@@ -982,7 +764,7 @@ FetchContext* FrameFetchContext::Detach() {
Url(), GetParentSecurityOrigin(), GetContentSecurityPolicy(),
GetSiteForCookies(), GetTopFrameOrigin(), GetClientHintsPreferences(),
GetDevicePixelRatio(), GetUserAgent(), GetUserAgentMetadata(),
- IsSVGImageChromeClient());
+ IsSVGImageChromeClient(), IsPrerendering());
document_loader_ = nullptr;
document_ = nullptr;
return this;
@@ -996,12 +778,13 @@ void FrameFetchContext::Trace(Visitor* visitor) const {
}
bool FrameFetchContext::CalculateIfAdSubresource(
- const ResourceRequest& resource_request,
+ const ResourceRequestHead& resource_request,
+ const base::Optional<KURL>& alias_url,
ResourceType type,
const FetchInitiatorInfo& initiator_info) {
- // Mark the resource as an Ad if the SubresourceFilter thinks it's an ad.
+ // Mark the resource as an Ad if the BaseFetchContext thinks it's an ad.
bool known_ad = BaseFetchContext::CalculateIfAdSubresource(
- resource_request, type, initiator_info);
+ resource_request, alias_url, type, initiator_info);
if (GetResourceFetcherProperties().IsDetached() ||
!GetFrame()->GetAdTracker()) {
return known_ad;
@@ -1009,8 +792,9 @@ bool FrameFetchContext::CalculateIfAdSubresource(
// The AdTracker needs to know about the request as well, and may also mark it
// as an ad.
+ const KURL& url = alias_url ? alias_url.value() : resource_request.Url();
return GetFrame()->GetAdTracker()->CalculateIfAdSubresource(
- document_->domWindow(), resource_request, type, initiator_info, known_ad);
+ document_->domWindow(), url, type, initiator_info, known_ad);
}
bool FrameFetchContext::SendConversionRequestInsteadOfRedirecting(
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 5c2fea0e9ea..61c5e82961a 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -99,6 +99,8 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
ResourceRequest&,
const ResourceLoaderOptions&) override;
+ bool IsPrerendering() const override;
+
// Exposed for testing.
void ModifyRequestForCSP(ResourceRequest&);
void AddClientHintsIfNecessary(const ClientHintsPreferences&,
@@ -110,7 +112,8 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
void Trace(Visitor*) const override;
bool CalculateIfAdSubresource(
- const ResourceRequest& resource_request,
+ const ResourceRequestHead& resource_request,
+ const base::Optional<KURL>& alias_url,
ResourceType type,
const FetchInitiatorInfo& initiator_info) override;
@@ -146,8 +149,6 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
net::SiteForCookies GetSiteForCookies() const override;
scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const override;
SubresourceFilter* GetSubresourceFilter() const override;
- PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
- const override;
PreviewsState previews_state() const override;
bool AllowScriptFromSource(const KURL&) const override;
bool ShouldBlockRequestByInspector(const KURL&) const override;
@@ -155,7 +156,7 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
const FetchInitiatorInfo&,
ResourceRequestBlockedReason,
ResourceType) const override;
- const ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
+ ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const override;
bool IsSVGImageChromeClient() const override;
void CountUsage(WebFeature) const override;
@@ -174,7 +175,7 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
const KURL& Url() const override;
const SecurityOrigin* GetParentSecurityOrigin() const override;
- const ContentSecurityPolicy* GetContentSecurityPolicy() const override;
+ ContentSecurityPolicy* GetContentSecurityPolicy() const override;
void AddConsoleMessage(ConsoleMessage*) const override;
WebContentSettingsClient* GetContentSettingsClient() const;
@@ -218,7 +219,7 @@ class CORE_EXPORT FrameFetchContext final : public BaseFetchContext,
const bool save_data_enabled_;
// Non-null only when detached.
- Member<const FrozenState> frozen_state_;
+ Member<FrozenState> frozen_state_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 5247e15ea1d..6770b4e4ae4 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -127,7 +127,7 @@ class FrameFetchContextTest : public testing::Test {
dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(500, 500));
dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0);
if (url.IsValid()) {
- auto params = WebNavigationParams::CreateWithHTMLBuffer(
+ auto params = WebNavigationParams::CreateWithHTMLBufferForTesting(
SharedBuffer::Create(), url);
if (!feature_policy_header.IsEmpty()) {
params->response.SetHttpHeaderField(http_names::kFeaturePolicy,
@@ -212,7 +212,8 @@ class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest {
ResourceRequest request(KURL("http://example.com/"));
FetchInitiatorInfo initiator_info;
EXPECT_EQ(expect_is_ad, GetFetchContext()->CalculateIfAdSubresource(
- request, ResourceType::kMock, initiator_info));
+ request, base::nullopt /* alias_url */,
+ ResourceType::kMock, initiator_info));
return reason;
}
@@ -273,7 +274,6 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
protected:
void ModifyRequestForCSP(ResourceRequest& resource_request,
mojom::RequestContextFrameType frame_type) {
- document->GetFrame()->Loader().RecordLatestRequiredCSP();
document->GetFrame()->Loader().ModifyRequestForCSP(
resource_request,
&document->Fetcher()->GetProperties().GetFetchClientSettingsObject(),
@@ -353,21 +353,6 @@ class FrameFetchContextModifyRequestTest : public FrameFetchContextTest {
EXPECT_EQ(expected_value, resource_request.IsAutomaticUpgrade());
}
- void ExpectSetRequiredCSPRequestHeader(
- const char* input,
- mojom::RequestContextFrameType frame_type,
- const AtomicString& expected_required_csp) {
- const KURL input_url(input);
- ResourceRequest resource_request(input_url);
- resource_request.SetRequestContext(
- mojom::blink::RequestContextType::SCRIPT);
-
- ModifyRequestForCSP(resource_request, frame_type);
-
- EXPECT_EQ(expected_required_csp,
- resource_request.HttpHeaderField(http_names::kSecRequiredCSP));
- }
-
void SetFrameOwnerBasedOnFrameType(mojom::RequestContextFrameType frame_type,
HTMLIFrameElement* iframe,
const AtomicString& potential_value) {
@@ -552,44 +537,6 @@ TEST_F(FrameFetchContextModifyRequestTest, SendUpgradeInsecureRequestHeader) {
}
}
-TEST_F(FrameFetchContextModifyRequestTest, SendRequiredCSPHeader) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE);
-
- struct TestCase {
- const char* to_request;
- mojom::RequestContextFrameType frame_type;
- } tests[] = {
- {"https://example.test/page.html",
- mojom::RequestContextFrameType::kAuxiliary},
- {"https://example.test/page.html",
- mojom::RequestContextFrameType::kNested},
- {"https://example.test/page.html", mojom::RequestContextFrameType::kNone},
- {"https://example.test/page.html",
- mojom::RequestContextFrameType::kTopLevel}};
-
- auto* iframe = MakeGarbageCollected<HTMLIFrameElement>(*document);
- const AtomicString& required_csp = AtomicString("default-src 'none'");
- const AtomicString& another_required_csp = AtomicString("default-src 'self'");
-
- for (const auto& test : tests) {
- SetFrameOwnerBasedOnFrameType(test.frame_type, iframe, required_csp);
- ExpectSetRequiredCSPRequestHeader(
- test.to_request, test.frame_type,
- test.frame_type == mojom::RequestContextFrameType::kNested
- ? required_csp
- : g_null_atom);
-
- SetFrameOwnerBasedOnFrameType(test.frame_type, iframe,
- another_required_csp);
- ExpectSetRequiredCSPRequestHeader(
- test.to_request, test.frame_type,
- test.frame_type == mojom::RequestContextFrameType::kNested
- ? another_required_csp
- : g_null_atom);
- }
-}
-
class FrameFetchContextHintsTest : public FrameFetchContextTest {
public:
FrameFetchContextHintsTest() = default;
@@ -774,15 +721,17 @@ TEST_F(FrameFetchContextHintsTest, MonitorLangHint) {
"\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
+ // TODO(crbug.com/924969): A refactoring exposed a bug in the languages
+ // override that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
- "\"en\", \"de\", \"fr\"");
+ "\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
document->domWindow()->navigator()->SetLanguagesForTesting(
"en-US,fr_FR,de-DE,es");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
- "\"en-US\", \"fr-FR\", \"de-DE\", \"es\"");
+ "\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
}
@@ -927,9 +876,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHints) {
ExpectHeader("https://www.example.com/1.gif", "Width", true, "400", 400);
ExpectHeader("https://www.example.com/1.gif", "Viewport-Width", true, "500");
+ // TODO(crbug.com/924969): A refactoring exposed a bug in the languages
+ // override setup that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
- "\"en\", \"de\", \"fr\"");
+ "\"en-US\"");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA", true, "");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, "");
@@ -990,9 +941,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHintsFeaturePolicy) {
ExpectHeader("https://www.example.net/1.gif", "DPR", true, "1");
ExpectHeader("https://www.example.net/1.gif", "Device-Memory", true, "4");
+ // TODO(crbug.com/924969): A refactoring exposed a bug in the languages
+ // override setup that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-Lang", true,
- "\"en\", \"de\", \"fr\"");
+ "\"en-US\"");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA", true, "");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Arch", true, "");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Platform", true, "");
@@ -1444,4 +1397,65 @@ TEST_F(FrameFetchContextTest, SameSiteBackForwardCache) {
}
}
+// Tests that CanRequestCanRequestBasedOnSubresourceFilterOnly will block ads
+// or not correctly, depending on the FilterPolicy.
+TEST_F(FrameFetchContextSubresourceFilterTest,
+ CanRequestBasedOnSubresourceFilterOnly) {
+ const struct {
+ WebDocumentSubresourceFilter::LoadPolicy policy;
+ base::Optional<ResourceRequestBlockedReason> expected_block_reason;
+ } kTestCases[] = {
+ {WebDocumentSubresourceFilter::kDisallow,
+ ResourceRequestBlockedReason::kSubresourceFilter},
+ {WebDocumentSubresourceFilter::kWouldDisallow, base::nullopt},
+ {WebDocumentSubresourceFilter::kAllow, base::nullopt}};
+
+ for (const auto& test : kTestCases) {
+ SetFilterPolicy(test.policy);
+
+ KURL url("http://ads.com/some_script.js");
+ ResourceRequest resource_request(url);
+ resource_request.SetRequestContext(
+ mojom::blink::RequestContextType::SCRIPT);
+ resource_request.SetRequestorOrigin(GetTopFrameOrigin());
+
+ ResourceLoaderOptions options(nullptr /* world */);
+
+ EXPECT_EQ(test.expected_block_reason,
+ GetFetchContext()->CanRequestBasedOnSubresourceFilterOnly(
+ ResourceType::kScript, resource_request, url, options,
+ ReportingDisposition::kReport, base::nullopt));
+ }
+}
+
+// Tests that CalculateIfAdSubresource with an alias URL will tag ads
+// correctly according to the SubresourceFilter mode.
+TEST_F(FrameFetchContextSubresourceFilterTest,
+ CalculateIfAdSubresourceWithAliasURL) {
+ const struct {
+ WebDocumentSubresourceFilter::LoadPolicy policy;
+ bool expected_to_be_tagged_ad;
+ } kTestCases[] = {{WebDocumentSubresourceFilter::kDisallow, true},
+ {WebDocumentSubresourceFilter::kWouldDisallow, true},
+ {WebDocumentSubresourceFilter::kAllow, false}};
+
+ for (const auto& test : kTestCases) {
+ SetFilterPolicy(test.policy);
+
+ KURL url("http://www.example.com");
+ KURL alias_url("http://ads.com/some_script.js");
+ ResourceRequest resource_request(url);
+ resource_request.SetRequestContext(
+ mojom::blink::RequestContextType::SCRIPT);
+ resource_request.SetRequestorOrigin(GetTopFrameOrigin());
+
+ ResourceLoaderOptions options(nullptr /* world */);
+
+ EXPECT_EQ(test.expected_to_be_tagged_ad,
+ GetFetchContext()->CalculateIfAdSubresource(
+ resource_request, alias_url, ResourceType::kScript,
+ options.initiator_info));
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_load_request.h b/chromium/third_party/blink/renderer/core/loader/frame_load_request.h
index 2e405209b7a..4f6ef1c4452 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_load_request.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -27,10 +27,12 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_FRAME_LOAD_REQUEST_H_
#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink.h"
-#include "third_party/blink/public/common/navigation/triggering_event_info.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/platform/web_impression.h"
#include "third_party/blink/public/web/web_window_features.h"
@@ -86,14 +88,24 @@ struct CORE_EXPORT FrameLoadRequest {
navigation_policy_ = navigation_policy;
}
- TriggeringEventInfo GetTriggeringEventInfo() const {
+ mojom::blink::TriggeringEventInfo GetTriggeringEventInfo() const {
return triggering_event_info_;
}
- void SetTriggeringEventInfo(TriggeringEventInfo info) {
- DCHECK(info != TriggeringEventInfo::kUnknown);
+ void SetTriggeringEventInfo(mojom::blink::TriggeringEventInfo info) {
+ DCHECK(info != mojom::blink::TriggeringEventInfo::kUnknown);
triggering_event_info_ = info;
}
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ TakeInitiatorPolicyContainerKeepAliveHandle() {
+ return std::move(initiator_policy_container_keep_alive_handle_);
+ }
+ void SetInitiatorPolicyContainerKeepAliveHandle(
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ handle) {
+ initiator_policy_container_keep_alive_handle_ = std::move(handle);
+ }
+
HTMLFormElement* Form() const { return form_; }
void SetForm(HTMLFormElement* form) { form_ = form; }
@@ -147,14 +159,23 @@ struct CORE_EXPORT FrameLoadRequest {
// Impressions are set when a FrameLoadRequest is created for a click on an
// anchor tag that has conversion measurement attributes.
- void SetImpression(const WebImpression& impression) {
+ void SetImpression(const base::Optional<WebImpression>& impression) {
impression_ = impression;
}
- const base::Optional<WebImpression>& Impression() { return impression_; }
+ const base::Optional<WebImpression>& Impression() const {
+ return impression_;
+ }
bool CanDisplay(const KURL&) const;
+ void SetInitiatorFrameToken(const LocalFrameToken& token) {
+ initiator_frame_token_ = token;
+ }
+ const LocalFrameToken* GetInitiatorFrameToken() const {
+ return base::OptionalOrNullptr(initiator_frame_token_);
+ }
+
private:
LocalDOMWindow* origin_window_;
ResourceRequest resource_request_;
@@ -162,8 +183,8 @@ struct CORE_EXPORT FrameLoadRequest {
ClientNavigationReason client_navigation_reason_ =
ClientNavigationReason::kNone;
NavigationPolicy navigation_policy_ = kNavigationPolicyCurrentTab;
- TriggeringEventInfo triggering_event_info_ =
- TriggeringEventInfo::kNotFromEvent;
+ mojom::blink::TriggeringEventInfo triggering_event_info_ =
+ mojom::blink::TriggeringEventInfo::kNotFromEvent;
HTMLFormElement* form_ = nullptr;
ShouldSendReferrer should_send_referrer_;
scoped_refptr<const DOMWrapperWorld> world_;
@@ -174,6 +195,9 @@ struct CORE_EXPORT FrameLoadRequest {
mojom::RequestContextFrameType::kNone;
WebWindowFeatures window_features_;
base::Optional<WebImpression> impression_;
+ base::Optional<LocalFrameToken> initiator_frame_token_;
+ mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle>
+ initiator_policy_container_keep_alive_handle_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
index dd7deeeeade..ec05377de86 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -41,7 +41,6 @@
#include "base/auto_reset.h"
#include "base/unguessable_token.h"
-#include "build/build_config.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -55,8 +54,6 @@
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/web_frame_load_type.h"
#include "third_party/blink/public/web/web_history_item.h"
@@ -67,6 +64,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/ignore_opens_during_unload_count_incrementer.h"
#include "third_party/blink/renderer/core/events/page_transition_event.h"
+#include "third_party/blink/renderer/core/exported/web_document_loader_impl.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/csp/csp_source.h"
@@ -123,7 +121,6 @@
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/web_test_support.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -135,6 +132,7 @@ namespace blink {
namespace {
void ApplyOriginPolicy(ContentSecurityPolicy* csp,
+ const KURL& response_url,
const WebOriginPolicy& origin_policy) {
// When this function is called. The following lines of code happen
// consecutively:
@@ -150,16 +148,23 @@ void ApplyOriginPolicy(ContentSecurityPolicy* csp,
DCHECK(!csp->HasPolicyFromSource(
network::mojom::ContentSecurityPolicySource::kOriginPolicy));
+ DCHECK(response_url.ProtocolIsInHTTPFamily());
+
+ scoped_refptr<SecurityOrigin> self_origin =
+ SecurityOrigin::Create(response_url);
+
for (const auto& policy : origin_policy.content_security_policies) {
csp->DidReceiveHeader(
- policy, network::mojom::ContentSecurityPolicyType::kEnforce,
+ policy, *self_origin,
+ network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kOriginPolicy);
}
for (const auto& policy :
origin_policy.content_security_policies_report_only) {
csp->DidReceiveHeader(
- policy, network::mojom::ContentSecurityPolicyType::kReport,
+ policy, *self_origin,
+ network::mojom::ContentSecurityPolicyType::kReport,
network::mojom::ContentSecurityPolicySource::kOriginPolicy);
}
}
@@ -216,14 +221,6 @@ ResourceRequest FrameLoader::ResourceRequestForReload(
FrameLoader::FrameLoader(LocalFrame* frame)
: frame_(frame),
progress_tracker_(MakeGarbageCollected<ProgressTracker>(frame)),
- // Frames need to inherit the sandbox flags of their parent frame.
- // These can be fixed at construction time, because the only actions that
- // trigger a sandbox flags change in the parent will necessarily detach
- // this frame.
- forced_sandbox_flags_(
- frame_->Tree().Parent()
- ? frame_->Tree().Parent()->GetSecurityContext()->GetSandboxFlags()
- : network::mojom::blink::WebSandboxFlags::kNone),
dispatching_did_clear_window_object_in_main_world_(false),
virtual_time_pauser_(
frame_->GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
@@ -249,10 +246,13 @@ void FrameLoader::Trace(Visitor* visitor) const {
void FrameLoader::Init() {
ScriptForbiddenScope forbid_scripts;
+ // Load the initial empty document:
auto navigation_params = std::make_unique<WebNavigationParams>();
navigation_params->url = KURL(g_empty_string);
navigation_params->frame_policy =
frame_->Owner() ? frame_->Owner()->GetFramePolicy() : FramePolicy();
+ navigation_params->frame_policy->sandbox_flags =
+ PendingEffectiveSandboxFlags();
DocumentLoader* new_document_loader = Client()->CreateDocumentLoader(
frame_, kWebNavigationTypeOther, CreateCSPForInitialEmptyDocument(),
@@ -350,8 +350,7 @@ void FrameLoader::DispatchUnloadEvent(
}
void FrameLoader::DidExplicitOpen() {
- probe::LifecycleEvent(frame_, GetDocumentLoader(), "init",
- base::TimeTicks::Now().since_origin().InSecondsF());
+ probe::DidOpenDocument(frame_, GetDocumentLoader());
if (empty_document_status_ == EmptyDocumentStatus::kOnlyEmpty)
empty_document_status_ = EmptyDocumentStatus::kOnlyEmptyButExplicitlyOpened;
@@ -436,18 +435,13 @@ void FrameLoader::SetOpener(LocalFrame* opener) {
frame_->SetOpener(opener);
}
-bool FrameLoader::AllowPlugins(ReasonForCallingAllowPlugins reason) {
+bool FrameLoader::AllowPlugins() {
// With Oilpan, a FrameLoader might be accessed after the Page has been
// detached. FrameClient will not be accessible, so bail early.
if (!Client())
return false;
Settings* settings = frame_->GetSettings();
- bool allowed = settings && settings->GetPluginsEnabled();
- if (!allowed && reason == kAboutToInstantiatePlugin) {
- if (auto* settings_client = frame_->GetContentSettingsClient())
- settings_client->DidNotAllowPlugins();
- }
- return allowed;
+ return settings && settings->GetPluginsEnabled();
}
void FrameLoader::DetachDocumentLoader(Member<DocumentLoader>& loader,
@@ -638,7 +632,8 @@ DetermineRequestDestinationFromNavigationType(
void FrameLoader::StartNavigation(FrameLoadRequest& request,
WebFrameLoadType frame_load_type) {
CHECK(!IsBackForwardLoadType(frame_load_type));
- DCHECK(request.GetTriggeringEventInfo() != TriggeringEventInfo::kUnknown);
+ DCHECK(request.GetTriggeringEventInfo() !=
+ mojom::blink::TriggeringEventInfo::kUnknown);
DCHECK(frame_->GetDocument());
if (HTMLFrameOwnerElement* element = frame_->DeprecatedLocalOwner())
element->CancelPendingLazyLoad();
@@ -699,8 +694,10 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
// Perform same document navigation.
if (same_document_navigation) {
document_loader_->CommitSameDocumentNavigation(
- url, frame_load_type, nullptr, request.ClientRedirect(), origin_window,
- request.GetTriggeringEventInfo() != TriggeringEventInfo::kNotFromEvent,
+ url, frame_load_type, nullptr, request.ClientRedirect(),
+ resource_request.HasUserGesture(), origin_window,
+ request.GetTriggeringEventInfo() !=
+ mojom::blink::TriggeringEventInfo::kNotFromEvent,
nullptr /* extra_data */);
return;
}
@@ -715,7 +712,8 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
WebNavigationType navigation_type = DetermineNavigationType(
frame_load_type, resource_request.HttpBody() || request.Form(),
- request.GetTriggeringEventInfo() != TriggeringEventInfo::kNotFromEvent);
+ request.GetTriggeringEventInfo() !=
+ mojom::blink::TriggeringEventInfo::kNotFromEvent);
mojom::blink::RequestContextType request_context_type =
DetermineRequestContextFromNavigationType(navigation_type);
@@ -733,19 +731,11 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
mojo::PendingRemote<mojom::blink::NavigationInitiator> navigation_initiator;
WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp;
- network::mojom::blink::CSPSourcePtr initiator_self_source;
if (origin_window && origin_window->GetContentSecurityPolicy()
->ExperimentalFeaturesEnabled()) {
ContentSecurityPolicy* origin_window_csp =
origin_window->GetContentSecurityPolicy();
- CSPSource* origin_window_csp_self_source =
- origin_window_csp->GetSelfSource();
-
- initiator_csp = origin_window_csp->ExposeForNavigationalChecks();
- if (origin_window_csp_self_source) {
- initiator_self_source =
- origin_window_csp_self_source->ExposeForNavigationalChecks();
- }
+ initiator_csp = mojo::Clone(origin_window_csp->GetParsedPolicies());
NavigationInitiatorImpl::From(*origin_window)
.BindReceiver(navigation_initiator.InitWithNewPipeAndPassReceiver());
}
@@ -761,10 +751,6 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
origin_window->GetContentSecurityPolicy());
}
- // Record the latest requiredCSP value that will be used when loading the
- // document at navigation commit time.
- RecordLatestRequiredCSP();
-
// TODO(arthursonzogni): 'frame-src' check is disabled on the
// renderer side, but is enforced on the browser side.
// See http://crbug.com/692595 for understanding why it
@@ -841,6 +827,18 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
request.JavascriptWorld().get())
? CSPDisposition::DO_NOT_CHECK
: CSPDisposition::CHECK;
+
+ // If this is a subframe load to a urn: URL, allow loading from a Web Bundle
+ // attached to the parent document.
+ if (url.Protocol() == "urn") {
+ auto* parent_local_frame = DynamicTo<LocalFrame>(frame_->Tree().Parent());
+ if (parent_local_frame &&
+ parent_local_frame->DomWindow() == origin_window &&
+ origin_window->Fetcher()) {
+ origin_window->Fetcher()->AttachWebBundleTokenIfNeeded(resource_request);
+ }
+ }
+
Client()->BeginNavigation(
resource_request, request.GetFrameType(), origin_window,
nullptr /* document_loader */, navigation_type,
@@ -849,9 +847,9 @@ void FrameLoader::StartNavigation(FrameLoadRequest& request,
request.GetTriggeringEventInfo(), request.Form(),
should_check_main_world_csp, request.GetBlobURLToken(),
request.GetInputStartTime(), request.HrefTranslate().GetString(),
- request.Impression(), std::move(initiator_csp),
- std::move(initiator_self_source), initiator_address_space,
- std::move(navigation_initiator));
+ request.Impression(), std::move(initiator_csp), initiator_address_space,
+ std::move(navigation_initiator), request.GetInitiatorFrameToken(),
+ request.TakeInitiatorPolicyContainerKeepAliveHandle());
}
static void FillStaticResponseIfNeeded(WebNavigationParams* params,
@@ -1020,8 +1018,6 @@ void FrameLoader::CommitNavigation(
// with regards to the last commit.
// In this rare case, we intentionally proceed as cross-document.
- RecordLatestRequiredCSP();
-
if (!CancelProvisionalLoaderForNewNavigation())
return;
@@ -1042,9 +1038,13 @@ void FrameLoader::CommitNavigation(
navigation_params->origin_policy, last_origin_window_csp_.Release(),
commit_reason);
+ DCHECK(content_security_policy);
+
for (auto& csp : navigation_params->forced_content_security_policies) {
- content_security_policy->AddPolicyFromHeaderValue(
- csp, network::mojom::ContentSecurityPolicyType::kEnforce,
+ scoped_refptr<SecurityOrigin> self_origin =
+ SecurityOrigin::Create(navigation_params->url);
+ content_security_policy->DidReceiveHeader(
+ csp, *self_origin, network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
}
@@ -1056,6 +1056,18 @@ void FrameLoader::CommitNavigation(
std::move(navigation_params->policy_container)));
}
+ // If this is a javascript: URL or XSLT commit, we must copy the ExtraData
+ // from the previous DocumentLoader to ensure the new DocumentLoader behaves
+ // the same way as the previous one.
+ if (commit_reason == CommitReason::kXSLT ||
+ commit_reason == CommitReason::kJavascriptUrl) {
+ DCHECK(!extra_data);
+ if (auto* old_document_loader =
+ static_cast<WebDocumentLoaderImpl*>(document_loader_.Get())) {
+ extra_data = old_document_loader->TakeExtraData();
+ }
+ }
+
base::Optional<Document::UnloadEventTiming> unload_timing;
FrameSwapScope frame_swap_scope(frame_owner);
{
@@ -1074,7 +1086,20 @@ void FrameLoader::CommitNavigation(
DCHECK(Client()->HasWebView());
scoped_refptr<SecurityOrigin> security_origin =
SecurityOrigin::Create(navigation_params->url);
- if (!DetachDocument(security_origin.get(), &unload_timing))
+
+ // If `frame_` is provisional, this is largely a no-op other than cleaning
+ // up the initial (and unused) empty document. Otherwise, this unloads the
+ // previous Document and detaches subframes. If `DetachDocument()` returns
+ // false, JS caused `frame_` to be removed, so just return.
+ const bool is_provisional = frame_->IsProvisional();
+ if (!DetachDocument(security_origin.get(), &unload_timing)) {
+ DCHECK(!is_provisional);
+ return;
+ }
+
+ // If the frame is provisional, swap it in now. However, if `Swap()` returns
+ // false, JS caused `frame_` to be removed, so just return.
+ if (is_provisional && !frame_->SwapIn())
return;
}
@@ -1161,6 +1186,9 @@ void FrameLoader::DidAccessInitialDocument() {
bool FrameLoader::DetachDocument(
SecurityOrigin* committing_origin,
base::Optional<Document::UnloadEventTiming>* timing) {
+ DCHECK(frame_->GetDocument());
+ DCHECK(document_loader_);
+
PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
ClientNavigationState* client_navigation = client_navigation_.get();
@@ -1178,8 +1206,7 @@ bool FrameLoader::DetachDocument(
// both when unloading itself and when unloading its descendants.
IgnoreOpensDuringUnloadCountIncrementer ignore_opens_during_unload(
frame_->GetDocument());
- if (document_loader_)
- DispatchUnloadEvent(committing_origin, timing);
+ DispatchUnloadEvent(committing_origin, timing);
frame_->DetachChildren();
// The previous calls to dispatchUnloadEvent() and detachChildren() can
// execute arbitrary script via things like unload events. If the executed
@@ -1189,14 +1216,13 @@ bool FrameLoader::DetachDocument(
return false;
// FrameNavigationDisabler should prevent another load from starting.
DCHECK_EQ(client_navigation_.get(), client_navigation);
- // detachFromFrame() will abort XHRs that haven't completed, which can trigger
- // event listeners for 'abort'. These event listeners might call
+ // Detaching the document loader will abort XHRs that haven't completed, which
+ // can trigger event listeners for 'abort'. These event listeners might call
// window.stop(), which will in turn detach the provisional document loader.
// At this point, the provisional document loader should not detach, because
// then the FrameLoader would not have any attached DocumentLoaders. This is
// guaranteed by FrameNavigationDisabler above.
- if (document_loader_)
- DetachDocumentLoader(document_loader_, true);
+ DetachDocumentLoader(document_loader_, true);
// 'abort' listeners can also detach the frame.
if (!frame_->Client())
return false;
@@ -1204,10 +1230,10 @@ bool FrameLoader::DetachDocument(
DCHECK_EQ(client_navigation_.get(), client_navigation);
// No more events will be dispatched so detach the Document.
+ // TODO(dcheng): Why is this a conditional check?
// TODO(yoav): Should we also be nullifying domWindow's document (or
// domWindow) since the doc is now detached?
- if (frame_->GetDocument())
- frame_->GetDocument()->Shutdown();
+ frame_->GetDocument()->Shutdown();
document_loader_ = nullptr;
return true;
@@ -1234,17 +1260,20 @@ void FrameLoader::CommitDocumentLoader(
// of the previous Document.
document_loader_->SetHistoryItemStateForCommit(
previous_history_item, document_loader_->LoadType(),
- DocumentLoader::HistoryNavigationType::kDifferentDocument);
+ DocumentLoader::HistoryNavigationType::kDifferentDocument,
+ commit_reason);
}
// Update the DocumentLoadTiming with the timings from the previous document
// unload event.
if (unload_timing.has_value()) {
- document_loader_->GetTiming().SetHasSameOriginAsPreviousDocument(true);
+ document_loader_->GetTiming().SetCanRequestFromPreviousDocument(
+ unload_timing->can_request);
document_loader_->GetTiming().MarkUnloadEventStart(
unload_timing->unload_event_start);
document_loader_->GetTiming().MarkUnloadEventEnd(
unload_timing->unload_event_end);
+ document_loader_->GetTiming().MarkCommitNavigationEnd();
}
TakeObjectSnapshot();
@@ -1255,8 +1284,7 @@ void FrameLoader::CommitDocumentLoader(
}
void FrameLoader::RestoreScrollPositionAndViewState() {
- if (RuntimeEnabledFeatures::ForceLoadAtTopEnabled(frame_->DomWindow()) ||
- !frame_->GetPage() || !GetDocumentLoader() ||
+ if (!frame_->GetPage() || !GetDocumentLoader() ||
!GetDocumentLoader()->GetHistoryItem() ||
!GetDocumentLoader()->GetHistoryItem()->GetViewState() ||
!GetDocumentLoader()->NavigationScrollAllowed()) {
@@ -1398,13 +1426,11 @@ void FrameLoader::ProcessFragment(const KURL& url,
GetDocumentLoader()->GetInitialScrollState().did_restore_from_history ||
uses_manual_scroll_restoration;
- // Scrolling at load can be blocked by document policy (or the equivalent
- // ForceLoadAtTop REF currently in origin trial). This policy applies only to
- // cross-document navigations.
+ // Scrolling at load can be blocked by document policy. This policy applies
+ // only to cross-document navigations.
const bool blocked_by_policy =
!is_same_document_navigation &&
- (RuntimeEnabledFeatures::ForceLoadAtTopEnabled(frame_->DomWindow()) ||
- !GetDocumentLoader()->NavigationScrollAllowed());
+ !GetDocumentLoader()->NavigationScrollAllowed();
// We should avoid scrolling the fragment if it would clobber a history
// restored scroll state but still allow it on same document navigations
@@ -1571,11 +1597,6 @@ void FrameLoader::RunScriptsAtDocumentElementAvailable() {
// The frame might be detached at this point.
}
-void FrameLoader::ForceSandboxFlags(
- network::mojom::blink::WebSandboxFlags flags) {
- forced_sandbox_flags_ |= flags;
-}
-
void FrameLoader::DispatchDidClearDocumentOfWindowObject() {
if (state_ == State::kUninitialized)
return;
@@ -1612,10 +1633,12 @@ void FrameLoader::DispatchDidClearWindowObjectInMainWorld() {
network::mojom::blink::WebSandboxFlags
FrameLoader::PendingEffectiveSandboxFlags() const {
- network::mojom::blink::WebSandboxFlags flags = forced_sandbox_flags_;
- if (FrameOwner* frame_owner = frame_->Owner())
- flags |= frame_owner->GetFramePolicy().sandbox_flags;
- return flags;
+ if (Frame* parent = frame_->Tree().Parent()) {
+ return parent->GetSecurityContext()->GetSandboxFlags() |
+ frame_->Owner()->GetFramePolicy().sandbox_flags;
+ } else {
+ return frame_->OpenerSandboxFlags();
+ }
}
void FrameLoader::ModifyRequestForCSP(
@@ -1623,14 +1646,6 @@ void FrameLoader::ModifyRequestForCSP(
const FetchClientSettingsObject* fetch_client_settings_object,
LocalDOMWindow* window_for_logging,
mojom::RequestContextFrameType frame_type) const {
- if (!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE) &&
- !RequiredCSP().IsEmpty()) {
- DCHECK(
- ContentSecurityPolicy::IsValidCSPAttr(RequiredCSP().GetString(), ""));
- resource_request.SetHttpHeaderField(http_names::kSecRequiredCSP,
- RequiredCSP());
- }
-
// Tack an 'Upgrade-Insecure-Requests' header to outgoing navigational
// requests, as described in
// https://w3c.github.io/webappsec-upgrade-insecure-requests/#feature-detect
@@ -1670,12 +1685,6 @@ void FrameLoader::ReportLegacyTLSVersion(const KURL& url,
.SetIsAdResource(is_ad_resource)
.Record(root.GetDocument()->UkmRecorder());
- // Web tests use an outdated server on macOS. See https://crbug.com/936515.
-#if defined(OS_MAC)
- if (WebTestSupport::IsRunningWebTest())
- return;
-#endif
-
String origin = SecurityOrigin::Create(url)->ToString();
// To prevent log spam, only log the message once per origin.
if (tls_version_warning_origins_.Contains(origin))
@@ -1721,21 +1730,15 @@ void FrameLoader::ReportLegacyTLSVersion(const KURL& url,
console_message));
}
-void FrameLoader::RecordLatestRequiredCSP() {
- required_csp_ =
- frame_->Owner() ? frame_->Owner()->RequiredCsp() : g_null_atom;
-}
-
-std::unique_ptr<TracedValue> FrameLoader::ToTracedValue() const {
- auto traced_value = std::make_unique<TracedValue>();
- traced_value->BeginDictionary("frame");
- traced_value->SetString("id_ref", IdentifiersFactory::FrameId(frame_.Get()));
- traced_value->EndDictionary();
- traced_value->SetBoolean("isLoadingMainFrame", frame_->IsMainFrame());
- traced_value->SetString(
- "documentLoaderURL",
- document_loader_ ? document_loader_->Url().GetString() : String());
- return traced_value;
+void FrameLoader::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ {
+ auto frame_dict = dict.AddDictionary("frame");
+ frame_dict.Add("id_ref", IdentifiersFactory::FrameId(frame_.Get()));
+ }
+ dict.Add("isLoadingMainFrame", frame_->IsMainFrame());
+ dict.Add("documentLoaderURL",
+ document_loader_ ? document_loader_->Url().GetString() : String());
}
inline void FrameLoader::TakeObjectSnapshot() const {
@@ -1743,8 +1746,7 @@ inline void FrameLoader::TakeObjectSnapshot() const {
// We already logged TRACE_EVENT_OBJECT_DELETED_WITH_ID in detach().
return;
}
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("loading", "FrameLoader", this,
- ToTracedValue());
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("loading", "FrameLoader", this, this);
}
ContentSecurityPolicy* FrameLoader::CreateCSPForInitialEmptyDocument() const {
@@ -1799,9 +1801,8 @@ ContentSecurityPolicy* FrameLoader::CreateCSP(
// iframe/popup's script at a fine-grained level.
ContentSecurityPolicy* csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->SetOverrideURLForSelf(response.CurrentRequestUrl());
- if (frame_->GetSettings()->BypassCSP())
+ if (frame_->GetSettings()->GetBypassCSP())
return csp; // Empty CSP.
// Parse CSP from the HTTP response.
@@ -1809,54 +1810,7 @@ ContentSecurityPolicy* FrameLoader::CreateCSP(
// Retrieve CSP stored in the OriginPolicy.
if (origin_policy)
- ApplyOriginPolicy(csp, origin_policy.value());
-
- // Plugin inherits plugin's CSP from their navigation initiator.
- DocumentInit::Type document_type =
- DocumentInit::ComputeDocumentType(frame_, url, response.MimeType());
- if (document_type == DocumentInit::Type::kPlugin) {
- Frame* owner_frame = frame_->Parent() ? frame_->Parent() : frame_->Opener();
- ContentSecurityPolicy* owner_csp =
- owner_frame
- ? owner_frame->GetSecurityContext()->GetContentSecurityPolicy()
- : nullptr;
- // TODO(andypaicu): This should always inherit the origin document's plugin
- // types but because this could be a OOPIF document it might not have
- // access. In this situation we fallback on using the parent/opener:
- ContentSecurityPolicy* inherited_csp =
- initiator_csp ? initiator_csp : owner_csp;
- if (inherited_csp)
- csp->CopyPluginTypesFrom(inherited_csp);
- }
-
- // When the embedder used the 'required-csp', its embeddee must either:
- // 1) Use the 'allow-csp' header for opting in inheriting them.
- // 2) Ensure its own CSP subsume them, or it will be blocked.
- //
- // See:
- // - https://w3c.github.io/webappsec-cspee/#required-csp-header
- // - https://w3c.github.io/webappsec-cspee/#allow-csp-from-header
- if (RequiredCSP().IsEmpty() ||
- base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE)) {
- return csp;
- }
-
- const SecurityOrigin* parent_security_origin =
- frame_->Tree().Parent()->GetSecurityContext()->GetSecurityOrigin();
- if (parent_security_origin &&
- ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
- response, parent_security_origin)) {
- csp->AddPolicyFromHeaderValue(
- RequiredCSP(), network::mojom::ContentSecurityPolicyType::kEnforce,
- network::mojom::ContentSecurityPolicySource::kHTTP);
- } else {
- auto* required_csp = MakeGarbageCollected<ContentSecurityPolicy>();
- required_csp->AddPolicyFromHeaderValue(
- RequiredCSP(), network::mojom::ContentSecurityPolicyType::kEnforce,
- network::mojom::ContentSecurityPolicySource::kHTTP);
- if (!required_csp->Subsumes(*csp))
- return nullptr; // Document blocked.
- }
+ ApplyOriginPolicy(csp, url, origin_policy.value());
return csp;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.h b/chromium/third_party/blink/renderer/core/loader/frame_loader.h
index 8cae0f05369..598d75368cc 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.h
@@ -145,18 +145,11 @@ class CORE_EXPORT FrameLoader final {
void DispatchDocumentElementAvailable();
void RunScriptsAtDocumentElementAvailable();
- // The following sandbox flags will be forced, regardless of changes to the
- // sandbox attribute of any parent frames.
- void ForceSandboxFlags(network::mojom::blink::WebSandboxFlags flags);
-
- network::mojom::blink::WebSandboxFlags GetForcedSandboxFlags() const {
- return forced_sandbox_flags_;
- }
-
- // Includes the collection of forced, inherited, and FrameOwner's sandbox
- // flags. Note: with FeaturePolicyForSandbox the frame owner's sandbox flags
- // only includes the flags which are *not* implemented as feature policies
- // already present in the FrameOwner's ContainerPolicy.
+ // See content/browser/renderer_host/sandbox_flags.md
+ // This contains the sandbox flags to commit for new documents.
+ // - For main documents, it contains the sandbox inherited from the opener.
+ // - For nested documents, it contains the sandbox flags inherited from the
+ // parent and the one defined in the <iframe>'s sandbox attribute.
network::mojom::blink::WebSandboxFlags PendingEffectiveSandboxFlags() const;
// Modifying itself is done based on |fetch_client_settings_object|.
@@ -174,9 +167,6 @@ class CORE_EXPORT FrameLoader final {
Frame* Opener();
void SetOpener(LocalFrame*);
- const AtomicString& RequiredCSP() const { return required_csp_; }
- void RecordLatestRequiredCSP();
-
void Detach();
void FinishedParsing();
@@ -206,7 +196,7 @@ class CORE_EXPORT FrameLoader final {
void DispatchUnloadEvent(SecurityOrigin* committing_origin,
base::Optional<Document::UnloadEventTiming>*);
- bool AllowPlugins(ReasonForCallingAllowPlugins);
+ bool AllowPlugins();
void SaveScrollAnchor();
void SaveScrollState();
@@ -237,6 +227,8 @@ class CORE_EXPORT FrameLoader final {
static bool NeedsHistoryItemRestore(WebFrameLoadType type);
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
private:
bool AllowRequestForThisFrame(const FrameLoadRequest&);
WebFrameLoadType DetermineFrameLoadType(const KURL& url,
@@ -264,7 +256,6 @@ class CORE_EXPORT FrameLoader final {
void DetachDocumentLoader(Member<DocumentLoader>&,
bool flush_microtask_queue = false);
- std::unique_ptr<TracedValue> ToTracedValue() const;
void TakeObjectSnapshot() const;
// Commits the given |document_loader|.
@@ -303,8 +294,6 @@ class CORE_EXPORT FrameLoader final {
};
std::unique_ptr<ClientNavigationState> client_navigation_;
- network::mojom::blink::WebSandboxFlags forced_sandbox_flags_;
-
// The state is set to kInitialized when Init() completes, and kDetached
// during teardown in Detach().
enum class State { kUninitialized, kInitialized, kDetached };
@@ -328,8 +317,6 @@ class CORE_EXPORT FrameLoader final {
// confused by several navigations submitted in a row.
Member<ContentSecurityPolicy> last_origin_window_csp_;
- AtomicString required_csp_;
-
// The origins for which a legacy TLS version warning has been printed. The
// size of this set is capped, after which no more warnings are printed.
HashSet<String> tls_version_warning_origins_;
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/frame_loader_test.cc
index 84064abfb62..8321eeba7a9 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader_test.cc
@@ -6,7 +6,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
#include "third_party/blink/renderer/core/page/chrome_client_impl.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
@@ -131,18 +130,19 @@ TEST_F(FrameLoaderTest, PolicyContainerIsStoredInLocalFrameOnCommitNavigation) {
const KURL& url = KURL(NullURL(), "https://www.example.com/bar.html");
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url);
params->policy_container = std::make_unique<WebPolicyContainer>(
- WebPolicyContainerDocumentPolicies{
- network::mojom::ReferrerPolicy::kAlways},
- CrossVariantMojoAssociatedRemote<
- mojom::PolicyContainerHostInterfaceBase>());
+ WebPolicyContainerPolicies{network::mojom::ReferrerPolicy::kAlways,
+ network::mojom::IPAddressSpace::kPublic},
+ mojo::NullAssociatedRemote());
LocalFrame* local_frame =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
local_frame->Loader().CommitNavigation(std::move(params), nullptr);
- EXPECT_EQ(mojom::blink::PolicyContainerDocumentPolicies::New(
- network::mojom::ReferrerPolicy::kAlways),
+ EXPECT_EQ(mojom::blink::PolicyContainerPolicies::New(
+ network::mojom::ReferrerPolicy::kAlways,
+ network::mojom::IPAddressSpace::kPublic),
local_frame->GetPolicyContainer()->GetPolicies());
}
diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
index d98fe097ea9..072f6d7e378 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h
@@ -33,11 +33,6 @@ namespace blink {
enum ShouldSendReferrer { kMaybeSendReferrer, kNeverSendReferrer };
-enum ReasonForCallingAllowPlugins {
- kAboutToInstantiatePlugin,
- kNotAboutToInstantiatePlugin
-};
-
enum LoadStartType {
kNavigationToDifferentDocument,
kNavigationWithinSameDocument
diff --git a/chromium/third_party/blink/renderer/core/loader/http_equiv.cc b/chromium/third_party/blink/renderer/core/loader/http_equiv.cc
index bb4c556b35c..a36a76e12fc 100644
--- a/chromium/third_party/blink/renderer/core/loader/http_equiv.cc
+++ b/chromium/third_party/blink/renderer/core/loader/http_equiv.cc
@@ -15,7 +15,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
+#include "third_party/blink/renderer/core/loader/frame_client_hints_preferences_context.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -97,16 +97,18 @@ void HttpEquiv::ProcessHttpEquivContentSecurityPolicy(
const AtomicString& content) {
if (!window || !window->GetFrame())
return;
- if (window->GetFrame()->GetSettings()->BypassCSP())
+ if (window->GetFrame()->GetSettings()->GetBypassCSP())
return;
if (EqualIgnoringASCIICase(equiv, "content-security-policy")) {
window->GetContentSecurityPolicy()->DidReceiveHeader(
- content, network::mojom::ContentSecurityPolicyType::kEnforce,
+ content, *(window->GetSecurityOrigin()),
+ network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kMeta);
} else if (EqualIgnoringASCIICase(equiv,
"content-security-policy-report-only")) {
window->GetContentSecurityPolicy()->DidReceiveHeader(
- content, network::mojom::ContentSecurityPolicyType::kReport,
+ content, *(window->GetSecurityOrigin()),
+ network::mojom::ContentSecurityPolicyType::kReport,
network::mojom::ContentSecurityPolicySource::kMeta);
} else {
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/core/loader/idleness_detector.cc b/chromium/third_party/blink/renderer/core/loader/idleness_detector.cc
index fa6dd8e7bec..2359f6c377f 100644
--- a/chromium/third_party/blink/renderer/core/loader/idleness_detector.cc
+++ b/chromium/third_party/blink/renderer/core/loader/idleness_detector.cc
@@ -223,6 +223,7 @@ void IdlenessDetector::NetworkQuietTimerFired(TimerBase*) {
void IdlenessDetector::Trace(Visitor* visitor) const {
visitor->Trace(local_frame_);
+ visitor->Trace(network_quiet_timer_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/idleness_detector.h b/chromium/third_party/blink/renderer/core/loader/idleness_detector.h
index 0dac8000cf4..65e4abd1418 100644
--- a/chromium/third_party/blink/renderer/core/loader/idleness_detector.h
+++ b/chromium/third_party/blink/renderer/core/loader/idleness_detector.h
@@ -82,7 +82,7 @@ class CORE_EXPORT IdlenessDetector
// Record the actual start time of network quiet.
base::TimeTicks network_0_quiet_start_time_;
base::TimeTicks network_2_quiet_start_time_;
- TaskRunnerTimer<IdlenessDetector> network_quiet_timer_;
+ HeapTaskRunnerTimer<IdlenessDetector> network_quiet_timer_;
DISALLOW_COPY_AND_ASSIGN(IdlenessDetector);
};
diff --git a/chromium/third_party/blink/renderer/core/loader/image_loader.cc b/chromium/third_party/blink/renderer/core/loader/image_loader.cc
index ea584df31ee..1c8b0d8e2d9 100644
--- a/chromium/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/image_loader.cc
@@ -25,7 +25,6 @@
#include <memory>
#include <utility>
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_client_hints_type.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -38,7 +37,6 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/increment_load_event_delay_count.h"
-#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_owner.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -53,6 +51,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
#include "third_party/blink/renderer/core/loader/lazy_image_helper.h"
+#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
#include "third_party/blink/renderer/core/probe/async_task_id.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
@@ -66,7 +65,6 @@
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
-#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -82,10 +80,7 @@ bool CheckForUnoptimizedImagePolicy(ExecutionContext* context,
// Render the image as a placeholder image if the image is not sufficiently
// well-compressed, according to the unoptimized image feature policies on
// |document|.
- // Note: UnoptimizedImagePolicies is currently part of DocumentPolicy.
- // The original runtime feature UnoptimizedImagePolicies is no longer used,
- // and are planned to be removed.
- if (RuntimeEnabledFeatures::DocumentPolicyEnabled(context) &&
+ if (RuntimeEnabledFeatures::ExperimentalPoliciesEnabled() &&
!new_image->IsAcceptableCompressionRatio(*context)) {
return true;
}
@@ -118,42 +113,6 @@ bool CanReuseFromListOfAvailableImages(
return true;
}
-// Returns whether subresource redirect can be attempted for the image fetch.
-// Redirect to other origins could be disabled due to CSP or CORS restrictions.
-bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
- const KURL& url) {
- // Allow redirection only when DataSaver is enabled and subresource redirect
- // feature is enabled which allows redirecting to better optimized versions.
- if (!base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect) ||
- !GetNetworkStateNotifier().SaveDataEnabled()) {
- return false;
- }
- // Enable subresource redirect only for <img> elements created by parser.
- // Images created from javascript, fetched via XHR/Fetch API should not be
- // subresource redirected due to the additional CORB/CORS handling needed for
- // them.
- if (!image_element || !image_element->ElementCreatedByParser()) {
- return false;
- }
- // Create a cross origin URL by appending a string to the original host. This
- // is used to find whether CSP is restricting image fetches from other
- // origins.
- KURL cross_origin_url = url;
- cross_origin_url.SetHost(url.Host() + "crossorigin.com");
- auto* content_security_policy =
- image_element->GetExecutionContext()->GetContentSecurityPolicy();
- if (content_security_policy &&
- !content_security_policy->AllowImageFromSource(
- cross_origin_url, cross_origin_url, RedirectStatus::kNoRedirect,
- ReportingDisposition::kSuppressReporting)) {
- return false;
- }
- // Allow subresource redirect only when cross-origin attribute is not set,
- // which indicates CORS validation is not triggered for the image.
- return (GetCrossOriginAttributeValue(image_element->FastGetAttribute(
- html_names::kCrossoriginAttr)) == kCrossOriginAttributeNotSet);
-}
-
} // namespace
class ImageLoader::Task {
@@ -440,8 +399,8 @@ inline void ImageLoader::DispatchErrorEvent() {
*GetElement()->GetDocument().GetTaskRunner(TaskType::kDOMManipulation),
FROM_HERE,
WTF::Bind(&ImageLoader::DispatchPendingErrorEvent, WrapPersistent(this),
- WTF::Passed(std::make_unique<IncrementLoadEventDelayCount>(
- GetElement()->GetDocument()))));
+ std::make_unique<IncrementLoadEventDelayCount>(
+ GetElement()->GetDocument())));
}
inline void ImageLoader::CrossSiteOrCSPViolationOccurred(
@@ -458,8 +417,7 @@ inline void ImageLoader::EnqueueImageLoadingMicroTask(
network::mojom::ReferrerPolicy referrer_policy) {
auto task = std::make_unique<Task>(this, update_behavior, referrer_policy);
pending_task_ = task->GetWeakPtr();
- Microtask::EnqueueMicrotask(
- WTF::Bind(&Task::Run, WTF::Passed(std::move(task))));
+ Microtask::EnqueueMicrotask(WTF::Bind(&Task::Run, std::move(task)));
delay_until_do_update_from_element_ =
std::make_unique<IncrementLoadEventDelayCount>(element_->GetDocument());
}
@@ -558,14 +516,14 @@ void ImageLoader::DoUpdateFromElement(
}
DCHECK(document.GetFrame());
+ auto* frame = document.GetFrame();
+
FetchParameters params(std::move(resource_request),
resource_loader_options);
- ConfigureRequest(params, *element_,
- document.GetFrame()->GetClientHintsPreferences());
+ ConfigureRequest(params, *element_, frame->GetClientHintsPreferences());
if (update_behavior != kUpdateForcedReload &&
lazy_image_load_state_ != LazyImageLoadState::kFullImage) {
- const auto* frame = document.GetFrame();
if (auto* html_image = DynamicTo<HTMLImageElement>(GetElement())) {
LoadingAttributeValue loading_attr = GetLoadingAttributeValue(
html_image->FastGetAttribute(html_names::kLoadingAttr));
@@ -670,6 +628,10 @@ void ImageLoader::DoUpdateFromElement(
void ImageLoader::UpdateFromElement(
UpdateFromElementBehavior update_behavior,
network::mojom::ReferrerPolicy referrer_policy) {
+ if (!element_->GetDocument().IsActive()) {
+ return;
+ }
+
AtomicString image_source_url = element_->ImageSourceURL();
suppress_error_events_ = (update_behavior == kUpdateSizeChanged);
last_base_element_url_ =
@@ -705,6 +667,9 @@ void ImageLoader::UpdateFromElement(
delay_until_do_update_from_element_ = nullptr;
}
+ // TODO(crbug.com/1175295): Remove this CHECK once the investigation is done.
+ CHECK(element_->GetDocument().GetExecutionContext());
+
if (ShouldLoadImmediately(ImageSourceToKURL(image_source_url))) {
DoUpdateFromElement(element_->GetExecutionContext()->GetCurrentWorld(),
update_behavior, referrer_policy, UpdateType::kSync);
@@ -865,13 +830,15 @@ void ImageLoader::ImageNotifyFinished(ImageResourceContent* content) {
return;
}
+ content->RecordDecodedImageType(&element_->GetDocument());
+
CHECK(!pending_load_event_.IsActive());
pending_load_event_ = PostCancellableTask(
*GetElement()->GetDocument().GetTaskRunner(TaskType::kDOMManipulation),
FROM_HERE,
WTF::Bind(&ImageLoader::DispatchPendingLoadEvent, WrapPersistent(this),
- WTF::Passed(std::make_unique<IncrementLoadEventDelayCount>(
- GetElement()->GetDocument()))));
+ std::make_unique<IncrementLoadEventDelayCount>(
+ GetElement()->GetDocument())));
}
LayoutImageResource* ImageLoader::GetLayoutImageResource() {
diff --git a/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc b/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
index 7db2d3b0d25..2da7358e7f3 100644
--- a/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
+++ b/chromium/third_party/blink/renderer/core/loader/interactive_detector.cc
@@ -243,7 +243,7 @@ void InteractiveDetector::HandleForInputDelay(
delay = processing_start - event_platform_timestamp;
event_timestamp = event_platform_timestamp;
}
-
+ pending_pointerdown_delay_ = base::TimeDelta();
pending_pointerdown_timestamp_ = base::TimeTicks();
bool interactive_timing_metrics_changed = false;
@@ -572,27 +572,23 @@ void InteractiveDetector::OnTimeToInteractiveDetected() {
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
"loading,rail", "InteractiveTime", interactive_time_, "frame",
ToTraceValue(GetSupplementable()->GetFrame()), "args",
- ComputeTimeToInteractiveTraceArgs());
+ [&](perfetto::TracedValue context) {
+ // We log the trace event even if there is user input, but annotate the
+ // event with whether that happened.
+ bool had_user_input_before_interactive =
+ !page_event_times_.first_invalidating_input.is_null() &&
+ page_event_times_.first_invalidating_input < interactive_time_;
+
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("had_user_input_before_interactive",
+ had_user_input_before_interactive);
+ dict.Add("total_blocking_time_ms",
+ ComputeTotalBlockingTime().InMillisecondsF());
+ });
long_tasks_.clear();
}
-std::unique_ptr<TracedValue>
-InteractiveDetector::ComputeTimeToInteractiveTraceArgs() {
- // We log the trace event even if there is user input, but annotate the event
- // with whether that happened.
- bool had_user_input_before_interactive =
- !page_event_times_.first_invalidating_input.is_null() &&
- page_event_times_.first_invalidating_input < interactive_time_;
-
- auto dict = std::make_unique<TracedValue>();
- dict->SetBoolean("had_user_input_before_interactive",
- had_user_input_before_interactive);
- dict->SetDouble("total_blocking_time_ms",
- ComputeTotalBlockingTime().InMillisecondsF());
- return dict;
-}
-
base::TimeDelta InteractiveDetector::ComputeTotalBlockingTime() {
// We follow the same logic as the lighthouse computation in
// https://github.com/GoogleChrome/lighthouse/blob/f150573b5970cc90c8d0c2214f5738df5cde8a31/lighthouse-core/computed/metrics/total-blocking-time.js#L60-L74.
@@ -615,6 +611,7 @@ void InteractiveDetector::ContextDestroyed() {
}
void InteractiveDetector::Trace(Visitor* visitor) const {
+ visitor->Trace(time_to_interactive_timer_);
Supplement<Document>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
@@ -638,46 +635,24 @@ void InteractiveDetector::SetUkmRecorderForTesting(
}
void InteractiveDetector::RecordInputEventTimingUKM(
- const Event& event,
- base::TimeTicks event_timestamp,
- base::TimeTicks processing_start,
- base::TimeTicks processing_end) {
- DCHECK(event.isTrusted());
-
- // This only happens sometimes on tests unrelated to InteractiveDetector. It
- // is safe to ignore events that are not properly initialized.
- if (event_timestamp.is_null())
- return;
-
- // We can't report a pointerDown until the pointerUp, in case it turns into a
- // scroll.
- if (event.type() == event_type_names::kPointerdown) {
- pending_pointerdown_processing_time_ = processing_end - processing_start;
- return;
- }
-
- base::TimeDelta input_delay;
- base::TimeDelta processing_time;
- if (event.type() == event_type_names::kPointerup) {
- // PointerUp by itself is not considered a significant input.
- if (!pending_pointerdown_processing_time_)
- return;
-
- input_delay = pending_pointerdown_delay_;
- processing_time = pending_pointerdown_processing_time_.value();
- } else {
- processing_time = processing_end - processing_start;
- input_delay = processing_start - event_timestamp;
- }
- pending_pointerdown_delay_ = base::TimeDelta();
- pending_pointerdown_processing_time_ = base::nullopt;
-
- // Record InputDelay and Input Event Processing Time UKM.
+ base::TimeDelta input_delay,
+ base::TimeDelta processing_time,
+ base::TimeDelta time_to_next_paint,
+ WTF::AtomicString event_type) {
ukm::SourceId source_id = GetSupplementable()->UkmSourceID();
+
DCHECK_NE(source_id, ukm::kInvalidSourceId);
+ static const WTF::HashMap<WTF::AtomicString, blink::InputEventType>&
+ event_type_to_enum = {{"mousedown", blink::InputEventType::kMousedown},
+ {"click", blink::InputEventType::kClick},
+ {"keydown", blink::InputEventType::kKeydown},
+ {"pointerup", blink::InputEventType::kPointerup}};
ukm::builders::InputEvent(source_id)
+ .SetEventType(static_cast<int>(event_type_to_enum.at(event_type)))
.SetInteractiveTiming_InputDelay(input_delay.InMilliseconds())
.SetInteractiveTiming_ProcessingTime(processing_time.InMilliseconds())
+ .SetInteractiveTiming_ProcessingFinishedToNextPaint(
+ time_to_next_paint.InMilliseconds())
.Record(GetUkmRecorder());
if (!page_event_times_.first_input_processing_time) {
diff --git a/chromium/third_party/blink/renderer/core/loader/interactive_detector.h b/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
index c465a86bbef..020be108878 100644
--- a/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
+++ b/chromium/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -33,6 +33,15 @@ namespace blink {
class Document;
class Event;
+// This enum is for EventType UKM and existing values should not be removed or
+// modified.
+enum class InputEventType {
+ kMousedown = 0,
+ kClick = 1,
+ kKeydown = 2,
+ kPointerup = 3
+};
+
// Detects when a page reaches First Idle and Time to Interactive. See
// https://goo.gl/SYt55W for detailed description and motivation of First Idle
// and Time to Interactive.
@@ -130,10 +139,10 @@ class CORE_EXPORT InteractiveDetector
void SetUkmRecorderForTesting(ukm::UkmRecorder* test_ukm_recorder);
- void RecordInputEventTimingUKM(const Event& event,
- base::TimeTicks event_timestamp,
- base::TimeTicks processing_start,
- base::TimeTicks processing_end);
+ void RecordInputEventTimingUKM(base::TimeDelta input_delay,
+ base::TimeDelta processing_time,
+ base::TimeDelta time_to_next_paint,
+ WTF::AtomicString event_type);
void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay,
base::TimeTicks first_scroll_timestamp);
@@ -201,13 +210,12 @@ class CORE_EXPORT InteractiveDetector
void UpdateNetworkQuietState(double request_count,
base::Optional<base::TimeTicks> current_time);
- TaskRunnerTimer<InteractiveDetector> time_to_interactive_timer_;
+ HeapTaskRunnerTimer<InteractiveDetector> time_to_interactive_timer_;
base::TimeTicks time_to_interactive_timer_fire_time_;
void StartOrPostponeCITimer(base::TimeTicks timer_fire_time);
void TimeToInteractiveTimerFired(TimerBase*);
void CheckTimeToInteractiveReached();
void OnTimeToInteractiveDetected();
- std::unique_ptr<TracedValue> ComputeTimeToInteractiveTraceArgs();
base::TimeDelta ComputeTotalBlockingTime();
Vector<VisibilityChangeEvent> visibility_change_events_;
@@ -228,10 +236,6 @@ class CORE_EXPORT InteractiveDetector
void OnLongTaskDetected(base::TimeTicks start_time,
base::TimeTicks end_time) override;
- // The duration of event handlers processing the event for the previous
- // pointer down.
- base::Optional<base::TimeDelta> pending_pointerdown_processing_time_;
-
// The duration between the hardware timestamp and when we received the event
// for the previous pointer down. Only non-zero if we've received a pointer
// down event, and haven't yet reported the first input delay.
diff --git a/chromium/third_party/blink/renderer/core/loader/interactive_detector_test.cc b/chromium/third_party/blink/renderer/core/loader/interactive_detector_test.cc
index 99beb9e3b2e..62a6f5b074e 100644
--- a/chromium/third_party/blink/renderer/core/loader/interactive_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/interactive_detector_test.cc
@@ -567,34 +567,6 @@ TEST_F(InteractiveDetectorTest, LongTaskAfterTTIDoesNothing) {
EXPECT_EQ(GetInteractiveTime(), long_task_1_end_time);
}
-TEST_F(InteractiveDetectorTest, RecordInputDelayUKM) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(20);
- base::TimeDelta processing_time = base::TimeDelta::FromMilliseconds(10);
- Event event;
- event.SetTrusted(true);
- event.SetType(event_type_names::kClick);
- base::TimeTicks processing_start = Now() + delay;
- base::TimeTicks event_platform_timestamp = Now();
- base::TimeTicks processing_end = processing_start + processing_time;
-
- ukm::TestAutoSetUkmRecorder test_ukm_recorder;
- GetDetector()->SetUkmRecorderForTesting(&test_ukm_recorder);
- GetDetector()->RecordInputEventTimingUKM(event, event_platform_timestamp,
- processing_start, processing_end);
- auto entries = test_ukm_recorder.GetEntriesByName(InputEvent::kEntryName);
- EXPECT_EQ(1ul, entries.size());
- auto* entry = entries[0];
- test_ukm_recorder.ExpectEntryMetric(
- entry, InputEvent::kInteractiveTiming_InputDelayName,
- delay.InMilliseconds());
- test_ukm_recorder.ExpectEntryMetric(
- entry, InputEvent::kInteractiveTiming_ProcessingTimeName,
- processing_time.InMilliseconds());
- EXPECT_EQ(
- GetDetector()->GetFirstInputProcessingTime().value().InMilliseconds(),
- processing_time.InMilliseconds());
-}
-
// In tests for Total Blocking Time (TBT) we call SetTimeToInteractive() instead
// of allowing TimeToInteractive to occur because the computation is gated
// behind tracing being enabled, which means that they won't run by default. In
diff --git a/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.cc b/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.cc
index db0a913e6da..6312cb3071b 100644
--- a/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.cc
+++ b/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.cc
@@ -96,7 +96,7 @@ void LazyImageHelper::StopMonitoring(Element* element) {
// static
LazyImageHelper::Eligibility
LazyImageHelper::DetermineEligibilityAndTrackVisibilityMetrics(
- const LocalFrame& frame,
+ LocalFrame& frame,
HTMLImageElement* html_image,
const KURL& url) {
if (!url.ProtocolIsInHTTPFamily())
diff --git a/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.h b/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.h
index 3eef6ae3110..68c6cf74223 100644
--- a/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.h
+++ b/chromium/third_party/blink/renderer/core/loader/lazy_image_helper.h
@@ -28,7 +28,7 @@ class LazyImageHelper final {
static void StopMonitoring(Element* element);
static Eligibility DetermineEligibilityAndTrackVisibilityMetrics(
- const LocalFrame& frame,
+ LocalFrame& frame,
HTMLImageElement* html_image,
const KURL& url);
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader.cc b/chromium/third_party/blink/renderer/core/loader/link_loader.cc
index e60fbdab658..36024db3b5c 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader.cc
@@ -39,7 +39,7 @@
#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
#include "third_party/blink/renderer/core/loader/link_loader_client.h"
#include "third_party/blink/renderer/core/loader/preload_helper.h"
-#include "third_party/blink/renderer/core/loader/private/prerender_handle.h"
+#include "third_party/blink/renderer/core/loader/prerender_handle.h"
#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
@@ -149,22 +149,6 @@ void LinkLoader::NotifyModuleLoadFinished(ModuleScript* module) {
client_->LinkLoaded();
}
-void LinkLoader::DidStartPrerender() {
- client_->DidStartLinkPrerender();
-}
-
-void LinkLoader::DidStopPrerender() {
- client_->DidStopLinkPrerender();
-}
-
-void LinkLoader::DidSendLoadForPrerender() {
- client_->DidSendLoadForLinkPrerender();
-}
-
-void LinkLoader::DidSendDOMContentLoadedForPrerender() {
- client_->DidSendDOMContentLoadedForLinkPrerender();
-}
-
Resource* LinkLoader::GetResourceForTesting() {
return finish_observer_ ? finish_observer_->GetResource() : nullptr;
}
@@ -201,18 +185,20 @@ bool LinkLoader::LoadLink(const LinkLoadParameters& params,
if (prerender_rel_type) {
// The previous prerender should already be aborted by Abort().
DCHECK(!prerender_);
- prerender_ = PrerenderHandle::Create(document, this, params.href,
- *prerender_rel_type);
+ prerender_ =
+ PrerenderHandle::Create(document, params.href, *prerender_rel_type);
}
return true;
}
-void LinkLoader::LoadStylesheet(const LinkLoadParameters& params,
- const AtomicString& local_name,
- const WTF::TextEncoding& charset,
- FetchParameters::DeferOption defer_option,
- Document& document,
- ResourceClient* link_client) {
+void LinkLoader::LoadStylesheet(
+ const LinkLoadParameters& params,
+ const AtomicString& local_name,
+ const WTF::TextEncoding& charset,
+ FetchParameters::DeferOption defer_option,
+ Document& document,
+ ResourceClient* link_client,
+ RenderBlockingBehavior render_blocking_behavior) {
ExecutionContext* context = document.GetExecutionContext();
ResourceRequest resource_request(context->CompleteURL(params.href));
resource_request.SetReferrerPolicy(params.referrer_policy);
@@ -225,11 +211,11 @@ void LinkLoader::LoadStylesheet(const LinkLoadParameters& params,
ResourceLoaderOptions options(context->GetCurrentWorld());
options.initiator_info.name = local_name;
+
FetchParameters link_fetch_params(std::move(resource_request), options);
link_fetch_params.SetCharset(charset);
-
link_fetch_params.SetDefer(defer_option);
-
+ link_fetch_params.SetRenderBlockingBehavior(render_blocking_behavior);
link_fetch_params.SetContentSecurityPolicyNonce(params.nonce);
CrossOriginAttributeValue cross_origin = params.cross_origin;
@@ -269,7 +255,6 @@ void LinkLoader::Trace(Visitor* visitor) const {
visitor->Trace(client_);
visitor->Trace(prerender_);
SingleModuleClient::Trace(visitor);
- PrerenderClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader.h b/chromium/third_party/blink/renderer/core/loader/link_loader.h
index 5b0fbaff703..f7a9ee0193e 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader.h
@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
-#include "third_party/blink/renderer/core/loader/private/prerender_client.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
@@ -48,18 +47,11 @@ class ResourceClient;
// The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and
// prerender.
-class CORE_EXPORT LinkLoader final : public SingleModuleClient,
- public PrerenderClient {
+class CORE_EXPORT LinkLoader final : public SingleModuleClient {
public:
LinkLoader(LinkLoaderClient*, scoped_refptr<base::SingleThreadTaskRunner>);
~LinkLoader() override;
- // from PrerenderClient
- void DidStartPrerender() override;
- void DidStopPrerender() override;
- void DidSendLoadForPrerender() override;
- void DidSendDOMContentLoadedForPrerender() override;
-
void Abort();
bool LoadLink(const LinkLoadParameters&, Document&);
void LoadStylesheet(const LinkLoadParameters&,
@@ -67,7 +59,8 @@ class CORE_EXPORT LinkLoader final : public SingleModuleClient,
const WTF::TextEncoding&,
FetchParameters::DeferOption,
Document&,
- ResourceClient*);
+ ResourceClient*,
+ RenderBlockingBehavior);
Resource* GetResourceForTesting();
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader_client.h b/chromium/third_party/blink/renderer/core/loader/link_loader_client.h
index 7a1b0ac66fd..d6cca52861d 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader_client.h
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader_client.h
@@ -49,10 +49,6 @@ class CORE_EXPORT LinkLoaderClient : public GarbageCollectedMixin {
virtual void LinkLoadingErrored() = 0;
// There is no notification for cancellation.
- virtual void DidStartLinkPrerender() = 0;
- virtual void DidStopLinkPrerender() = 0;
- virtual void DidSendLoadForLinkPrerender() = 0;
- virtual void DidSendDOMContentLoadedForLinkPrerender() = 0;
virtual bool IsLinkCreatedByParser() = 0;
virtual scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
index 2ce71732d16..a335cb82936 100644
--- a/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -52,10 +52,6 @@ class MockLinkLoaderClient final
void LinkLoaded() override {}
void LinkLoadingErrored() override {}
- void DidStartLinkPrerender() override {}
- void DidStopLinkPrerender() override {}
- void DidSendLoadForLinkPrerender() override {}
- void DidSendDOMContentLoadedForLinkPrerender() override {}
scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override {
return Thread::Current()->GetTaskRunner();
@@ -381,9 +377,11 @@ TEST_P(LinkLoaderPreloadNonceTest, Preload) {
dummy_page_holder_->GetFrame()
.DomWindow()
->GetContentSecurityPolicy()
- ->DidReceiveHeader(test_case.content_security_policy,
- network::mojom::ContentSecurityPolicyType::kEnforce,
- network::mojom::ContentSecurityPolicySource::kHTTP);
+ ->DidReceiveHeader(
+ test_case.content_security_policy,
+ *(dummy_page_holder_->GetFrame().DomWindow()->GetSecurityOrigin()),
+ network::mojom::ContentSecurityPolicyType::kEnforce,
+ network::mojom::ContentSecurityPolicySource::kHTTP);
LinkLoadParameters params(
LinkRelAttribute("preload"), kCrossOriginAttributeNotSet, String(),
"script", String(), test_case.nonce, String(), String(),
diff --git a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
index 842a216e701..95fd4e70338 100644
--- a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
+++ b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -28,12 +29,18 @@ LoaderFactoryForFrame::LoaderFactoryForFrame(DocumentLoader& document_loader,
: document_loader_(document_loader),
window_(window),
prefetched_signed_exchange_manager_(
- document_loader.GetPrefetchedSignedExchangeManager()) {}
+ document_loader.GetPrefetchedSignedExchangeManager()),
+ keep_alive_handle_factory_(&window) {
+ window.GetFrame()->GetLocalFrameHostRemote().GetKeepAliveHandleFactory(
+ keep_alive_handle_factory_.BindNewPipeAndPassReceiver(
+ window.GetTaskRunner(TaskType::kNetworking)));
+}
void LoaderFactoryForFrame::Trace(Visitor* visitor) const {
visitor->Trace(document_loader_);
visitor->Trace(window_);
visitor->Trace(prefetched_signed_exchange_manager_);
+ visitor->Trace(keep_alive_handle_factory_);
LoaderFactory::Trace(visitor);
}
@@ -41,7 +48,8 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForFrame::CreateURLLoader(
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
WrappedResourceRequest webreq(request);
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
@@ -89,16 +97,25 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForFrame::CreateURLLoader(
return Platform::Current()
->WrapURLLoaderFactory(std::move(url_loader_factory))
->CreateURLLoader(webreq, CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ back_forward_cache_loader_helper);
}
if (document_loader_->GetServiceWorkerNetworkProvider()) {
+ mojo::PendingRemote<mojom::blink::KeepAliveHandle> pending_remote;
+ mojo::PendingReceiver<mojom::blink::KeepAliveHandle> pending_receiver =
+ pending_remote.InitWithNewPipeAndPassReceiver();
auto loader =
document_loader_->GetServiceWorkerNetworkProvider()->CreateURLLoader(
webreq, CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
- if (loader)
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ std::move(pending_remote), back_forward_cache_loader_helper);
+ if (loader) {
+ IssueKeepAliveHandleIfRequested(request, frame->GetLocalFrameHostRemote(),
+ std::move(pending_receiver));
return loader;
+ }
}
if (prefetched_signed_exchange_manager_) {
@@ -107,9 +124,15 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForFrame::CreateURLLoader(
if (loader)
return loader;
}
+
+ mojo::PendingRemote<mojom::blink::KeepAliveHandle> pending_remote;
+ IssueKeepAliveHandleIfRequested(
+ request, frame->GetLocalFrameHostRemote(),
+ pending_remote.InitWithNewPipeAndPassReceiver());
return frame->GetURLLoaderFactory()->CreateURLLoader(
webreq, CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ std::move(pending_remote), back_forward_cache_loader_helper);
}
std::unique_ptr<WebCodeCacheLoader>
@@ -123,4 +146,22 @@ LoaderFactoryForFrame::CreateTaskRunnerHandle(
return scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
std::move(task_runner));
}
+
+void LoaderFactoryForFrame::IssueKeepAliveHandleIfRequested(
+ const ResourceRequest& request,
+ mojom::blink::LocalFrameHost& local_frame_host,
+ mojo::PendingReceiver<mojom::blink::KeepAliveHandle> pending_receiver) {
+ DCHECK(pending_receiver);
+ if (request.GetKeepalive() && keep_alive_handle_factory_.is_bound()) {
+ keep_alive_handle_factory_->IssueKeepAliveHandle(
+ std::move(pending_receiver));
+ }
+
+ if (!keep_alive_handle_factory_.is_bound()) {
+ // TODO(crbug.com/1188074): Remove this CHECK once the investigation is
+ // done.
+ CHECK(window_->IsContextDestroyed());
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.h b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.h
index c90dab88db9..0212df7bde8 100644
--- a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.h
+++ b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_frame.h
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -27,7 +28,8 @@ class LoaderFactoryForFrame final : public ResourceFetcher::LoaderFactory {
const ResourceRequest&,
const ResourceLoaderOptions&,
scoped_refptr<base::SingleThreadTaskRunner>,
- scoped_refptr<base::SingleThreadTaskRunner>) override;
+ scoped_refptr<base::SingleThreadTaskRunner>,
+ WebBackForwardCacheLoaderHelper) override;
std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override;
std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
@@ -35,10 +37,17 @@ class LoaderFactoryForFrame final : public ResourceFetcher::LoaderFactory {
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
private:
+ void IssueKeepAliveHandleIfRequested(
+ const ResourceRequest& request,
+ mojom::blink::LocalFrameHost& local_frame_host,
+ mojo::PendingReceiver<mojom::blink::KeepAliveHandle> pending_receiver);
+
const Member<DocumentLoader> document_loader_;
const Member<LocalDOMWindow> window_;
const Member<PrefetchedSignedExchangeManager>
prefetched_signed_exchange_manager_;
+ HeapMojoRemote<blink::mojom::blink::KeepAliveHandleFactory>
+ keep_alive_handle_factory_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.cc b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.cc
index a73f047fec3..a94da714c08 100644
--- a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.cc
@@ -9,6 +9,8 @@
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_worker_fetch_context.h"
#include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
@@ -28,7 +30,8 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForWorker::CreateURLLoader(
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
WrappedResourceRequest wrapped(request);
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
@@ -50,11 +53,16 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForWorker::CreateURLLoader(
request.Url(), url_loader_factory.InitWithNewPipeAndPassReceiver());
}
+ // KeepAlive is not yet supported in web workers.
+ mojo::PendingRemote<mojom::blink::KeepAliveHandle> keep_alive_handle =
+ mojo::NullRemote();
+
if (url_loader_factory) {
return web_context_->WrapURLLoaderFactory(std::move(url_loader_factory))
- ->CreateURLLoader(wrapped,
- CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
+ ->CreateURLLoader(
+ wrapped, CreateTaskRunnerHandle(freezable_task_runner),
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ std::move(keep_alive_handle), back_forward_cache_loader_helper);
}
// If |global_scope_| is a service worker, use |script_loader_factory_| for
@@ -75,7 +83,8 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForWorker::CreateURLLoader(
if (web_context_->GetScriptLoaderFactory()) {
return web_context_->GetScriptLoaderFactory()->CreateURLLoader(
wrapped, CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ std::move(keep_alive_handle), back_forward_cache_loader_helper);
}
}
} else {
@@ -84,7 +93,8 @@ std::unique_ptr<WebURLLoader> LoaderFactoryForWorker::CreateURLLoader(
return web_context_->GetURLLoaderFactory()->CreateURLLoader(
wrapped, CreateTaskRunnerHandle(freezable_task_runner),
- CreateTaskRunnerHandle(unfreezable_task_runner));
+ CreateTaskRunnerHandle(unfreezable_task_runner),
+ std::move(keep_alive_handle), back_forward_cache_loader_helper);
}
std::unique_ptr<WebCodeCacheLoader>
diff --git a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.h b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.h
index 6ca3c194670..f34cfbcdfe9 100644
--- a/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.h
+++ b/chromium/third_party/blink/renderer/core/loader/loader_factory_for_worker.h
@@ -32,8 +32,8 @@ class LoaderFactoryForWorker : public ResourceFetcher::LoaderFactory {
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner)
- override;
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper) override;
std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override;
private:
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index 7cc8cf037e6..7a7767a1770 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -31,10 +31,12 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/optional.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/security_context/insecure_request_policy.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
@@ -47,7 +49,6 @@
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/address_space_feature.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_fetch_context.h"
#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
@@ -58,6 +59,7 @@
#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/loader/fetch/resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/loader/mixed_content.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -137,6 +139,8 @@ const char* RequestContextName(mojom::blink::RequestContextType context) {
return "stylesheet";
case mojom::blink::RequestContextType::SUBRESOURCE:
return "resource";
+ case mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE:
+ return "webbundle";
case mojom::blink::RequestContextType::TRACK:
return "Text Track";
case mojom::blink::RequestContextType::UNSPECIFIED:
@@ -192,7 +196,7 @@ bool IsWebSocketAllowedInWorker(const WorkerFetchContext& fetch_context,
const KURL& url) {
fetch_context.CountUsage(WebFeature::kMixedContentPresent);
fetch_context.CountUsage(WebFeature::kMixedContentWebSocket);
- if (const ContentSecurityPolicy* policy =
+ if (ContentSecurityPolicy* policy =
fetch_context.GetContentSecurityPolicy()) {
policy->ReportMixedContent(url,
ResourceRequest::RedirectStatus::kNoRedirect);
@@ -247,6 +251,12 @@ void CreateMixedContentIssue(
} // namespace
+static bool IsInsecureUrl(const KURL& url) {
+ // |url| is mixed content if it is not a potentially trustworthy URL.
+ // See https://w3c.github.io/webappsec-mixed-content/#should-block-response
+ return !network::IsUrlPotentiallyTrustworthy(url);
+}
+
static void MeasureStricterVersionOfIsMixedContent(Frame& frame,
const KURL& url,
const LocalFrame* source) {
@@ -262,8 +272,9 @@ static void MeasureStricterVersionOfIsMixedContent(Frame& frame,
source->GetDocument(),
WebFeature::kMixedContentInNonHTTPSFrameThatRestrictsMixedContent);
}
- } else if (!SecurityOrigin::IsSecure(url) &&
- SchemeRegistry::ShouldTreatURLSchemeAsSecure(origin->Protocol())) {
+ } else if (network::IsUrlPotentiallyTrustworthy(url) &&
+ base::Contains(url::GetSecureSchemes(),
+ origin->Protocol().Ascii())) {
UseCounter::Count(
source->GetDocument(),
WebFeature::kMixedContentInSecureFrameThatDoesNotRestrictMixedContent);
@@ -274,19 +285,6 @@ bool RequestIsSubframeSubresource(Frame* frame) {
return frame && frame != frame->Tree().Top();
}
-static bool IsInsecureUrl(const KURL& url) {
- // |url| is mixed content if its origin is not potentially trustworthy nor
- // secure. We do a quick check against `SecurityOrigin::IsSecure` to catch
- // things like `about:blank`, which cannot be sanely passed into
- // `SecurityOrigin::Create` (as their origin depends on their context).
- // blob: and filesystem: URLs never hit the network, and access is restricted
- // to same-origin contexts, so they are not blocked either.
- bool is_allowed = url.ProtocolIs("blob") || url.ProtocolIs("filesystem") ||
- SecurityOrigin::IsSecure(url) ||
- SecurityOrigin::Create(url)->IsPotentiallyTrustworthy();
- return !is_allowed;
-}
-
// static
bool MixedContentChecker::IsMixedContent(const SecurityOrigin* security_origin,
const KURL& url) {
@@ -374,10 +372,10 @@ void MixedContentChecker::Count(
// Roll blockable content up into a single counter, count unblocked types
// individually so we can determine when they can be safely moved to the
// blockable category:
- WebMixedContentContextType context_type =
- WebMixedContent::ContextTypeFromRequestContext(
+ mojom::blink::MixedContentContextType context_type =
+ MixedContent::ContextTypeFromRequestContext(
request_context, DecideCheckModeForPlugin(frame->GetSettings()));
- if (context_type == WebMixedContentContextType::kBlockable) {
+ if (context_type == mojom::blink::MixedContentContextType::kBlockable) {
UseCounter::Count(source->GetDocument(),
WebFeature::kMixedContentBlockable);
return;
@@ -472,12 +470,12 @@ bool MixedContentChecker::ShouldBlockFetch(
mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone ||
settings->GetStrictMixedContentChecking();
- WebMixedContentContextType context_type =
- WebMixedContent::ContextTypeFromRequestContext(
+ mojom::blink::MixedContentContextType context_type =
+ MixedContent::ContextTypeFromRequestContext(
request_context, DecideCheckModeForPlugin(settings));
switch (context_type) {
- case WebMixedContentContextType::kOptionallyBlockable:
+ case mojom::blink::MixedContentContextType::kOptionallyBlockable:
allowed = !strict_mode;
if (allowed) {
if (content_settings_client)
@@ -486,7 +484,7 @@ bool MixedContentChecker::ShouldBlockFetch(
}
break;
- case WebMixedContentContextType::kBlockable: {
+ case mojom::blink::MixedContentContextType::kBlockable: {
// Strictly block subresources that are mixed with respect to their
// subframes, unless all insecure content is allowed. This is to avoid the
// following situation: https://a.com embeds https://b.com, which loads a
@@ -524,12 +522,12 @@ bool MixedContentChecker::ShouldBlockFetch(
break;
}
- case WebMixedContentContextType::kShouldBeBlockable:
+ case mojom::blink::MixedContentContextType::kShouldBeBlockable:
allowed = !strict_mode;
if (allowed)
local_frame_host.DidDisplayInsecureContent();
break;
- case WebMixedContentContextType::kNotMixedContent:
+ case mojom::blink::MixedContentContextType::kNotMixedContent:
NOTREACHED();
break;
};
@@ -764,9 +762,9 @@ bool MixedContentChecker::ShouldAutoupgrade(
if (!base::FeatureList::IsEnabled(
blink::features::kMixedContentAutoupgrade) ||
context_https_state == HttpsState::kNone ||
- WebMixedContent::ContextTypeFromRequestContext(
- type, WebMixedContent::CheckModeForPlugin::kStrict) !=
- WebMixedContentContextType::kOptionallyBlockable) {
+ MixedContent::ContextTypeFromRequestContext(
+ type, MixedContent::CheckModeForPlugin::kStrict) !=
+ mojom::blink::MixedContentContextType::kOptionallyBlockable) {
return false;
}
if (settings_client && !settings_client->ShouldAutoupgradeMixedContent()) {
@@ -776,40 +774,21 @@ bool MixedContentChecker::ShouldAutoupgrade(
return true;
}
-void MixedContentChecker::CheckMixedPrivatePublic(
- LocalFrame* frame,
- const ResourceResponse& response) {
- if (!frame)
- return;
-
- LocalDOMWindow* window = frame->DomWindow();
- base::Optional<WebFeature> feature =
- AddressSpaceFeature(window->AddressSpace(), window->IsSecureContext(),
- response.AddressSpace());
- if (!feature.has_value()) {
- return;
- }
-
- // This WebFeature encompasses all private network requests.
- UseCounter::Count(window,
- WebFeature::kMixedContentPrivateHostnameInPublicHostname);
- UseCounter::Count(window, *feature);
-}
-
void MixedContentChecker::HandleCertificateError(
const ResourceResponse& response,
mojom::blink::RequestContextType request_context,
- WebMixedContent::CheckModeForPlugin check_mode_for_plugin,
+ MixedContent::CheckModeForPlugin check_mode_for_plugin,
mojom::blink::ContentSecurityNotifier& notifier) {
- WebMixedContentContextType context_type =
- WebMixedContent::ContextTypeFromRequestContext(request_context,
- check_mode_for_plugin);
- if (context_type == WebMixedContentContextType::kBlockable) {
+ mojom::blink::MixedContentContextType context_type =
+ MixedContent::ContextTypeFromRequestContext(request_context,
+ check_mode_for_plugin);
+ if (context_type == mojom::blink::MixedContentContextType::kBlockable) {
notifier.NotifyContentWithCertificateErrorsRan();
} else {
// contextTypeFromRequestContext() never returns NotMixedContent (it
// computes the type of mixed content, given that the content is mixed).
- DCHECK_NE(context_type, WebMixedContentContextType::kNotMixedContent);
+ DCHECK_NE(context_type,
+ mojom::blink::MixedContentContextType::kNotMixedContent);
notifier.NotifyContentWithCertificateErrorsDisplayed();
}
}
@@ -863,13 +842,13 @@ ConsoleMessage* MixedContentChecker::CreateConsoleMessageAboutFetchAutoupgrade(
mojom::ConsoleMessageLevel::kWarning, message);
}
-WebMixedContentContextType MixedContentChecker::ContextTypeForInspector(
- LocalFrame* frame,
- const ResourceRequest& request) {
+mojom::blink::MixedContentContextType
+MixedContentChecker::ContextTypeForInspector(LocalFrame* frame,
+ const ResourceRequest& request) {
Frame* mixed_frame = InWhichFrameIsContentMixed(frame, request.Url());
if (!mixed_frame)
- return WebMixedContentContextType::kNotMixedContent;
- return WebMixedContent::ContextTypeFromRequestContext(
+ return mojom::blink::MixedContentContextType::kNotMixedContent;
+ return MixedContent::ContextTypeFromRequestContext(
request.GetRequestContext(),
DecideCheckModeForPlugin(mixed_frame->GetSettings()));
}
@@ -964,23 +943,23 @@ void MixedContentChecker::UpgradeInsecureRequest(
execution_context_for_logging,
WebFeature::kUpgradeInsecureRequestsUpgradedRequestUnknown);
} else {
- WebMixedContentContextType content_type =
- WebMixedContent::ContextTypeFromRequestContext(
- context, WebMixedContent::CheckModeForPlugin::kLax);
+ mojom::blink::MixedContentContextType content_type =
+ MixedContent::ContextTypeFromRequestContext(
+ context, MixedContent::CheckModeForPlugin::kLax);
switch (content_type) {
- case WebMixedContentContextType::kOptionallyBlockable:
+ case mojom::blink::MixedContentContextType::kOptionallyBlockable:
UseCounter::Count(
execution_context_for_logging,
WebFeature::
kUpgradeInsecureRequestsUpgradedRequestOptionallyBlockable);
break;
- case WebMixedContentContextType::kBlockable:
- case WebMixedContentContextType::kShouldBeBlockable:
+ case mojom::blink::MixedContentContextType::kBlockable:
+ case mojom::blink::MixedContentContextType::kShouldBeBlockable:
UseCounter::Count(
execution_context_for_logging,
WebFeature::kUpgradeInsecureRequestsUpgradedRequestBlockable);
break;
- case WebMixedContentContextType::kNotMixedContent:
+ case mojom::blink::MixedContentContextType::kNotMixedContent:
NOTREACHED();
}
}
@@ -993,11 +972,11 @@ void MixedContentChecker::UpgradeInsecureRequest(
}
// static
-WebMixedContent::CheckModeForPlugin
-MixedContentChecker::DecideCheckModeForPlugin(Settings* settings) {
+MixedContent::CheckModeForPlugin MixedContentChecker::DecideCheckModeForPlugin(
+ Settings* settings) {
if (settings && settings->GetStrictMixedContentCheckingForPlugin())
- return WebMixedContent::CheckModeForPlugin::kStrict;
- return WebMixedContent::CheckModeForPlugin::kLax;
+ return MixedContent::CheckModeForPlugin::kStrict;
+ return MixedContent::CheckModeForPlugin::kLax;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
index 3dfca3d4d52..f1de201aa0e 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker.h
@@ -35,14 +35,14 @@
#include "base/macros.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/loader/content_security_notifier.mojom-blink-forward.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/mixed_content.h"
#include "third_party/blink/renderer/platform/weborigin/reporting_disposition.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -109,17 +109,14 @@ class CORE_EXPORT MixedContentChecker final {
WebContentSettingsClient* settings_client,
const KURL& url);
- static void CheckMixedPrivatePublic(LocalFrame*,
- const ResourceResponse& response);
-
- static WebMixedContentContextType ContextTypeForInspector(
+ static mojom::blink::MixedContentContextType ContextTypeForInspector(
LocalFrame*,
const ResourceRequest&);
static void HandleCertificateError(
const ResourceResponse&,
mojom::blink::RequestContextType,
- WebMixedContent::CheckModeForPlugin,
+ MixedContent::CheckModeForPlugin,
mojom::blink::ContentSecurityNotifier& notifier);
// Receive information about mixed content found externally.
@@ -148,8 +145,7 @@ class CORE_EXPORT MixedContentChecker final {
mojom::RequestContextFrameType,
WebContentSettingsClient* settings_client);
- static WebMixedContent::CheckModeForPlugin DecideCheckModeForPlugin(
- Settings*);
+ static MixedContent::CheckModeForPlugin DecideCheckModeForPlugin(Settings*);
private:
FRIEND_TEST_ALL_PREFIXES(MixedContentCheckerTest, HandleCertificateError);
diff --git a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
index 495d1776fe6..2307304274c 100644
--- a/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
@@ -10,9 +10,8 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.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/loader/empty_clients.h"
@@ -20,6 +19,7 @@
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/mixed_content.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -45,10 +45,7 @@ TEST(MixedContentCheckerTest, IsMixedContent) {
{"https://example.com/foo", "wss://example.com/foo", false},
{"https://example.com/foo", "data:text/html,<p>Hi!</p>", false},
{"https://example.com/foo", "blob:https://example.com/foo", false},
- {"https://example.com/foo", "blob:http://example.com/foo", false},
- {"https://example.com/foo", "blob:null/foo", false},
{"https://example.com/foo", "filesystem:https://example.com/foo", false},
- {"https://example.com/foo", "filesystem:http://example.com/foo", false},
{"https://example.com/foo", "http://127.0.0.1/", false},
{"https://example.com/foo", "http://[::1]/", false},
{"https://example.com/foo", "http://a.localhost/", false},
@@ -59,6 +56,10 @@ TEST(MixedContentCheckerTest, IsMixedContent) {
{"https://example.com/foo", "ws://example.com/foo", true},
{"https://example.com/foo", "ws://google.com/foo", true},
{"https://example.com/foo", "http://192.168.1.1/", true},
+ {"https://example.com/foo", "blob:http://example.com/foo", true},
+ {"https://example.com/foo", "blob:null/foo", true},
+ {"https://example.com/foo", "filesystem:http://example.com/foo", true},
+ {"https://example.com/foo", "filesystem:null/foo", true},
};
for (const auto& test : cases) {
@@ -77,31 +78,31 @@ TEST(MixedContentCheckerTest, IsMixedContent) {
TEST(MixedContentCheckerTest, ContextTypeForInspector) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(1, 1));
dummy_page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("http://example.test")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("http://example.test")),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
ResourceRequest not_mixed_content("https://example.test/foo.jpg");
not_mixed_content.SetRequestContext(mojom::blink::RequestContextType::SCRIPT);
- EXPECT_EQ(WebMixedContentContextType::kNotMixedContent,
+ EXPECT_EQ(mojom::blink::MixedContentContextType::kNotMixedContent,
MixedContentChecker::ContextTypeForInspector(
&dummy_page_holder->GetFrame(), not_mixed_content));
dummy_page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("https://example.test")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("https://example.test")),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
- EXPECT_EQ(WebMixedContentContextType::kNotMixedContent,
+ EXPECT_EQ(mojom::blink::MixedContentContextType::kNotMixedContent,
MixedContentChecker::ContextTypeForInspector(
&dummy_page_holder->GetFrame(), not_mixed_content));
ResourceRequest blockable_mixed_content("http://example.test/foo.jpg");
blockable_mixed_content.SetRequestContext(
mojom::blink::RequestContextType::SCRIPT);
- EXPECT_EQ(WebMixedContentContextType::kBlockable,
+ EXPECT_EQ(mojom::blink::MixedContentContextType::kBlockable,
MixedContentChecker::ContextTypeForInspector(
&dummy_page_holder->GetFrame(), blockable_mixed_content));
@@ -109,7 +110,7 @@ TEST(MixedContentCheckerTest, ContextTypeForInspector) {
"http://example.test/foo.jpg");
blockable_mixed_content.SetRequestContext(
mojom::blink::RequestContextType::IMAGE);
- EXPECT_EQ(WebMixedContentContextType::kOptionallyBlockable,
+ EXPECT_EQ(mojom::blink::MixedContentContextType::kOptionallyBlockable,
MixedContentChecker::ContextTypeForInspector(
&dummy_page_holder->GetFrame(), blockable_mixed_content));
}
@@ -132,20 +133,20 @@ TEST(MixedContentCheckerTest, HandleCertificateError) {
EXPECT_CALL(mock_notifier, NotifyContentWithCertificateErrorsRan()).Times(1);
MixedContentChecker::HandleCertificateError(
response1, mojom::blink::RequestContextType::SCRIPT,
- WebMixedContent::CheckModeForPlugin::kLax, *notifier_remote);
+ MixedContent::CheckModeForPlugin::kLax, *notifier_remote);
ResourceResponse response2(displayed_url);
mojom::blink::RequestContextType request_context =
mojom::blink::RequestContextType::IMAGE;
ASSERT_EQ(
- WebMixedContentContextType::kOptionallyBlockable,
- WebMixedContent::ContextTypeFromRequestContext(
+ mojom::blink::MixedContentContextType::kOptionallyBlockable,
+ MixedContent::ContextTypeFromRequestContext(
request_context, MixedContentChecker::DecideCheckModeForPlugin(
dummy_page_holder->GetFrame().GetSettings())));
EXPECT_CALL(mock_notifier, NotifyContentWithCertificateErrorsDisplayed())
.Times(1);
MixedContentChecker::HandleCertificateError(
- response2, request_context, WebMixedContent::CheckModeForPlugin::kLax,
+ response2, request_context, MixedContent::CheckModeForPlugin::kLax,
*notifier_remote);
notifier_remote.FlushForTesting();
@@ -156,8 +157,8 @@ TEST(MixedContentCheckerTest, DetectMixedForm) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(
IntSize(1, 1), nullptr, MakeGarbageCollected<EmptyLocalFrameClient>());
dummy_page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- main_resource_url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), main_resource_url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
@@ -186,8 +187,8 @@ TEST(MixedContentCheckerTest, DetectMixedFavicon) {
auto dummy_page_holder = std::make_unique<DummyPageHolder>(
IntSize(1, 1), nullptr, MakeGarbageCollected<EmptyLocalFrameClient>());
dummy_page_holder->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- main_resource_url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), main_resource_url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
dummy_page_holder->GetFrame().GetSettings()->SetAllowRunningOfInsecureContent(
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
index 860134d9706..c9d624472eb 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
@@ -4,7 +4,11 @@
#include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h"
+#include "third_party/blink/public/mojom/script/script_type.mojom-blink-forward.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
+#include "third_party/blink/renderer/core/script/pending_script.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -12,40 +16,64 @@
namespace blink {
DocumentModuleScriptFetcher::DocumentModuleScriptFetcher(
- util::PassKey<ModuleScriptLoader> pass_key)
+ base::PassKey<ModuleScriptLoader> pass_key)
: ModuleScriptFetcher(pass_key) {}
void DocumentModuleScriptFetcher::Fetch(
FetchParameters& fetch_params,
+ ModuleType expected_module_type,
ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptFetcher::Client* client) {
+ DCHECK_EQ(fetch_params.GetScriptType(), mojom::blink::ScriptType::kModule);
DCHECK(fetch_client_settings_object_fetcher);
DCHECK(!client_);
client_ = client;
-
+ expected_module_type_ = expected_module_type;
+ // Streaming can currently only be triggered from the main thread. This
+ // currently happens only for dynamic imports in worker modules.
+ ScriptResource::StreamingAllowed streaming_allowed =
+ IsMainThread() ? ScriptResource::kAllowStreaming
+ : ScriptResource::kNoStreaming;
ScriptResource::Fetch(fetch_params, fetch_client_settings_object_fetcher,
- this, ScriptResource::kNoStreaming);
+ this, streaming_allowed);
}
void DocumentModuleScriptFetcher::NotifyFinished(Resource* resource) {
ClearResource();
- ScriptResource* script_resource = ToScriptResource(resource);
+ auto* script_resource = To<ScriptResource>(resource);
- HeapVector<Member<ConsoleMessage>> error_messages;
- ModuleScriptCreationParams::ModuleType module_type;
- if (!WasModuleLoadSuccessful(script_resource, &error_messages,
- &module_type)) {
- client_->NotifyFetchFinished(base::nullopt, error_messages);
- return;
+ {
+ HeapVector<Member<ConsoleMessage>> error_messages;
+ if (!WasModuleLoadSuccessful(script_resource, expected_module_type_,
+ &error_messages)) {
+ client_->NotifyFetchFinishedError(error_messages);
+ return;
+ }
}
+ // Check if we can use the script streamer.
+ ScriptStreamer* streamer;
+ ScriptStreamer::NotStreamingReason not_streamed_reason;
+ std::tie(streamer, not_streamed_reason) =
+ ScriptStreamer::TakeFrom(script_resource);
+
+ ScriptStreamer::RecordStreamingHistogram(ScriptSchedulingType::kAsync,
+ streamer, not_streamed_reason);
- ModuleScriptCreationParams params(
- script_resource->GetResponse().CurrentRequestUrl(), module_type,
- script_resource->SourceText(), script_resource->CacheHandler(),
- script_resource->GetResourceRequest().GetCredentialsMode());
- client_->NotifyFetchFinished(params, error_messages);
+ TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
+ "DocumentModuleScriptFetcher::NotifyFinished", this,
+ TRACE_EVENT_FLAG_FLOW_IN, "not_streamed_reason",
+ not_streamed_reason);
+ // TODO(crbug.com/1061857): Pass ScriptStreamer to the client here.
+ const KURL& url = script_resource->GetResponse().CurrentRequestUrl();
+ // Create an external module script where base_url == source_url.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
+ client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
+ /*source_url=*/url, /*base_url=*/url,
+ ScriptSourceLocationType::kExternalFile, expected_module_type_,
+ script_resource->SourceText(), script_resource->CacheHandler(), streamer,
+ not_streamed_reason));
}
void DocumentModuleScriptFetcher::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
index 16be1a4fdc2..8dd12f8bbe0 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h
@@ -19,10 +19,11 @@ class CORE_EXPORT DocumentModuleScriptFetcher final
: public GarbageCollected<DocumentModuleScriptFetcher>,
public ModuleScriptFetcher {
public:
- explicit DocumentModuleScriptFetcher(util::PassKey<ModuleScriptLoader>);
+ explicit DocumentModuleScriptFetcher(base::PassKey<ModuleScriptLoader>);
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ModuleType,
ResourceFetcher*,
ModuleGraphLevel,
Client*) override;
@@ -35,6 +36,7 @@ class CORE_EXPORT DocumentModuleScriptFetcher final
private:
Member<Client> client_;
+ ModuleType expected_module_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
index 8667eba3cc0..8a00638779c 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/workers/installed_scripts_manager.h"
@@ -20,20 +21,23 @@ namespace blink {
InstalledServiceWorkerModuleScriptFetcher::
InstalledServiceWorkerModuleScriptFetcher(
WorkerGlobalScope* global_scope,
- util::PassKey<ModuleScriptLoader> pass_key)
+ base::PassKey<ModuleScriptLoader> pass_key)
: ModuleScriptFetcher(pass_key), global_scope_(global_scope) {
DCHECK(global_scope_->IsServiceWorkerGlobalScope());
}
void InstalledServiceWorkerModuleScriptFetcher::Fetch(
FetchParameters& fetch_params,
+ ModuleType expected_module_type,
ResourceFetcher*,
ModuleGraphLevel level,
ModuleScriptFetcher::Client* client) {
+ DCHECK_EQ(fetch_params.GetScriptType(), mojom::blink::ScriptType::kModule);
DCHECK(global_scope_->IsContextThread());
auto* installed_scripts_manager = global_scope_->GetInstalledScriptsManager();
DCHECK(installed_scripts_manager);
DCHECK(installed_scripts_manager->IsScriptInstalled(fetch_params.Url()));
+ expected_module_type_ = expected_module_type;
std::unique_ptr<InstalledScriptsManager::ScriptData> script_data =
installed_scripts_manager->GetScriptData(fetch_params.Url());
@@ -45,7 +49,7 @@ void InstalledServiceWorkerModuleScriptFetcher::Fetch(
mojom::ConsoleMessageLevel::kError,
"Failed to load the script unexpectedly",
fetch_params.Url().GetString(), nullptr, 0));
- client->NotifyFetchFinished(base::nullopt, error_messages);
+ client->NotifyFetchFinishedError(error_messages);
return;
}
@@ -62,33 +66,27 @@ void InstalledServiceWorkerModuleScriptFetcher::Fetch(
kDoNotSupportReferrerPolicyLegacyKeywords, &response_referrer_policy);
}
- // Construct a ContentSecurityPolicy object to convert
- // ContentSecurityPolicyResponseHeaders to CSPHeaderAndType.
- // TODO(nhiroki): Find an efficient way to do this.
- auto* response_content_security_policy =
- MakeGarbageCollected<ContentSecurityPolicy>();
- response_content_security_policy->DidReceiveHeaders(
- script_data->GetContentSecurityPolicyResponseHeaders());
-
- global_scope_->Initialize(response_url, response_referrer_policy,
- script_data->GetResponseAddressSpace(),
- response_content_security_policy->Headers(),
- script_data->CreateOriginTrialTokens().get(),
- mojom::blink::kAppCacheNoCacheId);
+ global_scope_->Initialize(
+ response_url, response_referrer_policy,
+ script_data->GetResponseAddressSpace(),
+ ContentSecurityPolicy::ParseHeaders(
+ script_data->GetContentSecurityPolicyResponseHeaders()),
+ script_data->CreateOriginTrialTokens().get(),
+ mojom::blink::kAppCacheNoCacheId);
}
- ModuleScriptCreationParams::ModuleType module_type;
-
// TODO(sasebree) De-duplicate similar logic that lives in
// ModuleScriptFetcher::WasModuleLoadSuccessful
- if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
- script_data->GetHttpContentType())) {
- module_type = ModuleScriptCreationParams::ModuleType::kJavaScriptModule;
- } else if (base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
- MIMETypeRegistry::IsJSONMimeType(
- script_data->GetHttpContentType())) {
- module_type = ModuleScriptCreationParams::ModuleType::kJSONModule;
- } else {
+ const bool fetched_javascript_module =
+ expected_module_type_ == ModuleType::kJavaScript &&
+ MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
+ script_data->GetHttpContentType());
+ const bool fetched_json_module =
+ base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
+ expected_module_type_ == ModuleType::kJSON &&
+ MIMETypeRegistry::IsJSONMimeType(script_data->GetHttpContentType());
+
+ if (!fetched_javascript_module && !fetched_json_module) {
// This should never happen.
// If we reach here, we know we received an incompatible mime type from the
// network
@@ -98,16 +96,17 @@ void InstalledServiceWorkerModuleScriptFetcher::Fetch(
mojom::ConsoleMessageLevel::kError,
"Failed to load the script unexpectedly",
fetch_params.Url().GetString(), nullptr, 0));
- client->NotifyFetchFinished(base::nullopt, error_messages);
+ client->NotifyFetchFinishedError(error_messages);
return;
}
- ModuleScriptCreationParams params(
- fetch_params.Url(), module_type,
+ // Create an external module script where base_url == source_url.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
+ client->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
+ /*source_url=*/fetch_params.Url(), /*base_url=*/fetch_params.Url(),
+ ScriptSourceLocationType::kExternalFile, expected_module_type_,
ParkableString(script_data->TakeSourceText().Impl()),
- nullptr /* cache_handler */,
- fetch_params.GetResourceRequest().GetCredentialsMode());
- client->NotifyFetchFinished(params, HeapVector<Member<ConsoleMessage>>());
+ /*cache_handler=*/nullptr));
}
void InstalledServiceWorkerModuleScriptFetcher::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
index 3514259379b..97a0f17c750 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h
@@ -19,10 +19,11 @@ class CORE_EXPORT InstalledServiceWorkerModuleScriptFetcher final
public ModuleScriptFetcher {
public:
InstalledServiceWorkerModuleScriptFetcher(WorkerGlobalScope*,
- util::PassKey<ModuleScriptLoader>);
+ base::PassKey<ModuleScriptLoader>);
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ModuleType,
ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
@@ -35,6 +36,7 @@ class CORE_EXPORT InstalledServiceWorkerModuleScriptFetcher final
}
const Member<WorkerGlobalScope> global_scope_;
+ ModuleType expected_module_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc
new file mode 100644
index 00000000000..df4320c83b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
+
+namespace blink {
+
+String ModuleScriptCreationParams::ModuleTypeToString(
+ const ModuleType module_type) {
+ switch (module_type) {
+ case ModuleType::kJavaScript:
+ return "JavaScript";
+ case ModuleType::kJSON:
+ return "JSON";
+ case ModuleType::kCSS:
+ return "CSS";
+ case ModuleType::kInvalid:
+ NOTREACHED();
+ return "";
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
index 5f16296c974..d31a12d2374 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
@@ -7,6 +7,9 @@
#include "base/optional.h"
#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
+#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
@@ -16,26 +19,43 @@
namespace blink {
+enum class ModuleType { kInvalid, kJavaScript, kJSON, kCSS };
+
// ModuleScriptCreationParams contains parameters for creating ModuleScript.
class ModuleScriptCreationParams {
DISALLOW_NEW();
- enum class ModuleType { kJavaScriptModule, kJSONModule, kCSSModule };
-
public:
ModuleScriptCreationParams(
- const KURL& response_url,
- const ModuleScriptCreationParams::ModuleType module_type,
+ const KURL& source_url,
+ const KURL& base_url,
+ ScriptSourceLocationType source_location_type,
+ const ModuleType module_type,
const ParkableString& source_text,
SingleCachedMetadataHandler* cache_handler,
- network::mojom::CredentialsMode credentials_mode)
- : response_url_(response_url),
+ ScriptStreamer* script_streamer = nullptr,
+ ScriptStreamer::NotStreamingReason not_streaming_reason =
+ ScriptStreamer::NotStreamingReason::kStreamingDisabled)
+ : source_url_(source_url),
+ base_url_(base_url),
+ source_location_type_(source_location_type),
module_type_(module_type),
is_isolated_(false),
source_text_(source_text),
isolated_source_text_(),
cache_handler_(cache_handler),
- credentials_mode_(credentials_mode) {}
+ script_streamer_(script_streamer),
+ not_streaming_reason_(not_streaming_reason) {
+ DCHECK(source_location_type == ScriptSourceLocationType::kExternalFile ||
+ source_location_type == ScriptSourceLocationType::kInline);
+ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
+ if (source_location_type == ScriptSourceLocationType::kExternalFile) {
+ DCHECK_EQ(source_url, base_url);
+ }
+ DCHECK_EQ(
+ !script_streamer,
+ not_streaming_reason != ScriptStreamer::NotStreamingReason::kInvalid);
+ }
~ModuleScriptCreationParams() = default;
@@ -43,17 +63,16 @@ class ModuleScriptCreationParams {
String isolated_source_text =
isolated_source_text_ ? isolated_source_text_.IsolatedCopy()
: GetSourceText().ToString().IsolatedCopy();
-
- return ModuleScriptCreationParams(GetResponseUrl().Copy(), module_type_,
- isolated_source_text,
- GetFetchCredentialsMode());
+ return ModuleScriptCreationParams(SourceURL().Copy(), BaseURL().Copy(),
+ source_location_type_, GetModuleType(),
+ isolated_source_text);
}
- ModuleScriptCreationParams::ModuleType GetModuleType() const {
- return module_type_;
- }
+ ModuleType GetModuleType() const { return module_type_; }
+
+ const KURL& SourceURL() const { return source_url_; }
+ const KURL& BaseURL() const { return base_url_; }
- const KURL& GetResponseUrl() const { return response_url_; }
const ParkableString& GetSourceText() const {
if (is_isolated_) {
source_text_ = ParkableString(isolated_source_text_.ReleaseImpl());
@@ -62,30 +81,58 @@ class ModuleScriptCreationParams {
}
return source_text_;
}
- SingleCachedMetadataHandler* CacheHandler() const { return cache_handler_; }
- network::mojom::CredentialsMode GetFetchCredentialsMode() const {
- return credentials_mode_;
+
+ ScriptSourceLocationType SourceLocationType() const {
+ return source_location_type_;
}
+ ModuleScriptCreationParams CopyWithClearedSourceText() const {
+ return ModuleScriptCreationParams(
+ source_url_, base_url_, source_location_type_, module_type_,
+ ParkableString(), /*cache_handler=*/nullptr,
+ /*script_streamer=*/nullptr,
+ ScriptStreamer::NotStreamingReason::kStreamingDisabled);
+ }
+
+ SingleCachedMetadataHandler* CacheHandler() const { return cache_handler_; }
+
bool IsSafeToSendToAnotherThread() const {
- return response_url_.IsSafeToSendToAnotherThread() && is_isolated_;
+ return source_url_.IsSafeToSendToAnotherThread() &&
+ base_url_.IsSafeToSendToAnotherThread() && is_isolated_;
}
+ ScriptStreamer* GetScriptStreamer() const { return script_streamer_; }
+ ScriptStreamer::NotStreamingReason NotStreamingReason() const {
+ return not_streaming_reason_;
+ }
+
+ static String ModuleTypeToString(const ModuleType module_type);
+
private:
// Creates an isolated copy.
- ModuleScriptCreationParams(
- const KURL& response_url,
- const ModuleScriptCreationParams::ModuleType& module_type,
- const String& isolated_source_text,
- network::mojom::CredentialsMode credentials_mode)
- : response_url_(response_url),
+ ModuleScriptCreationParams(const KURL& source_url,
+ const KURL& base_url,
+ ScriptSourceLocationType source_location_type,
+ const ModuleType& module_type,
+ const String& isolated_source_text)
+ : source_url_(source_url),
+ base_url_(base_url),
+ source_location_type_(source_location_type),
module_type_(module_type),
is_isolated_(true),
source_text_(),
isolated_source_text_(isolated_source_text),
- credentials_mode_(credentials_mode) {}
-
- const KURL response_url_;
+ // The ScriptStreamer is intentionally cleared since it cannot be passed
+ // across threads. This only disables script streaming on worklet
+ // top-level scripts where the ModuleScriptCreationParams is
+ // passed across threads.
+ script_streamer_(nullptr),
+ not_streaming_reason_(
+ ScriptStreamer::NotStreamingReason::kStreamingDisabled) {}
+
+ const KURL source_url_;
+ const KURL base_url_;
+ const ScriptSourceLocationType source_location_type_;
const ModuleType module_type_;
// Mutable because an isolated copy can become bound to a thread when
@@ -97,15 +144,17 @@ class ModuleScriptCreationParams {
// |cache_handler_| is cleared when crossing thread boundaries.
Persistent<SingleCachedMetadataHandler> cache_handler_;
- const network::mojom::CredentialsMode credentials_mode_;
+ // |script_streamer_| is cleared when crossing thread boundaries.
+ Persistent<ScriptStreamer> script_streamer_;
+ const ScriptStreamer::NotStreamingReason not_streaming_reason_;
};
} // namespace blink
namespace WTF {
-// Creates a deep copy because |response_url_| and |source_text_| are not
-// cross-thread-transfer-safe.
+// Creates a deep copy because |source_url_|, |source_text_| and
+// |script_streamer_| are not cross-thread-transfer-safe.
template <>
struct CrossThreadCopier<blink::ModuleScriptCreationParams> {
static blink::ModuleScriptCreationParams Copy(
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h
index da0bb85c79c..b91d5b25218 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h
@@ -14,6 +14,8 @@
namespace blink {
+enum class ModuleType;
+
// A ModuleScriptFetchRequest essentially serves as a "parameter object" for
// Modulator::Fetch{Single,NewSingle}.
class ModuleScriptFetchRequest final {
@@ -23,27 +25,31 @@ class ModuleScriptFetchRequest final {
// Referrer is set only for internal module script fetch algorithms triggered
// from ModuleTreeLinker to fetch descendant module scripts.
ModuleScriptFetchRequest(const KURL& url,
+ ModuleType module_type,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
const ScriptFetchOptions& options,
const String& referrer_string,
const TextPosition& referrer_position)
: url_(url),
+ expected_module_type_(module_type),
context_type_(context_type),
destination_(destination),
options_(options),
referrer_string_(referrer_string),
referrer_position_(referrer_position) {}
- static ModuleScriptFetchRequest CreateForTest(const KURL& url) {
+ static ModuleScriptFetchRequest CreateForTest(const KURL& url,
+ ModuleType module_type) {
return ModuleScriptFetchRequest(
- url, mojom::blink::RequestContextType::SCRIPT,
+ url, module_type, mojom::blink::RequestContextType::SCRIPT,
network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
Referrer::ClientReferrerString(), TextPosition::MinimumPosition());
}
~ModuleScriptFetchRequest() = default;
const KURL& Url() const { return url_; }
+ ModuleType GetExpectedModuleType() const { return expected_module_type_; }
mojom::blink::RequestContextType ContextType() const { return context_type_; }
network::mojom::RequestDestination Destination() const {
return destination_;
@@ -54,6 +60,7 @@ class ModuleScriptFetchRequest final {
private:
const KURL url_;
+ const ModuleType expected_module_type_;
const mojom::blink::RequestContextType context_type_;
const network::mojom::RequestDestination destination_;
const ScriptFetchOptions options_;
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
index 5a29760fc6d..a65e1f1ee9d 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
@@ -17,15 +18,15 @@
namespace blink {
ModuleScriptFetcher::ModuleScriptFetcher(
- util::PassKey<ModuleScriptLoader> pass_key) {}
+ base::PassKey<ModuleScriptLoader> pass_key) {}
void ModuleScriptFetcher::Client::OnFetched(
- const base::Optional<ModuleScriptCreationParams>& params) {
- NotifyFetchFinished(params, HeapVector<Member<ConsoleMessage>>());
+ const ModuleScriptCreationParams& params) {
+ NotifyFetchFinishedSuccess(params);
}
void ModuleScriptFetcher::Client::OnFailed() {
- NotifyFetchFinished(base::nullopt, HeapVector<Member<ConsoleMessage>>());
+ NotifyFetchFinishedError(HeapVector<Member<ConsoleMessage>>());
}
void ModuleScriptFetcher::Trace(Visitor* visitor) const {
@@ -34,10 +35,11 @@ void ModuleScriptFetcher::Trace(Visitor* visitor) const {
// <specdef href="https://html.spec.whatwg.org/C/#fetch-a-single-module-script">
bool ModuleScriptFetcher::WasModuleLoadSuccessful(
- Resource* resource,
- HeapVector<Member<ConsoleMessage>>* error_messages,
- ModuleScriptCreationParams::ModuleType* module_type) {
+ ScriptResource* resource,
+ ModuleType expected_module_type,
+ HeapVector<Member<ConsoleMessage>>* error_messages) {
DCHECK(error_messages);
+ DCHECK_EQ(resource->GetScriptType(), mojom::blink::ScriptType::kModule);
if (resource) {
SubresourceIntegrityHelper::GetConsoleMessages(
@@ -67,38 +69,45 @@ bool ModuleScriptFetcher::WasModuleLoadSuccessful(
// MimeType() may be rewritten by mime sniffer.
//
// <spec step="12">If type is a JavaScript MIME type, then:</spec>
- if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
+ if (expected_module_type == ModuleType::kJavaScript &&
+ MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
response.HttpContentType())) {
- *module_type = ModuleScriptCreationParams::ModuleType::kJavaScriptModule;
return true;
}
// <spec step="13">If type is a JSON MIME type, then:</spec>
if (base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
+ expected_module_type == ModuleType::kJSON &&
MIMETypeRegistry::IsJSONMimeType(response.HttpContentType())) {
- *module_type = ModuleScriptCreationParams::ModuleType::kJSONModule;
return true;
}
if (RuntimeEnabledFeatures::CSSModulesEnabled() &&
+ expected_module_type == ModuleType::kCSS &&
MIMETypeRegistry::IsSupportedStyleSheetMIMEType(
response.HttpContentType())) {
- *module_type = ModuleScriptCreationParams::ModuleType::kCSSModule;
return true;
}
- String required_response_type = "JavaScript";
- if (base::FeatureList::IsEnabled(blink::features::kJSONModules)) {
- required_response_type = required_response_type + ", JSON";
- }
- if (RuntimeEnabledFeatures::CSSModulesEnabled()) {
- required_response_type = required_response_type + ", CSS";
+
+ String message;
+ if (base::FeatureList::IsEnabled(blink::features::kJSONModules) ||
+ RuntimeEnabledFeatures::CSSModulesEnabled()) {
+ message =
+ "Failed to load module script: Expected a " +
+ ModuleScriptCreationParams::ModuleTypeToString(expected_module_type) +
+ " module script but the server responded with a MIME type of \"" +
+ resource->GetResponse().HttpContentType() +
+ "\". Strict MIME type checking is enforced for module scripts per HTML "
+ "spec.";
+ } else {
+ message =
+ "Failed to load module script: The server responded with a "
+ "non-JavaScript "
+ "MIME type of \"" +
+ resource->GetResponse().HttpContentType() +
+ "\". Strict MIME type checking is enforced for module scripts per HTML "
+ "spec.";
}
- String message =
- "Failed to load module script: The server responded with a non-" +
- required_response_type + " MIME type of \"" +
- resource->GetResponse().HttpContentType() +
- "\". Strict MIME type checking is enforced for module scripts per HTML "
- "spec.";
error_messages->push_back(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kJavaScript,
mojom::ConsoleMessageLevel::kError, message,
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
index 8018964df93..f3881ae8374 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_fetcher.h
@@ -25,17 +25,18 @@ class ModuleScriptLoader;
class CORE_EXPORT ModuleScriptFetcher : public ResourceClient {
public:
// ModuleScriptFetcher should only be called from ModuleScriptLoader.
- explicit ModuleScriptFetcher(util::PassKey<ModuleScriptLoader>);
+ explicit ModuleScriptFetcher(base::PassKey<ModuleScriptLoader>);
class CORE_EXPORT Client : public GarbageCollectedMixin {
public:
- virtual void NotifyFetchFinished(
- const base::Optional<ModuleScriptCreationParams>&,
+ virtual void NotifyFetchFinishedError(
const HeapVector<Member<ConsoleMessage>>& error_messages) = 0;
+ virtual void NotifyFetchFinishedSuccess(
+ const ModuleScriptCreationParams&) = 0;
// These helpers are used only from WorkletModuleResponsesMap.
// TODO(nhiroki): Move these helpers to WorkletModuleResponsesMap.
- void OnFetched(const base::Optional<ModuleScriptCreationParams>&);
+ void OnFetched(const ModuleScriptCreationParams&);
void OnFailed();
};
@@ -45,6 +46,7 @@ class CORE_EXPORT ModuleScriptFetcher : public ResourceClient {
// Takes a non-const reference to FetchParameters because
// ScriptResource::Fetch() requires it.
virtual void Fetch(FetchParameters&,
+ ModuleType,
ResourceFetcher*,
ModuleGraphLevel,
Client*) = 0;
@@ -53,9 +55,9 @@ class CORE_EXPORT ModuleScriptFetcher : public ResourceClient {
protected:
static bool WasModuleLoadSuccessful(
- Resource* resource,
- HeapVector<Member<ConsoleMessage>>* error_messages,
- ModuleScriptCreationParams::ModuleType* module_type);
+ ScriptResource* resource,
+ ModuleType expected_module_type,
+ HeapVector<Member<ConsoleMessage>>* error_messages);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
index 7bff037bb47..075adfdbaab 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
@@ -122,12 +122,6 @@ void ModuleScriptLoader::FetchInternal(
ResourceLoaderOptions options(&modulator_->GetScriptState()->World());
- // <spec step="6">If destination is "worker" or "sharedworker" and the
- // top-level module fetch flag is set, then set request's mode to
- // "same-origin".</spec>
- // Cross-origin workers are not supported due to security checks in
- // AbstractWorker::ResolveURL, so no action needs to be taken here.
-
// <spec step="7">Set up the module script request given request and
// options.</spec>
//
@@ -154,6 +148,7 @@ void ModuleScriptLoader::FetchInternal(
// Note: |options| should not be modified after here.
FetchParameters fetch_params(std::move(resource_request), options);
+ fetch_params.SetModuleScript();
// <spec label="SMSR">... its integrity metadata to options's integrity
// metadata, ...</spec>
@@ -178,6 +173,26 @@ void ModuleScriptLoader::FetchInternal(
fetch_client_settings_object.GetSecurityOrigin(),
options_.CredentialsMode());
+ // <spec step="6">If destination is "worker" or "sharedworker" and the
+ // top-level module fetch flag is set, then set request's mode to
+ // "same-origin".</spec>
+ //
+ // `kServiceWorker` is included here for consistency, while it isn't mentioned
+ // in the spec. This doesn't affect the behavior, because we already forbid
+ // redirects and cross-origin response URLs in other places.
+ if ((module_request.Destination() ==
+ network::mojom::RequestDestination::kWorker ||
+ module_request.Destination() ==
+ network::mojom::RequestDestination::kSharedWorker ||
+ module_request.Destination() ==
+ network::mojom::RequestDestination::kServiceWorker) &&
+ level == ModuleGraphLevel::kTopLevelModuleFetch) {
+ // This should be done after SetCrossOriginAccessControl() that sets the
+ // mode to kCors.
+ fetch_params.MutableResourceRequest().SetMode(
+ network::mojom::RequestMode::kSameOrigin);
+ }
+
// <spec step="5">... referrer is referrer, ...</spec>
fetch_params.MutableResourceRequest().SetReferrerString(
module_request.ReferrerString());
@@ -199,6 +214,10 @@ void ModuleScriptLoader::FetchInternal(
// Module scripts are always defer.
fetch_params.SetDefer(FetchParameters::kLazyLoad);
+ // TODO(yoav): This is not accurate for module scripts with an async
+ // attribute.
+ fetch_params.SetRenderBlockingBehavior(RenderBlockingBehavior::kNonBlocking);
+
// [nospec] Unlike defer/async classic scripts, module scripts are fetched at
// High priority.
fetch_params.MutableResourceRequest().SetPriority(
@@ -218,13 +237,12 @@ void ModuleScriptLoader::FetchInternal(
// response.</spec>
module_fetcher_ =
modulator_->CreateModuleScriptFetcher(custom_fetch_type, PassKey());
- module_fetcher_->Fetch(fetch_params, fetch_client_settings_object_fetcher,
- level, this);
+ module_fetcher_->Fetch(fetch_params, module_request.GetExpectedModuleType(),
+ fetch_client_settings_object_fetcher, level, this);
}
// <specdef href="https://html.spec.whatwg.org/C/#fetch-a-single-module-script">
-void ModuleScriptLoader::NotifyFetchFinished(
- const base::Optional<ModuleScriptCreationParams>& params,
+void ModuleScriptLoader::NotifyFetchFinishedError(
const HeapVector<Member<ConsoleMessage>>& error_messages) {
// [nospec] Abort the steps if the browsing context is discarded.
if (!modulator_->HasValidContext()) {
@@ -237,11 +255,17 @@ void ModuleScriptLoader::NotifyFetchFinished(
// <spec step="9">If any of the following conditions are met, set
// moduleMap[url] to null, asynchronously complete this algorithm with null,
// and abort these steps: ...</spec>
- if (!params.has_value()) {
- for (ConsoleMessage* error_message : error_messages) {
- ExecutionContext::From(modulator_->GetScriptState())
- ->AddConsoleMessage(error_message);
- }
+ for (ConsoleMessage* error_message : error_messages) {
+ ExecutionContext::From(modulator_->GetScriptState())
+ ->AddConsoleMessage(error_message);
+ }
+ AdvanceState(State::kFinished);
+}
+
+void ModuleScriptLoader::NotifyFetchFinishedSuccess(
+ const ModuleScriptCreationParams& params) {
+ // [nospec] Abort the steps if the browsing context is discarded.
+ if (!modulator_->HasValidContext()) {
AdvanceState(State::kFinished);
return;
}
@@ -252,28 +276,27 @@ void ModuleScriptLoader::NotifyFetchFinished(
// <spec step="12.2">Set module script to the result of creating a JavaScript
// module script given source text, module map settings object, response's
// url, and options.</spec>
- switch (params->GetModuleType()) {
- case ModuleScriptCreationParams::ModuleType::kJSONModule:
+ switch (params.GetModuleType()) {
+ case ModuleType::kJSON:
DCHECK(base::FeatureList::IsEnabled(blink::features::kJSONModules));
module_script_ = ValueWrapperSyntheticModuleScript::
CreateJSONWrapperSyntheticModuleScript(params, modulator_);
break;
- case ModuleScriptCreationParams::ModuleType::kCSSModule:
+ case ModuleType::kCSS:
DCHECK(RuntimeEnabledFeatures::CSSModulesEnabled());
module_script_ = ValueWrapperSyntheticModuleScript::
CreateCSSWrapperSyntheticModuleScript(params, modulator_);
break;
- case ModuleScriptCreationParams::ModuleType::kJavaScriptModule:
+ case ModuleType::kJavaScript:
// Step 9. "Let source text be the result of UTF-8 decoding response's
// body." [spec text]
// Step 10. "Let module script be the result of creating
// a module script given source text, module map settings object,
// response's url, and options." [spec text]
- module_script_ = JSModuleScript::Create(
- params->GetSourceText(), params->CacheHandler(),
- ScriptSourceLocationType::kExternalFile, modulator_,
- params->GetResponseUrl(), params->GetResponseUrl(), options_);
+ module_script_ = JSModuleScript::Create(params, modulator_, options_);
break;
+ case ModuleType::kInvalid:
+ NOTREACHED();
}
AdvanceState(State::kFinished);
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
index df0bc08bb16..1681aec41a8 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader.h
@@ -58,8 +58,8 @@ class CORE_EXPORT ModuleScriptLoader final
ModuleScriptLoaderClient*);
// Implements ModuleScriptFetcher::Client.
- void NotifyFetchFinished(
- const base::Optional<ModuleScriptCreationParams>&,
+ void NotifyFetchFinishedSuccess(const ModuleScriptCreationParams&) override;
+ void NotifyFetchFinishedError(
const HeapVector<Member<ConsoleMessage>>& error_messages) override;
bool IsInitialState() const { return state_ == State::kInitial; }
@@ -77,10 +77,10 @@ class CORE_EXPORT ModuleScriptLoader final
void AdvanceState(State new_state);
- using PassKey = util::PassKey<ModuleScriptLoader>;
+ using PassKey = base::PassKey<ModuleScriptLoader>;
// PassKey should be private and cannot be accessed from outside, but allow
// accessing only from friend classes for testing.
- static util::PassKey<ModuleScriptLoader> CreatePassKeyForTests() {
+ static base::PassKey<ModuleScriptLoader> CreatePassKeyForTests() {
return PassKey();
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
index 51b7edf1713..c2097c241be 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
@@ -90,7 +90,8 @@ class ModuleScriptLoaderTestModulator final : public DummyModulator {
void SetModuleRequests(const Vector<String>& requests) {
requests_.clear();
for (const String& request : requests) {
- requests_.emplace_back(request, TextPosition::MinimumPosition());
+ requests_.emplace_back(request, TextPosition::MinimumPosition(),
+ Vector<ImportAssertion>());
}
}
Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
@@ -100,7 +101,7 @@ class ModuleScriptLoaderTestModulator final : public DummyModulator {
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType custom_fetch_type,
- util::PassKey<ModuleScriptLoader> pass_key) override {
+ base::PassKey<ModuleScriptLoader> pass_key) override {
auto* execution_context = ExecutionContext::From(script_state_);
if (auto* scope = DynamicTo<WorkletGlobalScope>(execution_context)) {
EXPECT_EQ(ModuleScriptCustomFetchType::kWorkletAddModule,
@@ -189,13 +190,14 @@ void ModuleScriptLoaderTest::InitializeForDocument() {
auto* fetch_context = MakeGarbageCollected<MockFetchContext>();
auto* properties =
MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_);
- fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), fetch_context,
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- MakeGarbageCollected<TestLoaderFactory>(
- platform_->GetURLLoaderMockFactory()),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(properties->MakeDetachable(), fetch_context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ MakeGarbageCollected<TestLoaderFactory>(
+ platform_->GetURLLoaderMockFactory()),
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
modulator_ = MakeGarbageCollected<ModuleScriptLoaderTestModulator>(
ToScriptStateForMainWorld(&GetFrame()));
}
@@ -204,19 +206,21 @@ void ModuleScriptLoaderTest::InitializeForWorklet() {
auto* fetch_context = MakeGarbageCollected<MockFetchContext>();
auto* properties =
MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_);
- fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), fetch_context,
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- MakeGarbageCollected<TestLoaderFactory>(
- platform_->GetURLLoaderMockFactory()),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ fetcher_ = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(properties->MakeDetachable(), fetch_context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ MakeGarbageCollected<TestLoaderFactory>(
+ platform_->GetURLLoaderMockFactory()),
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
reporting_proxy_ = std::make_unique<MockWorkerReportingProxy>();
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
url_, mojom::blink::ScriptType::kModule, "GlobalScopeName", "UserAgent",
UserAgentMetadata(), nullptr /* web_worker_fetch_context */,
- Vector<CSPHeaderAndType>(), network::mojom::ReferrerPolicy::kDefault,
- security_origin_.get(), true /* is_secure_context */, HttpsState::kModern,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
+ network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
+ true /* is_secure_context */, HttpsState::kModern,
nullptr /* worker_clients */, nullptr /* content_settings_client */,
network::mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_token */,
base::UnguessableToken::Create(), nullptr /* worker_settings */,
@@ -225,8 +229,7 @@ void ModuleScriptLoaderTest::InitializeForWorklet() {
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
base::UnguessableToken::Create() /* agent_cluster_id */);
- creation_params->parent_context_token =
- LocalFrameToken(GetFrame().GetFrameToken());
+ creation_params->parent_context_token = GetFrame().GetLocalFrameToken();
global_scope_ = MakeGarbageCollected<FakeWorkletGlobalScope>(
std::move(creation_params), *reporting_proxy_, &GetFrame(),
false /* create_microtask_queue */);
@@ -241,10 +244,10 @@ void ModuleScriptLoaderTest::TestFetchDataURL(
TestModuleScriptLoaderClient* client) {
auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>();
KURL url("data:text/javascript,export default 'grapes';");
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(),
+ custom_fetch_type, registry, client);
}
void ModuleScriptLoaderTest::TestFetchDataURLJSONModule(
@@ -255,10 +258,10 @@ void ModuleScriptLoaderTest::TestFetchDataURLJSONModule(
"data:application/"
"json,{\"1\":{\"name\":\"MIKE\",\"surname\":\"TAYLOR\"},\"2\":{\"name\":"
"\"TOM\",\"surname\":\"JERRY\"}}");
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJSON), fetcher_,
+ ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), custom_fetch_type,
+ registry, client);
}
void ModuleScriptLoaderTest::TestFetchDataURLInvalidJSONModule(
@@ -268,10 +271,10 @@ void ModuleScriptLoaderTest::TestFetchDataURLInvalidJSONModule(
KURL url(
"data:application/"
"json,{{{");
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJSON), fetcher_,
+ ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), custom_fetch_type,
+ registry, client);
}
TEST_F(ModuleScriptLoaderTest, FetchDataURL) {
@@ -422,10 +425,10 @@ void ModuleScriptLoaderTest::TestInvalidSpecifier(
auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>();
KURL url("data:text/javascript,import 'invalid';export default 'grapes';");
GetModulator()->SetModuleRequests({"invalid"});
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(),
+ custom_fetch_type, registry, client);
}
TEST_F(ModuleScriptLoaderTest, InvalidSpecifier) {
@@ -466,10 +469,10 @@ void ModuleScriptLoaderTest::TestFetchInvalidURL(
auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>();
KURL url;
EXPECT_FALSE(url.IsValid());
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(),
+ custom_fetch_type, registry, client);
}
TEST_F(ModuleScriptLoaderTest, FetchInvalidURL) {
@@ -508,10 +511,10 @@ void ModuleScriptLoaderTest::TestFetchURL(
platform_->GetURLLoaderMockFactory());
auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>();
- ModuleScriptLoader::Fetch(ModuleScriptFetchRequest::CreateForTest(url),
- fetcher_, ModuleGraphLevel::kTopLevelModuleFetch,
- GetModulator(), custom_fetch_type, registry,
- client);
+ ModuleScriptLoader::Fetch(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(),
+ custom_fetch_type, registry, client);
}
TEST_F(ModuleScriptLoaderTest, FetchURL) {
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index 17c63cee2de..024aa5cb96a 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
#include "third_party/blink/renderer/bindings/core/v8/module_request.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
#include "third_party/blink/renderer/core/script/module_script.h"
@@ -32,8 +33,24 @@
namespace blink {
+namespace {
+
+struct ModuleScriptFetchTarget {
+ ModuleScriptFetchTarget(KURL url,
+ ModuleType module_type,
+ TextPosition position)
+ : url(url), module_type(module_type), position(position) {}
+
+ KURL url;
+ ModuleType module_type;
+ TextPosition position;
+};
+
+} // namespace
+
void ModuleTreeLinker::Fetch(
const KURL& url,
+ const ModuleType& module_type,
ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
@@ -46,7 +63,7 @@ void ModuleTreeLinker::Fetch(
fetch_client_settings_object_fetcher, context_type, destination,
modulator, custom_fetch_type, registry, client);
registry->AddFetcher(fetcher);
- fetcher->FetchRoot(url, options);
+ fetcher->FetchRoot(url, module_type, options);
DCHECK(fetcher->IsFetching());
}
@@ -170,14 +187,18 @@ void ModuleTreeLinker::AdvanceState(State new_state) {
// #fetch-a-module-script-tree, #fetch-an-import()-module-script-graph, and
// #fetch-a-module-worker-script-tree.
void ModuleTreeLinker::FetchRoot(const KURL& original_url,
+ ModuleType module_type,
const ScriptFetchOptions& options) {
#if DCHECK_IS_ON()
original_url_ = original_url;
+ module_type_ = module_type;
root_is_inline_ = false;
#endif
// https://wicg.github.io/import-maps/#wait-for-import-maps
- modulator_->ClearIsAcquiringImportMaps();
+ // 1.2. Set document’s acquiring import maps to false. [spec text]
+ modulator_->SetAcquiringImportMapsState(
+ Modulator::AcquiringImportMapsState::kAfterModuleScriptLoad);
AdvanceState(State::kFetchingSelf);
@@ -206,6 +227,8 @@ void ModuleTreeLinker::FetchRoot(const KURL& original_url,
return;
}
+ CHECK_NE(module_type, ModuleType::kInvalid);
+
// <spec label="fetch-a-module-script-tree" step="3">Let visited set be « url
// ».</spec>
//
@@ -214,7 +237,7 @@ void ModuleTreeLinker::FetchRoot(const KURL& original_url,
//
// <spec label="fetch-a-module-worker-script-tree" step="4">Let visited set be
// « url ».</spec>
- visited_set_.insert(url);
+ visited_set_.insert(std::make_pair(url, module_type));
// <spec label="fetch-a-module-script-tree" step="1">Fetch a single module
// script given url, settings object, "script", options, settings object,
@@ -228,9 +251,9 @@ void ModuleTreeLinker::FetchRoot(const KURL& original_url,
// module script given url, fetch client settings object, destination,
// options, module map settings object, "client", and with the top-level
// module fetch flag set. ...</spec>
- ModuleScriptFetchRequest request(url, context_type_, destination_, options,
- Referrer::ClientReferrerString(),
- TextPosition::MinimumPosition());
+ ModuleScriptFetchRequest request(
+ url, module_type, context_type_, destination_, options,
+ Referrer::ClientReferrerString(), TextPosition::MinimumPosition());
++num_incomplete_fetches_;
modulator_->FetchSingle(request, fetch_client_settings_object_fetcher_.Get(),
ModuleGraphLevel::kTopLevelModuleFetch,
@@ -244,13 +267,16 @@ void ModuleTreeLinker::FetchRootInline(ModuleScript* module_script) {
#if DCHECK_IS_ON()
original_url_ = module_script->BaseURL();
url_ = original_url_;
+ module_type_ = ModuleType::kJavaScript;
root_is_inline_ = true;
#endif
// https://wicg.github.io/import-maps/#wait-for-import-maps
+ // 1.2. Set document’s acquiring import maps to false. [spec text]
//
// TODO(hiroshige): This should be done before |module_script| is created.
- modulator_->ClearIsAcquiringImportMaps();
+ modulator_->SetAcquiringImportMapsState(
+ Modulator::AcquiringImportMapsState::kAfterModuleScriptLoad);
AdvanceState(State::kFetchingSelf);
@@ -338,6 +364,8 @@ void ModuleTreeLinker::NotifyModuleLoadFinished(ModuleScript* module_script) {
// <specdef
// href="https://html.spec.whatwg.org/C/#fetch-the-descendants-of-a-module-script">
+// See also https://github.com/whatwg/html/pull/5658/ which adds ModuleRequest
+// and module type to the HTML spec.
void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
DCHECK(module_script);
@@ -375,44 +403,44 @@ void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
// Note: We defer this bail-out until the end of the procedure. The rest of
// the procedure will be no-op anyway if record.[[RequestedModules]] is empty.
- // <spec step="4">Let urls be a new empty list.</spec>
- Vector<KURL> urls;
- Vector<TextPosition> positions;
+ // <spec step="4">Let moduleRequests be a new empty list.</spec>
+ Vector<ModuleScriptFetchTarget> module_requests;
- // <spec step="5">For each string requested of
+ // <spec step="5">For each ModuleRequest Record requested of
// record.[[RequestedModules]],</spec>
- Vector<ModuleRequest> module_requests =
+ Vector<ModuleRequest> record_requested_modules =
modulator_->ModuleRequestsFromModuleRecord(record);
- for (const auto& module_request : module_requests) {
+ for (const auto& requested : record_requested_modules) {
// <spec step="5.1">Let url be the result of resolving a module specifier
- // given module script's base URL and requested.</spec>
- KURL url = module_script->ResolveModuleSpecifier(module_request.specifier);
+ // given module script's base URL and requested.[[Specifier]].</spec>
+ KURL url = module_script->ResolveModuleSpecifier(requested.specifier);
+ ModuleType module_type = modulator_->ModuleTypeFromRequest(requested);
// <spec step="5.2">Assert: url is never failure, because resolving a module
// specifier must have been previously successful with these same two
// arguments.</spec>
CHECK(url.IsValid()) << "ModuleScript::ResolveModuleSpecifier() impl must "
"return a valid url.";
+ CHECK_NE(module_type, ModuleType::kInvalid);
- // <spec step="5.3">If visited set does not contain url, then:</spec>
- if (!visited_set_.Contains(url)) {
- // <spec step="5.3.1">Append url to urls.</spec>
- urls.push_back(url);
+ // <spec step="5.4">If visited set does not contain (url, module type),
+ // then:</spec>
+ if (!visited_set_.Contains(std::make_pair(url, module_type))) {
+ // <spec step="5.4.1">Append (url, module type) to moduleRequests.</spec>
+ module_requests.emplace_back(url, module_type, requested.position);
- // <spec step="5.3.2">Append url to visited set.</spec>
- visited_set_.insert(url);
-
- positions.push_back(module_request.position);
+ // <spec step="5.4.2">Append (url, module type) to visited set.</spec>
+ visited_set_.insert(std::make_pair(url, module_type));
}
}
- if (urls.IsEmpty()) {
+ if (module_requests.IsEmpty()) {
// <spec step="3">... if record.[[RequestedModules]] is empty,
// asynchronously complete this algorithm with module script.</spec>
//
- // Also, if record.[[RequestedModules]] is not empty but |urls| is
- // empty here, we complete this algorithm.
+ // Also, if record.[[RequestedModules]] is not empty but |module_requests|
+ // is empty here, we complete this algorithm.
FinalizeFetchDescendantsForOneModuleScript();
return;
}
@@ -435,24 +463,27 @@ void ModuleTreeLinker::FetchDescendants(const ModuleScript* module_script) {
module_script->FetchOptions().ParserState(),
module_script->FetchOptions().CredentialsMode(),
module_script->FetchOptions().GetReferrerPolicy(),
- mojom::FetchImportanceMode::kImportanceAuto);
+ mojom::blink::FetchImportanceMode::kImportanceAuto,
+ RenderBlockingBehavior::kNonBlocking);
- // <spec step="8">For each url in urls, ...</spec>
+ // <spec step="8">For each moduleRequest in moduleRequests, ...</spec>
//
// <spec step="8">... These invocations of the internal module script graph
// fetching procedure should be performed in parallel to each other.
// ...</spec>
- for (wtf_size_t i = 0; i < urls.size(); ++i) {
+ for (const auto& module_request : module_requests) {
// <spec step="8">... perform the internal module script graph fetching
- // procedure given url, fetch client settings object, destination, options,
- // module script's settings object, visited set, and module script's base
- // URL. ...</spec>
+ // procedure given moduleRequest, fetch client settings object, destination,
+ // options, module script's settings object, visited set, and module
+ // script's base URL. ...</spec>
ModuleScriptFetchRequest request(
- urls[i], context_type_, destination_, options,
- module_script->BaseURL().GetString(), positions[i]);
+ module_request.url, module_request.module_type, context_type_,
+ destination_, options, module_script->BaseURL().GetString(),
+ module_request.position);
// <spec label="IMSGF" step="1">Assert: visited set contains url.</spec>
- DCHECK(visited_set_.Contains(request.Url()));
+ DCHECK(visited_set_.Contains(
+ std::make_pair(request.Url(), request.GetExpectedModuleType())));
++num_incomplete_fetches_;
@@ -583,6 +614,8 @@ ScriptValue ModuleTreeLinker::FindFirstParseError(
// moduleScript's base URL and that item. ...</spec>
KURL child_url =
module_script->ResolveModuleSpecifier(module_request.specifier);
+ ModuleType child_module_type =
+ modulator_->ModuleTypeFromRequest(module_request);
// <spec step="5.2">... (None of these will ever fail, as otherwise
// moduleScript would have been marked as itself having a parse
@@ -590,13 +623,14 @@ ScriptValue ModuleTreeLinker::FindFirstParseError(
CHECK(child_url.IsValid())
<< "ModuleScript::ResolveModuleSpecifier() impl must "
"return a valid url.";
+ CHECK_NE(child_module_type, ModuleType::kInvalid);
// <spec step="5.3">Let childModules be the list obtained by getting each
// value in moduleMap whose key is given by an item of childURLs.</spec>
//
// <spec step="5.4">For each childModule of childModules:</spec>
const ModuleScript* child_module =
- modulator_->GetFetchedModuleScript(child_url);
+ modulator_->GetFetchedModuleScript(child_url, child_module_type);
// <spec step="5.4.1">Assert: childModule is a module script (i.e., it is
// not "fetching" or null); ...</spec>
@@ -623,10 +657,29 @@ ScriptValue ModuleTreeLinker::FindFirstParseError(
}
#if DCHECK_IS_ON()
+std::ostream& operator<<(std::ostream& stream, ModuleType module_type) {
+ switch (module_type) {
+ case ModuleType::kInvalid:
+ stream << "Invalid";
+ break;
+ case ModuleType::kJavaScript:
+ stream << "JavaScript";
+ break;
+ case ModuleType::kJSON:
+ stream << "JSON";
+ break;
+ case ModuleType::kCSS:
+ stream << "CSS";
+ break;
+ }
+ return stream;
+}
+
std::ostream& operator<<(std::ostream& stream, const ModuleTreeLinker& linker) {
stream << "ModuleTreeLinker[" << &linker
<< ", original_url=" << linker.original_url_.GetString()
<< ", url=" << linker.url_.GetString()
+ << ", module_type=" << linker.module_type_
<< ", inline=" << linker.root_is_inline_ << "]";
return stream;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
index 9faa28e3730..325a6ce8ad7 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h
@@ -32,7 +32,8 @@ class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
// https://html.spec.whatwg.org/C/#fetch-a-module-script-tree
// https://html.spec.whatwg.org/C/#fetch-a-module-worker-script-tree
// https://html.spec.whatwg.org/C/#fetch-an-import()-module-script-graph
- static void Fetch(const KURL&,
+ static void Fetch(const KURL& url,
+ const ModuleType&,
ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
@@ -79,12 +80,13 @@ class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
kInstantiating,
kFinished,
};
+
#if DCHECK_IS_ON()
static const char* StateToString(State);
#endif
void AdvanceState(State);
- void FetchRoot(const KURL&, const ScriptFetchOptions&);
+ void FetchRoot(const KURL&, ModuleType, const ScriptFetchOptions&);
void FetchRootInline(ModuleScript*);
void NotifyModuleLoadFinished(ModuleScript*) override;
@@ -107,7 +109,7 @@ class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
const network::mojom::RequestDestination destination_;
const Member<Modulator> modulator_;
const ModuleScriptCustomFetchType custom_fetch_type_;
- HashSet<KURL> visited_set_;
+ HashSet<std::pair<KURL, ModuleType>> visited_set_;
const Member<ModuleTreeLinkerRegistry> registry_;
const Member<ModuleTreeClient> client_;
State state_ = State::kInitial;
@@ -123,8 +125,10 @@ class CORE_EXPORT ModuleTreeLinker final : public SingleModuleClient {
#if DCHECK_IS_ON()
KURL original_url_;
KURL url_;
+ ModuleType module_type_;
bool root_is_inline_;
+ friend CORE_EXPORT std::ostream& operator<<(std::ostream&, ModuleType);
friend CORE_EXPORT std::ostream& operator<<(std::ostream&,
const ModuleTreeLinker&);
#endif
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
index 740d58e07ce..b0c1f9aad10 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
@@ -14,11 +14,13 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
#include "third_party/blink/renderer/core/script/js_module_script.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/testing/dummy_modulator.h"
+#include "third_party/blink/renderer/core/testing/module_test_base.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
@@ -58,7 +60,7 @@ class TestModuleTreeClient final : public ModuleTreeClient {
class ModuleTreeLinkerTestModulator final : public DummyModulator {
public:
- ModuleTreeLinkerTestModulator(ScriptState* script_state)
+ explicit ModuleTreeLinkerTestModulator(ScriptState* script_state)
: script_state_(script_state) {}
~ModuleTreeLinkerTestModulator() override = default;
@@ -81,10 +83,8 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator {
}
source_text.Append("export default 'grapes';");
- v8::Local<v8::Module> module_record = ModuleRecord::Compile(
- script_state_->GetIsolate(), source_text.ToString(), url, url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module_record = ModuleTestBase::CompileModule(
+ script_state_->GetIsolate(), source_text.ToString(), url);
auto* module_script =
JSModuleScript::CreateForTest(this, module_record, url);
@@ -129,7 +129,7 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator {
String* failure_reason) final {
return KURL(base_url, module_request);
}
- void ClearIsAcquiringImportMaps() final {}
+ void SetAcquiringImportMapsState(AcquiringImportMapsState) final {}
void FetchSingle(const ModuleScriptFetchRequest& request,
ResourceFetcher*,
@@ -140,7 +140,8 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator {
pending_clients_.Set(request.Url(), client);
}
- ModuleScript* GetFetchedModuleScript(const KURL& url) override {
+ ModuleScript* GetFetchedModuleScript(const KURL& url,
+ ModuleType module_type) override {
const auto& it = module_map_.find(url);
if (it == module_map_.end())
return nullptr;
@@ -207,10 +208,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeNoDeps) {
KURL url("http://example.com/root.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -230,10 +232,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeInstantiationFailure) {
KURL url("http://example.com/root.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -257,10 +260,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWithSingleDependency) {
KURL url("http://example.com/root.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -285,10 +289,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps) {
KURL url("http://example.com/root.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -326,10 +331,11 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps1Fail) {
KURL url("http://example.com/root.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -386,10 +392,11 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyTree) {
KURL url("http://example.com/depth1.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
@@ -413,10 +420,11 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyOfCyclicGraph) {
KURL url("http://example.com/a.js");
TestModuleTreeClient* client = MakeGarbageCollected<TestModuleTreeClient>();
- ModuleTreeLinker::Fetch(
- url, GetDocument().Fetcher(), mojom::blink::RequestContextType::SCRIPT,
- network::mojom::RequestDestination::kScript, ScriptFetchOptions(),
- GetModulator(), ModuleScriptCustomFetchType::kNone, registry, client);
+ ModuleTreeLinker::Fetch(url, ModuleType::kJavaScript, GetDocument().Fetcher(),
+ mojom::blink::RequestContextType::SCRIPT,
+ network::mojom::RequestDestination::kScript,
+ ScriptFetchOptions(), GetModulator(),
+ ModuleScriptCustomFetchType::kNone, registry, client);
EXPECT_FALSE(client->WasNotifyFinished())
<< "ModuleTreeLinker should always finish asynchronously.";
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
index 88377d2c20b..e9bc8dde07c 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
@@ -10,6 +10,7 @@
#include "services/network/public/mojom/referrer_policy.mojom-blink.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/loader/network_utils.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -28,20 +29,23 @@ namespace blink {
WorkerModuleScriptFetcher::WorkerModuleScriptFetcher(
WorkerGlobalScope* global_scope,
- util::PassKey<ModuleScriptLoader> pass_key)
+ base::PassKey<ModuleScriptLoader> pass_key)
: ModuleScriptFetcher(pass_key), global_scope_(global_scope) {}
// <specdef href="https://html.spec.whatwg.org/C/#run-a-worker">
void WorkerModuleScriptFetcher::Fetch(
FetchParameters& fetch_params,
+ ModuleType expected_module_type,
ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptFetcher::Client* client) {
+ DCHECK_EQ(fetch_params.GetScriptType(), mojom::blink::ScriptType::kModule);
DCHECK(global_scope_->IsContextThread());
DCHECK(!fetch_client_settings_object_fetcher_);
fetch_client_settings_object_fetcher_ = fetch_client_settings_object_fetcher;
client_ = client;
level_ = level;
+ expected_module_type_ = expected_module_type;
// Use WorkerMainScriptLoader to load the main script when
// dedicated workers (PlzDedicatedWorker) and shared workers.
@@ -88,25 +92,24 @@ void WorkerModuleScriptFetcher::NotifyFinished(Resource* resource) {
DCHECK(global_scope_->IsContextThread());
ClearResource();
- ScriptResource* script_resource = ToScriptResource(resource);
- HeapVector<Member<ConsoleMessage>> error_messages;
- ModuleScriptCreationParams::ModuleType module_type;
- if (!WasModuleLoadSuccessful(script_resource, &error_messages,
- &module_type)) {
- client_->NotifyFetchFinished(base::nullopt, error_messages);
- return;
+ auto* script_resource = To<ScriptResource>(resource);
+ {
+ HeapVector<Member<ConsoleMessage>> error_messages;
+ if (!WasModuleLoadSuccessful(script_resource, expected_module_type_,
+ &error_messages)) {
+ client_->NotifyFetchFinishedError(error_messages);
+ return;
+ }
}
- NotifyClient(resource->Url(), module_type,
- script_resource->GetResourceRequest().GetCredentialsMode(),
+ NotifyClient(resource->Url(), expected_module_type_,
script_resource->SourceText(), resource->GetResponse(),
script_resource->CacheHandler());
}
void WorkerModuleScriptFetcher::NotifyClient(
const KURL& request_url,
- ModuleScriptCreationParams::ModuleType module_type,
- const network::mojom::CredentialsMode credentials_mode,
+ ModuleType module_type,
const ParkableString& source_text,
const ResourceResponse& response,
SingleCachedMetadataHandler* cache_handler) {
@@ -146,7 +149,7 @@ void WorkerModuleScriptFetcher::NotifyClient(
mojom::ConsoleMessageSource::kSecurity,
mojom::ConsoleMessageLevel::kError,
"Refused to cross-origin redirects of the top-level worker script."));
- client_->NotifyFetchFinished(base::nullopt, error_messages);
+ client_->NotifyFetchFinishedError(error_messages);
return;
}
@@ -159,11 +162,6 @@ void WorkerModuleScriptFetcher::NotifyClient(
kDoNotSupportReferrerPolicyLegacyKeywords, &response_referrer_policy);
}
- auto* response_content_security_policy =
- MakeGarbageCollected<ContentSecurityPolicy>();
- response_content_security_policy->DidReceiveHeaders(
- ContentSecurityPolicyResponseHeaders(response));
-
std::unique_ptr<Vector<String>> response_origin_trial_tokens =
OriginTrialContext::ParseHeaderValue(
response.HttpHeaderField(http_names::kOriginTrial));
@@ -171,17 +169,21 @@ void WorkerModuleScriptFetcher::NotifyClient(
// Step 12.3-12.6 are implemented in Initialize().
global_scope_->Initialize(
response_url, response_referrer_policy, response.AddressSpace(),
- response_content_security_policy->Headers(),
+ ContentSecurityPolicy::ParseHeaders(
+ ContentSecurityPolicyResponseHeaders(response)),
response_origin_trial_tokens.get(), response.AppCacheID());
}
- ModuleScriptCreationParams params(response.CurrentRequestUrl(), module_type,
- source_text, cache_handler,
- credentials_mode);
// <spec step="12.7">Asynchronously complete the perform the fetch steps with
// response.</spec>
- client_->NotifyFetchFinished(params, error_messages);
+ const KURL& url = response.CurrentRequestUrl();
+ // Create an external module script where base_url == source_url.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
+ client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
+ /*source_url=*/url, /*base_url=*/url,
+ ScriptSourceLocationType::kExternalFile, module_type, source_text,
+ cache_handler));
}
void WorkerModuleScriptFetcher::DidReceiveData(base::span<const char> span) {
@@ -212,7 +214,7 @@ void WorkerModuleScriptFetcher::OnStartLoadingBody(
resource_response.CurrentRequestUrl().GetString(), /*loader=*/nullptr,
-1));
worker_main_script_loader_->Cancel();
- client_->NotifyFetchFinished(base::nullopt, error_messages);
+ client_->NotifyFetchFinishedError(error_messages);
return;
}
}
@@ -222,15 +224,13 @@ void WorkerModuleScriptFetcher::OnFinishedLoadingWorkerMainScript() {
if (decoder_)
source_text_.Append(decoder_->Flush());
NotifyClient(worker_main_script_loader_->GetRequestURL(),
- ModuleScriptCreationParams::ModuleType::kJavaScriptModule,
- network::mojom::CredentialsMode::kSameOrigin,
+ ModuleType::kJavaScript,
ParkableString(source_text_.ToString().ReleaseImpl()), response,
worker_main_script_loader_->CreateCachedMetadataHandler());
}
void WorkerModuleScriptFetcher::OnFailedLoadingWorkerMainScript() {
- client_->NotifyFetchFinished(base::nullopt,
- HeapVector<Member<ConsoleMessage>>());
+ client_->NotifyFetchFinishedError(HeapVector<Member<ConsoleMessage>>());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
index ce9cf62135c..f351d88609c 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
@@ -25,10 +25,11 @@ class CORE_EXPORT WorkerModuleScriptFetcher final
public WorkerMainScriptLoaderClient {
public:
WorkerModuleScriptFetcher(WorkerGlobalScope*,
- util::PassKey<ModuleScriptLoader>);
+ base::PassKey<ModuleScriptLoader>);
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ModuleType,
ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
@@ -48,8 +49,7 @@ class CORE_EXPORT WorkerModuleScriptFetcher final
String DebugName() const override { return "WorkerModuleScriptFetcher"; }
void NotifyClient(const KURL& request_url,
- ModuleScriptCreationParams::ModuleType module_type,
- const network::mojom::CredentialsMode credentials_mode,
+ ModuleType module_type,
const ParkableString& source_text,
const ResourceResponse& response,
SingleCachedMetadataHandler* cache_handler);
@@ -65,6 +65,7 @@ class CORE_EXPORT WorkerModuleScriptFetcher final
Member<ResourceFetcher> fetch_client_settings_object_fetcher_;
Member<Client> client_;
ModuleGraphLevel level_;
+ ModuleType expected_module_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
index 43bb0c89006..d811c1fb03e 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
@@ -4,23 +4,26 @@
#include "third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
namespace blink {
WorkletModuleScriptFetcher::WorkletModuleScriptFetcher(
WorkletModuleResponsesMap* module_responses_map,
- util::PassKey<ModuleScriptLoader> pass_key)
+ base::PassKey<ModuleScriptLoader> pass_key)
: ModuleScriptFetcher(pass_key),
module_responses_map_(module_responses_map) {}
void WorkletModuleScriptFetcher::Fetch(
FetchParameters& fetch_params,
+ ModuleType expected_module_type,
ResourceFetcher* fetch_client_settings_object_fetcher,
ModuleGraphLevel level,
ModuleScriptFetcher::Client* client) {
+ DCHECK_EQ(fetch_params.GetScriptType(), mojom::blink::ScriptType::kModule);
if (module_responses_map_->GetEntry(
- fetch_params.Url(), client,
+ fetch_params.Url(), expected_module_type, client,
fetch_client_settings_object_fetcher->GetTaskRunner())) {
return;
}
@@ -36,6 +39,7 @@ void WorkletModuleScriptFetcher::Fetch(
// need to handle that case, maybe by having a way to restart fetches in a
// different global scope?
url_ = fetch_params.Url();
+ expected_module_type_ = expected_module_type;
ScriptResource::Fetch(fetch_params, fetch_client_settings_object_fetcher,
this, ScriptResource::kNoStreaming);
}
@@ -44,19 +48,22 @@ void WorkletModuleScriptFetcher::NotifyFinished(Resource* resource) {
ClearResource();
base::Optional<ModuleScriptCreationParams> params;
- ScriptResource* script_resource = ToScriptResource(resource);
+ auto* script_resource = To<ScriptResource>(resource);
HeapVector<Member<ConsoleMessage>> error_messages;
- ModuleScriptCreationParams::ModuleType module_type;
- if (WasModuleLoadSuccessful(script_resource, &error_messages, &module_type)) {
- params.emplace(script_resource->GetResponse().CurrentRequestUrl(),
- module_type, script_resource->SourceText(),
- script_resource->CacheHandler(),
- script_resource->GetResourceRequest().GetCredentialsMode());
+ if (WasModuleLoadSuccessful(script_resource, expected_module_type_,
+ &error_messages)) {
+ const KURL& url = script_resource->GetResponse().CurrentRequestUrl();
+ // Create an external module script where base_url == source_url.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
+ params.emplace(/*source_url=*/url, /*base_url=*/url,
+ ScriptSourceLocationType::kExternalFile,
+ expected_module_type_, script_resource->SourceText(),
+ script_resource->CacheHandler());
}
// This will eventually notify |client| passed to
// WorkletModuleScriptFetcher::Fetch().
- module_responses_map_->SetEntryParams(url_, params);
+ module_responses_map_->SetEntryParams(url_, expected_module_type_, params);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
index 6968128629b..f478f7f1cc7 100644
--- a/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
+++ b/chromium/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h
@@ -27,10 +27,11 @@ class CORE_EXPORT WorkletModuleScriptFetcher final
public ModuleScriptFetcher {
public:
WorkletModuleScriptFetcher(WorkletModuleResponsesMap*,
- util::PassKey<ModuleScriptLoader>);
+ base::PassKey<ModuleScriptLoader>);
// Implements ModuleScriptFetcher.
void Fetch(FetchParameters&,
+ ModuleType,
ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client*) override;
@@ -48,6 +49,7 @@ class CORE_EXPORT WorkletModuleScriptFetcher final
CrossThreadPersistent<WorkletModuleResponsesMap> module_responses_map_;
KURL url_;
+ ModuleType expected_module_type_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.cc b/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.cc
new file mode 100644
index 00000000000..388f2a229e2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "third_party/blink/renderer/core/loader/no_state_prefetch_client.h"
+
+#include "third_party/blink/public/web/web_no_state_prefetch_client.h"
+#include "third_party/blink/renderer/core/page/page.h"
+
+namespace blink {
+
+// static
+const char NoStatePrefetchClient::kSupplementName[] = "NoStatePrefetchClient";
+
+// static
+NoStatePrefetchClient* NoStatePrefetchClient::From(Page* page) {
+ return Supplement<Page>::From<NoStatePrefetchClient>(page);
+}
+
+NoStatePrefetchClient::NoStatePrefetchClient(Page& page,
+ WebNoStatePrefetchClient* client)
+ : Supplement<Page>(page), client_(client) {}
+
+bool NoStatePrefetchClient::IsPrefetchOnly() {
+ return client_ && client_->IsPrefetchOnly();
+}
+
+void ProvideNoStatePrefetchClientTo(Page& page, NoStatePrefetchClient* client) {
+ NoStatePrefetchClient::ProvideTo(page, client);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.h b/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.h
new file mode 100644
index 00000000000..10eda82ad48
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/no_state_prefetch_client.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_NO_STATE_PREFETCH_CLIENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_NO_STATE_PREFETCH_CLIENT_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Page;
+class WebNoStatePrefetchClient;
+
+class CORE_EXPORT NoStatePrefetchClient
+ : public GarbageCollected<NoStatePrefetchClient>,
+ public Supplement<Page> {
+ public:
+ static const char kSupplementName[];
+
+ NoStatePrefetchClient(Page&, WebNoStatePrefetchClient*);
+
+ virtual bool IsPrefetchOnly();
+
+ static NoStatePrefetchClient* From(Page*);
+
+ private:
+ WebNoStatePrefetchClient* client_;
+
+ DISALLOW_COPY_AND_ASSIGN(NoStatePrefetchClient);
+};
+
+CORE_EXPORT void ProvideNoStatePrefetchClientTo(Page&, NoStatePrefetchClient*);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_NO_STATE_PREFETCH_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
index 05c2c46e108..c596b10f91e 100644
--- a/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/ping_loader_test.cc
@@ -76,7 +76,8 @@ class PingLoaderTest : public PageTestBase {
void SetDocumentURL(const KURL& url) {
GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
diff --git a/chromium/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc b/chromium/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
index 7b9d349f573..fccba8e787e 100644
--- a/chromium/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
+++ b/chromium/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
@@ -235,7 +236,9 @@ PrefetchedSignedExchangeManager::CreateDefaultURLLoader(
request,
frame_->GetFrameScheduler()->CreateResourceLoadingTaskRunnerHandle(),
frame_->GetFrameScheduler()
- ->CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle());
+ ->CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ WebBackForwardCacheLoaderHelper());
}
std::unique_ptr<WebURLLoader>
@@ -249,7 +252,9 @@ PrefetchedSignedExchangeManager::CreatePrefetchedSignedExchangeURLLoader(
request,
frame_->GetFrameScheduler()->CreateResourceLoadingTaskRunnerHandle(),
frame_->GetFrameScheduler()
- ->CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle());
+ ->CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ WebBackForwardCacheLoaderHelper());
}
void PrefetchedSignedExchangeManager::TriggerLoad() {
diff --git a/chromium/third_party/blink/renderer/core/loader/preload_helper.cc b/chromium/third_party/blink/renderer/core/loader/preload_helper.cc
index 22f4bf2b6c8..aa62c8c2f66 100644
--- a/chromium/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/chromium/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
@@ -486,11 +487,12 @@ void PreloadHelper::ModulePreloadIfNeeded(
// metadata is "not-parser-inserted", credentials mode is credentials mode,
// and referrer policy is referrer policy." [spec text]
ModuleScriptFetchRequest request(
- params.href, context_type, destination,
+ params.href, ModuleType::kJavaScript, context_type, destination,
ScriptFetchOptions(params.nonce, integrity_metadata, params.integrity,
kNotParserInserted, credentials_mode,
params.referrer_policy,
- mojom::FetchImportanceMode::kImportanceAuto),
+ mojom::blink::FetchImportanceMode::kImportanceAuto,
+ RenderBlockingBehavior::kNonBlocking),
Referrer::NoReferrer(), TextPosition::MinimumPosition());
// Step 11. "Fetch a single module script given url, settings object,
@@ -695,7 +697,7 @@ Resource* PreloadHelper::StartPreload(ResourceType type,
case ResourceType::kFont:
resource = FontResource::Fetch(params, resource_fetcher, nullptr);
document.GetFontPreloadManager().FontPreloadingStarted(
- ToFontResource(resource));
+ To<FontResource>(resource));
break;
case ResourceType::kAudio:
case ResourceType::kVideo:
diff --git a/chromium/third_party/blink/renderer/core/loader/prerender_handle.cc b/chromium/third_party/blink/renderer/core/loader/prerender_handle.cc
new file mode 100644
index 00000000000..3eddf486f6e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/prerender_handle.cc
@@ -0,0 +1,125 @@
+/*
+ * 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/core/loader/prerender_handle.h"
+
+#include "services/network/public/mojom/referrer_policy.mojom-blink.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
+
+namespace blink {
+
+// static
+PrerenderHandle* PrerenderHandle::Create(
+ Document& document,
+ const KURL& url,
+ mojom::blink::PrerenderRelType prerender_rel_type) {
+ // Prerenders are unlike requests in most ways (for instance, they pass down
+ // fragments, and they don't return data), but they do have referrers.
+
+ if (!document.GetFrame())
+ return nullptr;
+
+ ExecutionContext* context = document.GetExecutionContext();
+ Referrer referrer = SecurityPolicy::GenerateReferrer(
+ context->GetReferrerPolicy(), url, context->OutgoingReferrer());
+
+ auto attributes = mojom::blink::PrerenderAttributes::New();
+ attributes->url = url;
+ attributes->rel_type = prerender_rel_type;
+ attributes->referrer = mojom::blink::Referrer::New(
+ KURL(NullURL(), referrer.referrer), referrer.referrer_policy);
+ attributes->view_size =
+ gfx::Size(document.GetFrame()->GetMainFrameViewportSize());
+
+ HeapMojoRemote<mojom::blink::PrerenderProcessor> prerender_processor(context);
+ HeapMojoRemote<mojom::blink::NoStatePrefetchProcessor> prefetch_processor(
+ context);
+
+ // Run prerendering only when kPrerender2 is enabled and the origin of the
+ // prerendering URL is the same as the origin of the trigger context.
+ // TODO(https://crbug.com/1176054): This is a tentative behavior. We plan to
+ // support cross-origin prerendering later.
+ if (features::IsPrerender2Enabled() &&
+ context->GetSecurityOrigin()->IsSameOriginWith(
+ SecurityOrigin::Create(url).get())) {
+ context->GetBrowserInterfaceBroker().GetInterface(
+ prerender_processor.BindNewPipeAndPassReceiver(
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ prerender_processor->Start(std::move(attributes));
+ } else {
+ context->GetBrowserInterfaceBroker().GetInterface(
+ prefetch_processor.BindNewPipeAndPassReceiver(
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ prefetch_processor->Start(std::move(attributes));
+ }
+ return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, url,
+ std::move(prerender_processor),
+ std::move(prefetch_processor));
+}
+
+PrerenderHandle::PrerenderHandle(
+ PassKey pass_key,
+ ExecutionContext* context,
+ const KURL& url,
+ HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_prerender_processor,
+ HeapMojoRemote<mojom::blink::NoStatePrefetchProcessor>
+ remote_fetch_processor)
+ : url_(url),
+ remote_prerender_processor_(std::move(remote_prerender_processor)),
+ remote_prefetch_processor_(std::move(remote_fetch_processor)) {}
+
+PrerenderHandle::~PrerenderHandle() = default;
+
+void PrerenderHandle::Cancel() {
+ if (remote_prerender_processor_.is_bound())
+ remote_prerender_processor_->Cancel();
+ remote_prerender_processor_.reset();
+
+ if (remote_prefetch_processor_.is_bound())
+ remote_prefetch_processor_->Cancel();
+ remote_prefetch_processor_.reset();
+}
+
+const KURL& PrerenderHandle::Url() const {
+ return url_;
+}
+
+void PrerenderHandle::Trace(Visitor* visitor) const {
+ visitor->Trace(remote_prerender_processor_);
+ visitor->Trace(remote_prefetch_processor_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/prerender_handle.h b/chromium/third_party/blink/renderer/core/loader/prerender_handle.h
new file mode 100644
index 00000000000..085fcabeab0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/prerender_handle.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDER_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDER_HANDLE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/types/pass_key.h"
+#include "third_party/blink/public/mojom/prerender/prerender.mojom-blink.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+class ExecutionContext;
+class Document;
+
+// This is the Blink-side liaison of mojom::PrerenderProcessor to request the
+// browser process to start prerendering. This is instantiated per prerender
+// request, for example, when a new <link rel=prerender> element is added, when
+// the element's href is changed etc.
+//
+// When you no longer need the prerendering page (e.g., when the
+// <link rel=prerender> element is removed), you can ask the browser process to
+// cancel the running prerender by Cancel(). If mojo connections are reset
+// without Cancel() call, the browser process considers this prerendering
+// request to be abandoned and may still use the prerendered page if a
+// navigation occurs to that URL shortly after.
+//
+// TODO(https://crbug.com/1126305): Rename this to PrerenderProcessorClient.
+class PrerenderHandle final : public GarbageCollected<PrerenderHandle> {
+ public:
+ static PrerenderHandle* Create(
+ Document&,
+ const KURL&,
+ mojom::blink::PrerenderRelType prerender_rel_type);
+
+ using PassKey = base::PassKey<PrerenderHandle>;
+ PrerenderHandle(PassKey,
+ ExecutionContext*,
+ const KURL&,
+ HeapMojoRemote<mojom::blink::PrerenderProcessor>,
+ HeapMojoRemote<mojom::blink::NoStatePrefetchProcessor>);
+ ~PrerenderHandle();
+
+ // Asks the browser process to cancel the running prerender.
+ void Cancel();
+
+ const KURL& Url() const;
+
+ virtual void Trace(Visitor*) const;
+
+ private:
+ const KURL url_;
+ HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_prerender_processor_;
+ HeapMojoRemote<mojom::blink::NoStatePrefetchProcessor>
+ remote_prefetch_processor_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderHandle);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDER_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/prerender_test.cc b/chromium/third_party/blink/renderer/core/loader/prerender_test.cc
index c28ee0acfb4..6fde43e6ca7 100644
--- a/chromium/third_party/blink/renderer/core/loader/prerender_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/prerender_test.cc
@@ -33,15 +33,17 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "base/test/scoped_feature_list.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom-blink.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/web/web_frame.h"
-#include "third_party/blink/public/web/web_prerenderer_client.h"
+#include "third_party/blink/public/web/web_no_state_prefetch_client.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_view_client.h"
@@ -57,30 +59,33 @@ namespace blink {
namespace {
-class TestWebPrerendererClient : public WebPrerendererClient {
+class TestWebNoStatePrefetchClient : public WebNoStatePrefetchClient {
public:
- TestWebPrerendererClient() = default;
- virtual ~TestWebPrerendererClient() = default;
+ TestWebNoStatePrefetchClient() = default;
+ virtual ~TestWebNoStatePrefetchClient() = default;
private:
bool IsPrefetchOnly() override { return false; }
};
-class MockPrerenderProcessor : public mojom::blink::PrerenderProcessor {
+class MockPrerenderProcessor : public mojom::blink::PrerenderProcessor,
+ public mojom::blink::NoStatePrefetchProcessor {
public:
explicit MockPrerenderProcessor(
mojo::PendingReceiver<mojom::blink::PrerenderProcessor>
pending_receiver) {
receiver_.Bind(std::move(pending_receiver));
}
+ explicit MockPrerenderProcessor(
+ mojo::PendingReceiver<mojom::blink::NoStatePrefetchProcessor>
+ pending_receiver) {
+ receiver_for_prefetch_.Bind(std::move(pending_receiver));
+ }
~MockPrerenderProcessor() override = default;
// mojom::blink::PrerenderProcessor implementation
- void Start(mojom::blink::PrerenderAttributesPtr attributes,
- mojo::PendingRemote<mojom::blink::PrerenderProcessorClient> client)
- override {
+ void Start(mojom::blink::PrerenderAttributesPtr attributes) override {
attributes_ = std::move(attributes);
- client_.Bind(std::move(client));
}
void Cancel() override { cancel_count_++; }
@@ -92,36 +97,23 @@ class MockPrerenderProcessor : public mojom::blink::PrerenderProcessor {
return attributes_->rel_type;
}
- // Used to simulate state changes of the mock prerendered web page. These
- // calls spin the message loop so that the client's receiver side gets a
- // chance to run.
- void NotifyDidStartPrerender() {
- client_->OnPrerenderStart();
- test::RunPendingTasks();
- }
- void NotifyDidSendDOMContentLoadedForPrerender() {
- client_->OnPrerenderDomContentLoaded();
- test::RunPendingTasks();
- }
- void NotifyDidSendLoadForPrerender() {
- client_->OnPrerenderStopLoading();
- test::RunPendingTasks();
- }
- void NotifyDidStopPrerender() {
- client_->OnPrerenderStop();
- test::RunPendingTasks();
- }
-
private:
mojom::blink::PrerenderAttributesPtr attributes_;
- mojo::Remote<mojom::blink::PrerenderProcessorClient> client_;
mojo::Receiver<mojom::blink::PrerenderProcessor> receiver_{this};
+ mojo::Receiver<mojom::blink::NoStatePrefetchProcessor> receiver_for_prefetch_{
+ this};
size_t cancel_count_ = 0;
};
-class PrerenderTest : public testing::Test {
+class PrerenderTest : public testing::Test,
+ public testing::WithParamInterface<bool> {
public:
+ PrerenderTest() {
+ if (GetParam())
+ feature_list_.InitAndEnableFeature(blink::features::kPrerender2);
+ }
+
~PrerenderTest() override {
if (web_view_helper_.GetWebView())
UnregisterMockPrerenderProcessor();
@@ -132,17 +124,21 @@ class PrerenderTest : public testing::Test {
// TODO(crbug.com/751425): We should use the mock functionality
// via |web_view_helper_|.
url_test_helpers::RegisterMockedURLLoadFromBase(
- WebString::FromUTF8(base_url), blink::test::CoreTestDataPath(),
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
WebString::FromUTF8(file_name));
web_view_helper_.Initialize();
- web_view_helper_.GetWebView()->SetPrerendererClient(&prerenderer_client_);
-
- web_view_helper_.LocalMainFrame()
- ->GetFrame()
- ->GetBrowserInterfaceBroker()
- .SetBinderForTesting(
- mojom::blink::PrerenderProcessor::Name_,
- WTF::BindRepeating(&PrerenderTest::Bind, WTF::Unretained(this)));
+ web_view_helper_.GetWebView()->SetNoStatePrefetchClient(
+ &no_state_prefetch_client_);
+
+ if (features::IsPrerender2Enabled()) {
+ GetBrowserInterfaceBroker().SetBinderForTesting(
+ mojom::blink::PrerenderProcessor::Name_,
+ WTF::BindRepeating(&PrerenderTest::Bind, WTF::Unretained(this)));
+ } else {
+ GetBrowserInterfaceBroker().SetBinderForTesting(
+ mojom::blink::NoStatePrefetchProcessor::Name_,
+ WTF::BindRepeating(&PrerenderTest::Bind, WTF::Unretained(this)));
+ }
frame_test_helpers::LoadFrame(
web_view_helper_.GetWebView()->MainFrameImpl(),
@@ -150,10 +146,17 @@ class PrerenderTest : public testing::Test {
}
void Bind(mojo::ScopedMessagePipeHandle message_pipe_handle) {
- auto processor = std::make_unique<MockPrerenderProcessor>(
- mojo::PendingReceiver<mojom::blink::PrerenderProcessor>(
- std::move(message_pipe_handle)));
- processors_.push_back(std::move(processor));
+ if (features::IsPrerender2Enabled()) {
+ auto processor = std::make_unique<MockPrerenderProcessor>(
+ mojo::PendingReceiver<mojom::blink::PrerenderProcessor>(
+ std::move(message_pipe_handle)));
+ processors_.push_back(std::move(processor));
+ } else {
+ auto processor = std::make_unique<MockPrerenderProcessor>(
+ mojo::PendingReceiver<mojom::blink::NoStatePrefetchProcessor>(
+ std::move(message_pipe_handle)));
+ processors_.push_back(std::move(processor));
+ }
}
void NavigateAway() {
@@ -172,34 +175,6 @@ class PrerenderTest : public testing::Test {
test::RunPendingTasks();
}
- Element& Console() {
- Document* document =
- web_view_helper_.LocalMainFrame()->GetFrame()->GetDocument();
- Element* console = document->getElementById("console");
- DCHECK(IsA<HTMLUListElement>(console));
- return *console;
- }
-
- unsigned ConsoleLength() { return Console().CountChildren() - 1; }
-
- WebString ConsoleAt(unsigned i) {
- DCHECK_GT(ConsoleLength(), i);
-
- Node* item = NodeTraversal::ChildAt(Console(), 1 + i);
-
- DCHECK(item);
- DCHECK(IsA<HTMLLIElement>(item));
- DCHECK(item->hasChildren());
-
- return item->textContent();
- }
-
- bool IsUseCounted(mojom::WebFeature web_feature) {
- Document* document =
- web_view_helper_.LocalMainFrame()->GetFrame()->GetDocument();
- return document->IsUseCounted(web_feature);
- }
-
void ExecuteScript(const char* code) {
web_view_helper_.LocalMainFrame()->ExecuteScript(
WebScriptSource(WebString::FromUTF8(code)));
@@ -212,94 +187,71 @@ class PrerenderTest : public testing::Test {
private:
void UnregisterMockPrerenderProcessor() {
- web_view_helper_.LocalMainFrame()
+ if (features::IsPrerender2Enabled()) {
+ GetBrowserInterfaceBroker().SetBinderForTesting(
+ mojom::blink::PrerenderProcessor::Name_, {});
+ } else {
+ GetBrowserInterfaceBroker().SetBinderForTesting(
+ mojom::blink::NoStatePrefetchProcessor::Name_, {});
+ }
+ }
+
+ BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() {
+ return web_view_helper_.LocalMainFrame()
->GetFrame()
- ->GetBrowserInterfaceBroker()
- .SetBinderForTesting(mojom::blink::PrerenderProcessor::Name_, {});
+ ->GetBrowserInterfaceBroker();
}
std::vector<std::unique_ptr<MockPrerenderProcessor>> processors_;
mojo::ReceiverSet<mojom::blink::PrerenderProcessor> receiver_set_;
- TestWebPrerendererClient prerenderer_client_;
+ TestWebNoStatePrefetchClient no_state_prefetch_client_;
frame_test_helpers::WebViewHelper web_view_helper_;
+
+ base::test::ScopedFeatureList feature_list_;
};
} // namespace
-TEST_F(PrerenderTest, SinglePrerender) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
+INSTANTIATE_TEST_SUITE_P(All, PrerenderTest, testing::Bool());
+
+TEST_P(PrerenderTest, SinglePrerender) {
+ Initialize("http://example.com/", "prerender/single_prerender.html");
ASSERT_EQ(processors().size(), 1u);
MockPrerenderProcessor& processor = *processors()[0];
- EXPECT_EQ(KURL("http://prerender.com/"), processor.Url());
+ EXPECT_EQ(KURL("http://example.com/prerender"), processor.Url());
EXPECT_EQ(mojom::blink::PrerenderRelType::kPrerender, processor.RelType());
EXPECT_EQ(0u, processor.CancelCount());
-
- EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderStartEventFired));
- processor.NotifyDidStartPrerender();
- EXPECT_EQ(1u, ConsoleLength());
- EXPECT_EQ("webkitprerenderstart", ConsoleAt(0));
- EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderStartEventFired));
-
- EXPECT_FALSE(
- IsUseCounted(WebFeature::kWebkitPrerenderDOMContentLoadedEventFired));
- processor.NotifyDidSendDOMContentLoadedForPrerender();
- EXPECT_EQ(2u, ConsoleLength());
- EXPECT_EQ("webkitprerenderdomcontentloaded", ConsoleAt(1));
- EXPECT_TRUE(
- IsUseCounted(WebFeature::kWebkitPrerenderDOMContentLoadedEventFired));
-
- EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderLoadEventFired));
- processor.NotifyDidSendLoadForPrerender();
- EXPECT_EQ(3u, ConsoleLength());
- EXPECT_EQ("webkitprerenderload", ConsoleAt(2));
- EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderLoadEventFired));
-
- EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderStopEventFired));
- processor.NotifyDidStopPrerender();
- EXPECT_EQ(4u, ConsoleLength());
- EXPECT_EQ("webkitprerenderstop", ConsoleAt(3));
- EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderStopEventFired));
}
-TEST_F(PrerenderTest, CancelPrerender) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
+TEST_P(PrerenderTest, CancelPrerender) {
+ Initialize("http://example.com/", "prerender/single_prerender.html");
ASSERT_EQ(processors().size(), 1u);
MockPrerenderProcessor& processor = *processors()[0];
EXPECT_EQ(0u, processor.CancelCount());
-
ExecuteScript("removePrerender()");
-
EXPECT_EQ(1u, processor.CancelCount());
}
-TEST_F(PrerenderTest, TwoPrerenders) {
- Initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
+TEST_P(PrerenderTest, TwoPrerenders) {
+ Initialize("http://example.com/", "prerender/multiple_prerenders.html");
ASSERT_EQ(processors().size(), 2u);
MockPrerenderProcessor& first_processor = *processors()[0];
- EXPECT_EQ(KURL("http://first-prerender.com/"), first_processor.Url());
+ EXPECT_EQ(KURL("http://example.com/first"), first_processor.Url());
MockPrerenderProcessor& second_processor = *processors()[1];
- EXPECT_EQ(KURL("http://second-prerender.com/"), second_processor.Url());
+ EXPECT_EQ(KURL("http://example.com/second"), second_processor.Url());
EXPECT_EQ(0u, first_processor.CancelCount());
EXPECT_EQ(0u, second_processor.CancelCount());
-
- first_processor.NotifyDidStartPrerender();
- EXPECT_EQ(1u, ConsoleLength());
- EXPECT_EQ("first_webkitprerenderstart", ConsoleAt(0));
-
- second_processor.NotifyDidStartPrerender();
- EXPECT_EQ(2u, ConsoleLength());
- EXPECT_EQ("second_webkitprerenderstart", ConsoleAt(1));
}
-TEST_F(PrerenderTest, TwoPrerendersRemovingFirstThenNavigating) {
- Initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
+TEST_P(PrerenderTest, TwoPrerendersRemovingFirstThenNavigating) {
+ Initialize("http://example.com/", "prerender/multiple_prerenders.html");
ASSERT_EQ(processors().size(), 2u);
MockPrerenderProcessor& first_processor = *processors()[0];
@@ -319,8 +271,8 @@ TEST_F(PrerenderTest, TwoPrerendersRemovingFirstThenNavigating) {
EXPECT_EQ(0u, second_processor.CancelCount());
}
-TEST_F(PrerenderTest, TwoPrerendersAddingThird) {
- Initialize("http://www.foo.com/", "prerender/multiple_prerenders.html");
+TEST_P(PrerenderTest, TwoPrerendersAddingThird) {
+ Initialize("http://example.com/", "prerender/multiple_prerenders.html");
ASSERT_EQ(processors().size(), 2u);
MockPrerenderProcessor& first_processor = *processors()[0];
@@ -339,46 +291,12 @@ TEST_F(PrerenderTest, TwoPrerendersAddingThird) {
EXPECT_EQ(0u, third_processor.CancelCount());
}
-TEST_F(PrerenderTest, ShortLivedClient) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
- ASSERT_EQ(processors().size(), 1u);
- MockPrerenderProcessor& processor = *processors()[0];
-
- EXPECT_EQ(0u, processor.CancelCount());
-
- NavigateAway();
- Close();
-
- // This test passes if this next line doesn't crash.
- processor.NotifyDidStartPrerender();
-}
-
-TEST_F(PrerenderTest, FastRemoveElement) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
- ASSERT_EQ(processors().size(), 1u);
- MockPrerenderProcessor& processor = *processors()[0];
-
- EXPECT_EQ(0u, processor.CancelCount());
-
- // Race removing & starting the prerender against each other, as if the
- // element was removed very quickly.
- ExecuteScript("removePrerender()");
- processor.NotifyDidStartPrerender();
-
- // Removing the element should cancel prerendering.
- EXPECT_EQ(1u, processor.CancelCount());
-
- // The page should be totally disconnected from the Prerender at this point,
- // so the console should not have updated.
- EXPECT_EQ(0u, ConsoleLength());
-}
-
-TEST_F(PrerenderTest, MutateTarget) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
+TEST_P(PrerenderTest, MutateTarget) {
+ Initialize("http://example.com/", "prerender/single_prerender.html");
ASSERT_EQ(processors().size(), 1u);
MockPrerenderProcessor& processor = *processors()[0];
- EXPECT_EQ(KURL("http://prerender.com/"), processor.Url());
+ EXPECT_EQ(KURL("http://example.com/prerender"), processor.Url());
EXPECT_EQ(0u, processor.CancelCount());
@@ -388,18 +306,18 @@ TEST_F(PrerenderTest, MutateTarget) {
ASSERT_EQ(processors().size(), 2u);
MockPrerenderProcessor& mutated_processor = *processors()[1];
- EXPECT_EQ(KURL("http://mutated.com/"), mutated_processor.Url());
+ EXPECT_EQ(KURL("http://example.com/mutated"), mutated_processor.Url());
EXPECT_EQ(1u, processor.CancelCount());
EXPECT_EQ(0u, mutated_processor.CancelCount());
}
-TEST_F(PrerenderTest, MutateRel) {
- Initialize("http://www.foo.com/", "prerender/single_prerender.html");
+TEST_P(PrerenderTest, MutateRel) {
+ Initialize("http://example.com/", "prerender/single_prerender.html");
ASSERT_EQ(processors().size(), 1u);
MockPrerenderProcessor& processor = *processors()[0];
- EXPECT_EQ(KURL("http://prerender.com/"), processor.Url());
+ EXPECT_EQ(KURL("http://example.com/prerender"), processor.Url());
EXPECT_EQ(0u, processor.CancelCount());
diff --git a/chromium/third_party/blink/renderer/core/loader/prerenderer_client.cc b/chromium/third_party/blink/renderer/core/loader/prerenderer_client.cc
deleted file mode 100644
index 6e194ca6a51..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/prerenderer_client.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "third_party/blink/renderer/core/loader/prerenderer_client.h"
-
-#include "third_party/blink/public/web/web_prerenderer_client.h"
-#include "third_party/blink/renderer/core/page/page.h"
-
-namespace blink {
-
-// static
-const char PrerendererClient::kSupplementName[] = "PrerendererClient";
-
-// static
-PrerendererClient* PrerendererClient::From(Page* page) {
- return Supplement<Page>::From<PrerendererClient>(page);
-}
-
-PrerendererClient::PrerendererClient(Page& page, WebPrerendererClient* client)
- : Supplement<Page>(page), client_(client) {}
-
-bool PrerendererClient::IsPrefetchOnly() {
- return client_ && client_->IsPrefetchOnly();
-}
-
-void ProvidePrerendererClientTo(Page& page, PrerendererClient* client) {
- PrerendererClient::ProvideTo(page, client);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/prerenderer_client.h b/chromium/third_party/blink/renderer/core/loader/prerenderer_client.h
deleted file mode 100644
index b97ba41fbbe..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/prerenderer_client.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDERER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDERER_CLIENT_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Page;
-class WebPrerendererClient;
-
-class CORE_EXPORT PrerendererClient
- : public GarbageCollected<PrerendererClient>,
- public Supplement<Page> {
- public:
- static const char kSupplementName[];
-
- PrerendererClient(Page&, WebPrerendererClient*);
-
- virtual bool IsPrefetchOnly();
-
- static PrerendererClient* From(Page*);
-
- private:
- WebPrerendererClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(PrerendererClient);
-};
-
-CORE_EXPORT void ProvidePrerendererClientTo(Page&, PrerendererClient*);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRERENDERER_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc b/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc
deleted file mode 100644
index dadf221af29..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
-
-#include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_macros.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-namespace {
-
-String GetConsoleLogStringForBlockedLoad(const KURL& url) {
- return "[Intervention] Non-critical resource " + url.GetString() +
- " is blocked due to page load being slow. Learn more at "
- "https://www.chromestatus.com/feature/4510564810227712.";
-}
-
-} // namespace
-
-// static
-PreviewsResourceLoadingHints* PreviewsResourceLoadingHints::Create(
- ExecutionContext& execution_context,
- int64_t ukm_source_id,
- const WebVector<WebString>& subresource_patterns_to_block) {
- return MakeGarbageCollected<PreviewsResourceLoadingHints>(
- &execution_context, ukm_source_id, subresource_patterns_to_block);
-}
-
-// static
-PreviewsResourceLoadingHints*
-PreviewsResourceLoadingHints::CreateFromLoadingHintsProvider(
- ExecutionContext& execution_context,
- std::unique_ptr<WebLoadingHintsProvider> loading_hints_provider) {
- WebVector<WebString> subresource_patterns_to_block;
- for (const auto& pattern :
- loading_hints_provider->subresource_patterns_to_block) {
- // |pattern| is guaranteed to be ascii.
- subresource_patterns_to_block.emplace_back(pattern);
- }
-
- return MakeGarbageCollected<PreviewsResourceLoadingHints>(
- &execution_context, loading_hints_provider->ukm_source_id,
- subresource_patterns_to_block);
-}
-
-PreviewsResourceLoadingHints::PreviewsResourceLoadingHints(
- ExecutionContext* execution_context,
- int64_t ukm_source_id,
- const WebVector<WebString>& subresource_patterns_to_block)
- : execution_context_(execution_context),
- ukm_source_id_(ukm_source_id),
- subresource_patterns_to_block_(subresource_patterns_to_block) {
- DCHECK_NE(ukm::kInvalidSourceId, ukm_source_id_);
-
- subresource_patterns_to_block_usage_.Fill(
- false,
- static_cast<WTF::wtf_size_t>(subresource_patterns_to_block.size()));
- blocked_resource_load_priority_counts_.Fill(
- 0, static_cast<int>(ResourceLoadPriority::kHighest) + 1);
-
- // Populate which specific resource types are eligible for blocking.
- // Certain resource types are blocked by default since their blocking
- // is currently verified by the server verification pipeline. Note that
- // the blocking of these resource types can be overridden using field trial.
- block_resource_type_[static_cast<int>(ResourceType::kCSSStyleSheet)] = true;
- block_resource_type_[static_cast<int>(ResourceType::kScript)] = true;
- block_resource_type_[static_cast<int>(ResourceType::kRaw)] = true;
- block_resource_type_[static_cast<int>(ResourceType::kFont)] = true;
- for (int i = 0; i < static_cast<int>(ResourceType::kMaxValue) + 1; ++i) {
- // Parameter names are of format: "block_resource_type_%d". The value
- // should be either "true" or "false".
- block_resource_type_[i] = base::GetFieldTrialParamByFeatureAsBool(
- features::kPreviewsResourceLoadingHintsSpecificResourceTypes,
- String::Format("block_resource_type_%d", i).Ascii(),
- block_resource_type_[i]);
- }
-
- // Ensure that the ResourceType enums have not changed. These should not be
- // changed since the resource type integer values are used as field trial
- // params.
- static_assert(static_cast<int>(ResourceType::kImage) == 1 &&
- static_cast<int>(ResourceType::kCSSStyleSheet) == 2 &&
- static_cast<int>(ResourceType::kScript) == 3,
- "ResourceType enums can't be changed");
-}
-
-PreviewsResourceLoadingHints::~PreviewsResourceLoadingHints() = default;
-
-bool PreviewsResourceLoadingHints::AllowLoad(
- ResourceType type,
- const KURL& resource_url,
- ResourceLoadPriority resource_load_priority) const {
- if (!resource_url.ProtocolIsInHTTPFamily())
- return true;
-
- if (!block_resource_type_[static_cast<int>(type)])
- return true;
-
- WTF::String resource_url_string = resource_url.GetString();
- resource_url_string = resource_url_string.Left(resource_url.PathEnd());
- bool allow_load = true;
-
- int pattern_index = 0;
- for (const WebString& subresource_pattern : subresource_patterns_to_block_) {
- // TODO(tbansal): https://crbug.com/856247. Add support for wildcard
- // matching.
- if (resource_url_string.Find(subresource_pattern) != kNotFound) {
- allow_load = false;
- subresource_patterns_to_block_usage_[pattern_index] = true;
- blocked_resource_load_priority_counts_[static_cast<int>(
- resource_load_priority)]++;
- break;
- }
- pattern_index++;
- }
-
- UMA_HISTOGRAM_BOOLEAN("ResourceLoadingHints.ResourceLoadingBlocked",
- !allow_load);
- if (!allow_load) {
- ReportBlockedLoading(resource_url);
- UMA_HISTOGRAM_ENUMERATION(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Blocked",
- resource_load_priority,
- static_cast<int>(ResourceLoadPriority::kHighest) + 1);
- } else {
- UMA_HISTOGRAM_ENUMERATION(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Allowed",
- resource_load_priority,
- static_cast<int>(ResourceLoadPriority::kHighest) + 1);
- }
- return allow_load;
-}
-
-void PreviewsResourceLoadingHints::ReportBlockedLoading(
- const KURL& resource_url) const {
- execution_context_->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kOther, mojom::ConsoleMessageLevel::kWarning,
- GetConsoleLogStringForBlockedLoad(resource_url)));
-}
-
-void PreviewsResourceLoadingHints::Trace(Visitor* visitor) const {
- visitor->Trace(execution_context_);
-}
-
-void PreviewsResourceLoadingHints::RecordUKM(
- ukm::UkmRecorder* ukm_recorder) const {
- DCHECK(ukm_recorder);
-
- size_t patterns_to_block_used_count = 0;
- for (bool pattern_used : subresource_patterns_to_block_usage_) {
- if (pattern_used) {
- patterns_to_block_used_count++;
- }
- }
-
- ukm::builders::PreviewsResourceLoadingHints(ukm_source_id_)
- .Setpatterns_to_block_total(subresource_patterns_to_block_.size())
- .Setpatterns_to_block_used(patterns_to_block_used_count)
- .Setblocked_very_low_priority(
- blocked_resource_load_priority_counts_[static_cast<int>(
- ResourceLoadPriority::kVeryLow)])
- .Setblocked_low_priority(
- blocked_resource_load_priority_counts_[static_cast<int>(
- ResourceLoadPriority::kLow)])
- .Setblocked_medium_priority(
- blocked_resource_load_priority_counts_[static_cast<int>(
- ResourceLoadPriority::kMedium)])
- .Setblocked_high_priority(
- blocked_resource_load_priority_counts_[static_cast<int>(
- ResourceLoadPriority::kHigh)])
- .Setblocked_very_high_priority(
- blocked_resource_load_priority_counts_[static_cast<int>(
- ResourceLoadPriority::kVeryHigh)])
- .Record(ukm_recorder);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h b/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h
deleted file mode 100644
index ecefad6ce83..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
-
-#include "base/feature_list.h"
-#include "third_party/blink/public/platform/web_loading_hints_provider.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace ukm {
-class UkmRecorder;
-}
-
-namespace blink {
-
-class ExecutionContext;
-class KURL;
-
-// PreviewsResourceLoadingHints stores the resource loading hints that apply to
-// a single document.
-class CORE_EXPORT PreviewsResourceLoadingHints final
- : public GarbageCollected<PreviewsResourceLoadingHints> {
- public:
- static PreviewsResourceLoadingHints* Create(
- ExecutionContext& execution_context,
- int64_t ukm_source_id,
- const WebVector<WebString>& subresource_patterns_to_block);
-
- static PreviewsResourceLoadingHints* CreateFromLoadingHintsProvider(
- ExecutionContext& execution_context,
- std::unique_ptr<WebLoadingHintsProvider> loading_hints_provider);
-
- PreviewsResourceLoadingHints(
- ExecutionContext* execution_context,
- int64_t ukm_source_id,
- const WebVector<WebString>& subresource_patterns_to_block);
- ~PreviewsResourceLoadingHints();
-
- // Returns true if load of resource with type |type|, URL |resource_url|
- // and priority |resource_load_priority| is allowed as per resource loading
- // hints.
- bool AllowLoad(ResourceType type,
- const KURL& resource_url,
- ResourceLoadPriority resource_load_priority) const;
-
- virtual void Trace(Visitor*) const;
-
- // Records UKM on the utilization of patterns to block during the document
- // load. This is expected to be called once after the document finishes
- // loading.
- void RecordUKM(ukm::UkmRecorder* ukm_recorder) const;
-
- private:
- // Reports to console when loading of |resource_url| is blocked.
- void ReportBlockedLoading(const KURL& resource_url) const;
-
- Member<ExecutionContext> execution_context_;
- const int64_t ukm_source_id_;
-
- // |subresource_patterns_to_block_| is a collection of subresource patterns
- // for resources whose loading should be blocked. Each pattern is a
- // WebString. If a subresource URL contains any of the strings specified in
- // |subresource_patterns_to_block_|, then that subresource's loading could
- // be blocked.
- const WebVector<WebString> subresource_patterns_to_block_;
-
- // True if resource blocking hints should apply to resource of a given type.
- bool block_resource_type_[static_cast<int>(ResourceType::kMaxValue) + 1] = {
- false};
-
- // |subresource_patterns_to_block_usage_| records whether the pattern located
- // at the same index in |subresource_patterns_to_block_| was ever blocked.
- mutable Vector<bool> subresource_patterns_to_block_usage_;
-
- // |blocked_resource_load_priority_counts_| records the total number of
- // resources blocked at each ResourceLoadPriority.
- mutable Vector<int> blocked_resource_load_priority_counts_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc b/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
deleted file mode 100644
index fff74cd93db..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/previews_resource_loading_hints_test.cc
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
-
-#include <memory>
-
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.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/loader/frame_loader.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/geometry/int_size.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
-#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-namespace {
-
-class PreviewsResourceLoadingHintsTest : public PageTestBase {
- public:
- PreviewsResourceLoadingHintsTest() {
- dummy_page_holder_ = std::make_unique<DummyPageHolder>(IntSize(1, 1));
- }
-
- protected:
- std::unique_ptr<DummyPageHolder> dummy_page_holder_;
-};
-
-TEST_F(PreviewsResourceLoadingHintsTest, NoPatterns) {
- Vector<WTF::String> subresources_to_block;
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
- EXPECT_TRUE(hints->AllowLoad(ResourceType::kScript,
- KURL("https://www.example.com/"),
- ResourceLoadPriority::kHighest));
-}
-
-TEST_F(PreviewsResourceLoadingHintsTest, OnePattern) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back("foo.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- bool allow_load_expected;
- } tests[] = {
- {KURL("https://www.example.com/"), true},
- {KURL("https://www.example.com/foo.js"), true},
- {KURL("https://www.example.com/foo.jpg"), false},
- {KURL("https://www.example.com/pages/foo.jpg"), false},
- {KURL("https://www.example.com/foobar.jpg"), true},
- {KURL("https://www.example.com/barfoo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg?q=alpha"), false},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true},
- };
-
- for (const auto& test : tests) {
- base::HistogramTester histogram_tester;
- // By default, resource blocking hints do not apply to images.
- EXPECT_TRUE(hints->AllowLoad(ResourceType::kImage, test.url,
- ResourceLoadPriority::kHighest));
- // By default, resource blocking hints apply to CSS and Scripts.
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kCSSStyleSheet, test.url,
- ResourceLoadPriority::kHighest));
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kScript, test.url,
- ResourceLoadPriority::kHighest));
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked",
- !test.allow_load_expected, 2);
- if (!test.allow_load_expected) {
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Blocked",
- ResourceLoadPriority::kHighest, 2);
- histogram_tester.ExpectTotalCount(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Allowed",
- 0);
- } else {
- histogram_tester.ExpectTotalCount(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Blocked",
- 0);
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Allowed",
- ResourceLoadPriority::kHighest, 2);
- }
- }
-}
-
-TEST_F(PreviewsResourceLoadingHintsTest, MultiplePatterns) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back(".example1.com/foo.jpg");
- subresources_to_block.push_back(".example1.com/bar.jpg");
- subresources_to_block.push_back(".example2.com/baz.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- bool allow_load_expected;
- } tests[] = {
- {KURL("https://www.example1.com/"), true},
- {KURL("https://www.example1.com/foo.js"), true},
- {KURL("https://www.example1.com/foo.jpg"), false},
- {KURL("https://www.example1.com/pages/foo.jpg"), true},
- {KURL("https://www.example1.com/foobar.jpg"), true},
- {KURL("https://www.example1.com/barfoo.jpg"), true},
- {KURL("http://www.example1.com/foo.jpg"), false},
- {KURL("http://www.example1.com/bar.jpg"), false},
- {KURL("http://www.example2.com/baz.jpg"), false},
- {KURL("http://www.example2.com/pages/baz.jpg"), true},
- {KURL("http://www.example2.com/baz.html"), true},
- };
-
- for (const auto& test : tests) {
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kScript, test.url,
- ResourceLoadPriority::kHighest));
- }
-}
-
-TEST_F(PreviewsResourceLoadingHintsTest, OnePatternHistogramChecker) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back("foo.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- bool allow_load_expected;
- ResourceLoadPriority resource_load_priority;
- } tests[] = {
- {KURL("https://www.example.com/foo.js"), true,
- ResourceLoadPriority::kLow},
- {KURL("https://www.example.com/foo.jpg"), false,
- ResourceLoadPriority::kLow},
- {KURL("https://www.example.com/foo.js"), true,
- ResourceLoadPriority::kMedium},
- {KURL("https://www.example.com/foo.jpg"), false,
- ResourceLoadPriority::kMedium},
- };
-
- for (const auto& test : tests) {
- base::HistogramTester histogram_tester;
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kScript, test.url,
- test.resource_load_priority));
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked",
- !test.allow_load_expected, 1);
- if (!test.allow_load_expected) {
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Blocked",
- test.resource_load_priority, 1);
- histogram_tester.ExpectTotalCount(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Allowed",
- 0);
- } else {
- histogram_tester.ExpectTotalCount(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Blocked",
- 0);
- histogram_tester.ExpectUniqueSample(
- "ResourceLoadingHints.ResourceLoadingBlocked.ResourceLoadPriority."
- "Allowed",
- test.resource_load_priority, 1);
- }
- }
-}
-
-TEST_F(PreviewsResourceLoadingHintsTest, MultiplePatternUKMChecker) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back(".example1.com/low_1.jpg");
- subresources_to_block.push_back(".example1.com/very_low_1.jpg");
- subresources_to_block.push_back(".example1.com/very_high_1.jpg");
- subresources_to_block.push_back(".example1.com/medium_1_and_medium_4.jpg");
- subresources_to_block.push_back(".example1.com/unused_1.jpg");
- subresources_to_block.push_back(".example2.com/medium_2.jpg");
- subresources_to_block.push_back(".example2.com/unused_2.jpg");
- subresources_to_block.push_back(".example3.com/unused_3.jpg");
- subresources_to_block.push_back(".example3.com/very_low_2_and_medium_3.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- ResourceLoadPriority resource_load_priority;
- } resources_to_load[] = {
- {KURL("https://www.example1.com/"), ResourceLoadPriority::kHigh},
- {KURL("https://www.example1.com/foo.js"), ResourceLoadPriority::kLow},
- {KURL("https://www.example1.com/very_low_1.jpg"),
- ResourceLoadPriority::kVeryLow},
- {KURL("https://www.example1.com/low_1.jpg"), ResourceLoadPriority::kLow},
- {KURL("https://www.example1.com/very_high_1.jpg"),
- ResourceLoadPriority::kVeryHigh},
- {KURL("https://www.example1.com/pages/foo.jpg"),
- ResourceLoadPriority::kVeryLow},
- {KURL("https://www.example1.com/foobar.jpg"),
- ResourceLoadPriority::kVeryHigh},
- {KURL("https://www.example1.com/barfoo.jpg"),
- ResourceLoadPriority::kVeryHigh},
- {KURL("http://www.example1.com/foo.jpg"), ResourceLoadPriority::kLow},
- {KURL("http://www.example1.com/medium_1_and_medium_4.jpg"),
- ResourceLoadPriority::kMedium},
- {KURL("http://www.example2.com/medium_2.jpg"),
- ResourceLoadPriority::kMedium},
- {KURL("http://www.example2.com/pages/baz.jpg"),
- ResourceLoadPriority::kLow},
- {KURL("http://www.example2.com/baz.html"),
- ResourceLoadPriority::kVeryHigh},
- {KURL("http://www.example3.com/very_low_2_and_medium_3.jpg"),
- ResourceLoadPriority::kVeryLow},
- {KURL("http://www.example3.com/very_low_2_and_medium_3.jpg"),
- ResourceLoadPriority::kMedium},
- {KURL("http://www.example1.com/medium_1_and_medium_4.jpg"),
- ResourceLoadPriority::kMedium},
- };
-
- for (const auto& resource_to_load : resources_to_load) {
- hints->AllowLoad(ResourceType::kScript, resource_to_load.url,
- resource_to_load.resource_load_priority);
- }
-
- ukm::TestAutoSetUkmRecorder test_ukm_recorder;
- hints->RecordUKM(&test_ukm_recorder);
-
- using UkmEntry = ukm::builders::PreviewsResourceLoadingHints;
- auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
- ASSERT_EQ(1u, entries.size());
- const auto* entry = entries[0];
- test_ukm_recorder.ExpectEntryMetric(
- entry, UkmEntry::kpatterns_to_block_totalName, 9);
- test_ukm_recorder.ExpectEntryMetric(entry,
- UkmEntry::kpatterns_to_block_usedName, 6);
- test_ukm_recorder.ExpectEntryMetric(
- entry, UkmEntry::kblocked_very_low_priorityName, 2);
- test_ukm_recorder.ExpectEntryMetric(entry,
- UkmEntry::kblocked_low_priorityName, 1);
- test_ukm_recorder.ExpectEntryMetric(
- entry, UkmEntry::kblocked_medium_priorityName, 4);
- test_ukm_recorder.ExpectEntryMetric(entry,
- UkmEntry::kblocked_high_priorityName, 0);
- test_ukm_recorder.ExpectEntryMetric(
- entry, UkmEntry::kblocked_very_high_priorityName, 1);
-}
-
-// Test class that overrides field trial so that resource blocking hints apply
-// to images as well.
-class PreviewsResourceLoadingHintsTestBlockImages
- : public PreviewsResourceLoadingHintsTest {
- public:
- PreviewsResourceLoadingHintsTestBlockImages() = default;
-
- void SetUp() override {
- std::map<std::string, std::string> feature_parameters;
- feature_parameters["block_resource_type_1"] = "true";
-
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- blink::features::kPreviewsResourceLoadingHintsSpecificResourceTypes,
- feature_parameters);
- }
-
- protected:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(PreviewsResourceLoadingHintsTestBlockImages,
- OnePatternWithResourceSubtype) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back("foo.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- bool allow_load_expected;
- } tests[] = {
- {KURL("https://www.example.com/"), true},
- {KURL("https://www.example.com/foo.js"), true},
- {KURL("https://www.example.com/foo.jpg"), false},
- {KURL("https://www.example.com/pages/foo.jpg"), false},
- {KURL("https://www.example.com/foobar.jpg"), true},
- {KURL("https://www.example.com/barfoo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg?q=alpha"), false},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true},
- };
-
- for (const auto& test : tests) {
- // By default, resource blocking hints do not apply to SVG documents.
- EXPECT_TRUE(hints->AllowLoad(ResourceType::kSVGDocument, test.url,
- ResourceLoadPriority::kHighest));
- // Feature override should cause resource blocking hints to apply to images.
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kImage, test.url,
- ResourceLoadPriority::kHighest));
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kScript, test.url,
- ResourceLoadPriority::kHighest));
- }
-}
-
-// Test class that overrides field trial so that resource blocking hints do not
-// apply to CSS.
-class PreviewsResourceLoadingHintsTestAllowCSS
- : public PreviewsResourceLoadingHintsTestBlockImages {
- public:
- PreviewsResourceLoadingHintsTestAllowCSS() = default;
-
- void SetUp() override {
- std::map<std::string, std::string> feature_parameters;
- feature_parameters["block_resource_type_2"] = "false";
-
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- blink::features::kPreviewsResourceLoadingHintsSpecificResourceTypes,
- feature_parameters);
- }
-};
-
-TEST_F(PreviewsResourceLoadingHintsTestAllowCSS,
- OnePatternWithResourceSubtype) {
- Vector<WTF::String> subresources_to_block;
- subresources_to_block.push_back("foo.jpg");
-
- PreviewsResourceLoadingHints* hints = PreviewsResourceLoadingHints::Create(
- *dummy_page_holder_->GetFrame().DomWindow(),
- ukm::UkmRecorder::GetNewSourceID(), subresources_to_block);
-
- const struct {
- KURL url;
- bool allow_load_expected;
- } tests[] = {
- {KURL("https://www.example.com/"), true},
- {KURL("https://www.example.com/foo.js"), true},
- {KURL("https://www.example.com/foo.jpg"), false},
- {KURL("https://www.example.com/pages/foo.jpg"), false},
- {KURL("https://www.example.com/foobar.jpg"), true},
- {KURL("https://www.example.com/barfoo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg"), false},
- {KURL("http://www.example.com/foo.jpg?q=alpha"), false},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg"), true},
- {KURL("http://www.example.com/bar.jpg?q=foo.jpg#foo.jpg"), true},
- };
-
- for (const auto& test : tests) {
- // Feature override should cause resource blocking hints to apply to only
- // scripts and fonts.
- EXPECT_TRUE(hints->AllowLoad(ResourceType::kImage, test.url,
- ResourceLoadPriority::kHighest));
- EXPECT_TRUE(hints->AllowLoad(ResourceType::kCSSStyleSheet, test.url,
- ResourceLoadPriority::kHighest));
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kScript, test.url,
- ResourceLoadPriority::kHighest));
- EXPECT_EQ(test.allow_load_expected,
- hints->AllowLoad(ResourceType::kFont, test.url,
- ResourceLoadPriority::kHighest));
- }
-}
-
-} // namespace
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc b/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
deleted file mode 100644
index df4d9667a1e..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
-
-#include "base/stl_util.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-namespace {
-
-// Mapping from WebClientHintsType to WebFeature. The ordering should match the
-// ordering of enums in WebClientHintsType.
-static constexpr WebFeature kWebFeatureMapping[] = {
- WebFeature::kClientHintsDeviceMemory,
- WebFeature::kClientHintsDPR,
- WebFeature::kClientHintsResourceWidth,
- WebFeature::kClientHintsViewportWidth,
- WebFeature::kClientHintsRtt,
- WebFeature::kClientHintsDownlink,
- WebFeature::kClientHintsEct,
- WebFeature::kClientHintsLang,
- WebFeature::kClientHintsUA,
- WebFeature::kClientHintsUAArch,
- WebFeature::kClientHintsUAPlatform,
- WebFeature::kClientHintsUAModel,
- WebFeature::kClientHintsUAMobile,
- WebFeature::kClientHintsUAFullVersion,
- WebFeature::kClientHintsUAPlatformVersion,
-};
-
-static_assert(static_cast<int>(network::mojom::WebClientHintsType::kMaxValue) +
- 1 ==
- base::size(kWebFeatureMapping),
- "unhandled client hint type");
-
-} // namespace
-
-FrameClientHintsPreferencesContext::FrameClientHintsPreferencesContext(
- LocalFrame* frame)
- : frame_(frame) {}
-
-void FrameClientHintsPreferencesContext::CountClientHints(
- network::mojom::WebClientHintsType type) {
- UseCounter::Count(*frame_->GetDocument(),
- kWebFeatureMapping[static_cast<int32_t>(type)]);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h b/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h
deleted file mode 100644
index 84b2185713f..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
-
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class LocalFrame;
-
-class FrameClientHintsPreferencesContext final
- : public ClientHintsPreferences::Context {
- STACK_ALLOCATED();
-
- public:
- explicit FrameClientHintsPreferencesContext(LocalFrame*);
-
- void CountClientHints(network::mojom::WebClientHintsType) override;
-
- private:
- LocalFrame* frame_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_FRAME_CLIENT_HINTS_PREFERENCES_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/private/prerender_client.h b/chromium/third_party/blink/renderer/core/loader/private/prerender_client.h
deleted file mode 100644
index 9965225e95f..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/private/prerender_client.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT PrerenderClient : public GarbageCollectedMixin {
- public:
- virtual ~PrerenderClient() = default;
-
- virtual void DidStartPrerender() = 0;
- virtual void DidStopPrerender() = 0;
- virtual void DidSendLoadForPrerender() = 0;
- virtual void DidSendDOMContentLoadedForPrerender() = 0;
-
- void Trace(Visitor* visitor) const override {}
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.cc b/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.cc
deleted file mode 100644
index 00330814baa..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/loader/private/prerender_handle.h"
-
-#include "services/network/public/mojom/referrer_policy.mojom-blink.h"
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/core/loader/private/prerender_client.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
-
-namespace blink {
-
-// static
-PrerenderHandle* PrerenderHandle::Create(
- Document& document,
- PrerenderClient* client,
- const KURL& url,
- mojom::blink::PrerenderRelType prerender_rel_type) {
- // Prerenders are unlike requests in most ways (for instance, they pass down
- // fragments, and they don't return data), but they do have referrers.
-
- if (!document.GetFrame())
- return nullptr;
-
- ExecutionContext* context = document.GetExecutionContext();
- Referrer referrer = SecurityPolicy::GenerateReferrer(
- context->GetReferrerPolicy(), url, context->OutgoingReferrer());
-
- auto attributes = mojom::blink::PrerenderAttributes::New();
- attributes->url = url;
- attributes->rel_type = prerender_rel_type;
- attributes->referrer = mojom::blink::Referrer::New(
- KURL(NullURL(), referrer.referrer), referrer.referrer_policy);
- attributes->view_size =
- gfx::Size(document.GetFrame()->GetMainFrameViewportSize());
-
- HeapMojoRemote<mojom::blink::PrerenderProcessor> prerender_processor(context);
- context->GetBrowserInterfaceBroker().GetInterface(
- prerender_processor.BindNewPipeAndPassReceiver(
- context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
-
- mojo::PendingRemote<mojom::blink::PrerenderProcessorClient>
- prerender_processor_client;
- auto receiver = prerender_processor_client.InitWithNewPipeAndPassReceiver();
-
- prerender_processor->Start(std::move(attributes),
- std::move(prerender_processor_client));
-
- return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, client, url,
- std::move(prerender_processor),
- std::move(receiver));
-}
-
-PrerenderHandle::PrerenderHandle(
- PassKey pass_key,
- ExecutionContext* context,
- PrerenderClient* client,
- const KURL& url,
- HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor,
- mojo::PendingReceiver<mojom::blink::PrerenderProcessorClient> receiver)
- : url_(url),
- client_(client),
- remote_processor_(std::move(remote_processor)),
- receiver_(this, context) {
- receiver_.Bind(std::move(receiver),
- context->GetTaskRunner(TaskType::kMiscPlatformAPI));
-}
-
-PrerenderHandle::~PrerenderHandle() = default;
-
-void PrerenderHandle::Cancel() {
- if (remote_processor_.is_bound())
- remote_processor_->Cancel();
- remote_processor_.reset();
- receiver_.reset();
-}
-
-const KURL& PrerenderHandle::Url() const {
- return url_;
-}
-
-void PrerenderHandle::OnPrerenderStart() {
- if (client_)
- client_->DidStartPrerender();
-}
-
-void PrerenderHandle::OnPrerenderStopLoading() {
- if (client_)
- client_->DidSendLoadForPrerender();
-}
-
-void PrerenderHandle::OnPrerenderDomContentLoaded() {
- if (client_)
- client_->DidSendDOMContentLoadedForPrerender();
-}
-
-void PrerenderHandle::OnPrerenderStop() {
- if (client_)
- client_->DidStopPrerender();
-}
-
-void PrerenderHandle::Trace(Visitor* visitor) const {
- visitor->Trace(client_);
- visitor->Trace(remote_processor_);
- visitor->Trace(receiver_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.h b/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.h
deleted file mode 100644
index e57bee1aa9d..00000000000
--- a/chromium/third_party/blink/renderer/core/loader/private/prerender_handle.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_HANDLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_HANDLE_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/pass_key.h"
-#include "third_party/blink/public/mojom/prerender/prerender.mojom-blink.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.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/weborigin/kurl.h"
-
-namespace blink {
-
-class ExecutionContext;
-class Document;
-class PrerenderClient;
-
-// This is the Blink-side liaison of mojom::PrerenderProcessor to request the
-// browser process to start prerendering, and implements
-// mojom::PrerenderProcessorClient to observe events about prerendering. This is
-// instantiated per prerender request, for example, when a new <link
-// rel=prerender> element is added, when the element's href is changed etc.
-//
-// When you no longer need the prerendering page (e.g., when the
-// <link rel=prerender> element is removed), you can ask the browser process to
-// cancel the running prerender by Cancel(). If mojo connections are reset
-// without Cancel() call, the browser process considers this prerendering
-// request to be abandoned and may still use the prerendered page if a
-// navigation occurs to that URL shortly after.
-//
-// TODO(https://crbug.com/1126305): Rename this to PrerenderProcessorClient.
-class PrerenderHandle final : public GarbageCollected<PrerenderHandle>,
- public mojom::blink::PrerenderProcessorClient {
- public:
- static PrerenderHandle* Create(
- Document&,
- PrerenderClient*,
- const KURL&,
- mojom::blink::PrerenderRelType prerender_rel_type);
-
- using PassKey = util::PassKey<PrerenderHandle>;
- PrerenderHandle(
- PassKey,
- ExecutionContext*,
- PrerenderClient*,
- const KURL&,
- HeapMojoRemote<mojom::blink::PrerenderProcessor>,
- mojo::PendingReceiver<mojom::blink::PrerenderProcessorClient>);
- ~PrerenderHandle() override;
-
- // Asks the browser process to cancel the running prerender.
- void Cancel();
-
- const KURL& Url() const;
-
- // mojom::blink::PrerenderProcessorClient:
- void OnPrerenderStart() override;
- void OnPrerenderStopLoading() override;
- void OnPrerenderDomContentLoaded() override;
- void OnPrerenderStop() override;
-
- virtual void Trace(Visitor*) const;
-
- private:
- const KURL url_;
- const WeakMember<PrerenderClient> client_;
- HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor_;
- HeapMojoReceiver<mojom::blink::PrerenderProcessorClient, PrerenderHandle>
- receiver_;
-
- DISALLOW_COPY_AND_ASSIGN(PrerenderHandle);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
index e9abb5612fd..4184294cc1d 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.cc
@@ -48,7 +48,7 @@ CSSStyleSheetResource* CSSStyleSheetResource::Fetch(FetchParameters& params,
ResourceClient* client) {
params.SetRequestContext(mojom::blink::RequestContextType::STYLE);
params.SetRequestDestination(network::mojom::RequestDestination::kStyle);
- CSSStyleSheetResource* resource = ToCSSStyleSheetResource(
+ auto* resource = To<CSSStyleSheetResource>(
fetcher->RequestResource(params, CSSStyleSheetResourceFactory(), client));
return resource;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
index d72509a4df8..2f5f204b9d9 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h
@@ -98,7 +98,12 @@ class CORE_EXPORT CSSStyleSheetResource final : public TextResource {
Member<StyleSheetContents> parsed_style_sheet_cache_;
};
-DEFINE_RESOURCE_TYPE_CASTS(CSSStyleSheet);
+template <>
+struct DowncastTraits<CSSStyleSheetResource> {
+ static bool AllowFrom(const Resource& resource) {
+ return resource.GetType() == ResourceType::kCSSStyleSheet;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.cc
index 12457e62883..09293d0bb2b 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
#include "base/metrics/histogram_functions.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/renderer/platform/fonts/font_custom_platform_data.h"
@@ -54,7 +55,7 @@ FontResource* FontResource::Fetch(FetchParameters& params,
FontResourceClient* client) {
params.SetRequestContext(mojom::blink::RequestContextType::FONT);
params.SetRequestDestination(network::mojom::RequestDestination::kFont);
- return ToFontResource(
+ return To<FontResource>(
fetcher->RequestResource(params, FontResourceFactory(), client));
}
@@ -209,7 +210,13 @@ void FontResource::OnMemoryDump(WebMemoryDumpLevelOfDetail level,
const String name = GetMemoryDumpName() + "/decoded_webfont";
WebMemoryAllocatorDump* dump = memory_dump->CreateMemoryAllocatorDump(name);
dump->AddScalar("size", "bytes", font_data_->DataSize());
- memory_dump->AddSuballocation(dump->Guid(), "malloc");
+
+ const char* system_allocator_name =
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->system_allocator_pool_name();
+ if (system_allocator_name) {
+ memory_dump->AddSuballocation(dump->Guid(), system_allocator_name);
+ }
}
void FontResource::AddClearDataObserver(
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
index b2f096bba34..59ec02de679 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/font_resource.h
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -123,7 +124,12 @@ class CORE_EXPORT FontResource final : public Resource {
FRIEND_TEST_ALL_PREFIXES(CacheAwareFontResourceTest, CacheAwareFontLoading);
};
-DEFINE_RESOURCE_TYPE_CASTS(Font);
+template <>
+struct DowncastTraits<FontResource> {
+ static bool AllowFrom(const Resource& resource) {
+ return resource.GetType() == ResourceType::kFont;
+ }
+};
class FontResourceClient : public ResourceClient {
public:
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
index dc57a6d728d..e466c0b1b1a 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
@@ -66,12 +66,13 @@ TEST_F(FontResourceTest,
MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context,
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- MakeGarbageCollected<TestLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(properties->MakeDetachable(), context,
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ base::MakeRefCounted<scheduler::FakeTaskRunner>(),
+ MakeGarbageCollected<TestLoaderFactory>(),
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
// Fetch to cache a resource.
ResourceRequest request1(url);
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
index b534f607409..5e21e53cb16 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.cc
@@ -166,7 +166,7 @@ ImageResource* ImageResource::Fetch(FetchParameters& params,
params.SetRequestDestination(network::mojom::RequestDestination::kImage);
}
- ImageResource* resource = ToImageResource(
+ auto* resource = To<ImageResource>(
fetcher->RequestResource(params, ImageResourceFactory(), nullptr));
// If the fetch originated from user agent CSS we should mark it as a user
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
index 40104357b42..0bbdaae8760 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -146,7 +147,12 @@ class CORE_EXPORT ImageResource final
bool is_pending_flushing_ = false;
};
-DEFINE_RESOURCE_TYPE_CASTS(Image);
+template <>
+struct DowncastTraits<ImageResource> {
+ static bool AllowFrom(const Resource& resource) {
+ return resource.GetType() == ResourceType::kImage;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index de27e8ee341..fc0c52a85b6 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -230,7 +230,16 @@ IntSize ImageResourceContent::IntrinsicSize(
RespectImageOrientationEnum should_respect_image_orientation) const {
if (!image_)
return IntSize();
- return image_->Size(should_respect_image_orientation);
+ RespectImageOrientationEnum respect_orientation =
+ ForceOrientationIfNecessary(should_respect_image_orientation);
+ return image_->Size(respect_orientation);
+}
+
+RespectImageOrientationEnum ImageResourceContent::ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const {
+ if (image_ && image_->IsBitmapImage() && !IsAccessAllowed())
+ return kRespectImageOrientation;
+ return default_orientation;
}
void ImageResourceContent::NotifyObservers(
@@ -580,7 +589,7 @@ void ImageResourceContent::Changed(const blink::Image* image) {
NotifyObservers(kDoNotNotifyFinish, CanDeferInvalidation::kYes);
}
-bool ImageResourceContent::IsAccessAllowed() {
+bool ImageResourceContent::IsAccessAllowed() const {
return info_->IsAccessAllowed(
GetImage()->CurrentFrameHasSingleSecurityOrigin()
? ImageResourceInfo::kHasSingleSecurityOrigin
@@ -657,4 +666,9 @@ bool ImageResourceContent::IsAdResource() const {
return info_->IsAdResource();
}
+void ImageResourceContent::RecordDecodedImageType(UseCounter* use_counter) {
+ if (auto* bitmap_image = DynamicTo<BitmapImage>(image_.get()))
+ bitmap_image->RecordDecodedImageType(use_counter);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
index dd9df748491..fb8e29584e8 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -30,6 +30,7 @@ class ImageResourceObserver;
class ResourceError;
class ResourceFetcher;
class ResourceResponse;
+class UseCounter;
// ImageResourceContent is a container that holds fetch result of
// an ImageResource in a decoded form.
@@ -60,12 +61,15 @@ class CORE_EXPORT ImageResourceContent final
blink::Image* GetImage() const;
bool HasImage() const { return image_.get(); }
- // The device pixel ratio we got from the server for this image, or 1.0.
- float DevicePixelRatioHeaderValue() const;
- bool HasDevicePixelRatioHeaderValue() const;
+ // Returns true if enough of the image has been decoded to allow its size to
+ // be determined. If this returns true, so will HasImage().
+ bool IsSizeAvailable() const {
+ return size_available_ != Image::kSizeUnavailable;
+ }
// Returns the intrinsic width and height of the image, or 0x0 if no image
- // exists. If the image is a BitmapImage, then this corresponds to the
+ // exists. IsSizeAvailable() can be used to determine if the value returned is
+ // reliable. If the image is a BitmapImage, then this corresponds to the
// physical pixel dimensions of the image. If the image is an SVGImage, this
// does not quite return the intrinsic width/height, but rather a concrete
// object size resolved using a default object size of 300x150.
@@ -76,9 +80,14 @@ class CORE_EXPORT ImageResourceContent final
void AddObserver(ImageResourceObserver*);
void RemoveObserver(ImageResourceObserver*);
- bool IsSizeAvailable() const {
- return size_available_ != Image::kSizeUnavailable;
- }
+ // The device pixel ratio we got from the server for this image, or 1.0.
+ float DevicePixelRatioHeaderValue() const;
+ bool HasDevicePixelRatioHeaderValue() const;
+
+ // Correct the image orientation preference for potentially cross-origin
+ // content.
+ RespectImageOrientationEnum ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const;
void Trace(Visitor*) const override;
@@ -104,7 +113,7 @@ class CORE_EXPORT ImageResourceContent final
// Redirecting methods to Resource.
const KURL& Url() const;
base::TimeTicks LoadResponseEnd() const;
- bool IsAccessAllowed();
+ bool IsAccessAllowed() const;
const ResourceResponse& GetResponse() const;
base::Optional<ResourceError> GetResourceError() const;
// DEPRECATED: ImageResourceContents consumers shouldn't need to worry about
@@ -183,6 +192,10 @@ class CORE_EXPORT ImageResourceContent final
// Returns whether the resource request has been tagged as an ad.
bool IsAdResource() const;
+ // Records the decoded image type in a UseCounter if the image is a
+ // BitmapImage. |use_counter| may be a null pointer.
+ void RecordDecodedImageType(UseCounter* use_counter);
+
private:
using CanDeferInvalidation = ImageResourceObserver::CanDeferInvalidation;
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
index b647ef124a2..0a349817b90 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -224,7 +224,8 @@ ResourceFetcher* CreateFetcher() {
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
}
TEST_F(ImageResourceTest, MultipartImage) {
@@ -937,7 +938,8 @@ TEST_F(ImageResourceTest, PeriodicFlushTest) {
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
properties, context, task_runner, unfreezable_task_runner,
MakeGarbageCollected<TestLoaderFactory>(),
- page_holder->GetFrame().DomWindow()));
+ page_holder->GetFrame().DomWindow(),
+ nullptr /* back_forward_cache_loader_helper */));
auto frame_scheduler = std::make_unique<scheduler::FakeFrameScheduler>();
auto* scheduler = MakeGarbageCollected<ResourceLoadScheduler>(
ResourceLoadScheduler::ThrottlingPolicy::kNormal,
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
index 86112d36a78..e38c594abad 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
@@ -82,32 +83,36 @@ ScriptResource* ScriptResource::Fetch(FetchParameters& params,
StreamingAllowed streaming_allowed) {
DCHECK(IsRequestContextSupported(
params.GetResourceRequest().GetRequestContext()));
- ScriptResource* resource = ToScriptResource(fetcher->RequestResource(
- params, ScriptResourceFactory(streaming_allowed), client));
+ auto* resource = To<ScriptResource>(fetcher->RequestResource(
+ params, ScriptResourceFactory(streaming_allowed, params.GetScriptType()),
+ client));
return resource;
}
ScriptResource* ScriptResource::CreateForTest(
const KURL& url,
- const WTF::TextEncoding& encoding) {
+ const WTF::TextEncoding& encoding,
+ mojom::blink::ScriptType script_type) {
ResourceRequest request(url);
request.SetCredentialsMode(network::mojom::CredentialsMode::kOmit);
ResourceLoaderOptions options(nullptr /* world */);
TextResourceDecoderOptions decoder_options(
TextResourceDecoderOptions::kPlainTextContent, encoding);
return MakeGarbageCollected<ScriptResource>(request, options, decoder_options,
- kNoStreaming);
+ kNoStreaming, script_type);
}
ScriptResource::ScriptResource(
const ResourceRequest& resource_request,
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options,
- StreamingAllowed streaming_allowed)
+ StreamingAllowed streaming_allowed,
+ mojom::blink::ScriptType script_type)
: TextResource(resource_request,
ResourceType::kScript,
options,
- decoder_options) {
+ decoder_options),
+ script_type_(script_type) {
static bool script_streaming_enabled =
base::FeatureList::IsEnabled(features::kScriptStreaming);
@@ -125,14 +130,28 @@ ScriptResource::~ScriptResource() = default;
void ScriptResource::Trace(Visitor* visitor) const {
visitor->Trace(streamer_);
+ visitor->Trace(cached_metadata_handler_);
TextResource::Trace(visitor);
}
+Resource::MatchStatus ScriptResource::CanReuse(
+ const FetchParameters& params) const {
+ if (script_type_ != params.GetScriptType())
+ return Resource::MatchStatus::kScriptTypeDoesNotMatch;
+ return Resource::CanReuse(params);
+}
+
void ScriptResource::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
WebProcessMemoryDump* memory_dump) const {
Resource::OnMemoryDump(level_of_detail, memory_dump);
- const String name = GetMemoryDumpName() + "/decoded_script";
- source_text_.OnMemoryDump(memory_dump, name);
+ {
+ const String name = GetMemoryDumpName() + "/decoded_script";
+ source_text_.OnMemoryDump(memory_dump, name);
+ }
+ if (cached_metadata_handler_) {
+ const String name = GetMemoryDumpName() + "/code_cache";
+ cached_metadata_handler_->OnMemoryDump(memory_dump, name);
+ }
}
const ParkableString& ScriptResource::SourceText() {
@@ -178,22 +197,21 @@ String ScriptResource::TextForInspector() const {
}
SingleCachedMetadataHandler* ScriptResource::CacheHandler() {
- return static_cast<SingleCachedMetadataHandler*>(Resource::CacheHandler());
-}
-
-CachedMetadataHandler* ScriptResource::CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) {
- return MakeGarbageCollected<ScriptCachedMetadataHandler>(
- Encoding(), std::move(send_callback));
+ return cached_metadata_handler_;
}
void ScriptResource::SetSerializedCachedMetadata(mojo_base::BigBuffer data) {
// Resource ignores the cached metadata.
Resource::SetSerializedCachedMetadata(mojo_base::BigBuffer());
- ScriptCachedMetadataHandler* cache_handler =
- static_cast<ScriptCachedMetadataHandler*>(Resource::CacheHandler());
- if (cache_handler) {
- cache_handler->SetSerializedCachedMetadata(std::move(data));
+ if (cached_metadata_handler_) {
+ cached_metadata_handler_->SetSerializedCachedMetadata(std::move(data));
+ }
+}
+
+void ScriptResource::DestroyDecodedDataIfPossible() {
+ if (cached_metadata_handler_) {
+ cached_metadata_handler_->ClearCachedMetadata(
+ CachedMetadataHandler::kClearLocally);
}
}
@@ -203,6 +221,7 @@ void ScriptResource::DestroyDecodedDataForFailedRevalidation() {
DCHECK(!streamer_);
DCHECK_EQ(streaming_state_, StreamingState::kStreamingDisabled);
SetDecodedSize(0);
+ cached_metadata_handler_ = nullptr;
}
void ScriptResource::SetRevalidatingRequest(
@@ -233,6 +252,32 @@ bool ScriptResource::CanUseCacheValidator() const {
return Resource::CanUseCacheValidator();
}
+size_t ScriptResource::CodeCacheSize() const {
+ return cached_metadata_handler_ ? cached_metadata_handler_->GetCodeCacheSize()
+ : 0;
+}
+
+void ScriptResource::ResponseReceived(const ResourceResponse& response) {
+ const bool is_successful_revalidation =
+ IsSuccessfulRevalidationResponse(response);
+ Resource::ResponseReceived(response);
+
+ if (is_successful_revalidation) {
+ return;
+ }
+
+ cached_metadata_handler_ = nullptr;
+ // Currently we support the metadata caching only for HTTP family.
+ if (GetResourceRequest().Url().ProtocolIsInHTTPFamily() &&
+ response.CurrentRequestUrl().ProtocolIsInHTTPFamily()) {
+ cached_metadata_handler_ =
+ MakeGarbageCollected<ScriptCachedMetadataHandler>(
+ Encoding(), CachedMetadataSender::Create(
+ response, mojom::blink::CodeCacheType::kJavascript,
+ GetResourceRequest().RequestorOrigin()));
+ }
+} // namespace blink
+
void ScriptResource::ResponseBodyReceived(
ResponseBodyLoaderDrainableInterface& body_loader,
scoped_refptr<base::SingleThreadTaskRunner> loader_task_runner) {
@@ -256,9 +301,9 @@ void ScriptResource::ResponseBodyReceived(
CheckStreamingState();
CHECK(!ErrorOccurred());
- streamer_ = MakeGarbageCollected<ScriptStreamer>(
- this, std::move(data_pipe), response_body_loader_client,
- v8::ScriptCompiler::kNoCompileOptions, loader_task_runner);
+ streamer_ = MakeGarbageCollected<ScriptStreamer>(this, std::move(data_pipe),
+ response_body_loader_client,
+ loader_task_runner);
CHECK_EQ(no_streamer_reason_, ScriptStreamer::NotStreamingReason::kInvalid);
AdvanceStreamingState(StreamingState::kStreaming);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
index 815a87ad57c..c906cd135c2 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.h
@@ -28,6 +28,8 @@
#include <memory>
+#include "third_party/blink/public/mojom/script/script_type.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/script/script_type.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
@@ -42,10 +44,12 @@ namespace blink {
class FetchParameters;
class KURL;
class ResourceFetcher;
+class ScriptCachedMetadataHandler;
class SingleCachedMetadataHandler;
// ScriptResource is a resource representing a JavaScript, either a classic or
-// module script.
+// module script. ScriptResources are not shared between classic and module
+// scripts.
//
// In addition to loading the script, a ScriptResource can optionally stream the
// script to the JavaScript parser/compiler, using a ScriptStreamer. In this
@@ -67,15 +71,22 @@ class CORE_EXPORT ScriptResource final : public TextResource {
StreamingAllowed);
// Public for testing
- static ScriptResource* CreateForTest(const KURL& url,
- const WTF::TextEncoding& encoding);
+ static ScriptResource* CreateForTest(
+ const KURL& url,
+ const WTF::TextEncoding& encoding,
+ mojom::blink::ScriptType = mojom::blink::ScriptType::kClassic);
ScriptResource(const ResourceRequest&,
const ResourceLoaderOptions&,
const TextResourceDecoderOptions&,
- StreamingAllowed);
+ StreamingAllowed,
+ mojom::blink::ScriptType);
~ScriptResource() override;
+ Resource::MatchStatus CanReuse(const FetchParameters& params) const override;
+
+ size_t CodeCacheSize() const override;
+ void ResponseReceived(const ResourceResponse&) override;
void ResponseBodyReceived(
ResponseBodyLoaderDrainableInterface& body_loader,
scoped_refptr<base::SingleThreadTaskRunner> loader_task_runner) override;
@@ -95,6 +106,8 @@ class CORE_EXPORT ScriptResource final : public TextResource {
SingleCachedMetadataHandler* CacheHandler();
+ mojom::blink::ScriptType GetScriptType() const { return script_type_; }
+
// Gets the script streamer from the ScriptResource, clearing the resource's
// streamer so that it cannot be used twice.
ScriptStreamer* TakeStreamer();
@@ -112,9 +125,7 @@ class CORE_EXPORT ScriptResource final : public TextResource {
void SetRevalidatingRequest(const ResourceRequestHead&) override;
protected:
- CachedMetadataHandler* CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) override;
-
+ void DestroyDecodedDataIfPossible() override;
void DestroyDecodedDataForFailedRevalidation() override;
// ScriptResources are considered finished when either:
@@ -145,21 +156,24 @@ class CORE_EXPORT ScriptResource final : public TextResource {
class ScriptResourceFactory : public ResourceFactory {
public:
- explicit ScriptResourceFactory(StreamingAllowed streaming_allowed)
+ explicit ScriptResourceFactory(StreamingAllowed streaming_allowed,
+ mojom::blink::ScriptType script_type)
: ResourceFactory(ResourceType::kScript,
TextResourceDecoderOptions::kPlainTextContent),
- streaming_allowed_(streaming_allowed) {}
+ streaming_allowed_(streaming_allowed),
+ script_type_(script_type) {}
Resource* Create(
const ResourceRequest& request,
const ResourceLoaderOptions& options,
const TextResourceDecoderOptions& decoder_options) const override {
return MakeGarbageCollected<ScriptResource>(
- request, options, decoder_options, streaming_allowed_);
+ request, options, decoder_options, streaming_allowed_, script_type_);
}
private:
StreamingAllowed streaming_allowed_;
+ mojom::blink::ScriptType script_type_;
};
bool CanUseCacheValidator() const override;
@@ -180,9 +194,16 @@ class CORE_EXPORT ScriptResource final : public TextResource {
ScriptStreamer::NotStreamingReason no_streamer_reason_ =
ScriptStreamer::NotStreamingReason::kInvalid;
StreamingState streaming_state_ = StreamingState::kWaitingForDataPipe;
+ Member<ScriptCachedMetadataHandler> cached_metadata_handler_;
+ const mojom::blink::ScriptType script_type_;
};
-DEFINE_RESOURCE_TYPE_CASTS(Script);
+template <>
+struct DowncastTraits<ScriptResource> {
+ static bool AllowFrom(const Resource& resource) {
+ return resource.GetType() == ResourceType::kScript;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource_test.cc b/chromium/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
new file mode 100644
index 00000000000..04436fcb9e6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this sink code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
+
+namespace blink {
+namespace {
+
+TEST(ScriptResourceTest, SuccessfulRevalidation) {
+ const KURL url("https://www.example.com/script.js");
+ ScriptResource* resource = ScriptResource::CreateForTest(url, UTF8Encoding());
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ resource->ResponseReceived(response);
+ constexpr char kData[5] = "abcd";
+ resource->AppendData(kData, strlen(kData));
+ resource->FinishForTest();
+
+ auto* original_handler = resource->CacheHandler();
+ EXPECT_TRUE(original_handler);
+ EXPECT_EQ(UTF8Encoding().GetName(), original_handler->Encoding());
+
+ resource->SetRevalidatingRequest(ResourceRequestHead(url));
+ ResourceResponse revalidation_response(url);
+ revalidation_response.SetHttpStatusCode(304);
+ resource->ResponseReceived(revalidation_response);
+
+ EXPECT_EQ(original_handler, resource->CacheHandler());
+}
+
+TEST(ScriptResourceTest, FailedRevalidation) {
+ const KURL url("https://www.example.com/script.js");
+ ScriptResource* resource =
+ ScriptResource::CreateForTest(url, Latin1Encoding());
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ resource->ResponseReceived(response);
+ constexpr char kData[5] = "abcd";
+ resource->AppendData(kData, strlen(kData));
+ resource->FinishForTest();
+
+ auto* original_handler = resource->CacheHandler();
+ EXPECT_TRUE(original_handler);
+ EXPECT_EQ(Latin1Encoding().GetName(), original_handler->Encoding());
+
+ resource->SetRevalidatingRequest(ResourceRequestHead(url));
+ ResourceResponse revalidation_response(url);
+ revalidation_response.SetHttpStatusCode(200);
+ resource->ResponseReceived(revalidation_response);
+
+ auto* new_handler = resource->CacheHandler();
+ EXPECT_TRUE(new_handler);
+ EXPECT_NE(original_handler, new_handler);
+}
+
+TEST(ScriptResourceTest, RedirectDuringRevalidation) {
+ const KURL url("https://www.example.com/script.js");
+ ScriptResource* resource = ScriptResource::CreateForTest(url, UTF8Encoding());
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ resource->ResponseReceived(response);
+ constexpr char kData[5] = "abcd";
+ resource->AppendData(kData, strlen(kData));
+ resource->FinishForTest();
+
+ auto* original_handler = resource->CacheHandler();
+ EXPECT_TRUE(original_handler);
+
+ resource->SetRevalidatingRequest(ResourceRequestHead(url));
+ const KURL destination("https://www.example.com/another-script.js");
+ ResourceResponse revalidation_response(url);
+ revalidation_response.SetHttpStatusCode(302);
+ revalidation_response.SetHttpHeaderField(
+ "location", AtomicString(destination.GetString()));
+ ResourceRequest redirect_request(destination);
+ resource->WillFollowRedirect(redirect_request, revalidation_response);
+
+ auto* new_handler = resource->CacheHandler();
+ EXPECT_FALSE(new_handler);
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.cc
index efbfa80a1c4..01a3685aa94 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.cc
@@ -53,9 +53,8 @@ XSLStyleSheetResource* XSLStyleSheetResource::FetchSynchronously(
ResourceFetcher* fetcher) {
ApplyXSLRequestProperties(params);
params.MakeSynchronous();
- XSLStyleSheetResource* resource =
- ToXSLStyleSheetResource(fetcher->RequestResource(
- params, XSLStyleSheetResourceFactory(), nullptr));
+ auto* resource = To<XSLStyleSheetResource>(fetcher->RequestResource(
+ params, XSLStyleSheetResourceFactory(), nullptr));
if (resource->Data())
resource->sheet_ = resource->DecodedText();
return resource;
@@ -66,7 +65,7 @@ XSLStyleSheetResource* XSLStyleSheetResource::Fetch(FetchParameters& params,
ResourceClient* client) {
DCHECK(RuntimeEnabledFeatures::XSLTEnabled());
ApplyXSLRequestProperties(params);
- return ToXSLStyleSheetResource(
+ return To<XSLStyleSheetResource>(
fetcher->RequestResource(params, XSLStyleSheetResourceFactory(), client));
}
diff --git a/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.h b/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.h
index 21c00df68c0..d072752de47 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource/xsl_style_sheet_resource.h
@@ -69,7 +69,12 @@ class XSLStyleSheetResource final : public TextResource {
String sheet_;
};
-DEFINE_RESOURCE_TYPE_CASTS(XSLStyleSheet);
+template <>
+struct DowncastTraits<XSLStyleSheetResource> {
+ static bool AllowFrom(const Resource& resource) {
+ return resource.GetType() == ResourceType::kXSLStyleSheet;
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
index b88ea85805b..8320aa1b855 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/loader/address_space_feature.h"
#include "third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
@@ -72,7 +73,8 @@ void ResourceLoadObserverForFrame::WillSendRequest(
const ResourceRequest& request,
const ResourceResponse& redirect_response,
ResourceType resource_type,
- const FetchInitiatorInfo& initiator_info) {
+ const FetchInitiatorInfo& initiator_info,
+ RenderBlockingBehavior render_blocking_behavior) {
LocalFrame* frame = document_->GetFrame();
DCHECK(frame);
if (redirect_response.IsNull()) {
@@ -83,7 +85,8 @@ void ResourceLoadObserverForFrame::WillSendRequest(
probe::WillSendRequest(
GetProbe(), identifier, document_loader_,
fetcher_properties_->GetFetchClientSettingsObject().GlobalObjectUrl(),
- request, redirect_response, initiator_info, resource_type);
+ request, redirect_response, initiator_info, resource_type,
+ render_blocking_behavior);
if (auto* idleness_detector = frame->GetIdlenessDetector())
idleness_detector->OnWillSendRequest(document_->Fetcher());
if (auto* interactive_detector = InteractiveDetector::From(*document_))
@@ -145,7 +148,7 @@ void ResourceLoadObserverForFrame::DidReceiveResponse(
return;
}
- MixedContentChecker::CheckMixedPrivatePublic(frame, response);
+ RecordAddressSpaceFeature(FetchType::kSubresource, frame, response);
std::unique_ptr<AlternateSignedExchangeResourceInfo> alternate_resource_info;
@@ -274,13 +277,6 @@ void ResourceLoadObserverForFrame::DidFailLoading(
document_->CheckCompleted();
}
-void ResourceLoadObserverForFrame::EvictFromBackForwardCache(
- mojom::blink::RendererEvictionReason reason) {
- LocalFrame* frame = document_->GetFrame();
- DCHECK(frame);
- frame->EvictFromBackForwardCache(reason);
-}
-
void ResourceLoadObserverForFrame::Trace(Visitor* visitor) const {
visitor->Trace(document_loader_);
visitor->Trace(document_);
diff --git a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h
index 3151a0926c2..95a69092119 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h
@@ -35,7 +35,8 @@ class CORE_EXPORT ResourceLoadObserverForFrame final
const ResourceRequest&,
const ResourceResponse& redirect_response,
ResourceType,
- const FetchInitiatorInfo&) override;
+ const FetchInitiatorInfo&,
+ RenderBlockingBehavior) override;
void DidChangePriority(uint64_t identifier,
ResourceLoadPriority,
int intra_priority_value) override;
@@ -59,7 +60,6 @@ class CORE_EXPORT ResourceLoadObserverForFrame final
const ResourceError&,
int64_t encoded_data_length,
IsInternalRequest) override;
- void EvictFromBackForwardCache(mojom::blink::RendererEvictionReason) override;
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc
index e0be94a48d5..a67ad8d26b3 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc
+++ b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc
@@ -4,14 +4,13 @@
#include "third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
#include "third_party/blink/renderer/core/core_probes_inl.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/mixed_content.h"
namespace blink {
@@ -35,11 +34,13 @@ void ResourceLoadObserverForWorker::WillSendRequest(
const ResourceRequest& request,
const ResourceResponse& redirect_response,
ResourceType resource_type,
- const FetchInitiatorInfo& initiator_info) {
+ const FetchInitiatorInfo& initiator_info,
+ RenderBlockingBehavior render_blocking_behavior) {
probe::WillSendRequest(
probe_, identifier, nullptr,
fetcher_properties_->GetFetchClientSettingsObject().GlobalObjectUrl(),
- request, redirect_response, initiator_info, resource_type);
+ request, redirect_response, initiator_info, resource_type,
+ render_blocking_behavior);
}
void ResourceLoadObserverForWorker::DidChangePriority(
@@ -56,7 +57,7 @@ void ResourceLoadObserverForWorker::DidReceiveResponse(
if (response.HasMajorCertificateErrors()) {
MixedContentChecker::HandleCertificateError(
response, request.GetRequestContext(),
- WebMixedContent::CheckModeForPlugin::kLax,
+ MixedContent::CheckModeForPlugin::kLax,
worker_fetch_context_->GetContentSecurityNotifier());
}
probe::DidReceiveResourceResponse(probe_, identifier, nullptr, response,
diff --git a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h
index 424dd7db2aa..5e59440df80 100644
--- a/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h
+++ b/chromium/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h
@@ -33,7 +33,8 @@ class ResourceLoadObserverForWorker final : public ResourceLoadObserver {
const ResourceRequest&,
const ResourceResponse& redirect_response,
ResourceType,
- const FetchInitiatorInfo&) override;
+ const FetchInitiatorInfo&,
+ RenderBlockingBehavior) override;
void DidChangePriority(uint64_t identifier,
ResourceLoadPriority,
int intra_priority_value) override;
@@ -57,8 +58,6 @@ class ResourceLoadObserverForWorker final : public ResourceLoadObserver {
const ResourceError&,
int64_t encoded_data_length,
IsInternalRequest) override;
- void EvictFromBackForwardCache(
- mojom::blink::RendererEvictionReason) override {}
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.cc b/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.cc
new file mode 100644
index 00000000000..1aac6488246
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.cc
@@ -0,0 +1,106 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
+#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+
+namespace blink {
+
+namespace {
+
+// Records the ineligibility metrics.
+void RecordSubresourceRedirectIneligibility(
+ BlinkSubresourceRedirectIneligibility reason) {
+ base::UmaHistogramEnumeration("SubresourceRedirect.Blink.Ineligibility",
+ reason);
+}
+
+// Returns whether the URL scheme is http or https.
+bool IsSchemeHttpOrHttps(const KURL& url) {
+ return url.Protocol() == url::kHttpsScheme ||
+ url.Protocol() == url::kHttpScheme;
+}
+
+} // namespace
+
+bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
+ const KURL& url) {
+ if (!image_element)
+ return false;
+
+ // Allow redirection only when DataSaver is enabled and subresource redirect
+ // feature is enabled which allows redirecting to better optimized versions.
+ if (!base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect) ||
+ !GetNetworkStateNotifier().SaveDataEnabled()) {
+ return false;
+ }
+
+ // Allow redirection only for http(s) subresources on http(s) documents.
+ if (!IsSchemeHttpOrHttps(url) ||
+ !IsSchemeHttpOrHttps(image_element->GetDocument().Url())) {
+ return false;
+ }
+
+ // Enable subresource redirect only for <img> elements created by parser.
+ // Images created from javascript, fetched via XHR/Fetch API should not be
+ // subresource redirected due to the additional CORB/CORS handling needed for
+ // them.
+ if (!image_element->ElementCreatedByParser()) {
+ RecordSubresourceRedirectIneligibility(
+ SecurityOrigin::AreSameOrigin(url, image_element->GetDocument().Url())
+ ? BlinkSubresourceRedirectIneligibility::
+ kJavascriptCreatedSameOrigin
+ : BlinkSubresourceRedirectIneligibility::
+ kJavascriptCreatedCrossOrigin);
+ return false;
+ }
+
+ // Create a cross origin URL by appending a string to the original host. This
+ // is used to find whether CSP is restricting image fetches from other
+ // origins.
+ KURL cross_origin_url = url;
+ cross_origin_url.SetHost(url.Host() + "crossorigin.com");
+ auto* content_security_policy =
+ image_element->GetExecutionContext()->GetContentSecurityPolicy();
+ if (content_security_policy &&
+ !content_security_policy->AllowImageFromSource(
+ cross_origin_url, cross_origin_url, RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting)) {
+ // Check if an object is allowed by CSP as a proxy to determine whether the
+ // image resource was disallowed by default-src or img-src directives. When
+ // an object is allowed it means default-src did not disallow the image.
+ RecordSubresourceRedirectIneligibility(
+ content_security_policy->AllowRequest(
+ mojom::blink::RequestContextType::OBJECT,
+ network::mojom::RequestDestination::kObject, cross_origin_url,
+ String() /* nonce */, IntegrityMetadataSet(),
+ ParserDisposition::kParserInserted, cross_origin_url,
+ RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting,
+ ContentSecurityPolicy::CheckHeaderType::kCheckEnforce)
+ ? BlinkSubresourceRedirectIneligibility::
+ kContentSecurityPolicyImgSrcRestricted
+ : BlinkSubresourceRedirectIneligibility::
+ kContentSecurityPolicyDefaultSrcRestricted);
+ return false;
+ }
+
+ // Allow subresource redirect only when cross-origin attribute is not set,
+ // which indicates CORS validation is not triggered for the image.
+ if (GetCrossOriginAttributeValue(image_element->FastGetAttribute(
+ html_names::kCrossoriginAttr)) != kCrossOriginAttributeNotSet) {
+ RecordSubresourceRedirectIneligibility(
+ BlinkSubresourceRedirectIneligibility::kCrossOriginAttributeSet);
+ return false;
+ }
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.h b/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.h
new file mode 100644
index 00000000000..6957284b934
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/loader/subresource_redirect_util.h
@@ -0,0 +1,46 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
+
+#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+// Enumerates the different ineligibility reasons for why a subresource
+// redirection was disabled in blink. This is recorded in metrics and should not
+// be reordered or removed. Should be in sync with the same name in enums.xml
+enum class BlinkSubresourceRedirectIneligibility {
+ // Created by javascript and is same-origin with the document.
+ kJavascriptCreatedSameOrigin = 0,
+
+ // Created by javascript and is cross-origin with the document.
+ kJavascriptCreatedCrossOrigin = 1,
+
+ // Restricted by Content-Security-Policy default-src directive.
+ kContentSecurityPolicyDefaultSrcRestricted = 2,
+
+ // Restricted by Content-Security-Policy img-src directive.
+ kContentSecurityPolicyImgSrcRestricted = 3,
+
+ // Crossorigin attribute was set which indicates CORS validation will happen
+ // for the subresource.
+ kCrossOriginAttributeSet = 4,
+
+ // New enum entries should be added here.
+
+ kMaxValue = kCrossOriginAttributeSet
+};
+
+// Returns whether subresource redirect can be attempted for fetching the image
+// with |url|. Redirect to other origins could be disabled due to CSP or CORS
+// restrictions.
+bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
+ const KURL& url);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
diff --git a/chromium/third_party/blink/renderer/core/loader/text_track_loader.cc b/chromium/third_party/blink/renderer/core/loader/text_track_loader.cc
index 4fc2eeb4237..b3b5546c47a 100644
--- a/chromium/third_party/blink/renderer/core/loader/text_track_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/text_track_loader.cc
@@ -164,6 +164,7 @@ void TextTrackLoader::Trace(Visitor* visitor) const {
visitor->Trace(client_);
visitor->Trace(cue_parser_);
visitor->Trace(document_);
+ visitor->Trace(cue_load_timer_);
RawResourceClient::Trace(visitor);
VTTParserClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/text_track_loader.h b/chromium/third_party/blink/renderer/core/loader/text_track_loader.h
index fe76c97e23c..67efb5c8465 100644
--- a/chromium/third_party/blink/renderer/core/loader/text_track_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/text_track_loader.h
@@ -81,7 +81,7 @@ class TextTrackLoader final : public GarbageCollected<TextTrackLoader>,
Member<VTTParser> cue_parser_;
// FIXME: Remove this pointer and get the Document from m_client.
Member<Document> document_;
- TaskRunnerTimer<TextTrackLoader> cue_load_timer_;
+ HeapTaskRunnerTimer<TextTrackLoader> cue_load_timer_;
State state_;
bool new_cues_available_;
};
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc b/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
index 2ca016ad3fd..005fcad8a63 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -312,15 +312,15 @@ void ThreadableLoader::ResponseBodyReceived(Resource* resource,
client_->DidStartLoadingResponseBody(body);
}
-void ThreadableLoader::SetSerializedCachedMetadata(Resource* resource,
- const uint8_t* data,
- size_t size) {
+void ThreadableLoader::CachedMetadataReceived(
+ Resource* resource,
+ mojo_base::BigBuffer cached_metadata) {
DCHECK(client_);
DCHECK_EQ(resource, GetResource());
checker_.SetSerializedCachedMetadata();
- client_->DidReceiveCachedMetadata(reinterpret_cast<const char*>(data),
- SafeCast<int>(size));
+
+ client_->DidReceiveCachedMetadata(std::move(cached_metadata));
}
void ThreadableLoader::DataReceived(Resource* resource,
@@ -384,6 +384,7 @@ void ThreadableLoader::Trace(Visitor* visitor) const {
visitor->Trace(execution_context_);
visitor->Trace(client_);
visitor->Trace(resource_fetcher_);
+ visitor->Trace(timeout_timer_);
RawResourceClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader.h b/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
index be9ca749c2c..7c2a504e7c8 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -140,7 +140,7 @@ class CORE_EXPORT ThreadableLoader final
uint64_t total_bytes_to_be_sent) override;
void ResponseReceived(Resource*, const ResourceResponse&) override;
void ResponseBodyReceived(Resource*, BytesConsumer& body) override;
- void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) override;
+ void CachedMetadataReceived(Resource*, mojo_base::BigBuffer) override;
void DataReceived(Resource*, const char* data, size_t data_length) override;
bool RedirectReceived(Resource*,
const ResourceRequest&,
@@ -163,7 +163,7 @@ class CORE_EXPORT ThreadableLoader final
// Set via SetTimeout() by a user before Start().
base::TimeDelta timeout_;
// Used to detect |timeout_| is over.
- TaskRunnerTimer<ThreadableLoader> timeout_timer_;
+ HeapTaskRunnerTimer<ThreadableLoader> timeout_timer_;
// Time an asynchronous fetch request is started
base::TimeTicks request_started_;
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h b/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
index 6b768cdc7f3..d60d28183bc 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader_client.h
@@ -34,6 +34,7 @@
#include <memory>
#include "base/macros.h"
+#include "mojo/public/cpp/base/big_buffer.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -59,7 +60,7 @@ class CORE_EXPORT ThreadableLoaderClient : public GarbageCollectedMixin {
const ResourceResponse&) {}
virtual void DidStartLoadingResponseBody(BytesConsumer&) {}
virtual void DidReceiveData(const char*, unsigned /*dataLength*/) {}
- virtual void DidReceiveCachedMetadata(const char*, int /*dataLength*/) {}
+ virtual void DidReceiveCachedMetadata(mojo_base::BigBuffer) {}
virtual void DidFinishLoading(uint64_t /*identifier*/) {}
virtual void DidFail(const ResourceError&) {}
virtual void DidFailRedirectCheck() {}
diff --git a/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
index 38e2db33cb7..7e5a383a4b9 100644
--- a/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
+++ b/chromium/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -61,7 +61,7 @@ class MockThreadableLoaderClient final
MOCK_METHOD2(DidSendData, void(uint64_t, uint64_t));
MOCK_METHOD2(DidReceiveResponse, void(uint64_t, const ResourceResponse&));
MOCK_METHOD2(DidReceiveData, void(const char*, unsigned));
- MOCK_METHOD2(DidReceiveCachedMetadata, void(const char*, int));
+ MOCK_METHOD1(DidReceiveCachedMetadata, void(mojo_base::BigBuffer));
MOCK_METHOD1(DidFinishLoading, void(uint64_t));
MOCK_METHOD1(DidFail, void(const ResourceError&));
MOCK_METHOD0(DidFailRedirectCheck, void());
@@ -135,7 +135,8 @@ class ThreadableLoaderTestHelper final {
: dummy_page_holder_(std::make_unique<DummyPageHolder>(IntSize(1, 1))) {
KURL url("http://fake.url/");
dummy_page_holder_->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
}
diff --git a/chromium/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc b/chromium/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
index 4b4766d5006..289f8c5019c 100644
--- a/chromium/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
+++ b/chromium/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
@@ -141,6 +141,11 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final
return client;
}
+ void Trace(Visitor* visitor) const final {
+ visitor->Trace(error_timer_);
+ ThreadableLoaderClient::Trace(visitor);
+ }
+
private:
void NotifyError(TimerBase*);
@@ -151,7 +156,7 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final
network::mojom::CredentialsMode credentials_mode_;
base::Optional<WebURLError> error_;
- TaskRunnerTimer<ClientAdapter> error_timer_;
+ HeapTaskRunnerTimer<ClientAdapter> error_timer_;
bool enable_error_notifications_;
bool did_fail_;
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 557d77d7190..066daa252b8 100644
--- a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -6,8 +6,6 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
-#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_worker_fetch_context.h"
@@ -76,11 +74,6 @@ SubresourceFilter* WorkerFetchContext::GetSubresourceFilter() const {
return subresource_filter_.Get();
}
-PreviewsResourceLoadingHints*
-WorkerFetchContext::GetPreviewsResourceLoadingHints() const {
- return nullptr;
-}
-
bool WorkerFetchContext::AllowScriptFromSource(const KURL& url) const {
if (!global_scope_->ContentSettingsClient()) {
return true;
@@ -106,8 +99,7 @@ void WorkerFetchContext::DispatchDidBlockRequest(
fetch_initiator_info, blocked_reason, resource_type);
}
-const ContentSecurityPolicy*
-WorkerFetchContext::GetContentSecurityPolicyForWorld(
+ContentSecurityPolicy* WorkerFetchContext::GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const {
// Worker threads don't support per-world CSP. Hence just return the default
// CSP.
@@ -194,8 +186,7 @@ const SecurityOrigin* WorkerFetchContext::GetParentSecurityOrigin() const {
return nullptr;
}
-const ContentSecurityPolicy* WorkerFetchContext::GetContentSecurityPolicy()
- const {
+ContentSecurityPolicy* WorkerFetchContext::GetContentSecurityPolicy() const {
return content_security_policy_;
}
diff --git a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
index ed70cf36f21..c935e69c586 100644
--- a/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
+++ b/chromium/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -48,15 +48,13 @@ class WorkerFetchContext final : public BaseFetchContext {
scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const override;
SubresourceFilter* GetSubresourceFilter() const override;
- PreviewsResourceLoadingHints* GetPreviewsResourceLoadingHints()
- const override;
bool AllowScriptFromSource(const KURL&) const override;
bool ShouldBlockRequestByInspector(const KURL&) const override;
void DispatchDidBlockRequest(const ResourceRequest&,
const FetchInitiatorInfo&,
ResourceRequestBlockedReason,
ResourceType) const override;
- const ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
+ ContentSecurityPolicy* GetContentSecurityPolicyForWorld(
const DOMWrapperWorld* world) const override;
bool IsSVGImageChromeClient() const override;
void CountUsage(WebFeature) const override;
@@ -74,7 +72,7 @@ class WorkerFetchContext final : public BaseFetchContext {
const KURL&) const override;
const KURL& Url() const override;
const SecurityOrigin* GetParentSecurityOrigin() const override;
- const ContentSecurityPolicy* GetContentSecurityPolicy() const override;
+ ContentSecurityPolicy* GetContentSecurityPolicy() const override;
void AddConsoleMessage(ConsoleMessage*) const override;
// FetchContext implementation:
diff --git a/chromium/third_party/blink/renderer/core/messaging/DIR_METADATA b/chromium/third_party/blink/renderer/core/messaging/DIR_METADATA
new file mode 100644
index 00000000000..169c29b7de1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/messaging/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Messaging"
+}
+
+team_email: "platform-architecture-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/messaging/OWNERS b/chromium/third_party/blink/renderer/core/messaging/OWNERS
index 2ae4d6dae1b..632fec45da9 100644
--- a/chromium/third_party/blink/renderer/core/messaging/OWNERS
+++ b/chromium/third_party/blink/renderer/core/messaging/OWNERS
@@ -3,6 +3,3 @@ jbroman@chromium.org
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Messaging
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.cc b/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.cc
index 76c8fd34b0b..83db543f11e 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.cc
@@ -51,9 +51,9 @@ bool StructTraits<blink::mojom::blink::CloneableMessage::DataView,
return false;
out->locked_agent_cluster_id = locked_agent_cluster_id;
- Vector<PendingRemote<blink::mojom::blink::NativeFileSystemTransferToken>>&
- tokens = out->message->NativeFileSystemTokens();
- if (!data.ReadNativeFileSystemTokens(&tokens)) {
+ Vector<PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken>>&
+ tokens = out->message->FileSystemAccessTokens();
+ if (!data.ReadFileSystemAccessTokens(&tokens)) {
return false;
}
return true;
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.h b/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.h
index 637c23a622f..43dab8ad9cd 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_cloneable_message_mojom_traits.h
@@ -9,7 +9,7 @@
#include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
#include "mojo/public/cpp/bindings/string_traits_wtf.h"
-#include "third_party/blink/public/mojom/file_system_access/native_file_system_transfer_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom-blink.h"
#include "third_party/blink/public/mojom/messaging/cloneable_message.mojom-shared.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -60,9 +60,9 @@ struct CORE_EXPORT StructTraits<blink::mojom::CloneableMessageDataView,
}
static Vector<
- mojo::PendingRemote<blink::mojom::blink::NativeFileSystemTransferToken>>
- native_file_system_tokens(blink::BlinkCloneableMessage& input) {
- return std::move(input.message->NativeFileSystemTokens());
+ mojo::PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken>>
+ file_system_access_tokens(blink::BlinkCloneableMessage& input) {
+ return std::move(input.message->FileSystemAccessTokens());
}
static bool Read(blink::mojom::CloneableMessageDataView,
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
index 7f9fb752ad7..157bcc2155b 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
@@ -8,14 +8,14 @@
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
+#include "third_party/blink/public/web/web_dom_message_event.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/frame/user_activation.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
-#include "third_party/blink/public/web/web_dom_message_event.h"
-
namespace blink {
// static
@@ -45,15 +45,16 @@ BlinkTransferableMessage BlinkTransferableMessage::FromMessageEvent(
user_activation->hasBeenActive(), user_activation->isActive());
}
+ // Capability delegation
+ result.delegate_payment_request = message_event->delegatePaymentRequest();
+
// Blobs.
for (const auto& blob : serialized_script_value->BlobDataHandles()) {
result.message->BlobDataHandles().Set(
blob.value->Uuid(),
BlobDataHandle::Create(blob.value->Uuid(), blob.value->GetType(),
blob.value->size(),
- mojo::PendingRemote<mojom::blink::Blob>(
- blob.value->CloneBlobRemote().PassPipe(),
- mojom::blink::Blob::Version_)));
+ blob.value->CloneBlobRemote()));
}
// Stream channels.
@@ -110,13 +111,9 @@ BlinkTransferableMessage BlinkTransferableMessage::FromMessageEvent(
std::move(image_bitmap_contents_array));
}
- // Native file system transfer tokens.
- for (auto& token : serialized_script_value->NativeFileSystemTokens()) {
- uint32_t token_version = token.version();
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
- converted_token(token.PassPipe(), token_version);
- result.message->NativeFileSystemTokens().push_back(
- std::move(converted_token));
+ // File System Access transfer tokens.
+ for (auto& token : serialized_script_value->FileSystemAccessTokens()) {
+ result.message->FileSystemAccessTokens().push_back(std::move(token));
}
return result;
@@ -132,11 +129,9 @@ BlinkTransferableMessage BlinkTransferableMessage::FromTransferableMessage(
for (auto& blob : message.blobs) {
result.message->BlobDataHandles().Set(
String::FromUTF8(blob->uuid),
- BlobDataHandle::Create(
- String::FromUTF8(blob->uuid), String::FromUTF8(blob->content_type),
- blob->size,
- mojo::PendingRemote<mojom::blink::Blob>(blob->blob.PassPipe(),
- mojom::Blob::Version_)));
+ BlobDataHandle::Create(String::FromUTF8(blob->uuid),
+ String::FromUTF8(blob->content_type), blob->size,
+ ToCrossVariantMojoType(std::move(blob->blob))));
}
if (message.sender_origin) {
result.sender_origin =
@@ -158,6 +153,7 @@ BlinkTransferableMessage BlinkTransferableMessage::FromTransferableMessage(
message.user_activation->has_been_active,
message.user_activation->was_active);
}
+ result.delegate_payment_request = message.delegate_payment_request;
if (!message.array_buffer_contents_array.empty()) {
SerializedScriptValue::ArrayBufferContentsArray array_buffer_contents_array;
@@ -197,14 +193,11 @@ BlinkTransferableMessage BlinkTransferableMessage::FromTransferableMessage(
std::move(image_bitmap_contents_array));
}
- // Convert the PendingRemote<NativeFileSystemTransferToken> from the
+ // Convert the PendingRemote<FileSystemAccessTransferToken> from the
// blink::mojom namespace to the blink::mojom::blink namespace.
- for (auto& native_file_system_token : message.native_file_system_tokens) {
- uint32_t token_version = native_file_system_token.version();
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
- converted_token(native_file_system_token.PassPipe(), token_version);
- result.message->NativeFileSystemTokens().push_back(
- std::move(converted_token));
+ for (auto& token : message.file_system_access_tokens) {
+ result.message->FileSystemAccessTokens().push_back(
+ ToCrossVariantMojoType(std::move(token)));
}
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.h b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.h
index f71d21ee435..7d54f162691 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.h
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message.h
@@ -39,6 +39,8 @@ struct CORE_EXPORT BlinkTransferableMessage : BlinkCloneableMessage {
mojom::blink::UserActivationSnapshotPtr user_activation;
+ bool delegate_payment_request = false;
+
private:
DISALLOW_COPY_AND_ASSIGN(BlinkTransferableMessage);
};
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.cc b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.cc
index 38f7a1c6471..96ea2a931b1 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.cc
@@ -53,6 +53,8 @@ bool StructTraits<blink::mojom::blink::TransferableMessage::DataView,
blink::SerializedScriptValue::Stream(std::move(channel)));
}
+ out->delegate_payment_request = data.delegate_payment_request();
+
out->message->SetArrayBufferContentsArray(
std::move(array_buffer_contents_array));
array_buffer_contents_array.clear();
diff --git a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.h b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.h
index c52434c3369..4f04f004b0c 100644
--- a/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits.h
@@ -58,6 +58,11 @@ struct CORE_EXPORT StructTraits<blink::mojom::TransferableMessageDataView,
return input.user_activation;
}
+ static bool delegate_payment_request(
+ const blink::BlinkTransferableMessage& input) {
+ return input.delegate_payment_request;
+ }
+
static bool Read(blink::mojom::TransferableMessageDataView,
blink::BlinkTransferableMessage* out);
};
diff --git a/chromium/third_party/blink/renderer/core/messaging/message_port_descriptor_mojom_traits_test.cc b/chromium/third_party/blink/renderer/core/messaging/message_port_descriptor_mojom_traits_test.cc
index 1b31b6f4d0a..b1ee9734254 100644
--- a/chromium/third_party/blink/renderer/core/messaging/message_port_descriptor_mojom_traits_test.cc
+++ b/chromium/third_party/blink/renderer/core/messaging/message_port_descriptor_mojom_traits_test.cc
@@ -28,7 +28,7 @@ TEST(MessagePortDescriptorTest, SerializationWorks) {
// the custom StructTraits.
MessagePortDescriptor port;
mojo::test::SerializeAndDeserialize<mojom::blink::MessagePortDescriptor,
- MessagePortDescriptor>(&port0, &port);
+ MessagePortDescriptor>(port0, port);
EXPECT_TRUE(port0.IsDefault());
EXPECT_TRUE(port.IsValid());
diff --git a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc
index 02fdb31f45f..a3fb99d4929 100644
--- a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc
+++ b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc
@@ -2,16 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <sstream>
-
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
namespace blink {
+const base::Feature kSmallTextRatio{"SmallTextRatio",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
MobileFriendlinessChecker::MobileFriendlinessChecker(LocalFrameView& frame_view)
- : frame_view_(&frame_view) {}
+ : frame_view_(&frame_view),
+ font_size_check_enabled_(base::FeatureList::IsEnabled(kSmallTextRatio) &&
+ frame_view_->GetFrame().GetWidgetForLocalRoot()),
+ needs_report_mf_(false),
+ viewport_scalar_(
+ font_size_check_enabled_
+ ? frame_view_->GetPage()
+ ->GetChromeClient()
+ .WindowToViewportScalar(&frame_view_->GetFrame(), 1)
+ : 0) {}
MobileFriendlinessChecker::~MobileFriendlinessChecker() = default;
@@ -31,8 +49,54 @@ void MobileFriendlinessChecker::NotifyViewportUpdated(
if (viewport.user_zoom_is_explicit)
mobile_friendliness_.allow_user_zoom = viewport.user_zoom;
+ frame_view_->DidChangeMobileFriendliness(mobile_friendliness_);
+}
+
+int MobileFriendlinessChecker::TextAreaWithFontSize::SmallTextRatio() const {
+ if (total_text_area == 0)
+ return 0;
+ return small_font_area * 100 / total_text_area;
+}
+
+void MobileFriendlinessChecker::NotifyInvalidatePaint(
+ const LayoutObject& object) {
+ if (!font_size_check_enabled_)
+ return;
+
+ if (const auto* text = DynamicTo<LayoutText>(object)) {
+ const ComputedStyle* style = text->Style();
+
+ if (style->Visibility() != EVisibility::kVisible)
+ return;
+
+ double actual_font_size = style->FontSize();
+ double initial_scale = frame_view_->GetPage()
+ ->GetPageScaleConstraintsSet()
+ .FinalConstraints()
+ .initial_scale;
+ if (initial_scale > 0)
+ actual_font_size *= initial_scale;
+ actual_font_size /= viewport_scalar_;
+
+ double area = text->PhysicalAreaSize();
+ if (actual_font_size < MobileFriendlinessChecker::kSmallFontThreshold)
+ text_area_sizes_.small_font_area += area;
+ text_area_sizes_.total_text_area += area;
+ const int previous_mfs = mobile_friendliness_.small_text_ratio * 100;
+ mobile_friendliness_.small_text_ratio = text_area_sizes_.SmallTextRatio();
+ const int current_mfs = mobile_friendliness_.small_text_ratio * 100;
+ needs_report_mf_ = needs_report_mf_ || (previous_mfs != current_mfs);
+ }
+}
+
+void MobileFriendlinessChecker::NotifyPrePaintFinished() {
+ if (!font_size_check_enabled_ || !needs_report_mf_)
+ return;
+ DCHECK_EQ(frame_view_->GetFrame().GetDocument()->Lifecycle().GetState(),
+ DocumentLifecycle::kInPrePaint);
frame_view_->DidChangeMobileFriendliness(mobile_friendliness_);
+ needs_report_mf_ = false;
}
void MobileFriendlinessChecker::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h
index 924292966cb..f9e2ce8a0a5 100644
--- a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h
+++ b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h
@@ -9,30 +9,47 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
-class Visitor;
class LocalFrameView;
+class LayoutObject;
struct ViewportDescription;
+CORE_EXPORT extern const base::Feature kSmallTextRatio;
+
// Calculates the mobile usability of current page, especially friendliness on
// smart phone devices are checked. The calculated value will be sent as a part
// of UKM.
class CORE_EXPORT MobileFriendlinessChecker
: public GarbageCollected<MobileFriendlinessChecker> {
+ static constexpr int kSmallFontThreshold = 12;
+
public:
explicit MobileFriendlinessChecker(LocalFrameView& frame_view);
virtual ~MobileFriendlinessChecker();
void NotifyViewportUpdated(const ViewportDescription&);
+ void NotifyInvalidatePaint(const LayoutObject& object);
+ void NotifyPrePaintFinished();
const blink::MobileFriendliness& GetMobileFriendliness() const {
return mobile_friendliness_;
}
void Trace(Visitor* visitor) const;
+ struct TextAreaWithFontSize {
+ double small_font_area = 0;
+ double total_text_area = 0;
+ int SmallTextRatio() const;
+ };
+
private:
+ TextAreaWithFontSize text_area_sizes_;
Member<LocalFrameView> frame_view_;
blink::MobileFriendliness mobile_friendliness_;
+ bool font_size_check_enabled_;
+ bool needs_report_mf_;
+ float viewport_scalar_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc
index 668c112449c..16dfef12ad6 100644
--- a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc
+++ b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
+#include "base/test/scoped_feature_list.h"
#include "third_party/blink/public/common/mobile_metrics/mobile_friendliness.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/mobile_metrics/mobile_metrics_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -19,48 +21,68 @@ class MobileFriendlinessCheckerTest : public testing::Test {
url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
}
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(kSmallTextRatio);
+ }
+
static void ConfigureAndroidSettings(WebSettings* settings) {
- settings->SetJavaScriptEnabled(true);
- settings->SetPreferCompositingToLCDTextEnabled(true);
settings->SetViewportEnabled(true);
settings->SetViewportMetaEnabled(true);
- settings->SetShrinksViewportContentToFit(true);
- settings->SetMainFrameResizesAreOrientationChanges(true);
}
- void SetUp() override {
- helper_.Initialize(nullptr, nullptr, nullptr, ConfigureAndroidSettings);
+ MobileFriendliness CalculateMetricsForHTMLString(const std::string& html) {
+ mobile_metrics_test_helpers::TestWebFrameClient web_frame_client;
+ {
+ // This scope is required to make sure that ~WebViewHelper() is called
+ // before the return value of this function is determined. Because
+ // MobileFriendlinessChecker::NotifyDocumentDestroying is called in
+ // destruction sequence of WebView.
+ frame_test_helpers::WebViewHelper helper;
+ helper.Initialize(&web_frame_client, nullptr, ConfigureAndroidSettings);
+ helper.GetWebView()->EnableAutoResizeForTesting(gfx::Size(480, 800),
+ gfx::Size(480, 800));
+ frame_test_helpers::LoadHTMLString(
+ helper.GetWebView()->MainFrameImpl(), html,
+ url_test_helpers::ToKURL("about:blank"));
+ LocalFrameView& frame_view =
+ *helper.GetWebView()->MainFrameImpl()->GetFrameView();
+ frame_view.UpdateLifecycleToPrePaintClean(DocumentUpdateReason::kTest);
+ }
+ return web_frame_client.GetMobileFriendliness();
}
- WebViewImpl* WebView() const { return helper_.GetWebView(); }
-
- const MobileFriendliness& CalculateMobileFriendlinessFromFile(
- const std::string& path) {
- RegisterMockedHttpURLLoad(path);
- NavigateTo(kBaseUrl + path);
- LocalFrameView& frame_view = *WebView()->MainFrameImpl()->GetFrameView();
- frame_view.UpdateLifecycleToPrePaintClean(DocumentUpdateReason::kTest);
- return frame_view.GetMobileFriendlinessChecker().GetMobileFriendliness();
+ MobileFriendliness CalculateMetricsForFile(const std::string& path) {
+ mobile_metrics_test_helpers::TestWebFrameClient web_frame_client;
+ {
+ // This scope is required to make sure that ~WebViewHelper() is called
+ // before the return value of this function is determined. Because
+ // MobileFriendlinessChecker::NotifyDocumentDestroying is called in
+ // destruction sequence of WebView.
+ frame_test_helpers::WebViewHelper helper;
+ helper.Initialize(&web_frame_client, nullptr, ConfigureAndroidSettings);
+ helper.GetWebView()->EnableAutoResizeForTesting(gfx::Size(480, 800),
+ gfx::Size(480, 800));
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(kBaseUrl), blink::test::CoreTestDataPath(),
+ WebString::FromUTF8(path));
+ frame_test_helpers::LoadFrame(helper.GetWebView()->MainFrameImpl(),
+ kBaseUrl + path);
+ LocalFrameView& frame_view =
+ *helper.GetWebView()->MainFrameImpl()->GetFrameView();
+ frame_view.UpdateLifecycleToPrePaintClean(DocumentUpdateReason::kTest);
+ }
+ return web_frame_client.GetMobileFriendliness();
}
private:
- void NavigateTo(const std::string& url) {
- frame_test_helpers::LoadFrame(WebView()->MainFrameImpl(), url);
- }
-
- void RegisterMockedHttpURLLoad(const std::string& file_name) {
- url_test_helpers::RegisterMockedURLLoadFromBase(
- WebString::FromUTF8(kBaseUrl), blink::test::CoreTestDataPath(),
- WebString::FromUTF8(file_name));
- }
-
- frame_test_helpers::WebViewHelper helper_;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(MobileFriendlinessCheckerTest, NoViewportSetting) {
MobileFriendliness expected_mf;
+ expected_mf.small_text_ratio = 100;
MobileFriendliness actual_mf =
- CalculateMobileFriendlinessFromFile("bar.html");
+ CalculateMetricsForHTMLString("<body>bar</body>");
EXPECT_EQ(expected_mf, actual_mf);
}
@@ -68,7 +90,7 @@ TEST_F(MobileFriendlinessCheckerTest, DeviceWidth) {
MobileFriendliness expected_mf;
expected_mf.viewport_device_width = true;
MobileFriendliness actual_mf =
- CalculateMobileFriendlinessFromFile("viewport/viewport-1.html");
+ CalculateMetricsForFile("viewport/viewport-1.html");
EXPECT_EQ(expected_mf, actual_mf);
}
@@ -76,7 +98,7 @@ TEST_F(MobileFriendlinessCheckerTest, HardcodedViewport) {
MobileFriendliness expected_mf;
expected_mf.viewport_hardcoded_width = 200;
MobileFriendliness actual_mf =
- CalculateMobileFriendlinessFromFile("viewport/viewport-30.html");
+ CalculateMetricsForFile("viewport/viewport-30.html");
EXPECT_EQ(expected_mf, actual_mf);
}
@@ -87,7 +109,7 @@ TEST_F(MobileFriendlinessCheckerTest, DeviceWidthWithInitialScale05) {
expected_mf.viewport_device_width = true;
expected_mf.viewport_initial_scale = 0.5;
MobileFriendliness actual_mf =
- CalculateMobileFriendlinessFromFile("viewport/viewport-34.html");
+ CalculateMetricsForFile("viewport/viewport-34.html");
EXPECT_EQ(expected_mf, actual_mf);
}
@@ -96,9 +118,189 @@ TEST_F(MobileFriendlinessCheckerTest, UserZoom) {
expected_mf.viewport_device_width = true;
expected_mf.viewport_initial_scale = 2.0;
expected_mf.allow_user_zoom = false;
- MobileFriendliness actual_mf = CalculateMobileFriendlinessFromFile(
+ expected_mf.small_text_ratio = 100;
+ MobileFriendliness actual_mf = CalculateMetricsForFile(
"viewport-initial-scale-and-user-scalable-no.html");
EXPECT_EQ(expected_mf, actual_mf);
}
+TEST_F(MobileFriendlinessCheckerTest, NoText) {
+ MobileFriendliness expected_mf;
+ expected_mf.small_text_ratio = 0;
+ MobileFriendliness actual_mf =
+ CalculateMetricsForHTMLString(R"(<body></body>)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, NoSmallFonts) {
+ MobileFriendliness expected_mf;
+ expected_mf.small_text_ratio = 0;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<div style="font-size: 12px">
+ This is legible font size example.
+</div>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, OnlySmallFonts) {
+ MobileFriendliness expected_mf;
+ expected_mf.small_text_ratio = 100;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<div style="font-size:7px">
+ Small font text.
+</div>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, MostlySmallFont) {
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<div style="font-size:12px">
+ legible text.
+ <div style="font-size:8px">
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ The quick brown fox jumps over the lazy dog.<br>
+ </div>
+</div>
+)");
+ EXPECT_LT(actual_mf.small_text_ratio, 100);
+ EXPECT_GT(actual_mf.small_text_ratio, 80);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, MostlySmallInSpan) {
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<div style="font-size: 12px">
+ x
+ <span style="font-size:11px">
+ This is the majority part of the document.
+ </span>
+ y
+</div>
+)");
+ EXPECT_LT(actual_mf.small_text_ratio, 100);
+ EXPECT_GT(actual_mf.small_text_ratio, 80);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, MultipleDivs) {
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<div style="font-size: 12px">
+ x
+ <div style="font-size:11px">
+ middle of div
+ <div style="font-size:1px">
+ inner of div
+ </div>
+ </div>
+ y
+</div>
+)");
+ EXPECT_LT(actual_mf.small_text_ratio, 100);
+ EXPECT_GT(actual_mf.small_text_ratio, 80);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, DontCountInvisibleSmallFontArea) {
+ MobileFriendliness expected_mf;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<html>
+ <body>
+ <div style="font-size: 12px">
+ x
+ <div style="font-size:4px;display:none;">
+ this is an invisible string.
+ </div>
+ </div>
+ </body>
+</html>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, ScaleZoomedLegibleFont) {
+ MobileFriendliness expected_mf;
+ expected_mf.viewport_device_width = true;
+ expected_mf.viewport_initial_scale = 10;
+ expected_mf.small_text_ratio = 0;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=10">
+ </head>
+ <body style="font-size: 5px">
+ Legible text in 50px.
+ </body>
+</html>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, ViewportZoomedOutIllegibleFont) {
+ MobileFriendliness expected_mf;
+ expected_mf.viewport_hardcoded_width = 480;
+ expected_mf.viewport_initial_scale = 0.5;
+ expected_mf.small_text_ratio = 100;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<html>
+ <head>
+ <meta name="viewport" content="width=480, initial-scale=0.5">
+ </head>
+ <body style="font-size: 22px; width: 960px">
+ Illegible text in 11px.
+ </body>
+</html>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, TooWideViewportWidthIllegibleFont) {
+ MobileFriendliness expected_mf;
+ expected_mf.viewport_hardcoded_width = 960;
+ expected_mf.small_text_ratio = 100;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<html>
+ <head>
+ <meta name="viewport" content="width=960">
+ </head>
+ <body style="font-size: 12px">
+ Illegible text in 6px.
+ </body>
+</html>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
+TEST_F(MobileFriendlinessCheckerTest, CSSZoomedIllegibleFont) {
+ MobileFriendliness expected_mf;
+ expected_mf.small_text_ratio = 100;
+ MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"(
+<html>
+ <body style="font-size: 12px; zoom:50%">
+ Illegible text in 6px.
+ </body>
+</html>
+)");
+ EXPECT_EQ(expected_mf, actual_mf);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_metrics_test_helpers.h b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_metrics_test_helpers.h
new file mode 100644
index 00000000000..1601f8bf878
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/mobile_metrics/mobile_metrics_test_helpers.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_MOBILE_METRICS_MOBILE_METRICS_TEST_HELPERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_MOBILE_METRICS_MOBILE_METRICS_TEST_HELPERS_H_
+
+#include "third_party/blink/public/common/mobile_metrics/mobile_friendliness.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+
+namespace blink {
+namespace mobile_metrics_test_helpers {
+
+class TestWebFrameClient : public frame_test_helpers::TestWebFrameClient {
+ public:
+ void DidChangeMobileFriendliness(const MobileFriendliness& mf) override {
+ mobile_friendliness_ = mf;
+ }
+ const MobileFriendliness& GetMobileFriendliness() const {
+ return mobile_friendliness_;
+ }
+
+ private:
+ MobileFriendliness mobile_friendliness_;
+};
+
+} // namespace mobile_metrics_test_helpers
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_MOBILE_METRICS_MOBILE_METRICS_TEST_HELPERS_H_
diff --git a/chromium/third_party/blink/renderer/core/mojo/BUILD.gn b/chromium/third_party/blink/renderer/core/mojo/BUILD.gn
deleted file mode 100644
index ecbb304b5fa..00000000000
--- a/chromium/third_party/blink/renderer/core/mojo/BUILD.gn
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-import("//third_party/blink/renderer/core/core.gni")
-
-source_set("unit_tests") {
- testonly = true
- sources = [ "tests/js_to_cpp_test.cc" ]
-
- data = [ "tests/JsToCppTest.js" ]
-
- configs += [
- "//third_party/blink/renderer/core:blink_core_pch",
- "//third_party/blink/renderer:config",
- "//third_party/blink/renderer:inside_blink",
- ]
-
- deps = [
- ":test_bindings_blink",
- "//mojo/public/cpp/bindings",
- "//testing/gtest",
- "//third_party/blink/renderer/controller:blink_bindings_test_sources",
- "//third_party/blink/renderer/core:core",
- "//third_party/blink/renderer/core:testing",
- "//third_party/blink/renderer/platform:test_support",
- ]
-
- data_deps = [
- ":test_bindings_js_data_deps",
- "//mojo/public/js:bindings",
- ]
-}
-
-mojom("test_bindings") {
- sources = [ "tests/js_to_cpp.mojom" ]
-}
diff --git a/chromium/third_party/blink/renderer/core/mojo/DIR_METADATA b/chromium/third_party/blink/renderer/core/mojo/DIR_METADATA
new file mode 100644
index 00000000000..92214b2320a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/mojo/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Mojo"
+}
diff --git a/chromium/third_party/blink/renderer/core/mojo/OWNERS b/chromium/third_party/blink/renderer/core/mojo/OWNERS
index 8df388c3640..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/core/mojo/OWNERS
+++ b/chromium/third_party/blink/renderer/core/mojo/OWNERS
@@ -1 +0,0 @@
-# COMPONENT: Internals>Mojo
diff --git a/chromium/third_party/blink/renderer/core/mojo/mojo.cc b/chromium/third_party/blink/renderer/core/mojo/mojo.cc
index 28de5f1938d..5a25af41c61 100644
--- a/chromium/third_party/blink/renderer/core/mojo/mojo.cc
+++ b/chromium/third_party/blink/renderer/core/mojo/mojo.cc
@@ -65,7 +65,7 @@ MojoCreateDataPipeResult* Mojo::createDataPipe(
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
- MojoResult result = mojo::CreateDataPipe(&options, &producer, &consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
result_dict->setResult(result);
if (result == MOJO_RESULT_OK) {
result_dict->setProducer(MakeGarbageCollected<MojoHandle>(
diff --git a/chromium/third_party/blink/renderer/core/mojo/mojo_handle.cc b/chromium/third_party/blink/renderer/core/mojo/mojo_handle.cc
index 8f61701fd46..a6bb3032531 100644
--- a/chromium/third_party/blink/renderer/core/mojo/mojo_handle.cc
+++ b/chromium/third_party/blink/renderer/core/mojo/mojo_handle.cc
@@ -72,7 +72,7 @@ MojoResult MojoHandle::writeMessage(
bytes = array->Data();
num_bytes = array->ByteLength();
} else {
- DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
+ DOMArrayBufferView* view = buffer.GetAsArrayBufferView().Get();
bytes = view->BaseAddress();
num_bytes = view->byteLength();
}
@@ -156,7 +156,7 @@ MojoWriteDataResult* MojoHandle::writeData(
elements = array->Data();
checked_num_bytes = array->ByteLength();
} else {
- DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
+ DOMArrayBufferView* view = buffer.GetAsArrayBufferView().Get();
elements = view->BaseAddress();
checked_num_bytes = view->byteLength();
}
@@ -222,7 +222,7 @@ MojoReadDataResult* MojoHandle::readData(
elements = array->Data();
checked_num_bytes = array->ByteLength();
} else {
- DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
+ DOMArrayBufferView* view = buffer.GetAsArrayBufferView().Get();
elements = view->BaseAddress();
checked_num_bytes = view->byteLength();
}
diff --git a/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.cc b/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.cc
index c7bd5290b8c..b22586872e3 100644
--- a/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.cc
+++ b/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.cc
@@ -89,6 +89,11 @@ MojoResult MojoWatcher::Watch(mojo::Handle handle,
if (result != MOJO_RESULT_OK)
return result;
+ // If MojoAddTrigger succeeded above, we need this object to stay alive at
+ // least until OnHandleReady is invoked with MOJO_RESULT_CANCELLED, which
+ // signals the final invocation by the trap.
+ keep_alive_ = this;
+
handle_ = handle;
MojoResult ready_result;
@@ -137,10 +142,9 @@ MojoResult MojoWatcher::Arm(MojoResult* ready_result) {
// static
void MojoWatcher::OnHandleReady(const MojoTrapEvent* event) {
- // It is safe to assume the MojoWathcer still exists. It stays alive at least
- // as long as |handle_| is valid, and |handle_| is only reset after we
- // dispatch a |MOJO_RESULT_CANCELLED| notification. That is always the last
- // notification received by this callback.
+ // It is safe to assume the MojoWathcer still exists, because we keep it alive
+ // until we've dispatched MOJO_RESULT_CANCELLED from here to RunReadyCallback,
+ // and that is always the last notification we'll dispatch.
MojoWatcher* watcher = reinterpret_cast<MojoWatcher*>(event->trigger_context);
PostCrossThreadTask(
*watcher->task_runner_, FROM_HERE,
@@ -152,6 +156,7 @@ void MojoWatcher::OnHandleReady(const MojoTrapEvent* event) {
void MojoWatcher::RunReadyCallback(MojoResult result) {
if (result == MOJO_RESULT_CANCELLED) {
// Last notification.
+ keep_alive_.Clear();
handle_ = mojo::Handle();
// Only dispatch to the callback if this cancellation was implicit due to
diff --git a/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.h b/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.h
index c1ce045f924..a83e72da10e 100644
--- a/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.h
+++ b/chromium/third_party/blink/renderer/core/mojo/mojo_watcher.h
@@ -10,6 +10,11 @@
#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"
+#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
namespace blink {
@@ -50,6 +55,7 @@ class MojoWatcher final : public ScriptWrappable,
static void OnHandleReady(const MojoTrapEvent*);
void RunReadyCallback(MojoResult);
+ SelfKeepAlive<MojoWatcher> keep_alive_{PERSISTENT_FROM_HERE};
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
Member<V8MojoWatchCallback> callback_;
mojo::ScopedTrapHandle trap_handle_;
diff --git a/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc b/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
index 5d669b90821..2c7d62b61ff 100644
--- a/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
+++ b/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h"
+#include <utility>
+
#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"
@@ -140,7 +142,7 @@ void MojoInterfaceInterceptor::OnInterfaceRequest(
->PostTask(
FROM_HERE,
WTF::Bind(&MojoInterfaceInterceptor::DispatchInterfaceRequestEvent,
- WrapPersistent(this), WTF::Passed(std::move(handle))));
+ WrapPersistent(this), std::move(handle)));
}
void MojoInterfaceInterceptor::DispatchInterfaceRequestEvent(
diff --git a/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h b/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
index c4f96747bd8..100c08641cd 100644
--- a/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
+++ b/chromium/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_MOJO_TEST_MOJO_INTERFACE_INTERCEPTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_MOJO_TEST_MOJO_INTERFACE_INTERCEPTOR_H_
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/dom/events/event_listener.h"
diff --git a/chromium/third_party/blink/renderer/core/mojo/tests/js_to_cpp.mojom b/chromium/third_party/blink/renderer/core/mojo/tests/js_to_cpp.mojom
deleted file mode 100644
index ca63916cc4b..00000000000
--- a/chromium/third_party/blink/renderer/core/mojo/tests/js_to_cpp.mojom
+++ /dev/null
@@ -1,61 +0,0 @@
-module js_to_cpp;
-
-// This struct encompasses all of the basic types, so that they
-// may be sent from C++ to JS and back for validation.
-struct EchoArgs {
- int64 si64;
- int32 si32;
- int16 si16;
- int8 si8;
- uint64 ui64;
- uint32 ui32;
- uint16 ui16;
- uint8 ui8;
- float float_val;
- float float_inf;
- float float_nan;
- double double_val;
- double double_inf;
- double double_nan;
- string? name;
- array<string>? string_array;
- handle<message_pipe>? message_handle;
- handle<data_pipe_consumer>? data_handle;
-};
-
-struct EchoArgsList {
- EchoArgsList? next;
- EchoArgs? item;
-};
-
-interface ForTesting {};
-
-// Note: For messages which control test flow, pick numbers that are unlikely
-// to be hit as a result of our deliberate corruption of response messages.
-interface CppSide {
- // Sent for all tests to notify that the JS side is now ready.
- StartTest@88888888();
-
- // Indicates end for echo, bit-flip, and back-pointer tests.
- TestFinished@99999999();
-
- // Responses from specific tests.
- PingResponse();
- EchoResponse(EchoArgsList list);
-
- // Having an associated remote in the message makes sure the message header
- // version 2 is tested.
- BitFlipResponse(EchoArgsList arg,
- pending_associated_remote<ForTesting>? not_used);
-
- BackPointerResponse(EchoArgsList arg);
-};
-
-interface JsSide {
- SetCppSide(pending_remote<CppSide> cpp);
-
- Ping();
- Echo(int32 numIterations, EchoArgs arg);
- BitFlip(EchoArgs arg);
- BackPointer(EchoArgs arg);
-};
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/DIR_METADATA b/chromium/third_party/blink/renderer/core/offscreencanvas/DIR_METADATA
new file mode 100644
index 00000000000..4ae95d48d73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Canvas"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/OWNERS b/chromium/third_party/blink/renderer/core/offscreencanvas/OWNERS
index 5ef87b1aa3f..1e563633b29 100644
--- a/chromium/third_party/blink/renderer/core/offscreencanvas/OWNERS
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/OWNERS
@@ -1,4 +1 @@
fserb@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
diff --git a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index a98d3ace666..efd549225cc 100644
--- a/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -12,6 +12,7 @@
#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/platform/platform.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
#include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
@@ -39,6 +40,7 @@
#include "third_party/blink/renderer/platform/image-encoders/image_encoder_utils.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/skia/include/core/SkFilterQuality.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -221,13 +223,6 @@ ImageBitmap* OffscreenCanvas::transferToImageBitmap(
"ImageBitmap construction failed");
}
- RecordIdentifiabilityMetric(
- blink::IdentifiableSurface::FromTypeAndToken(
- blink::IdentifiableSurface::Type::kCanvasReadback,
- context_ ? context_->GetContextType()
- : CanvasRenderingContext::kContextTypeUnknown),
- 0);
-
return image;
}
@@ -301,6 +296,12 @@ CanvasRenderingContext* OffscreenCanvas::GetCanvasRenderingContext(
return nullptr;
}
+ if (attributes.color_space != kSRGBCanvasColorSpaceName ||
+ attributes.pixel_format != kUint8CanvasPixelFormatName) {
+ if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext()))
+ UseCounter::Count(window->document(), WebFeature::kCanvasUseColorSpace);
+ }
+
// Log the aliased context type used.
if (!context_) {
UMA_HISTOGRAM_ENUMERATION("Blink.OffscreenCanvas.ContextType",
@@ -368,11 +369,32 @@ CanvasResourceDispatcher* OffscreenCanvas::GetOrCreateResourceDispatcher() {
// If we don't have a valid placeholder_canvas_id_, then this is a standalone
// OffscreenCanvas, and it should not have a placeholder.
if (!frame_dispatcher_) {
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner;
+ if (auto* global_scope =
+ DynamicTo<WorkerGlobalScope>(GetTopExecutionContext())) {
+ // When OffscreenCanvas is used from Worker, the per-AgentGroupScheduler
+ // |CompositorTaskRunner| can be obtained from |WorkerGlobalScope|.
+ agent_group_scheduler_compositor_task_runner =
+ global_scope->GetAgentGroupSchedulerCompositorTaskRunner();
+ } else {
+ // It is possible to use OffscreenCanvas from the main thread. If
+ // |OffscreenCanvas| is used from the main thread, per-AgentGroupScheduler
+ // |CompositorTaskRunner| can be obtained from |FrameScheduler|.
+ agent_group_scheduler_compositor_task_runner =
+ GetTopExecutionContext()
+ ->GetScheduler()
+ ->ToFrameScheduler()
+ ->GetAgentGroupScheduler()
+ ->CompositorTaskRunner();
+ }
+ DCHECK(agent_group_scheduler_compositor_task_runner);
// The frame dispatcher connects the current thread of OffscreenCanvas
// (either main or worker) to the browser process and remains unchanged
// throughout the lifetime of this OffscreenCanvas.
frame_dispatcher_ = std::make_unique<CanvasResourceDispatcher>(
- this, client_id_, sink_id_, placeholder_canvas_id_, size_);
+ this, std::move(agent_group_scheduler_compositor_task_runner),
+ client_id_, sink_id_, placeholder_canvas_id_, size_);
if (HasPlaceholderCanvas())
frame_dispatcher_->SetPlaceholderCanvasDispatcher(placeholder_canvas_id_);
@@ -394,19 +416,16 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() {
(Is3d() ? RuntimeEnabledFeatures::WebGLImageChromiumEnabled()
: RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled());
- // If this context has a placeholder, the resource needs to be optimized for
- // displaying on screen. In the case we are hardware compositing, we also
- // try to enable the usage of the image as scanout buffer (overlay).
- uint32_t shared_image_usage_flags = 0u;
- if (HasPlaceholderCanvas()) {
- shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_DISPLAY;
- if (composited_mode)
- shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
- }
+ uint32_t shared_image_usage_flags = gpu::SHARED_IMAGE_USAGE_DISPLAY;
+ if (composited_mode)
+ shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
+ const CanvasResourceParams resource_params =
+ context_->CanvasRenderingContextColorParams().GetAsResourceParams();
+ const SkFilterQuality filter_quality = FilterQuality();
if (can_use_gpu) {
provider = CanvasResourceProvider::CreateSharedImageProvider(
- surface_size, FilterQuality(), context_->ColorParams(),
+ surface_size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
false /*is_origin_top_left*/, shared_image_usage_flags);
@@ -414,7 +433,7 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() {
// Only try a SoftwareComposited SharedImage if the context has Placeholder
// canvas and the composited mode is enabled.
provider = CanvasResourceProvider::CreateSharedImageProvider(
- surface_size, FilterQuality(), context_->ColorParams(),
+ surface_size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kCPU,
false /*is_origin_top_left*/, shared_image_usage_flags);
@@ -427,7 +446,7 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() {
base::WeakPtr<CanvasResourceDispatcher> dispatcher_weakptr =
GetOrCreateResourceDispatcher()->GetWeakPtr();
provider = CanvasResourceProvider::CreateSharedBitmapProvider(
- surface_size, FilterQuality(), context_->ColorParams(),
+ surface_size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear,
std::move(dispatcher_weakptr));
}
@@ -436,7 +455,7 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() {
// If any of the above Create was able to create a valid provider, a
// BitmapProvider will be created here.
provider = CanvasResourceProvider::CreateBitmapProvider(
- surface_size, FilterQuality(), context_->ColorParams(),
+ surface_size, filter_quality, resource_params,
CanvasResourceProvider::ShouldInitialize::kCallClear);
}
diff --git a/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
index a2d2cbbd7d5..54a93a62f72 100644
--- a/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
+++ b/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -384,7 +384,10 @@ bool OriginTrialContext::CanEnableTrialFromName(const StringView& trial_name) {
!base::FeatureList::IsEnabled(network::features::kTrustTokens)) {
return false;
}
-
+ if (trial_name == "InterestCohortAPI" &&
+ !base::FeatureList::IsEnabled(features::kInterestCohortAPIOriginTrial)) {
+ return false;
+ }
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc b/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
index 4a300160ba4..6cc4544f525 100644
--- a/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
@@ -93,6 +93,9 @@ class OriginTrialContextTest : public testing::Test {
->SetTrialTokenValidatorForTesting(
std::unique_ptr<MockTokenValidator>(token_validator_));
}
+ ~OriginTrialContextTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
MockTokenValidator* TokenValidator() { return token_validator_; }
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
index 84e4f01a35c..cc558625673 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.cc
@@ -29,11 +29,13 @@
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/input/scroll_manager.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -143,6 +145,18 @@ void AutoscrollController::StopAutoscrollIfNeeded(LayoutObject* layout_object) {
if (pressed_layout_object_ == layout_object)
pressed_layout_object_ = nullptr;
+ if (horizontal_autoscroll_layout_box_ == layout_object)
+ horizontal_autoscroll_layout_box_ = nullptr;
+
+ if (vertical_autoscroll_layout_box_ == layout_object)
+ vertical_autoscroll_layout_box_ = nullptr;
+
+ if (MiddleClickAutoscrollInProgress() && !horizontal_autoscroll_layout_box_ &&
+ !vertical_autoscroll_layout_box_) {
+ page_->GetChromeClient().AutoscrollEnd(layout_object->GetFrame());
+ autoscroll_type_ = kNoAutoscroll;
+ }
+
if (autoscroll_layout_object_ != layout_object)
return;
autoscroll_layout_object_ = nullptr;
@@ -250,7 +264,16 @@ void AutoscrollController::HandleMouseMoveForMiddleClickAutoscroll(
if (!MiddleClickAutoscrollInProgress())
return;
- if (!autoscroll_layout_object_->CanBeScrolledAndHasScrollableArea()) {
+ bool horizontal_autoscroll_possible =
+ horizontal_autoscroll_layout_box_ &&
+ horizontal_autoscroll_layout_box_->GetNode();
+ bool vertical_autoscroll_possible =
+ vertical_autoscroll_layout_box_ &&
+ vertical_autoscroll_layout_box_->GetNode();
+ if (horizontal_autoscroll_possible &&
+ !horizontal_autoscroll_layout_box_->CanBeScrolledAndHasScrollableArea() &&
+ vertical_autoscroll_possible &&
+ !vertical_autoscroll_layout_box_->CanBeScrolledAndHasScrollableArea()) {
StopMiddleClickAutoscroll(frame);
return;
}
@@ -277,11 +300,17 @@ void AutoscrollController::HandleMouseMoveForMiddleClickAutoscroll(
pow(fabs(distance.Height()), kExponent) * kMultiplier * y_signum);
bool can_scroll_vertically =
- CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
- ScrollOrientation::kVerticalScroll);
+ vertical_autoscroll_possible
+ ? CanScrollDirection(vertical_autoscroll_layout_box_,
+ frame->GetPage(),
+ ScrollOrientation::kVerticalScroll)
+ : false;
bool can_scroll_horizontally =
- CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
- ScrollOrientation::kHorizontalScroll);
+ horizontal_autoscroll_possible
+ ? CanScrollDirection(horizontal_autoscroll_layout_box_,
+ frame->GetPage(),
+ ScrollOrientation::kHorizontalScroll)
+ : false;
if (velocity != last_velocity_) {
last_velocity_ = velocity;
@@ -319,7 +348,8 @@ void AutoscrollController::StopMiddleClickAutoscroll(LocalFrame* frame) {
autoscroll_type_ = kNoAutoscroll;
page_->GetChromeClient().SetCursorOverridden(false);
frame->LocalFrameRoot().GetEventHandler().UpdateCursor();
- autoscroll_layout_object_ = nullptr;
+ horizontal_autoscroll_layout_box_ = nullptr;
+ vertical_autoscroll_layout_box_ = nullptr;
}
bool AutoscrollController::MiddleClickAutoscrollInProgress() const {
@@ -338,17 +368,65 @@ void AutoscrollController::StartMiddleClickAutoscroll(
if (autoscroll_type_ != kNoAutoscroll)
return;
- autoscroll_layout_object_ = scrollable;
autoscroll_type_ = kAutoscrollForMiddleClick;
middle_click_mode_ = kMiddleClickInitial;
middle_click_autoscroll_start_pos_global_ = position_global;
- bool can_scroll_vertically =
- CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
- ScrollOrientation::kVerticalScroll);
- bool can_scroll_horizontally =
- CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
- ScrollOrientation::kHorizontalScroll);
+ bool can_scroll_vertically = false;
+ bool can_scroll_horizontally = false;
+
+ // Scroll propagation can be prevented in either direction independently.
+ // We check whether autoscroll can be prevented in either direction after
+ // checking whether the layout box can be scrolled. If propagation is not
+ // allowed, we do not perform further checks for whether parents can be
+ // scrolled in that direction.
+ bool can_propagate_vertically = true;
+ bool can_propagate_horizontally = true;
+
+ LayoutObject* layout_object = scrollable->GetNode()->GetLayoutObject();
+
+ while (layout_object && !(can_scroll_horizontally && can_scroll_vertically)) {
+ if (LayoutBox* layout_box = DynamicTo<LayoutBox>(layout_object)) {
+ // Check whether the layout box can be scrolled and has horizontal
+ // scrollable area.
+ if (can_propagate_vertically &&
+ CanScrollDirection(layout_box, frame->GetPage(),
+ ScrollOrientation::kVerticalScroll) &&
+ !vertical_autoscroll_layout_box_) {
+ vertical_autoscroll_layout_box_ = layout_box;
+ can_scroll_vertically = true;
+ }
+ // Check whether the layout box can be scrolled and has vertical
+ // scrollable area.
+ if (can_propagate_horizontally &&
+ CanScrollDirection(layout_box, frame->GetPage(),
+ ScrollOrientation::kHorizontalScroll) &&
+ !horizontal_autoscroll_layout_box_) {
+ horizontal_autoscroll_layout_box_ = layout_box;
+ can_scroll_horizontally = true;
+ }
+
+ can_propagate_vertically = ScrollManager::CanPropagate(
+ layout_box, ScrollPropagationDirection::kVertical);
+ can_propagate_horizontally = ScrollManager::CanPropagate(
+ layout_box, ScrollPropagationDirection::kHorizontal);
+ }
+
+ // Exit loop if we can't propagate to the parent in any direction or if
+ // layout boxes have been found for both directions.
+ if ((!can_propagate_vertically && !can_propagate_horizontally) ||
+ (can_scroll_horizontally && can_scroll_vertically))
+ break;
+
+ if (!layout_object->Parent() &&
+ layout_object->GetNode() == layout_object->GetDocument() &&
+ layout_object->GetDocument().LocalOwner()) {
+ layout_object =
+ layout_object->GetDocument().LocalOwner()->GetLayoutObject();
+ } else {
+ layout_object = layout_object->Parent();
+ }
+ }
UseCounter::Count(frame->GetDocument(),
WebFeature::kMiddleClickAutoscrollStart);
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
index 7e04c417625..0b0a7118604 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller.h
@@ -84,7 +84,7 @@ class CORE_EXPORT AutoscrollController final
// Middle-click autoscroll.
void StartMiddleClickAutoscroll(LocalFrame*,
- LayoutBox*,
+ LayoutBox* scrollable,
const FloatPoint& position,
const FloatPoint& position_global);
void HandleMouseMoveForMiddleClickAutoscroll(
@@ -102,15 +102,17 @@ class CORE_EXPORT AutoscrollController final
Member<Page> page_;
AutoscrollType autoscroll_type_ = kNoAutoscroll;
- LayoutBox* autoscroll_layout_object_ = nullptr;
// Selection and drag-and-drop autoscroll.
void ScheduleMainThreadAnimation();
+ LayoutBox* autoscroll_layout_object_ = nullptr;
LayoutBox* pressed_layout_object_ = nullptr;
PhysicalOffset drag_and_drop_autoscroll_reference_position_;
base::TimeTicks drag_and_drop_autoscroll_start_time_;
// Middle-click autoscroll.
+ LayoutBox* horizontal_autoscroll_layout_box_ = nullptr;
+ LayoutBox* vertical_autoscroll_layout_box_ = nullptr;
FloatPoint middle_click_autoscroll_start_pos_global_;
gfx::Vector2dF last_velocity_;
MiddleClickMode middle_click_mode_ = kMiddleClickInitial;
@@ -120,6 +122,9 @@ class CORE_EXPORT AutoscrollController final
FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest,
ContinueAutoscrollAfterMouseLeaveEvent);
FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest, StopAutoscrollOnResize);
+ FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest, AutoscrollIsNotPropagated);
+ FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest,
+ AutoscrollIsPropagatedInYDirection);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc b/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
index d24da0e3c36..ddd6816847b 100644
--- a/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
@@ -182,4 +182,102 @@ TEST_F(AutoscrollControllerTest, StopAutoscrollOnResize) {
EXPECT_TRUE(controller.IsAutoscrolling());
}
+// Ensure that middle click autoscroll is not propagated in a direction when
+// propagation is not allowed.
+TEST_F(AutoscrollControllerTest, AutoscrollIsNotPropagated) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <style>
+ #scrollable {
+ width: 820px;
+ height: 620px;
+ overflow: auto;
+ overscroll-behavior: contain;
+ }
+ #inner {
+ width: 2500px;
+ background-color: aqua;
+ height: 100px;
+ }
+ </style>
+ </head>
+ <body style='width: 3000px; height: 3000px;'>
+ <div id="scrollable">
+ <div id="inner"></div>
+ </div>
+ </body>
+ </html>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ AutoscrollController& controller = GetAutoscrollController();
+
+ EXPECT_FALSE(controller.IsAutoscrolling());
+
+ LocalFrame* frame = GetDocument().GetFrame();
+ LayoutBox* scrollable =
+ GetDocument().getElementById("scrollable")->GetLayoutBox();
+
+ controller.StartMiddleClickAutoscroll(
+ frame, scrollable, FloatPoint(15.0, 15.0), FloatPoint(15.0, 15.0));
+
+ EXPECT_TRUE(controller.IsAutoscrolling());
+ EXPECT_TRUE(controller.horizontal_autoscroll_layout_box_);
+ EXPECT_FALSE(controller.vertical_autoscroll_layout_box_);
+}
+
+// Ensure that middle click autoscroll is propagated in a direction when
+// overscroll-behavior is set to auto for a that direction.
+TEST_F(AutoscrollControllerTest, AutoscrollIsPropagatedInYDirection) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <style>
+ #scrollable {
+ width: 820px;
+ height: 620px;
+ overflow: auto;
+ overscroll-behavior-x: contain;
+ }
+ #inner {
+ width: 1000px;
+ background-color: aqua;
+ height: 100px;
+ }
+ </style>
+ </head>
+ <body style='width: 3000px; height: 3000px;'>
+ <div id="scrollable">
+ <div id="inner"></div>
+ </div>
+ </body>
+ </html>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ AutoscrollController& controller = GetAutoscrollController();
+
+ EXPECT_FALSE(controller.IsAutoscrolling());
+
+ LocalFrame* frame = GetDocument().GetFrame();
+ LayoutBox* scrollable =
+ GetDocument().getElementById("scrollable")->GetLayoutBox();
+
+ controller.StartMiddleClickAutoscroll(
+ frame, scrollable, FloatPoint(15.0, 15.0), FloatPoint(15.0, 15.0));
+
+ EXPECT_TRUE(controller.IsAutoscrolling());
+ EXPECT_TRUE(controller.vertical_autoscroll_layout_box_);
+ EXPECT_TRUE(controller.horizontal_autoscroll_layout_box_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client.cc b/chromium/third_party/blink/renderer/core/page/chrome_client.cc
index 4b42770e165..a4ee25fce05 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client.cc
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client.cc
@@ -147,7 +147,6 @@ Page* ChromeClient::CreateWindow(
const AtomicString& frame_name,
const WebWindowFeatures& features,
network::mojom::blink::WebSandboxFlags sandbox_flags,
- const FeaturePolicyFeatureState& opener_feature_state,
const SessionStorageNamespaceId& session_storage_namespace_id,
bool& consumed_user_gesture) {
if (!CanOpenUIElementIfDuringPageDismissal(
@@ -155,9 +154,9 @@ Page* ChromeClient::CreateWindow(
return nullptr;
}
- return CreateWindowDelegate(
- frame, r, frame_name, features, sandbox_flags, opener_feature_state,
- session_storage_namespace_id, consumed_user_gesture);
+ return CreateWindowDelegate(frame, r, frame_name, features, sandbox_flags,
+ session_storage_namespace_id,
+ consumed_user_gesture);
}
template <typename Delegate>
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client.h b/chromium/third_party/blink/renderer/core/page/chrome_client.h
index 451dc607195..c794005c378 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client.h
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client.h
@@ -32,6 +32,7 @@
#include "cc/input/overscroll_behavior.h"
#include "cc/paint/paint_image.h"
#include "cc/trees/paint_holding_commit_trigger.h"
+#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
#include "third_party/blink/public/common/feature_policy/feature_policy_features.h"
@@ -39,11 +40,10 @@
#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/platform/blame_context.h"
-#include "third_party/blink/public/platform/web_battery_savings.h"
#include "third_party/blink/public/web/web_swap_result.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/html/battery_savings.h"
#include "third_party/blink/renderer/core/html/forms/external_date_time_chooser.h"
#include "third_party/blink/renderer/core/html/forms/popup_menu.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
@@ -107,7 +107,6 @@ struct FrameLoadRequest;
struct ViewportDescription;
struct ScreenInfo;
struct WebWindowFeatures;
-struct WebRect;
namespace mojom {
namespace blink {
@@ -216,7 +215,6 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
const AtomicString& frame_name,
const WebWindowFeatures&,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
bool& consumed_user_gesture);
@@ -225,7 +223,7 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
// shown. Under some circumstances CreateWindow's implementation may return a
// previously shown page. Calling this method should still work and the
// browser will discard the unnecessary show request.
- virtual void Show(const base::UnguessableToken& opener_frame_token,
+ virtual void Show(const blink::LocalFrameToken& opener_frame_token,
NavigationPolicy navigation_policy,
const IntRect& initial_rect,
bool consumed_user_gesture) = 0;
@@ -264,8 +262,10 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
virtual void SetOverscrollBehavior(LocalFrame& main_frame,
const cc::OverscrollBehavior&) = 0;
- virtual bool ShouldReportDetailedMessageForSource(LocalFrame&,
- const String& source) = 0;
+ virtual bool ShouldReportDetailedMessageForSourceAndSeverity(
+ LocalFrame&,
+ mojom::blink::ConsoleMessageLevel log_level,
+ const String& source) = 0;
virtual void AddMessageToConsole(LocalFrame*,
mojom::ConsoleMessageSource,
mojom::ConsoleMessageLevel,
@@ -289,7 +289,8 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
String& result);
virtual bool TabsToLinks() = 0;
- virtual ScreenInfo GetScreenInfo(LocalFrame& frame) const = 0;
+ virtual const ScreenInfo& GetScreenInfo(LocalFrame& frame) const = 0;
+
virtual void SetCursor(const ui::Cursor&, LocalFrame* local_root) = 0;
virtual void SetCursorOverridden(bool) = 0;
@@ -321,7 +322,7 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
virtual void EnablePreferredSizeChangedMode() {}
- virtual void ZoomToFindInPageRect(const WebRect&) {}
+ virtual void ZoomToFindInPageRect(const gfx::Rect&) {}
virtual void ContentsSizeChanged(LocalFrame*, const IntSize&) const = 0;
// Call during pinch gestures, or when page-scale changes on main-frame load.
@@ -389,7 +390,9 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
FullscreenRequestType) {}
virtual void ExitFullscreen(LocalFrame&) {}
virtual void FullscreenElementChanged(Element* old_element,
- Element* new_element) {}
+ Element* new_element,
+ const FullscreenOptions* options,
+ FullscreenRequestType) {}
virtual void AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) {}
@@ -490,11 +493,13 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
}
// The |callback| will be fired when the corresponding renderer frame for the
- // |frame| is submitted (still called "swapped") to the display compositor
- // (either with DidSwap or DidNotSwap).
+ // |frame| is presented in the display compositor. The reported time could
+ // sometimes be the swap time, as is the case when the swap is aborted. In
+ // this case, WebSwapResult will be DidNotSwap.
using ReportTimeCallback =
WTF::CrossThreadOnceFunction<void(WebSwapResult, base::TimeTicks)>;
- virtual void NotifySwapTime(LocalFrame& frame, ReportTimeCallback callback) {}
+ virtual void NotifyPresentationTime(LocalFrame& frame,
+ ReportTimeCallback callback) {}
// Enable or disable BeginMainFrameNotExpected signals from the compositor of
// the local root of |frame|. These signals would be consumed by the blink
@@ -524,7 +529,7 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
std::unique_ptr<viz::DelegatedInkMetadata> metadata) {}
virtual void BatterySavingsChanged(LocalFrame& main_frame,
- WebBatterySavingsFlags savings) = 0;
+ BatterySavingsFlags savings) = 0;
virtual void FormElementReset(HTMLFormElement& element) {}
@@ -549,7 +554,6 @@ class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
const AtomicString& frame_name,
const WebWindowFeatures&,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
bool& consumed_user_gesture) = 0;
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
index 318a8eb24c3..ae4d460aaee 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -41,7 +41,6 @@
#include "cc/layers/picture_layer.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_autofill_client.h"
@@ -67,9 +66,9 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/html/forms/color_chooser.h"
#include "third_party/blink/renderer/core/html/forms/color_chooser_client.h"
@@ -193,9 +192,8 @@ void ChromeClientImpl::SetWindowRect(const IntRect& r, LocalFrame& frame) {
}
IntRect ChromeClientImpl::RootWindowRect(LocalFrame& frame) {
- // The WindowRect() for each WebWidgetClient will be the same rect of the top
- // level window. Since there is not always a WebWidgetClient attached to the
- // WebView, we ask the WebWidget associated with the |frame|'s local root.
+ // The WindowRect() for each WebFrameWidget will be the same rect of the top
+ // level window.
return IntRect(frame.GetWidgetForLocalRoot()->WindowRect());
}
@@ -246,7 +244,6 @@ Page* ChromeClientImpl::CreateWindowDelegate(
const AtomicString& name,
const WebWindowFeatures& features,
network::mojom::blink::WebSandboxFlags sandbox_flags,
- const FeaturePolicyFeatureState& opener_feature_state,
const SessionStorageNamespaceId& session_storage_namespace_id,
bool& consumed_user_gesture) {
if (!web_view_->Client())
@@ -263,8 +260,8 @@ Page* ChromeClientImpl::CreateWindowDelegate(
WebLocalFrameImpl::FromFrame(frame),
WrappedResourceRequest(r.GetResourceRequest()), features, frame_name,
static_cast<WebNavigationPolicy>(r.GetNavigationPolicy()),
- sandbox_flags, opener_feature_state, session_storage_namespace_id,
- consumed_user_gesture));
+ sandbox_flags, session_storage_namespace_id, consumed_user_gesture,
+ r.Impression()));
if (!new_view)
return nullptr;
return new_view->GetPage();
@@ -275,8 +272,6 @@ void ChromeClientImpl::DidOverscroll(
const gfx::Vector2dF& accumulated_overscroll,
const gfx::PointF& position_in_viewport,
const gfx::Vector2dF& velocity_in_viewport) {
- // WebWidgetClient can be null when not compositing, and this behaviour only
- // applies when compositing is enabled.
if (!web_view_->does_composite())
return;
// TODO(darin): Change caller to pass LocalFrame.
@@ -305,7 +300,7 @@ void ChromeClientImpl::SetOverscrollBehavior(
overscroll_behavior);
}
-void ChromeClientImpl::Show(const base::UnguessableToken& opener_frame_token,
+void ChromeClientImpl::Show(const blink::LocalFrameToken& opener_frame_token,
NavigationPolicy navigation_policy,
const IntRect& initial_rect,
bool user_gesture) {
@@ -313,13 +308,15 @@ void ChromeClientImpl::Show(const base::UnguessableToken& opener_frame_token,
user_gesture);
}
-bool ChromeClientImpl::ShouldReportDetailedMessageForSource(
+bool ChromeClientImpl::ShouldReportDetailedMessageForSourceAndSeverity(
LocalFrame& local_frame,
+ mojom::blink::ConsoleMessageLevel log_level,
const String& url) {
WebLocalFrameImpl* webframe =
WebLocalFrameImpl::FromFrame(local_frame.LocalFrameRoot());
return webframe && webframe->Client() &&
- webframe->Client()->ShouldReportDetailedMessageForSource(url);
+ webframe->Client()->ShouldReportDetailedMessageForSourceAndSeverity(
+ log_level, url);
}
void ChromeClientImpl::AddMessageToConsole(LocalFrame* local_frame,
@@ -329,6 +326,12 @@ void ChromeClientImpl::AddMessageToConsole(LocalFrame* local_frame,
unsigned line_number,
const String& source_id,
const String& stack_trace) {
+ if (!message.IsNull()) {
+ local_frame->GetLocalFrameHostRemote().DidAddMessageToConsole(
+ level, message, static_cast<int32_t>(line_number), source_id,
+ stack_trace);
+ }
+
WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(local_frame);
if (frame && frame->Client()) {
frame->Client()->DidAddMessageToConsole(
@@ -417,13 +420,7 @@ void ChromeClientImpl::ScheduleAnimation(const LocalFrameView* frame_view,
// WebFrameWidget needs to be initialized before initializing the core frame?
FrameWidget* widget = frame.GetWidgetForLocalRoot();
if (widget) {
- if (delay.is_zero()) {
- // LocalRootFrameWidget() is a WebWidget, its client is the embedder.
- WebWidgetClient* web_widget_client = widget->Client();
- web_widget_client->ScheduleAnimation();
- } else {
- widget->RequestAnimationAfterDelay(delay);
- }
+ widget->RequestAnimationAfterDelay(delay);
}
}
@@ -455,7 +452,7 @@ float ChromeClientImpl::WindowToViewportScalar(LocalFrame* frame,
return frame->GetWidgetForLocalRoot()->DIPsToBlinkSpace(scalar_value);
}
-ScreenInfo ChromeClientImpl::GetScreenInfo(LocalFrame& frame) const {
+const ScreenInfo& ChromeClientImpl::GetScreenInfo(LocalFrame& frame) const {
return frame.GetWidgetForLocalRoot()->GetScreenInfo();
}
@@ -487,7 +484,8 @@ void ChromeClientImpl::EnablePreferredSizeChangedMode() {
web_view_->EnablePreferredSizeChangedMode();
}
-void ChromeClientImpl::ZoomToFindInPageRect(const WebRect& rect_in_root_frame) {
+void ChromeClientImpl::ZoomToFindInPageRect(
+ const gfx::Rect& rect_in_root_frame) {
web_view_->ZoomToFindInPageRect(rect_in_root_frame);
}
@@ -545,13 +543,13 @@ void ChromeClientImpl::ShowMouseOverURL(const HitTestResult& result) {
void ChromeClientImpl::SetToolTip(LocalFrame& frame,
const String& tooltip_text,
TextDirection dir) {
- WebFrameWidgetBase* widget =
+ WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
if (!tooltip_text.IsEmpty()) {
widget->SetToolTipText(tooltip_text, dir);
did_request_non_empty_tool_tip_ = true;
} else if (did_request_non_empty_tool_tip_) {
- // WebFrameWidgetBase::SetToolTipText will send a Mojo message via
+ // WebFrameWidgetImpl::SetToolTipText will send a Mojo message via
// mojom::blink::WidgetHost. We'd like to reduce the number of
// SetToolTipText calls.
widget->SetToolTipText(tooltip_text, dir);
@@ -712,7 +710,7 @@ void ChromeClientImpl::SetCursorOverridden(bool overridden) {
void ChromeClientImpl::AutoscrollStart(const gfx::PointF& viewport_point,
LocalFrame* local_frame) {
// TODO(dcheng): Why is this null check necessary?
- if (WebFrameWidgetBase* widget =
+ if (WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget())
widget->AutoscrollStart(viewport_point);
}
@@ -720,20 +718,20 @@ void ChromeClientImpl::AutoscrollStart(const gfx::PointF& viewport_point,
void ChromeClientImpl::AutoscrollFling(const gfx::Vector2dF& velocity,
LocalFrame* local_frame) {
// TODO(dcheng): Why is this null check necessary?
- if (WebFrameWidgetBase* widget =
+ if (WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget())
widget->AutoscrollFling(velocity);
}
void ChromeClientImpl::AutoscrollEnd(LocalFrame* local_frame) {
// TODO(dcheng): Why is this null check necessary?
- if (WebFrameWidgetBase* widget =
+ if (WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget())
widget->AutoscrollEnd();
}
String ChromeClientImpl::AcceptLanguages() {
- return web_view_->Client()->AcceptLanguages();
+ return String::FromUTF8(web_view_->GetRendererPreferences().accept_languages);
}
void ChromeClientImpl::AttachRootLayer(scoped_refptr<cc::Layer> root_layer,
@@ -779,14 +777,18 @@ void ChromeClientImpl::ExitFullscreen(LocalFrame& frame) {
web_view_->ExitFullscreen(frame);
}
-void ChromeClientImpl::FullscreenElementChanged(Element* old_element,
- Element* new_element) {
- web_view_->FullscreenElementChanged(old_element, new_element);
+void ChromeClientImpl::FullscreenElementChanged(
+ Element* old_element,
+ Element* new_element,
+ const FullscreenOptions* options,
+ FullscreenRequestType request_type) {
+ web_view_->FullscreenElementChanged(old_element, new_element, options,
+ request_type);
}
void ChromeClientImpl::AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) {
- web_view_->AnimateDoubleTapZoom(point, WebRect(rect));
+ web_view_->AnimateDoubleTapZoom(point, rect);
}
void ChromeClientImpl::ClearLayerSelection(LocalFrame* frame) {
@@ -876,13 +878,13 @@ void ChromeClientImpl::RequestDecode(LocalFrame* frame,
widget->RequestDecode(image, std::move(callback));
}
-void ChromeClientImpl::NotifySwapTime(LocalFrame& frame,
- ReportTimeCallback callback) {
+void ChromeClientImpl::NotifyPresentationTime(LocalFrame& frame,
+ ReportTimeCallback callback) {
FrameWidget* widget = frame.GetWidgetForLocalRoot();
if (!widget)
return;
- widget->NotifySwapAndPresentationTimeInBlink(
- base::NullCallback(), ConvertToBaseOnceCallback(std::move(callback)));
+ widget->NotifyPresentationTimeInBlink(
+ ConvertToBaseOnceCallback(std::move(callback)));
}
void ChromeClientImpl::RequestBeginMainFrameNotExpected(LocalFrame& frame,
@@ -932,7 +934,7 @@ cc::EventListenerProperties ChromeClientImpl::EventListenerProperties(
if (!frame)
return cc::EventListenerProperties::kNone;
- WebFrameWidgetBase* widget =
+ WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
if (!widget)
return cc::EventListenerProperties::kNone;
@@ -979,7 +981,7 @@ void ChromeClientImpl::SetNeedsLowLatencyInput(LocalFrame* frame,
bool needs_low_latency) {
DCHECK(frame);
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
- WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
+ WebFrameWidgetImpl* widget = web_frame->LocalRootFrameWidget();
if (!widget)
return;
@@ -990,7 +992,7 @@ void ChromeClientImpl::SetNeedsUnbufferedInputForDebugger(LocalFrame* frame,
bool unbuffered) {
DCHECK(frame);
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
- WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
+ WebFrameWidgetImpl* widget = web_frame->LocalRootFrameWidget();
if (!widget)
return;
@@ -1000,7 +1002,7 @@ void ChromeClientImpl::SetNeedsUnbufferedInputForDebugger(LocalFrame* frame,
void ChromeClientImpl::RequestUnbufferedInputEvents(LocalFrame* frame) {
DCHECK(frame);
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
- WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
+ WebFrameWidgetImpl* widget = web_frame->LocalRootFrameWidget();
if (!widget)
return;
@@ -1011,7 +1013,7 @@ void ChromeClientImpl::SetTouchAction(LocalFrame* frame,
TouchAction touch_action) {
DCHECK(frame);
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
- WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget();
+ WebFrameWidgetImpl* widget = web_frame->LocalRootFrameWidget();
if (!widget)
return;
@@ -1173,7 +1175,7 @@ void ChromeClientImpl::SetDelegatedInkMetadata(
}
void ChromeClientImpl::BatterySavingsChanged(LocalFrame& main_frame,
- WebBatterySavingsFlags savings) {
+ BatterySavingsFlags savings) {
DCHECK(main_frame.IsMainFrame());
WebLocalFrameImpl::FromFrame(main_frame)
->FrameWidgetImpl()
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
index ab69bea683c..40b077aafa5 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -37,7 +37,6 @@
#include "cc/input/overscroll_behavior.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
#include "third_party/blink/public/web/web_navigation_policy.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/public/web/web_window_features.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -54,7 +53,6 @@ class PagePopup;
class PagePopupClient;
class WebAutofillClient;
class WebViewImpl;
-struct WebRect;
// Handles window-level notifications from core on behalf of a WebView.
class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
@@ -89,10 +87,9 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
const AtomicString& name,
const WebWindowFeatures&,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
bool& consumed_user_gesture) override;
- void Show(const base::UnguessableToken& opener_frame_token,
+ void Show(const blink::LocalFrameToken& opener_frame_token,
NavigationPolicy navigation_policy,
const IntRect& initial_rect,
bool user_gesture) override;
@@ -108,8 +105,10 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
ScrollGranularity granularity,
CompositorElementId scrollable_area_element_id,
WebInputEvent::Type injected_type) override;
- bool ShouldReportDetailedMessageForSource(LocalFrame&,
- const String&) override;
+ bool ShouldReportDetailedMessageForSourceAndSeverity(
+ LocalFrame&,
+ mojom::blink::ConsoleMessageLevel log_level,
+ const String&) override;
void AddMessageToConsole(LocalFrame*,
mojom::ConsoleMessageSource,
mojom::ConsoleMessageLevel,
@@ -138,14 +137,14 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
IntRect ViewportToScreen(const IntRect&,
const LocalFrameView*) const override;
float WindowToViewportScalar(LocalFrame*, const float) const override;
- ScreenInfo GetScreenInfo(LocalFrame&) const override;
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override;
void OverrideVisibleRectForMainFrame(LocalFrame& frame,
IntRect* paint_rect) const override;
float InputEventsScaleForEmulation() const override;
void ContentsSizeChanged(LocalFrame*, const IntSize&) const override;
bool DoubleTapToZoomEnabled() const override;
void EnablePreferredSizeChangedMode() override;
- void ZoomToFindInPageRect(const WebRect& rect_in_root_frame) override;
+ void ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame) override;
void PageScaleFactorChanged() const override;
float ClampPageScaleFactorToLimits(float scale) const override;
void MainFrameScrollOffsetChanged(LocalFrame& main_frame) const override;
@@ -195,7 +194,9 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
FullscreenRequestType) override;
void ExitFullscreen(LocalFrame&) override;
void FullscreenElementChanged(Element* old_element,
- Element* new_element) override;
+ Element* new_element,
+ const FullscreenOptions*,
+ FullscreenRequestType) override;
void AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) override;
@@ -270,7 +271,8 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
const cc::PaintImage&,
base::OnceCallback<void(bool)>) override;
- void NotifySwapTime(LocalFrame& frame, ReportTimeCallback callback) override;
+ void NotifyPresentationTime(LocalFrame& frame,
+ ReportTimeCallback callback) override;
void RequestBeginMainFrameNotExpected(LocalFrame& frame,
bool request) override;
@@ -285,7 +287,7 @@ class CORE_EXPORT ChromeClientImpl final : public ChromeClient {
double UserZoomFactor() const override;
void BatterySavingsChanged(LocalFrame& main_frame,
- WebBatterySavingsFlags savings) override;
+ BatterySavingsFlags savings) override;
void FormElementReset(HTMLFormElement& element) override;
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
index 5b91664d3bf..28ea8793f64 100644
--- a/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -65,9 +65,9 @@ class ViewCreatingClient : public frame_test_helpers::TestWebViewClient {
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
- const FeaturePolicyFeatureState&,
const SessionStorageNamespaceId&,
- bool& consumed_user_gesture) override {
+ bool& consumed_user_gesture,
+ const base::Optional<WebImpression>&) override {
return web_view_helper_.InitializeWithOpener(opener);
}
@@ -98,11 +98,10 @@ TEST_F(CreateWindowTest, CreateWindowFromPausedPage) {
request.SetNavigationPolicy(kNavigationPolicyNewForegroundTab);
WebWindowFeatures features;
bool consumed_user_gesture = false;
- EXPECT_EQ(nullptr,
- chrome_client_impl_->CreateWindow(
- frame, request, "", features,
- network::mojom::blink::WebSandboxFlags::kNone,
- FeaturePolicyFeatureState(), "", consumed_user_gesture));
+ EXPECT_EQ(nullptr, chrome_client_impl_->CreateWindow(
+ frame, request, "", features,
+ network::mojom::blink::WebSandboxFlags::kNone, "",
+ consumed_user_gesture));
}
class FakeColorChooserClient : public GarbageCollected<FakeColorChooserClient>,
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc b/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
index 9339db34d17..094a487ec8d 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -30,14 +30,22 @@
#include <memory>
#include <utility>
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
+#include "services/metrics/public/cpp/ukm_entry_builder.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/public/common/context_menu_data/context_menu_data.h"
#include "third_party/blink/public/common/context_menu_data/edit_flags.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_menu_source_type.h"
-#include "third_party/blink/public/web/web_context_menu_data.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom-blink.h"
+#include "third_party/blink/public/platform/impression_conversions.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_plugin.h"
#include "third_party/blink/public/web/web_text_check_client.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/editing/editing_tri_state.h"
#include "third_party/blink/renderer/core/editing/editor.h"
@@ -52,8 +60,9 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/picture_in_picture_controller.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html/conversion_measurement_parsing.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
@@ -71,10 +80,55 @@
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
namespace blink {
+namespace {
+
+// Returns true if node or any of its ancestors have a context menu event
+// listener. Uses already_visited_nodes to track nodes which have already
+// been checked across multiple calls to this function, which could cause
+// the output to be false despite having an ancestor context menu listener.
+bool UnvisitedNodeOrAncestorHasContextMenuListener(
+ Node* node,
+ HeapHashSet<Member<Node>>& already_visited_nodes) {
+ Node* current_node_for_parent_traversal = node;
+ while (current_node_for_parent_traversal != nullptr) {
+ if (current_node_for_parent_traversal->HasEventListeners(
+ event_type_names::kContextmenu)) {
+ return true;
+ }
+ // If we've already checked this node, all of its ancestors must not
+ // have had listeners (or, we already detected a listener and broke out
+ // early).
+ if (!already_visited_nodes.insert(current_node_for_parent_traversal)
+ .is_new_entry) {
+ break;
+ }
+ current_node_for_parent_traversal =
+ current_node_for_parent_traversal->parentNode();
+ }
+ return false;
+}
+
+void MaybeRecordImageSelectionUkm(
+ ukm::SourceId source_id,
+ ContextMenuController::ImageSelectionOutcome outcome) {
+ DCHECK_NE(source_id, ukm::kInvalidSourceId);
+ static bool enable = base::GetFieldTrialParamByFeatureAsInt(
+ features::kEnablePenetratingImageSelection, "logUkm", false);
+
+ if (enable) {
+ ukm::UkmEntryBuilder builder(source_id, "Blink.ContextMenu.ImageSelection");
+ builder.SetMetric("Outcome", outcome);
+ builder.Record(ukm::UkmRecorder::Get());
+ }
+}
+
+} // namespace
+
ContextMenuController::ContextMenuController(Page* page) : page_(page) {}
ContextMenuController::~ContextMenuController() = default;
@@ -83,12 +137,14 @@ void ContextMenuController::Trace(Visitor* visitor) const {
visitor->Trace(page_);
visitor->Trace(menu_provider_);
visitor->Trace(hit_test_result_);
+ visitor->Trace(context_menu_client_receiver_);
}
void ContextMenuController::ClearContextMenu() {
if (menu_provider_)
menu_provider_->ContextMenuCleared();
menu_provider_ = nullptr;
+ context_menu_client_receiver_.reset();
hit_test_result_ = HitTestResult();
}
@@ -129,12 +185,127 @@ void ContextMenuController::CustomContextMenuItemSelected(unsigned action) {
ClearContextMenu();
}
+Node* ContextMenuController::GetContextMenuNodeWithImageContents(
+ const bool report_histograms) {
+ uint32_t outcome = 0;
+ uint32_t hit_test_depth = 0;
+ LocalFrame* top_hit_frame =
+ hit_test_result_.InnerNode()->GetDocument().GetFrame();
+ Node* found_image_node = nullptr;
+ HeapHashSet<Member<Node>> already_visited_nodes_for_context_menu_listener;
+
+ for (const auto& raw_node : hit_test_result_.ListBasedTestResult()) {
+ hit_test_depth++;
+ Node* node = raw_node.Get();
+
+ // Execute context menu listener and cross frame checks before image check
+ // because these checks should also apply to the image node itself before
+ // breaking.
+ if (UnvisitedNodeOrAncestorHasContextMenuListener(
+ node, already_visited_nodes_for_context_menu_listener)) {
+ outcome |= EnumToBitmask(kFoundContextMenuListener);
+ // Don't break because it allows us to log the failure reason only
+ // if an image node was otherwise available lower in the hit test.
+ }
+ if (top_hit_frame != node->GetDocument().GetFrame()) {
+ outcome |= EnumToBitmask(kBlockedByCrossFrameNode);
+ // Don't break because it allows us to log the failure reason only
+ // if an image node was otherwise available lower in the hit test.
+ }
+
+ if (IsA<HTMLCanvasElement>(node) ||
+ !HitTestResult::AbsoluteImageURL(node).IsEmpty()) {
+ found_image_node = node;
+
+ if (hit_test_depth == 1) {
+ outcome |= EnumToBitmask(kImageFoundStandard);
+ // The context menu listener check is only necessary when penetrating,
+ // so clear the bit so we don't want to log it if the image was on top.
+ outcome &= ~EnumToBitmask(kFoundContextMenuListener);
+ } else {
+ outcome |= EnumToBitmask(kImageFoundPenetrating);
+ }
+ break;
+ }
+ // IMPORTANT: Check after image checks above so that non-transparent
+ // image elements don't trigger the opaque check.
+ if (node->GetLayoutBox() != nullptr &&
+ node->GetLayoutBox()->BackgroundIsKnownToBeOpaqueInRect(
+ HitTestLocation::RectForPoint(
+ hit_test_result_.PointInInnerNodeFrame()))) {
+ outcome |= EnumToBitmask(kBlockedByOpaqueNode);
+ // Don't break because it allows us to log the failure reason only
+ // if an image node was otherwise available lower in the hit test.
+ }
+ }
+
+ // Only log if we found an image node within the hit test.
+ if (report_histograms && (found_image_node != nullptr)) {
+ base::UmaHistogramCounts1000("Blink.ContextMenu.ImageSelection.Depth",
+ hit_test_depth);
+ for (uint32_t i = 0; i < kMaxValue; i++) {
+ unsigned val = 1 << i;
+ if (outcome & val) {
+ base::UmaHistogramEnumeration(
+ "Blink.ContextMenu.ImageSelection.Outcome",
+ ImageSelectionOutcome(i));
+ MaybeRecordImageSelectionUkm(
+ found_image_node->GetDocument().UkmSourceID(),
+ ImageSelectionOutcome(i));
+ }
+ }
+ }
+ // If there is anything preventing this image selection, return nullptr.
+ uint32_t blocking_image_selection_mask =
+ ~(EnumToBitmask(kImageFoundStandard) |
+ EnumToBitmask(kImageFoundPenetrating));
+ if (outcome & blocking_image_selection_mask) {
+ return nullptr;
+ }
+ return found_image_node;
+}
+
+// TODO(crbug.com/1184297) Cache image node when the context menu is shown and
+// return that rather than refetching.
+Node* ContextMenuController::ContextMenuImageNodeForFrame(LocalFrame* frame) {
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ // Don't report histograms because they were already sent for this node when
+ // ContextMenuData was populated.
+ Node* potential_image_node = GetContextMenuNodeWithImageContents(
+ /*report_histograms=*/false);
+ return potential_image_node != nullptr &&
+ potential_image_node->GetDocument().GetFrame() == frame
+ ? potential_image_node
+ : nullptr;
+ }
+ return ContextMenuNodeForFrame(frame);
+}
+
+// TODO(crbug.com/1184297) Cache image node when the context menu is shown and
+// return that rather than refetching.
Node* ContextMenuController::ContextMenuNodeForFrame(LocalFrame* frame) {
return hit_test_result_.InnerNodeFrame() == frame
? hit_test_result_.InnerNodeOrImageMapImage()
: nullptr;
}
+void ContextMenuController::CustomContextMenuAction(uint32_t action) {
+ CustomContextMenuItemSelected(action);
+}
+
+void ContextMenuController::ContextMenuClosed(const KURL& link_followed) {
+ if (!link_followed.IsValid())
+ return;
+
+ WebLocalFrameImpl* selected_web_frame =
+ WebLocalFrameImpl::FromFrame(hit_test_result_.InnerNodeFrame());
+ if (!selected_web_frame)
+ return;
+
+ selected_web_frame->SendPings(link_followed);
+}
+
static int ComputeEditFlags(Document& selected_document, Editor& editor) {
int edit_flags = ContextMenuDataEditFlags::kCanDoNone;
if (editor.CanUndo())
@@ -160,23 +331,23 @@ static int ComputeEditFlags(Document& selected_document, Editor& editor) {
return edit_flags;
}
-static ContextMenuDataInputFieldType ComputeInputFieldType(
+static mojom::blink::ContextMenuDataInputFieldType ComputeInputFieldType(
HitTestResult& result) {
if (auto* input = DynamicTo<HTMLInputElement>(result.InnerNode())) {
if (input->type() == input_type_names::kPassword)
- return ContextMenuDataInputFieldType::kPassword;
+ return mojom::blink::ContextMenuDataInputFieldType::kPassword;
if (input->type() == input_type_names::kNumber)
- return ContextMenuDataInputFieldType::kNumber;
+ return mojom::blink::ContextMenuDataInputFieldType::kNumber;
if (input->type() == input_type_names::kTel)
- return ContextMenuDataInputFieldType::kTelephone;
+ return mojom::blink::ContextMenuDataInputFieldType::kTelephone;
if (input->IsTextField())
- return ContextMenuDataInputFieldType::kPlainText;
- return ContextMenuDataInputFieldType::kOther;
+ return mojom::blink::ContextMenuDataInputFieldType::kPlainText;
+ return mojom::blink::ContextMenuDataInputFieldType::kOther;
}
- return ContextMenuDataInputFieldType::kNone;
+ return mojom::blink::ContextMenuDataInputFieldType::kNone;
}
-static WebRect ComputeSelectionRect(LocalFrame* selected_frame) {
+static gfx::Rect ComputeSelectionRect(LocalFrame* selected_frame) {
IntRect anchor;
IntRect focus;
selected_frame->Selection().ComputeAbsoluteBounds(anchor, focus);
@@ -201,16 +372,16 @@ static WebRect ComputeSelectionRect(LocalFrame* selected_frame) {
}
}
- return WebRect(left, top, right - left, bottom - top);
+ return gfx::Rect(left, top, right - left, bottom - top);
}
bool ContextMenuController::ShouldShowContextMenuFromTouch(
- const WebContextMenuData& data) {
+ const ContextMenuData& data) {
return page_->GetSettings().GetAlwaysShowContextMenuOnTouch() ||
- !data.link_url.IsEmpty() ||
- data.media_type == ContextMenuDataMediaType::kImage ||
- data.media_type == ContextMenuDataMediaType::kVideo ||
- data.is_editable || !data.selected_text.IsEmpty();
+ !data.link_url.is_empty() ||
+ data.media_type == mojom::blink::ContextMenuDataMediaType::kImage ||
+ data.media_type == mojom::blink::ContextMenuDataMediaType::kVideo ||
+ data.is_editable || !data.selected_text.empty();
}
bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
@@ -225,9 +396,17 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
if (!ContextMenuAllowedScope::IsContextMenuAllowed())
return false;
+ if (context_menu_client_receiver_.is_bound())
+ context_menu_client_receiver_.reset();
+
HitTestRequest::HitTestRequestType type = HitTestRequest::kReadOnly |
HitTestRequest::kActive |
HitTestRequest::kRetargetForInert;
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ type |= HitTestRequest::kPenetratingList | HitTestRequest::kListBased;
+ }
+
HitTestLocation location(point);
HitTestResult result(type, location);
if (frame)
@@ -248,7 +427,7 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
PhysicalOffset(FlooredIntPoint(point)));
}
- WebContextMenuData data;
+ ContextMenuData data;
data.mouse_position = selected_frame->View()->FrameToViewport(
result.RoundedPointInInnerNodeFrame());
@@ -276,25 +455,11 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
auto* html_element = DynamicTo<HTMLElement>(result.InnerNode());
if (html_element) {
- data.title_text = html_element->title();
- data.alt_text = html_element->AltText();
+ data.title_text = html_element->title().Utf8();
+ data.alt_text = html_element->AltText().Utf8();
}
-
- // Links, Images, Media tags, and Image/Media-Links take preference over
- // all else.
- if (IsA<HTMLCanvasElement>(result.InnerNode())) {
- data.media_type = ContextMenuDataMediaType::kCanvas;
- data.has_image_contents = true;
- } else if (!result.AbsoluteImageURL().IsEmpty()) {
- data.src_url = result.AbsoluteImageURL();
- data.media_type = ContextMenuDataMediaType::kImage;
- data.media_flags |= WebContextMenuData::kMediaCanPrint;
-
- // An image can be null for many reasons, like being blocked, no image
- // data received from server yet.
- data.has_image_contents = result.GetImage() && !result.GetImage()->IsNull();
- } else if (!result.AbsoluteMediaURL().IsEmpty() ||
- result.GetMediaStreamDescriptor()) {
+ if (!result.AbsoluteMediaURL().IsEmpty() ||
+ result.GetMediaStreamDescriptor()) {
if (!result.AbsoluteMediaURL().IsEmpty())
data.src_url = result.AbsoluteMediaURL();
@@ -305,53 +470,56 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
// A video element should be presented as an audio element when it has an
// audio track but no video track.
if (media_element->HasAudio() && !media_element->HasVideo())
- data.media_type = ContextMenuDataMediaType::kAudio;
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kAudio;
else
- data.media_type = ContextMenuDataMediaType::kVideo;
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kVideo;
if (media_element->SupportsPictureInPicture()) {
- data.media_flags |= WebContextMenuData::kMediaCanPictureInPicture;
+ data.media_flags |= ContextMenuData::kMediaCanPictureInPicture;
if (PictureInPictureController::IsElementInPictureInPicture(
media_element))
- data.media_flags |= WebContextMenuData::kMediaPictureInPicture;
+ data.media_flags |= ContextMenuData::kMediaPictureInPicture;
}
} else if (IsA<HTMLAudioElement>(*media_element)) {
- data.media_type = ContextMenuDataMediaType::kAudio;
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kAudio;
}
- data.suggested_filename = media_element->title();
+ data.suggested_filename = media_element->title().Utf8();
if (media_element->error())
- data.media_flags |= WebContextMenuData::kMediaInError;
+ data.media_flags |= ContextMenuData::kMediaInError;
if (media_element->paused())
- data.media_flags |= WebContextMenuData::kMediaPaused;
+ data.media_flags |= ContextMenuData::kMediaPaused;
if (media_element->muted())
- data.media_flags |= WebContextMenuData::kMediaMuted;
+ data.media_flags |= ContextMenuData::kMediaMuted;
if (media_element->SupportsLoop())
- data.media_flags |= WebContextMenuData::kMediaCanLoop;
+ data.media_flags |= ContextMenuData::kMediaCanLoop;
if (media_element->Loop())
- data.media_flags |= WebContextMenuData::kMediaLoop;
+ data.media_flags |= ContextMenuData::kMediaLoop;
if (media_element->SupportsSave())
- data.media_flags |= WebContextMenuData::kMediaCanSave;
+ data.media_flags |= ContextMenuData::kMediaCanSave;
if (media_element->HasAudio())
- data.media_flags |= WebContextMenuData::kMediaHasAudio;
+ data.media_flags |= ContextMenuData::kMediaHasAudio;
// Media controls can be toggled only for video player. If we toggle
// controls for audio then the player disappears, and there is no way to
// return it back. Don't set this bit for fullscreen video, since
// toggling is ignored in that case.
if (IsA<HTMLVideoElement>(media_element) && media_element->HasVideo() &&
!media_element->IsFullscreen())
- data.media_flags |= WebContextMenuData::kMediaCanToggleControls;
+ data.media_flags |= ContextMenuData::kMediaCanToggleControls;
if (media_element->ShouldShowControls())
- data.media_flags |= WebContextMenuData::kMediaControls;
+ data.media_flags |= ContextMenuData::kMediaControls;
} else if (IsA<HTMLObjectElement>(*result.InnerNode()) ||
IsA<HTMLEmbedElement>(*result.InnerNode())) {
if (auto* embedded = DynamicTo<LayoutEmbeddedContent>(
result.InnerNode()->GetLayoutObject())) {
WebPluginContainerImpl* plugin_view = embedded->Plugin();
if (plugin_view) {
- data.media_type = ContextMenuDataMediaType::kPlugin;
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kPlugin;
WebPlugin* plugin = plugin_view->Plugin();
- data.link_url = plugin->LinkAtPosition(data.mouse_position);
+ data.link_url = KURL(plugin->LinkAtPosition(data.mouse_position)
+ .GetString()
+ .Utf8()
+ .c_str());
auto* plugin_element = To<HTMLPlugInElement>(result.InnerNode());
data.src_url =
@@ -360,7 +528,7 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
// Figure out the text selection and text edit flags.
WebString text = plugin->SelectionAsText();
if (!text.IsEmpty()) {
- data.selected_text = text;
+ data.selected_text = text.Utf8();
data.edit_flags |= ContextMenuDataEditFlags::kCanCopy;
}
bool plugin_can_edit_text = plugin->CanEditText();
@@ -382,23 +550,51 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
data.edit_flags &= ~ContextMenuDataEditFlags::kCanTranslate;
// Figure out the media flags.
- data.media_flags |= WebContextMenuData::kMediaCanSave;
+ data.media_flags |= ContextMenuData::kMediaCanSave;
if (plugin->SupportsPaginatedPrint())
- data.media_flags |= WebContextMenuData::kMediaCanPrint;
+ data.media_flags |= ContextMenuData::kMediaCanPrint;
// Add context menu commands that are supported by the plugin.
// Only show rotate view options if focus is not in an editable text
// area.
if (!plugin_can_edit_text && plugin->CanRotateView())
- data.media_flags |= WebContextMenuData::kMediaCanRotate;
+ data.media_flags |= ContextMenuData::kMediaCanRotate;
}
}
- }
+ } else {
+ // Check image media last to ensure that penetrating image selection
+ // does not override a topmost media element.
+ // TODO(benwgold): Consider extending penetration to all media types.
+ Node* potential_image_node = result.InnerNodeOrImageMapImage();
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ SCOPED_BLINK_UMA_HISTOGRAM_TIMER(
+ "Blink.ContextMenu.ImageSelection.ElapsedTime");
+ potential_image_node =
+ GetContextMenuNodeWithImageContents(/*report_histograms=*/true);
+ }
+ if (potential_image_node != nullptr &&
+ IsA<HTMLCanvasElement>(potential_image_node)) {
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kCanvas;
+ data.has_image_contents = true;
+ } else if (potential_image_node != nullptr &&
+ !HitTestResult::AbsoluteImageURL(potential_image_node)
+ .IsEmpty()) {
+ data.src_url = HitTestResult::AbsoluteImageURL(potential_image_node);
+ data.media_type = mojom::blink::ContextMenuDataMediaType::kImage;
+ data.media_flags |= ContextMenuData::kMediaCanPrint;
+ data.has_image_contents =
+ HitTestResult::GetImage(potential_image_node) &&
+ !HitTestResult::GetImage(potential_image_node)->IsNull();
+ }
+ }
// If it's not a link, an image, a media element, or an image/media link,
// show a selection menu or a more generic page menu.
- if (selected_frame->GetDocument()->Loader())
- data.frame_encoding = selected_frame->GetDocument()->EncodingName();
+ if (selected_frame->GetDocument()->Loader()) {
+ data.frame_encoding =
+ selected_frame->GetDocument()->EncodingName().GetString().Utf8();
+ }
data.selection_start_offset = 0;
// HitTestResult::isSelected() ensures clean layout by performing a hit test.
@@ -408,7 +604,7 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
if (result.IsSelected(location) ||
source_type == kMenuSourceAdjustSelection ||
source_type == kMenuSourceAdjustSelectionReset) {
- data.selected_text = selected_frame->SelectedText();
+ data.selected_text = selected_frame->SelectedText().Utf8();
WebRange range =
selected_frame->GetInputMethodController().GetSelectionOffsets();
data.selection_start_offset = range.StartOffset();
@@ -438,17 +634,30 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
// spelling marker on the word instead of spellchecking it.
std::pair<String, String> misspelled_word_and_description =
spell_checker.SelectMisspellingAsync();
- data.misspelled_word = misspelled_word_and_description.first;
+ data.misspelled_word =
+ WebString::FromUTF8(misspelled_word_and_description.first.Utf8())
+ .Utf16();
const String& description = misspelled_word_and_description.second;
if (description.length()) {
Vector<String> suggestions;
description.Split('\n', suggestions);
- data.dictionary_suggestions = suggestions;
+ WebVector<base::string16> web_suggestions(suggestions.size());
+ std::transform(suggestions.begin(), suggestions.end(),
+ web_suggestions.begin(), [](const String& s) {
+ return WebString::FromUTF8(s.Utf8()).Utf16();
+ });
+ data.dictionary_suggestions = web_suggestions.ReleaseVector();
} else if (spell_checker.GetTextCheckerClient()) {
size_t misspelled_offset, misspelled_length;
+ WebVector<WebString> web_suggestions;
spell_checker.GetTextCheckerClient()->CheckSpelling(
- data.misspelled_word, misspelled_offset, misspelled_length,
- &data.dictionary_suggestions);
+ WebString::FromUTF16(data.misspelled_word), misspelled_offset,
+ misspelled_length, &web_suggestions);
+ WebVector<base::string16> suggestions(web_suggestions.size());
+ std::transform(web_suggestions.begin(), web_suggestions.end(),
+ suggestions.begin(),
+ [](const WebString& s) { return s.Utf16(); });
+ data.dictionary_suggestions = suggestions.ReleaseVector();
}
}
@@ -456,20 +665,20 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
CSSPropertyID::kDirection,
"ltr") != EditingTriState::kFalse) {
data.writing_direction_left_to_right |=
- WebContextMenuData::kCheckableMenuItemChecked;
+ ContextMenuData::kCheckableMenuItemChecked;
}
if (EditingStyle::SelectionHasStyle(*selected_frame,
CSSPropertyID::kDirection,
"rtl") != EditingTriState::kFalse) {
data.writing_direction_right_to_left |=
- WebContextMenuData::kCheckableMenuItemChecked;
+ ContextMenuData::kCheckableMenuItemChecked;
}
data.referrer_policy = selected_frame->DomWindow()->GetReferrerPolicy();
if (menu_provider_) {
// Filter out custom menu elements and add them into the data.
- data.custom_items = menu_provider_->PopulateContextMenu();
+ data.custom_items = menu_provider_->PopulateContextMenu().ReleaseVector();
}
if (auto* anchor = DynamicTo<HTMLAnchorElement>(result.URLElement())) {
@@ -478,7 +687,7 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
selected_frame->GetSecurityContext()->GetSecurityOrigin();
if (origin->CanReadContent(anchor->Url())) {
data.suggested_filename =
- anchor->FastGetAttribute(html_names::kDownloadAttr);
+ anchor->FastGetAttribute(html_names::kDownloadAttr).Utf8();
}
// If the anchor wants to suppress the referrer, update the referrerPolicy
@@ -486,10 +695,17 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
if (anchor->HasRel(kRelationNoReferrer))
data.referrer_policy = network::mojom::ReferrerPolicy::kNever;
- data.link_text = anchor->innerText();
+ data.link_text = anchor->innerText().Utf8();
- if (anchor->HasImpression())
- data.impression = anchor->GetImpressionForNavigation();
+ if (anchor->HasImpression()) {
+ base::Optional<WebImpression> web_impression =
+ GetImpressionForAnchor(anchor);
+ data.impression =
+ web_impression.has_value()
+ ? base::Optional<Impression>(
+ ConvertWebImpressionToImpression(web_impression.value()))
+ : base::nullopt;
+ }
}
data.input_field_type = ComputeInputFieldType(result);
@@ -515,8 +731,10 @@ bool ContextMenuController::ShowContextMenu(LocalFrame* frame,
if (!selected_web_frame || !selected_web_frame->Client())
return false;
- selected_web_frame->Client()->ShowContextMenu(data,
- host_context_menu_location);
+ selected_web_frame->ShowContextMenu(
+ context_menu_client_receiver_.BindNewEndpointAndPassRemote(
+ selected_web_frame->GetTaskRunner(TaskType::kInternalDefault)),
+ data, host_context_menu_location);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_controller.h b/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
index 7c4c7e8fca9..8aea0b8c7b0 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_controller.h
@@ -30,9 +30,11 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/common/input/web_menu_source_type.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h"
namespace blink {
@@ -41,13 +43,14 @@ class Document;
class LocalFrame;
class MouseEvent;
class Page;
-struct WebContextMenuData;
+struct ContextMenuData;
class CORE_EXPORT ContextMenuController final
- : public GarbageCollected<ContextMenuController> {
+ : public GarbageCollected<ContextMenuController>,
+ public mojom::blink::ContextMenuClient {
public:
explicit ContextMenuController(Page*);
- ~ContextMenuController();
+ ~ContextMenuController() override;
void Trace(Visitor*) const;
void ClearContextMenu();
@@ -62,23 +65,64 @@ class CORE_EXPORT ContextMenuController final
void CustomContextMenuItemSelected(unsigned action);
+ Node* ContextMenuImageNodeForFrame(LocalFrame*);
Node* ContextMenuNodeForFrame(LocalFrame*);
+ // mojom::blink::ContextMenuClient methods.
+ void CustomContextMenuAction(uint32_t action) override;
+ void ContextMenuClosed(const KURL& link_followed) override;
+
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused. Keep in sync with enum in
+ // tools/metrics/histograms/enums.xml
+ enum ImageSelectionOutcome : uint32_t {
+ // An image node was found to be the topmost node.
+ kImageFoundStandard = 0,
+
+ // An image node was found below the topmost node.
+ kImageFoundPenetrating = 1,
+
+ // An opaque node was found when penetrating to attempt to find an image
+ // nnode.
+ kBlockedByOpaqueNode = 2,
+
+ // A context menu listener was found to be on one of the penetrated nodes
+ // or on one of those nodes' ancestors.
+ kFoundContextMenuListener = 3,
+
+ // A cross frame node was found while penetrating, which is not yet
+ // supported.
+ kBlockedByCrossFrameNode = 4,
+
+ kMaxValue = kBlockedByCrossFrameNode,
+ };
+
private:
friend class ContextMenuControllerTest;
+ uint32_t EnumToBitmask(ImageSelectionOutcome outcome) { return 1 << outcome; }
+
// Returns whether a Context Menu was actually shown.
bool ShowContextMenu(LocalFrame*,
const PhysicalOffset&,
WebMenuSourceType,
const MouseEvent* mouse_event = nullptr);
- bool ShouldShowContextMenuFromTouch(const WebContextMenuData&);
+
+ bool ShouldShowContextMenuFromTouch(const ContextMenuData&);
+
+ Node* GetContextMenuNodeWithImageContents(const bool report_histograms);
void UpdateTextFragmentSelectorGenerator(LocalFrame*);
+ HeapMojoAssociatedReceiver<mojom::blink::ContextMenuClient,
+ ContextMenuController,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ context_menu_client_receiver_{this, nullptr};
+
Member<Page> page_;
Member<ContextMenuProvider> menu_provider_;
HitTestResult hit_test_result_;
+
DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
};
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/chromium/third_party/blink/renderer/core/page/context_menu_controller_test.cc
index fe81f72ae79..7d20321595e 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -5,17 +5,22 @@
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "base/optional.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/context_menu_data/context_menu_data.h"
#include "third_party/blink/public/common/context_menu_data/edit_flags.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_menu_source_type.h"
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/web/web_context_menu_data.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom-blink.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/dom/xml_document.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/html/html_document.h"
@@ -28,6 +33,9 @@
#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/weburl_loader_mock.h"
+#include "third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
using testing::Return;
@@ -36,6 +44,9 @@ namespace blink {
namespace {
+constexpr char kTestResourceFilename[] = "white-1x1.png";
+constexpr char kTestResourceMimeType[] = "image/png";
+
class MockWebMediaPlayerForContextMenu : public EmptyWebMediaPlayer {
public:
MOCK_CONST_METHOD0(Duration, double());
@@ -49,32 +60,49 @@ class MockWebMediaPlayerForContextMenu : public EmptyWebMediaPlayer {
class TestWebFrameClientImpl : public frame_test_helpers::TestWebFrameClient {
public:
- void ShowContextMenu(const WebContextMenuData& data,
- const base::Optional<gfx::Point>&) override {
+ void UpdateContextMenuDataForTesting(
+ const ContextMenuData& data,
+ const base::Optional<gfx::Point>&) override {
context_menu_data_ = data;
}
- WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
- WebMediaPlayerClient*,
- blink::MediaInspectorContext*,
- WebMediaPlayerEncryptedMediaClient*,
- WebContentDecryptionModule*,
- const WebString& sink_id) override {
+ WebMediaPlayer* CreateMediaPlayer(
+ const WebMediaPlayerSource&,
+ WebMediaPlayerClient*,
+ blink::MediaInspectorContext*,
+ WebMediaPlayerEncryptedMediaClient*,
+ WebContentDecryptionModule*,
+ const WebString& sink_id,
+ const cc::LayerTreeSettings& settings) override {
return new MockWebMediaPlayerForContextMenu();
}
- const WebContextMenuData& GetContextMenuData() const {
+ const ContextMenuData& GetContextMenuData() const {
return context_menu_data_;
}
private:
- WebContextMenuData context_menu_data_;
+ ContextMenuData context_menu_data_;
};
+void RegisterMockedImageURLLoad(const String& url) {
+ url_test_helpers::RegisterMockedURLLoad(
+ url_test_helpers::ToKURL(url.Utf8().c_str()),
+ test::CoreTestDataPath(kTestResourceFilename), kTestResourceMimeType);
+}
+
} // anonymous namespace
-class ContextMenuControllerTest : public testing::Test {
+class ContextMenuControllerTest : public testing::Test,
+ public ::testing::WithParamInterface<bool> {
public:
+ explicit ContextMenuControllerTest(
+ bool penetrating_image_selection_enabled = GetParam()) {
+ feature_list_.InitWithFeatureState(
+ features::kEnablePenetratingImageSelection,
+ penetrating_image_selection_enabled);
+ }
+
void SetUp() override {
web_view_helper_.Initialize(&web_frame_client_);
@@ -85,12 +113,19 @@ class ContextMenuControllerTest : public testing::Test {
DocumentUpdateReason::kTest);
}
+ void TearDown() override {
+ url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
+ }
+
bool ShowContextMenu(const PhysicalOffset& location,
WebMenuSourceType source) {
- return web_view_helper_.GetWebView()
- ->GetPage()
- ->GetContextMenuController()
- .ShowContextMenu(GetDocument()->GetFrame(), location, source);
+ bool success =
+ web_view_helper_.GetWebView()
+ ->GetPage()
+ ->GetContextMenuController()
+ .ShowContextMenu(GetDocument()->GetFrame(), location, source);
+ base::RunLoop().RunUntilIdle();
+ return success;
}
bool ShowContextMenuForElement(Element* element, WebMenuSourceType source) {
@@ -124,12 +159,15 @@ class ContextMenuControllerTest : public testing::Test {
video->SetReadyState(state);
}
- private:
+ protected:
+ base::test::ScopedFeatureList feature_list_;
TestWebFrameClientImpl web_frame_client_;
frame_test_helpers::WebViewHelper web_view_helper_;
};
-TEST_F(ContextMenuControllerTest, VideoNotLoaded) {
+INSTANTIATE_TEST_SUITE_P(, ContextMenuControllerTest, ::testing::Bool());
+
+TEST_P(ContextMenuControllerTest, VideoNotLoaded) {
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
@@ -157,26 +195,26 @@ TEST_F(ContextMenuControllerTest, VideoNotLoaded) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kVideo, context_menu_data.media_type);
- EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kVideo,
+ context_menu_data.media_type);
+ EXPECT_EQ(video_url, context_menu_data.src_url.spec());
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, true},
- {WebContextMenuData::kMediaHasAudio, false},
- {WebContextMenuData::kMediaCanToggleControls, false},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, false},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, true},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, true},
+ {ContextMenuData::kMediaHasAudio, false},
+ {ContextMenuData::kMediaCanToggleControls, false},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, false},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, true},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -186,7 +224,7 @@ TEST_F(ContextMenuControllerTest, VideoNotLoaded) {
}
}
-TEST_F(ContextMenuControllerTest, VideoWithAudioOnly) {
+TEST_P(ContextMenuControllerTest, VideoWithAudioOnly) {
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
@@ -218,26 +256,26 @@ TEST_F(ContextMenuControllerTest, VideoWithAudioOnly) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kAudio, context_menu_data.media_type);
- EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kAudio,
+ context_menu_data.media_type);
+ EXPECT_EQ(video_url, context_menu_data.src_url.spec());
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, true},
- {WebContextMenuData::kMediaHasAudio, true},
- {WebContextMenuData::kMediaCanToggleControls, false},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, false},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, true},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, true},
+ {ContextMenuData::kMediaHasAudio, true},
+ {ContextMenuData::kMediaCanToggleControls, false},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, false},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, true},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -247,7 +285,7 @@ TEST_F(ContextMenuControllerTest, VideoWithAudioOnly) {
}
}
-TEST_F(ContextMenuControllerTest, PictureInPictureEnabledVideoLoaded) {
+TEST_P(ContextMenuControllerTest, PictureInPictureEnabledVideoLoaded) {
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
@@ -275,26 +313,26 @@ TEST_F(ContextMenuControllerTest, PictureInPictureEnabledVideoLoaded) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kVideo, context_menu_data.media_type);
- EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kVideo,
+ context_menu_data.media_type);
+ EXPECT_EQ(video_url, context_menu_data.src_url.spec());
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, true},
- {WebContextMenuData::kMediaHasAudio, false},
- {WebContextMenuData::kMediaCanToggleControls, true},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, true},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, true},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, true},
+ {ContextMenuData::kMediaHasAudio, false},
+ {ContextMenuData::kMediaCanToggleControls, true},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, true},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, true},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -304,7 +342,7 @@ TEST_F(ContextMenuControllerTest, PictureInPictureEnabledVideoLoaded) {
}
}
-TEST_F(ContextMenuControllerTest, PictureInPictureDisabledVideoLoaded) {
+TEST_P(ContextMenuControllerTest, PictureInPictureDisabledVideoLoaded) {
// Make sure Picture-in-Picture is disabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(false);
@@ -332,26 +370,26 @@ TEST_F(ContextMenuControllerTest, PictureInPictureDisabledVideoLoaded) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kVideo, context_menu_data.media_type);
- EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kVideo,
+ context_menu_data.media_type);
+ EXPECT_EQ(video_url, context_menu_data.src_url.spec());
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, true},
- {WebContextMenuData::kMediaHasAudio, false},
- {WebContextMenuData::kMediaCanToggleControls, true},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, false},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, true},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, true},
+ {ContextMenuData::kMediaHasAudio, false},
+ {ContextMenuData::kMediaCanToggleControls, true},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, false},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, true},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -361,7 +399,7 @@ TEST_F(ContextMenuControllerTest, PictureInPictureDisabledVideoLoaded) {
}
}
-TEST_F(ContextMenuControllerTest, MediaStreamVideoLoaded) {
+TEST_P(ContextMenuControllerTest, MediaStreamVideoLoaded) {
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
@@ -391,25 +429,25 @@ TEST_F(ContextMenuControllerTest, MediaStreamVideoLoaded) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kVideo, context_menu_data.media_type);
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kVideo,
+ context_menu_data.media_type);
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, false},
- {WebContextMenuData::kMediaHasAudio, false},
- {WebContextMenuData::kMediaCanToggleControls, true},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, true},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, false},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, false},
+ {ContextMenuData::kMediaHasAudio, false},
+ {ContextMenuData::kMediaCanToggleControls, true},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, true},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -419,7 +457,7 @@ TEST_F(ContextMenuControllerTest, MediaStreamVideoLoaded) {
}
}
-TEST_F(ContextMenuControllerTest, InfiniteDurationVideoLoaded) {
+TEST_P(ContextMenuControllerTest, InfiniteDurationVideoLoaded) {
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
@@ -453,26 +491,26 @@ TEST_F(ContextMenuControllerTest, InfiniteDurationVideoLoaded) {
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(ContextMenuDataMediaType::kVideo, context_menu_data.media_type);
- EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kVideo,
+ context_menu_data.media_type);
+ EXPECT_EQ(video_url, context_menu_data.src_url.spec());
- const Vector<std::pair<WebContextMenuData::MediaFlags, bool>>
+ const Vector<std::pair<ContextMenuData::MediaFlags, bool>>
expected_media_flags = {
- {WebContextMenuData::kMediaInError, false},
- {WebContextMenuData::kMediaPaused, true},
- {WebContextMenuData::kMediaMuted, false},
- {WebContextMenuData::kMediaLoop, false},
- {WebContextMenuData::kMediaCanSave, false},
- {WebContextMenuData::kMediaHasAudio, false},
- {WebContextMenuData::kMediaCanToggleControls, true},
- {WebContextMenuData::kMediaControls, false},
- {WebContextMenuData::kMediaCanPrint, false},
- {WebContextMenuData::kMediaCanRotate, false},
- {WebContextMenuData::kMediaCanPictureInPicture, true},
- {WebContextMenuData::kMediaPictureInPicture, false},
- {WebContextMenuData::kMediaCanLoop, false},
+ {ContextMenuData::kMediaInError, false},
+ {ContextMenuData::kMediaPaused, true},
+ {ContextMenuData::kMediaMuted, false},
+ {ContextMenuData::kMediaLoop, false},
+ {ContextMenuData::kMediaCanSave, false},
+ {ContextMenuData::kMediaHasAudio, false},
+ {ContextMenuData::kMediaCanToggleControls, true},
+ {ContextMenuData::kMediaControls, false},
+ {ContextMenuData::kMediaCanPrint, false},
+ {ContextMenuData::kMediaCanRotate, false},
+ {ContextMenuData::kMediaCanPictureInPicture, true},
+ {ContextMenuData::kMediaPictureInPicture, false},
+ {ContextMenuData::kMediaCanLoop, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
@@ -482,7 +520,7 @@ TEST_F(ContextMenuControllerTest, InfiniteDurationVideoLoaded) {
}
}
-TEST_F(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
+TEST_P(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
frame_test_helpers::LoadFrame(LocalMainFrame(), R"SVG(data:image/svg+xml,
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:h='http://www.w3.org/1999/xhtml'
@@ -509,9 +547,9 @@ TEST_F(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
selection.SelectSubString(*text_element, 4, 8);
EXPECT_TRUE(ShowContextMenuForElement(text_element, kMenuSourceMouse));
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(context_menu_data.media_type, ContextMenuDataMediaType::kNone);
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(context_menu_data.media_type,
+ mojom::blink::ContextMenuDataMediaType::kNone);
EXPECT_EQ(context_menu_data.edit_flags, ContextMenuDataEditFlags::kCanCopy);
EXPECT_EQ(context_menu_data.selected_text, "able tex");
@@ -521,7 +559,8 @@ TEST_F(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
EXPECT_TRUE(ShowContextMenuForElement(editable_element, kMenuSourceMouse));
context_menu_data = GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(context_menu_data.media_type, ContextMenuDataMediaType::kNone);
+ EXPECT_EQ(context_menu_data.media_type,
+ mojom::blink::ContextMenuDataMediaType::kNone);
EXPECT_EQ(context_menu_data.edit_flags,
ContextMenuDataEditFlags::kCanCut |
ContextMenuDataEditFlags::kCanCopy |
@@ -530,7 +569,7 @@ TEST_F(ContextMenuControllerTest, EditingActionsEnabledInSVGDocument) {
ContextMenuDataEditFlags::kCanEditRichly);
}
-TEST_F(ContextMenuControllerTest, EditingActionsEnabledInXMLDocument) {
+TEST_P(ContextMenuControllerTest, EditingActionsEnabledInXMLDocument) {
frame_test_helpers::LoadFrame(LocalMainFrame(), R"XML(data:text/xml,
<root>
<style xmlns="http://www.w3.org/1999/xhtml">
@@ -551,14 +590,14 @@ TEST_F(ContextMenuControllerTest, EditingActionsEnabledInXMLDocument) {
selection.SelectAll();
EXPECT_TRUE(ShowContextMenuForElement(text_element, kMenuSourceMouse));
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(context_menu_data.media_type, ContextMenuDataMediaType::kNone);
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(context_menu_data.media_type,
+ mojom::blink::ContextMenuDataMediaType::kNone);
EXPECT_EQ(context_menu_data.edit_flags, ContextMenuDataEditFlags::kCanCopy);
EXPECT_EQ(context_menu_data.selected_text, "Blue text");
}
-TEST_F(ContextMenuControllerTest, ShowNonLocatedContextMenuEvent) {
+TEST_P(ContextMenuControllerTest, ShowNonLocatedContextMenuEvent) {
GetDocument()->documentElement()->setInnerHTML(
"<input id='sample' type='text' size='5' value='Sample Input Text'>");
@@ -575,8 +614,7 @@ TEST_F(ContextMenuControllerTest, ShowNonLocatedContextMenuEvent) {
GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(gesture_event, ui::LatencyInfo()));
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(context_menu_data.selected_text, "Sample");
// Adjust the selection from the start of |input| to the middle.
@@ -606,7 +644,7 @@ TEST_F(ContextMenuControllerTest, ShowNonLocatedContextMenuEvent) {
#if !defined(OS_MAC)
// Mac has no way to open a context menu based on a keyboard event.
-TEST_F(ContextMenuControllerTest,
+TEST_P(ContextMenuControllerTest,
ValidateNonLocatedContextMenuOnLargeImageElement) {
GetDocument()->documentElement()->setInnerHTML(
"<img src=\"http://example.test/cat.jpg\" id=\"sample_image\" "
@@ -630,13 +668,13 @@ TEST_F(ContextMenuControllerTest,
GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(key_event, ui::LatencyInfo()));
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
- EXPECT_EQ(context_menu_data.media_type, ContextMenuDataMediaType::kImage);
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(context_menu_data.media_type,
+ mojom::blink::ContextMenuDataMediaType::kImage);
}
#endif
-TEST_F(ContextMenuControllerTest, SelectionRectClipped) {
+TEST_P(ContextMenuControllerTest, SelectionRectClipped) {
GetDocument()->documentElement()->setInnerHTML(
"<textarea id='text-area' cols=6 rows=2>Sample editable text</textarea>");
@@ -654,8 +692,7 @@ TEST_F(ContextMenuControllerTest, SelectionRectClipped) {
GetWebView()->MainFrameWidget()->HandleInputEvent(
WebCoalescedInputEvent(gesture_event, ui::LatencyInfo()));
- WebContextMenuData context_menu_data =
- GetWebFrameClient().GetContextMenuData();
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(context_menu_data.selected_text, "Sample");
// The selection rect is not clipped.
@@ -667,7 +704,7 @@ TEST_F(ContextMenuControllerTest, SelectionRectClipped) {
int top = std::min(focus.Y(), anchor.Y());
int right = std::max(focus.MaxX(), anchor.MaxX());
int bottom = std::max(focus.MaxY(), anchor.MaxY());
- WebRect selection_rect(left, top, right - left, bottom - top);
+ gfx::Rect selection_rect(left, top, right - left, bottom - top);
EXPECT_EQ(context_menu_data.selection_rect, selection_rect);
// Select all the content of |textarea|.
@@ -686,8 +723,665 @@ TEST_F(ContextMenuControllerTest, SelectionRectClipped) {
top = std::max(clip_bound.Y(), std::min(focus.Y(), anchor.Y()));
right = std::min(clip_bound.MaxX(), std::max(focus.MaxX(), anchor.MaxX()));
bottom = std::min(clip_bound.MaxY(), std::max(focus.MaxY(), anchor.MaxY()));
- selection_rect = WebRect(left, top, right - left, bottom - top);
+ selection_rect = gfx::Rect(left, top, right - left, bottom - top);
EXPECT_EQ(context_menu_data.selection_rect, selection_rect);
}
+class MockEventListener final : public NativeEventListener {
+ public:
+ MOCK_METHOD2(Invoke, void(ExecutionContext*, Event*));
+};
+
+// Test that a basic image hit test works without penetration enabled.
+TEST_P(ContextMenuControllerTest, ContextMenuImageHitTestStandardImageControl) {
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ </body>
+ )HTML");
+
+ base::HistogramTester histograms;
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ("http://test.png/", context_menu_data.src_url.spec());
+ // EXPECT_TRUE(context_menu_data.has_image_contents);
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kImage,
+ context_menu_data.media_type);
+
+ // No histograms should be sent in the control group.
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that a basic image hit test works and is no† impacted by
+// penetrating image selection logic.
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestStandardImageSelectionExperiment) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+
+ String url = "http://test.png";
+ LOG(ERROR) << "URL IS: " << url.Utf8().c_str();
+ RegisterMockedImageURLLoad(url);
+
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ </style>
+ <img id=target src="http://test.png">
+ </body>
+ )HTML");
+
+ base::HistogramTester histograms;
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ("http://test.png/", context_menu_data.src_url.spec());
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kImage,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that image selection can penetrate through a fully transparent div
+// above the target image.
+TEST_P(ContextMenuControllerTest, ContextMenuImageHitTestSucceededPenetrating) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ <div id=occluder></div>
+ </body>
+ )HTML");
+
+ base::HistogramTester histograms;
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ("http://test.png/", context_menu_data.src_url.spec());
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kImage,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that a basic image hit test works and is no† impacted by
+// penetrating image selection logic.
+TEST_P(ContextMenuControllerTest, ContextMenuImageHitTestStandardCanvas) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ </style>
+ <canvas id=target>
+ </body>
+ )HTML");
+
+ base::HistogramTester histograms;
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kCanvas,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will not be selected through an opaque div
+// above the target image.
+TEST_P(ContextMenuControllerTest, ContextMenuImageHitTestOpaqueNodeBlocking) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #opaque {
+ background: blue;
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 3;
+ }
+ </style>
+
+ <img id=target src='http://test.png'>
+ <div id=opaque></div>
+ <div id=occluder></div>
+ </body>
+ )HTML");
+
+ base::HistogramTester histograms;
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kNone,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will not be selected if a node with a context menu
+// listener is above the image node, but that we will still log the presence of
+// the image.
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestContextMenuListenerAboveImageBlocking) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #nodewithlistener {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 3;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ <div id=nodewithlistener></div>
+ <div id=occluder></div>
+ </body>
+)HTML");
+
+ Persistent<MockEventListener> event_listener =
+ MakeGarbageCollected<MockEventListener>();
+ base::HistogramTester histograms;
+
+ Element* target_image = GetDocument()->getElementById("target");
+ target_image->addEventListener(event_type_names::kContextmenu,
+ event_listener);
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kNone,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will not be selected if the image node itself has a
+// context menu listener on it (and the image node is not the topmost element)
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestContextMenuListenerOnImageBlocking) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ <div id=occluder></div>
+ </body>
+ )HTML");
+
+ // Attaching a listener for the finished event indicates pending activity.
+ Persistent<MockEventListener> event_listener =
+ MakeGarbageCollected<MockEventListener>();
+ base::HistogramTester histograms;
+
+ Element* target_image = GetDocument()->getElementById("target");
+ target_image->addEventListener(event_type_names::kContextmenu,
+ event_listener);
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kNone,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will be selected if the image node itself has an
+// unrelated event listener on it.
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestNonBlockingNonContextMenuListenerOnImage) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ <div id=occluder></div>
+ </body>
+ )HTML");
+
+ Persistent<MockEventListener> event_listener =
+ MakeGarbageCollected<MockEventListener>();
+ base::HistogramTester histograms;
+
+ Element* target_image = GetDocument()->getElementById("target");
+ target_image->addEventListener(event_type_names::kClick, event_listener);
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kImage,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will still be selected if it is the topmost node
+// despite an ancestor having a context menu listener attached to it.
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestStandardContextMenuListenerAncestorNonBlocking) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #hiddenancestor {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ z-index: 1;
+ }
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 2;
+ }
+ </style>
+ <div id=hiddenancestor>
+ <img id=target src='http://test.png'>
+ </div>
+ </body>
+ )HTML");
+
+ Persistent<MockEventListener> event_listener =
+ MakeGarbageCollected<MockEventListener>();
+ base::HistogramTester histograms;
+
+ Element* hidden_ancestor = GetDocument()->getElementById("hiddenancestor");
+ hidden_ancestor->addEventListener(event_type_names::kContextmenu,
+ event_listener);
+
+ // This hit test would miss the node with the listener if it was not an
+ // ancestor.
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ // EXPECT_TRUE(context_menu_data.has_image_contents);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// Test that an image node will not be selected if a non image node with a
+// context listener ancestor is above it and verify that topmost context menu
+// listener special logic only applies if the topmost node is an image.
+TEST_P(ContextMenuControllerTest,
+ ContextMenuImageHitTestContextMenuListenerAncestorBlocking) {
+ if (!base::FeatureList::IsEnabled(
+ features::kEnablePenetratingImageSelection)) {
+ return;
+ }
+ RegisterMockedImageURLLoad("http://test.png");
+ ContextMenuAllowedScope context_menu_allowed_scope;
+
+ GetDocument()->documentElement()->setInnerHTML(R"HTML(
+ <body>
+ <style>
+ #target {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 1;
+ }
+ #hiddenancestor {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ z-index: 2;
+ }
+ #occluder {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ z-index: 3;
+ }
+ </style>
+ <img id=target src='http://test.png'>
+ <div id=hiddenancestor>
+ <div id=occluder></div>
+ </div>
+ </body>
+ )HTML");
+
+ Persistent<MockEventListener> event_listener =
+ MakeGarbageCollected<MockEventListener>();
+ base::HistogramTester histograms;
+
+ Element* hidden_ancestor = GetDocument()->getElementById("hiddenancestor");
+ hidden_ancestor->addEventListener(event_type_names::kContextmenu,
+ event_listener);
+
+ PhysicalOffset location(LayoutUnit(5), LayoutUnit(5));
+ EXPECT_TRUE(ShowContextMenu(location, kMenuSourceLongPress));
+
+ // Context menu info are sent to the WebLocalFrameClient.
+ ContextMenuData context_menu_data = GetWebFrameClient().GetContextMenuData();
+ EXPECT_EQ(mojom::blink::ContextMenuDataMediaType::kNone,
+ context_menu_data.media_type);
+
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundStandard, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kImageFoundPenetrating,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByOpaqueNode, 0);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kFoundContextMenuListener,
+ 1);
+ histograms.ExpectBucketCount("Blink.ContextMenu.ImageSelection.Outcome",
+ ContextMenuController::kBlockedByCrossFrameNode,
+ 0);
+}
+
+// TODO(crbug.com/1184996): Add additional unit test for blocking frame logging.
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/context_menu_provider.h b/chromium/third_party/blink/renderer/core/page/context_menu_provider.h
index 9df648c8565..4cb191b6201 100644
--- a/chromium/third_party/blink/renderer/core/page/context_menu_provider.h
+++ b/chromium/third_party/blink/renderer/core/page/context_menu_provider.h
@@ -36,14 +36,14 @@
namespace blink {
-struct WebMenuItemInfo;
+struct MenuItemInfo;
class ContextMenuProvider : public GarbageCollected<ContextMenuProvider> {
public:
virtual ~ContextMenuProvider() = default;
virtual void Trace(Visitor* visitor) const {}
- virtual WebVector<WebMenuItemInfo> PopulateContextMenu() = 0;
+ virtual WebVector<MenuItemInfo> PopulateContextMenu() = 0;
virtual void ContextMenuItemSelected(unsigned action) = 0;
virtual void ContextMenuCleared() = 0;
};
diff --git a/chromium/third_party/blink/renderer/core/page/create_window.cc b/chromium/third_party/blink/renderer/core/page/create_window.cc
index da7f4f29aa9..39004847485 100644
--- a/chromium/third_party/blink/renderer/core/page/create_window.cc
+++ b/chromium/third_party/blink/renderer/core/page/create_window.cc
@@ -279,34 +279,26 @@ Frame* CreateNewWindow(LocalFrame& opener_frame,
return nullptr;
}
- bool propagate_sandbox =
- opener_window.IsSandboxed(network::mojom::blink::WebSandboxFlags::
- kPropagatesToAuxiliaryBrowsingContexts);
network::mojom::blink::WebSandboxFlags sandbox_flags =
- propagate_sandbox ? opener_window.GetSandboxFlags()
- : network::mojom::blink::WebSandboxFlags::kNone;
- bool not_sandboxed = opener_window.GetSandboxFlags() ==
- network::mojom::blink::WebSandboxFlags::kNone;
- FeaturePolicyFeatureState opener_feature_state =
- (not_sandboxed || propagate_sandbox) ? opener_window.GetSecurityContext()
- .GetFeaturePolicy()
- ->GetFeatureState()
- : FeaturePolicyFeatureState();
+ opener_window.IsSandboxed(network::mojom::blink::WebSandboxFlags::
+ kPropagatesToAuxiliaryBrowsingContexts)
+ ? opener_window.GetSandboxFlags()
+ : network::mojom::blink::WebSandboxFlags::kNone;
SessionStorageNamespaceId new_namespace_id =
AllocateSessionStorageNamespaceId();
Page* old_page = opener_frame.GetPage();
- // TODO(dmurph): Don't copy session storage when features.noopener is true:
- // https://html.spec.whatwg.org/C/#copy-session-storage
- // https://crbug.com/771959
- CoreInitializer::GetInstance().CloneSessionStorage(old_page,
- new_namespace_id);
+ if (!features.noopener ||
+ base::FeatureList::IsEnabled(features::kCloneSessionStorageForNoOpener)) {
+ CoreInitializer::GetInstance().CloneSessionStorage(old_page,
+ new_namespace_id);
+ }
bool consumed_user_gesture = false;
Page* page = old_page->GetChromeClient().CreateWindow(
&opener_frame, request, frame_name, features, sandbox_flags,
- opener_feature_state, new_namespace_id, consumed_user_gesture);
+ new_namespace_id, consumed_user_gesture);
if (!page)
return nullptr;
@@ -341,7 +333,7 @@ Frame* CreateNewWindow(LocalFrame& opener_frame,
IntRect rect = page->GetChromeClient().CalculateWindowRectWithAdjustment(
window_rect, frame, opener_frame);
- page->GetChromeClient().Show(opener_frame.GetFrameToken(),
+ page->GetChromeClient().Show(opener_frame.GetLocalFrameToken(),
request.GetNavigationPolicy(), rect,
consumed_user_gesture);
MaybeLogWindowOpen(opener_frame);
diff --git a/chromium/third_party/blink/renderer/core/page/drag_controller.cc b/chromium/third_party/blink/renderer/core/page/drag_controller.cc
index 4845c786767..d4f132548d8 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_controller.cc
@@ -92,6 +92,7 @@
#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/shared_buffer.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -99,6 +100,8 @@
namespace blink {
+using ui::mojom::blink::DragOperation;
+
static const int kMaxOriginalImageArea = 1500 * 1500;
static const int kLinkDragBorderInset = 2;
static const float kDragImageAlpha = 0.75f;
@@ -284,7 +287,7 @@ void DragController::PerformDrag(DragData* drag_data, LocalFrame& local_root) {
return;
}
- if (OperationForLoad(drag_data, local_root) != kDragOperationNone) {
+ if (OperationForLoad(drag_data, local_root) != DragOperation::kNone) {
if (page_->GetSettings().GetNavigateOnDragDrop()) {
ResourceRequest resource_request(drag_data->AsURL());
resource_request.SetHasUserGesture(LocalFrame::HasTransientUserActivation(
@@ -346,7 +349,7 @@ DragOperation DragController::DragEnteredOrUpdated(DragData* drag_data,
: static_cast<DragDestinationAction>(kDragDestinationActionDHTML |
kDragDestinationActionEdit);
- DragOperation drag_operation = kDragOperationNone;
+ DragOperation drag_operation = DragOperation::kNone;
document_is_handling_drag_ = TryDocumentDrag(
drag_data, drag_destination_action_, drag_operation, local_root);
if (!document_is_handling_drag_ &&
@@ -445,8 +448,8 @@ bool DragController::TryDocumentDrag(DragData* drag_data,
LocalFrame* inner_frame = element->GetDocument().GetFrame();
drag_operation = DragIsMove(inner_frame->Selection(), drag_data)
- ? kDragOperationMove
- : kDragOperationCopy;
+ ? DragOperation::kMove
+ : DragOperation::kCopy;
if (file_input_element_under_mouse_) {
bool can_receive_dropped_files = false;
if (!file_input_element_under_mouse_->IsDisabledFormControl()) {
@@ -455,7 +458,7 @@ bool DragController::TryDocumentDrag(DragData* drag_data,
: drag_data->NumberOfFiles() == 1;
}
if (!can_receive_dropped_files)
- drag_operation = kDragOperationNone;
+ drag_operation = DragOperation::kNone;
file_input_element_under_mouse_->SetCanReceiveDroppedFiles(
can_receive_dropped_files);
}
@@ -480,7 +483,7 @@ DragOperation DragController::OperationForLoad(DragData* drag_data,
if (doc && (did_initiate_drag_ || IsA<PluginDocument>(doc) ||
HasEditableStyle(*doc)))
- return kDragOperationNone;
+ return DragOperation::kNone;
return GetDragOperation(drag_data);
}
@@ -754,21 +757,21 @@ bool DragController::CanProcessDrag(DragData* drag_data,
return true;
}
-static DragOperation DefaultOperationForDrag(DragOperation src_op_mask) {
+static DragOperation DefaultOperationForDrag(DragOperationsMask src_op_mask) {
// This is designed to match IE's operation fallback for the case where
// the page calls preventDefault() in a drag event but doesn't set dropEffect.
if (src_op_mask == kDragOperationEvery)
- return kDragOperationCopy;
+ return DragOperation::kCopy;
if (src_op_mask == kDragOperationNone)
- return kDragOperationNone;
+ return DragOperation::kNone;
if (src_op_mask & kDragOperationMove)
- return kDragOperationMove;
+ return DragOperation::kMove;
if (src_op_mask & kDragOperationCopy)
- return kDragOperationCopy;
+ return DragOperation::kCopy;
if (src_op_mask & kDragOperationLink)
- return kDragOperationLink;
+ return DragOperation::kLink;
- return kDragOperationNone;
+ return DragOperation::kNone;
}
bool DragController::TryDHTMLDrag(DragData* drag_data,
@@ -781,7 +784,7 @@ bool DragController::TryDHTMLDrag(DragData* drag_data,
DataTransferAccessPolicy policy = DataTransferAccessPolicy::kTypesReadable;
DataTransfer* data_transfer = CreateDraggingDataTransfer(policy, drag_data);
- DragOperation src_op_mask = drag_data->DraggingSourceOperationMask();
+ DragOperationsMask src_op_mask = drag_data->DraggingSourceOperationMask();
data_transfer->SetSourceOperation(src_op_mask);
WebMouseEvent event = CreateMouseEvent(drag_data);
@@ -793,12 +796,14 @@ bool DragController::TryDHTMLDrag(DragData* drag_data,
return false;
}
- operation = data_transfer->DestinationOperation();
- if (data_transfer->DropEffectIsUninitialized()) {
+ if (!data_transfer->DropEffectIsInitialized()) {
operation = DefaultOperationForDrag(src_op_mask);
- } else if (!(src_op_mask & operation)) {
- // The element picked an operation which is not supported by the source
- operation = kDragOperationNone;
+ } else {
+ operation = data_transfer->DestinationOperation();
+ if (!(src_op_mask & static_cast<int>(operation))) {
+ // The element picked an operation which is not supported by the source.
+ operation = DragOperation::kNone;
+ }
}
data_transfer->SetAccessPolicy(
@@ -906,21 +911,6 @@ Node* DragController::DraggableNode(const LocalFrame* src,
return node;
}
-static ImageResourceContent* GetImageResource(Element* element) {
- DCHECK(element);
- if (auto* layout_image = DynamicTo<LayoutImage>(element->GetLayoutObject()))
- return layout_image->CachedImage();
- return nullptr;
-}
-
-static Image* GetImage(Element* element) {
- DCHECK(element);
- ImageResourceContent* cached_image = GetImageResource(element);
- return (cached_image && !cached_image->ErrorOccurred())
- ? cached_image->GetImage()
- : nullptr;
-}
-
static void PrepareDataTransferForImageDrag(LocalFrame* source,
DataTransfer* data_transfer,
Element* node,
@@ -1063,63 +1053,68 @@ static const IntSize MaxDragImageSize(float device_scale_factor) {
return max_size_in_pixels;
}
+static bool CanDragImage(const Element& element) {
+ auto* layout_image = DynamicTo<LayoutImage>(element.GetLayoutObject());
+ if (!layout_image)
+ return false;
+ const ImageResourceContent* image_content = layout_image->CachedImage();
+ if (!image_content || image_content->ErrorOccurred() ||
+ image_content->GetImage()->IsNull())
+ return false;
+ scoped_refptr<const SharedBuffer> buffer = image_content->ResourceBuffer();
+ if (!buffer || !buffer->size())
+ return false;
+ // We shouldn't be starting a drag for an image that can't provide an
+ // extension.
+ // This is an early detection for problems encountered later upon drop.
+ DCHECK(!image_content->GetImage()->FilenameExtension().IsEmpty());
+ return true;
+}
+
static std::unique_ptr<DragImage> DragImageForImage(
- Element* element,
- Image* image,
+ const Element& element,
float device_scale_factor,
- const IntPoint& drag_origin,
- const IntPoint& image_element_location,
- const IntSize& image_element_size_in_pixels,
- IntPoint& drag_location) {
- std::unique_ptr<DragImage> drag_image;
- IntPoint origin;
-
- // Substitute an appropriately-sized SVGImageForContainer, to ensure dragged
- // SVG images scale seamlessly.
- scoped_refptr<SVGImageForContainer> svg_image;
- if (auto* svg_img = DynamicTo<SVGImage>(image)) {
- KURL url = element->GetDocument().CompleteURL(element->ImageSourceURL());
- svg_image = SVGImageForContainer::Create(
- svg_img, FloatSize(image_element_size_in_pixels), 1, url);
- image = svg_image.get();
- }
+ const IntSize& image_element_size_in_pixels) {
+ auto* layout_image = To<LayoutImage>(element.GetLayoutObject());
+ const LayoutImageResource& image_resource = *layout_image->ImageResource();
+ scoped_refptr<Image> image =
+ image_resource.GetImage(image_element_size_in_pixels);
+ RespectImageOrientationEnum respect_orientation =
+ image_resource.ImageOrientation();
+
+ IntSize image_size = image->Size(respect_orientation);
+ if (image_size.Area() > kMaxOriginalImageArea)
+ return nullptr;
InterpolationQuality interpolation_quality = kInterpolationDefault;
- if (const ComputedStyle* style = element->GetComputedStyle()) {
- if (style->ImageRendering() == EImageRendering::kPixelated)
- interpolation_quality = kInterpolationNone;
- }
-
- RespectImageOrientationEnum respect_image_orientation =
- LayoutObject::ShouldRespectImageOrientation(element->GetLayoutObject());
+ if (layout_image->StyleRef().ImageRendering() == EImageRendering::kPixelated)
+ interpolation_quality = kInterpolationNone;
- IntSize image_size = image->Size(respect_image_orientation);
FloatSize image_scale =
DragImage::ClampedImageScale(image_size, image_element_size_in_pixels,
MaxDragImageSize(device_scale_factor));
- if (image_size.Area() <= kMaxOriginalImageArea &&
- (drag_image = DragImage::Create(
- image, respect_image_orientation, device_scale_factor,
- interpolation_quality, kDragImageAlpha, image_scale))) {
- IntSize original_size = image_element_size_in_pixels;
- origin = image_element_location;
-
- IntSize new_size = drag_image->Size();
-
- // Properly orient the drag image and orient it differently if it's smaller
- // than the original
- float scale = new_size.Width() / (float)original_size.Width();
- float dx = origin.X() - drag_origin.X();
- dx *= scale;
- origin.SetX((int)(dx + 0.5));
- float dy = origin.Y() - drag_origin.Y();
- dy *= scale;
- origin.SetY((int)(dy + 0.5));
- }
+ return DragImage::Create(image.get(), respect_orientation,
+ device_scale_factor, interpolation_quality,
+ kDragImageAlpha, image_scale);
+}
- drag_location = drag_origin + origin;
- return drag_image;
+static IntPoint DragLocationForImage(
+ const DragImage* drag_image,
+ const IntPoint& drag_origin,
+ const IntPoint& image_element_location,
+ const IntSize& image_element_size_in_pixels) {
+ if (!drag_image)
+ return drag_origin;
+
+ IntSize original_size = image_element_size_in_pixels;
+ IntSize new_size = drag_image->Size();
+
+ // Properly orient the drag image and orient it differently if it's smaller
+ // than the original
+ float scale = new_size.Width() / static_cast<float>(original_size.Width());
+ FloatPoint offset(image_element_location - drag_origin);
+ return drag_origin + RoundedIntPoint(offset.ScaledBy(scale));
}
static std::unique_ptr<DragImage> DragImageForLink(const KURL& link_url,
@@ -1178,8 +1173,8 @@ std::unique_ptr<DragImage> DragController::DragImageForSelection(
.LocalBorderBoxProperties()
.Unalias();
return DataTransfer::CreateDragImageForFrame(
- frame, opacity, kRespectImageOrientation, painting_rect.Size(),
- painting_rect.Location(), builder, property_tree_state);
+ frame, opacity, painting_rect.Size(), painting_rect.Location(), builder,
+ property_tree_state);
}
bool DragController::StartDrag(LocalFrame* src,
@@ -1237,15 +1232,8 @@ bool DragController::StartDrag(LocalFrame* src,
src, false);
} else if (state.drag_type_ == kDragSourceActionImage) {
auto* element = DynamicTo<Element>(node);
- if (image_url.IsEmpty() || !element)
- return false;
- Image* image = GetImage(element);
- if (!image || image->IsNull() || !image->Data() || !image->Data()->size())
+ if (image_url.IsEmpty() || !element || !CanDragImage(*element))
return false;
- // We shouldn't be starting a drag for an image that can't provide an
- // extension.
- // This is an early detection for problems encountered later upon drop.
- DCHECK(!image->FilenameExtension().IsEmpty());
if (!drag_image) {
const IntRect& image_rect = hit_test_result.ImageRect();
IntSize image_size_in_pixels = image_rect.Size();
@@ -1262,9 +1250,11 @@ bool DragController::StartDrag(LocalFrame* src,
// TODO(oshima): Currently, the dragged image on high DPI is scaled and
// can be blurry because of this. Consider to clip in the screen
// coordinates to use high resolution image on high DPI screens.
- drag_image = DragImageForImage(element, image, screen_device_scale_factor,
- drag_origin, image_rect.Location(),
- image_size_in_pixels, drag_location);
+ drag_image = DragImageForImage(*element, screen_device_scale_factor,
+ image_size_in_pixels);
+ drag_location =
+ DragLocationForImage(drag_image.get(), drag_origin,
+ image_rect.Location(), image_size_in_pixels);
}
DoSystemDrag(drag_image.get(), drag_location, drag_origin, data_transfer,
src, false);
@@ -1353,13 +1343,13 @@ void DragController::DoSystemDrag(DragImage* image,
}
DragOperation DragController::GetDragOperation(DragData* drag_data) {
- // FIXME: To match the MacOS behaviour we should return DragOperationNone
+ // FIXME: To match the MacOS behaviour we should return DragOperation::kNone
// if we are a modal window, we are the drag source, or the window is an
// attached sheet If this can be determined from within WebCore
// operationForDrag can be pulled into WebCore itself
DCHECK(drag_data);
- return drag_data->ContainsURL() && !did_initiate_drag_ ? kDragOperationCopy
- : kDragOperationNone;
+ return drag_data->ContainsURL() && !did_initiate_drag_ ? DragOperation::kCopy
+ : DragOperation::kNone;
}
bool DragController::IsCopyKeyDown(DragData* drag_data) {
diff --git a/chromium/third_party/blink/renderer/core/page/drag_controller.h b/chromium/third_party/blink/renderer/core/page/drag_controller.h
index 82a386359d8..498edf24f21 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/drag_controller.h
@@ -27,7 +27,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_DRAG_CONTROLLER_H_
#include "base/macros.h"
-#include "third_party/blink/public/common/page/drag_operation.h"
#include "third_party/blink/renderer/core/core_export.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"
@@ -36,6 +35,7 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h"
namespace blink {
@@ -58,7 +58,8 @@ class CORE_EXPORT DragController final
public:
explicit DragController(Page*);
- DragOperation DragEnteredOrUpdated(DragData*, LocalFrame& local_root);
+ ui::mojom::blink::DragOperation DragEnteredOrUpdated(DragData*,
+ LocalFrame& local_root);
void DragExited(DragData*, LocalFrame& local_root);
void PerformDrag(DragData*, LocalFrame& local_root);
@@ -98,13 +99,16 @@ class CORE_EXPORT DragController final
DispatchEventResult DispatchTextInputEventFor(LocalFrame*, DragData*);
bool CanProcessDrag(DragData*, LocalFrame& local_root);
bool ConcludeEditDrag(DragData*);
- DragOperation OperationForLoad(DragData*, LocalFrame& local_root);
+ ui::mojom::blink::DragOperation OperationForLoad(DragData*,
+ LocalFrame& local_root);
bool TryDocumentDrag(DragData*,
DragDestinationAction,
- DragOperation&,
+ ui::mojom::blink::DragOperation&,
LocalFrame& local_root);
- bool TryDHTMLDrag(DragData*, DragOperation&, LocalFrame& local_root);
- DragOperation GetDragOperation(DragData*);
+ bool TryDHTMLDrag(DragData*,
+ ui::mojom::blink::DragOperation&,
+ LocalFrame& local_root);
+ ui::mojom::blink::DragOperation GetDragOperation(DragData*);
// Clear the selection from the document this drag is exiting.
void ClearDragCaret();
bool DragIsMove(FrameSelection&, DragData*);
diff --git a/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc b/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
index 3fcd7d966ca..1d4c15be797 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_controller_test.cc
@@ -101,8 +101,8 @@ TEST_F(DragControllerSimTest, DropURLOnNonNavigatingClearsState) {
object->SetURLAndTitle("https://www.example.com/index.html", "index");
DragData data(
object, FloatPoint(10, 10), FloatPoint(10, 10),
- static_cast<DragOperation>(kDragOperationCopy | kDragOperationLink |
- kDragOperationMove));
+ static_cast<DragOperationsMask>(kDragOperationCopy | kDragOperationLink |
+ kDragOperationMove));
WebView().GetPage()->GetDragController().DragEnteredOrUpdated(
&data, *GetDocument().GetFrame());
@@ -141,8 +141,8 @@ TEST_F(DragControllerSimTest, ThrottledDocumentHandled) {
object->SetURLAndTitle("https://www.example.com/index.html", "index");
DragData data(
object, FloatPoint(10, 10), FloatPoint(10, 10),
- static_cast<DragOperation>(kDragOperationCopy | kDragOperationLink |
- kDragOperationMove));
+ static_cast<DragOperationsMask>(kDragOperationCopy | kDragOperationLink |
+ kDragOperationMove));
WebView().GetPage()->GetDragController().DragEnteredOrUpdated(
&data, *GetDocument().GetFrame());
diff --git a/chromium/third_party/blink/renderer/core/page/drag_data.cc b/chromium/third_party/blink/renderer/core/page/drag_data.cc
index b50ffd80d6b..d5ace3a879a 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_data.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_data.cc
@@ -41,7 +41,7 @@ namespace blink {
DragData::DragData(DataObject* data,
const FloatPoint& client_position,
const FloatPoint& global_position,
- DragOperation source_operation_mask)
+ DragOperationsMask source_operation_mask)
: client_position_(client_position),
global_position_(global_position),
platform_drag_data_(data),
diff --git a/chromium/third_party/blink/renderer/core/page/drag_data.h b/chromium/third_party/blink/renderer/core/page/drag_data.h
index 5e88289e2f1..f63b61df401 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_data.h
+++ b/chromium/third_party/blink/renderer/core/page/drag_data.h
@@ -52,11 +52,11 @@ class CORE_EXPORT DragData {
DragData(DataObject*,
const FloatPoint& client_position,
const FloatPoint& global_position,
- DragOperation);
+ DragOperationsMask);
const FloatPoint& ClientPosition() const { return client_position_; }
const FloatPoint& GlobalPosition() const { return global_position_; }
DataObject* PlatformData() const { return platform_drag_data_; }
- DragOperation DraggingSourceOperationMask() const {
+ DragOperationsMask DraggingSourceOperationMask() const {
return dragging_source_operation_mask_;
}
bool ContainsURL(
@@ -79,7 +79,7 @@ class CORE_EXPORT DragData {
const FloatPoint client_position_;
const FloatPoint global_position_;
DataObject* const platform_drag_data_;
- const DragOperation dragging_source_operation_mask_;
+ const DragOperationsMask dragging_source_operation_mask_;
bool ContainsHTML() const;
};
diff --git a/chromium/third_party/blink/renderer/core/page/drag_image.cc b/chromium/third_party/blink/renderer/core/page/drag_image.cc
index 3378bf068ac..be32e889024 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_image.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_image.cc
@@ -204,7 +204,7 @@ std::unique_ptr<DragImage> DragImage::Create(const KURL& url,
// TODO(fserb): are we sure this should be software?
std::unique_ptr<CanvasResourceProvider> resource_provider(
CanvasResourceProvider::CreateBitmapProvider(
- scaled_image_size, kLow_SkFilterQuality, CanvasColorParams(),
+ scaled_image_size, kLow_SkFilterQuality, CanvasResourceParams(),
CanvasResourceProvider::ShouldInitialize::kNo));
if (!resource_provider)
return nullptr;
diff --git a/chromium/third_party/blink/renderer/core/page/drag_image_test.cc b/chromium/third_party/blink/renderer/core/page/drag_image_test.cc
index 6a2c5d59475..22b4631e12c 100644
--- a/chromium/third_party/blink/renderer/core/page/drag_image_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/drag_image_test.cc
@@ -70,6 +70,7 @@ class TestImage : public Image {
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override {
diff --git a/chromium/third_party/blink/renderer/core/page/focus_controller.cc b/chromium/third_party/blink/renderer/core/page/focus_controller.cc
index ac108548241..5ab2e0b67f9 100644
--- a/chromium/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/focus_controller.cc
@@ -310,9 +310,6 @@ ScopedFocusNavigation ScopedFocusNavigation::OwnedByIFrame(
const HTMLFrameOwnerElement& frame,
FocusController::OwnerMap& owner_map) {
DCHECK(frame.ContentFrame());
- To<LocalFrame>(frame.ContentFrame())
- ->GetDocument()
- ->UpdateDistributionForLegacyDistributedNodes();
return ScopedFocusNavigation(
*To<LocalFrame>(frame.ContentFrame())->GetDocument(), nullptr, owner_map);
}
@@ -427,7 +424,7 @@ inline bool IsShadowHostWithoutCustomFocusLogic(const Element& element) {
inline bool IsNonKeyboardFocusableShadowHost(const Element& element) {
return IsShadowHostWithoutCustomFocusLogic(element) &&
- !(element.ShadowRootIfV1()
+ !(element.GetShadowRoot()
? (element.IsFocusable() || element.DelegatesFocus())
: element.IsKeyboardFocusable());
}
@@ -918,6 +915,7 @@ void FocusController::FocusHasChanged() {
}
NotifyFocusChangedObservers();
+ page_->GetPageScheduler()->OnFocusChanged(focused);
}
void FocusController::SetFocused(bool focused) {
@@ -1023,7 +1021,6 @@ bool FocusController::AdvanceFocusInDocumentOrder(
TRACE_EVENT0("input", "FocusController::AdvanceFocusInDocumentOrder");
DCHECK(frame);
Document* document = frame->GetDocument();
- document->UpdateDistributionForLegacyDistributedNodes();
OwnerMap owner_map;
Element* current = start;
diff --git a/chromium/third_party/blink/renderer/core/page/link_highlight.h b/chromium/third_party/blink/renderer/core/page/link_highlight.h
index 7dc64a7a640..7a3d6801749 100644
--- a/chromium/third_party/blink/renderer/core/page/link_highlight.h
+++ b/chromium/third_party/blink/renderer/core/page/link_highlight.h
@@ -16,12 +16,13 @@ class AnimationHost;
}
namespace blink {
+class CompositorAnimationTimeline;
class GraphicsContext;
-class Page;
class LinkHighlightImpl;
-class CompositorAnimationTimeline;
-class LocalFrame;
class LayoutObject;
+class LocalFrame;
+class Node;
+class Page;
class CORE_EXPORT LinkHighlight final : public GarbageCollected<LinkHighlight> {
public:
diff --git a/chromium/third_party/blink/renderer/core/page/page.cc b/chromium/third_party/blink/renderer/core/page/page.cc
index 5e42e49edce..415b2934217 100644
--- a/chromium/third_party/blink/renderer/core/page/page.cc
+++ b/chromium/third_party/blink/renderer/core/page/page.cc
@@ -38,7 +38,6 @@
#include "third_party/blink/renderer/core/dom/visited_link_state.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
-#include "third_party/blink/renderer/core/execution_context/agent_metrics_collector.h"
#include "third_party/blink/renderer/core/frame/browser_controls.h"
#include "third_party/blink/renderer/core/frame/dom_timer.h"
#include "third_party/blink/renderer/core/frame/event_handler_registry.h"
@@ -130,12 +129,6 @@ Page::PageSet& Page::OrdinaryPages() {
return *pages;
}
-static AgentMetricsCollector& GlobalAgentMetricsCollector() {
- DEFINE_STATIC_LOCAL(Persistent<AgentMetricsCollector>, metrics_collector,
- (MakeGarbageCollected<AgentMetricsCollector>()));
- return *metrics_collector;
-}
-
void Page::InsertOrdinaryPageForTesting(Page* page) {
OrdinaryPages().insert(page);
}
@@ -159,25 +152,19 @@ float DeviceScaleFactorDeprecated(LocalFrame* frame) {
return page->DeviceScaleFactorDeprecated();
}
-Page* Page::CreateNonOrdinary(PageClients& page_clients) {
- Page* page = MakeGarbageCollected<Page>(page_clients);
- std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler =
- ThreadScheduler::Current()->CreateAgentGroupScheduler();
- page->SetPageScheduler(
- agent_group_scheduler->AsAgentGroupScheduler().CreatePageScheduler(page));
- page->SetAgentGroupSchedulerForNonOrdinary(std::move(agent_group_scheduler));
- return page;
+Page* Page::CreateNonOrdinary(
+ PageClients& page_clients,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler) {
+ return MakeGarbageCollected<Page>(page_clients, agent_group_scheduler,
+ /*is_ordinary=*/false);
}
Page* Page::CreateOrdinary(
PageClients& page_clients,
Page* opener,
scheduler::WebAgentGroupScheduler& agent_group_scheduler) {
- Page* page = MakeGarbageCollected<Page>(page_clients);
- page->is_ordinary_ = true;
- page->agent_metrics_collector_ = &GlobalAgentMetricsCollector();
- page->SetPageScheduler(
- agent_group_scheduler.AsAgentGroupScheduler().CreatePageScheduler(page));
+ Page* page = MakeGarbageCollected<Page>(page_clients, agent_group_scheduler,
+ /*is_ordinary=*/true);
if (opener) {
// Before: ... -> opener -> next -> ...
@@ -195,9 +182,12 @@ Page* Page::CreateOrdinary(
return page;
}
-Page::Page(PageClients& page_clients)
+Page::Page(PageClients& page_clients,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
+ bool is_ordinary)
: SettingsDelegate(std::make_unique<Settings>()),
main_frame_(nullptr),
+ agent_group_scheduler_(agent_group_scheduler),
animator_(MakeGarbageCollected<PageAnimator>(*this)),
autoscroll_controller_(MakeGarbageCollected<AutoscrollController>(*this)),
chrome_client_(page_clients.chrome_client),
@@ -228,7 +218,7 @@ Page::Page(PageClients& page_clients)
tab_key_cycles_through_elements_(true),
device_scale_factor_(1),
lifecycle_state_(mojom::blink::PageLifecycleState::New()),
- is_ordinary_(false),
+ is_ordinary_(is_ordinary),
is_cursor_visible_(true),
subframe_count_(0),
next_related_page_(this),
@@ -244,6 +234,15 @@ Page::Page(PageClients& page_clients)
// ScrollbarTheme, if they don't this call will crash. To set a mock theme,
// see ScopedMockOverlayScrollbars or WebScopedMockScrollbars.
DCHECK(&GetScrollbarTheme());
+
+ page_scheduler_ =
+ agent_group_scheduler.AsAgentGroupScheduler().CreatePageScheduler(this);
+ // The scheduler should be set before the main frame.
+ DCHECK(!main_frame_);
+ history_navigation_virtual_time_pauser_ =
+ page_scheduler_->CreateWebScopedVirtualTimePauser(
+ "HistoryNavigation",
+ WebScopedVirtualTimePauser::VirtualTaskDuration::kInstant);
}
Page::~Page() {
@@ -376,8 +375,11 @@ void Page::PlatformColorsChanged() {
for (const Page* page : AllPages())
for (Frame* frame = page->MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
- if (auto* local_frame = DynamicTo<LocalFrame>(frame))
+ if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
local_frame->GetDocument()->PlatformColorsChanged();
+ if (LayoutView* view = local_frame->ContentLayoutObject())
+ view->InvalidatePaintForViewAndDescendants();
+ }
}
}
@@ -626,12 +628,12 @@ int Page::SubframeCount() const {
return subframe_count_;
}
-void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
+void Page::SettingsChanged(ChangeType change_type) {
switch (change_type) {
- case SettingsDelegate::kStyleChange:
+ case ChangeType::kStyle:
InitialStyleChanged();
break;
- case SettingsDelegate::kViewportDescriptionChange:
+ case ChangeType::kViewportDescription:
if (MainFrame() && MainFrame()->IsLocalFrame()) {
DeprecatedLocalMainFrame()
->GetDocument()
@@ -644,7 +646,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
TextAutosizer::UpdatePageInfoInAllFrames(MainFrame());
}
break;
- case SettingsDelegate::kViewportPaintPropertiesChange:
+ case ChangeType::kViewportPaintProperties:
GetVisualViewport().SetNeedsPaintPropertyUpdate();
GetVisualViewport().InitializeScrollbars();
if (auto* local_frame = DynamicTo<LocalFrame>(MainFrame())) {
@@ -652,14 +654,14 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
view->SetNeedsPaintPropertyUpdate();
}
break;
- case SettingsDelegate::kDNSPrefetchingChange:
+ case ChangeType::kDNSPrefetching:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
local_frame->GetDocument()->InitDNSPrefetch();
}
break;
- case SettingsDelegate::kImageLoadingChange:
+ case ChangeType::kImageLoading:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
@@ -670,14 +672,14 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
}
break;
- case SettingsDelegate::kTextAutosizingChange:
+ case ChangeType::kTextAutosizing:
if (!MainFrame())
break;
// We need to update even for remote main frames since this setting
// could be changed via InternalSettings.
TextAutosizer::UpdatePageInfoInAllFrames(MainFrame());
break;
- case SettingsDelegate::kFontFamilyChange:
+ case ChangeType::kFontFamily:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
@@ -686,10 +688,10 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
.UpdateGenericFontFamilySettings();
}
break;
- case SettingsDelegate::kAcceleratedCompositingChange:
+ case ChangeType::kAcceleratedCompositing:
UpdateAcceleratedCompositingSettings();
break;
- case SettingsDelegate::kMediaQueryChange:
+ case ChangeType::kMediaQuery:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
@@ -698,7 +700,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
}
break;
- case SettingsDelegate::kAccessibilityStateChange:
+ case ChangeType::kAccessibilityState:
if (!MainFrame() || !MainFrame()->IsLocalFrame())
break;
DeprecatedLocalMainFrame()
@@ -706,7 +708,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
->AXObjectCacheOwner()
.ClearAXObjectCache();
break;
- case SettingsDelegate::kViewportRuleChange: {
+ case ChangeType::kViewportRule: {
auto* main_local_frame = DynamicTo<LocalFrame>(MainFrame());
if (!main_local_frame)
break;
@@ -714,7 +716,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
doc->GetStyleEngine().ViewportRulesChanged();
break;
}
- case SettingsDelegate::kTextTrackKindUserPreferenceChange:
+ case ChangeType::kTextTrackKindUserPreference:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
@@ -725,7 +727,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
}
break;
- case SettingsDelegate::kDOMWorldsChange: {
+ case ChangeType::kDOMWorlds: {
if (!GetSettings().GetForceMainWorldInitialization())
break;
for (Frame* frame = MainFrame(); frame;
@@ -738,7 +740,7 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
break;
}
- case SettingsDelegate::kMediaControlsChange:
+ case ChangeType::kMediaControls:
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
auto* local_frame = DynamicTo<LocalFrame>(frame);
@@ -749,11 +751,11 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
HTMLMediaElement::OnMediaControlsEnabledChange(doc);
}
break;
- case SettingsDelegate::kPluginsChange: {
+ case ChangeType::kPlugins: {
NotifyPluginsChanged();
break;
}
- case SettingsDelegate::kHighlightAdsChange: {
+ case ChangeType::kHighlightAds: {
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
@@ -761,11 +763,11 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
break;
}
- case SettingsDelegate::kPaintChange: {
+ case ChangeType::kPaint: {
InvalidatePaint();
break;
}
- case SettingsDelegate::kScrollbarLayoutChange: {
+ case ChangeType::kScrollbarLayout: {
for (Frame* frame = MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
auto* local_frame = DynamicTo<LocalFrame>(frame);
@@ -788,16 +790,16 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
break;
}
- case SettingsDelegate::kColorSchemeChange:
+ case ChangeType::kColorScheme:
InvalidateColorScheme();
break;
- case SettingsDelegate::kSpatialNavigationChange:
+ case ChangeType::kSpatialNavigation:
if (spatial_navigation_controller_ ||
GetSettings().GetSpatialNavigationEnabled()) {
GetSpatialNavigationController().OnSpatialNavigationSettingChanged();
}
break;
- case SettingsDelegate::kUniversalAccessChange: {
+ case ChangeType::kUniversalAccess: {
if (!GetSettings().GetAllowUniversalAccessFromFileURLs())
break;
for (Frame* frame = MainFrame(); frame;
@@ -812,15 +814,11 @@ void Page::SettingsChanged(SettingsDelegate::ChangeType change_type) {
}
break;
}
- case SettingsDelegate::kVisionDeficiencyChange: {
+ case ChangeType::kVisionDeficiency: {
if (auto* main_local_frame = DynamicTo<LocalFrame>(MainFrame()))
main_local_frame->GetDocument()->VisionDeficiencyChanged();
break;
}
- case SettingsDelegate::kForceDarkChange:
- InvalidateColorScheme();
- InvalidatePaint();
- break;
}
}
@@ -932,7 +930,6 @@ void Page::Trace(Visitor* visitor) const {
visitor->Trace(main_frame_);
visitor->Trace(plugin_data_);
visitor->Trace(validation_message_client_);
- visitor->Trace(agent_metrics_collector_);
visitor->Trace(plugins_changed_observers_);
visitor->Trace(next_related_page_);
visitor->Trace(prev_related_page_);
@@ -951,12 +948,25 @@ void Page::WillCloseAnimationHost(LocalFrameView* view) {
if (scrolling_coordinator_)
scrolling_coordinator_->WillCloseAnimationHost(view);
GetLinkHighlight().WillCloseAnimationHost();
+
+ // We may have disconnected the associated LayerTreeHost during
+ // the frame lifecycle so ensure the PageAnimator is reset to the
+ // default state.
+ animator_->SetSuppressFrameRequestsWorkaroundFor704763Only(false);
}
void Page::WillBeDestroyed() {
Frame* main_frame = main_frame_;
- main_frame->Detach(FrameDetachType::kRemove);
+ // TODO(https://crbug.com/838348): Sadly, there are situations where Blink may
+ // attempt to detach a main frame twice due to a bug. That rewinds
+ // FrameLifecycle from kDetached to kDetaching, but GetPage() will already be
+ // null. Since Detach() has already happened, just skip the actual Detach()
+ // call to try to limit the side effects of this bug on the rest of frame
+ // detach.
+ if (main_frame->GetPage()) {
+ main_frame->Detach(FrameDetachType::kRemove);
+ }
DCHECK(AllPages().Contains(this));
AllPages().erase(this);
@@ -982,9 +992,6 @@ void Page::WillBeDestroyed() {
validation_message_client_->WillBeDestroyed();
main_frame_ = nullptr;
- if (agent_metrics_collector_)
- agent_metrics_collector_->ReportMetrics();
-
page_visibility_observer_set_.ForEachObserver(
[](PageVisibilityObserver* observer) {
observer->ObserverSetWillBeCleared();
@@ -992,7 +999,6 @@ void Page::WillBeDestroyed() {
page_visibility_observer_set_.Clear();
page_scheduler_ = nullptr;
- agent_group_scheduler_for_non_ordinary_ = nullptr;
}
void Page::RegisterPluginsChangedObserver(PluginsChangedObserver* observer) {
@@ -1005,24 +1011,13 @@ ScrollbarTheme& Page::GetScrollbarTheme() const {
return ScrollbarTheme::GetTheme();
}
-PageScheduler* Page::GetPageScheduler() const {
- return page_scheduler_.get();
+scheduler::WebAgentGroupScheduler& Page::GetAgentGroupScheduler() const {
+ return agent_group_scheduler_;
}
-void Page::SetAgentGroupSchedulerForNonOrdinary(
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler) {
- agent_group_scheduler_for_non_ordinary_ = std::move(agent_group_scheduler);
-}
-
-void Page::SetPageScheduler(std::unique_ptr<PageScheduler> page_scheduler) {
- page_scheduler_ = std::move(page_scheduler);
- // The scheduler should be set before the main frame.
- DCHECK(!main_frame_);
- history_navigation_virtual_time_pauser_ =
- page_scheduler_->CreateWebScopedVirtualTimePauser(
- "HistoryNavigation",
- WebScopedVirtualTimePauser::VirtualTaskDuration::kInstant);
+PageScheduler* Page::GetPageScheduler() const {
+ DCHECK(page_scheduler_);
+ return page_scheduler_.get();
}
bool Page::IsOrdinary() const {
@@ -1055,6 +1050,10 @@ bool Page::LocalMainFrameNetworkIsAlmostIdle() const {
return frame->GetIdlenessDetector()->NetworkIsAlmostIdle();
}
+bool Page::IsFocused() const {
+ return GetFocusController().IsFocused();
+}
+
void Page::AddAutoplayFlags(int32_t value) {
autoplay_flags_ |= value;
}
@@ -1084,21 +1083,21 @@ void Page::SetMediaFeatureOverride(const AtomicString& media_feature,
}
media_feature_overrides_->SetOverride(media_feature, value);
if (media_feature == "prefers-color-scheme")
- SettingsChanged(SettingsDelegate::kColorSchemeChange);
+ SettingsChanged(ChangeType::kColorScheme);
else
- SettingsChanged(SettingsDelegate::kMediaQueryChange);
+ SettingsChanged(ChangeType::kMediaQuery);
}
void Page::ClearMediaFeatureOverrides() {
media_feature_overrides_.reset();
- SettingsChanged(SettingsDelegate::kMediaQueryChange);
- SettingsChanged(SettingsDelegate::kColorSchemeChange);
+ SettingsChanged(ChangeType::kMediaQuery);
+ SettingsChanged(ChangeType::kColorScheme);
}
void Page::SetVisionDeficiency(VisionDeficiency new_vision_deficiency) {
if (new_vision_deficiency != vision_deficiency_) {
vision_deficiency_ = new_vision_deficiency;
- SettingsChanged(SettingsDelegate::kVisionDeficiencyChange);
+ SettingsChanged(ChangeType::kVisionDeficiency);
}
}
diff --git a/chromium/third_party/blink/renderer/core/page/page.h b/chromium/third_party/blink/renderer/core/page/page.h
index 65b72a9867b..d2efc89d130 100644
--- a/chromium/third_party/blink/renderer/core/page/page.h
+++ b/chromium/third_party/blink/renderer/core/page/page.h
@@ -55,7 +55,6 @@ class AnimationHost;
}
namespace blink {
-class AgentMetricsCollector;
class AutoscrollController;
class BrowserControls;
class ChromeClient;
@@ -115,7 +114,9 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
};
// Any pages not owned by a web view should be created using this method.
- static Page* CreateNonOrdinary(PageClients& pages_clients);
+ static Page* CreateNonOrdinary(
+ PageClients& pages_clients,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler);
// An "ordinary" page is a fully-featured page owned by a web view.
static Page* CreateOrdinary(
@@ -123,7 +124,9 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
Page* opener,
scheduler::WebAgentGroupScheduler& agent_group_scheduler);
- explicit Page(PageClients&);
+ Page(PageClients&,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
+ bool is_ordinary);
~Page() override;
void CloseSoon();
@@ -197,9 +200,6 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
ValidationMessageClient& GetValidationMessageClient() const {
return *validation_message_client_;
}
- AgentMetricsCollector* GetAgentMetricsCollector() const {
- return agent_metrics_collector_.Get();
- }
void SetValidationMessageClientForTesting(ValidationMessageClient*);
ScrollingCoordinator* GetScrollingCoordinator();
@@ -320,6 +320,7 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
ScrollbarTheme& GetScrollbarTheme() const;
+ scheduler::WebAgentGroupScheduler& GetAgentGroupScheduler() const;
PageScheduler* GetPageScheduler() const;
// PageScheduler::Delegate implementation.
@@ -328,6 +329,7 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
bool RequestBeginMainFrameNotExpected(bool new_state) override;
void OnSetPageFrozen(bool is_frozen) override;
bool LocalMainFrameNetworkIsAlmostIdle() const override;
+ bool IsFocused() const override;
void AddAutoplayFlags(int32_t flags);
void ClearAutoplayFlags();
@@ -395,11 +397,6 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
// Notify |plugins_changed_observers_| that plugins have changed.
void NotifyPluginsChanged() const;
- void SetAgentGroupSchedulerForNonOrdinary(
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler);
- void SetPageScheduler(std::unique_ptr<PageScheduler>);
-
void InvalidateColorScheme();
void InvalidatePaint();
// Typically, the main frame and Page should both be owned by the embedder,
@@ -416,6 +413,7 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
// longer needed.
Member<Frame> main_frame_;
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler_;
Member<PageAnimator> animator_;
const Member<AutoscrollController> autoscroll_controller_;
Member<ChromeClient> chrome_client_;
@@ -441,10 +439,6 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
Member<ValidationMessageClient> validation_message_client_;
- // Stored only for ordinary pages to avoid adding metrics from things like
- // overlays, popups and SVG.
- Member<AgentMetricsCollector> agent_metrics_collector_;
-
Deprecation deprecation_;
WebWindowFeatures window_features_;
@@ -491,12 +485,6 @@ class CORE_EXPORT Page final : public GarbageCollected<Page>,
// pages or not.
FrameScheduler::SchedulingAffectingFeatureHandle has_related_pages_;
- // A non-ordinary Page has its own AgentGroupScheduler. This field
- // needs to be declared before |page_scheduler_| to make sure it
- // outlives it.
- std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
- agent_group_scheduler_for_non_ordinary_;
-
std::unique_ptr<PageScheduler> page_scheduler_;
// Overrides for various media features, set from DevTools.
diff --git a/chromium/third_party/blink/renderer/core/page/page_animator.cc b/chromium/third_party/blink/renderer/core/page/page_animator.cc
index 72049af1b2b..91bd40f8545 100644
--- a/chromium/third_party/blink/renderer/core/page/page_animator.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_animator.cc
@@ -22,12 +22,19 @@ namespace {
typedef HeapVector<Member<Document>, 32> DocumentsVector;
+enum OnlyThrottledOrNot { OnlyNonThrottled, AllDocuments };
+
// We walk through all the frames in DOM tree order and get all the documents
-DocumentsVector GetAllDocuments(Frame* main_frame) {
+DocumentsVector GetAllDocuments(Frame* main_frame,
+ OnlyThrottledOrNot which_documents) {
DocumentsVector documents;
for (Frame* frame = main_frame; frame; frame = frame->Tree().TraverseNext()) {
- if (auto* local_frame = DynamicTo<LocalFrame>(frame))
- documents.push_back(local_frame->GetDocument());
+ if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
+ Document* document = local_frame->GetDocument();
+ if (which_documents == AllDocuments || !document->View() ||
+ !document->View()->CanThrottleRendering())
+ documents.push_back(document);
+ }
}
return documents;
}
@@ -52,16 +59,18 @@ void PageAnimator::ServiceScriptedAnimations(
Clock().SetAllowedToDynamicallyUpdateTime(false);
Clock().UpdateTime(monotonic_animation_start_time);
- DocumentsVector documents = GetAllDocuments(page_->MainFrame());
+ DocumentsVector documents =
+ GetAllDocuments(page_->MainFrame(), OnlyNonThrottled);
for (auto& document : documents) {
ScopedFrameBlamer frame_blamer(document->GetFrame());
TRACE_EVENT0("blink,rail", "PageAnimator::serviceScriptedAnimations");
- if (!document->View() || document->View()->CanThrottleRendering()) {
+ if (!document->View()) {
document->GetDocumentAnimations()
.UpdateAnimationTimingForAnimationFrame();
continue;
}
+ DCHECK(!document->View()->CanThrottleRendering());
document->View()->ServiceScriptedAnimations(monotonic_animation_start_time);
}
@@ -131,13 +140,12 @@ void PageAnimator::UpdateAllLifecyclePhases(LocalFrame& root_frame,
view->UpdateAllLifecyclePhases(reason);
}
-void PageAnimator::UpdateAllLifecyclePhasesExceptPaint(
- LocalFrame& root_frame,
- DocumentUpdateReason reason) {
+void PageAnimator::UpdateLifecycleToPrePaintClean(LocalFrame& root_frame,
+ DocumentUpdateReason reason) {
LocalFrameView* view = root_frame.View();
base::AutoReset<bool> servicing(&updating_layout_and_style_for_painting_,
true);
- view->UpdateAllLifecyclePhasesExceptPaint(reason);
+ view->UpdateLifecycleToPrePaintClean(reason);
}
void PageAnimator::UpdateLifecycleToLayoutClean(LocalFrame& root_frame,
@@ -151,7 +159,7 @@ void PageAnimator::UpdateLifecycleToLayoutClean(LocalFrame& root_frame,
HeapVector<Member<Animation>> PageAnimator::GetAnimations(
const TreeScope& tree_scope) {
HeapVector<Member<Animation>> animations;
- DocumentsVector documents = GetAllDocuments(page_->MainFrame());
+ DocumentsVector documents = GetAllDocuments(page_->MainFrame(), AllDocuments);
for (auto& document : documents) {
document->GetDocumentAnimations().GetAnimationsTargetingTreeScope(
animations, tree_scope);
diff --git a/chromium/third_party/blink/renderer/core/page/page_animator.h b/chromium/third_party/blink/renderer/core/page/page_animator.h
index efce1740466..b9e34060f97 100644
--- a/chromium/third_party/blink/renderer/core/page/page_animator.h
+++ b/chromium/third_party/blink/renderer/core/page/page_animator.h
@@ -43,8 +43,8 @@ class CORE_EXPORT PageAnimator final : public GarbageCollected<PageAnimator> {
// See documents of methods with the same names in LocalFrameView class.
void UpdateAllLifecyclePhases(LocalFrame& root_frame,
DocumentUpdateReason reason);
- void UpdateAllLifecyclePhasesExceptPaint(LocalFrame& root_frame,
- DocumentUpdateReason reason);
+ void UpdateLifecycleToPrePaintClean(LocalFrame& root_frame,
+ DocumentUpdateReason reason);
void UpdateLifecycleToLayoutClean(LocalFrame& root_frame,
DocumentUpdateReason reason);
AnimationClock& Clock() { return animation_clock_; }
diff --git a/chromium/third_party/blink/renderer/core/page/page_popup_client.cc b/chromium/third_party/blink/renderer/core/page/page_popup_client.cc
index 3f7596b0e3b..10d7130cabf 100644
--- a/chromium/third_party/blink/renderer/core/page/page_popup_client.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_popup_client.cc
@@ -166,7 +166,7 @@ void PagePopupClient::AddLocalizedProperty(const char* name,
CSSFontSelector* PagePopupClient::CreateCSSFontSelector(
Document& popup_document) {
- return MakeGarbageCollected<CSSFontSelector>(&popup_document);
+ return MakeGarbageCollected<CSSFontSelector>(popup_document);
}
PagePopupController* PagePopupClient::CreatePagePopupController(
diff --git a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
index a392e4f45b2..7276be98a13 100644
--- a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
@@ -67,7 +67,7 @@ void PageWidgetDelegate::UpdateLifecycle(Page& page,
if (requested_update == WebLifecycleUpdate::kLayout) {
page.Animator().UpdateLifecycleToLayoutClean(root, reason);
} else if (requested_update == WebLifecycleUpdate::kPrePaint) {
- page.Animator().UpdateAllLifecyclePhasesExceptPaint(root, reason);
+ page.Animator().UpdateLifecycleToPrePaintClean(root, reason);
} else {
page.Animator().UpdateAllLifecyclePhases(root, reason);
}
@@ -211,60 +211,60 @@ WebInputEventResult PageWidgetDelegate::HandleInputEvent(
// Default handlers for PageWidgetEventHandler
void PageWidgetEventHandler::HandleMouseMove(
- LocalFrame& main_frame,
+ LocalFrame& local_root,
const WebMouseEvent& event,
const std::vector<std::unique_ptr<WebInputEvent>>& coalesced_events,
const std::vector<std::unique_ptr<WebInputEvent>>& predicted_events) {
WebMouseEvent transformed_event =
- TransformWebMouseEvent(main_frame.View(), event);
- main_frame.GetEventHandler().HandleMouseMoveEvent(
+ TransformWebMouseEvent(local_root.View(), event);
+ local_root.GetEventHandler().HandleMouseMoveEvent(
transformed_event,
- TransformWebMouseEventVector(main_frame.View(), coalesced_events),
- TransformWebMouseEventVector(main_frame.View(), predicted_events));
+ TransformWebMouseEventVector(local_root.View(), coalesced_events),
+ TransformWebMouseEventVector(local_root.View(), predicted_events));
}
-void PageWidgetEventHandler::HandleMouseLeave(LocalFrame& main_frame,
+void PageWidgetEventHandler::HandleMouseLeave(LocalFrame& local_root,
const WebMouseEvent& event) {
WebMouseEvent transformed_event =
- TransformWebMouseEvent(main_frame.View(), event);
- main_frame.GetEventHandler().HandleMouseLeaveEvent(transformed_event);
+ TransformWebMouseEvent(local_root.View(), event);
+ local_root.GetEventHandler().HandleMouseLeaveEvent(transformed_event);
}
-void PageWidgetEventHandler::HandleMouseDown(LocalFrame& main_frame,
+void PageWidgetEventHandler::HandleMouseDown(LocalFrame& local_root,
const WebMouseEvent& event) {
WebMouseEvent transformed_event =
- TransformWebMouseEvent(main_frame.View(), event);
- main_frame.GetEventHandler().HandleMousePressEvent(transformed_event);
+ TransformWebMouseEvent(local_root.View(), event);
+ local_root.GetEventHandler().HandleMousePressEvent(transformed_event);
}
WebInputEventResult PageWidgetEventHandler::HandleMouseUp(
- LocalFrame& main_frame,
+ LocalFrame& local_root,
const WebMouseEvent& event) {
WebMouseEvent transformed_event =
- TransformWebMouseEvent(main_frame.View(), event);
- return main_frame.GetEventHandler().HandleMouseReleaseEvent(
+ TransformWebMouseEvent(local_root.View(), event);
+ return local_root.GetEventHandler().HandleMouseReleaseEvent(
transformed_event);
}
WebInputEventResult PageWidgetEventHandler::HandleMouseWheel(
- LocalFrame& frame,
+ LocalFrame& local_root,
const WebMouseWheelEvent& event) {
WebMouseWheelEvent transformed_event =
- TransformWebMouseWheelEvent(frame.View(), event);
- return frame.GetEventHandler().HandleWheelEvent(transformed_event);
+ TransformWebMouseWheelEvent(local_root.View(), event);
+ return local_root.GetEventHandler().HandleWheelEvent(transformed_event);
}
WebInputEventResult PageWidgetEventHandler::HandlePointerEvent(
- LocalFrame& main_frame,
+ LocalFrame& local_root,
const WebPointerEvent& event,
const std::vector<std::unique_ptr<WebInputEvent>>& coalesced_events,
const std::vector<std::unique_ptr<WebInputEvent>>& predicted_events) {
WebPointerEvent transformed_event =
- TransformWebPointerEvent(main_frame.View(), event);
- return main_frame.GetEventHandler().HandlePointerEvent(
+ TransformWebPointerEvent(local_root.View(), event);
+ return local_root.GetEventHandler().HandlePointerEvent(
transformed_event,
- TransformWebPointerEventVector(main_frame.View(), coalesced_events),
- TransformWebPointerEventVector(main_frame.View(), predicted_events));
+ TransformWebPointerEventVector(local_root.View(), coalesced_events),
+ TransformWebPointerEventVector(local_root.View(), predicted_events));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
index d93ad4304cd..bb682f761d2 100644
--- a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
+++ b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.h
@@ -53,11 +53,11 @@ class CORE_EXPORT PageWidgetEventHandler {
const WebMouseEvent&,
const std::vector<std::unique_ptr<WebInputEvent>>&,
const std::vector<std::unique_ptr<WebInputEvent>>&);
- virtual void HandleMouseLeave(LocalFrame& main_frame, const WebMouseEvent&);
- virtual void HandleMouseDown(LocalFrame& main_frame, const WebMouseEvent&);
- virtual WebInputEventResult HandleMouseUp(LocalFrame& main_frame,
+ virtual void HandleMouseLeave(LocalFrame& local_root, const WebMouseEvent&);
+ virtual void HandleMouseDown(LocalFrame& local_root, const WebMouseEvent&);
+ virtual WebInputEventResult HandleMouseUp(LocalFrame& local_root,
const WebMouseEvent&);
- virtual WebInputEventResult HandleMouseWheel(LocalFrame& main_frame,
+ virtual WebInputEventResult HandleMouseWheel(LocalFrame& local_root,
const WebMouseWheelEvent&);
virtual WebInputEventResult HandleKeyEvent(const WebKeyboardEvent&) = 0;
virtual WebInputEventResult HandleCharEvent(const WebKeyboardEvent&) = 0;
diff --git a/chromium/third_party/blink/renderer/core/page/plugin_data_test.cc b/chromium/third_party/blink/renderer/core/page/plugin_data_test.cc
index 9114eac609a..9704a0fbf1a 100644
--- a/chromium/third_party/blink/renderer/core/page/plugin_data_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/plugin_data_test.cc
@@ -39,7 +39,6 @@ TEST(PluginDataTest, NonStandardUrlSchemeRequestsPluginsWithUniqueOrigin) {
// Create a scheme that's local but nonstandard, as in bug 862282.
url::ScopedSchemeRegistryForTests scoped_registry;
url::AddLocalScheme("nonstandard-862282");
- SchemeRegistry::RegisterURLSchemeAsLocal("nonstandard-862282");
MockPluginRegistry mock_plugin_registry;
mojo::Receiver<mojom::blink::PluginRegistry> registry_receiver(
diff --git a/chromium/third_party/blink/renderer/core/page/print_context_test.cc b/chromium/third_party/blink/renderer/core/page/print_context_test.cc
index b3f03281fc8..a74225b5425 100644
--- a/chromium/third_party/blink/renderer/core/page/print_context_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/print_context_test.cc
@@ -75,12 +75,17 @@ class MockPageContextCanvas : public SkCanvas {
void(const SkPicture*, const SkMatrix*, const SkPaint*));
MOCK_METHOD3(DrawPicture,
void(const SkPicture*, const SkMatrix*, const SkPaint*));
- MOCK_METHOD4(onDrawImage,
- void(const SkImage*, SkScalar, SkScalar, const SkPaint*));
- MOCK_METHOD5(onDrawImageRect,
+ MOCK_METHOD5(onDrawImage2,
void(const SkImage*,
- const SkRect*,
+ SkScalar,
+ SkScalar,
+ const SkSamplingOptions&,
+ const SkPaint*));
+ MOCK_METHOD6(onDrawImageRect2,
+ void(const SkImage*,
+ const SkRect&,
const SkRect&,
+ const SkSamplingOptions&,
const SkPaint*,
SrcRectConstraint));
@@ -119,8 +124,7 @@ class PrintContextTest : public PaintTestConfigurations, public RenderingTest {
GraphicsContext& context = builder.Context();
context.SetPrinting(true);
GetDocument().View()->PaintContentsOutsideOfLifecycle(
- context, kGlobalPaintPrinting | kGlobalPaintAddUrlMetadata,
- CullRect(page_rect));
+ context, kGlobalPaintAddUrlMetadata, CullRect(page_rect));
{
DrawingRecorder recorder(
context, *GetDocument().GetLayoutView(),
@@ -489,7 +493,7 @@ TEST_P(PrintContextTest, Canvas2DPixelated) {
"});");
GetDocument().body()->AppendChild(script_element);
- EXPECT_CALL(canvas, onDrawImageRect(_, _, _, _, _));
+ EXPECT_CALL(canvas, onDrawImageRect2(_, _, _, _, _, _));
PrintSinglePage(canvas);
}
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
index 89dd85a96ce..65c9a1b4a55 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#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/editing/frame_selection.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
@@ -174,11 +175,27 @@ void ElementFragmentAnchor::ApplyFocusIfNeeded() {
if (!anchor_node_)
return;
+ frame_->GetDocument()->UpdateStyleAndLayoutTree();
+
+ // If caret browsing is enabled, move the caret to the beginning of the
+ // fragment, or to the first non-inert position after it.
+ if (frame_->IsCaretBrowsingEnabled()) {
+ const Position& pos = Position::FirstPositionInOrBeforeNode(*anchor_node_);
+ if (pos.IsConnected()) {
+ frame_->Selection().SetSelection(
+ SelectionInDOMTree::Builder().Collapse(pos).Build(),
+ SetSelectionOptions::Builder()
+ .SetShouldCloseTyping(true)
+ .SetShouldClearTypingStyle(true)
+ .SetDoNotSetFocus(true)
+ .Build());
+ }
+ }
+
// If the anchor accepts keyboard focus and fragment scrolling is allowed,
// move focus there to aid users relying on keyboard navigation.
// If anchorNode is not focusable or fragment scrolling is not allowed,
// clear focus, which matches the behavior of other browsers.
- frame_->GetDocument()->UpdateStyleAndLayoutTree();
auto* element = DynamicTo<Element>(anchor_node_.Get());
if (element && element->IsFocusable()) {
element->focus();
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h
index ae6cdfeceb0..7f199925e95 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h
@@ -14,6 +14,7 @@ namespace blink {
class LocalFrame;
class KURL;
+class Node;
// An element fragment anchor is a FragmentAnchor based on a single element.
// This is the traditional fragment anchor of the web. For example, the fragment
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
index 82e8b75b5d0..0825e6b80be 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
@@ -192,7 +192,7 @@ TEST_F(MainThreadScrollingReasonsTest,
}
// Upon resizing the content size, the main thread scrolling reason
-// kHasNonLayerViewportConstrainedObject should be updated on all frames
+// kHasBackgroundAttachmentFixedObjects should be updated on all frames
TEST_F(MainThreadScrollingReasonsTest,
RecalculateMainThreadScrollingReasonsUponResize) {
GetWebView()->GetSettings()->SetPreferCompositingToLCDTextEnabled(false);
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
index dd5e111aa24..adb661f2c88 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h
@@ -13,6 +13,7 @@ namespace blink {
class Document;
class Element;
class HTMLFrameOwnerElement;
+class Node;
// Manages the root scroller associated with a given document. The root
// scroller causes browser controls movement, overscroll effects and prevents
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index 9c38f45e5e5..e7cf4856b41 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -19,7 +19,7 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
@@ -66,18 +66,11 @@ class RootScrollerTest : public testing::Test,
url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
}
- WebViewImpl* Initialize(const String& page_name,
- frame_test_helpers::TestWebWidgetClient* client) {
- return InitializeInternal(base_url_ + page_name, client);
- }
-
WebViewImpl* Initialize(const String& page_name) {
- return InitializeInternal(base_url_ + page_name, nullptr);
+ return InitializeInternal(base_url_ + page_name);
}
- WebViewImpl* Initialize() {
- return InitializeInternal("about:blank", nullptr);
- }
+ WebViewImpl* Initialize() { return InitializeInternal("about:blank"); }
static void ConfigureSettings(WebSettings* settings) {
settings->SetJavaScriptEnabled(true);
@@ -107,7 +100,7 @@ class RootScrollerTest : public testing::Test,
RunPendingTasks();
}
- WebViewImpl* GetWebView() const { return helper_.GetWebView(); }
+ WebViewImpl* GetWebView() const { return helper_->GetWebView(); }
Page& GetPage() const { return *GetWebView()->GetPage(); }
@@ -152,6 +145,12 @@ class RootScrollerTest : public testing::Test,
delta_y);
}
+ void SetCreateWebFrameWidgetCallback(
+ const frame_test_helpers::CreateTestWebFrameWidgetCallback&
+ create_widget_callback) {
+ create_widget_callback_ = create_widget_callback;
+ }
+
protected:
WebCoalescedInputEvent GenerateGestureEvent(WebInputEvent::Type type,
WebGestureDevice device,
@@ -170,11 +169,12 @@ class RootScrollerTest : public testing::Test,
return WebCoalescedInputEvent(event, ui::LatencyInfo());
}
- WebViewImpl* InitializeInternal(
- const String& url,
- frame_test_helpers::TestWebWidgetClient* client) {
- helper_.InitializeAndLoad(url.Utf8(), nullptr, nullptr, client,
- &ConfigureSettings);
+ WebViewImpl* InitializeInternal(const String& url) {
+ helper_ = std::make_unique<frame_test_helpers::WebViewHelper>(
+ create_widget_callback_);
+
+ helper_->InitializeAndLoad(url.Utf8(), nullptr, nullptr,
+ &ConfigureSettings);
// Initialize browser controls to be shown.
GetWebView()->ResizeWithBrowserControls(gfx::Size(400, 400), 50, 60, true);
@@ -190,8 +190,9 @@ class RootScrollerTest : public testing::Test,
}
String base_url_;
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback_;
std::unique_ptr<frame_test_helpers::TestWebViewClient> view_client_;
- frame_test_helpers::WebViewHelper helper_;
+ std::unique_ptr<frame_test_helpers::WebViewHelper> helper_;
RuntimeEnabledFeatures::Backup features_backup_;
};
@@ -244,9 +245,14 @@ class OverscrollWidgetInputHandlerHost
}
};
-class OverscrollTestWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
+class OverscrollTestWebFrameWidget
+ : public frame_test_helpers::TestWebFrameWidget {
public:
+ template <typename... Args>
+ explicit OverscrollTestWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {}
+
+ // frame_test_helpers::TestWebFrameWidget overrides.
frame_test_helpers::TestWidgetInputHandlerHost* GetInputHandlerHost()
override {
return &input_handler_host_;
@@ -263,8 +269,10 @@ class OverscrollTestWebWidgetClient
// Tests that setting an element as the root scroller causes it to control url
// bar hiding and overscroll.
TEST_F(RootScrollerTest, TestSetRootScroller) {
- OverscrollTestWebWidgetClient client;
- Initialize("root-scroller.html", &client);
+ SetCreateWebFrameWidgetCallback(base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ OverscrollTestWebFrameWidget>));
+ Initialize("root-scroller.html");
UpdateAllLifecyclePhases(MainFrameView());
Element* container = MainFrame()->GetDocument()->getElementById("container");
@@ -274,15 +282,17 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
// makes it 400x450 so max scroll is 550px.
double maximum_scroll = 550;
- GetWebView()->MainFrameWidget()->HandleInputEvent(
- GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollBegin));
+ OverscrollTestWebFrameWidget* widget =
+ static_cast<OverscrollTestWebFrameWidget*>(helper_->GetMainFrameWidget());
+ widget->HandleInputEvent(
+ GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollBegin));
{
// Scrolling over the #container DIV should cause the browser controls to
// hide.
EXPECT_FLOAT_EQ(1, GetBrowserControls().TopShownRatio());
EXPECT_FLOAT_EQ(1, GetBrowserControls().BottomShownRatio());
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, 0,
-GetBrowserControls().TopHeight()));
EXPECT_FLOAT_EQ(0, GetBrowserControls().TopShownRatio());
@@ -291,7 +301,7 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
{
// Make sure we're actually scrolling the DIV and not the LocalFrameView.
- GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
+ widget->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::Type::kGestureScrollUpdate, 0, -100));
EXPECT_FLOAT_EQ(100, container->scrollTop());
EXPECT_FLOAT_EQ(
@@ -301,65 +311,65 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
{
// Scroll 50 pixels past the end. Ensure we report the 50 pixels as
// overscroll.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 50), gfx::Vector2dF(0, 50),
gfx::PointF(100, 100), gfx::Vector2dF(),
cc::OverscrollBehavior()));
- GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
+ widget->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::Type::kGestureScrollUpdate, 0, -500));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
0, MainFrameView()->LayoutViewport()->GetScrollOffset().Height());
RunPendingTasks();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
{
// Continue the gesture overscroll.
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 20), gfx::Vector2dF(0, 70),
gfx::PointF(100, 100), gfx::Vector2dF(),
cc::OverscrollBehavior()));
- GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
+ widget->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::Type::kGestureScrollUpdate, 0, -20));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
0, MainFrameView()->LayoutViewport()->GetScrollOffset().Height());
RunPendingTasks();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
}
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollEnd));
{
// Make sure a new gesture scroll still won't scroll the frameview and
// overscrolls.
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollBegin));
- EXPECT_CALL(client.GetOverscrollWidgetInputHandlerHost(),
+ EXPECT_CALL(widget->GetOverscrollWidgetInputHandlerHost(),
DidOverscroll(gfx::Vector2dF(0, 30), gfx::Vector2dF(0, 30),
gfx::PointF(100, 100), gfx::Vector2dF(),
cc::OverscrollBehavior()));
- GetWebView()->MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
+ widget->HandleInputEvent(GenerateTouchGestureEvent(
WebInputEvent::Type::kGestureScrollUpdate, 0, -30));
EXPECT_FLOAT_EQ(maximum_scroll, container->scrollTop());
EXPECT_FLOAT_EQ(
0, MainFrameView()->LayoutViewport()->GetScrollOffset().Height());
RunPendingTasks();
Mock::VerifyAndClearExpectations(
- &client.GetOverscrollWidgetInputHandlerHost());
+ &widget->GetOverscrollWidgetInputHandlerHost());
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollEnd));
}
{
// Scrolling up should show the browser controls.
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollBegin));
EXPECT_FLOAT_EQ(0, GetBrowserControls().TopShownRatio());
@@ -369,12 +379,12 @@ TEST_F(RootScrollerTest, TestSetRootScroller) {
EXPECT_FLOAT_EQ(0.6, GetBrowserControls().TopShownRatio());
EXPECT_FLOAT_EQ(0.6, GetBrowserControls().BottomShownRatio());
- GetWebView()->MainFrameWidget()->HandleInputEvent(
+ widget->HandleInputEvent(
GenerateTouchGestureEvent(WebInputEvent::Type::kGestureScrollEnd));
}
// Reset manually to avoid lifetime issues with custom WebViewClient.
- helper_.Reset();
+ helper_->Reset();
}
// Tests that removing the element that is the root scroller from the DOM tree
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
index 7d989eef555..5b0c3dc1eb9 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_into_view_test.cc
@@ -175,7 +175,11 @@ TEST_F(ScrollIntoViewTest, SmoothScroll) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
// Finish scrolling the container
Compositor().BeginFrame(1);
@@ -211,7 +215,11 @@ TEST_F(ScrollIntoViewTest, NestedContainer) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
ASSERT_EQ(container->scrollTop(), 0);
// Finish scrolling the outer container
@@ -222,7 +230,11 @@ TEST_F(ScrollIntoViewTest, NestedContainer) {
// Scrolling the inner container
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(container->scrollTop(), 299, 1);
+ ASSERT_NEAR(
+ container->scrollTop(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 794
+ : 299),
+ 1);
// Finish scrolling the inner container
Compositor().BeginFrame(1);
@@ -265,14 +277,22 @@ TEST_F(ScrollIntoViewTest, NewScrollIntoViewAbortsCurrentAnimation) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
ASSERT_EQ(container1->scrollTop(), 0);
content2->scrollIntoView(arg);
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 61, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 171
+ : 61),
+ 1);
ASSERT_EQ(container1->scrollTop(), 0); // container1 should not scroll.
Compositor().BeginFrame(1);
@@ -282,7 +302,11 @@ TEST_F(ScrollIntoViewTest, NewScrollIntoViewAbortsCurrentAnimation) {
// Scrolling content2 in container2
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(container2->scrollTop(), 300, 1);
+ ASSERT_NEAR(
+ container2->scrollTop(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 952
+ : 300),
+ 1);
// Finish all the animation to make sure there is no another animation queued
// on container1.
@@ -324,7 +348,11 @@ TEST_F(ScrollIntoViewTest, ScrollWindowAbortsCurrentAnimation) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
ASSERT_EQ(container->scrollTop(), 0);
ScrollToOptions* window_option = ScrollToOptions::Create();
@@ -335,7 +363,11 @@ TEST_F(ScrollIntoViewTest, ScrollWindowAbortsCurrentAnimation) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 58, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 165
+ : 58),
+ 1);
Compositor().BeginFrame(1);
ASSERT_EQ(Window().scrollY(), 0);
@@ -439,7 +471,11 @@ TEST_F(ScrollIntoViewTest, SmoothAndInstantInChain) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(container->scrollTop(), 299, 1);
+ ASSERT_NEAR(
+ container->scrollTop(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 794
+ : 299),
+ 1);
// Finish scrolling the container
Compositor().BeginFrame(1);
@@ -472,7 +508,11 @@ TEST_F(ScrollIntoViewTest, SmoothScrollAnchor) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(container->scrollTop(), 299, 1);
+ ASSERT_NEAR(
+ container->scrollTop(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 794
+ : 299),
+ 1);
// Finish scrolling the container
Compositor().BeginFrame(1);
@@ -525,7 +565,11 @@ TEST_F(ScrollIntoViewTest, ApplyRootElementScrollBehaviorToViewport) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
// Finish scrolling the container
Compositor().BeginFrame(1);
@@ -696,7 +740,11 @@ TEST_F(ScrollIntoViewTest, SmoothUserScrollNotAbortedByProgrammaticScrolls) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 299, 1);
+ ASSERT_NEAR(
+ Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 800
+ : 299),
+ 1);
// ProgrammaticScroll that could interrupt the current smooth scroll.
Window().scrollTo(0, 0);
@@ -731,7 +779,11 @@ TEST_F(ScrollIntoViewTest, LongDistanceSmoothScrollFinishedInThreeSeconds) {
Compositor().BeginFrame(); // update run_state_.
Compositor().BeginFrame(); // Set start_time = now.
Compositor().BeginFrame(0.2);
- ASSERT_NEAR(Window().scrollY(), 16971, 1);
+ ASSERT_NEAR(Window().scrollY(),
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations)
+ ? 79389
+ : 16971),
+ 1);
// Finish scrolling the container
Compositor().BeginFrame(0.5);
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
index d4499f08644..27d39c35f27 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
@@ -90,12 +90,10 @@ class ScrollEndEventBuilder : public WebGestureEvent {
int NonCompositedMainThreadScrollingReasonRecordTest::GetBucketIndex(
uint32_t reason) {
- int index = 1;
- while (!(reason & 1)) {
- reason >>= 1;
+ int index = 0;
+ while (reason >>= 1)
++index;
- }
- DCHECK_EQ(reason, 1u);
+ DCHECK_NE(index, 0);
return index;
}
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index 4b0c31e1f4f..b4bb407c7f5 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -143,7 +143,7 @@ static void DetachScrollbarLayerFromGraphicsLayer(
GraphicsLayer* scrollbar_graphics_layer) {
DCHECK(scrollbar_graphics_layer);
- scrollbar_graphics_layer->SetContentsToCcLayer(nullptr, false);
+ scrollbar_graphics_layer->SetContentsToCcLayer(nullptr);
scrollbar_graphics_layer->SetDrawsContent(true);
scrollbar_graphics_layer->SetHitTestable(true);
}
@@ -159,9 +159,7 @@ static void SetupScrollbarLayer(GraphicsLayer* scrollbar_graphics_layer,
}
scrollbar_layer->SetScrollElementId(scrolling_layer->element_id());
- scrollbar_graphics_layer->SetContentsToCcLayer(
- scrollbar_layer,
- /*prevent_contents_opaque_changes=*/false);
+ scrollbar_graphics_layer->SetContentsToCcLayer(scrollbar_layer);
scrollbar_graphics_layer->SetDrawsContent(false);
scrollbar_graphics_layer->SetHitTestable(false);
}
@@ -215,16 +213,18 @@ void ScrollingCoordinator::ScrollableAreaScrollbarLayerDidChange(
cc::ScrollbarLayerBase::CreateOrReuse(std::move(scrollbar_delegate),
scrollbar_layer);
new_scrollbar_layer->SetElementId(scrollbar.GetElementId());
+ // Root layer non-overlay scrollbars should be marked opaque to disable
+ // blending.
+ // TODO(paint-dev): Opaqueness should be determined by the scrollbar,
+ // regardless of whether it's for the main frame root scroller.
+ bool contents_opaque =
+ IsForMainFrame(scrollable_area) && !scrollbar.IsOverlayScrollbar();
+ new_scrollbar_layer->SetContentsOpaque(contents_opaque);
SetupScrollbarLayer(scrollbar_graphics_layer, new_scrollbar_layer.get(),
scrollable_area->LayerForScrolling());
SetScrollbarLayer(scrollable_area, orientation,
std::move(new_scrollbar_layer));
-
- // Root layer non-overlay scrollbars should be marked opaque to disable
- // blending.
- bool is_opaque_scrollbar = !scrollbar.IsOverlayScrollbar();
- scrollbar_graphics_layer->SetContentsOpaque(
- IsForMainFrame(scrollable_area) && is_opaque_scrollbar);
+ scrollbar_graphics_layer->CcLayer().SetContentsOpaque(contents_opaque);
} else {
RemoveScrollbarLayer(scrollable_area, orientation);
}
@@ -289,8 +289,7 @@ void ScrollingCoordinator::ScrollableAreaScrollLayerDidChange(
}
}
- scrollable_area->LayerForScrollingDidChange(
- scrollable_area->GetCompositorAnimationTimeline());
+ scrollable_area->MainThreadScrollingDidChange();
}
void ScrollingCoordinator::Reset(LocalFrame* frame) {
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
index 0219026b2f6..8d90be489a7 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -34,7 +34,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_cache.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view_client.h"
@@ -48,7 +47,6 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_object_element.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
@@ -80,7 +78,7 @@ namespace blink {
class ScrollingTest : public testing::Test, public PaintTestConfigurations {
public:
ScrollingTest() : base_url_("http://www.test.com/") {
- helper_.Initialize(nullptr, nullptr, nullptr, &ConfigureSettings);
+ helper_.Initialize(nullptr, nullptr, &ConfigureSettings);
GetWebView()->MainFrameViewWidget()->Resize(gfx::Size(320, 240));
GetWebView()->MainFrameViewWidget()->UpdateAllLifecyclePhases(
DocumentUpdateReason::kTest);
@@ -114,8 +112,9 @@ class ScrollingTest : public testing::Test, public PaintTestConfigurations {
WebViewImpl* GetWebView() const { return helper_.GetWebView(); }
LocalFrame* GetFrame() const { return helper_.LocalMainFrame()->GetFrame(); }
- frame_test_helpers::TestWebWidgetClient* GetWidgetClient() const {
- return helper_.GetWebWidgetClient();
+
+ frame_test_helpers::TestWebFrameWidget* GetMainFrameWidget() const {
+ return helper_.GetMainFrameWidget();
}
PaintLayerScrollableArea* ScrollableAreaByDOMElementId(
@@ -479,7 +478,7 @@ TEST_P(ScrollingTest, scrollEventHandler) {
NavigateTo(base_url_ + "scroll-event-handler.html");
ForceFullCompositingUpdate();
- ASSERT_TRUE(GetWidgetClient()->HaveScrollEventHandlers());
+ ASSERT_TRUE(GetMainFrameWidget()->HaveScrollEventHandlers());
}
TEST_P(ScrollingTest, updateEventHandlersDuringTeardown) {
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
index ad820ba06cc..bbf710d1038 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
@@ -105,11 +105,12 @@ bool TextFragmentAnchor::GenerateNewToken(const DocumentLoader& loader) {
}
// A new permission to invoke should only be granted if the navigation had a
- // user gesture attached to it. Browser initiated navigations (e.g. typed
- // address in the omnibox) don't carry the |had_transient_activation_| bit so
- // we have to check that separately but we consider that user initiated as
- // well.
- return loader.HadTransientActivation() || loader.IsBrowserInitiated();
+ // transient user activation attached to it. Browser initiated navigations
+ // (e.g. typed address in the omnibox) don't carry the transient user
+ // activation bit so we have to check that separately but we consider that
+ // user initiated as well.
+ return loader.LastNavigationHadTransientUserActivation() ||
+ loader.IsBrowserInitiated();
}
// static
@@ -192,8 +193,11 @@ TextFragmentAnchor::TextFragmentAnchor(
frame.GetDocument()->GetFragmentDirective().length());
text_fragment_finders_.ReserveCapacity(text_fragment_selectors.size());
- for (TextFragmentSelector selector : text_fragment_selectors)
- text_fragment_finders_.emplace_back(*this, selector);
+ for (TextFragmentSelector selector : text_fragment_selectors) {
+ text_fragment_finders_.push_back(MakeGarbageCollected<TextFragmentFinder>(
+ *this, selector, frame_->GetDocument(),
+ TextFragmentFinder::FindBufferRunnerType::kSynchronous));
+ }
}
bool TextFragmentAnchor::Invoke() {
@@ -259,7 +263,7 @@ bool TextFragmentAnchor::Invoke() {
metrics_->ResetMatchCount();
for (auto& finder : text_fragment_finders_)
- finder.FindMatch(*frame_->GetDocument());
+ finder->FindMatch();
}
if (beforematch_state_ != kEventQueued)
@@ -308,6 +312,7 @@ void TextFragmentAnchor::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(element_fragment_anchor_);
visitor->Trace(metrics_);
+ visitor->Trace(text_fragment_finders_);
FragmentAnchor::Trace(visitor);
}
@@ -378,7 +383,6 @@ void TextFragmentAnchor::DidFindMatch(
did_find_match_ = true;
if (first_match_needs_scroll_) {
- metrics_->SetSearchEngineSource(HasSearchEngineSource());
first_match_needs_scroll_ = false;
PhysicalRect bounding_box(ComputeTextRect(range));
@@ -435,6 +439,7 @@ void TextFragmentAnchor::DidFinishSearch() {
DCHECK(!search_finished_);
search_finished_ = true;
+ metrics_->SetSearchEngineSource(HasSearchEngineSource());
metrics_->ReportMetrics();
if (!did_find_match_) {
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
index ee4d075662c..4ffc0281d75 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
@@ -97,7 +97,7 @@ class CORE_EXPORT TextFragmentAnchor final : public FragmentAnchor,
bool HasSearchEngineSource();
- Vector<TextFragmentFinder> text_fragment_finders_;
+ HeapVector<Member<TextFragmentFinder>> text_fragment_finders_;
Member<LocalFrame> frame_;
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
index c969660cef0..f8fe22470f3 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
@@ -159,6 +159,10 @@ void TextFragmentAnchorMetrics::ReportMetrics() {
TRACE_EVENT_SCOPE_THREAD, "end_text_length",
match.selector.End().length());
+ base::UmaHistogramBoolean(
+ base::StrCat({uma_prefix, "SpansMultipleBlocks"}),
+ match.spans_multiple_blocks);
+
// We only record ListItemMatch and TableCellMatch for exact matches
DCHECK(!match.is_list_item && !match.is_table_cell);
}
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
index 18117f01b78..b6f8d7c6900 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
@@ -24,6 +24,7 @@ class CORE_EXPORT TextFragmentAnchorMetrics final
TextFragmentSelector selector;
bool is_list_item = false;
bool is_table_cell = false;
+ bool spans_multiple_blocks = false;
};
// An enum to indicate which parameters were specified in the text fragment.
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
index e4ca4493575..f1300e5bfb9 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
@@ -63,11 +64,12 @@ class TextFragmentAnchorMetricsTest : public SimTest {
}
protected:
- HistogramTester histogram_tester_;
+ ukm::TestUkmRecorder* ukm_recorder() {
+ return scoped_fake_ukm_recorder_.recorder();
+ }
- // TODO(crbug.com/1153990): Find a better mocking solution and clean up this
- // variable.
- std::unique_ptr<ukm::UkmRecorder> old_ukm_recorder_;
+ HistogramTester histogram_tester_;
+ ScopedFakeUkmRecorder scoped_fake_ukm_recorder_;
};
// Test UMA metrics collection
@@ -264,8 +266,9 @@ TEST_F(TextFragmentAnchorMetricsTest, UMAMetricsCollectedSearchEngineReferrer) {
1);
}
-// Test UMA metrics collection when there is no match found
-TEST_F(TextFragmentAnchorMetricsTest, NoMatchFound) {
+// Test UMA metrics collection when there is no match found with an unknown
+// referrer.
+TEST_F(TextFragmentAnchorMetricsTest, NoMatchFoundWithUnknownSource) {
SimRequest request("https://example.com/test.html#:~:text=cat", "text/html");
LoadURL("https://example.com/test.html#:~:text=cat");
request.Complete(R"HTML(
@@ -344,6 +347,93 @@ TEST_F(TextFragmentAnchorMetricsTest, NoMatchFound) {
1);
}
+// Test UMA metrics collection when there is no match found with a Search Engine
+// referrer.
+TEST_F(TextFragmentAnchorMetricsTest, NoMatchFoundWithSearchEngineSource) {
+ // Set the referrer to a known search engine URL. This should cause metrics
+ // to be reported for the SearchEngine variant of histograms.
+ SimRequest::Params params;
+ params.referrer = "https://www.bing.com";
+ SimRequest request("https://example.com/test.html#:~:text=cat", "text/html",
+ params);
+ LoadURL("https://example.com/test.html#:~:text=cat");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ height: 1200px;
+ }
+ p {
+ position: absolute;
+ top: 1000px;
+ }
+ </style>
+ <p>This is a test page</p>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ // Render two frames to handle the async step added by the beforematch event.
+ Compositor().BeginFrame();
+ BeginEmptyFrame();
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.SelectorCount", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.SearchEngine.SelectorCount", 1, 1);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.MatchRate", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.SearchEngine.MatchRate", 0, 1);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.AmbiguousMatch", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.SearchEngine.AmbiguousMatch", 0, 1);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.ScrollCancelled", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.SearchEngine.ScrollCancelled", 0, 1);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.DidScrollIntoView", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.TimeToScrollIntoView", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.DirectiveLength", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.SearchEngine.DirectiveLength", 8, 1);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.ExactTextLength", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.RangeMatchLength", 0);
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.StartTextLength", 0);
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.EndTextLength", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.Parameters", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.TimeToScrollToTop", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.ListItemMatch", 0);
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.SearchEngine.TableCellMatch", 0);
+
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.LinkOpenSource", 1);
+ histogram_tester_.ExpectUniqueSample("TextFragmentAnchor.LinkOpenSource", 1,
+ 1);
+}
+
// Test that we don't collect any metrics when there is no text directive
TEST_F(TextFragmentAnchorMetricsTest, NoTextFragmentAnchor) {
SimRequest request("https://example.com/test.html", "text/html");
@@ -1468,6 +1558,79 @@ TEST_P(TextFragmentRelatedMetricTest, TextFragmentActivationDoesNotCountAPI) {
WebFeature::kV8Document_FragmentDirective_AttributeGetter));
}
+// Test recording of the SpansMultipleBlocks metric. Records true because the
+// range crosses an intervening block element.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocksInterveningBlock) {
+ SimRequest request("https://example.com/test.html#:~:text=start,end",
+ "text/html");
+ LoadURL("https://example.com/test.html#:~:text=start,end");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div>
+ start of text
+ <div>block</div>
+ text end
+ </div>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ BeginEmptyFrame();
+ BeginEmptyFrame();
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1, 1);
+}
+
+// Test recording of the SpansMultipleBlocks metric. Records true because the
+// range start and end are in different block elements.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocks) {
+ SimRequest request("https://example.com/test.html#:~:text=start,end",
+ "text/html");
+ LoadURL("https://example.com/test.html#:~:text=start,end");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div>
+ <div>start of text</div>
+ text end
+ </div>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ BeginEmptyFrame();
+ BeginEmptyFrame();
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1, 1);
+}
+
+// Test recording of the SpansMultipleBlocks metric. Records false because the
+// range start and end are in the same block element with no intervening block.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocksSingleBlock) {
+ SimRequest request("https://example.com/test.html#:~:text=start,end",
+ "text/html");
+ LoadURL("https://example.com/test.html#:~:text=start,end");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div>
+ start of <i>text</i>
+ text end
+ </div>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ BeginEmptyFrame();
+ BeginEmptyFrame();
+
+ histogram_tester_.ExpectTotalCount(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+ histogram_tester_.ExpectUniqueSample(
+ "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 0, 1);
+}
+
// Tests that a LinkOpened UKM Event is recorded upon a successful fragment
// highlight.
TEST_F(TextFragmentAnchorMetricsTest, LinkOpenedSuccessUKM) {
@@ -1489,26 +1652,21 @@ TEST_F(TextFragmentAnchorMetricsTest, LinkOpenedSuccessUKM) {
)HTML");
RunAsyncMatchingTasks();
- // Stub UKM Recorder. Set the older recorder as member variable as other
- // instances might depend on it. Its destruction would cause the test to crash
- // during teardown.
- old_ukm_recorder_ = std::move(GetDocument().ukm_recorder_);
- GetDocument().ukm_recorder_ = std::make_unique<ukm::TestUkmRecorder>();
-
// Render two frames to handle the async step added by the beforematch event.
Compositor().BeginFrame();
BeginEmptyFrame();
- auto* recorder =
- static_cast<ukm::TestUkmRecorder*>(GetDocument().UkmRecorder());
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
- auto entries = recorder->GetEntriesByName(
+ auto entries = ukm_recorder()->GetEntriesByName(
ukm::builders::SharedHighlights_LinkOpened::kEntryName);
ASSERT_EQ(1u, entries.size());
const ukm::mojom::UkmEntry* entry = entries[0];
EXPECT_EQ(GetDocument().UkmSourceID(), entry->source_id);
- recorder->ExpectEntryMetric(entry, kSuccessUkmMetric, /*success=*/true);
- EXPECT_TRUE(recorder->GetEntryMetric(entry, kSourceUkmMetric));
+ ukm_recorder()->ExpectEntryMetric(entry, kSuccessUkmMetric,
+ /*expected_value=*/true);
+ EXPECT_TRUE(ukm_recorder()->GetEntryMetric(entry, kSourceUkmMetric));
}
// Tests that a LinkOpened UKM Event is recorded upon a failed fragment
@@ -1533,26 +1691,77 @@ TEST_F(TextFragmentAnchorMetricsTest, LinkOpenedFailedUKM) {
)HTML");
RunAsyncMatchingTasks();
- // Stub UKM Recorder. Set the older recorder as member variable as other
- // instances might depend on it. Its destruction would cause the test to crash
- // during teardown.
- old_ukm_recorder_ = std::move(GetDocument().ukm_recorder_);
- GetDocument().ukm_recorder_ = std::make_unique<ukm::TestUkmRecorder>();
-
// Render two frames to handle the async step added by the beforematch event.
Compositor().BeginFrame();
BeginEmptyFrame();
- auto* recorder =
- static_cast<ukm::TestUkmRecorder*>(GetDocument().UkmRecorder());
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
- auto entries = recorder->GetEntriesByName(
+ auto entries = ukm_recorder()->GetEntriesByName(
ukm::builders::SharedHighlights_LinkOpened::kEntryName);
ASSERT_EQ(1u, entries.size());
const ukm::mojom::UkmEntry* entry = entries[0];
EXPECT_EQ(GetDocument().UkmSourceID(), entry->source_id);
- recorder->ExpectEntryMetric(entry, kSuccessUkmMetric, /*success=*/false);
- EXPECT_TRUE(recorder->GetEntryMetric(entry, kSourceUkmMetric));
+ ukm_recorder()->ExpectEntryMetric(entry, kSuccessUkmMetric,
+ /*expected_value=*/false);
+ EXPECT_TRUE(ukm_recorder()->GetEntryMetric(entry, kSourceUkmMetric));
+}
+
+// Tests that loading a page that has a ForceLoadAtTop DocumentPolicy invokes
+// the UseCounter.
+TEST_F(TextFragmentAnchorMetricsTest, ForceLoadAtTopUseCounter) {
+ SimRequest::Params params;
+ params.response_http_headers.insert("Document-Policy", "force-load-at-top");
+ SimRequest request("https://example.com/test.html", "text/html", params);
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <p>This is a test page</p>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ // Render two frames to handle the async step added by the beforematch event.
+ Compositor().BeginFrame();
+ BeginEmptyFrame();
+
+ EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kForceLoadAtTop));
+}
+
+// Tests that loading a page that explicitly disables ForceLoadAtTop
+// DocumentPolicy or has no DocumentPolicy doesn't invoke the UseCounter for
+// ForceLoadAtTop.
+TEST_F(TextFragmentAnchorMetricsTest, NoForceLoadAtTopUseCounter) {
+ SimRequest::Params params;
+ params.response_http_headers.insert("Document-Policy",
+ "no-force-load-at-top");
+ SimRequest request("https://example.com/test.html", "text/html", params);
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <p>This is a test page</p>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ // Render two frames to handle the async step added by the beforematch event.
+ Compositor().BeginFrame();
+ BeginEmptyFrame();
+
+ EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kForceLoadAtTop));
+
+ // Try without any DocumentPolicy headers.
+ SimRequest request2("https://example.com/test2.html", "text/html");
+ LoadURL("https://example.com/test2.html");
+ request2.Complete(R"HTML(
+ <!DOCTYPE html>
+ <p>This is a different test page</p>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ Compositor().BeginFrame();
+ BeginEmptyFrame();
+
+ EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kForceLoadAtTop));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
index 93ffc2eb404..a21b452b331 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
@@ -6,6 +6,7 @@
#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/core/dom/element.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/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -16,6 +17,7 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
@@ -2040,6 +2042,91 @@ TEST_F(TextFragmentAnchorTest, MatchAcrossCommentNode) {
EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
}
+// Test that selection is successful for same prefix and text start.
+TEST_F(TextFragmentAnchorTest, SamePrefixAndText) {
+ SimRequest request("https://example.com/test.html#:~:text=foo-,foo,-bar",
+ "text/html");
+ LoadURL("https://example.com/test.html#:~:text=foo-,foo,-bar");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ height: 1200px;
+ }
+ div {
+ position: absolute;
+ top: 1000px;
+ }
+ </style>
+ <div id="text">foo foo foo bar bar bar</div>
+ )HTML");
+ RunAsyncMatchingTasks();
+
+ // Render two frames to handle the async step added by the beforematch event.
+ Compositor().BeginFrame();
+ Compositor().BeginFrame();
+
+ Element& div = *GetDocument().getElementById("text");
+
+ EXPECT_EQ(div, *GetDocument().CssTarget());
+ EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(div)));
+ EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
+}
+// Checks that selection in the same text node is considerered uninterrupted.
+TEST_F(TextFragmentAnchorTest, IsInSameUninterruptedBlock_OneTextNode) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='first'>First paragraph text</div>
+ )HTML");
+ Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+ const auto& start = PositionInFlatTree(first_paragraph, 0);
+ const auto& end = PositionInFlatTree(first_paragraph, 15);
+ ASSERT_EQ("First paragraph", PlainText(EphemeralRangeInFlatTree(start, end)));
+
+ EXPECT_TRUE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
+// Checks that selection in the same text node with nested non-block element is
+// considerered uninterrupted.
+TEST_F(TextFragmentAnchorTest,
+ IsInSameUninterruptedBlock_NonBlockInterruption) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='first'>First <i>styled text</i> paragraph text</div>
+ )HTML");
+ Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+ const auto& start = PositionInFlatTree(first_paragraph, 0);
+ const auto& end =
+ PositionInFlatTree(first_paragraph->nextSibling()->nextSibling(), 10);
+ ASSERT_EQ("First styled text paragraph",
+ PlainText(EphemeralRangeInFlatTree(start, end)));
+
+ EXPECT_TRUE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
+// Checks that selection in the same text node with nested block element is
+// considerered interrupted.
+TEST_F(TextFragmentAnchorTest, IsInSameUninterruptedBlock_BlockInterruption) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='first'>First <div>block text</div> paragraph text</div>
+ )HTML");
+ Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+ const auto& start = PositionInFlatTree(first_paragraph, 0);
+ const auto& end =
+ PositionInFlatTree(first_paragraph->nextSibling()->nextSibling(), 10);
+ ASSERT_EQ("First\nblock text\nparagraph",
+ PlainText(EphemeralRangeInFlatTree(start, end)));
+
+ EXPECT_FALSE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
index 24470c3f51a..91dee7e80c7 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
@@ -11,15 +11,15 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
-#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/finder/async_find_buffer.h"
#include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
#include "third_party/blink/renderer/core/editing/finder/find_options.h"
+#include "third_party/blink/renderer/core/editing/finder/sync_find_buffer.h"
#include "third_party/blink/renderer/core/editing/iterators/character_iterator.h"
-#include "third_party/blink/renderer/core/editing/position.h"
-#include "third_party/blink/renderer/core/editing/position_iterator.h"
#include "third_party/blink/renderer/core/html/list_item_ordinal.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h"
#include "third_party/blink/renderer/platform/text/text_boundaries.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -80,33 +80,12 @@ PositionInFlatTree FirstWordBoundaryAfter(PositionInFlatTree position) {
PositionInFlatTree end_pos(position.AnchorNode(), word_end);
PositionIteratorInFlatTree itr(end_pos);
+ itr.Increment();
if (itr.AtEnd())
return end_pos;
-
- itr.Increment();
return itr.ComputePosition();
}
-EphemeralRangeInFlatTree FindMatchInRange(String search_text,
- PositionInFlatTree search_start,
- PositionInFlatTree search_end,
- bool word_start_bounded,
- bool word_end_bounded) {
- while (search_start < search_end) {
- const EphemeralRangeInFlatTree search_range(search_start, search_end);
- EphemeralRangeInFlatTree potential_match = FindBuffer::FindMatchInRange(
- search_range, search_text, kCaseInsensitive);
-
- if (potential_match.IsNull() ||
- IsWordBounded(potential_match, word_start_bounded, word_end_bounded))
- return potential_match;
-
- search_start = potential_match.EndPosition();
- }
-
- return EphemeralRangeInFlatTree();
-}
-
PositionInFlatTree NextTextPosition(PositionInFlatTree position,
PositionInFlatTree end_position) {
const TextIteratorBehavior options =
@@ -121,115 +100,6 @@ PositionInFlatTree NextTextPosition(PositionInFlatTree position,
return end_position;
}
-EphemeralRangeInFlatTree FindMatchInRangeWithContext(
- const String& start_text,
- const String& end_text,
- const String& prefix,
- const String& suffix,
- PositionInFlatTree search_start,
- PositionInFlatTree search_end) {
- while (search_start != search_end) {
- EphemeralRangeInFlatTree potential_match;
-
- if (!prefix.IsEmpty()) {
- EphemeralRangeInFlatTree prefix_match = FindMatchInRange(
- prefix, search_start, search_end, /*word_start_bounded=*/true,
- /*word_end_bounded=*/false);
-
- // No prefix_match in remaining range
- if (prefix_match.IsNull())
- return EphemeralRangeInFlatTree();
-
- // If we iterate again, start searching from the first boundary after the
- // prefix start (since prefix must start at a boundary). Note, we don't
- // advance to the prefix end; this is done since, if this prefix isn't
- // the one we're looking for, the next occurrence might be overlapping
- // with the current one. e.g. If |prefix| is "a a" and our search range
- // currently starts with "a a a b...", the next iteration should start at
- // the second a which is part of the current |prefix_match|.
- search_start = FirstWordBoundaryAfter(prefix_match.StartPosition());
-
- EphemeralRangeInFlatTree match_range(
- NextTextPosition(prefix_match.EndPosition(), search_end), search_end);
-
- // The match text need not be bounded at the end. If this is an exact
- // match (i.e. no |end_text|) and we have a suffix then the suffix will
- // be required to end on the word boundary instead. Since we have a
- // prefix, we don't need the match to be word bounded. See
- // https://github.com/WICG/scroll-to-text-fragment/issues/137 for
- // details.
- const bool end_at_word_boundary = !end_text.IsEmpty() || suffix.IsEmpty();
-
- potential_match = FindMatchInRange(
- start_text, match_range.StartPosition(), match_range.EndPosition(),
- /*word_start_bounded=*/false, end_at_word_boundary);
-
- // No start_text match after current prefix_match
- if (potential_match.IsNull())
- return EphemeralRangeInFlatTree();
-
- // We found a potential match but it didn't immediately follow the prefix.
- if (potential_match.StartPosition() != match_range.StartPosition())
- continue;
- } else {
- const bool end_at_word_boundary = !end_text.IsEmpty() || suffix.IsEmpty();
-
- potential_match =
- FindMatchInRange(start_text, search_start, search_end,
- /*word_start_bounded=*/true, end_at_word_boundary);
-
- // No start_text match in remaining range
- if (potential_match.IsNull())
- return EphemeralRangeInFlatTree();
-
- search_start = FirstWordBoundaryAfter(potential_match.StartPosition());
- }
-
- // If we've gotten here, we've found a |prefix| (if one was specified)
- // that's followed by the |start_text|. We'll now try to expand that into a
- // range match if |end_text| is specified.
- if (!end_text.IsEmpty()) {
- EphemeralRangeInFlatTree text_end_range(potential_match.EndPosition(),
- search_end);
- const bool end_at_word_boundary = suffix.IsEmpty();
-
- EphemeralRangeInFlatTree text_end_match =
- FindMatchInRange(end_text, text_end_range.StartPosition(),
- text_end_range.EndPosition(),
- /*word_start_bounded=*/true, end_at_word_boundary);
-
- if (text_end_match.IsNull())
- return EphemeralRangeInFlatTree();
-
- potential_match = EphemeralRangeInFlatTree(
- potential_match.StartPosition(), text_end_match.EndPosition());
- }
-
- DCHECK(!potential_match.IsNull());
- if (suffix.IsEmpty())
- return potential_match;
-
- // Now we just have to ensure the match is followed by the |suffix|.
- EphemeralRangeInFlatTree suffix_range(
- NextTextPosition(potential_match.EndPosition(), search_end),
- search_end);
-
- EphemeralRangeInFlatTree suffix_match = FindMatchInRange(
- suffix, suffix_range.StartPosition(), suffix_range.EndPosition(),
- /*word_start_bounded=*/false, /*word_end_bounded=*/true);
-
- // If no suffix appears in what follows the match, there's no way we can
- // possibly satisfy the constraints so bail.
- if (suffix_match.IsNull())
- return EphemeralRangeInFlatTree();
-
- if (suffix_match.StartPosition() == suffix_range.StartPosition())
- return potential_match;
- }
-
- return EphemeralRangeInFlatTree();
-}
-
bool ContainedByListItem(const EphemeralRangeInFlatTree& range) {
Node* node = range.CommonAncestorContainer();
while (node) {
@@ -254,68 +124,378 @@ bool ContainedByTableCell(const EphemeralRangeInFlatTree& range) {
} // namespace
+void TextFragmentFinder::OnFindMatchInRangeComplete(
+ String search_text,
+ RangeInFlatTree* search_range,
+ bool word_start_bounded,
+ bool word_end_bounded,
+ const EphemeralRangeInFlatTree& match) {
+ // If any of our ranges became invalid, stop the search.
+ if (!HasValidRanges()) {
+ potential_match_.Clear();
+ first_match_.Clear();
+ OnMatchComplete();
+ return;
+ }
+
+ if (match.IsNull() ||
+ IsWordBounded(match, word_start_bounded, word_end_bounded)) {
+ switch (step_) {
+ case kMatchPrefix:
+ OnPrefixMatchComplete(match);
+ break;
+ case kMatchTextStart:
+ OnTextStartMatchComplete(match);
+ break;
+ case kMatchTextEnd:
+ OnTextEndMatchComplete(match);
+ break;
+ case kMatchSuffix:
+ OnSuffixMatchComplete(match);
+ break;
+ }
+ return;
+ }
+ search_range->SetStart(match.EndPosition());
+ FindMatchInRange(search_text, search_range, word_start_bounded,
+ word_end_bounded);
+}
+
+void TextFragmentFinder::FindMatchInRange(String search_text,
+ RangeInFlatTree* search_range,
+ bool word_start_bounded,
+ bool word_end_bounded) {
+ find_buffer_runner_->FindMatchInRange(
+ search_range, search_text, kCaseInsensitive,
+ WTF::Bind(&TextFragmentFinder::OnFindMatchInRangeComplete,
+ WrapWeakPersistent(this), search_text,
+ WrapWeakPersistent(search_range), word_start_bounded,
+ word_end_bounded));
+}
+
+void TextFragmentFinder::FindPrefix() {
+ search_range_->SetStart(match_range_->StartPosition());
+ if (search_range_->IsCollapsed()) {
+ OnMatchComplete();
+ return;
+ }
+
+ if (selector_.Prefix().IsEmpty()) {
+ GoToStep(kMatchTextStart);
+ return;
+ }
+
+ FindMatchInRange(selector_.Prefix(), search_range_,
+ /*word_start_bounded=*/true,
+ /*word_end_bounded=*/false);
+}
+
+void TextFragmentFinder::OnPrefixMatchComplete(
+ EphemeralRangeInFlatTree prefix_match) {
+ // No prefix_match in remaining range
+ if (prefix_match.IsNull()) {
+ OnMatchComplete();
+ return;
+ }
+
+ // If we iterate again, start searching from the first boundary after the
+ // prefix start (since prefix must start at a boundary). Note, we don't
+ // advance to the prefix end; this is done since, if this prefix isn't
+ // the one we're looking for, the next occurrence might be overlapping
+ // with the current one. e.g. If |prefix| is "a a" and our search range
+ // currently starts with "a a a b...", the next iteration should start at
+ // the second a which is part of the current |prefix_match|.
+ match_range_->SetStart(FirstWordBoundaryAfter(prefix_match.StartPosition()));
+ SetPrefixMatch(prefix_match);
+ GoToStep(kMatchTextStart);
+ return;
+}
+
+void TextFragmentFinder::FindTextStart() {
+ DCHECK(!selector_.Start().IsEmpty());
+
+ // The match text need not be bounded at the end. If this is an exact
+ // match (i.e. no |end_text|) and we have a suffix then the suffix will
+ // be required to end on the word boundary instead. Since we have a
+ // prefix, we don't need the match to be word bounded. See
+ // https://github.com/WICG/scroll-to-text-fragment/issues/137 for
+ // details.
+ const bool end_at_word_boundary =
+ !selector_.End().IsEmpty() || selector_.Suffix().IsEmpty();
+ if (prefix_match_) {
+ search_range_->SetStart(NextTextPosition(prefix_match_->EndPosition(),
+ match_range_->EndPosition()));
+ FindMatchInRange(selector_.Start(), search_range_,
+ /*word_start_bounded=*/false, end_at_word_boundary);
+ } else {
+ FindMatchInRange(selector_.Start(), search_range_,
+ /*word_start_bounded=*/true, end_at_word_boundary);
+ }
+}
+
+void TextFragmentFinder::OnTextStartMatchComplete(
+ EphemeralRangeInFlatTree potential_match) {
+ if (prefix_match_) {
+ PositionInFlatTree next_position_after_prefix = NextTextPosition(
+ prefix_match_->EndPosition(), match_range_->EndPosition());
+ // We found a potential match but it didn't immediately follow the prefix.
+ if (!potential_match.IsNull() &&
+ potential_match.StartPosition() != next_position_after_prefix) {
+ potential_match_.Clear();
+ GoToStep(kMatchPrefix);
+ return;
+ }
+ }
+
+ // No start_text match after current prefix_match
+ if (potential_match.IsNull()) {
+ OnMatchComplete();
+ return;
+ }
+ if (!prefix_match_) {
+ match_range_->SetStart(
+ FirstWordBoundaryAfter(potential_match.StartPosition()));
+ }
+ if (!range_end_search_start_) {
+ range_end_search_start_ = MakeGarbageCollected<RelocatablePosition>(
+ ToPositionInDOMTree(potential_match.EndPosition()));
+ } else {
+ range_end_search_start_->SetPosition(
+ ToPositionInDOMTree(potential_match.EndPosition()));
+ }
+ SetPotentialMatch(potential_match);
+ GoToStep(kMatchTextEnd);
+}
+
+void TextFragmentFinder::FindTextEnd() {
+ // If we've gotten here, we've found a |prefix| (if one was specified)
+ // that's followed by the |start_text|. We'll now try to expand that into
+ // a range match if |end_text| is specified.
+ if (!selector_.End().IsEmpty()) {
+ search_range_->SetStart(
+ ToPositionInFlatTree(range_end_search_start_->GetPosition()));
+ const bool end_at_word_boundary = selector_.Suffix().IsEmpty();
+
+ FindMatchInRange(selector_.End(), search_range_,
+ /*word_start_bounded=*/true, end_at_word_boundary);
+ } else {
+ GoToStep(kMatchSuffix);
+ }
+}
+
+void TextFragmentFinder::OnTextEndMatchComplete(
+ EphemeralRangeInFlatTree text_end_match) {
+ if (text_end_match.IsNull()) {
+ potential_match_.Clear();
+ OnMatchComplete();
+ return;
+ }
+
+ potential_match_->SetEnd(text_end_match.EndPosition());
+ GoToStep(kMatchSuffix);
+}
+
+void TextFragmentFinder::FindSuffix() {
+ DCHECK(!potential_match_->IsNull());
+
+ if (selector_.Suffix().IsEmpty()) {
+ OnMatchComplete();
+ return;
+ }
+
+ // Now we just have to ensure the match is followed by the |suffix|.
+ search_range_->SetStart(NextTextPosition(potential_match_->EndPosition(),
+ match_range_->EndPosition()));
+ FindMatchInRange(selector_.Suffix(), search_range_,
+ /*word_start_bounded=*/false, /*word_end_bounded=*/true);
+}
+
+void TextFragmentFinder::OnSuffixMatchComplete(
+ EphemeralRangeInFlatTree suffix_match) {
+ // If no suffix appears in what follows the match, there's no way we can
+ // possibly satisfy the constraints so bail.
+ if (suffix_match.IsNull()) {
+ potential_match_.Clear();
+ OnMatchComplete();
+ return;
+ }
+
+ PositionInFlatTree next_position_after_match = NextTextPosition(
+ potential_match_->EndPosition(), match_range_->EndPosition());
+ if (suffix_match.StartPosition() == next_position_after_match) {
+ OnMatchComplete();
+ return;
+ }
+
+ // If this is an exact match(e.g. |end_text| is not specified), and we
+ // didn't match on suffix, continue searching for a new potential_match
+ // from it's start.
+ if (selector_.End().IsEmpty()) {
+ potential_match_.Clear();
+ GoToStep(kMatchPrefix);
+ return;
+ }
+
+ // If this is a range match(e.g. |end_text| is specified), it is possible
+ // that we found the correct range start, but not the correct range end.
+ // Continue searching for it, without restarting the range start search.
+ range_end_search_start_->SetPosition(
+ ToPositionInDOMTree(potential_match_->EndPosition()));
+ GoToStep(kMatchTextEnd);
+}
+
+void TextFragmentFinder::GoToStep(SelectorMatchStep step) {
+ step_ = step;
+ switch (step_) {
+ case kMatchPrefix:
+ FindPrefix();
+ break;
+ case kMatchTextStart:
+ FindTextStart();
+ break;
+ case kMatchTextEnd:
+ FindTextEnd();
+ break;
+ case kMatchSuffix:
+ FindSuffix();
+ break;
+ }
+}
+
+// static
+bool TextFragmentFinder::IsInSameUninterruptedBlock(
+ const PositionInFlatTree& start,
+ const PositionInFlatTree& end) {
+ if (!start.ComputeContainerNode()->GetLayoutObject() ||
+ !end.ComputeContainerNode()->GetLayoutObject())
+ return true;
+ return FindBuffer::IsInSameUninterruptedBlock(*start.ComputeContainerNode(),
+ *end.ComputeContainerNode());
+}
+
TextFragmentFinder::TextFragmentFinder(Client& client,
- const TextFragmentSelector& selector)
- : client_(client), selector_(selector) {
+ const TextFragmentSelector& selector,
+ Document* document,
+ FindBufferRunnerType runner_type)
+ : client_(client), selector_(selector), document_(document) {
DCHECK(!selector_.Start().IsEmpty());
DCHECK(selector_.Type() != TextFragmentSelector::SelectorType::kInvalid);
+ if (runner_type == TextFragmentFinder::FindBufferRunnerType::kAsynchronous) {
+ find_buffer_runner_ = MakeGarbageCollected<AsyncFindBuffer>();
+ } else {
+ find_buffer_runner_ = MakeGarbageCollected<SyncFindBuffer>();
+ }
+}
+
+void TextFragmentFinder::Cancel() {
+ if (find_buffer_runner_ && find_buffer_runner_->IsActive())
+ find_buffer_runner_->Cancel();
}
-void TextFragmentFinder::FindMatch(Document& document) {
- PositionInFlatTree search_start =
- PositionInFlatTree::FirstPositionInNode(document);
+void TextFragmentFinder::FindMatch() {
+ Cancel();
auto forced_lock_scope =
- document.GetDisplayLockDocumentState().GetScopedForceActivatableLocks();
- document.UpdateStyleAndLayout(DocumentUpdateReason::kFindInPage);
+ document_->GetDisplayLockDocumentState().GetScopedForceActivatableLocks();
+ document_->UpdateStyleAndLayout(DocumentUpdateReason::kFindInPage);
- EphemeralRangeInFlatTree match =
- FindMatchFromPosition(document, search_start);
+ first_match_.Clear();
+ FindMatchFromPosition(PositionInFlatTree::FirstPositionInNode(*document_));
+}
- if (match.IsNotNull()) {
- TextFragmentAnchorMetrics::Match match_metrics(selector_);
+void TextFragmentFinder::FindMatchFromPosition(
+ PositionInFlatTree search_start) {
+ PositionInFlatTree search_end;
+ if (document_->documentElement() &&
+ document_->documentElement()->lastChild()) {
+ search_end = PositionInFlatTree::AfterNode(
+ *document_->documentElement()->lastChild());
+ } else {
+ search_end = PositionInFlatTree::LastPositionInNode(*document_);
+ }
+ search_range_ =
+ MakeGarbageCollected<RangeInFlatTree>(search_start, search_end);
+ match_range_ =
+ MakeGarbageCollected<RangeInFlatTree>(search_start, search_end);
+ potential_match_.Clear();
+ prefix_match_.Clear();
+ GoToStep(kMatchPrefix);
+}
+void TextFragmentFinder::OnMatchComplete() {
+ if (!potential_match_ && !first_match_) {
+ client_.NoMatchFound();
+ } else if (potential_match_ && !first_match_) {
+ // Continue searching to see if we have an ambiguous selector.
+ // TODO(crbug.com/919204): This is temporary and only for measuring
+ // ambiguous matching during prototyping.
+ first_match_ = potential_match_;
+ FindMatchFromPosition(first_match_->EndPosition());
+ } else {
+ TextFragmentAnchorMetrics::Match match_metrics(selector_);
+ EphemeralRangeInFlatTree potential_match = first_match_->ToEphemeralRange();
if (selector_.Type() == TextFragmentSelector::SelectorType::kExact) {
// If it's an exact match, we don't need to do the PlainText conversion,
// we can just use the text from the selector.
- DCHECK_EQ(selector_.Start().length(), PlainText(match).length());
+ DCHECK_EQ(selector_.Start().length(),
+ PlainText(potential_match).length());
match_metrics.text = selector_.Start();
- if (ContainedByListItem(match)) {
+ if (ContainedByListItem(potential_match)) {
match_metrics.is_list_item = true;
}
- if (ContainedByTableCell(match)) {
+ if (ContainedByTableCell(potential_match)) {
match_metrics.is_table_cell = true;
}
} else if (selector_.Type() == TextFragmentSelector::SelectorType::kRange) {
- match_metrics.text = PlainText(match);
+ match_metrics.text = PlainText(potential_match);
+ match_metrics.spans_multiple_blocks = !IsInSameUninterruptedBlock(
+ potential_match.StartPosition(), potential_match.EndPosition());
}
+ client_.DidFindMatch(potential_match, match_metrics, !potential_match_);
+ }
+}
- // Continue searching to see if we have an ambiguous selector.
- // TODO(crbug.com/919204): This is temporary and only for measuring
- // ambiguous matching during prototyping.
- EphemeralRangeInFlatTree ambiguous_match =
- FindMatchFromPosition(document, match.EndPosition());
- client_.DidFindMatch(match, match_metrics, ambiguous_match.IsNull());
+void TextFragmentFinder::Trace(Visitor* visitor) const {
+ visitor->Trace(document_);
+ visitor->Trace(range_end_search_start_);
+ visitor->Trace(potential_match_);
+ visitor->Trace(prefix_match_);
+ visitor->Trace(first_match_);
+ visitor->Trace(search_range_);
+ visitor->Trace(match_range_);
+ visitor->Trace(find_buffer_runner_);
+}
+
+void TextFragmentFinder::SetPotentialMatch(EphemeralRangeInFlatTree range) {
+ if (potential_match_) {
+ potential_match_->SetStart(range.StartPosition());
+ potential_match_->SetEnd(range.EndPosition());
} else {
- client_.NoMatchFound();
+ potential_match_ = MakeGarbageCollected<RangeInFlatTree>(
+ range.StartPosition(), range.EndPosition());
}
}
-EphemeralRangeInFlatTree TextFragmentFinder::FindMatchFromPosition(
- Document& document,
- PositionInFlatTree search_start) {
- PositionInFlatTree search_end;
- if (document.documentElement() && document.documentElement()->lastChild()) {
- search_end =
- PositionInFlatTree::AfterNode(*document.documentElement()->lastChild());
+void TextFragmentFinder::SetPrefixMatch(EphemeralRangeInFlatTree range) {
+ if (prefix_match_) {
+ prefix_match_->SetStart(range.StartPosition());
+ prefix_match_->SetEnd(range.EndPosition());
} else {
- search_end = PositionInFlatTree::LastPositionInNode(document);
+ prefix_match_ = MakeGarbageCollected<RangeInFlatTree>(range.StartPosition(),
+ range.EndPosition());
}
+}
- return FindMatchInRangeWithContext(selector_.Start(), selector_.End(),
- selector_.Prefix(), selector_.Suffix(),
- search_start, search_end);
+bool TextFragmentFinder::HasValidRanges() {
+ return !((prefix_match_ &&
+ (prefix_match_->IsNull() || !prefix_match_->IsConnected())) ||
+ (potential_match_ &&
+ (potential_match_->IsNull() || !potential_match_->IsConnected())) ||
+ (search_range_ &&
+ (search_range_->IsNull() || !search_range_->IsConnected())) ||
+ (match_range_ &&
+ (match_range_->IsNull() || !match_range_->IsConnected())));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
index 31051b2e686..c02f8a02f9a 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
@@ -5,8 +5,14 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_FINDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_FINDER_H_
+#include "base/callback.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/finder/find_buffer_runner.h"
#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/core/editing/position.h"
+#include "third_party/blink/renderer/core/editing/position_iterator.h"
+#include "third_party/blink/renderer/core/editing/relocatable_position.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -17,8 +23,9 @@ class Document;
// This is a helper class to TextFragmentAnchor. It's responsible for actually
// performing the text search for the anchor and returning the results to the
-// anchor.
-class CORE_EXPORT TextFragmentFinder final {
+// anchor. Has derived class |MockTextFragmentFinder|.
+class CORE_EXPORT TextFragmentFinder
+ : public GarbageCollected<TextFragmentFinder> {
public:
class Client {
public:
@@ -29,20 +36,102 @@ class CORE_EXPORT TextFragmentFinder final {
virtual void NoMatchFound() = 0;
};
+ // Used for tracking what should be the next match stage.
+ enum FindBufferRunnerType { kAsynchronous, kSynchronous };
+ // Returns true if start and end positions are in the same block and there are
+ // no other blocks between them. Otherwise, returns false.
+ static bool IsInSameUninterruptedBlock(const PositionInFlatTree& start,
+ const PositionInFlatTree& end);
+
// Client must outlive the finder.
- TextFragmentFinder(Client& client, const TextFragmentSelector& selector);
- ~TextFragmentFinder() = default;
+ TextFragmentFinder(Client& client,
+ const TextFragmentSelector& selector,
+ Document* document,
+ FindBufferRunnerType runner_type);
+ virtual ~TextFragmentFinder() = default;
// Begins searching in the given top-level document.
- void FindMatch(Document& document);
+ void FindMatch();
+
+ void Cancel();
+
+ void Trace(Visitor*) const;
+
+ protected:
+ friend class TextFragmentFinderTest;
+ FRIEND_TEST_ALL_PREFIXES(TextFragmentFinderTest, DOMMutation);
+ void FindPrefix();
+ void FindTextStart();
+ void FindTextEnd();
+ void FindSuffix();
+
+ // Used for tracking what should be the next match stage.
+ enum SelectorMatchStep {
+ kMatchPrefix,
+ kMatchTextStart,
+ kMatchTextEnd,
+ kMatchSuffix
+ };
+
+ SelectorMatchStep step_ = kMatchPrefix;
private:
+ void FindMatchFromPosition(PositionInFlatTree search_start);
+
+ void OnFindMatchInRangeComplete(String search_text,
+ RangeInFlatTree* range,
+ bool word_start_bounded,
+ bool word_end_bounded,
+ const EphemeralRangeInFlatTree& match);
+
+ void FindMatchInRange(String search_text,
+ RangeInFlatTree* range,
+ bool word_start_bounded,
+ bool word_end_bounded);
+
+ void OnPrefixMatchComplete(EphemeralRangeInFlatTree match);
+ void OnTextStartMatchComplete(EphemeralRangeInFlatTree match);
+ void OnTextEndMatchComplete(EphemeralRangeInFlatTree match);
+ void OnSuffixMatchComplete(EphemeralRangeInFlatTree match);
+
+ virtual void GoToStep(SelectorMatchStep step);
+
+ void OnMatchComplete();
+
+ void SetPotentialMatch(EphemeralRangeInFlatTree range);
+ void SetPrefixMatch(EphemeralRangeInFlatTree range);
+
+ bool HasValidRanges();
+
Client& client_;
const TextFragmentSelector selector_;
+ Member<Document> document_;
+
+ // Start positions for the next text end |FindTask|, this is separate as the
+ // search for end might move the position, which should be discarded.
+ Member<RelocatablePosition> range_end_search_start_;
+
+ // For all the following ranges use |RangeInFlatTree| relocatable range to be
+ // safe for DOM mutations during the Find tasks.
- EphemeralRangeInFlatTree FindMatchFromPosition(
- Document& document,
- PositionInFlatTree search_start);
+ // Successful match after |FindMatchFromPosition| first run.
+ Member<RangeInFlatTree> first_match_;
+ // Current match after |FindMatchFromPosition| run. See
+ // https://wicg.github.io/scroll-to-text-fragment/#ref-for-range-collapsed:~:text=Let-,potentialMatch
+ Member<RangeInFlatTree> potential_match_;
+ // Used for text start match, the presence will change how the text start is
+ // matched. See
+ // https://wicg.github.io/scroll-to-text-fragment/#ref-for-range-collapsed:~:text=Let-,prefixMatch
+ Member<RangeInFlatTree> prefix_match_;
+ // Range for the current match task, including |prefix_match_|,
+ // |potential_match_| and |suffix_match|. See
+ // https://wicg.github.io/scroll-to-text-fragment/#ref-for-range-collapsed:~:text=Let-,searchRange
+ Member<RangeInFlatTree> search_range_;
+ // Start and end positions used for search for |potential_match_|.
+ // https://wicg.github.io/scroll-to-text-fragment/#ref-for-range-collapsed:~:text=Let-,matchRange
+ Member<RangeInFlatTree> match_range_;
+ // Used for running FindBuffer tasks.
+ Member<FindBufferRunner> find_buffer_runner_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder_test.cc
new file mode 100644
index 00000000000..7694fa44c8f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_finder_test.cc
@@ -0,0 +1,76 @@
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
+
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+
+namespace blink {
+
+class MockTextFragmentFinder : public TextFragmentFinder {
+ public:
+ MockTextFragmentFinder(Client& client,
+ const TextFragmentSelector& selector,
+ Document* document,
+ FindBufferRunnerType runner_type)
+ : TextFragmentFinder(client, selector, document, runner_type) {}
+
+ private:
+ void GoToStep(SelectorMatchStep step) override { step_ = step; }
+};
+
+class TextFragmentFinderTest : public SimTest,
+ public TextFragmentFinder::Client {
+ public:
+ void SetUp() override {
+ SimTest::SetUp();
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
+ }
+
+ void NoMatchFound() override { no_match_called_ = true; }
+
+ void DidFindMatch(const EphemeralRangeInFlatTree& match,
+ const TextFragmentAnchorMetrics::Match match_metrics,
+ bool is_unique) override {}
+ bool IsNoMatchFoundCalled() { return no_match_called_; }
+
+ private:
+ bool no_match_called_ = false;
+};
+
+// Tests that Find tasks will fail gracefully when DOM mutations invalidate the
+// Find task properties.
+TEST_F(TextFragmentFinderTest, DOMMutation) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <input id="input" type='submit' value="button text">
+ <p id='first'>First paragraph prefix to unique snippet of text.</p>
+ )HTML");
+
+ TextFragmentSelector selector(TextFragmentSelector::SelectorType::kExact,
+ "First paragraph", "", "button text",
+ "prefix to unique");
+
+ MockTextFragmentFinder* finder = MakeGarbageCollected<MockTextFragmentFinder>(
+ *this, selector, &GetDocument(),
+ TextFragmentFinder::FindBufferRunnerType::kSynchronous);
+ finder->FindMatch();
+
+ finder->FindPrefix();
+ EXPECT_EQ(false, IsNoMatchFoundCalled());
+
+ finder->FindTextStart();
+ EXPECT_EQ(false, IsNoMatchFoundCalled());
+
+ Node* input = GetDocument().getElementById("input");
+ input->remove();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+
+ finder->FindSuffix();
+ EXPECT_EQ(true, IsNoMatchFoundCalled());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
index e3c98ded913..f61ac5e7f75 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -6,6 +6,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/time/default_tick_clock.h"
+#include "components/shared_highlighting/core/common/shared_highlighting_features.h"
#include "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/interface_registry.h"
@@ -28,9 +29,10 @@ namespace {
bool IsFirstVisiblePosition(Node* node, unsigned pos_offset) {
auto range_start = Position::FirstPositionInNode(*node);
auto range_end = Position(node, pos_offset);
- return pos_offset == 0 || PlainText(EphemeralRange(range_start, range_end))
- .StripWhiteSpace()
- .IsEmpty();
+ return node->getNodeType() == Node::kElementNode || pos_offset == 0 ||
+ PlainText(EphemeralRange(range_start, range_end))
+ .StripWhiteSpace()
+ .IsEmpty();
}
// Returns true if text from |pos_offset| until end of |node| can be considered
@@ -38,7 +40,8 @@ bool IsFirstVisiblePosition(Node* node, unsigned pos_offset) {
bool IsLastVisiblePosition(Node* node, unsigned pos_offset) {
auto range_start = Position(node, pos_offset);
auto range_end = Position::LastPositionInNode(*node);
- return pos_offset == node->textContent().length() ||
+ return node->getNodeType() == Node::kElementNode ||
+ pos_offset == node->textContent().length() ||
PlainText(EphemeralRange(range_start, range_end))
.StripWhiteSpace()
.IsEmpty();
@@ -52,18 +55,25 @@ struct ForwadDirection {
static Node* GetVisibleTextNode(Node& start_node) {
return FindBuffer::ForwardVisibleTextNode(start_node);
}
+ // |IsInSameUninterruptedBlock| is diraction specific because |start| and
+ // |end| should be in right order.
+ static bool IsInSameUninterruptedBlock(Node& start, Node& end) {
+ return FindBuffer::IsInSameUninterruptedBlock(start, end);
+ }
};
struct BackwardDirection {
static Node* Next(const Node& node) {
return FlatTreeTraversal::Previous(node);
}
- static Node* Next(const Node& node, const Node* stay_within) {
- return FlatTreeTraversal::Previous(node, stay_within);
- }
static Node* GetVisibleTextNode(Node& start_node) {
return FindBuffer::BackwardVisibleTextNode(start_node);
}
+ // |IsInSameUninterruptedBlock| is diraction specific because |start| and
+ // |end| should be in right order.
+ static bool IsInSameUninterruptedBlock(Node& start, Node& end) {
+ return FindBuffer::IsInSameUninterruptedBlock(end, start);
+ }
};
template <class Direction>
@@ -97,19 +107,16 @@ Node* BackwardNonEmptyVisibleTextNode(Node* start_node) {
// Returns the next/previous visible node to |start_node|.
template <class Direction>
Node* FurthestVisibleTextNodeWithinBlock(Node* start_node) {
- Node& block_ancestor =
- FindBuffer::GetFirstBlockLevelAncestorInclusive(*start_node);
-
// Move forward/backward until no next/previous node is available within same
// |block_ancestor|.
- Node* last_node;
- for (Node* node = start_node; node;
- node = Direction::Next(*node, &block_ancestor)) {
+ Node* last_node = nullptr;
+ for (Node* node = start_node; node; node = Direction::Next(*node)) {
node = Direction::GetVisibleTextNode(*node);
+ if (node && !node->GetLayoutObject())
+ continue;
+
// Stop, if crossed block boundaries.
- if (!node ||
- !FindBuffer::GetFirstBlockLevelAncestorInclusive(*node).isSameNode(
- &block_ancestor))
+ if (!node || !Direction::IsInSameUninterruptedBlock(*start_node, *node))
break;
last_node = node;
}
@@ -152,6 +159,19 @@ String GetWordsFromStart(String text, int word_num) {
return text.Substring(0, pos).StripWhiteSpace();
}
+// For Element-based Position returns the node that its pointing to, otherwise
+// returns the container node.
+Node* ResolvePositionToNode(const PositionInFlatTree& position) {
+ Node* node = position.ComputeContainerNode();
+ int offset = position.ComputeOffsetInContainerNode();
+
+ if (node->getNodeType() == Node::kElementNode && node->hasChildren() &&
+ node->childNodes()->item(offset)) {
+ return node->childNodes()->item(offset);
+ }
+ return node;
+}
+
} // namespace
constexpr int kExactTextMaxChars = 300;
@@ -159,6 +179,7 @@ constexpr int kNoContextMinChars = 20;
constexpr int kMaxContextWords = 10;
constexpr int kMaxRangeWords = 10;
constexpr int kMaxIterationCountToRecord = 10;
+constexpr int kMinWordCount_ = 3;
void TextFragmentSelectorGenerator::UpdateSelection(
LocalFrame* selection_frame,
@@ -173,6 +194,11 @@ void TextFragmentSelectorGenerator::UpdateSelection(
selection_range.GetDocument(),
ToPositionInDOMTree(selection_range.StartPosition()),
ToPositionInDOMTree(selection_range.EndPosition()));
+ if (base::FeatureList::IsEnabled(
+ shared_highlighting::kPreemptiveLinkToTextGeneration)) {
+ Reset();
+ GenerateSelector();
+ }
}
void TextFragmentSelectorGenerator::BindTextFragmentSelectorProducer(
@@ -194,14 +220,23 @@ void TextFragmentSelectorGenerator::AdjustSelection() {
Node* start_container =
ephemeral_range.StartPosition().ComputeContainerNode();
Node* end_container = ephemeral_range.EndPosition().ComputeContainerNode();
+ Node* corrected_start =
+ ResolvePositionToNode(ephemeral_range.StartPosition());
+ int corrected_start_offset =
+ (corrected_start->isSameNode(start_container))
+ ? ephemeral_range.StartPosition().ComputeOffsetInContainerNode()
+ : 0;
+
+ Node* corrected_end = ResolvePositionToNode(ephemeral_range.EndPosition());
+ int corrected_end_offset =
+ (corrected_end->isSameNode(end_container))
+ ? ephemeral_range.EndPosition().ComputeOffsetInContainerNode()
+ : 0;
// If start node has no text or given start position point to the last visible
// text in its containiner node, use the following visible node for selection
// start. This has to happen before generation, so that selection is correctly
// classified as same block or not.
- Node* corrected_start = start_container;
- int corrected_start_offset =
- ephemeral_range.StartPosition().ComputeOffsetInContainerNode();
if (IsLastVisiblePosition(corrected_start, corrected_start_offset)) {
corrected_start = FirstNonEmptyVisibleTextNode(
FlatTreeTraversal::NextSkippingChildren(*corrected_start));
@@ -220,9 +255,6 @@ void TextFragmentSelectorGenerator::AdjustSelection() {
// text in its containiner node, use the previous visible node for selection
// end. This has to happen before generation, so that selection is correctly
// classified as same block or not.
- Node* corrected_end = end_container;
- int corrected_end_offset =
- ephemeral_range.EndPosition().ComputeOffsetInContainerNode();
if (IsFirstVisiblePosition(corrected_end, corrected_end_offset)) {
// Here, |Previous()| already skips the children of the given node,
// because we're doing pre-order traversal.
@@ -261,32 +293,56 @@ void TextFragmentSelectorGenerator::AdjustSelection() {
}
}
-void TextFragmentSelectorGenerator::GenerateSelector(
- GenerateSelectorCallback callback) {
- DCHECK(selection_range_);
+void TextFragmentSelectorGenerator::Cancel() {
+ Reset();
+}
+
+void TextFragmentSelectorGenerator::RequestSelector(
+ RequestSelectorCallback callback) {
DCHECK(callback);
+ if (!base::FeatureList::IsEnabled(
+ shared_highlighting::kPreemptiveLinkToTextGeneration)) {
+ Reset();
+ pending_generate_selector_callback_ = std::move(callback);
+ GenerateSelector();
+ } else {
+ pending_generate_selector_callback_ = std::move(callback);
+ DCHECK_NE(state_, kNotStarted);
+ if (state_ == kFailure || state_ == kSuccess) {
+ selector_requested_before_ready_ = false;
+ if (state_ == kFailure) {
+ NotifyClientSelectorReady(
+ TextFragmentSelector(TextFragmentSelector::SelectorType::kInvalid));
+ } else {
+ NotifyClientSelectorReady(*selector_);
+ }
+ return;
+ }
+ selector_requested_before_ready_ = true;
+ }
+}
- generation_start_time_ = base::DefaultTickClock::GetInstance()->NowTicks();
- pending_generate_selector_callback_ = std::move(callback);
- state_ = kNeedsNewCandidate;
- error_.reset();
- step_ = kExact;
- max_available_prefix_ = "";
- max_available_suffix_ = "";
- max_available_range_start_ = "";
- max_available_range_end_ = "";
- num_prefix_words_ = 0;
- num_suffix_words_ = 0;
- num_range_start_words_ = 0;
- num_range_end_words_ = 0;
- iteration_ = 0;
- selector_ = nullptr;
+void TextFragmentSelectorGenerator::GenerateSelector() {
+ DCHECK(selection_range_);
+
+ selection_range_->OwnerDocument().UpdateStyleAndLayout(
+ DocumentUpdateReason::kFindInPage);
+
+ // Shouldn't continue is selection is empty.
+ EphemeralRangeInFlatTree ephemeral_range(selection_range_);
+ String selected_text = PlainText(ephemeral_range).StripWhiteSpace();
+ if (selected_text.IsEmpty()) {
+ state_ = kFailure;
+ error_ = LinkGenerationError::kEmptySelection;
+ ResolveSelectorState();
+ return;
+ }
AdjustSelection();
UMA_HISTOGRAM_COUNTS_1000(
"SharedHighlights.LinkGenerated.SelectionLength",
PlainText(EphemeralRange(selection_range_)).length());
-
+ state_ = kNeedsNewCandidate;
GenerateSelectorCandidate();
}
@@ -309,15 +365,16 @@ void TextFragmentSelectorGenerator::ResolveSelectorState() {
case kTestCandidate:
RunTextFinder();
break;
+ case kNotStarted:
case kNeedsNewCandidate:
NOTREACHED();
ABSL_FALLTHROUGH_INTENDED;
case kFailure:
- NotifySelectorReady(
+ OnSelectorReady(
TextFragmentSelector(TextFragmentSelector::SelectorType::kInvalid));
break;
case kSuccess:
- NotifySelectorReady(*selector_);
+ OnSelectorReady(*selector_);
break;
}
}
@@ -326,8 +383,10 @@ void TextFragmentSelectorGenerator::RunTextFinder() {
DCHECK(selector_);
iteration_++;
// |FindMatch| will call |DidFindMatch| indicating if the match was unique.
- TextFragmentFinder finder(*this, *selector_);
- finder.FindMatch(*selection_frame_->GetDocument());
+ finder_ = MakeGarbageCollected<TextFragmentFinder>(
+ *this, *selector_, selection_frame_->GetDocument(),
+ TextFragmentFinder::FindBufferRunnerType::kAsynchronous);
+ finder_->FindMatch();
}
void TextFragmentSelectorGenerator::DidFindMatch(
@@ -335,7 +394,7 @@ void TextFragmentSelectorGenerator::DidFindMatch(
const TextFragmentAnchorMetrics::Match match_metrics,
bool is_unique) {
if (is_unique && PlainText(match).StripWhiteSpace().length() ==
- PlainText(EphemeralRange(selection_range_))
+ PlainText(EphemeralRangeInFlatTree(selection_range_))
.StripWhiteSpace()
.length()) {
state_ = kSuccess;
@@ -356,47 +415,20 @@ void TextFragmentSelectorGenerator::NoMatchFound() {
ResolveSelectorState();
}
-void TextFragmentSelectorGenerator::NotifySelectorReady(
+void TextFragmentSelectorGenerator::OnSelectorReady(
const TextFragmentSelector& selector) {
- DCHECK(pending_generate_selector_callback_);
- // TODO(crbug.com/1133823): Add unit tests for all SharedHighlights.*
- // histograms.
- UMA_HISTOGRAM_BOOLEAN(
- "SharedHighlights.LinkGenerated",
- selector.Type() != TextFragmentSelector::SelectorType::kInvalid);
-
- ukm::UkmRecorder* recorder = selection_frame_->GetDocument()->UkmRecorder();
- ukm::SourceId source_id = selection_frame_->GetDocument()->UkmSourceID();
-
- if (selector.Type() != TextFragmentSelector::SelectorType::kInvalid) {
- UMA_HISTOGRAM_COUNTS_1000("SharedHighlights.LinkGenerated.ParamLength",
- selector.ToString().length());
-
- UMA_HISTOGRAM_EXACT_LINEAR("SharedHighlights.LinkGenerated.Iterations",
- iteration_, kMaxIterationCountToRecord);
- UMA_HISTOGRAM_TIMES("SharedHighlights.LinkGenerated.TimeToGenerate",
- base::DefaultTickClock::GetInstance()->NowTicks() -
- generation_start_time_);
- UMA_HISTOGRAM_ENUMERATION(
- "SharedHighlights.LinkGenerated.SelectorParameters",
- TextFragmentAnchorMetrics::GetParametersForSelector(selector));
-
- shared_highlighting::LogLinkGeneratedSuccessUkmEvent(recorder, source_id);
- } else {
- UMA_HISTOGRAM_EXACT_LINEAR(
- "SharedHighlights.LinkGenerated.Error.Iterations", iteration_,
- kMaxIterationCountToRecord);
- UMA_HISTOGRAM_TIMES("SharedHighlights.LinkGenerated.Error.TimeToGenerate",
- base::DefaultTickClock::GetInstance()->NowTicks() -
- generation_start_time_);
-
- LinkGenerationError error =
- error_.has_value() ? error_.value() : LinkGenerationError::kUnknown;
- shared_highlighting::LogLinkGenerationErrorReason(error);
- shared_highlighting::LogLinkGeneratedErrorUkmEvent(recorder, source_id,
- error);
+ RecordAllMetrics(selector);
+ if (pending_generate_selector_callback_) {
+ NotifyClientSelectorReady(selector);
}
+}
+void TextFragmentSelectorGenerator::NotifyClientSelectorReady(
+ const TextFragmentSelector& selector) {
+ DCHECK(pending_generate_selector_callback_);
+ if (base::FeatureList::IsEnabled(
+ shared_highlighting::kPreemptiveLinkToTextGeneration))
+ RecordPreemptiveGenerationMetrics(selector);
std::move(pending_generate_selector_callback_).Run(selector.ToString());
}
@@ -412,6 +444,7 @@ void TextFragmentSelectorGenerator::Trace(Visitor* visitor) const {
visitor->Trace(selection_frame_);
visitor->Trace(selection_range_);
visitor->Trace(selector_producer_);
+ visitor->Trace(finder_);
}
void TextFragmentSelectorGenerator::GenerateExactSelector() {
@@ -419,24 +452,13 @@ void TextFragmentSelectorGenerator::GenerateExactSelector() {
DCHECK_EQ(kNeedsNewCandidate, state_);
EphemeralRangeInFlatTree ephemeral_range(selection_range_);
- // If not in same node, should use ranges.
- if (!IsInSameUninterruptedBlock(selection_range_->StartPosition(),
- selection_range_->EndPosition())) {
+ // If not in same block, should use ranges.
+ if (!TextFragmentFinder::IsInSameUninterruptedBlock(
+ ephemeral_range.StartPosition(), ephemeral_range.EndPosition())) {
step_ = kRange;
return;
}
-
- // TODO(gayane): If same node, need to check if start and end are interrupted
- // by a block. Example: <div>start of the selection <div> sub block </div>end
- // of the selection</div>.
-
String selected_text = PlainText(ephemeral_range).StripWhiteSpace();
- if (selected_text.IsEmpty()) {
- state_ = kFailure;
- error_ = LinkGenerationError::kEmptySelection;
- return;
- }
-
// If too long should use ranges.
if (selected_text.length() > kExactTextMaxChars) {
step_ = kRange;
@@ -459,21 +481,20 @@ void TextFragmentSelectorGenerator::ExtendRangeSelector() {
DCHECK_EQ(kRange, step_);
DCHECK_EQ(kNeedsNewCandidate, state_);
// Give up if range is already too long.
- if (num_range_start_words_ == kMaxRangeWords ||
- num_range_end_words_ == kMaxRangeWords) {
+ if (num_range_words_ > kMaxRangeWords) {
step_ = kContext;
return;
}
- // Initialize range start and end, if needed.
+ // Initialize range start/end and word min count, if needed.
if (max_available_range_start_.IsEmpty() &&
max_available_range_end_.IsEmpty()) {
EphemeralRangeInFlatTree ephemeral_range(selection_range_);
// If selection starts and ends in the same block, then split selected text
// roughly in the middle.
- if (IsInSameUninterruptedBlock(selection_range_->StartPosition(),
- selection_range_->EndPosition())) {
+ if (TextFragmentFinder::IsInSameUninterruptedBlock(
+ ephemeral_range.StartPosition(), ephemeral_range.EndPosition())) {
String selection_text = PlainText(ephemeral_range);
selection_text.Ensure16Bit();
int selection_length = selection_text.length();
@@ -500,12 +521,15 @@ void TextFragmentSelectorGenerator::ExtendRangeSelector() {
max_available_range_end_ =
GetPreviousTextBlock(selection_range_->EndPosition());
}
+
+ // Use at least 3 words from both sides for more robust link to text.
+ num_range_words_ = kMinWordCount_;
}
String start =
- GetWordsFromStart(max_available_range_start_, ++num_range_start_words_);
- String end =
- GetWordsFromEnd(max_available_range_end_, ++num_range_end_words_);
+ GetWordsFromStart(max_available_range_start_, num_range_words_);
+ String end = GetWordsFromEnd(max_available_range_end_, num_range_words_);
+ num_range_words_++;
// If the start and end didn't change, it means we exhausted the selected
// text and should try adding context.
@@ -524,8 +548,7 @@ void TextFragmentSelectorGenerator::ExtendContext() {
DCHECK(selector_);
// Give up if context is already too long.
- if (num_prefix_words_ == kMaxContextWords ||
- num_prefix_words_ == kMaxContextWords) {
+ if (num_context_words_ == kMaxContextWords) {
state_ = kFailure;
error_ = LinkGenerationError::kContextLimitReached;
return;
@@ -536,6 +559,9 @@ void TextFragmentSelectorGenerator::ExtendContext() {
max_available_prefix_ =
GetPreviousTextBlock(selection_range_->StartPosition());
max_available_suffix_ = GetNextTextBlock(selection_range_->EndPosition());
+
+ // Use at least 3 words from both sides for more robust link to text.
+ num_context_words_ = kMinWordCount_;
}
if (max_available_prefix_.IsEmpty() && max_available_suffix_.IsEmpty()) {
@@ -544,8 +570,9 @@ void TextFragmentSelectorGenerator::ExtendContext() {
return;
}
- String prefix = GetWordsFromEnd(max_available_prefix_, ++num_prefix_words_);
- String suffix = GetWordsFromStart(max_available_suffix_, ++num_suffix_words_);
+ String prefix = GetWordsFromEnd(max_available_prefix_, num_context_words_);
+ String suffix = GetWordsFromStart(max_available_suffix_, num_context_words_);
+ num_context_words_++;
// Give up if we were unable to get new prefix and suffix.
if (prefix == selector_->Prefix() && suffix == selector_->Suffix()) {
@@ -614,29 +641,86 @@ String TextFragmentSelectorGenerator::GetNextTextBlock(
return PlainText(EphemeralRange(range_start, range_end)).StripWhiteSpace();
}
-bool TextFragmentSelectorGenerator::IsInSameUninterruptedBlock(
- const Position& start,
- const Position& end) {
- Node* start_node = start.ComputeContainerNode();
- Node* end_node = end.ComputeContainerNode();
+void TextFragmentSelectorGenerator::Reset() {
+ if (finder_)
+ finder_->Cancel();
- if (start_node->isSameNode(end_node))
- return true;
+ generation_start_time_ = base::DefaultTickClock::GetInstance()->NowTicks();
+ state_ = kNotStarted;
+ error_.reset();
+ step_ = kExact;
+ max_available_prefix_ = "";
+ max_available_suffix_ = "";
+ max_available_range_start_ = "";
+ max_available_range_end_ = "";
+ num_context_words_ = 0;
+ num_range_words_ = 0;
+ iteration_ = 0;
+ selector_ = nullptr;
+ selector_requested_before_ready_.reset();
+ pending_generate_selector_callback_.Reset();
+}
- Node& start_ancestor =
- FindBuffer::GetFirstBlockLevelAncestorInclusive(*start_node);
- Node& end_ancestor =
- FindBuffer::GetFirstBlockLevelAncestorInclusive(*end_node);
+void TextFragmentSelectorGenerator::RecordAllMetrics(
+ const TextFragmentSelector& selector) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "SharedHighlights.LinkGenerated",
+ selector.Type() != TextFragmentSelector::SelectorType::kInvalid);
- if (!start_ancestor.isSameNode(&end_ancestor))
- return false;
+ ukm::UkmRecorder* recorder = selection_frame_->GetDocument()->UkmRecorder();
+ ukm::SourceId source_id = selection_frame_->GetDocument()->UkmSourceID();
- Node* node = start_node;
- while (!node->isSameNode(end_node)) {
- if (FindBuffer::IsNodeBlockLevel(*node))
- return false;
- node = FlatTreeTraversal::Next(*node);
+ if (selector.Type() != TextFragmentSelector::SelectorType::kInvalid) {
+ UMA_HISTOGRAM_COUNTS_1000("SharedHighlights.LinkGenerated.ParamLength",
+ selector.ToString().length());
+
+ UMA_HISTOGRAM_EXACT_LINEAR("SharedHighlights.LinkGenerated.Iterations",
+ iteration_, kMaxIterationCountToRecord);
+ UMA_HISTOGRAM_TIMES("SharedHighlights.LinkGenerated.TimeToGenerate",
+ base::DefaultTickClock::GetInstance()->NowTicks() -
+ generation_start_time_);
+ UMA_HISTOGRAM_ENUMERATION(
+ "SharedHighlights.LinkGenerated.SelectorParameters",
+ TextFragmentAnchorMetrics::GetParametersForSelector(selector));
+
+ shared_highlighting::LogLinkGeneratedSuccessUkmEvent(recorder, source_id);
+ } else {
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ "SharedHighlights.LinkGenerated.Error.Iterations", iteration_,
+ kMaxIterationCountToRecord);
+ UMA_HISTOGRAM_TIMES("SharedHighlights.LinkGenerated.Error.TimeToGenerate",
+ base::DefaultTickClock::GetInstance()->NowTicks() -
+ generation_start_time_);
+
+ LinkGenerationError error =
+ error_.has_value() ? error_.value() : LinkGenerationError::kUnknown;
+ shared_highlighting::LogLinkGenerationErrorReason(error);
+ shared_highlighting::LogLinkGeneratedErrorUkmEvent(recorder, source_id,
+ error);
}
- return true;
}
+
+void TextFragmentSelectorGenerator::RecordPreemptiveGenerationMetrics(
+ const TextFragmentSelector& selector) {
+ DCHECK(selector_requested_before_ready_.has_value());
+
+ bool success =
+ selector.Type() != TextFragmentSelector::SelectorType::kInvalid;
+
+ std::string uma_prefix = "SharedHighlights.LinkGenerated";
+ if (selector_requested_before_ready_.value()) {
+ uma_prefix = base::StrCat({uma_prefix, ".RequestedBeforeReady"});
+ } else {
+ uma_prefix = base::StrCat({uma_prefix, ".RequestedAfterReady"});
+ }
+ base::UmaHistogramBoolean(uma_prefix, success);
+
+ if (!success) {
+ LinkGenerationError error =
+ error_.has_value() ? error_.value() : LinkGenerationError::kUnknown;
+ base::UmaHistogramEnumeration(
+ "SharedHighlights.LinkGenerated.Error.Requested", error);
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
index e22ab89df2c..bd6be400528 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
@@ -49,8 +49,10 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
void AdjustSelection();
// blink::mojom::blink::TextFragmentSelectorProducer interface
- // Generates selector for current selection.
- void GenerateSelector(GenerateSelectorCallback callback) override;
+ void Cancel() override;
+
+ // Requests selector for current selection.
+ void RequestSelector(RequestSelectorCallback callback) override;
// TextFragmentFinder::Client interface
void DidFindMatch(const EphemeralRangeInFlatTree& match,
@@ -59,9 +61,6 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
void NoMatchFound() override;
- // Notifies the results of |GenerateSelector|.
- void NotifySelectorReady(const TextFragmentSelector& selector);
-
// Wrappers for tests.
String GetPreviousTextBlockForTesting(const Position& position) {
return GetPreviousTextBlock(position);
@@ -69,9 +68,8 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
String GetNextTextBlockForTesting(const Position& position) {
return GetNextTextBlock(position);
}
- bool IsInSameUninterruptedBlockForTesting(const Position& start,
- const Position& end) {
- return IsInSameUninterruptedBlock(start, end);
+ void SetCallbackForTesting(RequestSelectorCallback callback) {
+ pending_generate_selector_callback_ = std::move(callback);
}
// Releases members if necessary.
@@ -85,6 +83,9 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
// Used for determining the current state of |selector_|.
enum SelectorState {
+ // Sreach for candidate selector didn't start.
+ kNotStarted,
+
// Candidate selector should be generated or extended.
kNeedsNewCandidate,
@@ -100,6 +101,9 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
kSuccess
};
+ // Generates selector for current selection.
+ void GenerateSelector();
+
void GenerateSelectorCandidate();
void ResolveSelectorState();
@@ -113,14 +117,21 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
// boundaries.
String GetNextTextBlock(const Position& position);
- // Returns true if start and end positions are in the same block and there are
- // no other blocks between them. Otherwise, returns false.
- bool IsInSameUninterruptedBlock(const Position& start, const Position& end);
-
void GenerateExactSelector();
void ExtendRangeSelector();
void ExtendContext();
+ void Reset();
+
+ void RecordAllMetrics(const TextFragmentSelector& selector);
+ void RecordPreemptiveGenerationMetrics(const TextFragmentSelector& selector);
+
+ // Called when selector generation is complete.
+ void OnSelectorReady(const TextFragmentSelector& selector);
+
+ // Called to notify clients of the result of |GenerateSelector|.
+ void NotifyClientSelectorReady(const TextFragmentSelector& selector);
+
Member<LocalFrame> selection_frame_;
Member<Range> selection_range_;
std::unique_ptr<TextFragmentSelector> selector_;
@@ -130,11 +141,15 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
HeapMojoReceiver<blink::mojom::blink::TextFragmentSelectorProducer,
TextFragmentSelectorGenerator>
selector_producer_{this, nullptr};
- GenerateSelectorCallback pending_generate_selector_callback_;
+ RequestSelectorCallback pending_generate_selector_callback_;
GenerationStep step_ = kExact;
SelectorState state_ = kNeedsNewCandidate;
+ // Used when preemptive link generation is enabled to report
+ // whether |RequestSelector| was called before or after selector was ready.
+ base::Optional<bool> selector_requested_before_ready_;
+
base::Optional<shared_highlighting::LinkGenerationError> error_;
// Fields used for keeping track of context.
@@ -148,15 +163,15 @@ class CORE_EXPORT TextFragmentSelectorGenerator final
// Indicates a number of words used from |max_available_prefix_| and
// |max_available_suffix_| for the current |selector_|.
- int num_prefix_words_ = 0;
- int num_suffix_words_ = 0;
+ int num_context_words_ = 0;
- int num_range_start_words_ = 0;
- int num_range_end_words_ = 0;
+ int num_range_words_ = 0;
int iteration_ = 0;
base::TimeTicks generation_start_time_;
+ Member<TextFragmentFinder> finder_;
+
DISALLOW_COPY_AND_ASSIGN(TextFragmentSelectorGenerator);
};
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
index c8a2306a236..473285eb21c 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
@@ -9,6 +9,8 @@
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/shared_highlighting/core/common/shared_highlighting_features.h"
#include "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
#include "components/ukm/test_ukm_recorder.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
@@ -18,6 +20,7 @@
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -30,11 +33,21 @@ const char kSuccessUkmMetric[] = "Success";
const char kErrorUkmMetric[] = "Error";
} // namespace
-class TextFragmentSelectorGeneratorTest : public SimTest {
+class TextFragmentSelectorGeneratorTest
+ : public SimTest,
+ public ::testing::WithParamInterface<bool> {
public:
void SetUp() override {
SimTest::SetUp();
WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
+ preemptive_generation_enabled_ = GetParam();
+ if (preemptive_generation_enabled_) {
+ feature_list_.InitAndEnableFeature(
+ shared_highlighting::kPreemptiveLinkToTextGeneration);
+ } else {
+ feature_list_.InitAndDisableFeature(
+ shared_highlighting::kPreemptiveLinkToTextGeneration);
+ }
}
void VerifySelector(Position selected_start,
@@ -46,16 +59,18 @@ class TextFragmentSelectorGeneratorTest : public SimTest {
// Should not have logged errors in a success case.
histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error",
0);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.Error.Requested", 0);
- auto* recorder =
- static_cast<ukm::TestUkmRecorder*>(GetDocument().UkmRecorder());
- auto entries = recorder->GetEntriesByName(
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated",
+ generate_call_count_);
+ auto entries = ukm_recorder()->GetEntriesByName(
ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
ASSERT_EQ(1u, entries.size());
const ukm::mojom::UkmEntry* entry = entries[0];
EXPECT_EQ(GetDocument().UkmSourceID(), entry->source_id);
- recorder->ExpectEntryMetric(entry, kSuccessUkmMetric, true);
- EXPECT_FALSE(recorder->GetEntryMetric(entry, kErrorUkmMetric));
+ ukm_recorder()->ExpectEntryMetric(entry, kSuccessUkmMetric, true);
+ EXPECT_FALSE(ukm_recorder()->GetEntryMetric(entry, kErrorUkmMetric));
}
void VerifySelectorFails(Position selected_start,
@@ -64,24 +79,22 @@ class TextFragmentSelectorGeneratorTest : public SimTest {
String generated_selector = GenerateSelector(selected_start, selected_end);
EXPECT_EQ("", generated_selector);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated",
+ generate_call_count_);
histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
error, 1);
-
- auto* recorder =
- static_cast<ukm::TestUkmRecorder*>(GetDocument().UkmRecorder());
- auto entries = recorder->GetEntriesByName(
+ auto entries = ukm_recorder()->GetEntriesByName(
ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
ASSERT_EQ(1u, entries.size());
const ukm::mojom::UkmEntry* entry = entries[0];
EXPECT_EQ(GetDocument().UkmSourceID(), entry->source_id);
- recorder->ExpectEntryMetric(entry, kSuccessUkmMetric, false);
- recorder->ExpectEntryMetric(entry, kErrorUkmMetric,
- static_cast<int64_t>(error));
+ ukm_recorder()->ExpectEntryMetric(entry, kSuccessUkmMetric, false);
+ ukm_recorder()->ExpectEntryMetric(entry, kErrorUkmMetric,
+ static_cast<int64_t>(error));
}
String GenerateSelector(Position selected_start, Position selected_end) {
- StubUkmRecorder();
-
+ generate_call_count_++;
GetDocument()
.GetFrame()
->GetTextFragmentSelectorGenerator()
@@ -101,30 +114,65 @@ class TextFragmentSelectorGeneratorTest : public SimTest {
GetDocument()
.GetFrame()
->GetTextFragmentSelectorGenerator()
- ->GenerateSelector(std::move(callback));
+ ->RequestSelector(std::move(callback));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(callback_called);
return selector;
}
+ void VerifyPreemptiveGenerationMetrics(bool success) {
+ if (!preemptive_generation_enabled_) {
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.Error.Requested", 0);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", 0);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", 0);
+ } else {
+ EXPECT_EQ(
+ 1u, histogram_tester_
+ .GetAllSamples(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady")
+ .size() +
+ histogram_tester_
+ .GetAllSamples(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady")
+ .size());
+
+ if (!success) {
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.Error.Requested", 1);
+ } else {
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.Error.Requested", 0);
+ }
+ }
+
+ // Check async task metrics.
+ EXPECT_LT(0u, histogram_tester_
+ .GetAllSamples("SharedHighlights.AsyncTask.Iterations")
+ .size());
+ EXPECT_LT(0u,
+ histogram_tester_
+ .GetAllSamples("SharedHighlights.AsyncTask.SearchDuration")
+ .size());
+ }
+
protected:
- void StubUkmRecorder() {
- // Needed to keep old recorders alive, as other instances might depend on
- // one of them, causing tests to crash during teardown.
- old_ukm_recorders_.push_back(std::move(GetDocument().ukm_recorder_));
- GetDocument().ukm_recorder_ = std::make_unique<ukm::TestUkmRecorder>();
+ ukm::TestUkmRecorder* ukm_recorder() {
+ return scoped_ukm_recorder_.recorder();
}
base::HistogramTester histogram_tester_;
-
- // TODO(crbug.com/1153990): Find a better mocking solution and clean up this
- // variable.
- std::vector<std::unique_ptr<ukm::UkmRecorder>> old_ukm_recorders_;
+ ScopedFakeUkmRecorder scoped_ukm_recorder_;
+ int generate_call_count_ = 0;
+ bool preemptive_generation_enabled_;
+ base::test::ScopedFeatureList feature_list_;
};
// Basic exact selector case.
-TEST_F(TextFragmentSelectorGeneratorTest, EmptySelection) {
+TEST_P(TextFragmentSelectorGeneratorTest, EmptySelection) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -141,7 +189,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, EmptySelection) {
}
// Basic exact selector case.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -161,7 +209,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector) {
}
// Exact selector test where selection contains nested <i> node.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithNestedTextNodes) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextWithNestedTextNodes) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -182,7 +230,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithNestedTextNodes) {
}
// Exact selector test where selection contains multiple spaces.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithExtraSpace) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextWithExtraSpace) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -203,7 +251,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextWithExtraSpace) {
// Exact selector where selection is too short, in which case context is
// required.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_TooShortNeedsContext) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -219,12 +267,13 @@ TEST_F(TextFragmentSelectorGeneratorTest,
ASSERT_EQ("unique snippet",
PlainText(EphemeralRange(selected_start, selected_end)));
- VerifySelector(selected_start, selected_end, "to-,unique%20snippet,-of");
+ VerifySelector(selected_start, selected_end,
+ "paragraph%20prefix%20to-,unique%20snippet,-of%20text.");
}
// Exact selector with context test. Case when only one word for prefix and
// suffix is enough to disambiguate the selection.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_WithOneWordContext) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -241,12 +290,12 @@ TEST_F(TextFragmentSelectorGeneratorTest,
PlainText(EphemeralRange(selected_start, selected_end)));
VerifySelector(selected_start, selected_end,
- "First-,paragraph%20text%20that%20is,-longer");
+ "First-,paragraph%20text%20that%20is,-longer%20than%2020");
}
// Exact selector with context test. Case when multiple words for prefix and
// suffix is necessary to disambiguate the selection.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_MultipleWordContext) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -270,7 +319,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Exact selector with context test. Case when multiple words for prefix and
// suffix is necessary to disambiguate the selection and prefix and suffix
// contain extra space.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_MultipleWordContext_ExtraSpace) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -294,7 +343,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Exact selector with context test. Case when available prefix for all the
// occurrences of selected text is the same. In this case suffix should be
// extended until unique selector is found.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -317,7 +366,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefix) {
// Exact selector with context test. Case when available suffix for all the
// occurrences of selected text is the same. In this case prefix should be
// extended until unique selector is found.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SameSuffix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SameSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -340,7 +389,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SameSuffix) {
// Exact selector with context test. Case when available prefix and suffix for
// all the occurrences of selected text are the same. In this case generation
// should be unsuccessful.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefixSuffix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefixSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -362,7 +411,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_SamePrefixSuffix) {
// Exact selector with context test. Case when available prefix and suffix for
// all the occurrences of selected text are the same for the first 10 words. In
// this case generation should be unsuccessful.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_SimilarLongPreffixSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -385,7 +434,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
}
// Exact selector with context test. Case when no prefix is available.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoPrefix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoPrefix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -404,7 +453,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoPrefix) {
}
// Exact selector with context test. Case when no suffix is available.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoSuffix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -426,7 +475,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NoSuffix) {
// Exact selector with context test. Case when available prefix is the
// preceding block.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_PrevNodePrefix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_PrevNodePrefix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -442,12 +491,12 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_PrevNodePrefix) {
PlainText(EphemeralRange(selected_start, selected_end)));
VerifySelector(selected_start, selected_end,
- "snippet-,not%20unique%20snippet,-of");
+ "not%20unique%20snippet-,not%20unique%20snippet,-of%20text");
}
// Exact selector with context test. Case when available prefix is the
// preceding block, which is a text node.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_PrevTextNodePrefix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -465,12 +514,12 @@ TEST_F(TextFragmentSelectorGeneratorTest,
PlainText(EphemeralRange(selected_start, selected_end)));
VerifySelector(selected_start, selected_end,
- "text-,not%20unique%20snippet,-of");
+ "text-,not%20unique%20snippet,-of%20text");
}
// Exact selector with context test. Case when available suffix is the next
// block.
-TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NextNodeSuffix) {
+TEST_P(TextFragmentSelectorGeneratorTest, ExactTextSelector_NextNodeSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -486,12 +535,13 @@ TEST_F(TextFragmentSelectorGeneratorTest, ExactTextSelector_NextNodeSuffix) {
PlainText(EphemeralRange(selected_start, selected_end)));
VerifySelector(selected_start, selected_end,
- "with-,not%20unique%20snippet,-not");
+ "First%20paragraph%20with-,not%20unique%20snippet,-not%"
+ "20unique%20snippet");
}
// Exact selector with context test. Case when available suffix is the next
// block, which is a text node.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
ExactTextSelector_NexttextNodeSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -509,10 +559,10 @@ TEST_F(TextFragmentSelectorGeneratorTest,
PlainText(EphemeralRange(selected_start, selected_end)));
VerifySelector(selected_start, selected_end,
- "with-,not%20unique%20snippet,-text");
+ "First%20paragraph%20with-,not%20unique%20snippet,-text");
}
-TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector) {
+TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -528,12 +578,13 @@ TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector) {
ASSERT_EQ("First paragraph text that is longer than 20 chars\n\nSecond",
PlainText(EphemeralRange(selected_start, selected_end)));
- VerifySelector(selected_start, selected_end, "First,Second");
+ VerifySelector(selected_start, selected_end,
+ "First%20paragraph%20text,Second");
}
// It should be more than 300 characters selected from the same node so that
// ranges are used.
-TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -556,12 +607,13 @@ text text text text text text text text text text text text text \
text text text text text text text text text and last text",
PlainText(EphemeralRange(selected_start, selected_end)));
- VerifySelector(selected_start, selected_end, "First%20paragraph,last%20text");
+ VerifySelector(selected_start, selected_end,
+ "First%20paragraph%20text,and%20last%20text");
}
// It should be more than 300 characters selected from the same node so that
// ranges are used.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
RangeSelector_SameNode_MultipleSelections) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -587,7 +639,10 @@ text text text text text text text text text text and last text",
ASSERT_EQ(309u,
PlainText(EphemeralRange(selected_start, selected_end)).length());
- VerifySelector(selected_start, selected_end, "First%20paragraph,last%20text");
+ VerifySelector(selected_start, selected_end,
+ "First%20paragraph%20text,and%20last%20text");
+
+ scoped_ukm_recorder_.ResetRecorder();
const auto& second_selected_start = Position(first_paragraph, 6);
const auto& second_selected_end = Position(first_paragraph, 325);
@@ -603,12 +658,12 @@ text text text text text text text text text text and last text",
.length());
VerifySelector(second_selected_start, second_selected_end,
- "paragraph%20text,last%20text");
+ "paragraph%20text%20text,and%20last%20text");
}
// When using all the selected text for the range is not enough for unique
// match, context should be added.
-TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_RangeNotUnique) {
+TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_RangeNotUnique) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -624,12 +679,13 @@ TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_RangeNotUnique) {
ASSERT_EQ("paragraph\n\ntext",
PlainText(EphemeralRange(selected_start, selected_end)));
- VerifySelector(selected_start, selected_end, "First-,paragraph,text,-Second");
+ VerifySelector(selected_start, selected_end,
+ "First-,paragraph,text,-Second%20paragraph");
}
// When using all the selected text for the range is not enough for unique
// match, context should be added, but only prefxi and no suffix is available.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
RangeSelector_RangeNotUnique_NoSuffix) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -652,7 +708,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// When no range end is available it should return empty selector.
// There is no range end available because there is no word break in the second
// half of the selection.
-TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_NoRangeEnd) {
+TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_NoRangeEnd) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -678,7 +734,7 @@ text_text_text_text_text_text_text_text_text_and_last_text",
}
// Selection should be autocompleted to contain full words.
-TEST_F(TextFragmentSelectorGeneratorTest, WordLimit) {
+TEST_P(TextFragmentSelectorGeneratorTest, WordLimit) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -698,7 +754,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, WordLimit) {
// Selection should be autocompleted to contain full words. The autocompletion
// should work with extra spaces.
-TEST_F(TextFragmentSelectorGeneratorTest, WordLimit_ExtraSpaces) {
+TEST_P(TextFragmentSelectorGeneratorTest, WordLimit_ExtraSpaces) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -720,7 +776,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, WordLimit_ExtraSpaces) {
// When selection starts at the end of a word, selection shouldn't be
// autocompleted to contain extra words.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
WordLimit_SelectionStartsAndEndsAtWordLimit) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -740,7 +796,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
}
// Check the case when selections starts with an non text node.
-TEST_F(TextFragmentSelectorGeneratorTest, StartsWithImage) {
+TEST_P(TextFragmentSelectorGeneratorTest, StartsWithImage) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -755,11 +811,11 @@ TEST_F(TextFragmentSelectorGeneratorTest, StartsWithImage) {
const auto& end = Position(first_paragraph, 5);
ASSERT_EQ("\nFirst", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "page-,First,-paragraph");
+ VerifySelector(start, end, "Test%20page-,First,-paragraph%20text%20that");
}
// Check the case when selections starts with an non text node.
-TEST_F(TextFragmentSelectorGeneratorTest, StartsWithBlockWithImage) {
+TEST_P(TextFragmentSelectorGeneratorTest, StartsWithBlockWithImage) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -776,12 +832,12 @@ TEST_F(TextFragmentSelectorGeneratorTest, StartsWithBlockWithImage) {
const auto& end = Position(first_paragraph, 5);
ASSERT_EQ("\nFirst", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "page-,First,-paragraph");
+ VerifySelector(start, end, "Test%20page-,First,-paragraph%20text%20that");
}
// Check the case when selections starts with a node nested in "inline-block"
// node. crbug.com/1151474
-TEST_F(TextFragmentSelectorGeneratorTest, StartsWithInlineBlockChild) {
+TEST_P(TextFragmentSelectorGeneratorTest, StartsWithInlineBlockChild) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -809,15 +865,15 @@ TEST_F(TextFragmentSelectorGeneratorTest, StartsWithInlineBlockChild) {
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
Node* img = GetDocument().getElementById("link1");
Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
- const auto& start = Position(img, PositionAnchorType::kAfterChildren);
+ const auto& start = Position::LastPositionInNode(*img);
const auto& end = Position(first_paragraph, 5);
ASSERT_EQ(" \nFirst", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "page-,First,-paragraph");
+ VerifySelector(start, end, "Test%20page-,First,-paragraph%20text%20that");
}
// Check the case when selections ends with an non text node.
-TEST_F(TextFragmentSelectorGeneratorTest, EndswithImage) {
+TEST_P(TextFragmentSelectorGeneratorTest, EndswithImage) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -833,11 +889,11 @@ TEST_F(TextFragmentSelectorGeneratorTest, EndswithImage) {
const auto& end = Position(img, 0);
ASSERT_EQ("chars\n\n", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "20-,chars");
+ VerifySelector(start, end, "longer%20than%2020-,chars");
}
// Check the case when selections starts at the end of the previous block.
-TEST_F(TextFragmentSelectorGeneratorTest, StartIsEndofPrevBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, StartIsEndofPrevBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -851,11 +907,11 @@ TEST_F(TextFragmentSelectorGeneratorTest, StartIsEndofPrevBlock) {
const auto& end = Position(second_paragraph, 6);
ASSERT_EQ("\nSecond", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "paragraph-,Second,-paragraph");
+ VerifySelector(start, end, "First%20paragraph-,Second,-paragraph");
}
// Check the case when selections starts at the end of the previous block.
-TEST_F(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -869,7 +925,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
const auto& end = Position(second_paragraph, 2);
ASSERT_EQ("First paragraph\n\n", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "First%20paragraph,-Second");
+ VerifySelector(start, end, "First%20paragraph,-Second%20paragraph");
}
// Check the case when parent of selection start is a sibling of a node where
@@ -884,14 +940,12 @@ TEST_F(TextFragmentSelectorGeneratorTest, EndIsStartofNextBlock) {
// Where [] indicate selection. In this case, when the selection is adjusted, we
// want to ensure it correctly traverses the tree back to the previous text node
// and not to the <div>(sibling of second <p>).
-//
-// crbug.com/1154308 - checks the use of Previous instead of
-// PreviousSkippingChildren in TextFragmentSelectorGenerator::AdjustSelection
-TEST_F(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
+// See crbug.com/1154308 for more context.
+TEST_P(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- // HTML is intentionally not formatted. Adding new lines and itendation
+ // HTML is intentionally not formatted. Adding new lines and indentation
// creates empty text nodes which changes the dom tree.
request.Complete(R"HTML(
<!DOCTYPE html>
@@ -904,7 +958,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
const auto& end = Position(second_paragraph, 0);
ASSERT_EQ("First paragraph\n\n", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "First%20paragraph,-Second");
+ VerifySelector(start, end, "First%20paragraph,-Second%20paragraph");
}
// Check the case when parent of selection start is a sibling of a node where
@@ -920,13 +974,11 @@ TEST_F(TextFragmentSelectorGeneratorTest, PrevNodeIsSiblingsChild) {
// Where [] indicate selection. In this case, when the selection is adjusted, we
// want to ensure it correctly traverses the tree back to the previous text by
// correctly skipping the invisible div but not skipping the second <p>.
-//
-// crbug.com/1154308 - checks the use of Previous instead of
-// PreviousSkippingChildren in FindBuffer::BackwardVisibleTextNode
-TEST_F(TextFragmentSelectorGeneratorTest, PrevPrevNodeIsSiblingsChild) {
+// See crbug.com/1154308 for more context.
+TEST_P(TextFragmentSelectorGeneratorTest, PrevPrevNodeIsSiblingsChild) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
- // HTML is intentionally not formatted. Adding new lines and itendation
+ // HTML is intentionally not formatted. Adding new lines and indentation
// creates empty text nodes which changes the dom tree.
request.Complete(R"HTML(
<!DOCTYPE html>
@@ -939,12 +991,12 @@ TEST_F(TextFragmentSelectorGeneratorTest, PrevPrevNodeIsSiblingsChild) {
const auto& end = Position(second_paragraph, 0);
ASSERT_EQ("First paragraph\n\n", PlainText(EphemeralRange(start, end)));
- VerifySelector(start, end, "First%20paragraph,-Second");
+ VerifySelector(start, end, "First%20paragraph,-Second%20paragraph");
}
// Checks that for short selection that have nested block element range selector
// is used.
-TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode_Interrupted) {
+TEST_P(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode_Interrupted) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -960,8 +1012,271 @@ TEST_F(TextFragmentSelectorGeneratorTest, RangeSelector_SameNode_Interrupted) {
VerifySelector(start, end, "First,paragraph");
}
+// Check min number of words is used for context if possible.
+TEST_P(TextFragmentSelectorGeneratorTest, MultiwordContext) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div>Test page</div>
+ <p id='first'>First paragraph text that is longer than 20 chars</p>
+ <p id='second'>Second paragraph text that is short</p>
+ )HTML");
+ Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+ const auto& selected_start = Position(first_paragraph, 6);
+ const auto& selected_end = Position(first_paragraph, 28);
+ ASSERT_EQ("paragraph text that is",
+ PlainText(EphemeralRange(selected_start, selected_end)));
+
+ VerifySelector(selected_start, selected_end,
+ "First-,paragraph%20text%20that%20is,-longer%20than%2020");
+}
+
+// Check min number of words is used for range if possible.
+TEST_P(TextFragmentSelectorGeneratorTest, MultiWordRangeSelector) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div>Test page</div>
+ <p id='first'>First paragraph text that is longer than 20 chars</p>
+ <p id='second'>Second paragraph text</p>
+ )HTML");
+ Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+ Node* second_paragraph = GetDocument().getElementById("second")->firstChild();
+ const auto& selected_start = Position(first_paragraph, 0);
+ const auto& selected_end = Position(second_paragraph, 6);
+ ASSERT_EQ("First paragraph text that is longer than 20 chars\n\nSecond",
+ PlainText(EphemeralRange(selected_start, selected_end)));
+
+ VerifySelector(selected_start, selected_end,
+ "First%20paragraph%20text,Second");
+}
+
+// Checks the case when selection end position is a non text node.
+TEST_P(TextFragmentSelectorGeneratorTest, SelectionEndsWithNonText) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'>
+ <p id='start'>First paragraph</p>
+ <p id='second'>Second paragraph</p>
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* first_paragraph = GetDocument().getElementById("start")->firstChild();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(first_paragraph, 0);
+ const auto& end = Position(div, 2);
+ ASSERT_EQ("First paragraph\n\n", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First%20paragraph,-Second%20paragraph");
+}
+
+// Checks the case when selection end position is a non text node which doesn't
+// have text child node.
+TEST_P(TextFragmentSelectorGeneratorTest,
+ SelectionEndsWithNonTextWithNoTextChild) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'><p id='start'>First paragraph</p><p id='second'>Second paragraph</p><img id="img">
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* first_paragraph = GetDocument().getElementById("start")->firstChild();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(first_paragraph, 0);
+ const auto& end =
+ Position(div, 3); // Points to the 3rd child of the div, which is <img>
+ ASSERT_EQ("First paragraph\n\nSecond paragraph\n\n",
+ PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First%20paragraph,Second%20paragraph");
+}
+
+// Checks the case when selection end position is a non text node which doesn't
+// have text child node.
+TEST_P(TextFragmentSelectorGeneratorTest, SelectionEndsWithImageDiv) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'><p id='start'>First paragraph</p><p id='second'>Second paragraph</p><div id='div_img'><img id="img"></div>
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* first_paragraph = GetDocument().getElementById("start")->firstChild();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(first_paragraph, 0);
+ const auto& end =
+ Position(div, 3); // Points to the 3rd child of the div, which is div_img
+ ASSERT_EQ("First paragraph\n\nSecond paragraph\n\n",
+ PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First%20paragraph,Second%20paragraph");
+}
+
+// Checks the case when selected range contains a range with same start and end.
+// The problematic case should have both range end and suffix.
+TEST_P(TextFragmentSelectorGeneratorTest, OverlappingRange) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='first'>First <div>block text</div>text suffix</div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* start_node = GetDocument().getElementById("first")->firstChild();
+ Node* end_node = GetDocument().getElementById("first")->lastChild();
+ const auto& start = Position(start_node, 0);
+ const auto& end = Position(end_node, 4);
+ ASSERT_EQ("First\nblock text\ntext", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First,text,-suffix");
+}
+
+// Checks selection across table cells.
+TEST_P(TextFragmentSelectorGeneratorTest, Table) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+<table id='table'>
+ <tbody>
+ <tr>
+ <td id='row1-col1'>row1 col1</td>
+ <td id='row1-col2'>row1 col2</td>
+ <td id='row1-col3'>row1 col3</td>
+ </tr>
+ </tbody>
+</table>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* first_paragraph =
+ GetDocument().getElementById("row1-col1")->firstChild();
+ Node* second_paragraph =
+ GetDocument().getElementById("row1-col3")->firstChild();
+ const auto& start = Position(first_paragraph, 0);
+ const auto& end = Position(second_paragraph, 9);
+ ASSERT_EQ("row1 col1\trow1 col2\trow1 col3",
+ PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "row1%20col1,row1%20col3");
+}
+
+// Checks selection across an input element.
+TEST_P(TextFragmentSelectorGeneratorTest, Input) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'>
+ First paragraph<input type='text'> Second paragraph
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(div->firstChild(), 0);
+ const auto& end = Position(div->lastChild(), 7);
+ ASSERT_EQ("First paragraph Second", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First%20paragraph,Second");
+}
+
+// Checks selection across a shadow tree. Input that has text value will create
+// a shadow tree,
+TEST_P(TextFragmentSelectorGeneratorTest, InputSubmit) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'>
+ First paragraph<input type='submit' value="button text"> Second paragraph
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(div->firstChild(), 0);
+ const auto& end = Position(div->lastChild(), 7);
+ ASSERT_EQ("First paragraph Second", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "First%20paragraph,Second");
+}
+
+// Checks selection right after a shadow tree will use the shadow tree for
+// prefix. Input with text value will create a shadow tree.
+TEST_P(TextFragmentSelectorGeneratorTest, InputSubmitPrefix) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'>
+ <input type='submit' value="button text"> paragraph text
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(div->lastChild(), 0);
+ const auto& end = Position(div->lastChild(), 10);
+ ASSERT_EQ(" paragraph", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "button%20text-,paragraph,-text");
+}
+
+// Checks selection right after a shadow tree will use the shadow tree for
+// prefix. Input with text value will create a shadow tree.
+TEST_P(TextFragmentSelectorGeneratorTest, InputSubmitOneWordPrefix) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div id='div'>
+ <input type='submit' value="button"> paragraph text
+ </div>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* div = GetDocument().getElementById("div");
+ const auto& start = Position(div->lastChild(), 0);
+ const auto& end = Position(div->lastChild(), 10);
+ ASSERT_EQ(" paragraph", PlainText(EphemeralRange(start, end)));
+
+ VerifySelector(start, end, "button-,paragraph,-text");
+}
+
+// TODO(crbug.com/1192047): Update the test to better reflect the real repro
+// steps. Test case for crash in crbug.com/1190137. When selector is requested
+// after callback is set and unused.
+TEST_P(TextFragmentSelectorGeneratorTest, SecondGenerationCrash) {
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <p id='p'>First paragraph text</p>
+ )HTML");
+ GetDocument().UpdateStyleAndLayoutTree();
+ Node* p = GetDocument().getElementById("p");
+ const auto& start = Position(p->lastChild(), 0);
+ const auto& end = Position(p->lastChild(), 15);
+ ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
+
+ auto callback = WTF::Bind([](const String& generated_selector) {});
+ GetDocument()
+ .GetFrame()
+ ->GetTextFragmentSelectorGenerator()
+ ->SetCallbackForTesting(std::move(callback));
+
+ // This shouldn't crash.
+ GetDocument().GetFrame()->GetTextFragmentSelectorGenerator()->UpdateSelection(
+ GetDocument().GetFrame(),
+ ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
+ base::RunLoop().RunUntilIdle();
+}
+
// Basic test case for |GetNextTextBlock|.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -980,7 +1295,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock) {
}
// Check the case when available prefix contains collapsible space.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ExtraSpace) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ExtraSpace) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1002,7 +1317,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ExtraSpace) {
// Check the case when available prefix complete text content of the previous
// block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1024,7 +1339,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevNode) {
// Check the case when there is a commented block between selection and the
// available prefix.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetPreviousTextBlock_PrevNode_WithComment) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1050,7 +1365,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when available prefix is a text node outside of selection
// block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevTextNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevTextNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1071,7 +1386,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_PrevTextNode) {
// Check the case when available prefix is a parent node text content outside of
// selection block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ParentNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ParentNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1091,7 +1406,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_ParentNode) {
}
// Check the case when available prefix contains non-block tag(e.g. <b>).
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedTextNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedTextNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1111,7 +1426,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedTextNode) {
}
// Check the case when available prefix is collected until nested block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1131,7 +1446,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetPreviousTextBlock_NestedBlock) {
// Check the case when available prefix includes non-block element but stops at
// nested block.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetPreviousTextBlock_NestedBlockInNestedText) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1151,7 +1466,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
}
// Check the case when available prefix includes invisible block.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetPreviousTextBlock_NestedInvisibleBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1172,7 +1487,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when previous node is used for available prefix when selection
// is not at index=0 but there is only space before it.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetPreviousTextBlock_SpacesBeforeSelection) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1197,7 +1512,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when previous node is used for available prefix when selection
// is not at index=0 but there is only invisible block.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetPreviousTextBlock_InvisibleBeforeSelection) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1227,7 +1542,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Similar test for suffix.
// Basic test case for |GetNextTextBlock|.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1246,7 +1561,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock) {
}
// Check the case when available suffix contains collapsible space.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ExtraSpace) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ExtraSpace) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1269,7 +1584,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ExtraSpace) {
// Check the case when available suffix is complete text content of the next
// block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1290,7 +1605,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextNode) {
// Check the case when there is a commented block between selection and the
// available suffix.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_NextNode_WithComment) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1315,7 +1630,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when available suffix is a text node outside of selection
// block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextTextNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextTextNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1336,7 +1651,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NextTextNode) {
// Check the case when available suffix is a parent node text content outside of
// selection block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ParentNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ParentNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1355,7 +1670,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_ParentNode) {
}
// Check the case when available suffix contains non-block tag(e.g. <b>).
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedTextNode) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedTextNode) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1374,7 +1689,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedTextNode) {
}
// Check the case when available suffix is collected until nested block.
-TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedBlock) {
+TEST_P(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
@@ -1394,7 +1709,7 @@ TEST_F(TextFragmentSelectorGeneratorTest, GetNextTextBlock_NestedBlock) {
// Check the case when available suffix includes non-block element but stops at
// nested block.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_NestedBlockInNestedText) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1414,7 +1729,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
}
// Check the case when available suffix includes invisible block.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_NestedInvisibleBlock) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1435,7 +1750,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when next node is used for available suffix when selection is
// not at last index but there is only space after it.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_SpacesAfterSelection) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1461,7 +1776,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when next node is used for available suffix when selection is
// not at last index but there is only invisible block after it.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_InvisibleAfterSelection) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1491,7 +1806,7 @@ TEST_F(TextFragmentSelectorGeneratorTest,
// Check the case when previous node is used for available prefix when selection
// is not at last index but there is only invisible block. Invisible block
// contains another block which also should be invisible.
-TEST_F(TextFragmentSelectorGeneratorTest,
+TEST_P(TextFragmentSelectorGeneratorTest,
GetNextTextBlock_InvisibleAfterSelection_WithNestedInvisible) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -1528,68 +1843,50 @@ TEST_F(TextFragmentSelectorGeneratorTest,
->GetNextTextBlockForTesting(end));
}
-// Checks that selection in the same text node is considerered uninterrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
- IsInSameUninterruptedBlock_OneTextNode) {
- SimRequest request("https://example.com/test.html", "text/html");
- LoadURL("https://example.com/test.html");
- request.Complete(R"HTML(
- <!DOCTYPE html>
- <div id='first'>First paragraph text</div>
- )HTML");
- Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
- const auto& start = Position(first_paragraph, 0);
- const auto& end = Position(first_paragraph, 15);
- ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
-
- EXPECT_TRUE(GetDocument()
- .GetFrame()
- ->GetTextFragmentSelectorGenerator()
- ->IsInSameUninterruptedBlockForTesting(start, end));
-}
-
-// Checks that selection in the same text node with nested non-block element is
-// considerered uninterrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
- IsInSameUninterruptedBlock_NonBlockInterruption) {
+TEST_P(TextFragmentSelectorGeneratorTest, CheckMetrics_Success) {
+ base::test::ScopedFeatureList feature_list;
+ // Basic exact selector case.
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
<!DOCTYPE html>
- <div id='first'>First <i>styled text</i> paragraph text</div>
+ <div>Test page</div>
+ <p id='first'>First paragraph text that is longer than 20 chars</p>
+ <p id='second'>Second paragraph text</p>
)HTML");
Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
- const auto& start = Position(first_paragraph, 0);
- const auto& end = Position(first_paragraph->nextSibling()->nextSibling(), 10);
- ASSERT_EQ("First styled text paragraph",
- PlainText(EphemeralRange(start, end)));
+ const auto& selected_start = Position(first_paragraph, 0);
+ const auto& selected_end = Position(first_paragraph, 28);
+ ASSERT_EQ("First paragraph text that is",
+ PlainText(EphemeralRange(selected_start, selected_end)));
- EXPECT_TRUE(GetDocument()
- .GetFrame()
- ->GetTextFragmentSelectorGenerator()
- ->IsInSameUninterruptedBlockForTesting(start, end));
+ VerifySelector(selected_start, selected_end,
+ "First%20paragraph%20text%20that%20is");
+ VerifyPreemptiveGenerationMetrics(true);
}
-// Checks that selection in the same text node with nested block element is
-// considerered interrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
- IsInSameUninterruptedBlock_BlockInterruption) {
+TEST_P(TextFragmentSelectorGeneratorTest, CheckMetrics_Failure) {
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
<!DOCTYPE html>
- <div id='first'>First <div>block text</div> paragraph text</div>
+ <div>Test page</div>
+ <p id='first'>First paragraph prefix one two three four five six seven
+ eight nine ten to not unique snippet of text followed by suffix</p>
+ <p id='second'>Second paragraph prefix one two three four five six seven
+ eight nine ten to not unique snippet of text followed by suffix</p>
)HTML");
Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
- const auto& start = Position(first_paragraph, 0);
- const auto& end = Position(first_paragraph->nextSibling()->nextSibling(), 10);
- ASSERT_EQ("First\nblock text\nparagraph",
- PlainText(EphemeralRange(start, end)));
-
- EXPECT_FALSE(GetDocument()
- .GetFrame()
- ->GetTextFragmentSelectorGenerator()
- ->IsInSameUninterruptedBlockForTesting(start, end));
+ const auto& selected_start = Position(first_paragraph, 80);
+ const auto& selected_end = Position(first_paragraph, 106);
+ ASSERT_EQ("not unique snippet of text",
+ PlainText(EphemeralRange(selected_start, selected_end)));
+ VerifySelectorFails(selected_start, selected_end,
+ LinkGenerationError::kContextLimitReached);
+ VerifyPreemptiveGenerationMetrics(false);
}
+INSTANTIATE_TEST_SUITE_P(All,
+ TextFragmentSelectorGeneratorTest,
+ ::testing::Bool());
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc b/chromium/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
index 465990a5f20..1c61fb78468 100644
--- a/chromium/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
@@ -65,7 +65,6 @@ void SlotScopedTraversalTest::AttachOpenShadowRoot(
ShadowRoot& shadow_root =
shadow_host.AttachShadowRootInternal(ShadowRootType::kOpen);
shadow_root.setInnerHTML(String::FromUTF8(shadow_inner_html));
- GetDocument().body()->UpdateDistributionForFlatTreeTraversal();
}
TEST_F(SlotScopedTraversalTest, emptySlot) {
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index 781ca460235..505f8954348 100644
--- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
@@ -220,7 +221,8 @@ bool SpatialNavigationController::HandleEnterKeyboardEvent(
mojom::blink::FocusType::kSpatialNavigation, nullptr));
// We need enter to activate links, etc. The click should be after the
// focus in case the site transfers focus upon clicking.
- interest_element->DispatchSimulatedClick(event, kSendMouseUpDownEvents);
+ interest_element->DispatchSimulatedClick(
+ event, SimulatedClickCreationScope::kFromAccessibility);
}
}
diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
index 6ad77be97a7..52663c0f7c3 100644
--- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -784,6 +784,9 @@ TEST_F(SpatialNavigationTest, InlineImageLinkWithLineHeight) {
}
TEST_F(SpatialNavigationTest, InlineImageTextLinkWithLineHeight) {
+ // Fails when LayoutNG is disabled. See crbug.com/1160211
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(
"<!DOCTYPE html>"
@@ -809,6 +812,9 @@ TEST_F(SpatialNavigationTest, InlineImageTextLinkWithLineHeight) {
}
TEST_F(SpatialNavigationTest, InlineLinkWithInnerBlock) {
+ // Fails when LayoutNG is disabled. See crbug.com/1160211
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(
"<!DOCTYPE html>"
@@ -954,6 +960,9 @@ TEST_F(SpatialNavigationTest, NormalizedLineBrokenLink) {
}
TEST_F(SpatialNavigationTest, NormalizedLineBrokenLinkWithImg) {
+ // Fails when LayoutNG is disabled. See crbug.com/1160211
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(
"<!DOCTYPE html>"
diff --git a/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc b/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
index 5ec652f841c..795e520ee5c 100644
--- a/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/touch_adjustment_test.cc
@@ -20,7 +20,9 @@ class FakeChromeClient : public RenderingTestChromeClient {
screen_info_.device_scale_factor = device_scale_factor;
}
- ScreenInfo GetScreenInfo(LocalFrame&) const override { return screen_info_; }
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return screen_info_;
+ }
private:
ScreenInfo screen_info_;
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
index 7e5b29d8864..e5514582e10 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc
@@ -109,14 +109,15 @@ void ValidationMessageClientImpl::HideValidationMessage(const Element& anchor) {
}
DCHECK(overlay_);
overlay_delegate_->StartToHide();
- timer_ = std::make_unique<TaskRunnerTimer<ValidationMessageClientImpl>>(
+ timer_ = MakeGarbageCollected<
+ DisallowNewWrapper<HeapTaskRunnerTimer<ValidationMessageClientImpl>>>(
anchor.GetDocument().GetTaskRunner(TaskType::kInternalDefault), this,
&ValidationMessageClientImpl::Reset);
// This should be equal to or larger than transition duration of
// #container.hiding in validation_bubble.css.
const base::TimeDelta kHidingAnimationDuration =
base::TimeDelta::FromSecondsD(0.13333);
- timer_->StartOneShot(kHidingAnimationDuration, FROM_HERE);
+ timer_->Value().StartOneShot(kHidingAnimationDuration, FROM_HERE);
}
void ValidationMessageClientImpl::HideValidationMessageImmediately(
@@ -129,6 +130,9 @@ void ValidationMessageClientImpl::HideValidationMessageImmediately(
void ValidationMessageClientImpl::Reset(TimerBase*) {
const Element& anchor = *current_anchor_;
+ // Clearing out the pointer does not stop the timer.
+ if (timer_)
+ timer_->Value().Stop();
timer_ = nullptr;
current_anchor_ = nullptr;
message_ = String();
@@ -220,6 +224,7 @@ void ValidationMessageClientImpl::PaintOverlay(GraphicsContext& context) {
void ValidationMessageClientImpl::Trace(Visitor* visitor) const {
visitor->Trace(page_);
visitor->Trace(current_anchor_);
+ visitor->Trace(timer_);
ValidationMessageClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
index 07b29f8a065..2293a2d2c57 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/page/popup_opening_observer.h"
#include "third_party/blink/renderer/core/page/validation_message_client.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -85,7 +86,8 @@ class CORE_EXPORT ValidationMessageClientImpl final
Member<const Element> current_anchor_;
String message_;
base::TimeTicks finish_time_;
- std::unique_ptr<TimerBase> timer_;
+ Member<DisallowNewWrapper<HeapTaskRunnerTimer<ValidationMessageClientImpl>>>
+ timer_;
std::unique_ptr<FrameOverlay> overlay_;
// Raw pointer. This pointer is valid unless overlay_ is nullptr.
ValidationMessageOverlayDelegate* overlay_delegate_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
index 87a3dd369dd..a3c2628e235 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/resources/grit/blink_resources.h"
#include "third_party/blink/renderer/core/dom/dom_token_list.h"
#include "third_party/blink/renderer/core/dom/element.h"
@@ -111,7 +112,7 @@ void ValidationMessageOverlayDelegate::PaintFrameOverlay(
// The overlay frame is has a standalone paint property tree. Paint it in
// its root space into a paint record, then draw the record into the proper
// target space in the overlaid frame.
- PaintRecordBuilder paint_record_builder(nullptr, &context);
+ PaintRecordBuilder paint_record_builder(context);
FrameView().PaintOutsideOfLifecycle(paint_record_builder.Context(),
kGlobalPaintNormalPhase);
context.DrawRecord(paint_record_builder.EndRecording());
@@ -153,15 +154,16 @@ void ValidationMessageOverlayDelegate::CreatePage(const FrameOverlay& overlay) {
main_page_->GetChromeClient(), anchor_->GetDocument().View());
page_clients.chrome_client = chrome_client_;
Settings& main_settings = main_page_->GetSettings();
- page_ = Page::CreateNonOrdinary(page_clients);
+ page_ = Page::CreateNonOrdinary(
+ page_clients, main_page_->GetPageScheduler()->GetAgentGroupScheduler());
page_->GetSettings().SetMinimumFontSize(main_settings.GetMinimumFontSize());
page_->GetSettings().SetMinimumLogicalFontSize(
main_settings.GetMinimumLogicalFontSize());
auto* frame = MakeGarbageCollected<LocalFrame>(
MakeGarbageCollected<EmptyLocalFrameClient>(), *page_, nullptr, nullptr,
- nullptr, FrameInsertType::kInsertInConstructor,
- base::UnguessableToken::Create(), nullptr, nullptr,
+ nullptr, FrameInsertType::kInsertInConstructor, LocalFrameToken(),
+ nullptr, nullptr,
/* policy_container */ nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame, view_size));
frame->Init(nullptr);
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc
index b44defbcfb9..dba5877f8f1 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc
@@ -34,7 +34,7 @@ class ValidationMessageOverlayDelegateTest : public PaintTestConfigurations,
// an extra step is required to ensure that the system font is configured.
// See https://crbug.com/969622
blink::WebFontRendering::SetMenuFontMetrics(
- base::ASCIIToUTF16("Arial").c_str(), 12);
+ blink::WebString::FromASCII("Arial"), 12);
}
#endif
};
diff --git a/chromium/third_party/blink/renderer/core/page/viewport_test.cc b/chromium/third_party/blink/renderer/core/page/viewport_test.cc
index 125d46388fa..8c50727249d 100644
--- a/chromium/third_party/blink/renderer/core/page/viewport_test.cc
+++ b/chromium/third_party/blink/renderer/core/page/viewport_test.cc
@@ -138,8 +138,7 @@ TEST_F(ViewportTest, viewport1) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-1.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -157,8 +156,7 @@ TEST_F(ViewportTest, viewport2) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-2.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -176,8 +174,7 @@ TEST_F(ViewportTest, viewport3) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-3.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -195,8 +192,7 @@ TEST_F(ViewportTest, viewport4) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-4.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -214,8 +210,7 @@ TEST_F(ViewportTest, viewport5) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-5.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -233,8 +228,7 @@ TEST_F(ViewportTest, viewport6) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-6.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -252,8 +246,7 @@ TEST_F(ViewportTest, viewport7) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-7.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -271,8 +264,7 @@ TEST_F(ViewportTest, viewport8) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-8.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -290,8 +282,7 @@ TEST_F(ViewportTest, viewport9) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-9.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -309,8 +300,7 @@ TEST_F(ViewportTest, viewport10) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-10.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -328,8 +318,7 @@ TEST_F(ViewportTest, viewport11) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-11.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -347,8 +336,7 @@ TEST_F(ViewportTest, viewport12) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-12.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -366,8 +354,7 @@ TEST_F(ViewportTest, viewport13) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-13.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -385,8 +372,7 @@ TEST_F(ViewportTest, viewport14) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-14.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -404,8 +390,7 @@ TEST_F(ViewportTest, viewport15) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-15.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -423,8 +408,7 @@ TEST_F(ViewportTest, viewport16) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-16.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -442,8 +426,7 @@ TEST_F(ViewportTest, viewport17) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-17.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -461,8 +444,7 @@ TEST_F(ViewportTest, viewport18) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-18.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -480,8 +462,7 @@ TEST_F(ViewportTest, viewport19) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-19.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -499,8 +480,7 @@ TEST_F(ViewportTest, viewport20) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-20.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -518,8 +498,7 @@ TEST_F(ViewportTest, viewport21) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-21.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -537,8 +516,7 @@ TEST_F(ViewportTest, viewport22) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-22.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -556,8 +534,7 @@ TEST_F(ViewportTest, viewport23) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-23.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -575,8 +552,7 @@ TEST_F(ViewportTest, viewport24) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-24.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -594,8 +570,7 @@ TEST_F(ViewportTest, viewport25) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-25.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -613,8 +588,7 @@ TEST_F(ViewportTest, viewport26) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-26.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -632,8 +606,7 @@ TEST_F(ViewportTest, viewport27) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-27.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -651,8 +624,7 @@ TEST_F(ViewportTest, viewport28) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-28.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -670,8 +642,7 @@ TEST_F(ViewportTest, viewport29) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-29.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -689,8 +660,7 @@ TEST_F(ViewportTest, viewport30) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-30.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -708,8 +678,7 @@ TEST_F(ViewportTest, viewport31) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-31.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -727,8 +696,7 @@ TEST_F(ViewportTest, viewport32) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-32.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -746,8 +714,7 @@ TEST_F(ViewportTest, viewport33) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-33.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -765,8 +732,7 @@ TEST_F(ViewportTest, viewport34) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-34.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -784,8 +750,7 @@ TEST_F(ViewportTest, viewport35) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-35.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -803,8 +768,7 @@ TEST_F(ViewportTest, viewport36) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-36.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -822,8 +786,7 @@ TEST_F(ViewportTest, viewport37) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-37.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -841,8 +804,7 @@ TEST_F(ViewportTest, viewport38) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-38.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -860,8 +822,7 @@ TEST_F(ViewportTest, viewport39) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-39.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -879,8 +840,7 @@ TEST_F(ViewportTest, viewport40) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-40.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -898,8 +858,7 @@ TEST_F(ViewportTest, viewport41) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-41.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -917,8 +876,7 @@ TEST_F(ViewportTest, viewport42) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-42.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -936,8 +894,7 @@ TEST_F(ViewportTest, viewport43) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-43.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -955,8 +912,7 @@ TEST_F(ViewportTest, viewport44) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-44.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -974,8 +930,7 @@ TEST_F(ViewportTest, viewport45) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-45.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -993,8 +948,7 @@ TEST_F(ViewportTest, viewport46) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-46.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1012,8 +966,7 @@ TEST_F(ViewportTest, viewport47) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-47.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1031,8 +984,7 @@ TEST_F(ViewportTest, viewport48) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-48.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1050,8 +1002,7 @@ TEST_F(ViewportTest, viewport49) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-49.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1069,8 +1020,7 @@ TEST_F(ViewportTest, viewport50) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-50.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1088,8 +1038,7 @@ TEST_F(ViewportTest, viewport51) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-51.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1107,8 +1056,7 @@ TEST_F(ViewportTest, viewport52) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-52.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1126,8 +1074,7 @@ TEST_F(ViewportTest, viewport53) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-53.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1145,8 +1092,7 @@ TEST_F(ViewportTest, viewport54) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-54.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1164,8 +1110,7 @@ TEST_F(ViewportTest, viewport55) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-55.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1183,8 +1128,7 @@ TEST_F(ViewportTest, viewport56) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-56.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1202,8 +1146,7 @@ TEST_F(ViewportTest, viewport57) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-57.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1221,8 +1164,7 @@ TEST_F(ViewportTest, viewport58) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-58.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1240,8 +1182,7 @@ TEST_F(ViewportTest, viewport59) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-59.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1259,8 +1200,7 @@ TEST_F(ViewportTest, viewport60) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-60.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1278,8 +1218,7 @@ TEST_F(ViewportTest, viewport61) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-61.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1297,8 +1236,7 @@ TEST_F(ViewportTest, viewport62) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-62.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1316,8 +1254,7 @@ TEST_F(ViewportTest, viewport63) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-63.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1335,8 +1272,7 @@ TEST_F(ViewportTest, viewport64) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-64.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1354,8 +1290,7 @@ TEST_F(ViewportTest, viewport65) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-65.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1373,8 +1308,7 @@ TEST_F(ViewportTest, viewport66) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-66.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1392,8 +1326,7 @@ TEST_F(ViewportTest, viewport67) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-67.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1411,8 +1344,7 @@ TEST_F(ViewportTest, viewport68) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-68.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1430,8 +1362,7 @@ TEST_F(ViewportTest, viewport69) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-69.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1449,8 +1380,7 @@ TEST_F(ViewportTest, viewport70) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-70.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1468,8 +1398,7 @@ TEST_F(ViewportTest, viewport71) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-71.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1487,8 +1416,7 @@ TEST_F(ViewportTest, viewport72) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-72.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1506,8 +1434,7 @@ TEST_F(ViewportTest, viewport73) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-73.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1525,8 +1452,7 @@ TEST_F(ViewportTest, viewport74) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-74.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1544,8 +1470,7 @@ TEST_F(ViewportTest, viewport75) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-75.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1563,8 +1488,7 @@ TEST_F(ViewportTest, viewport76) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-76.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1582,8 +1506,7 @@ TEST_F(ViewportTest, viewport77) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-77.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1601,8 +1524,7 @@ TEST_F(ViewportTest, viewport78) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-78.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1620,8 +1542,7 @@ TEST_F(ViewportTest, viewport79) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-79.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1639,8 +1560,7 @@ TEST_F(ViewportTest, viewport80) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-80.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1658,8 +1578,7 @@ TEST_F(ViewportTest, viewport81) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-81.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1677,8 +1596,7 @@ TEST_F(ViewportTest, viewport82) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-82.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1696,8 +1614,7 @@ TEST_F(ViewportTest, viewport83) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-83.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1715,8 +1632,7 @@ TEST_F(ViewportTest, viewport84) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-84.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1734,8 +1650,7 @@ TEST_F(ViewportTest, viewport85) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-85.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1753,8 +1668,7 @@ TEST_F(ViewportTest, viewport86) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-86.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1772,8 +1686,7 @@ TEST_F(ViewportTest, viewport87) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-87.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1791,8 +1704,7 @@ TEST_F(ViewportTest, viewport88) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-88.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1810,8 +1722,7 @@ TEST_F(ViewportTest, viewport90) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-90.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1829,8 +1740,7 @@ TEST_F(ViewportTest, viewport100) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-100.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1848,8 +1758,7 @@ TEST_F(ViewportTest, viewport101) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-101.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1867,8 +1776,7 @@ TEST_F(ViewportTest, viewport102) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-102.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1886,8 +1794,7 @@ TEST_F(ViewportTest, viewport103) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-103.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1905,8 +1812,7 @@ TEST_F(ViewportTest, viewport104) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-104.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1924,8 +1830,7 @@ TEST_F(ViewportTest, viewport105) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-105.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1943,8 +1848,7 @@ TEST_F(ViewportTest, viewport106) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-106.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1962,8 +1866,7 @@ TEST_F(ViewportTest, viewport107) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-107.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -1981,8 +1884,7 @@ TEST_F(ViewportTest, viewport108) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-108.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2000,8 +1902,7 @@ TEST_F(ViewportTest, viewport109) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-109.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2019,8 +1920,7 @@ TEST_F(ViewportTest, viewport110) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-110.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2038,8 +1938,7 @@ TEST_F(ViewportTest, viewport111) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-111.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2057,8 +1956,7 @@ TEST_F(ViewportTest, viewport112) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-112.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2076,8 +1974,7 @@ TEST_F(ViewportTest, viewport113) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-113.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2095,8 +1992,7 @@ TEST_F(ViewportTest, viewport114) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-114.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2114,8 +2010,7 @@ TEST_F(ViewportTest, viewport115) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-115.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2133,8 +2028,7 @@ TEST_F(ViewportTest, viewport116) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-116.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2152,8 +2046,7 @@ TEST_F(ViewportTest, viewport117) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-117.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2171,8 +2064,7 @@ TEST_F(ViewportTest, viewport118) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-118.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2190,8 +2082,7 @@ TEST_F(ViewportTest, viewport119) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-119.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2209,8 +2100,7 @@ TEST_F(ViewportTest, viewport120) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-120.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2228,8 +2118,7 @@ TEST_F(ViewportTest, viewport121) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-121.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2247,8 +2136,7 @@ TEST_F(ViewportTest, viewport122) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-122.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2266,8 +2154,7 @@ TEST_F(ViewportTest, viewport123) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-123.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2285,8 +2172,7 @@ TEST_F(ViewportTest, viewport124) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-124.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2304,8 +2190,7 @@ TEST_F(ViewportTest, viewport125) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-125.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2323,8 +2208,7 @@ TEST_F(ViewportTest, viewport126) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-126.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2342,8 +2226,7 @@ TEST_F(ViewportTest, viewport127) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-127.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2361,8 +2244,7 @@ TEST_F(ViewportTest, viewport129) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-129.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2380,8 +2262,7 @@ TEST_F(ViewportTest, viewport130) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-130.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2399,8 +2280,7 @@ TEST_F(ViewportTest, viewport131) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-131.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2418,8 +2298,7 @@ TEST_F(ViewportTest, viewport132) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-132.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2437,8 +2316,7 @@ TEST_F(ViewportTest, viewport133) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-133.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2456,8 +2334,7 @@ TEST_F(ViewportTest, viewport134) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-134.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2475,8 +2352,7 @@ TEST_F(ViewportTest, viewport135) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-135.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2494,8 +2370,7 @@ TEST_F(ViewportTest, viewport136) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-136.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2513,8 +2388,7 @@ TEST_F(ViewportTest, viewport137) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-137.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2532,8 +2406,7 @@ TEST_F(ViewportTest, viewport138) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(base_url_ + "viewport/viewport-138.html",
- nullptr, nullptr, nullptr,
- SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2552,7 +2425,7 @@ TEST_F(ViewportTest, viewportLegacyHandheldFriendly) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-handheldfriendly.html", nullptr,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2578,7 +2451,7 @@ TEST_F(ViewportTest, viewportLegacyMergeQuirk1) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-merge-quirk-1.html", nullptr,
- nullptr, nullptr, SetQuirkViewportSettings);
+ nullptr, SetQuirkViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2597,7 +2470,7 @@ TEST_F(ViewportTest, viewportLegacyMergeQuirk2) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-merge-quirk-2.html", nullptr,
- nullptr, nullptr, SetQuirkViewportSettings);
+ nullptr, SetQuirkViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2619,7 +2492,7 @@ TEST_F(ViewportTest, viewportLegacyMobileOptimizedMetaWithoutContent) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-mobileoptimized.html", nullptr,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2639,7 +2512,7 @@ TEST_F(ViewportTest, viewportLegacyMobileOptimizedMetaWith0) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-mobileoptimized-2.html", nullptr,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2659,7 +2532,7 @@ TEST_F(ViewportTest, viewportLegacyMobileOptimizedMetaWith400) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-mobileoptimized-2.html", nullptr,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2679,7 +2552,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering2) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-2.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2699,7 +2572,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering3) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-3.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2719,7 +2592,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering4) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-4.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2739,7 +2612,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering5) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-5.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2759,7 +2632,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering6) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-6.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2779,7 +2652,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering7) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-7.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2799,7 +2672,7 @@ TEST_F(ViewportTest, viewportLegacyOrdering8) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-ordering-8.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2819,7 +2692,7 @@ TEST_F(ViewportTest, viewportLegacyDefaultValueChangedByXHTMLMP) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-xhtmlmp.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2840,7 +2713,7 @@ TEST_F(ViewportTest,
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-xhtmlmp-misplaced-doctype.html",
- nullptr, nullptr, nullptr, SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2859,7 +2732,7 @@ TEST_F(ViewportTest, viewportLegacyXHTMLMPOrdering) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-xhtmlmp-ordering.html", nullptr,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2878,7 +2751,7 @@ TEST_F(ViewportTest, viewportLegacyXHTMLMPRemoveAndAdd) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-legacy-xhtmlmp.html", nullptr, nullptr,
- nullptr, SetViewportSettings);
+ SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2923,7 +2796,7 @@ TEST_F(ViewportTest, viewportLimitsAdjustedForNoUserScale) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-limits-adjusted-for-no-user-scale.html",
- nullptr, nullptr, nullptr, SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
web_view_helper.GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
DocumentUpdateReason::kTest);
@@ -2942,7 +2815,7 @@ TEST_F(ViewportTest, viewportLimitsAdjustedForUserScale) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-limits-adjusted-for-user-scale.html",
- nullptr, nullptr, nullptr, SetViewportSettings);
+ nullptr, nullptr, SetViewportSettings);
web_view_helper.GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
DocumentUpdateReason::kTest);
Page* page = web_view_helper.GetWebView()->GetPage();
@@ -2974,7 +2847,7 @@ TEST_F(ViewportTest, viewportWarnings1) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-1.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -2997,7 +2870,7 @@ TEST_F(ViewportTest, viewportWarnings2) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-2.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -3024,7 +2897,7 @@ TEST_F(ViewportTest, viewportWarnings3) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-3.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -3053,7 +2926,7 @@ TEST_F(ViewportTest, viewportWarnings4) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-4.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -3082,7 +2955,7 @@ TEST_F(ViewportTest, viewportWarnings5) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-5.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -3112,7 +2985,7 @@ TEST_F(ViewportTest, viewportWarnings6) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-6.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
PageScaleConstraints constraints = RunViewportTest(page, 320, 352);
@@ -3140,7 +3013,7 @@ TEST_F(ViewportTest, viewportWarnings7) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-7.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
RunViewportTest(page, 320, 352);
@@ -3156,7 +3029,7 @@ TEST_F(ViewportTest, viewportWarnings8) {
frame_test_helpers::WebViewHelper web_view_helper;
web_view_helper.InitializeAndLoad(
base_url_ + "viewport/viewport-warnings-8.html", &web_frame_client,
- nullptr, nullptr, SetViewportSettings);
+ nullptr, SetViewportSettings);
Page* page = web_view_helper.GetWebView()->GetPage();
RunViewportTest(page, 320, 352);
diff --git a/chromium/third_party/blink/renderer/core/paint/DEPS b/chromium/third_party/blink/renderer/core/paint/DEPS
index a58190f2032..00b071d198a 100644
--- a/chromium/third_party/blink/renderer/core/paint/DEPS
+++ b/chromium/third_party/blink/renderer/core/paint/DEPS
@@ -4,12 +4,14 @@ include_rules = [
"+cc/layers/picture_layer.h",
# For DCHECK.
"+base/logging.h",
+ "+components/shared_highlighting/core/common",
]
specific_include_rules = {
- "(theme_painter|object_painter_base)\.cc": [
+ "(theme_painter|theme_painter_default|object_painter_base)\.cc": [
"+ui/native_theme/native_theme.h",
"+ui/native_theme/native_theme_base.h",
+ "+ui/gfx/color_utils.h"
],
".*test\.cc": [
"+base/test/trace_event_analyzer.h",
diff --git a/chromium/third_party/blink/renderer/core/paint/DIR_METADATA b/chromium/third_party/blink/renderer/core/paint/DIR_METADATA
new file mode 100644
index 00000000000..5dec41099a2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Paint"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/paint/OWNERS b/chromium/third_party/blink/renderer/core/paint/OWNERS
index d4b697b55dc..51aafa98fea 100644
--- a/chromium/third_party/blink/renderer/core/paint/OWNERS
+++ b/chromium/third_party/blink/renderer/core/paint/OWNERS
@@ -9,6 +9,3 @@ schenney@chromium.org
senorblanco@chromium.org
trchen@chromium.org
wangxianzhu@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Paint
diff --git a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 2f6a47972cb..7b8eaf5b893 100644
--- a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -306,16 +306,15 @@ PhysicalOffset BackgroundImageGeometry::GetPositioningOffsetForCell(
cell.Table()->BorderBefore() - height_of_captions) +
cell.Location().Y());
- DCHECK(positioning_box.IsLayoutTableCol());
- if (ToLayoutTableCol(positioning_box).IsTableColumn()) {
+ const auto& table_col = To<LayoutTableCol>(positioning_box);
+ if (table_col.IsTableColumn()) {
offset_in_background.top -= v_border_spacing;
return offset_in_background;
}
- DCHECK(ToLayoutTableCol(positioning_box).IsTableColumnGroup());
+ DCHECK(table_col.IsTableColumnGroup());
LayoutUnit offset = offset_in_background.left;
- ExpandToTableColumnGroup(cell, ToLayoutTableCol(positioning_box), offset,
- kColumnGroupStart);
+ ExpandToTableColumnGroup(cell, table_col, offset, kColumnGroupStart);
offset_in_background.left += offset;
offset_in_background.top -= v_border_spacing;
return offset_in_background;
@@ -343,15 +342,14 @@ PhysicalSize BackgroundImageGeometry::GetBackgroundObjectDimensions(
LayoutUnit column_height = sections_rect.Height() -
cell.Table()->BorderBefore() -
border_spacing.height - border_spacing.height;
- if (ToLayoutTableCol(positioning_box).IsTableColumn())
+ const auto& table_col = To<LayoutTableCol>(positioning_box);
+ if (table_col.IsTableColumn())
return PhysicalSize(cell.Size().Width(), column_height);
- DCHECK(ToLayoutTableCol(positioning_box).IsTableColumnGroup());
+ DCHECK(table_col.IsTableColumnGroup());
LayoutUnit width = cell.Size().Width();
- ExpandToTableColumnGroup(cell, ToLayoutTableCol(positioning_box), width,
- kColumnGroupStart);
- ExpandToTableColumnGroup(cell, ToLayoutTableCol(positioning_box), width,
- kColumnGroupEnd);
+ ExpandToTableColumnGroup(cell, table_col, width, kColumnGroupStart);
+ ExpandToTableColumnGroup(cell, table_col, width, kColumnGroupEnd);
return PhysicalSize(width, column_height);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
index 1e45914fe76..d060df86a42 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_invalidator.h"
namespace blink {
@@ -47,12 +46,6 @@ void BlockFlowPaintInvalidator::InvalidateDisplayItemClients(
ObjectPaintInvalidator object_paint_invalidator(block_flow_);
object_paint_invalidator.InvalidateDisplayItemClient(block_flow_, reason);
- const NGPaintFragment* paint_fragment = block_flow_.PaintFragment();
- if (paint_fragment) {
- object_paint_invalidator.InvalidateDisplayItemClient(*paint_fragment,
- reason);
- }
-
NGInlineCursor cursor(block_flow_);
if (cursor) {
// Line boxes record hit test data (see NGBoxFragmentPainter::PaintLineBox)
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter.cc b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
index 3d98e467706..652d4bc55eb 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
@@ -329,11 +329,10 @@ void BlockPainter::PaintCarets(const PaintInfo& paint_info,
}
}
-PhysicalRect BlockPainter::OverflowRectForCullRectTesting(
- bool is_printing) const {
+PhysicalRect BlockPainter::OverflowRectForCullRectTesting() const {
PhysicalRect overflow_rect;
- if (is_printing && layout_block_.IsAnonymousBlock() &&
- layout_block_.ChildrenInline()) {
+ if (layout_block_.IsAnonymousBlock() && layout_block_.ChildrenInline() &&
+ layout_block_.GetDocument().Printing()) {
// For case <a href="..."><div>...</div></a>, when layout_block_ is the
// anonymous container of <a>, the anonymous container's visual overflow is
// empty, but we need to continue painting to output <a>'s PDF URL rect
@@ -369,7 +368,7 @@ bool BlockPainter::ShouldPaint(const ScopedPaintState& paint_state) const {
return true;
return paint_state.LocalRectIntersectsCullRect(
- OverflowRectForCullRectTesting(paint_state.GetPaintInfo().IsPrinting()));
+ OverflowRectForCullRectTesting());
}
void BlockPainter::PaintContents(const PaintInfo& paint_info,
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter.h b/chromium/third_party/blink/renderer/core/paint/block_painter.h
index 40d7dac7750..faa3bad3888 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter.h
@@ -44,8 +44,7 @@ class BlockPainter {
bool ShouldPaint(const ScopedPaintState&) const;
- CORE_EXPORT PhysicalRect
- OverflowRectForCullRectTesting(bool is_printing) const;
+ CORE_EXPORT PhysicalRect OverflowRectForCullRectTesting() const;
FRIEND_TEST_ALL_PREFIXES(BlockPainterTest, OverflowRectForCullRectTesting);
FRIEND_TEST_ALL_PREFIXES(BlockPainterTest,
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
index da979a4b2ea..c9906300cb6 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -34,10 +34,10 @@ TEST_P(BlockPainterTest, OverflowRectForCullRectTesting) {
auto* scroller = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(PhysicalRect(0, 0, 50, 5000),
- BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+ BlockPainter(*scroller).OverflowRectForCullRectTesting());
} else {
EXPECT_EQ(PhysicalRect(0, 0, 50, 50),
- BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+ BlockPainter(*scroller).OverflowRectForCullRectTesting());
}
}
@@ -50,7 +50,7 @@ TEST_P(BlockPainterTest, OverflowRectCompositedScrollingForCullRectTesting) {
)HTML");
auto* scroller = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
EXPECT_EQ(PhysicalRect(0, 0, 50, 5000),
- BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
+ BlockPainter(*scroller).OverflowRectForCullRectTesting());
}
namespace {
class BlockPainterTestMockEventListener final : public NativeEventListener {
diff --git a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
index 4a91b9035cf..de7526d1945 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
@@ -62,7 +62,7 @@ void BoxModelObjectPainter::PaintTextClipMask(
const IntRect& mask_rect,
const PhysicalOffset& paint_offset,
bool object_has_multiple_boxes) {
- PaintInfo paint_info(context, mask_rect, PaintPhase::kTextClip,
+ PaintInfo paint_info(context, CullRect(mask_rect), PaintPhase::kTextClip,
kGlobalPaintNormalPhase, 0);
if (flow_box_) {
LayoutSize local_offset = ToLayoutSize(flow_box_->Location());
@@ -132,11 +132,16 @@ BoxPainterBase::FillLayerInfo BoxModelObjectPainter::GetFillLayerInfo(
PhysicalBoxSides sides_to_include;
if (flow_box_)
sides_to_include = flow_box_->SidesToInclude();
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(&box_model_);
+ if (auto* style_image = bg_layer.GetImage()) {
+ respect_orientation =
+ style_image->ForceOrientationIfNecessary(respect_orientation);
+ }
return BoxPainterBase::FillLayerInfo(
box_model_.GetDocument(), box_model_.StyleRef(),
box_model_.IsScrollContainer(), color, bg_layer, bleed_avoidance,
- LayoutObject::ShouldRespectImageOrientation(&box_model_),
- sides_to_include, box_model_.IsLayoutInline(),
+ respect_orientation, sides_to_include, box_model_.IsLayoutInline(),
is_painting_scrolling_background);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index 86d38c3371a..9f43df3f872 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -160,7 +160,8 @@ PaintInvalidationReason BoxPaintInvalidator::ComputePaintInvalidationReason() {
return PaintInvalidationReason::kGeometry;
if (style.HasVisualOverflowingEffect() || style.HasEffectiveAppearance() ||
- style.HasFilterInducingProperty() || style.HasMask() || style.ClipPath())
+ style.HasFilterInducingProperty() || style.HasMask() ||
+ style.HasClipPath())
return PaintInvalidationReason::kGeometry;
if (style.HasBorderRadius() || style.CanRenderBorderImage())
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
index 591960fbfd4..2519088ebcc 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -5,7 +5,8 @@
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
#include "base/optional.h"
-#include "third_party/blink/renderer/core/css/native_paint_image_generator.h"
+#include "third_party/blink/renderer/core/animation/element_animations.h"
+#include "third_party/blink/renderer/core/css/background_color_paint_image_generator.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -59,6 +60,24 @@ void BoxPainterBase::PaintFillLayers(const PaintInfo& paint_info,
context.EndLayer();
}
+namespace {
+
+void ApplySpreadToShadowShape(FloatRoundedRect& shadow_shape, float spread) {
+ if (spread == 0)
+ return;
+
+ if (spread >= 0)
+ shadow_shape.ExpandRadii(spread);
+ else
+ shadow_shape.ShrinkRadii(-spread);
+
+ if (!shadow_shape.IsRenderable())
+ shadow_shape.AdjustRadii();
+ shadow_shape.ConstrainRadii();
+}
+
+} // namespace
+
void BoxPainterBase::PaintNormalBoxShadow(const PaintInfo& info,
const PhysicalRect& paint_rect,
const ComputedStyle& style,
@@ -136,22 +155,18 @@ void BoxPainterBase::PaintNormalBoxShadow(const PaintInfo& info,
}
}
- // Draw only the shadow.
- context.SetShadow(shadow_offset, shadow_blur, shadow_color,
- DrawLooperBuilder::kShadowRespectsTransforms,
- DrawLooperBuilder::kShadowIgnoresAlpha, kDrawShadowOnly);
+ // Draw only the shadow. If the color of the shadow is transparent we will
+ // set an empty draw looper.
+ DrawLooperBuilder draw_looper_builder;
+ draw_looper_builder.AddShadow(shadow_offset, shadow_blur, shadow_color,
+ DrawLooperBuilder::kShadowRespectsTransforms,
+ DrawLooperBuilder::kShadowIgnoresAlpha);
+ context.SetDrawLooper(draw_looper_builder.DetachDrawLooper());
if (has_border_radius) {
FloatRoundedRect rounded_fill_rect = border;
rounded_fill_rect.Inflate(shadow_spread);
-
- if (shadow_spread >= 0)
- rounded_fill_rect.ExpandRadii(shadow_spread);
- else
- rounded_fill_rect.ShrinkRadii(-shadow_spread);
- if (!rounded_fill_rect.IsRenderable())
- rounded_fill_rect.AdjustRadii();
- rounded_fill_rect.ConstrainRadii();
+ ApplySpreadToShadowShape(rounded_fill_rect, shadow_spread);
context.FillRoundedRect(rounded_fill_rect, Color::kBlack);
} else {
context.FillRect(fill_rect, Color::kBlack);
@@ -182,42 +197,92 @@ void BoxPainterBase::PaintInsetBoxShadowWithInnerRect(
PaintInsetBoxShadow(info, bounds, style);
}
+namespace {
+
+inline FloatRect AreaCastingShadowInHole(const FloatRect& hole_rect,
+ const ShadowData& shadow) {
+ FloatRect bounds(hole_rect);
+ bounds.Inflate(shadow.Blur());
+
+ if (shadow.Spread() < 0)
+ bounds.Inflate(-shadow.Spread());
+
+ FloatRect offset_bounds = bounds;
+ offset_bounds.MoveBy(-shadow.Location());
+ return UnionRect(bounds, offset_bounds);
+}
+
+void AdjustInnerRectForSideClipping(FloatRect& inner_rect,
+ const ShadowData& shadow,
+ PhysicalBoxSides sides_to_include) {
+ if (!sides_to_include.left) {
+ float extend_by = std::max(shadow.X(), 0.0f) + shadow.Blur();
+ inner_rect.Move(-extend_by, 0);
+ inner_rect.SetWidth(inner_rect.Width() + extend_by);
+ }
+ if (!sides_to_include.top) {
+ float extend_by = std::max(shadow.Y(), 0.0f) + shadow.Blur();
+ inner_rect.Move(0, -extend_by);
+ inner_rect.SetHeight(inner_rect.Height() + extend_by);
+ }
+ if (!sides_to_include.right) {
+ float shrink_by = std::min(shadow.X(), 0.0f) - shadow.Blur();
+ inner_rect.SetWidth(inner_rect.Width() - shrink_by);
+ }
+ if (!sides_to_include.bottom) {
+ float shrink_by = std::min(shadow.Y(), 0.0f) - shadow.Blur();
+ inner_rect.SetHeight(inner_rect.Height() - shrink_by);
+ }
+}
+
+} // namespace
+
void BoxPainterBase::PaintInsetBoxShadow(const PaintInfo& info,
const FloatRoundedRect& bounds,
const ComputedStyle& style,
PhysicalBoxSides sides_to_include) {
GraphicsContext& context = info.context;
- GraphicsContextStateSaver state_saver(context, false);
const ShadowList* shadow_list = style.BoxShadow();
for (wtf_size_t i = shadow_list->Shadows().size(); i--;) {
const ShadowData& shadow = shadow_list->Shadows()[i];
if (shadow.Style() != ShadowStyle::kInset)
continue;
-
- FloatSize shadow_offset(shadow.X(), shadow.Y());
- float shadow_blur = shadow.Blur();
- float shadow_spread = shadow.Spread();
-
- if (shadow_offset.IsZero() && !shadow_blur && !shadow_spread)
+ if (!shadow.X() && !shadow.Y() && !shadow.Blur() && !shadow.Spread())
continue;
const Color& shadow_color = shadow.GetColor().Resolve(
style.VisitedDependentColor(GetCSSPropertyColor()),
style.UsedColorScheme());
- // The inset shadow case.
- GraphicsContext::Edges clipped_edges = GraphicsContext::kNoEdge;
- if (!sides_to_include.top)
- clipped_edges |= GraphicsContext::kTopEdge;
- if (!sides_to_include.right)
- clipped_edges |= GraphicsContext::kRightEdge;
- if (!sides_to_include.bottom)
- clipped_edges |= GraphicsContext::kBottomEdge;
- if (!sides_to_include.left)
- clipped_edges |= GraphicsContext::kLeftEdge;
- context.DrawInnerShadow(bounds, shadow_color, shadow_offset, shadow_blur,
- shadow_spread, clipped_edges);
+ FloatRect inner_rect(bounds.Rect());
+ inner_rect.Inflate(-shadow.Spread());
+ if (inner_rect.IsEmpty()) {
+ context.FillRoundedRect(bounds, shadow_color);
+ continue;
+ }
+ AdjustInnerRectForSideClipping(inner_rect, shadow, sides_to_include);
+
+ FloatRoundedRect inner_rounded_rect(inner_rect, bounds.GetRadii());
+ GraphicsContextStateSaver state_saver(context);
+ if (bounds.IsRounded()) {
+ context.ClipRoundedRect(bounds);
+ ApplySpreadToShadowShape(inner_rounded_rect, -shadow.Spread());
+ } else {
+ context.Clip(bounds.Rect());
+ }
+
+ DrawLooperBuilder draw_looper_builder;
+ draw_looper_builder.AddShadow(ToFloatSize(shadow.Location()), shadow.Blur(),
+ shadow_color,
+ DrawLooperBuilder::kShadowRespectsTransforms,
+ DrawLooperBuilder::kShadowIgnoresAlpha);
+ context.SetDrawLooper(draw_looper_builder.DetachDrawLooper());
+
+ Color fill_color(shadow_color.Red(), shadow_color.Green(),
+ shadow_color.Blue());
+ FloatRect outer_rect = AreaCastingShadowInHole(bounds.Rect(), shadow);
+ context.FillRectWithRoundedHole(outer_rect, inner_rounded_rect, fill_color);
}
}
@@ -314,6 +379,7 @@ BoxPainterBase::FillLayerInfo::FillLayerInfo(
is_rounded_fill =
has_rounded_border && !is_painting_scrolling_background &&
!(is_border_fill && BleedAvoidanceIsClipping(bleed_avoidance));
+ is_printing = doc.Printing();
should_paint_image = image && image->CanRender();
should_paint_color =
@@ -321,7 +387,8 @@ BoxPainterBase::FillLayerInfo::FillLayerInfo(
(!should_paint_image || !layer.ImageOccludesNextLayers(doc, style));
should_paint_color_with_paint_worklet_image =
should_paint_color &&
- RuntimeEnabledFeatures::CompositeBGColorAnimationEnabled();
+ RuntimeEnabledFeatures::CompositeBGColorAnimationEnabled() &&
+ style.HasCurrentBackgroundColorAnimation();
}
namespace {
@@ -489,22 +556,41 @@ void DrawTiledBackground(GraphicsContext& context,
respect_orientation);
}
-void FillRectWithPaintWorklet(const BoxPainterBase::FillLayerInfo& info,
+// Returning false meaning that we need to fall back to the main thread for the
+// background color animation.
+bool GetBGColorPaintWorkletParams(const BoxPainterBase::FillLayerInfo& info,
+ const Document* document,
+ Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) {
+ if (!info.should_paint_color_with_paint_worklet_image)
+ return false;
+ BackgroundColorPaintImageGenerator* generator =
+ document->GetFrame()->GetBackgroundColorPaintImageGenerator();
+ return generator->GetBGColorPaintWorkletParams(node, animated_colors,
+ offsets);
+}
+
+void FillRectWithPaintWorklet(const Document* document,
+ const BoxPainterBase::FillLayerInfo& info,
Node* node,
const FloatRoundedRect& dest_rect,
- GraphicsContext& context) {
- FloatRect src_rect = dest_rect.Rect();
- std::unique_ptr<NativePaintImageGenerator> generator =
- NativePaintImageGenerator::Create();
+ GraphicsContext& context,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets) {
+ FloatRect src_rect(FloatPoint(), dest_rect.Rect().Size());
+ BackgroundColorPaintImageGenerator* generator =
+ document->GetFrame()->GetBackgroundColorPaintImageGenerator();
scoped_refptr<Image> paint_worklet_image =
- generator->Paint(src_rect.Size(), SkColor(info.color));
+ generator->Paint(src_rect.Size(), node, animated_colors, offsets);
context.DrawImageRRect(
paint_worklet_image.get(), Image::kSyncDecode, dest_rect, src_rect,
node && node->ComputedStyleRef().HasFilterInducingProperty(),
SkBlendMode::kSrcOver, info.respect_image_orientation);
}
-inline bool PaintFastBottomLayer(Node* node,
+inline bool PaintFastBottomLayer(const Document* document,
+ Node* node,
const PaintInfo& paint_info,
const BoxPainterBase::FillLayerInfo& info,
const PhysicalRect& rect,
@@ -537,7 +623,7 @@ inline bool PaintFastBottomLayer(Node* node,
FloatRoundedRect image_border;
if (info.should_paint_image) {
// Avoid image shaders when printing (poorly supported in PDF).
- if (info.is_rounded_fill && paint_info.IsPrinting())
+ if (info.is_rounded_fill && info.is_printing)
return false;
// Compute the dest rect we will be using for images.
@@ -590,8 +676,12 @@ inline bool PaintFastBottomLayer(Node* node,
// Paint the color if needed.
if (info.should_paint_color) {
- if (info.should_paint_color_with_paint_worklet_image) {
- FillRectWithPaintWorklet(info, node, color_border, context);
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ if (GetBGColorPaintWorkletParams(info, document, node, &animated_colors,
+ &offsets)) {
+ FillRectWithPaintWorklet(document, info, node, color_border, context,
+ animated_colors, offsets);
} else {
context.FillRoundedRect(color_border, info.color);
}
@@ -652,17 +742,16 @@ inline bool PaintFastBottomLayer(Node* node,
node && node->ComputedStyleRef().HasFilterInducingProperty(),
composite_op, info.respect_image_orientation);
- if (info.image && info.image->IsImageResource()) {
+ if (node && info.image && info.image->IsImageResource()) {
PaintTimingDetector::NotifyBackgroundImagePaint(
- node, image, To<StyleFetchedImage>(info.image),
+ *node, *image, To<StyleFetchedImage>(*info.image),
paint_info.context.GetPaintController().CurrentPaintChunkProperties(),
RoundedIntRect(image_border.Rect()));
- }
- if (node && info.image && info.image->IsImageResource()) {
+
LocalDOMWindow* window = node->GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyBackgroundImagePainted(
- node, To<StyleFetchedImage>(info.image),
+ *node, To<StyleFetchedImage>(*info.image),
context.GetPaintController().CurrentPaintChunkProperties(),
RoundedIntRect(image_border.Rect()));
}
@@ -754,7 +843,8 @@ FloatRoundedRect RoundedBorderRectForClip(
return border;
}
-void PaintFillLayerBackground(GraphicsContext& context,
+void PaintFillLayerBackground(const Document* document,
+ GraphicsContext& context,
const BoxPainterBase::FillLayerInfo& info,
Node* node,
Image* image,
@@ -768,9 +858,13 @@ void PaintFillLayerBackground(GraphicsContext& context,
// painting area.
if (info.is_bottom_layer && info.color.Alpha() && info.should_paint_color) {
IntRect background_rect(PixelSnappedIntRect(scrolled_paint_rect));
- if (info.should_paint_color_with_paint_worklet_image) {
- FillRectWithPaintWorklet(info, node, FloatRoundedRect(background_rect),
- context);
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ if (GetBGColorPaintWorkletParams(info, document, node, &animated_colors,
+ &offsets)) {
+ FillRectWithPaintWorklet(document, info, node,
+ FloatRoundedRect(background_rect), context,
+ animated_colors, offsets);
} else {
context.FillRect(background_rect, info.color);
}
@@ -793,17 +887,16 @@ void PaintFillLayerBackground(GraphicsContext& context,
FloatSize(geometry.SpaceSize()),
node && node->ComputedStyleRef().HasFilterInducingProperty(),
info.respect_image_orientation);
- if (info.image && info.image->IsImageResource()) {
+ if (node && info.image && info.image->IsImageResource()) {
PaintTimingDetector::NotifyBackgroundImagePaint(
- node, image, To<StyleFetchedImage>(info.image),
+ *node, *image, To<StyleFetchedImage>(*info.image),
context.GetPaintController().CurrentPaintChunkProperties(),
EnclosingIntRect(geometry.SnappedDestRect()));
- }
- if (node && info.image && info.image->IsImageResource()) {
+
LocalDOMWindow* window = node->GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyBackgroundImagePainted(
- node, To<StyleFetchedImage>(info.image),
+ *node, To<StyleFetchedImage>(*info.image),
context.GetPaintController().CurrentPaintChunkProperties(),
EnclosingIntRect(geometry.SnappedDestRect()));
}
@@ -900,8 +993,8 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
(bleed_avoidance == kBackgroundBleedShrinkBackground ||
did_adjust_paint_rect);
if (!disable_fast_path &&
- PaintFastBottomLayer(node_, paint_info, info, rect, border_rect, geometry,
- image.get(), composite_op)) {
+ PaintFastBottomLayer(document_, node_, paint_info, info, rect,
+ border_rect, geometry, image.get(), composite_op)) {
return;
}
@@ -941,8 +1034,8 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
break;
}
- PaintFillLayerBackground(context, info, node_, image.get(), composite_op,
- geometry, scrolled_paint_rect);
+ PaintFillLayerBackground(document_, context, info, node_, image.get(),
+ composite_op, geometry, scrolled_paint_rect);
}
void BoxPainterBase::PaintFillLayerTextFillBox(
@@ -966,8 +1059,9 @@ void BoxPainterBase::PaintFillLayerTextFillBox(
context.Clip(mask_rect);
context.BeginLayer(1, composite_op);
- PaintFillLayerBackground(context, info, node_, image, SkBlendMode::kSrcOver,
- geometry, scrolled_paint_rect);
+ PaintFillLayerBackground(document_, context, info, node_, image,
+ SkBlendMode::kSrcOver, geometry,
+ scrolled_paint_rect);
// Create the text mask layer and draw the text into the mask. We do this by
// painting using a special paint phase that signals to InlineTextBoxes that
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
index cfdb240a943..c6190bc84a1 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
@@ -26,6 +26,7 @@ class GraphicsContext;
class ImageResourceObserver;
class IntRect;
class LayoutBox;
+class Node;
struct PaintInfo;
struct PhysicalOffset;
struct PhysicalRect;
@@ -132,6 +133,7 @@ class BoxPainterBase {
bool is_border_fill;
bool is_clipped_with_local_scrolling;
bool is_rounded_fill;
+ bool is_printing;
bool should_paint_image;
bool should_paint_color;
// True if we paint background color off main thread, design doc here:
diff --git a/chromium/third_party/blink/renderer/core/paint/build.gni b/chromium/third_party/blink/renderer/core/paint/build.gni
index 89a2d62a02a..c7a1937903e 100644
--- a/chromium/third_party/blink/renderer/core/paint/build.gni
+++ b/chromium/third_party/blink/renderer/core/paint/build.gni
@@ -59,6 +59,8 @@ blink_core_sources_paint = [
"compositing/paint_layer_compositor.h",
"css_mask_painter.cc",
"css_mask_painter.h",
+ "cull_rect_updater.cc",
+ "cull_rect_updater.h",
"custom_scrollbar_theme.cc",
"custom_scrollbar_theme.h",
"details_marker_painter.cc",
@@ -128,14 +130,14 @@ blink_core_sources_paint = [
"ng/ng_fieldset_painter.h",
"ng/ng_fragment_painter.cc",
"ng/ng_fragment_painter.h",
+ "ng/ng_highlight_painter.cc",
+ "ng/ng_highlight_painter.h",
"ng/ng_inline_box_fragment_painter.cc",
"ng/ng_inline_box_fragment_painter.h",
"ng/ng_mathml_painter.cc",
"ng/ng_mathml_painter.h",
- "ng/ng_paint_fragment.cc",
- "ng/ng_paint_fragment.h",
- "ng/ng_paint_fragment_traversal.cc",
- "ng/ng_paint_fragment_traversal.h",
+ "ng/ng_table_cell_paint_invalidator.cc",
+ "ng/ng_table_cell_paint_invalidator.h",
"ng/ng_table_painters.cc",
"ng/ng_table_painters.h",
"ng/ng_text_fragment_painter.cc",
@@ -202,6 +204,8 @@ blink_core_sources_paint = [
"scoped_svg_paint_state.h",
"scrollable_area_painter.cc",
"scrollable_area_painter.h",
+ "selection_bounds_recorder.cc",
+ "selection_bounds_recorder.h",
"svg_container_painter.cc",
"svg_container_painter.h",
"svg_foreign_object_painter.cc",
diff --git a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index 0a0cc1f30b3..aeba6f798ef 100644
--- a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -4,14 +4,12 @@
#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/clip_path_operation.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
@@ -25,22 +23,23 @@ namespace blink {
namespace {
+SVGResourceClient* GetResourceClient(const LayoutObject& object) {
+ if (object.IsSVGChild())
+ return SVGResources::GetClient(object);
+ CHECK(object.IsBoxModelObject());
+ return To<LayoutBoxModelObject>(object).Layer()->ResourceInfo();
+}
+
LayoutSVGResourceClipper* ResolveElementReference(
- const LayoutObject& layout_object,
+ const LayoutObject& object,
const ReferenceClipPathOperation& reference_clip_path_operation) {
- LayoutSVGResourceClipper* resource_clipper = nullptr;
- if (layout_object.IsSVGChild()) {
- // The reference will have been resolved in
- // SVGResources::buildResources, so we can just use the LayoutObject's
- // SVGResources.
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- resource_clipper = resources ? resources->Clipper() : nullptr;
- } else {
- // TODO(fs): Doesn't work with external SVG references (crbug.com/109212.)
- resource_clipper = GetSVGResourceAsType<LayoutSVGResourceClipper>(
- reference_clip_path_operation.Resource());
- }
+ SVGResourceClient* client = GetResourceClient(object);
+ // We may not have a resource client for some non-rendered elements (like
+ // filter primitives) that we visit during paint property tree construction.
+ if (!client)
+ return nullptr;
+ LayoutSVGResourceClipper* resource_clipper =
+ GetSVGResourceAsType(*client, reference_clip_path_operation);
if (resource_clipper) {
SECURITY_DCHECK(!resource_clipper->NeedsLayout());
resource_clipper->ClearInvalidationMask();
@@ -68,7 +67,7 @@ FloatRect ClipPathClipper::LocalReferenceBox(const LayoutObject& object) {
base::Optional<FloatRect> ClipPathClipper::LocalClipPathBoundingBox(
const LayoutObject& object) {
- if (object.IsText() || !object.StyleRef().ClipPath())
+ if (object.IsText() || !object.StyleRef().HasClipPath())
return base::nullopt;
FloatRect reference_box = LocalReferenceBox(object);
@@ -194,7 +193,7 @@ void ClipPathClipper::PaintClipPathAsMaskImage(
else
context.BeginLayer(1.f, SkBlendMode::kDstIn);
- if (resource_clipper->StyleRef().ClipPath()) {
+ if (resource_clipper->StyleRef().HasClipPath()) {
// Try to apply nested clip-path as path-based clip.
if (const base::Optional<Path>& path = PathBasedClipInternal(
*resource_clipper, uses_zoomed_reference_box, reference_box)) {
@@ -218,7 +217,7 @@ void ClipPathClipper::PaintClipPathAsMaskImage(
}
bool ClipPathClipper::ShouldUseMaskBasedClip(const LayoutObject& object) {
- if (object.IsText())
+ if (object.IsText() || !object.StyleRef().HasClipPath())
return false;
const auto* reference_clip =
DynamicTo<ReferenceClipPathOperation>(object.StyleRef().ClipPath());
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/DIR_METADATA b/chromium/third_party/blink/renderer/core/paint/compositing/DIR_METADATA
new file mode 100644
index 00000000000..096eaacd645
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Compositing"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/OWNERS b/chromium/third_party/blink/renderer/core/paint/compositing/OWNERS
index 3e7d12c1a67..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/OWNERS
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/OWNERS
@@ -1,2 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Compositing \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index aaa9ece2c8f..66ac9380346 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -28,6 +28,7 @@
#include <memory>
#include "cc/layers/picture_layer.h"
+#include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
@@ -88,12 +89,6 @@ static PhysicalRect ContentsRect(const LayoutObject& layout_object) {
return To<LayoutBox>(layout_object).PhysicalContentBoxRect();
}
-static PhysicalRect BackgroundRect(const LayoutObject& layout_object) {
- if (const auto* box = DynamicTo<LayoutBox>(layout_object))
- return box->PhysicalBackgroundRect(kBackgroundClipRect);
- return PhysicalRect();
-}
-
static inline bool IsTextureLayerCanvas(const LayoutObject& layout_object) {
if (layout_object.IsCanvas()) {
auto* canvas = To<HTMLCanvasElement>(layout_object.GetNode());
@@ -105,33 +100,10 @@ static inline bool IsTextureLayerCanvas(const LayoutObject& layout_object) {
return false;
}
-static inline bool IsSurfaceLayerCanvas(const LayoutObject& layout_object) {
- if (layout_object.IsCanvas()) {
- auto* canvas = To<HTMLCanvasElement>(layout_object.GetNode());
- return canvas->SurfaceLayerBridge();
- }
- return false;
-}
-
static bool HasBoxDecorationsOrBackgroundImage(const ComputedStyle& style) {
return style.HasBoxDecorations() || style.HasBackgroundImage();
}
-static bool ContentLayerSupportsDirectBackgroundComposition(
- const LayoutObject& layout_object) {
- // No support for decorations - border, border-radius or outline.
- // Only simple background - solid color or transparent.
- if (HasBoxDecorationsOrBackgroundImage(layout_object.StyleRef()))
- return false;
-
- // If there is no background, there is nothing to support.
- if (!layout_object.StyleRef().HasBackground())
- return true;
-
- // Simple background that is contained within the contents rect.
- return ContentsRect(layout_object).Contains(BackgroundRect(layout_object));
-}
-
static WebPluginContainerImpl* GetPluginContainer(LayoutObject& layout_object) {
if (auto* embedded_object = DynamicTo<LayoutEmbeddedObject>(layout_object))
return embedded_object->Plugin();
@@ -194,9 +166,7 @@ static bool NeedsDecorationOutlineLayer(const PaintLayer& paint_layer,
}
CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
- : owning_layer_(layer),
- pending_update_scope_(kGraphicsLayerUpdateNone),
- draws_background_onto_content_layer_(false) {
+ : owning_layer_(layer), pending_update_scope_(kGraphicsLayerUpdateNone) {
CreatePrimaryGraphicsLayer();
}
@@ -254,16 +224,16 @@ void CompositedLayerMapping::UpdateGraphicsLayerContentsOpaque(
if (BackgroundPaintsOntoGraphicsLayer()) {
bool contents_opaque = owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
CompositedBounds(), should_check_children);
- graphics_layer_->SetContentsOpaque(contents_opaque);
+ graphics_layer_->CcLayer().SetContentsOpaque(contents_opaque);
if (!contents_opaque) {
- graphics_layer_->SetContentsOpaqueForText(
+ graphics_layer_->CcLayer().SetContentsOpaqueForText(
GetLayoutObject().TextIsKnownToBeOnOpaqueBackground());
}
} else {
// If we only paint the background onto the scrolling contents layer we
// are going to leave a hole in the m_graphicsLayer where the background
// is so it is not opaque.
- graphics_layer_->SetContentsOpaque(false);
+ graphics_layer_->CcLayer().SetContentsOpaque(false);
}
}
@@ -272,30 +242,7 @@ void CompositedLayerMapping::UpdateContentsOpaque() {
// not graphics_layer_, and so don't contribute to the opaqueness of the
// latter.
bool should_check_children = !foreground_layer_.get();
- if (IsTextureLayerCanvas(GetLayoutObject())) {
- CanvasRenderingContext* context =
- To<HTMLCanvasElement>(GetLayoutObject().GetNode())->RenderingContext();
- cc::Layer* layer = context ? context->CcLayer() : nullptr;
- // Determine whether the external texture layer covers the whole graphics
- // layer. This may not be the case if there are box decorations or
- // shadows.
- if (layer && layer->bounds() == graphics_layer_->CcLayer().bounds()) {
- // Determine whether the rendering context's external texture layer is
- // opaque.
- if (!context->CreationAttributes().alpha) {
- graphics_layer_->SetContentsOpaque(true);
- } else {
- graphics_layer_->SetContentsOpaque(
- !Color(layer->background_color()).HasAlpha());
- }
- } else {
- graphics_layer_->SetContentsOpaque(false);
- }
- } else if (IsSurfaceLayerCanvas(GetLayoutObject())) {
- // TODO(crbug.com/705019): Contents could be opaque, but that cannot be
- // determined from the main thread. Or can it?
- graphics_layer_->SetContentsOpaque(false);
- } else if (BackgroundPaintsOntoScrollingContentsLayer()) {
+ if (BackgroundPaintsOntoScrollingContentsLayer()) {
DCHECK(scrolling_contents_layer_);
// Backgrounds painted onto the foreground are clipped by the padding box
// rect.
@@ -305,9 +252,9 @@ void CompositedLayerMapping::UpdateContentsOpaque() {
bool contents_opaque = owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
To<LayoutBox>(GetLayoutObject()).PhysicalPaddingBoxRect(),
should_check_children);
- scrolling_contents_layer_->SetContentsOpaque(contents_opaque);
+ scrolling_contents_layer_->CcLayer().SetContentsOpaque(contents_opaque);
if (!contents_opaque) {
- scrolling_contents_layer_->SetContentsOpaqueForText(
+ scrolling_contents_layer_->CcLayer().SetContentsOpaqueForText(
GetLayoutObject().TextIsKnownToBeOnOpaqueBackground());
}
@@ -315,12 +262,12 @@ void CompositedLayerMapping::UpdateContentsOpaque() {
} else {
DCHECK(BackgroundPaintsOntoGraphicsLayer());
if (scrolling_contents_layer_)
- scrolling_contents_layer_->SetContentsOpaque(false);
+ scrolling_contents_layer_->CcLayer().SetContentsOpaque(false);
UpdateGraphicsLayerContentsOpaque(should_check_children);
}
if (non_scrolling_squashing_layer_) {
- non_scrolling_squashing_layer_->SetContentsOpaque(false);
+ non_scrolling_squashing_layer_->CcLayer().SetContentsOpaque(false);
bool contents_opaque_for_text = true;
for (const GraphicsLayerPaintInfo& squashed_layer :
non_scrolling_squashed_layers_) {
@@ -330,7 +277,7 @@ void CompositedLayerMapping::UpdateContentsOpaque() {
break;
}
}
- non_scrolling_squashing_layer_->SetContentsOpaqueForText(
+ non_scrolling_squashing_layer_->CcLayer().SetContentsOpaqueForText(
contents_opaque_for_text);
}
}
@@ -404,24 +351,19 @@ bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
if (layout_object.IsLayoutEmbeddedContent()) {
if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
- graphics_layer_->SetContentsToCcLayer(
- plugin->CcLayer(), plugin->PreventContentsOpaqueChangesToCcLayer());
+ graphics_layer_->SetContentsToCcLayer(plugin->CcLayer());
} else if (auto* frame_owner =
DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode())) {
if (auto* remote = DynamicTo<RemoteFrame>(frame_owner->ContentFrame())) {
- graphics_layer_->SetContentsToCcLayer(
- remote->GetCcLayer(), remote->WebLayerHasFixedContentsOpaque());
+ graphics_layer_->SetContentsToCcLayer(remote->GetCcLayer());
}
}
} else if (IsA<LayoutVideo>(layout_object)) {
auto* media_element = To<HTMLMediaElement>(layout_object.GetNode());
- graphics_layer_->SetContentsToCcLayer(
- media_element->CcLayer(),
- /*prevent_contents_opaque_changes=*/true);
+ graphics_layer_->SetContentsToCcLayer(media_element->CcLayer());
} else if (layout_object.IsCanvas()) {
graphics_layer_->SetContentsToCcLayer(
- To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer(),
- /*prevent_contents_opaque_changes=*/false);
+ To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer());
layer_config_changed = true;
}
@@ -473,6 +415,38 @@ static PhysicalOffset ComputeOffsetFromCompositedAncestor(
return offset;
}
+PhysicalOffset ComputeSubpixelAccumulation(
+ const PhysicalOffset& offset_from_composited_ancestor,
+ const PaintLayer& layer,
+ IntPoint& snapped_offset_from_composited_ancestor) {
+ snapped_offset_from_composited_ancestor =
+ RoundedIntPoint(offset_from_composited_ancestor);
+ PhysicalOffset subpixel_accumulation =
+ offset_from_composited_ancestor -
+ PhysicalOffset(snapped_offset_from_composited_ancestor);
+ if (subpixel_accumulation.IsZero()) {
+ return subpixel_accumulation;
+ }
+ if (layer.GetCompositingReasons() &
+ CompositingReason::kPreventingSubpixelAccumulationReasons) {
+ return PhysicalOffset();
+ }
+ if (layer.GetCompositingReasons() &
+ CompositingReason::kActiveTransformAnimation) {
+ if (const Element* element =
+ To<Element>(layer.GetLayoutObject().GetNode())) {
+ DCHECK(element->GetElementAnimations());
+ if (element->GetElementAnimations()->IsIdentityOrTranslation())
+ return subpixel_accumulation;
+ }
+ return PhysicalOffset();
+ }
+ if (!layer.Transform() || layer.Transform()->IsIdentityOrTranslation()) {
+ return subpixel_accumulation;
+ }
+ return PhysicalOffset();
+}
+
void CompositedLayerMapping::ComputeBoundsOfOwningLayer(
const PaintLayer* composited_ancestor,
IntRect& local_bounds,
@@ -493,18 +467,9 @@ void CompositedLayerMapping::ComputeBoundsOfOwningLayer(
&owning_layer_, composited_ancestor,
local_representative_point_for_fragmentation,
offset_for_sticky_position);
- snapped_offset_from_composited_ancestor =
- RoundedIntPoint(offset_from_composited_ancestor);
-
- PhysicalOffset subpixel_accumulation;
- if ((!owning_layer_.Transform() ||
- owning_layer_.Transform()->IsIdentityOrTranslation()) &&
- !(owning_layer_.GetCompositingReasons() &
- CompositingReason::kPreventingSubpixelAccumulationReasons)) {
- subpixel_accumulation =
- offset_from_composited_ancestor -
- PhysicalOffset(snapped_offset_from_composited_ancestor);
- }
+ PhysicalOffset subpixel_accumulation = ComputeSubpixelAccumulation(
+ offset_from_composited_ancestor, owning_layer_,
+ snapped_offset_from_composited_ancestor);
// Invalidate the whole layer when subpixel accumulation changes, since
// the previous subpixel accumulation is baked into the display list.
@@ -964,21 +929,10 @@ void CompositedLayerMapping::UpdateDrawsContentAndPaintsHitTest() {
scrolling_contents_layer_->SetPaintsHitTest(paints_hit_test);
}
- draws_background_onto_content_layer_ = false;
- if (has_painted_content && IsTextureLayerCanvas(GetLayoutObject())) {
- CanvasRenderingContext* context =
- To<HTMLCanvasElement>(GetLayoutObject().GetNode())->RenderingContext();
- // Content layer may be null if context is lost.
- if (cc::Layer* content_layer = context->CcLayer()) {
- if (ContentLayerSupportsDirectBackgroundComposition(GetLayoutObject())) {
- has_painted_content = false;
- draws_background_onto_content_layer_ = true;
- Color contents_layer_background_color =
- GetLayoutObject().ResolveColor(GetCSSPropertyBackgroundColor());
- graphics_layer_->SetContentsLayerBackgroundColor(
- contents_layer_background_color);
- }
- }
+ if (has_painted_content && GetLayoutObject().IsCanvas() &&
+ To<LayoutHTMLCanvas>(GetLayoutObject())
+ .DrawsBackgroundOntoContentLayer()) {
+ has_painted_content = false;
}
// FIXME: we could refine this to only allocate backings for one of these
@@ -1628,15 +1582,12 @@ void CompositedLayerMapping::DoPaintTask(
// TODO(eseckler): Make recording distance configurable, e.g. for use in
// headless, where we would like to record an exact area.
-// Note however that the minimum value for this constant is the size of a
-// raster tile. This is because the raster system is not able to raster a
-// tile that is not completely covered by a display list. If the constant
-// were less than the size of a tile, then a tile which partially overlaps
-// the screen may not be rastered.
static const int kPixelDistanceToRecord = 4000;
IntRect CompositedLayerMapping::RecomputeInterestRect(
const GraphicsLayer* graphics_layer) const {
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
IntRect graphics_layer_bounds(IntPoint(), IntSize(graphics_layer->Size()));
FloatClipRect mapping_rect((FloatRect(graphics_layer_bounds)));
@@ -1647,38 +1598,26 @@ IntRect CompositedLayerMapping::RecomputeInterestRect(
while (root_view->GetFrame()->OwnerLayoutObject())
root_view = root_view->GetFrame()->OwnerLayoutObject()->View();
- auto root_view_contents_state =
- root_view->FirstFragment().ContentsProperties();
- auto root_view_border_box_state =
- root_view->FirstFragment().LocalBorderBoxProperties();
+ auto root_view_state = root_view->FirstFragment().LocalBorderBoxProperties();
// 1. Move into local transform space.
mapping_rect.MoveBy(FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
- // 2. Map into contents space of the root LayoutView.
- GeometryMapper::LocalToAncestorVisualRect(
- source_state, root_view_contents_state, mapping_rect);
+ // 2. Map into visible space of the root LayoutView.
+ GeometryMapper::LocalToAncestorVisualRect(source_state, root_view_state,
+ mapping_rect);
FloatRect visible_content_rect(EnclosingIntRect(mapping_rect.Rect()));
- // 3. Move into local border box transform space of the root LayoutView.
- // Note that the overflow clip has *not* been applied.
- GeometryMapper::SourceToDestinationRect(
- root_view_contents_state.Transform(),
- root_view_border_box_state.Transform(), visible_content_rect);
-
- // 4. Apply overflow clip, or adjusted version if necessary.
- root_view->GetFrameView()->ClipPaintRect(&visible_content_rect);
-
FloatRect local_interest_rect;
// If the visible content rect is empty, then it makes no sense to map it back
// since there is nothing to map.
if (!visible_content_rect.IsEmpty()) {
local_interest_rect = visible_content_rect;
- // 5. Map the visible content rect from root view space to local graphics
+ // 3. Map the visible content rect from root view space to local graphics
// layer space.
- GeometryMapper::SourceToDestinationRect(
- root_view_border_box_state.Transform(), source_state.Transform(),
- local_interest_rect);
+ GeometryMapper::SourceToDestinationRect(root_view_state.Transform(),
+ source_state.Transform(),
+ local_interest_rect);
local_interest_rect.MoveBy(
-FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
@@ -1754,6 +1693,8 @@ bool CompositedLayerMapping::InterestRectChangedEnoughToRepaint(
const IntRect& previous_interest_rect,
const IntRect& new_interest_rect,
const IntSize& layer_size) {
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
if (previous_interest_rect.IsEmpty() && new_interest_rect.IsEmpty())
return false;
@@ -1791,6 +1732,8 @@ bool CompositedLayerMapping::InterestRectChangedEnoughToRepaint(
IntRect CompositedLayerMapping::ComputeInterestRect(
const GraphicsLayer* graphics_layer,
const IntRect& previous_interest_rect) const {
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
// Use the previous interest rect if it covers the whole layer.
IntRect whole_layer_rect =
IntRect(IntPoint(), IntSize(graphics_layer->Size()));
@@ -1812,6 +1755,22 @@ IntRect CompositedLayerMapping::ComputeInterestRect(
return previous_interest_rect;
}
+IntRect CompositedLayerMapping::PaintableRegion(
+ const GraphicsLayer* graphics_layer) const {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ const auto& fragment = OwningLayer().GetLayoutObject().FirstFragment();
+ CullRect cull_rect = graphics_layer == scrolling_contents_layer_.get() ||
+ (graphics_layer == foreground_layer_.get() &&
+ scrolling_contents_layer_)
+ ? fragment.GetContentsCullRect()
+ : fragment.GetCullRect();
+ IntRect layer_rect(IntPoint(), IntSize(graphics_layer->Size()));
+ if (cull_rect.IsInfinite())
+ return layer_rect;
+ cull_rect.MoveBy(-graphics_layer->GetOffsetFromTransformNode());
+ return Intersection(cull_rect.Rect(), layer_rect);
+}
+
LayoutSize CompositedLayerMapping::SubpixelAccumulation() const {
return owning_layer_.SubpixelAccumulation().ToLayoutSize();
}
@@ -1872,7 +1831,11 @@ void CompositedLayerMapping::PaintContents(
const GraphicsLayer* graphics_layer,
GraphicsContext& context,
GraphicsLayerPaintingPhase graphics_layer_painting_phase,
- const IntRect& interest_rect) const {
+ const IntRect& interest_rect_arg) const {
+ IntRect interest_rect = RuntimeEnabledFeatures::CullRectUpdateEnabled()
+ ? PaintableRegion(graphics_layer)
+ : interest_rect_arg;
+
FramePaintTiming frame_paint_timing(context, GetLayoutObject().GetFrame());
// https://code.google.com/p/chromium/issues/detail?id=343772
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index c488ad050da..e13b33757c5 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -169,6 +169,7 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
IntRect ComputeInterestRect(
const GraphicsLayer*,
const IntRect& previous_interest_rect) const override;
+ IntRect PaintableRegion(const GraphicsLayer*) const override;
LayoutSize SubpixelAccumulation() const final;
bool NeedsRepaint(const GraphicsLayer&) const override;
void PaintContents(const GraphicsLayer*,
@@ -247,10 +248,6 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
bool AdjustForCompositedScrolling(const GraphicsLayer*,
IntSize& offset) const;
- bool DrawsBackgroundOntoContentLayer() const {
- return draws_background_onto_content_layer_;
- }
-
private:
// Returns true for layers with scrollable overflow which have a background
// that can be painted into the composited scrolling contents layer (i.e.
@@ -460,8 +457,6 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
unsigned pending_update_scope_ : 2;
- bool draws_background_onto_content_layer_;
-
friend class CompositedLayerMappingTest;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 0b1bf61f2bb..b9b9f148b76 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -22,29 +22,22 @@
#include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/testing/find_cc_layer.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
namespace blink {
// TODO(wangxianzhu): Though these tests don't directly apply in
// CompositeAfterPaint, we should ensure the cases are tested in
-// CompositeAfterPaint mode if applicable.
-class CompositedLayerMappingTest : public RenderingTest {
+// CompositeAfterPaint mode if applicable. Some interest rect / cull rect
+// tests have been migrated for CompositeAfterPaint into
+// PaintLayerPainterTestCAP.
+class CompositedLayerMappingTest : public RenderingTest,
+ public PaintTestConfigurations {
public:
CompositedLayerMappingTest()
: RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
protected:
- IntRect RecomputeInterestRect(const GraphicsLayer* graphics_layer) {
- return static_cast<CompositedLayerMapping&>(graphics_layer->Client())
- .RecomputeInterestRect(graphics_layer);
- }
-
- IntRect ComputeInterestRect(GraphicsLayer* graphics_layer,
- IntRect previous_interest_rect) {
- return static_cast<CompositedLayerMapping&>(graphics_layer->Client())
- .ComputeInterestRect(graphics_layer, previous_interest_rect);
- }
-
bool InterestRectChangedEnoughToRepaint(const IntRect& previous_interest_rect,
const IntRect& new_interest_rect,
const IntSize& layer_size) {
@@ -52,8 +45,8 @@ class CompositedLayerMappingTest : public RenderingTest {
previous_interest_rect, new_interest_rect, layer_size);
}
- IntRect PreviousInterestRect(const GraphicsLayer* graphics_layer) {
- return graphics_layer->previous_interest_rect_;
+ gfx::Rect PaintableRegion(const GraphicsLayer* graphics_layer) {
+ return graphics_layer->PaintableRegion();
}
static const GraphicsLayerPaintInfo* GetSquashedLayer(
@@ -86,7 +79,9 @@ class CompositedLayerMappingTest : public RenderingTest {
}
};
-TEST_F(CompositedLayerMappingTest, SubpixelAccumulationChange) {
+INSTANTIATE_PRE_CAP_TEST_SUITE_P(CompositedLayerMappingTest);
+
+TEST_P(CompositedLayerMappingTest, SubpixelAccumulationChange) {
SetBodyInnerHTML(R"HTML(
<div id='target' style='will-change: opacity; background: lightblue;
position: relative; left: 0.4px; width: 100px; height: 100px'>
@@ -111,7 +106,7 @@ TEST_F(CompositedLayerMappingTest, SubpixelAccumulationChange) {
GetDocument().View()->SetTracksRasterInvalidations(false);
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
SubpixelAccumulationChangeUnderInvalidation) {
ScopedPaintUnderInvalidationCheckingForTest test(true);
SetBodyInnerHTML(R"HTML(
@@ -138,7 +133,7 @@ TEST_F(CompositedLayerMappingTest,
GetDocument().View()->SetTracksRasterInvalidations(false);
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
SubpixelAccumulationChangeIndirectCompositing) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -180,72 +175,74 @@ TEST_F(CompositedLayerMappingTest,
GetDocument().View()->SetTracksRasterInvalidations(false);
}
-TEST_F(CompositedLayerMappingTest, SimpleInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 200px; will-change: "
- "transform'></div>");
+TEST_P(CompositedLayerMappingTest, SimpleInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target' style='width: 200px; height: 200px;
+ will-change: transform; background: blue'>
+ </div>
+ )HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
ASSERT_TRUE(paint_layer->GetCompositedLayerMapping());
- EXPECT_EQ(IntRect(0, 0, 200, 200),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, TallLayerInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 10000px; will-change: "
- "transform'></div>");
+TEST_P(CompositedLayerMappingTest, TallLayerInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target' style='width: 200px; height: 10000px;
+ will-change: transform; background: blue'>
+ </div>
+ )HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
// Screen-space visible content rect is [8, 8, 200, 600]. Mapping back to
// local, adding 4000px in all directions, then clipping, yields this rect.
- EXPECT_EQ(IntRect(0, 0, 200, 4592),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 4592),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, TallCompositedScrolledLayerInterestRect) {
+TEST_P(CompositedLayerMappingTest, TallCompositedScrolledLayerInterestRect) {
SetBodyInnerHTML(R"HTML(
- <div style='width: 200px; height: 1000px;'></div>
- <div id='target'
- style='width: 200px; height: 10000px; will-change: transform'>
- </div>
+ <div style='width: 200px; height: 1000px;'></div>
+ <div id='target' style='width: 200px; height: 10000px;
+ will-change: transform; background: blue'>
+ </div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 8000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 2992, 200, 7008),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 2992, 200, 7008),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, TallNonCompositedScrolledLayerInterestRect) {
+TEST_P(CompositedLayerMappingTest, TallNonCompositedScrolledLayerInterestRect) {
SetHtmlInnerHTML(R"HTML(
- <div style='width: 200px; height: 11000px;'></div>
+ <div style='width: 200px; height: 11000px'></div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 8000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetDocument().GetLayoutView()->Layer();
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 4000, 800, 7016),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 4000, 800, 7016),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, TallLayerWholeDocumentInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 10000px; will-change: "
- "transform'></div>");
+TEST_P(CompositedLayerMappingTest, TallLayerWholeDocumentInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target' style='width: 200px; height: 10000px;
+ will-change: transform; background: blue'>
+ </div>
+ )HTML");
GetDocument().GetSettings()->SetMainFrameClipsContent(false);
@@ -253,22 +250,18 @@ TEST_F(CompositedLayerMappingTest, TallLayerWholeDocumentInterestRect) {
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
ASSERT_TRUE(paint_layer->GetCompositedLayerMapping());
- // Clipping is disabled in recomputeInterestRect.
- EXPECT_EQ(IntRect(0, 0, 200, 10000),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
- EXPECT_EQ(
- IntRect(0, 0, 200, 10000),
- ComputeInterestRect(paint_layer->GraphicsLayerBacking(), IntRect()));
+ // Clipping is disabled.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 10000),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, VerticalRightLeftWritingModeDocument) {
+TEST_P(CompositedLayerMappingTest, VerticalRightLeftWritingModeDocument) {
SetBodyInnerHTML(R"HTML(
<style>html,body { margin: 0px } html { -webkit-writing-mode:
vertical-rl}</style> <div id='target' style='width: 10000px; height:
200px;'></div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(-5000, 0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
@@ -279,42 +272,40 @@ TEST_F(CompositedLayerMappingTest, VerticalRightLeftWritingModeDocument) {
// A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px =
// 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each
// direction yields this result.
- EXPECT_EQ(IntRect(200, 0, 8800, 600),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(200, 0, 8800, 600),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, RotatedInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 200px; will-change: "
- "transform; transform: rotateZ(45deg)'></div>");
+TEST_P(CompositedLayerMappingTest, RotatedInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 200px; height: 200px; will-change: transform;
+ transform: rotateZ(45deg); background: blue'>
+ </div>
+ )HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 200, 200),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, RotatedInterestRectNear90Degrees) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 10000px; height: 200px; will-change: "
- "transform; transform: rotateY(89.9999deg)'></div>");
+TEST_P(CompositedLayerMappingTest, RotatedInterestRectNear90Degrees) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 10000px; height: 200px; will-change: transform;
+ transform-origin: 0 0; transform: rotateY(89.9999deg);
+ background: blue'>
+ </div>
+ )HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- // Because the layer is rotated to almost 90 degrees, floating-point error
- // leads to a reverse-projected rect that is much much larger than the
- // original layer size in certain dimensions. In such cases, we often fall
- // back to the 4000px interest rect padding amount.
- EXPECT_EQ(IntRect(0, 0, 4000, 200),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 10000, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, LargeScaleInterestRect) {
- // It's rotated 90 degrees about the X axis, which means its visual content
- // rect is empty, and so the interest rect is the default (0, 0, 4000, 4000)
- // intersected with the layer bounds.
+TEST_P(CompositedLayerMappingTest, LargeScaleInterestRect) {
SetBodyInnerHTML(R"HTML(
<style>
.container {
@@ -348,14 +339,13 @@ TEST_F(CompositedLayerMappingTest, LargeScaleInterestRect) {
</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 1920, 5300),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 1920, 5300),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, PerspectiveInterestRect) {
+TEST_P(CompositedLayerMappingTest, PerspectiveInterestRect) {
SetBodyInnerHTML(R"HTML(<div style='left: 400px; position: absolute;'>
<div id=target style='transform: perspective(1000px) rotateX(-100deg);'>
<div style='width: 1200px; height: 835px; background: lightblue;
@@ -363,136 +353,196 @@ TEST_F(CompositedLayerMappingTest, PerspectiveInterestRect) {
</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 1202, 837),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 1202, 837),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, RotationInterestRect) {
+TEST_P(CompositedLayerMappingTest, RotationInterestRect) {
SetBodyInnerHTML(R"HTML(
- <style>
- .red_box {
- position: fixed;
- height: 100px;
- width: 100vh; /* height of view, after -90 rot */
- right: calc(16px - 50vh); /* 16 pixels above top of view, after -90 */
- top: calc(50vh - 16px); /* 16 pixels in from right side, after -90 rot */
- transform-origin: top;
- transform: rotate(-90deg);
- background-color: red;
- will-change: transform;
- }
- .blue_box {
- height: 30px;
- width: 600px;
- background: blue;
- }
-</style>
-<div class="red_box" id=target>
- <div class="blue_box"></div>
-</div>
-
+ <style>
+ .red_box {
+ position: fixed;
+ height: 100px;
+ width: 100vh; /* height of view, after -90 rot */
+ right: calc(16px - 50vh); /* 16 pixels above top of view, after -90 */
+ top: calc(50vh - 16px); /* 16 pixels in from right side, after -90 rot */
+ transform-origin: top;
+ transform: rotate(-90deg);
+ background-color: red;
+ will-change: transform;
+ }
+ .blue_box {
+ height: 30px;
+ width: 600px;
+ background: blue;
+ }
+ </style>
+ <div class="red_box" id=target>
+ <div class="blue_box"></div>
+ </div>
)HTML");
GetFrame().View()->Resize(2000, 3000);
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 3000, 100),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 3000, 100),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, 3D90DegRotatedTallInterestRect) {
+TEST_P(CompositedLayerMappingTest, 3D90DegRotatedTallInterestRect) {
// It's rotated 90 degrees about the X axis, which means its visual content
- // rect is empty, and so the interest rect is the default (0, 0, 4000, 4000)
- // intersected with the layer bounds.
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 10000px; will-change: "
- "transform; transform: rotateY(90deg)'></div>");
+ // rect is empty.
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin: 0}</style>
+ <div id='target'
+ style='width: 200px; height: 10000px; will-change: transform;
+ transform: rotateY(90deg); background: blue'>
+ </div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 200, 4000),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // Use the default (-4000, -4000, 8800, 8600) intersected with the layer
+ // bounds.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 4600),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ } else {
+ // Use the default (-4000, -4000, 8000, 8000) intersected with the layer
+ // bounds.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 4000),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ }
}
-TEST_F(CompositedLayerMappingTest, 3D45DegRotatedTallInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 10000px; will-change: "
- "transform; transform: rotateY(45deg)'></div>");
+TEST_P(CompositedLayerMappingTest, 3D45DegRotatedTallInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 200px; height: 10000px; will-change: transform;
+ transform: rotateY(45deg); background: blue'>
+ </div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 200, 6226),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // CullRectUpdate expands the cull rect twice. The first expansion is for
+ // composited scrolling of the LayoutView, and it's not big enough for
+ // |target| (as it has a sqrt(2) max scale from screen to local pixels)
+ // thus the second expansion.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 10000),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ } else {
+ // Interest rect is expanded in both direction by 4000 * sqrt(2) pixels,
+ // then intersected with the layer bounds.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 6226),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ }
}
-TEST_F(CompositedLayerMappingTest, RotatedTallInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 200px; height: 10000px; will-change: "
- "transform; transform: rotateZ(45deg)'></div>");
+TEST_P(CompositedLayerMappingTest, RotatedTallInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 200px; height: 10000px; will-change: transform;
+ transform: rotateZ(45deg); background: blue'>
+ </div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 200, 4000),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ } else {
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 4000),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ }
}
-TEST_F(CompositedLayerMappingTest, WideLayerInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 10000px; height: 200px; will-change: "
- "transform'></div>");
+TEST_P(CompositedLayerMappingTest, WideLayerInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target' style='width: 10000px; height: 200px;
+ will-change: transform; background: blue'>
+ </div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
// Screen-space visible content rect is [8, 8, 800, 200] (the screen is
// 800x600). Mapping back to local, adding 4000px in all directions, then
// clipping, yields this rect.
- EXPECT_EQ(IntRect(0, 0, 4792, 200),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 4792, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, FixedPositionInterestRect) {
- SetBodyInnerHTML(
- "<div id='target' style='width: 300px; height: 400px; will-change: "
- "transform; position: fixed; top: 100px; left: 200px;'></div>");
+TEST_P(CompositedLayerMappingTest, FixedPositionInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 300px; height: 400px; will-change: transform;
+ position: fixed; top: 100px; left: 200px; background: blue'>
+ </div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 300, 400),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ EXPECT_EQ(gfx::Rect(0, 0, 300, 400),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, LayerOffscreenInterestRect) {
+TEST_P(CompositedLayerMappingTest, LayerFarOffscreenInterestRect) {
SetBodyInnerHTML(R"HTML(
- <div id='target' style='width: 200px; height: 200px; will-change:
- transform; position: absolute; top: 9000px; left: 0px;'>
+ <div id='target'
+ style='width: 200px; height: 200px; position: absolute; top: 9000px;
+ left: 0px; will-change: transform; background: blue'>
</div>
)HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
- ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- // Offscreen layers are painted as usual.
- EXPECT_EQ(IntRect(0, 0, 200, 200),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // CullRectUpdate knows the layer is far away from the viewport.
+ EXPECT_EQ(gfx::Rect(),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ } else {
+ // Offscreen layers are painted as usual.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
+ }
+}
+
+TEST_P(CompositedLayerMappingTest, LayerNearOffscreenInterestRect) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='target'
+ style='width: 200px; height: 200px; position: absolute; top: 3000px;
+ left: 0px; will-change: transform; background: blue'>
+ </div>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+ PaintLayer* paint_layer = GetPaintLayerByElementId("target");
+ ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
+ // Offscreen layers near to the viewport are painted as usual.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, ScrollingLayerInterestRect) {
+TEST_P(CompositedLayerMappingTest, ScrollingLayerInterestRect) {
SetBodyInnerHTML(R"HTML(
<style>
div::-webkit-scrollbar{ width: 5px; }
</style>
- <div id='target' style='width: 200px; height: 200px; will-change:
- transform; overflow: scroll'>
- <div style='width: 100px; height: 10000px'></div></div>
+ <div id='target'
+ style='width: 200px; height: 200px; will-change: transform;
+ overflow: scroll; background: blue'>
+ <div style='width: 100px; height: 10000px'></div>
+ </div>
)HTML");
UpdateAllLifecyclePhasesForTest();
@@ -506,26 +556,31 @@ TEST_F(CompositedLayerMappingTest, ScrollingLayerInterestRect) {
// Applying the viewport clip of the root has no effect because
// the clip is already small. Mapping it down into the graphics layer
// space yields (0, 0, 195, 193). This is then expanded by 4000px.
- EXPECT_EQ(IntRect(0, 0, 195, 4193),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 195, 4193),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, ClippedBigLayer) {
+TEST_P(CompositedLayerMappingTest, ClippedBigLayer) {
SetBodyInnerHTML(R"HTML(
<div style='width: 1px; height: 1px; overflow: hidden'>
- <div id='target' style='width: 10000px; height: 10000px; will-change:
- transform'></div></div>
+ <div id='target' style='width: 10000px; height: 10000px;
+ will-change: transform; background: blue'>
+ </div>
+ </div>
)HTML");
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetPaintLayerByElementId("target");
ASSERT_TRUE(paint_layer->GraphicsLayerBacking());
// Offscreen layers are painted as usual.
- EXPECT_EQ(IntRect(0, 0, 4001, 4001),
- RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 4001, 4001),
+ PaintableRegion(paint_layer->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, InterestRectChangedEnoughToRepaintEmpty) {
+TEST_P(CompositedLayerMappingTest, InterestRectChangedEnoughToRepaintEmpty) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
IntSize layer_size(1000, 1000);
// Both empty means there is nothing to do.
EXPECT_FALSE(
@@ -539,8 +594,11 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangedEnoughToRepaintEmpty) {
IntRect(), layer_size));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectChangedEnoughToRepaintNotBigEnough) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
IntSize layer_size(1000, 1000);
IntRect previous_interest_rect(100, 100, 100, 100);
EXPECT_FALSE(InterestRectChangedEnoughToRepaint(
@@ -551,8 +609,11 @@ TEST_F(CompositedLayerMappingTest,
previous_interest_rect, IntRect(1, 1, 200, 200), layer_size));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectChangedEnoughToRepaintNotBigEnoughButNewAreaTouchesEdge) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
IntSize layer_size(500, 500);
IntRect previous_interest_rect(100, 100, 100, 100);
// Top edge.
@@ -571,8 +632,11 @@ TEST_F(CompositedLayerMappingTest,
// Verifies that having a current viewport that touches a layer edge does not
// force re-recording.
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectChangedEnoughToRepaintCurrentViewportTouchesEdge) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
IntSize layer_size(500, 500);
IntRect new_interest_rect(100, 100, 300, 300);
// Top edge.
@@ -589,8 +653,11 @@ TEST_F(CompositedLayerMappingTest,
IntRect(400, 300, 100, 100), new_interest_rect, layer_size));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectChangedEnoughToRepaintScrollScenarios) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
IntSize layer_size(1000, 1000);
IntRect previous_interest_rect(100, 100, 100, 100);
IntRect new_interest_rect(previous_interest_rect);
@@ -608,7 +675,7 @@ TEST_F(CompositedLayerMappingTest,
previous_interest_rect, new_interest_rect, layer_size));
}
-TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
+TEST_P(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { width: 0; height: 0; }
@@ -617,60 +684,45 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
<div id='div' style='width: 100px; height: 10000px'>Text</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
GraphicsLayer* root_scrolling_layer =
GetDocument().GetLayoutView()->Layer()->GraphicsLayerBacking();
- EXPECT_EQ(IntRect(0, 0, 800, 4600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), PaintableRegion(root_scrolling_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 300), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because the recomputed rect hasn't
// changed enough.
- EXPECT_EQ(IntRect(0, 0, 800, 4900),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 800, 4600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), PaintableRegion(root_scrolling_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 600), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Use recomputed interest rect because it changed enough.
- EXPECT_EQ(IntRect(0, 0, 800, 5200),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 800, 5200),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 5200), PaintableRegion(root_scrolling_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 5400), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 1400, 800, 8600),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 1400, 800, 8600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 1400, 800, 8600),
+ PaintableRegion(root_scrolling_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 9000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because it contains the recomputed
// interest rect.
- EXPECT_EQ(IntRect(0, 5000, 800, 5000),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 1400, 800, 8600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 1400, 800, 8600),
+ PaintableRegion(root_scrolling_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 2000), mojom::blink::ScrollType::kProgrammatic);
// Use recomputed interest rect because it changed enough.
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 0, 800, 6600),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 800, 6600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 6600), PaintableRegion(root_scrolling_layer));
}
-TEST_F(CompositedLayerMappingTest, InterestRectChangeOnShrunkenViewport) {
+TEST_P(CompositedLayerMappingTest, InterestRectChangeOnShrunkenViewport) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { width: 0; height: 0; }
@@ -679,22 +731,17 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnShrunkenViewport) {
<div id='div' style='width: 100px; height: 10000px'>Text</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
GraphicsLayer* root_scrolling_layer =
GetDocument().GetLayoutView()->Layer()->GraphicsLayerBacking();
- EXPECT_EQ(IntRect(0, 0, 800, 4600),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 4600), PaintableRegion(root_scrolling_layer));
GetDocument().View()->SetFrameRect(IntRect(0, 0, 800, 60));
UpdateAllLifecyclePhasesForTest();
// Repaint required, so interest rect should be updated to shrunken size.
- EXPECT_EQ(IntRect(0, 0, 800, 4060),
- RecomputeInterestRect(root_scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 800, 4060),
- PreviousInterestRect(root_scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 4060), PaintableRegion(root_scrolling_layer));
}
-TEST_F(CompositedLayerMappingTest, InterestRectChangeOnScroll) {
+TEST_P(CompositedLayerMappingTest, InterestRectChangeOnScroll) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
@@ -703,53 +750,44 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnScroll) {
::-webkit-scrollbar { width: 0; height: 0; }
body { margin: 0; }
</style>
- <div id='scroller' style='width: 400px; height: 400px; overflow:
- scroll'>
+ <div id='scroller' style='width: 400px; height: 400px; overflow: scroll'>
<div id='content' style='width: 100px; height: 10000px'>Text</div>
</div
)HTML");
- UpdateAllLifecyclePhasesForTest();
Element* scroller = GetDocument().getElementById("scroller");
GraphicsLayer* scrolling_layer =
scroller->GetLayoutBox()->Layer()->GraphicsLayerBacking();
- EXPECT_EQ(IntRect(0, 0, 400, 4400), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 400, 4400), PaintableRegion(scrolling_layer));
scroller->setScrollTop(300);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because the recomputed rect hasn't
// changed enough.
- EXPECT_EQ(IntRect(0, 0, 400, 4700), RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 400, 4400), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 400, 4400), PaintableRegion(scrolling_layer));
scroller->setScrollTop(600);
UpdateAllLifecyclePhasesForTest();
// Use recomputed interest rect because it changed enough.
- EXPECT_EQ(IntRect(0, 0, 400, 5000), RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 400, 5000), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 400, 5000), PaintableRegion(scrolling_layer));
scroller->setScrollTop(5600);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 1600, 400, 8400),
- RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 1600, 400, 8400), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 1600, 400, 8400), PaintableRegion(scrolling_layer));
scroller->setScrollTop(9000);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because it contains the recomputed
// interest rect.
- EXPECT_EQ(IntRect(0, 5000, 400, 5000),
- RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 1600, 400, 8400), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 1600, 400, 8400), PaintableRegion(scrolling_layer));
scroller->setScrollTop(2000);
// Use recomputed interest rect because it changed enough.
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 0, 400, 6400), RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 0, 400, 6400), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 0, 400, 6400), PaintableRegion(scrolling_layer));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectShouldChangeOnPaintInvalidation) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
@@ -770,23 +808,22 @@ TEST_F(CompositedLayerMappingTest,
GraphicsLayer* scrolling_layer =
scroller->GetLayoutBox()->Layer()->GraphicsLayerBacking();
- scroller->setScrollTop(5400);
+ scroller->setScrollTop(5800);
UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(gfx::Rect(0, 1800, 400, 8200), PaintableRegion(scrolling_layer));
+
scroller->setScrollTop(9400);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 5400, 400, 4600),
- RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 5400, 400, 4600), PreviousInterestRect(scrolling_layer));
+ // Still use the old cull rect because it contains the new recomputed one.
+ EXPECT_EQ(gfx::Rect(0, 1800, 400, 8200), PaintableRegion(scrolling_layer));
// Paint invalidation and repaint should change previous paint interest rect.
GetDocument().getElementById("content")->setTextContent("Change");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(0, 5400, 400, 4600),
- RecomputeInterestRect(scrolling_layer));
- EXPECT_EQ(IntRect(0, 5400, 400, 4600), PreviousInterestRect(scrolling_layer));
+ EXPECT_EQ(gfx::Rect(0, 5400, 400, 4600), PaintableRegion(scrolling_layer));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectOfSquashingLayerWithNegativeOverflow) {
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; font-size: 16px; }</style>
@@ -814,50 +851,59 @@ TEST_F(CompositedLayerMappingTest,
// The squashing layer is at (-10000, 190, 10100, 100) in viewport
// coordinates.
// The following rect is at (-4000, 190, 4100, 100) in viewport coordinates.
- EXPECT_EQ(IntRect(6000, 0, 4100, 100),
- grouped_mapping->ComputeInterestRect(
- grouped_mapping->NonScrollingSquashingLayer(), IntRect()));
+ EXPECT_EQ(gfx::Rect(6000, 0, 4100, 100),
+ PaintableRegion(grouped_mapping->NonScrollingSquashingLayer()));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
InterestRectOfSquashingLayerWithAncestorClip) {
- SetBodyInnerHTML(
- "<style>body { margin: 0; }</style>"
- "<div style='overflow: hidden; width: 400px; height: 400px'>"
- " <div style='position: relative; backface-visibility: hidden'>"
- " <div style='position: absolute; top: -500px; width: 200px; height: "
- "700px; backface-visibility: hidden'></div>"
- // Above overflow:hidden div and two composited layers make the squashing
- // layer a child of an ancestor clipping layer.
- " <div id='squashed' style='height: 1000px; width: 10000px; right: 0; "
- "position: absolute'></div>"
- " </div>"
- "</div>");
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin: 0; }</style>
+ <div style='overflow: hidden; width: 400px; height: 400px'>
+ <div style='position: relative; backface-visibility: hidden'>
+ <div style='position: absolute; top: -500px; width: 200px;
+ height: 700px; backface-visibility: hidden'></div>
+ <!-- Above overflow:hidden div and two composited layers make the
+ squashing layer a child of an ancestor clipping layer. -->
+ <div id='squashed' style='height: 1000px; width: 10000px; right: 0;
+ position: absolute'></div>
+ </div>
+ </div>
+ )HTML");
CompositedLayerMapping* grouped_mapping = GetDocument()
.getElementById("squashed")
->GetLayoutBox()
->Layer()
->GroupedMapping();
- // The squashing layer is at (-9600, 0, 10000, 1000) in viewport coordinates.
- // The following rect is at (-4000, 0, 4400, 1000) in viewport coordinates.
- EXPECT_EQ(IntRect(5600, 0, 4400, 1000),
- grouped_mapping->ComputeInterestRect(
- grouped_mapping->NonScrollingSquashingLayer(), IntRect()));
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // CullRectUpdate doesn't expand cull rect for layers without directly
+ // composited transform.
+ EXPECT_EQ(gfx::Rect(9600, 0, 400, 400),
+ PaintableRegion(grouped_mapping->NonScrollingSquashingLayer()));
+ } else {
+ // The squashing layer is at (-9600, 0, 10000, 1000) in viewport
+ // coordinates. The following rect is at (-4000, 0, 4400, 1000) in viewport
+ // coordinates.
+ EXPECT_EQ(gfx::Rect(5600, 0, 4400, 1000),
+ PaintableRegion(grouped_mapping->NonScrollingSquashingLayer()));
+ }
}
-TEST_F(CompositedLayerMappingTest, InterestRectOfIframeInScrolledDiv) {
+TEST_P(CompositedLayerMappingTest, InterestRectOfIframeInScrolledDiv) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
<div style='width: 200; height: 8000px'></div>
- <iframe src='http://test.com' width='500' height='500'
- frameBorder='0'>
+ <iframe src='http://test.com' width='500' height='500' frameBorder='0'>
</iframe>
)HTML");
- SetChildFrameHTML(
- "<style>body { margin: 0; } #target { width: 200px; height: 200px; "
- "will-change: transform}</style><div id=target></div>");
+ SetChildFrameHTML(R"HTML(
+ <style>body { margin: 0; }</style>
+ <div id=target style='width: 200px; height: 200px; will-change: transform;
+ background: blue'>
+ </div>
+ )HTML");
// Scroll 8000 pixels down to move the iframe into view.
GetDocument().View()->LayoutViewport()->SetScrollOffset(
@@ -868,25 +914,27 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeInScrolledDiv) {
ASSERT_TRUE(target);
EXPECT_EQ(
- IntRect(0, 0, 200, 200),
- RecomputeInterestRect(
+ gfx::Rect(0, 0, 200, 200),
+ PaintableRegion(
target->GetLayoutObject()->EnclosingLayer()->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, InterestRectOfScrolledIframe) {
+TEST_P(CompositedLayerMappingTest, InterestRectOfScrolledIframe) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
SetBodyInnerHTML(R"HTML(
- <style>body { margin: 0; } ::-webkit-scrollbar { display: none;
- }</style>
- <iframe src='http://test.com' width='500' height='500'
- frameBorder='0'>
+ <style>
+ body { margin: 0; }
+ ::-webkit-scrollbar { display: none; }
+ </style>
+ <iframe src='http://test.com' width='500' height='500' frameBorder='0'>
</iframe>
)HTML");
- SetChildFrameHTML(
- "<style>body { margin: 0; } #target { width: 200px; "
- "height: 8000px;}</style><div id=target></div>");
+ SetChildFrameHTML(R"HTML(
+ <style>body { margin: 0; }</style>
+ <div id=target style='width: 200px; height: 8000px'></div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
@@ -896,30 +944,33 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfScrolledIframe) {
UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(ChildDocument().View()->GetLayoutView()->HasLayer());
- EXPECT_EQ(IntRect(0, 3500, 500, 4500),
- RecomputeInterestRect(ChildDocument()
- .View()
- ->GetLayoutView()
- ->EnclosingLayer()
- ->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 3500, 500, 4500),
+ PaintableRegion(ChildDocument()
+ .View()
+ ->GetLayoutView()
+ ->EnclosingLayer()
+ ->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithContentBoxOffset) {
+TEST_P(CompositedLayerMappingTest, InterestRectOfIframeWithContentBoxOffset) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
// Set a 10px border in order to have a contentBoxOffset for the iframe
// element.
SetBodyInnerHTML(R"HTML(
- <style>body { margin: 0; } #frame { border: 10px solid black; }
- ::-webkit-scrollbar { display: none; }</style>
- <iframe src='http://test.com' width='500' height='500'
- frameBorder='0'>
+ <style>
+ body { margin: 0; }
+ #frame { border: 10px solid black; }
+ ::-webkit-scrollbar { display: none; }
+ </style>
+ <iframe src='http://test.com' width='500' height='500' frameBorder='0'>
</iframe>
)HTML");
- SetChildFrameHTML(
- "<style>body { margin: 0; } #target { width: 200px; "
- "height: 8000px;}</style> <div id=target></div>");
+ SetChildFrameHTML(R"HTML(
+ <style>body { margin: 0; }</style>
+ <div id=target style='width: 200px; height: 8000px'></div>
+ )HTML");
UpdateAllLifecyclePhasesForTest();
@@ -930,15 +981,15 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithContentBoxOffset) {
UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(ChildDocument().View()->GetLayoutView()->HasLayer());
- EXPECT_EQ(IntRect(0, 0, 500, 7500),
- RecomputeInterestRect(ChildDocument()
- .View()
- ->GetLayoutView()
- ->EnclosingLayer()
- ->GraphicsLayerBacking()));
+ EXPECT_EQ(gfx::Rect(0, 0, 500, 7500),
+ PaintableRegion(ChildDocument()
+ .View()
+ ->GetLayoutView()
+ ->EnclosingLayer()
+ ->GraphicsLayerBacking()));
}
-TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithFixedContents) {
+TEST_P(CompositedLayerMappingTest, InterestRectOfIframeWithFixedContents) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
@@ -950,8 +1001,8 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithFixedContents) {
SetChildFrameHTML(R"HTML(
<style>body { margin:0; } ::-webkit-scrollbar { display:none; }</style>
<div id='forcescroll' style='height:6000px;'></div>
- <div id='fixed' style='
- position:fixed; top:0; left:0; width:400px; height:300px;'>
+ <div id='fixed' style='position:fixed; top:0; left:0; width:400px;
+ height:300px; background:blue'>
<div id='leftbox' style='
position:absolute; left:-5000px; width:10px; height:10px;'></div>
<div id='child' style='
@@ -965,17 +1016,17 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithFixedContents) {
// The graphics layer has dimensions 5400x300 but the interest rect clamps
// this to the right-most 4000x4000 area.
- EXPECT_EQ(IntRect(1000, 0, 4400, 300), RecomputeInterestRect(graphics_layer));
+ EXPECT_EQ(gfx::Rect(1000, 0, 4400, 300), PaintableRegion(graphics_layer));
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0.0, 3000.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Because the fixed element does not scroll, the interest rect is unchanged.
- EXPECT_EQ(IntRect(1000, 0, 4400, 300), RecomputeInterestRect(graphics_layer));
+ EXPECT_EQ(gfx::Rect(1000, 0, 4400, 300), PaintableRegion(graphics_layer));
}
-TEST_F(CompositedLayerMappingTest, ScrolledFixedPositionInterestRect) {
+TEST_P(CompositedLayerMappingTest, ScrolledFixedPositionInterestRect) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
SetBodyInnerHTML(R"HTML(
@@ -988,20 +1039,19 @@ TEST_F(CompositedLayerMappingTest, ScrolledFixedPositionInterestRect) {
<div id="forcescroll" style="height: 2000px;"></div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
auto* fixed = GetDocument().getElementById("fixed")->GetLayoutObject();
auto* graphics_layer = fixed->EnclosingLayer()->GraphicsLayerBacking(fixed);
- EXPECT_EQ(IntRect(0, 500, 100, 4030), RecomputeInterestRect(graphics_layer));
+ EXPECT_EQ(gfx::Rect(0, 500, 100, 4030), PaintableRegion(graphics_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0.0, 200.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Because the fixed element does not scroll, the interest rect is unchanged.
- EXPECT_EQ(IntRect(0, 500, 100, 4030), RecomputeInterestRect(graphics_layer));
+ EXPECT_EQ(gfx::Rect(0, 500, 100, 4030), PaintableRegion(graphics_layer));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
ScrollingContentsAndForegroundLayerPaintingPhase) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
@@ -1051,20 +1101,21 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_FALSE(mapping->ForegroundLayer());
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
DecorationOutlineLayerOnlyCreatedInCompositedScrolling) {
SetBodyInnerHTML(R"HTML(
<style>
- #target { overflow: scroll; height: 200px; width: 200px; will-change:
- transform; background: white local content-box;
- outline: 1px solid blue; outline-offset: -2px;}
+ #target {
+ overflow: scroll; height: 200px; width: 200px; will-change: transform;
+ background: white local content-box;
+ outline: 1px solid blue; outline-offset: -2px;
+ }
#scrolled { height: 300px; }
</style>
<div id="parent">
<div id="target"><div id="scrolled"></div></div>
</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
Element* element = GetDocument().getElementById("target");
PaintLayer* paint_layer =
@@ -1089,19 +1140,20 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_FALSE(mapping->DecorationOutlineLayer());
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
DecorationOutlineLayerCreatedAndDestroyedInCompositedScrolling) {
SetBodyInnerHTML(R"HTML(
<style>
- #scroller { overflow: scroll; height: 200px; width: 200px; background:
- white local content-box; outline: 1px solid blue; contain: paint; }
+ #scroller {
+ overflow: scroll; height: 200px; width: 200px; contain: paint;
+ background: white local content-box; outline: 1px solid blue;
+ }
#scrolled { height: 300px; }
</style>
<div id="parent">
<div id="scroller"><div id="scrolled"></div></div>
</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
Element* scroller = GetDocument().getElementById("scroller");
PaintLayer* paint_layer =
@@ -1133,7 +1185,7 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_FALSE(mapping->DecorationOutlineLayer());
}
-TEST_F(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
+TEST_P(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
SetBodyInnerHTML(R"HTML(
<style>.composited { backface-visibility: hidden; }
#scroller { overflow: auto; height: 200px; width: 200px; }
@@ -1168,7 +1220,7 @@ TEST_F(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
EXPECT_FALSE(sticky_layer->NeedsCompositingInputsUpdate());
}
-TEST_F(CompositedLayerMappingTest, StickyPositionNotSquashed) {
+TEST_P(CompositedLayerMappingTest, StickyPositionNotSquashed) {
SetBodyInnerHTML(R"HTML(
<style>
#scroller { overflow: auto; height: 200px; }
@@ -1198,7 +1250,7 @@ TEST_F(CompositedLayerMappingTest, StickyPositionNotSquashed) {
EXPECT_EQ(kPaintsIntoOwnBacking, sticky3->GetCompositingState());
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
LayerPositionForStickyElementInCompositedScroller) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -1251,7 +1303,7 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_FLOAT_EQ(8, sticky_position_relative_to_root.Y());
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
LayerPositionForStickyElementInNonCompositedScroller) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -1297,7 +1349,7 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_FLOAT_EQ(8, sticky_position_relative_to_root.Y());
}
-TEST_F(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
+TEST_P(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
SetBodyInnerHTML(R"HTML(
@@ -1317,7 +1369,6 @@ TEST_F(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
</div
)HTML");
- UpdateAllLifecyclePhasesForTest();
Element* scrollerElement = GetDocument().getElementById("scroller");
auto* scroller =
To<LayoutBoxModelObject>(GetLayoutObjectByElementId("scroller"));
@@ -1348,8 +1399,7 @@ TEST_F(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
EXPECT_EQ(100, scroll_node->container_bounds.height());
}
-TEST_F(CompositedLayerMappingTest, MainFrameLayerBackgroundColor) {
- UpdateAllLifecyclePhasesForTest();
+TEST_P(CompositedLayerMappingTest, MainFrameLayerBackgroundColor) {
EXPECT_EQ(Color::kWhite, GetDocument().View()->BaseBackgroundColor());
auto* view_cc_layer = ScrollingContentsCcLayerByScrollElementId(
GetFrame().View()->RootCcLayer(),
@@ -1366,7 +1416,7 @@ TEST_F(CompositedLayerMappingTest, MainFrameLayerBackgroundColor) {
view_cc_layer->background_color());
}
-TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
+TEST_P(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
// This test verifies that when subpixel accumulation causes snapping it
// applies to the scrolling contents layer. Verify that the mapping doesn't
// have any vertical scrolling introduced as a result of the snapping
@@ -1398,7 +1448,6 @@ TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
<div id="space"></div>
</div>
)HTML");
- UpdateAllLifecyclePhasesForTest();
auto* mapping =
GetPaintLayerByElementId("scroller")->GetCompositedLayerMapping();
ASSERT_TRUE(mapping);
@@ -1407,15 +1456,15 @@ TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
EXPECT_EQ(gfx::Size(1000, 200), mapping->ScrollingContentsLayer()->Size());
}
-TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
+TEST_P(CompositedLayerMappingTest, SquashingScrollInterestRect) {
SetHtmlInnerHTML(R"HTML(
<style>
* { margin: 0 }
</style>
- <div id=target
- style='width: 200px; height: 200px; position: relative; will-change: transform'></div>
- <div id=squashed
- style='width: 200px; height: 6000px; top: -200px; position: relative;'></div>
+ <div id=target style='width: 200px; height: 200px; position: relative;
+ will-change: transform'></div>
+ <div id=squashed style='width: 200px; height: 6000px; top: -200px;
+ position: relative;'></div>
)HTML");
auto* squashed = GetPaintLayerByElementId("squashed");
@@ -1426,11 +1475,11 @@ TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(
- IntRect(0, 1000, 200, 5000),
- squashed->GroupedMapping()->SquashingLayer(*squashed)->InterestRect());
+ gfx::Rect(0, 1000, 200, 5000),
+ PaintableRegion(squashed->GroupedMapping()->SquashingLayer(*squashed)));
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
SquashingBoundsUnderCompositedScrollingWithTransform) {
SetHtmlInnerHTML(R"HTML(
<div id=scroller style="will-change: transform; overflow: scroll;
@@ -1463,7 +1512,7 @@ TEST_F(CompositedLayerMappingTest,
squashed->GraphicsLayerBacking()->GetOffsetFromTransformNode());
}
-TEST_F(CompositedLayerMappingTest, ContentsNotOpaqueWithForegroundLayer) {
+TEST_P(CompositedLayerMappingTest, ContentsNotOpaqueWithForegroundLayer) {
SetHtmlInnerHTML(R"HTML(
<style>
div {
@@ -1481,10 +1530,10 @@ TEST_F(CompositedLayerMappingTest, ContentsNotOpaqueWithForegroundLayer) {
PaintLayer* target_layer = GetPaintLayerByElementId("target");
CompositedLayerMapping* mapping = target_layer->GetCompositedLayerMapping();
EXPECT_TRUE(mapping->ForegroundLayer());
- EXPECT_FALSE(mapping->MainGraphicsLayer()->ContentsOpaque());
+ EXPECT_FALSE(mapping->MainGraphicsLayer()->CcLayer().contents_opaque());
}
-TEST_F(CompositedLayerMappingTest, EmptyBoundsDoesntDrawContent) {
+TEST_P(CompositedLayerMappingTest, EmptyBoundsDoesntDrawContent) {
SetHtmlInnerHTML(R"HTML(
<style>
div {
@@ -1502,7 +1551,7 @@ TEST_F(CompositedLayerMappingTest, EmptyBoundsDoesntDrawContent) {
EXPECT_FALSE(mapping->MainGraphicsLayer()->DrawsContent());
}
-TEST_F(CompositedLayerMappingTest, TouchActionRectsWithoutContent) {
+TEST_P(CompositedLayerMappingTest, TouchActionRectsWithoutContent) {
SetBodyInnerHTML(
"<div id='target' style='will-change: transform; width: 100px;"
" height: 100px; touch-action: none;'></div>");
@@ -1521,7 +1570,7 @@ TEST_F(CompositedLayerMappingTest, TouchActionRectsWithoutContent) {
EXPECT_FALSE(mapping->MainGraphicsLayer()->DrawsContent());
}
-TEST_F(CompositedLayerMappingTest, ContentsOpaque) {
+TEST_P(CompositedLayerMappingTest, ContentsOpaque) {
SetHtmlInnerHTML(R"HTML(
<style>
div {
@@ -1538,10 +1587,10 @@ TEST_F(CompositedLayerMappingTest, ContentsOpaque) {
PaintLayer* target_layer = GetPaintLayerByElementId("target");
CompositedLayerMapping* mapping = target_layer->GetCompositedLayerMapping();
EXPECT_FALSE(mapping->ForegroundLayer());
- EXPECT_TRUE(mapping->MainGraphicsLayer()->ContentsOpaque());
+ EXPECT_TRUE(mapping->MainGraphicsLayer()->CcLayer().contents_opaque());
}
-TEST_F(CompositedLayerMappingTest, NullOverflowControlLayers) {
+TEST_P(CompositedLayerMappingTest, NullOverflowControlLayers) {
SetHtmlInnerHTML("<div id='target' style='will-change: transform'></div>");
CompositedLayerMapping* mapping =
GetPaintLayerByElementId("target")->GetCompositedLayerMapping();
@@ -1550,7 +1599,7 @@ TEST_F(CompositedLayerMappingTest, NullOverflowControlLayers) {
EXPECT_FALSE(mapping->LayerForScrollCorner());
}
-TEST_F(CompositedLayerMappingTest, CompositedHiddenAnimatingLayer) {
+TEST_P(CompositedLayerMappingTest, CompositedHiddenAnimatingLayer) {
SetHtmlInnerHTML(R"HTML(
<style>
@keyframes slide {
@@ -1588,7 +1637,7 @@ TEST_F(CompositedLayerMappingTest, CompositedHiddenAnimatingLayer) {
CompositingReason::kActiveTransformAnimation);
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
RepaintScrollableAreaLayersInMainThreadScrolling) {
SetHtmlInnerHTML(R"HTML(
<style>
@@ -1653,7 +1702,7 @@ TEST_F(CompositedLayerMappingTest,
EXPECT_TRUE(mapping->NeedsRepaint(*vertical_scrollbar_layer));
}
-TEST_F(CompositedLayerMappingTest, IsolationClippingContainer) {
+TEST_P(CompositedLayerMappingTest, IsolationClippingContainer) {
SetBodyInnerHTML(R"HTML(
<style>
#hideable {
@@ -1701,7 +1750,7 @@ TEST_F(CompositedLayerMappingTest, IsolationClippingContainer) {
EXPECT_EQ(squash_container_a_layer->ClippingContainer(), isolation_a_object);
}
-TEST_F(CompositedLayerMappingTest, SquashIntoScrollingContents) {
+TEST_P(CompositedLayerMappingTest, SquashIntoScrollingContents) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
SetBodyInnerHTML(R"HTML(
@@ -1755,7 +1804,7 @@ TEST_F(CompositedLayerMappingTest, SquashIntoScrollingContents) {
EXPECT_TRUE(target2->HasCompositedLayerMapping());
}
-TEST_F(CompositedLayerMappingTest,
+TEST_P(CompositedLayerMappingTest,
SwitchSquashingBetweenScrollingAndNonScrolling) {
GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
true);
@@ -1806,7 +1855,7 @@ TEST_F(CompositedLayerMappingTest,
// Unlike CompositingTest.WillChangeTransformHintInSVG, will-change hints on the
// SVG element itself should not opt into creating layers after paint.
-TEST_F(CompositedLayerMappingTest, WillChangeTransformHintOnSVG) {
+TEST_P(CompositedLayerMappingTest, WillChangeTransformHintOnSVG) {
ScopedCompositeSVGForTest enable_feature(true);
SetBodyInnerHTML(R"HTML(
<svg width="99" height="99" id="willChange" style="will-change: transform;">
@@ -1821,7 +1870,7 @@ TEST_F(CompositedLayerMappingTest, WillChangeTransformHintOnSVG) {
// Test that will-change changes inside SVG correctly update whether the
// graphics layer should create layers after paint.
-TEST_F(CompositedLayerMappingTest, WillChangeTransformHintInSVGChanged) {
+TEST_P(CompositedLayerMappingTest, WillChangeTransformHintInSVGChanged) {
ScopedCompositeSVGForTest enable_feature(true);
SetBodyInnerHTML(R"HTML(
<svg width="99" height="99" id="svg" style="will-change: transform;">
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
index 00933f0ca1f..4d712def8d1 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -42,9 +42,16 @@ bool CompositingInputsUpdater::LayerOrDescendantShouldBeComposited(
if (layout_view->AdditionalCompositingReasons())
return true;
// The containing frame may call this function for the root layer of a
- // throttled frame. Return the current compositing status.
- if (layout_view->GetFrameView()->ShouldThrottleRendering())
- return layout_view->UsesCompositing();
+ // throttled frame. In that case, look for a pre-existing root GraphicsLayer
+ // in the iframe's compositor.
+ if (layout_view->GetFrameView()->ShouldThrottleRendering()) {
+ DisableCompositingQueryAsserts disabler;
+ if (auto* inner_compositor = layout_view->Compositor()) {
+ if (inner_compositor->RootGraphicsLayer())
+ return true;
+ }
+ return false;
+ }
}
DCHECK(!layer->GetLayoutObject().GetFrameView()->ShouldThrottleRendering());
PaintLayerCompositor* compositor =
@@ -103,9 +110,6 @@ void CompositingInputsUpdater::ApplyAncestorInfoToSelfAndAncestorsRecursively(
if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled())
geometry_map_->PushMappingsToAncestor(layer, layer->Parent());
UpdateAncestorInfo(layer, update_type, info);
- if (layer != compositing_inputs_root_ &&
- layer->GetLayoutObject().IsScrollContainer())
- info.last_scroll_container_layer = layer;
}
void CompositingInputsUpdater::UpdateSelfAndDescendantsRecursively(
@@ -113,44 +117,6 @@ void CompositingInputsUpdater::UpdateSelfAndDescendantsRecursively(
UpdateType update_type,
AncestorInfo info) {
LayoutBoxModelObject& layout_object = layer->GetLayoutObject();
- const ComputedStyle& style = layout_object.StyleRef();
-
- const PaintLayer* previous_scroll_container_layer =
- layer->AncestorScrollContainerLayer();
- layer->UpdateAncestorScrollContainerLayer(info.last_scroll_container_layer);
- if (info.last_scroll_container_layer &&
- layer->NeedsCompositingInputsUpdate() &&
- style.HasStickyConstrainedPosition()) {
- if (info.last_scroll_container_layer != previous_scroll_container_layer) {
- // Old ancestor scroller should no longer have these constraints.
- DCHECK(!previous_scroll_container_layer ||
- !previous_scroll_container_layer->GetScrollableArea() ||
- !previous_scroll_container_layer->GetScrollableArea()
- ->GetStickyConstraintsMap()
- .Contains(layer));
-
- // If our ancestor scroller has changed and the previous one was the
- // root layer, we are no longer viewport constrained.
- if (previous_scroll_container_layer &&
- previous_scroll_container_layer->IsRootLayer()) {
- layout_object.View()->GetFrameView()->RemoveViewportConstrainedObject(
- layout_object, LocalFrameView::ViewportConstrainedType::kSticky);
- }
- }
-
- if (info.last_scroll_container_layer->IsRootLayer()) {
- layout_object.View()->GetFrameView()->AddViewportConstrainedObject(
- layout_object, LocalFrameView::ViewportConstrainedType::kSticky);
- }
- layout_object.UpdateStickyPositionConstraints();
-
- // Sticky position constraints and ancestor overflow scroller affect
- // the sticky layer position, so we need to update it again here.
- // TODO(flackr): This should be refactored in the future to be clearer
- // (i.e. update layer position and ancestor inputs updates in the
- // same walk)
- layer->UpdateLayerPosition();
- }
// geometry_map_ has been already updated in ApplyAncestorInfo() and
// UpdateAncestorInfo has been already computed in ApplyAncestorInfo() for
@@ -160,8 +126,6 @@ void CompositingInputsUpdater::UpdateSelfAndDescendantsRecursively(
geometry_map_->PushMappingsToAncestor(layer, layer->Parent());
UpdateAncestorInfo(layer, update_type, info);
}
- if (layout_object.IsScrollContainer())
- info.last_scroll_container_layer = layer;
PaintLayerCompositor* compositor =
layer->GetLayoutObject().View()->Compositor();
@@ -433,8 +397,7 @@ void CompositingInputsUpdater::UpdateAncestorInfo(PaintLayer* const layer,
.IsStackingContext())
info.escape_clip_to_for_absolute = nullptr;
if (info.escape_clip_to_for_fixed && style.EffectiveZIndex() < 0 &&
- !info.escape_clip_to_for_fixed->GetLayoutObject()
- .IsStackingContext())
+ !info.escape_clip_to_for_fixed->GetLayoutObject().IsStackingContext())
info.escape_clip_to_for_fixed = nullptr;
info.needs_reparent_scroll = info.needs_reparent_scroll_for_absolute =
@@ -463,13 +426,17 @@ void CompositingInputsUpdater::UpdateAncestorDependentCompositingInputs(
properties.unclipped_absolute_bounding_box =
EnclosingIntRect(geometry_map_->AbsoluteRect(
- layer->BoundingBoxForCompositingOverlapTest()));
+ layer->LocalBoundingBoxForCompositingOverlapTest()));
bool affected_by_scroll = root_layer_->GetScrollableArea() &&
layer->IsAffectedByScrollOf(root_layer_);
- // At ths point, |unclipped_absolute_bounding_box| is in viewport space.
+ // At this point, |unclipped_absolute_bounding_box| is in viewport space.
// To convert to absolute space, add scroll offset for non-fixed layers.
+ // Content that is not affected by scroll, e.g. fixed-pos content and
+ // children of that content, stays in viewport space so we can expand its
+ // bounds during overlap testing without having a dependency on the scroll
+ // offset at the time these properties are calculated.
if (affected_by_scroll) {
properties.unclipped_absolute_bounding_box.Move(
RoundedIntSize(root_layer_->GetScrollableArea()->GetScrollOffset()));
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
index f588f52c861..c86de38d496 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
@@ -42,7 +42,6 @@ class CompositingInputsUpdater {
// layer. This variable stores the squashing composited layer for the
// nearest PaintLayer ancestor which is squashed.
PaintLayer* enclosing_squashing_composited_layer = nullptr;
- PaintLayer* last_scroll_container_layer = nullptr;
PaintLayer* clip_chain_parent_for_absolute = nullptr;
PaintLayer* clip_chain_parent_for_fixed = nullptr;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
index 21f33a24f3d..fe38ca73555 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
@@ -75,9 +75,8 @@ TEST_F(CompositingInputsUpdaterTest,
->SetInlineStyleProperty(CSSPropertyID::kOverflow, "scroll");
// Before we update compositing inputs, validate that the current ancestor
- // overflow no longer has a scrollable area.
- GetDocument().View()->UpdateLifecycleToLayoutClean(
- DocumentUpdateReason::kTest);
+ // overflow no longer has a scrollable area after style update.
+ GetDocument().UpdateStyleAndLayoutTree();
EXPECT_FALSE(
sticky->Layer()->AncestorScrollContainerLayer()->GetScrollableArea());
EXPECT_EQ(sticky->Layer()->AncestorScrollContainerLayer(),
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
index dd79e1d7052..bbc951891a9 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
@@ -208,7 +208,7 @@ CompositingLayerAssigner::GetReasonsPreventingSquashing(
.SubtreeWillChangeContents() &&
squashing_layer.GetLayoutObject()
.StyleRef()
- .IsRunningAnimationOnCompositor()) ||
+ .RequiresPropertyNodeForAnimation()) ||
squashing_layer.GetLayoutObject()
.StyleRef()
.ShouldCompositeForCurrentAnimations())
@@ -395,7 +395,7 @@ void CompositingLayerAssigner::AssignLayersToBackingsInternal(
// squash layers painted after the iframe with layers painted before it.
if (layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
To<LayoutEmbeddedContent>(layer->GetLayoutObject())
- .ContentDocumentIsCompositing()) {
+ .ContentDocumentContainsGraphicsLayer()) {
squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree =
false;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index 18dbf5e032c..ed1f714c79b 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
@@ -64,7 +65,7 @@ CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
(!style.HasAutoClip() && style.HasOutOfFlowPosition()) ||
style.HasIsolation()) == layout_object.CreatesGroup());
- if (style.HasMask() || style.ClipPath())
+ if (style.HasMask() || style.HasClipPath())
reasons |= CompositingReason::kMaskWithCompositedDescendants;
if (style.HasFilterInducingProperty())
@@ -150,6 +151,9 @@ CompositingReasons CompositingReasonFinder::DirectReasonsForPaintProperties(
if (RequiresCompositingForScrollDependentPosition(*layer))
reasons |= CompositingReason::kScrollDependentPosition;
+ if (RequiresCompositingForAffectedByOuterViewportBoundsDelta(object))
+ reasons |= CompositingReason::kAffectedByOuterViewportBoundsDelta;
+
if (style.HasBackdropFilter())
reasons |= CompositingReason::kBackdropFilter;
@@ -201,26 +205,24 @@ CompositingReasonFinder::DirectReasonsForSVGChildPaintProperties(
reasons &= ~CompositingReason::kWillChangeOther;
if (style.HasBackdropFilter())
reasons |= CompositingReason::kBackdropFilter;
+ // Though SVG doesn't support 3D transforms, they are frequently used as a
+ // compositing trigger for historical reasons.
+ reasons |= CompositingReasonsFor3DTransform(object);
return reasons;
}
-CompositingReasons CompositingReasonFinder::CompositingReasonsFor3DTransform(
- const LayoutObject& layout_object) {
- // Note that we ask the layoutObject if it has a transform, because the
- // style may have transforms, but the layoutObject may be an inline that
- // doesn't support them.
- if (!layout_object.HasTransformRelatedProperty())
- return CompositingReason::kNone;
-
+CompositingReasons
+CompositingReasonFinder::PotentialCompositingReasonsFor3DTransform(
+ const ComputedStyle& style) {
// Don't composite "trivial" 3D transforms such as translateZ(0).
if (Platform::Current()->IsLowEndDevice()) {
- return layout_object.StyleRef().HasNonTrivial3DTransformOperation()
+ return style.HasNonTrivial3DTransformOperation()
? CompositingReason::k3DTransform
: CompositingReason::kNone;
}
- if (layout_object.StyleRef().Has3DTransformOperation()) {
- return layout_object.StyleRef().HasNonTrivial3DTransformOperation()
+ if (style.Has3DTransformOperation()) {
+ return style.HasNonTrivial3DTransformOperation()
? CompositingReason::k3DTransform
: CompositingReason::kTrivial3DTransform;
}
@@ -228,6 +230,16 @@ CompositingReasons CompositingReasonFinder::CompositingReasonsFor3DTransform(
return CompositingReason::kNone;
}
+CompositingReasons CompositingReasonFinder::CompositingReasonsFor3DTransform(
+ const LayoutObject& layout_object) {
+ // Note that we ask the layoutObject if it has a transform, because the
+ // style may have transforms, but the layoutObject may be an inline that
+ // doesn't support them.
+ if (!layout_object.HasTransformRelatedProperty())
+ return CompositingReason::kNone;
+ return PotentialCompositingReasonsFor3DTransform(layout_object.StyleRef());
+}
+
CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
const PaintLayer& layer) {
CompositingReasons direct_reasons = CompositingReason::kNone;
@@ -260,6 +272,9 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
if (RequiresCompositingForScrollDependentPosition(layer))
direct_reasons |= CompositingReason::kScrollDependentPosition;
+ if (RequiresCompositingForAffectedByOuterViewportBoundsDelta(layout_object))
+ direct_reasons |= CompositingReason::kAffectedByOuterViewportBoundsDelta;
+
// Video is special. It's the only PaintLayer type that can both have
// PaintLayer children and whose children can't use its backing to render
// into. These children (the controls) always need to be promoted into their
@@ -292,8 +307,13 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
static bool ObjectTypeSupportsCompositedTransformAnimation(
const LayoutObject& object) {
- if (object.IsSVGChild())
- return RuntimeEnabledFeatures::CompositeSVGEnabled();
+ if (object.IsSVGChild()) {
+ if (!RuntimeEnabledFeatures::CompositeSVGEnabled())
+ return false;
+ // Transforms are not supported on hidden containers, inlines, or text.
+ return !object.IsSVGHiddenContainer() && !object.IsLayoutInline() &&
+ !object.IsText();
+ }
// Transforms don't apply on non-replaced inline elements.
return object.IsBox();
}
@@ -356,25 +376,51 @@ bool CompositingReasonFinder::RequiresCompositingForRootScroller(
bool CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
const PaintLayer& layer) {
- const auto& layout_object = layer.GetLayoutObject();
- if (!layout_object.StyleRef().HasViewportConstrainedPosition() &&
- !layout_object.StyleRef().HasStickyConstrainedPosition())
- return false;
-
// Don't promote fixed position elements that are descendants of a non-view
// container, e.g. transformed elements. They will stay fixed wrt the
// container rather than the enclosing frame.
- EPosition position = layout_object.StyleRef().GetPosition();
- if (position == EPosition::kFixed) {
- return layer.FixedToViewport() &&
- layout_object.GetFrameView()->LayoutViewport()->ScrollsOverflow();
+ if (layer.FixedToViewport()) {
+ // We check for |HasOverflow| instead of |ScrollsOverflow| to ensure fixed
+ // position elements are composited under overflow: hidden, which can still
+ // have smooth scroll animations.
+ LocalFrameView* frame_view = layer.GetLayoutObject().GetFrameView();
+ return frame_view->LayoutViewport()->HasOverflow();
}
- DCHECK_EQ(position, EPosition::kSticky);
// Don't promote sticky position elements that cannot move with scrolls.
- if (!layer.SticksToScroller())
+ if (layer.SticksToScroller()) {
+ // We check for |HasOverflow| instead of |ScrollsOverflow| to ensure sticky
+ // position elements are composited under overflow: hidden, which can still
+ // have smooth scroll animations.
+ return layer.AncestorScrollContainerLayer()
+ ->GetScrollableArea()
+ ->HasOverflow();
+ }
+
+ return false;
+}
+
+bool CompositingReasonFinder::
+ RequiresCompositingForAffectedByOuterViewportBoundsDelta(
+ const LayoutObject& layout_object) {
+ if (!layout_object.IsBox())
+ return false;
+
+ if (layout_object.StyleRef().GetPosition() != EPosition::kFixed ||
+ !layout_object.StyleRef().IsFixedToBottom())
+ return false;
+
+ // Objects inside an iframe that's the root scroller should get the same
+ // "pushed by top controls" behavior as for the main frame.
+ auto& controller =
+ layout_object.GetFrame()->GetPage()->GlobalRootScrollerController();
+ if (!layout_object.GetFrame()->IsMainFrame() &&
+ layout_object.GetFrame()->GetDocument() !=
+ controller.GlobalRootScroller())
return false;
- return layer.AncestorScrollContainerLayer()->ScrollsOverflow();
+
+ // It's affected by viewport only if the container is the LayoutView.
+ return IsA<LayoutView>(layout_object.Container());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
index 14bd321bcb2..7640882046b 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
@@ -39,11 +39,19 @@ class CORE_EXPORT CompositingReasonFinder {
static CompositingReasons CompositingReasonsForAnimation(const LayoutObject&);
static CompositingReasons CompositingReasonsForWillChange(
const ComputedStyle&);
+ // Some LayoutObject types do not support transforms (see:
+ // |LayoutObject::HasTransformRelatedProperty|) so this can return reasons
+ // that the LayoutObject does not end up using.
+ static CompositingReasons PotentialCompositingReasonsFor3DTransform(
+ const ComputedStyle&);
static CompositingReasons CompositingReasonsFor3DTransform(
const LayoutObject&);
static bool RequiresCompositingForRootScroller(const PaintLayer&);
static bool RequiresCompositingForScrollDependentPosition(const PaintLayer&);
+
+ static bool RequiresCompositingForAffectedByOuterViewportBoundsDelta(
+ const LayoutObject&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
index ca9787a1ee5..1629912056d 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -102,9 +102,25 @@ TEST_F(CompositingReasonFinderTest, OnlyAnchoredStickyPositionPromoted) {
TEST_F(CompositingReasonFinderTest, OnlyScrollingStickyPositionPromoted) {
SetBodyInnerHTML(R"HTML(
- <style>.scroller {width: 400px; height: 400px; overflow: auto;
- will-change: transform;}
- .sticky { position: sticky; top: 0; width: 10px; height: 10px;}
+ <style>
+ .scroller {
+ width: 400px;
+ height: 400px;
+ overflow: auto;
+ will-change: transform;
+ }
+ .sticky {
+ position: sticky;
+ top: 0;
+ width: 10px;
+ height: 10px;
+ }
+ .overflow-hidden {
+ width: 400px;
+ height: 400px;
+ overflow: hidden;
+ will-change: transform;
+ }
</style>
<div class='scroller'>
<div id='sticky-scrolling' class='sticky'></div>
@@ -113,14 +129,49 @@ TEST_F(CompositingReasonFinderTest, OnlyScrollingStickyPositionPromoted) {
<div class='scroller'>
<div id='sticky-no-scrolling' class='sticky'></div>
</div>
+ <div class='overflow-hidden'>
+ <div id='overflow-hidden-scrolling' class='sticky'></div>
+ <div style='height: 2000px;'></div>
+ </div>
+ <div class='overflow-hidden'>
+ <div id='overflow-hidden-no-scrolling' class='sticky'></div>
+ </div>
)HTML");
- EXPECT_EQ(
- kPaintsIntoOwnBacking,
- GetPaintLayerByElementId("sticky-scrolling")->GetCompositingState());
- EXPECT_EQ(
- kNotComposited,
- GetPaintLayerByElementId("sticky-no-scrolling")->GetCompositingState());
+ auto& sticky_scrolling =
+ *To<LayoutBoxModelObject>(GetLayoutObjectByElementId("sticky-scrolling"));
+ EXPECT_TRUE(
+ CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
+ *sticky_scrolling.Layer()));
+
+ auto& sticky_no_scrolling = *To<LayoutBoxModelObject>(
+ GetLayoutObjectByElementId("sticky-no-scrolling"));
+ EXPECT_FALSE(
+ CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
+ *sticky_no_scrolling.Layer()));
+
+ auto& overflow_hidden_scrolling = *To<LayoutBoxModelObject>(
+ GetLayoutObjectByElementId("overflow-hidden-scrolling"));
+ EXPECT_TRUE(
+ CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
+ *overflow_hidden_scrolling.Layer()));
+
+ auto& overflow_hidden_no_scrolling = *To<LayoutBoxModelObject>(
+ GetLayoutObjectByElementId("overflow-hidden-no-scrolling"));
+ EXPECT_FALSE(
+ CompositingReasonFinder::RequiresCompositingForScrollDependentPosition(
+ *overflow_hidden_no_scrolling.Layer()));
+
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(kPaintsIntoOwnBacking,
+ sticky_scrolling.Layer()->GetCompositingState());
+ EXPECT_EQ(kNotComposited,
+ sticky_no_scrolling.Layer()->GetCompositingState());
+ EXPECT_EQ(kPaintsIntoOwnBacking,
+ overflow_hidden_scrolling.Layer()->GetCompositingState());
+ EXPECT_EQ(kNotComposited,
+ overflow_hidden_no_scrolling.Layer()->GetCompositingState());
+ }
}
void CompositingReasonFinderTest::CheckCompositingReasonsForAnimation(
@@ -196,9 +247,6 @@ TEST_F(CompositingReasonFinderTest, DontPromoteEmptyIframe) {
}
TEST_F(CompositingReasonFinderTest, PromoteCrossOriginIframe) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<iframe id=iframe></iframe>
@@ -365,4 +413,46 @@ TEST_F(CompositingReasonFinderTest, CompositedSVGText) {
CompositingReasonFinder::DirectReasonsForPaintProperties(*text));
}
+TEST_F(CompositingReasonFinderTest, NotSupportedTransformAnimationsOnSVG) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ * { animation: transformKeyframes 1s infinite; }
+ @keyframes transformKeyframes {
+ 0% { transform: rotate(-5deg); }
+ 100% { transform: rotate(5deg); }
+ }
+ </style>
+ <svg>
+ <defs id="defs" />
+ <text id="text">text content
+ <tspan id="tspan">tspan content</tspan>
+ </text>
+ </svg>
+ )HTML");
+
+ auto* defs = GetLayoutObjectByElementId("defs");
+ EXPECT_EQ(CompositingReason::kNone,
+ CompositingReasonFinder::DirectReasonsForPaintProperties(*defs));
+
+ auto* text = GetLayoutObjectByElementId("text");
+ EXPECT_EQ(CompositingReason::kActiveTransformAnimation,
+ CompositingReasonFinder::DirectReasonsForPaintProperties(*text));
+
+ auto* text_content = text->SlowFirstChild();
+ ASSERT_TRUE(text_content->IsText());
+ EXPECT_EQ(
+ CompositingReason::kNone,
+ CompositingReasonFinder::DirectReasonsForPaintProperties(*text_content));
+
+ auto* tspan = GetLayoutObjectByElementId("tspan");
+ EXPECT_EQ(CompositingReason::kNone,
+ CompositingReasonFinder::DirectReasonsForPaintProperties(*tspan));
+
+ auto* tspan_content = tspan->SlowFirstChild();
+ ASSERT_TRUE(tspan_content->IsText());
+ EXPECT_EQ(
+ CompositingReason::kNone,
+ CompositingReasonFinder::DirectReasonsForPaintProperties(*tspan_content));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index cb0486ae225..a9e25c318d6 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -352,23 +352,8 @@ void CompositingRequirementsUpdater::UpdateRecursive(
unclipped_descendants.push_back(layer);
}
- IntRect abs_bounds = use_clipped_bounding_rect
- ? layer->ClippedAbsoluteBoundingBox()
- : layer->UnclippedAbsoluteBoundingBox();
-
- if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
- PaintLayer* root_layer = layout_view_.Layer();
- // |abs_bounds| does not include root scroller offset. For the purposes
- // of overlap, this only matters for fixed-position objects, and their
- // relative position to other elements. Therefore, it's still correct to,
- // instead of adding scroll to all non-fixed elements, add a reverse scroll
- // to ones that are fixed.
- if (root_layer->GetScrollableArea() &&
- !layer->IsAffectedByScrollOf(root_layer)) {
- abs_bounds.Move(
- RoundedIntSize(root_layer->GetScrollableArea()->GetScrollOffset()));
- }
- }
+ IntRect abs_bounds = layer->ExpandedBoundingBoxForCompositingOverlapTest(
+ use_clipped_bounding_rect);
absolute_descendant_bounding_box = abs_bounds;
if (layer_can_be_composited && current_recursion_data.testing_overlap_ &&
@@ -393,7 +378,7 @@ void CompositingRequirementsUpdater::UpdateRecursive(
bool contains_composited_layer =
(layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
To<LayoutEmbeddedContent>(layer->GetLayoutObject())
- .ContentDocumentIsCompositing());
+ .ContentDocumentContainsGraphicsLayer());
bool will_be_composited_or_squashed =
can_be_composited && RequiresCompositingOrSquashing(reasons_to_composite);
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
index 241260bc464..4014ebfebd8 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
@@ -5,9 +5,12 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -222,4 +225,88 @@ TEST_F(CompositingRequirementsUpdaterTest,
GetPaintLayerByElementId("3d-descendant")->GetCompositingReasons());
}
+class CompositingRequirementsUpdaterSimTest : public SimTest {
+ protected:
+ void SetUp() override {
+ SimTest::SetUp();
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
+ }
+};
+
+TEST_F(CompositingRequirementsUpdaterSimTest,
+ StaleCompositingStateInThrottledFrame) {
+ SimRequest top_resource("https://example.com/top.html", "text/html");
+ SimRequest middle_resource("https://cross-origin.com/middle.html",
+ "text/html");
+ SimRequest bottom_resource("https://cross-origin.com/bottom.html",
+ "text/html");
+
+ LoadURL("https://example.com/top.html");
+ top_resource.Complete(R"HTML(
+ <div id='spacer'></div>
+ <iframe id='middle' src='https://cross-origin.com/middle.html'></iframe>
+ )HTML");
+ middle_resource.Complete(R"HTML(
+ <iframe id='bottom' src='bottom.html'></iframe>
+ )HTML");
+ bottom_resource.Complete(R"HTML(
+ <div id='composited' style='will-change:transform'>Hello, world!</div>
+ )HTML");
+
+ LocalFrame& middle_frame =
+ *To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
+ LocalFrame& bottom_frame = *To<LocalFrame>(middle_frame.Tree().FirstChild());
+ middle_frame.View()->BeginLifecycleUpdates();
+ bottom_frame.View()->BeginLifecycleUpdates();
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest());
+ LayoutEmbeddedContent* bottom_owner = bottom_frame.OwnerLayoutObject();
+ EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
+ EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
+
+ // Move iframe offscreen to throttle it. Compositing status shouldn't change.
+ Element* spacer = GetDocument().getElementById("spacer");
+ spacer->setAttribute(html_names::kStyleAttr, "height:2000px");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ ASSERT_TRUE(middle_frame.View()->ShouldThrottleRenderingForTest());
+ ASSERT_TRUE(bottom_frame.View()->ShouldThrottleRenderingForTest());
+ EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
+ EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
+
+ // Remove direct compositing reason from iframe content, but add
+ // position:relative so it still has a PaintLayer and won't force a
+ // compositing update.
+ Element* composited =
+ bottom_frame.GetDocument()->getElementById("composited");
+ composited->setAttribute(html_names::kStyleAttr, "position:relative");
+
+ // Force a lifecycle update up to pre-paint clean; compositing inputs will be
+ // updated, but not compositing assignments. This imitates what would happen
+ // if a new IntersectionObservation is created inside a throttled frame. This
+ // should not affect final compositing state.
+ GetDocument().View()->ForceUpdateViewportIntersections();
+ EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
+ EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
+
+ // Force a full, throttled lifecycle update. Compositing state in the bottom
+ // frame will remain stale; compositing state in the middle frame will be
+ // based on the stale state of the iframe.
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(
+ middle_frame.ContentLayoutObject()->Layer()->GetCompositingReasons() |
+ CompositingReason::kRoot);
+ EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
+ EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
+
+ // Move the iframe back on screen and run two lifecycle updates to unthrottle
+ // it and update compositing.
+ spacer->setAttribute(html_names::kStyleAttr, "");
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ ASSERT_FALSE(middle_frame.View()->ShouldThrottleRenderingForTest());
+ ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest());
+ GetDocument().View()->UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(bottom_owner->ContentDocumentContainsGraphicsLayer());
+ EXPECT_FALSE(bottom_owner->Layer()->HasCompositingDescendant());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 4568bbd0246..a2660f9f5e8 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -41,7 +41,7 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
void SetUp() override {
web_view_helper_ = std::make_unique<frame_test_helpers::WebViewHelper>();
- web_view_helper_->Initialize(nullptr, nullptr, &web_widget_client_,
+ web_view_helper_->Initialize(nullptr, nullptr,
&ConfigureCompositingWebView);
web_view_helper_->Resize(gfx::Size(200, 200));
@@ -76,7 +76,9 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
}
cc::LayerTreeHost* LayerTreeHost() {
- return web_widget_client_.layer_tree_host();
+ return web_view_helper_->LocalMainFrame()
+ ->FrameWidgetImpl()
+ ->LayerTreeHostForTesting();
}
Element* GetElementById(const AtomicString& id) {
@@ -84,6 +86,10 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
return frame->GetFrame()->GetDocument()->getElementById(id);
}
+ LayoutObject* GetLayoutObjectById(const AtomicString& id) {
+ return GetElementById(id)->GetLayoutObject();
+ }
+
void UpdateAllLifecyclePhases() {
WebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
DocumentUpdateReason::kTest);
@@ -103,7 +109,6 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
}
private:
- frame_test_helpers::TestWebWidgetClient web_widget_client_;
std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
};
@@ -259,7 +264,120 @@ TEST_P(CompositingTest, WillChangeTransformHintInSVG) {
UpdateAllLifecyclePhases();
auto* layer = CcLayerByDOMElementId("willChange");
auto* transform_node = GetTransformNode(layer);
- EXPECT_TRUE(transform_node->will_change_transform);
+ // For now will-change:transform triggers compositing for SVG, but we don't
+ // pass the flag to cc to ensure raster quality.
+ EXPECT_FALSE(transform_node->will_change_transform);
+}
+
+TEST_P(CompositingTest, Compositing3DTransformOnSVGModelObject) {
+ ScopedCompositeSVGForTest enable_feature(true);
+ InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+ <!doctype html>
+ <svg width="200" height="200">
+ <rect id="target" fill="blue" width="100" height="100"></rect>
+ </svg>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Adding a 3D transform should trigger compositing.
+ auto* target_element = GetElementById("target");
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate3d(0, 0, 1px)");
+ UpdateAllLifecyclePhases();
+ // |HasTransformRelatedProperty| is used in |CompositingReasonsFor3DTransform|
+ // and must be set correctly.
+ ASSERT_TRUE(GetLayoutObjectById("target")->HasTransformRelatedProperty());
+ EXPECT_TRUE(CcLayerByDOMElementId("target"));
+
+ // Removing a 3D transform removes the compositing trigger.
+ target_element->setAttribute(html_names::kStyleAttr, "transform: none");
+ UpdateAllLifecyclePhases();
+ // |HasTransformRelatedProperty| is used in |CompositingReasonsFor3DTransform|
+ // and must be set correctly.
+ ASSERT_FALSE(GetLayoutObjectById("target")->HasTransformRelatedProperty());
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Adding a 2D transform should not trigger compositing.
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate(1px, 0)");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Switching from a 2D to a 3D transform should trigger compositing.
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate3d(0, 0, 1px)");
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(CcLayerByDOMElementId("target"));
+}
+
+TEST_P(CompositingTest, Compositing3DTransformOnSVGBlock) {
+ ScopedCompositeSVGForTest enable_feature(true);
+ InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+ <!doctype html>
+ <svg width="200" height="200">
+ <text id="target" x="50" y="50">text</text>
+ </svg>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Adding a 3D transform should trigger compositing.
+ auto* target_element = GetElementById("target");
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate3d(0, 0, 1px)");
+ UpdateAllLifecyclePhases();
+ // |HasTransformRelatedProperty| is used in |CompositingReasonsFor3DTransform|
+ // and must be set correctly.
+ ASSERT_TRUE(GetLayoutObjectById("target")->HasTransformRelatedProperty());
+ EXPECT_TRUE(CcLayerByDOMElementId("target"));
+
+ // Removing a 3D transform removes the compositing trigger.
+ target_element->setAttribute(html_names::kStyleAttr, "transform: none");
+ UpdateAllLifecyclePhases();
+ // |HasTransformRelatedProperty| is used in |CompositingReasonsFor3DTransform|
+ // and must be set correctly.
+ ASSERT_FALSE(GetLayoutObjectById("target")->HasTransformRelatedProperty());
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Adding a 2D transform should not trigger compositing.
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate(1px, 0)");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(CcLayerByDOMElementId("target"));
+
+ // Switching from a 2D to a 3D transform should trigger compositing.
+ target_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate3d(0, 0, 1px)");
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(CcLayerByDOMElementId("target"));
+}
+
+// Inlines do not support the transform property and should not be composited
+// due to 3D transforms.
+TEST_P(CompositingTest, NotCompositing3DTransformOnSVGInline) {
+ ScopedCompositeSVGForTest enable_feature(true);
+ InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+ <!doctype html>
+ <svg width="200" height="200">
+ <text x="50" y="50">
+ text
+ <tspan id="inline">tspan</tspan>
+ </text>
+ </svg>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ EXPECT_FALSE(CcLayerByDOMElementId("inline"));
+
+ // Adding a 3D transform to an inline should not trigger compositing.
+ auto* inline_element = GetElementById("inline");
+ inline_element->setAttribute(html_names::kStyleAttr,
+ "transform: translate3d(0, 0, 1px)");
+ UpdateAllLifecyclePhases();
+ // |HasTransformRelatedProperty| is used in |CompositingReasonsFor3DTransform|
+ // and must be set correctly.
+ ASSERT_FALSE(GetLayoutObjectById("inline")->HasTransformRelatedProperty());
+ EXPECT_FALSE(CcLayerByDOMElementId("inline"));
}
TEST_P(CompositingTest, PaintPropertiesWhenCompositingSVG) {
@@ -441,6 +559,32 @@ TEST_P(CompositingTest, ContainPaintLayerBounds) {
EXPECT_EQ(gfx::Size(200, 100), layer->bounds());
}
+TEST_P(CompositingTest, SVGForeignObjectDirectlyCompositedContainer) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+ <!doctype html>
+ <div id="container" style="backface-visibility: hidden">
+ <svg>
+ <foreignObject id="foreign">
+ <div id="child" style="position: relative"></div>
+ </foreignObject>
+ </svg>
+ </body>
+ )HTML");
+ UpdateAllLifecyclePhases();
+
+ // PaintInvalidator should use the same directly_composited_container during
+ // PrePaint and should not fail DCHECK.
+ auto* container = GetLayoutObjectById("container");
+ EXPECT_FALSE(container->IsStackingContext());
+ EXPECT_EQ(container,
+ &GetLayoutObjectById("foreign")->DirectlyCompositableContainer());
+ EXPECT_EQ(container,
+ &GetLayoutObjectById("child")->DirectlyCompositableContainer());
+}
+
class CompositingSimTest : public PaintTestConfigurations, public SimTest {
public:
void InitializeWithHTML(const String& html) {
@@ -484,7 +628,7 @@ class CompositingSimTest : public PaintTestConfigurations, public SimTest {
}
cc::PropertyTrees* GetPropertyTrees() {
- return Compositor().layer_tree_host()->property_trees();
+ return Compositor().LayerTreeHost()->property_trees();
}
cc::TransformNode* GetTransformNode(const cc::Layer* layer) {
@@ -533,7 +677,7 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
auto* b_layer = CcLayerByDOMElementId("b");
// Initially, neither a nor b should have a layer that should push properties.
- cc::LayerTreeHost& host = *Compositor().layer_tree_host();
+ cc::LayerTreeHost& host = *Compositor().LayerTreeHost();
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(a_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(b_layer));
@@ -575,7 +719,7 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
auto* c_layer = CcLayerByDOMElementId("c");
// Initially, no layer should need to push properties.
- cc::LayerTreeHost& host = *Compositor().layer_tree_host();
+ cc::LayerTreeHost& host = *Compositor().LayerTreeHost();
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(a_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(b_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(c_layer));
@@ -613,7 +757,7 @@ TEST_P(CompositingSimTest,
Compositor().BeginFrame();
// Initially the host should not need to sync.
- cc::LayerTreeHost& layer_tree_host = *Compositor().layer_tree_host();
+ cc::LayerTreeHost& layer_tree_host = *Compositor().LayerTreeHost();
EXPECT_FALSE(layer_tree_host.needs_full_tree_sync());
int sequence_number = GetPropertyTrees()->sequence_number;
EXPECT_GT(sequence_number, 0);
@@ -1193,16 +1337,88 @@ TEST_P(CompositingSimTest, LayerClipPropertyChanged) {
EXPECT_FALSE(inner_element_layer->subtree_property_changed());
}
-TEST_P(CompositingSimTest, SafeOpaqueBackgroundColorGetsSet) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
+TEST_P(CompositingSimTest, SafeOpaqueBackgroundColor) {
+ InitializeWithHTML(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body { background: yellow; }
+ div {
+ position: absolute;
+ z-index: 1;
+ width: 20px;
+ height: 20px;
+ will-change: transform; /* Composited */
+ }
+ #opaque-color {
+ background: blue;
+ }
+ #opaque-image, #opaque-image-translucent-color {
+ background: linear-gradient(blue, green);
+ }
+ #partly-opaque div {
+ width: 15px;
+ height: 15px;
+ background: blue;
+ will-change: initial;
+ }
+ #translucent, #opaque-image-translucent-color div {
+ background: rgba(0, 255, 255, 0.5);
+ will-change: initial;
+ }
+ </style>
+ <div id="opaque-color"></div>
+ <div id="opaque-image"></div>
+ <div id="opaque-image-translucent-color">
+ <div></div>
+ </div>
+ <div id="partly-opaque">
+ <div></div>
+ </div>
+ <div id="translucent"></div>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ auto* opaque_color = CcLayerByDOMElementId("opaque-color");
+ EXPECT_TRUE(opaque_color->contents_opaque());
+ EXPECT_EQ(SK_ColorBLUE, opaque_color->background_color());
+ EXPECT_EQ(SK_ColorBLUE, opaque_color->SafeOpaqueBackgroundColor());
+
+ auto* opaque_image = CcLayerByDOMElementId("opaque-image");
+ EXPECT_TRUE(opaque_image->contents_opaque());
+ EXPECT_EQ(SK_ColorTRANSPARENT, opaque_image->background_color());
+ // Fallback to use the viewport background.
+ EXPECT_EQ(SK_ColorYELLOW, opaque_image->SafeOpaqueBackgroundColor());
+
+ const SkColor kTranslucentCyan = SkColorSetARGB(128, 0, 255, 255);
+ auto* opaque_image_translucent_color =
+ CcLayerByDOMElementId("opaque-image-translucent-color");
+ EXPECT_TRUE(opaque_image_translucent_color->contents_opaque());
+ EXPECT_EQ(kTranslucentCyan,
+ opaque_image_translucent_color->background_color());
+ // Use background_color() with the alpha channel forced to be opaque.
+ EXPECT_EQ(SK_ColorCYAN,
+ opaque_image_translucent_color->SafeOpaqueBackgroundColor());
+
+ auto* partly_opaque = CcLayerByDOMElementId("partly-opaque");
+ EXPECT_FALSE(partly_opaque->contents_opaque());
+ EXPECT_EQ(SK_ColorBLUE, partly_opaque->background_color());
+ // SafeOpaqueBackgroundColor() returns SK_ColorTRANSPARENT when
+ // background_color() is opaque and contents_opaque() is false.
+ EXPECT_EQ(SK_ColorTRANSPARENT, partly_opaque->SafeOpaqueBackgroundColor());
+
+ auto* translucent = CcLayerByDOMElementId("translucent");
+ EXPECT_FALSE(translucent->contents_opaque());
+ EXPECT_EQ(kTranslucentCyan, translucent->background_color());
+ // SafeOpaqueBackgroundColor() returns background_color() if it's not opaque
+ // and contents_opaque() is false.
+ EXPECT_EQ(kTranslucentCyan, translucent->SafeOpaqueBackgroundColor());
+}
+TEST_P(CompositingSimTest, SquashingLayerSafeOpaqueBackgroundColor) {
InitializeWithHTML(R"HTML(
- <!DOCTYPE html>
- <style>
+ <!DOCTYPE html>
+ <style>
div {
position: absolute;
z-index: 1;
@@ -1223,52 +1439,32 @@ TEST_P(CompositingSimTest, SafeOpaqueBackgroundColorGetsSet) {
#bottomright {
top: 24px;
left: 24px;
+ width: 100px;
+ height: 100px;
background: cyan;
}
- </style>
- <div id="behind"></div>
- <div id="topleft"></div>
- <div id="bottomright"></div>
+ </style>
+ <div id="behind"></div>
+ <div id="topleft"></div>
+ <div id="bottomright"></div>
)HTML");
Compositor().BeginFrame();
- auto* behind_element = GetElementById("behind");
- auto* behind_layer = CcLayerByDOMElementId("behind");
- EXPECT_EQ(behind_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- behind_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
- EXPECT_EQ(behind_layer->SafeOpaqueBackgroundColor(), SK_ColorBLUE);
-
- auto* grouped_mapping =
- GetElementById("topleft")->GetLayoutBox()->Layer()->GroupedMapping();
- ASSERT_TRUE(grouped_mapping);
- ASSERT_TRUE(grouped_mapping->NonScrollingSquashingLayer());
- auto& squashing_layer =
- grouped_mapping->NonScrollingSquashingLayer()->CcLayer();
+ auto* squashing_layer = CcLayerByDOMElementId("topleft");
+ ASSERT_TRUE(squashing_layer);
+ EXPECT_EQ(gfx::Size(124, 124), squashing_layer->bounds());
// Top left and bottom right are squashed.
// This squashed layer should not be opaque, as it is squashing two squares
// with some gaps between them.
- EXPECT_FALSE(squashing_layer.contents_opaque());
- // This shouldn't DCHECK.
- squashing_layer.SafeOpaqueBackgroundColor();
- // Because contents_opaque is false, the SafeOpaqueBackgroundColor() getter
- // will return SK_ColorTRANSPARENT. So we need to grab the actual color,
- // to make sure it's right.
- SkColor squashed_bg_color =
- squashing_layer.ActualSafeOpaqueBackgroundColorForTesting();
- // The squashed layer should have a non-transparent safe opaque background
- // color, that isn't blue. Exactly which color it is depends on heuristics,
- // but it should be one of the two colors of the elements that created it.
- EXPECT_NE(squashed_bg_color, SK_ColorBLUE);
- EXPECT_EQ(SkColorGetA(squashed_bg_color), SK_AlphaOPAQUE);
- // #behind is blue, which is SK_ColorBLUE
- // #topleft is lime, which is SK_ColorGREEN
- // #bottomright is cyan, which is SK_ColorCYAN
- EXPECT_TRUE((squashed_bg_color == SK_ColorGREEN) ||
- (squashed_bg_color == SK_ColorCYAN));
+ EXPECT_FALSE(squashing_layer->contents_opaque());
+ // The background color of #bottomright is used as the background color
+ // because it covers the most significant area of the squashing layer.
+ EXPECT_EQ(squashing_layer->background_color(), SK_ColorCYAN);
+ // SafeOpaqueBackgroundColor() returns SK_ColorTRANSPARENT when
+ // background_color() is opaque and contents_opaque() is false.
+ EXPECT_EQ(squashing_layer->SafeOpaqueBackgroundColor(), SK_ColorTRANSPARENT);
}
// Test that a pleasant checkerboard color is used in the presence of blending.
@@ -1283,6 +1479,7 @@ TEST_P(CompositingSimTest, RootScrollingContentsSafeOpaqueBackgroundColor) {
auto* scrolling_contents = ScrollingContentsCcLayerByScrollElementId(
RootCcLayer(),
MainFrame().GetFrameView()->LayoutViewport()->GetScrollElementId());
+ EXPECT_EQ(scrolling_contents->background_color(), SK_ColorWHITE);
EXPECT_EQ(scrolling_contents->SafeOpaqueBackgroundColor(), SK_ColorWHITE);
}
@@ -1361,9 +1558,6 @@ TEST_P(CompositingSimTest, NoRenderSurfaceWithAxisAlignedTransformAnimation) {
}
TEST_P(CompositingSimTest, PromoteCrossOriginIframe) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
InitializeWithHTML("<!DOCTYPE html><iframe id=iframe sandbox></iframe>");
Compositor().BeginFrame();
Document* iframe_doc =
@@ -1380,10 +1574,6 @@ TEST_P(CompositingSimTest, PromoteCrossOriginIframe) {
// cross origin. This test ensures the iframe is promoted due to being cross
// origin after the iframe loads.
TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterLoading) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
SimRequest main_resource("https://origin-a.com/a.html", "text/html");
SimRequest frame_resource("https://origin-b.com/b.html", "text/html");
@@ -1407,10 +1597,6 @@ TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterLoading) {
// sets up nested frames with domains A -> B -> A. Both the child and grandchild
// frames should be composited because they are cross-origin to their parent.
TEST_P(CompositingSimTest, PromoteCrossOriginToParent) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
SimRequest main_resource("https://origin-a.com/a.html", "text/html");
SimRequest child_resource("https://origin-b.com/b.html", "text/html");
SimRequest grandchild_resource("https://origin-a.com/c.html", "text/html");
@@ -1444,10 +1630,6 @@ TEST_P(CompositingSimTest, PromoteCrossOriginToParent) {
// Initially the iframe is cross-origin and should be composited. After changing
// to same-origin, the frame should no longer be composited.
TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterDomainChange) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
SimRequest main_resource("https://origin-a.com/a.html", "text/html");
SimRequest frame_resource("https://sub.origin-a.com/b.html", "text/html");
@@ -1490,10 +1672,6 @@ TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterDomainChange) {
// child frame to A (same-origin), both child and grandchild frames should no
// longer be composited.
TEST_P(CompositingSimTest, PromoteCrossOriginToParentIframeAfterDomainChange) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
SimRequest main_resource("https://origin-a.com/a.html", "text/html");
SimRequest child_resource("https://sub.origin-a.com/b.html", "text/html");
SimRequest grandchild_resource("https://origin-a.com/c.html", "text/html");
@@ -1589,13 +1767,13 @@ TEST_P(CompositingSimTest, ImplSideScrollSkipsCommit) {
auto* scrollable_area = scroller->GetLayoutBox()->GetScrollableArea();
auto element_id = scrollable_area->GetScrollElementId();
- EXPECT_FALSE(Compositor().layer_tree_host()->CommitRequested());
+ EXPECT_FALSE(Compositor().LayerTreeHost()->CommitRequested());
// Simulate the scroll update with scroll delta from impl-side.
cc::CompositorCommitData commit_data;
commit_data.scrolls.emplace_back(cc::CompositorCommitData::ScrollUpdateInfo(
element_id, gfx::ScrollOffset(0, 10), base::nullopt));
- Compositor().layer_tree_host()->ApplyCompositorChanges(&commit_data);
+ Compositor().LayerTreeHost()->ApplyCompositorChanges(&commit_data);
EXPECT_EQ(FloatPoint(0, 10), scrollable_area->ScrollPosition());
EXPECT_EQ(gfx::ScrollOffset(0, 10),
GetPropertyTrees()->scroll_tree.current_scroll_offset(element_id));
@@ -1607,17 +1785,13 @@ TEST_P(CompositingSimTest, ImplSideScrollSkipsCommit) {
// A main frame is needed to call UpdateLayers which updates property trees,
// re-calculating cached to/from-screen transforms.
EXPECT_TRUE(
- Compositor().layer_tree_host()->RequestedMainFramePendingForTesting());
+ Compositor().LayerTreeHost()->RequestedMainFramePendingForTesting());
// A full commit is not needed.
- EXPECT_FALSE(Compositor().layer_tree_host()->CommitRequested());
+ EXPECT_FALSE(Compositor().LayerTreeHost()->CommitRequested());
}
TEST_P(CompositingSimTest, FrameAttribution) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
InitializeWithHTML(R"HTML(
<div id='child' style='will-change: transform;'>test</div>
<iframe id='iframe' sandbox></iframe>
@@ -1668,10 +1842,6 @@ TEST_P(CompositingSimTest, FrameAttribution) {
}
TEST_P(CompositingSimTest, VisibleFrameRootLayers) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatureState(
- blink::features::kCompositeCrossOriginIframes, true);
-
SimRequest main_resource("https://origin-a.com/a.html", "text/html");
SimRequest frame_resource("https://origin-b.com/b.html", "text/html");
@@ -1719,4 +1889,30 @@ TEST_P(CompositingSimTest, VisibleFrameRootLayers) {
EXPECT_FALSE(iframe_transform_node->visible_frame_element_id);
}
+TEST_P(CompositingSimTest, DecompositedTransformWithChange) {
+ InitializeWithHTML(R"HTML(
+ <style>
+ svg { overflow: hidden; }
+ .initial { transform: rotate3d(0,0,1,10deg); }
+ .changed { transform: rotate3d(0,0,1,0deg); }
+ </style>
+ <div style='will-change: transform;'>
+ <svg id='svg' xmlns='http://www.w3.org/2000/svg' class='initial'>
+ <line x1='50%' x2='50%' y1='0' y2='100%' stroke='blue'/>
+ <line y1='50%' y2='50%' x1='0' x2='100%' stroke='blue'/>
+ </svg>
+ </div>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ auto* svg_element_layer = CcLayerByDOMElementId("svg");
+ EXPECT_FALSE(svg_element_layer->subtree_property_changed());
+
+ auto* svg_element = GetElementById("svg");
+ svg_element->setAttribute(html_names::kClassAttr, "changed");
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(svg_element_layer->subtree_property_changed());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
index 113ef562773..b6ceee739f9 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
@@ -130,6 +130,8 @@ void GraphicsLayerTreeBuilder::RebuildRecursive(
PaintLayerCompositor* inner_compositor =
PaintLayerCompositor::FrameContentsCompositor(*embedded);
if (inner_compositor) {
+ // Disabler required because inner frame might be throttled.
+ DisableCompositingQueryAsserts disabler;
if (GraphicsLayer* inner_root_graphics_layer =
inner_compositor->RootGraphicsLayer()) {
// If inner_root_graphics_layer is non-null, then either the inner frame
@@ -141,6 +143,8 @@ void GraphicsLayerTreeBuilder::RebuildRecursive(
->ShouldThrottleRendering() ||
inner_compositor->InCompositingMode());
layer_vector_for_children->push_back(inner_root_graphics_layer);
+ CHECK(layer.Compositor()->RootLayer()->GetCompositingReasons() &
+ CompositingReason::kRoot);
}
inner_compositor->ClearRootLayerAttachmentDirty();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index edb39bf6430..88eb78f9e32 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -196,8 +196,21 @@ void PaintLayerCompositor::UpdateAssignmentsIfNeededRecursiveInternal(
if (target_state == DocumentLifecycle::kCompositingInputsClean)
return;
- if (layout_view_->GetFrameView()->ShouldThrottleRendering())
+ if (layout_view_->GetFrameView()->ShouldThrottleRendering()) {
+ if (auto* owner = layout_view_->GetFrame()->OwnerLayoutObject()) {
+ auto* parent_compositor = owner->View()->Compositor();
+ DCHECK(parent_compositor);
+ DisableCompositingQueryAsserts query_assert_disabler;
+ // TODO(szager): It's not clear how this can happen. Even if the child
+ // frame is throttled, if the child compositor has a root graphics layer,
+ // then the parent compositor should be in compositing mode.
+ DCHECK(parent_compositor->StaleInCompositingMode() ||
+ !RootGraphicsLayer());
+ if (!parent_compositor->StaleInCompositingMode() && RootGraphicsLayer())
+ root_layer_attachment_dirty_ = true;
+ }
return;
+ }
if (DisplayLockUtilities::PrePaintBlockedInParentFrame(layout_view_))
return;
@@ -221,6 +234,12 @@ void PaintLayerCompositor::UpdateAssignmentsIfNeededRecursiveInternal(
target_state, compositing_reasons_stats);
if (child_compositor->root_layer_attachment_dirty_)
SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
+#if DCHECK_IS_ON()
+ // Even if the child frame is throttled, this should be consistent.
+ DisableCompositingQueryAsserts query_assert_disabler;
+ DCHECK_EQ(child_compositor->InCompositingMode(),
+ (bool)child_compositor->RootGraphicsLayer());
+#endif
}
}
@@ -308,19 +327,13 @@ void PaintLayerCompositor::UpdateAssignmentsIfNeeded(
CompositingLayerAssigner layer_assigner(this);
layer_assigner.Assign(update_root, layers_needing_paint_invalidation);
+ // TODO(szager): Remove this after diagnosing crash.
+ CHECK_EQ(compositing_, (bool)RootGraphicsLayer());
if (layer_assigner.LayersChanged())
update_type = std::max(update_type, kCompositingUpdateRebuildTree);
}
- GraphicsLayer* current_parent = nullptr;
- // Save off our current parent. We need this in subframes, because our
- // parent attached us to itself via AttachFrameContentLayersToIframeLayer().
- if (!IsMainFrame() && update_root->GetCompositedLayerMapping()) {
- current_parent =
- update_root->GetCompositedLayerMapping()->MainGraphicsLayer()->Parent();
- }
-
#if DCHECK_IS_ON()
if (update_root->GetCompositingState() != kPaintsIntoOwnBacking) {
AssertWholeTreeNotComposited(*update_root);
diff --git a/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc b/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
index 0a0c8d8bc89..d9c097b25f3 100644
--- a/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
namespace blink {
@@ -18,24 +17,25 @@ base::Optional<IntRect> CSSMaskPainter::MaskBoundingBox(
if (!object.IsBoxModelObject() && !object.IsSVGChild())
return base::nullopt;
+ const ComputedStyle& style = object.StyleRef();
if (object.IsSVG()) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(object);
- LayoutSVGResourceMasker* masker = resources ? resources->Masker() : nullptr;
- if (masker) {
- const FloatRect reference_box =
- SVGResources::ReferenceBoxForEffects(object);
- const float reference_box_zoom =
- object.IsSVGForeignObject() ? object.StyleRef().EffectiveZoom() : 1;
- return EnclosingIntRect(
- masker->ResourceBoundingBox(reference_box, reference_box_zoom));
+ if (SVGResourceClient* client = SVGResources::GetClient(object)) {
+ auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, style.MaskerResource());
+ if (masker) {
+ const FloatRect reference_box =
+ SVGResources::ReferenceBoxForEffects(object);
+ const float reference_box_zoom =
+ object.IsSVGForeignObject() ? object.StyleRef().EffectiveZoom() : 1;
+ return EnclosingIntRect(
+ masker->ResourceBoundingBox(reference_box, reference_box_zoom));
+ }
}
}
if (object.IsSVGChild() && !object.IsSVGForeignObject())
return base::nullopt;
- const ComputedStyle& style = object.StyleRef();
if (!style.HasMask())
return base::nullopt;
@@ -61,13 +61,14 @@ base::Optional<IntRect> CSSMaskPainter::MaskBoundingBox(
ColorFilter CSSMaskPainter::MaskColorFilter(const LayoutObject& object) {
if (!object.IsSVGChild())
return kColorFilterNone;
-
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(object);
- LayoutSVGResourceMasker* masker = resources ? resources->Masker() : nullptr;
+ SVGResourceClient* client = SVGResources::GetClient(object);
+ if (!client)
+ return kColorFilterNone;
+ auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, object.StyleRef().MaskerResource());
if (!masker)
return kColorFilterNone;
- return masker->StyleRef().SvgStyle().MaskType() == MT_LUMINANCE
+ return masker->StyleRef().MaskType() == EMaskType::kLuminance
? kColorFilterLuminanceToAlpha
: kColorFilterNone;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.cc b/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.cc
new file mode 100644
index 00000000000..eba7a4ee030
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.cc
@@ -0,0 +1,287 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
+
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+
+namespace blink {
+
+namespace {
+
+void SetLayerNeedsRepaintOnCullRectChange(PaintLayer& layer) {
+ if (layer.PreviousPaintResult() == kMayBeClippedByCullRect ||
+ RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) {
+ layer.SetNeedsRepaint();
+ }
+}
+
+void SetFragmentCullRect(PaintLayer& layer,
+ FragmentData& fragment,
+ const CullRect& cull_rect) {
+ if (cull_rect == fragment.GetCullRect())
+ return;
+
+ fragment.SetCullRect(cull_rect);
+ SetLayerNeedsRepaintOnCullRectChange(layer);
+}
+
+// Returns true if the contents cull rect changed.
+bool SetFragmentContentsCullRect(PaintLayer& layer,
+ FragmentData& fragment,
+ const CullRect& contents_cull_rect) {
+ if (contents_cull_rect == fragment.GetContentsCullRect())
+ return false;
+
+ fragment.SetContentsCullRect(contents_cull_rect);
+ SetLayerNeedsRepaintOnCullRectChange(layer);
+ return true;
+}
+
+bool ShouldProactivelyUpdateCullRect(const PaintLayer& layer) {
+ // If we will repaint anyway, proactively refresh cull rect. A sliding
+ // window (aka hysteresis, see: CullRect::ChangedEnough()) is used to
+ // avoid frequent cull rect updates because they force a repaint (see:
+ // |CullRectUpdater::SetFragmentCullRects|). Proactively updating the cull
+ // rect resets the sliding window which will minimize the need to update
+ // the cull rect again.
+ return layer.SelfOrDescendantNeedsRepaint();
+}
+
+} // anonymous namespace
+
+CullRectUpdater::CullRectUpdater(PaintLayer& root_layer)
+ : root_layer_(root_layer),
+ root_state_(root_layer.GetLayoutObject()
+ .FirstFragment()
+ .LocalBorderBoxProperties()
+ .Unalias()) {
+ DCHECK(root_layer.IsRootLayer());
+}
+
+void CullRectUpdater::UpdateInternal(const CullRect& input_cull_rect) {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ DCHECK(root_layer_.IsRootLayer());
+ if (root_layer_.GetLayoutObject().GetFrameView()->ShouldThrottleRendering())
+ return;
+
+ auto& fragment =
+ root_layer_.GetLayoutObject().GetMutableForPainting().FirstFragment();
+ SetFragmentCullRect(root_layer_, fragment, input_cull_rect);
+ bool force_update_children = SetFragmentContentsCullRect(
+ root_layer_, fragment,
+ ComputeFragmentContentsCullRect(root_layer_, fragment, input_cull_rect));
+ UpdateForDescendants(root_layer_, force_update_children);
+}
+
+void CullRectUpdater::UpdateRecursively(PaintLayer& layer,
+ const PaintLayer& parent_painting_layer,
+ bool force_update_self) {
+ bool should_proactively_update = ShouldProactivelyUpdateCullRect(layer);
+ bool force_update_children = should_proactively_update;
+
+ if (force_update_self || should_proactively_update ||
+ layer.NeedsCullRectUpdate())
+ force_update_children |= UpdateForSelf(layer, parent_painting_layer);
+
+ if (force_update_children || should_proactively_update ||
+ layer.DescendantNeedsCullRectUpdate())
+ UpdateForDescendants(layer, force_update_children);
+
+ layer.ClearNeedsCullRectUpdate();
+}
+
+void CullRectUpdater::UpdateForDescendants(PaintLayer& layer,
+ bool force_update_children) {
+ const auto& object = layer.GetLayoutObject();
+
+ // DisplayLockContext will force cull rect update of the subtree on unlock.
+ if (object.ChildPaintBlockedByDisplayLock())
+ return;
+
+ if (auto* embedded_content = DynamicTo<LayoutEmbeddedContent>(object)) {
+ if (auto* embedded_view = embedded_content->GetEmbeddedContentView()) {
+ if (auto* embedded_frame_view =
+ DynamicTo<LocalFrameView>(embedded_view)) {
+ PaintLayer* subframe_root_layer = nullptr;
+ if (auto* sub_layout_view = embedded_frame_view->GetLayoutView())
+ subframe_root_layer = sub_layout_view->Layer();
+ if (embedded_frame_view->ShouldThrottleRendering()) {
+ if (force_update_children && subframe_root_layer)
+ subframe_root_layer->SetNeedsCullRectUpdate();
+ } else {
+ DCHECK(subframe_root_layer);
+ UpdateRecursively(*subframe_root_layer, layer, force_update_children);
+ }
+ }
+ }
+ }
+
+ // Update non-stacked direct children first. In the following case:
+ // <div id="layer" style="stacking-context">
+ // <div id="child" style="overflow: hidden; ...">
+ // <div id="stacked-child" style="position: relative"></div>
+ // </div>
+ // </div>
+ // If |child|'s contents cull rect changes, we need to update |stack-child|'s
+ // cull rect because it's clipped by |child|. The is done in the following
+ // order:
+ // UpdateForDescendants(|layer|)
+ // UpdateRecursively(|child|) (in the following loop)
+ // |stacked-child|->SetNeedsCullRectUpdate()
+ // UpdateRecursively(stacked-child) (in the next loop)
+ // Note that this iterates direct children (including non-stacked, and
+ // stacked children which may not be paint-order children of |layer|, e.g.
+ // |stacked-child| is not a paint-order child of |child|), which is
+ // different from PaintLayerPaintOrderIterator(kAllChildren) which iterates
+ // children in paint order.
+ for (auto* child = layer.FirstChild(); child; child = child->NextSibling()) {
+ if (child->GetLayoutObject().IsStacked()) {
+ // In the above example, during UpdateForDescendants(child), this
+ // forces cull rect update of |stacked-child| which will be updated in
+ // the next loop during UpdateForDescendants(layer).
+ if (force_update_children)
+ child->SetNeedsCullRectUpdate();
+ continue;
+ }
+ UpdateRecursively(*child, layer, force_update_children);
+ }
+
+ // Then stacked children (which may not be direct children in PaintLayer
+ // hierarchy) in paint order.
+ PaintLayerPaintOrderIterator iterator(layer, kStackedChildren);
+ while (PaintLayer* child = iterator.Next())
+ UpdateRecursively(*child, layer, force_update_children);
+}
+
+bool CullRectUpdater::UpdateForSelf(PaintLayer& layer,
+ const PaintLayer& parent_painting_layer) {
+ const auto& first_parent_fragment =
+ parent_painting_layer.GetLayoutObject().FirstFragment();
+ auto& first_fragment =
+ layer.GetLayoutObject().GetMutableForPainting().FirstFragment();
+ // If both |this| and |root_layer| are fragmented and are inside the same
+ // pagination container, then try to match fragments from |root_layer| to
+ // |this|, so that any fragment clip for |root_layer|'s fragment matches
+ // |this|'s. Note we check both ShouldFragmentCompositedBounds() and next
+ // fragment here because the former may return false even if |this| is
+ // fragmented, e.g. for fixed-position objects in paged media, and the next
+ // fragment can be null even if the first fragment is actually in a fragmented
+ // context when the current layer appears in only one of the multiple
+ // fragments of the pagination container.
+ bool is_fragmented =
+ layer.ShouldFragmentCompositedBounds() || first_fragment.NextFragment();
+ bool should_match_fragments =
+ is_fragmented && parent_painting_layer.EnclosingPaginationLayer() ==
+ layer.EnclosingPaginationLayer();
+ bool force_update_children = false;
+
+ for (auto* fragment = &first_fragment; fragment;
+ fragment = fragment->NextFragment()) {
+ const FragmentData* parent_fragment = nullptr;
+ if (should_match_fragments) {
+ for (parent_fragment = &first_parent_fragment; parent_fragment;
+ parent_fragment = parent_fragment->NextFragment()) {
+ if (parent_fragment->LogicalTopInFlowThread() ==
+ fragment->LogicalTopInFlowThread())
+ break;
+ }
+ } else {
+ parent_fragment = &first_parent_fragment;
+ }
+
+ CullRect cull_rect;
+ CullRect contents_cull_rect;
+ if (!parent_fragment || PaintLayerPainter(layer).ShouldUseInfiniteCullRect(
+ kGlobalPaintNormalPhase)) {
+ cull_rect = CullRect::Infinite();
+ contents_cull_rect = CullRect::Infinite();
+ } else {
+ cull_rect = ComputeFragmentCullRect(layer, *fragment, *parent_fragment);
+ contents_cull_rect =
+ ComputeFragmentContentsCullRect(layer, *fragment, cull_rect);
+ }
+
+ SetFragmentCullRect(layer, *fragment, cull_rect);
+ force_update_children |=
+ SetFragmentContentsCullRect(layer, *fragment, contents_cull_rect);
+ }
+
+ return force_update_children;
+}
+
+CullRect CullRectUpdater::ComputeFragmentCullRect(
+ PaintLayer& layer,
+ const FragmentData& fragment,
+ const FragmentData& parent_fragment) {
+ CullRect cull_rect = parent_fragment.GetContentsCullRect();
+ auto parent_state = parent_fragment.ContentsProperties().Unalias();
+ auto local_state = fragment.LocalBorderBoxProperties().Unalias();
+ if (parent_state != local_state) {
+ base::Optional<CullRect> old_cull_rect;
+ // Not using |old_cull_rect| will force the cull rect to be updated
+ // (skipping |ChangedEnough|) in |ApplyPaintProperties|.
+ if (!ShouldProactivelyUpdateCullRect(layer))
+ old_cull_rect = fragment.GetCullRect();
+ cull_rect.ApplyPaintProperties(root_state_, parent_state, local_state,
+ old_cull_rect);
+ }
+ return cull_rect;
+}
+
+CullRect CullRectUpdater::ComputeFragmentContentsCullRect(
+ PaintLayer& layer,
+ const FragmentData& fragment,
+ const CullRect& cull_rect) {
+ auto local_state = fragment.LocalBorderBoxProperties().Unalias();
+ CullRect contents_cull_rect = cull_rect;
+ auto contents_state = fragment.ContentsProperties().Unalias();
+ if (contents_state != local_state) {
+ base::Optional<CullRect> old_contents_cull_rect;
+ // Not using |old_cull_rect| will force the cull rect to be updated
+ // (skipping |CullRect::ChangedEnough|) in |ApplyPaintProperties|.
+ if (!ShouldProactivelyUpdateCullRect(layer))
+ old_contents_cull_rect = fragment.GetContentsCullRect();
+ contents_cull_rect.ApplyPaintProperties(
+ root_state_, local_state, contents_state, old_contents_cull_rect);
+ }
+ return contents_cull_rect;
+}
+
+OverriddenCullRectScope::OverriddenCullRectScope(LocalFrameView& frame_view,
+ const CullRect& cull_rect)
+ : frame_view_(frame_view) {
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
+ PaintLayer* root_layer = frame_view_.GetLayoutView()->Layer();
+ DCHECK(root_layer);
+
+ // The cull rects calculated during PrePaint are good.
+ if (frame_view.GetFrame().IsLocalRoot() &&
+ !root_layer->NeedsCullRectUpdate() &&
+ cull_rect ==
+ root_layer->GetLayoutObject().FirstFragment().GetCullRect()) {
+ DCHECK(!root_layer->DescendantNeedsCullRectUpdate());
+ return;
+ }
+
+ updated_ = true;
+ root_layer->SetNeedsCullRectUpdate();
+ CullRectUpdater(*root_layer).UpdateInternal(cull_rect);
+}
+
+OverriddenCullRectScope::~OverriddenCullRectScope() {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled() && updated_)
+ frame_view_.GetLayoutView()->Layer()->SetNeedsCullRectUpdate();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.h b/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.h
new file mode 100644
index 00000000000..bef51d2daa3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/cull_rect_updater.h
@@ -0,0 +1,75 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_CULL_RECT_UPDATER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_CULL_RECT_UPDATER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class FragmentData;
+class PaintLayer;
+class LocalFrameView;
+
+// This class is used for updating the cull rects of PaintLayer fragments (see:
+// |FragmentData::cull_rect_| and |FragmentData::contents_cull_rect_|.
+// Cull rects are used as an optimization to limit painting to areas "near" the
+// viewport. This update should happen during the PrePaint lifecycle stage.
+//
+// Dirty bits (see: |PaintLayer::NeedsCullRectUpdate()| and
+// PaintLayer::DescendantNeedsCullRectUpdate()|) are used to optimize this
+// update, and are cleared at the end.
+class CORE_EXPORT CullRectUpdater {
+ STACK_ALLOCATED();
+
+ public:
+ explicit CullRectUpdater(PaintLayer& root_layer);
+
+ void Update() { UpdateInternal(CullRect::Infinite()); }
+
+ private:
+ friend class OverriddenCullRectScope;
+
+ void UpdateInternal(const CullRect& input_cull_rect);
+ void UpdateRecursively(PaintLayer&,
+ const PaintLayer& parent_painting_layer,
+ bool force_update_self);
+ // Returns true if the contents cull rect changed which requires forced update
+ // for children.
+ bool UpdateForSelf(PaintLayer&, const PaintLayer& parent_painting_layer);
+ void UpdateForDescendants(PaintLayer&, bool force_update_children);
+ CullRect ComputeFragmentCullRect(PaintLayer&,
+ const FragmentData& fragment,
+ const FragmentData& parent_fragment);
+ CullRect ComputeFragmentContentsCullRect(PaintLayer&,
+ const FragmentData& fragment,
+ const CullRect& cull_rect);
+
+ PaintLayer& root_layer_;
+ PropertyTreeState root_state_;
+};
+
+// Used when painting with a custom top-level cull rect, e.g. when printing a
+// page. It temporarily overrides the cull rect on the PaintLayer of the
+// LocalFrameView and marks the PaintLayer as needing to recalculate the cull
+// rect when leaving this scope.
+class OverriddenCullRectScope {
+ STACK_ALLOCATED();
+
+ public:
+ OverriddenCullRectScope(LocalFrameView&, const CullRect&);
+ ~OverriddenCullRectScope();
+
+ private:
+ LocalFrameView& frame_view_;
+ bool updated_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_CULL_RECT_UPDATER_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
index bf189b3dfaf..d015d3ddb5d 100644
--- a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
+++ b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
@@ -206,7 +206,7 @@ void CustomScrollbarTheme::PaintIntoRect(
const LayoutCustomScrollbarPart& layout_custom_scrollbar_part,
GraphicsContext& graphics_context,
const PhysicalRect& rect) {
- PaintInfo paint_info(graphics_context, PixelSnappedIntRect(rect),
+ PaintInfo paint_info(graphics_context, CullRect(PixelSnappedIntRect(rect)),
PaintPhase::kForeground, kGlobalPaintNormalPhase,
kPaintLayerNoFlag);
ObjectPainter(layout_custom_scrollbar_part)
diff --git a/chromium/third_party/blink/renderer/core/paint/details_marker_painter.cc b/chromium/third_party/blink/renderer/core/paint/details_marker_painter.cc
index b22caa8f7bb..ef16b9aa5b1 100644
--- a/chromium/third_party/blink/renderer/core/paint/details_marker_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/details_marker_painter.cc
@@ -78,8 +78,9 @@ static Path CreateRightArrowPath() {
return CreatePath(points);
}
-Path DetailsMarkerPainter::GetCanonicalPath() const {
- switch (layout_details_marker_.GetOrientation()) {
+Path DetailsMarkerPainter::GetCanonicalPath(const ComputedStyle& style,
+ bool is_open) {
+ switch (LayoutDetailsMarker::GetOrientation(style, is_open)) {
case LayoutDetailsMarker::kLeft:
return CreateLeftArrowPath();
case LayoutDetailsMarker::kRight:
@@ -94,7 +95,8 @@ Path DetailsMarkerPainter::GetCanonicalPath() const {
}
Path DetailsMarkerPainter::GetPath(const PhysicalOffset& origin) const {
- Path result = GetCanonicalPath();
+ Path result = GetCanonicalPath(layout_details_marker_.StyleRef(),
+ layout_details_marker_.IsOpen());
result.Transform(AffineTransform().Scale(
layout_details_marker_.ContentWidth().ToFloat(),
layout_details_marker_.ContentHeight().ToFloat()));
diff --git a/chromium/third_party/blink/renderer/core/paint/details_marker_painter.h b/chromium/third_party/blink/renderer/core/paint/details_marker_painter.h
index e5b1064519f..6593b73e21d 100644
--- a/chromium/third_party/blink/renderer/core/paint/details_marker_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/details_marker_painter.h
@@ -9,6 +9,7 @@
namespace blink {
+class ComputedStyle;
class Path;
class LayoutDetailsMarker;
struct PaintInfo;
@@ -22,9 +23,9 @@ class DetailsMarkerPainter {
: layout_details_marker_(layout_details_marker) {}
void Paint(const PaintInfo&);
+ static Path GetCanonicalPath(const ComputedStyle& style, bool is_open);
private:
- Path GetCanonicalPath() const;
Path GetPath(const PhysicalOffset& origin) const;
const LayoutDetailsMarker& layout_details_marker_;
diff --git a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.h b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.h
index a0a1c35f3b1..559841271c2 100644
--- a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.h
@@ -15,6 +15,7 @@ class Document;
class FloatRect;
class GraphicsContext;
class LayoutUnit;
+class Node;
class StyleableMarker;
class TextMarkerBase;
struct PaintInfo;
diff --git a/chromium/third_party/blink/renderer/core/paint/element_timing_utils.cc b/chromium/third_party/blink/renderer/core/paint/element_timing_utils.cc
index 585578a8854..5b4c67ef183 100644
--- a/chromium/third_party/blink/renderer/core/paint/element_timing_utils.cc
+++ b/chromium/third_party/blink/renderer/core/paint/element_timing_utils.cc
@@ -4,8 +4,7 @@
#include "third_party/blink/renderer/core/paint/element_timing_utils.h"
-#include "third_party/blink/public/web/web_widget_client.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -27,7 +26,7 @@ FloatRect ElementTimingUtils::ComputeIntersectionRect(
->FirstFragment()
.LocalBorderBoxProperties(),
visual_rect);
- WebFrameWidgetBase* widget =
+ WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
DCHECK(widget);
return FloatRect(widget->BlinkSpaceToDIPs(visual_rect.Rect()));
diff --git a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
index 5a5736bc5d0..55a0e131a8b 100644
--- a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
@@ -122,14 +122,14 @@ Vector<float> SepiaMatrix(double amount) {
} // namespace
-FilterEffectBuilder::FilterEffectBuilder(
- const FloatRect& reference_box,
- float zoom,
- const PaintFlags* fill_flags,
- const PaintFlags* stroke_flags,
- SkBlurImageFilter::TileMode blur_tile_mode)
+FilterEffectBuilder::FilterEffectBuilder(const FloatRect& reference_box,
+ float zoom,
+ const PaintFlags* fill_flags,
+ const PaintFlags* stroke_flags,
+ SkTileMode blur_tile_mode)
: reference_box_(reference_box),
zoom_(zoom),
+ shorthand_scale_(1),
fill_flags_(fill_flags),
stroke_flags_(stroke_flags),
blur_tile_mode_(blur_tile_mode) {}
@@ -262,6 +262,7 @@ FilterEffect* FilterEffectBuilder::BuildFilterEffect(
case FilterOperation::BLUR: {
float std_deviation = FloatValueForLength(
To<BlurFilterOperation>(filter_operation)->StdDeviation(), 0);
+ std_deviation *= shorthand_scale_;
effect = MakeGarbageCollected<FEGaussianBlur>(
parent_filter, std_deviation, std_deviation);
break;
@@ -269,8 +270,10 @@ FilterEffect* FilterEffectBuilder::BuildFilterEffect(
case FilterOperation::DROP_SHADOW: {
const ShadowData& shadow =
To<DropShadowFilterOperation>(*filter_operation).Shadow();
+ FloatPoint offset = shadow.Location().ScaledBy(shorthand_scale_);
+ float radius = shadow.Blur() * shorthand_scale_;
effect = MakeGarbageCollected<FEDropShadow>(
- parent_filter, shadow.Blur(), shadow.Blur(), shadow.X(), shadow.Y(),
+ parent_filter, radius, radius, offset.X(), offset.Y(),
shadow.GetColor().GetColor(), 1);
break;
}
@@ -378,13 +381,16 @@ CompositorFilterOperations FilterEffectBuilder::BuildFilterOperations(
case FilterOperation::BLUR: {
float pixel_radius =
To<BlurFilterOperation>(*op).StdDeviation().GetFloatValue();
+ pixel_radius *= shorthand_scale_;
filters.AppendBlurFilter(pixel_radius, blur_tile_mode_);
break;
}
case FilterOperation::DROP_SHADOW: {
const ShadowData& shadow = To<DropShadowFilterOperation>(*op).Shadow();
- filters.AppendDropShadowFilter(FlooredIntPoint(shadow.Location()),
- shadow.Blur(),
+ IntPoint floored_offset =
+ FlooredIntPoint(shadow.Location().ScaledBy(shorthand_scale_));
+ float radius = shadow.Blur() * shorthand_scale_;
+ filters.AppendDropShadowFilter(floored_offset, radius,
shadow.GetColor().GetColor());
break;
}
@@ -424,7 +430,7 @@ Filter* FilterEffectBuilder::BuildReferenceFilter(
DynamicTo<SVGFilterElement>(resource ? resource->Target() : nullptr);
if (!filter_element)
return nullptr;
- if (auto* resource_container = resource->ResourceContainer())
+ if (auto* resource_container = resource->ResourceContainerNoCycleCheck())
resource_container->ClearInvalidationMask();
FloatRect filter_region =
SVGLengthContext::ResolveRectangle<SVGFilterElement>(
diff --git a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.h b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.h
index 111b5d2a140..f8da2537985 100644
--- a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.h
+++ b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.h
@@ -31,7 +31,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "third_party/skia/include/core/SkTileMode.h"
namespace blink {
@@ -51,8 +51,7 @@ class CORE_EXPORT FilterEffectBuilder final {
float zoom,
const PaintFlags* fill_flags = nullptr,
const PaintFlags* stroke_flags = nullptr,
- SkBlurImageFilter::TileMode blur_tile_mode =
- SkBlurImageFilter::kClampToBlack_TileMode);
+ SkTileMode blur_tile_mode = SkTileMode::kDecal);
Filter* BuildReferenceFilter(const ReferenceFilterOperation&,
FilterEffect* previous_effect,
@@ -63,12 +62,17 @@ class CORE_EXPORT FilterEffectBuilder final {
CompositorFilterOperations BuildFilterOperations(
const FilterOperations&) const;
+ void SetShorthandScale(float shorthand_scale) {
+ shorthand_scale_ = shorthand_scale;
+ }
+
private:
- FloatRect reference_box_;
- float zoom_;
+ const FloatRect reference_box_;
+ const float zoom_;
+ float shorthand_scale_; // Scale factor for shorthand filter functions.
const PaintFlags* fill_flags_;
const PaintFlags* stroke_flags_;
- const SkBlurImageFilter::TileMode blur_tile_mode_;
+ const SkTileMode blur_tile_mode_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 69a02a1afe7..30e45501136 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -96,8 +96,8 @@ void FirstMeaningfulPaintDetector::NotifyPaint() {
return;
had_user_input_before_provisional_first_meaningful_paint_ = had_user_input_;
- provisional_first_meaningful_paint_swap_ = base::TimeTicks();
- RegisterNotifySwapTime(PaintEvent::kProvisionalFirstMeaningfulPaint);
+ provisional_first_meaningful_paint_presentation_ = base::TimeTicks();
+ RegisterNotifyPresentationTime(PaintEvent::kProvisionalFirstMeaningfulPaint);
}
// This is called only on FirstMeaningfulPaintDetector for main frame.
@@ -115,31 +115,33 @@ void FirstMeaningfulPaintDetector::OnNetwork2Quiet() {
network_quiet_reached_ = true;
if (!provisional_first_meaningful_paint_.is_null()) {
- base::TimeTicks first_meaningful_paint_swap;
+ base::TimeTicks first_meaningful_paint_presentation;
// Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
if (provisional_first_meaningful_paint_ <
paint_timing_->FirstContentfulPaintRendered()) {
first_meaningful_paint_ = paint_timing_->FirstContentfulPaintRendered();
- first_meaningful_paint_swap = paint_timing_->FirstContentfulPaint();
+ first_meaningful_paint_presentation =
+ paint_timing_->FirstContentfulPaint();
// It's possible that this timer fires between when the first contentful
- // paint is set and its SwapPromise is fulfilled. If this happens, defer
- // until NotifyFirstContentfulPaint() is called.
- if (first_meaningful_paint_swap.is_null())
+ // paint is set and its presentation promise is fulfilled. If this
+ // happens, defer until NotifyFirstContentfulPaint() is called.
+ if (first_meaningful_paint_presentation.is_null())
defer_first_meaningful_paint_ = kDeferFirstContentfulPaintNotSet;
} else {
first_meaningful_paint_ = provisional_first_meaningful_paint_;
- first_meaningful_paint_swap = provisional_first_meaningful_paint_swap_;
- // We might still be waiting for one or more swap promises, in which case
- // we want to defer reporting first meaningful paint until they complete.
- // Otherwise, we would either report the wrong swap timestamp or none at
- // all.
- if (outstanding_swap_promise_count_ > 0)
- defer_first_meaningful_paint_ = kDeferOutstandingSwapPromises;
+ first_meaningful_paint_presentation =
+ provisional_first_meaningful_paint_presentation_;
+ // We might still be waiting for one or more presentation promises, in
+ // which case we want to defer reporting first meaningful paint until they
+ // complete. Otherwise, we would either report the wrong presentation
+ // timestamp or none at all.
+ if (outstanding_presentation_promise_count_ > 0)
+ defer_first_meaningful_paint_ = kDeferOutstandingPresentationPromises;
}
if (defer_first_meaningful_paint_ == kDoNotDefer) {
// Report FirstMeaningfulPaint when the page reached network 2-quiet if
- // we aren't waiting for a swap timestamp.
- SetFirstMeaningfulPaint(first_meaningful_paint_swap);
+ // we aren't waiting for a presentation timestamp.
+ SetFirstMeaningfulPaint(first_meaningful_paint_presentation);
}
}
}
@@ -148,34 +150,36 @@ bool FirstMeaningfulPaintDetector::SeenFirstMeaningfulPaint() const {
return !first_meaningful_paint_.is_null();
}
-void FirstMeaningfulPaintDetector::RegisterNotifySwapTime(PaintEvent event) {
- ++outstanding_swap_promise_count_;
- paint_timing_->RegisterNotifySwapTime(
- CrossThreadBindOnce(&FirstMeaningfulPaintDetector::ReportSwapTime,
+void FirstMeaningfulPaintDetector::RegisterNotifyPresentationTime(
+ PaintEvent event) {
+ ++outstanding_presentation_promise_count_;
+ paint_timing_->RegisterNotifyPresentationTime(
+ CrossThreadBindOnce(&FirstMeaningfulPaintDetector::ReportPresentationTime,
WrapCrossThreadWeakPersistent(this), event));
}
-void FirstMeaningfulPaintDetector::ReportSwapTime(PaintEvent event,
- WebSwapResult result,
- base::TimeTicks timestamp) {
+void FirstMeaningfulPaintDetector::ReportPresentationTime(
+ PaintEvent event,
+ WebSwapResult result,
+ base::TimeTicks timestamp) {
DCHECK(event == PaintEvent::kProvisionalFirstMeaningfulPaint);
- DCHECK_GT(outstanding_swap_promise_count_, 0U);
- --outstanding_swap_promise_count_;
-
- // If the swap fails for any reason, we use the timestamp when the SwapPromise
- // was broken. |result| == WebSwapResult::kDidNotSwapSwapFails
- // usually means the compositor decided not swap because there was no actual
- // damage, which can happen when what's being painted isn't visible. In this
- // case, the timestamp will be consistent with the case where the swap
- // succeeds, as they both capture the time up to swap. In other failure cases
- // (aborts during commit), this timestamp is an improvement over the blink
- // paint time, but does not capture some time we're interested in, e.g. image
- // decoding.
+ DCHECK_GT(outstanding_presentation_promise_count_, 0U);
+ --outstanding_presentation_promise_count_;
+
+ // If the presentation fails for any reason, we use the timestamp when the
+ // presentation promise was broken. |result| ==
+ // WebSwapResult::kDidNotSwapSwapFails usually means the compositor decided
+ // not swap because there was no actual damage, which can happen when what's
+ // being painted isn't visible. In this case, the timestamp will be consistent
+ // with the case where the presentation succeeds, as they both capture the
+ // time up to presentation. In other failure cases (aborts during commit),
+ // this timestamp is an improvement over the blink paint time, but does not
+ // capture some time we're interested in, e.g. image decoding.
//
// TODO(crbug.com/738235): Consider not reporting any timestamp when failing
// for reasons other than kDidNotSwapSwapFails.
paint_timing_->ReportSwapResultHistogram(result);
- provisional_first_meaningful_paint_swap_ = timestamp;
+ provisional_first_meaningful_paint_presentation_ = timestamp;
probe::PaintTiming(GetDocument(), "firstMeaningfulPaintCandidate",
timestamp.since_origin().InSecondsF());
@@ -186,39 +190,42 @@ void FirstMeaningfulPaintDetector::ReportSwapTime(PaintEvent event,
seen_first_meaningful_paint_candidate_ = true;
} else {
paint_timing_->SetFirstMeaningfulPaintCandidate(
- provisional_first_meaningful_paint_swap_);
+ provisional_first_meaningful_paint_presentation_);
}
- if (defer_first_meaningful_paint_ == kDeferOutstandingSwapPromises &&
- outstanding_swap_promise_count_ == 0) {
+ if (defer_first_meaningful_paint_ == kDeferOutstandingPresentationPromises &&
+ outstanding_presentation_promise_count_ == 0) {
DCHECK(!first_meaningful_paint_.is_null());
- SetFirstMeaningfulPaint(provisional_first_meaningful_paint_swap_);
+ SetFirstMeaningfulPaint(provisional_first_meaningful_paint_presentation_);
}
}
void FirstMeaningfulPaintDetector::NotifyFirstContentfulPaint(
- base::TimeTicks swap_stamp) {
+ base::TimeTicks presentation_time) {
if (defer_first_meaningful_paint_ != kDeferFirstContentfulPaintNotSet)
return;
- SetFirstMeaningfulPaint(swap_stamp);
+ SetFirstMeaningfulPaint(presentation_time);
}
void FirstMeaningfulPaintDetector::SetFirstMeaningfulPaint(
- base::TimeTicks swap_stamp) {
+ base::TimeTicks presentation_time) {
DCHECK(paint_timing_->FirstMeaningfulPaint().is_null());
- DCHECK(!swap_stamp.is_null());
+ DCHECK(!presentation_time.is_null());
DCHECK(network_quiet_reached_);
- double swap_time_seconds = swap_stamp.since_origin().InSecondsF();
- probe::PaintTiming(GetDocument(), "firstMeaningfulPaint", swap_time_seconds);
+ double presentation_time_seconds =
+ presentation_time.since_origin().InSecondsF();
+ probe::PaintTiming(GetDocument(), "firstMeaningfulPaint",
+ presentation_time_seconds);
// If there's only been one contentful paint, then there won't have been
// a meaningful paint signalled to the Scheduler, so mark one now.
// This is a no-op if a FMPC has already been marked.
- paint_timing_->SetFirstMeaningfulPaintCandidate(swap_stamp);
+ paint_timing_->SetFirstMeaningfulPaintCandidate(presentation_time);
paint_timing_->SetFirstMeaningfulPaint(
- swap_stamp, had_user_input_before_provisional_first_meaningful_paint_);
+ presentation_time,
+ had_user_input_before_provisional_first_meaningful_paint_);
}
// static
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index 606c3eab5c1..4d1b5d4a560 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -41,8 +41,8 @@ class CORE_EXPORT FirstMeaningfulPaintDetector
int visible_height);
void NotifyInputEvent();
void NotifyPaint();
- void ReportSwapTime(PaintEvent, WebSwapResult, base::TimeTicks);
- void NotifyFirstContentfulPaint(base::TimeTicks swap_stamp);
+ void ReportPresentationTime(PaintEvent, WebSwapResult, base::TimeTicks);
+ void NotifyFirstContentfulPaint(base::TimeTicks presentation_time);
void OnNetwork2Quiet();
bool SeenFirstMeaningfulPaint() const;
@@ -58,14 +58,14 @@ class CORE_EXPORT FirstMeaningfulPaintDetector
enum DeferFirstMeaningfulPaint {
kDoNotDefer,
- kDeferOutstandingSwapPromises,
+ kDeferOutstandingPresentationPromises,
kDeferFirstContentfulPaintNotSet
};
Document* GetDocument();
int ActiveConnections();
- void RegisterNotifySwapTime(PaintEvent);
- void SetFirstMeaningfulPaint(base::TimeTicks swap_stamp);
+ void RegisterNotifyPresentationTime(PaintEvent);
+ void SetFirstMeaningfulPaint(base::TimeTicks presentation_time);
bool next_paint_is_meaningful_ = false;
HadUserInput had_user_input_ = kNoUserInput;
@@ -74,14 +74,14 @@ class CORE_EXPORT FirstMeaningfulPaintDetector
Member<PaintTiming> paint_timing_;
base::TimeTicks provisional_first_meaningful_paint_;
- base::TimeTicks provisional_first_meaningful_paint_swap_;
+ base::TimeTicks provisional_first_meaningful_paint_presentation_;
double max_significance_so_far_ = 0.0;
double accumulated_significance_while_having_blank_text_ = 0.0;
unsigned prev_layout_object_count_ = 0;
bool seen_first_meaningful_paint_candidate_ = false;
bool network_quiet_reached_ = false;
base::TimeTicks first_meaningful_paint_;
- unsigned outstanding_swap_promise_count_ = 0;
+ unsigned outstanding_presentation_promise_count_ = 0;
DeferFirstMeaningfulPaint defer_first_meaningful_paint_ = kDoNotDefer;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
index b448877213e..07f86b41910 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -60,56 +60,57 @@ class FirstMeaningfulPaintDetectorTest : public PageTestBase {
void SimulateUserInput() { Detector().NotifyInputEvent(); }
- void ClearFirstPaintSwapPromise() {
+ void ClearFirstPaintPresentationPromise() {
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
- GetPaintTiming().ReportSwapTime(PaintEvent::kFirstPaint,
- WebSwapResult::kDidSwap, Now());
+ GetPaintTiming().ReportPresentationTime(PaintEvent::kFirstPaint,
+ WebSwapResult::kDidSwap, Now());
}
- void ClearFirstContentfulPaintSwapPromise() {
+ void ClearFirstContentfulPaintPresentationPromise() {
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
- GetPaintTiming().ReportSwapTime(PaintEvent::kFirstContentfulPaint,
- WebSwapResult::kDidSwap, Now());
+ GetPaintTiming().ReportPresentationTime(PaintEvent::kFirstContentfulPaint,
+ WebSwapResult::kDidSwap, Now());
}
- void ClearProvisionalFirstMeaningfulPaintSwapPromise() {
+ void ClearProvisionalFirstMeaningfulPaintPresentationPromise() {
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
- ClearProvisionalFirstMeaningfulPaintSwapPromise(Now());
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise(Now());
}
- void ClearProvisionalFirstMeaningfulPaintSwapPromise(
+ void ClearProvisionalFirstMeaningfulPaintPresentationPromise(
base::TimeTicks timestamp) {
- Detector().ReportSwapTime(PaintEvent::kProvisionalFirstMeaningfulPaint,
- WebSwapResult::kDidSwap, timestamp);
+ Detector().ReportPresentationTime(
+ PaintEvent::kProvisionalFirstMeaningfulPaint, WebSwapResult::kDidSwap,
+ timestamp);
}
- unsigned OutstandingDetectorSwapPromiseCount() {
- return Detector().outstanding_swap_promise_count_;
+ unsigned OutstandingDetectorPresentationPromiseCount() {
+ return Detector().outstanding_presentation_promise_count_;
}
- void MarkFirstContentfulPaintAndClearSwapPromise() {
+ void MarkFirstContentfulPaintAndClearPresentationPromise() {
GetPaintTiming().MarkFirstContentfulPaint();
- ClearFirstContentfulPaintSwapPromise();
+ ClearFirstContentfulPaintPresentationPromise();
}
- void MarkFirstPaintAndClearSwapPromise() {
+ void MarkFirstPaintAndClearPresentationPromise() {
GetPaintTiming().MarkFirstPaint();
- ClearFirstPaintSwapPromise();
+ ClearFirstPaintPresentationPromise();
}
};
TEST_F(FirstMeaningfulPaintDetectorTest, NoFirstPaint) {
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 0U);
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
}
TEST_F(FirstMeaningfulPaintDetectorTest, OneLayout) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
base::TimeTicks after_paint = AdvanceClockAndGetTime();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
SimulateNetworkStable();
@@ -117,14 +118,14 @@ TEST_F(FirstMeaningfulPaintDetectorTest, OneLayout) {
}
TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantSecond) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
base::TimeTicks after_layout1 = AdvanceClockAndGetTime();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
base::TimeTicks after_layout2 = AdvanceClockAndGetTime();
SimulateNetworkStable();
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_layout1);
@@ -132,13 +133,13 @@ TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantSecond) {
}
TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantFirst) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
base::TimeTicks after_layout1 = AdvanceClockAndGetTime();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 0U);
SimulateNetworkStable();
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstPaintRendered());
@@ -146,38 +147,38 @@ TEST_F(FirstMeaningfulPaintDetectorTest, TwoLayoutsSignificantFirst) {
}
TEST_F(FirstMeaningfulPaintDetectorTest, FirstMeaningfulPaintCandidate) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(),
base::TimeTicks());
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
base::TimeTicks after_paint = AdvanceClockAndGetTime();
// The first candidate gets ignored.
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(),
base::TimeTicks());
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
// The second candidate gets reported.
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaintCandidate(), after_paint);
base::TimeTicks candidate = GetPaintTiming().FirstMeaningfulPaintCandidate();
// The third candidate gets ignored since we already saw the first candidate.
SimulateLayoutAndPaint(20);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(), candidate);
}
TEST_F(FirstMeaningfulPaintDetectorTest,
OnlyOneFirstMeaningfulPaintCandidateBeforeNetworkStable) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(),
base::TimeTicks());
base::TimeTicks before_paint = AdvanceClockAndGetTime();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
// The first candidate is initially ignored.
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(),
base::TimeTicks());
@@ -187,31 +188,31 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
base::TimeTicks candidate = GetPaintTiming().FirstMeaningfulPaintCandidate();
// The second candidate is then ignored.
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 0U);
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaintCandidate(), candidate);
}
TEST_F(FirstMeaningfulPaintDetectorTest,
NetworkStableBeforeFirstContentfulPaint) {
- MarkFirstPaintAndClearSwapPromise();
+ MarkFirstPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateNetworkStable();
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
FirstMeaningfulPaintShouldNotBeBeforeFirstContentfulPaint) {
- MarkFirstPaintAndClearSwapPromise();
+ MarkFirstPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateNetworkStable();
EXPECT_GE(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstContentfulPaint());
@@ -219,82 +220,83 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
TEST_F(FirstMeaningfulPaintDetectorTest,
FirstMeaningfulPaintAfterUserInteraction) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateUserInput();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
}
TEST_F(FirstMeaningfulPaintDetectorTest, UserInteractionBeforeFirstPaint) {
SimulateUserInput();
- MarkFirstContentfulPaintAndClearSwapPromise();
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
SimulateNetworkStable();
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
- WaitForSingleOutstandingSwapPromiseAfterNetworkStable) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ WaitForSingleOutstandingPresentationPromiseAfterNetworkStable) {
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
EXPECT_NE(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
}
TEST_F(FirstMeaningfulPaintDetectorTest,
- WaitForMultipleOutstandingSwapPromisesAfterNetworkStable) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+ WaitForMultipleOutstandingPresentationPromisesAfterNetworkStable) {
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 2U);
- // Having outstanding swap promises should defer setting FMP.
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 2U);
+ // Having outstanding presentation promises should defer setting FMP.
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- // Clearing the first swap promise should have no effect on FMP.
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+ // Clearing the first presentation promise should have no effect on FMP.
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- base::TimeTicks after_first_swap = AdvanceClockAndGetTime();
- // Clearing the last outstanding swap promise should set FMP.
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+ base::TimeTicks after_first_presentation = AdvanceClockAndGetTime();
+ // Clearing the last outstanding presentation promise should set FMP.
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 0U);
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_swap);
+ EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), after_first_presentation);
}
TEST_F(FirstMeaningfulPaintDetectorTest,
- WaitForFirstContentfulPaintSwapAfterNetworkStable) {
- MarkFirstPaintAndClearSwapPromise();
+ WaitForFirstContentfulPaintPresentationpAfterNetworkStable) {
+ MarkFirstPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
- ClearProvisionalFirstMeaningfulPaintSwapPromise();
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise();
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
GetPaintTiming().MarkFirstContentfulPaint();
- // FCP > FMP candidate, but still waiting for FCP swap.
+ // FCP > FMP candidate, but still waiting for FCP presentation.
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- // Trigger notifying the detector about the FCP swap.
- ClearFirstContentfulPaintSwapPromise();
+ // Trigger notifying the detector about the FCP presentation.
+ ClearFirstContentfulPaintPresentationPromise();
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(),
GetPaintTiming().FirstContentfulPaint());
}
-TEST_F(FirstMeaningfulPaintDetectorTest,
- ProvisionalTimestampChangesAfterNetworkQuietWithOutstandingSwapPromise) {
- MarkFirstContentfulPaintAndClearSwapPromise();
+TEST_F(
+ FirstMeaningfulPaintDetectorTest,
+ ProvisionalTimestampChangesAfterNetworkQuietWithOutstandingPresentationPromise) {
+ MarkFirstContentfulPaintAndClearPresentationPromise();
SimulateLayoutAndPaint(1);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
// Simulate network stable so provisional FMP will be set on next layout.
base::TimeTicks pre_stable_timestamp = AdvanceClockAndGetTime();
@@ -302,17 +304,17 @@ TEST_F(FirstMeaningfulPaintDetectorTest,
SimulateNetworkStable();
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
- // Force another FMP candidate while there is a pending swap promise and the
- // FMP non-swap timestamp is set.
+ // Force another FMP candidate while there is a pending presentation promise
+ // and the FMP non-presentation timestamp is set.
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
SimulateLayoutAndPaint(10);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 1U);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 1U);
- // Simulate a delay in receiving the SwapPromise timestamp. Clearing this
- // SwapPromise will set FMP, and this will crash if the new provisional
- // non-swap timestamp is used.
- ClearProvisionalFirstMeaningfulPaintSwapPromise(pre_stable_timestamp);
- EXPECT_EQ(OutstandingDetectorSwapPromiseCount(), 0U);
+ // Simulate a delay in receiving the PresentationPromise timestamp. Clearing
+ // this PresentationPromise will set FMP, and this will crash if the new
+ // provisional non-presentation timestamp is used.
+ ClearProvisionalFirstMeaningfulPaintPresentationPromise(pre_stable_timestamp);
+ EXPECT_EQ(OutstandingDetectorPresentationPromiseCount(), 0U);
EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(), pre_stable_timestamp);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/fragment_data.cc b/chromium/third_party/blink/renderer/core/paint/fragment_data.cc
index 25f3846dd62..e4ecbb652b8 100644
--- a/chromium/third_party/blink/renderer/core/paint/fragment_data.cc
+++ b/chromium/third_party/blink/renderer/core/paint/fragment_data.cc
@@ -33,6 +33,19 @@ FragmentData& FragmentData::EnsureNextFragment() {
return *rare_data_->next_fragment_;
}
+FragmentData& FragmentData::LastFragment() {
+ for (FragmentData* fragment = this;;) {
+ FragmentData* next = fragment->NextFragment();
+ if (!next)
+ return *fragment;
+ fragment = next;
+ }
+}
+
+const FragmentData& FragmentData::LastFragment() const {
+ return const_cast<FragmentData*>(this)->LastFragment();
+}
+
FragmentData::RareData& FragmentData::EnsureRareData() {
if (!rare_data_)
rare_data_ = std::make_unique<RareData>();
diff --git a/chromium/third_party/blink/renderer/core/paint/fragment_data.h b/chromium/third_party/blink/renderer/core/paint/fragment_data.h
index 0cf85617021..2e275a680b0 100644
--- a/chromium/third_party/blink/renderer/core/paint/fragment_data.h
+++ b/chromium/third_party/blink/renderer/core/paint/fragment_data.h
@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
+#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -27,6 +28,9 @@ class CORE_EXPORT FragmentData {
FragmentData& EnsureNextFragment();
void ClearNextFragment() { DestroyTail(); }
+ FragmentData& LastFragment();
+ const FragmentData& LastFragment() const;
+
// Physical offset of this fragment's local border box's top-left position
// from the origin of the transform node of the fragment's property tree
// state.
@@ -175,6 +179,19 @@ class CORE_EXPORT FragmentData {
}
}
+ void SetCullRect(const CullRect& cull_rect) {
+ EnsureRareData().cull_rect_ = cull_rect;
+ }
+ CullRect GetCullRect() const {
+ return rare_data_ ? rare_data_->cull_rect_ : CullRect();
+ }
+ void SetContentsCullRect(const CullRect& contents_cull_rect) {
+ EnsureRareData().contents_cull_rect_ = contents_cull_rect;
+ }
+ CullRect GetContentsCullRect() const {
+ return rare_data_ ? rare_data_->contents_cull_rect_ : CullRect();
+ }
+
// This is the complete set of property nodes that is inherited
// from the ancestor before applying any local CSS properties,
// but includes paint offset transform.
@@ -242,6 +259,8 @@ class CORE_EXPORT FragmentData {
bool is_clip_path_cache_valid = false;
base::Optional<IntRect> clip_path_bounding_box;
scoped_refptr<const RefCountedPath> clip_path_path;
+ CullRect cull_rect_;
+ CullRect contents_cull_rect_;
std::unique_ptr<FragmentData> next_fragment_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/frame_painter.cc b/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
index a4bf31c51cc..ae7498371fe 100644
--- a/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/frame_painter.cc
@@ -74,9 +74,8 @@ void FramePainter::PaintContents(GraphicsContext& context,
FontCachePurgePreventer font_cache_purge_preventer;
PaintLayerFlags root_layer_paint_flags = 0;
- // This will prevent clipping the root PaintLayer to its visible content
- // rect when root layer scrolling is enabled.
- if (document->IsCapturingLayout())
+ // This will prevent clipping the root PaintLayer to its visible content rect.
+ if (document->IsPrintingOrPaintingPreview())
root_layer_paint_flags = kPaintLayerPaintingOverflowContents;
PaintLayer* root_layer = layout_view->Layer();
diff --git a/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils.cc b/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
index 74b41546921..762a9a6167d 100644
--- a/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
+++ b/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
+#include "components/shared_highlighting/core/common/text_fragments_constants.h"
#include "third_party/blink/renderer/core/css/pseudo_style_request.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/dom/element.h"
@@ -11,7 +12,6 @@
#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/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/core/paint/text_paint_style.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
@@ -106,6 +107,9 @@ Color HighlightThemeBackgroundColor(const Document& document,
: LayoutTheme::GetTheme().InactiveSelectionBackgroundColor(
style.UsedColorScheme());
case kPseudoIdTargetText:
+ if (RuntimeEnabledFeatures::TextFragmentColorChangeEnabled())
+ return Color(shared_highlighting::kFragmentTextBackgroundColorARGB);
+
return LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
false /* active match */, document.InForcedColorsMode(),
style.UsedColorScheme());
@@ -140,13 +144,8 @@ scoped_refptr<const ComputedStyle> HighlightPseudoStyle(Node* node,
if (!element)
element = Traversal<Element>::FirstAncestorOrSelf(*node);
- // <content> and <shadow> elements do not have ComputedStyle, hence they will
- // return null for StyleForPseudoElement(). Return early to avoid DCHECK
- // failure for GetComputedStyle() inside StyleForPseudoElement() below.
- if (!element || element->IsPseudoElement() ||
- IsActiveV0InsertionPoint(*element)) {
+ if (!element || element->IsPseudoElement())
return nullptr;
- }
PseudoElementStyleRequest request(pseudo);
@@ -156,7 +155,8 @@ scoped_refptr<const ComputedStyle> HighlightPseudoStyle(Node* node,
// ::selection and ::selection:window-inactive styles may be different. Only
// cache the styles for ::selection if there are no :window-inactive
// selector, or if the page is active.
- return element->StyleForPseudoElement(request, element->GetComputedStyle());
+ return element->UncachedStyleForPseudoElement(request,
+ element->GetComputedStyle());
}
return element->CachedStyleForPseudoElement(request);
@@ -288,6 +288,10 @@ TextPaintStyle HighlightPaintingUtils::HighlightPaintingStyle(
bool uses_text_as_clip = paint_info.phase == PaintPhase::kTextClip;
const GlobalPaintFlags global_paint_flags = paint_info.GetGlobalPaintFlags();
+ // Each highlight overlay’s shadows are completely independent of any shadows
+ // specified on the originating element (or the other highlight overlays).
+ highlight_style.shadow = nullptr;
+
if (!uses_text_as_clip) {
highlight_style.fill_color = HighlightForegroundColor(
document, style, node, pseudo, global_paint_flags);
@@ -309,7 +313,7 @@ TextPaintStyle HighlightPaintingUtils::HighlightPaintingStyle(
}
// Text shadows are disabled when printing. http://crbug.com/258321
- if (paint_info.IsPrinting())
+ if (document.Printing())
highlight_style.shadow = nullptr;
return highlight_style;
diff --git a/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils_test.cc b/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils_test.cc
index ee5f6fd3541..6b5c0aa0571 100644
--- a/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/highlight_painting_utils_test.cc
@@ -170,7 +170,7 @@ TEST_F(HighlightPaintingUtilsTest, SelectedTextInputShadow) {
std::unique_ptr<PaintController> controller{
std::make_unique<PaintController>()};
GraphicsContext context(*controller);
- PaintInfo paint_info(context, IntRect(), PaintPhase::kForeground,
+ PaintInfo paint_info(context, CullRect(), PaintPhase::kForeground,
kGlobalPaintNormalPhase, 0 /* paint_flags */);
TextPaintStyle paint_style;
diff --git a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
index f9c180e21f5..e736ec0f788 100644
--- a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter.cc
@@ -46,9 +46,19 @@ void HTMLCanvasPainter::PaintReplaced(const PaintInfo& paint_info,
bool flatten_composited_layers =
paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- !flatten_composited_layers) {
- if (auto* layer = canvas->ContentsCcLayer()) {
+
+ if (auto* layer = canvas->ContentsCcLayer()) {
+ // TODO(crbug.com/705019): For a texture layer canvas, setting the layer
+ // background color to an opaque color will cause the layer to be treated as
+ // opaque. For a surface layer canvas, contents could be opaque, but that
+ // cannot be determined from the main thread. Or can it?
+ if (layout_html_canvas_.DrawsBackgroundOntoContentLayer()) {
+ Color background_color =
+ layout_html_canvas_.ResolveColor(GetCSSPropertyBackgroundColor());
+ layer->SetBackgroundColor(background_color.Rgb());
+ }
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ !flatten_composited_layers) {
IntRect pixel_snapped_rect = PixelSnappedIntRect(paint_rect);
layer->SetBounds(gfx::Size(pixel_snapped_rect.Size()));
layer->SetIsDrawable(true);
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
index 18089bb7ace..0d98673fce7 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
@@ -23,9 +23,8 @@ namespace internal {
// "CORE_EXPORT" is needed to make this function visible to tests.
bool CORE_EXPORT
-IsExplicitlyRegisteredForTiming(const LayoutObject* layout_object) {
- DCHECK(layout_object);
- const auto* element = DynamicTo<Element>(layout_object->GetNode());
+IsExplicitlyRegisteredForTiming(const LayoutObject& layout_object) {
+ const auto* element = DynamicTo<Element>(layout_object.GetNode());
if (!element)
return false;
@@ -63,7 +62,7 @@ ImageElementTiming::ImageElementTiming(LocalDOMWindow& window)
void ImageElementTiming::NotifyImageFinished(
const LayoutObject& layout_object,
const ImageResourceContent* cached_image) {
- if (!internal::IsExplicitlyRegisteredForTiming(&layout_object))
+ if (!internal::IsExplicitlyRegisteredForTiming(layout_object))
return;
const auto& insertion_result = images_notified_.insert(
@@ -86,28 +85,28 @@ base::TimeTicks ImageElementTiming::GetBackgroundImageLoadTime(
}
void ImageElementTiming::NotifyImagePainted(
- const LayoutObject* layout_object,
- const ImageResourceContent* cached_image,
+ const LayoutObject& layout_object,
+ const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border) {
- DCHECK(layout_object);
-
if (!internal::IsExplicitlyRegisteredForTiming(layout_object))
return;
- auto it = images_notified_.find(std::make_pair(layout_object, cached_image));
+ auto it =
+ images_notified_.find(std::make_pair(&layout_object, &cached_image));
// It is possible that the pair is not in |images_notified_|. See
// https://crbug.com/1027948
- if (it != images_notified_.end() && !it->value.is_painted_ && cached_image) {
+ if (it != images_notified_.end() && !it->value.is_painted_) {
it->value.is_painted_ = true;
- NotifyImagePaintedInternal(layout_object->GetNode(), *layout_object,
- *cached_image, current_paint_chunk_properties,
+ DCHECK(layout_object.GetNode());
+ NotifyImagePaintedInternal(*layout_object.GetNode(), layout_object,
+ cached_image, current_paint_chunk_properties,
it->value.load_time_, image_border);
}
}
void ImageElementTiming::NotifyImagePaintedInternal(
- Node* node,
+ Node& node,
const LayoutObject& layout_object,
const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
@@ -115,7 +114,6 @@ void ImageElementTiming::NotifyImagePaintedInternal(
const IntRect& image_border) {
LocalFrame* frame = GetSupplementable()->GetFrame();
DCHECK(frame == layout_object.GetDocument().GetFrame());
- DCHECK(node);
// Background images could cause |node| to not be an element. For example,
// style applied to body causes this node to be a Document Node. Therefore,
// bail out if that is the case.
@@ -127,7 +125,7 @@ void ImageElementTiming::NotifyImagePaintedInternal(
// something once the discussions at
// https://github.com/WICG/element-timing/issues/3 and
// https://github.com/w3c/webcomponents/issues/816 have been resolved.
- if (node->IsInShadowTree())
+ if (node.IsInShadowTree())
return;
// Do not expose elements which should have effective zero opacity.
@@ -177,37 +175,34 @@ void ImageElementTiming::NotifyImagePaintedInternal(
element_timings_.emplace_back(MakeGarbageCollected<ElementTimingInfo>(
image_url, intersection_rect, load_time, attr,
cached_image.IntrinsicSize(respect_orientation), id, element));
- // Only queue a swap promise when |element_timings_| was empty. All of the
- // records in |element_timings_| will be processed when the promise succeeds
- // or fails, and at that time the vector is cleared.
+ // Only queue a presentation promise when |element_timings_| was empty. All of
+ // the records in |element_timings_| will be processed when the promise
+ // succeeds or fails, and at that time the vector is cleared.
if (element_timings_.size() == 1) {
- frame->GetChromeClient().NotifySwapTime(
- *frame,
- CrossThreadBindOnce(&ImageElementTiming::ReportImagePaintSwapTime,
- WrapCrossThreadWeakPersistent(this)));
+ frame->GetChromeClient().NotifyPresentationTime(
+ *frame, CrossThreadBindOnce(
+ &ImageElementTiming::ReportImagePaintPresentationTime,
+ WrapCrossThreadWeakPersistent(this)));
}
}
void ImageElementTiming::NotifyBackgroundImagePainted(
- Node* node,
- const StyleFetchedImage* background_image,
+ Node& node,
+ const StyleFetchedImage& background_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border) {
- DCHECK(node);
- DCHECK(background_image);
-
- const LayoutObject* layout_object = node->GetLayoutObject();
+ const LayoutObject* layout_object = node.GetLayoutObject();
if (!layout_object)
return;
- if (!internal::IsExplicitlyRegisteredForTiming(layout_object))
+ if (!internal::IsExplicitlyRegisteredForTiming(*layout_object))
return;
- const ImageResourceContent* cached_image = background_image->CachedImage();
+ const ImageResourceContent* cached_image = background_image.CachedImage();
if (!cached_image || !cached_image->IsLoaded())
return;
- auto it = background_image_timestamps_.find(background_image);
+ auto it = background_image_timestamps_.find(&background_image);
DCHECK(it != background_image_timestamps_.end());
ImageInfo& info =
@@ -216,14 +211,15 @@ void ImageElementTiming::NotifyBackgroundImagePainted(
.stored_value->value;
if (!info.is_painted_) {
info.is_painted_ = true;
- NotifyImagePaintedInternal(layout_object->GetNode(), *layout_object,
- *cached_image, current_paint_chunk_properties,
- it->value, image_border);
+ NotifyImagePaintedInternal(node, *layout_object, *cached_image,
+ current_paint_chunk_properties, it->value,
+ image_border);
}
}
-void ImageElementTiming::ReportImagePaintSwapTime(WebSwapResult,
- base::TimeTicks timestamp) {
+void ImageElementTiming::ReportImagePaintPresentationTime(
+ WebSwapResult,
+ base::TimeTicks timestamp) {
WindowPerformance* performance =
DOMWindowPerformance::performance(*GetSupplementable());
if (performance) {
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
index 0dbb052fe43..156884288fa 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -48,16 +48,16 @@ class CORE_EXPORT ImageElementTiming final
base::TimeTicks GetBackgroundImageLoadTime(const StyleFetchedImage*);
// Called when the LayoutObject has been painted. This method might queue a
- // swap promise to compute and report paint timestamps.
+ // presentation promise to compute and report paint timestamps.
void NotifyImagePainted(
- const LayoutObject*,
- const ImageResourceContent* cached_image,
+ const LayoutObject&,
+ const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border);
void NotifyBackgroundImagePainted(
- Node*,
- const StyleFetchedImage* background_image,
+ Node&,
+ const StyleFetchedImage& background_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border);
@@ -70,15 +70,16 @@ class CORE_EXPORT ImageElementTiming final
friend class ImageElementTimingTest;
void NotifyImagePaintedInternal(
- Node*,
+ Node&,
const LayoutObject&,
const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
base::TimeTicks load_time,
const IntRect& image_border);
- // Callback for the swap promise. Reports paint timestamps.
- void ReportImagePaintSwapTime(WebSwapResult, base::TimeTicks timestamp);
+ // Callback for the presentation promise. Reports paint timestamps.
+ void ReportImagePaintPresentationTime(WebSwapResult,
+ base::TimeTicks timestamp);
// Class containing information about image element timing.
class ElementTimingInfo final : public GarbageCollected<ElementTimingInfo> {
@@ -113,7 +114,7 @@ class CORE_EXPORT ImageElementTiming final
};
// Vector containing the element timing infos that will be reported during the
- // next swap promise callback.
+ // next presentation promise callback.
HeapVector<Member<ElementTimingInfo>> element_timings_;
struct ImageInfo {
ImageInfo() {}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
index 9cff06c969d..87050f8f3ad 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
@@ -18,9 +18,7 @@
namespace blink {
namespace internal {
-
-extern bool IsExplicitlyRegisteredForTiming(const LayoutObject* layout_object);
-
+extern bool IsExplicitlyRegisteredForTiming(const LayoutObject& layout_object);
}
class ImageElementTimingTest : public testing::Test,
@@ -126,25 +124,25 @@ TEST_P(ImageElementTimingTest, TestIsExplicitlyRegisteredForTiming) {
base_url_);
LayoutObject* without_attribute = GetLayoutObjectById("missing-attribute");
- bool actual = internal::IsExplicitlyRegisteredForTiming(without_attribute);
+ bool actual = internal::IsExplicitlyRegisteredForTiming(*without_attribute);
EXPECT_FALSE(actual) << "Nodes without an 'elementtiming' attribute should "
"not be explicitly registered.";
LayoutObject* with_undefined_attribute =
GetLayoutObjectById("unset-attribute");
- actual = internal::IsExplicitlyRegisteredForTiming(with_undefined_attribute);
+ actual = internal::IsExplicitlyRegisteredForTiming(*with_undefined_attribute);
EXPECT_TRUE(actual) << "Nodes with undefined 'elementtiming' attribute "
"should be explicitly registered.";
LayoutObject* with_empty_attribute = GetLayoutObjectById("empty-attribute");
- actual = internal::IsExplicitlyRegisteredForTiming(with_empty_attribute);
+ actual = internal::IsExplicitlyRegisteredForTiming(*with_empty_attribute);
EXPECT_TRUE(actual) << "Nodes with an empty 'elementtiming' attribute "
"should be explicitly registered.";
LayoutObject* with_explicit_element_timing =
GetLayoutObjectById("valid-attribute");
actual =
- internal::IsExplicitlyRegisteredForTiming(with_explicit_element_timing);
+ internal::IsExplicitlyRegisteredForTiming(*with_explicit_element_timing);
EXPECT_TRUE(actual) << "Nodes with a non-empty 'elementtiming' attribute "
"should be explicitly registered.";
}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
index e1ec4037aef..45f5dc6be8d 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -84,6 +84,9 @@ void ImagePaintTimingDetector::PopulateTraceValue(
value.SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame());
value.SetBoolean("isOOPIF",
!frame_view_->GetFrame().LocalFrameRoot().IsMainFrame());
+ if (first_image_paint.lcp_rect_info_) {
+ first_image_paint.lcp_rect_info_->OutputToTraceValue(value);
+ }
}
void ImagePaintTimingDetector::ReportCandidateToTrace(
@@ -151,7 +154,7 @@ void ImagePaintTimingDetector::OnPaintFinished() {
return;
last_registered_frame_index_ = frame_index_ - 1;
- RegisterNotifySwapTime();
+ RegisterNotifyPresentationTime();
}
void ImagePaintTimingDetector::NotifyImageRemoved(
@@ -179,24 +182,25 @@ void ImagePaintTimingDetector::StopRecordEntries() {
}
}
-void ImagePaintTimingDetector::RegisterNotifySwapTime() {
- auto callback = WTF::Bind(&ImagePaintTimingDetector::ReportSwapTime,
+void ImagePaintTimingDetector::RegisterNotifyPresentationTime() {
+ auto callback = WTF::Bind(&ImagePaintTimingDetector::ReportPresentationTime,
WrapCrossThreadWeakPersistent(this),
last_registered_frame_index_);
callback_manager_->RegisterCallback(std::move(callback));
- num_pending_swap_callbacks_++;
+ num_pending_presentation_callbacks_++;
}
-void ImagePaintTimingDetector::ReportSwapTime(unsigned last_queued_frame_index,
- base::TimeTicks timestamp) {
+void ImagePaintTimingDetector::ReportPresentationTime(
+ unsigned last_queued_frame_index,
+ base::TimeTicks timestamp) {
if (!is_recording_)
return;
// The callback is safe from race-condition only when running on main-thread.
DCHECK(ThreadState::Current()->IsMainThread());
records_manager_.AssignPaintTimeToRegisteredQueuedRecords(
timestamp, last_queued_frame_index);
- num_pending_swap_callbacks_--;
- DCHECK_GE(num_pending_swap_callbacks_, 0);
+ num_pending_presentation_callbacks_--;
+ DCHECK_GE(num_pending_presentation_callbacks_, 0);
}
void ImageRecordsManager::AssignPaintTimeToRegisteredQueuedRecords(
@@ -232,16 +236,21 @@ void ImagePaintTimingDetector::RecordImage(
return;
bool is_recorded_visible_image =
records_manager_.IsRecordedVisibleImage(record_id);
+
if (int depth = IgnorePaintTimingScope::IgnoreDepth()) {
// Record the largest loaded image that is hidden due to documentElement
// being invisible but by no other reason (i.e. IgnoreDepth() needs to be
// 1).
if (depth == 1 && IgnorePaintTimingScope::IsDocumentElementInvisible() &&
!is_recorded_visible_image && cached_image.IsLoaded()) {
- uint64_t rect_size = ComputeImageRectSize(image_border, intrinsic_size,
- current_paint_chunk_properties,
- object, cached_image);
- records_manager_.MaybeUpdateLargestIgnoredImage(record_id, rect_size);
+ FloatRect mapped_visual_rect =
+ frame_view_->GetPaintTimingDetector().CalculateVisualRect(
+ image_border, current_paint_chunk_properties);
+ uint64_t rect_size = ComputeImageRectSize(
+ image_border, mapped_visual_rect, intrinsic_size,
+ current_paint_chunk_properties, object, cached_image);
+ records_manager_.MaybeUpdateLargestIgnoredImage(
+ record_id, rect_size, image_border, mapped_visual_rect);
}
return;
}
@@ -269,13 +278,17 @@ void ImagePaintTimingDetector::RecordImage(
// until the size is known.
if (image_border.IsEmpty())
return;
- uint64_t rect_size = ComputeImageRectSize(image_border, intrinsic_size,
- current_paint_chunk_properties,
- object, cached_image);
+ FloatRect mapped_visual_rect =
+ frame_view_->GetPaintTimingDetector().CalculateVisualRect(
+ image_border, current_paint_chunk_properties);
+ uint64_t rect_size = ComputeImageRectSize(
+ image_border, mapped_visual_rect, intrinsic_size,
+ current_paint_chunk_properties, object, cached_image);
if (rect_size == 0) {
records_manager_.RecordInvisible(record_id);
} else {
- records_manager_.RecordVisible(record_id, rect_size);
+ records_manager_.RecordVisible(record_id, rect_size, image_border,
+ mapped_visual_rect);
if (cached_image.IsLoaded()) {
records_manager_.OnImageLoaded(record_id, frame_index_, style_image);
need_update_timing_at_frame_end_ = true;
@@ -285,13 +298,11 @@ void ImagePaintTimingDetector::RecordImage(
uint64_t ImagePaintTimingDetector::ComputeImageRectSize(
const IntRect& image_border,
+ const FloatRect& mapped_visual_rect,
const IntSize& intrinsic_size,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const LayoutObject& object,
const ImageResourceContent& cached_image) {
- FloatRect mapped_visual_rect =
- frame_view_->GetPaintTimingDetector().CalculateVisualRect(
- image_border, current_paint_chunk_properties);
if (base::Optional<PaintTimingVisualizer>& visualizer =
frame_view_->GetPaintTimingDetector().Visualizer()) {
visualizer->DumpImageDebuggingRect(object, mapped_visual_rect,
@@ -383,19 +394,25 @@ void ImageRecordsManager::OnImageLoadedInternal(
void ImageRecordsManager::MaybeUpdateLargestIgnoredImage(
const RecordId& record_id,
- const uint64_t& visual_size) {
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect) {
if (visual_size && (!largest_ignored_image_ ||
visual_size > largest_ignored_image_->first_size)) {
largest_ignored_image_ =
- CreateImageRecord(*record_id.first, record_id.second, visual_size);
+ CreateImageRecord(*record_id.first, record_id.second, visual_size,
+ frame_visual_rect, root_visual_rect);
largest_ignored_image_->load_time = base::TimeTicks::Now();
}
}
void ImageRecordsManager::RecordVisible(const RecordId& record_id,
- const uint64_t& visual_size) {
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect) {
std::unique_ptr<ImageRecord> record =
- CreateImageRecord(*record_id.first, record_id.second, visual_size);
+ CreateImageRecord(*record_id.first, record_id.second, visual_size,
+ frame_visual_rect, root_visual_rect);
size_ordered_set_.insert(record->AsWeakPtr());
visible_images_.insert(record_id, std::move(record));
}
@@ -403,12 +420,14 @@ void ImageRecordsManager::RecordVisible(const RecordId& record_id,
std::unique_ptr<ImageRecord> ImageRecordsManager::CreateImageRecord(
const LayoutObject& object,
const ImageResourceContent* cached_image,
- const uint64_t& visual_size) {
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect) {
DCHECK_GT(visual_size, 0u);
Node* node = object.GetNode();
DOMNodeId node_id = DOMNodeIds::IdForNode(node);
- std::unique_ptr<ImageRecord> record =
- std::make_unique<ImageRecord>(node_id, cached_image, visual_size);
+ std::unique_ptr<ImageRecord> record = std::make_unique<ImageRecord>(
+ node_id, cached_image, visual_size, frame_visual_rect, root_visual_rect);
return record;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
index 7b07678934c..39e0cd41f2b 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -11,7 +11,6 @@
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
@@ -31,12 +30,18 @@ class ImageRecord : public base::SupportsWeakPtr<ImageRecord> {
public:
ImageRecord(DOMNodeId new_node_id,
const ImageResourceContent* new_cached_image,
- uint64_t new_first_size)
+ uint64_t new_first_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect)
: node_id(new_node_id),
cached_image(new_cached_image),
first_size(new_first_size) {
static unsigned next_insertion_index_ = 1;
insertion_index = next_insertion_index_++;
+ if (PaintTimingVisualizer::IsTracingEnabled()) {
+ lcp_rect_info_ = std::make_unique<LCPRectInfo>(
+ frame_visual_rect, RoundedIntRect(root_visual_rect));
+ }
}
ImageRecord() {}
@@ -52,6 +57,8 @@ class ImageRecord : public base::SupportsWeakPtr<ImageRecord> {
base::TimeTicks paint_time = base::TimeTicks();
base::TimeTicks load_time = base::TimeTicks();
bool loaded = false;
+ // LCP rect information, only populated when tracing is enabled.
+ std::unique_ptr<LCPRectInfo> lcp_rect_info_;
};
typedef std::pair<const LayoutObject*, const ImageResourceContent*> RecordId;
@@ -109,7 +116,10 @@ class CORE_EXPORT ImageRecordsManager {
inline void RecordInvisible(const RecordId& record_id) {
invisible_images_.insert(record_id);
}
- void RecordVisible(const RecordId& record_id, const uint64_t& visual_size);
+ void RecordVisible(const RecordId& record_id,
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect);
bool IsRecordedVisibleImage(const RecordId& record_id) const {
return visible_images_.Contains(record_id);
}
@@ -141,7 +151,9 @@ class CORE_EXPORT ImageRecordsManager {
// opacity. May update |largest_ignored_image_| if the new candidate has a
// larger size.
void MaybeUpdateLargestIgnoredImage(const RecordId&,
- const uint64_t& visual_size);
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect);
void ReportLargestIgnoredImage(unsigned current_frame_index);
// Compare the last frame index in queue with the last frame index that has
@@ -183,7 +195,9 @@ class CORE_EXPORT ImageRecordsManager {
std::unique_ptr<ImageRecord> CreateImageRecord(
const LayoutObject& object,
const ImageResourceContent* cached_image,
- const uint64_t& visual_size);
+ const uint64_t& visual_size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect);
inline void QueueToMeasurePaintTime(base::WeakPtr<ImageRecord>& record,
unsigned current_frame_index) {
images_queued_for_paint_time_.push_back(record);
@@ -199,7 +213,7 @@ class CORE_EXPORT ImageRecordsManager {
// This stores the image records, which are ordered by size.
ImageRecordSet size_ordered_set_;
// |ImageRecord|s waiting for paint time are stored in this queue
- // until they get a swap time.
+ // until they get a presentation time.
Deque<base::WeakPtr<ImageRecord>> images_queued_for_paint_time_;
// Map containing timestamps of when LayoutObject::ImageNotifyFinished is
// first called.
@@ -268,12 +282,13 @@ class CORE_EXPORT ImagePaintTimingDetector final
void StopRecordEntries();
inline bool IsRecording() const { return is_recording_; }
inline bool FinishedReportingImages() const {
- return !is_recording_ && num_pending_swap_callbacks_ == 0;
+ return !is_recording_ && num_pending_presentation_callbacks_ == 0;
}
void ResetCallbackManager(PaintTimingCallbackManager* manager) {
callback_manager_ = manager;
}
- void ReportSwapTime(unsigned last_queued_frame_index, base::TimeTicks);
+ void ReportPresentationTime(unsigned last_queued_frame_index,
+ base::TimeTicks);
// Return the candidate.
ImageRecord* UpdateCandidate();
@@ -289,14 +304,15 @@ class CORE_EXPORT ImagePaintTimingDetector final
friend class LargestContentfulPaintCalculatorTest;
void PopulateTraceValue(TracedValue&, const ImageRecord& first_image_paint);
- void RegisterNotifySwapTime();
+ void RegisterNotifyPresentationTime();
void ReportCandidateToTrace(ImageRecord&);
void ReportNoCandidateToTrace();
// Computes the size of an image for the purpose of LargestContentfulPaint,
// downsizing the size of images with low intrinsic size. Images that occupy
// the full viewport are special-cased and this method returns 0 for them so
// that they are not considered valid candidates.
- uint64_t ComputeImageRectSize(const IntRect&,
+ uint64_t ComputeImageRectSize(const IntRect& image_border,
+ const FloatRect& mapped_visual_rect,
const IntSize&,
const PropertyTreeStateOrAlias&,
const LayoutObject&,
@@ -313,9 +329,10 @@ class CORE_EXPORT ImagePaintTimingDetector final
// no effect on recording the loading status.
bool is_recording_ = true;
- // Used to determine how many swap callbacks are pending. In combination with
- // |is_recording|, helps determine whether this detector can be destroyed.
- int num_pending_swap_callbacks_ = 0;
+ // Used to determine how many presentation callbacks are pending. In
+ // combination with |is_recording|, helps determine whether this detector can
+ // be destroyed.
+ int num_pending_presentation_callbacks_ = 0;
// This need to be set whenever changes that can affect the output of
// |FindLargestPaintCandidate| occur during the paint tree walk.
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
index 5ed2b8f4c37..d7f5982f4e3 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -11,7 +11,6 @@
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/web/web_performance.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
@@ -162,6 +161,12 @@ class ImagePaintTimingDetectorTest : public testing::Test,
GetPaintTimingDetector().GetImagePaintTimingDetector()->UpdateCandidate();
}
+ void UpdateCandidateForChildFrame() {
+ GetChildPaintTimingDetector()
+ .GetImagePaintTimingDetector()
+ ->UpdateCandidate();
+ }
+
base::TimeTicks LargestPaintTime() {
return GetPaintTimingDetector().largest_image_paint_time_;
}
@@ -193,7 +198,7 @@ class ImagePaintTimingDetectorTest : public testing::Test,
UpdateAllLifecyclePhases();
SimulatePassOfTime();
while (mock_callback_manager_->CountCallbacks() > 0)
- InvokeSwapTimeCallback(mock_callback_manager_);
+ InvokePresentationTimeCallback(mock_callback_manager_);
}
void SetBodyInnerHTML(const std::string& content) {
@@ -221,17 +226,18 @@ class ImagePaintTimingDetectorTest : public testing::Test,
void InvokeCallback() {
DCHECK_GT(mock_callback_manager_->CountCallbacks(), 0UL);
- InvokeSwapTimeCallback(mock_callback_manager_);
+ InvokePresentationTimeCallback(mock_callback_manager_);
}
void InvokeChildFrameCallback() {
DCHECK_GT(child_mock_callback_manager_->CountCallbacks(), 0UL);
- InvokeSwapTimeCallback(child_mock_callback_manager_);
+ InvokePresentationTimeCallback(child_mock_callback_manager_);
+ UpdateCandidateForChildFrame();
}
- void InvokeSwapTimeCallback(
+ void InvokePresentationTimeCallback(
MockPaintTimingCallbackManager* image_callback_manager) {
- image_callback_manager->InvokeSwapTimeCallback(
+ image_callback_manager->InvokePresentationTimeCallback(
test_task_runner_->NowTicks());
UpdateCandidate();
}
@@ -398,6 +404,96 @@ TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_Candidate) {
bool isOOPIF;
EXPECT_TRUE(arg_dict->GetBoolean("isOOPIF", &isOOPIF));
EXPECT_EQ(false, isOOPIF);
+ int x;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_x", &x));
+ EXPECT_EQ(x, 8);
+ int y;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_y", &y));
+ EXPECT_EQ(y, 8);
+ int width;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_width", &width));
+ EXPECT_EQ(width, 5);
+ int height;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_height", &height));
+ EXPECT_EQ(height, 5);
+ EXPECT_TRUE(arg_dict->GetInteger("root_x", &x));
+ EXPECT_EQ(x, 8);
+ EXPECT_TRUE(arg_dict->GetInteger("root_y", &y));
+ EXPECT_EQ(y, 8);
+ EXPECT_TRUE(arg_dict->GetInteger("root_width", &width));
+ EXPECT_EQ(width, 5);
+ EXPECT_TRUE(arg_dict->GetInteger("root_height", &height));
+ EXPECT_EQ(height, 5);
+}
+
+TEST_P(ImagePaintTimingDetectorTest,
+ LargestImagePaint_TraceEvent_Candidate_Frame) {
+ using trace_analyzer::Query;
+ trace_analyzer::Start("loading");
+ {
+ GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+ SetBodyInnerHTML(R"HTML(
+ <style>iframe { display: block; position: relative; margin-left: 30px; margin-top: 50px; width: 250px; height: 250px;} </style>
+ <iframe> </iframe>
+ )HTML");
+ SetChildBodyInnerHTML(R"HTML(
+ <style>body { margin: 10px;} #target { width: 200px; height: 200px; }
+ </style>
+ <img id="target"></img>
+ )HTML");
+ SetChildFrameImageAndPaint("target", 5, 5);
+ UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
+ InvokeChildFrameCallback();
+ }
+ auto analyzer = trace_analyzer::Stop();
+ trace_analyzer::TraceEventVector events;
+ Query q = Query::EventNameIs("LargestImagePaint::Candidate");
+ analyzer->FindEvents(q, &events);
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ("loading", events[0]->category);
+
+ EXPECT_TRUE(events[0]->HasArg("frame"));
+
+ EXPECT_TRUE(events[0]->HasArg("data"));
+ std::unique_ptr<base::Value> arg;
+ EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg));
+ base::DictionaryValue* arg_dict;
+ EXPECT_TRUE(arg->GetAsDictionary(&arg_dict));
+ DOMNodeId node_id;
+ EXPECT_TRUE(arg_dict->GetInteger("DOMNodeId", &node_id));
+ EXPECT_GT(node_id, 0);
+ int size;
+ EXPECT_TRUE(arg_dict->GetInteger("size", &size));
+ EXPECT_GT(size, 0);
+ DOMNodeId candidate_index;
+ EXPECT_TRUE(arg_dict->GetInteger("candidateIndex", &candidate_index));
+ EXPECT_EQ(candidate_index, 2);
+ bool isMainFrame;
+ EXPECT_TRUE(arg_dict->GetBoolean("isMainFrame", &isMainFrame));
+ EXPECT_EQ(false, isMainFrame);
+ bool isOOPIF;
+ EXPECT_TRUE(arg_dict->GetBoolean("isOOPIF", &isOOPIF));
+ EXPECT_EQ(false, isOOPIF);
+ int x;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_x", &x));
+ EXPECT_EQ(x, 10);
+ int y;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_y", &y));
+ EXPECT_EQ(y, 10);
+ int width;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_width", &width));
+ EXPECT_EQ(width, 200);
+ int height;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_height", &height));
+ EXPECT_EQ(height, 200);
+ EXPECT_TRUE(arg_dict->GetInteger("root_x", &x));
+ EXPECT_GT(x, 40);
+ EXPECT_TRUE(arg_dict->GetInteger("root_y", &y));
+ EXPECT_GT(y, 60);
+ EXPECT_TRUE(arg_dict->GetInteger("root_width", &width));
+ EXPECT_EQ(width, 200);
+ EXPECT_TRUE(arg_dict->GetInteger("root_height", &height));
+ EXPECT_EQ(height, 200);
}
TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_NoCandidate) {
@@ -833,10 +929,11 @@ TEST_P(ImagePaintTimingDetectorTest,
3 * kQuantumOfTime);
}
-// This is to prove that a swap time is assigned only to nodes of the frame who
-// register the swap time. In other words, swap time A should match frame A;
-// swap time B should match frame B.
-TEST_P(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
+// This is to prove that a presentation time is assigned only to nodes of the
+// frame who register the presentation time. In other words, presentation time A
+// should match frame A; presentation time B should match frame B.
+TEST_P(ImagePaintTimingDetectorTest,
+ MatchPresentationTimeToNodesOfDifferentFrames) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
<img height="5" width="5" id="smaller"></img>
@@ -890,7 +987,7 @@ TEST_P(ImagePaintTimingDetectorTest,
EXPECT_EQ(result2, ExperimentalLargestPaintTime());
}
-TEST_P(ImagePaintTimingDetectorTest, OneSwapPromiseForOneFrame) {
+TEST_P(ImagePaintTimingDetectorTest, OnePresentationPromiseForOneFrame) {
SetBodyInnerHTML(R"HTML(
<style>img { display:block }</style>
<div id="parent">
diff --git a/chromium/third_party/blink/renderer/core/paint/image_painter.cc b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
index f2e5450e91a..06c4a02f4c3 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
@@ -41,7 +41,7 @@ namespace {
bool CheckForOversizedImagesPolicy(const LayoutImage& layout_image,
scoped_refptr<Image> image) {
DCHECK(image);
- if (!RuntimeEnabledFeatures::UnoptimizedImagePoliciesEnabled(
+ if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled(
layout_image.GetDocument().GetExecutionContext()))
return false;
@@ -86,7 +86,7 @@ void ImagePainter::Paint(const PaintInfo& paint_info) {
void ImagePainter::PaintAreaElementFocusRing(const PaintInfo& paint_info) {
Document& document = layout_image_.GetDocument();
- if (paint_info.IsPrinting() ||
+ if (document.Printing() ||
!document.GetFrame()->Selection().FrameIsFocusedAndActive())
return;
@@ -205,10 +205,13 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
if (!image || image->IsNull())
return;
- // Do not respect the image orientation when computing the source rect. It is
- // in the un-orientated dimensions.
- FloatRect src_rect(FloatPoint(),
- image->SizeAsFloat(kDoNotRespectImageOrientation));
+ // Get the oriented source rect in order to correctly clip. We check the
+ // default orientation first to avoid expensive transform operations.
+ auto respect_orientation = image->HasDefaultOrientation()
+ ? kDoNotRespectImageOrientation
+ : image_resource.ImageOrientation();
+ FloatRect src_rect(FloatPoint(), image->SizeAsFloat(respect_orientation));
+
// If the content rect requires clipping, adjust |srcRect| and
// |pixelSnappedDestRect| over using a clip.
if (!content_rect.Contains(dest_rect)) {
@@ -221,6 +224,13 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
pixel_snapped_dest_rect = pixel_snapped_content_rect;
}
+ // Undo the image orientation in the source rect because subsequent code
+ // expects the source rect in unoriented image space.
+ if (respect_orientation == kRespectImageOrientation) {
+ src_rect = image->CorrectSrcRectForImageOrientation(
+ image->SizeAsFloat(respect_orientation), src_rect);
+ }
+
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
"data",
inspector_paint_image_event::Data(layout_image_, src_rect,
@@ -251,26 +261,26 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
}
}
- context.DrawImage(
- image.get(), decode_mode, FloatRect(pixel_snapped_dest_rect), &src_rect,
- layout_image_.StyleRef().HasFilterInducingProperty(),
- SkBlendMode::kSrcOver,
- LayoutObject::ShouldRespectImageOrientation(&layout_image_));
-
- ImageResourceContent* image_content = image_resource.CachedImage();
- if ((IsA<HTMLImageElement>(node) || IsA<HTMLVideoElement>(node)) &&
- image_content && image_content->IsLoaded()) {
- LocalDOMWindow* window = layout_image_.GetDocument().domWindow();
- DCHECK(window);
- ImageElementTiming::From(*window).NotifyImagePainted(
- &layout_image_, image_content,
+ context.DrawImage(image.get(), decode_mode,
+ FloatRect(pixel_snapped_dest_rect), &src_rect,
+ layout_image_.StyleRef().HasFilterInducingProperty(),
+ SkBlendMode::kSrcOver, respect_orientation);
+
+ if (ImageResourceContent* image_content = image_resource.CachedImage()) {
+ if ((IsA<HTMLImageElement>(node) || IsA<HTMLVideoElement>(node)) &&
+ image_content->IsLoaded()) {
+ LocalDOMWindow* window = layout_image_.GetDocument().domWindow();
+ DCHECK(window);
+ ImageElementTiming::From(*window).NotifyImagePainted(
+ layout_image_, *image_content,
+ context.GetPaintController().CurrentPaintChunkProperties(),
+ pixel_snapped_dest_rect);
+ }
+ PaintTimingDetector::NotifyImagePaint(
+ layout_image_, image->Size(), *image_content,
context.GetPaintController().CurrentPaintChunkProperties(),
pixel_snapped_dest_rect);
}
- PaintTimingDetector::NotifyImagePaint(
- layout_image_, image->Size(), image_content,
- context.GetPaintController().CurrentPaintChunkProperties(),
- pixel_snapped_dest_rect);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
index 03797b6e666..f389fe7c269 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
+#include "third_party/blink/renderer/core/paint/nine_piece_image_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
@@ -13,6 +14,28 @@
namespace blink {
+PhysicalRect InlineBoxPainterBase::ClipRectForNinePieceImageStrip(
+ const ComputedStyle& style,
+ PhysicalBoxSides sides_to_include,
+ const NinePieceImage& image,
+ const PhysicalRect& paint_rect) {
+ PhysicalRect clip_rect(paint_rect);
+ LayoutRectOutsets outsets = style.ImageOutsets(image);
+ if (sides_to_include.left) {
+ clip_rect.SetX(paint_rect.X() - outsets.Left());
+ clip_rect.SetWidth(paint_rect.Width() + outsets.Left());
+ }
+ if (sides_to_include.right)
+ clip_rect.SetWidth(clip_rect.Width() + outsets.Right());
+ if (sides_to_include.top) {
+ clip_rect.SetY(paint_rect.Y() - outsets.Top());
+ clip_rect.SetHeight(paint_rect.Height() + outsets.Top());
+ }
+ if (sides_to_include.bottom)
+ clip_rect.SetHeight(clip_rect.Height() + outsets.Bottom());
+ return clip_rect;
+}
+
void InlineBoxPainterBase::PaintBoxDecorationBackground(
BoxPainterBase& box_painter,
const PaintInfo& paint_info,
@@ -105,4 +128,44 @@ void InlineBoxPainterBase::PaintFillLayer(BoxPainterBase& box_painter,
paint_rect.size);
}
+void InlineBoxPainterBase::PaintMask(BoxPainterBase& box_painter,
+ const PaintInfo& paint_info,
+ const PhysicalRect& paint_rect,
+ BackgroundImageGeometry& geometry,
+ bool object_has_multiple_boxes,
+ PhysicalBoxSides sides_to_include) {
+ // Figure out if we need to push a transparency layer to render our mask.
+ PaintFillLayers(box_painter, paint_info, Color::kTransparent,
+ style_.MaskLayers(), paint_rect, geometry,
+ object_has_multiple_boxes);
+
+ const auto& mask_nine_piece_image = style_.MaskBoxImage();
+ const auto* mask_box_image = mask_nine_piece_image.GetImage();
+ bool has_box_image = mask_box_image && mask_box_image->CanRender();
+ if (!has_box_image || !mask_box_image->IsLoaded()) {
+ // Don't paint anything while we wait for the image to load.
+ return;
+ }
+
+ // The simple case is where we are the only box for this object. In those
+ // cases only a single call to draw is required.
+ PhysicalRect mask_image_paint_rect = paint_rect;
+ GraphicsContextStateSaver state_saver(paint_info.context, false);
+ if (object_has_multiple_boxes) {
+ // We have a mask image that spans multiple lines.
+ state_saver.Save();
+ // FIXME: What the heck do we do with RTL here? The math we're using is
+ // obviously not right, but it isn't even clear how this should work at all.
+ mask_image_paint_rect =
+ PaintRectForImageStrip(paint_rect, TextDirection::kLtr);
+ FloatRect clip_rect(ClipRectForNinePieceImageStrip(
+ style_, sides_to_include, mask_nine_piece_image, paint_rect));
+ // TODO(chrishtr): this should be pixel-snapped.
+ paint_info.context.Clip(clip_rect);
+ }
+ NinePieceImagePainter::Paint(paint_info.context, image_observer_, *document_,
+ node_, mask_image_paint_rect, style_,
+ mask_nine_piece_image);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
index 25c4be3f7d0..c8df0ca345c 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
@@ -18,6 +18,7 @@ class Color;
class ComputedStyle;
class FillLayer;
class IntRect;
+class NinePieceImage;
struct PaintInfo;
struct PhysicalOffset;
struct PhysicalRect;
@@ -62,6 +63,12 @@ class InlineBoxPainterBase {
const PhysicalRect&,
BackgroundImageGeometry& geometry,
bool object_has_multiple_boxes);
+ void PaintMask(BoxPainterBase&,
+ const PaintInfo&,
+ const PhysicalRect& paint_rect,
+ BackgroundImageGeometry&,
+ bool object_has_multiple_boxes,
+ PhysicalBoxSides sides_to_include);
virtual void PaintNormalBoxShadow(const PaintInfo&,
const ComputedStyle&,
const PhysicalRect& paint_rect) = 0;
@@ -69,6 +76,11 @@ class InlineBoxPainterBase {
const ComputedStyle&,
const PhysicalRect& paint_rect) = 0;
+ static PhysicalRect ClipRectForNinePieceImageStrip(
+ const ComputedStyle& style,
+ PhysicalBoxSides sides_to_include,
+ const NinePieceImage& image,
+ const PhysicalRect& paint_rect);
virtual PhysicalRect PaintRectForImageStrip(
const PhysicalRect&,
TextDirection direction) const = 0;
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
index c0fd60a6c4d..e8e3cf6c761 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
@@ -11,9 +11,7 @@
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
-#include "third_party/blink/renderer/core/paint/nine_piece_image_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -77,35 +75,6 @@ void InlineFlowBoxPainter::Paint(const PaintInfo& paint_info,
}
}
-static PhysicalRect ClipRectForNinePieceImageStrip(
- const InlineFlowBox& box,
- const NinePieceImage& image,
- const PhysicalRect& paint_rect) {
- PhysicalRect clip_rect = paint_rect;
- const ComputedStyle& style = box.GetLineLayoutItem().StyleRef();
- LayoutRectOutsets outsets = style.ImageOutsets(image);
- if (box.IsHorizontal()) {
- clip_rect.SetY(paint_rect.Y() - outsets.Top());
- clip_rect.SetHeight(paint_rect.Height() + outsets.Top() + outsets.Bottom());
- if (box.IncludeLogicalLeftEdge()) {
- clip_rect.SetX(paint_rect.X() - outsets.Left());
- clip_rect.SetWidth(paint_rect.Width() + outsets.Left());
- }
- if (box.IncludeLogicalRightEdge())
- clip_rect.SetWidth(clip_rect.Width() + outsets.Right());
- } else {
- clip_rect.SetX(paint_rect.X() - outsets.Left());
- clip_rect.SetWidth(paint_rect.Width() + outsets.Left() + outsets.Right());
- if (box.IncludeLogicalLeftEdge()) {
- clip_rect.SetY(paint_rect.Y() - outsets.Top());
- clip_rect.SetHeight(paint_rect.Height() + outsets.Top());
- }
- if (box.IncludeLogicalRightEdge())
- clip_rect.SetHeight(clip_rect.Height() + outsets.Bottom());
- }
- return clip_rect;
-}
-
PhysicalRect InlineFlowBoxPainter::PaintRectForImageStrip(
const PhysicalRect& paint_rect,
TextDirection direction) const {
@@ -155,28 +124,26 @@ InlineFlowBoxPainter::GetBorderPaintType(
IntRect& adjusted_clip_rect,
bool object_has_multiple_boxes) const {
adjusted_clip_rect = PixelSnappedIntRect(adjusted_frame_rect);
- if (inline_flow_box_.Parent() &&
- inline_flow_box_.GetLineLayoutItem().StyleRef().HasBorderDecoration()) {
- const NinePieceImage& border_image =
- inline_flow_box_.GetLineLayoutItem().StyleRef().BorderImage();
- StyleImage* border_image_source = border_image.GetImage();
- bool has_border_image =
- border_image_source && border_image_source->CanRender();
- if (has_border_image && !border_image_source->IsLoaded())
- return kDontPaintBorders;
-
- // The simple case is where we either have no border image or we are the
- // only box for this object. In those cases only a single call to draw is
- // required.
- if (!has_border_image || !object_has_multiple_boxes)
- return kPaintBordersWithoutClip;
-
- // We have a border image that spans multiple lines.
- adjusted_clip_rect = PixelSnappedIntRect(ClipRectForNinePieceImageStrip(
- inline_flow_box_, border_image, adjusted_frame_rect));
- return kPaintBordersWithClip;
- }
- return kDontPaintBorders;
+ if (!inline_flow_box_.Parent() || !style_.HasBorderDecoration())
+ return kDontPaintBorders;
+ const NinePieceImage& border_image = style_.BorderImage();
+ StyleImage* border_image_source = border_image.GetImage();
+ bool has_border_image =
+ border_image_source && border_image_source->CanRender();
+ if (has_border_image && !border_image_source->IsLoaded())
+ return kDontPaintBorders;
+
+ // The simple case is where we either have no border image or we are the
+ // only box for this object. In those cases only a single call to draw is
+ // required.
+ if (!has_border_image || !object_has_multiple_boxes)
+ return kPaintBordersWithoutClip;
+
+ // We have a border image that spans multiple lines.
+ adjusted_clip_rect = PixelSnappedIntRect(
+ ClipRectForNinePieceImageStrip(style_, inline_flow_box_.SidesToInclude(),
+ border_image, adjusted_frame_rect));
+ return kPaintBordersWithClip;
}
void InlineFlowBoxPainter::PaintBackgroundBorderShadow(
@@ -229,10 +196,7 @@ void InlineFlowBoxPainter::PaintBackgroundBorderShadow(
void InlineFlowBoxPainter::PaintMask(const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
DCHECK_EQ(PaintPhase::kMask, paint_info.phase);
- const auto& box_model = *To<LayoutBoxModelObject>(
- LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.BoxModelObject()));
- if (!box_model.HasMask() ||
- box_model.StyleRef().Visibility() != EVisibility::kVisible)
+ if (!style_.HasMask() || style_.Visibility() != EVisibility::kVisible)
return;
if (DrawingRecorder::UseCachedDrawingIfPossible(
@@ -243,47 +207,15 @@ void InlineFlowBoxPainter::PaintMask(const PaintInfo& paint_info,
DrawingRecorder recorder(paint_info.context, inline_flow_box_,
paint_info.phase, VisualRect(paint_rect));
- const auto& mask_nine_piece_image = box_model.StyleRef().MaskBoxImage();
- const auto* mask_box_image = mask_nine_piece_image.GetImage();
bool object_has_multiple_boxes = inline_flow_box_.PrevForSameLayoutObject() ||
inline_flow_box_.NextForSameLayoutObject();
-
- // Figure out if we need to push a transparency layer to render our mask.
+ const auto& box_model = *To<LayoutBoxModelObject>(
+ LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.BoxModelObject()));
BackgroundImageGeometry geometry(box_model);
BoxModelObjectPainter box_painter(box_model, &inline_flow_box_);
- PaintFillLayers(box_painter, paint_info, Color::kTransparent,
- box_model.StyleRef().MaskLayers(), paint_rect, geometry,
- object_has_multiple_boxes);
-
- bool has_box_image = mask_box_image && mask_box_image->CanRender();
- if (!has_box_image || !mask_box_image->IsLoaded()) {
- // Don't paint anything while we wait for the image to load.
- return;
- }
-
- // The simple case is where we are the only box for this object. In those
- // cases only a single call to draw is required.
- if (!object_has_multiple_boxes) {
- NinePieceImagePainter::Paint(paint_info.context, box_model,
- box_model.GetDocument(), GetNode(&box_model),
- paint_rect, box_model.StyleRef(),
- mask_nine_piece_image);
- } else {
- // We have a mask image that spans multiple lines.
- // FIXME: What the heck do we do with RTL here? The math we're using is
- // obviously not right, but it isn't even clear how this should work at all.
- PhysicalRect image_strip_paint_rect =
- PaintRectForImageStrip(paint_rect, TextDirection::kLtr);
- FloatRect clip_rect(ClipRectForNinePieceImageStrip(
- inline_flow_box_, mask_nine_piece_image, paint_rect));
- GraphicsContextStateSaver state_saver(paint_info.context);
- // TODO(chrishtr): this should be pixel-snapped.
- paint_info.context.Clip(clip_rect);
- NinePieceImagePainter::Paint(paint_info.context, box_model,
- box_model.GetDocument(), GetNode(&box_model),
- image_strip_paint_rect, box_model.StyleRef(),
- mask_nine_piece_image);
- }
+ InlineBoxPainterBase::PaintMask(box_painter, paint_info, paint_rect, geometry,
+ object_has_multiple_boxes,
+ inline_flow_box_.SidesToInclude());
}
// This method should not be needed. See crbug.com/530659.
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_painter.cc
index 077e9b1fad9..99533680b06 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_painter.cc
@@ -6,10 +6,8 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/paint/line_box_list_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 43a3834692e..8653ca0ef2f 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
+#include "third_party/blink/renderer/core/paint/selection_bounds_recorder.h"
#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
#include "third_party/blink/renderer/core/paint/text_painter.h"
#include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
@@ -34,6 +35,8 @@
namespace blink {
+class HTMLAnchorElement;
+
namespace {
// If an inline text box is truncated by an ellipsis, text box markers paint
@@ -131,7 +134,8 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
DCHECK(!ShouldPaintSelfOutline(paint_info.phase) &&
!ShouldPaintDescendantOutlines(paint_info.phase));
- bool is_printing = paint_info.IsPrinting();
+ bool is_printing =
+ inline_text_box_.GetLineLayoutItem().GetDocument().Printing();
// Determine whether or not we're selected.
bool have_selection = !is_printing &&
@@ -150,18 +154,6 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
physical_overflow.Move(paint_offset);
IntRect visual_rect = EnclosingIntRect(physical_overflow);
- // The text clip phase already has a DrawingRecorder. Text clips are initiated
- // only in BoxPainter::PaintFillLayer, which is already within a
- // DrawingRecorder.
- base::Optional<DrawingRecorder> recorder;
- if (paint_info.phase != PaintPhase::kTextClip) {
- if (DrawingRecorder::UseCachedDrawingIfPossible(
- paint_info.context, inline_text_box_, paint_info.phase))
- return;
- recorder.emplace(paint_info.context, inline_text_box_, paint_info.phase,
- visual_rect);
- }
-
GraphicsContext& context = paint_info.context;
PhysicalOffset box_origin =
inline_text_box_.PhysicalLocation() + paint_offset;
@@ -179,6 +171,49 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
PhysicalSize(inline_text_box_.LogicalWidth(),
inline_text_box_.LogicalHeight()));
+ base::Optional<SelectionBoundsRecorder> selection_recorder;
+ if (have_selection && paint_info.phase == PaintPhase::kForeground &&
+ !is_printing) {
+ const FrameSelection& frame_selection =
+ InlineLayoutObject().GetFrame()->Selection();
+ SelectionState selection_state =
+ frame_selection.ComputeLayoutSelectionStateForInlineTextBox(
+ inline_text_box_);
+ if (SelectionBoundsRecorder::ShouldRecordSelection(frame_selection,
+ selection_state)) {
+ PhysicalRect selection_rect =
+ GetSelectionRect<InlineTextBoxPainter::PaintOptions::kNormal>(
+ context, box_rect, style_to_use, style_to_use.GetFont());
+
+ TextDirection direction = inline_text_box_.IsLeftToRightDirection()
+ ? TextDirection::kLtr
+ : TextDirection::kRtl;
+ // We need to account for vertical writing mode rotation - for the
+ // actual painting of the selection_rect, this is done below by
+ // concatenating a rotation matrix on the context.
+ if (!style_to_use.IsHorizontalWritingMode()) {
+ FloatRect rotated_selection =
+ TextPainterBase::Rotation(box_rect, TextPainterBase::kClockwise)
+ .MapRect(static_cast<FloatRect>(selection_rect));
+ selection_rect = PhysicalRect::EnclosingRect(rotated_selection);
+ }
+ selection_recorder.emplace(selection_state, selection_rect,
+ context.GetPaintController(), direction,
+ style_to_use.GetWritingMode());
+ }
+ }
+
+ // The text clip phase already has a DrawingRecorder. Text clips are initiated
+ // only in BoxPainter::PaintFillLayer, which is already within a
+ // DrawingRecorder.
+ base::Optional<DrawingRecorder> recorder;
+ if (paint_info.phase != PaintPhase::kTextClip) {
+ if (DrawingRecorder::UseCachedDrawingIfPossible(context, inline_text_box_,
+ paint_info.phase))
+ return;
+ recorder.emplace(context, inline_text_box_, paint_info.phase, visual_rect);
+ }
+
unsigned length = inline_text_box_.Len();
const String& layout_item_string =
inline_text_box_.GetLineLayoutItem().GetText();
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter_test.cc
index 9754276f0a8..1b505e57d1e 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter_test.cc
@@ -6,6 +6,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
using testing::ElementsAre;
@@ -27,4 +28,64 @@ TEST_P(InlineTextBoxPainterTest, LineBreak) {
EXPECT_EQ(6u, ContentDisplayItems().size());
}
+class InlineTextBoxPainterNonNGTest : public PaintControllerPaintTest,
+ public ScopedLayoutNGForTest {
+ public:
+ InlineTextBoxPainterNonNGTest() : ScopedLayoutNGForTest(false) {}
+};
+
+INSTANTIATE_PAINT_TEST_SUITE_P(InlineTextBoxPainterNonNGTest);
+
+TEST_P(InlineTextBoxPainterNonNGTest, RecordedSelectionAll) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ SetBodyInnerHTML("<span>A<br>B<br>C</span>");
+
+ GetDocument().GetFrame()->Selection().SetHandleVisibleForTesting();
+ GetDocument().GetFrame()->Selection().SelectAll();
+ UpdateAllLifecyclePhasesForTest();
+
+ auto chunks = ContentPaintChunks();
+ EXPECT_EQ(chunks.size(), 1u);
+ EXPECT_TRUE(chunks.begin()->layer_selection_data->start.has_value());
+ EXPECT_TRUE(chunks.begin()->layer_selection_data->end.has_value());
+ PaintedSelectionBound start =
+ chunks.begin()->layer_selection_data->start.value();
+ EXPECT_EQ(start.type, gfx::SelectionBound::LEFT);
+ EXPECT_EQ(start.edge_start, IntPoint(8, 8));
+ EXPECT_EQ(start.edge_end, IntPoint(8, 9));
+
+ PaintedSelectionBound end = chunks.begin()->layer_selection_data->end.value();
+ EXPECT_EQ(end.type, gfx::SelectionBound::RIGHT);
+ EXPECT_EQ(end.edge_start, IntPoint(9, 10));
+ EXPECT_EQ(end.edge_end, IntPoint(9, 11));
+}
+
+TEST_P(InlineTextBoxPainterNonNGTest, RecordedSelectionMultiline) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ GetDocument().GetFrame()->Selection().SetSelectionAndEndTyping(
+ SelectionSample::SetSelectionText(
+ GetDocument().body(),
+ "<div style='white-space:pre'>f^oo\nbar\nb|az</div>"));
+ GetDocument().GetFrame()->Selection().SetHandleVisibleForTesting();
+ UpdateAllLifecyclePhasesForTest();
+
+ auto chunks = ContentPaintChunks();
+ EXPECT_EQ(chunks.size(), 1u);
+ EXPECT_TRUE(chunks.begin()->layer_selection_data->start.has_value());
+ EXPECT_TRUE(chunks.begin()->layer_selection_data->end.has_value());
+ PaintedSelectionBound start =
+ chunks.begin()->layer_selection_data->start.value();
+ EXPECT_EQ(start.type, gfx::SelectionBound::LEFT);
+ EXPECT_EQ(start.edge_start, IntPoint(8, 8));
+ EXPECT_EQ(start.edge_end, IntPoint(8, 9));
+
+ PaintedSelectionBound end = chunks.begin()->layer_selection_data->end.value();
+ EXPECT_EQ(end.type, gfx::SelectionBound::RIGHT);
+ EXPECT_EQ(end.edge_start, IntPoint(9, 10));
+ EXPECT_EQ(end.edge_end, IntPoint(9, 11));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
index 6e8011d4ff4..8614bf79f0b 100644
--- a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator_test.cc
@@ -80,10 +80,10 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
.UpdateLargestContentfulPaintCandidate();
}
- void SimulateContentSwapPromise() {
- mock_text_callback_manager_->InvokeSwapTimeCallback(
+ void SimulateContentPresentationPromise() {
+ mock_text_callback_manager_->InvokePresentationTimeCallback(
simulated_clock_.NowTicks());
- mock_image_callback_manager_->InvokeSwapTimeCallback(
+ mock_image_callback_manager_->InvokePresentationTimeCallback(
simulated_clock_.NowTicks());
// Outside the tests, this is invoked by
// |PaintTimingCallbackManagerImpl::ReportPaintTime|.
@@ -91,9 +91,9 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
}
// Outside the tests, the text callback and the image callback are run
- // together, as in |SimulateContentSwapPromise|.
- void SimulateImageSwapPromise() {
- mock_image_callback_manager_->InvokeSwapTimeCallback(
+ // together, as in |SimulateContentPresentationPromise|.
+ void SimulateImagePresentationPromise() {
+ mock_image_callback_manager_->InvokePresentationTimeCallback(
simulated_clock_.NowTicks());
// Outside the tests, this is invoked by
// |PaintTimingCallbackManagerImpl::ReportPaintTime|.
@@ -101,9 +101,9 @@ class LargestContentfulPaintCalculatorTest : public RenderingTest {
}
// Outside the tests, the text callback and the image callback are run
- // together, as in |SimulateContentSwapPromise|.
- void SimulateTextSwapPromise() {
- mock_text_callback_manager_->InvokeSwapTimeCallback(
+ // together, as in |SimulateContentPresentationPromise|.
+ void SimulateTextPresentationPromise() {
+ mock_text_callback_manager_->InvokePresentationTimeCallback(
simulated_clock_.NowTicks());
// Outside the tests, this is invoked by
// |PaintTimingCallbackManagerImpl::ReportPaintTime|.
@@ -130,7 +130,7 @@ TEST_F(LargestContentfulPaintCalculatorTest, SingleImage) {
)HTML");
SetImage("target", 100, 150);
UpdateAllLifecyclePhasesForTest();
- SimulateImageSwapPromise();
+ SimulateImagePresentationPromise();
EXPECT_EQ(LargestReportedSize(), 15000u);
EXPECT_EQ(CountCandidates(), 1u);
@@ -142,7 +142,7 @@ TEST_F(LargestContentfulPaintCalculatorTest, SingleText) {
<p>This is some text</p>
)HTML");
UpdateAllLifecyclePhasesForTest();
- SimulateTextSwapPromise();
+ SimulateTextPresentationPromise();
EXPECT_GT(LargestReportedSize(), 0u);
EXPECT_EQ(CountCandidates(), 1u);
@@ -156,10 +156,10 @@ TEST_F(LargestContentfulPaintCalculatorTest, ImageLargerText) {
)HTML");
SetImage("target", 3, 3);
UpdateAllLifecyclePhasesForTest();
- SimulateImageSwapPromise();
+ SimulateImagePresentationPromise();
EXPECT_EQ(LargestReportedSize(), 9u);
EXPECT_EQ(CountCandidates(), 1u);
- SimulateTextSwapPromise();
+ SimulateTextPresentationPromise();
EXPECT_GT(LargestReportedSize(), 9u);
EXPECT_EQ(CountCandidates(), 2u);
@@ -173,10 +173,10 @@ TEST_F(LargestContentfulPaintCalculatorTest, ImageSmallerText) {
)HTML");
SetImage("target", 100, 200);
UpdateAllLifecyclePhasesForTest();
- SimulateImageSwapPromise();
+ SimulateImagePresentationPromise();
EXPECT_EQ(LargestReportedSize(), 20000u);
EXPECT_EQ(CountCandidates(), 1u);
- SimulateTextSwapPromise();
+ SimulateTextPresentationPromise();
// Text should not be reported, since it is smaller than the image.
EXPECT_EQ(LargestReportedSize(), 20000u);
@@ -191,7 +191,7 @@ TEST_F(LargestContentfulPaintCalculatorTest, TextLargerImage) {
)HTML");
SetImage("target", 100, 200);
UpdateAllLifecyclePhasesForTest();
- SimulateContentSwapPromise();
+ SimulateContentPresentationPromise();
EXPECT_EQ(LargestReportedSize(), 20000u);
EXPECT_EQ(CountCandidates(), 1u);
@@ -205,7 +205,7 @@ TEST_F(LargestContentfulPaintCalculatorTest, TextSmallerImage) {
)HTML");
SetImage("target", 3, 3);
UpdateAllLifecyclePhasesForTest();
- SimulateContentSwapPromise();
+ SimulateContentPresentationPromise();
// Image should not be reported, since it is smaller than the text.
EXPECT_GT(LargestReportedSize(), 9u);
@@ -222,8 +222,8 @@ TEST_F(LargestContentfulPaintCalculatorTest, LargestImageRemoved) {
SetImage("large", 100, 200);
SetImage("small", 3, 3);
UpdateAllLifecyclePhasesForTest();
- SimulateImageSwapPromise();
- SimulateTextSwapPromise();
+ SimulateImagePresentationPromise();
+ SimulateTextPresentationPromise();
// Image is larger than the text.
EXPECT_EQ(LargestReportedSize(), 20000u);
EXPECT_EQ(CountCandidates(), 1u);
@@ -248,11 +248,11 @@ TEST_F(LargestContentfulPaintCalculatorTest, LargestTextRemoved) {
)HTML");
SetImage("medium", 10, 5);
UpdateAllLifecyclePhasesForTest();
- SimulateImageSwapPromise();
- SimulateTextSwapPromise();
+ SimulateImagePresentationPromise();
+ SimulateTextPresentationPromise();
// Test is larger than the image.
EXPECT_GT(LargestReportedSize(), 50u);
- // Image swap occurred first, so we have would have two candidates.
+ // Image presentation occurred first, so we have would have two candidates.
EXPECT_EQ(CountCandidates(), 2u);
GetDocument().getElementById("large")->remove();
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index f987f728017..dce23b7543b 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -33,7 +33,6 @@
#include "cc/layers/picture_layer.h"
#include "cc/paint/display_item_list.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
@@ -42,7 +41,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -154,7 +153,7 @@ LinkHighlightImpl::LinkHighlightFragment::~LinkHighlightFragment() {
layer_->ClearClient();
}
-gfx::Rect LinkHighlightImpl::LinkHighlightFragment::PaintableRegion() {
+gfx::Rect LinkHighlightImpl::LinkHighlightFragment::PaintableRegion() const {
return gfx::Rect(layer_->bounds());
}
@@ -295,8 +294,7 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
// NGFragmentItem to renderer rounded rect even if nested inline, e.g.
// <a>ABC<b>DEF</b>GHI</a>.
// See gesture-tapHighlight-simple-nested.html
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
- use_rounded_rects && object->IsLayoutInline() &&
+ if (use_rounded_rects && object->IsLayoutInline() &&
object->IsInLayoutNGInlineFormattingContext()) {
NGInlineCursor cursor;
cursor.MoveTo(*object);
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
index d4a41d2a5db..d4f6df1677a 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
@@ -101,7 +101,7 @@ class CORE_EXPORT LinkHighlightImpl final : public CompositorAnimationDelegate,
private:
// cc::ContentLayerClient implementation.
- gfx::Rect PaintableRegion() override;
+ gfx::Rect PaintableRegion() const override;
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() override;
bool FillsBoundsCompletely() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
index 603dd4ad850..3f771abdbb8 100644
--- a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
@@ -4,12 +4,14 @@
#include "third_party/blink/renderer/core/paint/list_marker_painter.h"
+#include "third_party/blink/renderer/core/css/counter_style.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/list_marker.h"
#include "third_party/blink/renderer/core/layout/list_marker_text.h"
#include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
+#include "third_party/blink/renderer/core/paint/details_marker_painter.h"
#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
@@ -24,8 +26,10 @@ namespace blink {
void ListMarkerPainter::PaintSymbol(const PaintInfo& paint_info,
const LayoutObject* object,
const ComputedStyle& style,
- const IntRect& marker) {
+ const LayoutRect& marker) {
DCHECK(object);
+ DCHECK(style.GetListStyleType());
+ DCHECK(style.GetListStyleType()->IsCounterStyle());
GraphicsContext& context = paint_info.context;
ScopedDarkModeElementRoleOverride list_symbol(
&context, DarkModeFilter::ElementRole::kListSymbol);
@@ -38,19 +42,22 @@ void ListMarkerPainter::PaintSymbol(const PaintInfo& paint_info,
context.SetStrokeColor(color);
context.SetStrokeStyle(kSolidStroke);
context.SetStrokeThickness(1.0f);
- switch (style.ListStyleType()) {
- case EListStyleType::kDisc:
- context.FillEllipse(FloatRect(marker));
- break;
- case EListStyleType::kCircle:
- context.StrokeEllipse(FloatRect(marker));
- break;
- case EListStyleType::kSquare:
- context.FillRect(marker);
- break;
- default:
- NOTREACHED();
- break;
+ IntRect snapped_rect = PixelSnappedIntRect(marker);
+ const AtomicString& type = style.GetListStyleType()->GetCounterStyleName();
+ if (type == "disc") {
+ context.FillEllipse(FloatRect(snapped_rect));
+ } else if (type == "circle") {
+ context.StrokeEllipse(FloatRect(snapped_rect));
+ } else if (type == "square") {
+ context.FillRect(snapped_rect);
+ } else if (type == "disclosure-open" || type == "disclosure-closed") {
+ Path path = DetailsMarkerPainter::GetCanonicalPath(
+ style, type == "disclosure-open");
+ path.Transform(AffineTransform().Scale(marker.Width(), marker.Height()));
+ path.Translate(FloatSize(marker.X(), marker.Y()));
+ context.FillPath(path);
+ } else {
+ NOTREACHED();
}
}
@@ -103,7 +110,7 @@ void ListMarkerPainter::Paint(const PaintInfo& paint_info) {
if (style_category == ListMarker::ListStyleCategory::kSymbol) {
PaintSymbol(paint_info, &layout_list_marker_,
- layout_list_marker_.StyleRef(), PixelSnappedIntRect(marker));
+ layout_list_marker_.StyleRef(), marker);
return;
}
@@ -166,27 +173,41 @@ void ListMarkerPainter::Paint(const PaintInfo& paint_info) {
return;
}
- const UChar suffix =
- list_marker_text::Suffix(layout_list_marker_.StyleRef().ListStyleType(),
- layout_list_marker_.ListItem()->Value());
- UChar suffix_str[2] = {suffix, static_cast<UChar>(' ')};
+ String prefix_str;
+ String suffix_str;
+ if (RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()) {
+ const CounterStyle& counter_style = layout_list_marker_.GetCounterStyle();
+ prefix_str = counter_style.GetPrefix();
+ suffix_str = counter_style.GetSuffix();
+ } else {
+ UChar chars[] = {
+ list_marker_text::Suffix(layout_list_marker_.StyleRef().ListStyleType(),
+ layout_list_marker_.ListItem()->Value()),
+ ' '};
+ suffix_str = String(chars, 2);
+ }
+ TextRun prefix_run =
+ ConstructTextRun(font, prefix_str, layout_list_marker_.StyleRef(),
+ layout_list_marker_.StyleRef().Direction());
+ TextRunPaintInfo prefix_run_info(prefix_run);
TextRun suffix_run =
- ConstructTextRun(font, suffix_str, 2, layout_list_marker_.StyleRef(),
+ ConstructTextRun(font, suffix_str, layout_list_marker_.StyleRef(),
layout_list_marker_.StyleRef().Direction());
TextRunPaintInfo suffix_run_info(suffix_run);
if (layout_list_marker_.StyleRef().IsLeftToRightDirection()) {
+ context.DrawText(font, prefix_run_info, text_origin, kInvalidDOMNodeId);
+ text_origin += FloatSize(IntSize(font.Width(prefix_run), 0));
context.DrawText(font, text_run_paint_info, text_origin, kInvalidDOMNodeId);
- context.DrawText(font, suffix_run_info,
- text_origin + FloatSize(IntSize(font.Width(text_run), 0)),
- kInvalidDOMNodeId);
- } else {
+ text_origin += FloatSize(IntSize(font.Width(text_run), 0));
context.DrawText(font, suffix_run_info, text_origin, kInvalidDOMNodeId);
+ } else {
// Is the truncation to IntSize below meaningful or a bug?
- context.DrawText(
- font, text_run_paint_info,
- text_origin + FloatSize(IntSize(font.Width(suffix_run), 0)),
- kInvalidDOMNodeId);
+ context.DrawText(font, suffix_run_info, text_origin, kInvalidDOMNodeId);
+ text_origin += FloatSize(IntSize(font.Width(suffix_run), 0));
+ context.DrawText(font, text_run_paint_info, text_origin, kInvalidDOMNodeId);
+ text_origin += FloatSize(IntSize(font.Width(text_run), 0));
+ context.DrawText(font, prefix_run_info, text_origin, kInvalidDOMNodeId);
}
// TODO(npm): Check that there are non-whitespace characters. See
// crbug.com/788444.
diff --git a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.h b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.h
index 86c2023c7d2..830de9d0d94 100644
--- a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.h
@@ -11,9 +11,9 @@ namespace blink {
struct PaintInfo;
class ComputedStyle;
-class IntRect;
class LayoutListMarker;
class LayoutObject;
+class LayoutRect;
class ListMarkerPainter {
STACK_ALLOCATED();
@@ -27,7 +27,7 @@ class ListMarkerPainter {
static void PaintSymbol(const PaintInfo&,
const LayoutObject*,
const ComputedStyle&,
- const IntRect&);
+ const LayoutRect&);
private:
const LayoutListMarker& layout_list_marker_;
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 9b44f5cf337..4cbbccb09fe 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -17,9 +17,9 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
@@ -30,7 +30,6 @@
#include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_table_painters.h"
#include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
@@ -172,32 +171,6 @@ bool HitTestCulledInlineAncestors(
bool HitTestCulledInlineAncestors(
HitTestResult& result,
- const NGInlineCursor& parent_cursor,
- const NGPaintFragment& fragment,
- const NGInlineCursorPosition& previous_sibling,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset) {
- DCHECK(fragment.Parent());
- DCHECK(fragment.PhysicalFragment().IsInline());
- // Ellipsis can appear under a different parent from the ellipsized object
- // that it can confuse culled inline logic.
- if (UNLIKELY(fragment.IsEllipsis()))
- return false;
- const NGPaintFragment& parent = *fragment.Parent();
- // To be passed as |accumulated_offset| to LayoutInline::HitTestCulledInline,
- // where it equals the physical offset of the containing block in paint layer.
- const PhysicalOffset fallback_accumulated_offset =
- physical_offset - fragment.OffsetInContainerBlock();
- const LayoutObject* limit_layout_object =
- parent.PhysicalFragment().IsLineBox() ? parent.Parent()->GetLayoutObject()
- : parent.GetLayoutObject();
- return HitTestCulledInlineAncestors(
- result, parent_cursor, fragment.GetLayoutObject(), limit_layout_object,
- previous_sibling, hit_test_location, fallback_accumulated_offset);
-}
-
-bool HitTestCulledInlineAncestors(
- HitTestResult& result,
const NGPhysicalBoxFragment& container,
const NGInlineCursor& parent_cursor,
const NGFragmentItem& item,
@@ -211,7 +184,7 @@ bool HitTestCulledInlineAncestors(
// To be passed as |accumulated_offset| to LayoutInline::HitTestCulledInline,
// where it equals the physical offset of the containing block in paint layer.
const PhysicalOffset fallback_accumulated_offset =
- physical_offset - item.OffsetInContainerBlock();
+ physical_offset - item.OffsetInContainerFragment();
return HitTestCulledInlineAncestors(
result, parent_cursor, item.GetLayoutObject(),
// Limit the traversal up to the container fragment, or its container if
@@ -231,10 +204,13 @@ bool HitTestCulledInlineAncestors(
// |NGBoxFragmentPainter| for all fragments, and we still want this
// oprimization.
bool FragmentRequiresLegacyFallback(const NGPhysicalFragment& fragment) {
- // Fallback to LayoutObject if this is a root of NG block layout.
- // If this box is for this painter, LayoutNGBlockFlow will call this back.
- // Otherwise it calls legacy painters.
- return fragment.IsFormattingContextRoot();
+ // If |fragment| is |IsFormattingContextRoot|, it may be legacy.
+ // Avoid falling back to |LayoutObject| if |CanTraverse|, because it
+ // cannot handle block fragmented objects.
+ if (!fragment.IsFormattingContextRoot() || fragment.CanTraverse())
+ return false;
+ DCHECK(!To<NGPhysicalBoxFragment>(&fragment)->BreakToken());
+ return true;
}
// Returns a vector of backplates that surround the paragraphs of text within
@@ -276,23 +252,6 @@ Vector<PhysicalRect> BuildBackplate(NGInlineCursor* descendants,
// backplate should only be painted for inline text and not for atomic
// inlines.
for (; *descendants; descendants->MoveToNext()) {
- if (const NGPaintFragment* child = descendants->CurrentPaintFragment()) {
- const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
- if (child_fragment.IsHiddenForPaint() || child_fragment.IsFloating())
- continue;
- if (auto* text_fragment =
- DynamicTo<NGPhysicalTextFragment>(child_fragment)) {
- if (text_fragment->IsLineBreak()) {
- backplates.AddLineBreak();
- continue;
- }
-
- PhysicalRect box_rect(child->OffsetInContainerBlock() + paint_offset,
- child->Size());
- backplates.AddTextRect(box_rect);
- }
- continue;
- }
if (const NGFragmentItem* child_item = descendants->CurrentItem()) {
if (child_item->IsHiddenForPaint())
continue;
@@ -303,7 +262,7 @@ Vector<PhysicalRect> BuildBackplate(NGInlineCursor* descendants,
}
PhysicalRect box_rect(
- child_item->OffsetInContainerBlock() + paint_offset,
+ child_item->OffsetInContainerFragment() + paint_offset,
child_item->Size());
backplates.AddTextRect(box_rect);
}
@@ -355,18 +314,10 @@ bool NodeAtPointInFragment(const NGPhysicalBoxFragment& fragment,
void UpdateHitTestResult(HitTestResult& result,
const NGPhysicalBoxFragment& fragment,
PhysicalOffset offset) {
- Node* node = fragment.NodeForHitTest();
- if (!node)
+ if (result.InnerNode())
return;
-
- // We may already have set an inner node, but not a box fragment, if the inner
- // node was text or non-atomic inline content. Set the containing box fragment
- // now.
- if (!result.BoxFragment())
- result.SetBoxFragment(&fragment);
-
- if (!result.InnerNode())
- result.SetNodeAndPosition(node, offset);
+ if (Node* node = fragment.NodeForHitTest())
+ result.SetNodeAndPosition(node, &fragment, offset);
}
// Return an ID for this fragmentainer, which is unique within the fragmentation
@@ -381,8 +332,6 @@ unsigned FragmentainerUniqueIdentifier(const NGPhysicalBoxFragment& fragment) {
} // anonymous namespace
PhysicalRect NGBoxFragmentPainter::SelfInkOverflow() const {
- if (paint_fragment_)
- return paint_fragment_->SelfInkOverflow();
if (box_item_)
return box_item_->SelfInkOverflow();
const NGPhysicalFragment& fragment = PhysicalFragment();
@@ -535,9 +484,9 @@ void NGBoxFragmentPainter::PaintObject(
const PhysicalOffset& paint_offset,
bool suppress_box_decoration_background) {
const PaintPhase paint_phase = paint_info.phase;
- const NGPhysicalBoxFragment& physical_box_fragment = PhysicalFragment();
- const ComputedStyle& style = box_fragment_.Style();
- bool is_visible = IsVisibleToPaint(physical_box_fragment, style);
+ const NGPhysicalBoxFragment& fragment = PhysicalFragment();
+ const ComputedStyle& style = fragment.Style();
+ bool is_visible = IsVisibleToPaint(fragment, style);
if (ShouldPaintSelfBlockBackground(paint_phase)) {
if (is_visible) {
PaintBoxDecorationBackground(paint_info, paint_offset,
@@ -555,21 +504,20 @@ void NGBoxFragmentPainter::PaintObject(
if (paint_phase == PaintPhase::kForeground) {
if (paint_info.ShouldAddUrlMetadata()) {
- NGFragmentPainter(box_fragment_, GetDisplayItemClient())
+ NGFragmentPainter(fragment, GetDisplayItemClient())
.AddURLRectIfNeeded(paint_info, paint_offset);
}
- if (is_visible && box_fragment_.HasExtraMathMLPainting())
- NGMathMLPainter(box_fragment_).Paint(paint_info, paint_offset);
+ if (is_visible && fragment.HasExtraMathMLPainting())
+ NGMathMLPainter(fragment).Paint(paint_info, paint_offset);
}
// Paint children.
if (paint_phase != PaintPhase::kSelfOutlineOnly &&
- (!physical_box_fragment.Children().empty() ||
- physical_box_fragment.HasItems() || inline_box_cursor_) &&
+ (!fragment.Children().empty() || fragment.HasItems() ||
+ inline_box_cursor_) &&
!paint_info.DescendantPaintingBlocked()) {
if (is_visible && UNLIKELY(paint_phase == PaintPhase::kForeground &&
- box_fragment_.IsCSSBox() &&
- box_fragment_.Style().HasColumnRule()))
+ fragment.IsCSSBox() && style.HasColumnRule()))
PaintColumnRules(paint_info, paint_offset);
if (paint_phase != PaintPhase::kFloat) {
@@ -581,72 +529,45 @@ void NGBoxFragmentPainter::PaintObject(
DCHECK(box_item_);
NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
const PhysicalOffset paint_offset_to_inline_formatting_context =
- paint_offset - box_item_->OffsetInContainerBlock();
+ paint_offset - box_item_->OffsetInContainerFragment();
PaintInlineItems(paint_info.ForDescendants(),
paint_offset_to_inline_formatting_context,
- box_item_->OffsetInContainerBlock(), &descendants);
+ box_item_->OffsetInContainerFragment(), &descendants);
} else if (items_) {
- if (physical_box_fragment.IsBlockFlow()) {
+ if (fragment.IsBlockFlow()) {
PaintBlockFlowContents(paint_info, paint_offset);
} else {
- DCHECK(physical_box_fragment.IsInlineBox());
- NGInlineCursor cursor(physical_box_fragment, *items_);
+ DCHECK(fragment.IsInlineBox());
+ NGInlineCursor cursor(fragment, *items_);
PaintInlineItems(paint_info.ForDescendants(), paint_offset,
PhysicalOffset(), &cursor);
}
- } else if (!physical_box_fragment.IsInlineFormattingContext()) {
+ } else if (!fragment.IsInlineFormattingContext()) {
PaintBlockChildren(paint_info, paint_offset);
- } else if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // This is the NGPaintFragment code path. We need the check for
- // !LayoutNGFragmentItemEnabled above, since it's possible to come up
- // with an empty (item-less) box that's in an inline formatting context,
- // even when that feature is enabled. This happens when an inline-level
- // float descendant gets block-fragmented. When resuming float layout in
- // the next fragment, the float will no longer be associated with a line
- // or a fragment item (this is an implementation detail), but rather a
- // regular box fragment child of this container. If there's no inline
- // content to put in that fragment, there'll be no items, just the box
- // fragment for the float. In that case, we have no work to do here.
- //
- // <div style="columns:2; column-fill:auto; height:100px;">
- // <div id="child">
- // <div id="fl" style="float:left; height:150px;"></div>
- // text
- // </div>
- // </div>
- //
- // #child will get two fragments. The first one will contain a line with
- // items for a 100px tall #fl fragment, and the text. The second
- // fragment of #child will just contain a regular box fragment child for
- // the remaining 50px of #fl - no items (all in-flow content fits in the
- // first fragment).
- DCHECK(paint_fragment_);
- if (physical_box_fragment.IsBlockFlow()) {
- PaintBlockFlowContents(paint_info, paint_offset);
- } else if (ShouldPaintDescendantOutlines(paint_info.phase)) {
- // TODO(kojii): |PaintInlineChildrenOutlines()| should do the work
- // instead. Legacy does so, and is more efficient. But NG outline
- // logic currently depends on |PaintInlineChildren()|.
- PaintInlineChildren(paint_fragment_->Children(),
- paint_info.ForDescendants(), paint_offset);
- } else {
- PaintInlineChildren(paint_fragment_->Children(), paint_info,
- paint_offset);
- }
}
}
if (paint_phase == PaintPhase::kFloat ||
paint_phase == PaintPhase::kSelectionDragImage ||
paint_phase == PaintPhase::kTextClip) {
- if (physical_box_fragment.HasFloatingDescendantsForPaint())
+ if (fragment.HasFloatingDescendantsForPaint())
PaintFloats(paint_info);
}
}
- if (is_visible && ShouldPaintSelfOutline(paint_phase)) {
- NGFragmentPainter(box_fragment_, GetDisplayItemClient())
- .PaintOutline(paint_info, paint_offset);
+ if (!is_visible)
+ return;
+ if (ShouldPaintSelfOutline(paint_phase)) {
+ if (NGOutlineUtils::HasPaintedOutline(style, fragment.GetNode())) {
+ NGFragmentPainter(fragment, GetDisplayItemClient())
+ .PaintOutline(paint_info, paint_offset, style);
+ }
+ } else if (ShouldPaintDescendantOutlines(paint_phase)) {
+ if (const ComputedStyle* outline_style =
+ fragment.StyleForContinuationOutline()) {
+ NGFragmentPainter(fragment, GetDisplayItemClient())
+ .PaintOutline(paint_info, paint_offset, *outline_style);
+ }
}
}
@@ -673,8 +594,7 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
// When the layout-tree gets into a bad state, we can end up trying to paint
// a fragment with inline children, without a paint fragment. See:
// http://crbug.com/1022545
- if ((!paint_fragment_ && !items_) ||
- (layout_object && layout_object->NeedsLayout())) {
+ if (!items_ || (layout_object && layout_object->NeedsLayout())) {
NOTREACHED();
return;
}
@@ -706,11 +626,6 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
return;
}
- if (paint_fragment_) {
- NGInlineCursor children(*paint_fragment_);
- PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
- return;
- }
DCHECK(items_);
NGInlineCursor children(fragment, *items_);
PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
@@ -779,7 +694,7 @@ void NGBoxFragmentPainter::PaintBlockChildren(const PaintInfo& paint_info,
}
}
if (paint_info.phase == PaintPhase::kForeground &&
- box_fragment_.IsTableNGPart() && box_fragment_.IsTable()) {
+ box_fragment_.IsTableNG()) {
NGTablePainter(box_fragment_)
.PaintCollapsedBorders(paint_info, paint_offset,
VisualRect(paint_offset));
@@ -911,8 +826,7 @@ void NGBoxFragmentPainter::PaintFloatingChildren(
PaintFloatingItems(float_paint_info, &descendants);
return;
}
- DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() ||
- !box->IsInlineBox());
+ DCHECK(!box->IsInlineBox());
}
}
@@ -1024,7 +938,7 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackground(
.PaintBoxDecorationBackground(paint_info, paint_offset,
visual_rect);
} else {
- DCHECK(box_fragment_.IsTable());
+ DCHECK(box_fragment_.IsTableNG());
NGTablePainter(box_fragment_)
.PaintBoxDecorationBackground(paint_info, paint_offset,
visual_rect);
@@ -1323,11 +1237,6 @@ void NGBoxFragmentPainter::PaintInlineChildBoxUsingLegacyFallback(
const PaintInfo& paint_info) {
const LayoutObject* child_layout_object = fragment.GetLayoutObject();
DCHECK(child_layout_object);
- if (child_layout_object->PaintFragment()) {
- // This object will use NGBoxFragmentPainter.
- child_layout_object->Paint(paint_info);
- return;
- }
if (child_layout_object->IsAtomicInlineLevel()) {
// Pre-NG painters also expect callers to use |PaintAllPhasesAtomically()|
@@ -1412,8 +1321,7 @@ void NGBoxFragmentPainter::PaintInlineItems(const PaintInfo& paint_info,
inline void NGBoxFragmentPainter::PaintLineBox(
const NGPhysicalFragment& line_box_fragment,
const DisplayItemClient& display_item_client,
- const NGPaintFragment* line_box_paint_fragment,
- const NGFragmentItem* line_box_item,
+ const NGFragmentItem& line_box_item,
wtf_size_t line_fragment_id,
const PaintInfo& paint_info,
const PhysicalOffset& child_offset) {
@@ -1422,8 +1330,7 @@ inline void NGBoxFragmentPainter::PaintLineBox(
base::Optional<ScopedDisplayItemFragment> display_item_fragment;
if (ShouldRecordHitTestData(paint_info)) {
- if (line_box_item)
- display_item_fragment.emplace(paint_info.context, line_fragment_id);
+ display_item_fragment.emplace(paint_info.context, line_fragment_id);
PhysicalRect border_box = line_box_fragment.LocalRect();
border_box.offset += child_offset;
paint_info.context.GetPaintController().RecordHitTestData(
@@ -1434,11 +1341,10 @@ inline void NGBoxFragmentPainter::PaintLineBox(
// Paint the background of the `::first-line` line box.
if (NGLineBoxFragmentPainter::NeedsPaint(line_box_fragment)) {
- if (!display_item_fragment && line_box_item)
+ if (!display_item_fragment)
display_item_fragment.emplace(paint_info.context, line_fragment_id);
- NGLineBoxFragmentPainter line_box_painter(
- line_box_fragment, line_box_paint_fragment, line_box_item,
- PhysicalFragment(), paint_fragment_);
+ NGLineBoxFragmentPainter line_box_painter(line_box_fragment, line_box_item,
+ PhysicalFragment());
line_box_painter.PaintBackgroundBorderShadow(paint_info, child_offset);
}
}
@@ -1478,48 +1384,8 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
return;
}
- if (UNLIKELY(children->IsItemCursor())) {
- PaintLineBoxChildItems(children, paint_info, paint_offset);
- return;
- }
-
- const bool is_horizontal = box_fragment_.Style().IsHorizontalWritingMode();
- for (; *children; children->MoveToNextSkippingChildren()) {
- const NGPaintFragment* line = children->CurrentPaintFragment();
- DCHECK(line);
- const NGPhysicalFragment& child_fragment = line->PhysicalFragment();
- DCHECK(!child_fragment.IsOutOfFlowPositioned());
- if (child_fragment.IsFloating())
- continue;
-
- // Check if CullRect intersects with this child, only in block direction
- // because soft-wrap and <br> needs to paint outside of InkOverflow() in
- // inline direction.
- const PhysicalOffset child_offset = paint_offset + line->Offset();
- PhysicalRect child_rect = line->InkOverflow();
- if (is_horizontal) {
- LayoutUnit y = child_rect.offset.top + child_offset.top;
- if (!paint_info.GetCullRect().IntersectsVerticalRange(
- y, y + child_rect.size.height))
- continue;
- } else {
- LayoutUnit x = child_rect.offset.left + child_offset.left;
- if (!paint_info.GetCullRect().IntersectsHorizontalRange(
- x, x + child_rect.size.width))
- continue;
- }
-
- if (child_fragment.IsListMarker()) {
- PaintAtomicInlineChild(*line, paint_info);
- continue;
- }
- DCHECK(child_fragment.IsLineBox());
- PaintLineBox(
- child_fragment, *line, line, /* line_box_item */ nullptr,
- // |line_fragment_id| is used only when |NGFragmentItem| is enabled.
- /* line_fragment_id */ 0, paint_info, child_offset);
- PaintInlineChildren(line->Children(), paint_info, child_offset);
- }
+ DCHECK(children->HasRoot());
+ PaintLineBoxChildItems(children, paint_info, paint_offset);
}
void NGBoxFragmentPainter::PaintLineBoxChildItems(
@@ -1538,7 +1404,7 @@ void NGBoxFragmentPainter::PaintLineBoxChildItems(
// because soft-wrap and <br> needs to paint outside of InkOverflow() in
// inline direction.
const PhysicalOffset& child_offset =
- paint_offset + child_item->OffsetInContainerBlock();
+ paint_offset + child_item->OffsetInContainerFragment();
const PhysicalRect child_rect = child_item->InkOverflow();
if (is_horizontal) {
LayoutUnit y = child_rect.offset.top + child_offset.top;
@@ -1557,11 +1423,11 @@ void NGBoxFragmentPainter::PaintLineBoxChildItems(
child_item->LineBoxFragment();
DCHECK(line_box_fragment);
PaintLineBox(*line_box_fragment, *child_item->GetDisplayItemClient(),
- /* line_box_paint_fragment */ nullptr, child_item,
- line_fragment_id++, paint_info, child_offset);
+ *child_item, line_fragment_id++, paint_info, child_offset);
NGInlineCursor line_box_cursor = children->CursorForDescendants();
PaintInlineItems(paint_info, paint_offset,
- child_item->OffsetInContainerBlock(), &line_box_cursor);
+ child_item->OffsetInContainerFragment(),
+ &line_box_cursor);
continue;
}
@@ -1610,82 +1476,6 @@ void NGBoxFragmentPainter::PaintBackplate(NGInlineCursor* line_boxes,
paint_info.context.FillRect(FloatRect(backplate), backplate_color);
}
-void NGBoxFragmentPainter::PaintInlineChildren(
- NGPaintFragment::ChildList inline_children,
- const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
- // TODO(kojii): Move kOutline painting into a |PaintInlineChildrenOutlines()|
- // method instead as it would be more efficient. Would require repeating some
- // of the code below though.
- // This DCHECK can then match to |InlineFlowBoxPainter::Paint|.
- DCHECK_NE(paint_info.phase, PaintPhase::kDescendantOutlinesOnly);
-
- for (const NGPaintFragment* child : inline_children) {
- const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
- if (child_fragment.IsHiddenForPaint())
- continue;
- if (child_fragment.IsFloating())
- continue;
-
- // Skip if this child does not intersect with CullRect.
- if (!paint_info.IntersectsCullRect(child->InkOverflow(),
- paint_offset + child->Offset()) &&
- // Don't skip empty size text in order to paint selection for <br>.
- !(child_fragment.IsText() && child_fragment.Size().IsEmpty() &&
- HasSelection(child_fragment.GetLayoutObject())))
- continue;
-
- if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) {
- DCHECK(!child_fragment.HasSelfPaintingLayer() ||
- To<NGPhysicalTextFragment>(child_fragment).IsEllipsis());
- PaintTextChild(*child, paint_info, paint_offset);
- } else if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
- if (child_fragment.HasSelfPaintingLayer())
- continue;
- if (child_fragment.IsAtomicInline())
- PaintAtomicInlineChild(*child, paint_info);
- else
- NGInlineBoxFragmentPainter(*child).Paint(paint_info, paint_offset);
- } else {
- NOTREACHED();
- }
- }
-}
-
-void NGBoxFragmentPainter::PaintAtomicInlineChild(const NGPaintFragment& child,
- const PaintInfo& paint_info) {
- // Inline children should be painted by PaintInlineChild.
- DCHECK(child.PhysicalFragment().IsAtomicInline());
-
- const NGPhysicalFragment& fragment = child.PhysicalFragment();
- if (child.HasSelfPaintingLayer())
- return;
- if (fragment.Type() == NGPhysicalFragment::kFragmentBox &&
- FragmentRequiresLegacyFallback(fragment)) {
- PaintInlineChildBoxUsingLegacyFallback(fragment, paint_info);
- } else {
- NGBoxFragmentPainter(child).PaintAllPhasesAtomically(paint_info);
- }
-}
-
-void NGBoxFragmentPainter::PaintTextChild(const NGPaintFragment& paint_fragment,
- const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
- // Inline blocks should be painted by PaintAtomicInlineChild.
- DCHECK(!paint_fragment.PhysicalFragment().IsAtomicInline());
-
- // Only paint during the foreground/selection phases.
- if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelectionDragImage &&
- paint_info.phase != PaintPhase::kTextClip &&
- paint_info.phase != PaintPhase::kMask)
- return;
-
- NGTextPainterCursor cursor(paint_fragment);
- NGTextFragmentPainter<NGTextPainterCursor> text_painter(cursor);
- text_painter.Paint(paint_info, paint_offset);
-}
-
void NGBoxFragmentPainter::PaintTextItem(const NGInlineCursor& cursor,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset,
@@ -1703,14 +1493,15 @@ void NGBoxFragmentPainter::PaintTextItem(const NGInlineCursor& cursor,
// Skip if this child does not intersect with CullRect.
if (!paint_info.IntersectsCullRect(
- item.InkOverflow(), paint_offset + item.OffsetInContainerBlock()) &&
+ item.InkOverflow(),
+ paint_offset + item.OffsetInContainerFragment()) &&
// Don't skip <br>, it doesn't have ink but need to paint selection.
!(item.IsLineBreak() && HasSelection(item.GetLayoutObject())))
return;
ScopedDisplayItemFragment display_item_fragment(paint_info.context,
item.FragmentId());
- NGTextFragmentPainter<NGInlineCursor> text_painter(cursor, parent_offset);
+ NGTextFragmentPainter text_painter(cursor, parent_offset);
text_painter.Paint(paint_info, paint_offset);
}
@@ -1730,7 +1521,7 @@ void NGBoxFragmentPainter::PaintBoxItem(
// Skip if this child does not intersect with CullRect.
if (!paint_info.IntersectsCullRect(
- item.InkOverflow(), paint_offset + item.OffsetInContainerBlock()))
+ item.InkOverflow(), paint_offset + item.OffsetInContainerFragment()))
return;
if (child_fragment.IsAtomicInline() || child_fragment.IsListMarker()) {
@@ -1762,7 +1553,7 @@ void NGBoxFragmentPainter::PaintBoxItem(const NGFragmentItem& item,
// Skip if this child does not intersect with CullRect.
if (!paint_info.IntersectsCullRect(
- item.InkOverflow(), paint_offset + item.OffsetInContainerBlock()))
+ item.InkOverflow(), paint_offset + item.OffsetInContainerFragment()))
return;
// This |item| is a culled inline box.
@@ -1790,10 +1581,6 @@ bool NGBoxFragmentPainter::IsPaintingScrollingBackground(
bool NGBoxFragmentPainter::ShouldPaint(
const ScopedPaintState& paint_state) const {
// TODO(layout-dev): Add support for scrolling, see BlockPainter::ShouldPaint.
- if (paint_fragment_) {
- return paint_state.LocalRectIntersectsCullRect(
- paint_fragment_->InkOverflow());
- }
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
if (!fragment.IsInlineBox()) {
return paint_state.LocalRectIntersectsCullRect(
@@ -1808,26 +1595,19 @@ void NGBoxFragmentPainter::PaintTextClipMask(GraphicsContext& context,
const IntRect& mask_rect,
const PhysicalOffset& paint_offset,
bool object_has_multiple_boxes) {
- PaintInfo paint_info(context, mask_rect, PaintPhase::kTextClip,
+ PaintInfo paint_info(context, CullRect(mask_rect), PaintPhase::kTextClip,
kGlobalPaintNormalPhase, 0);
if (!object_has_multiple_boxes) {
PaintObject(paint_info, paint_offset);
return;
}
- if (paint_fragment_) {
- NGInlineBoxFragmentPainter inline_box_painter(*paint_fragment_);
- PaintTextClipMask(paint_info, paint_offset - paint_fragment_->Offset(),
- &inline_box_painter);
- return;
- }
-
DCHECK(inline_box_cursor_);
DCHECK(box_item_);
NGInlineBoxFragmentPainter inline_box_painter(*inline_box_cursor_,
*box_item_);
PaintTextClipMask(paint_info,
- paint_offset - box_item_->OffsetInContainerBlock(),
+ paint_offset - box_item_->OffsetInContainerFragment(),
&inline_box_painter);
}
@@ -1889,11 +1669,16 @@ BoxPainterBase::FillLayerInfo NGBoxFragmentPainter::GetFillLayerInfo(
BackgroundBleedAvoidance bleed_avoidance,
bool is_painting_scrolling_background) const {
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(fragment.GetLayoutObject());
+ if (auto* style_image = bg_layer.GetImage()) {
+ respect_orientation =
+ style_image->ForceOrientationIfNecessary(respect_orientation);
+ }
return BoxPainterBase::FillLayerInfo(
fragment.GetLayoutObject()->GetDocument(), fragment.Style(),
fragment.IsScrollContainer(), color, bg_layer, bleed_avoidance,
- LayoutObject::ShouldRespectImageOrientation(fragment.GetLayoutObject()),
- box_fragment_.SidesToInclude(),
+ respect_orientation, box_fragment_.SidesToInclude(),
fragment.GetLayoutObject()->IsLayoutInline(),
is_painting_scrolling_background);
}
@@ -1909,6 +1694,16 @@ bool NGBoxFragmentPainter::HitTestContext::AddNodeToResult(
kStopHitTesting;
}
+bool NGBoxFragmentPainter::HitTestContext::AddNodeToResultWithContentOffset(
+ Node* node,
+ const NGPhysicalBoxFragment& container,
+ const PhysicalRect& bounds_rect,
+ PhysicalOffset offset) const {
+ if (container.IsScrollContainer())
+ offset += PhysicalOffset(container.PixelSnappedScrolledContentOffset());
+ return AddNodeToResult(node, &container, bounds_rect, offset);
+}
+
bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
@@ -2007,17 +1802,11 @@ bool NGBoxFragmentPainter::NodeAtPoint(const HitTestContext& hit_test,
// |NGBoxFragmentPainter::HitTestTextFragment()|.
// See http://crbug.com/1043471
if (box_item_ && box_item_->IsInlineBox()) {
- if (hit_test.AddNodeToResult(
- fragment.NodeForHitTest(), /* box_fragment */ nullptr,
- bounds_rect,
- physical_offset - box_item_->OffsetInContainerBlock()))
- return true;
- } else if (paint_fragment_ &&
- paint_fragment_->PhysicalFragment().IsInline()) {
- if (hit_test.AddNodeToResult(
- fragment.NodeForHitTest(), /* box_fragment */ nullptr,
- bounds_rect,
- physical_offset - paint_fragment_->OffsetInContainerBlock()))
+ DCHECK(inline_box_cursor_);
+ if (hit_test.AddNodeToResultWithContentOffset(
+ fragment.NodeForHitTest(),
+ inline_box_cursor_->ContainerFragment(), bounds_rect,
+ physical_offset - box_item_->OffsetInContainerFragment()))
return true;
} else {
if (hit_test.AddNodeToResult(fragment.NodeForHitTest(), &box_fragment_,
@@ -2066,38 +1855,10 @@ bool NGBoxFragmentPainter::HitTestAllPhases(
return inside;
}
-bool NGBoxFragmentPainter::HitTestTextFragment(
+bool NGBoxFragmentPainter::HitTestTextItem(
const HitTestContext& hit_test,
- const NGInlineBackwardCursor& cursor,
- const PhysicalOffset& physical_offset) {
- if (hit_test.action != kHitTestForeground)
- return false;
-
- const NGPaintFragment* text_paint_fragment = cursor.Current().PaintFragment();
- DCHECK(text_paint_fragment);
- const auto& text_fragment =
- To<NGPhysicalTextFragment>(text_paint_fragment->PhysicalFragment());
- if (!IsVisibleToHitTest(text_fragment, hit_test.result->GetHitTestRequest()))
- return false;
-
- // TODO(layout-dev): Clip to line-top/bottom.
- PhysicalRect border_rect(physical_offset, text_fragment.Size());
- PhysicalRect rect(PixelSnappedIntRect(border_rect));
- if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
- HitTestRequest::kHitTestVisualOverflow)) {
- rect = text_fragment.SelfInkOverflow();
- rect.Move(border_rect.offset);
- }
- if (!hit_test.location.Intersects(rect))
- return false;
-
- return hit_test.AddNodeToResult(
- text_fragment.NodeForHitTest(), /* box_fragment */ nullptr, rect,
- physical_offset - text_paint_fragment->OffsetInContainerBlock());
-}
-
-bool NGBoxFragmentPainter::HitTestTextItem(const HitTestContext& hit_test,
- const NGFragmentItem& text_item) {
+ const NGFragmentItem& text_item,
+ const NGInlineBackwardCursor& cursor) {
DCHECK(text_item.IsText());
if (hit_test.action != kHitTestForeground)
@@ -2107,7 +1868,7 @@ bool NGBoxFragmentPainter::HitTestTextItem(const HitTestContext& hit_test,
// TODO(layout-dev): Clip to line-top/bottom.
const PhysicalOffset offset =
- hit_test.inline_root_offset + text_item.OffsetInContainerBlock();
+ hit_test.inline_root_offset + text_item.OffsetInContainerFragment();
PhysicalRect border_rect(offset, text_item.Size());
PhysicalRect rect(PixelSnappedIntRect(border_rect));
if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
@@ -2118,9 +1879,9 @@ bool NGBoxFragmentPainter::HitTestTextItem(const HitTestContext& hit_test,
if (!hit_test.location.Intersects(rect))
return false;
- return hit_test.AddNodeToResult(text_item.NodeForHitTest(),
- /* box_fragment */ nullptr, rect,
- hit_test.inline_root_offset);
+ return hit_test.AddNodeToResultWithContentOffset(
+ text_item.NodeForHitTest(), cursor.ContainerFragment(), rect,
+ hit_test.inline_root_offset);
}
// Replicates logic in legacy InlineFlowBox::NodeAtPoint().
@@ -2176,9 +1937,9 @@ bool NGBoxFragmentPainter::HitTestLineBoxFragment(
return false;
}
- return hit_test.AddNodeToResult(
- fragment.NodeForHitTest(), &box_fragment_, bounds_rect,
- physical_offset - cursor.Current().OffsetInContainerBlock());
+ return hit_test.AddNodeToResultWithContentOffset(
+ fragment.NodeForHitTest(), box_fragment_, bounds_rect,
+ physical_offset - cursor.Current().OffsetInContainerFragment());
}
bool NGBoxFragmentPainter::HitTestChildBoxFragment(
@@ -2195,19 +1956,9 @@ bool NGBoxFragmentPainter::HitTestChildBoxFragment(
return false;
if (!FragmentRequiresLegacyFallback(fragment)) {
- DCHECK(!fragment.IsAtomicInline());
- DCHECK(!fragment.IsFloating());
- if (const NGPaintFragment* paint_fragment =
- backward_cursor.Current().PaintFragment()) {
- if (fragment.IsInlineBox()) {
- return NGBoxFragmentPainter(*paint_fragment)
- .NodeAtPoint(hit_test, physical_offset);
- }
- // When traversing into a different inline formatting context,
- // |inline_root_offset| needs to be updated.
- return NGBoxFragmentPainter(*paint_fragment)
- .NodeAtPoint(*hit_test.result, hit_test.location, physical_offset,
- hit_test.action);
+ if (fragment.IsPaintedAtomically()) {
+ return HitTestAllPhasesInFragment(fragment, hit_test.location,
+ physical_offset, hit_test.result);
}
NGInlineCursor cursor(backward_cursor);
const NGFragmentItem* item = cursor.Current().Item();
@@ -2245,7 +1996,7 @@ bool NGBoxFragmentPainter::HitTestChildBoxItem(
if (const NGPhysicalBoxFragment* child_fragment = item.BoxFragment()) {
const PhysicalOffset child_offset =
- hit_test.inline_root_offset + item.OffsetInContainerBlock();
+ hit_test.inline_root_offset + item.OffsetInContainerFragment();
return HitTestChildBoxFragment(hit_test, *child_fragment, cursor,
child_offset);
}
@@ -2261,7 +2012,7 @@ bool NGBoxFragmentPainter::HitTestChildBoxItem(
if (hit_test.action == kHitTestForeground &&
IsVisibleToHitTest(item, hit_test.result->GetHitTestRequest())) {
const PhysicalOffset child_offset =
- hit_test.inline_root_offset + item.OffsetInContainerBlock();
+ hit_test.inline_root_offset + item.OffsetInContainerFragment();
PhysicalRect bounds_rect(child_offset, item.Size());
if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) {
@@ -2272,9 +2023,9 @@ bool NGBoxFragmentPainter::HitTestChildBoxItem(
// snap, but matches to legacy and fixes crbug.com/976606.
bounds_rect = PhysicalRect(PixelSnappedIntRect(bounds_rect));
if (hit_test.location.Intersects(bounds_rect)) {
- if (hit_test.AddNodeToResult(item.NodeForHitTest(),
- /* box_fragment */ nullptr, bounds_rect,
- child_offset))
+ if (hit_test.AddNodeToResultWithContentOffset(item.NodeForHitTest(),
+ cursor.ContainerFragment(),
+ bounds_rect, child_offset))
return true;
}
}
@@ -2285,11 +2036,6 @@ bool NGBoxFragmentPainter::HitTestChildBoxItem(
bool NGBoxFragmentPainter::HitTestChildren(
const HitTestContext& hit_test,
const PhysicalOffset& accumulated_offset) {
- if (paint_fragment_) {
- NGInlineCursor cursor(*paint_fragment_);
- return HitTestChildren(hit_test, PhysicalFragment(), cursor,
- accumulated_offset);
- }
if (UNLIKELY(inline_box_cursor_)) {
NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
if (descendants) {
@@ -2306,8 +2052,7 @@ bool NGBoxFragmentPainter::HitTestChildren(
// Check descendants of this fragment because floats may be in the
// |NGFragmentItems| of the descendants.
if (hit_test.action == kHitTestFloat &&
- box_fragment_.HasFloatingDescendantsForPaint() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ box_fragment_.HasFloatingDescendantsForPaint()) {
return HitTestFloatingChildren(hit_test, box_fragment_, accumulated_offset);
}
@@ -2324,9 +2069,7 @@ bool NGBoxFragmentPainter::HitTestChildren(
const NGPhysicalBoxFragment& container,
const NGInlineCursor& children,
const PhysicalOffset& accumulated_offset) {
- if (children.IsPaintFragmentCursor())
- return HitTestPaintFragmentChildren(hit_test, children, accumulated_offset);
- if (children.IsItemCursor())
+ if (children.HasRoot())
return HitTestItemsChildren(hit_test, container, children);
// Hits nothing if there were no children.
return false;
@@ -2376,59 +2119,11 @@ bool NGBoxFragmentPainter::HitTestBlockChildren(
return false;
}
-bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
- const HitTestContext& hit_test,
- const NGInlineCursor& children,
- const PhysicalOffset& accumulated_offset) {
- DCHECK(children.IsPaintFragmentCursor());
- for (NGInlineBackwardCursor cursor(children); cursor;) {
- const NGPaintFragment* child_paint_fragment =
- cursor.Current().PaintFragment();
- DCHECK(child_paint_fragment);
- const NGPhysicalFragment& child_fragment =
- child_paint_fragment->PhysicalFragment();
- if (child_fragment.HasSelfPaintingLayer()) {
- cursor.MoveToPreviousSibling();
- continue;
- }
-
- const PhysicalOffset child_offset =
- child_paint_fragment->Offset() + accumulated_offset;
- if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
- if (HitTestChildBoxFragment(hit_test,
- To<NGPhysicalBoxFragment>(child_fragment),
- cursor, child_offset))
- return true;
- } else if (child_fragment.Type() == NGPhysicalFragment::kFragmentLineBox) {
- if (HitTestLineBoxFragment(hit_test,
- To<NGPhysicalLineBoxFragment>(child_fragment),
- cursor, child_offset))
- return true;
- } else if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) {
- if (HitTestTextFragment(hit_test, cursor, child_offset))
- return true;
- }
-
- cursor.MoveToPreviousSibling();
-
- if (child_fragment.IsInline() && hit_test.action == kHitTestForeground) {
- // Hit test culled inline boxes between |fragment| and its parent
- // fragment.
- if (HitTestCulledInlineAncestors(*hit_test.result, children,
- *child_paint_fragment, cursor.Current(),
- hit_test.location, child_offset))
- return true;
- }
- }
-
- return false;
-}
-
bool NGBoxFragmentPainter::HitTestItemsChildren(
const HitTestContext& hit_test,
const NGPhysicalBoxFragment& container,
const NGInlineCursor& children) {
- DCHECK(children.IsItemCursor());
+ DCHECK(children.HasRoot());
for (NGInlineBackwardCursor cursor(children); cursor;) {
const NGFragmentItem* item = cursor.Current().Item();
DCHECK(item);
@@ -2446,13 +2141,13 @@ bool NGBoxFragmentPainter::HitTestItemsChildren(
}
if (item->IsText()) {
- if (HitTestTextItem(hit_test, *item))
+ if (HitTestTextItem(hit_test, *item, cursor))
return true;
} else if (item->Type() == NGFragmentItem::kLine) {
const NGPhysicalLineBoxFragment* child_fragment = item->LineBoxFragment();
DCHECK(child_fragment);
const PhysicalOffset child_offset =
- hit_test.inline_root_offset + item->OffsetInContainerBlock();
+ hit_test.inline_root_offset + item->OffsetInContainerFragment();
if (HitTestLineBoxFragment(hit_test, *child_fragment, cursor,
child_offset))
return true;
@@ -2470,7 +2165,7 @@ bool NGBoxFragmentPainter::HitTestItemsChildren(
// Hit test culled inline boxes between |fragment| and its parent
// fragment.
const PhysicalOffset child_offset =
- hit_test.inline_root_offset + item->OffsetInContainerBlock();
+ hit_test.inline_root_offset + item->OffsetInContainerFragment();
if (HitTestCulledInlineAncestors(*hit_test.result, container, children,
*item, cursor.Current(),
hit_test.location, child_offset))
@@ -2528,8 +2223,7 @@ bool NGBoxFragmentPainter::HitTestFloatingChildren(
// If this is a legacy root, fallback to legacy. It does not have
// |HasFloatingDescendantsForPaint()| set, but it may have floating
// descendants.
- if (child_container->IsLegacyLayoutRoot() &&
- RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (child_container->IsLegacyLayoutRoot()) {
if (child_container->GetMutableLayoutObject()->NodeAtPoint(
*hit_test.result, hit_test.location, child_offset,
hit_test.action))
@@ -2578,7 +2272,7 @@ bool NGBoxFragmentPainter::HitTestFloatingChildItems(
continue;
const PhysicalOffset child_offset =
- accumulated_offset + item->OffsetInContainerBlock();
+ accumulated_offset + item->OffsetInContainerFragment();
if (child_box->IsFloating()) {
if (HitTestAllPhasesInFragment(*child_box, hit_test.location,
child_offset, hit_test.result))
@@ -2635,13 +2329,8 @@ IntRect NGBoxFragmentPainter::VisualRect(const PhysicalOffset& paint_offset) {
DynamicTo<LayoutBox>(box_fragment_.GetLayoutObject()))
return BoxPainter(*layout_box).VisualRect(paint_offset);
- PhysicalRect ink_overflow;
- if (paint_fragment_)
- ink_overflow = paint_fragment_->InkOverflow();
- else if (box_item_)
- ink_overflow = box_item_->InkOverflow();
- else
- NOTREACHED();
+ DCHECK(box_item_);
+ PhysicalRect ink_overflow = box_item_->InkOverflow();
ink_overflow.Move(paint_offset);
return EnclosingIntRect(ink_overflow);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 7aabb96f84a..4c433b31448 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -31,16 +30,11 @@ struct PaintInfo;
// Painter for LayoutNG box fragments, paints borders and background. Delegates
// to NGTextFragmentPainter to paint line box fragments.
-class NGBoxFragmentPainter : public BoxPainterBase {
+class CORE_EXPORT NGBoxFragmentPainter : public BoxPainterBase {
STACK_ALLOCATED();
public:
NGBoxFragmentPainter(const NGPhysicalBoxFragment&);
- // Construct for a box fragment. |NGPaintFragment| for this
- // box if this box has inline formatting context, otherwise |nullptr|.
- NGBoxFragmentPainter(const NGPhysicalBoxFragment&, const NGPaintFragment*);
- // Construct for an inline formatting context.
- NGBoxFragmentPainter(const NGPaintFragment&);
// Construct for an inline box.
NGBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& item,
@@ -102,7 +96,6 @@ class NGBoxFragmentPainter : public BoxPainterBase {
private:
NGBoxFragmentPainter(const NGPhysicalBoxFragment&,
const DisplayItemClient& display_item_client,
- const NGPaintFragment* = nullptr,
const NGInlineCursor* inline_box_cursor = nullptr,
const NGFragmentItem* = nullptr);
@@ -138,25 +131,17 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const PhysicalOffset& paint_offset);
void PaintLineBox(const NGPhysicalFragment& line_box_fragment,
const DisplayItemClient& display_item_client,
- const NGPaintFragment* line_box_paint_fragment,
- const NGFragmentItem* line_box_item,
+ const NGFragmentItem& line_box_item,
wtf_size_t line_fragment_id,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintBackplate(NGInlineCursor* descendants,
const PaintInfo&,
const PhysicalOffset& paint_offset);
- void PaintInlineChildren(NGPaintFragment::ChildList,
- const PaintInfo&,
- const PhysicalOffset& paint_offset);
void PaintInlineChildBoxUsingLegacyFallback(const NGPhysicalFragment&,
const PaintInfo&);
void PaintBlockFlowContents(const PaintInfo&,
const PhysicalOffset& paint_offset);
- void PaintAtomicInlineChild(const NGPaintFragment&, const PaintInfo&);
- void PaintTextChild(const NGPaintFragment&,
- const PaintInfo&,
- const PhysicalOffset& paint_offset);
void PaintTextItem(const NGInlineCursor& cursor,
const PaintInfo&,
const PhysicalOffset& paint_offset,
@@ -211,6 +196,14 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGPhysicalBoxFragment* box_fragment,
const PhysicalRect& bounds_rect,
const PhysicalOffset& offset) const;
+ // Same as |AddNodeToResult|, except that |offset| is in the content
+ // coordinate system rather than the container coordinate system. They
+ // differ when |container| is a scroll container.
+ bool AddNodeToResultWithContentOffset(
+ Node* node,
+ const NGPhysicalBoxFragment& container,
+ const PhysicalRect& bounds_rect,
+ PhysicalOffset offset) const;
HitTestAction action;
const HitTestLocation& location;
@@ -239,9 +232,6 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const HitTestLocation&,
PhysicalOffset,
HitTestAction);
- bool HitTestPaintFragmentChildren(const HitTestContext& hit_test,
- const NGInlineCursor& children,
- const PhysicalOffset& physical_offset);
bool HitTestItemsChildren(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& container,
const NGInlineCursor& children);
@@ -271,7 +261,8 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGInlineBackwardCursor& cursor,
const PhysicalOffset& physical_offset);
bool HitTestTextItem(const HitTestContext& hit_test,
- const NGFragmentItem& text_item);
+ const NGFragmentItem& text_item,
+ const NGInlineBackwardCursor& cursor);
// Hit tests the given line box fragment.
// @param physical_offset Physical offset of the line box fragment in paint
@@ -300,10 +291,6 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGPhysicalBoxFragment& box_fragment_;
const DisplayItemClient& display_item_client_;
- // If this box has inline children, either |paint_fragment_| or |items_| is
- // not null, depends on |LayoutNGFragmentItemEnabled|. TODO(kojii): Remove
- // |NGPaintFragment| once the transition is done. crbug.com/982194
- const NGPaintFragment* paint_fragment_;
const NGFragmentItems* items_;
const NGFragmentItem* box_item_ = nullptr;
const NGInlineCursor* inline_box_cursor_ = nullptr;
@@ -312,47 +299,23 @@ class NGBoxFragmentPainter : public BoxPainterBase {
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& box,
const DisplayItemClient& display_item_client,
- const NGPaintFragment* paint_fragment,
const NGInlineCursor* inline_box_cursor,
const NGFragmentItem* box_item)
: BoxPainterBase(&box.GetDocument(), box.Style(), box.GeneratingNode()),
box_fragment_(box),
display_item_client_(display_item_client),
- paint_fragment_(paint_fragment),
items_(box.Items()),
box_item_(box_item),
inline_box_cursor_(inline_box_cursor) {
DCHECK(box.IsBox() || box.IsRenderedLegend());
DCHECK_EQ(box.PostLayout(), &box);
#if DCHECK_IS_ON()
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- DCHECK(!paint_fragment_);
- if (inline_box_cursor_)
- DCHECK_EQ(inline_box_cursor_->Current().Item(), box_item_);
- if (box_item_)
- DCHECK_EQ(box_item_->BoxFragment(), &box);
- DCHECK_EQ(box.IsInlineBox(), !!inline_box_cursor_);
- DCHECK_EQ(box.IsInlineBox(), !!box_item_);
- } else {
- DCHECK(!inline_box_cursor_);
- DCHECK(!box_item_);
- if (paint_fragment)
- DCHECK_EQ(&paint_fragment->PhysicalFragment(), &box);
- if (box.IsInlineBox()) {
- DCHECK(paint_fragment_);
- } else if (box.IsInlineFormattingContext()) {
- // If no children, there maybe or may not be NGPaintFragment.
- // TODO(kojii): To be investigated if this correct or should be fixed.
- if (!box.Children().empty()) {
- if (!box.GetLayoutObject() ||
- !box.GetLayoutObject()->ChildPaintBlockedByDisplayLock()) {
- DCHECK(paint_fragment);
- }
- }
- } else {
- // We may not have |paint_fragment_| nor |box_item_|.
- }
- }
+ if (inline_box_cursor_)
+ DCHECK_EQ(inline_box_cursor_->Current().Item(), box_item_);
+ if (box_item_)
+ DCHECK_EQ(box_item_->BoxFragment(), &box);
+ DCHECK_EQ(box.IsInlineBox(), !!inline_box_cursor_);
+ DCHECK_EQ(box.IsInlineBox(), !!box_item_);
#endif
}
@@ -360,37 +323,15 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& fragment)
: NGBoxFragmentPainter(fragment,
*fragment.GetLayoutObject(),
- /* paint_fragment */ nullptr,
/* inline_box_cursor */ nullptr,
/* box_item */ nullptr) {}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
- const NGPhysicalBoxFragment& fragment,
- const NGPaintFragment* paint_fragment)
- : NGBoxFragmentPainter(
- fragment,
- paint_fragment
- ? *static_cast<const DisplayItemClient*>(paint_fragment)
- : *static_cast<const DisplayItemClient*>(
- fragment.GetLayoutObject()),
- paint_fragment,
- /* inline_box_cursor */ nullptr,
- /* box_item */ nullptr) {}
-
-inline NGBoxFragmentPainter::NGBoxFragmentPainter(
- const NGPaintFragment& paint_fragment)
- : NGBoxFragmentPainter(
- To<NGPhysicalBoxFragment>(paint_fragment.PhysicalFragment()),
- paint_fragment,
- &paint_fragment) {}
-
-inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& item,
const NGPhysicalBoxFragment& fragment)
: NGBoxFragmentPainter(fragment,
*item.GetDisplayItemClient(),
- /* paint_fragment */ nullptr,
&inline_box_cursor,
&item) {
DCHECK_EQ(item.BoxFragment(), &fragment);
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
index 0eb0deac526..ddc08a8e4a8 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -64,11 +63,7 @@ TEST_P(NGBoxFragmentPainterTest, ScrollHitTestOrder) {
<div id='scroller'>TEXT</div>
)HTML");
auto& scroller = *GetLayoutBoxByElementId("scroller");
-
- const DisplayItemClient& root_fragment =
- scroller.PaintFragment()
- ? static_cast<const DisplayItemClient&>(*scroller.PaintFragment())
- : static_cast<const DisplayItemClient&>(scroller);
+ const DisplayItemClient& root_fragment = scroller;
NGInlineCursor cursor;
cursor.MoveTo(*scroller.SlowFirstChild());
@@ -129,13 +124,13 @@ TEST_P(NGBoxFragmentPainterTest, AddUrlRects) {
// PaintPreviewTracker records URLs via the GraphicsContext under certain
// flagsets when painting. This is the simplest way to check if URLs were
// annotated.
- GetDocument().SetIsPaintingPreview(true);
+ Document::PaintPreviewScope paint_preview(GetDocument());
UpdateAllLifecyclePhasesForTest();
paint_preview::PaintPreviewTracker tracker(base::UnguessableToken::Create(),
base::nullopt, true);
- PaintRecordBuilder builder(nullptr, nullptr, nullptr, &tracker);
- builder.Context().SetIsPaintingPreview(true);
+ PaintRecordBuilder builder;
+ builder.Context().SetPaintPreviewTracker(&tracker);
GetDocument().View()->PaintContentsOutsideOfLifecycle(
builder.Context(),
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
index 855b7284278..40adc58c89c 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
@@ -11,7 +11,6 @@
#include "third_party/blink/renderer/core/paint/box_decoration_data.h"
#include "third_party/blink/renderer/core/paint/fieldset_paint_info.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
index cb665b1032c..b8aa544bf4a 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
@@ -14,18 +14,13 @@
namespace blink {
void NGFragmentPainter::PaintOutline(const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
- DCHECK(ShouldPaintSelfOutline(paint_info.phase));
-
+ const PhysicalOffset& paint_offset,
+ const ComputedStyle& style_to_use) {
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
- if (!NGOutlineUtils::HasPaintedOutline(fragment.Style(), fragment.GetNode()))
- return;
-
+ DCHECK(NGOutlineUtils::HasPaintedOutline(style_to_use, fragment.GetNode()));
Vector<PhysicalRect> outline_rects;
fragment.AddSelfOutlineRects(
- paint_offset,
- fragment.GetLayoutObject()
- ->OutlineRectsShouldIncludeBlockVisualOverflow(),
+ paint_offset, style_to_use.OutlineRectsShouldIncludeBlockVisualOverflow(),
&outline_rects);
if (outline_rects.IsEmpty())
@@ -38,10 +33,10 @@ void NGFragmentPainter::PaintOutline(const PaintInfo& paint_info,
IntRect visual_rect =
PixelSnappedIntRect(UnionRectEvenIfEmpty(outline_rects));
- visual_rect.Inflate(fragment.Style().OutlineOutsetExtent());
+ visual_rect.Inflate(style_to_use.OutlineOutsetExtent());
DrawingRecorder recorder(paint_info.context, display_item_client,
paint_info.phase, visual_rect);
- PaintOutlineRects(paint_info, outline_rects, fragment.Style());
+ PaintOutlineRects(paint_info, outline_rects, style_to_use);
}
void NGFragmentPainter::AddURLRectIfNeeded(const PaintInfo& paint_info,
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
index 60a21cf012d..eb94e0b2065 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
@@ -6,7 +6,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_FRAGMENT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_painter_base.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -25,7 +24,12 @@ class NGFragmentPainter : public ObjectPainterBase {
const DisplayItemClient& display_item_client)
: box_fragment_(box), display_item_client_(display_item_client) {}
- void PaintOutline(const PaintInfo&, const PhysicalOffset& paint_offset);
+ // |style_to_use| may be from other objects than |box_fragment_|. When
+ // painting outlines for a block in a continuation chain, its style does not
+ // have the `outline` property set.
+ void PaintOutline(const PaintInfo&,
+ const PhysicalOffset& paint_offset,
+ const ComputedStyle& style_to_use);
void AddURLRectIfNeeded(const PaintInfo&, const PhysicalOffset& paint_offset);
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
new file mode 100644
index 00000000000..ff9cc08c1c4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -0,0 +1,355 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/editing/editor.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
+#include "third_party/blink/renderer/core/editing/markers/styleable_marker.h"
+#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/paint/document_marker_painter.h"
+#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
+#include "third_party/blink/renderer/core/paint/inline_text_box_painter.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_text_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
+
+namespace blink {
+
+namespace {
+
+DocumentMarkerVector ComputeMarkersToPaint(Node* node, bool is_ellipsis) {
+ // TODO(yoichio): Handle first-letter
+ auto* text_node = DynamicTo<Text>(node);
+ if (!text_node)
+ return DocumentMarkerVector();
+ // We don't paint any marker on ellipsis.
+ if (is_ellipsis)
+ return DocumentMarkerVector();
+
+ DocumentMarkerController& document_marker_controller =
+ node->GetDocument().Markers();
+ return document_marker_controller.ComputeMarkersToPaint(*text_node);
+}
+
+unsigned GetTextContentOffset(const Text& text, unsigned offset) {
+ // TODO(yoichio): Sanitize DocumentMarker around text length.
+ const Position position(text, std::min(offset, text.length()));
+ const NGOffsetMapping* const offset_mapping =
+ NGOffsetMapping::GetFor(position);
+ DCHECK(offset_mapping);
+ const base::Optional<unsigned>& ng_offset =
+ offset_mapping->GetTextContentOffset(position);
+ DCHECK(ng_offset.has_value());
+ return ng_offset.value();
+}
+
+// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
+// offsets.
+// |offset| points not each character but each span between character.
+// With that concept, we can clear catch what is inside start / end.
+// Suppose we have "foo_bar"('_' is a space).
+// There are 8 offsets for that:
+// f o o _ b a r
+// 0 1 2 3 4 5 6 7
+// If "bar" is a TextFragment. That start(), end() {4, 7} correspond this
+// offset. If a marker has StartOffset / EndOffset as {2, 6},
+// ClampOffset returns{ 4,6 }, which represents "ba" on "foo_bar".
+unsigned ClampOffset(unsigned offset, const NGFragmentItem& text_fragment) {
+ return std::min(std::max(offset, text_fragment.StartOffset()),
+ text_fragment.EndOffset());
+}
+
+PhysicalRect MarkerRectForForeground(const NGFragmentItem& text_fragment,
+ StringView text,
+ unsigned start_offset,
+ unsigned end_offset) {
+ LayoutUnit start_position, end_position;
+ std::tie(start_position, end_position) =
+ text_fragment.LineLeftAndRightForOffsets(text, start_offset, end_offset);
+
+ const LayoutUnit height = text_fragment.Size()
+ .ConvertToLogical(static_cast<WritingMode>(
+ text_fragment.Style().GetWritingMode()))
+ .block_size;
+ return {start_position, LayoutUnit(), end_position - start_position, height};
+}
+
+void PaintRect(GraphicsContext& context,
+ const PhysicalRect& rect,
+ const Color color) {
+ if (!color.Alpha())
+ return;
+ if (rect.size.IsEmpty())
+ return;
+ const IntRect pixel_snapped_rect = PixelSnappedIntRect(rect);
+ if (!pixel_snapped_rect.IsEmpty())
+ context.FillRect(pixel_snapped_rect, color);
+}
+
+void PaintRect(GraphicsContext& context,
+ const PhysicalOffset& location,
+ const PhysicalRect& rect,
+ const Color color) {
+ PaintRect(context, PhysicalRect(rect.offset + location, rect.size), color);
+}
+
+Color SelectionBackgroundColor(const Document& document,
+ const ComputedStyle& style,
+ Node* node,
+ Color text_color) {
+ const Color color = HighlightPaintingUtils::HighlightBackgroundColor(
+ document, style, node, kPseudoIdSelection);
+ if (!color.Alpha())
+ return Color();
+
+ // If the text color ends up being the same as the selection background,
+ // invert the selection background.
+ if (text_color == color)
+ return Color(0xff - color.Red(), 0xff - color.Green(), 0xff - color.Blue());
+ return color;
+}
+
+} // namespace
+
+NGHighlightPainter::SelectionPaintState::SelectionPaintState(
+ const NGInlineCursor& containing_block)
+ : SelectionPaintState(containing_block,
+ containing_block.Current()
+ .GetLayoutObject()
+ ->GetDocument()
+ .GetFrame()
+ ->Selection()) {}
+NGHighlightPainter::SelectionPaintState::SelectionPaintState(
+ const NGInlineCursor& containing_block,
+ const FrameSelection& frame_selection)
+ : selection_status_(
+ frame_selection.ComputeLayoutSelectionStatus(containing_block)),
+ state_(frame_selection.ComputeLayoutSelectionStateForCursor(
+ containing_block.Current())),
+ containing_block_(containing_block) {}
+
+void NGHighlightPainter::SelectionPaintState::ComputeSelectionStyle(
+ const Document& document,
+ const ComputedStyle& style,
+ Node* node,
+ const PaintInfo& paint_info,
+ const TextPaintStyle& text_style) {
+ selection_style_ = TextPainterBase::SelectionPaintingStyle(
+ document, style, node, paint_info, text_style);
+ paint_selected_text_only_ =
+ (paint_info.phase == PaintPhase::kSelectionDragImage);
+}
+
+PhysicalRect NGHighlightPainter::SelectionPaintState::ComputeSelectionRect(
+ const PhysicalOffset& box_offset) {
+ if (!selection_rect_) {
+ selection_rect_ =
+ containing_block_.CurrentLocalSelectionRectForText(selection_status_);
+ selection_rect_->offset += box_offset;
+ }
+ return *selection_rect_;
+}
+
+// Logic is copied from InlineTextBoxPainter::PaintSelection.
+// |selection_start| and |selection_end| should be between
+// [text_fragment.StartOffset(), text_fragment.EndOffset()].
+void NGHighlightPainter::SelectionPaintState::PaintSelectionBackground(
+ GraphicsContext& context,
+ Node* node,
+ const Document& document,
+ const ComputedStyle& style,
+ const base::Optional<AffineTransform>& rotation) {
+ const Color color = SelectionBackgroundColor(document, style, node,
+ selection_style_.fill_color);
+
+ if (!rotation) {
+ PaintRect(context, *selection_rect_, color);
+ return;
+ }
+
+ // PaintRect tries to pixel-snap the given rect, but if we’re painting in a
+ // non-horizontal writing mode, our context has been transformed, regressing
+ // tests like <paint/invalidation/repaint-across-writing-mode-boundary>. To
+ // fix this, we undo the transformation temporarily, then use the original
+ // physical coordinates (before MapSelectionRectIntoRotatedSpace).
+ DCHECK(selection_rect_before_rotation_);
+ context.ConcatCTM(rotation->Inverse());
+ PaintRect(context, *selection_rect_before_rotation_, color);
+ context.ConcatCTM(*rotation);
+}
+
+// Called before we paint vertical selected text under a rotation transform.
+void NGHighlightPainter::SelectionPaintState::MapSelectionRectIntoRotatedSpace(
+ const AffineTransform& rotation) {
+ DCHECK(selection_rect_);
+ selection_rect_before_rotation_.emplace(*selection_rect_);
+ *selection_rect_ = PhysicalRect::EnclosingRect(
+ rotation.Inverse().MapRect(FloatRect(*selection_rect_)));
+}
+
+// Paint the selected text only.
+void NGHighlightPainter::SelectionPaintState::PaintSelectedText(
+ NGTextPainter& text_painter,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id) {
+ text_painter.PaintSelectedText(selection_status_.start, selection_status_.end,
+ length, text_style, selection_style_,
+ *selection_rect_, node_id);
+}
+
+// Paint the given text range in the given style, suppressing the text proper
+// (painting shadows only) where selected.
+void NGHighlightPainter::SelectionPaintState::
+ PaintSuppressingTextProperWhereSelected(NGTextPainter& text_painter,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id) {
+ // First paint the shadows for the whole range.
+ if (text_style.shadow) {
+ text_painter.Paint(start_offset, end_offset, length, text_style, node_id,
+ NGTextPainter::kShadowsOnly);
+ }
+
+ // Then paint the text proper for any unselected parts in storage order, so
+ // that they’re always on top of the shadows.
+ if (start_offset < selection_status_.start) {
+ text_painter.Paint(start_offset, selection_status_.start, length,
+ text_style, node_id, NGTextPainter::kTextProperOnly);
+ }
+ if (selection_status_.end < end_offset) {
+ text_painter.Paint(selection_status_.end, end_offset, length, text_style,
+ node_id, NGTextPainter::kTextProperOnly);
+ }
+}
+
+NGHighlightPainter::NGHighlightPainter(
+ NGTextPainter& text_painter,
+ const PaintInfo& paint_info,
+ const NGInlineCursor& cursor,
+ const NGFragmentItem& fragment_item,
+ const PhysicalOffset& box_origin,
+ const ComputedStyle& style,
+ base::Optional<SelectionPaintState> selection,
+ bool is_printing)
+ : text_painter_(text_painter),
+ paint_info_(paint_info),
+ cursor_(cursor),
+ fragment_item_(fragment_item),
+ box_origin_(box_origin),
+ style_(style),
+ selection_(selection),
+ layout_object_(fragment_item_.GetLayoutObject()),
+ node_(layout_object_->GetNode()),
+ markers_(ComputeMarkersToPaint(node_, fragment_item_.IsEllipsis())),
+ skip_backgrounds_(is_printing ||
+ paint_info.phase == PaintPhase::kTextClip ||
+ paint_info.phase == PaintPhase::kSelectionDragImage) {}
+
+void NGHighlightPainter::Paint(Phase phase) {
+ if (markers_.IsEmpty())
+ return;
+
+ if (skip_backgrounds_ && phase == kBackground)
+ return;
+
+ DCHECK(fragment_item_.GetNode());
+ const auto& text_node = To<Text>(*fragment_item_.GetNode());
+ const StringView text = cursor_.CurrentText();
+
+ for (const DocumentMarker* marker : markers_) {
+ const unsigned marker_start_offset =
+ GetTextContentOffset(text_node, marker->StartOffset());
+ const unsigned marker_end_offset =
+ GetTextContentOffset(text_node, marker->EndOffset());
+ const unsigned paint_start_offset =
+ ClampOffset(marker_start_offset, fragment_item_);
+ const unsigned paint_end_offset =
+ ClampOffset(marker_end_offset, fragment_item_);
+ if (paint_start_offset == paint_end_offset)
+ continue;
+
+ switch (marker->GetType()) {
+ case DocumentMarker::kSpelling:
+ case DocumentMarker::kGrammar: {
+ if (fragment_item_.GetNode()->GetDocument().Printing())
+ break;
+ if (phase == kBackground)
+ continue;
+ DocumentMarkerPainter::PaintDocumentMarker(
+ paint_info_, box_origin_, style_, marker->GetType(),
+ MarkerRectForForeground(fragment_item_, text, paint_start_offset,
+ paint_end_offset));
+ } break;
+
+ case DocumentMarker::kTextFragment:
+ case DocumentMarker::kTextMatch: {
+ const Document& document = node_->GetDocument();
+ if (marker->GetType() == DocumentMarker::kTextMatch &&
+ !document.GetFrame()->GetEditor().MarkedTextMatchesAreHighlighted())
+ break;
+ const auto& text_marker = To<TextMarkerBase>(*marker);
+ if (phase == kBackground) {
+ Color color;
+ if (marker->GetType() == DocumentMarker::kTextMatch) {
+ color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
+ text_marker.IsActiveMatch(), document.InForcedColorsMode(),
+ style_.UsedColorScheme());
+ } else {
+ color = HighlightPaintingUtils::HighlightBackgroundColor(
+ document, style_, node_, kPseudoIdTargetText);
+ }
+ PaintRect(paint_info_.context, PhysicalOffset(box_origin_),
+ fragment_item_.LocalRect(text, paint_start_offset,
+ paint_end_offset),
+ color);
+ break;
+ }
+
+ const TextPaintStyle text_style =
+ DocumentMarkerPainter::ComputeTextPaintStyleFrom(
+ document, node_, style_, text_marker, paint_info_);
+ if (text_style.current_color == Color::kTransparent)
+ break;
+ text_painter_.Paint(paint_start_offset, paint_end_offset,
+ paint_end_offset - paint_start_offset, text_style,
+ kInvalidDOMNodeId);
+ } break;
+
+ case DocumentMarker::kComposition:
+ case DocumentMarker::kActiveSuggestion:
+ case DocumentMarker::kSuggestion: {
+ const auto& styleable_marker = To<StyleableMarker>(*marker);
+ if (phase == kBackground) {
+ PaintRect(paint_info_.context, PhysicalOffset(box_origin_),
+ fragment_item_.LocalRect(text, paint_start_offset,
+ paint_end_offset),
+ styleable_marker.BackgroundColor());
+ break;
+ }
+ if (DocumentMarkerPainter::ShouldPaintMarkerUnderline(
+ styleable_marker)) {
+ const SimpleFontData* font_data = style_.GetFont().PrimaryFont();
+ DocumentMarkerPainter::PaintStyleableMarkerUnderline(
+ paint_info_.context, box_origin_, styleable_marker, style_,
+ FloatRect(MarkerRectForForeground(
+ fragment_item_, text, paint_start_offset, paint_end_offset)),
+ LayoutUnit(font_data->GetFontMetrics().Height()),
+ fragment_item_.GetNode()->GetDocument().InDarkMode());
+ }
+ } break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
new file mode 100644
index 00000000000..86c2ea74558
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_HIGHLIGHT_PAINTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_HIGHLIGHT_PAINTER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
+#include "third_party/blink/renderer/core/layout/api/selection_state.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/paint/text_paint_style.h"
+#include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class AffineTransform;
+class ComputedStyle;
+class FrameSelection;
+class LayoutObject;
+class NGFragmentItem;
+class NGTextPainter;
+class NGInlineCursor;
+class Node;
+struct LayoutSelectionStatus;
+struct PaintInfo;
+struct PhysicalOffset;
+
+// Highlight overlay painter for LayoutNG. Operates on NGFragmentItem that
+// IsText(). Delegates to NGTextPainter to paint the text itself.
+class CORE_EXPORT NGHighlightPainter {
+ STACK_ALLOCATED();
+
+ public:
+ class SelectionPaintState {
+ STACK_ALLOCATED();
+
+ public:
+ explicit SelectionPaintState(const NGInlineCursor& containing_block);
+ explicit SelectionPaintState(const NGInlineCursor& containing_block,
+ const FrameSelection&);
+
+ const LayoutSelectionStatus& Status() const { return selection_status_; }
+
+ const TextPaintStyle& GetSelectionStyle() const { return selection_style_; }
+
+ SelectionState State() const { return state_; }
+
+ bool ShouldPaintSelectedTextOnly() const {
+ return paint_selected_text_only_;
+ }
+
+ void ComputeSelectionStyle(const Document& document,
+ const ComputedStyle& style,
+ Node* node,
+ const PaintInfo& paint_info,
+ const TextPaintStyle& text_style);
+
+ PhysicalRect ComputeSelectionRect(const PhysicalOffset& box_offset);
+
+ void PaintSelectionBackground(
+ GraphicsContext& context,
+ Node* node,
+ const Document& document,
+ const ComputedStyle& style,
+ const base::Optional<AffineTransform>& rotation);
+
+ void MapSelectionRectIntoRotatedSpace(const AffineTransform& rotation);
+
+ void PaintSelectedText(NGTextPainter& text_painter,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id);
+
+ void PaintSuppressingTextProperWhereSelected(
+ NGTextPainter& text_painter,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id);
+
+ private:
+ const LayoutSelectionStatus selection_status_;
+ TextPaintStyle selection_style_;
+ const SelectionState state_;
+ base::Optional<PhysicalRect> selection_rect_;
+ base::Optional<PhysicalRect> selection_rect_before_rotation_;
+ const NGInlineCursor& containing_block_;
+ bool paint_selected_text_only_;
+ };
+
+ explicit NGHighlightPainter(NGTextPainter& text_painter,
+ const PaintInfo& paint_info,
+ const NGInlineCursor& cursor,
+ const NGFragmentItem& fragment_item,
+ const PhysicalOffset& box_origin,
+ const ComputedStyle& style,
+ base::Optional<SelectionPaintState>,
+ bool is_printing);
+
+ enum Phase { kBackground, kForeground };
+ void Paint(Phase phase);
+
+ base::Optional<SelectionPaintState>& Selection() { return selection_; }
+
+ private:
+ NGTextPainter& text_painter_;
+ const PaintInfo& paint_info_;
+ const NGInlineCursor& cursor_;
+ const NGFragmentItem& fragment_item_;
+ const PhysicalOffset& box_origin_;
+ const ComputedStyle& style_;
+ base::Optional<SelectionPaintState> selection_;
+ const LayoutObject* layout_object_;
+ Node* node_;
+ const DocumentMarkerVector markers_;
+ const bool skip_backgrounds_;
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
index 3b408445ad0..acddffe60bd 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -7,10 +7,8 @@
#include "third_party/blink/renderer/core/layout/background_bleed_avoidance.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_phase.h"
@@ -30,10 +28,6 @@ bool HasMultipleItems(const Items items) {
return iter != items.end() && ++iter != items.end();
}
-inline bool HasMultiplePaintFragments(const LayoutObject& layout_object) {
- return HasMultipleItems(NGPaintFragment::InlineFragmentsFor(&layout_object));
-}
-
inline bool MayHaveMultipleFragmentItems(const NGFragmentItem& item,
const LayoutObject& layout_object) {
return !item.IsFirstForNode() || !item.IsLastForNode() ||
@@ -54,30 +48,17 @@ PhysicalBoxSides NGInlineBoxFragmentPainter::SidesToInclude() const {
void NGInlineBoxFragmentPainter::Paint(const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
- base::Optional<ScopedDisplayItemFragment> display_item_fragment;
- if (inline_box_item_) {
- display_item_fragment.emplace(paint_info.context,
- inline_box_item_->FragmentId());
- }
+ ScopedDisplayItemFragment display_item_fragment(
+ paint_info.context, inline_box_item_.FragmentId());
const PhysicalOffset adjusted_paint_offset =
- paint_offset + (inline_box_paint_fragment_
- ? inline_box_paint_fragment_->Offset()
- : inline_box_item_->OffsetInContainerBlock());
+ paint_offset + inline_box_item_.OffsetInContainerFragment();
if (paint_info.phase == PaintPhase::kForeground)
PaintBackgroundBorderShadow(paint_info, adjusted_paint_offset);
const bool suppress_box_decoration_background = true;
- if (inline_box_paint_fragment_) {
- NGBoxFragmentPainter box_painter(PhysicalFragment(),
- inline_box_paint_fragment_);
- box_painter.PaintObject(paint_info, adjusted_paint_offset,
- suppress_box_decoration_background);
- return;
- }
DCHECK(inline_box_cursor_);
- DCHECK(inline_box_item_);
- NGBoxFragmentPainter box_painter(*inline_box_cursor_, *inline_box_item_,
+ NGBoxFragmentPainter box_painter(*inline_box_cursor_, inline_box_item_,
PhysicalFragment());
box_painter.PaintObject(paint_info, adjusted_paint_offset,
suppress_box_decoration_background);
@@ -116,27 +97,15 @@ void NGInlineBoxFragmentPainterBase::PaintBackgroundBorderShadow(
DCHECK(inline_box_fragment_.GetLayoutObject());
const LayoutObject& layout_object = *inline_box_fragment_.GetLayoutObject();
- DCHECK(inline_box_paint_fragment_ || inline_box_item_);
bool object_may_have_multiple_boxes =
- inline_box_paint_fragment_
- ? HasMultiplePaintFragments(layout_object)
- : MayHaveMultipleFragmentItems(*inline_box_item_, layout_object);
+ MayHaveMultipleFragmentItems(inline_box_item_, layout_object);
// TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
inline_box_fragment_.GetLayoutObject()));
- if (inline_box_paint_fragment_) {
- NGBoxFragmentPainter box_painter(
- To<NGPhysicalBoxFragment>(inline_box_fragment_),
- inline_box_paint_fragment_);
- PaintBoxDecorationBackground(
- box_painter, paint_info, paint_offset, adjusted_frame_rect, geometry,
- object_may_have_multiple_boxes, SidesToInclude());
- return;
- }
DCHECK(inline_box_cursor_);
NGBoxFragmentPainter box_painter(
- *inline_box_cursor_, *inline_box_item_,
+ *inline_box_cursor_, inline_box_item_,
To<NGPhysicalBoxFragment>(inline_box_fragment_));
PaintBoxDecorationBackground(
box_painter, paint_info, paint_offset, adjusted_frame_rect, geometry,
@@ -145,13 +114,7 @@ void NGInlineBoxFragmentPainterBase::PaintBackgroundBorderShadow(
IntRect NGInlineBoxFragmentPainterBase::VisualRect(
const PhysicalOffset& paint_offset) {
- PhysicalRect overflow_rect;
- if (inline_box_paint_fragment_) {
- overflow_rect = inline_box_paint_fragment_->SelfInkOverflow();
- } else {
- DCHECK(inline_box_item_);
- overflow_rect = inline_box_item_->SelfInkOverflow();
- }
+ PhysicalRect overflow_rect = inline_box_item_.SelfInkOverflow();
overflow_rect.Move(paint_offset);
return EnclosingIntRect(overflow_rect);
}
@@ -162,14 +125,9 @@ void NGLineBoxFragmentPainter::PaintBackgroundBorderShadow(
DCHECK_EQ(paint_info.phase, PaintPhase::kForeground);
DCHECK_EQ(inline_box_fragment_.Type(), NGPhysicalFragment::kFragmentLineBox);
DCHECK(NeedsPaint(inline_box_fragment_));
-#if DCHECK_IS_ON()
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- DCHECK(inline_box_item_);
- // |NGFragmentItem| uses the fragment id when painting the background of
- // line boxes. Please see |NGFragmentItem::kInitialLineFragmentId|.
- DCHECK_NE(paint_info.context.GetPaintController().CurrentFragment(), 0u);
- }
-#endif
+ // |NGFragmentItem| uses the fragment id when painting the background of
+ // line boxes. Please see |NGFragmentItem::kInitialLineFragmentId|.
+ DCHECK_NE(paint_info.context.GetPaintController().CurrentFragment(), 0u);
if (line_style_ == style_ ||
line_style_.Visibility() != EVisibility::kVisible)
@@ -208,7 +166,7 @@ void NGLineBoxFragmentPainter::PaintBackgroundBorderShadow(
const LayoutBlockFlow& layout_block_flow =
*To<LayoutBlockFlow>(block_fragment_.GetLayoutObject());
BackgroundImageGeometry geometry(layout_block_flow);
- NGBoxFragmentPainter box_painter(block_fragment_, block_paint_fragment_);
+ NGBoxFragmentPainter box_painter(block_fragment_);
PaintBoxDecorationBackground(
box_painter, paint_info, paint_offset, rect, geometry,
/*object_has_multiple_boxes*/ false, PhysicalBoxSides());
@@ -228,19 +186,10 @@ void NGInlineBoxFragmentPainterBase::ComputeFragmentOffsetOnLine(
LayoutUnit after;
bool before_self = true;
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
- if (inline_box_paint_fragment_) {
- DCHECK(cursor.CurrentPaintFragment());
- if (cursor.CurrentPaintFragment() == inline_box_paint_fragment_) {
- before_self = false;
- continue;
- }
- } else {
- DCHECK(inline_box_item_);
- DCHECK(cursor.CurrentItem());
- if (cursor.CurrentItem() == inline_box_item_) {
- before_self = false;
- continue;
- }
+ DCHECK(cursor.CurrentItem());
+ if (cursor.CurrentItem() == &inline_box_item_) {
+ before_self = false;
+ continue;
}
const NGPhysicalBoxFragment* box_fragment = cursor.Current().BoxFragment();
DCHECK(box_fragment);
@@ -281,28 +230,6 @@ PhysicalRect NGInlineBoxFragmentPainterBase::PaintRectForImageStrip(
paint_rect.Width(), total_width);
}
-static PhysicalRect NGClipRectForNinePieceImageStrip(
- const ComputedStyle& style,
- PhysicalBoxSides sides_to_include,
- const NinePieceImage& image,
- const PhysicalRect& paint_rect) {
- PhysicalRect clip_rect(paint_rect);
- LayoutRectOutsets outsets = style.ImageOutsets(image);
- if (sides_to_include.left) {
- clip_rect.SetX(paint_rect.X() - outsets.Left());
- clip_rect.SetWidth(paint_rect.Width() + outsets.Left());
- }
- if (sides_to_include.right)
- clip_rect.SetWidth(clip_rect.Width() + outsets.Right());
- if (sides_to_include.top) {
- clip_rect.SetY(paint_rect.Y() - outsets.Top());
- clip_rect.SetHeight(paint_rect.Height() + outsets.Top());
- }
- if (sides_to_include.bottom)
- clip_rect.SetHeight(clip_rect.Height() + outsets.Bottom());
- return clip_rect;
-}
-
InlineBoxPainterBase::BorderPaintingType
NGInlineBoxFragmentPainterBase::GetBorderPaintType(
const PhysicalRect& adjusted_frame_rect,
@@ -328,7 +255,7 @@ NGInlineBoxFragmentPainterBase::GetBorderPaintType(
}
// We have a border image that spans multiple lines.
- adjusted_clip_rect = PixelSnappedIntRect(NGClipRectForNinePieceImageStrip(
+ adjusted_clip_rect = PixelSnappedIntRect(ClipRectForNinePieceImageStrip(
style, SidesToInclude(), border_image, adjusted_frame_rect));
return kPaintBordersWithClip;
}
@@ -360,24 +287,6 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
if (UNLIKELY(block_flow->NeedsLayout()))
return;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_inline);
-
- // TODO(kojii): The root of this inline formatting context should have a
- // PaintFragment, but it looks like there's a case it doesn't stand.
- // crbug.com/969096
- CHECK(block_flow->PaintFragment() || fragments.IsEmpty());
-
- for (const NGPaintFragment* fragment : fragments) {
- PhysicalOffset child_offset = paint_offset +
- fragment->OffsetInContainerBlock() -
- fragment->Offset();
- DCHECK(fragment->PhysicalFragment().IsBox());
- NGInlineBoxFragmentPainter(*fragment).Paint(paint_info, child_offset);
- }
- return;
- }
-
NGInlineCursor cursor(*block_flow);
cursor.MoveTo(layout_inline);
if (!cursor)
@@ -386,10 +295,10 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
// inline may not start in the first fragment generated for the inline
// formatting context.
wtf_size_t target_fragment_idx =
- cursor.CurrentContainerFragmentIndex() +
+ cursor.ContainerFragmentIndex() +
paint_info.context.GetPaintController().CurrentFragment();
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
- if (target_fragment_idx != cursor.CurrentContainerFragmentIndex())
+ if (target_fragment_idx != cursor.ContainerFragmentIndex())
continue;
const NGFragmentItem* item = cursor.CurrentItem();
DCHECK(item);
@@ -402,10 +311,8 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
#if DCHECK_IS_ON()
void NGInlineBoxFragmentPainter::CheckValid() const {
- if (inline_box_item_) {
- DCHECK(inline_box_cursor_);
- DCHECK_EQ(inline_box_cursor_->Current().Item(), inline_box_item_);
- }
+ DCHECK(inline_box_cursor_);
+ DCHECK_EQ(inline_box_cursor_->Current().Item(), &inline_box_item_);
DCHECK_EQ(inline_box_fragment_.Type(),
NGPhysicalFragment::NGFragmentType::kFragmentBox);
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
index 9fca9c9d035..458ff7e3135 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
@@ -13,7 +13,6 @@
namespace blink {
-class NGPaintFragment;
struct PaintInfo;
struct PhysicalRect;
@@ -28,56 +27,30 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
LayoutUnit* total_width) const;
protected:
- NGInlineBoxFragmentPainterBase(
- const NGPhysicalFragment& inline_box_fragment,
- const NGInlineCursor* inline_box_cursor,
- const NGPaintFragment* inline_box_paint_fragment,
- const NGFragmentItem* inline_box_item,
- const LayoutObject& layout_object,
- const ComputedStyle& style,
- const ComputedStyle& line_style)
+ NGInlineBoxFragmentPainterBase(const NGPhysicalFragment& inline_box_fragment,
+ const NGInlineCursor* inline_box_cursor,
+ const NGFragmentItem& inline_box_item,
+ const LayoutObject& layout_object,
+ const ComputedStyle& style,
+ const ComputedStyle& line_style)
: InlineBoxPainterBase(layout_object,
&layout_object.GetDocument(),
layout_object.GeneratingNode(),
style,
line_style),
inline_box_fragment_(inline_box_fragment),
- inline_box_paint_fragment_(inline_box_paint_fragment),
inline_box_item_(inline_box_item),
inline_box_cursor_(inline_box_cursor) {
#if DCHECK_IS_ON()
- if (inline_box_cursor) {
- DCHECK(inline_box_item);
- DCHECK_EQ(inline_box_cursor->Current().Item(), inline_box_item);
- }
- if (inline_box_paint_fragment) {
- DCHECK_EQ(&inline_box_paint_fragment->PhysicalFragment(),
- &inline_box_fragment);
- DCHECK(!inline_box_item);
- } else if (inline_box_item) {
- if (inline_box_item->BoxFragment())
- DCHECK_EQ(inline_box_item->BoxFragment(), &inline_box_fragment);
- else
- DCHECK_EQ(inline_box_item->LineBoxFragment(), &inline_box_fragment);
- } else {
- NOTREACHED();
- }
+ if (inline_box_cursor)
+ DCHECK_EQ(inline_box_cursor->Current().Item(), &inline_box_item);
+ if (inline_box_item.BoxFragment())
+ DCHECK_EQ(inline_box_item.BoxFragment(), &inline_box_fragment);
+ else
+ DCHECK_EQ(inline_box_item.LineBoxFragment(), &inline_box_fragment);
#endif
}
- // Constructor for |NGPaintFragment|.
- NGInlineBoxFragmentPainterBase(const NGPaintFragment& inline_box_fragment,
- const LayoutObject& layout_object,
- const ComputedStyle& style,
- const ComputedStyle& line_style)
- : NGInlineBoxFragmentPainterBase(inline_box_fragment.PhysicalFragment(),
- /* inline_box_cursor */ nullptr,
- &inline_box_fragment,
- /* inline_box_item */ nullptr,
- layout_object,
- style,
- line_style) {}
-
// Constructor for |NGFragmentItem|.
NGInlineBoxFragmentPainterBase(
const NGInlineCursor& inline_box_cursor,
@@ -88,17 +61,14 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
const ComputedStyle& line_style)
: NGInlineBoxFragmentPainterBase(inline_box_fragment,
&inline_box_cursor,
- /* inline_box_paint_fragment */ nullptr,
- &inline_box_item,
+ inline_box_item,
layout_object,
style,
line_style) {}
const DisplayItemClient& GetDisplayItemClient() const {
- if (inline_box_paint_fragment_)
- return *inline_box_paint_fragment_;
- DCHECK(inline_box_item_);
- return *inline_box_item_->GetDisplayItemClient();
+ DCHECK(inline_box_item_.GetDisplayItemClient());
+ return *inline_box_item_.GetDisplayItemClient();
}
virtual PhysicalBoxSides SidesToInclude() const = 0;
@@ -123,8 +93,7 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
IntRect VisualRect(const PhysicalOffset& paint_offset);
const NGPhysicalFragment& inline_box_fragment_;
- const NGPaintFragment* inline_box_paint_fragment_ = nullptr;
- const NGFragmentItem* inline_box_item_ = nullptr;
+ const NGFragmentItem& inline_box_item_;
const NGInlineCursor* inline_box_cursor_ = nullptr;
};
@@ -134,18 +103,6 @@ class NGInlineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
STACK_ALLOCATED();
public:
- // Constructor for |NGPaintFragment|.
- NGInlineBoxFragmentPainter(const NGPaintFragment& inline_box_fragment)
- : NGInlineBoxFragmentPainterBase(inline_box_fragment,
- *inline_box_fragment.GetLayoutObject(),
- inline_box_fragment.Style(),
- inline_box_fragment.Style()) {
- DCHECK_EQ(inline_box_fragment.PhysicalFragment().Type(),
- NGPhysicalFragment::NGFragmentType::kFragmentBox);
- DCHECK_EQ(inline_box_fragment.PhysicalFragment().BoxType(),
- NGPhysicalFragment::NGBoxType::kInlineBox);
- }
-
// Constructor for |NGFragmentItem|.
NGInlineBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& inline_box_item,
@@ -194,15 +151,11 @@ class NGLineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
public:
NGLineBoxFragmentPainter(const NGPhysicalFragment& line_box_fragment,
- const NGPaintFragment* line_box_paint_fragment,
- const NGFragmentItem* line_box_item,
- const NGPhysicalBoxFragment& block_fragment,
- const NGPaintFragment* block_paint_fragment)
+ const NGFragmentItem& line_box_item,
+ const NGPhysicalBoxFragment& block_fragment)
: NGLineBoxFragmentPainter(line_box_fragment,
- line_box_paint_fragment,
line_box_item,
block_fragment,
- block_paint_fragment,
*block_fragment.GetLayoutObject()) {}
static bool NeedsPaint(const NGPhysicalFragment& line_fragment) {
@@ -218,15 +171,12 @@ class NGLineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
private:
NGLineBoxFragmentPainter(const NGPhysicalFragment& line_box_fragment,
- const NGPaintFragment* line_box_paint_fragment,
- const NGFragmentItem* line_box_item,
+ const NGFragmentItem& line_box_item,
const NGPhysicalBoxFragment& block_fragment,
- const NGPaintFragment* block_paint_fragment,
const LayoutObject& layout_block_flow)
: NGInlineBoxFragmentPainterBase(
line_box_fragment,
/* inline_box_cursor */ nullptr,
- line_box_paint_fragment,
line_box_item,
layout_block_flow,
// Use the style from the containing block. |line_fragment.Style()|
@@ -235,8 +185,7 @@ class NGLineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
// TODO(kojii): Reconsider |line_fragment.Style()|.
layout_block_flow.StyleRef(),
layout_block_flow.FirstLineStyleRef()),
- block_fragment_(block_fragment),
- block_paint_fragment_(block_paint_fragment) {
+ block_fragment_(block_fragment) {
DCHECK_EQ(line_box_fragment.Type(),
NGPhysicalFragment::NGFragmentType::kFragmentLineBox);
DCHECK(NeedsPaint(line_box_fragment));
@@ -250,7 +199,6 @@ class NGLineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
PhysicalBoxSides SidesToInclude() const final { return PhysicalBoxSides(); }
const NGPhysicalBoxFragment& block_fragment_;
- const NGPaintFragment* block_paint_fragment_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
index 17041ddec71..d764b2f2567 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/mathml/mathml_radical_element.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
deleted file mode 100644
index ee1c7867839..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ /dev/null
@@ -1,992 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-
-#include "third_party/blink/renderer/core/dom/pseudo_element.h"
-#include "third_party/blink/renderer/core/editing/bidi_adjustment.h"
-#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
-#include "third_party/blink/renderer/core/editing/text_affinity.h"
-#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
-#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
-#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
-
-namespace blink {
-
-namespace {
-
-struct SameSizeAsNGPaintFragment : public RefCounted<NGPaintFragment>,
- public DisplayItemClient {
- void* pointers[7];
- PhysicalOffset offsets[2];
- unsigned flags;
-};
-
-ASSERT_SIZE(NGPaintFragment, SameSizeAsNGPaintFragment);
-
-LogicalRect ExpandedSelectionRectForSoftLineBreakIfNeeded(
- const LogicalRect& rect,
- const NGInlineCursor& cursor,
- const LayoutSelectionStatus& selection_status) {
- // Expand paint rect if selection covers multiple lines and
- // this fragment is at the end of line.
- if (selection_status.line_break == SelectSoftLineBreak::kNotSelected)
- return rect;
- const LayoutBlockFlow* const layout_block_flow = cursor.GetLayoutBlockFlow();
- if (layout_block_flow && layout_block_flow->ShouldTruncateOverflowingText())
- return rect;
- // Copy from InlineTextBoxPainter::PaintSelection.
- const LayoutUnit space_width(cursor.Current().Style().GetFont().SpaceWidth());
- return {rect.offset,
- {rect.size.inline_size + space_width, rect.size.block_size}};
-}
-
-// Expands selection height so that the selection rect fills entire line.
-LogicalRect ExpandSelectionRectToLineHeight(
- const LogicalRect& rect,
- const LogicalRect& line_logical_rect) {
- // Unite the rect only in the block direction.
- const LayoutUnit selection_top =
- std::min(rect.offset.block_offset, line_logical_rect.offset.block_offset);
- const LayoutUnit selection_bottom =
- std::max(rect.BlockEndOffset(), line_logical_rect.BlockEndOffset());
- return {{rect.offset.inline_offset, selection_top},
- {rect.size.inline_size, selection_bottom - selection_top}};
-}
-
-LogicalRect ExpandSelectionRectToLineHeight(const LogicalRect& rect,
- const NGInlineCursor& cursor) {
- NGInlineCursor line(cursor);
- line.MoveToContainingLine();
- const PhysicalRect line_physical_rect(
- line.Current().OffsetInContainerBlock() -
- cursor.Current().OffsetInContainerBlock(),
- line.Current().Size());
- return ExpandSelectionRectToLineHeight(
- rect, cursor.Current().ConvertChildToLogical(line_physical_rect));
-}
-
-base::Optional<PositionWithAffinity> PositionForPointInChild(
- const NGPaintFragment& child,
- const PhysicalOffset& point) {
- const PhysicalOffset& child_point = point - child.Offset();
- // We must fallback to legacy for old layout roots. We also fallback (to
- // LayoutNGMixin::PositionForPoint()) for NG block layout, so that we can
- // utilize LayoutBlock::PositionForPoint() that resolves the position in block
- // layout.
- // TODO(xiaochengh): Don't fallback to legacy for NG block layout.
- const bool should_fallback = child.PhysicalFragment().IsBlockFlow() ||
- child.PhysicalFragment().IsLegacyLayoutRoot();
- const PositionWithAffinity result =
- should_fallback ? child.GetLayoutObject()->PositionForPoint(child_point)
- : child.PositionForPoint(child_point);
- if (result.IsNotNull())
- return result;
- return base::nullopt;
-}
-
-bool IsLastBRInPage(const LayoutObject& layout_object) {
- return layout_object.IsBR() && !layout_object.NextInPreOrder();
-}
-
-} // namespace
-
-NGPaintFragment::NGPaintFragment(
- scoped_refptr<const NGPhysicalFragment> fragment,
- PhysicalOffset offset,
- NGPaintFragment* parent)
- : physical_fragment_(std::move(fragment)),
- offset_(offset),
- parent_(parent),
- is_layout_object_destroyed_(false),
- is_dirty_inline_(false) {
- // TODO(crbug.com/924449): Once we get the caller passes null physical
- // fragment, we'll change to DCHECK().
- CHECK(physical_fragment_);
-}
-
-void NGPaintFragment::DestroyAll(scoped_refptr<NGPaintFragment> fragment) {
- DCHECK(fragment);
- while (fragment) {
- fragment = std::move(fragment->next_sibling_);
- }
-}
-
-void NGPaintFragment::RemoveChildren() {
- if (first_child_) {
- DestroyAll(std::move(first_child_));
- DCHECK(!first_child_);
- }
-}
-
-NGPaintFragment::~NGPaintFragment() {
- // The default destructor will deref |first_child_|, but because children are
- // in a linked-list, it will call this destructor recursively. Remove children
- // first non-recursively to avoid stack overflow when there are many chlidren.
- RemoveChildren();
-}
-
-void NGPaintFragment::CreateContext::SkipDestroyedPreviousInstances() {
- while (UNLIKELY(previous_instance && !previous_instance->IsAlive())) {
- previous_instance = std::move(previous_instance->next_sibling_);
- painting_layer_needs_repaint = true;
- }
-}
-
-void NGPaintFragment::CreateContext::DestroyPreviousInstances() {
- if (previous_instance) {
- DestroyAll(previous_instance);
- painting_layer_needs_repaint = true;
- }
-}
-
-template <typename Traverse>
-NGPaintFragment& NGPaintFragment::List<Traverse>::front() const {
- DCHECK(first_);
- return *first_;
-}
-
-template <typename Traverse>
-NGPaintFragment& NGPaintFragment::List<Traverse>::back() const {
- DCHECK(first_);
- NGPaintFragment* last = first_;
- for (NGPaintFragment* fragment : *this)
- last = fragment;
- return *last;
-}
-
-template <typename Traverse>
-wtf_size_t NGPaintFragment::List<Traverse>::size() const {
- wtf_size_t size = 0;
- for (NGPaintFragment* fragment : *this) {
- ANALYZER_ALLOW_UNUSED(fragment);
- ++size;
- }
- return size;
-}
-
-template <typename Traverse>
-void NGPaintFragment::List<Traverse>::ToList(
- Vector<NGPaintFragment*, 16>* list) const {
- if (UNLIKELY(!list->IsEmpty()))
- list->Shrink(0);
- if (IsEmpty())
- return;
- list->ReserveCapacity(size());
- for (NGPaintFragment* fragment : *this)
- list->push_back(fragment);
-}
-
-void NGPaintFragment::SetShouldDoFullPaintInvalidation() {
- if (LayoutObject* layout_object = GetMutableLayoutObject())
- layout_object->SetShouldDoFullPaintInvalidation();
-}
-
-scoped_refptr<NGPaintFragment> NGPaintFragment::CreateOrReuse(
- scoped_refptr<const NGPhysicalFragment> fragment,
- PhysicalOffset offset,
- CreateContext* context) {
- DCHECK(fragment);
-
- // If the previous instance is given, check if it is re-usable.
- // Re-using NGPaintFragment allows the paint system to identify objects.
- context->SkipDestroyedPreviousInstances();
- if (context->previous_instance) {
- // Take the first instance of previous instances, leaving its following
- // siblings at |context->previous_instance|. There is a trade-off between
- // faster check of reusability and higher reuse ratio. The current algorithm
- // assumes that the index of children does not change. If there were
- // insertions/deletions, all following instances will not match.
- scoped_refptr<NGPaintFragment> previous_instance =
- std::move(context->previous_instance);
- context->previous_instance = std::move(previous_instance->next_sibling_);
- DCHECK_EQ(previous_instance->parent_, context->parent);
- DCHECK(!previous_instance->next_sibling_);
-
-// TODO(kojii): This fails some tests when reusing line box was enabled.
-// Investigate and re-enable.
-#if 0
- // If the physical fragment was re-used, re-use the paint fragment as well.
- if (&previous_instance->PhysicalFragment() == fragment.get()) {
- previous_instance->offset_ = offset;
- previous_instance->next_for_same_layout_object_ = nullptr;
- previous_instance->is_dirty_inline_ = false;
- // No need to re-populate children because NGPhysicalFragment is
- // immutable and thus children should not have been changed.
- *populate_children = false;
- previous_instance->SetShouldDoFullPaintInvalidation();
- return previous_instance;
- }
-#endif
-
- // If the LayoutObject are the same, the new paint fragment should have the
- // same DisplayItemClient identity as the previous instance.
- if (previous_instance->GetLayoutObject() == fragment->GetLayoutObject()) {
- previous_instance->physical_fragment_ = std::move(fragment);
- previous_instance->offset_ = offset;
- previous_instance->next_for_same_layout_object_ = nullptr;
- CHECK(previous_instance->IsAlive());
- previous_instance->is_dirty_inline_ = false;
- // Destroy children of previous instances if the new instance doesn't have
- // any children. Otherwise keep them in case these previous children maybe
- // reused to populate children.
- if (!context->populate_children && previous_instance->first_child_) {
- context->painting_layer_needs_repaint = true;
- previous_instance->RemoveChildren();
- }
- return previous_instance;
- }
-
- // Mark needing to repaint because exiting the scope here destroys an unused
- // previous instance.
- context->painting_layer_needs_repaint = true;
- }
-
- scoped_refptr<NGPaintFragment> new_instance = base::AdoptRef(
- new NGPaintFragment(std::move(fragment), offset, context->parent));
- return new_instance;
-}
-
-scoped_refptr<NGPaintFragment> NGPaintFragment::Create(
- scoped_refptr<const NGPhysicalFragment> fragment,
- const NGBlockBreakToken* block_break_token,
- scoped_refptr<NGPaintFragment> previous_instance) {
- DCHECK(fragment);
-
- bool has_previous_instance = previous_instance.get();
- CreateContext context(std::move(previous_instance), fragment->IsContainer());
- scoped_refptr<NGPaintFragment> paint_fragment =
- CreateOrReuse(std::move(fragment), PhysicalOffset(), &context);
-
- if (context.populate_children) {
- if (has_previous_instance) {
- NGInlineNode::ClearAssociatedFragments(paint_fragment->PhysicalFragment(),
- block_break_token);
- }
- HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map;
- context.last_fragment_map = &last_fragment_map;
- paint_fragment->PopulateDescendants(&context);
- }
-
- context.DestroyPreviousInstances();
- if (context.painting_layer_needs_repaint) {
- ObjectPaintInvalidator(*paint_fragment->GetLayoutObject())
- .SlowSetPaintingLayerNeedsRepaint();
- }
-
- return paint_fragment;
-}
-
-scoped_refptr<NGPaintFragment>* NGPaintFragment::Find(
- scoped_refptr<NGPaintFragment>* fragment,
- const NGBlockBreakToken* break_token) {
- DCHECK(fragment);
-
- if (!break_token)
- return fragment;
-
- while (true) {
- // TODO(kojii): Sometimes an unknown break_token is given. Need to
- // investigate why, and handle appropriately. For now, just keep it to avoid
- // crashes and use-after-free.
- if (!*fragment)
- return fragment;
-
- scoped_refptr<NGPaintFragment>* next = &(*fragment)->next_fragmented_;
- auto* container =
- DynamicTo<NGPhysicalContainerFragment>((*fragment)->PhysicalFragment());
- if (container && container->BreakToken() == break_token)
- return next;
- fragment = next;
- }
- NOTREACHED();
-}
-
-bool NGPaintFragment::IsDescendantOfNotSelf(
- const NGPaintFragment& ancestor) const {
- for (const NGPaintFragment* fragment = Parent(); fragment;
- fragment = fragment->Parent()) {
- if (fragment == &ancestor)
- return true;
- }
- return false;
-}
-
-bool NGPaintFragment::IsEllipsis() const {
- if (auto* text_fragment =
- DynamicTo<NGPhysicalTextFragment>(PhysicalFragment()))
- return text_fragment->IsEllipsis();
- return false;
-}
-
-bool NGPaintFragment::HasSelfPaintingLayer() const {
- return PhysicalFragment().HasSelfPaintingLayer();
-}
-
-bool NGPaintFragment::ShouldClipOverflowAlongBothAxis() const {
- auto* box_physical_fragment =
- DynamicTo<NGPhysicalBoxFragment>(&PhysicalFragment());
- return box_physical_fragment &&
- box_physical_fragment->ShouldClipOverflowAlongBothAxis();
-}
-
-// Populate descendants from NGPhysicalFragment tree.
-void NGPaintFragment::PopulateDescendants(CreateContext* parent_context) {
- const NGPhysicalFragment& fragment = PhysicalFragment();
- const auto& container = To<NGPhysicalContainerFragment>(fragment);
- CreateContext child_context(parent_context, this);
- // Children should have been moved to |child_context| for possible reuse.
- DCHECK(!first_child_);
- scoped_refptr<NGPaintFragment>* last_child_ptr = &first_child_;
-
- auto* box_physical_fragment = DynamicTo<NGPhysicalBoxFragment>(fragment);
- bool is_inline_fc = !box_physical_fragment ||
- box_physical_fragment->IsInlineFormattingContext();
-
- for (const NGLink& child_fragment : container.Children()) {
- child_fragment->CheckType();
-
- // OOF objects are not needed because they always have self painting layer.
- if (UNLIKELY(child_fragment->IsOutOfFlowPositioned()))
- continue;
-
- child_context.populate_children =
- child_fragment->IsContainer() &&
- !child_fragment->IsFormattingContextRoot();
- scoped_refptr<NGPaintFragment> child = CreateOrReuse(
- child_fragment.get(), child_fragment.Offset(), &child_context);
-
- if (is_inline_fc) {
- DCHECK(!child_fragment->IsOutOfFlowPositioned());
- if (child_fragment->IsText() || child_fragment->IsInlineBox() ||
- child_fragment->IsAtomicInline()) {
- child->AssociateWithLayoutObject(
- child_fragment->GetMutableLayoutObject(),
- child_context.last_fragment_map);
- child->inline_offset_to_container_box_ =
- inline_offset_to_container_box_ + child_fragment.Offset();
- } else if (child_fragment->IsLineBox()) {
- child->inline_offset_to_container_box_ =
- inline_offset_to_container_box_ + child_fragment.Offset();
- } else {
- DCHECK(child_fragment->IsFloating() || child_fragment->IsListMarker());
- }
-
- if (child_context.populate_children) {
- child->PopulateDescendants(&child_context);
- }
- }
-
- DCHECK(!*last_child_ptr);
- *last_child_ptr = std::move(child);
- last_child_ptr = &((*last_child_ptr)->next_sibling_);
- }
-
- // Destroy unused previous instances if any, and propagate states to the
- // parent context.
- child_context.DestroyPreviousInstances();
- parent_context->painting_layer_needs_repaint |=
- child_context.painting_layer_needs_repaint;
-}
-
-// Add to a linked list for each LayoutObject.
-void NGPaintFragment::AssociateWithLayoutObject(
- LayoutObject* layout_object,
- HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) {
- DCHECK(layout_object);
- DCHECK(!next_for_same_layout_object_);
- DCHECK(layout_object->IsInline());
- DCHECK(PhysicalFragment().IsInline());
-
- auto add_result = last_fragment_map->insert(layout_object, this);
- NGPaintFragment* last_fragment;
- if (add_result.is_new_entry) {
- NGPaintFragment* first_fragment = layout_object->FirstInlineFragment();
- if (!first_fragment) {
- layout_object->SetFirstInlineFragment(this);
- return;
- }
- // This |layout_object| was fragmented across multiple blocks.
- last_fragment = first_fragment->LastForSameLayoutObject();
- } else {
- last_fragment = add_result.stored_value->value;
- DCHECK(last_fragment) << layout_object;
- add_result.stored_value->value = this;
- }
- DCHECK_EQ(layout_object, last_fragment->GetLayoutObject());
- DCHECK_NE(this, last_fragment);
- last_fragment->next_for_same_layout_object_ = this;
-}
-
-// TODO(kojii): Consider unifying this with
-// NGInlineNode::ClearAssociatedFragments.
-void NGPaintFragment::ClearAssociationWithLayoutObject() {
- // TODO(kojii): Support break_token for LayoutObject that spans across block
- // fragmentation boundaries.
- LayoutObject* last_object = nullptr;
- for (NGPaintFragment* child : Children()) {
- const NGPhysicalFragment& fragment = child->PhysicalFragment();
- if (fragment.IsInline()) {
- LayoutObject* object = fragment.GetMutableLayoutObject();
- if (object && object != last_object) {
- // |IsInLayoutNGInlineFormattingContext()| is cleared if its
- // NGInlineItem was invalidted.
- if (object->IsInLayoutNGInlineFormattingContext())
- object->SetFirstInlineFragment(nullptr);
- last_object = object;
- }
- }
- if (fragment.IsLineBox() || fragment.IsInlineBox() ||
- fragment.IsFragmentainerBox()) {
- child->ClearAssociationWithLayoutObject();
- } else {
- DCHECK(fragment.IsText() || fragment.IsFormattingContextRoot());
- DCHECK(child->Children().IsEmpty());
- }
- }
-}
-
-NGPaintFragment::FragmentRange NGPaintFragment::InlineFragmentsFor(
- const LayoutObject* layout_object) {
- DCHECK(layout_object);
- DCHECK(layout_object->IsInline());
- DCHECK(!layout_object->IsFloatingOrOutOfFlowPositioned());
-
- if (layout_object->IsInLayoutNGInlineFormattingContext())
- return FragmentRange(layout_object->FirstInlineFragment());
- return FragmentRange(nullptr, false);
-}
-
-const NGPaintFragment* NGPaintFragment::LastForSameLayoutObject() const {
- return const_cast<NGPaintFragment*>(this)->LastForSameLayoutObject();
-}
-
-NGPaintFragment* NGPaintFragment::LastForSameLayoutObject() {
- NGPaintFragment* fragment = this;
- while (fragment->next_for_same_layout_object_)
- fragment = fragment->next_for_same_layout_object_;
- return fragment;
-}
-
-void NGPaintFragment::LayoutObjectWillBeDestroyed() {
- for (NGPaintFragment* fragment = this; fragment;
- fragment = fragment->next_for_same_layout_object_) {
- fragment->is_layout_object_destroyed_ = true;
- // TODO(crbug.com/1033203): We should call this, but this seems to crash.
- // fragment->PhysicalFragment().LayoutObjectWillBeDestroyed();
- }
-}
-
-const LayoutBox* NGPaintFragment::InkOverflowOwnerBox() const {
- const NGPhysicalFragment& fragment = PhysicalFragment();
- if (fragment.IsBox() && !fragment.IsInlineBox())
- return To<LayoutBox>(fragment.GetLayoutObject());
- return nullptr;
-}
-
-PhysicalRect NGPaintFragment::SelfInkOverflow() const {
- // Get the cached value in |LayoutBox| if there is one.
- if (const LayoutBox* box = InkOverflowOwnerBox())
- return box->PhysicalSelfVisualOverflowRect();
-
- // NGPhysicalTextFragment caches ink overflow in layout.
- const NGPhysicalFragment& fragment = PhysicalFragment();
- if (const auto* text = DynamicTo<NGPhysicalTextFragment>(fragment))
- return text->SelfInkOverflow();
-
- if (!ink_overflow_)
- return fragment.LocalRect();
- return ink_overflow_->ink_overflow;
-}
-
-PhysicalRect NGPaintFragment::InkOverflow() const {
- // Get the cached value in |LayoutBox| if there is one.
- if (const LayoutBox* box = InkOverflowOwnerBox())
- return box->PhysicalVisualOverflowRect();
-
- // NGPhysicalTextFragment caches ink overflow in layout.
- const NGPhysicalFragment& fragment = PhysicalFragment();
- if (const auto* text = DynamicTo<NGPhysicalTextFragment>(fragment))
- return text->SelfInkOverflow();
-
- if (!ink_overflow_)
- return fragment.LocalRect();
-
- if (HasNonVisibleOverflow())
- return ink_overflow_->ink_overflow;
-
- PhysicalRect rect = ink_overflow_->ink_overflow;
- rect.Unite(ink_overflow_->contents_ink_overflow);
- return rect;
-}
-
-void NGPaintFragment::RecalcInlineChildrenInkOverflow() const {
- DCHECK(GetLayoutObject()->ChildrenInline());
- RecalcContentsInkOverflow();
-}
-
-PhysicalRect NGPaintFragment::RecalcContentsInkOverflow() const {
- PhysicalRect contents_rect;
- for (NGPaintFragment* child : Children()) {
- const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
- PhysicalRect child_rect;
-
- // A BFC root establishes a separate NGPaintFragment tree. Re-compute the
- // child tree using its LayoutObject, because it may not be NG.
- if (child_fragment.IsFormattingContextRoot()) {
- auto* layout_box = To<LayoutBox>(child_fragment.GetMutableLayoutObject());
- layout_box->RecalcVisualOverflow();
- child_rect = PhysicalRect(layout_box->VisualOverflowRect());
- } else {
- child_rect = child->RecalcInkOverflow();
- }
- if (child->HasSelfPaintingLayer())
- continue;
- if (!child_rect.IsEmpty()) {
- child_rect.offset += child->Offset();
- contents_rect.Unite(child_rect);
- }
- }
- return contents_rect;
-}
-
-PhysicalRect NGPaintFragment::RecalcInkOverflow() {
- const NGPhysicalFragment& fragment = PhysicalFragment();
- fragment.CheckCanUpdateInkOverflow();
- DCHECK(!fragment.IsFormattingContextRoot());
-
- // NGPhysicalTextFragment caches ink overflow in layout. No need to recalc nor
- // to store in NGPaintFragment.
- if (const auto* text = DynamicTo<NGPhysicalTextFragment>(&fragment)) {
- DCHECK(!ink_overflow_);
- return text->SelfInkOverflow();
- }
-
- PhysicalRect self_rect;
- PhysicalRect contents_rect;
- PhysicalRect self_and_contents_rect;
- if (fragment.IsLineBox()) {
- // Line boxes don't have self overflow. Compute content overflow only.
- contents_rect = RecalcContentsInkOverflow();
- self_and_contents_rect = contents_rect;
- } else if (const auto* box_fragment =
- DynamicTo<NGPhysicalBoxFragment>(fragment)) {
- contents_rect = RecalcContentsInkOverflow();
- self_rect = box_fragment->ComputeSelfInkOverflow();
- self_and_contents_rect = self_rect;
- self_and_contents_rect.Unite(contents_rect);
- } else {
- NOTREACHED();
- }
-
- DCHECK(!InkOverflowOwnerBox());
- if (fragment.LocalRect().Contains(self_and_contents_rect)) {
- ink_overflow_.reset();
- } else if (!ink_overflow_) {
- ink_overflow_ =
- std::make_unique<NGContainerInkOverflow>(self_rect, contents_rect);
- } else {
- ink_overflow_->ink_overflow = self_rect;
- ink_overflow_->contents_ink_overflow = contents_rect;
- }
- return self_and_contents_rect;
-}
-
-base::Optional<PhysicalRect> NGPaintFragment::LocalVisualRectFor(
- const LayoutObject& layout_object) {
- auto fragments = InlineFragmentsFor(&layout_object);
- if (!fragments.IsInLayoutNGInlineFormattingContext())
- return base::nullopt;
-
- PhysicalRect visual_rect;
- for (NGPaintFragment* fragment : fragments) {
- if (fragment->PhysicalFragment().IsHiddenForPaint())
- continue;
- PhysicalRect child_visual_rect = fragment->SelfInkOverflow();
- child_visual_rect.offset += fragment->OffsetInContainerBlock();
- visual_rect.Unite(child_visual_rect);
- }
- return visual_rect;
-}
-
-const NGPaintFragment* NGPaintFragment::ContainerLineBox() const {
- DCHECK(PhysicalFragment().IsInline());
- for (const NGPaintFragment* fragment :
- NGPaintFragmentTraversal::InclusiveAncestorsOf(*this)) {
- if (fragment->PhysicalFragment().IsLineBox())
- return fragment;
- }
- NOTREACHED();
- return nullptr;
-}
-
-NGPaintFragment* NGPaintFragment::FirstLineBox() const {
- for (NGPaintFragment* child : Children()) {
- if (child->PhysicalFragment().IsLineBox())
- return child;
- }
- return nullptr;
-}
-
-const NGPaintFragment* NGPaintFragment::Root() const {
- // Because of this function can be called during |LayoutObject::Destroy()|,
- // we use |physical_fragment_| to avoid calling |IsAlive()|.
- DCHECK(physical_fragment_->IsInline());
- const NGPaintFragment* root = this;
- for (const NGPaintFragment* fragment :
- NGPaintFragmentTraversal::InclusiveAncestorsOf(*this)) {
- root = fragment;
- }
- return root;
-}
-
-void NGPaintFragment::SetShouldDoFullPaintInvalidationRecursively() {
- if (LayoutObject* layout_object = GetMutableLayoutObject()) {
- layout_object->StyleRef().ClearCachedPseudoElementStyles();
- layout_object->SetShouldDoFullPaintInvalidation();
- }
- for (NGPaintFragment* child : Children())
- child->SetShouldDoFullPaintInvalidationRecursively();
-}
-
-void NGPaintFragment::SetShouldDoFullPaintInvalidationForFirstLine() const {
- DCHECK(PhysicalFragment().IsBox() && GetLayoutObject() &&
- GetLayoutObject()->IsLayoutBlockFlow());
-
- if (NGPaintFragment* line_box = FirstLineBox()) {
- line_box->SetShouldDoFullPaintInvalidationRecursively();
- GetLayoutObject()->StyleRef().ClearCachedPseudoElementStyles();
- GetMutableLayoutObject()->SetShouldDoFullPaintInvalidation();
- }
-}
-
-// TODO(yosin): We should move |ComputeLocalSelectionRectForText()| to
-// "ng_selection_painter.cc".
-PhysicalRect ComputeLocalSelectionRectForText(
- const NGInlineCursor& cursor,
- const LayoutSelectionStatus& selection_status) {
- const PhysicalRect selection_rect =
- cursor.CurrentLocalRect(selection_status.start, selection_status.end);
- LogicalRect logical_rect =
- cursor.Current().ConvertChildToLogical(selection_rect);
- // Let LocalRect for line break have a space width to paint line break
- // when it is only character in a line or only selected in a line.
- if (selection_status.start != selection_status.end &&
- cursor.Current().IsLineBreak() &&
- // This is for old compatible that old doesn't paint last br in a page.
- !IsLastBRInPage(*cursor.Current().GetLayoutObject())) {
- DCHECK(!logical_rect.size.inline_size);
- logical_rect.size.inline_size =
- LayoutUnit(cursor.Current().Style().GetFont().SpaceWidth());
- }
- const LogicalRect line_break_extended_rect =
- cursor.Current().IsLineBreak()
- ? logical_rect
- : ExpandedSelectionRectForSoftLineBreakIfNeeded(logical_rect, cursor,
- selection_status);
- const LogicalRect line_height_expanded_rect =
- ExpandSelectionRectToLineHeight(line_break_extended_rect, cursor);
- const PhysicalRect physical_rect =
- cursor.Current().ConvertChildToPhysical(line_height_expanded_rect);
- return physical_rect;
-}
-
-// TODO(yosin): We should move |ComputeLocalSelectionRectForReplaced()| to
-// "ng_selection_painter.cc".
-PhysicalRect ComputeLocalSelectionRectForReplaced(
- const NGInlineCursor& cursor) {
- DCHECK(cursor.Current().GetLayoutObject()->IsLayoutReplaced());
- const PhysicalRect selection_rect = PhysicalRect({}, cursor.Current().Size());
- LogicalRect logical_rect =
- cursor.Current().ConvertChildToLogical(selection_rect);
- const LogicalRect line_height_expanded_rect =
- ExpandSelectionRectToLineHeight(logical_rect, cursor);
- const PhysicalRect physical_rect =
- cursor.Current().ConvertChildToPhysical(line_height_expanded_rect);
- return physical_rect;
-}
-
-PositionWithAffinity NGPaintFragment::PositionForPointInText(
- const PhysicalOffset& point) const {
- const auto& text_fragment = To<NGPhysicalTextFragment>(PhysicalFragment());
- if (text_fragment.IsGeneratedText())
- return PositionWithAffinity();
- return PositionForPointInText(text_fragment.TextOffsetForPoint(point));
-}
-
-PositionWithAffinity NGPaintFragment::PositionForPointInText(
- unsigned text_offset) const {
- const auto& text_fragment = To<NGPhysicalTextFragment>(PhysicalFragment());
- DCHECK(!text_fragment.IsGeneratedText());
- NGInlineCursor cursor;
- cursor.MoveTo(*this);
- const NGCaretPosition unadjusted_position{
- cursor, NGCaretPositionType::kAtTextOffset, text_offset};
- if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled())
- return unadjusted_position.ToPositionInDOMTreeWithAffinity();
- if (text_offset > text_fragment.StartOffset() &&
- text_offset < text_fragment.EndOffset()) {
- return unadjusted_position.ToPositionInDOMTreeWithAffinity();
- }
- return BidiAdjustment::AdjustForHitTest(unadjusted_position)
- .ToPositionInDOMTreeWithAffinity();
-}
-
-PositionWithAffinity NGPaintFragment::PositionForPointInInlineLevelBox(
- const PhysicalOffset& point) const {
- DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
- DCHECK(!PhysicalFragment().IsBlockFlow());
-
- const LogicalOffset logical_point =
- point.ConvertToLogical(Style().GetWritingDirection(), Size(),
- // |point| is actually a pixel with size 1x1.
- PhysicalSize(LayoutUnit(1), LayoutUnit(1)));
- const LayoutUnit inline_point = logical_point.inline_offset;
-
- // Stores the closest child before |point| in the inline direction. Used if we
- // can't find any child |point| falls in to resolve the position.
- const NGPaintFragment* closest_child_before = nullptr;
- LayoutUnit closest_child_before_inline_offset = LayoutUnit::Min();
-
- // Stores the closest child after |point| in the inline direction. Used if we
- // can't find any child |point| falls in to resolve the position.
- const NGPaintFragment* closest_child_after = nullptr;
- LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
-
- for (const NGPaintFragment* child : Children()) {
- if (child->PhysicalFragment().IsFloating())
- continue;
-
- const LogicalRect logical_child_rect =
- PhysicalFragment().ConvertChildToLogical(child->Rect());
- const LayoutUnit child_inline_min = logical_child_rect.offset.inline_offset;
- const LayoutUnit child_inline_max =
- child_inline_min + logical_child_rect.size.inline_size;
-
- // Try to resolve if |point| falls in any child in inline direction.
- if (inline_point >= child_inline_min && inline_point <= child_inline_max) {
- if (auto child_position = PositionForPointInChild(*child, point))
- return child_position.value();
- continue;
- }
-
- if (inline_point < child_inline_min) {
- if (child_inline_min < closest_child_after_inline_offset) {
- closest_child_after = child;
- closest_child_after_inline_offset = child_inline_min;
- }
- }
-
- if (inline_point > child_inline_max) {
- if (child_inline_max > closest_child_before_inline_offset) {
- closest_child_before = child;
- closest_child_before_inline_offset = child_inline_max;
- }
- }
- }
-
- if (closest_child_after) {
- if (auto child_position =
- PositionForPointInChild(*closest_child_after, point))
- return child_position.value();
- }
-
- if (closest_child_before) {
- if (auto child_position =
- PositionForPointInChild(*closest_child_before, point))
- return child_position.value();
- }
-
- return PositionWithAffinity();
-}
-
-PositionWithAffinity NGPaintFragment::PositionForPointInInlineFormattingContext(
- const PhysicalOffset& point) const {
- DCHECK(PhysicalFragment().IsBlockFlow());
- DCHECK(PhysicalFragment().IsBox());
- DCHECK(To<NGPhysicalBoxFragment>(PhysicalFragment())
- .GetLayoutObject()
- ->ChildrenInline());
-
- const LogicalOffset logical_point =
- point.ConvertToLogical(Style().GetWritingDirection(), Size(),
- // |point| is actually a pixel with size 1x1.
- PhysicalSize(LayoutUnit(1), LayoutUnit(1)));
- const LayoutUnit block_point = logical_point.block_offset;
-
- // Stores the closest line box child below |point| in the block direction.
- // Used if we can't find any child |point| falls in to resolve the position.
- const NGPaintFragment* closest_line_below = nullptr;
- LayoutUnit closest_line_below_block_offset = LayoutUnit::Min();
-
- // Stores the closest line box child above |point| in the block direction.
- // Used if we can't find any child |point| falls in to resolve the position.
- const NGPaintFragment* closest_line_above = nullptr;
- LayoutUnit closest_line_above_block_offset = LayoutUnit::Max();
-
- for (const NGPaintFragment* child : Children()) {
- if (!child->PhysicalFragment().IsLineBox())
- continue;
- if (!NGInlineCursor(*child).TryToMoveToFirstInlineLeafChild()) {
- // editing/selection/last-empty-inline.html requires this to skip
- // empty <span> with padding.
- continue;
- }
-
- const LogicalRect logical_child_rect =
- PhysicalFragment().ConvertChildToLogical(child->Rect());
- const LayoutUnit line_min = logical_child_rect.offset.block_offset;
- const LayoutUnit line_max = line_min + logical_child_rect.size.block_size;
-
- // Try to resolve if |point| falls in a line box in block direction.
- // Hitting on line bottom doesn't count, to match legacy behavior.
- // TODO(xiaochengh): Consider floats.
- if (block_point >= line_min && block_point < line_max) {
- if (auto child_position = PositionForPointInChild(*child, point))
- return child_position.value();
- continue;
- }
-
- if (block_point < line_min) {
- if (line_min < closest_line_above_block_offset) {
- closest_line_above = child;
- closest_line_above_block_offset = line_min;
- }
- }
-
- if (block_point >= line_max) {
- if (line_max > closest_line_below_block_offset) {
- closest_line_below = child;
- closest_line_below_block_offset = line_max;
- }
- }
- }
-
- // Note: |move_caret_to_boundary| is true for Mac and Unix.
- const bool move_caret_to_boundary =
- To<LayoutBlockFlow>(GetLayoutObject())
- ->ShouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
-
- // At here, |point| is not inside any line in |this|:
- // |closest_line_above|
- // |point|
- // |closest_line_below|
- if (closest_line_above) {
- if (move_caret_to_boundary) {
- // Tests[1-3] reach here.
- // [1] editing/selection/click-in-margins-inside-editable-div.html
- // [2] fast/writing-mode/flipped-blocks-hit-test-line-edges.html
- // [3] All/LayoutViewHitTestTest.HitTestHorizontal/4
- NGInlineCursor line_box(*this);
- line_box.MoveTo(*closest_line_above);
- if (auto first_position = line_box.PositionForStartOfLine())
- return PositionWithAffinity(first_position.GetPosition());
- } else if (auto child_position =
- PositionForPointInChild(*closest_line_above, point)) {
- return child_position.value();
- }
- }
-
- if (closest_line_below) {
- if (move_caret_to_boundary) {
- // Tests[1-3] reach here.
- // [1] editing/selection/click-in-margins-inside-editable-div.html
- // [2] fast/writing-mode/flipped-blocks-hit-test-line-edges.html
- // [3] All/LayoutViewHitTestTest.HitTestHorizontal/4
- NGInlineCursor line_box(*this);
- line_box.MoveTo(*closest_line_below);
- if (auto last_position = line_box.PositionForEndOfLine())
- return PositionWithAffinity(last_position.GetPosition());
- } else if (auto child_position =
- PositionForPointInChild(*closest_line_below, point)) {
- // Test[1] reaches here.
- // [1] editing/selection/last-empty-inline.html
- return child_position.value();
- }
- }
-
- // TODO(xiaochengh): Looking at only the closest lines may not be enough,
- // when we have multiple lines full of pseudo elements. Fix it.
-
- // TODO(xiaochengh): Consider floats. See crbug.com/758526.
-
- return PositionWithAffinity();
-}
-
-PositionWithAffinity NGPaintFragment::PositionForPoint(
- const PhysicalOffset& point) const {
- if (PhysicalFragment().IsText())
- return PositionForPointInText(point);
-
- if (PhysicalFragment().IsBlockFlow()) {
- const LayoutObject& layout_object = *PhysicalFragment().GetLayoutObject();
- if (layout_object.ChildrenInline())
- return PositionForPointInInlineFormattingContext(point);
- // |NGInlineCursor::PositionForPointInChild()| calls this function with
- // inline block with with block formatting context that has block
- // children[1], e.g: <b style="display:inline-block"><div>b</div></b>
- // [1] NGInlineCursorTest.PositionForPointInChildBlockChildren
- return layout_object.PositionForPoint(point);
- }
-
- DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
- return PositionForPointInInlineLevelBox(point);
-}
-
-String NGPaintFragment::DebugName() const {
- StringBuilder name;
-
- DCHECK(physical_fragment_);
- const NGPhysicalFragment& physical_fragment = *physical_fragment_;
- if (physical_fragment.IsBox()) {
- const LayoutObject* layout_object = physical_fragment.GetLayoutObject();
- if (!layout_object)
- return "NGPhysicalBoxFragment";
- // For the root |NGPaintFragment|, return the name of the |LayoutObject| to
- // ease the transition to |NGFragmentItem|.
- if (!Parent())
- return layout_object->DebugName();
- name.Append("NGPhysicalBoxFragment");
- name.Append(' ');
- name.Append(layout_object->DebugName());
- } else if (physical_fragment.IsText()) {
- name.Append("NGPhysicalTextFragment '");
- name.Append(To<NGPhysicalTextFragment>(physical_fragment).Text());
- name.Append('\'');
- } else if (physical_fragment.IsLineBox()) {
- name.Append("NGPhysicalLineBoxFragment");
- } else {
- NOTREACHED();
- }
-
- return name.ToString();
-}
-
-template class CORE_TEMPLATE_EXPORT
- NGPaintFragment::List<NGPaintFragment::TraverseNextForSameLayoutObject>;
-template class CORE_TEMPLATE_EXPORT
- NGPaintFragment::List<NGPaintFragment::TraverseNextSibling>;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
deleted file mode 100644
index 6d6d083772a..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
-
-#include <iterator>
-#include <memory>
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/core/scroll/scroll_types.h"
-#include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class NGBlockBreakToken;
-class NGInlineCursor;
-struct LayoutSelectionStatus;
-struct NGContainerInkOverflow;
-enum class NGOutlineType;
-
-// The NGPaintFragment contains a NGPhysicalFragment and geometry in the paint
-// coordinate system.
-//
-// NGPhysicalFragment is limited to its parent coordinate system for caching and
-// sharing subtree. This class makes it possible to compute visual rects in the
-// parent transform node.
-//
-// NGPaintFragment is an ImageResourceObserver, which means that it gets
-// notified when associated images are changed.
-// This is used for 2 main use cases:
-// - reply to 'background-image' as we need to invalidate the background in this
-// case.
-// (See https://drafts.csswg.org/css-backgrounds-3/#the-background-image)
-// - image (<img>, svg <image>) or video (<video>) elements that are
-// placeholders for displaying them.
-class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
- public DisplayItemClient {
- public:
- NGPaintFragment(scoped_refptr<const NGPhysicalFragment>,
- PhysicalOffset offset,
- NGPaintFragment*);
- ~NGPaintFragment() override;
-
- static scoped_refptr<NGPaintFragment> Create(
- scoped_refptr<const NGPhysicalFragment>,
- const NGBlockBreakToken* break_token,
- scoped_refptr<NGPaintFragment> previous_instance = nullptr);
-
- const NGPhysicalFragment& PhysicalFragment() const {
- CHECK(IsAlive());
- return *physical_fragment_;
- }
-
- static scoped_refptr<NGPaintFragment>* Find(scoped_refptr<NGPaintFragment>*,
- const NGBlockBreakToken*);
-
- template <typename Traverse>
- class List {
- STACK_ALLOCATED();
-
- public:
- explicit List(NGPaintFragment* first) : first_(first) {}
-
- class iterator final
- : public std::iterator<std::forward_iterator_tag, NGPaintFragment*> {
- public:
- explicit iterator(NGPaintFragment* first) : current_(first) {}
-
- NGPaintFragment* operator*() const { return current_; }
- NGPaintFragment* operator->() const { return current_; }
- iterator& operator++() {
- DCHECK(current_);
- current_ = Traverse::Next(current_);
- return *this;
- }
- bool operator==(const iterator& other) const {
- return current_ == other.current_;
- }
- bool operator!=(const iterator& other) const {
- return current_ != other.current_;
- }
-
- private:
- NGPaintFragment* current_;
- };
-
- CORE_EXPORT iterator begin() const { return iterator(first_); }
- CORE_EXPORT iterator end() const { return iterator(nullptr); }
-
- // Returns the first |NGPaintFragment| in |FragmentRange| as STL container.
- // It is error to call |front()| for empty range.
- NGPaintFragment& front() const;
-
- // Returns the last |NGPaintFragment| in |FragmentRange| as STL container.
- // It is error to call |back()| for empty range.
- // Note: The complexity of |back()| is O(n) where n is number of elements
- // in this |FragmentRange|.
- NGPaintFragment& back() const;
-
- // Returns number of fragments in this range. The complexity is O(n) where n
- // is number of elements.
- wtf_size_t size() const;
- CORE_EXPORT bool IsEmpty() const { return !first_; }
-
- void ToList(Vector<NGPaintFragment*, 16>*) const;
-
- private:
- NGPaintFragment* first_;
- };
-
- class TraverseNextSibling {
- STATIC_ONLY(TraverseNextSibling);
-
- public:
- static NGPaintFragment* Next(NGPaintFragment* current) {
- return current->NextSibling();
- }
- };
- using ChildList = List<TraverseNextSibling>;
-
- // The parent NGPaintFragment. This is nullptr for a root; i.e., when parent
- // is not for NGPaint. In the first phase, this means that this is a root of
- // an inline formatting context.
- NGPaintFragment* Parent() const { return parent_; }
- NGPaintFragment* FirstChild() const { return FirstAlive(first_child_.get()); }
- NGPaintFragment* NextSibling() const {
- return FirstAlive(next_sibling_.get());
- }
- NGPaintFragment* NextForSameLayoutObject() const {
- return next_for_same_layout_object_;
- }
- ChildList Children() const { return ChildList(FirstChild()); }
- bool IsEllipsis() const;
-
- // Note, as the name implies, |IsDescendantOfNotSelf| returns false for the
- // same object. This is different from |LayoutObject::IsDescendant| but is
- // same as |Node::IsDescendant|.
- bool IsDescendantOfNotSelf(const NGPaintFragment&) const;
-
- // Returns the root box containing this.
- const NGPaintFragment* Root() const;
-
- // Returns the first line box for a block-level container.
- NGPaintFragment* FirstLineBox() const;
-
- // Returns the container line box for inline fragments.
- const NGPaintFragment* ContainerLineBox() const;
-
- // Returns true if this fragment is line box and marked dirty.
- bool IsDirty() const { return is_dirty_inline_; }
-
- // Returns offset to its container box for inline and line box fragments.
- const PhysicalOffset& OffsetInContainerBlock() const {
- DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
- return inline_offset_to_container_box_;
- }
- const PhysicalRect RectInContainerBlock() const {
- return PhysicalRect(OffsetInContainerBlock(), Size());
- }
-
- // InkOverflow of itself, not including contents, in the local coordinate.
- PhysicalRect SelfInkOverflow() const;
-
- // InkOverflow of itself, including contents if they contribute to the ink
- // overflow of this object (e.g. when not clipped,) in the local coordinate.
- PhysicalRect InkOverflow() const;
-
- void RecalcInlineChildrenInkOverflow() const;
-
- // TODO(layout-dev): Implement when we have oveflow support.
- // TODO(eae): Switch to using NG geometry types.
- bool HasNonVisibleOverflow() const {
- return PhysicalFragment().HasNonVisibleOverflow();
- }
-
- bool IsScrollContainer() const {
- return PhysicalFragment().IsScrollContainer();
- }
- bool ShouldClipOverflowAlongBothAxis() const;
- bool HasSelfPaintingLayer() const;
-
- // Set ShouldDoFullPaintInvalidation flag in the corresponding LayoutObject.
- void SetShouldDoFullPaintInvalidation();
-
- // Set ShouldDoFullPaintInvalidation flag in the corresponding LayoutObject
- // recursively.
- void SetShouldDoFullPaintInvalidationRecursively();
-
- // Set ShouldDoFullPaintInvalidation flag to all objects in the first line of
- // this block-level fragment.
- void SetShouldDoFullPaintInvalidationForFirstLine() const;
-
- // DisplayItemClient methods.
- String DebugName() const override;
-
- // Commonly used functions for NGPhysicalFragment.
- Node* GetNode() const { return PhysicalFragment().GetNode(); }
- const LayoutObject* GetLayoutObject() const {
- return PhysicalFragment().GetLayoutObject();
- }
- LayoutObject* GetMutableLayoutObject() const {
- return PhysicalFragment().GetMutableLayoutObject();
- }
- const ComputedStyle& Style() const { return PhysicalFragment().Style(); }
- PhysicalOffset Offset() const {
- DCHECK(parent_);
- return offset_;
- }
- PhysicalSize Size() const { return PhysicalFragment().Size(); }
- PhysicalRect Rect() const { return {Offset(), Size()}; }
-
- // Converts the given point, relative to the fragment itself, into a position
- // in DOM tree.
- PositionWithAffinity PositionForPoint(const PhysicalOffset&) const;
- PositionWithAffinity PositionForPointInText(unsigned text_offset) const;
-
- // A range of fragments for |FragmentsFor()|.
- class TraverseNextForSameLayoutObject {
- STATIC_ONLY(TraverseNextForSameLayoutObject);
-
- public:
- static NGPaintFragment* Next(NGPaintFragment* current) {
- return current->next_for_same_layout_object_;
- }
- };
- class CORE_EXPORT FragmentRange
- : public List<TraverseNextForSameLayoutObject> {
- public:
- explicit FragmentRange(
- NGPaintFragment* first,
- bool is_in_layout_ng_inline_formatting_context = true)
- : List(first),
- is_in_layout_ng_inline_formatting_context_(
- is_in_layout_ng_inline_formatting_context) {}
-
- bool IsInLayoutNGInlineFormattingContext() const {
- return is_in_layout_ng_inline_formatting_context_;
- }
-
- private:
- bool is_in_layout_ng_inline_formatting_context_;
- };
-
- // Returns a range of NGPaintFragment in an inline formatting context that are
- // for a LayoutObject.
- static FragmentRange InlineFragmentsFor(const LayoutObject*);
-
- const NGPaintFragment* LastForSameLayoutObject() const;
- NGPaintFragment* LastForSameLayoutObject();
- void LayoutObjectWillBeDestroyed();
-
- void ClearAssociationWithLayoutObject();
-
- // Computes LocalVisualRect for an inline LayoutObject. Returns nullopt if the
- // LayoutObject is not in LayoutNG inline formatting context.
- static base::Optional<PhysicalRect> LocalVisualRectFor(const LayoutObject&);
-
- private:
- bool IsAlive() const { return !is_layout_object_destroyed_; }
-
- // Returns the first "alive" fragment; i.e., fragment that doesn't have
- // destroyed LayoutObject.
- static NGPaintFragment* FirstAlive(NGPaintFragment* fragment) {
- while (UNLIKELY(fragment && !fragment->IsAlive()))
- fragment = fragment->next_sibling_.get();
- return fragment;
- }
-
- struct CreateContext {
- STACK_ALLOCATED();
-
- public:
- CreateContext(scoped_refptr<NGPaintFragment> previous_instance,
- bool populate_children)
- : previous_instance(std::move(previous_instance)),
- populate_children(populate_children) {}
- CreateContext(CreateContext* parent_context, NGPaintFragment* parent)
- : parent(parent),
- last_fragment_map(parent_context->last_fragment_map),
- previous_instance(std::move(parent->first_child_)) {}
-
- void SkipDestroyedPreviousInstances();
- void DestroyPreviousInstances();
-
- NGPaintFragment* parent = nullptr;
- HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map = nullptr;
- scoped_refptr<NGPaintFragment> previous_instance;
- bool populate_children = false;
- bool painting_layer_needs_repaint = false;
- };
- static scoped_refptr<NGPaintFragment> CreateOrReuse(
- scoped_refptr<const NGPhysicalFragment> fragment,
- PhysicalOffset offset,
- CreateContext* context);
-
- void PopulateDescendants(CreateContext* parent_context);
- void AssociateWithLayoutObject(
- LayoutObject*,
- HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map);
-
- static void DestroyAll(scoped_refptr<NGPaintFragment> fragment);
- void RemoveChildren();
-
- // Helps for PositionForPoint() when |this| falls in different categories.
- PositionWithAffinity PositionForPointInText(const PhysicalOffset&) const;
- PositionWithAffinity PositionForPointInInlineFormattingContext(
- const PhysicalOffset&) const;
- PositionWithAffinity PositionForPointInInlineLevelBox(
- const PhysicalOffset&) const;
-
- // Dirty line boxes containing |layout_object|.
- static void MarkLineBoxesDirtyFor(const LayoutObject& layout_object);
-
- // Returns |LayoutBox| that holds ink overflow for this fragment.
- const LayoutBox* InkOverflowOwnerBox() const;
-
- // Re-compute ink overflow of children and return the union.
- PhysicalRect RecalcInkOverflow();
- PhysicalRect RecalcContentsInkOverflow() const;
-
- //
- // Following fields are computed in the layout phase.
- //
-
- scoped_refptr<const NGPhysicalFragment> physical_fragment_;
- // The offset to |parent_| comes from |NGLink::Offset()|.
- PhysicalOffset offset_;
-
- NGPaintFragment* parent_;
- scoped_refptr<NGPaintFragment> first_child_;
- scoped_refptr<NGPaintFragment> next_sibling_;
-
- // The next fragment for when this is fragmented.
- scoped_refptr<NGPaintFragment> next_fragmented_;
-
- NGPaintFragment* next_for_same_layout_object_ = nullptr;
- PhysicalOffset inline_offset_to_container_box_;
-
- // The ink overflow storage for when |InkOverflowOwnerBox()| is nullptr.
- std::unique_ptr<NGContainerInkOverflow> ink_overflow_;
-
- // Set when the corresponding LayoutObject is destroyed.
- // TODO(kojii): This should move to |NGPhysicalFragment|.
- unsigned is_layout_object_destroyed_ : 1;
-
- // For a line box, this indicates it is dirty. This helps to determine if the
- // fragment is re-usable when part of an inline formatting context is changed.
- // For an inline box, this flag helps to avoid traversing up to its line box
- // every time.
- unsigned is_dirty_inline_ : 1;
-};
-
-extern template class CORE_EXTERN_TEMPLATE_EXPORT
- NGPaintFragment::List<NGPaintFragment::TraverseNextForSameLayoutObject>;
-extern template class CORE_EXTERN_TEMPLATE_EXPORT
- NGPaintFragment::List<NGPaintFragment::TraverseNextSibling>;
-
-PhysicalRect ComputeLocalSelectionRectForText(
- const NGInlineCursor& cursor,
- const LayoutSelectionStatus& selection_status);
-
-PhysicalRect ComputeLocalSelectionRectForReplaced(const NGInlineCursor& cursor);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
deleted file mode 100644
index 165c2101eba..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
+++ /dev/null
@@ -1,685 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
-#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-
-namespace blink {
-
-class NGPaintFragmentTest : public RenderingTest,
- private ScopedLayoutNGForTest {
- public:
- NGPaintFragmentTest(LocalFrameClient* local_frame_client = nullptr)
- : RenderingTest(local_frame_client), ScopedLayoutNGForTest(true) {}
-
- protected:
- const NGPaintFragment* GetPaintFragmentByElementId(const char* id) {
- const auto* block_flow =
- To<LayoutNGBlockFlow>(GetLayoutObjectByElementId(id));
- return block_flow ? block_flow->PaintFragment() : nullptr;
- }
-
- const NGPaintFragment& FirstLineBoxByElementId(const char* id) {
- const NGPaintFragment* root = GetPaintFragmentByElementId(id);
- EXPECT_TRUE(root);
- EXPECT_GE(1u, root->Children().size());
- const NGPaintFragment& line_box = *root->FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentLineBox,
- line_box.PhysicalFragment().Type());
- return line_box;
- }
-
- Vector<NGPaintFragment*, 16> ToList(
- const NGPaintFragment::ChildList& children) {
- Vector<NGPaintFragment*, 16> list;
- children.ToList(&list);
- return list;
- }
-};
-
-TEST_F(NGPaintFragmentTest, InlineFragmentsFor) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px/1 Ahem; width: 10ch; }
- span { background: yellow; }
- </style>
- <body>
- <div id="container">12345 <span id="box">789 123456789 123<span> 567</div>
- </body>
- )HTML");
- auto* container =
- To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
- ASSERT_TRUE(container);
- LayoutObject* text1 = container->FirstChild();
- ASSERT_TRUE(text1 && text1->IsText());
- LayoutObject* box = text1->NextSibling();
- ASSERT_TRUE(box && box->IsLayoutInline());
-
- Vector<NGPaintFragment*> results;
- auto it = NGPaintFragment::InlineFragmentsFor(text1);
- results.AppendRange(it.begin(), it.end());
- EXPECT_EQ(1u, results.size());
- EXPECT_EQ(text1, results[0]->GetLayoutObject());
- EXPECT_EQ(PhysicalOffset(), results[0]->OffsetInContainerBlock());
-
- results.clear();
- it = NGPaintFragment::InlineFragmentsFor(box);
- results.AppendRange(it.begin(), it.end());
- EXPECT_EQ(3u, results.size());
- EXPECT_EQ(box, results[0]->GetLayoutObject());
- EXPECT_EQ(box, results[1]->GetLayoutObject());
- EXPECT_EQ(box, results[2]->GetLayoutObject());
-
- EXPECT_EQ(PhysicalOffset(60, 0), results[0]->OffsetInContainerBlock());
- EXPECT_EQ("789", To<NGPhysicalTextFragment>(
- results[0]->FirstChild()->PhysicalFragment())
- .Text());
- EXPECT_EQ(PhysicalOffset(0, 10), results[1]->OffsetInContainerBlock());
- EXPECT_EQ("123456789", To<NGPhysicalTextFragment>(
- results[1]->FirstChild()->PhysicalFragment())
- .Text());
- EXPECT_EQ(PhysicalOffset(0, 20), results[2]->OffsetInContainerBlock());
- EXPECT_EQ("123", To<NGPhysicalTextFragment>(
- results[2]->FirstChild()->PhysicalFragment())
- .Text());
-}
-
-#define EXPECT_INK_OVERFLOWS(expected, fragment) \
- do { \
- EXPECT_EQ(expected, fragment.InkOverflow()); \
- EXPECT_EQ(expected, fragment.SelfInkOverflow()); \
- } while (false)
-
-TEST_F(NGPaintFragmentTest, InlineBox) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY</span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- // Inline boxes without box decorations (border, background, etc.) do not
- // generate box fragments and that their child fragments are placed directly
- // under the line box.
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- const NGPaintFragment& inner_text1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inner_text2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, InlineBoxVerticalRL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; height: 10ch;
- writing-mode: vertical-rl; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY</span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- // Inline boxes without box decorations (border, background, etc.) do not
- // generate box fragments and that their child fragments are placed directly
- // under the line box.
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 60), outer_text);
-
- const NGPaintFragment& inner_text1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inner_text2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, InlineBoxWithDecorations) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- #box { background: blue; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY<span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- // Inline boxes with box decorations generate box fragments.
- const NGPaintFragment& inline_box1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box1);
-
- EXPECT_EQ(1u, inline_box1.Children().size());
- const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inline_box2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box2);
-
- const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, InlineBoxWithDecorationsVerticalRL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; height: 10ch;
- writing-mode: vertical-rl; }
- #box { background: blue; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY<span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 60), outer_text);
-
- // Inline boxes with box decorations generate box fragments.
- const NGPaintFragment& inline_box1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inline_box1);
-
- EXPECT_EQ(1u, inline_box1.Children().size());
- const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inline_box2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inline_box2);
-
- const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 30), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, InlineBlock) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- /* box-shadow creates asymmetrical visual overflow. */
- span { display: inline-block; box-shadow: 10px 20px black; }
- #box2 { position: relative; top: 10px; width: 6px; height: 6px; }
- /* This div creates asymmetrical contents visual overflow. */
- #box2 div { margin-left: -10px; width: 50px; height: 70px; }
- </style>
- <body>
- <div id="container">12345
- <span id="box1">X</span><span id="box2"><div></div></span></div>
- </body>
- )HTML");
-
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_TRUE(container);
- EXPECT_EQ(1u, container->Children().size());
- const NGPaintFragment& line1 = *container->FirstChild();
- EXPECT_EQ(3u, line1.Children().size());
-
- // Test the outer text "12345".
- const NGPaintFragment& outer_text = *line1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_EQ("12345 ", To<NGPhysicalTextFragment>(outer_text.PhysicalFragment())
- .Text()
- .ToString());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- // Test |InlineFragmentsFor| can find the outer text.
- LayoutObject* layout_outer_text =
- GetLayoutObjectByElementId("container")->SlowFirstChild();
- EXPECT_TRUE(layout_outer_text && layout_outer_text->IsText());
- auto fragments = NGPaintFragment::InlineFragmentsFor(layout_outer_text);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&outer_text, *fragments.begin());
-
- // Test the inline block "box1".
- const NGPaintFragment& box1 = *ToList(line1.Children())[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box1.PhysicalFragment().Type());
- EXPECT_EQ(NGPhysicalFragment::kAtomicInline,
- box1.PhysicalFragment().BoxType());
- EXPECT_EQ(PhysicalRect(0, 0, 20, 30), box1.InkOverflow());
- EXPECT_EQ(PhysicalRect(0, 0, 20, 30), box1.SelfInkOverflow());
-
- // Test |InlineFragmentsFor| can find "box1".
- LayoutObject* layout_box1 = GetLayoutObjectByElementId("box1");
- EXPECT_TRUE(layout_box1 && layout_box1->IsLayoutBlockFlow());
- fragments = NGPaintFragment::InlineFragmentsFor(layout_box1);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&box1, *fragments.begin());
-
- // Test an inline block has its own NGPaintFragment.
- const NGPaintFragment* box1_inner = GetPaintFragmentByElementId("box1");
- EXPECT_TRUE(box1_inner);
- EXPECT_EQ(box1_inner->GetLayoutObject(), box1.GetLayoutObject());
-
- // Test the text fragment inside of the inline block.
- const NGPaintFragment& inner_line_box = *box1_inner->FirstChild();
- const NGPaintFragment& inner_text = *inner_line_box.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 10), inner_text);
-
- // Test |InlineFragmentsFor| can find the inner text of "box1".
- LayoutObject* layout_inner_text = layout_box1->SlowFirstChild();
- EXPECT_TRUE(layout_inner_text && layout_inner_text->IsText());
- fragments = NGPaintFragment::InlineFragmentsFor(layout_inner_text);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&inner_text, *fragments.begin());
-
- // Test the inline block "box2".
- const NGPaintFragment& box2 = *ToList(line1.Children())[2];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box2.PhysicalFragment().Type());
- EXPECT_EQ(NGPhysicalFragment::kAtomicInline,
- box2.PhysicalFragment().BoxType());
- EXPECT_EQ(PhysicalRect(-10, 0, 50, 70), box2.InkOverflow());
- EXPECT_EQ(PhysicalRect(0, 0, 16, 26), box2.SelfInkOverflow());
-}
-
-TEST_F(NGPaintFragmentTest, InlineBlockVerticalRL) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; height: 10ch;
- writing-mode: vertical-rl; }
- /* box-shadow creates asymmetrical visual overflow. */
- span { display: inline-block; box-shadow: 10px 20px black; }
- #box2 { position: relative; top: 10px; width: 6px; height: 6px; }
- /* This div creates asymmetrical contents visual overflow. */
- #box2 div { margin-top: -10px; width: 50px; height: 70px; }
- </style>
- <body>
- <div id="container">12345
- <span id="box1">X</span><span id="box2"><div></div></span></div>
- </body>
- )HTML");
-
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_TRUE(container);
- EXPECT_EQ(1u, container->Children().size());
- const NGPaintFragment& line1 = *container->FirstChild();
- EXPECT_EQ(3u, line1.Children().size());
-
- // Test the outer text "12345".
- const NGPaintFragment& outer_text = *line1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_EQ("12345 ", To<NGPhysicalTextFragment>(outer_text.PhysicalFragment())
- .Text()
- .ToString());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 60), outer_text);
-
- // Test |InlineFragmentsFor| can find the outer text.
- LayoutObject* layout_outer_text =
- GetLayoutObjectByElementId("container")->SlowFirstChild();
- EXPECT_TRUE(layout_outer_text && layout_outer_text->IsText());
- auto fragments = NGPaintFragment::InlineFragmentsFor(layout_outer_text);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&outer_text, *fragments.begin());
-
- // Test the inline block "box1".
- const NGPaintFragment& box1 = *ToList(line1.Children())[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box1.PhysicalFragment().Type());
- EXPECT_EQ(NGPhysicalFragment::kAtomicInline,
- box1.PhysicalFragment().BoxType());
- EXPECT_EQ(PhysicalRect(0, 0, 20, 30), box1.InkOverflow());
- EXPECT_EQ(PhysicalRect(0, 0, 20, 30), box1.SelfInkOverflow());
-
- // Test |InlineFragmentsFor| can find "box1".
- LayoutObject* layout_box1 = GetLayoutObjectByElementId("box1");
- EXPECT_TRUE(layout_box1 && layout_box1->IsLayoutBlockFlow());
- fragments = NGPaintFragment::InlineFragmentsFor(layout_box1);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&box1, *fragments.begin());
-
- // Test an inline block has its own NGPaintFragment.
- const NGPaintFragment* box1_inner = GetPaintFragmentByElementId("box1");
- EXPECT_TRUE(box1_inner);
- EXPECT_EQ(box1_inner->GetLayoutObject(), box1.GetLayoutObject());
-
- // Test the text fragment inside of the inline block.
- const NGPaintFragment& inner_line_box = *box1_inner->FirstChild();
- const NGPaintFragment& inner_text = *inner_line_box.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 10, 10), inner_text);
-
- // Test |InlineFragmentsFor| can find the inner text of "box1".
- LayoutObject* layout_inner_text = layout_box1->SlowFirstChild();
- EXPECT_TRUE(layout_inner_text && layout_inner_text->IsText());
- fragments = NGPaintFragment::InlineFragmentsFor(layout_inner_text);
- EXPECT_TRUE(fragments.IsInLayoutNGInlineFormattingContext());
- EXPECT_NE(fragments.begin(), fragments.end());
- EXPECT_EQ(&inner_text, *fragments.begin());
-
- // Test the inline block "box2".
- const NGPaintFragment& box2 = *ToList(line1.Children())[2];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box2.PhysicalFragment().Type());
- EXPECT_EQ(NGPhysicalFragment::kAtomicInline,
- box2.PhysicalFragment().BoxType());
- // -44 is because 50px child overflows out of the left edge of the 6px box.
- // 60 width covers both the overflowing contents and the box shadow.
- EXPECT_EQ(PhysicalRect(-44, -10, 60, 70), box2.InkOverflow());
- EXPECT_EQ(PhysicalRect(0, 0, 16, 26), box2.SelfInkOverflow());
-}
-
-TEST_F(NGPaintFragmentTest, RelativeBlock) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- #container { position: relative; top: 10px; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY</span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- const NGPaintFragment& line1 = *container->FirstChild();
- EXPECT_EQ(2u, line1.Children().size());
-
- const NGPaintFragment& outer_text = *line1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- const NGPaintFragment& inner_text1 = *ToList(line1.Children())[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text1);
-
- const NGPaintFragment& line2 = *ToList(container->Children())[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inner_text2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, RelativeInline) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- #box { position: relative; top: 10px; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY<span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- const NGPaintFragment& inline_box1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box1);
-
- EXPECT_EQ(1u, inline_box1.Children().size());
- const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inline_box2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box2);
-
- const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text2);
-}
-
-TEST_F(NGPaintFragmentTest, RelativeBlockAndInline) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- div { font: 10px Ahem; width: 10ch; }
- #container, #box { position: relative; top: 10px; }
- </style>
- <body>
- <div id="container">12345 <span id="box">XXX YYY<span></div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(2u, container->Children().size());
- auto lines = ToList(container->Children());
- const NGPaintFragment& line1 = *lines[0];
- EXPECT_EQ(2u, line1.Children().size());
-
- auto line1_children = ToList(line1.Children());
- const NGPaintFragment& outer_text = *line1_children[0];
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- outer_text.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 60, 10), outer_text);
-
- const NGPaintFragment& inline_box1 = *line1_children[1];
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box1);
-
- EXPECT_EQ(1u, inline_box1.Children().size());
- const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text1.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text1);
-
- const NGPaintFragment& line2 = *lines[1];
- EXPECT_EQ(1u, line2.Children().size());
- const NGPaintFragment& inline_box2 = *line2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
- inline_box2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inline_box2);
-
- const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
- EXPECT_EQ(NGPhysicalFragment::kFragmentText,
- inner_text2.PhysicalFragment().Type());
- EXPECT_INK_OVERFLOWS(PhysicalRect(0, 0, 30, 10), inner_text2);
-}
-
-// Test that OOF should not create a NGPaintFragment.
-TEST_F(NGPaintFragmentTest, OutOfFlow) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- div {
- position: relative;
- }
- span {
- position: absolute;
- }
- </style>
- <body>
- <div id="container">
- text
- <span>XXX</span>
- </div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- EXPECT_EQ(1u, container->Children().size());
- auto lines = ToList(container->Children());
- EXPECT_EQ(1u, lines[0]->Children().size());
-}
-
-static const char* inline_child_data[] = {
- "<span id='child'>XXX</span>",
- "<span id='child' style='background: yellow'>XXX</span>",
- "<span id='child' style='display: inline-block'>XXX</span>",
-};
-
-class InlineChildTest : public NGPaintFragmentTest,
- public testing::WithParamInterface<const char*> {};
-
-INSTANTIATE_TEST_SUITE_P(NGPaintFragmentTest,
- InlineChildTest,
- testing::ValuesIn(inline_child_data));
-
-TEST_P(InlineChildTest, RemoveInlineChild) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetBodyInnerHTML(String(R"HTML(
- <!DOCTYPE html>
- <style>
- </style>
- <body>
- <div id="container">
- 12345
- )HTML") + GetParam() +
- R"HTML(
- 67890
- </div>
- </body>
- )HTML");
- const NGPaintFragment* container = GetPaintFragmentByElementId("container");
- const NGPaintFragment& linebox = container->Children().front();
- EXPECT_EQ(linebox.Children().size(), 3u);
-
- Element* child = GetElementById("child");
- child->remove();
-
- // Destroyed children should be eliminated immediately.
- EXPECT_EQ(linebox.Children().size(), 2u);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
deleted file mode 100644
index e5c4b783bc7..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
-
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-
-namespace blink {
-
-namespace {
-
-// ------ Helpers for traversing inline fragments ------
-
-unsigned IndexOf(const Vector<NGPaintFragment*, 16>& fragments,
- const NGPaintFragment& fragment) {
- auto* const* it = std::find_if(
- fragments.begin(), fragments.end(),
- [&fragment](const auto& child) { return &fragment == child; });
- DCHECK(it != fragments.end());
- return static_cast<unsigned>(std::distance(fragments.begin(), it));
-}
-
-} // namespace
-
-NGPaintFragmentTraversal::NGPaintFragmentTraversal(const NGPaintFragment& root)
- : current_(root.FirstChild()), root_(&root) {}
-
-NGPaintFragmentTraversal::NGPaintFragmentTraversal(const NGPaintFragment& root,
- const NGPaintFragment& start)
- : root_(&root) {
- MoveTo(start);
-}
-
-NGPaintFragmentTraversal::NGPaintFragmentTraversal(
- const NGPaintFragmentTraversal& other)
- : current_(other.current_),
- root_(other.root_),
- current_index_(other.current_index_),
- siblings_(other.siblings_) {}
-
-NGPaintFragmentTraversal::NGPaintFragmentTraversal(
- NGPaintFragmentTraversal&& other)
- : current_(other.current_),
- root_(other.root_),
- current_index_(other.current_index_),
- siblings_(std::move(other.siblings_)) {
- other.current_ = nullptr;
-}
-
-NGPaintFragmentTraversal::NGPaintFragmentTraversal() = default;
-
-NGPaintFragmentTraversal& NGPaintFragmentTraversal::operator=(
- const NGPaintFragmentTraversal& other) {
- current_ = other.current_;
- root_ = other.root_;
- current_index_ = other.current_index_;
- siblings_ = other.siblings_;
- return *this;
-}
-
-void NGPaintFragmentTraversal::EnsureIndex() {
- current_->Parent()->Children().ToList(&siblings_);
- auto** const it =
- std::find_if(siblings_.begin(), siblings_.end(),
- [this](const auto& child) { return current_ == child; });
- DCHECK(it != siblings_.end());
- current_index_ = static_cast<unsigned>(std::distance(siblings_.begin(), it));
-}
-
-void NGPaintFragmentTraversal::Reset() {
- current_ = nullptr;
- current_index_ = 0;
- siblings_.Shrink(0);
-}
-
-void NGPaintFragmentTraversal::MoveTo(const NGPaintFragment& fragment) {
- DCHECK(fragment.IsDescendantOfNotSelf(*root_));
- current_ = &fragment;
-}
-
-void NGPaintFragmentTraversal::MoveToNext() {
- if (IsAtEnd())
- return;
-
- if (const NGPaintFragment* first_child = current_->FirstChild())
- return MoveToFirstChild();
- MoveToNextSiblingOrAncestor();
-}
-
-void NGPaintFragmentTraversal::MoveToNextSiblingOrAncestor() {
- while (!IsAtEnd()) {
- // Check if we have a next sibling.
- if (const NGPaintFragment* next = current_->NextSibling()) {
- current_ = next;
- if (!siblings_.IsEmpty()) {
- ++current_index_;
- return;
- }
- EnsureIndex();
- return;
- }
-
- MoveToParent();
- }
-}
-
-void NGPaintFragmentTraversal::MoveToParent() {
- if (IsAtEnd())
- return;
-
- current_ = current_->Parent();
- if (current_ == root_)
- current_ = nullptr;
- if (UNLIKELY(!siblings_.IsEmpty()))
- siblings_.Shrink(0);
-}
-
-void NGPaintFragmentTraversal::MoveToPrevious() {
- if (IsAtEnd())
- return;
-
- if (siblings_.IsEmpty()) {
- current_->Parent()->Children().ToList(&siblings_);
- current_index_ = IndexOf(siblings_, *current_);
- }
-
- if (!current_index_) {
- // There is no previous sibling of |current_|. We move to parent.
- MoveToParent();
- return;
- }
-
- current_ = siblings_[--current_index_];
- while (current_->FirstChild())
- MoveToLastChild();
-}
-
-NGPaintFragmentTraversal::AncestorRange
-NGPaintFragmentTraversal::InclusiveAncestorsOf(const NGPaintFragment& start) {
- return AncestorRange(start);
-}
-
-NGPaintFragmentTraversal::InlineDescendantsRange
-NGPaintFragmentTraversal::InlineDescendantsOf(
- const NGPaintFragment& container) {
- return InlineDescendantsRange(container);
-}
-
-void NGPaintFragmentTraversal::MoveToFirstChild() {
- DCHECK(current_->FirstChild());
- current_ = current_->FirstChild();
- current_index_ = 0;
- if (UNLIKELY(!siblings_.IsEmpty()))
- siblings_.Shrink(0);
-}
-
-void NGPaintFragmentTraversal::MoveToLastChild() {
- DCHECK(current_->FirstChild());
- current_->Children().ToList(&siblings_);
- DCHECK(!siblings_.IsEmpty());
- current_index_ = siblings_.size() - 1;
- current_ = siblings_[current_index_];
-}
-
-void NGPaintFragmentTraversal::MoveToNextInlineLeaf() {
- while (!IsAtEnd() && !IsInlineLeaf())
- MoveToNext();
- do {
- MoveToNext();
- } while (!IsAtEnd() && !IsInlineLeaf());
-}
-
-void NGPaintFragmentTraversal::MoveToPreviousInlineLeaf() {
- while (!IsAtEnd() && !IsInlineLeaf())
- MoveToPrevious();
- do {
- MoveToPrevious();
- } while (!IsAtEnd() && !IsInlineLeaf());
-}
-
-void NGPaintFragmentTraversal::MoveToPreviousInlineLeafIgnoringLineBreak() {
- do {
- MoveToPreviousInlineLeaf();
- } while (!IsAtEnd() && IsLineBreak());
-}
-
-void NGPaintFragmentTraversal::MoveToNextInlineLeafIgnoringLineBreak() {
- do {
- MoveToNextInlineLeaf();
- } while (!IsAtEnd() && IsLineBreak());
-}
-
-bool NGPaintFragmentTraversal::IsInlineLeaf() const {
- if (!current_->PhysicalFragment().IsInline())
- return false;
- return current_->PhysicalFragment().IsText() ||
- current_->PhysicalFragment().IsAtomicInline();
-}
-
-bool NGPaintFragmentTraversal::IsLineBreak() const {
- DCHECK(current_->PhysicalFragment().IsInline());
- auto* physical_text_fragment =
- DynamicTo<NGPhysicalTextFragment>(current_->PhysicalFragment());
- if (!physical_text_fragment)
- return false;
- return physical_text_fragment->IsLineBreak();
-}
-
-// ----
-NGPaintFragment* NGPaintFragmentTraversal::AncestorRange::Iterator::operator->()
- const {
- DCHECK(current_);
- return current_;
-}
-
-void NGPaintFragmentTraversal::AncestorRange::Iterator::operator++() {
- DCHECK(current_);
- current_ = current_->Parent();
-}
-
-// ----
-
-NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::Iterator(
- const NGPaintFragment& container)
- : container_(&container), current_(container.FirstChild()) {
- if (!current_ || IsInlineFragment(*current_))
- return;
- operator++();
-}
-
-NGPaintFragment* NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::
-operator->() const {
- DCHECK(current_);
- return current_;
-}
-
-void NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::operator++() {
- DCHECK(current_);
- do {
- current_ = Next(*current_);
- } while (current_ && !IsInlineFragment(*current_));
-}
-
-// static
-// Returns next fragment of |start| in DFS pre-order within |container_| and
-// skipping descendants in block formatting context.
-NGPaintFragment*
-NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::Next(
- const NGPaintFragment& start) const {
- if (ShouldTraverse(start) && start.FirstChild())
- return start.FirstChild();
- for (NGPaintFragment* runner = const_cast<NGPaintFragment*>(&start);
- runner != container_; runner = runner->Parent()) {
- if (NGPaintFragment* next_sibling = runner->NextSibling())
- return next_sibling;
- }
- return nullptr;
-}
-
-// static
-bool NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::
- IsInlineFragment(const NGPaintFragment& fragment) {
- return fragment.PhysicalFragment().IsInline() ||
- fragment.PhysicalFragment().IsLineBox();
-}
-
-// static
-bool NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::ShouldTraverse(
- const NGPaintFragment& fragment) {
- return fragment.PhysicalFragment().IsContainer() &&
- !fragment.PhysicalFragment().IsFormattingContextRoot();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
deleted file mode 100644
index 7fbbe3474e5..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_TRAVERSAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_TRAVERSAL_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class NGPaintFragment;
-
-// Utility class for traversing the paint fragment tree.
-//
-// This class has two groups of functions; one is a traversing cursor, by
-// instantiating and using instance functions. The other is a set of static
-// functions that are similar to DOM traversal functions.
-class CORE_EXPORT NGPaintFragmentTraversal {
- STACK_ALLOCATED();
-
- public:
- NGPaintFragmentTraversal(const NGPaintFragmentTraversal& other);
- NGPaintFragmentTraversal(NGPaintFragmentTraversal&& other);
- NGPaintFragmentTraversal();
- NGPaintFragmentTraversal& operator=(const NGPaintFragmentTraversal& other);
-
- // Create an instance to traverse descendants of |root|.
- explicit NGPaintFragmentTraversal(const NGPaintFragment& root);
-
- // Create an instance to traverse descendants of |root|, starting at |start|.
- // Same as constructing with |root| and then |MoveTo()|.
- NGPaintFragmentTraversal(const NGPaintFragment& root,
- const NGPaintFragment& start);
-
- bool IsAtEnd() const { return !current_; }
- explicit operator bool() const { return !IsAtEnd(); }
-
- const NGPaintFragment* get() const {
- DCHECK(current_);
- return current_;
- }
- const NGPaintFragment& operator*() const { return *get(); }
- const NGPaintFragment* operator->() const { return get(); }
-
- // Move to the specified fragment. The fragment must be a descendant of
- // |root|. This function is O(n) where |n| is the number of senior siblings
- // before |fragment|.
- void MoveTo(const NGPaintFragment& fragment);
-
- // Move to the next node using the pre-order depth-first-search.
- // Note: When |IsAtEnd()| is true, this function does nothing.
- void MoveToNext();
-
- // Move to the next sibling, or next ancestor node using the pre-order
- // depth-first-search, skipping children of the current node.
- void MoveToNextSiblingOrAncestor();
-
- // Move to the parent of current fragment. When |current_| is a child of
- // |root_|, this function makes |IsAtEnd()| to true.
- // Note: When |IsAtEnd()| is true, this function does nothing.
- void MoveToParent();
-
- // Move to the previous node using the pre-order depth-first-search. When
- // |current_| is the first child of |root_|, this function makes |IsAtEnd()|
- // to true.
- // Note: When |IsAtEnd()| is true, this function does nothing.
- void MoveToPrevious();
-
- // Returns the previous/next inline leaf fragment (text or atomic inline) of
- // the passed fragment, which itself must be inline.
- void MoveToPreviousInlineLeaf();
- void MoveToNextInlineLeaf();
-
- // Variants of the above two skipping line break fragments.
- void MoveToPreviousInlineLeafIgnoringLineBreak();
- void MoveToNextInlineLeafIgnoringLineBreak();
-
- //
- // Following functions are static, similar to DOM traversal utilities.
- //
- // Because fragments have children as a vector, not a two-way list, static
- // functions are not as cheap as their DOM versions. When traversing more than
- // once, instace functions are recommended.
-
- class AncestorRange final {
- STACK_ALLOCATED();
-
- public:
- class Iterator final
- : public std::iterator<std::forward_iterator_tag, NGPaintFragment*> {
- STACK_ALLOCATED();
-
- public:
- explicit Iterator(NGPaintFragment* current) : current_(current) {}
-
- NGPaintFragment* operator*() const { return operator->(); }
- NGPaintFragment* operator->() const;
-
- void operator++();
-
- bool operator==(const Iterator& other) const {
- return current_ == other.current_;
- }
- bool operator!=(const Iterator& other) const {
- return !operator==(other);
- }
-
- private:
- NGPaintFragment* current_;
- };
-
- explicit AncestorRange(const NGPaintFragment& start) : start_(&start) {}
-
- Iterator begin() const {
- return Iterator(const_cast<NGPaintFragment*>(start_));
- }
- Iterator end() const { return Iterator(nullptr); }
-
- private:
- const NGPaintFragment* const start_;
- };
-
- // Returns inclusive ancestors.
- static AncestorRange InclusiveAncestorsOf(const NGPaintFragment&);
-
- class CORE_EXPORT InlineDescendantsRange final {
- STACK_ALLOCATED();
-
- public:
- class CORE_EXPORT Iterator final
- : public std::iterator<std::forward_iterator_tag, NGPaintFragment*> {
- STACK_ALLOCATED();
-
- public:
- explicit Iterator(const NGPaintFragment& container);
- Iterator() = default;
-
- NGPaintFragment* operator*() const { return operator->(); }
- NGPaintFragment* operator->() const;
-
- void operator++();
-
- bool operator==(const Iterator& other) const {
- return current_ == other.current_;
- }
- bool operator!=(const Iterator& other) const {
- return !operator==(other);
- }
-
- private:
- NGPaintFragment* Next(const NGPaintFragment& fragment) const;
- static bool IsInlineFragment(const NGPaintFragment& fragment);
- static bool ShouldTraverse(const NGPaintFragment& fragment);
-
- const NGPaintFragment* container_ = nullptr;
- NGPaintFragment* current_ = nullptr;
- };
-
- explicit InlineDescendantsRange(const NGPaintFragment& container)
- : container_(&container) {}
-
- Iterator begin() const { return Iterator(*container_); }
- Iterator end() const { return Iterator(); }
-
- private:
- const NGPaintFragment* const container_;
- };
-
- // Returns inline descendants of |container| in preorder.
- static InlineDescendantsRange InlineDescendantsOf(
- const NGPaintFragment& container);
-
- private:
- void EnsureIndex();
- bool IsInlineLeaf() const;
- bool IsLineBreak() const;
- void MoveToFirstChild();
- void MoveToLastChild();
- void Reset();
-
- // |current_| holds a |NGPaintFragment| specified by |index|th child of
- // |parent| of the last element of |stack_|.
- const NGPaintFragment* current_ = nullptr;
-
- // The root of subtree where traversing is taken place. |root_| is excluded
- // from traversal. |current_| can't |root_|.
- const NGPaintFragment* root_ = nullptr;
-
- // Keep a list of siblings for MoveToPrevious().
- // TODO(kojii): We could keep a stack of this to avoid repetitive
- // constructions of the list when we move up/down levels. Also can consider
- // sharing with NGPaintFragmentTraversalContext.
- unsigned current_index_ = 0;
- Vector<NGPaintFragment*, 16> siblings_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_TRAVERSAL_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc
deleted file mode 100644
index 78d645533bf..00000000000
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-
-namespace blink {
-
-using testing::ElementsAreArray;
-
-class NGPaintFragmentTraversalTest : public RenderingTest,
- private ScopedLayoutNGForTest {
- public:
- NGPaintFragmentTraversalTest()
- : RenderingTest(nullptr), ScopedLayoutNGForTest(true) {}
-
- protected:
- void SetUpHtml(const char* container_id, const char* html) {
- SetBodyInnerHTML(html);
- layout_block_flow_ =
- To<LayoutBlockFlow>(GetLayoutObjectByElementId(container_id));
- root_fragment_ = layout_block_flow_->PaintFragment();
- }
-
- const NGPaintFragment::ChildList RootChildren() const {
- return root_fragment_->Children();
- }
-
- Vector<const NGPaintFragment*> ToDepthFirstList(
- NGPaintFragmentTraversal* traversal) const {
- Vector<const NGPaintFragment*> results;
- for (; *traversal; traversal->MoveToNext()) {
- const NGPaintFragment& fragment = **traversal;
- results.push_back(&fragment);
- }
- return results;
- }
-
- Vector<const NGPaintFragment*> ToReverseDepthFirstList(
- NGPaintFragmentTraversal* traversal) const {
- Vector<const NGPaintFragment*> results;
- for (; *traversal; traversal->MoveToPrevious()) {
- const NGPaintFragment& fragment = **traversal;
- results.push_back(&fragment);
- }
- return results;
- }
-
- Vector<NGPaintFragment*, 16> ToList(
- const NGPaintFragment::ChildList& children) {
- Vector<NGPaintFragment*, 16> list;
- children.ToList(&list);
- return list;
- }
-
- LayoutBlockFlow* layout_block_flow_;
- const NGPaintFragment* root_fragment_;
-};
-
-TEST_F(NGPaintFragmentTraversalTest, MoveToNext) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragmentTraversal traversal(*root_fragment_);
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* line1 = ToList(root_fragment_->Children())[1];
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- EXPECT_THAT(
- ToDepthFirstList(&traversal),
- ElementsAreArray({line0, line0->FirstChild(), span, span->FirstChild(),
- br, line1, line1->FirstChild()}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, MoveToNextWithRoot) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- NGPaintFragmentTraversal traversal(*line0);
- EXPECT_THAT(
- ToDepthFirstList(&traversal),
- ElementsAreArray({line0->FirstChild(), span, span->FirstChild(), br}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, MoveToPrevious) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragmentTraversal traversal(*root_fragment_);
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* line1 = ToList(root_fragment_->Children())[1];
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- traversal.MoveTo(*line1->FirstChild());
- EXPECT_THAT(
- ToReverseDepthFirstList(&traversal),
- ElementsAreArray({line1->FirstChild(), line1, br, span->FirstChild(),
- span, line0->FirstChild(), line0}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, MoveToPreviousWithRoot) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- NGPaintFragmentTraversal traversal(*line0);
- traversal.MoveTo(*br);
- EXPECT_THAT(
- ToReverseDepthFirstList(&traversal),
- ElementsAreArray({br, span->FirstChild(), span, line0->FirstChild()}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, MoveTo) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragmentTraversal traversal(*root_fragment_);
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* line1 = ToList(root_fragment_->Children())[1];
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- traversal.MoveTo(*span);
- EXPECT_EQ(span, &*traversal);
- EXPECT_THAT(ToDepthFirstList(&traversal),
- ElementsAreArray(
- {span, span->FirstChild(), br, line1, line1->FirstChild()}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, MoveToWithRoot) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t", R"HTML(
- <div id=t>
- line0
- <span style="background: red">red</span>
- <br>
- line1
- </div>
- )HTML");
- NGPaintFragment* line0 = root_fragment_->FirstChild();
- NGPaintFragment* span = ToList(line0->Children())[1];
- NGPaintFragment* br = ToList(line0->Children())[2];
- NGPaintFragmentTraversal traversal(*line0);
- traversal.MoveTo(*span);
- EXPECT_EQ(span, &*traversal);
- EXPECT_THAT(ToDepthFirstList(&traversal),
- ElementsAreArray({span, span->FirstChild(), br}));
-}
-
-TEST_F(NGPaintFragmentTraversalTest, InlineDescendantsOf) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
- return;
- SetUpHtml("t",
- "<ul>"
- "<li id=t style='position: absolute'>"
- "<span style='float: right'>float</span>"
- "<span style='position: absolute'>oof</span>"
- "text<br>"
- "<span style='display: inline-block'>inline block</span>"
- "</li>"
- "</ul>");
-
- // Tests that floats, out-of-flow positioned and descendants of atomic inlines
- // are excluded.
- Vector<const NGPaintFragment*> descendants;
- for (const NGPaintFragment* fragment :
- NGPaintFragmentTraversal::InlineDescendantsOf(*root_fragment_))
- descendants.push_back(fragment);
- ASSERT_EQ(6u, descendants.size());
- // TODO(layout-dev): This list marker is not in any line box. Should it be
- // treated as inline?
- EXPECT_TRUE(descendants[0]->PhysicalFragment().IsListMarker());
- EXPECT_TRUE(descendants[1]->PhysicalFragment().IsLineBox());
- EXPECT_TRUE(descendants[2]->PhysicalFragment().IsText()); // "text"
- EXPECT_TRUE(descendants[3]->PhysicalFragment().IsText()); // "br"
- EXPECT_TRUE(descendants[4]->PhysicalFragment().IsLineBox());
- EXPECT_TRUE(descendants[5]->PhysicalFragment().IsAtomicInline());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc
new file mode 100644
index 00000000000..46cd0143835
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.h"
+
+#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h"
+#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
+#include "third_party/blink/renderer/core/paint/block_paint_invalidator.h"
+#include "third_party/blink/renderer/core/paint/paint_invalidator.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+
+namespace blink {
+
+namespace {
+
+bool DisplayItemClientIsFullyInvalidated(const DisplayItemClient& client) {
+ return IsFullPaintInvalidationReason(client.GetPaintInvalidationReason());
+}
+
+void InvalidateContainerForCellGeometryChange(
+ const LayoutObject& container,
+ const PaintInvalidatorContext& container_context) {
+ // We only need to do this if the container hasn't been fully invalidated.
+ DCHECK(!DisplayItemClientIsFullyInvalidated(container));
+
+ // At this time we have already walked the container for paint invalidation,
+ // so we should invalidate the container immediately here instead of setting
+ // paint invalidation flags.
+ container_context.painting_layer->SetNeedsRepaint();
+ container.InvalidateDisplayItemClients(PaintInvalidationReason::kGeometry);
+}
+
+} // namespace
+
+void NGTableCellPaintInvalidator::InvalidatePaint() {
+ // The cell's containing row and section paint backgrounds behind the cell,
+ // and the row or table paints collapsed borders. If the cell's geometry
+ // changed and the containers which will paint backgrounds and/or collapsed
+ // borders haven't been full invalidated, invalidate the containers.
+ if (context_.old_paint_offset != context_.fragment_data->PaintOffset() ||
+ cell_.Size() != cell_.PreviousSize()) {
+ // Table row background is painted inside cell's geometry.
+ const auto& row = *cell_.Parent();
+ DCHECK(row.IsTableRow());
+ if (!DisplayItemClientIsFullyInvalidated(row) &&
+ row.StyleRef().HasBackground()) {
+ InvalidateContainerForCellGeometryChange(row, *context_.ParentContext());
+ }
+ // Table section background is painted inside cell's geometry.
+ const auto& section = *row.Parent();
+ DCHECK(section.IsTableSection());
+ if (!DisplayItemClientIsFullyInvalidated(section) &&
+ section.StyleRef().HasBackground()) {
+ InvalidateContainerForCellGeometryChange(
+ section, *context_.ParentContext()->ParentContext());
+ }
+ // Table paints its background, and column backgrounds inside cell's
+ // geometry.
+ const auto& table = *cell_.Table();
+ if (!DisplayItemClientIsFullyInvalidated(table) &&
+ (table.HasBackgroundForPaint() || table.HasCollapsedBorders())) {
+ InvalidateContainerForCellGeometryChange(
+ table, *context_.ParentContext()->ParentContext()->ParentContext());
+ }
+ }
+
+ BlockPaintInvalidator(cell_).InvalidatePaint(context_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.h
new file mode 100644
index 00000000000..70916779dec
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.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_CORE_PAINT_NG_NG_TABLE_CELL_PAINT_INVALIDATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TABLE_CELL_PAINT_INVALIDATOR_H_
+
+#include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class LayoutNGTableCell;
+struct PaintInvalidatorContext;
+
+class NGTableCellPaintInvalidator {
+ STACK_ALLOCATED();
+
+ public:
+ NGTableCellPaintInvalidator(const LayoutNGTableCell& cell,
+ const PaintInvalidatorContext& context)
+ : cell_(cell), context_(context) {}
+
+ void InvalidatePaint();
+
+ private:
+ const LayoutNGTableCell& cell_;
+ const PaintInvalidatorContext& context_;
+};
+
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc
index 25411fa7c12..eafa0a94d1e 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc
@@ -40,13 +40,14 @@ class NGTableCollapsedEdge {
NGTableCollapsedEdge(const NGTableCollapsedEdge& source, int offset)
: borders_(source.borders_) {
// If edge index would have been negative.
- if (offset < 0 && edge_index_ < static_cast<wtf_size_t>(abs(offset))) {
+ if (offset < 0 &&
+ source.edge_index_ < static_cast<wtf_size_t>(std::abs(offset))) {
edge_index_ = UINT_MAX;
- return;
+ } else {
+ edge_index_ = source.edge_index_ + offset;
+ if (edge_index_ >= borders_.EdgeCount())
+ edge_index_ = UINT_MAX;
}
- edge_index_ = source.edge_index_ + offset;
- if (edge_index_ >= borders_.EdgeCount())
- edge_index_ = UINT_MAX;
InitCachedProps();
}
@@ -383,12 +384,12 @@ void NGTablePainter::PaintCollapsedBorders(const PaintInfo& paint_info,
const IntRect& visual_rect) {
DCHECK_EQ(paint_info.phase, PaintPhase::kForeground);
const NGTableBorders* collapsed_borders = fragment_.TableCollapsedBorders();
- const NGTableFragmentData::CollapsedBordersGeometry*
- collapsed_borders_geometry = fragment_.TableCollapsedBordersGeometry();
if (!collapsed_borders)
return;
+ const NGTableFragmentData::CollapsedBordersGeometry*
+ collapsed_borders_geometry = fragment_.TableCollapsedBordersGeometry();
+ CHECK(collapsed_borders_geometry);
- BoxDecorationData box_decoration_data(paint_info, fragment_);
const LayoutNGTable& layout_table =
*To<LayoutNGTable>(fragment_.GetLayoutObject());
if (DrawingRecorder::UseCachedDrawingIfPossible(
@@ -415,10 +416,12 @@ void NGTablePainter::PaintCollapsedBorders(const PaintInfo& paint_info,
wtf_size_t table_row = edge.TableRow();
wtf_size_t table_column = edge.TableColumn();
if (edge.IsInlineAxis()) {
+ CHECK_LT(table_column + 1, collapsed_borders_geometry->columns.size());
inline_start = collapsed_borders_geometry->columns[table_column];
inline_size = collapsed_borders_geometry->columns[table_column + 1] -
collapsed_borders_geometry->columns[table_column];
block_size = edge.BorderWidth();
+ CHECK_LT(table_row, collapsed_borders_geometry->rows.size());
block_start =
collapsed_borders_geometry->rows[table_row] - edge.BorderWidth() / 2;
LogicalSize start_joint;
@@ -440,9 +443,11 @@ void NGTablePainter::PaintCollapsedBorders(const PaintInfo& paint_info,
inline_size -= end_joint.inline_size / 2;
}
} else { // block_axis
+ CHECK_LT(table_row + 1, collapsed_borders_geometry->rows.size());
block_start = collapsed_borders_geometry->rows[table_row];
block_size =
collapsed_borders_geometry->rows[table_row + 1] - block_start;
+ CHECK_LT(table_column, collapsed_borders_geometry->columns.size());
inline_start = collapsed_borders_geometry->columns[table_column] -
edge.BorderWidth() / 2;
inline_size = edge.BorderWidth();
@@ -507,8 +512,11 @@ void NGTableSectionPainter::PaintBoxDecorationBackground(
!box_decoration_data.ShouldPaintBackground());
}
for (const NGLink& child : fragment_.Children()) {
- DCHECK(child.fragment->IsBox());
- NGTableRowPainter(To<NGPhysicalBoxFragment>(*child.fragment))
+ const auto& child_fragment = *child;
+ DCHECK(child_fragment.IsBox());
+ if (!child_fragment.IsTableNGRow())
+ continue;
+ NGTableRowPainter(To<NGPhysicalBoxFragment>(child_fragment))
.PaintTablePartBackgroundIntoCells(
paint_info, layout_section,
PhysicalRect(paint_offset, fragment_.Size()), child.offset);
@@ -525,6 +533,8 @@ void NGTableSectionPainter::PaintColumnsBackground(
const PhysicalRect& columns_paint_rect,
const NGTableFragmentData::ColumnGeometries& column_geometries) {
for (const NGLink& row : fragment_.Children()) {
+ if (!row.fragment->IsTableNGRow())
+ continue;
NGTableRowPainter(To<NGPhysicalBoxFragment>(*row.fragment))
.PaintColumnsBackground(paint_info, section_offset + row.offset,
columns_paint_rect, column_geometries);
@@ -568,8 +578,12 @@ void NGTableRowPainter::PaintTablePartBackgroundIntoCells(
const PhysicalOffset& row_offset) {
for (const NGLink& child : fragment_.Children()) {
DCHECK(child.fragment->IsBox());
- DCHECK(child.fragment->GetLayoutObject()->IsTableCell());
- NGTableCellPainter(To<NGPhysicalBoxFragment>(*child.fragment))
+ DCHECK(child.fragment->GetLayoutObject()->IsTableCell() ||
+ child.fragment->GetLayoutObject()->IsOutOfFlowPositioned());
+ const auto& child_fragment = *child;
+ if (!child_fragment.IsTableNGCell())
+ continue;
+ NGTableCellPainter(To<NGPhysicalBoxFragment>(child_fragment))
.PaintBackgroundForTablePart(paint_info, table_part,
table_part_paint_rect,
row_offset + child.offset);
@@ -586,6 +600,8 @@ void NGTableRowPainter::PaintColumnsBackground(
bool is_horizontal =
IsHorizontalWritingMode(fragment_.Style().GetWritingMode());
for (const NGLink& child : fragment_.Children()) {
+ if (!child.fragment->IsTableNGCell())
+ continue;
wtf_size_t cell_column =
To<NGPhysicalBoxFragment>(child.fragment)->TableCellColumnIndex();
// if cell is in the column, generate column physical rect
@@ -642,17 +658,8 @@ void NGTableCellPainter::PaintBoxDecorationBackground(
DisplayItem::kBoxDecorationBackground, visual_rect);
PhysicalRect paint_rect(paint_offset, fragment_.Size());
-
- const NGPaintFragment* paint_fragment =
- To<LayoutNGTableCell>(fragment_.GetLayoutObject())->PaintFragment();
- if (paint_fragment) {
- NGBoxFragmentPainter(*paint_fragment)
- .PaintBoxDecorationBackgroundWithRectImpl(paint_info, paint_rect,
- box_decoration_data);
- } else {
- NGBoxFragmentPainter(fragment_).PaintBoxDecorationBackgroundWithRectImpl(
- paint_info, paint_rect, box_decoration_data);
- }
+ NGBoxFragmentPainter(fragment_).PaintBoxDecorationBackgroundWithRectImpl(
+ paint_info, paint_rect, box_decoration_data);
}
// Inspired by TableCellPainter::PaintBackground.
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.h
index 62485bd9751..f7cce1afd86 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_table_painters.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TABLE_PAINTERS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TABLE_PAINTERS_H_
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -20,7 +21,9 @@ class NGTablePainter {
public:
explicit NGTablePainter(const NGPhysicalBoxFragment& table_wrapper_fragment)
- : fragment_(table_wrapper_fragment) {}
+ : fragment_(table_wrapper_fragment) {
+ DCHECK(fragment_.IsTableNG());
+ }
void PaintBoxDecorationBackground(const PaintInfo&,
const PhysicalOffset&,
@@ -40,7 +43,9 @@ class NGTableSectionPainter {
public:
explicit NGTableSectionPainter(
const NGPhysicalBoxFragment& table_section_fragment)
- : fragment_(table_section_fragment) {}
+ : fragment_(table_section_fragment) {
+ DCHECK(fragment_.IsTableNGSection());
+ }
void PaintBoxDecorationBackground(const PaintInfo&,
const PhysicalOffset&,
@@ -60,7 +65,9 @@ class NGTableRowPainter {
public:
explicit NGTableRowPainter(const NGPhysicalBoxFragment& table_row_fragment)
- : fragment_(table_row_fragment) {}
+ : fragment_(table_row_fragment) {
+ DCHECK(fragment_.IsTableNGRow());
+ }
void PaintBoxDecorationBackground(const PaintInfo&,
const PhysicalOffset&,
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 0a5ca8c74f9..f67108c940d 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
+#include "cc/input/layer_selection_bound.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/markers/composition_marker.h"
@@ -15,16 +16,16 @@
#include "third_party/blink/renderer/core/layout/list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h"
#include "third_party/blink/renderer/core/paint/document_marker_painter.h"
#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
#include "third_party/blink/renderer/core/paint/inline_text_box_painter.h"
#include "third_party/blink/renderer/core/paint/list_marker_painter.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_text_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/selection_bounds_recorder.h"
#include "third_party/blink/renderer/core/paint/text_painter_base.h"
#include "third_party/blink/renderer/core/style/applied_text_decoration.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -37,24 +38,6 @@ namespace blink {
namespace {
-Color SelectionBackgroundColor(const Document& document,
- const ComputedStyle& style,
- Node* node,
- Color text_color) {
- const Color color = HighlightPaintingUtils::HighlightBackgroundColor(
- document, style, node, kPseudoIdSelection);
- if (!color.Alpha())
- return Color();
-
- // If the text color ends up being the same as the selection background,
- // invert the selection background.
- if (text_color == color)
- return Color(0xff - color.Red(), 0xff - color.Green(), 0xff - color.Blue());
- return color;
-}
-
-// TODO(yosin): Remove |AsDisplayItemClient| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
inline const DisplayItemClient& AsDisplayItemClient(
const NGInlineCursor& cursor,
bool for_selection) {
@@ -66,16 +49,10 @@ inline const DisplayItemClient& AsDisplayItemClient(
return *cursor.Current().GetDisplayItemClient();
}
-inline const DisplayItemClient& AsDisplayItemClient(
- const NGTextPainterCursor& cursor,
- bool for_selection) {
- return cursor.PaintFragment();
-}
-
inline PhysicalRect ComputeBoxRect(const NGInlineCursor& cursor,
const PhysicalOffset& paint_offset,
const PhysicalOffset& parent_offset) {
- PhysicalRect box_rect = cursor.CurrentItem()->RectInContainerBlock();
+ PhysicalRect box_rect = cursor.CurrentItem()->RectInContainerFragment();
box_rect.offset.left += paint_offset.left;
// We round the y-axis to ensure consistent line heights.
box_rect.offset.top =
@@ -84,17 +61,6 @@ inline PhysicalRect ComputeBoxRect(const NGInlineCursor& cursor,
return box_rect;
}
-inline PhysicalRect ComputeBoxRect(const NGTextPainterCursor& cursor,
- const PhysicalOffset& paint_offset,
- const PhysicalOffset& parent_offset) {
- PhysicalRect box_rect = cursor.PaintFragment().Rect();
- // We round the y-axis to ensure consistent line heights.
- PhysicalOffset adjusted_paint_offset(paint_offset.left,
- LayoutUnit(paint_offset.top.Round()));
- box_rect.offset += adjusted_paint_offset;
- return box_rect;
-}
-
inline const NGInlineCursor& InlineCursorForBlockFlow(
const NGInlineCursor& cursor,
base::Optional<NGInlineCursor>* storage) {
@@ -105,354 +71,6 @@ inline const NGInlineCursor& InlineCursorForBlockFlow(
return **storage;
}
-inline const NGInlineCursor& InlineCursorForBlockFlow(
- const NGTextPainterCursor& cursor,
- base::Optional<NGInlineCursor>* storage) {
- if (*storage)
- return **storage;
- storage->emplace(cursor.RootPaintFragment());
- (*storage)->MoveTo(cursor.PaintFragment());
- return **storage;
-}
-
-// TODO(yosin): Remove |GetTextFragmentPaintInfo| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
-inline NGTextFragmentPaintInfo GetTextFragmentPaintInfo(
- const NGInlineCursor& cursor) {
- return cursor.CurrentItem()->TextPaintInfo(cursor.Items());
-}
-
-inline NGTextFragmentPaintInfo GetTextFragmentPaintInfo(
- const NGTextPainterCursor& cursor) {
- return cursor.CurrentItem()->PaintInfo();
-}
-
-// TODO(yosin): Remove |GetLineLeftAndRightForOffsets| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
-inline std::pair<LayoutUnit, LayoutUnit> GetLineLeftAndRightForOffsets(
- const NGFragmentItem& text_item,
- StringView text,
- unsigned start_offset,
- unsigned end_offset) {
- return text_item.LineLeftAndRightForOffsets(text, start_offset, end_offset);
-}
-
-inline std::pair<LayoutUnit, LayoutUnit> GetLineLeftAndRightForOffsets(
- const NGPhysicalTextFragment& text_fragment,
- StringView text,
- unsigned start_offset,
- unsigned end_offset) {
- return text_fragment.LineLeftAndRightForOffsets(start_offset, end_offset);
-}
-
-// TODO(yosin): Remove |ComputeLayoutSelectionStatus| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
-inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
- const NGInlineCursor& cursor) {
- return cursor.Current()
- .GetLayoutObject()
- ->GetDocument()
- .GetFrame()
- ->Selection()
- .ComputeLayoutSelectionStatus(cursor);
-}
-
-// TODO(yosin): Remove |ComputeLocalRect| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
-inline PhysicalRect ComputeLocalRect(const NGFragmentItem& text_item,
- StringView text,
- unsigned start_offset,
- unsigned end_offset) {
- return text_item.LocalRect(text, start_offset, end_offset);
-}
-
-inline PhysicalRect ComputeLocalRect(
- const NGPhysicalTextFragment& text_fragment,
- StringView text,
- unsigned start_offset,
- unsigned end_offset) {
- return text_fragment.LocalRect(start_offset, end_offset);
-}
-
-DocumentMarkerVector ComputeMarkersToPaint(Node* node, bool is_ellipsis) {
- // TODO(yoichio): Handle first-letter
- auto* text_node = DynamicTo<Text>(node);
- if (!text_node)
- return DocumentMarkerVector();
- // We don't paint any marker on ellipsis.
- if (is_ellipsis)
- return DocumentMarkerVector();
-
- DocumentMarkerController& document_marker_controller =
- node->GetDocument().Markers();
- return document_marker_controller.ComputeMarkersToPaint(*text_node);
-}
-
-unsigned GetTextContentOffset(const Text& text, unsigned offset) {
- // TODO(yoichio): Sanitize DocumentMarker around text length.
- const Position position(text, std::min(offset, text.length()));
- const NGOffsetMapping* const offset_mapping =
- NGOffsetMapping::GetFor(position);
- DCHECK(offset_mapping);
- const base::Optional<unsigned>& ng_offset =
- offset_mapping->GetTextContentOffset(position);
- DCHECK(ng_offset.has_value());
- return ng_offset.value();
-}
-
-// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
-// offsets.
-// |offset| points not each character but each span between character.
-// With that concept, we can clear catch what is inside start / end.
-// Suppose we have "foo_bar"('_' is a space).
-// There are 8 offsets for that:
-// f o o _ b a r
-// 0 1 2 3 4 5 6 7
-// If "bar" is a TextFragment. That start(), end() {4, 7} correspond this
-// offset. If a marker has StartOffset / EndOffset as {2, 6},
-// ClampOffset returns{ 4,6 }, which represents "ba" on "foo_bar".
-template <typename TextItem>
-unsigned ClampOffset(unsigned offset, const TextItem& text_fragment) {
- return std::min(std::max(offset, text_fragment.StartOffset()),
- text_fragment.EndOffset());
-}
-
-void PaintRect(GraphicsContext& context,
- const PhysicalRect& rect,
- const Color color) {
- if (!color.Alpha())
- return;
- if (rect.size.IsEmpty())
- return;
- const IntRect pixel_snapped_rect = PixelSnappedIntRect(rect);
- if (!pixel_snapped_rect.IsEmpty())
- context.FillRect(pixel_snapped_rect, color);
-}
-
-void PaintRect(GraphicsContext& context,
- const PhysicalOffset& location,
- const PhysicalRect& rect,
- const Color color) {
- PaintRect(context, PhysicalRect(rect.offset + location, rect.size), color);
-}
-
-template <typename TextItem>
-PhysicalRect MarkerRectForForeground(const TextItem& text_fragment,
- StringView text,
- unsigned start_offset,
- unsigned end_offset) {
- LayoutUnit start_position, end_position;
- std::tie(start_position, end_position) = GetLineLeftAndRightForOffsets(
- text_fragment, text, start_offset, end_offset);
-
- const LayoutUnit height = text_fragment.Size()
- .ConvertToLogical(static_cast<WritingMode>(
- text_fragment.Style().GetWritingMode()))
- .block_size;
- return {start_position, LayoutUnit(), end_position - start_position, height};
-}
-
-// Copied from InlineTextBoxPainter
-template <typename TextItem>
-void PaintDocumentMarkers(const PaintInfo& paint_info,
- const TextItem& text_fragment,
- StringView text,
- const DocumentMarkerVector& markers_to_paint,
- const PhysicalOffset& box_origin,
- const ComputedStyle& style,
- DocumentMarkerPaintPhase marker_paint_phase,
- NGTextPainter* text_painter) {
- if (markers_to_paint.IsEmpty())
- return;
-
- DCHECK(text_fragment.GetNode());
- const auto& text_node = To<Text>(*text_fragment.GetNode());
- for (const DocumentMarker* marker : markers_to_paint) {
- const unsigned marker_start_offset =
- GetTextContentOffset(text_node, marker->StartOffset());
- const unsigned marker_end_offset =
- GetTextContentOffset(text_node, marker->EndOffset());
- const unsigned paint_start_offset =
- ClampOffset(marker_start_offset, text_fragment);
- const unsigned paint_end_offset =
- ClampOffset(marker_end_offset, text_fragment);
- if (paint_start_offset == paint_end_offset)
- continue;
-
- switch (marker->GetType()) {
- case DocumentMarker::kSpelling:
- case DocumentMarker::kGrammar: {
- if (paint_info.context.Printing())
- break;
- if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground)
- continue;
- DocumentMarkerPainter::PaintDocumentMarker(
- paint_info, box_origin, style, marker->GetType(),
- MarkerRectForForeground(text_fragment, text, paint_start_offset,
- paint_end_offset));
- } break;
-
- case DocumentMarker::kTextFragment:
- case DocumentMarker::kTextMatch: {
- Node* node = text_fragment.GetNode();
- const Document& document = node->GetDocument();
- if (marker->GetType() == DocumentMarker::kTextMatch &&
- !document.GetFrame()->GetEditor().MarkedTextMatchesAreHighlighted())
- break;
- const auto& text_marker = To<TextMarkerBase>(*marker);
- if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
- Color color;
- if (marker->GetType() == DocumentMarker::kTextMatch) {
- color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
- text_marker.IsActiveMatch(), document.InForcedColorsMode(),
- style.UsedColorScheme());
- } else {
- color = HighlightPaintingUtils::HighlightBackgroundColor(
- document, style, node, kPseudoIdTargetText);
- }
- PaintRect(paint_info.context, PhysicalOffset(box_origin),
- ComputeLocalRect(text_fragment, text, paint_start_offset,
- paint_end_offset),
- color);
- break;
- }
-
- const TextPaintStyle text_style =
- DocumentMarkerPainter::ComputeTextPaintStyleFrom(
- document, node, style, text_marker, paint_info);
- if (text_style.current_color == Color::kTransparent)
- break;
- text_painter->Paint(paint_start_offset, paint_end_offset,
- paint_end_offset - paint_start_offset, text_style,
- kInvalidDOMNodeId);
- } break;
-
- case DocumentMarker::kComposition:
- case DocumentMarker::kActiveSuggestion:
- case DocumentMarker::kSuggestion: {
- const auto& styleable_marker = To<StyleableMarker>(*marker);
- if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
- PaintRect(paint_info.context, PhysicalOffset(box_origin),
- ComputeLocalRect(text_fragment, text, paint_start_offset,
- paint_end_offset),
- styleable_marker.BackgroundColor());
- break;
- }
- if (DocumentMarkerPainter::ShouldPaintMarkerUnderline(
- styleable_marker)) {
- const SimpleFontData* font_data = style.GetFont().PrimaryFont();
- DocumentMarkerPainter::PaintStyleableMarkerUnderline(
- paint_info.context, box_origin, styleable_marker, style,
- FloatRect(MarkerRectForForeground(
- text_fragment, text, paint_start_offset, paint_end_offset)),
- LayoutUnit(font_data->GetFontMetrics().Height()),
- text_fragment.GetNode()->GetDocument().InDarkMode());
- }
- } break;
-
- default:
- NOTREACHED();
- break;
- }
- }
-}
-
-class SelectionPaintState {
- STACK_ALLOCATED();
-
- public:
- explicit SelectionPaintState(const NGInlineCursor& containing_block)
- : selection_status_(ComputeLayoutSelectionStatus(containing_block)),
- containing_block_(containing_block) {}
-
- const LayoutSelectionStatus& Status() const { return selection_status_; }
-
- const TextPaintStyle& GetSelectionStyle() const { return selection_style_; }
-
- bool ShouldPaintSelectedTextOnly() const { return paint_selected_text_only_; }
-
- bool ShouldPaintSelectedTextSeparately() const {
- return paint_selected_text_separately_;
- }
-
- bool IsSelectionRectComputed() const { return selection_rect_.has_value(); }
-
- void ComputeSelectionStyle(const Document& document,
- const ComputedStyle& style,
- Node* node,
- const PaintInfo& paint_info,
- const TextPaintStyle& text_style) {
- selection_style_ = TextPainterBase::SelectionPaintingStyle(
- document, style, node, paint_info, text_style);
- paint_selected_text_only_ =
- (paint_info.phase == PaintPhase::kSelectionDragImage);
- paint_selected_text_separately_ =
- !paint_selected_text_only_ && text_style != selection_style_;
- }
-
- PhysicalRect ComputeSelectionRect(const PhysicalOffset& box_offset) {
- DCHECK(!selection_rect_);
- selection_rect_ =
- ComputeLocalSelectionRectForText(containing_block_, selection_status_);
- selection_rect_->offset += box_offset;
- return *selection_rect_;
- }
-
- // Logic is copied from InlineTextBoxPainter::PaintSelection.
- // |selection_start| and |selection_end| should be between
- // [text_fragment.StartOffset(), text_fragment.EndOffset()].
- void PaintSelectionBackground(GraphicsContext& context,
- Node* node,
- const Document& document,
- const ComputedStyle& style) {
- const Color color = SelectionBackgroundColor(document, style, node,
- selection_style_.fill_color);
- PaintRect(context, *selection_rect_, color);
- }
-
- // Called before we paint vertical selected text under a rotation transform.
- void MapSelectionRectIntoRotatedSpace(const AffineTransform& rotation) {
- DCHECK(selection_rect_);
- *selection_rect_ = PhysicalRect::EnclosingRect(
- rotation.Inverse().MapRect(FloatRect(*selection_rect_)));
- }
-
- // Paint the selected text only.
- void PaintSelectedText(NGTextPainter& text_painter,
- unsigned length,
- const TextPaintStyle& text_style,
- DOMNodeId node_id) {
- text_painter.PaintSelectedText(selection_status_.start,
- selection_status_.end, length, text_style,
- selection_style_, *selection_rect_, node_id);
- }
-
- // Paint the text except selected parts. Does nothing if all is selected.
- void PaintBeforeAndAfterSelectedText(NGTextPainter& text_painter,
- unsigned start_offset,
- unsigned end_offset,
- unsigned length,
- const TextPaintStyle& text_style,
- DOMNodeId node_id) {
- if (start_offset < selection_status_.start) {
- text_painter.Paint(start_offset, selection_status_.start, length,
- text_style, node_id);
- }
- if (selection_status_.end < end_offset) {
- text_painter.Paint(selection_status_.end, end_offset, length, text_style,
- node_id);
- }
- }
-
- private:
- LayoutSelectionStatus selection_status_;
- TextPaintStyle selection_style_;
- base::Optional<PhysicalRect> selection_rect_;
- const NGInlineCursor& containing_block_;
- bool paint_selected_text_only_;
- bool paint_selected_text_separately_;
-};
-
// Check if text-emphasis and ruby annotation text are on different sides.
// See InlineTextBox::GetEmphasisMarkPosition().
//
@@ -484,36 +102,22 @@ bool ShouldPaintEmphasisMark(const ComputedStyle& style,
} // namespace
-StringView NGTextPainterCursor::CurrentText() const {
- return CurrentItem()->Text();
-}
-
-const NGPaintFragment& NGTextPainterCursor::RootPaintFragment() const {
- if (!root_paint_fragment_)
- root_paint_fragment_ = paint_fragment_.Root();
- return *root_paint_fragment_;
-}
-
-template <typename Cursor>
-void NGTextFragmentPainter<Cursor>::PaintSymbol(
- const LayoutObject* layout_object,
- const ComputedStyle& style,
- const PhysicalSize box_size,
- const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
+void NGTextFragmentPainter::PaintSymbol(const LayoutObject* layout_object,
+ const ComputedStyle& style,
+ const PhysicalSize box_size,
+ const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset) {
PhysicalRect marker_rect(
ListMarker::RelativeSymbolMarkerRect(style, box_size.width));
marker_rect.Move(paint_offset);
- IntRect rect = PixelSnappedIntRect(marker_rect);
-
- ListMarkerPainter::PaintSymbol(paint_info, layout_object, style, rect);
+ ListMarkerPainter::PaintSymbol(paint_info, layout_object, style,
+ marker_rect.ToLayoutRect());
}
// This is copied from InlineTextBoxPainter::PaintSelection() but lacks of
// ltr, expanding new line wrap or so which uses InlineTextBox functions.
-template <typename Cursor>
-void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
+void NGTextFragmentPainter::Paint(const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset) {
const auto& text_item = *cursor_.CurrentItem();
// We can skip painting if the fragment (including selection) is invisible.
if (!text_item.TextLength())
@@ -529,13 +133,13 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
return;
const NGTextFragmentPaintInfo& fragment_paint_info =
- GetTextFragmentPaintInfo(cursor_);
+ cursor_.Current()->TextPaintInfo(cursor_.Items());
const LayoutObject* layout_object = text_item.GetLayoutObject();
const Document& document = layout_object->GetDocument();
- const bool is_printing = paint_info.IsPrinting();
+ const bool is_printing = document.Printing();
// Determine whether or not we're selected.
- base::Optional<SelectionPaintState> selection;
+ base::Optional<NGHighlightPainter::SelectionPaintState> selection;
if (UNLIKELY(!is_printing && paint_info.phase != PaintPhase::kTextClip &&
layout_object->IsSelected())) {
const NGInlineCursor& root_inline_cursor =
@@ -564,12 +168,32 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
// only in BoxPainterBase::PaintFillLayer, which is already within a
// DrawingRecorder.
base::Optional<DrawingRecorder> recorder;
+ const auto& display_item_client =
+ AsDisplayItemClient(cursor_, selection.has_value());
+
+ // Ensure the selection bounds are recorded on the paint chunk regardless of
+ // whether the diplay item that contains the actual selection painting is
+ // reused.
+ base::Optional<SelectionBoundsRecorder> selection_recorder;
+ if (UNLIKELY(selection && paint_info.phase == PaintPhase::kForeground &&
+ !is_printing)) {
+ if (SelectionBoundsRecorder::ShouldRecordSelection(
+ cursor_.Current().GetLayoutObject()->GetFrame()->Selection(),
+ selection->State())) {
+ PhysicalRect selection_rect =
+ selection->ComputeSelectionRect(box_rect.offset);
+ selection_recorder.emplace(selection->State(), selection_rect,
+ paint_info.context.GetPaintController(),
+ cursor_.Current().ResolvedDirection(),
+ style.GetWritingMode());
+ }
+ }
+
if (paint_info.phase != PaintPhase::kTextClip) {
- const auto& display_item_client =
- AsDisplayItemClient(cursor_, selection.has_value());
if (DrawingRecorder::UseCachedDrawingIfPossible(
- paint_info.context, display_item_client, paint_info.phase))
+ paint_info.context, display_item_client, paint_info.phase)) {
return;
+ }
recorder.emplace(paint_info.context, display_item_client, paint_info.phase,
visual_rect);
}
@@ -607,28 +231,27 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
const SimpleFontData* font_data = font.PrimaryFont();
DCHECK(font_data);
- // 1. Paint backgrounds behind text if needed. Examples of such backgrounds
- // include selection and composition highlights. They use physical coordinates
- // so are painted before GraphicsContext rotation.
- const DocumentMarkerVector& markers_to_paint =
- ComputeMarkersToPaint(node, text_item.IsEllipsis());
- if (paint_info.phase != PaintPhase::kSelectionDragImage &&
- paint_info.phase != PaintPhase::kTextClip && !is_printing) {
- PaintDocumentMarkers(paint_info, text_item, cursor_.CurrentText(),
- markers_to_paint, box_rect.offset, style,
- DocumentMarkerPaintPhase::kBackground, nullptr);
- if (UNLIKELY(selection)) {
- auto selection_rect = selection->ComputeSelectionRect(box_rect.offset);
- selection->PaintSelectionBackground(context, node, document, style);
- if (recorder)
- recorder->UniteVisualRect(EnclosingIntRect(selection_rect));
- }
- }
-
+ const bool paint_marker_backgrounds =
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
+ paint_info.phase != PaintPhase::kTextClip && !is_printing;
base::Optional<GraphicsContextStateSaver> state_saver;
base::Optional<AffineTransform> rotation;
const WritingMode writing_mode = style.GetWritingMode();
const bool is_horizontal = IsHorizontalWritingMode(writing_mode);
+ int ascent = font_data ? font_data->GetFontMetrics().Ascent() : 0;
+ PhysicalOffset text_origin(box_rect.offset.left,
+ box_rect.offset.top + ascent);
+ NGTextPainter text_painter(context, font, fragment_paint_info, visual_rect,
+ text_origin, box_rect, is_horizontal);
+ NGHighlightPainter highlight_painter(
+ text_painter, paint_info, cursor_, *cursor_.CurrentItem(),
+ box_rect.offset, style, std::move(selection), is_printing);
+
+ // 1. Paint backgrounds for document markers that don’t participate in the CSS
+ // highlight overlay system, such as composition highlights. They use physical
+ // coordinates, so are painted before GraphicsContext rotation.
+ highlight_painter.Paint(NGHighlightPainter::kBackground);
+
if (!is_horizontal) {
state_saver.emplace(context);
// Because we rotate the GraphicsContext to match the logical direction,
@@ -641,13 +264,27 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
context.ConcatCTM(*rotation);
}
- // 2. Now paint the foreground, including text and decorations.
- int ascent = font_data ? font_data->GetFontMetrics().Ascent() : 0;
- PhysicalOffset text_origin(box_rect.offset.left,
- box_rect.offset.top + ascent);
- NGTextPainter text_painter(context, font, fragment_paint_info, visual_rect,
- text_origin, box_rect, is_horizontal);
+ if (UNLIKELY(highlight_painter.Selection())) {
+ PhysicalRect before_rotation =
+ highlight_painter.Selection()->ComputeSelectionRect(box_rect.offset);
+
+ // The selection rect is given in physical coordinates, so we need to map
+ // them into our now-possibly-rotated space before calling any methods
+ // that might rely on them. Best to do this immediately, because they are
+ // cached internally and could potentially affect any method.
+ if (rotation) {
+ highlight_painter.Selection()->MapSelectionRectIntoRotatedSpace(
+ *rotation);
+ }
+ // We still need to use physical coordinates when invalidating.
+ if (paint_marker_backgrounds && recorder)
+ recorder->UniteVisualRect(EnclosingIntRect(before_rotation));
+ }
+
+ // 2. Now paint the foreground, including text and decorations.
+ // TODO(dazabani@igalia.com): suppress text proper where one or more highlight
+ // overlays are active, but paint shadows in full <https://crbug.com/1147859>
if (ShouldPaintEmphasisMark(style, *layout_object)) {
text_painter.SetEmphasisMark(style.TextEmphasisMarkString(),
style.GetTextEmphasisPosition());
@@ -660,7 +297,8 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
}
const unsigned length = fragment_paint_info.to - fragment_paint_info.from;
- if (!selection || !selection->ShouldPaintSelectedTextOnly()) {
+ if (!highlight_painter.Selection() ||
+ !highlight_painter.Selection()->ShouldPaintSelectedTextOnly()) {
// Paint text decorations except line-through.
base::Optional<TextDecorationInfo> decoration_info;
bool has_line_through_decoration = false;
@@ -671,9 +309,11 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
PhysicalOffset local_origin = box_rect.offset;
LayoutUnit width = box_rect.Width();
base::Optional<AppliedTextDecoration> selection_text_decoration =
- UNLIKELY(selection)
+ UNLIKELY(highlight_painter.Selection())
? base::Optional<AppliedTextDecoration>(
- selection->GetSelectionStyle().selection_text_decoration)
+ highlight_painter.Selection()
+ ->GetSelectionStyle()
+ .selection_text_decoration)
: base::nullopt;
decoration_info.emplace(box_rect.offset, local_origin, width,
@@ -690,8 +330,8 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
unsigned start_offset = fragment_paint_info.from;
unsigned end_offset = fragment_paint_info.to;
- if (UNLIKELY(selection && selection->ShouldPaintSelectedTextSeparately())) {
- selection->PaintBeforeAndAfterSelectedText(
+ if (UNLIKELY(highlight_painter.Selection())) {
+ highlight_painter.Selection()->PaintSuppressingTextProperWhereSelected(
text_painter, start_offset, end_offset, length, text_style, node_id);
} else {
text_painter.Paint(start_offset, end_offset, length, text_style, node_id);
@@ -705,24 +345,27 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
}
}
- if (UNLIKELY(selection && (selection->ShouldPaintSelectedTextOnly() ||
- selection->ShouldPaintSelectedTextSeparately()))) {
+ // 3. Paint CSS highlight overlays, such as ::selection and ::target-text.
+ // For each overlay, we paint its background, then its shadows, then the text
+ // with any decorations it defines, and all of the ::selection overlay parts
+ // are painted over any ::target-text overlay parts, and so on. The text
+ // proper (as opposed to shadows) is only painted by the topmost overlay
+ // applying to a piece of text (if any), and suppressed everywhere else.
+ // TODO(dazabani@igalia.com): implement this for the other highlight pseudos
+ if (UNLIKELY(highlight_painter.Selection())) {
+ if (paint_marker_backgrounds) {
+ highlight_painter.Selection()->PaintSelectionBackground(
+ context, node, document, style, rotation);
+ }
+
// Paint only the text that is selected.
- if (!selection->IsSelectionRectComputed())
- selection->ComputeSelectionRect(box_rect.offset);
- if (rotation)
- selection->MapSelectionRectIntoRotatedSpace(*rotation);
- selection->PaintSelectedText(text_painter, length, text_style, node_id);
+ highlight_painter.Selection()->PaintSelectedText(text_painter, length,
+ text_style, node_id);
}
if (paint_info.phase != PaintPhase::kForeground)
return;
- PaintDocumentMarkers(paint_info, text_item, cursor_.CurrentText(),
- markers_to_paint, box_rect.offset, style,
- DocumentMarkerPaintPhase::kForeground, &text_painter);
+ highlight_painter.Paint(NGHighlightPainter::kForeground);
}
-template class NGTextFragmentPainter<NGTextPainterCursor>;
-template class NGTextFragmentPainter<NGInlineCursor>;
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
index beddc4dc958..08366f6686f 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
@@ -6,8 +6,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -17,7 +15,6 @@ namespace blink {
class ComputedStyle;
class DisplayItemClient;
class LayoutObject;
-class NGPaintFragment;
class NGInlineCursor;
struct NGTextFragmentPaintInfo;
struct PaintInfo;
@@ -25,41 +22,16 @@ struct PhysicalOffset;
struct PhysicalRect;
struct PhysicalSize;
-// The helper class for templatize |NGTextFragmentPainter|.
-// TODO(yosin): Remove |NGTextPainterCursor| once the transition to
-// |NGFragmentItem| is done. http://crbug.com/982194
-class NGTextPainterCursor {
- STACK_ALLOCATED();
-
- public:
- explicit NGTextPainterCursor(const NGPaintFragment& paint_fragment)
- : paint_fragment_(paint_fragment),
- text_fragment_(
- To<NGPhysicalTextFragment>(paint_fragment.PhysicalFragment())) {}
-
- const NGPaintFragment& PaintFragment() const { return paint_fragment_; }
- const NGPhysicalTextFragment* CurrentItem() const { return &text_fragment_; }
- StringView CurrentText() const;
- const NGPaintFragment& RootPaintFragment() const;
-
- private:
- const NGPaintFragment& paint_fragment_;
- const NGPhysicalTextFragment& text_fragment_;
- mutable const NGPaintFragment* root_paint_fragment_ = nullptr;
-};
-
-// Text fragment painter for LayoutNG. Operates on NGPhysicalTextFragments and
-// handles clipping, selection, etc. Delegates to NGTextPainter to paint the
+// Text fragment painter for LayoutNG. Operates on NGFragmentItem that IsText()
+// and handles clipping, selection, etc. Delegates to NGTextPainter to paint the
// text itself.
-// TODO(yosin): We should make |NGTextFragmentPainter| non-template class onnce
-// we get rid of |NGPaintFragment|.
-template <typename Cursor>
class NGTextFragmentPainter {
STACK_ALLOCATED();
public:
- explicit NGTextFragmentPainter(const Cursor& cursor) : cursor_(cursor) {}
- NGTextFragmentPainter(const Cursor& cursor,
+ explicit NGTextFragmentPainter(const NGInlineCursor& cursor)
+ : cursor_(cursor) {}
+ NGTextFragmentPainter(const NGInlineCursor& cursor,
const PhysicalOffset& parent_offset)
: cursor_(cursor), parent_offset_(parent_offset) {}
@@ -83,14 +55,11 @@ class NGTextFragmentPainter {
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset);
- const Cursor& cursor_;
+ const NGInlineCursor& cursor_;
PhysicalOffset parent_offset_;
base::Optional<NGInlineCursor> inline_cursor_for_block_flow_;
};
-extern template class NGTextFragmentPainter<NGTextPainterCursor>;
-extern template class NGTextFragmentPainter<NGInlineCursor>;
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
index 42eb1027cb8..d272a0a0568 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
index ba0a3f82e35..9766e759299 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
@@ -14,6 +13,7 @@
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
@@ -26,9 +26,11 @@ void NGTextPainter::Paint(unsigned start_offset,
unsigned end_offset,
unsigned length,
const TextPaintStyle& text_style,
- DOMNodeId node_id) {
+ DOMNodeId node_id,
+ ShadowMode shadow_mode) {
GraphicsContextStateSaver state_saver(graphics_context_, false);
- UpdateGraphicsContext(text_style, state_saver);
+ UpdateGraphicsContext(graphics_context_, text_style, horizontal_, state_saver,
+ shadow_mode);
// TODO(layout-dev): Handle combine text here or elsewhere.
PaintInternal<kPaintText>(start_offset, end_offset, length, node_id);
@@ -80,7 +82,8 @@ void NGTextPainter::PaintSelectedText(unsigned start_offset,
{
GraphicsContextStateSaver state_saver(graphics_context_);
graphics_context_.ClipOut(float_selection_rect);
- Paint(start_offset, end_offset, length, text_style, node_id);
+ Paint(start_offset, end_offset, length, text_style, node_id,
+ kTextProperOnly);
}
// Then draw the glyphs inside the selection area, with the selection style.
{
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
index 00794480e56..c2c42916cd9 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
@@ -46,7 +46,8 @@ class CORE_EXPORT NGTextPainter : public TextPainterBase {
unsigned end_offset,
unsigned length,
const TextPaintStyle&,
- DOMNodeId);
+ DOMNodeId,
+ ShadowMode = kBothShadowsAndTextProper);
void PaintSelectedText(unsigned start_offset,
unsigned end_offset,
diff --git a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
index 1efb5d8d14c..1520baf964b 100644
--- a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
+++ b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
@@ -22,9 +22,19 @@ static int ComputeEdgeWidth(const BorderImageLength& border_slice,
return ValueForLength(border_slice.length(), LayoutUnit(box_extent)).Floor();
}
-static int ComputeEdgeSlice(const Length& slice, int maximum) {
- return std::min<int>(maximum,
- ValueForLength(slice, LayoutUnit(maximum)).Floor());
+static float ComputeEdgeSlice(const Length& slice,
+ float slice_scale,
+ float maximum) {
+ float resolved;
+ // If the slice is a <number> (stored as a fixed Length), scale it by the
+ // slice scale to get to the same space as the image.
+ if (slice.IsFixed()) {
+ resolved = slice.Value() * slice_scale;
+ } else {
+ DCHECK(slice.IsPercent());
+ resolved = FloatValueForLength(slice, maximum);
+ }
+ return std::min(maximum, resolved);
}
// Scale the width of the |start| and |end| edges using |scale_factor|.
@@ -47,7 +57,9 @@ static void ScaleEdgeWidths(NinePieceImageGrid::Edge& start,
}
NinePieceImageGrid::NinePieceImageGrid(const NinePieceImage& nine_piece_image,
- IntSize image_size,
+ FloatSize image_size,
+ const FloatSize& slice_scale,
+ float zoom,
IntRect border_image_area,
const IntRectOutsets& border_widths,
PhysicalBoxSides sides_to_include)
@@ -56,38 +68,49 @@ NinePieceImageGrid::NinePieceImageGrid(const NinePieceImage& nine_piece_image,
horizontal_tile_rule_(nine_piece_image.HorizontalRule()),
vertical_tile_rule_(nine_piece_image.VerticalRule()),
fill_(nine_piece_image.Fill()) {
- top_.slice = ComputeEdgeSlice(nine_piece_image.ImageSlices().Top(),
+ const LengthBox& image_slices = nine_piece_image.ImageSlices();
+ top_.slice = ComputeEdgeSlice(image_slices.Top(), slice_scale.Height(),
image_size.Height());
- right_.slice = ComputeEdgeSlice(nine_piece_image.ImageSlices().Right(),
+ right_.slice = ComputeEdgeSlice(image_slices.Right(), slice_scale.Width(),
image_size.Width());
- bottom_.slice = ComputeEdgeSlice(nine_piece_image.ImageSlices().Bottom(),
+ bottom_.slice = ComputeEdgeSlice(image_slices.Bottom(), slice_scale.Height(),
image_size.Height());
- left_.slice = ComputeEdgeSlice(nine_piece_image.ImageSlices().Left(),
+ left_.slice = ComputeEdgeSlice(image_slices.Left(), slice_scale.Width(),
image_size.Width());
// TODO(fs): Compute edge widths to LayoutUnit, and then only round to
// integer at the end - after (potential) compensation for overlapping edges.
- top_.width = sides_to_include.top
- ? ComputeEdgeWidth(nine_piece_image.BorderSlices().Top(),
- border_widths.Top(), top_.slice,
- border_image_area.Height())
- : 0;
- right_.width = sides_to_include.right
- ? ComputeEdgeWidth(nine_piece_image.BorderSlices().Right(),
- border_widths.Right(), right_.slice,
- border_image_area.Width())
- : 0;
+
+ // |Edge::slice| is in image-local units (physical pixels for raster images),
+ // but when using it to resolve 'auto' for border-image-widths we want it to
+ // be in zoomed CSS pixels, so divide by |slice_scale| and multiply by zoom.
+ const FloatSize auto_slice_adjustment(zoom / slice_scale.Width(),
+ zoom / slice_scale.Height());
+ const BorderImageLengthBox& border_slices = nine_piece_image.BorderSlices();
+ top_.width =
+ sides_to_include.top
+ ? ComputeEdgeWidth(border_slices.Top(), border_widths.Top(),
+ top_.slice * auto_slice_adjustment.Height(),
+ border_image_area.Height())
+ : 0;
+ right_.width =
+ sides_to_include.right
+ ? ComputeEdgeWidth(border_slices.Right(), border_widths.Right(),
+ right_.slice * auto_slice_adjustment.Width(),
+ border_image_area.Width())
+ : 0;
bottom_.width =
sides_to_include.bottom
- ? ComputeEdgeWidth(nine_piece_image.BorderSlices().Bottom(),
- border_widths.Bottom(), bottom_.slice,
+ ? ComputeEdgeWidth(border_slices.Bottom(), border_widths.Bottom(),
+ bottom_.slice * auto_slice_adjustment.Height(),
border_image_area.Height())
: 0;
- left_.width = sides_to_include.left
- ? ComputeEdgeWidth(nine_piece_image.BorderSlices().Left(),
- border_widths.Left(), left_.slice,
- border_image_area.Width())
- : 0;
+ left_.width =
+ sides_to_include.left
+ ? ComputeEdgeWidth(border_slices.Left(), border_widths.Left(),
+ left_.slice * auto_slice_adjustment.Width(),
+ border_image_area.Width())
+ : 0;
// The spec says: Given Lwidth as the width of the border image area, Lheight
// as its height, and Wside as the border image width offset for the side, let
@@ -108,7 +131,7 @@ NinePieceImageGrid::NinePieceImageGrid(const NinePieceImage& nine_piece_image,
// Given a rectangle, construct a subrectangle using offset, width and height.
// Negative offsets are relative to the extent of the given rectangle.
-static FloatRect Subrect(IntRect rect,
+static FloatRect Subrect(FloatRect rect,
float offset_x,
float offset_y,
float width,
@@ -124,12 +147,21 @@ static FloatRect Subrect(IntRect rect,
return FloatRect(base_x + offset_x, base_y + offset_y, width, height);
}
-static FloatRect Subrect(IntSize size,
+static FloatRect Subrect(IntRect rect,
float offset_x,
float offset_y,
float width,
float height) {
- return Subrect(IntRect(IntPoint(), size), offset_x, offset_y, width, height);
+ return Subrect(FloatRect(rect), offset_x, offset_y, width, height);
+}
+
+static FloatRect Subrect(FloatSize size,
+ float offset_x,
+ float offset_y,
+ float width,
+ float height) {
+ return Subrect(FloatRect(FloatPoint(), size), offset_x, offset_y, width,
+ height);
}
static inline void SetCornerPiece(
@@ -212,8 +244,9 @@ static inline void SetVerticalEdge(
void NinePieceImageGrid::SetDrawInfoEdge(NinePieceDrawInfo& draw_info,
NinePiece piece) const {
- IntSize edge_source_size = image_size_ - IntSize(left_.slice + right_.slice,
- top_.slice + bottom_.slice);
+ FloatSize edge_source_size =
+ image_size_ -
+ FloatSize(left_.slice + right_.slice, top_.slice + bottom_.slice);
IntSize edge_destination_size =
border_image_area_.Size() -
IntSize(left_.width + right_.width, top_.width + bottom_.width);
@@ -258,8 +291,8 @@ void NinePieceImageGrid::SetDrawInfoEdge(NinePieceDrawInfo& draw_info,
}
void NinePieceImageGrid::SetDrawInfoMiddle(NinePieceDrawInfo& draw_info) const {
- IntSize source_size = image_size_ - IntSize(left_.slice + right_.slice,
- top_.slice + bottom_.slice);
+ FloatSize source_size = image_size_ - FloatSize(left_.slice + right_.slice,
+ top_.slice + bottom_.slice);
IntSize destination_size =
border_image_area_.Size() -
IntSize(left_.width + right_.width, top_.width + bottom_.width);
@@ -293,13 +326,14 @@ void NinePieceImageGrid::SetDrawInfoMiddle(NinePieceDrawInfo& draw_info) const {
// factor unless they have a rule other than "stretch". The middle however
// can have "stretch" specified in one axis but not the other, so we have to
// correct the scale here.
- if (horizontal_tile_rule_ == kStretchImageRule)
- middle_scale_factor.SetWidth((float)destination_size.Width() /
+ if (horizontal_tile_rule_ == kStretchImageRule) {
+ middle_scale_factor.SetWidth(destination_size.Width() /
source_size.Width());
-
- if (vertical_tile_rule_ == kStretchImageRule)
- middle_scale_factor.SetHeight((float)destination_size.Height() /
+ }
+ if (vertical_tile_rule_ == kStretchImageRule) {
+ middle_scale_factor.SetHeight(destination_size.Height() /
source_size.Height());
+ }
}
draw_info.tile_scale = middle_scale_factor;
@@ -307,10 +341,7 @@ void NinePieceImageGrid::SetDrawInfoMiddle(NinePieceDrawInfo& draw_info) const {
}
NinePieceImageGrid::NinePieceDrawInfo NinePieceImageGrid::GetNinePieceDrawInfo(
- NinePiece piece,
- float image_scale_factor) const {
- DCHECK_NE(image_scale_factor, 0);
-
+ NinePiece piece) const {
NinePieceDrawInfo draw_info;
draw_info.is_corner_piece =
piece == kTopLeftPiece || piece == kTopRightPiece ||
@@ -323,15 +354,6 @@ NinePieceImageGrid::NinePieceDrawInfo NinePieceImageGrid::GetNinePieceDrawInfo(
else
SetDrawInfoMiddle(draw_info);
- if (image_scale_factor != 1) {
- // The nine piece grid is computed in unscaled image coordinates but must be
- // drawn using scaled image coordinates.
- draw_info.source.Scale(image_scale_factor);
-
- // Compensate for source scaling by scaling down the individual tiles.
- draw_info.tile_scale.Scale(1 / image_scale_factor);
- }
-
return draw_info;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.h b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
index 3688b175de1..18c87201889 100644
--- a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
+++ b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
@@ -63,7 +63,9 @@ class CORE_EXPORT NinePieceImageGrid {
public:
NinePieceImageGrid(const NinePieceImage&,
- IntSize image_size,
+ FloatSize image_size,
+ const FloatSize& slice_scale,
+ float zoom,
IntRect border_image_area,
const IntRectOutsets& border_widths,
PhysicalBoxSides sides_to_include = PhysicalBoxSides());
@@ -85,13 +87,13 @@ class CORE_EXPORT NinePieceImageGrid {
ENinePieceImageRule vertical;
} tile_rule;
};
- NinePieceDrawInfo GetNinePieceDrawInfo(NinePiece, float) const;
+ NinePieceDrawInfo GetNinePieceDrawInfo(NinePiece) const;
struct Edge {
DISALLOW_NEW();
bool IsDrawable() const { return slice > 0 && width > 0; }
- float Scale() const { return IsDrawable() ? (float)width / slice : 1; }
- int slice;
+ float Scale() const { return IsDrawable() ? width / slice : 1; }
+ float slice;
int width;
};
@@ -101,7 +103,7 @@ class CORE_EXPORT NinePieceImageGrid {
void SetDrawInfoMiddle(NinePieceDrawInfo&) const;
IntRect border_image_area_;
- IntSize image_size_;
+ FloatSize image_size_;
ENinePieceImageRule horizontal_tile_rule_;
ENinePieceImageRule vertical_tile_rule_;
bool fill_;
diff --git a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
index b1af14b918e..f8e51fa6e97 100644
--- a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
@@ -30,15 +30,16 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoDrawables) {
NinePieceImage nine_piece;
nine_piece.SetImage(GeneratedImage());
- IntSize image_size(100, 100);
+ FloatSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(0, 0, 0, 0);
- NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, image_size, border_image_area, border_widths);
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
EXPECT_FALSE(draw_info.is_drawable);
}
}
@@ -49,15 +50,16 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_AllDrawable) {
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
nine_piece.SetFill(true);
- IntSize image_size(100, 100);
+ FloatSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
- NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, image_size, border_image_area, border_widths);
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
EXPECT_TRUE(draw_info.is_drawable);
}
}
@@ -68,15 +70,16 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_NoFillMiddleNotDrawable) {
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
nine_piece.SetFill(false); // default
- IntSize image_size(100, 100);
+ FloatSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
- NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, image_size, border_image_area, border_widths);
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
if (piece != kMiddlePiece)
EXPECT_TRUE(draw_info.is_drawable);
else
@@ -89,7 +92,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_TopLeftDrawable) {
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
- IntSize image_size(100, 100);
+ FloatSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
const struct {
@@ -103,11 +106,12 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_TopLeftDrawable) {
};
for (const auto& test_case : test_cases) {
- NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, image_size, border_image_area, test_case.border_widths);
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, test_case.border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
if (piece == kTopLeftPiece)
EXPECT_EQ(draw_info.is_drawable, test_case.expected_is_drawable);
}
@@ -119,7 +123,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
nine_piece.SetImage(GeneratedImage());
nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
- IntSize image_size(100, 100);
+ FloatSize image_size(100, 100);
IntRect border_image_area(0, 0, 100, 100);
IntRectOutsets border_widths(10, 10, 10, 10);
@@ -127,11 +131,12 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
// down and corner pieces cover the entire border image area.
nine_piece.SetBorderSlices(BorderImageLengthBox(6));
- NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, image_size, border_image_area, border_widths);
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
if (draw_info.is_corner_piece)
EXPECT_EQ(draw_info.destination.Size(), FloatSize(50, 50));
else
@@ -144,16 +149,16 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
BorderImageLength bottom_right(20);
nine_piece.SetBorderSlices(
BorderImageLengthBox(top_left, bottom_right, bottom_right, top_left));
- grid = NinePieceImageGrid(nine_piece, image_size, border_image_area,
- border_widths);
+ grid = NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(kTopLeftPiece, 1);
+ grid.GetNinePieceDrawInfo(kTopLeftPiece);
EXPECT_EQ(draw_info.destination.Size(), FloatSize(33, 33));
- draw_info = grid.GetNinePieceDrawInfo(kTopRightPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kTopRightPiece);
EXPECT_EQ(draw_info.destination.Size(), FloatSize(67, 33));
- draw_info = grid.GetNinePieceDrawInfo(kBottomLeftPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kBottomLeftPiece);
EXPECT_EQ(draw_info.destination.Size(), FloatSize(33, 67));
- draw_info = grid.GetNinePieceDrawInfo(kBottomRightPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kBottomRightPiece);
EXPECT_EQ(draw_info.destination.Size(), FloatSize(67, 67));
// Set border slices that overlap in one dimension but not in the other, and
@@ -163,24 +168,24 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ScaleDownBorder) {
BorderImageLength left_right(Length::Fixed(11));
nine_piece.SetBorderSlices(
BorderImageLengthBox(top_bottom, left_right, top_bottom, left_right));
- grid = NinePieceImageGrid(nine_piece, image_size, border_image_area,
- border_widths);
+ grid = NinePieceImageGrid(nine_piece, image_size, FloatSize(1, 1), 1,
+ border_image_area, border_widths);
NinePieceImageGrid::NinePieceDrawInfo tl_info =
- grid.GetNinePieceDrawInfo(kTopLeftPiece, 1);
+ grid.GetNinePieceDrawInfo(kTopLeftPiece);
EXPECT_EQ(tl_info.destination.Size(), FloatSize(6, 50));
// The top-right, bottom-left and bottom-right pieces are the same size as
// the top-left piece.
- draw_info = grid.GetNinePieceDrawInfo(kTopRightPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kTopRightPiece);
EXPECT_EQ(tl_info.destination.Size(), draw_info.destination.Size());
- draw_info = grid.GetNinePieceDrawInfo(kBottomLeftPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kBottomLeftPiece);
EXPECT_EQ(tl_info.destination.Size(), draw_info.destination.Size());
- draw_info = grid.GetNinePieceDrawInfo(kBottomRightPiece, 1);
+ draw_info = grid.GetNinePieceDrawInfo(kBottomRightPiece);
EXPECT_EQ(tl_info.destination.Size(), draw_info.destination.Size());
}
TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
const struct {
- IntSize image_size;
+ FloatSize image_size;
IntRect border_image_area;
IntRectOutsets border_widths;
bool fill;
@@ -199,7 +204,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
} pieces[9];
} test_cases[] = {
{// Empty border and slices but with fill
- IntSize(100, 100),
+ FloatSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 0),
true,
@@ -228,7 +233,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
1, 1, kStretchImageRule, kStretchImageRule},
}},
{// Single border and fill
- IntSize(100, 100),
+ FloatSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 10, 0),
true,
@@ -257,7 +262,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
1.666667, 1.5, kStretchImageRule, kStretchImageRule},
}},
{// All borders, no fill
- IntSize(100, 100),
+ FloatSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(10, 10, 10, 10),
false,
@@ -286,7 +291,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
kStretchImageRule, kStretchImageRule},
}},
{// Single border, no fill
- IntSize(100, 100),
+ FloatSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(0, 0, 0, 10),
false,
@@ -316,7 +321,7 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
}},
{// All borders but no slices, with fill (stretch horizontally, space
// vertically)
- IntSize(100, 100),
+ FloatSize(100, 100),
IntRect(0, 0, 100, 100),
IntRectOutsets(10, 10, 10, 10),
true,
@@ -356,11 +361,11 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
nine_piece.SetVerticalRule((ENinePieceImageRule)test_case.vertical_rule);
NinePieceImageGrid grid = NinePieceImageGrid(
- nine_piece, test_case.image_size, test_case.border_image_area,
- test_case.border_widths);
+ nine_piece, test_case.image_size, FloatSize(1, 1), 1,
+ test_case.border_image_area, test_case.border_widths);
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
NinePieceImageGrid::NinePieceDrawInfo draw_info =
- grid.GetNinePieceDrawInfo(piece, 1);
+ grid.GetNinePieceDrawInfo(piece);
EXPECT_EQ(test_case.pieces[piece].is_drawable, draw_info.is_drawable);
if (!test_case.pieces[piece].is_drawable)
continue;
@@ -395,5 +400,148 @@ TEST_F(NinePieceImageGridTest, NinePieceImagePainting) {
}
}
+TEST_F(NinePieceImageGridTest, NinePieceImagePainting_Zoomed) {
+ NinePieceImage nine_piece;
+ nine_piece.SetImage(GeneratedImage());
+ // Image slices are specified in CSS pixels.
+ nine_piece.SetImageSlices(LengthBox(10, 10, 10, 10));
+ nine_piece.SetFill(true);
+
+ FloatSize image_size(50, 50);
+ IntRect border_image_area(0, 0, 200, 200);
+ IntRectOutsets border_widths(20, 20, 20, 20);
+
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(2, 2), 2,
+ border_image_area, border_widths);
+ struct {
+ bool is_drawable;
+ bool is_corner_piece;
+ FloatRect destination;
+ FloatRect source;
+ float tile_scale_horizontal;
+ float tile_scale_vertical;
+ ENinePieceImageRule horizontal_rule;
+ ENinePieceImageRule vertical_rule;
+ } expected_pieces[kMaxPiece] = {
+ {true, true, FloatRect(0, 0, 20, 20), FloatRect(0, 0, 20, 20), 0, 0,
+ kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(0, 180, 20, 20), FloatRect(0, 30, 20, 20), 0, 0,
+ kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(0, 20, 20, 160), FloatRect(0, 20, 20, 10), 1, 1,
+ kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(180, 0, 20, 20), FloatRect(30, 0, 20, 20), 0, 0,
+ kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(180, 180, 20, 20), FloatRect(30, 30, 20, 20), 0, 0,
+ kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(180, 20, 20, 160), FloatRect(30, 20, 20, 10), 1,
+ 1, kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(20, 0, 160, 20), FloatRect(20, 0, 10, 20), 1, 1,
+ kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(20, 180, 160, 20), FloatRect(20, 30, 10, 20), 1,
+ 1, kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(20, 20, 160, 160), FloatRect(20, 20, 10, 10), 16,
+ 16, kStretchImageRule, kStretchImageRule},
+ };
+
+ for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
+ NinePieceImageGrid::NinePieceDrawInfo draw_info =
+ grid.GetNinePieceDrawInfo(piece);
+ EXPECT_TRUE(draw_info.is_drawable);
+
+ const auto& expected = expected_pieces[piece];
+ EXPECT_EQ(draw_info.destination, expected.destination);
+ EXPECT_EQ(draw_info.source, expected.source);
+
+ if (expected.is_corner_piece)
+ continue;
+
+ EXPECT_FLOAT_EQ(draw_info.tile_scale.Width(),
+ expected.tile_scale_horizontal);
+ EXPECT_FLOAT_EQ(draw_info.tile_scale.Height(),
+ expected.tile_scale_vertical);
+ EXPECT_EQ(draw_info.tile_rule.vertical, expected.vertical_rule);
+ EXPECT_EQ(draw_info.tile_rule.horizontal, expected.horizontal_rule);
+ }
+}
+
+TEST_F(NinePieceImageGridTest, NinePieceImagePainting_ZoomedNarrowSlices) {
+ NinePieceImage nine_piece;
+ nine_piece.SetImage(GeneratedImage());
+ // Image slices are specified in CSS pixels.
+ nine_piece.SetImageSlices(LengthBox(1, 1, 1, 1));
+ nine_piece.SetFill(true);
+
+ constexpr float zoom = 2.2f;
+ FloatSize image_size(3 * zoom, 3 * zoom);
+ IntRect border_image_area(0, 0, 220, 220);
+ IntRectOutsets border_widths(33, 33, 33, 33);
+
+ NinePieceImageGrid grid =
+ NinePieceImageGrid(nine_piece, image_size, FloatSize(zoom, zoom), zoom,
+ border_image_area, border_widths);
+ struct {
+ bool is_drawable;
+ bool is_corner_piece;
+ FloatRect destination;
+ FloatRect source;
+ float tile_scale_horizontal;
+ float tile_scale_vertical;
+ ENinePieceImageRule horizontal_rule;
+ ENinePieceImageRule vertical_rule;
+ } expected_pieces[kMaxPiece] = {
+ {true, true, FloatRect(0, 0, 33, 33), FloatRect(0, 0, 2.2f, 2.2f), 0, 0,
+ kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(0, 187, 33, 33), FloatRect(0, 4.4f, 2.2f, 2.2f), 0,
+ 0, kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(0, 33, 33, 154), FloatRect(0, 2.2f, 2.2f, 2.2f),
+ 15, 15, kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(187, 0, 33, 33), FloatRect(4.4f, 0, 2.2f, 2.2f), 0,
+ 0, kStretchImageRule, kStretchImageRule},
+ {true, true, FloatRect(187, 187, 33, 33),
+ FloatRect(4.4f, 4.4f, 2.2f, 2.2f), 0, 0, kStretchImageRule,
+ kStretchImageRule},
+ {true, false, FloatRect(187, 33, 33, 154),
+ FloatRect(4.4f, 2.2f, 2.2f, 2.2f), 15, 15, kStretchImageRule,
+ kStretchImageRule},
+ {true, false, FloatRect(33, 0, 154, 33), FloatRect(2.2f, 0, 2.2f, 2.2f),
+ 15, 15, kStretchImageRule, kStretchImageRule},
+ {true, false, FloatRect(33, 187, 154, 33),
+ FloatRect(2.2f, 4.4f, 2.2f, 2.2f), 15, 15, kStretchImageRule,
+ kStretchImageRule},
+ {true, false, FloatRect(33, 33, 154, 154),
+ FloatRect(2.2f, 2.2f, 2.2f, 2.2f), 70, 70, kStretchImageRule,
+ kStretchImageRule},
+ };
+
+ for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
+ NinePieceImageGrid::NinePieceDrawInfo draw_info =
+ grid.GetNinePieceDrawInfo(piece);
+ EXPECT_TRUE(draw_info.is_drawable);
+
+ const auto& expected = expected_pieces[piece];
+ EXPECT_FLOAT_EQ(draw_info.destination.X(), expected.destination.X());
+ EXPECT_FLOAT_EQ(draw_info.destination.Y(), expected.destination.Y());
+ EXPECT_FLOAT_EQ(draw_info.destination.Width(),
+ expected.destination.Width());
+ EXPECT_FLOAT_EQ(draw_info.destination.Height(),
+ expected.destination.Height());
+ EXPECT_FLOAT_EQ(draw_info.source.X(), expected.source.X());
+ EXPECT_FLOAT_EQ(draw_info.source.Y(), expected.source.Y());
+ EXPECT_FLOAT_EQ(draw_info.source.Width(), expected.source.Width());
+ EXPECT_FLOAT_EQ(draw_info.source.Height(), expected.source.Height());
+
+ if (expected.is_corner_piece)
+ continue;
+
+ EXPECT_FLOAT_EQ(draw_info.tile_scale.Width(),
+ expected.tile_scale_horizontal);
+ EXPECT_FLOAT_EQ(draw_info.tile_scale.Height(),
+ expected.tile_scale_vertical);
+ EXPECT_EQ(draw_info.tile_rule.vertical, expected.vertical_rule);
+ EXPECT_EQ(draw_info.tile_rule.horizontal, expected.horizontal_rule);
+ }
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
index 8be7a975418..67587b83c28 100644
--- a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
@@ -75,65 +75,84 @@ base::Optional<TileParameters> ComputeTileParameters(
return base::nullopt;
}
+bool ShouldTile(const NinePieceImageGrid::NinePieceDrawInfo& draw_info) {
+ // Corner pieces shouldn't be tiled.
+ if (draw_info.is_corner_piece)
+ return false;
+ // If we're supposed to stretch in both dimensions, we can skip tiling
+ // calculations.
+ if (draw_info.tile_rule.horizontal == kStretchImageRule &&
+ draw_info.tile_rule.vertical == kStretchImageRule)
+ return false;
+ return true;
+}
+
void PaintPieces(GraphicsContext& context,
const PhysicalRect& border_image_rect,
const ComputedStyle& style,
const NinePieceImage& nine_piece_image,
Image* image,
- IntSize image_size,
+ const FloatSize& unzoomed_image_size,
PhysicalBoxSides sides_to_include) {
+ // |image_size| is in the image's native resolution and |slice_scale| defines
+ // the effective size of a CSS pixel in the image.
+ FloatSize image_size = image->SizeAsFloat(kRespectImageOrientation);
+ // Compute the scale factor to apply to the slice values by relating the
+ // zoomed size to the "unzoomed" (CSS pixel) size. For raster images this
+ // should match any DPR scale while for generated images it should match the
+ // effective zoom. (Modulo imprecisions introduced by the computation.) This
+ // scale should in theory be uniform.
+ FloatSize slice_scale(image_size.Width() / unzoomed_image_size.Width(),
+ image_size.Height() / unzoomed_image_size.Height());
+
IntRectOutsets border_widths(style.BorderTopWidth(), style.BorderRightWidth(),
style.BorderBottomWidth(),
style.BorderLeftWidth());
- NinePieceImageGrid grid(nine_piece_image, image_size,
- PixelSnappedIntRect(border_image_rect), border_widths,
- sides_to_include);
+ NinePieceImageGrid grid(
+ nine_piece_image, image_size, slice_scale, style.EffectiveZoom(),
+ PixelSnappedIntRect(border_image_rect), border_widths, sides_to_include);
+ ScopedInterpolationQuality interpolation_quality_scope(
+ context, style.GetInterpolationQuality());
for (NinePiece piece = kMinPiece; piece < kMaxPiece; ++piece) {
- NinePieceImageGrid::NinePieceDrawInfo draw_info = grid.GetNinePieceDrawInfo(
- piece, nine_piece_image.GetImage()->ImageScaleFactor());
-
- if (draw_info.is_drawable) {
- if (draw_info.is_corner_piece) {
- // Since there is no way for the developer to specify decode behavior,
- // use kSync by default.
- context.DrawImage(image, Image::kSyncDecode, draw_info.destination,
- &draw_info.source, style.HasFilterInducingProperty());
- } else if (draw_info.tile_rule.horizontal == kStretchImageRule &&
- draw_info.tile_rule.vertical == kStretchImageRule) {
- // Just do a scale.
- // Since there is no way for the developer to specify decode behavior,
- // use kSync by default.
- context.DrawImage(image, Image::kSyncDecode, draw_info.destination,
- &draw_info.source, style.HasFilterInducingProperty());
- } else {
- // TODO(cavalcantii): see crbug.com/662513.
- base::Optional<TileParameters> h_tile = ComputeTileParameters(
- draw_info.tile_rule.horizontal, draw_info.destination.X(),
- draw_info.destination.Width(), draw_info.source.X(),
- draw_info.source.Width(), draw_info.tile_scale.Width());
- base::Optional<TileParameters> v_tile = ComputeTileParameters(
- draw_info.tile_rule.vertical, draw_info.destination.Y(),
- draw_info.destination.Height(), draw_info.source.Y(),
- draw_info.source.Height(), draw_info.tile_scale.Height());
- if (!h_tile || !v_tile)
- continue;
-
- FloatSize tile_scale_factor(h_tile->scale_factor, v_tile->scale_factor);
- FloatPoint tile_phase(draw_info.destination.X() - h_tile->phase,
- draw_info.destination.Y() - v_tile->phase);
- FloatSize tile_spacing(h_tile->spacing, v_tile->spacing);
-
- // TODO(cavalcantii): see crbug.com/662507.
- base::Optional<ScopedInterpolationQuality> interpolation_quality_scope;
- if (draw_info.tile_rule.horizontal == kRoundImageRule ||
- draw_info.tile_rule.vertical == kRoundImageRule)
- interpolation_quality_scope.emplace(context, kInterpolationMedium);
-
- context.DrawImageTiled(image, draw_info.destination, draw_info.source,
- tile_scale_factor, tile_phase, tile_spacing);
- }
+ NinePieceImageGrid::NinePieceDrawInfo draw_info =
+ grid.GetNinePieceDrawInfo(piece);
+ if (!draw_info.is_drawable)
+ continue;
+
+ if (!ShouldTile(draw_info)) {
+ // Since there is no way for the developer to specify decode behavior,
+ // use kSync by default.
+ context.DrawImage(image, Image::kSyncDecode, draw_info.destination,
+ &draw_info.source, style.HasFilterInducingProperty());
+ continue;
}
+
+ // TODO(cavalcantii): see crbug.com/662513.
+ base::Optional<TileParameters> h_tile = ComputeTileParameters(
+ draw_info.tile_rule.horizontal, draw_info.destination.X(),
+ draw_info.destination.Width(), draw_info.source.X(),
+ draw_info.source.Width(), draw_info.tile_scale.Width());
+ base::Optional<TileParameters> v_tile = ComputeTileParameters(
+ draw_info.tile_rule.vertical, draw_info.destination.Y(),
+ draw_info.destination.Height(), draw_info.source.Y(),
+ draw_info.source.Height(), draw_info.tile_scale.Height());
+ if (!h_tile || !v_tile)
+ continue;
+
+ FloatSize tile_scale_factor(h_tile->scale_factor, v_tile->scale_factor);
+ FloatPoint tile_phase(draw_info.destination.X() - h_tile->phase,
+ draw_info.destination.Y() - v_tile->phase);
+ FloatSize tile_spacing(h_tile->spacing, v_tile->spacing);
+
+ // TODO(cavalcantii): see crbug.com/662507.
+ base::Optional<ScopedInterpolationQuality> interpolation_quality_override;
+ if (draw_info.tile_rule.horizontal == kRoundImageRule ||
+ draw_info.tile_rule.vertical == kRoundImageRule)
+ interpolation_quality_override.emplace(context, kInterpolationMedium);
+
+ context.DrawImageTiled(image, draw_info.destination, draw_info.source,
+ tile_scale_factor, tile_phase, tile_spacing);
}
}
@@ -165,35 +184,33 @@ bool NinePieceImagePainter::Paint(GraphicsContext& graphics_context,
rect_with_outsets.Expand(style.ImageOutsets(nine_piece_image));
PhysicalRect border_image_rect = rect_with_outsets;
- // NinePieceImage returns the image slices without effective zoom applied and
- // thus we compute the nine piece grid on top of the image in unzoomed
- // coordinates.
- //
- // FIXME: The default object size passed to imageSize() should be scaled by
- // the zoom factor passed in. In this case it means that borderImageRect
- // should be passed in compensated by effective zoom, since the scale factor
- // is one. For generated images, the actual image data (gradient stops, etc.)
- // are scaled to effective zoom instead so we must take care not to cause
- // scale of them again.
- IntSize image_size = RoundedIntSize(
- style_image->ImageSize(document, 1, FloatSize(border_image_rect.size),
- kRespectImageOrientation));
+ // Resolve the image size for any image that may need it (for example
+ // generated or SVG), then get an image using that size. This will yield an
+ // image with either "native" size (raster images) or size scaled by effective
+ // zoom.
+ const FloatSize default_object_size(border_image_rect.size);
+ FloatSize image_size =
+ style_image->ImageSize(document, style.EffectiveZoom(),
+ default_object_size, kRespectImageOrientation);
scoped_refptr<Image> image =
- style_image->GetImage(observer, document, style, FloatSize(image_size));
+ style_image->GetImage(observer, document, style, image_size);
if (!image)
return true;
+ // Resolve the image size again, this time with a size-multiplier of one, to
+ // yield the size in CSS pixels. This is the unit/scale we expect the
+ // 'border-image-slice' values to be in.
+ FloatSize unzoomed_image_size = style_image->ImageSize(
+ document, 1, default_object_size.ScaledBy(1 / style.EffectiveZoom()),
+ kRespectImageOrientation);
+
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
"data",
inspector_paint_image_event::Data(node, *style_image,
FloatRect(image->Rect()),
FloatRect(border_image_rect)));
-
- ScopedInterpolationQuality interpolation_quality_scope(
- graphics_context, style.GetInterpolationQuality());
PaintPieces(graphics_context, border_image_rect, style, nine_piece_image,
- image.get(), image_size, sides_to_include);
-
+ image.get(), unzoomed_image_size, sides_to_include);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index 645379eaf28..aa420b67bd8 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -10,7 +10,6 @@
#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/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/object_painter.cc b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
index 9ace9c2dc48..a59fa4d19f7 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
@@ -37,7 +37,7 @@ void ObjectPainter::PaintOutline(const PaintInfo& paint_info,
auto outline_rects = layout_object_.OutlineRects(
paint_offset,
- layout_object_.OutlineRectsShouldIncludeBlockVisualOverflow());
+ style_to_use.OutlineRectsShouldIncludeBlockVisualOverflow());
if (outline_rects.IsEmpty())
return;
diff --git a/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
index be697658d52..4e1210df2d5 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
@@ -544,9 +544,16 @@ float GetFocusRingBorderRadius(const ComputedStyle& style) {
break;
}
if (part) {
- return ui::NativeTheme::GetInstanceForWeb()->GetBorderRadiusForPart(
- part.value(), style.Width().GetFloatValue(),
- style.Height().GetFloatValue(), style.EffectiveZoom());
+ border_radius =
+ ui::NativeTheme::GetInstanceForWeb()->GetBorderRadiusForPart(
+ part.value(), style.Width().GetFloatValue(),
+ style.Height().GetFloatValue());
+
+ // Form controls send to NativeTheme have zoom applied. But the focus ring
+ // outline does not. Apply zoom to checkbox focus ring.
+ return (style.EffectiveAppearance() == kCheckboxPart)
+ ? border_radius * style.EffectiveZoom()
+ : border_radius;
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index af13bf9f73c..fb7cf4730ca 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -841,20 +841,23 @@ TEST_P(PaintAndRasterInvalidationTest, SVGHiddenContainer) {
UpdateAllLifecyclePhasesForTest();
// Should invalidate raster for real_rect only.
- EXPECT_THAT(
- GetRasterInvalidationTracking()->Invalidations(),
- UnorderedElementsAre(
- RasterInvalidationInfo{real_rect, real_rect->DebugName(),
- IntRect(155, 166, 7, 8),
- PaintInvalidationReason::kSVGResource},
- RasterInvalidationInfo{real_rect, real_rect->DebugName(),
- IntRect(154, 165, 9, 10),
- PaintInvalidationReason::kSVGResource}));
+ EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+ UnorderedElementsAre(
+ RasterInvalidationInfo{real_rect, real_rect->DebugName(),
+ IntRect(155, 166, 7, 8),
+ PaintInvalidationReason::kSubtree},
+ RasterInvalidationInfo{real_rect, real_rect->DebugName(),
+ IntRect(154, 165, 9, 10),
+ PaintInvalidationReason::kSubtree}));
GetDocument().View()->SetTracksRasterInvalidations(false);
}
TEST_P(PaintAndRasterInvalidationTest, PaintPropertyChange) {
+ // TODO(wangxianzhu): See the TODO in CullRectUpdater::SetFragmentCullRects().
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
SetUpHTML(*this);
Element* target = GetDocument().getElementById("target");
auto* object = target->GetLayoutObject();
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
index 4bfe90f7436..6b02de06305 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_info.h b/chromium/third_party/blink/renderer/core/paint/paint_info.h
index 73c7cc76a03..a0950407858 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_info.h
@@ -53,11 +53,11 @@ namespace blink {
class LayoutBoxModelObject;
struct CORE_EXPORT PaintInfo {
- USING_FAST_MALLOC(PaintInfo);
+ STACK_ALLOCATED();
public:
PaintInfo(GraphicsContext& context,
- const IntRect& cull_rect,
+ const CullRect& cull_rect,
PaintPhase phase,
GlobalPaintFlags global_paint_flags,
PaintLayerFlags paint_flags,
@@ -70,9 +70,7 @@ struct CORE_EXPORT PaintInfo {
fragment_logical_top_in_flow_thread_(
fragment_logical_top_in_flow_thread),
paint_flags_(paint_flags),
- global_paint_flags_(global_paint_flags),
- is_painting_scrolling_background_(false),
- descendant_painting_blocked_(false) {}
+ global_paint_flags_(global_paint_flags) {}
PaintInfo(GraphicsContext& new_context,
const PaintInfo& copy_other_fields_from)
@@ -83,9 +81,7 @@ struct CORE_EXPORT PaintInfo {
fragment_logical_top_in_flow_thread_(
copy_other_fields_from.fragment_logical_top_in_flow_thread_),
paint_flags_(copy_other_fields_from.paint_flags_),
- global_paint_flags_(copy_other_fields_from.global_paint_flags_),
- is_painting_scrolling_background_(false),
- descendant_painting_blocked_(false) {
+ global_paint_flags_(copy_other_fields_from.global_paint_flags_) {
// We should never pass is_painting_scrolling_background_ other PaintInfo.
DCHECK(!copy_other_fields_from.is_painting_scrolling_background_);
}
@@ -124,7 +120,6 @@ struct CORE_EXPORT PaintInfo {
paint_flags_ &= ~kPaintLayerPaintingSkipRootBackground;
}
- bool IsPrinting() const { return global_paint_flags_ & kGlobalPaintPrinting; }
bool ShouldAddUrlMetadata() const {
return global_paint_flags_ & kGlobalPaintAddUrlMetadata;
}
@@ -142,6 +137,7 @@ struct CORE_EXPORT PaintInfo {
PaintLayerFlags PaintFlags() const { return paint_flags_; }
const CullRect& GetCullRect() const { return cull_rect_; }
+ void SetCullRect(const CullRect& cull_rect) { cull_rect_ = cull_rect; }
bool IntersectsCullRect(
const PhysicalRect& rect,
@@ -220,10 +216,10 @@ struct CORE_EXPORT PaintInfo {
const GlobalPaintFlags global_paint_flags_;
// For CAP only.
- bool is_painting_scrolling_background_ : 1;
+ bool is_painting_scrolling_background_ = false;
// Used by display-locking.
- bool descendant_painting_blocked_ : 1;
+ bool descendant_painting_blocked_ = false;
};
Image::ImageDecodingMode GetImageDecodingMode(Node*);
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 317a856ed2e..3d229397e89 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -19,10 +19,10 @@
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
#include "third_party/blink/renderer/core/page/link_highlight.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -64,8 +64,12 @@ void PaintInvalidator::UpdatePaintingLayer(const LayoutObject& object,
IsLayoutNGContainingBlock(object.ContainingBlock())))
context.painting_layer->SetNeedsPaintPhaseFloat();
- if (object != context.painting_layer->GetLayoutObject() &&
- object.StyleRef().HasOutline())
+ if (!context.painting_layer->NeedsPaintPhaseDescendantOutlines() &&
+ ((object != context.painting_layer->GetLayoutObject() &&
+ object.StyleRef().HasOutline()) ||
+ // If this is a block-in-inline, it may need to paint outline.
+ // See |StyleForContinuationOutline|.
+ (layout_block_flow && layout_block_flow->StyleForContinuationOutline())))
context.painting_layer->SetNeedsPaintPhaseDescendantOutlines();
}
@@ -104,20 +108,28 @@ void PaintInvalidator::UpdateDirectlyCompositedContainer(
// This is to exclude some objects (e.g. LayoutText) inheriting
// stacked style from parent but aren't actually stacked.
object.HasLayer() &&
- !To<LayoutBoxModelObject>(object)
- .Layer()
- ->IsReplacedNormalFlowStacking() &&
context.directly_composited_container !=
context.directly_composited_container_for_stacked_contents) {
- // The current object is stacked, so we should use
- // directly_composited_container_for_stacked_contents as its paint
- // invalidation container on which the current object is painted.
- context.directly_composited_container =
- context.directly_composited_container_for_stacked_contents;
- if (context.subtree_flags &
- PaintInvalidatorContext::kSubtreeFullInvalidationForStackedContents) {
- context.subtree_flags |=
- PaintInvalidatorContext::kSubtreeFullInvalidation;
+ if (To<LayoutBoxModelObject>(object)
+ .Layer()
+ ->IsReplacedNormalFlowStacking()) {
+ DCHECK(object.IsStackingContext());
+ // A ReplacedNormalFlowStacking object doesn't stack into parent stacking
+ // context, while the stacked descendants are stacked into it and inherit
+ // its direct_composited_container.
+ context.directly_composited_container_for_stacked_contents =
+ context.directly_composited_container;
+ } else {
+ // The current object is stacked, so we should use
+ // directly_composited_container_for_stacked_contents as its paint
+ // invalidation container on which the current object is painted.
+ context.directly_composited_container =
+ context.directly_composited_container_for_stacked_contents;
+ if (context.subtree_flags &
+ PaintInvalidatorContext::kSubtreeFullInvalidationForStackedContents) {
+ context.subtree_flags |=
+ PaintInvalidatorContext::kSubtreeFullInvalidation;
+ }
}
}
@@ -137,9 +149,10 @@ void PaintInvalidator::UpdateDirectlyCompositedContainer(
}
}
- DCHECK(context.directly_composited_container ==
- object.DirectlyCompositableContainer());
- DCHECK(context.painting_layer == object.PaintingLayer());
+ DCHECK_EQ(context.directly_composited_container,
+ object.DirectlyCompositableContainer())
+ << object;
+ DCHECK_EQ(context.painting_layer, object.PaintingLayer()) << object;
}
void PaintInvalidator::UpdateFromTreeBuilderContext(
@@ -171,6 +184,11 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
if (!object.ShouldCheckGeometryForPaintInvalidation())
return;
+ if (tree_builder_context.this_or_ancestor_opacity_is_zero) {
+ object.GetMutableForPainting().SetShouldSkipNextLayoutShiftTracking(true);
+ return;
+ }
+
auto& layout_shift_tracker = object.GetFrameView()->GetLayoutShiftTracker();
if (!layout_shift_tracker.NeedsToTrack(object)) {
object.GetMutableForPainting().SetShouldSkipNextLayoutShiftTracking(true);
@@ -181,6 +199,20 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
*tree_builder_context.current.transform,
*tree_builder_context.current.clip, *tree_builder_context.current_effect);
+ // Adjust old_paint_offset so that LayoutShiftTracker will see the change of
+ // offset caused by change of paint offset translations and scroll offset
+ // below the layout shift root. For more details, see
+ // renderer/core/layout/layout-shift-tracker-old-paint-offset.md.
+ PhysicalOffset adjusted_old_paint_offset =
+ context.old_paint_offset -
+ tree_builder_context.current
+ .additional_offset_to_layout_shift_root_delta -
+ PhysicalOffset::FromFloatSizeRound(
+ tree_builder_context.translation_2d_to_layout_shift_root_delta +
+ tree_builder_context.current
+ .scroll_offset_to_layout_shift_root_delta);
+ PhysicalOffset new_paint_offset = tree_builder_context.current.paint_offset;
+
if (object.IsText()) {
const auto& text = To<LayoutText>(object);
LogicalOffset new_starting_point;
@@ -199,11 +231,10 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
layout_shift_tracker.NotifyTextPrePaint(
text, property_tree_state, old_starting_point, new_starting_point,
- // Similar to the adjustment of old_paint_offset for LayoutBox.
- context.old_paint_offset -
- tree_builder_context.current
- .additional_offset_to_layout_shift_root_delta,
- tree_builder_context.current.paint_offset, logical_height);
+ adjusted_old_paint_offset,
+ tree_builder_context.translation_2d_to_layout_shift_root_delta,
+ tree_builder_context.current.scroll_offset_to_layout_shift_root_delta,
+ new_paint_offset, logical_height);
return;
}
@@ -211,7 +242,23 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
const auto& box = To<LayoutBox>(object);
PhysicalRect new_rect = box.PhysicalVisualOverflowRect();
+ new_rect.Move(new_paint_offset);
PhysicalRect old_rect = box.PreviousPhysicalVisualOverflowRect();
+ old_rect.Move(adjusted_old_paint_offset);
+
+ bool should_create_containing_block_scope =
+ // TODO(crbug.com/1178618): Support multiple-fragments when switching to
+ // LayoutNGFragmentTraversal.
+ context.fragment_data == &box.FirstFragment() &&
+ box.IsLayoutBlockFlow() && box.ChildrenInline() && box.SlowFirstChild();
+ if (should_create_containing_block_scope) {
+ // For layout shift tracking of contained LayoutTexts.
+ context.containing_block_scope_ =
+ std::make_unique<LayoutShiftTracker::ContainingBlockScope>(
+ PhysicalSizeToBeNoop(box.PreviousSize()),
+ PhysicalSizeToBeNoop(box.Size()), old_rect, new_rect);
+ }
+
bool should_report_layout_shift = [&]() -> bool {
if (box.ShouldSkipNextLayoutShiftTracking()) {
box.GetMutableForPainting().SetShouldSkipNextLayoutShiftTracking(false);
@@ -228,8 +275,10 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
if (object.HasLayer() &&
To<LayoutBoxModelObject>(object).HasSelfPaintingLayer())
return true;
- // We don't report shift for anonymous objects but report for the children.
- if (object.Parent()->IsAnonymous())
+ // Always track if the parent doesn't need to track (e.g. it has visibility:
+ // hidden), while this object needs (e.g. it has visibility: visible).
+ // This also includes non-anonymous child with an anonymous parent.
+ if (object.Parent()->ShouldSkipNextLayoutShiftTracking())
return true;
// Report if the parent is in a different transform space.
const auto* parent_context = context.ParentContext();
@@ -240,41 +289,15 @@ void PaintInvalidator::UpdateLayoutShiftTracking(
// different from that of the parent).
return parent_context->fragment_data->PaintOffset() -
parent_context->old_paint_offset !=
- tree_builder_context.current.paint_offset - context.old_paint_offset;
+ new_paint_offset - context.old_paint_offset;
}();
-
- bool should_create_containing_block_scope =
- // TODO(crbug.com/1104064): Support multiple-fragments when switching to
- // LayoutNGFragmentTraversal.
- context.fragment_data == &box.FirstFragment() &&
- box.IsLayoutBlockFlow() && box.ChildrenInline() && box.SlowFirstChild();
- if (!should_report_layout_shift && !should_create_containing_block_scope)
- return;
-
- new_rect.Move(tree_builder_context.current.paint_offset);
- old_rect.Move(context.old_paint_offset);
- // Adjust old_visual_rect so that LayoutShiftTracker can see the change of
- // offset caused by change of transforms below the 2d translation root.
- old_rect.Move(-tree_builder_context.current
- .additional_offset_to_layout_shift_root_delta);
-
- if (should_create_containing_block_scope) {
- // For layout shift tracking of contained LayoutTexts.
- context.containing_block_scope_ =
- std::make_unique<LayoutShiftTracker::ContainingBlockScope>(
- PhysicalSizeToBeNoop(box.PreviousSize()),
- PhysicalSizeToBeNoop(box.Size()), old_rect, new_rect);
- if (!should_report_layout_shift)
- return;
+ if (should_report_layout_shift) {
+ layout_shift_tracker.NotifyBoxPrePaint(
+ box, property_tree_state, old_rect, new_rect, adjusted_old_paint_offset,
+ tree_builder_context.translation_2d_to_layout_shift_root_delta,
+ tree_builder_context.current.scroll_offset_to_layout_shift_root_delta,
+ new_paint_offset);
}
-
- // Adjust old_paint_offset similarly.
- PhysicalOffset old_paint_offset =
- context.old_paint_offset -
- tree_builder_context.current.additional_offset_to_layout_shift_root_delta;
- layout_shift_tracker.NotifyBoxPrePaint(
- box, property_tree_state, old_rect, new_rect, old_paint_offset,
- tree_builder_context.current.paint_offset);
}
bool PaintInvalidator::InvalidatePaint(
@@ -312,7 +335,9 @@ bool PaintInvalidator::InvalidatePaint(
PaintInvalidatorContext::kSubtreeInvalidationChecking;
}
- if (UNLIKELY(object.ContainsInlineWithOutlineAndContinuation())) {
+ if (UNLIKELY(object.ContainsInlineWithOutlineAndContinuation()) &&
+ // Need this only if the subtree needs to check geometry change.
+ PrePaintTreeWalk::ObjectRequiresTreeBuilderContext(object)) {
// Force subtree invalidation checking to ensure invalidation of focus rings
// when continuation's geometry changes.
context.subtree_flags |=
@@ -351,6 +376,9 @@ bool PaintInvalidator::InvalidatePaint(
UpdateFromTreeBuilderContext(fragment_tree_builder_context, context);
UpdateLayoutShiftTracking(object, fragment_tree_builder_context,
context);
+ object.GetFrameView()
+ ->GetMobileFriendlinessChecker()
+ .NotifyInvalidatePaint(object);
} else {
context.old_paint_offset = fragment_data->PaintOffset();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
index 742fff0e8a5..34937525158 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -137,6 +137,28 @@ inline PhysicalRect PhysicalVisualOverflowRectAllowingUnset(
return layout_object.PhysicalVisualOverflowRect();
}
+PaintLayer* SlowContainingLayer(const PaintLayer* ancestor,
+ bool* skipped_ancestor,
+ LayoutObject* layout_object) {
+ // This is a universal approach to find the containing layer, but it is
+ // slower.
+ base::Optional<LayoutObject::AncestorSkipInfo> skip_info;
+ if (skipped_ancestor)
+ skip_info.emplace(&ancestor->GetLayoutObject());
+ while (auto* container = layout_object->Container(
+ skipped_ancestor ? &*skip_info : nullptr)) {
+ if (skipped_ancestor) {
+ if (skip_info->AncestorSkipped())
+ *skipped_ancestor = true;
+ skip_info.emplace(&ancestor->GetLayoutObject());
+ }
+ if (container->HasLayer())
+ return To<LayoutBoxModelObject>(container)->Layer();
+ layout_object = container;
+ }
+ return nullptr;
+}
+
} // namespace
PaintLayerRareData::PaintLayerRareData()
@@ -170,6 +192,9 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
lost_grouped_mapping_(false),
self_needs_repaint_(false),
descendant_needs_repaint_(false),
+ needs_cull_rect_update_(false),
+ forces_children_cull_rect_update_(false),
+ descendant_needs_cull_rect_update_(false),
previous_paint_result_(kFullyPainted),
needs_paint_phase_descendant_outlines_(false),
needs_paint_phase_float_(false),
@@ -333,12 +358,15 @@ void PaintLayer::UpdateLayerPositionsAfterLayout() {
RuntimeCallStats::CounterId::kUpdateLayerPositionsAfterLayout);
ClearClipRects();
- UpdateLayerPositionRecursive();
-
+ const LayoutBlock* enclosing_scrollport_box =
+ GetLayoutObject().EnclosingScrollportBox();
+ UpdateLayerPositionRecursive(
+ enclosing_scrollport_box ? enclosing_scrollport_box->Layer() : nullptr);
UpdatePaginationRecursive(EnclosingPaginationLayer());
}
-void PaintLayer::UpdateLayerPositionRecursive() {
+void PaintLayer::UpdateLayerPositionRecursive(
+ const PaintLayer* enclosing_scroller) {
auto old_location = location_without_position_offset_;
auto old_offset_for_in_flow_rel_position = OffsetForInFlowRelPosition();
UpdateLayerPosition();
@@ -354,6 +382,45 @@ void PaintLayer::UpdateLayerPositionRecursive() {
SetNeedsCompositingInputsUpdate();
}
+ const PaintLayer* previous_enclosing_scroller =
+ AncestorScrollContainerLayer();
+ UpdateAncestorScrollContainerLayer(enclosing_scroller);
+ if (enclosing_scroller &&
+ GetLayoutObject().StyleRef().HasStickyConstrainedPosition() &&
+ (NeedsCompositingInputsUpdate() ||
+ GetLayoutObject().NeedsPaintPropertyUpdate())) {
+ if (enclosing_scroller != previous_enclosing_scroller) {
+ // Old ancestor scroller should no longer have these constraints.
+ DCHECK(!previous_enclosing_scroller ||
+ !previous_enclosing_scroller->GetScrollableArea() ||
+ !previous_enclosing_scroller->GetScrollableArea()
+ ->GetStickyConstraintsMap()
+ .Contains(this));
+
+ // If our ancestor scroller has changed and the previous one was the
+ // root layer, we are no longer viewport constrained.
+ if (previous_enclosing_scroller &&
+ previous_enclosing_scroller->IsRootLayer()) {
+ GetLayoutObject()
+ .View()
+ ->GetFrameView()
+ ->RemoveViewportConstrainedObject(
+ GetLayoutObject(),
+ LocalFrameView::ViewportConstrainedType::kSticky);
+ }
+ }
+
+ if (enclosing_scroller->IsRootLayer()) {
+ GetLayoutObject().View()->GetFrameView()->AddViewportConstrainedObject(
+ GetLayoutObject(), LocalFrameView::ViewportConstrainedType::kSticky);
+ }
+ GetLayoutObject().UpdateStickyPositionConstraints();
+
+ // Sticky position constraints and ancestor overflow scroller affect
+ // the sticky layer position, so we need to update it again here.
+ UpdateLayerPosition();
+ }
+
// Display-locked elements always have a PaintLayer, meaning that the
// PaintLayer traversal won't skip locked elements. Thus, we don't have to do
// an ancestor check, and simply skip iterating children when this element is
@@ -361,8 +428,10 @@ void PaintLayer::UpdateLayerPositionRecursive() {
if (GetLayoutObject().ChildLayoutBlockedByDisplayLock())
return;
+ if (GetLayoutObject().IsScrollContainer())
+ enclosing_scroller = this;
for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
- child->UpdateLayerPositionRecursive();
+ child->UpdateLayerPositionRecursive(enclosing_scroller);
}
bool PaintLayer::SticksToScroller() const {
@@ -409,6 +478,30 @@ bool PaintLayer::IsAffectedByScrollOf(const PaintLayer* ancestor) const {
return current_layer == ancestor;
}
+bool PaintLayer::IsTopMostNotAffectedByScrollOf(
+ const PaintLayer* ancestor) const {
+ // Returns true if |this| is the top-most fixed-pos layer between |this|
+ // (inclusive) and |ancestor.
+
+ // Should only call this method for layers that we already know are not
+ // affected by the scroll offset of the ancestor (implying this element or
+ // an ancestor must be fixed).
+ DCHECK(!IsAffectedByScrollOf(ancestor));
+
+ // Only fixed-pos elements can be top-most.
+ if (!GetLayoutObject().IsFixedPositioned())
+ return false;
+
+ PaintLayer* curr = Parent();
+ while (curr && curr != ancestor) {
+ if (curr->GetLayoutObject().IsFixedPositioned())
+ return false;
+ curr = curr->Parent();
+ }
+
+ return true;
+}
+
void PaintLayer::UpdateTransformationMatrix() {
if (TransformationMatrix* transform = Transform()) {
LayoutBox* box = GetLayoutBox();
@@ -865,6 +958,14 @@ PaintLayer* PaintLayer::ContainingLayer(const PaintLayer* ancestor,
LayoutObject& layout_object = GetLayoutObject();
if (layout_object.IsOutOfFlowPositioned()) {
+ // In NG, the containing block chain goes directly from a column spanner to
+ // the multi-column container. Thus, for an OOF nested inside a spanner, we
+ // need to find its containing layer through its containing block to handle
+ // this case correctly. Therefore, we technically only need to take this
+ // path for OOFs inside an NG spanner. However, doing so for all OOF
+ // descendants of a multicol container is reasonable enough.
+ if (layout_object.IsInsideFlowThread())
+ return SlowContainingLayer(ancestor, skipped_ancestor, &layout_object);
auto can_contain_this_layer =
layout_object.IsFixedPositioned()
? &LayoutObject::CanContainFixedPositionObjects
@@ -890,21 +991,7 @@ PaintLayer* PaintLayer::ContainingLayer(const PaintLayer* ancestor,
!layout_object.IsColumnSpanAll() && !layout_object.IsRenderedLegend())
return Parent();
- // This is a universal approach to find containing layer, but is slower than
- // the earlier code.
- base::Optional<LayoutObject::AncestorSkipInfo> skip_info;
- if (skipped_ancestor)
- skip_info.emplace(&ancestor->GetLayoutObject());
- auto* object = &layout_object;
- while (auto* container =
- object->Container(skipped_ancestor ? &*skip_info : nullptr)) {
- if (skipped_ancestor && skip_info->AncestorSkipped())
- *skipped_ancestor = true;
- if (container->HasLayer())
- return To<LayoutBoxModelObject>(container)->Layer();
- object = container;
- }
- return nullptr;
+ return SlowContainingLayer(ancestor, skipped_ancestor, &layout_object);
}
PhysicalOffset PaintLayer::ComputeOffsetFromAncestor(
@@ -1081,10 +1168,14 @@ void PaintLayer::SetChildNeedsCompositingInputsUpdateUpToAncestor(
const IntRect PaintLayer::ClippedAbsoluteBoundingBox() const {
if (RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
- PhysicalRect mapping_rect = BoundingBoxForCompositingOverlapTest();
+ PhysicalRect mapping_rect = LocalBoundingBoxForCompositingOverlapTest();
GetLayoutObject().MapToVisualRectInAncestorSpace(
GetLayoutObject().View(), mapping_rect, kUseGeometryMapper);
- return EnclosingIntRect(mapping_rect);
+ // We use PixelSnappedIntRect here to match the behavior in
+ // CIU:: UpdateAncestorDependentCompositingInputs, even though the code
+ // in UnclippedAbsoluteBoundingBox and its equivalent in
+ // CIU::UpdateAncestorDependentCompositingInputs uses EnclosingIntRect.
+ return PixelSnappedIntRect(mapping_rect);
} else {
return GetAncestorDependentCompositingInputs()
.clipped_absolute_bounding_box;
@@ -1093,8 +1184,8 @@ const IntRect PaintLayer::ClippedAbsoluteBoundingBox() const {
const IntRect PaintLayer::UnclippedAbsoluteBoundingBox() const {
if (RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
return EnclosingIntRect(GetLayoutObject().LocalToAbsoluteRect(
- BoundingBoxForCompositingOverlapTest(),
- kUseGeometryMapperMode | kIgnoreScrollOffset));
+ LocalBoundingBoxForCompositingOverlapTest(),
+ kUseGeometryMapperMode | kIgnoreScrollOffsetOfAncestor));
} else {
return GetAncestorDependentCompositingInputs()
.unclipped_absolute_bounding_box;
@@ -1394,9 +1485,6 @@ void PaintLayer::RemoveOnlyThisLayerAfterStyleChange(
PaintLayer* next = current->NextSibling();
RemoveChild(current);
parent_->AddChild(current, next_sib);
-
- // FIXME: We should call a specialized version of this function.
- current->UpdateLayerPositionsAfterLayout();
current = next;
}
@@ -2506,8 +2594,8 @@ void PaintLayer::UpdateFilterReferenceBox() {
if (!HasFilterThatMovesPixels())
return;
PhysicalRect result = LocalBoundingBox();
- ExpandRectForStackingChildren(
- *this, result, PaintLayer::kIncludeTransformsAndCompositedChildLayers);
+ ExpandRectForSelfPaintingDescendants(
+ *this, result, kIncludeTransforms | kIncludeCompositedChildLayers);
FloatRect reference_box = FloatRect(result);
float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
@@ -2575,7 +2663,8 @@ bool PaintLayer::HitTestClippedOutByClipPath(
.Contains(point);
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
- LayoutSVGResourceClipper* clipper = GetSVGResourceAsType(clip_path_operation);
+ LayoutSVGResourceClipper* clipper =
+ GetSVGResourceAsType(*ResourceInfo(), clip_path_operation);
if (!clipper)
return false;
// If the clipPath is using "userspace on use" units, then the origin of
@@ -2625,6 +2714,13 @@ PhysicalRect PaintLayer::LocalBoundingBox() const {
return rect;
}
+PhysicalRect PaintLayer::ClippedLocalBoundingBox(
+ const PaintLayer& ancestor_layer) const {
+ return Intersection(LocalBoundingBox(),
+ Clipper(GeometryMapperOption::kUseGeometryMapper)
+ .LocalClipRect(ancestor_layer));
+}
+
PhysicalRect PaintLayer::PhysicalBoundingBox(
const PaintLayer* ancestor_layer) const {
PhysicalOffset offset_from_root;
@@ -2649,7 +2745,15 @@ PhysicalRect PaintLayer::FragmentsBoundingBox(
return result;
}
-PhysicalRect PaintLayer::BoundingBoxForCompositingOverlapTest() const {
+PhysicalRect PaintLayer::LocalBoundingBoxForCompositingOverlapTest() const {
+ // Returns the bounding box, in the local coordinate system for this layer,
+ // for the content that this paint layer is responsible for compositing. This
+ // doesn't include the content painted by self-painting descendants such as
+ // composited absolute positioned children. But the bounds is suitable for
+ // calculations such as squashing sparsity. To get the bounds that includes
+ // the visible extent of this layer and its children for overlap testing, use
+ // ExpandedBoundingBoxForCompositingOverlapTest.
+
// Apply NeverIncludeTransformForAncestorLayer, because the geometry map in
// CompositingInputsUpdater will take care of applying the transform of |this|
// (== the ancestorLayer argument to boundingBoxForCompositing).
@@ -2668,43 +2772,113 @@ PhysicalRect PaintLayer::BoundingBoxForCompositingOverlapTest() const {
style.BackdropFilter().MapRect(FloatRect(bounding_box)));
}
- if (FixedToViewport() && !bounding_box.IsEmpty()) {
- DCHECK_EQ(style.GetPosition(), EPosition::kFixed);
- // Note that we only expand the bounding box for overlap testing when the
- // fixed's containing block is the viewport. This keeps us from expanding
- // the bounds when the fixed is a child of an ancestor with transform,
- // filters, etc. and the fixed is no longer scroll position dependent.
-
- // Expand the bounding box by the amount that scrolling the
- // viewport can expand the area that this fixed-pos element could
- // cover. Compute how much we could still scroll in each direction.
- // |max_scroll_delta| is the amount we could still scroll in
- // increasing offset direction. |min_scroll_delta| is the amount we
- // can still scroll in a decreasing scroll offset direction.
- PaintLayerScrollableArea* scrollable_area =
- GetLayoutObject().View()->GetScrollableArea();
+ return bounding_box;
+}
+
+IntRect PaintLayer::ExpandedBoundingBoxForCompositingOverlapTest(
+ bool use_clipped_bounding_rect) const {
+ // Returns the bounding box for this layer and self-painted composited
+ // children which are otherwise not included in
+ // LocalBoundingBoxForCompositingOverlapTest. Use the bounds from this layer
+ // for overlap testing that cares about the bounds of this layer and all its
+ // children.
+ IntRect abs_bounds = use_clipped_bounding_rect
+ ? ClippedAbsoluteBoundingBox()
+ : UnclippedAbsoluteBoundingBox();
+ PaintLayer* root_layer = GetLayoutObject().View()->Layer();
+ // |abs_bounds| does not include root scroller offset, as in it's in absolute
+ // coordinates, for everything but fixed-pos objects (and their children)
+ // which are in viewport coords. Adjusting these to all be in absolute coords
+ // happens here. This adjustment is delayed until this point in time as doing
+ // it during compositing inputs update would embed the scroll offset at the
+ // time the compositing inputs was ran when converting from viewport to
+ // absolute, making the resulting rects unusable for any other scroll offset.
+ if (root_layer->GetScrollableArea() && !abs_bounds.IsEmpty() &&
+ !IsAffectedByScrollOf(root_layer)) {
+ PaintLayerScrollableArea* scrollable_area = root_layer->GetScrollableArea();
ScrollOffset current_scroll_offset = scrollable_area->GetScrollOffset();
- ScrollOffset max_scroll_delta =
- scrollable_area->MaximumScrollOffset() - current_scroll_offset;
- ScrollOffset min_scroll_delta =
- current_scroll_offset - scrollable_area->MinimumScrollOffset();
- bounding_box.Expand(
- LayoutRectOutsets(min_scroll_delta.Height(), max_scroll_delta.Width(),
- max_scroll_delta.Height(), min_scroll_delta.Width()));
+ // Move the bounds to absolute coords
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled())
+ abs_bounds.Move(RoundedIntSize(current_scroll_offset));
+
+ if (IsTopMostNotAffectedByScrollOf(root_layer)) {
+ // For overlap testing, expand the rect used for fixed-pos content in
+ // two ways. First, include any children such that overlap testing
+ // against the top-most fixed-pos layer is guaranteed to detect any
+ // overlap where a self-painting composited child of the fixed-pos layer
+ // exceeds the fixed-pos layer's bounds. Second, expand the rect to
+ // include the area it could cover if the view were to be scrolled to
+ // its minimum and maximum extents. This allows skipping overlap testing
+ // on scroll offset changes. Note that bounds expansion does not happen
+ // for fixed under a non-view container (under xform or filter for
+ // example) as those fixed still are affected by the view's scroll offset.
+ // This is checked for with the IsAffectedByScrollOf call earlier.
+
+ // Expand the rect to include children that are not already included in
+ // |layer|'s bounds.
+ PhysicalRect children_bounds;
+ if (!GetLayoutObject().ChildPaintBlockedByDisplayLock()) {
+ PaintLayerPaintOrderIterator iterator(*this, kAllChildren);
+ while (PaintLayer* child_layer = iterator.Next()) {
+ // Note that we intentionally include children irrespective of if they
+ // are composited or not.
+ children_bounds.Unite(child_layer->BoundingBoxForCompositingInternal(
+ *this, this,
+ kIncludeAncestorClips | kIncludeTransforms |
+ kIncludeCompositedChildLayers));
+ }
+ if (!children_bounds.IsEmpty()) {
+ GetLayoutObject().MapToVisualRectInAncestorSpace(
+ GetLayoutObject().View(), children_bounds, kUseGeometryMapper);
+ abs_bounds.Unite(EnclosingIntRect(children_bounds));
+ }
+ }
+
+ // Expand bounds to include min/max scroll extents
+ ScrollOffset max_scroll_delta =
+ scrollable_area->MaximumScrollOffset() - current_scroll_offset;
+ ScrollOffset min_scroll_delta =
+ current_scroll_offset - scrollable_area->MinimumScrollOffset();
+ abs_bounds.Expand(
+ IntRectOutsets(min_scroll_delta.Height(), max_scroll_delta.Width(),
+ max_scroll_delta.Height(), min_scroll_delta.Width()));
+ }
}
- return bounding_box;
+ return abs_bounds;
}
-void PaintLayer::ExpandRectForStackingChildren(
+void PaintLayer::ExpandRectForSelfPaintingDescendants(
const PaintLayer& composited_layer,
PhysicalRect& result,
- PaintLayer::CalculateBoundsOptions options) const {
- // If we're locked, th en the subtree does not contribute painted output.
+ unsigned options) const {
+ // If we're locked, then the subtree does not contribute painted output.
// Furthermore, we might not have up-to-date sizing and position information
// in the subtree, so skip recursing into the subtree.
if (GetLayoutObject().ChildPaintBlockedByDisplayLock())
return;
+ DCHECK_EQ(result, (options & kIncludeAncestorClips)
+ ? ClippedLocalBoundingBox(composited_layer)
+ : LocalBoundingBox());
+ // The input |result| is based on LayoutObject::PhysicalVisualOverflowRect()
+ // which already includes bounds non-self-painting descendants.
+ if (!HasSelfPaintingLayerDescendant())
+ return;
+
+ if (const auto* box = GetLayoutBox()) {
+ // If the layer clips overflow and all descendants are contained, then no
+ // need to expand for children. Not checking kIncludeAncestorClips because
+ // the clip of the current layer is always applied. The doesn't check
+ // whether the non-contained descendants are actual descendants of this
+ // layer in paint order because it's not easy.
+ if (box->ShouldClipOverflowAlongBothAxis() &&
+ !HasNonContainedAbsolutePositionDescendant() &&
+ !(HasFixedPositionDescendant() &&
+ !box->CanContainFixedPositionObjects())) {
+ return;
+ }
+ }
+
PaintLayerPaintOrderIterator iterator(*this, kAllChildren);
while (PaintLayer* child_layer = iterator.Next()) {
// Here we exclude both directly composited layers and squashing layers
@@ -2712,31 +2886,33 @@ void PaintLayer::ExpandRectForStackingChildren(
// for this Layer. For example, the bounds of squashed Layers
// will be included in the computation of the appropriate squashing
// GraphicsLayer.
- if (options != PaintLayer::CalculateBoundsOptions::
- kIncludeTransformsAndCompositedChildLayers &&
- child_layer->GetCompositingState() != kNotComposited)
- continue;
- result.Unite(child_layer->BoundingBoxForCompositingInternal(
- composited_layer, this, options));
+ if ((options & kIncludeCompositedChildLayers) ||
+ child_layer->GetCompositingState() == kNotComposited) {
+ result.Unite(child_layer->BoundingBoxForCompositingInternal(
+ composited_layer, this, options));
+ }
}
}
PhysicalRect PaintLayer::BoundingBoxForCompositing() const {
return BoundingBoxForCompositingInternal(
- *this, nullptr, kIncludeClipsAndMaybeIncludeTransformForAncestorLayer);
+ *this, nullptr,
+ kIncludeAncestorClips | kMaybeIncludeTransformForAncestorLayer);
}
bool PaintLayer::ShouldApplyTransformToBoundingBox(
const PaintLayer& composited_layer,
- CalculateBoundsOptions options) const {
+ unsigned options) const {
+ DCHECK(!(options & kIncludeTransforms) ||
+ !(options & kMaybeIncludeTransformForAncestorLayer));
if (!Transform())
return false;
- if (options == kIncludeTransformsAndCompositedChildLayers)
+ if (options & kIncludeTransforms)
return true;
if (PaintsWithTransform(kGlobalPaintNormalPhase)) {
if (this != &composited_layer)
return true;
- if (options == kIncludeClipsAndMaybeIncludeTransformForAncestorLayer)
+ if (options & kMaybeIncludeTransformForAncestorLayer)
return true;
}
return false;
@@ -2745,7 +2921,7 @@ bool PaintLayer::ShouldApplyTransformToBoundingBox(
PhysicalRect PaintLayer::BoundingBoxForCompositingInternal(
const PaintLayer& composited_layer,
const PaintLayer* stacking_parent,
- CalculateBoundsOptions options) const {
+ unsigned options) const {
DCHECK_GE(GetLayoutObject().GetDocument().Lifecycle().GetState(),
DocumentLifecycle::kInPrePaint);
if (!IsSelfPaintingLayer())
@@ -2775,22 +2951,16 @@ PhysicalRect PaintLayer::BoundingBoxForCompositingInternal(
return PhysicalRect();
PhysicalRect result;
- if (options == kIncludeClipsAndMaybeIncludeTransformForAncestorLayer) {
+ if (options & kIncludeAncestorClips) {
// If there is a clip applied by an ancestor to this PaintLayer but below or
- // equal to |ancestorLayer|, apply that clip. This optimizes the size
+ // equal to |composited_layer|, apply that clip. This optimizes the size
// of the composited layer to exclude clipped-out regions of descendants.
- result = Clipper((GetLayoutObject().GetDocument().Lifecycle().GetState() ==
- DocumentLifecycle::kInCompositingAssignmentsUpdate)
- ? GeometryMapperOption::kUseGeometryMapper
- : GeometryMapperOption::kUseGeometryMapper)
- .LocalClipRect(composited_layer);
-
- result.Intersect(LocalBoundingBox());
+ result = ClippedLocalBoundingBox(composited_layer);
} else {
result = LocalBoundingBox();
}
- ExpandRectForStackingChildren(composited_layer, result, options);
+ ExpandRectForSelfPaintingDescendants(composited_layer, result, options);
// Only enlarge by the filter outsets if we know the filter is going to be
// rendered in software. Accelerated filters will handle their own outsets.
@@ -3407,7 +3577,7 @@ PaintLayer::CreateCompositorFilterOperationsForBackdropFilter() const {
// Use kClamp tile mode to avoid pixel moving filters bringing in black
// transparent pixels from the viewport edge.
return_value = FilterEffectBuilder(reference_box, zoom, nullptr, nullptr,
- SkBlurImageFilter::kClamp_TileMode)
+ SkTileMode::kClamp)
.BuildFilterOperations(filter_operations);
// Note that return_value may be empty here, if the |filter_operations| list
// contains only invalid filters (e.g. invalid reference filters). See
@@ -3611,6 +3781,56 @@ const PaintLayer* PaintLayer::CommonAncestor(const PaintLayer* other) const {
return nullptr;
}
+void PaintLayer::SetNeedsCullRectUpdate() {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
+ if (needs_cull_rect_update_)
+ return;
+ needs_cull_rect_update_ = true;
+ MarkCompositingContainerChainForNeedsCullRectUpdate();
+}
+
+void PaintLayer::SetForcesChildrenCullRectUpdate() {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
+ if (forces_children_cull_rect_update_)
+ return;
+ forces_children_cull_rect_update_ = true;
+ descendant_needs_cull_rect_update_ = true;
+ MarkCompositingContainerChainForNeedsCullRectUpdate();
+}
+
+void PaintLayer::MarkCompositingContainerChainForNeedsCullRectUpdate() {
+ // Mark compositing container chain for needing cull rect update. This is
+ // similar to MarkCompositingContainerChainForNeedsRepaint().
+ PaintLayer* layer = this;
+ while (true) {
+ // For a non-self-painting layer having self-painting descendant, the
+ // descendant will be painted through this layer's Parent() instead of
+ // this layer's Container(), so in addition to the CompositingContainer()
+ // chain, we also need to mark NeedsRepaint for Parent().
+ // TODO(crbug.com/828103): clean up this.
+ if (layer->Parent() && !layer->IsSelfPaintingLayer())
+ layer->Parent()->SetNeedsCullRectUpdate();
+
+ PaintLayer* container = layer->CompositingContainer();
+ if (!container) {
+ auto* owner = layer->GetLayoutObject().GetFrame()->OwnerLayoutObject();
+ if (!owner)
+ break;
+ container = owner->EnclosingLayer();
+ }
+
+ DCHECK(!container->GetLayoutObject().ChildPrePaintBlockedByDisplayLock());
+
+ if (container->descendant_needs_cull_rect_update_)
+ break;
+
+ container->descendant_needs_cull_rect_update_ = true;
+ layer = container;
+ }
+}
+
void PaintLayer::DirtyStackingContextZOrderLists() {
auto* stacking_context = AncestorStackingContext();
if (!stacking_context)
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.h b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
index 694eeef4c7d..688a6e6b592 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
@@ -461,12 +461,17 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PhysicalRect& damage_rect,
const PhysicalOffset& offset_from_root) const;
- // MaybeIncludeTransformForAncestorLayer means that a transform on
- // |ancestorLayer| may be applied to the bounding box, in particular if
- // paintsWithTransform() is true.
enum CalculateBoundsOptions {
- kIncludeClipsAndMaybeIncludeTransformForAncestorLayer,
- kIncludeTransformsAndCompositedChildLayers,
+ // Include clips between this layer and its ancestor layer (inclusive).
+ kIncludeAncestorClips = 0x1,
+ // Include transforms, irrespective of if they are applied via composition
+ // or painting.
+ kIncludeTransforms = 0x2,
+ // Include child layers (recursive) whether composited or not.
+ kIncludeCompositedChildLayers = 0x4,
+ // Include transform for the ancestor layer (|composited_layer| in the
+ // initial call) if |PaintsWithTransform|
+ kMaybeIncludeTransformForAncestorLayer = 0x8
};
// Bounding box relative to some ancestor layer. Pass offsetFromRoot if known.
@@ -475,10 +480,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
PhysicalRect PhysicalBoundingBox(const PaintLayer* ancestor_layer) const;
PhysicalRect FragmentsBoundingBox(const PaintLayer* ancestor_layer) const;
- PhysicalRect BoundingBoxForCompositingOverlapTest() const;
+ PhysicalRect LocalBoundingBoxForCompositingOverlapTest() const;
+ IntRect ExpandedBoundingBoxForCompositingOverlapTest(
+ bool use_clipped_bounding_rect) const;
PhysicalRect BoundingBoxForCompositing() const;
-
// Static position is set in parent's coordinate space.
LayoutUnit StaticInlinePosition() const { return static_inline_position_; }
LayoutUnit StaticBlockPosition() const { return static_block_position_; }
@@ -804,7 +810,14 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PaintLayer* nearest_contained_layout_layer = nullptr;
// These two boxes do not include any applicable scroll offset of the
- // root PaintLayer.
+ // root PaintLayer. Note that 'absolute' here is potentially misleading as
+ // the actual coordinate system depends on if this layer is affected by the
+ // viewport's scroll offset or not. For content that is not affected by the
+ // viewport scroll offsets, this ends up being a rect in viewport coords.
+ // For content that is affected by the viewport's scroll offset this
+ // coordinate system is in absolute coords.
+ // Note: This stores LocalBoundingBoxForCompositingOverlapTest and not the
+ // expanded bounds (ExpandedBoundingBoxForCompositingOverlapTest).
IntRect clipped_absolute_bounding_box;
IntRect unclipped_absolute_bounding_box;
@@ -1009,13 +1022,37 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
void SetDescendantNeedsRepaint();
void ClearNeedsRepaintRecursively();
+ bool NeedsCullRectUpdate() const {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ return needs_cull_rect_update_;
+ }
+ bool ForcesChildrenCullRectUpdate() const {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ return forces_children_cull_rect_update_;
+ }
+ bool DescendantNeedsCullRectUpdate() const {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ return descendant_needs_cull_rect_update_;
+ }
+ void SetNeedsCullRectUpdate();
+ void SetForcesChildrenCullRectUpdate();
+ void MarkCompositingContainerChainForNeedsCullRectUpdate();
+ void ClearNeedsCullRectUpdate() {
+ DCHECK(RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ needs_cull_rect_update_ = false;
+ forces_children_cull_rect_update_ = false;
+ descendant_needs_cull_rect_update_ = false;
+ }
+
// These previousXXX() functions are for subsequence caching. They save the
// painting status of the layer during the previous painting with subsequence.
// A painting without subsequence [1] doesn't change this status. [1] See
// shouldCreateSubsequence() in PaintLayerPainter.cpp for the cases we use
// subsequence when painting a PaintLayer.
- CullRect PreviousCullRect() const { return previous_cull_rect_; }
+ // TODO(wangxianzhu): Remove these functions when we use the cull rects
+ // in FragmentData updated during PrePaint.
+ const CullRect& PreviousCullRect() const { return previous_cull_rect_; }
void SetPreviousCullRect(const CullRect& rect) { previous_cull_rect_ = rect; }
PaintResult PreviousPaintResult() const {
@@ -1147,10 +1184,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// Bounding box in the coordinates of this layer.
PhysicalRect LocalBoundingBox() const;
+ PhysicalRect ClippedLocalBoundingBox(const PaintLayer& ancestor_layer) const;
bool HasOverflowControls() const;
- void UpdateLayerPositionRecursive();
+ void UpdateLayerPositionRecursive(const PaintLayer* enclosing_scroller);
void SetNextSibling(PaintLayer* next) { next_ = next; }
void SetPreviousSibling(PaintLayer* prev) { previous_ = prev; }
@@ -1275,18 +1313,20 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
needs_paint_phase_float_ |= layer.needs_paint_phase_float_;
}
- void ExpandRectForStackingChildren(const PaintLayer& composited_layer,
- PhysicalRect& result,
- PaintLayer::CalculateBoundsOptions) const;
+ bool IsTopMostNotAffectedByScrollOf(const PaintLayer* ancestor) const;
+
+ void ExpandRectForSelfPaintingDescendants(const PaintLayer& composited_layer,
+ PhysicalRect& result,
+ unsigned options) const;
// The return value is in the space of |stackingParent|, if non-null, or
// |this| otherwise.
PhysicalRect BoundingBoxForCompositingInternal(
const PaintLayer& composited_layer,
const PaintLayer* stacking_parent,
- CalculateBoundsOptions) const;
+ unsigned options) const;
bool ShouldApplyTransformToBoundingBox(const PaintLayer& composited_layer,
- CalculateBoundsOptions) const;
+ unsigned options) const;
AncestorDependentCompositingInputs& EnsureAncestorDependentCompositingInputs()
const {
@@ -1346,8 +1386,14 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
unsigned self_needs_repaint_ : 1;
unsigned descendant_needs_repaint_ : 1;
+
+ unsigned needs_cull_rect_update_ : 1;
+ unsigned forces_children_cull_rect_update_ : 1;
+ // True if any descendant needs cull rect update.
+ unsigned descendant_needs_cull_rect_update_ : 1;
+
unsigned previous_paint_result_ : 1; // PaintResult
- static_assert(kMaxPaintResult <= 2,
+ static_assert(kMaxPaintResult < 2,
"Should update number of bits of previous_paint_result_");
unsigned needs_paint_phase_descendant_outlines_ : 1;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 8f3cfc4a409..9b54fcb0c36 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -111,7 +111,7 @@ static bool ShouldCreateSubsequence(
const GraphicsContext& context,
const PaintLayerPaintingInfo& painting_info) {
// Caching is not needed during printing or painting previews.
- if (context.Printing() || context.IsPaintingPreview())
+ if (paint_layer.GetLayoutObject().GetDocument().IsPrintingOrPaintingPreview())
return false;
if (context.GetPaintController().IsSkippingCache())
@@ -147,25 +147,45 @@ static bool ShouldRepaintSubsequence(
// Repaint if previously the layer may be clipped by cull rect, and cull rect
// changes.
- if ((paint_layer.PreviousPaintResult() == kMayBeClippedByCullRect ||
- // When PaintUnderInvalidationChecking is enabled, always repaint the
- // subsequence when the paint rect changes because we will strictly match
- // new and cached subsequences. Normally we can reuse the cached fully
- // painted subsequence even if we would partially paint this time.
- RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) &&
- paint_layer.PreviousCullRect() != painting_info.cull_rect)
- return true;
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ paint_layer.PreviousCullRect() != painting_info.cull_rect) {
+ if (paint_layer.PreviousPaintResult() == kMayBeClippedByCullRect)
+ return true;
+ // When PaintUnderInvalidationChecking is enabled, always repaint the
+ // subsequence when the paint rect changes because we will strictly match
+ // new and cached subsequences. Normally we can reuse the cached fully
+ // painted subsequence even if we would partially paint this time.
+ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
+ return true;
+ }
return false;
}
-static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
- const PaintLayer& layer,
- PaintLayerPaintingInfo& painting_info) {
+static bool IsUnclippedLayoutView(const PaintLayer& layer) {
+ // If MainFrameClipsContent is false which means that WebPreferences::
+ // record_whole_document is true, we should not cull the scrolling contents
+ // of the main frame.
+ if (IsA<LayoutView>(layer.GetLayoutObject())) {
+ const auto* frame = layer.GetLayoutObject().GetFrame();
+ if (frame && !frame->ClipsContent())
+ return true;
+ }
+ return false;
+}
+
+bool PaintLayerPainter::ShouldUseInfiniteCullRect(
+ GlobalPaintFlags global_flags) {
+ bool is_printing = paint_layer_.GetLayoutObject().GetDocument().Printing();
+ if (IsUnclippedLayoutView(paint_layer_) && !is_printing)
+ return true;
+
// Cull rects and clips can't be propagated across a filter which moves
// pixels, since the input of the filter may be outside the cull rect /
// clips yet still result in painted output.
- if (layer.HasFilterThatMovesPixels() &&
+ // TODO(wangxianzhu): With CullRectUpdate, we can let CullRect support
+ // mapping for pixel moving filters to avoid this infinite cull rect.
+ if (paint_layer_.HasFilterThatMovesPixels() &&
// However during printing, we don't want filter outset to cross page
// boundaries. This also avoids performance issue because the PDF renderer
// is super slow for big filters. Otherwise all filtered contents would
@@ -173,12 +193,12 @@ static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
// TODO(crbug.com/1098995): For now we don't adjust cull rect for clips.
// When we do, we need to check if we are painting under a real clip.
// This won't be a problem when we use block fragments for printing.
- !context.Printing())
+ !is_printing)
return true;
// Cull rect mapping doesn't work under perspective in some cases.
// See http://crbug.com/887558 for details.
- if (painting_info.root_layer->GetLayoutObject().StyleRef().HasPerspective())
+ if (paint_layer_.GetLayoutObject().StyleRef().HasPerspective())
return true;
// We do not apply cull rect optimizations across transforms for two
@@ -187,44 +207,29 @@ static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
// 2) Complexity: Difficulty updating clips when ancestor transforms
// change.
// For these reasons, we use an infinite dirty rect here.
- if (layer.PaintsWithTransform(painting_info.GetGlobalPaintFlags()) &&
+ // The reasons don't apply for CullRectUpdate.
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ paint_layer_.PaintsWithTransform(global_flags) &&
// The reasons don't apply for printing though, because when we enter and
// leaving printing mode, full invalidations occur.
- !context.Printing())
+ !is_printing)
return true;
return false;
}
-static bool IsUnclippedLayoutView(const PaintLayer& layer) {
- // If MainFrameClipsContent is false which means that WebPreferences::
- // record_whole_document is true, we should not cull the scrolling contents
- // of the main frame.
- if (IsA<LayoutView>(layer.GetLayoutObject())) {
- const auto* frame = layer.GetLayoutObject().GetFrame();
- if (frame && frame->IsMainFrame() && !frame->ClipsContent())
- return true;
- // True regardless whether this is the main frame when painting a preview.
- if (frame && frame->GetDocument()->IsPaintingPreview())
- return true;
- }
- return false;
-}
-
void PaintLayerPainter::AdjustForPaintProperties(
const GraphicsContext& context,
PaintLayerPaintingInfo& painting_info,
PaintLayerFlags& paint_flags) {
const auto& first_fragment = paint_layer_.GetLayoutObject().FirstFragment();
- bool is_unclipped_layout_view = IsUnclippedLayoutView(paint_layer_);
bool should_use_infinite_cull_rect =
- is_unclipped_layout_view ||
- ShouldUseInfiniteCullRect(context, paint_layer_, painting_info);
+ ShouldUseInfiniteCullRect(painting_info.GetGlobalPaintFlags());
if (should_use_infinite_cull_rect) {
painting_info.cull_rect = CullRect::Infinite();
// Avoid clipping during CollectFragments.
- if (is_unclipped_layout_view)
+ if (IsUnclippedLayoutView(paint_layer_))
paint_flags |= kPaintLayerPaintingOverflowContents;
}
@@ -254,7 +259,8 @@ void PaintLayerPainter::AdjustForPaintProperties(
// transform space. Convert cull_rect from the root layer's local space.
cull_rect.MoveBy(RoundedIntPoint(first_root_fragment.PaintOffset()));
base::Optional<CullRect> old_cull_rect;
- if (!paint_layer_.SelfOrDescendantNeedsRepaint()) {
+ if (!paint_layer_.SelfOrDescendantNeedsRepaint() &&
+ !RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
old_cull_rect = paint_layer_.PreviousCullRect();
// Convert old_cull_rect into the layer's transform space.
old_cull_rect->MoveBy(RoundedIntPoint(first_fragment.PaintOffset()));
@@ -312,36 +318,35 @@ PaintResult PaintLayerPainter::PaintLayerContents(
DCHECK(paint_layer_.IsSelfPaintingLayer() ||
paint_layer_.HasSelfPaintingLayerDescendant());
+ const auto& object = paint_layer_.GetLayoutObject();
PaintResult result = kFullyPainted;
- if (paint_layer_.GetLayoutObject().GetFrameView()->ShouldThrottleRendering())
+ if (object.GetFrameView()->ShouldThrottleRendering())
return result;
// A paint layer should always have LocalBorderBoxProperties when it's ready
// for paint.
- if (!paint_layer_.GetLayoutObject()
- .FirstFragment()
- .HasLocalBorderBoxProperties()) {
+ if (!object.FirstFragment().HasLocalBorderBoxProperties()) {
// TODO(crbug.com/848056): This can happen e.g. when we paint a filter
// referencing a SVG foreign object through feImage, especially when there
// is circular references. Should find a better solution.
- paint_layer_.SetPreviousCullRect(CullRect());
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ paint_layer_.SetPreviousCullRect(CullRect());
return kMayBeClippedByCullRect;
}
bool selection_drag_image_only = painting_info_arg.GetGlobalPaintFlags() &
kGlobalPaintSelectionDragImageOnly;
- if (selection_drag_image_only && !paint_layer_.GetLayoutObject().IsSelected())
+ if (selection_drag_image_only && !object.IsSelected())
return result;
IgnorePaintTimingScope ignore_paint_timing;
- if (paint_layer_.GetLayoutObject().StyleRef().Opacity() == 0.0f) {
+ if (object.StyleRef().Opacity() == 0.0f) {
IgnorePaintTimingScope::IncrementIgnoreDepth();
}
// Explicitly compute opacity of documentElement, as it is special-cased in
// Largest Contentful Paint.
bool is_document_element_invisible = false;
- if (const auto* document_element =
- paint_layer_.GetLayoutObject().GetDocument().documentElement()) {
+ if (const auto* document_element = object.GetDocument().documentElement()) {
if (document_element->GetLayoutObject() &&
document_element->GetLayoutObject()->StyleRef().Opacity() == 0.0f) {
is_document_element_invisible = true;
@@ -374,8 +379,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
// is not scrolled and should be above scrolled content.
bool should_paint_self_outline =
is_self_painting_layer && !is_painting_overlay_overflow_controls &&
- is_painting_composited_decoration &&
- paint_layer_.GetLayoutObject().StyleRef().HasOutline();
+ is_painting_composited_decoration && object.StyleRef().HasOutline();
PhysicalOffset subpixel_accumulation =
(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
@@ -386,7 +390,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
: painting_info.sub_pixel_accumulation;
ShouldRespectOverflowClipType respect_overflow_clip =
- ShouldRespectOverflowClip(paint_flags, paint_layer_.GetLayoutObject());
+ ShouldRespectOverflowClip(paint_flags, object);
bool should_paint_content =
paint_layer_.HasVisibleContent() &&
@@ -411,13 +415,33 @@ PaintResult PaintLayerPainter::PaintLayerContents(
subsequence_recorder.emplace(context, paint_layer_);
}
- PhysicalOffset offset_from_root;
- paint_layer_.ConvertToLayerCoords(painting_info.root_layer, offset_from_root);
+ PhysicalOffset offset_from_root =
+ paint_layer_.GetLayoutObject().FirstFragment().PaintOffset();
+ if (const PaintLayer* root = painting_info.root_layer)
+ offset_from_root -= root->GetLayoutObject().FirstFragment().PaintOffset();
offset_from_root += subpixel_accumulation;
- PhysicalRect bounds = paint_layer_.PhysicalBoundingBox(offset_from_root);
- if (!PhysicalRect(painting_info.cull_rect.Rect()).Contains(bounds))
- result = kMayBeClippedByCullRect;
+ IntRect visual_rect = FirstFragmentVisualRect(object);
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ if (object.FirstFragment().NextFragment()) {
+ result = kMayBeClippedByCullRect;
+ } else if (!object.FirstFragment().GetCullRect().Rect().Contains(
+ visual_rect)) {
+ result = kMayBeClippedByCullRect;
+ } else if (const auto* box = DynamicTo<LayoutBox>(object)) {
+ PhysicalRect contents_visual_rect =
+ box->PhysicalContentsVisualOverflowRect();
+ contents_visual_rect.Move(object.FirstFragment().PaintOffset());
+ if (!PhysicalRect(object.FirstFragment().GetContentsCullRect().Rect())
+ .Contains(contents_visual_rect)) {
+ result = kMayBeClippedByCullRect;
+ }
+ }
+ } else {
+ PhysicalRect bounds = paint_layer_.PhysicalBoundingBox(offset_from_root);
+ if (!PhysicalRect(painting_info.cull_rect.Rect()).Contains(bounds))
+ result = kMayBeClippedByCullRect;
+ }
PaintLayerPaintingInfo local_painting_info(painting_info);
local_painting_info.sub_pixel_accumulation = subpixel_accumulation;
@@ -463,24 +487,20 @@ PaintResult PaintLayerPainter::PaintLayerContents(
bool should_paint_normal_flow_and_pos_z_order_lists =
is_painting_composited_foreground &&
!is_painting_overlay_overflow_controls;
- bool is_video = IsA<LayoutVideo>(paint_layer_.GetLayoutObject());
+ bool is_video = IsA<LayoutVideo>(object);
base::Optional<ScopedPaintChunkHint> paint_chunk_hint;
- base::Optional<IntRect> visual_rect;
if (should_paint_content) {
- visual_rect.emplace(
- FirstFragmentVisualRect(paint_layer_.GetLayoutObject()));
paint_chunk_hint.emplace(context.GetPaintController(),
- paint_layer_.GetLayoutObject()
- .FirstFragment()
- .LocalBorderBoxProperties(),
+ object.FirstFragment().LocalBorderBoxProperties(),
paint_layer_, DisplayItem::kLayerChunk,
- *visual_rect);
+ visual_rect);
}
if (should_paint_background) {
- PaintBackgroundForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfBlockBackgroundOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (should_paint_neg_z_order_list) {
@@ -496,7 +516,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
// paint chunk after the previous forced paint chunks a stable id.
paint_chunk_hint_foreground.emplace(
context.GetPaintController(), paint_layer_,
- DisplayItem::kLayerChunkForeground, *visual_rect);
+ DisplayItem::kLayerChunkForeground, visual_rect);
}
if (selection_drag_image_only) {
PaintForegroundForFragmentsWithPhase(PaintPhase::kSelectionDragImage,
@@ -509,8 +529,9 @@ PaintResult PaintLayerPainter::PaintLayerContents(
}
if (!is_video && should_paint_self_outline) {
- PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfOutlineOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (should_paint_normal_flow_and_pos_z_order_lists) {
@@ -532,17 +553,17 @@ PaintResult PaintLayerPainter::PaintLayerContents(
if (is_video && should_paint_self_outline) {
// We paint outlines for video later so that they aren't obscured by the
// video controls.
- PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfOutlineOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (is_painting_mask && should_paint_content && !selection_drag_image_only) {
- const auto* properties =
- paint_layer_.GetLayoutObject().FirstFragment().PaintProperties();
- if (properties) {
+ if (const auto* properties = object.FirstFragment().PaintProperties()) {
if (properties->Mask()) {
- PaintMaskForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kMask, layer_fragments,
+ context, local_painting_info,
+ paint_flags);
}
if (properties->ClipPathMask()) {
PhysicalOffset visual_offset_from_root =
@@ -550,15 +571,15 @@ PaintResult PaintLayerPainter::PaintLayerContents(
? paint_layer_.VisualOffsetFromAncestor(
local_painting_info.root_layer, subpixel_accumulation)
: offset_from_root;
- ClipPathClipper::PaintClipPathAsMaskImage(
- context, paint_layer_.GetLayoutObject(),
- paint_layer_.GetLayoutObject(), visual_offset_from_root);
+ ClipPathClipper::PaintClipPathAsMaskImage(context, object, object,
+ visual_offset_from_root);
}
}
}
paint_layer_.SetPreviousPaintResult(result);
- paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
return result;
}
@@ -655,21 +676,16 @@ void PaintLayerPainter::PaintOverlayOverflowControlsForFragments(
paint_layer_.GetScrollableArea()->HasLayerForScrollCorner())
return;
- ForAllFragments(
- context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- if (!fragment.background_rect.IsEmpty()) {
- PaintFragmentWithPhase(PaintPhase::kOverlayOverflowControls, fragment,
- context, fragment.background_rect,
- painting_info, paint_flags);
- }
- });
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kOverlayOverflowControls,
+ layer_fragments, context, painting_info,
+ paint_flags);
}
void PaintLayerPainter::PaintFragmentWithPhase(
PaintPhase phase,
const PaintLayerFragment& fragment,
GraphicsContext& context,
- const ClipRect& clip_rect,
+ const CullRect& cull_rect,
const PaintLayerPaintingInfo& painting_info,
PaintLayerFlags paint_flags) {
DCHECK(paint_layer_.IsSelfPaintingLayer());
@@ -685,19 +701,11 @@ void PaintLayerPainter::PaintFragmentWithPhase(
context.GetPaintController(), chunk_properties, paint_layer_,
DisplayItem::PaintPhaseToDrawingType(phase));
- PhysicalRect new_cull_rect(clip_rect.Rect());
- // Now |new_cull_rect| is in the pixel-snapped border box space of
- // |fragment.root_fragment_data|. Adjust it to the containing transform node's
- // space in which we will paint.
- new_cull_rect.Move(PhysicalOffset(
- RoundedIntPoint(fragment.root_fragment_data->PaintOffset())));
-
- PaintInfo paint_info(context, PixelSnappedIntRect(new_cull_rect), phase,
- painting_info.GetGlobalPaintFlags(), paint_flags,
- &painting_info.root_layer->GetLayoutObject(),
- fragment.fragment_data
- ? fragment.fragment_data->LogicalTopInFlowThread()
- : LayoutUnit());
+ PaintInfo paint_info(
+ context, cull_rect, phase, painting_info.GetGlobalPaintFlags(),
+ paint_flags, &painting_info.root_layer->GetLayoutObject(),
+ fragment.fragment_data ? fragment.fragment_data->LogicalTopInFlowThread()
+ : LayoutUnit());
if (paint_layer_.GetLayoutObject().ChildPaintBlockedByDisplayLock())
paint_info.SetDescendantPaintingBlocked(true);
@@ -707,16 +715,34 @@ void PaintLayerPainter::PaintFragmentWithPhase(
paint_layer_.GetLayoutObject().Paint(paint_info);
}
-void PaintLayerPainter::PaintBackgroundForFragments(
+static CullRect LegacyCullRect(const PaintLayerFragment& fragment,
+ const ClipRect& clip_rect) {
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ PhysicalRect new_cull_rect(clip_rect.Rect());
+ // Now |new_cull_rect| is in the pixel-snapped border box space of
+ // |fragment.root_fragment_data|. Adjust it to the containing transform node's
+ // space in which we will paint.
+ new_cull_rect.Move(PhysicalOffset(
+ RoundedIntPoint(fragment.root_fragment_data->PaintOffset())));
+ return CullRect(PixelSnappedIntRect(new_cull_rect));
+}
+
+void PaintLayerPainter::PaintBackgroundForFragmentsWithPhase(
+ PaintPhase phase,
const PaintLayerFragments& layer_fragments,
GraphicsContext& context,
const PaintLayerPaintingInfo& local_painting_info,
PaintLayerFlags paint_flags) {
ForAllFragments(
context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- PaintFragmentWithPhase(PaintPhase::kSelfBlockBackgroundOnly, fragment,
- context, fragment.background_rect,
- local_painting_info, paint_flags);
+ CullRect cull_rect =
+ RuntimeEnabledFeatures::CullRectUpdateEnabled()
+ ? fragment.fragment_data->GetCullRect()
+ : LegacyCullRect(fragment, fragment.background_rect);
+ if (!cull_rect.Rect().IsEmpty()) {
+ PaintFragmentWithPhase(phase, fragment, context, cull_rect,
+ local_painting_info, paint_flags);
+ }
});
}
@@ -760,44 +786,24 @@ void PaintLayerPainter::PaintForegroundForFragmentsWithPhase(
GraphicsContext& context,
const PaintLayerPaintingInfo& local_painting_info,
PaintLayerFlags paint_flags) {
- ForAllFragments(context, layer_fragments,
- [&](const PaintLayerFragment& fragment) {
- if (!fragment.foreground_rect.IsEmpty()) {
- PaintFragmentWithPhase(phase, fragment, context,
- fragment.foreground_rect,
- local_painting_info, paint_flags);
- }
- });
-}
-
-void PaintLayerPainter::PaintSelfOutlineForFragments(
- const PaintLayerFragments& layer_fragments,
- GraphicsContext& context,
- const PaintLayerPaintingInfo& local_painting_info,
- PaintLayerFlags paint_flags) {
ForAllFragments(
context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- if (!fragment.background_rect.IsEmpty()) {
- PaintFragmentWithPhase(PaintPhase::kSelfOutlineOnly, fragment,
- context, fragment.background_rect,
+ CullRect cull_rect;
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // In CullRectUpdate, this function is the same as
+ // PaintBackgroundForFragmentsWithPhase(). The contents cull rect will
+ // be applied by ScopedBoxContentsPaintState.
+ cull_rect = fragment.fragment_data->GetCullRect();
+ } else {
+ cull_rect = LegacyCullRect(fragment, fragment.foreground_rect);
+ }
+ if (!cull_rect.Rect().IsEmpty()) {
+ PaintFragmentWithPhase(phase, fragment, context, cull_rect,
local_painting_info, paint_flags);
}
});
}
-void PaintLayerPainter::PaintMaskForFragments(
- const PaintLayerFragments& layer_fragments,
- GraphicsContext& context,
- const PaintLayerPaintingInfo& local_painting_info,
- PaintLayerFlags paint_flags) {
- ForAllFragments(context, layer_fragments,
- [&](const PaintLayerFragment& fragment) {
- PaintFragmentWithPhase(PaintPhase::kMask, fragment, context,
- fragment.background_rect,
- local_painting_info, paint_flags);
- });
-}
-
void PaintLayerPainter::PaintOverlayOverflowControls(
GraphicsContext& context,
const CullRect& cull_rect,
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
index fd6326d4a86..f92faa661fa 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -15,7 +15,6 @@
namespace blink {
class CullRect;
-class ClipRect;
class ComputedStyle;
class GraphicsContext;
struct PhysicalOffset;
@@ -56,6 +55,8 @@ class CORE_EXPORT PaintLayerPainter {
// invisible and therefore can't impact painted output.
static bool PaintedOutputInvisible(const ComputedStyle&);
+ bool ShouldUseInfiniteCullRect(GlobalPaintFlags);
+
private:
friend class PaintLayerPainterTest;
@@ -71,13 +72,14 @@ class CORE_EXPORT PaintLayerPainter {
void PaintFragmentWithPhase(PaintPhase,
const PaintLayerFragment&,
GraphicsContext&,
- const ClipRect&,
+ const CullRect&,
const PaintLayerPaintingInfo&,
PaintLayerFlags);
- void PaintBackgroundForFragments(const PaintLayerFragments&,
- GraphicsContext&,
- const PaintLayerPaintingInfo&,
- PaintLayerFlags);
+ void PaintBackgroundForFragmentsWithPhase(PaintPhase,
+ const PaintLayerFragments&,
+ GraphicsContext&,
+ const PaintLayerPaintingInfo&,
+ PaintLayerFlags);
void PaintForegroundForFragments(const PaintLayerFragments&,
GraphicsContext&,
const PaintLayerPaintingInfo&,
@@ -87,18 +89,10 @@ class CORE_EXPORT PaintLayerPainter {
GraphicsContext&,
const PaintLayerPaintingInfo&,
PaintLayerFlags);
- void PaintSelfOutlineForFragments(const PaintLayerFragments&,
- GraphicsContext&,
- const PaintLayerPaintingInfo&,
- PaintLayerFlags);
void PaintOverlayOverflowControlsForFragments(const PaintLayerFragments&,
GraphicsContext&,
const PaintLayerPaintingInfo&,
PaintLayerFlags);
- void PaintMaskForFragments(const PaintLayerFragments&,
- GraphicsContext&,
- const PaintLayerPaintingInfo&,
- PaintLayerFlags);
void AdjustForPaintProperties(const GraphicsContext&,
PaintLayerPaintingInfo&,
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index 95464938613..b61ef87e9e4 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -45,6 +45,12 @@ class PaintLayerPainterTest : public PaintControllerPaintTest {
->GraphicsLayerBacking(&GetLayoutView())
->GetPaintController();
}
+
+ CullRect GetCullRect(const PaintLayer& layer) {
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return layer.GetLayoutObject().FirstFragment().GetCullRect();
+ return layer.PreviousCullRect();
+ }
};
INSTANTIATE_PAINT_TEST_SUITE_P(PaintLayerPainterTest);
@@ -421,19 +427,14 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType)));
+ EXPECT_EQ(IntRect(0, 0, 800, 4600), GetCullRect(*target_layer).Rect());
auto chunks = ContentPaintChunks();
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // CAP doesn't clip the cull rect by the scrolling contents rect, which
- // doesn't affect painted results.
- EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
- target_layer->PreviousCullRect());
// |target| still created subsequence (cached).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 2)));
} else {
- EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
- target_layer->PreviousCullRect());
EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType)));
@@ -459,12 +460,10 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType)));
+ EXPECT_EQ(IntRect(0, 0, 800, 4600), GetCullRect(*target_layer).Rect());
chunks = ContentPaintChunks();
+ EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)), GetCullRect(*target_layer));
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // CAP doesn't clip the cull rect by the scrolling contents rect, which
- // doesn't affect painted results.
- EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
- target_layer->PreviousCullRect());
EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType)));
@@ -473,8 +472,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 2)));
} else {
- EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
- target_layer->PreviousCullRect());
// |target| still created subsequence (cached).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
@@ -486,9 +483,15 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
GetLayoutView().GetScrollableArea()->SetScrollOffset(
ScrollOffset(0, 3000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesExceptPaint();
- // Scrolling doesn't set SelfNeedsRepaint flag. Change of paint dirty rect of
- // a partially painted layer will trigger repaint.
- EXPECT_FALSE(target_layer->SelfNeedsRepaint());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // The layer needs repaint when its contents cull rect changes.
+ EXPECT_TRUE(target_layer->SelfNeedsRepaint());
+ } else {
+ // Scrolling doesn't set SelfNeedsRepaint flag. Change of paint dirty rect
+ // of a partially painted layer will trigger repaint.
+ EXPECT_FALSE(target_layer->SelfNeedsRepaint());
+ }
+
counter.Reset();
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(2u, counter.NumNewCachedItems());
@@ -501,19 +504,15 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType),
IsSameId(content2, kBackgroundType)));
+ EXPECT_EQ(IntRect(0, 0, 800, 7600), GetCullRect(*target_layer).Rect());
chunks = ContentPaintChunks();
+ EXPECT_EQ(CullRect(IntRect(0, 0, 800, 7600)), GetCullRect(*target_layer));
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // CAP doesn't clip the cull rect by the scrolling contents rect, which
- // doesn't affect painted results.
- EXPECT_EQ(CullRect(IntRect(-4000, -1000, 8800, 8600)),
- target_layer->PreviousCullRect());
// |target| still created subsequence (repainted).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 3)));
} else {
- EXPECT_EQ(CullRect(IntRect(0, 0, 800, 7600)),
- target_layer->PreviousCullRect());
// |target| still created subsequence (repainted).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
@@ -1047,7 +1046,7 @@ TEST_P(PaintLayerPainterTestCAP, SimpleCullRect) {
)HTML");
EXPECT_EQ(IntRect(0, 0, 800, 600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, TallLayerCullRect) {
@@ -1057,9 +1056,10 @@ TEST_P(PaintLayerPainterTestCAP, TallLayerCullRect) {
</div>
)HTML");
- // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling.
- EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped
+ // by the contents rect.
+ EXPECT_EQ(IntRect(0, 0, 800, 4600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, WideLayerCullRect) {
@@ -1070,39 +1070,40 @@ TEST_P(PaintLayerPainterTestCAP, WideLayerCullRect) {
)HTML");
// Same as TallLayerCullRect.
- EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 4800, 600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, TallScrolledLayerCullRect) {
SetBodyInnerHTML(R"HTML(
- <div id='target' style='width: 200px; height: 10000px; position: relative'>
+ <div id='target' style='width: 200px; height: 12000px; position: relative'>
</div>
)HTML");
- // Viewport rect (0, 0, 800, 600) expanded by 4000.
- EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped
+ // by the contents rect.
+ EXPECT_EQ(IntRect(0, 0, 800, 4600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 6000), mojom::blink::ScrollType::kProgrammatic);
+ ScrollOffset(0, 4000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 800, 8600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 6500), mojom::blink::ScrollType::kProgrammatic);
+ ScrollOffset(0, 4500), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Used the previous cull rect because the scroll amount is small.
- EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 800, 8600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 6600), mojom::blink::ScrollType::kProgrammatic);
+ ScrollOffset(0, 4600), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Used new cull rect.
- EXPECT_EQ(IntRect(-4000, 2600, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 600, 800, 8600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) {
@@ -1126,18 +1127,14 @@ TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) {
)HTML");
// Viewport clipping is disabled.
- EXPECT_TRUE(GetLayoutView().Layer()->PreviousCullRect().IsInfinite());
- EXPECT_TRUE(
- GetPaintLayerByElementId("relative")->PreviousCullRect().IsInfinite());
- EXPECT_TRUE(
- GetPaintLayerByElementId("fixed")->PreviousCullRect().IsInfinite());
- EXPECT_TRUE(
- GetPaintLayerByElementId("scroll")->PreviousCullRect().IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetLayoutView().Layer()).IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("relative")).IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("fixed")).IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("scroll")).IsInfinite());
// Cull rect is normal for contents below scroll other than the viewport.
- EXPECT_EQ(
- IntRect(-4000, -4000, 8200, 8200),
- GetPaintLayerByElementId("below-scroll")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 200, 4200),
+ GetCullRect(*GetPaintLayerByElementId("below-scroll")).Rect());
EXPECT_THAT(ContentDisplayItems(),
UnorderedElementsAre(
@@ -1174,23 +1171,31 @@ TEST_P(PaintLayerPainterTestCAP, VerticalRightLeftWritingModeDocument) {
// A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px =
// 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each
- // direction yields this result.
- EXPECT_EQ(IntRect(200, -4000, 8800, 8600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // direction and clipping by the contents rect yields this result.
+ EXPECT_EQ(IntRect(200, 0, 8800, 600),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
+// TODO(wangxianzhu): These tests should correspond to the tests in
+// CompositedLayerMapping testing interest rects. However, for now because in
+// CompositeAfterPaint we expand cull rect for composited scrollers only, so
+// the tests are modified to use composited scrolling. Will change these back to
+// their original version when we support expansion for all composited layers.
+// Will be done in CullRectUpdate.
TEST_P(PaintLayerPainterTestCAP, ScaledCullRect) {
GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5)'>
<div id='target' style='height: 400px; position: relative'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
// The scale doesn't affect the cull rect.
- EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // TODO(wangxianzhu): actually it should.
+ EXPECT_EQ(IntRect(0, 0, 4200, 4300),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, ScaledAndRotatedCullRect) {
@@ -1198,13 +1203,16 @@ TEST_P(PaintLayerPainterTestCAP, ScaledAndRotatedCullRect) {
SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5) rotateZ(45deg)'>
- <div id='target' style='height: 400px; position: relative'></div>
+ <div id='target' style='height: 400px; position: relative;
+ will-change: transform'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
// The scale and the rotation don't affect the cull rect.
- EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // TODO(wangxianzhu): actually they should.
+ EXPECT_EQ(IntRect(0, 0, 4200, 4300),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, 3DRotated90DegreesCullRect) {
@@ -1213,13 +1221,14 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotated90DegreesCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(90deg)'>
<div id='target' style='height: 400px; position: relative'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
// It's rotated 90 degrees about the X axis, which means its visual content
// rect is empty, we fall back to the 4000px cull rect padding amount.
- EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 4200, 4300),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
@@ -1228,6 +1237,7 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(89.9999deg)'>
<div id='target' style='height: 400px; position: relative'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
@@ -1235,8 +1245,8 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
// leads to a reverse-projected rect that is much much larger than the
// original layer size in certain dimensions. In such cases, we often fall
// back to the 4000px cull rect padding amount.
- EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 4200, 4300),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, PerspectiveCullRect) {
@@ -1247,8 +1257,7 @@ TEST_P(PaintLayerPainterTestCAP, PerspectiveCullRect) {
)HTML");
// Use infinite cull rect with perspective.
- EXPECT_TRUE(
- GetPaintLayerByElementId("target")->PreviousCullRect().IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("target")).IsInfinite());
}
TEST_P(PaintLayerPainterTestCAP, 3D45DegRotatedTallCullRect) {
@@ -1259,8 +1268,7 @@ TEST_P(PaintLayerPainterTestCAP, 3D45DegRotatedTallCullRect) {
)HTML");
// Use infinite cull rect with 3d transform.
- EXPECT_TRUE(
- GetPaintLayerByElementId("target")->PreviousCullRect().IsInfinite());
+ EXPECT_TRUE(GetCullRect(*GetPaintLayerByElementId("target")).IsInfinite());
}
TEST_P(PaintLayerPainterTestCAP, FixedPositionCullRect) {
@@ -1271,7 +1279,7 @@ TEST_P(PaintLayerPainterTestCAP, FixedPositionCullRect) {
)HTML");
EXPECT_EQ(IntRect(-200, -100, 800, 600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, LayerOffscreenNearCullRect) {
@@ -1280,11 +1288,12 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenNearCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 3000px; left: 0px;'>
<div id='target' style='height: 500px; position: relative'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
- EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(0, 0, 4200, 4300),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, LayerOffscreenFarCullRect) {
@@ -1293,12 +1302,12 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenFarCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 9000px'>
<div id='target' style='height: 500px; position: relative'></div>
+ <div style='width: 10000px; height: 10000px'></div>
</div>
)HTML");
// The layer is too far away from the viewport.
- EXPECT_EQ(IntRect(),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ EXPECT_EQ(IntRect(), GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, ScrollingLayerCullRect) {
@@ -1318,9 +1327,10 @@ TEST_P(PaintLayerPainterTestCAP, ScrollingLayerCullRect) {
// of 'target', scrollbar and root margin).
// Applying the viewport clip of the root has no effect because
// the clip is already small. Mapping it down into the graphics layer
- // space yields (0, 0, 195, 193). This is then expanded by 4000px.
- EXPECT_EQ(IntRect(-4000, -4000, 8195, 8193),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ // space yields (0, 0, 195, 193). This is then expanded by 4000px and clipped
+ // by the contents rect.
+ EXPECT_EQ(IntRect(0, 0, 195, 4193),
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, NonCompositedScrollingLayerCullRect) {
@@ -1338,7 +1348,7 @@ TEST_P(PaintLayerPainterTestCAP, NonCompositedScrollingLayerCullRect) {
// See ScrollingLayerCullRect for the calculation.
EXPECT_EQ(IntRect(0, 0, 195, 193),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
TEST_P(PaintLayerPainterTestCAP, ClippedBigLayer) {
@@ -1353,7 +1363,7 @@ TEST_P(PaintLayerPainterTestCAP, ClippedBigLayer) {
// The viewport is not scrollable because of the clip, so the cull rect is
// just the viewport rect.
EXPECT_EQ(IntRect(0, 0, 800, 600),
- GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
+ GetCullRect(*GetPaintLayerByElementId("target")).Rect());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
index bab1cced1e3..695b791d691 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.cc
@@ -30,7 +30,6 @@
#include "third_party/blink/renderer/core/paint/paint_layer_resource_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/graphics/filters/filter_effect.h"
namespace blink {
@@ -41,20 +40,7 @@ PaintLayerResourceInfo::~PaintLayerResourceInfo() {
DCHECK(!layer_);
}
-void PaintLayerResourceInfo::ResourceContentChanged(InvalidationModeMask) {
- DCHECK(layer_);
- LayoutObject& layout_object = layer_->GetLayoutObject();
- layout_object.SetShouldDoFullPaintInvalidation();
- layer_->SetNeedsCompositingInputsUpdate();
- layout_object.InvalidateClipPathCache();
- // The effect paint property nodes depend on SVG filters so we need
- // to update these properties when filter resources change.
- layout_object.SetNeedsPaintPropertyUpdate();
- layer_->SetFilterOnEffectNodeDirty();
- layer_->SetBackdropFilterOnEffectNodeDirty();
-}
-
-void PaintLayerResourceInfo::ResourceElementChanged() {
+void PaintLayerResourceInfo::ResourceContentChanged(SVGResource*) {
DCHECK(layer_);
LayoutObject& layout_object = layer_->GetLayoutObject();
layout_object.SetShouldDoFullPaintInvalidation();
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
index bd0ac7ad3bd..d09e9443628 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_resource_info.h
@@ -36,7 +36,6 @@
namespace blink {
-class FilterEffect;
class PaintLayer;
// PaintLayerResourceInfo holds the filter information for painting
@@ -64,8 +63,7 @@ class PaintLayerResourceInfo final
void ClearLayer() { layer_ = nullptr; }
- void ResourceContentChanged(InvalidationModeMask) override;
- void ResourceElementChanged() override;
+ void ResourceContentChanged(SVGResource*) override;
private:
// |ClearLayer| must be called before *layer_ becomes invalid.
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 5552748b8da..2a61f92e89f 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -121,7 +121,12 @@ PaintLayerScrollableAreaRareData::PaintLayerScrollableAreaRareData() = default;
const int kResizerControlExpandRatioForTouch = 2;
PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
- : layer_(&layer),
+ : ScrollableArea(layer.GetLayoutBox()
+ ->GetDocument()
+ .GetPage()
+ ->GetAgentGroupScheduler()
+ .CompositorTaskRunner()),
+ layer_(&layer),
in_resize_mode_(false),
scrolls_overflow_(false),
in_overflow_relayout_(false),
@@ -961,8 +966,11 @@ void PaintLayerScrollableArea::UpdateScrollOrigin() {
GetLayoutBox()->BorderTop()));
IntPoint new_origin(FlooredIntPoint(-scrollable_overflow.offset) +
GetLayoutBox()->OriginAdjustmentForScrollbars());
- if (new_origin != scroll_origin_)
+ if (new_origin != scroll_origin_) {
scroll_origin_changed_ = true;
+ // ScrollOrigin affects paint offsets of the scrolling contents.
+ GetLayoutBox()->SetSubtreeShouldCheckForPaintInvalidation();
+ }
scroll_origin_ = new_origin;
}
@@ -1122,7 +1130,7 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
}
LayoutObject* parent = GetLayoutBox()->Parent();
if (parent && parent->IsFlexibleBox()) {
- ToLayoutFlexibleBox(parent)->ClearCachedMainSizeForChild(
+ To<LayoutFlexibleBox>(parent)->ClearCachedMainSizeForChild(
*GetLayoutBox());
}
}
@@ -1163,7 +1171,7 @@ void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
}
const Document& document = GetLayoutBox()->GetDocument();
- if (document.IsCapturingLayout()) {
+ if (document.IsPrintingOrPaintingPreview()) {
// Scrollable elements may change size when generating layout for printing,
// which may require them to change the scroll position in order to keep the
// same content within view. In vertical-rl writing-mode, even the root
@@ -1356,6 +1364,9 @@ void PaintLayerScrollableArea::UpdateAfterStyleChange(
previous_vertical_scrollbar_on_left_ = vertical_scrollbar_on_left;
}
}
+
+ if (!old_style || old_style->UsedColorScheme() != UsedColorScheme())
+ SetScrollControlsNeedFullPaintInvalidation();
}
void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
@@ -2142,16 +2153,6 @@ void PaintLayerScrollableArea::InvalidateStickyConstraintsFor(
}
}
-bool PaintLayerScrollableArea::HasNonCompositedStickyDescendants() const {
- if (const PaintLayerScrollableAreaRareData* d = RareData()) {
- for (const PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
- if (sticky_layer->GetLayoutObject().IsSlowRepaintConstrainedObject())
- return true;
- }
- }
- return false;
-}
-
void PaintLayerScrollableArea::InvalidatePaintForStickyDescendants() {
if (PaintLayerScrollableAreaRareData* d = RareData()) {
for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys())
@@ -2492,12 +2493,11 @@ bool PaintLayerScrollableArea::ShouldScrollOnMainThread() const {
if (frame->View()->GetMainThreadScrollingReasons())
return true;
}
- if (HasNonCompositedStickyDescendants())
- return true;
// Property tree state is not available until the PrePaint lifecycle stage.
+ // PaintPropertyTreeBuilder needs to get the old status during PrePaint.
DCHECK_GE(GetDocument()->Lifecycle().GetState(),
- DocumentLifecycle::kPrePaintClean);
+ DocumentLifecycle::kInPrePaint);
const auto* properties = GetLayoutBox()->FirstFragment().PaintProperties();
if (!properties || !properties->Scroll() ||
properties->Scroll()->GetMainThreadScrollingReasons())
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index a0355c9fdb3..a0f9316c6c0 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -390,7 +390,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
void DidChangeGlobalRootScroller() override;
- void UpdateAfterStyleChange(const ComputedStyle*);
+ void UpdateAfterStyleChange(const ComputedStyle* old_style);
void UpdateAfterOverflowRecalc();
bool HasScrollbar() const {
@@ -685,8 +685,6 @@ class CORE_EXPORT PaintLayerScrollableArea final
void ScrollControlWasSetNeedsPaintInvalidation() override;
- bool HasNonCompositedStickyDescendants() const;
-
IntSize PixelSnappedBorderBoxSize() const;
using BackgroundPaintLocation = uint8_t;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 765d35db55d..44f6090818d 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -34,7 +34,7 @@ class ScrollableAreaMockChromeClient : public RenderingTestChromeClient {
}
};
-HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
+HeapVector<Member<ScrollTimelineOffset>> CreateScrollOffsets(
ScrollTimelineOffset* start_scroll_offset =
MakeGarbageCollected<ScrollTimelineOffset>(
CSSNumericLiteralValue::Create(
@@ -45,10 +45,9 @@ HeapVector<Member<ScrollTimelineOffset>>* CreateScrollOffsets(
CSSNumericLiteralValue::Create(
90.0,
CSSPrimitiveValue::UnitType::kPixels))) {
- HeapVector<Member<ScrollTimelineOffset>>* scroll_offsets =
- MakeGarbageCollected<HeapVector<Member<ScrollTimelineOffset>>>();
- scroll_offsets->push_back(start_scroll_offset);
- scroll_offsets->push_back(end_scroll_offset);
+ HeapVector<Member<ScrollTimelineOffset>> scroll_offsets;
+ scroll_offsets.push_back(start_scroll_offset);
+ scroll_offsets.push_back(end_scroll_offset);
return scroll_offsets;
}
@@ -113,7 +112,8 @@ class PaintLayerScrollableAreaTest : public RenderingTest,
return To<LayoutBoxModelObject>(scroller)
->Layer()
->GraphicsLayerBacking()
- ->ContentsOpaque();
+ ->CcLayer()
+ .contents_opaque();
}
private:
@@ -1590,12 +1590,12 @@ class ScrollTimelineForTest : public ScrollTimeline {
public:
ScrollTimelineForTest(Document* document,
Element* scroll_source,
- HeapVector<Member<ScrollTimelineOffset>>*
+ HeapVector<Member<ScrollTimelineOffset>>
scroll_offsets = CreateScrollOffsets())
: ScrollTimeline(document,
scroll_source,
ScrollTimeline::Vertical,
- scroll_offsets,
+ std::move(scroll_offsets),
100.0),
invalidated_(false) {}
void Invalidate() override {
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 58642bfe9c8..7c66b241630 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -220,12 +220,6 @@ TEST_P(PaintLayerTest, CompositedScrollingNoNeedsRepaint) {
}
TEST_P(PaintLayerTest, NonCompositedScrollingNeedsRepaint) {
- // CAP scrolling raster invalidation decisions are made in
- // ContentLayerClientImpl::GenerateRasterInvalidations through
- // PaintArtifactCompositor.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
SetBodyInnerHTML(R"HTML(
<style>
/* to prevent the mock overlay scrollbar from affecting compositing. */
@@ -238,6 +232,11 @@ TEST_P(PaintLayerTest, NonCompositedScrollingNeedsRepaint) {
)HTML");
PaintLayer* scroll_layer = GetPaintLayerByElementId("scroll");
+ EXPECT_FALSE(scroll_layer->GetLayoutObject()
+ .FirstFragment()
+ .PaintProperties()
+ ->ScrollTranslation()
+ ->HasDirectCompositingReasons());
EXPECT_EQ(kNotComposited, scroll_layer->GetCompositingState());
PaintLayer* content_layer = GetPaintLayerByElementId("content");
@@ -254,7 +253,14 @@ TEST_P(PaintLayerTest, NonCompositedScrollingNeedsRepaint) {
content_layer->ContainingLayer()->PixelSnappedScrolledContentOffset());
EXPECT_TRUE(scroll_layer->SelfNeedsRepaint());
- EXPECT_FALSE(content_layer->SelfNeedsRepaint());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // The content layer needs repaint because its cull rect changed.
+ EXPECT_TRUE(content_layer->SelfNeedsRepaint());
+ } else {
+ // We don't set the layer needing repaint, but will repaint the layer when
+ // we find that the cull rect changes during paint.
+ EXPECT_FALSE(content_layer->SelfNeedsRepaint());
+ }
UpdateAllLifecyclePhasesForTest();
}
@@ -2636,7 +2642,169 @@ TEST_P(PaintLayerTest, InlineWithBackdropFilterHasPaintLayer) {
EXPECT_NE(nullptr, paint_layer);
}
-TEST_P(PaintLayerTest, FixedUsesExpandedBoundingBoxForOverlap) {
+TEST_P(PaintLayerTest, DirectCompositingReasonsCrossingFrameBoundaries) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <iframe></iframe>
+ )HTML");
+ SetChildFrameHTML(R"HTML(
+ <div id=target style="position: relative"></div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ PaintLayer* target =
+ To<LayoutBoxModelObject>(
+ ChildDocument().getElementById("target")->GetLayoutObject())
+ ->Layer();
+
+ EXPECT_EQ(
+ GetDocument().View()->GetLayoutView()->Layer(),
+ target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+}
+
+TEST_P(PaintLayerTest,
+ DirectCompositingReasonsCrossingFrameBoundariesCompositedIframe) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <iframe id="iframe" style="will-change: transform";></iframe>
+ )HTML");
+ SetChildFrameHTML(R"HTML(
+ <div id=target style="position: relative"></div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ PaintLayer* target =
+ To<LayoutBoxModelObject>(
+ ChildDocument().getElementById("target")->GetLayoutObject())
+ ->Layer();
+
+ PaintLayer* iframe =
+ To<LayoutBoxModelObject>(
+ GetDocument().getElementById("iframe")->GetLayoutObject())
+ ->Layer();
+
+ EXPECT_EQ(
+ iframe,
+ target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+}
+
+TEST_P(PaintLayerTest,
+ DirectCompositingReasonsCrossingFrameBoundariesCompositedParent) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+ SetBodyInnerHTML(R"HTML(
+ <iframe></iframe>
+ )HTML");
+ SetChildFrameHTML(R"HTML(
+ <div id="parent" style="will-change: transform">
+ <div id=target style="position: relative"></div>
+ </div>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+
+ PaintLayer* target =
+ To<LayoutBoxModelObject>(
+ ChildDocument().getElementById("target")->GetLayoutObject())
+ ->Layer();
+
+ PaintLayer* parent =
+ To<LayoutBoxModelObject>(
+ ChildDocument().getElementById("parent")->GetLayoutObject())
+ ->Layer();
+
+ EXPECT_EQ(
+ parent,
+ target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+}
+
+TEST_P(PaintLayerTest, GlobalRootScrollerHitTest) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ :root {
+ clip-path: circle(30%);
+ background:blue;
+ transform: rotate(30deg);
+ transform-style: preserve-3d;
+ }
+ #perspective {
+ perspective:100px;
+ }
+ #threedee {
+ transform: rotate3d(1, 1, 1, 45deg);
+ width:100px; height:200px;
+ }
+ </style>
+ <div id="perspective">
+ <div id="threedee"></div>
+ </div>
+ )HTML");
+ GetDocument().GetPage()->SetPageScaleFactor(2);
+ UpdateAllLifecyclePhasesForTest();
+
+ const HitTestRequest hit_request(HitTestRequest::kActive);
+ const HitTestLocation location(IntPoint(400, 300));
+ HitTestResult result;
+ GetLayoutView().HitTestNoLifecycleUpdate(location, result);
+ EXPECT_EQ(result.InnerNode(), GetDocument().documentElement());
+ EXPECT_EQ(result.GetScrollbar(), nullptr);
+
+ if (GetDocument().GetPage()->GetScrollbarTheme().AllowsHitTest()) {
+ const HitTestLocation location_scrollbar(IntPoint(790, 300));
+ HitTestResult result_scrollbar;
+ EXPECT_EQ(result_scrollbar.InnerNode(), &GetDocument());
+ EXPECT_NE(result_scrollbar.GetScrollbar(), nullptr);
+ }
+}
+
+TEST_P(PaintLayerTest, HasNonEmptyChildLayoutObjectsZeroSizeOverflowVisible) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="layer" style="position: relative">
+ <div style="overflow: visible; height: 0; width: 0">text</div>
+ </div>
+ )HTML");
+
+ auto* layer = GetPaintLayerByElementId("layer");
+ EXPECT_TRUE(layer->HasVisibleContent());
+ EXPECT_FALSE(layer->HasVisibleDescendant());
+ EXPECT_TRUE(layer->HasNonEmptyChildLayoutObjects());
+}
+
+enum { kCompositingOptimizations = 1 << 0 };
+
+// TODO(chrishtr): Remove this test configuration and keep the appropriate
+// variants of the tests when CompositingOptimizations ships or is removed.
+class PaintLayerOverlapTestConfigurations
+ : public testing::WithParamInterface<unsigned>,
+ private ScopedCompositingOptimizationsForTest {
+ public:
+ PaintLayerOverlapTestConfigurations()
+ : ScopedCompositingOptimizationsForTest(GetParam() &
+ kCompositingOptimizations) {}
+ ~PaintLayerOverlapTestConfigurations() override {
+ // Must destruct all objects before toggling back feature flags.
+ WebHeap::CollectAllGarbageForTesting();
+ }
+};
+
+class PaintLayerOverlapTest : public PaintLayerOverlapTestConfigurations,
+ public RenderingTest {
+ public:
+ PaintLayerOverlapTest()
+ : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
+
+ void SetUp() override {
+ EnableCompositing();
+ RenderingTest::SetUp();
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ PaintLayerOverlapTest,
+ ::testing::Values(0, kCompositingOptimizations));
+
+TEST_P(PaintLayerOverlapTest, FixedUsesExpandedBoundingBoxForOverlap) {
SetBodyInnerHTML(R"HTML(
<style>
* {
@@ -2658,8 +2826,12 @@ TEST_P(PaintLayerTest, FixedUsesExpandedBoundingBoxForOverlap) {
)HTML");
PaintLayer* fixed = GetPaintLayerByElementId("fixed");
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(0, 0, 30, 20));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 30, 20));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
// Modify the viewport scroll offset and ensure that the bounding box is still
// adjusted by the new amount the viewport can scroll in any direction.
@@ -2667,11 +2839,44 @@ TEST_P(PaintLayerTest, FixedUsesExpandedBoundingBoxForOverlap) {
ScrollOffset(10, 10), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(-10, -10, 30, 20));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 30, 20));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ }
+}
+
+TEST_P(PaintLayerOverlapTest, IncludeIntermediateScrollerOffset) {
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div id=intermediate style="overflow:scroll; width: 100px; height: 100px">
+ <div style="height: 2000px"></div>
+ <div id="target" style="position: relative; width: 100px; height: 100px"></div>
+ </div>
+ <div style="height: 2000px"></div>
+ )HTML");
+ PaintLayer* position = GetPaintLayerByElementId("target");
+ LayoutBoxModelObject* intermediate =
+ To<LayoutBoxModelObject>(GetLayoutObjectByElementId("intermediate"));
+
+ intermediate->GetScrollableArea()->ScrollBy(ScrollOffset(0, 1950),
+ mojom::blink::ScrollType::kUser);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(100, 100), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(position->UnclippedAbsoluteBoundingBox(), IntRect(0, 50, 100, 100));
+ EXPECT_EQ(position->ClippedAbsoluteBoundingBox(), IntRect(0, 50, 100, 50));
}
-TEST_P(PaintLayerTest, FixedInScrollerUsesExpandedBoundingBoxForOverlap) {
+TEST_P(PaintLayerOverlapTest,
+ FixedInScrollerUsesExpandedBoundingBoxForOverlap) {
SetBodyInnerHTML(R"HTML(
<style>
* {
@@ -2707,8 +2912,12 @@ TEST_P(PaintLayerTest, FixedInScrollerUsesExpandedBoundingBoxForOverlap) {
)HTML");
PaintLayer* fixed = GetPaintLayerByElementId("fixed");
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(0, 0, 30, 20));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 30, 20));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
// Modify the inner scroll offset and ensure that the bounding box is still
// the same.
@@ -2717,8 +2926,12 @@ TEST_P(PaintLayerTest, FixedInScrollerUsesExpandedBoundingBoxForOverlap) {
scrollable_area->ScrollToAbsolutePosition(FloatPoint(10, 10));
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(0, 0, 30, 20));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 30, 20));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
// Modify the viewport scroll offset and ensure that the bounding box is still
// adjusted by the newamount the viewport can scroll in any direction.
@@ -2726,11 +2939,21 @@ TEST_P(PaintLayerTest, FixedInScrollerUsesExpandedBoundingBoxForOverlap) {
ScrollOffset(10, 10), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(-10, -10, 30, 20));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 30, 20));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ }
}
-TEST_P(PaintLayerTest, FixedUnderTransformDoesNotExpandBoundingBoxForOverlap) {
+TEST_P(PaintLayerOverlapTest,
+ FixedUnderTransformDoesNotExpandBoundingBoxForOverlap) {
SetBodyInnerHTML(R"HTML(
<style>
.anim {
@@ -2769,11 +2992,21 @@ TEST_P(PaintLayerTest, FixedUnderTransformDoesNotExpandBoundingBoxForOverlap) {
// fixed composited, it shouldn't have expanded bounds because its containing
// block isn't the viewport.
PaintLayer* fixed = GetPaintLayerByElementId("fixed");
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(117, 117, 66, 66));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
PhysicalRect(0, 0, 50, 50));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(117, 117, 66, 66));
+ // These values differ because CompositingOptimizationsEnabled takes into
+ // account transforms (the one one the .xform element), whereas
+ // CompositingOptimizationsDisabled (incorrectly) does not.
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled())
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(117, 117, 66, 66));
+ else
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(118, 118, 64, 64));
}
-TEST_P(PaintLayerTest, NestedFixedUsesExpandedBoundingBoxForOverlap) {
+TEST_P(PaintLayerOverlapTest, NestedFixedUsesExpandedBoundingBoxForOverlap) {
SetBodyInnerHTML(R"HTML(
<style>
* {
@@ -2818,8 +3051,12 @@ TEST_P(PaintLayerTest, NestedFixedUsesExpandedBoundingBoxForOverlap) {
To<LayoutBoxModelObject>(
ChildDocument().getElementById("fixed")->GetLayoutObject())
->Layer();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(0, 0, 410, 410));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 410, 410));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
// Modify the top-most viewport's scroll offset and ensure that the bounding
// box is still the same. This shows that we're not considering the wrong
@@ -2828,8 +3065,12 @@ TEST_P(PaintLayerTest, NestedFixedUsesExpandedBoundingBoxForOverlap) {
ScrollOffset(10, 10), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(0, 0, 410, 410));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 410, 410));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
// Now modify the iframe's scroll offset. This one should affect the fixed's
// bounding box.
@@ -2837,141 +3078,522 @@ TEST_P(PaintLayerTest, NestedFixedUsesExpandedBoundingBoxForOverlap) {
ScrollOffset(10, 10), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(fixed->BoundingBoxForCompositingOverlapTest(),
- PhysicalRect(-10, -10, 410, 410));
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 50, 410, 410));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 10, 10));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(50, 50, 10, 10));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(60, 60, 10, 10));
+ }
}
-TEST_P(PaintLayerTest, DirectCompositingReasonsCrossingFrameBoundaries) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
+TEST_P(PaintLayerOverlapTest, FixedWithExpandedBoundsForChild) {
SetBodyInnerHTML(R"HTML(
- <iframe></iframe>
- )HTML");
- SetChildFrameHTML(R"HTML(
- <div id=target style="position: relative"></div>
+ <style>
+ * {
+ margin: 0;
+ }
+ body {
+ height: 1000px;
+ }
+ #fixed {
+ height: 50px;
+ left: 25px;
+ position: fixed;
+ top: 25px;
+ width: 50px;
+ }
+ #abs {
+ height: 25px;
+ left: 50px;
+ position: absolute;
+ top: 200px;
+ width: 25px;
+ will-change: transform;
+ }
+ </style>
+ <div id=fixed>
+ <div id=abs></div>
+ </div>
)HTML");
UpdateAllLifecyclePhasesForTest();
- PaintLayer* target =
- To<LayoutBoxModelObject>(
- ChildDocument().getElementById("target")->GetLayoutObject())
- ->Layer();
+ // The fixed-pos layer should use bounds that have been expanded to include
+ // the absolutely positioned child. Without this expansion, overlap testing
+ // can miss overlap from that child leading to incorrect composition order.
+ PaintLayer* fixed = GetPaintLayerByElementId("fixed");
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 75, 625));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+
+ // Verify that the abs bounds is not expanded even though it is a child of a
+ // fixed-pos layer. Expanding the abs bounds would mean that it could
+ // unnecessarily detect overlap with siblings that it doesn't ever actually
+ // overlap with.
+ PaintLayer* abs = GetPaintLayerByElementId("abs");
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+
+ // Modify the scroll offset and ensure that the bounding box is still the
+ // same. Note that if we get different expanded bounding boxes for overlap
+ // testing with different scroll offsets then it implies that scroll offset is
+ // a part of that calculation and we may get incorrect results as scroll
+ // offsets changes and partial updates happen.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 400), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(
- GetDocument().View()->GetLayoutView()->Layer(),
- target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 75, 625));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
+
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ }
}
-TEST_P(PaintLayerTest,
- DirectCompositingReasonsCrossingFrameBoundariesCompositedIframe) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
+TEST_P(PaintLayerOverlapTest, FixedWithClippedExpandedBoundsForChild) {
SetBodyInnerHTML(R"HTML(
- <iframe id="iframe" style="will-change: transform";></iframe>
- )HTML");
- SetChildFrameHTML(R"HTML(
- <div id=target style="position: relative"></div>
+ <style>
+ * {
+ margin: 0;
+ }
+ body {
+ height: 1000px;
+ }
+ #fixed {
+ height: 50px;
+ left: 25px;
+ position: fixed;
+ top: 25px;
+ width: 50px;
+ overflow: hidden;
+ }
+ #abs {
+ height: 25px;
+ left: 50px;
+ position: absolute;
+ top: 200px;
+ width: 25px;
+ will-change: transform;
+ }
+ </style>
+ <div id=fixed>
+ <div id=abs></div>
+ </div>
)HTML");
UpdateAllLifecyclePhasesForTest();
- PaintLayer* target =
- To<LayoutBoxModelObject>(
- ChildDocument().getElementById("target")->GetLayoutObject())
- ->Layer();
+ // The fixed-pos layer should use bounds that have been expanded to include
+ // the absolutely positioned child. However, the fixed-pos ancestor also has
+ // clipping which will limit the expansion.
+ PaintLayer* fixed = GetPaintLayerByElementId("fixed");
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 50, 450));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+
+ // Verify that the abs bounds is not expanded even though it is a child of a
+ // fixed-pos layer. Expanding the abs bounds would mean that it could
+ // unnecessarily detect overlap with siblings that it doesn't ever actually
+ // overlap with. Note that the clipped bounds is an empty rect because of the
+ // clipping from the ancestor.
+ PaintLayer* abs = GetPaintLayerByElementId("abs");
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(0, 0, 0, 0));
+
+ // Modify the scroll offset and ensure that the bounding box is still the
+ // same. Note that if we get different expanded bounding boxes for overlap
+ // testing with different scroll offsets then it implies that scroll offset is
+ // a part of that calculation and we may get incorrect results as scroll
+ // offsets changes and partial updates happen.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 400), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
- PaintLayer* iframe =
- To<LayoutBoxModelObject>(
- GetDocument().getElementById("iframe")->GetLayoutObject())
- ->Layer();
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 50, 450));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
- EXPECT_EQ(
- iframe,
- target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(0, 0, 0, 0));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(0, 0, 0, 0));
+ }
}
-TEST_P(PaintLayerTest,
- DirectCompositingReasonsCrossingFrameBoundariesCompositedParent) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
+TEST_P(PaintLayerOverlapTest, FixedWithExpandedBoundsForGrandChild) {
SetBodyInnerHTML(R"HTML(
- <iframe></iframe>
- )HTML");
- SetChildFrameHTML(R"HTML(
- <div id="parent" style="will-change: transform">
- <div id=target style="position: relative"></div>
+ <style>
+ * {
+ margin: 0;
+ }
+ body {
+ height: 1000px;
+ }
+ #fixed {
+ height: 50px;
+ left: 25px;
+ position: fixed;
+ top: 25px;
+ width: 50px;
+ }
+ #abs {
+ height: 25px;
+ left: 50px;
+ position: absolute;
+ top: 200px;
+ width: 25px;
+ }
+ #abs2 {
+ height: 25px;
+ left: 50px;
+ position: absolute;
+ top: 100px;
+ width: 25px;
+ }
+ </style>
+ <div id=fixed>
+ <div id=abs>
+ <div id=abs2></div>
+ </div>
</div>
)HTML");
UpdateAllLifecyclePhasesForTest();
- PaintLayer* target =
- To<LayoutBoxModelObject>(
- ChildDocument().getElementById("target")->GetLayoutObject())
- ->Layer();
+ // The fixed-pos layer should use bounds that have been expanded to include
+ // the absolutely positioned grandchild.
+ PaintLayer* fixed = GetPaintLayerByElementId("fixed");
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 125, 725));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+
+ // Verify that the abs bounds is not expanded even though it is a child of a
+ // fixed-pos layer. Additionally, it shouldn't include its child as only
+ // fixed-pos expands to include descendants.
+ PaintLayer* abs = GetPaintLayerByElementId("abs");
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+
+ PaintLayer* abs2 = GetPaintLayerByElementId("abs2");
+ EXPECT_EQ(abs2->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+
+ // Modify the scroll offset and ensure that the bounding box is still the
+ // same. Note that if we get different expanded bounding boxes for overlap
+ // testing with different scroll offsets then it implies that scroll offset is
+ // a part of that calculation and we may get incorrect results as scroll
+ // offsets changes and partial updates happen.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 400), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
- PaintLayer* parent =
- To<LayoutBoxModelObject>(
- ChildDocument().getElementById("parent")->GetLayoutObject())
- ->Layer();
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 125, 725));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
- EXPECT_EQ(
- parent,
- target->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries());
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ }
+
+ EXPECT_EQ(abs2->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ } else {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ }
+
+ // Add will-change to the middle child to ensure the bounds are still the
+ // same. This helps confirm that the computation of the bounds is agnostic to
+ // if descendants are composited or not.
+ GetDocument().getElementById("abs")->setAttribute(html_names::kStyleAttr,
+ "will-change: transform");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 125, 725));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
+
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ }
+
+ EXPECT_EQ(abs2->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ } else {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ }
+
+ // Add will-change to the grandchild and ensure the bounds are still the same.
+ GetDocument().getElementById("abs2")->setAttribute(html_names::kStyleAttr,
+ "will-change: transform");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 125, 725));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
+
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ }
+
+ EXPECT_EQ(abs2->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ } else {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ }
+
+ // Remove will-change from the middle child and ensure the bounds are still
+ // the same.
+ GetDocument().getElementById("abs")->setAttribute(html_names::kStyleAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 125, 725));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
+
+ EXPECT_EQ(abs->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 225, 25, 25));
+ } else {
+ EXPECT_EQ(abs->UnclippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ EXPECT_EQ(abs->ClippedAbsoluteBoundingBox(), IntRect(75, 625, 25, 25));
+ }
+
+ EXPECT_EQ(abs2->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 325, 25, 25));
+ } else {
+ EXPECT_EQ(abs2->UnclippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ EXPECT_EQ(abs2->ClippedAbsoluteBoundingBox(), IntRect(125, 725, 25, 25));
+ }
}
-TEST_P(PaintLayerTest, GlobalRootScrollerHitTest) {
- USE_NON_OVERLAY_SCROLLBARS();
+TEST_P(PaintLayerOverlapTest, FixedWithExpandedBoundsForFixedChild) {
SetBodyInnerHTML(R"HTML(
<style>
- :root {
- clip-path: circle(30%);
- background:blue;
- transform: rotate(30deg);
- transform-style: preserve-3d;
- overflow-x: hidden;
+ * {
+ margin: 0;
}
- #perspective {
- perspective:100px;
+ body {
+ height: 1000px;
}
- #threedee {
- transform: rotate3d(1, 1, 1, 45deg);
- width:100px; height:200px;
+ #fixed {
+ height: 50px;
+ left: 25px;
+ position: fixed;
+ top: 25px;
+ width: 50px;
+ }
+ #nestedFixed {
+ height: 25px;
+ left: 50px;
+ position: fixed;
+ top: 100px;
+ width: 25px;
}
</style>
- <div id="perspective">
- <div id="threedee"></div>
+ <div id=fixed>
+ <div id=nestedFixed></div>
</div>
- <div style="height:1000px"></div>
)HTML");
- GetDocument().GetPage()->SetPageScaleFactor(2);
UpdateAllLifecyclePhasesForTest();
- const HitTestRequest hit_request(HitTestRequest::kActive);
- const HitTestLocation location(IntPoint(400, 300));
- HitTestResult result;
- GetLayoutView().HitTestNoLifecycleUpdate(location, result);
- EXPECT_EQ(result.InnerNode(), GetDocument().documentElement());
- EXPECT_EQ(result.GetScrollbar(), nullptr);
-
- const HitTestLocation location_scrollbar(IntPoint(790, 300));
- HitTestResult result_scrollbar;
- GetLayoutView().HitTestNoLifecycleUpdate(location_scrollbar,
- result_scrollbar);
- EXPECT_EQ(result_scrollbar.InnerNode(), GetDocument().documentElement());
- EXPECT_NE(result_scrollbar.GetScrollbar(), nullptr);
- EXPECT_EQ(result_scrollbar.LocalPoint(), location_scrollbar.Point());
-}
+ // The fixed-pos layer should use bounds that have been expanded to include
+ // the absolutely positioned child. Without this expansion, overlap testing
+ // can miss overlap from that child leading to incorrect composition order.
+ PaintLayer* fixed = GetPaintLayerByElementId("fixed");
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 50, 500));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+
+ // Note that the nested fixed should not expand its bounds as it doesn't move
+ // relative to its siblings, fixed-pos or not.
+ PaintLayer* nestedFixed = GetPaintLayerByElementId("nestedFixed");
+ EXPECT_EQ(nestedFixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 100, 25, 25));
+ EXPECT_EQ(nestedFixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ EXPECT_EQ(nestedFixed->UnclippedAbsoluteBoundingBox(),
+ IntRect(50, 100, 25, 25));
+ EXPECT_EQ(nestedFixed->ClippedAbsoluteBoundingBox(),
+ IntRect(50, 100, 25, 25));
+
+ // Modify the scroll offset and ensure that the bounding box is still the
+ // same.
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 400), mojom::blink::ScrollType::kProgrammatic);
+ UpdateAllLifecyclePhasesForTest();
-TEST_P(PaintLayerTest, HasNonEmptyChildLayoutObjectsZeroSizeOverflowVisible) {
- SetBodyInnerHTML(R"HTML(
- <div id="layer" style="position: relative">
- <div style="overflow: visible; height: 0; width: 0">text</div>
- </div>
- )HTML");
+ EXPECT_EQ(fixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(25, 25, 50, 500));
+ EXPECT_EQ(fixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 50, 50));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 25, 50, 50));
+ } else {
+ EXPECT_EQ(fixed->UnclippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ EXPECT_EQ(fixed->ClippedAbsoluteBoundingBox(), IntRect(25, 425, 50, 50));
+ }
- auto* layer = GetPaintLayerByElementId("layer");
- EXPECT_TRUE(layer->HasVisibleContent());
- EXPECT_FALSE(layer->HasVisibleDescendant());
- EXPECT_TRUE(layer->HasNonEmptyChildLayoutObjects());
+ EXPECT_EQ(nestedFixed->ExpandedBoundingBoxForCompositingOverlapTest(false),
+ IntRect(50, 500, 25, 25));
+ EXPECT_EQ(nestedFixed->LocalBoundingBoxForCompositingOverlapTest(),
+ PhysicalRect(0, 0, 25, 25));
+ if (!RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
+ EXPECT_EQ(nestedFixed->UnclippedAbsoluteBoundingBox(),
+ IntRect(50, 100, 25, 25));
+ EXPECT_EQ(nestedFixed->ClippedAbsoluteBoundingBox(),
+ IntRect(50, 100, 25, 25));
+ } else {
+ EXPECT_EQ(nestedFixed->UnclippedAbsoluteBoundingBox(),
+ IntRect(50, 500, 25, 25));
+ EXPECT_EQ(nestedFixed->ClippedAbsoluteBoundingBox(),
+ IntRect(50, 500, 25, 25));
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_phase.h b/chromium/third_party/blink/renderer/core/paint/paint_phase.h
index b316aa44ce5..99ba48994a5 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_phase.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_phase.h
@@ -133,12 +133,9 @@ enum GlobalPaintFlag {
// ignore the hardware layers and paint the whole tree
// into the topmost layer.
kGlobalPaintFlattenCompositingLayers = 1 << 1,
- // Used when printing in order to adapt the output to the medium, for
- // instance by not painting shadows and selections on text.
- kGlobalPaintPrinting = 1 << 2,
// Used when printing or painting a preview to in order to add URL
// metadata for links.
- kGlobalPaintAddUrlMetadata = 1 << 3
+ kGlobalPaintAddUrlMetadata = 1 << 2
};
typedef unsigned GlobalPaintFlags;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 2aabab81f21..123f896d7ab 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -30,7 +30,6 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/page/link_highlight.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -86,7 +85,9 @@ PaintPropertyTreeBuilderContext::PaintPropertyTreeBuilderContext()
clip_changed(false),
is_repeating_fixed_position(false),
has_svg_hidden_container_ancestor(false),
- supports_composited_raster_invalidation(true) {}
+ supports_composited_raster_invalidation(true),
+ was_layout_shift_root(false),
+ was_main_thread_scrolling(false) {}
PaintPropertyChangeType VisualViewportPaintPropertyTreeBuilder::Update(
VisualViewport& visual_viewport,
@@ -155,8 +156,7 @@ class FragmentPaintPropertyTreeBuilder {
full_context_(full_context),
context_(context),
fragment_data_(fragment_data),
- properties_(fragment_data.PaintProperties()),
- was_layout_shift_root_(IsLayoutShiftRoot()) {}
+ properties_(fragment_data.PaintProperties()) {}
~FragmentPaintPropertyTreeBuilder() {
if (property_changed_ >= PaintPropertyChangeType::kNodeAddedOrRemoved) {
@@ -187,6 +187,7 @@ class FragmentPaintPropertyTreeBuilder {
}
private:
+ ALWAYS_INLINE bool CanPropagateSubpixelAccumulation() const;
ALWAYS_INLINE void UpdatePaintOffset();
ALWAYS_INLINE void UpdateForPaintOffsetTranslation(base::Optional<IntPoint>&);
ALWAYS_INLINE void UpdatePaintOffsetTranslation(
@@ -219,6 +220,7 @@ class FragmentPaintPropertyTreeBuilder {
ALWAYS_INLINE void UpdateClipIsolationNode();
ALWAYS_INLINE void SetTransformNodeStateForSVGChild(
TransformPaintPropertyNode::State&);
+ ALWAYS_INLINE void UpdateLayoutShiftRootChanged(bool is_layout_shift_root);
bool NeedsPaintPropertyUpdate() const {
return object_.NeedsPaintPropertyUpdate() ||
@@ -270,18 +272,6 @@ class FragmentPaintPropertyTreeBuilder {
namespace_id);
}
- bool IsLayoutShiftRoot() const {
- if (!properties_)
- return false;
- return IsA<LayoutView>(object_) || properties_->Perspective() ||
- (properties_->Transform() &&
- !properties_->Transform()->IsIdentityOr2DTranslation()) ||
- properties_->ScrollTranslation() ||
- properties_->ReplacedContentTransform() ||
- properties_->TransformIsolationNode() ||
- object_.IsStickyPositioned();
- }
-
const LayoutObject& object_;
NGPrePaintInfo* pre_paint_info_;
// The tree builder context for the whole object.
@@ -293,7 +283,6 @@ class FragmentPaintPropertyTreeBuilder {
ObjectPaintProperties* properties_;
PaintPropertyChangeType property_changed_ =
PaintPropertyChangeType::kUnchanged;
- bool was_layout_shift_root_;
};
// True if a scroll translation is needed for static scroll offset (e.g.,
@@ -378,8 +367,7 @@ static bool NeedsStickyTranslation(const LayoutObject& object) {
static bool NeedsPaintOffsetTranslation(
const LayoutObject& object,
- CompositingReasons direct_compositing_reasons,
- bool is_affected_by_outer_viewport_bounds_delta) {
+ CompositingReasons direct_compositing_reasons) {
if (!object.IsBoxModelObject())
return false;
@@ -451,9 +439,6 @@ static bool NeedsPaintOffsetTranslation(
} else {
if (layer->NeedsPaintOffsetTranslationForCompositing())
return true;
-
- if (is_affected_by_outer_viewport_bounds_delta)
- return true;
}
}
}
@@ -461,11 +446,32 @@ static bool NeedsPaintOffsetTranslation(
return false;
}
+bool FragmentPaintPropertyTreeBuilder::CanPropagateSubpixelAccumulation()
+ const {
+ if (!object_.HasLayer())
+ return true;
+
+ if (full_context_.direct_compositing_reasons &
+ CompositingReason::kPreventingSubpixelAccumulationReasons) {
+ return false;
+ }
+ if (full_context_.direct_compositing_reasons &
+ CompositingReason::kActiveTransformAnimation) {
+ if (const auto* element = DynamicTo<Element>(object_.GetNode())) {
+ DCHECK(element->GetElementAnimations());
+ return element->GetElementAnimations()->IsIdentityOrTranslation();
+ }
+ return false;
+ }
+
+ const PaintLayer* layer = To<LayoutBoxModelObject>(object_).Layer();
+ return !layer->Transform() || layer->Transform()->IsIdentityOrTranslation();
+}
+
void FragmentPaintPropertyTreeBuilder::UpdateForPaintOffsetTranslation(
base::Optional<IntPoint>& paint_offset_translation) {
if (!NeedsPaintOffsetTranslation(
- object_, full_context_.direct_compositing_reasons,
- full_context_.is_affected_by_outer_viewport_bounds_delta))
+ object_, full_context_.direct_compositing_reasons))
return;
// We should use the same subpixel paint offset values for snapping regardless
@@ -494,14 +500,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateForPaintOffsetTranslation(
.IsZero()) {
// If the object has a non-translation transform, discard the fractional
// paint offset which can't be transformed by the transform.
- TransformationMatrix matrix;
- object_.StyleRef().ApplyTransform(
- matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
- ComputedStyle::kIncludeMotionPath,
- ComputedStyle::kIncludeIndependentTransformProperties);
- if ((full_context_.direct_compositing_reasons &
- CompositingReason::kPreventingSubpixelAccumulationReasons) ||
- !matrix.IsIdentityOrTranslation()) {
+ if (!CanPropagateSubpixelAccumulation()) {
context_.current.paint_offset = PhysicalOffset();
context_.current
.directly_composited_container_paint_offset_subpixel_delta =
@@ -543,8 +542,6 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
TransformPaintPropertyNode::State state{new_translation};
state.flags.flattens_inherited_transform =
context_.current.should_flatten_inherited_transform;
- state.flags.affected_by_outer_viewport_bounds_delta =
- full_context_.is_affected_by_outer_viewport_bounds_delta;
state.direct_compositing_reasons =
full_context_.direct_compositing_reasons &
CompositingReason::kDirectReasonsForPaintOffsetTranslationProperty;
@@ -568,8 +565,10 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
context_.fixed_position.transform = properties_->PaintOffsetTranslation();
}
- context_.current.additional_offset_to_layout_shift_root_delta +=
- PhysicalOffset(*paint_offset_translation);
+ if (!object_.ShouldAssumePaintOffsetTranslationForLayoutShiftTracking()) {
+ context_.current.additional_offset_to_layout_shift_root_delta +=
+ PhysicalOffset(*paint_offset_translation);
+ }
} else {
OnClear(properties_->ClearPaintOffsetTranslation());
}
@@ -777,6 +776,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransformForSVGChild(
CompositingReasonsForTransformProperty();
state.flags.flattens_inherited_transform =
context_.current.should_flatten_inherited_transform;
+ state.flags.is_for_svg_child = true;
state.compositor_element_id = GetCompositorElementId(
CompositorElementIdNamespace::kPrimaryTransform);
}
@@ -909,10 +909,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
state.rendering_context_id =
PtrHash<const LayoutObject>::GetHash(&object_);
}
- // TODO(flackr): This only needs to consider composited transform
- // animations. This is currently a cyclic dependency but we could
- // calculate most of the compositable animation reasons up front to
- // only consider animations which are candidates for compositing.
+
state.flags.animation_is_axis_aligned =
UpdateBoxSizeAndCheckActiveAnimationAxisAlignment(
box, full_context_.direct_compositing_reasons);
@@ -958,16 +955,19 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
// properties_->Transform() is present if a CSS transform is present,
// and is also present if transform-style: preserve-3d is set.
// See NeedsTransform.
- if (properties_->Transform()) {
- context_.current.transform = properties_->Transform();
+ if (const auto* transform = properties_->Transform()) {
+ context_.current.transform = transform;
if (object_.StyleRef().Preserves3D()) {
- context_.current.rendering_context_id =
- properties_->Transform()->RenderingContextId();
+ context_.current.rendering_context_id = transform->RenderingContextId();
context_.current.should_flatten_inherited_transform = false;
} else {
context_.current.rendering_context_id = 0;
context_.current.should_flatten_inherited_transform = true;
}
+ if (transform->IsIdentityOr2DTranslation()) {
+ context_.translation_2d_to_layout_shift_root_delta +=
+ transform->Translation2D();
+ }
} else if (RuntimeEnabledFeatures::TransformInteropEnabled() &&
!object_.IsAnonymous()) {
// With kTransformInterop enabled, 3D rendering contexts follow the
@@ -979,7 +979,10 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
}
static bool MayNeedClipPathClip(const LayoutObject& object) {
- return !object.IsText() && object.StyleRef().ClipPath();
+ // We only apply clip-path if the LayoutObject has a layer or is an SVG
+ // child. See NeedsEffect() for additional information on the former.
+ return !object.IsText() && object.StyleRef().HasClipPath() &&
+ (object.HasLayer() || object.IsSVGChild());
}
static bool NeedsClipPathClip(const LayoutObject& object) {
@@ -1063,7 +1066,7 @@ static bool NeedsEffect(const LayoutObject& object,
if (object.StyleRef().HasMask())
return true;
- if (object.StyleRef().ClipPath() &&
+ if (object.StyleRef().HasClipPath() &&
object.FirstFragment().ClipPathBoundingBox() &&
!object.FirstFragment().ClipPathPath()) {
// If the object has a valid clip-path but can't use path-based clip-path,
@@ -1120,7 +1123,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
base::Optional<IntRect> mask_clip = CSSMaskPainter::MaskBoundingBox(
object_, context_.current.paint_offset);
bool has_clip_path =
- style.ClipPath() && fragment_data_.ClipPathBoundingBox();
+ style.HasClipPath() && fragment_data_.ClipPathBoundingBox();
bool has_mask_based_clip_path =
has_clip_path && !fragment_data_.ClipPathPath();
base::Optional<IntRect> clip_path_clip;
@@ -1280,8 +1283,9 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
}
}
- if (properties_->Effect()) {
- context_.current_effect = properties_->Effect();
+ if (const auto* effect = properties_->Effect()) {
+ context_.current_effect = effect;
+ context_.this_or_ancestor_opacity_is_zero |= effect->Opacity() == 0;
if (properties_->MaskClip()) {
context_.current.clip = context_.absolute_position.clip =
context_.fixed_position.clip = properties_->MaskClip();
@@ -1316,15 +1320,6 @@ static CompositingReasons CompositingReasonsForFilterProperty() {
return reasons;
}
-static bool HasReferenceFilterOnly(const ComputedStyle& style) {
- if (!style.HasFilter())
- return false;
- const FilterOperations& operations = style.Filter();
- if (operations.size() != 1)
- return false;
- return operations.at(0)->GetType() == FilterOperation::REFERENCE;
-}
-
static bool IsClipPathDescendant(const LayoutObject& object) {
// If the object itself is a resource container (root of a resource subtree)
// it is not considered a clipPath descendant since it is independent of its
@@ -1354,7 +1349,7 @@ static bool NeedsFilter(const LayoutObject& object,
return true;
} else if (object.IsSVGChild() && !object.IsText() &&
SVGResources::GetClient(object)) {
- if (HasReferenceFilterOnly(object.StyleRef())) {
+ if (object.StyleRef().HasFilter()) {
// Filters don't apply to elements that are descendants of a <clipPath>.
if (!full_context.has_svg_hidden_container_ancestor ||
!IsClipPathDescendant(object))
@@ -1382,7 +1377,7 @@ static void UpdateFilterEffect(const LayoutObject& object,
SVGElementResourceClient* client = SVGResources::GetClient(object);
if (!client)
return;
- if (!HasReferenceFilterOnly(object.StyleRef()))
+ if (!object.StyleRef().HasFilter())
return;
// Try to use the cached filter.
if (effect_node)
@@ -1540,29 +1535,6 @@ void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip() {
}
}
-// Returns true if we are printing which was initiated by the frame. We should
-// ignore clipping and scroll transform on contents. WebLocalFrameImpl will
-// issue artificial page clip for each page, and always print from the origin
-// of the contents for which no scroll offset should be applied.
-static bool IsPrintingRootLayoutView(const LayoutObject& object) {
- if (!IsA<LayoutView>(object))
- return false;
-
- const auto& frame = *object.GetFrame();
- if (!frame.GetDocument()->Printing())
- return false;
-
- const auto* parent_frame = frame.Tree().Parent();
- // TODO(crbug.com/455764): The local frame may be not the root frame of
- // printing when it's printing under a remote frame.
- auto* parent_local_frame = DynamicTo<LocalFrame>(parent_frame);
- if (!parent_local_frame)
- return true;
-
- // If the parent frame is printing, this frame should clip normally.
- return !parent_local_frame->GetDocument()->Printing();
-}
-
// TODO(wangxianzhu): Combine the logic by overriding LayoutBox::
// ComputeOverflowClipAxes() in LayoutReplaced and subclasses and remove
// this function.
@@ -1597,9 +1569,16 @@ static bool NeedsOverflowClip(const LayoutObject& object) {
SVGLayoutSupport::IsOverflowHidden(object))
return true;
- return object.IsBox() &&
- To<LayoutBox>(object).ShouldClipOverflowAlongEitherAxis() &&
- !IsPrintingRootLayoutView(object);
+ if (!object.IsBox())
+ return false;
+
+ if (!To<LayoutBox>(object).ShouldClipOverflowAlongEitherAxis())
+ return false;
+
+ if (IsA<LayoutView>(object) && !object.GetFrame()->ClipsContent())
+ return false;
+
+ return true;
}
void FragmentPaintPropertyTreeBuilder::UpdateLocalBorderBoxContext() {
@@ -1725,56 +1704,11 @@ void FragmentPaintPropertyTreeBuilder::UpdateInnerBorderRadiusClip() {
context_.current.clip = border_radius_clip;
}
-static bool CanOmitOverflowClip(const LayoutObject& object) {
- DCHECK(NeedsOverflowClip(object));
-
- if (IsA<LayoutView>(object) && !object.GetFrame()->ClipsContent()) {
- return true;
- }
-
- // Some non-block boxes and SVG objects have special overflow rules.
- const auto* block = DynamicTo<LayoutBlock>(object);
- if (!block || object.IsSVG())
- return false;
-
- // Selection may overflow.
- if (block->IsSelected())
- return false;
- // Other cases that the contents may overflow. The conditions are copied from
- // BlockPainter for SPv1 clip. TODO(wangxianzhu): clean up.
- if (block->HasControlClip() || block->ShouldPaintCarets())
- return false;
-
- // We need OverflowClip for hit-testing if the clip rect excluding overlay
- // scrollbars is different from the normal clip rect.
- auto clip_rect = block->OverflowClipRect(PhysicalOffset());
- auto clip_rect_excluding_overlay_scrollbars = block->OverflowClipRect(
- PhysicalOffset(), kExcludeOverlayScrollbarSizeForHitTesting);
- if (clip_rect != clip_rect_excluding_overlay_scrollbars)
- return false;
-
- // Visual overflow extending beyond the clip rect must be clipped.
- // ContentsVisualOverflowRect() does not include self-painting descendants
- // (see comment above |BoxOverflowModel|) so, as a simplification, do not
- // omit the clip if there are any PaintLayer descendants.
- if (block->HasLayer() && block->Layer()->FirstChild())
- return false;
-
- // TODO(wangxianzhu): It's incorrect to test the physical clip_rect against
- // the flipped ContentsVisualOverflowRect and LayoutOverflowRect.
- if (!clip_rect.ToLayoutRect().Contains(block->ContentsVisualOverflowRect()))
- return false;
-
- // Content can scroll, and needs to be clipped, if the layout overflow extends
- // beyond the clip rect.
- return clip_rect.ToLayoutRect().Contains(block->LayoutOverflowRect());
-}
-
void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
DCHECK(properties_);
if (NeedsPaintPropertyUpdate()) {
- if (NeedsOverflowClip(object_) && !CanOmitOverflowClip(object_)) {
+ if (NeedsOverflowClip(object_)) {
ClipPaintPropertyNode::State state(context_.current.transform,
FloatRoundedRect());
@@ -1968,37 +1902,6 @@ static MainThreadScrollingReasons GetMainThreadScrollingReasons(
// setting is only for testing.
if (!object.GetFrame()->GetSettings()->GetThreadedScrollingEnabled())
reasons |= cc::MainThreadScrollingReason::kThreadedScrollingDisabled;
-
- // LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects depends
- // on compositing (LayoutBoxModelObject::IsSlowRepaintConstrainedObject
- // calls PaintLayer::GetCompositingState, and PaintLayer::SticksToScroller
- // depends on the ancestor overflow layer) so CompositeAfterPaint cannot
- // use LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // Force main-thread scrolling if the frame has uncomposited position:
- // fixed elements. Note: we care about this not only for input-scrollable
- // frames but also for overflow: hidden frames, because script can run
- // composited smooth-scroll animations. For this reason, we use
- // HasOverflow instead of ScrollsOverflow (which is false for overflow:
- // hidden).
- if (To<LayoutBox>(object).GetScrollableArea()->HasOverflow() &&
- object.StyleRef().VisibleToHitTesting() &&
- object.GetFrameView()
- ->HasVisibleSlowRepaintViewportConstrainedObjects()) {
- reasons |= cc::MainThreadScrollingReason::
- kHasNonLayerViewportConstrainedObjects;
- }
- } else {
- // TODO(pdr): CompositeAfterPaint should use an approach like
- // CompositingReasonFinder::RequiresCompositingForScrollDependentPosition,
- // adding main thread reasons if compositing was not required. This has
- // a small behavior change because main thread reasons will be added in
- // the case where a non-scroll compositing trigger (e.g., transform)
- // requires compositing, even though a main thread reason is not needed.
- // CompositingReasonFinder::RequiresCompositingForScrollDependentPosition
- // will need to be changed to not query
- // PaintLayer::AncestorScrollContainerLayer.
- }
}
return reasons;
}
@@ -2006,6 +1909,12 @@ static MainThreadScrollingReasons GetMainThreadScrollingReasons(
void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
DCHECK(properties_);
+ FloatSize old_scroll_offset;
+ if (const auto* old_scroll_translation = properties_->ScrollTranslation()) {
+ DCHECK(full_context_.was_layout_shift_root);
+ old_scroll_offset = old_scroll_translation->Translation2D();
+ }
+
if (NeedsPaintPropertyUpdate()) {
if (object_.IsBox() && To<LayoutBox>(object_).NeedsScrollNode(
full_context_.direct_compositing_reasons)) {
@@ -2156,12 +2065,17 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
if (properties_->Scroll())
context_.current.scroll = properties_->Scroll();
- if (properties_->ScrollTranslation()) {
+ if (const auto* scroll_translation = properties_->ScrollTranslation()) {
context_.current.transform = properties_->ScrollTranslation();
// See comments for ScrollTranslation in object_paint_properties.h for the
// reason of adding ScrollOrigin().
context_.current.paint_offset +=
PhysicalOffset(To<LayoutBox>(object_).ScrollOrigin());
+
+ // A scroller creates a layout shift root, so we just calculate one scroll
+ // offset delta without accumulation.
+ context_.current.scroll_offset_to_layout_shift_root_delta =
+ scroll_translation->Translation2D() - old_scroll_offset;
}
}
@@ -2395,108 +2309,61 @@ static PhysicalOffset PaintOffsetInPaginationContainer(
}
void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
- if (!IsInNGFragmentTraversal()) {
- // Paint offsets for fragmented content are computed from scratch.
- const auto* enclosing_pagination_layer =
- full_context_.painting_layer->EnclosingPaginationLayer();
- if (enclosing_pagination_layer &&
- // Except if the paint_offset_root is below the pagination container, in
- // which case fragmentation offsets are already baked into the paint
- // offset transform for paint_offset_root.
- !context_.current.paint_offset_root->PaintingLayer()
- ->EnclosingPaginationLayer()) {
- if (object_.StyleRef().GetPosition() == EPosition::kAbsolute)
- context_.current = context_.absolute_position;
- else if (object_.StyleRef().GetPosition() == EPosition::kFixed)
- context_.current = context_.fixed_position;
-
- // Set fragment visual paint offset.
- PhysicalOffset paint_offset = PaintOffsetInPaginationContainer(
- object_, *enclosing_pagination_layer);
-
- paint_offset += fragment_data_.LegacyPaginationOffset();
- paint_offset += context_.repeating_paint_offset_adjustment;
- paint_offset +=
- VisualOffsetFromPaintOffsetRoot(context_, enclosing_pagination_layer);
-
- // The paint offset root can have a subpixel paint offset adjustment.
- // The paint offset root always has one fragment.
- const auto& paint_offset_root_fragment =
- context_.current.paint_offset_root->FirstFragment();
- paint_offset += paint_offset_root_fragment.PaintOffset();
+ if (IsInNGFragmentTraversal()) {
+ // Text and non-atomic inlines are special, in that they share one
+ // FragmentData per fragmentainer, so their paint offset is kept at their
+ // container. For all other objects, include the offset now.
+ if (object_.IsBox())
+ context_.current.paint_offset += pre_paint_info_->iterator->Link().offset;
+ return;
+ }
- context_.current.paint_offset = paint_offset;
- return;
- }
+ // Paint offsets for fragmented content are computed from scratch.
+ const auto* enclosing_pagination_layer =
+ full_context_.painting_layer->EnclosingPaginationLayer();
+ if (enclosing_pagination_layer &&
+ // Except if the paint_offset_root is below the pagination container, in
+ // which case fragmentation offsets are already baked into the paint
+ // offset transform for paint_offset_root.
+ !context_.current.paint_offset_root->PaintingLayer()
+ ->EnclosingPaginationLayer()) {
+ if (object_.StyleRef().GetPosition() == EPosition::kAbsolute)
+ context_.current = context_.absolute_position;
+ else if (object_.StyleRef().GetPosition() == EPosition::kFixed)
+ context_.current = context_.fixed_position;
+
+ // Set fragment visual paint offset.
+ PhysicalOffset paint_offset =
+ PaintOffsetInPaginationContainer(object_, *enclosing_pagination_layer);
+
+ paint_offset += fragment_data_.LegacyPaginationOffset();
+ paint_offset += context_.repeating_paint_offset_adjustment;
+ paint_offset +=
+ VisualOffsetFromPaintOffsetRoot(context_, enclosing_pagination_layer);
+
+ // The paint offset root can have a subpixel paint offset adjustment. The
+ // paint offset root always has one fragment.
+ const auto& paint_offset_root_fragment =
+ context_.current.paint_offset_root->FirstFragment();
+ paint_offset += paint_offset_root_fragment.PaintOffset();
+
+ context_.current.paint_offset = paint_offset;
+ return;
+ }
- if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
- context_.current.paint_offset = context_.paint_offset_for_float;
+ if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
+ context_.current.paint_offset = context_.paint_offset_for_float;
- // Multicolumn spanners are painted starting at the multicolumn container
- // (but still inherit properties in layout-tree order) so reset the paint
- // offset.
- if (object_.IsColumnSpanAll()) {
- context_.current.paint_offset =
- object_.Container()->FirstFragment().PaintOffset();
- }
+ // Multicolumn spanners are painted starting at the multicolumn container (but
+ // still inherit properties in layout-tree order) so reset the paint offset.
+ if (object_.IsColumnSpanAll()) {
+ context_.current.paint_offset =
+ object_.Container()->FirstFragment().PaintOffset();
}
if (object_.IsBoxModelObject()) {
const auto& box_model_object = To<LayoutBoxModelObject>(object_);
- EPosition position = box_model_object.StyleRef().GetPosition();
- if (IsInNGFragmentTraversal() &&
- (position == EPosition::kAbsolute || position == EPosition::kFixed)) {
- // The LayoutNG fragment tree structure is very similar to the containing
- // block structure, with the exception of out-of-flow positioned boxes
- // whose containing block is a non-atomic inline. If this is the case, we
- // now need to add the offsets introduced by all inlines in the ancestry
- // that affect us. This is a way to work around the discrepancy between
- // the NG fragment tree structure and the actual containing block tree
- // structure.
- // TODO(mstensho): It's not good to walk up the ancestry
- // (LayoutObject::Container()) like this, in fact pretty disastrous for
- // e.g. fixed positioned objects, whose containing block is typically far
- // up in the tree. Should we introduce a bit on LayoutObject that's set
- // when this is necessary (or likely to be necessary)?
- const LayoutObject* container = object_.Container();
- if (container->IsLayoutInline() || container->IsAnonymousBlock()) {
- // Set up context_ and full_context_ to be aware of the inline that is
- // the actual containing block. This will be used by the code further
- // down in this method.
- // TODO(mstensho): This is currently incomplete. We're failing cases
- // where the containing block sets up a filter, for instance.
- if (position == EPosition::kFixed)
- full_context_.container_for_fixed_position = container;
- full_context_.container_for_absolute_position = container;
- PhysicalOffset relative_offset;
- if (const auto* box = DynamicTo<LayoutBox>(container)) {
- // If the OOF is contained by an anonymous block (because of inline
- // continuations), we need to take that into account.
- //
- // Example:
- // <span style="position:relative;">
- // <div>
- // <div id="box_model_object" style="position:absolute;">
- DCHECK(box->IsAnonymousBlock());
- relative_offset =
- box->PhysicalLocation() + box->OffsetForInFlowPosition();
- } else {
- do {
- relative_offset +=
- To<LayoutInline>(container)->OffsetForInFlowPosition();
- container = container->Container();
- } while (container->IsLayoutInline());
- }
- if (position == EPosition::kFixed) {
- context_.fixed_position = context_.current;
- context_.fixed_position.paint_offset += relative_offset;
- }
- context_.absolute_position = context_.current;
- context_.absolute_position.paint_offset += relative_offset;
- }
- }
-
- switch (position) {
+ switch (box_model_object.StyleRef().GetPosition()) {
case EPosition::kStatic:
break;
case EPosition::kRelative:
@@ -2504,21 +2371,15 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
box_model_object.OffsetForInFlowPosition();
break;
case EPosition::kAbsolute: {
- // TODO(almaher): Remove call to IsInNGFragmentTraversal().
- DCHECK(full_context_.container_for_absolute_position ==
- box_model_object.Container() ||
- (IsInNGFragmentTraversal() &&
- box_model_object.IsInsideFlowThread()));
+ DCHECK_EQ(full_context_.container_for_absolute_position,
+ box_model_object.Container());
context_.current = context_.absolute_position;
// Absolutely positioned content in an inline should be positioned
// relative to the inline.
const auto* container = full_context_.container_for_absolute_position;
if (container && container->IsLayoutInline()) {
- // TODO(almaher): Remove call to IsInNGFragmentTraversal().
- DCHECK(container->CanContainAbsolutePositionObjects() ||
- (IsInNGFragmentTraversal() &&
- box_model_object.IsInsideFlowThread()));
+ DCHECK(container->CanContainAbsolutePositionObjects());
DCHECK(box_model_object.IsBox());
context_.current.paint_offset +=
To<LayoutInline>(container)->OffsetForInFlowPositionedInline(
@@ -2529,11 +2390,8 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
case EPosition::kSticky:
break;
case EPosition::kFixed: {
- // TODO(almaher): Remove call to IsInNGFragmentTraversal().
- DCHECK(full_context_.container_for_fixed_position ==
- box_model_object.Container() ||
- (IsInNGFragmentTraversal() &&
- box_model_object.IsInsideFlowThread()));
+ DCHECK_EQ(full_context_.container_for_fixed_position,
+ box_model_object.Container());
context_.current = context_.fixed_position;
// Fixed-position elements that are fixed to the viewport have a
// transform above the scroll of the LayoutView. Child content is
@@ -2556,15 +2414,6 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
}
}
- if (IsInNGFragmentTraversal()) {
- // Text and non-atomic inlines are special, in that they share one
- // FragmentData per fragmentainer, so their paint offset is kept at their
- // container. For all other objects, include the offset now.
- if (object_.IsBox())
- context_.current.paint_offset += pre_paint_info_->iterator->Link().offset;
- return;
- }
-
if (object_.IsBox()) {
// TODO(pdr): Several calls in this function walk back up the tree to
// calculate containers (e.g., physicalLocation, offsetForInFlowPosition*).
@@ -2602,12 +2451,6 @@ void FragmentPaintPropertyTreeBuilder::SetNeedsPaintPropertyUpdateIfNeeded() {
const LayoutBox& box = To<LayoutBox>(object_);
- if (NeedsOverflowClip(box)) {
- bool had_overflow_clip = properties_ && properties_->OverflowClip();
- if (had_overflow_clip == CanOmitOverflowClip(box))
- box.GetMutableForPainting().SetNeedsPaintPropertyUpdate();
- }
-
if (box.IsLayoutReplaced() &&
box.PreviousPhysicalContentBoxRect() != box.PhysicalContentBoxRect())
box.GetMutableForPainting().SetNeedsPaintPropertyUpdate();
@@ -2713,6 +2556,30 @@ void FragmentPaintPropertyTreeBuilder::UpdateClipPathCache() {
path ? AdoptRef(new RefCountedPath(std::move(*path))) : nullptr);
}
+static bool IsLayoutShiftRoot(const LayoutObject& object,
+ const FragmentData& fragment) {
+ const auto* properties = fragment.PaintProperties();
+ if (!properties)
+ return false;
+ if (IsA<LayoutView>(object))
+ return true;
+ if (auto* transform = properties->Transform()) {
+ if (!transform->IsIdentityOr2DTranslation())
+ return true;
+ }
+ if (properties->ReplacedContentTransform())
+ return true;
+ if (properties->TransformIsolationNode())
+ return true;
+ if (auto* offset_translation = properties->PaintOffsetTranslation()) {
+ if (offset_translation->RequiresCompositingForScrollDependentPosition())
+ return true;
+ }
+ if (properties->OverflowClip())
+ return true;
+ return false;
+}
+
void FragmentPaintPropertyTreeBuilder::UpdateForSelf() {
#if DCHECK_IS_ON()
FindPaintOffsetNeedingUpdateScope check_paint_offset(
@@ -2762,14 +2629,18 @@ void FragmentPaintPropertyTreeBuilder::UpdateForSelf() {
context_.current.should_flatten_inherited_transform = true;
}
UpdateLocalBorderBoxContext();
+ UpdateLayoutShiftRootChanged(IsLayoutShiftRoot(object_, fragment_data_));
// For LayoutView, additional_offset_to_layout_shift_root_delta applies to
// neither itself nor descendants. For other layout shift roots, we clear the
// delta at the end of UpdateForChildren() because the delta still applies to
- // the object itself.
+ // the object itself. Same for translation_2d_to_layout_shift_delta and
+ // scroll_offset_to_layout_shift_root_delta.
if (IsA<LayoutView>(object_)) {
context_.current.additional_offset_to_layout_shift_root_delta =
PhysicalOffset();
+ context_.translation_2d_to_layout_shift_root_delta = FloatSize();
+ context_.current.scroll_offset_to_layout_shift_root_delta = FloatSize();
}
}
@@ -2796,23 +2667,36 @@ void FragmentPaintPropertyTreeBuilder::UpdateForChildren() {
}
UpdateOutOfFlowContext();
- bool is_layout_shift_root = IsLayoutShiftRoot();
- if (was_layout_shift_root_ || is_layout_shift_root) {
+ bool is_layout_shift_root = IsLayoutShiftRoot(object_, fragment_data_);
+ UpdateLayoutShiftRootChanged(is_layout_shift_root);
+ if (full_context_.was_layout_shift_root || is_layout_shift_root) {
+ // A layout shift root (e.g. with mere OverflowClip) may have non-zero
+ // paint offset. Exclude the layout shift root's paint offset delta from
+ // additional_offset_to_layout_shift_root_delta.
context_.current.additional_offset_to_layout_shift_root_delta =
- PhysicalOffset();
+ context_.old_paint_offset - fragment_data_.PaintOffset();
+ context_.translation_2d_to_layout_shift_root_delta = FloatSize();
+ // Don't reset scroll_offset_to_layout_shift_root_delta if this object has
+ // scroll translation because we need to propagate the delta to descendants.
+ if (!properties_ || !properties_->ScrollTranslation())
+ context_.current.scroll_offset_to_layout_shift_root_delta = FloatSize();
}
- if (is_layout_shift_root != was_layout_shift_root_)
- context_.current.layout_shift_root_changed = true;
- else if (is_layout_shift_root && was_layout_shift_root_)
- context_.current.layout_shift_root_changed = false;
-
#if DCHECK_IS_ON()
if (properties_)
properties_->Validate();
#endif
}
+void FragmentPaintPropertyTreeBuilder::UpdateLayoutShiftRootChanged(
+ bool is_layout_shift_root) {
+ if (is_layout_shift_root != full_context_.was_layout_shift_root) {
+ context_.current.layout_shift_root_changed = true;
+ } else if (is_layout_shift_root && full_context_.was_layout_shift_root) {
+ context_.current.layout_shift_root_changed = false;
+ }
+}
+
} // namespace
void PaintPropertyTreeBuilder::InitFragmentPaintProperties(
@@ -2831,6 +2715,12 @@ void PaintPropertyTreeBuilder::InitFragmentPaintProperties(
context.pending_additional_offset_to_layout_shift_root_delta =
-PhysicalOffset::FromFloatSizeRound(translation->Translation2D());
}
+ if (const auto* transform = properties->Transform()) {
+ if (transform->IsIdentityOr2DTranslation()) {
+ context.translation_2d_to_layout_shift_root_delta -=
+ transform->Translation2D();
+ }
+ }
}
if (needs_paint_properties) {
@@ -3580,8 +3470,7 @@ bool PaintPropertyTreeBuilder::UpdateFragments() {
!object_.IsText() &&
#endif
(NeedsPaintOffsetTranslation(
- object_, context_.direct_compositing_reasons,
- context_.is_affected_by_outer_viewport_bounds_delta) ||
+ object_, context_.direct_compositing_reasons) ||
NeedsStickyTranslation(object_) ||
NeedsTransform(object_, context_.direct_compositing_reasons) ||
// Note: It is important to use MayNeedClipPathClip() instead of
@@ -3681,33 +3570,20 @@ void PaintPropertyTreeBuilder::UpdatePaintingLayer() {
DCHECK(context_.painting_layer == object_.PaintingLayer());
}
-bool PaintPropertyTreeBuilder::IsAffectedByOuterViewportBoundsDelta() const {
- if (!object_.IsBox())
- return false;
-
- if (object_.StyleRef().GetPosition() != EPosition::kFixed ||
- !object_.StyleRef().IsFixedToBottom())
- return false;
-
- // Objects inside an iframe that's the root scroller should get the same
- // "pushed by top controls" behavior as for the main frame.
- auto& controller =
- object_.GetFrame()->GetPage()->GlobalRootScrollerController();
- if (!object_.GetFrame()->IsMainFrame() &&
- object_.GetFrame()->GetDocument() != controller.GlobalRootScroller())
- return false;
-
- // It's affected by viewport only if the container is the LayoutView.
- DCHECK_EQ(context_.container_for_fixed_position, object_.Container());
- return IsA<LayoutView>(context_.container_for_fixed_position);
-}
-
PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForSelf() {
// This is not inherited from the parent context and we always recalculate it.
context_.direct_compositing_reasons =
CompositingReasonFinder::DirectReasonsForPaintProperties(object_);
- context_.is_affected_by_outer_viewport_bounds_delta =
- IsAffectedByOuterViewportBoundsDelta();
+ context_.was_layout_shift_root =
+ IsLayoutShiftRoot(object_, object_.FirstFragment());
+ context_.was_main_thread_scrolling = false;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ IsA<LayoutBox>(object_)) {
+ if (auto* scrollable_area = To<LayoutBox>(object_).GetScrollableArea()) {
+ context_.was_main_thread_scrolling =
+ scrollable_area->ShouldScrollOnMainThread();
+ }
+ }
UpdatePaintingLayer();
@@ -3763,6 +3639,9 @@ PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForSelf() {
}
}
+ object_.GetMutableForPainting()
+ .SetShouldAssumePaintOffsetTranslationForLayoutShiftTracking(false);
+
return property_changed;
}
@@ -3830,6 +3709,15 @@ PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForChildren() {
if (property_changed >= PaintPropertyChangeType::kNodeAddedOrRemoved)
context_.painting_layer->SetNeedsRepaint();
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ IsA<LayoutBox>(object_)) {
+ if (auto* scrollable_area = To<LayoutBox>(object_).GetScrollableArea()) {
+ if (context_.was_main_thread_scrolling !=
+ scrollable_area->ShouldScrollOnMainThread())
+ scrollable_area->MainThreadScrollingDidChange();
+ }
+ }
+
return property_changed;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
index c948b3410e7..510f53a0858 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
@@ -49,14 +49,14 @@ struct PaintPropertyTreeBuilderFragmentContext {
// "Additional offset to layout shift root" is the accumulation of paint
// offsets encoded in PaintOffsetTranslations between the local transform
// space and the layout shift root. The layout shift root is the nearest
- // transform node (not including the transform nodes for the current object)
- // that is one of:
- // * The transform property tree state of the containing LayoutView
- // * A transform that is not identity or 2d translation
- // * A scroll translation
- // * A replaced contents transform
- // * A transform isolation node
- // * A sticky translation
+ // ancestor with
+ // - a transform node that is one of:
+ // * the transform property tree state of the containing LayoutView
+ // * a transform that is not identity or 2d translation
+ // * a replaced contents transform
+ // * a transform isolation node
+ // * a paint offset translation for a sticky or fixed position element
+ // - or an overflow clip node.
// The offset plus paint_offset is the offset for layout shift tracking.
// It doesn't include transforms because we need to ignore transform changes
// for layout shift tracking, see
@@ -65,6 +65,10 @@ struct PaintPropertyTreeBuilderFragmentContext {
// layout shift root.
PhysicalOffset additional_offset_to_layout_shift_root_delta;
+ // Similar to additional_offset_to_layout_shift_root_delta but for scroll
+ // offsets.
+ FloatSize scroll_offset_to_layout_shift_root_delta;
+
// For paint invalidation optimization for subpixel movement under
// composited layer. It's reset to zero if subpixel can't be propagated
// thus the optimization is not applicable (e.g. when crossing a
@@ -113,6 +117,8 @@ struct PaintPropertyTreeBuilderFragmentContext {
// containing block of corresponding positioned descendants. Overflow clips
// are also inherited by containing block tree instead of DOM tree, thus they
// are included in the additional context too.
+ //
+ // Note that these contexts are not used in LayoutNGFragmentTraversal.
ContainingBlockContext absolute_position;
ContainingBlockContext fixed_position;
@@ -127,6 +133,7 @@ struct PaintPropertyTreeBuilderFragmentContext {
// Therefore, we don't need extra bookkeeping for effect nodes and can
// generate the effect tree from a DOM-order traversal.
const EffectPaintPropertyNodeOrAlias* current_effect;
+ bool this_or_ancestor_opacity_is_zero = false;
// If the object is a flow thread, this records the clip rect for this
// fragment.
@@ -148,6 +155,10 @@ struct PaintPropertyTreeBuilderFragmentContext {
// ContainingBlockContext is set, this value should be added to
// ContainingBlockContext::additional_offset_to_layout_shift_root_delta.
PhysicalOffset pending_additional_offset_to_layout_shift_root_delta;
+
+ // The delta between the old and new accumulated offsets of 2d translation
+ // transforms to the layout shift root.
+ FloatSize translation_2d_to_layout_shift_root_delta;
};
struct PaintPropertyTreeBuilderContext {
@@ -157,6 +168,8 @@ struct PaintPropertyTreeBuilderContext {
PaintPropertyTreeBuilderContext();
Vector<PaintPropertyTreeBuilderFragmentContext, 1> fragments;
+
+ // TODO(mstensho): Stop using these in LayoutNGFragmentTraversal.
const LayoutObject* container_for_absolute_position = nullptr;
const LayoutObject* container_for_fixed_position = nullptr;
@@ -200,7 +213,7 @@ struct PaintPropertyTreeBuilderContext {
// its clip since this variable was last set to false. This is used
// to find out whether a clip changed since the last transform update.
// Code outside of this class resets clip_changed to false when transforms
- // change.
+ // change. Used only when CullRectUpdate is not enabled.
unsigned clip_changed : 1;
// When printing, fixed-position objects and their descendants need to repeat
@@ -215,7 +228,11 @@ struct PaintPropertyTreeBuilderContext {
// If not, subtree invalidations occur on every property tree change.
unsigned supports_composited_raster_invalidation : 1;
- unsigned is_affected_by_outer_viewport_bounds_delta : 1;
+ // Whether this object was a layout shift root during the previous render
+ // (not this one).
+ unsigned was_layout_shift_root : 1;
+
+ unsigned was_main_thread_scrolling : 1;
// This is always recalculated in PaintPropertyTreeBuilder::UpdateForSelf()
// which overrides the inherited value.
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index ad553248de2..7ac4b686fc0 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -5708,66 +5708,6 @@ TEST_P(PaintPropertyTreeBuilderTest, IframeDoesNotRequireCompositedScrolling) {
DocScrollTranslation(&ChildDocument())->HasDirectCompositingReasons());
}
-TEST_P(PaintPropertyTreeBuilderTest, OmitOverflowClip) {
- SetBodyInnerHTML(R"HTML(
- <style>
- .sized-container { width: 100px; height: 100px }
- .small-content { width: 50px; height: 50px }
- .big-content { width: 200px; height: 200px }
- </style>
- <div id="auto-size" style="overflow: hidden">
- <div class="small-content"></div>
- </div>
- <div id="overflow-hidden-no-overflow" class="sized-container"
- style="overflow: hidden">
- <div class="small-content"></div>
- </div>
- <div id="overflow-hidden-overflow" class="sized-container"
- style="overflow: hidden">
- <div class="big-content"></div>
- </div>
- <div id="contain-paint-no-overflow" class="sized-container"
- style="contain: paint">
- <div class="small-content"></div>
- </div>
- <div id="contain-paint-overflow" class="sized-container"
- style="contain: paint">
- <div class="big-content"></div>
- </div>
- <div id="has-self-painting-descendant" class="sized-container"
- style="overflow: hidden">
- <div class="small-content" style="position: relative; left: 100px"></div>
- </div>
- <div id="overflow-auto-no-overflow" class="sized-container"
- style="overflow: auto">
- <div class="small-content"></div>
- </div>
- <div id="overflow-auto-overflow" class="sized-container"
- style="overflow: auto">
- <div class="big-content"></div>
- </div>
- <input id="button" type="button" value="button">
- )HTML");
- CHECK(GetDocument().GetPage()->GetScrollbarTheme().UsesOverlayScrollbars());
-
- EXPECT_FALSE(PaintPropertiesForElement("auto-size")->OverflowClip());
- EXPECT_FALSE(
- PaintPropertiesForElement("overflow-hidden-no-overflow")->OverflowClip());
- EXPECT_TRUE(
- PaintPropertiesForElement("overflow-hidden-overflow")->OverflowClip());
- EXPECT_FALSE(
- PaintPropertiesForElement("contain-paint-no-overflow")->OverflowClip());
- EXPECT_TRUE(
- PaintPropertiesForElement("contain-paint-overflow")->OverflowClip());
- EXPECT_TRUE(PaintPropertiesForElement("has-self-painting-descendant")
- ->OverflowClip());
- EXPECT_FALSE(
- PaintPropertiesForElement("overflow-auto-no-overflow")->OverflowClip());
- EXPECT_TRUE(
- PaintPropertiesForElement("overflow-auto-overflow")->OverflowClip());
- EXPECT_TRUE(PaintPropertiesForElement("button")->OverflowClip());
-}
-
TEST_P(PaintPropertyTreeBuilderTest, ClipHitTestChangeDoesNotCauseFullRepaint) {
SetBodyInnerHTML(R"HTML(
<html>
@@ -5909,7 +5849,7 @@ TEST_P(PaintPropertyTreeBuilderTest, RepeatingFixedPositionInPagedMedia) {
EXPECT_EQ(3u, NumFragments(fixed));
for (int i = 0; i < 3; i++) {
const auto& fragment = FragmentAt(fixed, i);
- EXPECT_EQ(PhysicalOffset(20, -180 + i * 400), fragment.PaintOffset());
+ EXPECT_EQ(PhysicalOffset(0, 0), fragment.PaintOffset());
EXPECT_EQ(LayoutUnit(400 * i), fragment.LogicalTopInFlowThread());
}
@@ -5917,7 +5857,7 @@ TEST_P(PaintPropertyTreeBuilderTest, RepeatingFixedPositionInPagedMedia) {
EXPECT_EQ(3u, NumFragments(fixed_child));
for (int i = 0; i < 3; i++) {
const auto& fragment = FragmentAt(fixed_child, i);
- EXPECT_EQ(PhysicalOffset(20, -170 + i * 400), fragment.PaintOffset());
+ EXPECT_EQ(PhysicalOffset(0, 10), fragment.PaintOffset());
EXPECT_EQ(LayoutUnit(i * 400), fragment.LogicalTopInFlowThread());
}
@@ -5996,6 +5936,11 @@ TEST_P(PaintPropertyTreeBuilderTest,
}
TEST_P(PaintPropertyTreeBuilderTest, RepeatingTableSectionInPagedMedia) {
+ // TablesNG fragmentation has not been implemented. Once it is,
+ // this test still will not apply.
+ if (RuntimeEnabledFeatures::LayoutNGTableEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<style>
body { margin: 0; }
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index f1be2a34ecb..33e3260a0fe 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -333,9 +333,11 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
// Marking the child div as needing a paint property update should propagate
// up the tree and across frames.
inner_div_with_transform->SetNeedsPaintPropertyUpdate();
- EXPECT_TRUE(
+ // DescendantNeedsPaintPropertyUpdate flag is not propagated crossing frame
+ // boundaries until PrePaint.
+ EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
- EXPECT_TRUE(div_with_transform->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(div_with_transform->DescendantNeedsPaintPropertyUpdate());
EXPECT_TRUE(child_layout_view->DescendantNeedsPaintPropertyUpdate());
EXPECT_TRUE(inner_div_with_transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(inner_div_with_transform->DescendantNeedsPaintPropertyUpdate());
@@ -352,7 +354,7 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
// skipped if the owning layout tree does not need an update.
LocalFrameView* child_frame_view = ChildDocument().View();
child_frame_view->SetNeedsPaintPropertyUpdate();
- EXPECT_TRUE(
+ EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
frame_view->UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(
@@ -401,37 +403,45 @@ TEST_P(PaintPropertyTreeUpdateTest, BuildingStopsAtThrottledFrames) {
auto* iframe = To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
iframe->setAttribute(html_names::kStyleAttr, "transform: translateY(5555px)");
UpdateAllLifecyclePhasesForTest();
- // Ensure intersection observer notifications get delivered.
- test::RunPendingTasks();
EXPECT_FALSE(GetDocument().View()->IsHiddenForThrottling());
+ EXPECT_FALSE(GetDocument().View()->ShouldThrottleRenderingForTest());
EXPECT_TRUE(ChildDocument().View()->IsHiddenForThrottling());
+ EXPECT_TRUE(ChildDocument().View()->ShouldThrottleRenderingForTest());
auto* transform = GetLayoutObjectByElementId("transform");
auto* iframe_layout_view = ChildDocument().GetLayoutView();
auto* iframe_transform =
ChildDocument().getElementById("iframeTransform")->GetLayoutObject();
- // Invalidate properties in the iframe and ensure ancestors are marked.
+ // Invalidate properties in the iframe; invalidations will not be propagated
+ // into the embedding document while the iframe is throttle-able.
iframe_transform->SetNeedsPaintPropertyUpdate();
+ iframe_transform->SetShouldCheckForPaintInvalidation();
EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate());
- EXPECT_TRUE(
+ EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(
+ GetDocument().GetLayoutView()->ShouldCheckForPaintInvalidation());
EXPECT_FALSE(transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->ShouldCheckForPaintInvalidation());
EXPECT_FALSE(iframe_layout_view->NeedsPaintPropertyUpdate());
EXPECT_TRUE(iframe_layout_view->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframe_layout_view->ShouldCheckForPaintInvalidation());
EXPECT_TRUE(iframe_transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_transform->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframe_transform->ShouldCheckForPaintInvalidation());
+ // Invalidate properties in the top document.
transform->SetNeedsPaintPropertyUpdate();
+ EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate());
+ EXPECT_TRUE(
+ GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
EXPECT_TRUE(transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate());
- EXPECT_FALSE(GetDocument().View()->ShouldThrottleRenderingForTest());
- EXPECT_TRUE(ChildDocument().View()->ShouldThrottleRenderingForTest());
-
- // A lifecycle update should update all properties except those with
- // actively throttled descendants.
+ // A full lifecycle update with the iframe throttled will clear flags in the
+ // top document, but not in the throttled iframe.
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate());
EXPECT_FALSE(
@@ -440,23 +450,23 @@ TEST_P(PaintPropertyTreeUpdateTest, BuildingStopsAtThrottledFrames) {
EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_layout_view->NeedsPaintPropertyUpdate());
EXPECT_TRUE(iframe_layout_view->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframe_layout_view->ShouldCheckForPaintInvalidation());
EXPECT_TRUE(iframe_transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_transform->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframe_transform->ShouldCheckForPaintInvalidation());
- EXPECT_FALSE(GetDocument().View()->ShouldThrottleRendering());
- EXPECT_FALSE(ChildDocument().View()->ShouldThrottleRendering());
- // Once unthrottled, a lifecycel update should update all properties.
- GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(
+ // Run a force-unthrottled lifecycle update. All flags should be cleared.
+ GetDocument().View()->UpdateLifecycleToPrePaintClean(
DocumentUpdateReason::kTest);
- EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate());
EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
- EXPECT_FALSE(transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_layout_view->NeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_layout_view->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframe_layout_view->ShouldCheckForPaintInvalidation());
EXPECT_FALSE(iframe_transform->NeedsPaintPropertyUpdate());
EXPECT_FALSE(iframe_transform->DescendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframe_transform->ShouldCheckForPaintInvalidation());
}
TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
@@ -1236,45 +1246,6 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGForeignObjectOverflowChange) {
properties->OverflowClip()->UnsnappedClipRect().Rect());
}
-TEST_P(PaintPropertyTreeBuilderTest, OmitOverflowClipOnSelectionChange) {
- SetBodyInnerHTML(R"HTML(
- <div id="target" style="overflow: hidden">
- <img style="width: 50px; height: 50px">
- </div>
- )HTML");
-
- EXPECT_FALSE(PaintPropertiesForElement("target")->OverflowClip());
-
- GetDocument().GetFrame()->Selection().SelectAll();
- UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(PaintPropertiesForElement("target")->OverflowClip());
-
- GetDocument().GetFrame()->Selection().Clear();
- UpdateAllLifecyclePhasesForTest();
- EXPECT_FALSE(PaintPropertiesForElement("target")->OverflowClip());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest, OmitOverflowClipOnCaretChange) {
- SetBodyInnerHTML(R"HTML(
- <div id="target" contentEditable="true" style="overflow: hidden">
- <img style="width: 50px; height: 50px">
- </div>
- )HTML");
-
- GetDocument().GetPage()->GetFocusController().SetActive(true);
- GetDocument().GetPage()->GetFocusController().SetFocused(true);
- auto* target = GetDocument().getElementById("target");
- EXPECT_FALSE(PaintPropertiesForElement("target")->OverflowClip());
-
- target->focus();
- UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(PaintPropertiesForElement("target")->OverflowClip());
-
- target->blur();
- UpdateAllLifecyclePhasesForTest();
- EXPECT_FALSE(PaintPropertiesForElement("target")->OverflowClip());
-}
-
TEST_P(PaintPropertyTreeUpdateTest,
FragmentClipUpdateOnMulticolContainerWidthChange) {
SetBodyInnerHTML(R"HTML(
@@ -1838,4 +1809,34 @@ TEST_P(PaintPropertyTreeUpdateTest, StartSVGAnimation) {
EXPECT_TRUE(properties->Transform()->HasDirectCompositingReasons());
}
+TEST_P(PaintPropertyTreeUpdateTest, ScrollOriginChange) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ ::-webkit-scrollbar {width: 20px; height: 20px}
+ </style>
+ <div id="container" style="width: 100px; height: 100px; overflow: scroll;
+ writing-mode: vertical-rl">
+ <div id="child1" style="width: 100px"></div>
+ <div id="child2" style="width: 0"></div>
+ </div>
+ )HTML");
+
+ auto* container_properties = PaintPropertiesForElement("container");
+ ASSERT_TRUE(container_properties);
+ auto* child1 = GetLayoutObjectByElementId("child1");
+ auto* child2 = GetLayoutObjectByElementId("child2");
+ EXPECT_EQ(FloatSize(-20, 0),
+ container_properties->ScrollTranslation()->Translation2D());
+ EXPECT_EQ(PhysicalOffset(), child1->FirstFragment().PaintOffset());
+ EXPECT_EQ(PhysicalOffset(), child2->FirstFragment().PaintOffset());
+
+ To<Element>(child2->GetNode())
+ ->setAttribute(html_names::kStyleAttr, "width: 100px");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(FloatSize(-120, 0),
+ container_properties->ScrollTranslation()->Translation2D());
+ EXPECT_EQ(PhysicalOffset(100, 0), child1->FirstFragment().PaintOffset());
+ EXPECT_EQ(PhysicalOffset(), child2->FirstFragment().PaintOffset());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
index 2358d3234ed..c77d38a0b23 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -121,7 +121,7 @@ void PaintTiming::MarkFirstImagePaint() {
return;
first_image_paint_ = clock_->NowTicks();
SetFirstContentfulPaint(first_image_paint_);
- RegisterNotifySwapTime(PaintEvent::kFirstImagePaint);
+ RegisterNotifyPresentationTime(PaintEvent::kFirstImagePaint);
}
void PaintTiming::MarkFirstEligibleToPaint() {
@@ -132,10 +132,10 @@ void PaintTiming::MarkFirstEligibleToPaint() {
NotifyPaintTimingChanged();
}
-// We deliberately use |first_paint_| here rather than |first_paint_swap_|,
-// because |first_paint_swap_| is set asynchronously and we need to be able to
-// rely on a synchronous check that SetFirstPaintSwap hasn't been scheduled or
-// run.
+// We deliberately use |first_paint_| here rather than
+// |first_paint_presentation_|, because |first_paint_presentation_| is set
+// asynchronously and we need to be able to rely on a synchronous check that
+// SetFirstPaintPresentation hasn't been scheduled or run.
void PaintTiming::MarkIneligibleToPaint() {
if (first_eligible_to_paint_.is_null() || !first_paint_.is_null())
return;
@@ -154,19 +154,20 @@ void PaintTiming::SetFirstMeaningfulPaintCandidate(base::TimeTicks timestamp) {
}
void PaintTiming::SetFirstMeaningfulPaint(
- base::TimeTicks swap_stamp,
+ base::TimeTicks presentation_time,
FirstMeaningfulPaintDetector::HadUserInput had_input) {
- DCHECK(first_meaningful_paint_swap_.is_null());
- DCHECK(!swap_stamp.is_null());
+ DCHECK(first_meaningful_paint_presentation_.is_null());
+ DCHECK(!presentation_time.is_null());
- TRACE_EVENT_MARK_WITH_TIMESTAMP2(
- "loading,rail,devtools.timeline", "firstMeaningfulPaint", swap_stamp,
- "frame", ToTraceValue(GetFrame()), "afterUserInput", had_input);
+ TRACE_EVENT_MARK_WITH_TIMESTAMP2("loading,rail,devtools.timeline",
+ "firstMeaningfulPaint", presentation_time,
+ "frame", ToTraceValue(GetFrame()),
+ "afterUserInput", had_input);
// Notify FMP for UMA only if there's no user input before FMP, so that layout
// changes caused by user interactions wouldn't be considered as FMP.
if (had_input == FirstMeaningfulPaintDetector::kNoUserInput) {
- first_meaningful_paint_swap_ = swap_stamp;
+ first_meaningful_paint_presentation_ = presentation_time;
NotifyPaintTimingChanged();
}
}
@@ -184,13 +185,13 @@ void PaintTiming::NotifyPaint(bool is_first_paint,
}
void PaintTiming::OnPortalActivate() {
- last_portal_activated_swap_ = base::TimeTicks();
- RegisterNotifySwapTime(PaintEvent::kPortalActivatedPaint);
+ last_portal_activated_presentation_ = base::TimeTicks();
+ RegisterNotifyPresentationTime(PaintEvent::kPortalActivatedPaint);
}
void PaintTiming::SetPortalActivatedPaint(base::TimeTicks stamp) {
- DCHECK(last_portal_activated_swap_.is_null());
- last_portal_activated_swap_ = stamp;
+ DCHECK(last_portal_activated_presentation_.is_null());
+ last_portal_activated_presentation_ = stamp;
NotifyPaintTimingChanged();
}
@@ -230,7 +231,7 @@ void PaintTiming::SetFirstPaint(base::TimeTicks stamp) {
}
first_paint_ = stamp;
- RegisterNotifySwapTime(PaintEvent::kFirstPaint);
+ RegisterNotifyPresentationTime(PaintEvent::kFirstPaint);
}
void PaintTiming::SetFirstContentfulPaint(base::TimeTicks stamp) {
@@ -238,7 +239,7 @@ void PaintTiming::SetFirstContentfulPaint(base::TimeTicks stamp) {
return;
SetFirstPaint(stamp);
first_contentful_paint_ = stamp;
- RegisterNotifySwapTime(PaintEvent::kFirstContentfulPaint);
+ RegisterNotifyPresentationTime(PaintEvent::kFirstContentfulPaint);
// Restart commits that may have been deferred.
LocalFrame* frame = GetFrame();
@@ -253,55 +254,57 @@ void PaintTiming::SetFirstContentfulPaint(base::TimeTicks stamp) {
frame->GetFrameScheduler()->OnFirstContentfulPaint();
}
-void PaintTiming::RegisterNotifySwapTime(PaintEvent event) {
- RegisterNotifySwapTime(
- CrossThreadBindOnce(&PaintTiming::ReportSwapTime,
+void PaintTiming::RegisterNotifyPresentationTime(PaintEvent event) {
+ RegisterNotifyPresentationTime(
+ CrossThreadBindOnce(&PaintTiming::ReportPresentationTime,
WrapCrossThreadWeakPersistent(this), event));
}
-void PaintTiming::RegisterNotifyFirstPaintAfterBackForwardCacheRestoreSwapTime(
- size_t index) {
- RegisterNotifySwapTime(CrossThreadBindOnce(
- &PaintTiming::ReportFirstPaintAfterBackForwardCacheRestoreSwapTime,
+void PaintTiming::
+ RegisterNotifyFirstPaintAfterBackForwardCacheRestorePresentationTime(
+ size_t index) {
+ RegisterNotifyPresentationTime(CrossThreadBindOnce(
+ &PaintTiming::
+ ReportFirstPaintAfterBackForwardCacheRestorePresentationTime,
WrapCrossThreadWeakPersistent(this), index));
}
-void PaintTiming::RegisterNotifySwapTime(ReportTimeCallback callback) {
- // ReportSwapTime will queue a swap-promise, the callback is called when the
- // compositor submission of the current render frame completes or fails to
- // happen.
+void PaintTiming::RegisterNotifyPresentationTime(ReportTimeCallback callback) {
+ // ReportPresentationTime will queue a presentation-promise, the callback is
+ // called when the compositor submission of the current render frame completes
+ // or fails to happen.
if (!GetFrame() || !GetFrame()->GetPage())
return;
- GetFrame()->GetPage()->GetChromeClient().NotifySwapTime(*GetFrame(),
- std::move(callback));
+ GetFrame()->GetPage()->GetChromeClient().NotifyPresentationTime(
+ *GetFrame(), std::move(callback));
}
-void PaintTiming::ReportSwapTime(PaintEvent event,
- WebSwapResult result,
- base::TimeTicks timestamp) {
+void PaintTiming::ReportPresentationTime(PaintEvent event,
+ WebSwapResult result,
+ base::TimeTicks timestamp) {
DCHECK(IsMainThread());
- // If the swap fails for any reason, we use the timestamp when the SwapPromise
- // was broken. |result| == WebSwapResult::kDidNotSwapSwapFails
- // usually means the compositor decided not swap because there was no actual
- // damage, which can happen when what's being painted isn't visible. In this
- // case, the timestamp will be consistent with the case where the swap
- // succeeds, as they both capture the time up to swap. In other failure cases
- // (aborts during commit), this timestamp is an improvement over the blink
- // paint time, but does not capture some time we're interested in, e.g. image
- // decoding.
+ // If the presentation fails for any reason, we use the timestamp when the
+ // PresentationPromise was broken. |result| ==
+ // WebSwapResult::kDidNotSwapSwapFails usually means the compositor decided
+ // not to swap because there was no actual damage, which can happen when
+ // what's being painted isn't visible. In this case, the timestamp will be
+ // consistent with the case where the presentation succeeds, as they both
+ // capture the time up to presentation. In other failure cases (aborts during
+ // commit), this timestamp is an improvement over the blink paint time, but
+ // does not capture some time we're interested in, e.g. image decoding.
//
// TODO(crbug.com/738235): Consider not reporting any timestamp when failing
// for reasons other than kDidNotSwapSwapFails.
ReportSwapResultHistogram(result);
switch (event) {
case PaintEvent::kFirstPaint:
- SetFirstPaintSwap(timestamp);
+ SetFirstPaintPresentation(timestamp);
return;
case PaintEvent::kFirstContentfulPaint:
- SetFirstContentfulPaintSwap(timestamp);
+ SetFirstContentfulPaintPresentation(timestamp);
return;
case PaintEvent::kFirstImagePaint:
- SetFirstImagePaintSwap(timestamp);
+ SetFirstImagePaintPresentation(timestamp);
return;
case PaintEvent::kPortalActivatedPaint:
SetPortalActivatedPaint(timestamp);
@@ -311,44 +314,50 @@ void PaintTiming::ReportSwapTime(PaintEvent event,
}
}
-void PaintTiming::ReportFirstPaintAfterBackForwardCacheRestoreSwapTime(
+void PaintTiming::ReportFirstPaintAfterBackForwardCacheRestorePresentationTime(
size_t index,
WebSwapResult result,
base::TimeTicks timestamp) {
DCHECK(IsMainThread());
ReportSwapResultHistogram(result);
- SetFirstPaintAfterBackForwardCacheRestoreSwap(timestamp, index);
+ SetFirstPaintAfterBackForwardCacheRestorePresentation(timestamp, index);
}
-void PaintTiming::SetFirstPaintSwap(base::TimeTicks stamp) {
- DCHECK(first_paint_swap_.is_null());
- first_paint_swap_ = stamp;
+void PaintTiming::SetFirstPaintPresentation(base::TimeTicks stamp) {
+ DCHECK(first_paint_presentation_.is_null());
+ first_paint_presentation_ = stamp;
probe::PaintTiming(GetSupplementable(), "firstPaint",
- first_paint_swap_.since_origin().InSecondsF());
+ first_paint_presentation_.since_origin().InSecondsF());
WindowPerformance* performance = GetPerformanceInstance(GetFrame());
if (performance)
- performance->AddFirstPaintTiming(first_paint_swap_);
+ performance->AddFirstPaintTiming(first_paint_presentation_);
NotifyPaintTimingChanged();
}
-void PaintTiming::SetFirstContentfulPaintSwap(base::TimeTicks stamp) {
- DCHECK(first_contentful_paint_swap_.is_null());
- TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("loading", "FirstContentfulPaint",
+void PaintTiming::SetFirstContentfulPaintPresentation(base::TimeTicks stamp) {
+ DCHECK(first_contentful_paint_presentation_.is_null());
+ TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("benchmark,loading",
+ "GlobalFirstContentfulPaint",
TRACE_EVENT_SCOPE_GLOBAL, stamp);
- first_contentful_paint_swap_ = stamp;
- probe::PaintTiming(GetSupplementable(), "firstContentfulPaint",
- first_contentful_paint_swap_.since_origin().InSecondsF());
+ first_contentful_paint_presentation_ = stamp;
+ probe::PaintTiming(
+ GetSupplementable(), "firstContentfulPaint",
+ first_contentful_paint_presentation_.since_origin().InSecondsF());
WindowPerformance* performance = GetPerformanceInstance(GetFrame());
- if (performance)
- performance->AddFirstContentfulPaintTiming(first_contentful_paint_swap_);
+ if (performance) {
+ performance->AddFirstContentfulPaintTiming(
+ first_contentful_paint_presentation_);
+ }
if (GetFrame())
GetFrame()->Loader().Progress().DidFirstContentfulPaint();
NotifyPaintTimingChanged();
- fmp_detector_->NotifyFirstContentfulPaint(first_contentful_paint_swap_);
+ fmp_detector_->NotifyFirstContentfulPaint(
+ first_contentful_paint_presentation_);
InteractiveDetector* interactive_detector =
InteractiveDetector::From(*GetSupplementable());
if (interactive_detector) {
- interactive_detector->OnFirstContentfulPaint(first_contentful_paint_swap_);
+ interactive_detector->OnFirstContentfulPaint(
+ first_contentful_paint_presentation_);
}
auto* coordinator = GetSupplementable()->GetResourceCoordinator();
if (coordinator && GetFrame() && GetFrame()->IsMainFrame()) {
@@ -358,21 +367,24 @@ void PaintTiming::SetFirstContentfulPaintSwap(base::TimeTicks stamp) {
}
}
-void PaintTiming::SetFirstImagePaintSwap(base::TimeTicks stamp) {
- DCHECK(first_image_paint_swap_.is_null());
- first_image_paint_swap_ = stamp;
- probe::PaintTiming(GetSupplementable(), "firstImagePaint",
- first_image_paint_swap_.since_origin().InSecondsF());
+void PaintTiming::SetFirstImagePaintPresentation(base::TimeTicks stamp) {
+ DCHECK(first_image_paint_presentation_.is_null());
+ first_image_paint_presentation_ = stamp;
+ probe::PaintTiming(
+ GetSupplementable(), "firstImagePaint",
+ first_image_paint_presentation_.since_origin().InSecondsF());
NotifyPaintTimingChanged();
}
-void PaintTiming::SetFirstPaintAfterBackForwardCacheRestoreSwap(
+void PaintTiming::SetFirstPaintAfterBackForwardCacheRestorePresentation(
base::TimeTicks stamp,
size_t index) {
// The elements are allocated when the page is restored from the cache.
- DCHECK_GE(first_paints_after_back_forward_cache_restore_swap_.size(), index);
- DCHECK(first_paints_after_back_forward_cache_restore_swap_[index].is_null());
- first_paints_after_back_forward_cache_restore_swap_[index] = stamp;
+ DCHECK_GE(first_paints_after_back_forward_cache_restore_presentation_.size(),
+ index);
+ DCHECK(first_paints_after_back_forward_cache_restore_presentation_[index]
+ .is_null());
+ first_paints_after_back_forward_cache_restore_presentation_[index] = stamp;
NotifyPaintTimingChanged();
}
@@ -399,13 +411,14 @@ void PaintTiming::ReportSwapResultHistogram(WebSwapResult result) {
void PaintTiming::OnRestoredFromBackForwardCache() {
// Allocate the last element with 0, which indicates that the first paint
// after this navigation doesn't happen yet.
- size_t index = first_paints_after_back_forward_cache_restore_swap_.size();
+ size_t index =
+ first_paints_after_back_forward_cache_restore_presentation_.size();
DCHECK_EQ(index,
request_animation_frames_after_back_forward_cache_restore_.size());
- first_paints_after_back_forward_cache_restore_swap_.push_back(
+ first_paints_after_back_forward_cache_restore_presentation_.push_back(
base::TimeTicks());
- RegisterNotifyFirstPaintAfterBackForwardCacheRestoreSwapTime(index);
+ RegisterNotifyFirstPaintAfterBackForwardCacheRestorePresentationTime(index);
request_animation_frames_after_back_forward_cache_restore_.push_back(
RequestAnimationFrameTimesAfterBackForwardCacheRestore{});
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.h b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
index 747b52a9105..7f03844a609 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
@@ -46,10 +46,10 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
static PaintTiming& From(Document&);
- // Mark*() methods record the time for the given paint event and queue a swap
- // promise to record the |first_*_swap_| timestamp. These methods do nothing
- // (early return) if a time has already been recorded for the given paint
- // event.
+ // Mark*() methods record the time for the given paint event and queue a
+ // presentation promise to record the |first_*_presentation_| timestamp. These
+ // methods do nothing (early return) if a time has already been recorded for
+ // the given paint event.
void MarkFirstPaint();
// MarkFirstImagePaint, and MarkFirstContentfulPaint
@@ -71,7 +71,7 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
void SetFirstMeaningfulPaintCandidate(base::TimeTicks timestamp);
void SetFirstMeaningfulPaint(
- base::TimeTicks swap_stamp,
+ base::TimeTicks presentation_time,
FirstMeaningfulPaintDetector::HadUserInput had_input);
void NotifyPaint(bool is_first_paint, bool text_painted, bool image_painted);
@@ -86,13 +86,13 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
// FirstPaint returns the first time that anything was painted for the
// current document.
- base::TimeTicks FirstPaint() const { return first_paint_swap_; }
+ base::TimeTicks FirstPaint() const { return first_paint_presentation_; }
// Times when the first paint happens after the page is restored from the
// back-forward cache. If the element value is zero time tick, the first paint
// event did not happen for that navigation.
WTF::Vector<base::TimeTicks> FirstPaintsAfterBackForwardCacheRestore() const {
- return first_paints_after_back_forward_cache_restore_swap_;
+ return first_paints_after_back_forward_cache_restore_presentation_;
}
WTF::Vector<RequestAnimationFrameTimesAfterBackForwardCacheRestore>
@@ -104,11 +104,13 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
// painted. For instance, the first time that text or image content was
// painted.
base::TimeTicks FirstContentfulPaint() const {
- return first_contentful_paint_swap_;
+ return first_contentful_paint_presentation_;
}
// FirstImagePaint returns the first time that image content was painted.
- base::TimeTicks FirstImagePaint() const { return first_image_paint_swap_; }
+ base::TimeTicks FirstImagePaint() const {
+ return first_image_paint_presentation_;
+ }
// FirstEligibleToPaint returns the first time that the frame is not
// throttled and is eligible to paint. A null value indicates throttling.
@@ -119,12 +121,12 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
// FirstMeaningfulPaint returns the first time that page's primary content
// was painted.
base::TimeTicks FirstMeaningfulPaint() const {
- return first_meaningful_paint_swap_;
+ return first_meaningful_paint_presentation_;
}
// The time that the first paint happened after a portal activation.
base::TimeTicks LastPortalActivatedPaint() const {
- return last_portal_activated_swap_;
+ return last_portal_activated_presentation_;
}
// FirstMeaningfulPaintCandidate indicates the first time we considered a
@@ -139,9 +141,11 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
return *fmp_detector_;
}
- void RegisterNotifySwapTime(ReportTimeCallback);
- void ReportSwapTime(PaintEvent, WebSwapResult, base::TimeTicks timestamp);
- void ReportFirstPaintAfterBackForwardCacheRestoreSwapTime(
+ void RegisterNotifyPresentationTime(ReportTimeCallback);
+ void ReportPresentationTime(PaintEvent,
+ WebSwapResult,
+ base::TimeTicks timestamp);
+ void ReportFirstPaintAfterBackForwardCacheRestorePresentationTime(
size_t index,
WebSwapResult,
base::TimeTicks timestamp);
@@ -162,36 +166,37 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
void NotifyPaintTimingChanged();
// Set*() set the timing for the given paint event to the given timestamp if
- // the value is currently zero, and queue a swap promise to record the
- // |first_*_swap_| timestamp. These methods can be invoked from other Mark*()
- // or Set*() methods to make sure that first paint is marked as part of
- // marking first contentful paint, or that first contentful paint is marked as
- // part of marking first text/image paint, for example.
+ // the value is currently zero, and queue a presentation promise to record the
+ // |first_*_presentation_| timestamp. These methods can be invoked from other
+ // Mark*() or Set*() methods to make sure that first paint is marked as part
+ // of marking first contentful paint, or that first contentful paint is marked
+ // as part of marking first text/image paint, for example.
void SetFirstPaint(base::TimeTicks stamp);
// setFirstContentfulPaint will also set first paint time if first paint
// time has not yet been recorded.
void SetFirstContentfulPaint(base::TimeTicks stamp);
- // Set*Swap() are called when the SwapPromise is fulfilled and the swap
- // timestamp is available. These methods will record trace events, update Web
- // Perf API (FP and FCP only), and notify that paint timing has changed, which
- // triggers UMAs and UKMS.
- // |stamp| is the swap timestamp used for tracing, UMA, UKM, and Web Perf API.
- void SetFirstPaintSwap(base::TimeTicks stamp);
- void SetFirstContentfulPaintSwap(base::TimeTicks stamp);
- void SetFirstImagePaintSwap(base::TimeTicks stamp);
+ // Set*Presentation() are called when the presentation promise is fulfilled
+ // and the presentation timestamp is available. These methods will record
+ // trace events, update Web Perf API (FP and FCP only), and notify that paint
+ // timing has changed, which triggers UMAs and UKMS. |stamp| is the
+ // presentation timestamp used for tracing, UMA, UKM, and Web Perf API.
+ void SetFirstPaintPresentation(base::TimeTicks stamp);
+ void SetFirstContentfulPaintPresentation(base::TimeTicks stamp);
+ void SetFirstImagePaintPresentation(base::TimeTicks stamp);
// When quickly navigating back and forward between the pages in the cache
// paint events might race with navigations. Pass explicit bfcache restore
// index to avoid confusing the data from different navigations.
- void SetFirstPaintAfterBackForwardCacheRestoreSwap(base::TimeTicks stamp,
- size_t index);
+ void SetFirstPaintAfterBackForwardCacheRestorePresentation(
+ base::TimeTicks stamp,
+ size_t index);
void SetRequestAnimationFrameAfterBackForwardCacheRestore(size_t index,
size_t count);
- void RegisterNotifySwapTime(PaintEvent);
- void RegisterNotifyFirstPaintAfterBackForwardCacheRestoreSwapTime(
+ void RegisterNotifyPresentationTime(PaintEvent);
+ void RegisterNotifyFirstPaintAfterBackForwardCacheRestorePresentationTime(
size_t index);
base::TimeTicks FirstPaintRendered() const { return first_paint_; }
@@ -200,24 +205,24 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
return first_contentful_paint_;
}
- // TODO(crbug/738235): Non first_*_swap_ variables are only being tracked to
- // compute deltas for reporting histograms and should be removed once we
- // confirm the deltas and discrepancies look reasonable.
+ // TODO(crbug/738235): Non first_*_presentation_ variables are only being
+ // tracked to compute deltas for reporting histograms and should be removed
+ // once we confirm the deltas and discrepancies look reasonable.
base::TimeTicks first_paint_;
- base::TimeTicks first_paint_swap_;
+ base::TimeTicks first_paint_presentation_;
WTF::Vector<base::TimeTicks>
- first_paints_after_back_forward_cache_restore_swap_;
+ first_paints_after_back_forward_cache_restore_presentation_;
WTF::Vector<RequestAnimationFrameTimesAfterBackForwardCacheRestore>
request_animation_frames_after_back_forward_cache_restore_;
base::TimeTicks first_image_paint_;
- base::TimeTicks first_image_paint_swap_;
+ base::TimeTicks first_image_paint_presentation_;
base::TimeTicks first_contentful_paint_;
- base::TimeTicks first_contentful_paint_swap_;
- base::TimeTicks first_meaningful_paint_swap_;
+ base::TimeTicks first_contentful_paint_presentation_;
+ base::TimeTicks first_meaningful_paint_presentation_;
base::TimeTicks first_meaningful_paint_candidate_;
base::TimeTicks first_eligible_to_paint_;
- base::TimeTicks last_portal_activated_swap_;
+ base::TimeTicks last_portal_activated_presentation_;
Member<FirstMeaningfulPaintDetector> fmp_detector_;
@@ -227,45 +232,8 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
const base::TickClock* clock_;
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, NoFirstPaint);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, OneLayout);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- TwoLayoutsSignificantSecond);
FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
TwoLayoutsSignificantFirst);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- FirstMeaningfulPaintCandidate);
- FRIEND_TEST_ALL_PREFIXES(
- FirstMeaningfulPaintDetectorTest,
- OnlyOneFirstMeaningfulPaintCandidateBeforeNetworkStable);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- NetworkStableBeforeFirstContentfulPaint);
- FRIEND_TEST_ALL_PREFIXES(
- FirstMeaningfulPaintDetectorTest,
- FirstMeaningfulPaintShouldNotBeBeforeFirstContentfulPaint);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- Network2QuietThen0Quiet);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- Network0QuietThen2Quiet);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- Network0QuietTimer);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- Network2QuietTimer);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- FirstMeaningfulPaintAfterUserInteraction);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- UserInteractionBeforeFirstPaint);
- FRIEND_TEST_ALL_PREFIXES(
- FirstMeaningfulPaintDetectorTest,
- WaitForSingleOutstandingSwapPromiseAfterNetworkStable);
- FRIEND_TEST_ALL_PREFIXES(
- FirstMeaningfulPaintDetectorTest,
- WaitForMultipleOutstandingSwapPromisesAfterNetworkStable);
- FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
- WaitForFirstContentfulPaintSwapAfterNetworkStable);
- FRIEND_TEST_ALL_PREFIXES(
- FirstMeaningfulPaintDetectorTest,
- ProvisionalTimestampChangesAfterNetworkQuietWithOutstandingSwapPromise);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index a80fd7422b0..7842dfc53a8 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -104,16 +104,13 @@ void PaintTimingDetector::NotifyPaintFinished() {
// static
void PaintTimingDetector::NotifyBackgroundImagePaint(
- const Node* node,
- const Image* image,
- const StyleFetchedImage* style_image,
+ const Node& node,
+ const Image& image,
+ const StyleFetchedImage& style_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border) {
- DCHECK(image);
- DCHECK(style_image->CachedImage());
- if (!node)
- return;
- LayoutObject* object = node->GetLayoutObject();
+ DCHECK(style_image.CachedImage());
+ LayoutObject* object = node.GetLayoutObject();
if (!object)
return;
LocalFrameView* frame_view = object->GetFrameView();
@@ -122,18 +119,18 @@ void PaintTimingDetector::NotifyBackgroundImagePaint(
PaintTimingDetector& detector = frame_view->GetPaintTimingDetector();
if (!detector.GetImagePaintTimingDetector())
return;
- if (!IsBackgroundImageContentful(*object, *image))
+ if (!IsBackgroundImageContentful(*object, image))
return;
detector.GetImagePaintTimingDetector()->RecordImage(
- *object, image->Size(), *style_image->CachedImage(),
- current_paint_chunk_properties, style_image, image_border);
+ *object, image.Size(), *style_image.CachedImage(),
+ current_paint_chunk_properties, &style_image, image_border);
}
// static
void PaintTimingDetector::NotifyImagePaint(
const LayoutObject& object,
const IntSize& intrinsic_size,
- const ImageResourceContent* cached_image,
+ const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border) {
if (IgnorePaintTimingScope::ShouldIgnore())
@@ -141,13 +138,11 @@ void PaintTimingDetector::NotifyImagePaint(
LocalFrameView* frame_view = object.GetFrameView();
if (!frame_view)
return;
- if (!cached_image)
- return;
PaintTimingDetector& detector = frame_view->GetPaintTimingDetector();
if (!detector.GetImagePaintTimingDetector())
return;
detector.GetImagePaintTimingDetector()->RecordImage(
- object, intrinsic_size, *cached_image, current_paint_chunk_properties,
+ object, intrinsic_size, cached_image, current_paint_chunk_properties,
nullptr, image_border);
}
@@ -264,6 +259,7 @@ bool PaintTimingDetector::NotifyIfChangedLargestImagePaint(
std::min(image_paint_time, removed_image_paint_time);
}
}
+ UpdateLargestContentfulPaintTime();
DidChangePerformanceTiming();
return true;
}
@@ -282,10 +278,23 @@ bool PaintTimingDetector::NotifyIfChangedLargestTextPaint(
largest_text_paint_time_ = text_paint_time;
largest_text_paint_size_ = text_paint_size;
}
+ UpdateLargestContentfulPaintTime();
DidChangePerformanceTiming();
return true;
}
+void PaintTimingDetector::UpdateLargestContentfulPaintTime() {
+ if (largest_text_paint_size_ > largest_image_paint_size_) {
+ largest_contentful_paint_time_ = largest_text_paint_time_;
+ } else if (largest_text_paint_size_ < largest_image_paint_size_) {
+ largest_contentful_paint_time_ = largest_image_paint_time_;
+ } else {
+ // Size is the same, take the shorter time.
+ largest_contentful_paint_time_ =
+ std::min(largest_text_paint_time_, largest_image_paint_time_);
+ }
+}
+
bool PaintTimingDetector::HasLargestImagePaintChanged(
base::TimeTicks largest_image_paint_time,
uint64_t largest_image_paint_size) const {
@@ -431,7 +440,6 @@ void PaintTimingDetector::Trace(Visitor* visitor) const {
visitor->Trace(frame_view_);
visitor->Trace(largest_contentful_paint_calculator_);
visitor->Trace(callback_manager_);
- visitor->Trace(visualizer_);
}
void PaintTimingCallbackManagerImpl::
@@ -447,10 +455,10 @@ void PaintTimingCallbackManagerImpl::
frame_callbacks_ =
std::make_unique<PaintTimingCallbackManager::CallbackQueue>();
- // |ReportPaintTime| on |layerTreeView| will queue a swap-promise, the
- // callback is called when the swap for current render frame completes or
- // fails to happen.
- frame.GetPage()->GetChromeClient().NotifySwapTime(
+ // |ReportPaintTime| on |layerTreeView| will queue a presentation-promise, the
+ // callback is called when the presentation for current render frame completes
+ // or fails to happen.
+ frame.GetPage()->GetChromeClient().NotifyPresentationTime(
frame, std::move(combined_callback));
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
index 701deaf780b..6735413751d 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -119,15 +119,15 @@ class CORE_EXPORT PaintTimingDetector
PaintTimingDetector(LocalFrameView*);
static void NotifyBackgroundImagePaint(
- const Node*,
- const Image*,
- const StyleFetchedImage*,
+ const Node&,
+ const Image&,
+ const StyleFetchedImage&,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border);
static void NotifyImagePaint(
const LayoutObject&,
const IntSize& intrinsic_size,
- const ImageResourceContent* cached_image,
+ const ImageResourceContent& cached_image,
const PropertyTreeStateOrAlias& current_paint_chunk_properties,
const IntRect& image_border);
inline static void NotifyTextPaint(const IntRect& text_visual_rect);
@@ -182,6 +182,11 @@ class CORE_EXPORT PaintTimingDetector
uint64_t LargestImagePaintSize() const { return largest_image_paint_size_; }
base::TimeTicks LargestTextPaint() const { return largest_text_paint_time_; }
uint64_t LargestTextPaintSize() const { return largest_text_paint_size_; }
+
+ base::TimeTicks LargestContentfulPaint() const {
+ return largest_contentful_paint_time_;
+ }
+
// Experimental counterparts of the above methods. Currently these values are
// computed by looking at the largest content seen so far, but excluding
// content that is removed.
@@ -216,6 +221,7 @@ class CORE_EXPORT PaintTimingDetector
void OnInputOrScroll();
bool HasLargestImagePaintChanged(base::TimeTicks, uint64_t size) const;
bool HasLargestTextPaintChanged(base::TimeTicks, uint64_t size) const;
+ void UpdateLargestContentfulPaintTime();
Member<LocalFrameView> frame_view_;
// This member lives forever because it is also used for Text Element Timing.
Member<TextPaintTimingDetector> text_paint_timing_detector_;
@@ -240,6 +246,7 @@ class CORE_EXPORT PaintTimingDetector
uint64_t largest_image_paint_size_ = 0;
base::TimeTicks largest_text_paint_time_;
uint64_t largest_text_paint_size_ = 0;
+ base::TimeTicks largest_contentful_paint_time_;
base::TimeTicks experimental_largest_image_paint_time_;
uint64_t experimental_largest_image_paint_size_ = 0;
@@ -318,6 +325,27 @@ inline void PaintTimingDetector::NotifyTextPaint(
ScopedPaintTimingDetectorBlockPaintHook::AggregateTextPaint(text_visual_rect);
}
+class LCPRectInfo {
+ public:
+ LCPRectInfo(IntRect frame_rect_info, IntRect root_rect_info)
+ : frame_rect_info_(frame_rect_info), root_rect_info_(root_rect_info) {}
+
+ void OutputToTraceValue(TracedValue& value) {
+ value.SetInteger("frame_x", frame_rect_info_.X());
+ value.SetInteger("frame_y", frame_rect_info_.Y());
+ value.SetInteger("frame_width", frame_rect_info_.Width());
+ value.SetInteger("frame_height", frame_rect_info_.Height());
+ value.SetInteger("root_x", root_rect_info_.X());
+ value.SetInteger("root_y", root_rect_info_.Y());
+ value.SetInteger("root_width", root_rect_info_.Width());
+ value.SetInteger("root_height", root_rect_info_.Height());
+ }
+
+ private:
+ IntRect frame_rect_info_;
+ IntRect root_rect_info_;
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_test_helper.h b/chromium/third_party/blink/renderer/core/paint/paint_timing_test_helper.h
index f8d4365583d..2cf18401528 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_test_helper.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_test_helper.h
@@ -5,8 +5,8 @@
namespace blink {
// |MockPaintTimingCallbackManager| is used to mock
-// |ChromeClient::NotifySwapTime()|'s swap-time queueing and invoking for
-// unit-tests. Find more details in |PaintTimingCallbackManager|.
+// |ChromeClient::NotifyPresentationTime()|'s presentation-time queueing and
+// invoking for unit-tests. Find more details in |PaintTimingCallbackManager|.
class MockPaintTimingCallbackManager final
: public GarbageCollected<MockPaintTimingCallbackManager>,
public PaintTimingCallbackManager {
@@ -16,9 +16,9 @@ class MockPaintTimingCallbackManager final
PaintTimingCallbackManager::LocalThreadCallback callback) override {
callback_queue_.push(std::move(callback));
}
- void InvokeSwapTimeCallback(base::TimeTicks swap_time) {
+ void InvokePresentationTimeCallback(base::TimeTicks presentation_time) {
DCHECK_GT(callback_queue_.size(), 0UL);
- std::move(callback_queue_.front()).Run(swap_time);
+ std::move(callback_queue_.front()).Run(presentation_time);
callback_queue_.pop();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index 9ecfc821a4e..d6de62cbb86 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -24,11 +24,12 @@
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+#include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
@@ -179,8 +180,8 @@ void PrePaintTreeWalk::WalkTree(LocalFrameView& root_frame_view) {
return;
}
- DCHECK(root_frame_view.GetFrame().GetDocument()->Lifecycle().GetState() ==
- DocumentLifecycle::kInPrePaint);
+ DCHECK_EQ(root_frame_view.GetFrame().GetDocument()->Lifecycle().GetState(),
+ DocumentLifecycle::kInPrePaint);
// Reserve 50 elements for a really deep DOM. If the nesting is deeper than
// this, then the vector will reallocate, but it shouldn't be a big deal. This
@@ -212,6 +213,11 @@ void PrePaintTreeWalk::WalkTree(LocalFrameView& root_frame_view) {
paint_invalidator_.ProcessPendingDelayedPaintInvalidations();
context_storage_.pop_back();
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ if (auto* layout_view = root_frame_view.GetLayoutView())
+ CullRectUpdater(*layout_view->Layer()).Update();
+ }
+
#if DCHECK_IS_ON()
if (needs_tree_builder_context_update) {
if (VLOG_IS_ON(2) && root_frame_view.GetLayoutView()) {
@@ -233,11 +239,6 @@ void PrePaintTreeWalk::WalkTree(LocalFrameView& root_frame_view) {
}
void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
- if (frame_view.ShouldThrottleRendering()) {
- // Skip the throttled frame. Will update it when it becomes unthrottled.
- return;
- }
-
// We need to be careful not to have a reference to the parent context, since
// this reference will be to the context_storage_ memory which may be
// reallocated during this function call.
@@ -250,6 +251,24 @@ void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
bool needs_tree_builder_context_update =
NeedsTreeBuilderContextUpdate(frame_view, parent_context());
+ if (frame_view.ShouldThrottleRendering()) {
+ // Skip the throttled frame, and set dirty bits that will be applied when it
+ // becomes unthrottled.
+ if (LayoutView* layout_view = frame_view.GetLayoutView()) {
+ if (needs_tree_builder_context_update) {
+ layout_view->AddSubtreePaintPropertyUpdateReason(
+ SubtreePaintPropertyUpdateReason::kPreviouslySkipped);
+ }
+ if (parent_context().paint_invalidator_context.NeedsSubtreeWalk())
+ layout_view->SetSubtreeShouldDoFullPaintInvalidation();
+ if (parent_context().effective_allowed_touch_action_changed)
+ layout_view->MarkEffectiveAllowedTouchActionChanged();
+ if (parent_context().blocking_wheel_event_handler_changed)
+ layout_view->MarkBlockingWheelEventHandlerChanged();
+ }
+ return;
+ }
+
// Note that because we're emplacing an object constructed from
// parent_context() (which is a reference to the vector itself), it's
// important to first ensure that there's sufficient capacity in the vector.
@@ -282,14 +301,17 @@ void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
}
#endif
- Walk(*view, /* iterator */ nullptr,
- base::FeatureList::IsEnabled(::features::kWheelEventRegions));
+ is_wheel_event_regions_enabled_ =
+ base::FeatureList::IsEnabled(::features::kWheelEventRegions);
+
+ Walk(*view, /* iterator */ nullptr);
#if DCHECK_IS_ON()
view->AssertSubtreeClearedPaintInvalidationFlags();
#endif
}
frame_view.GetLayoutShiftTracker().NotifyPrePaintFinished();
+ frame_view.GetMobileFriendlinessChecker().NotifyPrePaintFinished();
context_storage_.pop_back();
}
@@ -419,15 +441,6 @@ void PrePaintTreeWalk::UpdateAuxiliaryObjectProperties(
paint_layer->UpdateAncestorScrollContainerLayer(
context.ancestor_scroll_container_paint_layer);
- if (object.StyleRef().HasStickyConstrainedPosition()) {
- paint_layer->GetLayoutObject().UpdateStickyPositionConstraints();
-
- // Sticky position constraints and ancestor overflow scroller affect the
- // sticky layer position, so we need to update it again here.
- // TODO(flackr): This should be refactored in the future to be clearer (i.e.
- // update layer position and ancestor inputs updates in the same walk).
- paint_layer->UpdateLayerPosition();
- }
if (object.IsScrollContainer())
context.ancestor_scroll_container_paint_layer = paint_layer;
}
@@ -442,7 +455,7 @@ bool PrePaintTreeWalk::NeedsTreeBuilderContextUpdate(
return frame_view.GetLayoutView() &&
(ObjectRequiresTreeBuilderContext(*frame_view.GetLayoutView()) ||
- ContextRequiresTreeBuilderContext(context));
+ ContextRequiresChildTreeBuilderContext(context));
}
bool PrePaintTreeWalk::ObjectRequiresPrePaint(const LayoutObject& object) {
@@ -454,7 +467,7 @@ bool PrePaintTreeWalk::ObjectRequiresPrePaint(const LayoutObject& object) {
;
}
-bool PrePaintTreeWalk::ContextRequiresPrePaint(
+bool PrePaintTreeWalk::ContextRequiresChildPrePaint(
const PrePaintTreeWalkContext& context) {
return context.paint_invalidator_context.NeedsSubtreeWalk() ||
context.effective_allowed_touch_action_changed ||
@@ -470,10 +483,16 @@ bool PrePaintTreeWalk::ObjectRequiresTreeBuilderContext(
object.DescendantShouldCheckGeometryForPaintInvalidation()));
}
-bool PrePaintTreeWalk::ContextRequiresTreeBuilderContext(
+bool PrePaintTreeWalk::ContextRequiresChildTreeBuilderContext(
const PrePaintTreeWalkContext& context) {
- return context.tree_builder_context &&
- context.tree_builder_context->force_subtree_update_reasons;
+ if (!context.NeedsTreeBuilderContext()) {
+ DCHECK(!context.tree_builder_context->force_subtree_update_reasons);
+ DCHECK(!context.paint_invalidator_context.NeedsSubtreeWalk());
+ return false;
+ }
+ return context.tree_builder_context->force_subtree_update_reasons ||
+ // PaintInvalidator forced subtree walk implies geometry update.
+ context.paint_invalidator_context.NeedsSubtreeWalk();
}
#if DCHECK_IS_ON()
@@ -482,7 +501,7 @@ void PrePaintTreeWalk::CheckTreeBuilderContextState(
const PrePaintTreeWalkContext& parent_context) {
if (parent_context.tree_builder_context ||
(!ObjectRequiresTreeBuilderContext(object) &&
- !ContextRequiresTreeBuilderContext(parent_context))) {
+ !ContextRequiresChildTreeBuilderContext(parent_context))) {
return;
}
@@ -557,19 +576,14 @@ void PrePaintTreeWalk::UpdatePaintInvalidationContainer(
void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
const NGFragmentChildIterator* iterator,
- PrePaintTreeWalkContext& context,
- bool is_wheel_event_regions_enabled) {
+ PrePaintTreeWalkContext& context) {
PaintInvalidatorContext& paint_invalidator_context =
context.paint_invalidator_context;
base::Optional<NGPrePaintInfo> pre_paint_info_storage;
NGPrePaintInfo* pre_paint_info = nullptr;
if (iterator) {
- bool allow_reset = context.tree_builder_context.has_value()
-#if DCHECK_IS_ON()
- && context.tree_builder_context->is_actually_needed
-#endif
- ;
+ bool allow_reset = context.NeedsTreeBuilderContext();
pre_paint_info_storage.emplace(SetupFragmentData(*iterator, allow_reset));
pre_paint_info = &pre_paint_info_storage.value();
}
@@ -600,7 +614,7 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
// depends on the effective allowed touch action and blocking wheel event
// handlers.
UpdateEffectiveAllowedTouchAction(object, context);
- if (is_wheel_event_regions_enabled)
+ if (is_wheel_event_regions_enabled_)
UpdateBlockingWheelEventHandler(object, context);
if (paint_invalidator_.InvalidatePaint(
@@ -619,10 +633,12 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
property_changed =
std::max(property_changed, property_tree_builder->UpdateForChildren());
- // Save clip_changed flag in |context| so that all descendants will see it
- // even if we don't create tree_builder_context.
- if (context.tree_builder_context->clip_changed)
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ context.tree_builder_context->clip_changed) {
+ // Save clip_changed flag in |context| so that all descendants will see it
+ // even if we don't create tree_builder_context.
context.clip_changed = true;
+ }
if (property_changed != PaintPropertyChangeType::kUnchanged) {
if (property_changed >
@@ -660,10 +676,31 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
}
}
- // When this or ancestor clip changed, the layer needs repaint because it
- // may paint more or less results according to the changed clip.
- if (context.clip_changed && object.HasLayer())
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ if (property_changed != PaintPropertyChangeType::kUnchanged ||
+ // CullRectUpdater proactively update cull rect if the layer or
+ // descendant will repaint, but in pre-CAP the repaint flag stops
+ // propagation at compositing boundaries, while cull rect update
+ // ancestor flag should not stop at compositing boundaries.
+ (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ context.paint_invalidator_context.painting_layer
+ ->SelfOrDescendantNeedsRepaint())) {
+ if (object.HasLayer()) {
+ To<LayoutBoxModelObject>(object).Layer()->SetNeedsCullRectUpdate();
+ } else if (object.SlowFirstChild()) {
+ // This ensures cull rect update of the child PaintLayers affected by
+ // the paint property change on a non-PaintLayer. Though this may
+ // unnecessarily force update of unrelated children, the situation is
+ // rare and this is much easier.
+ context.paint_invalidator_context.painting_layer
+ ->SetForcesChildrenCullRectUpdate();
+ }
+ }
+ } else if (context.clip_changed && object.HasLayer()) {
+ // When this or ancestor clip changed, the layer needs repaint because it
+ // may paint more or less results according to the changed clip.
To<LayoutBoxModelObject>(object).Layer()->SetNeedsRepaint();
+ }
}
LocalFrameView* FindWebViewPluginContentFrameView(
@@ -678,16 +715,18 @@ LocalFrameView* FindWebViewPluginContentFrameView(
}
void PrePaintTreeWalk::WalkNGChildren(const LayoutObject* parent,
- NGFragmentChildIterator* iterator,
- bool is_wheel_event_regions_enabled) {
+ NGFragmentChildIterator* iterator) {
+ FragmentData* fragmentainer_fragment_data = nullptr;
+#if DCHECK_IS_ON()
+ const LayoutObject* fragmentainer_owner_box = nullptr;
+#endif
for (; !iterator->IsAtEnd(); iterator->Advance()) {
const LayoutObject* object = (*iterator)->GetLayoutObject();
if (const auto* fragment_item = (*iterator)->FragmentItem()) {
// Line boxes are not interesting. They have no paint effects. Descend
// directly into children.
if (fragment_item->Type() == NGFragmentItem::kLine) {
- WalkChildren(/* parent */ nullptr, iterator,
- is_wheel_event_regions_enabled);
+ WalkChildren(/* parent */ nullptr, iterator);
continue;
}
} else if (!object) {
@@ -695,32 +734,63 @@ void PrePaintTreeWalk::WalkNGChildren(const LayoutObject* parent,
if (UNLIKELY(box_fragment->IsLayoutObjectDestroyedOrMoved()))
continue;
+ // Check |box_fragment| and the |LayoutBox| that produced it are in sync.
+ // |OwnerLayoutBox()| has a few DCHECKs for this purpose.
+ DCHECK(box_fragment->OwnerLayoutBox());
+
// A fragmentainer doesn't paint anything itself. Just include its offset
// and descend into children.
DCHECK((*iterator)->BoxFragment()->IsFragmentainerBox());
- PhysicalOffset offset = (*iterator)->Link().offset;
+ if (UNLIKELY(!context_storage_.back().tree_builder_context)) {
+ WalkChildren(/* parent */ nullptr, iterator);
+ continue;
+ }
+
+ PaintPropertyTreeBuilderContext& tree_builder_context =
+ context_storage_.back().tree_builder_context.value();
+ PaintPropertyTreeBuilderFragmentContext& context =
+ tree_builder_context.fragments[0];
PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext*
- containing_block_context = nullptr;
- if (context_storage_.back().tree_builder_context) {
- PaintPropertyTreeBuilderContext& tree_builder_context =
- context_storage_.back().tree_builder_context.value();
- PaintPropertyTreeBuilderFragmentContext& context =
- tree_builder_context.fragments[0];
- containing_block_context = &context.current;
- containing_block_context->paint_offset += offset;
-
- if (box_fragment->IsFragmentainerBox()) {
- context.absolute_position = *containing_block_context;
- context.fixed_position = *containing_block_context;
+ containing_block_context = &context.current;
+ const PhysicalOffset offset = (*iterator)->Link().offset;
+ containing_block_context->paint_offset += offset;
+ const PhysicalOffset paint_offset =
+ containing_block_context->paint_offset;
+
+ // Create corresponding |FragmentData|. Hit-testing needs
+ // |FragmentData.PaintOffset|.
+ if (fragmentainer_fragment_data) {
+ DCHECK(!box_fragment->IsFirstForNode());
+#if DCHECK_IS_ON()
+ DCHECK_EQ(fragmentainer_owner_box, box_fragment->OwnerLayoutBox());
+#endif
+ fragmentainer_fragment_data =
+ &fragmentainer_fragment_data->EnsureNextFragment();
+ } else {
+ const LayoutBox* owner_box = box_fragment->OwnerLayoutBox();
+#if DCHECK_IS_ON()
+ DCHECK(!fragmentainer_owner_box);
+ fragmentainer_owner_box = owner_box;
+#endif
+ fragmentainer_fragment_data =
+ &owner_box->GetMutableForPainting().FirstFragment();
+ if (box_fragment->IsFirstForNode()) {
+ fragmentainer_fragment_data->ClearNextFragment();
+ } else {
+ // |box_fragment| is nested in another fragmentainer, and that it is
+ // the first one in this loop, but not the first one for the
+ // |LayoutObject|. Append a new |FragmentData| to the last one.
+ fragmentainer_fragment_data =
+ &fragmentainer_fragment_data->LastFragment().EnsureNextFragment();
}
}
- WalkChildren(/* parent */ nullptr, iterator,
- is_wheel_event_regions_enabled);
- if (containing_block_context)
- containing_block_context->paint_offset -= offset;
+ fragmentainer_fragment_data->SetPaintOffset(paint_offset);
+
+ WalkChildren(/* parent */ nullptr, iterator);
+ containing_block_context->paint_offset -= offset;
continue;
}
- Walk(*object, iterator, is_wheel_event_regions_enabled);
+ Walk(*object, iterator);
}
const LayoutBlockFlow* parent_block = DynamicTo<LayoutBlockFlow>(parent);
@@ -736,8 +806,7 @@ void PrePaintTreeWalk::WalkNGChildren(const LayoutObject* parent,
}
}
-void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
- bool is_wheel_event_regions_enabled) {
+void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object) {
if (const auto* layout_box = DynamicTo<LayoutBox>(&object)) {
if (layout_box->CanTraversePhysicalFragments()) {
// Enter NG child fragment traversal. We'll stay in this mode for all
@@ -750,7 +819,7 @@ void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
To<NGPhysicalBoxFragment>(*layout_box->GetPhysicalFragment(0));
DCHECK(!fragment.BreakToken());
NGFragmentChildIterator child_iterator(fragment);
- WalkNGChildren(&object, &child_iterator, is_wheel_event_regions_enabled);
+ WalkNGChildren(&object, &child_iterator);
return;
}
}
@@ -763,7 +832,7 @@ void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
// way).
if (const LayoutBox* legend =
LayoutFieldset::FindInFlowLegend(To<LayoutBlock>(object)))
- Walk(*legend, /* iterator */ nullptr, is_wheel_event_regions_enabled);
+ Walk(*legend, /* iterator */ nullptr);
}
for (const LayoutObject* child = object.SlowFirstChild(); child;
@@ -791,7 +860,7 @@ void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
if (UNLIKELY(child->IsRenderedLegend()))
continue;
- Walk(*child, /* iterator */ nullptr, is_wheel_event_regions_enabled);
+ Walk(*child, /* iterator */ nullptr);
}
if (!RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled())
@@ -835,18 +904,17 @@ void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
!ObjectRequiresTreeBuilderContext(*box))
continue;
DCHECK_EQ(box->Container(), &object);
- Walk(*box, /* iterator */ nullptr, is_wheel_event_regions_enabled);
+ Walk(*box, /* iterator */ nullptr);
}
}
void PrePaintTreeWalk::WalkChildren(const LayoutObject* object,
- const NGFragmentChildIterator* iterator,
- bool is_wheel_event_regions_enabled) {
+ const NGFragmentChildIterator* iterator) {
DCHECK(iterator || object);
if (!iterator) {
// We're not doing LayoutNG fragment traversal of this object.
- WalkLegacyChildren(*object, is_wheel_event_regions_enabled);
+ WalkLegacyChildren(*object);
return;
}
@@ -860,18 +928,17 @@ void PrePaintTreeWalk::WalkChildren(const LayoutObject* object,
(object->IsBox() &&
To<LayoutBox>(object)->GetNGPaginationBreakability() ==
LayoutBox::kForbidBreaks));
- WalkLegacyChildren(*object, is_wheel_event_regions_enabled);
+ WalkLegacyChildren(*object);
return;
}
// Traverse child NG fragments.
NGFragmentChildIterator child_iterator(iterator->Descend());
- WalkNGChildren(object, &child_iterator, is_wheel_event_regions_enabled);
+ WalkNGChildren(object, &child_iterator);
}
void PrePaintTreeWalk::Walk(const LayoutObject& object,
- const NGFragmentChildIterator* iterator,
- bool is_wheel_event_regions_enabled) {
+ const NGFragmentChildIterator* iterator) {
const NGPhysicalBoxFragment* physical_fragment = nullptr;
bool is_last_fragment = true;
if (iterator) {
@@ -892,7 +959,7 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object,
};
bool needs_tree_builder_context_update =
- ContextRequiresTreeBuilderContext(parent_context()) ||
+ ContextRequiresChildTreeBuilderContext(parent_context()) ||
ObjectRequiresTreeBuilderContext(object);
#if DCHECK_IS_ON()
@@ -901,7 +968,7 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object,
// Early out from the tree walk if possible.
if (!needs_tree_builder_context_update && !ObjectRequiresPrePaint(object) &&
- !ContextRequiresPrePaint(parent_context())) {
+ !ContextRequiresChildPrePaint(parent_context())) {
return;
}
@@ -919,21 +986,22 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object,
return context_storage_.back();
};
- // Ignore clip changes from ancestor across transform boundaries.
if (object.StyleRef().HasTransform()) {
+ // Ignore clip changes from ancestor across transform boundaries.
context().clip_changed = false;
if (context().tree_builder_context)
context().tree_builder_context->clip_changed = false;
}
- WalkInternal(object, iterator, context(), is_wheel_event_regions_enabled);
+ WalkInternal(object, iterator, context());
bool child_walk_blocked = object.ChildPrePaintBlockedByDisplayLock();
// If we need a subtree walk due to context flags, we need to store that
// information on the display lock, since subsequent walks might not set the
// same bits on the context.
- if (child_walk_blocked && (ContextRequiresTreeBuilderContext(context()) ||
- ContextRequiresPrePaint(context()))) {
+ if (child_walk_blocked &&
+ (ContextRequiresChildTreeBuilderContext(context()) ||
+ ContextRequiresChildPrePaint(context()))) {
// Note that |effective_allowed_touch_action_changed| and
// |blocking_wheel_event_handler_changed| are special in that they requires
// us to specifically recalculate this value on each subtree element. Other
@@ -946,7 +1014,7 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object,
}
if (!child_walk_blocked) {
- WalkChildren(&object, iterator, is_wheel_event_regions_enabled);
+ WalkChildren(&object, iterator);
if (const auto* layout_embedded_content =
DynamicTo<LayoutEmbeddedContent>(object)) {
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index 71795789e93..3e4ddc8f5c2 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -74,6 +74,15 @@ class CORE_EXPORT PrePaintTreeWalk {
base::Optional<PaintPropertyTreeBuilderContext> tree_builder_context;
PaintInvalidatorContext paint_invalidator_context;
+ bool NeedsTreeBuilderContext() const {
+#if DCHECK_IS_ON()
+ DCHECK(tree_builder_context);
+ return tree_builder_context->is_actually_needed;
+#else
+ return tree_builder_context.has_value();
+#endif
+ }
+
// The ancestor in the PaintLayer tree which is a scroll container. Note
// that it is tree ancestor, not containing block or stacking ancestor.
PaintLayer* ancestor_scroll_container_paint_layer = nullptr;
@@ -94,7 +103,8 @@ class CORE_EXPORT PrePaintTreeWalk {
// This is set to true once we see tree_builder_context->clip_changed is
// true. It will be propagated to descendant contexts even if we don't
- // create tree_builder_context.
+ // create tree_builder_context. Used only when CullRectUpdate is not
+ // enabled.
bool clip_changed = false;
const LayoutBoxModelObject* paint_invalidation_container = nullptr;
@@ -102,8 +112,9 @@ class CORE_EXPORT PrePaintTreeWalk {
paint_invalidation_container_for_stacked_contents = nullptr;
};
- static bool ContextRequiresPrePaint(const PrePaintTreeWalkContext&);
- static bool ContextRequiresTreeBuilderContext(const PrePaintTreeWalkContext&);
+ static bool ContextRequiresChildPrePaint(const PrePaintTreeWalkContext&);
+ static bool ContextRequiresChildTreeBuilderContext(
+ const PrePaintTreeWalkContext&);
#if DCHECK_IS_ON()
void CheckTreeBuilderContextState(const LayoutObject&,
@@ -122,24 +133,13 @@ class CORE_EXPORT PrePaintTreeWalk {
// very big stack frames. Splitting the heavy lifting to a separate function
// makes sure the stack frame is freed prior to making a recursive call.
// See https://crbug.com/781301 .
-
- // TODO(https://crbug.com/841364): Remove is_wheel_event_regions_enabled
- // argument once kWheelEventRegions feature flag is removed.
NOINLINE void WalkInternal(const LayoutObject&,
const NGFragmentChildIterator*,
- PrePaintTreeWalkContext&,
- bool is_wheel_event_regions_enabled);
- void WalkNGChildren(const LayoutObject* parent,
- NGFragmentChildIterator*,
- bool is_wheel_event_regions_enabled);
- void WalkLegacyChildren(const LayoutObject&,
- bool is_wheel_event_regions_enabled);
- void WalkChildren(const LayoutObject*,
- const NGFragmentChildIterator*,
- bool is_wheel_event_regions_enabled);
- void Walk(const LayoutObject&,
- const NGFragmentChildIterator*,
- bool is_wheel_event_regions_enabled);
+ PrePaintTreeWalkContext&);
+ void WalkNGChildren(const LayoutObject* parent, NGFragmentChildIterator*);
+ void WalkLegacyChildren(const LayoutObject&);
+ void WalkChildren(const LayoutObject*, const NGFragmentChildIterator*);
+ void Walk(const LayoutObject&, const NGFragmentChildIterator*);
bool NeedsTreeBuilderContextUpdate(const LocalFrameView&,
const PrePaintTreeWalkContext&);
@@ -168,6 +168,10 @@ class CORE_EXPORT PrePaintTreeWalk {
PaintInvalidator paint_invalidator_;
Vector<PrePaintTreeWalkContext> context_storage_;
+ // TODO(https://crbug.com/841364): Remove is_wheel_event_regions_enabled
+ // argument once kWheelEventRegions feature flag is removed.
+ bool is_wheel_event_regions_enabled_ = false;
+
bool needs_invalidate_chrome_client_ = false;
FRIEND_TEST_ALL_PREFIXES(PrePaintTreeWalkTest, ClipRects);
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
index 50745d444d6..ff9e1eda625 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
@@ -245,13 +245,13 @@ TEST_P(PrePaintTreeWalkTest, ClearSubsequenceCachingClipChangePosFixed) {
TEST_P(PrePaintTreeWalkTest, ClipChangeRepaintsDescendants) {
SetBodyInnerHTML(R"HTML(
<style>
- #parent { height: 75px; position: relative; width: 100px; }
+ #parent { position: relative; width: 100px; }
#child { overflow: hidden; width: 10%; height: 100%; position: relative; }
#greatgrandchild {
- width: 5px; height: 5px; z-index: 100; position: relative;
+ width: 100px; height: 100px; z-index: 100; position: relative;
}
</style>
- <div id='parent' style='height: 100px;'>
+ <div id='parent' style='height: 10px'>
<div id='child'>
<div id='grandchild'>
<div id='greatgrandchild'></div>
@@ -260,7 +260,8 @@ TEST_P(PrePaintTreeWalkTest, ClipChangeRepaintsDescendants) {
</div>
)HTML");
- GetDocument().getElementById("parent")->removeAttribute("style");
+ GetDocument().getElementById("parent")->setAttribute(html_names::kStyleAttr,
+ "height: 100px");
UpdateAllLifecyclePhasesExceptPaint();
auto* paint_layer = GetPaintLayerByElementId("greatgrandchild");
@@ -451,4 +452,49 @@ TEST_P(PrePaintTreeWalkTest, InsideBlockingWheelEventHandlerUpdate) {
EXPECT_TRUE(descendant.InsideBlockingWheelEventHandler());
}
+TEST_P(PrePaintTreeWalkTest, CullRectUpdateOnSVGTransformChange) {
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
+ SetBodyInnerHTML(R"HTML(
+ <svg style="width: 200px; height: 200px">
+ <rect id="rect"/>
+ <g id="g"><foreignObject id="foreign"/></g>
+ </svg>
+ )HTML");
+
+ auto& foreign = *GetLayoutObjectByElementId("foreign");
+ EXPECT_EQ(IntRect(0, 0, 200, 200),
+ foreign.FirstFragment().GetCullRect().Rect());
+
+ GetDocument().getElementById("rect")->setAttribute(
+ html_names::kStyleAttr, "transform: translateX(20px)");
+ UpdateAllLifecyclePhasesExceptPaint();
+ EXPECT_EQ(IntRect(0, 0, 200, 200),
+ foreign.FirstFragment().GetCullRect().Rect());
+
+ GetDocument().getElementById("g")->setAttribute(
+ html_names::kStyleAttr, "transform: translateY(20px)");
+ UpdateAllLifecyclePhasesExceptPaint();
+ EXPECT_EQ(IntRect(0, -20, 200, 200),
+ foreign.FirstFragment().GetCullRect().Rect());
+}
+
+TEST_P(PrePaintTreeWalkTest, InlineOutlineWithContinuationPaintInvalidation) {
+ SetBodyInnerHTML(R"HTML(
+ <div>
+ <span style="outline: 1px solid black">
+ <span id="child-span">span</span>
+ <div>continuation</div>
+ </span>
+ </div>
+ )HTML");
+
+ // This test passes if the following doesn't crash.
+ GetDocument()
+ .getElementById("child-span")
+ ->setAttribute(html_names::kStyleAttr, "color: blue");
+ UpdateAllLifecyclePhasesForTest();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
index 098b8872061..821012b15c4 100644
--- a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -109,12 +109,7 @@ void ReplacedPainter::Paint(const PaintInfo& paint_info) {
}
}
if (should_paint_background) {
- if (layout_replaced_.HasLayer() &&
- layout_replaced_.Layer()->GetCompositingState() ==
- kPaintsIntoOwnBacking &&
- layout_replaced_.Layer()
- ->GetCompositedLayerMapping()
- ->DrawsBackgroundOntoContentLayer()) {
+ if (layout_replaced_.DrawsBackgroundOntoContentLayer()) {
// If the background paints into the content layer, we can skip painting
// the background but still need to paint the hit test rects.
BoxPainter(layout_replaced_)
@@ -176,7 +171,7 @@ void ReplacedPainter::Paint(const PaintInfo& paint_info) {
bool draw_selection_tint =
local_paint_info.phase == PaintPhase::kForeground &&
layout_replaced_.IsSelected() && layout_replaced_.CanBeSelectionLeaf() &&
- !local_paint_info.IsPrinting();
+ !layout_replaced_.GetDocument().Printing();
if (draw_selection_tint && !DrawingRecorder::UseCachedDrawingIfPossible(
local_paint_info.context, layout_replaced_,
DisplayItem::kSelectionTint)) {
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
index c7ef1d33d18..f2a9b3d16fb 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
@@ -64,11 +64,18 @@ void ScopedBoxContentsPaintState::AdjustForBoxContents(const LayoutBox& box) {
return;
// See comments for ScrollTranslation in object_paint_properties.h
- // for the reason of adding ScrollOrigin(). contents_paint_offset will
+ // for the reason of adding ScrollOrigin(). The paint offset will
// be used only for the scrolling contents that are not painted through
// descendant objects' Paint() method, e.g. inline boxes.
paint_offset_ += PhysicalOffset(box.ScrollOrigin());
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ adjusted_paint_info_.emplace(input_paint_info_);
+ adjusted_paint_info_->SetCullRect(
+ fragment_to_paint_->GetContentsCullRect());
+ return;
+ }
+
// If a LayoutView is using infinite cull rect, we are painting with viewport
// clip disabled, so don't cull the scrolling contents. This is just for
// completeness because we always paint the whole scrolling background even
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
index 808f2b5d647..b54e5d6f9e6 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
@@ -41,12 +41,9 @@ class ScopedPaintState {
paint_offset_ = fragment_to_paint_->PaintOffset();
if (&object == paint_info.PaintContainer()) {
// PaintLayerPainter already adjusted for PaintOffsetTranslation for
- // PaintContainer. TODO(wangxianzhu): Can we combine the code?
+ // PaintContainer.
return;
}
- // TODO(wangxianzhu): Combine code for other paint properties into this
- // class, then the following will be something like
- // AdjustForLocalBorcerBoxProperties().
const auto* properties = fragment_to_paint_->PaintProperties();
if (properties && properties->PaintOffsetTranslation()) {
AdjustForPaintOffsetTranslation(object,
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
index c0ad9202691..171b6347800 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
@@ -24,8 +24,8 @@
#include "third_party/blink/renderer/core/paint/scoped_svg_paint_state.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
#include "third_party/blink/renderer/core/paint/svg_mask_painter.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
@@ -34,12 +34,18 @@
namespace blink {
ScopedSVGPaintState::~ScopedSVGPaintState() {
+ // Paint mask before clip path as mask because if both exist, the ClipPathMask
+ // effect node is a child of the Mask node (see object_paint_properties.h for
+ // the node hierarchy), to ensure the clip-path mask will be applied to the
+ // mask to create an intersection of the masks, then the intersection will be
+ // applied to the masked content.
+ if (should_paint_mask_)
+ SVGMaskPainter::Paint(paint_info_.context, object_, display_item_client_);
+
if (should_paint_clip_path_as_mask_image_) {
ClipPathClipper::PaintClipPathAsMaskImage(
paint_info_.context, object_, display_item_client_, PhysicalOffset());
}
- if (should_paint_mask_)
- SVGMaskPainter::Paint(paint_info_.context, object_, display_item_client_);
}
void ScopedSVGPaintState::ApplyEffects() {
@@ -99,9 +105,11 @@ void ScopedSVGPaintState::ApplyPaintPropertyState(
}
void ScopedSVGPaintState::ApplyMaskIfNecessary() {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(object_);
- if (resources && resources->Masker())
+ SVGResourceClient* client = SVGResources::GetClient(object_);
+ if (!client)
+ return;
+ if (GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, object_.StyleRef().MaskerResource()))
should_paint_mask_ = true;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc b/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
new file mode 100644
index 00000000000..a338e55dc72
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
@@ -0,0 +1,155 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/selection_bounds_recorder.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/layout/api/selection_state.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+
+namespace blink {
+
+namespace {
+
+// This represents a directional edge of a rect, starting at one corner and
+// ending on another. Note that the 'left' and 'right' edges only have one
+// variant because the edge always ends on the bottom. However in vertical
+// writing modes, the edge end should follow the block direction, which can
+// be flipped.
+enum class RectEdge {
+ kTopLeftToBottomLeft,
+ kTopRightToBottomRight,
+ kTopLeftToTopRight,
+ kBottomLeftToBottomRight,
+ kTopRightToTopLeft,
+ kBottomRightToBottomLeft,
+};
+
+struct BoundEdges {
+ RectEdge start;
+ RectEdge end;
+};
+
+// Based on the given WritingMode and direction, return the pair of start and
+// end edges that should be used to determe the PaintedSelectionBound start
+// and end edges given a selection rectangle. For the simplest cases (i.e.
+// LTR horizontal writing mode), the left edge is the start and the right edge
+// would be the end. However, this flips for RTL, and vertical writing modes
+// additionally complicated matters.
+BoundEdges GetBoundEdges(WritingMode writing_mode, bool is_ltr) {
+ if (IsHorizontalWritingMode(writing_mode)) {
+ if (is_ltr)
+ return {RectEdge::kTopLeftToBottomLeft, RectEdge::kTopRightToBottomRight};
+ else
+ return {RectEdge::kTopRightToBottomRight, RectEdge::kTopLeftToBottomLeft};
+ } else if (IsFlippedBlocksWritingMode(writing_mode)) {
+ if (is_ltr)
+ return {RectEdge::kTopLeftToTopRight, RectEdge::kBottomRightToBottomLeft};
+ else
+ return {RectEdge::kBottomLeftToBottomRight, RectEdge::kTopRightToTopLeft};
+ } else {
+ if (is_ltr)
+ return {RectEdge::kTopRightToTopLeft, RectEdge::kBottomLeftToBottomRight};
+ else
+ return {RectEdge::kBottomRightToBottomLeft, RectEdge::kTopLeftToTopRight};
+ }
+}
+
+// Set the given bound's edge_start and edge_end, based on the provided
+// selection rect and edge.
+void SetBoundEdge(IntRect selection_rect,
+ RectEdge edge,
+ PaintedSelectionBound& bound) {
+ switch (edge) {
+ case RectEdge::kTopLeftToBottomLeft:
+ bound.edge_start = selection_rect.MinXMinYCorner();
+ bound.edge_end = selection_rect.MinXMaxYCorner();
+ return;
+ case RectEdge::kTopRightToBottomRight:
+ bound.edge_start = selection_rect.MaxXMinYCorner();
+ bound.edge_end = selection_rect.MaxXMaxYCorner();
+ return;
+ case RectEdge::kTopLeftToTopRight:
+ bound.edge_start = selection_rect.MinXMinYCorner();
+ bound.edge_end = selection_rect.MaxXMinYCorner();
+ return;
+ case RectEdge::kBottomLeftToBottomRight:
+ bound.edge_start = selection_rect.MinXMaxYCorner();
+ bound.edge_end = selection_rect.MaxXMaxYCorner();
+ return;
+ case RectEdge::kTopRightToTopLeft:
+ bound.edge_start = selection_rect.MaxXMinYCorner();
+ bound.edge_end = selection_rect.MinXMinYCorner();
+ return;
+ case RectEdge::kBottomRightToBottomLeft:
+ bound.edge_start = selection_rect.MaxXMaxYCorner();
+ bound.edge_end = selection_rect.MinXMaxYCorner();
+ return;
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace
+
+SelectionBoundsRecorder::SelectionBoundsRecorder(
+ SelectionState state,
+ PhysicalRect selection_rect,
+ PaintController& paint_controller,
+ TextDirection text_direction,
+ WritingMode writing_mode)
+ : state_(state),
+ selection_rect_(selection_rect),
+ paint_controller_(paint_controller),
+ text_direction_(text_direction),
+ writing_mode_(writing_mode) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+}
+
+SelectionBoundsRecorder::~SelectionBoundsRecorder() {
+ base::Optional<PaintedSelectionBound> start;
+ base::Optional<PaintedSelectionBound> end;
+ auto selection_rect = PixelSnappedIntRect(selection_rect_);
+ const bool is_ltr = IsLtr(text_direction_);
+ BoundEdges edges = GetBoundEdges(writing_mode_, is_ltr);
+ if (state_ == SelectionState::kStart ||
+ state_ == SelectionState::kStartAndEnd) {
+ start.emplace();
+ start->type = is_ltr ? gfx::SelectionBound::Type::LEFT
+ : gfx::SelectionBound::Type::RIGHT;
+ SetBoundEdge(selection_rect, edges.start, *start);
+
+ // TODO(crbug.com/1065049) Handle the case where selection within input
+ // text is clipped out.
+ start->hidden = false;
+ }
+
+ if (state_ == SelectionState::kStartAndEnd ||
+ state_ == SelectionState::kEnd) {
+ end.emplace();
+ end->type = is_ltr ? gfx::SelectionBound::Type::RIGHT
+ : gfx::SelectionBound::Type::LEFT;
+ SetBoundEdge(selection_rect, edges.end, *end);
+ end->hidden = false;
+ }
+
+ paint_controller_.RecordSelection(start, end);
+}
+
+bool SelectionBoundsRecorder::ShouldRecordSelection(
+ const FrameSelection& frame_selection,
+ SelectionState state) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return false;
+
+ if (!frame_selection.IsHandleVisible() || frame_selection.IsHidden())
+ return false;
+
+ if (state == SelectionState::kInside || state == SelectionState::kNone)
+ return false;
+
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.h b/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.h
new file mode 100644
index 00000000000..355da7af031
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/selection_bounds_recorder.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_CORE_PAINT_SELECTION_BOUNDS_RECORDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SELECTION_BOUNDS_RECORDER_H_
+
+#include "third_party/blink/renderer/core/layout/api/selection_state.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class FrameSelection;
+class PaintController;
+
+// This class is used for recording painted selection bounds when
+// CompositeAfterPaint is enabled. Based on the SelectionState and provided
+// |selection_rect|, records the appropriate bounds via the paint controller.
+// These bounds are consumed at composition time by PaintArtifactCompositor and
+// pushed to the LayerTreeHost. All of the work happens in the destructor to
+// ensure this information recorded after any painting is completed, even if
+// a cached drawing is re-used.
+class SelectionBoundsRecorder {
+ STACK_ALLOCATED();
+
+ public:
+ SelectionBoundsRecorder(SelectionState,
+ PhysicalRect,
+ PaintController&,
+ TextDirection,
+ WritingMode);
+
+ ~SelectionBoundsRecorder();
+
+ static bool ShouldRecordSelection(const FrameSelection&, SelectionState);
+
+ private:
+ const SelectionState state_;
+ PhysicalRect selection_rect_;
+ PaintController& paint_controller_;
+ TextDirection text_direction_;
+ WritingMode writing_mode_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SELECTION_BOUNDS_RECORDER_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
index 7cb6aa59436..df714ed11f5 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -42,9 +42,9 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
ScopedSVGTransformState transform_state(paint_info, layout_svg_image_);
{
ScopedSVGPaintState paint_state(layout_svg_image_, paint_info);
+ SVGModelObjectPainter::RecordHitTestData(layout_svg_image_, paint_info);
if (!DrawingRecorder::UseCachedDrawingIfPossible(
paint_info.context, layout_svg_image_, paint_info.phase)) {
- SVGModelObjectPainter::RecordHitTestData(layout_svg_image_, paint_info);
SVGDrawingRecorder recorder(paint_info.context, layout_svg_image_,
paint_info.phase);
PaintForeground(paint_info);
@@ -55,18 +55,19 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
}
void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
- const LayoutImageResource* image_resource = layout_svg_image_.ImageResource();
+ const LayoutImageResource& image_resource =
+ *layout_svg_image_.ImageResource();
FloatSize image_viewport_size = ComputeImageViewportSize();
image_viewport_size.Scale(layout_svg_image_.StyleRef().EffectiveZoom());
if (image_viewport_size.IsEmpty())
return;
- scoped_refptr<Image> image = image_resource->GetImage(image_viewport_size);
+ scoped_refptr<Image> image = image_resource.GetImage(image_viewport_size);
FloatRect dest_rect = layout_svg_image_.ObjectBoundingBox();
-
auto* image_element = To<SVGImageElement>(layout_svg_image_.GetElement());
RespectImageOrientationEnum respect_orientation =
- LayoutObject::ShouldRespectImageOrientation(&layout_svg_image_);
+ image_resource.ImageOrientation();
+
FloatRect src_rect(FloatPoint(), image->SizeAsFloat(respect_orientation));
if (respect_orientation && !image->HasDefaultOrientation()) {
// We need the oriented source rect for adjusting the aspect ratio
@@ -91,19 +92,19 @@ void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
image.get(), decode_mode, dest_rect, &src_rect,
layout_svg_image_.StyleRef().HasFilterInducingProperty(),
SkBlendMode::kSrcOver, respect_orientation);
- if (image_resource->CachedImage() &&
- image_resource->CachedImage()->IsLoaded()) {
+
+ ImageResourceContent* image_content = image_resource.CachedImage();
+ if (image_content->IsLoaded()) {
LocalDOMWindow* window = layout_svg_image_.GetDocument().domWindow();
DCHECK(window);
DCHECK(paint_info.PaintContainer());
ImageElementTiming::From(*window).NotifyImagePainted(
- &layout_svg_image_, image_resource->CachedImage(),
+ layout_svg_image_, *image_content,
paint_info.context.GetPaintController().CurrentPaintChunkProperties(),
EnclosingIntRect(dest_rect));
}
-
PaintTimingDetector::NotifyImagePaint(
- layout_svg_image_, image->Size(), image_resource->CachedImage(),
+ layout_svg_image_, image->Size(), *image_content,
paint_info.context.GetPaintController().CurrentPaintChunkProperties(),
EnclosingIntRect(dest_rect));
PaintTiming& timing = PaintTiming::From(
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
index 7f137038a60..5be998e9b02 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
@@ -16,15 +16,17 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
#include "third_party/blink/renderer/core/paint/inline_text_box_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_timing.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
+#include "third_party/blink/renderer/core/paint/text_painter_base.h"
#include "third_party/blink/renderer/core/style/applied_text_decoration.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
+#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
@@ -44,7 +46,7 @@ static inline bool TextShouldBePainted(
bool SVGInlineTextBoxPainter::ShouldPaintSelection(
const PaintInfo& paint_info) const {
// Don't paint selections when printing.
- if (paint_info.IsPrinting())
+ if (InlineLayoutObject().GetDocument().Printing())
return false;
// Don't paint selections when rendering a mask, clip-path (as a mask),
// pattern or feImage (element reference.)
@@ -53,11 +55,6 @@ bool SVGInlineTextBoxPainter::ShouldPaintSelection(
return svg_inline_text_box_.IsSelected();
}
-static bool HasShadow(const PaintInfo& paint_info, const ComputedStyle& style) {
- // Text shadows are disabled when printing. http://crbug.com/258321
- return style.TextShadow() && !paint_info.IsPrinting();
-}
-
LayoutObject& SVGInlineTextBoxPainter::InlineLayoutObject() const {
return *LineLayoutAPIShim::LayoutObjectFrom(
svg_inline_text_box_.GetLineLayoutItem());
@@ -124,10 +121,9 @@ void SVGInlineTextBoxPainter::PaintTextFragments(
const PaintInfo& paint_info,
LayoutObject& parent_layout_object) {
const ComputedStyle& style = parent_layout_object.StyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
- bool has_fill = svg_style.HasFill();
- bool has_visible_stroke = svg_style.HasVisibleStroke();
+ bool has_fill = style.HasFill();
+ bool has_visible_stroke = style.HasVisibleStroke();
const ComputedStyle* selection_style = &style;
bool should_paint_selection = ShouldPaintSelection(paint_info);
@@ -135,12 +131,10 @@ void SVGInlineTextBoxPainter::PaintTextFragments(
selection_style =
parent_layout_object.GetCachedPseudoElementStyle(kPseudoIdSelection);
if (selection_style) {
- const SVGComputedStyle& svg_selection_style = selection_style->SvgStyle();
-
if (!has_fill)
- has_fill = svg_selection_style.HasFill();
+ has_fill = selection_style->HasFill();
if (!has_visible_stroke)
- has_visible_stroke = svg_selection_style.HasVisibleStroke();
+ has_visible_stroke = selection_style->HasVisibleStroke();
} else {
selection_style = &style;
}
@@ -175,7 +169,7 @@ void SVGInlineTextBoxPainter::PaintTextFragments(
}
for (int i = 0; i < 3; i++) {
- switch (svg_style.PaintOrderType(i)) {
+ switch (style.PaintOrderType(i)) {
case PT_FILL:
if (has_fill) {
PaintText(paint_info, style, *selection_style, fragment,
@@ -210,17 +204,16 @@ void SVGInlineTextBoxPainter::PaintTextFragments(
void SVGInlineTextBoxPainter::PaintSelectionBackground(
const PaintInfo& paint_info) {
- if (svg_inline_text_box_.GetLineLayoutItem().StyleRef().Visibility() !=
- EVisibility::kVisible)
+ auto layout_item = svg_inline_text_box_.GetLineLayoutItem();
+ if (layout_item.StyleRef().Visibility() != EVisibility::kVisible)
return;
- DCHECK(!paint_info.IsPrinting());
+ DCHECK(!layout_item.GetDocument().Printing());
if (paint_info.phase == PaintPhase::kSelectionDragImage ||
!ShouldPaintSelection(paint_info))
return;
- auto layout_item = svg_inline_text_box_.GetLineLayoutItem();
Color background_color = HighlightPaintingUtils::HighlightBackgroundColor(
layout_item.GetDocument(), layout_item.StyleRef(), layout_item.GetNode(),
kPseudoIdSelection);
@@ -346,12 +339,10 @@ void SVGInlineTextBoxPainter::PaintDecoration(const PaintInfo& paint_info,
FloatRect(decoration_origin,
FloatSize(fragment.width, thickness / scaling_factor)));
- const SVGComputedStyle& svg_decoration_style = decoration_style.SvgStyle();
-
for (int i = 0; i < 3; i++) {
- switch (svg_decoration_style.PaintOrderType(i)) {
+ switch (decoration_style.PaintOrderType(i)) {
case PT_FILL:
- if (svg_decoration_style.HasFill()) {
+ if (decoration_style.HasFill()) {
PaintFlags fill_flags;
if (!SVGObjectPainter(*decoration_layout_object)
.PreparePaint(paint_info, decoration_style, kApplyToFillMode,
@@ -362,17 +353,17 @@ void SVGInlineTextBoxPainter::PaintDecoration(const PaintInfo& paint_info,
}
break;
case PT_STROKE:
- if (svg_decoration_style.HasVisibleStroke()) {
+ if (decoration_style.HasVisibleStroke()) {
PaintFlags stroke_flags;
if (!SVGObjectPainter(*decoration_layout_object)
.PreparePaint(paint_info, decoration_style,
kApplyToStrokeMode, stroke_flags))
break;
stroke_flags.setAntiAlias(true);
- float stroke_scale_factor =
- svg_decoration_style.VectorEffect() == VE_NON_SCALING_STROKE
- ? 1 / scaling_factor
- : 1;
+ float stroke_scale_factor = decoration_style.VectorEffect() ==
+ EVectorEffect::kNonScalingStroke
+ ? 1 / scaling_factor
+ : 1;
StrokeData stroke_data;
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(
stroke_data, decoration_style, *decoration_layout_object,
@@ -421,9 +412,11 @@ bool SVGInlineTextBoxPainter::SetupTextPaint(
return false;
flags.setAntiAlias(true);
- if (HasShadow(paint_info, style)) {
- flags.setLooper(style.TextShadow()->CreateDrawLooper(
- DrawLooperBuilder::kShadowRespectsAlpha,
+ if (style.TextShadow() &&
+ // Text shadows are disabled when printing. http://crbug.com/258321
+ !InlineLayoutObject().GetDocument().Printing()) {
+ flags.setLooper(TextPainterBase::CreateDrawLooper(
+ style.TextShadow(), DrawLooperBuilder::kShadowRespectsAlpha,
style.VisitedDependentColor(GetCSSPropertyColor()),
style.UsedColorScheme()));
}
@@ -431,7 +424,7 @@ bool SVGInlineTextBoxPainter::SetupTextPaint(
if (resource_mode == kApplyToStrokeMode) {
// The stroke geometry needs be generated based on the scaled font.
float stroke_scale_factor =
- style.SvgStyle().VectorEffect() != VE_NON_SCALING_STROKE
+ style.VectorEffect() != EVectorEffect::kNonScalingStroke
? scaling_factor
: 1;
StrokeData stroke_data;
@@ -485,6 +478,48 @@ void SVGInlineTextBoxPainter::PaintText(const PaintInfo& paint_info,
}
}
+namespace {
+
+class SelectionStyleScope {
+ STACK_ALLOCATED();
+
+ public:
+ SelectionStyleScope(LayoutObject&,
+ const ComputedStyle& style,
+ const ComputedStyle& selection_style);
+ SelectionStyleScope(const SelectionStyleScope&) = delete;
+ SelectionStyleScope& operator=(const SelectionStyleScope) = delete;
+ ~SelectionStyleScope();
+
+ private:
+ LayoutObject& layout_object_;
+ const ComputedStyle& selection_style_;
+ const bool styles_are_equal_;
+};
+
+SelectionStyleScope::SelectionStyleScope(LayoutObject& layout_object,
+ const ComputedStyle& style,
+ const ComputedStyle& selection_style)
+ : layout_object_(layout_object),
+ selection_style_(selection_style),
+ styles_are_equal_(style == selection_style) {
+ if (styles_are_equal_)
+ return;
+ DCHECK(IsA<SVGElement>(layout_object.GetNode()) &&
+ !layout_object.IsSVGInlineText());
+ auto& element = To<SVGElement>(*layout_object_.GetNode());
+ SVGResources::UpdatePaints(element, nullptr, selection_style_);
+}
+
+SelectionStyleScope::~SelectionStyleScope() {
+ if (styles_are_equal_)
+ return;
+ auto& element = To<SVGElement>(*layout_object_.GetNode());
+ SVGResources::ClearPaints(element, &selection_style_);
+}
+
+} // namespace
+
void SVGInlineTextBoxPainter::PaintText(
const PaintInfo& paint_info,
const ComputedStyle& style,
@@ -527,9 +562,8 @@ void SVGInlineTextBoxPainter::PaintText(
// Draw text using selection style from the start to the end position of the
// selection.
{
- SVGResourcesCache::TemporaryStyleScope scope(ParentInlineLayoutObject(),
- style, selection_style);
-
+ SelectionStyleScope scope(ParentInlineLayoutObject(), style,
+ selection_style);
PaintFlags flags;
if (SetupTextPaint(paint_info, selection_style, resource_mode, flags,
shader_transform)) {
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
index 9269343f1a6..fb46328ca94 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
@@ -41,9 +41,10 @@ void SVGMaskPainter::Paint(GraphicsContext& context,
DrawingRecorder recorder(context, display_item_client, DisplayItem::kSVGMask,
EnclosingIntRect(visual_rect));
- const SVGComputedStyle& svg_style = layout_object.StyleRef().SvgStyle();
- auto* masker =
- GetSVGResourceAsType<LayoutSVGResourceMasker>(svg_style.MaskerResource());
+ SVGResourceClient* client = SVGResources::GetClient(layout_object);
+ const ComputedStyle& style = layout_object.StyleRef();
+ auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ *client, style.MaskerResource());
DCHECK(masker);
SECURITY_DCHECK(!masker->NeedsLayout());
masker->ClearInvalidationMask();
@@ -56,7 +57,7 @@ void SVGMaskPainter::Paint(GraphicsContext& context,
content_transformation.ScaleNonUniform(reference_box.Width(),
reference_box.Height());
} else if (layout_object.IsSVGForeignObject()) {
- content_transformation.Scale(layout_object.StyleRef().EffectiveZoom());
+ content_transformation.Scale(style.EffectiveZoom());
}
sk_sp<const PaintRecord> record =
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
index 67a212006e6..acd0c2d1623 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -15,21 +14,6 @@ namespace blink {
namespace {
-Color ResolveColor(const ComputedStyle& style,
- const SVGPaint& paint,
- const SVGPaint& visited_paint) {
- Color color = style.ResolvedColor(paint.GetColor());
- if (style.InsideLink() != EInsideLink::kInsideVisitedLink)
- return color;
- // FIXME: This code doesn't support the uri component of the visited link
- // paint, https://bugs.webkit.org/show_bug.cgi?id=70006
- if (!visited_paint.HasColor())
- return color;
- const Color& visited_color = style.ResolvedColor(visited_paint.GetColor());
- return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
- color.Alpha());
-}
-
void CopyStateFromGraphicsContext(GraphicsContext& context, PaintFlags& flags) {
// TODO(fs): The color filter can be set when generating a picture for a mask
// due to color-interpolation. We could also just apply the
@@ -49,8 +33,7 @@ void CopyStateFromGraphicsContext(GraphicsContext& context, PaintFlags& flags) {
void SVGObjectPainter::PaintResourceSubtree(GraphicsContext& context) {
DCHECK(!layout_object_.NeedsLayout());
- PaintInfo info(context, LayoutRect::InfiniteIntRect(),
- PaintPhase::kForeground,
+ PaintInfo info(context, CullRect::Infinite(), PaintPhase::kForeground,
kGlobalPaintNormalPhase | kGlobalPaintFlattenCompositingLayers,
kPaintLayerPaintingRenderingResourceSubtree,
&layout_object_.PaintingLayer()->GetLayoutObject());
@@ -58,20 +41,17 @@ void SVGObjectPainter::PaintResourceSubtree(GraphicsContext& context) {
}
bool SVGObjectPainter::ApplyPaintResource(
- LayoutSVGResourceMode resource_mode,
- PaintFlags& flags,
- const AffineTransform* additional_paint_server_transform) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object_);
- if (!resources)
+ const SVGPaint& paint,
+ const AffineTransform* additional_paint_server_transform,
+ PaintFlags& flags) {
+ SVGElementResourceClient* client = SVGResources::GetClient(layout_object_);
+ auto* uri_resource = GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ *client, paint.Resource());
+ if (!uri_resource)
return false;
- const bool apply_to_fill = resource_mode == kApplyToFillMode;
- LayoutSVGResourcePaintServer* uri_resource =
- apply_to_fill ? resources->Fill() : resources->Stroke();
- if (!uri_resource || !uri_resource->ApplyShader(
- *SVGResources::GetClient(layout_object_),
- SVGResources::ReferenceBoxForEffects(layout_object_),
- additional_paint_server_transform, flags))
+ if (!uri_resource->ApplyShader(
+ *client, SVGResources::ReferenceBoxForEffects(layout_object_),
+ additional_paint_server_transform, flags))
return false;
return true;
}
@@ -91,24 +71,21 @@ bool SVGObjectPainter::PreparePaint(
}
const bool apply_to_fill = resource_mode == kApplyToFillMode;
- const SVGComputedStyle& svg_style = style.SvgStyle();
const SVGPaint& paint =
- apply_to_fill ? svg_style.FillPaint() : svg_style.StrokePaint();
+ apply_to_fill ? style.FillPaint() : style.StrokePaint();
const float alpha =
- apply_to_fill ? svg_style.FillOpacity() : svg_style.StrokeOpacity();
+ apply_to_fill ? style.FillOpacity() : style.StrokeOpacity();
if (paint.HasUrl()) {
- if (ApplyPaintResource(resource_mode, flags,
- additional_paint_server_transform)) {
+ if (ApplyPaintResource(paint, additional_paint_server_transform, flags)) {
flags.setColor(ScaleAlpha(SK_ColorBLACK, alpha));
CopyStateFromGraphicsContext(paint_info.context, flags);
return true;
}
}
if (paint.HasColor()) {
- const SVGPaint& visited_paint =
- apply_to_fill ? svg_style.InternalVisitedFillPaint()
- : svg_style.InternalVisitedStrokePaint();
- const Color color = ResolveColor(style, paint, visited_paint);
+ const CSSProperty& property =
+ apply_to_fill ? GetCSSPropertyFill() : GetCSSPropertyStroke();
+ const Color color = style.VisitedDependentColor(property);
flags.setColor(ScaleAlpha(color.Rgb(), alpha));
flags.setShader(nullptr);
CopyStateFromGraphicsContext(paint_info.context, flags);
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.h
index 117d56c3f0c..2be9fa3f5c2 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_object_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_object_painter.h
@@ -44,9 +44,9 @@ class SVGObjectPainter {
private:
bool ApplyPaintResource(
- LayoutSVGResourceMode resource_mode,
- PaintFlags& flags,
- const AffineTransform* additional_paint_server_transform);
+ const SVGPaint& paint,
+ const AffineTransform* additional_paint_server_transform,
+ PaintFlags& flags);
const LayoutObject& layout_object_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
index 19ba1fe6e84..a3a977b7508 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
@@ -22,11 +22,10 @@ void SVGRootInlineBoxPainter::Paint(const PaintInfo& paint_info,
DCHECK(paint_info.phase == PaintPhase::kForeground ||
paint_info.phase == PaintPhase::kSelectionDragImage);
- bool has_selection =
- !paint_info.IsPrinting() && svg_root_inline_box_.IsSelected();
-
const auto& layout_object = *LineLayoutAPIShim::ConstLayoutObjectFrom(
svg_root_inline_box_.GetLineLayoutItem());
+ bool has_selection = !layout_object.GetDocument().Printing() &&
+ svg_root_inline_box_.IsSelected();
if (has_selection &&
!DrawingRecorder::UseCachedDrawingIfPossible(
paint_info.context, layout_object, paint_info.phase)) {
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
index 727902ac0f9..65c8fd21b21 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_marker_data.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_timing.h"
#include "third_party/blink/renderer/core/paint/scoped_svg_paint_state.h"
@@ -36,10 +35,10 @@ static base::Optional<AffineTransform> SetupNonScalingStrokeContext(
}
static SkPathFillType FillRuleFromStyle(const PaintInfo& paint_info,
- const SVGComputedStyle& svg_style) {
+ const ComputedStyle& style) {
return WebCoreWindRuleToSkFillType(paint_info.IsRenderingClipPathAsMaskImage()
- ? svg_style.ClipRule()
- : svg_style.FillRule());
+ ? style.ClipRule()
+ : style.FillRule());
}
void SVGShapePainter::Paint(const PaintInfo& paint_info) {
@@ -59,32 +58,32 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
ScopedSVGTransformState transform_state(paint_info, layout_svg_shape_);
{
ScopedSVGPaintState paint_state(layout_svg_shape_, paint_info);
+ SVGModelObjectPainter::RecordHitTestData(layout_svg_shape_, paint_info);
if (!DrawingRecorder::UseCachedDrawingIfPossible(
paint_info.context, layout_svg_shape_, paint_info.phase)) {
- SVGModelObjectPainter::RecordHitTestData(layout_svg_shape_, paint_info);
SVGDrawingRecorder recorder(paint_info.context, layout_svg_shape_,
paint_info.phase);
- const SVGComputedStyle& svg_style =
- layout_svg_shape_.StyleRef().SvgStyle();
+ const ComputedStyle& style = layout_svg_shape_.StyleRef();
- bool should_anti_alias = svg_style.ShapeRendering() != SR_CRISPEDGES &&
- svg_style.ShapeRendering() != SR_OPTIMIZESPEED;
+ bool should_anti_alias =
+ style.ShapeRendering() != EShapeRendering::kCrispedges &&
+ style.ShapeRendering() != EShapeRendering::kOptimizespeed;
for (int i = 0; i < 3; i++) {
- switch (svg_style.PaintOrderType(i)) {
+ switch (style.PaintOrderType(i)) {
case PT_FILL: {
PaintFlags fill_flags;
if (!SVGObjectPainter(layout_svg_shape_)
- .PreparePaint(paint_info, layout_svg_shape_.StyleRef(),
- kApplyToFillMode, fill_flags))
+ .PreparePaint(paint_info, style, kApplyToFillMode,
+ fill_flags))
break;
fill_flags.setAntiAlias(should_anti_alias);
FillShape(paint_info.context, fill_flags,
- FillRuleFromStyle(paint_info, svg_style));
+ FillRuleFromStyle(paint_info, style));
break;
}
case PT_STROKE:
- if (svg_style.HasVisibleStroke()) {
+ if (style.HasVisibleStroke()) {
GraphicsContextStateSaver state_saver(paint_info.context, false);
base::Optional<AffineTransform> non_scaling_transform;
@@ -100,15 +99,14 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
PaintFlags stroke_flags;
if (!SVGObjectPainter(layout_svg_shape_)
.PreparePaint(
- paint_info, layout_svg_shape_.StyleRef(),
- kApplyToStrokeMode, stroke_flags,
+ paint_info, style, kApplyToStrokeMode, stroke_flags,
base::OptionalOrNullptr(non_scaling_transform)))
break;
stroke_flags.setAntiAlias(should_anti_alias);
StrokeData stroke_data;
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(
- stroke_data, layout_svg_shape_.StyleRef(), layout_svg_shape_,
+ stroke_data, style, layout_svg_shape_,
layout_svg_shape_.DashScaleFactor());
stroke_data.SetupPaint(&stroke_flags);
@@ -171,7 +169,7 @@ void SVGShapePainter::FillShape(GraphicsContext& context,
void SVGShapePainter::StrokeShape(GraphicsContext& context,
const PaintFlags& flags) {
- DCHECK(layout_svg_shape_.StyleRef().SvgStyle().HasVisibleStroke());
+ DCHECK(layout_svg_shape_.StyleRef().HasVisibleStroke());
switch (layout_svg_shape_.GeometryCodePath()) {
case kRectGeometryFastPath:
@@ -200,15 +198,14 @@ void SVGShapePainter::PaintMarkers(const PaintInfo& paint_info) {
layout_svg_shape_.MarkerPositions();
if (!marker_positions || marker_positions->IsEmpty())
return;
-
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_svg_shape_);
- if (!resources)
- return;
-
- LayoutSVGResourceMarker* marker_start = resources->MarkerStart();
- LayoutSVGResourceMarker* marker_mid = resources->MarkerMid();
- LayoutSVGResourceMarker* marker_end = resources->MarkerEnd();
+ SVGResourceClient* client = SVGResources::GetClient(layout_svg_shape_);
+ const ComputedStyle& style = layout_svg_shape_.StyleRef();
+ auto* marker_start = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerStartResource());
+ auto* marker_mid = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerMidResource());
+ auto* marker_end = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ *client, style.MarkerEndResource());
if (!marker_start && !marker_mid && !marker_end)
return;
@@ -241,7 +238,7 @@ void SVGShapePainter::PaintMarker(const PaintInfo& paint_info,
if (SVGLayoutSupport::IsOverflowHidden(marker))
canvas->clipRect(marker.Viewport());
- PaintRecordBuilder builder(nullptr, &paint_info.context);
+ PaintRecordBuilder builder(paint_info.context);
PaintInfo marker_paint_info(builder.Context(), paint_info);
// It's expensive to track the transformed paint cull rect for each
// marker so just disable culling. The shape paint call will already
diff --git a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
index 9e80e295120..7beb50752e1 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
@@ -15,7 +15,13 @@ using testing::ElementsAre;
namespace blink {
-using TablePainterTest = PaintControllerPaintTest;
+class TablePainterTest : public PaintControllerPaintTest,
+ private ScopedLayoutNGTableForTest {
+ protected:
+ TablePainterTest() : ScopedLayoutNGTableForTest(false) {}
+};
+
+// using TablePainterTest = PaintControllerPaintTest;
INSTANTIATE_PAINT_TEST_SUITE_P(TablePainterTest);
TEST_P(TablePainterTest, Background) {
@@ -109,11 +115,9 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
SetBodyInnerHTML(R"HTML(
<style>
body { margin: 0 }
- td { width: 200px; height: 200px; border: 0; background-color: green;
- }
+ td { width: 200px; height: 200px; border: 0; background-color: green; }
tr { background-color: blue; opacity: 0.5; }
- table { border: none; border-spacing: 100px; border-collapse:
- separate; }
+ table { border: none; border-spacing: 100px; border-collapse: separate; }
</style>
<table>
<tr id='row'><td id='cell1'><td id='cell2'></td></tr>
diff --git a/chromium/third_party/blink/renderer/core/paint/text_decoration_info.h b/chromium/third_party/blink/renderer/core/paint/text_decoration_info.h
index 31f05538ecc..9651589b253 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_decoration_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_decoration_info.h
@@ -33,6 +33,8 @@ enum class ResolvedUnderlinePosition {
// invalidation and painting. See also
// https://www.w3.org/TR/css-text-decor-3/#painting-order
class CORE_EXPORT TextDecorationInfo {
+ STACK_ALLOCATED();
+
public:
TextDecorationInfo(
const PhysicalOffset& box_origin,
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
index ecca4197cf8..e8317a47408 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -49,6 +49,9 @@ void LargestTextPaintManager::PopulateTraceValue(
value.SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame());
value.SetBoolean("isOOPIF",
!frame_view_->GetFrame().LocalFrameRoot().IsMainFrame());
+ if (first_text_paint.lcp_rect_info_) {
+ first_text_paint.lcp_rect_info_->OutputToTraceValue(value);
+ }
}
void LargestTextPaintManager::ReportCandidateToTrace(
@@ -101,11 +104,12 @@ void TextPaintTimingDetector::OnPaintFinished() {
.UpdateLargestContentfulPaintCandidate();
}
if (records_manager_.NeedMeausuringPaintTime()) {
- if (!awaiting_swap_promise_) {
+ if (!awaiting_presentation_promise_) {
// |WrapCrossThreadWeakPersistent| guarantees that when |this| is killed,
// the callback function will not be invoked.
- RegisterNotifySwapTime(WTF::Bind(&TextPaintTimingDetector::ReportSwapTime,
- WrapCrossThreadWeakPersistent(this)));
+ RegisterNotifyPresentationTime(
+ WTF::Bind(&TextPaintTimingDetector::ReportPresentationTime,
+ WrapCrossThreadWeakPersistent(this)));
}
}
}
@@ -121,13 +125,14 @@ void TextPaintTimingDetector::LayoutObjectWillBeDestroyed(
}
}
-void TextPaintTimingDetector::RegisterNotifySwapTime(
+void TextPaintTimingDetector::RegisterNotifyPresentationTime(
PaintTimingCallbackManager::LocalThreadCallback callback) {
callback_manager_->RegisterCallback(std::move(callback));
- awaiting_swap_promise_ = true;
+ awaiting_presentation_promise_ = true;
}
-void TextPaintTimingDetector::ReportSwapTime(base::TimeTicks timestamp) {
+void TextPaintTimingDetector::ReportPresentationTime(
+ base::TimeTicks timestamp) {
if (!records_manager_.HasTextElementTiming()) {
Document* document = frame_view_->GetFrame().GetDocument();
if (document) {
@@ -141,7 +146,7 @@ void TextPaintTimingDetector::ReportSwapTime(base::TimeTicks timestamp) {
records_manager_.AssignPaintTimeToQueuedRecords(timestamp);
if (IsRecordingLargestTextPaint())
UpdateCandidate();
- awaiting_swap_promise_ = false;
+ awaiting_presentation_promise_ = false;
}
bool TextPaintTimingDetector::ShouldWalkObject(
@@ -183,8 +188,9 @@ void TextPaintTimingDetector::RecordAggregatedText(
if (IgnorePaintTimingScope::IgnoreDepth() == 1) {
if (IgnorePaintTimingScope::IsDocumentElementInvisible() &&
records_manager_.IsRecordingLargestTextPaint()) {
- records_manager_.MaybeUpdateLargestIgnoredText(aggregator,
- aggregated_size);
+ records_manager_.MaybeUpdateLargestIgnoredText(
+ aggregator, aggregated_size, aggregated_visual_rect,
+ mapped_visual_rect);
}
return;
}
@@ -196,7 +202,8 @@ void TextPaintTimingDetector::RecordAggregatedText(
aggregator, aggregated_size,
TextElementTiming::ComputeIntersectionRect(
aggregator, aggregated_visual_rect, property_tree_state,
- frame_view_));
+ frame_view_),
+ aggregated_visual_rect, mapped_visual_rect);
if (base::Optional<PaintTimingVisualizer>& visualizer =
frame_view_->GetPaintTimingDetector().Visualizer()) {
visualizer->DumpTextDebuggingRect(aggregator, mapped_visual_rect);
@@ -227,14 +234,16 @@ LargestTextPaintManager::LargestTextPaintManager(
void LargestTextPaintManager::MaybeUpdateLargestIgnoredText(
const LayoutObject& object,
- const uint64_t& size) {
+ const uint64_t& size,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect) {
if (size &&
(!largest_ignored_text_ || size > largest_ignored_text_->first_size)) {
Node* node = object.GetNode();
DCHECK(node);
DOMNodeId node_id = DOMNodeIds::IdForNode(node);
- largest_ignored_text_ =
- std::make_unique<TextRecord>(node_id, size, FloatRect());
+ largest_ignored_text_ = std::make_unique<TextRecord>(
+ node_id, size, FloatRect(), frame_visual_rect, root_visual_rect);
}
}
@@ -255,7 +264,7 @@ void TextRecordsManager::RemoveVisibleRecord(const LayoutObject& object) {
}
void TextRecordsManager::CleanUpLargestTextPaint() {
- ltp_manager_.reset();
+ ltp_manager_.Clear();
}
void TextRecordsManager::RemoveInvisibleRecord(const LayoutObject& object) {
@@ -302,7 +311,9 @@ void TextRecordsManager::AssignPaintTimeToQueuedRecords(
void TextRecordsManager::RecordVisibleObject(
const LayoutObject& object,
const uint64_t& visual_size,
- const FloatRect& element_timing_rect) {
+ const FloatRect& element_timing_rect,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect) {
DCHECK_GT(visual_size, 0u);
Node* node = object.GetNode();
@@ -310,7 +321,8 @@ void TextRecordsManager::RecordVisibleObject(
DOMNodeId node_id = DOMNodeIds::IdForNode(node);
DCHECK_NE(node_id, kInvalidDOMNodeId);
std::unique_ptr<TextRecord> record =
- std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect);
+ std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect,
+ frame_visual_rect, root_visual_rect);
base::WeakPtr<TextRecord> record_weak_ptr = record->AsWeakPtr();
if (ltp_manager_)
ltp_manager_->InsertRecord(record_weak_ptr);
@@ -328,8 +340,8 @@ void TextRecordsManager::RecordInvisibleObject(const LayoutObject& object) {
DOMNodeId node_id = DOMNodeIds::IdForNode(node);
DCHECK_NE(node_id, kInvalidDOMNodeId);
// Since it is invisible, the record will have a size of 0 and an empty rect.
- std::unique_ptr<TextRecord> record =
- std::make_unique<TextRecord>(node_id, 0, FloatRect());
+ std::unique_ptr<TextRecord> record = std::make_unique<TextRecord>(
+ node_id, 0, FloatRect(), IntRect(), FloatRect());
size_zero_texts_queued_for_paint_time_.push_back(std::move(record));
}
@@ -368,9 +380,10 @@ base::WeakPtr<TextRecord> LargestTextPaintManager::FindLargestPaintCandidate() {
TextRecordsManager::TextRecordsManager(
LocalFrameView* frame_view,
- PaintTimingDetector* paint_timing_detector) {
- ltp_manager_.emplace(frame_view, paint_timing_detector);
-}
+ PaintTimingDetector* paint_timing_detector)
+ : ltp_manager_(MakeGarbageCollected<LargestTextPaintManager>(
+ frame_view,
+ paint_timing_detector)) {}
void TextRecordsManager::Trace(Visitor* visitor) const {
visitor->Trace(text_element_timing_);
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index 306a623f98e..c1c0e63a8cf 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -9,7 +9,6 @@
#include <queue>
#include <set>
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/text_element_timing.h"
@@ -28,12 +27,18 @@ class TextRecord : public base::SupportsWeakPtr<TextRecord> {
public:
TextRecord(DOMNodeId new_node_id,
uint64_t new_first_size,
- const FloatRect& element_timing_rect)
+ const FloatRect& element_timing_rect,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect)
: node_id(new_node_id),
first_size(new_first_size),
element_timing_rect_(element_timing_rect) {
static unsigned next_insertion_index_ = 1;
insertion_index_ = next_insertion_index_++;
+ if (PaintTimingVisualizer::IsTracingEnabled()) {
+ lcp_rect_info_ = std::make_unique<LCPRectInfo>(
+ frame_visual_rect, RoundedIntRect(root_visual_rect));
+ }
}
TextRecord(const TextRecord&) = delete;
TextRecord& operator=(const TextRecord&) = delete;
@@ -44,12 +49,13 @@ class TextRecord : public base::SupportsWeakPtr<TextRecord> {
// for ranking.
unsigned insertion_index_ = 0;
FloatRect element_timing_rect_;
+ std::unique_ptr<LCPRectInfo> lcp_rect_info_;
// The time of the first paint after fully loaded.
base::TimeTicks paint_time = base::TimeTicks();
};
-class CORE_EXPORT LargestTextPaintManager {
- DISALLOW_NEW();
+class CORE_EXPORT LargestTextPaintManager final
+ : public GarbageCollected<LargestTextPaintManager> {
using TextRecordSetComparator = bool (*)(const base::WeakPtr<TextRecord>&,
const base::WeakPtr<TextRecord>&);
using TextRecordSet =
@@ -83,7 +89,10 @@ class CORE_EXPORT LargestTextPaintManager {
SetCachedResultInvalidated(true);
}
- void MaybeUpdateLargestIgnoredText(const LayoutObject&, const uint64_t&);
+ void MaybeUpdateLargestIgnoredText(const LayoutObject&,
+ const uint64_t&,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect);
std::unique_ptr<TextRecord> PopLargestIgnoredText() {
return std::move(largest_ignored_text_);
}
@@ -128,7 +137,9 @@ class CORE_EXPORT TextRecordsManager {
void RemoveInvisibleRecord(const LayoutObject&);
void RecordVisibleObject(const LayoutObject&,
const uint64_t& visual_size,
- const FloatRect& element_timing_rect);
+ const FloatRect& element_timing_rect,
+ const IntRect& frame_visual_rect,
+ const FloatRect& root_visual_rect);
void RecordInvisibleObject(const LayoutObject& object);
bool NeedMeausuringPaintTime() const {
return !texts_queued_for_paint_time_.IsEmpty() ||
@@ -165,18 +176,19 @@ class CORE_EXPORT TextRecordsManager {
// opacity. May update |largest_ignored_text_| if the new candidate has a
// larger size.
void MaybeUpdateLargestIgnoredText(const LayoutObject& object,
- const uint64_t& size) {
+ const uint64_t& size,
+ const IntRect& aggregated_visual_rect,
+ const FloatRect& mapped_visual_rect) {
DCHECK(ltp_manager_);
- ltp_manager_->MaybeUpdateLargestIgnoredText(object, size);
+ ltp_manager_->MaybeUpdateLargestIgnoredText(
+ object, size, aggregated_visual_rect, mapped_visual_rect);
}
// Called when documentElement changes from zero to nonzero opacity. Makes the
// largest text that was hidden due to this a Largest Contentful Paint
// candidate.
void ReportLargestIgnoredText();
- inline bool IsRecordingLargestTextPaint() const {
- return ltp_manager_.has_value();
- }
+ inline bool IsRecordingLargestTextPaint() const { return ltp_manager_; }
void Trace(Visitor*) const;
@@ -199,7 +211,7 @@ class CORE_EXPORT TextRecordsManager {
// LCP computations, even if the size of the text itself is not 0. They are
// considered invisible objects by Largest Contentful Paint.
Deque<std::unique_ptr<TextRecord>> size_zero_texts_queued_for_paint_time_;
- base::Optional<LargestTextPaintManager> ltp_manager_;
+ Member<LargestTextPaintManager> ltp_manager_;
Member<TextElementTiming> text_element_timing_;
};
@@ -247,21 +259,21 @@ class CORE_EXPORT TextPaintTimingDetector final
return records_manager_.UpdateCandidate();
}
void ReportLargestIgnoredText();
- void ReportSwapTime(base::TimeTicks timestamp);
+ void ReportPresentationTime(base::TimeTicks timestamp);
void Trace(Visitor*) const;
private:
friend class LargestContentfulPaintCalculatorTest;
- void RegisterNotifySwapTime(
+ void RegisterNotifyPresentationTime(
PaintTimingCallbackManager::LocalThreadCallback callback);
TextRecordsManager records_manager_;
Member<PaintTimingCallbackManager> callback_manager_;
- // Make sure that at most one swap promise is ongoing.
- bool awaiting_swap_promise_ = false;
+ // Make sure that at most one presentation promise is ongoing.
+ bool awaiting_presentation_promise_ = false;
bool need_update_timing_at_frame_end_ = false;
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
index f7dc0cd36a1..63fc7b0ed8b 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -73,7 +73,7 @@ class TextPaintTimingDetectorTest : public testing::Test {
.GetTextPaintTimingDetector();
}
- base::Optional<LargestTextPaintManager>& GetLargestTextPaintManager() {
+ LargestTextPaintManager* GetLargestTextPaintManager() {
return GetTextPaintTimingDetector()->records_manager_.ltp_manager_;
}
@@ -117,17 +117,18 @@ class TextPaintTimingDetectorTest : public testing::Test {
void InvokeCallback() {
DCHECK_GT(mock_callback_manager_->CountCallbacks(), 0u);
- InvokeSwapTimeCallback(mock_callback_manager_);
+ InvokePresentationTimeCallback(mock_callback_manager_);
}
- void ChildFrameSwapTimeCallBack() {
+ void ChildFramePresentationTimeCallBack() {
DCHECK_GT(child_frame_mock_callback_manager_->CountCallbacks(), 0u);
- InvokeSwapTimeCallback(child_frame_mock_callback_manager_);
+ InvokePresentationTimeCallback(child_frame_mock_callback_manager_);
}
- void InvokeSwapTimeCallback(
+ void InvokePresentationTimeCallback(
MockPaintTimingCallbackManager* callback_manager) {
- callback_manager->InvokeSwapTimeCallback(test_task_runner_->NowTicks());
+ callback_manager->InvokePresentationTimeCallback(
+ test_task_runner_->NowTicks());
// Outside the tests, this is invoked by
// |PaintTimingCallbackManagerImpl::ReportPaintTime|.
GetLargestTextPaintManager()->UpdateCandidate();
@@ -176,17 +177,17 @@ class TextPaintTimingDetectorTest : public testing::Test {
static constexpr base::TimeDelta kQuantumOfTime =
base::TimeDelta::FromMilliseconds(10);
- // This only triggers ReportSwapTime in main frame.
- void UpdateAllLifecyclePhasesAndSimulateSwapTime() {
+ // This only triggers ReportPresentationTime in main frame.
+ void UpdateAllLifecyclePhasesAndSimulatePresentationTime() {
UpdateAllLifecyclePhases();
- // Advance the clock for a bit so different swap callbacks get different
- // times.
+ // Advance the clock for a bit so different presentation callbacks get
+ // different times.
AdvanceClock(kQuantumOfTime);
while (mock_callback_manager_->CountCallbacks() > 0)
InvokeCallback();
}
- size_t CountPendingSwapTime(LocalFrameView& frame_view) {
+ size_t CountPendingPresentationTime(LocalFrameView& frame_view) {
TextPaintTimingDetector* detector =
frame_view.GetPaintTimingDetector().GetTextPaintTimingDetector();
return detector->records_manager_.texts_queued_for_paint_time_.size();
@@ -280,7 +281,7 @@ INSTANTIATE_TEST_SUITE_P(All,
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_NoText) {
SetBodyInnerHTML(R"HTML(
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_FALSE(TextRecordOfLargestTextPaint());
}
@@ -288,7 +289,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_OneText) {
SetBodyInnerHTML(R"HTML(
)HTML");
Element* only_text = AppendDivElementToBody("The only text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(only_text));
}
@@ -299,7 +300,7 @@ TEST_F(TextPaintTimingDetectorTest, InsertionOrderIsSecondaryRankingKey) {
Element* first = AppendDivElementToBody("text");
AppendDivElementToBody("text");
AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(first));
EXPECT_EQ(LargestPaintSize(), ExperimentalLargestPaintSize());
@@ -313,7 +314,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_TraceEvent_Candidate) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("The only text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
}
auto analyzer = trace_analyzer::Stop();
trace_analyzer::TraceEventVector events;
@@ -344,6 +345,97 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_TraceEvent_Candidate) {
bool is_oopif;
EXPECT_TRUE(arg_dict->GetBoolean("isOOPIF", &is_oopif));
EXPECT_EQ(false, is_oopif);
+ int x;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_x", &x));
+ EXPECT_GT(x, 0);
+ int y;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_y", &y));
+ EXPECT_GT(y, 0);
+ int width;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_width", &width));
+ EXPECT_GT(width, 0);
+ int height;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_height", &height));
+ EXPECT_GT(height, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_x", &x));
+ EXPECT_GT(x, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_y", &y));
+ EXPECT_GT(y, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_width", &width));
+ EXPECT_GT(width, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_height", &height));
+ EXPECT_GT(height, 0);
+}
+
+TEST_F(TextPaintTimingDetectorTest,
+ LargestTextPaint_TraceEvent_Candidate_Frame) {
+ using trace_analyzer::Query;
+ trace_analyzer::Start("*");
+ {
+ GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin: 15px; } iframe { display: block; position: relative; margin-top: 50px; } </style>
+ <iframe> </iframe>
+ )HTML");
+ SetChildBodyInnerHTML(R"HTML(
+ <style>body { margin: 10px;} #target { width: 200px; height: 200px; }
+ </style>
+ <div>Some content</div>
+ )HTML");
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
+ ChildFramePresentationTimeCallBack();
+ }
+ auto analyzer = trace_analyzer::Stop();
+ trace_analyzer::TraceEventVector events;
+ Query q = Query::EventNameIs("LargestTextPaint::Candidate");
+ analyzer->FindEvents(q, &events);
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ("loading", events[0]->category);
+
+ EXPECT_TRUE(events[0]->HasArg("frame"));
+
+ EXPECT_TRUE(events[0]->HasArg("data"));
+ std::unique_ptr<base::Value> arg;
+ EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg));
+ base::DictionaryValue* arg_dict;
+ EXPECT_TRUE(arg->GetAsDictionary(&arg_dict));
+ DOMNodeId node_id;
+ EXPECT_TRUE(arg_dict->GetInteger("DOMNodeId", &node_id));
+ EXPECT_GT(node_id, 0);
+ int size;
+ EXPECT_TRUE(arg_dict->GetInteger("size", &size));
+ EXPECT_GT(size, 0);
+ DOMNodeId candidate_index;
+ EXPECT_TRUE(arg_dict->GetInteger("candidateIndex", &candidate_index));
+ EXPECT_EQ(candidate_index, 1);
+ bool is_main_frame;
+ EXPECT_TRUE(arg_dict->GetBoolean("isMainFrame", &is_main_frame));
+ EXPECT_EQ(false, is_main_frame);
+ bool is_oopif;
+ EXPECT_TRUE(arg_dict->GetBoolean("isOOPIF", &is_oopif));
+ EXPECT_EQ(false, is_oopif);
+ int x;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_x", &x));
+ EXPECT_EQ(x, 10);
+ int y;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_y", &y));
+ // There's sometimes a 1 pixel offset for the y dimensions.
+ EXPECT_GE(y, 9);
+ EXPECT_LE(y, 10);
+ int width;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_width", &width));
+ EXPECT_GT(width, 0);
+ int height;
+ EXPECT_TRUE(arg_dict->GetInteger("frame_height", &height));
+ EXPECT_GT(height, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_x", &x));
+ EXPECT_GT(x, 25);
+ EXPECT_TRUE(arg_dict->GetInteger("root_y", &y));
+ EXPECT_GT(y, 50);
+ EXPECT_TRUE(arg_dict->GetInteger("root_width", &width));
+ EXPECT_GT(width, 0);
+ EXPECT_TRUE(arg_dict->GetInteger("root_height", &height));
+ EXPECT_GT(height, 0);
}
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_TraceEvent_NoCandidate) {
@@ -353,7 +445,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_TraceEvent_NoCandidate) {
SetBodyInnerHTML(R"HTML(
)HTML");
Element* element = AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
RemoveElement(element);
UpdateAllLifecyclePhases();
EXPECT_GT(LargestPaintSize(), 0u);
@@ -396,7 +488,7 @@ TEST_F(TextPaintTimingDetectorTest, AggregationBySelfPaintingInlineElement) {
</div>
)HTML");
Element* span = GetDocument().getElementById("target");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(span));
}
@@ -410,11 +502,12 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_OpacityZero) {
</style>
)HTML");
AppendDivElementToBody("The only text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 0u);
}
-TEST_F(TextPaintTimingDetectorTest, NodeRemovedBeforeAssigningSwapTime) {
+TEST_F(TextPaintTimingDetectorTest,
+ NodeRemovedBeforeAssigningPresentationTime) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
<div id="remove">The only text</div>
@@ -431,13 +524,13 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_LargestText) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("medium text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
Element* large_text = AppendDivElementToBody("a long-long-long text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
AppendDivElementToBody("small");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(large_text));
@@ -450,7 +543,7 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
SetBodyInnerHTML(R"HTML(
<div>small text</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
base::TimeTicks time2 = NowTicks();
base::TimeTicks first_largest = LargestPaintTime();
EXPECT_GE(first_largest, time1);
@@ -458,7 +551,7 @@ TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) {
EXPECT_EQ(first_largest, ExperimentalLargestPaintTime());
AppendDivElementToBody("a long-long-long text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
base::TimeTicks time3 = NowTicks();
base::TimeTicks second_largest = LargestPaintTime();
EXPECT_GE(second_largest, time2);
@@ -474,7 +567,8 @@ TEST_F(TextPaintTimingDetectorTest, PendingTextIsLargest) {
)HTML");
AppendDivElementToBody("text");
GetFrameView().UpdateAllLifecyclePhasesForTest();
- // We do not call swap-time callback here in order to not set the paint time.
+ // We do not call presentation-time callback here in order to not set the
+ // paint time.
EXPECT_FALSE(TextRecordOfLargestTextPaint());
}
@@ -499,11 +593,11 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportFirstPaintTime) {
SetBodyInnerHTML(R"HTML(
)HTML");
Element* text = AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
AdvanceClock(base::TimeDelta::FromSecondsD(1));
text->setAttribute(html_names::kStyleAttr,
AtomicString("position:fixed;left:30px"));
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
AdvanceClock(base::TimeDelta::FromSecondsD(1));
base::WeakPtr<TextRecord> record = TextRecordOfLargestTextPaint();
EXPECT_TRUE(record);
@@ -524,7 +618,7 @@ TEST_F(TextPaintTimingDetectorTest,
</style>
<div class='out'>text outside of viewport</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_FALSE(TextRecordOfLargestTextPaint());
}
@@ -535,7 +629,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_RemovedText) {
"(large text)(large text)(large text)(large text)(large text)(large "
"text)");
Element* small_text = AppendDivElementToBody("small text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(large_text));
uint64_t size_before_remove = LargestPaintSize();
@@ -546,7 +640,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_RemovedText) {
EXPECT_GT(time_before_remove, base::TimeTicks());
RemoveElement(large_text);
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(small_text));
// LCP values should remain unchanged.
@@ -561,7 +655,7 @@ TEST_F(TextPaintTimingDetectorTest,
SetBodyInnerHTML(R"HTML(
)HTML");
Element* text = AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(ContainerTotalSize(), 2u);
RemoveElement(text);
@@ -573,18 +667,18 @@ TEST_F(TextPaintTimingDetectorTest,
SetBodyInnerHTML(R"HTML(
)HTML");
Element* text1 = AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(ContainerTotalSize(), 2u);
Element* text2 = AppendDivElementToBody("text2");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(ContainerTotalSize(), 4u);
RemoveElement(text1);
EXPECT_EQ(ContainerTotalSize(), 2u);
GetDocument().body()->AppendChild(text1);
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(ContainerTotalSize(), 4u);
RemoveElement(text1);
@@ -599,7 +693,7 @@ TEST_F(TextPaintTimingDetectorTest,
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_TRUE(GetLargestTextPaintManager());
SimulateInputEvent();
@@ -610,7 +704,7 @@ TEST_F(TextPaintTimingDetectorTest, KeepLargestTextPaintMangerAfterUserInput) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_TRUE(GetLargestTextPaintManager());
SimulateKeyUp();
@@ -621,7 +715,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) {
SetBodyInnerHTML(R"HTML(
)HTML");
Element* text = AppendDivElementToBody("text to remove");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(text));
base::TimeTicks largest_paint_time = LargestPaintTime();
@@ -632,7 +726,7 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) {
EXPECT_EQ(largest_paint_size, ExperimentalLargestPaintSize());
RemoveElement(text);
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_FALSE(TextRecordOfLargestTextPaint());
// LCP values should remain unchanged.
EXPECT_EQ(largest_paint_time, LargestPaintTime());
@@ -648,7 +742,7 @@ TEST_F(TextPaintTimingDetectorTest,
)HTML");
AppendDivElementToBody("a long text", "position:fixed;left:-10px");
Element* short_text = AppendDivElementToBody("short");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(short_text));
}
@@ -658,11 +752,11 @@ TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_CompareSizesAtFirstPaint) {
)HTML");
Element* shortening_long_text = AppendDivElementToBody("123456789");
AppendDivElementToBody("12345678"); // 1 letter shorter than the above.
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
// The visual size becomes smaller when less portion intersecting with
// viewport.
SetElementStyle(shortening_long_text, "position:fixed;left:-10px");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(shortening_long_text));
}
@@ -675,7 +769,7 @@ TEST_F(TextPaintTimingDetectorTest, TreatEllipsisAsText) {
00000000000000000000000000000000000000000000000000000000000000000000000000
</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
}
@@ -683,7 +777,7 @@ TEST_F(TextPaintTimingDetectorTest, TreatEllipsisAsText) {
TEST_F(TextPaintTimingDetectorTest, CaptureFileUploadController) {
SetBodyInnerHTML("<input type='file'>");
Element* element = GetDocument().QuerySelector("input");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
@@ -699,7 +793,7 @@ TEST_P(ParameterizedTextPaintTimingDetectorTest, CapturingListMarkers) {
<li>Another list item</li>
</ol>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), LayoutNGEnabled() ? 3u : 2u);
}
@@ -712,7 +806,7 @@ TEST_F(TextPaintTimingDetectorTest, CaptureSVGText) {
)HTML");
auto* elem = To<SVGTextContentElement>(GetDocument().QuerySelector("text"));
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
@@ -724,7 +818,7 @@ TEST_F(TextPaintTimingDetectorTest, NormalTextUnclipped) {
SetBodyInnerHTML(R"HTML(
<div id='d'>text</div>
)HTML");
- EXPECT_EQ(CountPendingSwapTime(GetFrameView()), 1u);
+ EXPECT_EQ(CountPendingPresentationTime(GetFrameView()), 1u);
EXPECT_EQ(CountVisibleTexts(), 1u);
}
@@ -737,7 +831,7 @@ TEST_F(TextPaintTimingDetectorTest, ClippedByViewport) {
)HTML");
// Make sure the margin-top is larger than the viewport height.
DCHECK_LT(GetViewportRect(GetFrameView()).Height(), 1234567);
- EXPECT_EQ(CountPendingSwapTime(GetFrameView()), 0u);
+ EXPECT_EQ(CountPendingPresentationTime(GetFrameView()), 0u);
EXPECT_EQ(CountVisibleTexts(), 0u);
}
@@ -766,7 +860,7 @@ TEST_F(TextPaintTimingDetectorTest, ClippedByParentVisibleRect) {
div1->AppendChild(text1);
GetDocument().body()->getElementById("outer1")->AppendChild(div1);
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(div1));
EXPECT_EQ(TextRecordOfLargestTextPaint()->first_size, 1u);
@@ -779,7 +873,7 @@ TEST_F(TextPaintTimingDetectorTest, ClippedByParentVisibleRect) {
div2->AppendChild(text2);
GetDocument().body()->getElementById("outer2")->AppendChild(div2);
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(div2));
// This size is larger than the size of the first object . But the exact size
@@ -794,8 +888,8 @@ TEST_F(TextPaintTimingDetectorTest, Iframe) {
)HTML");
SetChildBodyInnerHTML("A");
UpdateAllLifecyclePhases();
- EXPECT_EQ(CountPendingSwapTime(GetChildFrameView()), 1u);
- ChildFrameSwapTimeCallBack();
+ EXPECT_EQ(CountPendingPresentationTime(GetChildFrameView()), 1u);
+ ChildFramePresentationTimeCallBack();
base::WeakPtr<TextRecord> text = ChildFrameTextRecordOfLargestTextPaint();
EXPECT_TRUE(text);
}
@@ -812,7 +906,7 @@ TEST_F(TextPaintTimingDetectorTest, Iframe_ClippedByViewport) {
)HTML");
DCHECK_EQ(GetViewportRect(GetChildFrameView()).Height(), 100);
UpdateAllLifecyclePhases();
- EXPECT_EQ(CountPendingSwapTime(GetChildFrameView()), 0u);
+ EXPECT_EQ(CountPendingPresentationTime(GetChildFrameView()), 0u);
}
TEST_F(TextPaintTimingDetectorTest, SameSizeShouldNotBeIgnored) {
@@ -822,7 +916,7 @@ TEST_F(TextPaintTimingDetectorTest, SameSizeShouldNotBeIgnored) {
<div>text</div>
<div>text</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountRankingSetSize(), 4u);
}
@@ -830,12 +924,12 @@ TEST_F(TextPaintTimingDetectorTest, VisibleTextAfterUserInput) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
EXPECT_TRUE(GetLargestTextPaintManager());
SimulateInputEvent();
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
}
@@ -843,12 +937,12 @@ TEST_F(TextPaintTimingDetectorTest, VisibleTextAfterUserScroll) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("text");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
EXPECT_TRUE(GetLargestTextPaintManager());
SimulateScroll();
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
}
@@ -862,13 +956,13 @@ TEST_F(TextPaintTimingDetectorTest, OpacityZeroHTML) {
</style>
<div>Text</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 0u);
// Change the opacity of documentElement, now the img should be a candidate.
GetDocument().documentElement()->setAttribute(html_names::kStyleAttr,
"opacity: 1");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 1u);
EXPECT_TRUE(TextRecordOfLargestTextPaint());
}
@@ -883,17 +977,17 @@ TEST_F(TextPaintTimingDetectorTest, OpacityZeroHTML2) {
</style>
<div id="target">Text</div>
)HTML");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 0u);
GetDocument().documentElement()->setAttribute(html_names::kStyleAttr,
"opacity: 0");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 0u);
GetDocument().documentElement()->setAttribute(html_names::kStyleAttr,
"opacity: 1");
- UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ UpdateAllLifecyclePhasesAndSimulatePresentationTime();
EXPECT_EQ(CountVisibleTexts(), 0u);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
index db1a2c5fd73..e93d441b8c3 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -78,7 +78,8 @@ void TextPainterBase::UpdateGraphicsContext(
GraphicsContext& context,
const TextPaintStyle& text_style,
bool horizontal,
- GraphicsContextStateSaver& state_saver) {
+ GraphicsContextStateSaver& state_saver,
+ ShadowMode shadow_mode) {
TextDrawingModeFlags mode = context.TextDrawingMode();
if (text_style.stroke_width > 0) {
TextDrawingModeFlags new_mode = mode | kTextModeStroke;
@@ -99,12 +100,49 @@ void TextPainterBase::UpdateGraphicsContext(
context.SetStrokeThickness(text_style.stroke_width);
}
- if (text_style.shadow) {
- state_saver.SaveIfNeeded();
- context.SetDrawLooper(text_style.shadow->CreateDrawLooper(
- DrawLooperBuilder::kShadowIgnoresAlpha, text_style.current_color,
- text_style.color_scheme, horizontal));
+ if (shadow_mode != kTextProperOnly) {
+ DCHECK(shadow_mode == kBothShadowsAndTextProper ||
+ shadow_mode == kShadowsOnly);
+
+ // If there are shadows, we definitely need an SkDrawLooper, but if there
+ // are no shadows (nullptr), we still need one iff we’re in kShadowsOnly
+ // mode, because we suppress text proper by omitting AddUnmodifiedContent
+ // when building a looper (cf. CRC2DState::ShadowAndForegroundDrawLooper).
+ if (text_style.shadow || shadow_mode == kShadowsOnly) {
+ state_saver.SaveIfNeeded();
+ context.SetDrawLooper(CreateDrawLooper(
+ text_style.shadow, DrawLooperBuilder::kShadowIgnoresAlpha,
+ text_style.current_color, text_style.color_scheme, horizontal,
+ shadow_mode));
+ }
+ }
+}
+
+// static
+sk_sp<SkDrawLooper> TextPainterBase::CreateDrawLooper(
+ const ShadowList* shadow_list,
+ DrawLooperBuilder::ShadowAlphaMode alpha_mode,
+ const Color& current_color,
+ mojom::blink::ColorScheme color_scheme,
+ bool is_horizontal,
+ ShadowMode shadow_mode) {
+ DrawLooperBuilder draw_looper_builder;
+
+ // ShadowList nullptr means there are no shadows.
+ if (shadow_mode != kTextProperOnly && shadow_list) {
+ for (wtf_size_t i = shadow_list->Shadows().size(); i--;) {
+ const ShadowData& shadow = shadow_list->Shadows()[i];
+ float shadow_x = is_horizontal ? shadow.X() : shadow.Y();
+ float shadow_y = is_horizontal ? shadow.Y() : -shadow.X();
+ draw_looper_builder.AddShadow(
+ FloatSize(shadow_x, shadow_y), shadow.Blur(),
+ shadow.GetColor().Resolve(current_color, color_scheme),
+ DrawLooperBuilder::kShadowRespectsTransforms, alpha_mode);
+ }
}
+ if (shadow_mode != kShadowsOnly)
+ draw_looper_builder.AddUnmodifiedContent();
+ return draw_looper_builder.DetachDrawLooper();
}
Color TextPainterBase::TextColorForWhiteBackground(Color text_color) {
@@ -120,7 +158,6 @@ TextPaintStyle TextPainterBase::TextPaintingStyle(const Document& document,
TextPaintStyle text_style;
text_style.stroke_width = style.TextStrokeWidth();
text_style.color_scheme = style.UsedColorScheme();
- bool is_printing = paint_info.IsPrinting();
if (paint_info.phase == PaintPhase::kTextClip) {
// When we use the text as a clip, we only care about the alpha, thus we
@@ -142,7 +179,6 @@ TextPaintStyle TextPainterBase::TextPaintingStyle(const Document& document,
text_style.shadow = style.TextShadow();
// Adjust text color when printing with a white background.
- DCHECK_EQ(document.Printing(), is_printing);
bool force_background_to_white =
BoxPainterBase::ShouldForceWhiteBackgroundForPrintEconomy(document,
style);
diff --git a/chromium/third_party/blink/renderer/core/paint/text_painter_base.h b/chromium/third_party/blink/renderer/core/paint/text_painter_base.h
index 82c49b77450..cdcb917369e 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_painter_base.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/style/text_decoration_thickness.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/draw_looper_builder.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
@@ -23,6 +24,7 @@ class ComputedStyle;
class Document;
class GraphicsContext;
class GraphicsContextStateSaver;
+class Node;
class TextDecorationOffsetBase;
struct PaintInfo;
@@ -47,10 +49,19 @@ class CORE_EXPORT TextPainterBase {
void SetEmphasisMark(const AtomicString&, TextEmphasisPosition);
void SetEllipsisOffset(int offset) { ellipsis_offset_ = offset; }
+ enum ShadowMode { kBothShadowsAndTextProper, kShadowsOnly, kTextProperOnly };
static void UpdateGraphicsContext(GraphicsContext&,
const TextPaintStyle&,
bool horizontal,
- GraphicsContextStateSaver&);
+ GraphicsContextStateSaver&,
+ ShadowMode = kBothShadowsAndTextProper);
+ static sk_sp<SkDrawLooper> CreateDrawLooper(
+ const ShadowList* shadow_list,
+ DrawLooperBuilder::ShadowAlphaMode,
+ const Color& current_color,
+ mojom::blink::ColorScheme color_scheme,
+ bool is_horizontal = true,
+ ShadowMode = kBothShadowsAndTextProper);
void PaintDecorationsExceptLineThrough(const TextDecorationOffsetBase&,
TextDecorationInfo&,
diff --git a/chromium/third_party/blink/renderer/core/paint/text_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/text_painter_test.cc
index 2b5abd58190..08ddf3e3979 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_painter_test.cc
@@ -30,12 +30,14 @@ class TextPainterTest : public RenderingTest {
protected:
LineLayoutText GetLineLayoutText() { return LineLayoutText(layout_text_); }
- PaintInfo CreatePaintInfo(bool uses_text_as_clip, bool is_printing) {
- return PaintInfo(
- context_, IntRect(),
- uses_text_as_clip ? PaintPhase::kTextClip
- : PaintPhase::kSelfBlockBackgroundOnly,
- is_printing ? kGlobalPaintPrinting : kGlobalPaintNormalPhase, 0);
+ PaintInfo CreatePaintInfoForBackground() {
+ return PaintInfo(context_, CullRect(), PaintPhase::kSelfBlockBackgroundOnly,
+ kGlobalPaintNormalPhase, 0);
+ }
+
+ PaintInfo CreatePaintInfoForTextClip() {
+ return PaintInfo(context_, CullRect(), PaintPhase::kTextClip,
+ kGlobalPaintNormalPhase, 0);
}
protected:
@@ -63,7 +65,7 @@ TEST_F(TextPainterTest, TextPaintingStyle_Simple) {
TextPaintStyle text_style = TextPainter::TextPaintingStyle(
GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
- CreatePaintInfo(false /* usesTextAsClip */, false /* isPrinting */));
+ CreatePaintInfoForBackground());
EXPECT_EQ(Color(0, 0, 255), text_style.fill_color);
EXPECT_EQ(Color(0, 0, 255), text_style.stroke_color);
EXPECT_EQ(Color(0, 0, 255), text_style.emphasis_mark_color);
@@ -87,7 +89,7 @@ TEST_F(TextPainterTest, TextPaintingStyle_AllProperties) {
TextPaintStyle text_style = TextPainter::TextPaintingStyle(
GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
- CreatePaintInfo(false /* usesTextAsClip */, false /* isPrinting */));
+ CreatePaintInfoForBackground());
EXPECT_EQ(Color(255, 0, 0), text_style.fill_color);
EXPECT_EQ(Color(0, 255, 0), text_style.stroke_color);
EXPECT_EQ(Color(0, 0, 255), text_style.emphasis_mark_color);
@@ -117,7 +119,7 @@ TEST_F(TextPainterTest, TextPaintingStyle_UsesTextAsClip) {
TextPaintStyle text_style = TextPainter::TextPaintingStyle(
GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
- CreatePaintInfo(true /* usesTextAsClip */, false /* isPrinting */));
+ CreatePaintInfoForTextClip());
EXPECT_EQ(Color::kBlack, text_style.fill_color);
EXPECT_EQ(Color::kBlack, text_style.stroke_color);
EXPECT_EQ(Color::kBlack, text_style.emphasis_mark_color);
@@ -145,7 +147,7 @@ TEST_F(TextPainterTest,
TextPaintStyle text_style = TextPainter::TextPaintingStyle(
GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
- CreatePaintInfo(false /* usesTextAsClip */, true /* isPrinting */));
+ CreatePaintInfoForBackground());
EXPECT_EQ(Color(255, 0, 0), text_style.fill_color);
EXPECT_EQ(Color(0, 255, 0), text_style.stroke_color);
EXPECT_EQ(Color(0, 0, 255), text_style.emphasis_mark_color);
@@ -170,7 +172,7 @@ TEST_F(TextPainterTest, TextPaintingStyle_ForceBackgroundToWhite_Darkened) {
TextPaintStyle text_style = TextPainter::TextPaintingStyle(
GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
- CreatePaintInfo(false /* usesTextAsClip */, true /* isPrinting */));
+ CreatePaintInfoForBackground());
EXPECT_EQ(Color(255, 220, 220).Dark(), text_style.fill_color);
EXPECT_EQ(Color(220, 255, 220).Dark(), text_style.stroke_color);
EXPECT_EQ(Color(220, 220, 255).Dark(), text_style.emphasis_mark_color);
diff --git a/chromium/third_party/blink/renderer/core/paint/theme_painter.cc b/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
index b4b35343246..d6a615e130c 100644
--- a/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -23,7 +23,6 @@
#include "build/build_config.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
#include "third_party/blink/renderer/core/html/forms/html_data_list_options_collection.h"
diff --git a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
index 3a69a2f3296..d490a957dfd 100644
--- a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
+++ b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -39,6 +39,8 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "ui/base/ui_base_features.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
namespace blink {
@@ -70,6 +72,8 @@ WebThemeEngine::State GetWebThemeState(const Element& element) {
}
class DirectionFlippingScope {
+ STACK_ALLOCATED();
+
public:
DirectionFlippingScope(const LayoutObject&, const PaintInfo&, const IntRect&);
~DirectionFlippingScope();
@@ -163,15 +167,8 @@ bool ThemePainterDefault::PaintCheckbox(const Element& element,
float zoom_level = style.EffectiveZoom();
extra_params.button.zoom = zoom_level;
GraphicsContextStateSaver state_saver(paint_info.context, false);
- IntRect unzoomed_rect = rect;
- if (zoom_level != 1 && !features::IsFormControlsRefreshEnabled()) {
- state_saver.Save();
- unzoomed_rect.SetWidth(unzoomed_rect.Width() / zoom_level);
- unzoomed_rect.SetHeight(unzoomed_rect.Height() / zoom_level);
- paint_info.context.Translate(unzoomed_rect.X(), unzoomed_rect.Y());
- paint_info.context.Scale(zoom_level, zoom_level);
- paint_info.context.Translate(-unzoomed_rect.X(), -unzoomed_rect.Y());
- }
+ IntRect unzoomed_rect =
+ ApplyZoomToRect(rect, paint_info, state_saver, zoom_level);
Platform::Current()->ThemeEngine()->Paint(
canvas, WebThemeEngine::kPartCheckbox, GetWebThemeState(element),
@@ -189,9 +186,17 @@ bool ThemePainterDefault::PaintRadio(const Element& element,
extra_params.button = WebThemeEngine::ButtonExtraParams();
extra_params.button.checked = IsChecked(element);
+ float zoom_level = style.EffectiveZoom();
+ extra_params.button.zoom = zoom_level;
+ GraphicsContextStateSaver state_saver(paint_info.context, false);
+ IntRect unzoomed_rect =
+ features::IsFormControlsRefreshEnabled()
+ ? ApplyZoomToRect(rect, paint_info, state_saver, zoom_level)
+ : rect;
+
Platform::Current()->ThemeEngine()->Paint(
canvas, WebThemeEngine::kPartRadio, GetWebThemeState(element),
- gfx::Rect(rect), &extra_params, style.UsedColorScheme());
+ gfx::Rect(unzoomed_rect), &extra_params, style.UsedColorScheme());
return false;
}
@@ -205,6 +210,7 @@ bool ThemePainterDefault::PaintButton(const Element& element,
extra_params.button = WebThemeEngine::ButtonExtraParams();
extra_params.button.has_border = true;
extra_params.button.background_color = kDefaultButtonBackgroundColor;
+ extra_params.button.zoom = style.EffectiveZoom();
if (style.HasBackground()) {
extra_params.button.background_color =
style.VisitedDependentColor(GetCSSPropertyBackgroundColor()).Rgb();
@@ -239,6 +245,7 @@ bool ThemePainterDefault::PaintTextField(const Element& element,
extra_params.text_field.is_text_area = part == kTextAreaPart;
extra_params.text_field.is_listbox = part == kListboxPart;
extra_params.text_field.has_border = true;
+ extra_params.text_field.zoom = style.EffectiveZoom();
cc::PaintCanvas* canvas = paint_info.context.Canvas();
@@ -263,6 +270,7 @@ bool ThemePainterDefault::PaintMenuList(const Element& element,
// Match Chromium Win behaviour of showing all borders if any are shown.
extra_params.menu_list.has_border = style.HasBorder();
extra_params.menu_list.has_border_radius = style.HasBorderRadius();
+ extra_params.menu_list.zoom = style.EffectiveZoom();
// Fallback to transparent if the specified color object is invalid.
Color background_color(Color::kTransparent);
if (style.HasBackground()) {
@@ -469,6 +477,7 @@ bool ThemePainterDefault::PaintProgressBar(const Element& element,
extra_params.progress_bar.value_rect_y = value_rect.Y();
extra_params.progress_bar.value_rect_width = value_rect.Width();
extra_params.progress_bar.value_rect_height = value_rect.Height();
+ extra_params.progress_bar.zoom = o.StyleRef().EffectiveZoom();
DirectionFlippingScope scope(o, i, rect);
cc::PaintCanvas* canvas = i.context.Canvas();
@@ -532,14 +541,40 @@ bool ThemePainterDefault::PaintSearchFieldCancelButton(
DEFINE_STATIC_REF(
Image, cancel_pressed_image_dark_mode,
(Image::LoadPlatformResource(IDR_SEARCH_CANCEL_PRESSED_DARK_MODE)));
- Image* color_scheme_adjusted_cancel_image =
- color_scheme == mojom::blink::ColorScheme::kLight
- ? cancel_image
- : cancel_image_dark_mode;
- Image* color_scheme_adjusted_cancel_pressed_image =
- color_scheme == mojom::blink::ColorScheme::kLight
- ? cancel_pressed_image
- : cancel_pressed_image_dark_mode;
+ DEFINE_STATIC_REF(
+ Image, cancel_image_hc_light_mode,
+ (Image::LoadPlatformResource(IDR_SEARCH_CANCEL_HC_LIGHT_MODE)));
+ DEFINE_STATIC_REF(
+ Image, cancel_pressed_image_hc_light_mode,
+ (Image::LoadPlatformResource(IDR_SEARCH_CANCEL_PRESSED_HC_LIGHT_MODE)));
+ Image* color_scheme_adjusted_cancel_image;
+ Image* color_scheme_adjusted_cancel_pressed_image;
+ if (ui::NativeTheme::GetInstanceForWeb()->UserHasContrastPreference()) {
+ // TODO(crbug.com/1159597): Ideally we want the cancel button to be the same
+ // color as search field text. Since the cancel button is currently painted
+ // with a .png, it can't be colored dynamically so currently our only
+ // choices are black and white.
+ Color search_field_text_color =
+ cancel_button_object.StyleRef().VisitedDependentColor(
+ GetCSSPropertyColor());
+ bool text_is_dark = color_utils::GetRelativeLuminance(
+ SkColor(search_field_text_color)) < 0.5;
+ color_scheme_adjusted_cancel_image =
+ text_is_dark ? cancel_image_hc_light_mode : cancel_image_dark_mode;
+ color_scheme_adjusted_cancel_pressed_image =
+ color_scheme_adjusted_cancel_image =
+ text_is_dark ? cancel_pressed_image_hc_light_mode
+ : cancel_pressed_image_dark_mode;
+ } else {
+ color_scheme_adjusted_cancel_image =
+ color_scheme == mojom::blink::ColorScheme::kLight
+ ? cancel_image
+ : cancel_image_dark_mode;
+ color_scheme_adjusted_cancel_pressed_image =
+ color_scheme == mojom::blink::ColorScheme::kLight
+ ? cancel_pressed_image
+ : cancel_pressed_image_dark_mode;
+ }
paint_info.context.DrawImage(
To<Element>(cancel_button_object.GetNode())->IsActive()
? color_scheme_adjusted_cancel_pressed_image
@@ -548,4 +583,22 @@ bool ThemePainterDefault::PaintSearchFieldCancelButton(
return false;
}
+IntRect ThemePainterDefault::ApplyZoomToRect(
+ const IntRect& rect,
+ const PaintInfo& paint_info,
+ GraphicsContextStateSaver& state_saver,
+ float zoom_level) {
+ IntRect unzoomed_rect = rect;
+ if (zoom_level != 1) {
+ state_saver.Save();
+ unzoomed_rect.SetWidth(unzoomed_rect.Width() / zoom_level);
+ unzoomed_rect.SetHeight(unzoomed_rect.Height() / zoom_level);
+ paint_info.context.Translate(unzoomed_rect.X(), unzoomed_rect.Y());
+ paint_info.context.Scale(zoom_level, zoom_level);
+ paint_info.context.Translate(-unzoomed_rect.X(), -unzoomed_rect.Y());
+ }
+
+ return unzoomed_rect;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.h b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.h
index 344b6686830..b8acda0d556 100644
--- a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.h
+++ b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.h
@@ -34,6 +34,7 @@
namespace blink {
+class GraphicsContextStateSaver;
class LayoutThemeDefault;
class ThemePainterDefault final : public ThemePainter {
@@ -103,6 +104,11 @@ class ThemePainterDefault final : public ThemePainter {
const IntRect&,
WebThemeEngine::ExtraParams&);
+ IntRect ApplyZoomToRect(const IntRect&,
+ const PaintInfo&,
+ GraphicsContextStateSaver&,
+ float zoom_level);
+
// ThemePaintDefault is a part object of m_theme.
LayoutThemeDefault& theme_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter.cc b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
index e892ef5d01e..54fce1e13ae 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
@@ -50,7 +50,7 @@ void VideoPainter::PaintReplaced(const PaintInfo& paint_info,
PhysicalRect content_box_rect = layout_video_.PhysicalContentBoxRect();
content_box_rect.Move(paint_offset);
- if (context.IsPaintingPreview()) {
+ if (layout_video_.GetDocument().IsPaintingPreview()) {
// Create a canvas and draw a URL rect to it for the paint preview.
BoxDrawingRecorder recorder(context, layout_video_, paint_info.phase,
paint_offset);
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
index 649de37d36c..3b37ce2103e 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
@@ -46,7 +46,10 @@ class StubWebMediaPlayer : public EmptyWebMediaPlayer {
const cc::Layer* GetCcLayer() { return layer_.get(); }
// WebMediaPlayer
- LoadTiming Load(LoadType, const WebMediaPlayerSource&, CorsMode) override {
+ LoadTiming Load(LoadType,
+ const WebMediaPlayerSource&,
+ CorsMode,
+ bool is_cache_disabled) override {
network_state_ = kNetworkStateLoaded;
client_->NetworkStateChanged();
ready_state_ = kReadyStateHaveEnoughData;
@@ -182,7 +185,7 @@ TEST_P(VideoPaintPreviewTest, URLIsRecordedWhenPaintingPreview) {
recorder.beginRecording(bounds().width(), bounds().height());
canvas->SetPaintPreviewTracker(&tracker);
- GetLocalMainFrame().CapturePaintPreview(WebRect(bounds()), canvas,
+ GetLocalMainFrame().CapturePaintPreview(bounds(), canvas,
/*include_linked_destinations=*/true);
auto record = recorder.finishRecordingAsPicture();
std::vector<std::pair<GURL, SkRect>> links;
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter.cc b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
index 06cd5505996..416a030fd0b 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
@@ -102,9 +102,11 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
// The background rect always includes at least the visible content size.
PhysicalRect background_rect(layout_view_.BackgroundRect());
+ const Document& document = layout_view_.GetDocument();
+
// When printing or painting a preview, paint the entire unclipped scrolling
// content area.
- if (paint_info.IsPrinting() ||
+ if (document.IsPrintingOrPaintingPreview() ||
!layout_view_.GetFrameView()->GetFrame().ClipsContent()) {
background_rect.Unite(layout_view_.DocumentRect());
}
@@ -125,8 +127,6 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
IntRect pixel_snapped_background_rect(PixelSnappedIntRect(background_rect));
- const Document& document = layout_view_.GetDocument();
-
auto root_element_background_painting_state =
layout_view_.FirstFragment().ContentsProperties();
@@ -136,17 +136,14 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
bool painted_separate_effect = false;
bool should_apply_root_background_behavior =
- layout_view_.GetDocument().IsHTMLDocument() ||
- layout_view_.GetDocument().IsXHTMLDocument();
+ document.IsHTMLDocument() || document.IsXHTMLDocument();
bool should_paint_background = !paint_info.SkipRootBackground() &&
layout_view_.HasBoxDecorationBackground();
LayoutObject* root_object = nullptr;
- if (layout_view_.GetDocument().documentElement()) {
- root_object =
- layout_view_.GetDocument().documentElement()->GetLayoutObject();
- }
+ if (auto* document_element = document.documentElement())
+ root_object = document_element->GetLayoutObject();
// For HTML and XHTML documents, the root element may paint in a different
// clip, effect or transform state than the LayoutView. For
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.cc b/chromium/third_party/blink/renderer/core/probe/core_probes.cc
index a345337bfdf..48e534f0e76 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.cc
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.cc
@@ -52,8 +52,6 @@ void* AsyncId(AsyncTaskId* task) {
void AsyncTaskCanceled(v8::Isolate* isolate, AsyncTaskId* task) {
if (ThreadDebugger* debugger = ThreadDebugger::From(isolate))
debugger->AsyncTaskCanceled(AsyncId(task));
- TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask",
- TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)));
}
} // namespace
@@ -94,14 +92,6 @@ AsyncTask::AsyncTask(ExecutionContext* context,
ctx.event()->add_flow_ids(task->GetTraceId().value());
});
}
- if (recurring_) {
- TRACE_EVENT_FLOW_STEP0("devtools.timeline.async", "AsyncTask",
- TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)),
- step ? step : "");
- } else {
- TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask",
- TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)));
- }
if (debugger_)
debugger_->AsyncTaskStarted(AsyncId(task_));
@@ -127,9 +117,6 @@ AsyncTask::~AsyncTask() {
void AsyncTaskScheduled(ExecutionContext* context,
const StringView& name,
AsyncTaskId* task) {
- TRACE_EVENT_FLOW_BEGIN1("devtools.timeline.async", "AsyncTask",
- TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)),
- "data", inspector_async_task::Data(name));
uint64_t trace_id = base::trace_event::GetNextGlobalTraceId();
task->SetTraceId(trace_id);
TRACE_EVENT("blink", "AsyncTask Scheduled", [&](perfetto::EventContext ctx) {
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.h b/chromium/third_party/blink/renderer/core/probe/core_probes.h
index 2c0b2b9704c..789c6a30da9 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.h
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.h
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/ad_tracker.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.json5 b/chromium/third_party/blink/renderer/core/probe/core_probes.json5
index b09f3779e7f..e71e84c02db 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.json5
@@ -68,7 +68,6 @@
"DidInsertDOMNode",
"DidInvalidateStyleAttr",
"DidModifyDOMAttr",
- "DidPerformElementShadowDistribution",
"DidPerformSlotDistribution",
"DidPushShadowRoot",
"DidRemoveDOMAttr",
@@ -104,6 +103,7 @@
"DidCloseAudioContext",
"DidResumeAudioContext",
"DidSuspendAudioContext",
+ "OnContentSecurityPolicyViolation",
]
},
InspectorDOMSnapshotAgent: {
@@ -171,6 +171,9 @@
"ShouldBlockRequest",
"ShouldBypassServiceWorker",
"ShouldForceCorsPreflight",
+ "WebTransportCreated",
+ "WebTransportConnectionEstablished",
+ "WebTransportClosed",
"WillDispatchEventSourceEvent",
"WillLoadXHR",
"WillSendEventSourceRequest",
@@ -178,6 +181,7 @@
"WillSendNavigationRequest",
"WillSendWebSocketHandshakeRequest",
"SetDevToolsIds",
+ "IsCacheDisabled",
]
},
InspectorPageAgent: {
@@ -190,6 +194,7 @@
"DidResizeMainFrame",
"DidRunJavaScriptDialog",
"DomContentLoadedEventFired",
+ "DidOpenDocument",
"FileChooserOpened",
"FrameAttachedToParent",
"FrameClearedScheduledNavigation",
@@ -232,6 +237,11 @@
"DidFinishDebuggerTask",
]
},
+ InspectorPerformanceTimelineAgent: {
+ probes: [
+ "PerformanceEntryAdded",
+ ]
+ },
InspectorTraceEvents: {
probes: [
"CallFunction",
diff --git a/chromium/third_party/blink/renderer/core/probe/core_probes.pidl b/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
index a6d5f86bdfe..4dfe464bba6 100644
--- a/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/chromium/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -61,6 +61,7 @@ interface CoreProbes {
class XMLHttpRequest;
class HTMLInputElement;
class HTMLPortalElement;
+ class PerformanceEntry;
void DidClearDocumentOfWindowObject([Keep] LocalFrame*);
void WillInsertDOMNode([Keep] Node* parent);
@@ -72,7 +73,6 @@ interface CoreProbes {
void WillChangeStyleElement([Keep] Element*);
void CharacterDataModified([Keep] CharacterData*);
void DidInvalidateStyleAttr([Keep] Node*);
- void DidPerformElementShadowDistribution([Keep] Element*);
void DidPerformSlotDistribution([Keep] HTMLSlotElement*);
void DocumentDetached([Keep] Document*);
void ActiveStyleSheetsUpdated([Keep] Document*);
@@ -92,7 +92,7 @@ interface CoreProbes {
void DidBlockRequest(CoreProbeSink*, const ResourceRequest&, DocumentLoader*, const KURL& fetch_context_url, const FetchInitiatorInfo&, ResourceRequestBlockedReason, ResourceType);
void DidChangeResourcePriority(LocalFrame*, DocumentLoader*, uint64_t identifier, ResourceLoadPriority load_priority);
void PrepareRequest(CoreProbeSink*, DocumentLoader*, ResourceRequest&, ResourceLoaderOptions&, ResourceType);
- void WillSendRequest(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const KURL& fetch_context_url, const ResourceRequest&, const ResourceResponse& redirect_response, const FetchInitiatorInfo&, ResourceType);
+ void WillSendRequest(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const KURL& fetch_context_url, const ResourceRequest&, const ResourceResponse& redirect_response, const FetchInitiatorInfo&, ResourceType, RenderBlockingBehavior);
void WillSendNavigationRequest(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const KURL&, const AtomicString& http_method, EncodedFormData*);
void MarkResourceAsCached(LocalFrame*, DocumentLoader*, uint64_t identifier);
void DidReceiveResourceResponse(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const ResourceResponse&, const Resource*);
@@ -118,6 +118,7 @@ interface CoreProbes {
void WillCommitLoad([Keep] LocalFrame*, DocumentLoader*);
void DidCommitLoad([Keep] LocalFrame*, DocumentLoader*);
void DidNavigateWithinDocument([Keep] LocalFrame*);
+ void DidOpenDocument([Keep] LocalFrame*, DocumentLoader*);
void FrameDocumentUpdated([Keep] LocalFrame*);
void FrameOwnerContentUpdated([Keep] LocalFrame*, HTMLFrameOwnerElement*);
void FrameStartedLoading([Keep] LocalFrame*);
@@ -132,6 +133,9 @@ interface CoreProbes {
void DidReceiveWebSocketMessage(ExecutionContext*, uint64_t identifier, int opcode, bool masked, const Vector<base::span<const char>>& data);
void DidSendWebSocketMessage(ExecutionContext*, uint64_t identifier, int opcode, bool masked, const char* payload, size_t payload_length);
void DidReceiveWebSocketMessageError(ExecutionContext*, uint64_t identifier, const String& error_message);
+ void WebTransportCreated([Keep] ExecutionContext*, uint64_t transport_id, const KURL& request_url);
+ void WebTransportConnectionEstablished(ExecutionContext*, uint64_t transport_id);
+ void WebTransportClosed(ExecutionContext*, uint64_t transport_id);
void NetworkStateChanged([Keep] LocalFrame*, bool online);
void UpdateApplicationCacheStatus([Keep] LocalFrame*);
/* This is for pre-BlinkGenPropertyTrees. TODO(wangxianzhu): Remove this function for BlinkGenPropertyTrees. */
@@ -185,4 +189,7 @@ interface CoreProbes {
void LocalFontsEnabled(ExecutionContext*, bool* result);
void DidUpdateComputedStyle([Keep] Element*, const ComputedStyle* old_style, const ComputedStyle* new_style);
void GetDisabledImageTypes(ExecutionContext*, HashSet<String>* result);
+ void OnContentSecurityPolicyViolation(ExecutionContext* context, const blink::ContentSecurityPolicy::ContentSecurityPolicyViolationType violationType);
+ void IsCacheDisabled(ExecutionContext*, bool* is_cache_disabled);
+ void PerformanceEntryAdded([Keep] ExecutionContext*, PerformanceEntry*);
}
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/DIR_METADATA b/chromium/third_party/blink/renderer/core/resize_observer/DIR_METADATA
new file mode 100644
index 00000000000..3611c38fad3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/resize_observer/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Layout"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/OWNERS b/chromium/third_party/blink/renderer/core/resize_observer/OWNERS
index 4dd1b292f57..142a4b24584 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/OWNERS
+++ b/chromium/third_party/blink/renderer/core/resize_observer/OWNERS
@@ -1,4 +1 @@
atotic@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl
index 6537789bb6c..c6d0c24b290 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl
@@ -13,7 +13,7 @@ callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, R
ActiveScriptWrappable
] interface ResizeObserver {
[CallWith=ScriptState, MeasureAs=ResizeObserver_Constructor] constructor(ResizeObserverCallback callback);
- [RuntimeEnabled=ResizeObserverUpdates] void observe(Element target, ResizeObserverOptions options);
+ void observe(Element target, ResizeObserverOptions options);
void observe(Element target);
void unobserve(Element target);
void disconnect();
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
index 41216d9e3f5..fac588a7da2 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
@@ -30,21 +30,18 @@ ResizeObserverEntry::ResizeObserverEntry(Element* target) : target_(target) {
LayoutSize(svg_graphics_element->GetBBox().Size());
content_rect_ = DOMRectReadOnly::FromFloatRect(
FloatRect(FloatPoint(), FloatSize(bounding_box_size)));
- if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) {
- ResizeObserverSize* size = ResizeObserverSize::Create(
- bounding_box_size.Width(), bounding_box_size.Height());
- content_box_size_.push_back(size);
- border_box_size_.push_back(size);
- bounding_box_size.Scale(style.EffectiveZoom());
- FloatSize snapped_device_pixel_content_box =
- ResizeObserverUtilities::ComputeSnappedDevicePixelContentBox(
- bounding_box_size, layout_object, style);
- ResizeObserverSize* device_pixel_content_box_size =
- ResizeObserverSize::Create(
- snapped_device_pixel_content_box.Width(),
- snapped_device_pixel_content_box.Height());
- device_pixel_content_box_size_.push_back(device_pixel_content_box_size);
- }
+ ResizeObserverSize* size = ResizeObserverSize::Create(
+ bounding_box_size.Width(), bounding_box_size.Height());
+ content_box_size_.push_back(size);
+ border_box_size_.push_back(size);
+ bounding_box_size.Scale(style.EffectiveZoom());
+ FloatSize snapped_device_pixel_content_box =
+ ResizeObserverUtilities::ComputeSnappedDevicePixelContentBox(
+ bounding_box_size, layout_object, style);
+ ResizeObserverSize* device_pixel_content_box_size =
+ ResizeObserverSize::Create(snapped_device_pixel_content_box.Width(),
+ snapped_device_pixel_content_box.Height());
+ device_pixel_content_box_size_.push_back(device_pixel_content_box_size);
} else if (layout_object->IsBox()) {
LayoutBox* layout_box = target->GetLayoutBox();
LayoutRect content_rect(
@@ -53,42 +50,37 @@ ResizeObserverEntry::ResizeObserverEntry(Element* target) : target_(target) {
content_rect_ =
ResizeObserverUtilities::ZoomAdjustedLayoutRect(content_rect, style);
- if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) {
- FloatSize content_box = ResizeObserverUtilities::ComputeZoomAdjustedBox(
- ResizeObserverBoxOptions::ContentBox, layout_object, style);
- FloatSize border_box = ResizeObserverUtilities::ComputeZoomAdjustedBox(
- ResizeObserverBoxOptions::BorderBox, layout_object, style);
- FloatSize device_pixel_content_box =
- ResizeObserverUtilities::ComputeZoomAdjustedBox(
- ResizeObserverBoxOptions::DevicePixelContentBox, layout_object,
- style);
+ FloatSize content_box = ResizeObserverUtilities::ComputeZoomAdjustedBox(
+ ResizeObserverBoxOptions::ContentBox, layout_object, style);
+ FloatSize border_box = ResizeObserverUtilities::ComputeZoomAdjustedBox(
+ ResizeObserverBoxOptions::BorderBox, layout_object, style);
+ FloatSize device_pixel_content_box =
+ ResizeObserverUtilities::ComputeZoomAdjustedBox(
+ ResizeObserverBoxOptions::DevicePixelContentBox, layout_object,
+ style);
- ResizeObserverSize* device_pixel_content_box_size =
- ResizeObserverSize::Create(device_pixel_content_box.Width(),
- device_pixel_content_box.Height());
- ResizeObserverSize* content_box_size = ResizeObserverSize::Create(
- content_box.Width(), content_box.Height());
- ResizeObserverSize* border_box_size =
- ResizeObserverSize::Create(border_box.Width(), border_box.Height());
+ ResizeObserverSize* device_pixel_content_box_size =
+ ResizeObserverSize::Create(device_pixel_content_box.Width(),
+ device_pixel_content_box.Height());
+ ResizeObserverSize* content_box_size =
+ ResizeObserverSize::Create(content_box.Width(), content_box.Height());
+ ResizeObserverSize* border_box_size =
+ ResizeObserverSize::Create(border_box.Width(), border_box.Height());
- content_box_size_.push_back(content_box_size);
- border_box_size_.push_back(border_box_size);
- device_pixel_content_box_size_.push_back(device_pixel_content_box_size);
- }
+ content_box_size_.push_back(content_box_size);
+ border_box_size_.push_back(border_box_size);
+ device_pixel_content_box_size_.push_back(device_pixel_content_box_size);
}
}
if (!content_rect_)
content_rect_ = DOMRectReadOnly::FromFloatRect(
FloatRect(FloatPoint(LayoutPoint()), FloatSize(LayoutSize())));
- if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) {
- if (content_box_size_.size() == 0)
- content_box_size_.push_back(ResizeObserverSize::Create(0, 0));
- if (border_box_size_.size() == 0)
- border_box_size_.push_back(ResizeObserverSize::Create(0, 0));
- if (device_pixel_content_box_size_.size() == 0) {
- device_pixel_content_box_size_.push_back(
- ResizeObserverSize::Create(0, 0));
- }
+ if (content_box_size_.size() == 0)
+ content_box_size_.push_back(ResizeObserverSize::Create(0, 0));
+ if (border_box_size_.size() == 0)
+ border_box_size_.push_back(ResizeObserverSize::Create(0, 0));
+ if (device_pixel_content_box_size_.size() == 0) {
+ device_pixel_content_box_size_.push_back(ResizeObserverSize::Create(0, 0));
}
}
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
index 4a4006cc795..398060ec398 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
@@ -8,7 +8,7 @@
interface ResizeObserverEntry {
readonly attribute Element target;
readonly attribute DOMRectReadOnly contentRect;
- [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> contentBoxSize;
- [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> borderBoxSize;
- [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> devicePixelContentBoxSize;
+ readonly attribute FrozenArray<ResizeObserverSize> contentBoxSize;
+ readonly attribute FrozenArray<ResizeObserverSize> borderBoxSize;
+ readonly attribute FrozenArray<ResizeObserverSize> devicePixelContentBoxSize;
};
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl
index d043025e315..774a7d2199c 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl
@@ -5,8 +5,7 @@
// https://drafts.csswg.org/resize-observer-1/#resizeobserversize
[
- Exposed=Window,
- RuntimeEnabled=ResizeObserverUpdates
+ Exposed=Window
] interface ResizeObserverSize {
readonly attribute unrestricted double inlineSize;
readonly attribute unrestricted double blockSize;
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
index f930bc9faaa..fc5fee6dbd2 100644
--- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc
@@ -261,11 +261,11 @@ TEST_F(ResizeObserverUnitTest, TestMemoryLeaks) {
ClassicScript::CreateUnspecifiedScript(
ScriptSourceCode("var ro = new ResizeObserver( entries => {});"))
->RunScript(&Window(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
ASSERT_EQ(observers.size(), 1U);
ClassicScript::CreateUnspecifiedScript(ScriptSourceCode("ro = undefined;"))
->RunScript(&Window(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
ThreadState::Current()->CollectAllGarbageForTesting();
WebHeap::CollectAllGarbageForTesting();
ASSERT_EQ(observers.IsEmpty(), true);
@@ -279,14 +279,14 @@ TEST_F(ResizeObserverUnitTest, TestMemoryLeaks) {
"ro.observe(el);"
"ro = undefined;"))
->RunScript(&Window(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
ASSERT_EQ(observers.size(), 1U);
ThreadState::Current()->CollectAllGarbageForTesting();
WebHeap::CollectAllGarbageForTesting();
ASSERT_EQ(observers.size(), 1U);
ClassicScript::CreateUnspecifiedScript(ScriptSourceCode("el = undefined;"))
->RunScript(&Window(),
- ScriptController::kExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
ThreadState::Current()->CollectAllGarbageForTesting();
WebHeap::CollectAllGarbageForTesting();
ASSERT_EQ(observers.IsEmpty(), true);
diff --git a/chromium/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/chromium/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
index deb18489658..8b8ac0cdbb1 100644
--- a/chromium/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
+++ b/chromium/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -4,20 +4,25 @@
#include "base/callback.h"
#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
+#include "cc/base/features.h"
#include "cc/layers/picture_layer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/web/web_frame_content_dumper.h"
+#include "third_party/blink/public/test/test_web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_hit_test_result.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intersection_observer_init.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
+#include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -25,7 +30,11 @@
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
+#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
#include "third_party/blink/renderer/core/script/classic_script.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/intersection_observer_test_helper.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
@@ -72,6 +81,11 @@ class FrameThrottlingTest : public PaintTestConfigurations, public SimTest {
void UpdateAllLifecyclePhases() {
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
}
+
+ class EmptyEventListener final : public NativeEventListener {
+ public:
+ void Invoke(ExecutionContext* execution_context, Event*) override {}
+ };
};
INSTANTIATE_PAINT_TEST_SUITE_P(FrameThrottlingTest);
@@ -189,10 +203,14 @@ TEST_P(FrameThrottlingTest, IntersectionObservationOverridesThrottling) {
inner_frame_document->View()->SetIntersectionObservationState(
LocalFrameView::kRequired);
{
- GetDocument().GetFrame()->View()->SetInLifecycleUpdateForTest(true);
+ GetDocument().GetFrame()->View()->SetTargetStateForTest(
+ DocumentLifecycle::kPaintClean);
+ inner_frame_document->Lifecycle().EnsureStateAtMost(
+ DocumentLifecycle::kVisualUpdatePending);
EXPECT_FALSE(
inner_frame_document->View()->ShouldThrottleRenderingForTest());
- GetDocument().GetFrame()->View()->SetInLifecycleUpdateForTest(false);
+ GetDocument().GetFrame()->View()->SetTargetStateForTest(
+ DocumentLifecycle::kUninitialized);
}
inner_frame_document->View()->ScheduleAnimation();
@@ -223,10 +241,11 @@ TEST_P(FrameThrottlingTest, IntersectionObservationOverridesThrottling) {
EXPECT_TRUE(inner_frame_document->View()->ShouldThrottleRenderingForTest());
EXPECT_FALSE(inner_view->NeedsLayout());
- EXPECT_TRUE(inner_frame_document->View()
- ->GetLayoutView()
- ->ShouldDoFullPaintInvalidation());
+ EXPECT_LT(inner_frame_document->Lifecycle().GetState(),
+ DocumentLifecycle::kPaintClean);
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ // If IntersectionObserver is required to run, lifecycle will be updated
+ // through pre-paint, but not compositing assignment.
EXPECT_EQ(kCompositingUpdateRebuildTree,
inner_view->Compositor()->pending_update_type_);
}
@@ -345,9 +364,13 @@ TEST_P(FrameThrottlingTest,
LocalFrameView::kRequired);
EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest());
{
- GetDocument().GetFrame()->View()->SetInLifecycleUpdateForTest(true);
+ GetDocument().GetFrame()->View()->SetTargetStateForTest(
+ DocumentLifecycle::kPaintClean);
+ frame_document->Lifecycle().EnsureStateAtMost(
+ DocumentLifecycle::kVisualUpdatePending);
EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
- GetDocument().GetFrame()->View()->SetInLifecycleUpdateForTest(false);
+ GetDocument().GetFrame()->View()->SetTargetStateForTest(
+ DocumentLifecycle::kUninitialized);
}
// A lifecycle update can update the throttled frame to just LayoutClean but
@@ -357,7 +380,7 @@ TEST_P(FrameThrottlingTest,
frame_document->View()->ScheduleAnimation();
frame_document->View()->GetLayoutView()->Layer()->SetNeedsRepaint();
CompositeFrame();
- EXPECT_EQ(DocumentLifecycle::kLayoutClean,
+ EXPECT_EQ(DocumentLifecycle::kPrePaintClean,
frame_document->Lifecycle().GetState());
EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest());
}
@@ -1026,109 +1049,6 @@ TEST_P(FrameThrottlingTest, UnthrottleByTransformingWithoutLayout) {
frame_element->contentDocument()->View()->CanThrottleRendering());
}
-TEST_P(FrameThrottlingTest, ThrottledTopLevelEventHandlerIgnored) {
- WebView().GetSettings()->SetJavaScriptEnabled(true);
- EXPECT_EQ(0u, TouchHandlerRegionSize());
-
- // This test covers the case where a non-composited iframe is throttled. With
- // this flag enabled, that is impossible, because only cross-origin iframes
- // can be throttled.
- if (base::FeatureList::IsEnabled(features::kCompositeCrossOriginIframes))
- return;
-
- // Create a frame which is throttled and has two different types of
- // top-level touchstart handlers.
- SimRequest main_resource("https://example.com/", "text/html");
- SimRequest frame_resource("https://example.com/iframe.html", "text/html");
-
- LoadURL("https://example.com/");
- main_resource.Complete(
- "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
- frame_resource.Complete(R"HTML(
- <script>
- window.addEventListener('touchstart', function(){}, {passive: false});
- document.addEventListener('touchstart', function(){}, {passive: false});
- </script>
- )HTML");
- auto* frame_element =
- To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
- frame_element->setAttribute(kStyleAttr, "transform: translateY(480px)");
- CompositeFrame(); // Throttle the frame.
-
- // In here, throttle iframe doesn't throttle the main frame.
- EXPECT_TRUE(frame_element->contentDocument()
- ->View()
- ->ShouldThrottleRenderingForTest());
- EXPECT_FALSE(GetDocument().View()->ShouldThrottleRenderingForTest());
-
- // In this test, the iframe has the same origin as the main frame, so we have
- // two documents but one graphics layer tree. The test throttles the iframe
- // document only. In ScrollingCoordinator::UpdateLayerTouchActionRects, we
- // check whether the document associated with a certain grahpics layer is
- // throttled or not. Since the layers are associated with the main document
- // which is not throttled, we expect the main document to have one touch
- // handler region.
- EXPECT_EQ(1u, TouchHandlerRegionSize());
-
- // Unthrottling the frame makes the touch handlers active again. Note that
- // both handlers get combined into the same rectangle in the region, so
- // there is only one rectangle in total.
- frame_element->setAttribute(kStyleAttr, "transform: translateY(0px)");
- CompositeFrame(); // Unthrottle the frame.
- EXPECT_EQ(1u, TouchHandlerRegionSize());
-}
-
-TEST_P(FrameThrottlingTest, ThrottledEventHandlerIgnored) {
- WebView().GetSettings()->SetJavaScriptEnabled(true);
- EXPECT_EQ(0u, TouchHandlerRegionSize());
-
- // This test covers the case where a non-composited iframe is throttled. With
- // this flag enabled, that is impossible, because only cross-origin iframes
- // can be throttled.
- if (base::FeatureList::IsEnabled(features::kCompositeCrossOriginIframes))
- return;
-
- // Create a frame which is throttled and has a non-top-level touchstart
- // handler.
- SimRequest main_resource("https://example.com/", "text/html");
- SimRequest frame_resource("https://example.com/iframe.html", "text/html");
-
- LoadURL("https://example.com/");
- main_resource.Complete(
- "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
- frame_resource.Complete(R"HTML(
- <div id=d>touch handler</div>
- <script>
- document.querySelector('#d').addEventListener('touchstart',
- function(){});
- </script>
- )HTML");
- auto* frame_element =
- To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
- frame_element->setAttribute(kStyleAttr, "transform: translateY(480px)");
- CompositeFrame(); // Throttle the frame.
-
- // In here, throttle iframe doesn't throttle the main frame.
- EXPECT_TRUE(frame_element->contentDocument()
- ->View()
- ->ShouldThrottleRenderingForTest());
- EXPECT_FALSE(GetDocument().View()->ShouldThrottleRenderingForTest());
-
- // In this test, the iframe has the same origin as the main frame, so we have
- // two documents but one graphics layer tree. The test throttles the iframe
- // document only. In ScrollingCoordinator::UpdateLayerTouchActionRects, we
- // check whether the document associated with a certain grahpics layer is
- // throttled or not. Since the layers are associated with the main document
- // which is not throttled, we expect the main document to have one touch
- // handler region.
- EXPECT_EQ(1u, TouchHandlerRegionSize());
-
- // Unthrottling the frame makes the touch handler active again.
- frame_element->setAttribute(kStyleAttr, "transform: translateY(0px)");
- CompositeFrame(); // Unthrottle the frame.
- EXPECT_EQ(1u, TouchHandlerRegionSize());
-}
-
TEST_P(FrameThrottlingTest, DumpThrottledFrame) {
WebView().GetSettings()->SetJavaScriptEnabled(true);
@@ -1152,7 +1072,8 @@ TEST_P(FrameThrottlingTest, DumpThrottledFrame) {
EXPECT_FALSE(Compositor().NeedsBeginFrame());
// The dumped contents should not include the throttled frame.
- WebString result = WebFrameContentDumper::DumpWebViewAsText(&WebView(), 1024);
+ WebString result =
+ TestWebFrameContentDumper::DumpWebViewAsText(&WebView(), 1024);
EXPECT_NE(std::string::npos, result.Utf8().find("main"));
EXPECT_EQ(std::string::npos, result.Utf8().find("throttled"));
}
@@ -1162,6 +1083,10 @@ TEST_P(FrameThrottlingTest, PaintingViaGraphicsLayerIsThrottled) {
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
+ // TODO(wangxianzhu): See the TODO in CullRectUpdater::SetFragmentCullRects().
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
// Create a hidden frame which is throttled.
@@ -1459,6 +1384,7 @@ TEST_P(FrameThrottlingTest, UpdatePaintPropertiesOnUnthrottling) {
// The first update unthrottles the frame, the second actually update layout
// and paint properties etc.
CompositeFrame();
+ EXPECT_TRUE(frame_document->GetLayoutView()->Layer()->SelfNeedsRepaint());
CompositeFrame();
EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
EXPECT_EQ(FloatSize(0, 20), inner_div->GetLayoutObject()
@@ -1701,8 +1627,8 @@ TEST_P(FrameThrottlingTest, NestedFramesInRemoteFrameHiddenAndShown) {
intersection.main_frame_viewport_size = gfx::Size(100, 100);
intersection.viewport_intersection = gfx::Rect(0, 0, 100, 100);
LocalFrameRoot().FrameWidget()->Resize(gfx::Size(300, 200));
- static_cast<WebFrameWidgetBase*>(LocalFrameRoot().FrameWidget())
- ->SetRemoteViewportIntersection(intersection);
+ static_cast<WebFrameWidgetImpl*>(LocalFrameRoot().FrameWidget())
+ ->ApplyViewportIntersectionForTesting(intersection.Clone());
auto* root_frame = LocalFrameRoot().GetFrame();
auto* frame_document =
@@ -1742,8 +1668,8 @@ TEST_P(FrameThrottlingTest, NestedFramesInRemoteFrameHiddenAndShown) {
// Show the frame without any other change.
LocalFrameRoot().WasShown();
- static_cast<WebFrameWidgetBase*>(LocalFrameRoot().FrameWidget())
- ->SetRemoteViewportIntersection(intersection);
+ static_cast<WebFrameWidgetImpl*>(LocalFrameRoot().FrameWidget())
+ ->ApplyViewportIntersectionForTesting(intersection.Clone());
CompositeFrame();
EXPECT_EQ(root_frame->RemoteViewportIntersection(), IntRect(0, 0, 100, 100));
EXPECT_FALSE(root_frame->View()->CanThrottleRenderingForPropagation());
@@ -1810,4 +1736,366 @@ TEST_P(FrameThrottlingTest, LifecycleThrottledFrameNeedsRepaint) {
GetDocument().GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint());
}
+TEST_P(FrameThrottlingTest, AncestorTouchActionAndWheelEventHandlers) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(::features::kWheelEventRegions);
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+
+ LoadURL("https://example.com/");
+ // The frame is initially throttled.
+ main_resource.Complete(R"HTML(
+ <div id="parent">
+ <iframe id="frame" sandbox src="iframe.html"></iframe>
+ </div>
+ )HTML");
+ frame_resource.Complete("<div id='child'></div>");
+ CompositeFrame();
+
+ auto* frame_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
+ auto* frame_document = frame_element->contentDocument();
+ auto* parent = GetDocument().getElementById("parent");
+ auto* parent_object = parent->GetLayoutObject();
+ auto* child_layout_view = frame_document->GetLayoutView();
+ auto* child = frame_document->getElementById("child");
+ auto* child_object = child->GetLayoutObject();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_FALSE(parent_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(parent_object->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingWheelEventHandler());
+
+ // Moving the child fully outside the parent makes it invisible.
+ frame_element->setAttribute(kStyleAttr, "transform: translateY(480px)");
+ CompositeFrame();
+ EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest());
+
+ auto* handler = MakeGarbageCollected<EmptyEventListener>();
+ parent->addEventListener(event_type_names::kTouchstart, handler);
+ parent->addEventListener(event_type_names::kWheel, handler);
+ EXPECT_TRUE(parent_object->EffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(parent_object->BlockingWheelEventHandlerChanged());
+ UpdateAllLifecyclePhases();
+ EXPECT_TRUE(parent_object->InsideBlockingTouchEventHandler());
+ EXPECT_TRUE(parent_object->InsideBlockingWheelEventHandler());
+ // Event handler status update is pending in the throttled frame.
+ EXPECT_TRUE(child_layout_view->EffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(child_layout_view->BlockingWheelEventHandlerChanged());
+ EXPECT_FALSE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingWheelEventHandler());
+
+ // Move the child back to the visible viewport.
+ frame_element->setAttribute(kStyleAttr,
+ "transform: translate(-50px, 0px, 0px)");
+ // Update throttling, which will schedule visual update on unthrottling of the
+ // frame.
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_TRUE(parent_object->InsideBlockingTouchEventHandler());
+ EXPECT_TRUE(parent_object->InsideBlockingWheelEventHandler());
+ // Event handler status is updated in the unthrottled frame.
+ EXPECT_FALSE(child_layout_view->EffectiveAllowedTouchActionChanged());
+ EXPECT_FALSE(child_layout_view->BlockingWheelEventHandlerChanged());
+ EXPECT_TRUE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_TRUE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_TRUE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_TRUE(child_object->InsideBlockingWheelEventHandler());
+}
+
+TEST_P(FrameThrottlingTest, DescendantTouchActionAndWheelEventHandlers) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(::features::kWheelEventRegions);
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+
+ LoadURL("https://example.com/");
+ // The frame is initially throttled.
+ main_resource.Complete(R"HTML(
+ <div id="parent">
+ <iframe id="frame" sandbox src="iframe.html"></iframe>
+ </div>
+ )HTML");
+ frame_resource.Complete("<div id='child'></div>");
+ CompositeFrame();
+
+ auto* frame_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
+ auto* frame_document = frame_element->contentDocument();
+ auto* parent = GetDocument().getElementById("parent");
+ auto* parent_object = parent->GetLayoutObject();
+ auto* child_layout_view = frame_document->GetLayoutView();
+ auto* child = frame_document->getElementById("child");
+ auto* child_object = child->GetLayoutObject();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_FALSE(parent_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(parent_object->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingWheelEventHandler());
+
+ // Moving the child fully outside the parent makes it invisible.
+ frame_element->setAttribute(kStyleAttr, "transform: translateY(480px)");
+ CompositeFrame();
+ EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest());
+
+ auto* handler = MakeGarbageCollected<EmptyEventListener>();
+ child->addEventListener(event_type_names::kTouchstart, handler);
+ child->addEventListener(event_type_names::kWheel, handler);
+ EXPECT_TRUE(child_object->EffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(child_object->BlockingWheelEventHandlerChanged());
+ EXPECT_TRUE(
+ child_layout_view->DescendantEffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(child_layout_view->DescendantBlockingWheelEventHandlerChanged());
+ EXPECT_FALSE(parent_object->DescendantEffectiveAllowedTouchActionChanged());
+ EXPECT_FALSE(parent_object->DescendantBlockingWheelEventHandlerChanged());
+ UpdateAllLifecyclePhases();
+ // Event handler status update is pending in the throttled frame.
+ EXPECT_TRUE(child_object->EffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(child_object->BlockingWheelEventHandlerChanged());
+ EXPECT_TRUE(
+ child_layout_view->DescendantEffectiveAllowedTouchActionChanged());
+ EXPECT_TRUE(child_layout_view->DescendantBlockingWheelEventHandlerChanged());
+ EXPECT_FALSE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_object->InsideBlockingWheelEventHandler());
+
+ // Move the child back to the visible viewport.
+ frame_element->setAttribute(kStyleAttr,
+ "transform: translate(-50px, 0px, 0px)");
+ // Update throttling, which will schedule visual update on unthrottling of the
+ // frame.
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ // Event handler status is updated in the unthrottled frame.
+ EXPECT_FALSE(child_object->EffectiveAllowedTouchActionChanged());
+ EXPECT_FALSE(child_object->BlockingWheelEventHandlerChanged());
+ EXPECT_FALSE(
+ child_layout_view->DescendantEffectiveAllowedTouchActionChanged());
+ EXPECT_FALSE(child_layout_view->DescendantBlockingWheelEventHandlerChanged());
+ EXPECT_FALSE(child_layout_view->InsideBlockingTouchEventHandler());
+ EXPECT_FALSE(child_layout_view->InsideBlockingWheelEventHandler());
+ EXPECT_TRUE(child_object->InsideBlockingTouchEventHandler());
+ EXPECT_TRUE(child_object->InsideBlockingWheelEventHandler());
+}
+
+namespace {
+
+class TestResizeObserverDelegate : public ResizeObserver::Delegate {
+ public:
+ explicit TestResizeObserverDelegate() {}
+ void OnResize(
+ const HeapVector<Member<ResizeObserverEntry>>& entries) override {
+ entries[0]->target()->SetInlineStyleProperty(CSSPropertyID::kWidth,
+ "100px");
+ }
+};
+
+} // namespace
+
+TEST_P(FrameThrottlingTest, ForceUnthrottled) {
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+ LoadURL("https://example.com/");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="frame" sandbox src="iframe.html"
+ style="border:0;transform:translateY(480px)">
+ )HTML");
+ frame_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <div style="width:120px">Hello, world!</div>
+ )HTML");
+ CompositeFrame();
+ HTMLIFrameElement* frame_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
+ LocalFrameView* inner_frame_view =
+ To<LocalFrameView>(frame_element->OwnedEmbeddedContentView());
+ EXPECT_TRUE(inner_frame_view->ShouldThrottleRenderingForTest());
+
+ IntersectionObserverInit* intersection_init =
+ IntersectionObserverInit::Create();
+ TestIntersectionObserverDelegate* intersection_delegate =
+ MakeGarbageCollected<TestIntersectionObserverDelegate>(
+ *frame_element->contentDocument());
+ IntersectionObserver* intersection_observer =
+ IntersectionObserver::Create(intersection_init, *intersection_delegate);
+ intersection_observer->observe(frame_element->contentDocument()->body());
+
+ ResizeObserver::Delegate* resize_delegate =
+ MakeGarbageCollected<TestResizeObserverDelegate>();
+ ResizeObserver* resize_observer =
+ ResizeObserver::Create(&Window(), resize_delegate);
+ resize_observer->observe(frame_element);
+
+ // Apply style change here to ensure ResizeObserver will force a second pass
+ // through the lifecycle loop on the next update.
+ frame_element->SetInlineStyleProperty(CSSPropertyID::kWidth, "200px");
+
+ // Because there is a new IntersectionObserver target, the iframe will be
+ // force-unthrottled going into the lifecycle update. During the first pass
+ // through the lifecycle loop, the style change will cause the ResizeObserver
+ // callback to run. The ResizeObserver will dirty the iframe element by
+ // setting its width to 100px. At this point, the lifecycle state of the
+ // iframe will be kCompositingAssignmentsClean, which will cause
+ // ShouldThrottleRendering() to return true.
+ //
+ // Because ResizeObserver dirtied layout, there will be a second pass through
+ // the main lifecycle loop. When the iframe element runs layout again, setting
+ // its width to 100px, it will cause the iframe's contents to overflow, so the
+ // iframe will add a horizontal scrollbar and mark its LayoutView as needing
+ // paint property update. If the iframe's lifecycle state is still
+ // kCompositingAssignmentsClean, then it will skip pre-paint on the second
+ // pass through the lifecycle loop, leaving its paint properties in a dirty
+ // state (bad). If, however, the iframe's lifecycle state is reset to
+ // kVisualUpdatePending prior to the second pass through the loop, then it
+ // will be once again force-unthrottled, and will run lifecycle steps up
+ // through pre-paint (good).
+ CompositeFrame();
+
+ EXPECT_TRUE(inner_frame_view->ShouldThrottleRenderingForTest());
+ EXPECT_FALSE(inner_frame_view->GetLayoutView()->NeedsPaintPropertyUpdate());
+}
+
+TEST_P(FrameThrottlingTest, CullRectUpdate) {
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ return;
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+
+ LoadURL("https://example.com/");
+ // The frame is initially throttled.
+ main_resource.Complete(R"HTML(
+ <style>#clip { width: 100px; height: 100px; overflow: hidden }</style>
+ <div id="container" style="transform: translateY(480px)">
+ <div id="clip">
+ <iframe id="frame" sandbox src="iframe.html"
+ style="width: 400px; height: 400px; border: none"></iframe>
+ </div>
+ </div>
+ )HTML");
+ frame_resource.Complete("");
+ CompositeFrame();
+
+ auto* frame_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
+ auto* frame_object = frame_element->GetLayoutBox();
+ auto* frame_document = frame_element->contentDocument();
+ auto* child_layout_view = frame_document->GetLayoutView();
+
+ EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_EQ(IntRect(0, 0, 100, 100),
+ frame_object->FirstFragment().GetCullRect().Rect());
+ EXPECT_FALSE(child_layout_view->Layer()->NeedsCullRectUpdate());
+
+ // Change clip. |frame_element| should update its cull rect.
+ // |child_layout_view|'s cull rect update is pending.
+ GetDocument().getElementById("clip")->setAttribute(kStyleAttr,
+ "width: 630px");
+ CompositeFrame();
+ EXPECT_EQ(IntRect(0, 0, 630, 100),
+ frame_object->FirstFragment().GetCullRect().Rect());
+ EXPECT_TRUE(child_layout_view->Layer()->NeedsCullRectUpdate());
+
+ // Move the frame into the visible viewport.
+ GetDocument()
+ .getElementById("container")
+ ->setAttribute(kStyleAttr, "transform: translate(0)");
+ // Update throttling, which will schedule visual update on unthrottling of the
+ // frame.
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_EQ(IntRect(0, 0, 630, 100),
+ frame_object->FirstFragment().GetCullRect().Rect());
+ EXPECT_TRUE(child_layout_view->Layer()->NeedsCullRectUpdate());
+
+ // The frame is unthrottled.
+ CompositeFrame();
+ EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest());
+ EXPECT_EQ(IntRect(0, 0, 630, 100),
+ frame_object->FirstFragment().GetCullRect().Rect());
+ EXPECT_EQ(IntRect(-4000, -4000, 8630, 8100),
+ child_layout_view->FirstFragment().GetCullRect().Rect());
+ EXPECT_FALSE(child_layout_view->Layer()->NeedsCullRectUpdate());
+}
+
+TEST_P(FrameThrottlingTest, ForceCompositingUpdateOnVisibilityChange) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ SimRequest child_resource("https://example.com/child.html", "text/html");
+ SimRequest grandchild_resource("https://example.com/grandchild.html",
+ "text/html");
+
+ LoadURL("https://example.com/");
+ main_resource.Complete(R"HTML(
+ <iframe src="child.html"></iframe>
+ )HTML");
+ child_resource.Complete(R"HTML(
+ <iframe sandbox src="grandchild.html" style="margin-top: 1000px"></iframe>
+ )HTML");
+ grandchild_resource.Complete(R"HTML(
+ <div style="width:100px;height:100px;will-change:transform"></div>
+ )HTML");
+ CompositeFrame();
+
+ LocalFrame* child_frame =
+ To<LocalFrame>(MainFrame().GetFrame()->FirstChild());
+ LocalFrame* grandchild_frame = To<LocalFrame>(child_frame->FirstChild());
+ Element* composited_div =
+ grandchild_frame->GetDocument()->QuerySelector("div");
+
+ EXPECT_TRUE(grandchild_frame->View()->ShouldThrottleRenderingForTest());
+ EXPECT_TRUE(
+ child_frame->ContentLayoutObject()->Compositor()->InCompositingMode());
+ EXPECT_TRUE(grandchild_frame->ContentLayoutObject()
+ ->Compositor()
+ ->InCompositingMode());
+ EXPECT_TRUE(To<LayoutBoxModelObject>(composited_div->GetLayoutObject())
+ ->Layer()
+ ->HasCompositedLayerMapping());
+
+ // Remove the compositing trigger. Because the grandchild is throttled, it
+ // will not update its compositing state.
+ composited_div->RemoveInlineStyleProperty(CSSPropertyID::kWillChange);
+ MainFrame().GetFrame()->View()->ScheduleAnimation();
+ CompositeFrame();
+ EXPECT_TRUE(grandchild_frame->View()->ShouldThrottleRenderingForTest());
+ EXPECT_TRUE(
+ child_frame->ContentLayoutObject()->Compositor()->InCompositingMode());
+ EXPECT_TRUE(grandchild_frame->ContentLayoutObject()
+ ->Compositor()
+ ->InCompositingMode());
+ EXPECT_TRUE(To<LayoutBoxModelObject>(composited_div->GetLayoutObject())
+ ->Layer()
+ ->HasCompositedLayerMapping());
+
+ // Hide the child frame. This will force a compositing update of the throttled
+ // grandchild on the next lifecycle update, which should decomposite the div.
+ child_frame->DeprecatedLocalOwner()->SetInlineStyleProperty(
+ CSSPropertyID::kVisibility, CSSValueID::kHidden);
+ CompositeFrame();
+ EXPECT_TRUE(grandchild_frame->View()->ShouldThrottleRenderingForTest());
+ EXPECT_FALSE(
+ child_frame->ContentLayoutObject()->Compositor()->InCompositingMode());
+ EXPECT_FALSE(grandchild_frame->ContentLayoutObject()
+ ->Compositor()
+ ->InCompositingMode());
+ EXPECT_FALSE(composited_div->GetLayoutObject()->HasLayer());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/scheduler_integration_tests/throttling_test.cc b/chromium/third_party/blink/renderer/core/scheduler_integration_tests/throttling_test.cc
index ada3cae35e2..de31c75f3ac 100644
--- a/chromium/third_party/blink/renderer/core/scheduler_integration_tests/throttling_test.cc
+++ b/chromium/third_party/blink/renderer/core/scheduler_integration_tests/throttling_test.cc
@@ -139,63 +139,11 @@ TEST_F(BackgroundPageThrottlingTest, TimersThrottledInBackgroundPage) {
ElementsAre(console_message, console_message, console_message));
}
-// Verify that a timer with timeout=0 is not throttled until its timeout is
-// rounded up to 4ms.
-TEST_F(BackgroundPageThrottlingTest,
- ZeroTimeoutTimersThrottledInBackgroundPage) {
- SimRequest main_resource("https://example.com/", "text/html");
-
- LoadURL("https://example.com/");
-
- const String console_message = BuildTimerConsoleMessage();
- main_resource.Complete(
- String::Format("(<script>"
- " function f(repetitions) {"
- " if (repetitions == 0) return;"
- " console.log('%s');"
- " setTimeout(f, 0, repetitions - 1);"
- " }"
- " setTimeout(f, 0, 50);"
- "</script>)",
- console_message.Utf8().c_str()));
-
- GetDocument().GetPage()->GetPageScheduler()->SetPageVisible(false);
-
- // Initially, timeout is rounded up to 1ms and no throttling is applied
- // (https://crbug.com/402694). After 4 executions, timeout is rounded up to
- // 4ms and throttling is applied.
- constexpr base::TimeDelta k10Ms = base::TimeDelta::FromMilliseconds(10);
- platform_->RunForPeriod(k10Ms);
- EXPECT_THAT(FilteredConsoleMessages(),
- ElementsAre(console_message, console_message, console_message,
- console_message));
- platform_->RunForPeriod(base::TimeDelta::FromSeconds(1) - k10Ms);
- EXPECT_THAT(FilteredConsoleMessages(),
- ElementsAre(console_message, console_message, console_message,
- console_message, console_message));
-}
-
-namespace {
-
-class OptOutZeroTimeoutFromThrottlingTest : public ThrottlingTestBase {
- public:
- OptOutZeroTimeoutFromThrottlingTest() {
- scoped_feature_list_.InitAndEnableFeature(
- features::kOptOutZeroTimeoutTimersFromThrottling);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-} // namespace
-
-// Verify that in a hidden page, when the kOptOutZeroTimeoutTimersFromThrottling
-// feature is enabled:
+// Verify the execution time of non-nested timers on a hidden page.
// - setTimeout(..., 0) and setTimeout(..., -1) schedule their callback after
// 1ms. The 1 ms delay exists for historical reasons crbug.com/402694.
// - setTimeout(..., 5) schedules its callback at the next aligned time
-TEST_F(OptOutZeroTimeoutFromThrottlingTest, WithoutNesting) {
+TEST_F(BackgroundPageThrottlingTest, WithoutNesting) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
@@ -228,10 +176,9 @@ TEST_F(OptOutZeroTimeoutFromThrottlingTest, WithoutNesting) {
timeout_5_message));
}
-// Verify that in a hidden page, when the kOptOutZeroTimeoutTimersFromThrottling
-// feature is enabled, a timer created with setTimeout(..., 0) is throttled
-// after 5 nesting levels.
-TEST_F(OptOutZeroTimeoutFromThrottlingTest, SetTimeoutNesting) {
+// Verify that on a hidden page, a timer created with setTimeout(..., 0) is
+// throttled after 5 nesting levels.
+TEST_F(BackgroundPageThrottlingTest, NestedSetTimeoutZero) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
@@ -262,10 +209,9 @@ TEST_F(OptOutZeroTimeoutFromThrottlingTest, SetTimeoutNesting) {
EXPECT_THAT(FilteredConsoleMessages(), Vector<String>(5, console_message));
}
-// Verify that in a hidden page, when the kOptOutZeroTimeoutTimersFromThrottling
-// feature is enabled, a timer created with setInterval(..., 0) is throttled
-// after 5 nesting levels.
-TEST_F(OptOutZeroTimeoutFromThrottlingTest, SetIntervalNesting) {
+// Verify that in a hidden page, a timer created with setInterval(..., 0) is
+// throttled after 5 nesting levels.
+TEST_F(BackgroundPageThrottlingTest, NestedSetIntervalZero) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
diff --git a/chromium/third_party/blink/renderer/core/script/DIR_METADATA b/chromium/third_party/blink/renderer/core/script/DIR_METADATA
new file mode 100644
index 00000000000..b7353a18c04
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/script/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>HTML>Script"
+}
+
+team_email: "module-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/script/OWNERS b/chromium/third_party/blink/renderer/core/script/OWNERS
index 9413cd7999d..ec3c853c9fc 100644
--- a/chromium/third_party/blink/renderer/core/script/OWNERS
+++ b/chromium/third_party/blink/renderer/core/script/OWNERS
@@ -2,6 +2,3 @@ dom@chromium.org
hiroshige@chromium.org
jbroman@chromium.org
kouhei@chromium.org
-
-# TEAM: module-dev@chromium.org
-# COMPONENT: Blink>HTML>Script
diff --git a/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc b/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
index e6bbe213760..460936df8cb 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/classic_pending_script.cc
@@ -126,71 +126,6 @@ NOINLINE void ClassicPendingScript::CheckState() const {
DCHECK_EQ(is_external_, !!GetResource());
}
-namespace {
-
-enum class StreamedBoolean {
- // Must match BooleanStreamed in enums.xml.
- kNotStreamed = 0,
- kStreamed = 1,
- kMaxValue = kStreamed
-};
-
-void RecordStartedStreamingHistogram(ScriptSchedulingType type,
- bool did_use_streamer) {
- StreamedBoolean streamed = did_use_streamer ? StreamedBoolean::kStreamed
- : StreamedBoolean::kNotStreamed;
- switch (type) {
- case ScriptSchedulingType::kParserBlocking: {
- UMA_HISTOGRAM_ENUMERATION(
- "WebCore.Scripts.ParsingBlocking.StartedStreaming", streamed);
- break;
- }
- case ScriptSchedulingType::kDefer: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Deferred.StartedStreaming",
- streamed);
- break;
- }
- case ScriptSchedulingType::kAsync: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Async.StartedStreaming",
- streamed);
- break;
- }
- default: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Other.StartedStreaming",
- streamed);
- break;
- }
- }
-}
-
-void RecordNotStreamingReasonHistogram(
- ScriptSchedulingType type,
- ScriptStreamer::NotStreamingReason reason) {
- switch (type) {
- case ScriptSchedulingType::kParserBlocking: {
- UMA_HISTOGRAM_ENUMERATION(
- "WebCore.Scripts.ParsingBlocking.NotStreamingReason", reason);
- break;
- }
- case ScriptSchedulingType::kDefer: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Deferred.NotStreamingReason",
- reason);
- break;
- }
- case ScriptSchedulingType::kAsync: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Async.NotStreamingReason",
- reason);
- break;
- }
- default: {
- UMA_HISTOGRAM_ENUMERATION("WebCore.Scripts.Other.NotStreamingReason",
- reason);
- break;
- }
- }
-}
-
-} // namespace
void ClassicPendingScript::RecordThirdPartyRequestWithCookieIfNeeded(
const ResourceResponse& response) const {
@@ -236,16 +171,6 @@ void ClassicPendingScript::RecordThirdPartyRequestWithCookieIfNeeded(
kUndeferrableThirdPartySubresourceRequestWithCookie);
}
-void ClassicPendingScript::RecordStreamingHistogram(
- ScriptSchedulingType type,
- bool can_use_streamer,
- ScriptStreamer::NotStreamingReason reason) {
- RecordStartedStreamingHistogram(type, can_use_streamer);
- if (!can_use_streamer) {
- DCHECK_NE(ScriptStreamer::NotStreamingReason::kInvalid, reason);
- RecordNotStreamingReasonHistogram(type, reason);
- }
-}
void ClassicPendingScript::DisposeInternal() {
MemoryPressureListenerRegistry::Instance().UnregisterClient(this);
@@ -373,8 +298,9 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
}
DCHECK(!GetResource());
- RecordStreamingHistogram(GetSchedulingType(), false,
- ScriptStreamer::NotStreamingReason::kInlineScript);
+ ScriptStreamer::RecordStreamingHistogram(
+ GetSchedulingType(), false,
+ ScriptStreamer::NotStreamingReason::kInlineScript);
ScriptSourceCode source_code(source_text_for_inline_script_,
source_location_type_, cache_handler,
@@ -385,7 +311,7 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
}
DCHECK(GetResource()->IsLoaded());
- ScriptResource* resource = ToScriptResource(GetResource());
+ auto* resource = To<ScriptResource>(GetResource());
RecordThirdPartyRequestWithCookieIfNeeded(resource->GetResponse());
auto* fetcher = GetElement()->GetExecutionContext()->Fetcher();
@@ -398,34 +324,25 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
}
// Check if we can use the script streamer.
- bool did_stream = false;
- ScriptStreamer::NotStreamingReason not_streamed_reason =
- resource->NoStreamerReason();
- ScriptStreamer* streamer = resource->TakeStreamer();
- if (streamer) {
- DCHECK_EQ(not_streamed_reason,
- ScriptStreamer::NotStreamingReason::kInvalid);
- if (streamer->IsStreamingSuppressed()) {
- not_streamed_reason = streamer->StreamingSuppressedReason();
- } else if (ready_state_ == kErrorOccurred) {
- not_streamed_reason = ScriptStreamer::NotStreamingReason::kErrorOccurred;
- } else if (not_streamed_reason ==
- ScriptStreamer::NotStreamingReason::kInvalid) {
- // streamer can be used to compile script.
- CHECK_EQ(ready_state_, kReady);
- did_stream = true;
- }
+ ScriptStreamer* streamer;
+ ScriptStreamer::NotStreamingReason not_streamed_reason;
+ std::tie(streamer, not_streamed_reason) = ScriptStreamer::TakeFrom(resource);
+
+ if (ready_state_ == kErrorOccurred) {
+ not_streamed_reason = ScriptStreamer::NotStreamingReason::kErrorOccurred;
+ streamer = nullptr;
}
- RecordStreamingHistogram(GetSchedulingType(), did_stream,
- not_streamed_reason);
+ if (streamer)
+ CHECK_EQ(ready_state_, kReady);
+ ScriptStreamer::RecordStreamingHistogram(GetSchedulingType(), streamer,
+ not_streamed_reason);
TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"ClassicPendingScript::GetSource", this,
TRACE_EVENT_FLAG_FLOW_IN, "not_streamed_reason",
not_streamed_reason);
- ScriptSourceCode source_code(did_stream ? streamer : nullptr, resource,
- not_streamed_reason);
+ ScriptSourceCode source_code(streamer, resource, not_streamed_reason);
// The base URL for external classic script is
//
// <spec href="https://html.spec.whatwg.org/C/#concept-script-base-url">
diff --git a/chromium/third_party/blink/renderer/core/script/classic_pending_script.h b/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
index 842eed80761..503c7138e15 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
+++ b/chromium/third_party/blink/renderer/core/script/classic_pending_script.h
@@ -97,10 +97,6 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
void NotifyFinished(Resource*) override;
String DebugName() const override { return "PendingScript"; }
- static void RecordStreamingHistogram(
- ScriptSchedulingType type,
- bool can_use_streamer,
- ScriptStreamer::NotStreamingReason reason);
void RecordThirdPartyRequestWithCookieIfNeeded(const ResourceResponse&) const;
// MemoryPressureListener
diff --git a/chromium/third_party/blink/renderer/core/script/classic_script.cc b/chromium/third_party/blink/renderer/core/script/classic_script.cc
index 742bf3ca8de..702f35b4f10 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/classic_script.cc
@@ -25,41 +25,63 @@ void ClassicScript::Trace(Visitor* visitor) const {
visitor->Trace(script_source_code_);
}
+ScriptEvaluationResult ClassicScript::RunScriptOnScriptStateAndReturnValue(
+ ScriptState* script_state,
+ ExecuteScriptPolicy policy,
+ V8ScriptRunner::RethrowErrorsOption rethrow_errors) {
+ return V8ScriptRunner::CompileAndRunScript(script_state, this, policy,
+ std::move(rethrow_errors));
+}
+
void ClassicScript::RunScript(LocalDOMWindow* window) {
return RunScript(window,
- ScriptController::kDoNotExecuteScriptWhenScriptsDisabled);
+ ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled);
}
void ClassicScript::RunScript(LocalDOMWindow* window,
- ScriptController::ExecuteScriptPolicy policy) {
+ ExecuteScriptPolicy policy) {
v8::HandleScope handle_scope(window->GetIsolate());
RunScriptAndReturnValue(window, policy);
}
v8::Local<v8::Value> ClassicScript::RunScriptAndReturnValue(
LocalDOMWindow* window,
- ScriptController::ExecuteScriptPolicy policy) {
- return window->GetScriptController().EvaluateScriptInMainWorld(
- GetScriptSourceCode(), BaseURL(), sanitize_script_errors_, FetchOptions(),
- policy);
+ ExecuteScriptPolicy policy) {
+ ScriptEvaluationResult result = RunScriptOnScriptStateAndReturnValue(
+ ToScriptStateForMainWorld(window->GetFrame()), policy);
+
+ if (result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess)
+ return result.GetSuccessValue();
+ return v8::Local<v8::Value>();
}
v8::Local<v8::Value> ClassicScript::RunScriptInIsolatedWorldAndReturnValue(
LocalDOMWindow* window,
int32_t world_id) {
- return window->GetScriptController().ExecuteScriptInIsolatedWorld(
- world_id, GetScriptSourceCode(), BaseURL(), sanitize_script_errors_);
+ DCHECK_GT(world_id, 0);
+
+ // Unlike other methods, RunScriptInIsolatedWorldAndReturnValue()'s
+ // default policy is kExecuteScriptWhenScriptsDisabled, to keep existing
+ // behavior.
+ ScriptEvaluationResult result = RunScriptOnScriptStateAndReturnValue(
+ ToScriptState(window->GetFrame(),
+ *DOMWrapperWorld::EnsureIsolatedWorld(
+ ToIsolate(window->GetFrame()), world_id)),
+ ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled);
+
+ if (result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess)
+ return result.GetSuccessValue();
+ return v8::Local<v8::Value>();
}
bool ClassicScript::RunScriptOnWorkerOrWorklet(
WorkerOrWorkletGlobalScope& global_scope) {
DCHECK(global_scope.IsContextThread());
- ScriptState::Scope scope(global_scope.ScriptController()->GetScriptState());
- ScriptEvaluationResult result =
- global_scope.ScriptController()->EvaluateAndReturnValue(
- GetScriptSourceCode(), sanitize_script_errors_,
- global_scope.GetV8CacheOptions());
+ v8::HandleScope handle_scope(
+ global_scope.ScriptController()->GetScriptState()->GetIsolate());
+ ScriptEvaluationResult result = RunScriptOnScriptStateAndReturnValue(
+ global_scope.ScriptController()->GetScriptState());
return result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess;
}
diff --git a/chromium/third_party/blink/renderer/core/script/classic_script.h b/chromium/third_party/blink/renderer/core/script/classic_script.h
index e094c2396ec..117fc84b9cb 100644
--- a/chromium/third_party/blink/renderer/core/script/classic_script.h
+++ b/chromium/third_party/blink/renderer/core/script/classic_script.h
@@ -6,8 +6,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_CLASSIC_SCRIPT_H_
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/script/script.h"
@@ -44,19 +44,31 @@ class CORE_EXPORT ClassicScript final : public Script {
const ScriptSourceCode& GetScriptSourceCode() const {
return script_source_code_;
}
+ SanitizeScriptErrors GetSanitizeScriptErrors() const {
+ return sanitize_script_errors_;
+ }
- // TODO(crbug/1111134): The RunScript() with ExecuteScriptPolicy is declared
- // and overloaded here to avoid modifying Script::RunScript(), because this is
- // a tentative interface. When crbug/1111134 is done, this should be gone.
+ // TODO(crbug.com/1111134): Methods with ExecuteScriptPolicy are declared and
+ // overloaded here to avoid modifying Script::RunScript*(), because this is a
+ // tentative interface. When crbug/1111134 is done, these should be gone.
+ // TODO(crbug.com/1111134): Refactor RunScript*() interfaces.
void RunScript(LocalDOMWindow*) override;
- void RunScript(LocalDOMWindow*, ScriptController::ExecuteScriptPolicy);
+ void RunScript(LocalDOMWindow*, ExecuteScriptPolicy);
bool RunScriptOnWorkerOrWorklet(WorkerOrWorkletGlobalScope&) override;
// Unlike RunScript() and RunScriptOnWorkerOrWorklet(), callers of the
// following methods must enter a v8::HandleScope before calling.
+ // TODO(crbug.com/1129743): Use ScriptEvaluationResult instead of
+ // v8::Local<v8::Value> as the return type.
+ ScriptEvaluationResult RunScriptOnScriptStateAndReturnValue(
+ ScriptState*,
+ ExecuteScriptPolicy =
+ ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled,
+ V8ScriptRunner::RethrowErrorsOption =
+ V8ScriptRunner::RethrowErrorsOption::DoNotRethrow());
v8::Local<v8::Value> RunScriptAndReturnValue(
LocalDOMWindow*,
- ScriptController::ExecuteScriptPolicy = ScriptController::
+ ExecuteScriptPolicy =
ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled);
v8::Local<v8::Value> RunScriptInIsolatedWorldAndReturnValue(LocalDOMWindow*,
int32_t world_id);
diff --git a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
index 56d50a7b409..75b2adf534a 100644
--- a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.cc
@@ -4,11 +4,7 @@
#include "third_party/blink/renderer/core/script/document_modulator_impl.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/settings.h"
#include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
@@ -17,7 +13,7 @@ DocumentModulatorImpl::DocumentModulatorImpl(ScriptState* script_state)
ModuleScriptFetcher* DocumentModulatorImpl::CreateModuleScriptFetcher(
ModuleScriptCustomFetchType custom_fetch_type,
- util::PassKey<ModuleScriptLoader> pass_key) {
+ base::PassKey<ModuleScriptLoader> pass_key) {
DCHECK_EQ(ModuleScriptCustomFetchType::kNone, custom_fetch_type);
return MakeGarbageCollected<DocumentModuleScriptFetcher>(pass_key);
}
@@ -26,12 +22,4 @@ bool DocumentModulatorImpl::IsDynamicImportForbidden(String* reason) {
return false;
}
-mojom::blink::V8CacheOptions DocumentModulatorImpl::GetV8CacheOptions() const {
- LocalDOMWindow* window = To<LocalDOMWindow>(GetExecutionContext());
- const Settings* settings = window->GetFrame()->GetSettings();
- if (settings)
- return settings->GetV8CacheOptions();
- return mojom::blink::V8CacheOptions::kDefault;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
index e453b4f03e3..a4846d28bfd 100644
--- a/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/document_modulator_impl.h
@@ -26,12 +26,11 @@ class DocumentModulatorImpl final : public ModulatorImplBase {
// Implements Modulator.
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader>) override;
+ base::PassKey<ModuleScriptLoader>) override;
private:
// Implements ModulatorImplBase.
bool IsDynamicImportForbidden(String* reason) override;
- mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
index 9c51a277f34..a02c2198a09 100644
--- a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
@@ -259,7 +259,7 @@ void DynamicModuleResolver::Trace(Visitor* visitor) const {
// <specdef
// href="https://html.spec.whatwg.org/C/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)">
void DynamicModuleResolver::ResolveDynamically(
- const String& specifier,
+ const ModuleRequest& module_request,
const KURL& referrer_resource_url,
const ReferrerScriptInfo& referrer_info,
ScriptPromiseResolver* promise_resolver) {
@@ -267,14 +267,6 @@ void DynamicModuleResolver::ResolveDynamically(
<< "ResolveDynamically should be called from V8 callback, within a valid "
"context.";
- // https://github.com/WICG/import-maps/blob/master/spec.md#when-import-maps-can-be-encountered
- // Strictly, the flag should be cleared at
- // #internal-module-script-graph-fetching-procedure, i.e. in ModuleTreeLinker,
- // but due to https://crbug.com/928435 https://crbug.com/928564 we also clears
- // the flag here, as import maps can be accessed earlier than specced below
- // (in ResolveModuleSpecifier()) and we need to clear the flag before that.
- modulator_->ClearIsAcquiringImportMaps();
-
// <spec step="4.1">Let referencing script be
// referencingScriptOrModule.[[HostDefined]].</spec>
@@ -302,21 +294,37 @@ void DynamicModuleResolver::ResolveDynamically(
// <specdef label="fetch-an-import()-module-script-graph"
// href="https://html.spec.whatwg.org/C/#fetch-an-import()-module-script-graph">
+ // https://wicg.github.io/import-maps/#wait-for-import-maps
+ // 1.2. Set document’s acquiring import maps to false. [spec text]
+ modulator_->SetAcquiringImportMapsState(
+ Modulator::AcquiringImportMapsState::kAfterModuleScriptLoad);
+
// <spec label="fetch-an-import()-module-script-graph" step="1">Let url be the
// result of resolving a module specifier given base URL and specifier.</spec>
- KURL url = modulator_->ResolveModuleSpecifier(specifier, base_url);
+ KURL url =
+ modulator_->ResolveModuleSpecifier(module_request.specifier, base_url);
+
+ ModuleType module_type = modulator_->ModuleTypeFromRequest(module_request);
// <spec label="fetch-an-import()-module-script-graph" step="2">If url is
// failure, then asynchronously complete this algorithm with null, and abort
// these steps.</spec>
- if (!url.IsValid()) {
+ if (!url.IsValid() || module_type == ModuleType::kInvalid) {
// <spec step="6">If result is null, then:</spec>
- //
+ String error_message;
+ if (!url.IsValid()) {
+ error_message = "Failed to resolve module specifier '" +
+ module_request.specifier + "'";
+ } else {
+ error_message = "\"" + module_request.GetModuleTypeString() +
+ "\" is not a valid module type.";
+ }
+
// <spec step="6.1">Let completion be Completion { [[Type]]: throw,
// [[Value]]: a new TypeError, [[Target]]: empty }.</spec>
v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
- v8::Local<v8::Value> error = V8ThrowException::CreateTypeError(
- isolate, "Failed to resolve module specifier '" + specifier + "'");
+ v8::Local<v8::Value> error =
+ V8ThrowException::CreateTypeError(isolate, error_message);
// <spec step="6.2">Perform FinishDynamicImport(referencingScriptOrModule,
// specifier, promiseCapability, completion).</spec>
@@ -334,7 +342,8 @@ void DynamicModuleResolver::ResolveDynamically(
switch (referrer_info.GetBaseUrlSource()) {
case ReferrerScriptInfo::BaseUrlSource::kClassicScriptCORSSameOrigin:
- if (!modulator_->ResolveModuleSpecifier(specifier, BlankURL())
+ if (!modulator_
+ ->ResolveModuleSpecifier(module_request.specifier, BlankURL())
.IsValid()) {
UseCounter::Count(
ExecutionContext::From(modulator_->GetScriptState()),
@@ -342,7 +351,8 @@ void DynamicModuleResolver::ResolveDynamically(
}
break;
case ReferrerScriptInfo::BaseUrlSource::kClassicScriptCORSCrossOrigin:
- if (!modulator_->ResolveModuleSpecifier(specifier, BlankURL())
+ if (!modulator_
+ ->ResolveModuleSpecifier(module_request.specifier, BlankURL())
.IsValid()) {
UseCounter::Count(
ExecutionContext::From(modulator_->GetScriptState()),
@@ -372,7 +382,8 @@ void DynamicModuleResolver::ResolveDynamically(
String(), referrer_info.ParserState(),
referrer_info.CredentialsMode(),
referrer_info.GetReferrerPolicy(),
- mojom::FetchImportanceMode::kImportanceAuto);
+ mojom::blink::FetchImportanceMode::kImportanceAuto,
+ RenderBlockingBehavior::kNonBlocking);
// <spec label="fetch-an-import()-module-script-graph" step="3">Fetch a single
// module script given url, settings object, "script", options, settings
@@ -388,7 +399,7 @@ void DynamicModuleResolver::ResolveDynamically(
ExecutionContext::From(modulator_->GetScriptState());
if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context))
scope->EnsureFetcher();
- modulator_->FetchTree(url, execution_context->Fetcher(),
+ modulator_->FetchTree(url, module_type, execution_context->Fetcher(),
mojom::blink::RequestContextType::SCRIPT,
network::mojom::RequestDestination::kScript, options,
ModuleScriptCustomFetchType::kNone, tree_client);
diff --git a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.h b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.h
index 0052276c6b1..1c8bd2cccc6 100644
--- a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.h
+++ b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver.h
@@ -16,6 +16,7 @@ namespace blink {
class Modulator;
class ReferrerScriptInfo;
class ScriptPromiseResolver;
+struct ModuleRequest;
// DynamicModuleResolver implements "Runtime Semantics:
// HostImportModuleDynamically" per spec.
@@ -30,7 +31,7 @@ class CORE_EXPORT DynamicModuleResolver final
// Implements "HostImportModuleDynamically" semantics.
// Should be called w/ a valid V8 context.
- void ResolveDynamically(const String& specifier,
+ void ResolveDynamically(const ModuleRequest& module_request,
const KURL& referrer_resource_url,
const ReferrerScriptInfo& referrer_info,
ScriptPromiseResolver*);
diff --git a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index 67af9dccf85..802fe840bd2 100644
--- a/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/script/js_module_script.h"
#include "third_party/blink/renderer/core/testing/dummy_modulator.h"
@@ -26,6 +27,8 @@ namespace {
constexpr const char* kTestReferrerURL = "https://example.com/referrer.js";
constexpr const char* kTestDependencyURL = "https://example.com/dependency.js";
+constexpr const char* kTestDependencyURLJSON =
+ "https://example.com/dependency.json";
const KURL TestReferrerURL() {
return KURL(kTestReferrerURL);
@@ -33,6 +36,9 @@ const KURL TestReferrerURL() {
const KURL TestDependencyURL() {
return KURL(kTestDependencyURL);
}
+const KURL TestDependencyURLJSON() {
+ return KURL(kTestDependencyURLJSON);
+}
class DynamicModuleResolverTestModulator final : public DummyModulator {
public:
@@ -50,6 +56,9 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
void SetExpectedFetchTreeURL(const KURL& url) {
expected_fetch_tree_url_ = url;
}
+ void SetExpectedFetchTreeModuleType(const ModuleType& module_type) {
+ expected_fetch_tree_module_type_ = module_type;
+ }
bool fetch_tree_was_called() const { return fetch_tree_was_called_; }
void Trace(Visitor*) const override;
@@ -58,7 +67,8 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
// Implements Modulator:
ScriptState* GetScriptState() final { return script_state_; }
- ModuleScript* GetFetchedModuleScript(const KURL& url) final {
+ ModuleScript* GetFetchedModuleScript(const KURL& url,
+ ModuleType module_type) final {
EXPECT_EQ(TestReferrerURL(), url);
ModuleScript* module_script =
JSModuleScript::CreateForTest(this, v8::Local<v8::Module>(), url);
@@ -74,9 +84,10 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
return KURL(base_url, module_request);
}
- void ClearIsAcquiringImportMaps() final {}
+ void SetAcquiringImportMapsState(AcquiringImportMapsState) final {}
void FetchTree(const KURL& url,
+ ModuleType module_type,
ResourceFetcher*,
mojom::blink::RequestContextType,
network::mojom::RequestDestination,
@@ -84,6 +95,7 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
ModuleScriptCustomFetchType custom_fetch_type,
ModuleTreeClient* client) final {
EXPECT_EQ(expected_fetch_tree_url_, url);
+ EXPECT_EQ(expected_fetch_tree_module_type_, module_type);
// Currently there are no usage of custom fetch hooks for dynamic import in
// web specifications.
@@ -96,6 +108,7 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
Member<ScriptState> script_state_;
Member<ModuleTreeClient> pending_client_;
KURL expected_fetch_tree_url_;
+ ModuleType expected_fetch_tree_module_type_ = ModuleType::kJavaScript;
bool fetch_tree_was_called_ = false;
};
@@ -225,16 +238,16 @@ TEST_P(DynamicModuleResolverTest, ResolveSuccess) {
scope.GetScriptState()));
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
- resolver->ResolveDynamically("./dependency.js", TestReferrerURL(),
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ Vector<ImportAssertion>());
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
ReferrerScriptInfo(), promise_resolver);
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
EXPECT_FALSE(capture->WasCalled());
- v8::Local<v8::Module> record = ModuleRecord::Compile(
- scope.GetIsolate(), "export const foo = 'hello';", TestReferrerURL(),
- TestReferrerURL(), ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> record = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const foo = 'hello';", TestReferrerURL());
ModuleScript* module_script =
JSModuleScript::CreateForTest(modulator, record, TestDependencyURL());
EXPECT_TRUE(ModuleRecord::Instantiate(scope.GetScriptState(), record,
@@ -247,6 +260,33 @@ TEST_P(DynamicModuleResolverTest, ResolveSuccess) {
EXPECT_EQ("hello", capture->CapturedValue());
}
+TEST_P(DynamicModuleResolverTest, ResolveJSONModuleSuccess) {
+ V8TestingScope scope;
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
+ modulator->SetExpectedFetchTreeURL(TestDependencyURLJSON());
+ modulator->SetExpectedFetchTreeModuleType(ModuleType::kJSON);
+
+ auto* promise_resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
+ ScriptPromise promise = promise_resolver->Promise();
+
+ auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
+ Vector<ImportAssertion> import_assertions{
+ ImportAssertion("type", "json", TextPosition())};
+ ModuleRequest module_request("./dependency.json", TextPosition(),
+ import_assertions);
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
+ ReferrerScriptInfo(), promise_resolver);
+
+ // Instantiating and evaluating a JSON module requires a lot of
+ // machinery not currently available in this unit test suite. For
+ // the purposes of a DynamicModuleResolver unit test, it should be sufficient
+ // to validate that the correct arguments are passed from
+ // DynamicModuleResolver::ResolveDynamically to Modulator::FetchTree, which is
+ // validated during DynamicModuleResolverTestModulator::FetchTree.
+}
+
TEST_P(DynamicModuleResolverTest, ResolveSpecifierFailure) {
V8TestingScope scope;
auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
@@ -264,7 +304,9 @@ TEST_P(DynamicModuleResolverTest, ResolveSpecifierFailure) {
capture->Bind());
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
- resolver->ResolveDynamically("invalid-specifier", TestReferrerURL(),
+ ModuleRequest module_request("invalid-specifier", TextPosition(),
+ Vector<ImportAssertion>());
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
ReferrerScriptInfo(), promise_resolver);
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
@@ -273,6 +315,36 @@ TEST_P(DynamicModuleResolverTest, ResolveSpecifierFailure) {
EXPECT_TRUE(capture->Message().StartsWith("Failed to resolve"));
}
+TEST_P(DynamicModuleResolverTest, ResolveModuleTypeFailure) {
+ V8TestingScope scope;
+ auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
+ scope.GetScriptState());
+ modulator->SetExpectedFetchTreeURL(TestDependencyURL());
+
+ auto* promise_resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
+ ScriptPromise promise = promise_resolver->Promise();
+
+ auto* capture =
+ MakeGarbageCollected<CaptureErrorFunction>(scope.GetScriptState());
+ promise.Then(DynamicModuleResolverTestNotReached::CreateFunction(
+ scope.GetScriptState()),
+ capture->Bind());
+
+ auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
+ Vector<ImportAssertion> import_assertions{
+ ImportAssertion("type", "notARealType", TextPosition())};
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ import_assertions);
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
+ ReferrerScriptInfo(), promise_resolver);
+
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ EXPECT_TRUE(capture->WasCalled());
+ EXPECT_EQ("TypeError", capture->Name());
+ EXPECT_EQ("\"notARealType\" is not a valid module type.", capture->Message());
+}
+
TEST_P(DynamicModuleResolverTest, FetchFailure) {
V8TestingScope scope;
auto* modulator = MakeGarbageCollected<DynamicModuleResolverTestModulator>(
@@ -290,7 +362,9 @@ TEST_P(DynamicModuleResolverTest, FetchFailure) {
capture->Bind());
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
- resolver->ResolveDynamically("./dependency.js", TestReferrerURL(),
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ Vector<ImportAssertion>());
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
ReferrerScriptInfo(), promise_resolver);
EXPECT_FALSE(capture->WasCalled());
@@ -320,15 +394,15 @@ TEST_P(DynamicModuleResolverTest, ExceptionThrown) {
capture->Bind());
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
- resolver->ResolveDynamically("./dependency.js", TestReferrerURL(),
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ Vector<ImportAssertion>());
+ resolver->ResolveDynamically(module_request, TestReferrerURL(),
ReferrerScriptInfo(), promise_resolver);
EXPECT_FALSE(capture->WasCalled());
- v8::Local<v8::Module> record = ModuleRecord::Compile(
- scope.GetIsolate(), "throw Error('bar')", TestReferrerURL(),
- TestReferrerURL(), ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> record = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "throw Error('bar')", TestReferrerURL());
ModuleScript* module_script =
JSModuleScript::CreateForTest(modulator, record, TestDependencyURL());
EXPECT_TRUE(ModuleRecord::Instantiate(scope.GetScriptState(), record,
@@ -361,16 +435,16 @@ TEST_P(DynamicModuleResolverTest, ResolveWithNullReferrerScriptSuccess) {
scope.GetScriptState()));
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
- resolver->ResolveDynamically("./dependency.js", /* null referrer */ KURL(),
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ Vector<ImportAssertion>());
+ resolver->ResolveDynamically(module_request, /* null referrer */ KURL(),
ReferrerScriptInfo(), promise_resolver);
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
EXPECT_FALSE(capture->WasCalled());
- v8::Local<v8::Module> record = ModuleRecord::Compile(
- scope.GetIsolate(), "export const foo = 'hello';", TestDependencyURL(),
- TestDependencyURL(), ScriptFetchOptions(),
- TextPosition::MinimumPosition(), ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> record = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const foo = 'hello';", TestDependencyURL());
ModuleScript* module_script =
JSModuleScript::CreateForTest(modulator, record, TestDependencyURL());
EXPECT_TRUE(ModuleRecord::Instantiate(scope.GetScriptState(), record,
@@ -397,8 +471,10 @@ TEST_P(DynamicModuleResolverTest, ResolveWithReferrerScriptInfoBaseURL) {
auto* resolver = MakeGarbageCollected<DynamicModuleResolver>(modulator);
KURL wrong_base_url("https://example.com/wrong/bar.js");
KURL correct_base_url("https://example.com/correct/baz.js");
+ ModuleRequest module_request("./dependency.js", TextPosition(),
+ Vector<ImportAssertion>());
resolver->ResolveDynamically(
- "./dependency.js", wrong_base_url,
+ module_request, wrong_base_url,
ReferrerScriptInfo(correct_base_url, ScriptFetchOptions(),
ReferrerScriptInfo::BaseUrlSource::kOther),
promise_resolver);
diff --git a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
index 4bb932dd634..69789c92f1f 100644
--- a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
@@ -38,13 +38,6 @@ FetchClientSettingsObjectImpl::GetReferrerPolicy() const {
return execution_context_->GetReferrerPolicy();
}
-base::Optional<network::mojom::blink::ReferrerPolicy>
-FetchClientSettingsObjectImpl::
- GetReferrerPolicyDisregardingMetaTagsContainingLists() const {
- DCHECK(execution_context_->IsContextThread());
- return execution_context_->ReferrerPolicyButForMetaTagsWithListsOfPolicies();
-}
-
const String FetchClientSettingsObjectImpl::GetOutgoingReferrer() const {
DCHECK(execution_context_->IsContextThread());
return execution_context_->OutgoingReferrer();
diff --git a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
index a7445761aff..a00c6605b3a 100644
--- a/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
@@ -36,8 +36,6 @@ class CORE_EXPORT FetchClientSettingsObjectImpl final
const KURL& BaseUrl() const override;
const SecurityOrigin* GetSecurityOrigin() const override;
network::mojom::ReferrerPolicy GetReferrerPolicy() const override;
- base::Optional<network::mojom::blink::ReferrerPolicy>
- GetReferrerPolicyDisregardingMetaTagsContainingLists() const override;
const String GetOutgoingReferrer() const override;
diff --git a/chromium/third_party/blink/renderer/core/script/import_map.cc b/chromium/third_party/blink/renderer/core/script/import_map.cc
index 7149f83766b..1e1a78b696c 100644
--- a/chromium/third_party/blink/renderer/core/script/import_map.cc
+++ b/chromium/third_party/blink/renderer/core/script/import_map.cc
@@ -431,6 +431,15 @@ base::Optional<KURL> ImportMap::ResolveImportsMatch(
return ResolveImportsMatchInternal(key, exact, debug_message);
}
+ // <spec step="1.2">... either asURL is null, or asURL is special</spec>
+ if (parsed_specifier.GetType() == ParsedSpecifier::Type::kURL &&
+ !SchemeRegistry::IsSpecialScheme(parsed_specifier.GetUrl().Protocol())) {
+ *debug_message = "Import Map: \"" + key +
+ "\" skips prefix match because of non-special URL scheme";
+
+ return base::nullopt;
+ }
+
// Step 1.2.
if (auto prefix_match = MatchPrefix(parsed_specifier, specifier_map)) {
return ResolveImportsMatchInternal(key, *prefix_match, debug_message);
@@ -483,7 +492,17 @@ KURL ImportMap::ResolveImportsMatchInternal(const String& key,
return NullURL();
}
- // <spec step="1.2.8">Return url.</spec>
+ // <spec step="1.2.8">If the serialization of url does not start with the
+ // serialization of resolutionResult, then throw a TypeError indicating that
+ // resolution of normalizedSpecifier was blocked due to it backtracking above
+ // its prefix specifierKey.</spec>
+ if (!url.GetString().StartsWith(matched->value.GetString())) {
+ *debug_message = "Import Map: \"" + key + "\" matches with \"" +
+ matched->key + "\" but is blocked due to backtracking";
+ return NullURL();
+ }
+
+ // <spec step="1.2.9">Return url.</spec>
*debug_message = "Import Map: \"" + key + "\" matches with \"" +
matched->key + "\" and is mapped to " + url.ElidedString();
return url;
diff --git a/chromium/third_party/blink/renderer/core/script/js_module_script.cc b/chromium/third_party/blink/renderer/core/script/js_module_script.cc
index 0e405957b1a..ecd5ee7e7eb 100644
--- a/chromium/third_party/blink/renderer/core/script/js_module_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/js_module_script.cc
@@ -5,8 +5,12 @@
#include "third_party/blink/renderer/core/script/js_module_script.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
+#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_record_resolver.h"
+#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "v8/include/v8.h"
namespace blink {
@@ -14,19 +18,16 @@ namespace blink {
// <specdef
// href="https://html.spec.whatwg.org/C/#creating-a-javascript-module-script">
JSModuleScript* JSModuleScript::Create(
- const ParkableString& original_source_text,
- SingleCachedMetadataHandler* cache_handler,
- ScriptSourceLocationType source_location_type,
+ const ModuleScriptCreationParams& original_params,
Modulator* modulator,
- const KURL& source_url,
- const KURL& base_url,
const ScriptFetchOptions& options,
const TextPosition& start_position) {
// <spec step="1">If scripting is disabled for settings's responsible browsing
// context, then set source to the empty string.</spec>
- ParkableString source_text;
- if (!modulator->IsScriptingDisabled())
- source_text = original_source_text;
+ const ModuleScriptCreationParams& params =
+ modulator->IsScriptingDisabled()
+ ? original_params.CopyWithClearedSourceText()
+ : original_params;
// <spec step="2">Let script be a new module script that this algorithm will
// subsequently initialize.</spec>
@@ -46,9 +47,8 @@ JSModuleScript* JSModuleScript::Create(
ModuleRecordProduceCacheData* produce_cache_data = nullptr;
v8::Local<v8::Module> result = ModuleRecord::Compile(
- isolate, source_text.ToString(), source_url, base_url, options,
- start_position, exception_state, modulator->GetV8CacheOptions(),
- cache_handler, source_location_type, &produce_cache_data);
+ isolate, params, options, start_position, exception_state,
+ modulator->GetV8CacheOptions(), &produce_cache_data);
// CreateInternal processes Steps 4 and 8-10.
//
@@ -56,9 +56,9 @@ JSModuleScript* JSModuleScript::Create(
// Steps 8-13 before Step 6. In a case that compile failed, we will
// immediately turn the script into errored state. Thus the members will not
// be used for the speced algorithms, but may be used from inspector.
- JSModuleScript* script =
- CreateInternal(source_text.length(), modulator, result, source_url,
- base_url, options, start_position, produce_cache_data);
+ JSModuleScript* script = CreateInternal(
+ params.GetSourceText().length(), modulator, result, params.SourceURL(),
+ params.BaseURL(), options, start_position, produce_cache_data);
// <spec step="8">If result is a list of errors, then:</spec>
if (exception_state.HadException()) {
@@ -82,21 +82,30 @@ JSModuleScript* JSModuleScript::Create(
//
// <spec step="9.2">If url is failure, then:</spec>
String failure_reason;
- if (script->ResolveModuleSpecifier(requested.specifier, &failure_reason)
- .IsValid())
- continue;
-
- // <spec step="9.2.1">Let error be a new TypeError exception.</spec>
- String error_message = "Failed to resolve module specifier \"" +
- requested.specifier + "\". " + failure_reason;
- v8::Local<v8::Value> error =
- V8ThrowException::CreateTypeError(isolate, error_message);
-
- // <spec step="9.2.2">Set script's parse error to error.</spec>
- script->SetParseErrorAndClearRecord(ScriptValue(isolate, error));
-
- // <spec step="9.2.3">Return script.</spec>
- return script;
+ bool module_specifier_is_valid =
+ script->ResolveModuleSpecifier(requested.specifier, &failure_reason)
+ .IsValid();
+ ModuleType module_type = modulator->ModuleTypeFromRequest(requested);
+
+ if (!module_specifier_is_valid || module_type == ModuleType::kInvalid) {
+ // <spec step="9.2.1">Let error be a new TypeError exception.</spec>
+ String error_message;
+ if (!module_specifier_is_valid) {
+ error_message = "Failed to resolve module specifier \"" +
+ requested.specifier + "\". " + failure_reason;
+ } else {
+ error_message = "\"" + requested.GetModuleTypeString() +
+ "\" is not a valid module type.";
+ }
+ v8::Local<v8::Value> error =
+ V8ThrowException::CreateTypeError(isolate, error_message);
+
+ // <spec step="9.2.2">Set script's parse error to error.</spec>
+ script->SetParseErrorAndClearRecord(ScriptValue(isolate, error));
+
+ // <spec step="9.2.3">Return script.</spec>
+ return script;
+ }
}
// <spec step="11">Return script.</spec>
diff --git a/chromium/third_party/blink/renderer/core/script/js_module_script.h b/chromium/third_party/blink/renderer/core/script/js_module_script.h
index 3309db52e0a..3ec0c483476 100644
--- a/chromium/third_party/blink/renderer/core/script/js_module_script.h
+++ b/chromium/third_party/blink/renderer/core/script/js_module_script.h
@@ -5,20 +5,19 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_JS_MODULE_SCRIPT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_JS_MODULE_SCRIPT_H_
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
namespace blink {
+class KURL;
+class Modulator;
+class ModuleScriptCreationParams;
+
// JSModuleScript is a model object for the "JavaScript module script" spec
// concept. https://html.spec.whatwg.org/C/#javascript-module-script
class CORE_EXPORT JSModuleScript final : public ModuleScript,
@@ -26,12 +25,8 @@ class CORE_EXPORT JSModuleScript final : public ModuleScript,
public:
// https://html.spec.whatwg.org/C/#creating-a-javascript-module-script
static JSModuleScript* Create(
- const ParkableString& source_text,
- SingleCachedMetadataHandler*,
- ScriptSourceLocationType,
+ const ModuleScriptCreationParams& params,
Modulator*,
- const KURL& source_url,
- const KURL& base_url,
const ScriptFetchOptions&,
const TextPosition& start_position = TextPosition::MinimumPosition());
diff --git a/chromium/third_party/blink/renderer/core/script/modulator.h b/chromium/third_party/blink/renderer/core/script/modulator.h
index fe0ac6d5204..2315177edef 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator.h
+++ b/chromium/third_party/blink/renderer/core/script/modulator.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_MODULATOR_H_
#include "base/single_thread_task_runner.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -38,6 +38,7 @@ class ModuleRecordResolver;
class ScriptPromiseResolver;
class ScriptState;
class ScriptValue;
+enum class ModuleType;
// A SingleModuleClient is notified when single module script node (node as in a
// module tree graph) load is complete and its corresponding entry is created in
@@ -129,6 +130,7 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
// ResourceFetcher represents "fetch client settings object"
// used in the "fetch a module worker script graph" algorithm.
virtual void FetchTree(const KURL&,
+ ModuleType,
ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
@@ -161,7 +163,11 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
// entry.
// Note: returns nullptr if the module map entry doesn't exist, or
// is still "fetching".
- virtual ModuleScript* GetFetchedModuleScript(const KURL&) = 0;
+ // ModuleType indicates the resource type of the module script, e.g.
+ // JavaScript, JSON, or CSS. This is used as part of the module map cache key
+ // alongside the URL, so both are needed to retrieve the correct module. See
+ // https://github.com/whatwg/html/pull/5883
+ virtual ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) = 0;
// https://html.spec.whatwg.org/C/#resolve-a-module-specifier
virtual KURL ResolveModuleSpecifier(const String& module_request,
@@ -169,7 +175,7 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
String* failure_reason = nullptr) = 0;
// https://tc39.github.io/proposal-dynamic-import/#sec-hostimportmoduledynamically
- virtual void ResolveDynamically(const String& specifier,
+ virtual void ResolveDynamically(const ModuleRequest& module_request,
const KURL&,
const ReferrerScriptInfo&,
ScriptPromiseResolver*) = 0;
@@ -178,12 +184,26 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
virtual ScriptValue CreateSyntaxError(const String& message) const = 0;
// Import maps. https://github.com/WICG/import-maps
+
+ // https://wicg.github.io/import-maps/#register-an-import-map
virtual void RegisterImportMap(const ImportMap*,
ScriptValue error_to_rethrow) = 0;
- virtual bool IsAcquiringImportMaps() const = 0;
- virtual void ClearIsAcquiringImportMaps() = 0;
virtual const ImportMap* GetImportMapForTest() const = 0;
+ // https://wicg.github.io/import-maps/#document-acquiring-import-maps
+ enum class AcquiringImportMapsState {
+ // The flag is true.
+ kAcquiring,
+
+ // The flag is false, due to multiple import maps.
+ kMultipleImportMaps,
+
+ // The flag is false, because module script loading is already started.
+ kAfterModuleScriptLoad
+ };
+ virtual AcquiringImportMapsState GetAcquiringImportMapsState() const = 0;
+ virtual void SetAcquiringImportMapsState(AcquiringImportMapsState) = 0;
+
// https://html.spec.whatwg.org/C/#hostgetimportmetaproperties
virtual ModuleImportMeta HostGetImportMetaProperties(
v8::Local<v8::Module>) const = 0;
@@ -195,9 +215,12 @@ class CORE_EXPORT Modulator : public GarbageCollected<Modulator>,
virtual Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
v8::Local<v8::Module>) = 0;
+ virtual ModuleType ModuleTypeFromRequest(
+ const ModuleRequest& module_request) const = 0;
+
virtual ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader> pass_key) = 0;
+ base::PassKey<ModuleScriptLoader> pass_key) = 0;
// Produce V8 code cache for the given ModuleScript and its submodules.
virtual void ProduceCacheModuleTreeTopLevel(ModuleScript*) = 0;
diff --git a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
index 87b44193588..fd0acf8e434 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
@@ -57,21 +58,27 @@ bool ModulatorImplBase::ImportMapsEnabled() const {
return RuntimeEnabledFeatures::ImportMapsEnabled(GetExecutionContext());
}
+mojom::blink::V8CacheOptions ModulatorImplBase::GetV8CacheOptions() const {
+ return GetExecutionContext()->GetV8CacheOptions();
+}
+
// <specdef label="fetch-a-module-script-tree"
// href="https://html.spec.whatwg.org/C/#fetch-a-module-script-tree">
// <specdef label="fetch-a-module-worker-script-tree"
// href="https://html.spec.whatwg.org/C/#fetch-a-module-worker-script-tree">
void ModulatorImplBase::FetchTree(
const KURL& url,
+ ModuleType module_type,
ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
const ScriptFetchOptions& options,
ModuleScriptCustomFetchType custom_fetch_type,
ModuleTreeClient* client) {
- ModuleTreeLinker::Fetch(url, fetch_client_settings_object_fetcher,
- context_type, destination, options, this,
- custom_fetch_type, tree_linker_registry_, client);
+ ModuleTreeLinker::Fetch(url, module_type,
+ fetch_client_settings_object_fetcher, context_type,
+ destination, options, this, custom_fetch_type,
+ tree_linker_registry_, client);
}
void ModulatorImplBase::FetchDescendantsForInlineScript(
@@ -96,8 +103,10 @@ void ModulatorImplBase::FetchSingle(
level, custom_fetch_type, client);
}
-ModuleScript* ModulatorImplBase::GetFetchedModuleScript(const KURL& url) {
- return map_->GetFetchedModuleScript(url);
+ModuleScript* ModulatorImplBase::GetFetchedModuleScript(
+ const KURL& url,
+ ModuleType module_type) {
+ return map_->GetFetchedModuleScript(url, module_type);
}
// <specdef href="https://html.spec.whatwg.org/C/#resolve-a-module-specifier">
@@ -206,13 +215,10 @@ void ModulatorImplBase::RegisterImportMap(const ImportMap* import_map,
//
// TODO(crbug.com/927119): Implement merging. Currently only one import map is
// allowed.
- if (import_map_) {
- GetExecutionContext()->AddConsoleMessage(
- mojom::ConsoleMessageSource::kOther, mojom::ConsoleMessageLevel::kError,
- "Multiple import maps are not yet supported. https://crbug.com/927119");
- return;
- }
+ // Because the second and subsequent import maps are already rejected in
+ // ScriptLoader::PrepareScript(), this is called only once.
+ DCHECK(!import_map_);
import_map_ = import_map;
}
@@ -221,7 +227,7 @@ bool ModulatorImplBase::HasValidContext() {
}
void ModulatorImplBase::ResolveDynamically(
- const String& specifier,
+ const ModuleRequest& module_request,
const KURL& referrer_url,
const ReferrerScriptInfo& referrer_info,
ScriptPromiseResolver* resolver) {
@@ -233,7 +239,7 @@ void ModulatorImplBase::ResolveDynamically(
}
UseCounter::Count(GetExecutionContext(),
WebFeature::kDynamicImportModuleScript);
- dynamic_module_resolver_->ResolveDynamically(specifier, referrer_url,
+ dynamic_module_resolver_->ResolveDynamically(module_request, referrer_url,
referrer_info, resolver);
}
@@ -270,6 +276,31 @@ Vector<ModuleRequest> ModulatorImplBase::ModuleRequestsFromModuleRecord(
return ModuleRecord::ModuleRequests(script_state_, module_record);
}
+ModuleType ModulatorImplBase::ModuleTypeFromRequest(
+ const ModuleRequest& module_request) const {
+ String module_type_string = module_request.GetModuleTypeString();
+ if (module_type_string.IsNull()) {
+ // Per https://github.com/whatwg/html/pull/5883, if no type assertion is
+ // provided then the import should be treated as a JavaScript module.
+ return ModuleType::kJavaScript;
+ } else if (base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
+ module_type_string == "json") {
+ // Per https://github.com/whatwg/html/pull/5658, a "json" type assertion
+ // indicates that the import should be treated as a JSON module script.
+ return ModuleType::kJSON;
+ } else if (RuntimeEnabledFeatures::CSSModulesEnabled() &&
+ module_type_string == "css") {
+ // Per https://github.com/whatwg/html/pull/4898, a "css" type assertion
+ // indicates that the import should be treated as a CSS module script.
+ return ModuleType::kCSS;
+ } else {
+ // Per https://github.com/whatwg/html/pull/5883, if an unsupported type
+ // assertion is provided then the import should be treated as an error
+ // similar to an invalid module specifier.
+ return ModuleType::kInvalid;
+ }
+}
+
void ModulatorImplBase::ProduceCacheModuleTreeTopLevel(
ModuleScript* module_script) {
DCHECK(module_script);
@@ -303,11 +334,15 @@ void ModulatorImplBase::ProduceCacheModuleTree(
KURL child_url =
module_script->ResolveModuleSpecifier(module_request.specifier);
+ ModuleType child_module_type = this->ModuleTypeFromRequest(module_request);
+ CHECK_NE(child_module_type, ModuleType::kInvalid);
+
CHECK(child_url.IsValid())
<< "ModuleScript::ResolveModuleSpecifier() impl must "
"return a valid url.";
- ModuleScript* child_module = GetFetchedModuleScript(child_url);
+ ModuleScript* child_module =
+ GetFetchedModuleScript(child_url, child_module_type);
CHECK(child_module);
if (discovered_set->Contains(child_module))
diff --git a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
index ce455c87bbd..3ac03aca42c 100644
--- a/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/chromium/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -44,6 +44,8 @@ class ModulatorImplBase : public Modulator {
bool ImportMapsEnabled() const override;
+ mojom::blink::V8CacheOptions GetV8CacheOptions() const final;
+
ModuleRecordResolver* GetModuleRecordResolver() override {
return module_record_resolver_.Get();
}
@@ -52,6 +54,7 @@ class ModulatorImplBase : public Modulator {
}
void FetchTree(const KURL&,
+ ModuleType,
ResourceFetcher* fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
@@ -69,12 +72,12 @@ class ModulatorImplBase : public Modulator {
ModuleGraphLevel,
ModuleScriptCustomFetchType,
SingleModuleClient*) override;
- ModuleScript* GetFetchedModuleScript(const KURL&) override;
+ ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) override;
bool HasValidContext() override;
KURL ResolveModuleSpecifier(const String& module_request,
const KURL& base_url,
String* failure_reason) final;
- void ResolveDynamically(const String& specifier,
+ void ResolveDynamically(const ModuleRequest& module_request,
const KURL&,
const ReferrerScriptInfo&,
ScriptPromiseResolver*) override;
@@ -83,13 +86,19 @@ class ModulatorImplBase : public Modulator {
ScriptValue CreateTypeError(const String& message) const override;
ScriptValue CreateSyntaxError(const String& message) const override;
void RegisterImportMap(const ImportMap*, ScriptValue error_to_rethrow) final;
- bool IsAcquiringImportMaps() const final { return acquiring_import_maps_; }
- void ClearIsAcquiringImportMaps() final { acquiring_import_maps_ = false; }
+ AcquiringImportMapsState GetAcquiringImportMapsState() const final {
+ return acquiring_import_maps_;
+ }
+ void SetAcquiringImportMapsState(AcquiringImportMapsState value) final {
+ acquiring_import_maps_ = value;
+ }
ModuleImportMeta HostGetImportMetaProperties(
v8::Local<v8::Module>) const override;
ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
v8::Local<v8::Module>) override;
+ ModuleType ModuleTypeFromRequest(
+ const ModuleRequest& module_request) const override;
// Populates |reason| and returns true if the dynamic import is disallowed on
// the associated execution context. In that case, a caller of this function
@@ -111,10 +120,11 @@ class ModulatorImplBase : public Modulator {
Member<const ImportMap> import_map_;
- // https://github.com/WICG/import-maps/blob/master/spec.md#when-import-maps-can-be-encountered
- // Each realm (environment settings object) has a boolean, acquiring import
- // maps. It is initially true. [spec text]
- bool acquiring_import_maps_ = true;
+ // https://wicg.github.io/import-maps/#document-acquiring-import-maps
+ // Each Document has an acquiring import maps boolean. It is initially true.
+ // [spec text]
+ AcquiringImportMapsState acquiring_import_maps_ =
+ AcquiringImportMapsState::kAcquiring;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/module_map.cc b/chromium/third_party/blink/renderer/core/script/module_map.cc
index 1fe0c286d99..55737d7be2d 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_map.cc
@@ -120,7 +120,8 @@ void ModuleMap::FetchSingleModuleScript(
// <spec step="2">If moduleMap[url] is "fetching", wait in parallel until that
// entry's value changes, then queue a task on the networking task source to
// proceed with running the following steps.</spec>
- MapImpl::AddResult result = map_.insert(request.Url(), nullptr);
+ MapImpl::AddResult result = map_.insert(
+ std::make_pair(request.Url(), request.GetExpectedModuleType()), nullptr);
Member<Entry>& entry = result.stored_value->value;
if (result.is_new_entry) {
entry = MakeGarbageCollected<Entry>(this);
@@ -142,8 +143,9 @@ void ModuleMap::FetchSingleModuleScript(
entry->AddClient(client);
}
-ModuleScript* ModuleMap::GetFetchedModuleScript(const KURL& url) const {
- MapImpl::const_iterator it = map_.find(url);
+ModuleScript* ModuleMap::GetFetchedModuleScript(const KURL& url,
+ ModuleType module_type) const {
+ MapImpl::const_iterator it = map_.find(std::make_pair(url, module_type));
if (it == map_.end())
return nullptr;
return it->value->GetModuleScript();
diff --git a/chromium/third_party/blink/renderer/core/script/module_map.h b/chromium/third_party/blink/renderer/core/script/module_map.h
index da36d05005b..9274c7d2dd3 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map.h
+++ b/chromium/third_party/blink/renderer/core/script/module_map.h
@@ -22,6 +22,7 @@ class ResourceFetcher;
class SingleModuleClient;
enum class ModuleGraphLevel;
enum class ModuleScriptCustomFetchType;
+enum class ModuleType;
// A ModuleMap implements "module map" spec.
// https://html.spec.whatwg.org/C/#module-map
@@ -48,12 +49,13 @@ class CORE_EXPORT ModuleMap final : public GarbageCollected<ModuleMap>,
// Synchronously get the ModuleScript for a given URL.
// If the URL wasn't fetched, or is currently being fetched, this returns a
// nullptr.
- ModuleScript* GetFetchedModuleScript(const KURL&) const;
+ ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) const;
Modulator* GetModulator() { return modulator_; }
private:
- using MapImpl = HeapHashMap<KURL, Member<Entry>>;
+ using Key = std::pair<KURL, ModuleType>;
+ using MapImpl = HeapHashMap<Key, Member<Entry>>;
// A module map is a map of absolute URLs to map entry.
MapImpl map_;
diff --git a/chromium/third_party/blink/renderer/core/script/module_map_test.cc b/chromium/third_party/blink/renderer/core/script/module_map_test.cc
index 9431f7560ce..73d231332ed 100644
--- a/chromium/third_party/blink/renderer/core/script/module_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_map_test.cc
@@ -6,6 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
@@ -21,6 +22,7 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
@@ -71,7 +73,7 @@ class TestModuleRecordResolver final : public ModuleRecordResolver {
return nullptr;
}
- v8::Local<v8::Module> Resolve(const String& specifier,
+ v8::Local<v8::Module> Resolve(const ModuleRequest& module_request,
v8::Local<v8::Module> referrer,
ExceptionState&) override {
NOTREACHED();
@@ -108,19 +110,16 @@ class ModuleMapTestModulator final : public DummyModulator {
public ModuleScriptFetcher {
public:
TestModuleScriptFetcher(ModuleMapTestModulator* modulator,
- util::PassKey<ModuleScriptLoader> pass_key)
+ base::PassKey<ModuleScriptLoader> pass_key)
: ModuleScriptFetcher(pass_key), modulator_(modulator) {}
void Fetch(FetchParameters& request,
+ ModuleType module_type,
ResourceFetcher*,
ModuleGraphLevel,
ModuleScriptFetcher::Client* client) override {
- TestRequest* test_request = MakeGarbageCollected<TestRequest>(
- ModuleScriptCreationParams(
- request.Url(),
- ModuleScriptCreationParams::ModuleType::kJavaScriptModule,
- ParkableString(String("").ReleaseImpl()), nullptr,
- request.GetResourceRequest().GetCredentialsMode()),
- client);
+ CHECK_EQ(request.GetScriptType(), mojom::blink::ScriptType::kModule);
+ TestRequest* test_request =
+ MakeGarbageCollected<TestRequest>(request.Url(), client);
modulator_->test_requests_.push_back(test_request);
}
String DebugName() const override { return "TestModuleScriptFetcher"; }
@@ -135,7 +134,7 @@ class ModuleMapTestModulator final : public DummyModulator {
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader> pass_key) override {
+ base::PassKey<ModuleScriptLoader> pass_key) override {
return MakeGarbageCollected<TestModuleScriptFetcher>(this, pass_key);
}
@@ -149,17 +148,18 @@ class ModuleMapTestModulator final : public DummyModulator {
}
struct TestRequest final : public GarbageCollected<TestRequest> {
- TestRequest(const ModuleScriptCreationParams& params,
- ModuleScriptFetcher::Client* client)
- : params_(params), client_(client) {}
+ TestRequest(const KURL& url, ModuleScriptFetcher::Client* client)
+ : url_(url), client_(client) {}
void NotifyFetchFinished() {
- client_->NotifyFetchFinished(*params_,
- HeapVector<Member<ConsoleMessage>>());
+ client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
+ url_, url_, ScriptSourceLocationType::kExternalFile,
+ ModuleType::kJavaScript, ParkableString(String("").ReleaseImpl()),
+ nullptr));
}
void Trace(Visitor* visitor) const { visitor->Trace(client_); }
private:
- base::Optional<ModuleScriptCreationParams> params_;
+ const KURL url_;
Member<ModuleScriptFetcher::Client> client_;
};
HeapVector<Member<TestRequest>> test_requests_;
@@ -225,10 +225,10 @@ TEST_P(ModuleMapTest, sequentialRequests) {
// First request
TestSingleModuleClient* client =
MakeGarbageCollected<TestSingleModuleClient>();
- Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- GetDocument().Fetcher(),
- ModuleGraphLevel::kTopLevelModuleFetch,
- ModuleScriptCustomFetchType::kNone, client);
+ Map()->FetchSingleModuleScript(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ GetDocument().Fetcher(), ModuleGraphLevel::kTopLevelModuleFetch,
+ ModuleScriptCustomFetchType::kNone, client);
Modulator()->ResolveFetches();
EXPECT_FALSE(client->WasNotifyFinished())
<< "fetchSingleModuleScript shouldn't complete synchronously";
@@ -244,10 +244,10 @@ TEST_P(ModuleMapTest, sequentialRequests) {
// Secondary request
TestSingleModuleClient* client2 =
MakeGarbageCollected<TestSingleModuleClient>();
- Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- GetDocument().Fetcher(),
- ModuleGraphLevel::kTopLevelModuleFetch,
- ModuleScriptCustomFetchType::kNone, client2);
+ Map()->FetchSingleModuleScript(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ GetDocument().Fetcher(), ModuleGraphLevel::kTopLevelModuleFetch,
+ ModuleScriptCustomFetchType::kNone, client2);
Modulator()->ResolveFetches();
EXPECT_FALSE(client2->WasNotifyFinished())
<< "fetchSingleModuleScript shouldn't complete synchronously";
@@ -272,18 +272,18 @@ TEST_P(ModuleMapTest, concurrentRequestsShouldJoin) {
// First request
TestSingleModuleClient* client =
MakeGarbageCollected<TestSingleModuleClient>();
- Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- GetDocument().Fetcher(),
- ModuleGraphLevel::kTopLevelModuleFetch,
- ModuleScriptCustomFetchType::kNone, client);
+ Map()->FetchSingleModuleScript(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ GetDocument().Fetcher(), ModuleGraphLevel::kTopLevelModuleFetch,
+ ModuleScriptCustomFetchType::kNone, client);
// Secondary request (which should join the first request)
TestSingleModuleClient* client2 =
MakeGarbageCollected<TestSingleModuleClient>();
- Map()->FetchSingleModuleScript(ModuleScriptFetchRequest::CreateForTest(url),
- GetDocument().Fetcher(),
- ModuleGraphLevel::kTopLevelModuleFetch,
- ModuleScriptCustomFetchType::kNone, client2);
+ Map()->FetchSingleModuleScript(
+ ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript),
+ GetDocument().Fetcher(), ModuleGraphLevel::kTopLevelModuleFetch,
+ ModuleScriptCustomFetchType::kNone, client2);
Modulator()->ResolveFetches();
EXPECT_FALSE(client->WasNotifyFinished())
diff --git a/chromium/third_party/blink/renderer/core/script/module_record_resolver.h b/chromium/third_party/blink/renderer/core/script/module_record_resolver.h
index d9f7219d25d..6152e637859 100644
--- a/chromium/third_party/blink/renderer/core/script/module_record_resolver.h
+++ b/chromium/third_party/blink/renderer/core/script/module_record_resolver.h
@@ -42,7 +42,7 @@ class CORE_EXPORT ModuleRecordResolver
// Implements "Runtime Semantics: HostResolveImportedModule"
// https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule
// This returns a null ModuleRecord when an exception is thrown.
- virtual v8::Local<v8::Module> Resolve(const String& specifier,
+ virtual v8::Local<v8::Module> Resolve(const ModuleRequest& module_request,
v8::Local<v8::Module> referrer,
ExceptionState&) = 0;
};
diff --git a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.cc b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
index 8b234d805af..a615608ab39 100644
--- a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/script/module_record_resolver_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_script.h"
@@ -59,12 +60,12 @@ const ModuleScript* ModuleRecordResolverImpl::GetModuleScriptFromModuleRecord(
// <specdef
// href="https://html.spec.whatwg.org/C/#hostresolveimportedmodule(referencingscriptormodule,-specifier)">
v8::Local<v8::Module> ModuleRecordResolverImpl::Resolve(
- const String& specifier,
+ const ModuleRequest& module_request,
v8::Local<v8::Module> referrer,
ExceptionState& exception_state) {
v8::Isolate* isolate = modulator_->GetScriptState()->GetIsolate();
- DVLOG(1) << "ModuleRecordResolverImpl::resolve(specifier=\"" << specifier
- << ", referrer.hash="
+ DVLOG(1) << "ModuleRecordResolverImpl::resolve(specifier=\""
+ << module_request.specifier << ", referrer.hash="
<< BoxedV8ModuleHash::GetHash(
MakeGarbageCollected<BoxedV8Module>(isolate, referrer))
<< ")";
@@ -91,16 +92,20 @@ v8::Local<v8::Module> ModuleRecordResolverImpl::Resolve(
// <spec step="3.3">Set base URL to referencing script's base URL.</spec>
// <spec step="5">Let url be the result of resolving a module specifier given
// base URL and specifier.</spec>
- KURL url = referrer_module->ResolveModuleSpecifier(specifier);
+ KURL url = referrer_module->ResolveModuleSpecifier(module_request.specifier);
+ ModuleType child_module_type =
+ modulator_->ModuleTypeFromRequest(module_request);
// <spec step="6">Assert: url is never failure, because resolving a module
// specifier must have been previously successful with these same two
// arguments ...</spec>
DCHECK(url.IsValid());
+ CHECK_NE(child_module_type, ModuleType::kInvalid);
// <spec step="7">Let resolved module script be moduleMap[url]. (This entry
// must exist for us to have gotten to this point.)</spec>
- ModuleScript* module_script = modulator_->GetFetchedModuleScript(url);
+ ModuleScript* module_script =
+ modulator_->GetFetchedModuleScript(url, child_module_type);
// <spec step="8">Assert: resolved module script is a module script (i.e., is
// not null or "fetching").</spec>
diff --git a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.h b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.h
index 90cbd5de65e..896c88d85c7 100644
--- a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl.h
@@ -44,7 +44,7 @@ class CORE_EXPORT ModuleRecordResolverImpl final
// Implements "Runtime Semantics: HostResolveImportedModule" per HTML spec.
// https://html.spec.whatwg.org/C/#hostresolveimportedmodule(referencingscriptormodule,-specifier))
- v8::Local<v8::Module> Resolve(const String& specifier,
+ v8::Local<v8::Module> Resolve(const ModuleRequest& module_request,
v8::Local<v8::Module> referrer,
ExceptionState&) final;
diff --git a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
index 8ab80071c83..000a915a8eb 100644
--- a/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
@@ -51,7 +51,8 @@ class ModuleRecordResolverImplTestModulator final : public DummyModulator {
return KURL(base_url, module_request);
}
- ModuleScript* GetFetchedModuleScript(const KURL&) override;
+ ModuleScript* GetFetchedModuleScript(const KURL&,
+ ModuleType module_type) override;
Member<ScriptState> script_state_;
int get_fetched_module_script_called_ = 0;
@@ -66,7 +67,8 @@ void ModuleRecordResolverImplTestModulator::Trace(Visitor* visitor) const {
}
ModuleScript* ModuleRecordResolverImplTestModulator::GetFetchedModuleScript(
- const KURL& url) {
+ const KURL& url,
+ ModuleType module_type) {
get_fetched_module_script_called_++;
fetched_url_ = url;
return module_script_.Get();
@@ -75,10 +77,8 @@ ModuleScript* ModuleRecordResolverImplTestModulator::GetFetchedModuleScript(
ModuleScript* CreateReferrerModuleScript(Modulator* modulator,
V8TestingScope& scope) {
KURL js_url("https://example.com/referrer.js");
- v8::Local<v8::Module> referrer_record = ModuleRecord::Compile(
- scope.GetIsolate(), "import './target.js'; export const a = 42;", js_url,
- js_url, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> referrer_record = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "import './target.js'; export const a = 42;", js_url);
KURL referrer_url("https://example.com/referrer.js");
auto* referrer_module_script =
JSModuleScript::CreateForTest(modulator, referrer_record, referrer_url);
@@ -89,10 +89,8 @@ ModuleScript* CreateTargetModuleScript(Modulator* modulator,
V8TestingScope& scope,
bool has_parse_error = false) {
KURL js_url("https://example.com/target.js");
- v8::Local<v8::Module> record = ModuleRecord::Compile(
- scope.GetIsolate(), "export const pi = 3.14;", js_url, js_url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> record = ModuleTestBase::CompileModule(
+ scope.GetIsolate(), "export const pi = 3.14;", js_url);
KURL url("https://example.com/target.js");
auto* module_script = JSModuleScript::CreateForTest(modulator, record, url);
if (has_parse_error) {
@@ -147,9 +145,9 @@ TEST_P(ModuleRecordResolverImplTest, RegisterResolveSuccess) {
CreateTargetModuleScript(modulator_, scope);
Modulator()->SetModuleScript(target_module_script);
- v8::Local<v8::Module> resolved =
- resolver->Resolve("./target.js", referrer_module_script->V8Module(),
- scope.GetExceptionState());
+ v8::Local<v8::Module> resolved = resolver->Resolve(
+ ModuleRequest("./target.js", TextPosition(), Vector<ImportAssertion>()),
+ referrer_module_script->V8Module(), scope.GetExceptionState());
EXPECT_FALSE(scope.GetExceptionState().HadException());
EXPECT_EQ(resolved, target_module_script->V8Module());
EXPECT_EQ(1, modulator_->GetFetchedModuleScriptCalled());
diff --git a/chromium/third_party/blink/renderer/core/script/module_script.cc b/chromium/third_party/blink/renderer/core/script/module_script.cc
index e4dbe762a58..53848c41eef 100644
--- a/chromium/third_party/blink/renderer/core/script/module_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_script.cc
@@ -4,8 +4,11 @@
#include "third_party/blink/renderer/core/script/module_script.h"
+#include "base/feature_list.h"
#include "base/macros.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.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"
@@ -106,7 +109,7 @@ void ModuleScript::Trace(Visitor* visitor) const {
void ModuleScript::RunScript(LocalDOMWindow*) {
// We need a HandleScope for the `ScriptEvaluationResult` returned from
// `RunScriptAndReturnValue`.
- ScriptState::Scope scope(SettingsObject()->GetScriptState());
+ v8::HandleScope scope(SettingsObject()->GetScriptState()->GetIsolate());
DVLOG(1) << *this << "::RunScript()";
ignore_result(RunScriptAndReturnValue());
}
@@ -115,12 +118,27 @@ bool ModuleScript::RunScriptOnWorkerOrWorklet(
WorkerOrWorkletGlobalScope& global_scope) {
// We need a HandleScope for the `ScriptEvaluationResult` returned from
// `RunScriptAndReturnValue`.
- ScriptState::Scope scope(SettingsObject()->GetScriptState());
+ v8::HandleScope scope(SettingsObject()->GetScriptState()->GetIsolate());
DCHECK(global_scope.IsContextThread());
// TODO(nhiroki): Catch an error when an evaluation error happens.
// (https://crbug.com/680046)
ScriptEvaluationResult result = RunScriptAndReturnValue();
+
+ // Service workers prohibit async module graphs (those with top-level await),
+ // so the promise result from executing a service worker module is always
+ // settled. To maintain compatibility with synchronous module graphs, rejected
+ // promises are considered synchronous failures in service workers.
+ //
+ // https://github.com/w3c/ServiceWorker/pull/1444
+ if (base::FeatureList::IsEnabled(features::kTopLevelAwait) &&
+ global_scope.IsServiceWorkerGlobalScope() &&
+ result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess) {
+ v8::Local<v8::Promise> promise = result.GetSuccessValue().As<v8::Promise>();
+ DCHECK_NE(promise->State(), v8::Promise::kPending);
+ return promise->State() == v8::Promise::kFulfilled;
+ }
+
return result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess;
}
diff --git a/chromium/third_party/blink/renderer/core/script/module_script_test.cc b/chromium/third_party/blink/renderer/core/script/module_script_test.cc
index 09f6f342c97..69ac13344dc 100644
--- a/chromium/third_party/blink/renderer/core/script/module_script_test.cc
+++ b/chromium/third_party/blink/renderer/core/script/module_script_test.cc
@@ -11,6 +11,7 @@
#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_binding_for_testing.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/script/classic_script.h"
#include "third_party/blink/renderer/core/script/js_module_script.h"
#include "third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h"
@@ -80,11 +81,12 @@ class ModuleScriptTest : public ::testing::Test, public ParametrizedModuleTest {
Modulator* modulator,
const String& source_text,
SingleCachedMetadataHandler* cache_handler) {
- return JSModuleScript::Create(
- ParkableString(source_text.IsolatedCopy().ReleaseImpl()), cache_handler,
- ScriptSourceLocationType::kExternalFile, modulator,
+ ModuleScriptCreationParams params(
KURL("https://fox.url/script.js"), KURL("https://fox.url/"),
- ScriptFetchOptions());
+ ScriptSourceLocationType::kInline, ModuleType::kJavaScript,
+ ParkableString(source_text.IsolatedCopy().ReleaseImpl()),
+ cache_handler);
+ return JSModuleScript::Create(params, modulator, ScriptFetchOptions());
}
static ValueWrapperSyntheticModuleScript*
diff --git a/chromium/third_party/blink/renderer/core/script/script_loader.cc b/chromium/third_party/blink/renderer/core/script/script_loader.cc
index 63ca0952d47..49c44dd349d 100644
--- a/chromium/third_party/blink/renderer/core/script/script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/script/script_loader.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/script/script_loader.h"
#include "base/feature_list.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
@@ -44,6 +45,7 @@
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
#include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
#include "third_party/blink/renderer/core/script/classic_pending_script.h"
@@ -188,53 +190,56 @@ enum class ShouldFireErrorEvent {
kShouldFire,
};
+bool IsImportMapEnabled(LocalDOMWindow* context_window) {
+ // When window/modulator is null, `true` is returned here, because
+ // PrepareScript() should fail at "scripting is disabled" checks, not here.
+
+ if (!context_window)
+ return true;
+
+ Modulator* modulator =
+ Modulator::From(ToScriptStateForMainWorld(context_window->GetFrame()));
+ if (!modulator)
+ return true;
+
+ return modulator->ImportMapsEnabled();
+}
+
} // namespace
// <specdef href="https://html.spec.whatwg.org/C/#prepare-a-script">
-bool ScriptLoader::IsValidScriptTypeAndLanguage(
+ScriptLoader::ScriptTypeAtPrepare ScriptLoader::GetScriptTypeAtPrepare(
const String& type,
const String& language,
- LegacyTypeSupport support_legacy_types,
- mojom::blink::ScriptType* out_script_type,
- bool* out_is_import_map) {
+ LegacyTypeSupport support_legacy_types) {
if (IsValidClassicScriptTypeAndLanguage(type, language,
support_legacy_types)) {
// <spec step="7">... If the script block's type string is a JavaScript MIME
// type essence match, the script's type is "classic". ...</spec>
//
// TODO(hiroshige): Annotate and/or cleanup this step.
- if (out_script_type)
- *out_script_type = mojom::blink::ScriptType::kClassic;
- if (out_is_import_map)
- *out_is_import_map = false;
- return true;
+ return ScriptTypeAtPrepare::kClassic;
}
- if (type == "module") {
+ if (EqualIgnoringASCIICase(type, "module")) {
// <spec step="7">... If the script block's type string is an ASCII
// case-insensitive match for the string "module", the script's type is
// "module". ...</spec>
- if (out_script_type)
- *out_script_type = mojom::blink::ScriptType::kModule;
- if (out_is_import_map)
- *out_is_import_map = false;
- return true;
+ return ScriptTypeAtPrepare::kModule;
}
- if (type == "importmap") {
- if (out_is_import_map)
- *out_is_import_map = true;
- return true;
+ if (EqualIgnoringASCIICase(type, "importmap")) {
+ return ScriptTypeAtPrepare::kImportMap;
}
// <spec step="7">... If neither of the above conditions are true, then
// return. No script is executed.</spec>
- return false;
+ return ScriptTypeAtPrepare::kInvalid;
}
-bool ScriptLoader::BlockForNoModule(mojom::blink::ScriptType script_type,
+bool ScriptLoader::BlockForNoModule(ScriptTypeAtPrepare script_type,
bool nomodule) {
- return nomodule && script_type == mojom::blink::ScriptType::kClassic;
+ return nomodule && script_type == ScriptTypeAtPrepare::kClassic;
}
// Corresponds to
@@ -261,15 +266,17 @@ network::mojom::CredentialsMode ScriptLoader::ModuleScriptCredentialsMode(
// https://github.com/w3c/webappsec-permissions-policy/issues/135
bool ShouldBlockSyncScriptForDocumentPolicy(
const ScriptElementBase* element,
- mojom::blink::ScriptType script_type,
+ ScriptLoader::ScriptTypeAtPrepare script_type,
bool parser_inserted) {
if (element->GetExecutionContext()->IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature::kSyncScript)) {
return false;
}
- // Module scripts never block parsing.
- if (script_type == mojom::blink::ScriptType::kModule || !parser_inserted)
+ // Module scripts and import maps never block parsing.
+ if (script_type == ScriptLoader::ScriptTypeAtPrepare::kModule ||
+ script_type == ScriptLoader::ScriptTypeAtPrepare::kImportMap ||
+ !parser_inserted)
return false;
if (!element->HasSourceAttribute())
@@ -323,15 +330,26 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
if (!element_->IsConnected())
return false;
- bool is_import_map = false;
+ Document& element_document = element_->GetDocument();
+ LocalDOMWindow* context_window = element_document.ExecutingWindow();
// <spec step="7">... Determine the script's type as follows: ...</spec>
- //
- // |script_type_| is set here.
- if (!IsValidScriptTypeAndLanguage(
- element_->TypeAttributeValue(), element_->LanguageAttributeValue(),
- support_legacy_types, &script_type_, &is_import_map)) {
- return false;
+ script_type_ = GetScriptTypeAtPrepare(element_->TypeAttributeValue(),
+ element_->LanguageAttributeValue(),
+ support_legacy_types);
+
+ switch (GetScriptType()) {
+ case ScriptTypeAtPrepare::kInvalid:
+ return false;
+
+ case ScriptTypeAtPrepare::kImportMap:
+ if (!IsImportMapEnabled(context_window))
+ return false;
+ break;
+
+ case ScriptTypeAtPrepare::kClassic:
+ case ScriptTypeAtPrepare::kModule:
+ break;
}
// <spec step="8">If was-parser-inserted is true, then flag the element as
@@ -358,29 +376,15 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// <spec href="https://html.spec.whatwg.org/C/#concept-n-noscript">Scripting
// is disabled for a node if there is no such browsing context, or if
// scripting is disabled in that browsing context.</spec>
- Document& element_document = element_->GetDocument();
- LocalDOMWindow* context_window = element_document.ExecutingWindow();
if (!context_window)
return false;
if (!context_window->CanExecuteScripts(kAboutToExecuteScript))
return false;
- // Accept import maps only if ImportMapsEnabled().
- if (is_import_map) {
- Modulator* modulator =
- Modulator::From(ToScriptStateForMainWorld(context_window->GetFrame()));
- if (!modulator->ImportMapsEnabled()) {
- // Import maps should have been rejected in spec Step 7 above.
- // TODO(hiroshige): Returning here (i.e. after spec Step 11) is not spec
- // conformant. Fix this.
- return false;
- }
- }
-
// <spec step="12">If the script element has a nomodule content attribute and
// the script's type is "classic", then return. The script is not
// executed.</spec>
- if (BlockForNoModule(script_type_, element_->NomoduleAttributeValue()))
+ if (BlockForNoModule(GetScriptType(), element_->NomoduleAttributeValue()))
return false;
// TODO(csharrison): This logic only works if the tokenizer/parser was not
@@ -478,18 +482,22 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
ParserDisposition parser_state =
IsParserInserted() ? kParserInserted : kNotParserInserted;
- if (GetScriptType() == mojom::blink::ScriptType::kModule)
+ if (GetScriptType() == ScriptLoader::ScriptTypeAtPrepare::kModule)
UseCounter::Count(*context_window, WebFeature::kPrepareModuleScript);
DCHECK(!prepared_pending_script_);
+ RenderBlockingBehavior render_blocking_behavior =
+ non_blocking_ ? RenderBlockingBehavior::kNonBlocking
+ : RenderBlockingBehavior::kBlocking;
+
// <spec step="22">Let options be a script fetch options whose cryptographic
// nonce is cryptographic nonce, integrity metadata is integrity metadata,
// parser metadata is parser metadata, credentials mode is module script
// credentials mode, and referrer policy is referrer policy.</spec>
ScriptFetchOptions options(nonce, integrity_metadata, integrity_attr,
parser_state, credentials_mode, referrer_policy,
- importance);
+ importance, render_blocking_behavior);
// <spec step="23">Let settings object be the element's node document's
// relevant settings object.</spec>
@@ -501,22 +509,44 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
auto* fetch_client_settings_object_fetcher = context_window->Fetcher();
// https://wicg.github.io/import-maps/#integration-prepare-a-script
- // If the script’s type is "importmap" and the element’s node document’s
- // acquiring import maps is false, then queue a task to fire an event named
- // error at the element, and return. [spec text]
- if (is_import_map) {
+ // If the script’s type is "importmap": [spec text]
+ if (GetScriptType() == ScriptTypeAtPrepare::kImportMap) {
Modulator* modulator =
Modulator::From(ToScriptStateForMainWorld(context_window->GetFrame()));
- if (!modulator->IsAcquiringImportMaps()) {
- element_document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kError,
- "An import map is added after module script load was triggered."));
- element_document.GetTaskRunner(TaskType::kDOMManipulation)
- ->PostTask(FROM_HERE,
- WTF::Bind(&ScriptElementBase::DispatchErrorEvent,
- WrapPersistent(element_.Get())));
- return false;
+ auto aquiring_state = modulator->GetAcquiringImportMapsState();
+ switch (aquiring_state) {
+ case Modulator::AcquiringImportMapsState::kAfterModuleScriptLoad:
+ case Modulator::AcquiringImportMapsState::kMultipleImportMaps:
+ // 1. If the element’s node document's acquiring import maps is false,
+ // then queue a task to fire an event named error at the element, and
+ // return. [spec text]
+ element_document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kError,
+ aquiring_state ==
+ Modulator::AcquiringImportMapsState::kAfterModuleScriptLoad
+ ? "An import map is added after module script load was "
+ "triggered."
+ : "Multiple import maps are not yet supported. "
+ "https://crbug.com/927119"));
+ element_document.GetTaskRunner(TaskType::kDOMManipulation)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&ScriptElementBase::DispatchErrorEvent,
+ WrapPersistent(element_.Get())));
+ return false;
+
+ case Modulator::AcquiringImportMapsState::kAcquiring:
+ // 2. Set the element’s node document's acquiring import maps to false.
+ // [spec text]
+ modulator->SetAcquiringImportMapsState(
+ Modulator::AcquiringImportMapsState::kMultipleImportMaps);
+
+ // 3. Assert: the element’s node document's pending import map script is
+ // null. [spec text]
+ //
+ // TODO(crbug.com/922212): Currently there are no implementation for
+ // "pending import map script" as we don't support external import maps.
+ break;
}
}
@@ -556,70 +586,80 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
}
// <spec step="24.6">Switch on the script's type:</spec>
- if (is_import_map) {
- // TODO(crbug.com/922212): Implement external import maps.
- element_document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kError,
- "External import maps are not yet supported."));
- element_document.GetTaskRunner(TaskType::kDOMManipulation)
- ->PostTask(FROM_HERE,
- WTF::Bind(&ScriptElementBase::DispatchErrorEvent,
- WrapPersistent(element_.Get())));
- return false;
- }
-
- if (GetScriptType() == mojom::blink::ScriptType::kClassic) {
- // - "classic":
-
- // <spec step="15">If the script element has a charset attribute, then let
- // encoding be the result of getting an encoding from the value of the
- // charset attribute. If the script element does not have a charset
- // attribute, or if getting an encoding failed, let encoding be the same
- // as the encoding of the script element's node document.</spec>
- //
- // TODO(hiroshige): Should we handle failure in getting an encoding?
- WTF::TextEncoding encoding;
- if (!element_->CharsetAttributeValue().IsEmpty())
- encoding = WTF::TextEncoding(element_->CharsetAttributeValue());
- else
- encoding = element_document.Encoding();
-
- // <spec step="24.6.A">"classic"
- //
- // Fetch a classic script given url, settings object, options, classic
- // script CORS setting, and encoding.</spec>
- Document* document_for_origin = &element_document;
- if (element_document.ImportsController()) {
- document_for_origin = context_window->document();
+ switch (GetScriptType()) {
+ case ScriptTypeAtPrepare::kInvalid:
+ NOTREACHED();
+ return false;
+
+ case ScriptTypeAtPrepare::kImportMap:
+ // TODO(crbug.com/922212): Implement external import maps.
+ element_document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kError,
+ "External import maps are not yet supported."));
+ element_document.GetTaskRunner(TaskType::kDOMManipulation)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&ScriptElementBase::DispatchErrorEvent,
+ WrapPersistent(element_.Get())));
+ return false;
+
+ case ScriptTypeAtPrepare::kClassic: {
+ // - "classic":
+
+ // <spec step="15">If the script element has a charset attribute, then
+ // let encoding be the result of getting an encoding from the value of
+ // the charset attribute. If the script element does not have a charset
+ // attribute, or if getting an encoding failed, let encoding be the same
+ // as the encoding of the script element's node document.</spec>
+ //
+ // TODO(hiroshige): Should we handle failure in getting an encoding?
+ WTF::TextEncoding encoding;
+ if (!element_->CharsetAttributeValue().IsEmpty())
+ encoding = WTF::TextEncoding(element_->CharsetAttributeValue());
+ else
+ encoding = element_document.Encoding();
+
+ // <spec step="24.6.A">"classic"
+ //
+ // Fetch a classic script given url, settings object, options, classic
+ // script CORS setting, and encoding.</spec>
+ Document* document_for_origin = &element_document;
+ if (element_document.ImportsController()) {
+ document_for_origin = context_window->document();
+ }
+ FetchClassicScript(url, *document_for_origin, options, cross_origin,
+ encoding);
+ break;
}
- FetchClassicScript(url, *document_for_origin, options, cross_origin,
- encoding);
- } else {
- // - "module":
+ case ScriptTypeAtPrepare::kModule: {
+ // - "module":
- // Step 15 is skipped because they are not used in module
- // scripts.
+ // Step 15 is skipped because they are not used in module
+ // scripts.
- // <spec step="24.6.B">"module"
+ // <spec step="24.6.B">"module"
+ //
+ // Fetch an external module script graph given url, settings object, and
+ // options.</spec>
+ Modulator* modulator = Modulator::From(
+ ToScriptStateForMainWorld(context_window->GetFrame()));
+ FetchModuleScriptTree(url, fetch_client_settings_object_fetcher,
+ modulator, options);
+ }
+ // <spec step="24.6">When the chosen algorithm asynchronously completes,
+ // set the script's script to the result. At that time, the script is
+ // ready.
+ // ...</spec>
//
- // Fetch an external module script graph given url, settings object, and
- // options.</spec>
- Modulator* modulator = Modulator::From(
- ToScriptStateForMainWorld(context_window->GetFrame()));
- FetchModuleScriptTree(url, fetch_client_settings_object_fetcher,
- modulator, options);
+ // When the script is ready,
+ // PendingScriptClient::pendingScriptFinished() is used as the
+ // notification, and the action to take when the script is ready is
+ // specified later, in
+ // - ScriptLoader::PrepareScript(), or
+ // - HTMLParserScriptRunner,
+ // depending on the conditions in Step 25 of "prepare a script".
+ break;
}
- // <spec step="24.6">When the chosen algorithm asynchronously completes, set
- // the script's script to the result. At that time, the script is ready.
- // ...</spec>
- //
- // When the script is ready, PendingScriptClient::pendingScriptFinished()
- // is used as the notification, and the action to take when
- // the script is ready is specified later, in
- // - ScriptLoader::PrepareScript(), or
- // - HTMLParserScriptRunner,
- // depending on the conditions in Step 25 of "prepare a script".
}
// <spec step="25">If the element does not have a src content attribute, run
@@ -643,27 +683,31 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// <spec step="25.2">Switch on the script's type:</spec>
- if (is_import_map) {
- UseCounter::Count(*context_window, WebFeature::kImportMap);
-
- // https://wicg.github.io/import-maps/#integration-prepare-a-script
- // 1. Let import map parse result be the result of create an import map
- // parse result, given source text, base URL and settings object. [spec
- // text]
- PendingImportMap* pending_import_map =
- PendingImportMap::CreateInline(*element_, source_text, base_url);
-
- // Because we currently support inline import maps only, the pending
- // import map is ready immediately and thus we call `register an import
- // map` synchronously here.
- pending_import_map->RegisterImportMap();
-
- return false;
- }
-
switch (GetScriptType()) {
+ case ScriptTypeAtPrepare::kInvalid:
+ NOTREACHED();
+ return false;
+
+ case ScriptTypeAtPrepare::kImportMap: {
+ UseCounter::Count(*context_window, WebFeature::kImportMap);
+
+ // https://wicg.github.io/import-maps/#integration-prepare-a-script
+ // 1. Let import map parse result be the result of create an import map
+ // parse result, given source text, base URL and settings object. [spec
+ // text]
+ PendingImportMap* pending_import_map =
+ PendingImportMap::CreateInline(*element_, source_text, base_url);
+
+ // Because we currently support inline import maps only, the pending
+ // import map is ready immediately and thus we call `register an import
+ // map` synchronously here.
+ pending_import_map->RegisterImportMap();
+
+ return false;
+ }
+
// <spec step="25.2.A">"classic"</spec>
- case mojom::blink::ScriptType::kClassic: {
+ case ScriptTypeAtPrepare::kClassic: {
// <spec step="25.2.A.1">Let script be the result of creating a classic
// script using source text, settings object, base URL, and
// options.</spec>
@@ -691,7 +735,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
}
// <spec step="25.2.B">"module"</spec>
- case mojom::blink::ScriptType::kModule: {
+ case ScriptTypeAtPrepare::kModule: {
// <spec step="25.2.B.1">Fetch an inline module script graph, given
// source text, base URL, settings object, and options. When this
// asynchronously completes, set the script's script to the result. At
@@ -706,10 +750,13 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// <spec label="fetch-an-inline-module-script-graph" step="1">Let script
// be the result of creating a JavaScript module script using source
// text, settings object, base URL, and options.</spec>
+
+ ModuleScriptCreationParams params(
+ source_url, base_url, ScriptSourceLocationType::kInline,
+ ModuleType::kJavaScript, ParkableString(source_text.Impl()),
+ nullptr);
ModuleScript* module_script =
- JSModuleScript::Create(ParkableString(source_text.Impl()), nullptr,
- ScriptSourceLocationType::kInline, modulator,
- source_url, base_url, options, position);
+ JSModuleScript::Create(params, modulator, options, position);
// <spec label="fetch-an-inline-module-script-graph" step="2">If script
// is null, asynchronously complete this algorithm with null, and abort
@@ -735,6 +782,8 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
}
}
+ DCHECK_NE(GetScriptType(), ScriptLoader::ScriptTypeAtPrepare::kImportMap);
+
DCHECK(prepared_pending_script_);
// <spec step="26">Then, follow the first of the following options that
@@ -755,11 +804,11 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// If the script's type is "module", and the element has been flagged as
// "parser-inserted", and the element does not have an async attribute
// ...</spec>
- if ((GetScriptType() == mojom::blink::ScriptType::kClassic &&
+ if ((GetScriptType() == ScriptTypeAtPrepare::kClassic &&
element_->HasSourceAttribute() && element_->DeferAttributeValue() &&
parser_inserted_ && !element_->AsyncAttributeValue()) ||
- (GetScriptType() == mojom::blink::ScriptType::kModule &&
- parser_inserted_ && !element_->AsyncAttributeValue())) {
+ (GetScriptType() == ScriptTypeAtPrepare::kModule && parser_inserted_ &&
+ !element_->AsyncAttributeValue())) {
// This clause is implemented by the caller-side of prepareScript():
// - HTMLParserScriptRunner::requestDeferredScript(), and
// - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs()
@@ -770,7 +819,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
}
// Check for external script that should be force deferred.
- if (GetScriptType() == mojom::blink::ScriptType::kClassic &&
+ if (GetScriptType() == ScriptTypeAtPrepare::kClassic &&
element_->HasSourceAttribute() &&
context_window->GetFrame()->ShouldForceDeferScript() &&
IsA<HTMLDocument>(context_window->document()) && parser_inserted_ &&
@@ -791,7 +840,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// <spec step="26.B">If the script's type is "classic", and the element has a
// src attribute, and the element has been flagged as "parser-inserted", and
// the element does not have an async attribute ...</spec>
- if (GetScriptType() == mojom::blink::ScriptType::kClassic &&
+ if (GetScriptType() == ScriptTypeAtPrepare::kClassic &&
element_->HasSourceAttribute() && parser_inserted_ &&
!element_->AsyncAttributeValue()) {
// This clause is implemented by the caller-side of prepareScript():
@@ -809,10 +858,10 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// If the script's type is "module", and the element does not have an async
// attribute, and the element does not have the "non-blocking" flag set
// ...</spec>
- if ((GetScriptType() == mojom::blink::ScriptType::kClassic &&
+ if ((GetScriptType() == ScriptTypeAtPrepare::kClassic &&
element_->HasSourceAttribute() && !element_->AsyncAttributeValue() &&
!non_blocking_) ||
- (GetScriptType() == mojom::blink::ScriptType::kModule &&
+ (GetScriptType() == ScriptTypeAtPrepare::kModule &&
!element_->AsyncAttributeValue() && !non_blocking_)) {
// <spec step="26.C">... Add the element to the end of the list of scripts
// that will execute in order as soon as possible associated with the node
@@ -836,9 +885,9 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// src attribute
//
// If the script's type is "module" ...</spec>
- if ((GetScriptType() == mojom::blink::ScriptType::kClassic &&
+ if ((GetScriptType() == ScriptTypeAtPrepare::kClassic &&
element_->HasSourceAttribute()) ||
- GetScriptType() == mojom::blink::ScriptType::kModule) {
+ GetScriptType() == ScriptTypeAtPrepare::kModule) {
// <spec step="26.D">... The element must be added to the set of scripts
// that will execute as soon as possible of the node document of the script
// element at the time the prepare a script algorithm started. When the
@@ -862,7 +911,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// The following clauses are executed only if the script's type is "classic"
// and the element doesn't have a src attribute.
- DCHECK_EQ(GetScriptType(), mojom::blink::ScriptType::kClassic);
+ DCHECK_EQ(GetScriptType(), ScriptTypeAtPrepare::kClassic);
DCHECK(!is_external_script_);
// Check for inline script that should be force deferred.
@@ -924,9 +973,9 @@ void ScriptLoader::FetchClassicScript(const KURL& url,
const WTF::TextEncoding& encoding) {
FetchParameters::DeferOption defer = FetchParameters::kNoDefer;
if (!parser_inserted_ || element_->AsyncAttributeValue() ||
- element_->DeferAttributeValue())
+ element_->DeferAttributeValue()) {
defer = FetchParameters::kLazyLoad;
-
+ }
ClassicPendingScript* pending_script = ClassicPendingScript::Fetch(
url, document, options, cross_origin, encoding, element_, defer);
prepared_pending_script_ = pending_script;
@@ -945,7 +994,8 @@ void ScriptLoader::FetchModuleScriptTree(
// options.</spec>
auto* module_tree_client =
MakeGarbageCollected<ModulePendingScriptTreeClient>();
- modulator->FetchTree(url, fetch_client_settings_object_fetcher,
+ modulator->FetchTree(url, ModuleType::kJavaScript,
+ fetch_client_settings_object_fetcher,
mojom::blink::RequestContextType::SCRIPT,
network::mojom::RequestDestination::kScript, options,
ModuleScriptCustomFetchType::kNone, module_tree_client);
@@ -957,7 +1007,6 @@ PendingScript* ScriptLoader::TakePendingScript(
ScriptSchedulingType scheduling_type) {
CHECK(prepared_pending_script_);
- UMA_HISTOGRAM_ENUMERATION("Blink.Script.SchedulingType", scheduling_type);
PendingScript* pending_script = prepared_pending_script_;
prepared_pending_script_ = nullptr;
pending_script->SetSchedulingType(scheduling_type);
@@ -967,7 +1016,6 @@ PendingScript* ScriptLoader::TakePendingScript(
void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) {
DCHECK(!will_be_parser_executed_);
DCHECK_EQ(pending_script_, pending_script);
- DCHECK_EQ(pending_script_->GetScriptType(), GetScriptType());
DCHECK(pending_script->IsControlledByScriptRunner());
DCHECK(pending_script_->GetSchedulingType() == ScriptSchedulingType::kAsync ||
pending_script_->GetSchedulingType() ==
@@ -1012,7 +1060,7 @@ bool ScriptLoader::IsScriptForEventSupported() const {
// <spec step="14">If the script element has an event attribute and a for
// attribute, and the script's type is "classic", then:</spec>
- if (GetScriptType() != mojom::blink::ScriptType::kClassic ||
+ if (GetScriptType() != ScriptTypeAtPrepare::kClassic ||
event_attribute.IsNull() || for_attribute.IsNull())
return true;
diff --git a/chromium/third_party/blink/renderer/core/script/script_loader.h b/chromium/third_party/blink/renderer/core/script/script_loader.h
index 9a2d1c56c31..1453d40c0f7 100644
--- a/chromium/third_party/blink/renderer/core/script/script_loader.h
+++ b/chromium/third_party/blink/renderer/core/script/script_loader.h
@@ -61,19 +61,17 @@ class CORE_EXPORT ScriptLoader final : public GarbageCollected<ScriptLoader>,
kAllowLegacyTypeInTypeAttribute
};
- // |out_is_import_map| is set separately from |out_script_type| in order
- // to avoid adding import maps as a mojom::blink::ScriptType enum, because
- // import maps are processed quite differently from classic/module scripts.
- //
- // TODO(hiroshige, kouhei): Make the method signature simpler.
- static bool IsValidScriptTypeAndLanguage(
+ // Script type at the time of #prepare-a-script. Import maps are included here
+ // but not in `mojom::blink::ScriptType` because import maps are handled
+ // differently from ordinal scripts after PrepareScript().
+ enum class ScriptTypeAtPrepare { kClassic, kModule, kImportMap, kInvalid };
+
+ static ScriptTypeAtPrepare GetScriptTypeAtPrepare(
const String& type_attribute_value,
const String& language_attribute_value,
- LegacyTypeSupport support_legacy_types,
- mojom::blink::ScriptType* out_script_type = nullptr,
- bool* out_is_import_map = nullptr);
+ LegacyTypeSupport support_legacy_types);
- static bool BlockForNoModule(mojom::blink::ScriptType, bool nomodule);
+ static bool BlockForNoModule(ScriptTypeAtPrepare, bool nomodule);
static network::mojom::CredentialsMode ModuleScriptCredentialsMode(
CrossOriginAttributeValue);
@@ -97,7 +95,7 @@ class CORE_EXPORT ScriptLoader final : public GarbageCollected<ScriptLoader>,
bool IsParserInserted() const { return parser_inserted_; }
bool AlreadyStarted() const { return already_started_; }
bool IsNonBlocking() const { return non_blocking_; }
- mojom::blink::ScriptType GetScriptType() const { return script_type_; }
+ ScriptTypeAtPrepare GetScriptType() const { return script_type_; }
// Helper functions used by our parent classes.
void DidNotifySubtreeInsertionsToDocument();
@@ -178,7 +176,7 @@ class CORE_EXPORT ScriptLoader final : public GarbageCollected<ScriptLoader>,
// <spec href="https://html.spec.whatwg.org/C/#concept-script-type">... It is
// determined when the script is prepared, ...</spec>
- mojom::blink::ScriptType script_type_ = mojom::blink::ScriptType::kClassic;
+ ScriptTypeAtPrepare script_type_ = ScriptTypeAtPrepare::kInvalid;
// <spec href="https://html.spec.whatwg.org/C/#concept-script-external">
// ... It is determined when the script is prepared, ...</spec>
diff --git a/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.cc b/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.cc
index 23d74aa1d03..47d6e87a859 100644
--- a/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.cc
+++ b/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_css_style_sheet_init.h"
@@ -15,6 +16,7 @@
#include "third_party/blink/renderer/core/script/modulator.h"
#include "third_party/blink/renderer/core/script/module_record_resolver.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
#include "v8/include/v8.h"
@@ -24,7 +26,7 @@ namespace blink {
// https://whatpr.org/html/4898/webappapis.html#creating-a-css-module-script
ValueWrapperSyntheticModuleScript*
ValueWrapperSyntheticModuleScript::CreateCSSWrapperSyntheticModuleScript(
- const base::Optional<ModuleScriptCreationParams>& params,
+ const ModuleScriptCreationParams& params,
Modulator* settings_object) {
DCHECK(settings_object->HasValidContext());
ScriptState* script_state = settings_object->GetScriptState();
@@ -34,13 +36,14 @@ ValueWrapperSyntheticModuleScript::CreateCSSWrapperSyntheticModuleScript(
"ModuleScriptLoader",
"CreateCSSWrapperSyntheticModuleScript");
ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ UseCounter::Count(execution_context, WebFeature::kCreateCSSModuleScript);
auto* context_window = DynamicTo<LocalDOMWindow>(execution_context);
if (!context_window) {
v8::Local<v8::Value> error = V8ThrowException::CreateTypeError(
isolate, "Cannot create CSS Module in non-document context");
return ValueWrapperSyntheticModuleScript::CreateWithError(
- v8::Local<v8::Value>(), settings_object, params->GetResponseUrl(),
- KURL(), ScriptFetchOptions(), error);
+ v8::Local<v8::Value>(), settings_object, params.SourceURL(), KURL(),
+ ScriptFetchOptions(), error);
}
CSSStyleSheetInit* init = CSSStyleSheetInit::Create();
CSSStyleSheet* style_sheet =
@@ -49,26 +52,26 @@ ValueWrapperSyntheticModuleScript::CreateCSSWrapperSyntheticModuleScript(
v8::Local<v8::Value> error = exception_state.GetException();
exception_state.ClearException();
return ValueWrapperSyntheticModuleScript::CreateWithError(
- v8::Local<v8::Value>(), settings_object, params->GetResponseUrl(),
- KURL(), ScriptFetchOptions(), error);
+ v8::Local<v8::Value>(), settings_object, params.SourceURL(), KURL(),
+ ScriptFetchOptions(), error);
}
- style_sheet->replaceSync(params->GetSourceText().ToString(), exception_state);
+ style_sheet->replaceSync(params.GetSourceText().ToString(), exception_state);
if (exception_state.HadException()) {
v8::Local<v8::Value> error = exception_state.GetException();
exception_state.ClearException();
return ValueWrapperSyntheticModuleScript::CreateWithError(
- v8::Local<v8::Value>(), settings_object, params->GetResponseUrl(),
- KURL(), ScriptFetchOptions(), error);
+ v8::Local<v8::Value>(), settings_object, params.SourceURL(), KURL(),
+ ScriptFetchOptions(), error);
}
v8::Local<v8::Value> v8_value_stylesheet = ToV8(style_sheet, script_state);
return ValueWrapperSyntheticModuleScript::CreateWithDefaultExport(
- v8_value_stylesheet, settings_object, params->GetResponseUrl(), KURL(),
+ v8_value_stylesheet, settings_object, params.SourceURL(), KURL(),
ScriptFetchOptions());
}
ValueWrapperSyntheticModuleScript*
ValueWrapperSyntheticModuleScript::CreateJSONWrapperSyntheticModuleScript(
- const base::Optional<ModuleScriptCreationParams>& params,
+ const ModuleScriptCreationParams& params,
Modulator* settings_object) {
DCHECK(settings_object->HasValidContext());
ScriptState::Scope scope(settings_object->GetScriptState());
@@ -77,11 +80,13 @@ ValueWrapperSyntheticModuleScript::CreateJSONWrapperSyntheticModuleScript(
v8::Isolate* isolate = context->GetIsolate();
v8::TryCatch try_catch(isolate);
v8::Local<v8::String> original_json =
- V8String(isolate, params->GetSourceText().ToString());
+ V8String(isolate, params.GetSourceText());
v8::Local<v8::Value> parsed_json;
ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
"ModuleScriptLoader",
"CreateJSONWrapperSyntheticModuleScript");
+ UseCounter::Count(ExecutionContext::From(settings_object->GetScriptState()),
+ WebFeature::kCreateJSONModuleScript);
// Step 1. "Let script be a new module script that this algorithm will
// subsequently initialize."
// [spec text]
@@ -101,11 +106,11 @@ ValueWrapperSyntheticModuleScript::CreateJSONWrapperSyntheticModuleScript(
v8::Local<v8::Value> error = exception_state.GetException();
exception_state.ClearException();
return ValueWrapperSyntheticModuleScript::CreateWithError(
- parsed_json, settings_object, params->GetResponseUrl(), KURL(),
+ parsed_json, settings_object, params.SourceURL(), KURL(),
ScriptFetchOptions(), error);
} else {
return ValueWrapperSyntheticModuleScript::CreateWithDefaultExport(
- parsed_json, settings_object, params->GetResponseUrl(), KURL(),
+ parsed_json, settings_object, params.SourceURL(), KURL(),
ScriptFetchOptions());
}
}
@@ -199,7 +204,20 @@ v8::MaybeLocal<v8::Value> ValueWrapperSyntheticModuleScript::EvaluationSteps(
DCHECK(!try_catch.HasCaught());
DCHECK(!result.IsNothing() && result.FromJust());
- return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
+ if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
+ v8::Local<v8::Promise::Resolver> promise_resolver;
+ if (!v8::Promise::Resolver::New(context).ToLocal(&promise_resolver)) {
+ if (!isolate->IsExecutionTerminating()) {
+ LOG(FATAL) << "Cannot recover from failure to create a new "
+ "v8::Promise::Resolver object (OOM?)";
+ }
+ return v8::MaybeLocal<v8::Value>();
+ }
+ promise_resolver->Resolve(context, v8::Undefined(isolate)).ToChecked();
+ return promise_resolver->GetPromise();
+ }
+
+ return v8::Undefined(isolate);
}
void ValueWrapperSyntheticModuleScript::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h b/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h
index 184fe69619d..edb234e2db6 100644
--- a/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h
+++ b/chromium/third_party/blink/renderer/core/script/value_wrapper_synthetic_module_script.h
@@ -26,14 +26,12 @@ class CORE_EXPORT ValueWrapperSyntheticModuleScript final
: public ModuleScript {
public:
static ValueWrapperSyntheticModuleScript*
- CreateCSSWrapperSyntheticModuleScript(
- const base::Optional<ModuleScriptCreationParams>& params,
- Modulator* settings_object);
+ CreateCSSWrapperSyntheticModuleScript(const ModuleScriptCreationParams&,
+ Modulator* settings_object);
static ValueWrapperSyntheticModuleScript*
- CreateJSONWrapperSyntheticModuleScript(
- const base::Optional<ModuleScriptCreationParams>& params,
- Modulator* settings_object);
+ CreateJSONWrapperSyntheticModuleScript(const ModuleScriptCreationParams&,
+ Modulator* settings_object);
static ValueWrapperSyntheticModuleScript* CreateWithDefaultExport(
v8::Local<v8::Value> value,
@@ -78,4 +76,4 @@ class CORE_EXPORT ValueWrapperSyntheticModuleScript final
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_VALUE_WRAPPER_SYNTHETIC_MODULE_SCRIPT_H_ \ No newline at end of file
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_VALUE_WRAPPER_SYNTHETIC_MODULE_SCRIPT_H_
diff --git a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
index 0665ca8c5b9..c93b05f60da 100644
--- a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.cc
@@ -4,12 +4,10 @@
#include "third_party/blink/renderer/core/script/worker_modulator_impl.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h"
#include "third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h"
#include "third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
@@ -19,7 +17,7 @@ WorkerModulatorImpl::WorkerModulatorImpl(ScriptState* script_state)
ModuleScriptFetcher* WorkerModulatorImpl::CreateModuleScriptFetcher(
ModuleScriptCustomFetchType custom_fetch_type,
- util::PassKey<ModuleScriptLoader> pass_key) {
+ base::PassKey<ModuleScriptLoader> pass_key) {
auto* global_scope = To<WorkerGlobalScope>(GetExecutionContext());
switch (custom_fetch_type) {
case ModuleScriptCustomFetchType::kNone:
@@ -55,9 +53,4 @@ bool WorkerModulatorImpl::IsDynamicImportForbidden(String* reason) {
return true;
}
-mojom::blink::V8CacheOptions WorkerModulatorImpl::GetV8CacheOptions() const {
- auto* scope = To<WorkerGlobalScope>(GetExecutionContext());
- return scope->GetV8CacheOptions();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.h b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.h
index db1b378da9a..fa327d74baf 100644
--- a/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/worker_modulator_impl.h
@@ -22,12 +22,11 @@ class WorkerModulatorImpl final : public ModulatorImplBase {
// Implements ModulatorImplBase.
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader> pass_key) override;
+ base::PassKey<ModuleScriptLoader> pass_key) override;
private:
// Implements ModulatorImplBase.
bool IsDynamicImportForbidden(String* reason) override;
- mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
index 23d4c58608d..c78d70a0337 100644
--- a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
+++ b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
@@ -14,7 +14,7 @@ WorkletModulatorImpl::WorkletModulatorImpl(ScriptState* script_state)
ModuleScriptFetcher* WorkletModulatorImpl::CreateModuleScriptFetcher(
ModuleScriptCustomFetchType custom_fetch_type,
- util::PassKey<ModuleScriptLoader> pass_key) {
+ base::PassKey<ModuleScriptLoader> pass_key) {
DCHECK_EQ(ModuleScriptCustomFetchType::kWorkletAddModule, custom_fetch_type);
WorkletGlobalScope* global_scope =
To<WorkletGlobalScope>(GetExecutionContext());
@@ -27,9 +27,4 @@ bool WorkletModulatorImpl::IsDynamicImportForbidden(String* reason) {
return true;
}
-mojom::blink::V8CacheOptions WorkletModulatorImpl::GetV8CacheOptions() const {
- auto* scope = To<WorkletGlobalScope>(GetExecutionContext());
- return scope->GetV8CacheOptions();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.h b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.h
index e5c80fce60c..8784abdcbb3 100644
--- a/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.h
+++ b/chromium/third_party/blink/renderer/core/script/worklet_modulator_impl.h
@@ -24,12 +24,11 @@ class WorkletModulatorImpl final : public ModulatorImplBase {
// Implements ModulatorImplBase.
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader>) override;
+ base::PassKey<ModuleScriptLoader>) override;
private:
// Implements ModulatorImplBase.
bool IsDynamicImportForbidden(String* reason) override;
- mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/script/xml_parser_script_runner.cc b/chromium/third_party/blink/renderer/core/script/xml_parser_script_runner.cc
index 1b1617b8bf8..3bb606b9bac 100644
--- a/chromium/third_party/blink/renderer/core/script/xml_parser_script_runner.cc
+++ b/chromium/third_party/blink/renderer/core/script/xml_parser_script_runner.cc
@@ -77,7 +77,8 @@ void XMLParserScriptRunner::ProcessScriptElement(
bool success = script_loader->PrepareScript(
script_start_position, ScriptLoader::kAllowLegacyTypeInTypeAttribute);
- if (script_loader->GetScriptType() != mojom::blink::ScriptType::kClassic) {
+ if (script_loader->GetScriptType() ==
+ ScriptLoader::ScriptTypeAtPrepare::kModule) {
// XMLDocumentParser does not support a module script, and thus ignores it.
success = false;
document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
diff --git a/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc b/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
index 683df2318be..0f4f67818d1 100644
--- a/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
@@ -164,14 +164,14 @@ void ProgrammaticScrollAnimator::UpdateCompositorAnimations() {
}
}
-void ProgrammaticScrollAnimator::LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline* timeline) {
- ReattachCompositorAnimationIfNeeded(timeline);
+void ProgrammaticScrollAnimator::MainThreadScrollingDidChange() {
+ ReattachCompositorAnimationIfNeeded(
+ scrollable_area_->GetCompositorAnimationTimeline());
- // If the composited scrolling layer is lost during a composited animation,
- // continue the animation on the main thread.
+ // If the scrollable area switched to require main thread scrolling during a
+ // composited animation, continue the animation on the main thread.
if (run_state_ == RunState::kRunningOnCompositor &&
- !scrollable_area_->LayerForScrolling()) {
+ scrollable_area_->ShouldScrollOnMainThread()) {
RemoveAnimation();
run_state_ = RunState::kRunningOnMainThread;
animation_curve_->SetInitialValue(
diff --git a/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h b/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h
index fb7837f821a..65a00ac7176 100644
--- a/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h
+++ b/chromium/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h
@@ -14,7 +14,6 @@
namespace blink {
class ScrollableArea;
-class CompositorAnimationTimeline;
class CompositorScrollOffsetAnimationCurve;
// ProgrammaticScrollAnimator manages scroll offset animations ("smooth
@@ -50,8 +49,7 @@ class ProgrammaticScrollAnimator : public ScrollAnimatorCompositorCoordinator {
void UpdateCompositorAnimations() override;
void NotifyCompositorAnimationFinished(int group_id) override;
void NotifyCompositorAnimationAborted(int group_id) override {}
- void LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline*) override;
+ void MainThreadScrollingDidChange() override;
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
index cda134a8f21..39208df23cb 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.cc
@@ -351,9 +351,10 @@ void ScrollAnimator::UpdateCompositorAnimations() {
}
if (run_state_ == RunState::kWaitingToSendToCompositor) {
- if (!element_id_)
+ if (!element_id_) {
ReattachCompositorAnimationIfNeeded(
GetScrollableArea()->GetCompositorAnimationTimeline());
+ }
if (!animation_curve_)
CreateAnimationCurve();
@@ -392,9 +393,9 @@ void ScrollAnimator::TakeOverCompositorAnimation() {
ScrollAnimatorCompositorCoordinator::TakeOverCompositorAnimation();
}
-void ScrollAnimator::LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline* timeline) {
- ReattachCompositorAnimationIfNeeded(timeline);
+void ScrollAnimator::MainThreadScrollingDidChange() {
+ ReattachCompositorAnimationIfNeeded(
+ GetScrollableArea()->GetCompositorAnimationTimeline());
}
bool ScrollAnimator::RegisterAndScheduleAnimation() {
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.h b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.h
index 7a87645e920..4a6ec9437c1 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator.h
@@ -42,8 +42,6 @@
namespace blink {
-class CompositorAnimationTimeline;
-
// ScrollAnimator is the Blink-side implementation of user-input scroll offset
// animations ("smooth scrolling") on all platforms except for Mac.
//
@@ -128,8 +126,7 @@ class CORE_EXPORT ScrollAnimator : public ScrollAnimatorBase {
void UpdateCompositorAnimations() override;
void NotifyCompositorAnimationFinished(int group_id) override;
void NotifyCompositorAnimationAborted(int group_id) override;
- void LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline*) override;
+ void MainThreadScrollingDidChange() override;
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_base.h b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_base.h
index be126476aac..432a4e887bd 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_base.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_base.h
@@ -40,7 +40,6 @@
namespace blink {
-class CompositorAnimationTimeline;
class ScrollableArea;
class Scrollbar;
@@ -91,8 +90,7 @@ class CORE_EXPORT ScrollAnimatorBase
void UpdateCompositorAnimations() override {}
void NotifyCompositorAnimationFinished(int group_id) override {}
void NotifyCompositorAnimationAborted(int group_id) override {}
- void LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline*) override {}
+ void MainThreadScrollingDidChange() override {}
virtual void ContentAreaWillPaint() const {}
virtual void MouseEnteredContentArea() const {}
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
index 0b620202a51..ccaaf91ef01 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h
@@ -7,7 +7,6 @@
#include <memory>
#include "base/gtest_prod_util.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/scroll_offset_animations.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
@@ -16,6 +15,7 @@
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
namespace blink {
@@ -109,8 +109,7 @@ class CORE_EXPORT ScrollAnimatorCompositorCoordinator
virtual void TickAnimation(double monotonic_time) = 0;
virtual void NotifyCompositorAnimationFinished(int group_id) = 0;
virtual void NotifyCompositorAnimationAborted(int group_id) = 0;
- virtual void LayerForCompositedScrollingDidChange(
- CompositorAnimationTimeline*) = 0;
+ virtual void MainThreadScrollingDidChange() = 0;
RunState RunStateForTesting() { return run_state_; }
@@ -155,7 +154,7 @@ class CORE_EXPORT ScrollAnimatorCompositorCoordinator
void NotifyAnimationAborted(double monotonic_time, int group) override;
void NotifyAnimationTakeover(double monotonic_time,
double animation_start_time,
- std::unique_ptr<cc::AnimationCurve>) override {}
+ std::unique_ptr<gfx::AnimationCurve>) override {}
// CompositorAnimationClient implementation.
CompositorAnimation* GetCompositorAnimation() const override;
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
index 51d9ba90713..8ca84c39677 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
@@ -292,9 +292,11 @@ namespace blink {
// sandboxed renderer process.
class BlinkScrollbarPartAnimationTimer {
public:
- BlinkScrollbarPartAnimationTimer(BlinkScrollbarPartAnimation* animation,
- CFTimeInterval duration)
- : timer_(ThreadScheduler::Current()->CompositorTaskRunner(),
+ BlinkScrollbarPartAnimationTimer(
+ BlinkScrollbarPartAnimation* animation,
+ CFTimeInterval duration,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : timer_(std::move(task_runner),
this,
&BlinkScrollbarPartAnimationTimer::TimerFired),
start_time_(0.0),
@@ -327,6 +329,11 @@ class BlinkScrollbarPartAnimationTimer {
double fraction = delta / duration_;
fraction = clampTo(fraction, 0.0, 1.0);
double progress = timing_function_->Evaluate(fraction);
+ // In some scenarios, animation_ gets released during the call to
+ // setCurrentProgress. Because BlinkScrollbarPartAnimationTimer is a
+ // member variable of BlinkScrollbarPartAnimation animation_ the timer
+ // gets freed at the same time with animation_. In that case, it will
+ // not be safe to call any other code after animation_ setCurrentProgress.
[animation_ setCurrentProgress:progress];
}
@@ -351,7 +358,8 @@ class BlinkScrollbarPartAnimationTimer {
featureToAnimate:(FeatureToAnimate)featureToAnimate
animateFrom:(CGFloat)startValue
animateTo:(CGFloat)endValue
- duration:(NSTimeInterval)duration;
+ duration:(NSTimeInterval)duration
+ taskRunner:(scoped_refptr<base::SingleThreadTaskRunner>)taskRunner;
@end
@implementation BlinkScrollbarPartAnimation
@@ -360,13 +368,15 @@ class BlinkScrollbarPartAnimationTimer {
featureToAnimate:(FeatureToAnimate)featureToAnimate
animateFrom:(CGFloat)startValue
animateTo:(CGFloat)endValue
- duration:(NSTimeInterval)duration {
+ duration:(NSTimeInterval)duration
+ taskRunner:
+ (scoped_refptr<base::SingleThreadTaskRunner>)taskRunner {
self = [super init];
if (!self)
return nil;
- _timer =
- std::make_unique<blink::BlinkScrollbarPartAnimationTimer>(self, duration);
+ _timer = std::make_unique<blink::BlinkScrollbarPartAnimationTimer>(
+ self, duration, std::move(taskRunner));
_scrollbar = scrollbar;
_featureToAnimate = featureToAnimate;
_startValue = startValue;
@@ -401,6 +411,10 @@ class BlinkScrollbarPartAnimationTimer {
- (void)setCurrentProgress:(NSAnimationProgress)progress {
DCHECK(_scrollbar);
+ // In some scenarios, BlinkScrollbarPartAnimation is released in the middle
+ // of this method by _scrollbarPainter. This is why we have to retain the self
+ // pointer when we run this method.
+ [self retain];
CGFloat currentValue;
if (_startValue > _endValue)
@@ -427,7 +441,13 @@ class BlinkScrollbarPartAnimationTimer {
break;
}
- _scrollbar->SetNeedsPaintInvalidation(invalidParts);
+ // Before BlinkScrollbarPartAnimation is released by _scrollbarPainter,
+ // invalidate is called and _scrollbar is set to nullptr. Check to see
+ // if _scrollbar is non-null before calling SetNeedsPaintInvalidation.
+ if (_scrollbar)
+ _scrollbar->SetNeedsPaintInvalidation(invalidParts);
+
+ [self release];
}
- (void)invalidate {
@@ -441,6 +461,7 @@ class BlinkScrollbarPartAnimationTimer {
@interface BlinkScrollbarPainterDelegate : NSObject<NSAnimationDelegate> {
blink::Scrollbar* _scrollbar;
+ scoped_refptr<base::SingleThreadTaskRunner> _taskRunner;
base::scoped_nsobject<BlinkScrollbarPartAnimation> _knobAlphaAnimation;
base::scoped_nsobject<BlinkScrollbarPartAnimation> _trackAlphaAnimation;
@@ -450,19 +471,23 @@ class BlinkScrollbarPartAnimationTimer {
_expansionTransitionAnimation;
BOOL _hasExpandedSinceInvisible;
}
-- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar;
+- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
+ taskRunner:(scoped_refptr<base::SingleThreadTaskRunner>)taskRunner;
- (void)updateVisibilityImmediately:(bool)show;
- (void)cancelAnimations;
@end
@implementation BlinkScrollbarPainterDelegate
-- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar {
+- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
+ taskRunner:
+ (scoped_refptr<base::SingleThreadTaskRunner>)taskRunner {
self = [super init];
if (!self)
return nil;
_scrollbar = scrollbar;
+ _taskRunner = taskRunner;
return self;
}
@@ -529,7 +554,7 @@ class BlinkScrollbarPartAnimationTimer {
// If we are currently animating, stop
if (scrollbarPartAnimation) {
- [scrollbarPartAnimation stopAnimation];
+ [scrollbarPartAnimation invalidate];
scrollbarPartAnimation.reset();
}
@@ -539,7 +564,8 @@ class BlinkScrollbarPartAnimationTimer {
animateFrom:part == blink::kThumbPart ? [scrollerPainter knobAlpha]
: [scrollerPainter trackAlpha]
animateTo:newAlpha
- duration:duration]);
+ duration:duration
+ taskRunner:_taskRunner]);
[scrollbarPartAnimation startAnimation];
}
@@ -598,7 +624,8 @@ class BlinkScrollbarPartAnimationTimer {
featureToAnimate:UIStateTransition
animateFrom:[scrollbarPainter uiStateTransitionProgress]
animateTo:1.0
- duration:duration]);
+ duration:duration
+ taskRunner:_taskRunner]);
else {
// If we don't need to initialize the animation, just reset the values in
// case they have changed.
@@ -634,7 +661,8 @@ class BlinkScrollbarPartAnimationTimer {
featureToAnimate:ExpansionTransition
animateFrom:[scrollbarPainter expansionTransitionProgress]
animateTo:1.0
- duration:duration]);
+ duration:duration
+ taskRunner:_taskRunner]);
} else {
// If we don't need to initialize the animation, just reset the values in
// case they have changed.
@@ -690,7 +718,7 @@ ScrollAnimatorBase* ScrollAnimatorBase::Create(
ScrollAnimatorMac::ScrollAnimatorMac(blink::ScrollableArea* scrollable_area)
: ScrollAnimatorBase(scrollable_area),
- task_runner_(ThreadScheduler::Current()->CompositorTaskRunner()),
+ task_runner_(scrollable_area->GetCompositorTaskRunner()),
have_scrolled_since_page_load_(false),
needs_scroller_style_update_(false) {
scroll_animation_helper_delegate_.reset(
@@ -890,7 +918,8 @@ void ScrollAnimatorMac::DidAddVerticalScrollbar(Scrollbar& scrollbar) {
DCHECK(!vertical_scrollbar_painter_delegate_);
vertical_scrollbar_painter_delegate_.reset(
- [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar]);
+ [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar
+ taskRunner:task_runner_]);
[painter setDelegate:vertical_scrollbar_painter_delegate_];
[scrollbar_painter_controller_ setVerticalScrollerImp:painter];
@@ -916,7 +945,8 @@ void ScrollAnimatorMac::DidAddHorizontalScrollbar(Scrollbar& scrollbar) {
DCHECK(!horizontal_scrollbar_painter_delegate_);
horizontal_scrollbar_painter_delegate_.reset(
- [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar]);
+ [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar
+ taskRunner:task_runner_]);
[painter setDelegate:horizontal_scrollbar_painter_delegate_];
[scrollbar_painter_controller_ setHorizontalScrollerImp:painter];
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
index 8bd5f668ac0..9d538ac0bb4 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
@@ -62,7 +62,8 @@ class MockScrollableAreaForAnimatorTest
explicit MockScrollableAreaForAnimatorTest(bool scroll_animator_enabled,
const ScrollOffset& min_offset,
const ScrollOffset& max_offset)
- : scroll_animator_enabled_(scroll_animator_enabled),
+ : ScrollableArea(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+ scroll_animator_enabled_(scroll_animator_enabled),
min_offset_(min_offset),
max_offset_(max_offset) {}
diff --git a/chromium/third_party/blink/renderer/core/scroll/scroll_test.cc b/chromium/third_party/blink/renderer/core/scroll/scroll_test.cc
index 669d018bd4b..6bce2a00d2c 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scroll_test.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scroll_test.cc
@@ -29,7 +29,9 @@
namespace blink {
namespace {
-constexpr double kBeginFrameDelaySeconds = 0.5;
+const double kBeginFrameDelaySeconds =
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 1.5
+ : 0.5);
}
class FractionalScrollSimTest : public SimTest {
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
index 52b0c2804f3..7669bcbeae3 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -55,6 +55,7 @@
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
+#include "third_party/blink/renderer/platform/timer.h"
namespace blink {
@@ -95,7 +96,8 @@ mojom::blink::ScrollBehavior ScrollableArea::DetermineScrollBehavior(
return mojom::blink::ScrollBehavior::kInstant;
}
-ScrollableArea::ScrollableArea()
+ScrollableArea::ScrollableArea(
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner)
: scrollbar_overlay_color_theme_(kScrollbarOverlayColorThemeDark),
horizontal_scrollbar_needs_paint_invalidation_(false),
vertical_scrollbar_needs_paint_invalidation_(false),
@@ -105,7 +107,10 @@ ScrollableArea::ScrollableArea()
mouse_over_scrollbar_(false),
has_been_disposed_(false),
needs_show_scrollbar_layers_(false),
- uses_composited_scrolling_(false) {}
+ uses_composited_scrolling_(false),
+ compositor_task_runner_(std::move(compositor_task_runner)) {
+ DCHECK(compositor_task_runner_);
+}
ScrollableArea::~ScrollableArea() = default;
@@ -113,7 +118,7 @@ void ScrollableArea::Dispose() {
if (HasBeenDisposed())
return;
DisposeImpl();
- fade_overlay_scrollbars_timer_.reset();
+ fade_overlay_scrollbars_timer_ = nullptr;
has_been_disposed_ = true;
}
@@ -125,7 +130,7 @@ void ScrollableArea::ClearScrollableArea() {
scroll_animator_.Clear();
programmatic_scroll_animator_.Clear();
if (fade_overlay_scrollbars_timer_)
- fade_overlay_scrollbars_timer_->Stop();
+ fade_overlay_scrollbars_timer_->Value().Stop();
}
ScrollAnimatorBase& ScrollableArea::GetScrollAnimator() const {
@@ -489,7 +494,7 @@ void ScrollableArea::MouseEnteredScrollbar(Scrollbar& scrollbar) {
GetScrollAnimator().MouseEnteredScrollbar(scrollbar);
ShowNonMacOverlayScrollbars();
if (fade_overlay_scrollbars_timer_)
- fade_overlay_scrollbars_timer_->Stop();
+ fade_overlay_scrollbars_timer_->Value().Stop();
}
void ScrollableArea::MouseExitedScrollbar(Scrollbar& scrollbar) {
@@ -505,7 +510,7 @@ void ScrollableArea::MouseCapturedScrollbar() {
scrollbar_captured_ = true;
ShowNonMacOverlayScrollbars();
if (fade_overlay_scrollbars_timer_)
- fade_overlay_scrollbars_timer_->Stop();
+ fade_overlay_scrollbars_timer_->Value().Stop();
}
void ScrollableArea::MouseReleasedScrollbar() {
@@ -646,14 +651,11 @@ bool ScrollableArea::HasLayerForScrollCorner() const {
return LayerForScrollCorner();
}
-void ScrollableArea::LayerForScrollingDidChange(
- CompositorAnimationTimeline* timeline) {
- if (ProgrammaticScrollAnimator* programmatic_scroll_animator =
- ExistingProgrammaticScrollAnimator())
- programmatic_scroll_animator->LayerForCompositedScrollingDidChange(
- timeline);
- if (ScrollAnimatorBase* scroll_animator = ExistingScrollAnimator())
- scroll_animator->LayerForCompositedScrollingDidChange(timeline);
+void ScrollableArea::MainThreadScrollingDidChange() {
+ if (auto* programmatic_scroll_animator = ExistingProgrammaticScrollAnimator())
+ programmatic_scroll_animator->MainThreadScrollingDidChange();
+ if (auto* scroll_animator = ExistingScrollAnimator())
+ scroll_animator->MainThreadScrollingDidChange();
}
void ScrollableArea::ServiceScrollAnimations(double monotonic_time) {
@@ -768,16 +770,23 @@ void ScrollableArea::ShowNonMacOverlayScrollbars() {
return;
if (!fade_overlay_scrollbars_timer_) {
- fade_overlay_scrollbars_timer_.reset(new TaskRunnerTimer<ScrollableArea>(
- ThreadScheduler::Current()->CompositorTaskRunner(), this,
- &ScrollableArea::FadeOverlayScrollbarsTimerFired));
+ fade_overlay_scrollbars_timer_ = MakeGarbageCollected<
+ DisallowNewWrapper<HeapTaskRunnerTimer<ScrollableArea>>>(
+ GetCompositorTaskRunner(), this,
+ &ScrollableArea::FadeOverlayScrollbarsTimerFired);
}
if (!scrollbar_captured_ && !mouse_over_scrollbar_) {
- fade_overlay_scrollbars_timer_->StartOneShot(time_until_disable, FROM_HERE);
+ fade_overlay_scrollbars_timer_->Value().StartOneShot(time_until_disable,
+ FROM_HERE);
}
}
+scoped_refptr<base::SingleThreadTaskRunner>
+ScrollableArea::GetCompositorTaskRunner() {
+ return compositor_task_runner_;
+}
+
Node* ScrollableArea::EventTargetNode() const {
const LayoutBox* box = GetLayoutBox();
Node* node = box->GetNode();
@@ -984,6 +993,7 @@ bool ScrollableArea::PerformSnapping(
void ScrollableArea::Trace(Visitor* visitor) const {
visitor->Trace(scroll_animator_);
visitor->Trace(programmatic_scroll_animator_);
+ visitor->Trace(fade_overlay_scrollbars_timer_);
}
void ScrollableArea::InjectGestureScrollEvent(
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h
index c15845a1afc..3f420088eef 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -38,8 +38,10 @@
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
#include "third_party/blink/renderer/platform/graphics/overlay_scrollbar_clip_behavior.h"
+#include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -59,6 +61,7 @@ class Document;
class LayoutBox;
class LayoutObject;
class LocalFrame;
+class Node;
class PaintLayer;
class ProgrammaticScrollAnimator;
class ScrollAnchor;
@@ -397,6 +400,7 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
uses_composited_scrolling_ = uses_composited_scrolling;
}
virtual bool ShouldScrollOnMainThread() const { return false; }
+ void MainThreadScrollingDidChange();
// Overlay scrollbars can "fade-out" when inactive. This value should only be
// updated if BlinkControlsOverlayVisibility is true in the
@@ -448,7 +452,6 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
return scroll_corner_needs_paint_invalidation_;
}
- void LayerForScrollingDidChange(CompositorAnimationTimeline*);
bool NeedsShowScrollbarLayers() const { return needs_show_scrollbar_layers_; }
void DidShowScrollbarLayers() { needs_show_scrollbar_layers_ = false; }
@@ -549,6 +552,8 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
// box. GetLayoutBox()->GetNode() doesn't work in this case.
Node* EventTargetNode() const;
+ scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner();
+
protected:
// Deduces the mojom::blink::ScrollBehavior based on the
// element style and the parameter set by programmatic scroll into either
@@ -557,7 +562,8 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
mojom::blink::ScrollBehavior behavior_from_style,
mojom::blink::ScrollBehavior behavior_from_param);
- ScrollableArea();
+ explicit ScrollableArea(
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner);
ScrollbarOrientation ScrollbarOrientationFromDirection(
ScrollDirectionPhysical) const;
@@ -628,7 +634,7 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
mutable Member<ScrollAnimatorBase> scroll_animator_;
mutable Member<ProgrammaticScrollAnimator> programmatic_scroll_animator_;
- std::unique_ptr<TaskRunnerTimer<ScrollableArea>>
+ Member<DisallowNewWrapper<HeapTaskRunnerTimer<ScrollableArea>>>
fade_overlay_scrollbars_timer_;
Vector<ScrollCallback> pending_scroll_complete_callbacks_;
@@ -647,6 +653,8 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin {
// cc::Layer::ShowScrollbars() on our scroll layer. Ignored if not composited.
unsigned needs_show_scrollbar_layers_ : 1;
unsigned uses_composited_scrolling_ : 1;
+
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar.cc b/chromium/third_party/blink/renderer/core/scroll/scrollbar.cc
index 6dad36bd61f..09a75313b4d 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -80,6 +80,7 @@ Scrollbar::~Scrollbar() = default;
void Scrollbar::Trace(Visitor* visitor) const {
visitor->Trace(scrollable_area_);
+ visitor->Trace(scroll_timer_);
visitor->Trace(style_source_);
}
@@ -524,10 +525,6 @@ void Scrollbar::MouseUp(const WebMouseEvent& mouse_event) {
if (is_captured)
scrollable_area_->MouseReleasedScrollbar();
- ScrollableArea* scrollable_area_for_scrolling =
- ScrollableArea::GetForScrolling(scrollable_area_->GetLayoutBox());
- scrollable_area_for_scrolling->SnapAfterScrollbarScrolling(orientation_);
-
ScrollbarPart part = GetTheme().HitTestRootFramePosition(
*this, FlooredIntPoint(mouse_event.PositionInRootFrame()));
if (part == kNoPart) {
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar.h b/chromium/third_party/blink/renderer/core/scroll/scrollbar.h
index 71d86529fd0..d4b7dd5837b 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar.h
@@ -235,7 +235,7 @@ class CORE_EXPORT Scrollbar : public GarbageCollected<Scrollbar>,
bool enabled_;
- TaskRunnerTimer<Scrollbar> scroll_timer_;
+ HeapTaskRunnerTimer<Scrollbar> scroll_timer_;
float elastic_overscroll_;
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h b/chromium/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
index e162dcc0fc3..857a4a99d33 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
@@ -50,10 +50,12 @@ class MockScrollableArea : public GarbageCollected<MockScrollableArea>,
}
explicit MockScrollableArea()
- : maximum_scroll_offset_(ScrollOffset(0, 100)),
+ : ScrollableArea(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+ maximum_scroll_offset_(ScrollOffset(0, 100)),
chrome_client_(MakeGarbageCollected<MockPlatformChromeClient>()) {}
explicit MockScrollableArea(const ScrollOffset& offset)
- : maximum_scroll_offset_(offset),
+ : ScrollableArea(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+ maximum_scroll_offset_(offset),
chrome_client_(MakeGarbageCollected<MockPlatformChromeClient>()) {}
MOCK_CONST_METHOD0(VisualRectForScrollbarParts, LayoutRect());
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
index 311edeff8b0..c0de6f951d4 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -161,7 +161,7 @@ void ScrollbarTheme::PaintTickmarks(GraphicsContext& context,
const int y_pos = rect.Y() + (rect.Height() * percent);
FloatRect tick_rect(rect.X(), y_pos, rect.Width(), 3);
- context.FillRect(tick_rect, Color(0xCC, 0xAA, 0x00, 0xFF));
+ context.FillRect(tick_rect, Color(0xB0, 0x60, 0x00, 0xFF));
FloatRect tick_stroke(rect.X() + TickmarkBorderWidth(), y_pos + 1,
rect.Width() - 2 * TickmarkBorderWidth(), 1);
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
index 75baf5d363c..54f6741b8a3 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
@@ -31,10 +31,10 @@
#include "third_party/blink/renderer/core/scroll/scrollbar_theme_aura.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/input/scrollbar.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scrollbar.h"
@@ -137,7 +137,9 @@ bool ScrollbarThemeAura::SupportsDragSnapBack() const {
// Disable snapback on desktop Linux to better integrate with the desktop
// behavior. Typically, Linux apps do not implement scrollbar snapback (this
// is true for at least GTK and QT apps).
-#if defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return false;
#else
return true;
@@ -303,7 +305,9 @@ ScrollbarPart ScrollbarThemeAura::PartsToInvalidateOnThumbPositionChange(
bool ScrollbarThemeAura::ShouldCenterOnThumb(const Scrollbar& scrollbar,
const WebMouseEvent& event) {
-#if defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (event.button == WebPointerProperties::Button::kMiddle)
return true;
#endif
diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
index 4a9ca3c7886..bcc6e202199 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
@@ -32,7 +32,6 @@
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/platform/mac/web_scrollbar_theme.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/renderer/core/scroll/ns_scroller_imp_details.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_mac.h"
diff --git a/chromium/third_party/blink/renderer/core/streams/DIR_METADATA b/chromium/third_party/blink/renderer/core/streams/DIR_METADATA
new file mode 100644
index 00000000000..0bf5ee2e3fa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Network>StreamsAPI"
+}
+
+team_email: "blink-network-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/streams/OWNERS b/chromium/third_party/blink/renderer/core/streams/OWNERS
index b63f88130bc..a2e6241b06e 100644
--- a/chromium/third_party/blink/renderer/core/streams/OWNERS
+++ b/chromium/third_party/blink/renderer/core/streams/OWNERS
@@ -1,5 +1,2 @@
yhirano@chromium.org
ricea@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>StreamsAPI
diff --git a/chromium/third_party/blink/renderer/core/streams/count_queuing_strategy.cc b/chromium/third_party/blink/renderer/core/streams/count_queuing_strategy.cc
index bfd6d1f474a..98ca42425db 100644
--- a/chromium/third_party/blink/renderer/core/streams/count_queuing_strategy.cc
+++ b/chromium/third_party/blink/renderer/core/streams/count_queuing_strategy.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.h"
#include "third_party/blink/renderer/core/streams/queuing_strategy_common.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.cc b/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
index ffaeaa9689c..eb843c56898 100644
--- a/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
+++ b/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
@@ -196,6 +196,48 @@ class JavaScriptStreamAlgorithmWithExtraArg final : public StreamAlgorithm {
TraceWrapperV8Reference<v8::Value> extra_arg_;
};
+class JavaScriptByteStreamStartAlgorithm : public StreamStartAlgorithm {
+ public:
+ JavaScriptByteStreamStartAlgorithm(v8::Isolate* isolate,
+ v8::Local<v8::Function> method,
+ v8::Local<v8::Object> recv,
+ v8::Local<v8::Value> controller)
+ : recv_(isolate, recv),
+ method_(isolate, method),
+ controller_(isolate, controller) {}
+
+ v8::MaybeLocal<v8::Promise> Run(ScriptState* script_state,
+ ExceptionState& exception_state) override {
+ auto* isolate = script_state->GetIsolate();
+
+ auto value_maybe =
+ Call1(script_state, method_.NewLocal(isolate), recv_.NewLocal(isolate),
+ controller_.NewLocal(isolate), exception_state);
+ if (exception_state.HadException()) {
+ return v8::MaybeLocal<v8::Promise>();
+ }
+
+ v8::Local<v8::Value> value;
+ if (!value_maybe.ToLocal(&value)) {
+ exception_state.ThrowTypeError("internal error");
+ return v8::MaybeLocal<v8::Promise>();
+ }
+ return PromiseResolve(script_state, value);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(recv_);
+ visitor->Trace(method_);
+ visitor->Trace(controller_);
+ StreamStartAlgorithm::Trace(visitor);
+ }
+
+ private:
+ TraceWrapperV8Reference<v8::Object> recv_;
+ TraceWrapperV8Reference<v8::Function> method_;
+ TraceWrapperV8Reference<v8::Value> controller_;
+};
+
class JavaScriptStreamStartAlgorithm : public StreamStartAlgorithm {
public:
JavaScriptStreamStartAlgorithm(v8::Isolate* isolate,
@@ -343,10 +385,24 @@ CORE_EXPORT StreamStartAlgorithm* CreateStartAlgorithm(
controller);
}
+CORE_EXPORT StreamStartAlgorithm* CreateByteStreamStartAlgorithm(
+ ScriptState* script_state,
+ v8::Local<v8::Object> underlying_object,
+ v8::Local<v8::Value> method,
+ v8::Local<v8::Value> controller) {
+ return MakeGarbageCollected<JavaScriptByteStreamStartAlgorithm>(
+ script_state->GetIsolate(), method.As<v8::Function>(), underlying_object,
+ controller);
+}
+
CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm() {
return MakeGarbageCollected<TrivialStartAlgorithm>();
}
+CORE_EXPORT StreamAlgorithm* CreateTrivialStreamAlgorithm() {
+ return MakeGarbageCollected<TrivialStreamAlgorithm>();
+}
+
CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(
ScriptState* script_state,
v8::Local<v8::Object> object,
@@ -381,6 +437,21 @@ CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(
return result;
}
+CORE_EXPORT v8::MaybeLocal<v8::Value> Call1(ScriptState* script_state,
+ v8::Local<v8::Function> method,
+ v8::Local<v8::Object> object,
+ v8::Local<v8::Value> arg0,
+ ExceptionState& exception_state) {
+ v8::TryCatch try_catch(script_state->GetIsolate());
+ v8::MaybeLocal<v8::Value> result =
+ method->Call(script_state->GetContext(), object, 1, &arg0);
+ if (result.IsEmpty()) {
+ exception_state.RethrowV8Exception(try_catch.Exception());
+ return v8::MaybeLocal<v8::Value>();
+ }
+ return result;
+}
+
CORE_EXPORT v8::Local<v8::Promise> PromiseCall(ScriptState* script_state,
v8::Local<v8::Function> method,
v8::Local<v8::Object> recv,
@@ -562,4 +633,8 @@ double StrategyUnpacker::GetHighWaterMark(
exception_state);
}
+bool StrategyUnpacker::IsSizeUndefined() const {
+ return size_->IsUndefined();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.h b/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.h
index 2a588744813..70dacef4ef7 100644
--- a/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.h
+++ b/chromium/third_party/blink/renderer/core/streams/miscellaneous_operations.h
@@ -68,10 +68,22 @@ CORE_EXPORT StreamStartAlgorithm* CreateStartAlgorithm(
const char* method_name_for_error,
v8::Local<v8::Value> controller);
+// Create a StreamStartAlgorithm from the "start" method on |underlying_object|
+// for readable byte streams.
+CORE_EXPORT StreamStartAlgorithm* CreateByteStreamStartAlgorithm(
+ ScriptState*,
+ v8::Local<v8::Object> underlying_object,
+ v8::Local<v8::Value> method,
+ v8::Local<v8::Value> controller);
+
// Returns a startAlgorithm that always returns a promise resolved with
// undefined.
CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm();
+// Returns a streamAlgorithm that always returns a promise resolved with
+// undefined.
+CORE_EXPORT StreamAlgorithm* CreateTrivialStreamAlgorithm();
+
// Used in place of InvokeOrNoop in spec. Always takes 1 argument.
// https://streams.spec.whatwg.org/#invoke-or-noop
CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(ScriptState*,
@@ -81,6 +93,15 @@ CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(ScriptState*,
v8::Local<v8::Value> arg0,
ExceptionState&);
+// Used in JavaScriptByteStreamStartAlgoirthm to call the method.
+// This is a variation of the CallOrNoop1 method where it is given the method
+// function already.
+CORE_EXPORT v8::MaybeLocal<v8::Value> Call1(ScriptState*,
+ v8::Local<v8::Function> method,
+ v8::Local<v8::Object> object,
+ v8::Local<v8::Value> arg0,
+ ExceptionState&);
+
// https://streams.spec.whatwg.org/#promise-call
// "PromiseCall(F, V, args)"
// "F" is called |method| here
@@ -153,6 +174,8 @@ class StrategyUnpacker final {
int default_value,
ExceptionState&) const;
+ bool IsSizeUndefined() const;
+
private:
v8::Local<v8::Value> size_;
v8::Local<v8::Value> high_water_mark_;
diff --git a/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.cc b/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.cc
index 280c8b5e2bd..13f04aff4cc 100644
--- a/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.cc
+++ b/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.cc
@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.h b/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.h
index 343134e8bbb..49b3dea4a87 100644
--- a/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.h
+++ b/chromium/third_party/blink/renderer/core/streams/queue_with_sizes.h
@@ -10,12 +10,12 @@
#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/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ExceptionState;
-class Visitor;
// Implementation of the "Queue-with-sizes" operations from the standard. Unlike
// the standard, these operations do not operate polymorphically on the
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
index ec76fac8d54..7bdec2cd742 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -4,51 +4,1309 @@
#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
+#include "base/numerics/checked_math.h"
+#include "base/numerics/clamped_math.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer_view.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source_cancel_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source_pull_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source_start_callback.h"
+#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
+#include "third_party/blink/renderer/core/streams/promise_handler.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_byob_request.h"
+#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.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/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "v8/include/v8.h"
namespace blink {
-ReadableStreamBYOBRequest* ReadableByteStreamController::byobRequest(
- ExceptionState& exception_state) const {
- ThrowUnimplemented(exception_state);
- return nullptr;
+namespace {
+
+template <typename DOMType>
+DOMArrayBufferView* CreateAsArrayBufferView(DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t length) {
+ return DOMType::Create(buffer, byte_offset, length);
+}
+
+} // namespace
+
+ReadableByteStreamController::QueueEntry::QueueEntry(DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t byte_length)
+ : buffer(buffer), byte_offset(byte_offset), byte_length(byte_length) {}
+
+void ReadableByteStreamController::QueueEntry::Trace(Visitor* visitor) const {
+ visitor->Trace(buffer);
}
-base::Optional<double> ReadableByteStreamController::desiredSize(
- ExceptionState& exception_state) const {
- ThrowUnimplemented(exception_state);
- return base::nullopt;
+ReadableByteStreamController::PullIntoDescriptor::PullIntoDescriptor(
+ DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t byte_length,
+ size_t bytes_filled,
+ size_t element_size,
+ ViewConstructorType view_constructor,
+ ReaderType reader_type)
+ : buffer(buffer),
+ byte_offset(byte_offset),
+ byte_length(byte_length),
+ bytes_filled(bytes_filled),
+ element_size(element_size),
+ view_constructor(view_constructor),
+ reader_type(reader_type) {}
+
+void ReadableByteStreamController::PullIntoDescriptor::Trace(
+ Visitor* visitor) const {
+ visitor->Trace(buffer);
+}
+
+// This constructor is used internally; it is not reachable from Javascript.
+ReadableByteStreamController::ReadableByteStreamController()
+ : queue_total_size_(queue_.size()) {}
+
+ReadableStreamBYOBRequest* ReadableByteStreamController::byobRequest() {
+ // https://streams.spec.whatwg.org/#rbs-controller-byob-request
+ // 1. If this.[[byobRequest]] is null and this.[[pendingPullIntos]] is not
+ // empty,
+ if (!byob_request_ && !pending_pull_intos_.IsEmpty()) {
+ // a. Let firstDescriptor be this.[[pendingPullIntos]][0].
+ const PullIntoDescriptor* first_descriptor = pending_pull_intos_[0];
+ // b. Let view be ! Construct(%Uint8Array%, « firstDescriptor’s buffer,
+ // firstDescriptor’s byte offset + firstDescriptor’s bytes filled,
+ // firstDescriptor’s byte length − firstDescriptor’s bytes filled »).
+ DOMUint8Array* const view = DOMUint8Array::Create(
+ first_descriptor->buffer,
+ first_descriptor->byte_offset + first_descriptor->bytes_filled,
+ first_descriptor->byte_length - first_descriptor->bytes_filled);
+ // c. Let byobRequest be a new ReadableStreamBYOBRequest.
+ // d. Set byobRequest.[[controller]] to this.
+ // e. Set byobRequest.[[view]] to view.
+ // f. Set this.[[byobRequest]] to byobRequest.
+ byob_request_ = MakeGarbageCollected<ReadableStreamBYOBRequest>(
+ this, NotShared<DOMUint8Array>(view));
+ }
+ // 2. Return this.[[byobRequest]].
+ return byob_request_;
+}
+
+base::Optional<double> ReadableByteStreamController::desiredSize() {
+ // https://streams.spec.whatwg.org/#rbs-controller-desired-size
+ // 1. Return ! ReadableByteStreamControllerGetDesiredSize(this).
+ return GetDesiredSize(this);
+}
+
+base::Optional<double> ReadableByteStreamController::GetDesiredSize(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
+ // 1. Let state be controller.[[stream]].[[state]].
+ switch (controller->controlled_readable_stream_->state_) {
+ // 2. If state is "errored", return null.
+ case ReadableStream::kErrored:
+ return base::nullopt;
+
+ // 3. If state is "closed", return 0.
+ case ReadableStream::kClosed:
+ return 0.0;
+
+ case ReadableStream::kReadable:
+ // 4. Return controller.[[strategyHWM]]] - controller.[[queueTotalSize]].
+ return controller->strategy_high_water_mark_ -
+ controller->queue_total_size_;
+ }
}
void ReadableByteStreamController::close(ScriptState* script_state,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ // https://streams.spec.whatwg.org/#rbs-controller-close
+ // 1. If this.[[closeRequested]] is true, throw a TypeError exception.
+ if (close_requested_) {
+ exception_state.ThrowTypeError(
+ "Cannot close a readable stream that has already been requested "
+ "to be closed");
+ return;
+ }
+
+ // 2. If this.[[stream]].[[state]] is not "readable", throw a TypeError
+ // exception.
+ if (controlled_readable_stream_->state_ != ReadableStream::kReadable) {
+ exception_state.ThrowTypeError(
+ "Cannot close a readable stream that is not readable");
+ return;
+ }
+
+ // 3. Perform ? ReadableByteStreamControllerClose(this).
+ Close(script_state, this, exception_state);
}
void ReadableByteStreamController::enqueue(ScriptState* script_state,
NotShared<DOMArrayBufferView> chunk,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ // https://streams.spec.whatwg.org/#rbs-controller-enqueue
+ // 1. If chunk.[[ByteLength]] is 0, throw a TypeError exception.
+ if (chunk->byteLength() == 0) {
+ exception_state.ThrowTypeError("chunk is empty");
+ return;
+ }
+
+ // 2. If chunk.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a
+ // TypeError exception.
+ if (chunk->buffer()->ByteLength() == 0) {
+ exception_state.ThrowTypeError("chunk's buffer is empty");
+ return;
+ }
+
+ // 3. If this.[[closeRequested]] is true, throw a TypeError exception.
+ if (close_requested_) {
+ exception_state.ThrowTypeError("close requested already");
+ return;
+ }
+
+ // 4. If this.[[stream]].[[state]] is not "readable", throw a TypeError
+ // exception.
+ if (controlled_readable_stream_->state_ != ReadableStream::kReadable) {
+ exception_state.ThrowTypeError("stream is not readable");
+ return;
+ }
+
+ // 5. Return ! ReadableByteStreamControllerEnqueue(this, chunk).
+ Enqueue(script_state, this, chunk, exception_state);
}
-void ReadableByteStreamController::error(ScriptState* script_state,
- ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+void ReadableByteStreamController::error(ScriptState* script_state) {
+ error(script_state, ScriptValue(script_state->GetIsolate(),
+ v8::Undefined(script_state->GetIsolate())));
}
void ReadableByteStreamController::error(ScriptState* script_state,
- ScriptValue e,
- ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ const ScriptValue& e) {
+ // https://streams.spec.whatwg.org/#rbs-controller-error
+ // 1. Perform ! ReadableByteStreamControllerError(this, e).
+ Error(script_state, this, e.V8Value());
+}
+
+void ReadableByteStreamController::Close(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
+ // 1. Let stream be controller.[[stream]].
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+
+ // 2. If controller.[[closeRequested]] is true or stream.[[state]] is not
+ // "readable", return.
+ if (controller->close_requested_ ||
+ stream->state_ != ReadableStream::kReadable) {
+ return;
+ }
+
+ // 3. If controller.[[queueTotalSize]] > 0,
+ if (controller->queue_total_size_ > 0) {
+ // a. Set controller.[[closeRequested]] to true.
+ controller->close_requested_ = true;
+ // b. Return.
+ return;
+ }
+
+ // 4. If controller.[[pendingPullIntos]] is not empty,
+ if (!controller->pending_pull_intos_.IsEmpty()) {
+ // a. Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
+ const PullIntoDescriptor* first_pending_pull_into =
+ controller->pending_pull_intos_[0];
+ // b. If firstPendingPullInto’s bytes filled > 0,
+ if (first_pending_pull_into->bytes_filled > 0) {
+ // i. Let e be a new TypeError exception.
+ exception_state.ThrowTypeError("Cannot close while responding");
+ v8::Local<v8::Value> e = exception_state.GetException();
+ // ii. Perform ! ReadableByteStreamControllerError(controller, e).
+ Error(script_state, controller, e);
+ // iii. Throw e.
+ return;
+ }
+ }
+
+ // 5. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+ ClearAlgorithms(controller);
+
+ // 6. Perform ! ReadableStreamClose(stream).
+ ReadableStream::Close(script_state, stream);
+}
+
+void ReadableByteStreamController::Error(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ v8::Local<v8::Value> e) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
+ // 1. Let stream by controller.[[stream]].
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+
+ // 2. If stream.[[state]] is not "readable", return.
+ if (stream->state_ != ReadableStream::kReadable) {
+ return;
+ }
+
+ // 3. Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
+ ClearPendingPullIntos(controller);
+
+ // 4. Perform ! ResetQueue(controller).
+ ResetQueue(controller);
+
+ // 5. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+ ClearAlgorithms(controller);
+
+ // 6. Perform ! ReadableStreamError(stream, e).
+ ReadableStream::Error(script_state, stream, e);
+}
+
+void ReadableByteStreamController::Enqueue(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ NotShared<DOMArrayBufferView> chunk,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
+ // 1. Let stream be controller.[[stream]].i
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+
+ // 2. If controller.[[closeRequested]] is true or stream.[[state]] is not
+ // "readable", return.
+ if (controller->close_requested_ ||
+ stream->state_ != ReadableStream::kReadable) {
+ return;
+ }
+
+ // 3. Let buffer be chunk.[[ViewedArrayBuffer]].
+ DOMArrayBuffer* const buffer = chunk->buffer();
+
+ // 4. Let byteOffset be chunk.[[ByteOffset]].
+ const size_t byte_offset = chunk->byteOffset();
+
+ // 5. Let byteLength be chunk.[[ByteLength]].
+ const size_t byte_length = chunk->byteLength();
+
+ // 6. Let transferredBuffer be ! TransferArrayBuffer(buffer).
+ DOMArrayBuffer* const transferred_buffer =
+ TransferArrayBuffer(script_state, buffer, exception_state);
+
+ // 7. If ! ReadableStreamHasDefaultReader(stream) is true
+ if (ReadableStream::HasDefaultReader(stream)) {
+ // a. If ! ReadableStreamGetNumReadRequests(stream) is 0,
+ if (ReadableStream::GetNumReadRequests(stream) == 0) {
+ // i. Perform !
+ // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+ // transferredBuffer, byteOffset, byteLength).
+ EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+ byte_length);
+ } else {
+ // b. Otherwise,
+ // i. Assert: controller.[[queue]] is empty.
+ DCHECK(controller->queue_.IsEmpty());
+ // ii. Let transferredView be ! Construct(%Uint8Array%, «
+ // transferredBuffer, byteOffset, byteLength »).
+ v8::Local<v8::Value> const transferred_view = v8::Uint8Array::New(
+ ToV8(transferred_buffer, script_state).As<v8::ArrayBuffer>(),
+ byte_offset, byte_length);
+ // iii. Perform ! ReadableStreamFulfillReadRequest(stream,
+ // transferredView, false).
+ ReadableStream::FulfillReadRequest(script_state, stream, transferred_view,
+ false);
+ }
+ }
+
+ // 8. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
+ else if (ReadableStream::HasBYOBReader(stream)) {
+ // a. Perform !
+ // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+ // transferredBuffer, byteOffset, byteLength).
+ EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+ byte_length);
+ // b. Perform !
+ // ReadableByteStreamControllerProcessPullIntoDescriptorsUsing
+ // Queue(controller).
+ ProcessPullIntoDescriptorsUsingQueue(script_state, controller);
+ } else {
+ // 9. Otherwise,
+ // a. Assert: ! IsReadableStreamLocked(stream) is false.
+ DCHECK(!ReadableStream::IsLocked(stream));
+ // b. Perform !
+ // ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+ // transferredBuffer, byteOffset, byteLength).
+ EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+ byte_length);
+ }
+
+ // 10. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::EnqueueChunkToQueue(
+ ReadableByteStreamController* controller,
+ DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t byte_length) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
+ // 1. Append a new readable byte stream queue entry with buffer buffer, byte
+ // offset byteOffset, and byte length byteLength to controller.[[queue]].
+ QueueEntry* const entry =
+ MakeGarbageCollected<QueueEntry>(buffer, byte_offset, byte_length);
+ controller->queue_.push_back(entry);
+ // 2. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] +
+ // byteLength.
+ controller->queue_total_size_ += byte_length;
+}
+
+void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
+ // 1. Assert: controller.[[closeRequested]] is false.
+ DCHECK(!controller->close_requested_);
+ // 2. While controller.[[pendingPullIntos]] is not empty,
+ while (!controller->pending_pull_intos_.IsEmpty()) {
+ // a. If controller.[[queueTotalSize]] is 0, return.
+ if (controller->queue_total_size_ == 0) {
+ return;
+ }
+ // b. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
+ PullIntoDescriptor* const pull_into_descriptor =
+ controller->pending_pull_intos_[0];
+ // c. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
+ // controller, pullIntoDescriptor) is true,
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ // i. Perform !
+ // ReadableByteStreamControllerShiftPendingPullInto(controller).
+ ShiftPendingPullInto(controller);
+ // ii. Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(
+ // controller.[[stream]], pullIntoDescriptor).
+ CommitPullIntoDescriptor(script_state,
+ controller->controlled_readable_stream_,
+ pull_into_descriptor);
+ }
+ }
+}
+
+void ReadableByteStreamController::CallPullIfNeeded(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
+ // 1. Let shouldPull be !
+ // ReadableByteStreamControllerShouldCallPull(controller).
+ const bool should_pull = ShouldCallPull(controller);
+ // 2. If shouldPull is false, return.
+ if (!should_pull) {
+ return;
+ }
+ // 3. If controller.[[pulling]] is true,
+ if (controller->pulling_) {
+ // a. Set controller.[[pullAgain]] to true.
+ controller->pull_again_ = true;
+ // b. Return.
+ return;
+ }
+ // 4. Assert: controller.[[pullAgain]] is false.
+ DCHECK(!controller->pull_again_);
+ // 5. Set controller.[[pulling]] to true.
+ controller->pulling_ = true;
+ // 6. Let pullPromise be the result of performing
+ // controller.[[pullAlgorithm]].
+ auto pull_promise =
+ controller->pull_algorithm_->Run(script_state, 0, nullptr);
+
+ class ResolveFunction final : public PromiseHandler {
+ public:
+ ResolveFunction(ScriptState* script_state,
+ ReadableByteStreamController* controller)
+ : PromiseHandler(script_state), controller_(controller) {}
+
+ void CallWithLocal(v8::Local<v8::Value>) override {
+ // 7. Upon fulfillment of pullPromise,
+ // a. Set controller.[[pulling]] to false.
+ controller_->pulling_ = false;
+ // b. If controller.[[pullAgain]] is true,
+ if (controller_->pull_again_) {
+ // i. Set controller.[[pullAgain]] to false.
+ controller_->pull_again_ = false;
+ // ii. Perform !
+ // ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(GetScriptState(), controller_);
+ }
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(controller_);
+ PromiseHandler::Trace(visitor);
+ }
+
+ private:
+ const Member<ReadableByteStreamController> controller_;
+ };
+
+ class RejectFunction final : public PromiseHandler {
+ public:
+ RejectFunction(ScriptState* script_state,
+ ReadableByteStreamController* controller)
+ : PromiseHandler(script_state), controller_(controller) {}
+
+ void CallWithLocal(v8::Local<v8::Value> e) override {
+ // 8. Upon rejection of pullPromise with reason e,
+ // a. Perform ! ReadableByteStreamControllerError(controller, e).
+ Error(GetScriptState(), controller_, e);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(controller_);
+ PromiseHandler::Trace(visitor);
+ }
+
+ private:
+ const Member<ReadableByteStreamController> controller_;
+ };
+
+ StreamThenPromise(
+ script_state->GetContext(), pull_promise,
+ MakeGarbageCollected<ResolveFunction>(script_state, controller),
+ MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+ReadableByteStreamController::PullIntoDescriptor*
+ReadableByteStreamController::ShiftPendingPullInto(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
+ // 1. Let descriptor be controller.[[pendingPullIntos]][0].
+ PullIntoDescriptor* const descriptor = controller->pending_pull_intos_[0];
+ // 2. Remove descriptor from controller.[[pendingPullIntos]].
+ controller->pending_pull_intos_.pop_front();
+ // 3. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+ InvalidateBYOBRequest(controller);
+ // 4. Return descriptor.
+ return descriptor;
+}
+
+bool ReadableByteStreamController::ShouldCallPull(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
+ // 1. Let stream be controller.[[stream]].
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+ // 2. If stream.[[state]] is not "readable", return false.
+ if (stream->state_ != ReadableStream::kReadable) {
+ return false;
+ }
+ // 3. If controller.[[closeRequested]] is true, return false.
+ if (controller->close_requested_) {
+ return false;
+ }
+ // 4. If controller.[[started]] is false, return false.
+ if (!controller->started_) {
+ return false;
+ }
+ // 5. If ! ReadableStreamHasDefaultReader(stream) is true and !
+ // ReadableStreamGetNumReadRequests(stream) > 0, return true.
+ if (ReadableStream::HasDefaultReader(stream) &&
+ ReadableStream::GetNumReadRequests(stream) > 0) {
+ return true;
+ }
+ // 6. If ! ReadableStreamHasBYOBReader(stream) is true and !
+ // ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
+ if (ReadableStream::HasBYOBReader(stream) &&
+ ReadableStream::GetNumReadIntoRequests(stream) > 0) {
+ return true;
+ }
+ // 7. Let desiredSize be !
+ // ReadableByteStreamControllerGetDesiredSize(controller).
+ const base::Optional<double> desired_size = GetDesiredSize(controller);
+ // 8. Assert: desiredSize is not null.
+ DCHECK(desired_size);
+ // 9. If desiredSize > 0, return true.
+ if (*desired_size > 0) {
+ return true;
+ }
+ // 10. Return false.
+ return false;
+}
+
+void ReadableByteStreamController::CommitPullIntoDescriptor(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ PullIntoDescriptor* pull_into_descriptor) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
+ // 1. Assert: stream.[[state]] is not "errored".
+ DCHECK_NE(stream->state_, ReadableStream::kErrored);
+ // 2. Let done be false.
+ bool done = false;
+ // 3. If stream.[[state]] is "closed",
+ if (stream->state_ == ReadableStream::kClosed) {
+ // a. Assert: pullIntoDescriptor’s bytes filled is 0.
+ DCHECK_EQ(pull_into_descriptor->bytes_filled, 0u);
+ // b. Set done to true.
+ done = true;
+ }
+ // 4. Let filledView be !
+ // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
+ auto* filled_view = ConvertPullIntoDescriptor(pull_into_descriptor);
+ // 5. If pullIntoDescriptor’s reader type is "default",
+ if (pull_into_descriptor->reader_type == ReaderType::kDefault) {
+ // a. Perform ! ReadableStreamFulfillReadRequest(stream, filledView,
+ // done).
+ ReadableStream::FulfillReadRequest(script_state, stream,
+ ToV8(filled_view, script_state), done);
+ } else {
+ // 6. Otherwise,
+ // a. Assert: pullIntoDescriptor’s reader type is "byob".
+ DCHECK_EQ(pull_into_descriptor->reader_type, ReaderType::kBYOB);
+ // b. Perform ! ReadableStreamFulfillReadIntoRequest(stream, filledView,
+ // done).
+ ReadableStream::FulfillReadIntoRequest(script_state, stream, filled_view,
+ done);
+ }
+}
+
+DOMArrayBufferView* ReadableByteStreamController::ConvertPullIntoDescriptor(
+ PullIntoDescriptor* pull_into_descriptor) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
+ // 1. Let bytesFilled be pullIntoDescriptor’s bytes filled.
+ const size_t bytes_filled = pull_into_descriptor->bytes_filled;
+ // 2. Let elementSize be pullIntoDescriptor’s element size.
+ const size_t element_size = pull_into_descriptor->element_size;
+ // 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
+ DCHECK_LE(bytes_filled, pull_into_descriptor->byte_length);
+ // 4. Assert: bytesFilled mod elementSize is 0.
+ DCHECK_EQ(bytes_filled % element_size, 0u);
+ // 5. Return ! Construct(pullIntoDescriptor’s view constructor, «
+ // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, bytesFilled
+ // ÷ elementSize »).
+ return pull_into_descriptor->view_constructor(
+ pull_into_descriptor->buffer, pull_into_descriptor->byte_offset,
+ (bytes_filled / element_size));
+}
+
+void ReadableByteStreamController::ClearPendingPullIntos(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
+ // 1. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+ InvalidateBYOBRequest(controller);
+ // 2. Set controller.[[pendingPullIntos]] to a new empty list.
+ controller->pending_pull_intos_.clear();
+}
+
+void ReadableByteStreamController::ClearAlgorithms(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
+ // 1. Set controller.[[pullAlgorithm]] to undefined.
+ controller->pull_algorithm_ = nullptr;
+
+ // 2. Set controller.[[cancelAlgorithm]] to undefined.
+ controller->cancel_algorithm_ = nullptr;
+}
+
+void ReadableByteStreamController::InvalidateBYOBRequest(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
+ // 1. If controller.[[byobRequest]] is null, return.
+ if (!controller->byob_request_) {
+ return;
+ }
+ // 2. Set controller.[[byobRequest]].[[controller]] to undefined.
+ controller->byob_request_->controller_ = nullptr;
+ // 3. Set controller.[[byobRequest]].[[view]] to null.
+ controller->byob_request_->view_ = NotShared<DOMArrayBufferView>(nullptr);
+ // 4. Set controller.[[byobRequest]] to null.
+ controller->byob_request_ = nullptr;
+}
+
+void ReadableByteStreamController::SetUp(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ ReadableByteStreamController* controller,
+ StreamStartAlgorithm* start_algorithm,
+ StreamAlgorithm* pull_algorithm,
+ StreamAlgorithm* cancel_algorithm,
+ double high_water_mark,
+ size_t auto_allocate_chunk_size,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
+ // 1. Assert: stream.[[controller]] is undefined.
+ DCHECK(!stream->readable_stream_controller_);
+ // 2. If autoAllocateChunkSize is not undefined,
+ if (auto_allocate_chunk_size) {
+ // a. Assert: ! IsInteger(autoAllocateChunkSize) is true.
+ // b. Assert: autoAllocateChunkSize is positive.
+ // Due to autoAllocateChunkSize having the [EnforceRange] attribute, it
+ // can never be negative.
+ DCHECK_GT(auto_allocate_chunk_size, 0u);
+ }
+ // 3. Set controller.[[stream]] to stream.
+ controller->controlled_readable_stream_ = stream;
+ // 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false.
+ DCHECK(!controller->pull_again_);
+ DCHECK(!controller->pulling_);
+ // 5. Set controller.[[byobRequest]] to null.
+ DCHECK(!controller->byob_request_);
+ // 6. Perform ! ResetQueue(controller).
+ ResetQueue(controller);
+ // 7. Set controller.[[closeRequested]] and controller.[[started]] to false.
+ DCHECK(!controller->close_requested_);
+ DCHECK(!controller->started_);
+ // 8. Set controller.[[strategyHWM]] to highWaterMark.
+ controller->strategy_high_water_mark_ = high_water_mark;
+ // 9. Set controller.[[pullAlgorithm]] to pullAlgorithm.
+ controller->pull_algorithm_ = pull_algorithm;
+ // 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
+ controller->cancel_algorithm_ = cancel_algorithm;
+ // 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.
+ controller->auto_allocate_chunk_size_ = auto_allocate_chunk_size;
+ // 12. Set controller.[[pendingPullIntos]] to a new empty list.
+ DCHECK(controller->pending_pull_intos_.IsEmpty());
+ // 13. Set stream.[[controller]] to controller.
+ stream->readable_stream_controller_ = controller;
+ // 14. Let startResult be the result of performing startAlgorithm.
+ // 15. Let startPromise be a promise resolved with startResult.
+ // The conversion of startResult to a promise happens inside start_algorithm
+ // in this implementation.
+ v8::Local<v8::Promise> start_promise;
+ if (!start_algorithm->Run(script_state, exception_state)
+ .ToLocal(&start_promise)) {
+ if (!exception_state.HadException()) {
+ exception_state.ThrowException(
+ static_cast<int>(DOMExceptionCode::kInvalidStateError),
+ "start algorithm failed with no exception thrown");
+ }
+ return;
+ }
+ DCHECK(!exception_state.HadException());
+
+ class ResolveFunction final : public PromiseHandler {
+ public:
+ ResolveFunction(ScriptState* script_state,
+ ReadableByteStreamController* controller)
+ : PromiseHandler(script_state), controller_(controller) {}
+
+ void CallWithLocal(v8::Local<v8::Value>) override {
+ // 16. Upon fulfillment of startPromise,
+ // a. Set controller.[[started]] to true.
+ controller_->started_ = true;
+ // b. Assert: controller.[[pulling]] is false.
+ DCHECK(!controller_->pulling_);
+ // c. Assert: controller.[[pullAgain]] is false.
+ DCHECK(!controller_->pull_again_);
+ // d. Perform !
+ // ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(GetScriptState(), controller_);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(controller_);
+ PromiseHandler::Trace(visitor);
+ }
+
+ private:
+ const Member<ReadableByteStreamController> controller_;
+ };
+
+ class RejectFunction final : public PromiseHandler {
+ public:
+ RejectFunction(ScriptState* script_state,
+ ReadableByteStreamController* controller)
+ : PromiseHandler(script_state), controller_(controller) {}
+
+ void CallWithLocal(v8::Local<v8::Value> r) override {
+ // 17. Upon rejection of startPromise with reason r,
+ // a. Perform ! ReadableByteStreamControllerError(controller, r).
+ Error(GetScriptState(), controller_, r);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(controller_);
+ PromiseHandler::Trace(visitor);
+ }
+
+ private:
+ const Member<ReadableByteStreamController> controller_;
+ };
+
+ StreamThenPromise(
+ script_state->GetContext(), start_promise,
+ MakeGarbageCollected<ResolveFunction>(script_state, controller),
+ MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+void ReadableByteStreamController::SetUpFromUnderlyingSource(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ v8::Local<v8::Object> underlying_source,
+ UnderlyingSource* underlying_source_dict,
+ double high_water_mark,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
+ // 1. Let controller be a new ReadableByteStreamController.
+ ReadableByteStreamController* controller =
+ MakeGarbageCollected<ReadableByteStreamController>();
+ // 2. Let startAlgorithm be an algorithm that returns undefined.
+ StreamStartAlgorithm* start_algorithm = CreateTrivialStartAlgorithm();
+ // 3. Let pullAlgorithm be an algorithm that returns a promise resolved with
+ // undefined.
+ StreamAlgorithm* pull_algorithm = CreateTrivialStreamAlgorithm();
+ // 4. Let cancelAlgorithm be an algorithm that returns a promise resolved with
+ // undefined.
+ StreamAlgorithm* cancel_algorithm = CreateTrivialStreamAlgorithm();
+
+ const auto controller_value = ToV8(controller, script_state);
+ // 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an
+ // algorithm which returns the result of invoking
+ // underlyingSourceDict["start"] with argument list « controller » and
+ // callback this value underlyingSource.
+ if (underlying_source_dict->hasStart()) {
+ start_algorithm = CreateByteStreamStartAlgorithm(
+ script_state, underlying_source,
+ ToV8(underlying_source_dict->start(), script_state), controller_value);
+ }
+ // 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an
+ // algorithm which returns the result of invoking underlyingSourceDict["pull"]
+ // with argument list « controller » and callback this value underlyingSource.
+ if (underlying_source_dict->hasPull()) {
+ pull_algorithm = CreateAlgorithmFromResolvedMethod(
+ script_state, underlying_source,
+ ToV8(underlying_source_dict->pull(), script_state), controller_value);
+ }
+ // 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an
+ // algorithm which takes an argument reason and returns the result of invoking
+ // underlyingSourceDict["cancel"] with argument list « reason » and callback
+ // this value underlyingSource.
+ if (underlying_source_dict->hasCancel()) {
+ cancel_algorithm = CreateAlgorithmFromResolvedMethod(
+ script_state, underlying_source,
+ ToV8(underlying_source_dict->cancel(), script_state), controller_value);
+ }
+ // 8. Let autoAllocateChunkSize be
+ // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined
+ // otherwise.
+ size_t auto_allocate_chunk_size =
+ underlying_source_dict->hasAutoAllocateChunkSize()
+ ? static_cast<size_t>(underlying_source_dict->autoAllocateChunkSize())
+ : 0u;
+ // 9. If autoAllocateChunkSize is 0, then throw a TypeError exception.
+ if (underlying_source_dict->hasAutoAllocateChunkSize() &&
+ auto_allocate_chunk_size == 0) {
+ exception_state.ThrowTypeError("autoAllocateChunkSize cannot be 0");
+ return;
+ }
+ // 10. Perform ? SetUpReadableByteStreamController(stream, controller,
+ // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
+ // autoAllocateChunkSize).
+ SetUp(script_state, stream, controller, start_algorithm, pull_algorithm,
+ cancel_algorithm, high_water_mark, auto_allocate_chunk_size,
+ exception_state);
+}
+
+void ReadableByteStreamController::FillHeadPullIntoDescriptor(
+ ReadableByteStreamController* controller,
+ size_t size,
+ PullIntoDescriptor* pull_into_descriptor) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
+ // 1. Assert: either controller.[[pendingPullIntos]] is empty, or
+ // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
+ DCHECK(controller->pending_pull_intos_.IsEmpty() ||
+ controller->pending_pull_intos_[0] == pull_into_descriptor);
+ // 2. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+ InvalidateBYOBRequest(controller);
+ // 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
+ pull_into_descriptor->bytes_filled =
+ base::CheckAdd(pull_into_descriptor->bytes_filled, size).ValueOrDie();
+}
+
+bool ReadableByteStreamController::FillPullIntoDescriptorFromQueue(
+ ReadableByteStreamController* controller,
+ PullIntoDescriptor* pull_into_descriptor) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
+ // 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
+ const size_t element_size = pull_into_descriptor->element_size;
+ // 2. Let currentAlignedBytes be pullIntoDescriptor's bytes filled −
+ // (pullIntoDescriptor's bytes filled mod elementSize).
+ const size_t current_aligned_bytes =
+ pull_into_descriptor->bytes_filled -
+ (pull_into_descriptor->bytes_filled % element_size);
+ // 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
+ // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
+ // The subtraction will not underflow because bytes length will always be more
+ // than or equal to bytes filled.
+ const size_t max_bytes_to_copy = std::min(
+ static_cast<size_t>(controller->queue_total_size_),
+ pull_into_descriptor->byte_length - pull_into_descriptor->bytes_filled);
+ // 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
+ // maxBytesToCopy.
+ // This addition will not overflow because maxBytesToCopy can be at most
+ // queue_total_size_. Both bytes_filled and queue_total_size_ refer to
+ // actually allocated memory, so together they cannot exceed size_t.
+ const size_t max_bytes_filled =
+ pull_into_descriptor->bytes_filled + max_bytes_to_copy;
+ // 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod
+ // elementSize).
+ // This subtraction will not underflow because the modulus operator is
+ // guaranteed to return a value less than or equal to the first argument.
+ const size_t max_aligned_bytes =
+ max_bytes_filled - (max_bytes_filled % element_size);
+ // 6. Let totalBytesToCopyRemaining be maxBytesToCopy.
+ size_t total_bytes_to_copy_remaining = max_bytes_to_copy;
+ // 7. Let ready be false;
+ bool ready = false;
+ // 8. If maxAlignedBytes > currentAlignedBytes,
+ if (max_aligned_bytes > current_aligned_bytes) {
+ // a. Set totalBytesToCopyRemaining to maxAlignedBytes −
+ // pullIntoDescriptor’s bytes filled.
+ total_bytes_to_copy_remaining =
+ base::CheckSub(max_aligned_bytes, pull_into_descriptor->bytes_filled)
+ .ValueOrDie();
+ // b. Set ready to true.
+ ready = true;
+ }
+ // 9. Let queue be controller.[[queue]].
+ HeapDeque<Member<QueueEntry>>& queue = controller->queue_;
+ // 10. While totalBytesToCopyRemaining > 0,
+ while (total_bytes_to_copy_remaining > 0) {
+ // a. Let headOfQueue be queue[0].
+ QueueEntry* head_of_queue = queue[0];
+ // b. Let bytesToCopy be min(totalBytesToCopyRemaining,
+ // headOfQueue’s byte length).
+ size_t bytes_to_copy =
+ std::min(total_bytes_to_copy_remaining, head_of_queue->byte_length);
+ // c. Let destStart be pullIntoDescriptor’s byte offset +
+ // pullIntoDescriptor’s bytes filled.
+ // This addition will not overflow because byte offset and bytes filled
+ // refer to actually allocated memory, so together they cannot exceed
+ // size_t.
+ size_t dest_start =
+ pull_into_descriptor->byte_offset + pull_into_descriptor->bytes_filled;
+ // d. Perform ! CopyDataBlockBytes(pullIntoDescriptor’s
+ // buffer.[[ArrayBufferData]], destStart, headOfQueue’s
+ // buffer.[[ArrayBufferData]], headOfQueue’s byte offset, bytesToCopy).
+ memcpy(
+ static_cast<char*>(pull_into_descriptor->buffer->Data()) + dest_start,
+ static_cast<char*>(head_of_queue->buffer->Data()) +
+ head_of_queue->byte_offset,
+ bytes_to_copy);
+ // e. If headOfQueue’s byte length is bytesToCopy,
+ if (head_of_queue->byte_length == bytes_to_copy) {
+ // i. Remove queue[0].
+ queue.pop_front();
+ } else {
+ // f. Otherwise,
+ // i. Set headOfQueue’s byte offset to headOfQueue’s byte offset +
+ // bytesToCopy.
+ head_of_queue->byte_offset =
+ base::CheckAdd(head_of_queue->byte_offset, bytes_to_copy)
+ .ValueOrDie();
+ // ii. Set headOfQueue’s byte length to headOfQueue’s byte
+ // length − bytesToCopy.
+ head_of_queue->byte_length =
+ base::CheckSub(head_of_queue->byte_length, bytes_to_copy)
+ .ValueOrDie();
+ }
+ // g. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] −
+ // bytesToCopy.
+ controller->queue_total_size_ =
+ base::CheckSub(controller->queue_total_size_, bytes_to_copy)
+ .ValueOrDie();
+ // h. Perform !
+ // ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
+ // bytesToCopy, pullIntoDescriptor).
+ FillHeadPullIntoDescriptor(controller, bytes_to_copy, pull_into_descriptor);
+ // i. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining −
+ // bytesToCopy.
+ // This subtraction will not underflow because bytes_to_copy will always be
+ // greater than or equal to total_bytes_to_copy_remaining.
+ total_bytes_to_copy_remaining -= bytes_to_copy;
+ }
+ // 11. If ready is false,
+ if (!ready) {
+ // a. Assert: controller.[[queueTotalSize]] is 0.
+ DCHECK_EQ(controller->queue_total_size_, 0u);
+ // b. Assert: pullIntoDescriptor’s bytes filled > 0.
+ DCHECK_GT(pull_into_descriptor->bytes_filled, 0.0);
+ // c. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s
+ // element size.
+ DCHECK_LT(pull_into_descriptor->bytes_filled,
+ pull_into_descriptor->element_size);
+ }
+ // 12. Return ready.
+ return ready;
+}
+
+void ReadableByteStreamController::PullInto(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ NotShared<DOMArrayBufferView> view,
+ ReadableStreamBYOBReader::ReadIntoRequest* read_into_request,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
+ // 1. Let stream be controller.[[stream]].
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+ // 2. Let elementSize be 1.
+ size_t element_size = 1;
+ // 3. Let ctor be %DataView%.
+ auto* ctor = &CreateAsArrayBufferView<DOMDataView>;
+ // 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a
+ // DataView),
+ if (view->GetType() != DOMArrayBufferView::kTypeDataView) {
+ // a. Set elementSize to be the element size specified in the typed array
+ // constructors table for view.[[TypedArrayName]].
+ element_size = view->TypeSize();
+ // b. Set ctor to the constructor specified in the typed array
+ // constructors table for view.[[TypedArrayName]].
+ switch (view->GetType()) {
+ case DOMArrayBufferView::kTypeInt8:
+ ctor = &CreateAsArrayBufferView<DOMInt8Array>;
+ break;
+ case DOMArrayBufferView::kTypeUint8:
+ ctor = &CreateAsArrayBufferView<DOMUint8Array>;
+ break;
+ case DOMArrayBufferView::kTypeUint8Clamped:
+ ctor = &CreateAsArrayBufferView<DOMUint8ClampedArray>;
+ break;
+ case DOMArrayBufferView::kTypeInt16:
+ ctor = &CreateAsArrayBufferView<DOMInt16Array>;
+ break;
+ case DOMArrayBufferView::kTypeUint16:
+ ctor = &CreateAsArrayBufferView<DOMUint16Array>;
+ break;
+ case DOMArrayBufferView::kTypeInt32:
+ ctor = &CreateAsArrayBufferView<DOMInt32Array>;
+ break;
+ case DOMArrayBufferView::kTypeUint32:
+ ctor = &CreateAsArrayBufferView<DOMUint32Array>;
+ break;
+ case DOMArrayBufferView::kTypeFloat32:
+ ctor = &CreateAsArrayBufferView<DOMFloat32Array>;
+ break;
+ case DOMArrayBufferView::kTypeFloat64:
+ ctor = &CreateAsArrayBufferView<DOMFloat64Array>;
+ break;
+ case DOMArrayBufferView::kTypeBigInt64:
+ ctor = &CreateAsArrayBufferView<DOMBigInt64Array>;
+ break;
+ case DOMArrayBufferView::kTypeBigUint64:
+ ctor = &CreateAsArrayBufferView<DOMBigUint64Array>;
+ break;
+ case DOMArrayBufferView::kTypeDataView:
+ NOTREACHED();
+ }
+ }
+ // 5. Let byteOffset be view.[[ByteOffset]].
+ const size_t byte_offset = view->byteOffset();
+ // 6. Let byteLength be view.[[ByteLength]].
+ const size_t byte_length = view->byteLength();
+ // 7. Let buffer be ! TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
+ DOMArrayBuffer* buffer =
+ TransferArrayBuffer(script_state, view->buffer(), exception_state);
+ // 8. Let pullIntoDescriptor be a new pull-into descriptor with buffer buffer,
+ // byte offset byteOffset, byte length byteLength, bytes filled 0, element
+ // size elementSize, view construcot ctor, and reader type "byob".
+ PullIntoDescriptor* pull_into_descriptor =
+ MakeGarbageCollected<PullIntoDescriptor>(buffer, byte_offset, byte_length,
+ 0, element_size, ctor,
+ ReaderType::kBYOB);
+ // 9. If controller.[[pendingPullIntos]] is not empty,
+ if (!controller->pending_pull_intos_.IsEmpty()) {
+ // a. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
+ controller->pending_pull_intos_.push_back(pull_into_descriptor);
+ // b. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
+ ReadableStream::AddReadIntoRequest(script_state, stream, read_into_request);
+ // c. Return.
+ return;
+ }
+ // 10. If stream.[[state]] is "closed",
+ if (stream->state_ == ReadableStream::kClosed) {
+ // a. Let emptyView be ! Construct(ctor, « pullIntoDescriptor’s buffer,
+ // pullIntoDescriptor’s byte offset, 0 »).
+ DOMArrayBufferView* emptyView = ctor(pull_into_descriptor->buffer,
+ pull_into_descriptor->byte_offset, 0);
+ // b. Perform readIntoRequest’s close steps, given emptyView.
+ read_into_request->CloseSteps(script_state, emptyView);
+ // c. Return.
+ return;
+ }
+ // 11. If controller.[[queueTotalSize]] > 0,
+ if (controller->queue_total_size_ > 0) {
+ // a. If !
+ // ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
+ // pullIntoDescriptor) is true,
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ // i. Let filledView be !
+ // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
+ DOMArrayBufferView* filled_view =
+ ConvertPullIntoDescriptor(pull_into_descriptor);
+ // ii. Perform !
+ // ReadableByteStreamControllerHandleQueueDrain(controller).
+ HandleQueueDrain(script_state, controller);
+ // iii. Perform readIntoRequest’s chunk steps, given filledView.
+ read_into_request->ChunkSteps(script_state, filled_view);
+ // iv. Return.
+ return;
+ }
+ // b. If controller.[[closeRequested]] is true,
+ if (controller->close_requested_) {
+ // i. Let e be a TypeError exception.
+ v8::Local<v8::Value> e = V8ThrowException::CreateTypeError(
+ script_state->GetIsolate(), "close requested");
+ // ii. Perform ! ReadableByteStreamControllerError(controller, e).
+ controller->Error(script_state, controller, e);
+ // iii. Perform readIntoRequest’s error steps, given e.
+ read_into_request->ErrorSteps(script_state, e);
+ // iv. Return.
+ return;
+ }
+ }
+ // 12. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
+ controller->pending_pull_intos_.push_back(pull_into_descriptor);
+ // 13. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
+ ReadableStream::AddReadIntoRequest(script_state, stream, read_into_request);
+ // 14. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::HandleQueueDrain(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
+ // 1. Assert: controller.[[stream]].[[state]] is "readable".
+ DCHECK_EQ(controller->controlled_readable_stream_->state_,
+ ReadableStream::kReadable);
+ // 2. If controller.[[queueTotalSize]] is 0 and controller.[[closeRequested]]
+ // is true,
+ if (!controller->queue_total_size_ && controller->close_requested_) {
+ // a. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+ ClearAlgorithms(controller);
+ // b. Perform ! ReadableStreamClose(controller.[[stream]]).
+ ReadableStream::Close(script_state,
+ controller->controlled_readable_stream_);
+ } else {
+ // 3. Otherwise,
+ // a. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(script_state, controller);
+ }
+}
+
+void ReadableByteStreamController::ResetQueue(
+ ReadableByteStreamController* controller) {
+ // https://streams.spec.whatwg.org/#reset-queue
+ // 1. Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
+ // 2. Set container.[[queue]] to a new empty list.
+ controller->queue_.clear();
+ // 3. Set container.[[queueTotalSize]] to 0.
+ controller->queue_total_size_ = 0;
+}
+
+void ReadableByteStreamController::Respond(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ size_t bytes_written,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
+ // 1. Assert: controller.[[pendingPullIntos]] is not empty.
+ DCHECK(!controller->pending_pull_intos_.IsEmpty());
+ // 2. Perform ? ReadableByteStreamControllerRespondInternal(controller,
+ // bytesWritten).
+ RespondInternal(script_state, controller, bytes_written, exception_state);
+}
+
+void ReadableByteStreamController::RespondInClosedState(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ PullIntoDescriptor* first_descriptor,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
+ // 1. Set firstDescriptor’s buffer to ! TransferArrayBuffer(firstDescriptor’s
+ // buffer).
+ first_descriptor->buffer = TransferArrayBuffer(
+ script_state, first_descriptor->buffer, exception_state);
+ // 2. Assert: firstDescriptor’s bytes filled is 0.
+ DCHECK_EQ(first_descriptor->bytes_filled, 0u);
+ // 3. Let stream be controller.[[stream]].
+ ReadableStream* const stream = controller->controlled_readable_stream_;
+ // 4. If ! ReadableStreamHasBYOBReader(stream) is true,
+ if (ReadableStream::HasBYOBReader(stream)) {
+ // a. While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
+ while (ReadableStream::GetNumReadIntoRequests(stream) > 0) {
+ // i. Let pullIntoDescriptor be !
+ // ReadableByteStreamControllerShiftPendingPullInto(controller).
+ PullIntoDescriptor* pull_into_descriptor =
+ ShiftPendingPullInto(controller);
+ // ii. Perform !
+ // ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
+ // pullIntoDescriptor).
+ CommitPullIntoDescriptor(script_state, stream, pull_into_descriptor);
+ }
+ }
+}
+
+void ReadableByteStreamController::RespondInReadableState(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ size_t bytes_written,
+ PullIntoDescriptor* pull_into_descriptor,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
+ // 1. If pullIntoDescriptor’s bytes filled + bytesWritten >
+ // pullIntoDescriptor’s byte length, throw a RangeError exception.
+ if (base::ClampAdd(pull_into_descriptor->bytes_filled, bytes_written) >
+ pull_into_descriptor->byte_length) {
+ exception_state.ThrowRangeError(
+ "Cannot respond because buffer will overflow if written to");
+ return;
+ }
+ // 2. Perform !
+ // ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
+ // bytesWritten, pullIntoDescriptor).
+ FillHeadPullIntoDescriptor(controller, bytes_written, pull_into_descriptor);
+ // 3. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element
+ // size, return.
+ if (pull_into_descriptor->bytes_filled < pull_into_descriptor->element_size) {
+ return;
+ }
+ // 4. Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
+ ShiftPendingPullInto(controller);
+ // 5. Let remainderSize be pullIntoDescriptor’s bytes filled mod
+ // pullIntoDescriptor’s element size.
+ const size_t remainder_size =
+ pull_into_descriptor->bytes_filled % pull_into_descriptor->element_size;
+ // 6. If remainderSize > 0,
+ if (remainder_size > 0) {
+ // a. Let end be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s
+ // bytes filled.
+ // This addition will not overflow because byte offset and bytes filled
+ // refer to actually allocated memory, so together they cannot exceed
+ // size_t.
+ size_t end =
+ pull_into_descriptor->byte_offset + pull_into_descriptor->bytes_filled;
+ // b. Let remainder be ? CloneArrayBuffer(pullIntoDescriptor’s
+ // buffer, end − remainderSize, remainderSize, %ArrayBuffer%).
+ DOMArrayBuffer* const remainder = DOMArrayBuffer::Create(
+ static_cast<char*>(pull_into_descriptor->buffer->Data()) + end -
+ remainder_size,
+ remainder_size);
+ // c. Perform !
+ // ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder,
+ // 0, remainder.[[ByteLength]]).
+ EnqueueChunkToQueue(controller, remainder, 0, remainder->ByteLength());
+ }
+ // 7. Set pullIntoDescriptor’s buffer to !
+ // TransferArrayBuffer(pullIntoDescriptor’s buffer).
+ pull_into_descriptor->buffer = TransferArrayBuffer(
+ script_state, pull_into_descriptor->buffer, exception_state);
+ // 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes
+ // filled − remainderSize.
+ pull_into_descriptor->bytes_filled =
+ pull_into_descriptor->bytes_filled - remainder_size;
+ // 9. Perform !
+ // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
+ // pullIntoDescriptor).
+ CommitPullIntoDescriptor(script_state,
+ controller->controlled_readable_stream_,
+ pull_into_descriptor);
+ // 10. Perform !
+ // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
+ ProcessPullIntoDescriptorsUsingQueue(script_state, controller);
+}
+
+void ReadableByteStreamController::RespondInternal(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ size_t bytes_written,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
+ // 1. Let firstDescriptor be controller.[[pendingPullIntos]][0].
+ PullIntoDescriptor* const first_descriptor =
+ controller->pending_pull_intos_[0];
+ // 2. Let state be controller.[[stream]].[[state]].
+ const ReadableStream::State state =
+ controller->controlled_readable_stream_->state_;
+ // 3. If state is "closed",
+ if (state == ReadableStream::kClosed) {
+ // a. If bytesWritten is not 0, throw a TypeError exception.
+ if (bytes_written != 0) {
+ exception_state.ThrowTypeError("bytes written is not 0");
+ return;
+ }
+ // b. Perform !
+ // ReadableByteStreamControllerRespondInClosedState(controller,
+ // firstDescriptor).
+ RespondInClosedState(script_state, controller, first_descriptor,
+ exception_state);
+ } else {
+ // 4. Otherwise,
+ // a. Assert: state is "readable".
+ DCHECK_EQ(state, ReadableStream::kReadable);
+ // b. Perform ?
+ // ReadableByteStreamControllerRespondInReadableState(controller,
+ // bytesWritten, firstDescriptor).
+ RespondInReadableState(script_state, controller, bytes_written,
+ first_descriptor, exception_state);
+ }
+ // 5. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+ CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::RespondWithNewView(
+ ScriptState* script_state,
+ ReadableByteStreamController* controller,
+ NotShared<DOMArrayBufferView> view,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
+ // 1. Assert: controller.[[pendingPullIntos]] is not empty.
+ DCHECK(!controller->pending_pull_intos_.IsEmpty());
+ // 2. Let firstDescriptor be controller.[[pendingPullIntos]][0].
+ PullIntoDescriptor* first_descriptor = controller->pending_pull_intos_[0];
+ // 3. If firstDescriptor’s byte offset + firstDescriptor’ bytes filled is not
+ // view.[[ByteOffset]], throw a RangeError exception.
+ // We don't expect this addition to overflow as the bytes are expected to be
+ // equal.
+ if (first_descriptor->byte_offset + first_descriptor->bytes_filled !=
+ view->byteOffset()) {
+ exception_state.ThrowRangeError(
+ "First descriptor's byte offset and bytes filled is not the same as "
+ "the view's byte offset");
+ return;
+ }
+ // 4. If firstDescriptor’s byte length is not view.[[ByteLength]], throw a
+ // RangeError exception.
+ if (first_descriptor->byte_length != view->byteLength()) {
+ exception_state.ThrowRangeError("byte lengths are not equal");
+ return;
+ }
+ // 5. Set firstDescriptor’s buffer to view.[[ViewedArrayBuffer]].
+ first_descriptor->buffer = view->buffer();
+ // 6. Perform ? ReadableByteStreamControllerRespondInternal(controller,
+ // view.[[ByteLength]]).
+ RespondInternal(script_state, controller, view->byteLength(),
+ exception_state);
+}
+
+DOMArrayBuffer* ReadableByteStreamController::TransferArrayBuffer(
+ ScriptState* script_state,
+ DOMArrayBuffer* buffer,
+ ExceptionState& exception_state) {
+ ArrayBufferContents contents;
+ if (buffer->IsDetachable(script_state->GetIsolate()) &&
+ buffer->Transfer(script_state->GetIsolate(), contents)) {
+ return DOMArrayBuffer::Create(std::move(contents));
+ }
+ exception_state.ThrowTypeError("not able to transfer array buffer");
+ return nullptr;
+}
+
+void ReadableByteStreamController::Trace(Visitor* visitor) const {
+ visitor->Trace(byob_request_);
+ visitor->Trace(cancel_algorithm_);
+ visitor->Trace(controlled_readable_stream_);
+ visitor->Trace(pending_pull_intos_);
+ visitor->Trace(pull_algorithm_);
+ visitor->Trace(queue_);
+ ScriptWrappable::Trace(visitor);
}
//
@@ -58,25 +1316,95 @@ void ReadableByteStreamController::error(ScriptState* script_state,
v8::Local<v8::Promise> ReadableByteStreamController::CancelSteps(
ScriptState* script_state,
v8::Local<v8::Value> reason) {
- ExceptionState exception_state(script_state->GetIsolate(),
- ExceptionState::kExecutionContext, nullptr,
- nullptr);
- ThrowUnimplemented(exception_state);
- return v8::Local<v8::Promise>();
+ // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
+ // 1. If this.[[pendingPullIntos]] is not empty,
+ if (!pending_pull_intos_.IsEmpty()) {
+ // a. Let firstDescriptor be this.[[pendingPullIntos]][0].
+ PullIntoDescriptor* first_descriptor = pending_pull_intos_[0];
+ // b. Set firstDescriptor’s bytes filled to 0.
+ first_descriptor->bytes_filled = 0;
+ }
+ // 2. Perform ! ResetQueue(this).
+ ResetQueue(this);
+ // 3. Let result be the result of performing this.[[cancelAlgorithm]], passing
+ // in reason.
+ auto result = cancel_algorithm_->Run(script_state, 1, &reason);
+ // 4. Perform ! ReadableByteStreamControllerClearAlgorithms(this).
+ ClearAlgorithms(this);
+ // 5. Return result.
+ return result;
}
StreamPromiseResolver* ReadableByteStreamController::PullSteps(
ScriptState* script_state) {
- ExceptionState exception_state(script_state->GetIsolate(),
- ExceptionState::kExecutionContext, nullptr,
- nullptr);
- ThrowUnimplemented(exception_state);
- return nullptr;
-}
+ // https://whatpr.org/streams/1029.html#rbs-controller-private-pull
+ // TODO: This function follows an old version of the spec referenced above, so
+ // it needs to be updated to the new version on
+ // https://streams.spec.whatwg.org when the ReadableStreamDefaultReader
+ // implementation is updated.
+ // 1. Let stream be this.[[controlledReadableByteStream]].
+ ReadableStream* const stream = controlled_readable_stream_;
+ // 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
+ DCHECK(ReadableStream::HasDefaultReader(stream));
+ // 3. If this.[[queueTotalSize]] > 0,
+ if (queue_total_size_ > 0) {
+ // a. Assert: ! ReadableStreamGetNumReadRequests(stream) is 0.
+ DCHECK_EQ(ReadableStream::GetNumReadRequests(stream), 0);
+ // b. Let entry be the first element of this.[[queue]].
+ QueueEntry* entry = queue_[0];
+ // c. Remove entry from this.[[queue]], shifting all other elements
+ // downward (so that the second becomes the first, and so on).
+ queue_.pop_front();
+ // d. Set this.[[queueTotalSize]] to this.[[queueTotalSize]] −
+ // entry.[[byteLength]].
+ queue_total_size_ -= entry->byte_length;
+ // e. Perform ! ReadableByteStreamControllerHandleQueueDrain(this).
+ HandleQueueDrain(script_state, this);
+ // f. Let view be ! Construct(%Uint8Array%, « entry.[[buffer]],
+ // entry.[[byteOffset]], entry.[[byteLength]] »).
+ DOMUint8Array* view = DOMUint8Array::Create(
+ entry->buffer, entry->byte_offset, entry->byte_length);
+ // g. Return a promise resolved with !
+ // ReadableStreamCreateReadResult(view, false,
+ // stream.[[reader]].[[forAuthorCode]]).
+ ReadableStreamGenericReader* reader = stream->reader_;
+ return StreamPromiseResolver::CreateResolved(
+ script_state,
+ ReadableStream::CreateReadResult(
+ script_state, ToV8(view, script_state), false,
+ To<ReadableStreamDefaultReader>(reader)->for_author_code_));
+ }
+ // 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
+ const size_t auto_allocate_chunk_size = auto_allocate_chunk_size_;
+ // 5. If autoAllocateChunkSize is not undefined,
+ if (auto_allocate_chunk_size) {
+ // a. Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize »).
+ auto* buffer = DOMArrayBuffer::Create(auto_allocate_chunk_size, 1);
+ // b. If buffer is an abrupt completion, return a promise rejected with
+ // buffer.[[Value]].
+ // This is not needed as DOMArrayBuffer::Create() is designed to
+ // crash if it cannot allocate the memory.
-void ReadableByteStreamController::ThrowUnimplemented(
- ExceptionState& exception_state) {
- exception_state.ThrowTypeError("unimplemented");
+ // c. Let pullIntoDescriptor be Record {[[buffer]]: buffer.[[Value]],
+ // [[byteOffset]]: 0, [[byteLength]]: autoAllocateChunkSize,
+ // [[bytesFilled]]: 0, [[elementSize]]: 1, [[ctor]]: %Uint8Array%,
+ // [[readerType]]: "default"}.
+ auto* ctor = &CreateAsArrayBufferView<DOMUint8Array>;
+ PullIntoDescriptor* pull_into_descriptor =
+ MakeGarbageCollected<PullIntoDescriptor>(buffer, 0,
+ auto_allocate_chunk_size, 0, 1,
+ ctor, ReaderType::kDefault);
+ // d. Append pullIntoDescriptor as the last element of
+ // this.[[pendingPullIntos]].
+ pending_pull_intos_.push_back(pull_into_descriptor);
+ }
+ // 6. Let promise be ! ReadableStreamAddReadRequest(stream).
+ StreamPromiseResolver* promise =
+ ReadableStream::AddReadRequest(script_state, stream);
+ // 7. Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
+ CallPullIfNeeded(script_state, this);
+ // 8. Return promise.
+ return promise;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
index 348a6a24eac..faf5fa3d249 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -1,4 +1,4 @@
-// Copyright 2020 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.
@@ -7,28 +7,40 @@
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "v8/include/v8.h"
namespace blink {
+class DOMArrayBuffer;
class DOMArrayBufferView;
class ExceptionState;
+class ReadableStream;
class ReadableStreamBYOBRequest;
class ScriptState;
+class StreamAlgorithm;
+class StreamStartAlgorithm;
class StreamPromiseResolver;
+class UnderlyingSource;
class ReadableByteStreamController : public ReadableStreamController {
DEFINE_WRAPPERTYPEINFO();
public:
+ ReadableByteStreamController();
+
// https://streams.spec.whatwg.org/#rbs-controller-byob-request
- ReadableStreamBYOBRequest* byobRequest(ExceptionState&) const;
+ ReadableStreamBYOBRequest* byobRequest();
// https://streams.spec.whatwg.org/#rbs-controller-desired-size
- base::Optional<double> desiredSize(ExceptionState&) const;
+ base::Optional<double> desiredSize();
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
+ static base::Optional<double> GetDesiredSize(ReadableByteStreamController*);
// https://streams.spec.whatwg.org/#rbs-controller-close
void close(ScriptState*, ExceptionState&);
@@ -39,8 +51,192 @@ class ReadableByteStreamController : public ReadableStreamController {
ExceptionState&);
// https://streams.spec.whatwg.org/#rbs-controller-error
- void error(ScriptState*, ExceptionState&);
- void error(ScriptState*, ScriptValue e, ExceptionState&);
+ void error(ScriptState*);
+ void error(ScriptState*, const ScriptValue& e);
+
+ bool IsByteStreamController() const override { return true; }
+ bool IsDefaultController() const override { return false; }
+
+ void Trace(Visitor*) const override;
+
+ private:
+ friend class ReadableStream;
+ friend class ReadableStreamBYOBReader;
+ friend class ReadableStreamBYOBRequest;
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry
+ struct QueueEntry final : public GarbageCollected<QueueEntry> {
+ explicit QueueEntry(DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t byte_length);
+
+ const Member<DOMArrayBuffer> buffer;
+ size_t byte_offset;
+ size_t byte_length;
+
+ void Trace(Visitor*) const;
+ };
+
+ enum class ReaderType { kDefault, kBYOB };
+
+ // https://streams.spec.whatwg.org/#pull-into-descriptor
+ struct PullIntoDescriptor final
+ : public GarbageCollected<PullIntoDescriptor> {
+ // A function pointer is used to represent the view constructor
+ // to accommodate for different array types as specified by the
+ // ArrayBufferViewConstructorAdaptor.
+ using ViewConstructorType = DOMArrayBufferView* (*)(DOMArrayBuffer*,
+ size_t,
+ size_t);
+
+ explicit PullIntoDescriptor(DOMArrayBuffer* buffer,
+ size_t byte_offset,
+ size_t byte_length,
+ size_t bytes_filled,
+ size_t element_size,
+ ViewConstructorType view_constructor,
+ ReaderType reader_type);
+
+ Member<DOMArrayBuffer> buffer;
+ size_t byte_offset;
+ const size_t byte_length;
+ size_t bytes_filled;
+ const size_t element_size;
+ const ViewConstructorType view_constructor;
+ const ReaderType reader_type;
+
+ void Trace(Visitor*) const;
+ };
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
+ void Close(ScriptState*, ReadableByteStreamController*, ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
+ static void Error(ScriptState*,
+ ReadableByteStreamController*,
+ v8::Local<v8::Value> e);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
+ void Enqueue(ScriptState*,
+ ReadableByteStreamController*,
+ NotShared<DOMArrayBufferView> chunk,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
+ static void EnqueueChunkToQueue(ReadableByteStreamController*,
+ DOMArrayBuffer*,
+ size_t byte_offset,
+ size_t byte_length);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
+ static void ProcessPullIntoDescriptorsUsingQueue(
+ ScriptState*,
+ ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
+ static void CallPullIfNeeded(ScriptState*, ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
+ static PullIntoDescriptor* ShiftPendingPullInto(
+ ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
+ static bool ShouldCallPull(ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
+ static void CommitPullIntoDescriptor(ScriptState*,
+ ReadableStream*,
+ PullIntoDescriptor*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
+ static DOMArrayBufferView* ConvertPullIntoDescriptor(PullIntoDescriptor*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
+ static void ClearPendingPullIntos(ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
+ static void ClearAlgorithms(ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
+ static void InvalidateBYOBRequest(ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
+ static void SetUp(ScriptState*,
+ ReadableStream*,
+ ReadableByteStreamController*,
+ StreamStartAlgorithm* start_algorithm,
+ StreamAlgorithm* pull_algorithm,
+ StreamAlgorithm* cancel_algorithm,
+ double high_water_mark,
+ size_t auto_allocate_chunk_size,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
+ static void SetUpFromUnderlyingSource(
+ ScriptState*,
+ ReadableStream*,
+ v8::Local<v8::Object> underlying_source,
+ UnderlyingSource* underlying_source_dict,
+ double high_water_mark,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
+ static void FillHeadPullIntoDescriptor(ReadableByteStreamController*,
+ size_t size,
+ PullIntoDescriptor*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
+ static bool FillPullIntoDescriptorFromQueue(ReadableByteStreamController*,
+ PullIntoDescriptor*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
+ static void PullInto(ScriptState*,
+ ReadableByteStreamController*,
+ NotShared<DOMArrayBufferView> view,
+ ReadableStreamBYOBReader::ReadIntoRequest*,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
+ static void HandleQueueDrain(ScriptState*, ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#reset-queue
+ static void ResetQueue(ReadableByteStreamController*);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
+ static void Respond(ScriptState*,
+ ReadableByteStreamController*,
+ size_t bytes_written,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
+ static void RespondInClosedState(ScriptState*,
+ ReadableByteStreamController*,
+ PullIntoDescriptor* first_descriptor,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
+ static void RespondInReadableState(ScriptState*,
+ ReadableByteStreamController*,
+ size_t bytes_written,
+ PullIntoDescriptor*,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
+ static void RespondInternal(ScriptState*,
+ ReadableByteStreamController*,
+ size_t bytes_written,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
+ static void RespondWithNewView(ScriptState*,
+ ReadableByteStreamController*,
+ NotShared<DOMArrayBufferView> view,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#transfer-array-buffer
+ static DOMArrayBuffer* TransferArrayBuffer(ScriptState*,
+ DOMArrayBuffer* buffer,
+ ExceptionState&);
// https://streams.spec.whatwg.org/#rbs-controller-private-cancel
v8::Local<v8::Promise> CancelSteps(ScriptState*,
@@ -49,8 +245,27 @@ class ReadableByteStreamController : public ReadableStreamController {
// https://streams.spec.whatwg.org/#rbs-controller-private-pull
StreamPromiseResolver* PullSteps(ScriptState*) override;
- private:
- static void ThrowUnimplemented(ExceptionState&);
+ // autoAllocateChunkSize is encoded as 0 when it is undefined
+ size_t auto_allocate_chunk_size_ = 0u;
+ Member<ReadableStreamBYOBRequest> byob_request_;
+ Member<StreamAlgorithm> cancel_algorithm_;
+ bool close_requested_ = false;
+ bool pull_again_ = false;
+ Member<StreamAlgorithm> pull_algorithm_;
+ bool pulling_ = false;
+ HeapDeque<Member<PullIntoDescriptor>> pending_pull_intos_;
+ HeapDeque<Member<QueueEntry>> queue_;
+ double queue_total_size_;
+ bool started_ = false;
+ double strategy_high_water_mark_ = 0.0;
+ Member<ReadableStream> controlled_readable_stream_;
+};
+
+template <>
+struct DowncastTraits<ReadableByteStreamController> {
+ static bool AllowFrom(const ReadableStreamController& controller) {
+ return controller.IsByteStreamController();
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
index db8ac02beae..c1703b75a72 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
@@ -4,13 +4,12 @@
// https://streams.spec.whatwg.org/#rbs-controller-class-definition
[
- Exposed=(Window,Worker,Worklet),
- RuntimeEnabled=ReadableByteStream
+ Exposed=(Window,Worker,Worklet)
] interface ReadableByteStreamController {
- [RaisesException] readonly attribute ReadableStreamBYOBRequest? byobRequest;
- [RaisesException] readonly attribute double? desiredSize;
+ readonly attribute ReadableStreamBYOBRequest? byobRequest;
+ readonly attribute double? desiredSize;
[CallWith=ScriptState, RaisesException] void close();
[CallWith=ScriptState, RaisesException] void enqueue(ArrayBufferView chunk);
- [CallWith=ScriptState, RaisesException] void error(optional any e);
+ [CallWith=ScriptState] void error(optional any e);
};
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
index b79380ac009..6473b2186e2 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -5,30 +5,36 @@
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/readable_stream_default_reader_or_readable_stream_byob_reader.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_abort_signal.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_writable_pair.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
#include "third_party/blink/renderer/core/streams/promise_handler.h"
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
#include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_get_reader_options.h"
-#include "third_party/blink/renderer/core/streams/readable_writable_pair.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
-#include "third_party/blink/renderer/core/streams/stream_pipe_options.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
#include "third_party/blink/renderer/core/streams/transferable_streams.h"
#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/core/streams/writable_stream.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/core/streams/writable_stream_transferring_optimizer.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/bindings/script_state.h"
@@ -36,7 +42,6 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
@@ -1011,7 +1016,11 @@ void ReadableStream::TeeEngine::Start(ScriptState* script_state,
}
for (int branch = 0; branch < 2; ++branch) {
- controller_[branch] = branch_[branch]->readable_stream_controller_;
+ ReadableStreamController* controller =
+ branch_[branch]->readable_stream_controller_;
+ // We just created the branches above. It is obvious that the controllers
+ // are default controllers.
+ controller_[branch] = To<ReadableStreamDefaultController>(controller);
}
class RejectFunction final : public PromiseHandler {
@@ -1093,6 +1102,16 @@ ReadableStream* ReadableStream::CreateWithCountQueueingStrategy(
ScriptState* script_state,
UnderlyingSourceBase* underlying_source,
size_t high_water_mark) {
+ return CreateWithCountQueueingStrategy(script_state, underlying_source,
+ high_water_mark,
+ /*optimizer=*/nullptr);
+}
+
+ReadableStream* ReadableStream::CreateWithCountQueueingStrategy(
+ ScriptState* script_state,
+ UnderlyingSourceBase* underlying_source,
+ size_t high_water_mark,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer) {
auto* isolate = script_state->GetIsolate();
// It's safer to use a workalike rather than a real CountQueuingStrategy
@@ -1129,6 +1148,7 @@ ReadableStream* ReadableStream::CreateWithCountQueueingStrategy(
<< "Ignoring an exception in CreateWithCountQueuingStrategy().";
}
+ stream->transferring_optimizer_ = std::move(optimizer);
return stream;
}
@@ -1224,17 +1244,17 @@ void ReadableStream::getReader(
ReadableStreamDefaultReaderOrReadableStreamBYOBReader& return_value,
ExceptionState& exception_state) {
// https://streams.spec.whatwg.org/#rs-get-reader
- // Since byob readers are not completely implemented yet, this function should
- // just call the default getReader().
- // TODO(nidhijaju): Add assertion options["mode"] is "byob" and return
- // ? AcquireReadableStreamBYOBReader(this) according to spec, once byob
- // readers have been implemented.
if (options->hasMode()) {
DCHECK_EQ(options->mode(), "byob");
- exception_state.ThrowTypeError("byob not implemented");
- return;
+
+ UseCounter::Count(ExecutionContext::From(script_state),
+ WebFeature::kReadableStreamBYOBReader);
+
+ return_value.SetReadableStreamBYOBReader(
+ AcquireBYOBReader(script_state, this, exception_state));
+ } else {
+ getReader(script_state, return_value, exception_state);
}
- getReader(script_state, return_value, exception_state);
}
ReadableStreamDefaultReader* ReadableStream::GetDefaultReaderForTesting(
@@ -1395,14 +1415,34 @@ void ReadableStream::InitInternal(ScriptState* script_state,
// 6. If typeString is "bytes",
if (type_string == V8AtomicString(isolate, "bytes")) {
- // TODO(ricea): Implement bytes type.
- exception_state.ThrowRangeError("bytes type is not yet implemented");
+ UseCounter::Count(ExecutionContext::From(script_state),
+ WebFeature::kReadableStreamWithByteSource);
+
+ UnderlyingSource* underlying_source_dict =
+ NativeValueTraits<UnderlyingSource>::NativeValue(
+ script_state->GetIsolate(), raw_underlying_source.V8Value(),
+ exception_state);
+ if (!strategy_unpacker.IsSizeUndefined()) {
+ exception_state.ThrowRangeError(
+ "Cannot create byte stream with size() defined on the strategy");
+ return;
+ }
+ double high_water_mark =
+ strategy_unpacker.GetHighWaterMark(script_state, 0, exception_state);
+ if (exception_state.HadException()) {
+ return;
+ }
+ ReadableByteStreamController::SetUpFromUnderlyingSource(
+ script_state, this, underlying_source, underlying_source_dict,
+ high_water_mark, exception_state);
return;
}
// 8. Otherwise, throw a RangeError exception.
- exception_state.ThrowRangeError("Invalid type is specified");
- return;
+ else {
+ exception_state.ThrowRangeError("Invalid type is specified");
+ return;
+ }
}
// 7. Otherwise, if type is undefined,
@@ -1455,6 +1495,23 @@ ReadableStreamDefaultReader* ReadableStream::AcquireDefaultReader(
return reader;
}
+ReadableStreamBYOBReader* ReadableStream::AcquireBYOBReader(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#acquire-readable-stream-byob-reader
+ // 1. Let reader be a new ReadableStreamBYOBReader.
+ // 2. Perform ? SetUpBYOBReader(reader, stream).
+ auto* reader = MakeGarbageCollected<ReadableStreamBYOBReader>(
+ script_state, stream, exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+
+ // 3. Return reader.
+ return reader;
+}
+
void ReadableStream::Initialize(ReadableStream* stream) {
// Fields are initialised by the constructor, so we only check that they were
// initialised correctly.
@@ -1514,8 +1571,8 @@ void ReadableStream::Serialize(ScriptState* script_state,
// 5. Let writable be a new WritableStream in the current Realm.
// 6. Perform ! SetUpCrossRealmTransformWritable(writable, port1).
- auto* writable =
- CreateCrossRealmTransformWritable(script_state, port, exception_state);
+ auto* writable = CreateCrossRealmTransformWritable(
+ script_state, port, /*optimizer=*/nullptr, exception_state);
if (exception_state.HadException()) {
return;
}
@@ -1533,9 +1590,11 @@ void ReadableStream::Serialize(ScriptState* script_state,
// « port2 »).
}
-ReadableStream* ReadableStream::Deserialize(ScriptState* script_state,
- MessagePort* port,
- ExceptionState& exception_state) {
+ReadableStream* ReadableStream::Deserialize(
+ ScriptState* script_state,
+ MessagePort* port,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer,
+ ExceptionState& exception_state) {
// We need to execute JavaScript to call "Then" on v8::Promises. We will not
// run author code.
v8::Isolate::AllowJavascriptExecutionScope allow_js(
@@ -1551,8 +1610,8 @@ ReadableStream* ReadableStream::Deserialize(ScriptState* script_state,
// 3. Perform ! SetUpCrossRealmTransformReadable(value, port).
// In the standard |value| contains an uninitialized ReadableStream. In the
// implementation, we create the stream here.
- auto* readable =
- CreateCrossRealmTransformReadable(script_state, port, exception_state);
+ auto* readable = CreateCrossRealmTransformReadable(
+ script_state, port, std::move(optimizer), exception_state);
if (exception_state.HadException()) {
return nullptr;
}
@@ -1581,6 +1640,11 @@ v8::Local<v8::Value> ReadableStream::GetStoredError(
return stored_error_.NewLocal(isolate);
}
+std::unique_ptr<ReadableStreamTransferringOptimizer>
+ReadableStream::TakeTransferringOptimizer() {
+ return std::move(transferring_optimizer_);
+}
+
void ReadableStream::Trace(Visitor* visitor) const {
visitor->Trace(readable_stream_controller_);
visitor->Trace(reader_);
@@ -1592,13 +1656,28 @@ void ReadableStream::Trace(Visitor* visitor) const {
// Abstract Operations Used By Controllers
//
+void ReadableStream::AddReadIntoRequest(
+ ScriptState* script_state,
+ ReadableStream* stream,
+ ReadableStreamBYOBReader::ReadIntoRequest* readRequest) {
+ // https://streams.spec.whatwg.org/#readable-stream-add-read-into-request
+ // 1. Assert: stream.[[reader]] implements ReadableStreamBYOBReader.
+ DCHECK(stream->reader_->IsBYOBReader());
+ // 2. Assert: stream.[[state]] is "readable" or "closed".
+ DCHECK(stream->state_ == kReadable || stream->state_ == kClosed);
+ // 3. Append readRequest to stream.[[reader]].[[readIntoRequests]].
+ ReadableStreamGenericReader* reader = stream->reader_;
+ ReadableStreamBYOBReader* byob_reader = To<ReadableStreamBYOBReader>(reader);
+ byob_reader->read_into_requests_.push_back(readRequest);
+}
+
StreamPromiseResolver* ReadableStream::AddReadRequest(ScriptState* script_state,
ReadableStream* stream) {
// https://streams.spec.whatwg.org/#readable-stream-add-read-request
// 1. Assert: ! IsReadableStreamDefaultReader(stream.[[reader]]) is true.
ReadableStreamGenericReader* reader = stream->reader_;
ReadableStreamDefaultReader* default_reader =
- static_cast<ReadableStreamDefaultReader*>(reader);
+ To<ReadableStreamDefaultReader>(reader);
DCHECK(default_reader);
// 2. Assert: stream.[[state]] is "readable".
@@ -1680,30 +1759,28 @@ void ReadableStream::Close(ScriptState* script_state, ReadableStream* stream) {
return;
}
- // TODO(ricea): Support BYOB readers.
// 5. If ! IsReadableStreamDefaultReader(reader) is true,
- // TODO(nidhijaju): Add a check that the reader is a default reader once BYOB
- // readers have been implemented, so the static_cast can be changed later on.
- // a. Repeat for each readRequest that is an element of reader.
- // [[readRequests]],
- HeapDeque<Member<StreamPromiseResolver>> requests;
- requests.Swap(
- static_cast<ReadableStreamDefaultReader*>(reader)->read_requests_);
- for (StreamPromiseResolver* promise : requests) {
- // i. Resolve readRequest.[[promise]] with !
- // ReadableStreamCreateReadResult(undefined, true, reader.
- // [[forAuthorCode]]).
- promise->Resolve(
- script_state,
- CreateReadResult(script_state,
- v8::Undefined(script_state->GetIsolate()), true,
- static_cast<ReadableStreamDefaultReader*>(reader)
- ->for_author_code_));
- }
-
- // b. Set reader.[[readRequests]] to an empty List.
- // This is not required since we've already called Swap().
+ if (reader->IsDefaultReader()) {
+ // a. Repeat for each readRequest that is an element of reader.
+ // [[readRequests]],
+ HeapDeque<Member<StreamPromiseResolver>> requests;
+ requests.Swap(To<ReadableStreamDefaultReader>(reader)->read_requests_);
+ bool for_author_code =
+ To<ReadableStreamDefaultReader>(reader)->for_author_code_;
+ for (StreamPromiseResolver* promise : requests) {
+ // i. Resolve readRequest.[[promise]] with !
+ // ReadableStreamCreateReadResult(undefined, true, reader.
+ // [[forAuthorCode]]).
+ promise->Resolve(
+ script_state,
+ CreateReadResult(script_state,
+ v8::Undefined(script_state->GetIsolate()), true,
+ for_author_code));
+ }
+ // b. Set reader.[[readRequests]] to an empty List.
+ // This is not required since we've already called Swap().
+ }
// 6. Resolve reader.[[closedPromise]] with undefined.
reader->closed_promise_->ResolveWithUndefined(script_state);
}
@@ -1758,76 +1835,162 @@ void ReadableStream::Error(ScriptState* script_state,
ReadableStream* stream,
v8::Local<v8::Value> e) {
// https://streams.spec.whatwg.org/#readable-stream-error
- // 2. Assert: stream.[[state]] is "readable".
+ // 1. Assert: stream.[[state]] is "readable".
CHECK_EQ(stream->state_, kReadable);
auto* isolate = script_state->GetIsolate();
- // 3. Set stream.[[state]] to "errored".
+ // 2. Set stream.[[state]] to "errored".
stream->state_ = kErrored;
- // 4. Set stream.[[storedError]] to e.
+ // 3. Set stream.[[storedError]] to e.
stream->stored_error_.Set(isolate, e);
- // 5. Let reader be stream.[[reader]].
+ // 4. Let reader be stream.[[reader]].
ReadableStreamGenericReader* reader = stream->reader_;
- // 6. If reader is undefined, return.
+ // 5. If reader is undefined, return.
if (!reader) {
return;
}
- // 7. If ! IsReadableStreamDefaultReader(reader) is true,
- // TODO(ricea): Support BYOB readers.
+ // 6. If ! IsReadableStreamDefaultReader(reader) is true,
// a. Repeat for each readRequest that is an element of reader.
// [[readRequests]],
- ReadableStreamDefaultReader* default_reader =
- static_cast<ReadableStreamDefaultReader*>(reader);
- for (StreamPromiseResolver* promise : default_reader->read_requests_) {
- // i. Reject readRequest.[[promise]] with e.
- promise->Reject(script_state, e);
- }
+ if (reader->IsDefaultReader()) {
+ ReadableStreamDefaultReader* default_reader =
+ To<ReadableStreamDefaultReader>(reader);
+ for (StreamPromiseResolver* promise : default_reader->read_requests_) {
+ // i. Reject readRequest.[[promise]] with e.
+ promise->Reject(script_state, e);
+ }
- // b. Set reader.[[readRequests]] to a new empty List.
- default_reader->read_requests_.clear();
+ // b. Set reader.[[readRequests]] to a new empty List.
+ default_reader->read_requests_.clear();
+ }
+
+ // 7. Otherwise,
+ else {
+ // a. Assert: reader implements ReadableStreamBYOBReader.
+ DCHECK(reader->IsBYOBReader());
+ // b. For each readIntoRequest of reader.[[readIntoRequests]],
+ ReadableStreamBYOBReader* byob_reader =
+ To<ReadableStreamBYOBReader>(reader);
+ for (ReadableStreamBYOBReader::ReadIntoRequest* request :
+ byob_reader->read_into_requests_) {
+ // i. Perform readIntoRequests' error steps, given e.
+ request->ErrorSteps(script_state, e);
+ }
+ // c. Set reader.[[readIntoRequests]] to a new empty list.
+ byob_reader->read_into_requests_.clear();
+ }
- // 9. Reject reader.[[closedPromise]] with e.
+ // 8. Reject reader.[[closedPromise]] with e.
reader->closed_promise_->Reject(script_state, e);
- // 10. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
+ // 9. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
reader->closed_promise_->MarkAsHandled(isolate);
}
+void ReadableStream::FulfillReadIntoRequest(ScriptState* script_state,
+ ReadableStream* stream,
+ DOMArrayBufferView* chunk,
+ bool done) {
+ // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
+ // 1. Assert: ! ReadableStreamHasBYOBReader(stream) is true.
+ DCHECK(HasBYOBReader(stream));
+ // 2. Let reader be stream.[[reader]].
+ ReadableStreamGenericReader* reader = stream->reader_;
+ ReadableStreamBYOBReader* byob_reader = To<ReadableStreamBYOBReader>(reader);
+ // 3. Assert: reader.[[readIntoRequests]] is not empty.
+ DCHECK(!byob_reader->read_into_requests_.IsEmpty());
+ // 4. Let readIntoRequest be reader.[[readIntoRequests]][0].
+ ReadableStreamBYOBReader::ReadIntoRequest* read_into_request =
+ byob_reader->read_into_requests_[0];
+ // 5. Remove readIntoRequest from reader.[[readIntoRequests]].
+ byob_reader->read_into_requests_.pop_front();
+ // 6. If done is true, perform readIntoRequest’s close steps, given chunk.
+ if (done) {
+ read_into_request->CloseSteps(script_state, chunk);
+ } else {
+ // 7. Otherwise, perform readIntoRequest’s chunk steps, given chunk.
+ read_into_request->ChunkSteps(script_state, chunk);
+ }
+}
+
void ReadableStream::FulfillReadRequest(ScriptState* script_state,
ReadableStream* stream,
v8::Local<v8::Value> chunk,
bool done) {
// https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request
- // 1. Let reader be stream.[[reader]].
+ // 1. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
+ DCHECK(HasDefaultReader(stream));
+
+ // 2. Let reader be stream.[[reader]].
ReadableStreamGenericReader* reader = stream->reader_;
ReadableStreamDefaultReader* default_reader =
- static_cast<ReadableStreamDefaultReader*>(reader);
+ To<ReadableStreamDefaultReader>(reader);
- // 2. Let readRequest be the first element of reader.[[readRequests]].
+ // 3. Let readRequest be the first element of reader.[[readRequests]].
StreamPromiseResolver* read_request = default_reader->read_requests_.front();
- // 3. Remove readIntoRequest from reader.[[readIntoRequests]], shifting all
+ // 4. Remove readIntoRequest from reader.[[readIntoRequests]], shifting all
// other elements downward (so that the second becomes the first, and so
// on).
default_reader->read_requests_.pop_front();
- // 4. Resolve readIntoRequest.[[promise]] with !
+ // 5. Resolve readIntoRequest.[[promise]] with !
// ReadableStreamCreateReadResult(chunk, done, reader.[[forAuthorCode]]).
read_request->Resolve(script_state, ReadableStream::CreateReadResult(
script_state, chunk, done,
default_reader->for_author_code_));
}
+int ReadableStream::GetNumReadIntoRequests(const ReadableStream* stream) {
+ // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
+ // 1. Assert: ! ReadableStreamHasBYOBReader(stream) is true.
+ DCHECK(HasBYOBReader(stream));
+ // 2. Return stream.[[reader]].[[readIntoRequests]]'s size.
+ ReadableStreamGenericReader* reader = stream->reader_;
+ return To<ReadableStreamBYOBReader>(reader)->read_into_requests_.size();
+}
+
int ReadableStream::GetNumReadRequests(const ReadableStream* stream) {
// https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
- // 1. Return the number of elements in stream.[[reader]].[[readRequests]].
+ // 1. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
+ DCHECK(HasDefaultReader(stream));
+ // 2. Return the number of elements in stream.[[reader]].[[readRequests]].
+ ReadableStreamGenericReader* reader = stream->reader_;
+ return To<ReadableStreamDefaultReader>(reader)->read_requests_.size();
+}
+
+bool ReadableStream::HasBYOBReader(const ReadableStream* stream) {
+ // https://streams.spec.whatwg.org/#readable-stream-has-byob-reader
+ // 1. Let reader be stream.[[reader]].
ReadableStreamGenericReader* reader = stream->reader_;
- return static_cast<ReadableStreamDefaultReader*>(reader)
- ->read_requests_.size();
+
+ // 2. If reader is undefined, return false.
+ if (!reader) {
+ return false;
+ }
+
+ // 3. If reader implements ReadableStreamBYOBReader, return true.
+ // 4. Return false.
+ return reader->IsBYOBReader();
+}
+
+bool ReadableStream::HasDefaultReader(const ReadableStream* stream) {
+ // https://streams.spec.whatwg.org/#readable-stream-has-default-reader
+ // 1. Let reader be stream.[[reader]].
+ ReadableStreamGenericReader* reader = stream->reader_;
+
+ // 2. If reader is undefined, return false.
+ if (!reader) {
+ return false;
+ }
+
+ // 3. If reader implements ReadableStreamDefaultReader, return true.
+ // 4. Return false.
+ return reader->IsDefaultReader();
}
//
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream.h b/chromium/third_party/blink/renderer/core/streams/readable_stream.h
index 290b800d40f..de623500e0d 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream.h
@@ -6,13 +6,16 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_H_
#include <stdint.h>
+#include <memory>
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
@@ -20,9 +23,12 @@ namespace blink {
class AbortSignal;
class ExceptionState;
class MessagePort;
+class ReadableByteStreamController;
+class ReadableStreamController;
class ReadableStreamDefaultController;
class ReadableStreamDefaultReaderOrReadableStreamBYOBReader;
class ReadableStreamGetReaderOptions;
+class ReadableStreamTransferringOptimizer;
class ReadableWritablePair;
class ScriptPromise;
class ScriptState;
@@ -32,7 +38,6 @@ class StreamPipeOptions;
class StreamPromiseResolver;
class StreamStartAlgorithm;
class UnderlyingSourceBase;
-class Visitor;
class WritableStream;
// C++ implementation of ReadableStream.
@@ -65,29 +70,32 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
Member<AbortSignal> signal_;
};
- // Create* functions create an appropriate subclass depending on which
- // implementation is selected by blink features.
+ enum State : uint8_t { kReadable, kClosed, kErrored };
+
+ // Zero-argument form of the constructor called from JavaScript.
static ReadableStream* Create(ScriptState*, ExceptionState&);
+
+ // One-argument constructor called from JavaScript.
static ReadableStream* Create(ScriptState*,
ScriptValue underlying_source,
ExceptionState&);
- enum State : uint8_t { kReadable, kClosed, kErrored };
- // Implements ReadableStream::Create() when this implementation is enabled.
+ // Two-argument constructor called from JavaScript.
static ReadableStream* Create(ScriptState* script_state,
ScriptValue underlying_source,
ScriptValue strategy,
ExceptionState& exception_state);
- // Implements ReadableStream::CreateWithCountQueueingStrategy() when this
- // implementation is enabled.
- //
- // TODO(ricea): Replace this API with something more efficient when the old
- // implementation is gone.
+ // Entry point to create a ReadableStream from other C++ APIs.
static ReadableStream* CreateWithCountQueueingStrategy(
ScriptState* script_state,
UnderlyingSourceBase* underlying_source,
size_t high_water_mark);
+ static ReadableStream* CreateWithCountQueueingStrategy(
+ ScriptState* script_state,
+ UnderlyingSourceBase* underlying_source,
+ size_t high_water_mark,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer);
// CreateReadableStream():
// https://streams.spec.whatwg.org/#create-readable-stream
@@ -169,9 +177,11 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
void Serialize(ScriptState*, MessagePort* port, ExceptionState&);
- static ReadableStream* Deserialize(ScriptState*,
- MessagePort* port,
- ExceptionState&);
+ static ReadableStream* Deserialize(
+ ScriptState*,
+ MessagePort* port,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer,
+ ExceptionState&);
// Returns a reader that doesn't have the |for_author_code_| flag set. This is
// used in contexts where reads should not be interceptable by user code. This
@@ -198,6 +208,17 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
WritableStream*,
PipeOptions*);
+ // https://streams.spec.whatwg.org/#acquire-readable-stream-reader
+ static ReadableStreamDefaultReader* AcquireDefaultReader(ScriptState*,
+ ReadableStream*,
+ bool for_author_code,
+ ExceptionState&);
+
+ // https://streams.spec.whatwg.org/#acquire-readable-stream-byob-reader
+ static ReadableStreamBYOBReader* AcquireBYOBReader(ScriptState*,
+ ReadableStream*,
+ ExceptionState&);
+
//
// Functions exported for use by TransformStream. Not part of the standard.
//
@@ -214,15 +235,20 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
return stream->state_ == kErrored;
}
- ReadableStreamDefaultController* GetController() {
+ ReadableStreamController* GetController() {
return readable_stream_controller_;
}
v8::Local<v8::Value> GetStoredError(v8::Isolate*) const;
+ std::unique_ptr<ReadableStreamTransferringOptimizer>
+ TakeTransferringOptimizer();
+
void Trace(Visitor*) const override;
private:
+ friend class ReadableByteStreamController;
+ friend class ReadableStreamBYOBReader;
friend class ReadableStreamDefaultController;
friend class ReadableStreamDefaultReader;
friend class ReadableStreamGenericReader;
@@ -241,11 +267,9 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
// https://streams.spec.whatwg.org/#initialize-readable-stream
static void Initialize(ReadableStream*);
- // https://streams.spec.whatwg.org/#acquire-readable-stream-reader
- static ReadableStreamDefaultReader* AcquireDefaultReader(ScriptState*,
- ReadableStream*,
- bool for_author_code,
- ExceptionState&);
+ static void AddReadIntoRequest(ScriptState*,
+ ReadableStream*,
+ ReadableStreamBYOBReader::ReadIntoRequest*);
// https://streams.spec.whatwg.org/#readable-stream-add-read-request
static StreamPromiseResolver* AddReadRequest(ScriptState*, ReadableStream*);
@@ -267,15 +291,30 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
// https://streams.spec.whatwg.org/#readable-stream-error
static void Error(ScriptState*, ReadableStream*, v8::Local<v8::Value> e);
+ // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
+ static void FulfillReadIntoRequest(ScriptState*,
+ ReadableStream*,
+ DOMArrayBufferView* chunk,
+ bool done);
+
// https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request
static void FulfillReadRequest(ScriptState*,
ReadableStream*,
v8::Local<v8::Value> chunk,
bool done);
+ // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
+ static int GetNumReadIntoRequests(const ReadableStream*);
+
// https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
static int GetNumReadRequests(const ReadableStream*);
+ // https://streams.spec.whatwg.org/#readable-stream-has-byob-reader
+ static bool HasBYOBReader(const ReadableStream*);
+
+ // https://streams.spec.whatwg.org/#readable-stream-has-default-reader
+ static bool HasDefaultReader(const ReadableStream*);
+
//
// TODO(ricea): Functions for transferable streams.
//
@@ -289,9 +328,10 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
bool is_disturbed_ = false;
State state_ = kReadable;
- Member<ReadableStreamDefaultController> readable_stream_controller_;
+ Member<ReadableStreamController> readable_stream_controller_;
Member<ReadableStreamGenericReader> reader_;
TraceWrapperV8Reference<v8::Value> stored_error_;
+ std::unique_ptr<ReadableStreamTransferringOptimizer> transferring_optimizer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream.idl b/chromium/third_party/blink/renderer/core/streams/readable_stream.idl
index acb9cdf376b..b0bb8623c85 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -4,8 +4,10 @@
// https://streams.spec.whatwg.org/#rs-class
typedef (ReadableStreamDefaultReader or ReadableStreamBYOBReader) ReadableStreamReader;
+typedef (ReadableStreamDefaultController or ReadableByteStreamController) ReadableStreamController;
enum ReadableStreamReaderMode { "byob" };
+enum ReadableStreamType { "bytes" };
[
Exposed=(Window,Worker,Worklet)
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
index f801a0d4b86..1dba45d7863 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
@@ -5,28 +5,64 @@
#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
namespace blink {
+ReadableStreamBYOBReader::ReadIntoRequest::ReadIntoRequest(
+ StreamPromiseResolver* resolver)
+ : resolver_(resolver) {}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::ChunkSteps(
+ ScriptState* script_state,
+ DOMArrayBufferView* chunk) const {
+ resolver_->Resolve(script_state,
+ ReadableStream::CreateReadResult(
+ script_state, ToV8(chunk, script_state), false, true));
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::CloseSteps(
+ ScriptState* script_state,
+ DOMArrayBufferView* chunk) const {
+ resolver_->Resolve(script_state,
+ ReadableStream::CreateReadResult(
+ script_state, ToV8(chunk, script_state), true, true));
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::ErrorSteps(
+ ScriptState* script_state,
+ v8::Local<v8::Value> e) const {
+ resolver_->Reject(script_state, e);
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::Trace(Visitor* visitor) const {
+ visitor->Trace(resolver_);
+}
+
ReadableStreamBYOBReader* ReadableStreamBYOBReader::Create(
ScriptState* script_state,
ReadableStream* stream,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return nullptr;
+ auto* reader = MakeGarbageCollected<ReadableStreamBYOBReader>(
+ script_state, stream, exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+ return reader;
}
ReadableStreamBYOBReader::ReadableStreamBYOBReader(
ScriptState* script_state,
ReadableStream* stream,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ SetUpBYOBReader(script_state, this, stream, exception_state);
}
ReadableStreamBYOBReader::~ReadableStreamBYOBReader() = default;
@@ -34,26 +70,135 @@ ReadableStreamBYOBReader::~ReadableStreamBYOBReader() = default;
ScriptPromise ReadableStreamBYOBReader::read(ScriptState* script_state,
NotShared<DOMArrayBufferView> view,
ExceptionState& exception_state) {
- return RejectUnimplemented(script_state);
+ // https://streams.spec.whatwg.org/#byob-reader-read
+ // 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError
+ // exception.
+ if (view->byteLength() == 0) {
+ exception_state.ThrowTypeError(
+ "This readable stream reader cannot be used to read as the view has "
+ "byte length equal to 0");
+ return ScriptPromise();
+ }
+
+ // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a
+ // promise rejected with a TypeError exception.
+ if (view->buffer()->ByteLength() == 0) {
+ exception_state.ThrowTypeError(
+ "This readable stream reader cannot be used to read as the viewed "
+ "array buffer has 0 byte length");
+ return ScriptPromise();
+ }
+
+ // 3. If this.[[stream]] is undefined, return a promise rejected with a
+ // TypeError exception.
+ if (!owner_readable_stream_) {
+ exception_state.ThrowTypeError(
+ "This readable stream reader has been released and cannot be used to "
+ "read from its previous owner stream");
+ return ScriptPromise();
+ }
+
+ // 4. Let promise be a new promise.
+ auto* promise = MakeGarbageCollected<StreamPromiseResolver>(script_state);
+
+ // 5. Let readIntoRequest be a new read-into request with the following items:
+ // chunk steps, given chunk
+ // 1. Resolve promise with «[ "value" → chunk, "done" → false ]».
+ // close steps, given chunk
+ // 1. Resolve promise with «[ "value" → chunk, "done" → true ]».
+ // error steps, given e
+ // 1. Reject promise with e.
+ auto* read_into_request = MakeGarbageCollected<ReadIntoRequest>(promise);
+
+ // 6. Perform ! ReadableStreamBYOBReaderRead(this, view, readIntoRequest).
+ Read(script_state, this, view, read_into_request, exception_state);
+ // 7. Return promise.
+ return promise->GetScriptPromise(script_state);
+}
+
+void ReadableStreamBYOBReader::Read(ScriptState* script_state,
+ ReadableStreamBYOBReader* reader,
+ NotShared<DOMArrayBufferView> view,
+ ReadIntoRequest* read_into_request,
+ ExceptionState& exception_state) {
+ // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
+ // 1. Let stream be reader.[[stream]].
+ ReadableStream* stream = reader->owner_readable_stream_;
+
+ // 2. Assert: stream is not undefined.
+ DCHECK(stream);
+
+ // 3. Set stream.[[disturbed]] to true.
+ stream->is_disturbed_ = true;
+
+ // 4. If stream.[[state]] is "errored", perform readIntoRequest's error steps
+ // given stream.[[storedError]].
+ if (stream->state_ == ReadableStream::kErrored) {
+ read_into_request->ErrorSteps(
+ script_state, stream->GetStoredError(script_state->GetIsolate()));
+ } else {
+ // 5. Otherwise, perform !
+ // ReadableByteStreamControllerPullInto(stream.[[controller]], view,
+ // readIntoRequest).
+ ReadableStreamController* controller = stream->readable_stream_controller_;
+ ReadableByteStreamController::PullInto(
+ script_state, To<ReadableByteStreamController>(controller), view,
+ read_into_request, exception_state);
+ }
}
void ReadableStreamBYOBReader::releaseLock(ScriptState* script_state,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ // https://streams.spec.whatwg.org/#byob-reader-release-lock
+ // 1. If this.[[stream]] is undefined, return.
+ if (!owner_readable_stream_) {
+ return;
+ }
+
+ // 2. If this.[[readIntoRequests]] is not empty, throw a TypeError exception.
+ if (read_into_requests_.size() > 0) {
+ exception_state.ThrowTypeError(
+ "Cannot release a readable stream reader when it still has outstanding "
+ "read() calls that have not yet settled");
+ return;
+ }
+
+ // 3. Perform ! ReadableStreamReaderGenericRelease(this).
+ GenericRelease(script_state, this);
}
-void ReadableStreamBYOBReader::ThrowUnimplemented(
+void ReadableStreamBYOBReader::SetUpBYOBReader(
+ ScriptState* script_state,
+ ReadableStreamBYOBReader* reader,
+ ReadableStream* stream,
ExceptionState& exception_state) {
- exception_state.ThrowTypeError("unimplemented");
+ // https://streams.spec.whatwg.org/#set-up-readable-stream-byob-reader
+ // If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
+ if (ReadableStream::IsLocked(stream)) {
+ exception_state.ThrowTypeError(
+ "ReadableStreamBYOBReader constructor can only accept readable streams "
+ "that are not yet locked to a reader");
+ return;
+ }
+
+ // If stream.[[controller]] does not implement ReadableByteStreamController,
+ // throw a TypeError exception.
+ if (!stream->readable_stream_controller_->IsByteStreamController()) {
+ exception_state.ThrowTypeError(
+ "Cannot use a BYOB reader with a non-byte stream");
+ return;
+ }
+
+ // Perform ! ReadableStreamReaderGenericInitialize(reader, stream).
+ ReadableStreamGenericReader::GenericInitialize(script_state, reader, stream);
+
+ // Set reader.[[readIntoRequests]] to a new empty list.
+ DCHECK_EQ(reader->read_into_requests_.size(), 0u);
}
-ScriptPromise ReadableStreamBYOBReader::RejectUnimplemented(
- ScriptState* script_state) {
- return StreamPromiseResolver::CreateRejected(
- script_state, v8::Exception::TypeError(V8String(
- script_state->GetIsolate(), "unimplemented")))
- ->GetScriptPromise(script_state);
+void ReadableStreamBYOBReader::Trace(Visitor* visitor) const {
+ visitor->Trace(read_into_requests_);
+ ReadableStreamGenericReader::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
index 198e915cca1..fb7ac5bc9b2 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
@@ -1,4 +1,4 @@
-// Copyright 2020 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.
@@ -9,13 +9,16 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
class ExceptionState;
class ScriptPromise;
class ScriptState;
+class StreamPromiseResolver;
class ReadableStream;
class DOMArrayBufferView;
@@ -34,6 +37,9 @@ class CORE_EXPORT ReadableStreamBYOBReader
ExceptionState&);
~ReadableStreamBYOBReader() override;
+ bool IsDefaultReader() const override { return false; }
+ bool IsBYOBReader() const override { return true; }
+
// https://streams.spec.whatwg.org/#byob-reader-read
ScriptPromise read(ScriptState*,
NotShared<DOMArrayBufferView> view,
@@ -42,11 +48,51 @@ class CORE_EXPORT ReadableStreamBYOBReader
// https://streams.spec.whatwg.org/#byob-reader-release-lock
void releaseLock(ScriptState*, ExceptionState&);
+ // https://streams.spec.whatwg.org/#set-up-readable-stream-byob-reader
+ static void SetUpBYOBReader(ScriptState*,
+ ReadableStreamBYOBReader* reader,
+ ReadableStream* stream,
+ ExceptionState&);
+
+ void Trace(Visitor*) const override;
+
private:
+ friend class ReadableByteStreamController;
friend class ReadableStream;
- static void ThrowUnimplemented(ExceptionState&);
- static ScriptPromise RejectUnimplemented(ScriptState*);
+
+ class ReadIntoRequest : public GarbageCollected<ReadIntoRequest> {
+ public:
+ explicit ReadIntoRequest(StreamPromiseResolver* resolver);
+
+ void ChunkSteps(ScriptState*, DOMArrayBufferView* chunk) const;
+ void CloseSteps(ScriptState*, DOMArrayBufferView* chunk) const;
+ void ErrorSteps(ScriptState*, v8::Local<v8::Value> e) const;
+
+ void Trace(Visitor*) const;
+
+ private:
+ friend class ReadableStream;
+
+ Member<StreamPromiseResolver> resolver_;
+ };
+
+ // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
+ static void Read(ScriptState*,
+ ReadableStreamBYOBReader*,
+ NotShared<DOMArrayBufferView> view,
+ ReadIntoRequest*,
+ ExceptionState&);
+
+ HeapDeque<Member<ReadIntoRequest>> read_into_requests_;
};
+
+template <>
+struct DowncastTraits<ReadableStreamBYOBReader> {
+ static bool AllowFrom(const ReadableStreamGenericReader& reader) {
+ return reader.IsBYOBReader();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_READER_H_
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
index 2fdd984c2bb..66b10131904 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
@@ -4,8 +4,7 @@
// https://streams.spec.whatwg.org/#byob-reader-class-definition
[
- Exposed=(Window,Worker,Worklet),
- RuntimeEnabled=ReadableByteStream
+ Exposed=(Window,Worker,Worklet)
] interface ReadableStreamBYOBReader {
[CallWith=ScriptState, RaisesException] constructor(ReadableStream stream);
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
index 86bf059d3ff..3c446df62a3 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
@@ -11,30 +11,77 @@
namespace blink {
+ReadableStreamBYOBRequest::ReadableStreamBYOBRequest(
+ ReadableByteStreamController* controller,
+ NotShared<DOMUint8Array> view)
+ : controller_(controller), view_(view) {}
+
NotShared<DOMArrayBufferView> ReadableStreamBYOBRequest::view(
ExceptionState& exception_state) const {
- ThrowUnimplemented(exception_state);
- return NotShared<DOMArrayBufferView>();
+ // https://streams.spec.whatwg.org/#rs-byob-request-view
+ // 1. Return this.[[view]].
+ return view_;
}
void ReadableStreamBYOBRequest::respond(ScriptState* script_state,
- uint64_t bytesWritten,
+ uint64_t bytes_written,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ // https://streams.spec.whatwg.org/#rs-byob-request-respond
+ // 1. If this.[[controller]] is undefined, throw a TypeError exception.
+ if (!controller_) {
+ exception_state.ThrowTypeError(
+ "Cannot respond to an invalidated ReadableStreamBYOBRequest");
+ return;
+ }
+ // 2. If IsDetachedBuffer(this.[[view]].[[ArrayBuffer]]) is true, throw a
+ // TypeError exception.
+ if (view_->buffer()->IsDetached()) {
+ exception_state.ThrowTypeError("ArrayBufferView is detached");
+ return;
+ }
+ // 3. Assert: this.[[view]].[[ByteLength]] > 0.
+ DCHECK_GT(view_->byteLength(), 0u);
+ // 4. Assert: this.[[view]].[[ViewedArrayBuffer]].[[ByteLength]] > 0.
+ DCHECK_GT(view_->buffer()->ByteLength(), 0.0);
+ // 5. Perform ? ReadableByteStreamControllerRespond(this.[[controller]],
+ // bytesWritten).
+ ReadableByteStreamController::Respond(script_state, controller_,
+ static_cast<size_t>(bytes_written),
+ exception_state);
}
void ReadableStreamBYOBRequest::respondWithNewView(
ScriptState* script_state,
NotShared<DOMArrayBufferView> view,
ExceptionState& exception_state) {
- ThrowUnimplemented(exception_state);
- return;
+ // https://streams.spec.whatwg.org/#rs-byob-request-respond-with-new-view
+ // 1. If view.[[ByteLength]] is 0, throw a TypeError exception.
+ if (view->byteLength() == 0) {
+ exception_state.ThrowTypeError("ArrayBufferView is empty");
+ return;
+ }
+ // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a
+ // TypeError exception.
+ if (view->buffer()->ByteLength() == 0) {
+ exception_state.ThrowTypeError("ArrayBuffer is empty");
+ return;
+ }
+ // 3. If this.[[controller]] is undefined, throw a TypeError exception.
+ if (!controller_) {
+ exception_state.ThrowTypeError(
+ "Cannot respond to an invalidated ReadableStreamBYOBRequest");
+ return;
+ }
+ // 4. Return ?
+ // ReadableByteStreamControllerRespondWithNewView(this.[[controller]], view).
+ ReadableByteStreamController::RespondWithNewView(script_state, controller_,
+ view, exception_state);
}
-void ReadableStreamBYOBRequest::ThrowUnimplemented(
- ExceptionState& exception_state) {
- exception_state.ThrowTypeError("unimplemented");
+void ReadableStreamBYOBRequest::Trace(Visitor* visitor) const {
+ visitor->Trace(controller_);
+ visitor->Trace(view_);
+ ScriptWrappable::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
index 834e17f95c2..16304775052 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
@@ -1,10 +1,11 @@
-// Copyright 2020 The Chromium AUthors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_REQUEST_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_REQUEST_H_
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -18,19 +19,27 @@ class ReadableStreamBYOBRequest : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
+ ReadableStreamBYOBRequest(ReadableByteStreamController*,
+ NotShared<DOMUint8Array> view);
+
// https://streams.spec.whatwg.org/#rs-byob-request-view
NotShared<DOMArrayBufferView> view(ExceptionState&) const;
// https://streams.spec.whatwg.org/#rs-byob-request-respond
- void respond(ScriptState*, uint64_t bytesWritten, ExceptionState&);
+ void respond(ScriptState*, uint64_t bytes_written, ExceptionState&);
// https://streams.spec.whatwg.org/#rs-byob-request-respond-with-new-view
void respondWithNewView(ScriptState*,
NotShared<DOMArrayBufferView> view,
ExceptionState&);
+ void Trace(Visitor*) const override;
+
private:
- static void ThrowUnimplemented(ExceptionState&);
+ friend class ReadableByteStreamController;
+
+ Member<ReadableByteStreamController> controller_;
+ NotShared<DOMArrayBufferView> view_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
index 2149df28910..66bd7f0e50a 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
@@ -4,8 +4,7 @@
// https://streams.spec.whatwg.org/#readablestreambyobrequest
[
- Exposed=(Window,Worker,Worklet),
- RuntimeEnabled=ReadableByteStream
+ Exposed=(Window,Worker,Worklet)
] interface ReadableStreamBYOBRequest {
[RaisesException] readonly attribute ArrayBufferView? view;
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_controller.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_controller.h
index b8161c112fc..8ea66c0ced9 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_controller.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_controller.h
@@ -1,4 +1,4 @@
-// Copyright 2020 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.
@@ -15,6 +15,9 @@ class StreamPromiseResolver;
class ReadableStreamController : public ScriptWrappable {
public:
+ virtual bool IsDefaultController() const = 0;
+ virtual bool IsByteStreamController() const = 0;
+
// https://streams.spec.whatwg.org/#abstract-opdef-readablestreamcontroller-cancelsteps
virtual v8::Local<v8::Promise> CancelSteps(ScriptState*,
v8::Local<v8::Value> reason) = 0;
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
index 3826889c228..bc2a9194174 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
@@ -316,10 +316,10 @@ StreamPromiseResolver* ReadableStreamDefaultController::PullSteps(
// stream.[[reader]].[[forAuthorCode]]).
ReadableStreamGenericReader* reader = stream->reader_;
return StreamPromiseResolver::CreateResolved(
- script_state, ReadableStream::CreateReadResult(
- script_state, chunk, false,
- static_cast<ReadableStreamDefaultReader*>(reader)
- ->for_author_code_));
+ script_state,
+ ReadableStream::CreateReadResult(
+ script_state, chunk, false,
+ To<ReadableStreamDefaultReader>(reader)->for_author_code_));
}
// 3. Let pendingPromise be ! ReadableStreamAddReadRequest(stream).
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
index b96ce094de1..ca53eca0890 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
@@ -7,6 +7,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "v8/include/v8.h"
namespace blink {
@@ -70,6 +71,9 @@ class ReadableStreamDefaultController : public ReadableStreamController {
static const char* EnqueueExceptionMessage(
const ReadableStreamDefaultController*);
+ bool IsDefaultController() const override { return true; }
+ bool IsByteStreamController() const override { return false; }
+
void Trace(Visitor*) const override;
// https://streams.spec.whatwg.org/#rs-default-controller-private-cancel
@@ -125,6 +129,13 @@ class ReadableStreamDefaultController : public ReadableStreamController {
Member<StrategySizeAlgorithm> strategy_size_algorithm_;
};
+template <>
+struct DowncastTraits<ReadableStreamDefaultController> {
+ static bool AllowFrom(const ReadableStreamController& controller) {
+ return controller.IsDefaultController();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_CONTROLLER_H_
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
index 33c806618e7..d9b03f00ca6 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
@@ -3,6 +3,9 @@
// found in the LICENSE file.
// https://streams.spec.whatwg.org/#rs-default-controller-class-definition
+[
+ Exposed=(Window,Worker,Worklet)
+]
interface ReadableStreamDefaultController {
readonly attribute double? desiredSize;
[CallWith=ScriptState, RaisesException] void close();
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h
index 9c3dc2f15d9..9843b82e3bf 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h
@@ -8,13 +8,13 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ReadableStreamDefaultController;
class ScriptState;
-class Visitor;
class CORE_EXPORT ReadableStreamDefaultControllerWithScriptScope
: public GarbageCollected<ReadableStreamDefaultControllerWithScriptScope> {
@@ -48,6 +48,10 @@ class CORE_EXPORT ReadableStreamDefaultControllerWithScriptScope
Error(js_error);
}
+ ReadableStreamDefaultController* GetOriginalController() {
+ return controller_;
+ }
+
void Trace(Visitor*) const;
private:
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
index bb041f3f92b..089b6164764 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.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/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
@@ -28,7 +29,8 @@ ReadableStreamDefaultReader* ReadableStreamDefaultReader::Create(
ReadableStreamDefaultReader::ReadableStreamDefaultReader(
ScriptState* script_state,
ReadableStream* stream,
- ExceptionState& exception_state) {
+ ExceptionState& exception_state)
+ : ExecutionContextClient(ExecutionContext::From(script_state)) {
// https://streams.spec.whatwg.org/#default-reader-constructor
// 1. Perform ? SetUpReadableStreamDefaultReader(this, stream).
SetUpDefaultReader(script_state, this, stream, exception_state);
@@ -140,6 +142,11 @@ void ReadableStreamDefaultReader::SetUpDefaultReader(
void ReadableStreamDefaultReader::Trace(Visitor* visitor) const {
visitor->Trace(read_requests_);
ReadableStreamGenericReader::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+bool ReadableStreamDefaultReader::HasPendingActivity() const {
+ return !read_requests_.empty();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
index a313fb1985b..5ab9f590285 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
@@ -5,9 +5,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
#include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -18,7 +22,9 @@ class ScriptState;
class StreamPromiseResolver;
class CORE_EXPORT ReadableStreamDefaultReader
- : public ReadableStreamGenericReader {
+ : public ReadableStreamGenericReader,
+ public ActiveScriptWrappable<ReadableStreamDefaultReader>,
+ public ExecutionContextClient {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -32,6 +38,9 @@ class CORE_EXPORT ReadableStreamDefaultReader
ExceptionState&);
~ReadableStreamDefaultReader() override;
+ bool IsDefaultReader() const override { return true; }
+ bool IsBYOBReader() const override { return false; }
+
// https://streams.spec.whatwg.org/#default-reader-read
ScriptPromise read(ScriptState*, ExceptionState&);
@@ -53,7 +62,10 @@ class CORE_EXPORT ReadableStreamDefaultReader
void Trace(Visitor*) const override;
+ bool HasPendingActivity() const final;
+
private:
+ friend class ReadableByteStreamController;
friend class ReadableStreamDefaultController;
friend class ReadableStream;
@@ -61,6 +73,13 @@ class CORE_EXPORT ReadableStreamDefaultReader
bool for_author_code_ = true;
};
+template <>
+struct DowncastTraits<ReadableStreamDefaultReader> {
+ static bool AllowFrom(const ReadableStreamGenericReader& reader) {
+ return reader.IsDefaultReader();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
index 8fb01bee347..0dbbf86e261 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
@@ -4,7 +4,8 @@
// https://streams.spec.whatwg.org/#default-reader-class-definition
[
- Exposed=(Window,Worker,Worklet)
+ Exposed=(Window,Worker,Worklet),
+ ActiveScriptWrappable
] interface ReadableStreamDefaultReader {
[CallWith=ScriptState, RaisesException] constructor(ReadableStream stream);
[CallWith=ScriptState] readonly attribute Promise<void>
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.cc
index 52f656403da..7168d98f410 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.cc
@@ -128,7 +128,7 @@ void ReadableStreamGenericReader::GenericInitialize(
reader->owner_readable_stream_ = stream;
// 2. Set stream.[[reader]] to reader.
- stream->reader_ = static_cast<ReadableStreamDefaultReader*>(reader);
+ stream->reader_ = reader;
switch (stream->state_) {
// 3. If stream.[[state]] is "readable",
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
index 7e238447d32..dc3b75351b4 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
@@ -17,7 +18,6 @@ class ReadableStream;
class ScriptPromise;
class ScriptState;
class StreamPromiseResolver;
-class Visitor;
// The specification sometimes treats ReadableStreamDefaultReader and
// ReadableStreamBYOBReader generically. Currently ReadableStreamBYOBReader
@@ -31,6 +31,9 @@ class CORE_EXPORT ReadableStreamGenericReader : public ScriptWrappable {
ReadableStreamGenericReader();
~ReadableStreamGenericReader() override;
+ virtual bool IsDefaultReader() const = 0;
+ virtual bool IsBYOBReader() const = 0;
+
// https://streams.spec.whatwg.org/#generic-reader-closed
ScriptPromise closed(ScriptState*) const;
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_test.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_test.cc
index b596f19cfeb..adf91375067 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_test.cc
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -6,15 +6,19 @@
#include "base/optional.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/readable_stream_default_reader_or_readable_stream_byob_reader.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h"
#include "third_party/blink/renderer/core/messaging/message_channel.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/test_underlying_source.h"
#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -93,6 +97,35 @@ readAll(stream);
}
};
+// This breaks expectations for general ReadableStreamTransferringOptimizer
+// subclasses, but we don't care.
+class TestTransferringOptimizer final
+ : public ReadableStreamTransferringOptimizer {
+ USING_FAST_MALLOC(TestTransferringOptimizer);
+
+ public:
+ TestTransferringOptimizer() = default;
+
+ UnderlyingSourceBase* PerformInProcessOptimization(
+ ScriptState* script_state) override {
+ return MakeGarbageCollected<Source>(script_state);
+ }
+
+ private:
+ class Source final : public UnderlyingSourceBase {
+ public:
+ explicit Source(ScriptState* script_state)
+ : UnderlyingSourceBase(script_state) {}
+
+ ScriptPromise Start(ScriptState* script_state) override {
+ Controller()->Enqueue("foo");
+ Controller()->Enqueue(", bar");
+ Controller()->Close();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ };
+};
+
TEST_F(ReadableStreamTest, CreateWithoutArguments) {
V8TestingScope scope;
@@ -190,6 +223,42 @@ TEST_F(ReadableStreamTest, GetReader) {
EXPECT_TRUE(stream->IsDisturbed());
}
+// Testing getReader with mode BYOB.
+TEST_F(ReadableStreamTest, GetBYOBReader) {
+ V8TestingScope scope;
+ ScriptState* script_state = scope.GetScriptState();
+ v8::Isolate* isolate = scope.GetIsolate();
+
+ ScriptValue byte_stream =
+ EvalWithPrintingError(&scope, "new ReadableStream({type: 'bytes'})");
+ ReadableStream* stream{
+ V8ReadableStream::ToImplWithTypeCheck(isolate, byte_stream.V8Value())};
+ ASSERT_TRUE(stream);
+
+ EXPECT_FALSE(stream->locked());
+ EXPECT_FALSE(stream->IsLocked());
+ EXPECT_FALSE(stream->IsDisturbed());
+
+ auto* options = ReadableStreamGetReaderOptions::Create();
+ options->setMode("byob");
+
+ ReadableStreamDefaultReaderOrReadableStreamBYOBReader return_value;
+ stream->getReader(script_state, options, return_value, ASSERT_NO_EXCEPTION);
+ ReadableStreamBYOBReader* reader =
+ return_value.GetAsReadableStreamBYOBReader();
+ ASSERT_TRUE(reader);
+
+ EXPECT_TRUE(stream->locked());
+ EXPECT_TRUE(stream->IsLocked());
+ EXPECT_FALSE(stream->IsDisturbed());
+
+ NotShared<DOMArrayBufferView> view =
+ NotShared<DOMUint8Array>(DOMUint8Array::Create(1));
+ reader->read(script_state, view, ASSERT_NO_EXCEPTION);
+
+ EXPECT_TRUE(stream->IsDisturbed());
+}
+
TEST_F(ReadableStreamTest, Cancel) {
V8TestingScope scope;
ScriptState* script_state = scope.GetScriptState();
@@ -369,8 +438,9 @@ TEST_F(ReadableStreamTest, Serialize) {
stream->Serialize(script_state, channel->port1(), ASSERT_NO_EXCEPTION);
EXPECT_TRUE(stream->IsLocked());
- auto* transferred = ReadableStream::Deserialize(
- script_state, channel->port2(), ASSERT_NO_EXCEPTION);
+ auto* transferred =
+ ReadableStream::Deserialize(script_state, channel->port2(),
+ /*optimizer=*/nullptr, ASSERT_NO_EXCEPTION);
ASSERT_TRUE(transferred);
underlying_source->Enqueue(ScriptValue(isolate, V8String(isolate, "hello")));
@@ -381,6 +451,68 @@ TEST_F(ReadableStreamTest, Serialize) {
base::make_optional<String>("hello, bye"));
}
+TEST_F(ReadableStreamTest, DeserializeWithNullOptimizer) {
+ V8TestingScope scope;
+ auto optimizer = std::make_unique<ReadableStreamTransferringOptimizer>();
+ auto* script_state = scope.GetScriptState();
+ auto* isolate = scope.GetIsolate();
+
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(script_state);
+ auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_source, 0);
+ ASSERT_TRUE(stream);
+
+ auto* channel =
+ MakeGarbageCollected<MessageChannel>(scope.GetExecutionContext());
+
+ stream->Serialize(script_state, channel->port1(), ASSERT_NO_EXCEPTION);
+ EXPECT_TRUE(stream->IsLocked());
+
+ auto* transferred =
+ ReadableStream::Deserialize(script_state, channel->port2(),
+ std::move(optimizer), ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(transferred);
+
+ underlying_source->Enqueue(ScriptValue(isolate, V8String(isolate, "hello")));
+ underlying_source->Enqueue(ScriptValue(isolate, V8String(isolate, ", bye")));
+ underlying_source->Close();
+
+ EXPECT_EQ(ReadAll(scope, transferred),
+ base::make_optional<String>("hello, bye"));
+}
+
+TEST_F(ReadableStreamTest, DeserializeWithTestOptimizer) {
+ V8TestingScope scope;
+ auto optimizer = std::make_unique<TestTransferringOptimizer>();
+ auto* script_state = scope.GetScriptState();
+ auto* isolate = scope.GetIsolate();
+
+ auto* underlying_source =
+ MakeGarbageCollected<TestUnderlyingSource>(script_state);
+ auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_source, 0);
+ ASSERT_TRUE(stream);
+
+ auto* channel =
+ MakeGarbageCollected<MessageChannel>(scope.GetExecutionContext());
+
+ stream->Serialize(script_state, channel->port1(), ASSERT_NO_EXCEPTION);
+ EXPECT_TRUE(stream->IsLocked());
+
+ auto* transferred =
+ ReadableStream::Deserialize(script_state, channel->port2(),
+ std::move(optimizer), ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(transferred);
+
+ underlying_source->Enqueue(ScriptValue(isolate, V8String(isolate, "hello")));
+ underlying_source->Enqueue(ScriptValue(isolate, V8String(isolate, ", bye")));
+ underlying_source->Close();
+
+ EXPECT_EQ(ReadAll(scope, transferred),
+ base::make_optional<String>("hello, byefoo, bar"));
+}
+
TEST_F(ReadableStreamTest, GarbageCollectJavaScriptUnderlyingSource) {
V8TestingScope scope;
auto* isolate = scope.GetIsolate();
diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h b/chromium/third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h
index fee43c40a55..aafe8a25f1c 100644
--- a/chromium/third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h
+++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h
@@ -1,4 +1,4 @@
-// Copyright 2020 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.
diff --git a/chromium/third_party/blink/renderer/core/streams/stream_algorithms.h b/chromium/third_party/blink/renderer/core/streams/stream_algorithms.h
index c56a8ff7137..5362af4ed9d 100644
--- a/chromium/third_party/blink/renderer/core/streams/stream_algorithms.h
+++ b/chromium/third_party/blink/renderer/core/streams/stream_algorithms.h
@@ -8,13 +8,13 @@
#include "base/optional.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ExceptionState;
class ScriptState;
-class Visitor;
// Base class for algorithms that calculate the size of a given chunk as part of
// the stream's queuing strategy. This is the type for the
diff --git a/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.cc b/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
index 505c7b61057..9cb208904aa 100644
--- a/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
+++ b/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.h b/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.h
index b4528cf63b9..13723308f85 100644
--- a/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.h
+++ b/chromium/third_party/blink/renderer/core/streams/stream_promise_resolver.h
@@ -8,13 +8,14 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ScriptPromise;
class ScriptState;
-class Visitor;
// A thin wrapper around v8::Promise::Resolver that matches the semantics used
// for promises in the standard. StreamPromiseResolver is used for promises that
diff --git a/chromium/third_party/blink/renderer/core/streams/transferable_streams.cc b/chromium/third_party/blink/renderer/core/streams/transferable_streams.cc
index d26dca6914e..c793e966ff2 100644
--- a/chromium/third_party/blink/renderer/core/streams/transferable_streams.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transferable_streams.cc
@@ -8,9 +8,13 @@
#include "third_party/blink/renderer/core/streams/transferable_streams.h"
#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/readable_stream_default_reader_or_readable_stream_byob_reader.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_post_message_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_default_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
@@ -20,13 +24,18 @@
#include "third_party/blink/renderer/core/streams/promise_handler.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.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/assertions.h"
@@ -50,6 +59,12 @@ namespace blink {
namespace {
+template <typename T, typename... Args>
+NewScriptFunction* CreateFunction(ScriptState* script_state, Args&&... args) {
+ return MakeGarbageCollected<NewScriptFunction>(
+ script_state, MakeGarbageCollected<T>(std::forward<Args>(args)...));
+}
+
// These are the types of messages that are sent between peers.
enum class MessageType { kPull, kChunk, kClose, kError };
@@ -737,6 +752,168 @@ class CrossRealmTransformReadable::CancelAlgorithm final
const Member<CrossRealmTransformReadable> readable_;
};
+class ConcatenatingUnderlyingSource final : public UnderlyingSourceBase {
+ public:
+ using Constant = NewScriptFunction::Constant;
+
+ class PullSource2 final : public NewScriptFunction::Callable {
+ public:
+ explicit PullSource2(ConcatenatingUnderlyingSource* source)
+ : source_(source) {}
+
+ ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
+ return source_->source2_->pull(script_state).AsScriptValue();
+ }
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(source_);
+ NewScriptFunction::Callable::Trace(visitor);
+ }
+
+ private:
+ const Member<ConcatenatingUnderlyingSource> source_;
+ };
+
+ class OnReadingSource1Success final : public NewScriptFunction::Callable {
+ public:
+ explicit OnReadingSource1Success(ConcatenatingUnderlyingSource* source)
+ : source_(source) {}
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(source_);
+ NewScriptFunction::Callable::Trace(visitor);
+ }
+ ScriptValue Call(ScriptState* script_state,
+ ScriptValue read_result) override {
+ DCHECK(read_result.IsObject());
+ bool done = false;
+ v8::Local<v8::Value> value =
+ V8UnpackIteratorResult(script_state,
+ read_result.V8Value().As<v8::Object>(), &done)
+ .ToLocalChecked();
+ if (done) {
+ // We've finished reading `source1_`. Let's start reading `source2_`.
+ source_->has_finished_reading_stream1_ = true;
+ ReadableStreamDefaultController* controller =
+ source_->Controller()->GetOriginalController();
+ return source_->source2_
+ ->startWrapper(script_state,
+ ScriptValue::From(script_state, controller))
+ .Then(CreateFunction<PullSource2>(script_state, source_))
+ .AsScriptValue();
+ }
+ source_->Controller()->Enqueue(value);
+ return ScriptPromise::CastUndefined(script_state).AsScriptValue();
+ }
+
+ private:
+ const Member<ConcatenatingUnderlyingSource> source_;
+ };
+
+ class OnReadingSource1Fail final : public NewScriptFunction::Callable {
+ public:
+ explicit OnReadingSource1Fail(ConcatenatingUnderlyingSource* source)
+ : source_(source) {}
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(source_);
+ NewScriptFunction::Callable::Trace(visitor);
+ }
+
+ ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
+ ScriptValue reason(script_state->GetIsolate(),
+ v8::Undefined(script_state->GetIsolate()));
+
+ ReadableStream* dummy_stream =
+ ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, source_->source2_,
+ /*high_water_mark=*/0);
+ ExceptionState exception_state(script_state->GetIsolate(),
+ ExceptionState::kUnknownContext, "", "");
+ dummy_stream->cancel(script_state, reason, exception_state);
+ // We don't care about the result of the cancellation, including
+ // exceptions.
+ exception_state.ClearException();
+
+ return ScriptPromise::Reject(script_state, value).AsScriptValue();
+ }
+
+ private:
+ const Member<ConcatenatingUnderlyingSource> source_;
+ };
+
+ ConcatenatingUnderlyingSource(ScriptState* script_state,
+ ReadableStream* stream1,
+ UnderlyingSourceBase* source2)
+ : UnderlyingSourceBase(script_state),
+ stream1_(stream1),
+ source2_(source2) {}
+
+ ScriptPromise Start(ScriptState* script_state) override {
+ ExceptionState exception_state(script_state->GetIsolate(),
+ ExceptionState::kUnknownContext, "", "");
+ reader_for_stream1_ = ReadableStream::AcquireDefaultReader(
+ script_state, stream1_, /*for_author_code=*/false, exception_state);
+ if (exception_state.HadException()) {
+ return ScriptPromise::Reject(script_state, exception_state);
+ }
+ DCHECK(reader_for_stream1_);
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise pull(ScriptState* script_state) override {
+ if (has_finished_reading_stream1_) {
+ return source2_->pull(script_state);
+ }
+ ExceptionState exception_state(script_state->GetIsolate(),
+ ExceptionState::kUnknownContext, "", "");
+ ScriptPromise read_promise =
+ reader_for_stream1_->read(script_state, exception_state);
+ if (exception_state.HadException()) {
+ return ScriptPromise::Reject(script_state, exception_state);
+ }
+ return read_promise.Then(
+ CreateFunction<OnReadingSource1Success>(script_state, this),
+ CreateFunction<OnReadingSource1Fail>(script_state, this));
+ }
+
+ ScriptPromise Cancel(ScriptState* script_state, ScriptValue reason) override {
+ if (has_finished_reading_stream1_) {
+ return source2_->Cancel(script_state, reason);
+ }
+ ExceptionState exception_state(script_state->GetIsolate(),
+ ExceptionState::kUnknownContext, "", "");
+ ScriptPromise cancel_promise1 =
+ reader_for_stream1_->cancel(script_state, reason, exception_state);
+ if (exception_state.HadException()) {
+ cancel_promise1 = ScriptPromise::Reject(script_state, exception_state);
+ }
+
+ ReadableStream* dummy_stream =
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source2_,
+ /*high_water_mark=*/0);
+ ScriptPromise cancel_promise2 =
+ dummy_stream->cancel(script_state, reason, exception_state);
+ if (exception_state.HadException()) {
+ cancel_promise2 = ScriptPromise::Reject(script_state, exception_state);
+ }
+
+ return ScriptPromise::All(script_state, {cancel_promise1, cancel_promise2});
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(stream1_);
+ visitor->Trace(reader_for_stream1_);
+ visitor->Trace(source2_);
+ UnderlyingSourceBase::Trace(visitor);
+ }
+
+ private:
+ Member<ReadableStream> stream1_;
+ Member<ReadableStreamDefaultReader> reader_for_stream1_;
+ bool has_finished_reading_stream1_ = false;
+ Member<UnderlyingSourceBase> source2_;
+};
+
ReadableStream* CrossRealmTransformReadable::CreateReadableStream(
ExceptionState& exception_state) {
DCHECK(!controller_) << "CreateReadableStream can only be called once";
@@ -770,7 +947,10 @@ ReadableStream* CrossRealmTransformReadable::CreateReadableStream(
return nullptr;
}
- controller_ = stream->GetController();
+ // The stream is created right above, and the type of the source is not given,
+ // hence it is guaranteed that the controller is a
+ // ReadableStreamDefaultController.
+ controller_ = To<ReadableStreamDefaultController>(stream->GetController());
return stream;
}
@@ -839,17 +1019,67 @@ void CrossRealmTransformReadable::HandleError(v8::Local<v8::Value> error) {
CORE_EXPORT WritableStream* CreateCrossRealmTransformWritable(
ScriptState* script_state,
MessagePort* port,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer,
ExceptionState& exception_state) {
- return MakeGarbageCollected<CrossRealmTransformWritable>(script_state, port)
- ->CreateWritableStream(exception_state);
+ WritableStream* stream =
+ MakeGarbageCollected<CrossRealmTransformWritable>(script_state, port)
+ ->CreateWritableStream(exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+ if (!optimizer) {
+ return stream;
+ }
+ UnderlyingSinkBase* sink =
+ optimizer->PerformInProcessOptimization(script_state);
+ if (!sink) {
+ return stream;
+ }
+ stream->close(script_state, exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+
+ return WritableStream::CreateWithCountQueueingStrategy(script_state, sink,
+ /*high_water_mark=*/1);
}
CORE_EXPORT ReadableStream* CreateCrossRealmTransformReadable(
ScriptState* script_state,
MessagePort* port,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer,
ExceptionState& exception_state) {
- return MakeGarbageCollected<CrossRealmTransformReadable>(script_state, port)
- ->CreateReadableStream(exception_state);
+ ReadableStream* stream =
+ MakeGarbageCollected<CrossRealmTransformReadable>(script_state, port)
+ ->CreateReadableStream(exception_state);
+ if (!optimizer) {
+ return stream;
+ }
+ UnderlyingSourceBase* source2 =
+ optimizer->PerformInProcessOptimization(script_state);
+ if (!source2) {
+ return stream;
+ }
+
+ return ReadableStream::CreateWithCountQueueingStrategy(
+ script_state,
+ MakeGarbageCollected<ConcatenatingUnderlyingSource>(script_state, stream,
+ source2),
+ /*high_water_mark=*/0);
+}
+
+ReadableStream* CreateConcatenatedReadableStream(
+ ScriptState* script_state,
+ UnderlyingSourceBase* source1,
+ UnderlyingSourceBase* source2) {
+ auto* const stream1 =
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source1,
+ /*high_water_mark=*/0);
+ return ReadableStream::CreateWithCountQueueingStrategy(
+ script_state,
+ MakeGarbageCollected<ConcatenatingUnderlyingSource>(script_state, stream1,
+ source2),
+ /*high_water_mark=*/0);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/transferable_streams.h b/chromium/third_party/blink/renderer/core/streams/transferable_streams.h
index 3c75195255e..dbace5ce634 100644
--- a/chromium/third_party/blink/renderer/core/streams/transferable_streams.h
+++ b/chromium/third_party/blink/renderer/core/streams/transferable_streams.h
@@ -7,6 +7,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFERABLE_STREAMS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFERABLE_STREAMS_H_
+#include <memory>
+
#include "third_party/blink/renderer/core/core_export.h"
namespace blink {
@@ -14,25 +16,42 @@ namespace blink {
class ExceptionState;
class MessagePort;
class ReadableStream;
+class ReadableStreamTransferringOptimizer;
class ScriptState;
+class UnderlyingSourceBase;
class WritableStream;
+class WritableStreamTransferringOptimizer;
// Creates the writable side of a cross-realm identity transform stream, using
// |port| for communication. |port| must be entangled with another MessagePort
// which is passed to CreateCrossRealmTransformReadable().
// Equivalent to SetUpCrossRealmTransformWritable in the standard:
// https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable
-CORE_EXPORT WritableStream* CreateCrossRealmTransformWritable(ScriptState*,
- MessagePort* port,
- ExceptionState&);
+CORE_EXPORT WritableStream* CreateCrossRealmTransformWritable(
+ ScriptState*,
+ MessagePort* port,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer,
+ ExceptionState&);
// Creates the readable side of a cross-realm identity transform stream. |port|
// is used symmetrically with CreateCrossRealmTransformWritable().
// Equivalent to SetUpCrossRealmTransformReadable in the standard:
// https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
-CORE_EXPORT ReadableStream* CreateCrossRealmTransformReadable(ScriptState*,
- MessagePort* port,
- ExceptionState&);
+CORE_EXPORT ReadableStream* CreateCrossRealmTransformReadable(
+ ScriptState*,
+ MessagePort* port,
+ std::unique_ptr<ReadableStreamTransferringOptimizer> optimizer,
+ ExceptionState&);
+
+// Creates a ReadableStream that is identical to the concatenation of
+// a ReadableStream created with `source1` and a ReadableStream created with
+// `source2`.
+// The implementation is optimized with an assumption that `source2` is (much)
+// longer than `source1`.
+CORE_EXPORT ReadableStream* CreateConcatenatedReadableStream(
+ ScriptState*,
+ UnderlyingSourceBase* source1,
+ UnderlyingSourceBase* source2);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/transferable_streams_test.cc b/chromium/third_party/blink/renderer/core/streams/transferable_streams_test.cc
index 0bf3d389f4b..19d12ac49cc 100644
--- a/chromium/third_party/blink/renderer/core/streams/transferable_streams_test.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transferable_streams_test.cc
@@ -4,27 +4,155 @@
#include "third_party/blink/renderer/core/streams/transferable_streams.h"
+#include "base/types/strong_alias.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/readable_stream_default_reader_or_readable_stream_byob_reader.h"
#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/script_promise_resolver.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_readable_stream_default_reader.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream_default_writer.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/messaging/message_channel.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/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "v8/include/v8.h"
namespace blink {
namespace {
+enum class SourceType { kPush, kPull };
+
+class TestUnderlyingSource final : public UnderlyingSourceBase {
+ public:
+ TestUnderlyingSource(SourceType source_type,
+ ScriptState* script_state,
+ Vector<int> sequence,
+ ScriptPromise start_promise)
+ : UnderlyingSourceBase(script_state),
+ type_(source_type),
+ sequence_(std::move(sequence)),
+ start_promise_(start_promise) {}
+ TestUnderlyingSource(SourceType source_type,
+ ScriptState* script_state,
+ Vector<int> sequence)
+ : TestUnderlyingSource(source_type,
+ script_state,
+ std::move(sequence),
+ ScriptPromise::CastUndefined(script_state)) {}
+ ~TestUnderlyingSource() override = default;
+
+ ScriptPromise Start(ScriptState* script_state) override {
+ started_ = true;
+ if (type_ == SourceType::kPush) {
+ for (int element : sequence_) {
+ EnqueueOrError(script_state, element);
+ }
+ index_ = sequence_.size();
+ Controller()->Close();
+ }
+ return start_promise_;
+ }
+ ScriptPromise pull(ScriptState* script_state) override {
+ if (type_ == SourceType::kPush) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ if (index_ == sequence_.size()) {
+ Controller()->Close();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ EnqueueOrError(script_state, sequence_[index_]);
+ ++index_;
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ ScriptPromise Cancel(ScriptState* script_state, ScriptValue reason) override {
+ cancelled_ = true;
+ cancel_reason_ = reason;
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ bool IsStarted() const { return started_; }
+ bool IsCancelled() const { return cancelled_; }
+ ScriptValue CancelReason() const { return cancel_reason_; }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(start_promise_);
+ visitor->Trace(cancel_reason_);
+ UnderlyingSourceBase::Trace(visitor);
+ }
+
+ private:
+ void EnqueueOrError(ScriptState* script_state, int num) {
+ if (num < 0) {
+ Controller()->Error(V8ThrowException::CreateRangeError(
+ script_state->GetIsolate(), "foo"));
+ return;
+ }
+ Controller()->Enqueue(num);
+ }
+
+ const SourceType type_;
+ const Vector<int> sequence_;
+ wtf_size_t index_ = 0;
+
+ const ScriptPromise start_promise_;
+ bool started_ = false;
+ bool cancelled_ = false;
+ ScriptValue cancel_reason_;
+};
+
+void ExpectValue(int line,
+ ScriptState* script_state,
+ v8::Local<v8::Value> result,
+ int32_t expectation) {
+ SCOPED_TRACE(testing::Message() << "__LINE__ = " << line);
+ if (!result->IsObject()) {
+ ADD_FAILURE() << "The result is not an Object.";
+ return;
+ }
+ v8::Local<v8::Value> value;
+ bool done = false;
+ if (!V8UnpackIteratorResult(script_state, result.As<v8::Object>(), &done)
+ .ToLocal(&value)) {
+ ADD_FAILURE() << "Failed to unpack the iterator result.";
+ return;
+ }
+ EXPECT_FALSE(done);
+ if (!value->IsInt32()) {
+ ADD_FAILURE() << "The value is not an int32.";
+ return;
+ }
+ EXPECT_EQ(value.As<v8::Number>()->Value(), expectation);
+}
+
+void ExpectDone(int line,
+ ScriptState* script_state,
+ v8::Local<v8::Value> result) {
+ SCOPED_TRACE(testing::Message() << "__LINE__ = " << line);
+ v8::Local<v8::Value> value;
+ bool done = false;
+ if (!V8UnpackIteratorResult(script_state, result.As<v8::Object>(), &done)
+ .ToLocal(&value)) {
+ ADD_FAILURE() << "Failed to unpack the iterator result.";
+ return;
+ }
+ EXPECT_TRUE(done);
+}
+
// We only do minimal testing here. The functionality of transferable streams is
// tested in the layout tests.
TEST(TransferableStreamsTest, SmokeTest) {
@@ -34,10 +162,12 @@ TEST(TransferableStreamsTest, SmokeTest) {
MakeGarbageCollected<MessageChannel>(scope.GetExecutionContext());
auto* script_state = scope.GetScriptState();
auto* writable = CreateCrossRealmTransformWritable(
- script_state, channel->port1(), ASSERT_NO_EXCEPTION);
+ script_state, channel->port1(), /*optimizer=*/nullptr,
+ ASSERT_NO_EXCEPTION);
ASSERT_TRUE(writable);
auto* readable = CreateCrossRealmTransformReadable(
- script_state, channel->port2(), ASSERT_NO_EXCEPTION);
+ script_state, channel->port2(), /*optimizer=*/nullptr,
+ ASSERT_NO_EXCEPTION);
ASSERT_TRUE(readable);
auto* writer = writable->getWriter(script_state, ASSERT_NO_EXCEPTION);
@@ -120,6 +250,366 @@ TEST(TransferableStreamsTest, SmokeTest) {
EXPECT_TRUE(got_response);
}
+TEST(ConcatenatedReadableStreamTest, Empty) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectDone(__LINE__, script_state, read_promise->Result());
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_TRUE(source2->IsStarted());
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_FALSE(source2->IsCancelled());
+}
+
+TEST(ConcatenatedReadableStreamTest, SuccessfulRead) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5, 6}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source2->IsStarted());
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 5);
+ EXPECT_TRUE(source2->IsStarted());
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 6);
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectDone(__LINE__, script_state, read_promise->Result());
+ }
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_FALSE(source2->IsCancelled());
+}
+
+TEST(ConcatenatedReadableStreamTest, SuccessfulReadForPushSources) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPush, script_state, Vector<int>({1}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPush, script_state, Vector<int>({5, 6}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source2->IsStarted());
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 5);
+ EXPECT_TRUE(source2->IsStarted());
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 6);
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectDone(__LINE__, script_state, read_promise->Result());
+ }
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_FALSE(source2->IsCancelled());
+}
+
+TEST(ConcatenatedReadableStreamTest, ErrorInSource1) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1, -2}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5, 6}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kRejected);
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_TRUE(source2->IsStarted());
+ EXPECT_TRUE(source2->IsCancelled());
+}
+
+TEST(ConcatenatedReadableStreamTest, ErrorInSource2) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({-2}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kRejected);
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_TRUE(source2->IsStarted());
+ EXPECT_FALSE(source2->IsCancelled());
+}
+
+TEST(ConcatenatedReadableStreamTest, Cancel1) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1, 2}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5, 6}));
+
+ ScriptValue reason = ScriptValue::From(script_state, "hello");
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_FALSE(source2->IsStarted());
+ EXPECT_FALSE(source2->IsCancelled());
+ {
+ reader->cancel(script_state, reason, ASSERT_NO_EXCEPTION);
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_TRUE(source1->IsCancelled());
+ EXPECT_EQ(reason, source1->CancelReason());
+ EXPECT_TRUE(source2->IsStarted());
+ EXPECT_TRUE(source2->IsCancelled());
+ EXPECT_EQ(reason, source2->CancelReason());
+}
+
+TEST(ConcatenatedReadableStreamTest, Cancel2) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5}));
+
+ ScriptValue reason = ScriptValue::From(script_state, "hello");
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 5);
+ }
+ {
+ reader->cancel(script_state, reason, ASSERT_NO_EXCEPTION);
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source1->IsCancelled());
+ EXPECT_TRUE(source2->IsStarted());
+ EXPECT_TRUE(source2->IsCancelled());
+ EXPECT_EQ(reason, source2->CancelReason());
+}
+
+TEST(ConcatenatedReadableStreamTest, PendingStart1) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1, 2}),
+ resolver->Promise());
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5, 6}));
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kPending);
+
+ resolver->Resolve();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_FALSE(source2->IsStarted());
+}
+
+TEST(ConcatenatedReadableStreamTest, PendingStart2) {
+ V8TestingScope scope;
+ auto* script_state = scope.GetScriptState();
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ TestUnderlyingSource* source1 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({1}));
+ TestUnderlyingSource* source2 = MakeGarbageCollected<TestUnderlyingSource>(
+ SourceType::kPull, script_state, Vector<int>({5, 6}),
+ resolver->Promise());
+
+ ReadableStream* stream =
+ CreateConcatenatedReadableStream(script_state, source1, source2);
+ ASSERT_TRUE(stream);
+
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ ASSERT_TRUE(reader);
+
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 1);
+ }
+ {
+ v8::Local<v8::Promise> read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION).V8Promise();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kPending);
+
+ resolver->Resolve();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_EQ(read_promise->State(), v8::Promise::kFulfilled);
+ ExpectValue(__LINE__, script_state, read_promise->Result(), 5);
+ }
+ EXPECT_TRUE(source1->IsStarted());
+ EXPECT_TRUE(source2->IsStarted());
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
index bd3f3061642..884e5182014 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -21,7 +21,6 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -55,7 +54,7 @@ class TransformStream::FlushAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
- return promise.V8Value().As<v8::Promise>();
+ return promise.V8Promise();
}
// SetController() must be called before Run() is.
@@ -101,7 +100,7 @@ class TransformStream::TransformAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
- return promise.V8Value().As<v8::Promise>();
+ return promise.V8Promise();
}
// SetController() must be called before Run() is.
@@ -262,6 +261,13 @@ TransformStream::TransformStream(ReadableStream* readable,
WritableStream* writable)
: readable_(readable), writable_(writable) {}
+ReadableStreamDefaultController* TransformStream::GetReadableController() {
+ // The type of source is not given when constructing the readable stream in
+ // TranformStream, so it is guaranteed that the controller is a
+ // ReadableStreamDefaultController.
+ return To<ReadableStreamDefaultController>(readable_->GetController());
+}
+
void TransformStream::Trace(Visitor* visitor) const {
visitor->Trace(backpressure_change_promise_);
visitor->Trace(readable_);
@@ -437,7 +443,6 @@ class TransformStream::DefaultSinkCloseAlgorithm final
DCHECK_EQ(argc, 0);
// https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm
// 1. Let readable be stream.[[readable]].
- ReadableStream* readable = stream_->readable_;
// 2. Let controller be stream.[[transformStreamController]].
TransformStreamDefaultController* controller =
@@ -453,24 +458,24 @@ class TransformStream::DefaultSinkCloseAlgorithm final
class ResolveFunction final : public PromiseHandlerWithValue {
public:
- ResolveFunction(ScriptState* script_state, ReadableStream* readable)
- : PromiseHandlerWithValue(script_state), readable_(readable) {}
+ ResolveFunction(ScriptState* script_state, TransformStream* stream)
+ : PromiseHandlerWithValue(script_state), stream_(stream) {}
v8::Local<v8::Value> CallWithLocal(v8::Local<v8::Value>) override {
// 5. Return the result of transforming flushPromise with:
// a. A fulfillment handler that performs the following steps:
// i. If readable.[[state]] is "errored", throw
// readable.[[storedError]].
- if (ReadableStream::IsErrored(readable_)) {
+ if (ReadableStream::IsErrored(stream_->readable_)) {
// Returning a rejection is equivalent to throwing here.
- return PromiseReject(
- GetScriptState(),
- readable_->GetStoredError(GetScriptState()->GetIsolate()));
+ return PromiseReject(GetScriptState(),
+ stream_->readable_->GetStoredError(
+ GetScriptState()->GetIsolate()));
}
// ii. Let readableController be
// readable.[[readableStreamController]].
- auto* readable_controller = readable_->GetController();
+ auto* readable_controller = stream_->GetReadableController();
// iii. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(
// readableController) is true, perform !
@@ -485,12 +490,12 @@ class TransformStream::DefaultSinkCloseAlgorithm final
}
void Trace(Visitor* visitor) const override {
- visitor->Trace(readable_);
+ visitor->Trace(stream_);
PromiseHandlerWithValue::Trace(visitor);
}
private:
- Member<ReadableStream> readable_;
+ Member<TransformStream> stream_;
};
class RejectFunction final : public PromiseHandlerWithValue {
@@ -522,7 +527,7 @@ class TransformStream::DefaultSinkCloseAlgorithm final
// 5. Return the result of transforming flushPromise ...
return StreamThenPromise(
script_state->GetContext(), flush_promise,
- MakeGarbageCollected<ResolveFunction>(script_state, readable),
+ MakeGarbageCollected<ResolveFunction>(script_state, stream_),
MakeGarbageCollected<RejectFunction>(script_state, stream_));
}
@@ -828,9 +833,8 @@ void TransformStream::Error(ScriptState* script_state,
// https://streams.spec.whatwg.org/#transform-stream-error
// 1. Perform ! ReadableStreamDefaultControllerError(stream.[[readable]].
// [[readableStreamController]], e).
- ReadableStream* readable = stream->readable_;
ReadableStreamDefaultController::Error(script_state,
- readable->GetController(), e);
+ stream->GetReadableController(), e);
// 2. Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, e).
ErrorWritableAndUnblockWrite(script_state, stream, e);
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.h b/chromium/third_party/blink/renderer/core/streams/transform_stream.h
index 1db4d3c6565..64b8fa71c0c 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream.h
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.h
@@ -9,12 +9,14 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ExceptionState;
class ReadableStream;
+class ReadableStreamDefaultController;
class ScriptState;
class StrategySizeAlgorithm;
class StreamAlgorithm;
@@ -22,7 +24,6 @@ class StreamPromiseResolver;
class StreamStartAlgorithm;
class TransformStreamDefaultController;
class TransformStreamTransformer;
-class Visitor;
class WritableStream;
// Implementation of TransformStream for Blink. See
@@ -124,6 +125,8 @@ class CORE_EXPORT TransformStream final : public ScriptWrappable {
TransformStream*,
bool backpressure);
+ ReadableStreamDefaultController* GetReadableController();
+
// The [[backpressure]] internal slot from the standard is here called
// |had_backpressure_| to conform to Blink style. The initial value is
// *undefined* in the standard, but it is set to *true* by
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
index fc1749b6004..2929929e70f 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
@@ -16,21 +16,30 @@
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.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/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
TransformStreamDefaultController::TransformStreamDefaultController() = default;
TransformStreamDefaultController::~TransformStreamDefaultController() = default;
+ReadableStreamDefaultController*
+TransformStreamDefaultController::GetDefaultController(
+ TransformStream* stream) {
+ // The TransformStreamDefaultController will always use a
+ // ReadableStreamDefaultController. Hence, it is safe to down-cast here.
+ return To<ReadableStreamDefaultController>(
+ stream->readable_->GetController());
+}
+
base::Optional<double> TransformStreamDefaultController::desiredSize() const {
// https://streams.spec.whatwg.org/#ts-default-controller-desired-size
// 2. Let readableController be
// this.[[controlledTransformStream]].[[readable]].
// [[readableStreamController]].
const auto* readable_controller =
- controlled_transform_stream_->readable_->GetController();
+ GetDefaultController(controlled_transform_stream_);
// 3. Return !
// ReadableStreamDefaultControllerGetDesiredSize(readableController).
@@ -249,7 +258,7 @@ void TransformStreamDefaultController::Enqueue(
// 2. Let readableController be
// stream.[[readable]].[[readableStreamController]].
- auto* readable_controller = stream->readable_->GetController();
+ auto* readable_controller = GetDefaultController(stream);
// 3. If !
// ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
@@ -360,7 +369,7 @@ void TransformStreamDefaultController::Terminate(
// 2. Let readableController be
// stream.[[readable]].[[readableStreamController]].
ReadableStreamDefaultController* readable_controller =
- stream->readable_->GetController();
+ GetDefaultController(stream);
// 3. If !
// ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.h b/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
index f4d188b1449..b274e19f30c 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
@@ -8,15 +8,16 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
class ExceptionState;
+class ReadableStreamDefaultController;
class ScriptState;
class StreamAlgorithm;
class TransformStream;
-class Visitor;
class CORE_EXPORT TransformStreamDefaultController : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -82,6 +83,9 @@ class CORE_EXPORT TransformStreamDefaultController : public ScriptWrappable {
// https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate
static void Terminate(ScriptState*, TransformStreamDefaultController*);
+ static ReadableStreamDefaultController* GetDefaultController(
+ TransformStream*);
+
Member<TransformStream> controlled_transform_stream_;
Member<StreamAlgorithm> flush_algorithm_;
Member<StreamAlgorithm> transform_algorithm_;
diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream_transformer.h b/chromium/third_party/blink/renderer/core/streams/transform_stream_transformer.h
index 48ac197c709..530b2c9ee07 100644
--- a/chromium/third_party/blink/renderer/core/streams/transform_stream_transformer.h
+++ b/chromium/third_party/blink/renderer/core/streams/transform_stream_transformer.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
@@ -17,7 +18,6 @@ class ExceptionState;
class ScriptPromise;
class ScriptState;
class TransformStreamDefaultController;
-class Visitor;
// Interface to be implemented by C++ code that needs to create a
// TransformStream. Based on the JavaScript [Transformer
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source.idl
new file mode 100644
index 00000000000..dfc0184be03
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source.idl
@@ -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.
+
+// https://streams.spec.whatwg.org/#dictdef-underlyingsource
+
+dictionary UnderlyingSource {
+ UnderlyingSourceStartCallback start;
+ UnderlyingSourcePullCallback pull;
+ UnderlyingSourceCancelCallback cancel;
+ ReadableStreamType type;
+ [EnforceRange] unsigned long long autoAllocateChunkSize;
+};
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.h b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.h
index d1ccf1a0ee3..37c944665c3 100644
--- a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.h
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.h
@@ -29,7 +29,7 @@ class CORE_EXPORT UnderlyingSourceBase
void Trace(Visitor*) const override;
~UnderlyingSourceBase() override = default;
- ScriptPromise startWrapper(ScriptState*, ScriptValue stream);
+ ScriptPromise startWrapper(ScriptState*, ScriptValue controller);
virtual ScriptPromise Start(ScriptState*);
virtual ScriptPromise pull(ScriptState*);
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl
new file mode 100644
index 00000000000..1b671b8b130
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl
@@ -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.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcecancelcallback
+
+callback UnderlyingSourceCancelCallback = Promise<void> (optional any reason);
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl
new file mode 100644
index 00000000000..9f69e86c8dd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl
@@ -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.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcepullcallback
+
+callback UnderlyingSourcePullCallback = Promise<void> (ReadableStreamController controller);
diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl
new file mode 100644
index 00000000000..e20a211de06
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl
@@ -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.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcestartcallback
+
+callback UnderlyingSourceStartCallback = any (ReadableStreamController controller);
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
index 8c3dcfd537b..eda57163385 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc
@@ -11,11 +11,13 @@
#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
#include "third_party/blink/renderer/core/streams/promise_handler.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
#include "third_party/blink/renderer/core/streams/transferable_streams.h"
#include "third_party/blink/renderer/core/streams/underlying_sink_base.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/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
@@ -199,6 +201,16 @@ WritableStream* WritableStream::CreateWithCountQueueingStrategy(
ScriptState* script_state,
UnderlyingSinkBase* underlying_sink,
size_t high_water_mark) {
+ return CreateWithCountQueueingStrategy(script_state, underlying_sink,
+ high_water_mark,
+ /*optimizer=*/nullptr);
+}
+
+WritableStream* WritableStream::CreateWithCountQueueingStrategy(
+ ScriptState* script_state,
+ UnderlyingSinkBase* underlying_sink,
+ size_t high_water_mark,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer) {
// TODO(crbug.com/902633): This method of constructing a WritableStream
// introduces unnecessary trips through V8. Implement algorithms based on an
// UnderlyingSinkBase.
@@ -219,6 +231,8 @@ WritableStream* WritableStream::CreateWithCountQueueingStrategy(
exception_state);
if (exception_state.HadException())
return nullptr;
+
+ stream->transferring_optimizer_ = std::move(optimizer);
return stream;
}
@@ -240,8 +254,8 @@ void WritableStream::Serialize(ScriptState* script_state,
// 5. Let readable be a new ReadableStream in the current Realm.
// 6. Perform ! SetUpCrossRealmTransformReadable(readable, port1).
- auto* readable =
- CreateCrossRealmTransformReadable(script_state, port, exception_state);
+ auto* readable = CreateCrossRealmTransformReadable(
+ script_state, port, /*optimizer=*/nullptr, exception_state);
if (exception_state.HadException()) {
return;
}
@@ -260,9 +274,11 @@ void WritableStream::Serialize(ScriptState* script_state,
// port2 »).
}
-WritableStream* WritableStream::Deserialize(ScriptState* script_state,
- MessagePort* port,
- ExceptionState& exception_state) {
+WritableStream* WritableStream::Deserialize(
+ ScriptState* script_state,
+ MessagePort* port,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer,
+ ExceptionState& exception_state) {
// We need to execute JavaScript to call "Then" on v8::Promises. We will not
// run author code.
v8::Isolate::AllowJavascriptExecutionScope allow_js(
@@ -278,8 +294,8 @@ WritableStream* WritableStream::Deserialize(ScriptState* script_state,
// 3. Perform ! SetUpCrossRealmTransformWritable(value, port).
// In the standard |value| contains an unitialized WritableStream. In the
// implementation, we create the stream here.
- auto* writable =
- CreateCrossRealmTransformWritable(script_state, port, exception_state);
+ auto* writable = CreateCrossRealmTransformWritable(
+ script_state, port, std::move(optimizer), exception_state);
if (exception_state.HadException()) {
return nullptr;
}
@@ -816,6 +832,11 @@ void WritableStream::SetWriter(WritableStreamDefaultWriter* writer) {
writer_ = writer;
}
+std::unique_ptr<WritableStreamTransferringOptimizer>
+WritableStream::TakeTransferringOptimizer() {
+ return std::move(transferring_optimizer_);
+}
+
// static
v8::Local<v8::String> WritableStream::CreateCannotActionOnStateStreamMessage(
v8::Isolate* isolate,
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.h b/chromium/third_party/blink/renderer/core/streams/writable_stream.h
index c6e012bdb9a..85bde28c2c5 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream.h
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_H_
+#include <memory>
+
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
@@ -28,6 +30,7 @@ class StreamStartAlgorithm;
class UnderlyingSinkBase;
class WritableStreamDefaultController;
class WritableStreamDefaultWriter;
+class WritableStreamTransferringOptimizer;
class CORE_EXPORT WritableStream : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -66,6 +69,11 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
ScriptState*,
UnderlyingSinkBase*,
size_t high_water_mark);
+ static WritableStream* CreateWithCountQueueingStrategy(
+ ScriptState*,
+ UnderlyingSinkBase*,
+ size_t high_water_mark,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer);
// Called by Create().
WritableStream();
@@ -96,9 +104,11 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
void Serialize(ScriptState*, MessagePort*, ExceptionState&);
- static WritableStream* Deserialize(ScriptState*,
- MessagePort*,
- ExceptionState&);
+ static WritableStream* Deserialize(
+ ScriptState*,
+ MessagePort*,
+ std::unique_ptr<WritableStreamTransferringOptimizer> optimizer,
+ ExceptionState&);
//
// Methods used by ReadableStream::PipeTo
@@ -201,6 +211,9 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
void SetController(WritableStreamDefaultController*);
void SetWriter(WritableStreamDefaultWriter*);
+ std::unique_ptr<WritableStreamTransferringOptimizer>
+ TakeTransferringOptimizer();
+
// Utility methods shared with other classes.
static v8::Local<v8::String> CreateCannotActionOnStateStreamMessage(
v8::Isolate*,
@@ -259,6 +272,7 @@ class CORE_EXPORT WritableStream : public ScriptWrappable {
Member<WritableStreamDefaultController> writable_stream_controller_;
Member<WritableStreamDefaultWriter> writer_;
PromiseQueue write_requests_;
+ std::unique_ptr<WritableStreamTransferringOptimizer> transferring_optimizer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
index d366fe47be4..cc76647826c 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
@@ -16,7 +16,6 @@
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.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/assertions.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.h b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
index 191a06daa48..3351dcd6941 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
@@ -18,7 +19,6 @@ class ScriptValue;
class StrategySizeAlgorithm;
class StreamAlgorithm;
class StreamStartAlgorithm;
-class Visitor;
class WritableStreamDefaultWriter;
class WritableStream;
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
index 940f5a964ba..d3e696f1fe4 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.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/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.h b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.h
index f81f40b9326..c9ae03f8be9 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.h
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_default_writer.h
@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "v8/include/v8.h"
namespace blink {
@@ -17,7 +18,6 @@ class ScriptPromise;
class ScriptState;
class ScriptValue;
class StreamPromiseResolver;
-class Visitor;
class WritableStream;
class WritableStream;
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_test.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream_test.cc
index dcfec54ebb9..c8813cee708 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_test.cc
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_test.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.h"
#include "third_party/blink/renderer/core/messaging/message_channel.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -71,8 +72,9 @@ underlying_sink)JS";
stream->Serialize(script_state, channel->port1(), ASSERT_NO_EXCEPTION);
EXPECT_TRUE(stream->locked());
- auto* transferred = WritableStream::Deserialize(
- script_state, channel->port2(), ASSERT_NO_EXCEPTION);
+ auto* transferred =
+ WritableStream::Deserialize(script_state, channel->port2(),
+ /*optimizer=*/nullptr, ASSERT_NO_EXCEPTION);
ASSERT_TRUE(transferred);
WritableStreamDefaultWriter* writer =
diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h b/chromium/third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h
index a5858b86058..d6e34461ab4 100644
--- a/chromium/third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h
+++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium AUthors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this sink code is governed by a BSD-style license that can be found
// in the LICENSE file.
diff --git a/chromium/third_party/blink/renderer/core/style/DIR_METADATA b/chromium/third_party/blink/renderer/core/style/DIR_METADATA
new file mode 100644
index 00000000000..1876fb375cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>CSS"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/style/OWNERS b/chromium/third_party/blink/renderer/core/style/OWNERS
index a007a39a025..7c1cab453b7 100644
--- a/chromium/third_party/blink/renderer/core/style/OWNERS
+++ b/chromium/third_party/blink/renderer/core/style/OWNERS
@@ -3,6 +3,3 @@ andruud@chromium.org
ericwilligers@chromium.org
futhark@chromium.org
xiaochengh@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/chromium/third_party/blink/renderer/core/style/build.gni b/chromium/third_party/blink/renderer/core/style/build.gni
index 846e6ee1f33..e35765c64d4 100644
--- a/chromium/third_party/blink/renderer/core/style/build.gni
+++ b/chromium/third_party/blink/renderer/core/style/build.gni
@@ -20,7 +20,6 @@ blink_core_sources_style = [
"computed_style_constants.h",
"content_data.cc",
"content_data.h",
- "counter_content.h",
"counter_directives.cc",
"counter_directives.h",
"cursor_data.h",
@@ -41,6 +40,8 @@ blink_core_sources_style = [
"grid_track_list.cc",
"grid_track_list.h",
"grid_track_size.h",
+ "list_style_type_data.cc",
+ "list_style_type_data.h",
"member_copy.h",
"named_grid_lines_map.h",
"nine_piece_image.cc",
@@ -90,13 +91,14 @@ blink_core_sources_style = [
"style_self_alignment_data.h",
"style_variables.cc",
"style_variables.h",
- "svg_computed_style.cc",
- "svg_computed_style.h",
- "svg_computed_style_defs.cc",
- "svg_computed_style_defs.h",
+ "svg_dash_array.cc",
+ "svg_dash_array.h",
+ "svg_paint.cc",
+ "svg_paint.h",
"text_decoration_thickness.cc",
"text_decoration_thickness.h",
"text_size_adjust.h",
+ "unzoomed_length.h",
]
blink_core_tests_style = [
@@ -107,5 +109,4 @@ blink_core_tests_style = [
"style_name_or_keyword_test.cc",
"style_name_test.cc",
"style_variables_test.cc",
- "svg_computed_style_test.cc",
]
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style.cc b/chromium/third_party/blink/renderer/core/style/computed_style.cc
index cd03d7459b5..80cb3a2f4da 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style.cc
+++ b/chromium/third_party/blink/renderer/core/style/computed_style.cc
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
+#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
#include "third_party/blink/renderer/core/style/applied_text_decoration.h"
#include "third_party/blink/renderer/core/style/border_edge.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -102,20 +103,18 @@ struct SameSizeAsComputedStyleBase {
}
private:
- void* data_refs[8];
- unsigned bitfields[6];
+ void* data_refs[9];
+ unsigned bitfields[5];
};
struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase,
public RefCounted<SameSizeAsComputedStyle> {
SameSizeAsComputedStyle() {
base::debug::Alias(&own_ptrs);
- base::debug::Alias(&data_ref_svg_style);
}
private:
void* own_ptrs[1];
- void* data_ref_svg_style;
};
// If this assert fails, it means that size of ComputedStyle has changed. Please
@@ -170,13 +169,10 @@ scoped_refptr<ComputedStyle> ComputedStyle::Clone(const ComputedStyle& other) {
ALWAYS_INLINE ComputedStyle::ComputedStyle()
: ComputedStyleBase(), RefCounted<ComputedStyle>() {
- svg_style_.Init();
}
ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& o)
- : ComputedStyleBase(o),
- RefCounted<ComputedStyle>(),
- svg_style_(o.svg_style_) {}
+ : ComputedStyleBase(o), RefCounted<ComputedStyle>() {}
ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key) : ComputedStyle() {}
@@ -448,8 +444,6 @@ void ComputedStyle::InheritFrom(const ComputedStyle& inherit_parent,
EUserModify current_user_modify = UserModify();
ComputedStyleBase::InheritFrom(inherit_parent, is_at_shadow_boundary);
- if (svg_style_ != inherit_parent.svg_style_)
- svg_style_.Access()->InheritFrom(*inherit_parent.svg_style_);
if (is_at_shadow_boundary == kAtShadowBoundary) {
// Even if surrounding content is user-editable, shadow DOM should act as a
@@ -492,9 +486,6 @@ void ComputedStyle::CopyNonInheritedFromCached(const ComputedStyle& other) {
// m_affectedByActive
// m_affectedByDrag
// m_isLink
-
- if (svg_style_ != other.svg_style_)
- svg_style_.Access()->CopyNonInheritedFromCached(*other.svg_style_);
}
bool ComputedStyle::operator==(const ComputedStyle& o) const {
@@ -506,7 +497,8 @@ const ComputedStyle* ComputedStyle::GetCachedPseudoElementStyle(
if (!cached_pseudo_element_styles_ || !cached_pseudo_element_styles_->size())
return nullptr;
- if (StyleType() != kPseudoIdNone)
+ if (StyleType() != kPseudoIdNone &&
+ StyleType() != kPseudoIdFirstLineInherited)
return nullptr;
for (const auto& pseudo_style : *cached_pseudo_element_styles_) {
@@ -558,20 +550,17 @@ bool ComputedStyle::IndependentInheritedEqual(
bool ComputedStyle::NonIndependentInheritedEqual(
const ComputedStyle& other) const {
- return ComputedStyleBase::NonIndependentInheritedEqual(other) &&
- svg_style_->InheritedEqual(*other.svg_style_);
+ return ComputedStyleBase::NonIndependentInheritedEqual(other);
}
bool ComputedStyle::NonInheritedEqual(const ComputedStyle& other) const {
// compare everything except the pseudoStyle pointer
- return ComputedStyleBase::NonInheritedEqual(other) &&
- svg_style_->NonInheritedEqual(*other.svg_style_);
+ return ComputedStyleBase::NonInheritedEqual(other);
}
bool ComputedStyle::InheritedDataShared(const ComputedStyle& other) const {
// This is a fast check that only looks if the data structures are shared.
- return ComputedStyleBase::InheritedDataShared(other) &&
- svg_style_.Get() == other.svg_style_.Get();
+ return ComputedStyleBase::InheritedDataShared(other);
}
static bool DependenceOnContentHeightHasChanged(const ComputedStyle& a,
@@ -592,9 +581,6 @@ StyleDifference ComputedStyle::VisualInvalidationDiff(
// property inside this function anyway.
StyleDifference diff;
- if (svg_style_.Get() != other.svg_style_.Get())
- diff = svg_style_->Diff(*other.svg_style_);
-
if ((!diff.NeedsReshape() || !diff.NeedsFullLayout() ||
!diff.NeedsPaintInvalidation()) &&
DiffNeedsReshapeAndFullLayoutAndPaintInvalidation(*this, other)) {
@@ -908,6 +894,17 @@ bool ComputedStyle::DiffNeedsVisualRectUpdate(
return ComputedStyleBase::DiffNeedsVisualRectUpdate(*this, other);
}
+bool ComputedStyle::PotentialCompositingReasonsFor3DTransformChanged(
+ const ComputedStyle& other) const {
+ // Compositing reasons for 3D transforms depend on the LayoutObject type (see:
+ // |LayoutObject::HasTransformRelatedProperty|)) This will return true for
+ // some LayoutObjects that end up not supporting transforms.
+ return CompositingReasonFinder::PotentialCompositingReasonsFor3DTransform(
+ *this) !=
+ CompositingReasonFinder::PotentialCompositingReasonsFor3DTransform(
+ other);
+}
+
void ComputedStyle::UpdatePropertySpecificDifferences(
const ComputedStyle& other,
StyleDifference& diff) const {
@@ -958,7 +955,8 @@ void ComputedStyle::UpdatePropertySpecificDifferences(
IsOverflowVisibleAlongBothAxes() !=
other.IsOverflowVisibleAlongBothAxes() ||
WillChangeProperties() != other.WillChangeProperties() ||
- !BackdropFilterDataEquivalent(other)) {
+ !BackdropFilterDataEquivalent(other) ||
+ PotentialCompositingReasonsFor3DTransformChanged(other)) {
diff.SetCompositingReasonsChanged();
}
}
@@ -1264,15 +1262,16 @@ void ComputedStyle::ApplyMotionPathTransform(
const BasicShape* path = OffsetPath();
const StyleOffsetRotation& rotate = OffsetRotate();
- FloatPoint point;
- float angle;
+ PointAndTangent path_position;
if (path->GetType() == BasicShape::kStyleRayType) {
// TODO(ericwilligers): crbug.com/641245 Support <size> for ray paths.
float float_distance = FloatValueForLength(distance, 0);
- angle = To<StyleRay>(*path).Angle() - 90;
- point.SetX(float_distance * cos(deg2rad(angle)));
- point.SetY(float_distance * sin(deg2rad(angle)));
+ path_position.tangent_in_degrees = To<StyleRay>(*path).Angle() - 90;
+ path_position.point.SetX(float_distance *
+ cos(deg2rad(path_position.tangent_in_degrees)));
+ path_position.point.SetY(float_distance *
+ sin(deg2rad(path_position.tangent_in_degrees)));
} else {
float zoom = EffectiveZoom();
const StylePath& motion_path = To<StylePath>(*path);
@@ -1288,14 +1287,13 @@ void ComputedStyle::ApplyMotionPathTransform(
computed_distance = clampTo<float>(float_distance, 0, path_length);
}
- motion_path.GetPath().PointAndNormalAtLength(computed_distance, point,
- angle);
-
- point.Scale(zoom, zoom);
+ path_position =
+ motion_path.GetPath().PointAndNormalAtLength(computed_distance);
+ path_position.point.Scale(zoom, zoom);
}
if (rotate.type == OffsetRotationType::kFixed)
- angle = 0;
+ path_position.tangent_in_degrees = 0;
float origin_shift_x = 0;
float origin_shift_y = 0;
@@ -1311,9 +1309,10 @@ void ComputedStyle::ApplyMotionPathTransform(
origin_shift_y = anchor_point.Y() - origin_y;
}
- transform.Translate(point.X() - anchor_point.X() + origin_shift_x,
- point.Y() - anchor_point.Y() + origin_shift_y);
- transform.Rotate(angle + rotate.angle);
+ transform.Translate(
+ path_position.point.X() - anchor_point.X() + origin_shift_x,
+ path_position.point.Y() - anchor_point.Y() + origin_shift_y);
+ transform.Rotate(path_position.tangent_in_degrees + rotate.angle);
if (!position.X().IsAuto() || !anchor.X().IsAuto())
// Shift the origin back to transform-origin.
@@ -2072,7 +2071,8 @@ void ComputedStyle::ApplyTextDecorations(
bool is_simple_underline = decoration_lines == TextDecoration::kUnderline &&
decoration_style == ETextDecorationStyle::kSolid &&
TextDecorationColor().IsCurrentColor() &&
- TextUnderlineOffset().IsAuto();
+ TextUnderlineOffset().IsAuto() &&
+ GetTextDecorationThickness().IsAuto();
if (is_simple_underline && !AppliedTextDecorationsInternal()) {
SetHasSimpleUnderlineInternal(true);
return;
@@ -2174,6 +2174,12 @@ Color ComputedStyle::ResolvedColor(const StyleColor& color) const {
return color.Resolve(current_color, UsedColorScheme());
}
+bool ComputedStyle::ShouldForceColor(const StyleColor& unforced_color) const {
+ return InForcedColorsMode() &&
+ ForcedColorAdjust() != EForcedColorAdjust::kNone &&
+ !unforced_color.IsSystemColor();
+}
+
void ComputedStyle::SetMarginStart(const Length& margin) {
if (IsHorizontalWritingMode()) {
if (IsLeftToRightDirection())
@@ -2226,6 +2232,11 @@ float ComputedStyle::GetOutlineStrokeWidthForFocusRing() const {
#endif
}
+bool ComputedStyle::StrokeDashArrayDataEquivalent(
+ const ComputedStyle& other) const {
+ return StrokeDashArray()->data == other.StrokeDashArray()->data;
+}
+
bool ComputedStyle::ColumnRuleEquivalent(
const ComputedStyle& other_style) const {
return ColumnRuleStyle() == other_style.ColumnRuleStyle() &&
@@ -2359,6 +2370,22 @@ Color ComputedStyle::GetInternalVisitedCurrentColor() const {
return InternalVisitedColor().Resolve(Color(), UsedColorScheme());
}
+Color ComputedStyle::GetInternalForcedCurrentColor() const {
+ DCHECK(!InternalForcedColor().IsCurrentColor());
+ if (GetColor().IsSystemColor())
+ return GetCurrentColor();
+ return InternalForcedColor().Resolve(Color(), UsedColorScheme(),
+ /* is_forced_color */ true);
+}
+
+Color ComputedStyle::GetInternalForcedVisitedCurrentColor() const {
+ DCHECK(!InternalForcedVisitedColor().IsCurrentColor());
+ if (InternalVisitedColor().IsSystemColor())
+ return GetInternalVisitedCurrentColor();
+ return InternalForcedVisitedColor().Resolve(Color(), UsedColorScheme(),
+ /* is_forced_color */ true);
+}
+
bool ComputedStyle::ShadowListHasCurrentColor(const ShadowList* shadow_list) {
if (!shadow_list)
return false;
@@ -2369,6 +2396,72 @@ bool ComputedStyle::ShadowListHasCurrentColor(const ShadowList* shadow_list) {
});
}
+void ComputedStyle::ClearBackgroundImage() {
+ FillLayer* curr_child = &AccessBackgroundLayers();
+ curr_child->SetImage(
+ FillLayer::InitialFillImage(EFillLayerType::kBackground));
+ for (curr_child = curr_child->Next(); curr_child;
+ curr_child = curr_child->Next())
+ curr_child->ClearImage();
+}
+
+ListStyleTypeData* ComputedStyle::GetListStyleType() const {
+ return ListStyleTypeInternal();
+}
+
+EListStyleType ComputedStyle::ListStyleType() const {
+ if (!GetListStyleType())
+ return EListStyleType::kNone;
+ if (GetListStyleType()->IsString())
+ return EListStyleType::kString;
+ return GetListStyleType()->ToDeprecatedListStyleTypeEnum();
+}
+
+const AtomicString& ComputedStyle::ListStyleStringValue() const {
+ if (!GetListStyleType() || !GetListStyleType()->IsString())
+ return g_null_atom;
+ return GetListStyleType()->GetStringValue();
+}
+
+static const int kPaintOrderBitwidth = 2;
+
+static unsigned PaintOrderSequence(EPaintOrderType first,
+ EPaintOrderType second,
+ EPaintOrderType third) {
+ return (((third << kPaintOrderBitwidth) | second) << kPaintOrderBitwidth) |
+ first;
+}
+
+EPaintOrderType ComputedStyle::PaintOrderType(unsigned index) const {
+ unsigned pt = 0;
+ DCHECK(index < ((1 << kPaintOrderBitwidth) - 1));
+ switch (PaintOrder()) {
+ case kPaintOrderNormal:
+ case kPaintOrderFillStrokeMarkers:
+ pt = PaintOrderSequence(PT_FILL, PT_STROKE, PT_MARKERS);
+ break;
+ case kPaintOrderFillMarkersStroke:
+ pt = PaintOrderSequence(PT_FILL, PT_MARKERS, PT_STROKE);
+ break;
+ case kPaintOrderStrokeFillMarkers:
+ pt = PaintOrderSequence(PT_STROKE, PT_FILL, PT_MARKERS);
+ break;
+ case kPaintOrderStrokeMarkersFill:
+ pt = PaintOrderSequence(PT_STROKE, PT_MARKERS, PT_FILL);
+ break;
+ case kPaintOrderMarkersFillStroke:
+ pt = PaintOrderSequence(PT_MARKERS, PT_FILL, PT_STROKE);
+ break;
+ case kPaintOrderMarkersStrokeFill:
+ pt = PaintOrderSequence(PT_MARKERS, PT_STROKE, PT_FILL);
+ break;
+ }
+
+ pt =
+ (pt >> (kPaintOrderBitwidth * index)) & ((1u << kPaintOrderBitwidth) - 1);
+ return static_cast<EPaintOrderType>(pt);
+}
+
STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kAuto,
EOverscrollBehavior::kAuto);
STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kContain,
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style.h b/chromium/third_party/blink/renderer/core/style/computed_style.h
index 769673d7709..a19b503403b 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style.h
+++ b/chromium/third_party/blink/renderer/core/style/computed_style.h
@@ -27,7 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_H_
#include <memory>
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/css/style_color.h"
#include "third_party/blink/renderer/core/layout/geometry/box_sides.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/core/style/border_value.h"
#include "third_party/blink/renderer/core/style/computed_style_base.h"
@@ -42,7 +43,6 @@
#include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
#include "third_party/blink/renderer/core/style/cursor_list.h"
#include "third_party/blink/renderer/core/style/data_ref.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/style/transform_origin.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
@@ -87,7 +87,6 @@ class StyleDifference;
class StyleImage;
class StyleInheritedVariables;
class StyleInitialData;
-class StylePath;
class StyleResolver;
class StyleSelfAlignmentData;
class TransformationMatrix;
@@ -109,6 +108,11 @@ class ColumnRuleColor;
class Fill;
class Float;
class FloodColor;
+class InternalForcedBackgroundColor;
+class InternalForcedBorderColor;
+class InternalForcedColor;
+class InternalForcedOutlineColor;
+class InternalForcedVisitedColor;
class InternalVisitedBackgroundColor;
class InternalVisitedBorderBottomColor;
class InternalVisitedBorderLeftColor;
@@ -117,7 +121,9 @@ class InternalVisitedBorderTopColor;
class InternalVisitedCaretColor;
class InternalVisitedColor;
class InternalVisitedColumnRuleColor;
+class InternalVisitedFill;
class InternalVisitedOutlineColor;
+class InternalVisitedStroke;
class InternalVisitedTextDecorationColor;
class InternalVisitedTextEmphasisColor;
class InternalVisitedTextFillColor;
@@ -213,6 +219,11 @@ class ComputedStyle : public ComputedStyleBase,
friend class css_longhand::Fill;
friend class css_longhand::Float;
friend class css_longhand::FloodColor;
+ friend class css_longhand::InternalForcedBackgroundColor;
+ friend class css_longhand::InternalForcedBorderColor;
+ friend class css_longhand::InternalForcedColor;
+ friend class css_longhand::InternalForcedOutlineColor;
+ friend class css_longhand::InternalForcedVisitedColor;
friend class css_longhand::InternalVisitedBackgroundColor;
friend class css_longhand::InternalVisitedBorderBottomColor;
friend class css_longhand::InternalVisitedBorderLeftColor;
@@ -221,7 +232,9 @@ class ComputedStyle : public ComputedStyleBase,
friend class css_longhand::InternalVisitedCaretColor;
friend class css_longhand::InternalVisitedColor;
friend class css_longhand::InternalVisitedColumnRuleColor;
+ friend class css_longhand::InternalVisitedFill;
friend class css_longhand::InternalVisitedOutlineColor;
+ friend class css_longhand::InternalVisitedStroke;
friend class css_longhand::InternalVisitedTextDecorationColor;
friend class css_longhand::InternalVisitedTextEmphasisColor;
friend class css_longhand::InternalVisitedTextFillColor;
@@ -242,13 +255,7 @@ class ComputedStyle : public ComputedStyleBase,
friend class StyleCascade;
friend class css_longhand::Appearance;
// Editing has to only reveal unvisited info.
- friend class ApplyStyleCommand;
- // Editing has to only reveal unvisited info.
friend class EditingStyle;
- // Needs to be able to see visited and unvisited colors for devtools.
- friend class ComputedStyleCSSValueMapping;
- // Sets color styles
- friend class StyleBuilderFunctions;
// Saves Border/Background information for later comparison.
friend class CachedUAStyle;
// Accesses visited and unvisited colors.
@@ -257,13 +264,10 @@ class ComputedStyle : public ComputedStyleBase,
friend class StyleAdjuster;
// Access to private SetFontInternal().
friend class FontBuilder;
-
- // FIXME: When we stop resolving currentColor at style time, these can be
- // removed.
- friend class CSSToStyleMap;
+ // Access to GetCurrentColor(). (drop-shadow() does not resolve 'currentcolor'
+ // at use-time.)
friend class FilterOperationResolver;
- friend class StyleBuilderConverter;
- friend class StyleResolverState;
+ // Access to SetInitialData() and GetCurrentColor().
friend class StyleResolver;
protected:
@@ -288,8 +292,6 @@ class ComputedStyle : public ComputedStyleBase,
mutable std::unique_ptr<PseudoElementStyleCache>
cached_pseudo_element_styles_;
- DataRef<SVGComputedStyle> svg_style_;
-
private:
// TODO(sashab): Move these private members to the bottom of ComputedStyle.
ALWAYS_INLINE ComputedStyle();
@@ -300,7 +302,7 @@ class ComputedStyle : public ComputedStyleBase,
CORE_EXPORT static ComputedStyle& MutableInitialStyle();
public:
- using PassKey = util::PassKey<ComputedStyle>;
+ using PassKey = base::PassKey<ComputedStyle>;
ALWAYS_INLINE ComputedStyle(PassKey, const ComputedStyle&);
ALWAYS_INLINE explicit ComputedStyle(PassKey);
@@ -580,6 +582,20 @@ class ComputedStyle : public ComputedStyleBase,
return DataEquivalent(BoxShadow(), other.BoxShadow());
}
+ // clip-path
+ ClipPathOperation* ClipPath() const {
+ // This method is accessed frequently during SVG Hit Testing, but the
+ // cumulative cost of calling |ClipPathInternal| can be fairly high due to
+ // multiple rare data pointer indirections. |HasClipPath| was added as a way
+ // to reduce the cost of these expensive indirections by placing a bit
+ // in more easily accessible memory.
+ return HasClipPath() ? ClipPathInternal().get() : nullptr;
+ }
+ void SetClipPath(scoped_refptr<ClipPathOperation> clip_path) {
+ SetHasClipPath(clip_path.get());
+ SetClipPathInternal(std::move(clip_path));
+ }
+
// clip
void SetClip(const LengthBox& box) {
SetHasAutoClipInternal(false);
@@ -698,6 +714,16 @@ class ComputedStyle : public ComputedStyleBase,
// outline-offset
int16_t OutlineOffsetInt() const { return OutlineOffset().ToInt(); }
+ // For history and compatibility reasons, we draw outline:auto (for focus
+ // rings) and normal style outline differently.
+ // Focus rings enclose block visual overflows (of line boxes and descendants),
+ // while normal outlines don't.
+ NGOutlineType OutlineRectsShouldIncludeBlockVisualOverflow() const {
+ return OutlineStyleIsAuto()
+ ? NGOutlineType::kIncludeBlockVisualOverflow
+ : NGOutlineType::kDontIncludeBlockVisualOverflow;
+ }
+
// -webkit-perspective-origin-x
const Length& PerspectiveOriginX() const { return PerspectiveOrigin().X(); }
void SetPerspectiveOriginX(const Length& v) {
@@ -944,6 +970,19 @@ class ComputedStyle : public ComputedStyleBase,
CORE_EXPORT StyleImage* ListStyleImage() const;
void SetListStyleImage(StyleImage*);
+ // list-style-type
+ // TODO(crbug.com/687225): These functions are deprecated. Callers should be
+ // migrated to GetListStyleType().
+ CORE_EXPORT EListStyleType ListStyleType() const;
+ const AtomicString& ListStyleStringValue() const;
+ // TODO(crbug.com/687225): Get rid of the deprecated functions above so that
+ // the getter can also be auto-generated.
+ CORE_EXPORT ListStyleTypeData* GetListStyleType() const;
+ bool ListStyleTypeDataEquivalent(const ComputedStyle& other) const {
+ return DataEquivalent(ListStyleTypeInternal(),
+ other.ListStyleTypeInternal());
+ }
+
// quotes
bool QuotesDataEquivalent(const ComputedStyle&) const;
@@ -972,7 +1011,8 @@ class ComputedStyle : public ComputedStyleBase,
// If true, the ComputedStyle must be recalculated when fonts are updated.
bool DependsOnFontMetrics() const {
- return HasGlyphRelativeUnits() || HasFontSizeAdjust();
+ return HasGlyphRelativeUnits() || HasFontSizeAdjust() ||
+ CustomStyleCallbackDependsOnFont();
}
bool CachedPseudoElementStylesDependOnFontMetrics() const;
@@ -1054,95 +1094,32 @@ class ComputedStyle : public ComputedStyleBase,
// widows
void SetWidows(int16_t w) { SetWidowsInternal(clampTo<int16_t>(w, 1)); }
- // SVG properties.
- const SVGComputedStyle& SvgStyle() const { return *svg_style_.Get(); }
- SVGComputedStyle& AccessSVGStyle() { return *svg_style_.Access(); }
-
- // baseline-shift
- EBaselineShift BaselineShift() const { return SvgStyle().BaselineShift(); }
- const Length& BaselineShiftValue() const {
- return SvgStyle().BaselineShiftValue();
- }
- void SetBaselineShiftValue(const Length& value) {
- SVGComputedStyle& svg_style = AccessSVGStyle();
- svg_style.SetBaselineShift(BS_LENGTH);
- svg_style.SetBaselineShiftValue(value);
+ // fill helpers
+ bool HasFill() const { return !FillPaint().IsNone(); }
+ bool IsFillColorCurrentColor() const {
+ return FillPaint().HasCurrentColor() ||
+ InternalVisitedFillPaint().HasCurrentColor();
}
- // cx
- void SetCx(const Length& cx) { AccessSVGStyle().SetCx(cx); }
-
- // cy
- void SetCy(const Length& cy) { AccessSVGStyle().SetCy(cy); }
-
- // d
- void SetD(scoped_refptr<StylePath> d) { AccessSVGStyle().SetD(std::move(d)); }
-
- // x
- void SetX(const Length& x) { AccessSVGStyle().SetX(x); }
-
- // y
- void SetY(const Length& y) { AccessSVGStyle().SetY(y); }
-
- // r
- void SetR(const Length& r) { AccessSVGStyle().SetR(r); }
-
- // rx
- void SetRx(const Length& rx) { AccessSVGStyle().SetRx(rx); }
-
- // ry
- void SetRy(const Length& ry) { AccessSVGStyle().SetRy(ry); }
-
- // fill-opacity
- float FillOpacity() const { return SvgStyle().FillOpacity(); }
- void SetFillOpacity(float f) { AccessSVGStyle().SetFillOpacity(f); }
-
- // stop-color
- void SetStopColor(const StyleColor& c) { AccessSVGStyle().SetStopColor(c); }
-
- // flood-color
- void SetFloodColor(const StyleColor& c) { AccessSVGStyle().SetFloodColor(c); }
-
- // lighting-color
- void SetLightingColor(const StyleColor& c) {
- AccessSVGStyle().SetLightingColor(c);
+ // marker-* helpers
+ bool HasMarkers() const {
+ return MarkerStartResource() || MarkerMidResource() || MarkerEndResource();
}
- // flood-opacity
- float FloodOpacity() const { return SvgStyle().FloodOpacity(); }
- void SetFloodOpacity(float f) { AccessSVGStyle().SetFloodOpacity(f); }
-
- // stop-opacity
- float StopOpacity() const { return SvgStyle().StopOpacity(); }
- void SetStopOpacity(float f) { AccessSVGStyle().SetStopOpacity(f); }
-
- // stroke-dasharray
- SVGDashArray* StrokeDashArray() const { return SvgStyle().StrokeDashArray(); }
- void SetStrokeDashArray(scoped_refptr<SVGDashArray> array) {
- AccessSVGStyle().SetStrokeDashArray(std::move(array));
- }
+ // paint-order helper
+ EPaintOrderType PaintOrderType(unsigned index) const;
- // stroke-dashoffset
- const Length& StrokeDashOffset() const {
- return SvgStyle().StrokeDashOffset();
+ // stroke helpers
+ bool HasStroke() const { return !StrokePaint().IsNone(); }
+ bool HasVisibleStroke() const {
+ return HasStroke() && !StrokeWidth().IsZero();
}
- void SetStrokeDashOffset(const Length& d) {
- AccessSVGStyle().SetStrokeDashOffset(d);
- }
-
- // stroke-miterlimit
- float StrokeMiterLimit() const { return SvgStyle().StrokeMiterLimit(); }
- void SetStrokeMiterLimit(float f) { AccessSVGStyle().SetStrokeMiterLimit(f); }
-
- // stroke-opacity
- float StrokeOpacity() const { return SvgStyle().StrokeOpacity(); }
- void SetStrokeOpacity(float f) { AccessSVGStyle().SetStrokeOpacity(f); }
-
- // stroke-width
- const UnzoomedLength& StrokeWidth() const { return SvgStyle().StrokeWidth(); }
- void SetStrokeWidth(const UnzoomedLength& w) {
- AccessSVGStyle().SetStrokeWidth(w);
+ bool IsStrokeColorCurrentColor() const {
+ return StrokePaint().HasCurrentColor() ||
+ InternalVisitedStrokePaint().HasCurrentColor();
}
+ bool HasDashArray() const { return !StrokeDashArray()->data.IsEmpty(); }
+ bool StrokeDashArrayDataEquivalent(const ComputedStyle&) const;
// Comparison operators
// FIXME: Replace callers of operator== wth a named method instead, e.g.
@@ -2054,7 +2031,11 @@ class ComputedStyle : public ComputedStyleBase,
bool ContainsPaint() const { return Contain() & kContainsPaint; }
bool ContainsStyle() const { return Contain() & kContainsStyle; }
bool ContainsLayout() const { return Contain() & kContainsLayout; }
- bool ContainsSize() const { return Contain() & kContainsSize; }
+ bool ContainsSize() const {
+ return (Contain() & kContainsSize) == kContainsSize;
+ }
+ bool ContainsInlineSize() const { return Contain() & kContainsInlineSize; }
+ bool ContainsBlockSize() const { return Contain() & kContainsBlockSize; }
// Display utility functions.
bool IsDisplayReplacedType() const {
@@ -2125,7 +2106,9 @@ class ComputedStyle : public ComputedStyleBase,
void ClearCursorList();
// Resize utility functions.
- bool HasResize() const { return ResizeInternal() != EResize::kNone; }
+ bool HasResize() const {
+ return StyleType() == kPseudoIdNone && ResizeInternal() != EResize::kNone;
+ }
EResize UnresolvedResize() const { return ResizeInternal(); }
EResize Resize(const ComputedStyle& cb_style) const {
@@ -2221,7 +2204,7 @@ class ComputedStyle : public ComputedStyleBase,
return HasCurrentOpacityAnimation() || HasCurrentTransformAnimation() ||
HasCurrentFilterAnimation() || HasCurrentBackdropFilterAnimation();
}
- bool IsRunningAnimationOnCompositor() const {
+ bool RequiresPropertyNodeForAnimation() const {
return IsRunningOpacityAnimationOnCompositor() ||
IsRunningTransformAnimationOnCompositor() ||
IsRunningFilterAnimationOnCompositor() ||
@@ -2233,7 +2216,10 @@ class ComputedStyle : public ComputedStyleBase,
// Table layout utility functions.
bool IsFixedTableLayout() const {
- return TableLayout() == ETableLayout::kFixed && !LogicalWidth().IsAuto();
+ // https://www.w3.org/TR/css-tables-3/#table-layout-property
+ return TableLayout() == ETableLayout::kFixed &&
+ (LogicalWidth().IsSpecified() || LogicalWidth().IsMinContent() ||
+ LogicalWidth().IsFitContent());
}
LogicalSize TableBorderSpacing() const {
@@ -2360,7 +2346,7 @@ class ComputedStyle : public ComputedStyleBase,
return true;
if (has_box_reflection)
return true;
- if (ClipPath())
+ if (HasClipPath())
return true;
if (HasIsolation())
return true;
@@ -2392,6 +2378,12 @@ class ComputedStyle : public ComputedStyleBase,
HasWillChangeTransformHint();
}
+ // Return true if this style has properties ('filter', 'clip-path' and 'mask')
+ // that applies an effect to SVG elements.
+ bool HasSVGEffect() const {
+ return HasFilter() || HasClipPath() || MaskerResource();
+ }
+
// Paint utility functions.
CORE_EXPORT void AddPaintImage(StyleImage*);
@@ -2489,6 +2481,10 @@ class ComputedStyle : public ComputedStyleBase,
GetLineBreak() == LineBreak::kAfterWhiteSpace;
}
+ bool NeedsTrailingSpace() const {
+ return BreakOnlyAfterWhiteSpace() && AutoWrap();
+ }
+
bool BreakWords() const {
return (WordBreak() == EWordBreak::kBreakWord ||
OverflowWrap() != EOverflowWrap::kNormal) &&
@@ -2534,7 +2530,8 @@ class ComputedStyle : public ComputedStyleBase,
}
bool HasBackgroundRelatedColorReferencingCurrentColor() const {
if (BackgroundColor().IsCurrentColor() ||
- InternalVisitedBackgroundColor().IsCurrentColor())
+ InternalVisitedBackgroundColor().IsCurrentColor() ||
+ InternalForcedBackgroundColor().IsCurrentColor())
return true;
if (!BoxShadow())
return false;
@@ -2551,13 +2548,6 @@ class ComputedStyle : public ComputedStyleBase,
CORE_EXPORT Color
VisitedDependentColor(const CSSProperty& color_property) const;
- // Helper for resolving a StyleColor which may contain currentColor or a
- // system color keyword. This is intended for cases such as SVG <paint> where
- // a given property consists of a StyleColor plus additional information. For
- // <color> properties, prefer VisitedDependentColor() or
- // Longhand::ColorIncludingFallback() instead.
- Color ResolvedColor(const StyleColor& color) const;
-
// -webkit-appearance utility functions.
bool HasEffectiveAppearance() const {
return EffectiveAppearance() != kNoControlPart;
@@ -2630,6 +2620,12 @@ class ComputedStyle : public ComputedStyleBase,
return LogicalSize(LayoutUnit(ratio.Width()), LayoutUnit(ratio.Height()));
}
+ EBoxSizing BoxSizingForAspectRatio() const {
+ if (AspectRatio().GetType() == EAspectRatioType::kAutoAndRatio)
+ return EBoxSizing::kContentBox;
+ return BoxSizing();
+ }
+
private:
EClear Clear() const { return ClearInternal(); }
EFloat Floating() const { return FloatingInternal(); }
@@ -2672,6 +2668,10 @@ class ComputedStyle : public ComputedStyleBase,
SetInternalVisitedTextStrokeColorInternal(color);
}
+ void SetInternalForcedVisitedColor(const StyleColor& v) {
+ SetInternalForcedVisitedColorInternal(v);
+ }
+
static bool IsDisplayBlockContainer(EDisplay display) {
return display == EDisplay::kBlock || display == EDisplay::kListItem ||
display == EDisplay::kInlineBlock ||
@@ -2747,6 +2747,7 @@ class ComputedStyle : public ComputedStyleBase,
return ColumnRuleColorInternal();
}
const StyleColor& OutlineColor() const { return OutlineColorInternal(); }
+ const StyleColor& StopColor() const { return StopColorInternal(); }
const StyleColor& TextDecorationColor() const {
return TextDecorationColorInternal();
}
@@ -2827,11 +2828,23 @@ class ComputedStyle : public ComputedStyleBase,
return InternalVisitedTextStrokeColorInternal();
}
- StyleColor DecorationColorIncludingFallback(bool visited_link) const;
+ const StyleColor& InternalForcedBackgroundColor() const {
+ return InternalForcedBackgroundColorInternal();
+ }
+ const StyleColor& InternalForcedBorderColor() const {
+ return InternalForcedBorderColorInternal();
+ }
+ const StyleColor& InternalForcedColor() const {
+ return InternalForcedColorInternal();
+ }
+ const StyleColor& InternalForcedOutlineColor() const {
+ return InternalForcedOutlineColorInternal();
+ }
+ const StyleColor& InternalForcedVisitedColor() const {
+ return InternalForcedVisitedColorInternal();
+ }
- const StyleColor& StopColor() const { return SvgStyle().StopColor(); }
- const StyleColor& FloodColor() const { return SvgStyle().FloodColor(); }
- const StyleColor& LightingColor() const { return SvgStyle().LightingColor(); }
+ StyleColor DecorationColorIncludingFallback(bool visited_link) const;
// Appearance accessors are private to make sure callers use
// EffectiveAppearance in almost all cases.
@@ -2864,6 +2877,8 @@ class ComputedStyle : public ComputedStyleBase,
bool DiffNeedsVisualRectUpdate(const ComputedStyle& other) const;
CORE_EXPORT void UpdatePropertySpecificDifferences(const ComputedStyle& other,
StyleDifference&) const;
+ bool PotentialCompositingReasonsFor3DTransformChanged(
+ const ComputedStyle& other) const;
bool PropertiesEqual(const Vector<CSSPropertyID>& properties,
const ComputedStyle& other) const;
@@ -2872,6 +2887,15 @@ class ComputedStyle : public ComputedStyleBase,
Color GetCurrentColor() const;
Color GetInternalVisitedCurrentColor() const;
+ Color GetInternalForcedCurrentColor() const;
+ Color GetInternalForcedVisitedCurrentColor() const;
+
+ // Helper for resolving a StyleColor which may contain currentColor or a
+ // system color keyword. This is intended for cases where a given property
+ // consists of a StyleColor plus additional information. For <color>
+ // properties, prefer VisitedDependentColor() or
+ // Longhand::ColorIncludingFallback() instead.
+ Color ResolvedColor(const StyleColor& color) const;
static bool ShadowListHasCurrentColor(const ShadowList*);
@@ -2921,6 +2945,10 @@ class ComputedStyle : public ComputedStyleBase,
const ComputedStyle& old_style,
const ComputedStyle& new_style);
+ bool ShouldForceColor(const StyleColor& unforced_color) const;
+
+ void ClearBackgroundImage();
+
FRIEND_TEST_ALL_PREFIXES(
ComputedStyleTest,
UpdatePropertySpecificDifferencesRespectsTransformAnimation);
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_constants.h b/chromium/third_party/blink/renderer/core/style/computed_style_constants.h
index c1f9aa7bc3e..1202b4337ce 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_constants.h
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_constants.h
@@ -65,6 +65,8 @@ enum PseudoId : uint8_t {
kPseudoIdSelection,
kPseudoIdScrollbar,
kPseudoIdTargetText,
+ kPseudoIdSpellingError,
+ kPseudoIdGrammarError,
// Internal IDs follow:
kPseudoIdFirstLineInherited,
kPseudoIdScrollbarThumb,
@@ -164,13 +166,15 @@ enum GridAutoFlow {
int(kInternalAutoFlowDirectionColumn)
};
-static const size_t kContainmentBits = 4;
+static const size_t kContainmentBits = 5;
enum Containment {
kContainsNone = 0x0,
kContainsLayout = 0x1,
kContainsStyle = 0x2,
kContainsPaint = 0x4,
- kContainsSize = 0x8,
+ kContainsBlockSize = 0x8,
+ kContainsInlineSize = 0x10,
+ kContainsSize = kContainsBlockSize | kContainsInlineSize,
kContainsStrict = kContainsLayout | kContainsPaint | kContainsSize,
kContainsContent = kContainsLayout | kContainsPaint,
};
@@ -280,6 +284,96 @@ inline ScrollbarGutter& operator|=(ScrollbarGutter& a, ScrollbarGutter b) {
return a = a | b;
}
+// https://drafts.csswg.org/css-counter-styles-3/#predefined-counters
+enum class EListStyleType : unsigned {
+ // https://drafts.csswg.org/css-counter-styles-3/#simple-symbolic
+ kDisc,
+ kCircle,
+ kSquare,
+ kDisclosureOpen,
+ kDisclosureClosed,
+
+ // https://drafts.csswg.org/css-counter-styles-3/#simple-numeric
+ kDecimal,
+ kDecimalLeadingZero,
+ kArabicIndic,
+ kBengali,
+ kCambodian,
+ kKhmer,
+ kDevanagari,
+ kGujarati,
+ kGurmukhi,
+ kKannada,
+ kLao,
+ kMalayalam,
+ kMongolian,
+ kMyanmar,
+ kOriya,
+ kPersian,
+ kUrdu,
+ kTelugu,
+ kTibetan,
+ kThai,
+ kLowerRoman,
+ kUpperRoman,
+
+ // https://drafts.csswg.org/css-counter-styles-3/#simple-alphabetic
+ kLowerGreek,
+ kLowerAlpha,
+ kLowerLatin,
+ kUpperAlpha,
+ kUpperLatin,
+
+ // https://drafts.csswg.org/css-counter-styles-3/#simple-fixed
+ kCjkEarthlyBranch,
+ kCjkHeavenlyStem,
+
+ kEthiopicHalehame,
+ kEthiopicHalehameAm,
+ kEthiopicHalehameTiEr,
+ kEthiopicHalehameTiEt,
+ kHangul,
+ kHangulConsonant,
+ kKoreanHangulFormal,
+ kKoreanHanjaFormal,
+ kKoreanHanjaInformal,
+ kHebrew,
+ kArmenian,
+ kLowerArmenian,
+ kUpperArmenian,
+ kGeorgian,
+ kCjkIdeographic,
+ kSimpChineseFormal,
+ kSimpChineseInformal,
+ kTradChineseFormal,
+ kTradChineseInformal,
+ kHiragana,
+ kKatakana,
+ kHiraganaIroha,
+ kKatakanaIroha,
+ kNone,
+ kString,
+};
+
+enum class EBaselineShiftType : unsigned { kLength, kSub, kSuper };
+
+enum EPaintOrderType {
+ PT_NONE = 0,
+ PT_FILL = 1,
+ PT_STROKE = 2,
+ PT_MARKERS = 3
+};
+
+enum EPaintOrder {
+ kPaintOrderNormal,
+ kPaintOrderFillStrokeMarkers,
+ kPaintOrderFillMarkersStroke,
+ kPaintOrderStrokeFillMarkers,
+ kPaintOrderStrokeMarkersFill,
+ kPaintOrderMarkersFillStroke,
+ kPaintOrderMarkersStrokeFill
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_CONSTANTS_H_
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 7de711f04e1..b7378fc468b 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -102,7 +102,11 @@
"grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end",
"column-gap", "column-width", "column-rule-style",
"column-rule-width", "column-rule-color", "-internal-visited-column-rule-color",
- "column-count", "HasAutoColumnCount", "HasAutoColumnWidth", "column-fill", "column-span",],
+ "column-count", "HasAutoColumnCount", "HasAutoColumnWidth", "column-fill", "column-span",
+ "cx", "cy", "d", "rx", "ry", "x", "y", "r", "alignment-baseline", "vector-effect",
+ "BaselineShiftType", "baseline-shift", "dominant-baseline", "text-anchor",
+ "stroke-width", "stroke-miterlimit", "stroke-linecap", "stroke-linejoin",
+ "marker-end", "marker-mid", "marker-start",],
methods_to_diff: [
{
method: "BorderLeftWidth()",
@@ -160,6 +164,14 @@
method: "OriginalDisplay()",
field_dependencies: ["OriginalDisplay"]
},
+ {
+ method: "HasStroke()",
+ field_dependencies: ["stroke"]
+ },
+ {
+ method: "HasDashArray()",
+ field_dependencies: ["stroke-dasharray"]
+ },
],
predicates_to_test: [
{
@@ -202,17 +214,15 @@
name: "DiffNeedsFullLayoutAndPaintInvalidationDisplayListItem",
methods_to_diff: [
{
- method: "ListStyleType()",
- field_dependencies: ["ListStyleType"]
- },
- {
- method: "ListStyleStringValue()",
- field_dependencies: ["ListStyleStringValue"]
- },
- {
method: "ListStylePosition()",
field_dependencies: ["list-style-position"]
},
+ ],
+ predicates_to_test: [
+ {
+ predicate: "a.ListStyleTypeDataEquivalent(b)",
+ field_dependencies: ["list-style-type"]
+ },
]
},
{
@@ -221,7 +231,8 @@
"max-height", "VerticalAlignLength", "box-sizing", "align-content",
"align-items", "align-self", "justify-content", "justify-items",
"justify-self", "contain", "contain-intrinsic-size", "aspect-ratio",
- "overflow-clip-margin", "-internal-align-self-block"],
+ "overflow-clip-margin", "-internal-align-self-block", "orphans",
+ "widows"],
methods_to_diff: [
{
method: "VerticalAlign()",
@@ -237,7 +248,12 @@
name: "DiffNeedsPaintInvalidation",
fields_to_diff: ["-webkit-user-modify", "user-select", "image-rendering",
"-webkit-user-drag", "object-fit", "object-position",
- "mix-blend-mode", "isolation", "Mask", "MaskBoxImage"],
+ "mix-blend-mode", "isolation", "Mask", "MaskBoxImage", "mask", "mask-type",
+ "stop-color", "stop-opacity", "flood-color", "flood-opacity",
+ "lighting-color", "shape-rendering", "clip-rule", "fill-rule",
+ "color-interpolation", "color-interpolation-filters", "paint-order",
+ "fill", "fill-opacity", "stroke", "stroke-opacity",
+ "-internal-visited-stroke", "stroke-dashoffset"],
methods_to_diff: [
{
method: "Visibility()",
@@ -301,6 +317,10 @@
predicate: "a.InternalVisitedOutlineColorHasNotChanged(b)",
field_dependencies: ["-internal-visited-outline-color"]
},
+ {
+ predicate: "a.StrokeDashArrayDataEquivalent(b)",
+ field_dependencies: ["stroke-dasharray"]
+ },
]
},
{
@@ -376,7 +396,7 @@
},
{
name: "UpdatePropertySpecificDifferencesMask",
- fields_to_diff: ["Mask", "MaskBoxImage"],
+ fields_to_diff: ["Mask", "MaskBoxImage", "mask"],
},
{
name: "UpdatePropertySpecificDifferencesNeedsRecomputeVisualOverflow",
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 05ca626c00a..ffab1426f99 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -85,6 +85,13 @@
keywords: ["not-inside-link", "inside-unvisited-link", "inside-visited-link"],
inherited: true,
},
+ {
+ name: "InForcedColorsMode",
+ field_template: "primitive",
+ default_value: "false",
+ type_name: "bool",
+ inherited: true,
+ },
// Whether we're inside an NG block fragmentation context.
{
name: "InsideNGFragmentationContext",
@@ -207,6 +214,14 @@
default_value: "false",
custom_compare: true,
},
+ // True if this ComputedStyle is the result of CustomStyleForLayoutObject()
+ // that uses font metrics in its calculation.
+ {
+ name: "CustomStyleCallbackDependsOnFont",
+ field_template: "monotonic_flag",
+ default_value: "false",
+ custom_compare: true,
+ },
// These properties only have generated storage, and their methods are handwritten in ComputedStyle.
{
name: "StyleType",
@@ -221,7 +236,7 @@
{
name: "PseudoBits",
field_template: "primitive",
- field_size: 9,
+ field_size: 11,
default_value: "kPseudoIdNone",
type_name: "unsigned",
custom_copy: true,
@@ -276,6 +291,13 @@
computed_style_custom_functions: ["getter", "setter"],
},
{
+ name: "HasClipPath",
+ field_template: "primitive",
+ type_name: "bool",
+ default_value: "false",
+ field_group: "visual",
+ },
+ {
name: "HasAutoClip",
field_template: "primitive",
type_name: "bool",
@@ -377,14 +399,6 @@
default_value: "false",
field_group: "*",
},
- {
- name: "SelfOrAncestorHasDirAutoAttribute",
- inherited: true,
- field_template: "primitive",
- type_name: "bool",
- default_value: "false",
- field_group: "*",
- },
// Though position: sticky is not itself an inherited property, being a
// descendent of a sticky element changes some document lifecycle logic.
{
@@ -615,6 +629,13 @@
default_value: "false",
},
{
+ name: "HasCurrentBackgroundColorAnimation",
+ field_template: "primitive",
+ type_name: "bool",
+ field_group: "*",
+ default_value: "false",
+ },
+ {
name: "IsRunningOpacityAnimationOnCompositor",
field_template: "primitive",
type_name: "bool",
@@ -926,38 +947,6 @@
custom_compare: true,
},
{
- name: "ListStyleType",
- inherited: true,
- field_template: "keyword",
- type_name: "EListStyleType",
- keywords: [
- "disc", "circle", "square", "decimal", "decimal-leading-zero",
- "arabic-indic", "bengali", "cambodian", "khmer", "devanagari",
- "gujarati", "gurmukhi", "kannada", "lao", "malayalam", "mongolian",
- "myanmar", "oriya", "persian", "urdu", "telugu", "tibetan", "thai",
- "lower-roman", "upper-roman", "lower-greek", "lower-alpha",
- "lower-latin", "upper-alpha", "upper-latin", "cjk-earthly-branch",
- "cjk-heavenly-stem", "ethiopic-halehame", "ethiopic-halehame-am",
- "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "hangul",
- "hangul-consonant", "korean-hangul-formal", "korean-hanja-formal",
- "korean-hanja-informal", "hebrew", "armenian", "lower-armenian",
- "upper-armenian", "georgian", "cjk-ideographic", "simp-chinese-formal",
- "simp-chinese-informal", "trad-chinese-formal", "trad-chinese-informal",
- "hiragana", "katakana", "hiragana-iroha", "katakana-iroha", "none",
- "string",
- ],
- default_value: "disc",
- },
- {
- name: "ListStyleStringValue",
- inherited: true,
- field_template: "external",
- field_group: "*",
- type_name: "AtomicString",
- include_paths: ["third_party/blink/renderer/platform/wtf/text/atomic_string.h"],
- default_value: "g_null_atom",
- },
- {
name: "IsEnsuredOutsideFlatTree",
field_template: "monotonic_flag",
default_value: "false",
@@ -1062,5 +1051,21 @@
field_group: "*",
default_value: "false",
},
+ {
+ name: "BaselineShiftType",
+ field_group: "svg->misc",
+ // Use a keyword?
+ field_template: "primitive",
+ field_size: 2,
+ type_name: "EBaselineShiftType",
+ default_value: "EBaselineShiftType::kLength",
+ },
+ {
+ name: "DependsOnContainerQueries",
+ field_template: "primitive",
+ type_name: "bool",
+ field_group: "*",
+ default_value: "false",
+ },
],
}
diff --git a/chromium/third_party/blink/renderer/core/style/computed_style_test.cc b/chromium/third_party/blink/renderer/core/style/computed_style_test.cc
index 34681378068..c066f28990e 100644
--- a/chromium/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/chromium/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -155,12 +155,12 @@ TEST(ComputedStyleTest, FirstPublicPseudoStyle) {
}
TEST(ComputedStyleTest, LastPublicPseudoElementStyle) {
- static_assert(kFirstInternalPseudoId - 1 == kPseudoIdTargetText,
+ static_assert(kFirstInternalPseudoId - 1 == kPseudoIdGrammarError,
"Make sure we are testing the last public pseudo id");
scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
- style->SetHasPseudoElementStyle(kPseudoIdTargetText);
- EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdTargetText));
+ style->SetHasPseudoElementStyle(kPseudoIdGrammarError);
+ EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdGrammarError));
EXPECT_TRUE(style->HasAnyPseudoElementStyles());
}
@@ -805,11 +805,10 @@ TEST(ComputedStyleTest, StrokeWidthZoomAndCalc) {
true));
To<Longhand>(GetCSSPropertyStrokeWidth()).ApplyValue(state, *calc_value);
- auto* computed_value =
- To<Longhand>(GetCSSPropertyStrokeWidth())
- .CSSValueFromComputedStyleInternal(*style, style->SvgStyle(),
- nullptr /* layout_object */,
- false /* allow_visited_style */);
+ auto* computed_value = To<Longhand>(GetCSSPropertyStrokeWidth())
+ .CSSValueFromComputedStyleInternal(
+ *style, nullptr /* layout_object */,
+ false /* allow_visited_style */);
ASSERT_TRUE(computed_value);
auto* numeric_value = DynamicTo<CSSNumericLiteralValue>(computed_value);
ASSERT_TRUE(numeric_value);
@@ -942,8 +941,7 @@ TEST(ComputedStyleTest, BorderWidthZoom) {
const Longhand& longhand = To<Longhand>(*property);
longhand.ApplyValue(state, *test.css_value);
auto* computed_value = longhand.CSSValueFromComputedStyleInternal(
- *style, style->SvgStyle(), nullptr /* layout_object */,
- false /* allow_visited_style */);
+ *style, nullptr /* layout_object */, false /* allow_visited_style */);
AtomicString prop_name = longhand.GetCSSPropertyName().ToAtomicString();
ASSERT_TRUE(computed_value) << prop_name;
auto* numeric_value = DynamicTo<CSSNumericLiteralValue>(computed_value);
@@ -1122,4 +1120,49 @@ TEST(ComputedStyleTest, ApplyInitialAnimationNameAndTransitionProperty) {
EXPECT_FALSE(style->Transitions());
}
+#define TEST_STYLE_VALUE_NO_DIFF(field_name) \
+ { \
+ scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create(); \
+ scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create(); \
+ style1->Set##field_name( \
+ ComputedStyleInitialValues::Initial##field_name()); \
+ style2->Set##field_name( \
+ ComputedStyleInitialValues::Initial##field_name()); \
+ auto diff = style1->VisualInvalidationDiff(*document, *style2); \
+ EXPECT_FALSE(diff.HasDifference()); \
+ }
+
+// Ensures ref-counted values are compared by their values, not by pointers.
+#define TEST_STYLE_REFCOUNTED_VALUE_NO_DIFF(type, field_name) \
+ { \
+ scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create(); \
+ scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create(); \
+ scoped_refptr<type> value1 = base::MakeRefCounted<type>(); \
+ scoped_refptr<type> value2 = base::MakeRefCounted<type>(value1->data); \
+ style1->Set##field_name(value1); \
+ style2->Set##field_name(value2); \
+ auto diff = style1->VisualInvalidationDiff(*document, *style2); \
+ EXPECT_FALSE(diff.HasDifference()); \
+ }
+
+TEST(ComputedStyleTest, SvgStrokeStyleShouldCompareValue) {
+ Persistent<Document> document = Document::CreateForTest();
+ TEST_STYLE_VALUE_NO_DIFF(StrokeOpacity);
+ TEST_STYLE_VALUE_NO_DIFF(StrokeMiterLimit);
+ TEST_STYLE_VALUE_NO_DIFF(StrokeWidth);
+ TEST_STYLE_VALUE_NO_DIFF(StrokeDashOffset);
+ TEST_STYLE_REFCOUNTED_VALUE_NO_DIFF(SVGDashArray, StrokeDashArray);
+
+ TEST_STYLE_VALUE_NO_DIFF(StrokePaint);
+ TEST_STYLE_VALUE_NO_DIFF(InternalVisitedStrokePaint);
+}
+
+TEST(ComputedStyleTest, SvgMiscStyleShouldCompareValue) {
+ Persistent<Document> document = Document::CreateForTest();
+ TEST_STYLE_VALUE_NO_DIFF(FloodColor);
+ TEST_STYLE_VALUE_NO_DIFF(FloodOpacity);
+ TEST_STYLE_VALUE_NO_DIFF(LightingColor);
+ TEST_STYLE_VALUE_NO_DIFF(BaselineShift);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/content_data.cc b/chromium/third_party/blink/renderer/core/style/content_data.cc
index dea85fb4c13..142199a968e 100644
--- a/chromium/third_party/blink/renderer/core/style/content_data.cc
+++ b/chromium/third_party/blink/renderer/core/style/content_data.cc
@@ -24,6 +24,7 @@
#include <memory>
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
+#include "third_party/blink/renderer/core/dom/tree_scope.h"
#include "third_party/blink/renderer/core/layout/layout_counter.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_image_resource.h"
@@ -96,11 +97,16 @@ LayoutObject* CounterContentData::CreateLayoutObject(
PseudoElement& pseudo,
const ComputedStyle& pseudo_style,
LegacyLayout) const {
- LayoutObject* layout_object = new LayoutCounter(pseudo, *counter_);
+ LayoutObject* layout_object = new LayoutCounter(pseudo, *this);
layout_object->SetPseudoElementStyle(&pseudo_style);
return layout_object;
}
+void CounterContentData::Trace(Visitor* visitor) const {
+ visitor->Trace(tree_scope_);
+ ContentData::Trace(visitor);
+}
+
LayoutObject* QuoteContentData::CreateLayoutObject(
PseudoElement& pseudo,
const ComputedStyle& pseudo_style,
diff --git a/chromium/third_party/blink/renderer/core/style/content_data.h b/chromium/third_party/blink/renderer/core/style/content_data.h
index 486b3256fb1..37e2176efad 100644
--- a/chromium/third_party/blink/renderer/core/style/content_data.h
+++ b/chromium/third_party/blink/renderer/core/style/content_data.h
@@ -29,10 +29,11 @@
#include <memory>
#include <utility>
-#include "third_party/blink/renderer/core/style/counter_content.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/style/style_image.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
@@ -40,6 +41,7 @@ class ComputedStyle;
class LayoutObject;
enum class LegacyLayout;
class PseudoElement;
+class TreeScope;
class ContentData : public GarbageCollected<ContentData> {
public:
@@ -191,34 +193,50 @@ class CounterContentData final : public ContentData {
friend class ContentData;
public:
- const CounterContent* Counter() const { return counter_.get(); }
- void SetCounter(std::unique_ptr<CounterContent> counter) {
- counter_ = std::move(counter);
- }
-
- explicit CounterContentData(std::unique_ptr<CounterContent> counter)
- : counter_(std::move(counter)) {}
+ explicit CounterContentData(const AtomicString& identifier,
+ const AtomicString& style,
+ const AtomicString& separator,
+ const TreeScope* tree_scope)
+ : identifier_(identifier),
+ list_style_(style),
+ separator_(separator),
+ tree_scope_(tree_scope) {}
bool IsCounter() const override { return true; }
LayoutObject* CreateLayoutObject(PseudoElement&,
const ComputedStyle&,
LegacyLayout) const override;
+ const AtomicString& Identifier() const { return identifier_; }
+ const AtomicString& ListStyle() const { return list_style_; }
+ const AtomicString& Separator() const { return separator_; }
+ const TreeScope* GetTreeScope() const { return tree_scope_; }
+
+ EListStyleType ToDeprecatedListStyleTypeEnum() const;
+
+ void Trace(Visitor*) const override;
+
private:
ContentData* CloneInternal() const override {
- std::unique_ptr<CounterContent> counter_data =
- std::make_unique<CounterContent>(*Counter());
- return MakeGarbageCollected<CounterContentData>(std::move(counter_data));
+ return MakeGarbageCollected<CounterContentData>(identifier_, list_style_,
+ separator_, tree_scope_);
}
bool Equals(const ContentData& data) const override {
if (!data.IsCounter())
return false;
- return *static_cast<const CounterContentData&>(data).Counter() ==
- *Counter();
+ const CounterContentData& other =
+ static_cast<const CounterContentData&>(data);
+ return Identifier() == other.Identifier() &&
+ ListStyle() == other.ListStyle() &&
+ Separator() == other.Separator() &&
+ GetTreeScope() == other.GetTreeScope();
}
- std::unique_ptr<CounterContent> counter_;
+ AtomicString identifier_;
+ AtomicString list_style_;
+ AtomicString separator_;
+ Member<const TreeScope> tree_scope_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/style/counter_content.h b/chromium/third_party/blink/renderer/core/style/counter_content.h
deleted file mode 100644
index 49f86a5c6bf..00000000000
--- a/chromium/third_party/blink/renderer/core/style/counter_content.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
- * (C) 2000 Antti Koivisto (koivisto@kde.org)
- * (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COUNTER_CONTENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COUNTER_CONTENT_H_
-
-#include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-
-namespace blink {
-
-class CounterContent {
- USING_FAST_MALLOC(CounterContent);
-
- public:
- CounterContent(const AtomicString& identifier,
- EListStyleType style,
- const AtomicString& separator)
- : identifier_(identifier), list_style_(style), separator_(separator) {
- DCHECK_NE(style, EListStyleType::kString);
- }
-
- const AtomicString& Identifier() const { return identifier_; }
- EListStyleType ListStyle() const { return list_style_; }
- const AtomicString& Separator() const { return separator_; }
-
- private:
- AtomicString identifier_;
- EListStyleType list_style_;
- AtomicString separator_;
-};
-
-static inline bool operator==(const CounterContent& a,
- const CounterContent& b) {
- return a.Identifier() == b.Identifier() && a.ListStyle() == b.ListStyle() &&
- a.Separator() == b.Separator();
-}
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COUNTER_CONTENT_H_
diff --git a/chromium/third_party/blink/renderer/core/style/data_equivalency.h b/chromium/third_party/blink/renderer/core/style/data_equivalency.h
index c5aa44e7f1b..6cdd579e895 100644
--- a/chromium/third_party/blink/renderer/core/style/data_equivalency.h
+++ b/chromium/third_party/blink/renderer/core/style/data_equivalency.h
@@ -7,15 +7,11 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
template <typename T>
-class Persistent;
-template <typename T>
-class Member;
-
-template <typename T>
bool DataEquivalent(const T* a, const T* b) {
if (a == b)
return true;
diff --git a/chromium/third_party/blink/renderer/core/style/fill_layer.cc b/chromium/third_party/blink/renderer/core/style/fill_layer.cc
index 2f27e0359ce..a8c40abff33 100644
--- a/chromium/third_party/blink/renderer/core/style/fill_layer.cc
+++ b/chromium/third_party/blink/renderer/core/style/fill_layer.cc
@@ -407,10 +407,10 @@ bool FillLayer::ImageTilesLayer() const {
// TODO(schenney) We could relax the repeat mode requirement if we also knew
// the rect we had to fill, and the portion of the image we need to use, and
// know that the latter covers the former.
- return (static_cast<EFillRepeat>(repeat_x_) == EFillRepeat::kRepeatFill ||
- static_cast<EFillRepeat>(repeat_x_) == EFillRepeat::kRoundFill) &&
- (static_cast<EFillRepeat>(repeat_y_) == EFillRepeat::kRepeatFill ||
- static_cast<EFillRepeat>(repeat_y_) == EFillRepeat::kRoundFill);
+ return (RepeatX() == EFillRepeat::kRepeatFill ||
+ RepeatX() == EFillRepeat::kRoundFill) &&
+ (RepeatY() == EFillRepeat::kRepeatFill ||
+ RepeatY() == EFillRepeat::kRoundFill);
}
bool FillLayer::ImageOccludesNextLayers(const Document& document,
@@ -424,8 +424,8 @@ bool FillLayer::ImageOccludesNextLayers(const Document& document,
case kCompositeCopy:
return ImageTilesLayer();
case kCompositeSourceOver:
- return (blend_mode_ == static_cast<unsigned>(BlendMode::kNormal)) &&
- ImageTilesLayer() && ImageIsOpaque(document, style);
+ return GetBlendMode() == BlendMode::kNormal && ImageTilesLayer() &&
+ ImageIsOpaque(document, style);
default: {}
}
diff --git a/chromium/third_party/blink/renderer/core/style/grid_area.h b/chromium/third_party/blink/renderer/core/style/grid_area.h
index a286b5243d4..a4fd4bcd958 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_area.h
+++ b/chromium/third_party/blink/renderer/core/style/grid_area.h
@@ -70,6 +70,17 @@ struct GridSpan {
end_line_ == o.end_line_;
}
+ bool operator<(const GridSpan& o) const {
+ DCHECK(IsTranslatedDefinite());
+ return start_line_ < o.start_line_ ||
+ (start_line_ == o.start_line_ && end_line_ < o.end_line_);
+ }
+
+ bool operator<=(const GridSpan& o) const {
+ DCHECK(IsTranslatedDefinite());
+ return *this < o || *this == o;
+ }
+
size_t IntegerSpan() const {
DCHECK(IsTranslatedDefinite());
DCHECK_GT(end_line_, start_line_);
@@ -120,8 +131,8 @@ struct GridSpan {
return end_line_;
}
+ bool IsUntranslatedDefinite() const { return type_ == kUntranslatedDefinite; }
bool IsTranslatedDefinite() const { return type_ == kTranslatedDefinite; }
-
bool IsIndefinite() const { return type_ == kIndefinite; }
void Translate(size_t offset) {
diff --git a/chromium/third_party/blink/renderer/core/style/grid_track_list.cc b/chromium/third_party/blink/renderer/core/style/grid_track_list.cc
index a484c44fd1d..98b48db09ae 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_track_list.cc
+++ b/chromium/third_party/blink/renderer/core/style/grid_track_list.cc
@@ -82,6 +82,10 @@ wtf_size_t NGGridTrackList::TotalTrackCount() const {
return total_track_count_;
}
+wtf_size_t NGGridTrackList::AutoRepeatSize() const {
+ return HasAutoRepeater() ? repeaters_[auto_repeater_index_].repeat_size : 0;
+}
+
bool NGGridTrackList::AddRepeater(
const Vector<GridTrackSize>& repeater_track_sizes,
wtf_size_t repeat_count) {
diff --git a/chromium/third_party/blink/renderer/core/style/grid_track_list.h b/chromium/third_party/blink/renderer/core/style/grid_track_list.h
index ba6321d4109..e2620d6204c 100644
--- a/chromium/third_party/blink/renderer/core/style/grid_track_list.h
+++ b/chromium/third_party/blink/renderer/core/style/grid_track_list.h
@@ -43,6 +43,7 @@ class CORE_EXPORT NGGridTrackList {
public:
NGGridTrackList() = default;
NGGridTrackList(const NGGridTrackList& other) = default;
+
// Returns the repeat count of the repeater at |index|, or |auto_value|
// if the repeater is auto.
wtf_size_t RepeatCount(const wtf_size_t index,
@@ -54,10 +55,13 @@ class CORE_EXPORT NGGridTrackList {
// Returns the size of the |n|-th specified track of the repeater at |index|.
const GridTrackSize& RepeatTrackSize(const wtf_size_t index,
const wtf_size_t n) const;
+
// Returns the count of repeaters.
wtf_size_t RepeaterCount() const;
// Returns the total count of all the tracks in this list.
wtf_size_t TotalTrackCount() const;
+ // Returns the number of tracks in the auto repeater, or 0 if there is none.
+ wtf_size_t AutoRepeatSize() const;
// Adds a non-auto repeater.
bool AddRepeater(const Vector<GridTrackSize>& repeater_track_sizes,
diff --git a/chromium/third_party/blink/renderer/core/style/list_style_type_data.cc b/chromium/third_party/blink/renderer/core/style/list_style_type_data.cc
new file mode 100644
index 00000000000..4af9f60f5cf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/list_style_type_data.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/core/style/list_style_type_data.h"
+
+#include "third_party/blink/renderer/core/css/counter_style.h"
+#include "third_party/blink/renderer/core/css/css_value_id_mappings.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/tree_scope.h"
+#include "third_party/blink/renderer/core/style/content_data.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+namespace {
+
+using PredefinedCounterStyleNameMap = HashMap<AtomicString, EListStyleType>;
+
+PredefinedCounterStyleNameMap BuildPredefinedCounterStyleNameMap() {
+ PredefinedCounterStyleNameMap map;
+ for (unsigned i = 0; i < static_cast<unsigned>(EListStyleType::kString);
+ ++i) {
+ EListStyleType list_style_type = static_cast<EListStyleType>(i);
+ CSSValueID css_value_id = PlatformEnumToCSSValueID(list_style_type);
+ AtomicString value_name(getValueName(css_value_id));
+ map.Set(value_name, list_style_type);
+ }
+ return map;
+}
+
+EListStyleType CounterStyleNameToDeprecatedEnum(const AtomicString& name) {
+ DEFINE_STATIC_LOCAL(PredefinedCounterStyleNameMap,
+ predefined_counter_style_name_map,
+ (BuildPredefinedCounterStyleNameMap()));
+ auto iterator = predefined_counter_style_name_map.find(name);
+ if (iterator != predefined_counter_style_name_map.end())
+ return iterator->value;
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+ return EListStyleType::kDecimal;
+}
+
+} // namespace
+
+void ListStyleTypeData::Trace(Visitor* visitor) const {
+ visitor->Trace(tree_scope_);
+ visitor->Trace(counter_style_);
+}
+
+// static
+ListStyleTypeData* ListStyleTypeData::CreateString(const AtomicString& value) {
+ return MakeGarbageCollected<ListStyleTypeData>(Type::kString, value, nullptr);
+}
+
+// static
+ListStyleTypeData* ListStyleTypeData::CreateCounterStyle(
+ const AtomicString& name,
+ const TreeScope* tree_scope) {
+ return MakeGarbageCollected<ListStyleTypeData>(Type::kCounterStyle, name,
+ tree_scope);
+}
+
+EListStyleType ListStyleTypeData::ToDeprecatedListStyleTypeEnum() const {
+ if (IsString())
+ return EListStyleType::kString;
+ return CounterStyleNameToDeprecatedEnum(GetCounterStyleName());
+}
+
+// TODO(crbug.com/687225): We temporarily put this function here to share the
+// common logic. Clean it up when @counter-style is shipped.
+EListStyleType CounterContentData::ToDeprecatedListStyleTypeEnum() const {
+ if (ListStyle() == "none")
+ return EListStyleType::kNone;
+ return CounterStyleNameToDeprecatedEnum(ListStyle());
+}
+
+bool ListStyleTypeData::IsCounterStyleReferenceValid(Document& document) const {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+
+ if (!IsCounterStyle()) {
+ DCHECK(!counter_style_);
+ return true;
+ }
+
+ if (!counter_style_ || counter_style_->IsDirty())
+ return false;
+
+ // Even if the referenced counter style is clean, it may still be stale if new
+ // counter styles have been inserted, in which case the same (scope, name) now
+ // refers to a different counter style. So we make an extra lookup to verify.
+ return counter_style_ ==
+ &document.GetStyleEngine().FindCounterStyleAcrossScopes(
+ GetCounterStyleName(), GetTreeScope());
+}
+
+const CounterStyle& ListStyleTypeData::GetCounterStyle(
+ Document& document) const {
+ DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled());
+ DCHECK(IsCounterStyle());
+ if (!IsCounterStyleReferenceValid(document)) {
+ counter_style_ = document.GetStyleEngine().FindCounterStyleAcrossScopes(
+ GetCounterStyleName(), GetTreeScope());
+ }
+ return *counter_style_;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/list_style_type_data.h b/chromium/third_party/blink/renderer/core/style/list_style_type_data.h
new file mode 100644
index 00000000000..8b79e26d5a0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/list_style_type_data.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_LIST_STYLE_TYPE_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_LIST_STYLE_TYPE_DATA_H_
+
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink {
+
+class CounterStyle;
+class Document;
+class TreeScope;
+
+class ListStyleTypeData final : public GarbageCollected<ListStyleTypeData> {
+ public:
+ ~ListStyleTypeData() = default;
+ void Trace(Visitor*) const;
+
+ enum class Type { kCounterStyle, kString };
+
+ ListStyleTypeData(Type type,
+ AtomicString name_or_string_value,
+ const TreeScope* tree_scope)
+ : type_(type),
+ name_or_string_value_(std::move(name_or_string_value)),
+ tree_scope_(tree_scope) {}
+
+ static ListStyleTypeData* CreateString(const AtomicString&);
+ static ListStyleTypeData* CreateCounterStyle(const AtomicString&,
+ const TreeScope*);
+
+ bool operator==(const ListStyleTypeData& other) const {
+ return type_ == other.type_ &&
+ name_or_string_value_ == other.name_or_string_value_ &&
+ tree_scope_ == other.tree_scope_;
+ }
+ bool operator!=(const ListStyleTypeData& other) const {
+ return !operator==(other);
+ }
+
+ bool IsCounterStyle() const { return type_ == Type::kCounterStyle; }
+ bool IsString() const { return type_ == Type::kString; }
+
+ const AtomicString& GetCounterStyleName() const {
+ DCHECK_EQ(Type::kCounterStyle, type_);
+ return name_or_string_value_;
+ }
+
+ const AtomicString& GetStringValue() const {
+ DCHECK_EQ(Type::kString, type_);
+ return name_or_string_value_;
+ }
+
+ const TreeScope* GetTreeScope() const { return tree_scope_; }
+
+ // TODO(crbug.com/687225): Try not to pass a Document, which is cumbersome.
+ bool IsCounterStyleReferenceValid(Document&) const;
+ const CounterStyle& GetCounterStyle(Document&) const;
+
+ EListStyleType ToDeprecatedListStyleTypeEnum() const;
+
+ private:
+ Type type_;
+ AtomicString name_or_string_value_;
+
+ // The tree scope for looking up the custom counter style name
+ Member<const TreeScope> tree_scope_;
+
+ // The CounterStyle that we are using. The reference is updated on demand.
+ // Note: this is NOT part of the computed value of 'list-style-type'.
+ mutable Member<const CounterStyle> counter_style_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_LIST_STYLE_TYPE_DATA_H_
diff --git a/chromium/third_party/blink/renderer/core/style/shadow_list.cc b/chromium/third_party/blink/renderer/core/style/shadow_list.cc
index 64ed569056e..efcde4f8bf3 100644
--- a/chromium/third_party/blink/renderer/core/style/shadow_list.cc
+++ b/chromium/third_party/blink/renderer/core/style/shadow_list.cc
@@ -49,23 +49,4 @@ void ShadowList::AdjustRectForShadow(FloatRect& rect) const {
rect.Expand(RectOutsetsIncludingOriginal());
}
-sk_sp<SkDrawLooper> ShadowList::CreateDrawLooper(
- DrawLooperBuilder::ShadowAlphaMode alpha_mode,
- const Color& current_color,
- mojom::blink::ColorScheme color_scheme,
- bool is_horizontal) const {
- DrawLooperBuilder draw_looper_builder;
- for (wtf_size_t i = Shadows().size(); i--;) {
- const ShadowData& shadow = Shadows()[i];
- float shadow_x = is_horizontal ? shadow.X() : shadow.Y();
- float shadow_y = is_horizontal ? shadow.Y() : -shadow.X();
- draw_looper_builder.AddShadow(
- FloatSize(shadow_x, shadow_y), shadow.Blur(),
- shadow.GetColor().Resolve(current_color, color_scheme),
- DrawLooperBuilder::kShadowRespectsTransforms, alpha_mode);
- }
- draw_looper_builder.AddUnmodifiedContent();
- return draw_looper_builder.DetachDrawLooper();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/shadow_list.h b/chromium/third_party/blink/renderer/core/style/shadow_list.h
index 78ee292cff8..f292cf73ecc 100644
--- a/chromium/third_party/blink/renderer/core/style/shadow_list.h
+++ b/chromium/third_party/blink/renderer/core/style/shadow_list.h
@@ -65,11 +65,6 @@ class ShadowList : public RefCounted<ShadowList> {
void AdjustRectForShadow(FloatRect&) const;
- sk_sp<SkDrawLooper> CreateDrawLooper(DrawLooperBuilder::ShadowAlphaMode,
- const Color& current_color,
- mojom::blink::ColorScheme color_scheme,
- bool is_horizontal = true) const;
-
private:
ShadowList(ShadowDataVector& shadows) {
// If we have no shadows, we use a null ShadowList
diff --git a/chromium/third_party/blink/renderer/core/style/style_aspect_ratio.h b/chromium/third_party/blink/renderer/core/style/style_aspect_ratio.h
index f451519ec51..e2d42141182 100644
--- a/chromium/third_party/blink/renderer/core/style/style_aspect_ratio.h
+++ b/chromium/third_party/blink/renderer/core/style/style_aspect_ratio.h
@@ -5,7 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_ASPECT_RATIO_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_ASPECT_RATIO_H_
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/style/style_fetched_image.cc b/chromium/third_party/blink/renderer/core/style/style_fetched_image.cc
index 90f227b82b9..3b7c304d151 100644
--- a/chromium/third_party/blink/renderer/core/style/style_fetched_image.cc
+++ b/chromium/third_party/blink/renderer/core/style/style_fetched_image.cc
@@ -118,7 +118,7 @@ FloatSize StyleFetchedImage::ImageSize(
if (auto* svg_image = DynamicTo<SVGImage>(image)) {
return ImageSizeForSVGImage(svg_image, multiplier, default_object_size);
}
-
+ respect_orientation = ForceOrientationIfNecessary(respect_orientation);
FloatSize size(image->Size(respect_orientation));
return ApplyZoom(size, multiplier);
}
@@ -136,18 +136,26 @@ void StyleFetchedImage::RemoveClient(ImageResourceObserver* observer) {
}
void StyleFetchedImage::ImageNotifyFinished(ImageResourceContent*) {
+ if (!document_)
+ return;
+
if (image_ && image_->HasImage()) {
Image& image = *image_->GetImage();
- auto* svg_image = DynamicTo<SVGImage>(image);
- if (document_ && svg_image)
+ if (auto* svg_image = DynamicTo<SVGImage>(image)) {
+ // SVG's document should be completely loaded before access control
+ // checks, which can occur anytime after ImageNotifyFinished()
+ // (See SVGImage::CurrentFrameHasSingleSecurityOrigin()).
+ // We check the document is loaded here to catch violation of the
+ // assumption reliably.
+ svg_image->CheckLoaded();
svg_image->UpdateUseCounters(*document_);
+ }
+ image_->RecordDecodedImageType(document_->GetExecutionContext());
}
- if (document_) {
- if (LocalDOMWindow* window = document_->domWindow())
- ImageElementTiming::From(*window).NotifyBackgroundImageFinished(this);
- }
+ if (LocalDOMWindow* window = document_->domWindow())
+ ImageElementTiming::From(*window).NotifyBackgroundImageFinished(this);
// Oilpan: do not prolong the Document's lifetime.
document_.Clear();
@@ -187,6 +195,19 @@ void StyleFetchedImage::LoadDeferredImage(const Document& document) {
image_->LoadDeferredImage(document_->Fetcher());
}
+RespectImageOrientationEnum StyleFetchedImage::ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const {
+ // SVG Images don't have orientation and assert on loading when
+ // IsAccessAllowed is called.
+ if (image_->GetImage()->IsSVGImage())
+ return default_orientation;
+ // Cross-origin images must always respect orientation to prevent
+ // potentially private data leakage.
+ if (!image_->IsAccessAllowed())
+ return kRespectImageOrientation;
+ return default_orientation;
+}
+
bool StyleFetchedImage::GetImageAnimationPolicy(
mojom::blink::ImageAnimationPolicy& policy) {
if (!document_ || !document_->GetSettings()) {
diff --git a/chromium/third_party/blink/renderer/core/style/style_fetched_image.h b/chromium/third_party/blink/renderer/core/style/style_fetched_image.h
index 65596587c45..97548e6647b 100644
--- a/chromium/third_party/blink/renderer/core/style/style_fetched_image.h
+++ b/chromium/third_party/blink/renderer/core/style/style_fetched_image.h
@@ -74,6 +74,9 @@ class StyleFetchedImage final : public StyleImage,
void LoadDeferredImage(const Document& document);
+ RespectImageOrientationEnum ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const override;
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.cc b/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.cc
index 288d471aeeb..0fe22a09cd9 100644
--- a/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.cc
+++ b/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.cc
@@ -102,6 +102,7 @@ FloatSize StyleFetchedImageSet::ImageSize(
if (auto* svg_image = DynamicTo<SVGImage>(image)) {
return ImageSizeForSVGImage(svg_image, multiplier, default_object_size);
}
+ respect_orientation = ForceOrientationIfNecessary(respect_orientation);
FloatSize natural_size(image->Size(respect_orientation));
FloatSize scaled_image_size(ApplyZoom(natural_size, multiplier));
scaled_image_size.Scale(1 / image_scale_factor_);
@@ -143,6 +144,19 @@ bool StyleFetchedImageSet::KnownToBeOpaque(const Document&,
return best_fit_image_->GetImage()->CurrentFrameKnownToBeOpaque();
}
+RespectImageOrientationEnum StyleFetchedImageSet::ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const {
+ // SVG Images don't have orientation and assert on loading when
+ // IsAccessAllowed is called.
+ if (best_fit_image_->GetImage()->IsSVGImage())
+ return default_orientation;
+ // Cross-origin images must always respect orientation to prevent
+ // potentially private data leakage.
+ if (!best_fit_image_->IsAccessAllowed())
+ return kRespectImageOrientation;
+ return default_orientation;
+}
+
void StyleFetchedImageSet::Trace(Visitor* visitor) const {
visitor->Trace(best_fit_image_);
visitor->Trace(image_set_value_);
diff --git a/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.h b/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.h
index 24ed4143769..5eb6f5f943e 100644
--- a/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.h
+++ b/chromium/third_party/blink/renderer/core/style/style_fetched_image_set.h
@@ -80,6 +80,9 @@ class StyleFetchedImageSet final : public StyleImage,
bool KnownToBeOpaque(const Document&, const ComputedStyle&) const override;
ImageResourceContent* CachedImage() const override;
+ RespectImageOrientationEnum ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const override;
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/core/style/style_image.h b/chromium/third_party/blink/renderer/core/style/style_image.h
index a6eedc714df..2ca275b575c 100644
--- a/chromium/third_party/blink/renderer/core/style/style_image.h
+++ b/chromium/third_party/blink/renderer/core/style/style_image.h
@@ -133,6 +133,13 @@ class CORE_EXPORT StyleImage : public GarbageCollected<StyleImage> {
// underlying ImageResourceContent, or otherwise nullptr.
virtual ImageResourceContent* CachedImage() const { return nullptr; }
+ // Correct the image orientation preference for potentially cross-origin
+ // content.
+ virtual RespectImageOrientationEnum ForceOrientationIfNecessary(
+ RespectImageOrientationEnum default_orientation) const {
+ return default_orientation;
+ }
+
ALWAYS_INLINE bool IsImageResource() const { return is_image_resource_; }
ALWAYS_INLINE bool IsPendingImage() const { return is_pending_image_; }
ALWAYS_INLINE bool IsGeneratedImage() const { return is_generated_image_; }
diff --git a/chromium/third_party/blink/renderer/core/style/style_pending_image.cc b/chromium/third_party/blink/renderer/core/style/style_pending_image.cc
index 68468ada2a8..f793daca994 100644
--- a/chromium/third_party/blink/renderer/core/style/style_pending_image.cc
+++ b/chromium/third_party/blink/renderer/core/style/style_pending_image.cc
@@ -4,6 +4,9 @@
#include "third_party/blink/renderer/core/style/style_pending_image.h"
+#include "third_party/blink/renderer/core/css/css_image_generator_value.h"
+#include "third_party/blink/renderer/core/css/css_image_set_value.h"
+#include "third_party/blink/renderer/core/css/css_image_value.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
@@ -13,14 +16,15 @@ CSSValue* StylePendingImage::ComputedCSSValue(const ComputedStyle& style,
DCHECK(style.IsEnsuredInDisplayNone() ||
style.Display() == EDisplay::kContents);
- if (CSSImageValue* image_value = CssImageValue())
+ CSSValue* value = CssValue();
+ if (auto* image_value = DynamicTo<CSSImageValue>(value))
return image_value->ValueWithURLMadeAbsolute();
- if (CSSImageSetValue* image_set_value = CssImageSetValue())
+ if (auto* image_set_value = DynamicTo<CSSImageSetValue>(value))
return image_set_value->ValueWithURLsMadeAbsolute();
- if (CSSImageGeneratorValue* image_generator_value = CssImageGeneratorValue())
+ if (auto* image_generator_value = DynamicTo<CSSImageGeneratorValue>(value))
return image_generator_value->ComputedCSSValue(style, allow_visited_style);
NOTREACHED();
- return CssValue();
+ return value;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/style_pending_image.h b/chromium/third_party/blink/renderer/core/style/style_pending_image.h
index 961228307a3..d06e9a5d541 100644
--- a/chromium/third_party/blink/renderer/core/style/style_pending_image.h
+++ b/chromium/third_party/blink/renderer/core/style/style_pending_image.h
@@ -26,16 +26,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_PENDING_IMAGE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_PENDING_IMAGE_H_
-#include "third_party/blink/renderer/core/css/css_image_generator_value.h"
-#include "third_party/blink/renderer/core/css/css_image_set_value.h"
-#include "third_party/blink/renderer/core/css/css_image_value.h"
-#include "third_party/blink/renderer/core/css/css_paint_value.h"
#include "third_party/blink/renderer/core/style/style_image.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
+class CSSValue;
class ImageResourceObserver;
// StylePendingImage is a placeholder StyleImage that is entered into the
@@ -57,19 +54,6 @@ class StylePendingImage final : public StyleImage {
CSSValue* ComputedCSSValue(const ComputedStyle& style,
bool allow_visited_style) const override;
- CSSImageValue* CssImageValue() const {
- return DynamicTo<CSSImageValue>(value_.Get());
- }
- CSSPaintValue* CssPaintValue() const {
- return DynamicTo<CSSPaintValue>(value_.Get());
- }
- CSSImageGeneratorValue* CssImageGeneratorValue() const {
- return DynamicTo<CSSImageGeneratorValue>(value_.Get());
- }
- CSSImageSetValue* CssImageSetValue() const {
- return DynamicTo<CSSImageSetValue>(value_.Get());
- }
-
FloatSize ImageSize(const Document&,
float,
const FloatSize&,
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style.cc b/chromium/third_party/blink/renderer/core/style/svg_computed_style.cc
deleted file mode 100644
index 6d4354beaff..00000000000
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style.cc
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005, 2010 Rob Buis <buis@kde.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- Based on khtml code by:
- Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
- Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
- Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
- Copyright (C) 2002 Apple Computer, Inc.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
-
-#include "third_party/blink/renderer/core/style/data_equivalency.h"
-#include "third_party/blink/renderer/core/style/style_difference.h"
-#include "third_party/blink/renderer/core/style/style_svg_resource.h"
-
-namespace blink {
-
-static const int kPaintOrderBitwidth = 2;
-
-SVGComputedStyle::SVGComputedStyle() {
- static SVGComputedStyle* initial_style = new SVGComputedStyle(kCreateInitial);
-
- fill = initial_style->fill;
- stroke = initial_style->stroke;
- stops = initial_style->stops;
- misc = initial_style->misc;
- inherited_resources = initial_style->inherited_resources;
- geometry = initial_style->geometry;
- resources = initial_style->resources;
-
- SetBitDefaults();
-}
-
-SVGComputedStyle::SVGComputedStyle(CreateInitialType) {
- SetBitDefaults();
-
- fill.Init();
- stroke.Init();
- stops.Init();
- misc.Init();
- inherited_resources.Init();
- geometry.Init();
- resources.Init();
-}
-
-SVGComputedStyle::SVGComputedStyle(const SVGComputedStyle& other)
- : RefCounted<SVGComputedStyle>() {
- fill = other.fill;
- stroke = other.stroke;
- stops = other.stops;
- misc = other.misc;
- inherited_resources = other.inherited_resources;
- geometry = other.geometry;
- resources = other.resources;
-
- svg_inherited_flags = other.svg_inherited_flags;
- svg_noninherited_flags = other.svg_noninherited_flags;
-}
-
-SVGComputedStyle::~SVGComputedStyle() = default;
-
-bool SVGComputedStyle::operator==(const SVGComputedStyle& other) const {
- return InheritedEqual(other) && NonInheritedEqual(other);
-}
-
-bool SVGComputedStyle::InheritedEqual(const SVGComputedStyle& other) const {
- return fill == other.fill && stroke == other.stroke &&
- inherited_resources == other.inherited_resources &&
- svg_inherited_flags == other.svg_inherited_flags;
-}
-
-bool SVGComputedStyle::NonInheritedEqual(const SVGComputedStyle& other) const {
- return stops == other.stops && misc == other.misc &&
- geometry == other.geometry && resources == other.resources &&
- svg_noninherited_flags == other.svg_noninherited_flags;
-}
-
-void SVGComputedStyle::InheritFrom(const SVGComputedStyle& svg_inherit_parent) {
- fill = svg_inherit_parent.fill;
- stroke = svg_inherit_parent.stroke;
- inherited_resources = svg_inherit_parent.inherited_resources;
-
- svg_inherited_flags = svg_inherit_parent.svg_inherited_flags;
-}
-
-void SVGComputedStyle::CopyNonInheritedFromCached(
- const SVGComputedStyle& other) {
- svg_noninherited_flags = other.svg_noninherited_flags;
- stops = other.stops;
- misc = other.misc;
- geometry = other.geometry;
- resources = other.resources;
-}
-
-scoped_refptr<SVGDashArray> SVGComputedStyle::InitialStrokeDashArray() {
- DEFINE_STATIC_REF(SVGDashArray, initial_dash_array,
- base::MakeRefCounted<SVGDashArray>());
- return initial_dash_array;
-}
-
-StyleDifference SVGComputedStyle::Diff(const SVGComputedStyle& other) const {
- StyleDifference style_difference;
-
- if (DiffNeedsLayoutAndPaintInvalidation(other)) {
- style_difference.SetNeedsFullLayout();
- style_difference.SetNeedsPaintInvalidation();
- } else if (DiffNeedsPaintInvalidation(other)) {
- style_difference.SetNeedsPaintInvalidation();
- }
-
- if (!DataEquivalent(resources->masker, other.resources->masker))
- style_difference.SetMaskChanged();
-
- return style_difference;
-}
-
-bool SVGComputedStyle::DiffNeedsLayoutAndPaintInvalidation(
- const SVGComputedStyle& other) const {
- // If resources change, we need a relayout, as the presence of resources
- // influences the visual rect.
- if (resources != other.resources)
- return true;
-
- // If markers change, we need a relayout, as marker boundaries are cached in
- // LayoutSVGPath.
- if (inherited_resources != other.inherited_resources)
- return true;
-
- // All text related properties influence layout.
- if (svg_inherited_flags.text_anchor !=
- other.svg_inherited_flags.text_anchor ||
- svg_inherited_flags.dominant_baseline !=
- other.svg_inherited_flags.dominant_baseline ||
- svg_noninherited_flags.f.alignment_baseline !=
- other.svg_noninherited_flags.f.alignment_baseline ||
- svg_noninherited_flags.f.baseline_shift !=
- other.svg_noninherited_flags.f.baseline_shift)
- return true;
-
- // Text related properties influence layout.
- if (misc->baseline_shift_value != other.misc->baseline_shift_value)
- return true;
-
- // These properties affect the cached stroke bounding box rects.
- if (svg_inherited_flags.cap_style != other.svg_inherited_flags.cap_style ||
- svg_inherited_flags.join_style != other.svg_inherited_flags.join_style)
- return true;
-
- // vector-effect changes require a re-layout.
- if (svg_noninherited_flags.f.vector_effect !=
- other.svg_noninherited_flags.f.vector_effect)
- return true;
-
- // Some stroke properties require relayouts as the cached stroke boundaries
- // need to be recalculated.
- if (stroke.Get() != other.stroke.Get()) {
- if (stroke->width != other.stroke->width ||
- stroke->miter_limit != other.stroke->miter_limit)
- return true;
- // If the stroke is toggled from/to 'none' we need to relayout, because the
- // stroke shape will have changed.
- if (stroke->paint.IsNone() != other.stroke->paint.IsNone())
- return true;
- // If the dash array is toggled from/to 'none' we need to relayout, because
- // some shapes will decide on which codepath to use based on the presence
- // of a dash array.
- if (stroke->dash_array->data.IsEmpty() !=
- other.stroke->dash_array->data.IsEmpty())
- return true;
- }
-
- // The geometry properties require a re-layout.
- if (geometry.Get() != other.geometry.Get() && *geometry != *other.geometry)
- return true;
-
- return false;
-}
-
-bool SVGComputedStyle::DiffNeedsPaintInvalidation(
- const SVGComputedStyle& other) const {
- if (stroke.Get() != other.stroke.Get()) {
- if (stroke->paint != other.stroke->paint ||
- stroke->opacity != other.stroke->opacity ||
- stroke->visited_link_paint != other.stroke->visited_link_paint)
- return true;
- // Changes to the dash effect only require a repaint because we don't
- // include it when computing (approximating) the stroke boundaries during
- // layout.
- if (stroke->dash_offset != other.stroke->dash_offset ||
- stroke->dash_array->data != other.stroke->dash_array->data)
- return true;
- }
-
- // Painting related properties only need paint invalidation.
- if (misc.Get() != other.misc.Get()) {
- if (misc->flood_color != other.misc->flood_color ||
- misc->flood_opacity != other.misc->flood_opacity ||
- misc->lighting_color != other.misc->lighting_color)
- return true;
- }
-
- // If fill changes, we just need to issue paint invalidations. Fill boundaries
- // are not influenced by this, only by the Path, that LayoutSVGPath contains.
- if (fill.Get() != other.fill.Get()) {
- if (fill->paint != other.fill->paint ||
- fill->opacity != other.fill->opacity)
- return true;
- }
-
- // If gradient stops change, we just need to issue paint invalidations. Style
- // updates are already handled through SVGStopElement.
- if (stops != other.stops)
- return true;
-
- // Changes of these flags only cause paint invalidations.
- if (svg_inherited_flags.shape_rendering !=
- other.svg_inherited_flags.shape_rendering ||
- svg_inherited_flags.clip_rule != other.svg_inherited_flags.clip_rule ||
- svg_inherited_flags.fill_rule != other.svg_inherited_flags.fill_rule ||
- svg_inherited_flags.color_interpolation !=
- other.svg_inherited_flags.color_interpolation ||
- svg_inherited_flags.color_interpolation_filters !=
- other.svg_inherited_flags.color_interpolation_filters ||
- svg_inherited_flags.paint_order != other.svg_inherited_flags.paint_order)
- return true;
-
- if (svg_noninherited_flags.f.mask_type !=
- other.svg_noninherited_flags.f.mask_type)
- return true;
-
- return false;
-}
-
-unsigned PaintOrderSequence(EPaintOrderType first,
- EPaintOrderType second,
- EPaintOrderType third) {
- return (((third << kPaintOrderBitwidth) | second) << kPaintOrderBitwidth) |
- first;
-}
-
-EPaintOrderType SVGComputedStyle::PaintOrderType(unsigned index) const {
- unsigned pt = 0;
- DCHECK(index < ((1 << kPaintOrderBitwidth) - 1));
- switch (this->PaintOrder()) {
- case kPaintOrderNormal:
- case kPaintOrderFillStrokeMarkers:
- pt = PaintOrderSequence(PT_FILL, PT_STROKE, PT_MARKERS);
- break;
- case kPaintOrderFillMarkersStroke:
- pt = PaintOrderSequence(PT_FILL, PT_MARKERS, PT_STROKE);
- break;
- case kPaintOrderStrokeFillMarkers:
- pt = PaintOrderSequence(PT_STROKE, PT_FILL, PT_MARKERS);
- break;
- case kPaintOrderStrokeMarkersFill:
- pt = PaintOrderSequence(PT_STROKE, PT_MARKERS, PT_FILL);
- break;
- case kPaintOrderMarkersFillStroke:
- pt = PaintOrderSequence(PT_MARKERS, PT_FILL, PT_STROKE);
- break;
- case kPaintOrderMarkersStrokeFill:
- pt = PaintOrderSequence(PT_MARKERS, PT_STROKE, PT_FILL);
- break;
- }
-
- pt =
- (pt >> (kPaintOrderBitwidth * index)) & ((1u << kPaintOrderBitwidth) - 1);
- return (EPaintOrderType)pt;
-}
-
-void SVGComputedStyle::SetMaskerResource(
- scoped_refptr<StyleSVGResource> resource) {
- if (!(resources->masker == resource))
- resources.Access()->masker = std::move(resource);
-}
-
-void SVGComputedStyle::SetMarkerStartResource(
- scoped_refptr<StyleSVGResource> resource) {
- if (!(inherited_resources->marker_start == resource))
- inherited_resources.Access()->marker_start = std::move(resource);
-}
-
-void SVGComputedStyle::SetMarkerMidResource(
- scoped_refptr<StyleSVGResource> resource) {
- if (!(inherited_resources->marker_mid == resource))
- inherited_resources.Access()->marker_mid = std::move(resource);
-}
-
-void SVGComputedStyle::SetMarkerEndResource(
- scoped_refptr<StyleSVGResource> resource) {
- if (!(inherited_resources->marker_end == resource))
- inherited_resources.Access()->marker_end = std::move(resource);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style.h b/chromium/third_party/blink/renderer/core/style/svg_computed_style.h
deleted file mode 100644
index 2e6c5496b55..00000000000
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style.h
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005 Rob Buis <buis@kde.org>
- Copyright (C) 2005, 2006 Apple Computer, Inc.
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/style_color.h"
-#include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/core/style/data_ref.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
-#include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-
-namespace blink {
-
-class StyleDifference;
-
-// TODO(sashab): Move this into a private class on ComputedStyle, and remove
-// all methods on it, merging them into copy/creation methods on ComputedStyle
-// instead. Keep the allocation logic, only allocating a new object if needed.
-class SVGComputedStyle : public RefCounted<SVGComputedStyle> {
- USING_FAST_MALLOC(SVGComputedStyle);
-
- public:
- static scoped_refptr<SVGComputedStyle> Create() {
- return base::AdoptRef(new SVGComputedStyle);
- }
- scoped_refptr<SVGComputedStyle> Copy() const {
- return base::AdoptRef(new SVGComputedStyle(*this));
- }
- CORE_EXPORT ~SVGComputedStyle();
-
- bool InheritedEqual(const SVGComputedStyle&) const;
- bool NonInheritedEqual(const SVGComputedStyle&) const;
- void InheritFrom(const SVGComputedStyle&);
- void CopyNonInheritedFromCached(const SVGComputedStyle&);
-
- CORE_EXPORT StyleDifference Diff(const SVGComputedStyle&) const;
-
- bool operator==(const SVGComputedStyle&) const;
- bool operator!=(const SVGComputedStyle& o) const { return !(*this == o); }
-
- // Initial values for all the properties
- static EAlignmentBaseline InitialAlignmentBaseline() { return AB_AUTO; }
- static EDominantBaseline InitialDominantBaseline() { return DB_AUTO; }
- static EBaselineShift InitialBaselineShift() { return BS_LENGTH; }
- static Length InitialBaselineShiftValue() { return Length::Fixed(); }
- static EVectorEffect InitialVectorEffect() { return VE_NONE; }
- static EBufferedRendering InitialBufferedRendering() { return BR_AUTO; }
- static LineCap InitialCapStyle() { return kButtCap; }
- static WindRule InitialClipRule() { return RULE_NONZERO; }
- static EColorInterpolation InitialColorInterpolation() { return CI_SRGB; }
- static EColorInterpolation InitialColorInterpolationFilters() {
- return CI_LINEARRGB;
- }
- static EColorRendering InitialColorRendering() { return CR_AUTO; }
- static WindRule InitialFillRule() { return RULE_NONZERO; }
- static LineJoin InitialJoinStyle() { return kMiterJoin; }
- static EShapeRendering InitialShapeRendering() { return SR_AUTO; }
- static ETextAnchor InitialTextAnchor() { return TA_START; }
- static float InitialFillOpacity() { return 1; }
- static SVGPaint InitialFillPaint() { return SVGPaint(Color::kBlack); }
- static float InitialStrokeOpacity() { return 1; }
- static SVGPaint InitialStrokePaint() { return SVGPaint(); }
- static scoped_refptr<SVGDashArray> InitialStrokeDashArray();
- static Length InitialStrokeDashOffset() { return Length::Fixed(); }
- static float InitialStrokeMiterLimit() { return 4; }
- static UnzoomedLength InitialStrokeWidth() {
- return UnzoomedLength(Length::Fixed(1));
- }
- static float InitialStopOpacity() { return 1; }
- static StyleColor InitialStopColor() { return StyleColor(Color::kBlack); }
- static float InitialFloodOpacity() { return 1; }
- static StyleColor InitialFloodColor() { return StyleColor(Color::kBlack); }
- static StyleColor InitialLightingColor() { return StyleColor(Color::kWhite); }
- static StyleSVGResource* InitialMaskerResource() { return nullptr; }
- static StyleSVGResource* InitialMarkerStartResource() { return nullptr; }
- static StyleSVGResource* InitialMarkerMidResource() { return nullptr; }
- static StyleSVGResource* InitialMarkerEndResource() { return nullptr; }
- static EMaskType InitialMaskType() { return MT_LUMINANCE; }
- static EPaintOrder InitialPaintOrder() { return kPaintOrderNormal; }
- static StylePath* InitialD() { return nullptr; }
- static Length InitialCx() { return Length::Fixed(); }
- static Length InitialCy() { return Length::Fixed(); }
- static Length InitialX() { return Length::Fixed(); }
- static Length InitialY() { return Length::Fixed(); }
- static Length InitialR() { return Length::Fixed(); }
- static Length InitialRx() { return Length::Auto(); }
- static Length InitialRy() { return Length::Auto(); }
-
- // SVG CSS Property setters
- void SetAlignmentBaseline(EAlignmentBaseline val) {
- svg_noninherited_flags.f.alignment_baseline = val;
- }
- void SetDominantBaseline(EDominantBaseline val) {
- svg_inherited_flags.dominant_baseline = val;
- }
- void SetBaselineShift(EBaselineShift val) {
- svg_noninherited_flags.f.baseline_shift = val;
- }
- void SetVectorEffect(EVectorEffect val) {
- svg_noninherited_flags.f.vector_effect = val;
- }
- void SetBufferedRendering(EBufferedRendering val) {
- svg_noninherited_flags.f.buffered_rendering = val;
- }
- void SetCapStyle(LineCap val) { svg_inherited_flags.cap_style = val; }
- void SetClipRule(WindRule val) { svg_inherited_flags.clip_rule = val; }
- void SetColorInterpolation(EColorInterpolation val) {
- svg_inherited_flags.color_interpolation = val;
- }
- void SetColorInterpolationFilters(EColorInterpolation val) {
- svg_inherited_flags.color_interpolation_filters = val;
- }
- void SetColorRendering(EColorRendering val) {
- svg_inherited_flags.color_rendering = val;
- }
- void SetFillRule(WindRule val) { svg_inherited_flags.fill_rule = val; }
- void SetJoinStyle(LineJoin val) { svg_inherited_flags.join_style = val; }
- void SetShapeRendering(EShapeRendering val) {
- svg_inherited_flags.shape_rendering = val;
- }
- void SetTextAnchor(ETextAnchor val) { svg_inherited_flags.text_anchor = val; }
- void SetMaskType(EMaskType val) { svg_noninherited_flags.f.mask_type = val; }
- void SetPaintOrder(EPaintOrder val) {
- svg_inherited_flags.paint_order = (int)val;
- }
- void SetD(scoped_refptr<StylePath> d) {
- if (!(geometry->d == d))
- geometry.Access()->d = std::move(d);
- }
- void SetCx(const Length& obj) {
- if (!(geometry->cx == obj))
- geometry.Access()->cx = obj;
- }
- void SetCy(const Length& obj) {
- if (!(geometry->cy == obj))
- geometry.Access()->cy = obj;
- }
- void SetX(const Length& obj) {
- if (!(geometry->x == obj))
- geometry.Access()->x = obj;
- }
- void SetY(const Length& obj) {
- if (!(geometry->y == obj))
- geometry.Access()->y = obj;
- }
- void SetR(const Length& obj) {
- if (!(geometry->r == obj))
- geometry.Access()->r = obj;
- }
- void SetRx(const Length& obj) {
- if (!(geometry->rx == obj))
- geometry.Access()->rx = obj;
- }
- void SetRy(const Length& obj) {
- if (!(geometry->ry == obj))
- geometry.Access()->ry = obj;
- }
- void SetFillOpacity(float obj) {
- if (!(fill->opacity == obj))
- fill.Access()->opacity = obj;
- }
-
- void SetFillPaint(const SVGPaint& paint) {
- if (!(fill->paint == paint))
- fill.Access()->paint = paint;
- }
-
- void SetInternalVisitedFillPaint(const SVGPaint& paint) {
- if (!(fill->visited_link_paint == paint))
- fill.Access()->visited_link_paint = paint;
- }
-
- void SetStrokeOpacity(float obj) {
- if (!(stroke->opacity == obj))
- stroke.Access()->opacity = obj;
- }
-
- void SetStrokePaint(const SVGPaint& paint) {
- if (!(stroke->paint == paint))
- stroke.Access()->paint = paint;
- }
-
- void SetInternalVisitedStrokePaint(const SVGPaint& paint) {
- if (!(stroke->visited_link_paint == paint))
- stroke.Access()->visited_link_paint = paint;
- }
-
- void SetStrokeDashArray(scoped_refptr<SVGDashArray> dash_array) {
- if (stroke->dash_array->data != dash_array->data)
- stroke.Access()->dash_array = std::move(dash_array);
- }
-
- void SetStrokeMiterLimit(float obj) {
- if (!(stroke->miter_limit == obj))
- stroke.Access()->miter_limit = obj;
- }
-
- void SetStrokeWidth(const UnzoomedLength& stroke_width) {
- if (!(stroke->width == stroke_width))
- stroke.Access()->width = stroke_width;
- }
-
- void SetStrokeDashOffset(const Length& dash_offset) {
- if (!(stroke->dash_offset == dash_offset))
- stroke.Access()->dash_offset = dash_offset;
- }
-
- void SetStopOpacity(float obj) {
- if (!(stops->opacity == obj))
- stops.Access()->opacity = obj;
- }
-
- void SetStopColor(const StyleColor& obj) {
- if (!(stops->color == obj))
- stops.Access()->color = obj;
- }
-
- void SetFloodOpacity(float obj) {
- if (!(misc->flood_opacity == obj))
- misc.Access()->flood_opacity = obj;
- }
-
- void SetFloodColor(const StyleColor& color) {
- if (!(misc->flood_color == color))
- misc.Access()->flood_color = color;
- }
-
- void SetLightingColor(const StyleColor& color) {
- if (!(misc->lighting_color == color))
- misc.Access()->lighting_color = color;
- }
-
- void SetBaselineShiftValue(const Length& baseline_shift_value) {
- if (!(misc->baseline_shift_value == baseline_shift_value))
- misc.Access()->baseline_shift_value = baseline_shift_value;
- }
-
- // Setters for non-inherited resources
- void SetMaskerResource(scoped_refptr<StyleSVGResource> resource);
-
- // Setters for inherited resources
- void SetMarkerStartResource(scoped_refptr<StyleSVGResource> resource);
-
- void SetMarkerMidResource(scoped_refptr<StyleSVGResource> resource);
-
- void SetMarkerEndResource(scoped_refptr<StyleSVGResource> resource);
-
- // Read accessors for all the properties
- EAlignmentBaseline AlignmentBaseline() const {
- return (EAlignmentBaseline)svg_noninherited_flags.f.alignment_baseline;
- }
- EDominantBaseline DominantBaseline() const {
- return (EDominantBaseline)svg_inherited_flags.dominant_baseline;
- }
- EBaselineShift BaselineShift() const {
- return (EBaselineShift)svg_noninherited_flags.f.baseline_shift;
- }
- EVectorEffect VectorEffect() const {
- return (EVectorEffect)svg_noninherited_flags.f.vector_effect;
- }
- EBufferedRendering BufferedRendering() const {
- return (EBufferedRendering)svg_noninherited_flags.f.buffered_rendering;
- }
- LineCap CapStyle() const { return (LineCap)svg_inherited_flags.cap_style; }
- WindRule ClipRule() const { return (WindRule)svg_inherited_flags.clip_rule; }
- EColorInterpolation ColorInterpolation() const {
- return (EColorInterpolation)svg_inherited_flags.color_interpolation;
- }
- EColorInterpolation ColorInterpolationFilters() const {
- return (EColorInterpolation)svg_inherited_flags.color_interpolation_filters;
- }
- EColorRendering ColorRendering() const {
- return (EColorRendering)svg_inherited_flags.color_rendering;
- }
- WindRule FillRule() const { return (WindRule)svg_inherited_flags.fill_rule; }
- LineJoin JoinStyle() const {
- return (LineJoin)svg_inherited_flags.join_style;
- }
- EShapeRendering ShapeRendering() const {
- return (EShapeRendering)svg_inherited_flags.shape_rendering;
- }
- ETextAnchor TextAnchor() const {
- return (ETextAnchor)svg_inherited_flags.text_anchor;
- }
- float FillOpacity() const { return fill->opacity; }
- const SVGPaint& FillPaint() const { return fill->paint; }
- float StrokeOpacity() const { return stroke->opacity; }
- const SVGPaint& StrokePaint() const { return stroke->paint; }
- SVGDashArray* StrokeDashArray() const { return stroke->dash_array.get(); }
- float StrokeMiterLimit() const { return stroke->miter_limit; }
- const UnzoomedLength& StrokeWidth() const { return stroke->width; }
- const Length& StrokeDashOffset() const { return stroke->dash_offset; }
- float StopOpacity() const { return stops->opacity; }
- const StyleColor& StopColor() const { return stops->color; }
- float FloodOpacity() const { return misc->flood_opacity; }
- const StyleColor& FloodColor() const { return misc->flood_color; }
- const StyleColor& LightingColor() const { return misc->lighting_color; }
- const Length& BaselineShiftValue() const {
- return misc->baseline_shift_value;
- }
- StylePath* D() const { return geometry->d.get(); }
- const Length& Cx() const { return geometry->cx; }
- const Length& Cy() const { return geometry->cy; }
- const Length& X() const { return geometry->x; }
- const Length& Y() const { return geometry->y; }
- const Length& R() const { return geometry->r; }
- const Length& Rx() const { return geometry->rx; }
- const Length& Ry() const { return geometry->ry; }
- StyleSVGResource* MaskerResource() const { return resources->masker.get(); }
- StyleSVGResource* MarkerStartResource() const {
- return inherited_resources->marker_start.get();
- }
- StyleSVGResource* MarkerMidResource() const {
- return inherited_resources->marker_mid.get();
- }
- StyleSVGResource* MarkerEndResource() const {
- return inherited_resources->marker_end.get();
- }
- EMaskType MaskType() const {
- return (EMaskType)svg_noninherited_flags.f.mask_type;
- }
- EPaintOrder PaintOrder() const {
- return (EPaintOrder)svg_inherited_flags.paint_order;
- }
- EPaintOrderType PaintOrderType(unsigned index) const;
-
- const SVGPaint& InternalVisitedFillPaint() const {
- return fill->visited_link_paint;
- }
- const SVGPaint& InternalVisitedStrokePaint() const {
- return stroke->visited_link_paint;
- }
-
- bool IsFillColorCurrentColor() const {
- return FillPaint().HasCurrentColor() ||
- InternalVisitedFillPaint().HasCurrentColor();
- }
-
- bool IsStrokeColorCurrentColor() const {
- return StrokePaint().HasCurrentColor() ||
- InternalVisitedStrokePaint().HasCurrentColor();
- }
-
- // convenience
- bool HasMasker() const { return MaskerResource(); }
- bool HasMarkers() const {
- return MarkerStartResource() || MarkerMidResource() || MarkerEndResource();
- }
- bool HasStroke() const { return !StrokePaint().IsNone(); }
- bool HasVisibleStroke() const {
- return HasStroke() && !StrokeWidth().IsZero();
- }
- bool HasFill() const { return !FillPaint().IsNone(); }
-
- protected:
- // inherit
- struct InheritedFlags {
- bool operator==(const InheritedFlags& other) const {
- return (color_rendering == other.color_rendering) &&
- (shape_rendering == other.shape_rendering) &&
- (clip_rule == other.clip_rule) && (fill_rule == other.fill_rule) &&
- (cap_style == other.cap_style) &&
- (join_style == other.join_style) &&
- (text_anchor == other.text_anchor) &&
- (color_interpolation == other.color_interpolation) &&
- (color_interpolation_filters ==
- other.color_interpolation_filters) &&
- (paint_order == other.paint_order) &&
- (dominant_baseline == other.dominant_baseline);
- }
-
- bool operator!=(const InheritedFlags& other) const {
- return !(*this == other);
- }
-
- unsigned color_rendering : 2; // EColorRendering
- unsigned shape_rendering : 2; // EShapeRendering
- unsigned clip_rule : 1; // WindRule
- unsigned fill_rule : 1; // WindRule
- unsigned cap_style : 2; // LineCap
- unsigned join_style : 2; // LineJoin
- unsigned text_anchor : 2; // ETextAnchor
- unsigned color_interpolation : 2; // EColorInterpolation
- unsigned color_interpolation_filters : 2; // EColorInterpolation_
- unsigned paint_order : 3; // EPaintOrder
- unsigned dominant_baseline : 4; // EDominantBaseline
- } svg_inherited_flags;
-
- // don't inherit
- struct NonInheritedFlags {
- // 32 bit non-inherited, don't add to the struct, or the operator will
- // break.
- bool operator==(const NonInheritedFlags& other) const {
- return niflags == other.niflags;
- }
- bool operator!=(const NonInheritedFlags& other) const {
- return niflags != other.niflags;
- }
-
- union {
- struct {
- unsigned alignment_baseline : 4; // EAlignmentBaseline
- unsigned baseline_shift : 2; // EBaselineShift
- unsigned vector_effect : 1; // EVectorEffect
- unsigned buffered_rendering : 2; // EBufferedRendering
- unsigned mask_type : 1; // EMaskType
- // 18 bits unused
- } f;
- uint32_t niflags;
- };
- } svg_noninherited_flags;
-
- // inherited attributes
- DataRef<StyleFillData> fill;
- DataRef<StyleStrokeData> stroke;
- DataRef<StyleInheritedResourceData> inherited_resources;
-
- // non-inherited attributes
- DataRef<StyleStopData> stops;
- DataRef<StyleMiscData> misc;
- DataRef<StyleGeometryData> geometry;
- DataRef<StyleResourceData> resources;
-
- private:
- enum CreateInitialType { kCreateInitial };
-
- CORE_EXPORT SVGComputedStyle();
- SVGComputedStyle(const SVGComputedStyle&);
- SVGComputedStyle(
- CreateInitialType); // Used to create the initial style singleton.
-
- bool DiffNeedsLayoutAndPaintInvalidation(const SVGComputedStyle& other) const;
- bool DiffNeedsPaintInvalidation(const SVGComputedStyle& other) const;
-
- void SetBitDefaults() {
- svg_inherited_flags.clip_rule = InitialClipRule();
- svg_inherited_flags.color_rendering = InitialColorRendering();
- svg_inherited_flags.fill_rule = InitialFillRule();
- svg_inherited_flags.shape_rendering = InitialShapeRendering();
- svg_inherited_flags.text_anchor = InitialTextAnchor();
- svg_inherited_flags.cap_style = InitialCapStyle();
- svg_inherited_flags.join_style = InitialJoinStyle();
- svg_inherited_flags.color_interpolation = InitialColorInterpolation();
- svg_inherited_flags.color_interpolation_filters =
- InitialColorInterpolationFilters();
- svg_inherited_flags.paint_order = InitialPaintOrder();
- svg_inherited_flags.dominant_baseline = InitialDominantBaseline();
-
- svg_noninherited_flags.niflags = 0;
- svg_noninherited_flags.f.alignment_baseline = InitialAlignmentBaseline();
- svg_noninherited_flags.f.baseline_shift = InitialBaselineShift();
- svg_noninherited_flags.f.vector_effect = InitialVectorEffect();
- svg_noninherited_flags.f.buffered_rendering = InitialBufferedRendering();
- svg_noninherited_flags.f.mask_type = InitialMaskType();
- }
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_H_
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
deleted file mode 100644
index 9b1daa507b5..00000000000
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005, 2007 Rob Buis <buis@kde.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- Based on khtml code by:
- Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
- Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
- Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
- Copyright (C) 2002 Apple Computer, Inc.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
-
-#include "third_party/blink/renderer/core/style/data_equivalency.h"
-#include "third_party/blink/renderer/core/style/style_svg_resource.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
-
-namespace blink {
-
-SVGPaint::SVGPaint() = default;
-SVGPaint::SVGPaint(Color color) : color(color), type(SVG_PAINTTYPE_COLOR) {}
-SVGPaint::SVGPaint(const SVGPaint& paint) = default;
-
-SVGPaint::~SVGPaint() = default;
-
-SVGPaint& SVGPaint::operator=(const SVGPaint& paint) = default;
-
-bool SVGPaint::operator==(const SVGPaint& other) const {
- return type == other.type && color == other.color &&
- DataEquivalent(resource, other.resource);
-}
-
-const AtomicString& SVGPaint::GetUrl() const {
- return Resource()->Url();
-}
-
-StyleFillData::StyleFillData()
- : opacity(SVGComputedStyle::InitialFillOpacity()),
- paint(SVGComputedStyle::InitialFillPaint()),
- visited_link_paint(SVGComputedStyle::InitialFillPaint()) {}
-
-StyleFillData::StyleFillData(const StyleFillData& other)
- : RefCounted<StyleFillData>(),
- opacity(other.opacity),
- paint(other.paint),
- visited_link_paint(other.visited_link_paint) {}
-
-bool StyleFillData::operator==(const StyleFillData& other) const {
- return opacity == other.opacity && paint == other.paint &&
- visited_link_paint == other.visited_link_paint;
-}
-
-StyleStrokeData::StyleStrokeData()
- : opacity(SVGComputedStyle::InitialStrokeOpacity()),
- miter_limit(SVGComputedStyle::InitialStrokeMiterLimit()),
- width(SVGComputedStyle::InitialStrokeWidth()),
- dash_offset(SVGComputedStyle::InitialStrokeDashOffset()),
- dash_array(SVGComputedStyle::InitialStrokeDashArray()),
- paint(SVGComputedStyle::InitialStrokePaint()),
- visited_link_paint(SVGComputedStyle::InitialStrokePaint()) {}
-
-StyleStrokeData::StyleStrokeData(const StyleStrokeData& other)
- : RefCounted<StyleStrokeData>(),
- opacity(other.opacity),
- miter_limit(other.miter_limit),
- width(other.width),
- dash_offset(other.dash_offset),
- dash_array(other.dash_array),
- paint(other.paint),
- visited_link_paint(other.visited_link_paint) {}
-
-bool StyleStrokeData::operator==(const StyleStrokeData& other) const {
- return width == other.width && opacity == other.opacity &&
- miter_limit == other.miter_limit && dash_offset == other.dash_offset &&
- dash_array->data == other.dash_array->data && paint == other.paint &&
- visited_link_paint == other.visited_link_paint;
-}
-
-StyleStopData::StyleStopData()
- : color(SVGComputedStyle::InitialStopColor()),
- opacity(SVGComputedStyle::InitialStopOpacity()) {}
-
-StyleStopData::StyleStopData(const StyleStopData& other)
- : RefCounted<StyleStopData>(), color(other.color), opacity(other.opacity) {}
-
-bool StyleStopData::operator==(const StyleStopData& other) const {
- return color == other.color && opacity == other.opacity;
-}
-
-StyleMiscData::StyleMiscData()
- : baseline_shift_value(SVGComputedStyle::InitialBaselineShiftValue()),
- flood_color(SVGComputedStyle::InitialFloodColor()),
- lighting_color(SVGComputedStyle::InitialLightingColor()),
- flood_opacity(SVGComputedStyle::InitialFloodOpacity()) {}
-
-StyleMiscData::StyleMiscData(const StyleMiscData& other)
- : RefCounted<StyleMiscData>(),
- baseline_shift_value(other.baseline_shift_value),
- flood_color(other.flood_color),
- lighting_color(other.lighting_color),
- flood_opacity(other.flood_opacity) {}
-
-bool StyleMiscData::operator==(const StyleMiscData& other) const {
- return flood_color == other.flood_color &&
- lighting_color == other.lighting_color &&
- baseline_shift_value == other.baseline_shift_value &&
- flood_opacity == other.flood_opacity;
-}
-
-StyleResourceData::StyleResourceData()
- : masker(SVGComputedStyle::InitialMaskerResource()) {}
-
-StyleResourceData::StyleResourceData(const StyleResourceData& other)
- : RefCounted<StyleResourceData>(), masker(other.masker) {}
-
-StyleResourceData::~StyleResourceData() = default;
-
-bool StyleResourceData::operator==(const StyleResourceData& other) const {
- return DataEquivalent(masker, other.masker);
-}
-
-StyleInheritedResourceData::StyleInheritedResourceData()
- : marker_start(SVGComputedStyle::InitialMarkerStartResource()),
- marker_mid(SVGComputedStyle::InitialMarkerMidResource()),
- marker_end(SVGComputedStyle::InitialMarkerEndResource()) {}
-
-StyleInheritedResourceData::StyleInheritedResourceData(
- const StyleInheritedResourceData& other)
- : RefCounted<StyleInheritedResourceData>(),
- marker_start(other.marker_start),
- marker_mid(other.marker_mid),
- marker_end(other.marker_end) {}
-
-StyleInheritedResourceData::~StyleInheritedResourceData() = default;
-
-bool StyleInheritedResourceData::operator==(
- const StyleInheritedResourceData& other) const {
- return DataEquivalent(marker_start, other.marker_start) &&
- DataEquivalent(marker_mid, other.marker_mid) &&
- DataEquivalent(marker_end, other.marker_end);
-}
-
-StyleGeometryData::StyleGeometryData()
- : d(SVGComputedStyle::InitialD()),
- cx(SVGComputedStyle::InitialCx()),
- cy(SVGComputedStyle::InitialCy()),
- x(SVGComputedStyle::InitialX()),
- y(SVGComputedStyle::InitialY()),
- r(SVGComputedStyle::InitialR()),
- rx(SVGComputedStyle::InitialRx()),
- ry(SVGComputedStyle::InitialRy()) {}
-
-inline StyleGeometryData::StyleGeometryData(const StyleGeometryData& other)
- : RefCounted<StyleGeometryData>(),
- d(other.d),
- cx(other.cx),
- cy(other.cy),
- x(other.x),
- y(other.y),
- r(other.r),
- rx(other.rx),
- ry(other.ry) {}
-
-scoped_refptr<StyleGeometryData> StyleGeometryData::Copy() const {
- return base::AdoptRef(new StyleGeometryData(*this));
-}
-
-bool StyleGeometryData::operator==(const StyleGeometryData& other) const {
- return x == other.x && y == other.y && r == other.r && rx == other.rx &&
- ry == other.ry && cx == other.cx && cy == other.cy &&
- DataEquivalent(d, other.d);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h b/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h
deleted file mode 100644
index 40e11080c26..00000000000
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style_defs.h
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005 Rob Buis <buis@kde.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- Based on khtml code by:
- Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
- (C) 2000 Antti Koivisto (koivisto@kde.org)
- (C) 2000-2003 Dirk Mueller (mueller@kde.org)
- (C) 2002-2003 Apple Computer, Inc.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_DEFS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_DEFS_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/style_color.h"
-#include "third_party/blink/renderer/core/style/style_path.h"
-#include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class StyleSVGResource;
-
-typedef base::RefCountedData<WTF::Vector<Length>> SVGDashArray;
-
-enum SVGPaintType {
- SVG_PAINTTYPE_COLOR,
- SVG_PAINTTYPE_NONE,
- SVG_PAINTTYPE_URI_NONE,
- SVG_PAINTTYPE_URI_COLOR,
- SVG_PAINTTYPE_URI
-};
-
-enum EBaselineShift { BS_LENGTH, BS_SUB, BS_SUPER };
-
-enum ETextAnchor { TA_START, TA_MIDDLE, TA_END };
-
-enum EColorInterpolation { CI_AUTO, CI_SRGB, CI_LINEARRGB };
-
-enum EColorRendering { CR_AUTO, CR_OPTIMIZESPEED, CR_OPTIMIZEQUALITY };
-enum EShapeRendering {
- SR_AUTO,
- SR_OPTIMIZESPEED,
- SR_CRISPEDGES,
- SR_GEOMETRICPRECISION
-};
-
-enum EAlignmentBaseline {
- AB_AUTO,
- AB_BASELINE,
- AB_BEFORE_EDGE,
- AB_TEXT_BEFORE_EDGE,
- AB_MIDDLE,
- AB_CENTRAL,
- AB_AFTER_EDGE,
- AB_TEXT_AFTER_EDGE,
- AB_IDEOGRAPHIC,
- AB_ALPHABETIC,
- AB_HANGING,
- AB_MATHEMATICAL
-};
-
-enum EDominantBaseline {
- DB_AUTO,
- DB_USE_SCRIPT,
- DB_NO_CHANGE,
- DB_RESET_SIZE,
- DB_IDEOGRAPHIC,
- DB_ALPHABETIC,
- DB_HANGING,
- DB_MATHEMATICAL,
- DB_CENTRAL,
- DB_MIDDLE,
- DB_TEXT_AFTER_EDGE,
- DB_TEXT_BEFORE_EDGE
-};
-
-enum EVectorEffect { VE_NONE, VE_NON_SCALING_STROKE };
-
-enum EBufferedRendering { BR_AUTO, BR_DYNAMIC, BR_STATIC };
-
-enum EMaskType { MT_LUMINANCE, MT_ALPHA };
-
-enum EPaintOrderType {
- PT_NONE = 0,
- PT_FILL = 1,
- PT_STROKE = 2,
- PT_MARKERS = 3
-};
-
-enum EPaintOrder {
- kPaintOrderNormal = 0,
- kPaintOrderFillStrokeMarkers = 1,
- kPaintOrderFillMarkersStroke = 2,
- kPaintOrderStrokeFillMarkers = 3,
- kPaintOrderStrokeMarkersFill = 4,
- kPaintOrderMarkersFillStroke = 5,
- kPaintOrderMarkersStrokeFill = 6
-};
-
-struct SVGPaint {
- CORE_EXPORT SVGPaint();
- SVGPaint(Color color);
- SVGPaint(const SVGPaint& paint);
- CORE_EXPORT ~SVGPaint();
- CORE_EXPORT SVGPaint& operator=(const SVGPaint& paint);
-
- CORE_EXPORT bool operator==(const SVGPaint&) const;
- bool operator!=(const SVGPaint& other) const { return !(*this == other); }
-
- bool IsNone() const { return type == SVG_PAINTTYPE_NONE; }
- bool IsColor() const { return type == SVG_PAINTTYPE_COLOR; }
- // Used by CSSPropertyEquality::PropertiesEqual.
- bool EqualTypeOrColor(const SVGPaint& other) const {
- return type == other.type &&
- (type != SVG_PAINTTYPE_COLOR || color == other.color);
- }
- bool HasColor() const { return IsColor() || type == SVG_PAINTTYPE_URI_COLOR; }
- bool HasUrl() const { return type >= SVG_PAINTTYPE_URI_NONE; }
- bool HasCurrentColor() const { return HasColor() && color.IsCurrentColor(); }
- StyleSVGResource* Resource() const { return resource.get(); }
-
- const StyleColor& GetColor() const { return color; }
- const AtomicString& GetUrl() const;
-
- scoped_refptr<StyleSVGResource> resource;
- StyleColor color;
- SVGPaintType type{SVG_PAINTTYPE_NONE};
-};
-
-// Inherited/Non-Inherited Style Datastructures
-class StyleFillData : public RefCounted<StyleFillData> {
- USING_FAST_MALLOC(StyleFillData);
-
- public:
- static scoped_refptr<StyleFillData> Create() {
- return base::AdoptRef(new StyleFillData);
- }
- scoped_refptr<StyleFillData> Copy() const {
- return base::AdoptRef(new StyleFillData(*this));
- }
-
- bool operator==(const StyleFillData&) const;
- bool operator!=(const StyleFillData& other) const {
- return !(*this == other);
- }
-
- float opacity;
- SVGPaint paint;
- SVGPaint visited_link_paint;
-
- private:
- StyleFillData();
- StyleFillData(const StyleFillData&);
-};
-
-class UnzoomedLength {
- DISALLOW_NEW();
-
- public:
- explicit UnzoomedLength(const Length& length) : length_(length) {}
-
- bool IsZero() const { return length_.IsZero(); }
-
- bool operator==(const UnzoomedLength& other) const {
- return length_ == other.length_;
- }
- bool operator!=(const UnzoomedLength& other) const {
- return !operator==(other);
- }
-
- const Length& length() const { return length_; }
-
- private:
- Length length_;
-};
-
-class CORE_EXPORT StyleStrokeData : public RefCounted<StyleStrokeData> {
- USING_FAST_MALLOC(StyleStrokeData);
-
- public:
- static scoped_refptr<StyleStrokeData> Create() {
- return base::AdoptRef(new StyleStrokeData);
- }
-
- scoped_refptr<StyleStrokeData> Copy() const {
- return base::AdoptRef(new StyleStrokeData(*this));
- }
-
- bool operator==(const StyleStrokeData&) const;
- bool operator!=(const StyleStrokeData& other) const {
- return !(*this == other);
- }
-
- float opacity;
- float miter_limit;
-
- UnzoomedLength width;
- Length dash_offset;
- scoped_refptr<SVGDashArray> dash_array;
-
- SVGPaint paint;
- SVGPaint visited_link_paint;
-
- private:
- StyleStrokeData();
- StyleStrokeData(const StyleStrokeData&);
-};
-
-class StyleStopData : public RefCounted<StyleStopData> {
- USING_FAST_MALLOC(StyleStopData);
-
- public:
- static scoped_refptr<StyleStopData> Create() {
- return base::AdoptRef(new StyleStopData);
- }
- scoped_refptr<StyleStopData> Copy() const {
- return base::AdoptRef(new StyleStopData(*this));
- }
-
- bool operator==(const StyleStopData&) const;
- bool operator!=(const StyleStopData& other) const {
- return !(*this == other);
- }
-
- StyleColor color;
- float opacity;
-
- private:
- StyleStopData();
- StyleStopData(const StyleStopData&);
-};
-
-// Note: the rule for this class is, *no inheritance* of these props
-class CORE_EXPORT StyleMiscData : public RefCounted<StyleMiscData> {
- USING_FAST_MALLOC(StyleMiscData);
-
- public:
- static scoped_refptr<StyleMiscData> Create() {
- return base::AdoptRef(new StyleMiscData);
- }
- scoped_refptr<StyleMiscData> Copy() const {
- return base::AdoptRef(new StyleMiscData(*this));
- }
-
- bool operator==(const StyleMiscData&) const;
- bool operator!=(const StyleMiscData& other) const {
- return !(*this == other);
- }
-
- Length baseline_shift_value;
-
- StyleColor flood_color;
- StyleColor lighting_color;
-
- float flood_opacity;
-
- private:
- StyleMiscData();
- StyleMiscData(const StyleMiscData&);
-};
-
-// Non-inherited resources
-class StyleResourceData : public RefCounted<StyleResourceData> {
- USING_FAST_MALLOC(StyleResourceData);
-
- public:
- static scoped_refptr<StyleResourceData> Create() {
- return base::AdoptRef(new StyleResourceData);
- }
- ~StyleResourceData();
- scoped_refptr<StyleResourceData> Copy() const {
- return base::AdoptRef(new StyleResourceData(*this));
- }
-
- bool operator==(const StyleResourceData&) const;
- bool operator!=(const StyleResourceData& other) const {
- return !(*this == other);
- }
-
- scoped_refptr<StyleSVGResource> masker;
-
- private:
- StyleResourceData();
- StyleResourceData(const StyleResourceData&);
-};
-
-// Inherited resources
-class StyleInheritedResourceData
- : public RefCounted<StyleInheritedResourceData> {
- USING_FAST_MALLOC(StyleInheritedResourceData);
-
- public:
- static scoped_refptr<StyleInheritedResourceData> Create() {
- return base::AdoptRef(new StyleInheritedResourceData);
- }
- ~StyleInheritedResourceData();
- scoped_refptr<StyleInheritedResourceData> Copy() const {
- return base::AdoptRef(new StyleInheritedResourceData(*this));
- }
-
- bool operator==(const StyleInheritedResourceData&) const;
- bool operator!=(const StyleInheritedResourceData& other) const {
- return !(*this == other);
- }
-
- scoped_refptr<StyleSVGResource> marker_start;
- scoped_refptr<StyleSVGResource> marker_mid;
- scoped_refptr<StyleSVGResource> marker_end;
-
- private:
- StyleInheritedResourceData();
- StyleInheritedResourceData(const StyleInheritedResourceData&);
-};
-
-// Geometry properties
-class StyleGeometryData : public RefCounted<StyleGeometryData> {
- USING_FAST_MALLOC(StyleGeometryData);
-
- public:
- static scoped_refptr<StyleGeometryData> Create() {
- return base::AdoptRef(new StyleGeometryData);
- }
- scoped_refptr<StyleGeometryData> Copy() const;
- bool operator==(const StyleGeometryData&) const;
- bool operator!=(const StyleGeometryData& other) const {
- return !(*this == other);
- }
- scoped_refptr<StylePath> d;
- Length cx;
- Length cy;
- Length x;
- Length y;
- Length r;
- Length rx;
- Length ry;
-
- private:
- StyleGeometryData();
- StyleGeometryData(const StyleGeometryData&);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_COMPUTED_STYLE_DEFS_H_
diff --git a/chromium/third_party/blink/renderer/core/style/svg_computed_style_test.cc b/chromium/third_party/blink/renderer/core/style/svg_computed_style_test.cc
deleted file mode 100644
index 2559a45b921..00000000000
--- a/chromium/third_party/blink/renderer/core/style/svg_computed_style_test.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
-
-#include "third_party/blink/renderer/core/style/style_difference.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace blink {
-
-// Ensures RefPtr values are compared by their values, not by pointers.
-#define TEST_STYLE_REFCOUNTED_VALUE_NO_DIFF(type, fieldName) \
- { \
- scoped_refptr<SVGComputedStyle> svg1 = SVGComputedStyle::Create(); \
- scoped_refptr<SVGComputedStyle> svg2 = SVGComputedStyle::Create(); \
- scoped_refptr<type> value1 = base::MakeRefCounted<type>(); \
- scoped_refptr<type> value2 = base::MakeRefCounted<type>(value1->data); \
- svg1->Set##fieldName(value1); \
- svg2->Set##fieldName(value2); \
- EXPECT_FALSE(svg1->Diff(*svg2).HasDifference()); \
- }
-
-// This is not very useful for fields directly stored by values, because they
-// can only be compared by values. This macro mainly ensures that we update the
-// comparisons and tests when we change some field to RefPtr in the future.
-#define TEST_STYLE_VALUE_NO_DIFF(type, fieldName) \
- { \
- scoped_refptr<SVGComputedStyle> svg1 = SVGComputedStyle::Create(); \
- scoped_refptr<SVGComputedStyle> svg2 = SVGComputedStyle::Create(); \
- svg1->Set##fieldName(SVGComputedStyle::Initial##fieldName()); \
- svg2->Set##fieldName(SVGComputedStyle::Initial##fieldName()); \
- EXPECT_FALSE(svg1->Diff(*svg2).HasDifference()); \
- }
-
-TEST(SVGComputedStyleTest, StrokeStyleShouldCompareValue) {
- TEST_STYLE_VALUE_NO_DIFF(float, StrokeOpacity);
- TEST_STYLE_VALUE_NO_DIFF(float, StrokeMiterLimit);
- TEST_STYLE_VALUE_NO_DIFF(UnzoomedLength, StrokeWidth);
- TEST_STYLE_VALUE_NO_DIFF(Length, StrokeDashOffset);
- TEST_STYLE_REFCOUNTED_VALUE_NO_DIFF(SVGDashArray, StrokeDashArray);
-
- TEST_STYLE_VALUE_NO_DIFF(SVGPaint, StrokePaint);
- {
- scoped_refptr<SVGComputedStyle> svg1 = SVGComputedStyle::Create();
- scoped_refptr<SVGComputedStyle> svg2 = SVGComputedStyle::Create();
- svg1->SetInternalVisitedStrokePaint(SVGComputedStyle::InitialStrokePaint());
- svg2->SetInternalVisitedStrokePaint(SVGComputedStyle::InitialStrokePaint());
- EXPECT_FALSE(svg1->Diff(*svg2).HasDifference());
- }
-}
-
-TEST(SVGComputedStyleTest, MiscStyleShouldCompareValue) {
- TEST_STYLE_VALUE_NO_DIFF(Color, FloodColor);
- TEST_STYLE_VALUE_NO_DIFF(float, FloodOpacity);
- TEST_STYLE_VALUE_NO_DIFF(Color, LightingColor);
- TEST_STYLE_VALUE_NO_DIFF(Length, BaselineShiftValue);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/svg_dash_array.cc b/chromium/third_party/blink/renderer/core/style/svg_dash_array.cc
new file mode 100644
index 00000000000..c4ea85810a8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/svg_dash_array.cc
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2010 Rob Buis <buis@kde.org>
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ Based on khtml code by:
+ Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "third_party/blink/renderer/core/style/svg_dash_array.h"
+
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+SVGDashArray* EmptyDashArray() {
+ DEFINE_STATIC_REF(SVGDashArray, empty_dash_array,
+ base::MakeRefCounted<SVGDashArray>());
+ return empty_dash_array;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/svg_dash_array.h b/chromium/third_party/blink/renderer/core/style/svg_dash_array.h
new file mode 100644
index 00000000000..a8f646de23b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/svg_dash_array.h
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ Based on khtml code by:
+ Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
+ (C) 2000 Antti Koivisto (koivisto@kde.org)
+ (C) 2000-2003 Dirk Mueller (mueller@kde.org)
+ (C) 2002-2003 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_DASH_ARRAY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_DASH_ARRAY_H_
+
+#include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+using SVGDashArray = base::RefCountedData<WTF::Vector<Length>>;
+
+// TODO(fs): Should return const.
+SVGDashArray* EmptyDashArray();
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_DASH_ARRAY_H_
diff --git a/chromium/third_party/blink/renderer/core/style/svg_paint.cc b/chromium/third_party/blink/renderer/core/style/svg_paint.cc
new file mode 100644
index 00000000000..7735fea516e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/svg_paint.cc
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ Based on khtml code by:
+ Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "third_party/blink/renderer/core/style/svg_paint.h"
+
+#include "third_party/blink/renderer/core/style/data_equivalency.h"
+#include "third_party/blink/renderer/core/style/style_svg_resource.h"
+
+namespace blink {
+
+SVGPaint::SVGPaint() = default;
+SVGPaint::SVGPaint(Color color) : color(color), type(SVG_PAINTTYPE_COLOR) {}
+SVGPaint::SVGPaint(const SVGPaint& paint) = default;
+
+SVGPaint::~SVGPaint() = default;
+
+SVGPaint& SVGPaint::operator=(const SVGPaint& paint) = default;
+
+bool SVGPaint::operator==(const SVGPaint& other) const {
+ return type == other.type && color == other.color &&
+ DataEquivalent(resource, other.resource);
+}
+
+const AtomicString& SVGPaint::GetUrl() const {
+ return Resource()->Url();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/style/svg_paint.h b/chromium/third_party/blink/renderer/core/style/svg_paint.h
new file mode 100644
index 00000000000..10b83c9ca0e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/svg_paint.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ Based on khtml code by:
+ Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
+ (C) 2000 Antti Koivisto (koivisto@kde.org)
+ (C) 2000-2003 Dirk Mueller (mueller@kde.org)
+ (C) 2002-2003 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_PAINT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_PAINT_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/style_color.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class StyleSVGResource;
+
+enum SVGPaintType {
+ SVG_PAINTTYPE_COLOR,
+ SVG_PAINTTYPE_NONE,
+ SVG_PAINTTYPE_URI_NONE,
+ SVG_PAINTTYPE_URI_COLOR,
+ SVG_PAINTTYPE_URI
+};
+
+struct SVGPaint {
+ CORE_EXPORT SVGPaint();
+ explicit SVGPaint(Color color);
+ SVGPaint(const SVGPaint& paint);
+ CORE_EXPORT ~SVGPaint();
+ CORE_EXPORT SVGPaint& operator=(const SVGPaint& paint);
+
+ CORE_EXPORT bool operator==(const SVGPaint&) const;
+ bool operator!=(const SVGPaint& other) const { return !(*this == other); }
+
+ bool IsNone() const { return type == SVG_PAINTTYPE_NONE; }
+ bool IsColor() const { return type == SVG_PAINTTYPE_COLOR; }
+ // Used by CSSPropertyEquality::PropertiesEqual.
+ bool EqualTypeOrColor(const SVGPaint& other) const {
+ return type == other.type &&
+ (type != SVG_PAINTTYPE_COLOR || color == other.color);
+ }
+ bool HasColor() const { return IsColor() || type == SVG_PAINTTYPE_URI_COLOR; }
+ bool HasUrl() const { return type >= SVG_PAINTTYPE_URI_NONE; }
+ bool HasCurrentColor() const { return HasColor() && color.IsCurrentColor(); }
+ StyleSVGResource* Resource() const { return resource.get(); }
+
+ const StyleColor& GetColor() const { return color; }
+ const AtomicString& GetUrl() const;
+
+ scoped_refptr<StyleSVGResource> resource;
+ StyleColor color;
+ SVGPaintType type{SVG_PAINTTYPE_NONE};
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_SVG_PAINT_H_
diff --git a/chromium/third_party/blink/renderer/core/style/unzoomed_length.h b/chromium/third_party/blink/renderer/core/style/unzoomed_length.h
new file mode 100644
index 00000000000..ebecbe88250
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/style/unzoomed_length.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ Based on khtml code by:
+ Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
+ (C) 2000 Antti Koivisto (koivisto@kde.org)
+ (C) 2000-2003 Dirk Mueller (mueller@kde.org)
+ (C) 2002-2003 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_UNZOOMED_LENGTH_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_UNZOOMED_LENGTH_H_
+
+#include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+// A wrapper around a Length that has not been subjected to zoom adjustment when
+// computed. Used for stroke-width.
+class UnzoomedLength {
+ DISALLOW_NEW();
+
+ public:
+ explicit UnzoomedLength(const Length& length) : length_(length) {}
+
+ bool IsZero() const { return length_.IsZero(); }
+
+ bool operator==(const UnzoomedLength& other) const {
+ return length_ == other.length_;
+ }
+ bool operator!=(const UnzoomedLength& other) const {
+ return !operator==(other);
+ }
+
+ const Length& length() const { return length_; }
+
+ private:
+ Length length_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_UNZOOMED_LENGTH_H_
diff --git a/chromium/third_party/blink/renderer/core/svg/DIR_METADATA b/chromium/third_party/blink/renderer/core/svg/DIR_METADATA
new file mode 100644
index 00000000000..20ba44d55bc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/svg/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>SVG"
+}
+
+team_email: "paint-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/svg/OWNERS b/chromium/third_party/blink/renderer/core/svg/OWNERS
index 8db19674eda..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/core/svg/OWNERS
+++ b/chromium/third_party/blink/renderer/core/svg/OWNERS
@@ -1,2 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>SVG \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.cc b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
index 369c64eacc8..c01165073a2 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
+++ b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
@@ -608,6 +608,7 @@ void SMILTimeContainer::AdvanceFrameForTesting() {
}
void SMILTimeContainer::Trace(Visitor* visitor) const {
+ visitor->Trace(wakeup_timer_);
visitor->Trace(animated_targets_);
visitor->Trace(priority_queue_);
visitor->Trace(owner_svg_element_);
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.h b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.h
index c69148a5249..0ef1c3bc035 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.h
+++ b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container.h
@@ -135,7 +135,7 @@ class CORE_EXPORT SMILTimeContainer final
bool document_order_indexes_dirty_ : 1;
bool is_updating_intervals_;
- TaskRunnerTimer<SMILTimeContainer> wakeup_timer_;
+ HeapTaskRunnerTimer<SMILTimeContainer> wakeup_timer_;
using AnimatedTargets = HeapHashCountedSet<WeakMember<SVGElement>>;
AnimatedTargets animated_targets_;
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container_test.cc b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container_test.cc
index 80e49676521..5d3ec152d78 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container_test.cc
+++ b/chromium/third_party/blink/renderer/core/svg/animation/smil_time_container_test.cc
@@ -33,7 +33,7 @@ class SMILTimeContainerTest : public PageTestBase {
}
void Load(base::span<const char> data) {
- auto params = WebNavigationParams::CreateWithHTMLString(
+ auto params = WebNavigationParams::CreateWithHTMLStringForTesting(
data, KURL("http://example.com"));
GetFrame().Loader().CommitNavigation(std::move(params),
nullptr /* extra_data */);
@@ -113,7 +113,7 @@ class SMILTimeContainerAnimationPolicyOnceTest : public PageTestBase {
}
void Load(base::span<const char> data) {
- auto params = WebNavigationParams::CreateWithHTMLString(
+ auto params = WebNavigationParams::CreateWithHTMLStringForTesting(
data, KURL("http://example.com"));
GetFrame().Loader().CommitNavigation(std::move(params),
nullptr /* extra_data */);
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 467b9c4d59c..8a6f6139e34 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -561,15 +561,16 @@ void SVGSMILElement::ParseAttribute(const AttributeModificationParams& params) {
}
}
-void SVGSMILElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (SVGURIReference::IsKnownAttribute(attr_name)) {
+void SVGSMILElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (SVGURIReference::IsKnownAttribute(params.name)) {
// TODO(fs): Could be smarter here when 'href' is specified and 'xlink:href'
// is changed.
SVGElement::InvalidationGuard invalidation_guard(this);
BuildPendingResource();
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
bool SVGSMILElement::IsPresentationAttribute(
@@ -667,7 +668,7 @@ static SMILRepeatCount ParseRepeatCount(const AtomicString& value) {
return SMILRepeatCount::Indefinite();
bool ok;
double result = value.ToDouble(&ok);
- if (ok && result > 0)
+ if (ok && result > 0 && std::isfinite(result))
return SMILRepeatCount::Numeric(result);
return SMILRepeatCount::Unspecified();
}
diff --git a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index 9758eb00154..0b47881c86c 100644
--- a/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -82,7 +82,7 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
~SVGSMILElement() override;
void ParseAttribute(const AttributeModificationParams&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/build.gni b/chromium/third_party/blink/renderer/core/svg/build.gni
index 2909fe9781e..76efc7db5b3 100644
--- a/chromium/third_party/blink/renderer/core/svg/build.gni
+++ b/chromium/third_party/blink/renderer/core/svg/build.gni
@@ -113,8 +113,6 @@ blink_core_sources_svg = [
"svg_enumeration.h",
"svg_enumeration_map.cc",
"svg_enumeration_map.h",
- "svg_external_document_cache.cc",
- "svg_external_document_cache.h",
"svg_fe_blend_element.cc",
"svg_fe_blend_element.h",
"svg_fe_color_matrix_element.cc",
@@ -282,6 +280,8 @@ blink_core_sources_svg = [
"svg_resource.cc",
"svg_resource.h",
"svg_resource_client.h",
+ "svg_resource_document_content.cc",
+ "svg_resource_document_content.h",
"svg_script_element.cc",
"svg_script_element.h",
"svg_set_element.cc",
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
index cbf1cff8164..e7c9a74951f 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
@@ -37,6 +37,7 @@ class FEImage final : public FilterEffect {
public:
FEImage(Filter*, scoped_refptr<Image>, const SVGPreserveAspectRatio*);
FEImage(Filter*, const SVGElement*, const SVGPreserveAspectRatio*);
+ ~FEImage() override = default;
// feImage does not perform color interpolation of any kind, so doesn't
// depend on the value of color-interpolation-filters.
@@ -48,7 +49,6 @@ class FEImage final : public FilterEffect {
void Trace(Visitor*) const override;
private:
- ~FEImage() override = default;
const LayoutObject* ReferencedLayoutObject() const;
FilterEffectType GetFilterEffectType() const override {
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc
index 3dd66330e96..bea7d731a63 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc
@@ -137,7 +137,7 @@ static EColorInterpolation ColorInterpolationForElement(
SVGElement& element,
EColorInterpolation parent_color_interpolation) {
if (const LayoutObject* layout_object = element.GetLayoutObject())
- return layout_object->StyleRef().SvgStyle().ColorInterpolationFilters();
+ return layout_object->StyleRef().ColorInterpolationFilters();
// No layout has been performed, try to determine the property value
// "manually" (used by external SVG files.)
@@ -156,15 +156,16 @@ static EColorInterpolation ColorInterpolationForElement(
InterpolationSpace SVGFilterBuilder::ResolveInterpolationSpace(
EColorInterpolation color_interpolation) {
- return color_interpolation == CI_LINEARRGB ? kInterpolationSpaceLinear
- : kInterpolationSpaceSRGB;
+ return color_interpolation == EColorInterpolation::kLinearrgb
+ ? kInterpolationSpaceLinear
+ : kInterpolationSpaceSRGB;
}
void SVGFilterBuilder::BuildGraph(Filter* filter,
SVGFilterElement& filter_element,
const FloatRect& reference_box) {
EColorInterpolation filter_color_interpolation =
- ColorInterpolationForElement(filter_element, CI_AUTO);
+ ColorInterpolationForElement(filter_element, EColorInterpolation::kAuto);
SVGUnitTypes::SVGUnitType primitive_units =
filter_element.primitiveUnits()->CurrentEnumValue();
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
index 6153e4f4037..195d87fe48d 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h
@@ -21,7 +21,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_GRAPHICS_FILTERS_SVG_FILTER_BUILDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_GRAPHICS_FILTERS_SVG_FILTER_BUILDER_H_
-#include "third_party/blink/renderer/core/style/svg_computed_style_defs.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/graphics/interpolation_space.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index a054569fdf3..b6213539ed7 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -29,7 +29,9 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
@@ -48,7 +50,6 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -72,6 +73,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
namespace blink {
@@ -136,7 +138,10 @@ class FailingLoaderFactory final : public WebURLLoaderFactory {
std::unique_ptr<WebURLLoader> CreateURLLoader(
const WebURLRequest&,
std::unique_ptr<TaskRunnerHandle> freezable_task_runner_handle,
- std::unique_ptr<TaskRunnerHandle> unfreezable_task_runner_handle)
+ std::unique_ptr<TaskRunnerHandle> unfreezable_task_runner_handle,
+ CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>
+ keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
return std::make_unique<FailingLoader>(
std::move(freezable_task_runner_handle),
@@ -179,6 +184,18 @@ class SVGImage::SVGImageLocalFrameClient : public EmptyLocalFrameClient {
SVGImage::SVGImage(ImageObserver* observer, bool is_multipart)
: Image(observer, is_multipart),
paint_controller_(std::make_unique<PaintController>()),
+ // TODO(chikamune): use an existing AgentGroupScheduler
+ // SVG will be shared via MemoryCache (which is renderer process
+ // global cache) across multiple AgentSchedulingGroups. That's
+ // why we can't use an existing AgentSchedulingGroup for now. If
+ // we incorrectly use the existing ASG/AGS and if we freeze task
+ // queues on a AGS, it will affect SVGs on other AGS. To
+ // mitigate this problem, we need to split the MemoryCache into
+ // smaller granularity. There is an active effort to mitigate
+ // this which is called "Memory Cache Per Context"
+ // (https://crbug.com/1127971).
+ agent_group_scheduler_(
+ Thread::MainThread()->Scheduler()->CreateAgentGroupScheduler()),
has_pending_timeline_rewind_(false) {}
SVGImage::~SVGImage() {
@@ -214,27 +231,38 @@ bool SVGImage::IsInSVGImage(const Node* node) {
return page->GetChromeClient().IsSVGImageChromeClient();
}
-void SVGImage::CheckLoaded() const {
- CHECK(page_);
+LocalFrame* SVGImage::GetFrame() const {
+ DCHECK(page_);
+ return To<LocalFrame>(page_->MainFrame());
+}
+
+SVGSVGElement* SVGImage::RootElement() const {
+ if (!page_)
+ return nullptr;
+ return DynamicTo<SVGSVGElement>(GetFrame()->GetDocument()->documentElement());
+}
- auto* frame = To<LocalFrame>(page_->MainFrame());
+LayoutSVGRoot* SVGImage::LayoutRoot() const {
+ if (SVGSVGElement* root_element = RootElement())
+ return To<LayoutSVGRoot>(root_element->GetLayoutObject());
+ return nullptr;
+}
+void SVGImage::CheckLoaded() const {
+ CHECK(page_);
// Failures of this assertion might result in wrong origin tainting checks,
// because CurrentFrameHasSingleSecurityOrigin() assumes all subresources of
// the SVG are loaded and thus ready for origin checks.
- CHECK(frame->GetDocument()->LoadEventFinished());
+ CHECK(GetFrame()->GetDocument()->LoadEventFinished());
}
bool SVGImage::CurrentFrameHasSingleSecurityOrigin() const {
if (!page_)
return true;
- auto* frame = To<LocalFrame>(page_->MainFrame());
-
CheckLoaded();
- auto* root_element =
- DynamicTo<SVGSVGElement>(frame->GetDocument()->documentElement());
+ SVGSVGElement* root_element = RootElement();
if (!root_element)
return true;
@@ -257,34 +285,6 @@ bool SVGImage::CurrentFrameHasSingleSecurityOrigin() const {
return true;
}
-static SVGSVGElement* SvgRootElement(Page* page) {
- if (!page)
- return nullptr;
- auto* frame = To<LocalFrame>(page->MainFrame());
- return DynamicTo<SVGSVGElement>(frame->GetDocument()->documentElement());
-}
-
-LayoutSize SVGImage::ContainerSize() const {
- SVGSVGElement* root_element = SvgRootElement(page_.Get());
- if (!root_element)
- return LayoutSize();
-
- auto* layout_object = To<LayoutSVGRoot>(root_element->GetLayoutObject());
- if (!layout_object)
- return LayoutSize();
-
- // If a container size is available it has precedence.
- LayoutSize container_size = layout_object->ContainerSize();
- if (!container_size.IsEmpty())
- return container_size;
-
- // Assure that a container size is always given for a non-identity zoom level.
- DCHECK_EQ(layout_object->StyleRef().EffectiveZoom(), 1);
-
- // No set container size; use concrete object size.
- return intrinsic_size_;
-}
-
IntSize SVGImage::Size() const {
return RoundedIntSize(intrinsic_size_);
}
@@ -299,26 +299,16 @@ static float ResolveHeightForRatio(float width,
return width * intrinsic_ratio.Height() / intrinsic_ratio.Width();
}
-bool SVGImage::HasIntrinsicDimensions() const {
- return !ConcreteObjectSize(FloatSize()).IsEmpty();
-}
-
bool SVGImage::HasIntrinsicSizingInfo() const {
- SVGSVGElement* svg = SvgRootElement(page_.Get());
- return svg && svg->GetLayoutObject();
+ return LayoutRoot();
}
bool SVGImage::GetIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
- SVGSVGElement* svg = SvgRootElement(page_.Get());
- if (!svg)
+ const LayoutSVGRoot* layout_root = LayoutRoot();
+ if (!layout_root)
return false;
-
- auto* layout_object = To<LayoutSVGRoot>(svg->GetLayoutObject());
- if (!layout_object)
- return false;
-
- layout_object->UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
+ layout_root->UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
return true;
}
@@ -335,7 +325,7 @@ FloatSize SVGImage::ConcreteObjectSize(
// We're not using an intrinsic aspect ratio to resolve a missing
// intrinsic width or height when preserveAspectRatio is none.
// (Ref: crbug.com/584172)
- SVGSVGElement* svg = SvgRootElement(page_.Get());
+ SVGSVGElement* svg = RootElement();
if (svg->preserveAspectRatio()->CurrentValue()->Align() ==
SVGPreserveAspectRatio::kSvgPreserveaspectratioNone)
return default_object_size;
@@ -378,64 +368,50 @@ FloatSize SVGImage::ConcreteObjectSize(
return default_object_size;
}
-template <typename Func>
-void SVGImage::ForContainer(const FloatSize& container_size, Func&& func) {
- if (!page_)
- return;
-
- // Temporarily disable the image observer to prevent changeInRect() calls due
- // re-laying out the image.
- ImageObserverDisabler image_observer_disabler(this);
-
- LayoutSize rounded_container_size = RoundedLayoutSize(container_size);
+SVGImage::DrawInfo::DrawInfo(const FloatSize& container_size,
+ float zoom,
+ const KURL& url)
+ : container_size_(container_size),
+ rounded_container_size_(RoundedLayoutSize(container_size)),
+ zoom_(zoom),
+ url_(url) {}
- if (SVGSVGElement* root_element = SvgRootElement(page_.Get())) {
- if (auto* layout_object =
- To<LayoutSVGRoot>(root_element->GetLayoutObject()))
- layout_object->SetContainerSize(rounded_container_size);
- }
-
- func(FloatSize(rounded_container_size.Width() / container_size.Width(),
- rounded_container_size.Height() / container_size.Height()));
+FloatSize SVGImage::DrawInfo::CalculateResidualScale() const {
+ return FloatSize(rounded_container_size_.Width() / container_size_.Width(),
+ rounded_container_size_.Height() / container_size_.Height());
}
-void SVGImage::DrawForContainer(cc::PaintCanvas* canvas,
+void SVGImage::DrawForContainer(const DrawInfo& draw_info,
+ cc::PaintCanvas* canvas,
const PaintFlags& flags,
- const FloatSize& container_size,
- float zoom,
const FloatRect& dst_rect,
- const FloatRect& src_rect,
- const KURL& url) {
- ForContainer(container_size, [&](const FloatSize& residual_scale) {
- FloatRect scaled_src = src_rect;
- scaled_src.Scale(1 / zoom);
+ const FloatRect& src_rect) {
+ FloatRect unzoomed_src = src_rect;
+ unzoomed_src.Scale(1 / draw_info.Zoom());
- // Compensate for the container size rounding by adjusting the source rect.
- FloatSize adjusted_src_size = scaled_src.Size();
- adjusted_src_size.Scale(residual_scale.Width(), residual_scale.Height());
- scaled_src.SetSize(adjusted_src_size);
+ // Compensate for the container size rounding by adjusting the source rect.
+ FloatSize residual_scale = draw_info.CalculateResidualScale();
+ unzoomed_src.SetSize(unzoomed_src.Size().ScaledBy(residual_scale.Width(),
+ residual_scale.Height()));
- DrawInternal(canvas, flags, dst_rect, scaled_src, kRespectImageOrientation,
- kClampImageToSourceRect, url);
- });
+ DrawInternal(draw_info, canvas, flags, dst_rect, unzoomed_src);
}
PaintImage SVGImage::PaintImageForCurrentFrame() {
+ const DrawInfo draw_info(FloatSize(intrinsic_size_), 1, NullURL());
auto builder = CreatePaintImageBuilder();
- PopulatePaintRecordForCurrentFrameForContainer(builder, Size(), 1, NullURL());
+ PopulatePaintRecordForCurrentFrameForContainer(draw_info, builder);
return builder.TakePaintImage();
}
-void SVGImage::DrawPatternForContainer(GraphicsContext& context,
- const FloatSize container_size,
- float zoom,
+void SVGImage::DrawPatternForContainer(const DrawInfo& draw_info,
+ GraphicsContext& context,
const FloatRect& src_rect,
const FloatSize& tile_scale,
const FloatPoint& phase,
SkBlendMode composite_op,
const FloatRect& dst_rect,
- const FloatSize& repeat_spacing,
- const KURL& url) {
+ const FloatSize& repeat_spacing) {
// Tile adjusted for scaling/stretch.
FloatRect tile(src_rect);
tile.Scale(tile_scale.Width(), tile_scale.Height());
@@ -444,7 +420,11 @@ void SVGImage::DrawPatternForContainer(GraphicsContext& context,
FloatRect spaced_tile(tile);
spaced_tile.Expand(FloatSize(repeat_spacing));
- PaintRecordBuilder builder(nullptr, &context);
+ SkMatrix pattern_transform;
+ pattern_transform.setTranslate(phase.X() + spaced_tile.X(),
+ phase.Y() + spaced_tile.Y());
+
+ PaintRecordBuilder builder(context);
{
DrawingRecorder recorder(builder.Context(), builder,
DisplayItem::Type::kSVGImage);
@@ -452,20 +432,14 @@ void SVGImage::DrawPatternForContainer(GraphicsContext& context,
// spacing area.
if (tile != spaced_tile)
builder.Context().Clip(tile);
- PaintFlags flags;
- DrawForContainer(builder.Context().Canvas(), flags, container_size, zoom,
- tile, src_rect, url);
+ DrawForContainer(draw_info, builder.Context().Canvas(), PaintFlags(), tile,
+ src_rect);
}
- sk_sp<PaintRecord> record = builder.EndRecording();
-
- SkMatrix pattern_transform;
- pattern_transform.setTranslate(phase.X() + spaced_tile.X(),
- phase.Y() + spaced_tile.Y());
PaintFlags flags;
- flags.setShader(
- PaintShader::MakePaintRecord(record, spaced_tile, SkTileMode::kRepeat,
- SkTileMode::kRepeat, &pattern_transform));
+ flags.setShader(PaintShader::MakePaintRecord(
+ builder.EndRecording(), spaced_tile, SkTileMode::kRepeat,
+ SkTileMode::kRepeat, &pattern_transform));
// If the shader could not be instantiated (e.g. non-invertible matrix),
// draw transparent.
// Note: we can't simply bail, because of arbitrary blend mode.
@@ -480,109 +454,91 @@ void SVGImage::DrawPatternForContainer(GraphicsContext& context,
}
void SVGImage::PopulatePaintRecordForCurrentFrameForContainer(
- PaintImageBuilder& builder,
- const IntSize& zoomed_container_size,
- float zoom,
- const KURL& url) {
+ const DrawInfo& draw_info,
+ PaintImageBuilder& builder) {
+ PaintRecorder recorder;
+ const FloatSize size(draw_info.ContainerSize().ScaledBy(draw_info.Zoom()));
+ const IntRect dest_rect(IntPoint(), RoundedIntSize(size));
+ cc::PaintCanvas* canvas = recorder.beginRecording(dest_rect);
+ DrawForContainer(draw_info, canvas, PaintFlags(), FloatRect(dest_rect),
+ FloatRect(FloatPoint(), size));
+ builder.set_paint_record(recorder.finishRecordingAsPicture(), dest_rect,
+ PaintImage::GetNextContentId());
+
builder.set_completion_state(
load_state_ == LoadState::kLoadCompleted
? PaintImage::CompletionState::DONE
: PaintImage::CompletionState::PARTIALLY_DONE);
- if (!page_)
- return;
-
- const IntRect container_rect(IntPoint(), zoomed_container_size);
- // Compute a new container size based on the zoomed (and potentially
- // rounded) size.
- FloatSize container_size(zoomed_container_size);
- container_size.Scale(1 / zoom);
-
- PaintRecorder recorder;
- cc::PaintCanvas* canvas = recorder.beginRecording(container_rect);
- DrawForContainer(canvas, PaintFlags(), container_size, zoom,
- FloatRect(container_rect), FloatRect(container_rect), url);
- builder.set_paint_record(recorder.finishRecordingAsPicture(), container_rect,
- PaintImage::GetNextContentId());
-}
-
-static bool DrawNeedsLayer(const PaintFlags& flags) {
- if (SkColorGetA(flags.getColor()) < 255)
- return true;
-
- // This is needed to preserve the dark mode filter that
- // has been set in GraphicsContext.
- if (flags.getColorFilter())
- return true;
-
- return flags.getBlendMode() != SkBlendMode::kSrcOver;
}
-bool SVGImage::ApplyShaderInternal(PaintFlags& flags,
- const SkMatrix& local_matrix,
- const KURL& url) {
- const FloatSize size(ContainerSize());
- if (size.IsEmpty())
+bool SVGImage::ApplyShaderInternal(const DrawInfo& draw_info,
+ PaintFlags& flags,
+ const SkMatrix& local_matrix) {
+ if (draw_info.ContainerSize().IsEmpty())
+ return false;
+ sk_sp<PaintRecord> record = PaintRecordForCurrentFrame(draw_info);
+ if (!record)
return false;
- FloatRect bounds(FloatPoint(), size);
+ const FloatRect bounds(FloatPoint(), draw_info.ContainerSize());
flags.setShader(PaintShader::MakePaintRecord(
- PaintRecordForCurrentFrame(url), bounds, SkTileMode::kRepeat,
- SkTileMode::kRepeat, &local_matrix));
+ std::move(record), bounds, SkTileMode::kRepeat, SkTileMode::kRepeat,
+ &local_matrix));
- // Animation is normally refreshed in draw() impls, which we don't reach when
+ // Animation is normally refreshed in Draw() impls, which we don't reach when
// painting via shaders.
StartAnimation();
-
return true;
}
bool SVGImage::ApplyShader(PaintFlags& flags, const SkMatrix& local_matrix) {
- return ApplyShaderInternal(flags, local_matrix, NullURL());
+ const DrawInfo draw_info(FloatSize(intrinsic_size_), 1, NullURL());
+ return ApplyShaderInternal(draw_info, flags, local_matrix);
}
-bool SVGImage::ApplyShaderForContainer(const FloatSize& container_size,
- float zoom,
- const KURL& url,
+bool SVGImage::ApplyShaderForContainer(const DrawInfo& draw_info,
PaintFlags& flags,
const SkMatrix& local_matrix) {
- bool result = false;
- ForContainer(container_size, [&](const FloatSize& residual_scale) {
- // Compensate for the container size rounding.
- auto adjusted_local_matrix = local_matrix;
- adjusted_local_matrix.preScale(zoom * residual_scale.Width(),
- zoom * residual_scale.Height());
-
- result = ApplyShaderInternal(flags, adjusted_local_matrix, url);
- });
-
- return result;
-}
-
-void SVGImage::Draw(
- cc::PaintCanvas* canvas,
- const PaintFlags& flags,
- const FloatRect& dst_rect,
- const FloatRect& src_rect,
- RespectImageOrientationEnum should_respect_image_orientation,
- ImageClampingMode clamp_mode,
- ImageDecodingMode) {
+ // Compensate for the container size rounding.
+ FloatSize residual_scale =
+ draw_info.CalculateResidualScale().ScaledBy(draw_info.Zoom());
+ auto adjusted_local_matrix = local_matrix;
+ adjusted_local_matrix.preScale(residual_scale.Width(),
+ residual_scale.Height());
+ return ApplyShaderInternal(draw_info, flags, adjusted_local_matrix);
+}
+
+void SVGImage::Draw(cc::PaintCanvas* canvas,
+ const PaintFlags& flags,
+ const FloatRect& dst_rect,
+ const FloatRect& src_rect,
+ const SkSamplingOptions&,
+ RespectImageOrientationEnum,
+ ImageClampingMode,
+ ImageDecodingMode) {
+ const DrawInfo draw_info(FloatSize(intrinsic_size_), 1, NullURL());
+ DrawInternal(draw_info, canvas, flags, dst_rect, src_rect);
+}
+
+sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(
+ const DrawInfo& draw_info) {
if (!page_)
- return;
-
- DrawInternal(canvas, flags, dst_rect, src_rect,
- should_respect_image_orientation, clamp_mode, NullURL());
-}
+ return nullptr;
+ // Temporarily disable the image observer to prevent ChangeInRect() calls due
+ // re-laying out the image.
+ ImageObserverDisabler disable_image_observer(this);
-sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const KURL& url) {
- DCHECK(page_);
- LocalFrameView* view = To<LocalFrame>(page_->MainFrame())->View();
- IntSize rounded_container_size = RoundedIntSize(ContainerSize());
+ const LayoutSize layout_container_size = draw_info.RoundedContainerSize();
+ if (LayoutSVGRoot* layout_root = LayoutRoot())
+ layout_root->SetContainerSize(layout_container_size);
+ LocalFrameView* view = GetFrame()->View();
+ const IntSize rounded_container_size = RoundedIntSize(layout_container_size);
view->Resize(rounded_container_size);
page_->GetVisualViewport().SetSize(rounded_container_size);
// Always call processUrlFragment, even if the url is empty, because
// there may have been a previous url/fragment that needs to be reset.
- view->ProcessUrlFragment(url, /*same_document_navigation=*/false);
+ view->ProcessUrlFragment(draw_info.Url(), /*same_document_navigation=*/false);
// If the image was reset, we need to rewind the timeline back to 0. This
// needs to be done before painting, or else we wouldn't get the correct
@@ -597,18 +553,32 @@ sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const KURL& url) {
}
view->UpdateAllLifecyclePhasesExceptPaint(DocumentUpdateReason::kSVGImage);
- PaintRecordBuilder builder(nullptr, nullptr, paint_controller_.get());
+ PaintRecordBuilder builder(*paint_controller_);
view->PaintOutsideOfLifecycle(builder.Context(), kGlobalPaintNormalPhase);
return builder.EndRecording();
}
-void SVGImage::DrawInternal(cc::PaintCanvas* canvas,
+static bool DrawNeedsLayer(const PaintFlags& flags) {
+ if (SkColorGetA(flags.getColor()) < 255)
+ return true;
+
+ // This is needed to preserve the dark mode filter that
+ // has been set in GraphicsContext.
+ if (flags.getColorFilter())
+ return true;
+
+ return flags.getBlendMode() != SkBlendMode::kSrcOver;
+}
+
+void SVGImage::DrawInternal(const DrawInfo& draw_info,
+ cc::PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dst_rect,
- const FloatRect& src_rect,
- RespectImageOrientationEnum,
- ImageClampingMode,
- const KURL& url) {
+ const FloatRect& unzoomed_src_rect) {
+ sk_sp<PaintRecord> record = PaintRecordForCurrentFrame(draw_info);
+ if (!record)
+ return;
+
{
PaintCanvasAutoRestore ar(canvas, false);
if (DrawNeedsLayer(flags)) {
@@ -620,9 +590,8 @@ void SVGImage::DrawInternal(cc::PaintCanvas* canvas,
// without clipping, and translate accordingly.
canvas->save();
canvas->clipRect(EnclosingIntRect(dst_rect));
- canvas->concat(SkMatrix::MakeRectToRect(src_rect, dst_rect,
- SkMatrix::kFill_ScaleToFit));
- canvas->drawPicture(PaintRecordForCurrentFrame(url));
+ canvas->concat(SkMatrix::RectToRect(unzoomed_src_rect, dst_rect));
+ canvas->drawPicture(std::move(record));
canvas->restore();
}
@@ -639,13 +608,13 @@ void SVGImage::ScheduleTimelineRewind() {
void SVGImage::FlushPendingTimelineRewind() {
if (!has_pending_timeline_rewind_)
return;
- if (SVGSVGElement* root_element = SvgRootElement(page_.Get()))
+ if (SVGSVGElement* root_element = RootElement())
root_element->setCurrentTime(0);
has_pending_timeline_rewind_ = false;
}
void SVGImage::StartAnimation() {
- SVGSVGElement* root_element = SvgRootElement(page_.Get());
+ SVGSVGElement* root_element = RootElement();
if (!root_element)
return;
chrome_client_->ResumeAnimation();
@@ -654,7 +623,7 @@ void SVGImage::StartAnimation() {
}
void SVGImage::StopAnimation() {
- SVGSVGElement* root_element = SvgRootElement(page_.Get());
+ SVGSVGElement* root_element = RootElement();
if (!root_element)
return;
chrome_client_->SuspendAnimation();
@@ -662,7 +631,7 @@ void SVGImage::StopAnimation() {
}
void SVGImage::ResetAnimation() {
- SVGSVGElement* root_element = SvgRootElement(page_.Get());
+ SVGSVGElement* root_element = RootElement();
if (!root_element)
return;
chrome_client_->SuspendAnimation();
@@ -682,14 +651,11 @@ void SVGImage::RestoreAnimation() {
}
bool SVGImage::MaybeAnimated() {
- SVGSVGElement* root_element = SvgRootElement(page_.Get());
+ SVGSVGElement* root_element = RootElement();
if (!root_element)
return false;
return root_element->TimeContainer()->HasAnimations() ||
- To<LocalFrame>(page_->MainFrame())
- ->GetDocument()
- ->Timeline()
- .HasPendingUpdates();
+ root_element->GetDocument().Timeline().HasPendingUpdates();
}
void SVGImage::ServiceAnimations(
@@ -720,7 +686,8 @@ void SVGImage::ServiceAnimations(
// actually generating painted output, not only for performance reasons,
// but to preserve correct coherence of the cache of the output with
// the needsRepaint bits of the PaintLayers in the image.
- LocalFrameView* frame_view = To<LocalFrame>(page_->MainFrame())->View();
+ LocalFrame* frame = GetFrame();
+ LocalFrameView* frame_view = frame->View();
frame_view->UpdateAllLifecyclePhasesExceptPaint(
DocumentUpdateReason::kSVGImage);
@@ -729,14 +696,12 @@ void SVGImage::ServiceAnimations(
// know SVG images never have composited animations, we can update animations
// directly without worrying about including PaintArtifactCompositor's
// analysis of whether animations should be composited.
- frame_view->GetLayoutView()
- ->GetDocument()
- .GetDocumentAnimations()
- .UpdateAnimations(DocumentLifecycle::kLayoutClean, nullptr);
+ frame->GetDocument()->GetDocumentAnimations().UpdateAnimations(
+ DocumentLifecycle::kLayoutClean, nullptr);
}
void SVGImage::AdvanceAnimationForTesting() {
- if (SVGSVGElement* root_element = SvgRootElement(page_.Get())) {
+ if (SVGSVGElement* root_element = RootElement()) {
root_element->TimeContainer()->AdvanceFrameForTesting();
// The following triggers animation updates which can issue a new draw
@@ -749,7 +714,7 @@ void SVGImage::AdvanceAnimationForTesting() {
if (root_element->TimeContainer()->IsStarted())
root_element->TimeContainer()->ResetDocumentTime();
page_->Animator().ServiceScriptedAnimations(
- root_element->GetDocument().Timeline().ZeroTime() +
+ root_element->GetDocument().Timeline().CalculateZeroTime() +
base::TimeDelta::FromSecondsD(root_element->getCurrentTime()));
GetImageObserver()->Changed(this);
page_->Animator().Clock().ResetTimeForTesting();
@@ -762,7 +727,7 @@ SVGImageChromeClient& SVGImage::ChromeClientForTesting() {
}
void SVGImage::UpdateUseCounters(const Document& document) const {
- if (SVGSVGElement* root_element = SvgRootElement(page_.Get())) {
+ if (SVGSVGElement* root_element = RootElement()) {
if (root_element->TimeContainer()->HasAnimations()) {
document.CountUse(WebFeature::kSVGSMILAnimationInImageRegardlessOfCache);
}
@@ -782,7 +747,7 @@ void SVGImage::LoadCompleted() {
// Document::ImplicitClose(), we defer AsyncLoadCompleted() to avoid
// potential bugs and timing dependencies around ImplicitClose() and
// to make LoadEventFinished() true when AsyncLoadCompleted() is called.
- To<LocalFrame>(page_->MainFrame())
+ GetFrame()
->GetTaskRunner(TaskType::kInternalLoading)
->PostTask(FROM_HERE, WTF::Bind(&SVGImage::NotifyAsyncLoadCompleted,
scoped_refptr<SVGImage>(this)));
@@ -835,7 +800,7 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
Page* page;
{
TRACE_EVENT0("blink", "SVGImage::dataChanged::createPage");
- page = Page::CreateNonOrdinary(page_clients);
+ page = Page::CreateNonOrdinary(page_clients, *agent_group_scheduler_);
page->GetSettings().SetScriptEnabled(false);
page->GetSettings().SetPluginsEnabled(false);
@@ -861,6 +826,9 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
page->GetSettings().SetPreferredColorScheme(
default_settings.GetPreferredColorScheme());
}
+ chrome_client_->InitAnimationTimer(page->GetPageScheduler()
+ ->GetAgentGroupScheduler()
+ .CompositorTaskRunner());
}
LocalFrame* frame = nullptr;
@@ -870,15 +838,12 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
frame_client_ = MakeGarbageCollected<SVGImageLocalFrameClient>(this);
frame = MakeGarbageCollected<LocalFrame>(
frame_client_, *page, nullptr, nullptr, nullptr,
- FrameInsertType::kInsertInConstructor, base::UnguessableToken::Create(),
- nullptr, nullptr, /* policy_container */ nullptr);
+ FrameInsertType::kInsertInConstructor, LocalFrameToken(), nullptr,
+ nullptr, /* policy_container */ nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame));
frame->Init(nullptr);
}
- FrameLoader& loader = frame->Loader();
- loader.ForceSandboxFlags(network::mojom::blink::WebSandboxFlags::kAll);
-
// SVG Images will always synthesize a viewBox, if it's not available, and
// thus never see scrollbars.
frame->View()->SetCanHaveScrollbars(false);
@@ -903,12 +868,11 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
switch (load_state_) {
case kInDataChanged:
load_state_ = kWaitingForAsyncLoadCompletion;
- return SvgRootElement(page_.Get())
- ? kSizeAvailableAndLoadingAsynchronously
- : kSizeUnavailable;
+ return RootElement() ? kSizeAvailableAndLoadingAsynchronously
+ : kSizeUnavailable;
case kLoadCompleted:
- return SvgRootElement(page_.Get()) ? kSizeAvailable : kSizeUnavailable;
+ return RootElement() ? kSizeAvailable : kSizeUnavailable;
case kDataChangedNotStarted:
case kWaitingForAsyncLoadCompletion:
@@ -921,7 +885,7 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
}
bool SVGImage::IsSizeAvailable() {
- return SvgRootElement(page_.Get());
+ return RootElement();
}
String SVGImage::FilenameExtension() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
index 54242e09143..58096e62477 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image.h
@@ -28,6 +28,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_GRAPHICS_SVG_IMAGE_H_
#include "base/macros.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
@@ -41,10 +42,14 @@
namespace blink {
class Document;
+class LayoutSVGRoot;
+class LocalFrame;
+class Node;
class Page;
class PaintController;
class SVGImageChromeClient;
class SVGImageForContainer;
+class SVGSVGElement;
struct IntrinsicSizingInfo;
// SVGImage does not use Skia to draw images (as BitmapImage does) but instead
@@ -106,12 +111,6 @@ class CORE_EXPORT SVGImage final : public Image {
// returns true if GetIntrinsicSizingInfo would.)
bool HasIntrinsicSizingInfo() const;
- // Unlike the above (HasIntrinsicSizingInfo) - which only indicates that
- // dimensions can be read - this returns true if those dimensions are not
- // empty (i.e if the concrete object size resolved using an empty default
- // object size is non-empty.)
- bool HasIntrinsicDimensions() const;
-
PaintImage PaintImageForCurrentFrame() override;
protected:
@@ -130,8 +129,6 @@ class CORE_EXPORT SVGImage final : public Image {
String FilenameExtension() const override;
- LayoutSize ContainerSize() const;
-
SizeAvailability DataChanged(bool all_data_received) override;
// FIXME: SVGImages are underreporting decoded sizes and will be unable
@@ -141,59 +138,66 @@ class CORE_EXPORT SVGImage final : public Image {
// FIXME: Implement this to be less conservative.
bool CurrentFrameKnownToBeOpaque() override { return false; }
+ class DrawInfo {
+ STACK_ALLOCATED();
+
+ public:
+ DrawInfo(const FloatSize& container_size, float zoom, const KURL& url);
+
+ FloatSize CalculateResidualScale() const;
+ float Zoom() const { return zoom_; }
+ const FloatSize& ContainerSize() const { return container_size_; }
+ const LayoutSize& RoundedContainerSize() const {
+ return rounded_container_size_;
+ }
+ const KURL& Url() const { return url_; }
+
+ private:
+ const FloatSize container_size_;
+ const LayoutSize rounded_container_size_;
+ const float zoom_;
+ const KURL& url_;
+ };
+
void Draw(cc::PaintCanvas*,
const cc::PaintFlags&,
- const FloatRect& from_rect,
- const FloatRect& to_rect,
+ const FloatRect& dst_rect,
+ const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
- void DrawForContainer(cc::PaintCanvas*,
+ void DrawForContainer(const DrawInfo&,
+ cc::PaintCanvas*,
const cc::PaintFlags&,
- const FloatSize&,
- float,
- const FloatRect&,
- const FloatRect&,
- const KURL&);
- void DrawPatternForContainer(GraphicsContext&,
- const FloatSize,
- float,
- const FloatRect&,
- const FloatSize&,
- const FloatPoint&,
- SkBlendMode,
- const FloatRect&,
- const FloatSize& repeat_spacing,
- const KURL&);
- void PopulatePaintRecordForCurrentFrameForContainer(
- PaintImageBuilder&,
- const IntSize& container_size,
- float zoom,
- const KURL&);
+ const FloatRect& dst_rect,
+ const FloatRect& src_rect);
+ void DrawPatternForContainer(const DrawInfo&,
+ GraphicsContext&,
+ const FloatRect& src_rect,
+ const FloatSize& tile_scale,
+ const FloatPoint& phase,
+ SkBlendMode composite_op,
+ const FloatRect& dst_rect,
+ const FloatSize& repeat_spacing);
+ void PopulatePaintRecordForCurrentFrameForContainer(const DrawInfo&,
+ PaintImageBuilder&);
// Paints the current frame. Returns new PaintRecord.
- sk_sp<PaintRecord> PaintRecordForCurrentFrame(const KURL&);
+ sk_sp<PaintRecord> PaintRecordForCurrentFrame(const DrawInfo&);
- void DrawInternal(cc::PaintCanvas*,
+ void DrawInternal(const DrawInfo&,
+ cc::PaintCanvas*,
const cc::PaintFlags&,
- const FloatRect& from_rect,
- const FloatRect& to_rect,
- RespectImageOrientationEnum,
- ImageClampingMode,
- const KURL&);
-
- template <typename Func>
- void ForContainer(const FloatSize&, Func&&);
-
+ const FloatRect& dst_rect,
+ const FloatRect& unzoomed_src_rect);
bool ApplyShader(cc::PaintFlags&, const SkMatrix& local_matrix) override;
- bool ApplyShaderForContainer(const FloatSize&,
- float zoom,
- const KURL&,
+ bool ApplyShaderForContainer(const DrawInfo&,
cc::PaintFlags&,
const SkMatrix& local_matrix);
- bool ApplyShaderInternal(cc::PaintFlags&,
- const SkMatrix& local_matrix,
- const KURL&);
+ bool ApplyShaderInternal(const DrawInfo&,
+ cc::PaintFlags&,
+ const SkMatrix& local_matrix);
void StopAnimation();
void ScheduleTimelineRewind();
@@ -203,11 +207,16 @@ class CORE_EXPORT SVGImage final : public Image {
void LoadCompleted();
void NotifyAsyncLoadCompleted();
+ LocalFrame* GetFrame() const;
+ SVGSVGElement* RootElement() const;
+ LayoutSVGRoot* LayoutRoot() const;
+
class SVGImageLocalFrameClient;
Persistent<SVGImageChromeClient> chrome_client_;
Persistent<Page> page_;
std::unique_ptr<PaintController> paint_controller_;
+ std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler_;
// When an SVG image has no intrinsic size, the size depends on the default
// object size, which in turn depends on the container. One SVGImage may
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.cc
index eba9f3feaef..5425a59b423 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.cc
@@ -38,16 +38,20 @@
namespace blink {
static constexpr base::TimeDelta kAnimationFrameDelay =
- base::TimeDelta::FromSecondsD(1.0 / 60);
+ base::TimeDelta::FromHz(60);
SVGImageChromeClient::SVGImageChromeClient(SVGImage* image)
: image_(image),
- animation_timer_(std::make_unique<TaskRunnerTimer<SVGImageChromeClient>>(
- ThreadScheduler::Current()->CompositorTaskRunner(),
- this,
- &SVGImageChromeClient::AnimationTimerFired)),
timeline_state_(kRunning) {}
+void SVGImageChromeClient::InitAnimationTimer(
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner) {
+ animation_timer_ = MakeGarbageCollected<
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>>(
+ std::move(compositor_task_runner), this,
+ &SVGImageChromeClient::AnimationTimerFired);
+}
+
bool SVGImageChromeClient::IsSVGImageChromeClient() const {
return true;
}
@@ -93,12 +97,13 @@ void SVGImageChromeClient::RestoreAnimationIfNeeded() {
void SVGImageChromeClient::ScheduleAnimation(const LocalFrameView*,
base::TimeDelta fire_time) {
+ DCHECK(animation_timer_);
// Because a single SVGImage can be shared by multiple pages, we can't key
// our svg image layout on the page's real animation frame. Therefore, we
// run this fake animation timer to trigger layout in SVGImages. The name,
// "animationTimer", is to match the new requestAnimationFrame-based layout
// approach.
- if (animation_timer_->IsActive())
+ if (animation_timer_->Value().IsActive())
return;
// Schedule the 'animation' ASAP if the image does not contain any
// animations, but prefer a fixed, jittery, frame-delay if there're any
@@ -110,11 +115,12 @@ void SVGImageChromeClient::ScheduleAnimation(const LocalFrameView*,
if (fire_time.is_zero())
fire_time = kAnimationFrameDelay;
}
- animation_timer_->StartOneShot(fire_time, FROM_HERE);
+ animation_timer_->Value().StartOneShot(fire_time, FROM_HERE);
}
-void SVGImageChromeClient::SetTimer(std::unique_ptr<TimerBase> timer) {
- animation_timer_ = std::move(timer);
+void SVGImageChromeClient::SetTimerForTesting(
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>* timer) {
+ animation_timer_ = timer;
}
void SVGImageChromeClient::AnimationTimerFired(TimerBase*) {
@@ -134,4 +140,9 @@ void SVGImageChromeClient::AnimationTimerFired(TimerBase*) {
image_->ServiceAnimations(base::TimeTicks::Now());
}
+void SVGImageChromeClient::Trace(Visitor* visitor) const {
+ visitor->Trace(animation_timer_);
+ EmptyChromeClient::Trace(visitor);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
index 69506e85d6c..5cdacbf2518 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_chrome_client.h
@@ -33,6 +33,7 @@
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
+#include "third_party/blink/renderer/platform/heap/disallow_new_wrapper.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -44,6 +45,9 @@ class CORE_EXPORT SVGImageChromeClient final : public EmptyChromeClient {
public:
explicit SVGImageChromeClient(SVGImage*);
+ void InitAnimationTimer(
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner);
+
bool IsSVGImageChromeClient() const override;
SVGImage* GetImage() const { return image_; }
@@ -54,18 +58,22 @@ class CORE_EXPORT SVGImageChromeClient final : public EmptyChromeClient {
bool IsSuspended() const { return timeline_state_ >= kSuspended; }
+ void Trace(Visitor*) const final;
+
private:
void ChromeDestroyed() override;
void InvalidateRect(const IntRect&) override;
void ScheduleAnimation(const LocalFrameView*,
base::TimeDelta = base::TimeDelta()) override;
- void SetTimer(std::unique_ptr<TimerBase>);
- TimerBase* GetTimerForTesting() const { return animation_timer_.get(); }
+ void SetTimerForTesting(
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>*);
+ TimerBase& GetTimerForTesting() const { return animation_timer_->Value(); }
void AnimationTimerFired(TimerBase*);
SVGImage* image_;
- std::unique_ptr<TimerBase> animation_timer_;
+ Member<DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>>
+ animation_timer_;
enum {
kRunning,
kSuspended,
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.cc
index f09e5845e75..9814e891f26 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.cc
@@ -19,12 +19,6 @@
#include "third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h"
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/geometry/float_size.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkImage.h"
-
namespace blink {
IntSize SVGImageForContainer::Size() const {
@@ -34,20 +28,19 @@ IntSize SVGImageForContainer::Size() const {
}
FloatSize SVGImageForContainer::SizeAsFloat(RespectImageOrientationEnum) const {
- FloatSize scaled_container_size(container_size_);
- scaled_container_size.Scale(zoom_);
- return scaled_container_size;
+ return container_size_.ScaledBy(zoom_);
}
void SVGImageForContainer::Draw(cc::PaintCanvas* canvas,
const cc::PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) {
- image_->DrawForContainer(canvas, flags, container_size_, zoom_, dst_rect,
- src_rect, url_);
+ const SVGImage::DrawInfo draw_info(container_size_, zoom_, url_);
+ image_->DrawForContainer(draw_info, canvas, flags, dst_rect, src_rect);
}
void SVGImageForContainer::DrawPattern(GraphicsContext& context,
@@ -58,21 +51,21 @@ void SVGImageForContainer::DrawPattern(GraphicsContext& context,
const FloatRect& dst_rect,
const FloatSize& repeat_spacing,
RespectImageOrientationEnum) {
- image_->DrawPatternForContainer(context, container_size_, zoom_, src_rect,
- scale, phase, op, dst_rect, repeat_spacing,
- url_);
+ const SVGImage::DrawInfo draw_info(container_size_, zoom_, url_);
+ image_->DrawPatternForContainer(draw_info, context, src_rect, scale, phase,
+ op, dst_rect, repeat_spacing);
}
bool SVGImageForContainer::ApplyShader(cc::PaintFlags& flags,
const SkMatrix& local_matrix) {
- return image_->ApplyShaderForContainer(container_size_, zoom_, url_, flags,
- local_matrix);
+ const SVGImage::DrawInfo draw_info(container_size_, zoom_, url_);
+ return image_->ApplyShaderForContainer(draw_info, flags, local_matrix);
}
PaintImage SVGImageForContainer::PaintImageForCurrentFrame() {
+ const SVGImage::DrawInfo draw_info(container_size_, zoom_, url_);
auto builder = CreatePaintImageBuilder();
- image_->PopulatePaintRecordForCurrentFrameForContainer(builder, Size(), zoom_,
- url_);
+ image_->PopulatePaintRecordForCurrentFrameForContainer(draw_info, builder);
return builder.TakePaintImage();
}
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
index c170dc07b1e..a69c1243035 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/platform/geometry/float_size.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
namespace blink {
@@ -81,6 +80,7 @@ class CORE_EXPORT SVGImageForContainer final : public Image {
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
index 506a0cbe154..3cd32995018 100644
--- a/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
+++ b/chromium/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
@@ -60,7 +60,7 @@ class SVGImageTest : public testing::Test, private ScopedMockOverlayScrollbars {
SkiaPaintCanvas canvas(null_canvas.get());
PaintFlags flags;
FloatRect dummy_rect(0, 0, 100, 100);
- image->Draw(&canvas, flags, dummy_rect, dummy_rect,
+ image->Draw(&canvas, flags, dummy_rect, dummy_rect, SkSamplingOptions(),
kRespectImageOrientation, Image::kDoNotClampImageToSourceRect,
Image::kSyncDecode);
}
@@ -114,28 +114,29 @@ TEST_F(SVGImageTest, TimelineSuspendAndResume) {
const bool kShouldPause = true;
Load(kAnimatedDocument, kShouldPause);
SVGImageChromeClient& chrome_client = GetImage().ChromeClientForTesting();
- TaskRunnerTimer<SVGImageChromeClient>* timer =
- new TaskRunnerTimer<SVGImageChromeClient>(
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>* timer =
+ MakeGarbageCollected<
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>>(
scheduler::GetSingleThreadTaskRunnerForTesting(), &chrome_client,
&SVGImageChromeClient::AnimationTimerFired);
- chrome_client.SetTimer(base::WrapUnique(timer));
+ chrome_client.SetTimerForTesting(timer);
// Simulate a draw. Cause a frame (timer) to be scheduled.
PumpFrame();
EXPECT_TRUE(GetImage().MaybeAnimated());
- EXPECT_TRUE(timer->IsActive());
+ EXPECT_TRUE(timer->Value().IsActive());
// Fire the timer/trigger a frame update. Since the observer always returns
// true for shouldPauseAnimation, this will result in the timeline being
// suspended.
test::RunDelayedTasks(base::TimeDelta::FromMilliseconds(1) +
- timer->NextFireInterval());
+ timer->Value().NextFireInterval());
EXPECT_TRUE(chrome_client.IsSuspended());
- EXPECT_FALSE(timer->IsActive());
+ EXPECT_FALSE(timer->Value().IsActive());
// Simulate a draw. This should resume the animation again.
PumpFrame();
- EXPECT_TRUE(timer->IsActive());
+ EXPECT_TRUE(timer->Value().IsActive());
EXPECT_FALSE(chrome_client.IsSuspended());
}
@@ -143,34 +144,35 @@ TEST_F(SVGImageTest, ResetAnimation) {
const bool kShouldPause = false;
Load(kAnimatedDocument, kShouldPause);
SVGImageChromeClient& chrome_client = GetImage().ChromeClientForTesting();
- TaskRunnerTimer<SVGImageChromeClient>* timer =
- new TaskRunnerTimer<SVGImageChromeClient>(
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>* timer =
+ MakeGarbageCollected<
+ DisallowNewWrapper<HeapTaskRunnerTimer<SVGImageChromeClient>>>(
scheduler::GetSingleThreadTaskRunnerForTesting(), &chrome_client,
&SVGImageChromeClient::AnimationTimerFired);
- chrome_client.SetTimer(base::WrapUnique(timer));
+ chrome_client.SetTimerForTesting(timer);
// Simulate a draw. Cause a frame (timer) to be scheduled.
PumpFrame();
EXPECT_TRUE(GetImage().MaybeAnimated());
- EXPECT_TRUE(timer->IsActive());
+ EXPECT_TRUE(timer->Value().IsActive());
// Reset the animation. This will suspend the timeline but not cancel the
// timer.
GetImage().ResetAnimation();
EXPECT_TRUE(chrome_client.IsSuspended());
- EXPECT_TRUE(timer->IsActive());
+ EXPECT_TRUE(timer->Value().IsActive());
// Fire the timer/trigger a frame update. The timeline will remain
// suspended and no frame will be scheduled.
test::RunDelayedTasks(base::TimeDelta::FromMillisecondsD(1) +
- timer->NextFireInterval());
+ timer->Value().NextFireInterval());
EXPECT_TRUE(chrome_client.IsSuspended());
- EXPECT_FALSE(timer->IsActive());
+ EXPECT_FALSE(timer->Value().IsActive());
// Simulate a draw. This should resume the animation again.
PumpFrame();
EXPECT_FALSE(chrome_client.IsSuspended());
- EXPECT_TRUE(timer->IsActive());
+ EXPECT_TRUE(timer->Value().IsActive());
}
TEST_F(SVGImageTest, SupportsSubsequenceCaching) {
@@ -282,12 +284,12 @@ TEST_F(SVGImageSimTest, PageVisibilityHiddenToVisible) {
ASSERT_TRUE(IsA<SVGImage>(image));
SVGImageChromeClient& svg_image_chrome_client =
To<SVGImage>(*image).ChromeClientForTesting();
- TimerBase* timer = svg_image_chrome_client.GetTimerForTesting();
+ TimerBase& timer = svg_image_chrome_client.GetTimerForTesting();
// Wait for the next animation frame to be triggered, and then trigger a new
// frame. The image animation timeline should be running.
test::RunDelayedTasks(base::TimeDelta::FromMilliseconds(1) +
- timer->NextFireInterval());
+ timer.NextFireInterval());
Compositor().BeginFrame();
EXPECT_FALSE(svg_image_chrome_client.IsSuspended());
@@ -298,7 +300,7 @@ TEST_F(SVGImageSimTest, PageVisibilityHiddenToVisible) {
WebView().SetVisibilityState(mojom::blink::PageVisibilityState::kHidden,
/*initial_state=*/false);
test::RunDelayedTasks(base::TimeDelta::FromMilliseconds(1) +
- timer->NextFireInterval());
+ timer.NextFireInterval());
EXPECT_TRUE(svg_image_chrome_client.IsSuspended());
@@ -307,7 +309,7 @@ TEST_F(SVGImageSimTest, PageVisibilityHiddenToVisible) {
WebView().SetVisibilityState(mojom::blink::PageVisibilityState::kVisible,
/*initial_state=*/false);
test::RunDelayedTasks(base::TimeDelta::FromMilliseconds(1) +
- timer->NextFireInterval());
+ timer.NextFireInterval());
Compositor().BeginFrame();
EXPECT_FALSE(svg_image_chrome_client.IsSuspended());
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_a_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_a_element.cc
index 48071f5c2f5..494c2d491e7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_a_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -75,11 +75,11 @@ String SVGAElement::title() const {
return SVGElement::title();
}
-void SVGAElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGAElement::SvgAttributeChanged(const SvgAttributeChangedParams& params) {
// Unlike other SVG*Element classes, SVGAElement only listens to
// SVGURIReference changes as none of the other properties changes the linking
// behaviour for our <a> element.
- if (SVGURIReference::IsKnownAttribute(attr_name)) {
+ if (SVGURIReference::IsKnownAttribute(params.name)) {
SVGElement::InvalidationGuard invalidation_guard(this);
bool was_link = IsLink();
@@ -94,7 +94,7 @@ void SVGAElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
LayoutObject* SVGAElement::CreateLayoutObject(const ComputedStyle&,
@@ -141,8 +141,9 @@ void SVGAElement::DefaultEventHandler(Event& event) {
ResourceRequest(GetDocument().CompleteURL(url)));
frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(&event));
frame_request.SetTriggeringEventInfo(
- event.isTrusted() ? TriggeringEventInfo::kFromTrustedEvent
- : TriggeringEventInfo::kFromUntrustedEvent);
+ event.isTrusted()
+ ? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
+ : mojom::blink::TriggeringEventInfo::kFromUntrustedEvent);
frame_request.GetResourceRequest().SetHasUserGesture(
LocalFrame::HasTransientUserActivation(GetDocument().GetFrame()));
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_a_element.h b/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
index f3c1ab500f2..1c6d75152cf 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_a_element.h
@@ -42,7 +42,7 @@ class CORE_EXPORT SVGAElement final : public SVGGraphicsElement,
private:
String title() const override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_animate_element.cc
index 49537cf5f32..62d3ae2f8a8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -43,12 +43,6 @@ namespace blink {
namespace {
-bool IsTargetAttributeCSSProperty(const SVGElement& target_element,
- const QualifiedName& attribute_name) {
- return SVGElement::IsAnimatableCSSProperty(attribute_name) ||
- target_element.IsPresentationAttribute(attribute_name);
-}
-
String ComputeCSSPropertyValue(SVGElement* element, CSSPropertyID id) {
DCHECK(element);
// TODO(fs): StyleEngine doesn't support document without a frame.
@@ -187,7 +181,7 @@ void SVGAnimateElement::ResolveTargetProperty() {
type_ = SVGElement::AnimatedPropertyTypeForCSSAttribute(AttributeName());
css_property_id_ =
type_ != kAnimatedUnknown
- ? cssPropertyID(targetElement()->GetExecutionContext(),
+ ? CssPropertyID(targetElement()->GetExecutionContext(),
AttributeName().LocalName())
: CSSPropertyID::kInvalid;
}
@@ -217,16 +211,13 @@ void SVGAnimateElement::UpdateTargetProperty() {
}
bool SVGAnimateElement::HasValidAnimation() const {
- if (AttributeName() == AnyQName())
- return false;
if (type_ == kAnimatedUnknown)
return false;
// Always animate CSS properties using the ApplyCSSAnimation code path,
// regardless of the attributeType value.
// If attributeType="CSS" and attributeName doesn't point to a CSS property,
// ignore the animation.
- return IsTargetAttributeCSSProperty(*targetElement(), AttributeName()) ||
- GetAttributeType() != kAttributeTypeCSS;
+ return IsAnimatingCSSProperty() || GetAttributeType() != kAttributeTypeCSS;
}
SVGPropertyBase* SVGAnimateElement::CreatePropertyForAttributeAnimation(
@@ -296,8 +287,7 @@ SVGPropertyBase* SVGAnimateElement::CreatePropertyForCSSAnimation(
return nullptr;
}
-SVGPropertyBase* SVGAnimateElement::CreatePropertyForAnimation(
- const String& value) const {
+SVGPropertyBase* SVGAnimateElement::ParseValue(const String& value) const {
if (IsAnimatingSVGDom())
return CreatePropertyForAttributeAnimation(value);
DCHECK(IsAnimatingCSSProperty());
@@ -309,6 +299,7 @@ SVGPropertyBase* SVGAnimateElement::AdjustForInheritance(
AnimatedPropertyValueType value_type) const {
if (value_type != kInheritValue)
return property_value;
+ DCHECK(IsAnimatingCSSProperty());
// TODO(fs): At the moment the computed style gets returned as a String and
// needs to get parsed again. In the future we might want to work with the
// value type directly to avoid the String parsing.
@@ -319,7 +310,7 @@ SVGPropertyBase* SVGAnimateElement::AdjustForInheritance(
return property_value;
// Replace 'inherit' by its computed property value.
String value = ComputeCSSPropertyValue(svg_parent, css_property_id_);
- return CreatePropertyForAnimation(value);
+ return CreatePropertyForCSSAnimation(value);
}
static SVGPropertyBase* DiscreteSelectValue(AnimationMode animation_mode,
@@ -389,17 +380,16 @@ bool SVGAnimateElement::CalculateToAtEndOfDurationValue(
const String& to_at_end_of_duration_string) {
if (to_at_end_of_duration_string.IsEmpty())
return false;
- to_at_end_of_duration_property_ =
- CreatePropertyForAnimation(to_at_end_of_duration_string);
+ to_at_end_of_duration_property_ = ParseValue(to_at_end_of_duration_string);
return true;
}
bool SVGAnimateElement::CalculateFromAndToValues(const String& from_string,
const String& to_string) {
DCHECK(targetElement());
- from_property_ = CreatePropertyForAnimation(from_string);
+ from_property_ = ParseValue(from_string);
from_property_value_type_ = PropertyValueType(AttributeName(), from_string);
- to_property_ = CreatePropertyForAnimation(to_string);
+ to_property_ = ParseValue(to_string);
to_property_value_type_ = PropertyValueType(AttributeName(), to_string);
return true;
}
@@ -417,9 +407,9 @@ bool SVGAnimateElement::CalculateFromAndByValues(const String& from_string,
DCHECK(!IsA<SVGSetElement>(*this));
- from_property_ = CreatePropertyForAnimation(from_string);
+ from_property_ = ParseValue(from_string);
from_property_value_type_ = PropertyValueType(AttributeName(), from_string);
- to_property_ = CreatePropertyForAnimation(by_string);
+ to_property_ = ParseValue(by_string);
to_property_value_type_ = PropertyValueType(AttributeName(), by_string);
to_property_->Add(from_property_, targetElement());
return true;
@@ -441,7 +431,7 @@ SMILAnimationValue SVGAnimateElement::CreateAnimationValue() const {
// CSS properties animation code-path.
String base_value =
ComputeCSSPropertyValue(targetElement(), css_property_id_);
- animation_value.property_value = CreatePropertyForAnimation(base_value);
+ animation_value.property_value = CreatePropertyForCSSAnimation(base_value);
}
return animation_value;
}
@@ -519,8 +509,8 @@ float SVGAnimateElement::CalculateDistance(const String& from_string,
DCHECK(targetElement());
// FIXME: A return value of float is not enough to support paced animations on
// lists.
- SVGPropertyBase* from_value = CreatePropertyForAnimation(from_string);
- SVGPropertyBase* to_value = CreatePropertyForAnimation(to_string);
+ SVGPropertyBase* from_value = ParseValue(from_string);
+ SVGPropertyBase* to_value = ParseValue(to_string);
return from_value->CalculateDistance(to_value, targetElement());
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_element.h b/chromium/third_party/blink/renderer/core/svg/svg_animate_element.h
index 1bd694d2981..e6d26951763 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -104,7 +104,7 @@ class CORE_EXPORT SVGAnimateElement : public SVGAnimationElement {
void WillChangeAnimatedType();
void DidChangeAnimatedType();
- virtual SVGPropertyBase* CreatePropertyForAnimation(const String&) const;
+ virtual SVGPropertyBase* ParseValue(const String&) const;
SVGPropertyBase* CreatePropertyForAttributeAnimation(const String&) const;
SVGPropertyBase* CreatePropertyForCSSAnimation(const String&) const;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
index 14cb933b468..bb52b24eef1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
@@ -218,26 +218,25 @@ void SVGAnimateMotionElement::CalculateAnimationValue(
DCHECK(!animation_path_.IsEmpty());
- float position_on_path = animation_path_.length() * percentage;
- FloatPoint position;
- float angle;
- animation_path_.PointAndNormalAtLength(position_on_path, position, angle);
+ const float path_length = animation_path_.length();
+ float position_on_path = path_length * percentage;
+ PointAndTangent position =
+ animation_path_.PointAndNormalAtLength(position_on_path);
// Handle accumulate="sum".
if (repeat_count && parameters.is_cumulative) {
FloatPoint position_at_end_of_duration =
- animation_path_.PointAtLength(animation_path_.length());
- position.Move(position_at_end_of_duration.X() * repeat_count,
- position_at_end_of_duration.Y() * repeat_count);
+ animation_path_.PointAtLength(path_length);
+ position.point.MoveBy(position_at_end_of_duration.ScaledBy(repeat_count));
}
- transform->Translate(position.X(), position.Y());
+ transform->Translate(position.point.X(), position.point.Y());
RotateMode rotate_mode = GetRotateMode();
if (rotate_mode != kRotateAuto && rotate_mode != kRotateAutoReverse)
return;
if (rotate_mode == kRotateAutoReverse)
- angle += 180;
- transform->Rotate(angle);
+ position.tangent_in_degrees += 180;
+ transform->Rotate(position.tangent_in_degrees);
}
void SVGAnimateMotionElement::ApplyResultsToTarget(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
index d60487879b6..5e4014c936b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
@@ -55,7 +55,7 @@ void SVGAnimateTransformElement::ResolveTargetProperty() {
css_property_id_ = CSSPropertyID::kInvalid;
}
-SVGPropertyBase* SVGAnimateTransformElement::CreatePropertyForAnimation(
+SVGPropertyBase* SVGAnimateTransformElement::ParseValue(
const String& value) const {
DCHECK(IsAnimatingSVGDom());
return MakeGarbageCollected<SVGTransformList>(transform_type_, value);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
index b5607c5148c..7a5f0601ef5 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
@@ -40,7 +40,7 @@ class SVGAnimateTransformElement final : public SVGAnimateElement {
void ParseAttribute(const AttributeModificationParams&) override;
- SVGPropertyBase* CreatePropertyForAnimation(const String&) const override;
+ SVGPropertyBase* ParseValue(const String&) const override;
SVGTransformType transform_type_;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_animated_path.cc b/chromium/third_party/blink/renderer/core/svg/svg_animated_path.cc
index 5bacbfdb963..5e5723c1495 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_animated_path.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_animated_path.cc
@@ -46,10 +46,10 @@ SVGAnimatedPath::SVGAnimatedPath(SVGElement* context_element,
SVGAnimatedPath::~SVGAnimatedPath() = default;
const CSSValue& SVGAnimatedPath::CssValue() const {
- const cssvalue::CSSPathValue* path_value = CurrentValue()->PathValue();
- if (path_value->GetStylePath()->ByteStream().IsEmpty())
+ const cssvalue::CSSPathValue& path_value = CurrentValue()->PathValue();
+ if (path_value.GetStylePath()->ByteStream().IsEmpty())
return *CSSIdentifierValue::Create(CSSValueID::kNone);
- return *path_value;
+ return path_value;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.cc
index 98403ab4904..3ba4de8d5ba 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.cc
@@ -66,13 +66,11 @@ Path SVGCircleElement::AsPath() const {
SVGLengthContext length_context(this);
const ComputedStyle& style = ComputedStyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
-
- float r = length_context.ValueForLength(svg_style.R(), style,
- SVGLengthMode::kOther);
+ float r =
+ length_context.ValueForLength(style.R(), style, SVGLengthMode::kOther);
if (r > 0) {
- FloatPoint center(length_context.ResolveLengthPair(svg_style.Cx(),
- svg_style.Cy(), style));
+ FloatPoint center(
+ length_context.ResolveLengthPair(style.Cx(), style.Cy(), style));
FloatSize radii(r, r);
path.AddEllipse(FloatRect(center - radii, radii.ScaledBy(2)));
}
@@ -99,7 +97,9 @@ void SVGCircleElement::CollectStyleForPresentationAttribute(
}
}
-void SVGCircleElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGCircleElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kRAttr || attr_name == svg_names::kCxAttr ||
attr_name == svg_names::kCyAttr) {
UpdateRelativeLengthsInformation();
@@ -107,7 +107,7 @@ void SVGCircleElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
bool SVGCircleElement::SelfHasRelativeLengths() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
index 652b360719e..7ae9436604a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_circle_element.h
@@ -43,7 +43,7 @@ class SVGCircleElement final : public SVGGeometryElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void CollectStyleForPresentationAttribute(
const QualifiedName&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
index 9c8e0f300a3..63ff57c8478 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
@@ -41,8 +41,9 @@ void SVGClipPathElement::Trace(Visitor* visitor) const {
SVGGraphicsElement::Trace(visitor);
}
-void SVGClipPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (attr_name == svg_names::kClipPathUnitsAttr) {
+void SVGClipPathElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kClipPathUnitsAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
auto* layout_object = To<LayoutSVGResourceContainer>(GetLayoutObject());
@@ -51,7 +52,7 @@ void SVGClipPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
void SVGClipPathElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
index 2ed4287e3e7..e34bc62b50a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_clip_path_element.h
@@ -45,7 +45,7 @@ class SVGClipPathElement final : public SVGGraphicsElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ChildrenChanged(const ChildrenChange&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
index 74922b59a3f..abe29155aa9 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
@@ -93,7 +93,8 @@ void SVGComponentTransferFunctionElement::Trace(Visitor* visitor) const {
}
void SVGComponentTransferFunctionElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kTypeAttr ||
attr_name == svg_names::kTableValuesAttr ||
attr_name == svg_names::kSlopeAttr ||
@@ -106,7 +107,7 @@ void SVGComponentTransferFunctionElement::SvgAttributeChanged(
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
ComponentTransferFunction
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.h b/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.h
index 62f09ff1ca5..ec47151c8ae 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.h
@@ -52,7 +52,7 @@ class SVGComponentTransferFunctionElement : public SVGElement {
protected:
SVGComponentTransferFunctionElement(const QualifiedName&, Document&);
- void SvgAttributeChanged(const QualifiedName&) final;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) final;
bool LayoutObjectIsNeeded(const ComputedStyle& style) const final {
return false;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_document_extensions.h b/chromium/third_party/blink/renderer/core/svg/svg_document_extensions.h
index f9a07131064..ae23e809c08 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_document_extensions.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_document_extensions.h
@@ -23,7 +23,6 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/platform/geometry/float_point.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -57,8 +56,6 @@ class CORE_EXPORT SVGDocumentExtensions final
void DispatchSVGLoadEventToOutermostSVGElements();
- SVGResourcesCache& ResourcesCache() { return resources_cache_; }
-
void AddSVGRootWithRelativeLengthDescendents(SVGSVGElement*);
void RemoveSVGRootWithRelativeLengthDescendents(SVGSVGElement*);
void InvalidateSVGRootsWithRelativeLengthDescendents(SubtreeLayoutScope*);
@@ -77,7 +74,6 @@ class CORE_EXPORT SVGDocumentExtensions final
HeapHashSet<Member<SVGSVGElement>> time_containers_;
using SVGElementSet = HeapHashSet<Member<SVGElement>>;
SVGElementSet web_animations_pending_svg_elements_;
- SVGResourcesCache resources_cache_;
// Root SVG elements with relative length descendants.
HeapHashSet<Member<SVGSVGElement>> relative_length_svg_roots_;
FloatPoint translate_;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_element.cc
index c2ef55dcd95..1d54d973fe7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_element.cc
@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -248,21 +249,25 @@ void SVGElement::SetAnimatedAttribute(const QualifiedName& attribute,
if (attribute == html_names::kClassAttr)
EnsureUniqueElementData();
- ForSelfAndInstances(this, [&attribute, &value](SVGElement* element) {
+ const SvgAttributeChangedParams params(
+ attribute, AttributeModificationReason::kDirectly);
+ ForSelfAndInstances(this, [&params, &value](SVGElement* element) {
if (SVGAnimatedPropertyBase* animated_property =
- element->PropertyFromAttribute(attribute)) {
+ element->PropertyFromAttribute(params.name)) {
animated_property->SetAnimatedValue(value);
- element->SvgAttributeChanged(attribute);
+ element->SvgAttributeChanged(params);
}
});
}
void SVGElement::ClearAnimatedAttribute(const QualifiedName& attribute) {
- ForSelfAndInstances(this, [&attribute](SVGElement* element) {
+ const SvgAttributeChangedParams params(
+ attribute, AttributeModificationReason::kDirectly);
+ ForSelfAndInstances(this, [&params](SVGElement* element) {
if (SVGAnimatedPropertyBase* animated_property =
- element->PropertyFromAttribute(attribute)) {
+ element->PropertyFromAttribute(params.name)) {
animated_property->AnimationEnded();
- element->SvgAttributeChanged(attribute);
+ element->SvgAttributeChanged(params);
}
});
}
@@ -448,7 +453,7 @@ CSSPropertyID SVGElement::CssPropertyIdForSVGAttributeName(
};
for (size_t i = 0; i < base::size(attr_names); i++) {
CSSPropertyID property_id =
- cssPropertyID(execution_context, attr_names[i]->LocalName());
+ CssPropertyID(execution_context, attr_names[i]->LocalName());
DCHECK_GT(property_id, CSSPropertyID::kInvalid);
property_name_to_id_map->Set(attr_names[i]->LocalName().Impl(),
property_id);
@@ -904,11 +909,12 @@ void SVGElement::AttributeChanged(const AttributeModificationParams& params) {
if (params.name == html_names::kStyleAttr)
return;
- SvgAttributeChanged(params.name);
+ SvgAttributeChanged({params.name, params.reason});
UpdateWebAnimatedAttributeOnBaseValChange(params.name);
}
-void SVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGElement::SvgAttributeChanged(const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
CSSPropertyID prop_id = SVGElement::CssPropertyIdForSVGAttributeName(
GetExecutionContext(), attr_name);
if (prop_id > CSSPropertyID::kInvalid) {
@@ -927,7 +933,7 @@ void SVGElement::BaseValueChanged(
const SVGAnimatedPropertyBase& animated_property) {
const QualifiedName& attribute = animated_property.AttributeName();
EnsureUniqueElementData().SetSvgAttributesAreDirty(true);
- SvgAttributeChanged(attribute);
+ SvgAttributeChanged({attribute, AttributeModificationReason::kDirectly});
if (class_name_ == &animated_property) {
UpdateClassList(g_null_atom,
AtomicString(class_name_->BaseValue()->Value()));
@@ -977,7 +983,7 @@ void SVGElement::SynchronizeSVGAttribute(const QualifiedName& name) const {
}
}
-void SVGElement::CollectStyleForAnimatedPresentationAttributes(
+void SVGElement::CollectExtraStyleForPresentationAttribute(
MutableCSSPropertyValueSet* style) {
// TODO(fs): This re-applies all animating attributes that are also
// presentation attributes. The precise predicate that we want is animated
@@ -1001,17 +1007,20 @@ void SVGElement::CollectStyleForAnimatedPresentationAttributes(
}
}
-scoped_refptr<ComputedStyle> SVGElement::CustomStyleForLayoutObject() {
+scoped_refptr<ComputedStyle> SVGElement::CustomStyleForLayoutObject(
+ const StyleRecalcContext& style_recalc_context) {
SVGElement* corresponding_element = CorrespondingElement();
- if (!corresponding_element)
- return GetDocument().GetStyleResolver().StyleForElement(this);
+ if (!corresponding_element) {
+ return GetDocument().GetStyleResolver().StyleForElement(
+ this, style_recalc_context);
+ }
const ComputedStyle* style = nullptr;
if (Element* parent = ParentOrShadowHostElement())
style = parent->GetComputedStyle();
- return GetDocument().GetStyleResolver().StyleForElement(corresponding_element,
- style, style);
+ return GetDocument().GetStyleResolver().StyleForElement(
+ corresponding_element, style_recalc_context, style, style);
}
bool SVGElement::LayoutObjectIsNeeded(const ComputedStyle& style) const {
@@ -1233,16 +1242,18 @@ void SVGElement::RebuildAllIncomingReferences() {
const SVGElementSet& incoming_references =
SvgRareData()->IncomingReferences();
- // Iterate on a snapshot as |incomingReferences| may be altered inside loop.
+ // Iterate on a snapshot as |incoming_references| may be altered inside loop.
HeapVector<Member<SVGElement>> incoming_references_snapshot;
CopyToVector(incoming_references, incoming_references_snapshot);
- // Force rebuilding the |sourceElement| so it knows about this change.
+ // Force rebuilding the |source_element| so it knows about this change.
+ const SvgAttributeChangedParams params(
+ svg_names::kHrefAttr, AttributeModificationReason::kDirectly);
for (SVGElement* source_element : incoming_references_snapshot) {
- // Before rebuilding |sourceElement| ensure it was not removed from under
+ // Before rebuilding |source_element| ensure it was not removed from under
// us.
if (incoming_references.Contains(source_element))
- source_element->SvgAttributeChanged(svg_names::kHrefAttr);
+ source_element->SvgAttributeChanged(params);
}
}
@@ -1288,9 +1299,8 @@ void SVGElement::Trace(Visitor* visitor) const {
Element::Trace(visitor);
}
-void SVGElement::AccessKeyAction(bool send_mouse_events) {
- DispatchSimulatedClick(
- nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
+void SVGElement::AccessKeyAction(SimulatedClickCreationScope creation_scope) {
+ DispatchSimulatedClick(nullptr, creation_scope);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_element.h b/chromium/third_party/blink/renderer/core/svg/svg_element.h
index 4c15e7599ba..778b564531e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_element.h
@@ -25,6 +25,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/svg/properties/svg_property_info.h"
#include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
#include "third_party/blink/renderer/core/svg_names.h"
@@ -124,7 +125,18 @@ class CORE_EXPORT SVGElement : public Element {
// For SVGTests
virtual bool IsValid() const { return true; }
- virtual void SvgAttributeChanged(const QualifiedName&);
+ struct SvgAttributeChangedParams {
+ STACK_ALLOCATED();
+
+ public:
+ SvgAttributeChangedParams(const QualifiedName& qname,
+ AttributeModificationReason reason)
+ : name(qname), reason(reason) {}
+
+ const QualifiedName& name;
+ const AttributeModificationReason reason;
+ };
+ virtual void SvgAttributeChanged(const SvgAttributeChangedParams&);
SVGAnimatedPropertyBase* PropertyFromAttribute(
const QualifiedName& attribute_name) const;
@@ -149,10 +161,11 @@ class CORE_EXPORT SVGElement : public Element {
SVGUseElement* GeneratingUseElement() const;
void SynchronizeSVGAttribute(const QualifiedName&) const;
- void CollectStyleForAnimatedPresentationAttributes(
- MutableCSSPropertyValueSet*);
+ void CollectExtraStyleForPresentationAttribute(
+ MutableCSSPropertyValueSet*) override;
- scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() final;
+ scoped_refptr<ComputedStyle> CustomStyleForLayoutObject(
+ const StyleRecalcContext&) final;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
#if DCHECK_IS_ON()
@@ -266,7 +279,7 @@ class CORE_EXPORT SVGElement : public Element {
void RemovedEventListener(const AtomicString& event_type,
const RegisteredEventListener&) final;
- void AccessKeyAction(bool send_mouse_events) override;
+ void AccessKeyAction(SimulatedClickCreationScope creation_scope) override;
private:
bool IsSVGElement() const =
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_element_rare_data.cc b/chromium/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
index 7fca1f994c0..3802c720554 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
@@ -32,12 +32,16 @@ const ComputedStyle* SVGElementRareData::OverrideComputedStyle(
const ComputedStyle* parent_style) {
DCHECK(element);
if (!override_computed_style_ || needs_override_computed_style_update_) {
+ // TODO(crbug.com/1145970): Use actual StyleRecalcContext.
+ StyleRecalcContext style_recalc_context;
+
// The style computed here contains no CSS Animations/Transitions or SMIL
// induced rules - this is needed to compute the "base value" for the SMIL
// animation sandwhich model.
override_computed_style_ =
element->GetDocument().GetStyleResolver().StyleForElement(
- element, parent_style, parent_style, kMatchAllRulesExcludingSMIL);
+ element, style_recalc_context, parent_style, parent_style,
+ kMatchAllRulesExcludingSMIL);
needs_override_computed_style_update_ = false;
}
DCHECK(override_computed_style_);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
index d71cf6c8405..c12f8f45bd3 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
@@ -74,20 +74,18 @@ Path SVGEllipseElement::AsPath() const {
SVGLengthContext length_context(this);
const ComputedStyle& style = ComputedStyleRef();
- const SVGComputedStyle& svg_style = style.SvgStyle();
-
FloatSize radii(ToFloatSize(
- length_context.ResolveLengthPair(svg_style.Rx(), svg_style.Ry(), style)));
- if (svg_style.Rx().IsAuto())
+ length_context.ResolveLengthPair(style.Rx(), style.Ry(), style)));
+ if (style.Rx().IsAuto())
radii.SetWidth(radii.Height());
- else if (svg_style.Ry().IsAuto())
+ else if (style.Ry().IsAuto())
radii.SetHeight(radii.Width());
if (radii.Width() < 0 || radii.Height() < 0 ||
(!radii.Width() && !radii.Height()))
return path;
FloatPoint center(
- length_context.ResolveLengthPair(svg_style.Cx(), svg_style.Cy(), style));
+ length_context.ResolveLengthPair(style.Cx(), style.Cy(), style));
path.AddEllipse(FloatRect(center - radii, radii.ScaledBy(2)));
return path;
}
@@ -115,7 +113,9 @@ void SVGEllipseElement::CollectStyleForPresentationAttribute(
}
}
-void SVGEllipseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGEllipseElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kCxAttr || attr_name == svg_names::kCyAttr ||
attr_name == svg_names::kRxAttr || attr_name == svg_names::kRyAttr) {
UpdateRelativeLengthsInformation();
@@ -123,7 +123,7 @@ void SVGEllipseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGeometryElement::SvgAttributeChanged(attr_name);
+ SVGGeometryElement::SvgAttributeChanged(params);
}
bool SVGEllipseElement::SelfHasRelativeLengths() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
index 3697849a5c8..300bcd3b05e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_ellipse_element.h
@@ -49,7 +49,7 @@ class SVGEllipseElement final : public SVGGeometryElement {
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool SelfHasRelativeLengths() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.cc b/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.cc
deleted file mode 100644
index 8b1428a787b..00000000000
--- a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
- Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
- Copyright (C) 2012 University of Szeged
- Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
-
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/document_init.h"
-#include "third_party/blink/renderer/core/dom/xml_document.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
-
-namespace blink {
-
-namespace {
-
-bool MimeTypeAllowed(const ResourceResponse& response) {
- AtomicString mime_type = response.MimeType();
- if (response.IsHTTP())
- mime_type = response.HttpContentType();
- return mime_type == "image/svg+xml" || mime_type == "text/xml" ||
- mime_type == "application/xml" || mime_type == "application/xhtml+xml";
-}
-
-} // namespace
-
-void SVGExternalDocumentCache::Entry::AddClient(Client* client) {
- if (!GetResource()->IsLoaded()) {
- clients_.insert(client);
- return;
- }
- context_->GetTaskRunner(TaskType::kInternalLoading)
- ->PostTask(
- FROM_HERE,
- WTF::Bind(&SVGExternalDocumentCache::Client::NotifyFinished,
- WrapPersistent(client), WrapPersistent(document_.Get())));
-}
-
-void SVGExternalDocumentCache::Entry::NotifyFinished(Resource* resource) {
- DCHECK_EQ(GetResource(), resource);
- for (auto client : clients_) {
- if (client)
- client->NotifyFinished(GetDocument());
- }
-}
-
-Document* SVGExternalDocumentCache::Entry::GetDocument() {
- const TextResource* resource = To<TextResource>(GetResource());
- if (!document_ && resource->IsLoaded() && resource->HasData() &&
- MimeTypeAllowed(resource->GetResponse())) {
- document_ = XMLDocument::CreateSVG(
- DocumentInit::Create()
- .WithURL(resource->GetResponse().CurrentRequestUrl())
- .WithExecutionContext(context_.Get()));
- document_->SetContent(resource->DecodedText());
- }
- return document_.Get();
-}
-
-void SVGExternalDocumentCache::Entry::Trace(Visitor* visitor) const {
- ResourceClient::Trace(visitor);
- visitor->Trace(document_);
- visitor->Trace(context_);
- visitor->Trace(clients_);
-}
-
-const char SVGExternalDocumentCache::kSupplementName[] =
- "SVGExternalDocumentCache";
-
-SVGExternalDocumentCache* SVGExternalDocumentCache::From(Document& document) {
- SVGExternalDocumentCache* cache =
- Supplement<Document>::From<SVGExternalDocumentCache>(document);
- if (!cache) {
- cache = MakeGarbageCollected<SVGExternalDocumentCache>(document);
- Supplement<Document>::ProvideTo(document, cache);
- }
- return cache;
-}
-
-SVGExternalDocumentCache::SVGExternalDocumentCache(Document& document)
- : Supplement<Document>(document) {}
-
-SVGExternalDocumentCache::Entry* SVGExternalDocumentCache::Get(
- Client* client,
- const KURL& url,
- const AtomicString& initiator_name,
- network::mojom::blink::CSPDisposition csp_disposition) {
- Document* context_document = GetSupplementable();
- ResourceLoaderOptions options(
- context_document->GetExecutionContext()->GetCurrentWorld());
- options.initiator_info.name = initiator_name;
- FetchParameters params(ResourceRequest(url), options);
- params.SetContentSecurityCheck(csp_disposition);
- params.MutableResourceRequest().SetMode(
- network::mojom::blink::RequestMode::kSameOrigin);
- params.SetRequestContext(mojom::blink::RequestContextType::IMAGE);
- params.SetRequestDestination(network::mojom::RequestDestination::kImage);
-
- Entry* entry =
- MakeGarbageCollected<Entry>(context_document->GetExecutionContext());
- Resource* resource = TextResource::FetchSVGDocument(
- params, context_document->Fetcher(), entry);
- // TODO(fs): Handle revalidations that return a new/different resource without
- // needing to throw away the old Entry.
- if (resource && resource->IsCacheValidator())
- entries_.erase(resource);
- entry = entries_.insert(resource, entry).stored_value->value;
- entry->AddClient(client);
- return entry;
-}
-
-void SVGExternalDocumentCache::Trace(Visitor* visitor) const {
- Supplement<Document>::Trace(visitor);
- visitor->Trace(entries_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.h b/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.h
deleted file mode 100644
index 379f5c99768..00000000000
--- a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
- Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
- Copyright (C) 2012 University of Szeged
- Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
-
-#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-class Document;
-class ExecutionContext;
-
-class CORE_EXPORT SVGExternalDocumentCache
- : public GarbageCollected<SVGExternalDocumentCache>,
- public Supplement<Document> {
- public:
- static const char kSupplementName[];
- static SVGExternalDocumentCache* From(Document&);
- explicit SVGExternalDocumentCache(Document&);
- void Trace(Visitor*) const override;
-
- class Client : public GarbageCollectedMixin {
- public:
- virtual void NotifyFinished(Document*) = 0;
- };
-
- class CORE_EXPORT Entry final : public GarbageCollected<Entry>,
- public ResourceClient {
- public:
- explicit Entry(ExecutionContext* context) : context_(context) {}
- ~Entry() override = default;
- void Trace(Visitor*) const override;
- Document* GetDocument();
- const KURL& Url() const { return GetResource()->Url(); }
-
- private:
- friend class SVGExternalDocumentCache;
- void AddClient(Client*);
-
- // ResourceClient overrides;
- void NotifyFinished(Resource*) override;
- String DebugName() const override { return "SVGExternalDocumentCache"; }
-
- Member<Document> document_;
- Member<ExecutionContext> context_;
- HeapHashSet<WeakMember<Client>> clients_;
- };
-
- Entry* Get(Client*,
- const KURL&,
- const AtomicString& initiator_name,
- network::mojom::blink::CSPDisposition =
- network::mojom::blink::CSPDisposition::CHECK);
-
- private:
- HeapHashMap<WeakMember<Resource>, WeakMember<Entry>> entries_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_EXTERNAL_DOCUMENT_CACHE_H_
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache_test.cc b/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache_test.cc
deleted file mode 100644
index 18868377333..00000000000
--- a/chromium/third_party/blink/renderer/core/svg/svg_external_document_cache_test.cc
+++ /dev/null
@@ -1,49 +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/core/svg/svg_external_document_cache.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
-
-namespace blink {
-
-class DummyCacheClient : public GarbageCollected<DummyCacheClient>,
- public SVGExternalDocumentCache::Client {
- public:
- DummyCacheClient() = default;
- void NotifyFinished(Document*) override {}
-};
-
-class SVGExternalDocumentCacheTest : public SimTest {};
-
-TEST_F(SVGExternalDocumentCacheTest, GetDocumentBeforeLoadComplete) {
- SimRequest main_resource("https://example.com/test.html", "text/html");
- LoadURL("https://example.com/test.html");
- main_resource.Complete("<html><body></body></html>");
-
- const char kSVGUrl[] = "https://example.com/svg.svg";
- SimSubresourceRequest svg_resource(kSVGUrl, "application/xml");
- DummyCacheClient* client = MakeGarbageCollected<DummyCacheClient>();
-
- // Request a resource from the cache.
- auto* entry =
- SVGExternalDocumentCache::From(GetDocument())
- ->Get(client, KURL(kSVGUrl), fetch_initiator_type_names::kCSS);
-
- // Write part of the response. The document should not be initialized yet,
- // because the response is not complete. The document would be invalid at this
- // point.
- svg_resource.Start();
- svg_resource.Write("<sv");
- EXPECT_EQ(nullptr, entry->GetDocument());
-
- // Finish the response, the Document should now be accessible.
- svg_resource.Complete("g></svg>");
- EXPECT_NE(nullptr, entry->GetDocument());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
index 0177a228e23..f187bc940d9 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
@@ -113,7 +113,9 @@ bool SVGFEBlendElement::SetFilterEffectAttribute(
effect, attr_name);
}
-void SVGFEBlendElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGFEBlendElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kModeAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
PrimitiveAttributeChanged(attr_name);
@@ -126,7 +128,7 @@ void SVGFEBlendElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEBlendElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
index 6a00a00d314..025980f6af1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
@@ -62,7 +62,7 @@ class SVGFEBlendElement final : public SVGFilterPrimitiveStandardAttributes {
private:
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
index 94ba0e6c754..2c32e91d560 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
@@ -78,7 +78,8 @@ bool SVGFEColorMatrixElement::SetFilterEffectAttribute(
}
void SVGFEColorMatrixElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kTypeAttr ||
attr_name == svg_names::kValuesAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
@@ -92,7 +93,7 @@ void SVGFEColorMatrixElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEColorMatrixElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
index 029a6102832..00deed6f9a0 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
@@ -47,7 +47,7 @@ class SVGFEColorMatrixElement final
private:
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
index e68f02671f6..a679b817d06 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
@@ -46,14 +46,14 @@ void SVGFEComponentTransferElement::Trace(Visitor* visitor) const {
}
void SVGFEComponentTransferElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
- if (attr_name == svg_names::kInAttr) {
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kInAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
Invalidate();
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEComponentTransferElement::Build(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
index ae5f775492e..676b1ea8e0e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
@@ -38,7 +38,7 @@ class SVGFEComponentTransferElement final
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
index d7856ef43ac..eb6e21241ae 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
@@ -107,7 +107,8 @@ bool SVGFECompositeElement::SetFilterEffectAttribute(
}
void SVGFECompositeElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kOperatorAttr ||
attr_name == svg_names::kK1Attr || attr_name == svg_names::kK2Attr ||
attr_name == svg_names::kK3Attr || attr_name == svg_names::kK4Attr) {
@@ -122,7 +123,7 @@ void SVGFECompositeElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFECompositeElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
index 1a1731a6897..4c5730b9063 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
@@ -53,7 +53,7 @@ class SVGFECompositeElement final
private:
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
index b68058ae842..e43d94a0ca4 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
@@ -205,7 +205,8 @@ bool SVGFEConvolveMatrixElement::SetFilterEffectAttribute(
}
void SVGFEConvolveMatrixElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kEdgeModeAttr ||
attr_name == svg_names::kDivisorAttr ||
attr_name == svg_names::kBiasAttr ||
@@ -224,7 +225,7 @@ void SVGFEConvolveMatrixElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEConvolveMatrixElement::Build(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
index 6542d6b6f0b..39dd9d22fcf 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
@@ -64,7 +64,7 @@ class SVGFEConvolveMatrixElement final
float ComputeDivisor() const;
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
index b508e9d947f..7def4c59460 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
@@ -122,7 +122,8 @@ bool SVGFEDiffuseLightingElement::SetFilterEffectAttribute(
}
void SVGFEDiffuseLightingElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kSurfaceScaleAttr ||
attr_name == svg_names::kDiffuseConstantAttr ||
attr_name == svg_names::kLightingColorAttr) {
@@ -137,7 +138,7 @@ void SVGFEDiffuseLightingElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
void SVGFEDiffuseLightingElement::LightElementAttributeChanged(
@@ -180,7 +181,7 @@ bool SVGFEDiffuseLightingElement::TaintsOrigin() const {
// TaintsOrigin() is only called after a successful call to Build()
// (see above), so we should have a ComputedStyle here.
DCHECK(style);
- return style->SvgStyle().LightingColor().IsCurrentColor();
+ return style->LightingColor().IsCurrentColor();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
index 56fa8bdf9b0..bcac4ab4b76 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
@@ -51,7 +51,7 @@ class SVGFEDiffuseLightingElement final
private:
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
index 9ac09aea930..705c21019d5 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
@@ -91,7 +91,8 @@ bool SVGFEDisplacementMapElement::SetFilterEffectAttribute(
}
void SVGFEDisplacementMapElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kXChannelSelectorAttr ||
attr_name == svg_names::kYChannelSelectorAttr ||
attr_name == svg_names::kScaleAttr) {
@@ -106,7 +107,7 @@ void SVGFEDisplacementMapElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEDisplacementMapElement::Build(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
index 7e648bfb15c..7ec641187bd 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
@@ -55,7 +55,7 @@ class SVGFEDisplacementMapElement final
private:
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
index 3e0d0060ac4..f7419497bc1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
@@ -21,7 +21,6 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_animated_number.h"
#include "third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h"
@@ -82,7 +81,7 @@ bool SVGFEDropShadowElement::SetFilterEffectAttribute(
return true;
}
if (attr_name == svg_names::kFloodOpacityAttr) {
- drop_shadow->SetShadowOpacity(style.SvgStyle().FloodOpacity());
+ drop_shadow->SetShadowOpacity(style.FloodOpacity());
return true;
}
return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -90,7 +89,8 @@ bool SVGFEDropShadowElement::SetFilterEffectAttribute(
}
void SVGFEDropShadowElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kInAttr ||
attr_name == svg_names::kStdDeviationAttr ||
attr_name == svg_names::kDxAttr || attr_name == svg_names::kDyAttr) {
@@ -99,7 +99,7 @@ void SVGFEDropShadowElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEDropShadowElement::Build(SVGFilterBuilder* filter_builder,
@@ -109,7 +109,7 @@ FilterEffect* SVGFEDropShadowElement::Build(SVGFilterBuilder* filter_builder,
return nullptr;
Color color = style->VisitedDependentColor(GetCSSPropertyFloodColor());
- float opacity = style->SvgStyle().FloodOpacity();
+ float opacity = style->FloodOpacity();
FilterEffect* input1 = filter_builder->GetEffectById(
AtomicString(in1_->CurrentValue()->Value()));
@@ -130,7 +130,7 @@ bool SVGFEDropShadowElement::TaintsOrigin() const {
// TaintsOrigin() is only called after a successful call to Build()
// (see above), so we should have a ComputedStyle here.
DCHECK(style);
- return style->SvgStyle().FloodColor().IsCurrentColor();
+ return style->FloodColor().IsCurrentColor();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
index b62b8c0538e..d56f7c1f15e 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
@@ -46,7 +46,7 @@ class SVGFEDropShadowElement final
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
index 37fc529ebb7..bb15c83377a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
@@ -22,7 +22,6 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/platform/graphics/filters/fe_flood.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -43,7 +42,7 @@ bool SVGFEFloodElement::SetFilterEffectAttribute(
style.VisitedDependentColor(GetCSSPropertyFloodColor()));
}
if (attr_name == svg_names::kFloodOpacityAttr)
- return flood->SetFloodOpacity(style.SvgStyle().FloodOpacity());
+ return flood->SetFloodOpacity(style.FloodOpacity());
return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
effect, attr_name);
@@ -55,7 +54,7 @@ FilterEffect* SVGFEFloodElement::Build(SVGFilterBuilder*, Filter* filter) {
return nullptr;
Color color = style->VisitedDependentColor(GetCSSPropertyFloodColor());
- float opacity = style->SvgStyle().FloodOpacity();
+ float opacity = style->FloodOpacity();
return MakeGarbageCollected<FEFlood>(filter, color, opacity);
}
@@ -65,7 +64,7 @@ bool SVGFEFloodElement::TaintsOrigin() const {
// TaintsOrigin() is only called after a successful call to Build()
// (see above), so we should have a ComputedStyle here.
DCHECK(style);
- return style->SvgStyle().FloodColor().IsCurrentColor();
+ return style->FloodColor().IsCurrentColor();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
index 092c7569848..9c628e90c1b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
@@ -62,7 +62,8 @@ void SVGFEGaussianBlurElement::Trace(Visitor* visitor) const {
}
void SVGFEGaussianBlurElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kInAttr ||
attr_name == svg_names::kStdDeviationAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
@@ -70,7 +71,7 @@ void SVGFEGaussianBlurElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEGaussianBlurElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
index 748c6b2c9c2..63858358e51 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
@@ -45,7 +45,7 @@ class SVGFEGaussianBlurElement final
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
index aa571841c32..119fcf85529 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
@@ -114,7 +114,9 @@ void SVGFEImageElement::BuildPendingResource() {
Invalidate();
}
-void SVGFEImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGFEImageElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kPreserveAspectRatioAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
Invalidate();
@@ -127,7 +129,7 @@ void SVGFEImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
Node::InsertionNotificationRequest SVGFEImageElement::InsertedInto(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
index 2e6e334e529..0f93691f80c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_image_element.h
@@ -54,7 +54,7 @@ class SVGFEImageElement final : public SVGFilterPrimitiveStandardAttributes,
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ImageNotifyFinished(ImageResourceContent*) override;
String DebugName() const override { return "SVGFEImageElement"; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
index 041e19c6c6e..e43d0521863 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
@@ -113,7 +113,9 @@ FloatPoint3D SVGFELightElement::PointsAt() const {
pointsAtZ()->CurrentValue()->Value());
}
-void SVGFELightElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGFELightElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kAzimuthAttr ||
attr_name == svg_names::kElevationAttr ||
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
@@ -140,7 +142,7 @@ void SVGFELightElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
void SVGFELightElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.h
index d03447757cc..2af96ad62de 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_light_element.h
@@ -71,7 +71,7 @@ class SVGFELightElement : public SVGElement {
SVGFELightElement(const QualifiedName&, Document&);
private:
- void SvgAttributeChanged(const QualifiedName&) final;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) final;
void ChildrenChanged(const ChildrenChange&) final;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
index 4dffd34f07a..9b161fecf2f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
@@ -38,14 +38,14 @@ void SVGFEMergeNodeElement::Trace(Visitor* visitor) const {
}
void SVGFEMergeNodeElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
- if (attr_name == svg_names::kInAttr) {
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kInAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
InvalidateFilterPrimitiveParent(*this);
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
index a45c205dec0..eb29bff9b42 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
@@ -39,7 +39,7 @@ class SVGFEMergeNodeElement final : public SVGElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
return false;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
index 2e2831f706d..09602876d82 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
@@ -90,7 +90,8 @@ bool SVGFEMorphologyElement::SetFilterEffectAttribute(
}
void SVGFEMorphologyElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kOperatorAttr ||
attr_name == svg_names::kRadiusAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
@@ -104,7 +105,7 @@ void SVGFEMorphologyElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEMorphologyElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
index b2b6856da7d..8c579ff8c8b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
@@ -50,7 +50,7 @@ class SVGFEMorphologyElement final
private:
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
index d385252d861..200e12e1a64 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
@@ -50,7 +50,9 @@ void SVGFEOffsetElement::Trace(Visitor* visitor) const {
SVGFilterPrimitiveStandardAttributes::Trace(visitor);
}
-void SVGFEOffsetElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGFEOffsetElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kInAttr || attr_name == svg_names::kDxAttr ||
attr_name == svg_names::kDyAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
@@ -58,7 +60,7 @@ void SVGFEOffsetElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFEOffsetElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
index c991d38a30e..b72050e6bc2 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
@@ -41,7 +41,7 @@ class SVGFEOffsetElement final : public SVGFilterPrimitiveStandardAttributes {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
index eed9a0ed766..8f542156f7f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
@@ -133,7 +133,8 @@ bool SVGFESpecularLightingElement::SetFilterEffectAttribute(
}
void SVGFESpecularLightingElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kSurfaceScaleAttr ||
attr_name == svg_names::kSpecularConstantAttr ||
attr_name == svg_names::kSpecularExponentAttr) {
@@ -148,7 +149,7 @@ void SVGFESpecularLightingElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
void SVGFESpecularLightingElement::LightElementAttributeChanged(
@@ -193,7 +194,7 @@ bool SVGFESpecularLightingElement::TaintsOrigin() const {
// TaintsOrigin() is only called after a successful call to Build()
// (see above), so we should have a ComputedStyle here.
DCHECK(style);
- return style->SvgStyle().LightingColor().IsCurrentColor();
+ return style->LightingColor().IsCurrentColor();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
index a22b45c5c85..b12a250b310 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
@@ -52,7 +52,7 @@ class SVGFESpecularLightingElement final
private:
bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
index fa21f4943e8..60fe3d7bed0 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
@@ -39,14 +39,15 @@ void SVGFETileElement::Trace(Visitor* visitor) const {
SVGFilterPrimitiveStandardAttributes::Trace(visitor);
}
-void SVGFETileElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (attr_name == svg_names::kInAttr) {
+void SVGFETileElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kInAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
Invalidate();
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFETileElement::Build(SVGFilterBuilder* filter_builder,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
index faa7e913b47..e7a2b107ca1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
@@ -37,7 +37,7 @@ class SVGFETileElement final : public SVGFilterPrimitiveStandardAttributes {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
bool TaintsOrigin() const override { return false; }
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
index c15a08d1c4e..101c777bc31 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
@@ -122,7 +122,8 @@ bool SVGFETurbulenceElement::SetFilterEffectAttribute(
}
void SVGFETurbulenceElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kBaseFrequencyAttr ||
attr_name == svg_names::kNumOctavesAttr ||
attr_name == svg_names::kSeedAttr ||
@@ -133,7 +134,7 @@ void SVGFETurbulenceElement::SvgAttributeChanged(
return;
}
- SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
+ SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(params);
}
FilterEffect* SVGFETurbulenceElement::Build(SVGFilterBuilder*, Filter* filter) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
index ca35f467f80..c9af3729511 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
@@ -66,7 +66,7 @@ class SVGFETurbulenceElement final
private:
bool SetFilterEffectAttribute(FilterEffect*,
const QualifiedName& attr_name) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
FilterEffect* Build(SVGFilterBuilder*, Filter*) override;
Member<SVGAnimatedNumberOptionalNumber> base_frequency_;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.cc
index a27e517916c..d1925a7cfd7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.cc
@@ -89,7 +89,9 @@ void SVGFilterElement::Trace(Visitor* visitor) const {
SVGURIReference::Trace(visitor);
}
-void SVGFilterElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGFilterElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool is_xywh =
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
@@ -103,7 +105,7 @@ void SVGFilterElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
LocalSVGResource* SVGFilterElement::AssociatedResource() const {
@@ -119,10 +121,8 @@ void SVGFilterElement::PrimitiveAttributeChanged(
}
void SVGFilterElement::InvalidateFilterChain() {
- if (LocalSVGResource* resource = AssociatedResource()) {
- resource->NotifyContentChanged(SVGResourceClient::kPaintInvalidation |
- SVGResourceClient::kFilterCacheInvalidation);
- }
+ if (LocalSVGResource* resource = AssociatedResource())
+ resource->NotifyContentChanged();
}
void SVGFilterElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
index b622704ddaa..f98ad53de48 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_filter_element.h
@@ -68,7 +68,7 @@ class CORE_EXPORT SVGFilterElement final : public SVGElement,
LocalSVGResource* AssociatedResource() const;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ChildrenChanged(const ChildrenChange&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc b/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
index c6bd88dd2ad..6bf7616c4cb 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
@@ -86,7 +86,7 @@ bool SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
DCHECK(attr_name == svg_names::kColorInterpolationFiltersAttr);
DCHECK(GetLayoutObject());
EColorInterpolation color_interpolation =
- GetLayoutObject()->StyleRef().SvgStyle().ColorInterpolationFilters();
+ GetLayoutObject()->StyleRef().ColorInterpolationFilters();
InterpolationSpace resolved_interpolation_space =
SVGFilterBuilder::ResolveInterpolationSpace(color_interpolation);
if (resolved_interpolation_space == effect->OperatingInterpolationSpace())
@@ -96,7 +96,8 @@ bool SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
}
void SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr ||
attr_name == svg_names::kHeightAttr ||
@@ -106,7 +107,7 @@ void SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
void SVGFilterPrimitiveStandardAttributes::ChildrenChanged(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h b/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h
index 9a3b046df23..834ba63f99c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h
@@ -64,7 +64,7 @@ class SVGFilterPrimitiveStandardAttributes : public SVGElement {
protected:
SVGFilterPrimitiveStandardAttributes(const QualifiedName&, Document&);
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ChildrenChanged(const ChildrenChange&) override;
private:
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
index ed8b645225d..17963047e0b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
@@ -97,7 +97,8 @@ void SVGForeignObjectElement::CollectStyleForPresentationAttribute(
}
void SVGForeignObjectElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool is_width_height_attribute =
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
bool is_xy_attribute =
@@ -121,7 +122,7 @@ void SVGForeignObjectElement::SvgAttributeChanged(
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
LayoutObject* SVGForeignObjectElement::CreateLayoutObject(const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
index e5b14175498..44ab35e6cf1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
@@ -45,7 +45,7 @@ class SVGForeignObjectElement final : public SVGGraphicsElement {
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.cc
index 1b681771049..4a54d968a7b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -65,7 +65,9 @@ SVGGeometryElement::SVGGeometryElement(const QualifiedName& tag_name,
AddToPropertyMap(path_length_);
}
-void SVGGeometryElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGGeometryElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kPathLengthAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
if (LayoutObject* layout_object = GetLayoutObject())
@@ -73,7 +75,7 @@ void SVGGeometryElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
void SVGGeometryElement::Trace(Visitor* visitor) const {
@@ -92,7 +94,7 @@ bool SVGGeometryElement::isPointInFill(SVGPointTearOff* point) const {
return false;
// Path::Contains will reject points with a non-finite component.
- WindRule fill_rule = layout_object->StyleRef().SvgStyle().FillRule();
+ WindRule fill_rule = layout_object->StyleRef().FillRule();
return AsPath().Contains(point->Target()->Value(), fill_rule);
}
@@ -138,7 +140,7 @@ Path SVGGeometryElement::ToClipPath() const {
DCHECK(GetLayoutObject());
DCHECK(GetLayoutObject()->Style());
- path.SetWindRule(GetLayoutObject()->StyleRef().SvgStyle().ClipRule());
+ path.SetWindRule(GetLayoutObject()->StyleRef().ClipRule());
return path;
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.h b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.h
index c13b1b981cb..24f9dc56453 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_geometry_element.h
@@ -66,7 +66,7 @@ class SVGGeometryElement : public SVGGraphicsElement {
Document&,
ConstructionType = kCreateSVGElement);
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void GeometryAttributeChanged();
void GeometryPresentationAttributeChanged(const QualifiedName&);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.cc
index 0491c328ee1..872e185635c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.cc
@@ -107,7 +107,9 @@ void SVGGradientElement::CollectStyleForPresentationAttribute(
SVGElement::CollectStyleForPresentationAttribute(name, value, style);
}
-void SVGGradientElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGGradientElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kGradientTransformAttr) {
InvalidateSVGPresentationAttributeStyle();
SetNeedsStyleRecalc(kLocalStyleChange,
@@ -128,7 +130,7 @@ void SVGGradientElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
Node::InsertionNotificationRequest SVGGradientElement::InsertedInto(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.h b/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.h
index b3cb4160e5a..b2652df04b7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_gradient_element.h
@@ -71,7 +71,7 @@ class SVGGradientElement : public SVGElement, public SVGURIReference {
using VisitedSet = HeapHashSet<Member<const SVGGradientElement>>;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
private:
void CollectStyleForPresentationAttribute(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.cc
index 220ed53b6c8..314fa308f8a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.cc
@@ -127,7 +127,9 @@ AffineTransform* SVGGraphicsElement::AnimateMotionTransform() {
return EnsureSVGRareData()->AnimateMotionTransform();
}
-void SVGGraphicsElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGGraphicsElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
// Reattach so the isValid() check will be run again during layoutObject
// creation.
if (SVGTests::IsKnownAttribute(attr_name)) {
@@ -150,7 +152,7 @@ void SVGGraphicsElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
SVGElement* SVGGraphicsElement::nearestViewportElement() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.h b/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.h
index fbc8b4e3d0b..3a85b4de254 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_graphics_element.h
@@ -77,7 +77,7 @@ class CORE_EXPORT SVGGraphicsElement : public SVGElement, public SVGTests {
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
Member<SVGAnimatedTransformList> transform_;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_image_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_image_element.cc
index 7f1b0b4f127..043760b59ba 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -131,7 +131,9 @@ void SVGImageElement::CollectStyleForPresentationAttribute(
}
}
-void SVGImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGImageElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool is_length_attribute =
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
@@ -165,7 +167,7 @@ void SVGImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
void SVGImageElement::ParseAttribute(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_image_element.h b/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
index 240a54bfb9f..5dcd827a0fb 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_image_element.h
@@ -84,7 +84,7 @@ class CORE_EXPORT SVGImageElement final
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ParseAttribute(const AttributeModificationParams&) override;
void AttachLayoutTree(AttachContext&) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_length.cc b/chromium/third_party/blink/renderer/core/svg/svg_length.cc
index fc137aabc4c..ff760af7a5f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_length.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_length.cc
@@ -179,15 +179,6 @@ float SVGLength::ValueAsPercentage() const {
return value_->GetFloatValue();
}
-float SVGLength::ValueAsPercentage100() const {
- // LengthTypePercentage is represented with 100% = 100.0. Good for accuracy
- // but could eventually be changed.
- if (value_->IsPercentage())
- return value_->GetFloatValue();
-
- return value_->GetFloatValue() * 100;
-}
-
float SVGLength::ScaleByPercentage(float input) const {
float result = input * value_->GetFloatValue();
if (value_->IsPercentage()) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_length.h b/chromium/third_party/blink/renderer/core/svg/svg_length.h
index 8fbdf7e896e..d23594f3668 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_length.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_length.h
@@ -92,9 +92,6 @@ class CORE_EXPORT SVGLength final : public SVGListablePropertyBase {
// value is 1.0).
float ValueAsPercentage() const;
- // Returns a number to be used as percentage (so full value is 100)
- float ValueAsPercentage100() const;
-
// Scale the input value by this SVGLength. Higher precision than input *
// valueAsPercentage().
float ScaleByPercentage(float) const;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_length_context.cc b/chromium/third_party/blink/renderer/core/svg/svg_length_context.cc
index bcff11845c6..b4d12cdf9e9 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_length_context.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_length_context.cc
@@ -50,11 +50,10 @@ static inline float DimensionForLengthMode(SVGLengthMode mode,
return 0;
}
-static float ConvertValueFromPercentageToUserUnits(
- const SVGLength& value,
- const FloatSize& viewport_size) {
- return CSSPrimitiveValue::ClampToCSSLengthRange(value.ScaleByPercentage(
- DimensionForLengthMode(value.UnitMode(), viewport_size)));
+static float ConvertValueFromPercentageToUserUnits(const SVGLength& value,
+ float viewport_dimension) {
+ return CSSPrimitiveValue::ClampToCSSLengthRange(
+ value.ScaleByPercentage(viewport_dimension));
}
static const ComputedStyle* ComputedStyleForLengthResolving(
@@ -168,12 +167,13 @@ FloatRect SVGLengthContext::ResolveRectangle(const SVGElement* context,
const SVGLength& height) {
DCHECK_NE(SVGUnitTypes::kSvgUnitTypeUnknown, type);
if (type != SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
- const FloatSize& viewport_size = viewport.Size();
return FloatRect(
- ConvertValueFromPercentageToUserUnits(x, viewport_size) + viewport.X(),
- ConvertValueFromPercentageToUserUnits(y, viewport_size) + viewport.Y(),
- ConvertValueFromPercentageToUserUnits(width, viewport_size),
- ConvertValueFromPercentageToUserUnits(height, viewport_size));
+ ConvertValueFromPercentageToUserUnits(x, viewport.Width()) +
+ viewport.X(),
+ ConvertValueFromPercentageToUserUnits(y, viewport.Height()) +
+ viewport.Y(),
+ ConvertValueFromPercentageToUserUnits(width, viewport.Width()),
+ ConvertValueFromPercentageToUserUnits(height, viewport.Height()));
}
SVGLengthContext length_context(context);
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_line_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_line_element.cc
index cc8ef9c8364..633655d5937 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_line_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_line_element.cc
@@ -78,7 +78,9 @@ Path SVGLineElement::AsPath() const {
return path;
}
-void SVGLineElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGLineElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kX1Attr || attr_name == svg_names::kY1Attr ||
attr_name == svg_names::kX2Attr || attr_name == svg_names::kY2Attr) {
UpdateRelativeLengthsInformation();
@@ -86,7 +88,7 @@ void SVGLineElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGeometryElement::SvgAttributeChanged(attr_name);
+ SVGGeometryElement::SvgAttributeChanged(params);
}
bool SVGLineElement::SelfHasRelativeLengths() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_line_element.h b/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
index d4cc8a4eee1..72f49ec77ce 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_line_element.h
@@ -44,7 +44,7 @@ class SVGLineElement final : public SVGGeometryElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool SelfHasRelativeLengths() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
index 8299e39a596..b050ac450be 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
@@ -72,7 +72,8 @@ void SVGLinearGradientElement::Trace(Visitor* visitor) const {
}
void SVGLinearGradientElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kX1Attr || attr_name == svg_names::kX2Attr ||
attr_name == svg_names::kY1Attr || attr_name == svg_names::kY2Attr) {
SVGElement::InvalidationGuard invalidation_guard(this);
@@ -81,7 +82,7 @@ void SVGLinearGradientElement::SvgAttributeChanged(
return;
}
- SVGGradientElement::SvgAttributeChanged(attr_name);
+ SVGGradientElement::SvgAttributeChanged(params);
}
LayoutObject* SVGLinearGradientElement::CreateLayoutObject(const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
index 70879d11370..fbd14b1f763 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
@@ -46,7 +46,7 @@ class SVGLinearGradientElement final : public SVGGradientElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.cc
index 33cb7d15953..1018203353b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.cc
@@ -105,7 +105,9 @@ AffineTransform SVGMarkerElement::ViewBoxToViewTransform(
viewport_size);
}
-void SVGMarkerElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGMarkerElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool viewbox_attribute_changed = SVGFitToViewBox::IsKnownAttribute(attr_name);
bool length_attribute_changed = attr_name == svg_names::kRefXAttr ||
attr_name == svg_names::kRefYAttr ||
@@ -131,7 +133,7 @@ void SVGMarkerElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
void SVGMarkerElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
index 69c3a29c033..c3c41b0dfd5 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_marker_element.h
@@ -77,7 +77,7 @@ class SVGMarkerElement final : public SVGElement, public SVGFitToViewBox {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ChildrenChanged(const ChildrenChange&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.cc
index a869de157b4..2af1739dcc7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.cc
@@ -112,7 +112,9 @@ void SVGMaskElement::CollectStyleForPresentationAttribute(
}
}
-void SVGMaskElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGMaskElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool is_length_attr =
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
@@ -137,7 +139,7 @@ void SVGMaskElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
void SVGMaskElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
index 7285ac80435..f008ac7a1cb 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mask_element.h
@@ -56,7 +56,7 @@ class SVGMaskElement final : public SVGElement, public SVGTests {
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void ChildrenChanged(const ChildrenChange&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.cc
index a626d40594c..87844bdd6df 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.cc
@@ -72,14 +72,15 @@ void SVGMPathElement::RemovedFrom(ContainerNode& root_parent) {
ClearResourceReferences();
}
-void SVGMPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (SVGURIReference::IsKnownAttribute(attr_name)) {
+void SVGMPathElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (SVGURIReference::IsKnownAttribute(params.name)) {
SVGElement::InvalidationGuard invalidation_guard(this);
BuildPendingResource();
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
SVGPathElement* SVGMPathElement::PathElement() {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
index d64628cf588..9db6ca2a531 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_mpath_element.h
@@ -46,7 +46,7 @@ class SVGMPathElement final : public SVGElement, public SVGURIReference {
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
return false;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_parser_utilities.h b/chromium/third_party/blink/renderer/core/svg/svg_parser_utilities.h
index 43c737704a7..a18f2dcb5a4 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_parser_utilities.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_parser_utilities.h
@@ -60,7 +60,7 @@ inline bool SkipOptionalSVGSpacesOrDelimiter(const CharType*& ptr,
if (ptr < end && !IsHTMLSpace<CharType>(*ptr) && *ptr != delimiter)
return false;
if (SkipOptionalSVGSpaces(ptr, end)) {
- if (ptr < end && *ptr == delimiter) {
+ if (*ptr == delimiter) {
ptr++;
SkipOptionalSVGSpaces(ptr, end);
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_path.cc b/chromium/third_party/blink/renderer/core/svg/svg_path.cc
index e2dd56c4509..dabcc69e9bf 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_path.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_path.cc
@@ -82,9 +82,7 @@ std::unique_ptr<SVGPathByteStream> ConditionallyAddPathByteStreams(
SVGPath::SVGPath() : path_value_(CSSPathValue::EmptyPathValue()) {}
-SVGPath::SVGPath(CSSPathValue* path_value) : path_value_(path_value) {
- DCHECK(path_value_);
-}
+SVGPath::SVGPath(const CSSPathValue& path_value) : path_value_(path_value) {}
SVGPath::~SVGPath() = default;
@@ -93,7 +91,7 @@ String SVGPath::ValueAsString() const {
}
SVGPath* SVGPath::Clone() const {
- return MakeGarbageCollected<SVGPath>(path_value_);
+ return MakeGarbageCollected<SVGPath>(*path_value_);
}
SVGParsingError SVGPath::SetValueAsString(const String& string) {
@@ -110,7 +108,7 @@ SVGPropertyBase* SVGPath::CloneForAnimation(const String& value) const {
std::make_unique<SVGPathByteStream>();
BuildByteStreamFromString(value, *byte_stream);
return MakeGarbageCollected<SVGPath>(
- MakeGarbageCollected<CSSPathValue>(std::move(byte_stream)));
+ *MakeGarbageCollected<CSSPathValue>(std::move(byte_stream)));
}
void SVGPath::Add(const SVGPropertyBase* other, const SVGElement*) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_path.h b/chromium/third_party/blink/renderer/core/svg/svg_path.h
index 481529cb2de..f185337040c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_path.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_path.h
@@ -44,14 +44,14 @@ class SVGPath final : public SVGPropertyBase {
typedef void TearOffType;
SVGPath();
- explicit SVGPath(cssvalue::CSSPathValue*);
+ explicit SVGPath(const cssvalue::CSSPathValue&);
~SVGPath() override;
const SVGPathByteStream& ByteStream() const {
return path_value_->ByteStream();
}
StylePath* GetStylePath() const { return path_value_->GetStylePath(); }
- cssvalue::CSSPathValue* PathValue() const { return path_value_.Get(); }
+ const cssvalue::CSSPathValue& PathValue() const { return *path_value_; }
// SVGPropertyBase:
SVGPath* Clone() const;
@@ -77,7 +77,7 @@ class SVGPath final : public SVGPropertyBase {
void Trace(Visitor*) const override;
private:
- Member<cssvalue::CSSPathValue> path_value_;
+ Member<const cssvalue::CSSPathValue> path_value_;
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_path_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_path_element.cc
index b15ea5f1f12..2d7aa59da7f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_path_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_path_element.cc
@@ -50,8 +50,7 @@ Path SVGPathElement::AttributePath() const {
const StylePath* SVGPathElement::GetStylePath() const {
if (const ComputedStyle* style = GetComputedStyle()) {
- const StylePath* style_path = style->SvgStyle().D();
- if (style_path)
+ if (const StylePath* style_path = style->D())
return style_path;
return StylePath::EmptyPath();
}
@@ -101,14 +100,16 @@ SVGPointTearOff* SVGPathElement::getPointAtLength(
return SVGPointTearOff::CreateDetached(point);
}
-void SVGPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGPathElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kDAttr) {
InvalidateMPathDependencies();
GeometryPresentationAttributeChanged(attr_name);
return;
}
- SVGGeometryElement::SvgAttributeChanged(attr_name);
+ SVGGeometryElement::SvgAttributeChanged(params);
}
void SVGPathElement::CollectStyleForPresentationAttribute(
@@ -155,7 +156,7 @@ void SVGPathElement::RemovedFrom(ContainerNode& root_parent) {
FloatRect SVGPathElement::GetBBox() {
// We want the exact bounds.
- return SVGPathElement::AsPath().BoundingRect();
+ return SVGPathElement::AsPath().TightBoundingRect();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
index 1c728218d8f..e29d2f672f1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_path_element.h
@@ -53,7 +53,7 @@ class SVGPathElement final : public SVGGeometryElement {
private:
const StylePath* GetStylePath() const;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void CollectStyleForPresentationAttribute(
const QualifiedName&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.cc
index f19aa7eefc2..dc182528cc8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.cc
@@ -24,16 +24,13 @@
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/svg/pattern_attributes.h"
#include "third_party/blink/renderer/core/svg/svg_animated_length.h"
#include "third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h"
#include "third_party/blink/renderer/core/svg/svg_animated_rect.h"
#include "third_party/blink/renderer/core/svg/svg_animated_transform_list.h"
-#include "third_party/blink/renderer/core/svg/svg_resource.h"
-#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
@@ -95,7 +92,7 @@ void SVGPatternElement::Trace(Visitor* visitor) const {
visitor->Trace(pattern_transform_);
visitor->Trace(pattern_units_);
visitor->Trace(pattern_content_units_);
- visitor->Trace(resource_);
+ visitor->Trace(target_id_observer_);
SVGElement::Trace(visitor);
SVGURIReference::Trace(visitor);
SVGTests::Trace(visitor);
@@ -106,28 +103,16 @@ void SVGPatternElement::BuildPendingResource() {
ClearResourceReferences();
if (!isConnected())
return;
- TreeScope& tree_scope = GetTreeScope();
- SVGTreeScopeResources& tree_scope_resources =
- tree_scope.EnsureSVGTreeScopedResources();
- resource_ = tree_scope_resources.ResourceForId(
- FragmentIdentifierFromIRIString(HrefString(), tree_scope));
- if (resource_)
- resource_->AddClient(EnsureSVGResourceClient());
+ Element* target = ObserveTarget(target_id_observer_, *this);
+ if (auto* pattern = DynamicTo<SVGPatternElement>(target))
+ AddReferenceTo(pattern);
InvalidatePattern(layout_invalidation_reason::kSvgResourceInvalidated);
- if (auto* layout_object = GetLayoutObject()) {
- if (!layout_object->Parent())
- return;
- SVGResourcesCache::UpdateResources(*layout_object);
- InvalidateDependentPatterns();
- }
}
void SVGPatternElement::ClearResourceReferences() {
- if (!resource_)
- return;
- resource_->RemoveClient(*GetSVGResourceClient());
- resource_ = nullptr;
+ UnobserveTarget(target_id_observer_);
+ RemoveAllOutgoingReferences();
}
void SVGPatternElement::CollectStyleForPresentationAttribute(
@@ -143,7 +128,9 @@ void SVGPatternElement::CollectStyleForPresentationAttribute(
SVGElement::CollectStyleForPresentationAttribute(name, value, style);
}
-void SVGPatternElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGPatternElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool is_length_attr =
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
@@ -174,7 +161,7 @@ void SVGPatternElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
Node::InsertionNotificationRequest SVGPatternElement::InsertedInto(
@@ -263,8 +250,8 @@ static void SetPatternAttributes(const SVGPatternElement& element,
}
const SVGPatternElement* SVGPatternElement::ReferencedElement() const {
- return DynamicTo<SVGPatternElement>(resource_ ? resource_->Target()
- : nullptr);
+ return DynamicTo<SVGPatternElement>(
+ TargetElementFromIRIString(HrefString(), GetTreeScope()));
}
void SVGPatternElement::CollectPatternAttributes(
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
index 8c099f2d944..4458010a7c7 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_pattern_element.h
@@ -35,7 +35,6 @@ namespace blink {
class PatternAttributes;
class SVGAnimatedLength;
class SVGAnimatedTransformList;
-class SVGResource;
class SVGPatternElement final : public SVGElement,
public SVGURIReference,
@@ -90,7 +89,7 @@ class SVGPatternElement final : public SVGElement,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) final;
void RemovedFrom(ContainerNode&) final;
void ChildrenChanged(const ChildrenChange&) override;
@@ -110,7 +109,7 @@ class SVGPatternElement final : public SVGElement,
Member<SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>> pattern_units_;
Member<SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>>
pattern_content_units_;
- Member<SVGResource> resource_;
+ Member<IdTargetObserver> target_id_observer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_point.cc b/chromium/third_party/blink/renderer/core/svg/svg_point.cc
index 5209e5e5817..73759127947 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_point.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_point.cc
@@ -30,10 +30,7 @@
#include "third_party/blink/renderer/core/svg/svg_point.h"
-#include "third_party/blink/renderer/core/svg/svg_parser_utilities.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
-#include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -53,40 +50,6 @@ SVGPropertyBase* SVGPoint::CloneForAnimation(const String& value) const {
return nullptr;
}
-template <typename CharType>
-SVGParsingError SVGPoint::Parse(const CharType* ptr, const CharType* end) {
- float x = 0;
- float y = 0;
- if (!ParseNumber(ptr, end, x) ||
- !ParseNumber(ptr, end, y, kDisallowWhitespace))
- return SVGParseStatus::kExpectedNumber;
-
- if (SkipOptionalSVGSpaces(ptr, end)) {
- // Nothing should come after the second number.
- return SVGParseStatus::kTrailingGarbage;
- }
-
- value_ = FloatPoint(x, y);
- return SVGParseStatus::kNoError;
-}
-
-FloatPoint SVGPoint::MatrixTransform(const AffineTransform& transform) const {
- double new_x, new_y;
- transform.Map(static_cast<double>(X()), static_cast<double>(Y()), new_x,
- new_y);
- return FloatPoint::NarrowPrecision(new_x, new_y);
-}
-
-SVGParsingError SVGPoint::SetValueAsString(const String& string) {
- if (string.IsEmpty()) {
- value_ = FloatPoint(0.0f, 0.0f);
- return SVGParseStatus::kNoError;
- }
- return WTF::VisitCharacters(string, [&](const auto* chars, unsigned length) {
- return Parse(chars, chars + length);
- });
-}
-
String SVGPoint::ValueAsString() const {
StringBuilder builder;
builder.AppendNumber(X());
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_point.h b/chromium/third_party/blink/renderer/core/svg/svg_point.h
index 81446fd5065..c59918b7021 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_point.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_point.h
@@ -32,13 +32,11 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_POINT_H_
#include "third_party/blink/renderer/core/svg/properties/svg_listable_property.h"
-#include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
#include "third_party/blink/renderer/platform/geometry/float_point.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
-class AffineTransform;
class SVGPointTearOff;
class SVGPoint final : public SVGListablePropertyBase {
@@ -59,10 +57,7 @@ class SVGPoint final : public SVGListablePropertyBase {
void SetX(float f) { value_.SetX(f); }
void SetY(float f) { value_.SetY(f); }
- FloatPoint MatrixTransform(const AffineTransform&) const;
-
String ValueAsString() const override;
- SVGParsingError SetValueAsString(const String&);
void Add(const SVGPropertyBase*, const SVGElement*) override;
void CalculateAnimatedValue(
@@ -80,9 +75,6 @@ class SVGPoint final : public SVGListablePropertyBase {
AnimatedPropertyType GetType() const override { return ClassType(); }
private:
- template <typename CharType>
- SVGParsingError Parse(const CharType* ptr, const CharType* end);
-
FloatPoint value_;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_point_tear_off.cc b/chromium/third_party/blink/renderer/core/svg/svg_point_tear_off.cc
index afd2aab4a95..fbe6a386484 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_point_tear_off.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_point_tear_off.cc
@@ -62,8 +62,7 @@ void SVGPointTearOff::setY(float f, ExceptionState& exception_state) {
}
SVGPointTearOff* SVGPointTearOff::matrixTransform(SVGMatrixTearOff* matrix) {
- FloatPoint point = Target()->MatrixTransform(matrix->Value());
- return CreateDetached(point);
+ return CreateDetached(matrix->Value().MapPoint(Target()->Value()));
}
SVGPointTearOff* SVGPointTearOff::CreateDetached(const FloatPoint& point) {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_poly_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_poly_element.cc
index b64f401cd51..055be1276d1 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_poly_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_poly_element.cc
@@ -70,13 +70,14 @@ Path SVGPolyElement::AsPathFromPoints() const {
return path;
}
-void SVGPolyElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (attr_name == svg_names::kPointsAttr) {
+void SVGPolyElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kPointsAttr) {
GeometryAttributeChanged();
return;
}
- SVGGeometryElement::SvgAttributeChanged(attr_name);
+ SVGGeometryElement::SvgAttributeChanged(params);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_poly_element.h b/chromium/third_party/blink/renderer/core/svg/svg_poly_element.h
index b2b29665aaf..01adc73c24f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_poly_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_poly_element.h
@@ -45,9 +45,8 @@ class SVGPolyElement : public SVGGeometryElement {
Path AsPathFromPoints() const;
private:
- void SvgAttributeChanged(const QualifiedName&) final;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) final;
- private:
Member<SVGAnimatedPointList> points_;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
index e5d53637f1e..7cc27ba8bb0 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
@@ -85,7 +85,8 @@ void SVGRadialGradientElement::Trace(Visitor* visitor) const {
}
void SVGRadialGradientElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kCxAttr || attr_name == svg_names::kCyAttr ||
attr_name == svg_names::kFxAttr || attr_name == svg_names::kFyAttr ||
attr_name == svg_names::kRAttr || attr_name == svg_names::kFrAttr) {
@@ -95,7 +96,7 @@ void SVGRadialGradientElement::SvgAttributeChanged(
return;
}
- SVGGradientElement::SvgAttributeChanged(attr_name);
+ SVGGradientElement::SvgAttributeChanged(params);
}
LayoutObject* SVGRadialGradientElement::CreateLayoutObject(const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
index 537352723fb..feeb533c334 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
@@ -48,7 +48,7 @@ class SVGRadialGradientElement final : public SVGGradientElement {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.cc
index a0435766f69..8f48e0dc108 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.cc
@@ -96,16 +96,14 @@ Path SVGRectElement::AsPath() const {
(!size.Width() && !size.Height()))
return path;
- const SVGComputedStyle& svg_style = style.SvgStyle();
- FloatRect rect(
- length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
- size);
+ FloatRect rect(length_context.ResolveLengthPair(style.X(), style.Y(), style),
+ size);
FloatPoint radii(
- length_context.ResolveLengthPair(svg_style.Rx(), svg_style.Ry(), style));
+ length_context.ResolveLengthPair(style.Rx(), style.Ry(), style));
if (radii.X() > 0 || radii.Y() > 0) {
- if (svg_style.Rx().IsAuto())
+ if (style.Rx().IsAuto())
radii.SetX(radii.Y());
- else if (svg_style.Ry().IsAuto())
+ else if (style.Ry().IsAuto())
radii.SetY(radii.X());
path.AddRoundedRect(rect, ToFloatSize(radii));
@@ -144,7 +142,9 @@ void SVGRectElement::CollectStyleForPresentationAttribute(
}
}
-void SVGRectElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGRectElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr ||
attr_name == svg_names::kHeightAttr || attr_name == svg_names::kRxAttr ||
@@ -154,7 +154,7 @@ void SVGRectElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGeometryElement::SvgAttributeChanged(attr_name);
+ SVGGeometryElement::SvgAttributeChanged(params);
}
bool SVGRectElement::SelfHasRelativeLengths() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
index 347186fd766..92954722ad8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_rect_element.h
@@ -50,7 +50,7 @@ class SVGRectElement final : public SVGGeometryElement {
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool SelfHasRelativeLengths() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource.cc b/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
index 15560f2550b..7782d55cadc 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource.cc
@@ -4,13 +4,17 @@
#include "third_party/blink/renderer/core/svg/svg_resource.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/tree_scope.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
+#include "third_party/blink/renderer/core/svg/svg_resource_document_content.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
namespace blink {
@@ -25,35 +29,97 @@ void SVGResource::Trace(Visitor* visitor) const {
}
void SVGResource::AddClient(SVGResourceClient& client) {
- clients_.insert(&client);
- if (LayoutSVGResourceContainer* container = ResourceContainer())
+ auto& entry = clients_.insert(&client, ClientEntry()).stored_value->value;
+ entry.count++;
+ entry.cached_cycle_check = kNeedCheck;
+ if (LayoutSVGResourceContainer* container = ResourceContainerNoCycleCheck())
container->ClearInvalidationMask();
}
void SVGResource::RemoveClient(SVGResourceClient& client) {
- if (!clients_.erase(&client))
+ auto it = clients_.find(&client);
+ DCHECK(it != clients_.end());
+ it->value.count--;
+ if (it->value.count)
return;
+ clients_.erase(it);
// The last instance of |client| was removed. Clear its entry in
// resource's cache.
- if (LayoutSVGResourceContainer* container = ResourceContainer())
+ if (LayoutSVGResourceContainer* container = ResourceContainerNoCycleCheck())
container->RemoveClientFromCache(client);
}
-void SVGResource::NotifyElementChanged() {
+void SVGResource::InvalidateCycleCache() {
+ for (auto& client_entry : clients_.Values())
+ client_entry.cached_cycle_check = kNeedCheck;
+}
+
+void SVGResource::NotifyContentChanged() {
+ InvalidateCycleCache();
+
HeapVector<Member<SVGResourceClient>> clients;
- CopyToVector(clients_, clients);
+ CopyKeysToVector(clients_, clients);
for (SVGResourceClient* client : clients)
- client->ResourceElementChanged();
+ client->ResourceContentChanged(this);
}
-LayoutSVGResourceContainer* SVGResource::ResourceContainer() const {
+LayoutSVGResourceContainer* SVGResource::ResourceContainerNoCycleCheck() const {
if (!target_)
return nullptr;
- LayoutObject* layout_object = target_->GetLayoutObject();
- if (!layout_object || !layout_object->IsSVGResourceContainer())
+ return DynamicTo<LayoutSVGResourceContainer>(target_->GetLayoutObject());
+}
+
+LayoutSVGResourceContainer* SVGResource::ResourceContainer(
+ SVGResourceClient& client) const {
+ auto it = clients_.find(&client);
+ if (it == clients_.end())
+ return nullptr;
+ auto* container = ResourceContainerNoCycleCheck();
+ if (!container)
return nullptr;
- return To<LayoutSVGResourceContainer>(layout_object);
+ ClientEntry& entry = it->value;
+ if (entry.cached_cycle_check == kNeedCheck) {
+ entry.cached_cycle_check = kPerformingCheck;
+ bool has_cycle = container->FindCycle();
+ DCHECK_EQ(entry.cached_cycle_check, kPerformingCheck);
+ entry.cached_cycle_check = has_cycle ? kHasCycle : kNoCycle;
+ }
+ if (entry.cached_cycle_check == kHasCycle)
+ return nullptr;
+ DCHECK_EQ(entry.cached_cycle_check, kNoCycle);
+ return container;
+}
+
+bool SVGResource::FindCycle(SVGResourceClient& client) const {
+ auto it = clients_.find(&client);
+ if (it == clients_.end())
+ return false;
+ auto* container = ResourceContainerNoCycleCheck();
+ if (!container)
+ return false;
+ ClientEntry& entry = it->value;
+ switch (entry.cached_cycle_check) {
+ case kNeedCheck: {
+ entry.cached_cycle_check = kPerformingCheck;
+ bool has_cycle = container->FindCycle();
+ DCHECK_EQ(entry.cached_cycle_check, kPerformingCheck);
+ // Update our cached state based on the result of FindCycle(), but don't
+ // signal a cycle since ResourceContainer() will consider the resource
+ // invalid if one is present, thus we break the cycle at this resource.
+ entry.cached_cycle_check = has_cycle ? kHasCycle : kNoCycle;
+ return false;
+ }
+ case kPerformingCheck:
+ // If we're on the current checking path, signal a cycle.
+ return true;
+ case kHasCycle:
+ case kNoCycle:
+ // We have a cached result, but don't signal a cycle since
+ // ResourceContainer() will consider the resource invalid if one is
+ // present.
+ return false;
+ }
}
LocalSVGResource::LocalSVGResource(TreeScope& tree_scope,
@@ -69,44 +135,14 @@ void LocalSVGResource::Unregister() {
SVGURIReference::UnobserveTarget(id_observer_);
}
-void LocalSVGResource::NotifyContentChanged(
- InvalidationModeMask invalidation_mask) {
- HeapVector<Member<SVGResourceClient>> clients;
- CopyToVector(clients_, clients);
-
- for (SVGResourceClient* client : clients)
- client->ResourceContentChanged(invalidation_mask);
-}
-
void LocalSVGResource::NotifyFilterPrimitiveChanged(
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
HeapVector<Member<SVGResourceClient>> clients;
- CopyToVector(clients_, clients);
+ CopyKeysToVector(clients_, clients);
for (SVGResourceClient* client : clients)
- client->FilterPrimitiveChanged(primitive, attribute);
-}
-
-void LocalSVGResource::NotifyResourceAttached(
- LayoutSVGResourceContainer& attached_resource) {
- // Checking the element here because
- if (attached_resource.GetElement() != Target())
- return;
- NotifyElementChanged();
-}
-
-void LocalSVGResource::NotifyResourceDestroyed(
- LayoutSVGResourceContainer& destroyed_resource) {
- if (destroyed_resource.GetElement() != Target())
- return;
- destroyed_resource.RemoveAllClientsFromCache();
-
- HeapVector<Member<SVGResourceClient>> clients;
- CopyToVector(clients_, clients);
-
- for (SVGResourceClient* client : clients)
- client->ResourceDestroyed(&destroyed_resource);
+ client->FilterPrimitiveChanged(this, primitive, attribute);
}
void LocalSVGResource::TargetChanged(const AtomicString& id) {
@@ -115,10 +151,11 @@ void LocalSVGResource::TargetChanged(const AtomicString& id) {
return;
// Clear out caches on the old resource, and then notify clients about the
// change.
- if (LayoutSVGResourceContainer* old_resource = ResourceContainer())
+ LayoutSVGResourceContainer* old_resource = ResourceContainerNoCycleCheck();
+ if (old_resource)
old_resource->RemoveAllClientsFromCache();
target_ = new_target;
- NotifyElementChanged();
+ NotifyContentChanged();
}
void LocalSVGResource::Trace(Visitor* visitor) const {
@@ -130,36 +167,47 @@ void LocalSVGResource::Trace(Visitor* visitor) const {
ExternalSVGResource::ExternalSVGResource(const KURL& url) : url_(url) {}
void ExternalSVGResource::Load(Document& document) {
- if (cache_entry_)
+ if (document_content_)
return;
- cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
- this, url_, fetch_initiator_type_names::kCSS);
+ ExecutionContext* execution_context = document.GetExecutionContext();
+ ResourceLoaderOptions options(execution_context->GetCurrentWorld());
+ options.initiator_info.name = fetch_initiator_type_names::kCSS;
+ FetchParameters params(ResourceRequest(url_), options);
+ document_content_ = SVGResourceDocumentContent::Fetch(params, document, this);
target_ = ResolveTarget();
}
void ExternalSVGResource::LoadWithoutCSP(Document& document) {
- if (cache_entry_)
+ if (document_content_)
return;
- cache_entry_ = SVGExternalDocumentCache::From(document)->Get(
- this, url_, fetch_initiator_type_names::kCSS,
+ ExecutionContext* execution_context = document.GetExecutionContext();
+ ResourceLoaderOptions options(execution_context->GetCurrentWorld());
+ options.initiator_info.name = fetch_initiator_type_names::kCSS;
+ FetchParameters params(ResourceRequest(url_), options);
+ params.SetContentSecurityCheck(
network::mojom::blink::CSPDisposition::DO_NOT_CHECK);
+ document_content_ = SVGResourceDocumentContent::Fetch(params, document, this);
target_ = ResolveTarget();
}
-void ExternalSVGResource::NotifyFinished(Document*) {
+void ExternalSVGResource::NotifyFinished(Resource*) {
Element* new_target = ResolveTarget();
if (new_target == target_)
return;
target_ = new_target;
- NotifyElementChanged();
+ NotifyContentChanged();
+}
+
+String ExternalSVGResource::DebugName() const {
+ return "ExternalSVGResource";
}
Element* ExternalSVGResource::ResolveTarget() {
- if (!cache_entry_)
+ if (!document_content_)
return nullptr;
if (!url_.HasFragmentIdentifier())
return nullptr;
- Document* external_document = cache_entry_->GetDocument();
+ Document* external_document = document_content_->GetDocument();
if (!external_document)
return nullptr;
AtomicString decoded_fragment(DecodeURLEscapeSequences(
@@ -168,9 +216,9 @@ Element* ExternalSVGResource::ResolveTarget() {
}
void ExternalSVGResource::Trace(Visitor* visitor) const {
- visitor->Trace(cache_entry_);
+ visitor->Trace(document_content_);
SVGResource::Trace(visitor);
- SVGExternalDocumentCache::Client::Trace(visitor);
+ ResourceClient::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource.h b/chromium/third_party/blink/renderer/core/svg/svg_resource.h
index 7a2006d5f95..7f591d7ce8c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_resource.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource.h
@@ -6,12 +6,10 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_H_
#include "base/macros.h"
-#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
-#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
@@ -20,6 +18,10 @@ class Document;
class Element;
class IdTargetObserver;
class LayoutSVGResourceContainer;
+class QualifiedName;
+class SVGFilterPrimitiveStandardAttributes;
+class SVGResourceClient;
+class SVGResourceDocumentContent;
class TreeScope;
// A class tracking a reference to an SVG resource (an element that constitutes
@@ -66,7 +68,16 @@ class SVGResource : public GarbageCollected<SVGResource> {
virtual void LoadWithoutCSP(Document&) {}
Element* Target() const { return target_; }
- LayoutSVGResourceContainer* ResourceContainer() const;
+ // Returns the target's LayoutObject (if target exists and is attached to the
+ // layout tree). Also perform cycle-checking, and may thus return nullptr if
+ // this SVGResourceClient -> SVGResource reference would start a cycle.
+ LayoutSVGResourceContainer* ResourceContainer(SVGResourceClient&) const;
+ // Same as the above, minus the cycle-checking.
+ LayoutSVGResourceContainer* ResourceContainerNoCycleCheck() const;
+ // Run cycle-checking for this SVGResourceClient -> SVGResource
+ // reference. Used internally by the cycle-checking, and shouldn't be called
+ // directly in general.
+ bool FindCycle(SVGResourceClient&) const;
void AddClient(SVGResourceClient&);
void RemoveClient(SVGResourceClient&);
@@ -76,10 +87,22 @@ class SVGResource : public GarbageCollected<SVGResource> {
protected:
SVGResource();
- void NotifyElementChanged();
+ void InvalidateCycleCache();
+ void NotifyContentChanged();
Member<Element> target_;
- HeapHashCountedSet<Member<SVGResourceClient>> clients_;
+
+ enum CycleState {
+ kNeedCheck,
+ kPerformingCheck,
+ kHasCycle,
+ kNoCycle,
+ };
+ struct ClientEntry {
+ int count = 0;
+ CycleState cached_cycle_check = kNeedCheck;
+ };
+ mutable HeapHashMap<Member<SVGResourceClient>, ClientEntry> clients_;
private:
DISALLOW_COPY_AND_ASSIGN(SVGResource);
@@ -92,14 +115,12 @@ class LocalSVGResource final : public SVGResource {
void Unregister();
- void NotifyContentChanged(InvalidationModeMask);
+ using SVGResource::NotifyContentChanged;
+
void NotifyFilterPrimitiveChanged(
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute);
- void NotifyResourceAttached(LayoutSVGResourceContainer&);
- void NotifyResourceDestroyed(LayoutSVGResourceContainer&);
-
void Trace(Visitor*) const override;
private:
@@ -110,8 +131,7 @@ class LocalSVGResource final : public SVGResource {
};
// External resource reference (see SVGResource.)
-class ExternalSVGResource final : public SVGResource,
- private SVGExternalDocumentCache::Client {
+class ExternalSVGResource final : public SVGResource, public ResourceClient {
public:
explicit ExternalSVGResource(const KURL&);
@@ -123,10 +143,11 @@ class ExternalSVGResource final : public SVGResource,
private:
Element* ResolveTarget();
- // SVGExternalDocumentCache::Client implementation
- void NotifyFinished(Document*) override;
+ // ResourceClient implementation
+ void NotifyFinished(Resource*) override;
+ String DebugName() const override;
- Member<SVGExternalDocumentCache::Entry> cache_entry_;
+ Member<SVGResourceDocumentContent> document_content_;
KURL url_;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource_client.h b/chromium/third_party/blink/renderer/core/svg/svg_resource_client.h
index 2783e52403a..634979f5363 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_resource_client.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource_client.h
@@ -6,38 +6,25 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_CLIENT_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
namespace blink {
-class LayoutSVGResourceContainer;
class QualifiedName;
class SVGFilterPrimitiveStandardAttributes;
-
-typedef unsigned InvalidationModeMask;
+class SVGResource;
class CORE_EXPORT SVGResourceClient : public GarbageCollectedMixin {
public:
virtual ~SVGResourceClient() = default;
- // When adding modes, make sure we don't overflow
- // |LayoutSVGResourceContainer::completed_invalidation_mask_|.
- enum InvalidationMode {
- kLayoutInvalidation = 1 << 0,
- kBoundariesInvalidation = 1 << 1,
- kPaintInvalidation = 1 << 2,
- kPaintPropertiesInvalidation = 1 << 3,
- kClipCacheInvalidation = 1 << 4,
- kFilterCacheInvalidation = 1 << 5,
- };
- virtual void ResourceContentChanged(InvalidationModeMask) = 0;
- virtual void ResourceElementChanged() = 0;
- virtual void ResourceDestroyed(LayoutSVGResourceContainer*) {}
+ virtual void ResourceContentChanged(SVGResource*) = 0;
virtual void FilterPrimitiveChanged(
+ SVGResource* resource,
SVGFilterPrimitiveStandardAttributes& primitive,
const QualifiedName& attribute) {
- ResourceContentChanged(kPaintInvalidation | kFilterCacheInvalidation);
+ ResourceContentChanged(resource);
}
protected:
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.cc b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.cc
new file mode 100644
index 00000000000..f0ea678369d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.cc
@@ -0,0 +1,158 @@
+/*
+ Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
+ Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
+ Copyright (C) 2012 University of Szeged
+ Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "third_party/blink/renderer/core/svg/svg_resource_document_content.h"
+
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/document_init.h"
+#include "third_party/blink/renderer/core/dom/xml_document.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/loader/resource/text_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+namespace {
+
+class SVGExternalDocumentCache final
+ : public GarbageCollected<SVGExternalDocumentCache>,
+ public Supplement<Document> {
+ public:
+ static const char kSupplementName[];
+ static SVGExternalDocumentCache* From(Document&);
+ explicit SVGExternalDocumentCache(Document&);
+
+ SVGResourceDocumentContent* Get(TextResource*);
+
+ void Trace(Visitor*) const override;
+
+ private:
+ HeapHashMap<WeakMember<Resource>, Member<SVGResourceDocumentContent>>
+ entries_;
+};
+
+const char SVGExternalDocumentCache::kSupplementName[] =
+ "SVGExternalDocumentCache";
+
+SVGExternalDocumentCache* SVGExternalDocumentCache::From(Document& document) {
+ SVGExternalDocumentCache* cache =
+ Supplement<Document>::From<SVGExternalDocumentCache>(document);
+ if (!cache) {
+ cache = MakeGarbageCollected<SVGExternalDocumentCache>(document);
+ Supplement<Document>::ProvideTo(document, cache);
+ }
+ return cache;
+}
+
+SVGExternalDocumentCache::SVGExternalDocumentCache(Document& document)
+ : Supplement<Document>(document) {}
+
+SVGResourceDocumentContent* SVGExternalDocumentCache::Get(
+ TextResource* resource) {
+ auto& entry = entries_.insert(resource, nullptr).stored_value->value;
+ if (!entry) {
+ entry = MakeGarbageCollected<SVGResourceDocumentContent>(
+ resource, GetSupplementable()->GetExecutionContext());
+ }
+ return entry;
+}
+
+void SVGExternalDocumentCache::Trace(Visitor* visitor) const {
+ Supplement<Document>::Trace(visitor);
+ visitor->Trace(entries_);
+}
+
+bool MimeTypeAllowed(const ResourceResponse& response) {
+ AtomicString mime_type = response.MimeType();
+ if (response.IsHTTP())
+ mime_type = response.HttpContentType();
+ return mime_type == "image/svg+xml" || mime_type == "text/xml" ||
+ mime_type == "application/xml" || mime_type == "application/xhtml+xml";
+}
+
+Document* CreateDocument(const TextResource* resource,
+ ExecutionContext* execution_context) {
+ const ResourceResponse& response = resource->GetResponse();
+ if (!MimeTypeAllowed(response))
+ return nullptr;
+ auto* document =
+ XMLDocument::CreateSVG(DocumentInit::Create()
+ .WithURL(response.CurrentRequestUrl())
+ .WithExecutionContext(execution_context));
+ document->SetContent(resource->DecodedText());
+ return document;
+}
+
+} // namespace
+
+Document* SVGResourceDocumentContent::GetDocument() {
+ if (resource_->IsLoaded()) {
+ // If this entry saw a revalidation, re-parse the document.
+ // TODO(fs): This will be inefficient for successful revalidations, so we
+ // want to detect those and not re-parse the document in those cases.
+ if (was_revalidating_) {
+ document_.Clear();
+ was_revalidating_ = false;
+ }
+ if (!document_ && resource_->HasData())
+ document_ = CreateDocument(resource_, context_);
+ }
+ return document_;
+}
+
+const KURL& SVGResourceDocumentContent::Url() const {
+ return resource_->Url();
+}
+
+void SVGResourceDocumentContent::Trace(Visitor* visitor) const {
+ visitor->Trace(resource_);
+ visitor->Trace(document_);
+ visitor->Trace(context_);
+}
+
+SVGResourceDocumentContent* SVGResourceDocumentContent::Fetch(
+ FetchParameters& params,
+ Document& document,
+ ResourceClient* client) {
+ params.MutableResourceRequest().SetMode(
+ network::mojom::blink::RequestMode::kSameOrigin);
+ DCHECK_EQ(params.GetResourceRequest().GetRequestContext(),
+ mojom::blink::RequestContextType::UNSPECIFIED);
+ params.SetRequestContext(mojom::blink::RequestContextType::IMAGE);
+ params.SetRequestDestination(network::mojom::RequestDestination::kImage);
+
+ TextResource* resource =
+ TextResource::FetchSVGDocument(params, document.Fetcher(), client);
+ if (!resource)
+ return nullptr;
+ auto* document_content =
+ SVGExternalDocumentCache::From(document)->Get(resource);
+ if (resource->IsCacheValidator())
+ document_content->SetWasRevalidating();
+ return document_content;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.h b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.h
new file mode 100644
index 00000000000..15da254e42a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
+ Copyright (C) 2011 Cosmin Truta <ctruta@gmail.com>
+ Copyright (C) 2012 University of Szeged
+ Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_DOCUMENT_CONTENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_DOCUMENT_CONTENT_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class Document;
+class ExecutionContext;
+class FetchParameters;
+class KURL;
+class ResourceClient;
+class TextResource;
+
+class CORE_EXPORT SVGResourceDocumentContent final
+ : public GarbageCollected<SVGResourceDocumentContent> {
+ public:
+ static SVGResourceDocumentContent* Fetch(FetchParameters&,
+ Document&,
+ ResourceClient*);
+
+ SVGResourceDocumentContent(TextResource* resource, ExecutionContext* context)
+ : resource_(resource), context_(context) {
+ DCHECK(resource_);
+ DCHECK(context_);
+ }
+
+ Document* GetDocument();
+ const KURL& Url() const;
+
+ void Trace(Visitor*) const;
+
+ private:
+ void SetWasRevalidating() { was_revalidating_ = true; }
+
+ Member<TextResource> resource_;
+ Member<Document> document_;
+ Member<ExecutionContext> context_;
+ bool was_revalidating_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_RESOURCE_DOCUMENT_CONTENT_H_
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content_test.cc b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content_test.cc
new file mode 100644
index 00000000000..319f0960849
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/svg/svg_resource_document_content_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/svg/svg_resource_document_content.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
+
+namespace blink {
+
+class SVGResourceDocumentContentTest : public SimTest {};
+
+TEST_F(SVGResourceDocumentContentTest, GetDocumentBeforeLoadComplete) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete("<html><body></body></html>");
+
+ const char kSVGUrl[] = "https://example.com/svg.svg";
+ SimSubresourceRequest svg_resource(kSVGUrl, "application/xml");
+
+ // Request a resource from the cache.
+ ExecutionContext* execution_context = GetDocument().GetExecutionContext();
+ ResourceLoaderOptions options(execution_context->GetCurrentWorld());
+ options.initiator_info.name = fetch_initiator_type_names::kCSS;
+ FetchParameters params(ResourceRequest(kSVGUrl), options);
+ auto* entry =
+ SVGResourceDocumentContent::Fetch(params, GetDocument(), nullptr);
+
+ // Write part of the response. The document should not be initialized yet,
+ // because the response is not complete. The document would be invalid at this
+ // point.
+ svg_resource.Start();
+ svg_resource.Write("<sv");
+ EXPECT_EQ(nullptr, entry->GetDocument());
+
+ // Finish the response, the Document should now be accessible.
+ svg_resource.Complete("g></svg>");
+ EXPECT_NE(nullptr, entry->GetDocument());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_script_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_script_element.cc
index a2aa6bf09cd..153028af10f 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_script_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_script_element.cc
@@ -53,14 +53,15 @@ void SVGScriptElement::ParseAttribute(
}
}
-void SVGScriptElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (SVGURIReference::IsKnownAttribute(attr_name)) {
+void SVGScriptElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (SVGURIReference::IsKnownAttribute(params.name)) {
SVGElement::InvalidationGuard invalidation_guard(this);
loader_->HandleSourceAttribute(LegacyHrefString(*this));
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
Node::InsertionNotificationRequest SVGScriptElement::InsertedInto(
@@ -171,7 +172,7 @@ void SVGScriptElement::DispatchErrorEvent() {
void SVGScriptElement::SetScriptElementForBinding(
HTMLScriptElementOrSVGScriptElement& element) {
- if (!IsInV1ShadowTree())
+ if (!IsInShadowTree())
element.SetSVGScriptElement(this);
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_script_element.h b/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
index e99ffec3cb6..3b7d172958c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_script_element.h
@@ -60,7 +60,7 @@ class SVGScriptElement final : public SVGElement,
void ChildrenChanged(const ChildrenChange&) override;
void DidMoveToNewDocument(Document& old_document) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool IsURLAttribute(const Attribute&) const override;
bool IsStructurallyExternal() const override { return HasSourceAttribute(); }
void FinishParsingChildren() override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
index 2b64ba5b74d..4c6f6f6aea5 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.cc
@@ -58,13 +58,14 @@ void InvalidateInstancesAndAncestorResources(SVGStopElement* stop_element) {
} // namespace
-void SVGStopElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (attr_name == svg_names::kOffsetAttr) {
+void SVGStopElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (params.name == svg_names::kOffsetAttr) {
InvalidateInstancesAndAncestorResources(this);
return;
}
- SVGElement::SvgAttributeChanged(attr_name);
+ SVGElement::SvgAttributeChanged(params);
}
void SVGStopElement::DidRecalcStyle(const StyleRecalcChange change) {
@@ -77,13 +78,14 @@ Color SVGStopElement::StopColorIncludingOpacity() const {
const ComputedStyle* style = GetComputedStyle();
// Normally, we should always have a computed style for <stop> elements. But
- // there are some odd corner cases (*cough* shadow DOM v0 undistributed light
- // tree *cough*) which leave it null.
+ // there are some odd corner cases which leave it null. It is possible that
+ // the only such corner cases were due to Shadow DOM v0. This may be able
+ // to be removed.
if (!style)
return Color::kBlack;
Color base_color = style->VisitedDependentColor(GetCSSPropertyStopColor());
- return base_color.CombineWithAlpha(style->SvgStyle().StopOpacity());
+ return base_color.CombineWithAlpha(style->StopOpacity());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
index f73b1e2dcd2..86c7c33beaa 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_stop_element.h
@@ -45,7 +45,7 @@ class SVGStopElement final : public SVGElement {
void DidRecalcStyle(const StyleRecalcChange) override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
// Stop elements don't have associated layout objects.
bool LayoutObjectIsNeeded(const ComputedStyle&) const override {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.cc
index de9fc41823c..d56c473c623 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.cc
@@ -233,7 +233,9 @@ void SVGSVGElement::CollectStyleForPresentationAttribute(
}
}
-void SVGSVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGSVGElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool update_relative_lengths_or_view_box = false;
bool width_or_height_changed =
attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
@@ -285,7 +287,7 @@ void SVGSVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
// FloatRect::intersects does not consider horizontal or vertical lines (because
@@ -475,8 +477,8 @@ AffineTransform SVGSVGElement::LocalCoordinateSpaceTransform(
// At the SVG/HTML boundary (aka LayoutSVGRoot), we need to apply the
// localToBorderBoxTransform to map an element from SVG viewport
// coordinates to CSS box coordinates.
- matrix.Multiply(
- To<LayoutSVGRoot>(layout_object)->LocalToBorderBoxTransform());
+ matrix.Multiply(TransformationMatrix(
+ To<LayoutSVGRoot>(layout_object)->LocalToBorderBoxTransform()));
// Drop any potential non-affine parts, because we're not able to convey
// that information further anyway until getScreenCTM returns a DOMMatrix
// (4x4 matrix.)
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
index f96a19e2ac1..4e561690ff3 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_svg_element.h
@@ -47,6 +47,7 @@ class SVGSVGElement final : public SVGGraphicsElement,
public:
explicit SVGSVGElement(Document&);
+ ~SVGSVGElement() override;
base::Optional<float> IntrinsicWidth() const;
base::Optional<float> IntrinsicHeight() const;
@@ -108,8 +109,6 @@ class SVGSVGElement final : public SVGGraphicsElement,
void Trace(Visitor*) const override;
private:
- ~SVGSVGElement() override;
-
void SetViewSpec(const SVGViewSpec*);
void ParseAttribute(const AttributeModificationParams&) override;
@@ -126,7 +125,7 @@ class SVGSVGElement final : public SVGGraphicsElement,
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
void DidMoveToNewDocument(Document& old_document) override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.cc
index 60533aab29a..8cf42a89b76 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.cc
@@ -33,8 +33,9 @@ void SVGSymbolElement::Trace(Visitor* visitor) const {
SVGFitToViewBox::Trace(visitor);
}
-void SVGSymbolElement::SvgAttributeChanged(const QualifiedName& attr_name) {
- if (SVGFitToViewBox::IsKnownAttribute(attr_name))
+void SVGSymbolElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ if (SVGFitToViewBox::IsKnownAttribute(params.name))
InvalidateInstances();
}
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
index 04925c59de8..71d5103e2a3 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_symbol_element.h
@@ -35,7 +35,7 @@ class SVGSymbolElement final : public SVGElement, public SVGFitToViewBox {
void Trace(Visitor*) const override;
private:
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
};
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.cc
index 9bba53d6dbe..c50de2b8681 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.cc
@@ -258,7 +258,8 @@ void SVGTextContentElement::CollectStyleForPresentationAttribute(
}
void SVGTextContentElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kTextLengthAttr)
text_length_is_specified_by_user_ = true;
@@ -273,7 +274,7 @@ void SVGTextContentElement::SvgAttributeChanged(
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
bool SVGTextContentElement::SelfHasRelativeLengths() const {
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.h b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.h
index 4c5898c83be..348ed4e6b8c 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_content_element.h
@@ -80,7 +80,7 @@ class CORE_EXPORT SVGTextContentElement : public SVGGraphicsElement {
void CollectStyleForPresentationAttribute(const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) final;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
bool SelfHasRelativeLengths() const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.cc
index aca65e99144..f8149a62326 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.cc
@@ -86,7 +86,9 @@ void SVGTextPathElement::ClearResourceReferences() {
RemoveAllOutgoingReferences();
}
-void SVGTextPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGTextPathElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (SVGURIReference::IsKnownAttribute(attr_name)) {
SVGElement::InvalidationGuard invalidation_guard(this);
BuildPendingResource();
@@ -106,7 +108,7 @@ void SVGTextPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGTextContentElement::SvgAttributeChanged(attr_name);
+ SVGTextContentElement::SvgAttributeChanged(params);
}
LayoutObject* SVGTextPathElement::CreateLayoutObject(const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
index d3ed63a0896..35b72fd151b 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_path_element.h
@@ -56,6 +56,7 @@ class SVGTextPathElement final : public SVGTextContentElement,
};
explicit SVGTextPathElement(Document&);
+ ~SVGTextPathElement() override;
SVGAnimatedLength* startOffset() const { return start_offset_.Get(); }
SVGAnimatedEnumeration<SVGTextPathMethodType>* method() {
@@ -68,15 +69,13 @@ class SVGTextPathElement final : public SVGTextContentElement,
void Trace(Visitor*) const override;
private:
- ~SVGTextPathElement() override;
-
void ClearResourceReferences();
void BuildPendingResource() override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
index 0a7c0f60b37..373e242949d 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
@@ -70,7 +70,8 @@ void SVGTextPositioningElement::Trace(Visitor* visitor) const {
}
void SVGTextPositioningElement::SvgAttributeChanged(
- const QualifiedName& attr_name) {
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
bool update_relative_lengths =
attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kDxAttr || attr_name == svg_names::kDyAttr;
@@ -92,7 +93,7 @@ void SVGTextPositioningElement::SvgAttributeChanged(
return;
}
- SVGTextContentElement::SvgAttributeChanged(attr_name);
+ SVGTextContentElement::SvgAttributeChanged(params);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.h b/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.h
index b6f1b16f349..1a56b63e9af 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_text_positioning_element.h
@@ -44,7 +44,7 @@ class SVGTextPositioningElement : public SVGTextContentElement {
protected:
SVGTextPositioningElement(const QualifiedName&, Document&);
- void SvgAttributeChanged(const QualifiedName&) final;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) final;
bool IsTextPositioning() const final { return true; }
Member<SVGAnimatedLengthList> x_;
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc b/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
index 165282fbe18..f2ca426540a 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/chromium/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/svg/svg_animated_length.h"
#include "third_party/blink/renderer/core/svg/svg_g_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
+#include "third_party/blink/renderer/core/svg/svg_resource_document_content.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
#include "third_party/blink/renderer/core/svg/svg_symbol_element.h"
#include "third_party/blink/renderer/core/svg/svg_title_element.h"
@@ -93,7 +94,7 @@ SVGUseElement::SVGUseElement(Document& document)
SVGUseElement::~SVGUseElement() = default;
void SVGUseElement::Trace(Visitor* visitor) const {
- visitor->Trace(cache_entry_);
+ visitor->Trace(document_content_);
visitor->Trace(x_);
visitor->Trace(y_);
visitor->Trace(width_);
@@ -101,7 +102,7 @@ void SVGUseElement::Trace(Visitor* visitor) const {
visitor->Trace(target_id_observer_);
SVGGraphicsElement::Trace(visitor);
SVGURIReference::Trace(visitor);
- SVGExternalDocumentCache::Client::Trace(visitor);
+ ResourceClient::Trace(visitor);
}
#if DCHECK_IS_ON()
@@ -195,12 +196,13 @@ void SVGUseElement::UpdateTargetReference() {
element_url_ = GetDocument().CompleteURL(url_string);
element_url_is_local_ = url_string.StartsWith('#');
if (!IsStructurallyExternal() || !GetDocument().IsActive()) {
- cache_entry_ = nullptr;
+ ClearResource();
+ document_content_ = nullptr;
return;
}
if (!element_url_.HasFragmentIdentifier() ||
- (cache_entry_ &&
- EqualIgnoringFragmentIdentifier(element_url_, cache_entry_->Url()))) {
+ (document_content_ && EqualIgnoringFragmentIdentifier(
+ element_url_, document_content_->Url()))) {
return;
}
@@ -213,11 +215,18 @@ void SVGUseElement::UpdateTargetReference() {
context_document =
To<LocalDOMWindow>(GetDocument().GetExecutionContext())->document();
}
- cache_entry_ = SVGExternalDocumentCache::From(*context_document)
- ->Get(this, element_url_, localName());
+
+ ExecutionContext* execution_context = context_document->GetExecutionContext();
+ ResourceLoaderOptions options(execution_context->GetCurrentWorld());
+ options.initiator_info.name = localName();
+ FetchParameters params(ResourceRequest(element_url_), options);
+ document_content_ =
+ SVGResourceDocumentContent::Fetch(params, *context_document, this);
}
-void SVGUseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
+void SVGUseElement::SvgAttributeChanged(
+ const SvgAttributeChangedParams& params) {
+ const QualifiedName& attr_name = params.name;
if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
attr_name == svg_names::kWidthAttr ||
attr_name == svg_names::kHeightAttr) {
@@ -249,7 +258,7 @@ void SVGUseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
return;
}
- SVGGraphicsElement::SvgAttributeChanged(attr_name);
+ SVGGraphicsElement::SvgAttributeChanged(params);
}
static bool IsDisallowedElement(const Element& element) {
@@ -312,9 +321,9 @@ Element* SVGUseElement::ResolveTargetElement() {
WrapWeakPersistent(this)));
}
}
- if (!cache_entry_ || !cache_entry_->GetDocument())
+ if (!document_content_ || !document_content_->GetDocument())
return nullptr;
- return cache_entry_->GetDocument()->getElementById(element_identifier);
+ return document_content_->GetDocument()->getElementById(element_identifier);
}
SVGElement* SVGUseElement::InstanceRoot() const {
@@ -585,12 +594,12 @@ void SVGUseElement::DispatchPendingEvent() {
DispatchEvent(*Event::Create(event_type_names::kLoad));
}
-void SVGUseElement::NotifyFinished(Document* external_document) {
+void SVGUseElement::NotifyFinished(Resource* resource) {
if (!isConnected())
return;
InvalidateShadowTree();
- if (!external_document) {
+ if (resource->ErrorOccurred() || !document_content_->GetDocument()) {
DispatchEvent(*Event::Create(event_type_names::kError));
} else {
if (have_fired_load_event_)
@@ -606,4 +615,8 @@ void SVGUseElement::NotifyFinished(Document* external_document) {
}
}
+String SVGUseElement::DebugName() const {
+ return "SVGUseElement";
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/svg/svg_use_element.h b/chromium/third_party/blink/renderer/core/svg/svg_use_element.h
index 66d62890061..383b1abf5b8 100644
--- a/chromium/third_party/blink/renderer/core/svg/svg_use_element.h
+++ b/chromium/third_party/blink/renderer/core/svg/svg_use_element.h
@@ -24,19 +24,20 @@
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/svg/svg_external_document_cache.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
namespace blink {
class SVGAnimatedLength;
+class SVGResourceDocumentContent;
class SVGUseElement final : public SVGGraphicsElement,
public SVGURIReference,
- public SVGExternalDocumentCache::Client {
+ public ResourceClient {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -77,7 +78,7 @@ class SVGUseElement final : public SVGGraphicsElement,
void RemovedFrom(ContainerNode&) override;
void DidMoveToNewDocument(Document&) override;
- void SvgAttributeChanged(const QualifiedName&) override;
+ void SvgAttributeChanged(const SvgAttributeChangedParams&) override;
LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
@@ -104,10 +105,11 @@ class SVGUseElement final : public SVGGraphicsElement,
bool HasCycleUseReferencing(const ContainerNode& target_instance,
const SVGElement& new_target) const;
- void NotifyFinished(Document*) override;
+ void NotifyFinished(Resource*) override;
+ String DebugName() const override;
void UpdateTargetReference();
- Member<SVGExternalDocumentCache::Entry> cache_entry_;
+ Member<SVGResourceDocumentContent> document_content_;
Member<SVGAnimatedLength> x_;
Member<SVGAnimatedLength> y_;
diff --git a/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc b/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
index 60fd9c72c10..069726756c8 100644
--- a/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
+++ b/chromium/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
-#include "third_party/blink/renderer/core/editing/selection_type.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_element.h"
diff --git a/chromium/third_party/blink/renderer/core/testing/DEPS b/chromium/third_party/blink/renderer/core/testing/DEPS
index 9c2773daa13..7d8ad3b7bbb 100644
--- a/chromium/third_party/blink/renderer/core/testing/DEPS
+++ b/chromium/third_party/blink/renderer/core/testing/DEPS
@@ -1,6 +1,8 @@
include_rules = [
"+base/run_loop.h",
+ "+base/process/process_handle.h",
"+cc",
+ "+components/ukm/test_ukm_recorder.h",
# TODO(crbug.com/838693): Test harnesses use LayerTreeView
# from content instead of a fake WebLayerTreeView implementation, so
# that the Web abstraction can go away.
diff --git a/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.cc b/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
index c2581c876a6..b7ad0351301 100644
--- a/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
+++ b/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -25,9 +26,9 @@ LocalFrame* SingleChildLocalFrameClient::CreateFrame(
MakeGarbageCollected<LocalFrameClientWithParent>(parent_frame);
LocalFrame* child = MakeGarbageCollected<LocalFrame>(
child_client, *parent_frame->GetPage(), owner_element, parent_frame,
- nullptr, FrameInsertType::kInsertInConstructor,
- base::UnguessableToken::Create(), &parent_frame->window_agent_factory(),
- nullptr, /* policy_container */ nullptr);
+ nullptr, FrameInsertType::kInsertInConstructor, LocalFrameToken(),
+ &parent_frame->window_agent_factory(), nullptr,
+ /* policy_container */ nullptr);
child->CreateView(IntSize(500, 500), Color::kTransparent);
child->Init(nullptr);
diff --git a/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.h b/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.h
index d02c3609841..e2e2316cd3b 100644
--- a/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.h
+++ b/chromium/third_party/blink/renderer/core/testing/core_unit_test_helper.h
@@ -19,7 +19,6 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/testing/layer_tree_host_embedder.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -150,9 +149,6 @@ class RenderingTest : public PageTestBase {
const DisplayItemClient* GetDisplayItemClientFromLayoutObject(
LayoutObject* obj) const {
- auto* block_flow = DynamicTo<LayoutNGBlockFlow>(obj);
- if (block_flow && block_flow->PaintFragment())
- return block_flow->PaintFragment();
return obj;
}
diff --git a/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-main.html b/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-main.html
new file mode 100644
index 00000000000..8a174381a9b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-main.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body><iframe src="add-frame-in-unload-subframe.html"></iframe></body>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-subframe.html b/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-subframe.html
new file mode 100644
index 00000000000..a037c299757
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/add-frame-in-unload-subframe.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+window.addEventListener('unload', () => {
+ window.top.document.body.appendChild(document.createElement('iframe'));
+});
+</script>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_basic_rtl.html b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_basic_rtl.html
new file mode 100644
index 00000000000..fa1998166d9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_basic_rtl.html
@@ -0,0 +1,24 @@
+<style>
+ @font-face {
+ font-family: ahem;
+ src: url(Ahem.ttf);
+ }
+ * {
+ font-family: ahem;
+ }
+ body {
+ direction: rtl;
+ }
+</style>
+<span id="text">
+ &#x202E;The quick brown fox jumped over the lazy dog.
+</span>
+<script>
+ var range = document.createRange();
+ var textNode = document.getElementById("text").firstChild;
+ range.setStart(textNode, 10);
+ range.setEnd(textNode, 25);
+ document.getSelection().addRange(range);
+
+ window.expectedResult = [document, 584, 8, 584, 20, document, 404, 8, 404, 20];
+</script>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_lr_rtl.html b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_lr_rtl.html
new file mode 100644
index 00000000000..e3188ab769f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_lr_rtl.html
@@ -0,0 +1,25 @@
+<style>
+ @font-face {
+ font-family: ahem;
+ src: url(Ahem.ttf);
+ }
+ * {
+ font-family: ahem;
+ }
+ body {
+ direction: rtl;
+ -webkit-writing-mode: vertical-lr;
+ }
+</style>
+<span id="text">
+ &#x202E;The quick brown fox jumped over the lazy dog.
+</span>
+<script>
+ var range = document.createRange();
+ var textNode = document.getElementById("text").firstChild;
+ range.setStart(textNode, 10);
+ range.setEnd(textNode, 25);
+ document.getSelection().addRange(range);
+
+ window.expectedResult = [document, 20, 424, 8, 424, document, 8, 244, 20, 244];
+</script>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_rl_rtl.html b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_rl_rtl.html
new file mode 100644
index 00000000000..0aa385479b1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/composited_selection_bounds_vertical_rl_rtl.html
@@ -0,0 +1,25 @@
+<style>
+ @font-face {
+ font-family: ahem;
+ src: url(Ahem.ttf);
+ }
+ * {
+ font-family: ahem;
+ }
+ body {
+ direction: rtl;
+ -webkit-writing-mode: vertical-rl;
+ }
+</style>
+<span id="text">
+ &#x202E;The quick brown fox jumped over the lazy dog.
+</span>
+<script>
+ var range = document.createRange();
+ var textNode = document.getElementById("text").firstChild;
+ range.setStart(textNode, 10);
+ range.setEnd(textNode, 25);
+ document.getSelection().addRange(range);
+
+ window.expectedResult = [document, 620, 424, 632, 424, document, 632, 244, 620, 244];
+</script>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/display_none_frame.html b/chromium/third_party/blink/renderer/core/testing/data/display_none_frame.html
new file mode 100644
index 00000000000..e2b58e67908
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/data/display_none_frame.html
@@ -0,0 +1,5 @@
+<html style="display:none;">
+ <body>
+ <p>This text is inside an invisible document.</p>
+ </body>
+</html>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html b/chromium/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
index faa70844040..de16538faa7 100644
--- a/chromium/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
+++ b/chromium/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
@@ -1,22 +1,8 @@
<html>
- <head>
- <script>
- function log(message)
- {
- var item = document.createElement("li");
- item.appendChild(document.createTextNode(message));
- document.getElementById("console").appendChild(item);
- }
-
- </script>
-
- </head>
+ <head></head>
<body>
- <ul id=console>
- </ul>
-
- <link id="firstPrerender" rel=prerender href="http://first-prerender.com/"/>
- <link id="secondPrerender" rel=prerender href="http://second-prerender.com/"/>
+ <link id="firstPrerender" rel=prerender href="/first"/>
+ <link id="secondPrerender" rel=prerender href="/second"/>
<p id="emptyParagraph"></p>
@@ -42,26 +28,11 @@
link.parentElement.removeChild(link);
}
- firstPrerender.addEventListener('webkitprerenderstart', function() { log("first_webkitprerenderstart"); }, false);
- firstPrerender.addEventListener('webkitprerenderstop', function() { log("first_webkitprerenderstop"); }, false);
- firstPrerender.addEventListener('webkitprerenderload', function() { log("first_webkitprerenderload"); }, false);
- firstPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("first_webkitprerenderdomcontentloaded"); }, false);
-
- secondPrerender.addEventListener('webkitprerenderstart', function() { log("second_webkitprerenderstart"); }, false);
- secondPrerender.addEventListener('webkitprerenderstop', function() { log("second_webkitprerenderstop"); }, false);
- secondPrerender.addEventListener('webkitprerenderload', function() { log("second_webkitprerenderload"); }, false);
- secondPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("second_webkitprerenderdomcontentloaded"); }, false);
-
function addThirdPrerender()
{
var emptyParagraph = document.getElementById("emptyParagraph");
- emptyParagraph.innerHTML = '<link id="thirdPrerender" rel=prerender href="http://third-prererender.com/"/>';
+ emptyParagraph.innerHTML = '<link id="thirdPrerender" rel=prerender href="/third"/>';
var thirdPrerender = document.getElementById('thirdPrerender');
-
- thirdPrerender.addEventListener('webkitprerenderstart', function() { log("third_webkitprerenderstart"); }, false);
- thirdPrerender.addEventListener('webkitprerenderstop', function() { log("third_webkitprerenderstop"); }, false);
- thirdPrerender.addEventListener('webkitprerenderload', function() { log("third_webkitprerenderload"); }, false);
- thirdPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("third_webkitprerenderdomcontentloaded"); }, false);
}
</script>
</body>
diff --git a/chromium/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html b/chromium/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
index 00d42c01269..9d89474ff6e 100644
--- a/chromium/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
+++ b/chromium/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
@@ -1,19 +1,7 @@
<html>
- <head>
- <script>
- function log(message)
- {
- var item = document.createElement("li");
- item.appendChild(document.createTextNode(message));
- document.getElementById("console").appendChild(item);
- }
- </script>
- </head>
+ <head></head>
<body>
- <ul id=console>
- </ul>
-
- <link id="theprerender" rel=prerender href="http://prerender.com/"/>
+ <link id="theprerender" rel=prerender href="/prerender"/>
<script>
var prerender = document.getElementById('theprerender');
@@ -27,19 +15,14 @@
function mutateTarget()
{
var link = document.getElementById('theprerender');
- link.href = "http://mutated.com/";
+ link.href = "/mutated";
}
function mutateRel()
{
var link = document.getElementById('theprerender');
- link.rel = "something-else";
+ link.rel = "/something-else";
}
-
- prerender.addEventListener('webkitprerenderstart', function() { log("webkitprerenderstart"); }, false);
- prerender.addEventListener('webkitprerenderstop', function() { log("webkitprerenderstop"); }, false);
- prerender.addEventListener('webkitprerenderload', function() { log("webkitprerenderload"); }, false);
- prerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("webkitprerenderdomcontentloaded"); }, false);
</script>
</body>
</html>
diff --git a/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc b/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
index 15f6ecf7d97..f8e211610d2 100644
--- a/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dictionary_test.cc
@@ -66,8 +66,10 @@ void DictionaryTest::set(const InternalDictionary* testing_dictionary) {
enum_or_null_member_ = testing_dictionary->enumOrNullMember();
if (testing_dictionary->hasElementMember())
element_member_ = testing_dictionary->elementMember();
- if (testing_dictionary->hasElementOrNullMember())
+ if (testing_dictionary->hasElementOrNullMember()) {
element_or_null_member_ = testing_dictionary->elementOrNullMember();
+ has_element_or_null_member_ = true;
+ }
if (testing_dictionary->hasObjectMember())
object_member_ = testing_dictionary->objectMember();
object_or_null_member_with_default_ =
@@ -75,7 +77,9 @@ void DictionaryTest::set(const InternalDictionary* testing_dictionary) {
if (testing_dictionary->hasDoubleOrStringMember())
double_or_string_member_ = testing_dictionary->doubleOrStringMember();
if (testing_dictionary->hasDoubleOrStringSequenceMember()) {
- double_or_string_sequence_member_ =
+ double_or_string_sequence_or_null_member_ =
+ MakeGarbageCollected<HeapVector<DoubleOrString>>();
+ *double_or_string_sequence_or_null_member_ =
testing_dictionary->doubleOrStringSequenceMember();
}
// eventTargetOrNullMember has a default null value.
@@ -149,10 +153,12 @@ void DictionaryTest::Reset() {
enum_member_with_default_ = String();
enum_or_null_member_ = base::nullopt;
element_member_ = nullptr;
- element_or_null_member_.reset();
+ element_or_null_member_.Clear();
+ has_element_or_null_member_ = false;
object_member_ = ScriptValue();
object_or_null_member_with_default_ = ScriptValue();
double_or_string_member_ = DoubleOrString();
+ double_or_string_sequence_or_null_member_ = nullptr;
event_target_or_null_member_ = nullptr;
derived_string_member_ = base::nullopt;
derived_string_member_with_default_ = String();
@@ -211,15 +217,15 @@ void DictionaryTest::GetInternals(InternalDictionary* dict) {
dict->setEnumOrNullMember(enum_or_null_member_.value());
if (element_member_)
dict->setElementMember(element_member_);
- if (element_or_null_member_.has_value())
- dict->setElementOrNullMember(element_or_null_member_.value());
+ if (has_element_or_null_member_)
+ dict->setElementOrNullMember(element_or_null_member_);
dict->setObjectMember(object_member_);
dict->setObjectOrNullMemberWithDefault(object_or_null_member_with_default_);
if (!double_or_string_member_.IsNull())
dict->setDoubleOrStringMember(double_or_string_member_);
- if (double_or_string_sequence_member_) {
+ if (double_or_string_sequence_or_null_member_) {
dict->setDoubleOrStringSequenceMember(
- double_or_string_sequence_member_.value());
+ *double_or_string_sequence_or_null_member_);
}
dict->setEventTargetOrNullMember(event_target_or_null_member_);
dict->setInternalEnumOrInternalEnumSequenceMember(
@@ -251,7 +257,7 @@ void DictionaryTest::Trace(Visitor* visitor) const {
visitor->Trace(element_or_null_member_);
visitor->Trace(object_member_);
visitor->Trace(object_or_null_member_with_default_);
- visitor->Trace(double_or_string_sequence_member_);
+ visitor->Trace(double_or_string_sequence_or_null_member_);
visitor->Trace(event_target_or_null_member_);
visitor->Trace(any_member_);
visitor->Trace(callback_function_member_);
diff --git a/chromium/third_party/blink/renderer/core/testing/dictionary_test.h b/chromium/third_party/blink/renderer/core/testing/dictionary_test.h
index 1840a361d37..5bbd24c53a3 100644
--- a/chromium/third_party/blink/renderer/core/testing/dictionary_test.h
+++ b/chromium/third_party/blink/renderer/core/testing/dictionary_test.h
@@ -56,6 +56,8 @@ class DictionaryTest : public ScriptWrappable {
// Some members are not wrapped with Optional because:
// - |longMemberWithDefault| has a non-null default value
// - String and PtrTypes can express whether they are null
+ // - base::Optional does not work with GarbageCollected types when used on
+ // heap.
base::Optional<int> long_member_;
base::Optional<int> long_member_with_clamp_;
base::Optional<int> long_member_with_enforce_range_;
@@ -82,11 +84,12 @@ class DictionaryTest : public ScriptWrappable {
base::Optional<String> enum_or_null_member_;
#endif
Member<Element> element_member_;
- base::Optional<Member<Element>> element_or_null_member_;
+ Member<Element> element_or_null_member_;
+ bool has_element_or_null_member_ = false;
ScriptValue object_member_;
ScriptValue object_or_null_member_with_default_;
DoubleOrString double_or_string_member_;
- base::Optional<HeapVector<DoubleOrString>> double_or_string_sequence_member_;
+ Member<HeapVector<DoubleOrString>> double_or_string_sequence_or_null_member_;
Member<EventTarget> event_target_or_null_member_;
base::Optional<String> derived_string_member_;
String derived_string_member_with_default_;
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
index 876b7cb4c82..de225c91f58 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/script/module_record_resolver.h"
namespace blink {
@@ -27,7 +28,7 @@ class EmptyModuleRecordResolver final : public ModuleRecordResolver {
return nullptr;
}
- v8::Local<v8::Module> Resolve(const String& specifier,
+ v8::Local<v8::Module> Resolve(const ModuleRequest& module_request,
v8::Local<v8::Module> referrer,
ExceptionState&) override {
NOTREACHED();
@@ -74,6 +75,7 @@ base::SingleThreadTaskRunner* DummyModulator::TaskRunner() {
}
void DummyModulator::FetchTree(const KURL&,
+ ModuleType,
ResourceFetcher*,
mojom::blink::RequestContextType,
network::mojom::RequestDestination,
@@ -100,7 +102,7 @@ void DummyModulator::FetchDescendantsForInlineScript(
NOTREACHED();
}
-ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&) {
+ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&, ModuleType) {
NOTREACHED();
return nullptr;
}
@@ -116,7 +118,7 @@ bool DummyModulator::HasValidContext() {
return true;
}
-void DummyModulator::ResolveDynamically(const String&,
+void DummyModulator::ResolveDynamically(const ModuleRequest& module_request,
const KURL&,
const ReferrerScriptInfo&,
ScriptPromiseResolver*) {
@@ -137,12 +139,13 @@ void DummyModulator::RegisterImportMap(const ImportMap*,
NOTREACHED();
}
-bool DummyModulator::IsAcquiringImportMaps() const {
+Modulator::AcquiringImportMapsState
+DummyModulator::GetAcquiringImportMapsState() const {
NOTREACHED();
- return true;
+ return AcquiringImportMapsState::kAcquiring;
}
-void DummyModulator::ClearIsAcquiringImportMaps() {
+void DummyModulator::SetAcquiringImportMapsState(AcquiringImportMapsState) {
NOTREACHED();
}
@@ -169,9 +172,32 @@ Vector<ModuleRequest> DummyModulator::ModuleRequestsFromModuleRecord(
return Vector<ModuleRequest>();
}
+ModuleType DummyModulator::ModuleTypeFromRequest(
+ const ModuleRequest& module_request) const {
+ String module_type_string = module_request.GetModuleTypeString();
+ if (module_type_string.IsNull()) {
+ // Per https://github.com/whatwg/html/pull/5883, if no type assertion is
+ // provided then the import should be treated as a JavaScript module.
+ return ModuleType::kJavaScript;
+ } else if (module_type_string == "json") {
+ // Per https://github.com/whatwg/html/pull/5658, a "json" type assertion
+ // indicates that the import should be treated as a JSON module script.
+ return ModuleType::kJSON;
+ } else if (module_type_string == "css") {
+ // Per https://github.com/whatwg/html/pull/4898, a "css" type assertion
+ // indicates that the import should be treated as a CSS module script.
+ return ModuleType::kCSS;
+ } else {
+ // Per https://github.com/whatwg/html/pull/5883, if an unsupported type
+ // assertion is provided then the import should be treated as an error
+ // similar to an invalid module specifier.
+ return ModuleType::kInvalid;
+ }
+}
+
ModuleScriptFetcher* DummyModulator::CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader> pass_key) {
+ base::PassKey<ModuleScriptLoader> pass_key) {
NOTREACHED();
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
index 19f1523b75c..13a7f2ae8fb 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -40,6 +40,7 @@ class DummyModulator : public Modulator {
bool ImportMapsEnabled() const override;
void FetchTree(const KURL&,
+ ModuleType,
ResourceFetcher*,
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
@@ -57,10 +58,10 @@ class DummyModulator : public Modulator {
mojom::blink::RequestContextType context_type,
network::mojom::RequestDestination destination,
ModuleTreeClient*) override;
- ModuleScript* GetFetchedModuleScript(const KURL&) override;
+ ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) override;
KURL ResolveModuleSpecifier(const String&, const KURL&, String*) override;
bool HasValidContext() override;
- void ResolveDynamically(const String& specifier,
+ void ResolveDynamically(const ModuleRequest& module_request,
const KURL&,
const ReferrerScriptInfo&,
ScriptPromiseResolver*) override;
@@ -68,17 +69,19 @@ class DummyModulator : public Modulator {
ScriptValue CreateSyntaxError(const String& message) const override;
void RegisterImportMap(const ImportMap*,
ScriptValue error_to_rethrow) override;
- bool IsAcquiringImportMaps() const override;
- void ClearIsAcquiringImportMaps() override;
+ AcquiringImportMapsState GetAcquiringImportMapsState() const override;
+ void SetAcquiringImportMapsState(AcquiringImportMapsState) override;
ModuleImportMeta HostGetImportMetaProperties(
v8::Local<v8::Module>) const override;
const ImportMap* GetImportMapForTest() const override;
ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
v8::Local<v8::Module>) override;
+ ModuleType ModuleTypeFromRequest(
+ const ModuleRequest& module_request) const override;
ModuleScriptFetcher* CreateModuleScriptFetcher(
ModuleScriptCustomFetchType,
- util::PassKey<ModuleScriptLoader>) override;
+ base::PassKey<ModuleScriptLoader>) override;
void ProduceCacheModuleTreeTopLevel(ModuleScript*) override;
Member<ModuleRecordResolver> resolver_;
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
index 84b56a35610..07c2ea23f5a 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.cc
@@ -33,7 +33,10 @@
#include <memory>
#include "base/memory/ptr_util.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/core/core_initializer.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -44,6 +47,8 @@
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
@@ -69,13 +74,15 @@ DummyPageHolder::DummyPageHolder(
LocalFrameClient* local_frame_client,
base::OnceCallback<void(Settings&)> setting_overrider,
const base::TickClock* clock)
- : enable_mock_scrollbars_(true) {
+ : enable_mock_scrollbars_(true),
+ agent_group_scheduler_(
+ Thread::MainThread()->Scheduler()->CreateAgentGroupScheduler()) {
Page::PageClients page_clients;
if (!page_clients_argument)
FillWithEmptyClients(page_clients);
else
page_clients.chrome_client = page_clients_argument->chrome_client;
- page_ = Page::CreateNonOrdinary(page_clients);
+ page_ = Page::CreateNonOrdinary(page_clients, *agent_group_scheduler_);
Settings& settings = page_->GetSettings();
if (setting_overrider)
std::move(setting_overrider).Run(settings);
@@ -84,23 +91,14 @@ DummyPageHolder::DummyPageHolder(
if (!local_frame_client_)
local_frame_client_ = MakeGarbageCollected<DummyLocalFrameClient>();
- mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost>
- stub_policy_container_remote;
- ignore_result(
- stub_policy_container_remote.InitWithNewEndpointAndPassReceiver());
-
// Create new WindowAgentFactory as this page will be isolated from others.
frame_ = MakeGarbageCollected<LocalFrame>(
local_frame_client_.Get(), *page_,
/* FrameOwner* */ nullptr, /* Frame* parent */ nullptr,
/* Frame* previous_sibling */ nullptr,
- FrameInsertType::kInsertInConstructor, base::UnguessableToken::Create(),
+ FrameInsertType::kInsertInConstructor, LocalFrameToken(),
/* WindowAgentFactory* */ nullptr,
- /* InterfaceRegistry* */ nullptr,
- std::make_unique<PolicyContainer>(
- std::move(stub_policy_container_remote),
- mojom::blink::PolicyContainerDocumentPolicies::New()),
- clock);
+ /* InterfaceRegistry* */ nullptr, /* policy_container */ nullptr, clock);
frame_->SetView(
MakeGarbageCollected<LocalFrameView>(*frame_, initial_view_size));
frame_->View()->GetPage()->GetVisualViewport().SetSize(initial_view_size);
diff --git a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.h b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.h
index be7505bb55a..c0994380565 100644
--- a/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.h
+++ b/chromium/third_party/blink/renderer/core/testing/dummy_page_holder.h
@@ -99,6 +99,7 @@ class DummyPageHolder {
CrossThreadPersistent<LocalFrame> frame_;
Persistent<LocalFrameClient> local_frame_client_;
+ std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler_;
DISALLOW_COPY_AND_ASSIGN(DummyPageHolder);
};
diff --git a/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.cc b/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
index d24d6cab43f..77c2f0d7a33 100644
--- a/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
+++ b/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
@@ -25,7 +25,9 @@ void FakeLocalFrameHost::EnterFullscreen(
void FakeLocalFrameHost::ExitFullscreen() {}
-void FakeLocalFrameHost::FullscreenStateChanged(bool is_fullscreen) {}
+void FakeLocalFrameHost::FullscreenStateChanged(
+ bool is_fullscreen,
+ mojom::blink::FullscreenOptionsPtr options) {}
void FakeLocalFrameHost::RegisterProtocolHandler(const WTF::String& scheme,
const ::blink::KURL& url,
@@ -175,6 +177,11 @@ void FakeLocalFrameHost::ShowPopupMenu(
bool right_aligned,
bool allow_multiple_selection) {}
+void FakeLocalFrameHost::ShowContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient>
+ context_menu_client,
+ const blink::UntrustworthyContextMenuParams& params) {}
+
void FakeLocalFrameHost::DidLoadResourceFromMemoryCache(
const KURL& url,
const WTF::String& http_method,
@@ -182,30 +189,41 @@ void FakeLocalFrameHost::DidLoadResourceFromMemoryCache(
network::mojom::blink::RequestDestination request_destination) {}
void FakeLocalFrameHost::DidChangeFrameOwnerProperties(
- const base::UnguessableToken& child_frame_token,
+ const blink::FrameToken& child_frame_token,
mojom::blink::FrameOwnerPropertiesPtr frame_owner_properties) {}
void FakeLocalFrameHost::DidChangeOpener(
- const base::Optional<base::UnguessableToken>& opener_frame) {}
+ const base::Optional<LocalFrameToken>& opener_frame) {}
void FakeLocalFrameHost::DidChangeCSPAttribute(
- const base::UnguessableToken& child_frame_token,
+ const blink::FrameToken& child_frame_token,
network::mojom::blink::ContentSecurityPolicyPtr) {}
void FakeLocalFrameHost::DidChangeFramePolicy(
- const base::UnguessableToken& child_frame_token,
+ const blink::FrameToken& child_frame_token,
const FramePolicy& frame_policy) {}
-void FakeLocalFrameHost::BindPolicyContainer(
- mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
- receiver) {}
-
void FakeLocalFrameHost::CapturePaintPreviewOfSubframe(
const gfx::Rect& clip_rect,
const base::UnguessableToken& guid) {}
+void FakeLocalFrameHost::SetModalCloseListener(
+ mojo::PendingRemote<mojom::blink::ModalCloseListener>) {}
+
void FakeLocalFrameHost::Detach() {}
+void FakeLocalFrameHost::GetKeepAliveHandleFactory(
+ mojo::PendingReceiver<mojom::blink::KeepAliveHandleFactory> receiver) {}
+
+void FakeLocalFrameHost::DidAddMessageToConsole(
+ mojom::ConsoleMessageLevel log_level,
+ const WTF::String& message,
+ int32_t line_no,
+ const WTF::String& source_id,
+ const WTF::String& untrusted_stack_trace) {}
+
+void FakeLocalFrameHost::FrameSizeChanged(const gfx::Size& frame_size) {}
+
void FakeLocalFrameHost::BindFrameHostReceiver(
mojo::ScopedInterfaceEndpointHandle handle) {
receiver_.Bind(mojo::PendingAssociatedReceiver<mojom::blink::LocalFrameHost>(
diff --git a/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.h b/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.h
index 84b55274873..4f6b1c7b33b 100644
--- a/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.h
+++ b/chromium/third_party/blink/renderer/core/testing/fake_local_frame_host.h
@@ -8,6 +8,8 @@
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom-blink.h"
#include "third_party/blink/public/mojom/favicon/favicon_url.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/policy_container.mojom-blink.h"
@@ -27,7 +29,9 @@ class FakeLocalFrameHost : public mojom::blink::LocalFrameHost {
void EnterFullscreen(mojom::blink::FullscreenOptionsPtr options,
EnterFullscreenCallback callback) override;
void ExitFullscreen() override;
- void FullscreenStateChanged(bool is_fullscreen) override;
+ void FullscreenStateChanged(
+ bool is_fullscreen,
+ mojom::blink::FullscreenOptionsPtr options) override;
void RegisterProtocolHandler(const WTF::String& scheme,
const ::blink::KURL& url,
bool user_gesture) override;
@@ -111,28 +115,41 @@ class FakeLocalFrameHost : public mojom::blink::LocalFrameHost {
Vector<mojom::blink::MenuItemPtr> menu_items,
bool right_aligned,
bool allow_multiple_selection) override;
+ void ShowContextMenu(
+ mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient>
+ context_menu_client,
+ const blink::UntrustworthyContextMenuParams& params) override;
void DidLoadResourceFromMemoryCache(
const KURL& url,
const WTF::String& http_method,
const WTF::String& mime_type,
network::mojom::blink::RequestDestination request_destination) override;
void DidChangeFrameOwnerProperties(
- const base::UnguessableToken& child_frame_token,
+ const blink::FrameToken& child_frame_token,
mojom::blink::FrameOwnerPropertiesPtr frame_owner_properties) override;
void DidChangeOpener(
- const base::Optional<base::UnguessableToken>& opener_frame) override;
- void DidChangeCSPAttribute(const base::UnguessableToken& child_frame_token,
+ const base::Optional<LocalFrameToken>& opener_frame) override;
+ void DidChangeCSPAttribute(const blink::FrameToken& child_frame_token,
network::mojom::blink::ContentSecurityPolicyPtr
parsed_csp_attribute) override;
- void DidChangeFramePolicy(const base::UnguessableToken& child_frame_token,
+ void DidChangeFramePolicy(const blink::FrameToken& child_frame_token,
const FramePolicy& frame_policy) override;
- void BindPolicyContainer(
- mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
- receiver) override;
void CapturePaintPreviewOfSubframe(
const gfx::Rect& clip_rect,
const base::UnguessableToken& guid) override;
+ void SetModalCloseListener(
+ mojo::PendingRemote<mojom::blink::ModalCloseListener>) override;
void Detach() override;
+ void GetKeepAliveHandleFactory(
+ mojo::PendingReceiver<mojom::blink::KeepAliveHandleFactory> receiver)
+ override;
+ void DidAddMessageToConsole(
+ mojom::blink::ConsoleMessageLevel log_level,
+ const WTF::String& message,
+ int32_t line_no,
+ const WTF::String& source_id,
+ const WTF::String& untrusted_stack_trace) override;
+ void FrameSizeChanged(const gfx::Size& frame_size) override;
private:
void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle);
diff --git a/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc b/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc
index 67e82050b35..a4d2140015e 100644
--- a/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc
+++ b/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc
@@ -17,8 +17,8 @@ void FakeRemoteFrameHost::SetInheritedEffectiveTouchAction(
cc::TouchAction touch_action) {}
void FakeRemoteFrameHost::UpdateRenderThrottlingStatus(bool is_throttled,
- bool subtree_throttled) {
-}
+ bool subtree_throttled,
+ bool display_locked) {}
void FakeRemoteFrameHost::VisibilityChanged(
mojom::blink::FrameVisibility visibility) {}
@@ -34,14 +34,14 @@ void FakeRemoteFrameHost::CapturePaintPreviewOfCrossProcessSubframe(
void FakeRemoteFrameHost::SetIsInert(bool inert) {}
void FakeRemoteFrameHost::DidChangeOpener(
- const base::Optional<base::UnguessableToken>& opener_frame_token) {}
+ const base::Optional<LocalFrameToken>& opener_frame_token) {}
void FakeRemoteFrameHost::AdvanceFocus(
blink::mojom::FocusType focus_type,
- const base::UnguessableToken& source_frame_token) {}
+ const LocalFrameToken& source_frame_token) {}
void FakeRemoteFrameHost::RouteMessageEvent(
- const base::Optional<base::UnguessableToken>& source_frame_token,
+ const base::Optional<LocalFrameToken>& source_frame_token,
const String& source_origin,
const String& target_origin,
BlinkTransferableMessage message) {}
@@ -52,7 +52,11 @@ void FakeRemoteFrameHost::PrintCrossProcessSubframe(const gfx::Rect& rect,
void FakeRemoteFrameHost::Detach() {}
void FakeRemoteFrameHost::UpdateViewportIntersection(
- blink::mojom::blink::ViewportIntersectionStatePtr intersection_state) {}
+ blink::mojom::blink::ViewportIntersectionStatePtr intersection_state,
+ const base::Optional<FrameVisualProperties>& visual_properties) {}
+
+void FakeRemoteFrameHost::SynchronizeVisualProperties(
+ const blink::FrameVisualProperties& properties) {}
void FakeRemoteFrameHost::BindFrameHostReceiver(
mojo::ScopedInterfaceEndpointHandle handle) {
diff --git a/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.h b/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.h
index 3b8c60293d1..91a1d719ee4 100644
--- a/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.h
+++ b/chromium/third_party/blink/renderer/core/testing/fake_remote_frame_host.h
@@ -10,6 +10,7 @@
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/frame/frame_visual_properties.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
#include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
@@ -26,7 +27,8 @@ class FakeRemoteFrameHost : public mojom::blink::RemoteFrameHost {
void Init(blink::AssociatedInterfaceProvider* provider);
void SetInheritedEffectiveTouchAction(cc::TouchAction touch_action) override;
void UpdateRenderThrottlingStatus(bool is_throttled,
- bool subtree_throttled) override;
+ bool subtree_throttled,
+ bool display_locked) override;
void VisibilityChanged(mojom::blink::FrameVisibility visibility) override;
void DidFocusFrame() override;
void CheckCompleted() override;
@@ -35,11 +37,11 @@ class FakeRemoteFrameHost : public mojom::blink::RemoteFrameHost {
const base::UnguessableToken& guid) override;
void SetIsInert(bool inert) override;
void DidChangeOpener(
- const base::Optional<base::UnguessableToken>& opener_frame) override;
+ const base::Optional<LocalFrameToken>& opener_frame) override;
void AdvanceFocus(blink::mojom::FocusType focus_type,
- const base::UnguessableToken& source_frame_token) override;
+ const LocalFrameToken& source_frame_token) override;
void RouteMessageEvent(
- const base::Optional<base::UnguessableToken>& source_frame_token,
+ const base::Optional<LocalFrameToken>& source_frame_token,
const String& source_origin,
const String& target_origin,
BlinkTransferableMessage message) override;
@@ -47,8 +49,11 @@ class FakeRemoteFrameHost : public mojom::blink::RemoteFrameHost {
int document_cookie) override;
void Detach() override;
void UpdateViewportIntersection(
- blink::mojom::blink::ViewportIntersectionStatePtr intersection_state)
- override;
+ blink::mojom::blink::ViewportIntersectionStatePtr intersection_state,
+ const base::Optional<FrameVisualProperties>& visual_properties) override;
+
+ void SynchronizeVisualProperties(
+ const blink::FrameVisualProperties& properties) override;
private:
void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle);
diff --git a/chromium/third_party/blink/renderer/core/testing/fake_web_plugin.h b/chromium/third_party/blink/renderer/core/testing/fake_web_plugin.h
index 93d00dad31f..cf5e751cfa0 100644
--- a/chromium/third_party/blink/renderer/core/testing/fake_web_plugin.h
+++ b/chromium/third_party/blink/renderer/core/testing/fake_web_plugin.h
@@ -55,10 +55,10 @@ class FakeWebPlugin : public WebPlugin {
void Destroy() override;
bool CanProcessDrag() const override { return false; }
void UpdateAllLifecyclePhases(blink::DocumentUpdateReason) override {}
- void Paint(cc::PaintCanvas*, const WebRect&) override {}
- void UpdateGeometry(const WebRect& client_rect,
- const WebRect& clip_rect,
- const WebRect& window_clip_rect,
+ void Paint(cc::PaintCanvas*, const gfx::Rect&) override {}
+ void UpdateGeometry(const gfx::Rect& client_rect,
+ const gfx::Rect& clip_rect,
+ const gfx::Rect& window_clip_rect,
bool is_visible) override {}
void UpdateFocus(bool, mojom::blink::FocusType) override {}
void UpdateVisibility(bool) override {}
diff --git a/chromium/third_party/blink/renderer/core/testing/internal_settings.cc b/chromium/third_party/blink/renderer/core/testing/internal_settings.cc
index 99aebc4f3a4..bb4fc83e71b 100644
--- a/chromium/third_party/blink/renderer/core/testing/internal_settings.cc
+++ b/chromium/third_party/blink/renderer/core/testing/internal_settings.cc
@@ -57,13 +57,16 @@
namespace blink {
+using mojom::blink::HoverType;
+using mojom::blink::PointerType;
+
InternalSettings::Backup::Backup(Settings* settings)
: original_csp_(RuntimeEnabledFeatures::
ExperimentalContentSecurityPolicyFeaturesEnabled()),
original_editing_behavior_(settings->GetEditingBehaviorType()),
- original_text_autosizing_enabled_(settings->TextAutosizingEnabled()),
+ original_text_autosizing_enabled_(settings->GetTextAutosizingEnabled()),
original_text_autosizing_window_size_override_(
- settings->TextAutosizingWindowSizeOverride()),
+ settings->GetTextAutosizingWindowSizeOverride()),
original_accessibility_font_scale_factor_(
settings->GetAccessibilityFontScaleFactor()),
original_media_type_override_(settings->GetMediaTypeOverride()),
@@ -121,7 +124,7 @@ void InternalSettings::ResetToConsistentState() {
backup_.RestoreTo(GetSettings());
backup_ = Backup(GetSettings());
backup_.original_text_autosizing_enabled_ =
- GetSettings()->TextAutosizingEnabled();
+ GetSettings()->GetTextAutosizingEnabled();
InternalSettingsGenerated::resetToConsistentState();
}
@@ -373,11 +376,11 @@ void InternalSettings::setAvailablePointerTypes(
String token = split_token.StripWhiteSpace();
if (token == "coarse") {
- pointer_types |= ui::POINTER_TYPE_COARSE;
+ pointer_types |= static_cast<int>(PointerType::kPointerCoarseType);
} else if (token == "fine") {
- pointer_types |= ui::POINTER_TYPE_FINE;
+ pointer_types |= static_cast<int>(PointerType::kPointerFineType);
} else if (token == "none") {
- pointer_types |= ui::POINTER_TYPE_NONE;
+ pointer_types |= static_cast<int>(PointerType::kPointerNone);
} else {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
@@ -418,13 +421,13 @@ void InternalSettings::setPrimaryPointerType(const String& pointer,
InternalSettingsGuardForSettings();
String token = pointer.StripWhiteSpace();
- ui::PointerType type = ui::POINTER_TYPE_NONE;
+ PointerType type = PointerType::kPointerNone;
if (token == "coarse") {
- type = ui::POINTER_TYPE_COARSE;
+ type = PointerType::kPointerCoarseType;
} else if (token == "fine") {
- type = ui::POINTER_TYPE_FINE;
+ type = PointerType::kPointerFineType;
} else if (token == "none") {
- type = ui::POINTER_TYPE_NONE;
+ type = PointerType::kPointerNone;
} else {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
@@ -448,9 +451,9 @@ void InternalSettings::setAvailableHoverTypes(const String& types,
for (const String& split_token : tokens) {
String token = split_token.StripWhiteSpace();
if (token == "none") {
- hover_types |= ui::HOVER_TYPE_NONE;
+ hover_types |= static_cast<int>(HoverType::kHoverNone);
} else if (token == "hover") {
- hover_types |= ui::HOVER_TYPE_HOVER;
+ hover_types |= static_cast<int>(HoverType::kHoverHoverType);
} else {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
@@ -467,11 +470,11 @@ void InternalSettings::setPrimaryHoverType(const String& type,
InternalSettingsGuardForSettings();
String token = type.StripWhiteSpace();
- ui::HoverType hover_type = ui::HOVER_TYPE_NONE;
+ HoverType hover_type = HoverType::kHoverNone;
if (token == "none") {
- hover_type = ui::HOVER_TYPE_NONE;
+ hover_type = HoverType::kHoverNone;
} else if (token == "hover") {
- hover_type = ui::HOVER_TYPE_HOVER;
+ hover_type = HoverType::kHoverHoverType;
} else {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.cc b/chromium/third_party/blink/renderer/core/testing/internals.cc
index eb3d6363d82..955af860a40 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.cc
+++ b/chromium/third_party/blink/renderer/core/testing/internals.cc
@@ -26,11 +26,15 @@
#include "third_party/blink/renderer/core/testing/internals.h"
+#include <atomic>
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "base/optional.h"
+#include "base/process/process_handle.h"
#include "cc/layers/picture_layer.h"
+#include "cc/trees/layer_tree_host.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/blink/public/common/widget/device_emulation_params.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
@@ -58,7 +62,6 @@
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/dom/tree_scope.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
@@ -102,7 +105,6 @@
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/forms/text_control_inner_elements.h"
-#include "third_party/blink/renderer/core/html/html_content_element.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
@@ -139,6 +141,13 @@
#include "third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
+#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/readable_stream_transferring_optimizer.h"
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
#include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/core/svg_names.h"
@@ -223,6 +232,373 @@ class UseCounterHelperObserverImpl final : public UseCounterHelper::Observer {
DISALLOW_COPY_AND_ASSIGN(UseCounterHelperObserverImpl);
};
+class TestReadableStreamSource : public UnderlyingSourceBase {
+ public:
+ class Generator;
+
+ using Reply = CrossThreadOnceFunction<void(std::unique_ptr<Generator>)>;
+ using OptimizerCallback =
+ CrossThreadOnceFunction<void(scoped_refptr<base::SingleThreadTaskRunner>,
+ Reply)>;
+
+ enum class Type {
+ kWithNullOptimizer,
+ kWithPerformNullOptimizer,
+ kWithObservableOptimizer,
+ kWithPerfectOptimizer,
+ };
+
+ class Generator final {
+ USING_FAST_MALLOC(Generator);
+
+ public:
+ explicit Generator(int max_count) : max_count_(max_count) {}
+
+ base::Optional<int> Generate() {
+ if (count_ >= max_count_) {
+ return base::nullopt;
+ }
+ ++count_;
+ return current_++;
+ }
+
+ void Add(int n) { current_ += n; }
+
+ private:
+ friend class Optimizer;
+
+ int current_ = 0;
+ int count_ = 0;
+ const int max_count_;
+ };
+
+ class Optimizer final : public ReadableStreamTransferringOptimizer {
+ USING_FAST_MALLOC(Optimizer);
+
+ public:
+ Optimizer(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ OptimizerCallback callback,
+ Type type)
+ : task_runner_(std::move(task_runner)),
+ callback_(std::move(callback)),
+ type_(type) {}
+
+ UnderlyingSourceBase* PerformInProcessOptimization(
+ ScriptState* script_state) override;
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ OptimizerCallback callback_;
+ const Type type_;
+ };
+
+ TestReadableStreamSource(ScriptState* script_state, Type type)
+ : UnderlyingSourceBase(script_state), type_(type) {}
+
+ ScriptPromise Start(ScriptState* script_state) override {
+ if (generator_) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ return resolver_->Promise();
+ }
+
+ ScriptPromise pull(ScriptState* script_state) override {
+ if (!generator_) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ const auto result = generator_->Generate();
+ if (!result) {
+ Controller()->Close();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ Controller()->Enqueue(*result);
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ std::unique_ptr<ReadableStreamTransferringOptimizer>
+ CreateTransferringOptimizer(ScriptState* script_state) {
+ switch (type_) {
+ case Type::kWithNullOptimizer:
+ return nullptr;
+ case Type::kWithPerformNullOptimizer:
+ return std::make_unique<ReadableStreamTransferringOptimizer>();
+ case Type::kWithObservableOptimizer:
+ case Type::kWithPerfectOptimizer:
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ return std::make_unique<Optimizer>(
+ context->GetTaskRunner(TaskType::kInternalDefault),
+ CrossThreadBindOnce(&TestReadableStreamSource::Detach,
+ WrapCrossThreadWeakPersistent(this)),
+ type_);
+ }
+ }
+
+ void Attach(std::unique_ptr<Generator> generator) {
+ if (type_ == Type::kWithObservableOptimizer) {
+ generator->Add(100);
+ }
+ generator_ = std::move(generator);
+ if (resolver_) {
+ resolver_->Resolve();
+ }
+ }
+
+ void Detach(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ Reply reply) {
+ Controller()->Close();
+ PostCrossThreadTask(
+ *task_runner, FROM_HERE,
+ CrossThreadBindOnce(std::move(reply), std::move(generator_)));
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(resolver_);
+ UnderlyingSourceBase::Trace(visitor);
+ }
+
+ private:
+ const Type type_;
+ std::unique_ptr<Generator> generator_;
+ Member<ScriptPromiseResolver> resolver_;
+};
+
+UnderlyingSourceBase*
+TestReadableStreamSource::Optimizer::PerformInProcessOptimization(
+ ScriptState* script_state) {
+ TestReadableStreamSource* source =
+ MakeGarbageCollected<TestReadableStreamSource>(script_state, type_);
+ ExecutionContext* context = ExecutionContext::From(script_state);
+
+ Reply reply = CrossThreadBindOnce(&TestReadableStreamSource::Attach,
+ WrapCrossThreadPersistent(source));
+
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(std::move(callback_),
+ context->GetTaskRunner(TaskType::kInternalDefault),
+ std::move(reply)));
+ return source;
+}
+
+class TestWritableStreamSink final : public UnderlyingSinkBase {
+ public:
+ class InternalSink;
+
+ using Reply = CrossThreadOnceFunction<void(std::unique_ptr<InternalSink>)>;
+ using OptimizerCallback =
+ CrossThreadOnceFunction<void(scoped_refptr<base::SingleThreadTaskRunner>,
+ Reply)>;
+ enum class Type {
+ kWithNullOptimizer,
+ kWithPerformNullOptimizer,
+ kWithObservableOptimizer,
+ kWithPerfectOptimizer,
+ };
+
+ class InternalSink final {
+ USING_FAST_MALLOC(InternalSink);
+
+ public:
+ InternalSink(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ CrossThreadOnceFunction<void(std::string)> success_callback,
+ CrossThreadOnceFunction<void()> error_callback)
+ : task_runner_(std::move(task_runner)),
+ success_callback_(std::move(success_callback)),
+ error_callback_(std::move(error_callback)) {}
+
+ void Append(const std::string& s) { result_.append(s); }
+ void Close() {
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(std::move(success_callback_), result_));
+ }
+ void Abort() {
+ PostCrossThreadTask(*task_runner_, FROM_HERE, std::move(error_callback_));
+ }
+
+ // We don't use WTF::String because this object can be accessed from
+ // multiple threads.
+ std::string result_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ CrossThreadOnceFunction<void(std::string)> success_callback_;
+ CrossThreadOnceFunction<void()> error_callback_;
+ };
+
+ class Optimizer final : public WritableStreamTransferringOptimizer {
+ USING_FAST_MALLOC(Optimizer);
+
+ public:
+ Optimizer(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ OptimizerCallback callback,
+ scoped_refptr<base::RefCountedData<std::atomic_bool>> optimizer_flag,
+ Type type)
+ : task_runner_(std::move(task_runner)),
+ callback_(std::move(callback)),
+ optimizer_flag_(std::move(optimizer_flag)),
+ type_(type) {}
+
+ UnderlyingSinkBase* PerformInProcessOptimization(
+ ScriptState* script_state) override;
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ OptimizerCallback callback_;
+ scoped_refptr<base::RefCountedData<std::atomic_bool>> optimizer_flag_;
+ const Type type_;
+ };
+
+ explicit TestWritableStreamSink(ScriptState* script_state, Type type)
+ : type_(type),
+ optimizer_flag_(
+ base::MakeRefCounted<base::RefCountedData<std::atomic_bool>>(
+ base::in_place,
+ false)) {}
+
+ ScriptPromise start(ScriptState* script_state,
+ WritableStreamDefaultController*,
+ ExceptionState&) override {
+ if (internal_sink_) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ start_resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ return start_resolver_->Promise();
+ }
+ ScriptPromise write(ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController*,
+ ExceptionState&) override {
+ DCHECK(internal_sink_);
+ internal_sink_->Append(
+ ToCoreString(chunk.V8Value()
+ ->ToString(script_state->GetContext())
+ .ToLocalChecked())
+ .Utf8());
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ ScriptPromise close(ScriptState* script_state, ExceptionState&) override {
+ DCHECK(internal_sink_);
+ closed_ = true;
+ if (!optimizer_flag_->data.load()) {
+ // The normal closure case.
+ internal_sink_->Close();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ // When the optimizer is active, we need to detach `internal_sink_` and
+ // pass it to the optimizer (i.e., the sink in the destination realm).
+ if (detached_) {
+ PostCrossThreadTask(
+ *reply_task_runner_, FROM_HERE,
+ CrossThreadBindOnce(std::move(reply_), std::move(internal_sink_)));
+ }
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ ScriptPromise abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState&) override {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ void Attach(std::unique_ptr<InternalSink> internal_sink) {
+ DCHECK(!internal_sink_);
+
+ if (type_ == Type::kWithObservableOptimizer) {
+ internal_sink->Append("A");
+ }
+
+ internal_sink_ = std::move(internal_sink);
+ if (start_resolver_) {
+ start_resolver_->Resolve();
+ }
+ }
+
+ void Detach(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ Reply reply) {
+ detached_ = true;
+
+ // We need to wait for the close signal before actually detaching
+ // `internal_sink_`.
+ if (closed_) {
+ PostCrossThreadTask(
+ *task_runner, FROM_HERE,
+ CrossThreadBindOnce(std::move(reply), std::move(internal_sink_)));
+ } else {
+ reply_ = std::move(reply);
+ reply_task_runner_ = std::move(task_runner);
+ }
+ }
+
+ std::unique_ptr<WritableStreamTransferringOptimizer>
+ CreateTransferringOptimizer(ScriptState* script_state) {
+ DCHECK(internal_sink_);
+
+ if (type_ == Type::kWithNullOptimizer) {
+ return nullptr;
+ }
+
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ return std::make_unique<Optimizer>(
+ context->GetTaskRunner(TaskType::kInternalDefault),
+ CrossThreadBindOnce(&TestWritableStreamSink::Detach,
+ WrapCrossThreadWeakPersistent(this)),
+ optimizer_flag_, type_);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(start_resolver_);
+ UnderlyingSinkBase::Trace(visitor);
+ }
+
+ static void Resolve(ScriptPromiseResolver* resolver, std::string result) {
+ resolver->Resolve(String::FromUTF8(result));
+ }
+ static void Reject(ScriptPromiseResolver* resolver) {
+ ScriptState* script_state = resolver->GetScriptState();
+ ScriptState::Scope scope(script_state);
+ resolver->Reject(
+ V8ThrowException::CreateTypeError(script_state->GetIsolate(), "error"));
+ }
+
+ private:
+ const Type type_;
+ // `optimizer_flag_` is always non_null. The flag referenced is false
+ // initially, and set atomically when the associated optimizer is activated.
+ scoped_refptr<base::RefCountedData<std::atomic_bool>> optimizer_flag_;
+ std::unique_ptr<InternalSink> internal_sink_;
+ Member<ScriptPromiseResolver> start_resolver_;
+ bool closed_ = false;
+ bool detached_ = false;
+ Reply reply_;
+ scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner_;
+};
+
+UnderlyingSinkBase*
+TestWritableStreamSink::Optimizer::PerformInProcessOptimization(
+ ScriptState* script_state) {
+ if (type_ == Type::kWithPerformNullOptimizer) {
+ return nullptr;
+ }
+ TestWritableStreamSink* sink =
+ MakeGarbageCollected<TestWritableStreamSink>(script_state, type_);
+
+ // Set the flag atomically, to notify that this optimizer is active.
+ optimizer_flag_->data.store(true);
+
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ Reply reply = CrossThreadBindOnce(&TestWritableStreamSink::Attach,
+ WrapCrossThreadPersistent(sink));
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(std::move(callback_),
+ context->GetTaskRunner(TaskType::kInternalDefault),
+ std::move(reply)));
+ return sink;
+}
+
} // namespace
static base::Optional<DocumentMarker::MarkerType> MarkerTypeFrom(
@@ -503,8 +879,7 @@ ScriptPromise Internals::getResourcePriority(ScriptState* script_state,
DCHECK(document);
auto callback = WTF::Bind(&Internals::ResolveResourcePriority,
- WTF::Passed(WrapPersistent(this)),
- WTF::Passed(WrapPersistent(resolver)));
+ WrapPersistent(this), WrapPersistent(resolver));
ResourceFetcher::AddPriorityObserverForTesting(resource_url,
std::move(callback));
@@ -532,19 +907,6 @@ String Internals::getResourceHeader(const String& url,
return resource->GetResourceRequest().HttpHeaderField(AtomicString(header));
}
-bool Internals::isValidContentSelect(Element* insertion_point,
- ExceptionState& exception_state) {
- DCHECK(insertion_point);
- if (!insertion_point->IsV0InsertionPoint()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
- "The element is not an insertion point.");
- return false;
- }
-
- auto* html_content_element = DynamicTo<HTMLContentElement>(insertion_point);
- return html_content_element && html_content_element->IsSelectValid();
-}
-
Node* Internals::treeScopeRootNode(Node* node) {
DCHECK(node);
return &node->GetTreeScope().RootNode();
@@ -598,7 +960,8 @@ void Internals::pauseAnimations(double pause_time,
return;
GetFrame()->View()->UpdateAllLifecyclePhasesForTest();
- GetFrame()->GetDocument()->Timeline().PauseAnimationsForTesting(pause_time);
+ GetFrame()->GetDocument()->Timeline().PauseAnimationsForTesting(
+ AnimationTimeDelta::FromSecondsD(pause_time));
}
bool Internals::isCompositedAnimation(Animation* animation) {
@@ -635,30 +998,6 @@ void Internals::advanceImageAnimation(Element* image,
image_data->AdvanceAnimationForTesting();
}
-bool Internals::hasShadowInsertionPoint(const Node* root,
- ExceptionState& exception_state) const {
- DCHECK(root);
- if (!IsA<ShadowRoot>(root)) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidAccessError,
- "The node argument is not a shadow root.");
- return false;
- }
- return To<ShadowRoot>(root)->V0().ContainsShadowElements();
-}
-
-bool Internals::hasContentElement(const Node* root,
- ExceptionState& exception_state) const {
- DCHECK(root);
- if (!IsA<ShadowRoot>(root)) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidAccessError,
- "The node argument is not a shadow root.");
- return false;
- }
- return To<ShadowRoot>(root)->V0().ContainsContentElements();
-}
-
uint32_t Internals::countElementShadow(const Node* root,
ExceptionState& exception_state) const {
DCHECK(root);
@@ -798,8 +1137,6 @@ String Internals::shadowRootType(const Node* root,
switch (shadow_root->GetType()) {
case ShadowRootType::kUserAgent:
return String("UserAgentShadowRoot");
- case ShadowRootType::V0:
- return String("V0ShadowRoot");
case ShadowRootType::kOpen:
return String("OpenShadowRoot");
case ShadowRootType::kClosed:
@@ -2989,6 +3326,15 @@ void Internals::forceCompositingUpdate(Document* document,
document->GetFrame()->View()->UpdateAllLifecyclePhasesForTest();
}
+void Internals::setForcedColorsAndDarkPreferredColorScheme(Document* document) {
+ DCHECK(document);
+ ColorSchemeHelper color_scheme_helper(*document);
+ color_scheme_helper.SetPreferredColorScheme(
+ mojom::blink::PreferredColorScheme::kDark);
+ color_scheme_helper.SetForcedColors(*document, ForcedColors::kActive);
+ document->GetFrame()->View()->UpdateAllLifecyclePhasesForTest();
+}
+
void Internals::setShouldRevealPassword(Element* element,
bool reveal,
ExceptionState& exception_state) {
@@ -3005,25 +3351,16 @@ void Internals::setShouldRevealPassword(Element* element,
namespace {
-class AddOneFunction : public ScriptFunction {
+class AddOneFunction : public NewScriptFunction::Callable {
public:
- static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
- AddOneFunction* self = MakeGarbageCollected<AddOneFunction>(script_state);
- return self->BindToV8Function();
- }
-
- explicit AddOneFunction(ScriptState* script_state)
- : ScriptFunction(script_state) {}
-
- private:
- ScriptValue Call(ScriptValue value) override {
+ ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
v8::Local<v8::Value> v8_value = value.V8Value();
DCHECK(v8_value->IsNumber());
int32_t int_value =
static_cast<int32_t>(v8_value.As<v8::Integer>()->Value());
return ScriptValue(
- GetScriptState()->GetIsolate(),
- v8::Integer::New(GetScriptState()->GetIsolate(), int_value + 1));
+ script_state->GetIsolate(),
+ v8::Integer::New(script_state->GetIsolate(), int_value + 1));
}
};
@@ -3047,7 +3384,8 @@ ScriptPromise Internals::createRejectedPromise(ScriptState* script_state,
ScriptPromise Internals::addOneToPromise(ScriptState* script_state,
ScriptPromise promise) {
- return promise.Then(AddOneFunction::CreateFunction(script_state));
+ return promise.Then(MakeGarbageCollected<NewScriptFunction>(
+ script_state, MakeGarbageCollected<AddOneFunction>()));
}
ScriptPromise Internals::promiseCheck(ScriptState* script_state,
@@ -3193,8 +3531,14 @@ String Internals::selectedTextForClipboard() {
void Internals::setVisualViewportOffset(int x, int y) {
if (!GetFrame())
return;
+ FloatPoint offset(x, y);
- GetFrame()->GetPage()->GetVisualViewport().SetLocation(FloatPoint(x, y));
+ // `setVisualViewportOffset()` inputs are in physical pixels, but
+ // `SetLocation()` gets positions in DIPs when --use-zoom-for-dsf disabled.
+ GetFrame()->GetPage()->GetVisualViewport().SetLocation(
+ Platform::Current()->IsUseZoomForDSFEnabled()
+ ? offset
+ : offset.ScaledBy(1 / GetFrame()->DevicePixelRatio()));
}
bool Internals::isUseCounted(Document* document, uint32_t feature) {
@@ -3206,13 +3550,13 @@ bool Internals::isUseCounted(Document* document, uint32_t feature) {
bool Internals::isCSSPropertyUseCounted(Document* document,
const String& property_name) {
return document->IsPropertyCounted(
- unresolvedCSSPropertyID(document->GetExecutionContext(), property_name));
+ UnresolvedCSSPropertyID(document->GetExecutionContext(), property_name));
}
bool Internals::isAnimatedCSSPropertyUseCounted(Document* document,
const String& property_name) {
return document->IsAnimatedPropertyCounted(
- unresolvedCSSPropertyID(document->GetExecutionContext(), property_name));
+ UnresolvedCSSPropertyID(document->GetExecutionContext(), property_name));
}
void Internals::clearUseCounter(Document* document, uint32_t feature) {
@@ -3246,7 +3590,7 @@ Vector<String> Internals::getCSSPropertyShorthands() const {
Vector<String> Internals::getCSSPropertyAliases() const {
Vector<String> result;
for (CSSPropertyID alias : kCSSPropertyAliasList) {
- DCHECK(isPropertyAlias(alias));
+ DCHECK(IsPropertyAlias(alias));
result.push_back(CSSUnresolvedProperty::GetAliasProperty(alias)
->GetPropertyNameString());
}
@@ -3395,10 +3739,6 @@ bool Internals::isTrackingOcclusionForIFrame(HTMLIFrameElement* iframe) const {
return remote_frame->View()->NeedsOcclusionTracking();
}
-void Internals::DisableFrequencyCappingForOverlayPopupDetection() const {
- OverlayInterstitialAdDetector::DisableFrequencyCappingForTesting();
-}
-
void Internals::addEmbedderCustomElementName(const AtomicString& name,
ExceptionState& exception_state) {
CustomElement::AddEmbedderCustomElementNameForTesting(name, exception_state);
@@ -3475,10 +3815,8 @@ String Internals::getAgentId(DOMWindow* window) {
if (!window->IsLocalDOMWindow())
return String();
- // Sounds like there's no notion of "process ID" in Blink, but the main
- // thread's thread ID serves for that purpose.
- PlatformThreadId process_id = Thread::MainThread()->ThreadId();
-
+ // Create a unique id from the process id and the address of the agent.
+ const base::ProcessId process_id = base::GetCurrentProcId();
uintptr_t agent_address =
reinterpret_cast<uintptr_t>(To<LocalDOMWindow>(window)->GetAgent());
@@ -3522,4 +3860,81 @@ void Internals::setIsAdSubframe(HTMLIFrameElement* iframe,
: blink::mojom::AdFrameType::kRootAd);
}
+ReadableStream* Internals::createReadableStream(
+ ScriptState* script_state,
+ int32_t queue_size,
+ const String& optimizer,
+ ExceptionState& exception_state) {
+ TestReadableStreamSource::Type type;
+ if (optimizer.IsEmpty()) {
+ type = TestReadableStreamSource::Type::kWithNullOptimizer;
+ } else if (optimizer == "perform-null") {
+ type = TestReadableStreamSource::Type::kWithPerformNullOptimizer;
+ } else if (optimizer == "observable") {
+ type = TestReadableStreamSource::Type::kWithObservableOptimizer;
+ } else if (optimizer == "perfect") {
+ type = TestReadableStreamSource::Type::kWithPerformNullOptimizer;
+ } else {
+ exception_state.ThrowRangeError(
+ "The \"optimizer\" parameter is not correctly set.");
+ return nullptr;
+ }
+ auto* source =
+ MakeGarbageCollected<TestReadableStreamSource>(script_state, type);
+ source->Attach(std::make_unique<TestReadableStreamSource::Generator>(10));
+ return ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, source, queue_size,
+ source->CreateTransferringOptimizer(script_state));
+}
+
+ScriptValue Internals::createWritableStreamAndSink(
+ ScriptState* script_state,
+ int32_t queue_size,
+ const String& optimizer,
+ ExceptionState& exception_state) {
+ TestWritableStreamSink::Type type;
+ if (optimizer.IsEmpty()) {
+ type = TestWritableStreamSink::Type::kWithNullOptimizer;
+ } else if (optimizer == "perform-null") {
+ type = TestWritableStreamSink::Type::kWithPerformNullOptimizer;
+ } else if (optimizer == "observable") {
+ type = TestWritableStreamSink::Type::kWithObservableOptimizer;
+ } else if (optimizer == "perfect") {
+ type = TestWritableStreamSink::Type::kWithPerfectOptimizer;
+ } else {
+ exception_state.ThrowRangeError(
+ "The \"optimizer\" parameter is not correctly set.");
+ return ScriptValue();
+ }
+
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto internal_sink = std::make_unique<TestWritableStreamSink::InternalSink>(
+ context->GetTaskRunner(TaskType::kInternalDefault),
+ CrossThreadBindOnce(&TestWritableStreamSink::Resolve,
+ WrapCrossThreadPersistent(resolver)),
+ CrossThreadBindOnce(&TestWritableStreamSink::Reject,
+ WrapCrossThreadPersistent(resolver)));
+ auto* sink = MakeGarbageCollected<TestWritableStreamSink>(script_state, type);
+
+ sink->Attach(std::move(internal_sink));
+ auto* stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, sink, queue_size,
+ sink->CreateTransferringOptimizer(script_state));
+
+ v8::Local<v8::Object> object = v8::Object::New(script_state->GetIsolate());
+ object
+ ->Set(script_state->GetContext(),
+ V8String(script_state->GetIsolate(), "stream"),
+ ToV8(stream, script_state))
+
+ .Check();
+ object
+ ->Set(script_state->GetContext(),
+ V8String(script_state->GetIsolate(), "sink"),
+ ToV8(resolver->Promise(), script_state))
+ .Check();
+ return ScriptValue(script_state->GetIsolate(), object);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.h b/chromium/third_party/blink/renderer/core/testing/internals.h
index 96de90eb180..c89c13ba5f3 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.h
+++ b/chromium/third_party/blink/renderer/core/testing/internals.h
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
+#include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -72,6 +73,7 @@ class Node;
class OriginTrialsTest;
class Page;
class Range;
+class ReadableStream;
class RecordTest;
class ScriptPromiseResolver;
class ScrollState;
@@ -122,8 +124,6 @@ class Internals final : public ScriptWrappable {
ShadowRoot* shadowRoot(Element* host);
String shadowRootType(const Node*, ExceptionState&) const;
- bool hasShadowInsertionPoint(const Node*, ExceptionState&) const;
- bool hasContentElement(const Node*, ExceptionState&) const;
uint32_t countElementShadow(const Node*, ExceptionState&) const;
const AtomicString& shadowPseudoId(Element*);
@@ -138,7 +138,6 @@ class Internals final : public ScriptWrappable {
// animation update for CSS and advance the SMIL timeline by one frame.
void advanceImageAnimation(Element* image, ExceptionState&);
- bool isValidContentSelect(Element* insertion_point, ExceptionState&);
Node* treeScopeRootNode(Node*);
Node* parentTreeScope(Node*);
uint16_t compareTreeScopePosition(const Node*,
@@ -472,6 +471,8 @@ class Internals final : public ScriptWrappable {
void forceCompositingUpdate(Document*, ExceptionState&);
+ void setForcedColorsAndDarkPreferredColorScheme(Document* document);
+
void setShouldRevealPassword(Element*, bool, ExceptionState&);
ScriptPromise createResolvedPromise(ScriptState*, ScriptValue);
@@ -596,8 +597,6 @@ class Internals final : public ScriptWrappable {
bool isSiteIsolated(HTMLIFrameElement* iframe) const;
bool isTrackingOcclusionForIFrame(HTMLIFrameElement* iframe) const;
- void DisableFrequencyCappingForOverlayPopupDetection() const;
-
void addEmbedderCustomElementName(const AtomicString& name, ExceptionState&);
LocalFrame* GetFrame() const;
@@ -614,6 +613,16 @@ class Internals final : public ScriptWrappable {
void setIsAdSubframe(HTMLIFrameElement* iframe,
ExceptionState& exception_state);
+ ReadableStream* createReadableStream(ScriptState* script_state,
+ int32_t queueSize,
+ const String& optimizer,
+ ExceptionState&);
+
+ ScriptValue createWritableStreamAndSink(ScriptState* script_state,
+ int32_t queueSize,
+ const String& optimizer,
+ ExceptionState&);
+
private:
Document* ContextDocument() const;
Vector<String> IconURLs(Document*, int icon_types_mask) const;
diff --git a/chromium/third_party/blink/renderer/core/testing/internals.idl b/chromium/third_party/blink/renderer/core/testing/internals.idl
index db1171d7e2f..af4e47d1c01 100644
--- a/chromium/third_party/blink/renderer/core/testing/internals.idl
+++ b/chromium/third_party/blink/renderer/core/testing/internals.idl
@@ -56,11 +56,8 @@
Node effectiveRootScroller(Document document);
[RaisesException] DOMString shadowRootType(Node root);
- [RaisesException] boolean hasShadowInsertionPoint(Node root);
- [RaisesException] boolean hasContentElement(Node root);
[RaisesException] unsigned long countElementShadow(Node Root);
DOMString shadowPseudoId(Element element);
- [RaisesException] boolean isValidContentSelect(Element contentElement);
Node treeScopeRootNode(Node node);
Node parentTreeScope(Node node);
[RaisesException] unsigned short compareTreeScopePosition(Node treeScope1, Node treeScope2);
@@ -298,6 +295,8 @@
[RaisesException] void forceCompositingUpdate(Document document);
+ void setForcedColorsAndDarkPreferredColorScheme(Document document);
+
[RaisesException] void setShouldRevealPassword(Element element, boolean reveal);
[CallWith=ScriptState] Promise<any> createResolvedPromise(any value);
@@ -415,11 +414,6 @@
// instances that track visibility.
boolean isTrackingOcclusionForIFrame(HTMLIFrameElement iframe);
- // Disable the frequency capping for overlay popup detection. This
- // eliminates the need to for waitings in web tests to trigger a detection
- // event.
- void DisableFrequencyCappingForOverlayPopupDetection();
-
// Declare that the given |name| is in use by the embedder via the custom
// element mechanism.
[RaisesException] void addEmbedderCustomElementName(DOMString name);
@@ -451,4 +445,9 @@
void generateTestReport(DOMString message);
[RaisesException] void setIsAdSubframe(HTMLIFrameElement iframe);
+
+ [RaisesException, CallWith=ScriptState] ReadableStream createReadableStream(long queueSize, DOMString optimizer);
+ // The return value consists of a WritableStream (.stream) and a promise of
+ // a sink object (.sink).
+ [RaisesException, CallWith=ScriptState] any createWritableStreamAndSink(long queueSize, DOMString optimizer);
};
diff --git a/chromium/third_party/blink/renderer/core/testing/intersection_observer_test_helper.h b/chromium/third_party/blink/renderer/core/testing/intersection_observer_test_helper.h
new file mode 100644
index 00000000000..785bb0fa0cf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/intersection_observer_test_helper.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_INTERSECTION_OBSERVER_TEST_HELPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_INTERSECTION_OBSERVER_TEST_HELPER_H_
+
+#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_delegate.h"
+#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_entry.h"
+
+namespace blink {
+
+class TestIntersectionObserverDelegate : public IntersectionObserverDelegate {
+ public:
+ explicit TestIntersectionObserverDelegate(Document& document)
+ : document_(document), call_count_(0) {}
+ // TODO(szager): Add tests for the synchronous delivery code path. There is
+ // already some indirect coverage by unit tests exercising features that rely
+ // on it, but we should have some direct coverage in here.
+ LocalFrameUkmAggregator::MetricId GetUkmMetricId() const override {
+ return LocalFrameUkmAggregator::kJavascriptIntersectionObserver;
+ }
+ IntersectionObserver::DeliveryBehavior GetDeliveryBehavior() const override {
+ return IntersectionObserver::kPostTaskToDeliver;
+ }
+ void Deliver(const HeapVector<Member<IntersectionObserverEntry>>& entries,
+ IntersectionObserver&) override {
+ call_count_++;
+ entries_.AppendVector(entries);
+ }
+ ExecutionContext* GetExecutionContext() const override {
+ return document_->GetExecutionContext();
+ }
+ int CallCount() const { return call_count_; }
+ int EntryCount() const { return entries_.size(); }
+ const IntersectionObserverEntry* LastEntry() const { return entries_.back(); }
+ void Clear() {
+ entries_.clear();
+ call_count_ = 0;
+ }
+ PhysicalRect LastIntersectionRect() const {
+ if (entries_.IsEmpty())
+ return PhysicalRect();
+ const IntersectionGeometry& geometry = entries_.back()->GetGeometry();
+ return geometry.IntersectionRect();
+ }
+
+ void Trace(Visitor* visitor) const override {
+ IntersectionObserverDelegate::Trace(visitor);
+ visitor->Trace(document_);
+ visitor->Trace(entries_);
+ }
+
+ private:
+ Member<Document> document_;
+ HeapVector<Member<IntersectionObserverEntry>> entries_;
+ int call_count_;
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_INTERSECTION_OBSERVER_TEST_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.cc b/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
index 120840e69ac..4cc25246733 100644
--- a/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
+++ b/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
@@ -100,6 +100,11 @@ void MockClipboardHost::ReadImage(mojom::ClipboardBuffer clipboard_buffer,
std::move(callback).Run(image_);
}
+void MockClipboardHost::ReadFiles(mojom::ClipboardBuffer clipboard_buffer,
+ ReadFilesCallback callback) {
+ std::move(callback).Run(mojom::blink::ClipboardFiles::New());
+}
+
void MockClipboardHost::ReadCustomData(mojom::ClipboardBuffer clipboard_buffer,
const String& type,
ReadCustomDataCallback callback) {
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.h b/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.h
index 7df1da1b2e8..b725a7ee672 100644
--- a/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.h
+++ b/chromium/third_party/blink/renderer/core/testing/mock_clipboard_host.h
@@ -43,6 +43,8 @@ class MockClipboardHost : public mojom::blink::ClipboardHost {
ReadRtfCallback callback) override;
void ReadImage(mojom::ClipboardBuffer clipboard_buffer,
ReadImageCallback callback) override;
+ void ReadFiles(mojom::ClipboardBuffer clipboard_buffer,
+ ReadFilesCallback callback) override;
void ReadCustomData(mojom::ClipboardBuffer clipboard_buffer,
const String& type,
ReadCustomDataCallback callback) override;
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_function_scope.cc b/chromium/third_party/blink/renderer/core/testing/mock_function_scope.cc
new file mode 100644
index 00000000000..998ac45fb17
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/mock_function_scope.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/core/testing/mock_function_scope.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+
+namespace blink {
+
+MockFunctionScope::MockFunctionScope(ScriptState* script_state)
+ : script_state_(script_state) {}
+
+MockFunctionScope::~MockFunctionScope() {
+ v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate());
+ for (MockFunction* mock_function : mock_functions_) {
+ testing::Mock::VerifyAndClearExpectations(mock_function);
+ }
+}
+
+v8::Local<v8::Function> MockFunctionScope::ExpectCall(String* captor) {
+ mock_functions_.push_back(
+ MakeGarbageCollected<MockFunction>(script_state_, captor));
+ EXPECT_CALL(*mock_functions_.back(), Call(testing::_));
+ return mock_functions_.back()->Bind();
+}
+
+v8::Local<v8::Function> MockFunctionScope::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> MockFunctionScope::ExpectNoCall() {
+ mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_));
+ EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0);
+ return mock_functions_.back()->Bind();
+}
+
+ACTION_P2(SaveValueIn, script_state, captor) {
+ *captor = ToCoreString(
+ arg0.V8Value()->ToString(script_state->GetContext()).ToLocalChecked());
+}
+
+MockFunctionScope::MockFunction::MockFunction(ScriptState* script_state)
+ : ScriptFunction(script_state) {
+ ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>());
+}
+
+MockFunctionScope::MockFunction::MockFunction(ScriptState* script_state,
+ String* captor)
+ : ScriptFunction(script_state) {
+ ON_CALL(*this, Call(testing::_))
+ .WillByDefault(
+ testing::DoAll(SaveValueIn(WrapPersistent(script_state), captor),
+ testing::ReturnArg<0>()));
+}
+
+v8::Local<v8::Function> MockFunctionScope::MockFunction::Bind() {
+ return BindToV8Function();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_function_scope.h b/chromium/third_party/blink/renderer/core/testing/mock_function_scope.h
new file mode 100644
index 00000000000..e575c5c8d87
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/mock_function_scope.h
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class ScriptState;
+class ScriptValue;
+
+class MockFunctionScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit MockFunctionScope(ScriptState*);
+ ~MockFunctionScope();
+
+ v8::Local<v8::Function> ExpectCall();
+ v8::Local<v8::Function> ExpectCall(String* captor);
+ v8::Local<v8::Function> ExpectNoCall();
+
+ private:
+ class MockFunction : public ScriptFunction {
+ public:
+ explicit MockFunction(ScriptState*);
+ // TODO(http://crbug.com/1159794): add other convenience methods that allow
+ // the test case to capture non-String values.
+ MockFunction(ScriptState*, String* captor);
+ v8::Local<v8::Function> Bind();
+ MOCK_METHOD1(Call, ScriptValue(ScriptValue));
+ };
+
+ ScriptState* script_state_;
+ Vector<Persistent<MockFunction>> mock_functions_;
+};
+
+} // namespace blink
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.cc b/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.cc
index 5c40b997035..16fb0903df5 100644
--- a/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.cc
+++ b/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.cc
@@ -15,4 +15,11 @@ void MockPolicyContainerHost::FlushForTesting() {
receiver_.FlushForTesting();
}
+void MockPolicyContainerHost::BindWithNewEndpoint(
+ mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
+ receiver) {
+ receiver.EnableUnassociatedUsage();
+ receiver_.Bind(std::move(receiver));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.h b/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.h
index 7f34a984e59..c2ededd4975 100644
--- a/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.h
+++ b/chromium/third_party/blink/renderer/core/testing/mock_policy_container_host.h
@@ -18,12 +18,26 @@ class MockPolicyContainerHost : public mojom::blink::PolicyContainerHost {
SetReferrerPolicy,
(network::mojom::ReferrerPolicy),
(override));
+ MOCK_METHOD(
+ void,
+ IssueKeepAliveHandle,
+ (mojo::PendingReceiver<mojom::blink::PolicyContainerHostKeepAliveHandle>),
+ (override));
MockPolicyContainerHost() = default;
+ // Wrapper around AssociatedReceiver::BindNewEndpointAndPassDedicatedRemote.
mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost>
BindNewEndpointAndPassDedicatedRemote();
+
+ // Wrapper around AssociatedReceiver::FlushForTesting.
void FlushForTesting();
+ // This does the same as BindNewEndpointAndPassDedicatedRemote, but allows the
+ // remote to be created first and the receiver to be passed in.
+ void BindWithNewEndpoint(
+ mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
+ receiver);
+
private:
mojo::AssociatedReceiver<mojom::blink::PolicyContainerHost> receiver_{this};
};
diff --git a/chromium/third_party/blink/renderer/core/testing/module_test_base.cc b/chromium/third_party/blink/renderer/core/testing/module_test_base.cc
index 9ddbd8dcc19..13b07bf4f11 100644
--- a/chromium/third_party/blink/renderer/core/testing/module_test_base.cc
+++ b/chromium/third_party/blink/renderer/core/testing/module_test_base.cc
@@ -3,12 +3,39 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/testing/module_test_base.h"
+#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
#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/script_source_location_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
namespace blink {
+v8::Local<v8::Module> ModuleTestBase::CompileModule(
+ v8::Isolate* isolate,
+ const char* source,
+ const KURL& url,
+ ExceptionState& exception_state) {
+ return CompileModule(isolate, String(source), url, exception_state);
+}
+
+v8::Local<v8::Module> ModuleTestBase::CompileModule(
+ v8::Isolate* isolate,
+ String source,
+ const KURL& url,
+ ExceptionState& exception_state) {
+ ModuleScriptCreationParams params(
+ /*source_url=*/url, /*base_url=*/url,
+ ScriptSourceLocationType::kExternalFile, ModuleType::kJavaScript,
+ ParkableString(source.Impl()), nullptr);
+ return ModuleRecord::Compile(isolate, params, ScriptFetchOptions(),
+ TextPosition::MinimumPosition(),
+ exception_state);
+}
+
void ParametrizedModuleTestBase::SetUp(bool use_top_level_await) {
if (use_top_level_await) {
feature_list_.InitAndEnableFeature(features::kTopLevelAwait);
@@ -78,7 +105,7 @@ v8::Local<v8::Value> ParametrizedModuleTestBase::GetResult(
}
ScriptPromise script_promise = result.GetPromise(script_state);
- v8::Local<v8::Promise> promise = script_promise.V8Value().As<v8::Promise>();
+ v8::Local<v8::Promise> promise = script_promise.V8Promise();
if (promise->State() == v8::Promise::kFulfilled) {
return promise->Result();
}
@@ -106,7 +133,7 @@ v8::Local<v8::Value> ParametrizedModuleTestBase::GetException(
ScriptEvaluationResult::ResultType::kSuccess);
ScriptPromise script_promise = result.GetPromise(script_state);
- v8::Local<v8::Promise> promise = script_promise.V8Value().As<v8::Promise>();
+ v8::Local<v8::Promise> promise = script_promise.V8Promise();
if (promise->State() == v8::Promise::kRejected) {
return promise->Result();
}
diff --git a/chromium/third_party/blink/renderer/core/testing/module_test_base.h b/chromium/third_party/blink/renderer/core/testing/module_test_base.h
index a9762b90a97..91b017ea9fd 100644
--- a/chromium/third_party/blink/renderer/core/testing/module_test_base.h
+++ b/chromium/third_party/blink/renderer/core/testing/module_test_base.h
@@ -9,12 +9,28 @@
#include "base/test/scoped_feature_list.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "v8/include/v8.h"
namespace blink {
+class ModuleTestBase {
+ public:
+ static v8::Local<v8::Module> CompileModule(
+ v8::Isolate*,
+ const char*,
+ const KURL&,
+ ExceptionState& state = DummyExceptionStateForTesting().ReturnThis());
+ static v8::Local<v8::Module> CompileModule(
+ v8::Isolate*,
+ String,
+ const KURL&,
+ ExceptionState& state = DummyExceptionStateForTesting().ReturnThis());
+};
+
// Helper used to enable or disable top-level await in parametrized tests.
-class ParametrizedModuleTestBase {
+class ParametrizedModuleTestBase : public ModuleTestBase {
protected:
void SetUp(bool use_top_level_await);
void TearDown() {}
diff --git a/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc b/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
index 5545bde85a4..1130e90eace 100644
--- a/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
+++ b/chromium/third_party/blink/renderer/core/testing/null_execution_context.cc
@@ -43,7 +43,8 @@ scoped_refptr<base::SingleThreadTaskRunner> NullExecutionContext::GetTaskRunner(
return Thread::Current()->GetTaskRunner();
}
-BrowserInterfaceBrokerProxy& NullExecutionContext::GetBrowserInterfaceBroker() {
+const BrowserInterfaceBrokerProxy&
+NullExecutionContext::GetBrowserInterfaceBroker() const {
return GetEmptyBrowserInterfaceBroker();
}
diff --git a/chromium/third_party/blink/renderer/core/testing/null_execution_context.h b/chromium/third_party/blink/renderer/core/testing/null_execution_context.h
index 24c97bb9e47..e7bc27c16d9 100644
--- a/chromium/third_party/blink/renderer/core/testing/null_execution_context.h
+++ b/chromium/third_party/blink/renderer/core/testing/null_execution_context.h
@@ -52,7 +52,7 @@ class NullExecutionContext : public GarbageCollected<NullExecutionContext>,
void CountUse(mojom::WebFeature) override {}
- BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() override;
+ const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() const override;
ExecutionContextToken GetExecutionContextToken() const final {
return token_;
diff --git a/chromium/third_party/blink/renderer/core/testing/page_test_base.cc b/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
index cd07e256f18..2926376ada6 100644
--- a/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
+++ b/chromium/third_party/blink/renderer/core/testing/page_test_base.cc
@@ -201,8 +201,8 @@ void PageTestBase::InsertStyleElement(const std::string& style_rules) {
void PageTestBase::NavigateTo(const KURL& url,
const WTF::HashMap<String, String>& headers) {
- auto params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
+ auto params = WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url);
for (const auto& header : headers)
params->response.SetHttpHeaderField(header.key, header.value);
diff --git a/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.cc b/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.cc
new file mode 100644
index 00000000000..ccaf85049e5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.cc
@@ -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.
+
+#include "third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h"
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom-blink.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/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+ScopedFakeUkmRecorder::ScopedFakeUkmRecorder()
+ : recorder_(std::make_unique<ukm::TestUkmRecorder>()) {
+ Platform::Current()->GetBrowserInterfaceBroker()->SetBinderForTesting(
+ ukm::mojom::UkmRecorderInterface::Name_,
+ WTF::BindRepeating(
+ [](ScopedFakeUkmRecorder* interface,
+ mojo::ScopedMessagePipeHandle handle) {
+ interface->SetHandle(std::move(handle));
+ },
+ WTF::Unretained(this)));
+}
+
+ScopedFakeUkmRecorder::~ScopedFakeUkmRecorder() {
+ Platform::Current()->GetBrowserInterfaceBroker()->SetBinderForTesting(
+ ukm::mojom::UkmRecorderInterface::Name_, {});
+}
+
+void ScopedFakeUkmRecorder::AddEntry(ukm::mojom::UkmEntryPtr entry) {
+ recorder_->AddEntry(std::move(entry));
+}
+
+void ScopedFakeUkmRecorder::UpdateSourceURL(int64_t source_id,
+ const std::string& url) {
+ recorder_->UpdateSourceURL(source_id, GURL(url));
+}
+
+void ScopedFakeUkmRecorder::ResetRecorder() {
+ recorder_ = std::make_unique<ukm::TestUkmRecorder>();
+}
+
+void ScopedFakeUkmRecorder::SetHandle(mojo::ScopedMessagePipeHandle handle) {
+ receiver_ =
+ std::make_unique<mojo::Receiver<ukm::mojom::UkmRecorderInterface>>(
+ this, mojo::PendingReceiver<ukm::mojom::UkmRecorderInterface>(
+ std::move(handle)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h b/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h
new file mode 100644
index 00000000000..c7423756c41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SCOPED_FAKE_UKM_RECORDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SCOPED_FAKE_UKM_RECORDER_H_
+
+#include "components/ukm/test_ukm_recorder.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace blink {
+
+// Class used to mock the UKM recorder living in the browser process and being
+// served UKM events over Mojo. When instantiated, this class will register
+// itself as the Mojo interface for the UkmRecorderInterface in the
+// BrowserInterfaceBroker. It will then forward UKM logging events to a
+// TestUkmRecorder instance it owns and make it available for validation.
+// Consumers of this class should make sure to instantiate it before any other
+// instance takes a dependency on that mojo interface.
+class ScopedFakeUkmRecorder : public ukm::mojom::UkmRecorderInterface {
+ public:
+ explicit ScopedFakeUkmRecorder();
+ ~ScopedFakeUkmRecorder() override;
+
+ // ukm::mojom::UkmRecorderInterface:
+ void AddEntry(ukm::mojom::UkmEntryPtr entry) override;
+ void UpdateSourceURL(int64_t source_id, const std::string& url) override;
+
+ void ResetRecorder();
+
+ ukm::TestUkmRecorder* recorder() { return recorder_.get(); }
+
+ private:
+ void SetHandle(mojo::ScopedMessagePipeHandle handle);
+
+ std::unique_ptr<mojo::Receiver<ukm::mojom::UkmRecorderInterface>> receiver_;
+ std::unique_ptr<ukm::TestUkmRecorder> recorder_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SCOPED_FAKE_UKM_RECORDER_H_
diff --git a/chromium/third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h b/chromium/third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h
index 4ae0ef4ba8e..44bbb12eea5 100644
--- a/chromium/third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h
+++ b/chromium/third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h
@@ -68,7 +68,7 @@ class ScopedMockOverlayScrollbars {
// platform independent.
if (use_mock_overlay_scrollbars_)
return true;
-#if defined(OS_ANDROID) || BUILDFLAG(IS_ASH)
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// Non-overlay scrollbar is not supported on Android and ChromeOS.
return false;
#else
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
index 29217bb4175..ca14a3522f7 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.cc
@@ -68,23 +68,25 @@ void SimCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
SkCanvas::onDrawPath(path, paint);
}
-void SimCanvas::onDrawImage(const SkImage* image,
- SkScalar left,
- SkScalar top,
- const SkPaint* paint) {
+void SimCanvas::onDrawImage2(const SkImage* image,
+ SkScalar left,
+ SkScalar top,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint) {
DrawScope scope;
AddCommand(CommandType::kImage);
- SkCanvas::onDrawImage(image, left, top, paint);
+ SkCanvas::onDrawImage2(image, left, top, sampling, paint);
}
-void SimCanvas::onDrawImageRect(const SkImage* image,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- SrcRectConstraint constraint) {
+void SimCanvas::onDrawImageRect2(const SkImage* image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint,
+ SrcRectConstraint constraint) {
DrawScope scope;
AddCommand(CommandType::kImage);
- SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
+ SkCanvas::onDrawImageRect2(image, src, dst, sampling, paint, constraint);
}
void SimCanvas::onDrawTextBlob(const SkTextBlob* blob,
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
index eaf713f1552..5e58a1ac595 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_canvas.h
@@ -57,12 +57,17 @@ class SimCanvas : public SkCanvas {
void onDrawPath(const SkPath&, const SkPaint&) override;
// Image
- void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
- void onDrawImageRect(const SkImage*,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint*,
- SrcRectConstraint) override;
+ void onDrawImage2(const SkImage*,
+ SkScalar,
+ SkScalar,
+ const SkSamplingOptions&,
+ const SkPaint*) override;
+ void onDrawImageRect2(const SkImage*,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions&,
+ const SkPaint*,
+ SrcRectConstraint) override;
// Text
void onDrawTextBlob(const SkTextBlob*,
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
index 92f9ed5276d..7dfb166b4f0 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
@@ -6,7 +6,6 @@
#include "cc/test/fake_layer_tree_frame_sink.h"
#include "cc/trees/render_frame_metadata_observer.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -37,20 +36,18 @@ void SimCompositor::SetWebView(
SimCanvas::Commands SimCompositor::BeginFrame(double time_delta_in_seconds,
bool raster) {
DCHECK(web_view_);
- DCHECK(!layer_tree_host()->defer_main_frame_update());
+ DCHECK(!LayerTreeHost()->defer_main_frame_update());
// Verify that the need for a BeginMainFrame has been registered, and would
// have caused the compositor to schedule one if we were using its scheduler.
DCHECK(NeedsBeginFrame());
DCHECK_GT(time_delta_in_seconds, 0);
- ClearAnimationScheduled();
-
last_frame_time_ += base::TimeDelta::FromSecondsD(time_delta_in_seconds);
SimCanvas::Commands commands;
paint_commands_ = &commands;
- layer_tree_host()->CompositeForTest(last_frame_time_, raster);
+ LayerTreeHost()->CompositeForTest(last_frame_time_, raster);
paint_commands_ = nullptr;
return commands;
@@ -81,4 +78,12 @@ void SimCompositor::DidBeginMainFrame() {
*paint_commands_ = PaintFrame();
}
+void SimCompositor::SetLayerTreeHost(cc::LayerTreeHost* layer_tree_host) {
+ layer_tree_host_ = layer_tree_host;
+}
+
+cc::LayerTreeHost* SimCompositor::LayerTreeHost() const {
+ return layer_tree_host_;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
index d0c070124c9..464d853b364 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_compositor.h
@@ -24,10 +24,10 @@ class WebViewImpl;
// only part of the layer was invalid.
//
// Note: This also does not support compositor driven animations.
-class SimCompositor final : public frame_test_helpers::TestWebWidgetClient {
+class SimCompositor final {
public:
SimCompositor();
- ~SimCompositor() override;
+ ~SimCompositor();
// When the compositor asks for a main frame, this WebViewImpl will have its
// lifecycle updated and be painted.
@@ -39,6 +39,9 @@ class SimCompositor final : public frame_test_helpers::TestWebWidgetClient {
// available on the WebViewImpl as well.
void SetWebView(WebViewImpl&, frame_test_helpers::TestWebViewClient&);
+ // Set the LayerTreeHost that the compositor is associated with.
+ void SetLayerTreeHost(cc::LayerTreeHost*);
+
// Executes the BeginMainFrame processing steps, an approximation of what
// cc::ThreadProxy::BeginMainFrame would do.
// If time is not specified a 60Hz frame rate time progression is used.
@@ -52,36 +55,38 @@ class SimCompositor final : public frame_test_helpers::TestWebWidgetClient {
// Helpers to query the state of the compositor from tests.
//
// Returns true if a main frame has been requested from blink, until the
- // BeginFrame() step occurs. The AnimationScheduled() checks if an explicit
- // requet for BeginFrame() was made, vs an implicit one by making changes
- // to the compositor's state.
+ // BeginFrame() step occurs.
bool NeedsBeginFrame() const {
- return AnimationScheduled() ||
- layer_tree_host()->RequestedMainFramePendingForTesting();
+ return LayerTreeHost()->RequestedMainFramePendingForTesting();
}
// Returns true if commits are deferred in the compositor. Since these tests
// use synchronous compositing through BeginFrame(), the deferred state has no
// real effect.
bool DeferMainFrameUpdate() const {
- return layer_tree_host()->defer_main_frame_update();
+ return LayerTreeHost()->defer_main_frame_update();
}
// Returns true if a selection is set on the compositor.
bool HasSelection() const {
- return layer_tree_host()->selection() != cc::LayerSelection();
+ return LayerTreeHost()->selection() != cc::LayerSelection();
}
// Returns the background color set on the compositor.
- SkColor background_color() { return layer_tree_host()->background_color(); }
+ SkColor background_color() const {
+ return LayerTreeHost()->background_color();
+ }
base::TimeTicks LastFrameTime() const { return last_frame_time_; }
+ // Called when the begin frame occured.
+ void DidBeginMainFrame();
+
+ cc::LayerTreeHost* LayerTreeHost() const;
+
private:
SimCanvas::Commands PaintFrame();
- // TestWebWidgetClient overrides:
- void DidBeginMainFrame() override;
-
WebViewImpl* web_view_ = nullptr;
frame_test_helpers::TestWebViewClient* test_web_view_client_ = nullptr;
+ cc::LayerTreeHost* layer_tree_host_ = nullptr;
base::TimeTicks last_frame_time_;
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
index df31ecd701d..8654d3ee26f 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.cc
@@ -47,13 +47,18 @@ void SimTest::SetUp() {
std::make_unique<frame_test_helpers::TestWebFrameClient>();
web_view_client_ = std::make_unique<frame_test_helpers::TestWebViewClient>();
page_ = std::make_unique<SimPage>();
- web_view_helper_ = std::make_unique<frame_test_helpers::WebViewHelper>();
+ web_view_helper_ =
+ std::make_unique<frame_test_helpers::WebViewHelper>(base::BindRepeating(
+ &SimTest::CreateTestWebFrameWidget, base::Unretained(this)));
- web_view_helper_->Initialize(web_frame_client_.get(), web_view_client_.get(),
- compositor_.get());
+ web_view_helper_->Initialize(web_frame_client_.get(), web_view_client_.get());
compositor_->SetWebView(WebView(), *web_view_client_);
page_->SetPage(WebView().GetPage());
local_frame_root_ = WebView().MainFrameImpl();
+ compositor_->SetLayerTreeHost(
+ local_frame_root_->FrameWidgetImpl()->LayerTreeHostForTesting());
+
+ WebView().MainFrameViewWidget()->Resize(gfx::Size(300, 200));
}
void SimTest::TearDown() {
@@ -83,10 +88,11 @@ void SimTest::InitializeRemote() {
page_->SetPage(WebView().GetPage());
web_frame_client_ =
std::make_unique<frame_test_helpers::TestWebFrameClient>();
- local_frame_root_ = frame_test_helpers::CreateLocalChild(
+ local_frame_root_ = web_view_helper_->CreateLocalChild(
*WebView().MainFrame()->ToWebRemoteFrame(), "local_frame_root",
- WebFrameOwnerProperties(), nullptr, web_frame_client_.get(),
- compositor_.get());
+ WebFrameOwnerProperties(), nullptr, web_frame_client_.get());
+ compositor_->SetLayerTreeHost(
+ local_frame_root_->FrameWidgetImpl()->LayerTreeHostForTesting());
}
void SimTest::LoadURL(const String& url_string) {
@@ -128,14 +134,14 @@ frame_test_helpers::TestWebViewClient& SimTest::WebViewClient() {
return *web_view_client_;
}
-frame_test_helpers::TestWebWidgetClient& SimTest::WebWidgetClient() {
- return *compositor_;
-}
-
frame_test_helpers::TestWebFrameClient& SimTest::WebFrameClient() {
return *web_frame_client_;
}
+SimWebFrameWidget& SimTest::GetWebFrameWidget() {
+ return *static_cast<SimWebFrameWidget*>(local_frame_root_->FrameWidgetImpl());
+}
+
SimCompositor& SimTest::Compositor() {
return *compositor_;
}
@@ -144,4 +150,51 @@ Vector<String>& SimTest::ConsoleMessages() {
return web_frame_client_->ConsoleMessages();
}
+SimWebFrameWidget* SimTest::CreateSimWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ SimCompositor* compositor) {
+ return MakeGarbageCollected<SimWebFrameWidget>(
+ compositor, std::move(pass_key), std::move(frame_widget_host),
+ std::move(frame_widget), std::move(widget_host), std::move(widget),
+ std::move(task_runner), frame_sink_id, hidden, never_composited,
+ is_for_child_local_root, is_for_nested_main_frame);
+}
+
+frame_test_helpers::TestWebFrameWidget* SimTest::CreateTestWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame) {
+ return CreateSimWebFrameWidget(
+ std::move(pass_key), std::move(frame_widget_host),
+ std::move(frame_widget), std::move(widget_host), std::move(widget),
+ std::move(task_runner), frame_sink_id, hidden, never_composited,
+ is_for_child_local_root, is_for_nested_main_frame, compositor_.get());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
index 1d5d8ffb211..cb301f5edbf 100644
--- a/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_test.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_network.h"
#include "third_party/blink/renderer/core/testing/sim/sim_page.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h"
namespace blink {
@@ -43,13 +44,50 @@ class SimTest : public testing::Test {
WebLocalFrameImpl& MainFrame();
WebLocalFrameImpl& LocalFrameRoot();
frame_test_helpers::TestWebViewClient& WebViewClient();
- frame_test_helpers::TestWebWidgetClient& WebWidgetClient();
frame_test_helpers::TestWebFrameClient& WebFrameClient();
+ SimWebFrameWidget& GetWebFrameWidget();
SimCompositor& Compositor();
Vector<String>& ConsoleMessages();
+ // Creates a SimWebFrameWidget. Subclasses can override this if the
+ // wish to create their own.
+ virtual SimWebFrameWidget* CreateSimWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ SimCompositor* compositor);
+
private:
+ frame_test_helpers::TestWebFrameWidget* CreateTestWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame);
+
// These are unique_ptrs in order to destroy them in TearDown. Subclasses
// may override Platform::Current() and these must shutdown before the
// subclass destructor.
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.cc b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.cc
new file mode 100644
index 00000000000..5edf4296655
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.cc
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h"
+
+#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
+
+namespace blink {
+
+void SimWebFrameWidget::DidBeginMainFrame() {
+ // Notify the SimCompositor before calling the super, as the
+ // overriden method will advance the lifecycle.
+ sim_compositor_->DidBeginMainFrame();
+ frame_test_helpers::TestWebFrameWidget::DidBeginMainFrame();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h
new file mode 100644
index 00000000000..1c80a306f59
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/testing/sim/sim_web_frame_widget.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_FRAME_WIDGET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_FRAME_WIDGET_H_
+
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+
+namespace blink {
+
+class SimCompositor;
+
+class SimWebFrameWidget : public frame_test_helpers::TestWebFrameWidget {
+ public:
+ template <typename... Args>
+ SimWebFrameWidget(SimCompositor* compositor, Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...),
+ sim_compositor_(compositor) {}
+
+ // WidgetBaseClient overrides.
+ void DidBeginMainFrame() override;
+
+ private:
+ SimCompositor* const sim_compositor_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_SIM_SIM_WEB_FRAME_WIDGET_H_
diff --git a/chromium/third_party/blink/renderer/core/testing/wait_for_event.cc b/chromium/third_party/blink/renderer/core/testing/wait_for_event.cc
index 405cc582410..479a05f86b2 100644
--- a/chromium/third_party/blink/renderer/core/testing/wait_for_event.cc
+++ b/chromium/third_party/blink/renderer/core/testing/wait_for_event.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/testing/wait_for_event.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/core/dom/element.h"
@@ -12,7 +12,7 @@ namespace blink {
WaitForEvent::WaitForEvent(Element* element, const AtomicString& name)
: element_(element), event_name_(name) {
element_->addEventListener(event_name_, this);
- ThreadState::HeapPointersOnStackScope scan_stack(ThreadState::Current());
+ HeapPointersOnStackScope scan_stack(ThreadState::Current());
run_loop_.Run();
}
diff --git a/chromium/third_party/blink/renderer/core/timing/DIR_METADATA b/chromium/third_party/blink/renderer/core/timing/DIR_METADATA
new file mode 100644
index 00000000000..8f13e49a253
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>PerformanceAPIs"
+}
+
+team_email: "speed-metrics-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/timing/OWNERS b/chromium/third_party/blink/renderer/core/timing/OWNERS
index afc8230f65f..9e3a2546556 100644
--- a/chromium/third_party/blink/renderer/core/timing/OWNERS
+++ b/chromium/third_party/blink/renderer/core/timing/OWNERS
@@ -1,4 +1 @@
npm@chromium.org
-
-# TEAM: speed-metrics-dev@chromium.org
-# COMPONENT: Blink>PerformanceAPIs
diff --git a/chromium/third_party/blink/renderer/core/timing/build.gni b/chromium/third_party/blink/renderer/core/timing/build.gni
index f0b692b53a3..016200a206b 100644
--- a/chromium/third_party/blink/renderer/core/timing/build.gni
+++ b/chromium/third_party/blink/renderer/core/timing/build.gni
@@ -17,8 +17,6 @@ blink_core_sources_timing = [
"layout_shift_attribution.h",
"measure_memory/measure_memory_controller.cc",
"measure_memory/measure_memory_controller.h",
- "measure_memory/measure_memory_delegate.cc",
- "measure_memory/measure_memory_delegate.h",
"memory_info.cc",
"memory_info.h",
"performance.cc",
diff --git a/chromium/third_party/blink/renderer/core/timing/event_timing.cc b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
index 3b3b1fa63b9..ad1207b4190 100644
--- a/chromium/third_party/blink/renderer/core/timing/event_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
@@ -116,14 +116,6 @@ void EventTiming::DidDispatchEvent(const Event& event, Document& document) {
performance_->RegisterEventTiming(event.type(), event_timestamp_,
processing_start_, processing_end,
event.cancelable(), target);
- if (should_log_event_) {
- InteractiveDetector* interactive_detector =
- InteractiveDetector::From(document);
- if (interactive_detector) {
- interactive_detector->RecordInputEventTimingUKM(
- event, event_timestamp_, processing_start_, processing_end);
- }
- }
}
// static
diff --git a/chromium/third_party/blink/renderer/core/timing/largest_contentful_paint.h b/chromium/third_party/blink/renderer/core/timing/largest_contentful_paint.h
index bbebf97d0ca..97b66eb1e53 100644
--- a/chromium/third_party/blink/renderer/core/timing/largest_contentful_paint.h
+++ b/chromium/third_party/blink/renderer/core/timing/largest_contentful_paint.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/timing/performance_entry.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -51,6 +52,14 @@ class CORE_EXPORT LargestContentfulPaint final : public PerformanceEntry {
WeakMember<Element> element_;
};
+template <>
+struct DowncastTraits<LargestContentfulPaint> {
+ static bool AllowFrom(const PerformanceEntry& entry) {
+ return entry.EntryTypeEnum() ==
+ PerformanceEntry::EntryType::kLargestContentfulPaint;
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_LARGEST_CONTENTFUL_PAINT_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/layout_shift.h b/chromium/third_party/blink/renderer/core/timing/layout_shift.h
index f20e951713e..fcf9987b5ca 100644
--- a/chromium/third_party/blink/renderer/core/timing/layout_shift.h
+++ b/chromium/third_party/blink/renderer/core/timing/layout_shift.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/timing/layout_shift_attribution.h"
#include "third_party/blink/renderer/core/timing/performance_entry.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -45,7 +46,7 @@ class CORE_EXPORT LayoutShift final : public PerformanceEntry {
bool hadRecentInput() const { return had_recent_input_; }
double lastInputTime() const { return most_recent_input_timestamp_; }
- AttributionList sources() const { return sources_; }
+ const AttributionList& sources() const { return sources_; }
void Trace(Visitor*) const override;
@@ -58,6 +59,13 @@ class CORE_EXPORT LayoutShift final : public PerformanceEntry {
AttributionList sources_;
};
+template <>
+struct DowncastTraits<LayoutShift> {
+ static bool AllowFrom(const PerformanceEntry& entry) {
+ return entry.EntryTypeEnum() == PerformanceEntry::EntryType::kLayoutShift;
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_LAYOUT_SHIFT_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.cc b/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.cc
index 1da6afd1bf0..791652df91f 100644
--- a/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.cc
+++ b/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.cc
@@ -31,6 +31,10 @@ Node* LayoutShiftAttribution::node() const {
return Performance::CanExposeNode(node_) ? node_ : nullptr;
}
+Node* LayoutShiftAttribution::rawNodeForInspector() const {
+ return node_;
+}
+
DOMRectReadOnly* LayoutShiftAttribution::previousRect() const {
return previous_rect_;
}
diff --git a/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.h b/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.h
index 62fa9253d2e..8b4fef906ea 100644
--- a/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.h
+++ b/chromium/third_party/blink/renderer/core/timing/layout_shift_attribution.h
@@ -11,6 +11,7 @@
namespace blink {
class DOMRectReadOnly;
+class Node;
class ScriptState;
class ScriptValue;
@@ -27,6 +28,9 @@ class CORE_EXPORT LayoutShiftAttribution : public ScriptWrappable {
~LayoutShiftAttribution() override;
Node* node() const;
+ // Return node_ unconditionally, skipping the checks that apply
+ // to exposing it through bindings.
+ Node* rawNodeForInspector() const;
DOMRectReadOnly* previousRect() const;
DOMRectReadOnly* currentRect() const;
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS b/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS
new file mode 100644
index 00000000000..ccae9082083
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/OWNERS
@@ -0,0 +1 @@
+ulan@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
deleted file mode 100644
index d319cef8df4..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
+++ /dev/null
@@ -1,11 +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.
-
-// https://github.com/WICG/performance-measure-memory
-
-// The result of performance.measureMemory().
-dictionary MeasureMemory {
- required unsigned long long bytes;
- required sequence<MeasureMemoryBreakdown> breakdown;
-};
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl
deleted file mode 100644
index e90820e6bda..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_breakdown.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://github.com/ulan/performance-measure-memory.
-
-// A single entry of performance.measureMemory() result.
-dictionary MeasureMemoryBreakdown {
- unsigned long long bytes;
- sequence<DOMString> attribution;
- sequence<DOMString> userAgentSpecificTypes;
-};
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
index 1a0aab598a2..3759664a803 100644
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -4,38 +4,56 @@
#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h"
-#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h"
-
+#include <algorithm>
+#include "base/rand_util.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
+#include "third_party/blink/public/common/features.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/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution_container.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.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/settings.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/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "v8/include/v8.h"
+using performance_manager::mojom::blink::WebMemoryAttribution;
+using performance_manager::mojom::blink::WebMemoryAttributionPtr;
+using performance_manager::mojom::blink::WebMemoryBreakdownEntryPtr;
+using performance_manager::mojom::blink::WebMemoryMeasurement;
+using performance_manager::mojom::blink::WebMemoryMeasurementPtr;
+using performance_manager::mojom::blink::WebMemoryUsagePtr;
+
namespace blink {
-static MeasureMemoryController::V8MemoryReporter*
- g_dedicated_worker_memory_reporter_ = nullptr;
+namespace {
-void MeasureMemoryController::SetDedicatedWorkerMemoryReporter(
- V8MemoryReporter* reporter) {
- g_dedicated_worker_memory_reporter_ = reporter;
-}
+// String constants used for building the result.
+constexpr const char* kCrossOriginUrl = "cross-origin-url";
+constexpr const char* kMemoryTypeDom = "DOM";
+constexpr const char* kMemoryTypeJavaScript = "JavaScript";
+constexpr const char* kMemoryTypeShared = "Shared";
+constexpr const char* kScopeCrossOriginAggregated = "cross-origin-aggregated";
+constexpr const char* kScopeDedicatedWorker = "DedicatedWorker";
+constexpr const char* kScopeWindow = "Window";
+
+} // anonymous namespace
MeasureMemoryController::MeasureMemoryController(
- util::PassKey<MeasureMemoryController>,
+ base::PassKey<MeasureMemoryController>,
v8::Isolate* isolate,
v8::Local<v8::Context> context,
v8::Local<v8::Promise::Resolver> promise_resolver)
@@ -51,17 +69,77 @@ MeasureMemoryController::MeasureMemoryController(
void MeasureMemoryController::Trace(Visitor* visitor) const {
visitor->Trace(promise_resolver_);
- visitor->Trace(main_result_);
- visitor->Trace(worker_result_);
}
+namespace {
+
+enum class ApiStatus {
+ kAvailable,
+ kNotAvailableDueToFlag,
+ kNotAvailableDueToDetachedContext,
+ kNotAvailableDueToCrossOriginContext,
+ kNotAvailableDueToCrossOriginIsolation,
+ kNotAvailableDueToResourceCoordinator,
+};
+
+ApiStatus CheckMeasureMemoryAvailability(LocalDOMWindow* window) {
+ if (!base::FeatureList::IsEnabled(
+ features::kWebMeasureMemoryViaPerformanceManager)) {
+ return ApiStatus::kNotAvailableDueToFlag;
+ }
+ if (!window) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+ LocalFrame* local_frame = window->GetFrame();
+ if (!local_frame) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+ if (!window->CrossOriginIsolatedCapability() &&
+ local_frame->GetSettings()->GetWebSecurityEnabled()) {
+ return ApiStatus::kNotAvailableDueToCrossOriginIsolation;
+ }
+
+ // We need DocumentResourceCoordinator to query PerformanceManager.
+ if (!window->document()) {
+ return ApiStatus::kNotAvailableDueToDetachedContext;
+ }
+
+ if (!window->document()->GetResourceCoordinator()) {
+ return ApiStatus::kNotAvailableDueToResourceCoordinator;
+ }
+
+ return ApiStatus::kAvailable;
+}
+
+} // anonymous namespace
+
ScriptPromise MeasureMemoryController::StartMeasurement(
ScriptState* script_state,
ExceptionState& exception_state) {
- if (!IsMeasureMemoryAvailable(LocalDOMWindow::From(script_state))) {
- exception_state.ThrowSecurityError(
- "performance.measureMemory is not available in this context");
- return ScriptPromise();
+ switch (auto status = CheckMeasureMemoryAvailability(
+ LocalDOMWindow::From(script_state))) {
+ case ApiStatus::kAvailable:
+ break;
+ case ApiStatus::kNotAvailableDueToFlag:
+ case ApiStatus::kNotAvailableDueToResourceCoordinator:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not available.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToDetachedContext:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not supported"
+ " in detached iframes.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToCrossOriginContext:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory is not supported"
+ " in cross-origin iframes.");
+ return ScriptPromise();
+ case ApiStatus::kNotAvailableDueToCrossOriginIsolation:
+ exception_state.ThrowSecurityError(
+ "performance.measureUserAgentSpecificMemory requires"
+ " cross-origin isolation.");
+ return ScriptPromise();
}
v8::Isolate* isolate = script_state->GetIsolate();
v8::TryCatch try_catch(isolate);
@@ -71,73 +149,143 @@ ScriptPromise MeasureMemoryController::StartMeasurement(
exception_state.RethrowV8Exception(try_catch.Exception());
return ScriptPromise();
}
- v8::MeasureMemoryExecution execution =
+ auto measurement_mode =
RuntimeEnabledFeatures::ForceEagerMeasureMemoryEnabled(
ExecutionContext::From(script_state))
- ? v8::MeasureMemoryExecution::kEager
- : v8::MeasureMemoryExecution::kDefault;
+ ? WebMemoryMeasurement::Mode::kEager
+ : WebMemoryMeasurement::Mode::kDefault;
auto* impl = MakeGarbageCollected<MeasureMemoryController>(
- util::PassKey<MeasureMemoryController>(), isolate, context,
+ base::PassKey<MeasureMemoryController>(), isolate, context,
promise_resolver);
+ Document* document = LocalDOMWindow::From(script_state)->document();
+ document->GetResourceCoordinator()->OnWebMemoryMeasurementRequested(
+ measurement_mode, WTF::Bind(&MeasureMemoryController::MeasurementComplete,
+ WrapPersistent(impl)));
- isolate->MeasureMemory(
- std::make_unique<MeasureMemoryDelegate>(
- isolate, context,
- WTF::Bind(&MeasureMemoryController::MainMeasurementComplete,
- WrapPersistent(impl))),
- execution);
- if (g_dedicated_worker_memory_reporter_) {
- g_dedicated_worker_memory_reporter_->GetMemoryUsage(
- WTF::Bind(&MeasureMemoryController::WorkerMeasurementComplete,
- WrapPersistent(impl)),
-
- execution);
- } else {
- HeapVector<Member<MeasureMemoryBreakdown>> result;
- impl->WorkerMeasurementComplete(result);
- }
return ScriptPromise(script_state, promise_resolver->GetPromise());
}
-bool MeasureMemoryController::IsMeasureMemoryAvailable(LocalDOMWindow* window) {
- // TODO(ulan): We should check for window.crossOriginIsolated when it ships.
- // Until then we enable the API only for processes locked to a site
- // similar to the precise mode of the legacy performance.memory API.
- if (!Platform::Current()->IsLockedToSite()) {
- return false;
+
+namespace {
+
+// Satisfies the requirements of UniformRandomBitGenerator from C++ standard.
+// It is used in std::shuffle calls below.
+struct RandomBitGenerator {
+ using result_type = size_t;
+ static constexpr size_t min() { return 0; }
+ static constexpr size_t max() {
+ return static_cast<size_t>(std::numeric_limits<int>::max());
+ }
+ size_t operator()() {
+ return static_cast<size_t>(base::RandInt(min(), max()));
+ }
+};
+
+// These functions convert WebMemory* mojo structs to IDL and JS values.
+WTF::AtomicString ConvertScope(WebMemoryAttribution::Scope scope) {
+ using Scope = WebMemoryAttribution::Scope;
+ switch (scope) {
+ case Scope::kDedicatedWorker:
+ return kScopeDedicatedWorker;
+ case Scope::kWindow:
+ return kScopeWindow;
+ case Scope::kCrossOriginAggregated:
+ return kScopeCrossOriginAggregated;
+ }
+}
+
+MemoryAttributionContainer* ConvertContainer(
+ const WebMemoryAttributionPtr& attribution) {
+ if (!attribution->src && !attribution->id) {
+ return nullptr;
}
- // The window.crossOriginIsolated will be true only for the top-level frame.
- // Until the flag is available we check for the top-level condition manually.
- if (!window) {
- return false;
+ auto* result = MemoryAttributionContainer::Create();
+ result->setSrc(attribution->src);
+ result->setId(attribution->id);
+ return result;
+}
+
+MemoryAttribution* ConvertAttribution(
+ const WebMemoryAttributionPtr& attribution) {
+ auto* result = MemoryAttribution::Create();
+ if (attribution->url) {
+ result->setUrl(attribution->url);
+ } else {
+ result->setUrl(kCrossOriginUrl);
}
- LocalFrame* local_frame = window->GetFrame();
- if (!local_frame || !local_frame->IsMainFrame()) {
- return false;
+ result->setScope(ConvertScope(attribution->scope));
+ result->setContainer(ConvertContainer(attribution));
+ return result;
+}
+
+MemoryBreakdownEntry* ConvertBreakdown(
+ const WebMemoryBreakdownEntryPtr& breakdown_entry) {
+ auto* result = MemoryBreakdownEntry::Create();
+ DCHECK(breakdown_entry->memory);
+ result->setBytes(breakdown_entry->memory->bytes);
+ HeapVector<Member<MemoryAttribution>> attribution;
+ for (const auto& entry : breakdown_entry->attribution) {
+ attribution.push_back(ConvertAttribution(entry));
}
- return true;
+ result->setAttribution(attribution);
+ result->setTypes({WTF::AtomicString(kMemoryTypeJavaScript)});
+ return result;
}
-void MeasureMemoryController::MainMeasurementComplete(Result result) {
- DCHECK(!main_measurement_completed_);
- main_result_ = result;
- main_measurement_completed_ = true;
- MaybeResolvePromise();
+MemoryBreakdownEntry* CreateUnattributedBreakdown(
+ const WebMemoryUsagePtr& memory,
+ const WTF::String& memory_type) {
+ auto* result = MemoryBreakdownEntry::Create();
+ DCHECK(memory);
+ result->setBytes(memory->bytes);
+ result->setAttribution({});
+ Vector<String> types;
+ types.push_back(memory_type);
+ result->setTypes(types);
+ return result;
}
-void MeasureMemoryController::WorkerMeasurementComplete(Result result) {
- DCHECK(!worker_measurement_completed_);
- worker_result_ = result;
- worker_measurement_completed_ = true;
- MaybeResolvePromise();
+MemoryBreakdownEntry* EmptyBreakdown() {
+ auto* result = MemoryBreakdownEntry::Create();
+ result->setBytes(0);
+ result->setAttribution({});
+ result->setTypes({});
+ return result;
}
-void MeasureMemoryController::MaybeResolvePromise() {
- if (!main_measurement_completed_ || !worker_measurement_completed_) {
- // Wait until we have all results.
- return;
+MemoryMeasurement* ConvertResult(const WebMemoryMeasurementPtr& measurement) {
+ HeapVector<Member<MemoryBreakdownEntry>> breakdown;
+ for (const auto& entry : measurement->breakdown) {
+ // Skip breakdowns that didn't get a measurement.
+ if (entry->memory)
+ breakdown.push_back(ConvertBreakdown(entry));
}
+ // Add breakdowns for memory that isn't attributed to an execution context.
+ breakdown.push_back(CreateUnattributedBreakdown(measurement->shared_memory,
+ kMemoryTypeShared));
+ breakdown.push_back(
+ CreateUnattributedBreakdown(measurement->blink_memory, kMemoryTypeDom));
+ // TODO(1085129): Report memory usage of detached frames once implemented.
+ // Add an empty breakdown entry as required by the spec.
+ // See https://github.com/WICG/performance-measure-memory/issues/10.
+ breakdown.push_back(EmptyBreakdown());
+ // Randomize the order of the entries as required by the spec.
+ std::shuffle(breakdown.begin(), breakdown.end(), RandomBitGenerator{});
+ size_t bytes = 0;
+ for (auto entry : breakdown) {
+ bytes += entry->bytes();
+ }
+ auto* result = MemoryMeasurement::Create();
+ result->setBreakdown(breakdown);
+ result->setBytes(bytes);
+ return result;
+}
+
+} // anonymous namespace
+
+void MeasureMemoryController::MeasurementComplete(
+ WebMemoryMeasurementPtr measurement) {
if (context_.IsEmpty()) {
// The context was garbage collected in the meantime.
return;
@@ -145,15 +293,7 @@ void MeasureMemoryController::MaybeResolvePromise() {
v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Context> context = context_.NewLocal(isolate_);
v8::Context::Scope context_scope(context);
- MeasureMemory* result = MeasureMemory::Create();
- auto breakdown = main_result_;
- breakdown.AppendVector(worker_result_);
- size_t total_size = 0;
- for (auto entry : breakdown) {
- total_size += entry->bytes();
- }
- result->setBytes(total_size);
- result->setBreakdown(breakdown);
+ auto* result = ConvertResult(measurement);
v8::Local<v8::Promise::Resolver> promise_resolver =
promise_resolver_.NewLocal(isolate_);
promise_resolver->Resolve(context, ToV8(result, promise_resolver, isolate_))
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
index 6a59e0c99b3..b20ab9ed6ff 100644
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
@@ -5,7 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_CONTROLLER_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
@@ -16,12 +17,10 @@
namespace blink {
-class LocalDOMWindow;
-class MeasureMemoryBreakdown;
class ScriptState;
class ExceptionState;
-// The implementation of Performance.measureMemory() Web API.
+// The implementation of performance.measureUserAgentSpecificMemory() Web API.
// It is responsible for:
// 1. Starting an asynchronous memory measurement of the main V8 isolate.
// 2. Starting an asynchronous memory measurement of dedicated workers.
@@ -30,24 +29,9 @@ class ExceptionState;
class MeasureMemoryController final
: public GarbageCollected<MeasureMemoryController> {
public:
- using Result = HeapVector<Member<MeasureMemoryBreakdown>>;
- using ResultCallback = base::OnceCallback<void(Result)>;
-
- // PerformanceManager in blink/renderer/controller uses this interface
- // to provide an implementation of memory measurement for dedicated workers.
- //
- // It will be removed in the future when performance.measureMemory switches
- // to a mojo-based implementation that queries PerformanceManager in the
- // browser process.
- class V8MemoryReporter {
- public:
- virtual void GetMemoryUsage(MeasureMemoryController::ResultCallback,
- v8::MeasureMemoryExecution) = 0;
- };
-
// Private constructor guarded by PassKey. Use the StartMeasurement() wrapper
// to construct the object and start the measurement.
- MeasureMemoryController(util::PassKey<MeasureMemoryController>,
+ MeasureMemoryController(base::PassKey<MeasureMemoryController>,
v8::Isolate*,
v8::Local<v8::Context>,
v8::Local<v8::Promise::Resolver>);
@@ -58,25 +42,14 @@ class MeasureMemoryController final
void Trace(Visitor* visitor) const;
- // The entry point for injecting dependency on PerformanceManager.
- CORE_EXPORT static void SetDedicatedWorkerMemoryReporter(V8MemoryReporter*);
-
private:
- static bool IsMeasureMemoryAvailable(LocalDOMWindow* window);
// Invoked when the memory of the main V8 isolate is measured.
- void MainMeasurementComplete(Result);
- // Invoked when the memory of all dedicated workers is measured.
- void WorkerMeasurementComplete(Result);
- // Resolves the JS promise if both pending measurements are done.
- void MaybeResolvePromise();
+ void MeasurementComplete(
+ performance_manager::mojom::blink::WebMemoryMeasurementPtr);
v8::Isolate* isolate_;
ScopedPersistent<v8::Context> context_;
TraceWrapperV8Reference<v8::Promise::Resolver> promise_resolver_;
- Result main_result_;
- Result worker_result_;
- bool main_measurement_completed_ = false;
- bool worker_measurement_completed_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc
deleted file mode 100644
index 28f6202d87e..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc
+++ /dev/null
@@ -1,286 +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/core/timing/measure_memory/measure_memory_delegate.h"
-
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/web/web_frame.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_measure_memory_breakdown.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/frame.h"
-#include "third_party/blink/renderer/core/frame/frame_owner.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/html/html_frame_owner_element.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-
-namespace blink {
-
-MeasureMemoryDelegate::MeasureMemoryDelegate(v8::Isolate* isolate,
- v8::Local<v8::Context> context,
- ResultCallback callback)
- : isolate_(isolate),
- context_(isolate, context),
- callback_(std::move(callback)) {
- context_.SetPhantom();
-}
-
-// Returns true if the given context should be included in the current memory
-// measurement. Currently it is very conservative and allows only the same
-// origin contexts that belong to the same JavaScript origin.
-// With COOP/COEP we will be able to relax this restriction for the contexts
-// that opt-in into memory measurement.
-bool MeasureMemoryDelegate::ShouldMeasure(v8::Local<v8::Context> context) {
- if (context_.IsEmpty()) {
- // The original context was garbage collected in the meantime.
- return false;
- }
- v8::Local<v8::Context> original_context = context_.NewLocal(isolate_);
- ExecutionContext* original_execution_context =
- ExecutionContext::From(original_context);
- ExecutionContext* execution_context = ExecutionContext::From(context);
- if (!original_execution_context || !execution_context) {
- // One of the contexts is detached or is created by DevTools.
- return false;
- }
- if (original_execution_context->GetAgent() != execution_context->GetAgent()) {
- // Context do not belong to the same JavaScript agent.
- return false;
- }
- if (ScriptState::From(context)->World().IsIsolatedWorld()) {
- // Context belongs to an extension. Skip it.
- return false;
- }
- const SecurityOrigin* original_security_origin =
- original_execution_context->GetSecurityContext().GetSecurityOrigin();
- const SecurityOrigin* security_origin =
- execution_context->GetSecurityContext().GetSecurityOrigin();
- if (!original_security_origin->IsSameOriginWith(security_origin)) {
- // TODO(ulan): Check for COOP/COEP and allow cross-origin contexts that
- // opted in for memory measurement.
- // Until then we allow cross-origin measurement only for site-isolated
- // web pages.
- return Platform::Current()->IsLockedToSite();
- }
- return true;
-}
-
-namespace {
-// Helper functions for constructing a memory measurement result.
-
-LocalFrame* GetLocalFrame(v8::Local<v8::Context> context) {
- LocalDOMWindow* window = ToLocalDOMWindow(context);
- if (!window) {
- // The context was detached. Ignore it.
- return nullptr;
- }
- return window->GetFrame();
-}
-
-// Returns true if all frames on the path from the main frame to
-// the given frame (excluding the given frame) have the same origin.
-bool AllAncestorsAndOpenersAreSameOrigin(const WebFrame* main_frame,
- const WebFrame* frame) {
- while (frame != main_frame) {
- frame = frame->Parent() ? frame->Parent() : frame->Opener();
- if (!main_frame->GetSecurityOrigin().CanAccess(frame->GetSecurityOrigin()))
- return false;
- }
- return true;
-}
-
-// Returns the URL corresponding to the given frame. It is:
-// - document's URL if the frame is a same-origin top frame.
-// - the src attribute of the owner iframe element if the frame is
-// an iframe.
-// - nullopt, otherwise.
-// Preconditions:
-// - If the frame is cross-origin, then all its ancestors/openers
-// must be of the same origin as the main frame.
-// - The frame must be attached to the DOM tree and the main frame
-// must be reachable via child => parent and openee => opener edges.
-String GetUrl(const WebFrame* main_frame, const WebFrame* frame) {
- DCHECK(AllAncestorsAndOpenersAreSameOrigin(main_frame, frame));
- if (!frame->Parent()) {
- // TODO(ulan): Turn this conditional into a DCHECK once the API
- // is gated behind COOP+COEP. Only same-origin frames can appear here.
- if (!main_frame->GetSecurityOrigin().CanAccess(frame->GetSecurityOrigin()))
- return {};
- // The frame must be local because it is in the same browsing context
- // group as the main frame and has the same origin.
- // Check to avoid memory corruption in the case if our invariant is off.
- CHECK(IsA<LocalFrame>(WebFrame::ToCoreFrame(*frame)));
- LocalFrame* local = To<LocalFrame>(WebFrame::ToCoreFrame(*frame));
- return local->GetDocument()->Url().GetString();
- }
- FrameOwner* frame_owner = WebFrame::ToCoreFrame(*frame)->Owner();
- // The frame owner must be local because the parent of the frame has
- // the same origin as the main frame. Also the frame cannot be provisional
- // here because it is attached and has a document.
- // Check to avoid of memory corruption in the case if our invariant is off.
- CHECK(IsA<HTMLFrameOwnerElement>(frame_owner));
- HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(frame_owner);
- switch (owner_element->OwnerType()) {
- case mojom::blink::FrameOwnerElementType::kIframe:
- return owner_element->getAttribute(html_names::kSrcAttr);
- case mojom::blink::FrameOwnerElementType::kObject:
- case mojom::blink::FrameOwnerElementType::kEmbed:
- case mojom::blink::FrameOwnerElementType::kFrame:
- case mojom::blink::FrameOwnerElementType::kPortal:
- // TODO(ulan): return the data/src attribute after adding tests.
- return {};
- case mojom::blink::FrameOwnerElementType::kNone:
- // The main frame was handled as a local frame above.
- NOTREACHED();
- return {};
- }
-}
-
-// To avoid information leaks cross-origin iframes are considered opaque for
-// the purposes of attribution. This means the memory of all iframes nested
-// in a cross-origin iframe is attributed to the cross-origin iframe.
-// See https://github.com/WICG/performance-measure-memory for more details.
-//
-// Given the main frame and a frame, this function find the first cross-origin
-// frame in the path from the main frame to the given frame. Edges in the path
-// are parent/child and opener/openee edges.
-// If the path doesn't exist then it returns nullptr.
-// If there are no cross-origin frames, then it returns the given frame.
-//
-// Precondition: the frame must be attached to the DOM tree.
-const WebFrame* GetAttributionFrame(const WebFrame* main_frame,
- const WebFrame* frame) {
- WebSecurityOrigin main_security_origin = main_frame->GetSecurityOrigin();
- // Walk up the tree and the openers to find the first cross-origin frame
- // on the path from the main frame to the given frame.
- const WebFrame* result = frame;
- while (frame != main_frame) {
- if (frame->Parent()) {
- frame = frame->Parent();
- } else if (frame->Opener()) {
- frame = frame->Opener();
- } else {
- // The opener was reset. We cannot get the attribution.
- return nullptr;
- }
- if (!main_security_origin.CanAccess(frame->GetSecurityOrigin()))
- result = frame;
- }
- // The result frame must be attached because we started from an attached
- // frame (precondition) and followed the parent and opener references until
- // the main frame, which is also attached.
- DCHECK(WebFrame::ToCoreFrame(*result)->IsAttached());
- return result;
-}
-
-// Return per-frame sizes based on the given per-context size.
-// TODO(ulan): Revisit this after Origin Trial and see if the results
-// are precise enough or if we need to additionally group by JS agent.
-HashMap<const WebFrame*, size_t> GroupByFrame(
- const WebFrame* main_frame,
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& context_sizes,
- size_t& detached_size,
- size_t& unknown_frame_size) {
- detached_size = 0;
- unknown_frame_size = 0;
- HashMap<const WebFrame*, size_t> per_frame;
- for (const auto& context_size : context_sizes) {
- const WebFrame* frame =
- WebFrame::FromFrame(GetLocalFrame(context_size.first));
- if (!frame) {
- detached_size += context_size.second;
- continue;
- }
- frame = GetAttributionFrame(main_frame, frame);
- if (!frame) {
- unknown_frame_size += context_size.second;
- continue;
- }
- auto it = per_frame.find(frame);
- if (it == per_frame.end()) {
- per_frame.insert(frame, context_size.second);
- } else {
- it->value += context_size.second;
- }
- }
- return per_frame;
-}
-
-MeasureMemoryBreakdown* CreateMeasureMemoryBreakdown(
- size_t bytes,
- const Vector<String>& types,
- const String& url) {
- MeasureMemoryBreakdown* result = MeasureMemoryBreakdown::Create();
- result->setBytes(bytes);
- result->setUserAgentSpecificTypes(types);
- result->setAttribution(url.length() ? Vector<String>{url} : Vector<String>());
- return result;
-}
-
-} // anonymous namespace
-
-// Constructs a memory measurement result based on the given list of (context,
-// size) pairs and resolves the promise.
-void MeasureMemoryDelegate::MeasurementComplete(
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& context_sizes,
- size_t unattributed_size) {
- if (context_.IsEmpty()) {
- // The context was garbage collected in the meantime.
- return;
- }
- v8::Local<v8::Context> context = context_.NewLocal(isolate_);
- const WebFrame* main_frame = WebFrame::FromFrame(GetLocalFrame(context));
- if (!main_frame) {
- // The context was detached in the meantime.
- return;
- }
- DCHECK(!main_frame->Parent());
- v8::Context::Scope context_scope(context);
- size_t total_size = 0;
- for (const auto& context_size : context_sizes) {
- total_size += context_size.second;
- }
- HeapVector<Member<MeasureMemoryBreakdown>> breakdown;
- size_t detached_size;
- size_t unknown_frame_size;
- HashMap<const WebFrame*, size_t> per_frame(GroupByFrame(
- main_frame, context_sizes, detached_size, unknown_frame_size));
- size_t attributed_size = 0;
- const String kWindow("Window");
- const String kJS("JS");
- const Vector<String> js_window_types = {kWindow, kJS};
- for (const auto& it : per_frame) {
- String url = GetUrl(main_frame, it.key);
- if (url.IsNull()) {
- unknown_frame_size += it.value;
- continue;
- }
- attributed_size += it.value;
- breakdown.push_back(
- CreateMeasureMemoryBreakdown(it.value, js_window_types, url));
- }
- if (detached_size) {
- const String kDetached("Detached");
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- detached_size, Vector<String>{kWindow, kJS, kDetached}, ""));
- }
- if (unattributed_size) {
- const String kShared("Shared");
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- unattributed_size, Vector<String>{kWindow, kJS, kShared}, ""));
- }
- if (unknown_frame_size) {
- breakdown.push_back(CreateMeasureMemoryBreakdown(
- unknown_frame_size, Vector<String>{kWindow, kJS}, ""));
- }
- std::move(callback_).Run(breakdown);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h
deleted file mode 100644
index 23a1100784f..00000000000
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h
+++ /dev/null
@@ -1,42 +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_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
-
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class MeasureMemoryBreakdown;
-
-// Specifies V8 contexts to be measured and invokes the given callback once V8
-// completes the memory measurement.
-class MeasureMemoryDelegate : public v8::MeasureMemoryDelegate {
- public:
- using ResultCallback =
- base::OnceCallback<void(HeapVector<Member<MeasureMemoryBreakdown>>)>;
-
- MeasureMemoryDelegate(v8::Isolate* isolate,
- v8::Local<v8::Context> context,
- ResultCallback callback);
-
- // v8::MeasureMemoryDelegate overrides.
- bool ShouldMeasure(v8::Local<v8::Context> context) override;
- void MeasurementComplete(
- const std::vector<std::pair<v8::Local<v8::Context>, size_t>>&
- context_sizes,
- size_t unattributed_size) override;
- private:
- v8::Isolate* isolate_;
- ScopedPersistent<v8::Context> context_;
- ResultCallback callback_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl
new file mode 100644
index 00000000000..5a8d9c27bb4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution.idl
@@ -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.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memoryattribution
+
+// Describes a context to which the memory was attributed.
+dictionary MemoryAttribution {
+ required USVString url;
+ MemoryAttributionContainer container;
+ required DOMString scope;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.idl
new file mode 100644
index 00000000000..bb47082f790
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_attribution_container.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://wicg.github.io/performance-measure-memory/#dictdef-memoryattribution
+
+// The attributes of the container iframe element.
+dictionary MemoryAttributionContainer {
+ DOMString id;
+ USVString src;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl
new file mode 100644
index 00000000000..e3461faef8e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl
@@ -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.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memorybreakdownentry
+
+// A single entry of performance.measureUserAgentSpecificMemory() result.
+dictionary MemoryBreakdownEntry {
+ required unsigned long long bytes;
+ required sequence<MemoryAttribution> attribution;
+ required sequence<DOMString> types;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl
new file mode 100644
index 00000000000..0f8feeb5797
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/performance-measure-memory/#dictdef-memorymeasurement
+
+// The result of performance.measureUserAgentSpecificMemory().
+dictionary MemoryMeasurement {
+ required unsigned long long bytes;
+ required sequence<MemoryBreakdownEntry> breakdown;
+};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.cc b/chromium/third_party/blink/renderer/core/timing/performance.cc
index 3f732b25d25..fb00b62a386 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance.cc
@@ -36,6 +36,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
+#include "third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom-blink.h"
#include "third_party/blink/public/mojom/timing/worker_timing_container.mojom-blink-forward.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -52,9 +53,11 @@
#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/settings.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
#include "third_party/blink/renderer/core/timing/layout_shift.h"
#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h"
@@ -150,7 +153,7 @@ EventCounts* Performance::eventCounts() {
return nullptr;
}
-ScriptPromise Performance::measureMemory(
+ScriptPromise Performance::measureUserAgentSpecificMemory(
ScriptState* script_state,
ExceptionState& exception_state) const {
return MeasureMemoryController::StartMeasurement(script_state,
@@ -532,6 +535,7 @@ mojom::blink::ResourceTimingInfoPtr Performance::GenerateResourceTiming(
result->encoded_body_size = final_response.EncodedBodyLength();
result->decoded_body_size = final_response.DecodedBodyLength();
result->did_reuse_connection = final_response.ConnectionReused();
+ // TODO(crbug.com/1153336) Use network::IsUrlPotentiallyTrustworthy().
result->is_secure_context =
SecurityOrigin::IsSecure(final_response.ResponseUrl());
result->allow_negative_values = info.NegativeAllowed();
@@ -631,11 +635,13 @@ void Performance::AddEventTimingBuffer(PerformanceEventTiming& entry) {
}
void Performance::AddLayoutShiftBuffer(LayoutShift& entry) {
+ probe::PerformanceEntryAdded(GetExecutionContext(), &entry);
if (layout_shift_buffer_.size() < kDefaultLayoutShiftBufferSize)
layout_shift_buffer_.push_back(&entry);
}
void Performance::AddLargestContentfulPaint(LargestContentfulPaint* entry) {
+ probe::PerformanceEntryAdded(GetExecutionContext(), entry);
if (largest_contentful_paint_buffer_.size() <
kDefaultLargestContenfulPaintSize) {
largest_contentful_paint_buffer_.push_back(entry);
@@ -672,13 +678,18 @@ void Performance::AddLongTaskTiming(base::TimeTicks start_time,
base::TimeTicks end_time,
const AtomicString& name,
const AtomicString& container_type,
- const String& container_src,
- const String& container_id,
- const String& container_name) {
+ const AtomicString& container_src,
+ const AtomicString& container_id,
+ const AtomicString& container_name) {
+ double dom_high_res_start_time =
+ MonotonicTimeToDOMHighResTimeStamp(start_time);
auto* entry = MakeGarbageCollected<PerformanceLongTaskTiming>(
- MonotonicTimeToDOMHighResTimeStamp(start_time),
- MonotonicTimeToDOMHighResTimeStamp(end_time), name, container_type,
- container_src, container_id, container_name);
+ dom_high_res_start_time,
+ // Convert the delta between start and end times to an int to reduce the
+ // granularity of the duration to 1 ms.
+ static_cast<int>(MonotonicTimeToDOMHighResTimeStamp(end_time) -
+ dom_high_res_start_time),
+ name, container_type, container_src, container_id, container_name);
if (longtask_buffer_.size() < kDefaultLongTaskBufferSize) {
longtask_buffer_.push_back(entry);
} else {
@@ -861,7 +872,26 @@ ScriptPromise Performance::profile(ScriptState* script_state,
DCHECK(
RuntimeEnabledFeatures::ExperimentalJSProfilerEnabled(execution_context));
- if (!execution_context->CrossOriginIsolatedCapability()) {
+ if (!GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kJSProfiling,
+ ReportOptions::kReportOnFailure)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "JS profiling is disabled by Document Policy.");
+ return ScriptPromise();
+ }
+
+ // Bypass COOP/COEP checks when the |--disable-web-security| flag is present.
+ bool web_security_enabled = true;
+ if (LocalDOMWindow* window = LocalDOMWindow::From(script_state)) {
+ if (LocalFrame* local_frame = window->GetFrame()) {
+ web_security_enabled =
+ local_frame->GetSettings()->GetWebSecurityEnabled();
+ }
+ }
+
+ if (web_security_enabled &&
+ !execution_context->CrossOriginIsolatedCapability()) {
exception_state.ThrowSecurityError(
"performance.profile() requires COOP+COEP (web.dev/coop-coep)");
return ScriptPromise();
@@ -1029,6 +1059,8 @@ void Performance::Trace(Visitor* visitor) const {
visitor->Trace(observers_);
visitor->Trace(active_observers_);
visitor->Trace(suspended_observers_);
+ visitor->Trace(deliver_observations_timer_);
+ visitor->Trace(resource_timing_buffer_full_timer_);
EventTargetWithInlineData::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.h b/chromium/third_party/blink/renderer/core/timing/performance.h
index 8609a2a87b9..65898ea8131 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance.h
@@ -97,8 +97,9 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
virtual PerformanceTiming* timing() const;
virtual PerformanceNavigation* navigation() const;
virtual MemoryInfo* memory() const;
- virtual ScriptPromise measureMemory(ScriptState*,
- ExceptionState& exception_state) const;
+ virtual ScriptPromise measureUserAgentSpecificMemory(
+ ScriptState*,
+ ExceptionState& exception_state) const;
virtual EventCounts* eventCounts();
// Reduce the resolution to prevent timing attacks. See:
@@ -159,9 +160,9 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
base::TimeTicks end_time,
const AtomicString& name,
const AtomicString& container_type,
- const String& container_src,
- const String& container_id,
- const String& container_name);
+ const AtomicString& container_src,
+ const AtomicString& container_id,
+ const AtomicString& container_name);
// Generates and add a performance entry for the given ResourceTimingInfo.
// |overridden_initiator_type| allows the initiator type to be overridden to
@@ -388,8 +389,8 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
HeapLinkedHashSet<Member<PerformanceObserver>> active_observers_;
HeapLinkedHashSet<Member<PerformanceObserver>> suspended_observers_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- TaskRunnerTimer<Performance> deliver_observations_timer_;
- TaskRunnerTimer<Performance> resource_timing_buffer_full_timer_;
+ HeapTaskRunnerTimer<Performance> deliver_observations_timer_;
+ HeapTaskRunnerTimer<Performance> resource_timing_buffer_full_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.idl b/chromium/third_party/blink/renderer/core/timing/performance.idl
index 4939cad8a26..44502c55e83 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance.idl
@@ -67,7 +67,7 @@ interface Performance : EventTarget {
// https://groups.google.com/a/chromium.org/d/msg/blink-dev/g5YRCGpC9vs/b4OJz71NmPwJ
[Exposed=Window, Measure] readonly attribute MemoryInfo memory;
- [MeasureAs=MeasureMemory, Exposed=Window, CallWith=ScriptState, RuntimeEnabled=MeasureMemory, RaisesException] Promise<MeasureMemory> measureMemory();
+ [MeasureAs=MeasureMemory, Exposed=Window, CallWith=ScriptState, RuntimeEnabled=MeasureMemory, RaisesException] Promise<MemoryMeasurement> measureUserAgentSpecificMemory();
// JS Self-Profiling API
// https://github.com/WICG/js-self-profiling/
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_entry.cc b/chromium/third_party/blink/renderer/core/timing/performance_entry.cc
index cda5624b9a0..8fe854540da 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_entry.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_entry.cc
@@ -50,6 +50,16 @@ PerformanceEntry::PerformanceEntry(const AtomicString& name,
start_time_(start_time),
index_(index_seq.GetNext()) {}
+PerformanceEntry::PerformanceEntry(double duration,
+ const AtomicString& name,
+ double start_time)
+ : duration_(duration),
+ name_(name),
+ start_time_(start_time),
+ index_(index_seq.GetNext()) {
+ DCHECK_GE(duration_, 0.0);
+}
+
PerformanceEntry::~PerformanceEntry() = default;
DOMHighResTimeStamp PerformanceEntry::startTime() const {
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_entry.h b/chromium/third_party/blink/renderer/core/timing/performance_entry.h
index 82e50edb3e7..59679f11c16 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_entry.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_entry.h
@@ -124,6 +124,9 @@ class CORE_EXPORT PerformanceEntry : public ScriptWrappable {
PerformanceEntry(const AtomicString& name,
double start_time,
double finish_time);
+ PerformanceEntry(double duration,
+ const AtomicString& name,
+ double start_time);
virtual void BuildJSONValue(V8ObjectBuilder&) const;
// Protected and not const because PerformanceEventTiming needs to modify it.
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.cc
index a5723822a4f..5777ecd3fd7 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/performance_entry_names.h"
#include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
namespace blink {
@@ -85,7 +86,6 @@ void PerformanceEventTiming::BuildJSONValue(V8ObjectBuilder& builder) const {
builder.AddNumber("processingStart", processingStart());
builder.AddNumber("processingEnd", processingEnd());
builder.AddBoolean("cancelable", cancelable_);
- builder.Add("target", target());
}
void PerformanceEventTiming::Trace(Visitor* visitor) const {
@@ -93,4 +93,15 @@ void PerformanceEventTiming::Trace(Visitor* visitor) const {
visitor->Trace(target_);
}
+std::unique_ptr<TracedValue> PerformanceEventTiming::ToTracedValue() const {
+ auto traced_value = std::make_unique<TracedValue>();
+ traced_value->SetString("type", name());
+ traced_value->SetInteger("timeStamp", startTime());
+ traced_value->SetInteger("processingStart", processingStart());
+ traced_value->SetInteger("processingEnd", processingEnd());
+ traced_value->SetInteger("duration", duration());
+ traced_value->SetBoolean("cancelable", cancelable());
+ return traced_value;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.h
index 78560ef5ed2..cf689f84da5 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.h
@@ -51,6 +51,8 @@ class CORE_EXPORT PerformanceEventTiming final : public PerformanceEntry {
void Trace(Visitor*) const override;
+ std::unique_ptr<TracedValue> ToTracedValue() const;
+
private:
AtomicString entry_type_;
DOMHighResTimeStamp processing_start_;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.cc
index 83ced4ebcb9..a901c81bf14 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.cc
@@ -15,13 +15,13 @@ namespace blink {
PerformanceLongTaskTiming::PerformanceLongTaskTiming(
double start_time,
- double end_time,
+ int duration,
const AtomicString& name,
const AtomicString& culprit_type,
- const String& culprit_src,
- const String& culprit_id,
- const String& culprit_name)
- : PerformanceEntry(name, start_time, end_time) {
+ const AtomicString& culprit_src,
+ const AtomicString& culprit_id,
+ const AtomicString& culprit_name)
+ : PerformanceEntry(duration, name, start_time) {
auto* attribution_entry = MakeGarbageCollected<TaskAttributionTiming>(
"unknown", culprit_type, culprit_src, culprit_id, culprit_name);
attribution_.push_back(*attribution_entry);
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.h
index 8dd3530ebcb..fb000654c81 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_long_task_timing.h
@@ -19,13 +19,18 @@ class PerformanceLongTaskTiming final : public PerformanceEntry {
DEFINE_WRAPPERTYPEINFO();
public:
+ // This constructor uses int for |duration| on purpose: to avoid exposing a
+ // high resolution value in its entry. Having it be int ensures 1 ms
+ // granularity, even though it is ultimately stored as a double in
+ // PerformanceEntry.
PerformanceLongTaskTiming(double start_time,
- double end_time,
+ int duration,
const AtomicString& name,
const AtomicString& culprit_type,
- const String& culprit_src,
- const String& culprit_id,
- const String& culprit_name);
+ const AtomicString& culprit_src,
+ const AtomicString& culprit_id,
+ const AtomicString& culprit_name);
+ ~PerformanceLongTaskTiming() override;
AtomicString entryType() const override;
PerformanceEntryType EntryTypeEnum() const override;
@@ -35,8 +40,6 @@ class PerformanceLongTaskTiming final : public PerformanceEntry {
void Trace(Visitor*) const override;
private:
- ~PerformanceLongTaskTiming() override;
-
void BuildJSONValue(V8ObjectBuilder&) const override;
TaskAttributionVector attribution_;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_mark.h b/chromium/third_party/blink/renderer/core/timing/performance_mark.h
index 2ae62a7e5f0..ea3a65062fa 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_mark.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_mark.h
@@ -58,6 +58,7 @@ class CORE_EXPORT PerformanceMark final : public PerformanceEntry {
double start_time,
scoped_refptr<SerializedScriptValue>,
ExceptionState& exception_state);
+ ~PerformanceMark() override = default;
AtomicString entryType() const override;
PerformanceEntryType EntryTypeEnum() const override;
@@ -69,8 +70,6 @@ class CORE_EXPORT PerformanceMark final : public PerformanceEntry {
void Trace(Visitor*) const override;
private:
- ~PerformanceMark() override = default;
-
scoped_refptr<SerializedScriptValue> serialized_detail_;
// In order to prevent cross-world reference leak, we create a copy of the
// detail for each world.
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_measure.h b/chromium/third_party/blink/renderer/core/timing/performance_measure.h
index f1258ced973..862b24de3fd 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_measure.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_measure.h
@@ -49,6 +49,7 @@ class CORE_EXPORT PerformanceMeasure final : public PerformanceEntry {
double end_time,
scoped_refptr<SerializedScriptValue>,
ExceptionState&);
+ ~PerformanceMeasure() override = default;
static PerformanceMeasure* Create(ScriptState*,
const AtomicString& name,
@@ -67,7 +68,6 @@ class CORE_EXPORT PerformanceMeasure final : public PerformanceEntry {
void Trace(Visitor* visitor) const override;
private:
- ~PerformanceMeasure() override = default;
scoped_refptr<SerializedScriptValue> serialized_detail_;
// In order to prevent cross-world reference leak, we create a copy of the
// detail for each world.
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index de84bfd7ab6..441620f5276 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -55,6 +55,7 @@ PerformanceNavigationTiming::PerformanceNavigationTiming(
info->FinalResponse().CurrentRequestUrl().GetString())
: g_empty_atom,
time_origin,
+ // TODO(crbug.com/1153336) Use network::IsUrlPotentiallyTrustworthy().
SecurityOrigin::IsSecure(window->Url()),
std::move(server_timing),
window),
@@ -166,7 +167,7 @@ DOMHighResTimeStamp PerformanceNavigationTiming::unloadEventStart() const {
DocumentLoadTiming* timing = GetDocumentLoadTiming();
if (!allow_redirect_details || !timing ||
- !timing->HasSameOriginAsPreviousDocument())
+ !timing->CanRequestFromPreviousDocument())
return 0;
return Performance::MonotonicTimeToDOMHighResTimeStamp(
TimeOrigin(), timing->UnloadEventStart(),
@@ -178,7 +179,7 @@ DOMHighResTimeStamp PerformanceNavigationTiming::unloadEventEnd() const {
DocumentLoadTiming* timing = GetDocumentLoadTiming();
if (!allow_redirect_details || !timing ||
- !timing->HasSameOriginAsPreviousDocument())
+ !timing->CanRequestFromPreviousDocument())
return 0;
return Performance::MonotonicTimeToDOMHighResTimeStamp(
TimeOrigin(), timing->UnloadEventEnd(), false /* allow_negative_value */);
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
index c566ccb134b..22eb990a25e 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
@@ -35,6 +35,7 @@ class CORE_EXPORT PerformanceNavigationTiming final
ResourceTimingInfo*,
base::TimeTicks time_origin,
HeapVector<Member<PerformanceServerTiming>>);
+ ~PerformanceNavigationTiming() override;
// Attributes inherited from PerformanceEntry.
DOMHighResTimeStamp duration() const override;
@@ -67,8 +68,6 @@ class CORE_EXPORT PerformanceNavigationTiming final
void BuildJSONValue(V8ObjectBuilder&) const override;
private:
- ~PerformanceNavigationTiming() override;
-
static AtomicString GetNavigationType(WebNavigationType, const Document*);
const DocumentTiming* GetDocumentTiming() const;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_test.cc b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
index d423813523f..ac07945835e 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
@@ -45,6 +45,8 @@ class TestPerformance : public Performance {
class PerformanceTest : public PageTestBase {
protected:
+ ~PerformanceTest() override { execution_context_->NotifyContextDestroyed(); }
+
void Initialize(ScriptState* script_state) {
v8::Local<v8::Function> callback =
v8::Function::New(script_state->GetContext(), nullptr).ToLocalChecked();
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
index e297230e2e1..589a2514be7 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -85,7 +85,7 @@ uint64_t PerformanceTiming::unloadEventStart() const {
return 0;
if (timing->HasCrossOriginRedirect() ||
- !timing->HasSameOriginAsPreviousDocument())
+ !timing->CanRequestFromPreviousDocument())
return 0;
return MonotonicTimeToIntegerMilliseconds(timing->UnloadEventStart());
@@ -97,7 +97,7 @@ uint64_t PerformanceTiming::unloadEventEnd() const {
return 0;
if (timing->HasCrossOriginRedirect() ||
- !timing->HasSameOriginAsPreviousDocument())
+ !timing->CanRequestFromPreviousDocument())
return 0;
return MonotonicTimeToIntegerMilliseconds(timing->UnloadEventEnd());
@@ -482,6 +482,15 @@ uint64_t PerformanceTiming::ExperimentalLargestTextPaintSize() const {
return paint_timing_detector->ExperimentalLargestTextPaintSize();
}
+base::TimeTicks PerformanceTiming::LargestContentfulPaintAsMonotonicTime()
+ const {
+ PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
+ if (!paint_timing_detector)
+ return base::TimeTicks();
+
+ return paint_timing_detector->LargestContentfulPaint();
+}
+
uint64_t PerformanceTiming::FirstEligibleToPaint() const {
const PaintTiming* timing = GetPaintTiming();
if (!timing)
@@ -624,6 +633,30 @@ base::Optional<base::TimeTicks> PerformanceTiming::LastPortalActivatedPaint()
return timing->LastPortalActivatedPaint();
}
+base::Optional<base::TimeTicks> PerformanceTiming::UnloadStart() const {
+ DocumentLoadTiming* timing = GetDocumentLoadTiming();
+ if (!timing)
+ return base::nullopt;
+
+ return timing->UnloadEventStart();
+}
+
+base::Optional<base::TimeTicks> PerformanceTiming::UnloadEnd() const {
+ DocumentLoadTiming* timing = GetDocumentLoadTiming();
+ if (!timing)
+ return base::nullopt;
+
+ return timing->UnloadEventEnd();
+}
+
+base::Optional<base::TimeTicks> PerformanceTiming::CommitNavigationEnd() const {
+ DocumentLoadTiming* timing = GetDocumentLoadTiming();
+ if (!timing)
+ return base::nullopt;
+
+ return timing->CommitNavigationEnd();
+}
+
DocumentLoader* PerformanceTiming::GetDocumentLoader() const {
return DomWindow() ? DomWindow()->GetFrame()->Loader().GetDocumentLoader()
: nullptr;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
index 2d210014755..8afad757e2d 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
@@ -97,12 +97,13 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
uint64_t loadEventStart() const;
uint64_t loadEventEnd() const;
- // The below are non-spec timings, for Page Load UMA metrics.
+ // The below are non-spec timings, for Page Load UMA metrics. Not to be
+ // exposed to JavaScript.
// The time immediately after the user agent finishes prompting to unload the
// previous document, or if there is no previous document, the same value as
// fetchStart. Intended to be used for correlation with other events internal
- // to blink. Not to be exposed to JavaScript.
+ // to blink.
base::TimeTicks NavigationStartAsMonotonicTime() const;
// The timings after the page is restored from back-forward cache.
BackForwardCacheRestoreTimings BackForwardCacheRestore() const;
@@ -114,8 +115,7 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// that includes content of some kind (for example, text or image content).
uint64_t FirstContentfulPaint() const;
// The first 'contentful' paint as full-resolution monotonic time. Intended to
- // be used for correlation with other events internal to blink. Not to be
- // exposed to JavaScript.
+ // be used for correlation with other events internal to blink.
base::TimeTicks FirstContentfulPaintAsMonotonicTime() const;
// The time of the first 'meaningful' paint, A meaningful paint is a paint
// where the page's primary content is visible.
@@ -138,6 +138,9 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// are the time and size of it.
uint64_t LargestTextPaint() const;
uint64_t LargestTextPaintSize() const;
+ // Largest Contentful Paint is the either the largest text paint time or the
+ // largest image paint time, whichever has the larger size.
+ base::TimeTicks LargestContentfulPaintAsMonotonicTime() const;
// Experimental versions of the above metrics. Currently these are computed by
// considering the largest content seen so far, regardless of DOM node
// removal.
@@ -169,6 +172,11 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
base::Optional<base::TimeDelta> FirstScrollDelay() const;
// The hardware timestamp of the first scroll.
base::Optional<base::TimeDelta> FirstScrollTimestamp() const;
+ // TimeTicks for unload start and end.
+ base::Optional<base::TimeTicks> UnloadStart() const;
+ base::Optional<base::TimeTicks> UnloadEnd() const;
+ // The timestamp of when the commit navigation finished in the frame loader.
+ base::Optional<base::TimeTicks> CommitNavigationEnd() const;
uint64_t ParseStart() const;
uint64_t ParseStop() const;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
index e4aa78261c8..05da2ae0e57 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -42,11 +42,11 @@ void InsertPerformanceEntry(PerformanceEntryMap& performance_entry_map,
PerformanceEntryMap::iterator it = performance_entry_map.find(entry.name());
if (it != performance_entry_map.end()) {
DCHECK(it->value);
- it->value->push_back(entry);
+ it->value->push_back(&entry);
} else {
PerformanceEntryVector* vector =
MakeGarbageCollected<PerformanceEntryVector>();
- vector->push_back(entry);
+ vector->push_back(&entry);
performance_entry_map.Set(entry.name(), vector);
}
}
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_group.cc b/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
index 4404ed897f1..790ebdc3311 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
@@ -90,34 +90,50 @@ Profiler* ProfilerGroup::CreateProfiler(ScriptState* script_state,
: v8::CpuProfilingOptions::kNoSampleLimit,
static_cast<int>(sample_interval_us));
- cpu_profiler_->StartProfiling(V8String(isolate_, profiler_id), options);
-
- // Limit non-crossorigin script frames to the origin that started the
- // profiler.
- auto* execution_context = ExecutionContext::From(script_state);
- scoped_refptr<const SecurityOrigin> source_origin(
- execution_context->GetSecurityOrigin());
-
- // The V8 CPU profiler ticks in multiples of the base sampling interval. This
- // effectively means that we gather samples at the multiple of the base
- // sampling interval that's greater than or equal to the requested interval.
- int effective_sample_interval_ms =
- static_cast<int>(sample_interval.InMilliseconds());
- if (effective_sample_interval_ms % kBaseSampleIntervalMs != 0 ||
- effective_sample_interval_ms == 0) {
- effective_sample_interval_ms +=
- (kBaseSampleIntervalMs -
- effective_sample_interval_ms % kBaseSampleIntervalMs);
+ v8::CpuProfilingStatus status =
+ cpu_profiler_->StartProfiling(V8String(isolate_, profiler_id), options);
+
+ switch (status) {
+ case v8::CpuProfilingStatus::kErrorTooManyProfilers: {
+ exception_state.ThrowTypeError(
+ "Reached maximum concurrent amount of profilers");
+ return nullptr;
+ }
+ case v8::CpuProfilingStatus::kAlreadyStarted: {
+ // Since we increment the profiler id for every invocation of
+ // StartProfiling, we do not expect to hit kAlreadyStarted status
+ DCHECK(false);
+ return nullptr;
+ }
+ case v8::CpuProfilingStatus::kStarted: {
+ // Limit non-crossorigin script frames to the origin that started the
+ // profiler.
+ auto* execution_context = ExecutionContext::From(script_state);
+ scoped_refptr<const SecurityOrigin> source_origin(
+ execution_context->GetSecurityOrigin());
+
+ // The V8 CPU profiler ticks in multiples of the base sampling interval.
+ // This effectively means that we gather samples at the multiple of the
+ // base sampling interval that's greater than or equal to the requested
+ // interval.
+ int effective_sample_interval_ms =
+ static_cast<int>(sample_interval.InMilliseconds());
+ if (effective_sample_interval_ms % kBaseSampleIntervalMs != 0 ||
+ effective_sample_interval_ms == 0) {
+ effective_sample_interval_ms +=
+ (kBaseSampleIntervalMs -
+ effective_sample_interval_ms % kBaseSampleIntervalMs);
+ }
+
+ auto* profiler = MakeGarbageCollected<Profiler>(
+ this, script_state, profiler_id, effective_sample_interval_ms,
+ source_origin, time_origin);
+ profilers_.insert(profiler);
+
+ num_active_profilers_++;
+ return profiler;
+ }
}
-
- auto* profiler = MakeGarbageCollected<Profiler>(
- this, script_state, profiler_id, effective_sample_interval_ms,
- source_origin, time_origin);
- profilers_.insert(profiler);
-
- num_active_profilers_++;
-
- return profiler;
}
ProfilerGroup::~ProfilerGroup() {
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_group.h b/chromium/third_party/blink/renderer/core/timing/profiler_group.h
index c775f27c1be..da540b773de 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_group.h
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_group.h
@@ -53,7 +53,7 @@ class CORE_EXPORT ProfilerGroup
// Cancels a profiler, discarding its associated trace.
void CancelProfiler(Profiler*);
- // Asynchronously cancels a profiler. Invoked on Profiler descrution.
+ // Asynchronously cancels a profiler. Invoked on Profiler destruction.
void CancelProfilerAsync(ScriptState*, Profiler*);
// Internal implementation of cancel.
void CancelProfilerImpl(String profiler_id);
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_group_test.cc b/chromium/third_party/blink/renderer/core/timing/profiler_group_test.cc
index c0af8fdd41c..eb477f3852b 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_group_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_group_test.cc
@@ -16,25 +16,10 @@ namespace blink {
namespace {
static constexpr int kLargeProfilerCount = 128;
+static constexpr int kMaxConcurrentProfilerCount = 100;
} // namespace
-// Tests that a leaked profiler doesn't crash the isolate on heap teardown.
-TEST(ProfilerGroupTest, LeakProfiler) {
- V8TestingScope scope;
-
- ProfilerGroup* profiler_group = ProfilerGroup::From(scope.GetIsolate());
-
- ProfilerInitOptions* init_options = ProfilerInitOptions::Create();
- init_options->setSampleInterval(0);
- init_options->setMaxBufferSize(0);
- Profiler* profiler = profiler_group->CreateProfiler(
- scope.GetScriptState(), *init_options, base::TimeTicks(),
- scope.GetExceptionState());
-
- EXPECT_FALSE(profiler->stopped());
-}
-
TEST(ProfilerGroupTest, StopProfiler) {
V8TestingScope scope;
@@ -83,6 +68,9 @@ TEST(ProfilerGroupTest, CreateProfiler) {
EXPECT_FALSE(profiler->stopped());
EXPECT_FALSE(scope.GetExceptionState().HadException());
+
+ // clean up
+ profiler->stop(scope.GetScriptState());
}
TEST(ProfilerGroupTest, ClampedSamplingIntervalZero) {
@@ -102,6 +90,9 @@ TEST(ProfilerGroupTest, ClampedSamplingIntervalZero) {
// interval.
EXPECT_EQ(profiler->sampleInterval(),
ProfilerGroup::GetBaseSampleInterval().InMilliseconds());
+
+ // clean up
+ profiler->stop(scope.GetScriptState());
}
TEST(ProfilerGroupTest, ClampedSamplingIntervalNext) {
@@ -123,6 +114,42 @@ TEST(ProfilerGroupTest, ClampedSamplingIntervalNext) {
// interval.
EXPECT_EQ(profiler->sampleInterval(),
(ProfilerGroup::GetBaseSampleInterval() * 2).InMilliseconds());
+
+ // clean up
+ profiler->stop(scope.GetScriptState());
+}
+
+TEST(ProfilerGroupTest, V8ProfileLimitThrowsExceptionWhenMaxConcurrentReached) {
+ V8TestingScope scope;
+
+ HeapVector<Member<Profiler>> profilers;
+ ProfilerGroup* profiler_group = ProfilerGroup::From(scope.GetIsolate());
+ ProfilerInitOptions* init_options = ProfilerInitOptions::Create();
+
+ for (auto i = 0; i < kMaxConcurrentProfilerCount; i++) {
+ init_options->setSampleInterval(i);
+ profilers.push_back(profiler_group->CreateProfiler(
+ scope.GetScriptState(), *init_options, base::TimeTicks(),
+ scope.GetExceptionState()));
+ EXPECT_FALSE(scope.GetExceptionState().HadException());
+ }
+
+ // check kErrorTooManyProfilers
+ ProfilerGroup* extra_profiler_group = ProfilerGroup::From(scope.GetIsolate());
+ ProfilerInitOptions* extra_init_options = ProfilerInitOptions::Create();
+ extra_init_options->setSampleInterval(100);
+ for (auto i = kMaxConcurrentProfilerCount; i < kLargeProfilerCount; i++) {
+ extra_profiler_group->CreateProfiler(scope.GetScriptState(),
+ *extra_init_options, base::TimeTicks(),
+ scope.GetExceptionState());
+ EXPECT_TRUE(scope.GetExceptionState().HadException());
+ EXPECT_EQ(scope.GetExceptionState().Message(),
+ "Reached maximum concurrent amount of profilers");
+ }
+
+ for (auto profiler : profilers) {
+ profiler->stop(scope.GetScriptState());
+ }
}
TEST(ProfilerGroupTest, NegativeSamplingInterval) {
@@ -152,30 +179,6 @@ TEST(ProfilerGroupTest, OverflowSamplingInterval) {
EXPECT_TRUE(scope.GetExceptionState().HadException());
}
-// Tests behaviour when exceeding the maximum number of concurrent profiles
-// supported by the V8 profiling API (https://crbug.com/1052341).
-TEST(ProfilerGroupTest, V8ProfileLimit) {
- V8TestingScope scope;
-
- ProfilerGroup* profiler_group = ProfilerGroup::From(scope.GetIsolate());
-
- ProfilerInitOptions* init_options = ProfilerInitOptions::Create();
- init_options->setSampleInterval(0);
-
- HeapVector<Member<Profiler>> profilers;
- for (auto i = 0; i < kLargeProfilerCount; i++) {
- // TODO(acomminos): The V8 public API should likely be changed to expose
- // exceeding the profile limit during creation. This would enable
- // instantiation of profiles to cause a promise rejection instead.
- profilers.push_back(profiler_group->CreateProfiler(
- scope.GetScriptState(), *init_options, base::TimeTicks(),
- scope.GetExceptionState()));
- }
- for (auto profiler : profilers) {
- profiler->stop(scope.GetScriptState());
- }
-}
-
TEST(ProfilerGroupTest, Bug1119865) {
class ExpectNoCallFunction : public ScriptFunction {
public:
@@ -208,6 +211,27 @@ TEST(ProfilerGroupTest, Bug1119865) {
profiler->stop(scope.GetScriptState()).Then(function);
}
+/*
+ * LEAK TESTS - SHOULD RUN LAST
+ */
+
+// Tests that a leaked profiler doesn't crash the isolate on heap teardown.
+// These should run last
+TEST(ProfilerGroupTest, LeakProfiler) {
+ V8TestingScope scope;
+
+ ProfilerGroup* profiler_group = ProfilerGroup::From(scope.GetIsolate());
+
+ ProfilerInitOptions* init_options = ProfilerInitOptions::Create();
+ init_options->setSampleInterval(0);
+ init_options->setMaxBufferSize(0);
+ Profiler* profiler = profiler_group->CreateProfiler(
+ scope.GetScriptState(), *init_options, base::TimeTicks(),
+ scope.GetExceptionState());
+
+ EXPECT_FALSE(profiler->stopped());
+}
+
// Tests that a leaked profiler doesn't crash when disposed alongside its
// context.
TEST(ProfilerGroupTest, LeakProfilerWithContext) {
diff --git a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.cc b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.cc
index 2588b14206b..67c00aa7793 100644
--- a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.cc
@@ -12,9 +12,9 @@ namespace blink {
TaskAttributionTiming::TaskAttributionTiming(const AtomicString& name,
const AtomicString& container_type,
- const String& container_src,
- const String& container_id,
- const String& container_name)
+ const AtomicString& container_src,
+ const AtomicString& container_id,
+ const AtomicString& container_name)
: PerformanceEntry(name, 0.0, 0.0),
container_type_(container_type),
container_src_(container_src),
diff --git a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.h b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.h
index 2c2ead9d6e1..7f33034e4c0 100644
--- a/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/task_attribution_timing.h
@@ -28,9 +28,9 @@ class TaskAttributionTiming final : public PerformanceEntry {
TaskAttributionTiming(const AtomicString& type,
const AtomicString& container_type,
- const String& container_src,
- const String& container_id,
- const String& container_name);
+ const AtomicString& container_src,
+ const AtomicString& container_id,
+ const AtomicString& container_name);
~TaskAttributionTiming() override;
private:
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.cc b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
index bf39c372991..8f068c7d8b9 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/timing/window_performance.h"
+#include "base/trace_event/common/trace_event_common.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -44,6 +45,7 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/interactive_detector.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/page_hidden_state.h"
@@ -201,6 +203,10 @@ WindowPerformance::CreateNavigationTimingInstance() {
if (!DomWindow())
return nullptr;
DocumentLoader* document_loader = DomWindow()->document()->Loader();
+ // TODO(npm): figure out when |document_loader| can be null and add tests.
+ DCHECK(document_loader);
+ if (!document_loader)
+ return nullptr;
ResourceTimingInfo* info = document_loader->GetNavigationTimingInfo();
if (!info)
return nullptr;
@@ -314,7 +320,7 @@ void WindowPerformance::ReportLongTask(base::TimeTicks start_time,
if (!culprit_dom_window || !culprit_dom_window->GetFrame() ||
!culprit_dom_window->GetFrame()->DeprecatedLocalOwner()) {
AddLongTaskTiming(start_time, end_time, attribution.first, "window",
- g_empty_string, g_empty_string, g_empty_string);
+ g_empty_atom, g_empty_atom, g_empty_atom);
} else {
HTMLFrameOwnerElement* frame_owner =
culprit_dom_window->GetFrame()->DeprecatedLocalOwner();
@@ -346,40 +352,46 @@ void WindowPerformance::RegisterEventTiming(const AtomicString& event_type,
MonotonicTimeToDOMHighResTimeStamp(processing_start),
MonotonicTimeToDOMHighResTimeStamp(processing_end), cancelable, target);
// Add |entry| to the end of the queue along with the frame index at which is
- // is being queued to know when to queue a swap promise for it.
+ // is being queued to know when to queue a presentation promise for it.
event_timings_.push_back(entry);
event_frames_.push_back(frame_index_);
- bool should_queue_swap_promise = false;
- // If there are no pending swap promises, we should queue one. This ensures
- // that |event_timings_| are processed even if the Blink lifecycle does not
- // occur due to no DOM updates.
- if (pending_swap_promise_count_ == 0u) {
- should_queue_swap_promise = true;
+ bool should_queue_presentation_promise = false;
+ // If there are no pending presentation promises, we should queue one. This
+ // ensures that |event_timings_| are processed even if the Blink lifecycle
+ // does not occur due to no DOM updates.
+ if (pending_presentation_promise_count_ == 0u) {
+ should_queue_presentation_promise = true;
} else {
- // There are pending swap promises, so only queue one if the event
- // corresponds to a later frame than the one of the latest queued swap
- // promise.
- should_queue_swap_promise = frame_index_ > last_registered_frame_index_;
+ // There are pending presentation promises, so only queue one if the event
+ // corresponds to a later frame than the one of the latest queued
+ // presentation promise.
+ should_queue_presentation_promise =
+ frame_index_ > last_registered_frame_index_;
}
- if (should_queue_swap_promise) {
- DomWindow()->GetFrame()->GetChromeClient().NotifySwapTime(
+ if (should_queue_presentation_promise) {
+ DomWindow()->GetFrame()->GetChromeClient().NotifyPresentationTime(
*DomWindow()->GetFrame(),
CrossThreadBindOnce(&WindowPerformance::ReportEventTimings,
WrapCrossThreadWeakPersistent(this), frame_index_));
last_registered_frame_index_ = frame_index_;
- ++pending_swap_promise_count_;
+ ++pending_presentation_promise_count_;
}
}
void WindowPerformance::ReportEventTimings(uint64_t frame_index,
WebSwapResult result,
base::TimeTicks timestamp) {
- DCHECK(pending_swap_promise_count_);
- --pending_swap_promise_count_;
+ DCHECK(pending_presentation_promise_count_);
+ --pending_presentation_promise_count_;
// |event_timings_| and |event_frames_| should always have the same size.
DCHECK(event_timings_.size() == event_frames_.size());
if (event_timings_.IsEmpty())
return;
+
+ if (!DomWindow())
+ return;
+ InteractiveDetector* interactive_detector =
+ InteractiveDetector::From(*(DomWindow()->document()));
bool event_timing_enabled =
RuntimeEnabledFeatures::EventTimingEnabled(GetExecutionContext());
DOMHighResTimeStamp end_time = MonotonicTimeToDOMHighResTimeStamp(timestamp);
@@ -396,7 +408,35 @@ void WindowPerformance::ReportEventTimings(uint64_t frame_index,
event_frames_.pop_front();
int duration_in_ms = std::round((end_time - entry->startTime()) / 8) * 8;
+ base::TimeDelta input_delay = base::TimeDelta::FromMillisecondsD(
+ entry->processingStart() - entry->startTime());
+ base::TimeDelta processing_time = base::TimeDelta::FromMillisecondsD(
+ entry->processingEnd() - entry->processingStart());
+ base::TimeDelta time_to_next_paint =
+ base::TimeDelta::FromMillisecondsD(end_time - entry->processingEnd());
entry->SetDuration(duration_in_ms);
+ TRACE_EVENT2("devtools.timeline", "EventTiming", "data",
+ entry->ToTracedValue(), "frame",
+ ToTraceValue(DomWindow()->GetFrame()));
+ if (entry->name() == "pointerdown") {
+ pending_pointer_down_input_delay_ = input_delay;
+ pending_pointer_down_processing_time_ = processing_time;
+ pending_pointer_down_time_to_next_paint_ = time_to_next_paint;
+ } else if (entry->name() == "pointerup") {
+ if (pending_pointer_down_time_to_next_paint_.has_value() &&
+ interactive_detector) {
+ interactive_detector->RecordInputEventTimingUKM(
+ pending_pointer_down_input_delay_.value(),
+ pending_pointer_down_processing_time_.value(),
+ pending_pointer_down_time_to_next_paint_.value(), entry->name());
+ }
+ } else if ((entry->name() == "click" || entry->name() == "keydown" ||
+ entry->name() == "mousedown") &&
+ interactive_detector) {
+ interactive_detector->RecordInputEventTimingUKM(
+ input_delay, processing_time, time_to_next_paint, entry->name());
+ }
+
if (!first_input_timing_) {
if (entry->name() == "pointerdown") {
first_pointer_down_event_timing_ =
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.h b/chromium/third_party/blink/renderer/core/timing/window_performance.h
index be9e535390b..7c33989791a 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.h
@@ -70,9 +70,9 @@ class CORE_EXPORT WindowPerformance final : public Performance,
bool FirstInputDetected() const { return !!first_input_timing_; }
- // This method creates a PerformanceEventTiming and if needed creates a swap
- // promise to calculate the |duration| attribute when such promise is
- // resolved.
+ // This method creates a PerformanceEventTiming and if needed creates a
+ // presentation promise to calculate the |duration| attribute when such
+ // promise is resolved.
void RegisterEventTiming(const AtomicString& event_type,
base::TimeTicks start_time,
base::TimeTicks processing_start,
@@ -123,8 +123,8 @@ class CORE_EXPORT WindowPerformance final : public Performance,
void BuildJSONValue(V8ObjectBuilder&) const override;
- // Method called once swap promise is resolved. It will add all event timings
- // that have not been added since the last swap promise.
+ // Method called once presentation promise is resolved. It will add all event
+ // timings that have not been added since the last presentation promise.
void ReportEventTimings(uint64_t frame_index,
WebSwapResult result,
base::TimeTicks timestamp);
@@ -133,13 +133,13 @@ class CORE_EXPORT WindowPerformance final : public Performance,
// Counter of the current frame index, based on calls to OnPaintFinished().
uint64_t frame_index_ = 1;
- // Monotonically increasing value with the last frame index on which a swap
- // promise was queued;
+ // Monotonically increasing value with the last frame index on which a
+ // presentation promise was queued;
uint64_t last_registered_frame_index_ = 0;
- // Number of pending swap promises.
- uint16_t pending_swap_promise_count_ = 0;
+ // Number of pending presentation promises.
+ uint16_t pending_presentation_promise_count_ = 0;
// PerformanceEventTiming entries that have not been sent to observers yet:
- // the event dispatch has been completed but the swap promise used to
+ // the event dispatch has been completed but the presentation promise used to
// determine |duration| has not yet been resolved. It is handled as a queue:
// FIFO.
HeapDeque<Member<PerformanceEventTiming>> event_timings_;
@@ -155,6 +155,9 @@ class CORE_EXPORT WindowPerformance final : public Performance,
Member<EventCounts> event_counts_;
mutable Member<PerformanceNavigation> navigation_;
mutable Member<PerformanceTiming> timing_;
+ base::Optional<base::TimeDelta> pending_pointer_down_input_delay_;
+ base::Optional<base::TimeDelta> pending_pointer_down_processing_time_;
+ base::Optional<base::TimeDelta> pending_pointer_down_time_to_next_paint_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
index 070c3f609e3..c2ae1bfcb68 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -184,7 +184,8 @@ TEST(PerformanceLifetimeTest, SurviveContextSwitch) {
// Simulate changing the document while keeping the window.
std::unique_ptr<WebNavigationParams> params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url);
page_holder->GetFrame().Loader().CommitNavigation(std::move(params), nullptr);
EXPECT_EQ(perf, DOMWindowPerformance::performance(
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/DIR_METADATA b/chromium/third_party/blink/renderer/core/trustedtypes/DIR_METADATA
new file mode 100644
index 00000000000..867490302d6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>SecurityFeature"
+}
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/OWNERS b/chromium/third_party/blink/renderer/core/trustedtypes/OWNERS
index 41f2787228f..5440e488672 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/OWNERS
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/OWNERS
@@ -1,4 +1,2 @@
mkwst@chromium.org
vogelheim@chromium.org
-
-# COMPONENT: Blink>SecurityFeature
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.h
index 8e269e3accf..049eadf4c8c 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.h
@@ -19,6 +19,7 @@ class CORE_EXPORT TrustedHTML final : public ScriptWrappable {
// TrustedHTML.idl
const String& toString() const;
+ const String& toJSON() const { return toString(); }
private:
const String html_;
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
index 7eabd4d4ddd..828b9bed25c 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
@@ -11,5 +11,6 @@ typedef [StringContext=TrustedHTML] DOMString HTMLString;
RuntimeEnabled=TrustedDOMTypes
] interface TrustedHTML {
stringifier;
+ DOMString toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.h
index c93620a95b8..4e9ec671a0f 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.h
@@ -19,6 +19,7 @@ class CORE_EXPORT TrustedScript final : public ScriptWrappable {
// TrustedScript.idl
const String& toString() const;
+ const String& toJSON() const { return toString(); }
private:
const String script_;
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
index 07fbef3c64c..fc0390f325d 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
@@ -12,4 +12,5 @@ typedef [StringContext=TrustedScript] DOMString ScriptString;
RuntimeEnabled=TrustedDOMTypes
] interface TrustedScript {
stringifier;
+ DOMString toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
index d287ebd43d7..8341e0075f7 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
@@ -19,6 +19,7 @@ class CORE_EXPORT TrustedScriptURL final : public ScriptWrappable {
// TrustedScriptURL.idl
const String& toString() const;
+ const String& toJSON() const { return toString(); }
private:
const String url_;
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
index 711b491833f..b5b9cc1e33a 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
@@ -11,4 +11,5 @@ typedef [StringContext=TrustedScriptURL] USVString ScriptURLString;
RuntimeEnabled=TrustedDOMTypes
] interface TrustedScriptURL {
stringifier;
+ USVString toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
index da295291317..b21e05d0a83 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
@@ -18,7 +18,9 @@ namespace blink {
TrustedTypePolicy::TrustedTypePolicy(const String& policy_name,
TrustedTypePolicyOptions* policy_options)
- : name_(policy_name), policy_options_(policy_options) {}
+ : name_(policy_name), policy_options_(policy_options) {
+ DCHECK(policy_options_);
+}
TrustedHTML* TrustedTypePolicy::createHTML(ScriptState* script_state,
const String& input,
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h
index af13e11476c..5677fe37876 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_H_
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_trusted_type_policy_options.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
index 524a072e9a3..638295dcea5 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
@@ -15,6 +15,7 @@
#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/local_frame.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -27,6 +28,14 @@ namespace blink {
TrustedTypePolicy* TrustedTypePolicyFactory::createPolicy(
const String& policy_name,
+ ExceptionState& exception_state) {
+ return createPolicy(policy_name,
+ MakeGarbageCollected<TrustedTypePolicyOptions>(),
+ exception_state);
+}
+
+TrustedTypePolicy* TrustedTypePolicyFactory::createPolicy(
+ const String& policy_name,
const TrustedTypePolicyOptions* policy_options,
ExceptionState& exception_state) {
if (RuntimeEnabledFeatures::TrustedTypeBeforePolicyCreationEventEnabled()) {
@@ -46,27 +55,39 @@ TrustedTypePolicy* TrustedTypePolicyFactory::createPolicy(
}
UseCounter::Count(GetExecutionContext(),
WebFeature::kTrustedTypesCreatePolicy);
+
if (RuntimeEnabledFeatures::TrustedDOMTypesEnabled(GetExecutionContext()) &&
- GetExecutionContext()->GetContentSecurityPolicy() &&
- !GetExecutionContext()
- ->GetContentSecurityPolicy()
- ->AllowTrustedTypePolicy(policy_name,
- policy_map_.Contains(policy_name))) {
- // For a better error message, we'd like to disambiguate between
- // "disallowed" and "disallowed because of a duplicate name". Instead of
- // piping the reason through all the layers, we'll just check whether it
- // had also been disallowed as a non-duplicate name.
- bool disallowed_because_of_duplicate_name =
- policy_map_.Contains(policy_name) &&
- GetExecutionContext()
- ->GetContentSecurityPolicy()
- ->AllowTrustedTypePolicy(policy_name, false);
- const String message =
- disallowed_because_of_duplicate_name
- ? "Policy with name \"" + policy_name + "\" already exists."
- : "Policy \"" + policy_name + "\" disallowed.";
- exception_state.ThrowTypeError(message);
- return nullptr;
+ GetExecutionContext()->GetContentSecurityPolicy()) {
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails violation_details =
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::kAllowed;
+ bool disallowed = !GetExecutionContext()
+ ->GetContentSecurityPolicy()
+ ->AllowTrustedTypePolicy(
+ policy_name, policy_map_.Contains(policy_name),
+ violation_details);
+ if (violation_details != ContentSecurityPolicy::ContentSecurityPolicy::
+ AllowTrustedTypePolicyDetails::kAllowed) {
+ // We may report a violation here even when disallowed is false
+ // in case policy is a report-only one.
+ probe::OnContentSecurityPolicyViolation(
+ GetExecutionContext(),
+ ContentSecurityPolicy::ContentSecurityPolicyViolationType::
+ kTrustedTypesPolicyViolation);
+ }
+ if (disallowed) {
+ // For a better error message, we'd like to disambiguate between
+ // "disallowed" and "disallowed because of a duplicate name".
+ bool disallowed_because_of_duplicate_name =
+ violation_details ==
+ ContentSecurityPolicy::AllowTrustedTypePolicyDetails::
+ kDisallowedDuplicateName;
+ const String message =
+ disallowed_because_of_duplicate_name
+ ? "Policy with name \"" + policy_name + "\" already exists."
+ : "Policy \"" + policy_name + "\" disallowed.";
+ exception_state.ThrowTypeError(message);
+ return nullptr;
+ }
}
UseCounter::Count(GetExecutionContext(),
WebFeature::kTrustedTypesPolicyCreated);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
index 82cd9c256f6..22aa22542ef 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -31,6 +31,7 @@ class CORE_EXPORT TrustedTypePolicyFactory final
explicit TrustedTypePolicyFactory(ExecutionContext*);
// TrustedTypePolicyFactory.idl
+ TrustedTypePolicy* createPolicy(const String&, ExceptionState&);
TrustedTypePolicy* createPolicy(const String&,
const TrustedTypePolicyOptions*,
ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
index 7465e550acf..7de315d89ad 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
@@ -8,7 +8,7 @@
Exposed=(Window, Worker),
RuntimeEnabled=TrustedDOMTypes
] interface TrustedTypePolicyFactory : EventTarget {
- [RaisesException] TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions);
+ [RaisesException] TrustedTypePolicy createPolicy(DOMString policyName, optional TrustedTypePolicyOptions policyOptions);
// All the policy object names that have been created
[CallWith=ScriptState] boolean isHTML(any checkedObject);
[CallWith=ScriptState] boolean isScript(any checkedObject);
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
index 29586e78b29..c66bec1ae9b 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -14,6 +14,7 @@
#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/inspector/console_message.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/script/script_element_base.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
@@ -45,6 +46,12 @@ enum TrustedTypeViolationKind {
kScriptExecutionAndDefaultPolicyFailed,
};
+// String to determine whether an incoming eval-ish call is comig from
+// an actual eval or a Function constructor. The value is derived from
+// from how JS builds up a string in the Function constructor, which in
+// turn is defined in the TC39 spec.
+const char* kAnonymousPrefix = "(function anonymous";
+
const char kFunctionConstructorFailureConsoleMessage[] =
"The JavaScript Function constructor does not accept TrustedString "
"arguments. See https://github.com/w3c/webappsec-trusted-types/wiki/"
@@ -98,7 +105,8 @@ const char* GetMessage(TrustedTypeViolationKind kind) {
return "";
}
-String GetSamplePrefix(const ExceptionState& exception_state) {
+String GetSamplePrefix(const ExceptionState& exception_state,
+ const String& value) {
const char* interface_name = exception_state.InterfaceName();
const char* property_name = exception_state.PropertyName();
@@ -109,7 +117,9 @@ String GetSamplePrefix(const ExceptionState& exception_state) {
if (!interface_name) {
// No interface name? Then we have no prefix to use.
} else if (strcmp("eval", interface_name) == 0) {
- sample_prefix.Append("eval");
+ // eval? Try to distinguish between eval and Function constructor.
+ sample_prefix.Append(value.StartsWith(kAnonymousPrefix) ? "Function"
+ : "eval");
} else if ((strcmp("Worker", interface_name) == 0 ||
strcmp("SharedWorker", interface_name) == 0) &&
!property_name) {
@@ -138,12 +148,13 @@ const char* GetElementName(const ScriptElementBase::Type type) {
HeapVector<ScriptValue> GetDefaultCallbackArgs(
v8::Isolate* isolate,
const char* type,
- const ExceptionState& exception_state) {
+ const ExceptionState& exception_state,
+ const String& value = g_empty_string) {
ScriptState* script_state = ScriptState::Current(isolate);
HeapVector<ScriptValue> args;
args.push_back(ScriptValue::From(script_state, type));
args.push_back(
- ScriptValue::From(script_state, GetSamplePrefix(exception_state)));
+ ScriptValue::From(script_state, GetSamplePrefix(exception_state, value)));
return args;
}
@@ -167,11 +178,7 @@ bool TrustedTypeFail(TrustedTypeViolationKind kind,
if (execution_context->GetTrustedTypes())
execution_context->GetTrustedTypes()->CountTrustedTypeAssignmentError();
- const char* kAnonymousPrefix = "(function anonymous";
- String prefix = GetSamplePrefix(exception_state);
- if (prefix == "eval" && value.StartsWith(kAnonymousPrefix)) {
- prefix = "Function";
- }
+ String prefix = GetSamplePrefix(exception_state, value);
bool allow =
execution_context->GetContentSecurityPolicy()
->AllowTrustedTypeAssignmentFailure(
@@ -184,7 +191,8 @@ bool TrustedTypeFail(TrustedTypeViolationKind kind,
// constructor failures, to warn the developer of the outstanding issues
// with TT and Function constructors. This should be removed once the
// underlying issue has been fixed.
- if (prefix == "Function" && !allow) {
+ if (prefix == "Function" && !allow &&
+ !RuntimeEnabledFeatures::TrustedTypesUseCodeLikeEnabled()) {
DCHECK(kind == kTrustedScriptAssignment ||
kind == kTrustedScriptAssignmentAndDefaultPolicyFailed ||
kind == kTrustedScriptAssignmentAndNoDefaultPolicyExisted);
@@ -194,6 +202,10 @@ bool TrustedTypeFail(TrustedTypeViolationKind kind,
mojom::blink::ConsoleMessageLevel::kInfo,
kFunctionConstructorFailureConsoleMessage));
}
+ probe::OnContentSecurityPolicyViolation(
+ const_cast<ExecutionContext*>(execution_context),
+ ContentSecurityPolicy::ContentSecurityPolicyViolationType::
+ kTrustedTypesSinkViolation);
if (!allow) {
exception_state.ThrowTypeError(GetMessage(kind));
@@ -260,7 +272,7 @@ String GetStringFromScriptHelper(
TrustedScript* result = default_policy->CreateScript(
context->GetIsolate(), script,
GetDefaultCallbackArgs(context->GetIsolate(), "TrustedScript",
- exception_state),
+ exception_state, script),
exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
@@ -365,7 +377,7 @@ String TrustedTypesCheckForScript(String script,
TrustedScript* result = default_policy->CreateScript(
execution_context->GetIsolate(), script,
GetDefaultCallbackArgs(execution_context->GetIsolate(), "TrustedScript",
- exception_state),
+ exception_state, script),
exception_state);
DCHECK_EQ(!result, exception_state.HadException());
if (exception_state.HadException()) {
diff --git a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
index 030078ebe7a..59af2dabf56 100644
--- a/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
+++ b/chromium/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
@@ -30,7 +30,7 @@ void TrustedTypesCheckForHTMLThrows(const String& string) {
EXPECT_FALSE(exception_state.HadException());
window->GetContentSecurityPolicy()->DidReceiveHeader(
- "require-trusted-types-for 'script'",
+ "require-trusted-types-for 'script'", *(window->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kMeta);
ASSERT_FALSE(exception_state.HadException());
@@ -50,7 +50,7 @@ void TrustedTypesCheckForScriptThrows(const String& string) {
EXPECT_FALSE(exception_state.HadException());
window->GetContentSecurityPolicy()->DidReceiveHeader(
- "require-trusted-types-for 'script'",
+ "require-trusted-types-for 'script'", *(window->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kMeta);
ASSERT_FALSE(exception_state.HadException());
@@ -70,7 +70,7 @@ void TrustedTypesCheckForScriptURLThrows(const String& string) {
EXPECT_FALSE(exception_state.HadException());
window->GetContentSecurityPolicy()->DidReceiveHeader(
- "require-trusted-types-for 'script'",
+ "require-trusted-types-for 'script'", *(window->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kMeta);
ASSERT_FALSE(exception_state.HadException());
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc b/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
index 686806bcafa..ec217020077 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
@@ -25,10 +25,11 @@
*/
#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
-#include "build/build_config.h"
-#include <string.h>
+#include <cstring>
+
#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/bits.h"
#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -106,17 +107,38 @@ void ArrayBufferContents::CopyTo(ArrayBufferContents& other) {
DataLength(), 1, IsShared() ? kShared : kNotShared, kDontInitialize);
if (!IsValid() || !other.IsValid())
return;
- memcpy(other.Data(), Data(), DataLength());
+ std::memcpy(other.Data(), Data(), DataLength());
}
void* ArrayBufferContents::AllocateMemoryWithFlags(size_t size,
InitializationPolicy policy,
int flags) {
+ // The array buffer contents are sometimes expected to be 16-byte aligned in
+ // order to get the best optimization of SSE, especially in case of audio and
+ // video buffers. Hence, align the given size up to 16-byte boundary.
+ // Technically speaking, 16-byte aligned size doesn't mean 16-byte aligned
+ // address, but this heuristics works with the current implementation of
+ // PartitionAlloc (and PartitionAlloc doesn't support a better way for now).
+ if (base::kAlignment < 16) { // base::kAlignment is a compile-time constant.
+ size_t aligned_size = base::bits::AlignUp(size, 16);
+ if (size == 0) {
+ aligned_size = 16;
+ }
+ if (aligned_size >= size) { // Only when no overflow
+ size = aligned_size;
+ }
+ }
+
if (policy == kZeroInitialize) {
flags |= base::PartitionAllocZeroFill;
}
void* data = WTF::Partitions::ArrayBufferPartition()->AllocFlags(
flags, size, WTF_HEAP_PROFILER_TYPE_NAME(ArrayBufferContents));
+ if (base::kAlignment < 16) {
+ char* ptr = reinterpret_cast<char*>(data);
+ DCHECK_EQ(base::bits::AlignUp(ptr, 16), ptr)
+ << "Pointer " << ptr << " not 16B aligned for size " << size;
+ }
InstanceCounters::IncrementCounter(
InstanceCounters::kArrayBufferContentsCounter);
return data;
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h b/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h
index 6223672e294..4fd11b7280f 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h
@@ -52,8 +52,6 @@ class NotShared {
return *this;
}
- // |View()| is a legacy API and deprecated. Use Get() instead.
- T* View() const { return GetRaw(); }
T* Get() const { return GetRaw(); }
void Clear() { typed_array_ = nullptr; }
@@ -110,8 +108,6 @@ class MaybeShared {
return *this;
}
- // |View()| is a legacy API and deprecated. Use Get() instead.
- T* View() const { return GetRaw(); }
T* Get() const { return GetRaw(); }
void Clear() { typed_array_ = nullptr; }
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
index abb1c4b716a..83c6b151f1d 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -117,6 +117,24 @@ v8::Local<v8::Value> DOMArrayBuffer::Wrap(
return AssociateWithWrapper(isolate, wrapper_type_info, wrapper);
}
+v8::MaybeLocal<v8::Value> DOMArrayBuffer::WrapV2(ScriptState* script_state) {
+ DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+ const WrapperTypeInfo* wrapper_type_info = this->GetWrapperTypeInfo();
+
+ v8::Local<v8::ArrayBuffer> wrapper;
+ {
+ v8::Context::Scope context_scope(script_state->GetContext());
+ wrapper = v8::ArrayBuffer::New(script_state->GetIsolate(),
+ Content()->BackingStore());
+
+ wrapper->Externalize(Content()->BackingStore());
+ }
+
+ return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
+ wrapper);
+}
+
DOMArrayBuffer* DOMArrayBuffer::Create(
scoped_refptr<SharedBuffer> shared_buffer) {
ArrayBufferContents contents(shared_buffer->size(), 1,
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
index e9a85d38d4d..e4314f3a780 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
@@ -78,6 +78,7 @@ class CORE_EXPORT DOMArrayBuffer final : public DOMArrayBufferBase {
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override;
private:
bool TransferDetachable(v8::Isolate*, ArrayBufferContents& result);
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
index 979628f76e2..ecc33268eb5 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
@@ -33,11 +33,16 @@ class CORE_EXPORT DOMArrayBufferBase : public ScriptWrappable {
bool IsShared() const { return contents_.IsShared(); }
+ // ScriptWrappable overrides:
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override {
NOTREACHED();
return v8::Local<v8::Object>();
}
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override {
+ NOTREACHED();
+ return v8::MaybeLocal<v8::Value>();
+ }
protected:
explicit DOMArrayBufferBase(ArrayBufferContents contents)
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h
index 701292794d5..504a8db9447 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h
@@ -111,17 +111,26 @@ class CORE_EXPORT DOMArrayBufferView : public ScriptWrappable {
return !IsDetached() ? raw_base_address_ : nullptr;
}
+ // ScriptWrappable overrides:
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override {
NOTREACHED();
return v8::Local<v8::Object>();
}
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override {
+ NOTREACHED();
+ return v8::MaybeLocal<v8::Value>();
+ }
void Trace(Visitor* visitor) const override {
visitor->Trace(dom_array_buffer_);
ScriptWrappable::Trace(visitor);
}
+ void DetachForTesting() { dom_array_buffer_->Detach(); }
+
+ bool IsDetached() const { return dom_array_buffer_->IsDetached(); }
+
protected:
DOMArrayBufferView(DOMArrayBufferBase* dom_array_buffer, size_t byte_offset)
: raw_byte_offset_(byte_offset), dom_array_buffer_(dom_array_buffer) {
@@ -130,8 +139,6 @@ class CORE_EXPORT DOMArrayBufferView : public ScriptWrappable {
static_cast<char*>(dom_array_buffer_->DataMaybeShared()) + byte_offset;
}
- bool IsDetached() const { return dom_array_buffer_->IsDetached(); }
-
private:
// The raw_* fields may be stale after Detach. Use getters instead.
// This is the address of the ArrayBuffer's storage, plus the byte offset.
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_piece.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_piece.cc
index e271b437cf6..e8cc31cf78a 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_piece.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_array_piece.cc
@@ -15,7 +15,7 @@ DOMArrayPiece::DOMArrayPiece(
InitWithArrayBuffer(array_buffer);
} else if (array_buffer_or_view.IsArrayBufferView()) {
DOMArrayBufferView* array_buffer_view =
- array_buffer_or_view.GetAsArrayBufferView().View();
+ array_buffer_or_view.GetAsArrayBufferView().Get();
InitWithArrayBufferView(array_buffer_view);
}
}
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
index 4c8dbaaac99..1e22255a331 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
#include "base/numerics/checked_math.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
@@ -35,4 +36,22 @@ v8::Local<v8::Value> DOMDataView::Wrap(v8::Isolate* isolate,
return AssociateWithWrapper(isolate, wrapper_type_info, wrapper);
}
+v8::MaybeLocal<v8::Value> DOMDataView::WrapV2(ScriptState* script_state) {
+ DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+ const WrapperTypeInfo* wrapper_type_info = this->GetWrapperTypeInfo();
+ v8::Local<v8::Value> v8_buffer;
+ if (!ToV8Traits<DOMArrayBuffer>::ToV8(script_state, buffer())
+ .ToLocal(&v8_buffer)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ DCHECK(v8_buffer->IsArrayBuffer());
+
+ v8::Local<v8::Object> wrapper = v8::DataView::New(
+ v8_buffer.As<v8::ArrayBuffer>(), byteOffset(), byteLength());
+
+ return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
+ wrapper);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.h
index a8362e9cbb9..a4734d523d8 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_data_view.h
@@ -28,6 +28,7 @@ class CORE_EXPORT DOMDataView final : public DOMArrayBufferView {
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override;
size_t byteLength() const final {
return !IsDetached() ? raw_byte_length_ : 0;
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
index 720f112b53d..f897b6c7943 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
@@ -21,4 +21,17 @@ v8::Local<v8::Value> DOMSharedArrayBuffer::Wrap(
return AssociateWithWrapper(isolate, wrapper_type_info, wrapper);
}
+v8::MaybeLocal<v8::Value> DOMSharedArrayBuffer::WrapV2(
+ ScriptState* script_state) {
+ DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+ const WrapperTypeInfo* wrapper_type_info = this->GetWrapperTypeInfo();
+ v8::Local<v8::SharedArrayBuffer> wrapper = v8::SharedArrayBuffer::New(
+ script_state->GetIsolate(), Content()->BackingStore());
+ wrapper->Externalize(Content()->BackingStore());
+
+ return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
+ wrapper);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h
index a504cf95640..14e34840e77 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.h
@@ -57,6 +57,7 @@ class CORE_EXPORT DOMSharedArrayBuffer final : public DOMArrayBufferBase {
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
index 9ca42d46ed5..68748957739 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_big_int_64_array.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_big_uint_64_array.h"
@@ -45,6 +46,33 @@ v8::Local<v8::Value> DOMTypedArray<T, V8TypedArray, clamped>::Wrap(
return AssociateWithWrapper(isolate, wrapper_type_info, wrapper);
}
+template <typename T, typename V8TypedArray, bool clamped>
+v8::MaybeLocal<v8::Value> DOMTypedArray<T, V8TypedArray, clamped>::WrapV2(
+ ScriptState* script_state) {
+ DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+ const WrapperTypeInfo* wrapper_type_info = this->GetWrapperTypeInfo();
+ DOMArrayBufferBase* buffer = this->BufferBase();
+ v8::Local<v8::Value> v8_buffer;
+ if (!ToV8Traits<DOMArrayBufferBase>::ToV8(script_state, buffer)
+ .ToLocal(&v8_buffer)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ DCHECK_EQ(IsShared(), v8_buffer->IsSharedArrayBuffer());
+
+ v8::Local<v8::Object> wrapper;
+ if (IsShared()) {
+ wrapper = V8TypedArray::New(v8_buffer.As<v8::SharedArrayBuffer>(),
+ byteOffset(), length());
+ } else {
+ wrapper = V8TypedArray::New(v8_buffer.As<v8::ArrayBuffer>(), byteOffset(),
+ length());
+ }
+
+ return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
+ wrapper);
+}
+
// TODO(tasak): The following traits should be auto-generated by binding
// script and should be placed in bindings/core/v8/V8*Array.h.
template <typename ArrayType>
diff --git a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
index 6e793c17e9a..452a6d2c75d 100644
--- a/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
+++ b/chromium/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
@@ -98,6 +98,7 @@ class DOMTypedArray final : public DOMArrayBufferView {
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) override;
private:
// It may be stale after Detach. Use length() instead.
diff --git a/chromium/third_party/blink/renderer/core/url/DIR_METADATA b/chromium/third_party/blink/renderer/core/url/DIR_METADATA
new file mode 100644
index 00000000000..791d1cbe758
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/url/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Network"
+}
+
+team_email: "blink-network-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/url/OWNERS b/chromium/third_party/blink/renderer/core/url/OWNERS
index aa9bc482b2e..3f8456354bd 100644
--- a/chromium/third_party/blink/renderer/core/url/OWNERS
+++ b/chromium/third_party/blink/renderer/core/url/OWNERS
@@ -1,4 +1 @@
mkwst@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network
diff --git a/chromium/third_party/blink/renderer/core/web_test/BUILD.gn b/chromium/third_party/blink/renderer/core/web_test/BUILD.gn
new file mode 100644
index 00000000000..0c9288da751
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/web_test/BUILD.gn
@@ -0,0 +1,44 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import("//build/config/dcheck_always_on.gni")
+import("//third_party/blink/renderer/core/core.gni")
+
+source_set("web_test") {
+ testonly = true
+
+ visibility = [ "//content/web_test:web_test_renderer" ]
+
+ configs += [
+ "//third_party/blink/renderer:config",
+ "//third_party/blink/renderer:inside_blink",
+ ]
+
+ deps = [
+ "//base:base",
+
+ # There is a circular dependency with test runner. This
+ # will eventually be removed when all dependent classes move
+ # into blink.
+ # We do not include the dependency here but it is marked as allowing
+ # circular includes in the web_test_renderer config.
+ # "//content/web_test:web_test_renderer",
+
+ # TODO(crbug.com/1154721): The `allow_circular_includes_from` declared in
+ # `//content/web_test:web_test_renderer` does not propagate the public_deps
+ # from `web_test_renderer`'s own dependencies. This means that those targets
+ # are not built, and some generated mojom headers are missing. As a
+ # workaround, add this dep so that `web_test_renderer` has all of the
+ # headers it needs.
+ "//content/web_test:web_test_common",
+
+ "//third_party/blink/public:blink_headers",
+ "//third_party/blink/public:test_headers",
+ "//third_party/blink/renderer/core:core",
+ ]
+
+ sources = [
+ "web_test_web_frame_widget_impl.cc",
+ "web_test_web_frame_widget_impl.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/core/web_test/DEPS b/chromium/third_party/blink/renderer/core/web_test/DEPS
new file mode 100644
index 00000000000..e963884b68b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/web_test/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+content/web_test/renderer/event_sender.h",
+ "+content/web_test/renderer/test_runner.h",
+]
diff --git a/chromium/third_party/blink/renderer/core/web_test/OWNERS b/chromium/third_party/blink/renderer/core/web_test/OWNERS
new file mode 100644
index 00000000000..d2f8ec502af
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/web_test/OWNERS
@@ -0,0 +1,4 @@
+mkwst@chromium.org
+peter@chromium.org
+danakj@chromium.org
+
diff --git a/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc b/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc
new file mode 100644
index 00000000000..520b10bdafa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc
@@ -0,0 +1,274 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h"
+
+#include "content/web_test/renderer/event_sender.h"
+#include "content/web_test/renderer/test_runner.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_page_popup.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/public/web/web_widget.h"
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+
+namespace blink {
+
+WebFrameWidget* FrameWidgetTestHelper::CreateTestWebFrameWidget(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ content::TestRunner* test_runner) {
+ return MakeGarbageCollected<WebTestWebFrameWidgetImpl>(
+ pass_key, std::move(frame_widget_host), std::move(frame_widget),
+ std::move(widget_host), std::move(widget), std::move(task_runner),
+ frame_sink_id, hidden, never_composited, is_for_child_local_root,
+ is_for_nested_main_frame, test_runner);
+}
+
+WebTestWebFrameWidgetImpl::WebTestWebFrameWidgetImpl(
+ base::PassKey<WebLocalFrame> pass_key,
+ CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
+ frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ content::TestRunner* test_runner)
+ : WebFrameWidgetImpl(pass_key,
+ std::move(frame_widget_host),
+ std::move(frame_widget),
+ std::move(widget_host),
+ std::move(widget),
+ std::move(task_runner),
+ frame_sink_id,
+ hidden,
+ never_composited,
+ is_for_child_local_root,
+ is_for_nested_main_frame),
+ test_runner_(test_runner) {}
+
+WebTestWebFrameWidgetImpl::~WebTestWebFrameWidgetImpl() = default;
+
+void WebTestWebFrameWidgetImpl::BindLocalRoot(WebLocalFrame& local_root) {
+ WebFrameWidgetImpl::BindLocalRoot(local_root);
+ // We need to initialize EventSender after the binding of the local root
+ // as the EventSender constructor accesses LocalRoot and that is not
+ // set until BindLocalRoot is called.
+ event_sender_ = std::make_unique<content::EventSender>(this, test_runner_);
+}
+
+void WebTestWebFrameWidgetImpl::WillBeginMainFrame() {
+ // WillBeginMainFrame occurs before we run BeginMainFrame() in the base
+ // class, which will change states. TestFinished() wants to grab the current
+ // state.
+ GetTestRunner()->FinishTestIfReady();
+
+ WebFrameWidgetImpl::WillBeginMainFrame();
+}
+
+void WebTestWebFrameWidgetImpl::ScheduleAnimation() {
+ if (GetTestRunner()->TestIsRunning())
+ ScheduleAnimationInternal(GetTestRunner()->animation_requires_raster());
+}
+
+void WebTestWebFrameWidgetImpl::ScheduleAnimationForWebTests() {
+ // Single threaded web tests must explicitly schedule commits.
+ //
+ // Pass true for |do_raster| to ensure the compositor is actually run, rather
+ // than just doing the main frame animate step. That way we know it will
+ // submit a frame and later trigger the presentation callback in order to make
+ // progress in the test.
+ if (GetTestRunner()->TestIsRunning())
+ ScheduleAnimationInternal(/*do_raster=*/true);
+}
+
+void WebTestWebFrameWidgetImpl::UpdateAllLifecyclePhasesAndComposite(
+ base::OnceClosure callback) {
+ LayerTreeHost()->RequestPresentationTimeForNextFrame(WTF::Bind(
+ [](base::OnceClosure callback, const gfx::PresentationFeedback&) {
+ std::move(callback).Run();
+ },
+ std::move(callback)));
+ LayerTreeHost()->SetNeedsCommitWithForcedRedraw();
+ ScheduleAnimationForWebTests();
+}
+
+void WebTestWebFrameWidgetImpl::ScheduleAnimationInternal(bool do_raster) {
+ // When using threaded compositing, have the WeFrameWidgetImpl normally
+ // schedule a request for a frame, as we use the compositor's scheduler.
+ if (scheduler::WebThreadScheduler::CompositorThreadScheduler()) {
+ WebFrameWidgetImpl::ScheduleAnimation();
+ return;
+ }
+
+ // If an animation already scheduled we'll make it composite, otherwise we'll
+ // schedule another animation step with composite now.
+ composite_requested_ |= do_raster;
+
+ if (!animation_scheduled_) {
+ animation_scheduled_ = true;
+
+ WebLocalFrame* frame = LocalRoot();
+
+ frame->GetTaskRunner(TaskType::kInternalTest)
+ ->PostDelayedTask(FROM_HERE,
+ WTF::Bind(&WebTestWebFrameWidgetImpl::AnimateNow,
+ WrapWeakPersistent(this)),
+ base::TimeDelta::FromMilliseconds(1));
+ }
+}
+
+void WebTestWebFrameWidgetImpl::StartDragging(const WebDragData& data,
+ DragOperationsMask mask,
+ const SkBitmap& drag_image,
+ const gfx::Point& image_offset) {
+ doing_drag_and_drop_ = true;
+ GetTestRunner()->SetDragImage(drag_image);
+
+ // When running a test, we need to fake a drag drop operation otherwise
+ // Windows waits for real mouse events to know when the drag is over.
+ event_sender_->DoDragDrop(data, mask);
+}
+
+FrameWidgetTestHelper*
+WebTestWebFrameWidgetImpl::GetFrameWidgetTestHelperForTesting() {
+ return this;
+}
+
+void WebTestWebFrameWidgetImpl::Reset() {
+ event_sender_->Reset();
+ // Ends any synthetic gestures started in |event_sender_|.
+ FlushInputProcessedCallback();
+
+ // Reset state in the base class.
+ ClearEditCommands();
+
+ SetDeviceScaleFactorForTesting(0);
+ ReleaseMouseLockAndPointerCaptureForTesting();
+
+ // These things are only modified/valid for the main frame's widget.
+ if (ForMainFrame()) {
+ ResetZoomLevelForTesting();
+
+ SetMainFrameOverlayColor(SK_ColorTRANSPARENT);
+ SetTextZoomFactor(1);
+ }
+}
+
+content::EventSender* WebTestWebFrameWidgetImpl::GetEventSender() {
+ return event_sender_.get();
+}
+
+void WebTestWebFrameWidgetImpl::SynchronouslyCompositeAfterTest() {
+ // We could DCHECK(!GetTestRunner()->TestIsRunning()) except that frames in
+ // other processes than the main frame do not hear when the test ends.
+
+ // This would be very weird and prevent us from producing pixels.
+ DCHECK(!in_synchronous_composite_);
+
+ SynchronouslyComposite(/*do_raster=*/true);
+}
+
+content::TestRunner* WebTestWebFrameWidgetImpl::GetTestRunner() {
+ return test_runner_;
+}
+
+// static
+void WebTestWebFrameWidgetImpl::DoComposite(cc::LayerTreeHost* layer_tree_host,
+ bool do_raster) {
+ // Ensure that there is damage so that the compositor submits, and the display
+ // compositor draws this frame.
+ if (do_raster) {
+ layer_tree_host->SetNeedsCommitWithForcedRedraw();
+ }
+
+ layer_tree_host->CompositeForTest(base::TimeTicks::Now(), do_raster);
+}
+
+void WebTestWebFrameWidgetImpl::SynchronouslyComposite(bool do_raster) {
+ if (!LocalRootImpl()->ViewImpl()->does_composite())
+ return;
+ DCHECK(!LayerTreeHost()->GetSettings().single_thread_proxy_scheduler);
+
+ if (!LayerTreeHost()->IsVisible())
+ return;
+
+ if (in_synchronous_composite_) {
+ // Web tests can use a nested message loop to pump frames while inside a
+ // frame, but the compositor does not support this. In this case, we only
+ // run blink's lifecycle updates.
+ UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
+ return;
+ }
+
+ in_synchronous_composite_ = true;
+
+ // DoComposite() can detach the frame.
+ DoComposite(LayerTreeHost(), do_raster);
+ if (!LocalRoot())
+ return;
+
+ in_synchronous_composite_ = false;
+
+ // If this widget is for the main frame, we also composite the current
+ // PagePopup afterward.
+ //
+ // TODO(danakj): This means that an OOPIF's popup, which is attached to a
+ // WebView without a main frame, would have no opportunity to execute this
+ // method call.
+ if (ForMainFrame()) {
+ WebViewImpl* view = LocalRootImpl()->ViewImpl();
+ if (WebPagePopupImpl* popup = view->GetPagePopup()) {
+ DoComposite(popup->LayerTreeHostForTesting(), do_raster);
+ }
+ }
+}
+
+void WebTestWebFrameWidgetImpl::AnimateNow() {
+ // If we have been Closed but not destroyed yet, return early.
+ if (!LocalRootImpl()) {
+ return;
+ }
+ bool do_raster = composite_requested_;
+ animation_scheduled_ = false;
+ composite_requested_ = false;
+ // Composite may destroy |this|, so don't use it afterward.
+ SynchronouslyComposite(do_raster);
+}
+
+void WebTestWebFrameWidgetImpl::RequestDecode(
+ const PaintImage& image,
+ base::OnceCallback<void(bool)> callback) {
+ WebFrameWidgetImpl::RequestDecode(image, std::move(callback));
+
+ // In web tests the request does not actually cause a commit, because the
+ // compositor is scheduled by the test runner to avoid flakiness. So for this
+ // case we must request a main frame.
+ ScheduleAnimationForWebTests();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h b/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h
new file mode 100644
index 00000000000..ba740c8ccb1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h
@@ -0,0 +1,112 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WEB_TEST_WEB_TEST_WEB_FRAME_WIDGET_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_WEB_TEST_WEB_TEST_WEB_FRAME_WIDGET_IMPL_H_
+
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "third_party/blink/public/test/frame_widget_test_helper.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
+
+namespace blink {
+
+// WebTestWebFrameWidgetImpl is used to run web tests. This class is a subclass
+// of WebFrameWidgetImpl that overrides the minimal necessary portions. These
+// portions are limited:
+// 1) Handling single threaded compositing.
+// 2) Emulating drag and drop.
+//
+// This class exists inside blink so that it can subclass the WebFrameWidgetImpl
+// yet still depends on content/web_test/renderer classes. This will eventually
+// be cleaned up with more content code moving into blink but it is fine for
+// now since it is only used in tests.
+class WebTestWebFrameWidgetImpl : public WebFrameWidgetImpl,
+ public FrameWidgetTestHelper {
+ public:
+ WebTestWebFrameWidgetImpl(
+ base::PassKey<WebLocalFrame>,
+ CrossVariantMojoAssociatedRemote<
+ mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
+ frame_widget,
+ CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
+ widget_host,
+ CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
+ widget,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const viz::FrameSinkId& frame_sink_id,
+ bool hidden,
+ bool never_composited,
+ bool is_for_child_local_root,
+ bool is_for_nested_main_frame,
+ content::TestRunner* test_runner);
+
+ ~WebTestWebFrameWidgetImpl() override;
+
+ // FrameWidgetTestHelper overrides.
+ void Reset() override;
+ content::EventSender* GetEventSender() override;
+ void SynchronouslyCompositeAfterTest() override;
+ void UpdateAllLifecyclePhasesAndComposite(
+ base::OnceClosure completion_callback) override;
+
+ // WebFrameWidget overrides.
+ FrameWidgetTestHelper* GetFrameWidgetTestHelperForTesting() override;
+
+ // FrameWidget overrides.
+ void RequestDecode(const cc::PaintImage&,
+ base::OnceCallback<void(bool)>) override;
+
+ private:
+ // WebFrameWidgetImpl overrides.
+ void BindLocalRoot(WebLocalFrame&) override;
+ void StartDragging(const WebDragData& drag_data,
+ DragOperationsMask operations_allowed,
+ const SkBitmap& drag_image,
+ const gfx::Point& drag_image_offset) override;
+
+ // WidgetBaseClient overrides:
+ void ScheduleAnimation() override;
+ void WillBeginMainFrame() override;
+ void ScheduleAnimationForWebTests() override;
+
+ content::TestRunner* GetTestRunner();
+
+ void ScheduleAnimationInternal(bool do_raster);
+ void AnimateNow();
+
+ // When |do_raster| is false, only a main frame animation step is performed,
+ // but when true, a full composite is performed and a frame submitted to the
+ // display compositor if there is any damage.
+ // Note that compositing has the potential to detach the current frame and
+ // thus destroy |this| before returning.
+ void SynchronouslyComposite(bool do_raster);
+
+ // Perform the synchronous composite step for a given LayerTreeHost.
+ static void DoComposite(cc::LayerTreeHost* layer_tree_host, bool do_raster);
+
+ std::unique_ptr<content::EventSender> event_sender_;
+
+ content::TestRunner* const test_runner_;
+
+ // For collapsing multiple simulated ScheduleAnimation() calls.
+ bool animation_scheduled_ = false;
+ // When true, an AnimateNow() is scheduled that will perform a full composite.
+ // Otherwise, any scheduled AnimateNow() calls will only perform the animation
+ // step, which calls out to blink but doesn't composite for performance
+ // reasons. See setAnimationRequiresRaster() in
+ // https://chromium.googlesource.com/chromium/src/+/master/docs/testing/writing_web_tests.md
+ // for details on the optimization.
+ bool composite_requested_ = false;
+ // Synchronous composites should not be nested inside another
+ // composite, and this bool is used to guard against that.
+ bool in_synchronous_composite_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WEB_TEST_WEB_TEST_WEB_FRAME_WIDGET_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/DIR_METADATA b/chromium/third_party/blink/renderer/core/workers/DIR_METADATA
new file mode 100644
index 00000000000..a458fab72fe
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Workers"
+}
+
+team_email: "worker-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/workers/OWNERS b/chromium/third_party/blink/renderer/core/workers/OWNERS
index 2cdf64f5ada..51ebce62704 100644
--- a/chromium/third_party/blink/renderer/core/workers/OWNERS
+++ b/chromium/third_party/blink/renderer/core/workers/OWNERS
@@ -3,6 +3,3 @@ falken@chromium.org
hiroshige@chromium.org
japhet@chromium.org
nhiroki@chromium.org
-
-# TEAM: worker-dev@chromium.org
-# COMPONENT: Blink>Workers
diff --git a/chromium/third_party/blink/renderer/core/workers/README.md b/chromium/third_party/blink/renderer/core/workers/README.md
index 9d1ea093c51..b00106eaec8 100644
--- a/chromium/third_party/blink/renderer/core/workers/README.md
+++ b/chromium/third_party/blink/renderer/core/workers/README.md
@@ -160,6 +160,7 @@ in the following files and directories to avoid breakage.
- Web Platform Tests
- [content-security-policy/](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/content-security-policy/)
+ - [cross-origin-embedder-policy/](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/)
- [fetch/](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/fetch/)
- [mixed-content/](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/mixed-content/)
- [performance-timeline/](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/performance-timeline/)
diff --git a/chromium/third_party/blink/renderer/core/workers/build.gni b/chromium/third_party/blink/renderer/core/workers/build.gni
index 6e8cda93515..5581cc057d5 100644
--- a/chromium/third_party/blink/renderer/core/workers/build.gni
+++ b/chromium/third_party/blink/renderer/core/workers/build.gni
@@ -7,6 +7,8 @@ import("//third_party/blink/renderer/core/core.gni")
blink_core_sources_workers = [
"abstract_worker.cc",
"abstract_worker.h",
+ "cross_thread_global_scope_creation_params_copier.cc",
+ "cross_thread_global_scope_creation_params_copier.h",
"dedicated_worker.cc",
"dedicated_worker.h",
"dedicated_worker_global_scope.cc",
diff --git a/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.cc b/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.cc
new file mode 100644
index 00000000000..e97ac0282b2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.cc
@@ -0,0 +1,122 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.h"
+
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
+
+namespace WTF {
+
+namespace {
+
+network::mojom::blink::CSPSourcePtr CSPSourceIsolatedCopy(
+ const network::mojom::blink::CSPSourcePtr& in) {
+ if (!in)
+ return nullptr;
+ return network::mojom::blink::CSPSource::New(
+ CrossThreadCopier<String>::Copy(in->scheme),
+ CrossThreadCopier<String>::Copy(in->host), in->port,
+ CrossThreadCopier<String>::Copy(in->path), in->is_host_wildcard,
+ in->is_port_wildcard);
+}
+
+network::mojom::blink::CSPHashSourcePtr CSPHashSourceIsolatedCopy(
+ const network::mojom::blink::CSPHashSourcePtr& in) {
+ if (!in)
+ return nullptr;
+ return network::mojom::blink::CSPHashSource::New(
+ in->algorithm, CrossThreadCopier<Vector<uint8_t>>::Copy(in->value));
+}
+
+HashMap<network::mojom::blink::CSPDirectiveName, String>
+RawDirectivesIsolatedCopy(
+ const HashMap<network::mojom::blink::CSPDirectiveName, String>& in) {
+ HashMap<network::mojom::blink::CSPDirectiveName, String> out;
+ for (const auto& element : in) {
+ out.insert(element.key, CrossThreadCopier<String>::Copy(element.value));
+ }
+ return out;
+}
+
+network::mojom::blink::CSPSourceListPtr CSPSourceListIsolatedCopy(
+ const network::mojom::blink::CSPSourceListPtr& in) {
+ if (!in)
+ return nullptr;
+ Vector<network::mojom::blink::CSPSourcePtr> sources;
+ for (const auto& source : in->sources)
+ sources.push_back(CSPSourceIsolatedCopy(source));
+
+ Vector<network::mojom::blink::CSPHashSourcePtr> hashes;
+ for (const auto& hash : in->hashes)
+ hashes.push_back(CSPHashSourceIsolatedCopy(hash));
+
+ return network::mojom::blink::CSPSourceList::New(
+ std::move(sources), CrossThreadCopier<Vector<String>>::Copy(in->nonces),
+ std::move(hashes), in->allow_self, in->allow_star,
+ in->allow_response_redirects, in->allow_inline, in->allow_eval,
+ in->allow_wasm_eval, in->allow_dynamic, in->allow_unsafe_hashes,
+ in->report_sample);
+}
+
+HashMap<network::mojom::blink::CSPDirectiveName,
+ network::mojom::blink::CSPSourceListPtr>
+DirectivesIsolatedCopy(
+ const HashMap<network::mojom::blink::CSPDirectiveName,
+ network::mojom::blink::CSPSourceListPtr>& in) {
+ HashMap<network::mojom::blink::CSPDirectiveName,
+ network::mojom::blink::CSPSourceListPtr>
+ out;
+ for (const auto& element : in) {
+ out.insert(element.key, CSPSourceListIsolatedCopy(element.value));
+ }
+ return out;
+}
+
+network::mojom::blink::ContentSecurityPolicyPtr
+ContentSecurityPolicyIsolatedCopy(
+ const network::mojom::blink::ContentSecurityPolicyPtr& csp) {
+ if (!csp)
+ return nullptr;
+ return network::mojom::blink::ContentSecurityPolicy::New(
+ CSPSourceIsolatedCopy(csp->self_origin),
+ RawDirectivesIsolatedCopy(csp->raw_directives),
+ DirectivesIsolatedCopy(csp->directives), csp->upgrade_insecure_requests,
+ csp->treat_as_public_address, csp->block_all_mixed_content, csp->sandbox,
+ network::mojom::blink::ContentSecurityPolicyHeader::New(
+ CrossThreadCopier<String>::Copy(csp->header->header_value),
+ csp->header->type, csp->header->source),
+ csp->use_reporting_api,
+ CrossThreadCopier<Vector<String>>::Copy(csp->report_endpoints),
+ csp->require_trusted_types_for,
+ csp->trusted_types ? network::mojom::blink::CSPTrustedTypes::New(
+ CrossThreadCopier<Vector<String>>::Copy(
+ csp->trusted_types->list),
+ csp->trusted_types->allow_any,
+ csp->trusted_types->allow_duplicates)
+ : nullptr,
+ CrossThreadCopier<Vector<String>>::Copy(csp->parsing_errors));
+}
+
+} // namespace
+
+CrossThreadCopier<Vector<network::mojom::blink::ContentSecurityPolicyPtr>>::Type
+CrossThreadCopier<Vector<network::mojom::blink::ContentSecurityPolicyPtr>>::
+ Copy(const Vector<network::mojom::blink::ContentSecurityPolicyPtr>&
+ list_in) {
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> list_out;
+ for (const auto& element : list_in)
+ list_out.emplace_back(ContentSecurityPolicyIsolatedCopy(element));
+ return list_out;
+}
+
+CrossThreadCopier<std::unique_ptr<blink::GlobalScopeCreationParams>>::Type
+CrossThreadCopier<std::unique_ptr<blink::GlobalScopeCreationParams>>::Copy(
+ std::unique_ptr<blink::GlobalScopeCreationParams> pointer) {
+ pointer->outside_content_security_policies = CrossThreadCopier<
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>>::
+ Copy(pointer->outside_content_security_policies);
+ return pointer;
+}
+
+} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.h b/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.h
new file mode 100644
index 00000000000..dc736c5d00f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_CROSS_THREAD_GLOBAL_SCOPE_CREATION_PARAMS_COPIER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_CROSS_THREAD_GLOBAL_SCOPE_CREATION_PARAMS_COPIER_H_
+
+#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
+#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
+
+namespace WTF {
+
+template <>
+struct CrossThreadCopier<
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = Vector<network::mojom::blink::ContentSecurityPolicyPtr>;
+ static Type Copy(const Type&);
+};
+
+template <>
+struct CrossThreadCopier<std::unique_ptr<blink::GlobalScopeCreationParams>> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = std::unique_ptr<blink::GlobalScopeCreationParams>;
+ static Type Copy(Type);
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_CROSS_THREAD_GLOBAL_SCOPE_CREATION_PARAMS_COPIER_H_
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
index fee83e61fc7..39ebcef3f86 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -19,7 +19,6 @@
#include "third_party/blink/public/mojom/worker/dedicated_worker_host_factory.mojom-blink.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_fetch_client_settings_object.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_post_message_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -30,7 +29,7 @@
#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/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
#include "third_party/blink/renderer/core/loader/appcache/application_cache_host.h"
@@ -281,7 +280,7 @@ BeginFrameProviderParams DedicatedWorker::CreateBeginFrameProviderParams() {
if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext())) {
LocalFrame* frame = window->GetFrame();
if (frame) {
- WebFrameWidgetBase* widget =
+ WebFrameWidgetImpl* widget =
WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget();
begin_frame_provider_params.parent_frame_sink_id =
widget->GetFrameSinkId();
@@ -309,9 +308,12 @@ bool DedicatedWorker::HasPendingActivity() const {
void DedicatedWorker::OnWorkerHostCreated(
CrossVariantMojoRemote<mojom::blink::BrowserInterfaceBrokerInterfaceBase>
- browser_interface_broker) {
+ browser_interface_broker,
+ CrossVariantMojoRemote<mojom::blink::DedicatedWorkerHostInterfaceBase>
+ dedicated_worker_host) {
DCHECK(!browser_interface_broker_);
browser_interface_broker_ = std::move(browser_interface_broker);
+ pending_dedicated_worker_host_ = std::move(dedicated_worker_host);
}
void DedicatedWorker::OnScriptLoadStarted(
@@ -400,7 +402,8 @@ void DedicatedWorker::ContinueStart(
response_address_space),
std::move(worker_main_script_load_params), options_, script_url,
*outside_fetch_client_settings_object_, v8_stack_trace_id_, source_code,
- reject_coep_unsafe_none, token_);
+ reject_coep_unsafe_none, token_,
+ std::move(pending_dedicated_worker_host_));
}
std::unique_ptr<GlobalScopeCreationParams>
@@ -410,23 +413,31 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
base::Optional<network::mojom::IPAddressSpace> response_address_space) {
base::UnguessableToken parent_devtools_token;
std::unique_ptr<WorkerSettings> settings;
- UserAgentMetadata ua_metadata;
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner;
if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext())) {
+ // When the main thread creates a new DedicatedWorker.
auto* frame = window->GetFrame();
- if (frame) {
+ if (frame)
parent_devtools_token = frame->GetDevToolsFrameToken();
- ua_metadata = frame->Loader().UserAgentMetadata().value_or(
- blink::UserAgentMetadata());
- }
settings = std::make_unique<WorkerSettings>(frame->GetSettings());
+ agent_group_scheduler_compositor_task_runner =
+ GetExecutionContext()
+ ->GetScheduler()
+ ->ToFrameScheduler()
+ ->GetAgentGroupScheduler()
+ ->CompositorTaskRunner();
} else {
+ // When a DedicatedWorker creates another DedicatedWorker (nested worker).
WorkerGlobalScope* worker_global_scope =
To<WorkerGlobalScope>(GetExecutionContext());
parent_devtools_token =
worker_global_scope->GetThread()->GetDevToolsWorkerToken();
- ua_metadata = worker_global_scope->GetUserAgentMetadata();
settings = WorkerSettings::Copy(worker_global_scope->GetWorkerSettings());
+ agent_group_scheduler_compositor_task_runner =
+ worker_global_scope->GetAgentGroupSchedulerCompositorTaskRunner();
}
+ DCHECK(agent_group_scheduler_compositor_task_runner);
mojom::blink::ScriptType script_type =
(options_->type() == "classic") ? mojom::blink::ScriptType::kClassic
@@ -434,9 +445,12 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
return std::make_unique<GlobalScopeCreationParams>(
script_url, script_type, options_->name(),
- GetExecutionContext()->UserAgent(), ua_metadata,
+ GetExecutionContext()->UserAgent(),
+ GetExecutionContext()->GetUserAgentMetadata(),
CreateWebWorkerFetchContext(),
- GetExecutionContext()->GetContentSecurityPolicy()->Headers(),
+ mojo::Clone(GetExecutionContext()
+ ->GetContentSecurityPolicy()
+ ->GetParsedPolicies()),
referrer_policy, GetExecutionContext()->GetSecurityOrigin(),
GetExecutionContext()->IsSecureContext(),
GetExecutionContext()->GetHttpsState(),
@@ -449,8 +463,10 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
std::move(browser_interface_broker_), CreateBeginFrameProviderParams(),
GetExecutionContext()->GetSecurityContext().GetFeaturePolicy(),
GetExecutionContext()->GetAgentClusterID(),
+ GetExecutionContext()->UkmSourceID(),
GetExecutionContext()->GetExecutionContextToken(),
- GetExecutionContext()->CrossOriginIsolatedCapability());
+ GetExecutionContext()->CrossOriginIsolatedCapability(),
+ std::move(agent_group_scheduler_compositor_task_runner));
}
scoped_refptr<WebWorkerFetchContext>
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
index f31072794ff..7daf1b185e3 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -12,6 +12,7 @@
#include "third_party/blink/public/common/loader/worker_main_script_load_parameters.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/browser_interface_broker.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_dedicated_worker.h"
#include "third_party/blink/public/platform/web_dedicated_worker_host_factory_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
@@ -85,10 +86,11 @@ class CORE_EXPORT DedicatedWorker final
bool HasPendingActivity() const final;
// Implements WebDedicatedWorker.
- // Called only when PlzDedicatedWorker is enabled.
void OnWorkerHostCreated(
CrossVariantMojoRemote<mojom::blink::BrowserInterfaceBrokerInterfaceBase>
- browser_interface_broker) override;
+ browser_interface_broker,
+ CrossVariantMojoRemote<mojom::blink::DedicatedWorkerHostInterfaceBase>
+ dedicated_worker_host) override;
void OnScriptLoadStarted(std::unique_ptr<WorkerMainScriptLoadParameters>
worker_main_script_load_params) override;
void OnScriptLoadStartFailed() override;
@@ -159,6 +161,10 @@ class CORE_EXPORT DedicatedWorker final
mojo::PendingRemote<mojom::blink::BrowserInterfaceBroker>
browser_interface_broker_;
+ // Passed to DedicatedWorkerMessagingProxy on worker thread start.
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ pending_dedicated_worker_host_;
+
// Whether the worker is frozen due to a call from this context.
bool requested_frozen_ = false;
};
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
index 955bd663b4f..bcd8d6e96d8 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
@@ -32,7 +32,6 @@
#include <memory>
#include "base/feature_list.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/loader/worker_main_script_load_parameters.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
@@ -66,7 +65,8 @@ DedicatedWorkerGlobalScope* DedicatedWorkerGlobalScope::Create(
std::unique_ptr<GlobalScopeCreationParams> creation_params,
DedicatedWorkerThread* thread,
base::TimeTicks time_origin,
- ukm::SourceId ukm_source_id) {
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host) {
std::unique_ptr<Vector<String>> outside_origin_trial_tokens =
std::move(creation_params->origin_trial_tokens);
BeginFrameProviderParams begin_frame_provider_params =
@@ -83,7 +83,8 @@ DedicatedWorkerGlobalScope* DedicatedWorkerGlobalScope::Create(
auto* global_scope = MakeGarbageCollected<DedicatedWorkerGlobalScope>(
std::move(creation_params), thread, time_origin,
std::move(outside_origin_trial_tokens), begin_frame_provider_params,
- ukm_source_id, parent_cross_origin_isolated_capability);
+ parent_cross_origin_isolated_capability,
+ std::move(dedicated_worker_host));
if (global_scope->IsOffMainThreadScriptFetchDisabled()) {
// Legacy on-the-main-thread worker script fetch (to be removed):
@@ -95,7 +96,8 @@ DedicatedWorkerGlobalScope* DedicatedWorkerGlobalScope::Create(
// have its own appcache and instead depends on the parent frame's one.
global_scope->Initialize(
response_script_url, response_referrer_policy, *response_address_space,
- Vector<CSPHeaderAndType>(), nullptr /* response_origin_trial_tokens */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
+ nullptr /* response_origin_trial_tokens */,
mojom::blink::kAppCacheNoCacheId);
return global_scope;
} else {
@@ -127,16 +129,17 @@ DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
base::TimeTicks time_origin,
std::unique_ptr<Vector<String>> outside_origin_trial_tokens,
const BeginFrameProviderParams& begin_frame_provider_params,
- ukm::SourceId ukm_source_id,
- bool parent_cross_origin_isolated_capability)
+ bool parent_cross_origin_isolated_capability,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host)
: DedicatedWorkerGlobalScope(
ParseCreationParams(std::move(creation_params)),
thread,
time_origin,
std::move(outside_origin_trial_tokens),
begin_frame_provider_params,
- ukm_source_id,
- parent_cross_origin_isolated_capability) {}
+ parent_cross_origin_isolated_capability,
+ std::move(dedicated_worker_host)) {}
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
ParsedCreationParams parsed_creation_params,
@@ -144,12 +147,12 @@ DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
base::TimeTicks time_origin,
std::unique_ptr<Vector<String>> outside_origin_trial_tokens,
const BeginFrameProviderParams& begin_frame_provider_params,
- ukm::SourceId ukm_source_id,
- bool parent_cross_origin_isolated_capability)
+ bool parent_cross_origin_isolated_capability,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host)
: WorkerGlobalScope(std::move(parsed_creation_params.creation_params),
thread,
- time_origin,
- ukm_source_id),
+ time_origin),
token_(thread->WorkerObjectProxy().token()),
parent_token_(parsed_creation_params.parent_context_token),
cross_origin_isolated_capability_(Agent::IsCrossOriginIsolated()),
@@ -168,6 +171,9 @@ DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
ReadyToRunWorkerScript();
// Inherit the outside's origin trial tokens.
OriginTrialContext::AddTokens(this, outside_origin_trial_tokens.get());
+
+ dedicated_worker_host_.Bind(std::move(dedicated_worker_host),
+ GetTaskRunner(TaskType::kInternalDefault));
}
DedicatedWorkerGlobalScope::~DedicatedWorkerGlobalScope() = default;
@@ -181,7 +187,8 @@ void DedicatedWorkerGlobalScope::Initialize(
const KURL& response_url,
network::mojom::ReferrerPolicy response_referrer_policy,
network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& /* response_csp_headers */,
+ Vector<network::mojom::blink::
+ ContentSecurityPolicyPtr> /* response_csp_headers */,
const Vector<String>* /* response_origin_trial_tokens */,
int64_t appcache_id) {
// Step 14.3. "Set worker global scope's url to response's url."
@@ -204,7 +211,8 @@ void DedicatedWorkerGlobalScope::Initialize(
// response CSP headers. These should be called after SetAddressSpace() to
// correctly override the address space by the "treat-as-public-address" CSP
// directive.
- InitContentSecurityPolicyFromVector(OutsideContentSecurityPolicyHeaders());
+ InitContentSecurityPolicyFromVector(
+ mojo::Clone(OutsideContentSecurityPolicies()));
BindContentSecurityPolicyToExecutionContext();
// This should be called after OriginTrialContext::AddTokens() to install
@@ -399,7 +407,7 @@ void DedicatedWorkerGlobalScope::DidFetchClassicScript(
// origin trial tokens in DedicatedWorkerGlobalScope's constructor.
Initialize(classic_script_loader->ResponseURL(), response_referrer_policy,
classic_script_loader->ResponseAddressSpace(),
- Vector<CSPHeaderAndType>(),
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
nullptr /* response_origin_trial_tokens */,
classic_script_loader->AppCacheID());
@@ -437,6 +445,7 @@ DedicatedWorkerObjectProxy& DedicatedWorkerGlobalScope::WorkerObjectProxy()
}
void DedicatedWorkerGlobalScope::Trace(Visitor* visitor) const {
+ visitor->Trace(dedicated_worker_host_);
visitor->Trace(animation_frame_provider_);
WorkerGlobalScope::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
index 2894b42f567..703b1a7f04a 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -33,6 +33,7 @@
#include <memory>
#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom-blink.h"
#include "third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
@@ -59,7 +60,8 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
std::unique_ptr<GlobalScopeCreationParams>,
DedicatedWorkerThread*,
base::TimeTicks time_origin,
- ukm::SourceId ukm_source_id);
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host);
// Do not call this. Use Create() instead. This is public only for
// MakeGarbageCollected.
@@ -69,8 +71,9 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
base::TimeTicks time_origin,
std::unique_ptr<Vector<String>> outside_origin_trial_tokens,
const BeginFrameProviderParams& begin_frame_provider_params,
- ukm::SourceId ukm_source_id,
- bool parent_cross_origin_isolated_capability);
+ bool parent_cross_origin_isolated_capability,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host);
~DedicatedWorkerGlobalScope() override;
@@ -89,12 +92,13 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
}
// Implements WorkerGlobalScope.
- void Initialize(const KURL& response_url,
- network::mojom::ReferrerPolicy response_referrer_policy,
- network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
- const Vector<String>* response_origin_trial_tokens,
- int64_t appcache_host) override;
+ void Initialize(
+ const KURL& response_url,
+ network::mojom::ReferrerPolicy response_referrer_policy,
+ network::mojom::IPAddressSpace response_address_space,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
+ const Vector<String>* response_origin_trial_tokens,
+ int64_t appcache_host) override;
void FetchAndRunClassicScript(
const KURL& script_url,
std::unique_ptr<WorkerMainScriptLoadParameters>
@@ -170,8 +174,9 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
base::TimeTicks time_origin,
std::unique_ptr<Vector<String>> outside_origin_trial_tokens,
const BeginFrameProviderParams& begin_frame_provider_params,
- ukm::SourceId ukm_source_id,
- bool parent_cross_origin_isolated_capability);
+ bool parent_cross_origin_isolated_capability,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host);
void DidReceiveResponseForClassicScript(
WorkerClassicScriptLoader* classic_script_loader);
@@ -187,6 +192,9 @@ class CORE_EXPORT DedicatedWorkerGlobalScope final : public WorkerGlobalScope {
bool cross_origin_isolated_capability_;
Member<WorkerAnimationFrameProvider> animation_frame_provider_;
RejectCoepUnsafeNone reject_coep_unsafe_none_ = RejectCoepUnsafeNone(false);
+
+ HeapMojoRemote<mojom::blink::DedicatedWorkerHost> dedicated_worker_host_{
+ this};
};
template <>
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
index f887ec95b88..3fdb4427a8e 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom-blink-forward.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_worker_options.h"
@@ -57,7 +58,9 @@ void DedicatedWorkerMessagingProxy::StartWorkerGlobalScope(
const v8_inspector::V8StackTraceId& stack_id,
const String& source_code,
RejectCoepUnsafeNone reject_coep_unsafe_none,
- const blink::DedicatedWorkerToken& token) {
+ const blink::DedicatedWorkerToken& token,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host) {
DCHECK(IsParentContextThread());
if (AskedToTerminate()) {
// Worker.terminate() could be called from JS before the thread was
@@ -65,6 +68,8 @@ void DedicatedWorkerMessagingProxy::StartWorkerGlobalScope(
return;
}
+ // |dedicated_worker_host| must be stored before InitializeWorkerThread.
+ pending_dedicated_worker_host_ = std::move(dedicated_worker_host);
InitializeWorkerThread(
std::move(creation_params),
CreateBackingThreadStartupData(GetExecutionContext()->GetIsolate()),
@@ -125,8 +130,7 @@ void DedicatedWorkerMessagingProxy::PostMessageToWorkerGlobalScope(
*GetWorkerThread()->GetTaskRunner(TaskType::kPostedMessage), FROM_HERE,
CrossThreadBindOnce(
&DedicatedWorkerObjectProxy::ProcessMessageFromWorkerObject,
- CrossThreadUnretained(&WorkerObjectProxy()),
- WTF::Passed(std::move(message)),
+ CrossThreadUnretained(&WorkerObjectProxy()), std::move(message),
CrossThreadUnretained(GetWorkerThread())));
}
@@ -179,8 +183,7 @@ void DedicatedWorkerMessagingProxy::DidEvaluateScript(bool success) {
*GetWorkerThread()->GetTaskRunner(TaskType::kPostedMessage), FROM_HERE,
CrossThreadBindOnce(
&DedicatedWorkerObjectProxy::ProcessMessageFromWorkerObject,
- CrossThreadUnretained(&WorkerObjectProxy()),
- WTF::Passed(std::move(task)),
+ CrossThreadUnretained(&WorkerObjectProxy()), std::move(task),
CrossThreadUnretained(GetWorkerThread())));
}
}
@@ -263,8 +266,10 @@ DedicatedWorkerMessagingProxy::CreateBackingThreadStartupData(
std::unique_ptr<WorkerThread>
DedicatedWorkerMessagingProxy::CreateWorkerThread() {
- return std::make_unique<DedicatedWorkerThread>(GetExecutionContext(),
- WorkerObjectProxy());
+ DCHECK(pending_dedicated_worker_host_);
+ return std::make_unique<DedicatedWorkerThread>(
+ GetExecutionContext(), WorkerObjectProxy(),
+ std::move(pending_dedicated_worker_host_));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
index 113f7f0ea22..77a475f9baf 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
@@ -11,6 +11,7 @@
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/messaging/transferable_message.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
@@ -46,7 +47,9 @@ class CORE_EXPORT DedicatedWorkerMessagingProxy
const v8_inspector::V8StackTraceId&,
const String& source_code,
RejectCoepUnsafeNone reject_coep_unsafe_none,
- const blink::DedicatedWorkerToken& token);
+ const blink::DedicatedWorkerToken& token,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host);
void PostMessageToWorkerGlobalScope(BlinkTransferableMessage);
bool HasPendingActivity() const;
@@ -98,6 +101,11 @@ class CORE_EXPORT DedicatedWorkerMessagingProxy
// Tasks are queued here until worker scripts are evaluated on the worker
// global scope.
Vector<BlinkTransferableMessage> queued_early_tasks_;
+
+ // Passed to DedicatedWorkerThread on worker thread creation.
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ pending_dedicated_worker_host_;
+
DISALLOW_COPY_AND_ASSIGN(DedicatedWorkerMessagingProxy);
};
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
index 108e957162e..a02e954e8e3 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.cc
@@ -63,7 +63,7 @@ void DedicatedWorkerObjectProxy::PostMessageToWorkerObject(
FROM_HERE,
CrossThreadBindOnce(
&DedicatedWorkerMessagingProxy::PostMessageToWorkerObject,
- messaging_proxy_weak_ptr_, WTF::Passed(std::move(message))));
+ messaging_proxy_weak_ptr_, std::move(message)));
}
void DedicatedWorkerObjectProxy::ProcessMessageFromWorkerObject(
@@ -90,7 +90,7 @@ void DedicatedWorkerObjectProxy::ReportException(
FROM_HERE,
CrossThreadBindOnce(&DedicatedWorkerMessagingProxy::DispatchErrorEvent,
messaging_proxy_weak_ptr_, error_message,
- WTF::Passed(location->Clone()), exception_id));
+ location->Clone(), exception_id));
}
void DedicatedWorkerObjectProxy::DidFailToFetchClassicScript() {
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
index 0f7ab8e3494..3b281bd8d24 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
@@ -10,6 +10,7 @@
#include "testing/gmock/include/gmock/gmock.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/mojom/worker/dedicated_worker_host.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/core/events/message_event.h"
@@ -36,15 +37,24 @@ class DedicatedWorkerThreadForTest final : public DedicatedWorkerThread {
public:
DedicatedWorkerThreadForTest(ExecutionContext* parent_execution_context,
DedicatedWorkerObjectProxy& worker_object_proxy)
- : DedicatedWorkerThread(parent_execution_context, worker_object_proxy) {
+ : DedicatedWorkerThread(
+ parent_execution_context,
+ worker_object_proxy,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>()) {
worker_backing_thread_ = std::make_unique<WorkerBackingThread>(
ThreadCreationParams(ThreadType::kTestThread));
}
WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) override {
+ // Needed to avoid calling into an uninitialized broker.
+ if (!creation_params->browser_interface_broker) {
+ (void)creation_params->browser_interface_broker
+ .InitWithNewPipeAndPassReceiver();
+ }
auto* global_scope = DedicatedWorkerGlobalScope::Create(
- std::move(creation_params), this, time_origin_, ukm::kInvalidSourceId);
+ std::move(creation_params), this, time_origin_,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>());
// Initializing a global scope with a dummy creation params may emit warning
// messages (e.g., invalid CSP directives). Clear them here for tests that
// check console messages (i.e., UseCounter tests).
@@ -124,15 +134,13 @@ class DedicatedWorkerMessagingProxyForTest
void StartWithSourceCode(const String& source) {
KURL script_url("http://fake.url/");
security_origin_ = SecurityOrigin::Create(script_url);
- Vector<CSPHeaderAndType> headers{
- {"contentSecurityPolicy",
- network::mojom::ContentSecurityPolicyType::kReport}};
auto worker_settings = std::make_unique<WorkerSettings>(
To<LocalDOMWindow>(GetExecutionContext())->GetFrame()->GetSettings());
auto params = std::make_unique<GlobalScopeCreationParams>(
script_url, mojom::blink::ScriptType::kClassic,
"fake global scope name", "fake user agent", UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, headers,
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
false /* starter_secure_context */,
CalculateHttpsState(security_origin_.get()),
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
index e805e993988..c0790dfde89 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.cc
@@ -47,19 +47,18 @@ namespace blink {
DedicatedWorkerThread::DedicatedWorkerThread(
ExecutionContext* parent_execution_context,
- DedicatedWorkerObjectProxy& worker_object_proxy)
+ DedicatedWorkerObjectProxy& worker_object_proxy,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host)
: WorkerThread(worker_object_proxy),
- worker_object_proxy_(worker_object_proxy) {
+ worker_object_proxy_(worker_object_proxy),
+ pending_dedicated_worker_host_(std::move(dedicated_worker_host)) {
FrameOrWorkerScheduler* scheduler =
parent_execution_context ? parent_execution_context->GetScheduler()
: nullptr;
worker_backing_thread_ = std::make_unique<WorkerBackingThread>(
ThreadCreationParams(GetThreadType())
.SetFrameOrWorkerScheduler(scheduler));
-
- // As a dedicated worker can only be associated with one parent context,
- // we inherit the parent's UKM source id.
- ukm_source_id_ = parent_execution_context->UkmSourceID();
}
DedicatedWorkerThread::~DedicatedWorkerThread() = default;
@@ -70,8 +69,10 @@ void DedicatedWorkerThread::ClearWorkerBackingThread() {
WorkerOrWorkletGlobalScope* DedicatedWorkerThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
- return DedicatedWorkerGlobalScope::Create(std::move(creation_params), this,
- time_origin_, ukm_source_id_);
+ DCHECK(pending_dedicated_worker_host_);
+ return DedicatedWorkerGlobalScope::Create(
+ std::move(creation_params), this, time_origin_,
+ std::move(pending_dedicated_worker_host_));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
index 8958bdb6f4a..d9c914ca9d2 100644
--- a/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
+++ b/chromium/third_party/blink/renderer/core/workers/dedicated_worker_thread.h
@@ -31,6 +31,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_DEDICATED_WORKER_THREAD_H_
#include <memory>
+#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
namespace blink {
@@ -41,7 +42,9 @@ struct GlobalScopeCreationParams;
class CORE_EXPORT DedicatedWorkerThread : public WorkerThread {
public:
DedicatedWorkerThread(ExecutionContext* parent_execution_context,
- DedicatedWorkerObjectProxy&);
+ DedicatedWorkerObjectProxy&,
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ dedicated_worker_host);
~DedicatedWorkerThread() override;
WorkerBackingThread& GetWorkerBackingThread() override {
@@ -65,6 +68,10 @@ class CORE_EXPORT DedicatedWorkerThread : public WorkerThread {
std::unique_ptr<WorkerBackingThread> worker_backing_thread_;
DedicatedWorkerObjectProxy& worker_object_proxy_;
ukm::SourceId ukm_source_id_;
+
+ // Passed to DedicatedWorkerGlobalScope on global scope creation.
+ mojo::PendingRemote<mojom::blink::DedicatedWorkerHost>
+ pending_dedicated_worker_host_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
index 128cc7ec06f..5f5332b5355 100644
--- a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
+++ b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
@@ -20,7 +20,8 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
const String& user_agent,
const base::Optional<UserAgentMetadata>& ua_metadata,
scoped_refptr<WebWorkerFetchContext> web_worker_fetch_context,
- const Vector<CSPHeaderAndType>& outside_content_security_policy_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ outside_content_security_policies,
network::mojom::ReferrerPolicy referrer_policy,
const SecurityOrigin* starter_origin,
bool starter_secure_context,
@@ -38,14 +39,19 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
BeginFrameProviderParams begin_frame_provider_params,
const FeaturePolicy* parent_feature_policy,
base::UnguessableToken agent_cluster_id,
+ ukm::SourceId ukm_source_id,
const base::Optional<ExecutionContextToken>& parent_context_token,
- bool parent_cross_origin_isolated_capability)
+ bool parent_cross_origin_isolated_capability,
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner)
: script_url(script_url.Copy()),
script_type(script_type),
global_scope_name(global_scope_name.IsolatedCopy()),
user_agent(user_agent.IsolatedCopy()),
ua_metadata(ua_metadata.value_or(blink::UserAgentMetadata())),
web_worker_fetch_context(std::move(web_worker_fetch_context)),
+ outside_content_security_policies(
+ std::move(outside_content_security_policies)),
referrer_policy(referrer_policy),
starter_origin(starter_origin ? starter_origin->IsolatedCopy() : nullptr),
starter_secure_context(starter_secure_context),
@@ -66,16 +72,12 @@ GlobalScopeCreationParams::GlobalScopeCreationParams(
ParsedFeaturePolicy() /* container_policy */,
starter_origin->ToUrlOrigin())),
agent_cluster_id(agent_cluster_id),
+ ukm_source_id(ukm_source_id),
parent_context_token(parent_context_token),
parent_cross_origin_isolated_capability(
- parent_cross_origin_isolated_capability) {
- this->outside_content_security_policy_headers.ReserveInitialCapacity(
- outside_content_security_policy_headers.size());
- for (const auto& header : outside_content_security_policy_headers) {
- this->outside_content_security_policy_headers.emplace_back(
- header.first.IsolatedCopy(), header.second);
- }
-
+ parent_cross_origin_isolated_capability),
+ agent_group_scheduler_compositor_task_runner(
+ std::move(agent_group_scheduler_compositor_task_runner)) {
this->origin_trial_tokens = std::make_unique<Vector<String>>();
if (origin_trial_tokens) {
for (const String& token : *origin_trial_tokens)
diff --git a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
index 50abbf2495c..517c976d575 100644
--- a/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
+++ b/chromium/third_party/blink/renderer/core/workers/global_scope_creation_params.h
@@ -10,6 +10,7 @@
#include "base/optional.h"
#include "base/unguessable_token.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink-forward.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
@@ -47,7 +48,8 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
const String& user_agent,
const base::Optional<UserAgentMetadata>& ua_metadata,
scoped_refptr<WebWorkerFetchContext>,
- const Vector<CSPHeaderAndType>& outside_content_security_policy_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ outside_content_security_policies,
network::mojom::ReferrerPolicy referrer_policy,
const SecurityOrigin*,
bool starter_secure_context,
@@ -65,9 +67,12 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
BeginFrameProviderParams begin_frame_provider_params = {},
const FeaturePolicy* parent_feature_policy = nullptr,
base::UnguessableToken agent_cluster_id = {},
+ ukm::SourceId ukm_source_id = ukm::kInvalidSourceId,
const base::Optional<ExecutionContextToken>& parent_context_token =
base::nullopt,
- bool parent_cross_origin_isolated_capability = false);
+ bool parent_cross_origin_isolated_capability = false,
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner = nullptr);
~GlobalScopeCreationParams() = default;
@@ -96,7 +101,8 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
// TODO(bashi): This contains "inside" CSP headers for on-the-main-thread
// service/shared worker script fetch. Add a separate parameter for "inside"
// CSP headers.
- Vector<CSPHeaderAndType> outside_content_security_policy_headers;
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ outside_content_security_policies;
network::mojom::ReferrerPolicy referrer_policy;
std::unique_ptr<Vector<String>> origin_trial_tokens;
@@ -164,6 +170,9 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
// See https://tc39.github.io/ecma262/#sec-agent-clusters
base::UnguessableToken agent_cluster_id;
+ // Set to ukm::kInvalidSourceId when the global scope is not provided an ID.
+ ukm::SourceId ukm_source_id;
+
// The identity of the parent ExecutionContext that is the sole owner of this
// worker or worklet, which caused it to be created, and to whose lifetime
// this worker/worklet is bound. This is used for resource usage attribution.
@@ -173,6 +182,11 @@ struct CORE_EXPORT GlobalScopeCreationParams final {
// Used by dedicated workers, and set to false when there is no parent.
const bool parent_cross_origin_isolated_capability;
+ // The compositor task runner associated with the |AgentGroupScheduler| this
+ // worker belongs to.
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner;
+
DISALLOW_COPY_AND_ASSIGN(GlobalScopeCreationParams);
};
diff --git a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
index c63721e4a30..0ac82a2b00a 100644
--- a/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
+++ b/chromium/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
@@ -40,7 +40,7 @@ InstalledScriptsManager::ScriptData::ScriptData(
ContentSecurityPolicyResponseHeaders
InstalledScriptsManager::ScriptData::GetContentSecurityPolicyResponseHeaders() {
- return ContentSecurityPolicyResponseHeaders(headers_);
+ return ContentSecurityPolicyResponseHeaders(headers_, script_url_);
}
String InstalledScriptsManager::ScriptData::GetReferrerPolicy() {
diff --git a/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc b/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
index 89e91e8c847..6cdd5496585 100644
--- a/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
@@ -46,13 +46,15 @@ class MainThreadWorkletTest : public PageTestBase {
}
void SetUpScope(const String& csp_header) {
PageTestBase::SetUp(IntSize());
- NavigateTo(KURL("https://example.com/"));
+ KURL url = KURL("https://example.com/");
+ NavigateTo(url);
LocalDOMWindow* window = GetFrame().DomWindow();
// Set up the CSP for Document before starting MainThreadWorklet because
// MainThreadWorklet inherits the owner Document's CSP.
auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
- csp->DidReceiveHeader(csp_header,
+ scoped_refptr<SecurityOrigin> self_origin = SecurityOrigin::Create(url);
+ csp->DidReceiveHeader(csp_header, *(self_origin),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
window->GetSecurityContext().SetContentSecurityPolicy(csp);
@@ -63,7 +65,7 @@ class MainThreadWorkletTest : public PageTestBase {
window->Url(), mojom::blink::ScriptType::kModule, "MainThreadWorklet",
window->UserAgent(), window->GetFrame()->Loader().UserAgentMetadata(),
nullptr /* web_worker_fetch_context */,
- window->GetContentSecurityPolicy()->Headers(),
+ mojo::Clone(window->GetContentSecurityPolicy()->GetParsedPolicies()),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(),
nullptr /* worker_clients */, nullptr /* content_settings_client */,
@@ -73,7 +75,8 @@ class MainThreadWorkletTest : public PageTestBase {
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken());
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken());
global_scope_ = MakeGarbageCollected<FakeWorkletGlobalScope>(
std::move(creation_params), *reporting_proxy_, &GetFrame(),
false /* create_microtask_queue */);
@@ -165,13 +168,14 @@ TEST_F(MainThreadWorkletTest, TaskRunner) {
// Test that having an invalid CSP does not result in an exception.
// See bugs: 844383,844317
TEST_F(MainThreadWorkletInvalidCSPTest, InvalidContentSecurityPolicy) {
- ContentSecurityPolicy* csp = global_scope_->GetContentSecurityPolicy();
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>& csp =
+ global_scope_->GetContentSecurityPolicy()->GetParsedPolicies();
// At this point check that the CSP that was set is indeed invalid.
- EXPECT_EQ(1ul, csp->Headers().size());
- EXPECT_EQ("invalid-csp", csp->Headers().at(0).first);
+ EXPECT_EQ(1ul, csp.size());
+ EXPECT_EQ("invalid-csp", csp[0]->header->header_value);
EXPECT_EQ(network::mojom::ContentSecurityPolicyType::kEnforce,
- csp->Headers().at(0).second);
+ csp[0]->header->type);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h b/chromium/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
index ce6e158a505..b38186d9f20 100644
--- a/chromium/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
+++ b/chromium/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
index 7886a7c550b..5fde09d7f5f 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker.cc
@@ -69,7 +69,7 @@ SharedWorker::SharedWorker(ExecutionContext* context)
is_being_connected_(false),
feature_handle_for_scheduler_(context->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kSharedWorker,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
+ {SchedulingPolicy::DisableBackForwardCache()})) {}
SharedWorker* SharedWorker::Create(ExecutionContext* context,
const String& url,
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
index 9968508ac33..11103cba910 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_client_holder.cc
@@ -91,20 +91,6 @@ void SharedWorkerClientHolder::Connect(
DCHECK(IsMainThread());
DCHECK(options);
- // TODO(estark): this is broken, as it only uses the first header
- // when multiple might have been sent. Fix by making the
- // mojom::blink::SharedWorkerInfo take a map that can contain multiple
- // headers.
- Vector<CSPHeaderAndType> headers =
- worker->GetExecutionContext()->GetContentSecurityPolicy()->Headers();
- WebString header = "";
- auto header_type = network::mojom::ContentSecurityPolicyType::kReport;
- if (headers.size() > 0) {
- header = headers[0].first;
- header_type = static_cast<network::mojom::ContentSecurityPolicyType>(
- headers[0].second);
- }
-
mojo::PendingRemote<mojom::blink::SharedWorkerClient> client;
client_receivers_.Add(std::make_unique<SharedWorkerClient>(worker),
client.InitWithNewPipeAndPassReceiver(), task_runner_);
@@ -124,7 +110,10 @@ void SharedWorkerClientHolder::Connect(
: mojom::InsecureRequestsPolicy::kDoNotUpgrade;
auto info = mojom::blink::SharedWorkerInfo::New(
- url, std::move(options), header, header_type,
+ url, std::move(options),
+ mojo::Clone(worker->GetExecutionContext()
+ ->GetContentSecurityPolicy()
+ ->GetParsedPolicies()),
worker->GetExecutionContext()->AddressSpace(),
mojom::blink::FetchClientSettingsObject::New(
outside_fetch_client_settings_object->GetReferrerPolicy(),
@@ -134,12 +123,9 @@ void SharedWorkerClientHolder::Connect(
connector_->Connect(
std::move(info), std::move(client),
worker->GetExecutionContext()->IsSecureContext()
- ? mojom::SharedWorkerCreationContextType::kSecure
- : mojom::SharedWorkerCreationContextType::kNonsecure,
- port.ReleaseHandle(),
- mojo::PendingRemote<mojom::blink::BlobURLToken>(
- blob_url_token.PassPipe(), mojom::blink::BlobURLToken::Version_),
- client_ukm_source_id);
+ ? mojom::blink::SharedWorkerCreationContextType::kSecure
+ : mojom::blink::SharedWorkerCreationContextType::kNonsecure,
+ port.ReleaseHandle(), std::move(blob_url_token), client_ukm_source_id);
}
void SharedWorkerClientHolder::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
index 74e260587e4..361d9843008 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
@@ -59,16 +59,12 @@ SharedWorkerGlobalScope::SharedWorkerGlobalScope(
SharedWorkerThread* thread,
base::TimeTicks time_origin,
const SharedWorkerToken& token,
- const base::UnguessableToken& appcache_host_id,
- ukm::SourceId ukm_source_id)
- : WorkerGlobalScope(std::move(creation_params),
- thread,
- time_origin,
- ukm_source_id),
+ const base::UnguessableToken& appcache_host_id)
+ : WorkerGlobalScope(std::move(creation_params), thread, time_origin),
token_(token) {
appcache_host_ = MakeGarbageCollected<ApplicationCacheHostForWorker>(
appcache_host_id, GetBrowserInterfaceBroker(),
- GetTaskRunner(TaskType::kInternalLoading), this);
+ GetTaskRunner(TaskType::kInternalLoading));
}
SharedWorkerGlobalScope::~SharedWorkerGlobalScope() = default;
@@ -82,7 +78,7 @@ void SharedWorkerGlobalScope::Initialize(
const KURL& response_url,
network::mojom::ReferrerPolicy response_referrer_policy,
network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
const Vector<String>* response_origin_trial_tokens,
int64_t appcache_id) {
// Step 12.3. "Set worker global scope's url to response's url."
@@ -110,12 +106,12 @@ void SharedWorkerGlobalScope::Initialize(
// https://w3c.github.io/webappsec-csp/#initialize-global-object-csp
// These should be called after SetAddressSpace() to correctly override the
// address space by the "treat-as-public-address" CSP directive.
- Vector<CSPHeaderAndType> csp_headers =
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> csp_headers =
response_url.ProtocolIsAbout() || response_url.ProtocolIsData() ||
response_url.ProtocolIs("blob")
- ? OutsideContentSecurityPolicyHeaders()
- : response_csp_headers;
- InitContentSecurityPolicyFromVector(csp_headers);
+ ? mojo::Clone(OutsideContentSecurityPolicies())
+ : std::move(response_csp);
+ InitContentSecurityPolicyFromVector(std::move(csp_headers));
BindContentSecurityPolicyToExecutionContext();
OriginTrialContext::AddTokens(this, response_origin_trial_tokens);
@@ -262,8 +258,9 @@ void SharedWorkerGlobalScope::DidFetchClassicScript(
Initialize(classic_script_loader->ResponseURL(), response_referrer_policy,
classic_script_loader->ResponseAddressSpace(),
classic_script_loader->GetContentSecurityPolicy()
- ? classic_script_loader->GetContentSecurityPolicy()->Headers()
- : Vector<CSPHeaderAndType>(),
+ ? mojo::Clone(classic_script_loader->GetContentSecurityPolicy()
+ ->GetParsedPolicies())
+ : Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
classic_script_loader->OriginTrialTokens(),
classic_script_loader->AppCacheID());
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
index dcfeb252523..29750461500 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
@@ -32,7 +32,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_GLOBAL_SCOPE_H_
#include <memory>
-#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/messaging/message_port_channel.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/core/core_export.h"
@@ -55,8 +54,7 @@ class CORE_EXPORT SharedWorkerGlobalScope final : public WorkerGlobalScope {
SharedWorkerThread* thread,
base::TimeTicks time_origin,
const SharedWorkerToken& token,
- const base::UnguessableToken& appcache_host_id,
- ukm::SourceId ukm_source_id);
+ const base::UnguessableToken& appcache_host_id);
~SharedWorkerGlobalScope() override;
@@ -66,12 +64,13 @@ class CORE_EXPORT SharedWorkerGlobalScope final : public WorkerGlobalScope {
const AtomicString& InterfaceName() const override;
// WorkerGlobalScope
- void Initialize(const KURL& response_url,
- network::mojom::ReferrerPolicy response_referrer_policy,
- network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
- const Vector<String>* response_origin_trial_tokens,
- int64_t appcache_id) override;
+ void Initialize(
+ const KURL& response_url,
+ network::mojom::ReferrerPolicy response_referrer_policy,
+ network::mojom::IPAddressSpace response_address_space,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
+ const Vector<String>* response_origin_trial_tokens,
+ int64_t appcache_id) override;
void FetchAndRunClassicScript(
const KURL& script_url,
std::unique_ptr<WorkerMainScriptLoadParameters>
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.cc b/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.cc
index 2200309e50b..2e15e699263 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.cc
@@ -41,14 +41,12 @@ namespace blink {
SharedWorkerThread::SharedWorkerThread(
WorkerReportingProxy& worker_reporting_proxy,
const SharedWorkerToken& token,
- const base::UnguessableToken& appcache_host_id,
- ukm::SourceId ukm_source_id)
+ const base::UnguessableToken& appcache_host_id)
: WorkerThread(worker_reporting_proxy),
worker_backing_thread_(std::make_unique<WorkerBackingThread>(
ThreadCreationParams(GetThreadType()))),
token_(token),
- appcache_host_id_(appcache_host_id),
- ukm_source_id_(ukm_source_id) {}
+ appcache_host_id_(appcache_host_id) {}
SharedWorkerThread::~SharedWorkerThread() = default;
@@ -59,8 +57,8 @@ void SharedWorkerThread::ClearWorkerBackingThread() {
WorkerOrWorkletGlobalScope* SharedWorkerThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
return MakeGarbageCollected<SharedWorkerGlobalScope>(
- std::move(creation_params), this, time_origin_, token_, appcache_host_id_,
- ukm_source_id_);
+ std::move(creation_params), this, time_origin_, token_,
+ appcache_host_id_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.h b/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.h
index a400165372d..caeebeb26c9 100644
--- a/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.h
+++ b/chromium/third_party/blink/renderer/core/workers/shared_worker_thread.h
@@ -31,7 +31,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_SHARED_WORKER_THREAD_H_
#include <memory>
-#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
@@ -44,8 +43,7 @@ class CORE_EXPORT SharedWorkerThread : public WorkerThread {
public:
SharedWorkerThread(WorkerReportingProxy& worker_reporting_proxy,
const SharedWorkerToken& token,
- const base::UnguessableToken& appcache_host_id,
- ukm::SourceId ukm_source_id);
+ const base::UnguessableToken& appcache_host_id);
~SharedWorkerThread() override;
WorkerBackingThread& GetWorkerBackingThread() override {
@@ -64,7 +62,6 @@ class CORE_EXPORT SharedWorkerThread : public WorkerThread {
std::unique_ptr<WorkerBackingThread> worker_backing_thread_;
const SharedWorkerToken token_;
const base::UnguessableToken appcache_host_id_;
- const ukm::SourceId ukm_source_id_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc b/chromium/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
index 231a67f805c..44c431e1e92 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
@@ -38,7 +38,7 @@ ThreadedMessagingProxyBase::ThreadedMessagingProxyBase(
feature_handle_for_scheduler_(
execution_context->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kDedicatedWorkerOrWorklet,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})),
+ {SchedulingPolicy::DisableBackForwardCache()})),
keep_alive_(PERSISTENT_FROM_HERE, this) {
DCHECK(IsParentContextThread());
g_live_messaging_proxy_count++;
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_object_proxy_base.cc b/chromium/third_party/blink/renderer/core/workers/threaded_object_proxy_base.cc
index 9f72fc36c77..5346a51378f 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_object_proxy_base.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_object_proxy_base.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/workers/threaded_object_proxy_base.h"
#include <memory>
+
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h"
@@ -33,7 +34,7 @@ void ThreadedObjectProxyBase::ReportConsoleMessage(
FROM_HERE,
CrossThreadBindOnce(&ThreadedMessagingProxyBase::ReportConsoleMessage,
MessagingProxyWeakPtr(), source, level, message,
- WTF::Passed(location->Clone())));
+ location->Clone()));
}
void ThreadedObjectProxyBase::DidCloseWorkerGlobalScope() {
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
index dcb924356e3..52431662279 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h"
+#include <utility>
+
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
@@ -62,7 +64,7 @@ void ThreadedWorkletMessagingProxy::Initialize(
window->UserAgent(),
window->GetFrame()->Client()->UserAgentMetadata(),
window->GetFrame()->Client()->CreateWorkerFetchContext(),
- csp->Headers(), window->GetReferrerPolicy(),
+ mojo::Clone(csp->GetParsedPolicies()), window->GetReferrerPolicy(),
window->GetSecurityOrigin(), window->IsSecureContext(),
window->GetHttpsState(), worker_clients,
window->GetFrame()->Client()->CreateWorkerContentSettingsClient(),
@@ -72,7 +74,8 @@ void ThreadedWorkletMessagingProxy::Initialize(
mojom::blink::V8CacheOptions::kDefault, module_responses_map,
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken(),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken(),
window->CrossOriginIsolatedCapability());
// Worklets share the pre-initialized backing thread so that we don't have to
@@ -98,7 +101,7 @@ void ThreadedWorkletMessagingProxy::FetchAndInvokeScript(
CrossThreadBindOnce(
&ThreadedWorkletObjectProxy::FetchAndInvokeScript,
CrossThreadUnretained(worklet_object_proxy_.get()), module_url_record,
- credentials_mode, WTF::Passed(outside_settings_object.CopyData()),
+ credentials_mode, outside_settings_object.CopyData(),
WrapCrossThreadPersistent(&outside_resource_timing_notifier),
std::move(outside_settings_task_runner),
WrapCrossThreadPersistent(pending_tasks),
diff --git a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index 80fffd838ce..4671d2433a2 100644
--- a/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -98,11 +98,13 @@ class ThreadedWorkletThreadForTest : public WorkerThread {
void TestContentSecurityPolicy() {
EXPECT_TRUE(IsCurrentThread());
ContentSecurityPolicy* csp = GlobalScope()->GetContentSecurityPolicy();
+ KURL main_document_url = KURL("https://example.com/script.js");
- // The "script-src 'self'" directive allows this.
+ // The "script-src 'self'" directive allows |main_document_url| since it is
+ // same-origin with the main document.
EXPECT_TRUE(csp->AllowScriptFromSource(
- GlobalScope()->Url(), String(), IntegrityMetadataSet(), kParserInserted,
- GlobalScope()->Url(), RedirectStatus::kNoRedirect));
+ main_document_url, String(), IntegrityMetadataSet(), kParserInserted,
+ main_document_url, RedirectStatus::kNoRedirect));
// The "script-src https://allowed.example.com" should allow this.
EXPECT_TRUE(csp->AllowScriptFromSource(
@@ -125,11 +127,12 @@ class ThreadedWorkletThreadForTest : public WorkerThread {
EXPECT_TRUE(IsCurrentThread());
// At this point check that the CSP that was set is indeed invalid.
- ContentSecurityPolicy* csp = GlobalScope()->GetContentSecurityPolicy();
- EXPECT_EQ(1ul, csp->Headers().size());
- EXPECT_EQ("invalid-csp", csp->Headers().at(0).first);
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>& csp =
+ GlobalScope()->GetContentSecurityPolicy()->GetParsedPolicies();
+ EXPECT_EQ(1ul, csp.size());
+ EXPECT_EQ("invalid-csp", csp[0]->header->header_value);
EXPECT_EQ(network::mojom::ContentSecurityPolicyType::kEnforce,
- csp->Headers().at(0).second);
+ csp[0]->header->type);
PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
CrossThreadBindOnce(&test::ExitRunLoop));
@@ -208,7 +211,9 @@ class ThreadedWorkletMessagingProxyForTest
->Loader()
.UserAgentMetadata(),
nullptr /* web_worker_fetch_context */,
- GetExecutionContext()->GetContentSecurityPolicy()->Headers(),
+ mojo::Clone(GetExecutionContext()
+ ->GetContentSecurityPolicy()
+ ->GetParsedPolicies()),
GetExecutionContext()->GetReferrerPolicy(),
GetExecutionContext()->GetSecurityOrigin(),
GetExecutionContext()->IsSecureContext(),
@@ -221,7 +226,7 @@ class ThreadedWorkletMessagingProxyForTest
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- GetExecutionContext()->GetAgentClusterID(),
+ GetExecutionContext()->GetAgentClusterID(), ukm::kInvalidSourceId,
GetExecutionContext()->GetExecutionContextToken()),
base::nullopt, base::nullopt);
}
@@ -240,7 +245,8 @@ class ThreadedWorkletTest : public testing::Test {
page_ = std::make_unique<DummyPageHolder>();
KURL url("https://example.com/");
page_->GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url),
nullptr /* extra_data */);
blink::test::RunPendingTasks();
ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
@@ -305,6 +311,7 @@ TEST_F(ThreadedWorkletTest, ContentSecurityPolicy) {
// ThreadedWorklet inherits the owner Document's CSP.
auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
csp->DidReceiveHeader("script-src 'self' https://allowed.example.com",
+ *(GetExecutionContext()->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
GetExecutionContext()->GetSecurityContext().SetContentSecurityPolicy(csp);
@@ -322,6 +329,7 @@ TEST_F(ThreadedWorkletTest, ContentSecurityPolicy) {
TEST_F(ThreadedWorkletTest, InvalidContentSecurityPolicy) {
auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
csp->DidReceiveHeader("invalid-csp",
+ *(GetExecutionContext()->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
GetExecutionContext()->GetSecurityContext().SetContentSecurityPolicy(csp);
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index db56f38c755..870beea1249 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -269,10 +269,10 @@ void WorkerClassicScriptLoader::DidReceiveData(const char* data, unsigned len) {
source_text_.Append(decoder_->Decode(data, len));
}
-void WorkerClassicScriptLoader::DidReceiveCachedMetadata(const char* data,
- int size) {
- cached_metadata_ = std::make_unique<Vector<uint8_t>>(size);
- memcpy(cached_metadata_->data(), data, size);
+void WorkerClassicScriptLoader::DidReceiveCachedMetadata(
+ mojo_base::BigBuffer data) {
+ cached_metadata_ = std::make_unique<Vector<uint8_t>>(data.size());
+ memcpy(cached_metadata_->data(), data.data(), data.size());
}
void WorkerClassicScriptLoader::DidFinishLoading(uint64_t identifier) {
@@ -369,8 +369,6 @@ void WorkerClassicScriptLoader::ProcessContentSecurityPolicy(
!response.CurrentRequestUrl().ProtocolIs("file") &&
!response.CurrentRequestUrl().ProtocolIs("filesystem")) {
content_security_policy_ = MakeGarbageCollected<ContentSecurityPolicy>();
- content_security_policy_->SetOverrideURLForSelf(
- response.CurrentRequestUrl());
content_security_policy_->DidReceiveHeaders(
ContentSecurityPolicyResponseHeaders(response));
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
index 28d0a0b0263..7688023e180 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
@@ -135,7 +135,7 @@ class CORE_EXPORT WorkerClassicScriptLoader final
void DidReceiveResponse(uint64_t /*identifier*/,
const ResourceResponse&) override;
void DidReceiveData(const char* data, unsigned data_length) override;
- void DidReceiveCachedMetadata(const char*, int /*dataLength*/) override;
+ void DidReceiveCachedMetadata(mojo_base::BigBuffer) override;
void DidFinishLoading(uint64_t identifier) override;
void DidFail(const ResourceError&) override;
void DidFailRedirectCheck() override;
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 2a34728a31d..ef4dce6a428 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -31,6 +31,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/browser_interface_broker.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -204,10 +205,8 @@ WorkerLocation* WorkerGlobalScope::location() const {
}
WorkerNavigator* WorkerGlobalScope::navigator() const {
- if (!navigator_) {
- navigator_ = MakeGarbageCollected<WorkerNavigator>(
- user_agent_, ua_metadata_, GetExecutionContext());
- }
+ if (!navigator_)
+ navigator_ = MakeGarbageCollected<WorkerNavigator>(GetExecutionContext());
return navigator_.Get();
}
@@ -326,21 +325,33 @@ void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls) {
? SanitizeScriptErrors::kDoNotSanitize
: SanitizeScriptErrors::kSanitize;
- // Step 5.2: "Run the classic script script, with the rethrow errors
- // argument set to true."
+ const KURL script_url =
+ ScriptSourceCode::UsePostRedirectURL() ? response_url : complete_url;
+
+ // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-worker-imported-script
+ // Step 7: Let script be the result of creating a classic script given
+ // source text, settings object, response's url, the default classic script
+ // fetch options, and muted errors.
+ // TODO(crbug.com/1082086): Fix the base URL.
SingleCachedMetadataHandler* handler(
CreateWorkerScriptCachedMetadataHandler(complete_url,
std::move(cached_meta_data)));
+ ClassicScript* script = MakeGarbageCollected<ClassicScript>(
+ ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
+ handler, script_url),
+ script_url /* base_url */, ScriptFetchOptions(),
+ sanitize_script_errors);
+
+ // Step 5.2: "Run the classic script script, with the rethrow errors
+ // argument set to true."
ReportingProxy().WillEvaluateImportedClassicScript(
source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
- ScriptState::Scope scope(ScriptController()->GetScriptState());
- ScriptEvaluationResult result = ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
- handler,
- ScriptSourceCode::UsePostRedirectURL() ? response_url
- : complete_url),
- sanitize_script_errors, GetV8CacheOptions(),
- V8ScriptRunner::RethrowErrorsOption::Rethrow(error_message));
+ v8::HandleScope scope(isolate);
+ ScriptEvaluationResult result =
+ script->RunScriptOnScriptStateAndReturnValue(
+ ScriptController()->GetScriptState(),
+ ExecuteScriptPolicy::kDoNotExecuteScriptWhenScriptsDisabled,
+ V8ScriptRunner::RethrowErrorsOption::Rethrow(error_message));
// Step 5.2: "If an exception was thrown or if the script was prematurely
// aborted, then abort all these steps, letting the exception or aborting
@@ -404,7 +415,8 @@ CoreProbeSink* WorkerGlobalScope::GetProbeSink() {
return nullptr;
}
-BrowserInterfaceBrokerProxy& WorkerGlobalScope::GetBrowserInterfaceBroker() {
+const BrowserInterfaceBrokerProxy&
+WorkerGlobalScope::GetBrowserInterfaceBroker() const {
return browser_interface_broker_proxy_;
}
@@ -523,8 +535,7 @@ void WorkerGlobalScope::ReceiveMessage(BlinkTransferableMessage message) {
WorkerGlobalScope::WorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params,
WorkerThread* thread,
- base::TimeTicks time_origin,
- ukm::SourceId ukm_source_id)
+ base::TimeTicks time_origin)
: WorkerOrWorkletGlobalScope(
thread->GetIsolate(),
CreateSecurityOrigin(creation_params.get(), GetExecutionContext()),
@@ -544,10 +555,12 @@ WorkerGlobalScope::WorkerGlobalScope(
user_agent_(creation_params->user_agent),
ua_metadata_(creation_params->ua_metadata),
thread_(thread),
+ agent_group_scheduler_compositor_task_runner_(std::move(
+ creation_params->agent_group_scheduler_compositor_task_runner)),
time_origin_(time_origin),
font_selector_(MakeGarbageCollected<OffscreenFontSelector>(this)),
script_eval_state_(ScriptEvalState::kPauseAfterFetch),
- ukm_source_id_(ukm_source_id) {
+ ukm_source_id_(creation_params->ukm_source_id) {
InstanceCounters::IncrementCounter(
InstanceCounters::kWorkerGlobalScopeCounter);
@@ -557,18 +570,17 @@ WorkerGlobalScope::WorkerGlobalScope(
https_state_ = CalculateHttpsState(GetSecurityOrigin(),
creation_params->starter_https_state);
- SetOutsideContentSecurityPolicyHeaders(
- creation_params->outside_content_security_policy_headers);
+ SetOutsideContentSecurityPolicies(
+ std::move(creation_params->outside_content_security_policies));
SetWorkerSettings(std::move(creation_params->worker_settings));
// TODO(sammc): Require a valid |creation_params->browser_interface_broker|
// once all worker types provide a valid
// |creation_params->browser_interface_broker|.
if (creation_params->browser_interface_broker.is_valid()) {
- auto pipe = creation_params->browser_interface_broker.PassPipe();
browser_interface_broker_proxy_.Bind(
- mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>(
- std::move(pipe), blink::mojom::BrowserInterfaceBroker::Version_),
+ ToCrossVariantMojoType(
+ std::move(creation_params->browser_interface_broker)),
GetTaskRunner(TaskType::kInternalDefault));
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
index 033762b86e8..d716adec520 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -85,6 +85,7 @@ class CORE_EXPORT WorkerGlobalScope
void Dispose() override;
WorkerThread* GetThread() const final { return thread_; }
const base::UnguessableToken& GetDevToolsToken() const override;
+ bool IsInitialized() const final { return !url_.IsNull(); }
void ExceptionUnhandled(int exception_id);
@@ -116,14 +117,16 @@ class CORE_EXPORT WorkerGlobalScope
bool IsContextThread() const final;
const KURL& BaseURL() const final;
String UserAgent() const final { return user_agent_; }
- const UserAgentMetadata& GetUserAgentMetadata() const { return ua_metadata_; }
+ UserAgentMetadata GetUserAgentMetadata() const override {
+ return ua_metadata_;
+ }
HttpsState GetHttpsState() const override { return https_state_; }
scheduler::WorkerScheduler* GetScheduler() final;
ukm::UkmRecorder* UkmRecorder() final;
ScriptWrappable* ToScriptWrappable() final { return this; }
void AddConsoleMessageImpl(ConsoleMessage*, bool discard_duplicates) final;
- BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() final;
+ const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() const final;
OffscreenFontSelector* GetFontSelector() { return font_selector_; }
@@ -145,7 +148,7 @@ class CORE_EXPORT WorkerGlobalScope
const KURL& response_url,
network::mojom::ReferrerPolicy response_referrer_policy,
network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
const Vector<String>* response_origin_trial_tokens,
int64_t appcache_id) = 0;
@@ -223,11 +226,17 @@ class CORE_EXPORT WorkerGlobalScope
// successful and not successful) by the worker.
FontMatchingMetrics* GetFontMatchingMetrics();
+ scoped_refptr<base::SingleThreadTaskRunner>
+ GetAgentGroupSchedulerCompositorTaskRunner() {
+ return agent_group_scheduler_compositor_task_runner_;
+ }
+
+ bool IsUrlValid() { return url_.IsValid(); }
+
protected:
WorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
WorkerThread*,
- base::TimeTicks time_origin,
- ukm::SourceId);
+ base::TimeTicks time_origin);
// ExecutionContext
void ExceptionThrown(ErrorEvent*) override;
@@ -278,6 +287,11 @@ class CORE_EXPORT WorkerGlobalScope
WorkerThread* thread_;
+ // The compositor task runner associated with the |AgentGroupScheduler| this
+ // worker belongs to.
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner_;
+
bool closing_ = false;
const base::TimeTicks time_origin_;
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc b/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
index 2be0731c9f8..cc4025d8f6a 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_navigator.cc
@@ -36,20 +36,11 @@
namespace blink {
-WorkerNavigator::WorkerNavigator(const String& user_agent,
- const UserAgentMetadata& ua_metadata,
- ExecutionContext* execution_context)
- : ExecutionContextClient(execution_context),
- NavigatorLanguage(execution_context),
- user_agent_(user_agent),
- ua_metadata_(ua_metadata) {}
+WorkerNavigator::WorkerNavigator(ExecutionContext* execution_context)
+ : NavigatorBase(execution_context) {}
WorkerNavigator::~WorkerNavigator() = default;
-String WorkerNavigator::userAgent() const {
- return user_agent_;
-}
-
String WorkerNavigator::GetAcceptLanguages() {
WorkerOrWorkletGlobalScope* global_scope =
To<WorkerOrWorkletGlobalScope>(GetExecutionContext());
@@ -68,11 +59,4 @@ void WorkerNavigator::NotifyUpdate() {
*Event::Create(event_type_names::kLanguagechange));
}
-void WorkerNavigator::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
- NavigatorLanguage::Trace(visitor);
- Supplementable<WorkerNavigator>::Trace(visitor);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_navigator.h b/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
index 2d2e5f78e60..20ed3c67a07 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_navigator.h
@@ -28,61 +28,25 @@
#include "third_party/blink/public/platform/web_worker_fetch_context.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/frame/navigator_concurrent_hardware.h"
-#include "third_party/blink/renderer/core/frame/navigator_device_memory.h"
-#include "third_party/blink/renderer/core/frame/navigator_id.h"
-#include "third_party/blink/renderer/core/frame/navigator_language.h"
-#include "third_party/blink/renderer/core/frame/navigator_on_line.h"
-#include "third_party/blink/renderer/core/frame/navigator_ua.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-class CORE_EXPORT WorkerNavigator final
- : public ScriptWrappable,
- public AcceptLanguagesWatcher,
- public ExecutionContextClient,
- public NavigatorConcurrentHardware,
- public NavigatorDeviceMemory,
- public NavigatorID,
- public NavigatorLanguage,
- public NavigatorOnLine,
- public NavigatorUA,
- public Supplementable<WorkerNavigator> {
+class CORE_EXPORT WorkerNavigator final : public NavigatorBase,
+ public AcceptLanguagesWatcher {
DEFINE_WRAPPERTYPEINFO();
public:
- WorkerNavigator(const String& user_agent,
- const UserAgentMetadata&,
- ExecutionContext* execution_context);
+ explicit WorkerNavigator(ExecutionContext*);
~WorkerNavigator() override;
- // NavigatorID override
- String userAgent() const override;
-
// NavigatorLanguage override
String GetAcceptLanguages() override;
// AcceptLanguagesWatcher override
void NotifyUpdate() override;
-
- void Trace(Visitor*) const override;
-
- protected:
- UserAgentMetadata GetUserAgentMetadata() const override {
- return ua_metadata_;
- }
- ExecutionContext* GetUAExecutionContext() const override {
- return GetExecutionContext();
- }
-
- private:
- String user_agent_;
- UserAgentMetadata ua_metadata_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 776f9bbdfcc..a0c5b61e367 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -221,6 +221,13 @@ v8::Local<v8::Value> WorkerOrWorkletGlobalScope::Wrap(
return v8::Local<v8::Object>();
}
+v8::MaybeLocal<v8::Value> WorkerOrWorkletGlobalScope::WrapV2(ScriptState*) {
+ LOG(FATAL) << "WorkerOrWorkletGlobalScope must never be wrapped with wrap "
+ "method. The global object of ECMAScript environment is used "
+ "as the wrapper.";
+ return v8::MaybeLocal<v8::Value>();
+}
+
v8::Local<v8::Object> WorkerOrWorkletGlobalScope::AssociateWithWrapper(
v8::Isolate*,
const WrapperTypeInfo*,
@@ -314,12 +321,12 @@ ResourceFetcher* WorkerOrWorkletGlobalScope::CreateFetcherInternal(
auto* worker_fetch_context = MakeGarbageCollected<WorkerFetchContext>(
properties, *this, web_worker_fetch_context_, subresource_filter_,
content_security_policy, resource_timing_notifier);
- ResourceFetcherInit init(properties, worker_fetch_context,
- GetTaskRunner(TaskType::kNetworking),
- GetTaskRunner(TaskType::kNetworkingUnfreezable),
- MakeGarbageCollected<LoaderFactoryForWorker>(
- *this, web_worker_fetch_context_),
- this);
+ ResourceFetcherInit init(
+ properties, worker_fetch_context, GetTaskRunner(TaskType::kNetworking),
+ GetTaskRunner(TaskType::kNetworkingUnfreezable),
+ MakeGarbageCollected<LoaderFactoryForWorker>(*this,
+ web_worker_fetch_context_),
+ this, nullptr /* back_forward_cache_loader_helper */);
init.use_counter = MakeGarbageCollected<DetachableUseCounter>(this);
init.console_logger = MakeGarbageCollected<DetachableConsoleLogger>(this);
@@ -351,7 +358,8 @@ ResourceFetcher* WorkerOrWorkletGlobalScope::CreateFetcherInternal(
ResourceFetcherInit(properties, &FetchContext::NullInstance(),
GetTaskRunner(TaskType::kNetworking),
GetTaskRunner(TaskType::kNetworkingUnfreezable),
- nullptr /* loader_factory */, this));
+ nullptr /* loader_factory */, this,
+ nullptr /* back_forward_cache_loader_helper */));
}
if (IsContextPaused())
fetcher->SetDefersLoading(WebURLLoader::DeferType::kDeferred);
@@ -376,11 +384,8 @@ ResourceFetcher* WorkerOrWorkletGlobalScope::CreateOutsideSettingsFetcher(
content_security_policy->SetSupportsWasmEval(
SchemeRegistry::SchemeSupportsWasmEvalCSP(
outside_settings_object.GetSecurityOrigin()->Protocol()));
- for (const auto& policy_and_type : outside_content_security_policy_headers_) {
- content_security_policy->DidReceiveHeader(
- policy_and_type.first, policy_and_type.second,
- network::mojom::ContentSecurityPolicySource::kHTTP);
- }
+ content_security_policy->AddPolicies(
+ mojo::Clone(outside_content_security_policies_));
OutsideSettingsCSPDelegate* csp_delegate =
MakeGarbageCollected<OutsideSettingsCSPDelegate>(outside_settings_object,
@@ -429,9 +434,9 @@ WorkerOrWorkletGlobalScope::GetTaskRunner(TaskType type) {
return GetThread()->GetTaskRunner(type);
}
-void WorkerOrWorkletGlobalScope::ApplySandboxFlags(
+void WorkerOrWorkletGlobalScope::SetSandboxFlags(
network::mojom::blink::WebSandboxFlags mask) {
- GetSecurityContext().ApplySandboxFlags(mask);
+ GetSecurityContext().SetSandboxFlags(mask);
if (IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin) &&
!GetSecurityOrigin()->IsOpaque()) {
GetSecurityContext().SetSecurityOrigin(
@@ -439,24 +444,20 @@ void WorkerOrWorkletGlobalScope::ApplySandboxFlags(
}
}
-void WorkerOrWorkletGlobalScope::SetOutsideContentSecurityPolicyHeaders(
- const Vector<CSPHeaderAndType>& headers) {
- outside_content_security_policy_headers_ = headers;
+void WorkerOrWorkletGlobalScope::SetOutsideContentSecurityPolicies(
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies) {
+ outside_content_security_policies_ = std::move(policies);
}
void WorkerOrWorkletGlobalScope::InitContentSecurityPolicyFromVector(
- const Vector<CSPHeaderAndType>& headers) {
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies) {
if (!GetContentSecurityPolicy()) {
auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
csp->SetSupportsWasmEval(SchemeRegistry::SchemeSupportsWasmEvalCSP(
GetSecurityOrigin()->Protocol()));
GetSecurityContext().SetContentSecurityPolicy(csp);
}
- for (const auto& policy_and_type : headers) {
- GetContentSecurityPolicy()->DidReceiveHeader(
- policy_and_type.first, policy_and_type.second,
- network::mojom::ContentSecurityPolicySource::kHTTP);
- }
+ GetContentSecurityPolicy()->AddPolicies(std::move(policies));
}
void WorkerOrWorkletGlobalScope::BindContentSecurityPolicyToExecutionContext() {
@@ -502,12 +503,13 @@ void WorkerOrWorkletGlobalScope::FetchModuleScript(
ScriptFetchOptions options(
nonce, IntegrityMetadataSet(), integrity_attribute, parser_state,
credentials_mode, network::mojom::ReferrerPolicy::kDefault,
- mojom::FetchImportanceMode::kImportanceAuto, reject_coep_unsafe_none);
+ mojom::blink::FetchImportanceMode::kImportanceAuto,
+ RenderBlockingBehavior::kNonBlocking, reject_coep_unsafe_none);
Modulator* modulator = Modulator::From(ScriptController()->GetScriptState());
// Step 3. "Perform the internal module script graph fetching procedure ..."
modulator->FetchTree(
- module_url_record,
+ module_url_record, ModuleType::kJavaScript,
CreateOutsideSettingsFetcher(fetch_client_settings_object,
resource_timing_notifier),
context_type, destination, options, custom_fetch_type, client);
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
index 5701984bae8..005c6ddd2bb 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -64,6 +64,7 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
// ScriptWrappable
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) final;
+ v8::MaybeLocal<v8::Value> WrapV2(ScriptState*) final;
v8::Local<v8::Object> AssociateWithWrapper(
v8::Isolate*,
const WrapperTypeInfo*,
@@ -140,7 +141,7 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
WorkerOrWorkletScriptController* ScriptController() {
return script_controller_.Get();
}
- mojom::blink::V8CacheOptions GetV8CacheOptions() const {
+ mojom::blink::V8CacheOptions GetV8CacheOptions() const override {
return v8_cache_options_;
}
@@ -150,21 +151,27 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) override;
- void ApplySandboxFlags(network::mojom::blink::WebSandboxFlags mask);
+ void SetSandboxFlags(network::mojom::blink::WebSandboxFlags mask);
void SetDefersLoadingForResourceFetchers(WebURLLoader::DeferType defers);
virtual int GetOutstandingThrottledLimit() const;
+ // TODO(crbug.com/1146824): Remove this once PlzDedicatedWorker and
+ // PlzServiceWorker ship.
+ virtual bool IsInitialized() const = 0;
+
Deprecation& GetDeprecation() { return deprecation_; }
protected:
// Sets outside's CSP used for off-main-thread top-level worker script
// fetch.
- void SetOutsideContentSecurityPolicyHeaders(const Vector<CSPHeaderAndType>&);
+ void SetOutsideContentSecurityPolicies(
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>);
// Initializes inside's CSP used for subresource fetch etc.
- void InitContentSecurityPolicyFromVector(const Vector<CSPHeaderAndType>&);
+ void InitContentSecurityPolicyFromVector(
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> policies);
virtual void BindContentSecurityPolicyToExecutionContext();
void FetchModuleScript(const KURL& module_url_record,
@@ -176,8 +183,9 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
ModuleScriptCustomFetchType,
ModuleTreeClient*);
- const Vector<CSPHeaderAndType>& OutsideContentSecurityPolicyHeaders() const {
- return outside_content_security_policy_headers_;
+ const Vector<network::mojom::blink::ContentSecurityPolicyPtr>&
+ OutsideContentSecurityPolicies() const {
+ return outside_content_security_policies_;
}
void SetIsOfflineMode(bool is_offline_mode) {
@@ -236,7 +244,8 @@ class CORE_EXPORT WorkerOrWorkletGlobalScope : public EventTargetWithInlineData,
// TODO(hiroshige): Pass outsideSettings-CSP via
// outsideSettings-FetchClientSettingsObject.
- Vector<CSPHeaderAndType> outside_content_security_policy_headers_;
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>
+ outside_content_security_policies_;
WorkerReportingProxy& reporting_proxy_;
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread.cc b/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
index 7a04127a614..d06931f255e 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -45,6 +45,7 @@
#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
#include "third_party/blink/renderer/core/loader/worker_resource_timing_notifier_impl.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/workers/cross_thread_global_scope_creation_params_copier.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/core/workers/worker_clients.h"
@@ -188,10 +189,10 @@ void WorkerThread::Start(
PostCrossThreadTask(
*GetWorkerBackingThread().BackingThread().GetTaskRunner(), FROM_HERE,
- CrossThreadBindOnce(
- &WorkerThread::InitializeOnWorkerThread, CrossThreadUnretained(this),
- WTF::Passed(std::move(global_scope_creation_params)),
- thread_startup_data, WTF::Passed(std::move(devtools_params))));
+ CrossThreadBindOnce(&WorkerThread::InitializeOnWorkerThread,
+ CrossThreadUnretained(this),
+ std::move(global_scope_creation_params),
+ thread_startup_data, std::move(devtools_params)));
}
void WorkerThread::EvaluateClassicScript(
@@ -204,7 +205,7 @@ void WorkerThread::EvaluateClassicScript(
*GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
CrossThreadBindOnce(&WorkerThread::EvaluateClassicScriptOnWorkerThread,
CrossThreadUnretained(this), script_url, source_code,
- WTF::Passed(std::move(cached_meta_data)), stack_id));
+ std::move(cached_meta_data), stack_id));
}
void WorkerThread::FetchAndRunClassicScript(
@@ -221,8 +222,8 @@ void WorkerThread::FetchAndRunClassicScript(
CrossThreadBindOnce(
&WorkerThread::FetchAndRunClassicScriptOnWorkerThread,
CrossThreadUnretained(this), script_url,
- WTF::Passed(std::move(worker_main_script_load_params)),
- WTF::Passed(std::move(outside_settings_object_data)),
+ std::move(worker_main_script_load_params),
+ std::move(outside_settings_object_data),
WrapCrossThreadPersistent(outside_resource_timing_notifier),
stack_id));
}
@@ -242,8 +243,8 @@ void WorkerThread::FetchAndRunModuleScript(
CrossThreadBindOnce(
&WorkerThread::FetchAndRunModuleScriptOnWorkerThread,
CrossThreadUnretained(this), script_url,
- WTF::Passed(std::move(worker_main_script_load_params)),
- WTF::Passed(std::move(outside_settings_object_data)),
+ std::move(worker_main_script_load_params),
+ std::move(outside_settings_object_data),
WrapCrossThreadPersistent(outside_resource_timing_notifier),
credentials_mode, reject_coep_unsafe_none.value()));
}
@@ -400,10 +401,6 @@ HashSet<WorkerThread*>& WorkerThread::WorkerThreads() {
return threads;
}
-PlatformThreadId WorkerThread::GetPlatformThreadId() {
- return GetWorkerBackingThread().BackingThread().ThreadId();
-}
-
bool WorkerThread::IsForciblyTerminated() {
MutexLocker lock(mutex_);
switch (exit_code_) {
@@ -580,6 +577,7 @@ void WorkerThread::InitializeSchedulerOnWorkerThread(
TaskType::kPostedMessage,
TaskType::kRemoteEvent,
TaskType::kUserInteraction,
+ TaskType::kWakeLock,
TaskType::kWebGL,
TaskType::kWebLocks,
TaskType::kWebSocket,
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread.h b/chromium/third_party/blink/renderer/core/workers/worker_thread.h
index 5f0bd9e75d3..60298036272 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread.h
@@ -219,8 +219,6 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver {
int GetWorkerThreadId() const { return worker_thread_id_; }
- PlatformThreadId GetPlatformThreadId();
-
bool IsForciblyTerminated() LOCKS_EXCLUDED(mutex_);
void WaitForShutdownForTesting();
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc b/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
index b59483ccb7e..53385b70ebe 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -380,15 +380,12 @@ TEST_F(WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunningOnInitialization) {
EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope()).Times(1);
EXPECT_CALL(*reporting_proxy_, DidTerminateWorkerThread()).Times(1);
- Vector<CSPHeaderAndType> headers{
- {"contentSecurityPolicy",
- network::mojom::ContentSecurityPolicyType::kReport}};
-
auto global_scope_creation_params =
std::make_unique<GlobalScopeCreationParams>(
KURL("http://fake.url/"), mojom::blink::ScriptType::kClassic,
"fake global scope name", "fake user agent", UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, headers,
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
network::mojom::ReferrerPolicy::kDefault, security_origin_.get(),
false /* starter_secure_context */,
CalculateHttpsState(security_origin_.get()),
diff --git a/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
index 76bb3c700b6..b5da6efcf40 100644
--- a/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
+++ b/chromium/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -50,8 +50,7 @@ class FakeWorkerGlobalScope : public WorkerGlobalScope {
WorkerThread* thread)
: WorkerGlobalScope(std::move(creation_params),
thread,
- base::TimeTicks::Now(),
- ukm::kInvalidSourceId) {
+ base::TimeTicks::Now()) {
ReadyToRunWorkerScript();
}
@@ -63,19 +62,20 @@ class FakeWorkerGlobalScope : public WorkerGlobalScope {
}
// WorkerGlobalScope
- void Initialize(const KURL& response_url,
- network::mojom::ReferrerPolicy response_referrer_policy,
- network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
- const Vector<String>* response_origin_trial_tokens,
- int64_t appcache_id) override {
+ void Initialize(
+ const KURL& response_url,
+ network::mojom::ReferrerPolicy response_referrer_policy,
+ network::mojom::IPAddressSpace response_address_space,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
+ const Vector<String>* response_origin_trial_tokens,
+ int64_t appcache_id) override {
InitializeURL(response_url);
SetReferrerPolicy(response_referrer_policy);
SetAddressSpace(response_address_space);
// These should be called after SetAddressSpace() to correctly override the
// address space by the "treat-as-public-address" CSP directive.
- InitContentSecurityPolicyFromVector(response_csp_headers);
+ InitContentSecurityPolicyFromVector(std::move(response_csp));
BindContentSecurityPolicyToExecutionContext();
OriginTrialContext::AddTokens(this, response_origin_trial_tokens);
@@ -137,13 +137,11 @@ class WorkerThreadForTest : public WorkerThread {
const String& source,
const KURL& script_url = KURL("http://fake.url/"),
WorkerClients* worker_clients = nullptr) {
- Vector<CSPHeaderAndType> headers{
- {"contentSecurityPolicy",
- network::mojom::ContentSecurityPolicyType::kReport}};
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
script_url, mojom::blink::ScriptType::kClassic,
"fake global scope name", "fake user agent", UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, headers,
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
network::mojom::ReferrerPolicy::kDefault, security_origin,
false /* starter_secure_context */,
CalculateHttpsState(security_origin), worker_clients,
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
index 818ab0d61a3..224fe05d9e2 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -113,23 +113,27 @@ WorkletGlobalScope::WorkletGlobalScope(
// Step 5: "Let inheritedReferrerPolicy be outsideSettings's referrer policy."
SetReferrerPolicy(creation_params->referrer_policy);
- SetOutsideContentSecurityPolicyHeaders(
- creation_params->outside_content_security_policy_headers);
+ SetOutsideContentSecurityPolicies(
+ mojo::Clone(creation_params->outside_content_security_policies));
// https://drafts.css-houdini.org/worklets/#creating-a-workletglobalscope
// Step 6: "Invoke the initialize a global object's CSP list algorithm given
// workletGlobalScope."
InitContentSecurityPolicyFromVector(
- creation_params->outside_content_security_policy_headers);
+ std::move(creation_params->outside_content_security_policies));
BindContentSecurityPolicyToExecutionContext();
OriginTrialContext::AddTokens(this,
creation_params->origin_trial_tokens.get());
+
+ // WorkletGlobalScopes are not currently provided with UKM source IDs.
+ DCHECK_EQ(creation_params->ukm_source_id, ukm::kInvalidSourceId);
}
WorkletGlobalScope::~WorkletGlobalScope() = default;
-BrowserInterfaceBrokerProxy& WorkletGlobalScope::GetBrowserInterfaceBroker() {
+const BrowserInterfaceBrokerProxy&
+WorkletGlobalScope::GetBrowserInterfaceBroker() const {
NOTIMPLEMENTED();
return GetEmptyBrowserInterfaceBroker();
}
@@ -274,20 +278,6 @@ KURL WorkletGlobalScope::CompleteURL(const String& url) const {
return KURL(BaseURL(), url);
}
-void WorkletGlobalScope::BindContentSecurityPolicyToExecutionContext() {
- WorkerOrWorkletGlobalScope::BindContentSecurityPolicyToExecutionContext();
-
- // CSP checks should resolve self based on the 'fetch client settings object'
- // (i.e., the document's origin), not the 'module map settings object' (i.e.,
- // the opaque origin of this worklet global scope). The current implementation
- // doesn't have separate CSP objects for these two contexts. Therefore,
- // we initialize the worklet global scope's CSP object (which would naively
- // appear to be a CSP object for the 'module map settings object') entirely
- // based on state from the document (the origin and CSP headers it passed
- // here), and use the document's origin for 'self' CSP checks.
- GetContentSecurityPolicy()->SetupSelf(*document_security_origin_);
-}
-
ukm::UkmRecorder* WorkletGlobalScope::UkmRecorder() {
if (ukm_recorder_)
return ukm_recorder_.get();
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
index b57faf0491c..459d909d089 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -71,6 +71,7 @@ class CORE_EXPORT WorkletGlobalScope
void Dispose() override;
WorkerThread* GetThread() const final;
const base::UnguessableToken& GetDevToolsToken() const override;
+ bool IsInitialized() const final { return true; }
virtual LocalFrame* GetFrame() const;
@@ -123,7 +124,7 @@ class CORE_EXPORT WorkletGlobalScope
WorkerReportingProxy&,
WorkerThread*);
- BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() override;
+ const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() const override;
// Returns the WorkletToken that uniquely identifies this worklet.
virtual WorkletToken GetWorkletToken() const = 0;
@@ -158,8 +159,6 @@ class CORE_EXPORT WorkletGlobalScope
EventTarget* ErrorEventTarget() final { return nullptr; }
- void BindContentSecurityPolicyToExecutionContext() override;
-
// The |url_| and |user_agent_| are inherited from the parent Document.
const KURL url_;
const String user_agent_;
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.cc b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.cc
index 85d81f3e036..62af82b1d68 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.cc
@@ -70,9 +70,11 @@ void WorkletModuleResponsesMap::Entry::SetParams(
// Step 2: "Let url be request's url."
bool WorkletModuleResponsesMap::GetEntry(
const KURL& url,
+ ModuleType module_type,
ModuleScriptFetcher::Client* client,
scoped_refptr<base::SingleThreadTaskRunner> client_task_runner) {
MutexLocker lock(mutex_);
+ DCHECK_NE(module_type, ModuleType::kInvalid);
if (!is_available_ || !IsValidURL(url)) {
client_task_runner->PostTask(
FROM_HERE, WTF::Bind(&ModuleScriptFetcher::Client::OnFailed,
@@ -80,7 +82,7 @@ bool WorkletModuleResponsesMap::GetEntry(
return true;
}
- auto it = entries_.find(url);
+ auto it = entries_.find(std::make_pair(url, module_type));
if (it != entries_.end()) {
Entry* entry = it->value.get();
switch (entry->GetState()) {
@@ -111,7 +113,7 @@ bool WorkletModuleResponsesMap::GetEntry(
// Step 5: "Create an entry in cache with key url and value "fetching"."
std::unique_ptr<Entry> entry = std::make_unique<Entry>();
entry->AddClient(client, client_task_runner);
- entries_.insert(url.Copy(), std::move(entry));
+ entries_.insert(std::make_pair(url.Copy(), module_type), std::move(entry));
// Step 6: "Fetch request."
// Running the callback with an empty params will make the fetcher to fallback
@@ -122,13 +124,14 @@ bool WorkletModuleResponsesMap::GetEntry(
void WorkletModuleResponsesMap::SetEntryParams(
const KURL& url,
+ ModuleType module_type,
const base::Optional<ModuleScriptCreationParams>& params) {
MutexLocker lock(mutex_);
if (!is_available_)
return;
- DCHECK(entries_.Contains(url));
- Entry* entry = entries_.find(url)->value.get();
+ DCHECK(entries_.Contains(std::make_pair(url, module_type)));
+ Entry* entry = entries_.find(std::make_pair(url, module_type))->value.get();
entry->SetParams(params);
}
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.h b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
index 92fcebc86c4..3f5600f3a53 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map.h
@@ -42,12 +42,14 @@ class CORE_EXPORT WorkletModuleResponsesMap final
// class-level comment.
// Called on worklet threads.
bool GetEntry(const KURL&,
+ ModuleType,
ModuleScriptFetcher::Client*,
scoped_refptr<base::SingleThreadTaskRunner> client_task_runner)
LOCKS_EXCLUDED(mutex_);
// Called on worklet threads.
void SetEntryParams(const KURL&,
+ ModuleType,
const base::Optional<ModuleScriptCreationParams>&)
LOCKS_EXCLUDED(mutex_);
@@ -92,7 +94,8 @@ class CORE_EXPORT WorkletModuleResponsesMap final
// addModule() calls for a newly created global scope.
// See https://drafts.css-houdini.org/worklets/#creating-a-workletglobalscope
// Can be read/written by any thread.
- HashMap<KURL, std::unique_ptr<Entry>> entries_ GUARDED_BY(mutex_);
+ using Key = std::pair<KURL, ModuleType>;
+ HashMap<Key, std::unique_ptr<Entry>> entries_ GUARDED_BY(mutex_);
Mutex mutex_;
};
diff --git a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
index c2eefc1df2f..2e9648f7ba7 100644
--- a/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/workers/worklet_module_responses_map_test.cc
@@ -38,7 +38,8 @@ class WorkletModuleResponsesMapTest : public testing::Test {
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>(
platform_->GetURLLoaderMockFactory()),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
map_ = MakeGarbageCollected<WorkletModuleResponsesMap>();
}
@@ -47,23 +48,22 @@ class WorkletModuleResponsesMapTest : public testing::Test {
public:
enum class Result { kInitial, kOK, kFailed };
- void NotifyFetchFinished(
- const base::Optional<ModuleScriptCreationParams>& params,
+ void NotifyFetchFinishedError(
const HeapVector<Member<ConsoleMessage>>&) override {
ASSERT_EQ(Result::kInitial, result_);
- if (params) {
- result_ = Result::kOK;
- params_.emplace(*params);
- } else {
- result_ = Result::kFailed;
- }
+ result_ = Result::kFailed;
}
- Result GetResult() const { return result_; }
- base::Optional<ModuleScriptCreationParams> GetParams() const {
- return params_;
+ void NotifyFetchFinishedSuccess(
+ const ModuleScriptCreationParams& params) override {
+ ASSERT_EQ(Result::kInitial, result_);
+ result_ = Result::kOK;
+ params_.emplace(std::move(params));
}
+ Result GetResult() const { return result_; }
+ bool HasParams() const { return params_.has_value(); }
+
private:
Result result_ = Result::kInitial;
base::Optional<ModuleScriptCreationParams> params_;
@@ -77,10 +77,11 @@ class WorkletModuleResponsesMapTest : public testing::Test {
mojom::blink::RequestContextType::SCRIPT);
FetchParameters fetch_params =
FetchParameters::CreateForTest(std::move(resource_request));
+ fetch_params.SetModuleScript();
WorkletModuleScriptFetcher* module_fetcher =
MakeGarbageCollected<WorkletModuleScriptFetcher>(
map_.Get(), ModuleScriptLoader::CreatePassKeyForTests());
- module_fetcher->Fetch(fetch_params, fetcher_.Get(),
+ module_fetcher->Fetch(fetch_params, ModuleType::kJavaScript, fetcher_.Get(),
ModuleGraphLevel::kTopLevelModuleFetch, client);
}
@@ -107,7 +108,7 @@ TEST_F(WorkletModuleResponsesMapTest, Basic) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
- EXPECT_FALSE(clients[0]->GetParams().has_value());
+ EXPECT_FALSE(clients[0]->HasParams());
// The entry is now being fetched. Following read calls should wait for the
// completion.
@@ -124,7 +125,7 @@ TEST_F(WorkletModuleResponsesMapTest, Basic) {
RunUntilIdle();
for (auto client : clients) {
EXPECT_EQ(ClientImpl::Result::kOK, client->GetResult());
- EXPECT_TRUE(client->GetParams().has_value());
+ EXPECT_TRUE(client->HasParams());
}
}
@@ -138,7 +139,7 @@ TEST_F(WorkletModuleResponsesMapTest, Failure) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
- EXPECT_FALSE(clients[0]->GetParams().has_value());
+ EXPECT_FALSE(clients[0]->HasParams());
// The entry is now being fetched. Following read calls should wait for the
// completion.
@@ -155,7 +156,7 @@ TEST_F(WorkletModuleResponsesMapTest, Failure) {
RunUntilIdle();
for (auto client : clients) {
EXPECT_EQ(ClientImpl::Result::kFailed, client->GetResult());
- EXPECT_FALSE(client->GetParams().has_value());
+ EXPECT_FALSE(client->HasParams());
}
}
@@ -173,7 +174,7 @@ TEST_F(WorkletModuleResponsesMapTest, Isolation) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
- EXPECT_FALSE(clients[0]->GetParams().has_value());
+ EXPECT_FALSE(clients[0]->HasParams());
// The entry is now being fetched. Following read calls for |kUrl1| should
// wait for the completion.
@@ -185,7 +186,7 @@ TEST_F(WorkletModuleResponsesMapTest, Isolation) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
- EXPECT_FALSE(clients[2]->GetParams().has_value());
+ EXPECT_FALSE(clients[2]->HasParams());
// The entry is now being fetched. Following read calls for |kUrl2| should
// wait for the completion.
@@ -200,13 +201,13 @@ TEST_F(WorkletModuleResponsesMapTest, Isolation) {
platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, clients[0]->GetResult());
- EXPECT_FALSE(clients[0]->GetParams().has_value());
+ EXPECT_FALSE(clients[0]->HasParams());
EXPECT_EQ(ClientImpl::Result::kFailed, clients[1]->GetResult());
- EXPECT_FALSE(clients[1]->GetParams().has_value());
+ EXPECT_FALSE(clients[1]->HasParams());
EXPECT_EQ(ClientImpl::Result::kOK, clients[2]->GetResult());
- EXPECT_TRUE(clients[2]->GetParams().has_value());
+ EXPECT_TRUE(clients[2]->HasParams());
EXPECT_EQ(ClientImpl::Result::kOK, clients[3]->GetResult());
- EXPECT_TRUE(clients[3]->GetParams().has_value());
+ EXPECT_TRUE(clients[3]->HasParams());
}
TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
@@ -216,7 +217,7 @@ TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
Fetch(kEmptyURL, client1);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client1->GetResult());
- EXPECT_FALSE(client1->GetParams().has_value());
+ EXPECT_FALSE(client1->HasParams());
const KURL kNullURL = NullURL();
ASSERT_TRUE(kNullURL.IsNull());
@@ -224,7 +225,7 @@ TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
Fetch(kNullURL, client2);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client2->GetResult());
- EXPECT_FALSE(client2->GetParams().has_value());
+ EXPECT_FALSE(client2->HasParams());
const KURL kInvalidURL;
ASSERT_FALSE(kInvalidURL.IsValid());
@@ -232,7 +233,7 @@ TEST_F(WorkletModuleResponsesMapTest, InvalidURL) {
Fetch(kInvalidURL, client3);
RunUntilIdle();
EXPECT_EQ(ClientImpl::Result::kFailed, client3->GetResult());
- EXPECT_FALSE(client3->GetParams().has_value());
+ EXPECT_FALSE(client3->HasParams());
}
TEST_F(WorkletModuleResponsesMapTest, Dispose) {
@@ -251,7 +252,7 @@ TEST_F(WorkletModuleResponsesMapTest, Dispose) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl1, clients[0]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
- EXPECT_FALSE(clients[0]->GetParams().has_value());
+ EXPECT_FALSE(clients[0]->HasParams());
// The entry is now being fetched. Following read calls for |kUrl1| should
// wait for the completion.
@@ -264,7 +265,7 @@ TEST_F(WorkletModuleResponsesMapTest, Dispose) {
clients.push_back(MakeGarbageCollected<ClientImpl>());
Fetch(kUrl2, clients[2]);
EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
- EXPECT_FALSE(clients[2]->GetParams().has_value());
+ EXPECT_FALSE(clients[2]->HasParams());
// The entry is now being fetched. Following read calls for |kUrl2| should
// wait for the completion.
@@ -277,7 +278,7 @@ TEST_F(WorkletModuleResponsesMapTest, Dispose) {
RunUntilIdle();
for (auto client : clients) {
EXPECT_EQ(ClientImpl::Result::kFailed, client->GetResult());
- EXPECT_FALSE(client->GetParams().has_value());
+ EXPECT_FALSE(client->HasParams());
}
}
diff --git a/chromium/third_party/blink/renderer/core/xml/DIR_METADATA b/chromium/third_party/blink/renderer/core/xml/DIR_METADATA
new file mode 100644
index 00000000000..3f57820b025
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/xml/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>XML"
+}
diff --git a/chromium/third_party/blink/renderer/core/xml/OWNERS b/chromium/third_party/blink/renderer/core/xml/OWNERS
index 5c2ac186c8c..300e43542d2 100644
--- a/chromium/third_party/blink/renderer/core/xml/OWNERS
+++ b/chromium/third_party/blink/renderer/core/xml/OWNERS
@@ -1,5 +1,4 @@
# There's no real owners here. If you're familiar with the code please send
# a CL to add yourself here.
-# COMPONENT: Blink>XML
dcheng@chromium.org
palmer@chromium.org
diff --git a/chromium/third_party/blink/renderer/core/xml/dom_parser.cc b/chromium/third_party/blink/renderer/core/xml/dom_parser.cc
index 949b2d90a58..faf389ee603 100644
--- a/chromium/third_party/blink/renderer/core/xml/dom_parser.cc
+++ b/chromium/third_party/blink/renderer/core/xml/dom_parser.cc
@@ -19,10 +19,10 @@
#include "third_party/blink/renderer/core/xml/dom_parser.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_parse_from_string_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/xml/parse_from_string_options.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -37,8 +37,8 @@ Document* DOMParser::parseFromString(const String& str,
.WithTypeFrom(type)
.WithExecutionContext(window_)
.CreateDocument();
- doc->setAllowDeclarativeShadowRoot(options->hasAllowShadowRoot() &&
- options->allowShadowRoot());
+ doc->setAllowDeclarativeShadowRoots(options->hasIncludeShadowRoots() &&
+ options->includeShadowRoots());
doc->SetContent(str);
doc->SetMimeType(AtomicString(type));
return doc;
diff --git a/chromium/third_party/blink/renderer/core/xml/dom_parser.h b/chromium/third_party/blink/renderer/core/xml/dom_parser.h
index 1cd7a6b762b..d7c8c8309c2 100644
--- a/chromium/third_party/blink/renderer/core/xml/dom_parser.h
+++ b/chromium/third_party/blink/renderer/core/xml/dom_parser.h
@@ -20,6 +20,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_XML_DOM_PARSER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_XML_DOM_PARSER_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -31,7 +32,7 @@ class ParseFromStringOptions;
class LocalDOMWindow;
class ScriptState;
-class DOMParser final : public ScriptWrappable {
+class CORE_EXPORT DOMParser final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
diff --git a/chromium/third_party/blink/renderer/core/xml/parse_from_string_options.idl b/chromium/third_party/blink/renderer/core/xml/parse_from_string_options.idl
index 29d7beecac3..3e2781e5e2d 100644
--- a/chromium/third_party/blink/renderer/core/xml/parse_from_string_options.idl
+++ b/chromium/third_party/blink/renderer/core/xml/parse_from_string_options.idl
@@ -3,5 +3,5 @@
// found in the LICENSE file.
dictionary ParseFromStringOptions {
- boolean allowShadowRoot = false;
+ boolean includeShadowRoots = false;
};
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
index a88d822f1ec..813f0133c88 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y
@@ -269,7 +269,7 @@ NodeTest:
OptionalPredicateList:
/* empty */
{
- $$ = 0;
+ $$ = nullptr;
}
|
PredicateList
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.cc b/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.cc
index 1934f5aa7d9..504cc4e160c 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.cc
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.cc
@@ -1,9 +1,9 @@
// clang-format off
-// A Bison parser, made by GNU Bison 3.4.2.
+// A Bison parser, made by GNU Bison 3.7.4.
// Skeleton implementation for Bison LALR(1) parsers in C++
-// Copyright (C) 2002-2015, 2018-2019 Free Software Foundation, Inc.
+// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,8 +31,9 @@
// This special exception was added by the Free Software Foundation in
// version 2.2 of Bison.
-// Undocumented macros, especially those whose name start with YY_,
-// are private implementation details. Do not rely on them.
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_. They are
+// private implementation details that can be changed or removed.
@@ -54,7 +55,7 @@
using blink::xpath::Step;
-#line 57 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 58 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
#include "xpath_grammar_generated.h"
@@ -73,7 +74,7 @@ void YyParser::error(const std::string&) { }
}
-#line 76 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 77 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
#ifndef YY_
@@ -88,6 +89,7 @@ void YyParser::error(const std::string&) { }
# endif
#endif
+
// Whether we are compiled with exception support.
#ifndef YY_EXCEPTIONS
# if defined __GNUC__ && !defined __EXCEPTIONS
@@ -124,7 +126,7 @@ void YyParser::error(const std::string&) { }
# define YY_STACK_PRINT() \
do { \
if (yydebug_) \
- yystack_print_ (); \
+ yy_stack_print_ (); \
} while (false)
#else // !YYDEBUG
@@ -146,15 +148,15 @@ void YyParser::error(const std::string&) { }
#line 69 "third_party/blink/renderer/core/xml/xpath_grammar.y"
namespace xpathyy {
-#line 149 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
-
+#line 151 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
/// Build a parser object.
YyParser::YyParser (blink::xpath::Parser* parser__yyarg)
- :
#if YYDEBUG
- yydebug_ (false),
+ : yydebug_ (false),
yycdebug_ (&std::cerr),
+#else
+ :
#endif
parser_ (parser__yyarg)
{}
@@ -166,163 +168,81 @@ namespace xpathyy {
{}
/*---------------.
- | Symbol types. |
+ | symbol kinds. |
`---------------*/
// basic_symbol.
-#if 201103L <= YY_CPLUSPLUS
- template <typename Base>
- YyParser::basic_symbol<Base>::basic_symbol (basic_symbol&& that)
- : Base (std::move (that))
- , value ()
- {
- switch (this->type_get ())
- {
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
- value.move< String > (std::move (that.value));
- break;
-
- case 45: // ArgumentList
- value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (std::move (that.value));
- break;
-
- case 38: // OptionalPredicateList
- case 39: // PredicateList
- value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (std::move (that.value));
- break;
-
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
- value.move< blink::Persistent<blink::xpath::Expression> > (std::move (that.value));
- break;
-
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
- value.move< blink::Persistent<blink::xpath::LocationPath> > (std::move (that.value));
- break;
-
- case 37: // NodeTest
- value.move< blink::Persistent<blink::xpath::Step::NodeTest> > (std::move (that.value));
- break;
-
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
- value.move< blink::Persistent<blink::xpath::Step> > (std::move (that.value));
- break;
-
- case 4: // kEqOp
- case 5: // kRelOp
- value.move< blink::xpath::EqTestOp::Opcode > (std::move (that.value));
- break;
-
- case 3: // kMulOp
- value.move< blink::xpath::NumericOp::Opcode > (std::move (that.value));
- break;
-
- case 10: // kAxisName
- case 36: // AxisSpecifier
- value.move< blink::xpath::Step::Axis > (std::move (that.value));
- break;
-
- default:
- break;
- }
-
- }
-#endif
-
template <typename Base>
YyParser::basic_symbol<Base>::basic_symbol (const basic_symbol& that)
: Base (that)
, value ()
{
- switch (this->type_get ())
+ switch (this->kind ())
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.copy< String > (YY_MOVE (that.value));
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.copy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (YY_MOVE (that.value));
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.copy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (YY_MOVE (that.value));
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.copy< blink::Persistent<blink::xpath::Expression> > (YY_MOVE (that.value));
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.copy< blink::Persistent<blink::xpath::LocationPath> > (YY_MOVE (that.value));
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.copy< blink::Persistent<blink::xpath::Step::NodeTest> > (YY_MOVE (that.value));
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.copy< blink::Persistent<blink::xpath::Step> > (YY_MOVE (that.value));
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.copy< blink::xpath::EqTestOp::Opcode > (YY_MOVE (that.value));
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.copy< blink::xpath::NumericOp::Opcode > (YY_MOVE (that.value));
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.copy< blink::xpath::Step::Axis > (YY_MOVE (that.value));
break;
@@ -335,10 +255,17 @@ namespace xpathyy {
template <typename Base>
+ YyParser::symbol_kind_type
+ YyParser::basic_symbol<Base>::type_get () const YY_NOEXCEPT
+ {
+ return this->kind ();
+ }
+
+ template <typename Base>
bool
YyParser::basic_symbol<Base>::empty () const YY_NOEXCEPT
{
- return Base::type_get () == empty_symbol;
+ return this->kind () == symbol_kind::S_YYEMPTY;
}
template <typename Base>
@@ -346,72 +273,72 @@ namespace xpathyy {
YyParser::basic_symbol<Base>::move (basic_symbol& s)
{
super_type::move (s);
- switch (this->type_get ())
+ switch (this->kind ())
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.move< String > (YY_MOVE (s.value));
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (YY_MOVE (s.value));
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (YY_MOVE (s.value));
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.move< blink::Persistent<blink::xpath::Expression> > (YY_MOVE (s.value));
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.move< blink::Persistent<blink::xpath::LocationPath> > (YY_MOVE (s.value));
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.move< blink::Persistent<blink::xpath::Step::NodeTest> > (YY_MOVE (s.value));
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.move< blink::Persistent<blink::xpath::Step> > (YY_MOVE (s.value));
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.move< blink::xpath::EqTestOp::Opcode > (YY_MOVE (s.value));
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.move< blink::xpath::NumericOp::Opcode > (YY_MOVE (s.value));
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.move< blink::xpath::Step::Axis > (YY_MOVE (s.value));
break;
@@ -421,44 +348,50 @@ namespace xpathyy {
}
- // by_type.
- YyParser::by_type::by_type ()
- : type (empty_symbol)
+ // by_kind.
+ YyParser::by_kind::by_kind ()
+ : kind_ (symbol_kind::S_YYEMPTY)
{}
#if 201103L <= YY_CPLUSPLUS
- YyParser::by_type::by_type (by_type&& that)
- : type (that.type)
+ YyParser::by_kind::by_kind (by_kind&& that)
+ : kind_ (that.kind_)
{
that.clear ();
}
#endif
- YyParser::by_type::by_type (const by_type& that)
- : type (that.type)
+ YyParser::by_kind::by_kind (const by_kind& that)
+ : kind_ (that.kind_)
{}
- YyParser::by_type::by_type (token_type t)
- : type (yytranslate_ (t))
+ YyParser::by_kind::by_kind (token_kind_type t)
+ : kind_ (yytranslate_ (t))
{}
void
- YyParser::by_type::clear ()
+ YyParser::by_kind::clear ()
{
- type = empty_symbol;
+ kind_ = symbol_kind::S_YYEMPTY;
}
void
- YyParser::by_type::move (by_type& that)
+ YyParser::by_kind::move (by_kind& that)
{
- type = that.type;
+ kind_ = that.kind_;
that.clear ();
}
- int
- YyParser::by_type::type_get () const YY_NOEXCEPT
+ YyParser::symbol_kind_type
+ YyParser::by_kind::kind () const YY_NOEXCEPT
+ {
+ return kind_;
+ }
+
+ YyParser::symbol_kind_type
+ YyParser::by_kind::type_get () const YY_NOEXCEPT
{
- return type;
+ return this->kind ();
}
@@ -488,13 +421,13 @@ namespace xpathyy {
: state (s)
{}
- YyParser::symbol_number_type
- YyParser::by_state::type_get () const YY_NOEXCEPT
+ YyParser::symbol_kind_type
+ YyParser::by_state::kind () const YY_NOEXCEPT
{
if (state == empty_state)
- return empty_symbol;
+ return symbol_kind::S_YYEMPTY;
else
- return yystos_[state];
+ return YY_CAST (symbol_kind_type, yystos_[+state]);
}
YyParser::stack_symbol_type::stack_symbol_type ()
@@ -503,72 +436,72 @@ namespace xpathyy {
YyParser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that)
: super_type (YY_MOVE (that.state))
{
- switch (that.type_get ())
+ switch (that.kind ())
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.YY_MOVE_OR_COPY< String > (YY_MOVE (that.value));
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.YY_MOVE_OR_COPY< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (YY_MOVE (that.value));
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.YY_MOVE_OR_COPY< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (YY_MOVE (that.value));
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.YY_MOVE_OR_COPY< blink::Persistent<blink::xpath::Expression> > (YY_MOVE (that.value));
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.YY_MOVE_OR_COPY< blink::Persistent<blink::xpath::LocationPath> > (YY_MOVE (that.value));
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.YY_MOVE_OR_COPY< blink::Persistent<blink::xpath::Step::NodeTest> > (YY_MOVE (that.value));
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.YY_MOVE_OR_COPY< blink::Persistent<blink::xpath::Step> > (YY_MOVE (that.value));
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.YY_MOVE_OR_COPY< blink::xpath::EqTestOp::Opcode > (YY_MOVE (that.value));
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.YY_MOVE_OR_COPY< blink::xpath::NumericOp::Opcode > (YY_MOVE (that.value));
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.YY_MOVE_OR_COPY< blink::xpath::Step::Axis > (YY_MOVE (that.value));
break;
@@ -585,72 +518,72 @@ namespace xpathyy {
YyParser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that)
: super_type (s)
{
- switch (that.type_get ())
+ switch (that.kind ())
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.move< String > (YY_MOVE (that.value));
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (YY_MOVE (that.value));
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (YY_MOVE (that.value));
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.move< blink::Persistent<blink::xpath::Expression> > (YY_MOVE (that.value));
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.move< blink::Persistent<blink::xpath::LocationPath> > (YY_MOVE (that.value));
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.move< blink::Persistent<blink::xpath::Step::NodeTest> > (YY_MOVE (that.value));
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.move< blink::Persistent<blink::xpath::Step> > (YY_MOVE (that.value));
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.move< blink::xpath::EqTestOp::Opcode > (YY_MOVE (that.value));
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.move< blink::xpath::NumericOp::Opcode > (YY_MOVE (that.value));
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.move< blink::xpath::Step::Axis > (YY_MOVE (that.value));
break;
@@ -659,80 +592,160 @@ namespace xpathyy {
}
// that is emptied.
- that.type = empty_symbol;
+ that.kind_ = symbol_kind::S_YYEMPTY;
}
#if YY_CPLUSPLUS < 201103L
YyParser::stack_symbol_type&
+ YyParser::stack_symbol_type::operator= (const stack_symbol_type& that)
+ {
+ state = that.state;
+ switch (that.kind ())
+ {
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
+ value.copy< String > (that.value);
+ break;
+
+ case symbol_kind::S_ArgumentList: // ArgumentList
+ value.copy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (that.value);
+ break;
+
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
+ value.copy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (that.value);
+ break;
+
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
+ value.copy< blink::Persistent<blink::xpath::Expression> > (that.value);
+ break;
+
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
+ value.copy< blink::Persistent<blink::xpath::LocationPath> > (that.value);
+ break;
+
+ case symbol_kind::S_NodeTest: // NodeTest
+ value.copy< blink::Persistent<blink::xpath::Step::NodeTest> > (that.value);
+ break;
+
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
+ value.copy< blink::Persistent<blink::xpath::Step> > (that.value);
+ break;
+
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
+ value.copy< blink::xpath::EqTestOp::Opcode > (that.value);
+ break;
+
+ case symbol_kind::S_kMulOp: // kMulOp
+ value.copy< blink::xpath::NumericOp::Opcode > (that.value);
+ break;
+
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
+ value.copy< blink::xpath::Step::Axis > (that.value);
+ break;
+
+ default:
+ break;
+ }
+
+ return *this;
+ }
+
+ YyParser::stack_symbol_type&
YyParser::stack_symbol_type::operator= (stack_symbol_type& that)
{
state = that.state;
- switch (that.type_get ())
+ switch (that.kind ())
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.move< String > (that.value);
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (that.value);
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (that.value);
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.move< blink::Persistent<blink::xpath::Expression> > (that.value);
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.move< blink::Persistent<blink::xpath::LocationPath> > (that.value);
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.move< blink::Persistent<blink::xpath::Step::NodeTest> > (that.value);
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.move< blink::Persistent<blink::xpath::Step> > (that.value);
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.move< blink::xpath::EqTestOp::Opcode > (that.value);
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.move< blink::xpath::NumericOp::Opcode > (that.value);
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.move< blink::xpath::Step::Axis > (that.value);
break;
@@ -757,22 +770,20 @@ namespace xpathyy {
#if YYDEBUG
template <typename Base>
void
- YyParser::yy_print_ (std::ostream& yyo,
- const basic_symbol<Base>& yysym) const
+ YyParser::yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const
{
std::ostream& yyoutput = yyo;
YYUSE (yyoutput);
- symbol_number_type yytype = yysym.type_get ();
-#if defined __GNUC__ && ! defined __clang__ && ! defined __ICC && __GNUC__ * 100 + __GNUC_MINOR__ <= 408
- // Avoid a (spurious) G++ 4.8 warning about "array subscript is
- // below array bounds".
if (yysym.empty ())
- std::abort ();
-#endif
- yyo << (yytype < yyntokens_ ? "token" : "nterm")
- << ' ' << yytname_[yytype] << " (";
- YYUSE (yytype);
- yyo << ')';
+ yyo << "empty symbol";
+ else
+ {
+ symbol_kind_type yykind = yysym.kind ();
+ yyo << (yykind < YYNTOKENS ? "token" : "nterm")
+ << ' ' << yysym.name () << " (";
+ YYUSE (yykind);
+ yyo << ')';
+ }
}
#endif
@@ -831,11 +842,11 @@ namespace xpathyy {
YyParser::state_type
YyParser::yy_lr_goto_state_ (state_type yystate, int yysym)
{
- int yyr = yypgoto_[yysym - yyntokens_] + yystate;
+ int yyr = yypgoto_[yysym - YYNTOKENS] + yystate;
if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
return yytable_[yyr];
else
- return yydefgoto_[yysym - yyntokens_];
+ return yydefgoto_[yysym - YYNTOKENS];
}
bool
@@ -859,7 +870,6 @@ namespace xpathyy {
int
YyParser::parse ()
{
- // State.
int yyn;
/// Length of the RHS of the rule being reduced.
int yylen = 0;
@@ -892,7 +902,8 @@ namespace xpathyy {
| yynewstate -- push a new symbol on the stack. |
`-----------------------------------------------*/
yynewstate:
- YYCDEBUG << "Entering state " << yystack_[0].state << '\n';
+ YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n';
+ YY_STACK_PRINT ();
// Accept?
if (yystack_[0].state == yyfinal_)
@@ -906,19 +917,19 @@ namespace xpathyy {
`-----------*/
yybackup:
// Try to take a decision without lookahead.
- yyn = yypact_[yystack_[0].state];
+ yyn = yypact_[+yystack_[0].state];
if (yy_pact_value_is_default_ (yyn))
goto yydefault;
// Read a lookahead token.
if (yyla.empty ())
{
- YYCDEBUG << "Reading a token: ";
+ YYCDEBUG << "Reading a token\n";
#if YY_EXCEPTIONS
try
#endif // YY_EXCEPTIONS
{
- yyla.type = yytranslate_ (yylex (&yyla.value));
+ yyla.kind_ = yytranslate_ (yylex (&yyla.value));
}
#if YY_EXCEPTIONS
catch (const syntax_error& yyexc)
@@ -931,11 +942,23 @@ namespace xpathyy {
}
YY_SYMBOL_PRINT ("Next token is", yyla);
+ if (yyla.kind () == symbol_kind::S_YYerror)
+ {
+ // The scanner already issued an error message, process directly
+ // to error recovery. But do not keep the error token as
+ // lookahead, it is too special and may lead us to an endless
+ // loop in error recovery. */
+ yyla.kind_ = symbol_kind::S_YYUNDEF;
+ goto yyerrlab1;
+ }
+
/* If the proper action on seeing token YYLA.TYPE is to reduce or
to detect an error, take that action. */
- yyn += yyla.type_get ();
- if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.type_get ())
- goto yydefault;
+ yyn += yyla.kind ();
+ if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ())
+ {
+ goto yydefault;
+ }
// Reduce or error.
yyn = yytable_[yyn];
@@ -952,7 +975,7 @@ namespace xpathyy {
--yyerrstatus_;
// Shift the lookahead token.
- yypush_ ("Shifting", yyn, YY_MOVE (yyla));
+ yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla));
goto yynewstate;
@@ -960,7 +983,7 @@ namespace xpathyy {
| yydefault -- do the default action for the current state. |
`-----------------------------------------------------------*/
yydefault:
- yyn = yydefact_[yystack_[0].state];
+ yyn = yydefact_[+yystack_[0].state];
if (yyn == 0)
goto yyerrlab;
goto yyreduce;
@@ -979,70 +1002,70 @@ namespace xpathyy {
when using variants. */
switch (yyr1_[yyn])
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
yylhs.value.emplace< String > ();
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
yylhs.value.emplace< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ();
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
yylhs.value.emplace< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ();
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
yylhs.value.emplace< blink::Persistent<blink::xpath::Expression> > ();
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
yylhs.value.emplace< blink::Persistent<blink::xpath::LocationPath> > ();
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
yylhs.value.emplace< blink::Persistent<blink::xpath::Step::NodeTest> > ();
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
yylhs.value.emplace< blink::Persistent<blink::xpath::Step> > ();
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
yylhs.value.emplace< blink::xpath::EqTestOp::Opcode > ();
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
yylhs.value.emplace< blink::xpath::NumericOp::Opcode > ();
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
yylhs.value.emplace< blink::xpath::Step::Axis > ();
break;
@@ -1060,87 +1083,87 @@ namespace xpathyy {
{
switch (yyn)
{
- case 2:
+ case 2: // Expr: OrExpr
#line 129 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
parser_->top_expr_ = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ();
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ();
}
-#line 1069 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1092 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 3:
+ case 3: // LocationPath: RelativeLocationPath
#line 137 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->SetAbsolute(false);
}
-#line 1078 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1101 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 4:
+ case 4: // LocationPath: AbsoluteLocationPath
#line 143 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->SetAbsolute(true);
}
-#line 1087 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1110 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 5:
+ case 5: // AbsoluteLocationPath: '/'
#line 151 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = blink::MakeGarbageCollected<blink::xpath::LocationPath>();
}
-#line 1095 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1118 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 6:
+ case 6: // AbsoluteLocationPath: '/' RelativeLocationPath
#line 156 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
}
-#line 1103 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1126 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 7:
+ case 7: // AbsoluteLocationPath: DescendantOrSelf RelativeLocationPath
#line 161 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->InsertFirstStep(yystack_[1].value.as < blink::Persistent<blink::xpath::Step> > ());
}
-#line 1112 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1135 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 8:
+ case 8: // RelativeLocationPath: Step
#line 169 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = blink::MakeGarbageCollected<blink::xpath::LocationPath>();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->AppendStep(yystack_[0].value.as < blink::Persistent<blink::xpath::Step> > ());
}
-#line 1121 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1144 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 9:
+ case 9: // RelativeLocationPath: RelativeLocationPath '/' Step
#line 175 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[2].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->AppendStep(yystack_[0].value.as < blink::Persistent<blink::xpath::Step> > ());
}
-#line 1130 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1153 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 10:
+ case 10: // RelativeLocationPath: RelativeLocationPath DescendantOrSelf Step
#line 181 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > () = yystack_[2].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->AppendStep(yystack_[1].value.as < blink::Persistent<blink::xpath::Step> > ());
yylhs.value.as < blink::Persistent<blink::xpath::LocationPath> > ()->AppendStep(yystack_[0].value.as < blink::Persistent<blink::xpath::Step> > ());
}
-#line 1140 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1163 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 11:
+ case 11: // Step: NodeTest OptionalPredicateList
#line 190 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
if (yystack_[0].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ())
@@ -1148,10 +1171,10 @@ namespace xpathyy {
else
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(Step::kChildAxis, *yystack_[1].value.as < blink::Persistent<blink::xpath::Step::NodeTest> > ());
}
-#line 1151 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1174 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 12:
+ case 12: // Step: kNameTest OptionalPredicateList
#line 198 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
AtomicString local_name;
@@ -1166,10 +1189,10 @@ namespace xpathyy {
else
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(Step::kChildAxis, Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
}
-#line 1169 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1192 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 13:
+ case 13: // Step: AxisSpecifier NodeTest OptionalPredicateList
#line 213 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
if (yystack_[0].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ())
@@ -1177,10 +1200,10 @@ namespace xpathyy {
else
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(yystack_[2].value.as < blink::xpath::Step::Axis > (), *yystack_[1].value.as < blink::Persistent<blink::xpath::Step::NodeTest> > ());
}
-#line 1180 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1203 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 14:
+ case 14: // Step: AxisSpecifier kNameTest OptionalPredicateList
#line 221 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
AtomicString local_name;
@@ -1195,30 +1218,30 @@ namespace xpathyy {
else
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(yystack_[2].value.as < blink::xpath::Step::Axis > (), Step::NodeTest(Step::NodeTest::kNameTest, local_name, namespace_uri));
}
-#line 1198 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1221 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 15:
+ case 15: // Step: AbbreviatedStep
#line 235 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Step> > (); }
-#line 1204 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1227 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 16:
+ case 16: // AxisSpecifier: kAxisName
#line 239 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::xpath::Step::Axis > () = yystack_[0].value.as < blink::xpath::Step::Axis > (); }
-#line 1210 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1233 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 17:
+ case 17: // AxisSpecifier: '@'
#line 242 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::xpath::Step::Axis > () = Step::kAttributeAxis;
}
-#line 1218 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1241 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 18:
+ case 18: // NodeTest: kNodeType '(' ')'
#line 249 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
if (yystack_[2].value.as < String > () == "node")
@@ -1228,345 +1251,345 @@ namespace xpathyy {
else if (yystack_[2].value.as < String > () == "comment")
yylhs.value.as < blink::Persistent<blink::xpath::Step::NodeTest> > () = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kCommentNodeTest);
}
-#line 1231 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1254 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 19:
+ case 19: // NodeTest: kPI '(' ')'
#line 259 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Step::NodeTest> > () = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kProcessingInstructionNodeTest);
}
-#line 1239 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1262 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 20:
+ case 20: // NodeTest: kPI '(' kLiteral ')'
#line 264 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Step::NodeTest> > () = blink::MakeGarbageCollected<Step::NodeTest>(Step::NodeTest::kProcessingInstructionNodeTest, yystack_[1].value.as < String > ().StripWhiteSpace());
}
-#line 1247 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1270 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 21:
+ case 21: // OptionalPredicateList: %empty
#line 271 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
- yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > () = 0;
+ yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > () = nullptr;
}
-#line 1255 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1278 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 22:
+ case 22: // OptionalPredicateList: PredicateList
#line 276 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > () = yystack_[0].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ();
}
-#line 1263 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1286 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 23:
+ case 23: // PredicateList: Predicate
#line 283 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > () = blink::MakeGarbageCollected<blink::HeapVector<blink::Member<blink::xpath::Predicate>>>();
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ()->push_back(blink::MakeGarbageCollected<blink::xpath::Predicate>(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ()));
}
-#line 1272 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1295 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 24:
+ case 24: // PredicateList: PredicateList Predicate
#line 289 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > () = yystack_[1].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ();
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ()->push_back(blink::MakeGarbageCollected<blink::xpath::Predicate>(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ()));
}
-#line 1281 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1304 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 25:
+ case 25: // Predicate: '[' Expr ']'
#line 297 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[1].value.as < blink::Persistent<blink::xpath::Expression> > ();
}
-#line 1289 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1312 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 26:
+ case 26: // DescendantOrSelf: kSlashSlash
#line 304 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(Step::kDescendantOrSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
-#line 1297 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1320 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 27:
+ case 27: // AbbreviatedStep: '.'
#line 311 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(Step::kSelfAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
-#line 1305 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1328 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 28:
+ case 28: // AbbreviatedStep: kDotDot
#line 316 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Step> > () = blink::MakeGarbageCollected<Step>(Step::kParentAxis, Step::NodeTest(Step::NodeTest::kAnyNodeTest));
}
-#line 1313 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1336 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 29:
+ case 29: // PrimaryExpr: kVariableReference
#line 323 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::VariableReference>(yystack_[0].value.as < String > ());
}
-#line 1321 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1344 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 30:
+ case 30: // PrimaryExpr: '(' Expr ')'
#line 328 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[1].value.as < blink::Persistent<blink::xpath::Expression> > ();
}
-#line 1329 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1352 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 31:
+ case 31: // PrimaryExpr: kLiteral
#line 333 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::StringExpression>(yystack_[0].value.as < String > ());
}
-#line 1337 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1360 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 32:
+ case 32: // PrimaryExpr: kNumber
#line 338 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Number>(yystack_[0].value.as < String > ().ToDouble());
}
-#line 1345 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1368 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 33:
+ case 33: // PrimaryExpr: FunctionCall
#line 342 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1351 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1374 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 34:
+ case 34: // FunctionCall: kFunctionName '(' ')'
#line 347 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::xpath::CreateFunction(yystack_[2].value.as < String > ());
if (!yylhs.value.as < blink::Persistent<blink::xpath::Expression> > ())
YYABORT;
}
-#line 1361 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1384 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 35:
+ case 35: // FunctionCall: kFunctionName '(' ArgumentList ')'
#line 354 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::xpath::CreateFunction(yystack_[3].value.as < String > (), *yystack_[1].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ());
if (!yylhs.value.as < blink::Persistent<blink::xpath::Expression> > ())
YYABORT;
}
-#line 1371 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1394 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 36:
+ case 36: // ArgumentList: Argument
#line 363 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > () = blink::MakeGarbageCollected<blink::HeapVector<blink::Member<blink::xpath::Expression>>>();
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ()->push_back(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1380 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1403 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 37:
+ case 37: // ArgumentList: ArgumentList ',' Argument
#line 369 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > () = yystack_[2].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ();
yylhs.value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ()->push_back(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1389 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1412 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 38:
+ case 38: // Argument: Expr
#line 376 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1395 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1418 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 39:
+ case 39: // UnionExpr: PathExpr
#line 380 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1401 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1424 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 40:
+ case 40: // UnionExpr: UnionExpr '|' PathExpr
#line 383 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Union>();
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > ()->AddSubExpression(yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > ());
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > ()->AddSubExpression(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1411 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1434 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 41:
+ case 41: // PathExpr: LocationPath
#line 392 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ();
}
-#line 1419 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1442 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 42:
+ case 42: // PathExpr: FilterExpr
#line 396 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1425 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1448 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 43:
+ case 43: // PathExpr: FilterExpr '/' RelativeLocationPath
#line 399 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ()->SetAbsolute(true);
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Path>(yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ());
}
-#line 1434 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1457 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 44:
+ case 44: // PathExpr: FilterExpr DescendantOrSelf RelativeLocationPath
#line 405 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ()->InsertFirstStep(yystack_[1].value.as < blink::Persistent<blink::xpath::Step> > ());
yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ()->SetAbsolute(true);
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Path>(yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::LocationPath> > ());
}
-#line 1444 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1467 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 45:
+ case 45: // FilterExpr: PrimaryExpr
#line 413 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1450 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1473 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 46:
+ case 46: // FilterExpr: PrimaryExpr PredicateList
#line 416 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Filter>(yystack_[1].value.as < blink::Persistent<blink::xpath::Expression> > (), *yystack_[0].value.as < blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ());
}
-#line 1458 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1481 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 47:
+ case 47: // OrExpr: AndExpr
#line 422 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1464 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1487 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 48:
+ case 48: // OrExpr: OrExpr kOr AndExpr
#line 425 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::LogicalOp>(blink::xpath::LogicalOp::kOP_Or, yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1472 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1495 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 49:
+ case 49: // AndExpr: EqualityExpr
#line 431 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1478 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1501 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 50:
+ case 50: // AndExpr: AndExpr kAnd EqualityExpr
#line 434 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::LogicalOp>(blink::xpath::LogicalOp::kOP_And, yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1486 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1509 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 51:
+ case 51: // EqualityExpr: RelationalExpr
#line 440 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1492 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1515 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 52:
+ case 52: // EqualityExpr: EqualityExpr kEqOp RelationalExpr
#line 443 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::EqTestOp>(yystack_[1].value.as < blink::xpath::EqTestOp::Opcode > (), yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1500 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1523 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 53:
+ case 53: // RelationalExpr: AdditiveExpr
#line 449 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1506 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1529 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 54:
+ case 54: // RelationalExpr: RelationalExpr kRelOp AdditiveExpr
#line 452 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::EqTestOp>(yystack_[1].value.as < blink::xpath::EqTestOp::Opcode > (), yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1514 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1537 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 55:
+ case 55: // AdditiveExpr: MultiplicativeExpr
#line 458 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1520 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1543 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 56:
+ case 56: // AdditiveExpr: AdditiveExpr kPlus MultiplicativeExpr
#line 461 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::NumericOp>(blink::xpath::NumericOp::kOP_Add, yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1528 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1551 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 57:
+ case 57: // AdditiveExpr: AdditiveExpr kMinus MultiplicativeExpr
#line 466 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::NumericOp>(blink::xpath::NumericOp::kOP_Sub, yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1536 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1559 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 58:
+ case 58: // MultiplicativeExpr: UnaryExpr
#line 472 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1542 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1565 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 59:
+ case 59: // MultiplicativeExpr: MultiplicativeExpr kMulOp UnaryExpr
#line 475 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::NumericOp>(yystack_[1].value.as < blink::xpath::NumericOp::Opcode > (), yystack_[2].value.as < blink::Persistent<blink::xpath::Expression> > (), yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1550 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1573 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 60:
+ case 60: // UnaryExpr: UnionExpr
#line 481 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{ yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > (); }
-#line 1556 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1579 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
- case 61:
+ case 61: // UnaryExpr: kMinus UnaryExpr
#line 484 "third_party/blink/renderer/core/xml/xpath_grammar.y"
{
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > () = blink::MakeGarbageCollected<blink::xpath::Negative>();
yylhs.value.as < blink::Persistent<blink::xpath::Expression> > ()->AddSubExpression(yystack_[0].value.as < blink::Persistent<blink::xpath::Expression> > ());
}
-#line 1565 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1588 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
break;
-#line 1569 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 1592 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
default:
break;
@@ -1583,7 +1606,6 @@ namespace xpathyy {
YY_SYMBOL_PRINT ("-> $$ =", yylhs);
yypop_ (yylen);
yylen = 0;
- YY_STACK_PRINT ();
// Shift the result of the reduction.
yypush_ (YY_NULLPTR, YY_MOVE (yylhs));
@@ -1599,7 +1621,8 @@ namespace xpathyy {
if (!yyerrstatus_)
{
++yynerrs_;
- error (yysyntax_error_ (yystack_[0].state, yyla));
+ std::string msg = YY_("syntax error");
+ error (YY_MOVE (msg));
}
@@ -1609,7 +1632,7 @@ namespace xpathyy {
error, discard it. */
// Return failure if at end of input.
- if (yyla.type_get () == yyeof_)
+ if (yyla.kind () == symbol_kind::S_YYEOF)
YYABORT;
else if (!yyla.empty ())
{
@@ -1635,6 +1658,7 @@ namespace xpathyy {
this YYERROR. */
yypop_ (yylen);
yylen = 0;
+ YY_STACK_PRINT ();
goto yyerrlab1;
@@ -1643,34 +1667,36 @@ namespace xpathyy {
`-------------------------------------------------------------*/
yyerrlab1:
yyerrstatus_ = 3; // Each real token shifted decrements this.
- {
- stack_symbol_type error_token;
- for (;;)
- {
- yyn = yypact_[yystack_[0].state];
- if (!yy_pact_value_is_default_ (yyn))
- {
- yyn += yyterror_;
- if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yyterror_)
- {
- yyn = yytable_[yyn];
- if (0 < yyn)
- break;
- }
- }
+ // Pop stack until we find a state that shifts the error token.
+ for (;;)
+ {
+ yyn = yypact_[+yystack_[0].state];
+ if (!yy_pact_value_is_default_ (yyn))
+ {
+ yyn += symbol_kind::S_YYerror;
+ if (0 <= yyn && yyn <= yylast_
+ && yycheck_[yyn] == symbol_kind::S_YYerror)
+ {
+ yyn = yytable_[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
- // Pop the current state because it cannot handle the error token.
- if (yystack_.size () == 1)
- YYABORT;
+ // Pop the current state because it cannot handle the error token.
+ if (yystack_.size () == 1)
+ YYABORT;
- yy_destroy_ ("Error: popping", yystack_[0]);
- yypop_ ();
- YY_STACK_PRINT ();
- }
+ yy_destroy_ ("Error: popping", yystack_[0]);
+ yypop_ ();
+ YY_STACK_PRINT ();
+ }
+ {
+ stack_symbol_type error_token;
// Shift the error token.
- error_token.state = yyn;
+ error_token.state = state_type (yyn);
yypush_ ("Shifting", YY_MOVE (error_token));
}
goto yynewstate;
@@ -1702,6 +1728,7 @@ namespace xpathyy {
/* Do not reclaim the symbols of the rule whose action triggered
this YYABORT or YYACCEPT. */
yypop_ (yylen);
+ YY_STACK_PRINT ();
while (1 < yystack_.size ())
{
yy_destroy_ ("Cleanup: popping", yystack_[0]);
@@ -1735,12 +1762,16 @@ namespace xpathyy {
error (yyexc.what ());
}
- // Generate an error message.
- std::string
- YyParser::yysyntax_error_ (state_type, const symbol_type&) const
+#if YYDEBUG || 0
+ const char *
+ YyParser::symbol_name (symbol_kind_type yysymbol)
{
- return YY_("syntax error");
+ return yytname_[yysymbol];
}
+#endif // #if YYDEBUG || 0
+
+
+
const signed char YyParser::yypact_ninf_ = -44;
@@ -1762,7 +1793,7 @@ namespace xpathyy {
-44, 77, -44, -44
};
- const unsigned char
+ const signed char
YyParser::yydefact_[] =
{
0, 0, 16, 0, 0, 0, 31, 29, 32, 28,
@@ -1793,7 +1824,7 @@ namespace xpathyy {
30, 31, 32, 33, 34, 35, 36
};
- const unsigned char
+ const signed char
YyParser::yytable_[] =
{
37, 45, 16, 49, 52, 75, 76, 73, 2, 3,
@@ -1829,7 +1860,7 @@ namespace xpathyy {
-1, -1, 27
};
- const unsigned char
+ const signed char
YyParser::yystos_[] =
{
0, 7, 10, 11, 12, 13, 14, 15, 16, 17,
@@ -1844,7 +1875,7 @@ namespace xpathyy {
24, 28, 26, 46
};
- const unsigned char
+ const signed char
YyParser::yyr1_[] =
{
0, 30, 31, 32, 32, 33, 33, 33, 34, 34,
@@ -1856,7 +1887,7 @@ namespace xpathyy {
56, 56
};
- const unsigned char
+ const signed char
YyParser::yyr2_[] =
{
0, 2, 1, 1, 1, 1, 2, 2, 1, 3,
@@ -1871,25 +1902,27 @@ namespace xpathyy {
#if YYDEBUG
// YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- // First, the terminals, then, starting at \a yyntokens_, nonterminals.
+ // First, the terminals, then, starting at \a YYNTOKENS, nonterminals.
const char*
const YyParser::yytname_[] =
{
- "$end", "error", "$undefined", "kMulOp", "kEqOp", "kRelOp", "kPlus",
- "kMinus", "kOr", "kAnd", "kAxisName", "kNodeType", "kPI",
- "kFunctionName", "kLiteral", "kVariableReference", "kNumber", "kDotDot",
- "kSlashSlash", "kNameTest", "kXPathError", "'/'", "'@'", "'('", "')'",
- "'['", "']'", "'.'", "','", "'|'", "$accept", "Expr", "LocationPath",
- "AbsoluteLocationPath", "RelativeLocationPath", "Step", "AxisSpecifier",
- "NodeTest", "OptionalPredicateList", "PredicateList", "Predicate",
- "DescendantOrSelf", "AbbreviatedStep", "PrimaryExpr", "FunctionCall",
- "ArgumentList", "Argument", "UnionExpr", "PathExpr", "FilterExpr",
- "OrExpr", "AndExpr", "EqualityExpr", "RelationalExpr", "AdditiveExpr",
- "MultiplicativeExpr", "UnaryExpr", YY_NULLPTR
+ "\"end of file\"", "error", "\"invalid token\"", "kMulOp", "kEqOp",
+ "kRelOp", "kPlus", "kMinus", "kOr", "kAnd", "kAxisName", "kNodeType",
+ "kPI", "kFunctionName", "kLiteral", "kVariableReference", "kNumber",
+ "kDotDot", "kSlashSlash", "kNameTest", "kXPathError", "'/'", "'@'",
+ "'('", "')'", "'['", "']'", "'.'", "','", "'|'", "$accept", "Expr",
+ "LocationPath", "AbsoluteLocationPath", "RelativeLocationPath", "Step",
+ "AxisSpecifier", "NodeTest", "OptionalPredicateList", "PredicateList",
+ "Predicate", "DescendantOrSelf", "AbbreviatedStep", "PrimaryExpr",
+ "FunctionCall", "ArgumentList", "Argument", "UnionExpr", "PathExpr",
+ "FilterExpr", "OrExpr", "AndExpr", "EqualityExpr", "RelationalExpr",
+ "AdditiveExpr", "MultiplicativeExpr", "UnaryExpr", YY_NULLPTR
};
+#endif
- const unsigned short
+#if YYDEBUG
+ const short
YyParser::yyrline_[] =
{
0, 128, 128, 136, 142, 150, 155, 160, 168, 174,
@@ -1901,24 +1934,22 @@ namespace xpathyy {
481, 483
};
- // Print the state stack on the debug stream.
void
- YyParser::yystack_print_ ()
+ YyParser::yy_stack_print_ () const
{
*yycdebug_ << "Stack now";
for (stack_type::const_iterator
i = yystack_.begin (),
i_end = yystack_.end ();
i != i_end; ++i)
- *yycdebug_ << ' ' << i->state;
+ *yycdebug_ << ' ' << int (i->state);
*yycdebug_ << '\n';
}
- // Report on the debug stream that the rule \a yyrule is going to be reduced.
void
- YyParser::yy_reduce_print_ (int yyrule)
+ YyParser::yy_reduce_print_ (int yyrule) const
{
- unsigned yylno = yyrline_[yyrule];
+ int yylno = yyrline_[yyrule];
int yynrhs = yyr2_[yyrule];
// Print the symbols being reduced, and their result.
*yycdebug_ << "Reducing stack by rule " << yyrule - 1
@@ -1930,13 +1961,13 @@ namespace xpathyy {
}
#endif // YYDEBUG
- YyParser::token_number_type
+ YyParser::symbol_kind_type
YyParser::yytranslate_ (int t)
{
// YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to
// TOKEN-NUM as returned by yylex.
static
- const token_number_type
+ const signed char
translate_table[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -1968,20 +1999,20 @@ namespace xpathyy {
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20
};
- const unsigned user_token_number_max_ = 275;
- const token_number_type undef_token_ = 2;
+ // Last valid token kind.
+ const int code_max = 275;
- if (static_cast<int> (t) <= yyeof_)
- return yyeof_;
- else if (static_cast<unsigned> (t) <= user_token_number_max_)
- return translate_table[t];
+ if (t <= 0)
+ return symbol_kind::S_YYEOF;
+ else if (t <= code_max)
+ return YY_CAST (symbol_kind_type, translate_table[t]);
else
- return undef_token_;
+ return symbol_kind::S_YYUNDEF;
}
#line 69 "third_party/blink/renderer/core/xml/xpath_grammar.y"
} // xpathyy
-#line 1984 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
+#line 2015 "third_party/blink/renderer/core/xml/xpath_grammar_generated.cc"
#line 490 "third_party/blink/renderer/core/xml/xpath_grammar.y"
diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.h b/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.h
index b8469fb1d05..f69f24eebf1 100644
--- a/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.h
+++ b/chromium/third_party/blink/renderer/core/xml/xpath_grammar_generated.h
@@ -1,11 +1,11 @@
// clang-format off
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_XML_XPATH_GRAMMAR_GENERATED_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_XML_XPATH_GRAMMAR_GENERATED_H_
-// A Bison parser, made by GNU Bison 3.4.2.
+// A Bison parser, made by GNU Bison 3.7.4.
// Skeleton interface for Bison LALR(1) parsers in C++
-// Copyright (C) 2002-2015, 2018-2019 Free Software Foundation, Inc.
+// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -41,19 +41,20 @@
// C++ LALR(1) parser skeleton written by Akim Demaille.
-// Undocumented macros, especially those whose name start with YY_,
-// are private implementation details. Do not rely on them.
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_. They are
+// private implementation details that can be changed or removed.
#ifndef YY_YY_THIRD_PARTY_BLINK_RENDERER_CORE_XML_XPATH_GRAMMAR_GENERATED_HH_INCLUDED
# define YY_YY_THIRD_PARTY_BLINK_RENDERER_CORE_XML_XPATH_GRAMMAR_GENERATED_HH_INCLUDED
-// // "%code requires" blocks.
+// "%code requires" blocks.
#line 46 "third_party/blink/renderer/core/xml/xpath_grammar.y"
#include "third_party/blink/renderer/platform/heap/persistent.h"
-#line 54 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
+#line 55 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
# include <cstdlib> // std::abort
@@ -100,28 +101,21 @@
#endif
-#ifndef YYASSERT
-# include <cassert>
-# define YYASSERT assert
-#endif
-
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__ \
- && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
- || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
# else
-# define YY_ATTRIBUTE(Spec) /* empty */
+# define YY_ATTRIBUTE_PURE
# endif
#endif
-#ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
-#endif
-
#ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
@@ -133,11 +127,11 @@
#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
/* Suppress an incorrect diagnostic about yylval being uninitialized. */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
- _Pragma ("GCC diagnostic push") \
- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
_Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
_Pragma ("GCC diagnostic pop")
#else
# define YY_INITIAL_VALUE(Value) Value
@@ -150,6 +144,27 @@
# define YY_INITIAL_VALUE(Value) /* Nothing. */
#endif
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
# ifndef YY_NULLPTR
# if defined __cplusplus
# if 201103L <= __cplusplus
@@ -169,7 +184,7 @@
#line 69 "third_party/blink/renderer/core/xml/xpath_grammar.y"
namespace xpathyy {
-#line 170 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
+#line 185 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
@@ -199,10 +214,16 @@ namespace xpathyy {
template <typename T>
semantic_type (YY_RVREF (T) t)
{
- YYASSERT (sizeof (T) <= size);
new (yyas_<T> ()) T (YY_MOVE (t));
}
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ semantic_type (const self_type&) = delete;
+ /// Non copyable.
+ self_type& operator= (const self_type&) = delete;
+#endif
+
/// Destruction, allowed only if empty.
~semantic_type () YY_NOEXCEPT
{}
@@ -326,9 +347,12 @@ namespace xpathyy {
}
private:
- /// Prohibit blind copies.
- self_type& operator= (const self_type&);
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
semantic_type (const self_type&);
+ /// Non copyable.
+ self_type& operator= (const self_type&);
+#endif
/// Accessor to raw memory as \a T.
template <typename T>
@@ -440,48 +464,121 @@ namespace xpathyy {
~syntax_error () YY_NOEXCEPT YY_NOTHROW;
};
- /// Tokens.
+ /// Token kinds.
struct token
{
- enum yytokentype
+ enum token_kind_type
{
- kMulOp = 258,
- kEqOp = 259,
- kRelOp = 260,
- kPlus = 261,
- kMinus = 262,
- kOr = 263,
- kAnd = 264,
- kAxisName = 265,
- kNodeType = 266,
- kPI = 267,
- kFunctionName = 268,
- kLiteral = 269,
- kVariableReference = 270,
- kNumber = 271,
- kDotDot = 272,
- kSlashSlash = 273,
- kNameTest = 274,
- kXPathError = 275
+ YYEMPTY = -2,
+ YYEOF = 0, // "end of file"
+ YYerror = 256, // error
+ YYUNDEF = 257, // "invalid token"
+ kMulOp = 258, // kMulOp
+ kEqOp = 259, // kEqOp
+ kRelOp = 260, // kRelOp
+ kPlus = 261, // kPlus
+ kMinus = 262, // kMinus
+ kOr = 263, // kOr
+ kAnd = 264, // kAnd
+ kAxisName = 265, // kAxisName
+ kNodeType = 266, // kNodeType
+ kPI = 267, // kPI
+ kFunctionName = 268, // kFunctionName
+ kLiteral = 269, // kLiteral
+ kVariableReference = 270, // kVariableReference
+ kNumber = 271, // kNumber
+ kDotDot = 272, // kDotDot
+ kSlashSlash = 273, // kSlashSlash
+ kNameTest = 274, // kNameTest
+ kXPathError = 275 // kXPathError
};
+ /// Backward compatibility alias (Bison 3.6).
+ typedef token_kind_type yytokentype;
};
- /// (External) token type, as returned by yylex.
- typedef token::yytokentype token_type;
+ /// Token kind, as returned by yylex.
+ typedef token::yytokentype token_kind_type;
+
+ /// Backward compatibility alias (Bison 3.6).
+ typedef token_kind_type token_type;
- /// Symbol type: an internal symbol number.
- typedef int symbol_number_type;
+ /// Symbol kinds.
+ struct symbol_kind
+ {
+ enum symbol_kind_type
+ {
+ YYNTOKENS = 30, ///< Number of tokens.
+ S_YYEMPTY = -2,
+ S_YYEOF = 0, // "end of file"
+ S_YYerror = 1, // error
+ S_YYUNDEF = 2, // "invalid token"
+ S_kMulOp = 3, // kMulOp
+ S_kEqOp = 4, // kEqOp
+ S_kRelOp = 5, // kRelOp
+ S_kPlus = 6, // kPlus
+ S_kMinus = 7, // kMinus
+ S_kOr = 8, // kOr
+ S_kAnd = 9, // kAnd
+ S_kAxisName = 10, // kAxisName
+ S_kNodeType = 11, // kNodeType
+ S_kPI = 12, // kPI
+ S_kFunctionName = 13, // kFunctionName
+ S_kLiteral = 14, // kLiteral
+ S_kVariableReference = 15, // kVariableReference
+ S_kNumber = 16, // kNumber
+ S_kDotDot = 17, // kDotDot
+ S_kSlashSlash = 18, // kSlashSlash
+ S_kNameTest = 19, // kNameTest
+ S_kXPathError = 20, // kXPathError
+ S_21_ = 21, // '/'
+ S_22_ = 22, // '@'
+ S_23_ = 23, // '('
+ S_24_ = 24, // ')'
+ S_25_ = 25, // '['
+ S_26_ = 26, // ']'
+ S_27_ = 27, // '.'
+ S_28_ = 28, // ','
+ S_29_ = 29, // '|'
+ S_YYACCEPT = 30, // $accept
+ S_Expr = 31, // Expr
+ S_LocationPath = 32, // LocationPath
+ S_AbsoluteLocationPath = 33, // AbsoluteLocationPath
+ S_RelativeLocationPath = 34, // RelativeLocationPath
+ S_Step = 35, // Step
+ S_AxisSpecifier = 36, // AxisSpecifier
+ S_NodeTest = 37, // NodeTest
+ S_OptionalPredicateList = 38, // OptionalPredicateList
+ S_PredicateList = 39, // PredicateList
+ S_Predicate = 40, // Predicate
+ S_DescendantOrSelf = 41, // DescendantOrSelf
+ S_AbbreviatedStep = 42, // AbbreviatedStep
+ S_PrimaryExpr = 43, // PrimaryExpr
+ S_FunctionCall = 44, // FunctionCall
+ S_ArgumentList = 45, // ArgumentList
+ S_Argument = 46, // Argument
+ S_UnionExpr = 47, // UnionExpr
+ S_PathExpr = 48, // PathExpr
+ S_FilterExpr = 49, // FilterExpr
+ S_OrExpr = 50, // OrExpr
+ S_AndExpr = 51, // AndExpr
+ S_EqualityExpr = 52, // EqualityExpr
+ S_RelationalExpr = 53, // RelationalExpr
+ S_AdditiveExpr = 54, // AdditiveExpr
+ S_MultiplicativeExpr = 55, // MultiplicativeExpr
+ S_UnaryExpr = 56 // UnaryExpr
+ };
+ };
- /// The symbol type number to denote an empty symbol.
- enum { empty_symbol = -2 };
+ /// (Internal) symbol kind.
+ typedef symbol_kind::symbol_kind_type symbol_kind_type;
- /// Internal symbol number for tokens (subsumed by symbol_number_type).
- typedef unsigned char token_number_type;
+ /// The number of tokens.
+ static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS;
/// A complete symbol.
///
- /// Expects its Base type to provide access to the symbol type
- /// via type_get ().
+ /// Expects its Base type to provide access to the symbol kind
+ /// via kind ().
///
/// Provide access to semantic value.
template <typename Base>
@@ -497,13 +594,90 @@ namespace xpathyy {
#if 201103L <= YY_CPLUSPLUS
/// Move constructor.
- basic_symbol (basic_symbol&& that);
+ basic_symbol (basic_symbol&& that)
+ : Base (std::move (that))
+ , value ()
+ {
+ switch (this->kind ())
+ {
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
+ value.move< String > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_ArgumentList: // ArgumentList
+ value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
+ value.move< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
+ value.move< blink::Persistent<blink::xpath::Expression> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
+ value.move< blink::Persistent<blink::xpath::LocationPath> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_NodeTest: // NodeTest
+ value.move< blink::Persistent<blink::xpath::Step::NodeTest> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
+ value.move< blink::Persistent<blink::xpath::Step> > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
+ value.move< blink::xpath::EqTestOp::Opcode > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_kMulOp: // kMulOp
+ value.move< blink::xpath::NumericOp::Opcode > (std::move (that.value));
+ break;
+
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
+ value.move< blink::xpath::Step::Axis > (std::move (that.value));
+ break;
+
+ default:
+ break;
+ }
+
+ }
#endif
/// Copy constructor.
basic_symbol (const basic_symbol& that);
- /// Constructor for valueless symbols, and symbols from each type.
+ /// Constructors for typed symbols.
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t)
: Base (t)
@@ -513,6 +687,7 @@ namespace xpathyy {
: Base (t)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, String&& v)
: Base (t)
@@ -524,6 +699,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>>&& v)
: Base (t)
@@ -535,6 +711,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>>&& v)
: Base (t)
@@ -546,6 +723,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::xpath::Expression>&& v)
: Base (t)
@@ -557,6 +735,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::xpath::LocationPath>&& v)
: Base (t)
@@ -568,6 +747,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::xpath::Step::NodeTest>&& v)
: Base (t)
@@ -579,6 +759,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::Persistent<blink::xpath::Step>&& v)
: Base (t)
@@ -590,6 +771,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::xpath::EqTestOp::Opcode&& v)
: Base (t)
@@ -601,6 +783,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::xpath::NumericOp::Opcode&& v)
: Base (t)
@@ -612,6 +795,7 @@ namespace xpathyy {
, value (v)
{}
#endif
+
#if 201103L <= YY_CPLUSPLUS
basic_symbol (typename Base::kind_type t, blink::xpath::Step::Axis&& v)
: Base (t)
@@ -634,82 +818,82 @@ namespace xpathyy {
void clear ()
{
// User destructor.
- symbol_number_type yytype = this->type_get ();
+ symbol_kind_type yykind = this->kind ();
basic_symbol<Base>& yysym = *this;
(void) yysym;
- switch (yytype)
+ switch (yykind)
{
default:
break;
}
- // Type destructor.
-switch (yytype)
+ // Value type destructor.
+switch (yykind)
{
- case 11: // kNodeType
- case 12: // kPI
- case 13: // kFunctionName
- case 14: // kLiteral
- case 15: // kVariableReference
- case 16: // kNumber
- case 19: // kNameTest
+ case symbol_kind::S_kNodeType: // kNodeType
+ case symbol_kind::S_kPI: // kPI
+ case symbol_kind::S_kFunctionName: // kFunctionName
+ case symbol_kind::S_kLiteral: // kLiteral
+ case symbol_kind::S_kVariableReference: // kVariableReference
+ case symbol_kind::S_kNumber: // kNumber
+ case symbol_kind::S_kNameTest: // kNameTest
value.template destroy< String > ();
break;
- case 45: // ArgumentList
+ case symbol_kind::S_ArgumentList: // ArgumentList
value.template destroy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Expression>>> > ();
break;
- case 38: // OptionalPredicateList
- case 39: // PredicateList
+ case symbol_kind::S_OptionalPredicateList: // OptionalPredicateList
+ case symbol_kind::S_PredicateList: // PredicateList
value.template destroy< blink::Persistent<blink::HeapVector<blink::Member<blink::xpath::Predicate>>> > ();
break;
- case 31: // Expr
- case 40: // Predicate
- case 43: // PrimaryExpr
- case 44: // FunctionCall
- case 46: // Argument
- case 47: // UnionExpr
- case 48: // PathExpr
- case 49: // FilterExpr
- case 50: // OrExpr
- case 51: // AndExpr
- case 52: // EqualityExpr
- case 53: // RelationalExpr
- case 54: // AdditiveExpr
- case 55: // MultiplicativeExpr
- case 56: // UnaryExpr
+ case symbol_kind::S_Expr: // Expr
+ case symbol_kind::S_Predicate: // Predicate
+ case symbol_kind::S_PrimaryExpr: // PrimaryExpr
+ case symbol_kind::S_FunctionCall: // FunctionCall
+ case symbol_kind::S_Argument: // Argument
+ case symbol_kind::S_UnionExpr: // UnionExpr
+ case symbol_kind::S_PathExpr: // PathExpr
+ case symbol_kind::S_FilterExpr: // FilterExpr
+ case symbol_kind::S_OrExpr: // OrExpr
+ case symbol_kind::S_AndExpr: // AndExpr
+ case symbol_kind::S_EqualityExpr: // EqualityExpr
+ case symbol_kind::S_RelationalExpr: // RelationalExpr
+ case symbol_kind::S_AdditiveExpr: // AdditiveExpr
+ case symbol_kind::S_MultiplicativeExpr: // MultiplicativeExpr
+ case symbol_kind::S_UnaryExpr: // UnaryExpr
value.template destroy< blink::Persistent<blink::xpath::Expression> > ();
break;
- case 32: // LocationPath
- case 33: // AbsoluteLocationPath
- case 34: // RelativeLocationPath
+ case symbol_kind::S_LocationPath: // LocationPath
+ case symbol_kind::S_AbsoluteLocationPath: // AbsoluteLocationPath
+ case symbol_kind::S_RelativeLocationPath: // RelativeLocationPath
value.template destroy< blink::Persistent<blink::xpath::LocationPath> > ();
break;
- case 37: // NodeTest
+ case symbol_kind::S_NodeTest: // NodeTest
value.template destroy< blink::Persistent<blink::xpath::Step::NodeTest> > ();
break;
- case 35: // Step
- case 41: // DescendantOrSelf
- case 42: // AbbreviatedStep
+ case symbol_kind::S_Step: // Step
+ case symbol_kind::S_DescendantOrSelf: // DescendantOrSelf
+ case symbol_kind::S_AbbreviatedStep: // AbbreviatedStep
value.template destroy< blink::Persistent<blink::xpath::Step> > ();
break;
- case 4: // kEqOp
- case 5: // kRelOp
+ case symbol_kind::S_kEqOp: // kEqOp
+ case symbol_kind::S_kRelOp: // kRelOp
value.template destroy< blink::xpath::EqTestOp::Opcode > ();
break;
- case 3: // kMulOp
+ case symbol_kind::S_kMulOp: // kMulOp
value.template destroy< blink::xpath::NumericOp::Opcode > ();
break;
- case 10: // kAxisName
- case 36: // AxisSpecifier
+ case symbol_kind::S_kAxisName: // kAxisName
+ case symbol_kind::S_AxisSpecifier: // AxisSpecifier
value.template destroy< blink::xpath::Step::Axis > ();
break;
@@ -720,6 +904,18 @@ switch (yytype)
Base::clear ();
}
+#if YYDEBUG || 0
+ /// The user-facing name of this symbol.
+ const char *name () const YY_NOEXCEPT
+ {
+ return YyParser::symbol_name (this->kind ());
+ }
+#endif // #if YYDEBUG || 0
+
+
+ /// Backward compatibility (Bison 3.6).
+ symbol_kind_type type_get () const YY_NOEXCEPT;
+
/// Whether empty.
bool empty () const YY_NOEXCEPT;
@@ -737,49 +933,51 @@ switch (yytype)
};
/// Type access provider for token (enum) based symbols.
- struct by_type
+ struct by_kind
{
/// Default constructor.
- by_type ();
+ by_kind ();
#if 201103L <= YY_CPLUSPLUS
/// Move constructor.
- by_type (by_type&& that);
+ by_kind (by_kind&& that);
#endif
/// Copy constructor.
- by_type (const by_type& that);
+ by_kind (const by_kind& that);
- /// The symbol type as needed by the constructor.
- typedef token_type kind_type;
+ /// The symbol kind as needed by the constructor.
+ typedef token_kind_type kind_type;
/// Constructor from (external) token numbers.
- by_type (kind_type t);
+ by_kind (kind_type t);
/// Record that this symbol is empty.
void clear ();
- /// Steal the symbol type from \a that.
- void move (by_type& that);
+ /// Steal the symbol kind from \a that.
+ void move (by_kind& that);
/// The (internal) type number (corresponding to \a type).
/// \a empty when empty.
- symbol_number_type type_get () const YY_NOEXCEPT;
+ symbol_kind_type kind () const YY_NOEXCEPT;
- /// The token.
- token_type token () const YY_NOEXCEPT;
+ /// Backward compatibility (Bison 3.6).
+ symbol_kind_type type_get () const YY_NOEXCEPT;
- /// The symbol type.
- /// \a empty_symbol when empty.
- /// An int, not token_number_type, to be able to store empty_symbol.
- int type;
+ /// The symbol kind.
+ /// \a S_YYEMPTY when empty.
+ symbol_kind_type kind_;
};
+ /// Backward compatibility for a private implementation detail (Bison 3.6).
+ typedef by_kind by_type;
+
/// "External" symbols: returned by the scanner.
- struct symbol_type : basic_symbol<by_type>
+ struct symbol_type : basic_symbol<by_kind>
{
/// Superclass.
- typedef basic_symbol<by_type> super_type;
+ typedef basic_symbol<by_kind> super_type;
/// Empty symbol.
symbol_type () {}
@@ -788,74 +986,56 @@ switch (yytype)
#if 201103L <= YY_CPLUSPLUS
symbol_type (int tok)
: super_type(token_type (tok))
- {
- YYASSERT (tok == 0 || tok == token::kPlus || tok == token::kMinus || tok == token::kOr || tok == token::kAnd || tok == token::kDotDot || tok == token::kSlashSlash || tok == token::kXPathError || tok == 47 || tok == 64 || tok == 40 || tok == 41 || tok == 91 || tok == 93 || tok == 46 || tok == 44 || tok == 124);
- }
#else
symbol_type (int tok)
: super_type(token_type (tok))
- {
- YYASSERT (tok == 0 || tok == token::kPlus || tok == token::kMinus || tok == token::kOr || tok == token::kAnd || tok == token::kDotDot || tok == token::kSlashSlash || tok == token::kXPathError || tok == 47 || tok == 64 || tok == 40 || tok == 41 || tok == 91 || tok == 93 || tok == 46 || tok == 44 || tok == 124);
- }
#endif
+ {}
#if 201103L <= YY_CPLUSPLUS
symbol_type (int tok, String v)
: super_type(token_type (tok), std::move (v))
- {
- YYASSERT (tok == token::kNodeType || tok == token::kPI || tok == token::kFunctionName || tok == token::kLiteral || tok == token::kVariableReference || tok == token::kNumber || tok == token::kNameTest);
- }
#else
symbol_type (int tok, const String& v)
: super_type(token_type (tok), v)
- {
- YYASSERT (tok == token::kNodeType || tok == token::kPI || tok == token::kFunctionName || tok == token::kLiteral || tok == token::kVariableReference || tok == token::kNumber || tok == token::kNameTest);
- }
#endif
+ {}
#if 201103L <= YY_CPLUSPLUS
symbol_type (int tok, blink::xpath::EqTestOp::Opcode v)
: super_type(token_type (tok), std::move (v))
- {
- YYASSERT (tok == token::kEqOp || tok == token::kRelOp);
- }
#else
symbol_type (int tok, const blink::xpath::EqTestOp::Opcode& v)
: super_type(token_type (tok), v)
- {
- YYASSERT (tok == token::kEqOp || tok == token::kRelOp);
- }
#endif
+ {}
#if 201103L <= YY_CPLUSPLUS
symbol_type (int tok, blink::xpath::NumericOp::Opcode v)
: super_type(token_type (tok), std::move (v))
- {
- YYASSERT (tok == token::kMulOp);
- }
#else
symbol_type (int tok, const blink::xpath::NumericOp::Opcode& v)
: super_type(token_type (tok), v)
- {
- YYASSERT (tok == token::kMulOp);
- }
#endif
+ {}
#if 201103L <= YY_CPLUSPLUS
symbol_type (int tok, blink::xpath::Step::Axis v)
: super_type(token_type (tok), std::move (v))
- {
- YYASSERT (tok == token::kAxisName);
- }
#else
symbol_type (int tok, const blink::xpath::Step::Axis& v)
: super_type(token_type (tok), v)
- {
- YYASSERT (tok == token::kAxisName);
- }
#endif
+ {}
};
/// Build a parser object.
YyParser (blink::xpath::Parser* parser__yyarg);
virtual ~YyParser ();
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ YyParser (const YyParser&) = delete;
+ /// Non copyable.
+ YyParser& operator= (const YyParser&) = delete;
+#endif
+
/// Parse. An alias for parse ().
/// \returns 0 iff parsing succeeded.
int operator() ();
@@ -885,10 +1065,62 @@ switch (yytype)
/// Report a syntax error.
void error (const syntax_error& err);
+#if YYDEBUG || 0
+ /// The user-facing name of the symbol whose (internal) number is
+ /// YYSYMBOL. No bounds checking.
+ static const char *symbol_name (symbol_kind_type yysymbol);
+#endif // #if YYDEBUG || 0
+
+
// Implementation of make_symbol for each symbol type.
#if 201103L <= YY_CPLUSPLUS
static
symbol_type
+ make_YYEOF ()
+ {
+ return symbol_type (token::YYEOF);
+ }
+#else
+ static
+ symbol_type
+ make_YYEOF ()
+ {
+ return symbol_type (token::YYEOF);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_YYerror ()
+ {
+ return symbol_type (token::YYerror);
+ }
+#else
+ static
+ symbol_type
+ make_YYerror ()
+ {
+ return symbol_type (token::YYerror);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
+ make_YYUNDEF ()
+ {
+ return symbol_type (token::YYUNDEF);
+ }
+#else
+ static
+ symbol_type
+ make_YYUNDEF ()
+ {
+ return symbol_type (token::YYUNDEF);
+ }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+ static
+ symbol_type
make_kMulOp (blink::xpath::NumericOp::Opcode v)
{
return symbol_type (token::kMulOp, std::move (v));
@@ -1159,23 +1391,21 @@ switch (yytype)
private:
- /// This class is not copyable.
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
YyParser (const YyParser&);
+ /// Non copyable.
YyParser& operator= (const YyParser&);
+#endif
- /// State numbers.
- typedef int state_type;
- /// Generate an error message.
- /// \param yystate the state where the error occurred.
- /// \param yyla the lookahead token.
- virtual std::string yysyntax_error_ (state_type yystate,
- const symbol_type& yyla) const;
+ /// Stored state numbers (used for stacks).
+ typedef signed char state_type;
/// Compute post-reduction state.
/// \param yystate the current state
/// \param yysym the nonterminal to push on the stack
- state_type yy_lr_goto_state_ (state_type yystate, int yysym);
+ static state_type yy_lr_goto_state_ (state_type yystate, int yysym);
/// Whether the given \c yypact_ value indicates a defaulted state.
/// \param yyvalue the value to check
@@ -1188,60 +1418,65 @@ switch (yytype)
static const signed char yypact_ninf_;
static const signed char yytable_ninf_;
- /// Convert a scanner token number \a t to a symbol number.
- static token_number_type yytranslate_ (int t);
+ /// Convert a scanner token kind \a t to a symbol kind.
+ /// In theory \a t should be a token_kind_type, but character literals
+ /// are valid, yet not members of the token_type enum.
+ static symbol_kind_type yytranslate_ (int t);
+
+#if YYDEBUG || 0
+ /// For a symbol, its name in clear.
+ static const char* const yytname_[];
+#endif // #if YYDEBUG || 0
+
// Tables.
- // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- // STATE-NUM.
- static const signed char yypact_[];
+ // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ // STATE-NUM.
+ static const signed char yypact_[];
- // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
- // Performed when YYTABLE does not specify something else to do. Zero
- // means the default is an error.
- static const unsigned char yydefact_[];
+ // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ // Performed when YYTABLE does not specify something else to do. Zero
+ // means the default is an error.
+ static const signed char yydefact_[];
- // YYPGOTO[NTERM-NUM].
- static const signed char yypgoto_[];
+ // YYPGOTO[NTERM-NUM].
+ static const signed char yypgoto_[];
- // YYDEFGOTO[NTERM-NUM].
- static const signed char yydefgoto_[];
+ // YYDEFGOTO[NTERM-NUM].
+ static const signed char yydefgoto_[];
- // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
- // positive, shift that token. If negative, reduce the rule whose
- // number is the opposite. If YYTABLE_NINF, syntax error.
- static const unsigned char yytable_[];
+ // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ // positive, shift that token. If negative, reduce the rule whose
+ // number is the opposite. If YYTABLE_NINF, syntax error.
+ static const signed char yytable_[];
- static const signed char yycheck_[];
+ static const signed char yycheck_[];
- // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- // symbol of state STATE-NUM.
- static const unsigned char yystos_[];
+ // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ // symbol of state STATE-NUM.
+ static const signed char yystos_[];
- // YYR1[YYN] -- Symbol number of symbol that rule YYN derives.
- static const unsigned char yyr1_[];
+ // YYR1[YYN] -- Symbol number of symbol that rule YYN derives.
+ static const signed char yyr1_[];
- // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.
- static const unsigned char yyr2_[];
+ // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.
+ static const signed char yyr2_[];
#if YYDEBUG
- /// For a symbol, its name in clear.
- static const char* const yytname_[];
-
- // YYRLINE[YYN] -- Source line where rule number YYN was defined.
- static const unsigned short yyrline_[];
+ // YYRLINE[YYN] -- Source line where rule number YYN was defined.
+ static const short yyrline_[];
/// Report on the debug stream that the rule \a r is going to be reduced.
- virtual void yy_reduce_print_ (int r);
+ virtual void yy_reduce_print_ (int r) const;
/// Print the state stack on the debug stream.
- virtual void yystack_print_ ();
+ virtual void yy_stack_print_ () const;
/// Debugging level.
int yydebug_;
/// Debug stream.
std::ostream* yycdebug_;
- /// \brief Display a symbol type, value and location.
+ /// \brief Display a symbol kind, value and location.
/// \param yyo The output stream.
/// \param yysym The symbol.
template <typename Base>
@@ -1262,7 +1497,7 @@ switch (yytype)
/// Default constructor.
by_state () YY_NOEXCEPT;
- /// The symbol type as needed by the constructor.
+ /// The symbol kind as needed by the constructor.
typedef state_type kind_type;
/// Constructor.
@@ -1274,15 +1509,16 @@ switch (yytype)
/// Record that this symbol is empty.
void clear () YY_NOEXCEPT;
- /// Steal the symbol type from \a that.
+ /// Steal the symbol kind from \a that.
void move (by_state& that);
- /// The (internal) type number (corresponding to \a state).
- /// \a empty_symbol when empty.
- symbol_number_type type_get () const YY_NOEXCEPT;
+ /// The symbol kind (corresponding to \a state).
+ /// \a symbol_kind::S_YYEMPTY when empty.
+ symbol_kind_type kind () const YY_NOEXCEPT;
/// The state number used to denote an empty symbol.
- enum { empty_state = -1 };
+ /// We use the initial state, as it does not have a value.
+ enum { empty_state = 0 };
/// The state.
/// \a empty when empty.
@@ -1304,6 +1540,10 @@ switch (yytype)
/// Assignment, needed by push_back by some old implementations.
/// Moves the contents of that.
stack_symbol_type& operator= (stack_symbol_type& that);
+
+ /// Assignment, needed by push_back by other implementations.
+ /// Needed by some other old implementations.
+ stack_symbol_type& operator= (const stack_symbol_type& that);
#endif
};
@@ -1313,48 +1553,38 @@ switch (yytype)
{
public:
// Hide our reversed order.
- typedef typename S::reverse_iterator iterator;
- typedef typename S::const_reverse_iterator const_iterator;
+ typedef typename S::iterator iterator;
+ typedef typename S::const_iterator const_iterator;
typedef typename S::size_type size_type;
+ typedef typename std::ptrdiff_t index_type;
stack (size_type n = 200)
: seq_ (n)
{}
- /// Random access.
- ///
- /// Index 0 returns the topmost element.
- T&
- operator[] (size_type i)
- {
- return seq_[size () - 1 - i];
- }
-
- /// Random access.
- ///
- /// Index 0 returns the topmost element.
- T&
- operator[] (int i)
- {
- return operator[] (size_type (i));
- }
+#if 201103L <= YY_CPLUSPLUS
+ /// Non copyable.
+ stack (const stack&) = delete;
+ /// Non copyable.
+ stack& operator= (const stack&) = delete;
+#endif
/// Random access.
///
/// Index 0 returns the topmost element.
const T&
- operator[] (size_type i) const
+ operator[] (index_type i) const
{
- return seq_[size () - 1 - i];
+ return seq_[size_type (size () - 1 - i)];
}
/// Random access.
///
/// Index 0 returns the topmost element.
- const T&
- operator[] (int i) const
+ T&
+ operator[] (index_type i)
{
- return operator[] (size_type (i));
+ return seq_[size_type (size () - 1 - i)];
}
/// Steal the contents of \a t.
@@ -1369,7 +1599,7 @@ switch (yytype)
/// Pop elements from the stack.
void
- pop (int n = 1) YY_NOEXCEPT
+ pop (std::ptrdiff_t n = 1) YY_NOEXCEPT
{
for (; 0 < n; --n)
seq_.pop_back ();
@@ -1383,49 +1613,53 @@ switch (yytype)
}
/// Number of elements on the stack.
- size_type
+ index_type
size () const YY_NOEXCEPT
{
- return seq_.size ();
+ return index_type (seq_.size ());
}
/// Iterator on top of the stack (going downwards).
const_iterator
begin () const YY_NOEXCEPT
{
- return seq_.rbegin ();
+ return seq_.begin ();
}
/// Bottom of the stack.
const_iterator
end () const YY_NOEXCEPT
{
- return seq_.rend ();
+ return seq_.end ();
}
/// Present a slice of the top of a stack.
class slice
{
public:
- slice (const stack& stack, int range)
+ slice (const stack& stack, index_type range)
: stack_ (stack)
, range_ (range)
{}
const T&
- operator[] (int i) const
+ operator[] (index_type i) const
{
return stack_[range_ - i];
}
private:
const stack& stack_;
- int range_;
+ index_type range_;
};
private:
+#if YY_CPLUSPLUS < 201103L
+ /// Non copyable.
stack (const stack&);
+ /// Non copyable.
stack& operator= (const stack&);
+#endif
/// The wrapped container.
S seq_;
};
@@ -1458,25 +1692,21 @@ switch (yytype)
/// Constants.
enum
{
- yyeof_ = 0,
yylast_ = 122, ///< Last index in yytable_.
yynnts_ = 27, ///< Number of nonterminal symbols.
- yyfinal_ = 47, ///< Termination state number.
- yyterror_ = 1,
- yyerrcode_ = 256,
- yyntokens_ = 30 ///< Number of tokens.
+ yyfinal_ = 47 ///< Termination state number.
};
// User arguments.
blink::xpath::Parser* parser_;
+
};
#line 69 "third_party/blink/renderer/core/xml/xpath_grammar.y"
} // xpathyy
-#line 1476 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
-
+#line 1707 "third_party/blink/renderer/core/xml/xpath_grammar_generated.h"
diff --git a/chromium/third_party/blink/renderer/core/xml/xslt_processor.cc b/chromium/third_party/blink/renderer/core/xml/xslt_processor.cc
index 1549d0a44e6..224e33308ff 100644
--- a/chromium/third_party/blink/renderer/core/xml/xslt_processor.cc
+++ b/chromium/third_party/blink/renderer/core/xml/xslt_processor.cc
@@ -88,8 +88,10 @@ Document* XSLTProcessor::CreateDocumentFromSource(
}
if (frame) {
- auto params = std::make_unique<WebNavigationParams>();
- params->url = url;
+ auto* previous_document_loader = frame->Loader().GetDocumentLoader();
+ DCHECK(previous_document_loader);
+ std::unique_ptr<WebNavigationParams> params =
+ previous_document_loader->CreateWebNavigationParamsToCloneDocument();
WebNavigationParams::FillStaticResponse(
params.get(), mime_type,
source_encoding.IsEmpty() ? "UTF-8" : source_encoding,
diff --git a/chromium/third_party/blink/renderer/core/xml/xslt_processor.idl b/chromium/third_party/blink/renderer/core/xml/xslt_processor.idl
index 6217fa81601..d34ea84293a 100644
--- a/chromium/third_party/blink/renderer/core/xml/xslt_processor.idl
+++ b/chromium/third_party/blink/renderer/core/xml/xslt_processor.idl
@@ -39,8 +39,8 @@
void importStylesheet(Node style);
// TODO(foolip): In Gecko, the transformTo*() methods throw an exception in
// case of error instead of returning null.
- [CustomElementCallbacks] DocumentFragment? transformToFragment(Node source, Document output);
- [CustomElementCallbacks] Document? transformToDocument(Node source);
+ DocumentFragment? transformToFragment(Node source, Document output);
+ Document? transformToDocument(Node source);
// TODO(foolip): In Gecko, it's possible to set and get back any parameter
// value, not just DOMString.
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/DIR_METADATA b/chromium/third_party/blink/renderer/core/xmlhttprequest/DIR_METADATA
new file mode 100644
index 00000000000..4a6576d882e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Network>XHR"
+}
+
+team_email: "blink-network-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/OWNERS b/chromium/third_party/blink/renderer/core/xmlhttprequest/OWNERS
index aac34a8eaf9..99b341d28b4 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/OWNERS
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/OWNERS
@@ -1,5 +1,2 @@
kouhei@chromium.org
yhirano@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>XHR
diff --git a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 72054a48a15..92c2cff30af 100644
--- a/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/chromium/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -92,7 +92,6 @@
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
-#include "third_party/blink/renderer/platform/network/network_log.h"
#include "third_party/blink/renderer/platform/network/parsed_content_type.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -349,7 +348,7 @@ void XMLHttpRequest::InitResponseDocument() {
.WithURL(response_.ResponseUrl());
if (is_html) {
response_document_ = MakeGarbageCollected<HTMLDocument>(init);
- response_document_->setAllowDeclarativeShadowRoot(false);
+ response_document_->setAllowDeclarativeShadowRoots(false);
} else
response_document_ = MakeGarbageCollected<XMLDocument>(init);
@@ -639,8 +638,8 @@ void XMLHttpRequest::open(const AtomicString& method,
const KURL& url,
bool async,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " open(" << method << ", " << url.ElidedString()
- << ", " << async << ")";
+ DVLOG(1) << this << " open(" << method << ", " << url.ElidedString() << ", "
+ << async << ")";
DCHECK(ValidateOpenArguments(method, url, exception_state));
@@ -731,14 +730,27 @@ bool XMLHttpRequest::InitSend(ExceptionState& exception_state) {
}
if (!async_) {
- if (GetExecutionContext()->IsWindow() &&
- !GetExecutionContext()->IsFeatureEnabled(
- mojom::blink::FeaturePolicyFeature::kSyncXHR,
- ReportOptions::kReportOnFailure,
- "Synchronous requests are disabled by Feature Policy.")) {
- HandleNetworkError();
- ThrowForLoadFailureIfNeeded(exception_state, String());
- return false;
+ if (GetExecutionContext()->IsWindow()) {
+ bool sync_xhr_disabled_by_feature_policy =
+ !GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kSyncXHR,
+ ReportOptions::kReportOnFailure,
+ "Synchronous requests are disabled by permissions policy.");
+
+ bool sync_xhr_disabled_by_document_policy =
+ !GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::DocumentPolicyFeature::kSyncXHR,
+ ReportOptions::kReportOnFailure,
+ "Synchronous requests are disabled by document policy.");
+
+ // SyncXHR can be controlled by either feature policy or document policy
+ // during the migration period. See crbug.com/1146505.
+ if (sync_xhr_disabled_by_feature_policy ||
+ sync_xhr_disabled_by_document_policy) {
+ HandleNetworkError();
+ ThrowForLoadFailureIfNeeded(exception_state, String());
+ return false;
+ }
}
v8::Isolate* isolate = v8::Isolate::GetCurrent();
if (isolate && v8::MicrotasksScope::IsRunningMicrotasks(isolate)) {
@@ -778,7 +790,7 @@ void XMLHttpRequest::send(
}
if (body.IsArrayBufferView()) {
- send(body.GetAsArrayBufferView().View(), exception_state);
+ send(body.GetAsArrayBufferView().Get(), exception_state);
return;
}
@@ -802,8 +814,7 @@ bool XMLHttpRequest::AreMethodAndURLValidForSend() {
}
void XMLHttpRequest::send(Document* document, ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() Document "
- << static_cast<void*>(document);
+ DVLOG(1) << this << " send() Document " << static_cast<void*>(document);
DCHECK(document);
@@ -828,7 +839,7 @@ void XMLHttpRequest::send(Document* document, ExceptionState& exception_state) {
}
void XMLHttpRequest::send(const String& body, ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() String " << body;
+ DVLOG(1) << this << " send() String " << body;
if (!InitSend(exception_state))
return;
@@ -845,7 +856,7 @@ void XMLHttpRequest::send(const String& body, ExceptionState& exception_state) {
}
void XMLHttpRequest::send(Blob* body, ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() Blob " << body->Uuid();
+ DVLOG(1) << this << " send() Blob " << body->Uuid();
if (!InitSend(exception_state))
return;
@@ -878,7 +889,7 @@ void XMLHttpRequest::send(Blob* body, ExceptionState& exception_state) {
}
void XMLHttpRequest::send(FormData* body, ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() FormData " << body;
+ DVLOG(1) << this << " send() FormData " << body;
if (!InitSend(exception_state))
return;
@@ -903,7 +914,7 @@ void XMLHttpRequest::send(FormData* body, ExceptionState& exception_state) {
void XMLHttpRequest::send(URLSearchParams* body,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() URLSearchParams " << body;
+ DVLOG(1) << this << " send() URLSearchParams " << body;
if (!InitSend(exception_state))
return;
@@ -921,14 +932,14 @@ void XMLHttpRequest::send(URLSearchParams* body,
void XMLHttpRequest::send(DOMArrayBuffer* body,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() ArrayBuffer " << body;
+ DVLOG(1) << this << " send() ArrayBuffer " << body;
SendBytesData(body->Data(), body->ByteLength(), exception_state);
}
void XMLHttpRequest::send(DOMArrayBufferView* body,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << this << " send() ArrayBufferView " << body;
+ DVLOG(1) << this << " send() ArrayBufferView " << body;
SendBytesData(body->BaseAddress(), body->byteLength(), exception_state);
}
@@ -1165,7 +1176,7 @@ void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
}
void XMLHttpRequest::abort() {
- NETWORK_DVLOG(1) << this << " abort()";
+ DVLOG(1) << this << " abort()";
// internalAbort() clears the response. Save the data needed for
// dispatching ProgressEvents.
@@ -1303,7 +1314,7 @@ void XMLHttpRequest::DispatchProgressEventFromSnapshot(
}
void XMLHttpRequest::HandleNetworkError() {
- NETWORK_DVLOG(1) << this << " handleNetworkError()";
+ DVLOG(1) << this << " handleNetworkError()";
// Response is cleared next, save needed progress event data.
int64_t expected_length = response_.ExpectedContentLength();
@@ -1316,7 +1327,7 @@ void XMLHttpRequest::HandleNetworkError() {
}
void XMLHttpRequest::HandleDidCancel() {
- NETWORK_DVLOG(1) << this << " handleDidCancel()";
+ DVLOG(1) << this << " handleDidCancel()";
// Response is cleared next, save needed progress event data.
int64_t expected_length = response_.ExpectedContentLength();
@@ -1335,7 +1346,7 @@ void XMLHttpRequest::HandleRequestError(DOMExceptionCode exception_code,
const AtomicString& type,
int64_t received_length,
int64_t expected_length) {
- NETWORK_DVLOG(1) << this << " handleRequestError()";
+ DVLOG(1) << this << " handleRequestError()";
probe::DidFinishXHR(GetExecutionContext(), this);
@@ -1675,7 +1686,7 @@ String XMLHttpRequest::statusText() const {
}
void XMLHttpRequest::DidFail(const ResourceError& error) {
- NETWORK_DVLOG(1) << this << " didFail()";
+ DVLOG(1) << this << " didFail()";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
// If we are already in an error state, for instance we called abort(), bail
@@ -1708,14 +1719,14 @@ void XMLHttpRequest::DidFail(const ResourceError& error) {
}
void XMLHttpRequest::DidFailRedirectCheck() {
- NETWORK_DVLOG(1) << this << " didFailRedirectCheck()";
+ DVLOG(1) << this << " didFailRedirectCheck()";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
HandleNetworkError();
}
void XMLHttpRequest::DidFinishLoading(uint64_t identifier) {
- NETWORK_DVLOG(1) << this << " didFinishLoading(" << identifier << ")";
+ DVLOG(1) << this << " didFinishLoading(" << identifier << ")";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
if (error_)
@@ -1761,14 +1772,14 @@ void XMLHttpRequest::DidFinishLoadingInternal() {
}
void XMLHttpRequest::DidFinishLoadingFromBlob() {
- NETWORK_DVLOG(1) << this << " didFinishLoadingFromBlob";
+ DVLOG(1) << this << " didFinishLoadingFromBlob";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
DidFinishLoadingInternal();
}
void XMLHttpRequest::DidFailLoadingFromBlob() {
- NETWORK_DVLOG(1) << this << " didFailLoadingFromBlob()";
+ DVLOG(1) << this << " didFailLoadingFromBlob()";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
if (error_)
@@ -1819,8 +1830,8 @@ void XMLHttpRequest::EndLoading() {
void XMLHttpRequest::DidSendData(uint64_t bytes_sent,
uint64_t total_bytes_to_be_sent) {
- NETWORK_DVLOG(1) << this << " didSendData(" << bytes_sent << ", "
- << total_bytes_to_be_sent << ")";
+ DVLOG(1) << this << " didSendData(" << bytes_sent << ", "
+ << total_bytes_to_be_sent << ")";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
if (!upload_)
@@ -1843,7 +1854,7 @@ void XMLHttpRequest::DidReceiveResponse(uint64_t identifier,
// TODO(yhirano): Remove this CHECK: see https://crbug.com/570946.
CHECK(&response);
- NETWORK_DVLOG(1) << this << " didReceiveResponse(" << identifier << ")";
+ DVLOG(1) << this << " didReceiveResponse(" << identifier << ")";
ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
response_ = response;
@@ -2024,7 +2035,7 @@ void XMLHttpRequest::DidDownloadToBlob(scoped_refptr<BlobDataHandle> blob) {
}
void XMLHttpRequest::HandleDidTimeout() {
- NETWORK_DVLOG(1) << this << " handleDidTimeout()";
+ DVLOG(1) << this << " handleDidTimeout()";
// Response is cleared next, save needed progress event data.
int64_t expected_length = response_.ExpectedContentLength();
diff --git a/chromium/third_party/blink/renderer/modules/BUILD.gn b/chromium/third_party/blink/renderer/modules/BUILD.gn
index 79788bf60db..f9f35f747e7 100644
--- a/chromium/third_party/blink/renderer/modules/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/BUILD.gn
@@ -10,6 +10,7 @@ import("//third_party/blink/renderer/bindings/modules/v8/v8.gni")
import("//third_party/blink/renderer/build/scripts/scripts.gni")
import("//third_party/blink/renderer/modules/modules.gni")
import("//third_party/blink/renderer/modules/modules_idl_files.gni")
+import("//third_party/webrtc/webrtc.gni")
if (is_android) {
import("//build/config/android/rules.gni")
@@ -82,10 +83,12 @@ component("modules") {
"//third_party/blink/renderer/modules/background_fetch",
"//third_party/blink/renderer/modules/background_sync",
"//third_party/blink/renderer/modules/badging",
+ "//third_party/blink/renderer/modules/device",
"//third_party/blink/renderer/modules/battery",
"//third_party/blink/renderer/modules/beacon",
"//third_party/blink/renderer/modules/bluetooth",
"//third_party/blink/renderer/modules/broadcastchannel",
+ "//third_party/blink/renderer/modules/buckets",
"//third_party/blink/renderer/modules/cache_storage",
"//third_party/blink/renderer/modules/canvas",
"//third_party/blink/renderer/modules/clipboard",
@@ -104,11 +107,13 @@ component("modules") {
"//third_party/blink/renderer/modules/encryptedmedia",
"//third_party/blink/renderer/modules/eventsource",
"//third_party/blink/renderer/modules/exported",
+ "//third_party/blink/renderer/modules/eyedropper",
"//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",
+ "//third_party/blink/renderer/modules/handwriting",
"//third_party/blink/renderer/modules/hid",
"//third_party/blink/renderer/modules/idle",
"//third_party/blink/renderer/modules/imagecapture",
@@ -128,7 +133,7 @@ component("modules") {
"//third_party/blink/renderer/modules/mediasource",
"//third_party/blink/renderer/modules/mediastream",
"//third_party/blink/renderer/modules/media",
- "//third_party/blink/renderer/modules/webrtc",
+ "//third_party/blink/renderer/modules/modalclosewatcher",
"//third_party/blink/renderer/modules/native_io",
"//third_party/blink/renderer/modules/navigatorcontentutils",
"//third_party/blink/renderer/modules/netinfo",
@@ -154,6 +159,7 @@ component("modules") {
"//third_party/blink/renderer/modules/speech",
"//third_party/blink/renderer/modules/srcobject",
"//third_party/blink/renderer/modules/storage",
+ "//third_party/blink/renderer/modules/url_pattern",
"//third_party/blink/renderer/modules/vibration",
"//third_party/blink/renderer/modules/video_rvfc",
"//third_party/blink/renderer/modules/virtualkeyboard",
@@ -165,6 +171,7 @@ component("modules") {
"//third_party/blink/renderer/modules/webgpu",
"//third_party/blink/renderer/modules/webid",
"//third_party/blink/renderer/modules/webmidi",
+ "//third_party/blink/renderer/modules/webrtc",
"//third_party/blink/renderer/modules/webshare",
"//third_party/blink/renderer/modules/websockets",
"//third_party/blink/renderer/modules/webtransport",
@@ -273,6 +280,15 @@ group("make_modules_generated") {
source_set("unit_tests") {
testonly = true
+ # TODO(crbug.com/1173961): avoid depending on testonly webrtc targets.
+ if (rtc_include_tests) {
+ # This target uses some webrtc targets that are not part of
+ # "webrtc_component". This target relies on the fact that including a header
+ # that is not tracked by GN works without raising any warning. However it
+ # leads to build errors if rtc_include_tests = true.
+ check_includes = false
+ }
+
sources = [
"accessibility/accessibility_object_model_test.cc",
"accessibility/ax_inline_text_box_test.cc",
@@ -301,6 +317,7 @@ source_set("unit_tests") {
"content_index/content_description_type_converter_test.cc",
"credentialmanager/credentials_container_test.cc",
"credentialmanager/password_credential_test.cc",
+ "csspaint/background_color_paint_worklet_test.cc",
"csspaint/document_paint_definition_test.cc",
"csspaint/paint_rendering_context_2d_test.cc",
"csspaint/paint_worklet_global_scope_test.cc",
@@ -313,6 +330,7 @@ source_set("unit_tests") {
"eventsource/event_source_parser_test.cc",
"filesystem/dom_file_system_base_test.cc",
"filesystem/file_writer_test.cc",
+ "handwriting/handwriting_type_converters_unittest.cc",
"installedapp/installed_app_controller_test.cc",
"manifest/image_resource_type_converters_test.cc",
"manifest/manifest_manager_unittest.cc",
@@ -351,6 +369,8 @@ source_set("unit_tests") {
"mediastream/media_constraints_test.cc",
"mediastream/media_devices_test.cc",
"mediastream/media_stream_audio_processor_test.cc",
+ "mediastream/media_stream_audio_track_underlying_sink_test.cc",
+ "mediastream/media_stream_audio_track_underlying_source_test.cc",
"mediastream/media_stream_constraints_util_audio_test.cc",
"mediastream/media_stream_constraints_util_sets_test.cc",
"mediastream/media_stream_constraints_util_test.cc",
@@ -359,6 +379,7 @@ source_set("unit_tests") {
"mediastream/media_stream_device_observer_test.cc",
"mediastream/media_stream_track_generator_test.cc",
"mediastream/media_stream_track_processor_test.cc",
+ "mediastream/media_stream_track_test.cc",
"mediastream/media_stream_video_capturer_source_test.cc",
"mediastream/media_stream_video_renderer_sink_test.cc",
"mediastream/media_stream_video_source_test.cc",
@@ -368,9 +389,14 @@ source_set("unit_tests") {
"mediastream/mock_mojo_media_stream_dispatcher_host.cc",
"mediastream/mock_mojo_media_stream_dispatcher_host.h",
"mediastream/processed_local_audio_source_test.cc",
+ "mediastream/pushable_media_stream_audio_source_test.cc",
"mediastream/pushable_media_stream_video_source_test.cc",
+ "mediastream/stream_test_utils.cc",
+ "mediastream/stream_test_utils.h",
"mediastream/user_media_client_test.cc",
"mediastream/video_track_adapter_unittest.cc",
+ "mediastream/video_track_signal_underlying_sink_test.cc",
+ "mediastream/video_track_signal_underlying_source_test.cc",
"mediastream/webaudio_media_stream_audio_sink_test.cc",
"mediastream/webmediaplayer_ms_test.cc",
"nfc/nfc_proxy_test.cc",
@@ -528,6 +554,10 @@ source_set("unit_tests") {
"//v8",
]
+ if (!is_android) {
+ deps += [ "//third_party/blink/renderer/modules/direct_sockets:unit_tests" ]
+ }
+
data_deps = [
":accessibility_unittests_data",
":mediastream_unittests_data",
@@ -589,6 +619,59 @@ if (use_libfuzzer) {
]
}
+ image_decoder_fuzzer_seed_corpus_dir =
+ "$target_gen_dir/webcodecs/image_fuzzer_seed_corpus"
+
+ action("generate_image_decoder_fuzzer_corpus") {
+ script = "webcodecs/fuzzer_seed_corpus/generate_image_corpus.py"
+ sources = [ "webcodecs/image_decoder_base.textproto" ]
+
+ data = [ "//third_party/blink/web_tests/images/resources/" ]
+
+ deps = [
+ "//third_party/blink/renderer/modules/webcodecs:fuzzer_protos",
+ "//third_party/protobuf:py_proto",
+ ]
+
+ pyproto_path = "$root_out_dir/pyproto"
+
+ args = [ "-i" ]
+ args += rebase_path(sources, root_build_dir)
+ args += [
+ "-o",
+ "ignored",
+ "-d",
+ rebase_path(image_decoder_fuzzer_seed_corpus_dir, root_build_dir),
+ "-p",
+ rebase_path(pyproto_path, root_build_dir),
+ "-p",
+ rebase_path("$pyproto_path/third_party/blink/renderer/modules/webcodecs/",
+ root_build_dir),
+ ]
+
+ outputs = [ image_decoder_fuzzer_seed_corpus_dir ]
+ }
+
+ fuzzer_test("webcodecs_image_decoder_fuzzer") {
+ sources = [
+ "webcodecs/fuzzer_utils.cc",
+ "webcodecs/fuzzer_utils.h",
+ "webcodecs/image_decoder_fuzzer.cc",
+ ]
+
+ seed_corpus = image_decoder_fuzzer_seed_corpus_dir
+ seed_corpus_deps = [ ":generate_image_decoder_fuzzer_corpus" ]
+
+ 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",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+ }
+
fuzzer_test("webcodecs_audio_decoder_fuzzer") {
sources = [
"webcodecs/audio_decoder_fuzzer.cc",
diff --git a/chromium/third_party/blink/renderer/modules/DEPS b/chromium/third_party/blink/renderer/modules/DEPS
index 33f2edaef70..9c9c62f92d0 100644
--- a/chromium/third_party/blink/renderer/modules/DEPS
+++ b/chromium/third_party/blink/renderer/modules/DEPS
@@ -8,6 +8,7 @@ include_rules = [
"+services/device/public/mojom",
"+services/network/public/cpp/shared_url_loader_factory.h",
"+services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h",
+ "+skia/ext/skia_utils_base.h",
"+third_party/blink/public/common",
"+third_party/blink/public/web",
"+third_party/blink/renderer/bindings",
@@ -40,4 +41,7 @@ specific_include_rules = {
"canvas_fuzzer.cc": [
"+base/test/bind.h",
],
+ "web_ax_object.cc": [
+ "+ui/accessibility/ax_action_data.h",
+ ],
}
diff --git a/chromium/third_party/blink/renderer/modules/DIR_METADATA b/chromium/third_party/blink/renderer/modules/DIR_METADATA
new file mode 100644
index 00000000000..fb78ce0b4b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Internals>Modularization"
+}
+team_email: "platform-architecture-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/OWNERS b/chromium/third_party/blink/renderer/modules/OWNERS
index d4382735457..37e2b610bf4 100644
--- a/chromium/third_party/blink/renderer/modules/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/OWNERS
@@ -9,6 +9,3 @@ mlamouri@chromium.org
dgozman@chromium.org
pfeldman@chromium.org
caseq@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>Modularization
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
index c4724fbce3a..e7dabc4d991 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
@@ -14,8 +14,6 @@ blink_modules_sources("accessibility") {
"ax_inline_text_box.h",
"ax_layout_object.cc",
"ax_layout_object.h",
- "ax_list.cc",
- "ax_list.h",
"ax_list_box.cc",
"ax_list_box.h",
"ax_list_box_option.cc",
@@ -40,8 +38,6 @@ blink_modules_sources("accessibility") {
"ax_position.h",
"ax_progress_indicator.cc",
"ax_progress_indicator.h",
- "ax_radio_input.cc",
- "ax_radio_input.h",
"ax_range.cc",
"ax_range.h",
"ax_relation_cache.cc",
@@ -52,8 +48,6 @@ blink_modules_sources("accessibility") {
"ax_slider.h",
"ax_sparse_attribute_setter.cc",
"ax_sparse_attribute_setter.h",
- "ax_svg_root.cc",
- "ax_svg_root.h",
"ax_validation_message.cc",
"ax_validation_message.h",
"ax_virtual_object.cc",
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/DEPS b/chromium/third_party/blink/renderer/modules/accessibility/DEPS
index 2bfd7d06e2e..50948449d65 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/DEPS
+++ b/chromium/third_party/blink/renderer/modules/accessibility/DEPS
@@ -5,6 +5,8 @@ include_rules = [
"+third_party/blink/renderer/modules/media_controls",
"+third_party/blink/renderer/modules/modules_export.h",
"+third_party/blink/renderer/modules/permissions",
+ "+ui/accessibility/ax_action_data.h",
+ "+ui/accessibility/ax_common.h",
"+ui/accessibility/ax_enums.mojom-blink.h",
"+ui/accessibility/ax_enums.mojom-blink-forward.h",
"+ui/accessibility/ax_event.h",
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/DIR_METADATA b/chromium/third_party/blink/renderer/modules/accessibility/DIR_METADATA
new file mode 100644
index 00000000000..007f8236cd6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/accessibility/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/OWNERS b/chromium/third_party/blink/renderer/modules/accessibility/OWNERS
index 2f62f51436b..31035ef506e 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/accessibility/OWNERS
@@ -2,6 +2,3 @@ aboxhall@chromium.org
aleventhal@chromium.org
dmazzoni@chromium.org
nektar@chromium.org
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: Blink>Accessibility
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 09230fa0bb5..c06f240c14a 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
@@ -264,32 +264,6 @@ TEST_F(AccessibilityObjectModelTest, Grid) {
EXPECT_EQ(0U, ax_cell2->AriaRowIndex());
}
-class SparseAttributeAdapter : public AXSparseAttributeClient {
- STACK_ALLOCATED();
-
- public:
- SparseAttributeAdapter() = default;
- ~SparseAttributeAdapter() = default;
-
- HeapHashMap<AXObjectAttribute, Member<AXObject>> object_attributes;
- HeapHashMap<AXObjectVectorAttribute, Member<HeapVector<Member<AXObject>>>>
- object_vector_attributes;
-
- private:
- void AddObjectAttribute(AXObjectAttribute attribute,
- AXObject& value) override {
- ASSERT_TRUE(object_attributes.find(attribute) == object_attributes.end());
- object_attributes.insert(attribute, &value);
- }
-
- void AddObjectVectorAttribute(AXObjectVectorAttribute attribute,
- HeapVector<Member<AXObject>>* value) override {
- ASSERT_TRUE(object_vector_attributes.find(attribute) ==
- object_vector_attributes.end());
- object_vector_attributes.insert(attribute, value);
- }
-};
-
TEST_F(AccessibilityObjectModelTest, SparseAttributes) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
@@ -297,6 +271,7 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) {
<input id=target
aria-keyshortcuts=Ctrl+K
aria-roledescription=Widget
+ aria-virtualcontent=block-end
aria-activedescendant=active
aria-details=details
aria-errormessage=error>
@@ -313,9 +288,6 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) {
auto* cache = AXObjectCache();
ASSERT_NE(nullptr, cache);
auto* ax_target = cache->GetOrCreate(target);
- SparseAttributeAdapter sparse_attributes;
- ax_target->GetSparseAXAttributes(sparse_attributes);
-
ui::AXNodeData node_data;
ax_target->Serialize(&node_data, ui::kAXModeComplete);
@@ -323,21 +295,27 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) {
ax::mojom::blink::StringAttribute::kKeyShortcuts));
ASSERT_EQ("Widget", node_data.GetStringAttribute(
ax::mojom::blink::StringAttribute::kRoleDescription));
+ ASSERT_EQ("block-end",
+ node_data.GetStringAttribute(
+ ax::mojom::blink::StringAttribute::kVirtualContent));
+ auto* active_descendant_target =
+ cache->ObjectFromAXID(node_data.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kActivedescendantId));
+ ASSERT_NE(nullptr, active_descendant_target);
ASSERT_EQ(ax::mojom::Role::kListBoxOption,
- sparse_attributes.object_attributes
- .at(AXObjectAttribute::kAriaActiveDescendant)
- ->RoleValue());
- ASSERT_EQ(ax::mojom::Role::kContentInfo,
- (*sparse_attributes.object_vector_attributes.at(
- AXObjectVectorAttribute::kAriaDetails))[0]
- ->RoleValue());
- ASSERT_EQ(ax::mojom::Role::kArticle,
- sparse_attributes.object_attributes
- .at(AXObjectAttribute::kAriaErrorMessage)
- ->RoleValue());
+ active_descendant_target->RoleValue());
+ auto* aria_details_target =
+ cache->ObjectFromAXID(node_data.GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kDetailsIds)[0]);
+ ASSERT_EQ(ax::mojom::Role::kContentInfo, aria_details_target->RoleValue());
+ auto* error_message_target = cache->ObjectFromAXID(node_data.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kErrormessageId));
+ ASSERT_NE(nullptr, error_message_target);
+ ASSERT_EQ(ax::mojom::Role::kArticle, error_message_target->RoleValue());
target->accessibleNode()->setKeyShortcuts("Ctrl+L");
target->accessibleNode()->setRoleDescription("Object");
+ target->accessibleNode()->setVirtualContent("inline-start");
target->accessibleNode()->setActiveDescendant(
GetDocument().getElementById("active2")->accessibleNode());
AccessibleNodeList* details_node_list =
@@ -348,25 +326,30 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) {
target->accessibleNode()->setErrorMessage(
GetDocument().getElementById("error2")->accessibleNode());
- SparseAttributeAdapter sparse_attributes2;
- ax_target->GetSparseAXAttributes(sparse_attributes2);
+ ui::AXNodeData node_data2;
+ ax_target->Serialize(&node_data2, ui::kAXModeComplete);
ASSERT_EQ("Ctrl+K", node_data.GetStringAttribute(
ax::mojom::blink::StringAttribute::kKeyShortcuts));
ASSERT_EQ("Widget", node_data.GetStringAttribute(
ax::mojom::blink::StringAttribute::kRoleDescription));
+ ASSERT_EQ(target->accessibleNode()->virtualContent(), "inline-start");
+ ASSERT_EQ("block-end",
+ node_data.GetStringAttribute(
+ ax::mojom::blink::StringAttribute::kVirtualContent));
+ auto* active_descendant_target2 =
+ cache->ObjectFromAXID(node_data2.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kActivedescendantId));
ASSERT_EQ(ax::mojom::Role::kListBoxOption,
- sparse_attributes2.object_attributes
- .at(AXObjectAttribute::kAriaActiveDescendant)
- ->RoleValue());
- ASSERT_EQ(ax::mojom::Role::kContentInfo,
- (*sparse_attributes2.object_vector_attributes.at(
- AXObjectVectorAttribute::kAriaDetails))[0]
- ->RoleValue());
- ASSERT_EQ(ax::mojom::Role::kArticle,
- sparse_attributes2.object_attributes
- .at(AXObjectAttribute::kAriaErrorMessage)
- ->RoleValue());
+ active_descendant_target2->RoleValue());
+ auto* aria_details_target2 =
+ cache->ObjectFromAXID(node_data2.GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kDetailsIds)[0]);
+ ASSERT_EQ(ax::mojom::Role::kContentInfo, aria_details_target2->RoleValue());
+ auto* error_message_target2 = cache->ObjectFromAXID(node_data.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kErrormessageId));
+ ASSERT_NE(nullptr, error_message_target2);
+ ASSERT_EQ(ax::mojom::Role::kArticle, error_message_target2->RoleValue());
}
TEST_F(AccessibilityObjectModelTest, LabeledBy) {
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h
index 559d483645f..aeb5b69ba2b 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h
@@ -59,6 +59,9 @@ enum class AXUIntAttribute {
enum class AXStringAttribute {
kAriaKeyShortcuts,
kAriaRoleDescription,
+ // TODO(bebeaudr): kAriaVirtualContent is currently a string attribute to
+ // facilitate prototyping. Make it an enum when we're done prototyping.
+ kAriaVirtualContent,
};
enum class AXObjectAttribute {
@@ -94,6 +97,7 @@ enum AXTextFromNativeHTML {
kAXTextFromNativeHTMLLabelFor,
kAXTextFromNativeHTMLLabelWrapped,
kAXTextFromNativeHTMLLegend,
+ kAXTextFromNativeHTMLRubyAnnotation,
kAXTextFromNativeHTMLTableCaption,
kAXTextFromNativeHTMLTitleElement,
};
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
index 6889176407f..92087554c47 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
@@ -50,30 +50,33 @@ HTMLMapElement* AXImageMapLink::MapElement() const {
return Traversal<HTMLMapElement>::FirstAncestor(*area);
}
-AXObject* AXImageMapLink::ComputeParent() const {
- DCHECK(!IsDetached());
- if (parent_)
- return parent_;
-
- if (!MapElement())
- return nullptr;
-
- return AXObjectCache().GetOrCreate(MapElement()->GetLayoutObject());
+AXObject* AXImageMapLink::ComputeParentImpl() const {
+ if (MapElement()) {
+ AXObject* ax_parent =
+ AXObjectCache().GetOrCreate(MapElement()->GetLayoutObject());
+ if (ax_parent)
+ return ax_parent;
+ }
+ return AXNodeObject::ComputeParentImpl();
}
-ax::mojom::Role AXImageMapLink::RoleValue() const {
- const AtomicString& aria_role =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole);
- if (!aria_role.IsEmpty())
- return AXObject::AriaRoleToWebCoreRole(aria_role);
-
+ax::mojom::blink::Role AXImageMapLink::DetermineAccessibilityRole() {
// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
// <area> tags without an href should be treated as static text.
+ // If the area has child nodes, those will be rendered naturally, and the
+ // role needs to be a generic container role that allows children.
KURL url = Url();
- if (url.IsNull() || url.IsEmpty())
- return ax::mojom::Role::kStaticText;
+ bool has_url = !url.IsNull() && !url.IsEmpty();
+ if (has_url)
+ native_role_ = ax::mojom::blink::Role::kLink;
+ else if (!GetElement()->hasChildren())
+ native_role_ = ax::mojom::blink::Role::kStaticText;
+ else
+ native_role_ = ax::mojom::blink::Role::kGenericContainer;
- return ax::mojom::Role::kLink;
+ aria_role_ = DetermineAriaRoleAttribute();
+ return aria_role_ == ax::mojom::blink::Role::kUnknown ? native_role_
+ : aria_role_;
}
bool AXImageMapLink::ComputeAccessibilityIsIgnored(
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h
index b3775a45bad..06989709af1 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h
@@ -50,14 +50,20 @@ class AXImageMapLink final : public AXNodeObject {
HTMLMapElement* MapElement() const;
- ax::mojom::Role RoleValue() const override;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
+ bool CanHaveChildren() const override {
+ // If the area has child nodes, those will be rendered, and the combination
+ // of Role::kGenericContainer and CanHaveChildren() = true allows for those
+ // children to show in the AX hierarchy.
+ return RoleValue() == ax::mojom::blink::Role::kGenericContainer;
+ }
Element* AnchorElement() const override;
Element* ActionElement() const override;
KURL Url() const override;
bool IsLinked() const override { return true; }
- AXObject* ComputeParent() const override;
+ AXObject* ComputeParentImpl() const override;
void GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
index 2bbb0e49ed3..f49bc9f3ae2 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,6 +28,8 @@
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
+#include <stdint.h>
+
#include <utility>
#include "base/numerics/clamped_math.h"
@@ -43,6 +45,7 @@
#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/runtime_enabled_features.h"
+#include "ui/accessibility/ax_role_properties.h"
namespace blink {
@@ -51,10 +54,6 @@ AXInlineTextBox::AXInlineTextBox(
AXObjectCacheImpl& ax_object_cache)
: AXObject(ax_object_cache), inline_text_box_(std::move(inline_text_box)) {}
-ax::mojom::blink::Role AXInlineTextBox::RoleValue() const {
- return ax::mojom::blink::Role::kInlineTextBox;
-}
-
void AXInlineTextBox::GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
@@ -154,7 +153,12 @@ int AXInlineTextBox::TextOffsetInContainer(int offset) const {
// 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);
+ // TODO(nektar) Figure out why this asserts in marker-hyphens.html.
+ // To see error, comment out below early return and run command similar to:
+ // run_web_tests.py --driver-logging -t linux-debug
+ // --additional-driver-flag=--force-renderer-accessibility
+ // external/wpt/css/css-pseudo/marker-hyphens.html
+ // DCHECK_LE(offset_in_inline_parent, offset_in_block_flow_container);
return offset_in_block_flow_container - offset_in_inline_parent;
}
@@ -167,17 +171,6 @@ String AXInlineTextBox::GetName(ax::mojom::blink::NameFrom& name_from,
return inline_text_box_->GetText();
}
-AXObject* AXInlineTextBox::ComputeParent() const {
- DCHECK(!IsDetached());
- if (!inline_text_box_ || !ax_object_cache_)
- return nullptr;
- LineLayoutText line_layout_text = inline_text_box_->GetLineLayoutItem();
- if (!line_layout_text)
- return nullptr;
- return ax_object_cache_->GetOrCreate(
- LineLayoutAPIShim::LayoutObjectFrom(line_layout_text));
-}
-
// 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 {
@@ -205,6 +198,10 @@ Node* AXInlineTextBox::GetNode() const {
return inline_text_box_->GetNode();
}
+Document* AXInlineTextBox::GetDocument() const {
+ return ParentObject() ? ParentObject()->GetDocument() : nullptr;
+}
+
AXObject* AXInlineTextBox::NextOnLine() const {
if (IsDetached())
return nullptr;
@@ -215,7 +212,7 @@ AXObject* AXInlineTextBox::NextOnLine() const {
scoped_refptr<AbstractInlineTextBox> next_on_line =
inline_text_box_->NextOnLine();
if (next_on_line)
- return ax_object_cache_->GetOrCreate(next_on_line.get());
+ return AXObjectCache().GetOrCreate(next_on_line.get(), nullptr);
return nullptr;
}
@@ -230,14 +227,22 @@ AXObject* AXInlineTextBox::PreviousOnLine() const {
scoped_refptr<AbstractInlineTextBox> previous_on_line =
inline_text_box_->PreviousOnLine();
if (previous_on_line)
- return ax_object_cache_->GetOrCreate(previous_on_line.get());
+ return AXObjectCache().GetOrCreate(previous_on_line.get(), nullptr);
return nullptr;
}
-void AXInlineTextBox::GetDocumentMarkers(
- Vector<DocumentMarker::MarkerType>* marker_types,
- Vector<AXRange>* marker_ranges) const {
+void AXInlineTextBox::SerializeMarkerAttributes(
+ ui::AXNodeData* node_data) const {
+ // TODO(nektar) Address 20% performance degredation and restore code.
+ // It may be necessary to add document markers as part of tree data instead
+ // of computing for every node. To measure current performance, create a
+ // release build without DCHECKs, and then run command similar to:
+ // tools/perf/run_benchmark blink_perf.accessibility --browser=exact \
+ // --browser-executable=path/to/chrome --story-filter="accessibility.*"
+ // --results-label="[my-branch-name]"
+ // Pay attention only to rows with ProcessDeferredAccessibilityEvents
+ // and RenderAccessibilityImpl::SendPendingAccessibilityEvents.
if (!RuntimeEnabledFeatures::
AccessibilityUseAXPositionForDocumentMarkersEnabled())
return;
@@ -260,12 +265,17 @@ void AXInlineTextBox::GetDocumentMarkers(
return;
const auto ax_range = AXRange::RangeOfContents(*this);
+ std::vector<int32_t> marker_types;
+ std::vector<int32_t> marker_starts;
+ std::vector<int32_t> marker_ends;
+
// 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);
+ marker_types.push_back(ToAXMarkerType(aria_marker_type.value()));
+ marker_starts.push_back(ax_range.Start().TextOffset());
+ marker_ends.push_back(ax_range.End().TextOffset());
}
DocumentMarkerController& marker_controller = GetDocument()->Markers();
@@ -276,6 +286,14 @@ void AXInlineTextBox::GetDocumentMarkers(
if (dom_range_start.IsNull() || dom_range_end.IsNull())
return;
+ // TODO(nektar) Figure out why the start > end sometimes.
+ // To see error, comment out below early return and run command similar to:
+ // run_web_tests.py --driver-logging -t linux-debug
+ // --additional-driver-flag=--force-renderer-accessibility
+ // external/wpt/css/css-ui/text-overflow-006.html
+ if (dom_range_start > dom_range_end)
+ return; // Temporary until above TODO is resolved.
+ DCHECK_LE(dom_range_start, dom_range_end);
const EphemeralRangeInFlatTree dom_range(
ToPositionInFlatTree(dom_range_start),
ToPositionInFlatTree(dom_range_end));
@@ -318,22 +336,37 @@ void AXInlineTextBox::GetDocumentMarkers(
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));
+ marker_types.push_back(int32_t{ToAXMarkerType(marker->GetType())});
+ marker_starts.push_back(local_start_offset);
+ marker_ends.push_back(local_end_offset);
}
+
+ DCHECK_EQ(marker_types.size(), marker_starts.size());
+ DCHECK_EQ(marker_types.size(), marker_ends.size());
+
+ if (marker_types.empty())
+ return;
+
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerTypes, marker_types);
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerStarts, marker_starts);
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerEnds, marker_ends);
}
-void AXInlineTextBox::Init() {}
+void AXInlineTextBox::Init(AXObject* parent) {
+ role_ = ax::mojom::blink::Role::kInlineTextBox;
+ DCHECK(parent);
+ DCHECK(ui::CanHaveInlineTextBoxChildren(parent->RoleValue()))
+ << "Unexpected parent of inline text box: " << parent->RoleValue();
+ SetParent(parent);
+ UpdateCachedAttributeValuesIfNeeded(false);
+}
void AXInlineTextBox::Detach() {
- inline_text_box_ = nullptr;
AXObject::Detach();
-}
-
-bool AXInlineTextBox::IsDetached() const {
- return !inline_text_box_ || AXObject::IsDetached();
+ inline_text_box_ = nullptr;
}
bool AXInlineTextBox::IsAXInlineTextBox() const {
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 57548db4e29..f1e59cd89fe 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
@@ -46,7 +46,7 @@ class AXInlineTextBox final : public AXObject {
AXInlineTextBox(scoped_refptr<AbstractInlineTextBox>, AXObjectCacheImpl&);
// AXObject overrides.
- ax::mojom::blink::Role RoleValue() const override;
+ RGBA32 GetColor() const override { return Color::kTransparent; }
String GetName(ax::mojom::blink::NameFrom&,
AXObject::AXObjectVector* name_objects) const override;
void TextCharacterOffsets(Vector<int>&) const override;
@@ -58,22 +58,29 @@ class AXInlineTextBox final : public AXObject {
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
bool* clips_children = nullptr) const override;
- AXObject* ComputeParent() const override;
ax::mojom::blink::WritingDirection GetTextDirection() const override;
Node* GetNode() const override;
+ Document* GetDocument() const override;
AXObject* NextOnLine() const override;
AXObject* PreviousOnLine() const override;
- void GetDocumentMarkers(Vector<DocumentMarker::MarkerType>* marker_types,
- Vector<AXRange>* marker_ranges) const override;
+ void SerializeMarkerAttributes(ui::AXNodeData* node_data) const override;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override {
+ // role_ is set manually in Init(), but must implement pure virtual method.
+ NOTREACHED();
+ return ax::mojom::blink::Role::kInlineTextBox;
+ }
protected:
- void Init() override;
+ void Init(AXObject* parent) override;
void Detach() override;
- bool IsDetached() const override;
bool IsAXInlineTextBox() const override;
bool IsLineBreakingObject() const override;
int TextLength() const override;
+ // Always a leaf.
+ bool CanHaveChildren() const override { return false; }
+ void AddChildren() override {}
+
private:
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
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 bb4c02b5cb0..416b4b7cecf 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
@@ -14,6 +14,9 @@
#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+using AXIntListAttribute = ax::mojom::blink::IntListAttribute;
+using AXMarkerType = ax::mojom::blink::MarkerType;
+
namespace blink {
namespace test {
@@ -84,64 +87,59 @@ TEST_P(ParameterizedAccessibilityTest, GetDocumentMarkers) {
// 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);
+ {
+ ui::AXNodeData node_data;
+ ax_inline_text_box->Serialize(&node_data, ui::kAXModeComplete);
+ EXPECT_EQ(std::vector<int32_t>{int32_t(AXMarkerType::kSpelling)},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerTypes));
+ EXPECT_EQ(std::vector<int32_t>{0},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerStarts));
+ EXPECT_EQ(std::vector<int32_t>{11},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerEnds));
+ }
// 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);
+ {
+ ui::AXNodeData node_data;
+ ax_inline_text_box->Serialize(&node_data, ui::kAXModeComplete);
+ EXPECT_EQ((std::vector<int32_t>{int32_t(AXMarkerType::kSpelling),
+ int32_t(AXMarkerType::kGrammar)}),
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerTypes));
+ EXPECT_EQ((std::vector<int32_t>{0, 10}),
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerStarts));
+ EXPECT_EQ((std::vector<int32_t>{4, 12}),
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerEnds));
+ }
// 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);
+ {
+ ui::AXNodeData node_data;
+ ax_inline_text_box->Serialize(&node_data, ui::kAXModeComplete);
+ EXPECT_EQ(std::vector<int32_t>{int32_t(AXMarkerType::kGrammar)},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerTypes));
+ EXPECT_EQ(std::vector<int32_t>{0},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerStarts));
+ EXPECT_EQ(std::vector<int32_t>{8},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerEnds));
+ }
// 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);
+ {
+ ui::AXNodeData node_data;
+ ax_inline_text_box->Serialize(&node_data, ui::kAXModeComplete);
+ EXPECT_EQ(std::vector<int32_t>{int32_t(AXMarkerType::kGrammar)},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerTypes));
+ EXPECT_EQ(std::vector<int32_t>{0},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerStarts));
+ EXPECT_EQ(std::vector<int32_t>{5},
+ node_data.GetIntListAttribute(AXIntListAttribute::kMarkerEnds));
+ }
}
TEST_P(ParameterizedAccessibilityTest, TextOffsetInContainerWithASpan) {
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 fc3fbd37b5a..a33b926b2ef 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
@@ -1,30 +1,30 @@
/*
-* Copyright (C) 2008 Apple Inc. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-*
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
-* its contributors may be used to endorse or promote products derived
-* from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
-* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
@@ -33,6 +33,7 @@
#include <string>
#include "third_party/blink/renderer/core/aom/accessible_node.h"
+#include "third_party/blink/renderer/core/css/counter_style_map.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -66,13 +67,13 @@
#include "third_party/blink/renderer/core/layout/layout_html_canvas.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "third_party/blink/renderer/core/layout/layout_list_item.h"
#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.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"
#include "third_party/blink/renderer/core/layout/layout_table_section.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"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
@@ -91,10 +92,8 @@
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
#include "third_party/blink/renderer/modules/accessibility/ax_mock_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_svg_root.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
-#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
@@ -105,6 +104,7 @@ AXLayoutObject::AXLayoutObject(LayoutObject* layout_object,
layout_object_(layout_object) {
// TODO(aleventhal) Get correct current state of autofill.
#if DCHECK_IS_ON()
+ DCHECK(layout_object_);
layout_object_->SetHasAXObject(true);
#endif
}
@@ -113,10 +113,6 @@ AXLayoutObject::~AXLayoutObject() {
DCHECK(IsDetached());
}
-LayoutBoxModelObject* AXLayoutObject::GetLayoutBoxModelObject() const {
- return DynamicTo<LayoutBoxModelObject>(layout_object_);
-}
-
bool IsProgrammaticallyScrollable(LayoutBox* box) {
if (!box->IsScrollContainer())
return false;
@@ -154,8 +150,9 @@ ScrollableArea* AXLayoutObject::GetScrollableAreaIfScrollable() const {
return nullptr;
}
-static bool IsImageOrAltText(LayoutBoxModelObject* box, Node* node) {
- if (box && box->IsImage())
+static bool IsImageOrAltText(LayoutObject* layout_object, Node* node) {
+ DCHECK(layout_object);
+ if (layout_object->IsImage())
return true;
if (IsA<HTMLImageElement>(node))
return true;
@@ -167,12 +164,12 @@ static bool IsImageOrAltText(LayoutBoxModelObject* box, Node* node) {
ax::mojom::blink::Role AXLayoutObject::RoleFromLayoutObject(
ax::mojom::blink::Role dom_role) const {
+ DCHECK(layout_object_);
// Markup did not provide a specific role, so attempt to determine one
// from the computed style.
- Node* node = layout_object_->GetNode();
- LayoutBoxModelObject* css_box = GetLayoutBoxModelObject();
+ Node* node = GetNode();
- if ((css_box && css_box->IsListItem()) || IsA<HTMLLIElement>(node))
+ if (layout_object_->IsListItem() || IsA<HTMLLIElement>(node))
return ax::mojom::blink::Role::kListItem;
if (layout_object_->IsListMarkerIncludingAll())
return ax::mojom::blink::Role::kListMarker;
@@ -194,13 +191,11 @@ ax::mojom::blink::Role AXLayoutObject::RoleFromLayoutObject(
if (layout_object_->IsTableCell() && node)
return DetermineTableCellRole();
- if (css_box && IsImageOrAltText(css_box, node)) {
+ if (IsImageOrAltText(layout_object_, node)) {
if (node && node->IsLink())
return ax::mojom::blink::Role::kImageMap;
if (IsA<HTMLInputElement>(node))
return ButtonRoleType();
- if (IsSVGImage())
- return ax::mojom::blink::Role::kSvgRoot;
return ax::mojom::blink::Role::kImage;
}
@@ -208,7 +203,7 @@ ax::mojom::blink::Role AXLayoutObject::RoleFromLayoutObject(
if (IsA<HTMLCanvasElement>(node))
return ax::mojom::blink::Role::kCanvas;
- if (IsA<LayoutView>(css_box))
+ if (IsA<LayoutView>(layout_object_))
return ax::mojom::blink::Role::kRootWebArea;
if (layout_object_->IsSVGImage())
@@ -226,8 +221,10 @@ ax::mojom::blink::Role AXLayoutObject::RoleFromLayoutObject(
}
ax::mojom::blink::Role AXLayoutObject::DetermineAccessibilityRole() {
- if (!layout_object_)
+ if (!layout_object_) {
+ NOTREACHED();
return ax::mojom::blink::Role::kUnknown;
+ }
if (GetCSSAltText(GetNode())) {
const ComputedStyle* style = GetNode()->GetComputedStyle();
ContentData* content_data = style->GetContentData();
@@ -285,15 +282,9 @@ Node* AXLayoutObject::GetNodeOrContainingBlockNode() const {
return GetNode();
}
-void AXLayoutObject::Init() {
- AXNodeObject::Init();
-}
-
void AXLayoutObject::Detach() {
AXNodeObject::Detach();
- DetachRemoteSVGRoot();
-
#if DCHECK_IS_ON()
if (layout_object_)
layout_object_->SetHasAXObject(false);
@@ -301,10 +292,6 @@ void AXLayoutObject::Detach() {
layout_object_ = nullptr;
}
-bool AXLayoutObject::IsDetached() const {
- return !layout_object_ || AXObject::IsDetached();
-}
-
bool AXLayoutObject::IsAXLayoutObject() const {
return true;
}
@@ -396,11 +383,16 @@ bool AXLayoutObject::IsRichlyEditable() const {
bool AXLayoutObject::IsLineBreakingObject() const {
if (IsDetached())
- return AXNodeObject::IsLineBreakingObject();
+ return false;
+
+ // Presentational objects should not contribute any of their remove semantic
+ // meaning to the accessibility tree, including to its text representation.
+ if (IsPresentational())
+ return false;
const LayoutObject* layout_object = GetLayoutObject();
if (layout_object->IsBR() || layout_object->IsLayoutBlock() ||
- layout_object->IsAnonymousBlock() ||
+ layout_object->IsTableSection() || layout_object->IsAnonymousBlock() ||
(layout_object->IsLayoutBlockFlow() &&
layout_object->StyleRef().IsDisplayBlockContainer())) {
return true;
@@ -440,82 +432,6 @@ bool AXLayoutObject::IsVisited() const {
// Check object state.
//
-bool AXLayoutObject::IsFocused() const {
- if (!GetDocument())
- return false;
-
- // A web area is represented by the Document node in the DOM tree, which isn't
- // focusable. Check instead if the frame's selection controller is focused.
- if (IsWebArea() &&
- GetDocument()->GetFrame()->Selection().FrameIsFocusedAndActive()) {
- return true;
- }
-
- Element* focused_element = GetDocument()->FocusedElement();
- return focused_element && focused_element == GetElement();
-}
-
-// aria-grabbed is deprecated in WAI-ARIA 1.1.
-AccessibilityGrabbedState AXLayoutObject::IsGrabbed() const {
- if (!SupportsARIADragging())
- return kGrabbedStateUndefined;
-
- const AtomicString& grabbed = GetAttribute(html_names::kAriaGrabbedAttr);
- return EqualIgnoringASCIICase(grabbed, "true") ? kGrabbedStateTrue
- : kGrabbedStateFalse;
-}
-
-AccessibilitySelectedState AXLayoutObject::IsSelected() const {
- if (!GetLayoutObject() || !GetNode() || !IsSubWidget())
- return kSelectedStateUndefined;
-
- // The aria-selected attribute overrides automatic behaviors.
- bool is_selected;
- if (HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kSelected, is_selected))
- return is_selected ? kSelectedStateTrue : kSelectedStateFalse;
-
- // The selection should only follow the focus when the aria-selected attribute
- // is marked as required or implied for this element in the ARIA specs.
- // If this object can't follow the focus, then we can't say that it's selected
- // nor that it's not.
- if (!SelectionShouldFollowFocus())
- return kSelectedStateUndefined;
-
- // Selection follows focus, but ONLY in single selection containers, and only
- // if aria-selected was not present to override.
- return IsSelectedFromFocus() ? kSelectedStateTrue : kSelectedStateFalse;
-}
-
-// In single selection containers, selection follows focus unless aria_selected
-// is set to false. This is only valid for a subset of elements.
-bool AXLayoutObject::IsSelectedFromFocus() const {
- if (!SelectionShouldFollowFocus())
- return false;
-
- // A tab item can also be selected if it is associated to a focused tabpanel
- // via the aria-labelledby attribute.
- if (IsTabItem() && IsTabItemSelected())
- return kSelectedStateTrue;
-
- // If not a single selection container, selection does not follow focus.
- AXObject* container = ContainerWidget();
- if (!container || container->IsMultiSelectable())
- return false;
-
- // If this object is not accessibility focused, then it is not selected from
- // focus.
- AXObject* focused_object = AXObjectCache().FocusedObject();
- if (focused_object != this &&
- (!focused_object || focused_object->ActiveDescendant() != this))
- return false;
-
- // In single selection container and accessibility focused => true if
- // aria-selected wasn't used as an override.
- bool is_selected;
- return !HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kSelected,
- is_selected);
-}
-
// Returns true if the object is marked user-select:none
bool AXLayoutObject::IsNotUserSelectable() const {
if (!GetLayoutObject())
@@ -528,20 +444,6 @@ bool AXLayoutObject::IsNotUserSelectable() const {
return (style->UserSelect() == EUserSelect::kNone);
}
-// Returns true if the node's aria-selected attribute should be set to true
-// when the node is focused. This is true for only a subset of roles.
-bool AXLayoutObject::SelectionShouldFollowFocus() const {
- switch (RoleValue()) {
- case ax::mojom::blink::Role::kListBoxOption:
- case ax::mojom::blink::Role::kMenuListOption:
- case ax::mojom::blink::Role::kTab:
- return true;
- default:
- break;
- }
- return false;
-}
-
//
// Whether objects are ignored, i.e. not included in the tree.
//
@@ -602,11 +504,12 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
#endif
// All nodes must have an unignored parent within their tree under
- // kRootWebArea, so force kRootWebArea to always be unignored.
- if (role_ == ax::mojom::blink::Role::kRootWebArea)
+ // the root node of the web area, so force that node to always be unignored.
+ if (IsWebArea())
return false;
- if (IsA<HTMLHtmlElement>(GetNode()))
+ const Node* node = GetNode();
+ if (IsA<HTMLHtmlElement>(node))
return true;
if (!layout_object_) {
@@ -615,13 +518,9 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
return true;
}
- // Ignore continuations, since those are essentially duplicate copies
- // of inline nodes with blocks inside.
- if (layout_object_->IsElementContinuation()) {
- if (ignored_reasons)
- ignored_reasons->push_back(IgnoredReason(kAXUninteresting));
- return true;
- }
+ // Ignore continuations, they're duplicate copies of inline nodes with blocks
+ // inside. AXObjects are no longer created for these.
+ DCHECK(!layout_object_->IsElementContinuation());
// Check first if any of the common reasons cause this element to be ignored.
AXObjectInclusion default_inclusion = DefaultObjectInclusion(ignored_reasons);
@@ -637,20 +536,14 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
if (semantic_inclusion == kIgnoreObject)
return true;
- if (layout_object_->IsAnonymousBlock() && !IsEditable()) {
- if (ignored_reasons)
- ignored_reasons->push_back(IgnoredReason(kAXUninteresting));
- return true;
- }
-
// A LayoutEmbeddedContent is an iframe element or embedded object element or
// something like that. We don't want to ignore those.
if (layout_object_->IsLayoutEmbeddedContent())
return false;
// Make sure renderers with layers stay in the tree.
- if (GetLayoutObject() && GetLayoutObject()->HasLayer() && GetNode() &&
- GetNode()->hasChildren()) {
+ if (GetLayoutObject() && GetLayoutObject()->HasLayer() && node &&
+ node->hasChildren()) {
if (IsPlaceholder()) {
// Placeholder is already exposed via AX attributes, do not expose as
// child of text input. Therefore, if there is a child of a text input,
@@ -683,21 +576,37 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
return false;
if (layout_object_->IsText()) {
- if (CanIgnoreTextAsEmpty()) {
+ // Ignore TextAlternative of the list marker for SUMMARY because:
+ // - TextAlternatives for disclosure-* are triangle symbol characters used
+ // to visually indicate the expansion state.
+ // - It's redundant. The host DETAILS exposes the expansion state.
+ if (layout_object_->Parent()->IsListMarkerForSummary()) {
if (ignored_reasons)
- ignored_reasons->push_back(IgnoredReason(kAXEmptyText));
+ ignored_reasons->push_back(IgnoredReason(kAXPresentational));
return true;
}
return false;
}
// FIXME(aboxhall): may need to move?
- base::Optional<String> alt_text = GetCSSAltText(GetNode());
+ base::Optional<String> alt_text = GetCSSAltText(node);
if (alt_text)
return alt_text->IsEmpty();
- if (IsWebArea() || layout_object_->IsListMarkerIncludingAll())
+ if (IsWebArea())
+ return false;
+ if (layout_object_->IsListMarkerIncludingAll()) {
+ // Ignore TextAlternative of the list marker for SUMMARY because:
+ // - TextAlternatives for disclosure-* are triangle symbol characters used
+ // to visually indicate the expansion state.
+ // - It's redundant. The host DETAILS exposes the expansion state.
+ if (layout_object_->IsListMarkerForSummary()) {
+ if (ignored_reasons)
+ ignored_reasons->push_back(IgnoredReason(kAXPresentational));
+ return true;
+ }
return false;
+ }
// Positioned elements and scrollable containers are important for
// determining bounding boxes.
@@ -709,9 +618,10 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
// Inner editor element of editable area with empty text provides bounds
// 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()->IsTextControlIncludingNG()) {
- return false;
+ if (node) {
+ const TextControlElement* text_control = EnclosingTextControl(node);
+ if (text_control && text_control->InnerEditorElement() == node)
+ return false;
}
// Ignore layout objects that are block flows with inline children. These
@@ -724,9 +634,8 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
const bool has_any_text = HasLineBox(*block_flow);
// Always include interesting-looking objects.
- if (has_any_text ||
- (GetNode() && GetNode()->HasAnyEventListeners(
- event_util::MouseButtonEventTypes()))) {
+ if (has_any_text || (node && node->HasAnyEventListeners(
+ event_util::MouseButtonEventTypes()))) {
return false;
}
@@ -736,7 +645,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
}
// If setting enabled, do not ignore SVG grouping (<g>) elements.
- if (IsA<SVGGElement>(GetNode())) {
+ if (IsA<SVGGElement>(node)) {
Settings* settings = GetDocument()->GetSettings();
if (settings->GetAccessibilityIncludeSvgGElement()) {
return false;
@@ -750,115 +659,6 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
return true;
}
-bool AXLayoutObject::HasAriaCellRole(Element* elem) const {
- DCHECK(elem);
- const AtomicString& aria_role_str =
- elem->FastGetAttribute(html_names::kRoleAttr);
- if (aria_role_str.IsEmpty())
- return false;
-
- ax::mojom::blink::Role aria_role = AriaRoleToWebCoreRole(aria_role_str);
- return aria_role == ax::mojom::blink::Role::kCell ||
- aria_role == ax::mojom::blink::Role::kColumnHeader ||
- aria_role == ax::mojom::blink::Role::kRowHeader;
-}
-
-// Return true if whitespace is not necessary to keep adjacent_node separate
-// in screen reader output from surrounding nodes.
-bool AXLayoutObject::CanIgnoreSpaceNextTo(LayoutObject* layout,
- bool is_after) const {
- if (!layout)
- return true;
-
- // If adjacent to a whitespace character, the current space can be ignored.
- if (layout->IsText()) {
- auto* layout_text = To<LayoutText>(layout);
- if (layout_text->HasEmptyText())
- return false;
- if (layout_text->GetText().Impl()->ContainsOnlyWhitespaceOrEmpty())
- return true;
- auto adjacent_char =
- is_after ? layout_text->FirstCharacterAfterWhitespaceCollapsing()
- : layout_text->LastCharacterAfterWhitespaceCollapsing();
- return adjacent_char == ' ' || adjacent_char == '\n' ||
- adjacent_char == '\t';
- }
-
- // Keep spaces between images and other visible content.
- if (layout->IsLayoutImage())
- return false;
-
- // Do not keep spaces between blocks.
- if (!layout->IsLayoutInline())
- return true;
-
- // If next to an element that a screen reader will always read separately,
- // the the space can be ignored.
- // Elements that are naturally focusable even without a tabindex tend
- // to be rendered separately even if there is no space between them.
- // Some ARIA roles act like table cells and don't need adjacent whitespace to
- // indicate separation.
- // False negatives are acceptable in that they merely lead to extra whitespace
- // static text nodes.
- // TODO(aleventhal) Do we want this? Is it too hard/complex for Braille/Cvox?
- auto* elem = DynamicTo<Element>(layout->GetNode());
- if (elem && HasAriaCellRole(elem)) {
- return true;
- }
-
- // Test against the appropriate child text node.
- auto* layout_inline = To<LayoutInline>(layout);
- LayoutObject* child =
- is_after ? layout_inline->FirstChild() : layout_inline->LastChild();
- return CanIgnoreSpaceNextTo(child, is_after);
-}
-
-bool AXLayoutObject::CanIgnoreTextAsEmpty() const {
- if (!layout_object_ || !layout_object_->IsText() || !layout_object_->Parent())
- return false;
-
- auto* layout_text = To<LayoutText>(layout_object_);
-
- // Ignore empty text
- if (layout_text->HasEmptyText()) {
- return true;
- }
-
- // Don't ignore node-less text (e.g. list bullets)
- Node* node = GetNode();
- if (!node)
- return false;
-
- // Always keep if anything other than collapsible whitespace.
- if (!layout_text->IsAllCollapsibleWhitespace())
- return false;
-
- // Will now look at sibling nodes.
- // Using "skipping children" methods as we need the closest element to the
- // whitespace markup-wise, e.g. tag1 in these examples:
- // [whitespace] <tag1><tag2>x</tag2></tag1>
- // <span>[whitespace]</span> <tag1><tag2>x</tag2></tag1>
- Node* prev_node = FlatTreeTraversal::PreviousSkippingChildren(*node);
- if (!prev_node)
- return true;
-
- Node* next_node = FlatTreeTraversal::NextSkippingChildren(*node);
- if (!next_node)
- return true;
-
- // Ignore extra whitespace-only text if a sibling will be presented
- // separately by screen readers whether whitespace is there or not.
- if (CanIgnoreSpaceNextTo(prev_node->GetLayoutObject(), false) ||
- CanIgnoreSpaceNextTo(next_node->GetLayoutObject(), true))
- return true;
-
- // Text elements with empty whitespace are returned, because of cases
- // such as <span>Hello</span><span> </span><span>World</span>. Keeping
- // the whitespace-only node means we now correctly expose "Hello World".
- // See crbug.com/435765.
- return false;
-}
-
//
// Properties of static elements.
//
@@ -876,19 +676,38 @@ ax::mojom::blink::ListStyle AXLayoutObject::GetListStyle() const {
if (style_image && !style_image->ErrorOccurred())
return ax::mojom::blink::ListStyle::kImage;
- switch (computed_style->ListStyleType()) {
- case EListStyleType::kNone:
+ // TODO(crbug.com/1166766): Use the 'speak-as' descriptor value following
+ // https://drafts.csswg.org/css-counter-styles-3/#counter-style-speak-as
+ switch (ListMarker::GetListStyleCategory(*GetDocument(), *computed_style)) {
+ case ListMarker::ListStyleCategory::kNone:
return ax::mojom::blink::ListStyle::kNone;
- case EListStyleType::kDisc:
- return ax::mojom::blink::ListStyle::kDisc;
- case EListStyleType::kCircle:
- return ax::mojom::blink::ListStyle::kCircle;
- case EListStyleType::kSquare:
- return ax::mojom::blink::ListStyle::kSquare;
- case EListStyleType::kDecimal:
- case EListStyleType::kDecimalLeadingZero:
- return ax::mojom::blink::ListStyle::kNumeric;
- default:
+ case ListMarker::ListStyleCategory::kSymbol: {
+ const AtomicString& counter_style_name =
+ computed_style->GetListStyleType()->GetCounterStyleName();
+ if (counter_style_name == "disc")
+ return ax::mojom::blink::ListStyle::kDisc;
+ if (counter_style_name == "circle")
+ return ax::mojom::blink::ListStyle::kCircle;
+ if (counter_style_name == "square")
+ return ax::mojom::blink::ListStyle::kSquare;
+ return ax::mojom::blink::ListStyle::kOther;
+ }
+ case ListMarker::ListStyleCategory::kLanguage: {
+ const AtomicString& counter_style_name =
+ computed_style->GetListStyleType()->GetCounterStyleName();
+ if (counter_style_name == "decimal")
+ return ax::mojom::blink::ListStyle::kNumeric;
+ if (counter_style_name == "decimal-leading-zero") {
+ // 'decimal-leading-zero' may be overridden by custom counter styles. We
+ // return kNumeric only when we are using the predefined counter style.
+ if (!RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled() ||
+ ListMarker::GetCounterStyle(*GetDocument(), *computed_style)
+ .IsPredefined())
+ return ax::mojom::blink::ListStyle::kNumeric;
+ }
+ return ax::mojom::blink::ListStyle::kOther;
+ }
+ case ListMarker::ListStyleCategory::kStaticString:
return ax::mojom::blink::ListStyle::kOther;
}
}
@@ -932,134 +751,55 @@ String AXLayoutObject::GetText() const {
return AXNodeObject::GetText();
}
-ax::mojom::blink::WritingDirection AXLayoutObject::GetTextDirection() const {
- if (!GetLayoutObject())
- return AXNodeObject::GetTextDirection();
-
- const ComputedStyle* style = GetLayoutObject()->Style();
- if (!style)
- return AXNodeObject::GetTextDirection();
-
- if (style->IsHorizontalWritingMode()) {
- switch (style->Direction()) {
- case TextDirection::kLtr:
- return ax::mojom::blink::WritingDirection::kLtr;
- case TextDirection::kRtl:
- return ax::mojom::blink::WritingDirection::kRtl;
- }
- } else {
- switch (style->Direction()) {
- case TextDirection::kLtr:
- return ax::mojom::blink::WritingDirection::kTtb;
- case TextDirection::kRtl:
- return ax::mojom::blink::WritingDirection::kBtt;
- }
- }
-
- return AXNodeObject::GetTextDirection();
+static bool ShouldUseLayoutNG(const LayoutObject& layout_object) {
+ return (layout_object.IsInline() || layout_object.IsLayoutInline() ||
+ layout_object.IsText()) &&
+ layout_object.ContainingNGBlockFlow();
}
-ax::mojom::blink::TextPosition AXLayoutObject::GetTextPosition() const {
- if (!GetLayoutObject())
- return AXNodeObject::GetTextPosition();
+// Get the deepest descendant that is included in the tree.
+// |start_object| does not have to be included in the tree.
+// If |first| is true, returns the deepest first descendant.
+// Otherwise, returns the deepest last descendant.
+static AXObject* GetDeepestAXChildInLayoutTree(AXObject* start_object,
+ bool first) {
+ if (!start_object)
+ return nullptr;
- const ComputedStyle* style = GetLayoutObject()->Style();
- if (!style)
- return AXNodeObject::GetTextPosition();
-
- switch (style->VerticalAlign()) {
- case EVerticalAlign::kBaseline:
- case EVerticalAlign::kMiddle:
- case EVerticalAlign::kTextTop:
- case EVerticalAlign::kTextBottom:
- case EVerticalAlign::kTop:
- case EVerticalAlign::kBottom:
- case EVerticalAlign::kBaselineMiddle:
- case EVerticalAlign::kLength:
- return AXNodeObject::GetTextPosition();
- case EVerticalAlign::kSub:
- return ax::mojom::blink::TextPosition::kSubscript;
- case EVerticalAlign::kSuper:
- return ax::mojom::blink::TextPosition::kSuperscript;
- }
-}
+ // Return the deepest last child that is included.
+ // Uses LayoutTreeBuildTraversaler to get children, in order to avoid getting
+ // children unconnected to the line, e.g. via aria-owns. Doing this first also
+ // avoids the issue that |start_object| may not be included in the tree.
+ AXObject* result = start_object;
+ Node* current_node = start_object->GetNode();
+ while (current_node) {
+ current_node = first ? LayoutTreeBuilderTraversal::FirstChild(*current_node)
+ : LayoutTreeBuilderTraversal::LastChild(*current_node);
+ if (!current_node)
+ break;
-static unsigned TextStyleFlag(ax::mojom::blink::TextStyle text_style_enum) {
- return static_cast<unsigned>(1 << static_cast<int>(text_style_enum));
-}
+ AXObject* tentative_child =
+ start_object->AXObjectCache().GetOrCreate(current_node);
-void AXLayoutObject::GetTextStyleAndTextDecorationStyle(
- int32_t* text_style,
- ax::mojom::blink::TextDecorationStyle* text_overline_style,
- ax::mojom::blink::TextDecorationStyle* text_strikethrough_style,
- ax::mojom::blink::TextDecorationStyle* text_underline_style) const {
- if (!GetLayoutObject()) {
- AXNodeObject::GetTextStyleAndTextDecorationStyle(
- text_style, text_overline_style, text_strikethrough_style,
- text_underline_style);
- return;
- }
- const ComputedStyle* style = GetLayoutObject()->Style();
- if (!style) {
- AXNodeObject::GetTextStyleAndTextDecorationStyle(
- text_style, text_overline_style, text_strikethrough_style,
- text_underline_style);
- return;
+ if (tentative_child && tentative_child->AccessibilityIsIncludedInTree())
+ result = tentative_child;
}
- *text_style = 0;
- *text_overline_style = ax::mojom::blink::TextDecorationStyle::kNone;
- *text_strikethrough_style = ax::mojom::blink::TextDecorationStyle::kNone;
- *text_underline_style = ax::mojom::blink::TextDecorationStyle::kNone;
-
- if (style->GetFontWeight() == BoldWeightValue())
- *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kBold);
- if (style->GetFontDescription().Style() == ItalicSlopeValue())
- *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kItalic);
+ // Have reached the end of LayoutTreeBuilderTraversal. From here on, traverse
+ // AXObjects to get deepest descendant of pseudo element or static text,
+ // such as an AXInlineTextBox.
- for (const auto& decoration : style->AppliedTextDecorations()) {
- if (EnumHasFlags(decoration.Lines(), TextDecoration::kOverline)) {
- *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kOverline);
- *text_overline_style =
- TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
- }
- if (EnumHasFlags(decoration.Lines(), TextDecoration::kLineThrough)) {
- *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kLineThrough);
- *text_strikethrough_style =
- TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
- }
- if (EnumHasFlags(decoration.Lines(), TextDecoration::kUnderline)) {
- *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kUnderline);
- *text_underline_style =
- TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
- }
- }
-}
+ // Relevant static text or pseudo element is always included.
+ if (!result->AccessibilityIsIncludedInTree())
+ return nullptr;
-ax::mojom::blink::TextDecorationStyle
-AXLayoutObject::TextDecorationStyleToAXTextDecorationStyle(
- const blink::ETextDecorationStyle text_decoration_style) {
- switch (text_decoration_style) {
- case ETextDecorationStyle::kDashed:
- return ax::mojom::blink::TextDecorationStyle::kDashed;
- case ETextDecorationStyle::kSolid:
- return ax::mojom::blink::TextDecorationStyle::kSolid;
- case ETextDecorationStyle::kDotted:
- return ax::mojom::blink::TextDecorationStyle::kDotted;
- case ETextDecorationStyle::kDouble:
- return ax::mojom::blink::TextDecorationStyle::kDouble;
- case ETextDecorationStyle::kWavy:
- return ax::mojom::blink::TextDecorationStyle::kWavy;
- }
-
- NOTREACHED();
- return ax::mojom::blink::TextDecorationStyle::kNone;
-}
+ // Already a leaf: return current result.
+ if (!result->ChildCountIncludingIgnored())
+ return result;
-static bool ShouldUseLayoutNG(const LayoutObject& layout_object) {
- return (layout_object.IsInline() || layout_object.IsLayoutInline() ||
- layout_object.IsText()) &&
- layout_object.ContainingNGBlockFlow();
+ // Get deepest AXObject descendant.
+ return first ? result->DeepestFirstChildIncludingIgnored()
+ : result->DeepestLastChildIncludingIgnored();
}
// Note: |NextOnLineInternalNG()| returns null when fragment for |layout_object|
@@ -1069,28 +809,54 @@ static bool ShouldUseLayoutNG(const LayoutObject& layout_object) {
// "next" and |back()| instead of "previous" and |front()|.
static AXObject* NextOnLineInternalNG(const AXObject& ax_object) {
DCHECK(!ax_object.IsDetached());
- const LayoutObject& layout_object = *ax_object.GetLayoutObject();
- DCHECK(ShouldUseLayoutNG(layout_object)) << layout_object;
- if (layout_object.IsBoxListMarkerIncludingNG() ||
- !layout_object.IsInLayoutNGInlineFormattingContext())
+ const LayoutObject* layout_object = ax_object.GetLayoutObject();
+ DCHECK(layout_object);
+ DCHECK(ShouldUseLayoutNG(*layout_object)) << layout_object;
+ if (layout_object->IsBoxListMarkerIncludingNG() ||
+ !layout_object->IsInLayoutNGInlineFormattingContext()) {
return nullptr;
+ }
+
NGInlineCursor cursor;
- cursor.MoveTo(layout_object);
- if (!cursor)
- return nullptr;
- for (;;) {
- cursor.MoveToNextInlineLeafOnLine();
- if (!cursor)
+ while (true) {
+ // Try to get cursor for layout_object.
+ cursor.MoveToIncludingCulledInline(*layout_object);
+ if (cursor)
break;
- LayoutObject* runner_layout_object = cursor.CurrentMutableLayoutObject();
- if (AXObject* result =
- ax_object.AXObjectCache().GetOrCreate(runner_layout_object))
- return result;
+
+ // No cursor found: will try get cursor from first layout child.
+ // This can happen on an inline element.
+ LayoutObject* layout_child = layout_object->SlowLastChild();
+ if (!layout_child)
+ break;
+
+ layout_object = layout_child;
+ }
+
+ // Found cursor: use it to find next inline leaf.
+ if (cursor) {
+ cursor.MoveToNextInlineLeafOnLine();
+ if (cursor) {
+ LayoutObject* runner_layout_object = cursor.CurrentMutableLayoutObject();
+ AXObject* result =
+ ax_object.AXObjectCache().GetOrCreate(runner_layout_object);
+ result = GetDeepestAXChildInLayoutTree(result, true);
+ if (result)
+ return result;
+ }
}
- if (!ax_object.ParentObject())
+
+ // We need to ensure that we are at the end of our parent layout object
+ // before attempting to connect to the next AXObject that is on the same
+ // line as its first line.
+ if (layout_object->NextSibling())
+ return nullptr; // Not at end of parent layout object.
+ if (!ax_object.ParentObject()) {
+ NOTREACHED();
return nullptr;
- // Returns next object of parent, since next of |ax_object| isn't appeared on
- // line.
+ }
+
+ // Fallback: Use AX parent's next on line.
return ax_object.ParentObject()->NextOnLine();
}
@@ -1099,85 +865,73 @@ AXObject* AXLayoutObject::NextOnLine() const {
// AXLayoutObjects, regardless of role and tree depth, are connected to the
// next inline text box on the same line. If there is no inline text box, they
// are connected to the next leaf AXObject.
- if (IsDetached())
+ if (IsDetached()) {
+ NOTREACHED();
return nullptr;
+ }
- AXObject* result = nullptr;
if (GetLayoutObject()->IsBoxListMarkerIncludingNG()) {
- // A list marker should be followed by a list item on the same line. The
- // list item might have no text children, so we don't eagerly descend to the
- // inline text box.
- //
- // For example, <li><button aria-label="button"></button></li>.
- //
- // This AXLayoutObject might not be included in the accessibility tree at
- // all, so "RawNextSibling" needs to be used to walk the layout tree.
- result = RawNextSibling();
- } else if (ShouldUseLayoutNG(*GetLayoutObject())) {
- result = NextOnLineInternalNG(*this);
- } else {
- InlineBox* inline_box = nullptr;
- if (GetLayoutObject()->IsBox()) {
- inline_box = To<LayoutBox>(GetLayoutObject())->InlineBoxWrapper();
- } else if (GetLayoutObject()->IsLayoutInline()) {
- // For performance and memory consumption, LayoutInline may ignore some
- // inline-boxes during line layout because they don't actually impact
- // layout. This is known as "culled inline". We have to recursively look
- // to the LayoutInline's children via "LastLineBoxIncludingCulling".
- inline_box =
- To<LayoutInline>(GetLayoutObject())->LastLineBoxIncludingCulling();
- } else if (GetLayoutObject()->IsText()) {
- inline_box = To<LayoutText>(GetLayoutObject())->LastTextBox();
- }
+ // A list marker should be followed by a list item on the same line.
+ // Note that pseudo content is always included in the tree, so
+ // NextSiblingIncludingIgnored() will succeed.
+ return GetDeepestAXChildInLayoutTree(NextSiblingIncludingIgnored(), true);
+ }
- if (!inline_box)
- return nullptr;
+ if (ShouldUseLayoutNG(*GetLayoutObject())) {
+ return NextOnLineInternalNG(*this);
+ }
- for (InlineBox* next = inline_box->NextOnLine(); next;
- next = next->NextOnLine()) {
- LayoutObject* layout_object =
- LineLayoutAPIShim::LayoutObjectFrom(next->GetLineLayoutItem());
- result = AXObjectCache().GetOrCreate(layout_object);
- if (result)
- break;
- }
+ InlineBox* inline_box = nullptr;
+ if (GetLayoutObject()->IsBox()) {
+ inline_box = To<LayoutBox>(GetLayoutObject())->InlineBoxWrapper();
+ } else if (GetLayoutObject()->IsLayoutInline()) {
+ // For performance and memory consumption, LayoutInline may ignore some
+ // inline-boxes during line layout because they don't actually impact
+ // layout. This is known as "culled inline". We have to recursively look
+ // to the LayoutInline's children via "LastLineBoxIncludingCulling".
+ inline_box =
+ To<LayoutInline>(GetLayoutObject())->LastLineBoxIncludingCulling();
+ } else if (GetLayoutObject()->IsText()) {
+ inline_box = To<LayoutText>(GetLayoutObject())->LastTextBox();
+ }
- if (!result) {
- AXObject* parent = ParentObject();
- // Our parent object could have been created based on an ignored inline or
- // inline block spanning multiple lines. We need to ensure that we are
- // really at the end of our parent before attempting to connect to the
- // next AXObject that is on the same line as its last line.
- //
- // For example, look at the following layout tree:
- // LayoutBlockFlow
- // ++LayoutInline
- // ++++LayoutText "Beginning of line one "
- // ++++AnonymousLayoutInline
- // ++++++LayoutText "end of line one"
- // ++++++LayoutBR
- // ++++++LayoutText "Beginning of line two "
- // ++++LayoutText "End of line two"
- //
- // If we are on kStaticText "End of line one", and retrieve the parent
- // AXObject, it will be the anonymous layout inline which actually ends
- // somewhere in the second line, not the first line. Its "NextOnLine"
- // AXObject will be kStaticText "End of line two", which is obviously
- // wrong.
- //
- // Note that we can't use AXObject::IndexInParent() to do this, because
- // for performance reasons we don't define it on objects that are not
- // included in the accessibility tree at all.
- if (parent && !RawNextSibling())
- result = parent->NextOnLine();
- }
+ if (!inline_box)
+ return nullptr;
+
+ for (InlineBox* next = inline_box->NextOnLine(); next;
+ next = next->NextOnLine()) {
+ LayoutObject* layout_object =
+ LineLayoutAPIShim::LayoutObjectFrom(next->GetLineLayoutItem());
+ AXObject* result = AXObjectCache().GetOrCreate(layout_object);
+ result = GetDeepestAXChildInLayoutTree(result, true);
+ if (result)
+ return result;
}
- // For consistency between the forward and backward directions, try to always
- // return leaf nodes.
- if (result && result->ChildCountIncludingIgnored())
- return result->DeepestFirstChildIncludingIgnored();
- return result;
+ // Our parent object could have been created based on an ignored inline or
+ // inline block spanning multiple lines. We need to ensure that we are
+ // really at the end of our parent before attempting to connect to the
+ // next AXObject that is on the same line as its last line.
+ //
+ // For example, look at the following layout tree:
+ // LayoutBlockFlow
+ // ++LayoutInline
+ // ++++LayoutText "Beginning of line one "
+ // ++++AnonymousLayoutInline
+ // ++++++LayoutText "end of line one"
+ // ++++++LayoutBR
+ // ++++++LayoutText "Beginning of line two "
+ // ++++LayoutText "End of line two"
+ //
+ // If we are on kStaticText "End of line one", and retrieve the parent
+ // AXObject, it will be the anonymous layout inline which actually ends
+ // somewhere in the second line, not the first line. Its "NextOnLine"
+ // AXObject will be kStaticText "End of line two", which is obviously
+ // wrong.
+ if (!GetLayoutObject()->NextSibling())
+ return ParentObject()->NextOnLine();
+
+ return nullptr;
}
// Note: |PreviousOnLineInlineNG()| returns null when fragment for
@@ -1187,30 +941,56 @@ AXObject* AXLayoutObject::NextOnLine() const {
// instead of "next" and |back()|.
static AXObject* PreviousOnLineInlineNG(const AXObject& ax_object) {
DCHECK(!ax_object.IsDetached());
- const LayoutObject& layout_object = *ax_object.GetLayoutObject();
- DCHECK(ShouldUseLayoutNG(layout_object)) << layout_object;
- if (layout_object.IsBoxListMarkerIncludingNG() ||
- !layout_object.IsInLayoutNGInlineFormattingContext()) {
+ const LayoutObject* layout_object = ax_object.GetLayoutObject();
+ DCHECK(layout_object);
+ DCHECK(ShouldUseLayoutNG(*layout_object)) << layout_object;
+
+ if (layout_object->IsBoxListMarkerIncludingNG() ||
+ !layout_object->IsInLayoutNGInlineFormattingContext()) {
return nullptr;
}
+
NGInlineCursor cursor;
- cursor.MoveTo(layout_object);
- if (!cursor)
- return nullptr;
- for (;;) {
- cursor.MoveToPreviousInlineLeafOnLine();
- if (!cursor)
+ while (true) {
+ // Try to get cursor for layout_object.
+ cursor.MoveToIncludingCulledInline(*layout_object);
+ if (cursor)
break;
- LayoutObject* earlier_layout_object = cursor.CurrentMutableLayoutObject();
- if (AXObject* result =
- ax_object.AXObjectCache().GetOrCreate(earlier_layout_object)) {
- return result;
+
+ // No cursor found: will try get cursor from first layout child.
+ // This can happen on an inline element.
+ LayoutObject* layout_child = layout_object->SlowFirstChild();
+ if (!layout_child)
+ break;
+
+ layout_object = layout_child;
+ }
+
+ // Found cursor: use it to find previous inline leaf.
+ if (cursor) {
+ cursor.MoveToPreviousInlineLeafOnLine();
+ if (cursor) {
+ LayoutObject* runner_layout_object = cursor.CurrentMutableLayoutObject();
+ AXObject* result =
+ ax_object.AXObjectCache().GetOrCreate(runner_layout_object);
+ result = GetDeepestAXChildInLayoutTree(result, false);
+ if (result)
+ return result;
}
}
- if (!ax_object.ParentObject())
+
+ // We need to ensure that we are at the start of our parent layout object
+ // before attempting to connect to the previous AXObject that is on the same
+ // line as its first line.
+ if (layout_object->PreviousSibling())
+ return nullptr; // Not at start of parent layout object.
+
+ if (!ax_object.ParentObject()) {
+ NOTREACHED();
return nullptr;
- // Returns previous object of parent, since next of |ax_object| isn't appeared
- // on line.
+ }
+
+ // Fallback: Use AX parent's next on line.
return ax_object.ParentObject()->PreviousOnLine();
}
@@ -1219,80 +999,72 @@ AXObject* AXLayoutObject::PreviousOnLine() const {
// all AXLayoutObjects, regardless of role and tree depth, are connected to
// the previous inline text box on the same line. If there is no inline text
// box, they are connected to the previous leaf AXObject.
- if (IsDetached())
+ if (IsDetached()) {
+ NOTREACHED();
return nullptr;
+ }
- AXObject* result = nullptr;
AXObject* previous_sibling = AccessibilityIsIncludedInTree()
? PreviousSiblingIncludingIgnored()
: nullptr;
if (previous_sibling && previous_sibling->GetLayoutObject() &&
previous_sibling->GetLayoutObject()->IsLayoutNGOutsideListMarker()) {
// A list item should be proceeded by a list marker on the same line.
- result = previous_sibling;
- } else if (ShouldUseLayoutNG(*GetLayoutObject())) {
- result = PreviousOnLineInlineNG(*this);
- } else {
- InlineBox* inline_box = nullptr;
- if (GetLayoutObject()->IsBox()) {
- inline_box = To<LayoutBox>(GetLayoutObject())->InlineBoxWrapper();
- } else if (GetLayoutObject()->IsLayoutInline()) {
- // For performance and memory consumption, LayoutInline may ignore some
- // inline-boxes during line layout because they don't actually impact
- // layout. This is known as "culled inline". We have to recursively look
- // to the LayoutInline's children via "FirstLineBoxIncludingCulling".
- inline_box =
- To<LayoutInline>(GetLayoutObject())->FirstLineBoxIncludingCulling();
- } else if (GetLayoutObject()->IsText()) {
- inline_box = To<LayoutText>(GetLayoutObject())->FirstTextBox();
- }
+ return GetDeepestAXChildInLayoutTree(previous_sibling, false);
+ }
- if (!inline_box)
- return nullptr;
+ if (ShouldUseLayoutNG(*GetLayoutObject()))
+ return PreviousOnLineInlineNG(*this);
- for (InlineBox* prev = inline_box->PrevOnLine(); prev;
- prev = prev->PrevOnLine()) {
- LayoutObject* layout_object =
- LineLayoutAPIShim::LayoutObjectFrom(prev->GetLineLayoutItem());
- result = AXObjectCache().GetOrCreate(layout_object);
- if (result)
- break;
- }
+ InlineBox* inline_box = nullptr;
+ if (GetLayoutObject()->IsBox()) {
+ inline_box = To<LayoutBox>(GetLayoutObject())->InlineBoxWrapper();
+ } else if (GetLayoutObject()->IsLayoutInline()) {
+ // For performance and memory consumption, LayoutInline may ignore some
+ // inline-boxes during line layout because they don't actually impact
+ // layout. This is known as "culled inline". We have to recursively look
+ // to the LayoutInline's children via "FirstLineBoxIncludingCulling".
+ inline_box =
+ To<LayoutInline>(GetLayoutObject())->FirstLineBoxIncludingCulling();
+ } else if (GetLayoutObject()->IsText()) {
+ inline_box = To<LayoutText>(GetLayoutObject())->FirstTextBox();
+ }
- if (!result) {
- AXObject* parent = ParentObject();
- // Our parent object could have been created based on an ignored inline or
- // inline block spanning multiple lines. We need to ensure that we are
- // really at the start of our parent before attempting to connect to the
- // previous AXObject that is on the same line as its first line.
- //
- // For example, fook at the following layout tree:
- // LayoutBlockFlow
- // ++LayoutInline
- // ++++LayoutText "Beginning of line one "
- // ++++AnonymousLayoutInline
- // ++++++LayoutText "end of line one"
- // ++++++LayoutBR
- // ++++++LayoutText "Line two"
- //
- // If we are on kStaticText "Line two", and retrieve the parent AXObject,
- // it will be the anonymous layout inline which actually started somewhere
- // in the first line, not the second line. Its "PreviousOnLine" AXObject
- // will be kStaticText "Start of line one", which is obviously wrong.
- //
- // Note that we can't use AXObject::IndexInParent() to do this, because
- // for performance reasons we don't define it on objects that are not
- // included in the accessibility tree at all.
- if (parent && parent->RawFirstChild() == this)
- result = parent->PreviousOnLine();
- }
+ if (!inline_box)
+ return nullptr;
+
+ for (InlineBox* prev = inline_box->PrevOnLine(); prev;
+ prev = prev->PrevOnLine()) {
+ LayoutObject* layout_object =
+ LineLayoutAPIShim::LayoutObjectFrom(prev->GetLineLayoutItem());
+ AXObject* result = AXObjectCache().GetOrCreate(layout_object);
+ result = GetDeepestAXChildInLayoutTree(result, false);
+ if (result)
+ return result;
}
- // For consistency between the forward and backward directions, try to always
- // return leaf nodes.
- if (result && result->ChildCountIncludingIgnored())
- return result->DeepestLastChildIncludingIgnored();
- return result;
+ // Our parent object could have been created based on an ignored inline or
+ // inline block spanning multiple lines. We need to ensure that we are
+ // at the start of our parent layout object before attempting to connect
+ // to the previous AXObject that is on the same line as its first line.
+ //
+ // For example, fook at the following layout tree:
+ // LayoutBlockFlow
+ // ++LayoutInline
+ // ++++LayoutText "Beginning of line one "
+ // ++++AnonymousLayoutInline
+ // ++++++LayoutText "end of line one"
+ // ++++++LayoutBR
+ // ++++++LayoutText "Line two"
+ //
+ // If we are on kStaticText "Line two", and retrieve the parent AXObject,
+ // it will be the anonymous layout inline which actually started somewhere
+ // in the first line, not the second line. Its "PreviousOnLine" AXObject
+ // will be kStaticText "Start of line one", which is obviously wrong.
+ if (!GetLayoutObject()->PreviousSibling())
+ return ParentObject()->PreviousOnLine();
+
+ return nullptr;
}
//
@@ -1303,13 +1075,11 @@ String AXLayoutObject::StringValue() const {
if (!layout_object_)
return String();
- LayoutBoxModelObject* css_box = GetLayoutBoxModelObject();
-
auto* select_element =
DynamicTo<HTMLSelectElement>(layout_object_->GetNode());
- if (css_box && select_element && select_element->UsesMenuList()) {
+ if (select_element && select_element->UsesMenuList()) {
// LayoutMenuList will go straight to the text() of its selected item.
- // This has to be overridden in the case where the selected item has an ARIA
+ // This has to be overridde`he case where the selected item has an ARIA
// label.
int selected_index = select_element->SelectedListIndex();
const HeapVector<Member<HTMLElement>>& list_items =
@@ -1334,8 +1104,11 @@ String AXLayoutObject::StringValue() const {
NOTREACHED();
}
- if (IsTextControl())
+ if (IsTextControl()) {
+ // TODO(https://crbug.com/1165853) For contenteditable, compute on browser
+ // side instead.
return GetText();
+ }
if (layout_object_->IsFileUploadControl())
return To<LayoutFileUploadControl>(layout_object_)->FileTextValue();
@@ -1364,11 +1137,6 @@ String AXLayoutObject::StringValue() const {
return TextFromDescendants(visited, false);
}
- // FIXME: We might need to implement a value here for more types
- // FIXME: It would be better not to advertise a value at all for the types for
- // which we don't implement one; this would require subclassing or making
- // accessibilityAttributeNames do something other than return a single static
- // array.
return String();
}
@@ -1402,7 +1170,7 @@ String AXLayoutObject::TextAlternative(bool recursive,
// No visible rendered text -- must be whitespace.
// Either it is useful whitespace for separating words or not.
if (layout_text->IsAllCollapsibleWhitespace()) {
- if (cached_is_ignored_)
+ if (LastKnownIsIgnoredValue())
return "";
// If no textboxes, this was whitespace at the line's end.
text_alternative = " ";
@@ -1489,10 +1257,9 @@ AXObject* AXLayoutObject::AccessibilityHitTest(const IntPoint& point) const {
}
LayoutObject* obj = node->GetLayoutObject();
- if (!obj)
- return nullptr;
-
AXObject* result = AXObjectCache().GetOrCreate(obj);
+ if (!result)
+ return nullptr;
result->UpdateChildrenIfNecessary();
// Allow the element to perform any hit-testing it might need to do to reach
@@ -1514,296 +1281,6 @@ AXObject* AXLayoutObject::AccessibilityHitTest(const IntPoint& point) const {
return result;
}
-AXObject* AXLayoutObject::ElementAccessibilityHitTest(
- const IntPoint& point) const {
- if (IsSVGImage())
- return RemoteSVGElementHitTest(point);
-
- return AXObject::ElementAccessibilityHitTest(point);
-}
-
-//
-// Low-level accessibility tree exploration, only for use within the
-// accessibility module.
-//
-// LAYOUT TREE WALKING ALGORITHM
-//
-// The fundamental types of elements in the Blink layout tree are block
-// elements and inline elements. It can get a little confusing when
-// an inline element has both inline and block children, for example:
-//
-// <a href="#">
-// Before Block
-// <div>
-// In Block
-// </div>
-// Outside Block
-// </a>
-//
-// Blink wants to maintain the invariant that all of the children of a node
-// are either all block or all inline, so it creates three anonymous blocks:
-//
-// #1 LayoutBlockFlow (anonymous)
-// #2 LayoutInline A continuation=#4
-// #3 LayoutText "Before Block"
-// #4 LayoutBlockFlow (anonymous) continuation=#8
-// #5 LayoutBlockFlow DIV
-// #6 LayoutText "In Block"
-// #7 LayoutBlockFlow (anonymous)
-// #8 LayoutInline A is_continuation
-// #9 LayoutText "Outside Block"
-//
-// For a good explanation of why this is done, see this blog entry. It's
-// describing WebKit in 2007, but the fundamentals haven't changed much.
-//
-// https://webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/
-//
-// Now, it's important to understand that we couldn't just use the layout
-// tree as the accessibility tree as-is, because the div is no longer
-// inside the link! In fact, the link has been split into two different
-// nodes, #2 and #8. Luckily, the layout tree contains continuations to
-// help us untangle situations like this.
-//
-// Here's the algorithm we use to walk the layout tree in order to build
-// the accessibility tree:
-//
-// 1. When computing the first child or next sibling of a node, skip over any
-// LayoutObjects that are continuations.
-//
-// 2. When computing the next sibling of a node and there are no more siblings
-// in the layout tree, see if the parent node has a continuation, and if
-// so follow it and make that the next sibling.
-//
-// 3. When computing the first child of a node that has a continuation but
-// no children in the layout tree, the continuation is the first child.
-//
-// The end result is this tree, which we use as the basis for the
-// accessibility tree.
-//
-// #1 LayoutBlockFlow (anonymous)
-// #2 LayoutInline A
-// #3 LayoutText "Before Block"
-// #4 LayoutBlockFlow (anonymous)
-// #5 LayoutBlockFlow DIV
-// #6 LayoutText "In Block"
-// #8 LayoutInline A is_continuation
-// #9 LayoutText "Outside Block"
-// #7 LayoutBlockFlow (anonymous)
-//
-// This algorithm results in an accessibility tree that preserves containment
-// (i.e. the contents of the link in the example above are descendants of the
-// link node) while including all of the rich layout detail from the layout
-// tree.
-//
-// There are just a couple of other corner cases to walking the layout tree:
-//
-// * Walk tables in table order (thead, tbody, tfoot), which may not match
-// layout order.
-// * Skip CSS first-letter nodes.
-//
-
-// Given a layout object, return the start of the continuation chain.
-static inline LayoutInline* StartOfContinuations(LayoutObject* layout_object) {
- // See LAYOUT TREE WALKING ALGORITHM, above, for more context as to why
- // we need to do this.
-
- // For inline elements, if it's a continuation, the start of the chain
- // is always the primary layout object associated with the node.
- if (layout_object->IsInlineElementContinuation())
- return To<LayoutInline>(layout_object->GetNode()->GetLayoutObject());
-
- // Blocks with a previous continuation always have a next continuation,
- // so we can get the next continuation and do the same trick to get
- // the primary layout object associated with the node.
- auto* layout_block_flow = DynamicTo<LayoutBlockFlow>(layout_object);
- if (layout_block_flow && layout_block_flow->InlineElementContinuation()) {
- auto* result =
- To<LayoutInline>(layout_block_flow->InlineElementContinuation()
- ->GetNode()
- ->GetLayoutObject());
- DCHECK_NE(result, layout_object);
- return result;
- }
-
- return nullptr;
-}
-
-// See LAYOUT TREE WALKING ALGORITHM, above, for details.
-static inline LayoutObject* ParentLayoutObject(LayoutObject* layout_object) {
- if (!layout_object)
- return nullptr;
-
- // If the node is a continuation, the parent is the start of the continuation
- // chain. See LAYOUT TREE WALKING ALGORITHM, above, for more context as to
- // why we need to do this.
- LayoutObject* start_of_conts = StartOfContinuations(layout_object);
- if (start_of_conts)
- return start_of_conts;
-
- // Otherwise just return the parent in the layout tree.
- return layout_object->Parent();
-}
-
-// See LAYOUT TREE WALKING ALGORITHM, above, for details.
-// Return true if this layout object is the continuation of some other
-// layout object.
-static bool IsContinuation(LayoutObject* layout_object) {
- if (layout_object->IsElementContinuation())
- return true;
-
- auto* block_flow = DynamicTo<LayoutBlockFlow>(layout_object);
- return block_flow && block_flow->IsAnonymousBlock() &&
- block_flow->Continuation();
-}
-
-// See LAYOUT TREE WALKING ALGORITHM, above, for details.
-// Return the continuation of this layout object, or nullptr if it doesn't
-// have one.
-LayoutObject* GetContinuation(LayoutObject* layout_object) {
- if (layout_object->IsLayoutInline())
- return To<LayoutInline>(layout_object)->Continuation();
-
- if (auto* block_flow = DynamicTo<LayoutBlockFlow>(layout_object))
- return block_flow->Continuation();
-
- return nullptr;
-}
-
-// See LAYOUT TREE WALKING ALGORITHM, above, for details.
-AXObject* AXLayoutObject::RawFirstChild() const {
- if (!layout_object_)
- return nullptr;
-
- // Walk sections of a table (thead, tbody, tfoot) in visual order.
- // Note: always call RecalcSectionsIfNeeded() before accessing
- // the sections of a LayoutTable.
- if (layout_object_->IsTable()) {
- LayoutNGTableInterface* table =
- ToInterface<LayoutNGTableInterface>(layout_object_);
- table->RecalcSectionsIfNeeded();
- LayoutNGTableSectionInterface* top_section = table->TopSectionInterface();
- return AXObjectCache().GetOrCreate(
- top_section ? top_section->ToMutableLayoutObject() : nullptr);
- }
-
- LayoutObject* first_child = layout_object_->SlowFirstChild();
-
- // CSS first-letter pseudo element is handled as continuation. Returning it
- // will result in duplicated elements.
- auto* fragment = DynamicTo<LayoutTextFragment>(first_child);
- if (fragment && fragment->GetFirstLetterPseudoElement())
- return nullptr;
-
- // Skip over continuations.
- while (first_child && IsContinuation(first_child))
- first_child = first_child->NextSibling();
-
- // If there's a first child that's not a continuation, return that.
- if (first_child)
- return AXObjectCache().GetOrCreate(first_child);
-
- // Finally check if this object has no children but it has a continuation
- // itself - and if so, it's the first child.
- LayoutObject* continuation = GetContinuation(layout_object_);
- if (continuation)
- return AXObjectCache().GetOrCreate(continuation);
-
- return nullptr;
-}
-
-// See LAYOUT TREE WALKING ALGORITHM, above, for details.
-AXObject* AXLayoutObject::RawNextSibling() const {
- if (!layout_object_)
- return nullptr;
-
- // Walk sections of a table (thead, tbody, tfoot) in visual order.
- if (layout_object_->IsTableSection()) {
- const LayoutNGTableSectionInterface* section =
- ToInterface<LayoutNGTableSectionInterface>(layout_object_);
- const LayoutNGTableSectionInterface* section_below =
- section->TableInterface()->SectionBelowInterface(section,
- kSkipEmptySections);
- // const_cast is necessary to avoid creating non-const versions of
- // table interfaces.
- LayoutObject* section_below_layout_object = const_cast<LayoutObject*>(
- section_below ? section_below->ToLayoutObject() : nullptr);
- return AXObjectCache().GetOrCreate(section_below_layout_object);
- }
-
- // If it's not a continuation, just get the next sibling from the
- // layout tree, skipping over continuations.
- if (!IsContinuation(layout_object_)) {
- LayoutObject* next_sibling = layout_object_->NextSibling();
- while (next_sibling && IsContinuation(next_sibling))
- next_sibling = next_sibling->NextSibling();
-
- if (next_sibling)
- return AXObjectCache().GetOrCreate(next_sibling);
- }
-
- // If we've run out of siblings, check to see if the parent of this
- // object has a continuation, and if so, follow it.
- LayoutObject* parent = layout_object_->Parent();
- if (parent) {
- LayoutObject* continuation = GetContinuation(parent);
- if (continuation)
- return AXObjectCache().GetOrCreate(continuation);
- }
-
- return nullptr;
-}
-
-//
-// High-level accessibility tree access.
-//
-
-AXObject* AXLayoutObject::ComputeParent() const {
- DCHECK(!IsDetached());
- if (!layout_object_)
- return nullptr;
-
- if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar)
- return AXObjectCache().GetOrCreate(layout_object_->Parent());
-
- if (GetNode())
- return AXNodeObject::ComputeParent();
-
- LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_);
- if (parent_layout_obj)
- return AXObjectCache().GetOrCreate(parent_layout_obj);
-
- // A WebArea's parent should be the page popup owner, if any, otherwise null.
- if (IsWebArea()) {
- LocalFrame* frame = layout_object_->GetFrame();
- return AXObjectCache().GetOrCreate(frame->PagePopupOwner());
- }
-
- return nullptr;
-}
-
-AXObject* AXLayoutObject::ComputeParentIfExists() const {
- if (!layout_object_)
- return nullptr;
-
- if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar)
- return AXObjectCache().Get(layout_object_->Parent());
-
- if (GetNode())
- return AXNodeObject::ComputeParentIfExists();
-
- LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_);
- if (parent_layout_obj)
- return AXObjectCache().Get(parent_layout_obj);
-
- // A WebArea's parent should be the page popup owner, if any, otherwise null.
- if (IsWebArea()) {
- LocalFrame* frame = layout_object_->GetFrame();
- return AXObjectCache().Get(frame->PagePopupOwner());
- }
-
- return nullptr;
-}
-
bool AXLayoutObject::CanHaveChildren() const {
if (!layout_object_)
return false;
@@ -1818,24 +1295,12 @@ bool AXLayoutObject::CanHaveChildren() const {
// DOM and layout tree access.
//
-Node* AXLayoutObject::GetNode() const {
- return GetLayoutObject() ? GetLayoutObject()->GetNode() : nullptr;
-}
-
Document* AXLayoutObject::GetDocument() const {
if (!GetLayoutObject())
return nullptr;
return &GetLayoutObject()->GetDocument();
}
-LocalFrameView* AXLayoutObject::DocumentFrameView() const {
- if (!GetLayoutObject())
- return nullptr;
-
- // this is the LayoutObject's Document's LocalFrame's LocalFrameView
- return GetLayoutObject()->GetDocument().View();
-}
-
Element* AXLayoutObject::AnchorElement() const {
if (!layout_object_)
return nullptr;
@@ -1880,46 +1345,6 @@ Element* AXLayoutObject::AnchorElement() const {
}
//
-// Modify or take an action on an object.
-//
-
-bool AXLayoutObject::OnNativeSetValueAction(const String& string) {
- if (!GetNode() || !GetNode()->IsElementNode())
- return false;
- if (!layout_object_ || !layout_object_->IsBoxModelObject())
- return false;
-
- auto* layout_object = To<LayoutBoxModelObject>(layout_object_);
- auto* html_input_element = DynamicTo<HTMLInputElement>(*GetNode());
- 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->IsTextAreaIncludingNG());
- text_area_element->setValue(
- string, TextFieldEventBehavior::kDispatchInputAndChangeEvent);
- return true;
- }
-
- if (HasContentEditableAttributeSet()) {
- ExceptionState exception_state(v8::Isolate::GetCurrent(),
- ExceptionState::kExecutionContext, nullptr,
- nullptr);
- To<HTMLElement>(GetNode())->setInnerText(string, exception_state);
- if (exception_state.HadException()) {
- exception_state.ClearException();
- return false;
- }
- return true;
- }
-
- return false;
-}
-
-//
// Notifications that this object may have changed.
//
@@ -1994,12 +1419,6 @@ void AXLayoutObject::HandleAriaExpandedChanged() {
}
}
-bool AXLayoutObject::IsAutofillAvailable() const {
- // Autofill state is stored in AXObjectCache.
- WebAXAutofillState state = AXObjectCache().GetAutofillState(AXObjectID());
- return state == WebAXAutofillState::kAutofillAvailable;
-}
-
void AXLayoutObject::HandleAutofillStateChanged(WebAXAutofillState state) {
// Autofill state is stored in AXObjectCache.
AXObjectCache().SetAutofillState(AXObjectID(), state);
@@ -2161,7 +1580,7 @@ bool AXLayoutObject::IsDataTable() const {
if (row < 5 && row == alternating_row_color_count) {
LayoutObject* layout_row = cell_layout_block->Parent();
if (!layout_row || !layout_row->IsBoxModelObject() ||
- !To<LayoutBoxModelObject>(layout_row)->IsTableRow())
+ !layout_row->IsTableRow())
continue;
const ComputedStyle* row_computed_style = layout_row->Style();
if (!row_computed_style)
@@ -2478,48 +1897,6 @@ AXObject* AXLayoutObject::HeaderObject() const {
// Private.
//
-bool AXLayoutObject::IsTabItemSelected() const {
- if (!IsTabItem() || !GetLayoutObject())
- return false;
-
- Node* node = GetNode();
- if (!node || !node->IsElementNode())
- return false;
-
- // The ARIA spec says a tab item can also be selected if it is aria-labeled by
- // a tabpanel that has keyboard focus inside of it, or if a tabpanel in its
- // aria-controls list has KB focus inside of it.
- AXObject* focused_element = AXObjectCache().FocusedObject();
- if (!focused_element)
- return false;
-
- HeapVector<Member<Element>> elements;
- if (!HasAOMPropertyOrARIAAttribute(AOMRelationListProperty::kControls,
- elements))
- return false;
-
- for (const auto& element : elements) {
- AXObject* tab_panel = AXObjectCache().GetOrCreate(element);
-
- // A tab item should only control tab panels.
- if (!tab_panel ||
- tab_panel->RoleValue() != ax::mojom::blink::Role::kTabPanel) {
- continue;
- }
-
- AXObject* check_focus_element = focused_element;
- // Check if the focused element is a descendant of the element controlled by
- // the tab item.
- while (check_focus_element) {
- if (tab_panel == check_focus_element)
- return true;
- check_focus_element = check_focus_element->ParentObject();
- }
- }
-
- return false;
-}
-
AXObject* AXLayoutObject::AccessibilityImageMapHitTest(
HTMLAreaElement* area,
const IntPoint& point) const {
@@ -2538,34 +1915,4 @@ AXObject* AXLayoutObject::AccessibilityImageMapHitTest(
return nullptr;
}
-void AXLayoutObject::DetachRemoteSVGRoot() {
- if (AXSVGRoot* root = RemoteSVGRootElement())
- root->SetParent(nullptr);
-}
-
-AXObject* AXLayoutObject::RemoteSVGElementHitTest(const IntPoint& point) const {
- AXObject* remote = RemoteSVGRootElement();
- if (!remote)
- return nullptr;
-
- IntSize offset =
- point - RoundedIntPoint(GetBoundsInFrameCoordinates().Location());
- return remote->AccessibilityHitTest(IntPoint(offset));
-}
-
-// The boundingBox for elements within the remote SVG element needs to be offset
-// by its position within the parent page, otherwise they are in relative
-// coordinates only.
-void AXLayoutObject::OffsetBoundingBoxForRemoteSVGElement(
- LayoutRect& rect) const {
- for (AXObject* parent = ParentObject(); parent;
- parent = parent->ParentObject()) {
- if (parent->IsAXSVGRoot()) {
- rect.MoveBy(
- parent->ParentObject()->GetBoundsInFrameCoordinates().Location());
- break;
- }
- }
-}
-
} // namespace blink
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 b00fde59d91..0c4750459da 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
@@ -40,7 +40,6 @@ class AXObjectCacheImpl;
class Element;
class HTMLAreaElement;
class IntPoint;
-class LocalFrameView;
class Node;
class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
@@ -58,31 +57,20 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
Node* GetNodeOrContainingBlockNode() const;
// DOM and layout tree access.
- Node* GetNode() const override;
Document* GetDocument() const override;
- LocalFrameView* DocumentFrameView() const override;
Element* AnchorElement() const override;
protected:
LayoutObject* layout_object_;
- LayoutBoxModelObject* GetLayoutBoxModelObject() const override;
-
- LayoutObject* LayoutObjectForRelativeBounds() const override {
- return layout_object_;
- }
-
//
// Overridden from AXObject.
//
- void Init() override;
void Detach() override;
- bool IsDetached() const override;
bool IsAXLayoutObject() const final;
// Check object role or purpose.
- bool IsAutofillAvailable() const override;
bool IsEditable() const override;
bool IsRichlyEditable() const override;
bool IsLineBreakingObject() const override;
@@ -91,30 +79,16 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
bool IsVisited() const override;
// Check object state.
- bool IsFocused() const override;
- // aria-grabbed is deprecated in WAI-ARIA 1.1.
- AccessibilityGrabbedState IsGrabbed() const override;
- AccessibilitySelectedState IsSelected() const override;
- bool IsSelectedFromFocus() const override;
bool IsNotUserSelectable() const override;
// Whether objects are ignored, i.e. not included in the tree.
AXObjectInclusion DefaultObjectInclusion(
IgnoredReasons* = nullptr) const override;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
- bool CanIgnoreTextAsEmpty() const override;
// Properties of static elements.
ax::mojom::blink::ListStyle GetListStyle() const final;
String GetText() const override;
- ax::mojom::blink::WritingDirection GetTextDirection() const final;
- ax::mojom::blink::TextPosition GetTextPosition() const final;
- void GetTextStyleAndTextDecorationStyle(
- int32_t* text_style,
- ax::mojom::blink::TextDecorationStyle* text_overline_style,
- ax::mojom::blink::TextDecorationStyle* text_strikethrough_style,
- ax::mojom::blink::TextDecorationStyle* text_underline_style) const final;
-
// Inline text boxes.
AXObject* NextOnLine() const override;
AXObject* PreviousOnLine() const override;
@@ -130,22 +104,9 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
AXRelatedObjectVector*,
NameSources*) const override;
- // Modify or take an action on an object.
- bool OnNativeSetValueAction(const String&) override;
-
// Hit testing.
AXObject* AccessibilityHitTest(const IntPoint&) const override;
- AXObject* ElementAccessibilityHitTest(const IntPoint&) const override;
-
- // High-level accessibility tree access. Other modules should only use these
- // functions.
- AXObject* ComputeParent() const override;
- AXObject* ComputeParentIfExists() const override;
- // Low-level accessibility tree exploration, only for use within the
- // accessibility module.
- AXObject* RawFirstChild() const override;
- AXObject* RawNextSibling() const override;
bool CanHaveChildren() const override;
// Notifications that this object may have changed.
@@ -184,23 +145,12 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
ax::mojom::blink::Role dom_role) const override;
private:
- bool IsTabItemSelected() const;
AXObject* AccessibilityImageMapHitTest(HTMLAreaElement*,
const IntPoint&) const;
- void DetachRemoteSVGRoot();
- AXObject* RemoteSVGElementHitTest(const IntPoint&) const;
- void OffsetBoundingBoxForRemoteSVGElement(LayoutRect&) const;
bool FindAllTableCellsWithRole(ax::mojom::blink::Role, AXObjectVector&) const;
LayoutRect ComputeElementRect() const;
- bool CanIgnoreSpaceNextTo(LayoutObject*, bool is_after) const;
- bool HasAriaCellRole(Element*) const;
bool IsPlaceholder() const;
- bool SelectionShouldFollowFocus() const;
-
- static ax::mojom::blink::TextDecorationStyle
- TextDecorationStyleToAXTextDecorationStyle(
- const ETextDecorationStyle text_decoration_style);
DISALLOW_COPY_AND_ASSIGN(AXLayoutObject);
};
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object_test.cc
index 6da054191ef..643eb215423 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object_test.cc
@@ -166,4 +166,54 @@ TEST_F(AXLayoutObjectTest, AccessibilityHitTestShadowDOM) {
run_test(ShadowRootType::kClosed);
}
+// https://crbug.com/1167596
+TEST_F(AXLayoutObjectTest, GetListStyleDecimalLeadingZero) {
+ ScopedCSSAtRuleCounterStyleForTest scope(false);
+
+ using ListStyle = ax::mojom::blink::ListStyle;
+
+ SetBodyInnerHTML(R"HTML(
+ <ul>
+ <li id="target" style="list-style-type: decimal-leading-zero"></li>
+ </ul>
+ )HTML");
+
+ EXPECT_EQ(ListStyle::kNumeric,
+ GetAXObjectByElementId("target")->GetListStyle());
+}
+
+// https://crbug.com/1167596
+TEST_F(AXLayoutObjectTest, GetListStyleDecimalLeadingZeroAsCustomCounterStyle) {
+ ScopedCSSAtRuleCounterStyleForTest scope(true);
+
+ using ListStyle = ax::mojom::blink::ListStyle;
+
+ SetBodyInnerHTML(R"HTML(
+ <ul>
+ <li id="target" style="list-style-type: decimal-leading-zero"></li>
+ </ul>
+ )HTML");
+
+ EXPECT_EQ(ListStyle::kNumeric,
+ GetAXObjectByElementId("target")->GetListStyle());
+}
+// https://crbug.com/1167596
+TEST_F(AXLayoutObjectTest, GetListStyleOverriddenDecimalLeadingZero) {
+ ScopedCSSAtRuleCounterStyleForTest scope(true);
+
+ using ListStyle = ax::mojom::blink::ListStyle;
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ @counter-style decimal-leading-zero { system: extends upper-roman; }
+ </style>
+ <ul>
+ <li id="target" style="list-style-type: decimal-leading-zero"></li>
+ </ul>
+ )HTML");
+
+ EXPECT_EQ(ListStyle::kOther,
+ GetAXObjectByElementId("target")->GetListStyle());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc
deleted file mode 100644
index 576bea195ca..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/modules/accessibility/ax_list.h"
-
-#include "third_party/blink/renderer/core/html/html_ulist_element.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
-
-namespace blink {
-
-AXList::AXList(LayoutObject* layout_object, AXObjectCacheImpl& ax_object_cache)
- : AXLayoutObject(layout_object, ax_object_cache) {}
-
-AXList::~AXList() = default;
-
-bool AXList::ComputeAccessibilityIsIgnored(
- IgnoredReasons* ignored_reasons) const {
- return AccessibilityIsIgnoredByDefault(ignored_reasons);
-}
-
-bool AXList::IsDescriptionList() const {
- if (!layout_object_)
- return false;
-
- Node* node = layout_object_->GetNode();
- return node && node->HasTagName(html_names::kDlTag);
-}
-
-ax::mojom::Role AXList::RoleValue() const {
- if (IsDescriptionList())
- return ax::mojom::Role::kDescriptionList;
-
- return ax::mojom::Role::kList;
-}
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h
deleted file mode 100644
index 3fb9a7f0db0..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_LIST_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_LIST_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
-
-namespace blink {
-
-class AXObjectCacheImpl;
-
-class AXList final : public AXLayoutObject {
- public:
- AXList(LayoutObject*, AXObjectCacheImpl&);
- ~AXList() override;
-
- bool IsList() const override { return true; }
-
- ax::mojom::Role RoleValue() const final;
-
- private:
- bool IsDescriptionList() const;
- bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
-
- DISALLOW_COPY_AND_ASSIGN(AXList);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_LIST_H_
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_element.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
index 7e59e351cda..e12b63f3df3 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_element.cc
@@ -15,6 +15,7 @@ AXObject* AccessibilityMediaElement::Create(
LayoutObject* layout_object,
AXObjectCacheImpl& ax_object_cache) {
DCHECK(layout_object->GetNode());
+ DCHECK(IsA<HTMLMediaElement>(layout_object->GetNode()));
return MakeGarbageCollected<AccessibilityMediaElement>(layout_object,
ax_object_cache);
}
@@ -58,15 +59,26 @@ AXRestriction AccessibilityMediaElement::Restriction() const {
}
bool AccessibilityMediaElement::HasControls() const {
+ if (IsDetached())
+ return false;
+ if (!IsA<HTMLMediaElement>(GetNode()) || !GetNode()->isConnected()) {
+ NOTREACHED() << "Accessible media element not ready: " << GetNode()
+ << " isConnected? " << GetNode()->isConnected();
+ return false;
+ }
return To<HTMLMediaElement>(GetNode())->ShouldShowControls();
}
bool AccessibilityMediaElement::HasEmptySource() const {
+ if (IsDetached())
+ return false;
return To<HTMLMediaElement>(GetNode())->getNetworkState() ==
HTMLMediaElement::kNetworkEmpty;
}
bool AccessibilityMediaElement::IsUnplayable() const {
+ if (IsDetached())
+ return true;
HTMLMediaElement* element =
static_cast<HTMLMediaElement*>(layout_object_->GetNode());
HTMLMediaElement::NetworkState network_state = element->getNetworkState();
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 b0390d8d926..9ce60db6930 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
@@ -57,34 +57,74 @@ bool AXMenuList::OnNativeClickAction() {
return true;
}
-void AXMenuList::ClearChildren() {
- children_dirty_ = false;
+void AXMenuList::Detach() {
+ // Detach() calls ClearChildren(), but AXMenuList::ClearChildren()
+ // detaches the grandchild options, not the child option.
+ AXLayoutObject::Detach();
+ DCHECK_LE(children_.size(), 1U);
+
+ // Clear the popup.
+ if (children_.size()) {
+ children_[0]->DetachFromParent();
+ // Unfortunately, the popup will be left hanging around until
+ // AXObjectCacheImpl() is reset. We cannot remove it here because
+ // this can be called while AXObjectCacheImpl() is detaching all objects,
+ // and the hash map of objects does not allow similtaneous iteration and
+ // removal of objects.
+ // TODO(accessibility) Consider something like this, or something that
+ // marks the object for imminent diposal.
+ // if (!AXObjectCache().IsDisposing()
+ // children_[0]->AXObjectCache().Remove(children_[0]);
+ children_[0]->Detach();
+ children_.clear();
+ }
+}
+
+void AXMenuList::ClearChildren() const {
if (children_.IsEmpty())
return;
- // There's no reason to clear our AXMenuListPopup child. If we get a
- // call to clearChildren, it's because the options might have changed,
- // so call it on our popup.
- DCHECK_EQ(ChildCountIncludingIgnored(), 1);
+ // Unless the menu list is detached, there's no reason to clear our
+ // AXMenuListPopup child. If we get a call to clearChildren, it's because the
+ // options might have changed, so call it on our popup. Clearing the
+ // AXMenuListPopup child would cause additional thrashing and events that the
+ // AT would need to process, potentially causing the AT to believe that the
+ // popup had closed and a new popup and reopened.
+ // The mock AXMenuListPopup child will be cleared when this object is
+ // detached, as it has no use without this object as an owner.
+ DCHECK_EQ(children_.size(), 1U);
children_[0]->ClearChildren();
}
void AXMenuList::AddChildren() {
+#if DCHECK_IS_ON()
DCHECK(!IsDetached());
- have_children_ = true;
-
- AXObjectCacheImpl& cache = AXObjectCache();
- AXObject* popup = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup);
- DCHECK(popup);
+ DCHECK(!is_adding_children_) << " Reentering method on " << GetNode();
+ base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true);
+ // ClearChildren() does not clear the menulist popup chld.
+ DCHECK_LE(children_.size(), 1U)
+ << "Parent still has " << children_.size() << " children before adding:"
+ << "\nParent is " << ToString(true, true) << "\nFirst child is "
+ << children_[0]->ToString(true, true);
+#endif
+
+ DCHECK(children_dirty_);
+ children_dirty_ = false;
- To<AXMockObject>(popup)->SetParent(this);
- if (!popup->AccessibilityIsIncludedInTree()) {
- cache.Remove(popup->AXObjectID());
- return;
+ // Ensure mock AXMenuListPopup exists.
+ if (children_.IsEmpty()) {
+ AXObjectCacheImpl& cache = AXObjectCache();
+ AXObject* popup =
+ cache.CreateAndInit(ax::mojom::blink::Role::kMenuListPopup, this);
+ DCHECK(popup);
+ DCHECK(!popup->IsDetached());
+ DCHECK(popup->CachedParentObject());
+ children_.push_back(popup);
}
- children_.push_back(popup);
- popup->AddChildren();
+ // Update mock AXMenuListPopup children.
+ children_[0]->SetNeedsToUpdateChildren();
+ children_[0]->UpdateChildrenIfNecessary();
}
bool AXMenuList::IsCollapsed() const {
@@ -107,7 +147,10 @@ void AXMenuList::DidUpdateActiveOption(int option_index) {
bool suppress_notifications =
(GetNode() && !GetNode()->IsFinishedParsingChildren());
- if (HasChildren()) {
+ // TODO(aleventhal) The NeedsToUpdateChildren() check is necessary to avoid a
+ // illegal lifecycle while adding children, since this can be called at any
+ // time by AXObjectCacheImpl(). Look into calling with clean layout.
+ if (!NeedsToUpdateChildren()) {
const auto& child_objects = ChildrenIncludingIgnored();
if (!child_objects.IsEmpty()) {
DCHECK_EQ(child_objects.size(), 1ul);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h
index 6a10c075125..548c56d721f 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h
@@ -39,7 +39,8 @@ class AXMenuList final : public AXLayoutObject {
AccessibilityExpanded IsExpanded() const final;
bool OnNativeClickAction() override;
- void ClearChildren() override;
+ void ClearChildren() const override;
+ void Detach() override;
void DidUpdateActiveOption(int option_index);
void DidShowPopup();
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 cdc6fb7778b..6d56cefaa54 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
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h"
#include "third_party/blink/renderer/core/aom/accessible_node.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/modules/accessibility/ax_menu_list.h"
#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h"
@@ -36,66 +37,51 @@ namespace blink {
AXMenuListOption::AXMenuListOption(HTMLOptionElement* element,
AXObjectCacheImpl& ax_object_cache)
- : AXNodeObject(element, ax_object_cache), element_(element) {}
-
-AXMenuListOption::~AXMenuListOption() {
- DCHECK(!element_);
-}
-
-void AXMenuListOption::Detach() {
- element_ = nullptr;
- AXNodeObject::Detach();
-}
-
-LocalFrameView* AXMenuListOption::DocumentFrameView() const {
- if (IsDetached())
- return nullptr;
- return element_->GetDocument().View();
-}
-
-ax::mojom::Role AXMenuListOption::RoleValue() const {
- const AtomicString& aria_role =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole);
- if (aria_role.IsEmpty())
- return ax::mojom::Role::kMenuListOption;
-
- ax::mojom::Role role = AriaRoleToWebCoreRole(aria_role);
- if (role != ax::mojom::Role::kUnknown)
- return role;
- return ax::mojom::Role::kMenuListOption;
-}
+ : AXNodeObject(element, ax_object_cache) {}
Element* AXMenuListOption::ActionElement() const {
- return element_;
+ return GetElement();
}
-AXObject* AXMenuListOption::ComputeParent() const {
+AXObject* AXMenuListOption::ComputeParentImpl() const {
Node* node = GetNode();
- if (!node)
+ if (!node) {
+ NOTREACHED();
return nullptr;
+ }
+
auto* select = To<HTMLOptionElement>(node)->OwnerSelectElement();
- if (!select)
+ if (!select) {
+ NOTREACHED();
return nullptr;
+ }
+
AXObject* select_ax_object = AXObjectCache().GetOrCreate(select);
- if (!select_ax_object)
+ if (!select_ax_object) {
+ NOTREACHED();
return nullptr;
+ }
// This happens if the <select> is not rendered. Return it and move on.
auto* menu_list = DynamicTo<AXMenuList>(select_ax_object);
if (!menu_list)
return select_ax_object;
- if (menu_list->HasChildren()) {
- const auto& child_objects = menu_list->ChildrenIncludingIgnored();
- if (child_objects.IsEmpty())
- return nullptr;
- DCHECK_EQ(child_objects.size(), 1UL);
- DCHECK(IsA<AXMenuListPopup>(child_objects[0].Get()));
- To<AXMenuListPopup>(child_objects[0].Get())->UpdateChildrenIfNecessary();
- } else {
+ // In order to return the popup, which is a mock object, we need to grab
+ // the AXMenuList itself, and get its only child.
+ if (menu_list->NeedsToUpdateChildren())
menu_list->UpdateChildrenIfNecessary();
- }
- return parent_.Get();
+
+ const auto& child_objects = menu_list->ChildrenIncludingIgnored();
+ if (child_objects.IsEmpty())
+ return nullptr;
+ DCHECK_EQ(child_objects.size(), 1UL)
+ << "A menulist must have a single popup child";
+ DCHECK(IsA<AXMenuListPopup>(child_objects[0].Get()));
+ To<AXMenuListPopup>(child_objects[0].Get())->UpdateChildrenIfNecessary();
+
+ // Return the popup child, which is the parent of this AXMenuListOption.
+ return child_objects[0];
}
bool AXMenuListOption::IsVisible() const {
@@ -117,24 +103,28 @@ AccessibilitySelectedState AXMenuListOption::IsSelected() const {
if (!GetNode() || !CanSetSelectedAttribute())
return kSelectedStateUndefined;
- AXMenuListPopup* parent = static_cast<AXMenuListPopup*>(ParentObject());
- if (parent && !parent->IsOffScreen()) {
+ AXObject* parent = ParentObject();
+ if (!parent || !parent->IsMenuListPopup())
+ return kSelectedStateUndefined;
+
+ if (!parent->IsOffScreen()) {
return ((parent->ActiveDescendant() == this) ? kSelectedStateTrue
: kSelectedStateFalse);
}
- return ((element_ && element_->Selected()) ? kSelectedStateTrue
- : kSelectedStateFalse);
+ return To<HTMLOptionElement>(GetNode())->Selected() ? kSelectedStateTrue
+ : kSelectedStateFalse;
}
bool AXMenuListOption::OnNativeClickAction() {
- if (!element_)
+ if (!GetNode())
return false;
if (IsA<AXMenuListPopup>(ParentObject())) {
// Clicking on an option within a menu list should first select that item
// (which should include firing `input` and `change` events), then toggle
// whether the menu list is showing.
- static_cast<HTMLElement*>(element_)->AccessKeyAction(true);
+ GetElement()->AccessKeyAction(
+ SimulatedClickCreationScope::kFromAccessibility);
// Calling OnNativeClickAction on the parent select element will toggle
// it open or closed.
@@ -145,18 +135,17 @@ bool AXMenuListOption::OnNativeClickAction() {
}
bool AXMenuListOption::OnNativeSetSelectedAction(bool b) {
- if (!element_ || !CanSetSelectedAttribute())
+ if (!GetElement() || !CanSetSelectedAttribute())
return false;
- element_->SetSelected(b);
+ To<HTMLOptionElement>(GetElement())->SetSelected(b);
return true;
}
bool AXMenuListOption::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
- if (IsInertOrAriaHidden()) {
- if (ignored_reasons)
- ComputeIsInertOrAriaHidden(ignored_reasons);
+ if (IsDetached()) {
+ NOTREACHED();
return true;
}
@@ -171,21 +160,31 @@ void AXMenuListOption::GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
bool* clips_children) const {
+ DCHECK(!IsDetached());
*out_container = nullptr;
out_bounds_in_container = FloatRect();
out_container_transform.setIdentity();
- AXObject* parent = ParentObject();
- if (!parent)
- return;
- DCHECK(IsA<AXMenuListPopup>(parent));
-
- AXObject* grandparent = parent->ParentObject();
- if (!grandparent)
+ // When a <select> is collapsed, the bounds of its options are the same as
+ // that of the containing <select>.
+ // It is not necessary to compute the bounds of options in an expanded select.
+ // On Mac and Android, the menu list is native and already accessible; those
+ // are the platforms where we need AXMenuList so that the options can be part
+ // of the accessibility tree when collapsed, and there's never going to be a
+ // need to expose the bounds of options on those platforms.
+ // On Windows and Linux, AXObjectCacheImpl::UseAXMenuList() will return false,
+ // and therefore this code should not be reached.
+
+ auto* select = To<HTMLOptionElement>(GetNode())->OwnerSelectElement();
+ AXObject* ax_menu_list = AXObjectCache().GetOrCreate(select);
+ if (!ax_menu_list)
return;
- DCHECK(grandparent->IsMenuList());
- grandparent->GetRelativeBounds(out_container, out_bounds_in_container,
- out_container_transform, clips_children);
+ DCHECK(ax_menu_list->IsMenuList());
+ DCHECK(ax_menu_list->GetLayoutObject());
+ if (ax_menu_list->GetLayoutObject()) {
+ ax_menu_list->GetRelativeBounds(out_container, out_bounds_in_container,
+ out_container_transform, clips_children);
+ }
}
String AXMenuListOption::TextAlternative(bool recursive,
@@ -210,7 +209,7 @@ String AXMenuListOption::TextAlternative(bool recursive,
return text_alternative;
name_from = ax::mojom::NameFrom::kContents;
- text_alternative = element_->DisplayLabel();
+ text_alternative = To<HTMLOptionElement>(GetNode())->DisplayLabel();
if (name_sources) {
name_sources->push_back(NameSource(found_text_alternative));
name_sources->back().type = name_from;
@@ -231,9 +230,4 @@ HTMLSelectElement* AXMenuListOption::ParentSelectNode() const {
return nullptr;
}
-void AXMenuListOption::Trace(Visitor* visitor) const {
- visitor->Trace(element_);
- AXNodeObject::Trace(visitor);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
index 1f917c19a9a..aa6ae5c1da5 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h
@@ -37,20 +37,13 @@ class AXObjectCacheImpl;
class AXMenuListOption final : public AXNodeObject {
public:
AXMenuListOption(HTMLOptionElement*, AXObjectCacheImpl&);
- ~AXMenuListOption() override;
+ ~AXMenuListOption() override = default;
private:
- void Trace(Visitor*) const override;
-
bool IsMenuListOption() const override { return true; }
- Node* GetNode() const override { return element_; }
- void Detach() override;
- bool IsDetached() const override { return !element_; }
- LocalFrameView* DocumentFrameView() const override;
- ax::mojom::Role RoleValue() const override;
bool CanHaveChildren() const override { return false; }
- AXObject* ComputeParent() const override;
+ AXObject* ComputeParentImpl() const override;
Element* ActionElement() const override;
bool IsVisible() const override;
@@ -72,8 +65,6 @@ class AXMenuListOption final : public AXNodeObject {
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
HTMLSelectElement* ParentSelectNode() const;
- Member<HTMLOptionElement> element_;
-
DISALLOW_COPY_AND_ASSIGN(AXMenuListOption);
};
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 b4823a35d5d..335bc775b4a 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
@@ -61,17 +61,14 @@ bool AXMenuListPopup::ComputeAccessibilityIsIgnored(
}
AXMenuListOption* AXMenuListPopup::MenuListOptionAXObject(
- HTMLElement* element) const {
+ HTMLElement* element) {
DCHECK(element);
if (!IsA<HTMLOptionElement>(*element))
return nullptr;
- auto* ax_object =
- DynamicTo<AXMenuListOption>(AXObjectCache().GetOrCreate(element));
- if (!ax_object)
- return nullptr;
+ AXObject* ax_object = AXObjectCache().GetOrCreate(element, this);
- return ax_object;
+ return DynamicTo<AXMenuListOption>(ax_object);
}
int AXMenuListPopup::GetSelectedIndex() const {
@@ -93,7 +90,16 @@ bool AXMenuListPopup::OnNativeClickAction() {
}
void AXMenuListPopup::AddChildren() {
+#if DCHECK_IS_ON()
DCHECK(!IsDetached());
+ DCHECK(!is_adding_children_) << " Reentering method on " << GetNode();
+ base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true);
+ DCHECK_EQ(children_.size(), 0U)
+ << "Parent still has " << children_.size() << " children before adding:"
+ << "\nParent is " << ToString(true, true) << "\nFirst child is "
+ << children_[0]->ToString(true, true);
+#endif
+
if (!parent_)
return;
@@ -101,28 +107,34 @@ void AXMenuListPopup::AddChildren() {
if (!html_select_element)
return;
- have_children_ = true;
+ DCHECK(children_.IsEmpty());
+ DCHECK(children_dirty_);
+ children_dirty_ = false;
if (active_index_ == -1)
active_index_ = GetSelectedIndex();
for (auto* const option_element : html_select_element->GetOptionList()) {
+#if DCHECK_IS_ON()
+ AXObject* ax_preexisting = AXObjectCache().Get(option_element);
+ DCHECK(!ax_preexisting ||
+ !ax_preexisting->AccessibilityIsIncludedInTree() ||
+ !ax_preexisting->CachedParentObject() ||
+ ax_preexisting->CachedParentObject() == this)
+ << "\nChild = " << ax_preexisting->ToString(true, true)
+ << "\n IsAXMenuListOption? " << IsA<AXMenuListOption>(ax_preexisting)
+ << "\nNew parent = " << ToString(true, true)
+ << "\nPreexisting parent = "
+ << ax_preexisting->CachedParentObject()->ToString(true, true);
+#endif
AXMenuListOption* option = MenuListOptionAXObject(option_element);
- if (option) {
+ if (option && option->AccessibilityIsIncludedInTree()) {
+ DCHECK(!option->IsDetached());
children_.push_back(option);
- option->SetParent(this);
}
}
}
-void AXMenuListPopup::UpdateChildrenIfNecessary() {
- if (have_children_ && parent_ && parent_->NeedsToUpdateChildren())
- ClearChildren();
-
- if (!have_children_)
- AddChildren();
-}
-
void AXMenuListPopup::DidUpdateActiveOption(int option_index,
bool fire_notifications) {
UpdateChildrenIfNecessary();
@@ -159,8 +171,7 @@ void AXMenuListPopup::DidHide() {
}
void AXMenuListPopup::DidShow() {
- if (!have_children_)
- AddChildren();
+ UpdateChildrenIfNecessary();
AXObjectCacheImpl& cache = AXObjectCache();
cache.PostNotification(this, ax::mojom::Event::kShow);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h
index a2d74177e23..a51b0a6156c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h
@@ -35,6 +35,7 @@ class AXObjectCacheImpl;
class AXMenuListOption;
class HTMLElement;
+// AXMenuListPopup is the only kind of AXMockObject used in Blink accessibility.
class AXMenuListPopup final : public AXMockObject {
public:
explicit AXMenuListPopup(AXObjectCacheImpl&);
@@ -46,13 +47,12 @@ class AXMenuListPopup final : public AXMockObject {
void DidShow();
void DidHide();
AXObject* ActiveDescendant() final;
- void UpdateChildrenIfNecessary() override;
private:
bool IsMenuListPopup() const override { return true; }
- ax::mojom::Role RoleValue() const override {
- return ax::mojom::Role::kMenuListPopup;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override {
+ return ax::mojom::blink::Role::kMenuListPopup;
}
bool IsVisible() const override;
@@ -60,7 +60,7 @@ class AXMenuListPopup final : public AXMockObject {
void AddChildren() override;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
- AXMenuListOption* MenuListOptionAXObject(HTMLElement*) const;
+ AXMenuListOption* MenuListOptionAXObject(HTMLElement*);
int GetSelectedIndex() const;
// Note that this may be -1 if nothing is selected.
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.cc
index bd136b2d766..ad4dd62d0c4 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.cc
@@ -39,4 +39,14 @@ bool AXMockObject::ComputeAccessibilityIsIgnored(
return AccessibilityIsIgnoredByDefault(ignored_reasons);
}
+Document* AXMockObject::GetDocument() const {
+ return ParentObject() ? ParentObject()->GetDocument() : nullptr;
+}
+
+AXObject* AXMockObject::ComputeParentImpl() const {
+ NOTREACHED()
+ << "Mock objects are explicitly parented until their parent is detached";
+ return nullptr;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.h
index 5e409c075a9..e39de671ead 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_mock_object.h
@@ -34,6 +34,11 @@ namespace blink {
class AXObjectCacheImpl;
+// A mock object is an AXObject defined only by a role, having no backing object
+// such as a node, layout object or AccessibleNode. It must be explicitly added
+// by its parent. The only current type of AXMockObject is an AXMenuListPopup.
+// TODO(accessibility) Remove this class.
+
class MODULES_EXPORT AXMockObject : public AXObject {
protected:
explicit AXMockObject(AXObjectCacheImpl&);
@@ -42,9 +47,14 @@ class MODULES_EXPORT AXMockObject : public AXObject {
~AXMockObject() override;
// AXObject overrides.
- AXObject* ComputeParent() const override { return parent_; }
AXRestriction Restriction() const override { return kRestrictionNone; }
bool IsMockObject() const final { return true; }
+ Document* GetDocument() const override;
+ AXObject* ComputeParentImpl() const override;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override {
+ NOTREACHED();
+ return ax::mojom::blink::Role::kUnknown;
+ }
private:
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
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 cfc03288711..47a6903b267 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
@@ -62,6 +62,8 @@
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
#include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/forms/labels_node_list.h"
@@ -72,6 +74,7 @@
#include "third_party/blink/renderer/core/html/html_dlist_element.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/core/html/html_map_element.h"
#include "third_party/blink/renderer/core/html/html_meter_element.h"
#include "third_party/blink/renderer/core/html/html_plugin_element.h"
#include "third_party/blink/renderer/core/html/html_table_caption_element.h"
@@ -89,6 +92,7 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -98,36 +102,73 @@
#include "third_party/blink/renderer/core/mathml_names.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/svg/svg_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"
#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.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/modules/accessibility/ax_svg_root.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_relation_cache.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
namespace {
+blink::HTMLMapElement* GetMapForImage(blink::LayoutObject* layout_object) {
+ blink::LayoutImage* layout_image =
+ blink::DynamicTo<blink::LayoutImage>(layout_object);
+ if (!layout_image)
+ return nullptr;
+
+ return layout_image->ImageMap();
+}
+
bool IsNeutralWithinTable(blink::AXObject* obj) {
if (!obj)
return false;
ax::mojom::blink::Role role = obj->RoleValue();
return role == ax::mojom::blink::Role::kGroup ||
role == ax::mojom::blink::Role::kGenericContainer ||
- role == ax::mojom::blink::Role::kIgnored ||
role == ax::mojom::blink::Role::kRowGroup;
}
+// Within a table, provide the accessible, semantic parent of |node|,
+// by traversing the DOM tree, ignoring elements that are neutral in a table.
+// Return the AXObject for the ancestor.
+blink::AXObject* GetDOMTableAXAncestor(blink::Node* node,
+ blink::AXObjectCacheImpl& cache) {
+ // Used by code to determine roles of elements inside of an HTML table,
+ // Use DOM to get parent since parent_ is not initialized yet when role is
+ // being computed, and because HTML table structure should not take into
+ // account aria-owns.
+ if (!node)
+ return nullptr;
+
+ while (true) {
+ node = blink::NodeTraversal::Parent(*node);
+ if (!node)
+ return nullptr;
+
+ blink::AXObject* ax_object = cache.GetOrCreate(node);
+ if (ax_object && !IsNeutralWithinTable(ax_object))
+ return ax_object;
+ }
+
+ return nullptr;
+}
+
enum class AXAction {
kActionIncrement = 0,
kActionDecrement,
@@ -159,6 +200,30 @@ blink::KeyboardEvent* CreateKeyboardEvent(
return blink::KeyboardEvent::Create(key, local_dom_window, true);
}
+unsigned TextStyleFlag(ax::mojom::blink::TextStyle text_style_enum) {
+ return static_cast<unsigned>(1 << static_cast<int>(text_style_enum));
+}
+
+ax::mojom::blink::TextDecorationStyle
+TextDecorationStyleToAXTextDecorationStyle(
+ const blink::ETextDecorationStyle text_decoration_style) {
+ switch (text_decoration_style) {
+ case blink::ETextDecorationStyle::kDashed:
+ return ax::mojom::blink::TextDecorationStyle::kDashed;
+ case blink::ETextDecorationStyle::kSolid:
+ return ax::mojom::blink::TextDecorationStyle::kSolid;
+ case blink::ETextDecorationStyle::kDotted:
+ return ax::mojom::blink::TextDecorationStyle::kDotted;
+ case blink::ETextDecorationStyle::kDouble:
+ return ax::mojom::blink::TextDecorationStyle::kDouble;
+ case blink::ETextDecorationStyle::kWavy:
+ return ax::mojom::blink::TextDecorationStyle::kWavy;
+ }
+
+ NOTREACHED();
+ return ax::mojom::blink::TextDecorationStyle::kNone;
+}
+
} // namespace
namespace blink {
@@ -173,7 +238,6 @@ const int kDefaultHeadingLevel = 2;
AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& ax_object_cache)
: AXObject(ax_object_cache),
- children_dirty_(false),
native_role_(ax::mojom::blink::Role::kUnknown),
node_(node) {}
@@ -191,9 +255,15 @@ void AXNodeObject::AlterSliderOrSpinButtonValue(bool increase) {
if (!ValueForRange(&value))
return;
+ // If no step was provided on the element, use a default value.
float step;
- if (!StepValueForRange(&step))
- return;
+ if (!StepValueForRange(&step)) {
+ if (IsNativeSlider() || IsNativeSpinButton()) {
+ step = StepRange().Step().ToString().ToFloat();
+ } else {
+ return;
+ }
+ }
value += increase ? step : -step;
@@ -260,12 +330,6 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics(
return kIgnoreObject;
}
- if (RoleValue() == ax::mojom::blink::Role::kIgnored) {
- if (ignored_reasons)
- ignored_reasons->push_back(IgnoredReason(kAXUninteresting));
- return kIgnoreObject;
- }
-
if (HasInheritedPresentationalRole()) {
if (ignored_reasons) {
const AXObject* inherits_from = InheritsPresentationalRoleFrom();
@@ -355,6 +419,10 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics(
if (IsA<HTMLLabelElement>(node))
return kIncludeObject;
+ // Don't ignored legends, because JAWS uses them to determine redundant text.
+ if (IsA<HTMLLegendElement>(node))
+ return kIncludeObject;
+
// Anything that is content editable should not be ignored.
// However, one cannot just call node->hasEditableStyle() since that will ask
// if its parents are also editable. Only the top level content editable
@@ -369,9 +437,13 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics(
ax::mojom::blink::Role::kContentDeletion,
ax::mojom::blink::Role::kContentInsertion,
ax::mojom::blink::Role::kDetails,
+ ax::mojom::blink::Role::kDescriptionList,
+ ax::mojom::blink::Role::kDescriptionListDetail,
+ ax::mojom::blink::Role::kDescriptionListTerm,
ax::mojom::blink::Role::kDialog,
ax::mojom::blink::Role::kFigcaption,
ax::mojom::blink::Role::kFigure,
+ ax::mojom::blink::Role::kList,
ax::mojom::blink::Role::kListItem,
ax::mojom::blink::Role::kMark,
ax::mojom::blink::Role::kMath,
@@ -387,6 +459,17 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics(
always_included_computed_roles.end())
return kIncludeObject;
+ // Avoid double speech. The ruby text describes pronunciation of the ruby
+ // base, and generally produces redundant screen reader output. Expose it only
+ // as a description on the <ruby> element so that screen reader users can
+ // toggle it on/off as with other descriptions/annotations.
+ if (RoleValue() == ax::mojom::blink::Role::kRubyAnnotation ||
+ (RoleValue() == ax::mojom::blink::Role::kStaticText && ParentObject() &&
+ ParentObject()->RoleValue() ==
+ ax::mojom::blink::Role::kRubyAnnotation)) {
+ return kIgnoreObject;
+ }
+
// If this element has aria attributes on it, it should not be ignored.
if (HasGlobalARIAAttribute())
return kIncludeObject;
@@ -423,7 +506,7 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics(
return kDefaultBehavior;
}
-base::Optional<String> AXNodeObject::GetCSSAltText(Node* node) {
+base::Optional<String> AXNodeObject::GetCSSAltText(const Node* node) {
if (!node || !node->GetComputedStyle() ||
node->GetComputedStyle()->ContentBehavesAsNormal()) {
return base::nullopt;
@@ -459,19 +542,21 @@ bool AXNodeObject::ComputeAccessibilityIsIgnored(
DCHECK(initialized_);
#endif
+ // If we don't have a node, then ignore the node object.
+ // TODO(vmpstr/aleventhal): Investigate how this can happen.
+ if (!GetNode()) {
+ NOTREACHED();
+ return true;
+ }
+
// All nodes must have an unignored parent within their tree under
- // kRootWebArea, so force kRootWebArea to always be unignored.
- if (role_ == ax::mojom::blink::Role::kRootWebArea)
+ // the root node of the web area, so force that node to always be unignored.
+ if (IsWebArea())
return false;
- if (GetLayoutObject()) {
- if (role_ == ax::mojom::blink::Role::kUnknown) {
- if (ignored_reasons)
- ignored_reasons->push_back(IgnoredReason(kAXUninteresting));
- return true;
- }
- return false;
- }
+ DCHECK_NE(role_, ax::mojom::blink::Role::kUnknown);
+ // Use AXLayoutObject::ComputeAccessibilityIsIgnored().
+ DCHECK(!GetLayoutObject());
if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) {
if (DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock(
@@ -506,14 +591,6 @@ bool AXNodeObject::ComputeAccessibilityIsIgnored(
return true;
}
-bool AXNodeObject::CanIgnoreTextAsEmpty() const {
- // Note: it's safe to call AXNodeObject::ComputeAccessibilityIsIgnored,
- // since that has just the logic we need - but note that
- // AXLayoutObject::ComputeAccessibilityIsIgnored calls CanIgnoreTextAsEmpty
- // so that'd create a loop.
- return ComputeAccessibilityIsIgnored();
-}
-
static bool IsListElement(Node* node) {
return IsA<HTMLUListElement>(*node) || IsA<HTMLOListElement>(*node) ||
IsA<HTMLDListElement>(*node);
@@ -531,10 +608,6 @@ static bool IsRequiredOwnedElement(AXObject* parent,
return IsListElement(parent_node);
if (current_role == ax::mojom::blink::Role::kListMarker)
return IsA<HTMLLIElement>(*parent_node);
- if (current_role == ax::mojom::blink::Role::kMenuItemCheckBox ||
- current_role == ax::mojom::blink::Role::kMenuItem ||
- current_role == ax::mojom::blink::Role::kMenuItemRadio)
- return IsA<HTMLMenuElement>(*parent_node);
if (!current_element)
return false;
@@ -561,8 +634,7 @@ const AXObject* AXNodeObject::InheritsPresentationalRoleFrom() const {
// http://www.w3.org/TR/wai-aria/complete#presentation
// ARIA spec says that the user agent MUST apply an inherited role of
- // presentation
- // to any owned elements that do not have an explicit role defined.
+ // presentation to any owned elements that do not have an explicit role.
if (AriaRoleAttribute() != ax::mojom::blink::Role::kUnknown)
return nullptr;
@@ -668,20 +740,18 @@ ax::mojom::blink::Role AXNodeObject::DetermineTableSectionRole() const {
if (!GetElement())
return ax::mojom::blink::Role::kUnknown;
- AXObject* parent = ParentObject();
+ AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache());
if (!parent || !parent->IsTableLikeRole())
return ax::mojom::blink::Role::kGenericContainer;
if (parent->RoleValue() == ax::mojom::blink::Role::kLayoutTable)
- return ax::mojom::blink::Role::kIgnored;
+ return ax::mojom::blink::Role::kGenericContainer;
return ax::mojom::blink::Role::kRowGroup;
}
ax::mojom::blink::Role AXNodeObject::DetermineTableRowRole() const {
- AXObject* parent = ParentObject();
- while (IsNeutralWithinTable(parent))
- parent = parent->ParentObject();
+ AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache());
if (!parent || !parent->IsTableLikeRole())
return ax::mojom::blink::Role::kGenericContainer;
@@ -689,21 +759,17 @@ ax::mojom::blink::Role AXNodeObject::DetermineTableRowRole() const {
if (parent->RoleValue() == ax::mojom::blink::Role::kLayoutTable)
return ax::mojom::blink::Role::kLayoutTableRow;
- if (parent->IsTableLikeRole())
- return ax::mojom::blink::Role::kRow;
-
- return ax::mojom::blink::Role::kGenericContainer;
+ return ax::mojom::blink::Role::kRow;
}
ax::mojom::blink::Role AXNodeObject::DetermineTableCellRole() const {
- AXObject* parent = ParentObject();
+ AXObject* parent = GetDOMTableAXAncestor(GetNode(), AXObjectCache());
if (!parent || !parent->IsTableRowLikeRole())
return ax::mojom::blink::Role::kGenericContainer;
// Ensure table container.
- AXObject* grandparent = parent->ParentObject();
- while (IsNeutralWithinTable(grandparent))
- grandparent = grandparent->ParentObject();
+ AXObject* grandparent =
+ GetDOMTableAXAncestor(parent->GetNode(), AXObjectCache());
if (!grandparent || !grandparent->IsTableLikeRole())
return ax::mojom::blink::Role::kGenericContainer;
@@ -734,12 +800,25 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
if (!GetNode())
return RoleFromLayoutObject(ax::mojom::blink::Role::kUnknown);
- // |HTMLAnchorElement| sets isLink only when it has kHrefAttr.
if (GetNode()->IsLink()) {
- if (IsA<HTMLImageElement>(GetNode()))
- return ax::mojom::blink::Role::kImageMap;
- else
+ if (IsA<HTMLImageElement>(GetNode())) {
+ // If the image will have area children, it is a map, otherwise an image.
+ // Unlike most roles, this may be recomputed again in the lifetime of
+ // |this| object, as children are gained or removed.
+ HTMLMapElement* map_element = GetMapForImage(GetLayoutObject());
+ // Make sure this is the primary image for this <map>. For more details on
+ // multiple images referring to the same map, see AddImageMapChildren().
+ if (map_element && map_element->ImageElement() == GetElement())
+ return ax::mojom::blink::Role::kImageMap;
+ return ax::mojom::blink::Role::kImage;
+ }
+ if (IsA<HTMLImageElement>(GetNode())) {
+ return children_.size() ? ax::mojom::blink::Role::kImageMap
+ : ax::mojom::blink::Role::kImage;
+ } else { // <a href> or <svg:a xlink:href>
+ // |HTMLAnchorElement| sets isLink only when it has kHrefAttr.
return ax::mojom::blink::Role::kLink;
+ }
}
if (IsA<HTMLPortalElement>(*GetNode())) {
@@ -788,22 +867,10 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
const AtomicString& type = input->type();
if (input->DataList() && type != input_type_names::kColor)
return ax::mojom::blink::Role::kTextFieldWithComboBox;
- if (type == input_type_names::kButton) {
- if ((GetNode()->parentNode() &&
- IsA<HTMLMenuElement>(GetNode()->parentNode())) ||
- (ParentObject() &&
- ParentObject()->RoleValue() == ax::mojom::blink::Role::kMenu))
- return ax::mojom::blink::Role::kMenuItem;
+ if (type == input_type_names::kButton)
return ButtonRoleType();
- }
- if (type == input_type_names::kCheckbox) {
- if ((GetNode()->parentNode() &&
- IsA<HTMLMenuElement>(GetNode()->parentNode())) ||
- (ParentObject() &&
- ParentObject()->RoleValue() == ax::mojom::blink::Role::kMenu))
- return ax::mojom::blink::Role::kMenuItemCheckBox;
+ if (type == input_type_names::kCheckbox)
return ax::mojom::blink::Role::kCheckBox;
- }
if (type == input_type_names::kDate)
return ax::mojom::blink::Role::kDate;
if (type == input_type_names::kDatetime ||
@@ -812,14 +879,8 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
return ax::mojom::blink::Role::kDateTime;
if (type == input_type_names::kFile)
return ax::mojom::blink::Role::kButton;
- if (type == input_type_names::kRadio) {
- if ((GetNode()->parentNode() &&
- IsA<HTMLMenuElement>(GetNode()->parentNode())) ||
- (ParentObject() &&
- ParentObject()->RoleValue() == ax::mojom::blink::Role::kMenu))
- return ax::mojom::blink::Role::kMenuItemRadio;
+ if (type == input_type_names::kRadio)
return ax::mojom::blink::Role::kRadioButton;
- }
if (type == input_type_names::kNumber)
return ax::mojom::blink::Role::kSpinButton;
if (input->IsTextButton())
@@ -863,6 +924,16 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
if (IsA<HTMLDivElement>(*GetNode()))
return RoleFromLayoutObject(ax::mojom::blink::Role::kGenericContainer);
+ if (IsA<HTMLMenuElement>(*GetNode()) || IsA<HTMLUListElement>(*GetNode()) ||
+ IsA<HTMLOListElement>(*GetNode())) {
+ // <menu> is a deprecated feature of HTML 5, but is included for semantic
+ // compatibility with HTML3, and may contain list items. Exposing it as an
+ // unordered list works better than the current HTML-AAM recommendaton of
+ // exposing as a role=menu, because if it's just used semantically, it won't
+ // be interactive. If used as a widget, the author must provide role=menu.
+ return ax::mojom::blink::Role::kList;
+ }
+
if (IsA<HTMLMeterElement>(*GetNode()))
return ax::mojom::blink::Role::kMeter;
@@ -1012,8 +1083,10 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
}
ax::mojom::blink::Role AXNodeObject::DetermineAccessibilityRole() {
- if (!GetNode())
+ if (!GetNode()) {
+ NOTREACHED();
return ax::mojom::blink::Role::kUnknown;
+ }
native_role_ = NativeRoleIgnoringAria();
@@ -1038,6 +1111,8 @@ void AXNodeObject::AccessibilityChildrenFromAOMProperty(
for (const auto& element : elements) {
if (AXObject* child = cache.GetOrCreate(element)) {
// Only aria-labelledby and aria-describedby can target hidden elements.
+ if (!child)
+ continue;
if (child->AccessibilityIsIgnored() &&
property != AOMRelationListProperty::kLabeledBy &&
property != AOMRelationListProperty::kDescribedBy) {
@@ -1152,23 +1227,28 @@ Element* AXNodeObject::MouseButtonListener() const {
return nullptr;
}
-void AXNodeObject::Init() {
+void AXNodeObject::Init(AXObject* parent_if_known) {
#if DCHECK_IS_ON()
DCHECK(!initialized_);
initialized_ = true;
#endif
- AXObject::Init();
+ AXObject::Init(parent_if_known);
+
+ DCHECK(node_ ||
+ (GetLayoutObject() &&
+ AXObjectCacheImpl::IsPseudoElementDescendant(*GetLayoutObject())))
+ << "Nodeless AXNodeObject can only exist inside a pseudo element: "
+ << GetLayoutObject();
}
void AXNodeObject::Detach() {
+#if DCHECK_IS_ON()
+ DCHECK(!is_adding_children_) << "Cannot Detach |this| during AddChildren()";
+#endif
AXObject::Detach();
node_ = nullptr;
}
-bool AXNodeObject::IsDetached() const {
- return !node_ || AXObject::IsDetached();
-}
-
bool AXNodeObject::IsAXNodeObject() const {
return true;
}
@@ -1192,6 +1272,12 @@ bool AXNodeObject::IsControllingVideoElement() const {
MediaControlElementsHelper::ToParentMediaElement(node));
}
+bool AXNodeObject::IsAutofillAvailable() const {
+ // Autofill state is stored in AXObjectCache.
+ WebAXAutofillState state = AXObjectCache().GetAutofillState(AXObjectID());
+ return state == WebAXAutofillState::kAutofillAvailable;
+}
+
bool AXNodeObject::IsDefault() const {
if (IsDetached())
return false;
@@ -1296,14 +1382,6 @@ bool AXNodeObject::IsMultiSelectable() const {
return html_select_element && html_select_element->IsMultiple();
}
-bool AXNodeObject::IsNativeCheckboxOrRadio() const {
- if (const auto* input = DynamicTo<HTMLInputElement>(GetNode())) {
- return input->type() == input_type_names::kCheckbox ||
- input->type() == input_type_names::kRadio;
- }
- return false;
-}
-
bool AXNodeObject::IsNativeImage() const {
Node* node = this->GetNode();
if (!node)
@@ -1346,6 +1424,9 @@ bool AXNodeObject::IsNonNativeTextControl() const {
}
bool AXNodeObject::IsOffScreen() const {
+ if (IsDetached())
+ return false;
+ DCHECK(GetNode());
return DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode());
}
@@ -1407,6 +1488,138 @@ bool AXNodeObject::IsClickable() const {
return IsTextControl() || AXObject::IsClickable();
}
+bool AXNodeObject::IsFocused() const {
+ if (!GetDocument())
+ return false;
+
+ // A web area is represented by the Document node in the DOM tree, which isn't
+ // focusable. Check instead if the frame's selection controller is focused.
+ if (IsWebArea() &&
+ GetDocument()->GetFrame()->Selection().FrameIsFocusedAndActive()) {
+ return true;
+ }
+
+ Element* focused_element = GetDocument()->FocusedElement();
+ return focused_element && focused_element == GetElement();
+}
+
+// aria-grabbed is deprecated in WAI-ARIA 1.1.
+AccessibilityGrabbedState AXNodeObject::IsGrabbed() const {
+ if (!SupportsARIADragging())
+ return kGrabbedStateUndefined;
+
+ const AtomicString& grabbed = GetAttribute(html_names::kAriaGrabbedAttr);
+ return EqualIgnoringASCIICase(grabbed, "true") ? kGrabbedStateTrue
+ : kGrabbedStateFalse;
+}
+
+AccessibilitySelectedState AXNodeObject::IsSelected() const {
+ if (!GetNode() || !GetLayoutObject() || !IsSubWidget())
+ return kSelectedStateUndefined;
+
+ // The aria-selected attribute overrides automatic behaviors.
+ bool is_selected;
+ if (HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kSelected, is_selected))
+ return is_selected ? kSelectedStateTrue : kSelectedStateFalse;
+
+ // The selection should only follow the focus when the aria-selected attribute
+ // is marked as required or implied for this element in the ARIA specs.
+ // If this object can't follow the focus, then we can't say that it's selected
+ // nor that it's not.
+ if (!SelectionShouldFollowFocus())
+ return kSelectedStateUndefined;
+
+ // Selection follows focus, but ONLY in single selection containers, and only
+ // if aria-selected was not present to override.
+ return IsSelectedFromFocus() ? kSelectedStateTrue : kSelectedStateFalse;
+}
+
+// In single selection containers, selection follows focus unless aria_selected
+// is set to false. This is only valid for a subset of elements.
+bool AXNodeObject::IsSelectedFromFocus() const {
+ if (!SelectionShouldFollowFocus())
+ return false;
+
+ // A tab item can also be selected if it is associated to a focused tabpanel
+ // via the aria-labelledby attribute.
+ if (IsTabItem() && IsTabItemSelected())
+ return kSelectedStateTrue;
+
+ // If not a single selection container, selection does not follow focus.
+ AXObject* container = ContainerWidget();
+ if (!container || container->IsMultiSelectable())
+ return false;
+
+ // If this object is not accessibility focused, then it is not selected from
+ // focus.
+ AXObject* focused_object = AXObjectCache().FocusedObject();
+ if (focused_object != this &&
+ (!focused_object || focused_object->ActiveDescendant() != this))
+ return false;
+
+ // In single selection container and accessibility focused => true if
+ // aria-selected wasn't used as an override.
+ bool is_selected;
+ return !HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kSelected,
+ is_selected);
+}
+
+// Returns true if the node's aria-selected attribute should be set to true
+// when the node is focused. This is true for only a subset of roles.
+bool AXNodeObject::SelectionShouldFollowFocus() const {
+ switch (RoleValue()) {
+ case ax::mojom::blink::Role::kListBoxOption:
+ case ax::mojom::blink::Role::kMenuListOption:
+ case ax::mojom::blink::Role::kTab:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool AXNodeObject::IsTabItemSelected() const {
+ if (!IsTabItem() || !GetLayoutObject())
+ return false;
+
+ Node* node = GetNode();
+ if (!node || !node->IsElementNode())
+ return false;
+
+ // The ARIA spec says a tab item can also be selected if it is aria-labeled by
+ // a tabpanel that has keyboard focus inside of it, or if a tabpanel in its
+ // aria-controls list has KB focus inside of it.
+ AXObject* focused_element = AXObjectCache().FocusedObject();
+ if (!focused_element)
+ return false;
+
+ HeapVector<Member<Element>> elements;
+ if (!HasAOMPropertyOrARIAAttribute(AOMRelationListProperty::kControls,
+ elements))
+ return false;
+
+ for (const auto& element : elements) {
+ AXObject* tab_panel = AXObjectCache().GetOrCreate(element);
+
+ // A tab item should only control tab panels.
+ if (!tab_panel ||
+ tab_panel->RoleValue() != ax::mojom::blink::Role::kTabPanel) {
+ continue;
+ }
+
+ AXObject* check_focus_element = focused_element;
+ // Check if the focused element is a descendant of the element controlled by
+ // the tab item.
+ while (check_focus_element) {
+ if (tab_panel == check_focus_element)
+ return true;
+ check_focus_element = check_focus_element->ParentObject();
+ }
+ }
+
+ return false;
+}
+
AXRestriction AXNodeObject::Restriction() const {
Element* elem = GetElement();
if (!elem)
@@ -1482,11 +1695,12 @@ AccessibilityExpanded AXNodeObject::IsExpanded() const {
if (GetNode() && IsA<HTMLSummaryElement>(*GetNode())) {
if (GetNode()->parentNode() &&
- IsA<HTMLDetailsElement>(GetNode()->parentNode()))
+ IsA<HTMLDetailsElement>(GetNode()->parentNode())) {
return To<Element>(GetNode()->parentNode())
->FastHasAttribute(html_names::kOpenAttr)
? kExpandedExpanded
: kExpandedCollapsed;
+ }
}
bool expanded = false;
@@ -1497,21 +1711,6 @@ AccessibilityExpanded AXNodeObject::IsExpanded() const {
return kExpandedUndefined;
}
-bool AXNodeObject::IsModal() const {
- if (RoleValue() != ax::mojom::blink::Role::kDialog &&
- RoleValue() != ax::mojom::blink::Role::kAlertDialog)
- return false;
-
- bool modal = false;
- if (HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kModal, modal))
- return modal;
-
- if (GetNode() && IsA<HTMLDialogElement>(*GetNode()))
- return To<Element>(GetNode())->IsInTopLayer();
-
- return false;
-}
-
bool AXNodeObject::IsRequired() const {
auto* form_control = DynamicTo<HTMLFormControlElement>(GetNode());
if (form_control && form_control->IsRequired())
@@ -1653,9 +1852,10 @@ String AXNodeObject::AutoComplete() const {
return String();
}
-void AXNodeObject::GetDocumentMarkers(
- Vector<DocumentMarker::MarkerType>* marker_types,
- Vector<AXRange>* marker_ranges) const {
+// TODO(nektar): Consider removing this method in favor of
+// AXInlineTextBox::GetDocumentMarkers, or add document markers to the tree data
+// instead of nodes objects.
+void AXNodeObject::SerializeMarkerAttributes(ui::AXNodeData* node_data) const {
if (!GetNode() || !GetDocument() || !GetDocument()->View())
return;
@@ -1663,12 +1863,18 @@ void AXNodeObject::GetDocumentMarkers(
if (!text_node)
return;
+ std::vector<int32_t> marker_types;
+ std::vector<int32_t> marker_starts;
+ std::vector<int32_t> marker_ends;
+
// 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(AXRange::RangeOfContents(*this));
+ AXRange range = AXRange::RangeOfContents(*this);
+ marker_types.push_back(ToAXMarkerType(aria_marker_type.value()));
+ marker_starts.push_back(range.Start().TextOffset());
+ marker_ends.push_back(range.End().TextOffset());
}
DocumentMarkerController& marker_controller = GetDocument()->Markers();
@@ -1689,13 +1895,26 @@ void AXNodeObject::GetDocumentMarkers(
continue;
}
- marker_types->push_back(marker->GetType());
- marker_ranges->emplace_back(
+ marker_types.push_back(ToAXMarkerType(marker->GetType()));
+ auto start_pos =
AXPosition::FromPosition(start_position, TextAffinity::kDownstream,
- AXPositionAdjustmentBehavior::kMoveLeft),
+ AXPositionAdjustmentBehavior::kMoveLeft);
+ auto end_pos =
AXPosition::FromPosition(end_position, TextAffinity::kDownstream,
- AXPositionAdjustmentBehavior::kMoveRight));
+ AXPositionAdjustmentBehavior::kMoveRight);
+ marker_starts.push_back(start_pos.TextOffset());
+ marker_ends.push_back(end_pos.TextOffset());
}
+
+ if (marker_types.empty())
+ return;
+
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerTypes, marker_types);
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerStarts, marker_starts);
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kMarkerEnds, marker_ends);
}
AXObject* AXNodeObject::InPageLinkTarget() const {
@@ -1839,7 +2058,107 @@ String AXNodeObject::GetText() const {
}
auto* element = DynamicTo<Element>(node);
- return element ? element->innerText() : String();
+ return element ? element->GetInnerTextWithoutUpdate() : String();
+}
+
+ax::mojom::blink::WritingDirection AXNodeObject::GetTextDirection() const {
+ if (!GetLayoutObject())
+ return AXObject::GetTextDirection();
+
+ const ComputedStyle* style = GetLayoutObject()->Style();
+ if (!style)
+ return AXObject::GetTextDirection();
+
+ if (style->IsHorizontalWritingMode()) {
+ switch (style->Direction()) {
+ case TextDirection::kLtr:
+ return ax::mojom::blink::WritingDirection::kLtr;
+ case TextDirection::kRtl:
+ return ax::mojom::blink::WritingDirection::kRtl;
+ }
+ } else {
+ switch (style->Direction()) {
+ case TextDirection::kLtr:
+ return ax::mojom::blink::WritingDirection::kTtb;
+ case TextDirection::kRtl:
+ return ax::mojom::blink::WritingDirection::kBtt;
+ }
+ }
+
+ return AXNodeObject::GetTextDirection();
+}
+
+ax::mojom::blink::TextPosition AXNodeObject::GetTextPosition() const {
+ if (!GetLayoutObject())
+ return AXObject::GetTextPosition();
+
+ const ComputedStyle* style = GetLayoutObject()->Style();
+ if (!style)
+ return AXObject::GetTextPosition();
+
+ switch (style->VerticalAlign()) {
+ case EVerticalAlign::kBaseline:
+ case EVerticalAlign::kMiddle:
+ case EVerticalAlign::kTextTop:
+ case EVerticalAlign::kTextBottom:
+ case EVerticalAlign::kTop:
+ case EVerticalAlign::kBottom:
+ case EVerticalAlign::kBaselineMiddle:
+ case EVerticalAlign::kLength:
+ return AXObject::GetTextPosition();
+ case EVerticalAlign::kSub:
+ return ax::mojom::blink::TextPosition::kSubscript;
+ case EVerticalAlign::kSuper:
+ return ax::mojom::blink::TextPosition::kSuperscript;
+ }
+}
+
+void AXNodeObject::GetTextStyleAndTextDecorationStyle(
+ int32_t* text_style,
+ ax::mojom::blink::TextDecorationStyle* text_overline_style,
+ ax::mojom::blink::TextDecorationStyle* text_strikethrough_style,
+ ax::mojom::blink::TextDecorationStyle* text_underline_style) const {
+ if (!GetLayoutObject()) {
+ AXObject::GetTextStyleAndTextDecorationStyle(
+ text_style, text_overline_style, text_strikethrough_style,
+ text_underline_style);
+ return;
+ }
+ const ComputedStyle* style = GetLayoutObject()->Style();
+ if (!style) {
+ AXObject::GetTextStyleAndTextDecorationStyle(
+ text_style, text_overline_style, text_strikethrough_style,
+ text_underline_style);
+ return;
+ }
+
+ *text_style = 0;
+ *text_overline_style = ax::mojom::blink::TextDecorationStyle::kNone;
+ *text_strikethrough_style = ax::mojom::blink::TextDecorationStyle::kNone;
+ *text_underline_style = ax::mojom::blink::TextDecorationStyle::kNone;
+
+ if (style->GetFontWeight() == BoldWeightValue())
+ *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kBold);
+ if (style->GetFontDescription().Style() == ItalicSlopeValue())
+ *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kItalic);
+
+ for (const auto& decoration : style->AppliedTextDecorations()) {
+ if (EnumHasFlags(decoration.Lines(), TextDecoration::kOverline)) {
+ *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kOverline);
+ *text_overline_style =
+ TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
+ }
+ if (EnumHasFlags(decoration.Lines(), TextDecoration::kLineThrough)) {
+ *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kLineThrough);
+ *text_strikethrough_style =
+ TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
+ }
+ if (EnumHasFlags(decoration.Lines(), TextDecoration::kUnderline)) {
+ *text_style |= TextStyleFlag(ax::mojom::blink::TextStyle::kUnderline);
+ *text_underline_style =
+ TextDecorationStyleToAXTextDecorationStyle(decoration.Style());
+ }
+ }
}
ax::mojom::blink::TextAlign AXNodeObject::GetTextAlign() const {
@@ -1937,7 +2256,8 @@ String AXNodeObject::ImageDataUrl(const IntSize& max_size) const {
SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.clear(SK_ColorTRANSPARENT);
- canvas.drawImageRect(image, SkRect::MakeIWH(width, height), nullptr);
+ canvas.drawImageRect(image, SkRect::MakeIWH(width, height),
+ SkSamplingOptions());
}
// Copy the bits into a buffer in RGBA_8888 unpremultiplied format
@@ -1990,46 +2310,24 @@ RGBA32 AXNodeObject::ColorValue() const {
return color.Rgb();
}
-RGBA32 AXNodeObject::ComputeBackgroundColor() const {
- if (!GetLayoutObject())
- return AXObject::BackgroundColor();
-
- Color blended_color = Color::kTransparent;
- // Color::blend should be called like this: background.blend(foreground).
- for (LayoutObject* layout_object = GetLayoutObject(); layout_object;
- layout_object = layout_object->Parent()) {
- const AXObject* ax_parent = AXObjectCache().GetOrCreate(layout_object);
- if (ax_parent && ax_parent != this) {
- Color parent_color = ax_parent->BackgroundColor();
- blended_color = parent_color.Blend(blended_color);
- return blended_color.Rgb();
- }
-
- const ComputedStyle* style = layout_object->Style();
- if (!style || !style->HasBackground())
- continue;
+RGBA32 AXNodeObject::BackgroundColor() const {
+ LayoutObject* layout_object = GetLayoutObject();
+ if (!layout_object)
+ return Color::kTransparent;
- Color current_color =
- style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
- blended_color = current_color.Blend(blended_color);
- // Continue blending until we get no transparency.
- if (!blended_color.HasAlpha())
- break;
- }
-
- // If we still have some transparency, blend in the document base color.
- if (blended_color.HasAlpha()) {
+ if (IsWebArea()) {
LocalFrameView* view = DocumentFrameView();
- if (view) {
- Color document_base_color = view->BaseBackgroundColor();
- blended_color = document_base_color.Blend(blended_color);
- } else {
- // Default to a white background.
- blended_color.BlendWithWhite();
- }
+ if (view)
+ return view->BaseBackgroundColor().Rgb();
+ else
+ return Color::kWhite;
}
- return blended_color.Rgb();
+ const ComputedStyle* style = layout_object->Style();
+ if (!style || !style->HasBackground())
+ return Color::kTransparent;
+
+ return style->VisitedDependentColor(GetCSSPropertyBackgroundColor()).Rgb();
}
RGBA32 AXNodeObject::GetColor() const {
@@ -2295,6 +2593,14 @@ bool AXNodeObject::MinValueForRange(float* out_value) const {
bool AXNodeObject::StepValueForRange(float* out_value) const {
if (IsNativeSlider() || IsNativeSpinButton()) {
+ // AT may want to know whether a step value was explicitly provided or not,
+ // so return false if there was not one set.
+ if (!To<HTMLInputElement>(*GetNode())
+ .FastGetAttribute(html_names::kStepAttr)) {
+ *out_value = 0.0f;
+ return false;
+ }
+
auto step =
To<HTMLInputElement>(*GetNode()).CreateStepRange(kRejectAny).Step();
*out_value = step.ToString().ToFloat();
@@ -2491,51 +2797,6 @@ void AXNodeObject::Dropeffects(
}
}
-//
-// ARIA live-region features.
-//
-
-const AtomicString& AXNodeObject::LiveRegionStatus() const {
- DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_assertive,
- ("assertive"));
- DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_polite,
- ("polite"));
- DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_off, ("off"));
-
- const AtomicString& live_region_status =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kLive);
- // These roles have implicit live region status.
- if (live_region_status.IsEmpty()) {
- switch (RoleValue()) {
- case ax::mojom::blink::Role::kAlert:
- return live_region_status_assertive;
- case ax::mojom::blink::Role::kLog:
- case ax::mojom::blink::Role::kStatus:
- return live_region_status_polite;
- case ax::mojom::blink::Role::kTimer:
- case ax::mojom::blink::Role::kMarquee:
- return live_region_status_off;
- default:
- break;
- }
- }
-
- return live_region_status;
-}
-
-const AtomicString& AXNodeObject::LiveRegionRelevant() const {
- DEFINE_STATIC_LOCAL(const AtomicString, default_live_region_relevant,
- ("additions text"));
- const AtomicString& relevant =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRelevant);
-
- // Default aria-relevant = "additions text".
- if (relevant.IsEmpty())
- return default_live_region_relevant;
-
- return relevant;
-}
-
ax::mojom::blink::HasPopup AXNodeObject::HasPopup() const {
const AtomicString& has_popup =
GetAOMPropertyOrARIAAttribute(AOMStringProperty::kHasPopUp);
@@ -2558,9 +2819,8 @@ ax::mojom::blink::HasPopup AXNodeObject::HasPopup() const {
// To provide backward compatibility with ARIA 1.0 content,
// user agents MUST treat an aria-haspopup value of true
// as equivalent to a value of menu.
- // And unknown value also return menu too.
if (EqualIgnoringASCIICase(has_popup, "true") ||
- EqualIgnoringASCIICase(has_popup, "menu") || !has_popup.IsEmpty())
+ EqualIgnoringASCIICase(has_popup, "menu"))
return ax::mojom::blink::HasPopup::kMenu;
}
@@ -2604,6 +2864,46 @@ static bool IsInSameNonInlineBlockFlow(LayoutObject* r1, LayoutObject* r2) {
}
//
+// Modify or take an action on an object.
+//
+
+bool AXNodeObject::OnNativeSetValueAction(const String& string) {
+ if (!GetNode() || !GetNode()->IsElementNode())
+ return false;
+ const LayoutObject* layout_object = GetLayoutObject();
+ if (!layout_object || !layout_object->IsBoxModelObject())
+ return false;
+
+ auto* html_input_element = DynamicTo<HTMLInputElement>(*GetNode());
+ 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->IsTextAreaIncludingNG());
+ text_area_element->setValue(
+ string, TextFieldEventBehavior::kDispatchInputAndChangeEvent);
+ return true;
+ }
+
+ if (HasContentEditableAttributeSet()) {
+ ExceptionState exception_state(v8::Isolate::GetCurrent(),
+ ExceptionState::kUnknownContext, nullptr,
+ nullptr);
+ To<HTMLElement>(GetNode())->setInnerText(string, exception_state);
+ if (exception_state.HadException()) {
+ exception_state.ClearException();
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+//
// New AX name calculation.
//
@@ -2652,47 +2952,29 @@ String AXNodeObject::TextAlternative(bool recursive,
return String();
}
- // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 -- value from control
- if (recursive && CanSetValueAttribute()) {
- // No need to set any name source info in a recursive call.
- if (IsTextControl())
- return GetText();
-
- if (IsRangeValueSupported()) {
- const AtomicString& aria_valuetext =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kValueText);
- if (!aria_valuetext.IsNull())
- return aria_valuetext.GetString();
- float value;
- if (ValueForRange(&value))
- return String::Number(value);
- }
-
- return StringValue();
- }
-
- // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
- // "If the embedded control has role combobox or listbox, return the text
- // alternative of the chosen option."
- if (NameFromSelectedOption(recursive)) {
- StringBuilder accumulated_text;
- AXObjectVector selected_options;
- SelectedOptions(selected_options);
- for (const auto& child : selected_options) {
- if (accumulated_text.length())
- accumulated_text.Append(" ");
- accumulated_text.Append(child->ComputedName());
- }
- return accumulated_text.ToString();
+ // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 -- value from control.
+ // This must occur before 2C, because 2C is not applied if 2E will be:
+ // 2C: "If traversal of the current node is due to recursion and the current
+ // node is an embedded control as defined in step 2E, ignore aria-label and
+ // skip to rule 2E".
+ // Note that 2E only applies the label is for "another widget", therefore, the
+ // value cannot be used to label the original control, even if aria-labelledby
+ // points to itself. The easiest way to check this is by testing whether this
+ // node has already been visited.
+ if (recursive && !visited.Contains(this)) {
+ String value_for_name = GetValueContributionToName();
+ if (!value_for_name.IsNull())
+ return value_for_name;
}
+ // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 -- aria-label.
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
+ // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 -- native markup.
text_alternative =
NativeTextAlternative(visited, name_from, related_objects, name_sources,
&found_text_alternative);
@@ -2702,7 +2984,7 @@ String AXNodeObject::TextAlternative(bool recursive,
if (has_text_alternative && !name_sources)
return text_alternative;
- // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1
+ // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 -- from content.
if (in_aria_labelled_by_traversal || SupportsNameFromContents(recursive)) {
Node* node = GetNode();
if (!IsA<HTMLSelectElement>(node)) { // Avoid option descendant text
@@ -2832,6 +3114,8 @@ String AXNodeObject::TextFromDescendants(AXObjectSet& visited,
HeapVector<Member<AXObject>> owned_children;
AXObjectCache().GetAriaOwnedChildren(this, owned_children);
+ // TODO(aleventhal) Why isn't this just using cached children?
+ AXNodeObject* parent = const_cast<AXNodeObject*>(this);
for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child;
child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
auto* child_text_node = DynamicTo<Text>(child);
@@ -2840,7 +3124,7 @@ String AXNodeObject::TextFromDescendants(AXObjectSet& visited,
// skip over empty text nodes
continue;
}
- AXObject* child_obj = AXObjectCache().GetOrCreate(child);
+ AXObject* child_obj = AXObjectCache().GetOrCreate(child, parent);
if (child_obj && !AXObjectCache().IsAriaOwned(child_obj))
children.push_back(child_obj);
}
@@ -2954,12 +3238,17 @@ void AXNodeObject::GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
bool* clips_children) const {
- if (LayoutObjectForRelativeBounds()) {
+ if (GetLayoutObject()) {
AXObject::GetRelativeBounds(out_container, out_bounds_in_container,
out_container_transform, clips_children);
return;
}
+#if DCHECK_IS_ON()
+ DCHECK(!getting_bounds_) << "GetRelativeBounds reentrant: " << ToString(true);
+ base::AutoReset<bool> reentrancy_protector(&getting_bounds_, true);
+#endif
+
*out_container = nullptr;
out_bounds_in_container = FloatRect();
out_container_transform.setIdentity();
@@ -3023,68 +3312,60 @@ void AXNodeObject::GetRelativeBounds(AXObject** out_container,
}
}
-static Node* GetParentNodeForComputeParent(Node* node) {
- if (!node)
- return nullptr;
-
- return LayoutTreeBuilderTraversal::Parent(*node);
-}
-
-AXObject* AXNodeObject::ComputeParent() const {
- DCHECK(!IsDetached());
- if (Node* parent_node = GetParentNodeForComputeParent(GetNode()))
- return AXObjectCache().GetOrCreate(parent_node);
-
- return nullptr;
-}
-
-AXObject* AXNodeObject::ComputeParentIfExists() const {
- if (Node* parent_node = GetParentNodeForComputeParent(GetNode()))
- return AXObjectCache().Get(parent_node);
-
- return nullptr;
-}
-
-AXObject* AXNodeObject::RawFirstChild() const {
- if (!GetNode())
- return nullptr;
-
- Node* first_child = LayoutTreeBuilderTraversal::FirstChild(*GetNode());
-
- if (!first_child)
- return nullptr;
-
- return AXObjectCache().GetOrCreate(first_child);
-}
-
-AXObject* AXNodeObject::RawNextSibling() const {
- if (!GetNode())
- return nullptr;
+bool AXNodeObject::HasValidHTMLTableStructureAndLayout() const {
+ // Is it a visible <table> with a table-like role and layout?
+ if (!IsTableLikeRole() || !GetLayoutObject() ||
+ !GetLayoutObject()->IsTable() || !IsA<HTMLTableElement>(GetNode()))
+ return false;
- Node* next_sibling = LayoutTreeBuilderTraversal::NextSibling(*GetNode());
- if (!next_sibling)
- return nullptr;
+ // Check for any invalid children, as far as W3C table validity is concerned.
+ // * If no invalid children exist, this will be considered a valid table,
+ // and AddTableChildren() can be used to add the children in rendered order.
+ // * If any invalid children exist, this table will be considered invalid.
+ // In that case the children will still be added via AddNodeChildren(),
+ // so that no content is lost.
+ // See comments in AddTableChildren() for more information about valid tables.
+ for (Element* child = ElementTraversal::FirstChild(*GetElement()); child;
+ child = ElementTraversal::NextSibling(*child)) {
+ if (!IsA<HTMLTableSectionElement>(child) &&
+ !IsA<HTMLTableCaptionElement>(child) &&
+ !child->HasTagName(html_names::kColgroupTag)) {
+ return false;
+ }
+ }
- return AXObjectCache().GetOrCreate(next_sibling);
+ return true;
}
void AXNodeObject::AddTableChildren() {
- if (!IsTableLikeRole() || !GetLayoutObject() || !GetLayoutObject()->IsTable())
- return;
-
- AXObjectCacheImpl& ax_cache = AXObjectCache();
- LayoutNGTableInterface* table =
- ToInterface<LayoutNGTableInterface>(GetLayoutObject());
- if (table)
- table->RecalcSectionsIfNeeded();
- Node* table_node = GetNode();
- if (auto* html_table_element = DynamicTo<HTMLTableElement>(table_node)) {
- if (HTMLTableCaptionElement* caption = html_table_element->caption()) {
- AXObject* caption_object = ax_cache.GetOrCreate(caption);
- if (caption_object && caption_object->AccessibilityIsIncludedInTree())
- children_.push_front(caption_object);
- }
- }
+ // Add the caption (if any) and table sections in the visible order.
+ //
+ // Implementation notes:
+ //
+ // * In a valid table, there is always at least one section child DOM node.
+ // For example, if the HTML of the web page includes <tr>s as direct
+ // children of a <table>, Blink will insert a <tbody> as a child of the
+ // table, and parent of the <tr> elements.
+ //
+ // * Rendered order can differ from DOM order:
+ // The valid DOM order of <table> children is specified here:
+ // https://html.spec.whatwg.org/multipage/tables.html#the-table-element,
+ // "... optionally a caption element, followed by zero or more
+ // colgroup elements, followed optionally by a thead element, followed by
+ // either zero or more tbody elements or one or more tr elements, followed
+ // optionally by a tfoot element"
+ // However, even if the DOM children occur in an incorrect order, Blink
+ // automatically renders them as if they were in the correct order.
+ // The following code ensures that the children are added to the AX tree in
+ // the same order as Blink renders them.
+
+ DCHECK(HasValidHTMLTableStructureAndLayout());
+ auto* html_table_element = To<HTMLTableElement>(GetNode());
+ AddNodeChild(html_table_element->caption());
+ AddNodeChild(html_table_element->tHead());
+ for (Node* node : *html_table_element->tBodies())
+ AddNodeChild(node);
+ AddNodeChild(html_table_element->tFoot());
}
int AXNodeObject::TextOffsetInFormattingContext(int offset) const {
@@ -3179,6 +3460,7 @@ void AXNodeObject::LoadInlineTextBoxes() {
if (GetLayoutObject()->IsText()) {
ClearChildren();
AddInlineTextBoxChildren(true);
+ children_dirty_ = false; // Avoid adding these children twice.
return;
}
@@ -3189,8 +3471,10 @@ void AXNodeObject::LoadInlineTextBoxes() {
void AXNodeObject::AddInlineTextBoxChildren(bool force) {
Document* document = GetDocument();
- if (!document)
+ if (!document) {
+ NOTREACHED();
return;
+ }
Settings* settings = document->GetSettings();
if (!force &&
@@ -3208,105 +3492,129 @@ void AXNodeObject::AddInlineTextBoxChildren(bool force) {
return;
}
+ if (LastKnownIsIgnoredValue()) {
+ // Inline textboxes are included if and only if the parent is unignored.
+ // If the parent is ignored but included in tree, the inline textbox is
+ // still withheld.
+ return;
+ }
+
auto* layout_text = To<LayoutText>(GetLayoutObject());
for (scoped_refptr<AbstractInlineTextBox> box =
layout_text->FirstAbstractInlineTextBox();
box.get(); box = box->NextInlineTextBox()) {
- AXObject* ax_box = AXObjectCache().GetOrCreate(box.get());
- if (!ax_box || !ax_box->AccessibilityIsIncludedInTree())
+ AXObject* ax_box = AXObjectCache().GetOrCreate(box.get(), this);
+ if (!ax_box)
continue;
children_.push_back(ax_box);
- // If |force| is set to true, it means that we are forcing the children to
- // be added without going through the normal tree building mechanism, which
- // would have also set the parent of each child to |this|.
- if (force)
- ax_box->SetParent(this);
}
}
void AXNodeObject::AddValidationMessageChild() {
- if (!IsWebArea())
- return;
- AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfInvalid();
- if (ax_object)
- children_.push_back(ax_object);
+ DCHECK(IsWebArea()) << "Validation message must be child of root";
+ // First child requirement enables easy checking to see if a children changed
+ // event is needed in AXObjectCacheImpl::ValidationMessageObjectIfInvalid().
+ DCHECK_EQ(children_.size(), 0U)
+ << "Validation message must be the first child";
+ AddChildAndCheckIncluded(AXObjectCache().ValidationMessageObjectIfInvalid(
+ /* suppress children changed, already processing that */ false));
}
-// Hidden children are those that are not laid out or visible, but are
-// specifically marked as aria-hidden=false,
-// meaning that they should be exposed to the AX hierarchy.
-void AXNodeObject::AddHiddenChildren() {
- Node* node = this->GetNode();
- if (!node)
+void AXNodeObject::AddImageMapChildren() {
+ HTMLMapElement* map = GetMapForImage(GetLayoutObject());
+ if (!map)
return;
- // First do a quick run through to determine if we have any hidden nodes (most
- // often we will not). If we do have hidden nodes, we need to determine where
- // to insert them so they match DOM order as close as possible.
- bool should_insert_hidden_nodes = false;
- for (Node& child : NodeTraversal::ChildrenOf(*node)) {
- if (!child.GetLayoutObject() && IsNodeAriaVisible(&child)) {
- should_insert_hidden_nodes = true;
- break;
- }
- }
+ HTMLImageElement* curr_image_element = DynamicTo<HTMLImageElement>(GetNode());
+ DCHECK(curr_image_element);
+ DCHECK(curr_image_element->IsLink());
+ String usemap = curr_image_element->FastGetAttribute(html_names::kUsemapAttr);
+ DCHECK(!usemap.IsEmpty());
+
+ // Even though several images can point to the same map via usemap, only
+ // use one reported via HTMLImageMapElement::ImageElement(), which is always
+ // the first image in the DOM that matches the #usemap, even if there are
+ // changes to the DOM. Only allow map children for the primary image.
+ // This avoids two problems:
+ // 1. Focusing the same area but in a different image scrolls the page to
+ // the first image that uses that map. Safari does the same thing, and
+ // Firefox does something similar (but seems to prefer the last image).
+ // 2. When an object has multiple parents, serialization errors occur.
+ // While allowed in the spec, using multiple images with the same map is not
+ // handled well in browsers (problem #1), and serializer support for multiple
+ // parents of the same area children is messy.
+
+ // Get the primary image, which is the first image using this map.
+ HTMLImageElement* primary_image_element = map->ImageElement();
+ DCHECK(primary_image_element);
+#if DCHECK_IS_ON()
+ // Prove that this is the same as getting the first image using this map.
+ String usemap_selector = "img[usemap=\"";
+ usemap_selector = usemap_selector + usemap + "\"]";
+ Element* first_image_with_this_usemap =
+ GetDocument()->QuerySelector(AtomicString(usemap_selector));
+ DCHECK(primary_image_element) << "No match for " << usemap_selector;
+ DCHECK_EQ(primary_image_element, first_image_with_this_usemap);
+#endif
- if (!should_insert_hidden_nodes)
+ // Is this the primary image for this map?
+ if (primary_image_element != curr_image_element) {
+ // No, the current image (for |this|) is not the primary image.
+ // Therefore, do not add area children to it.
+ AXObject* ax_primary_image =
+ AXObjectCache().GetOrCreate(primary_image_element);
+ if (ax_primary_image &&
+ ax_primary_image->ChildCountIncludingIgnored() == 0 &&
+ Traversal<HTMLAreaElement>::FirstWithin(*map)) {
+ // The primary image still needs to add the area children, and there's at
+ // least one to add. Its role also needs to change to kImageMap.
+ // The children change will force the role change as well.
+ AXObjectCache().ChildrenChanged(primary_image_element);
+ // The current image may change role from an image map to an image.
+ // Unlike many role changes, this can be done on the same object.
+ // There's no need to fire a role changed event or MarkDirty because the
+ // only time the role changes is when we're updating children anyway.
+ if (role_ == ax::mojom::blink::Role::kImageMap) {
+ ax_primary_image->ClearChildren(); // Clear the children now.
+ ax_primary_image->UpdateRoleForImage();
+ }
+ }
return;
+ }
- // Iterate through all of the children, including those that may have already
- // been added, and try to insert hidden nodes in the correct place in the DOM
- // order.
- unsigned insertion_index = 0;
- for (Node& child : NodeTraversal::ChildrenOf(*node)) {
- if (child.GetLayoutObject()) {
- // Find out where the last layout sibling is located within children_.
- if (AXObject* child_object =
- AXObjectCache().Get(child.GetLayoutObject())) {
- if (!child_object->AccessibilityIsIncludedInTree()) {
- const auto& children = child_object->ChildrenIncludingIgnored();
- child_object = children.size() ? children.back().Get() : nullptr;
+ // Yes, this is the primary image.
+ HTMLAreaElement* first_area = Traversal<HTMLAreaElement>::FirstWithin(*map);
+ if (first_area) {
+ // If the <area> children were part of a different parent, notify that
+ // parent that its children have changed.
+ if (AXObject* ax_preexisting = AXObjectCache().Get(first_area)) {
+ if (AXObject* ax_previous_parent = ax_preexisting->CachedParentObject()) {
+ DCHECK_NE(ax_previous_parent, this);
+ DCHECK(ax_previous_parent->GetNode());
+ AXObjectCache().ChildrenChangedWithCleanLayout(
+ ax_previous_parent->GetNode(), ax_previous_parent);
+ if (ax_previous_parent->RoleValue() ==
+ ax::mojom::blink::Role::kImageMap) {
+ ax_previous_parent->ClearChildren();
+ ax_previous_parent->UpdateRoleForImage();
}
- if (child_object)
- insertion_index = children_.Find(child_object) + 1;
- continue;
}
}
- if (!IsNodeAriaVisible(&child))
- continue;
-
- unsigned previous_size = children_.size();
- if (insertion_index > previous_size)
- insertion_index = previous_size;
-
- InsertChild(AXObjectCache().GetOrCreate(&child), insertion_index);
- insertion_index += (children_.size() - previous_size);
- }
-}
-
-void AXNodeObject::AddImageMapChildren() {
- LayoutBoxModelObject* css_box = GetLayoutBoxModelObject();
- if (!css_box || !css_box->IsLayoutImage())
- return;
-
- HTMLMapElement* map = To<LayoutImage>(css_box)->ImageMap();
- if (!map)
- return;
+ // Add the area children to |this|.
+ for (HTMLAreaElement& area :
+ Traversal<HTMLAreaElement>::DescendantsOf(*map)) {
+ // Add an <area> element for this child if it has a link and is visible.
+ AddChildAndCheckIncluded(AXObjectCache().GetOrCreate(&area, this));
+ }
- for (HTMLAreaElement& area :
- Traversal<HTMLAreaElement>::DescendantsOf(*map)) {
- // add an <area> element for this child if it has a link
- AXObject* obj = AXObjectCache().GetOrCreate(&area);
- if (obj) {
- auto* area_object = To<AXImageMapLink>(obj);
- DCHECK_NE(area_object->AXObjectID(), 0U);
- if (area_object->AccessibilityIsIncludedInTree()) {
- children_.push_back(area_object);
- } else {
- AXObjectCache().Remove(area_object->AXObjectID());
- }
+ // The current image may change role from an image to an image map.
+ // Unlike many role changes, this can be done on the same object.
+ if (role_ == ax::mojom::blink::Role::kImage) {
+ // There's no need to fire a role changed event or MarkDirty because the
+ // only time the role changes is when we're updating children anyway.
+ UpdateRoleForImage();
}
}
}
@@ -3314,163 +3622,326 @@ void AXNodeObject::AddImageMapChildren() {
void AXNodeObject::AddPopupChildren() {
if (!AXObjectCache().UseAXMenuList()) {
auto* html_select_element = DynamicTo<HTMLSelectElement>(GetNode());
- if (!html_select_element || !html_select_element->UsesMenuList())
- return;
- if (AXObject* ax_popup = html_select_element->PopupRootAXObject())
- children_.push_back(ax_popup);
+ if (html_select_element && html_select_element->UsesMenuList())
+ AddChildAndCheckIncluded(html_select_element->PopupRootAXObject());
return;
}
auto* html_input_element = DynamicTo<HTMLInputElement>(GetNode());
if (!html_input_element)
return;
- if (AXObject* ax_popup = html_input_element->PopupRootAXObject())
- children_.push_back(ax_popup);
+ AddChildAndCheckIncluded(html_input_element->PopupRootAXObject());
}
-AXSVGRoot* AXNodeObject::RemoteSVGRootElement() const {
- // FIXME(dmazzoni): none of this code properly handled multiple references to
- // the same remote SVG document. I'm disabling this support until it can be
- // fixed properly.
- return nullptr;
-}
+bool AXNodeObject::CanAddLayoutChild(LayoutObject& child) {
+ if (child.IsAnonymous())
+ return true;
-void AXNodeObject::AddRemoteSVGChildren() {
- AXSVGRoot* root = RemoteSVGRootElement();
- if (!root)
- return;
+ // An non-anonymous layout object (has a DOM node) is only reached when a
+ // pseudo element is inside another pseudo element.
+ // This is because layout object traversal only occurs for pseudo element
+ // subtrees -- see AXObject::ShouldUseLayoutObjectTraversalForChildren().
+ // The only way a node will occur inside of that subtree is if it's another
+ // pseudo element.
+ DCHECK(child.GetNode()->IsPseudoElement());
- if (!root->AccessibilityIsIncludedInTree()) {
- for (const auto& child : root->ChildrenIncludingIgnored())
- children_.push_back(child);
- } else {
- children_.push_back(root);
- }
+ // Only add this inner pseudo element if it hasn't been added elsewhere.
+ // An example is ::before with ::first-letter.
+ AXObject* ax_preexisting = AXObjectCache().Get(&child);
+ return !ax_preexisting || !ax_preexisting->CachedParentObject() ||
+ ax_preexisting->CachedParentObject() == this;
}
-bool AXNodeObject::ShouldUseLayoutBuilderTraversal() const {
- // TODO(accessibility) Look into having one method of traversal, otherwise
- // it's possible for the same object to become a child of 2 different nodes,
- // e.g. if it has a different layout parent and DOM parent.
-
- // Avoid calling AXNodeObject logic for continuations.
- if (GetLayoutObject() && GetLayoutObject()->IsElementContinuation())
- return false;
+#if DCHECK_IS_ON()
+#define CHECK_NO_OTHER_PARENT_FOR(child) \
+ AXObject* ax_preexisting = AXObjectCache().Get(child); \
+ DCHECK(!ax_preexisting || !ax_preexisting->CachedParentObject() || \
+ ax_preexisting->CachedParentObject() == this) \
+ << "Newly added child can't have a different preexisting parent:" \
+ << "\nChild = " << ax_preexisting->ToString(true, true) \
+ << "\nNew parent = " << ToString(true, true) \
+ << "\nPreexisting parent = " \
+ << ax_preexisting->CachedParentObject()->ToString(true, true);
+#else
+#define CHECK_NO_OTHER_PARENT_FOR(child) (void(0))
+#endif
- Node* node = GetNode();
- if (!node)
- return false;
+void AXNodeObject::AddLayoutChildren() {
+ // Children are added this way only for pseudo-element subtrees.
+ // See AXObject::ShouldUseLayoutObjectTraversalForChildren().
+ DCHECK(GetLayoutObject());
+ LayoutObject* child = GetLayoutObject()->SlowFirstChild();
+ while (child) {
+ DCHECK(AXObjectCacheImpl::IsPseudoElementDescendant(*child));
+ if (CanAddLayoutChild(*child)) {
+ CHECK_NO_OTHER_PARENT_FOR(child);
+ // All added pseudo element desecendants are included in the tree.
+ AddChildAndCheckIncluded(AXObjectCache().GetOrCreate(child, this));
+ }
+ child = child->NextSibling();
+ }
+}
- // <ruby>: special layout handling
- if (IsA<HTMLRubyElement>(*node))
- return false;
+void AXNodeObject::AddNodeChildren() {
+ if (!node_)
+ return;
- // <table>: a thead/tfoot in the middle are bumped to the top/bottom in
- // the layout representation.
- if (IsA<HTMLTableElement>(*node))
- return false;
+ for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child;
+ child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
+ AddNodeChild(child);
+ }
+}
- // Pseudo elements often have text children that are not
- // visited by the LayoutTreeBuilderTraversal class used in DOM traversal.
- // Without this condition, list bullets would not have static text children.
+void AXNodeObject::AddAccessibleNodeChildren() {
Element* element = GetElement();
- if (element && element->IsPseudoElement())
- return false;
-
- return true;
-}
+ if (!element)
+ return;
-void AXNodeObject::AddChildren() {
- if (IsDetached())
+ AccessibleNode* accessible_node = element->ExistingAccessibleNode();
+ if (!accessible_node)
return;
- // If the need to add more children in addition to existing children arises,
- // childrenChanged should have been called, leaving the object with no
- // children.
- DCHECK(!have_children_);
- have_children_ = true;
+ for (const auto& child : accessible_node->GetChildren()) {
+ CHECK_NO_OTHER_PARENT_FOR(child);
+ AddChildAndCheckIncluded(AXObjectCache().GetOrCreate(child, this));
+ }
+}
+void AXNodeObject::AddOwnedChildren() {
AXObjectVector owned_children;
AXObjectCache().GetAriaOwnedChildren(this, owned_children);
- if (ShouldUseLayoutBuilderTraversal()) {
- for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child;
- child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
- if (child->IsMarkerPseudoElement() && AccessibilityIsIgnored())
- continue;
- AXObject* child_obj = AXObjectCache().GetOrCreate(child);
+ DCHECK(owned_children.size() == 0 || AXRelationCache::IsValidOwner(this))
+ << "This object is not allowed to use aria-owns, but is: "
+ << ToString(true, true);
- if (RuntimeEnabledFeatures::AccessibilityExposeIgnoredNodesEnabled() &&
- child_obj &&
- child_obj->RoleValue() == ax::mojom::blink::Role::kStaticText &&
- child_obj->CanIgnoreTextAsEmpty())
- continue;
+ // Always include owned children.
+ for (const auto& owned_child : owned_children) {
+ DCHECK(AXRelationCache::IsValidOwnedChild(owned_child))
+ << "This object is not allowed to be owned, but is: "
+ << owned_child->ToString(true, true);
+ AddChildAndCheckIncluded(owned_child, true);
+ }
+}
- // TODO(crbug.com/1158511) This shouldn't be needed!
- if (IsDetached())
- return;
+void AXNodeObject::AddChildrenImpl() {
+#define CHECK_ATTACHED() \
+ if (IsDetached()) { \
+ NOTREACHED() << "Detached adding children: " << ToString(true, true); \
+ return; \
+ }
- AddChild(child_obj);
- }
- } else {
- for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) {
- if (RuntimeEnabledFeatures::AccessibilityExposeIgnoredNodesEnabled() &&
- obj && obj->RoleValue() == ax::mojom::blink::Role::kStaticText &&
- obj->CanIgnoreTextAsEmpty())
- continue;
+ DCHECK(children_dirty_);
- AddChild(obj);
- }
+ if (!CanHaveChildren()) {
+ NOTREACHED()
+ << "Should not reach AddChildren() if CanHaveChildren() is false "
+ << ToString(true, true);
+ return;
}
- // TODO(crbug.com/1158511) This shouldn't be needed!
- if (IsDetached())
+ if (ui::CanHaveInlineTextBoxChildren(RoleValue())) {
+ AddInlineTextBoxChildren();
+ CHECK_ATTACHED();
+ return;
+ }
+
+ if (IsA<HTMLImageElement>(GetNode())) {
+ AddImageMapChildren();
+ CHECK_ATTACHED();
return;
+ }
+
+ // If validation message exists, always make it the first child of the root,
+ // to enable easy checking of whether it's a known child of the root.
+ if (IsWebArea())
+ AddValidationMessageChild();
+ CHECK_ATTACHED();
+
+ if (HasValidHTMLTableStructureAndLayout())
+ AddTableChildren();
+ else if (ShouldUseLayoutObjectTraversalForChildren())
+ AddLayoutChildren();
+ else
+ AddNodeChildren();
+ CHECK_ATTACHED();
- AddHiddenChildren();
AddPopupChildren();
- AddRemoteSVGChildren();
- AddImageMapChildren();
- AddTableChildren();
- AddInlineTextBoxChildren(false);
- AddValidationMessageChild();
+ CHECK_ATTACHED();
+
AddAccessibleNodeChildren();
+ CHECK_ATTACHED();
- for (const auto& owned_child : owned_children)
- AddChild(owned_child, true);
+ AddOwnedChildren();
+ CHECK_ATTACHED();
+}
+void AXNodeObject::AddChildren() {
+#if DCHECK_IS_ON()
+ DCHECK(!IsDetached());
+ DCHECK(!is_adding_children_) << " Reentering method on " << GetNode();
+ base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true);
+ // If the need to add more children in addition to existing children arises,
+ // childrenChanged should have been called, which leads to children_dirty_
+ // being true, then UpdateChildrenIfNecessary() clears the children before
+ // calling AddChildren().
+ DCHECK_EQ(children_.size(), 0U)
+ << "\nParent still has " << children_.size() << " children before adding:"
+ << "\nParent is " << ToString(true, true) << "\nFirst child is "
+ << children_[0]->ToString(true, true);
+#endif
+
+ AddChildrenImpl();
+ children_dirty_ = false;
+
+#if DCHECK_IS_ON()
+ // All added children must be attached.
for (const auto& child : children_) {
- if (!child->CachedParentObject())
- child->SetParent(this);
+ DCHECK(!child->IsDetached())
+ << "A brand new child was detached: " << child->ToString(true, true)
+ << "\n ... of parent " << ToString(true, true);
+ }
+#endif
+}
+
+// Add non-owned children that are backed with a DOM node.
+void AXNodeObject::AddNodeChild(Node* node) {
+ if (!node)
+ return;
+
+ AXObject* ax_child = AXObjectCache().Get(node);
+ // Should not have another parent unless owned.
+ if (AXObjectCache().IsAriaOwned(ax_child))
+ return; // Do not add owned children to their natural parent.
+
+#if DCHECK_IS_ON()
+ AXObject* ax_cached_parent =
+ ax_child ? ax_child->CachedParentObject() : nullptr;
+ size_t num_children_before_add = children_.size();
+#endif
+
+ if (!ax_child) {
+ ax_child = AXObjectCache().GetOrCreate(node, this);
+ if (!ax_child)
+ return;
+ }
+
+ AddChild(ax_child);
+
+#if DCHECK_IS_ON()
+ bool did_add_child = children_.size() == num_children_before_add + 1 &&
+ children_[0] == ax_child;
+ if (did_add_child) {
+ DCHECK(!ax_cached_parent || ax_cached_parent->AXObjectID() == AXObjectID())
+ << "Newly added child shouldn't have a different preexisting parent:"
+ << "\nChild = " << ax_child->ToString(true, true)
+ << "\nNew parent = " << ToString(true, true)
+ << "\nPreexisting parent = " << ax_cached_parent->ToString(true, true);
}
+#endif
+}
+
+#if DCHECK_IS_ON()
+void AXNodeObject::CheckValidChild(AXObject* child) {
+ DCHECK(!child->IsDetached())
+ << "Cannot add a detached child: " << child->ToString(true, true);
+
+ Node* child_node = child->GetNode();
+
+ // An HTML image can only have area children.
+ DCHECK(!IsA<HTMLImageElement>(GetNode()) || IsA<HTMLAreaElement>(child_node))
+ << "Image elements can only have area children, had "
+ << child->ToString(true, true);
+
+ // <area> children should only be added via AddImageMapChildren(), as the
+ // children of an <image usemap>, and never alone or as children of a <map>.
+ DCHECK(IsA<HTMLImageElement>(GetNode()) || !IsA<HTMLAreaElement>(child_node))
+ << "Area elements can only be added by image parents: "
+ << child->ToString(true, true) << " had a parent of "
+ << ToString(true, true);
+
+ // An option or popup for a <select size=1> must only be added via an
+ // overridden AddChildren() on AXMenuList/AXMenuListPopup.
+ // These AXObjects must be added in an overridden AddChildren() method, and
+ // that will only occur if AXObjectCacheImpl::UseAXMenuList() returns true.
+ DCHECK(!IsA<AXMenuListOption>(child))
+ << "Adding menulist option child in wrong place: "
+ << "\nChild: " << child->ToString(true, true)
+ << "\nParent: " << child->ParentObject()->ToString(true, true)
+ << "\nUseAXMenuList()=" << AXObjectCacheImpl::UseAXMenuList();
+
+ // An popup for a <select size=1> must only be added via an overridden
+ // AddChildren() on AXMenuList.
+ DCHECK(!IsA<AXMenuListPopup>(child))
+ << "Adding menulist popup in wrong place: "
+ << "\nChild: " << child->ToString(true, true)
+ << "\nParent: " << child->ParentObject()->ToString(true, true)
+ << "\nUseAXMenuList()=" << AXObjectCacheImpl::UseAXMenuList()
+ << "\nShouldCreateAXMenuListOptionFor()="
+ << AXObjectCacheImpl::ShouldCreateAXMenuListOptionFor(child_node);
}
+#endif
void AXNodeObject::AddChild(AXObject* child, bool is_from_aria_owns) {
+ if (!child)
+ return;
+
+#if DCHECK_IS_ON()
+ CheckValidChild(child);
+#endif
+
unsigned int index = children_.size();
- if (child)
- InsertChild(child, index, is_from_aria_owns);
+ InsertChild(child, index, is_from_aria_owns);
+}
+
+void AXNodeObject::AddChildAndCheckIncluded(AXObject* child,
+ bool is_from_aria_owns) {
+ if (!child)
+ return;
+ DCHECK(child->AccessibilityIsIncludedInTree())
+ << "A parent " << ToString(true, true) << "\n ... tried to add child "
+ << child->ToString(true, true);
+ AddChild(child, is_from_aria_owns);
}
void AXNodeObject::InsertChild(AXObject* child,
unsigned index,
bool is_from_aria_owns) {
- if (!child || !CanHaveChildren())
+ if (!child)
return;
- if (is_from_aria_owns) {
- DCHECK(AXObjectCache().IsAriaOwned(child));
- } else {
- // Don't add an aria-owned child to its natural parent, because it will
- // already be the child of the element with aria-owns.
- if (AXObjectCache().IsAriaOwned(child))
- return;
- }
+ DCHECK(CanHaveChildren());
+ DCHECK(!child->IsDetached())
+ << "Cannot add a detached child: " << child->ToString(true, true);
+ // Enforce expected aria-owns status:
+ // - Don't add a non-aria-owned child when called from AddOwnedChildren().
+ // - Don't add an aria-owned child to its natural parent, because it will
+ // already be the child of the element with aria-owns.
+ DCHECK_EQ(AXObjectCache().IsAriaOwned(child), is_from_aria_owns);
+
+ // Set the parent:
+ // - For a new object it will have already been set.
+ // - For a reused, older object, it may need to be changed to a new parent.
+ child->SetParent(this);
+
+#if DCHECK_IS_ON()
+ child->EnsureCorrectParentComputation();
+#endif
+
+ // Update cached values preemptively, but don't allow children changed to be
+ // called if ignored change, we are already recomputing children and don't
+ // want to recurse.
+ child->UpdateCachedAttributeValuesIfNeeded(false);
- if (!child->AccessibilityIsIncludedInTree()) {
- DCHECK(!is_from_aria_owns) << "Owned elements smust be in tree";
+ if (!child->LastKnownIsIncludedInTreeValue()) {
+ DCHECK(!is_from_aria_owns)
+ << "Owned elements must be in tree: " << child->ToString(true, true)
+ << "\nRecompute included in tree: "
+ << child->ComputeAccessibilityIsIgnoredButIncludedInTree();
// 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.
@@ -3479,22 +3950,18 @@ void AXNodeObject::InsertChild(AXObject* child,
int new_index = index;
for (wtf_size_t i = 0; i < length; ++i) {
// If the child was owned, it will be added elsewhere as a direct
- // child of the object owning it, and not as an indirect child under
- // an object not included in the tree.
- if (!AXObjectCache().IsAriaOwned(children[i]))
+ // child of the object owning it.
+ if (!AXObjectCache().IsAriaOwned(children[i])) {
+ DCHECK(!children[i]->IsDetached()) << "Cannot add a detached child: "
+ << children[i]->ToString(true, true);
children_.insert(new_index++, children[i]);
+ }
}
- } else if (!child->IsMenuListOption()) {
- // MenuListOptions must only be added in AXMenuListPopup::AddChildren.
+ } else {
children_.insert(index, child);
}
}
-void AXNodeObject::ClearChildren() {
- AXObject::ClearChildren();
- children_dirty_ = false;
-}
-
bool AXNodeObject::CanHaveChildren() const {
// If this is an AXLayoutObject, then it's okay if this object
// doesn't have a node - there are some layoutObjects that don't have
@@ -3502,8 +3969,7 @@ bool AXNodeObject::CanHaveChildren() const {
if (!GetNode() && !IsAXLayoutObject())
return false;
- if (GetNode() && IsA<HTMLMapElement>(GetNode()))
- return false; // Does not have a role, so check here
+ DCHECK(!IsA<HTMLMapElement>(GetNode()));
// 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
@@ -3516,7 +3982,6 @@ bool AXNodeObject::CanHaveChildren() const {
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::kMenuListOption:
case ax::mojom::blink::Role::kMenuItem:
@@ -3535,8 +4000,12 @@ bool AXNodeObject::CanHaveChildren() const {
return false;
case ax::mojom::blink::Role::kPopUpButton:
return true;
+ case ax::mojom::blink::Role::kLineBreak:
case ax::mojom::blink::Role::kStaticText:
return AXObjectCache().InlineTextBoxAccessibilityEnabled();
+ case ax::mojom::blink::Role::kImage:
+ // Can turn into an image map if gains children later.
+ return GetNode() && GetNode()->IsLink();
default:
break;
}
@@ -3706,10 +4175,6 @@ const AtomicString& AXNodeObject::GetInternalsAttribute(
return element.EnsureElementInternals().FastGetAttribute(attribute);
}
-void AXNodeObject::SetNode(Node* node) {
- node_ = node;
-}
-
AXObject* AXNodeObject::CorrespondingControlAXObjectForLabelElement() const {
HTMLLabelElement* label_element = LabelElementContainer();
if (!label_element)
@@ -3849,6 +4314,24 @@ void AXNodeObject::ChildrenChanged() {
if (!GetNode() && !GetLayoutObject())
return;
+ DCHECK(!IsDetached()) << "Avoid ChildrenChanged() on detached node: "
+ << ToString(true, true);
+
+ // When children changed on a <map> that means we need to forward the
+ // children changed to the <img> that parents the <area> elements.
+ // TODO(accessibility) Consider treating <img usemap> as aria-owns so that
+ // we get implementation "for free" vai relation cache, etc.
+ if (HTMLMapElement* map_element = DynamicTo<HTMLMapElement>(GetNode())) {
+ HTMLImageElement* image_element = map_element->ImageElement();
+ if (image_element) {
+ AXObject* ax_image = AXObjectCache().Get(image_element);
+ if (ax_image) {
+ ax_image->ChildrenChanged();
+ return;
+ }
+ }
+ }
+
// Always update 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
@@ -3866,7 +4349,6 @@ void AXNodeObject::ChildrenChanged() {
node_to_update->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:
@@ -3874,24 +4356,20 @@ void AXNodeObject::ChildrenChanged() {
// - this or an ancestor is a leaf node
// Uses |cached_is_descendant_of_leaf_node_| to avoid updating cached
// attributes for eachc change via | UpdateCachedAttributeValuesIfNeeded()|.
- if (!CanHaveChildren() || cached_is_descendant_of_leaf_node_)
+ if (!CanHaveChildren() || LastKnownIsDescendantOfLeafNode())
return;
- // Calling CanHaveChildren(), above, can occasionally detach |this|.
- if (IsDetached())
+ // TODO(aleventhal) Consider removing.
+ if (IsDetached()) {
+ NOTREACHED() << "None of the above calls should be able to detach |this|: "
+ << ToString(true, true);
return;
+ }
AXObjectCache().PostNotification(this,
ax::mojom::blink::Event::kChildrenChanged);
}
-void AXNodeObject::UpdateChildrenIfNecessary() {
- if (NeedsToUpdateChildren())
- ClearChildren();
-
- AXObject::UpdateChildrenIfNecessary();
-}
-
void AXNodeObject::SelectedOptions(AXObjectVector& options) const {
if (auto* select = DynamicTo<HTMLSelectElement>(GetNode())) {
for (auto* const option : *select->selectedOptions()) {
@@ -3902,14 +4380,10 @@ void AXNodeObject::SelectedOptions(AXObjectVector& options) const {
return;
}
- // If the combobox or listbox is a descendant of a label element for another
- // widget, it may be ignored and Children() won't return all its children.
- // As a result, we need to use RawFirstChild and RawNextSibling to iterate
- // over the children in search of the selected option(s).
-
+ const AXObjectVector& children = ChildrenIncludingIgnored();
if (RoleValue() == ax::mojom::blink::Role::kComboBoxGrouping ||
RoleValue() == ax::mojom::blink::Role::kComboBoxMenuButton) {
- for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) {
+ for (const auto& obj : children) {
if (obj->RoleValue() == ax::mojom::blink::Role::kListBox) {
obj->SelectedOptions(options);
return;
@@ -3917,7 +4391,7 @@ void AXNodeObject::SelectedOptions(AXObjectVector& options) const {
}
}
- for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) {
+ for (const auto& obj : children) {
if (obj->IsSelected() == kSelectedStateTrue)
options.push_back(obj);
}
@@ -3953,7 +4427,7 @@ AXObject* AXNodeObject::ErrorMessage() const {
if (this != AXObjectCache().FocusedObject())
return nullptr;
- return AXObjectCache().ValidationMessageObjectIfInvalid();
+ return AXObjectCache().ValidationMessageObjectIfInvalid(true);
}
// According to the standard, the figcaption should only be the first or
@@ -4474,7 +4948,8 @@ String AXNodeObject::NativeTextAlternative(
}
Element* title_element = document->TitleElement();
- AXObject* title_ax_object = AXObjectCache().GetOrCreate(title_element);
+ AXObject* title_ax_object = AXObjectCache().GetOrCreate(
+ title_element, AXObjectCache().Get(document));
if (title_ax_object) {
if (related_objects) {
local_related_objects.push_back(
@@ -4542,6 +5017,17 @@ String AXNodeObject::Description(
AXRelatedObjectVector* related_objects) const {
// If descriptionSources is non-null, relatedObjects is used in filling it in,
// so it must be non-null as well.
+ // Important: create a DescriptionSource for every *potential* description
+ // source, even if it ends up not being present.
+ // When adding a new description_from type:
+ // * Also add it to AXValueNativeSourceType here:
+ // blink/public/devtools_protocol/browser_protocol.pdl
+ // * Update InspectorTypeBuilderHelper to map the new enum to
+ // the browser_protocol enum in NativeSourceType():
+ // blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
+ // * Update devtools_frontend to add a new string for the new type of
+ // description. See AXNativeSourceTypes at:
+ // devtools-frontend/src/front_end/accessibility/AccessibilityStrings.js
if (description_sources)
DCHECK(related_objects);
@@ -4640,6 +5126,43 @@ String AXNodeObject::Description(
}
}
+ if (RoleValue() == ax::mojom::blink::Role::kRuby) {
+ description_from = ax::mojom::blink::DescriptionFrom::kRelatedElement;
+ if (description_sources) {
+ description_sources->push_back(DescriptionSource(found_description));
+ description_sources->back().type = description_from;
+ description_sources->back().native_source =
+ kAXTextFromNativeHTMLRubyAnnotation;
+ }
+ AXObject* ruby_annotation_ax_object = nullptr;
+ for (const auto& child : children_) {
+ if (child->RoleValue() == ax::mojom::blink::Role::kRubyAnnotation &&
+ child->GetNode() &&
+ child->GetNode()->HasTagName(html_names::kRtTag)) {
+ ruby_annotation_ax_object = child;
+ break;
+ }
+ }
+ if (ruby_annotation_ax_object) {
+ AXObjectSet visited;
+ description =
+ RecursiveTextAlternative(*ruby_annotation_ax_object, true, visited);
+ if (related_objects) {
+ related_objects->push_back(
+ MakeGarbageCollected<NameSourceRelatedObject>(
+ ruby_annotation_ax_object, description));
+ }
+ if (description_sources) {
+ DescriptionSource& source = description_sources->back();
+ source.related_objects = *related_objects;
+ source.text = description;
+ found_description = true;
+ } else {
+ return description;
+ }
+ }
+ }
+
// table caption, 5.9.2 from:
// http://rawgit.com/w3c/aria/master/html-aam/html-aam.html
auto* table_element = DynamicTo<HTMLTableElement>(element);
@@ -4776,6 +5299,56 @@ String AXNodeObject::PlaceholderFromNativeAttribute() const {
return ToTextControl(node)->StrippedPlaceholder();
}
+String AXNodeObject::GetValueContributionToName() const {
+ if (CanSetValueAttribute()) {
+ if (IsTextControl())
+ return GetText();
+
+ if (IsRangeValueSupported()) {
+ const AtomicString& aria_valuetext =
+ GetAOMPropertyOrARIAAttribute(AOMStringProperty::kValueText);
+ if (!aria_valuetext.IsNull())
+ return aria_valuetext.GetString();
+ float value;
+ if (ValueForRange(&value))
+ return String::Number(value);
+ }
+ }
+
+ // "If the embedded control has role combobox or listbox, return the text
+ // alternative of the chosen option."
+ if (UseNameFromSelectedOption()) {
+ StringBuilder accumulated_text;
+ AXObjectVector selected_options;
+ SelectedOptions(selected_options);
+ for (const auto& child : selected_options) {
+ if (accumulated_text.length())
+ accumulated_text.Append(" ");
+ accumulated_text.Append(child->ComputedName());
+ }
+ return accumulated_text.ToString();
+ }
+
+ return String();
+}
+
+bool AXNodeObject::UseNameFromSelectedOption() const {
+ // Assumes that the node was reached via recursion in the name calculation.
+ switch (RoleValue()) {
+ // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
+ case ax::mojom::blink::Role::kComboBoxGrouping:
+ case ax::mojom::blink::Role::kComboBoxMenuButton:
+ case ax::mojom::blink::Role::kListBox:
+ return true;
+ // This can be either a button widget with a non-false value of
+ // aria-haspopup or a select element with size of 1.
+ case ax::mojom::blink::Role::kPopUpButton:
+ return DynamicTo<HTMLSelectElement>(*GetNode());
+ default:
+ return false;
+ }
+}
+
void AXNodeObject::Trace(Visitor* visitor) const {
visitor->Trace(node_);
AXObject::Trace(visitor);
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 6cf5409a044..296384cf86b 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
@@ -37,7 +37,6 @@
namespace blink {
class AXObjectCacheImpl;
-class AXSVGRoot;
class Element;
class HTMLLabelElement;
class Node;
@@ -49,18 +48,18 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
void Trace(Visitor*) const override;
protected:
- bool children_dirty_;
#if DCHECK_IS_ON()
bool initialized_ = false;
+ mutable bool getting_bounds_ = false;
#endif
+
// The accessibility role, not taking ARIA into account.
ax::mojom::blink::Role native_role_;
- static base::Optional<String> GetCSSAltText(Node*);
+ static base::Optional<String> GetCSSAltText(const Node*);
AXObjectInclusion ShouldIncludeBasedOnSemantics(
IgnoredReasons* = nullptr) const;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
- bool CanIgnoreTextAsEmpty() const override;
const AXObject* InheritsPresentationalRoleFrom() const override;
ax::mojom::blink::Role DetermineTableSectionRole() const;
ax::mojom::blink::Role DetermineTableCellRole() const;
@@ -77,8 +76,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool IsTextControl() const override;
Element* MenuItemElementForMenu() const;
Element* MouseButtonListener() const;
- bool IsNativeCheckboxOrRadio() const;
- void SetNode(Node*);
AXObject* CorrespondingControlAXObjectForLabelElement() const;
AXObject* CorrespondingLabelAXObject() const;
HTMLLabelElement* LabelElementContainer() const;
@@ -87,12 +84,12 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Overridden from AXObject.
//
- void Init() override;
+ void Init(AXObject* parent_if_known) override;
void Detach() override;
- bool IsDetached() const override;
bool IsAXNodeObject() const final;
// Check object role or purpose.
+ bool IsAutofillAvailable() const override;
bool IsControllingVideoElement() const;
bool IsDefault() const final;
bool IsMultiline() const override;
@@ -120,8 +117,12 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Check object state.
bool IsClickable() const final;
+ bool IsFocused() const override;
+ // aria-grabbed is deprecated in WAI-ARIA 1.1.
+ AccessibilityGrabbedState IsGrabbed() const override;
AccessibilityExpanded IsExpanded() const override;
- bool IsModal() const final;
+ AccessibilitySelectedState IsSelected() const override;
+ bool IsSelectedFromFocus() const override;
bool IsRequired() const final;
bool IsControl() const override;
AXRestriction Restriction() const override;
@@ -129,8 +130,8 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Properties of static elements.
const AtomicString& AccessKey() const override;
RGBA32 ColorValue() const final;
- RGBA32 ComputeBackgroundColor() const final;
RGBA32 GetColor() const final;
+ RGBA32 BackgroundColor() const override;
String FontFamily() const final;
// Font size is in pixels.
float FontSize() const final;
@@ -138,14 +139,25 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool CanvasHasFallbackContent() const final;
int HeadingLevel() const final;
unsigned HierarchicalLevel() const final;
- void GetDocumentMarkers(Vector<DocumentMarker::MarkerType>* marker_types,
- Vector<AXRange>* marker_ranges) const override;
+ void SerializeMarkerAttributes(ui::AXNodeData* node_data) const override;
AXObject* InPageLinkTarget() const override;
AccessibilityOrientation Orientation() const override;
+
+ // Used to compute kRadioGroupIds, which is only used on Mac.
+ // TODO(accessibility) Consider computing on browser side and removing here.
AXObjectVector RadioButtonsInGroup() const override;
static HeapVector<Member<HTMLInputElement>> FindAllRadioButtonsWithSameName(
HTMLInputElement* radio_button);
+
String GetText() const override;
+ ax::mojom::blink::WritingDirection GetTextDirection() const final;
+ ax::mojom::blink::TextPosition GetTextPosition() const final;
+ void GetTextStyleAndTextDecorationStyle(
+ int32_t* text_style,
+ ax::mojom::blink::TextDecorationStyle* text_overline_style,
+ ax::mojom::blink::TextDecorationStyle* text_strikethrough_style,
+ ax::mojom::blink::TextDecorationStyle* text_underline_style) const final;
+
String ImageDataUrl(const IntSize& max_size) const final;
int TextLength() const override;
int TextOffsetInFormattingContext(int offset) const override;
@@ -179,12 +191,11 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
void Dropeffects(
Vector<ax::mojom::blink::Dropeffect>& dropeffects) const override;
- // ARIA live-region features.
- const AtomicString& LiveRegionStatus() const override;
- const AtomicString& LiveRegionRelevant() const override;
-
ax::mojom::blink::HasPopup HasPopup() const override;
+ // Modify or take an action on an object.
+ bool OnNativeSetValueAction(const String&) override;
+
// AX name calculation.
String GetName(ax::mojom::blink::NameFrom&,
AXObjectVector* name_objects) const override;
@@ -211,26 +222,18 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
SkMatrix44& out_container_transform,
bool* clips_children = nullptr) const override;
- // High-level accessibility tree access.
- AXObject* ComputeParent() const override;
- AXObject* ComputeParentIfExists() const override;
-
- // Low-level accessibility tree exploration.
- AXObject* RawFirstChild() const override;
- AXObject* RawNextSibling() const override;
void AddChildren() override;
-
bool CanHaveChildren() const override;
// Set is_from_aria_owns to true if the child is being added because it was
// pointed to from aria-owns.
void AddChild(AXObject*, bool is_from_aria_owns = false);
+ // Add a child that must be included in tree, enforced via DCHECK.
+ void AddChildAndCheckIncluded(AXObject*, bool is_from_aria_owns = false);
+ // If node is non-null, GetOrCreate an AXObject for it and add as a child.
+ void AddNodeChild(Node*);
// Set is_from_aria_owns to true if the child is being insert because it was
// pointed to from aria-owns.
void InsertChild(AXObject*, unsigned index, bool is_from_aria_owns = false);
- void ClearChildren() override;
- bool NeedsToUpdateChildren() const override { return children_dirty_; }
- void SetNeedsToUpdateChildren() override { children_dirty_ = true; }
- void UpdateChildrenIfNecessary() override;
void SelectedOptions(AXObjectVector&) const override;
// Properties of the object's owning document or page.
@@ -272,14 +275,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Inline text boxes.
void LoadInlineTextBoxes() override;
- // SVG.
- bool IsSVGImage() const { return RemoteSVGRootElement(); }
- AXSVGRoot* RemoteSVGRootElement() const;
-
- virtual LayoutBoxModelObject* GetLayoutBoxModelObject() const {
- return nullptr;
- }
-
//
// Layout object specific methods.
//
@@ -291,9 +286,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
return dom_role;
}
- FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, SetNeedsToUpdateChildren);
- FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, UpdateChildrenIfNecessary);
-
private:
bool HasInternalsAttribute(Element&, const QualifiedName&) const;
const AtomicString& GetInternalsAttribute(Element&,
@@ -309,16 +301,27 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool* found_text_alternative) const;
bool IsDescendantOfElementType(HashSet<QualifiedName>& tag_names) const;
String PlaceholderFromNativeAttribute() const;
-
- void AddInlineTextBoxChildren(bool force);
+ String GetValueContributionToName() const;
+ bool UseNameFromSelectedOption() const;
+ bool SelectionShouldFollowFocus() const;
+ virtual bool IsTabItemSelected() const;
+
+ void AddChildrenImpl();
+ void AddNodeChildren();
+ void AddLayoutChildren();
+ bool CanAddLayoutChild(LayoutObject& child);
+ void AddInlineTextBoxChildren(bool force = false);
void AddImageMapChildren();
- void AddHiddenChildren();
void AddPopupChildren();
- void AddRemoteSVGChildren();
+ bool HasValidHTMLTableStructureAndLayout() const;
void AddTableChildren();
void AddValidationMessageChild();
- // For some nodes, only LayoutBuilderTraversal visits the necessary children.
- bool ShouldUseLayoutBuilderTraversal() const;
+ void AddAccessibleNodeChildren();
+ void AddOwnedChildren();
+#if DCHECK_IS_ON()
+ void CheckValidChild(AXObject* child);
+#endif
+
ax::mojom::blink::Dropeffect ParseDropeffect(String& dropeffect) const;
DISALLOW_COPY_AND_ASSIGN(AXNodeObject);
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 a04debe9b6d..b6f9ff0fa38 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -30,6 +30,7 @@
#include <algorithm>
#include "base/strings/string_util.h"
+#include "build/build_config.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"
@@ -37,6 +38,7 @@
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
+#include "third_party/blink/renderer/core/dom/events/simulated_click_options.h"
#include "third_party/blink/renderer/core/dom/focus_params.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -48,6 +50,14 @@
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/html_dialog_element.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_head_element.h"
+#include "third_party/blink/renderer/core/html/html_script_element.h"
+#include "third_party/blink/renderer/core/html/html_style_element.h"
+#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
+#include "third_party/blink/renderer/core/html/html_table_element.h"
+#include "third_party/blink/renderer/core/html/html_table_row_element.h"
+#include "third_party/blink/renderer/core/html/html_table_section_element.h"
+#include "third_party/blink/renderer/core/html/html_title_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
@@ -78,6 +88,8 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
#include "third_party/skia/include/core/SkMatrix44.h"
+#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_common.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_role_properties.h"
@@ -85,6 +97,130 @@ namespace blink {
namespace {
+#if defined(AX_FAIL_FAST_BUILD)
+// TODO(accessibility) Move this out of DEBUG by having a new enum in
+// ax_enums.mojom, and a matching ToString() in ax_enum_utils, as well as move
+// out duplicate code of String IgnoredReasonName(AXIgnoredReason reason) in
+// inspector_type_builder_helper.cc.
+String IgnoredReasonName(AXIgnoredReason reason) {
+ switch (reason) {
+ case kAXActiveModalDialog:
+ return "activeModalDialog";
+ case kAXAriaModalDialog:
+ return "activeAriaModalDialog";
+ case kAXAncestorIsLeafNode:
+ return "ancestorIsLeafNode";
+ case kAXAriaHiddenElement:
+ return "ariaHiddenElement";
+ case kAXAriaHiddenSubtree:
+ return "ariaHiddenSubtree";
+ case kAXEmptyAlt:
+ return "emptyAlt";
+ case kAXEmptyText:
+ return "emptyText";
+ case kAXInertElement:
+ return "inertElement";
+ case kAXInertSubtree:
+ return "inertSubtree";
+ case kAXInheritsPresentation:
+ return "inheritsPresentation";
+ case kAXLabelContainer:
+ return "labelContainer";
+ case kAXLabelFor:
+ return "labelFor";
+ case kAXNotRendered:
+ return "notRendered";
+ case kAXNotVisible:
+ return "notVisible";
+ case kAXPresentational:
+ return "presentationalRole";
+ case kAXProbablyPresentational:
+ return "probablyPresentational";
+ case kAXStaticTextUsedAsNameFor:
+ return "staticTextUsedAsNameFor";
+ case kAXUninteresting:
+ return "uninteresting";
+ }
+ NOTREACHED();
+ return "";
+}
+
+String GetIgnoredReasonsDebugString(AXObject::IgnoredReasons& reasons) {
+ if (reasons.size() == 0)
+ return "";
+ String string_builder = "(";
+ for (wtf_size_t count = 0; count < reasons.size(); count++) {
+ if (count > 0)
+ string_builder = string_builder + ',';
+ string_builder = string_builder + IgnoredReasonName(reasons[count].reason);
+ }
+ string_builder = string_builder + ")";
+ return string_builder;
+}
+
+#endif
+
+String GetElementString(Element* element) {
+ if (!element)
+ return "<null>";
+
+ String string_builder = "<";
+
+ string_builder = string_builder + element->tagName().LowerASCII();
+ // Cannot safely get @class from SVG elements.
+ if (!element->IsSVGElement() &&
+ element->FastHasAttribute(html_names::kClassAttr)) {
+ string_builder = string_builder + "." +
+ element->FastGetAttribute(html_names::kClassAttr);
+ }
+ if (element->FastHasAttribute(html_names::kIdAttr)) {
+ string_builder =
+ string_builder + "#" + element->FastGetAttribute(html_names::kIdAttr);
+ }
+ return string_builder + ">";
+}
+
+Node* GetParentNodeForComputeParent(Node* node) {
+ if (!node)
+ return nullptr;
+
+ // Prefer LayoutTreeBuilderTraversal::Parent(), which handles pseudo content.
+ Node* parent = LayoutTreeBuilderTraversal::Parent(*node);
+ if (parent)
+ return parent;
+
+ // Unfortunately, LayoutTreeBuilderTraversal::Parent() can return nullptr for
+ // a text node, such as inside a text area. Fall back on DOM parentNode().
+ return node->parentNode();
+}
+
+#if DCHECK_IS_ON()
+bool IsValidRole(ax::mojom::blink::Role role) {
+ // Check for illegal roles that should not be assigned in Blink.
+ switch (role) {
+ case ax::mojom::blink::Role::kCaret:
+ case ax::mojom::blink::Role::kClient:
+ case ax::mojom::blink::Role::kColumn:
+ case ax::mojom::blink::Role::kDesktop:
+ case ax::mojom::blink::Role::kKeyboard:
+ case ax::mojom::blink::Role::kIgnored:
+ case ax::mojom::blink::Role::kImeCandidate:
+ case ax::mojom::blink::Role::kListGrid:
+ case ax::mojom::blink::Role::kPane:
+ case ax::mojom::blink::Role::kPdfActionableHighlight:
+ case ax::mojom::blink::Role::kPdfRoot:
+ case ax::mojom::blink::Role::kTableHeaderContainer:
+ case ax::mojom::blink::Role::kTitleBar:
+ case ax::mojom::blink::Role::kUnknown:
+ case ax::mojom::blink::Role::kWebView:
+ case ax::mojom::blink::Role::kWindow:
+ return false;
+ default:
+ return true;
+ }
+}
+#endif
+
struct RoleHashTraits : HashTraits<ax::mojom::blink::Role> {
static const bool kEmptyValueIsZero = true;
static ax::mojom::blink::Role EmptyValue() {
@@ -400,6 +536,7 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::blink::Role::kPane, "Pane"},
{ax::mojom::blink::Role::kParagraph, "Paragraph"},
{ax::mojom::blink::Role::kPdfActionableHighlight, "PdfActionableHighlight"},
+ {ax::mojom::blink::Role::kPdfRoot, "PdfRoot"},
{ax::mojom::blink::Role::kPluginObject, "PluginObject"},
{ax::mojom::blink::Role::kPopUpButton, "PopUpButton"},
{ax::mojom::blink::Role::kPortal, "Portal"},
@@ -422,7 +559,6 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::blink::Role::kSearch, "Search"},
{ax::mojom::blink::Role::kSearchBox, "SearchBox"},
{ax::mojom::blink::Role::kSlider, "Slider"},
- {ax::mojom::blink::Role::kSliderThumb, "SliderThumb"},
{ax::mojom::blink::Role::kSpinButton, "SpinButton"},
{ax::mojom::blink::Role::kSplitter, "Splitter"},
{ax::mojom::blink::Role::kStaticText, "StaticText"},
@@ -449,7 +585,6 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::blink::Role::kTooltip, "UserInterfaceTooltip"},
{ax::mojom::blink::Role::kUnknown, "Unknown"},
{ax::mojom::blink::Role::kVideo, "Video"},
- {ax::mojom::blink::Role::kWebArea, "WebArea"},
{ax::mojom::blink::Role::kWebView, "WebView"},
{ax::mojom::blink::Role::kWindow, "Window"}};
@@ -560,17 +695,41 @@ std::string GetEquivalentAriaRoleString(const ax::mojom::blink::Role role) {
} // namespace
+int32_t ToAXMarkerType(DocumentMarker::MarkerType marker_type) {
+ ax::mojom::blink::MarkerType result;
+ switch (marker_type) {
+ case DocumentMarker::kSpelling:
+ result = ax::mojom::blink::MarkerType::kSpelling;
+ break;
+ case DocumentMarker::kGrammar:
+ result = ax::mojom::blink::MarkerType::kGrammar;
+ break;
+ case DocumentMarker::kTextFragment:
+ case DocumentMarker::kTextMatch:
+ result = ax::mojom::blink::MarkerType::kTextMatch;
+ break;
+ case DocumentMarker::kActiveSuggestion:
+ result = ax::mojom::blink::MarkerType::kActiveSuggestion;
+ break;
+ case DocumentMarker::kSuggestion:
+ result = ax::mojom::blink::MarkerType::kSuggestion;
+ break;
+ default:
+ result = ax::mojom::blink::MarkerType::kNone;
+ break;
+ }
+
+ return static_cast<int32_t>(result);
+}
+
unsigned AXObject::number_of_live_ax_objects_ = 0;
AXObject::AXObject(AXObjectCacheImpl& ax_object_cache)
: id_(0),
- have_children_(false),
+ parent_(nullptr),
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),
cached_is_ignored_(false),
cached_is_ignored_but_included_in_tree_(false),
@@ -591,25 +750,227 @@ AXObject::~AXObject() {
--number_of_live_ax_objects_;
}
-void AXObject::Init() {
+void AXObject::Init(AXObject* parent_if_known) {
+#if DCHECK_IS_ON()
+ DCHECK(!parent_);
+ DCHECK(!is_initializing_);
+ base::AutoReset<bool> reentrancy_protector(&is_initializing_, true);
+#endif
+
+ // The role must be determined immediately.
+ // Note: in order to avoid reentrancy, the role computation cannot use the
+ // ParentObject(), although it can use the DOM parent.
role_ = DetermineAccessibilityRole();
+#if DCHECK_IS_ON()
+ DCHECK(IsValidRole(role_)) << "Illegal " << role_ << " for\n"
+ << GetNode() << '\n'
+ << GetLayoutObject();
+#endif
+
+ // Determine the parent as soon as possible.
+ // Every AXObject must have a parent unless it's the root.
+ SetParent(parent_if_known ? parent_if_known : ComputeParent());
+ DCHECK(parent_ || IsA<Document>(GetNode()))
+ << "The following node should have a parent: " << GetNode();
+
+ SetNeedsToUpdateChildren(); // Should be called after role_ is set.
+ UpdateCachedAttributeValuesIfNeeded(false);
}
void AXObject::Detach() {
- // Clear any children and call detachFromParent on them so that
+#if DCHECK_IS_ON()
+ // Only mock objects can end up being detached twice, because their owner
+ // may have needed to detach them when they were detached, but couldn't
+ // remove them from the object cache yet.
+ if (IsDetached()) {
+ DCHECK(IsMockObject()) << "Object detached twice: " << RoleValue();
+ return;
+ }
+ DCHECK(!is_adding_children_) << ToString(true, true);
+ DCHECK(ax_object_cache_);
+ DCHECK(!ax_object_cache_->IsFrozen())
+ << "Do not detach children while the tree is frozen, in order to avoid "
+ "an object detaching itself in the middle of computing its own "
+ "accessibility properties.";
+#endif
+
+ // Clear any children and call DetachFromParent() on them so that
// no children are left with dangling pointers to their parent.
ClearChildren();
+ parent_ = nullptr;
ax_object_cache_ = nullptr;
+ children_dirty_ = false;
}
bool AXObject::IsDetached() const {
return !ax_object_cache_;
}
-void AXObject::SetParent(AXObject* parent) {
- parent_ = parent;
+void AXObject::SetParent(AXObject* new_parent) {
+ DCHECK(new_parent || IsA<Document>(GetNode()))
+ << "Parent cannot be null, except at the root, was null at " << GetNode()
+ << " " << GetLayoutObject();
+
+#if DCHECK_IS_ON()
+ // Check to ensure that if the parent is changing from a previous parent,
+ // that |this| is not still a child of that one.
+ // This is similar to the IsParentUnignoredOf() check in
+ // BlinkAXTreeSource, but closer to where the problem would occur.
+ if (parent_ && new_parent != parent_ && !parent_->NeedsToUpdateChildren() &&
+ !parent_->IsDetached()) {
+ for (const auto& child : parent_->ChildrenIncludingIgnored()) {
+ DCHECK(child != this) << "Previous parent still has |this| child:\n"
+ << ToString(true, true) << " should be a child of "
+ << new_parent->ToString(true, true) << " not of "
+ << parent_->ToString(true, true);
+ }
+ // TODO(accessibility) This should not be reached unless this method is
+ // called on an AXObject of role kRootWebArea or when the parent's
+ // children are dirty, aka parent_->NeedsToUpdateChildren());
+ // Ideally we will also ensure |this| is in the parent's children now, so
+ // that ClearChildren() can later find the child to detach from the parent.
+ }
+#endif
+ parent_ = new_parent;
+}
+
+// In many cases, ComputeParent() is not called, because the parent adding
+// the child will pass itself into AXObject::Init() via parent_if_known.
+// ComputeParent() is still necessary because some parts of the code,
+// especially web tests, result in AXObjects being created in the middle of
+// the tree before their parents are created.
+// TODO(accessibility) Consider forcing all ax objects to be created from
+// the top down, eliminating the need for ComputeParent().
+AXObject* AXObject::ComputeParent() const {
+ DCHECK(!IsDetached());
+
+ DCHECK(!parent_ || parent_->IsDetached())
+ << "Should use cached parent unless it's detached, and should not "
+ "attempt to recompute it, occurred on "
+ << GetNode();
+
+ if (!GetNode() && !GetLayoutObject()) {
+ NOTREACHED() << "Can't compute parent on AXObjects without a backing Node "
+ "or LayoutObject. Objects without those must set the "
+ "parent in Init(), |this| = "
+ << RoleValue();
+ return nullptr;
+ }
+
+ return ComputeParentImpl();
+}
+
+AXObject* AXObject::ComputeParentImpl() const {
+ DCHECK(!IsDetached());
+
+ if (AXObjectCache().IsAriaOwned(this))
+ return AXObjectCache().GetAriaOwnedParent(this);
+
+ Node* current_node = GetNode();
+
+ // A WebArea's parent should be the page popup owner, if any, otherwise null.
+ if (IsA<Document>(current_node)) {
+ LocalFrame* frame = GetLayoutObject()->GetFrame();
+ return AXObjectCache().GetOrCreate(frame->PagePopupOwner());
+ }
+
+ if (IsVirtualObject()) {
+ NOTREACHED()
+ << "A virtual object must have a parent, and cannot exist without one. "
+ "The parent is set when the object is constructed.";
+ return nullptr;
+ }
+
+ // If no node, or a pseudo element, use the layout parent.
+ if (!current_node) {
+ LayoutObject* current_layout_obj = GetLayoutObject();
+ if (!current_layout_obj) {
+ NOTREACHED()
+ << "Can't compute parent on AXObjects without a backing Node "
+ "or LayoutObject. Objects without those must set the "
+ "parent in Init(), |this| = "
+ << RoleValue();
+ return nullptr;
+ }
+ // If no DOM node and no parent, this must be an anonymous layout object.
+ DCHECK(current_layout_obj->IsAnonymous());
+ LayoutObject* parent_layout_obj = current_layout_obj->Parent();
+ if (!parent_layout_obj)
+ return nullptr;
+ if (AXObject* ax_parent = AXObjectCache().GetOrCreate(parent_layout_obj)) {
+ DCHECK(!ax_parent->IsDetached());
+ return ax_parent;
+ }
+ // Switch to using DOM nodes. The only cases that should occur do not have
+ // chains of multiple parents without DOM nodes.
+ Node* parent_node = parent_layout_obj->GetNode();
+ DCHECK(parent_node) << "Computing an accessible parent from the layout "
+ "parent did not yield an accessible object nor a "
+ "DOM node to walk up from, current_layout_obj = "
+ << current_layout_obj;
+ if (!parent_node)
+ return nullptr;
+ }
+
+ while (true) {
+ current_node = GetParentNodeForComputeParent(current_node);
+ if (!current_node)
+ break;
+ AXObject* ax_parent = AXObjectCache().GetOrCreate(current_node);
+ if (ax_parent) {
+ DCHECK(!ax_parent->IsDetached());
+ return ax_parent;
+ }
+ }
+
+ return nullptr;
+}
+
+#if DCHECK_IS_ON()
+void AXObject::EnsureCorrectParentComputation() {
+ if (!parent_)
+ return;
+
+ DCHECK(!parent_->IsDetached());
+
+ // Don't check the computed parent if the cached parent is a mock object.
+ // It is expected that a computed parent could never be a mock object,
+ // which has no backing DOM node or layout object, and therefore cannot be
+ // found by traversing DOM/layout ancestors.
+ if (parent_->IsMockObject())
+ return;
+
+ // Cannot compute a parent for an object that has no backing node or layout
+ // object to start from.
+ if (!GetNode() || !GetLayoutObject())
+ return;
+
+ // Don't check the computed parent if the cached parent is an image map:
+ // <area> children's location in the DOM and HTML hierarchy does not match.
+ // TODO(aleventhal) Try to remove this rule, it may be unnecessary now.
+ if (parent_->RoleValue() == ax::mojom::blink::Role::kImageMap)
+ return;
+
+ // TODO(aleventhal) Different in test fast/css/first-letter-removed-added.html
+ // when run with --force-renderer-accessibility.
+ if (GetNode() && GetNode()->IsPseudoElement())
+ return;
+
+ // Verify that the algorithm in ComputeParentImpl() provides same results as
+ // parents that init their children with themselves as the parent_if_known.
+ // Inconsistency indicates a problem could potentially exist where a child's
+ // parent does not include the child in its children.
+ DCHECK(ComputeParentImpl())
+ << "Computed parent was null for " << this << ", expected " << parent_;
+ DCHECK_EQ(ComputeParentImpl(), parent_)
+ << "\n**** ComputeParent should have provided the same result as "
+ "the known parent.\n**** Computed parent layout object was "
+ << ComputeParentImpl()->GetLayoutObject()
+ << "\n**** Actual parent's layout object was "
+ << parent_->GetLayoutObject() << "\n**** Child was " << this;
}
+#endif
const AtomicString& AXObject::GetAOMPropertyOrARIAAttribute(
AOMStringProperty property) const {
@@ -730,49 +1091,16 @@ AccessibleNode* AXObject::GetAccessibleNode() const {
return element->ExistingAccessibleNode();
}
-void AXObject::GetSparseAXAttributes(
- AXSparseAttributeClient& sparse_attribute_client) const {
- AXSparseAttributeAOMPropertyClient property_client(*ax_object_cache_,
- sparse_attribute_client);
- AccessibleNode* accessible_node = GetAccessibleNode();
-
- // Virtual nodes for AOM are still tied to the AXTree.
- if (accessible_node && IsVirtualObject())
- accessible_node->GetAllAOMProperties(&property_client);
-
- Element* element = GetElement();
- if (!element)
- return;
-
- AXSparseAttributeSetterMap& ax_sparse_attribute_setter_map =
- GetSparseAttributeSetterMap();
- AttributeCollection attributes = element->AttributesWithoutUpdate();
- HashSet<QualifiedName> set_attributes;
- for (const Attribute& attr : attributes) {
- set_attributes.insert(attr.GetName());
-
- AXSparseAttributeSetter* setter =
- ax_sparse_attribute_setter_map.at(attr.GetName());
- if (setter)
- setter->Run(*this, sparse_attribute_client, 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;
- AXSparseAttributeSetter* setter = ax_sparse_attribute_setter_map.at(attr);
- if (setter) {
- setter->Run(*this, sparse_attribute_client,
- internals_attributes.at(attr));
- }
- }
-}
-
void AXObject::Serialize(ui::AXNodeData* node_data,
ui::AXMode accessibility_mode) {
+ node_data->role = RoleValue();
+ node_data->id = AXObjectID();
+
+ DCHECK(!IsDetached()) << "Do not serialize detached nodes: "
+ << ToString(true, true);
+ DCHECK(AccessibilityIsIncludedInTree())
+ << "Do not serialize unincluded nodes: " << ToString(true, true);
+
AccessibilityExpanded expanded = IsExpanded();
if (expanded) {
if (expanded == kExpandedCollapsed)
@@ -888,6 +1216,23 @@ void AXObject::Serialize(ui::AXNodeData* node_data,
dom_node_id);
}
+ // Heading level.
+ if (ui::IsHeading(RoleValue()) && HeadingLevel()) {
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kHierarchicalLevel, HeadingLevel());
+ }
+
+ AXObject* parent = ParentObject();
+ if (Language().length()) {
+ // TODO(chrishall): should we still trim redundant languages off here?
+ if (!parent || parent->Language() != Language()) {
+ TruncateAndAddStringAttribute(
+ node_data, ax::mojom::blink::StringAttribute::kLanguage,
+ Language().Utf8());
+ }
+ }
+
+ SerializeListAttributes(node_data);
SerializeTableAttributes(node_data);
}
@@ -926,10 +1271,11 @@ void AXObject::Serialize(ui::AXNodeData* node_data,
}
if (accessibility_mode.has_mode(ui::AXMode::kScreenReader)) {
+ SerializeMarkerAttributes(node_data);
SerializeStyleAttributes(node_data);
}
- SerializePartialSparseAttributes(node_data);
+ SerializeSparseAttributes(node_data);
if (Element* element = this->GetElement()) {
if (const AtomicString& class_name = element->GetClassAttribute()) {
@@ -979,6 +1325,18 @@ void AXObject::Serialize(ui::AXNodeData* node_data,
}
}
}
+
+ if (IsScrollableContainer())
+ SerializeScrollAttributes(node_data);
+
+ SerializeChooserPopupAttributes(node_data);
+
+ if (GetElement()) {
+ SerializeElementAttributes(node_data);
+ if (accessibility_mode.has_mode(ui::AXMode::kHTML)) {
+ SerializeHTMLAttributes(node_data);
+ }
+ }
}
void AXObject::SerializeTableAttributes(ui::AXNodeData* node_data) {
@@ -1036,6 +1394,82 @@ void AXObject::SerializeTableAttributes(ui::AXNodeData* node_data) {
}
}
+void AXObject::SerializeScrollAttributes(ui::AXNodeData* node_data) {
+ // Only mark as scrollable if user has actual scrollbars to use.
+ node_data->AddBoolAttribute(ax::mojom::blink::BoolAttribute::kScrollable,
+ IsUserScrollable());
+ // Provide x,y scroll info if scrollable in any way (programmatically or via
+ // user).
+ const gfx::Point& scroll_offset = GetScrollOffset();
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollX,
+ scroll_offset.x());
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollY,
+ scroll_offset.y());
+
+ const gfx::Point& min_scroll_offset = MinimumScrollOffset();
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollXMin,
+ min_scroll_offset.x());
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollYMin,
+ min_scroll_offset.y());
+
+ const gfx::Point& max_scroll_offset = MaximumScrollOffset();
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollXMax,
+ max_scroll_offset.x());
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kScrollYMax,
+ max_scroll_offset.y());
+}
+
+void AXObject::SerializeElementAttributes(ui::AXNodeData* node_data) {
+ Element* element = this->GetElement();
+ if (!element)
+ return;
+
+ if (const AtomicString& class_name = element->GetClassAttribute()) {
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kClassName,
+ class_name.Utf8());
+ }
+
+ // ARIA role.
+ if (const AtomicString& aria_role =
+ GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole)) {
+ TruncateAndAddStringAttribute(
+ node_data, ax::mojom::blink::StringAttribute::kRole, aria_role.Utf8());
+ } else {
+ std::string role = GetEquivalentAriaRoleString(RoleValue());
+ if (!role.empty()) {
+ TruncateAndAddStringAttribute(
+ node_data, ax::mojom::blink::StringAttribute::kRole, role);
+ }
+ }
+}
+
+void AXObject::SerializeHTMLAttributes(ui::AXNodeData* node_data) {
+ Element* element = GetElement();
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kHtmlTag,
+ element->tagName().LowerASCII().Utf8());
+ for (const Attribute& attr : element->Attributes()) {
+ std::string name = attr.LocalName().LowerASCII().Utf8();
+ if (name == "class") { // class already in kClassName
+ continue;
+ }
+ std::string value = attr.Value().Utf8();
+ node_data->html_attributes.push_back(std::make_pair(name, value));
+ }
+
+// TODO(nektar): Turn off kHTMLAccessibilityMode for automation and Mac
+// and remove ifdef.
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+ if (node_data->role == ax::mojom::blink::Role::kMath &&
+ element->innerHTML().length()) {
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kInnerHtml,
+ element->innerHTML().Utf8());
+ }
+#endif
+}
+
void AXObject::SerializeStyleAttributes(ui::AXNodeData* node_data) {
// Text attributes.
if (BackgroundColor()) {
@@ -1114,7 +1548,7 @@ void AXObject::SerializeStyleAttributes(ui::AXNodeData* node_data) {
}
}
-void AXObject::SerializePartialSparseAttributes(ui::AXNodeData* node_data) {
+void AXObject::SerializeSparseAttributes(ui::AXNodeData* node_data) {
if (IsVirtualObject()) {
AccessibleNode* accessible_node = GetAccessibleNode();
if (accessible_node) {
@@ -1128,7 +1562,7 @@ void AXObject::SerializePartialSparseAttributes(ui::AXNodeData* node_data) {
if (!element)
return;
- TempSetterMap& setter_map = GetTempSetterMap();
+ AXSparseAttributeSetterMap& setter_map = GetAXSparseAttributeSetterMap();
AttributeCollection attributes = element->AttributesWithoutUpdate();
HashSet<QualifiedName> set_attributes;
for (const Attribute& attr : attributes) {
@@ -1154,6 +1588,35 @@ void AXObject::SerializePartialSparseAttributes(ui::AXNodeData* node_data) {
}
}
+void AXObject::SerializeListAttributes(ui::AXNodeData* node_data) {
+ if (SetSize()) {
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kSetSize,
+ SetSize());
+ }
+
+ if (PosInSet()) {
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kPosInSet,
+ PosInSet());
+ }
+}
+
+void AXObject::SerializeMarkerAttributes(ui::AXNodeData* node_data) const {
+ // Implemented in subclasses.
+}
+
+void AXObject::SerializeChooserPopupAttributes(ui::AXNodeData* node_data) {
+ AXObject* chooser_popup = ChooserPopup();
+ if (!chooser_popup)
+ return;
+
+ int32_t chooser_popup_id = chooser_popup->AXObjectID();
+ auto controls_ids = node_data->GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kControlsIds);
+ controls_ids.push_back(chooser_popup_id);
+ node_data->AddIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kControlsIds, controls_ids);
+}
+
void AXObject::TruncateAndAddStringAttribute(
ui::AXNodeData* dst,
ax::mojom::blink::StringAttribute attribute,
@@ -1220,10 +1683,6 @@ bool AXObject::IsSlider() const {
return false;
}
-bool AXObject::IsAXSVGRoot() const {
- return false;
-}
-
bool AXObject::IsValidationMessage() const {
return false;
}
@@ -1254,12 +1713,17 @@ bool AXObject::IsCanvas() const {
return RoleValue() == ax::mojom::blink::Role::kCanvas;
}
-bool AXObject::IsCheckbox() const {
- return RoleValue() == ax::mojom::blink::Role::kCheckBox;
-}
-
bool AXObject::IsCheckboxOrRadio() const {
- return IsCheckbox() || IsRadioButton();
+ switch (RoleValue()) {
+ case ax::mojom::blink::Role::kCheckBox:
+ case ax::mojom::blink::Role::kMenuItemCheckBox:
+ case ax::mojom::blink::Role::kMenuItemRadio:
+ case ax::mojom::blink::Role::kRadioButton:
+ return true;
+ default:
+ break;
+ }
+ return false;
}
bool AXObject::IsColorWell() const {
@@ -1494,13 +1958,11 @@ bool AXObject::IsClickable() const {
}
bool AXObject::AccessibilityIsIgnored() const {
- UpdateDistributionForFlatTreeTraversal();
UpdateCachedAttributeValuesIfNeeded();
return cached_is_ignored_;
}
bool AXObject::AccessibilityIsIgnoredButIncludedInTree() const {
- UpdateDistributionForFlatTreeTraversal();
UpdateCachedAttributeValuesIfNeeded();
return cached_is_ignored_but_included_in_tree_;
}
@@ -1511,69 +1973,132 @@ bool AXObject::AccessibilityIsIncludedInTree() const {
return !AccessibilityIsIgnored() || AccessibilityIsIgnoredButIncludedInTree();
}
-void AXObject::UpdateCachedAttributeValuesIfNeeded() const {
- if (IsDetached())
+void AXObject::UpdateCachedAttributeValuesIfNeeded(
+ bool notify_parent_of_ignored_changes) const {
+ if (IsDetached()) {
+ cached_is_ignored_ = true;
+ cached_is_ignored_but_included_in_tree_ = false;
return;
+ }
AXObjectCacheImpl& cache = AXObjectCache();
if (cache.ModificationCount() == last_modification_count_)
return;
+ last_modification_count_ = cache.ModificationCount();
+
#if DCHECK_IS_ON() // Required in order to get Lifecycle().ToString()
+ DCHECK(!is_updating_cached_values_)
+ << "Reentering UpdateCachedAttributeValuesIfNeeded() on same node: "
+ << GetNode();
+
+ base::AutoReset<bool> reentrancy_protector(&is_updating_cached_values_, true);
+
DCHECK(!GetDocument() || GetDocument()->Lifecycle().GetState() >=
DocumentLifecycle::kAfterPerformLayout)
<< "Unclean document at lifecycle "
<< GetDocument()->Lifecycle().ToString();
#endif
- last_modification_count_ = cache.ModificationCount();
-
- cached_background_color_ = ComputeBackgroundColor();
- // TODO(aleventhal) Temporary crash fix until CL:2485519 lands.
- if (IsDetached())
- return;
+ // TODO(accessibility) Every AXObject must have a parent except the root.
+ // Sometimes the parent is detached and a new parent isn't yet reattached.
+ if (!parent_)
+ parent_ = ComputeParent();
cached_is_hidden_via_style = ComputeIsHiddenViaStyle();
- cached_is_inert_or_aria_hidden_ = ComputeIsInertOrAriaHidden();
+
+ // Decisions in what subtree descendants are included (each descendant's
+ // cached children_) depends on the ARIA hidden state. When it changes,
+ // the entire subtree needs to recompute descendants.
+ // In addition, the below computations for is_ignored_but_included_in_tree is
+ // dependent on having the correct new cached value.
+ bool is_inert_or_aria_hidden = ComputeIsInertOrAriaHidden();
+ if (cached_is_inert_or_aria_hidden_ != is_inert_or_aria_hidden) {
+ // Update children if not already dirty (e.g. during Init() time.
+ SetNeedsToUpdateChildren();
+ cached_is_inert_or_aria_hidden_ = is_inert_or_aria_hidden;
+ }
cached_is_descendant_of_leaf_node_ = !!LeafNodeAncestor();
cached_is_descendant_of_disabled_node_ = !!DisabledAncestor();
cached_has_inherited_presentational_role_ =
!!InheritsPresentationalRoleFrom();
- cached_is_ignored_ = ComputeAccessibilityIsIgnored();
- cached_is_ignored_but_included_in_tree_ =
- cached_is_ignored_ && ComputeAccessibilityIsIgnoredButIncludedInTree();
+
+ bool is_ignored = ComputeAccessibilityIsIgnored();
+ bool is_ignored_but_included_in_tree =
+ is_ignored && ComputeAccessibilityIsIgnoredButIncludedInTree();
+#if DCHECK_IS_ON()
+ // Ensure that display-locked text is pruned from the tree. This means that
+ // they will be missed in the virtual buffer; therefore, it may be a rule
+ // subject to change. Note that changing the rule would potentially cause a
+ // lot of display-locked whitespace to be exposed.
+ if (is_ignored && RoleValue() == ax::mojom::blink::Role::kStaticText &&
+ GetNode() &&
+ DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) {
+ DCHECK(!cached_is_ignored_but_included_in_tree_)
+ << "Display locked text should not be included in the tree (subject to "
+ "future rule change)";
+ }
+#endif
+ bool included_in_tree_changed = false;
+
+ // If the child's "included in tree" state changes, we will be notifying the
+ // parent to recompute it's children.
+ // Exceptions:
+ // - Caller passes in |notify_parent_of_ignored_changes = false| -- this
+ // occurs when this is a new child, or when a parent is in the middle of
+ // adding this child, and doing this would be redundant.
+ // - Inline text boxes: their "included in tree" state is entirely dependent
+ // on their static text parent.
+ if (notify_parent_of_ignored_changes &&
+ RoleValue() != ax::mojom::blink::Role::kInlineTextBox) {
+ bool is_included_in_tree = !is_ignored || is_ignored_but_included_in_tree;
+ if (is_included_in_tree != LastKnownIsIncludedInTreeValue())
+ included_in_tree_changed = true;
+ }
+
+ // Presence of inline text children depends on ignored state.
+ if (is_ignored != LastKnownIsIgnoredValue() &&
+ ui::CanHaveInlineTextBoxChildren(RoleValue())) {
+ // Update children if not already dirty (e.g. during Init() time.
+ SetNeedsToUpdateChildren();
+ }
+
+ cached_is_ignored_ = is_ignored;
+ cached_is_ignored_but_included_in_tree_ = is_ignored_but_included_in_tree;
cached_is_editable_root_ = ComputeIsEditableRoot();
// Compute live region root, which can be from any ARIA live value, including
// "off", or from an automatic ARIA live value, e.g. from role="status".
// TODO(dmazzoni): remove this const_cast.
AtomicString aria_live;
- cached_live_region_root_ =
- IsLiveRegionRoot()
- ? const_cast<AXObject*>(this)
- : (ParentObjectIfExists() ? ParentObjectIfExists()->LiveRegionRoot()
- : nullptr);
+ if (GetNode() && IsA<Document>(GetNode())) {
+ // The document root is never a live region root.
+ cached_live_region_root_ = nullptr;
+ } else if (RoleValue() == ax::mojom::blink::Role::kInlineTextBox) {
+ // Inline text boxes do not need live region properties.
+ cached_live_region_root_ = nullptr;
+ } else if (parent_) {
+ // Is a live region root if this or an ancestor is a live region.
+ cached_live_region_root_ = IsLiveRegionRoot() ? const_cast<AXObject*>(this)
+ : parent_->LiveRegionRoot();
+ }
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();
+ if (included_in_tree_changed) {
+ if (AXObject* parent = CachedParentObject()) {
+ // TODO(aleventhal) Reenable DCHECK. It fails on PDF tests.
+ // DCHECK(!ax_object_cache_->IsFrozen())
+ // << "Attempting to change children on an ancestor is dangerous during "
+ // "serialization, because the ancestor may have already been "
+ // "visited. Reaching this line indicates that AXObjectCacheImpl did "
+ // "not handle a signal and call ChilldrenChanged() earlier."
+ // << "\nChild: " << ToString(true)
+ // << "\nParent: " << parent->ToString(true);
+ // Defer this ChildrenChanged(), otherwise it can cause reentry into
+ // UpdateCachedAttributeValuesIfNeeded() on |this|.
+ AXObjectCache().ChildrenChanged(parent);
+ }
}
if (GetLayoutObject() && GetLayoutObject()->IsText()) {
@@ -1660,6 +2185,22 @@ bool AXObject::ComputeIsInertOrAriaHidden(
return false;
}
+bool AXObject::IsModal() const {
+ if (RoleValue() != ax::mojom::blink::Role::kDialog &&
+ RoleValue() != ax::mojom::blink::Role::kAlertDialog)
+ return false;
+
+ bool modal = false;
+ if (HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kModal, modal)) {
+ return modal;
+ }
+
+ if (GetNode() && IsA<HTMLDialogElement>(*GetNode()))
+ return To<Element>(GetNode())->IsInTopLayer();
+
+ return false;
+}
+
bool AXObject::IsBlockedByAriaModalDialog(
IgnoredReasons* ignored_reasons) const {
AXObject* active_aria_modal_dialog =
@@ -1843,24 +2384,55 @@ bool AXObject::ComputeAccessibilityIsIgnoredButIncludedInTree() const {
return true;
}
- if (!GetNode())
- return false;
+ const Node* node = GetNode();
+
+ if (!node) {
+ if (GetLayoutObject()) {
+ // All AXObjects created for anonymous layout objects are included.
+ // See IsLayoutObjectRelevantForAccessibility() in
+ // ax_object_cache_impl.cc.
+ // - Visible content, such as text, images and quotes (can't have
+ // children).
+ // - Any containers inside of pseudo-elements.
+ DCHECK(GetLayoutObject()->IsAnonymous())
+ << "Object has layout object but no node and is not anonymous: "
+ << GetLayoutObject();
+ } else {
+ // Include ignored mock objects, virtual objects and inline text boxes.
+ DCHECK(IsMockObject() || IsVirtualObject() ||
+ RoleValue() == ax::mojom::blink::Role::kInlineTextBox)
+ << "Nodeless, layout-less object found with role " << RoleValue();
+ }
+ // By including all of these objects in the tree, it is ensured that
+ // ClearChildren() will be able to find these children and detach them
+ // from their parent.
+ return true;
+ }
+
+ // Include all pseudo element content. Any anonymous subtree is included
+ // from above, in the condition where there is no node.
+ if (node->IsPseudoElement())
+ return true;
+
+ // <slot>s and their children are included in the tree.
+ // TODO(accessibility) Consider including all shadow content; however, this
+ // can actually be a lot of nodes inside of a web component, e.g. svg.
+ if (IsA<HTMLSlotElement>(node))
+ return true;
+ if (CachedParentObject() &&
+ IsA<HTMLSlotElement>(CachedParentObject()->GetNode()))
+ return true;
+
+ if (GetElement() && GetElement()->IsCustomElement())
+ return true;
// Use a flag to control whether or not the <html> element is included
// in the accessibility tree. Either way it's always marked as "ignored",
// but eventually we want to always include it in the tree to simplify
// some logic.
- if (GetNode() && IsA<HTMLHtmlElement>(GetNode()))
+ if (IsA<HTMLHtmlElement>(node))
return RuntimeEnabledFeatures::AccessibilityExposeHTMLElementEnabled();
- // If the node is part of the user agent shadow dom, or has the explicit
- // internal Role::kIgnored, they aren't interesting for paragraph navigation
- // or LabelledBy/DescribedBy relationships.
- if (RoleValue() == ax::mojom::blink::Role::kIgnored ||
- GetNode()->IsInUserAgentShadowRoot()) {
- return false;
- }
-
// Keep the internal accessibility tree consistent for videos which lack
// a player and also inner text.
if (RoleValue() == ax::mojom::blink::Role::kVideo ||
@@ -1893,12 +2465,20 @@ bool AXObject::ComputeAccessibilityIsIgnoredButIncludedInTree() const {
// Allow the browser side ax tree to access "aria-hidden" nodes.
// This is useful for APIs that return the node referenced by
// aria-labeledby and aria-describedby.
- if (GetLayoutObject() && AriaHiddenRoot())
+ if (GetLayoutObject() && IsInertOrAriaHidden() && AriaHiddenRoot())
return true;
// Preserve SVG grouping elements.
- if (GetNode() && IsA<SVGGElement>(GetNode()))
+ if (IsA<SVGGElement>(node))
+ return true;
+
+ // Keep table-related elements in the tree, because it's too easy for them
+ // to in and out of being ignored based on their ancestry, as their role
+ // can depend on several levels up in the hierarchy.
+ if (IsA<HTMLTableElement>(node) || IsA<HTMLTableSectionElement>(node) ||
+ IsA<HTMLTableRowElement>(node) || IsA<HTMLTableCellElement>(node)) {
return true;
+ }
// Preserve nodes with language attributes.
if (HasAttribute(html_names::kLangAttr))
@@ -1942,32 +2522,11 @@ const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const {
}
bool AXObject::LastKnownIsIgnoredValue() const {
- 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;
+ return cached_is_ignored_;
}
bool AXObject::LastKnownIsIgnoredButIncludedInTreeValue() const {
- 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;
+ return cached_is_ignored_but_included_in_tree_;
}
bool AXObject::LastKnownIsIncludedInTreeValue() const {
@@ -2152,27 +2711,6 @@ bool AXObject::CanBeActiveDescendant() const {
AncestorExposesActiveDescendant();
}
-void AXObject::UpdateDistributionForFlatTreeTraversal() const {
- Node* node = GetNode();
- if (!node) {
- AXObject* parent = this->ParentObject();
- while (!node && parent) {
- node = parent->GetNode();
- parent = parent->ParentObject();
- }
- }
-
- if (node)
- node->UpdateDistributionForFlatTreeTraversal();
-
- // TODO(aboxhall): Instead of this, propagate inert down through frames
- Document* document = GetDocument();
- while (document && document->LocalOwner()) {
- document->LocalOwner()->UpdateDistributionForFlatTreeTraversal();
- document = document->LocalOwner()->ownerDocument();
- }
-}
-
bool AXObject::IsARIAControlledByTextboxWithActiveDescendant() const {
if (IsDetached() || !GetDocument())
return false;
@@ -2230,10 +2768,6 @@ bool AXObject::AncestorExposesActiveDescendant() const {
return parent->AncestorExposesActiveDescendant();
}
-bool AXObject::HasIndirectChildren() const {
- return RoleValue() == ax::mojom::blink::Role::kTableHeaderContainer;
-}
-
bool AXObject::CanSetSelectedAttribute() const {
// Sub-widget elements can be selected if not disabled (native or ARIA)
return IsSubWidget() && Restriction() != kRestrictionDisabled;
@@ -2365,14 +2899,20 @@ bool AXObject::ComputeIsHiddenViaStyle() const {
if (!node)
return false;
- // Display-locked nodes are always hidden.
- if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node))
- return true;
+ if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
+ // Ensure contents of head, style and script are never exposed.
+ // Note: an AXObject is created for <title> to gather the document's name.
+ DCHECK(!Traversal<SVGStyleElement>::FirstAncestorOrSelf(*node)) << node;
+ DCHECK(!Traversal<HTMLHeadElement>::FirstAncestorOrSelf(*node) ||
+ IsA<HTMLTitleElement>(node))
+ << node;
+ DCHECK(!Traversal<HTMLStyleElement>::FirstAncestorOrSelf(*node)) << node;
+ DCHECK(!Traversal<HTMLScriptElement>::FirstAncestorOrSelf(*node)) << node;
- // Style elements in SVG are not display: none, unlike HTML style elements,
- // but they are still hidden and thus treated as hidden from style.
- if (IsA<SVGStyleElement>(node))
- return true;
+ // content-visibility: hidden subtrees are always hidden.
+ return DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock(
+ *node, DisplayLockActivationReason::kAccessibility);
+ }
// For elements with layout objects we can get their style directly.
if (GetLayoutObject())
@@ -2624,11 +3164,6 @@ String AXObject::TextFromAriaDescribedby(AXRelatedObjectVector* related_objects,
return TextFromElements(true, visited, elements, related_objects);
}
-RGBA32 AXObject::BackgroundColor() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_background_color_;
-}
-
AccessibilityOrientation AXObject::Orientation() const {
// In ARIA 1.1, the default value for aria-orientation changed from
// horizontal to undefined.
@@ -2665,10 +3200,6 @@ AXObject::GetAriaSpellingOrGrammarMarker() const {
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,
@@ -2849,13 +3380,20 @@ bool AXObject::HasGlobalARIAAttribute() const {
int AXObject::IndexInParent() const {
DCHECK(AccessibilityIsIncludedInTree())
<< "IndexInParent is only valid when a node is included in the tree";
- if (!ParentObjectIncludedInTree())
+ AXObject* ax_parent_included = ParentObjectIncludedInTree();
+ if (!ax_parent_included)
return 0;
const AXObjectVector& siblings =
- ParentObjectIncludedInTree()->ChildrenIncludingIgnored();
+ ax_parent_included->ChildrenIncludingIgnored();
+
wtf_size_t index = siblings.Find(this);
- DCHECK_NE(index, kNotFound);
+
+ DCHECK_NE(index, kNotFound)
+ << "Could not find child in parent:"
+ << "\nChild: " << ToString(true)
+ << "\nParent: " << ax_parent_included->ToString(true)
+ << " #children=" << siblings.size();
return (index == kNotFound) ? 0 : static_cast<int>(index);
}
@@ -2869,6 +3407,47 @@ bool AXObject::IsActiveLiveRegionRoot() const {
return !live_region.IsEmpty() && !EqualIgnoringASCIICase(live_region, "off");
}
+const AtomicString& AXObject::LiveRegionStatus() const {
+ DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_assertive,
+ ("assertive"));
+ DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_polite,
+ ("polite"));
+ DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_off, ("off"));
+
+ const AtomicString& live_region_status =
+ GetAOMPropertyOrARIAAttribute(AOMStringProperty::kLive);
+ // These roles have implicit live region status.
+ if (live_region_status.IsEmpty()) {
+ switch (RoleValue()) {
+ case ax::mojom::blink::Role::kAlert:
+ return live_region_status_assertive;
+ case ax::mojom::blink::Role::kLog:
+ case ax::mojom::blink::Role::kStatus:
+ return live_region_status_polite;
+ case ax::mojom::blink::Role::kTimer:
+ case ax::mojom::blink::Role::kMarquee:
+ return live_region_status_off;
+ default:
+ break;
+ }
+ }
+
+ return live_region_status;
+}
+
+const AtomicString& AXObject::LiveRegionRelevant() const {
+ DEFINE_STATIC_LOCAL(const AtomicString, default_live_region_relevant,
+ ("additions text"));
+ const AtomicString& relevant =
+ GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRelevant);
+
+ // Default aria-relevant = "additions text".
+ if (relevant.IsEmpty())
+ return default_live_region_relevant;
+
+ return relevant;
+}
+
AXRestriction AXObject::Restriction() const {
// According to ARIA, all elements of the base markup can be disabled.
// According to CORE-AAM, any focusable descendant of aria-disabled
@@ -2897,11 +3476,6 @@ AXRestriction AXObject::Restriction() const {
return kRestrictionNone;
}
-ax::mojom::blink::Role AXObject::DetermineAccessibilityRole() {
- aria_role_ = DetermineAriaRoleAttribute();
- return aria_role_;
-}
-
ax::mojom::blink::Role AXObject::AriaRoleAttribute() const {
return aria_role_;
}
@@ -2917,16 +3491,17 @@ ax::mojom::blink::Role AXObject::DetermineAriaRoleAttribute() const {
// 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.
- if ((role == ax::mojom::blink::Role::kNone ||
- role == ax::mojom::blink::Role::kPresentational) &&
- (CanSetFocusAttribute() || HasGlobalARIAAttribute()))
+ if (ui::IsPresentational(role) &&
+ ((GetElement() && GetElement()->SupportsFocus()) ||
+ HasGlobalARIAAttribute())) {
+ // If we return an unknown role, then the native HTML role would be used
+ // instead.
return ax::mojom::blink::Role::kUnknown;
+ }
if (role == ax::mojom::blink::Role::kButton)
role = ButtonRoleType();
- role = RemapAriaRoleDueToParent(role);
-
// Distinguish between different uses of the "combobox" role:
//
// ax::mojom::blink::Role::kComboBoxGrouping:
@@ -2942,64 +3517,15 @@ ax::mojom::blink::Role AXObject::DetermineAriaRoleAttribute() const {
role = ax::mojom::blink::Role::kComboBoxMenuButton;
}
- if (role != ax::mojom::blink::Role::kUnknown)
- return role;
-
- return ax::mojom::blink::Role::kUnknown;
+ return role;
}
-ax::mojom::blink::Role AXObject::RemapAriaRoleDueToParent(
- ax::mojom::blink::Role role) const {
- // Some objects change their role based on their parent.
- // However, asking for the unignoredParent calls accessibilityIsIgnored(),
- // which can trigger a loop. While inside the call stack of creating an
- // element, we need to avoid accessibilityIsIgnored().
- // https://bugs.webkit.org/show_bug.cgi?id=65174
-
- // Don't return table roles unless inside a table-like container.
- switch (role) {
- case ax::mojom::blink::Role::kRow:
- case ax::mojom::blink::Role::kRowGroup:
- case ax::mojom::blink::Role::kCell:
- case ax::mojom::blink::Role::kRowHeader:
- case ax::mojom::blink::Role::kColumnHeader:
- for (AXObject* ancestor = ParentObjectUnignored(); ancestor;
- ancestor = ancestor->ParentObjectUnignored()) {
- ax::mojom::blink::Role ancestor_aria_role =
- ancestor->AriaRoleAttribute();
- if (ancestor_aria_role == ax::mojom::blink::Role::kCell)
- return ax::mojom::blink::Role::kGenericContainer; // In another cell,
- // illegal.
- if (ancestor->IsTableLikeRole())
- return role; // Inside a table: ARIA role is legal.
- }
- return ax::mojom::blink::Role::kGenericContainer; // Not in a table.
- default:
- break;
- }
-
- if (role != ax::mojom::blink::Role::kListBoxOption &&
- role != ax::mojom::blink::Role::kMenuItem)
- return role;
-
- for (AXObject* parent = ParentObject();
- parent && !parent->AccessibilityIsIgnored();
- parent = parent->ParentObject()) {
- ax::mojom::blink::Role parent_aria_role = parent->AriaRoleAttribute();
-
- // Selects and listboxes both have options as child roles, but they map to
- // different roles within WebCore.
- if (role == ax::mojom::blink::Role::kListBoxOption &&
- parent_aria_role == ax::mojom::blink::Role::kMenu)
- return ax::mojom::blink::Role::kMenuItem;
-
- // If the parent had a different role, then we don't need to continue
- // searching up the chain.
- if (parent_aria_role != ax::mojom::blink::Role::kUnknown)
- break;
- }
-
- return role;
+void AXObject::UpdateRoleForImage() {
+ // There's no need to fire a role changed event or MarkDirty because the
+ // only time the role changes is when we're updating children anyway.
+ // TODO(accessibility) Use one Blink role and move this to the browser.
+ role_ = children_.size() ? ax::mojom::blink::Role::kImageMap
+ : ax::mojom::blink::Role::kImage;
}
bool AXObject::IsEditableRoot() const {
@@ -3076,20 +3602,19 @@ AXObject::InOrderTraversalIterator AXObject::GetInOrderTraversalIterator() {
}
int AXObject::ChildCountIncludingIgnored() const {
- return HasIndirectChildren() ? 0 : int{ChildrenIncludingIgnored().size()};
+ return int{ChildrenIncludingIgnored().size()};
}
AXObject* AXObject::ChildAtIncludingIgnored(int index) const {
- // We need to use "ChildCountIncludingIgnored()" and
- // "ChildrenIncludingIgnored()" instead of using the "children_" member
- // directly, because we might need to update children and check for the
- // presence of indirect children.
- if (index < 0 || index >= ChildCountIncludingIgnored())
+ DCHECK_GE(index, 0);
+ DCHECK_LE(index, ChildCountIncludingIgnored());
+ if (index >= ChildCountIncludingIgnored())
return nullptr;
return ChildrenIncludingIgnored()[index];
}
const AXObject::AXObjectVector& AXObject::ChildrenIncludingIgnored() const {
+ DCHECK(!IsDetached());
return const_cast<AXObject*>(this)->ChildrenIncludingIgnored();
}
@@ -3103,14 +3628,15 @@ const AXObject::AXObjectVector AXObject::UnignoredChildren() const {
}
const AXObject::AXObjectVector AXObject::UnignoredChildren() {
+ UpdateChildrenIfNecessary();
+
if (!AccessibilityIsIncludedInTree()) {
NOTREACHED() << "We don't support finding the unignored children of "
- "objects excluded from the accessibility tree.";
+ "objects excluded from the accessibility tree: "
+ << ToString(true, true);
return {};
}
- UpdateChildrenIfNecessary();
-
// Capture only descendants that are not accessibility ignored, and that are
// one level deeper than the current object after flattening any accessibility
// ignored descendants.
@@ -3156,11 +3682,16 @@ AXObject* AXObject::FirstChildIncludingIgnored() const {
}
AXObject* AXObject::LastChildIncludingIgnored() const {
+ DCHECK(!IsDetached());
return ChildCountIncludingIgnored() ? *(ChildrenIncludingIgnored().end() - 1)
: nullptr;
}
AXObject* AXObject::DeepestFirstChildIncludingIgnored() const {
+ if (IsDetached()) {
+ NOTREACHED();
+ return nullptr;
+ }
if (!ChildCountIncludingIgnored())
return nullptr;
@@ -3172,6 +3703,10 @@ AXObject* AXObject::DeepestFirstChildIncludingIgnored() const {
}
AXObject* AXObject::DeepestLastChildIncludingIgnored() const {
+ if (IsDetached()) {
+ NOTREACHED();
+ return nullptr;
+ }
if (!ChildCountIncludingIgnored())
return nullptr;
@@ -3195,8 +3730,9 @@ bool AXObject::IsDescendantOf(const AXObject& ancestor) const {
AXObject* AXObject::NextSiblingIncludingIgnored() const {
if (!AccessibilityIsIncludedInTree()) {
- NOTREACHED() << "We don't support iterating over objects excluded "
- "from the accessibility tree.";
+ NOTREACHED() << "We don't support iterating children of objects excluded "
+ "from the accessibility tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3212,8 +3748,9 @@ AXObject* AXObject::NextSiblingIncludingIgnored() const {
AXObject* AXObject::PreviousSiblingIncludingIgnored() const {
if (!AccessibilityIsIncludedInTree()) {
- NOTREACHED() << "We don't support iterating over objects excluded "
- "from the accessibility tree.";
+ NOTREACHED() << "We don't support iterating children of objects excluded "
+ "from the accessibility tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3230,8 +3767,9 @@ AXObject* AXObject::PreviousSiblingIncludingIgnored() const {
AXObject* AXObject::NextInPreOrderIncludingIgnored(
const AXObject* within) const {
if (!AccessibilityIsIncludedInTree()) {
- NOTREACHED() << "We don't support iterating over objects excluded "
- "from the accessibility tree.";
+ NOTREACHED() << "We don't support iterating children of objects excluded "
+ "from the accessibility tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3254,8 +3792,9 @@ AXObject* AXObject::NextInPreOrderIncludingIgnored(
AXObject* AXObject::PreviousInPreOrderIncludingIgnored(
const AXObject* within) const {
if (!AccessibilityIsIncludedInTree()) {
- NOTREACHED() << "We don't support iterating over objects excluded "
- "from the accessibility tree.";
+ NOTREACHED() << "We don't support iterating children of objects excluded "
+ "from the accessibility tree: "
+ << ToString(true, true);
return nullptr;
}
if (within == this)
@@ -3273,8 +3812,9 @@ AXObject* AXObject::PreviousInPreOrderIncludingIgnored(
AXObject* AXObject::PreviousInPostOrderIncludingIgnored(
const AXObject* within) const {
if (!AccessibilityIsIncludedInTree()) {
- NOTREACHED() << "We don't support iterating over objects excluded "
- "from the accessibility tree.";
+ NOTREACHED() << "We don't support iterating children of objects excluded "
+ "from the accessibility tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3309,7 +3849,8 @@ AXObject* AXObject::UnignoredNextSibling() const {
if (AccessibilityIsIgnored()) {
NOTREACHED() << "We don't support finding unignored siblings for ignored "
"objects because it is not clear whether to search for the "
- "sibling in the unignored tree or in the whole tree.";
+ "sibling in the unignored tree or in the whole tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3350,7 +3891,8 @@ AXObject* AXObject::UnignoredPreviousSibling() const {
if (AccessibilityIsIgnored()) {
NOTREACHED() << "We don't support finding unignored siblings for ignored "
"objects because it is not clear whether to search for the "
- "sibling in the unignored tree or in the whole tree.";
+ "sibling in the unignored tree or in the whole tree: "
+ << ToString(true, true);
return nullptr;
}
@@ -3408,23 +3950,20 @@ AXObject* AXObject::ParentObject() const {
if (IsDetached())
return nullptr;
- if (parent_)
- return parent_;
-
- if (AXObjectCache().IsAriaOwned(this))
- return AXObjectCache().GetAriaOwnedParent(this);
-
- return ComputeParent();
-}
-
-AXObject* AXObject::ParentObjectIfExists() const {
- if (IsDetached())
- return nullptr;
-
- if (parent_)
- return parent_;
+ // This can happen when an object in the middle of the tree is suddenly
+ // detached, but the children still exist. One example of this is when
+ // a <select size="1"> changes to <select size="2">, where the
+ // Role::kMenuListPopup is detached.
+ if (!parent_) {
+ DCHECK(!IsVirtualObject())
+ << "A virtual object must have a parent, and cannot exist without one. "
+ "The parent is set when the object is constructed.";
+ parent_ = ComputeParent();
+ DCHECK(parent_ || IsA<Document>(GetNode()))
+ << "The following node should have a parent: " << GetNode();
+ }
- return ComputeParentIfExists();
+ return parent_;
}
AXObject* AXObject::ParentObjectUnignored() const {
@@ -3460,47 +3999,139 @@ AXObject* AXObject::ContainerWidget() const {
return ancestor;
}
+// Only use layout object traversal for pseudo elements and their descendants.
+bool AXObject::ShouldUseLayoutObjectTraversalForChildren() const {
+ if (!GetLayoutObject())
+ return false;
+
+ // If no node, this is an anonymous layout object. The only way this can be
+ // reached is inside a pseudo element subtree.
+ if (!GetNode()) {
+ DCHECK(GetLayoutObject()->IsAnonymous());
+ DCHECK(AXObjectCacheImpl::IsPseudoElementDescendant(*GetLayoutObject()));
+ return true;
+ }
+
+ // The only other case for using layout builder traversal is for a pseudo
+ // element, such as ::before. Pseudo element child text and images are not
+ // visibited by LayoutBuilderTraversal.
+ return GetNode()->IsPseudoElement();
+}
+
void AXObject::UpdateChildrenIfNecessary() {
- if (!HasChildren())
- AddChildren();
+#if DCHECK_IS_ON()
+ DCHECK(GetDocument()) << ToString(true, true);
+ DCHECK(GetDocument()->IsActive());
+ DCHECK(!GetDocument()->IsDetached());
+ DCHECK(GetDocument()->GetPage());
+ DCHECK(GetDocument()->View());
+ DCHECK(!AXObjectCache().HasBeenDisposed());
+#endif
+
+ if (!NeedsToUpdateChildren())
+ return;
+
+ // Ensure children already cleared.
+#if DCHECK_IS_ON()
+ if (IsMenuList()) {
+ // AXMenuList is special and keeps its popup child.
+ DCHECK_LE(children_.size(), 1U);
+ } else {
+ // Ensure children have been correctly cleared.
+ DCHECK_EQ(children_.size(), 0U)
+ << "\nChildren should have been cleared in SetNeedsToUpdateChildren(): "
+ << GetNode() << " with " << children_.size() << " children";
+ }
+#endif
+
+ AddChildren();
+}
+
+bool AXObject::NeedsToUpdateChildren() const {
+ DCHECK(!children_dirty_ || CanHaveChildren())
+ << "Needs to update children but cannot have children: " << GetNode()
+ << " " << GetLayoutObject();
+ return children_dirty_;
+}
+
+void AXObject::SetNeedsToUpdateChildren() const {
+ DCHECK(!IsDetached()) << "Cannot update children on a detached node: "
+ << ToString(true, true);
+ if (children_dirty_ || !CanHaveChildren())
+ return;
+ children_dirty_ = true;
+ ClearChildren();
}
-void AXObject::ClearChildren() {
- // Detach all weak pointers from objects to their parents.
+void AXObject::ClearChildren() const {
+ // Detach all weak pointers from immediate children to their parents.
+ // First check to make sure the child's parent wasn't already reassigned.
+ // In addition, the immediate children are different from children_, and are
+ // the objects where the parent_ points to this. For example:
+ // Parent (this)
+ // Child not included in tree (immediate child)
+ // Child included in tree (an item in |children_|)
+ // These situations only occur for children that were backed by a DOM node.
+ // Therefore, in addition to looping through |children_|, we must also loop
+ // through any unincluded children associated with any DOM children;
+ // TODO(accessibility) Try to remove ugly second loop when we transition to
+ // AccessibilityExposeIgnoredNodes().
+
+ // Loop through AXObject children.
+
+#if DCHECK_IS_ON()
+ DCHECK(!is_adding_children_)
+ << "Should not be attempting to clear children while in the middle of "
+ "adding children on parent: "
+ << ToString(true, true);
+#endif
+
for (const auto& child : children_) {
- if (child->parent_ == this)
+ if (child->CachedParentObject() == this)
child->DetachFromParent();
}
children_.clear();
- have_children_ = false;
-}
-void AXObject::AddAccessibleNodeChildren() {
- Element* element = GetElement();
- if (!element)
+ if (!GetNode())
return;
- AccessibleNode* accessible_node = element->ExistingAccessibleNode();
- if (!accessible_node)
+ // <slot> content is always included in the tree, so there is no need to
+ // iterate through the nodes. This also protects us against slot use "after
+ // poison", where attempts to access assigned nodes triggers a DCHECK.
+
+ // Detailed explanation:
+ // <slot> elements are placeholders marking locations in a shadow tree where
+ // users of a web component can insert their own custom nodes. Inserted nodes
+ // (also known as distributed nodes) become children of their respective slots
+ // in the accessibility tree. In other words, the accessibility tree mirrors
+ // the flattened DOM tree or the layout tree, not the original DOM tree.
+ // Distributed nodes still maintain their parent relations and computed style
+ // information with their original location in the DOM. Therefore, we need to
+ // ensure that in the accessibility tree no remnant information from the
+ // unflattened DOM tree remains, such as the cached parent.
+ if (IsA<HTMLSlotElement>(GetNode()))
return;
- for (const auto& child : accessible_node->GetChildren())
- children_.push_back(AXObjectCache().GetOrCreate(child));
+ for (Node* child_node = LayoutTreeBuilderTraversal::FirstChild(*GetNode());
+ child_node;
+ child_node = LayoutTreeBuilderTraversal::NextSibling(*child_node)) {
+ AXObject* ax_child_from_node = AXObjectCache().Get(child_node);
+ if (ax_child_from_node &&
+ ax_child_from_node->CachedParentObject() == this) {
+ // Child was not cleared from first loop.
+ // It must have been an unincluded node who's parent is this,
+ // although it may now be included since the children were last updated.
+ // Check current parent first. It may be owned by another node.
+ ax_child_from_node->DetachFromParent();
+ }
+ }
}
Element* AXObject::GetElement() const {
return DynamicTo<Element>(GetNode());
}
-Document* AXObject::GetDocument() const {
- LocalFrameView* frame_view = DocumentFrameView();
- if (!frame_view)
- return nullptr;
-
- return frame_view->GetFrame().GetDocument();
-}
-
AXObject* AXObject::RootScroller() const {
Node* global_root_scroller = GetDocument()
->GetPage()
@@ -3517,14 +4148,9 @@ AXObject* AXObject::RootScroller() const {
}
LocalFrameView* AXObject::DocumentFrameView() const {
- const AXObject* object = this;
- while (object && !object->IsAXLayoutObject())
- object = object->ParentObject();
-
- if (!object)
- return nullptr;
-
- return object->DocumentFrameView();
+ if (Document* document = GetDocument())
+ return document->View();
+ return nullptr;
}
AtomicString AXObject::Language() const {
@@ -3544,8 +4170,8 @@ AtomicString AXObject::Language() const {
// handled browser side within AXNode::GetLanguage.
//
// TODO(chrishall): Consider moving this to AXNodeObject or AXLayoutObject as
- // the kRootWebArea node is currently an AXLayoutObject.
- if (RoleValue() == ax::mojom::blink::Role::kRootWebArea) {
+ // the web area node is currently an AXLayoutObject.
+ if (IsWebArea()) {
const Document* document = GetDocument();
if (document) {
// Fall back to the first content language specified in the meta tag.
@@ -3875,7 +4501,7 @@ void AXObject::GetRelativeBounds(AXObject** out_container,
}
}
- LayoutObject* layout_object = LayoutObjectForRelativeBounds();
+ LayoutObject* layout_object = GetLayoutObject();
if (!layout_object)
return;
@@ -4018,6 +4644,63 @@ LayoutRect AXObject::GetBoundsInFrameCoordinates() const {
// Modify or take an action on an object.
//
+bool AXObject::PerformAction(const ui::AXActionData& action_data) {
+ switch (action_data.action) {
+ case ax::mojom::blink::Action::kBlur:
+ return RequestFocusAction();
+ case ax::mojom::blink::Action::kClearAccessibilityFocus:
+ return InternalClearAccessibilityFocusAction();
+ case ax::mojom::blink::Action::kDecrement:
+ return RequestDecrementAction();
+ case ax::mojom::blink::Action::kDoDefault:
+ return RequestClickAction();
+ case ax::mojom::blink::Action::kFocus:
+ return RequestFocusAction();
+ case ax::mojom::blink::Action::kIncrement:
+ return RequestIncrementAction();
+ case ax::mojom::blink::Action::kScrollToPoint:
+ return RequestScrollToGlobalPointAction(
+ IntPoint(action_data.target_point));
+ case ax::mojom::blink::Action::kSetAccessibilityFocus:
+ return InternalSetAccessibilityFocusAction();
+ case ax::mojom::blink::Action::kSetScrollOffset:
+ SetScrollOffset(IntPoint(action_data.target_point));
+ return true;
+ case ax::mojom::blink::Action::kSetSequentialFocusNavigationStartingPoint:
+ return RequestSetSequentialFocusNavigationStartingPointAction();
+ break;
+ case ax::mojom::blink::Action::kSetValue:
+ return RequestSetValueAction(
+ WTF::String::FromUTF8(action_data.value.c_str()));
+ case ax::mojom::blink::Action::kShowContextMenu:
+ return RequestShowContextMenuAction();
+
+ case ax::mojom::blink::Action::kAnnotatePageImages:
+ case ax::mojom::blink::Action::kCollapse:
+ case ax::mojom::blink::Action::kCustomAction:
+ case ax::mojom::blink::Action::kExpand:
+ case ax::mojom::blink::Action::kGetImageData:
+ case ax::mojom::blink::Action::kGetTextLocation:
+ case ax::mojom::blink::Action::kHideTooltip:
+ case ax::mojom::blink::Action::kHitTest:
+ case ax::mojom::blink::Action::kInternalInvalidateTree:
+ case ax::mojom::blink::Action::kLoadInlineTextBoxes:
+ case ax::mojom::blink::Action::kNone:
+ case ax::mojom::blink::Action::kReplaceSelectedText:
+ case ax::mojom::blink::Action::kScrollBackward:
+ case ax::mojom::blink::Action::kScrollDown:
+ case ax::mojom::blink::Action::kScrollForward:
+ case ax::mojom::blink::Action::kScrollLeft:
+ case ax::mojom::blink::Action::kScrollRight:
+ case ax::mojom::blink::Action::kScrollToMakeVisible:
+ case ax::mojom::blink::Action::kScrollUp:
+ case ax::mojom::blink::Action::kSetSelection:
+ case ax::mojom::blink::Action::kShowTooltip:
+ case ax::mojom::blink::Action::kSignalEndOfTest:
+ return false;
+ }
+}
+
bool AXObject::RequestDecrementAction() {
Event* event =
Event::CreateCancelable(event_type_names::kAccessibledecrement);
@@ -4072,7 +4755,7 @@ bool AXObject::OnNativeClickAction() {
// For most elements, AccessKeyAction triggers sending a simulated
// click, including simulating the mousedown, mouseup, and click events.
- element->AccessKeyAction(true);
+ element->AccessKeyAction(SimulatedClickCreationScope::kFromAccessibility);
return true;
}
@@ -4269,7 +4952,7 @@ bool AXObject::OnNativeShowContextMenuAction() {
}
void AXObject::SelectionChanged() {
- if (AXObject* parent = ParentObjectIfExists())
+ if (AXObject* parent = ParentObject())
parent->SelectionChanged();
}
@@ -4327,22 +5010,6 @@ ax::mojom::blink::Role AXObject::AriaRoleToWebCoreRole(const String& value) {
return role;
}
-bool AXObject::NameFromSelectedOption(bool recursive) const {
- switch (RoleValue()) {
- // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
- case ax::mojom::blink::Role::kComboBoxGrouping:
- case ax::mojom::blink::Role::kComboBoxMenuButton:
- case ax::mojom::blink::Role::kListBox:
- return recursive;
- // This can be either a button widget with a non-false value of
- // aria-haspopup or a select element with size of 1.
- case ax::mojom::blink::Role::kPopUpButton:
- return DynamicTo<HTMLSelectElement>(*GetNode()) ? recursive : false;
- default:
- return false;
- }
-}
-
bool AXObject::SupportsNameFromContents(bool recursive) const {
// ARIA 1.1, section 5.2.7.5.
bool result = false;
@@ -4365,6 +5032,7 @@ bool AXObject::SupportsNameFromContents(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::kMath:
case ax::mojom::blink::Role::kMenuItem:
case ax::mojom::blink::Role::kMenuItemCheckBox:
case ax::mojom::blink::Role::kMenuItemRadio:
@@ -4392,10 +5060,7 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kArticle:
case ax::mojom::blink::Role::kBanner:
case ax::mojom::blink::Role::kBlockquote:
- case ax::mojom::blink::Role::kCaret:
- case ax::mojom::blink::Role::kClient:
case ax::mojom::blink::Role::kColorWell:
- case ax::mojom::blink::Role::kColumn:
case ax::mojom::blink::Role::kComboBoxMenuButton: // Only value from
// content.
case ax::mojom::blink::Role::kComboBoxGrouping:
@@ -4404,7 +5069,6 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kContentInfo:
case ax::mojom::blink::Role::kDate:
case ax::mojom::blink::Role::kDateTime:
- case ax::mojom::blink::Role::kDesktop:
case ax::mojom::blink::Role::kDialog:
case ax::mojom::blink::Role::kDirectory:
case ax::mojom::blink::Role::kDocCover:
@@ -4458,23 +5122,17 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kIframePresentational:
case ax::mojom::blink::Role::kIframe:
case ax::mojom::blink::Role::kImage:
- case ax::mojom::blink::Role::kImeCandidate: // Internal role, not used on
- // the web.
case ax::mojom::blink::Role::kInputTime:
- case ax::mojom::blink::Role::kKeyboard:
case ax::mojom::blink::Role::kListBox:
- case ax::mojom::blink::Role::kListGrid:
case ax::mojom::blink::Role::kLog:
case ax::mojom::blink::Role::kMain:
case ax::mojom::blink::Role::kMarquee:
- case ax::mojom::blink::Role::kMath:
case ax::mojom::blink::Role::kMenuListPopup:
case ax::mojom::blink::Role::kMenu:
case ax::mojom::blink::Role::kMenuBar:
case ax::mojom::blink::Role::kMeter:
case ax::mojom::blink::Role::kNavigation:
case ax::mojom::blink::Role::kNote:
- case ax::mojom::blink::Role::kPane:
case ax::mojom::blink::Role::kPluginObject:
case ax::mojom::blink::Role::kProgressIndicator:
case ax::mojom::blink::Role::kRadioGroup:
@@ -4487,25 +5145,19 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kSlider:
case ax::mojom::blink::Role::kSpinButton:
case ax::mojom::blink::Role::kStatus:
- case ax::mojom::blink::Role::kSliderThumb:
case ax::mojom::blink::Role::kSuggestion:
case ax::mojom::blink::Role::kSvgRoot:
case ax::mojom::blink::Role::kTable:
- case ax::mojom::blink::Role::kTableHeaderContainer:
case ax::mojom::blink::Role::kTabList:
case ax::mojom::blink::Role::kTabPanel:
case ax::mojom::blink::Role::kTerm:
case ax::mojom::blink::Role::kTextField:
case ax::mojom::blink::Role::kTextFieldWithComboBox:
- case ax::mojom::blink::Role::kTitleBar:
case ax::mojom::blink::Role::kTimer:
case ax::mojom::blink::Role::kToolbar:
case ax::mojom::blink::Role::kTree:
case ax::mojom::blink::Role::kTreeGrid:
case ax::mojom::blink::Role::kVideo:
- case ax::mojom::blink::Role::kWebArea:
- case ax::mojom::blink::Role::kWebView:
- case ax::mojom::blink::Role::kWindow:
result = false;
break;
@@ -4529,7 +5181,6 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kFooterAsNonLandmark:
case ax::mojom::blink::Role::kGenericContainer:
case ax::mojom::blink::Role::kHeaderAsNonLandmark:
- case ax::mojom::blink::Role::kIgnored:
case ax::mojom::blink::Role::kImageMap:
case ax::mojom::blink::Role::kInlineTextBox:
case ax::mojom::blink::Role::kLabelText:
@@ -4550,7 +5201,6 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
// if the row might receive focus
case ax::mojom::blink::Role::kRow:
case ax::mojom::blink::Role::kRuby:
- case ax::mojom::blink::Role::kRubyAnnotation:
case ax::mojom::blink::Role::kSection:
case ax::mojom::blink::Role::kStrong:
case ax::mojom::blink::Role::kTime:
@@ -4580,11 +5230,21 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
}
break;
- case ax::mojom::blink::Role::kPdfActionableHighlight:
- LOG(ERROR) << "PDF specific highlight role, Blink shouldn't generate "
- "this role type";
- NOTREACHED();
- break;
+ case ax::mojom::blink::Role::kRubyAnnotation:
+ // Ruby annotations are removed from accessible names and instead used
+ // as a description of the parent Role::kRuby object. The benefit is that
+ // announcement of the description can be toggled on/off per user choice.
+ // In this way, ruby annotations are treated like other annotations, e.g.
+ // <mark aria-description="annotation">base text</mark>.
+ // In order to achieve the above:
+ // * When recursive is true:
+ // Return false, so that the ruby annotation text does not contribute to
+ // the name of the parent Role::kRuby, since it will also be in the
+ // description of that object.
+ // * When recursive is false:
+ // Return true, so that text is generated for the object. This text will
+ // be assigned as the description of he parent Role::kRuby object.
+ return !recursive;
// A root web area normally only computes its name from the document title,
// but a root web area inside a portal's main frame should compute its name
@@ -4600,9 +5260,23 @@ bool AXObject::SupportsNameFromContents(bool recursive) const {
return is_inside_portal && is_main_frame;
}
+ case ax::mojom::blink::Role::kCaret:
+ case ax::mojom::blink::Role::kClient:
+ case ax::mojom::blink::Role::kColumn:
+ case ax::mojom::blink::Role::kDesktop:
+ case ax::mojom::blink::Role::kKeyboard:
+ case ax::mojom::blink::Role::kIgnored:
+ case ax::mojom::blink::Role::kImeCandidate:
+ case ax::mojom::blink::Role::kListGrid:
+ case ax::mojom::blink::Role::kPane:
+ case ax::mojom::blink::Role::kPdfActionableHighlight:
+ case ax::mojom::blink::Role::kPdfRoot:
+ case ax::mojom::blink::Role::kTableHeaderContainer:
+ case ax::mojom::blink::Role::kTitleBar:
case ax::mojom::blink::Role::kUnknown:
- LOG(ERROR) << "ax::mojom::blink::Role::kUnknown for " << GetNode();
- NOTREACHED();
+ case ax::mojom::blink::Role::kWebView:
+ case ax::mojom::blink::Role::kWindow:
+ NOTREACHED() << "Role shouldn't occur in Blink: " << ToString(true, true);
break;
}
@@ -4696,63 +5370,104 @@ const AXObject* AXObject::LowestCommonAncestor(const AXObject& first,
return common_ancestor;
}
-String AXObject::ToString(bool verbose) const {
+String AXObject::ToString(bool verbose, bool cached_values_only) const {
// Build a friendly name for debugging the object.
// If verbose, build a longer name name in the form of:
// CheckBox axid#28 <input.someClass#cbox1> name="checkbox"
String string_builder =
AXObject::InternalRoleName(RoleValue()).GetString().EncodeForDebugging();
+ if (IsDetached())
+ string_builder = string_builder + " (detached)";
+
if (verbose) {
string_builder = string_builder + " axid#" + String::Number(AXObjectID());
// Add useful HTML element info, like <div.myClass#myId>.
- if (GetElement()) {
+ if (GetElement())
+ string_builder = string_builder + " " + GetElementString(GetElement());
+
+ // Add properties of interest that often contribute to errors:
+ if (HasARIAOwns(GetElement())) {
string_builder =
- string_builder + " <" + GetElement()->tagName().LowerASCII();
- if (GetElement()->FastHasAttribute(html_names::kClassAttr)) {
- string_builder = string_builder + "." +
- GetElement()->FastGetAttribute(html_names::kClassAttr);
- }
- if (GetElement()->FastHasAttribute(html_names::kIdAttr)) {
- string_builder = string_builder + "#" +
- GetElement()->FastGetAttribute(html_names::kIdAttr);
- }
- string_builder = string_builder + ">";
+ string_builder + " aria-owns=" +
+ GetElement()->FastGetAttribute(html_names::kAriaOwnsAttr);
}
- // Add properties of interest that often contribute to errors:
- if (HasARIAOwns(GetElement()))
- string_builder = string_builder + " @aria-owns";
- if (GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kActiveDescendant))
- string_builder = string_builder + " @aria-activedescendant";
+ if (GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kActiveDescendant)) {
+ string_builder =
+ string_builder + " aria-activedescendant=" +
+ GetElement()->FastGetAttribute(html_names::kAriaOwnsAttr);
+ }
if (IsFocused())
string_builder = string_builder + " focused";
- if (AXObjectCache().IsAriaOwned(this))
+ if (!IsDetached() && AXObjectCache().IsAriaOwned(this))
string_builder = string_builder + " isAriaOwned";
- if (AccessibilityIsIgnored()) {
+ if (cached_values_only ? LastKnownIsIgnoredValue()
+ : AccessibilityIsIgnored()) {
string_builder = string_builder + " isIgnored";
- if (!AccessibilityIsIncludedInTree())
+#if defined(AX_FAIL_FAST_BUILD)
+ // TODO(accessibility) Move this out of AX_FAIL_FAST_BUILD by having a new
+ // ax_enum, and a ToString() in ax_enum_utils, as well as move out of
+ // String IgnoredReasonName(AXIgnoredReason reason) in
+ // inspector_type_builder_helper.cc.
+ if (!cached_values_only) {
+ AXObject::IgnoredReasons reasons;
+ ComputeAccessibilityIsIgnored(&reasons);
+ string_builder = string_builder + GetIgnoredReasonsDebugString(reasons);
+ }
+#endif
+ if (cached_values_only ? !LastKnownIsIncludedInTreeValue()
+ : !AccessibilityIsIncludedInTree())
string_builder = string_builder + " isRemovedFromTree";
}
- if (GetNode() &&
- DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock(
- *GetNode(), DisplayLockActivationReason::kAccessibility)) {
- string_builder = string_builder + " isDisplayLocked";
+ if (GetNode()) {
+ if (GetNode()->OwnerShadowHost()) {
+ string_builder = string_builder + (GetNode()->IsInUserAgentShadowRoot()
+ ? " inUserAgentShadowRoot:"
+ : " inShadowRoot:");
+ string_builder = string_builder + "<" +
+ GetNode()->OwnerShadowHost()->tagName().LowerASCII() +
+ ">";
+ }
+ if (GetNode()->GetShadowRoot()) {
+ string_builder = string_builder + " hasShadowRoot";
+ }
+ if (DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock(
+ *GetNode(), DisplayLockActivationReason::kAccessibility)) {
+ string_builder = string_builder + " isDisplayLocked";
+ }
}
- if (AriaHiddenRoot())
- string_builder = string_builder + " isAriaHidden";
- if (IsHiddenViaStyle())
+ if (const AXObject* aria_hidden_root = AriaHiddenRoot()) {
+ string_builder = string_builder + " ariaHiddenRoot";
+ if (aria_hidden_root != this) {
+ string_builder =
+ string_builder + GetElementString(aria_hidden_root->GetElement());
+ }
+ }
+ if (GetDocument() && GetDocument()->Lifecycle().GetState() <
+ DocumentLifecycle::kLayoutClean) {
+ string_builder = string_builder + " styleInfoUnavailable";
+ } else if (IsHiddenViaStyle()) {
string_builder = string_builder + " isHiddenViaCSS";
+ }
if (GetNode() && GetNode()->IsInert())
string_builder = string_builder + " isInert";
+ if (NeedsToUpdateChildren())
+ string_builder = string_builder + " needsToUpdateChildren";
+ if (!GetLayoutObject())
+ string_builder = string_builder + " missingLayout";
- string_builder = string_builder + " name=";
+ if (!cached_values_only)
+ string_builder = string_builder + " name=";
} else {
string_builder = string_builder + ": ";
}
// Append name last, in case it is long.
- return string_builder + ComputedName().EncodeForDebugging();
+ if (!cached_values_only)
+ string_builder = string_builder + ComputedName().EncodeForDebugging();
+
+ return string_builder;
}
bool operator==(const AXObject& first, const AXObject& second) {
@@ -4805,6 +5520,13 @@ bool operator>=(const AXObject& first, const AXObject& second) {
return first == second || first > second;
}
+std::ostream& operator<<(std::ostream& stream, const AXObject* obj) {
+ if (obj)
+ return stream << obj->ToString(true).Utf8();
+ else
+ return stream << "<AXObject nullptr>";
+}
+
std::ostream& operator<<(std::ostream& stream, const AXObject& obj) {
return stream << obj.ToString(true).Utf8();
}
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 facf78875de..0f4b4809704 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -57,6 +57,7 @@
class SkMatrix44;
namespace ui {
+struct AXActionData;
struct AXNodeData;
}
@@ -65,7 +66,6 @@ namespace blink {
class AccessibleNodeList;
class AXObject;
class AXObjectCacheImpl;
-class AXRange;
class IntPoint;
class LayoutObject;
class LocalFrameView;
@@ -80,13 +80,6 @@ enum class AOMFloatProperty;
enum class AOMRelationProperty;
enum class AOMRelationListProperty;
-class AXSparseAttributeClient {
- public:
- virtual void AddObjectAttribute(AXObjectAttribute, AXObject&) = 0;
- virtual void AddObjectVectorAttribute(AXObjectVectorAttribute,
- HeapVector<Member<AXObject>>*) = 0;
-};
-
class IgnoredReason {
DISALLOW_NEW();
@@ -163,6 +156,10 @@ class DescriptionSource {
void Trace(Visitor* visitor) const { visitor->Trace(related_objects); }
};
+// Returns a ax::mojom::blink::MarkerType cast to an int, suitable
+// for serializing into AXNodeData.
+int32_t ToAXMarkerType(DocumentMarker::MarkerType marker_type);
+
} // namespace blink
WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::IgnoredReason)
@@ -343,6 +340,12 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
protected:
explicit AXObject(AXObjectCacheImpl&);
+#if DCHECK_IS_ON()
+ bool is_initializing_ = false;
+ mutable bool is_updating_cached_values_ = false;
+ bool is_adding_children_ = false;
+#endif
+
public:
virtual ~AXObject();
virtual void Trace(Visitor*) const;
@@ -353,16 +356,21 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// unique ID, then added to AXObjectCacheImpl, and finally init() must
// be called last.
void SetAXObjectID(AXID ax_object_id) { id_ = ax_object_id; }
- virtual void Init();
+ virtual void Init(AXObject* parent_if_known);
// When the corresponding WebCore object that this AXObject
// wraps is deleted, it must be detached.
virtual void Detach();
- virtual bool IsDetached() const;
+ bool IsDetached() const;
- // Sets the parent AXObject directly. If the parent of this object is known,
- // this can be faster than using computeParent().
- virtual void SetParent(AXObject* parent);
+ // Updates the cached attribute values. This may be recursive, so to prevent
+ // deadlocks, functions called here may only search up the tree (ancestors),
+ // not down.
+ // Fires children change on the parent if the node's ignored or included in
+ // tree status changes. Use |notify_parent_of_ignored_changes = false| to
+ // prevent this.
+ void UpdateCachedAttributeValuesIfNeeded(
+ bool notify_parent_of_ignored_changes = true) const;
// The AXObjectCacheImpl that owns this object, and its unique ID within this
// cache.
@@ -395,8 +403,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
void TokenVectorFromAttribute(Vector<String>&, const QualifiedName&) const;
- void GetSparseAXAttributes(AXSparseAttributeClient&) const;
-
// Serialize the properties of this node into |node_data|.
//
// TODO(crbug.com/1068668): AX onion soup - finish migrating
@@ -418,17 +424,15 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual bool IsProgressIndicator() const;
virtual bool IsAXRadioInput() const;
virtual bool IsSlider() const;
- virtual bool IsAXSVGRoot() const;
virtual bool IsValidationMessage() const;
virtual bool IsVirtualObject() const;
// Check object role or purpose.
- virtual ax::mojom::blink::Role RoleValue() const;
+ ax::mojom::blink::Role RoleValue() const;
bool IsARIATextControl() const;
bool IsAnchor() const;
bool IsButton() const;
bool IsCanvas() const;
- bool IsCheckbox() const;
bool IsCheckboxOrRadio() const;
bool IsColorWell() const;
virtual bool IsControl() const;
@@ -453,9 +457,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual bool IsPasswordField() const;
bool IsPasswordFieldAndShouldHideValue() const;
bool IsPresentational() const;
- bool IsRadioButton() const {
- return RoleValue() == ax::mojom::blink::Role::kRadioButton;
- }
bool IsRangeValueSupported() const;
bool IsScrollbar() const {
return RoleValue() == ax::mojom::blink::Role::kScrollBar;
@@ -487,7 +488,7 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual bool IsLineBreakingObject() const { return false; }
virtual bool IsLinked() const { return false; }
virtual bool IsLoaded() const { return false; }
- virtual bool IsModal() const { return false; }
+ virtual bool IsModal() const;
virtual bool IsMultiSelectable() const { return false; }
virtual bool IsOffScreen() const { return false; }
virtual bool IsRequired() const { return false; }
@@ -524,7 +525,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const {
return true;
}
- virtual bool CanIgnoreTextAsEmpty() const { return false; }
bool AccessibilityIsIgnoredByDefault(IgnoredReasons* = nullptr) const;
virtual AXObjectInclusion DefaultObjectInclusion(
IgnoredReasons* = nullptr) const;
@@ -533,6 +533,9 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
bool ComputeIsInertOrAriaHidden(IgnoredReasons* = nullptr) const;
bool IsBlockedByAriaModalDialog(IgnoredReasons* = nullptr) const;
bool IsDescendantOfLeafNode() const;
+ bool LastKnownIsDescendantOfLeafNode() const {
+ return cached_is_descendant_of_leaf_node_;
+ }
AXObject* LeafNodeAncestor() const;
bool IsDescendantOfDisabledNode() const;
bool ComputeAccessibilityIsIgnoredButIncludedInTree() const;
@@ -541,10 +544,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
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;
@@ -638,8 +639,7 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
//
virtual const AtomicString& AccessKey() const { return g_null_atom; }
- RGBA32 BackgroundColor() const;
- virtual RGBA32 ComputeBackgroundColor() const { return Color::kTransparent; }
+ virtual RGBA32 BackgroundColor() const { return Color::kTransparent; }
virtual RGBA32 GetColor() const { return Color::kBlack; }
// Used by objects of role ColorWellRole.
virtual RGBA32 ColorValue() const { return Color::kTransparent; }
@@ -708,13 +708,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
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.
@@ -786,7 +779,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual AXRestriction Restriction() const;
// ARIA attributes.
- virtual ax::mojom::blink::Role DetermineAccessibilityRole();
+ virtual ax::mojom::blink::Role DetermineAccessibilityRole() = 0;
+ void UpdateRoleForImage(); // Set role to image (leaf) or map (has children).
ax::mojom::blink::Role DetermineAriaRoleAttribute() const;
virtual ax::mojom::blink::Role AriaRoleAttribute() const;
virtual bool HasAriaAttribute() const { return false; }
@@ -825,8 +819,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
bool IsLiveRegionRoot() const; // Any live region, including polite="off".
bool IsActiveLiveRegionRoot() const; // Live region that is not polite="off".
AXObject* LiveRegionRoot() const; // Container that controls live politeness.
- virtual const AtomicString& LiveRegionStatus() const { return g_null_atom; }
- virtual const AtomicString& LiveRegionRelevant() const { return g_null_atom; }
+ virtual const AtomicString& LiveRegionStatus() const;
+ virtual const AtomicString& LiveRegionRelevant() const;
bool LiveRegionAtomic() const;
const AtomicString& ContainerLiveRegionStatus() const;
@@ -867,7 +861,7 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
}
// Called on the AX object after the layout tree determines which is the right
// AXLayoutObject.
- virtual AXObject* ElementAccessibilityHitTest(const IntPoint&) const;
+ AXObject* ElementAccessibilityHitTest(const IntPoint&) const;
//
// High-level accessibility tree access. Other modules should only use these
@@ -915,9 +909,6 @@ 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.
@@ -927,6 +918,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
//
// Can be called on all nodes that are included in the accessibility tree,
// including those that are accessibility ignored.
+ // TODO(accessibility) This actually returns ignored children when they are
+ // included in the tree. A better name would be ChildrenIncludedInTree().
const AXObjectVector UnignoredChildren() const;
const AXObjectVector UnignoredChildren();
@@ -1046,15 +1039,29 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
AXObject* ParentObject() const;
// Get the parent of this object if it has already been created.
- //
// Works for all nodes, and may return nodes that are accessibility ignored,
// including nodes that might not be in the tree.
- AXObject* ParentObjectIfExists() const;
-
- virtual AXObject* ComputeParent() const = 0;
- virtual AXObject* ComputeParentIfExists() const { return nullptr; }
AXObject* CachedParentObject() const { return parent_; }
+ // Sets the parent AXObject directly. If the parent of this object is known,
+ // this can be faster than using ComputeParent().
+ void SetParent(AXObject* new_parent);
+
+ // If parent was not initialized during AddChildren() it can be computed by
+ // walking the DOM (or layout for nodeless aka anonymous layout object).
+ // ComputeParent() adds DCHECKs to ensure that it is not being called when
+ // an attached parent_ is already cached, and that it is possible to compute
+ // the parent. It calls ComputeParentImpl() for the actual work.
+ AXObject* ComputeParent() const;
+ // Subclasses override ComputeParentImpl() to change parent computation.
+ virtual AXObject* ComputeParentImpl() const;
+
+#if DCHECK_IS_ON()
+ // When the parent on children during AddChildren(), take the opportunity to
+ // check out ComputeParent() implementation. It should match.
+ void EnsureCorrectParentComputation();
+#endif
+
// Get or create the first ancestor that's not accessibility ignored.
// Works for all nodes.
AXObject* ParentObjectUnignored() const;
@@ -1066,36 +1073,19 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
AXObject* ContainerWidget() const;
bool IsContainerWidget() const;
- // Low-level accessibility tree exploration, only for use within the
- // accessibility module.
-
- // Returns the AXObject's first child, skipping over any children that
- // represent continuations in the layout tree. If the AXObject has no
- // children, returns the AXObject representing the next in pre-order
- // continuation in the layout tree, if any.
- //
- // In the accessibility tree, this results in continuations becoming
- // descendants of the nodes they "continue".
- virtual AXObject* RawFirstChild() const { return nullptr; }
-
- // Returns the AXObject's next sibling, skipping over any siblings that
- // represent continuations in the layout tree. If this is the last child,
- // returns the AXObject representing the next in pre-order continuation in the
- // layout tree, if any.
- //
- // In the accessibility tree, this results in continuations becoming
- // descendants of the nodes they "continue".
- virtual AXObject* RawNextSibling() const { return nullptr; }
-
- virtual void AddChildren() {}
+ // There are two types of traversal for obtaining children:
+ // 1. LayoutTreeBuilderTraversal. Despite the name, this traverses a flattened
+ // DOM tree that includes pseudo element children such as ::before, and where
+ // shadow DOM slotting has been run.
+ // 2. LayoutObject traversal. This is necessary if there is no parent node,
+ // or in a pseudo element subtree.
+ bool ShouldUseLayoutObjectTraversalForChildren() const;
virtual bool CanHaveChildren() const { return true; }
- bool HasChildren() const { return have_children_; }
- virtual void UpdateChildrenIfNecessary();
- virtual bool NeedsToUpdateChildren() const { return false; }
- virtual void SetNeedsToUpdateChildren() {}
- virtual void ClearChildren();
+ void UpdateChildrenIfNecessary();
+ bool NeedsToUpdateChildren() const;
+ void SetNeedsToUpdateChildren() const;
+ virtual void ClearChildren() const;
void DetachFromParent() { parent_ = nullptr; }
- void AddAccessibleNodeChildren();
virtual void SelectedOptions(AXObjectVector&) const {}
// Properties of the object's owning document or page.
@@ -1106,8 +1096,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual Node* GetNode() const { return nullptr; }
Element* GetElement() const; // Same as GetNode, if it's an Element.
virtual LayoutObject* GetLayoutObject() const { return nullptr; }
- virtual Document* GetDocument() const;
- virtual LocalFrameView* DocumentFrameView() const;
+ virtual Document* GetDocument() const = 0;
+ LocalFrameView* DocumentFrameView() const;
virtual Element* AnchorElement() const { return nullptr; }
virtual Element* ActionElement() const { return nullptr; }
virtual AtomicString Language() const;
@@ -1169,6 +1159,10 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// that isn't handled it calls |DoNativeIncrement|.
//
// These all return true if handled.
+ //
+ // Note: we're migrating to have PerformAction() be the only public
+ // interface, the others will all be private.
+ bool PerformAction(const ui::AXActionData&);
bool RequestDecrementAction();
bool RequestClickAction();
bool RequestFocusAction();
@@ -1243,19 +1237,24 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
bool IsHiddenForTextAlternativeCalculation() const;
// Returns a string representation of this object.
- String ToString(bool verbose = false) const;
+ // |cached_values_only| avoids recomputing cached values, and thus can be
+ // used during UpdateCachedValuesIfNecessary() without causing recursion.
+ String ToString(bool verbose = false, bool cached_values_only = false) const;
protected:
AXID id_;
- AXObjectVector children_;
- mutable bool have_children_;
+ // Any parent, regardless of whether it's ignored or not included in the tree.
+ mutable Member<AXObject> parent_;
+ // Only children that are included in tree, maybe rename to children_in_tree_.
+ mutable AXObjectVector children_;
+ mutable bool children_dirty_;
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_;
+ virtual void AddChildren() = 0;
+
// Used only inside textAlternative():
static String CollapseWhitespace(const String&);
static String RecursiveTextAlternative(const AXObject&,
@@ -1290,14 +1289,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
return nullptr;
}
- bool NameFromSelectedOption(bool recursive) const;
-
ax::mojom::blink::Role ButtonRoleType() const;
- virtual LayoutObject* LayoutObjectForRelativeBounds() const {
- return nullptr;
- }
-
bool CanSetSelectedAttribute() const;
const AXObject* InertRoot() const;
@@ -1311,16 +1304,27 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
const AXObject* TableRowParent() const;
const AXObject* TableParent() const;
- mutable Member<AXObject> parent_;
+ // Helpers for serialization.
+ void SerializeStyleAttributes(ui::AXNodeData* node_data);
+ void SerializeSparseAttributes(ui::AXNodeData* node_data);
+ void SerializeTableAttributes(ui::AXNodeData* node_data);
+ void SerializeListAttributes(ui::AXNodeData* node_data);
+ void SerializeScrollAttributes(ui::AXNodeData* node_data);
+ void SerializeChooserPopupAttributes(ui::AXNodeData* node_data);
+ void SerializeElementAttributes(ui::AXNodeData* dst);
+ void SerializeHTMLAttributes(ui::AXNodeData* dst);
- // The following cached attribute values (the ones starting with m_cached*)
- // are only valid if m_lastModificationCount matches
- // AXObjectCacheImpl::modificationCount().
+ // Serialization implemented in specific subclasses.
+ virtual void SerializeMarkerAttributes(ui::AXNodeData* node_data) const;
+
+ private:
mutable int last_modification_count_;
- mutable RGBA32 cached_background_color_;
+
+ // The following cached attribute values (the ones starting with m_cached*)
+ // are only valid if last_modification_count_ matches
+ // AXObjectCacheImpl::ModificationCount().
mutable bool cached_is_ignored_ : 1;
mutable bool cached_is_ignored_but_included_in_tree_ : 1;
-
mutable bool cached_is_inert_or_aria_hidden_ : 1;
mutable bool cached_is_hidden_via_style : 1;
mutable bool cached_is_descendant_of_leaf_node_ : 1;
@@ -1334,18 +1338,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
Member<AXObjectCacheImpl> ax_object_cache_;
- // Updates the cached attribute values. This may be recursive, so to prevent
- // deadlocks,
- // 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 SerializeStyleAttributes(ui::AXNodeData* node_data);
- void SerializeTableAttributes(ui::AXNodeData* node_data);
-
- private:
void UpdateDistributionForFlatTreeTraversal() const;
bool IsARIAControlledByTextboxWithActiveDescendant() const;
bool AncestorExposesActiveDescendant() const;
@@ -1391,6 +1383,7 @@ MODULES_EXPORT bool operator<=(const AXObject& first, const AXObject& second);
MODULES_EXPORT bool operator>(const AXObject& first, const AXObject& second);
MODULES_EXPORT bool operator>=(const AXObject& first, const AXObject& second);
MODULES_EXPORT std::ostream& operator<<(std::ostream&, const AXObject&);
+MODULES_EXPORT std::ostream& operator<<(std::ostream&, const AXObject*);
} // namespace blink
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 a9d8fe00ad0..8e205fe4669 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
@@ -52,18 +52,21 @@
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_label_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/html/html_area_element.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
-#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
-#include "third_party/blink/renderer/core/html/html_table_element.h"
-#include "third_party/blink/renderer/core/html/html_table_row_element.h"
+#include "third_party/blink/renderer/core/html/html_plugin_element.h"
+#include "third_party/blink/renderer/core/html/html_script_element.h"
+#include "third_party/blink/renderer/core/html/html_slot_element.h"
+#include "third_party/blink/renderer/core/html/html_style_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
-#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_progress.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
@@ -73,10 +76,10 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/svg/svg_style_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"
#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_list.h"
#include "third_party/blink/renderer/modules/accessibility/ax_list_box.h"
#include "third_party/blink/renderer/modules/accessibility/ax_list_box_option.h"
#include "third_party/blink/renderer/modules/accessibility/ax_media_element.h"
@@ -84,10 +87,8 @@
#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h"
#include "third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h"
#include "third_party/blink/renderer/modules/accessibility/ax_progress_indicator.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_radio_input.h"
#include "third_party/blink/renderer/modules/accessibility/ax_relation_cache.h"
#include "third_party/blink/renderer/modules/accessibility/ax_slider.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_svg_root.h"
#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h"
#include "third_party/blink/renderer/modules/accessibility/ax_virtual_object.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
@@ -129,9 +130,328 @@ bool IsActive(Document& document) {
return document.IsActive() && !document.IsDetached();
}
+bool HasAriaCellRole(Element* elem) {
+ DCHECK(elem);
+ const AtomicString& role_str = elem->FastGetAttribute(html_names::kRoleAttr);
+ if (role_str.IsEmpty())
+ return false;
+
+ return ui::IsCellOrTableHeader(AXObject::AriaRoleToWebCoreRole(role_str));
+}
+
+// Return true if whitespace is not necessary to keep adjacent_node separate
+// in screen reader output from surrounding nodes.
+bool CanIgnoreSpaceNextTo(LayoutObject* layout_object, bool is_after) {
+ if (!layout_object)
+ return true;
+
+ auto* elem = DynamicTo<Element>(layout_object->GetNode());
+
+ // Can usually ignore space next to a <br>.
+ // Exception: if the space was next to a <br> with an ARIA role.
+ if (layout_object->IsBR()) {
+ // As an example of a <br> with a role, Google Docs uses:
+ // <span contenteditable=false> <br role="presentation></span>.
+ // This construct hides the <br> from the AX tree and uses the space
+ // instead, presenting a hard line break as a soft line break.
+ DCHECK(elem);
+ return !is_after || !elem->FastHasAttribute(html_names::kRoleAttr);
+ }
+
+ // If adjacent to a whitespace character, the current space can be ignored.
+ if (layout_object->IsText()) {
+ auto* layout_text = To<LayoutText>(layout_object);
+ if (layout_text->HasEmptyText())
+ return false;
+ if (layout_text->GetText().Impl()->ContainsOnlyWhitespaceOrEmpty())
+ return true;
+ auto adjacent_char =
+ is_after ? layout_text->FirstCharacterAfterWhitespaceCollapsing()
+ : layout_text->LastCharacterAfterWhitespaceCollapsing();
+ return adjacent_char == ' ' || adjacent_char == '\n' ||
+ adjacent_char == '\t';
+ }
+
+ // Keep spaces between images and other visible content.
+ if (layout_object->IsLayoutImage())
+ return false;
+
+ // Do not keep spaces between blocks.
+ if (!layout_object->IsLayoutInline())
+ return true;
+
+ // If next to an element that a screen reader will always read separately,
+ // the the space can be ignored.
+ // Elements that are naturally focusable even without a tabindex tend
+ // to be rendered separately even if there is no space between them.
+ // Some ARIA roles act like table cells and don't need adjacent whitespace to
+ // indicate separation.
+ // False negatives are acceptable in that they merely lead to extra whitespace
+ // static text nodes.
+ if (elem && HasAriaCellRole(elem))
+ return true;
+
+ // Test against the appropriate child text node.
+ auto* layout_inline = To<LayoutInline>(layout_object);
+ LayoutObject* child =
+ is_after ? layout_inline->FirstChild() : layout_inline->LastChild();
+ if (!child && elem) {
+ // No children of inline element. Check adjacent sibling in same direction.
+ Node* adjacent_node =
+ is_after ? FlatTreeTraversal::NextSkippingChildren(*elem)
+ : FlatTreeTraversal::PreviousAbsoluteSibling(*elem);
+ return adjacent_node &&
+ CanIgnoreSpaceNextTo(adjacent_node->GetLayoutObject(), is_after);
+ }
+ return CanIgnoreSpaceNextTo(child, is_after);
+}
+
+bool IsTextRelevantForAccessibility(const LayoutText& layout_text) {
+ DCHECK(layout_text.Parent());
+ Node* node = layout_text.GetNode();
+ DCHECK(node); // Anonymous text is processed earlier, doesn't reach here.
+
+ // Ignore empty text.
+ if (layout_text.HasEmptyText())
+ return false;
+
+ // Always keep if anything other than collapsible whitespace.
+ if (!layout_text.IsAllCollapsibleWhitespace() || layout_text.IsBR())
+ return true;
+
+ // Will now look at sibling nodes. We need the closest element to the
+ // whitespace markup-wise, e.g. tag1 in these examples:
+ // [whitespace] <tag1><tag2>x</tag2></tag1>
+ // <span>[whitespace]</span> <tag1><tag2>x</tag2></tag1>
+ Node* prev_node = FlatTreeTraversal::PreviousAbsoluteSibling(*node);
+ if (!prev_node)
+ return false;
+
+ Node* next_node = FlatTreeTraversal::NextSkippingChildren(*node);
+ if (!next_node)
+ return false;
+
+ // Ignore extra whitespace-only text if a sibling will be presented
+ // separately by screen readers whether whitespace is there or not.
+ if (CanIgnoreSpaceNextTo(prev_node->GetLayoutObject(), false) ||
+ CanIgnoreSpaceNextTo(next_node->GetLayoutObject(), true)) {
+ return false;
+ }
+
+ // Text elements with empty whitespace are returned, because of cases
+ // such as <span>Hello</span><span> </span><span>World</span>. Keeping
+ // the whitespace-only node means we now correctly expose "Hello World".
+ // See crbug.com/435765.
+ return true;
+}
+
+bool IsShadowContentRelevantForAccessibility(const Node* node) {
+ DCHECK(node->ContainingShadowRoot());
+ // All author shadow content is relevant.
+ if (!node->IsInUserAgentShadowRoot())
+ return true;
+
+ // All non-slot user agent shadow nodes are relevant.
+ if (!IsA<HTMLSlotElement>(node))
+ return true;
+
+ // A PDF plugin (when it has content) exposes a slot as its first child.
+ // This child is only relevant if it has contents. Marking others irrelevant
+ // keeps PDF plugin AX hierarchies as expected, otherwise there is an extra
+ // ignored Role::kGenericContainer sibling before the Role::kPdfRoot.
+ // TODO(accessibility) This should either be a more general rule about slots,
+ // or fixed in the PDF tests.
+ if (IsA<HTMLPlugInElement>(LayoutTreeBuilderTraversal::Parent(*node)))
+ return To<HTMLSlotElement>(node)->AssignedNodes().size();
+
+ // If the UseAXMenuList flag is on, we use a specialized class AXMenuList
+ // for handling the user-agent shadow DOM exposed by a <select> element.
+ if (AXObjectCacheImpl::UseAXMenuList()) {
+ // Don't use any shadow root descendants, because AXMenuList already
+ // handles adding descendants and these would be redundant.
+ // DOM traversal is still necessary for the <canvas> case.
+ Node* host = node->OwnerShadowHost();
+ auto* select_element = DynamicTo<HTMLSelectElement>(host);
+ if (!select_element) {
+ if (auto* opt_group_element = DynamicTo<HTMLOptGroupElement>(host))
+ select_element = opt_group_element->OwnerSelectElement();
+ }
+
+ if (select_element) {
+ return !select_element->UsesMenuList() ||
+ select_element->IsInCanvasSubtree();
+ }
+ }
+
+ return true;
+}
+
+bool IsLayoutObjectRelevantForAccessibility(const LayoutObject& layout_object) {
+ if (layout_object.IsAnonymous()) {
+ // Anonymous means there is no DOM node, and it's been inserted by the
+ // layout engine within the tree. An example is an anonymous block that is
+ // inserted as a parent of an inline where there are block siblings.
+
+ // Visible anonymous content (text, image, layout quotes) is relevant.
+ if (!layout_object.CanHaveChildren()) {
+ if (layout_object.IsText())
+ return !To<LayoutText>(layout_object).HasEmptyText();
+ return true;
+ }
+
+ // Anonymous containers are not relevant, unless inside a pseudo element.
+ // Allowing anonymous pseudo elements ensures that all visible descendant
+ // pseudo content will be reached, despite only being able to walk layout
+ // inside of pseudo content.
+ return AXObjectCacheImpl::IsPseudoElementDescendant(layout_object);
+ }
+
+ if (layout_object.IsText())
+ return IsTextRelevantForAccessibility(To<LayoutText>(layout_object));
+
+ Node* node = layout_object.GetNode();
+ DCHECK(node) << "Non-anonymous layout objects always have a node";
+
+ if (node->ContainingShadowRoot() &&
+ !IsShadowContentRelevantForAccessibility(node)) {
+ return false;
+ }
+ // Menu list option and HTML area elements are indexed by DOM node, never by
+ // layout object.
+ if (AXObjectCacheImpl::ShouldCreateAXMenuListOptionFor(node))
+ return false;
+
+ if (IsA<HTMLAreaElement>(node))
+ return false;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// IsNodeRelevantForAccessibility() and IsLayoutObjectRelevantForAccessibility()
+// * if the LayoutObject is relevant and not display-locked,
+// GetOrCreate() will return an object that will be an AXLayoutObject or
+// derivative. Note that the node may or may not be relevant.
+// * Else if the Node is relevant, GetOrCreate() will return an object that will
+// be an AXNodeObject or derivative.
+// * Else neither are relevant, and the tree will be truncated (no descendants)
+// at this point.
+// -----------------------------------------------------------------------------
+// TODO(accessibility) Merge IsNodeRelevantForAccessibility() and
+// IsLayoutObjectRelevantForAccessibility() producing a function like
+// GetAXType(node, layout_object) returning kTruncateSubtree,
+// kAXNodeObject, or kAXLayoutObject. This will allow some of the checks that
+// currently happen twice, to only happen once.
+bool IsNodeRelevantForAccessibility(const Node* node,
+ bool parent_ax_known,
+ bool is_layout_object_relevant) {
+ if (!node || !node->isConnected())
+ return false;
+
+ if (node->IsDocumentNode())
+ return true;
+
+ if (node->IsTextNode()) {
+ // Layout has more info available to determine if whitespace is relevant.
+ // If display-locked, layout object may be missing or stale:
+ // Assume that all display-locked text nodes are relevant.
+ if (DisplayLockUtilities::NearestLockedInclusiveAncestor(*node))
+ return true;
+
+ // If rendered, decision is from IsLayoutObjectRelevantForAccessibility().
+ if (node->GetLayoutObject())
+ return is_layout_object_relevant;
+
+ // If unrendered + no parent, it is in a shadow tree. Consider irrelevant.
+ if (!node->parentElement()) {
+ DCHECK(node->IsInShadowTree());
+ return false;
+ }
+
+ // If unrendered and in <canvas>, consider even whitespace relevant.
+ // TODO(aleventhal) Consider including all text, even unrendered whitespace,
+ // whether or not in <canvas>. For now this matches previous behavior.
+ // Including all text would allow simply returning true at this point.
+ if (node->parentElement()->IsInCanvasSubtree())
+ return true;
+
+ // Must be unrendered because of CSS. Consider relevant if non-whitespace.
+ // Allowing rendered non-whitespace to be considered relevant will allow
+ // use for accessible relations such as labelledby and describedby.
+ return !To<Text>(node)->ContainsOnlyWhitespaceOrEmpty();
+ }
+
+ // Node also not relevant -- truncate subtree here.
+ if (node->ContainingShadowRoot() &&
+ !IsShadowContentRelevantForAccessibility(node)) {
+ return false;
+ }
+
+ if (!node->IsElementNode())
+ return false; // Only documents, elements and text nodes get ax objects.
+
+ if (IsA<HTMLAreaElement>(node) &&
+ !Traversal<HTMLMapElement>::FirstAncestor(*node)) {
+ return false; // <area> without ancestor <map> is not relevant.
+ }
+
+ if (IsA<HTMLMapElement>(node))
+ return false; // Contains children for an img, but is not its own object.
+
+ // When there is a layout object, the element is known to be visible, so
+ // consider it relevant and return early. Checking the layout object is only
+ // useful when display locking (content-visibility) is not used.
+ if (node->GetLayoutObject() &&
+ !DisplayLockUtilities::NearestLockedInclusiveAncestor(*node)) {
+ return true;
+ }
+
+ // The node is either hidden or display locked:
+ // Do not consider <head>/<style>/<script> relevant in these cases.
+ if (IsA<HTMLHeadElement>(node))
+ return false;
+ if (IsA<HTMLStyleElement>(node))
+ return false;
+ if (IsA<HTMLScriptElement>(node))
+ return false;
+
+ // Style elements in SVG are not display: none, unlike HTML style elements,
+ // but they are still hidden and thus treated as irrelevant for accessibility.
+ if (IsA<SVGStyleElement>(node))
+ return false;
+
+ // Not a <head>/<style>/<script>, or SVG<style>:
+ // Use a slower check to see if this node is anywhere inside of a <head>,
+ // <style> or <script>.
+ // This check is not necessary if the parent_ax is already known, which means
+ // we are attempting to add this object from something already relevant in the
+ // AX tree, and therefore can't be inside a <head>, <style>, <script> or SVG
+ // <style> element.
+ if (parent_ax_known)
+ return true; // No need to check inside if the parent exists.
+ // Objects inside <head> are irrelevant, except <title> (collects title text).
+ if (Traversal<HTMLHeadElement>::FirstAncestor(*node))
+ return IsA<HTMLTitleElement>(node);
+ // Objects inside a <style> are irrelevant.
+ if (Traversal<HTMLStyleElement>::FirstAncestor(*node))
+ return false;
+ // Objects inside a <script> are irrelevant.
+ if (Traversal<HTMLScriptElement>::FirstAncestor(*node))
+ return false;
+ // Objects inside an SVG <style> are irrelevant.
+ if (Traversal<SVGStyleElement>::FirstAncestor(*node))
+ return false;
+
+ // All other objects are relevant, even if hidden.
+ return true;
+}
+
} // namespace
// static
+bool AXObjectCacheImpl::use_ax_menu_list_ = false;
+
+// static
AXObjectCache* AXObjectCacheImpl::Create(Document& document) {
return MakeGarbageCollected<AXObjectCacheImpl>(document);
}
@@ -149,10 +469,6 @@ AXObjectCacheImpl::AXObjectCacheImpl(Document& document)
AddPermissionStatusListener();
documents_.insert(&document);
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() {
@@ -162,6 +478,11 @@ AXObjectCacheImpl::~AXObjectCacheImpl() {
}
void AXObjectCacheImpl::Dispose() {
+#if DCHECK_IS_ON()
+ DCHECK(!has_been_disposed_) << "Something is wrong, trying to dispose twice.";
+ has_been_disposed_ = true;
+#endif
+
for (auto& entry : objects_) {
AXObject* obj = entry.value;
obj->Detach();
@@ -169,10 +490,6 @@ void AXObjectCacheImpl::Dispose() {
}
permission_observer_receiver_.reset();
-
-#if DCHECK_IS_ON()
- has_been_disposed_ = true;
-#endif
}
AXObject* AXObjectCacheImpl::Root() {
@@ -198,10 +515,6 @@ Node* AXObjectCacheImpl::FocusedElement() {
if (!focused_node)
focused_node = document_;
- // If it's an image map, get the focused link within the image map.
- if (IsA<HTMLAreaElement>(focused_node))
- return focused_node;
-
// See if there's a page popup, for example a calendar picker.
Element* adjusted_focused_element = document_->AdjustedFocusedElement();
if (auto* input = DynamicTo<HTMLInputElement>(adjusted_focused_element)) {
@@ -216,10 +529,6 @@ Node* AXObjectCacheImpl::FocusedElement() {
}
AXObject* AXObjectCacheImpl::GetOrCreateFocusedObjectFromNode(Node* node) {
- // If it's an image map, get the focused link within the image map.
- if (auto* area = DynamicTo<HTMLAreaElement>(node))
- return FocusedImageMapUIElement(area);
-
if (node->GetDocument() != GetDocument() &&
node->GetDocument().Lifecycle().GetState() <
DocumentLifecycle::kLayoutClean) {
@@ -246,36 +555,6 @@ AXObject* AXObjectCacheImpl::GetOrCreateFocusedObjectFromNode(Node* node) {
return obj;
}
-AXObject* AXObjectCacheImpl::FocusedImageMapUIElement(
- HTMLAreaElement* area_element) {
- // Find the corresponding accessibility object for the HTMLAreaElement. This
- // should be in the list of children for its corresponding image.
- if (!area_element)
- return nullptr;
-
- HTMLImageElement* image_element = area_element->ImageElement();
- if (!image_element)
- return nullptr;
-
- AXObject* ax_layout_image = GetOrCreate(image_element);
- if (!ax_layout_image)
- return nullptr;
-
- const AXObject::AXObjectVector& image_children =
- ax_layout_image->ChildrenIncludingIgnored();
- unsigned count = image_children.size();
- for (unsigned k = 0; k < count; ++k) {
- AXObject* child = image_children[k];
- auto* ax_object = DynamicTo<AXImageMapLink>(child);
- if (!ax_object)
- continue;
-
- if (ax_object->AreaElement() == area_element)
- return child;
- }
-
- return nullptr;
-}
AXObject* AXObjectCacheImpl::FocusedObject() {
return GetOrCreateFocusedObjectFromNode(this->FocusedElement());
@@ -289,54 +568,37 @@ AXObject* AXObjectCacheImpl::Get(const LayoutObject* layout_object) {
DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
Node* node = layout_object->GetNode();
- if (node && DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
- // It's in a locked subtree so we need to search by node instead of by
- // layout object.
- if (ax_id) {
- // We previously saved the node in the cache with its layout object,
- // but now it's in a locked subtree so we should remove the entry with its
- // layout object and replace it with an AXNodeObject created from the node
- // instead.
- Remove(ax_id);
- return GetOrCreate(node);
- }
- return Get(node);
- }
if (!ax_id)
- return nullptr;
+ return node ? Get(node) : nullptr;
- return objects_.at(ax_id);
-}
-
-// Returns true if |node| is an <option> element and its parent <select>
-// is a menu list (not a list box).
-static bool IsMenuListOption(const Node* node) {
- auto* option_element = DynamicTo<HTMLOptionElement>(node);
- if (!option_element)
- return false;
- const HTMLSelectElement* select = option_element->OwnerSelectElement();
- if (!select || !select->UsesMenuList())
- return false;
- return select->GetLayoutObject();
-}
+ if ((node && DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) ||
+ !IsLayoutObjectRelevantForAccessibility(*layout_object)) {
+ // Change from AXLayoutObject -> AXNodeObject.
+ // We previously saved the node in the cache with its layout object,
+ // but now it's in a locked subtree so we should remove the entry with its
+ // layout object and replace it with an AXNodeObject created from the node
+ // instead. Do this later at a safe time.
+ Invalidate(ax_id);
+ }
-AXObject* AXObjectCacheImpl::GetIfExists(const Node* node) {
- AXID node_id = node_object_mapping_.at(node);
- DCHECK(!HashTraits<AXID>::IsDeletedValue(node_id));
- return node_id ? objects_.at(node_id) : nullptr;
+ AXObject* result = objects_.at(ax_id);
+#if DCHECK_IS_ON()
+ DCHECK(result) << "Had AXID for Node but no entry in objects_";
+ DCHECK(result->IsAXNodeObject());
+ // Do not allow detached objects except when disposing entire tree.
+ DCHECK(!result->IsDetached() || has_been_disposed_)
+ << "Detached AXNodeObject in map: "
+ << "AXID#" << ax_id << " Node=" << node;
+#endif
+ return result;
}
-// TODO(aleventhal) Remove side effects or rename, e.g. GetUpdated().
AXObject* AXObjectCacheImpl::Get(const Node* node) {
if (!node)
return nullptr;
- // Menu list option and HTML area elements are indexed by DOM node, never by
- // layout object.
LayoutObject* layout_object = node->GetLayoutObject();
- if (IsMenuListOption(node) || IsA<HTMLAreaElement>(node))
- layout_object = nullptr;
AXID layout_id = layout_object ? layout_object_mapping_.at(layout_object) : 0;
DCHECK(!HashTraits<AXID>::IsDeletedValue(layout_id));
@@ -344,54 +606,71 @@ AXObject* AXObjectCacheImpl::Get(const Node* node) {
AXID node_id = node_object_mapping_.at(node);
DCHECK(!HashTraits<AXID>::IsDeletedValue(node_id));
- if (layout_object &&
- DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
- // The node is in a display locked subtree, but we've previously put it in
- // the cache with its layout object.
- if (layout_id) {
- Remove(layout_id);
+ if (!layout_id && !node_id)
+ return nullptr;
+
+ // Some elements such as <area> are indexed by DOM node, not by layout object.
+ if (!layout_object ||
+ !IsLayoutObjectRelevantForAccessibility(*layout_object)) {
+ // Only text nodes still are able to become suddenly irrelevant.
+ if (layout_id && node->IsTextNode() &&
+ !IsNodeRelevantForAccessibility(node, /*parent known*/ false,
+ /*layout relevant*/ false)) {
+ // Layout object and node are now both irrelevant for accessibility.
+ // For example, text becomes irrelevant when it changes to whitespace, or
+ // if it already is whitespace and the text around it changes to makes it
+ // redundant whitespace. In this case, Invalidate(), which will remove
+ // objects that are no longer relevant.
+ Invalidate(layout_id);
+ } else {
+ // Layout object is irrelevant, but node object is still relevant.
+ layout_object = nullptr;
layout_id = 0;
}
- layout_object = nullptr;
}
- if (layout_object && node_id && !layout_id && !IsMenuListOption(node) &&
- !IsA<HTMLAreaElement>(node)) {
+ if (layout_id &&
+ DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
+ // Change from AXLayoutObject -> AXNodeObject.
+ // The node is in a display locked subtree, but we've previously put it in
+ // the cache with its layout object.
+ Invalidate(layout_id);
+ } else if (layout_object && node_id && !layout_id &&
+ !DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
+ // Change from AXNodeObject -> AXLayoutObject.
// 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.
- // In any case, reuse the ax_id since the node didn't change.
- Remove(node_id);
-
- // Note that this codepath can be reached when |layout_object| is about to
- // be destroyed.
-
- // This potentially misses root LayoutObject re-creation, but we have no way
- // of knowing whether the |layout_object| in those cases is still valid.
- if (!layout_object->Parent())
- return nullptr;
-
- layout_object_mapping_.Set(layout_object, node_id);
- AXObject* new_obj = CreateFromRenderer(layout_object);
- ids_in_use_.insert(node_id);
- 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;
+ Invalidate(node_id);
}
- if (layout_id)
- return objects_.at(layout_id);
+ if (layout_id) {
+ AXObject* result = objects_.at(layout_id);
+#if DCHECK_IS_ON()
+ DCHECK(result) << "Had AXID for LayoutObject but no entry in objects_";
+ DCHECK(result->IsAXLayoutObject());
+ // Do not allow detached objects except when disposing entire tree.
+ DCHECK(!result->IsDetached() || has_been_disposed_)
+ << "Detached AXLayoutObject in map: "
+ << "AXID#" << layout_id << " LayoutObject=" << layout_object;
+#endif
+ return result;
+ }
- if (!node_id)
- return nullptr;
+ DCHECK(node_id);
- return objects_.at(node_id);
+ AXObject* result = objects_.at(node_id);
+#if DCHECK_IS_ON()
+ DCHECK(result) << "Had AXID for Node but no entry in objects_";
+ DCHECK(result->IsAXNodeObject());
+ // Do not allow detached objects except when disposing entire tree.
+ DCHECK(!result->IsDetached() || has_been_disposed_)
+ << "Detached AXNodeObject in map: "
+ << "AXID#" << node_id << " Node=" << node;
+#endif
+ return result;
}
AXObject* AXObjectCacheImpl::Get(AbstractInlineTextBox* inline_text_box) {
@@ -403,7 +682,21 @@ AXObject* AXObjectCacheImpl::Get(AbstractInlineTextBox* inline_text_box) {
if (!ax_id)
return nullptr;
- return objects_.at(ax_id);
+ AXObject* result = objects_.at(ax_id);
+#if DCHECK_IS_ON()
+ DCHECK(result) << "Had AXID for inline text box but no entry in objects_";
+ DCHECK(result->IsAXInlineTextBox());
+ // Do not allow detached objects except when disposing entire tree.
+ DCHECK(!result->IsDetached() || has_been_disposed_)
+ << "Detached AXInlineTextBox in map: "
+ << "AXID#" << ax_id << " Node=" << inline_text_box->GetText();
+#endif
+ return result;
+}
+
+void AXObjectCacheImpl::Invalidate(AXID ax_id) {
+ if (invalidated_ids_.insert(ax_id).is_new_entry)
+ ScheduleVisualUpdate();
}
AXID AXObjectCacheImpl::GetAXID(Node* node) {
@@ -429,33 +722,30 @@ AXObject* AXObjectCacheImpl::Get(AccessibleNode* accessible_node) {
if (!ax_id)
return nullptr;
- return objects_.at(ax_id);
+ AXObject* result = objects_.at(ax_id);
+#if DCHECK_IS_ON()
+ DCHECK(result) << "Had AXID for accessible_node but no entry in objects_";
+ DCHECK(result->IsVirtualObject());
+ // Do not allow detached objects except when disposing entire tree.
+ DCHECK(!result->IsDetached() || has_been_disposed_)
+ << "Detached AXVirtualObject in map: "
+ << "AXID#" << ax_id << " Node=" << accessible_node->element();
+#endif
+ return result;
}
-// FIXME: This probably belongs on Node.
-// FIXME: This should take a const char*, but one caller passes g_null_atom.
-static bool NodeHasRole(Node* node, const String& role) {
- auto* element = DynamicTo<Element>(node);
- if (!element)
- return false;
-
- // TODO(accessibility) support role strings with multiple roles.
- return EqualIgnoringASCIICase(
- element->FastGetAttribute(html_names::kRoleAttr), role);
+AXObject* AXObjectCacheImpl::GetAXImageForMap(HTMLMapElement& map) {
+ HTMLElement* first_area = Traversal<HTMLAreaElement>::FirstWithin(map);
+ AXObject* ax_child_area = Get(first_area);
+ if (!ax_child_area)
+ return nullptr;
+ return ax_child_area->CachedParentObject();
}
AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
// FIXME: How could layoutObject->node() ever not be an Element?
Node* node = layout_object->GetNode();
- // If the node is aria role="list" or the aria role is empty and its a
- // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
- if (NodeHasRole(node, "list") || NodeHasRole(node, "directory") ||
- (NodeHasRole(node, g_null_atom) &&
- (IsA<HTMLUListElement>(node) || IsA<HTMLOListElement>(node) ||
- IsA<HTMLDListElement>(node))))
- return MakeGarbageCollected<AXList>(layout_object, *this);
-
// media element
if (node && node->IsMediaElement())
return AccessibilityMediaElement::Create(layout_object, *this);
@@ -465,15 +755,10 @@ AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
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);
-
if (layout_object->IsBoxModelObject()) {
auto* css_box = To<LayoutBoxModelObject>(layout_object);
if (auto* select_element = DynamicTo<HTMLSelectElement>(node)) {
@@ -495,8 +780,36 @@ AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
return MakeGarbageCollected<AXLayoutObject>(layout_object, *this);
}
+// Returns true if |node| is an <option> element and its parent <select>
+// is a menu list (not a list box).
+// static
+bool AXObjectCacheImpl::ShouldCreateAXMenuListOptionFor(const Node* node) {
+ auto* option_element = DynamicTo<HTMLOptionElement>(node);
+ if (!option_element)
+ return false;
+ const HTMLSelectElement* select = option_element->OwnerSelectElement();
+ if (!select || !select->UsesMenuList())
+ return false;
+ return select->GetLayoutObject() && AXObjectCacheImpl::UseAXMenuList();
+}
+
+// static
+bool AXObjectCacheImpl::IsPseudoElementDescendant(
+ const LayoutObject& layout_object) {
+ const LayoutObject* ancestor = &layout_object;
+ while (true) {
+ ancestor = ancestor->Parent();
+ if (!ancestor)
+ return false;
+ if (ancestor->IsPseudoElement())
+ return true;
+ if (!ancestor->IsAnonymous())
+ return false;
+ }
+}
+
AXObject* AXObjectCacheImpl::CreateFromNode(Node* node) {
- if (IsMenuListOption(node) && use_ax_menu_list_) {
+ if (ShouldCreateAXMenuListOptionFor(node)) {
return MakeGarbageCollected<AXMenuListOption>(To<HTMLOptionElement>(node),
*this);
}
@@ -512,80 +825,120 @@ AXObject* AXObjectCacheImpl::CreateFromInlineTextBox(
return MakeGarbageCollected<AXInlineTextBox>(inline_text_box, *this);
}
-AXObject* AXObjectCacheImpl::GetOrCreate(AccessibleNode* accessible_node) {
+AXObject* AXObjectCacheImpl::GetOrCreate(AccessibleNode* accessible_node,
+ AXObject* parent) {
if (AXObject* obj = Get(accessible_node))
return obj;
+ DCHECK(parent)
+ << "A virtual object must have a parent, and cannot exist without one. "
+ "The parent is set when the object is constructed.";
+
AXObject* new_obj =
MakeGarbageCollected<AXVirtualObject>(*this, accessible_node);
- const AXID ax_id = GetOrCreateAXID(new_obj);
+ const AXID ax_id = AssociateAXID(new_obj);
accessible_node_mapping_.Set(accessible_node, ax_id);
- new_obj->Init();
+ new_obj->Init(parent);
return new_obj;
}
AXObject* AXObjectCacheImpl::GetOrCreate(const Node* node) {
- return GetOrCreate(const_cast<Node*>(node));
+ return GetOrCreate(node, nullptr);
}
AXObject* AXObjectCacheImpl::GetOrCreate(Node* node) {
- if (!node || !node->isConnected())
- return nullptr;
+ return GetOrCreate(node, nullptr);
+}
- if (!node->IsElementNode() && !node->IsTextNode() && !node->IsDocumentNode())
- return nullptr; // Only documents, elements and text nodes get a11y objects
+AXObject* AXObjectCacheImpl::GetOrCreate(const Node* node,
+ AXObject* parent_if_known) {
+ return GetOrCreate(const_cast<Node*>(node), parent_if_known);
+}
+
+AXObject* AXObjectCacheImpl::GetOrCreate(Node* node,
+ AXObject* parent_if_known) {
+ if (!node)
+ return nullptr;
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()
+ return CreateAndInit(node, parent_if_known);
+}
+
+AXObject* AXObjectCacheImpl::CreateAndInit(Node* node,
+ AXObject* parent_if_known,
+ AXID use_axid) {
+ DCHECK(node);
// 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.
- if (node->GetLayoutObject() && !IsA<HTMLAreaElement>(node) &&
+ LayoutObject* layout_object = node->GetLayoutObject();
+ if (layout_object && IsLayoutObjectRelevantForAccessibility(*layout_object) &&
!DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
- return GetOrCreate(node->GetLayoutObject());
+ return CreateAndInit(layout_object, parent_if_known, use_axid);
}
- if (!LayoutTreeBuilderTraversal::Parent(*node))
+ if (!IsNodeRelevantForAccessibility(node, parent_if_known, false))
return nullptr;
- if (IsA<HTMLHeadElement>(node))
- return nullptr;
+#if DCHECK_IS_ON()
+ DCHECK(node->isConnected());
+ DCHECK(node->IsElementNode() || node->IsTextNode() || node->IsDocumentNode());
+ Document* document = &node->GetDocument();
+ DCHECK(document);
+ DCHECK(document->Lifecycle().GetState() >=
+ DocumentLifecycle::kAfterPerformLayout)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
+ // Return null if inside a shadow tree of something that can't have children,
+ // for example, an <img> has a user agent shadow root containing a <span> for
+ // the alt text. Do not create an accessible for that as it would be unable
+ // to have a parent that has it as a child.
+ if (node->IsInShadowTree()) {
+ AXObject* shadow_host = Get(node->OwnerShadowHost());
+ if (shadow_host && !shadow_host->CanHaveChildren())
+ return nullptr;
+ }
AXObject* new_obj = CreateFromNode(node);
// Will crash later if we have two objects for the same node.
- DCHECK(!Get(node));
+ DCHECK(!node_object_mapping_.at(node))
+ << "Already have an AXObject for " << node;
- const AXID ax_id = GetOrCreateAXID(new_obj);
+ const AXID ax_id = AssociateAXID(new_obj, use_axid);
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);
+ new_obj->Init(parent_if_known);
+ MaybeNewRelationTarget(*node, new_obj);
return new_obj;
}
AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) {
+ return GetOrCreate(layout_object, nullptr);
+}
+
+AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object,
+ AXObject* parent_if_known) {
if (!layout_object)
return nullptr;
if (AXObject* obj = Get(layout_object))
return obj;
+ return CreateAndInit(layout_object, parent_if_known);
+}
+
+AXObject* AXObjectCacheImpl::CreateAndInit(LayoutObject* layout_object,
+ AXObject* parent_if_known,
+ AXID use_axid) {
#if DCHECK_IS_ON()
+ DCHECK(layout_object);
Document* document = &layout_object->GetDocument();
DCHECK(document);
DCHECK(document->Lifecycle().GetState() >=
@@ -593,12 +946,24 @@ AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) {
<< "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.
+ if (!IsLayoutObjectRelevantForAccessibility(*layout_object))
+ return nullptr;
+
Node* node = layout_object->GetNode();
- if (node && (IsMenuListOption(node) || IsA<HTMLAreaElement>(node)))
+
+ if (node && !IsNodeRelevantForAccessibility(node, parent_if_known, true))
return nullptr;
+ // Return null if inside a shadow tree of something that can't have children,
+ // for example, an <img> has a user agent shadow root containing a <span> for
+ // the alt text. Do not create an accessible for that as it would be unable
+ // to have a parent that has it as a child.
+ if (node && node->IsInShadowTree()) {
+ AXObject* shadow_host = Get(node->OwnerShadowHost());
+ if (shadow_host && !shadow_host->CanHaveChildren())
+ return nullptr;
+ }
+
// Prefer creating AXNodeObjects over AXLayoutObjects in locked subtrees
// (e.g. content-visibility: auto), even if a LayoutObject is available,
// because the LayoutObject is not guaranteed to be up-to-date (it might come
@@ -618,64 +983,78 @@ AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) {
// when there isn't. The locked subtree should not have AXLayoutObjects.
return nullptr;
}
- return GetOrCreate(layout_object->GetNode());
+ return CreateAndInit(node, parent_if_known, use_axid);
}
AXObject* new_obj = CreateFromRenderer(layout_object);
// Will crash later if we have two objects for the same layoutObject.
- DCHECK(!Get(layout_object));
-
- const AXID axid = GetOrCreateAXID(new_obj);
+ DCHECK(!layout_object_mapping_.at(layout_object))
+ << "Already have an AXObject for " << layout_object;
+ const AXID axid = AssociateAXID(new_obj, use_axid);
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) {
- Remove(prev_axid);
- node_object_mapping_.Set(node, axid);
- }
- MaybeNewRelationTarget(node, new_obj);
- }
+ new_obj->Init(parent_if_known);
+ if (node) // There may not be a node, e.g. for an anonymous block.
+ MaybeNewRelationTarget(*node, new_obj);
return new_obj;
}
-AXObject* AXObjectCacheImpl::GetOrCreate(
- AbstractInlineTextBox* inline_text_box) {
+AXObject* AXObjectCacheImpl::GetOrCreate(AbstractInlineTextBox* inline_text_box,
+ AXObject* parent) {
if (!inline_text_box)
return nullptr;
- if (AXObject* obj = Get(inline_text_box))
+ if (!parent) {
+ LayoutObject* layout_text_parent = inline_text_box->GetLayoutObject();
+ DCHECK(layout_text_parent);
+ DCHECK(layout_text_parent->IsText());
+ parent = GetOrCreate(layout_text_parent);
+ if (!parent) {
+ // Allowed to not have a parent if the text was irrelevant whitespace.
+ DCHECK(inline_text_box->GetText().ContainsOnlyWhitespaceOrEmpty())
+ << "No parent for non-whitespace inline textbox: "
+ << layout_text_parent;
+ return nullptr;
+ }
+ }
+
+ if (AXObject* obj = Get(inline_text_box)) {
+#if DCHECK_IS_ON()
+ DCHECK(!obj->IsDetached())
+ << "AXObject for inline text box should not be detached: "
+ << obj->ToString(true, true);
+ // AXInlineTextbox objects can't get a new parent, unlike other types of
+ // accessible objects that can get a new parent because they moved or
+ // because of aria-owns.
+ // AXInlineTextbox objects are only added via AddChildren() on static text
+ // or line break parents. The children are cleared, and detached from their
+ // parent before AddChildren() executes. There should be no previous parent.
+ DCHECK(parent->RoleValue() == ax::mojom::blink::Role::kStaticText ||
+ parent->RoleValue() == ax::mojom::blink::Role::kLineBreak);
+ DCHECK(!obj->CachedParentObject() || obj->CachedParentObject() == parent);
+#endif
+ obj->SetParent(parent);
return obj;
+ }
AXObject* new_obj = CreateFromInlineTextBox(inline_text_box);
- // Will crash later if we have two objects for the same inlineTextBox.
- DCHECK(!Get(inline_text_box));
-
- const AXID axid = GetOrCreateAXID(new_obj);
+ const AXID axid = AssociateAXID(new_obj);
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());
+ new_obj->Init(parent);
return new_obj;
}
-AXObject* AXObjectCacheImpl::GetOrCreate(ax::mojom::blink::Role role) {
+AXObject* AXObjectCacheImpl::CreateAndInit(ax::mojom::blink::Role role,
+ AXObject* parent) {
+ DCHECK(parent);
AXObject* obj = nullptr;
switch (role) {
- case ax::mojom::Role::kSliderThumb:
- obj = MakeGarbageCollected<AXSliderThumb>(*this);
- break;
- case ax::mojom::Role::kMenuListPopup:
+ case ax::mojom::blink::Role::kMenuListPopup:
DCHECK(use_ax_menu_list_);
obj = MakeGarbageCollected<AXMenuListPopup>(*this);
break;
@@ -686,35 +1065,13 @@ AXObject* AXObjectCacheImpl::GetOrCreate(ax::mojom::blink::Role role) {
if (!obj)
return nullptr;
- GetOrCreateAXID(obj);
+ AssociateAXID(obj);
- obj->Init();
+ obj->Init(parent);
return obj;
}
-ContainerNode* FindParentTable(Node* node) {
- ContainerNode* parent = node->parentNode();
- while (parent && !IsA<HTMLTableElement>(*parent))
- parent = parent->parentNode();
- return parent;
-}
-
-void AXObjectCacheImpl::ContainingTableRowsOrColsMaybeChanged(Node* node) {
- // Any containing table must recompute its rows and columns on insertion or
- // removal of a <tr> or <td>.
- // Get parent table from DOM, because AXObject/layout tree are incomplete.
- ContainerNode* containing_table = nullptr;
- if (IsA<HTMLTableCellElement>(node) || IsA<HTMLTableRowElement>(node))
- containing_table = FindParentTable(node);
-
- if (containing_table) {
- AXObject* ax_table = Get(containing_table);
- if (ax_table)
- ax_table->SetNeedsToUpdateChildren();
- }
-}
-
-void AXObjectCacheImpl::InvalidateTableSubtree(AXObject* subtree) {
+void AXObjectCacheImpl::RemoveAXObjectsInLayoutSubtree(AXObject* subtree) {
if (!subtree)
return;
@@ -722,13 +1079,24 @@ void AXObjectCacheImpl::InvalidateTableSubtree(AXObject* subtree) {
if (layout_object) {
LayoutObject* layout_child = layout_object->SlowFirstChild();
while (layout_child) {
- InvalidateTableSubtree(Get(layout_child));
+ RemoveAXObjectsInLayoutSubtree(Get(layout_child));
layout_child = layout_child->NextSibling();
}
}
- AXID ax_id = subtree->AXObjectID();
- Remove(ax_id);
+ Remove(subtree);
+}
+
+void AXObjectCacheImpl::Remove(AXObject* object) {
+ DCHECK(object);
+ if (object->GetNode())
+ Remove(object->GetNode());
+ else if (object->GetLayoutObject())
+ Remove(object->GetLayoutObject());
+ else if (object->GetAccessibleNode())
+ Remove(object->GetAccessibleNode());
+ else
+ Remove(object->AXObjectID());
}
void AXObjectCacheImpl::Remove(AXID ax_id) {
@@ -740,10 +1108,14 @@ void AXObjectCacheImpl::Remove(AXID ax_id) {
if (!obj)
return;
+ ChildrenChanged(obj->CachedParentObject());
+
obj->Detach();
RemoveAXID(obj);
// Finally, remove the object.
+ // TODO(accessibility) We don't use the return value, can we use .erase()
+ // and it will still make sure that the object is cleaned up?
if (!objects_.Take(ax_id))
return;
@@ -764,6 +1136,7 @@ void AXObjectCacheImpl::Remove(LayoutObject* layout_object) {
return;
AXID ax_id = layout_object_mapping_.at(layout_object);
+
Remove(ax_id);
layout_object_mapping_.erase(layout_object);
}
@@ -811,15 +1184,11 @@ void AXObjectCacheImpl::AddToFixedOrStickyNodeList(const AXObject* object) {
fixed_or_sticky_node_ids_.insert(object->AXObjectID());
}
-AXID AXObjectCacheImpl::GetOrCreateAXID(AXObject* obj) {
- // check for already-assigned ID
- const AXID existing_axid = obj->AXObjectID();
- if (existing_axid) {
- DCHECK(ids_in_use_.Contains(existing_axid));
- return existing_axid;
- }
+AXID AXObjectCacheImpl::AssociateAXID(AXObject* obj, AXID use_axid) {
+ // Check for already-assigned ID.
+ DCHECK(!obj->AXObjectID()) << "Object should not already have an AXID";
- const AXID new_axid = GenerateAXID();
+ const AXID new_axid = use_axid ? use_axid : GenerateAXID();
ids_in_use_.insert(new_axid);
obj->SetAXObjectID(new_axid);
@@ -908,15 +1277,21 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
return;
}
+#if DCHECK_IS_ON()
DCHECK(!tree_update_document->GetPage()->Animator().IsServicingAnimations() ||
(tree_update_document->Lifecycle().GetState() <
DocumentLifecycle::kInAccessibility ||
tree_update_document->Lifecycle().StateAllowsDetach()))
<< "DeferTreeUpdateInternal should only be outside of the lifecycle or "
- "before the accessibility state.";
+ "before the accessibility state:"
+ << "\n* IsServicingAnimations: "
+ << tree_update_document->GetPage()->Animator().IsServicingAnimations()
+ << "\n* Lifecycle: " << tree_update_document->Lifecycle().ToString();
+#endif
+
tree_update_callback_queue_.push_back(MakeGarbageCollected<TreeUpdateParams>(
obj->GetNode(), obj->AXObjectID(), ComputeEventFrom(),
- ActiveEventIntents(), std::move(callback)));
+ active_event_from_action_, ActiveEventIntents(), std::move(callback)));
// These events are fired during DocumentLifecycle::kInAccessibility,
// ensure there is a document lifecycle update scheduled.
@@ -944,14 +1319,21 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
return;
}
+#if DCHECK_IS_ON()
DCHECK(!tree_update_document.GetPage()->Animator().IsServicingAnimations() ||
(tree_update_document.Lifecycle().GetState() <
DocumentLifecycle::kInAccessibility ||
tree_update_document.Lifecycle().StateAllowsDetach()))
<< "DeferTreeUpdateInternal should only be outside of the lifecycle or "
- "before the accessibility state.";
+ "before the accessibility state:"
+ << "\n* IsServicingAnimations: "
+ << tree_update_document.GetPage()->Animator().IsServicingAnimations()
+ << "\n* Lifecycle: " << tree_update_document.Lifecycle().ToString();
+#endif
+
tree_update_callback_queue_.push_back(MakeGarbageCollected<TreeUpdateParams>(
- node, 0, ComputeEventFrom(), ActiveEventIntents(), std::move(callback)));
+ node, 0, ComputeEventFrom(), active_event_from_action_,
+ ActiveEventIntents(), std::move(callback)));
// These events are fired during DocumentLifecycle::kInAccessibility,
// ensure there is a document lifecycle update scheduled.
@@ -974,9 +1356,6 @@ 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),
@@ -1026,10 +1405,6 @@ void AXObjectCacheImpl::SelectionChangedWithCleanLayout(Node* node) {
if (!node)
return;
- // 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->UpdateDistributionForFlatTreeTraversal();
AXObject* ax_object = GetOrCreate(node);
if (ax_object)
ax_object->SelectionChanged();
@@ -1141,7 +1516,7 @@ void AXObjectCacheImpl::TextChangedWithCleanLayout(
}
if (optional_node_for_relation_update)
- relation_cache_->UpdateRelatedTree(optional_node_for_relation_update);
+ relation_cache_->UpdateRelatedTree(optional_node_for_relation_update, obj);
}
void AXObjectCacheImpl::TextChangedWithCleanLayout(Node* node) {
@@ -1213,7 +1588,7 @@ void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttachedWithCleanLayout(
if (AXObject::HasARIAOwns(element))
HandleAttributeChangedWithCleanLayout(html_names::kAriaOwnsAttr, element);
- MaybeNewRelationTarget(node, Get(node));
+ MaybeNewRelationTarget(*node, Get(node));
// Even if the node or parent are ignored, an ancestor may need to include
// descendants of the attached node, thus ChildrenChangedWithCleanLayout()
@@ -1228,7 +1603,7 @@ void AXObjectCacheImpl::DidInsertChildrenOfNode(Node* node) {
// changed.
DCHECK(node);
while (node) {
- if (AXObject* obj = GetIfExists(node)) {
+ if (AXObject* obj = Get(node)) {
TextChanged(node);
return;
}
@@ -1236,6 +1611,22 @@ void AXObjectCacheImpl::DidInsertChildrenOfNode(Node* node) {
}
}
+void AXObjectCacheImpl::ChildrenChanged(const AXObject* obj) {
+ ChildrenChanged(const_cast<AXObject*>(obj));
+}
+
+void AXObjectCacheImpl::ChildrenChanged(AXObject* obj) {
+ if (!obj)
+ return;
+
+ Node* node = obj->GetNode();
+ if (node && !nodes_with_pending_children_changed_.insert(node).is_new_entry)
+ return;
+
+ DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout,
+ obj->GetNode(), obj);
+}
+
void AXObjectCacheImpl::ChildrenChanged(Node* node) {
if (!node)
return;
@@ -1251,37 +1642,27 @@ void AXObjectCacheImpl::ChildrenChanged(const LayoutObject* layout_object) {
if (!layout_object)
return;
+ // Ensure that this object is touched, so that Get() can Invalidate() it if
+ // necessary, e.g. to change whether it's an AXNodeObject <--> AXLayoutObject.
+ Get(layout_object);
+
// Update using nearest node (walking ancestors if necessary).
Node* node = GetClosestNodeForLayoutObject(layout_object);
- if (node) {
- // Don't enqueue a deferred event on the same node more than once.
- if (!nodes_with_pending_children_changed_.insert(node).is_new_entry)
- return;
-
- DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, node);
+ if (!node)
+ return;
- if (layout_object->GetNode() == node)
- return; // Node matched the layout object passed in, no further updates.
+ // Don't enqueue a deferred event on the same node more than once.
+ if (!nodes_with_pending_children_changed_.insert(node).is_new_entry)
+ return;
- // 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.
- }
+ DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, node);
- // 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)
+ if (!layout_object->IsAnonymous())
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);
- }
+ DCHECK_NE(node->GetLayoutObject(), layout_object);
- // 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
@@ -1292,11 +1673,16 @@ void AXObjectCacheImpl::ChildrenChanged(const LayoutObject* layout_object) {
// then we also process ChildrenChanged() on the <div> and <a>:
// <div>
// | \
- // <p> Anonymous block
+ // <p> Anonymous block (Note: Anonymous blocks do not get AXObjects)
// \
// <a>
// \
// text
+
+ // TODO(aleventhal) Why is this needed for shadow-distribution.js test?
+ if (GetDocument().IsFlatTreeTraversalForbidden())
+ return;
+
for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node); child;
child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, child);
@@ -1318,6 +1704,12 @@ void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* node) {
if (!node)
return;
+ LayoutObject* layout_object = node->GetLayoutObject();
+ AXID layout_id = layout_object ? layout_object_mapping_.at(layout_object) : 0;
+ DCHECK(!HashTraits<AXID>::IsDeletedValue(layout_id));
+
+ AXID node_id = node_object_mapping_.at(node);
+ DCHECK(!HashTraits<AXID>::IsDeletedValue(node_id));
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
ChildrenChangedWithCleanLayout(node, Get(node));
@@ -1325,22 +1717,31 @@ void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* node) {
void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* optional_node,
AXObject* obj) {
+ if (HTMLMapElement* map_element = DynamicTo<HTMLMapElement>(optional_node)) {
+ obj = GetAXImageForMap(*map_element);
+ if (!obj)
+ return;
+ optional_node = obj->GetNode();
+ }
if (obj ? obj->IsDetached() : !optional_node)
return;
#if DCHECK_IS_ON()
+ if (obj && optional_node) {
+ DCHECK_EQ(obj->GetNode(), optional_node);
+ DCHECK_EQ(obj, Get(optional_node));
+ }
Document* document = obj ? obj->GetDocument() : &optional_node->GetDocument();
+ DCHECK(document);
DCHECK(document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
<< "Unclean document at lifecycle " << document->Lifecycle().ToString();
#endif // DCHECK_IS_ON()
- if (obj && !obj->IsDetached())
+ if (obj)
obj->ChildrenChanged();
- if (optional_node) {
- ContainingTableRowsOrColsMaybeChanged(optional_node);
- relation_cache_->UpdateRelatedTree(optional_node);
- }
+ if (optional_node)
+ relation_cache_->UpdateRelatedTree(optional_node, obj);
}
void AXObjectCacheImpl::ProcessDeferredAccessibilityEvents(Document& document) {
@@ -1352,18 +1753,34 @@ void AXObjectCacheImpl::ProcessDeferredAccessibilityEvents(Document& document) {
return;
}
- ProcessUpdates(document);
+ // Destroy and recreate any objects which are no longer valid, for example
+ // they used AXNodeObject and now must be an AXLayoutObject, or vice-versa.
+ // Also fires children changed on the parent of these nodes.
+ ProcessInvalidatedObjects(document);
+
+ // Call the queued callback methods that do processing which must occur when
+ // layout is clean. These callbacks are stored in tree_update_callback_queue_,
+ // and have names like FooBarredWithCleanLayout().
+ ProcessCleanLayoutCallbacks(document);
// Changes to ids or aria-owns may have resulted in queued up relation
// cache work; do that now.
relation_cache_->ProcessUpdatesWithCleanLayout();
+ // Perform this step a second time, to refresh any new invalidated objects
+ // from the previous deferred processing steps.
+ ProcessInvalidatedObjects(document);
+
+ // Send events to RenderAccessibilityImpl, which serializes them and then
+ // sends the serialized events and dirty objects to the browser process.
PostNotifications(document);
}
bool AXObjectCacheImpl::IsDirty() const {
- return !tree_updates_paused_ &&
- (tree_update_callback_queue_.size() || notifications_to_post_.size());
+ if (tree_updates_paused_)
+ return false;
+ return tree_update_callback_queue_.size() || notifications_to_post_.size() ||
+ invalidated_ids_.size();
}
void AXObjectCacheImpl::EmbeddingTokenChanged(HTMLFrameOwnerElement* element) {
@@ -1373,7 +1790,119 @@ void AXObjectCacheImpl::EmbeddingTokenChanged(HTMLFrameOwnerElement* element) {
MarkElementDirty(element, false);
}
-void AXObjectCacheImpl::ProcessUpdates(Document& document) {
+void AXObjectCacheImpl::ProcessInvalidatedObjects(Document& document) {
+ HashSet<AXID> wrong_document_invalidated_ids;
+ HashSet<AXID> old_invalidated_ids;
+ HashSet<AXID> pending_children_changed_ids;
+
+ // Create a new object with the same AXID as the old one.
+ // Currently only supported for objects with a backing node.
+ // Returns the new object.
+ auto refresh = [this](AXObject* current) {
+ Node* node = current->GetNode();
+ DCHECK(node) << "Refresh() is currently only supported for objects "
+ "with a backing node";
+ AXID retained_axid = current->AXObjectID();
+ // Remove from relevant maps, but not from relation cache, as the relations
+ // between AXIDs will still the same.
+ node_object_mapping_.erase(node);
+ if (current->GetLayoutObject()) {
+ layout_object_mapping_.erase(current->GetLayoutObject());
+ } else if (node->GetLayoutObject()) {
+ DCHECK(!layout_object_mapping_.at(node->GetLayoutObject()))
+ << node << " " << node->GetLayoutObject();
+ }
+ current->Detach();
+ // TODO(accessibility) We don't use the return value, can we use .erase()
+ // and it will still make sure that the object is cleaned up?
+ objects_.Take(retained_axid);
+ // Do not pass in the previous parent. It may not end up being the same,
+ // e.g. in the case of a <select> option where the select changed size.
+ // TODO(accessibility) That may be the only example of this, in which case
+ // it could be handled in RoleChangedWithCleanLayout(), and the cached
+ // parent could be used.
+ AXObject* new_object = CreateAndInit(node, nullptr, retained_axid);
+ if (!new_object)
+ RemoveAXID(current); // Failed to create, so remove object completely.
+ return new_object;
+ };
+
+ while (!invalidated_ids_.IsEmpty()) {
+ // ChildrenChanged() below may invalidate more objects. This outer loop
+ // ensures all newly invalid objects are caught and refreshed before the
+ // function returns.
+ old_invalidated_ids.swap(invalidated_ids_);
+ for (AXID ax_id : old_invalidated_ids) {
+ AXObject* object = ObjectFromAXID(ax_id);
+ if (!object || object->IsDetached())
+ continue;
+ if (object->GetDocument() != &document) {
+ // Wrong document -- this AXObjectCache processes the current popup
+ // document too. Keep the ID around until its document is processed.
+ DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
+ wrong_document_invalidated_ids.insert(ax_id);
+ continue;
+ }
+
+ bool did_use_layout_object_traversal =
+ object->ShouldUseLayoutObjectTraversalForChildren();
+
+ // Invalidate children on the first available non-detached parent that is
+ // included in the tree. Sometimes a cached parent is detached because
+ // an object was detached in the middle of the tree, and cached parents
+ // are not corrected until the call to UpdateChildrenIfNecessary() below.
+ AXObject* parent = object;
+ while (true) {
+ AXObject* candidate_parent = parent->CachedParentObject();
+ if (!candidate_parent || candidate_parent->IsDetached()) {
+ // The cached parent pointed to a detached AXObject. Compute a new
+ // candidate parent and repair the cached parent now, so that
+ // refreshing and initializing the new object can occur (a parent is
+ // required).
+ candidate_parent = parent->ComputeParent();
+ parent->SetParent(candidate_parent);
+ }
+
+ if (!candidate_parent)
+ break; // No higher candidate parent found, will invalidate |parent|.
+
+ parent = candidate_parent;
+ // Queue up a ChildrenChanged() call for this parent.
+ pending_children_changed_ids.insert(parent->AXObjectID());
+ if (parent->LastKnownIsIncludedInTreeValue())
+ break; // Stop here (otherwise continue to higher ancestor).
+ }
+
+ AXObject* new_object = refresh(object);
+ MarkAXObjectDirty(new_object, false);
+
+ // Children might change because child traversal style changed.
+ if (new_object &&
+ new_object->ShouldUseLayoutObjectTraversalForChildren() !=
+ did_use_layout_object_traversal) {
+ // TODO(accessibility) Need test for this.
+ DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
+ pending_children_changed_ids.insert(ax_id);
+ }
+ }
+ // Update parents' children.
+ for (AXID parent_id : pending_children_changed_ids) {
+ AXObject* parent = ObjectFromAXID(parent_id);
+ if (parent) {
+ // Invalidate the parent's children.
+ ChildrenChangedWithCleanLayout(parent->GetNode(), parent);
+ // Update children now.
+ parent->UpdateChildrenIfNecessary();
+ }
+ }
+ old_invalidated_ids.clear();
+ pending_children_changed_ids.clear();
+ }
+ // Invalidate these objects when their document is clean.
+ invalidated_ids_.swap(wrong_document_invalidated_ids);
+}
+
+void AXObjectCacheImpl::ProcessCleanLayoutCallbacks(Document& document) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(document);
if (tree_updates_paused_) {
@@ -1398,6 +1927,19 @@ void AXObjectCacheImpl::ProcessUpdates(Document& document) {
if (!axid || !ObjectFromAXID(axid))
continue;
}
+
+#if DCHECK_IS_ON()
+ if (axid) {
+ AXObject* obj = ObjectFromAXID(axid);
+ if (obj) {
+ DCHECK(!obj->IsDetached());
+ if (node) {
+ DCHECK_EQ(node, obj->GetNode());
+ DCHECK_EQ(Get(node), obj);
+ }
+ }
+ }
+#endif
base::OnceClosure& callback = tree_update->callback;
// Insure the update is for the correct document.
// If no node, this update must be from an AXObject with no DOM node,
@@ -1407,14 +1949,15 @@ void AXObjectCacheImpl::ProcessUpdates(Document& document) {
if (document != tree_update_document) {
tree_update_callback_queue_.push_back(
MakeGarbageCollected<TreeUpdateParams>(
- node, axid, tree_update->event_from, tree_update->event_intents,
+ node, axid, tree_update->event_from,
+ tree_update->event_from_action, tree_update->event_intents,
std::move(callback)));
continue;
}
- FireTreeUpdatedEventImmediately(document, tree_update->event_from,
- tree_update->event_intents,
- std::move(callback));
+ FireTreeUpdatedEventImmediately(
+ document, tree_update->event_from, tree_update->event_from_action,
+ tree_update->event_intents, std::move(callback));
}
}
@@ -1432,14 +1975,16 @@ void AXObjectCacheImpl::PostNotifications(Document& document) {
ax::mojom::blink::Event event_type = params->event_type;
ax::mojom::blink::EventFrom event_from = params->event_from;
+ ax::mojom::blink::Action event_from_action = params->event_from_action;
const BlinkAXEventIntentsSet& event_intents = params->event_intents;
if (obj->GetDocument() != &document) {
notifications_to_post_.push_back(MakeGarbageCollected<AXEventParams>(
- obj, event_type, event_from, event_intents));
+ obj, event_type, event_from, event_from_action, event_intents));
continue;
}
- FireAXEventImmediately(obj, event_type, event_from, event_intents);
+ FireAXEventImmediately(obj, event_type, event_from, event_from_action,
+ event_intents);
}
}
@@ -1450,8 +1995,6 @@ 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)
@@ -1480,12 +2023,13 @@ void AXObjectCacheImpl::PostNotification(AXObject* object,
if (object->GetDocument()->Lifecycle().GetState() ==
DocumentLifecycle::kInAccessibility) {
FireAXEventImmediately(object, event_type, ComputeEventFrom(),
- ActiveEventIntents());
+ active_event_from_action_, ActiveEventIntents());
return;
}
notifications_to_post_.push_back(MakeGarbageCollected<AXEventParams>(
- object, event_type, ComputeEventFrom(), ActiveEventIntents()));
+ object, event_type, ComputeEventFrom(), active_event_from_action_,
+ ActiveEventIntents()));
// These events are fired during DocumentLifecycle::kInAccessibility,
// ensure there is a visual update scheduled.
@@ -1517,6 +2061,7 @@ void AXObjectCacheImpl::ScheduleVisualUpdate() {
void AXObjectCacheImpl::FireTreeUpdatedEventImmediately(
Document& document,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& event_intents,
base::OnceClosure callback) {
DCHECK_EQ(document.Lifecycle().GetState(),
@@ -1524,6 +2069,8 @@ void AXObjectCacheImpl::FireTreeUpdatedEventImmediately(
base::AutoReset<ax::mojom::blink::EventFrom> event_from_resetter(
&active_event_from_, event_from);
+ base::AutoReset<ax::mojom::blink::Action> event_from_action_resetter(
+ &active_event_from_action_, event_from_action);
ScopedBlinkAXEventIntent defered_event_intents(event_intents.AsVector(),
&document);
std::move(callback).Run();
@@ -1533,6 +2080,7 @@ void AXObjectCacheImpl::FireAXEventImmediately(
AXObject* obj,
ax::mojom::blink::Event event_type,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& event_intents) {
DCHECK_EQ(obj->GetDocument()->Lifecycle().GetState(),
DocumentLifecycle::kInAccessibility);
@@ -1550,18 +2098,18 @@ void AXObjectCacheImpl::FireAXEventImmediately(
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*obj->GetDocument());
#endif // DCHECK_IS_ON()
- PostPlatformNotification(obj, event_type, event_from, event_intents);
+ PostPlatformNotification(obj, event_type, event_from, event_from_action,
+ event_intents);
if (event_type == ax::mojom::blink::Event::kChildrenChanged &&
obj->CachedParentObject()) {
const bool was_ignored = obj->LastKnownIsIgnoredValue();
- const bool was_ignored_but_included_in_tree =
- obj->LastKnownIsIgnoredButIncludedInTreeValue();
- bool is_ignored_changed =
- was_ignored != obj->AccessibilityIsIgnored() ||
- was_ignored_but_included_in_tree !=
- obj->AccessibilityIsIgnoredButIncludedInTree();
- if (is_ignored_changed)
+ const bool was_in_tree = obj->LastKnownIsIncludedInTreeValue();
+ obj->UpdateCachedAttributeValuesIfNeeded(false);
+ const bool is_ignored = obj->LastKnownIsIgnoredValue();
+ const bool is_in_tree = obj->LastKnownIsIncludedInTreeValue();
+
+ if (is_ignored != was_ignored || was_in_tree != is_in_tree)
ChildrenChangedWithCleanLayout(nullptr, obj->CachedParentObject());
}
}
@@ -1631,27 +2179,6 @@ void AXObjectCacheImpl::LocationChanged(const LayoutObject* layout_object) {
PostNotification(layout_object, ax::mojom::Event::kLocationChanged);
}
-void AXObjectCacheImpl::RadiobuttonRemovedFromGroup(
- HTMLInputElement* group_member) {
- SCOPED_DISALLOW_LIFECYCLE_TRANSITION(group_member->GetDocument());
-
- auto* ax_object = DynamicTo<AXRadioInput>(Get(group_member));
- if (!ax_object)
- return;
-
- // The 'posInSet' and 'setSize' attributes should be updated from the first
- // node, as the removed node is already detached from tree.
- auto* first_radio = ax_object->FindFirstRadioButtonInGroup(group_member);
- AXObject* first_obj = Get(first_radio);
- auto* ax_first_obj = DynamicTo<AXRadioInput>(first_obj);
- if (!ax_first_obj)
- return;
-
- ax_first_obj->UpdatePosAndSetSize(1);
- PostNotification(first_obj, ax::mojom::Event::kAriaAttributeChanged);
- ax_first_obj->RequestUpdateToNextNode(true);
-}
-
void AXObjectCacheImpl::ImageLoaded(const LayoutObject* layout_object) {
AXObject* obj = Get(layout_object);
MarkAXObjectDirty(obj, false);
@@ -1719,13 +2246,10 @@ void AXObjectCacheImpl::HandleNodeGainedFocusWithCleanLayout(Node* node) {
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);
@@ -1742,23 +2266,28 @@ void AXObjectCacheImpl::HandleNodeGainedFocusWithCleanLayout(Node* node) {
}
// This might be the new target of a relation. Handle all possible cases.
-void AXObjectCacheImpl::MaybeNewRelationTarget(Node* node, AXObject* obj) {
+void AXObjectCacheImpl::MaybeNewRelationTarget(Node& node, AXObject* obj) {
// Track reverse relations
- relation_cache_->UpdateRelatedTree(node);
+ relation_cache_->UpdateRelatedTree(&node, obj);
if (!obj)
return;
- // Check whether aria-activedescendant on a focused object points to |obj|.
- // If so, fire activedescendantchanged event now.
- // This is only for ARIA active descendants, not in a native control like a
- // listbox, which has its own initial active descendant handling.
+ DCHECK_EQ(obj->GetNode(), &node);
+
+ // Check whether aria-activedescendant on the focused object points to
+ // |obj|. If so, fire activedescendantchanged event now. This is only for
+ // ARIA active descendants, not in a native control like a listbox, which
+ // has its own initial active descendant handling.
Node* focused_node = document_->FocusedElement();
if (focused_node) {
AXObject* focus = Get(focused_node);
- if (focus && focus->ActiveDescendant() == obj &&
- obj->CanBeActiveDescendant())
+ if (focus &&
+ focus->GetAOMPropertyOrARIAAttribute(
+ AOMRelationProperty::kActiveDescendant) == &node &&
+ obj->CanBeActiveDescendant()) {
focus->HandleActiveDescendantChanged();
+ }
}
}
@@ -1785,49 +2314,75 @@ void AXObjectCacheImpl::HandleRoleChangeWithCleanLayout(Node* node) {
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
- // Invalidate the current object and make the parent reconsider its children.
+ // Remove the current object and make the parent reconsider its children.
if (AXObject* obj = GetOrCreate(node)) {
- // Save parent for later use.
- AXObject* parent = obj->ParentObject();
-
- // 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.
+ // When the role of `obj` is changed, its AXObject needs to be destroyed and
+ // a new one needs to be created in its place. We destroy the current
+ // AXObject in this method and call ChildrenChangeWithCleanLayout() on the
+ // parent so that future updates to its children will create the alert.
+ ChildrenChangedWithCleanLayout(nullptr, obj->CachedParentObject());
LayoutObject* layout_object = node->GetLayoutObject();
- if (layout_object && layout_object->IsTable())
- InvalidateTableSubtree(obj);
- else
+ if (layout_object && layout_object->IsTable()) {
+ // 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.
+ RemoveAXObjectsInLayoutSubtree(obj);
+ } else {
Remove(node);
-
- // Parent object changed children, as the previous AXObject for this node
- // was destroyed and a different one was created in its place.
- if (parent)
- ChildrenChangedWithCleanLayout(parent->GetNode(), parent);
- modification_count_++;
+ }
}
}
-void AXObjectCacheImpl::HandleRoleChangeIfNotEditableWithCleanLayout(
- Node* node) {
+void AXObjectCacheImpl::HandleAriaHiddenChangedWithCleanLayout(Node* node) {
if (!node)
return;
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
- // Do not invalidate object if the role doesn't actually change when it's a
- // text control, otherwise unique id will change on platform side, and confuse
- // some screen readers as user edits.
- // TODO(aleventhal) Ideally the text control check would be removed, and
- // HandleRoleChangeWithCleanLayout() and only ever invalidate when the role
- // actually changes. For example:
- // if (obj->RoleValue() == obj->ComputeAccessibilityRole())
- // return;
- // However, doing that would require
- // waiting for layout to complete, as ComputeAccessibilityRole() looks at
- // layout objects.
- AXObject* obj = Get(node);
- if (!obj || !obj->IsTextControl())
- HandleRoleChangeWithCleanLayout(node);
+ AXObject* obj = GetOrCreate(node);
+ if (!obj)
+ return;
+
+ // https://www.w3.org/TR/wai-aria-1.1/#aria-hidden
+ // An element is considered hidden if it, or any of its ancestors are not
+ // rendered or have their aria-hidden attribute value set to true.
+ AXObject* parent = obj->ParentObject();
+ if (parent) {
+ // If the parent is inert or aria-hidden, then the subtree will be
+ // ignored and changing aria-hidden will have no effect.
+ // |IsInertOrAriaHidden| returns true if the element or one of its
+ // ancestors is either inert or within an aria-hidden subtree.
+ if (parent->IsInertOrAriaHidden())
+ return;
+ // If the parent is 'display: none', then the subtree will be ignored and
+ // changing aria-hidden will have no effect.
+ if (parent->GetLayoutObject()) {
+ // For elements with layout objects we can get their style directly.
+ if (parent->GetLayoutObject()->Style()->Display() == EDisplay::kNone)
+ return;
+ } else if (Element* parent_element = parent->GetElement()) {
+ // No layout object: must ensure computed style.
+ const ComputedStyle* parent_style = parent_element->EnsureComputedStyle();
+ if (!parent_style || parent_style->IsEnsuredInDisplayNone())
+ return;
+ }
+ // Unlike AXObject's |IsVisible| or |IsHiddenViaStyle| this method does not
+ // consider 'visibility: [hidden|collapse]', because while the visibility
+ // property is inherited it can be overridden by any descendant by providing
+ // 'visibility: visible' so it would be safest to invalidate the subtree in
+ // such a case.
+ }
+
+ // Changing the aria hidden state should trigger recomputing all
+ // cached values even if it doesn't result in a notification, because
+ // it affects accessibility ignored state.
+ modification_count_++;
+
+ // Invalidate the subtree because aria-hidden affects the
+ // accessibility ignored state for the entire subtree.
+ MarkAXObjectDirty(obj, /*subtree=*/true);
+ ChildrenChangedWithCleanLayout(node->parentNode());
}
void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
@@ -1847,8 +2402,12 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
HandleRoleChangeWithCleanLayout(element);
} else if (attr_name == html_names::kSizeAttr ||
attr_name == html_names::kAriaHaspopupAttr) {
- // Role won't change on edits.
- HandleRoleChangeIfNotEditableWithCleanLayout(element);
+ // Role won't change on edits, so avoid invalidation so that object is not
+ // destroyed during editing.
+ if (AXObject* obj = Get(element)) {
+ if (!obj->IsTextControl())
+ HandleRoleChangeWithCleanLayout(element);
+ }
} else if (attr_name == html_names::kAltAttr ||
attr_name == html_names::kTitleAttr) {
TextChangedWithCleanLayout(element);
@@ -1856,7 +2415,7 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
IsA<HTMLLabelElement>(*element)) {
LabelChangedWithCleanLayout(element);
} else if (attr_name == html_names::kIdAttr) {
- MaybeNewRelationTarget(element, Get(element));
+ MaybeNewRelationTarget(*element, Get(element));
} else if (attr_name == html_names::kTabindexAttr) {
FocusableChangedWithCleanLayout(element);
} else if (attr_name == html_names::kDisabledAttr ||
@@ -1869,6 +2428,10 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
MarkElementDirty(element, false);
} else if (attr_name == html_names::kStepAttr) {
MarkElementDirty(element, false);
+ } else if (attr_name == html_names::kUsemapAttr) {
+ HandleUseMapAttributeChangedWithCleanLayout(element);
+ } else if (attr_name == html_names::kNameAttr) {
+ HandleNameAttributeChangedWithCleanLayout(element);
}
if (!attr_name.LocalName().StartsWith("aria-"))
@@ -1886,7 +2449,6 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
TextChangedWithCleanLayout(element);
} else if (attr_name == html_names::kAriaDescriptionAttr ||
attr_name == html_names::kAriaDescribedbyAttr) {
- // TODO do we need a DescriptionChanged() ?
TextChangedWithCleanLayout(element);
} else if (attr_name == html_names::kAriaCheckedAttr ||
attr_name == html_names::kAriaPressedAttr) {
@@ -1896,7 +2458,7 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
} else if (attr_name == html_names::kAriaExpandedAttr) {
HandleAriaExpandedChangeWithCleanLayout(element);
} else if (attr_name == html_names::kAriaHiddenAttr) {
- ChildrenChangedWithCleanLayout(element->parentNode());
+ HandleAriaHiddenChangedWithCleanLayout(element);
} else if (attr_name == html_names::kAriaInvalidAttr) {
MarkElementDirty(element, false);
} else if (attr_name == html_names::kAriaErrormessageAttr) {
@@ -1909,28 +2471,63 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
}
}
+void AXObjectCacheImpl::HandleUseMapAttributeChangedWithCleanLayout(
+ Element* element) {
+ if (!IsA<HTMLImageElement>(element))
+ return;
+ // Get an area (aka image link) from the previous usemap.
+ AXObject* ax_image = Get(element);
+ AXObject* ax_image_link =
+ ax_image ? ax_image->FirstChildIncludingIgnored() : nullptr;
+ HTMLMapElement* previous_map =
+ ax_image_link && ax_image_link->GetNode()
+ ? Traversal<HTMLMapElement>::FirstAncestor(*ax_image_link->GetNode())
+ : nullptr;
+ // Both the old and new image may change image <--> image map.
+ HandleRoleChangeWithCleanLayout(element);
+ if (previous_map)
+ HandleRoleChangeWithCleanLayout(previous_map->ImageElement());
+}
+
+void AXObjectCacheImpl::HandleNameAttributeChangedWithCleanLayout(
+ Element* element) {
+ // Changing a map name can alter an image's role and children.
+ // The name has already changed, so we can no longer find the primary image
+ // via the DOM. Use an area child's parent to find the old image.
+ // If the old image was treated as a map, and now isn't, it will take care
+ // of updating any other image that is newly associated with the map,
+ // via AXNodeObject::AddImageMapChildren().
+ if (HTMLMapElement* map = DynamicTo<HTMLMapElement>(element)) {
+ if (AXObject* ax_previous_image = GetAXImageForMap(*map))
+ HandleRoleChangeWithCleanLayout(ax_previous_image->GetNode());
+ }
+}
+
AXObject* AXObjectCacheImpl::GetOrCreateValidationMessageObject() {
AXObject* message_ax_object = nullptr;
// Create only if it does not already exist.
if (validation_message_axid_) {
message_ax_object = ObjectFromAXID(validation_message_axid_);
}
- if (!message_ax_object) {
+ if (message_ax_object) {
+ DCHECK(!message_ax_object->IsDetached());
+ message_ax_object->SetParent(Root()); // Reattach to parent (root).
+ } else {
message_ax_object = MakeGarbageCollected<AXValidationMessage>(*this);
DCHECK(message_ax_object);
// Cache the validation message container for reuse.
- validation_message_axid_ = GetOrCreateAXID(message_ax_object);
- message_ax_object->Init();
+ validation_message_axid_ = AssociateAXID(message_ax_object);
// Validation message alert object is a child of the document, as not all
// form controls can have a child. Also, there are form controls such as
// listbox that technically can have children, but they are probably not
// expected to have alerts within AT client code.
- ChildrenChanged(document_);
+ message_ax_object->Init(Root());
}
return message_ax_object;
}
-AXObject* AXObjectCacheImpl::ValidationMessageObjectIfInvalid() {
+AXObject* AXObjectCacheImpl::ValidationMessageObjectIfInvalid(
+ bool notify_children_changed) {
Element* focused_element = document_->FocusedElement();
if (focused_element) {
ListedElement* form_control = ListedElement::From(*focused_element);
@@ -1951,8 +2548,14 @@ AXObject* AXObjectCacheImpl::ValidationMessageObjectIfInvalid() {
AOMRelationProperty::kErrorMessage);
if (!override_native_validation_message) {
AXObject* message = GetOrCreateValidationMessageObject();
- if (message && !was_validation_message_already_created)
+ DCHECK(message);
+ DCHECK(!message->IsDetached());
+ if (notify_children_changed &&
+ Root()->FirstChildIncludingIgnored() != message) {
+ // Only notify children changed if not already processing new root
+ // children, and the root doesn't already have this child.
ChildrenChanged(document_);
+ }
return message;
}
}
@@ -1999,7 +2602,8 @@ void AXObjectCacheImpl::HandleValidationMessageVisibilityChangedWithCleanLayout(
<< "Unclean document at lifecycle " << document->Lifecycle().ToString();
#endif // DCHECK_IS_ON()
- AXObject* message_ax_object = ValidationMessageObjectIfInvalid();
+ AXObject* message_ax_object = ValidationMessageObjectIfInvalid(
+ /* Fire children changed on root if it gains message child */ true);
if (message_ax_object)
MarkAXObjectDirty(message_ax_object, false); // May be invisible now.
@@ -2051,20 +2655,27 @@ void AXObjectCacheImpl::LabelChangedWithCleanLayout(Element* element) {
relation_cache_->LabelChanged(element);
}
-void AXObjectCacheImpl::InlineTextBoxesUpdated(
- LineLayoutItem line_layout_item) {
+void AXObjectCacheImpl::InlineTextBoxesUpdated(LayoutObject* layout_object) {
if (!InlineTextBoxAccessibilityEnabled())
return;
- LayoutObject* layout_object =
- LineLayoutAPIShim::LayoutObjectFrom(line_layout_item);
+ AXID ax_id = layout_object_mapping_.at(layout_object);
+ DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
// Only update if the accessibility object already exists and it's
// not already marked as dirty.
- if (AXObject* obj = Get(layout_object)) {
+ // Do not use Get(): it does extra work to determine whether the object should
+ // be invalidated, including calling IsLayoutObjectRelevantForAccessibility(),
+ // which uses the NGInlineCursor. However, the NGInlineCursor cannot be used
+ // while inline boxes are being updated.
+ if (ax_id) {
+ AXObject* obj = objects_.at(ax_id);
+ DCHECK(obj);
+ DCHECK(obj->IsAXLayoutObject());
+ DCHECK(!obj->IsDetached());
if (!obj->NeedsToUpdateChildren()) {
obj->SetNeedsToUpdateChildren();
- PostNotification(layout_object, ax::mojom::Event::kChildrenChanged);
+ PostNotification(obj, ax::mojom::blink::Event::kChildrenChanged);
}
}
}
@@ -2138,6 +2749,7 @@ void AXObjectCacheImpl::PostPlatformNotification(
AXObject* obj,
ax::mojom::blink::Event event_type,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& event_intents) {
if (!document_ || !document_->View() ||
!document_->View()->GetFrame().GetPage()) {
@@ -2151,6 +2763,7 @@ void AXObjectCacheImpl::PostPlatformNotification(
event.id = obj->AXObjectID();
event.event_type = event_type;
event.event_from = event_from;
+ event.event_from_action = event_from_action;
event.event_intents.resize(event_intents.size());
// We need to filter out the counts from every intent.
std::transform(event_intents.begin(), event_intents.end(),
@@ -2243,6 +2856,8 @@ AXObject* AXObjectCacheImpl::AncestorAriaModalDialog(Node* node) {
}
AXObject* ancestor_ax_object = GetOrCreate(ancestor);
+ if (!ancestor_ax_object)
+ return nullptr;
ax::mojom::blink::Role ancestor_role = ancestor_ax_object->RoleValue();
if (!ui::IsDialog(ancestor_role))
@@ -2320,7 +2935,7 @@ void AXObjectCacheImpl::HandleValueChanged(Node* node) {
// If it's a slider, invalidate the thumb's bounding box.
AXObject* ax_object = Get(node);
if (ax_object && ax_object->RoleValue() == ax::mojom::blink::Role::kSlider &&
- ax_object->HasChildren() && !ax_object->NeedsToUpdateChildren() &&
+ !ax_object->NeedsToUpdateChildren() &&
ax_object->ChildCountIncludingIgnored() == 1) {
changed_bounds_ids_.insert(
ax_object->ChildAtIncludingIgnored(0)->AXObjectID());
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 ca59325b5c5..ecb56140a54 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
@@ -75,6 +75,10 @@ class MODULES_EXPORT AXObjectCacheImpl
void Dispose() override;
+ void Freeze() override { is_frozen_ = true; }
+ void Thaw() override { is_frozen_ = false; }
+ bool IsFrozen() { return is_frozen_; }
+
// Register/remove popups
void InitializePopup(Document* document) override;
void DisposePopup(Document* document) override;
@@ -89,6 +93,8 @@ class MODULES_EXPORT AXObjectCacheImpl
void SelectionChanged(Node*) override;
void UpdateReverseRelations(const AXObject* relation_source,
const Vector<String>& target_ids);
+ void ChildrenChanged(AXObject*);
+ void ChildrenChanged(const AXObject*);
void ChildrenChanged(Node*) override;
void ChildrenChanged(const LayoutObject*) override;
void ChildrenChanged(AccessibleNode*) override;
@@ -97,13 +103,13 @@ class MODULES_EXPORT AXObjectCacheImpl
void ListboxSelectedChildrenChanged(HTMLSelectElement*) override;
void ListboxActiveIndexChanged(HTMLSelectElement*) override;
void LocationChanged(const LayoutObject*) override;
- void RadiobuttonRemovedFromGroup(HTMLInputElement*) override;
void ImageLoaded(const LayoutObject*) override;
void Remove(AccessibleNode*) override;
void Remove(LayoutObject*) override;
void Remove(Node*) override;
void Remove(AbstractInlineTextBox*) override;
+ void Remove(AXObject*); // Calls more specific Remove methods as necessary.
const Element* RootAXEditableElement(const Node*) override;
@@ -151,7 +157,7 @@ class MODULES_EXPORT AXObjectCacheImpl
Element*,
const LayoutRect&) override;
- void InlineTextBoxesUpdated(LineLayoutItem) override;
+ void InlineTextBoxesUpdated(LayoutObject*) override;
void ProcessDeferredAccessibilityEvents(Document&) override;
bool IsDirty() const override;
@@ -181,40 +187,39 @@ class MODULES_EXPORT AXObjectCacheImpl
AXObject* ObjectFromAXID(AXID id) const { return objects_.at(id); }
AXObject* Root();
- // used for objects without backing elements
- AXObject* GetOrCreate(ax::mojom::blink::Role);
- AXObject* GetOrCreate(AccessibleNode*);
- AXObject* GetOrCreate(LayoutObject*) override;
- AXObject* GetOrCreate(const Node*);
+ // Used for objects without backing DOM nodes, layout objects, etc.
+ AXObject* CreateAndInit(ax::mojom::blink::Role, AXObject* parent);
+
+ AXObject* GetOrCreate(AccessibleNode*, AXObject* parent);
+ AXObject* GetOrCreate(LayoutObject*, AXObject* parent_if_known) override;
+ AXObject* GetOrCreate(LayoutObject* layout_object);
+ AXObject* GetOrCreate(const Node*, AXObject* parent_if_known);
+ AXObject* GetOrCreate(Node*, AXObject* parent_if_known);
AXObject* GetOrCreate(Node*);
- AXObject* GetOrCreate(AbstractInlineTextBox*);
+ AXObject* GetOrCreate(const Node*);
+ AXObject* GetOrCreate(AbstractInlineTextBox*, AXObject* parent_if_known);
AXID GetAXID(Node*) override;
Element* GetElementFromAXID(AXID) override;
- // Will only return the AXObject if it already exists.
- AXObject* GetIfExists(const Node*);
AXObject* Get(AccessibleNode*);
AXObject* Get(AbstractInlineTextBox*);
- // These can actually return a different AXObject* if it's determined that
- // the wrong type currently axists (AXNodeObject vs AXLayoutObject).
- // TODO(aleventhal) These should not have any side effects.
AXObject* Get(const Node*) override;
AXObject* Get(const LayoutObject*);
AXObject* FirstAccessibleObjectFromNode(const Node*);
- void Remove(AXID);
-
void ChildrenChangedWithCleanLayout(Node* optional_node_for_relation_update,
AXObject*);
- void MaybeNewRelationTarget(Node* node, AXObject* obj);
+ // When an object is created or its id changes, this must be called so that
+ // the relation cache is updated.
+ void MaybeNewRelationTarget(Node& node, AXObject* obj);
void HandleActiveDescendantChangedWithCleanLayout(Node*);
void HandleRoleChangeWithCleanLayout(Node*);
- void HandleRoleChangeIfNotEditableWithCleanLayout(Node*);
+ void HandleAriaHiddenChangedWithCleanLayout(Node*);
void HandleAriaExpandedChangeWithCleanLayout(Node*);
void HandleAriaSelectedChangedWithCleanLayout(Node*);
void HandleNodeLostFocusWithCleanLayout(Node*);
@@ -279,22 +284,34 @@ class MODULES_EXPORT AXObjectCacheImpl
// granted, it only applies to the next event received.
void RequestAOMEventListenerPermission();
- // For built-in HTML form validation messages.
- AXObject* ValidationMessageObjectIfInvalid();
+ // For built-in HTML form validation messages. Set notify_children_changed to
+ // true if not already processing changed children.
+ AXObject* ValidationMessageObjectIfInvalid(bool notify_children_changed);
WebAXAutofillState GetAutofillState(AXID id) const;
void SetAutofillState(AXID id, WebAXAutofillState state);
- ax::mojom::blink::EventFrom active_event_from() const {
- return active_event_from_;
+ std::pair<ax::mojom::blink::EventFrom, ax::mojom::blink::Action>
+ active_event_from_data() const {
+ return std::make_pair(active_event_from_, active_event_from_action_);
}
- void set_active_event_from(const ax::mojom::blink::EventFrom event_from) {
+
+ void set_active_event_from_data(
+ const ax::mojom::blink::EventFrom event_from,
+ const ax::mojom::blink::Action event_from_action) {
active_event_from_ = event_from;
+ active_event_from_action_ = event_from_action;
}
AXObject* GetActiveAriaModalDialog() const;
- bool UseAXMenuList() { return use_ax_menu_list_; }
+ static bool UseAXMenuList() { return use_ax_menu_list_; }
+ static bool ShouldCreateAXMenuListOptionFor(const Node*);
+ static bool IsPseudoElementDescendant(const LayoutObject& layout_object);
+
+#if DCHECK_IS_ON()
+ bool HasBeenDisposed() { return has_been_disposed_; }
+#endif
// Retrieves a vector of all AXObjects whose bounding boxes may have changed
// since the last query. Clears the vector so that the next time it's
@@ -307,6 +324,8 @@ class MODULES_EXPORT AXObjectCacheImpl
ax::mojom::blink::Event event_type,
ax::mojom::blink::EventFrom event_from =
ax::mojom::blink::EventFrom::kNone,
+ ax::mojom::blink::Action event_from_action =
+ ax::mojom::blink::Action::kNone,
const BlinkAXEventIntentsSet& event_intents = BlinkAXEventIntentsSet());
void LabelChangedWithCleanLayout(Element*);
@@ -315,17 +334,38 @@ class MODULES_EXPORT AXObjectCacheImpl
return active_event_intents_;
}
+ // Create an AXObject, and do not check if a previous one exists.
+ // Also, initialize the object and add it to maps for later retrieval.
+ AXObject* CreateAndInit(Node*, AXObject* parent_if_known, AXID use_axid = 0);
+ AXObject* CreateAndInit(LayoutObject*,
+ AXObject* parent_if_known,
+ AXID use_axid = 0);
+
+ // Mark object as invalid and needing to be refreshed when layout is clean.
+ // Will result in a new object with the same AXID, and will also call
+ // ChildrenChanged() on the parent of invalidated objects. Automatically
+ // de-dupes extra object refreshes and ChildrenChanged() calls.
+ void Invalidate(AXID);
+
AXObject* CreateFromRenderer(LayoutObject*);
AXObject* CreateFromNode(Node*);
AXObject* CreateFromInlineTextBox(AbstractInlineTextBox*);
+ void Remove(AXID);
+
+ // Given a <map> element, get the image currently associated with it, if any.
+ AXObject* GetAXImageForMap(HTMLMapElement& map);
private:
struct AXEventParams final : public GarbageCollected<AXEventParams> {
AXEventParams(AXObject* target,
ax::mojom::blink::Event event_type,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& intents)
- : target(target), event_type(event_type), event_from(event_from) {
+ : target(target),
+ event_type(event_type),
+ event_from(event_from),
+ event_from_action(event_from_action) {
for (const auto& intent : intents) {
event_intents.insert(intent.key, intent.value);
}
@@ -333,6 +373,7 @@ class MODULES_EXPORT AXObjectCacheImpl
Member<AXObject> target;
ax::mojom::blink::Event event_type;
ax::mojom::blink::EventFrom event_from;
+ ax::mojom::blink::Action event_from_action;
BlinkAXEventIntentsSet event_intents;
void Trace(Visitor* visitor) const { visitor->Trace(target); }
@@ -342,11 +383,13 @@ class MODULES_EXPORT AXObjectCacheImpl
TreeUpdateParams(const Node* node,
AXID axid,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& intents,
base::OnceClosure callback)
: node(node),
axid(axid),
event_from(event_from),
+ event_from_action(event_from_action),
callback(std::move(callback)) {
for (const auto& intent : intents) {
event_intents.insert(intent.key, intent.value);
@@ -355,6 +398,7 @@ class MODULES_EXPORT AXObjectCacheImpl
WeakMember<const Node> node;
AXID axid;
ax::mojom::blink::EventFrom event_from;
+ ax::mojom::blink::Action event_from_action;
BlinkAXEventIntentsSet event_intents;
base::OnceClosure callback;
@@ -395,7 +439,18 @@ class MODULES_EXPORT AXObjectCacheImpl
HeapVector<Member<AXEventParams>> notifications_to_post_;
- void ProcessUpdates(Document&);
+ // Call the queued callback methods that do processing which must occur when
+ // layout is clean. These callbacks are stored in tree_update_callback_queue_,
+ // and have names like FooBarredWithCleanLayout().
+ void ProcessCleanLayoutCallbacks(Document&);
+
+ // Destroy and recreate any objects which are no longer valid, for example
+ // they used to be an AXNodeObject and now must be an AXLayoutObject, or
+ // vice-versa. Also fires children changed on the parent of these nodes.
+ void ProcessInvalidatedObjects(Document&);
+
+ // Send events to RenderAccessibilityImpl, which serializes them and then
+ // sends the serialized events and dirty objects to the browser process.
void PostNotifications(Document&);
// Get the currently focused Node element.
@@ -406,7 +461,8 @@ class MODULES_EXPORT AXObjectCacheImpl
AXObject* FocusedImageMapUIElement(HTMLAreaElement*);
- AXID GetOrCreateAXID(AXObject*);
+ // Associate an AXObject with an AXID. Generate one if none is supplied.
+ AXID AssociateAXID(AXObject*, AXID use_axid = 0);
void TextChanged(Node*);
bool NodeIsTextControl(const Node*);
@@ -427,7 +483,7 @@ class MODULES_EXPORT AXObjectCacheImpl
void ContainingTableRowsOrColsMaybeChanged(Node*);
// Must be called an entire subtree of accessible objects are no longer valid.
- void InvalidateTableSubtree(AXObject* subtree);
+ void RemoveAXObjectsInLayoutSubtree(AXObject* subtree);
// Object for HTML validation alerts. Created at most once per object cache.
AXObject* GetOrCreateValidationMessageObject();
@@ -461,6 +517,8 @@ class MODULES_EXPORT AXObjectCacheImpl
void ChildrenChangedWithCleanLayout(Node* node);
void HandleAttributeChangedWithCleanLayout(const QualifiedName& attr_name,
Element* element);
+ void HandleUseMapAttributeChangedWithCleanLayout(Element*);
+ void HandleNameAttributeChangedWithCleanLayout(Element*);
bool DoesEventListenerImpactIgnoredState(
const AtomicString& event_type) const;
@@ -484,11 +542,13 @@ class MODULES_EXPORT AXObjectCacheImpl
void FireTreeUpdatedEventImmediately(
Document& document,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& event_intents,
base::OnceClosure callback);
void FireAXEventImmediately(AXObject* obj,
ax::mojom::blink::Event event_type,
ax::mojom::blink::EventFrom event_from,
+ ax::mojom::blink::Action event_from_action,
const BlinkAXEventIntentsSet& event_intents);
void SetMaxPendingUpdatesForTesting(wtf_size_t max_pending_updates) {
@@ -540,12 +600,22 @@ class MODULES_EXPORT AXObjectCacheImpl
ax::mojom::blink::EventFrom active_event_from_ =
ax::mojom::blink::EventFrom::kNone;
+ // The accessibility action that caused the event. Will only be valid if
+ // active_event_from_ is set to kAction.
+ ax::mojom::blink::Action active_event_from_action_ =
+ ax::mojom::blink::Action::kNone;
+
// A set of currently active event intents.
BlinkAXEventIntentsSet active_event_intents_;
+ bool is_frozen_ = false; // Used with Freeze(), Thaw() and IsFrozen() above.
+
+ // Set of ID's of current AXObjects that need to be destroyed and recreated.
+ HashSet<AXID> invalidated_ids_;
+
// If false, exposes the internal accessibility tree of a select pop-up
// instead.
- bool use_ax_menu_list_ = true;
+ static bool use_ax_menu_list_;
DISALLOW_COPY_AND_ASSIGN(AXObjectCacheImpl);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
index d78827c6149..c4db137cc71 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
@@ -64,8 +64,12 @@ class MockAXObject : public AXObject {
static unsigned num_children_changed_calls_;
void ChildrenChanged() final { num_children_changed_calls_++; }
- AXObject* ComputeParent() const final { return nullptr; }
+ AXObject* ComputeParentImpl() const final { return nullptr; }
Document* GetDocument() const final { return &AXObjectCache().GetDocument(); }
+ void AddChildren() final {}
+ ax::mojom::blink::Role DetermineAccessibilityRole() override {
+ return ax::mojom::blink::Role::kUnknown;
+ }
};
unsigned MockAXObject::num_children_changed_calls_ = 0;
@@ -80,13 +84,13 @@ TEST_F(AccessibilityTest, PauseUpdatesAfterMaxNumberQueued) {
ax_object_cache->SetMaxPendingUpdatesForTesting(max_updates);
MockAXObject* ax_obj = MakeGarbageCollected<MockAXObject>(*ax_object_cache);
- ax_obj->SetAXObjectID(ax_object_cache->GetOrCreateAXID(ax_obj));
+ ax_object_cache->AssociateAXID(ax_obj);
for (unsigned i = 0; i < max_updates + 1; i++) {
ax_object_cache->DeferTreeUpdate(
&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, nullptr, ax_obj);
}
document.Lifecycle().AdvanceTo(DocumentLifecycle::kInAccessibility);
- ax_object_cache->ProcessUpdates(document);
+ ax_object_cache->ProcessCleanLayoutCallbacks(document);
ASSERT_EQ(0u, MockAXObject::num_children_changed_calls_);
}
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 03c3cc8462f..5a649c79d54 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
@@ -40,6 +40,22 @@ TEST_F(AccessibilityTest, IsAncestorOf) {
EXPECT_FALSE(button->IsAncestorOf(*root));
}
+TEST_F(AccessibilityTest, DetachedIsIgnored) {
+ SetBodyInnerHTML(R"HTML(<button id="button">button</button>)HTML");
+
+ const AXObject* root = GetAXRootObject();
+ ASSERT_NE(nullptr, root);
+ AXObject* button = GetAXObjectByElementId("button");
+ ASSERT_NE(nullptr, button);
+
+ EXPECT_FALSE(button->IsDetached());
+ EXPECT_FALSE(button->AccessibilityIsIgnored());
+ GetAXObjectCache().Remove(button->GetNode());
+ EXPECT_TRUE(button->IsDetached());
+ EXPECT_TRUE(button->AccessibilityIsIgnored());
+ EXPECT_FALSE(button->AccessibilityIsIgnoredButIncludedInTree());
+}
+
TEST_F(AccessibilityTest, UnignoredChildren) {
SetBodyInnerHTML(R"HTML(This is a test with
<p role="presentation">
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 17268a2b41c..783a72e5e66 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
@@ -392,6 +392,9 @@ AXPosition::AXPosition(const AXObject& container)
const AXObject* AXPosition::ChildAfterTreePosition() const {
if (!IsValid() || IsTextPosition())
return nullptr;
+ if (ChildIndex() == container_object_->ChildCountIncludingIgnored())
+ return nullptr;
+ DCHECK_LT(ChildIndex(), container_object_->ChildCountIncludingIgnored());
return container_object_->ChildAtIncludingIgnored(ChildIndex());
}
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 56a29df6f05..dfb9e2abc37 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
@@ -1215,7 +1215,8 @@ TEST_F(AccessibilityTest, PositionAfterListMarker) {
EXPECT_EQ(0, ax_position_from_dom.TextOffset());
}
-TEST_F(AccessibilityTest, PositionInCSSContent) {
+// TODO(nektar) Fix test to work with ignored containers of pseudo content.
+TEST_F(AccessibilityTest, DISABLED_PositionInCSSContent) {
SetBodyInnerHTML(kCSSBeforeAndAfter);
const Node* quote = GetElementById("quote");
@@ -1263,7 +1264,8 @@ TEST_F(AccessibilityTest, PositionInCSSContent) {
EXPECT_EQ(12, position_after.GetPosition().OffsetInContainerNode());
}
-TEST_F(AccessibilityTest, PositionInCSSImageContent) {
+// TODO(nektar) Fix test to work with ignored containers of pseudo content.
+TEST_F(AccessibilityTest, DISABLED_PositionInCSSImageContent) {
constexpr char css_content_no_text[] = R"HTML(
<style>
.heading::before {
@@ -1293,7 +1295,8 @@ TEST_F(AccessibilityTest, PositionInCSSImageContent) {
EXPECT_EQ(3, position.GetPosition().OffsetInContainerNode());
}
-TEST_F(AccessibilityTest, PositionInTableWithCSSContent) {
+// TODO(nektar) Fix test to work with ignored containers of pseudo content.
+TEST_F(AccessibilityTest, DISABLED_PositionInTableWithCSSContent) {
SetBodyInnerHTML(kHTMLTable);
// Add some CSS content, i.e. a plus symbol before and a colon after each
@@ -1338,15 +1341,19 @@ TEST_F(AccessibilityTest, PositionInTableWithCSSContent) {
ASSERT_EQ(ax::mojom::Role::kColumnHeader, ax_last_header_cell->RoleValue());
ASSERT_EQ(3, ax_first_header_cell->ChildCountIncludingIgnored());
+ // Get grandchild text, not the child ignored generic container.
AXObject* const ax_first_cell_css_before =
- ax_first_header_cell->FirstChildIncludingIgnored();
+ ax_first_header_cell->FirstChildIncludingIgnored()
+ ->FirstChildIncludingIgnored();
ASSERT_NE(nullptr, ax_first_cell_css_before);
ASSERT_EQ(ax::mojom::Role::kStaticText,
ax_first_cell_css_before->RoleValue());
ASSERT_EQ(3, ax_last_header_cell->ChildCountIncludingIgnored());
+ // Get grandchild text, not the child ignored generic container.
AXObject* const ax_last_cell_css_after =
- ax_last_header_cell->LastChildIncludingIgnored();
+ ax_last_header_cell->FirstChildIncludingIgnored()
+ ->LastChildIncludingIgnored();
ASSERT_NE(nullptr, ax_last_cell_css_after);
ASSERT_EQ(ax::mojom::Role::kStaticText, ax_last_cell_css_after->RoleValue());
@@ -1472,10 +1479,14 @@ TEST_F(AccessibilityTest, PositionBeforeAndAfterTable) {
TEST_F(AccessibilityTest, PositionAtStartAndEndOfTable) {
SetBodyInnerHTML(kHTMLTable);
- // In the accessibility tree, the thead and tbody elements are ignored, but
- // they are used as anchors when converting an AX position to a DOM position
- // because they are the closest anchor to the first and last unignored AX
- // positions inside the table.
+ // In the accessibility tree, the thead and tbody elements are accessibility
+ // ignored but included in the AXTree.
+ // Calling CreateFirstPositionInObject and CreateLastPositionInObject with the
+ // |table| element will create a position anchored to |table| which points to
+ // the |thead| element and the last whitespace text node within the table
+ // respectively.
+ const Node* table = GetElementById("table");
+ ASSERT_NE(nullptr, table);
const Node* thead = GetElementById("thead");
ASSERT_NE(nullptr, thead);
const Node* header_row = GetElementById("headerRow");
@@ -1490,26 +1501,25 @@ TEST_F(AccessibilityTest, PositionAtStartAndEndOfTable) {
ASSERT_NE(nullptr, ax_header_row);
ASSERT_EQ(ax::mojom::Role::kRow, ax_header_row->RoleValue());
+ const AXObject* ax_thead = GetAXObjectByElementId("thead");
const auto ax_position_at_start =
AXPosition::CreateFirstPositionInObject(*ax_table);
const auto position_at_start = ax_position_at_start.ToPositionWithAffinity();
- EXPECT_EQ(thead, position_at_start.AnchorNode());
+ EXPECT_EQ(table, position_at_start.AnchorNode());
EXPECT_EQ(1, position_at_start.GetPosition().OffsetInContainerNode());
- EXPECT_EQ(header_row,
- position_at_start.GetPosition().ComputeNodeAfterPosition());
+ EXPECT_EQ(thead, position_at_start.GetPosition().ComputeNodeAfterPosition());
const auto ax_position_at_start_from_dom =
AXPosition::FromPosition(position_at_start);
EXPECT_EQ(ax_position_at_start, ax_position_at_start_from_dom);
- EXPECT_EQ(ax_header_row,
- ax_position_at_start_from_dom.ChildAfterTreePosition());
+ EXPECT_EQ(ax_thead, ax_position_at_start_from_dom.ChildAfterTreePosition());
const auto ax_position_at_end =
AXPosition::CreateLastPositionInObject(*ax_table);
const auto position_at_end = ax_position_at_end.ToPositionWithAffinity();
- EXPECT_EQ(tbody, position_at_end.AnchorNode());
+ EXPECT_EQ(table, position_at_end.AnchorNode());
// There are three rows and a line break before and after each one.
- EXPECT_EQ(6, position_at_end.GetPosition().OffsetInContainerNode());
+ EXPECT_EQ(4, position_at_end.GetPosition().OffsetInContainerNode());
const auto ax_position_at_end_from_dom =
AXPosition::FromPosition(position_at_end);
@@ -1659,23 +1669,28 @@ TEST_F(AccessibilityTest, PositionInInvalidMapLayout) {
Node* map = GetElementById("map");
ASSERT_NE(nullptr, map);
+ const AXObject* ax_map = GetAXObjectByElementId("map");
+ ASSERT_EQ(nullptr, ax_map); // No AXObject is created for a <map>.
+
// Create an invalid layout by appending a child to the <br>
br->appendChild(map);
GetDocument().UpdateStyleAndLayoutTree();
- const AXObject* ax_map = GetAXObjectByElementId("map");
- ASSERT_NE(nullptr, ax_map);
- ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_map->RoleValue());
+ ax_map = GetAXObjectByElementId("map");
+ ASSERT_EQ(nullptr, ax_map);
+
+ const AXObject* ax_br = GetAXObjectByElementId("br");
+ ASSERT_NE(nullptr, ax_br);
const auto ax_position_before =
- AXPosition::CreatePositionBeforeObject(*ax_map);
+ AXPosition::CreateFirstPositionInObject(*ax_br);
const auto position_before = ax_position_before.ToPositionWithAffinity();
- EXPECT_EQ(nullptr, position_before.AnchorNode());
+ EXPECT_EQ(br, position_before.AnchorNode());
EXPECT_EQ(0, position_before.GetPosition().OffsetInContainerNode());
- const auto ax_position_after = AXPosition::CreatePositionAfterObject(*ax_map);
+ const auto ax_position_after = AXPosition::CreateLastPositionInObject(*ax_br);
const auto position_after = ax_position_after.ToPositionWithAffinity();
- EXPECT_EQ(nullptr, position_after.AnchorNode());
+ EXPECT_EQ(br, position_after.AnchorNode());
EXPECT_EQ(0, position_after.GetPosition().OffsetInContainerNode());
}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc
deleted file mode 100644
index 18e5c357fdc..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc
+++ /dev/null
@@ -1,132 +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/accessibility/ax_radio_input.h"
-
-#include "third_party/blink/renderer/core/aom/accessible_node.h"
-#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
-#include "third_party/blink/renderer/core/html/forms/radio_input_type.h"
-#include "third_party/blink/renderer/core/input_type_names.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
-
-namespace blink {
-
-AXRadioInput::AXRadioInput(LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache)
- : AXLayoutObject(layout_object, ax_object_cache) {
- // Updates posInSet and setSize for the current object and the next objects.
- if (!CalculatePosInSet())
- return;
- // When a new object is inserted, it needs to update setSize for the previous
- // objects.
- RequestUpdateToNextNode(false);
-}
-
-void AXRadioInput::UpdatePosAndSetSize(int position) {
- if (position)
- pos_in_set_ = position;
- set_size_ = SizeOfRadioGroup();
-}
-
-void AXRadioInput::RequestUpdateToNextNode(bool forward) {
- HTMLInputElement* next_element =
- RadioInputType::NextRadioButtonInGroup(GetInputElement(), forward);
- AXObject* next_axobject = AXObjectCache().Get(next_element);
- auto* ax_radio_input = DynamicTo<AXRadioInput>(next_axobject);
- if (!ax_radio_input)
- return;
-
- int position = 0;
- if (forward)
- position = PosInSet() + 1;
- // If it is backward, it keeps position as positions are already assigned for
- // previous objects. updatePosAndSetSize() is called with '0' and it doesn't
- // modify m_posInSet and updates m_setSize as size is increased.
-
- ax_radio_input->UpdatePosAndSetSize(position);
- AXObjectCache().PostNotification(next_axobject,
- ax::mojom::Event::kAriaAttributeChanged);
- ax_radio_input->RequestUpdateToNextNode(forward);
-}
-
-HTMLInputElement* AXRadioInput::FindFirstRadioButtonInGroup(
- HTMLInputElement* current) const {
- while (HTMLInputElement* prev_element =
- RadioInputType::NextRadioButtonInGroup(current, false))
- current = prev_element;
- return current;
-}
-
-int AXRadioInput::PosInSet() const {
- uint32_t pos_in_set;
- if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kPosInSet, pos_in_set))
- return pos_in_set;
- return pos_in_set_;
-}
-
-int AXRadioInput::SetSize() const {
- int32_t set_size;
- if (HasAOMPropertyOrARIAAttribute(AOMIntProperty::kSetSize, set_size))
- return set_size;
- return set_size_;
-}
-
-bool AXRadioInput::CalculatePosInSet() {
- // Calculate 'posInSet' attribute when AXRadioInputs need to be updated
- // as a new AXRadioInput Object is added or one of objects from RadioGroup is
- // removed.
- bool need_to_update_prev = false;
- int position = 1;
- HTMLInputElement* prev_element =
- RadioInputType::NextRadioButtonInGroup(GetInputElement(), false);
- if (prev_element) {
- AXObject* object = AXObjectCache().Get(prev_element);
- // If the previous element doesn't have AXObject yet, caculate position
- // from the first element. Otherwise, get position from the previous
- // AXObject.
- if (!object || !object->IsAXRadioInput()) {
- position = CountFromFirstElement();
- } else {
- position = object->PosInSet() + 1;
- // It returns true if previous objects need to be updated.
- // When AX tree exists already and a new node is inserted,
- // as updating is started from the inserted node,
- // we need to update setSize for previous nodes.
- if (SetSize() != object->SetSize())
- need_to_update_prev = true;
- }
- }
- UpdatePosAndSetSize(position);
-
- // If it is not the last element, request update to the next node.
- if (position != SetSize())
- RequestUpdateToNextNode(true);
- return need_to_update_prev;
-}
-
-int AXRadioInput::CountFromFirstElement() const {
- int count = 1;
- HTMLInputElement* current = GetInputElement();
- while (HTMLInputElement* prev_element =
- RadioInputType::NextRadioButtonInGroup(current, false)) {
- current = prev_element;
- count++;
- }
- return count;
-}
-
-HTMLInputElement* AXRadioInput::GetInputElement() const {
- return To<HTMLInputElement>(layout_object_->GetNode());
-}
-
-int AXRadioInput::SizeOfRadioGroup() const {
- int size = GetInputElement()->SizeOfRadioGroup();
- // If it has no size in Group, it means that there is only itself.
- if (!size)
- return 1;
- return size;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.h
deleted file mode 100644
index e171357281e..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.h
+++ /dev/null
@@ -1,51 +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_ACCESSIBILITY_AX_RADIO_INPUT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_RADIO_INPUT_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
-
-namespace blink {
-
-class AXObjectCacheImpl;
-class HTMLInputElement;
-
-class AXRadioInput final : public AXLayoutObject {
- public:
- AXRadioInput(LayoutObject*, AXObjectCacheImpl&);
- ~AXRadioInput() override = default;
-
- bool IsAXRadioInput() const override { return true; }
- void UpdatePosAndSetSize(int position = 0);
- void RequestUpdateToNextNode(bool forward);
- HTMLInputElement* FindFirstRadioButtonInGroup(
- HTMLInputElement* current) const;
-
- int PosInSet() const final;
- int SetSize() const final;
-
- private:
- bool CalculatePosInSet();
- int CountFromFirstElement() const;
- HTMLInputElement* GetInputElement() const;
- int SizeOfRadioGroup() const;
-
- int pos_in_set_;
- int set_size_;
-
- DISALLOW_COPY_AND_ASSIGN(AXRadioInput);
-};
-
-template <>
-struct DowncastTraits<AXRadioInput> {
- static bool AllowFrom(const AXObject& object) {
- return object.IsAXRadioInput();
- }
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_RADIO_INPUT_H_
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 ab78f47da88..ccba469aff7 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
@@ -15,7 +15,7 @@ AXRelationCache::AXRelationCache(AXObjectCacheImpl* object_cache)
AXRelationCache::~AXRelationCache() = default;
-void AXRelationCache::Init() {
+void AXRelationCache::DoInitialDocumentScan() {
// Init the relation cache with elements already in the document.
Document& document = object_cache_->GetDocument();
for (Element& element :
@@ -28,15 +28,24 @@ void AXRelationCache::Init() {
// 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 DCHECK_IS_ON()
+ DCHECK(document.Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
+ << "Unclean document at lifecycle " << document.Lifecycle().ToString();
+#endif
if (element.FastHasAttribute(html_names::kAriaOwnsAttr)) {
- if (AXObject* owner = GetOrCreate(&element)) {
+ if (AXObject* owner = GetOrCreate(&element, nullptr)) {
owner_ids_to_update_.insert(owner->AXObjectID());
}
}
}
+
+ initialized_ = true;
}
void AXRelationCache::ProcessUpdatesWithCleanLayout() {
+ if (!initialized_)
+ DoInitialDocumentScan();
+
for (AXID aria_owns_obj_id : owner_ids_to_update_) {
AXObject* obj = ObjectFromAXID(aria_owns_obj_id);
if (obj)
@@ -47,7 +56,8 @@ void AXRelationCache::ProcessUpdatesWithCleanLayout() {
}
bool AXRelationCache::IsAriaOwned(const AXObject* child) const {
- return aria_owned_child_to_owner_mapping_.Contains(child->AXObjectID());
+ return child &&
+ aria_owned_child_to_owner_mapping_.Contains(child->AXObjectID());
}
AXObject* AXRelationCache::GetAriaOwnedParent(const AXObject* child) const {
@@ -85,23 +95,12 @@ static bool ContainsCycle(AXObject* owner, AXObject* child) {
bool AXRelationCache::IsValidOwnsRelation(AXObject* owner,
AXObject* child) const {
- if (!child)
- return false;
-
- // Some objects aren't allowed to aria-own children - in particular
- // aria-owns is sometimes set on combo boxes but we don't want to
- // rearrange the tree because then we'd interpret that as the owned
- // children actually being part of the editable content of the text
- // field.
- if (!owner->CanHaveChildren() || owner->IsNativeTextControl() ||
- owner->HasContentEditableAttributeSet()) {
+ if (!IsValidOwner(owner) || !IsValidOwnedChild(child))
return false;
- }
// If this child is already aria-owned by a different owner, continue.
// It's an author error if this happens and we don't worry about which of
- // the two owners wins ownership of the child, as long as only one of them
- // does.
+ // the two owners wins ownership, as long as only one of them does.
if (IsAriaOwned(child) && GetAriaOwnedParent(child) != owner)
return false;
@@ -112,6 +111,48 @@ bool AXRelationCache::IsValidOwnsRelation(AXObject* owner,
return true;
}
+bool AXRelationCache::IsValidOwner(AXObject* owner) {
+ if (!owner->GetNode()) {
+ NOTREACHED() << "Cannot use aria-owns without a node on both ends";
+ return false;
+ }
+
+ // Can't have children.
+ if (!owner->CanHaveChildren())
+ return false;
+
+ // No aria-owns in editable controlsm otherwise wreaks havoc.
+ if (owner->IsNativeTextControl() || owner->HasContentEditableAttributeSet())
+ return false;
+
+ // Image maps can only use <img usemap> to "own" <area> children.
+ // This requires special parenting logic, and aria-owns is prevented here in
+ // order to keep things from getting too complex.
+ if (owner->RoleValue() == ax::mojom::blink::Role::kImageMap)
+ return false;
+
+ // Similarly, do not allow <area> to own another object.
+ if (owner->IsImageMapLink())
+ return false;
+
+ return true;
+}
+
+bool AXRelationCache::IsValidOwnedChild(AXObject* child) {
+ if (!child)
+ return false;
+
+ if (!child->GetNode()) {
+ NOTREACHED() << "Cannot use aria-owns without a node on both ends";
+ return false;
+ }
+
+ if (child->IsImageMapLink())
+ return false; // An area can't be owned, only parented by <img usemap>.
+
+ return true;
+}
+
void AXRelationCache::UnmapOwnedChildren(const AXObject* owner,
const Vector<AXID> child_ids) {
for (AXID removed_child_id : child_ids) {
@@ -132,8 +173,8 @@ void AXRelationCache::UnmapOwnedChildren(const AXObject* owner,
// back to its real parent in the tree by detaching it from its current
// parent and calling childrenChanged on its real parent.
removed_child->DetachFromParent();
- AXObject* real_parent = removed_child->ParentObjectIncludedInTree();
-
+ // Recompute the real parent and cache it.
+ AXObject* real_parent = removed_child->ParentObject();
ChildrenChanged(real_parent);
}
}
@@ -151,6 +192,7 @@ void AXRelationCache::MapOwnedChildren(const AXObject* owner,
// on the original parent so that it can recompute its list of children.
AXObject* original_parent = added_child->ParentObject();
added_child->DetachFromParent();
+ added_child->SetParent(const_cast<AXObject*>(owner));
ChildrenChanged(original_parent);
}
}
@@ -165,14 +207,20 @@ void AXRelationCache::UpdateAriaOwnsFromAttrAssociatedElementsWithCleanLayout(
Vector<String> owned_id_vector;
for (const auto& element : attr_associated_elements) {
- AXObject* child = GetOrCreate(element);
+ // Pass in owner parent assuming that the owns relationship will be valid.
+ // It will be cleared below if the owns relationship is found to be invalid.
+ AXObject* child = GetOrCreate(element, owner);
// TODO(meredithl): Determine how to update reverse relations for elements
// without an id.
if (element->GetIdAttribute())
owned_id_vector.push_back(element->GetIdAttribute());
- if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child))
- validated_owned_children_result.push_back(GetOrCreate(element));
+ if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child)) {
+ validated_owned_children_result.push_back(child);
+ } else if (child) {
+ // Invalid owns relation: repair the parent that was set above.
+ child->SetParent(child->ComputeParentImpl());
+ }
}
// Track reverse relations for future tree updates.
@@ -192,8 +240,10 @@ void AXRelationCache::GetAriaOwnedChildren(
aria_owner_to_children_mapping_.at(owner->AXObjectID());
for (AXID child_id : current_child_axids) {
AXObject* child = ObjectFromAXID(child_id);
- if (child)
+ if (child) {
validated_owned_children_result.push_back(child);
+ DCHECK(IsAriaOwned(child)) << "Owned child not in owned child map";
+ }
}
}
@@ -232,9 +282,16 @@ void AXRelationCache::UpdateAriaOwnsWithCleanLayout(AXObject* owner) {
Vector<AXID> validated_owned_child_axids;
for (const String& id_name : owned_id_vector) {
Element* child_element = scope.getElementById(AtomicString(id_name));
- AXObject* child = GetOrCreate(child_element);
- if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child))
+ // Pass in owner parent assuming that the owns relationship will be valid.
+ // It will be cleared below if the owns relationship is found to be
+ // invalid.
+ AXObject* child = GetOrCreate(child_element, owner);
+ if (IsValidOwnsRelation(const_cast<AXObject*>(owner), child)) {
owned_children.push_back(child);
+ } else if (child) {
+ // Invalid owns relation: repair the parent that was set above.
+ child->SetParent(child->ComputeParentImpl());
+ }
}
}
@@ -263,18 +320,22 @@ void AXRelationCache::UpdateAriaOwnerToChildrenMappingWithCleanLayout(
UnmapOwnedChildren(owner, current_child_axids);
MapOwnedChildren(owner, validated_owned_child_axids);
- // Finally, update the mapping from the owner to the list of child IDs.
- aria_owner_to_children_mapping_.Set(owner->AXObjectID(),
- validated_owned_child_axids);
-
- ChildrenChanged(owner);
-
#if DCHECK_IS_ON()
// Owned children must be in tree to avoid serialization issues.
for (AXObject* child : validated_owned_children_result) {
- DCHECK(child->AccessibilityIsIncludedInTree());
+ DCHECK(child->AccessibilityIsIncludedInTree())
+ << "Owned child not in tree: " << child->ToString(true, false)
+ << "\nRecompute included in tree: "
+ << child->ComputeAccessibilityIsIgnoredButIncludedInTree();
}
#endif
+
+ // Finally, update the mapping from the owner to the list of child IDs.
+ aria_owner_to_children_mapping_.Set(owner->AXObjectID(),
+ validated_owned_child_axids);
+
+ ChildrenChanged(owner);
+ owner->UpdateChildrenIfNecessary();
}
bool AXRelationCache::MayHaveHTMLLabelViaForAttribute(
@@ -307,9 +368,18 @@ void AXRelationCache::GetReverseRelated(
}
}
-void AXRelationCache::UpdateRelatedTree(Node* node) {
+void AXRelationCache::UpdateRelatedTree(Node* node, AXObject* obj) {
HeapVector<Member<AXObject>> related_sources;
- AXObject* related_target = Get(node);
+#if DCHECK_IS_ON()
+ DCHECK(node);
+ AXObject* obj_for_node = Get(node);
+ DCHECK(!obj || obj_for_node == obj)
+ << "Object and node did not match:"
+ << "\n* node = " << node << "\n* obj = " << obj->ToString(true, true)
+ << "\n* obj_for_node = "
+ << (obj_for_node ? obj_for_node->ToString(true, true) : "null");
+#endif
+ AXObject* related_target = obj ? obj : Get(node);
// If it's already owned, schedule an update on the owner.
if (related_target && IsAriaOwned(related_target)) {
AXObject* owned_parent = GetAriaOwnedParent(related_target);
@@ -359,12 +429,33 @@ void AXRelationCache::UpdateRelatedText(Node* node) {
}
void AXRelationCache::RemoveAXID(AXID obj_id) {
+ // Need to remove from maps.
+ // There are maps from children to their owners, and owners to their children.
+ // In addition, the removed id may be an owner, or be owned, or both.
+
+ // |obj_id| owned others:
if (aria_owner_to_children_mapping_.Contains(obj_id)) {
+ // |obj_id| longer owns anything.
Vector<AXID> child_axids = aria_owner_to_children_mapping_.at(obj_id);
aria_owned_child_to_owner_mapping_.RemoveAll(child_axids);
+ // Owned children are no longer owned by |obj_id|
aria_owner_to_children_mapping_.erase(obj_id);
}
- aria_owned_child_to_owner_mapping_.erase(obj_id);
+
+ // Another id owned |obj_id|:
+ if (aria_owned_child_to_owner_mapping_.Contains(obj_id)) {
+ // Previous owner no longer relevant to this child.
+ // Also, remove |obj_id| from previous owner's owned child list:
+ AXID owner_id = aria_owned_child_to_owner_mapping_.Take(obj_id);
+ const Vector<AXID>& owners_owned_children =
+ aria_owner_to_children_mapping_.at(owner_id);
+ for (wtf_size_t index = 0; index < owners_owned_children.size(); index++) {
+ if (owners_owned_children[index] == obj_id) {
+ aria_owner_to_children_mapping_.at(owner_id).EraseAt(index);
+ break;
+ }
+ }
+ }
}
AXObject* AXRelationCache::ObjectFromAXID(AXID axid) const {
@@ -375,8 +466,8 @@ AXObject* AXRelationCache::Get(Node* node) {
return object_cache_->Get(node);
}
-AXObject* AXRelationCache::GetOrCreate(Node* node) {
- return object_cache_->GetOrCreate(node);
+AXObject* AXRelationCache::GetOrCreate(Node* node, const AXObject* owner) {
+ return object_cache_->GetOrCreate(node, const_cast<AXObject*>(owner));
}
void AXRelationCache::ChildrenChanged(AXObject* object) {
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
index 20a0fb8eb1f..0d9bb159121 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
@@ -26,11 +26,9 @@ class AXRelationCache {
// Safe to call at any time. Doesn't make any changes to the tree.
//
- // Scan the initial document.
- void Init();
-
// Returns true if the given object's position in the tree was due to
// aria-owns.
+ bool IsAriaOwned(AXID) const;
bool IsAriaOwned(const AXObject*) const;
// Returns the parent of the given object due to aria-owns.
@@ -47,7 +45,9 @@ class AXRelationCache {
// just changed, check to see if another object wants to be its parent due to
// aria-owns. If so, add it to a queue of ids to process later during
// ProcessUpdatesWithCleanLayout.
- void UpdateRelatedTree(Node*);
+ // |node| is not optional.
+ // |obj| is optional. If provided, it must match the AXObject for |node|.
+ void UpdateRelatedTree(Node* node, AXObject* obj);
// Remove given AXID from cache.
void RemoveAXID(AXID);
@@ -82,6 +82,9 @@ class AXRelationCache {
// specific time in the lifecycle.
void UpdateAriaOwnsWithCleanLayout(AXObject* owner);
+ static bool IsValidOwner(AXObject* owner);
+ static bool IsValidOwnedChild(AXObject* child);
+
private:
// Given an object that has explicitly set elements for aria-owns, update the
// internal state to reflect the new set of children owned by this object.
@@ -108,6 +111,10 @@ class AXRelationCache {
AXObject* owner,
HeapVector<Member<AXObject>>& validated_owned_children_result);
+ // Whether the document has been scanned for initial relationships
+ // first or not.
+ bool initialized_ = false;
+
WeakPersistent<AXObjectCacheImpl> object_cache_;
// Map from the AXID of the owner to the AXIDs of the children.
@@ -144,10 +151,14 @@ class AXRelationCache {
// Helpers that call back into object cache
AXObject* ObjectFromAXID(AXID) const;
- AXObject* GetOrCreate(Node*);
+ AXObject* GetOrCreate(Node*, const AXObject* owner);
AXObject* Get(Node*);
void ChildrenChanged(AXObject*);
+ // Do an initial scan of the document to find any relationships.
+ // We'll catch any subsequent ones when attributes change.
+ void DoInitialDocumentScan();
+
DISALLOW_COPY_AND_ASSIGN(AXRelationCache);
};
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 badb6d76e4b..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
@@ -28,7 +28,6 @@
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h"
#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -761,9 +760,6 @@ TEST_F(AccessibilitySelectionTest, FromCurrentSelectionInTextareaWithAffinity) {
TEST_F(AccessibilitySelectionTest,
FromCurrentSelectionInTextareaWithCollapsedSelectionAndAffinity) {
- // TODO(crbug.com/1140302): This test fails with LayoutNGTextControl.
- ScopedLayoutNGTextControlForTest scope(false);
-
SetBodyInnerHTML(R"HTML(
<textarea id="textarea"
rows="2" cols="15"
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 fd3eab74e45..229031887bb 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc
@@ -75,36 +75,6 @@ AccessibilityOrientation AXSlider::Orientation() const {
}
}
-void AXSlider::AddChildren() {
- DCHECK(!IsDetached());
- DCHECK(!have_children_);
- have_children_ = true;
-
- AXObjectCacheImpl& cache = AXObjectCache();
- AXObject* thumb = cache.GetOrCreate(ax::mojom::Role::kSliderThumb);
- DCHECK(thumb);
- thumb->SetParent(this);
-
- // Before actually adding the value indicator to the hierarchy,
- // allow the platform to make a final decision about it.
- if (!thumb->AccessibilityIsIncludedInTree()) {
- cache.Remove(thumb->AXObjectID());
- return;
- }
-
- children_.push_back(thumb);
-}
-
-AXObject* AXSlider::ElementAccessibilityHitTest(const IntPoint& point) const {
- if (HasChildren()) {
- DCHECK(children_.size() == 1);
- if (children_[0]->GetBoundsInFrameCoordinates().Contains(point))
- return children_[0].Get();
- }
-
- return AXObjectCache().GetOrCreate(layout_object_);
-}
-
bool AXSlider::OnNativeSetValueAction(const String& value) {
HTMLInputElement* input = GetInputElement();
@@ -131,27 +101,4 @@ HTMLInputElement* AXSlider::GetInputElement() const {
return To<HTMLInputElement>(layout_object_->GetNode());
}
-AXSliderThumb::AXSliderThumb(AXObjectCacheImpl& ax_object_cache)
- : AXMockObject(ax_object_cache) {}
-
-LayoutObject* AXSliderThumb::LayoutObjectForRelativeBounds() const {
- if (!parent_)
- return nullptr;
-
- LayoutObject* slider_layout_object = parent_->GetLayoutObject();
- if (!slider_layout_object)
- return nullptr;
- Element* thumb_element =
- To<Element>(slider_layout_object->GetNode())
- ->UserAgentShadowRoot()
- ->getElementById(shadow_element_names::kIdSliderThumb);
- DCHECK(thumb_element);
- return thumb_element->GetLayoutObject();
-}
-
-bool AXSliderThumb::ComputeAccessibilityIsIgnored(
- IgnoredReasons* ignored_reasons) const {
- return AccessibilityIsIgnoredByDefault(ignored_reasons);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h
index 1dd6000d39f..982bbbe9ba1 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h
@@ -45,36 +45,17 @@ class AXSlider : public AXLayoutObject {
private:
HTMLInputElement* GetInputElement() const;
- AXObject* ElementAccessibilityHitTest(const IntPoint&) const final;
ax::mojom::Role DetermineAccessibilityRole() final;
bool IsSlider() const final { return true; }
bool IsControl() const final { return true; }
- void AddChildren() final;
-
bool OnNativeSetValueAction(const String&) final;
AccessibilityOrientation Orientation() const final;
DISALLOW_COPY_AND_ASSIGN(AXSlider);
};
-class AXSliderThumb final : public AXMockObject {
- public:
- explicit AXSliderThumb(AXObjectCacheImpl&);
- ~AXSliderThumb() override = default;
-
- ax::mojom::Role RoleValue() const override {
- return ax::mojom::Role::kSliderThumb;
- }
-
- private:
- bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
- LayoutObject* LayoutObjectForRelativeBounds() const override;
-
- DISALLOW_COPY_AND_ASSIGN(AXSliderThumb);
-};
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_SLIDER_H_
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 1b159247de3..4fa047eea78 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,6 +5,7 @@
#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/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -34,274 +35,230 @@ void SetStringAttribute(ax::mojom::blink::StringAttribute attribute,
node_data->AddStringAttribute(attribute, value.Utf8());
}
-class ObjectAttributeSetter : public AXSparseAttributeSetter {
- public:
- ObjectAttributeSetter(AXObjectAttribute attribute) : attribute_(attribute) {}
-
- private:
- AXObjectAttribute attribute_;
-
- QualifiedName GetAttributeQualifiedName() {
- switch (attribute_) {
- case AXObjectAttribute::kAriaActiveDescendant:
- return html_names::kAriaActivedescendantAttr;
- case AXObjectAttribute::kAriaErrorMessage:
- return html_names::kAriaErrormessageAttr;
- default:
- NOTREACHED();
- }
- return g_null_name;
- }
-
- void Run(const AXObject& obj,
- AXSparseAttributeClient& attribute_map,
- const AtomicString& value) override {
- if (value.IsNull())
- return;
-
- Element* element = obj.GetElement();
- if (!element)
- return;
- const QualifiedName& q_name = GetAttributeQualifiedName();
- Element* target = element->GetElementAttribute(q_name);
- if (!target)
- return;
- AXObject* ax_target = obj.AXObjectCache().GetOrCreate(target);
- if (ax_target)
- attribute_map.AddObjectAttribute(attribute_, *ax_target);
- }
-};
+void SetObjectAttribute(ax::mojom::blink::IntAttribute attribute,
+ QualifiedName qualified_name,
+ AXObject* object,
+ ui::AXNodeData* node_data,
+ const AtomicString& value) {
+ Element* element = object->GetElement();
+ if (!element)
+ return;
-class ObjectVectorAttributeSetter : public AXSparseAttributeSetter {
- public:
- ObjectVectorAttributeSetter(AXObjectVectorAttribute attribute)
- : attribute_(attribute) {}
+ Element* target = element->GetElementAttribute(qualified_name);
- private:
- AXObjectVectorAttribute attribute_;
+ if (!target)
+ return;
- QualifiedName GetAttributeQualifiedName() {
- switch (attribute_) {
- case AXObjectVectorAttribute::kAriaControls:
- return html_names::kAriaControlsAttr;
- case AXObjectVectorAttribute::kAriaDetails:
- return html_names::kAriaDetailsAttr;
- case AXObjectVectorAttribute::kAriaFlowTo:
- return html_names::kAriaFlowtoAttr;
- default:
- NOTREACHED();
- }
- return g_null_name;
+ AXObject* ax_target = object->AXObjectCache().GetOrCreate(target);
+ if (!ax_target)
+ return;
+ if (attribute == ax::mojom::blink::IntAttribute::kActivedescendantId &&
+ !ax_target->IsVisible()) {
+ return;
}
- void Run(const AXObject& obj,
- AXSparseAttributeClient& attribute_map,
- const AtomicString& value) override {
- Element* element = obj.GetElement();
- if (!element)
- return;
+ node_data->AddIntAttribute(attribute, ax_target->AXObjectID());
+}
- base::Optional<HeapVector<Member<Element>>> attr_associated_elements =
- element->GetElementArrayAttribute(GetAttributeQualifiedName());
- if (!attr_associated_elements)
- return;
- HeapVector<Member<AXObject>>* objects =
- MakeGarbageCollected<HeapVector<Member<AXObject>>>();
- for (const auto& associated_element : attr_associated_elements.value()) {
- AXObject* ax_element =
- obj.AXObjectCache().GetOrCreate(associated_element);
- if (!ax_element)
- continue;
- if (AXObject* parent = ax_element->ParentObject())
- parent->UpdateChildrenIfNecessary();
- if (!ax_element->AccessibilityIsIgnored())
- objects->push_back(ax_element);
- }
- attribute_map.AddObjectVectorAttribute(attribute_, objects);
+void SetIntListAttribute(ax::mojom::blink::IntListAttribute attribute,
+ QualifiedName qualified_name,
+ AXObject* object,
+ ui::AXNodeData* node_data,
+ const AtomicString& value) {
+ Element* element = object->GetElement();
+ if (!element)
+ return;
+ base::Optional<HeapVector<Member<Element>>> attr_associated_elements =
+ element->GetElementArrayAttribute(qualified_name);
+ if (!attr_associated_elements)
+ return;
+ std::vector<int32_t> ax_ids;
+
+ for (const auto& associated_element : attr_associated_elements.value()) {
+ AXObject* ax_element =
+ object->AXObjectCache().GetOrCreate(associated_element);
+ if (!ax_element)
+ continue;
+ if (!ax_element->AccessibilityIsIgnored())
+ ax_ids.push_back(ax_element->AXObjectID());
}
-};
-
-AXSparseAttributeSetterMap& GetSparseAttributeSetterMap() {
- // Use a map from attribute name to properties of that attribute.
- // That way we only need to iterate over the list of attributes once,
- // rather than calling getAttribute() once for each possible obscure
- // accessibility attribute.
- DEFINE_STATIC_LOCAL(AXSparseAttributeSetterMap,
- ax_sparse_attribute_setter_map, ());
- if (ax_sparse_attribute_setter_map.IsEmpty()) {
- ax_sparse_attribute_setter_map.Set(
- html_names::kAriaActivedescendantAttr,
- new ObjectAttributeSetter(AXObjectAttribute::kAriaActiveDescendant));
- ax_sparse_attribute_setter_map.Set(
- html_names::kAriaControlsAttr,
- new ObjectVectorAttributeSetter(
- AXObjectVectorAttribute::kAriaControls));
- ax_sparse_attribute_setter_map.Set(
- html_names::kAriaFlowtoAttr,
- new ObjectVectorAttributeSetter(AXObjectVectorAttribute::kAriaFlowTo));
- ax_sparse_attribute_setter_map.Set(
- html_names::kAriaDetailsAttr,
- new ObjectVectorAttributeSetter(AXObjectVectorAttribute::kAriaDetails));
- ax_sparse_attribute_setter_map.Set(
- html_names::kAriaErrormessageAttr,
- new ObjectAttributeSetter(AXObjectAttribute::kAriaErrorMessage));
- }
- return ax_sparse_attribute_setter_map;
+ node_data->AddIntListAttribute(attribute, ax_ids);
}
-// TODO(meredithl): move the rest of the sparse attributes to this map.
-TempSetterMap& GetTempSetterMap() {
- DEFINE_STATIC_LOCAL(TempSetterMap, temp_setter_map, ());
- if (temp_setter_map.IsEmpty()) {
- temp_setter_map.Set(
+AXSparseAttributeSetterMap& GetAXSparseAttributeSetterMap() {
+ DEFINE_STATIC_LOCAL(AXSparseAttributeSetterMap, ax_sparse_setter_map, ());
+ if (ax_sparse_setter_map.IsEmpty()) {
+ ax_sparse_setter_map.Set(
+ html_names::kAriaActivedescendantAttr,
+ WTF::BindRepeating(&SetObjectAttribute,
+ ax::mojom::blink::IntAttribute::kActivedescendantId,
+ html_names::kAriaActivedescendantAttr));
+ ax_sparse_setter_map.Set(
html_names::kAriaBusyAttr,
WTF::BindRepeating(&SetBoolAttribute,
ax::mojom::blink::BoolAttribute::kBusy));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaColcountAttr,
WTF::BindRepeating(&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaColumnCount));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaColindexAttr,
WTF::BindRepeating(
&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaCellColumnIndex));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaColspanAttr,
WTF::BindRepeating(
&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaCellColumnSpan));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
+ html_names::kAriaControlsAttr,
+ WTF::BindRepeating(&SetIntListAttribute,
+ ax::mojom::blink::IntListAttribute::kControlsIds,
+ html_names::kAriaControlsAttr));
+ ax_sparse_setter_map.Set(
+ html_names::kAriaErrormessageAttr,
+ WTF::BindRepeating(&SetObjectAttribute,
+ ax::mojom::blink::IntAttribute::kErrormessageId,
+ html_names::kAriaErrormessageAttr));
+ ax_sparse_setter_map.Set(
+ html_names::kAriaDetailsAttr,
+ WTF::BindRepeating(&SetIntListAttribute,
+ ax::mojom::blink::IntListAttribute::kDetailsIds,
+ html_names::kAriaDetailsAttr));
+ ax_sparse_setter_map.Set(
+ html_names::kAriaFlowtoAttr,
+ WTF::BindRepeating(&SetIntListAttribute,
+ ax::mojom::blink::IntListAttribute::kFlowtoIds,
+ html_names::kAriaFlowtoAttr));
+ ax_sparse_setter_map.Set(
html_names::kAriaRowcountAttr,
WTF::BindRepeating(&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaRowCount));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaRowindexAttr,
WTF::BindRepeating(&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaCellRowIndex));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaRowspanAttr,
WTF::BindRepeating(&SetIntAttribute,
ax::mojom::blink::IntAttribute::kAriaCellRowSpan));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
html_names::kAriaRoledescriptionAttr,
WTF::BindRepeating(
&SetStringAttribute,
ax::mojom::blink::StringAttribute::kRoleDescription));
- temp_setter_map.Set(
+ ax_sparse_setter_map.Set(
+ html_names::kAriaTouchpassthroughAttr,
+ WTF::BindRepeating(&SetBoolAttribute,
+ ax::mojom::blink::BoolAttribute::kTouchPassthrough));
+ if (RuntimeEnabledFeatures::AccessibilityAriaVirtualContentEnabled()) {
+ ax_sparse_setter_map.Set(
+ html_names::kAriaVirtualcontentAttr,
+ WTF::BindRepeating(
+ &SetStringAttribute,
+ ax::mojom::blink::StringAttribute::kVirtualContent));
+ }
+ ax_sparse_setter_map.Set(
html_names::kAriaKeyshortcutsAttr,
WTF::BindRepeating(&SetStringAttribute,
ax::mojom::blink::StringAttribute::kKeyShortcuts));
}
- return temp_setter_map;
+ return ax_sparse_setter_map;
}
-void AXSparseAttributeAOMPropertyClient::AddStringProperty(
- AOMStringProperty property,
- const String& value) {}
+void AXNodeDataAOMPropertyClient::AddStringProperty(AOMStringProperty property,
+ const String& value) {
+ ax::mojom::blink::StringAttribute attribute;
+ switch (property) {
+ case AOMStringProperty::kKeyShortcuts:
+ attribute = ax::mojom::blink::StringAttribute::kKeyShortcuts;
+ break;
+ case AOMStringProperty::kRoleDescription:
+ attribute = ax::mojom::blink::StringAttribute::kRoleDescription;
+ break;
+ case AOMStringProperty::kVirtualContent:
+ if (!RuntimeEnabledFeatures::AccessibilityAriaVirtualContentEnabled())
+ return;
+ attribute = ax::mojom::blink::StringAttribute::kVirtualContent;
+ break;
+ default:
+ return;
+ }
+ node_data_.AddStringAttribute(attribute, value.Utf8());
+}
-void AXSparseAttributeAOMPropertyClient::AddBooleanProperty(
+void AXNodeDataAOMPropertyClient::AddBooleanProperty(
AOMBooleanProperty property,
- bool value) {}
+ bool value) {
+ ax::mojom::blink::BoolAttribute attribute;
+ switch (property) {
+ case AOMBooleanProperty::kBusy:
+ attribute = ax::mojom::blink::BoolAttribute::kBusy;
+ break;
+ default:
+ return;
+ }
+ node_data_.AddBoolAttribute(attribute, value);
+}
-void AXSparseAttributeAOMPropertyClient::AddFloatProperty(
- AOMFloatProperty property,
- float value) {}
+void AXNodeDataAOMPropertyClient::AddFloatProperty(AOMFloatProperty property,
+ float value) {}
-void AXSparseAttributeAOMPropertyClient::AddRelationProperty(
+void AXNodeDataAOMPropertyClient::AddRelationProperty(
AOMRelationProperty property,
const AccessibleNode& value) {
- AXObjectAttribute attribute;
+ ax::mojom::blink::IntAttribute attribute;
switch (property) {
case AOMRelationProperty::kActiveDescendant:
- attribute = AXObjectAttribute::kAriaActiveDescendant;
+ attribute = ax::mojom::blink::IntAttribute::kActivedescendantId;
break;
case AOMRelationProperty::kErrorMessage:
- attribute = AXObjectAttribute::kAriaErrorMessage;
+ attribute = ax::mojom::blink::IntAttribute::kErrormessageId;
break;
default:
return;
}
- Element* target_element = value.element();
- AXObject* target_obj = ax_object_cache_->GetOrCreate(target_element);
- if (target_element)
- sparse_attribute_client_.AddObjectAttribute(attribute, *target_obj);
+ Element* target = value.element();
+ AXObject* ax_target = ax_object_cache_->GetOrCreate(target);
+ if (!ax_target)
+ return;
+
+ node_data_.AddIntAttribute(attribute, ax_target->AXObjectID());
}
-void AXSparseAttributeAOMPropertyClient::AddRelationListProperty(
+void AXNodeDataAOMPropertyClient::AddRelationListProperty(
AOMRelationListProperty property,
const AccessibleNodeList& relations) {
- AXObjectVectorAttribute attribute;
+ ax::mojom::blink::IntListAttribute attribute;
switch (property) {
case AOMRelationListProperty::kControls:
- attribute = AXObjectVectorAttribute::kAriaControls;
+ attribute = ax::mojom::blink::IntListAttribute::kControlsIds;
break;
case AOMRelationListProperty::kDetails:
- attribute = AXObjectVectorAttribute::kAriaDetails;
+ attribute = ax::mojom::blink::IntListAttribute::kDetailsIds;
break;
case AOMRelationListProperty::kFlowTo:
- attribute = AXObjectVectorAttribute::kAriaFlowTo;
+ attribute = ax::mojom::blink::IntListAttribute::kFlowtoIds;
break;
default:
return;
}
- HeapVector<Member<AXObject>>* objects =
- MakeGarbageCollected<HeapVector<Member<AXObject>>>();
+ std::vector<int32_t> ax_ids;
for (unsigned i = 0; i < relations.length(); ++i) {
AccessibleNode* accessible_node = relations.item(i);
if (accessible_node) {
Element* element = accessible_node->element();
AXObject* ax_element = ax_object_cache_->GetOrCreate(element);
if (ax_element && !ax_element->AccessibilityIsIgnored())
- objects->push_back(ax_element);
+ ax_ids.push_back(ax_element->AXObjectID());
}
}
- sparse_attribute_client_.AddObjectVectorAttribute(attribute, objects);
-}
-
-void AXNodeDataAOMPropertyClient::AddStringProperty(AOMStringProperty property,
- const String& value) {
- ax::mojom::blink::StringAttribute attribute;
- switch (property) {
- case AOMStringProperty::kKeyShortcuts:
- attribute = ax::mojom::blink::StringAttribute::kKeyShortcuts;
- break;
- case AOMStringProperty::kRoleDescription:
- attribute = ax::mojom::blink::StringAttribute::kRoleDescription;
- break;
- default:
- return;
- }
- node_data_.AddStringAttribute(attribute, value.Utf8());
-}
-
-void AXNodeDataAOMPropertyClient::AddBooleanProperty(
- AOMBooleanProperty property,
- bool value) {
- ax::mojom::blink::BoolAttribute attribute;
- switch (property) {
- case AOMBooleanProperty::kBusy:
- attribute = ax::mojom::blink::BoolAttribute::kBusy;
- break;
- default:
- return;
- }
- node_data_.AddBoolAttribute(attribute, value);
+ node_data_.AddIntListAttribute(attribute, ax_ids);
}
-void AXNodeDataAOMPropertyClient::AddFloatProperty(AOMFloatProperty property,
- float value) {}
-
-void AXNodeDataAOMPropertyClient::AddRelationProperty(
- AOMRelationProperty property,
- const AccessibleNode& value) {}
-
-void AXNodeDataAOMPropertyClient::AddRelationListProperty(
- AOMRelationListProperty property,
- const AccessibleNodeList& relations) {}
-
} // namespace blink
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 50150c1dd66..cdc0b9f566f 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
@@ -13,63 +13,20 @@
namespace blink {
-class AXSparseAttributeSetter {
- USING_FAST_MALLOC(AXSparseAttributeSetter);
-
- public:
- virtual void Run(const AXObject&,
- AXSparseAttributeClient&,
- const AtomicString& value) = 0;
-};
-
-using AXSparseAttributeSetterMap =
- HashMap<QualifiedName, AXSparseAttributeSetter*>;
-
-// A map from attribute name to a AXSparseAttributeSetter that
-// calls AXSparseAttributeClient when that attribute's value
-// changes.
+// A map from attribute name to a callback that sets the |value| for that
+// attribute on an AXNodeData.
//
// 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(AXObject* ax_object,
ui::AXNodeData* node_data,
const AtomicString& value)>;
-using TempSetterMap = HashMap<QualifiedName, AXSparseSetterFunc>;
-
-TempSetterMap& GetTempSetterMap();
+using AXSparseAttributeSetterMap = HashMap<QualifiedName, AXSparseSetterFunc>;
-// An implementation of AOMPropertyClient that calls
-// AXSparseAttributeClient for an AOM property.
-class AXSparseAttributeAOMPropertyClient : public AOMPropertyClient {
- public:
- AXSparseAttributeAOMPropertyClient(
- AXObjectCacheImpl& ax_object_cache,
- AXSparseAttributeClient& sparse_attribute_client)
- : ax_object_cache_(ax_object_cache),
- sparse_attribute_client_(sparse_attribute_client) {}
-
- void AddStringProperty(AOMStringProperty, const String& value) override;
- void AddBooleanProperty(AOMBooleanProperty, bool value) override;
- void AddFloatProperty(AOMFloatProperty, float value) override;
- void AddRelationProperty(AOMRelationProperty,
- const AccessibleNode& value) override;
- void AddRelationListProperty(AOMRelationListProperty,
- const AccessibleNodeList& relations) override;
-
- private:
- Persistent<AXObjectCacheImpl> ax_object_cache_;
- AXSparseAttributeClient& sparse_attribute_client_;
-};
+AXSparseAttributeSetterMap& GetAXSparseAttributeSetterMap();
class AXNodeDataAOMPropertyClient : public AOMPropertyClient {
public:
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc
deleted file mode 100644
index 6bee5789063..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/modules/accessibility/ax_svg_root.h"
-
-#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
-
-namespace blink {
-
-AXSVGRoot::AXSVGRoot(LayoutObject* layout_object,
- AXObjectCacheImpl& ax_object_cache)
- : AXLayoutObject(layout_object, ax_object_cache) {}
-
-AXSVGRoot::~AXSVGRoot() = default;
-
-void AXSVGRoot::SetParent(AXObject* parent) {
- // Only update the parent to another objcet if it wasn't already set to
- // something. Multiple elements in an HTML document can reference
- // the same remote SVG document, and in that case the parent should just
- // stay with the first one.
- if (!parent_ || !parent)
- parent_ = parent;
-}
-
-AXObject* AXSVGRoot::ComputeParent() const {
- DCHECK(!IsDetached());
- // If a parent was set because this is a remote SVG resource, use that
- // but otherwise, we should rely on the standard layout tree for the parent.
- if (parent_)
- return parent_;
-
- return AXLayoutObject::ComputeParent();
-}
-
-// SVG AAM 1.0 S8.2: the default role for an SVG root is "group".
-ax::mojom::Role AXSVGRoot::DetermineAccessibilityRole() {
- ax::mojom::Role role = AXLayoutObject::DetermineAccessibilityRole();
- if (role == ax::mojom::Role::kUnknown)
- role = ax::mojom::Role::kGroup;
- return role;
-}
-
-// SVG elements are only ignored if they are a descendant of a leaf or when a
-// generic element would also be ignored.
-bool AXSVGRoot::ComputeAccessibilityIsIgnored(IgnoredReasons* reasons) const {
- if (IsDescendantOfLeafNode())
- return AXLayoutObject::ComputeAccessibilityIsIgnored(reasons);
-
- return AccessibilityIsIgnoredByDefault(reasons);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h
deleted file mode 100644
index 32ce72fe675..00000000000
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_SVG_ROOT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_SVG_ROOT_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h"
-
-namespace blink {
-
-class AXObjectCacheImpl;
-
-class AXSVGRoot final : public AXLayoutObject {
- public:
- AXSVGRoot(LayoutObject*, AXObjectCacheImpl&);
- ~AXSVGRoot() override;
-
- void SetParent(AXObject*) override;
-
- ax::mojom::Role DetermineAccessibilityRole() override;
- bool ComputeAccessibilityIsIgnored(IgnoredReasons*) const override;
-
- private:
- AXObject* ComputeParent() const override;
- bool IsAXSVGRoot() const override { return true; }
-
- DISALLOW_COPY_AND_ASSIGN(AXSVGRoot);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_SVG_ROOT_H_
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
index e1b718930d1..15eed4a4eb6 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
@@ -18,10 +18,6 @@ AXValidationMessage::AXValidationMessage(AXObjectCacheImpl& ax_object_cache)
AXValidationMessage::~AXValidationMessage() {}
-AXObject* AXValidationMessage::ComputeParent() const {
- return AXObjectCache().Root();
-}
-
bool AXValidationMessage::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
return false;
@@ -76,8 +72,8 @@ const AtomicString& AXValidationMessage::LiveRegionRelevant() const {
return live_region_relevant_additions;
}
-ax::mojom::Role AXValidationMessage::RoleValue() const {
- return ax::mojom::Role::kAlert;
+ax::mojom::blink::Role AXValidationMessage::DetermineAccessibilityRole() {
+ return ax::mojom::blink::Role::kAlert;
}
ListedElement* AXValidationMessage::RelatedFormControlIfVisible() const {
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
index fd9abe4e67f..1e3c762210f 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
@@ -24,9 +24,10 @@ class AXValidationMessage final : public AXMockObject {
private:
// AXObject:
+ // Always a leaf.
bool CanHaveChildren() const override { return false; }
+ void AddChildren() override {}
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
- AXObject* ComputeParent() const override;
void GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
@@ -42,7 +43,7 @@ class AXValidationMessage final : public AXMockObject {
ax::mojom::NameFrom&,
AXRelatedObjectVector*,
NameSources*) const override;
- ax::mojom::Role RoleValue() const override;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override;
ListedElement* RelatedFormControlIfVisible() const;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
index b6f83fe58ed..792336befdc 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
@@ -21,22 +21,39 @@ void AXVirtualObject::Detach() {
accessible_node_ = nullptr;
}
+Document* AXVirtualObject::GetDocument() const {
+ return GetAccessibleNode() ? GetAccessibleNode()->GetDocument() : nullptr;
+}
+
bool AXVirtualObject::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignoredReasons) const {
return AccessibilityIsIgnoredByDefault(ignoredReasons);
}
void AXVirtualObject::AddChildren() {
+#if DCHECK_IS_ON()
+ DCHECK(!IsDetached());
+ DCHECK(!is_adding_children_) << " Reentering method on " << GetNode();
+ base::AutoReset<bool> reentrancy_protector(&is_adding_children_, true);
+ DCHECK_EQ(children_.size(), 0U)
+ << "Parent still has " << children_.size() << " children before adding:"
+ << "\nParent is " << ToString(true, true) << "\nFirst child is "
+ << children_[0]->ToString(true, true);
+#endif
if (!accessible_node_)
return;
+ DCHECK(children_dirty_);
+ children_dirty_ = false;
+
for (const auto& child : accessible_node_->GetChildren()) {
- AXObject* ax_child = AXObjectCache().GetOrCreate(child);
+ AXObject* ax_child = AXObjectCache().GetOrCreate(child, this);
if (!ax_child)
continue;
+ DCHECK(!ax_child->IsDetached());
+ DCHECK(ax_child->AccessibilityIsIncludedInTree());
children_.push_back(ax_child);
- ax_child->SetParent(this);
}
}
@@ -82,6 +99,16 @@ String AXVirtualObject::TextAlternative(bool recursive,
&found_text_alternative);
}
+ax::mojom::blink::Role AXVirtualObject::DetermineAccessibilityRole() {
+ aria_role_ = DetermineAriaRoleAttribute();
+
+ // If no role was assigned, fall back to role="generic".
+ if (aria_role_ == ax::mojom::blink::Role::kUnknown)
+ aria_role_ = ax::mojom::blink::Role::kGenericContainer;
+
+ return aria_role_;
+}
+
void AXVirtualObject::Trace(Visitor* visitor) const {
visitor->Trace(accessible_node_);
AXObject::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
index 4049d30dd26..735d5c1b5bb 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h
@@ -21,7 +21,6 @@ class MODULES_EXPORT AXVirtualObject : public AXObject {
// AXObject overrides.
void Detach() override;
- AXObject* ComputeParent() const override { return parent_; }
bool IsVirtualObject() const override { return true; }
void AddChildren() override;
void ChildrenChanged() override;
@@ -36,6 +35,8 @@ class MODULES_EXPORT AXVirtualObject : public AXObject {
ax::mojom::NameFrom&,
AXRelatedObjectVector*,
NameSources*) const override;
+ Document* GetDocument() const override;
+ ax::mojom::blink::Role DetermineAccessibilityRole() override;
private:
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const 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 1dcf5aed84e..30770913131 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
@@ -378,59 +378,6 @@ std::unique_ptr<AXProperty> CreateRelatedNodeListProperty(
return CreateProperty(key, std::move(node_list_value));
}
-class SparseAttributeAXPropertyAdapter
- : public GarbageCollected<SparseAttributeAXPropertyAdapter>,
- public AXSparseAttributeClient {
- public:
- SparseAttributeAXPropertyAdapter(AXObject& ax_object,
- protocol::Array<AXProperty>& properties)
- : ax_object_(&ax_object), properties_(properties) {}
-
- void Trace(Visitor* visitor) const { visitor->Trace(ax_object_); }
-
- private:
- Member<AXObject> ax_object_;
- protocol::Array<AXProperty>& properties_;
-
- void AddObjectAttribute(AXObjectAttribute attribute,
- AXObject& object) override {
- switch (attribute) {
- case AXObjectAttribute::kAriaActiveDescendant:
- properties_.emplace_back(
- CreateProperty(AXPropertyNameEnum::Activedescendant,
- CreateRelatedNodeListValue(object)));
- break;
- case AXObjectAttribute::kAriaErrorMessage:
- properties_.emplace_back(
- CreateProperty(AXPropertyNameEnum::Errormessage,
- CreateRelatedNodeListValue(object)));
- break;
- }
- }
-
- void AddObjectVectorAttribute(
- AXObjectVectorAttribute attribute,
- HeapVector<Member<AXObject>>* objects) override {
- switch (attribute) {
- case AXObjectVectorAttribute::kAriaControls:
- properties_.emplace_back(CreateRelatedNodeListProperty(
- AXPropertyNameEnum::Controls, *objects,
- html_names::kAriaControlsAttr, *ax_object_));
- break;
- case AXObjectVectorAttribute::kAriaDetails:
- properties_.emplace_back(CreateRelatedNodeListProperty(
- AXPropertyNameEnum::Details, *objects, html_names::kAriaDetailsAttr,
- *ax_object_));
- break;
- case AXObjectVectorAttribute::kAriaFlowTo:
- properties_.emplace_back(CreateRelatedNodeListProperty(
- AXPropertyNameEnum::Flowto, *objects, html_names::kAriaFlowtoAttr,
- *ax_object_));
- break;
- }
- }
-};
-
void FillRelationships(AXObject& ax_object,
protocol::Array<AXProperty>& properties) {
AXObject::AXObjectVector results;
@@ -451,11 +398,19 @@ void FillRelationships(AXObject& ax_object,
results.clear();
}
+void GetObjectsFromAXIDs(const AXObjectCacheImpl& cache,
+ const std::vector<int32_t>& ax_ids,
+ AXObject::AXObjectVector* ax_objects) {
+ for (const auto& ax_id : ax_ids) {
+ AXObject* ax_object = cache.ObjectFromAXID(ax_id);
+ if (!ax_object)
+ continue;
+ ax_objects->push_back(ax_object);
+ }
+}
+
void FillSparseAttributes(AXObject& ax_object,
protocol::Array<AXProperty>& properties) {
- SparseAttributeAXPropertyAdapter adapter(ax_object, properties);
- ax_object.GetSparseAXAttributes(adapter);
-
ui::AXNodeData node_data;
ax_object.Serialize(&node_data, ui::kAXModeComplete);
@@ -486,6 +441,58 @@ void FillSparseAttributes(AXObject& ax_object,
CreateValue(WTF::String(role_description.c_str()),
AXValueTypeEnum::String)));
}
+
+ if (node_data.HasIntAttribute(
+ ax::mojom::blink::IntAttribute::kActivedescendantId)) {
+ AXObject* target =
+ ax_object.AXObjectCache().ObjectFromAXID(node_data.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kActivedescendantId));
+ properties.emplace_back(
+ CreateProperty(AXPropertyNameEnum::Activedescendant,
+ CreateRelatedNodeListValue(*target)));
+ }
+
+ if (node_data.HasIntAttribute(
+ ax::mojom::blink::IntAttribute::kErrormessageId)) {
+ AXObject* target =
+ ax_object.AXObjectCache().ObjectFromAXID(node_data.GetIntAttribute(
+ ax::mojom::blink::IntAttribute::kErrormessageId));
+ properties.emplace_back(CreateProperty(
+ AXPropertyNameEnum::Errormessage, CreateRelatedNodeListValue(*target)));
+ }
+
+ if (node_data.HasIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kControlsIds)) {
+ const auto ax_ids = node_data.GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kControlsIds);
+ AXObject::AXObjectVector ax_objects;
+ GetObjectsFromAXIDs(ax_object.AXObjectCache(), ax_ids, &ax_objects);
+ properties.emplace_back(CreateRelatedNodeListProperty(
+ AXPropertyNameEnum::Controls, ax_objects, html_names::kAriaControlsAttr,
+ ax_object));
+ }
+
+ if (node_data.HasIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kDetailsIds)) {
+ const auto ax_ids = node_data.GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kDetailsIds);
+ AXObject::AXObjectVector ax_objects;
+ GetObjectsFromAXIDs(ax_object.AXObjectCache(), ax_ids, &ax_objects);
+ properties.emplace_back(
+ CreateRelatedNodeListProperty(AXPropertyNameEnum::Details, ax_objects,
+ html_names::kAriaDetailsAttr, ax_object));
+ }
+
+ if (node_data.HasIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kFlowtoIds)) {
+ const auto ax_ids = node_data.GetIntListAttribute(
+ ax::mojom::blink::IntListAttribute::kFlowtoIds);
+ AXObject::AXObjectVector ax_objects;
+ GetObjectsFromAXIDs(ax_object.AXObjectCache(), ax_ids, &ax_objects);
+ properties.emplace_back(
+ CreateRelatedNodeListProperty(AXPropertyNameEnum::Flowto, ax_objects,
+ html_names::kAriaFlowtoAttr, ax_object));
+ }
return;
}
@@ -686,8 +693,8 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject(
FillWidgetProperties(ax_object, *(properties.get()));
FillWidgetStates(ax_object, *(properties.get()));
FillRelationships(ax_object, *(properties.get()));
+ FillSparseAttributes(ax_object, *(properties.get()));
- FillSparseAttributes(ax_object, *properties);
AXObject::NameSources name_sources;
String computed_name = ax_object.GetName(&name_sources);
if (!name_sources.IsEmpty()) {
@@ -719,35 +726,98 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject(
}
Response InspectorAccessibilityAgent::getFullAXTree(
+ protocol::Maybe<int> max_depth,
std::unique_ptr<protocol::Array<AXNode>>* nodes) {
Document* document = inspected_frames_->Root()->GetDocument();
if (!document)
return Response::ServerError("No document.");
if (document->View()->NeedsLayout() || document->NeedsLayoutTreeUpdate())
document->UpdateStyleAndLayout(DocumentUpdateReason::kInspector);
- *nodes = std::make_unique<protocol::Array<protocol::Accessibility::AXNode>>();
+
+ *nodes = WalkAXNodesToDepth(document, max_depth.fromMaybe(-1));
+
+ return Response::Success();
+}
+
+std::unique_ptr<protocol::Array<AXNode>>
+InspectorAccessibilityAgent::WalkAXNodesToDepth(Document* document,
+ int max_depth) {
+ std::unique_ptr<protocol::Array<AXNode>> nodes =
+ std::make_unique<protocol::Array<protocol::Accessibility::AXNode>>();
+
AXContext ax_context(*document);
auto& cache = To<AXObjectCacheImpl>(ax_context.GetAXObjectCache());
- Deque<AXID> ids;
- ids.emplace_back(cache.Root()->AXObjectID());
- while (!ids.empty()) {
- AXID ax_id = ids.front();
- ids.pop_front();
- AXObject* ax_object = cache.ObjectFromAXID(ax_id);
+
+ Deque<std::pair<AXID, int>> id_depths;
+ id_depths.emplace_back(cache.Root()->AXObjectID(), 0);
+
+ while (!id_depths.empty()) {
+ std::pair<AXID, int> id_depth = id_depths.front();
+ id_depths.pop_front();
+ AXObject* ax_object = cache.ObjectFromAXID(id_depth.first);
std::unique_ptr<AXNode> node =
- BuildProtocolAXObject(*ax_object, nullptr, false, *nodes, cache);
+ BuildProtocolAXObject(*ax_object, nullptr, false, nodes, cache);
auto child_ids = std::make_unique<protocol::Array<AXNodeId>>();
- const AXObject::AXObjectVector& children =
- ax_object->ChildrenIncludingIgnored();
- for (unsigned i = 0; i < children.size(); i++) {
- AXObject& child_ax_object = *children[i].Get();
- child_ids->emplace_back(String::Number(child_ax_object.AXObjectID()));
- ids.emplace_back(child_ax_object.AXObjectID());
+ const AXObject::AXObjectVector& children = ax_object->UnignoredChildren();
+
+ for (auto& child_ax_object : children) {
+ child_ids->emplace_back(String::Number(child_ax_object->AXObjectID()));
+
+ int depth = id_depth.second;
+ if (max_depth == -1 || depth < max_depth)
+ id_depths.emplace_back(child_ax_object->AXObjectID(), depth + 1);
}
node->setChildIds(std::move(child_ids));
- (*nodes)->emplace_back(std::move(node));
+ nodes->emplace_back(std::move(node));
}
+
+ return nodes;
+}
+
+protocol::Response InspectorAccessibilityAgent::getChildAXNodes(
+ const String& in_id,
+ std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*
+ out_nodes) {
+ if (!enabled_.Get())
+ return Response::ServerError("Accessibility has not been enabled.");
+
+ // FIXME(aboxhall): specify a document to this and getRootAXNode()
+ Document* document = inspected_frames_->Root()->GetDocument();
+ if (!document)
+ return Response::ServerError("No document.");
+
+ if (document->View()->NeedsLayout() || document->NeedsLayoutTreeUpdate())
+ document->UpdateStyleAndLayout(DocumentUpdateReason::kInspector);
+
+ // Since we called enable(), this should exist.
+ AXObjectCacheImpl* cache =
+ To<AXObjectCacheImpl>(document->ExistingAXObjectCache());
+ if (!cache)
+ return Response::ServerError("No AXObjectCache.");
+
+ AXID ax_id = in_id.ToUInt();
+ AXObject* ax_object = cache->ObjectFromAXID(ax_id);
+
+ if (!ax_object)
+ return Response::InvalidParams("Invalid ID");
+
+ *out_nodes =
+ std::make_unique<protocol::Array<protocol::Accessibility::AXNode>>();
+
+ const AXObject::AXObjectVector& children = ax_object->UnignoredChildren();
+ for (auto& child_ax_object : children) {
+ std::unique_ptr<AXNode> child_node = BuildProtocolAXObject(
+ *child_ax_object, nullptr, false, *out_nodes, *cache);
+ auto grandchild_ids = std::make_unique<protocol::Array<AXNodeId>>();
+ const AXObject::AXObjectVector& grandchildren =
+ child_ax_object->UnignoredChildren();
+ for (AXObject* grandchild : grandchildren)
+ grandchild_ids->emplace_back(String::Number(grandchild->AXObjectID()));
+ child_node->setChildIds(std::move(grandchild_ids));
+ (*out_nodes)->emplace_back(std::move(child_node));
+ }
+
return Response::Success();
}
@@ -822,8 +892,7 @@ void InspectorAccessibilityAgent::AddChildren(
return;
}
- const AXObject::AXObjectVector& children =
- ax_object.ChildrenIncludingIgnored();
+ const AXObject::AXObjectVector& children = ax_object.UnignoredChildren();
for (unsigned i = 0; i < children.size(); i++) {
AXObject& child_ax_object = *children[i].Get();
child_ids->emplace_back(String::Number(child_ax_object.AXObjectID()));
@@ -893,8 +962,7 @@ Response InspectorAccessibilityAgent::queryAXTree(
while (!reachable.IsEmpty()) {
AXObject* ax_object = reachable.back();
reachable.pop_back();
- const AXObject::AXObjectVector& children =
- ax_object->ChildrenIncludingIgnored();
+ const AXObject::AXObjectVector& children = ax_object->UnignoredChildren();
reachable.AppendRange(children.rbegin(), children.rend());
// if querying by name: skip if name of current object does not match.
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 ab973dad456..cce276c7f8d 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
@@ -45,8 +45,13 @@ class MODULES_EXPORT InspectorAccessibilityAgent
std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*)
override;
protocol::Response getFullAXTree(
+ protocol::Maybe<int> max_depth,
std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*)
override;
+ protocol::Response getChildAXNodes(
+ const String& in_id,
+ std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*
+ out_nodes) override;
protocol::Response queryAXTree(
protocol::Maybe<int> dom_node_id,
protocol::Maybe<int> backend_node_id,
@@ -60,6 +65,10 @@ class MODULES_EXPORT InspectorAccessibilityAgent
// Unconditionally enables the agent, even if |enabled_.Get()==true|.
// For idempotence, call enable().
void EnableAndReset();
+ std::unique_ptr<protocol::Array<AXNode>> WalkAllAXNodes(Document* document);
+ std::unique_ptr<protocol::Array<AXNode>> WalkAXNodesToDepth(
+ Document* document,
+ int max_depth);
std::unique_ptr<AXNode> BuildObjectForIgnoredNode(
Node* dom_node,
AXObject*,
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc b/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
index 87c63efce32..5654a3fe566 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
@@ -200,6 +200,8 @@ String NativeSourceType(AXTextFromNativeHTML native_source) {
return SourceType::Labelfor;
case kAXTextFromNativeHTMLLabelWrapped:
return SourceType::Labelwrapped;
+ case kAXTextFromNativeHTMLRubyAnnotation:
+ return SourceType::Rubyannotation;
case kAXTextFromNativeHTMLTableCaption:
return SourceType::Tablecaption;
case kAXTextFromNativeHTMLLegend:
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 941c2bb7bb9..bf1f9c1784d 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
@@ -312,7 +312,11 @@ class AXSelectionDeserializer final {
}
void HandleObject(const AXObject& object) {
- for (const AXObject* child : object.ChildrenIncludingIgnored()) {
+ // Make a copy of the children, because they may be cleared when a sibling
+ // is invalidated and calls SetNeedsToUpdateChildren() on the parent.
+ const auto children = object.ChildrenIncludingIgnored();
+
+ for (const AXObject* child : children) {
DCHECK(child);
FindSelectionMarkers(*child);
}
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 a272709c2c9..099e53b6869 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
@@ -5,8 +5,7 @@ AXSelection from AX text position in "StaticText": "Some text.", 0 to AX object
++<GenericContainer>
++++<GenericContainer>
++++++<Main>
-++++++++<Presentational>
-^++++++++++<StaticText: ^Some text.>
+^++++++++<StaticText: ^Some text.>
++++++++<GenericContainer>
|++++++++<Paragraph>
++++++++<Paragraph>
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 d37521e6944..ff8604f721a 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
@@ -5,26 +5,29 @@ AXSelection from AX text position in "StaticText": "Sum", 0 to AX text position
++<GenericContainer>
++++<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>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<ColumnHeader: Sum>
+^++++++++++++++<StaticText: ^Sum>
+++++++++++++<ColumnHeader: Subtraction>
+++++++++++++++<StaticText: Subtraction|>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<Cell: 10>
+++++++++++++++<StaticText: 10>
+++++++++++++<Cell: 7>
+++++++++++++++<StaticText: 7>
+++++++++++<Row>
+++++++++++++<Cell: 2>
+++++++++++++++<StaticText: 2>
+++++++++++++<Cell: 4>
+++++++++++++++<StaticText: 4>
+++++++++<RowGroup>
+++++++++++<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
@@ -32,26 +35,29 @@ AXSelection from AX text position in "StaticText": "7", 1 to AX text position in
++<GenericContainer>
++++<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>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<ColumnHeader: Sum>
+++++++++++++++<StaticText: Sum>
+++++++++++++<ColumnHeader: Subtraction>
+++++++++++++++<StaticText: Subtraction>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<Cell: 10>
+|++++++++++++++<StaticText: |10>
+++++++++++++<Cell: 7>
+++++++++++++++<StaticText: 7^>
+++++++++++<Row>
+++++++++++++<Cell: 2>
+++++++++++++++<StaticText: 2>
+++++++++++++<Cell: 4>
+++++++++++++++<StaticText: 4>
+++++++++<RowGroup>
+++++++++++<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
@@ -59,26 +65,29 @@ AXSelection from AX text position in "StaticText": "2", 1 to AX text position in
++<GenericContainer>
++++<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>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<ColumnHeader: Sum>
+++++++++++++++<StaticText: Sum>
+++++++++++++<ColumnHeader: Subtraction>
+++++++++++++++<StaticText: Subtraction>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<Cell: 10>
+++++++++++++++<StaticText: 10>
+++++++++++++<Cell: 7>
+++++++++++++++<StaticText: 7>
+++++++++++<Row>
+++++++++++++<Cell: 2>
+++++++++++++++<StaticText: 2^>
+++++++++++++<Cell: 4>
+|++++++++++++++<StaticText: |4>
+++++++++<RowGroup>
+++++++++++<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
@@ -86,23 +95,26 @@ AXSelection from AX text position in "StaticText": "12", 0 to AX text position i
++<GenericContainer>
++++<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|>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<ColumnHeader: Sum>
+++++++++++++++<StaticText: Sum>
+++++++++++++<ColumnHeader: Subtraction>
+++++++++++++++<StaticText: Subtraction>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<Cell: 10>
+++++++++++++++<StaticText: 10>
+++++++++++++<Cell: 7>
+++++++++++++++<StaticText: 7>
+++++++++++<Row>
+++++++++++++<Cell: 2>
+++++++++++++++<StaticText: 2>
+++++++++++++<Cell: 4>
+++++++++++++++<StaticText: 4>
+++++++++<RowGroup>
+++++++++++<Row>
+++++++++++++<Cell: 12>
+^++++++++++++++<StaticText: ^12>
+++++++++++++<Cell: 3>
+++++++++++++++<StaticText: 3|>
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/DIR_METADATA b/chromium/third_party/blink/renderer/modules/animationworklet/DIR_METADATA
new file mode 100644
index 00000000000..714dcc0b40d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Internals>Compositing>Animation"
+}
+team_email: "threaded-rendering-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/OWNERS b/chromium/third_party/blink/renderer/modules/animationworklet/OWNERS
index f5e07fae3c2..759412f561f 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/OWNERS
@@ -4,6 +4,3 @@ majidvp@chromium.org
# for Worker related changes
kinuko@chromium.org
nhiroki@chromium.org
-
-# TEAM: threaded-rendering-dev@chromium.org
-# COMPONENT: Internals>Compositing>Animation
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 3ef1a129082..757a1c4718c 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
@@ -155,11 +155,13 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
DCHECK(script_state);
v8::Isolate* isolate = script_state->GetIsolate();
DCHECK(isolate);
- ScriptState::Scope scope(script_state);
+ v8::HandleScope scope(isolate);
+
+ ClassicScript* classic_script =
+ ClassicScript::CreateUnspecifiedScript(ScriptSourceCode(script));
ScriptEvaluationResult result =
- global_scope->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode(script), SanitizeScriptErrors::kSanitize);
+ classic_script->RunScriptOnScriptStateAndReturnValue(script_state);
DCHECK_EQ(result.GetResultType(),
ScriptEvaluationResult::ResultType::kSuccess);
return ToBoolean(isolate, result.GetSuccessValue(), ASSERT_NO_EXCEPTION);
@@ -455,8 +457,7 @@ TEST_F(AnimationWorkletGlobalScopeTest,
PostCrossThreadTask(
*worklet->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
CrossThreadBindOnce(&AnimationWorkletGlobalScopeTest::RunScriptOnWorklet,
- CrossThreadUnretained(this),
- Passed(std::move(source_code)),
+ CrossThreadUnretained(this), std::move(source_code),
CrossThreadUnretained(worklet.get()),
CrossThreadUnretained(&waitable_event)));
waitable_event.Wait();
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h
index 3656a604f66..bea297b5500 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h
@@ -23,12 +23,11 @@ class AnimationWorkletMessagingProxy final
: public ThreadedWorkletMessagingProxy {
public:
explicit AnimationWorkletMessagingProxy(ExecutionContext*);
+ ~AnimationWorkletMessagingProxy() override;
void Trace(Visitor*) const override;
private:
- ~AnimationWorkletMessagingProxy() override;
-
std::unique_ptr<WorkerThread> CreateWorkerThread() override;
};
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
index 21803ad7b6c..e7b4ff74854 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc
@@ -8,12 +8,14 @@
#include "base/metrics/histogram_macros.h"
#include "base/timer/elapsed_timer.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/renderer/core/animation/worklet_animation_controller.h"
#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
@@ -211,17 +213,25 @@ AnimationWorkletProxyClient* AnimationWorkletProxyClient::FromDocument(
WebLocalFrameImpl* local_frame =
WebLocalFrameImpl::FromFrame(document->GetFrame());
- scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue;
+ // By default web tests run without threaded compositing. See
+ // https://crbug.com/770028. If threaded compositing is disabled, we
+ // run on the main thread's compositor task runner otherwise we run
+ // tasks on the compositor thread's default task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue =
+ Thread::CompositorThread()
+ ? Thread::CompositorThread()->GetTaskRunner()
+ : local_frame->GetAgentGroupScheduler()->CompositorTaskRunner();
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
compositor_mutator_dispatcher =
local_frame->LocalRootFrameWidget()
- ->EnsureCompositorMutatorDispatcher(&compositor_host_queue);
+ ->EnsureCompositorMutatorDispatcher(compositor_host_queue);
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_host_queue;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_host_queue =
+ local_frame->GetAgentGroupScheduler()->CompositorTaskRunner();
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
main_thread_mutator_dispatcher =
document->GetWorkletAnimationController()
- .EnsureMainThreadMutatorDispatcher(&main_thread_host_queue);
+ .EnsureMainThreadMutatorDispatcher(main_thread_host_queue);
return MakeGarbageCollected<AnimationWorkletProxyClient>(
worklet_id, std::move(compositor_mutator_dispatcher),
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_test.cc
index 5093b0687c9..0aa9947c542 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_test.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_test.cc
@@ -44,9 +44,9 @@ class AnimationWorkletProxyClientTest : public RenderingTest {
void SetUp() override {
RenderingTest::SetUp();
- auto mutator =
- std::make_unique<AnimationWorkletMutatorDispatcherImpl>(true);
mutator_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
+ auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(
+ mutator_task_runner_);
proxy_client_ = MakeGarbageCollected<AnimationWorkletProxyClient>(
1, nullptr, nullptr, mutator->GetWeakPtr(), mutator_task_runner_);
@@ -226,9 +226,10 @@ TEST_F(AnimationWorkletProxyClientTest,
nullptr, nullptr);
EXPECT_TRUE(proxy_client->mutator_items_.IsEmpty());
- auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(true);
scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner =
- mutator->GetTaskRunner();
+ base::ThreadTaskRunnerHandle::Get();
+ auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(
+ mutator_task_runner);
proxy_client = MakeGarbageCollected<AnimationWorkletProxyClient>(
1, nullptr, nullptr, mutator->GetWeakPtr(), mutator_task_runner);
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 5f4b5c2378d..144138af233 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -166,6 +166,13 @@ base::Optional<base::TimeDelta> CalculateStartTime(
base::TimeDelta current_time,
double playback_rate,
AnimationTimeline& timeline) {
+ // Handle some special cases, note |playback_rate| can never be 0 before
+ // SetPlaybackRateInternal has a DCHECK for that.
+ DCHECK_NE(playback_rate, 0);
+ if (current_time.is_max())
+ return base::TimeDelta::FromMilliseconds(0);
+ if (current_time.is_min())
+ return base::TimeDelta::Max();
base::Optional<double> timeline_current_time_ms =
timeline.CurrentTimeMilliseconds();
return base::TimeDelta::FromMillisecondsD(timeline_current_time_ms.value()) -
@@ -477,8 +484,9 @@ void WorkletAnimation::Update(TimingUpdateReason reason) {
DCHECK_EQ(effects_.size(), local_times_.size());
for (wtf_size_t i = 0; i < effects_.size(); ++i) {
effects_[i]->UpdateInheritedTime(
- local_times_[i] ? base::Optional<double>(local_times_[i]->InSecondsF())
- : base::nullopt,
+ local_times_[i]
+ ? base::make_optional(AnimationTimeDelta(local_times_[i].value()))
+ : base::nullopt,
base::nullopt, reason);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
index 9f08f02db5b..84de608e9b5 100644
--- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
+++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
@@ -240,6 +240,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
bool effect_needs_restart_;
FRIEND_TEST_ALL_PREFIXES(WorkletAnimationTest, PausePlay);
+ FRIEND_TEST_ALL_PREFIXES(WorkletAnimationTest, SetCurrentTimeInfNotCrash);
};
} // namespace blink
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 581ac98357a..04860d42394 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
@@ -106,7 +106,9 @@ class WorkletAnimationTest : public RenderingTest {
void SimulateFrame(double milliseconds) {
base::TimeTicks tick =
- GetDocument().Timeline().ZeroTime() + ToTimeDelta(milliseconds);
+ base::TimeTicks() +
+ GetDocument().Timeline().CalculateZeroTime().since_origin() +
+ ToTimeDelta(milliseconds);
GetDocument().GetAnimationClock().UpdateTime(tick);
GetDocument().GetWorkletAnimationController().UpdateAnimationStates();
GetDocument().GetWorkletAnimationController().UpdateAnimationTimings(
@@ -131,9 +133,21 @@ TEST_F(WorkletAnimationTest, WorkletAnimationInElementAnimations) {
element_->EnsureElementAnimations().GetWorkletAnimations().size());
}
+// Regression test for crbug.com/1136120, pass if there is no crash.
+TEST_F(WorkletAnimationTest, SetCurrentTimeInfNotCrash) {
+ base::Optional<base::TimeDelta> seek_time =
+ base::TimeDelta::FromString("inf");
+ worklet_animation_->SetPlayState(Animation::kRunning);
+ GetDocument().GetAnimationClock().UpdateTime(base::TimeTicks::Max());
+ worklet_animation_->SetCurrentTime(seek_time);
+}
+
TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) {
scoped_refptr<ComputedStyle> style =
- GetDocument().GetStyleResolver().StyleForElement(element_).get();
+ GetDocument()
+ .GetStyleResolver()
+ .StyleForElement(element_, StyleRecalcContext())
+ .get();
EXPECT_EQ(false, style->HasCurrentOpacityAnimation());
worklet_animation_->play(ASSERT_NO_EXCEPTION);
element_->EnsureElementAnimations().UpdateAnimationFlags(*style);
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/DIR_METADATA b/chromium/third_party/blink/renderer/modules/app_banner/DIR_METADATA
new file mode 100644
index 00000000000..45ae75a7acc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/app_banner/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/OWNERS b/chromium/third_party/blink/renderer/modules/app_banner/OWNERS
index e670be67593..b9a348aaf38 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/app_banner/OWNERS
@@ -1,5 +1,5 @@
+cmp@chromium.org
+dmurph@chromium.org
dominickn@chromium.org
mlamouri@chromium.org
-
-# COMPONENT: UI>Browser>WebAppInstalls
-# TEAM: web-apps-platform-team@chromium.org
+msw@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc b/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
index 93812588f90..8cee11e58ce 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
@@ -46,7 +46,7 @@ void AppBannerController::BannerPromptRequest(
// hidden properly. We disable bfcache to avoid these issues.
frame_->GetFrameScheduler()->RegisterStickyFeature(
blink::SchedulingPolicy::Feature::kAppBanner,
- {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {blink::SchedulingPolicy::DisableBackForwardCache()});
mojom::AppBannerPromptReply reply =
frame_->DomWindow()->DispatchEvent(*BeforeInstallPromptEvent::Create(
diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/DIR_METADATA b/chromium/third_party/blink/renderer/modules/audio_output_devices/DIR_METADATA
new file mode 100644
index 00000000000..7fdbb5e4bdd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebRTC"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/OWNERS b/chromium/third_party/blink/renderer/modules/audio_output_devices/OWNERS
index dc849b7f2ea..a026093f8ec 100644
--- a/chromium/third_party/blink/renderer/modules/audio_output_devices/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/OWNERS
@@ -1,4 +1,2 @@
guidou@chromium.org
tommi@chromium.org
-
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
index 4b63698626c..ab924355857 100644
--- a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
+++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc
@@ -100,8 +100,10 @@ void SetSinkIdResolver::DoSetSinkId() {
WTF::Bind(&SetSinkIdResolver::OnSetSinkIdComplete, WrapPersistent(this));
WebMediaPlayer* web_media_player = element_->GetWebMediaPlayer();
if (web_media_player) {
- web_media_player->SetSinkId(sink_id_,
- std::move(set_sink_id_completion_callback));
+ if (web_media_player->SetSinkId(
+ sink_id_, std::move(set_sink_id_completion_callback))) {
+ element_->DidAudioOutputSinkChanged(sink_id_);
+ }
return;
}
@@ -152,7 +154,22 @@ void SetSinkIdResolver::Trace(Visitor* visitor) const {
} // namespace
-HTMLMediaElementAudioOutputDevice::HTMLMediaElementAudioOutputDevice() {}
+HTMLMediaElementAudioOutputDevice::HTMLMediaElementAudioOutputDevice(
+ HTMLMediaElement& element)
+ : AudioOutputDeviceController(element) {}
+
+// static
+HTMLMediaElementAudioOutputDevice& HTMLMediaElementAudioOutputDevice::From(
+ HTMLMediaElement& element) {
+ HTMLMediaElementAudioOutputDevice* self =
+ static_cast<HTMLMediaElementAudioOutputDevice*>(
+ AudioOutputDeviceController::From(element));
+ if (!self) {
+ self = MakeGarbageCollected<HTMLMediaElementAudioOutputDevice>(element);
+ AudioOutputDeviceController::ProvideTo(element, self);
+ }
+ return *self;
+}
String HTMLMediaElementAudioOutputDevice::sinkId(HTMLMediaElement& element) {
HTMLMediaElementAudioOutputDevice& aod_element =
@@ -179,23 +196,22 @@ ScriptPromise HTMLMediaElementAudioOutputDevice::setSinkId(
return promise;
}
-const char HTMLMediaElementAudioOutputDevice::kSupplementName[] =
- "HTMLMediaElementAudioOutputDevice";
+void HTMLMediaElementAudioOutputDevice::SetSinkId(const String& sink_id) {
+ // No need to call WebFrameClient::CheckIfAudioSinkExistsAndIsAuthorized as
+ // this call is not coming from content and should already be allowed.
+ HTMLMediaElement* html_media_element = GetSupplementable();
+ WebMediaPlayer* web_media_player = html_media_element->GetWebMediaPlayer();
+ if (!web_media_player)
+ return;
-HTMLMediaElementAudioOutputDevice& HTMLMediaElementAudioOutputDevice::From(
- HTMLMediaElement& element) {
- HTMLMediaElementAudioOutputDevice* supplement =
- Supplement<HTMLMediaElement>::From<HTMLMediaElementAudioOutputDevice>(
- element);
- if (!supplement) {
- supplement = MakeGarbageCollected<HTMLMediaElementAudioOutputDevice>();
- ProvideTo(element, supplement);
- }
- return *supplement;
+ sink_id_ = sink_id;
+
+ if (web_media_player->SetSinkId(sink_id_, base::DoNothing()))
+ html_media_element->DidAudioOutputSinkChanged(sink_id_);
}
void HTMLMediaElementAudioOutputDevice::Trace(Visitor* visitor) const {
- Supplement<HTMLMediaElement>::Trace(visitor);
+ AudioOutputDeviceController::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.h b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.h
index ddd712820d3..d26931e3a40 100644
--- a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.h
+++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.h
@@ -7,10 +7,10 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/html/media/audio_output_device_controller.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.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/supplementable.h"
namespace blink {
@@ -19,20 +19,23 @@ class ScriptState;
class MODULES_EXPORT HTMLMediaElementAudioOutputDevice final
: public GarbageCollected<HTMLMediaElementAudioOutputDevice>,
- public Supplement<HTMLMediaElement> {
+ public AudioOutputDeviceController {
public:
- static const char kSupplementName[];
+ HTMLMediaElementAudioOutputDevice(HTMLMediaElement&);
- HTMLMediaElementAudioOutputDevice();
+ static HTMLMediaElementAudioOutputDevice& From(HTMLMediaElement&);
- void Trace(Visitor*) const override;
static String sinkId(HTMLMediaElement&);
static ScriptPromise setSinkId(ScriptState*,
HTMLMediaElement&,
const String& sink_id);
- static HTMLMediaElementAudioOutputDevice& From(HTMLMediaElement&);
void setSinkId(const String&);
+ // AudioOutputDeviceController implementation.
+ void SetSinkId(const String&) override;
+
+ void Trace(Visitor*) const override;
+
private:
String sink_id_;
};
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/DIR_METADATA b/chromium/third_party/blink/renderer/modules/background_fetch/DIR_METADATA
new file mode 100644
index 00000000000..56639a06a43
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>BackgroundFetch"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/OWNERS b/chromium/third_party/blink/renderer/modules/background_fetch/OWNERS
index d797831588a..20aa409b986 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/OWNERS
@@ -2,6 +2,3 @@ peter@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>BackgroundFetch
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
index 4cbe284a7f4..4d5e46df3e5 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
@@ -59,11 +59,11 @@ void BackgroundFetchBridge::Fetch(
const SkBitmap& icon,
mojom::blink::BackgroundFetchUkmDataPtr ukm_data,
RegistrationCallback callback) {
- GetService()->Fetch(
- GetSupplementable()->RegistrationId(), developer_id, std::move(requests),
- std::move(options), icon, std::move(ukm_data),
- WTF::Bind(&BackgroundFetchBridge::DidGetRegistration,
- WrapPersistent(this), WTF::Passed(std::move(callback))));
+ GetService()->Fetch(GetSupplementable()->RegistrationId(), developer_id,
+ std::move(requests), std::move(options), icon,
+ std::move(ukm_data),
+ WTF::Bind(&BackgroundFetchBridge::DidGetRegistration,
+ WrapPersistent(this), std::move(callback)));
}
void BackgroundFetchBridge::GetRegistration(const String& developer_id,
@@ -71,7 +71,7 @@ void BackgroundFetchBridge::GetRegistration(const String& developer_id,
GetService()->GetRegistration(
GetSupplementable()->RegistrationId(), developer_id,
WTF::Bind(&BackgroundFetchBridge::DidGetRegistration,
- WrapPersistent(this), WTF::Passed(std::move(callback))));
+ WrapPersistent(this), std::move(callback)));
}
void BackgroundFetchBridge::DidGetRegistration(
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
index 2bd8ae92fbb..eb1ca004e36 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h"
+#include <utility>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_url.h"
@@ -112,7 +114,7 @@ class BackgroundFetchIconLoaderTest : public PageTestBase {
loader_->DidGetIconDisplaySizeIfSoLoadIcon(
GetContext(),
WTF::Bind(&BackgroundFetchIconLoaderTest::IconLoaded,
- WTF::Unretained(this), WTF::Passed(std::move(quit_closure))),
+ WTF::Unretained(this), std::move(quit_closure)),
maximum_size);
}
diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index d9012d9716e..4553e5e5dc3 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -268,9 +268,8 @@ ScriptPromise BackgroundFetchManager::fetch(
loader->Start(
bridge_.Get(), execution_context, options->icons(),
WTF::Bind(&BackgroundFetchManager::DidLoadIcons, WrapPersistent(this),
- id, WTF::Passed(std::move(fetch_api_requests)),
- std::move(options_ptr), WrapPersistent(resolver),
- WrapWeakPersistent(loader)));
+ id, std::move(fetch_api_requests), std::move(options_ptr),
+ WrapPersistent(resolver), WrapWeakPersistent(loader)));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/background_sync/DIR_METADATA b/chromium/third_party/blink/renderer/modules/background_sync/DIR_METADATA
new file mode 100644
index 00000000000..283199aecbb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/background_sync/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>BackgroundSync"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/background_sync/OWNERS b/chromium/third_party/blink/renderer/modules/background_sync/OWNERS
index e5a07143f3d..da9ba969fae 100644
--- a/chromium/third_party/blink/renderer/modules/background_sync/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/background_sync/OWNERS
@@ -1,2 +1 @@
-file://chrome/browser/background_sync/OWNERS
-# COMPONENT: Blink>BackgroundSync
+file://chrome/browser/background_sync/OWNERS \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/badging/DIR_METADATA b/chromium/third_party/blink/renderer/modules/badging/DIR_METADATA
new file mode 100644
index 00000000000..45ae75a7acc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/badging/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/badging/OWNERS b/chromium/third_party/blink/renderer/modules/badging/OWNERS
index dd81d8dc5c4..3da12768b75 100644
--- a/chromium/third_party/blink/renderer/modules/badging/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/badging/OWNERS
@@ -1,4 +1 @@
file://chrome/browser/badging/OWNERS
-
-# COMPONENT: UI>Browser>WebAppInstalls
-# TEAM: web-apps-platform-team@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/battery/BUILD.gn b/chromium/third_party/blink/renderer/modules/battery/BUILD.gn
index 26c0a5e697a..bc5c43f6341 100644
--- a/chromium/third_party/blink/renderer/modules/battery/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/battery/BUILD.gn
@@ -11,8 +11,6 @@ blink_modules_sources("battery") {
"battery_manager.cc",
"battery_manager.h",
"battery_status.h",
- "navigator_battery.cc",
- "navigator_battery.h",
]
deps = [ "//services/service_manager/public/cpp" ]
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
index 6495c21bcba..74d44b574f7 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/modules/battery/battery_dispatcher.h"
#include "services/device/public/mojom/battery_status.mojom-blink.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/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
@@ -13,14 +13,8 @@
namespace blink {
-BatteryDispatcher& BatteryDispatcher::Instance() {
- DEFINE_STATIC_LOCAL(Persistent<BatteryDispatcher>, battery_dispatcher,
- (MakeGarbageCollected<BatteryDispatcher>()));
- return *battery_dispatcher;
-}
-
-BatteryDispatcher::BatteryDispatcher()
- : monitor_(nullptr), has_latest_data_(false) {}
+BatteryDispatcher::BatteryDispatcher(ExecutionContext* context)
+ : monitor_(context), has_latest_data_(false) {}
void BatteryDispatcher::Trace(Visitor* visitor) const {
visitor->Trace(monitor_);
@@ -53,7 +47,7 @@ void BatteryDispatcher::UpdateBatteryStatus(
void BatteryDispatcher::StartListening(LocalDOMWindow* window) {
DCHECK(!monitor_.is_bound());
// See https://bit.ly/2S0zRAS for task types.
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ window->GetBrowserInterfaceBroker().GetInterface(
monitor_.BindNewPipeAndPassReceiver(
window->GetTaskRunner(TaskType::kMiscPlatformAPI)));
QueryNextStatus();
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
index ff496eb15b6..32c22d859d5 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.h
@@ -7,8 +7,8 @@
#include "base/macros.h"
#include "services/device/public/mojom/battery_monitor.mojom-blink.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/platform_event_dispatcher.h"
-#include "third_party/blink/renderer/modules/battery/battery_manager.h"
#include "third_party/blink/renderer/modules/battery/battery_status.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
@@ -19,9 +19,7 @@ class MODULES_EXPORT BatteryDispatcher final
: public GarbageCollected<BatteryDispatcher>,
public PlatformEventDispatcher {
public:
- static BatteryDispatcher& Instance();
-
- BatteryDispatcher();
+ explicit BatteryDispatcher(ExecutionContext*);
const BatteryStatus* LatestData() const {
return has_latest_data_ ? &battery_status_ : nullptr;
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
index 795f34af8d5..bb1e4d42299 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc
@@ -9,23 +9,47 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/battery/battery_dispatcher.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
-BatteryManager* BatteryManager::Create(ExecutionContext* context) {
- BatteryManager* battery_manager =
- MakeGarbageCollected<BatteryManager>(context);
- battery_manager->UpdateStateIfNeeded();
- return battery_manager;
+const char BatteryManager::kSupplementName[] = "BatteryManager";
+
+// static
+ScriptPromise BatteryManager::getBattery(ScriptState* script_state,
+ Navigator& navigator) {
+ if (!navigator.DomWindow())
+ return ScriptPromise();
+
+ // Check to see if this request would be blocked according to the Battery
+ // Status API specification.
+ LocalDOMWindow* window = navigator.DomWindow();
+ if (!window->IsSecureContext())
+ UseCounter::Count(window, WebFeature::kBatteryStatusInsecureOrigin);
+ window->GetFrame()->CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+ WebFeature::kBatteryStatusCrossOrigin,
+ WebFeature::kBatteryStatusSameOriginABA);
+
+ auto* supplement = Supplement<Navigator>::From<BatteryManager>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<BatteryManager>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement->StartRequest(script_state);
}
BatteryManager::~BatteryManager() = default;
-BatteryManager::BatteryManager(ExecutionContext* context)
- : ExecutionContextLifecycleStateObserver(context),
- PlatformEventController(*To<LocalDOMWindow>(context)) {}
+BatteryManager::BatteryManager(Navigator& navigator)
+ : Supplement<Navigator>(navigator),
+ ExecutionContextLifecycleStateObserver(navigator.DomWindow()),
+ PlatformEventController(*navigator.DomWindow()),
+ battery_dispatcher_(
+ MakeGarbageCollected<BatteryDispatcher>(navigator.DomWindow())) {
+ UpdateStateIfNeeded();
+}
ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) {
if (!battery_property_) {
@@ -64,7 +88,7 @@ void BatteryManager::DidUpdateData() {
DCHECK(battery_property_);
BatteryStatus old_status = battery_status_;
- battery_status_ = *BatteryDispatcher::Instance().LatestData();
+ battery_status_ = *battery_dispatcher_->LatestData();
if (battery_property_->GetState() == BatteryProperty::kPending) {
battery_property_->Resolve(this);
@@ -88,15 +112,15 @@ void BatteryManager::DidUpdateData() {
}
void BatteryManager::RegisterWithDispatcher() {
- BatteryDispatcher::Instance().AddController(this, DomWindow());
+ battery_dispatcher_->AddController(this, DomWindow());
}
void BatteryManager::UnregisterWithDispatcher() {
- BatteryDispatcher::Instance().RemoveController(this);
+ battery_dispatcher_->RemoveController(this);
}
bool BatteryManager::HasLastData() {
- return BatteryDispatcher::Instance().LatestData();
+ return battery_dispatcher_->LatestData();
}
void BatteryManager::ContextLifecycleStateChanged(
@@ -126,6 +150,8 @@ bool BatteryManager::HasPendingActivity() const {
void BatteryManager::Trace(Visitor* visitor) const {
visitor->Trace(battery_property_);
+ visitor->Trace(battery_dispatcher_);
+ Supplement<Navigator>::Trace(visitor);
PlatformEventController::Trace(visitor);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleStateObserver::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.h b/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
index 6e9cfe07995..bce6a793ac0 100644
--- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
+++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.h
@@ -10,22 +10,27 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
+#include "third_party/blink/renderer/modules/battery/battery_dispatcher.h"
#include "third_party/blink/renderer/modules/battery/battery_status.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/supplementable.h"
namespace blink {
+class Navigator;
+
class BatteryManager final : public EventTargetWithInlineData,
public ActiveScriptWrappable<BatteryManager>,
+ public Supplement<Navigator>,
public ExecutionContextLifecycleStateObserver,
public PlatformEventController {
DEFINE_WRAPPERTYPEINFO();
public:
- static BatteryManager* Create(ExecutionContext*);
-
- explicit BatteryManager(ExecutionContext*);
+ static const char kSupplementName[];
+ static ScriptPromise getBattery(ScriptState*, Navigator&);
+ explicit BatteryManager(Navigator&);
~BatteryManager() override;
// Returns a promise object that will be resolved with this BatteryManager.
@@ -69,6 +74,7 @@ class BatteryManager final : public EventTargetWithInlineData,
ScriptPromiseProperty<Member<BatteryManager>, Member<DOMException>>;
Member<BatteryProperty> battery_property_;
BatteryStatus battery_status_;
+ Member<BatteryDispatcher> battery_dispatcher_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc
deleted file mode 100644
index e0985db82e9..00000000000
--- a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/battery/navigator_battery.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/modules/battery/battery_manager.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-
-namespace blink {
-
-NavigatorBattery::NavigatorBattery(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
-
-ScriptPromise NavigatorBattery::getBattery(ScriptState* script_state,
- Navigator& navigator) {
- return NavigatorBattery::From(navigator).getBattery(script_state);
-}
-
-ScriptPromise NavigatorBattery::getBattery(ScriptState* script_state) {
- if (!script_state->ContextIsValid())
- return ScriptPromise();
-
- LocalDOMWindow* window = LocalDOMWindow::From(script_state);
-
- // Check to see if this request would be blocked according to the Battery
- // Status API specification.
- if (window) {
- if (LocalFrame* frame = window->GetFrame()) {
- if (!window->IsSecureContext())
- UseCounter::Count(window, WebFeature::kBatteryStatusInsecureOrigin);
- frame->CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
- WebFeature::kBatteryStatusCrossOrigin,
- WebFeature::kBatteryStatusSameOriginABA);
- }
- }
-
- if (!battery_manager_)
- battery_manager_ = BatteryManager::Create(window);
- return battery_manager_->StartRequest(script_state);
-}
-
-const char NavigatorBattery::kSupplementName[] = "NavigatorBattery";
-
-NavigatorBattery& NavigatorBattery::From(Navigator& navigator) {
- NavigatorBattery* supplement =
- Supplement<Navigator>::From<NavigatorBattery>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorBattery>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-void NavigatorBattery::Trace(Visitor* visitor) const {
- visitor->Trace(battery_manager_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.h b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.h
deleted file mode 100644
index 6e7b9e22c74..00000000000
--- a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BATTERY_NAVIGATOR_BATTERY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_BATTERY_NAVIGATOR_BATTERY_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class BatteryManager;
-class Navigator;
-
-class NavigatorBattery final : public GarbageCollected<NavigatorBattery>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static NavigatorBattery& From(Navigator&);
-
- static ScriptPromise getBattery(ScriptState*, Navigator&);
- ScriptPromise getBattery(ScriptState*);
-
- explicit NavigatorBattery(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<BatteryManager> battery_manager_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BATTERY_NAVIGATOR_BATTERY_H_
diff --git a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
index ce0f3997f81..13f92c9fccc 100644
--- a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
+++ b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.idl
@@ -4,7 +4,7 @@
// https://w3c.github.io/battery/#the-navigator-interface
[
- ImplementedAs=NavigatorBattery
+ ImplementedAs=BatteryManager
] partial interface Navigator {
[CallWith=ScriptState, MeasureAs=BatteryStatusGetBattery] Promise<BatteryManager> getBattery();
};
diff --git a/chromium/third_party/blink/renderer/modules/beacon/DIR_METADATA b/chromium/third_party/blink/renderer/modules/beacon/DIR_METADATA
new file mode 100644
index 00000000000..17e49e6acba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/beacon/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Network"
+}
+team_email: "blink-network-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/beacon/OWNERS b/chromium/third_party/blink/renderer/modules/beacon/OWNERS
index 7115fad815c..acbf93af41e 100644
--- a/chromium/third_party/blink/renderer/modules/beacon/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/beacon/OWNERS
@@ -1,4 +1 @@
yhirano@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network
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 47285756462..25a39d8c012 100644
--- a/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
+++ b/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
@@ -80,9 +80,16 @@ bool NavigatorBeacon::SendBeaconImpl(
ExceptionState& exception_state) {
ExecutionContext* context = ExecutionContext::From(script_state);
KURL url = context->CompleteURL(urlstring);
- if (!CanSendBeacon(context, url, exception_state))
+ if (!CanSendBeacon(context, url, exception_state)) {
+ // TODO(crbug.com/1161996): Remove this VLOG once the investigation is done.
+ VLOG(1) << "Cannot send a beacon to " << url.ElidedString()
+ << ", initiator = " << context->Url();
return false;
+ }
+ // TODO(crbug.com/1161996): Remove this VLOG once the investigation is done.
+ VLOG(1) << "Send a beacon to " << url.ElidedString()
+ << ", initiator = " << context->Url();
bool allowed;
LocalFrame* frame = GetSupplementable()->DomWindow()->GetFrame();
@@ -99,7 +106,7 @@ bool NavigatorBeacon::SendBeaconImpl(
}
allowed = PingLoader::SendBeacon(*script_state, frame, url, data_buffer);
} else if (data.IsArrayBufferView()) {
- auto* data_view = data.GetAsArrayBufferView().View();
+ auto* data_view = data.GetAsArrayBufferView().Get();
if (!base::CheckedNumeric<wtf_size_t>(data_view->byteLength()).IsValid()) {
// At the moment the PingLoader::SendBeacon implementation cannot deal
// with huge ArrayBuffers.
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/DIR_METADATA b/chromium/third_party/blink/renderer/modules/bluetooth/DIR_METADATA
new file mode 100644
index 00000000000..1db37d60f0e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Bluetooth"
+}
+team_email: "web-bluetooth@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS b/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
index 9d049d44c15..837ee391b5d 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/OWNERS
@@ -1,4 +1 @@
file://content/browser/bluetooth/OWNERS
-
-# TEAM: web-bluetooth@chromium.org
-# COMPONENT: Blink>Bluetooth
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
index d9da75ff768..f12d137ead8 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -56,7 +56,7 @@ const char kHandleGestureForPermissionRequest[] =
// TODO(https://crbug.com/570344): Remove this method when all platforms are
// supported.
void AddUnsupportedPlatformConsoleMessage(ExecutionContext* context) {
-#if !BUILDFLAG(IS_ASH) && !defined(OS_ANDROID) && !defined(OS_MAC) && \
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) && !defined(OS_MAC) && \
!defined(OS_WIN)
context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kJavaScript,
@@ -467,9 +467,7 @@ Bluetooth::Bluetooth(Navigator& navigator)
client_receivers_(this, navigator.DomWindow()),
service_(navigator.DomWindow()) {}
-Bluetooth::~Bluetooth() {
- DCHECK(client_receivers_.empty());
-}
+Bluetooth::~Bluetooth() = default;
BluetoothDevice* Bluetooth::GetBluetoothDeviceRepresentingDevice(
mojom::blink::WebBluetoothDevicePtr device_ptr,
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
index daa05e73043..195ecbfdb1a 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.cc
@@ -222,12 +222,6 @@ void BluetoothDevice::WatchAdvertisementsCallback(
if (!watch_advertisements_resolver_)
return;
- if (!watch_advertisements_resolver_->GetExecutionContext() ||
- watch_advertisements_resolver_->GetExecutionContext()
- ->IsContextDestroyed()) {
- return;
- }
-
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements
// 2.2.2. If the UA fails to enable scanning, queue a task to perform the
// following steps, and abort these steps:
diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA b/chromium/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA
new file mode 100644
index 00000000000..441101820d4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Messaging"
+}
+team_email: "platform-architecture-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/OWNERS b/chromium/third_party/blink/renderer/modules/broadcastchannel/OWNERS
index 94902aa42fe..1b10b3436d9 100644
--- a/chromium/third_party/blink/renderer/modules/broadcastchannel/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/OWNERS
@@ -1,4 +1 @@
mek@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Messaging
diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
index cf5510635a7..92f7f6f2a17 100644
--- a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
+++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -142,7 +142,7 @@ BroadcastChannel::BroadcastChannel(ExecutionContext* execution_context,
feature_handle_for_scheduler_(
execution_context->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kBroadcastChannel,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
mojo::Remote<mojom::blink::BroadcastChannelProvider>& provider =
GetThreadSpecificProvider();
diff --git a/chromium/third_party/blink/renderer/modules/buckets/BUILD.gn b/chromium/third_party/blink/renderer/modules/buckets/BUILD.gn
new file mode 100644
index 00000000000..cbcd5eb19a0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("buckets") {
+ sources = [
+ "storage_bucket.cc",
+ "storage_bucket.h",
+ "storage_bucket_manager.cc",
+ "storage_bucket_manager.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/buckets/DEPS b/chromium/third_party/blink/renderer/modules/buckets/DEPS
new file mode 100644
index 00000000000..5c028941f41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "-third_party/blink/renderer/modules",
+ "+third_party/blink/renderer/modules/buckets",
+ "+third_party/blink/renderer/modules/modules_export.h",
+]
diff --git a/chromium/third_party/blink/renderer/modules/buckets/OWNERS b/chromium/third_party/blink/renderer/modules/buckets/OWNERS
new file mode 100644
index 00000000000..be790201c29
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/OWNERS
@@ -0,0 +1 @@
+file://content/browser/buckets/OWNERS
diff --git a/chromium/third_party/blink/renderer/modules/buckets/idls.gni b/chromium/third_party/blink/renderer/modules/buckets/idls.gni
new file mode 100644
index 00000000000..c3d1f981411
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/idls.gni
@@ -0,0 +1,15 @@
+# Copyright 2020 The Chromium 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_idl_files = [
+ "storage_bucket_manager.idl",
+ "storage_bucket.idl",
+]
+
+modules_dictionary_idl_files = [ "storage_bucket_options.idl" ]
+
+modules_dependency_idl_files = [
+ "navigator_storage_buckets.idl",
+ "worker_navigator_storage_buckets.idl",
+]
diff --git a/chromium/third_party/blink/renderer/modules/buckets/navigator_storage_buckets.idl b/chromium/third_party/blink/renderer/modules/buckets/navigator_storage_buckets.idl
new file mode 100644
index 00000000000..3ce25042d9e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/navigator_storage_buckets.idl
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/storage-buckets
+
+[
+ SecureContext,
+ ImplementedAs=StorageBucketManager,
+ RuntimeEnabled=StorageBuckets
+] partial interface Navigator {
+ [CallWith=ScriptState, RaisesException]
+ readonly attribute StorageBucketManager storageBuckets;
+};
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.cc b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.cc
new file mode 100644
index 00000000000..bb2096ddd27
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.cc
@@ -0,0 +1,206 @@
+// Copyright 2020 The Chromium Authors. 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/buckets/storage_bucket.h"
+
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_storage_estimate.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_storage_usage_details.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/dom_time_stamp.h"
+
+namespace blink {
+
+StorageBucket::StorageBucket(
+ ExecutionContext* context,
+ mojo::PendingRemote<mojom::blink::BucketHost> remote)
+ : ExecutionContextLifecycleObserver(context) {
+ remote_.Bind(std::move(remote), GetExecutionContext()->GetTaskRunner(
+ TaskType::kInternalDefault));
+}
+
+ScriptPromise StorageBucket::persist(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->Persist(WTF::Bind(&StorageBucket::DidRequestPersist,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucket::persisted(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->Persisted(WTF::Bind(&StorageBucket::DidGetPersisted,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucket::estimate(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->Estimate(WTF::Bind(&StorageBucket::DidGetEstimate,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucket::durability(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->Durability(WTF::Bind(&StorageBucket::DidGetDurability,
+ WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucket::setExpires(ScriptState* script_state,
+ const DOMTimeStamp& expires) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->SetExpires(
+ base::Time::FromJavaTime(expires),
+ WTF::Bind(&StorageBucket::DidSetExpires, WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucket::expires(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ remote_->Expires(WTF::Bind(&StorageBucket::DidGetExpires,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return promise;
+}
+
+bool StorageBucket::HasPendingActivity() const {
+ return GetExecutionContext();
+}
+
+void StorageBucket::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ ExecutionContextLifecycleObserver::Trace(visitor);
+}
+
+void StorageBucket::DidRequestPersist(ScriptPromiseResolver* resolver,
+ bool persisted,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while requesting persist."));
+ return;
+ }
+
+ ScriptState::Scope scope(script_state);
+ resolver->Resolve(persisted);
+}
+
+void StorageBucket::DidGetPersisted(ScriptPromiseResolver* resolver,
+ bool persisted,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while getting persisted."));
+ return;
+ }
+
+ ScriptState::Scope scope(script_state);
+ resolver->Resolve(persisted);
+}
+
+void StorageBucket::DidGetEstimate(ScriptPromiseResolver* resolver,
+ int64_t current_usage,
+ int64_t current_quota,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while getting estimate."));
+ return;
+ }
+
+ // TODO(ayui): Pass correct values once connected to quota.
+ StorageEstimate* estimate = StorageEstimate::Create();
+ estimate->setUsage(0);
+ estimate->setQuota(0);
+ StorageUsageDetails* details = StorageUsageDetails::Create();
+ estimate->setUsageDetails(details);
+ resolver->Resolve(estimate);
+}
+
+void StorageBucket::DidGetDurability(ScriptPromiseResolver* resolver,
+ mojom::blink::BucketDurability durability,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while getting durability."));
+ return;
+ }
+
+ ScriptState::Scope scope(script_state);
+
+ if (durability == mojom::blink::BucketDurability::kRelaxed)
+ resolver->Resolve("relaxed");
+ resolver->Resolve("strict");
+}
+
+void StorageBucket::DidSetExpires(ScriptPromiseResolver* resolver,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (success) {
+ resolver->Resolve();
+ } else {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while setting expires."));
+ }
+}
+
+void StorageBucket::DidGetExpires(ScriptPromiseResolver* resolver,
+ const base::Optional<base::Time> expires,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while getting expires."));
+ } else if (expires.has_value()) {
+ resolver->Resolve(
+ ConvertSecondsToDOMTimeStamp(expires.value().ToDoubleT()));
+ } else {
+ resolver->Resolve(v8::Null(script_state->GetIsolate()));
+ }
+}
+
+void StorageBucket::ContextDestroyed() {
+ remote_.reset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.h b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.h
new file mode 100644
index 00000000000..7c6094d9274
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.h
@@ -0,0 +1,75 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_H_
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/buckets/bucket_manager_host.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_time_stamp.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class ScriptState;
+
+class StorageBucket final : public ScriptWrappable,
+ public ActiveScriptWrappable<StorageBucket>,
+ public ExecutionContextLifecycleObserver {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ StorageBucket(ExecutionContext* context,
+ mojo::PendingRemote<mojom::blink::BucketHost> remote);
+
+ ~StorageBucket() override = default;
+
+ ScriptPromise persist(ScriptState*);
+ ScriptPromise persisted(ScriptState*);
+ ScriptPromise estimate(ScriptState*);
+ ScriptPromise durability(ScriptState*);
+ ScriptPromise setExpires(ScriptState*, const DOMTimeStamp&);
+ ScriptPromise expires(ScriptState*);
+
+ // ActiveScriptWrappable
+ bool HasPendingActivity() const final;
+
+ // GarbageCollected
+ void Trace(Visitor*) const override;
+
+ private:
+ void DidRequestPersist(ScriptPromiseResolver* resolver,
+ bool persisted,
+ bool success);
+ void DidGetPersisted(ScriptPromiseResolver* resolver,
+ bool persisted,
+ bool success);
+ void DidGetEstimate(ScriptPromiseResolver* resolver,
+ int64_t current_usage,
+ int64_t current_quota,
+ bool success);
+ void DidGetDurability(ScriptPromiseResolver* resolver,
+ mojom::blink::BucketDurability durability,
+ bool success);
+ void DidSetExpires(ScriptPromiseResolver* resolver, bool success);
+ void DidGetExpires(ScriptPromiseResolver* resolver,
+ const base::Optional<base::Time> expires,
+ bool success);
+
+ // ExecutionContextLifecycleObserver
+ void ContextDestroyed() override;
+
+ // BucketHost in the browser process.
+ mojo::Remote<mojom::blink::BucketHost> remote_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_H_
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.idl b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.idl
new file mode 100644
index 00000000000..21d9f7b582d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket.idl
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/storage-buckets
+
+[
+ ActiveScriptWrappable,
+ RuntimeEnabled=StorageBuckets,
+ Exposed=(Window,Worker),
+ SecureContext
+] interface StorageBucket {
+ [Exposed=Window, CallWith=ScriptState] Promise<boolean> persist();
+ [CallWith=ScriptState] Promise<boolean> persisted();
+
+ [CallWith=ScriptState] Promise<StorageEstimate> estimate();
+
+ [CallWith=ScriptState] Promise<StorageBucketDurability> durability();
+
+ [CallWith=ScriptState] Promise<void> setExpires(DOMTimeStamp expires);
+ [CallWith=ScriptState] Promise<DOMTimeStamp?> expires();
+};
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.cc b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.cc
new file mode 100644
index 00000000000..a5b3e771ed1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 The Chromium Authors. 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/buckets/storage_bucket_manager.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/modules/v8/v8_storage_bucket_options.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
+#include "third_party/blink/renderer/modules/buckets/storage_bucket.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+namespace {
+
+mojom::blink::BucketPoliciesPtr ToMojoBucketPolicies(
+ const StorageBucketOptions* options) {
+ auto policies = mojom::blink::BucketPolicies::New();
+ policies->persisted = options->persisted();
+ policies->title = (options->hasTitle() && !options->title().IsEmpty())
+ ? options->title()
+ : "";
+ policies->quota = options->hasQuotaNonNull()
+ ? options->quotaNonNull()
+ : mojom::blink::kNoQuotaPolicyValue;
+
+ if (options->durability() == "strict") {
+ policies->durability = mojom::blink::BucketDurability::kStrict;
+ } else {
+ policies->durability = mojom::blink::BucketDurability::kRelaxed;
+ }
+
+ if (options->hasExpiresNonNull())
+ policies->expires = base::Time::FromJavaTime(options->expiresNonNull());
+ return policies;
+}
+
+} // namespace
+
+const char StorageBucketManager::kSupplementName[] = "StorageBucketManager";
+
+StorageBucketManager::StorageBucketManager(NavigatorBase& navigator,
+ ExecutionContext* context)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextClient(context),
+ manager_remote_(context) {
+ context->GetBrowserInterfaceBroker().GetInterface(
+ manager_remote_.BindNewPipeAndPassReceiver(
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ DCHECK(manager_remote_.is_bound());
+}
+
+StorageBucketManager* StorageBucketManager::storageBuckets(
+ ScriptState* script_state,
+ NavigatorBase& navigator,
+ ExceptionState& exception_state) {
+ auto* supplement =
+ Supplement<NavigatorBase>::From<StorageBucketManager>(navigator);
+ if (!supplement) {
+ auto* context = ExecutionContext::From(script_state);
+ supplement = MakeGarbageCollected<StorageBucketManager>(navigator, context);
+ Supplement<NavigatorBase>::ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+ScriptPromise StorageBucketManager::open(ScriptState* script_state,
+ const String& name,
+ const StorageBucketOptions* options,
+ ExceptionState& exception_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ mojom::blink::BucketPoliciesPtr bucket_policies =
+ ToMojoBucketPolicies(options);
+
+ manager_remote_->OpenBucket(
+ name, std::move(bucket_policies),
+ WTF::Bind(&StorageBucketManager::DidOpen, WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucketManager::keys(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ manager_remote_->Keys(WTF::Bind(&StorageBucketManager::DidGetKeys,
+ WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise StorageBucketManager::Delete(ScriptState* script_state,
+ const String& name,
+ ExceptionState& exception_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ manager_remote_->DeleteBucket(
+ name, WTF::Bind(&StorageBucketManager::DidDelete, WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+void StorageBucketManager::DidOpen(
+ ScriptPromiseResolver* resolver,
+ mojo::PendingRemote<mojom::blink::BucketHost> bucket_remote) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!bucket_remote) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while creating a bucket."));
+ return;
+ }
+ resolver->Resolve(MakeGarbageCollected<StorageBucket>(
+ GetExecutionContext(), std::move(bucket_remote)));
+}
+
+void StorageBucketManager::DidGetKeys(ScriptPromiseResolver* resolver,
+ const Vector<String>& keys,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while retrieving bucket names."));
+ return;
+ }
+ resolver->Resolve(keys);
+}
+
+void StorageBucketManager::DidDelete(ScriptPromiseResolver* resolver,
+ bool success) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!success) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError,
+ "Unknown error occured while deleting a bucket."));
+ return;
+ }
+ resolver->Resolve();
+}
+
+void StorageBucketManager::Trace(Visitor* visitor) const {
+ visitor->Trace(manager_remote_);
+ ScriptWrappable::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.h b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.h
new file mode 100644
index 00000000000..1a495c5bc7b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_MANAGER_H_
+
+#include "third_party/blink/public/mojom/buckets/bucket_manager_host.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.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/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ExceptionState;
+class NavigatorBase;
+class StorageBucketOptions;
+
+class MODULES_EXPORT StorageBucketManager final
+ : public ScriptWrappable,
+ public Supplement<NavigatorBase>,
+ public ExecutionContextClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static const char kSupplementName[];
+
+ // Web-exposed as navigator.storageBuckets
+ static StorageBucketManager* storageBuckets(ScriptState* script_state,
+ NavigatorBase& navigator,
+ ExceptionState& exception_state);
+
+ StorageBucketManager(NavigatorBase& navigator, ExecutionContext* context);
+ ~StorageBucketManager() override = default;
+
+ ScriptPromise open(ScriptState* script_state,
+ const String& name,
+ const StorageBucketOptions* options,
+ ExceptionState& exception_state);
+ ScriptPromise keys(ScriptState* script_state,
+ ExceptionState& exception_state);
+ ScriptPromise Delete(ScriptState* script_state,
+ const String& name,
+ ExceptionState& exception_state);
+
+ // GarbageCollected
+ void Trace(Visitor*) const override;
+
+ private:
+ void DidOpen(ScriptPromiseResolver* resolver,
+ mojo::PendingRemote<mojom::blink::BucketHost> bucket_remote);
+ void DidGetKeys(ScriptPromiseResolver* resolver,
+ const Vector<String>& keys,
+ bool success);
+ void DidDelete(ScriptPromiseResolver* resolver, bool success);
+
+ HeapMojoRemote<mojom::blink::BucketManagerHost> manager_remote_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BUCKETS_STORAGE_BUCKET_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.idl b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.idl
new file mode 100644
index 00000000000..434f84cc72e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_manager.idl
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/storage-buckets
+
+[
+ Exposed=(Window,Worker),
+ RuntimeEnabled=StorageBuckets,
+ SecureContext
+] interface StorageBucketManager {
+ [
+ CallWith=ScriptState,
+ RaisesException
+ ] Promise<StorageBucket> open(DOMString name, optional StorageBucketOptions options = {});
+ [CallWith=ScriptState, RaisesException] Promise<sequence<DOMString>> keys();
+ [CallWith=ScriptState, RaisesException, ImplementedAs=Delete] Promise<void> delete(DOMString name);
+};
diff --git a/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_options.idl b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_options.idl
new file mode 100644
index 00000000000..a6c3f5ed9f6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/storage_bucket_options.idl
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/storage-buckets
+
+enum StorageBucketDurability {
+ "strict",
+ "relaxed"
+};
+
+dictionary StorageBucketOptions {
+ DOMString? title = null;
+ boolean persisted = false;
+ StorageBucketDurability durability = "relaxed";
+ unsigned long long? quota = null;
+ DOMTimeStamp? expires = null;
+};
diff --git a/chromium/third_party/blink/renderer/modules/buckets/worker_navigator_storage_buckets.idl b/chromium/third_party/blink/renderer/modules/buckets/worker_navigator_storage_buckets.idl
new file mode 100644
index 00000000000..ed2cc306d3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/buckets/worker_navigator_storage_buckets.idl
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/storage-buckets
+
+[
+ SecureContext,
+ ImplementedAs=StorageBucketManager,
+ RuntimeEnabled=StorageBuckets
+] partial interface WorkerNavigator {
+ [CallWith=ScriptState, RaisesException]
+ readonly attribute StorageBucketManager storageBuckets;
+};
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/DIR_METADATA b/chromium/third_party/blink/renderer/modules/cache_storage/DIR_METADATA
new file mode 100644
index 00000000000..c09c8e08303
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>CacheStorage"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS b/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
index f8dfe14fe70..46d121ddb3e 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/OWNERS
@@ -1,4 +1 @@
file://content/browser/cache_storage/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>CacheStorage
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
index 460ca6e6a17..5482ce90e5a 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -589,7 +589,7 @@ class Cache::FetchHandler final : public ScriptFunction {
// If we return our real result and an exception occurs then unhandled
// promise errors will occur.
ScriptValue rtn =
- ScriptPromise::CastUndefined(GetScriptState()).GetScriptValue();
+ ScriptPromise::CastUndefined(GetScriptState()).AsScriptValue();
// If there is no loader, we were created as a reject handler.
if (!response_loader_) {
@@ -878,11 +878,11 @@ ScriptPromise Cache::keys(ScriptState* script_state,
}
Cache::Cache(GlobalFetch::ScopedFetcher* fetcher,
+ CacheStorageBlobClientList* blob_client_list,
mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>
cache_pending_remote,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : scoped_fetcher_(fetcher),
- blob_client_list_(MakeGarbageCollected<CacheStorageBlobClientList>()) {
+ : scoped_fetcher_(fetcher), blob_client_list_(blob_client_list) {
cache_remote_.Bind(std::move(cache_pending_remote), std::move(task_runner));
}
@@ -1212,7 +1212,8 @@ void Cache::PutImpl(ScriptPromiseResolver* resolver,
BytesConsumer* consumer =
MakeGarbageCollected<BlobBytesConsumer>(context, blob_list[i]);
BodyStreamBuffer* buffer =
- BodyStreamBuffer::Create(script_state, consumer, /*signal=*/nullptr);
+ BodyStreamBuffer::Create(script_state, consumer, /*signal=*/nullptr,
+ /*cached_metadata_handler=*/nullptr);
FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsArrayBuffer();
buffer->StartLoading(loader,
MakeGarbageCollected<CodeCacheHandleCallbackForPut>(
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 74f36eda42e..e37401b47ca 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
@@ -55,6 +55,7 @@ class MODULES_EXPORT Cache : public ScriptWrappable {
public:
Cache(GlobalFetch::ScopedFetcher*,
+ CacheStorageBlobClientList* blob_client_list,
mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>,
scoped_refptr<base::SingleThreadTaskRunner>);
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 432a40115db..38dbb33c17a 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
@@ -119,8 +119,10 @@ ScriptPromise CacheStorage::open(ScriptState* script_state,
cache_name, trace_id,
WTF::Bind(
[](ScriptPromiseResolver* resolver,
- GlobalFetch::ScopedFetcher* fetcher, base::TimeTicks start_time,
- int64_t trace_id, mojom::blink::OpenResultPtr result) {
+ GlobalFetch::ScopedFetcher* fetcher,
+ CacheStorageBlobClientList* blob_client_list,
+ base::TimeTicks start_time, int64_t trace_id,
+ mojom::blink::OpenResultPtr result) {
UMA_HISTOGRAM_TIMES("ServiceWorkerCache.CacheStorage.Renderer.Open",
base::TimeTicks::Now() - start_time);
if (!resolver->GetExecutionContext() ||
@@ -140,13 +142,14 @@ ScriptPromise CacheStorage::open(ScriptState* script_state,
"success");
// See https://bit.ly/2S0zRAS for task types.
resolver->Resolve(MakeGarbageCollected<Cache>(
- fetcher, std::move(result->get_cache()),
+ fetcher, blob_client_list, std::move(result->get_cache()),
resolver->GetExecutionContext()->GetTaskRunner(
blink::TaskType::kMiscPlatformAPI)));
}
},
WrapPersistent(resolver), WrapPersistent(scoped_fetcher_.Get()),
- base::TimeTicks::Now(), trace_id));
+ WrapPersistent(blob_client_list_.Get()), base::TimeTicks::Now(),
+ trace_id));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc
index 29f7ca17c60..ccd7ab70137 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.cc
@@ -83,17 +83,17 @@ void CacheStorageBlobClientList::AddClient(
mojo::PendingReceiver<mojom::blink::BlobReaderClient>
client_pending_receiver,
DataPipeBytesConsumer::CompletionNotifier* completion_notifier) {
- clients.emplace_back(MakeGarbageCollected<Client>(
+ clients_.emplace_back(MakeGarbageCollected<Client>(
this, context, std::move(client_pending_receiver), completion_notifier));
}
void CacheStorageBlobClientList::Trace(Visitor* visitor) const {
- visitor->Trace(clients);
+ visitor->Trace(clients_);
}
void CacheStorageBlobClientList::RevokeClient(Client* client) {
- auto index = clients.Find(client);
- clients.EraseAt(index);
+ auto index = clients_.Find(client);
+ clients_.EraseAt(index);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h
index ed92282d9d9..5bcfd307dba 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h
@@ -8,6 +8,7 @@
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h"
@@ -15,7 +16,7 @@ namespace blink {
// This class holds a list of BlobReaderClient implementations alive until
// they complete or the entire list is garbage collected.
-class CacheStorageBlobClientList
+class MODULES_EXPORT CacheStorageBlobClientList
: public GarbageCollected<CacheStorageBlobClientList> {
public:
CacheStorageBlobClientList() = default;
@@ -32,7 +33,7 @@ class CacheStorageBlobClientList
void RevokeClient(Client* client);
- HeapVector<Member<Client>> clients;
+ HeapVector<Member<Client>> clients_;
DISALLOW_COPY_AND_ASSIGN(CacheStorageBlobClientList);
};
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 7ce8d499404..6bebd1beba5 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
@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/core/fetch/response.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -162,6 +163,12 @@ class ErrorCacheForTests : public mojom::blink::CacheStorageCache {
result->set_status(error_);
std::move(callback).Run(std::move(result));
}
+ void GetAllMatchedEntries(mojom::blink::FetchAPIRequestPtr request,
+ mojom::blink::CacheQueryOptionsPtr query_options,
+ int64_t trace_id,
+ GetAllMatchedEntriesCallback callback) override {
+ NOTREACHED();
+ }
void Keys(mojom::blink::FetchAPIRequestPtr fetch_api_request,
mojom::blink::CacheQueryOptionsPtr query_options,
int64_t trace_id,
@@ -183,6 +190,13 @@ class ErrorCacheForTests : public mojom::blink::CacheStorageCache {
CheckBatchOperationsIfProvided(batch_operations);
std::move(callback).Run(CacheStorageVerboseError::New(error_, String()));
}
+ void WriteSideData(const blink::KURL& url,
+ base::Time expected_response_time,
+ mojo_base::BigBuffer data,
+ int64_t trace_id,
+ WriteSideDataCallback callback) override {
+ NOTREACHED();
+ }
protected:
void CheckUrlIfProvided(const KURL& url) {
@@ -264,7 +278,10 @@ class TestCache : public Cache {
GlobalFetch::ScopedFetcher* fetcher,
mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> remote,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : Cache(fetcher, std::move(remote), std::move(task_runner)) {}
+ : Cache(fetcher,
+ MakeGarbageCollected<CacheStorageBlobClientList>(),
+ std::move(remote),
+ std::move(task_runner)) {}
bool IsAborted() const {
return abort_controller_ && abort_controller_->signal()->aborted();
@@ -753,12 +770,13 @@ TEST_F(CacheStorageTest, Add) {
fetcher->SetExpectedFetchUrl(&url);
Request* request = NewRequestFromUrl(url);
- Response* response = Response::Create(
- GetScriptState(),
- BodyStreamBuffer::Create(
- GetScriptState(),
- MakeGarbageCollected<FormDataBytesConsumer>(content), nullptr),
- content_type, ResponseInit::Create(), exception_state);
+ Response* response =
+ Response::Create(GetScriptState(),
+ BodyStreamBuffer::Create(
+ GetScriptState(),
+ MakeGarbageCollected<FormDataBytesConsumer>(content),
+ nullptr, /*cached_metadata_handler=*/nullptr),
+ content_type, ResponseInit::Create(), exception_state);
fetcher->SetResponse(response);
Vector<mojom::blink::BatchOperationPtr> expected_put_operations(size_t(1));
diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_utils.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_utils.cc
index 7f4936a40c1..d852f2b23b5 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_utils.cc
@@ -29,7 +29,8 @@ Response* CreateEagerResponse(ScriptState* script_state,
MakeGarbageCollected<DataPipeBytesConsumer>(
context->GetTaskRunner(TaskType::kNetworking),
std::move(eager_response->pipe), &completion_notifier),
- nullptr /* AbortSignal */, std::move(response->side_data_blob)));
+ nullptr /* AbortSignal */, /*cached_metadata_handler=*/nullptr,
+ std::move(response->side_data_blob)));
// Create a BlobReaderClient in the provided list. This will track the
// completion of the eagerly read blob and propagate it to the given
diff --git a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
index 3dee2798eee..2a069bf9356 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
@@ -9,8 +9,14 @@ blink_modules_sources("canvas") {
sources = [
"canvas2d/base_rendering_context_2d.cc",
"canvas2d/base_rendering_context_2d.h",
+ "canvas2d/canvas_formatted_text.cc",
+ "canvas2d/canvas_formatted_text.h",
+ "canvas2d/canvas_formatted_text_run.cc",
+ "canvas2d/canvas_formatted_text_run.h",
"canvas2d/canvas_gradient.cc",
"canvas2d/canvas_gradient.h",
+ "canvas2d/canvas_image_source_util.cc",
+ "canvas2d/canvas_image_source_util.h",
"canvas2d/canvas_path.cc",
"canvas2d/canvas_path.h",
"canvas2d/canvas_pattern.cc",
@@ -32,15 +38,22 @@ blink_modules_sources("canvas") {
"htmlcanvas/canvas_context_creation_attributes_helpers.h",
"htmlcanvas/html_canvas_element_module.cc",
"htmlcanvas/html_canvas_element_module.h",
+ "imagebitmap/image_bitmap_factories.cc",
+ "imagebitmap/image_bitmap_factories.h",
"imagebitmap/image_bitmap_rendering_context.cc",
"imagebitmap/image_bitmap_rendering_context.h",
"imagebitmap/image_bitmap_rendering_context_base.cc",
"imagebitmap/image_bitmap_rendering_context_base.h",
+ "imagebitmap/image_bitmap_source_union.h",
"offscreencanvas/offscreen_canvas_module.cc",
"offscreencanvas/offscreen_canvas_module.h",
"offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc",
"offscreencanvas2d/offscreen_canvas_rendering_context_2d.h",
]
+
+ deps = [ "//third_party/blink/renderer/modules/webcodecs" ]
+ allow_circular_includes_from =
+ [ "//third_party/blink/renderer/modules/webcodecs" ]
}
fuzzer_test("canvas_fuzzer") {
diff --git a/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA b/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA
new file mode 100644
index 00000000000..73333465b1f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Canvas"
+}
+team_email: "paint-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/canvas/OWNERS b/chromium/third_party/blink/renderer/modules/canvas/OWNERS
index 4abe99a57af..319149318fa 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/canvas/OWNERS
@@ -6,6 +6,3 @@ yiyix@chromium.org
senorblanco@chromium.org
# lowLatency
mcasas@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
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 efc376143b4..98b485c0911 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
@@ -12,13 +12,9 @@
#include "base/metrics/histogram_functions.h"
#include "base/numerics/checked_math.h"
#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h"
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
#include "third_party/blink/renderer/core/html/canvas/text_metrics.h"
-#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
-#include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_pattern.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/path_2d.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
@@ -36,6 +32,15 @@ const char BaseRenderingContext2D::kLtrDirectionString[] = "ltr";
const char BaseRenderingContext2D::kAutoKerningString[] = "auto";
const char BaseRenderingContext2D::kNormalKerningString[] = "normal";
const char BaseRenderingContext2D::kNoneKerningString[] = "none";
+const char BaseRenderingContext2D::kUltraCondensedString[] = "ultra-condensed";
+const char BaseRenderingContext2D::kExtraCondensedString[] = "extra-condensed";
+const char BaseRenderingContext2D::kCondensedString[] = "condensed";
+const char BaseRenderingContext2D::kSemiCondensedString[] = "semi-condensed";
+const char BaseRenderingContext2D::kNormalStretchString[] = "normal";
+const char BaseRenderingContext2D::kSemiExpandedString[] = "semi-expanded";
+const char BaseRenderingContext2D::kExpandedString[] = "expanded";
+const char BaseRenderingContext2D::kExtraExpandedString[] = "extra-expanded";
+const char BaseRenderingContext2D::kUltraExpandedString[] = "ultra-expanded";
const char BaseRenderingContext2D::kNormalVariantString[] = "normal";
const char BaseRenderingContext2D::kSmallCapsVariantString[] = "small-caps";
const char BaseRenderingContext2D::kAllSmallCapsVariantString[] =
@@ -136,11 +141,11 @@ void BaseRenderingContext2D::RestoreMatrixClipStack(cc::PaintCanvas* c) const {
DCHECK(state_stack_.begin() < state_stack_.end());
for (curr_state = state_stack_.begin(); curr_state < state_stack_.end();
curr_state++) {
- c->setMatrix(SkMatrix::I());
+ c->setMatrix(SkM44());
if (curr_state->Get()) {
curr_state->Get()->PlaybackClips(c);
c->setMatrix(
- TransformationMatrixToSkMatrix(curr_state->Get()->GetTransform()));
+ TransformationMatrix::ToSkM44(curr_state->Get()->GetTransform()));
}
c->save();
}
@@ -175,6 +180,9 @@ void BaseRenderingContext2D::reset() {
DCHECK(c->getDeviceClipBounds(&clip_bounds));
DCHECK(clip_bounds == c->imageInfo().bounds());
#endif
+ // We only want to clear the backing buffer if the surface exists because
+ // this function is also used when the context is lost.
+ clearRect(0, 0, Width(), Height());
}
ValidateStateStack();
origin_tainted_by_content_ = false;
@@ -208,6 +216,15 @@ void BaseRenderingContext2D::IdentifiabilityMaybeUpdateForStyleUnion(
}
}
+RespectImageOrientationEnum
+BaseRenderingContext2D::RespectImageOrientationInternal(
+ CanvasImageSource* image_source) {
+ if ((image_source->IsImageBitmap() || image_source->IsImageElement()) &&
+ image_source->WouldTaintOrigin())
+ return kRespectImageOrientation;
+ return RespectImageOrientation();
+}
+
void BaseRenderingContext2D::strokeStyle(
StringOrCanvasGradientOrCanvasPattern& return_value) const {
ConvertCanvasStyleToUnionType(GetState().StrokeStyle(), return_value);
@@ -474,6 +491,8 @@ void BaseRenderingContext2D::setFilter(
}
void BaseRenderingContext2D::scale(double sx, double sy) {
+ // TODO(crbug.com/1140535): Investigate the performance impact of simply
+ // calling the 3d version of this function
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
if (!c)
return;
@@ -496,6 +515,33 @@ void BaseRenderingContext2D::scale(double sx, double sy) {
path_.Transform(AffineTransform().ScaleNonUniform(1.0 / fsx, 1.0 / fsy));
}
+void BaseRenderingContext2D::scale(double sx, double sy, double sz) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (!std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sz))
+ return;
+
+ TransformationMatrix new_transform = GetState().GetTransform();
+ float fsx = clampTo<float>(sx);
+ float fsy = clampTo<float>(sy);
+ float fsz = clampTo<float>(sz);
+ new_transform.Scale3d(fsx, fsy, fsz);
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ // SkCanvas has no 3d scale method for now
+ TransformationMatrix scale_matrix =
+ TransformationMatrix().Scale3d(fsx, fsy, fsz);
+ c->concat(TransformationMatrix::ToSkM44(scale_matrix));
+ path_.Transform(scale_matrix);
+}
+
void BaseRenderingContext2D::rotate(double angle_in_radians) {
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
if (!c)
@@ -516,10 +562,70 @@ void BaseRenderingContext2D::rotate(double angle_in_radians) {
path_.Transform(AffineTransform().RotateRadians(-angle_in_radians));
}
+// All angles are in radians
+void BaseRenderingContext2D::rotate3d(double rx, double ry, double rz) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (!std::isfinite(rx) || !std::isfinite(ry) || !std::isfinite(rz))
+ return;
+
+ TransformationMatrix rotation_matrix =
+ TransformationMatrix().Rotate3d(rad2deg(rx), rad2deg(ry), rad2deg(rz));
+
+ // Check if the transformation is a no-op and early out if that is the case.
+ TransformationMatrix new_transform =
+ GetState().GetTransform().Rotate3d(rad2deg(rx), rad2deg(ry), rad2deg(rz));
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ // Must call setTransform to set the IsTransformInvertible flag.
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ c->concat(TransformationMatrix::ToSkM44(rotation_matrix));
+ path_.Transform(rotation_matrix.Inverse());
+}
+
+void BaseRenderingContext2D::rotateAxis(double axisX,
+ double axisY,
+ double axisZ,
+ double angle_in_radians) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (!std::isfinite(axisX) || !std::isfinite(axisY) || !std::isfinite(axisZ) ||
+ !std::isfinite(angle_in_radians))
+ return;
+
+ TransformationMatrix rotation_matrix = TransformationMatrix().Rotate3d(
+ axisX, axisY, axisZ, rad2deg(angle_in_radians));
+
+ // Check if the transformation is a no-op and early out if that is the case.
+ TransformationMatrix new_transform = GetState().GetTransform().Rotate3d(
+ axisX, axisY, axisZ, rad2deg(angle_in_radians));
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ // Must call setTransform to set the IsTransformInvertible flag.
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ c->concat(TransformationMatrix::ToSkM44(rotation_matrix));
+ path_.Transform(rotation_matrix.Inverse());
+}
+
void BaseRenderingContext2D::translate(double tx, double ty) {
+ // TODO(crbug.com/1140535): Investigate the performance impact of simply
+ // calling the 3d version of this function
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
if (!c)
return;
+
if (!GetState().IsTransformInvertible())
return;
@@ -537,16 +643,144 @@ void BaseRenderingContext2D::translate(double tx, double ty) {
ModifiableState().SetTransform(new_transform);
if (!GetState().IsTransformInvertible())
return;
+
c->translate(ftx, fty);
path_.Transform(AffineTransform().Translate(-ftx, -fty));
}
+void BaseRenderingContext2D::translate(double tx, double ty, double tz) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (!std::isfinite(tx) || !std::isfinite(ty) || !std::isfinite(tz))
+ return;
+
+ // clamp to float to avoid float cast overflow when used as SkScalar
+ float ftx = clampTo<float>(tx);
+ float fty = clampTo<float>(ty);
+ float ftz = clampTo<float>(ty);
+
+ TransformationMatrix translation_matrix =
+ TransformationMatrix().Translate3d(ftx, fty, ftz);
+
+ // Check if the transformation is a no-op and early out if that is the case.
+ TransformationMatrix new_transform =
+ GetState().GetTransform().Translate3d(ftx, fty, ftz);
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ // We need to call SetTransform() to set the IsTransformInvertible flag.
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ c->concat(TransformationMatrix::ToSkM44(translation_matrix));
+ path_.Transform(translation_matrix.Inverse());
+}
+
+void BaseRenderingContext2D::perspective(double length) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (length == 0 || !std::isfinite(length))
+ return;
+
+ float flength = clampTo<float>(length);
+
+ TransformationMatrix perspective_matrix =
+ TransformationMatrix().ApplyPerspective(flength);
+
+ // Check if the transformation is a no-op and early out if that is the case.
+ TransformationMatrix new_transform =
+ GetState().GetTransform().ApplyPerspective(flength);
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ // We need to call SetTransform() to set the IsTransformInvertible flag.
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ c->concat(TransformationMatrix::ToSkM44(perspective_matrix));
+ path_.Transform(perspective_matrix.Inverse());
+}
+
+void BaseRenderingContext2D::transform(double m11,
+ double m12,
+ double m13,
+ double m14,
+ double m21,
+ double m22,
+ double m23,
+ double m24,
+ double m31,
+ double m32,
+ double m33,
+ double m34,
+ double m41,
+ double m42,
+ double m43,
+ double m44) {
+ cc::PaintCanvas* c = GetOrCreatePaintCanvas();
+ if (!c)
+ return;
+
+ if (!std::isfinite(m11) || !std::isfinite(m12) || !std::isfinite(m13) ||
+ !std::isfinite(m14) || !std::isfinite(m21) || !std::isfinite(m22) ||
+ !std::isfinite(m23) || !std::isfinite(m24) || !std::isfinite(m31) ||
+ !std::isfinite(m32) || !std::isfinite(m33) || !std::isfinite(m34) ||
+ !std::isfinite(m41) || !std::isfinite(m42) || !std::isfinite(m43) ||
+ !std::isfinite(m44))
+ return;
+
+ // clamp to float to avoid float cast overflow when used as SkScalar
+ float fm11 = clampTo<float>(m11);
+ float fm12 = clampTo<float>(m12);
+ float fm13 = clampTo<float>(m13);
+ float fm14 = clampTo<float>(m14);
+ float fm21 = clampTo<float>(m21);
+ float fm22 = clampTo<float>(m22);
+ float fm23 = clampTo<float>(m23);
+ float fm24 = clampTo<float>(m24);
+ float fm31 = clampTo<float>(m31);
+ float fm32 = clampTo<float>(m32);
+ float fm33 = clampTo<float>(m33);
+ float fm34 = clampTo<float>(m34);
+ float fm41 = clampTo<float>(m41);
+ float fm42 = clampTo<float>(m42);
+ float fm43 = clampTo<float>(m43);
+ float fm44 = clampTo<float>(m44);
+
+ TransformationMatrix transform =
+ TransformationMatrix(fm11, fm12, fm13, fm14, fm21, fm22, fm23, fm24, fm31,
+ fm32, fm33, fm34, fm41, fm42, fm43, fm44);
+
+ // Check if the transformation is a no-op and early out if that is the case.
+ TransformationMatrix new_transform = GetState().GetTransform() * transform;
+ if (GetState().GetTransform() == new_transform)
+ return;
+
+ // Must call setTransform to set the IsTransformInvertible flag.
+ ModifiableState().SetTransform(new_transform);
+ if (!GetState().IsTransformInvertible())
+ return;
+
+ c->concat(TransformationMatrix::ToSkM44(transform));
+ path_.Transform(transform.Inverse());
+}
+
void BaseRenderingContext2D::transform(double m11,
double m12,
double m21,
double m22,
double dx,
double dy) {
+ // TODO(crbug.com/1140535) Investigate the performance implications of simply
+ // calling the 3d version above with:
+ // transform(m11, m12, 0, 0, m21, m22, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
+
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
if (!c)
return;
@@ -572,7 +806,7 @@ void BaseRenderingContext2D::transform(double m11,
if (!GetState().IsTransformInvertible())
return;
- c->concat(TransformationMatrixToSkMatrix(transform));
+ c->concat(TransformationMatrix::ToSkM44(transform));
path_.Transform(transform.Inverse());
}
@@ -590,7 +824,8 @@ void BaseRenderingContext2D::resetTransform() {
// resetTransform() resolves the non-invertible CTM state.
ModifiableState().ResetTransform();
- c->setMatrix(TransformationMatrixToSkMatrix(TransformationMatrix()));
+ // Set the SkCanvas' matrix to identity.
+ c->setMatrix(SkM44());
if (invertible_ctm)
path_.Transform(ctm);
@@ -611,37 +846,77 @@ void BaseRenderingContext2D::setTransform(double m11,
return;
resetTransform();
- // clamp to float to avoid float cast overflow when used as SkScalar
- float fm11 = clampTo<float>(m11);
- float fm12 = clampTo<float>(m12);
- float fm21 = clampTo<float>(m21);
- float fm22 = clampTo<float>(m22);
- float fdx = clampTo<float>(dx);
- float fdy = clampTo<float>(dy);
+ transform(m11, m12, m21, m22, dx, dy);
+}
- transform(fm11, fm12, fm21, fm22, fdx, fdy);
+void BaseRenderingContext2D::setTransform(double m11,
+ double m12,
+ double m13,
+ double m14,
+ double m21,
+ double m22,
+ double m23,
+ double m24,
+ double m31,
+ double m32,
+ double m33,
+ double m34,
+ double m41,
+ double m42,
+ double m43,
+ double m44) {
+ if (!std::isfinite(m11) || !std::isfinite(m12) || !std::isfinite(m13) ||
+ !std::isfinite(m14) || !std::isfinite(m21) || !std::isfinite(m22) ||
+ !std::isfinite(m23) || !std::isfinite(m24) || !std::isfinite(m31) ||
+ !std::isfinite(m32) || !std::isfinite(m33) || !std::isfinite(m34) ||
+ !std::isfinite(m41) || !std::isfinite(m42) || !std::isfinite(m43) ||
+ !std::isfinite(m44))
+ return;
+
+ resetTransform();
+ transform(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41,
+ m42, m43, m44);
}
-void BaseRenderingContext2D::setTransform(DOMMatrix2DInit* transform,
+void BaseRenderingContext2D::setTransform(DOMMatrixInit* transform,
ExceptionState& exception_state) {
DOMMatrixReadOnly* m =
- DOMMatrixReadOnly::fromMatrix2D(transform, exception_state);
+ DOMMatrixReadOnly::fromMatrix(transform, exception_state);
if (!m)
return;
- setTransform(m->m11(), m->m12(), m->m21(), m->m22(), m->m41(), m->m42());
+ // The new canvas 2d API supports 3d transforms.
+ // https://github.com/fserb/canvas2D/blob/master/spec/perspective-transforms.md
+ // If it is not enabled, throw 3d information away.
+ if (RuntimeEnabledFeatures::NewCanvas2DAPIEnabled()) {
+ setTransform(m->m11(), m->m12(), m->m13(), m->m14(), m->m21(), m->m22(),
+ m->m23(), m->m24(), m->m31(), m->m32(), m->m33(), m->m34(),
+ m->m41(), m->m42(), m->m43(), m->m44());
+ } else {
+ setTransform(m->m11(), m->m12(), m->m21(), m->m22(), m->m41(), m->m42());
+ }
}
DOMMatrix* BaseRenderingContext2D::getTransform() {
const TransformationMatrix& t = GetState().GetTransform();
DOMMatrix* m = DOMMatrix::Create();
- m->setA(t.A());
- m->setB(t.B());
- m->setC(t.C());
- m->setD(t.D());
- m->setE(t.E());
- m->setF(t.F());
+ m->setM11(t.M11());
+ m->setM12(t.M12());
+ m->setM13(t.M13());
+ m->setM14(t.M14());
+ m->setM21(t.M21());
+ m->setM22(t.M22());
+ m->setM23(t.M23());
+ m->setM24(t.M24());
+ m->setM31(t.M31());
+ m->setM32(t.M32());
+ m->setM33(t.M33());
+ m->setM34(t.M34());
+ m->setM41(t.M41());
+ m->setM42(t.M42());
+ m->setM43(t.M43());
+ m->setM44(t.M44());
return m;
}
@@ -983,63 +1258,6 @@ static inline void ClipRectsToImageRect(const FloatRect& image_rect,
dst_rect->Move(offset);
}
-static inline CanvasImageSource* ToImageSourceInternal(
- const CanvasImageSourceUnion& value,
- ExceptionState& exception_state) {
- if (value.IsCSSImageValue()) {
- return value.GetAsCSSImageValue();
- }
- if (value.IsHTMLImageElement())
- return value.GetAsHTMLImageElement();
- if (value.IsHTMLVideoElement()) {
- HTMLVideoElement* video = value.GetAsHTMLVideoElement();
- video->VideoWillBeDrawnToCanvas();
- return video;
- }
- if (value.IsSVGImageElement())
- return value.GetAsSVGImageElement();
- if (value.IsHTMLCanvasElement()) {
- if (static_cast<HTMLCanvasElement*>(value.GetAsHTMLCanvasElement())
- ->Size()
- .IsEmpty()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "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,
- "The image source is detached");
- return nullptr;
- }
- return value.GetAsImageBitmap();
- }
- if (value.IsOffscreenCanvas()) {
- if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
- ->IsNeutered()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The image source is detached");
- return nullptr;
- }
- if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
- ->Size()
- .IsEmpty()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- "The image argument is an OffscreenCanvas element "
- "with a width or height of 0.");
- return nullptr;
- }
- return value.GetAsOffscreenCanvas();
- }
- NOTREACHED();
- return nullptr;
-}
-
void BaseRenderingContext2D::drawImage(
ScriptState* script_state,
const CanvasImageSourceUnion& image_source,
@@ -1047,10 +1265,11 @@ void BaseRenderingContext2D::drawImage(
double y,
ExceptionState& exception_state) {
CanvasImageSource* image_source_internal =
- ToImageSourceInternal(image_source, exception_state);
+ ToCanvasImageSource(image_source, exception_state);
if (!image_source_internal)
return;
- RespectImageOrientationEnum respect_orientation = RespectImageOrientation();
+ RespectImageOrientationEnum respect_orientation =
+ RespectImageOrientationInternal(image_source_internal);
FloatSize default_object_size(Width(), Height());
FloatSize source_rect_size = image_source_internal->ElementSize(
default_object_size, respect_orientation);
@@ -1070,12 +1289,13 @@ void BaseRenderingContext2D::drawImage(
double height,
ExceptionState& exception_state) {
CanvasImageSource* image_source_internal =
- ToImageSourceInternal(image_source, exception_state);
+ ToCanvasImageSource(image_source, exception_state);
if (!image_source_internal)
return;
FloatSize default_object_size(this->Width(), this->Height());
FloatSize source_rect_size = image_source_internal->ElementSize(
- default_object_size, RespectImageOrientation());
+ default_object_size,
+ RespectImageOrientationInternal(image_source_internal));
drawImage(script_state, image_source_internal, 0, 0, source_rect_size.Width(),
source_rect_size.Height(), x, y, width, height, exception_state);
}
@@ -1093,7 +1313,7 @@ void BaseRenderingContext2D::drawImage(
double dh,
ExceptionState& exception_state) {
CanvasImageSource* image_source_internal =
- ToImageSourceInternal(image_source, exception_state);
+ ToCanvasImageSource(image_source, exception_state);
if (!image_source_internal)
return;
drawImage(script_state, image_source_internal, sx, sy, sw, sh, dx, dy, dw, dh,
@@ -1131,12 +1351,14 @@ bool BaseRenderingContext2D::ShouldDrawImageAntialiased(
dest_rect.Height() * fabs(height_expansion) < 1;
}
-void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c,
- CanvasImageSource* image_source,
- Image* image,
- const FloatRect& src_rect,
- const FloatRect& dst_rect,
- const PaintFlags* flags) {
+void BaseRenderingContext2D::DrawImageInternal(
+ cc::PaintCanvas* c,
+ CanvasImageSource* image_source,
+ Image* image,
+ const FloatRect& src_rect,
+ const FloatRect& dst_rect,
+ const SkSamplingOptions& sampling,
+ const PaintFlags* flags) {
int initial_save_count = c->getSaveCount();
PaintFlags image_flags = *flags;
@@ -1177,7 +1399,8 @@ void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c,
// We always use the image-orientation property on the canvas element
// because the alternative would result in complex rules depending on
// the source of the image.
- RespectImageOrientationEnum respect_orientation = RespectImageOrientation();
+ RespectImageOrientationEnum respect_orientation =
+ RespectImageOrientationInternal(image_source);
FloatRect corrected_src_rect = src_rect;
if (respect_orientation == kRespectImageOrientation &&
!image->HasDefaultOrientation()) {
@@ -1185,7 +1408,7 @@ void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c,
image->SizeAsFloat(kRespectImageOrientation), src_rect);
}
image_flags.setAntiAlias(ShouldDrawImageAntialiased(dst_rect));
- image->Draw(c, image_flags, dst_rect, corrected_src_rect,
+ image->Draw(c, image_flags, dst_rect, corrected_src_rect, sampling,
respect_orientation, Image::kDoNotClampImageToSourceRect,
Image::kSyncDecode);
} else {
@@ -1263,8 +1486,8 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
FloatRect src_rect = NormalizeRect(FloatRect(fsx, fsy, fsw, fsh));
FloatRect dst_rect = NormalizeRect(FloatRect(fdx, fdy, fdw, fdh));
- FloatSize image_size =
- image_source->ElementSize(default_object_size, RespectImageOrientation());
+ FloatSize image_size = image_source->ElementSize(
+ default_object_size, RespectImageOrientationInternal(image_source));
ClipRectsToImageRect(FloatRect(FloatPoint(), image_size), &src_rect,
&dst_rect);
@@ -1285,8 +1508,11 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state,
[this, &image_source, &image, &src_rect, dst_rect](
cc::PaintCanvas* c, const PaintFlags* flags) // draw lambda
{
+ SkSamplingOptions sampling(
+ flags ? flags->getFilterQuality() : kNone_SkFilterQuality,
+ SkSamplingOptions::kMedium_asMipmapLinear);
DrawImageInternal(c, image_source, image.get(), src_rect, dst_rect,
- flags);
+ sampling, flags);
},
[this, &dst_rect](const SkIRect& clip_bounds) // overdraw test lambda
{ return RectContainsTransformedRect(dst_rect, clip_bounds); },
@@ -1445,7 +1671,7 @@ CanvasPattern* BaseRenderingContext2D::createPattern(
const String& repetition_type,
ExceptionState& exception_state) {
CanvasImageSource* image_source_internal =
- ToImageSourceInternal(image_source, exception_state);
+ ToCanvasImageSource(image_source, exception_state);
if (!image_source_internal) {
return nullptr;
}
@@ -1483,7 +1709,8 @@ CanvasPattern* BaseRenderingContext2D::createPattern(
String::Format("The canvas %s is 0.",
image_source
->ElementSize(default_object_size,
- RespectImageOrientation())
+ RespectImageOrientationInternal(
+ image_source))
.Width()
? "height"
: "width"));
@@ -1543,56 +1770,44 @@ bool BaseRenderingContext2D::ComputeDirtyRect(
return true;
}
-ImageDataColorSettings*
-BaseRenderingContext2D::GetColorSettingsAsImageDataColorSettings() const {
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- color_settings->setColorSpace(ColorSpaceAsString());
- if (PixelFormat() == CanvasPixelFormat::kF16)
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- return color_settings;
-}
-
ImageData* BaseRenderingContext2D::createImageData(
ImageData* image_data,
ExceptionState& exception_state) const {
- ImageData* result = nullptr;
- ImageDataColorSettings* color_settings =
- GetColorSettingsAsImageDataColorSettings();
- result = ImageData::Create(image_data->Size(), color_settings);
- if (!result)
- exception_state.ThrowRangeError("Out of memory at ImageData creation");
- return result;
+ return ImageData::ValidateAndCreate(
+ image_data->Size().Width(), image_data->Size().Height(), base::nullopt,
+ image_data->getSettings(), exception_state,
+ ImageData::Context2DErrorMode);
}
ImageData* BaseRenderingContext2D::createImageData(
int sw,
int sh,
ExceptionState& exception_state) const {
- if (!sw || !sh) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kIndexSizeError,
- String::Format("The source %s is 0.", sw ? "height" : "width"));
- return nullptr;
- }
-
- IntSize size(abs(sw), abs(sh));
- ImageData* result = nullptr;
- ImageDataColorSettings* color_settings =
- GetColorSettingsAsImageDataColorSettings();
- result = ImageData::Create(size, color_settings);
-
- if (!result)
- exception_state.ThrowRangeError("Out of memory at ImageData creation");
- return result;
+ ImageDataSettings* image_data_settings = ImageDataSettings::Create();
+ image_data_settings->setColorSpace(kSRGBCanvasColorSpaceName);
+ image_data_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ return ImageData::ValidateAndCreate(std::abs(sw), std::abs(sh), base::nullopt,
+ image_data_settings, exception_state,
+ ImageData::Context2DErrorMode);
}
ImageData* BaseRenderingContext2D::createImageData(
- unsigned width,
- unsigned height,
- ImageDataColorSettings* color_settings,
+ unsigned sw,
+ unsigned sh,
+ ImageDataSettings* image_data_settings,
ExceptionState& exception_state) const {
- return ImageData::CreateImageData(width, height, color_settings,
- exception_state);
+ return ImageData::ValidateAndCreate(sw, sh, base::nullopt,
+ image_data_settings, exception_state,
+ ImageData::Context2DErrorMode);
+}
+
+ImageData* BaseRenderingContext2D::getImageData(
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ ExceptionState& exception_state) {
+ return getImageDataInternal(sx, sy, sw, sh, nullptr, exception_state);
}
ImageData* BaseRenderingContext2D::getImageData(
@@ -1600,6 +1815,18 @@ ImageData* BaseRenderingContext2D::getImageData(
int sy,
int sw,
int sh,
+ ImageDataSettings* image_data_settings,
+ ExceptionState& exception_state) {
+ return getImageDataInternal(sx, sy, sw, sh, image_data_settings,
+ exception_state);
+}
+
+ImageData* BaseRenderingContext2D::getImageDataInternal(
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ ImageDataSettings* image_data_settings,
ExceptionState& exception_state) {
if (!base::CheckMul(sw, sh).IsValid<int>()) {
exception_state.ThrowRangeError("Out of memory at ImageData creation");
@@ -1643,91 +1870,144 @@ ImageData* BaseRenderingContext2D::getImageData(
return nullptr;
}
- IntRect image_data_rect(sx, sy, sw, sh);
- bool hasResourceProvider = CanCreateCanvas2dResourceProvider();
- ImageDataColorSettings* color_settings =
- GetColorSettingsAsImageDataColorSettings();
- if (!hasResourceProvider || isContextLost()) {
- ImageData* result =
- ImageData::Create(image_data_rect.Size(), color_settings);
- if (!result)
- exception_state.ThrowRangeError("Out of memory at ImageData creation");
- return result;
+ const IntRect image_data_rect(sx, sy, sw, sh);
+
+ if (!image_data_settings) {
+ image_data_settings = ImageDataSettings::Create();
+ image_data_settings->setColorSpace(kSRGBCanvasColorSpaceName);
+ image_data_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ }
+
+ const ImageDataStorageFormat storage_format =
+ ImageData::GetImageDataStorageFormat(
+ image_data_settings->storageFormat());
+ if (!CanCreateCanvas2dResourceProvider() || isContextLost()) {
+ return ImageData::ValidateAndCreate(sw, sh, base::nullopt,
+ image_data_settings, exception_state,
+ ImageData::Context2DErrorMode);
}
- const CanvasColorParams& color_params = ColorParams();
// Deferred offscreen canvases might have recorded commands, make sure
// that those get drawn here
FinalizeFrame();
- scoped_refptr<StaticBitmapImage> snapshot = GetImage();
// TODO(crbug.com/1101055): Remove the check for NewCanvas2DAPI flag once
// released.
- // New Canvas2D API utilizes willReadFrequently attribute that let the users
- // indicate if a canvas will be read frequently through getImageData, thus
- // uses CPU rendering from the start in such cases. (crbug.com/1090180)
+ // TODO(crbug.com/1090180): New Canvas2D API utilizes willReadFrequently
+ // attribute that let the users indicate if a canvas will be read frequently
+ // through getImageData, thus uses CPU rendering from the start in such cases.
if (!RuntimeEnabledFeatures::NewCanvas2DAPIEnabled()) {
- // GetImagedata is faster in Unaccelerated canvases
- if (IsAccelerated()) {
+ // GetImagedata is faster in Unaccelerated canvases.
+ // In Desynchronized canvas disabling the acceleration will break
+ // putImageData: crbug.com/1112060.
+ if (IsAccelerated() && !IsDesynchronized()) {
DisableAcceleration();
base::UmaHistogramEnumeration("Blink.Canvas.GPUFallbackToCPU",
GPUFallbackToCPUScenario::kGetImageData);
}
}
- size_t size_in_bytes;
- if (!StaticBitmapImage::GetSizeInBytes(image_data_rect, color_params)
- .AssignIfValid(&size_in_bytes) ||
- size_in_bytes > v8::TypedArray::kMaxLength) {
- exception_state.ThrowRangeError("Out of memory at ImageData creation");
- return nullptr;
- }
-
- bool may_have_stray_area =
- IsAccelerated() // GPU readback may fail silently.
- || StaticBitmapImage::MayHaveStrayArea(snapshot, image_data_rect);
- ArrayBufferContents::InitializationPolicy initialization_policy =
- may_have_stray_area ? ArrayBufferContents::kZeroInitialize
- : ArrayBufferContents::kDontInitialize;
+ scoped_refptr<StaticBitmapImage> snapshot = GetImage();
- ArrayBufferContents contents(
- size_in_bytes, 1, ArrayBufferContents::kNotShared, initialization_policy);
- if (contents.DataLength() != size_in_bytes) {
- exception_state.ThrowRangeError("Out of memory at ImageData creation");
- return nullptr;
+ // Compute the ImageData's SkImageInfo;
+ SkImageInfo image_info;
+ {
+ SkColorType color_type = kRGBA_8888_SkColorType;
+ switch (storage_format) {
+ case kUint8ClampedArrayStorageFormat:
+ color_type = kRGBA_8888_SkColorType;
+ break;
+ case kUint16ArrayStorageFormat:
+ color_type = kR16G16B16A16_unorm_SkColorType;
+ break;
+ case kFloat32ArrayStorageFormat:
+ color_type = kRGBA_F32_SkColorType;
+ break;
+ default:
+ NOTREACHED();
+ }
+ sk_sp<SkColorSpace> color_space = CanvasColorSpaceToSkColorSpace(
+ CanvasColorSpaceFromName(image_data_settings->colorSpace()));
+ image_info = SkImageInfo::Make(sw, sh, color_type, kUnpremul_SkAlphaType,
+ color_space);
}
- if (!StaticBitmapImage::CopyToByteArray(
- snapshot,
- base::span<uint8_t>(reinterpret_cast<uint8_t*>(contents.Data()),
- contents.DataLength()),
- image_data_rect, color_params)) {
- exception_state.ThrowRangeError("Failed to copy image data");
- return nullptr;
+ // Compute the size of and allocate |contents|, the ArrayContentsBuffer.
+ ArrayBufferContents contents;
+ const size_t data_size_bytes = image_info.computeMinByteSize();
+ {
+ if (data_size_bytes > std::numeric_limits<unsigned int>::max()) {
+ exception_state.ThrowRangeError(
+ "Buffer size exceeds maximum heap object size.");
+ return nullptr;
+ }
+ if (SkImageInfo::ByteSizeOverflowed(data_size_bytes) ||
+ data_size_bytes > v8::TypedArray::kMaxLength) {
+ exception_state.ThrowRangeError("Out of memory at ImageData creation");
+ return nullptr;
+ }
+ ArrayBufferContents::InitializationPolicy initialization_policy =
+ ArrayBufferContents::kDontInitialize;
+ if (IsAccelerated()) {
+ // GPU readback may fail silently.
+ initialization_policy = ArrayBufferContents::kZeroInitialize;
+ } else if (snapshot) {
+ // Zero-initialize if some of the readback area is out of bounds.
+ if (image_data_rect.X() < 0 || image_data_rect.Y() < 0 ||
+ image_data_rect.MaxX() > snapshot->Size().Width() ||
+ image_data_rect.MaxY() > snapshot->Size().Height()) {
+ initialization_policy = ArrayBufferContents::kZeroInitialize;
+ }
+ }
+ contents =
+ ArrayBufferContents(data_size_bytes, 1, ArrayBufferContents::kNotShared,
+ initialization_policy);
+ if (contents.DataLength() != data_size_bytes) {
+ exception_state.ThrowRangeError("Out of memory at ImageData creation");
+ return nullptr;
+ }
}
- // Convert pixels to proper storage format if needed
- if (PixelFormat() != CanvasColorParams::GetNativeCanvasPixelFormat()) {
- ImageDataStorageFormat storage_format =
- ImageData::GetImageDataStorageFormat(color_settings->storageFormat());
- NotShared<DOMArrayBufferView> array_buffer_view =
- ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- contents, PixelFormat(), storage_format);
- return ImageData::Create(image_data_rect.Size(), array_buffer_view,
- color_settings);
- }
- if (size_in_bytes > std::numeric_limits<unsigned int>::max()) {
- exception_state.ThrowRangeError(
- "Buffer size exceeds maximum heap object size.");
- return nullptr;
+ // Read pixels into |contents|.
+ if (snapshot) {
+ const bool read_pixels_successful =
+ snapshot->PaintImageForCurrentFrame().readPixels(
+ image_info, contents.Data(), image_info.minRowBytes(), sx, sy);
+ if (!read_pixels_successful) {
+ SkIRect bounds =
+ snapshot->PaintImageForCurrentFrame().GetSkImageInfo().bounds();
+ DCHECK(!bounds.intersect(SkIRect::MakeXYWH(sx, sy, sw, sh)));
+ }
}
- DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(std::move(contents));
- ImageData* imageData = ImageData::Create(
- image_data_rect.Size(),
- NotShared<DOMUint8ClampedArray>(DOMUint8ClampedArray::Create(
- array_buffer, 0, static_cast<unsigned int>(size_in_bytes))),
- color_settings);
+ // Wrap |contents| in an ImageData.
+ DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(std::move(contents));
+ NotShared<DOMArrayBufferView> data_array;
+ switch (storage_format) {
+ case kUint8ClampedArrayStorageFormat: {
+ size_t num_elements = data_size_bytes;
+ data_array = NotShared<DOMArrayBufferView>(
+ DOMUint8ClampedArray::Create(array_buffer, 0, num_elements));
+ break;
+ }
+ case kUint16ArrayStorageFormat: {
+ size_t num_elements = data_size_bytes / 2;
+ data_array = NotShared<DOMArrayBufferView>(
+ DOMUint16Array::Create(array_buffer, 0, num_elements));
+ break;
+ }
+ case kFloat32ArrayStorageFormat: {
+ size_t num_elements = data_size_bytes / 4;
+ data_array = NotShared<DOMArrayBufferView>(
+ DOMFloat32Array::Create(array_buffer, 0, num_elements));
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+ ImageData* image_data = ImageData::ValidateAndCreate(
+ sw, sh, data_array, image_data_settings, exception_state,
+ ImageData::Context2DErrorMode);
if (!IsPaint2D()) {
int scaled_time = getScaledElapsedTime(
@@ -1740,8 +2020,7 @@ ImageData* BaseRenderingContext2D::getImageData(
"Blink.Canvas.GetImageDataScaledDuration.CPU", scaled_time);
}
}
-
- return imageData;
+ return image_data;
}
int BaseRenderingContext2D::getScaledElapsedTime(float width,
@@ -1779,7 +2058,7 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
}
base::TimeTicks start_time = base::TimeTicks::Now();
- if (data->BufferBase()->IsDetached()) {
+ if (data->IsBufferBaseDetached()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The source data has been detached.");
return;
@@ -1828,32 +2107,39 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
// in sRGB color space and use uint8 pixel storage format. We use RGBA pixel
// order for both ImageData and CanvasResourceProvider, therefore no
// additional swizzling is needed.
- CanvasColorParams data_color_params = data->GetCanvasColorParams();
- CanvasColorParams context_color_params =
- CanvasColorParams(ColorParams().ColorSpace(), PixelFormat(), kNonOpaque);
-
- size_t data_length;
- if (!base::CheckMul(data->Size().Area(), context_color_params.BytesPerPixel())
- .AssignIfValid(&data_length))
- return;
-
- if (data_color_params.ColorSpace() != context_color_params.ColorSpace() ||
- data_color_params.PixelFormat() != context_color_params.PixelFormat() ||
- PixelFormat() == CanvasPixelFormat::kF16) {
- std::unique_ptr<uint8_t[]> converted_pixels(new uint8_t[data_length]);
- if (data->ImageDataInCanvasColorSettings(
- ColorParams().ColorSpace(), PixelFormat(), converted_pixels.get(),
- kRGBAColorType)) {
- PutByteArray(converted_pixels.get(),
- IntSize(data->width(), data->height()), source_rect,
- IntPoint(dest_offset));
+ SkPixmap data_pixmap = data->GetSkPixmap();
+ CanvasColorParams data_color_params(
+ data->GetCanvasColorSpace(),
+ data->GetImageDataStorageFormat() != kUint8ClampedArrayStorageFormat
+ ? CanvasPixelFormat::kF16
+ : CanvasPixelFormat::kUint8,
+ kNonOpaque);
+ if (data_color_params.ColorSpace() != GetCanvas2DColorParams().ColorSpace() ||
+ data_color_params.PixelFormat() !=
+ GetCanvas2DColorParams().PixelFormat() ||
+ GetCanvas2DColorParams().PixelFormat() == CanvasPixelFormat::kF16) {
+ SkImageInfo converted_info = data_pixmap.info();
+ converted_info =
+ converted_info.makeColorType(GetCanvas2DColorParams().GetSkColorType());
+ converted_info = converted_info.makeColorSpace(
+ GetCanvas2DColorParams().GetSkColorSpace());
+ if (converted_info.colorType() == kN32_SkColorType)
+ converted_info = converted_info.makeColorType(kRGBA_8888_SkColorType);
+
+ const size_t converted_data_bytes = converted_info.computeMinByteSize();
+ const size_t converted_row_bytes = converted_info.minRowBytes();
+ if (SkImageInfo::ByteSizeOverflowed(converted_data_bytes))
+ return;
+ std::unique_ptr<uint8_t[]> converted_pixels(
+ new uint8_t[converted_data_bytes]);
+ if (data_pixmap.readPixels(converted_info, converted_pixels.get(),
+ converted_row_bytes)) {
+ PutByteArray(
+ SkPixmap(converted_info, converted_pixels.get(), converted_row_bytes),
+ source_rect, IntPoint(dest_offset));
}
} else {
- // 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));
+ PutByteArray(data_pixmap, source_rect, IntPoint(dest_offset));
}
if (!IsPaint2D()) {
@@ -1871,59 +2157,37 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
DidDraw(dest_rect);
}
-void BaseRenderingContext2D::PutByteArray(const unsigned char* source,
- const IntSize& source_size,
+void BaseRenderingContext2D::PutByteArray(const SkPixmap& source,
const IntRect& source_rect,
const IntPoint& dest_point) {
if (!IsCanvas2DBufferValid())
return;
- uint8_t bytes_per_pixel = ColorParams().BytesPerPixel();
-
- DCHECK_GT(source_rect.Width(), 0);
- DCHECK_GT(source_rect.Height(), 0);
- int origin_x = source_rect.X();
+ DCHECK(IntRect(0, 0, source.width(), source.height()).Contains(source_rect));
int dest_x = dest_point.X() + source_rect.X();
DCHECK_GE(dest_x, 0);
DCHECK_LT(dest_x, Width());
- DCHECK_GE(origin_x, 0);
- DCHECK_LT(origin_x, source_rect.MaxX());
-
- int origin_y = source_rect.Y();
int dest_y = dest_point.Y() + source_rect.Y();
DCHECK_GE(dest_y, 0);
DCHECK_LT(dest_y, Height());
- DCHECK_GE(origin_y, 0);
- DCHECK_LT(origin_y, source_rect.MaxY());
- const base::CheckedNumeric<size_t> src_bytes_per_row_checked =
- base::CheckMul(bytes_per_pixel, source_size.Width());
- if (!src_bytes_per_row_checked.IsValid()) {
- VLOG(1) << "Invalid sizes";
- return;
- }
- const size_t src_bytes_per_row = src_bytes_per_row_checked.ValueOrDie();
- const void* src_addr =
- source + origin_y * src_bytes_per_row + origin_x * bytes_per_pixel;
-
- SkAlphaType alpha_type;
- if (kOpaque == ColorParams().GetOpacityMode()) {
+ SkImageInfo info =
+ source.info().makeWH(source_rect.Width(), source_rect.Height());
+ if (kOpaque == GetCanvas2DColorParams().GetOpacityMode()) {
// If the surface is opaque, tell it that we are writing opaque
// pixels. Writing non-opaque pixels to opaque is undefined in
// Skia. There is some discussion about whether it should be
// defined in skbug.com/6157. For now, we can get the desired
// behavior (memcpy) by pretending the write is opaque.
- alpha_type = kOpaque_SkAlphaType;
+ info = info.makeAlphaType(kOpaque_SkAlphaType);
} else {
- alpha_type = kUnpremul_SkAlphaType;
+ info = info.makeAlphaType(kUnpremul_SkAlphaType);
}
-
- SkImageInfo info = SkImageInfo::Make(
- source_rect.Width(), source_rect.Height(), ColorParams().GetSkColorType(),
- alpha_type, ColorParams().GetSkColorSpace());
if (info.colorType() == kN32_SkColorType)
info = info.makeColorType(kRGBA_8888_SkColorType);
- WritePixels(info, src_addr, src_bytes_per_row, dest_x, dest_y);
+
+ WritePixels(info, source.addr(source_rect.X(), source_rect.Y()),
+ source.rowBytes(), dest_x, dest_y);
}
void BaseRenderingContext2D::InflateStrokeRect(FloatRect& rect) const {
@@ -2077,6 +2341,10 @@ String BaseRenderingContext2D::fontKerning() const {
return FontDescription::ToString(GetState().GetFontKerning());
}
+String BaseRenderingContext2D::fontStretch() const {
+ return FontDescription::ToString(GetState().GetFontStretch());
+}
+
String BaseRenderingContext2D::fontVariantCaps() const {
return FontDescription::ToString(GetState().GetFontVariantCaps());
}
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 57554d72d86..679622118be 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
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/geometry/dom_matrix.h"
#include "third_party/blink/renderer/core/html/canvas/image_data.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h"
+#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h"
@@ -24,9 +25,6 @@ class Color;
class Image;
class Path2D;
-typedef CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas
- CanvasImageSourceUnion;
-
class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
public CanvasPath {
public:
@@ -82,21 +80,61 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
void reset();
void scale(double sx, double sy);
+ void scale(double sx, double sy, double sz);
void rotate(double angle_in_radians);
+ void rotate3d(double rx, double ry, double rz);
+ void rotateAxis(double axisX,
+ double axisY,
+ double axisZ,
+ double angle_in_radians);
void translate(double tx, double ty);
+ void translate(double tx, double ty, double tz);
+ void perspective(double length);
void transform(double m11,
double m12,
double m21,
double m22,
double dx,
double dy);
+ void transform(double m11,
+ double m12,
+ double m13,
+ double m14,
+ double m21,
+ double m22,
+ double m23,
+ double m24,
+ double m31,
+ double m32,
+ double m33,
+ double m34,
+ double m41,
+ double m42,
+ double m43,
+ double m44);
+ void setTransform(double m11,
+ double m12,
+ double m13,
+ double m14,
+ double m21,
+ double m22,
+ double m23,
+ double m24,
+ double m31,
+ double m32,
+ double m33,
+ double m34,
+ double m41,
+ double m42,
+ double m43,
+ double m44);
void setTransform(double m11,
double m12,
double m21,
double m22,
double dx,
double dy);
- void setTransform(DOMMatrix2DInit*, ExceptionState&);
+ void setTransform(DOMMatrixInit*, ExceptionState&);
virtual DOMMatrix* getTransform();
virtual void resetTransform();
@@ -185,16 +223,25 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
ImageData* createImageData(int width, int height, ExceptionState&) const;
ImageData* createImageData(unsigned,
unsigned,
- ImageDataColorSettings*,
+ ImageDataSettings*,
ExceptionState&) const;
// For deferred canvases this will have the side effect of drawing recorded
// commands in order to finalize the frame
- virtual ImageData* getImageData(int sx,
- int sy,
- int sw,
- int sh,
- ExceptionState&);
+ ImageData* getImageData(int sx, int sy, int sw, int sh, ExceptionState&);
+ ImageData* getImageData(int sx,
+ int sy,
+ int sw,
+ int sh,
+ ImageDataSettings*,
+ ExceptionState&);
+ virtual ImageData* getImageDataInternal(int sx,
+ int sy,
+ int sw,
+ int sh,
+ ImageDataSettings*,
+ ExceptionState&);
+
void putImageData(ImageData*, int dx, int dy, ExceptionState&);
void putImageData(ImageData*,
int dx,
@@ -244,17 +291,15 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
virtual bool HasAlpha() const = 0;
+ virtual bool IsDesynchronized() const {
+ NOTREACHED();
+ return false;
+ }
+
virtual bool isContextLost() const = 0;
virtual void WillDrawImage(CanvasImageSource*) const {}
- virtual String ColorSpaceAsString() const {
- return kSRGBCanvasColorSpaceName;
- }
- virtual CanvasPixelFormat PixelFormat() const {
- return CanvasColorParams::GetNativeCanvasPixelFormat();
- }
-
void RestoreMatrixClipStack(cc::PaintCanvas*) const;
String textAlign() const;
@@ -268,6 +313,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
String textRendering() const;
String fontKerning() const;
+ String fontStretch() const;
String fontVariantCaps() const;
void Trace(Visitor*) const override;
@@ -350,7 +396,10 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
void UnwindStateStack();
- virtual CanvasColorParams ColorParams() const { return CanvasColorParams(); }
+ // The implementations of this will query the CanvasColorParams from the
+ // CanvasRenderingContext.
+ virtual CanvasColorParams GetCanvas2DColorParams() const = 0;
+
virtual bool WritePixels(const SkImageInfo& orig_info,
const void* pixels,
size_t row_bytes,
@@ -389,6 +438,15 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
static const char kNormalKerningString[];
static const char kNoneKerningString[];
static const char kNormalVariantString[];
+ static const char kUltraCondensedString[];
+ static const char kExtraCondensedString[];
+ static const char kCondensedString[];
+ static const char kSemiCondensedString[];
+ static const char kNormalStretchString[];
+ static const char kSemiExpandedString[];
+ static const char kExpandedString[];
+ static const char kExtraExpandedString[];
+ static const char kUltraExpandedString[];
static const char kSmallCapsVariantString[];
static const char kAllSmallCapsVariantString[];
static const char kPetiteVariantString[];
@@ -434,6 +492,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
Image*,
const FloatRect& src_rect,
const FloatRect& dst_rect,
+ const SkSamplingOptions&,
const PaintFlags*);
void ClipInternal(const Path&, const String& winding_rule_string);
@@ -464,10 +523,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
// such as tainting from a filter applied to the canvas.
void SetOriginTaintedByContent();
- ImageDataColorSettings* GetColorSettingsAsImageDataColorSettings() const;
-
- void PutByteArray(const unsigned char* source,
- const IntSize& source_size,
+ void PutByteArray(const SkPixmap& source,
const IntRect& source_rect,
const IntPoint& dest_point);
virtual bool IsCanvas2DBufferValid() const {
@@ -482,6 +538,9 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
void IdentifiabilityMaybeUpdateForStyleUnion(
const StringOrCanvasGradientOrCanvasPattern& style);
+ RespectImageOrientationEnum RespectImageOrientationInternal(
+ CanvasImageSource*);
+
bool origin_tainted_by_content_;
DISALLOW_COPY_AND_ASSIGN(BaseRenderingContext2D);
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc
new file mode 100644
index 00000000000..87478d8b386
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc
@@ -0,0 +1,187 @@
+// Copyright 2020 The Chromium Authors. 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/canvas/canvas2d/canvas_formatted_text.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/fonts/font_description.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+
+namespace blink {
+
+void CanvasFormattedText::Trace(Visitor* visitor) const {
+ visitor->Trace(text_runs_);
+ ScriptWrappable::Trace(visitor);
+}
+
+CanvasFormattedText* CanvasFormattedText::Create(
+ ExecutionContext* execution_context,
+ const String text) {
+ CanvasFormattedText* canvas_formatted_text =
+ MakeGarbageCollected<CanvasFormattedText>(execution_context);
+ CanvasFormattedTextRun* run =
+ MakeGarbageCollected<CanvasFormattedTextRun>(execution_context, text);
+ canvas_formatted_text->text_runs_.push_back(run);
+ canvas_formatted_text->block_->AddChild(run->GetLayoutObject());
+ return canvas_formatted_text;
+}
+
+CanvasFormattedText::CanvasFormattedText(ExecutionContext* execution_context) {
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+ style->SetDisplay(EDisplay::kBlock);
+ // Refrain from extending the use of document, apart from creating layout
+ // block flow. In the future we should handle execution_context's from worker
+ // threads that do not have a document.
+ auto* window = To<LocalDOMWindow>(execution_context);
+ block_ = LayoutBlockFlow::CreateAnonymous(window->document(), style,
+ LegacyLayout::kAuto);
+ block_->SetIsLayoutNGObjectForCanvasFormattedText(true);
+}
+
+void CanvasFormattedText::Dispose() {
+ // Detach all the anonymous children we added, since block_->Destroy will
+ // destroy them. We want the lifetime of the children to be managed by their
+ // corresponding CanvasFormattedTextRun and not destroyed at this point.
+ while (block_->FirstChild()) {
+ block_->RemoveChild(block_->FirstChild());
+ }
+ AllowDestroyingLayoutObjectInFinalizerScope scope;
+ if (block_)
+ block_->Destroy();
+}
+
+LayoutBlockFlow* CanvasFormattedText::GetLayoutBlock(
+ Document& document,
+ const FontDescription& defaultFont) {
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+ style->SetDisplay(EDisplay::kBlock);
+ style->SetFontDescription(defaultFont);
+ block_->SetStyle(style);
+ return block_;
+}
+
+CanvasFormattedTextRun* CanvasFormattedText::appendRun(
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state) {
+ if (!CheckRunIsNotParented(run, &exception_state))
+ return nullptr;
+ text_runs_.push_back(run);
+ block_->AddChild(run->GetLayoutObject());
+ return run;
+}
+
+CanvasFormattedTextRun* CanvasFormattedText::setRun(
+ unsigned index,
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state) {
+ if (!CheckRunsIndexBound(index, &exception_state) ||
+ !CheckRunIsNotParented(run, &exception_state))
+ return nullptr;
+ block_->AddChild(run->GetLayoutObject(),
+ text_runs_[index]->GetLayoutObject());
+ block_->RemoveChild(text_runs_[index]->GetLayoutObject());
+ text_runs_[index] = run;
+ return text_runs_[index];
+}
+
+CanvasFormattedTextRun* CanvasFormattedText::insertRun(
+ unsigned index,
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state) {
+ if (!CheckRunIsNotParented(run, &exception_state))
+ return nullptr;
+ if (index == text_runs_.size())
+ return appendRun(run, exception_state);
+ if (!CheckRunsIndexBound(index, &exception_state))
+ return nullptr;
+ block_->AddChild(run->GetLayoutObject(),
+ text_runs_[index]->GetLayoutObject());
+ text_runs_.insert(index, run);
+ return text_runs_[index];
+}
+
+void CanvasFormattedText::deleteRun(unsigned index,
+ unsigned length,
+ ExceptionState& exception_state) {
+ if (!CheckRunsIndexBound(index, &exception_state))
+ return;
+ // Protect against overflow, do not perform math like index + length <
+ // text_runs_.size(). The length passed in can be close to INT_MAX.
+ if (text_runs_.size() - index < length) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ ExceptionMessages::IndexExceedsMaximumBound("length", length,
+ text_runs_.size() - index));
+ return;
+ }
+
+ for (wtf_size_t i = index; i < index + length; i++) {
+ block_->RemoveChild(text_runs_[i]->GetLayoutObject());
+ }
+ block_->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kCanvasFormattedTextRunChange);
+ text_runs_.EraseAt(static_cast<wtf_size_t>(index),
+ static_cast<wtf_size_t>(length));
+}
+
+sk_sp<PaintRecord> CanvasFormattedText::PaintFormattedText(
+ Document& document,
+ const FontDescription& font,
+ double x,
+ double y,
+ double wrap_width,
+ FloatRect& bounds) {
+ LayoutBlockFlow* block = GetLayoutBlock(document, font);
+ NGBlockNode block_node(block);
+ NGInlineNode node(block);
+ // Call IsEmptyInline to force prepare layout.
+ if (node.IsEmptyInline())
+ return nullptr;
+
+ // TODO(sushraja) Once we add support for writing mode on the canvas formatted
+ // text, fix this to be not hardcoded horizontal top to bottom.
+ NGConstraintSpaceBuilder builder(
+ WritingMode::kHorizontalTb,
+ {WritingMode::kHorizontalTb, TextDirection::kLtr},
+ /* is_new_fc */ true);
+ LayoutUnit available_logical_width(wrap_width);
+ LogicalSize available_size = {available_logical_width, kIndefiniteSize};
+ builder.SetAvailableSize(available_size);
+ NGConstraintSpace space = builder.ToConstraintSpace();
+ scoped_refptr<const NGLayoutResult> block_results =
+ block_node.Layout(space, nullptr);
+ const auto& fragment =
+ To<NGPhysicalBoxFragment>(block_results->PhysicalFragment());
+ block->RecalcInlineChildrenVisualOverflow();
+ bounds = FloatRect(block->PhysicalVisualOverflowRect());
+
+ PaintController paint_controller(PaintController::Usage::kTransient);
+ paint_controller.UpdateCurrentPaintChunkProperties(nullptr,
+ PropertyTreeState::Root());
+ GraphicsContext graphics_context(paint_controller);
+ PhysicalOffset physical_offset((LayoutUnit(x)), (LayoutUnit(y)));
+ NGBoxFragmentPainter box_fragment_painter(fragment);
+ PaintInfo paint_info(graphics_context, CullRect::Infinite(),
+ PaintPhase::kForeground, kGlobalPaintNormalPhase,
+ kPaintLayerPaintingRenderingClipPathAsMask |
+ kPaintLayerPaintingRenderingResourceSubtree);
+ box_fragment_painter.PaintObject(paint_info, physical_offset);
+ paint_controller.CommitNewDisplayItems();
+ paint_controller.FinishCycle();
+ sk_sp<PaintRecord> recording =
+ paint_controller.GetPaintArtifact().GetPaintRecord(
+ PropertyTreeState::Root());
+ return recording;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h
new file mode 100644
index 00000000000..f3284c1eeba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h
@@ -0,0 +1,129 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text_run.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/modules/modules_export.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_wrappable.h"
+#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
+#include "third_party/blink/renderer/platform/text/bidi_text_run.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/text/text_run_iterator.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class LayoutBlockFlow;
+class FontDescription;
+class Document;
+
+class MODULES_EXPORT CanvasFormattedText final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+ USING_PRE_FINALIZER(CanvasFormattedText, Dispose);
+
+ public:
+ static CanvasFormattedText* Create(ExecutionContext* execution_context) {
+ return MakeGarbageCollected<CanvasFormattedText>(execution_context);
+ }
+
+ static CanvasFormattedText* Create(ExecutionContext* execution_context,
+ const String text);
+
+ static CanvasFormattedText* Create(ExecutionContext* execution_context,
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state) {
+ CanvasFormattedText* canvas_formatted_text =
+ MakeGarbageCollected<CanvasFormattedText>(execution_context);
+ canvas_formatted_text->appendRun(run, exception_state);
+ return canvas_formatted_text;
+ }
+
+ explicit CanvasFormattedText(ExecutionContext* execution_context);
+ CanvasFormattedText(const CanvasFormattedText&) = delete;
+ CanvasFormattedText& operator=(const CanvasFormattedText&) = delete;
+
+ void Trace(Visitor* visitor) const override;
+
+ unsigned length() const { return text_runs_.size(); }
+
+ bool CheckRunsIndexBound(uint32_t index,
+ ExceptionState* exception_state) const {
+ if (index >= text_runs_.size()) {
+ if (exception_state) {
+ exception_state->ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ ExceptionMessages::IndexExceedsMaximumBound("index", index,
+ text_runs_.size()));
+ }
+ return false;
+ }
+ return true;
+ }
+
+ bool CheckRunIsNotParented(CanvasFormattedTextRun* run,
+ ExceptionState* exception_state) const {
+ if (run->GetLayoutObject() && run->GetLayoutObject()->Parent()) {
+ if (exception_state) {
+ exception_state->ThrowDOMException(
+ DOMExceptionCode::kInvalidModificationError,
+ "The run is already a part of a formatted text. Remove it from "
+ "that formatted text before insertion.");
+ }
+ return false;
+ }
+ return true;
+ }
+
+ CanvasFormattedTextRun* getRun(unsigned index,
+ ExceptionState& exception_state) const {
+ if (!CheckRunsIndexBound(index, &exception_state))
+ return nullptr;
+ return text_runs_[index];
+ }
+
+ CanvasFormattedTextRun* appendRun(CanvasFormattedTextRun* run,
+ ExceptionState& exception_state);
+
+ CanvasFormattedTextRun* setRun(unsigned index,
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state);
+
+ CanvasFormattedTextRun* insertRun(unsigned index,
+ CanvasFormattedTextRun* run,
+ ExceptionState& exception_state);
+
+ void deleteRun(unsigned index, ExceptionState& exception_state) {
+ deleteRun(index, 1, exception_state);
+ }
+
+ void deleteRun(unsigned index,
+ unsigned length,
+ ExceptionState& exception_state);
+
+ LayoutBlockFlow* GetLayoutBlock(Document& document,
+ const FontDescription& defaultFont);
+
+ sk_sp<PaintRecord> PaintFormattedText(Document& document,
+ const FontDescription& font,
+ double x,
+ double y,
+ double wrap_width,
+ FloatRect& bounds);
+
+ void Dispose();
+
+ private:
+ HeapVector<Member<CanvasFormattedTextRun>> text_runs_;
+ LayoutBlockFlow* block_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl
new file mode 100644
index 00000000000..0e3b846cf6e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+[
+ RuntimeEnabled=CanvasFormattedText,
+ Exposed=Window
+]
+interface CanvasFormattedText{
+ [CallWith=ExecutionContext] constructor();
+ [CallWith=ExecutionContext] constructor(DOMString text);
+ [CallWith=ExecutionContext, RaisesException] constructor(CanvasFormattedTextRun text);
+
+ [RaisesException] getter CanvasFormattedTextRun getRun(unsigned long index);
+ [RaisesException] CanvasFormattedTextRun appendRun(
+ CanvasFormattedTextRun newRun);
+ [RaisesException] setter CanvasFormattedTextRun setRun(
+ unsigned long index, CanvasFormattedTextRun run);
+ [RaisesException] CanvasFormattedTextRun insertRun(
+ unsigned long index, CanvasFormattedTextRun run);
+ [RaisesException] void deleteRun(unsigned long index);
+ [RaisesException] void deleteRun(unsigned long index, unsigned long length);
+
+ readonly attribute unsigned long length;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc
new file mode 100644
index 00000000000..a09607b2a83
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h"
+
+namespace blink {
+
+CanvasFormattedTextRun::CanvasFormattedTextRun(
+ ExecutionContext* execution_context,
+ const String text)
+ : text_(text) {
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+ style->SetDisplay(EDisplay::kInline);
+ // Refrain from extending the use of document, apart from creating layout
+ // text. In the future we should handle execution_context's from worker
+ // threads that do not have a document.
+ auto* window = To<LocalDOMWindow>(execution_context);
+ layout_text_ =
+ LayoutText::CreateAnonymous(*(window->document()), std::move(style),
+ text.Impl(), LegacyLayout::kAuto);
+ layout_text_->SetIsLayoutNGObjectForCanvasFormattedText(true);
+}
+
+void CanvasFormattedTextRun::Dispose() {
+ AllowDestroyingLayoutObjectInFinalizerScope scope;
+ if (layout_text_)
+ layout_text_->Destroy();
+}
+
+void CanvasFormattedTextRun::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h
new file mode 100644
index 00000000000..5818ae82442
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h
@@ -0,0 +1,50 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_
+
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/layout/layout_text.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/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class MODULES_EXPORT CanvasFormattedTextRun final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+ USING_PRE_FINALIZER(CanvasFormattedTextRun, Dispose);
+
+ public:
+ static CanvasFormattedTextRun* Create(ExecutionContext* execution_context,
+ const String text) {
+ return MakeGarbageCollected<CanvasFormattedTextRun>(execution_context,
+ text);
+ }
+
+ CanvasFormattedTextRun(ExecutionContext*, const String text);
+ CanvasFormattedTextRun(const CanvasFormattedTextRun&) = delete;
+ CanvasFormattedTextRun& operator=(const CanvasFormattedTextRun&) = delete;
+
+ String text() const { return text_; }
+ void setText(const String text) { text_ = text; }
+
+ unsigned length() const { return text_.length(); }
+
+ LayoutText* GetLayoutObject() { return layout_text_; }
+
+ void Trace(Visitor* visitor) const override;
+
+ void Dispose();
+
+ private:
+ String text_;
+
+ LayoutText* layout_text_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl
new file mode 100644
index 00000000000..7e1ea4f1a93
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+[
+ RuntimeEnabled=CanvasFormattedText,
+ Exposed=Window
+]
+interface CanvasFormattedTextRun{
+ [CallWith = ExecutionContext] constructor(DOMString text);
+
+ attribute DOMString text;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc
new file mode 100644
index 00000000000..b388139d389
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc
@@ -0,0 +1,82 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h"
+
+#include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h"
+#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
+#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
+#include "third_party/blink/renderer/core/svg/svg_image_element.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
+
+namespace blink {
+
+CanvasImageSource* ToCanvasImageSource(const CanvasImageSourceUnion& value,
+ ExceptionState& exception_state) {
+ if (value.IsCSSImageValue())
+ return value.GetAsCSSImageValue();
+ if (value.IsHTMLImageElement())
+ return value.GetAsHTMLImageElement();
+ if (value.IsHTMLVideoElement()) {
+ HTMLVideoElement* video = value.GetAsHTMLVideoElement();
+ video->VideoWillBeDrawnToCanvas();
+ return video;
+ }
+ if (value.IsSVGImageElement())
+ return value.GetAsSVGImageElement();
+ if (value.IsHTMLCanvasElement()) {
+ if (static_cast<HTMLCanvasElement*>(value.GetAsHTMLCanvasElement())
+ ->Size()
+ .IsEmpty()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "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,
+ "The image source is detached");
+ return nullptr;
+ }
+ return value.GetAsImageBitmap();
+ }
+ if (value.IsOffscreenCanvas()) {
+ if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
+ ->IsNeutered()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The image source is detached");
+ return nullptr;
+ }
+ if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
+ ->Size()
+ .IsEmpty()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "The image argument is an OffscreenCanvas element "
+ "with a width or height of 0.");
+ return nullptr;
+ }
+ return value.GetAsOffscreenCanvas();
+ }
+ if (value.IsVideoFrame()) {
+ auto* video_frame = static_cast<VideoFrame*>(value.GetAsVideoFrame());
+ if (!video_frame->frame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The VideoFrame has been closed");
+ return nullptr;
+ }
+ return video_frame;
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h
new file mode 100644
index 00000000000..f003578953b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/canvas_image_source.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+class CanvasImageSource;
+
+using CanvasImageSourceUnion =
+ CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame;
+
+MODULES_EXPORT CanvasImageSource* ToCanvasImageSource(
+ const CanvasImageSourceUnion& value,
+ ExceptionState& exception_state);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_
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 bd3bf105d7a..6a67606bfee 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
@@ -50,10 +50,7 @@ namespace blink {
void CanvasPath::closePath() {
if (path_.IsEmpty())
return;
-
- FloatRect bound_rect = path_.BoundingRect();
- if (bound_rect.Width() || bound_rect.Height())
- path_.CloseSubpath();
+ path_.CloseSubpath();
}
void CanvasPath::moveTo(double double_x, double double_y) {
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 22d3464e6e5..b3ef16c347a 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,8 +38,6 @@
#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"
@@ -245,6 +243,9 @@ void CanvasRenderingContext2D::DidSetSurfaceSize() {
void CanvasRenderingContext2D::Trace(Visitor* visitor) const {
visitor->Trace(hit_region_manager_);
+ visitor->Trace(dispatch_context_lost_event_timer_);
+ visitor->Trace(dispatch_context_restored_event_timer_);
+ visitor->Trace(try_restore_context_event_timer_);
visitor->Trace(filter_operations_);
CanvasRenderingContext::Trace(visitor);
BaseRenderingContext2D::Trace(visitor);
@@ -307,12 +308,8 @@ void CanvasRenderingContext2D::WillDrawImage(CanvasImageSource* source) const {
canvas()->WillDrawImageTo2DContext(source);
}
-String CanvasRenderingContext2D::ColorSpaceAsString() const {
- return CanvasRenderingContext::ColorSpaceAsString();
-}
-
-CanvasColorParams CanvasRenderingContext2D::ColorParams() const {
- return CanvasRenderingContext::ColorParams();
+CanvasColorParams CanvasRenderingContext2D::GetCanvas2DColorParams() const {
+ return CanvasRenderingContext::CanvasRenderingContextColorParams();
}
bool CanvasRenderingContext2D::WritePixels(const SkImageInfo& orig_info,
@@ -330,10 +327,6 @@ void CanvasRenderingContext2D::WillOverwriteCanvas() {
canvas()->GetCanvas2DLayerBridge()->WillOverwriteCanvas();
}
-CanvasPixelFormat CanvasRenderingContext2D::PixelFormat() const {
- return ColorParams().PixelFormat();
-}
-
void CanvasRenderingContext2D::Reset() {
// This is a multiple inheritance bootstrap
BaseRenderingContext2D::reset();
@@ -655,11 +648,7 @@ void CanvasRenderingContext2D::UpdateFilterReferences(
filter_operations_ = filters;
}
-void CanvasRenderingContext2D::ResourceContentChanged(InvalidationModeMask) {
- ResourceElementChanged();
-}
-
-void CanvasRenderingContext2D::ResourceElementChanged() {
+void CanvasRenderingContext2D::ResourceContentChanged(SVGResource*) {
ClearFilterReferences();
GetState().ClearResolvedFilter();
}
@@ -690,20 +679,15 @@ scoped_refptr<StaticBitmapImage> blink::CanvasRenderingContext2D::GetImage() {
return canvas()->GetCanvas2DLayerBridge()->NewImageSnapshot();
}
-ImageData* CanvasRenderingContext2D::getImageData(
+ImageData* CanvasRenderingContext2D::getImageDataInternal(
int sx,
int sy,
int sw,
int sh,
+ ImageDataSettings* image_data_settings,
ExceptionState& exception_state) {
- 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);
+ return BaseRenderingContext2D::getImageDataInternal(
+ sx, sy, sw, sh, image_data_settings, exception_state);
}
void CanvasRenderingContext2D::FinalizeFrame() {
@@ -873,6 +857,39 @@ void CanvasRenderingContext2D::setFontKerning(
ModifiableState().SetFontKerning(kerning, Host()->GetFontSelector());
}
+void CanvasRenderingContext2D::setFontStretch(const String& font_stretch) {
+ if (!GetState().HasRealizedFont())
+ setFont(font());
+
+ String font_stretch_string = font_stretch.LowerASCII();
+ FontSelectionValue stretch_vale;
+ if (font_stretch_string == kUltraCondensedString)
+ stretch_vale = UltraCondensedWidthValue();
+ else if (font_stretch_string == kExtraCondensedString)
+ stretch_vale = ExtraCondensedWidthValue();
+ else if (font_stretch_string == kCondensedString)
+ stretch_vale = CondensedWidthValue();
+ else if (font_stretch_string == kSemiCondensedString)
+ stretch_vale = SemiCondensedWidthValue();
+ else if (font_stretch_string == kNormalStretchString)
+ stretch_vale = NormalWidthValue();
+ else if (font_stretch_string == kSemiExpandedString)
+ stretch_vale = SemiExpandedWidthValue();
+ else if (font_stretch_string == kExpandedString)
+ stretch_vale = ExpandedWidthValue();
+ else if (font_stretch_string == kExtraExpandedString)
+ stretch_vale = ExtraExpandedWidthValue();
+ else if (font_stretch_string == kUltraExpandedString)
+ stretch_vale = UltraExpandedWidthValue();
+ else
+ return;
+
+ if (GetState().GetFontStretch() == stretch_vale)
+ return;
+
+ ModifiableState().SetFontStretch(stretch_vale, Host()->GetFontSelector());
+}
+
void CanvasRenderingContext2D::setFontVariantCaps(
const String& font_variant_caps_string) {
if (!GetState().HasRealizedFont())
@@ -952,6 +969,28 @@ TextMetrics* CanvasRenderingContext2D::measureText(const String& text) {
GetState().GetTextAlign(), text);
}
+void CanvasRenderingContext2D::fillFormattedText(
+ CanvasFormattedText* formatted_text,
+ double x,
+ double y,
+ double wrap_width) {
+ if (!formatted_text)
+ return;
+
+ if (!GetState().HasRealizedFont())
+ setFont(font());
+
+ FloatRect bounds;
+ sk_sp<PaintRecord> recording = formatted_text->PaintFormattedText(
+ canvas()->GetDocument(), GetState().GetFontDescription(), x, y,
+ wrap_width, bounds);
+ Draw([recording](cc::PaintCanvas* c, const PaintFlags* flags) // draw lambda
+ { c->drawPicture(recording); },
+ [](const SkIRect& rect) { return false; }, bounds,
+ CanvasRenderingContext2DState::PaintType::kFillPaintType,
+ CanvasRenderingContext2DState::kNoImage);
+}
+
void CanvasRenderingContext2D::DrawTextInternal(
const String& text,
double x,
@@ -1099,8 +1138,8 @@ CanvasRenderingContext2D::getContextAttributes() const {
CanvasRenderingContext2DSettings::Create();
settings->setAlpha(CreationAttributes().alpha);
if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
- settings->setColorSpace(ColorSpaceAsString());
- settings->setPixelFormat(PixelFormatAsString());
+ settings->setColorSpace(GetCanvas2DColorParams().GetColorSpaceAsString());
+ settings->setPixelFormat(GetCanvas2DColorParams().GetPixelFormatAsString());
}
settings->setDesynchronized(Host()->LowLatencyEnabled());
if (RuntimeEnabledFeatures::NewCanvas2DAPIEnabled())
@@ -1151,7 +1190,11 @@ void CanvasRenderingContext2D::DrawFocusRing(const Path& path) {
if (!GetOrCreatePaintCanvas())
return;
- SkColor color = LayoutTheme::GetTheme().FocusRingColor().Rgb();
+ // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
+ SkColor color =
+ LayoutTheme::GetTheme()
+ .FocusRingColor(ComputedStyle::InitialStyle().UsedColorScheme())
+ .Rgb();
const int kFocusRingWidth = 5;
DrawPlatformFocusRing(path.GetSkPath(), GetPaintCanvas(), color,
/*width=*/kFocusRingWidth, /*radius=*/kFocusRingWidth);
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 4e6faada14c..0243cee60c5 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -31,6 +31,7 @@
#include "base/macros.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
@@ -39,6 +40,7 @@
#include "third_party/blink/renderer/core/style/filter_operations.h"
#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h"
+#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -68,8 +70,8 @@ class HitTestCanvasResult;
class Path2D;
class TextMetrics;
-typedef CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas
- CanvasImageSourceUnion;
+using CanvasImageSourceUnion =
+ CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame;
class MODULES_EXPORT CanvasRenderingContext2D final
: public CanvasRenderingContext,
@@ -131,6 +133,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final
void setTextRendering(const String&);
void setFontKerning(const String&);
+ void setFontStretch(const String&);
void setFontVariantCaps(const String&);
void fillText(const String& text, double x, double y);
@@ -141,6 +144,11 @@ class MODULES_EXPORT CanvasRenderingContext2D final
CanvasRenderingContext2DSettings* getContextAttributes() const;
+ void fillFormattedText(CanvasFormattedText* formatted_text,
+ double x,
+ double y,
+ double wrap_width);
+
void drawFocusIfNeeded(Element*);
void drawFocusIfNeeded(Path2D*, Element*);
@@ -165,8 +173,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final
String GetIdFromControl(const Element*) override;
// SVGResourceClient implementation
- void ResourceContentChanged(InvalidationModeMask) override;
- void ResourceElementChanged() override;
+ void ResourceContentChanged(SVGResource*) override;
void UpdateFilterReferences(const FilterOperations&);
void ClearFilterReferences();
@@ -210,13 +217,16 @@ class MODULES_EXPORT CanvasRenderingContext2D final
void Trace(Visitor*) const override;
- ImageData* getImageData(int sx,
- int sy,
- int sw,
- int sh,
- ExceptionState&) override;
+ ImageData* getImageDataInternal(int sx,
+ int sy,
+ int sw,
+ int sh,
+ ImageDataSettings*,
+ ExceptionState&) final;
- CanvasColorParams ColorParamsForTest() const { return ColorParams(); }
+ CanvasColorParams ColorParamsForTest() const {
+ return GetCanvas2DColorParams();
+ }
IdentifiableToken IdentifiableTextToken() const override {
return identifiability_study_helper_.GetToken();
@@ -231,7 +241,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final
}
protected:
- CanvasColorParams ColorParams() const override;
+ CanvasColorParams GetCanvas2DColorParams() const override;
bool WritePixels(const SkImageInfo& orig_info,
const void* pixels,
size_t row_bytes,
@@ -267,14 +277,14 @@ class MODULES_EXPORT CanvasRenderingContext2D final
return CanvasRenderingContext::kContext2D;
}
- String ColorSpaceAsString() const override;
- CanvasPixelFormat PixelFormat() const override;
-
bool IsRenderingContext2D() const override { return true; }
bool IsComposited() const override;
bool IsAccelerated() const override;
bool IsOriginTopLeft() const override;
bool HasAlpha() const override { return CreationAttributes().alpha; }
+ bool IsDesynchronized() const override {
+ return CreationAttributes().desynchronized;
+ }
void SetIsInHiddenPage(bool) override;
void SetIsBeingDisplayed(bool) override;
void Stop() final;
@@ -289,10 +299,12 @@ class MODULES_EXPORT CanvasRenderingContext2D final
LostContextMode context_lost_mode_;
bool context_restorable_;
unsigned try_restore_context_attempt_count_;
- TaskRunnerTimer<CanvasRenderingContext2D> dispatch_context_lost_event_timer_;
- TaskRunnerTimer<CanvasRenderingContext2D>
+ HeapTaskRunnerTimer<CanvasRenderingContext2D>
+ dispatch_context_lost_event_timer_;
+ HeapTaskRunnerTimer<CanvasRenderingContext2D>
dispatch_context_restored_event_timer_;
- TaskRunnerTimer<CanvasRenderingContext2D> try_restore_context_event_timer_;
+ HeapTaskRunnerTimer<CanvasRenderingContext2D>
+ try_restore_context_event_timer_;
FilterOperations filter_operations_;
HashMap<String, FontDescription> fonts_resolved_using_current_style_;
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 78e1c791ef2..f2ea9e5ee4c 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
@@ -39,7 +39,8 @@ typedef (CSSImageValue or
HTMLVideoElement or
HTMLCanvasElement or
ImageBitmap or
- OffscreenCanvas) CanvasImageSource;
+ OffscreenCanvas or
+ VideoFrame) CanvasImageSource;
enum CanvasFillRule { "nonzero", "evenodd" };
enum ImageSmoothingQuality {"low", "medium", "high"};
@@ -57,11 +58,22 @@ interface CanvasRenderingContext2D {
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void scale(unrestricted double x, unrestricted double y, unrestricted double z);
void rotate(unrestricted double angle);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotate3d(unrestricted double angleX, unrestricted double angleY, unrestricted double angleZ);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle);
void translate(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z);
+ [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length);
void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
+ [RuntimeEnabled=NewCanvas2DAPI] void transform(
+ unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
+ unrestricted double m21, unrestricted double m22, unrestricted double m23, unrestricted double m24,
+ unrestricted double m31, unrestricted double m32, unrestricted double m33, unrestricted double m34,
+ unrestricted double m41, unrestricted double m42, unrestricted double m43, unrestricted double m44
+ );
void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
- [RaisesException] void setTransform(optional DOMMatrix2DInit transform = {});
+ [RaisesException] void setTransform(optional DOMMatrixInit transform = {});
DOMMatrix getTransform();
void resetTransform();
@@ -116,6 +128,9 @@ interface CanvasRenderingContext2D {
void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
TextMetrics measureText(DOMString text);
+ // Render entire CanvasFormattedText with line wrapping (one-shot)
+ [RuntimeEnabled=CanvasFormattedText] void fillFormattedText(CanvasFormattedText formattedText, double x, double y, double wrapWidth);
+
// drawing images
[CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y);
[CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y, unrestricted double width, unrestricted double height);
@@ -134,7 +149,8 @@ interface CanvasRenderingContext2D {
[RaisesException] void putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight);
// 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 getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, ImageDataSettings imageDataSettings);
+ [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh, ImageDataSettings imageDataSettings);
// Context state
// Should be merged with WebGL counterpart in CanvasRenderingContext, once no-longer experimental
@@ -159,11 +175,12 @@ 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")
- [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0)
- [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontKerning; // "auto", "normal", "none" (default: "auto")
+ [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontStretch; // "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" (default: normal)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontVariantCaps; // "normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps" (default: "normal")
+ [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString textRendering; // "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision" (default: auto)
+ [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0)
};
-CanvasRenderingContext2D includes CanvasPath; \ No newline at end of file
+CanvasRenderingContext2D includes CanvasPath;
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 28d4ca0cf6d..d030abae93f 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
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h"
#include <memory>
+#include "base/metrics/histogram_functions.h"
#include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
#include "third_party/blink/renderer/core/css/resolver/style_builder.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
@@ -28,7 +29,6 @@
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
-#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
static const char defaultFont[] = "10px sans-serif";
static const char defaultFilter[] = "none";
@@ -105,6 +105,7 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState(
word_spacing_(other.word_spacing_),
text_rendering_mode_(other.text_rendering_mode_),
font_kerning_(other.font_kerning_),
+ font_stretch_(other.font_stretch_),
font_variant_caps_(other.font_variant_caps_),
realized_font_(other.realized_font_),
is_transform_invertible_(other.is_transform_invertible_),
@@ -291,6 +292,16 @@ void CanvasRenderingContext2DState::SetFontKerning(
SetFont(font_description, selector);
}
+void CanvasRenderingContext2DState::SetFontStretch(
+ FontSelectionValue font_stretch,
+ FontSelector* selector) {
+ DCHECK(realized_font_);
+ FontDescription font_description(GetFontDescription());
+ font_description.SetStretch(font_stretch);
+ font_stretch_ = font_stretch;
+ SetFont(font_description, selector);
+}
+
void CanvasRenderingContext2DState::SetFontVariantCaps(
FontDescription::FontVariantCaps font_variant_caps,
FontSelector* selector) {
@@ -486,24 +497,24 @@ SkDrawLooper* CanvasRenderingContext2DState::ShadowAndForegroundDrawLooper()
sk_sp<PaintFilter> CanvasRenderingContext2DState::ShadowOnlyImageFilter()
const {
+ using ShadowMode = DropShadowPaintFilter::ShadowMode;
if (!shadow_only_image_filter_) {
const auto sigma = BlurRadiusToStdDev(shadow_blur_);
shadow_only_image_filter_ = sk_make_sp<DropShadowPaintFilter>(
shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma,
- shadow_color_, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
- nullptr);
+ shadow_color_, ShadowMode::kDrawShadowOnly, nullptr);
}
return shadow_only_image_filter_;
}
sk_sp<PaintFilter>
CanvasRenderingContext2DState::ShadowAndForegroundImageFilter() const {
+ using ShadowMode = DropShadowPaintFilter::ShadowMode;
if (!shadow_and_foreground_image_filter_) {
const auto sigma = BlurRadiusToStdDev(shadow_blur_);
shadow_and_foreground_image_filter_ = sk_make_sp<DropShadowPaintFilter>(
shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma,
- shadow_color_,
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, nullptr);
+ shadow_color_, ShadowMode::kDrawShadowAndForeground, nullptr);
}
return shadow_and_foreground_image_filter_;
}
@@ -591,6 +602,9 @@ void CanvasRenderingContext2DState::UpdateFilterQuality() const {
if (!image_smoothing_enabled_) {
UpdateFilterQualityWithSkFilterQuality(kNone_SkFilterQuality);
} else {
+ base::UmaHistogramExactLinear("Blink.Canvas.ImageSmoothingQuality",
+ static_cast<int>(image_smoothing_quality_),
+ static_cast<int>(kLast_SkFilterQuality) + 1);
UpdateFilterQualityWithSkFilterQuality(image_smoothing_quality_);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
index e4559b94190..237a1a8af61 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
@@ -24,6 +24,12 @@ class CanvasStyle;
class CSSValue;
class Element;
+enum ShadowMode {
+ kDrawShadowAndForeground,
+ kDrawShadowOnly,
+ kDrawForegroundOnly
+};
+
class CanvasRenderingContext2DState final
: public GarbageCollected<CanvasRenderingContext2DState>,
public FontSelectorClient {
@@ -144,6 +150,9 @@ class CanvasRenderingContext2DState final
FontSelector* selector);
FontDescription::Kerning GetFontKerning() const { return font_kerning_; }
+ void SetFontStretch(FontSelectionValue font_stretch, FontSelector* selector);
+ FontSelectionValue GetFontStretch() const { return font_stretch_; }
+
void SetFontVariantCaps(FontDescription::FontVariantCaps font_kerning,
FontSelector* selector);
FontDescription::FontVariantCaps GetFontVariantCaps() const {
@@ -267,6 +276,7 @@ class CanvasRenderingContext2DState final
float word_spacing_{0};
TextRenderingMode text_rendering_mode_{TextRenderingMode::kAutoTextRendering};
FontDescription::Kerning font_kerning_{FontDescription::kAutoKerning};
+ FontSelectionValue font_stretch_{NormalWidthValue()};
FontDescription::FontVariantCaps font_variant_caps_{
FontDescription::kCapsNormal};
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 2dfcebff125..896a32b5cea 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
@@ -231,8 +231,8 @@ void CanvasRenderingContext2DTest::SetUp() {
canvas_element_ = To<HTMLCanvasElement>(GetDocument().getElementById("c"));
- full_image_data_ = ImageData::Create(IntSize(10, 10));
- partial_image_data_ = ImageData::Create(IntSize(2, 2));
+ full_image_data_ = ImageData::Create(10, 10, ASSERT_NO_EXCEPTION);
+ partial_image_data_ = ImageData::Create(2, 2, ASSERT_NO_EXCEPTION);
NonThrowableExceptionState exception_state;
auto* opaque_gradient =
@@ -310,12 +310,12 @@ class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge {
class FakeCanvasResourceProvider : public CanvasResourceProvider {
public:
FakeCanvasResourceProvider(const IntSize& size,
- CanvasColorParams color_params,
+ CanvasResourceParams params,
RasterModeHint hint)
: CanvasResourceProvider(CanvasResourceProvider::kBitmap,
size,
kLow_SkFilterQuality,
- color_params,
+ params,
/*is_origin_top_left=*/false,
nullptr,
nullptr),
@@ -608,7 +608,7 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) {
IntSize size(10, 10);
std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider =
- std::make_unique<FakeCanvasResourceProvider>(size, CanvasColorParams(),
+ std::make_unique<FakeCanvasResourceProvider>(size, CanvasResourceParams(),
RasterModeHint::kPreferGPU);
std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge =
std::make_unique<FakeCanvas2DLayerBridge>(size, CanvasColorParams(),
@@ -639,8 +639,8 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) {
std::make_unique<FakeCanvas2DLayerBridge>(size2, CanvasColorParams(),
RasterModeHint::kPreferGPU);
std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider2 =
- std::make_unique<FakeCanvasResourceProvider>(size2, CanvasColorParams(),
- RasterModeHint::kPreferGPU);
+ std::make_unique<FakeCanvasResourceProvider>(
+ size2, CanvasResourceParams(), RasterModeHint::kPreferGPU);
anotherCanvas->SetResourceProviderForTesting(
std::move(fake_resource_provider2), std::move(fake_2d_layer_bridge2),
size2);
@@ -757,6 +757,7 @@ static void TestDrawSingleHighBitDepthPNGOnCanvas(
String filepath,
CanvasRenderingContext2D* context,
Document& document,
+ ImageDataSettings* color_setting,
ScriptState* script_state) {
scoped_refptr<SharedBuffer> pixel_buffer = test::ReadFromFile(filepath);
ASSERT_EQ(false, pixel_buffer->IsEmpty());
@@ -782,10 +783,11 @@ static void TestDrawSingleHighBitDepthPNGOnCanvas(
image_union.SetHTMLImageElement(image_element);
context->drawImage(script_state, image_union, 0, 0, exception_state);
- ImageData* image_data = context->getImageData(0, 0, 2, 2, exception_state);
+ ImageData* image_data =
+ context->getImageData(0, 0, 2, 2, color_setting, exception_state);
ImageDataArray data_array = image_data->data();
ASSERT_TRUE(data_array.IsFloat32Array());
- DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().View();
+ DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().Get();
ASSERT_EQ(16u, buffer_view->byteLength() / buffer_view->TypeSize());
float* actual_pixels = static_cast<float*>(buffer_view->BaseAddress());
@@ -826,6 +828,9 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas(
StringBuilder path;
path.Append(test::CoreTestDataPath());
path.Append("/png-16bit/");
+ ImageDataSettings* color_setting = ImageDataSettings::Create();
+ color_setting->setStorageFormat(kFloat32ArrayStorageFormatName);
+ color_setting->setColorSpace(canvas_color_space);
for (auto interlace : interlace_status) {
for (auto color_profile : color_profiles) {
for (auto alpha : alpha_status) {
@@ -837,7 +842,8 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas(
full_path.Append(alpha);
full_path.Append(".png");
TestDrawSingleHighBitDepthPNGOnCanvas(full_path.ToString(), context,
- document, script_state);
+ document, color_setting,
+ script_state);
}
}
}
@@ -845,8 +851,8 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas(
TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnP3Canvas) {
TestDrawHighBitDepthPNGsOnWideGamutCanvas(
- "p3", GetDocument(), Persistent<HTMLCanvasElement>(CanvasElement()),
- GetScriptState());
+ "display-p3", GetDocument(),
+ Persistent<HTMLCanvasElement>(CanvasElement()), GetScriptState());
}
TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnRec2020Canvas) {
@@ -897,14 +903,14 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings(
kRec2020CanvasColorSpaceName, kP3CanvasColorSpaceName};
CanvasPixelFormat canvas_pixel_formats[] = {
- CanvasPixelFormat::kRGBA8,
+ CanvasPixelFormat::kUint8,
CanvasPixelFormat::kF16,
CanvasPixelFormat::kF16,
CanvasPixelFormat::kF16,
};
String canvas_pixel_format_names[] = {
- kRGBA8CanvasPixelFormatName, kF16CanvasPixelFormatName,
+ kUint8CanvasPixelFormatName, kF16CanvasPixelFormatName,
kF16CanvasPixelFormatName, kF16CanvasPixelFormatName,
kF16CanvasPixelFormatName};
@@ -937,7 +943,7 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings(
EXPECT_EQ(data_length, data_f32->length());
ImageData* image_data = nullptr;
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
+ ImageDataSettings* image_data_settings = ImageDataSettings::Create();
int num_pixels = data_length / 4;
// At most four bytes are needed for Float32 output per color component.
@@ -947,7 +953,7 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings(
// Loop through different possible combinations of image data color space and
// storage formats and create the respective test image data objects.
for (unsigned i = 0; i < num_image_data_color_spaces; i++) {
- color_settings->setColorSpace(
+ image_data_settings->setColorSpace(
ImageData::CanvasColorSpaceName(image_data_color_spaces[i]));
for (unsigned j = 0; j < num_image_data_storage_formats; j++) {
@@ -955,24 +961,40 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings(
switch (image_data_storage_formats[j]) {
case kUint8ClampedArrayStorageFormat:
data_array = data_u8;
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ image_data_settings->setStorageFormat(
+ kUint8ClampedArrayStorageFormatName);
break;
case kUint16ArrayStorageFormat:
data_array = data_u16;
- color_settings->setStorageFormat(kUint16ArrayStorageFormatName);
+ image_data_settings->setStorageFormat(kUint16ArrayStorageFormatName);
break;
case kFloat32ArrayStorageFormat:
data_array = data_f32;
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
+ image_data_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
break;
default:
NOTREACHED();
}
- image_data =
- ImageData::CreateForTest(IntSize(2, 2), data_array, color_settings);
+ image_data = ImageData::CreateForTest(IntSize(2, 2), data_array,
+ image_data_settings);
+ unsigned k = static_cast<unsigned>(canvas_colorspace_setting);
+ ImageDataSettings* canvas_color_setting = ImageDataSettings::Create();
+ canvas_color_setting->setColorSpace(
+ ImageData::CanvasColorSpaceName(canvas_color_spaces[k]));
+ switch (canvas_pixel_formats[k]) {
+ case CanvasPixelFormat::kUint8:
+ canvas_color_setting->setStorageFormat(
+ kUint8ClampedArrayStorageFormatName);
+ break;
+ case CanvasPixelFormat::kF16:
+ canvas_color_setting->setStorageFormat(
+ kFloat32ArrayStorageFormatName);
+ break;
+ default:
+ NOTREACHED();
+ }
- unsigned k = (unsigned)(canvas_colorspace_setting);
// Convert the original data used to create ImageData to the
// canvas color space and canvas pixel format.
EXPECT_TRUE(
@@ -995,14 +1017,15 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings(
NonThrowableExceptionState exception_state;
context->putImageData(image_data, 0, 0, exception_state);
- void* pixels_from_get_image_data =
- context->getImageData(0, 0, 2, 2, exception_state)
- ->BufferBase()
- ->Data();
+ const void* pixels_from_get_image_data =
+ context
+ ->getImageData(0, 0, 2, 2, canvas_color_setting, exception_state)
+ ->GetSkPixmap()
+ .addr();
ColorCorrectionTestUtils::CompareColorCorrectedPixels(
pixels_from_get_image_data, pixels_converted_manually.get(),
num_pixels,
- (canvas_pixel_formats[k] == CanvasPixelFormat::kRGBA8)
+ (canvas_pixel_formats[k] == CanvasPixelFormat::kUint8)
? kPixelFormat_8888
: kPixelFormat_ffff,
kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
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 4fecf3deee9..83c1620d804 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
@@ -73,7 +73,9 @@ static Color CurrentColor(HTMLCanvasElement* canvas) {
}
static mojom::blink::ColorScheme ColorScheme(HTMLCanvasElement* canvas) {
- if (canvas && canvas->isConnected()) {
+ if (!canvas)
+ return mojom::blink::ColorScheme::kLight;
+ if (canvas->isConnected()) {
if (auto* style = canvas->GetComputedStyle())
return style->UsedColorScheme();
}
@@ -91,7 +93,7 @@ bool ParseColorOrCurrentColor(Color& parsed_color,
case kParsedSystemColor:
return true;
case kParsedCurrentColor:
- parsed_color = canvas ? CurrentColor(canvas) : Color::kBlack;
+ parsed_color = CurrentColor(canvas);
return true;
case kParseFailed:
return false;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
index 3ce12a41b15..106a7bb5c18 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
@@ -108,7 +108,7 @@ TEST_P(HTMLCanvasElementModuleTest, LowLatencyCanvasCompositorFrameOpacity) {
auto context_provider = viz::TestContextProvider::Create();
context_provider->UnboundTestContextGL()
->set_supports_gpu_memory_buffer_format(
- CanvasColorParams().GetBufferFormat(), true);
+ CanvasColorParams().GetAsResourceParams().GetBufferFormat(), true);
InitializeSharedGpuContext(context_provider.get());
// To intercept SubmitCompositorFrame/SubmitCompositorFrameSync messages sent
diff --git a/chromium/third_party/blink/renderer/modules/canvas/idls.gni b/chromium/third_party/blink/renderer/modules/canvas/idls.gni
index 582575f4478..96740fd08c7 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/canvas/idls.gni
@@ -5,6 +5,8 @@
import("//third_party/blink/renderer/config.gni")
modules_idl_files = [
+ "canvas2d/canvas_formatted_text.idl",
+ "canvas2d/canvas_formatted_text_run.idl",
"canvas2d/canvas_gradient.idl",
"canvas2d/canvas_pattern.idl",
"canvas2d/canvas_rendering_context_2d.idl",
@@ -22,6 +24,8 @@ modules_dictionary_idl_files = [
modules_dependency_idl_files = [
"canvas2d/canvas_path.idl",
"htmlcanvas/html_canvas_element_module.idl",
+ "imagebitmap/window_create_image_bitmap.idl",
+ "imagebitmap/worker_create_image_bitmap.idl",
"offscreencanvas/offscreen_canvas_module.idl",
]
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
new file mode 100644
index 00000000000..d111834f2af
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
@@ -0,0 +1,384 @@
+/*
+ * 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/canvas/imagebitmap/image_bitmap_factories.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/location.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_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/fileapi/blob.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
+#include "third_party/blink/renderer/core/html/canvas/image_data.h"
+#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
+#include "third_party/blink/renderer/core/svg/svg_image_element.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+namespace {
+// This enum is used in a UMA histogram.
+enum CreateImageBitmapSource {
+ kCreateImageBitmapSourceBlob = 0,
+ kCreateImageBitmapSourceImageBitmap = 1,
+ kCreateImageBitmapSourceImageData = 2,
+ kCreateImageBitmapSourceHTMLCanvasElement = 3,
+ kCreateImageBitmapSourceHTMLImageElement = 4,
+ kCreateImageBitmapSourceHTMLVideoElement = 5,
+ kCreateImageBitmapSourceOffscreenCanvas = 6,
+ kCreateImageBitmapSourceSVGImageElement = 7,
+ kCreateImageBitmapSourceVideoFrame = 8,
+ kMaxValue = kCreateImageBitmapSourceVideoFrame,
+};
+
+} // namespace
+
+static inline ImageBitmapSource* ToImageBitmapSourceInternal(
+ const ImageBitmapSourceUnion& value,
+ const ImageBitmapOptions* options,
+ bool has_crop_rect) {
+ if (value.IsHTMLVideoElement()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceHTMLVideoElement);
+ return value.GetAsHTMLVideoElement();
+ }
+ if (value.IsHTMLImageElement()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceHTMLImageElement);
+ return value.GetAsHTMLImageElement();
+ }
+ if (value.IsSVGImageElement()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceSVGImageElement);
+ return value.GetAsSVGImageElement();
+ }
+ if (value.IsHTMLCanvasElement()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceHTMLCanvasElement);
+ return value.GetAsHTMLCanvasElement();
+ }
+ if (value.IsBlob()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceBlob);
+ return value.GetAsBlob();
+ }
+ if (value.IsImageData()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceImageData);
+ return value.GetAsImageData();
+ }
+ if (value.IsImageBitmap()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceImageBitmap);
+ return value.GetAsImageBitmap();
+ }
+ if (value.IsOffscreenCanvas()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceOffscreenCanvas);
+ return value.GetAsOffscreenCanvas();
+ }
+ if (value.IsVideoFrame()) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource",
+ kCreateImageBitmapSourceVideoFrame);
+ return value.GetAsVideoFrame();
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob(
+ ScriptState* script_state,
+ ImageBitmapSource* bitmap_source,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions* options) {
+ DCHECK(script_state->ContextIsValid());
+ ImageBitmapFactories& factory = From(*ExecutionContext::From(script_state));
+ ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::Create(
+ factory, crop_rect, options, script_state);
+ factory.AddLoader(loader);
+ loader->LoadBlobAsync(static_cast<Blob*>(bitmap_source));
+ return loader->Promise();
+}
+
+ScriptPromise ImageBitmapFactories::CreateImageBitmap(
+ ScriptState* script_state,
+ const ImageBitmapSourceUnion& bitmap_source,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ WebFeature feature = WebFeature::kCreateImageBitmap;
+ UseCounter::Count(ExecutionContext::From(script_state), feature);
+ ImageBitmapSource* bitmap_source_internal =
+ ToImageBitmapSourceInternal(bitmap_source, options, false);
+ if (!bitmap_source_internal)
+ return ScriptPromise();
+ return CreateImageBitmap(script_state, bitmap_source_internal,
+ base::Optional<IntRect>(), options, exception_state);
+}
+
+ScriptPromise ImageBitmapFactories::CreateImageBitmap(
+ ScriptState* script_state,
+ const ImageBitmapSourceUnion& bitmap_source,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ WebFeature feature = WebFeature::kCreateImageBitmap;
+ UseCounter::Count(ExecutionContext::From(script_state), feature);
+ ImageBitmapSource* bitmap_source_internal =
+ ToImageBitmapSourceInternal(bitmap_source, options, true);
+ if (!bitmap_source_internal)
+ return ScriptPromise();
+ base::Optional<IntRect> crop_rect = IntRect(sx, sy, sw, sh);
+ return CreateImageBitmap(script_state, bitmap_source_internal, crop_rect,
+ options, exception_state);
+}
+
+ScriptPromise ImageBitmapFactories::CreateImageBitmap(
+ ScriptState* script_state,
+ ImageBitmapSource* bitmap_source,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ if (crop_rect && (crop_rect->Width() == 0 || crop_rect->Height() == 0)) {
+ exception_state.ThrowRangeError(String::Format(
+ "The crop rect %s is 0.", crop_rect->Width() ? "height" : "width"));
+ return ScriptPromise();
+ }
+
+ if (bitmap_source->IsBlob()) {
+ return CreateImageBitmapFromBlob(script_state, bitmap_source, crop_rect,
+ options);
+ }
+
+ if (bitmap_source->BitmapSourceSize().Width() == 0 ||
+ bitmap_source->BitmapSourceSize().Height() == 0) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ String::Format(
+ "The source image %s is 0.",
+ bitmap_source->BitmapSourceSize().Width() ? "height" : "width"));
+ return ScriptPromise();
+ }
+
+ return bitmap_source->CreateImageBitmap(script_state, crop_rect, options,
+ exception_state);
+}
+
+const char ImageBitmapFactories::kSupplementName[] = "ImageBitmapFactories";
+
+ImageBitmapFactories& ImageBitmapFactories::From(ExecutionContext& context) {
+ ImageBitmapFactories* supplement =
+ Supplement<ExecutionContext>::From<ImageBitmapFactories>(context);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<ImageBitmapFactories>();
+ Supplement<ExecutionContext>::ProvideTo(context, supplement);
+ }
+ return *supplement;
+}
+
+void ImageBitmapFactories::AddLoader(ImageBitmapLoader* loader) {
+ pending_loaders_.insert(loader);
+}
+
+void ImageBitmapFactories::DidFinishLoading(ImageBitmapLoader* loader) {
+ DCHECK(pending_loaders_.Contains(loader));
+ pending_loaders_.erase(loader);
+}
+
+void ImageBitmapFactories::Trace(Visitor* visitor) const {
+ visitor->Trace(pending_loaders_);
+ Supplement<ExecutionContext>::Trace(visitor);
+}
+
+ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(
+ ImageBitmapFactories& factory,
+ base::Optional<IntRect> crop_rect,
+ ScriptState* script_state,
+ const ImageBitmapOptions* options)
+ : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
+ loader_(std::make_unique<FileReaderLoader>(
+ FileReaderLoader::kReadAsArrayBuffer,
+ this,
+ GetExecutionContext()->GetTaskRunner(TaskType::kFileReading))),
+ factory_(&factory),
+ resolver_(MakeGarbageCollected<ScriptPromiseResolver>(script_state)),
+ crop_rect_(crop_rect),
+ options_(options) {}
+
+void ImageBitmapFactories::ImageBitmapLoader::LoadBlobAsync(Blob* blob) {
+ loader_->Start(blob->GetBlobDataHandle());
+}
+
+ImageBitmapFactories::ImageBitmapLoader::~ImageBitmapLoader() {
+ DCHECK(!loader_);
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::RejectPromise(
+ ImageBitmapRejectionReason reason) {
+ switch (reason) {
+ case kUndecodableImageBitmapRejectionReason:
+ resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError,
+ "The source image could not be decoded."));
+ break;
+ case kAllocationFailureImageBitmapRejectionReason:
+ resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError,
+ "The ImageBitmap could not be allocated."));
+ break;
+ default:
+ NOTREACHED();
+ }
+ loader_.reset();
+ factory_->DidFinishLoading(this);
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::ContextDestroyed() {
+ if (loader_)
+ factory_->DidFinishLoading(this);
+ loader_.reset();
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() {
+ auto contents = loader_->TakeContents();
+ loader_.reset();
+ if (!contents.IsValid()) {
+ RejectPromise(kAllocationFailureImageBitmapRejectionReason);
+ return;
+ }
+ ScheduleAsyncImageBitmapDecoding(std::move(contents));
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) {
+ RejectPromise(kUndecodableImageBitmapRejectionReason);
+}
+
+namespace {
+void DecodeImageOnDecoderThread(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ ArrayBufferContents contents,
+ ImageDecoder::AlphaOption alpha_option,
+ ColorBehavior color_behavior,
+ WTF::CrossThreadOnceFunction<
+ void(sk_sp<SkImage>, const ImageOrientationEnum)> result_callback) {
+ const bool data_complete = true;
+ std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
+ SegmentReader::CreateFromSkData(
+ SkData::MakeWithoutCopy(contents.Data(), contents.DataLength())),
+ data_complete, alpha_option, ImageDecoder::kDefaultBitDepth,
+ color_behavior);
+ sk_sp<SkImage> frame;
+ ImageOrientationEnum orientation = ImageOrientationEnum::kDefault;
+ if (decoder) {
+ orientation = decoder->Orientation().Orientation();
+ frame = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
+ }
+ PostCrossThreadTask(*task_runner, FROM_HERE,
+ CrossThreadBindOnce(std::move(result_callback),
+ std::move(frame), orientation));
+}
+} // namespace
+
+void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding(
+ ArrayBufferContents contents) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ Thread::Current()->GetTaskRunner();
+ ImageDecoder::AlphaOption alpha_option =
+ options_->premultiplyAlpha() != "none"
+ ? ImageDecoder::AlphaOption::kAlphaPremultiplied
+ : ImageDecoder::AlphaOption::kAlphaNotPremultiplied;
+ ColorBehavior color_behavior = options_->colorSpaceConversion() == "none"
+ ? ColorBehavior::Ignore()
+ : ColorBehavior::Tag();
+ worker_pool::PostTask(
+ FROM_HERE,
+ CrossThreadBindOnce(
+ DecodeImageOnDecoderThread, std::move(task_runner),
+ std::move(contents), alpha_option, color_behavior,
+ CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader::
+ ResolvePromiseOnOriginalThread,
+ WrapCrossThreadWeakPersistent(this))));
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::ResolvePromiseOnOriginalThread(
+ sk_sp<SkImage> frame,
+ const ImageOrientationEnum orientation) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!frame) {
+ RejectPromise(kUndecodableImageBitmapRejectionReason);
+ return;
+ }
+ DCHECK(frame->width());
+ DCHECK(frame->height());
+ scoped_refptr<StaticBitmapImage> image =
+ UnacceleratedStaticBitmapImage::Create(std::move(frame), orientation);
+
+ image->SetOriginClean(true);
+ auto* image_bitmap =
+ MakeGarbageCollected<ImageBitmap>(image, crop_rect_, options_);
+ if (image_bitmap && image_bitmap->BitmapImage()) {
+ resolver_->Resolve(image_bitmap);
+ } else {
+ RejectPromise(kAllocationFailureImageBitmapRejectionReason);
+ return;
+ }
+ factory_->DidFinishLoading(this);
+}
+
+void ImageBitmapFactories::ImageBitmapLoader::Trace(Visitor* visitor) const {
+ ExecutionContextLifecycleObserver::Trace(visitor);
+ visitor->Trace(factory_);
+ visitor->Trace(resolver_);
+ visitor->Trace(options_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
new file mode 100644
index 00000000000..69f0dedd350
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
@@ -0,0 +1,213 @@
+/*
+ * 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_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
+
+#include <memory>
+
+#include "base/single_thread_task_runner.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/image_bitmap_source.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
+#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/bindings/name_client.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+class SkImage;
+
+namespace blink {
+
+class Blob;
+class ExecutionContext;
+class ImageBitmapSource;
+
+class MODULES_EXPORT ImageBitmapFactories final
+ : public GarbageCollected<ImageBitmapFactories>,
+ public Supplement<ExecutionContext>,
+ public NameClient {
+ public:
+ static const char kSupplementName[];
+
+ static ScriptPromise CreateImageBitmap(ScriptState*,
+ const ImageBitmapSourceUnion&,
+ const ImageBitmapOptions*,
+ ExceptionState&);
+ static ScriptPromise CreateImageBitmap(ScriptState*,
+ const ImageBitmapSourceUnion&,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ const ImageBitmapOptions*,
+ ExceptionState&);
+ static ScriptPromise CreateImageBitmap(ScriptState*,
+ ImageBitmapSource*,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions*,
+ ExceptionState&);
+
+ // window.createImageBitmap()
+ static ScriptPromise createImageBitmap(
+ ScriptState* script_state,
+ LocalDOMWindow&,
+ const ImageBitmapSourceUnion& bitmap_source,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ return CreateImageBitmap(script_state, bitmap_source, options,
+ exception_state);
+ }
+ static ScriptPromise createImageBitmap(
+ ScriptState* script_state,
+ LocalDOMWindow&,
+ const ImageBitmapSourceUnion& bitmap_source,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ return CreateImageBitmap(script_state, bitmap_source, sx, sy, sw, sh,
+ options, exception_state);
+ }
+
+ // worker.createImageBitmap()
+ static ScriptPromise createImageBitmap(
+ ScriptState* script_state,
+ WorkerGlobalScope&,
+ const ImageBitmapSourceUnion& bitmap_source,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ return CreateImageBitmap(script_state, bitmap_source, options,
+ exception_state);
+ }
+ static ScriptPromise createImageBitmap(
+ ScriptState* script_state,
+ WorkerGlobalScope&,
+ const ImageBitmapSourceUnion& bitmap_source,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ const ImageBitmapOptions* options,
+ ExceptionState& exception_state) {
+ return CreateImageBitmap(script_state, bitmap_source, sx, sy, sw, sh,
+ options, exception_state);
+ }
+
+ virtual ~ImageBitmapFactories() = default;
+
+ void Trace(Visitor*) const override;
+ const char* NameInHeapSnapshot() const override {
+ return "ImageBitmapLoader";
+ }
+
+ private:
+ class ImageBitmapLoader final : public GarbageCollected<ImageBitmapLoader>,
+ public ExecutionContextLifecycleObserver,
+ public FileReaderLoaderClient {
+ public:
+ static ImageBitmapLoader* Create(ImageBitmapFactories& factory,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions* options,
+ ScriptState* script_state) {
+ return MakeGarbageCollected<ImageBitmapLoader>(factory, crop_rect,
+ script_state, options);
+ }
+
+ ImageBitmapLoader(ImageBitmapFactories&,
+ base::Optional<IntRect> crop_rect,
+ ScriptState*,
+ const ImageBitmapOptions*);
+
+ void LoadBlobAsync(Blob*);
+ ScriptPromise Promise() { return resolver_->Promise(); }
+
+ void Trace(Visitor*) const override;
+
+ ~ImageBitmapLoader() override;
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ enum ImageBitmapRejectionReason {
+ kUndecodableImageBitmapRejectionReason,
+ kAllocationFailureImageBitmapRejectionReason,
+ };
+
+ void RejectPromise(ImageBitmapRejectionReason);
+
+ void ScheduleAsyncImageBitmapDecoding(ArrayBufferContents);
+ void ResolvePromiseOnOriginalThread(sk_sp<SkImage>,
+ const ImageOrientationEnum);
+
+ // ExecutionContextLifecycleObserver
+ void ContextDestroyed() override;
+
+ // FileReaderLoaderClient
+ void DidStartLoading() override {}
+ void DidReceiveData() override {}
+ void DidFinishLoading() override;
+ void DidFail(FileErrorCode) override;
+
+ std::unique_ptr<FileReaderLoader> loader_;
+ Member<ImageBitmapFactories> factory_;
+ Member<ScriptPromiseResolver> resolver_;
+ base::Optional<IntRect> crop_rect_;
+ Member<const ImageBitmapOptions> options_;
+ };
+
+ static ImageBitmapFactories& From(ExecutionContext&);
+ static ScriptPromise CreateImageBitmapFromBlob(
+ ScriptState*,
+ ImageBitmapSource*,
+ base::Optional<IntRect> crop_rect,
+ const ImageBitmapOptions*);
+
+ void AddLoader(ImageBitmapLoader*);
+ void DidFinishLoading(ImageBitmapLoader*);
+
+ HeapHashSet<Member<ImageBitmapLoader>> pending_loaders_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
index 4b94289ec16..6d57d4e62e1 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
@@ -109,7 +109,8 @@ bool ImageBitmapRenderingContextBase::PushFrame() {
cc::PaintFlags paint_flags;
paint_flags.setBlendMode(SkBlendMode::kSrc);
Host()->ResourceProvider()->Canvas()->drawImage(
- image->PaintImageForCurrentFrame(), 0, 0, &paint_flags);
+ image->PaintImageForCurrentFrame(), 0, 0, SkSamplingOptions(),
+ &paint_flags);
scoped_refptr<CanvasResource> resource =
Host()->ResourceProvider()->ProduceCanvasResource();
Host()->PushFrame(
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h
new file mode 100644
index 00000000000..7f2c0f047d2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/image_bitmap_source.h"
+
+namespace blink {
+
+using ImageBitmapSourceUnion =
+ HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvasOrVideoFrame;
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl
new file mode 100644
index 00000000000..8cf42d0f1c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://html.spec.whatwg.org/C/#imagebitmapsource
+typedef (HTMLImageElement or
+ SVGImageElement or
+ HTMLVideoElement or
+ HTMLCanvasElement or
+ Blob or
+ ImageData or
+ ImageBitmap or
+ OffscreenCanvas or
+ VideoFrame) ImageBitmapSource;
+
+[
+ ImplementedAs=ImageBitmapFactories
+] partial interface Window {
+ // https://html.spec.whatwg.org/#windoworworkerglobalscope
+ [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
+ ImageBitmapSource imageBitmap, optional ImageBitmapOptions options = {});
+ [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
+ ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {});
+};
diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl
new file mode 100644
index 00000000000..ee0f155d8bc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ ImplementedAs=ImageBitmapFactories
+] partial interface WorkerGlobalScope {
+ // https://html.spec.whatwg.org/#windoworworkerglobalscope
+ [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
+ ImageBitmapSource imageBitmap, optional ImageBitmapOptions options = {});
+ [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
+ ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {});
+};
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
index 472c8aa6a88..92ffb0ee1e4 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
@@ -148,7 +148,7 @@ TEST_P(OffscreenCanvasTest, CompositorFrameOpacity) {
const bool context_alpha = GetParam().alpha;
const auto canvas_resource = CanvasResourceSharedBitmap::Create(
- offscreen_canvas().Size(), CanvasColorParams(), nullptr /* provider */,
+ offscreen_canvas().Size(), CanvasResourceParams(), nullptr /* provider */,
kLow_SkFilterQuality);
EXPECT_TRUE(!!canvas_resource);
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 eba6275b84f..aa61e529143 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
@@ -136,6 +136,7 @@ void OffscreenCanvasRenderingContext2D::FlushRecording() {
return;
GetCanvasResourceProvider()->FlushCanvas();
+ GetCanvasResourceProvider()->ReleaseLockedImages();
}
void OffscreenCanvasRenderingContext2D::FinalizeFrame() {
@@ -316,16 +317,9 @@ bool OffscreenCanvasRenderingContext2D::IsPaintable() const {
return Host()->ResourceProvider();
}
-String OffscreenCanvasRenderingContext2D::ColorSpaceAsString() const {
- return CanvasRenderingContext::ColorSpaceAsString();
-}
-
-CanvasPixelFormat OffscreenCanvasRenderingContext2D::PixelFormat() const {
- return ColorParams().PixelFormat();
-}
-
-CanvasColorParams OffscreenCanvasRenderingContext2D::ColorParams() const {
- return CanvasRenderingContext::ColorParams();
+CanvasColorParams OffscreenCanvasRenderingContext2D::GetCanvas2DColorParams()
+ const {
+ return CanvasRenderingContext::CanvasRenderingContextColorParams();
}
bool OffscreenCanvasRenderingContext2D::WritePixels(
@@ -535,6 +529,40 @@ void OffscreenCanvasRenderingContext2D::setFontKerning(
ModifiableState().SetFontKerning(kerning, Host()->GetFontSelector());
}
+void OffscreenCanvasRenderingContext2D::setFontStretch(
+ const String& font_stretch) {
+ if (!GetState().HasRealizedFont())
+ setFont(font());
+
+ String font_stretch_string = font_stretch.LowerASCII();
+ FontSelectionValue stretch_vale;
+ if (font_stretch_string == kUltraCondensedString)
+ stretch_vale = UltraCondensedWidthValue();
+ else if (font_stretch_string == kExtraCondensedString)
+ stretch_vale = ExtraCondensedWidthValue();
+ else if (font_stretch_string == kCondensedString)
+ stretch_vale = CondensedWidthValue();
+ else if (font_stretch_string == kSemiCondensedString)
+ stretch_vale = SemiCondensedWidthValue();
+ else if (font_stretch_string == kNormalStretchString)
+ stretch_vale = NormalWidthValue();
+ else if (font_stretch_string == kSemiExpandedString)
+ stretch_vale = SemiExpandedWidthValue();
+ else if (font_stretch_string == kExpandedString)
+ stretch_vale = ExpandedWidthValue();
+ else if (font_stretch_string == kExtraExpandedString)
+ stretch_vale = ExtraExpandedWidthValue();
+ else if (font_stretch_string == kUltraExpandedString)
+ stretch_vale = UltraExpandedWidthValue();
+ else
+ return;
+
+ if (GetState().GetFontStretch() == stretch_vale)
+ return;
+
+ ModifiableState().SetFontStretch(stretch_vale, Host()->GetFontSelector());
+}
+
void OffscreenCanvasRenderingContext2D::setFontVariantCaps(
const String& font_variant_caps_string) {
if (!GetState().HasRealizedFont())
diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index 5d5b0db0f86..42c9ddcb80f 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -82,6 +82,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
void setTextWordSpacing(const double word_spacing);
void setTextRendering(const String&);
void setFontKerning(const String&);
+ void setFontStretch(const String&);
void setFontVariantCaps(const String&);
void fillText(const String& text, double x, double y);
@@ -122,6 +123,9 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
void ValidateStateStackWithCanvas(const cc::PaintCanvas*) const final;
bool HasAlpha() const final { return CreationAttributes().alpha; }
+ bool IsDesynchronized() const final {
+ return CreationAttributes().desynchronized;
+ }
bool isContextLost() const override;
ImageBitmap* TransferToImageBitmap(ScriptState*) final;
@@ -143,7 +147,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
}
protected:
- CanvasColorParams ColorParams() const override;
+ CanvasColorParams GetCanvas2DColorParams() const override;
bool WritePixels(const SkImageInfo& orig_info,
const void* pixels,
size_t row_bytes,
@@ -167,8 +171,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
scoped_refptr<CanvasResource> ProduceCanvasResource();
- String ColorSpaceAsString() const override;
- CanvasPixelFormat PixelFormat() const override;
SkIRect dirty_rect_for_commit_;
bool is_valid_size_ = false;
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 78d97b46178..50727f9025c 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
@@ -21,11 +21,22 @@
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void scale(unrestricted double x, unrestricted double y, unrestricted double z);
void rotate(unrestricted double angle);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotate3d(unrestricted double angleX, unrestricted double angleY, unrestricted double angleZ);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle);
void translate(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z);
+ [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length);
void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
+ [RuntimeEnabled=NewCanvas2DAPI] void transform(
+ unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
+ unrestricted double m21, unrestricted double m22, unrestricted double m23, unrestricted double m24,
+ unrestricted double m31, unrestricted double m32, unrestricted double m33, unrestricted double m34,
+ unrestricted double m41, unrestricted double m42, unrestricted double m43, unrestricted double m44
+ );
void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
- [RaisesException] void setTransform(optional DOMMatrix2DInit transform = {});
+ [RaisesException] void setTransform(optional DOMMatrixInit transform = {});
DOMMatrix getTransform();
void resetTransform();
@@ -89,7 +100,8 @@
// 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 getImageData(long sx, long sy, long sw, long sh, ImageDataSettings imageDataSettings);
+ [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(long sw, long sh, ImageDataSettings imageDataSettings);
// Line caps/joins
attribute unrestricted double lineWidth; // (default 1)
@@ -107,11 +119,12 @@
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")
- [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0)
- [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontKerning; // "auto", "normal", "none" (default: "auto")
+ [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontStretch; // "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" (default: normal)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontVariantCaps; // "normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps" (default: "normal")
+ [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0)
[RuntimeEnabled=NewCanvas2DAPI] attribute DOMString textRendering; // "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision" (default: auto)
+ [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0)
};
OffscreenCanvasRenderingContext2D includes CanvasPath;
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/DIR_METADATA b/chromium/third_party/blink/renderer/modules/clipboard/DIR_METADATA
new file mode 100644
index 00000000000..0fd680e90f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/clipboard/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>DataTransfer"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/OWNERS b/chromium/third_party/blink/renderer/modules/clipboard/OWNERS
index 9b7f5d3e07b..e75672699c9 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/clipboard/OWNERS
@@ -5,6 +5,3 @@ huangdarwin@chromium.org
garykac@chromium.org
pwnall@chromium.org
jsbell@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>DataTransfer
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index f84c35290bd..33b2d9f4a0f 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -272,8 +272,10 @@ void ClipboardPromise::OnReadAvailableFormatNames(
clipboard_item_data_.ReserveInitialCapacity(format_names.size());
for (const String& format_name : format_names) {
- clipboard_item_data_.emplace_back(format_name,
- /* Placeholder value. */ nullptr);
+ if (ClipboardWriter::IsValidType(format_name, is_raw_)) {
+ clipboard_item_data_.emplace_back(format_name,
+ /* Placeholder value. */ nullptr);
+ }
}
ReadNextRepresentation();
}
@@ -434,8 +436,9 @@ void ClipboardPromise::RequestPermission(
}
constexpr char kFeaturePolicyMessage[] =
- "The Clipboard API has been blocked because of a Feature Policy applied "
- "to the current document. See https://goo.gl/EuHzyv for more details.";
+ "The Clipboard API has been blocked because of a permissions policy "
+ "applied to the current document. See https://goo.gl/EuHzyv for more "
+ "details.";
if ((permission == mojom::blink::PermissionName::CLIPBOARD_READ &&
!window.IsFeatureEnabled(
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index 25a2ce0133d..62abb810749 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -15,12 +15,12 @@
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_item.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_reader.h"
-#include "third_party/blink/renderer/modules/clipboard/clipboard_writer.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
namespace blink {
+class ClipboardWriter;
class ScriptPromiseResolver;
class LocalFrame;
class ExecutionContext;
@@ -42,7 +42,7 @@ class ClipboardPromise final : public GarbageCollected<ClipboardPromise>,
const String&);
ClipboardPromise(ExecutionContext*, ScriptState*);
- virtual ~ClipboardPromise();
+ ~ClipboardPromise() override;
// Completes current write and starts next write.
void CompleteWriteRepresentation();
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 f0a1f98096a..f370565643c 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
+#include "third_party/blink/renderer/modules/clipboard/clipboard_writer.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"
@@ -220,7 +221,7 @@ class ClipboardHtmlReader final : public ClipboardReader {
}
};
-// Reads SVG from the System Clipboard as a Blob with image/svg content.
+// Reads SVG from the System Clipboard as a Blob with image/svg+xml content.
class ClipboardSvgReader final : public ClipboardReader {
public:
ClipboardSvgReader(SystemClipboard* system_clipboard,
@@ -303,6 +304,7 @@ class ClipboardSvgReader final : public ClipboardReader {
ClipboardReader* ClipboardReader::Create(SystemClipboard* system_clipboard,
const String& mime_type,
ClipboardPromise* promise) {
+ DCHECK(ClipboardWriter::IsValidType(mime_type, /*is_raw=*/false));
if (mime_type == kMimeTypeImagePng)
return MakeGarbageCollected<ClipboardImageReader>(system_clipboard,
promise);
@@ -315,7 +317,9 @@ ClipboardReader* ClipboardReader::Create(SystemClipboard* system_clipboard,
if (mime_type == kMimeTypeImageSvg &&
RuntimeEnabledFeatures::ClipboardSvgEnabled())
return MakeGarbageCollected<ClipboardSvgReader>(system_clipboard, promise);
- // The MIME type is not supported.
+
+ NOTREACHED()
+ << "IsValidType() and Create() have inconsistent implementations.";
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.h
index af847af5bb3..f66dcb15ae4 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.h
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.h
@@ -20,8 +20,10 @@ class ClipboardPromise;
// Reading a type from the system clipboard to a Blob is accomplished by:
// (1) Reading - the format from the system clipboard.
// (2) Encoding - the system clipboard's contents for a format. Encoding may be
-// time-consuming, and so is done on a background thread whenever possible.
-// (3) Writing - the decoded contents to a Blob.
+// time-consuming, so it is done on a background thread whenever possible.
+// An example where encoding is done on the main thread is HTML, where
+// Blink's HTML encoder can only be used on the main thread.
+// (3) Writing - the encoded contents to a Blob.
//
// ClipboardReader takes as input a ClipboardPromise, from which it expects
// a clipboard format, and to which it provides a Blob containing an encoded
@@ -38,7 +40,7 @@ class ClipboardPromise;
// ClipboardReader::NextRead().
class ClipboardReader : public GarbageCollected<ClipboardReader> {
public:
- // Returns nullptr if there is no implementation for the given mime_type.
+ // ClipboardWriter::IsValidType() must return true for `mime_type`.
static ClipboardReader* Create(SystemClipboard* system_clipboard,
const String& mime_type,
ClipboardPromise* promise);
@@ -59,9 +61,12 @@ class ClipboardReader : public GarbageCollected<ClipboardReader> {
virtual void NextRead(Vector<uint8_t> utf8_bytes) = 0;
SystemClipboard* system_clipboard() { return system_clipboard_; }
- // This ClipboardPromise owns this ClipboardReader.
+ // This ClipboardPromise owns this ClipboardReader. Subclasses use `promise_`
+ // to report the Blob output, or to obtain the execution context.
Member<ClipboardPromise> promise_;
+ // Every subclass method that runs on the main thread should
+ // DCHECK_CALLED_ON_VALID_SEQUENCE with this checker.
SEQUENCE_CHECKER(sequence_checker_);
private:
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 cec48308f21..48469de5608 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -16,7 +16,6 @@
#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
-#include "third_party/blink/renderer/modules/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"
@@ -28,7 +27,7 @@ namespace blink {
namespace { // anonymous namespace for ClipboardWriter's derived classes.
-// Writes a blob with image/png content to the System Clipboard.
+// Writes a Blob with image/png content to the System Clipboard.
class ClipboardImageWriter final : public ClipboardWriter {
public:
ClipboardImageWriter(SystemClipboard* system_clipboard,
@@ -59,7 +58,7 @@ class ClipboardImageWriter final : public ClipboardWriter {
true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth,
ColorBehavior::Tag());
sk_sp<SkImage> image = nullptr;
- // |decoder| is nullptr if |png_data| doesn't begin with the PNG signature.
+ // `decoder` is nullptr if `png_data` doesn't begin with the PNG signature.
if (decoder)
image = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
@@ -74,6 +73,8 @@ class ClipboardImageWriter final : public ClipboardWriter {
promise_->RejectFromReadOrDecodeFailure();
return;
}
+ if (!promise_->GetLocalFrame())
+ return;
SkBitmap bitmap;
image->asLegacyBitmap(&bitmap);
system_clipboard()->WriteImage(std::move(bitmap));
@@ -81,7 +82,7 @@ class ClipboardImageWriter final : public ClipboardWriter {
}
};
-// Writes a blob with text/plain content to the System Clipboard.
+// Writes a Blob with text/plain content to the System Clipboard.
class ClipboardTextWriter final : public ClipboardWriter {
public:
ClipboardTextWriter(SystemClipboard* system_clipboard,
@@ -118,12 +119,15 @@ class ClipboardTextWriter final : public ClipboardWriter {
}
void Write(const String& text) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!promise_->GetLocalFrame())
+ return;
system_clipboard()->WritePlainText(text);
promise_->CompleteWriteRepresentation();
}
};
+// Writes a blob with text/html content to the System Clipboard.
class ClipboardHtmlWriter final : public ClipboardWriter {
public:
ClipboardHtmlWriter(SystemClipboard* system_clipboard,
@@ -137,8 +141,10 @@ class ClipboardHtmlWriter final : public ClipboardWriter {
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- promise_->GetExecutionContext()->CountUse(
- WebFeature::kHtmlClipboardApiWrite);
+ auto* execution_context = promise_->GetExecutionContext();
+ if (!execution_context)
+ return;
+ execution_context->CountUse(WebFeature::kHtmlClipboardApiWrite);
String html_string =
String::FromUTF8(reinterpret_cast<const LChar*>(html_data->Data()),
@@ -150,7 +156,10 @@ class ClipboardHtmlWriter final : public ClipboardWriter {
unsigned fragment_start = 0;
unsigned fragment_end = html_string.length();
- Document* document = promise_->GetLocalFrame()->GetDocument();
+ LocalFrame* local_frame = promise_->GetLocalFrame();
+ if (!local_frame)
+ return;
+ Document* document = local_frame->GetDocument();
DocumentFragment* fragment = CreateSanitizedFragmentFromMarkupWithContext(
*document, html_string, fragment_start, fragment_end, url);
String sanitized_html =
@@ -165,6 +174,7 @@ class ClipboardHtmlWriter final : public ClipboardWriter {
}
};
+// Writes a blob with image/svg+xml content to the System Clipboard.
class ClipboardSvgWriter final : public ClipboardWriter {
public:
ClipboardSvgWriter(SystemClipboard* system_clipboard,
@@ -173,8 +183,6 @@ class ClipboardSvgWriter final : public ClipboardWriter {
~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(
DOMArrayBuffer* svg_data,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
@@ -184,12 +192,16 @@ class ClipboardSvgWriter final : public ClipboardWriter {
String::FromUTF8(reinterpret_cast<const LChar*>(svg_data->Data()),
svg_data->ByteLength());
- // Now sanitize the SVG string.
+ // Sanitizing on the main thread because SVG/XML DOM nodes can only be used
+ // on the main thread.
KURL url;
unsigned fragment_start = 0;
unsigned fragment_end = svg_string.length();
- Document* document = promise_->GetLocalFrame()->GetDocument();
+ LocalFrame* local_frame = promise_->GetLocalFrame();
+ if (!local_frame)
+ return;
+ Document* document = local_frame->GetDocument();
DocumentFragment* fragment = CreateSanitizedFragmentFromMarkupWithContext(
*document, svg_string, fragment_start, fragment_end, url);
String sanitized_svg =
@@ -204,7 +216,7 @@ class ClipboardSvgWriter final : public ClipboardWriter {
}
};
-// Writes a blob with arbitrary, unsanitized content to the System Clipboard.
+// Writes a Blob with arbitrary, unsanitized content to the System Clipboard.
class ClipboardRawDataWriter final : public ClipboardWriter {
public:
ClipboardRawDataWriter(RawSystemClipboard* raw_system_clipboard,
@@ -236,6 +248,8 @@ class ClipboardRawDataWriter final : public ClipboardWriter {
mojo_base::BigBuffer buffer(std::vector<uint8_t>(
raw_data_pointer, raw_data_pointer + raw_data->ByteLength()));
+ if (!promise_->GetLocalFrame())
+ return;
raw_system_clipboard()->Write(mime_type_, std::move(buffer));
promise_->CompleteWriteRepresentation();
@@ -252,6 +266,7 @@ class ClipboardRawDataWriter final : public ClipboardWriter {
ClipboardWriter* ClipboardWriter::Create(SystemClipboard* system_clipboard,
const String& mime_type,
ClipboardPromise* promise) {
+ DCHECK(ClipboardWriter::IsValidType(mime_type, /*is_raw=*/false));
if (mime_type == kMimeTypeImagePng) {
return MakeGarbageCollected<ClipboardImageWriter>(system_clipboard,
promise);
@@ -266,7 +281,8 @@ ClipboardWriter* ClipboardWriter::Create(SystemClipboard* system_clipboard,
RuntimeEnabledFeatures::ClipboardSvgEnabled())
return MakeGarbageCollected<ClipboardSvgWriter>(system_clipboard, promise);
- NOTREACHED() << "Type " << mime_type << " was not implemented";
+ NOTREACHED()
+ << "IsValidType() and Create() have inconsistent implementations.";
return nullptr;
}
@@ -276,7 +292,7 @@ ClipboardWriter* ClipboardWriter::Create(
const String& mime_type,
ClipboardPromise* promise) {
DCHECK(base::FeatureList::IsEnabled(features::kRawClipboard));
-
+ DCHECK(ClipboardWriter::IsValidType(mime_type, /*is_raw=*/true));
return MakeGarbageCollected<ClipboardRawDataWriter>(raw_system_clipboard,
promise, mime_type);
}
@@ -310,9 +326,12 @@ bool ClipboardWriter::IsValidType(const String& type, bool is_raw) {
if (is_raw)
return type.length() < mojom::blink::RawClipboardHost::kMaxFormatSize;
+ if (type == kMimeTypeImageSvg)
+ return RuntimeEnabledFeatures::ClipboardSvgEnabled();
+
// TODO(https://crbug.com/1029857): Add support for other types.
return type == kMimeTypeImagePng || type == kMimeTypeTextPlain ||
- type == kMimeTypeTextHTML || type == kMimeTypeImageSvg;
+ type == kMimeTypeTextHTML;
}
void ClipboardWriter::WriteToSystem(Blob* blob) {
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
index 2ca24aa3c33..442a3c5fb9f 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
@@ -8,26 +8,44 @@
#include "base/sequence_checker.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
+#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
#include "third_party/skia/include/core/SkImage.h"
namespace blink {
-class ClipboardPromise;
class FileReaderLoader;
class SystemClipboard;
class RawSystemClipboard;
-// Interface for writing async-clipboard-compatible types as a Blob to the
-// System Clipboard, asynchronously.
+// Interface for writing an individual Clipboard API format as a Blob to the
+// System Clipboard, safely and asynchronously.
+//
+// ClipboardWriter takes as input a ClipboardPromise, which manages writing
+// multiple formats and passes in unsanitized clipboard payloads.
+// ClipboardWriter then sanitizes a Blob payload and writes it onto the
+// underlying system clipboard. All System Clipboard operations should be
+// called from the main thread.
//
// Writing a Blob's data to the system clipboard is accomplished by:
-// (1) Reading the blob's contents using a FileReaderLoader.
-// (2) Decoding the blob's contents to avoid RCE in native applications that may
-// take advantage of vulnerabilities in their decoders. In
-// ClipboardRawDataWriter, this decoding is skipped.
-// (3) Writing the blob's decoded contents to the system clipboard.
+// (1) Reading - the Blob's contents using a FileReaderLoader.
+// (2) Decoding - or sanitizing the Blob's contents to avoid RCE in native
+// applications that may take advantage of vulnerabilities in their
+// decoders, whenever possible. Decoding may be time-consuming, so it
+// is done on a background thread whenever possible. An example where
+// decoding is done on the main thread is HTML, where Blink's HTML decoder
+// can only be used on the main thread.
+// (3) Writing - the Blob's decoded contents to the system clipboard.
+//
+// Subclasses of ClipboardWriter should be implemented for each supported
+// format. Subclasses should:
+// (1) Begin execution by implementing ClipboardWriter::StartWrite().
+// (2) Decode the payload on a background thread (if possible) by implementing
+// a static DecodeOnBackgroundThread() function. This function is called by
+// StartWrite() via worker_pool::PostTask().
+// (3) Write the decoded content to the system clipboard by implementing
+// ClipboardWriter::Write();
//
// ClipboardWriter is owned only by itself and ClipboardPromise. It keeps
// itself alive for the duration of FileReaderLoader's async operations using
@@ -36,20 +54,29 @@ class RawSystemClipboard;
class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
public FileReaderLoaderClient {
public:
+ // For writing sanitized MIME types.
+ // IsValidType() must return true on types passed into `mime_type`.
static ClipboardWriter* Create(SystemClipboard* system_clipboard,
const String& mime_type,
ClipboardPromise* promise);
+ // For writing unsanitized types.
+ // IsValidType() must return true on types passed into `mime_type`.
static ClipboardWriter* Create(RawSystemClipboard* raw_system_clipboard,
const String& mime_type,
ClipboardPromise* promise);
- static ClipboardWriter* Create(SystemClipboard* system_clipboard,
- const String& mime_type,
- ClipboardPromise* promise,
- LocalFrame* frame);
~ClipboardWriter() override;
- static bool IsValidType(const String& type, bool is_raw);
- void WriteToSystem(Blob*);
+ // Returns whether ClipboardWriter has implemented support for this type.
+ //
+ // IsValidType() is expected to be called before Create(). If it returns false
+ // for a `mime_type`, Create() must not be called with that `mime_type`.
+ //
+ // IsValidType() is used for both ClipboardWriter and ClipboardReader, as read
+ // and write currently support the same types. If this changes in the future,
+ // please create separate IsValidType functions.
+ static bool IsValidType(const String& mime_type, bool is_raw);
+ // Begins the sequence of writing the Blob to the system clipbaord.
+ void WriteToSystem(Blob* blob);
// FileReaderLoaderClient.
void DidStartLoading() override;
@@ -69,15 +96,27 @@ class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
virtual void StartWrite(
DOMArrayBuffer* raw_data,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
- // This ClipboardPromise owns this ClipboardWriter.
+
+ // SystemClipboard and RawSystemClipboard are bound to LocalFrame, so the
+ // bound LocalFrame must still be valid by the time they're used.
+ SystemClipboard* system_clipboard() {
+ DCHECK(promise_->GetLocalFrame());
+ return system_clipboard_;
+ }
+
+ RawSystemClipboard* raw_system_clipboard() {
+ DCHECK(promise_->GetLocalFrame());
+ return raw_system_clipboard_;
+ }
+
+ // This ClipboardPromise owns this ClipboardWriter. Subclasses use `promise_`
+ // to report success or failure, or to obtain the execution context.
Member<ClipboardPromise> promise_;
- // Ensure that System Clipboard operations occur on the main thread.
+ // Every subclass method that runs on the main thread should
+ // DCHECK_CALLED_ON_VALID_SEQUENCE with this checker.
SEQUENCE_CHECKER(sequence_checker_);
- SystemClipboard* system_clipboard() { return system_clipboard_; }
- RawSystemClipboard* raw_system_clipboard() { return raw_system_clipboard_; }
-
private:
ClipboardWriter(SystemClipboard* system_clipboard,
RawSystemClipboard* raw_system_clipboard,
diff --git a/chromium/third_party/blink/renderer/modules/compression/DIR_METADATA b/chromium/third_party/blink/renderer/modules/compression/DIR_METADATA
new file mode 100644
index 00000000000..301c1aa2c90
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/compression/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Network>StreamsAPI"
+}
+team_email: "blink-network-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/compression/OWNERS b/chromium/third_party/blink/renderer/modules/compression/OWNERS
index b63f88130bc..a2e6241b06e 100644
--- a/chromium/third_party/blink/renderer/modules/compression/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/compression/OWNERS
@@ -1,5 +1,2 @@
yhirano@chromium.org
ricea@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>StreamsAPI
diff --git a/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.cc b/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.cc
index 91a3b4164a6..5c4601dc816 100644
--- a/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.cc
+++ b/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.cc
@@ -64,7 +64,7 @@ ScriptPromise DeflateTransformer::Transform(
return ScriptPromise();
}
if (buffer_source.IsArrayBufferView()) {
- const auto* view = buffer_source.GetAsArrayBufferView().View();
+ const auto* view = buffer_source.GetAsArrayBufferView().Get();
const uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
size_t length = view->byteLength();
if (length > std::numeric_limits<wtf_size_t>::max()) {
diff --git a/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.h b/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.h
index d753166ccf9..16d70ae5bf6 100644
--- a/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.h
+++ b/chromium/third_party/blink/renderer/modules/compression/deflate_transformer.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_DEFLATE_TRANSFORMER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_DEFLATE_TRANSFORMER_H_
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
@@ -33,7 +33,7 @@ class DeflateTransformer final : public TransformStreamTransformer {
void Trace(Visitor*) const override;
private:
- using IsFinished = util::StrongAlias<class IsFinishedTag, bool>;
+ using IsFinished = base::StrongAlias<class IsFinishedTag, bool>;
void Deflate(const uint8_t*,
wtf_size_t,
diff --git a/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.cc b/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.cc
index fddb53b1fc2..b052abe307b 100644
--- a/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.cc
+++ b/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.cc
@@ -63,7 +63,7 @@ ScriptPromise InflateTransformer::Transform(
return ScriptPromise();
}
if (buffer_source.IsArrayBufferView()) {
- const auto* view = buffer_source.GetAsArrayBufferView().View();
+ const auto* view = buffer_source.GetAsArrayBufferView().Get();
const uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
size_t length = view->byteLength();
if (length > std::numeric_limits<wtf_size_t>::max()) {
diff --git a/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.h b/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.h
index c5df437f168..ac01659f96d 100644
--- a/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.h
+++ b/chromium/third_party/blink/renderer/modules/compression/inflate_transformer.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_INFLATE_TRANSFORMER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_INFLATE_TRANSFORMER_H_
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
@@ -33,7 +33,7 @@ class InflateTransformer final : public TransformStreamTransformer {
void Trace(Visitor*) const override;
private:
- using IsFinished = util::StrongAlias<class IsFinishedTag, bool>;
+ using IsFinished = base::StrongAlias<class IsFinishedTag, bool>;
void Inflate(const uint8_t*,
wtf_size_t,
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/DIR_METADATA b/chromium/third_party/blink/renderer/modules/contacts_picker/DIR_METADATA
new file mode 100644
index 00000000000..1525bd8f5fc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Contacts"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/contacts_picker/OWNERS b/chromium/third_party/blink/renderer/modules/contacts_picker/OWNERS
index a74a53fbba0..3a06654b44b 100644
--- a/chromium/third_party/blink/renderer/modules/contacts_picker/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/contacts_picker/OWNERS
@@ -1,5 +1,2 @@
finnur@chromium.org
peter@chromium.org
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>Contacts
diff --git a/chromium/third_party/blink/renderer/modules/content_index/DIR_METADATA b/chromium/third_party/blink/renderer/modules/content_index/DIR_METADATA
new file mode 100644
index 00000000000..aeef9010c3d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/content_index/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>ContentIndexing"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/content_index/OWNERS b/chromium/third_party/blink/renderer/modules/content_index/OWNERS
index 67eed44a0b7..e7fa78954ac 100644
--- a/chromium/third_party/blink/renderer/modules/content_index/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/content_index/OWNERS
@@ -4,6 +4,3 @@ rayankans@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>ContentIndexing
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 412a1c44643..60687c8d634 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn
@@ -16,8 +16,6 @@ blink_modules_sources("cookie_store") {
"extendable_cookie_change_event.h",
"global_cookie_store.cc",
"global_cookie_store.h",
- "service_worker_registration_cookies.cc",
- "service_worker_registration_cookies.h",
]
deps = [ "//third_party/blink/renderer/platform" ]
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/DIR_METADATA b/chromium/third_party/blink/renderer/modules/cookie_store/DIR_METADATA
new file mode 100644
index 00000000000..348e0c9ab40
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>CookiesAPI"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/OWNERS b/chromium/third_party/blink/renderer/modules/cookie_store/OWNERS
index c9ae9e5c245..7e45685dea1 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/OWNERS
@@ -1,4 +1 @@
file://content/browser/cookie_store/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>CookiesAPI
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 049c5bd8009..0522d29a1f3 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
@@ -3,14 +3,13 @@
// found in the LICENSE file.
// Used to signal cookie changes to Document contexts.
-// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
//
// See extendable_cookie_change_event.idl for the equivalent event in
// ServiceWorker contexts.
[
Exposed=Window,
- RuntimeEnabled=CookieStoreDocument,
SecureContext
] interface CookieChangeEvent : Event {
constructor(DOMString type, optional CookieChangeEventInit eventInitDict = {});
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event_init.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event_init.idl
index ebce1f1273d..6b37d5458d6 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event_init.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event_init.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/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
dictionary CookieChangeEventInit : EventInit {
CookieList changed;
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 da6df111e53..05d3cfc4fae 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
@@ -130,6 +130,7 @@ std::unique_ptr<net::CanonicalCookie> ToCanonicalCookie(
//
// The Cookie Store API can only set secure cookies, so it is unusable on
// insecure origins.
+ // TODO(crbug.com/1153336) Use network::IsUrlPotentiallyTrustworthy().
if (!SecurityOrigin::IsSecure(cookie_url)) {
exception_state.ThrowTypeError(
"Cannot modify a secure cookie on insecure origin");
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.idl
index b1bb1b83d0d..c617c115760 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.idl
@@ -6,7 +6,6 @@
[
Exposed=(ServiceWorker,Window),
- RuntimeEnabled=CookieStoreDocument,
SecureContext
] interface CookieStore : EventTarget {
// https://wicg.github.io/cookie-store/explainer.html#the-query-api
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_delete_options.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_delete_options.idl
index d3b03cbf627..a51968036cd 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_delete_options.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_delete_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
dictionary CookieStoreDeleteOptions {
required USVString name;
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 1202deb9df5..c1994611322 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
@@ -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/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
dictionary CookieStoreGetOptions {
USVString name;
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 dda14e457cd..bf3a5694a02 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
@@ -85,15 +85,31 @@ KURL DefaultCookieURL(ServiceWorkerRegistration* registration) {
} // namespace
-CookieStoreManager::CookieStoreManager(
- ServiceWorkerRegistration* registration,
- HeapMojoRemote<mojom::blink::CookieStore,
- HeapMojoWrapperMode::kWithoutContextObserver> backend)
- : registration_(registration),
- backend_(std::move(backend)),
- default_cookie_url_(DefaultCookieURL(registration)) {
- DCHECK(registration_);
- DCHECK(backend_.is_bound());
+// static
+const char CookieStoreManager::kSupplementName[] = "CookieStoreManager";
+
+// static
+CookieStoreManager* CookieStoreManager::cookies(
+ ServiceWorkerRegistration& registration) {
+ auto* supplement =
+ Supplement<ServiceWorkerRegistration>::From<CookieStoreManager>(
+ registration);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<CookieStoreManager>(registration);
+ ProvideTo(registration, supplement);
+ }
+ return supplement;
+}
+
+CookieStoreManager::CookieStoreManager(ServiceWorkerRegistration& registration)
+ : Supplement<ServiceWorkerRegistration>(registration),
+ registration_(&registration),
+ backend_(registration.GetExecutionContext()),
+ default_cookie_url_(DefaultCookieURL(&registration)) {
+ auto* execution_context = registration.GetExecutionContext();
+ execution_context->GetBrowserInterfaceBroker().GetInterface(
+ backend_.BindNewPipeAndPassReceiver(
+ execution_context->GetTaskRunner(TaskType::kDOMManipulation)));
}
ScriptPromise CookieStoreManager::subscribe(
@@ -166,6 +182,7 @@ ScriptPromise CookieStoreManager::getSubscriptions(
void CookieStoreManager::Trace(Visitor* visitor) const {
visitor->Trace(registration_);
visitor->Trace(backend_);
+ Supplement<ServiceWorkerRegistration>::Trace(visitor);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h
index d42c09d23d3..ffbc4f98f4b 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/heap/handle.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"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -22,14 +23,17 @@ class ExceptionState;
class ScriptPromiseResolver;
class ScriptState;
-class CookieStoreManager final : public ScriptWrappable {
+class CookieStoreManager final : public ScriptWrappable,
+ public Supplement<ServiceWorkerRegistration> {
DEFINE_WRAPPERTYPEINFO();
public:
- CookieStoreManager(
- ServiceWorkerRegistration* registration,
- HeapMojoRemote<mojom::blink::CookieStore,
- HeapMojoWrapperMode::kWithoutContextObserver> backend);
+ static const char kSupplementName[];
+ // Web Exposed as registration.cookies
+ static CookieStoreManager* cookies(ServiceWorkerRegistration& registration);
+
+ explicit CookieStoreManager(ServiceWorkerRegistration& registration);
+
~CookieStoreManager() override = default;
ScriptPromise subscribe(
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.idl
index 8876f55c5e1..e97ebc5cd11 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.idl
@@ -5,7 +5,7 @@
// https://wicg.github.io/cookie-store/explainer.html#the-change-events-api
[
- Exposed(ServiceWorker CookieStoreWorker, Window CookieStoreDocument),
+ Exposed=(ServiceWorker,Window),
SecureContext
] interface CookieStoreManager {
[CallWith=ScriptState, MeasureAs=CookieStoreAPI, RaisesException]
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 72f5588a58b..3d2124aa730 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
@@ -3,13 +3,12 @@
// found in the LICENSE file.
// Used to signal cookie changes to ServiceWorker contexts.
-// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
//
// See cookie_change_event.idl for the equivalent event in Document contexts.
[
- Exposed=ServiceWorker,
- RuntimeEnabled=CookieStoreWorker
+ Exposed=ServiceWorker
] interface ExtendableCookieChangeEvent : ExtendableEvent {
constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict = {});
[
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 72c2d0cc851..ccc8e5a9d0d 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
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
[
- RuntimeEnabled=CookieStoreWorker,
ImplementedAs=GlobalCookieStore
] partial interface ServiceWorkerGlobalScope {
[SameObject] readonly attribute CookieStore cookieStore;
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
deleted file mode 100644
index 71eccd487af..00000000000
--- a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc
+++ /dev/null
@@ -1,85 +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/cookie_store/service_worker_registration_cookies.h"
-
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/renderer/modules/cookie_store/cookie_store_manager.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
-
-namespace blink {
-
-namespace {
-
-class ServiceWorkerRegistrationCookiesImpl final
- : public GarbageCollected<ServiceWorkerRegistrationCookiesImpl>,
- public Supplement<ServiceWorkerRegistration> {
- public:
- static const char kSupplementName[];
-
- static ServiceWorkerRegistrationCookiesImpl& From(
- ServiceWorkerRegistration& registration) {
- ServiceWorkerRegistrationCookiesImpl* supplement =
- Supplement<ServiceWorkerRegistration>::From<
- ServiceWorkerRegistrationCookiesImpl>(registration);
- if (!supplement) {
- supplement = MakeGarbageCollected<ServiceWorkerRegistrationCookiesImpl>(
- registration);
- ProvideTo(registration, supplement);
- }
- return *supplement;
- }
-
- explicit ServiceWorkerRegistrationCookiesImpl(
- ServiceWorkerRegistration& registration)
- : registration_(&registration) {}
-
- ~ServiceWorkerRegistrationCookiesImpl() = default;
-
- CookieStoreManager* GetCookieStoreManager() {
- if (!cookie_store_manager_) {
- ExecutionContext* execution_context =
- registration_->GetExecutionContext();
- DCHECK(execution_context);
-
- HeapMojoRemote<mojom::blink::CookieStore,
- HeapMojoWrapperMode::kWithoutContextObserver>
- backend(execution_context);
- execution_context->GetBrowserInterfaceBroker().GetInterface(
- backend.BindNewPipeAndPassReceiver(
- execution_context->GetTaskRunner(TaskType::kDOMManipulation)));
- cookie_store_manager_ = MakeGarbageCollected<CookieStoreManager>(
- registration_, std::move(backend));
- }
- return cookie_store_manager_.Get();
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(registration_);
- visitor->Trace(cookie_store_manager_);
- Supplement<ServiceWorkerRegistration>::Trace(visitor);
- }
-
- private:
- Member<ServiceWorkerRegistration> registration_;
- Member<CookieStoreManager> cookie_store_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationCookiesImpl);
-};
-
-const char ServiceWorkerRegistrationCookiesImpl::kSupplementName[] =
- "ServiceWorkerRegistrationCookies";
-
-} // namespace
-
-// static
-CookieStoreManager* ServiceWorkerRegistrationCookies::cookies(
- ServiceWorkerRegistration& registration) {
- return ServiceWorkerRegistrationCookiesImpl::From(registration)
- .GetCookieStoreManager();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.h b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.h
deleted file mode 100644
index 034a6e26d28..00000000000
--- a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.h
+++ /dev/null
@@ -1,24 +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_COOKIE_STORE_SERVICE_WORKER_REGISTRATION_COOKIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_SERVICE_WORKER_REGISTRATION_COOKIES_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class CookieStoreManager;
-class ServiceWorkerRegistration;
-
-class ServiceWorkerRegistrationCookies final {
- STATIC_ONLY(ServiceWorkerRegistrationCookies);
-
- public:
- static CookieStoreManager* cookies(ServiceWorkerRegistration& registration);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_SERVICE_WORKER_REGISTRATION_COOKIES_H_
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 40bed0e19a1..151f2c67987 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
@@ -4,8 +4,7 @@
[
Exposed=(ServiceWorker,Window),
- RuntimeEnabled=CookieStoreWorker,
- ImplementedAs=ServiceWorkerRegistrationCookies
+ ImplementedAs=CookieStoreManager
] partial interface ServiceWorkerRegistration {
[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 c86f9a4f77a..6882018f599 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
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
+// https://wicg.github.io/cookie-store/explainer.html
[
- RuntimeEnabled=CookieStoreDocument,
ImplementedAs=GlobalCookieStore,
SecureContext
] partial interface Window {
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/BUILD.gn b/chromium/third_party/blink/renderer/modules/credentialmanager/BUILD.gn
index 0b14647807e..e3bc4a0c538 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/BUILD.gn
@@ -18,8 +18,6 @@ blink_modules_sources("credentialmanager") {
"credential_manager_proxy.h",
"credential_manager_type_converters.cc",
"credential_manager_type_converters.h",
- "credential_metrics.cc",
- "credential_metrics.h",
"credentials_container.cc",
"credentials_container.h",
"federated_credential.cc",
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/DIR_METADATA b/chromium/third_party/blink/renderer/modules/credentialmanager/DIR_METADATA
new file mode 100644
index 00000000000..838d991b3e8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>SecurityFeature>CredentialManagement"
+}
+team_email: "identity-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/OWNERS b/chromium/third_party/blink/renderer/modules/credentialmanager/OWNERS
index 8e0914e13b2..d19e950583f 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/OWNERS
@@ -4,6 +4,3 @@ file://device/fido/OWNERS
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: identity-dev@chromium.org
-# COMPONENT: Blink>SecurityFeature>CredentialManagement
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 5ac82e37e8a..7095d17ad20 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
@@ -189,7 +189,7 @@ Vector<uint8_t> ConvertFixedSizeArray(
}
if (buffer.IsArrayBufferView() &&
- buffer.GetAsArrayBufferView().View()->byteLength() != length) {
+ buffer.GetAsArrayBufferView()->byteLength() != length) {
return Vector<uint8_t>();
}
@@ -208,10 +208,10 @@ TypeConverter<Vector<uint8_t>, blink::ArrayBufferOrArrayBufferView>::Convert(
buffer.GetAsArrayBuffer()->ByteLength()));
} else {
DCHECK(buffer.IsArrayBufferView());
- vector.Append(static_cast<uint8_t*>(
- buffer.GetAsArrayBufferView().View()->BaseAddress()),
- base::checked_cast<wtf_size_t>(
- buffer.GetAsArrayBufferView().View()->byteLength()));
+ vector.Append(
+ static_cast<uint8_t*>(buffer.GetAsArrayBufferView()->BaseAddress()),
+ base::checked_cast<wtf_size_t>(
+ buffer.GetAsArrayBufferView()->byteLength()));
}
return vector;
}
@@ -321,12 +321,15 @@ TypeConverter<AuthenticatorAttachment, base::Optional<String>>::Convert(
}
// static
-LargeBlobSupport TypeConverter<LargeBlobSupport, String>::Convert(
- const String& large_blob_support) {
- if (large_blob_support == "required")
- return LargeBlobSupport::REQUIRED;
- if (large_blob_support == "preferred")
- return LargeBlobSupport::PREFERRED;
+LargeBlobSupport
+TypeConverter<LargeBlobSupport, base::Optional<String>>::Convert(
+ const base::Optional<String>& large_blob_support) {
+ if (large_blob_support) {
+ if (*large_blob_support == "required")
+ return LargeBlobSupport::REQUIRED;
+ if (*large_blob_support == "preferred")
+ return LargeBlobSupport::PREFERRED;
+ }
// Unknown values are treated as preferred.
return LargeBlobSupport::PREFERRED;
@@ -570,9 +573,12 @@ TypeConverter<PublicKeyCredentialCreationOptionsPtr,
WebAuthenticationResidentKeyRequirementEnabled());
mojo_options->cred_props = true;
}
- if (extensions->largeBlob()) {
- mojo_options->large_blob_enable =
- ConvertTo<LargeBlobSupport>(extensions->largeBlob()->support());
+ if (extensions->hasLargeBlob()) {
+ base::Optional<WTF::String> support;
+ if (extensions->largeBlob()->hasSupport()) {
+ support = extensions->largeBlob()->support();
+ }
+ mojo_options->large_blob_enable = ConvertTo<LargeBlobSupport>(support);
}
}
@@ -585,14 +591,31 @@ TypeConverter<CableAuthenticationPtr, blink::CableAuthenticationData>::Convert(
const blink::CableAuthenticationData& data) {
auto entity = CableAuthentication::New();
entity->version = data.version();
- entity->client_eid = ConvertFixedSizeArray(data.clientEid(), 16);
- entity->authenticator_eid =
- ConvertFixedSizeArray(data.authenticatorEid(), 16);
- entity->session_pre_key = ConvertFixedSizeArray(data.sessionPreKey(), 32);
- if (entity->client_eid.IsEmpty() || entity->authenticator_eid.IsEmpty() ||
- entity->session_pre_key.IsEmpty()) {
- return nullptr;
+ switch (entity->version) {
+ case 1:
+ entity->client_eid = ConvertFixedSizeArray(data.clientEid(), 16);
+ entity->authenticator_eid =
+ ConvertFixedSizeArray(data.authenticatorEid(), 16);
+ entity->session_pre_key = ConvertFixedSizeArray(data.sessionPreKey(), 32);
+ if (entity->client_eid->IsEmpty() ||
+ entity->authenticator_eid->IsEmpty() ||
+ entity->session_pre_key->IsEmpty()) {
+ return nullptr;
+ }
+ break;
+
+ case 2:
+ entity->server_link_data =
+ ConvertTo<Vector<uint8_t>>(data.sessionPreKey());
+ if (entity->server_link_data->IsEmpty()) {
+ return nullptr;
+ }
+ break;
+
+ default:
+ return nullptr;
}
+
return entity;
}
@@ -651,7 +674,7 @@ TypeConverter<PublicKeyCredentialRequestOptionsPtr,
if (extensions->hasCableAuthentication()) {
Vector<CableAuthenticationPtr> mojo_data;
for (auto& data : extensions->cableAuthentication()) {
- if (data->version() != 1) {
+ if (data->version() < 1 || data->version() > 2) {
continue;
}
CableAuthenticationPtr mojo_cable = CableAuthentication::From(*data);
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 70bf4951482..3b95eaafce9 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
@@ -106,8 +106,10 @@ struct TypeConverter<blink::mojom::blink::AuthenticatorAttachment,
};
template <>
-struct TypeConverter<blink::mojom::blink::LargeBlobSupport, String> {
- static blink::mojom::blink::LargeBlobSupport Convert(const String&);
+struct TypeConverter<blink::mojom::blink::LargeBlobSupport,
+ base::Optional<String>> {
+ static blink::mojom::blink::LargeBlobSupport Convert(
+ const base::Optional<String>&);
};
template <>
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc
deleted file mode 100644
index 0dd32f13927..00000000000
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc
+++ /dev/null
@@ -1,60 +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/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 {
-
-void RecordSmsOutcome(WebOTPServiceOutcome outcome,
- ukm::SourceId source_id,
- ukm::UkmRecorder* ukm_recorder) {
- DCHECK_NE(source_id, ukm::kInvalidSourceId);
- DCHECK(ukm_recorder);
-
- ukm::builders::SMSReceiver builder(source_id);
- builder.SetOutcome(static_cast<int>(outcome));
- builder.Record(ukm_recorder);
-
- UMA_HISTOGRAM_ENUMERATION("Blink.Sms.Receive.Outcome", outcome);
-}
-
-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);
-}
-
-void RecordSmsUserCancelTime(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.SetTimeUserCancelMs(
- ukm::GetExponentialBucketMinForUserTiming(duration.InMilliseconds()));
- builder.Record(ukm_recorder);
-
- UMA_HISTOGRAM_MEDIUM_TIMES("Blink.Sms.Receive.TimeUserCancel", duration);
-}
-
-void RecordSmsCancelTime(base::TimeDelta duration) {
- UMA_HISTOGRAM_MEDIUM_TIMES("Blink.Sms.Receive.TimeCancel", duration);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h
deleted file mode 100644
index 60c69f12db8..00000000000
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h
+++ /dev/null
@@ -1,47 +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_CREDENTIALMANAGER_CREDENTIAL_METRICS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_METRICS_H_
-
-#include <stdint.h>
-
-#include "base/time/time.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
-#include "third_party/blink/public/common/sms/webotp_service_outcome.h"
-
-namespace ukm {
-class UkmRecorder;
-} // namespace ukm
-
-namespace blink {
-
-// Records the result of a call to navigator.credentials.get({otp}) using
-// the same histogram as WebOTPService API to provide continuity with previous
-// iterations of the API.
-void RecordSmsOutcome(WebOTPServiceOutcome outcome,
- ukm::SourceId source_id,
- ukm::UkmRecorder* ukm_recorder);
-
-// Records the time from when the API is called to when the user successfully
-// receives the SMS and presses verify to move on with the verification flow.
-// This uses the same histogram as WebOTPService API to provide continuity with
-// previous iterations of the API.
-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 WebOTPService
-// API to provide continuity with previous iterations of the API.
-void RecordSmsUserCancelTime(base::TimeDelta duration,
- ukm::SourceId source_id,
- ukm::UkmRecorder* ukm_recorder);
-// Records the time from when the API is called to when the request is cancelled
-// by the service due to duplicated requests or lack of delegate.
-void RecordSmsCancelTime(base::TimeDelta duration);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_METRICS_H_
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
index ffd56e866f8..3767cc3c5e4 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_request_options.idl
@@ -19,5 +19,8 @@ dictionary CredentialRequestOptions {
[RuntimeEnabled=WebOTP] OTPCredentialRequestOptions otp;
PublicKeyCredentialRequestOptions publicKey;
+ [RuntimeEnabled=WebAuthenticationConditionalUI]
+ PublicKeyCredentialRequestOptions conditionalPublicKey;
+
AbortSignal signal;
};
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 3d667409eee..e31a945502b 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -11,6 +11,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
#include "build/build_config.h"
+#include "third_party/blink/public/common/sms/webotp_constants.h"
#include "third_party/blink/public/common/sms/webotp_service_outcome.h"
#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
@@ -31,8 +32,10 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_creation_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_creation_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_rp_entity.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_user_entity.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -50,14 +53,11 @@
#include "third_party/blink/renderer/modules/credentialmanager/credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h"
#include "third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h"
-#include "third_party/blink/renderer/modules/credentialmanager/credential_metrics.h"
#include "third_party/blink/renderer/modules/credentialmanager/federated_credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/otp_credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/password_credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/payment_credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/public_key_credential.h"
-#include "third_party/blink/renderer/modules/credentialmanager/public_key_credential_descriptor.h"
-#include "third_party/blink/renderer/modules/credentialmanager/public_key_credential_user_entity.h"
#include "third_party/blink/renderer/modules/credentialmanager/scoped_promise_resolver.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -87,8 +87,9 @@ using mojom::blink::MakeCredentialAuthenticatorResponsePtr;
using MojoPublicKeyCredentialRequestOptions =
mojom::blink::PublicKeyCredentialRequestOptions;
using mojom::blink::GetAssertionAuthenticatorResponsePtr;
-using payments::mojom::blink::PaymentCredentialCreationStatus;
using payments::mojom::blink::PaymentCredentialInstrument;
+using payments::mojom::blink::PaymentCredentialStorageStatus;
+using payments::mojom::blink::PaymentCredentialUserPromptStatus;
constexpr char kCryptotokenOrigin[] =
"chrome-extension://kmendfapggjehodndflmmgagdbamhnfd";
@@ -111,7 +112,9 @@ enum class RequiredOriginType {
// expressed in various ways, e.g.: |allow| iframe attribute and/or
// feature-policy header, and may be inherited from parent browsing
// contexts. See Feature Policy spec.
- kSecureAndPermittedByFeaturePolicy,
+ kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy,
+ // Similar to the enum above, checks the "otp-credentials" feature policy.
+ kSecureAndPermittedByWebOTPAssertionFeaturePolicy,
};
bool IsSameOriginWithAncestors(const Frame* frame) {
@@ -128,6 +131,37 @@ bool IsSameOriginWithAncestors(const Frame* frame) {
return true;
}
+// An ancestor chain is valid iff there are at most 2 unique origins on the
+// chain (current origin included), the unique origins must be consecutive.
+// e.g. the following are valid:
+// A.com (calls WebOTP API)
+// A.com -> A.com (calls WebOTP API)
+// A.com -> A.com -> B.com (calls WebOTP API)
+// A.com -> B.com -> B.com (calls WebOTP API)
+// while the following are invalid:
+// A.com -> B.com -> A.com (calls WebOTP API)
+// A.com -> B.com -> C.com (calls WebOTP API)
+// Note that there is additional requirement on feature permission being granted
+// upon crossing origins but that is not verified by this function.
+bool IsAncestorChainValidForWebOTP(const Frame* frame) {
+ const SecurityOrigin* current_origin =
+ frame->GetSecurityContext()->GetSecurityOrigin();
+ int number_of_unique_origin = 1;
+
+ const Frame* parent = frame->Tree().Parent();
+ while (parent) {
+ auto* parent_origin = parent->GetSecurityContext()->GetSecurityOrigin();
+ if (!parent_origin->IsSameOriginWith(current_origin)) {
+ ++number_of_unique_origin;
+ current_origin = parent_origin;
+ }
+ if (number_of_unique_origin > kMaxUniqueOriginInAncestorChainForWebOTP)
+ return false;
+ parent = parent->Tree().Parent();
+ }
+ return true;
+}
+
bool CheckSecurityRequirementsBeforeRequest(
ScriptPromiseResolver* resolver,
RequiredOriginType required_origin_type) {
@@ -163,7 +197,8 @@ bool CheckSecurityRequirementsBeforeRequest(
}
break;
- case RequiredOriginType::kSecureAndPermittedByFeaturePolicy:
+ case RequiredOriginType::
+ kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy:
// The 'publickey-credentials-get' feature's "default allowlist" is
// "self", which means the webauthn feature is allowed by default in
// same-origin child browsing contexts.
@@ -172,7 +207,7 @@ bool CheckSecurityRequirementsBeforeRequest(
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError,
"The 'publickey-credentials-get' feature is not enabled in this "
- "document. Feature Policy may be used to delegate Web "
+ "document. Permissions Policy may be used to delegate Web "
"Authentication capabilities to cross-origin child frames."));
return false;
} else {
@@ -181,6 +216,22 @@ bool CheckSecurityRequirementsBeforeRequest(
WebFeature::kCredentialManagerCrossOriginPublicKeyGetRequest);
}
break;
+
+ case RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy:
+ if (!resolver->GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kOTPCredentials)) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError,
+ "The 'otp-credentials` feature is not enabled in this document."));
+ return false;
+ }
+ if (!IsAncestorChainValidForWebOTP(resolver->DomWindow()->GetFrame())) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError,
+ "More than two unique origins are detected in the origin chain."));
+ return false;
+ }
+ break;
}
return true;
@@ -208,10 +259,18 @@ void AssertSecurityRequirementsBeforeResponse(
IsSameOriginWithAncestors(resolver->DomWindow()->GetFrame()));
break;
- case RequiredOriginType::kSecureAndPermittedByFeaturePolicy:
+ case RequiredOriginType::
+ kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy:
SECURITY_CHECK(resolver->GetExecutionContext()->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kPublicKeyCredentialsGet));
break;
+
+ case RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy:
+ SECURITY_CHECK(
+ resolver->GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kOTPCredentials) &&
+ IsAncestorChainValidForWebOTP(resolver->DomWindow()->GetFrame()));
+ break;
}
}
@@ -579,73 +638,49 @@ void OnSmsReceive(ScriptPromiseResolver* resolver,
mojom::blink::SmsStatus status,
const WTF::String& otp) {
AssertSecurityRequirementsBeforeResponse(
- resolver, RequiredOriginType::kSecureAndSameWithAncestors);
- auto& window = *LocalDOMWindow::From(resolver->GetScriptState());
- ukm::SourceId source_id = window.UkmSourceID();
- ukm::UkmRecorder* recorder = window.UkmRecorder();
-
+ resolver, resolver->GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kOTPCredentials)
+ ? RequiredOriginType::
+ kSecureAndPermittedByWebOTPAssertionFeaturePolicy
+ : RequiredOriginType::kSecureAndSameWithAncestors);
if (status == mojom::blink::SmsStatus::kUnhandledRequest) {
- RecordSmsOutcome(WebOTPServiceOutcome::kUnhandledRequest, source_id,
- recorder);
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
"OTP retrieval request not handled."));
return;
} else if (status == mojom::blink::SmsStatus::kAborted) {
- RecordSmsOutcome(WebOTPServiceOutcome::kAborted, source_id, recorder);
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kAbortError, "OTP retrieval was aborted."));
return;
} else if (status == mojom::blink::SmsStatus::kCancelled) {
- RecordSmsOutcome(WebOTPServiceOutcome::kCancelled, source_id, recorder);
- RecordSmsCancelTime(base::TimeTicks::Now() - start_time);
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kAbortError, "OTP retrieval was cancelled."));
return;
} else if (status == mojom::blink::SmsStatus::kTimeout) {
- RecordSmsOutcome(WebOTPServiceOutcome::kTimeout, source_id, recorder);
- // We do not reject the promise as in other branches because the failure
- // may not belong to the origin that sends the request. e.g. there are two
- // origins A and B in the queue and A aborts the request. The prompt that
- // is timeout may belong to A but we are sending the failure information to
- // the only origin in the queue which is B. Therefore rejecting the promise
- // may leak information. This should be rare so recording metrics is fine.
- // TODO(crbug.com/1138454): We should improve the infrastructure to be able
- // to handle failed requests when there are multiple pending origins
- // simultaneously.
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError, "OTP retrieval timed out."));
return;
- } else if (status == mojom::blink::SmsStatus::kUserCancelled) {
- RecordSmsOutcome(WebOTPServiceOutcome::kUserCancelled, source_id, recorder);
- RecordSmsUserCancelTime(base::TimeTicks::Now() - start_time, source_id,
- recorder);
- // Similar to kTimeout, the promise is not rejected here.
+ } else if (status == mojom::blink::SmsStatus::kBackendNotAvailable) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError, "OTP backend unavailable."));
return;
}
- RecordSmsSuccessTime(base::TimeTicks::Now() - start_time, source_id,
- recorder);
- RecordSmsOutcome(WebOTPServiceOutcome::kSuccess, source_id, recorder);
resolver->Resolve(MakeGarbageCollected<OTPCredential>(otp));
}
void OnPaymentCredentialCreationComplete(
std::unique_ptr<ScopedPromiseResolver> scoped_resolver,
MakeCredentialAuthenticatorResponsePtr credential,
- PaymentCredentialCreationStatus status) {
+ PaymentCredentialStorageStatus status) {
auto* resolver = scoped_resolver->Release();
- if (status == PaymentCredentialCreationStatus::FAILED_TO_DOWNLOAD_ICON) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNetworkError,
- "Unable to download payment instrument icon."));
- return;
- } else if (status ==
- PaymentCredentialCreationStatus::FAILED_TO_STORE_INSTRUMENT) {
+ if (status == PaymentCredentialStorageStatus::FAILED_TO_STORE_INSTRUMENT) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kUnknownError,
"Failed to store payment instrument."));
return;
} else {
- DCHECK(status == PaymentCredentialCreationStatus::SUCCESS);
+ DCHECK(status == PaymentCredentialStorageStatus::SUCCESS);
}
DOMArrayBuffer* client_data_buffer =
@@ -671,6 +706,14 @@ void OnPaymentCredentialCreationComplete(
AuthenticationExtensionsClientOutputs::Create()));
}
+void OnPaymentCredentialCreationFailure(
+ std::unique_ptr<ScopedPromiseResolver> scoped_resolver,
+ AuthenticatorStatus status) {
+ auto* resolver = scoped_resolver->Release();
+ resolver->Reject(CredentialManagerErrorToDOMException(
+ mojo::ConvertTo<CredentialManagerError>(status)));
+}
+
void OnMakePublicKeyCredentialForPaymentComplete(
std::unique_ptr<ScopedPromiseResolver> scoped_resolver,
const PaymentCredentialCreationOptions* options,
@@ -680,32 +723,58 @@ void OnMakePublicKeyCredentialForPaymentComplete(
const auto required_origin_type = RequiredOriginType::kSecure;
AssertSecurityRequirementsBeforeResponse(resolver, required_origin_type);
+ auto* payment_credential_remote =
+ CredentialManagerProxy::From(resolver->GetScriptState())
+ ->PaymentCredential();
if (status == AuthenticatorStatus::SUCCESS) {
DCHECK(credential);
DCHECK(!credential->info->client_data_json.IsEmpty());
DCHECK(!credential->attestation_object.IsEmpty());
- auto payment_instrument = PaymentCredentialInstrument::New();
- payment_instrument->display_name = options->instrument()->displayName();
- payment_instrument->icon = KURL(options->instrument()->icon());
-
- 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_id, options->rp()->id(),
- WTF::Bind(
- &OnPaymentCredentialCreationComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver)),
- std::move(credential)));
+ payment_credential_remote->StorePaymentCredentialAndHideUserPrompt(
+ PaymentCredentialInstrument::New(options->instrument()->displayName(),
+ KURL(options->instrument()->icon())),
+ credential_id, options->rp()->id(),
+ WTF::Bind(&OnPaymentCredentialCreationComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver),
+ std::move(credential)));
} else {
DCHECK(!credential);
- resolver->Reject(CredentialManagerErrorToDOMException(
- mojo::ConvertTo<CredentialManagerError>(status)));
+ payment_credential_remote->HideUserPrompt(
+ WTF::Bind(&OnPaymentCredentialCreationFailure,
+ std::make_unique<ScopedPromiseResolver>(resolver), status));
}
}
+void DidDownloadPaymentCredentialIconAndShowUserPrompt(
+ std::unique_ptr<ScopedPromiseResolver> scoped_resolver,
+ mojom::blink::PublicKeyCredentialCreationOptionsPtr mojo_options,
+ const PaymentCredentialCreationOptions* options,
+ PaymentCredentialUserPromptStatus status) {
+ auto* resolver = scoped_resolver->Release();
+ if (status == PaymentCredentialUserPromptStatus::FAILED_TO_DOWNLOAD_ICON) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "Unable to download payment instrument icon."));
+ return;
+ } else if (status == PaymentCredentialUserPromptStatus::USER_CANCEL_FROM_UI) {
+ resolver->Reject(
+ CredentialManagerErrorToDOMException(CredentialManagerError::ABORT));
+ return;
+ } else {
+ DCHECK(status == PaymentCredentialUserPromptStatus::USER_CONFIRM_FROM_UI);
+ }
+
+ auto* authenticator =
+ CredentialManagerProxy::From(resolver->GetScriptState())->Authenticator();
+ authenticator->MakeCredential(
+ std::move(mojo_options),
+ WTF::Bind(&OnMakePublicKeyCredentialForPaymentComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver),
+ WrapPersistent(options)));
+}
+
void CreatePublicKeyCredentialForPaymentCredential(
const PaymentCredentialCreationOptions* options,
ScriptPromiseResolver* resolver) {
@@ -825,13 +894,19 @@ void CreatePublicKeyCredentialForPaymentCredential(
return;
}
- auto* authenticator =
- CredentialManagerProxy::From(resolver->GetScriptState())->Authenticator();
- authenticator->MakeCredential(
- std::move(mojo_options),
- WTF::Bind(&OnMakePublicKeyCredentialForPaymentComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver)),
- WrapPersistent(options)));
+ mojo_options->is_payment_credential_creation = true;
+
+ // Download instrument icon and prompt the user before creating the
+ // credential.
+ auto* payment_credential_remote =
+ CredentialManagerProxy::From(resolver->GetScriptState())
+ ->PaymentCredential();
+ payment_credential_remote->DownloadIconAndShowUserPrompt(
+ PaymentCredentialInstrument::New(options->instrument()->displayName(),
+ KURL(options->instrument()->icon())),
+ WTF::Bind(&DidDownloadPaymentCredentialIconAndShowUserPrompt,
+ std::make_unique<ScopedPromiseResolver>(resolver),
+ std::move(mojo_options), WrapPersistent(options)));
}
} // namespace
@@ -857,18 +932,33 @@ ScriptPromise CredentialsContainer::get(
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
+ auto required_origin_type = RequiredOriginType::kSecureAndSameWithAncestors;
// hasPublicKey() implies that this is a WebAuthn request.
- auto required_origin_type =
- options->hasPublicKey() &&
- RuntimeEnabledFeatures::
- WebAuthenticationGetAssertionFeaturePolicyEnabled()
- ? RequiredOriginType::kSecureAndPermittedByFeaturePolicy
- : RequiredOriginType::kSecureAndSameWithAncestors;
+ if ((options->hasPublicKey() || options->hasConditionalPublicKey()) &&
+ RuntimeEnabledFeatures::
+ WebAuthenticationGetAssertionFeaturePolicyEnabled()) {
+ required_origin_type = RequiredOriginType::
+ kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy;
+ } else if (options->hasOtp() &&
+ RuntimeEnabledFeatures::WebOTPAssertionFeaturePolicyEnabled()) {
+ required_origin_type =
+ RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy;
+ }
if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type)) {
return promise;
}
- if (options->hasPublicKey()) {
+ if (options->hasPublicKey() || options->hasConditionalPublicKey()) {
+ const PublicKeyCredentialRequestOptions* public_key_options;
+ bool is_conditional_ui_request;
+ if (options->hasPublicKey()) {
+ public_key_options = options->publicKey();
+ is_conditional_ui_request = false;
+ } else {
+ public_key_options = options->conditionalPublicKey();
+ is_conditional_ui_request = true;
+ }
+
auto cryptotoken_origin = SecurityOrigin::Create(KURL(kCryptotokenOrigin));
if (!cryptotoken_origin->IsSameOriginWith(
resolver->GetExecutionContext()->GetSecurityOrigin())) {
@@ -877,22 +967,23 @@ ScriptPromise CredentialsContainer::get(
UseCounter::Count(resolver->GetExecutionContext(),
WebFeature::kCredentialManagerGetPublicKeyCredential);
}
+
#if defined(OS_ANDROID)
- if (options->publicKey()->hasExtensions() &&
- options->publicKey()->extensions()->hasUvm()) {
+ if (public_key_options->hasExtensions() &&
+ public_key_options->extensions()->hasUvm()) {
UseCounter::Count(resolver->GetExecutionContext(),
WebFeature::kCredentialManagerGetWithUVM);
}
#endif
- if (!IsArrayBufferOrViewBelowSizeLimit(options->publicKey()->challenge())) {
+ if (!IsArrayBufferOrViewBelowSizeLimit(public_key_options->challenge())) {
resolver->Reject(DOMException::Create(
"The `challenge` attribute exceeds the maximum allowed size.",
"RangeError"));
return promise;
}
- if (options->publicKey()->hasExtensions()) {
- if (options->publicKey()->extensions()->hasAppid()) {
- const auto& appid = options->publicKey()->extensions()->appid();
+ if (public_key_options->hasExtensions()) {
+ if (public_key_options->extensions()->hasAppid()) {
+ const auto& appid = public_key_options->extensions()->appid();
if (!appid.IsEmpty()) {
KURL appid_url(appid);
if (!appid_url.IsValid()) {
@@ -904,24 +995,24 @@ ScriptPromise CredentialsContainer::get(
}
}
}
- if (options->publicKey()->extensions()->hasCableRegistration()) {
+ if (public_key_options->extensions()->hasCableRegistration()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError,
"The 'cableRegistration' extension is only valid when creating "
"a credential"));
return promise;
}
- if (options->publicKey()->extensions()->credProps()) {
+ if (public_key_options->extensions()->credProps()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError,
"The 'credProps' extension is only valid when creating "
"a credential"));
return promise;
}
- if (options->publicKey()->extensions()->hasLargeBlob()) {
+ if (public_key_options->extensions()->hasLargeBlob()) {
DCHECK(RuntimeEnabledFeatures::
WebAuthenticationLargeBlobExtensionEnabled());
- if (options->publicKey()->extensions()->largeBlob()->hasSupport()) {
+ if (public_key_options->extensions()->largeBlob()->hasSupport()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError,
"The 'largeBlob' extension's 'support' parameter is only valid "
@@ -931,7 +1022,7 @@ ScriptPromise CredentialsContainer::get(
}
}
- if (!options->publicKey()->hasUserVerification()) {
+ if (!public_key_options->hasUserVerification()) {
resolver->DomWindow()->AddConsoleMessage(
MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kJavaScript,
@@ -956,9 +1047,19 @@ ScriptPromise CredentialsContainer::get(
WTF::Bind(&AbortPublicKeyRequest, WrapPersistent(script_state)));
}
+ if (is_conditional_ui_request &&
+ public_key_options->hasAllowCredentials() &&
+ !public_key_options->allowCredentials().IsEmpty()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError,
+ "allowCredentials is not supported for conditionalPublicKey"));
+ return promise;
+ }
+
auto mojo_options =
- MojoPublicKeyCredentialRequestOptions::From(*options->publicKey());
+ MojoPublicKeyCredentialRequestOptions::From(*public_key_options);
if (mojo_options) {
+ mojo_options->is_conditional = is_conditional_ui_request;
if (!mojo_options->relying_party_id) {
mojo_options->relying_party_id =
resolver->GetExecutionContext()->GetSecurityOrigin()->Domain();
@@ -967,9 +1068,8 @@ ScriptPromise CredentialsContainer::get(
CredentialManagerProxy::From(script_state)->Authenticator();
authenticator->GetAssertion(
std::move(mojo_options),
- WTF::Bind(
- &OnGetAssertionComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
+ WTF::Bind(&OnGetAssertionComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver)));
} else {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError,
@@ -996,11 +1096,6 @@ ScriptPromise CredentialsContainer::get(
WTF::Bind(&AbortOtpRequest, WrapPersistent(script_state)));
}
- if (!CheckSecurityRequirementsBeforeRequest(
- resolver, RequiredOriginType::kSecureAndSameWithAncestors)) {
- return promise;
- }
-
auto* webotp_service =
CredentialManagerProxy::From(script_state)->WebOTPService();
webotp_service->Receive(WTF::Bind(&OnSmsReceive, WrapPersistent(resolver),
@@ -1039,7 +1134,7 @@ ScriptPromise CredentialsContainer::get(
credential_manager->Get(
requirement, options->password(), std::move(providers),
WTF::Bind(&OnGetComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver)),
+ std::make_unique<ScopedPromiseResolver>(resolver),
required_origin_type));
return promise;
@@ -1077,9 +1172,8 @@ ScriptPromise CredentialsContainer::store(ScriptState* script_state,
CredentialManagerProxy::From(script_state)->CredentialManager();
credential_manager->Store(
CredentialInfo::From(credential),
- WTF::Bind(
- &OnStoreComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
+ WTF::Bind(&OnStoreComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver)));
return promise;
}
@@ -1122,7 +1216,9 @@ ScriptPromise CredentialsContainer::create(
FederatedCredential::Create(options->federated(), exception_state));
} else if (options->hasPayment()) {
if (RuntimeEnabledFeatures::SecurePaymentConfirmationEnabled(
- resolver->GetExecutionContext())) {
+ resolver->GetExecutionContext()) &&
+ resolver->GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kPayment)) {
CreatePublicKeyCredentialForPaymentCredential(options->payment(),
resolver);
} else {
@@ -1292,9 +1388,8 @@ ScriptPromise CredentialsContainer::create(
CredentialManagerProxy::From(script_state)->Authenticator();
authenticator->MakeCredential(
std::move(mojo_options),
- WTF::Bind(
- &OnMakePublicKeyCredentialComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
+ WTF::Bind(&OnMakePublicKeyCredentialComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver)));
}
}
@@ -1312,9 +1407,9 @@ ScriptPromise CredentialsContainer::preventSilentAccess(
auto* credential_manager =
CredentialManagerProxy::From(script_state)->CredentialManager();
- credential_manager->PreventSilentAccess(WTF::Bind(
- &OnPreventSilentAccessComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
+ credential_manager->PreventSilentAccess(
+ WTF::Bind(&OnPreventSilentAccessComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver)));
return promise;
}
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 20e2b809cde..0463d18e65d 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
@@ -178,8 +178,7 @@ TEST(CredentialsContainerTest,
mock_credential_manager.InvokeGetCallback();
- EXPECT_EQ(v8::Promise::kPending,
- promise.V8Value().As<v8::Promise>()->State());
+ EXPECT_EQ(v8::Promise::kPending, promise.V8Promise()->State());
}
TEST(CredentialsContainerTest, RejectPublicKeyCredentialStoreOperation) {
@@ -191,8 +190,7 @@ TEST(CredentialsContainerTest, RejectPublicKeyCredentialStoreOperation) {
->store(context.GetScriptState(),
MakeGarbageCollected<MockPublicKeyCredential>());
- EXPECT_EQ(v8::Promise::kRejected,
- promise.V8Value().As<v8::Promise>()->State());
+ EXPECT_EQ(v8::Promise::kRejected, promise.V8Promise()->State());
}
TEST(CredentialsContainerTest,
@@ -208,7 +206,7 @@ TEST(CredentialsContainerTest,
CredentialsContainer::credentials(*context.DomWindow().navigator())
->store(context.GetScriptState(), credential);
- auto v8promise = promise.V8Value().As<v8::Promise>();
+ auto v8promise = promise.V8Promise();
EXPECT_EQ(v8::Promise::kRejected, v8promise->State());
auto* exception = ToScriptWrappable(v8promise->Result().As<v8::Object>())
@@ -231,7 +229,7 @@ TEST(CredentialsContainerTest,
CredentialsContainer::credentials(*context.DomWindow().navigator())
->store(context.GetScriptState(), credential);
- auto v8promise = promise.V8Value().As<v8::Promise>();
+ auto v8promise = promise.V8Promise();
EXPECT_EQ(v8::Promise::kRejected, v8promise->State());
auto* exception = ToScriptWrappable(v8promise->Result().As<v8::Object>())
@@ -278,7 +276,7 @@ TEST(CredentialsContainerTest,
->create(context.GetScriptState(), credential_options,
IGNORE_EXCEPTION_FOR_TESTING);
- auto v8promise = promise.V8Value().As<v8::Promise>();
+ auto v8promise = promise.V8Promise();
EXPECT_EQ(v8::Promise::kRejected, v8promise->State());
auto* exception = ToScriptWrappable(v8promise->Result().As<v8::Object>())
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.cc
index 470a32dbc97..7461beab985 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/public_key_credential.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/credentialmanager/public_key_credential.h"
+#include <utility>
+
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -59,9 +61,9 @@ PublicKeyCredential::isUserVerifyingPlatformAuthenticatorAvailable(
auto* authenticator =
CredentialManagerProxy::From(script_state)->Authenticator();
- authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(WTF::Bind(
- &OnIsUserVerifyingComplete,
- WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver))));
+ authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(
+ WTF::Bind(&OnIsUserVerifyingComplete,
+ std::make_unique<ScopedPromiseResolver>(resolver)));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/crypto/DIR_METADATA b/chromium/third_party/blink/renderer/modules/crypto/DIR_METADATA
new file mode 100644
index 00000000000..e6176439b82
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/crypto/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebCrypto"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/crypto/OWNERS b/chromium/third_party/blink/renderer/modules/crypto/OWNERS
index b89daa82485..e69de29bb2d 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/crypto/OWNERS
@@ -1 +0,0 @@
-# COMPONENT: Blink>WebCrypto
diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto.cc b/chromium/third_party/blink/renderer/modules/crypto/crypto.cc
index 85e4c4e451d..513c634d09d 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/crypto.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/crypto.cc
@@ -36,7 +36,7 @@ namespace blink {
namespace {
-bool IsIntegerArray(DOMArrayBufferView* array) {
+bool IsIntegerArray(NotShared<DOMArrayBufferView> array) {
DOMArrayBufferView::ViewType type = array->GetType();
return type == DOMArrayBufferView::kTypeInt8 ||
type == DOMArrayBufferView::kTypeUint8 ||
@@ -53,24 +53,24 @@ NotShared<DOMArrayBufferView> Crypto::getRandomValues(
NotShared<DOMArrayBufferView> array,
ExceptionState& exception_state) {
DCHECK(array);
- if (!IsIntegerArray(array.View())) {
+ if (!IsIntegerArray(array)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kTypeMismatchError,
String::Format("The provided ArrayBufferView is of type '%s', which is "
"not an integer array type.",
- array.View()->TypeName()));
+ array->TypeName()));
return NotShared<DOMArrayBufferView>(nullptr);
}
- if (array.View()->byteLength() > 65536) {
+ if (array->byteLength() > 65536) {
exception_state.ThrowDOMException(
DOMExceptionCode::kQuotaExceededError,
String::Format("The ArrayBufferView's byte length (%zu) exceeds the "
"number of bytes of entropy available via this API "
"(65536).",
- array.View()->byteLength()));
+ array->byteLength()));
return NotShared<DOMArrayBufferView>(nullptr);
}
- crypto::RandBytes(array.View()->BaseAddress(), array.View()->byteLength());
+ crypto::RandBytes(array->BaseAddress(), array->byteLength());
return array;
}
diff --git a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
index 893cf784b8f..11c6b295b2d 100644
--- a/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
+++ b/chromium/third_party/blink/renderer/modules/crypto/subtle_crypto.cc
@@ -407,7 +407,7 @@ ScriptPromise SubtleCrypto::importKey(
if (raw_key_data.IsArrayBuffer()) {
key_data = CopyBytes(raw_key_data.GetAsArrayBuffer());
} else if (raw_key_data.IsArrayBufferView()) {
- key_data = CopyBytes(raw_key_data.GetAsArrayBufferView().View());
+ key_data = CopyBytes(raw_key_data.GetAsArrayBufferView().Get());
} else {
result->CompleteWithError(
kWebCryptoErrorTypeType,
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn b/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
index 3a72840f595..48cd55d5699 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
@@ -6,6 +6,10 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("csspaint") {
sources = [
+ "background_color_paint_image_generator_impl.cc",
+ "background_color_paint_image_generator_impl.h",
+ "background_color_paint_worklet.cc",
+ "background_color_paint_worklet.h",
"css_paint_definition.cc",
"css_paint_definition.h",
"css_paint_image_generator_impl.cc",
@@ -14,10 +18,9 @@ blink_modules_sources("csspaint") {
"css_paint_worklet.h",
"document_paint_definition.cc",
"document_paint_definition.h",
- "native_paint_image_generator_impl.cc",
- "native_paint_image_generator_impl.h",
"native_paint_worklet.cc",
"native_paint_worklet.h",
+ "native_paint_worklet_proxy_client.h",
"paint_rendering_context_2d.cc",
"paint_rendering_context_2d.h",
"paint_size.h",
@@ -27,6 +30,8 @@ blink_modules_sources("csspaint") {
"paint_worklet_global_scope.h",
"paint_worklet_global_scope_proxy.cc",
"paint_worklet_global_scope_proxy.h",
+ "paint_worklet_id_generator.cc",
+ "paint_worklet_id_generator.h",
"paint_worklet_messaging_proxy.cc",
"paint_worklet_messaging_proxy.h",
"paint_worklet_pending_generator_registry.cc",
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/DIR_METADATA b/chromium/third_party/blink/renderer/modules/csspaint/DIR_METADATA
new file mode 100644
index 00000000000..660b831728f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/OWNERS b/chromium/third_party/blink/renderer/modules/csspaint/OWNERS
index f61c6d21618..cffe5fc12a3 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/csspaint/OWNERS
@@ -1,6 +1,3 @@
flackr@chromium.org
ikilpatrick@chromium.org
xidachen@chromium.org
-
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/README.md b/chromium/third_party/blink/renderer/modules/csspaint/README.md
index 2b70c76e1a7..26a07ad805c 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/README.md
+++ b/chromium/third_party/blink/renderer/modules/csspaint/README.md
@@ -50,16 +50,84 @@ During the main thread paint, the `PaintWorklet::Paint` is called, which
executes the V8 paint callback synchronously. A PaintRecord is produced and
passed to the compositor thread to raster.
+When animation is involved, the main thread animation system updates the value
+of the animated properties, which are used by the `PaintWorklet::Paint`.
+
### Off main thread workflow
-During the main thread paint, a
-[PaintWorkletInput](../../core/css/cssom/paint_worklet_input.h) is created and
-passed to the compositor. The PaintWorkletInput contains all necessary
-information for the compositor to run the V8 paint callback. The compositor
-thread asynchronously dispatches the V8 paint callback to a Worklet thread.
-The V8 paint callback is then executed on the Worklet thread and a PaintRecord is
-given back to the compositor thread. The compositor thread then rasters the
-PaintRecord.
+Let's see how it works without animations.
+
+1. During the main thread paint, a
+ [PaintWorkletDeferredImage](../../core/css/cssom/paint_worklet_deferred_image.h)
+ is created. This is an image without any color information, it is a
+ placeholder to the Blink paint system. The creation of its actual content
+ is deferred to CC raster time. It holds input arguments which is
+ encapsulated in [CSSPaintWorkletInput](../../core/css/cssom/css_paint_worklet_input.h).
+ The input arguments contain necessary information for the CC raster phase.
+
+1. During commit, the `PaintWorkletInput` is passed to CC. Specifically, the
+ `PictureLayerImpl` owns `PaintWorkletRecordMap`, which is a map from
+ `PaintWorkletInput` to `std::pair<PaintImage::Id, PaintRecord>`. The
+ `PaintImage::Id` is used for efficient invalidation. The `PaintRecord` is
+ the actual content of the `PaintWorkletDeferredImage`, which will be
+ generated at CC raster time. Initially the `PaintRecord` is `nullptr` which
+ indicates that it needs to be produced.
+
+1. After commit, we need to update the pending tree. This happens in
+ `LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation`.
+ There are two steps involved.
+
+ 1. The first step is to gather all dirty paint worklets that need to be
+ updated, which happens in `LayerTreeHostImpl::GatherDirtyPaintWorklets`. It
+ basically goes through each `PictureLayerImpl` whose
+ `PaintWorkletRecrodMap` isn't empty, and if there is a `PaintWorkletInput`
+ with its associated `PaintRecord` being nullptr, then this worklet needs to
+ be updated.
+
+ 1. Once we have gathered all the dirty paint worklets, the next step is to
+ produce the `PaintRecord` which is the actual contents. The compositor
+ thread asynchronously dispatches the paint jobs that produce the
+ `PaintRecord` to a worklet thread. Each paint job is basically a V8 paint
+ callback, the paint callback is executed on the worklet thread and the
+ `PaintRecord` is given back to the compositor thread such that it can be
+ rastered. Given that the V8 paint callback contains user defined javascript
+ code and can take arbitrary amount of time, the paint job doesn't block the
+ tree activation. In other word, the pending tree can be activated even if
+ the paint jobs are not finished, it will just use the `PaintRecord` that
+ was produced in the previous frame.
+
+Now let's see how it works with animation. Here is an
+[example](https://jsbin.com/muwiyux/9/edit?html,css,output) that animates a
+custom property '--foo' with paint worklet. Traditionally
+[custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
+cannot be animated on the compositor thread. With off main thread paint worklet
+design, we can animate the custom properties off the main thread and use them in
+paint worklet. Note that currently our implementation supports custom property
+animations only, not native properties. We do intend to extend to support
+native properties in the future.
+
+1. When resolving style, `CompositorKeyframeValue` will be created through
+ `CompositorKeyframeValueFactory::Create` function. This basically tells the
+ main thread animation system to not animate the custom properties, and
+ instead creating a compositor animation for each custom property.
+
+1. After Blink paint, a compositor animation will be created through the
+ `CreateCompositorAnimation` function. The compositor animation is passed to
+ CC via commit process.
+
+1. CC ticks the compositor animation, which updates the value for the custom
+ property. Currently we only support custom properties that represents number
+ or color. This is handled by
+ `AnimatedPaintWorkletTracker::OnCustomPropertyMutated`. The
+ `AnimatedPaintWorkletTracker` class handles custom properties animated by
+ paint worklet.
+
+1. By combining custom property name with `ElementId`, we create
+ `PaintWorkletInput::PropertyKey` which can be used to identify a
+ `PaintWorkletInput`. Then we can use the `PaintWorkletInput` to find its
+ associated `PaintRecord` in the `PictureLayerImpl`'s `PaintWorkletRecordMap`,
+ invalidate it and update its content when we update the pending tree via
+ `LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation`.
## Implementation
@@ -116,4 +184,3 @@ paint.
Tests live [here](../../../web_tests/http/tests/csspaint/) and
[here](../../../web_tests/external/wpt/css/css-paint-api/).
-
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.cc b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.cc
new file mode 100644
index 00000000000..3d87d0746b3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h"
+
+#include "third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h"
+#include "third_party/blink/renderer/platform/graphics/image.h"
+
+namespace blink {
+
+BackgroundColorPaintImageGenerator*
+BackgroundColorPaintImageGeneratorImpl::Create(LocalFrame& local_root) {
+ BackgroundColorPaintWorklet* background_color_paint_worklet =
+ BackgroundColorPaintWorklet::Create(local_root);
+
+ DCHECK(background_color_paint_worklet);
+ BackgroundColorPaintImageGeneratorImpl* generator =
+ MakeGarbageCollected<BackgroundColorPaintImageGeneratorImpl>(
+ background_color_paint_worklet);
+
+ return generator;
+}
+
+BackgroundColorPaintImageGeneratorImpl::BackgroundColorPaintImageGeneratorImpl(
+ BackgroundColorPaintWorklet* background_color_paint_worklet)
+ : background_color_paint_worklet_(background_color_paint_worklet) {}
+
+scoped_refptr<Image> BackgroundColorPaintImageGeneratorImpl::Paint(
+ const FloatSize& container_size,
+ const Node* node,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets) {
+ return background_color_paint_worklet_->Paint(container_size, node,
+ animated_colors, offsets);
+}
+
+bool BackgroundColorPaintImageGeneratorImpl::GetBGColorPaintWorkletParams(
+ Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) {
+ return BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ node, animated_colors, offsets);
+}
+
+void BackgroundColorPaintImageGeneratorImpl::Shutdown() {
+ background_color_paint_worklet_->UnregisterProxyClient();
+}
+
+void BackgroundColorPaintImageGeneratorImpl::Trace(Visitor* visitor) const {
+ visitor->Trace(background_color_paint_worklet_);
+ BackgroundColorPaintImageGenerator::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h
new file mode 100644
index 00000000000..a8fabf9747e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_IMPL_H_
+
+#include "third_party/blink/renderer/core/css/background_color_paint_image_generator.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class Image;
+class BackgroundColorPaintWorklet;
+
+class MODULES_EXPORT BackgroundColorPaintImageGeneratorImpl final
+ : public BackgroundColorPaintImageGenerator {
+ public:
+ static BackgroundColorPaintImageGenerator* Create(LocalFrame&);
+
+ explicit BackgroundColorPaintImageGeneratorImpl(BackgroundColorPaintWorklet*);
+ ~BackgroundColorPaintImageGeneratorImpl() override = default;
+
+ // The |container_size| is without subpixel snapping.
+ scoped_refptr<Image> Paint(const FloatSize& container_size,
+ const Node*,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets) final;
+
+ bool GetBGColorPaintWorkletParams(Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) final;
+
+ void Shutdown() final;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ Member<BackgroundColorPaintWorklet> background_color_paint_worklet_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_IMAGE_GENERATOR_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.cc b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.cc
new file mode 100644
index 00000000000..1a9ea1e2ceb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.cc
@@ -0,0 +1,288 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h"
+
+#include "third_party/blink/renderer/core/animation/animation_effect.h"
+#include "third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h"
+#include "third_party/blink/renderer/core/animation/css_color_interpolation_type.h"
+#include "third_party/blink/renderer/core/animation/element_animations.h"
+#include "third_party/blink/renderer/core/css/css_color_value.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h"
+#include "third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/platform_paint_worklet_layer_painter.h"
+
+namespace blink {
+
+namespace {
+
+const float kProgressBoundsTolerance = 0.000001f;
+
+// This class includes information that is required by the compositor thread
+// when painting background color.
+class BackgroundColorPaintWorkletInput : public PaintWorkletInput {
+ public:
+ BackgroundColorPaintWorkletInput(
+ const FloatSize& container_size,
+ int worklet_id,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets,
+ cc::PaintWorkletInput::PropertyKeys property_keys)
+ : PaintWorkletInput(container_size, worklet_id, std::move(property_keys)),
+ animated_colors_(animated_colors),
+ offsets_(offsets) {}
+
+ ~BackgroundColorPaintWorkletInput() override = default;
+
+ const Vector<Color>& AnimatedColors() const { return animated_colors_; }
+ const Vector<double>& Offsets() const { return offsets_; }
+
+ private:
+ Vector<Color> animated_colors_;
+ Vector<double> offsets_;
+};
+
+class BackgroundColorPaintWorkletProxyClient
+ : public NativePaintWorkletProxyClient {
+ DISALLOW_COPY_AND_ASSIGN(BackgroundColorPaintWorkletProxyClient);
+
+ public:
+ static BackgroundColorPaintWorkletProxyClient* Create(int worklet_id) {
+ return MakeGarbageCollected<BackgroundColorPaintWorkletProxyClient>(
+ worklet_id);
+ }
+
+ explicit BackgroundColorPaintWorkletProxyClient(int worklet_id)
+ : NativePaintWorkletProxyClient(worklet_id) {}
+ ~BackgroundColorPaintWorkletProxyClient() override = default;
+
+ // PaintWorkletPainter implementation.
+ sk_sp<PaintRecord> Paint(
+ const CompositorPaintWorkletInput* compositor_input,
+ const CompositorPaintWorkletJob::AnimatedPropertyValues&
+ animated_property_values) override {
+ if (animated_property_values.empty())
+ return nullptr;
+ const BackgroundColorPaintWorkletInput* input =
+ static_cast<const BackgroundColorPaintWorkletInput*>(compositor_input);
+ FloatSize container_size = input->ContainerSize();
+ Vector<Color> animated_colors = input->AnimatedColors();
+ Vector<double> offsets = input->Offsets();
+ DCHECK_GT(animated_colors.size(), 1u);
+ DCHECK_EQ(animated_colors.size(), offsets.size());
+
+ DCHECK_EQ(animated_property_values.size(), 1u);
+ const auto& entry = animated_property_values.begin();
+ float progress = entry->second.float_value.value();
+
+ // Get the start and end color based on the progress and offsets.
+ unsigned result_index = offsets.size() - 1;
+ // The progress of the animation might outside of [0, 1] by
+ // kProgressBoundsTolerance.
+ if (progress <= 0) {
+ result_index = 0;
+ DCHECK_GE(progress, -kProgressBoundsTolerance);
+ } else if (progress > 0 && progress < 1) {
+ for (unsigned i = 0; i < offsets.size() - 1; i++) {
+ if (progress <= offsets[i + 1]) {
+ result_index = i;
+ break;
+ }
+ }
+ }
+ if (result_index == offsets.size() - 1) {
+ DCHECK_LE(std::fabs(progress - 1), kProgressBoundsTolerance);
+ result_index = offsets.size() - 2;
+ }
+ // Because the progress is a global one, we need to adjust it with offsets.
+ float adjusted_progress =
+ (progress - offsets[result_index]) /
+ (offsets[result_index + 1] - offsets[result_index]);
+ std::unique_ptr<InterpolableValue> from =
+ CSSColorInterpolationType::CreateInterpolableColor(
+ animated_colors[result_index]);
+ std::unique_ptr<InterpolableValue> to =
+ CSSColorInterpolationType::CreateInterpolableColor(
+ animated_colors[result_index + 1]);
+ std::unique_ptr<InterpolableValue> result =
+ CSSColorInterpolationType::CreateInterpolableColor(
+ animated_colors[result_index + 1]);
+ from->Interpolate(*to, adjusted_progress, *result);
+ Color rgba = CSSColorInterpolationType::GetRGBA(*(result.get()));
+ SkColor current_color = static_cast<SkColor>(rgba);
+
+ PaintRenderingContext2DSettings* context_settings =
+ PaintRenderingContext2DSettings::Create();
+ auto* rendering_context = MakeGarbageCollected<PaintRenderingContext2D>(
+ RoundedIntSize(container_size), context_settings, 1, 1);
+ rendering_context->GetPaintCanvas()->drawColor(current_color);
+ return rendering_context->GetRecord();
+ }
+};
+
+// TODO(crbug.com/1163949): Support animation keyframes without 0% or 100%.
+// Returns false if we cannot successfully get the animated color.
+bool GetColorsFromStringKeyframe(const PropertySpecificKeyframe* frame,
+ Vector<Color>* animated_colors,
+ const Element* element) {
+ DCHECK(frame->IsCSSPropertySpecificKeyframe());
+ const CSSValue* value = To<CSSPropertySpecificKeyframe>(frame)->Value();
+ if (!value)
+ return false;
+ const CSSPropertyName property_name =
+ CSSPropertyName(CSSPropertyID::kBackgroundColor);
+ const CSSValue* computed_value = StyleResolver::ComputeValue(
+ const_cast<Element*>(element), property_name, *value);
+ DCHECK(computed_value->IsColorValue());
+ const cssvalue::CSSColorValue* color_value =
+ static_cast<const cssvalue::CSSColorValue*>(computed_value);
+ animated_colors->push_back(color_value->Value());
+ return true;
+}
+
+// Returns false if we cannot successfully get the animated color.
+bool GetColorsFromTransitionKeyframe(const PropertySpecificKeyframe* frame,
+ Vector<Color>* animated_colors,
+ const Element* element) {
+ DCHECK(frame->IsTransitionPropertySpecificKeyframe());
+ const TransitionKeyframe::PropertySpecificKeyframe* keyframe =
+ To<TransitionKeyframe::PropertySpecificKeyframe>(frame);
+ InterpolableValue* value =
+ keyframe->GetValue()->Value().interpolable_value.get();
+ if (!value)
+ return false;
+ const InterpolableList& list = To<InterpolableList>(*value);
+ // Only the first one has the real value.
+ Color rgba = CSSColorInterpolationType::GetRGBA(*(list.Get(0)));
+ animated_colors->push_back(rgba);
+ return true;
+}
+
+void GetCompositorKeyframeOffset(const PropertySpecificKeyframe* frame,
+ Vector<double>* offsets) {
+ const CompositorKeyframeDouble& value =
+ To<CompositorKeyframeDouble>(*(frame->GetCompositorKeyframeValue()));
+ offsets->push_back(value.ToDouble());
+}
+
+bool GetBGColorPaintWorkletParamsInternal(Element* element,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) {
+ if (!element->GetElementAnimations())
+ return false;
+ // We composite the background color animation that has the highest composite
+ // order. Or if we have only one animation on background color and other
+ // animation(s) are on other properties, then we can also composite the
+ // background color animation.
+ Animation* composited_animation = nullptr;
+ for (const auto& animation : element->GetElementAnimations()->Animations()) {
+ if (animation.key->CalculateAnimationPlayState() == Animation::kIdle ||
+ !animation.key->Affects(*element, GetCSSPropertyBackgroundColor()))
+ continue;
+ animation.key->ResetCanCompositeBGColorAnim();
+ if (!composited_animation ||
+ Animation::HasLowerCompositeOrdering(
+ composited_animation, animation.key,
+ Animation::CompareAnimationsOrdering::kPointerOrder))
+ composited_animation = animation.key;
+ }
+ if (!composited_animation)
+ return false;
+
+ // If we are here, then this element must have one background color animation
+ // only. Fall back to the main thread if it is not composite:replace.
+ const AnimationEffect* effect = composited_animation->effect();
+ DCHECK(effect->IsKeyframeEffect());
+ const KeyframeEffectModelBase* model =
+ static_cast<const KeyframeEffect*>(effect)->Model();
+ if (model->Composite() != EffectModel::kCompositeReplace)
+ return false;
+ const PropertySpecificKeyframeVector* frames =
+ model->GetPropertySpecificKeyframes(
+ PropertyHandle(GetCSSPropertyBackgroundColor()));
+ DCHECK_GE(frames->size(), 2u);
+ for (const auto& frame : *frames) {
+ if (model->IsStringKeyframeEffectModel()) {
+ if (!GetColorsFromStringKeyframe(frame, animated_colors, element))
+ return false;
+ } else {
+ if (!GetColorsFromTransitionKeyframe(frame, animated_colors, element))
+ return false;
+ }
+ GetCompositorKeyframeOffset(frame, offsets);
+ }
+ composited_animation->SetCanCompositeBGColorAnim();
+ return true;
+}
+
+} // namespace
+
+// static
+BackgroundColorPaintWorklet* BackgroundColorPaintWorklet::Create(
+ LocalFrame& local_root) {
+ return MakeGarbageCollected<BackgroundColorPaintWorklet>(local_root);
+}
+
+BackgroundColorPaintWorklet::BackgroundColorPaintWorklet(LocalFrame& local_root)
+ : NativePaintWorklet(local_root) {
+ // This is called only once per document.
+ BackgroundColorPaintWorkletProxyClient* client =
+ BackgroundColorPaintWorkletProxyClient::Create(worklet_id_);
+ RegisterProxyClient(client);
+}
+
+BackgroundColorPaintWorklet::~BackgroundColorPaintWorklet() = default;
+
+scoped_refptr<Image> BackgroundColorPaintWorklet::Paint(
+ const FloatSize& container_size,
+ const Node* node,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets) {
+ node->GetLayoutObject()->GetMutableForPainting().EnsureId();
+ CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
+ node->GetLayoutObject()->UniqueId(),
+ CompositorAnimations::CompositorElementNamespaceForProperty(
+ CSSPropertyID::kBackgroundColor));
+ CompositorPaintWorkletInput::PropertyKeys input_property_keys;
+ input_property_keys.emplace_back(
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor,
+ element_id);
+ scoped_refptr<BackgroundColorPaintWorkletInput> input =
+ base::MakeRefCounted<BackgroundColorPaintWorkletInput>(
+ container_size, worklet_id_, animated_colors, offsets,
+ std::move(input_property_keys));
+ return PaintWorkletDeferredImage::Create(std::move(input), container_size);
+}
+
+bool BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets) {
+ DCHECK(node->IsElementNode());
+ Element* element = static_cast<Element*>(node);
+ return GetBGColorPaintWorkletParamsInternal(element, animated_colors,
+ offsets);
+}
+
+sk_sp<PaintRecord> BackgroundColorPaintWorklet::ProxyClientPaintForTest(
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets,
+ const CompositorPaintWorkletJob::AnimatedPropertyValues&
+ animated_property_values) {
+ FloatSize container_size(100, 100);
+ CompositorPaintWorkletInput::PropertyKeys property_keys;
+ scoped_refptr<BackgroundColorPaintWorkletInput> input =
+ base::MakeRefCounted<BackgroundColorPaintWorkletInput>(
+ container_size, 1u, animated_colors, offsets, property_keys);
+ BackgroundColorPaintWorkletProxyClient* client =
+ BackgroundColorPaintWorkletProxyClient::Create(1u);
+ return client->Paint(input.get(), animated_property_values);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h
new file mode 100644
index 00000000000..145e479b119
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_WORKLET_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_WORKLET_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
+#include "third_party/blink/renderer/modules/csspaint/native_paint_worklet.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace blink {
+
+class Image;
+class LocalFrame;
+class Node;
+
+class MODULES_EXPORT BackgroundColorPaintWorklet : public NativePaintWorklet {
+ DISALLOW_COPY_AND_ASSIGN(BackgroundColorPaintWorklet);
+
+ public:
+ static BackgroundColorPaintWorklet* Create(LocalFrame&);
+
+ explicit BackgroundColorPaintWorklet(LocalFrame&);
+ ~BackgroundColorPaintWorklet() final;
+
+ // The |container_size| is without subpixel snapping.
+ scoped_refptr<Image> Paint(const FloatSize& container_size,
+ const Node*,
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets);
+
+ // Get the animated colors and offsets from the animation keyframes.
+ // Returning false meaning that we need to fall back to the main thread for
+ // the animation.
+ static bool GetBGColorPaintWorkletParams(Node* node,
+ Vector<Color>* animated_colors,
+ Vector<double>* offsets);
+
+ // For testing purpose only.
+ static sk_sp<cc::PaintRecord> ProxyClientPaintForTest(
+ const Vector<Color>& animated_colors,
+ const Vector<double>& offsets,
+ const CompositorPaintWorkletJob::AnimatedPropertyValues&
+ animated_property_values);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_BACKGROUND_COLOR_PAINT_WORKLET_H_
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet_test.cc b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet_test.cc
new file mode 100644
index 00000000000..b3d4b9bdd04
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/background_color_paint_worklet_test.cc
@@ -0,0 +1,272 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/csspaint/background_color_paint_worklet.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/renderer/core/animation/document_timeline.h"
+#include "third_party/blink/renderer/core/animation/element_animations.h"
+#include "third_party/blink/renderer/core/animation/inert_effect.h"
+#include "third_party/blink/renderer/core/animation/keyframe_effect.h"
+#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
+#include "third_party/blink/renderer/core/animation/string_keyframe.h"
+#include "third_party/blink/renderer/core/animation/timing.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/platform_paint_worklet_layer_painter.h"
+
+namespace blink {
+
+using BackgroundColorPaintWorkletTest = PageTestBase;
+
+// Test the case when there is no animation attached to the element.
+TEST_F(BackgroundColorPaintWorkletTest, FallbackToMainNoAnimation) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+ Element* element = GetElementById("target");
+ EXPECT_FALSE(element->GetElementAnimations());
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ EXPECT_FALSE(BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ element, &animated_colors, &offsets));
+}
+
+// Test that when an element has other animations but no background color
+// animation, then we fall back to the main thread. Also testing that calling
+// BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams do not crash.
+TEST_F(BackgroundColorPaintWorkletTest, NoBGColorAnimationFallback) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+
+ Timing timing;
+ timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
+
+ CSSPropertyID property_id = CSSPropertyID::kColor;
+ Persistent<StringKeyframe> start_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ start_keyframe->SetCSSPropertyValue(
+ property_id, "red", SecureContextMode::kInsecureContext, nullptr);
+ Persistent<StringKeyframe> end_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ end_keyframe->SetCSSPropertyValue(
+ property_id, "green", SecureContextMode::kInsecureContext, nullptr);
+
+ StringKeyframeVector keyframes;
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+
+ auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+ model->SetComposite(EffectModel::kCompositeAccumulate);
+
+ Element* element = GetElementById("target");
+ NonThrowableExceptionState exception_state;
+ DocumentTimeline* timeline =
+ MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+ Animation* animation = Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
+ exception_state);
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+
+ EXPECT_TRUE(element->GetElementAnimations());
+ EXPECT_EQ(element->GetElementAnimations()->Animations().size(), 1u);
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ EXPECT_FALSE(BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ element, &animated_colors, &offsets));
+ EXPECT_TRUE(animated_colors.IsEmpty());
+ EXPECT_TRUE(offsets.IsEmpty());
+}
+
+// Test the case where the composite mode is not replace.
+TEST_F(BackgroundColorPaintWorkletTest, FallbackToMainCompositeAccumulate) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+
+ Timing timing;
+ timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
+
+ CSSPropertyID property_id = CSSPropertyID::kBackgroundColor;
+ Persistent<StringKeyframe> start_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ start_keyframe->SetCSSPropertyValue(
+ property_id, "red", SecureContextMode::kInsecureContext, nullptr);
+ Persistent<StringKeyframe> end_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ end_keyframe->SetCSSPropertyValue(
+ property_id, "green", SecureContextMode::kInsecureContext, nullptr);
+
+ StringKeyframeVector keyframes;
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+
+ auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+ model->SetComposite(EffectModel::kCompositeAccumulate);
+
+ Element* element = GetElementById("target");
+ NonThrowableExceptionState exception_state;
+ DocumentTimeline* timeline =
+ MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+ Animation* animation = Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
+ exception_state);
+ UpdateAllLifecyclePhasesForTest();
+ animation->play();
+ EXPECT_FALSE(animation->CanCompositeBGColorAnim());
+
+ EXPECT_TRUE(element->GetElementAnimations());
+ EXPECT_EQ(element->GetElementAnimations()->Animations().size(), 1u);
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ EXPECT_FALSE(BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ element, &animated_colors, &offsets));
+ EXPECT_FALSE(animation->CanCompositeBGColorAnim());
+}
+
+// Test that when there are multiple bgcolor animations on an Element, we
+// composite the animation with the highest compositing order.
+TEST_F(BackgroundColorPaintWorkletTest, MultipleAnimationsNotFallback) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ SetBodyInnerHTML(R"HTML(
+ <div id ="target" style="width: 100px; height: 100px">
+ </div>
+ )HTML");
+
+ Timing timing;
+ timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
+
+ CSSPropertyID property_id = CSSPropertyID::kBackgroundColor;
+ Persistent<StringKeyframe> start_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ start_keyframe->SetCSSPropertyValue(
+ property_id, "red", SecureContextMode::kInsecureContext, nullptr);
+ Persistent<StringKeyframe> end_keyframe =
+ MakeGarbageCollected<StringKeyframe>();
+ end_keyframe->SetCSSPropertyValue(
+ property_id, "green", SecureContextMode::kInsecureContext, nullptr);
+
+ StringKeyframeVector keyframes;
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+ auto* model1 = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+
+ Element* element = GetElementById("target");
+ NonThrowableExceptionState exception_state;
+ DocumentTimeline* timeline =
+ MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+ Animation* animation1 = Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model1, timing), timeline,
+ exception_state);
+
+ start_keyframe->SetCSSPropertyValue(
+ property_id, "blue", SecureContextMode::kInsecureContext, nullptr);
+ end_keyframe->SetCSSPropertyValue(
+ property_id, "yellow", SecureContextMode::kInsecureContext, nullptr);
+ keyframes.clear();
+ keyframes.push_back(start_keyframe);
+ keyframes.push_back(end_keyframe);
+ auto* model2 = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+ Animation* animation2 = Animation::Create(
+ MakeGarbageCollected<KeyframeEffect>(element, model2, timing), timeline,
+ exception_state);
+ UpdateAllLifecyclePhasesForTest();
+ animation1->play();
+ animation2->play();
+ EXPECT_FALSE(animation1->CanCompositeBGColorAnim());
+ EXPECT_FALSE(animation2->CanCompositeBGColorAnim());
+
+ // Two active background-color animations, fall back to main.
+ EXPECT_TRUE(element->GetElementAnimations());
+ EXPECT_EQ(element->GetElementAnimations()->Animations().size(), 2u);
+ Vector<Color> animated_colors;
+ Vector<double> offsets;
+ EXPECT_TRUE(BackgroundColorPaintWorklet::GetBGColorPaintWorkletParams(
+ element, &animated_colors, &offsets));
+ EXPECT_FALSE(animation1->CanCompositeBGColorAnim());
+ EXPECT_TRUE(animation2->CanCompositeBGColorAnim());
+ EXPECT_EQ(animated_colors.size(), 2u);
+ // The animated_colors should be blue and yellow.
+ EXPECT_EQ(animated_colors[0].Red(), 0);
+ EXPECT_EQ(animated_colors[0].Green(), 0);
+ EXPECT_EQ(animated_colors[0].Blue(), 255);
+ EXPECT_EQ(animated_colors[1].Red(), 255);
+ EXPECT_EQ(animated_colors[1].Green(), 255);
+ EXPECT_EQ(animated_colors[1].Blue(), 0);
+}
+
+// Test that calling BackgroundColorPaintWorkletProxyClient::Paint won't crash
+// when the animated property value is empty.
+TEST_F(BackgroundColorPaintWorkletTest, ProxyClientPaintWithNoPropertyValue) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ Vector<Color> animated_colors = {Color(0, 255, 0), Color(255, 0, 0)};
+ Vector<double> offsets = {0, 1};
+ CompositorPaintWorkletJob::AnimatedPropertyValues property_values;
+ BackgroundColorPaintWorklet::ProxyClientPaintForTest(animated_colors, offsets,
+ property_values);
+}
+
+// Test that BackgroundColorPaintWorkletProxyClient::Paint won't crash if the
+// progress of the animation is a negative number.
+TEST_F(BackgroundColorPaintWorkletTest, ProxyClientPaintWithNegativeProgress) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ Vector<Color> animated_colors = {Color(0, 255, 0), Color(255, 0, 0)};
+ Vector<double> offsets = {0, 1};
+ CompositorPaintWorkletJob::AnimatedPropertyValues property_values;
+ CompositorPaintWorkletInput::PropertyKey property_key(
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor,
+ CompositorElementId(1u));
+ CompositorPaintWorkletInput::PropertyValue property_value(-0.0f);
+ property_values.insert(std::make_pair(property_key, property_value));
+ BackgroundColorPaintWorklet::ProxyClientPaintForTest(animated_colors, offsets,
+ property_values);
+}
+
+// Test that BackgroundColorPaintWorkletProxyClient::Paint won't crash if the
+// progress of the animation is > 1.
+TEST_F(BackgroundColorPaintWorkletTest,
+ ProxyClientPaintWithLargerThanOneProgress) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ Vector<Color> animated_colors = {Color(0, 255, 0), Color(255, 0, 0)};
+ Vector<double> offsets = {0, 1};
+ CompositorPaintWorkletJob::AnimatedPropertyValues property_values;
+ CompositorPaintWorkletInput::PropertyKey property_key(
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor,
+ CompositorElementId(1u));
+ float progress = 1 + std::numeric_limits<float>::epsilon();
+ CompositorPaintWorkletInput::PropertyValue property_value(progress);
+ property_values.insert(std::make_pair(property_key, property_value));
+ BackgroundColorPaintWorklet::ProxyClientPaintForTest(animated_colors, offsets,
+ property_values);
+}
+
+// Test that BackgroundColorPaintWorkletProxyClient::Paint won't crash when the
+// largest offset is not exactly one.
+TEST_F(BackgroundColorPaintWorkletTest, ProxyClientPaintWithCloseToOneOffset) {
+ ScopedCompositeBGColorAnimationForTest composite_bgcolor_animation(true);
+ Vector<Color> animated_colors = {Color(0, 255, 0), Color(0, 255, 255),
+ Color(255, 0, 0)};
+ Vector<double> offsets = {0, 0.6, 0.99999};
+ CompositorPaintWorkletJob::AnimatedPropertyValues property_values;
+ CompositorPaintWorkletInput::PropertyKey property_key(
+ CompositorPaintWorkletInput::NativePropertyType::kBackgroundColor,
+ CompositorElementId(1u));
+ float progress = 1 - std::numeric_limits<float>::epsilon();
+ CompositorPaintWorkletInput::PropertyValue property_value(progress);
+ property_values.insert(std::make_pair(property_key, property_value));
+ BackgroundColorPaintWorklet::ProxyClientPaintForTest(animated_colors, offsets,
+ property_values);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.cc b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.cc
deleted file mode 100644
index a62dd4a44fa..00000000000
--- a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.cc
+++ /dev/null
@@ -1,37 +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/csspaint/native_paint_image_generator_impl.h"
-
-#include "third_party/blink/renderer/modules/csspaint/native_paint_worklet.h"
-#include "third_party/blink/renderer/platform/graphics/image.h"
-
-namespace blink {
-
-std::unique_ptr<NativePaintImageGenerator>
-NativePaintImageGeneratorImpl::Create() {
- std::unique_ptr<NativePaintWorklet> native_paint_worklet =
- std::make_unique<NativePaintWorklet>();
-
- DCHECK(native_paint_worklet);
- std::unique_ptr<NativePaintImageGeneratorImpl> generator =
- std::make_unique<NativePaintImageGeneratorImpl>(
- std::move(native_paint_worklet));
-
- return generator;
-}
-
-NativePaintImageGeneratorImpl::NativePaintImageGeneratorImpl(
- std::unique_ptr<NativePaintWorklet> native_paint_worklet)
- : native_paint_worklet_(std::move(native_paint_worklet)) {}
-
-NativePaintImageGeneratorImpl::~NativePaintImageGeneratorImpl() = default;
-
-scoped_refptr<Image> NativePaintImageGeneratorImpl::Paint(
- const FloatSize& container_size,
- SkColor color) {
- return native_paint_worklet_->Paint(container_size, color);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.h b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.h
deleted file mode 100644
index 897f2c124ae..00000000000
--- a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.h
+++ /dev/null
@@ -1,36 +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_CSSPAINT_NATIVE_PAINT_IMAGE_GENERATOR_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_NATIVE_PAINT_IMAGE_GENERATOR_IMPL_H_
-
-#include "third_party/blink/renderer/core/css/native_paint_image_generator.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/geometry/float_size.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class Image;
-class NativePaintWorklet;
-
-class MODULES_EXPORT NativePaintImageGeneratorImpl final
- : public NativePaintImageGenerator {
- public:
- static std::unique_ptr<NativePaintImageGenerator> Create();
-
- explicit NativePaintImageGeneratorImpl(std::unique_ptr<NativePaintWorklet>);
- ~NativePaintImageGeneratorImpl() override;
-
- // The |container_size| is without subpixel snapping.
- scoped_refptr<Image> Paint(const FloatSize& container_size,
- SkColor color) final;
-
- private:
- std::unique_ptr<NativePaintWorklet> native_paint_worklet_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_NATIVE_PAINT_IMAGE_GENERATOR_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.cc b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.cc
index 72a359cd9dc..a9b42d21c15 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.cc
@@ -4,26 +4,53 @@
#include "third_party/blink/renderer/modules/csspaint/native_paint_worklet.h"
-#include "third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h"
-#include "third_party/blink/renderer/platform/graphics/paint_generated_image.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h"
+#include "third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h"
+#include "third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
-NativePaintWorklet::NativePaintWorklet() = default;
+NativePaintWorklet::NativePaintWorklet(LocalFrame& local_root)
+ : worklet_id_(PaintWorkletIdGenerator::NextId()) {
+ DCHECK(local_root.IsLocalRoot());
+ paint_dispatcher_ =
+ WebLocalFrameImpl::FromFrame(local_root)
+ ->FrameWidgetImpl()
+ ->EnsureCompositorPaintDispatcher(&compositor_host_queue_);
+ DCHECK(IsMainThread());
+ ThreadCreationParams params(ThreadType::kDedicatedWorkerThread);
+ // TODO(crbug.com/1143407): We don't need this thread if we can make the
+ // compositor thread support GC.
+ worker_thread_ = Thread::CreateThread(params.SetSupportsGC(true));
+}
-NativePaintWorklet::~NativePaintWorklet() = default;
+void NativePaintWorklet::RegisterProxyClient(
+ NativePaintWorkletProxyClient* client) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ worker_thread_->GetTaskRunner();
+ // At this moment, we are in the paint phase which is before commit, we queue
+ // a task to the compositor thread to register the |paint_dispatcher_|. When
+ // compositor schedules the actual paint job (PaintWorkletPainter::Paint),
+ // which is after commit, the |paint_dispatcher_| should have been registerted
+ // and ready to use.
+ PostCrossThreadTask(
+ *compositor_host_queue_, FROM_HERE,
+ CrossThreadBindOnce(
+ &PaintWorkletPaintDispatcher::RegisterPaintWorkletPainter,
+ paint_dispatcher_, WrapCrossThreadPersistent(client), task_runner));
+}
-scoped_refptr<Image> NativePaintWorklet::Paint(const FloatSize& container_size,
- SkColor color) {
- PaintRenderingContext2DSettings* context_settings =
- PaintRenderingContext2DSettings::Create();
- auto* rendering_context = MakeGarbageCollected<PaintRenderingContext2D>(
- RoundedIntSize(container_size), context_settings, 1, 1);
- rendering_context->GetPaintCanvas()->drawColor(color);
- sk_sp<PaintRecord> paint_record = rendering_context->GetRecord();
- if (!paint_record)
- return nullptr;
- return PaintGeneratedImage::Create(paint_record, container_size);
+void NativePaintWorklet::UnregisterProxyClient() {
+ PostCrossThreadTask(
+ *compositor_host_queue_, FROM_HERE,
+ CrossThreadBindOnce(
+ &PaintWorkletPaintDispatcher::UnregisterPaintWorkletPainter,
+ paint_dispatcher_, worklet_id_));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.h b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.h
index 71d0696de0e..501803f0a6e 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.h
+++ b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet.h
@@ -15,16 +15,46 @@
namespace blink {
-class MODULES_EXPORT NativePaintWorklet {
+class LocalFrame;
+class NativePaintWorkletProxyClient;
+class PaintWorkletPaintDispatcher;
+class SingleThreadTaskRunner;
+class Thread;
+
+// NativePaintWorklet contains the shared information by all kinds of native
+// paint worklet. We allow the instance creation of its subclasses, but not this
+// class. Each subclass would have its own implementation of the Paint function.
+// For example, the BackgroundColorPaintWorklet takes a SkColor in its Paint
+// function.
+class MODULES_EXPORT NativePaintWorklet
+ : public GarbageCollected<NativePaintWorklet> {
+ DISALLOW_COPY_AND_ASSIGN(NativePaintWorklet);
+
public:
- explicit NativePaintWorklet();
- virtual ~NativePaintWorklet();
+ virtual ~NativePaintWorklet() = default;
- // The |container_size| is without subpixel snapping.
- scoped_refptr<Image> Paint(const FloatSize& container_size, SkColor color);
+ int WorkletId() const { return worklet_id_; }
- private:
- DISALLOW_COPY_AND_ASSIGN(NativePaintWorklet);
+ // Register the NativePaintWorkletProxyClient to the compositor thread that
+ // will hold a cross thread persistent pointer to it. This should be called
+ // during the construction of native paint worklets, to ensure that the proxy
+ // client is ready on the compositor thread when dispatching a paint job.
+ void RegisterProxyClient(NativePaintWorkletProxyClient*);
+
+ // Unregister the painter to ensure that there is no memory leakage on the
+ // compositor thread.
+ void UnregisterProxyClient();
+
+ virtual void Trace(Visitor*) const {}
+
+ protected:
+ explicit NativePaintWorklet(LocalFrame& local_root);
+
+ int worklet_id_;
+ base::WeakPtr<PaintWorkletPaintDispatcher> paint_dispatcher_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue_;
+ // The worker thread that does the paint work.
+ std::unique_ptr<Thread> worker_thread_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h
new file mode 100644
index 00000000000..81b51abec98
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/native_paint_worklet_proxy_client.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_NATIVE_PAINT_WORKLET_PROXY_CLIENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_NATIVE_PAINT_WORKLET_PROXY_CLIENT_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/graphics/paint_worklet_painter.h"
+
+namespace blink {
+
+// This class contains the shared bits for all kinds of
+// NativePaintWorkletProxyClient. Instance creation of this class is not
+// allowed, but its subclasses are allowed. Each subclass should have its own
+// implementation of the Paint function from the PaintWorkletPainter.
+class MODULES_EXPORT NativePaintWorkletProxyClient
+ : public GarbageCollected<NativePaintWorkletProxyClient>,
+ public PaintWorkletPainter {
+ DISALLOW_COPY_AND_ASSIGN(NativePaintWorkletProxyClient);
+
+ public:
+ ~NativePaintWorkletProxyClient() override = default;
+
+ // PaintWorkletPainter implementation.
+ int GetWorkletId() const override { return worklet_id_; }
+
+ protected:
+ explicit NativePaintWorkletProxyClient(int worklet_id)
+ : worklet_id_(worklet_id) {}
+
+ private:
+ const int worklet_id_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_NATIVE_PAINT_WORKLET_PROXY_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
index 8e85976b57a..46f89b37824 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
@@ -118,6 +118,10 @@ sk_sp<PaintFilter> PaintRenderingContext2D::StateGetFilter() {
this);
}
+CanvasColorParams PaintRenderingContext2D::GetCanvas2DColorParams() const {
+ return CanvasColorParams();
+}
+
void PaintRenderingContext2D::WillOverwriteCanvas() {
previous_frame_.reset();
if (did_record_draw_commands_in_paint_recorder_) {
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
index f4a11396349..cd568e8ea0a 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
@@ -94,6 +94,7 @@ class MODULES_EXPORT PaintRenderingContext2D : public ScriptWrappable,
sk_sp<PaintRecord> GetRecord();
protected:
+ CanvasColorParams GetCanvas2DColorParams() const override;
bool IsPaint2D() const override { return true; }
void WillOverwriteCanvas() override;
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
index 94d6d465805..6e4ef60d87d 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
@@ -13,12 +13,23 @@
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void scale(unrestricted double x, unrestricted double y, unrestricted double z);
void rotate(unrestricted double angle);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotate3d(unrestricted double angleX, unrestricted double angleY, unrestricted double angleZ);
+ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle);
void translate(unrestricted double x, unrestricted double y);
+ [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z);
+ [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length);
void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
+ [RuntimeEnabled=NewCanvas2DAPI] void transform(
+ unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
+ unrestricted double m21, unrestricted double m22, unrestricted double m23, unrestricted double m24,
+ unrestricted double m31, unrestricted double m32, unrestricted double m33, unrestricted double m34,
+ unrestricted double m41, unrestricted double m42, unrestricted double m43, unrestricted double m44
+ );
void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
void resetTransform();
- [RaisesException] void setTransform(optional DOMMatrix2DInit transform = {});
+ [RaisesException] void setTransform(optional DOMMatrixInit transform = {});
DOMMatrix getTransform();
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
index 5b3fd3f7ee4..e6e0c5b909c 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/modules/csspaint/paint_worklet.h"
-#include "base/atomic_sequence_num.h"
#include "base/rand_util.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.h"
@@ -16,20 +15,12 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/modules/csspaint/css_paint_definition.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h"
+#include "third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h"
#include "third_party/blink/renderer/platform/graphics/paint_generated_image.h"
namespace blink {
-namespace {
-base::AtomicSequenceNumber g_next_worklet_id;
-int NextId() {
- // Start id from 1. This way it safe to use it as key in hashmap with default
- // key traits.
- return g_next_worklet_id.GetNext() + 1;
-}
-} // namespace
-
const wtf_size_t PaintWorklet::kNumGlobalScopesPerThread = 2u;
const size_t kMaxPaintCountToSwitch = 30u;
@@ -49,7 +40,7 @@ PaintWorklet::PaintWorklet(LocalDOMWindow& window)
Supplement<LocalDOMWindow>(window),
pending_generator_registry_(
MakeGarbageCollected<PaintWorkletPendingGeneratorRegistry>()),
- worklet_id_(NextId()),
+ worklet_id_(PaintWorkletIdGenerator::NextId()),
is_paint_off_thread_(
RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled() &&
Thread::CompositorThread()) {}
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 fecba43701e..b22149ce8ef 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
@@ -41,7 +41,7 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
window->Url(), mojom::blink::ScriptType::kModule, global_scope_name,
window->UserAgent(), frame->Client()->UserAgentMetadata(),
frame->Client()->CreateWorkerFetchContext(),
- window->GetContentSecurityPolicy()->Headers(),
+ mojo::Clone(window->GetContentSecurityPolicy()->GetParsedPolicies()),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(),
nullptr /* worker_clients */,
@@ -51,7 +51,8 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
mojom::blink::V8CacheOptions::kDefault, module_responses_map,
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken(),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken(),
window->CrossOriginIsolatedCapability());
global_scope_ = PaintWorkletGlobalScope::Create(
frame, std::move(creation_params), *reporting_proxy_);
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.cc
new file mode 100644
index 00000000000..89afa58c888
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h"
+
+#include <limits>
+
+#include "base/check_op.h"
+
+namespace blink {
+
+namespace {
+// Note that the NextId() is called from the main thread only, and that's why
+// it is fine with current_id being int. In the future, if NextId is called from
+// a thread other than the main thread, then we should use AtomicSequenceNumber.
+static int current_id = 0;
+} // namespace
+
+int PaintWorkletIdGenerator::NextId() {
+ CHECK_LT(current_id, std::numeric_limits<int>::max());
+ return ++current_id;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h
new file mode 100644
index 00000000000..9b52d387e29
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_id_generator.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_ID_GENERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_ID_GENERATOR_H_
+
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class MODULES_EXPORT PaintWorkletIdGenerator {
+ public:
+ static int NextId();
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_ID_GENERATOR_H_
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h
index a5646995f6f..fcfdec2ae44 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_messaging_proxy.h
@@ -20,12 +20,11 @@ class WorkerThread;
class PaintWorkletMessagingProxy final : public ThreadedWorkletMessagingProxy {
public:
explicit PaintWorkletMessagingProxy(ExecutionContext*);
+ ~PaintWorkletMessagingProxy() override;
void Trace(Visitor*) const override;
private:
- ~PaintWorkletMessagingProxy() override;
-
std::unique_ptr<WorkerThread> CreateWorkerThread() override;
};
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
index bd7c861d8be..0fba4407010 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
+++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h"
#include <memory>
+#include <utility>
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_color_value.h"
@@ -12,7 +13,7 @@
#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
#include "third_party/blink/renderer/core/css/cssom/css_style_value.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/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/modules/csspaint/css_paint_definition.h"
@@ -135,7 +136,7 @@ void PaintWorkletProxyClient::RegisterCSSPaintDefinition(
CrossThreadBindOnce(
&PaintWorklet::RegisterMainThreadDocumentPaintDefinition,
paint_worklet_, name, definition->NativeInvalidationProperties(),
- WTF::Passed(std::move(passed_custom_properties)),
+ std::move(passed_custom_properties),
definition->InputArgumentTypes(),
definition->GetPaintRenderingContext2DSettings()->alpha()));
}
@@ -220,7 +221,8 @@ void PaintWorkletProxyClient::ApplyAnimatedPropertyOverrides(
animated_property_values) {
for (const auto& property_value : animated_property_values) {
DCHECK(property_value.second.has_value());
- String property_name(property_value.first.c_str());
+ String property_name(
+ property_value.first.custom_property_name.value().c_str());
DCHECK(style_map->StyleMapData().Contains(property_name));
CrossThreadStyleValue* old_value =
style_map->StyleMapData().at(property_name);
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 c8431ee4bba..b574e0351a3 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
@@ -133,11 +133,25 @@ void DelegatedInkTrailPresenter::updateInkTrailStartPoint(
border_box_rect_absolute.Width().ToFloat(),
border_box_rect_absolute.Height().ToFloat());
+ // This is used to know if the user starts inking with the pointer down or
+ // not, so that we can stop drawing delegated ink trails as quickly as
+ // possible if the left button state changes, as presumably that indicates the
+ // the end of inking.
+ // Touch events do not need to be special cased here. When something is
+ // physically touching the screen to trigger a touch event, it is converted to
+ // a pointerevent with kLeftButtonDown, and if a stylus with hovering
+ // capabilities sent the touch event, then the resulting pointerevent will not
+ // have the kLeftButtonDown modifier. In either case, it will match the
+ // expectations of a normal mouse event, so it doesn't need to be handled
+ // separately.
+ const bool is_hovering =
+ !(evt->GetModifiers() & WebInputEvent::Modifiers::kLeftButtonDown);
+
const double diameter_in_physical_pixels = style->diameter() * effective_zoom;
std::unique_ptr<viz::DelegatedInkMetadata> metadata =
std::make_unique<viz::DelegatedInkMetadata>(
point, diameter_in_physical_pixels, color.Rgb(),
- evt->PlatformTimeStamp(), area);
+ evt->PlatformTimeStamp(), area, is_hovering);
TRACE_EVENT_INSTANT1(
"blink", "DelegatedInkTrailPresenter::updateInkTrailStartPoint",
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 cae308ee1cb..6faf0672964 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
@@ -24,7 +24,8 @@ class TestDelegatedInkMetadata {
: point_(metadata->point()),
color_(metadata->color()),
diameter_(metadata->diameter()),
- area_(metadata->presentation_area()) {}
+ area_(metadata->presentation_area()),
+ is_hovering_(metadata->is_hovering()) {}
explicit TestDelegatedInkMetadata(gfx::RectF area,
float device_pixel_ratio = 1.0)
: area_(area) {
@@ -43,18 +44,21 @@ class TestDelegatedInkMetadata {
EXPECT_NEAR(area_.y(), actual.area_.y(), LayoutUnit::Epsilon());
EXPECT_NEAR(area_.width(), actual.area_.width(), LayoutUnit::Epsilon());
EXPECT_NEAR(area_.height(), actual.area_.height(), LayoutUnit::Epsilon());
+ EXPECT_EQ(is_hovering_, actual.is_hovering_);
}
void SetPoint(gfx::PointF pt) { point_ = pt; }
void SetColor(SkColor color) { color_ = color; }
void SetDiameter(double diameter) { diameter_ = diameter; }
void SetArea(gfx::RectF area) { area_ = area; }
+ void SetHovering(bool hovering) { is_hovering_ = hovering; }
private:
gfx::PointF point_;
SkColor color_;
double diameter_;
gfx::RectF area_;
+ bool is_hovering_;
};
DelegatedInkTrailPresenter* CreatePresenter(Element* element,
@@ -78,18 +82,24 @@ class DelegatedInkTrailPresenterUnitTest : public SimTest {
SetWebViewSize(width + 1, height + 1);
}
- PointerEvent* CreatePointerMoveEvent(gfx::PointF pt) {
+ PointerEvent* CreatePointerMoveEvent(gfx::PointF pt, bool hovering) {
PointerEventInit* init = PointerEventInit::Create();
init->setClientX(pt.x());
init->setClientY(pt.y());
+ if (!hovering) {
+ init->setButtons(MouseEvent::WebInputEventModifiersToButtons(
+ WebInputEvent::Modifiers::kLeftButtonDown));
+ }
PointerEvent* event = PointerEvent::Create("pointermove", init);
event->SetTrusted(true);
return event;
}
TestDelegatedInkMetadata GetActualMetadata() {
- return TestDelegatedInkMetadata(
- WebWidgetClient().layer_tree_host()->DelegatedInkMetadataForTesting());
+ return TestDelegatedInkMetadata(WebView()
+ .MainFrameViewWidget()
+ ->LayerTreeHostForTesting()
+ ->DelegatedInkMetadataForTesting());
}
void SetPageZoomFactor(const float zoom) {
@@ -165,7 +175,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
gfx::PointF pt(100, 100);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
+ expected_metadata.SetHovering(true);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
@@ -225,7 +236,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
gfx::PointF pt(87, 113);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
+ expected_metadata.SetHovering(true);
pt.Scale(kZoom);
expected_metadata.SetPoint(pt);
@@ -289,7 +301,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasNotAtOrigin) {
gfx::PointF pt(380, 175);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
+ expected_metadata.SetHovering(false);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
@@ -387,7 +400,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasInIFrame) {
gfx::PointF pt(380, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
+ expected_metadata.SetHovering(false);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
@@ -513,7 +527,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, NestedIframe) {
gfx::PointF pt(350, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
+ expected_metadata.SetHovering(true);
expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
pt.y() + kInnerIframeTopOffset));
@@ -596,7 +611,8 @@ TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
gfx::PointF pt(380, 375);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
+ expected_metadata.SetHovering(true);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
@@ -630,7 +646,8 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, PresentationAreaNotProvided) {
gfx::PointF pt(70, 109);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(GetDocument().GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
+ expected_metadata.SetHovering(false);
expected_metadata.SetPoint(pt);
expected_metadata.ExpectEqual(GetActualMetadata());
@@ -714,7 +731,8 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasExtendsOutsideOfIframe) {
gfx::PointF pt(102, 67);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
+ expected_metadata.SetHovering(false);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
@@ -804,7 +822,8 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasLeftAndAboveIframeBoundaries) {
gfx::PointF pt(102, 67);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ true), &style);
+ expected_metadata.SetHovering(true);
expected_metadata.SetPoint(
gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
@@ -925,7 +944,8 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, OuterIframeClipsInnerIframe) {
gfx::PointF pt(357, 401);
presenter->updateInkTrailStartPoint(
ToScriptStateForMainWorld(iframe_document->GetFrame()),
- CreatePointerMoveEvent(pt), &style);
+ CreatePointerMoveEvent(pt, /*hovering*/ false), &style);
+ expected_metadata.SetHovering(false);
expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
pt.y() + kInnerIframeTopOffset));
diff --git a/chromium/third_party/blink/renderer/modules/device/BUILD.gn b/chromium/third_party/blink/renderer/modules/device/BUILD.gn
new file mode 100644
index 00000000000..0bfbee68a8c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("device") {
+ sources = [
+ "device_service.cc",
+ "device_service.h",
+ ]
+
+ public_deps = [ "//third_party/blink/renderer/platform" ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/device/OWNERS b/chromium/third_party/blink/renderer/modules/device/OWNERS
new file mode 100644
index 00000000000..62fa406f905
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/OWNERS
@@ -0,0 +1,2 @@
+# Device API owners.
+file://chrome/browser/device_api/OWNERS
diff --git a/chromium/third_party/blink/renderer/modules/device/device_service.cc b/chromium/third_party/blink/renderer/modules/device/device_service.cc
new file mode 100644
index 00000000000..726c1bec163
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/device_service.cc
@@ -0,0 +1,219 @@
+// Copyright 2020 The Chromium Authors. 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/device/device_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"
+#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.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/navigator.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+
+namespace blink {
+
+namespace {
+
+const char kNotHighTrustedAppExceptionMessage[] =
+ "This API is available only for high trusted apps.";
+
+} // namespace
+
+const char DeviceService::kSupplementName[] = "DeviceService";
+
+DeviceService* DeviceService::device(Navigator& navigator) {
+ if (!navigator.DomWindow())
+ return nullptr;
+
+ DeviceService* device_service =
+ Supplement<Navigator>::From<DeviceService>(navigator);
+ if (!device_service) {
+ device_service = MakeGarbageCollected<DeviceService>(navigator);
+ ProvideTo(navigator, device_service);
+ }
+ return device_service;
+}
+
+DeviceService::DeviceService(Navigator& navigator)
+ : Supplement<Navigator>(navigator),
+ device_api_service_(navigator.DomWindow()),
+ configuration_observer_(this, navigator.DomWindow()) {}
+
+const AtomicString& DeviceService::InterfaceName() const {
+ return event_target_names::kDeviceService;
+}
+
+ExecutionContext* DeviceService::GetExecutionContext() const {
+ return GetSupplementable()->DomWindow();
+}
+
+bool DeviceService::HasPendingActivity() const {
+ // Prevents garbage collecting of this object when not hold by another
+ // object but still has listeners registered.
+ return !pending_promises_.IsEmpty() || HasEventListeners();
+}
+
+void DeviceService::Trace(Visitor* visitor) const {
+ EventTargetWithInlineData::Trace(visitor);
+ ActiveScriptWrappable::Trace(visitor);
+ Supplement<Navigator>::Trace(visitor);
+
+ visitor->Trace(device_api_service_);
+ visitor->Trace(pending_promises_);
+ visitor->Trace(configuration_observer_);
+}
+
+mojom::blink::DeviceAPIService* DeviceService::GetService() {
+ if (!device_api_service_.is_bound()) {
+ GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
+ device_api_service_.BindNewPipeAndPassReceiver(
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ // The access status of Device API can change dynamically. Hence, we have to
+ // properly handle cases when we are losing this access.
+ device_api_service_.set_disconnect_handler(WTF::Bind(
+ &DeviceService::OnServiceConnectionError, WrapWeakPersistent(this)));
+ }
+
+ return device_api_service_.get();
+}
+
+void DeviceService::OnServiceConnectionError() {
+ device_api_service_.reset();
+ // Resolve all pending promises with a failure.
+ for (ScriptPromiseResolver* resolver : pending_promises_) {
+ resolver->Reject(
+ MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotAllowedError,
+ kNotHighTrustedAppExceptionMessage));
+ }
+}
+
+ScriptPromise DeviceService::getManagedConfiguration(ScriptState* script_state,
+ Vector<String> keys) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ pending_promises_.insert(resolver);
+
+ ScriptPromise promise = resolver->Promise();
+ GetService()->GetManagedConfiguration(
+ keys, Bind(&DeviceService::OnConfigurationReceived,
+ WrapWeakPersistent(this), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise DeviceService::getDirectoryId(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ pending_promises_.insert(resolver);
+
+ ScriptPromise promise = resolver->Promise();
+ GetService()->GetDirectoryId(
+ WTF::Bind(&DeviceService::OnAttributeReceived, WrapWeakPersistent(this),
+ WrapPersistent(script_state), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise DeviceService::getSerialNumber(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ pending_promises_.insert(resolver);
+
+ ScriptPromise promise = resolver->Promise();
+ GetService()->GetSerialNumber(
+ WTF::Bind(&DeviceService::OnAttributeReceived, WrapWeakPersistent(this),
+ WrapPersistent(script_state), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise DeviceService::getAnnotatedAssetId(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ pending_promises_.insert(resolver);
+
+ ScriptPromise promise = resolver->Promise();
+ GetService()->GetAnnotatedAssetId(
+ WTF::Bind(&DeviceService::OnAttributeReceived, WrapWeakPersistent(this),
+ WrapPersistent(script_state), WrapPersistent(resolver)));
+ return promise;
+}
+
+ScriptPromise DeviceService::getAnnotatedLocation(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ pending_promises_.insert(resolver);
+
+ ScriptPromise promise = resolver->Promise();
+ GetService()->GetAnnotatedLocation(
+ WTF::Bind(&DeviceService::OnAttributeReceived, WrapWeakPersistent(this),
+ WrapPersistent(script_state), WrapPersistent(resolver)));
+ return promise;
+}
+
+void DeviceService::OnConfigurationReceived(
+ ScriptPromiseResolver* scoped_resolver,
+ const HashMap<String, String>& configurations) {
+ pending_promises_.erase(scoped_resolver);
+
+ ScriptState* script_state = scoped_resolver->GetScriptState();
+ ScriptState::Scope scope(script_state);
+
+ V8ObjectBuilder result(script_state);
+ for (const auto& config_pair : configurations) {
+ v8::Local<v8::Value> v8_object;
+ if (v8::JSON::Parse(script_state->GetContext(),
+ V8String(script_state->GetIsolate(), config_pair.value))
+ .ToLocal(&v8_object)) {
+ result.Add(config_pair.key, v8_object);
+ }
+ }
+ scoped_resolver->Resolve(result.GetScriptValue());
+}
+
+void DeviceService::OnAttributeReceived(
+ ScriptState* script_state,
+ ScriptPromiseResolver* scoped_resolver,
+ mojom::blink::DeviceAttributeResultPtr result) {
+ pending_promises_.erase(scoped_resolver);
+
+ if (result->is_error_message()) {
+ scoped_resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError, result->get_error_message()));
+ } else if (result->get_attribute().IsNull()) {
+ scoped_resolver->Resolve(v8::Null(script_state->GetIsolate()));
+ } else {
+ scoped_resolver->Resolve(result->get_attribute());
+ }
+}
+
+void DeviceService::OnConfigurationChanged() {
+ DispatchEvent(*Event::Create(event_type_names::kManagedconfigurationchange));
+}
+
+void DeviceService::AddedEventListener(
+ const AtomicString& event_type,
+ RegisteredEventListener& registered_listener) {
+ EventTargetWithInlineData::AddedEventListener(event_type,
+ registered_listener);
+ if (event_type == event_type_names::kManagedconfigurationchange) {
+ if (!configuration_observer_.is_bound()) {
+ GetService()->SubscribeToManagedConfiguration(
+ configuration_observer_.BindNewPipeAndPassRemote(
+ GetExecutionContext()->GetTaskRunner(
+ TaskType::kMiscPlatformAPI)));
+ }
+ }
+}
+
+void DeviceService::RemovedEventListener(
+ const AtomicString& event_type,
+ const RegisteredEventListener& registered_listener) {
+ EventTargetWithInlineData::RemovedEventListener(event_type,
+ registered_listener);
+ if (!HasEventListeners())
+ StopObserving();
+}
+
+void DeviceService::StopObserving() {
+ if (!configuration_observer_.is_bound())
+ return;
+ configuration_observer_.reset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/device/device_service.h b/chromium/third_party/blink/renderer/modules/device/device_service.h
new file mode 100644
index 00000000000..15879f3f98a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/device_service.h
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DEVICE_DEVICE_SERVICE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_DEVICE_DEVICE_SERVICE_H_
+
+#include "third_party/blink/public/mojom/device/device.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/modules/modules_export.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/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Navigator;
+class ExecutionContext;
+class ScriptPromiseResolver;
+class ScriptPromise;
+class ScriptState;
+
+class MODULES_EXPORT DeviceService final
+ : public EventTargetWithInlineData,
+ public ActiveScriptWrappable<DeviceService>,
+ public Supplement<Navigator>,
+ public mojom::blink::ManagedConfigurationObserver {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static const char kSupplementName[];
+
+ // Web-based getter for navigator.device.
+ static DeviceService* device(Navigator&);
+
+ explicit DeviceService(Navigator&);
+ DeviceService(const DeviceService&) = delete;
+ DeviceService& operator=(const DeviceService&) = delete;
+
+ void Trace(Visitor*) const override;
+
+ // EventTargetWithInlineData:
+ const AtomicString& InterfaceName() const override;
+ ExecutionContext* GetExecutionContext() const override;
+ void AddedEventListener(
+ const AtomicString& event_type,
+ RegisteredEventListener& registered_listener) override;
+ void RemovedEventListener(
+ const AtomicString& event_type,
+ const RegisteredEventListener& registered_listener) override;
+
+ // ScriptWrappable implementation.
+ bool HasPendingActivity() const final;
+
+ // Managed Configuration API:
+ ScriptPromise getManagedConfiguration(ScriptState* script_state,
+ Vector<String> keys);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(managedconfigurationchange,
+ kManagedconfigurationchange)
+
+ // Device Attributes API:
+ ScriptPromise getDirectoryId(ScriptState* script_state);
+ ScriptPromise getSerialNumber(ScriptState* script_state);
+ ScriptPromise getAnnotatedAssetId(ScriptState* script_state);
+ ScriptPromise getAnnotatedLocation(ScriptState* script_state);
+
+ private:
+ // ManagedConfigurationObserver:
+ void OnConfigurationChanged() override;
+
+ void OnConfigurationReceived(ScriptPromiseResolver* scoped_resolver,
+ const HashMap<String, String>& configurations);
+
+ void OnAttributeReceived(ScriptState* script_state,
+ ScriptPromiseResolver* scoped_resolver,
+ mojom::blink::DeviceAttributeResultPtr result);
+
+ // Lazily binds mojo interface.
+ mojom::blink::DeviceAPIService* GetService();
+
+ void OnServiceConnectionError();
+ void StopObserving();
+
+ HeapMojoRemote<mojom::blink::DeviceAPIService,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ device_api_service_;
+ HeapMojoReceiver<mojom::blink::ManagedConfigurationObserver, DeviceService>
+ configuration_observer_;
+ HeapHashSet<Member<ScriptPromiseResolver>> pending_promises_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DEVICE_DEVICE_SERVICE_H_
diff --git a/chromium/third_party/blink/renderer/modules/device/device_service.idl b/chromium/third_party/blink/renderer/modules/device/device_service.idl
new file mode 100644
index 00000000000..6473e224a3d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/device_service.idl
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ ActiveScriptWrappable,
+ Exposed=Window,
+ RuntimeEnabled=DeviceInterface,
+ SecureContext
+] interface DeviceService : EventTarget {
+ // Managed Configuration API.
+ [CallWith=ScriptState]
+ Promise<object> getManagedConfiguration(sequence<DOMString> keys);
+ attribute EventHandler onmanagedconfigurationchange;
+
+ // Device Attributes API.
+ [CallWith=ScriptState] Promise<DOMString> getDirectoryId();
+ [CallWith=ScriptState] Promise<DOMString> getSerialNumber();
+ [CallWith=ScriptState] Promise<DOMString> getAnnotatedAssetId();
+ [CallWith=ScriptState] Promise<DOMString> getAnnotatedLocation();
+};
diff --git a/chromium/third_party/blink/renderer/modules/device/idls.gni b/chromium/third_party/blink/renderer/modules/device/idls.gni
new file mode 100644
index 00000000000..942beca83f9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/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_idl_files = [ "device_service.idl" ]
+
+modules_dependency_idl_files = [ "navigator_device.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/device/navigator_device.idl b/chromium/third_party/blink/renderer/modules/device/navigator_device.idl
new file mode 100644
index 00000000000..85128da6b66
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device/navigator_device.idl
@@ -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.
+//
+[
+ ImplementedAs=DeviceService,
+ RuntimeEnabled=DeviceInterface,
+ SecureContext
+] partial interface Navigator {
+ [SameObject]
+ readonly attribute DeviceService device;
+};
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/DIR_METADATA b/chromium/third_party/blink/renderer/modules/device_orientation/DIR_METADATA
new file mode 100644
index 00000000000..c6646678817
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Sensor>DeviceOrientation"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/OWNERS b/chromium/third_party/blink/renderer/modules/device_orientation/OWNERS
index ae8770e0f4c..72fc2caf38b 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/OWNERS
@@ -1,5 +1,2 @@
reillyg@chromium.org
timvolodine@chromium.org
-
-# COMPONENT: Blink>Sensor>DeviceOrientation
-# TEAM: device-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc
index 39c9f5caa99..feb0ec4b08d 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc
@@ -10,6 +10,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/cpp/test/fake_sensor_and_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
@@ -84,9 +85,7 @@ class DeviceMotionEventPumpTest : public testing::Test {
auto* motion_pump =
MakeGarbageCollected<DeviceMotionEventPump>(page_holder_->GetFrame());
motion_pump->SetSensorProviderForTesting(
- mojo::PendingRemote<device::mojom::blink::SensorProvider>(
- sensor_provider.PassPipe(),
- device::mojom::SensorProvider::Version_));
+ ToCrossVariantMojoType(std::move(sensor_provider)));
controller_ = MakeGarbageCollected<MockDeviceMotionController>(
motion_pump, *page_holder_->GetFrame().DomWindow());
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
index 30cd0df7d2c..02b20acfbb0 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
@@ -59,8 +59,6 @@ void DeviceOrientationAbsoluteController::DidAddEventListener(
WebFeature::kDeviceOrientationAbsoluteSecureOrigin);
if (!has_event_listener_) {
- // TODO: add rappor url logging as in DeviceOrientationController.
-
if (!CheckPolicyFeatures(
{mojom::blink::FeaturePolicyFeature::kAccelerometer,
mojom::blink::FeaturePolicyFeature::kGyroscope,
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
index 701ea76138b..b73ab189b64 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
@@ -153,9 +153,9 @@ void DeviceOrientationController::LogToConsolePolicyFeaturesDisabled(
LocalFrame& frame,
const AtomicString& event_name) {
const String& message = String::Format(
- "The %s events are blocked by feature policy. "
+ "The %s events are blocked by permissions policy. "
"See "
- "https://github.com/WICG/feature-policy/blob/master/"
+ "https://github.com/w3c/webappsec-permissions-policy/blob/master/"
"features.md#sensor-features",
event_name.Ascii().c_str());
auto* console_message = MakeGarbageCollected<ConsoleMessage>(
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump_unittest.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump_unittest.cc
index 38accddee95..67577c4add9 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump_unittest.cc
@@ -10,6 +10,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/cpp/test/fake_sensor_and_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/platform_event_controller.h"
@@ -90,14 +91,12 @@ class DeviceOrientationEventPumpTest : public testing::Test {
void SetUp() override {
page_holder_ = std::make_unique<DummyPageHolder>();
- mojo::PendingRemote<device::mojom::SensorProvider> sensor_provider;
- sensor_provider_.Bind(sensor_provider.InitWithNewPipeAndPassReceiver());
+ mojo::PendingRemote<device::mojom::blink::SensorProvider> sensor_provider;
+ sensor_provider_.Bind(ToCrossVariantMojoType(
+ sensor_provider.InitWithNewPipeAndPassReceiver()));
auto* orientation_pump = MakeGarbageCollected<DeviceOrientationEventPump>(
page_holder_->GetFrame(), false /* absolute */);
- orientation_pump->SetSensorProviderForTesting(
- mojo::PendingRemote<device::mojom::blink::SensorProvider>(
- sensor_provider.PassPipe(),
- device::mojom::SensorProvider::Version_));
+ orientation_pump->SetSensorProviderForTesting(std::move(sensor_provider));
controller_ = MakeGarbageCollected<MockDeviceOrientationController>(
orientation_pump, *page_holder_->GetFrame().DomWindow());
@@ -497,15 +496,14 @@ class DeviceAbsoluteOrientationEventPumpTest : public testing::Test {
void SetUp() override {
page_holder_ = std::make_unique<DummyPageHolder>();
- mojo::PendingRemote<device::mojom::SensorProvider> sensor_provider;
- sensor_provider_.Bind(sensor_provider.InitWithNewPipeAndPassReceiver());
+ mojo::PendingRemote<device::mojom::blink::SensorProvider> sensor_provider;
+ sensor_provider_.Bind(ToCrossVariantMojoType(
+ sensor_provider.InitWithNewPipeAndPassReceiver()));
auto* absolute_orientation_pump =
MakeGarbageCollected<DeviceOrientationEventPump>(
page_holder_->GetFrame(), true /* absolute */);
absolute_orientation_pump->SetSensorProviderForTesting(
- mojo::PendingRemote<device::mojom::blink::SensorProvider>(
- sensor_provider.PassPipe(),
- device::mojom::SensorProvider::Version_));
+ std::move(sensor_provider));
controller_ = MakeGarbageCollected<MockDeviceOrientationController>(
absolute_orientation_pump, *page_holder_->GetFrame().DomWindow());
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.cc
index 822de52a92e..5d104326b6a 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.cc
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.cc
@@ -56,6 +56,7 @@ DeviceSensorEventPump::GetPumpStateForTesting() {
void DeviceSensorEventPump::Trace(Visitor* visitor) const {
visitor->Trace(sensor_provider_);
+ visitor->Trace(timer_);
}
DeviceSensorEventPump::DeviceSensorEventPump(LocalFrame& frame)
diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h b/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h
index f13389a06ad..7434c7247e9 100644
--- a/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h
+++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h
@@ -76,7 +76,7 @@ class MODULES_EXPORT DeviceSensorEventPump : public GarbageCollectedMixin {
virtual bool SensorsReadyOrErrored() const = 0;
PumpState state_;
- TaskRunnerTimer<DeviceSensorEventPump> timer_;
+ HeapTaskRunnerTimer<DeviceSensorEventPump> timer_;
};
} // 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
index 8359925ef95..070ee3ee996 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn
@@ -8,10 +8,40 @@ blink_modules_sources("direct_sockets") {
sources = [
"navigator_socket.cc",
"navigator_socket.h",
+ "tcp_readable_stream_wrapper.cc",
+ "tcp_readable_stream_wrapper.h",
"tcp_socket.cc",
"tcp_socket.h",
+ "tcp_writable_stream_wrapper.cc",
+ "tcp_writable_stream_wrapper.h",
"udp_socket.cc",
"udp_socket.h",
]
deps = [ "//net:net" ]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "tcp_readable_stream_wrapper_unittest.cc",
+ "tcp_socket_unittest.cc",
+ "tcp_writable_stream_wrapper_unittest.cc",
+ ]
+
+ configs += [
+ "//third_party/blink/renderer:config",
+ "//third_party/blink/renderer:inside_blink",
+ "//third_party/blink/renderer/core:blink_core_pch",
+ ]
+
+ 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/direct_sockets/DIR_METADATA b/chromium/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA
new file mode 100644
index 00000000000..6cb0ce25b09
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Network"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS b/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS
index 39333436eb6..5a733a4a4aa 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS
@@ -1,5 +1,3 @@
ericwilligers@chromium.org
glenrob@chromium.org
mgiuca@chromium.org
-
-# COMPONENT: Blink>Network
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
index 29eadda1ea1..81fbb37a2f6 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc
@@ -54,6 +54,7 @@ NavigatorSocket& NavigatorSocket::From(ScriptState* script_state) {
Supplement<ExecutionContext>::From<NavigatorSocket>(context);
if (!supplement) {
supplement = MakeGarbageCollected<NavigatorSocket>(context);
+ supplement->UpdateStateIfNeeded();
ProvideTo(*context, supplement);
}
return *supplement;
@@ -186,15 +187,6 @@ bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state,
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.");
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc
new file mode 100644
index 00000000000..242ab35a767
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc
@@ -0,0 +1,252 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.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_source_base.h"
+#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.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/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+// An implementation of UnderlyingSourceBase that forwards all operations to the
+// TCPReadableStreamWrapper object that created it.
+class TCPReadableStreamWrapper::UnderlyingSource final
+ : public UnderlyingSourceBase {
+ public:
+ UnderlyingSource(ScriptState* script_state, TCPReadableStreamWrapper* stream)
+ : UnderlyingSourceBase(script_state),
+ tcp_readable_stream_wrapper_(stream) {}
+
+ ScriptPromise Start(ScriptState* script_state) override {
+ DVLOG(1) << "TCPReadableStreamWrapper::UnderlyingSource::start() "
+ "tcp_readable_stream_wrapper_="
+ << tcp_readable_stream_wrapper_;
+
+ tcp_readable_stream_wrapper_->controller_ = Controller();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise pull(ScriptState* script_state) override {
+ DVLOG(1) << "TCPReadableStreamWrapper::UnderlyingSource::pull() "
+ "tcp_readable_stream_wrapper_="
+ << tcp_readable_stream_wrapper_;
+
+ tcp_readable_stream_wrapper_->ReadFromPipeAndEnqueue();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise Cancel(ScriptState* script_state, ScriptValue reason) override {
+ DVLOG(1) << "TCPReadableStreamWrapper::UnderlyingSource::Cancel() "
+ "tcp_readable_stream_wrapper_="
+ << tcp_readable_stream_wrapper_;
+
+ tcp_readable_stream_wrapper_->AbortAndReset();
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(tcp_readable_stream_wrapper_);
+ UnderlyingSourceBase::Trace(visitor);
+ }
+
+ private:
+ const Member<TCPReadableStreamWrapper> tcp_readable_stream_wrapper_;
+};
+
+TCPReadableStreamWrapper::TCPReadableStreamWrapper(
+ ScriptState* script_state,
+ base::OnceClosure on_abort,
+ mojo::ScopedDataPipeConsumerHandle handle)
+ : script_state_(script_state),
+ on_abort_(std::move(on_abort)),
+ data_pipe_(std::move(handle)),
+ read_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ close_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {
+ read_watcher_.Watch(
+ data_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ WTF::BindRepeating(&TCPReadableStreamWrapper::OnHandleReady,
+ WrapWeakPersistent(this)));
+ close_watcher_.Watch(
+ data_pipe_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ WTF::BindRepeating(&TCPReadableStreamWrapper::OnPeerClosed,
+ WrapWeakPersistent(this)));
+
+ ScriptState::Scope scope(script_state_);
+ // Set queuing strategy of default behavior with a high water mark of 1.
+ readable_ = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state_,
+ MakeGarbageCollected<UnderlyingSource>(script_state_, this), 1);
+}
+
+TCPReadableStreamWrapper::~TCPReadableStreamWrapper() = default;
+
+void TCPReadableStreamWrapper::Reset() {
+ DVLOG(1) << "TCPReadableStreamWrapper::Reset() this=" << this;
+ // We no longer need to call |on_abort_|.
+ on_abort_.Reset();
+
+ ErrorStreamAbortAndReset();
+}
+
+void TCPReadableStreamWrapper::Trace(Visitor* visitor) const {
+ visitor->Trace(script_state_);
+ visitor->Trace(readable_);
+ visitor->Trace(controller_);
+}
+
+void TCPReadableStreamWrapper::OnHandleReady(MojoResult result,
+ const mojo::HandleSignalsState&) {
+ DVLOG(1) << "TCPReadableStreamWrapper::OnHandleReady() this=" << this
+ << " result=" << result;
+
+ switch (result) {
+ case MOJO_RESULT_OK:
+ ReadFromPipeAndEnqueue();
+ break;
+
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // Will be handled by |close_watcher_|.
+ break;
+
+ default:
+ NOTREACHED();
+ }
+}
+
+void TCPReadableStreamWrapper::OnPeerClosed(MojoResult result,
+ const mojo::HandleSignalsState&) {
+ DVLOG(1) << "TCPReadableStreamWrapper::OnPeerClosed() this=" << this
+ << " result=" << result;
+
+ DCHECK_EQ(result, MOJO_RESULT_OK);
+
+ DCHECK_EQ(state_, State::kOpen);
+ state_ = State::kClosed;
+
+ ErrorStreamAbortAndReset();
+}
+
+void TCPReadableStreamWrapper::ReadFromPipeAndEnqueue() {
+ if (!script_state_->ContextIsValid())
+ return;
+
+ DVLOG(1) << "TCPReadableStreamWrapper::ReadFromPipeAndEnqueue() this=" << this
+ << " in_two_phase_read_=" << in_two_phase_read_
+ << " read_pending_=" << read_pending_;
+
+ // Protect against re-entrancy.
+ if (in_two_phase_read_) {
+ read_pending_ = true;
+ return;
+ }
+ DCHECK(!read_pending_);
+
+ const void* buffer = nullptr;
+ uint32_t buffer_num_bytes = 0;
+ auto result = data_pipe_->BeginReadData(&buffer, &buffer_num_bytes,
+ MOJO_BEGIN_READ_DATA_FLAG_NONE);
+ switch (result) {
+ case MOJO_RESULT_OK: {
+ in_two_phase_read_ = true;
+ // EnqueueBytes() may re-enter this method via pull().
+ EnqueueBytes(buffer, buffer_num_bytes);
+ data_pipe_->EndReadData(buffer_num_bytes);
+ in_two_phase_read_ = false;
+ if (read_pending_) {
+ read_pending_ = false;
+ // pull() will not be called when another pull() is in progress, so the
+ // maximum recursion depth is 1.
+ ReadFromPipeAndEnqueue();
+ }
+ break;
+ }
+
+ case MOJO_RESULT_SHOULD_WAIT:
+ read_watcher_.ArmOrNotify();
+ return;
+
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // This will be handled by close_watcher_.
+ return;
+
+ default:
+ NOTREACHED() << "Unexpected result: " << result;
+ return;
+ }
+}
+
+void TCPReadableStreamWrapper::EnqueueBytes(const void* source,
+ uint32_t byte_length) {
+ DVLOG(1) << "TCPReadableStreamWrapper::EnqueueBytes() this=" << this;
+
+ auto* buffer =
+ DOMUint8Array::Create(static_cast<const uint8_t*>(source), byte_length);
+ controller_->Enqueue(buffer);
+}
+
+ScriptValue TCPReadableStreamWrapper::CreateAbortException() {
+ DVLOG(1) << "TCPReadableStreamWrapper::CreateAbortException() this=" << this;
+
+ DOMExceptionCode code = DOMExceptionCode::kNetworkError;
+ String message = "The stream was aborted by the remote";
+
+ return ScriptValue(script_state_->GetIsolate(),
+ V8ThrowDOMException::CreateOrEmpty(
+ script_state_->GetIsolate(), code, message));
+}
+
+void TCPReadableStreamWrapper::ErrorStreamAbortAndReset() {
+ DVLOG(1) << "TCPReadableStreamWrapper::ErrorStreamAbortAndReset() this="
+ << this;
+
+ if (script_state_->ContextIsValid()) {
+ ScriptState::Scope scope(script_state_);
+ if (controller_) {
+ controller_->Error(CreateAbortException());
+ }
+ }
+
+ controller_ = nullptr;
+ AbortAndReset();
+}
+
+void TCPReadableStreamWrapper::AbortAndReset() {
+ DVLOG(1) << "TCPReadableStreamWrapper::AbortAndReset() this=" << this;
+ state_ = State::kAborted;
+
+ if (on_abort_) {
+ std::move(on_abort_).Run();
+ }
+
+ ResetPipe();
+}
+
+void TCPReadableStreamWrapper::ResetPipe() {
+ DVLOG(1) << "TCPReadableStreamWrapper::ResetPipe() this=" << this;
+
+ read_watcher_.Cancel();
+ close_watcher_.Cancel();
+ data_pipe_.reset();
+}
+
+void TCPReadableStreamWrapper::Dispose() {
+ DVLOG(1) << "TCPReadableStreamWrapper::Dispose() this=" << this;
+
+ ResetPipe();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h
new file mode 100644
index 00000000000..fa733f0c7d1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h
@@ -0,0 +1,114 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_READABLE_STREAM_WRAPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_READABLE_STREAM_WRAPPER_H_
+
+#include "base/callback.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+class ScriptState;
+class ReadableStream;
+class ReadableStreamDefaultControllerWithScriptScope;
+
+// Helper class to read from a mojo consumer handle
+class MODULES_EXPORT TCPReadableStreamWrapper final
+ : public GarbageCollected<TCPReadableStreamWrapper> {
+ USING_PRE_FINALIZER(TCPReadableStreamWrapper, Dispose);
+
+ public:
+ enum class State {
+ kOpen,
+ kAborted,
+ kClosed,
+ };
+
+ TCPReadableStreamWrapper(ScriptState*,
+ base::OnceClosure on_abort,
+ mojo::ScopedDataPipeConsumerHandle);
+ ~TCPReadableStreamWrapper();
+
+ ReadableStream* Readable() const {
+ DVLOG(1) << "TCPReadableStreamWrapper::readable() called";
+
+ return readable_;
+ }
+
+ ScriptState* GetScriptState() { return script_state_; }
+
+ void Reset();
+
+ State GetState() const { return state_; }
+
+ void Trace(Visitor*) const;
+
+ private:
+ class UnderlyingSource;
+
+ // Called when |data_pipe_| becomes readable or errored.
+ void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
+
+ // Called when |data_pipe_| is closed.
+ void OnPeerClosed(MojoResult, const mojo::HandleSignalsState&);
+
+ // Reads all the data currently in the pipe and enqueues it. If no data is
+ // currently available, triggers the |read_watcher_| and enqueues when data
+ // becomes available.
+ void ReadFromPipeAndEnqueue();
+
+ // Copies a sequence of bytes into an ArrayBuffer and enqueues it.
+ void EnqueueBytes(const void* source, uint32_t byte_length);
+
+ // Creates a DOMException indicating that the stream has been aborted.
+ ScriptValue CreateAbortException();
+
+ // Errors |readable_| and resets |data_pipe_|.
+ void ErrorStreamAbortAndReset();
+
+ // Resets the |data_pipe_|.
+ void AbortAndReset();
+
+ // Resets |data_pipe_| and clears the watchers.
+ void ResetPipe();
+
+ // Prepares the object for destruction.
+ void Dispose();
+
+ const Member<ScriptState> script_state_;
+
+ base::OnceClosure on_abort_;
+
+ mojo::ScopedDataPipeConsumerHandle data_pipe_;
+
+ // Only armed when we need to read something.
+ mojo::SimpleWatcher read_watcher_;
+
+ // Always armed to detect close.
+ mojo::SimpleWatcher close_watcher_;
+
+ Member<ReadableStream> readable_;
+ Member<ReadableStreamDefaultControllerWithScriptScope> controller_;
+
+ State state_ = State::kOpen;
+
+ // Indicates if we are currently performing a two-phase read from the pipe and
+ // so can't start another read.
+ bool in_two_phase_read_ = false;
+
+ // Indicates if we need to perform another read after the current one
+ // completes.
+ bool read_pending_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_READABLE_STREAM_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper_unittest.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper_unittest.cc
new file mode 100644
index 00000000000..d9568fca5f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright 2020 The Chromium Authors. 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/tcp_readable_stream_wrapper.h"
+
+#include "base/test/mock_callback.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/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/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::StrictMock;
+
+// The purpose of this class is to ensure that the data pipe is reset before the
+// V8TestingScope is destroyed, so that the TCPReadableStreamWrapper object
+// doesn't try to create a DOMException after the ScriptState has gone away.
+class StreamCreator {
+ STACK_ALLOCATED();
+
+ public:
+ StreamCreator() = default;
+ ~StreamCreator() {
+ ClosePipe();
+
+ // Let the TCPReadableStreamWrapper object respond to the closure if it
+ // needs to.
+ test::RunPendingTasks();
+ }
+
+ // The default value of |capacity| means some sensible value selected by mojo.
+ TCPReadableStreamWrapper* Create(const V8TestingScope& scope,
+ uint32_t capacity = 0) {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = capacity;
+
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ MojoResult result =
+ mojo::CreateDataPipe(&options, data_pipe_producer_, data_pipe_consumer);
+ if (result != MOJO_RESULT_OK) {
+ ADD_FAILURE() << "CreateDataPipe() returned " << result;
+ }
+
+ auto* script_state = scope.GetScriptState();
+ auto* tcp_readable_stream_wrapper =
+ MakeGarbageCollected<TCPReadableStreamWrapper>(
+ script_state,
+ base::BindOnce(&StreamCreator::OnAbort, base::Unretained(this)),
+ std::move(data_pipe_consumer));
+ return tcp_readable_stream_wrapper;
+ }
+
+ void WriteToPipe(Vector<uint8_t> data) {
+ uint32_t num_bytes = data.size();
+ EXPECT_EQ(data_pipe_producer_->WriteData(data.data(), &num_bytes,
+ MOJO_WRITE_DATA_FLAG_ALL_OR_NONE),
+ MOJO_RESULT_OK);
+ EXPECT_EQ(num_bytes, data.size());
+ }
+
+ void ClosePipe() { data_pipe_producer_.reset(); }
+
+ // Copies the contents of a v8::Value containing a Uint8Array to a Vector.
+ static Vector<uint8_t> ToVector(const V8TestingScope& scope,
+ v8::Local<v8::Value> v8value) {
+ Vector<uint8_t> ret;
+
+ DOMUint8Array* value =
+ V8Uint8Array::ToImplWithTypeCheck(scope.GetIsolate(), v8value);
+ if (!value) {
+ ADD_FAILURE() << "chunk is not an Uint8Array";
+ return ret;
+ }
+ ret.Append(static_cast<uint8_t*>(value->Data()),
+ static_cast<wtf_size_t>(value->byteLength()));
+ return ret;
+ }
+
+ struct Iterator {
+ bool done = false;
+ Vector<uint8_t> value;
+ };
+
+ // Performs a single read from |reader|, converting the output to the
+ // Iterator type. Assumes that the readable stream is not errored.
+ // static Iterator Read(const V8TestingScope& scope,
+ Iterator Read(const V8TestingScope& scope,
+ ReadableStreamDefaultReader* reader) {
+ auto* script_state = scope.GetScriptState();
+ ScriptPromise read_promise =
+ reader->read(script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(script_state, read_promise);
+ tester.WaitUntilSettled();
+ EXPECT_TRUE(tester.IsFulfilled());
+ return IteratorFromReadResult(scope, tester.Value().V8Value());
+ }
+
+ static Iterator IteratorFromReadResult(const V8TestingScope& scope,
+ v8::Local<v8::Value> result) {
+ CHECK(result->IsObject());
+ Iterator ret;
+ v8::Local<v8::Value> v8value;
+ if (!V8UnpackIteratorResult(scope.GetScriptState(), result.As<v8::Object>(),
+ &ret.done)
+ .ToLocal(&v8value)) {
+ ADD_FAILURE() << "Couldn't unpack iterator";
+ return ret;
+ }
+ if (ret.done) {
+ EXPECT_TRUE(v8value->IsUndefined());
+ return ret;
+ }
+
+ ret.value = ToVector(scope, v8value);
+ return ret;
+ }
+
+ void OnAbort() { on_abort_called_ = true; }
+ bool HasAborted() const { return on_abort_called_; }
+
+ private:
+ bool on_abort_called_ = false;
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer_;
+};
+
+TEST(TCPReadableStreamWrapperTest, Create) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ auto* tcp_readable_stream_wrapper = stream_creator.Create(scope);
+ EXPECT_TRUE(tcp_readable_stream_wrapper->Readable());
+}
+
+TEST(TCPReadableStreamWrapperTest, ReadArrayBuffer) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+
+ auto* tcp_readable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* reader =
+ tcp_readable_stream_wrapper->Readable()->GetDefaultReaderForTesting(
+ script_state, ASSERT_NO_EXCEPTION);
+ stream_creator.WriteToPipe({'A'});
+
+ StreamCreator::Iterator result = stream_creator.Read(scope, reader);
+ EXPECT_FALSE(result.done);
+ EXPECT_THAT(result.value, ElementsAre('A'));
+}
+
+TEST(TCPReadableStreamWrapperTest, WriteToPipeWithPendingRead) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+
+ auto* tcp_readable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* reader =
+ tcp_readable_stream_wrapper->Readable()->GetDefaultReaderForTesting(
+ script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromise read_promise = reader->read(script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(script_state, read_promise);
+
+ test::RunPendingTasks();
+
+ stream_creator.WriteToPipe({'A'});
+
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsFulfilled());
+
+ StreamCreator::Iterator result =
+ stream_creator.IteratorFromReadResult(scope, tester.Value().V8Value());
+ EXPECT_FALSE(result.done);
+ EXPECT_THAT(result.value, ElementsAre('A'));
+}
+
+TEST(TCPReadableStreamWrapperTest, TriggerOnAborted) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ EXPECT_FALSE(stream_creator.HasAborted());
+
+ auto* tcp_readable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* reader =
+ tcp_readable_stream_wrapper->Readable()->GetDefaultReaderForTesting(
+ script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromise read_promise = reader->read(script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(script_state, read_promise);
+
+ test::RunPendingTasks();
+ stream_creator.WriteToPipe({'A'});
+ // Trigger OnAborted() on purpose.
+ stream_creator.ClosePipe();
+ tester.WaitUntilSettled();
+
+ ASSERT_TRUE(tester.IsFulfilled());
+ EXPECT_TRUE(stream_creator.HasAborted());
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.cc
index d8c7e335d72..d20b6d408fe 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.cc
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.cc
@@ -21,7 +21,7 @@ TCPSocket::TCPSocket(ScriptPromiseResolver& resolver)
->RegisterFeature(
SchedulingPolicy::Feature::
kOutstandingNetworkRequestDirectSocket,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
DCHECK(resolver_);
}
@@ -50,41 +50,141 @@ void TCPSocket::Init(int32_t result,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream) {
DCHECK(resolver_);
+ DCHECK(!tcp_readable_stream_wrapper_);
+ DCHECK(!tcp_writable_stream_wrapper_);
if (result == net::Error::OK) {
- // TODO(crbug.com/905818): Finish initialization.
- NOTIMPLEMENTED();
+ local_addr_ = local_addr;
+ peer_addr_ = peer_addr;
+ tcp_readable_stream_wrapper_ =
+ MakeGarbageCollected<TCPReadableStreamWrapper>(
+ resolver_->GetScriptState(),
+ WTF::Bind(&TCPSocket::OnReadableStreamAbort,
+ WrapWeakPersistent(this)),
+ std::move(receive_stream));
+ tcp_writable_stream_wrapper_ =
+ MakeGarbageCollected<TCPWritableStreamWrapper>(
+ resolver_->GetScriptState(),
+ WTF::Bind(&TCPSocket::OnWritableStreamAbort,
+ WrapWeakPersistent(this)),
+ std::move(send_stream));
resolver_->Resolve(this);
} else {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "Permission denied"));
+ socket_observer_receiver_.reset();
}
resolver_ = nullptr;
}
-ScriptPromise TCPSocket::close(ScriptState*, ExceptionState&) {
- // TODO(crbug.com/905818): Implement close.
- NOTIMPLEMENTED();
- return ScriptPromise();
+ScriptPromise TCPSocket::close(ScriptState* script_state, ExceptionState&) {
+ DoClose(/*is_local_close=*/true);
+
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ReadableStream* TCPSocket::readable() const {
+ DCHECK(tcp_readable_stream_wrapper_);
+ return tcp_readable_stream_wrapper_->Readable();
+}
+
+WritableStream* TCPSocket::writable() const {
+ DCHECK(tcp_writable_stream_wrapper_);
+ return tcp_writable_stream_wrapper_->Writable();
+}
+
+String TCPSocket::remoteAddress() const {
+ DCHECK(peer_addr_);
+ return String::FromUTF8(peer_addr_->ToStringWithoutPort());
+}
+
+uint16_t TCPSocket::remotePort() const {
+ DCHECK(peer_addr_);
+ return peer_addr_->port();
}
void TCPSocket::OnReadError(int32_t net_error) {
- // TODO(crbug.com/905818): Implement error handling.
- NOTIMPLEMENTED();
+ if (net_error > 0 || net_error == net::Error::ERR_IO_PENDING) {
+ return;
+ }
+
+ ResetReadableStream();
}
void TCPSocket::OnWriteError(int32_t net_error) {
- // TODO(crbug.com/905818): Implement error handling.
- NOTIMPLEMENTED();
+ if (net_error > 0 || net_error == net::Error::ERR_IO_PENDING) {
+ return;
+ }
+
+ ResetWritableStream();
}
void TCPSocket::Trace(Visitor* visitor) const {
visitor->Trace(resolver_);
+ visitor->Trace(tcp_readable_stream_wrapper_);
+ visitor->Trace(tcp_writable_stream_wrapper_);
ScriptWrappable::Trace(visitor);
}
void TCPSocket::OnSocketObserverConnectionError() {
- // TODO(crbug.com/905818): Implement error handling.
- NOTIMPLEMENTED();
+ DoClose(/*is_local_close=*/false);
+}
+
+void TCPSocket::OnReadableStreamAbort() {
+ ResetWritableStream();
+}
+
+void TCPSocket::OnWritableStreamAbort() {
+ ResetReadableStream();
+}
+
+void TCPSocket::DoClose(bool is_local_close) {
+ local_addr_ = base::nullopt;
+ peer_addr_ = base::nullopt;
+ tcp_socket_.reset();
+ socket_observer_receiver_.reset();
+ feature_handle_for_scheduler_.reset();
+
+ if (resolver_) {
+ DOMExceptionCode code = is_local_close ? DOMExceptionCode::kAbortError
+ : DOMExceptionCode::kNetworkError;
+ String message =
+ String::Format("The request was aborted %s",
+ is_local_close ? "locally" : "due to connection error");
+ resolver_->Reject(MakeGarbageCollected<DOMException>(code, message));
+ resolver_ = nullptr;
+
+ DCHECK(!tcp_readable_stream_wrapper_);
+ DCHECK(!tcp_writable_stream_wrapper_);
+
+ return;
+ }
+
+ ResetReadableStream();
+ ResetWritableStream();
+}
+
+void TCPSocket::ResetReadableStream() {
+ if (!tcp_readable_stream_wrapper_)
+ return;
+
+ if (tcp_readable_stream_wrapper_->GetState() ==
+ TCPReadableStreamWrapper::State::kAborted) {
+ return;
+ }
+ tcp_readable_stream_wrapper_->Reset();
+ tcp_readable_stream_wrapper_ = nullptr;
+}
+
+void TCPSocket::ResetWritableStream() {
+ if (!tcp_writable_stream_wrapper_)
+ return;
+
+ if (tcp_writable_stream_wrapper_->GetState() ==
+ TCPWritableStreamWrapper::State::kAborted) {
+ return;
+ }
+ tcp_writable_stream_wrapper_->Reset();
+ tcp_writable_stream_wrapper_ = nullptr;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.h b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.h
index 862a1170ba4..af3b3827d0f 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.h
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.h
@@ -13,6 +13,8 @@
#include "mojo/public/cpp/system/data_pipe.h"
#include "services/network/public/mojom/tcp_socket.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.h"
+#include "third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.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.h"
@@ -51,6 +53,11 @@ class MODULES_EXPORT TCPSocket final
// Web-exposed function
ScriptPromise close(ScriptState*, ExceptionState&);
+ ReadableStream* readable() const;
+ WritableStream* writable() const;
+ String remoteAddress() const;
+ uint16_t remotePort() const;
+
// network::mojom::blink::SocketObserver:
void OnReadError(int32_t net_error) override;
void OnWriteError(int32_t net_error) override;
@@ -61,6 +68,13 @@ class MODULES_EXPORT TCPSocket final
private:
void OnSocketObserverConnectionError();
+ void OnReadableStreamAbort();
+ void OnWritableStreamAbort();
+
+ void DoClose(bool is_local_close);
+ void ResetReadableStream();
+ void ResetWritableStream();
+
Member<ScriptPromiseResolver> resolver_;
FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
@@ -68,6 +82,11 @@ class MODULES_EXPORT TCPSocket final
mojo::Remote<network::mojom::blink::TCPConnectedSocket> tcp_socket_;
mojo::Receiver<network::mojom::blink::SocketObserver>
socket_observer_receiver_{this};
+
+ Member<TCPReadableStreamWrapper> tcp_readable_stream_wrapper_;
+ Member<TCPWritableStreamWrapper> tcp_writable_stream_wrapper_;
+ base::Optional<net::IPEndPoint> local_addr_;
+ base::Optional<net::IPEndPoint> peer_addr_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl
index 5f0486d5587..2003fae855c 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl
@@ -9,9 +9,11 @@
RuntimeEnabled=DirectSockets,
SecureContext
] interface TCPSocket {
- // TODO(crbug.com/905818): Add support for sending, receiving
- // TODO(crbug.com/905818): Add measurement
-
- [RaisesException, CallWith=ScriptState]
+ [RaisesException, CallWith=ScriptState, Measure]
Promise<void> close();
+
+ [Measure] readonly attribute DOMString remoteAddress;
+ [Measure] readonly attribute unsigned short remotePort;
+ [Measure] readonly attribute ReadableStream readable;
+ [Measure] readonly attribute WritableStream writable;
};
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket_unittest.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket_unittest.cc
new file mode 100644
index 00000000000..487a4dcfa78
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_socket_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2020 The Chromium Authors. 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/tcp_socket.h"
+
+#include "net/base/net_errors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.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/bindings/core/v8/v8_dom_exception.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+
+namespace blink {
+
+namespace {
+
+class TCPSocketCreator {
+ STACK_ALLOCATED();
+
+ public:
+ TCPSocketCreator() = default;
+ ~TCPSocketCreator() = default;
+
+ TCPSocket* Create(const V8TestingScope& scope) {
+ auto* script_state = scope.GetScriptState();
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto* tcp_socket = MakeGarbageCollected<TCPSocket>(*resolver);
+ create_promise_ = resolver->Promise();
+
+ return tcp_socket;
+ }
+
+ ScriptPromise GetSciptPromise() { return create_promise_; }
+
+ private:
+ ScriptPromise create_promise_;
+};
+
+TEST(TCPSocketTest, Create) {
+ V8TestingScope scope;
+ TCPSocketCreator tcp_socket_creator;
+
+ auto create_promise = tcp_socket_creator.GetSciptPromise();
+ EXPECT_TRUE(create_promise.IsEmpty());
+
+ tcp_socket_creator.Create(scope);
+
+ auto* script_state = scope.GetScriptState();
+ create_promise = tcp_socket_creator.GetSciptPromise();
+ ScriptPromiseTester create_tester(script_state, create_promise);
+ EXPECT_TRUE(create_promise.IsAssociatedWith(script_state));
+
+ ASSERT_FALSE(create_tester.IsFulfilled());
+}
+
+TEST(TCPSocketTest, CloseBeforeInit) {
+ V8TestingScope scope;
+ TCPSocketCreator tcp_socket_creator;
+
+ auto* tcp_socket = tcp_socket_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto create_promise = tcp_socket_creator.GetSciptPromise();
+ ScriptPromiseTester create_tester(script_state, create_promise);
+ ASSERT_FALSE(create_tester.IsRejected());
+
+ auto close_promise =
+ tcp_socket->close(script_state, scope.GetExceptionState());
+ ScriptPromiseTester close_tester(script_state, close_promise);
+
+ create_tester.WaitUntilSettled();
+ ASSERT_TRUE(create_tester.IsRejected());
+
+ DOMException* create_exception = V8DOMException::ToImplWithTypeCheck(
+ scope.GetIsolate(), create_tester.Value().V8Value());
+ ASSERT_TRUE(create_exception);
+ EXPECT_EQ(create_exception->name(), "AbortError");
+ EXPECT_EQ(create_exception->message(), "The request was aborted locally");
+
+ close_tester.WaitUntilSettled();
+ ASSERT_TRUE(close_tester.IsFulfilled());
+}
+
+TEST(TCPSocketTest, CloseAfterInitWithoutResultOK) {
+ V8TestingScope scope;
+ TCPSocketCreator tcp_socket_creator;
+
+ auto* tcp_socket = tcp_socket_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto create_promise = tcp_socket_creator.GetSciptPromise();
+ ScriptPromiseTester create_tester(script_state, create_promise);
+ ASSERT_FALSE(create_tester.IsRejected());
+
+ int32_t result = net::Error::ERR_FAILED;
+ tcp_socket->Init(result, net::IPEndPoint(), net::IPEndPoint(),
+ mojo::ScopedDataPipeConsumerHandle(),
+ mojo::ScopedDataPipeProducerHandle());
+
+ auto close_promise =
+ tcp_socket->close(script_state, scope.GetExceptionState());
+ ScriptPromiseTester close_tester(script_state, close_promise);
+
+ create_tester.WaitUntilSettled();
+ ASSERT_TRUE(create_tester.IsRejected());
+
+ DOMException* create_exception = V8DOMException::ToImplWithTypeCheck(
+ scope.GetIsolate(), create_tester.Value().V8Value());
+ ASSERT_TRUE(create_exception);
+ EXPECT_EQ(create_exception->name(), "NotAllowedError");
+ EXPECT_EQ(create_exception->message(), "Permission denied");
+
+ close_tester.WaitUntilSettled();
+ ASSERT_TRUE(close_tester.IsFulfilled());
+}
+
+TEST(TCPSocketTest, CloseAfterInitWithResultOK) {
+ V8TestingScope scope;
+ TCPSocketCreator tcp_socket_creator;
+
+ auto* tcp_socket = tcp_socket_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto create_promise = tcp_socket_creator.GetSciptPromise();
+ ScriptPromiseTester create_tester(script_state, create_promise);
+ ASSERT_FALSE(create_tester.IsFulfilled());
+
+ int32_t result = net::Error::OK;
+ tcp_socket->Init(result, net::IPEndPoint(), net::IPEndPoint(),
+ mojo::ScopedDataPipeConsumerHandle(),
+ mojo::ScopedDataPipeProducerHandle());
+ EXPECT_TRUE(tcp_socket->readable());
+ EXPECT_TRUE(tcp_socket->writable());
+
+ auto close_promise =
+ tcp_socket->close(script_state, scope.GetExceptionState());
+ ScriptPromiseTester close_tester(script_state, close_promise);
+
+ create_tester.WaitUntilSettled();
+ ASSERT_TRUE(create_tester.IsFulfilled());
+ close_tester.WaitUntilSettled();
+ ASSERT_TRUE(close_tester.IsFulfilled());
+}
+
+TEST(TCPSocketTest, OnSocketObserverConnectionError) {
+ V8TestingScope scope;
+ TCPSocketCreator tcp_socket_creator;
+
+ auto* tcp_socket = tcp_socket_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto create_promise = tcp_socket_creator.GetSciptPromise();
+ ScriptPromiseTester create_tester(script_state, create_promise);
+ ASSERT_FALSE(create_tester.IsRejected());
+
+ // Trigger OnSocketObserverConnectionError().
+ auto observer = tcp_socket->GetTCPSocketObserver();
+ observer.reset();
+
+ create_tester.WaitUntilSettled();
+ ASSERT_TRUE(create_tester.IsRejected());
+
+ DOMException* create_exception = V8DOMException::ToImplWithTypeCheck(
+ scope.GetIsolate(), create_tester.Value().V8Value());
+ ASSERT_TRUE(create_exception);
+ EXPECT_EQ(create_exception->name(), "NetworkError");
+ EXPECT_EQ(create_exception->message(),
+ "The request was aborted due to connection error");
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc
new file mode 100644
index 00000000000..aa492d71d03
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc
@@ -0,0 +1,372 @@
+// Copyright 2020 The Chromium Authors. 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/tcp_writable_stream_wrapper.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.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/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+// An implementation of UnderlyingSinkBase that forwards all operations to the
+// TCPWritableStreamWrapper object that created it.
+class TCPWritableStreamWrapper::UnderlyingSink final
+ : public UnderlyingSinkBase {
+ public:
+ explicit UnderlyingSink(TCPWritableStreamWrapper* tcp_writable_stream_wrapper)
+ : tcp_writable_stream_wrapper_(tcp_writable_stream_wrapper) {}
+
+ // Implementation of UnderlyingSinkBase
+ ScriptPromise start(ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState&) override {
+ DVLOG(1) << "TCPWritableStreamWrapper::UnderlyinkSink::start() "
+ "tcp_writable_stream_wrapper_="
+ << tcp_writable_stream_wrapper_;
+
+ tcp_writable_stream_wrapper_->controller_ = controller;
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise write(ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController*,
+ ExceptionState& exception_state) override {
+ DVLOG(1) << "TCPWritableStreamWrapper::UnderlyingSink::write() "
+ "tcp_writable_stream_wrapper_="
+ << tcp_writable_stream_wrapper_;
+
+ return tcp_writable_stream_wrapper_->SinkWrite(script_state, chunk,
+ exception_state);
+ }
+
+ ScriptPromise close(ScriptState* script_state, ExceptionState&) override {
+ DVLOG(1) << "TCPWritableStreamWrapper::UnderlingSink::close() "
+ "tcp_writable_stream_wrapper_="
+ << tcp_writable_stream_wrapper_;
+
+ DCHECK(!tcp_writable_stream_wrapper_->write_promise_resolver_);
+
+ tcp_writable_stream_wrapper_->AbortAndReset();
+
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) override {
+ DVLOG(1) << "TCPWritableStreamWrapper::UnderlyingSink::abort() "
+ "tcp_writable_stream_wrapper_="
+ << tcp_writable_stream_wrapper_;
+
+ return close(script_state, exception_state);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(tcp_writable_stream_wrapper_);
+ UnderlyingSinkBase::Trace(visitor);
+ }
+
+ private:
+ const Member<TCPWritableStreamWrapper> tcp_writable_stream_wrapper_;
+};
+
+TCPWritableStreamWrapper::CachedDataBuffer::CachedDataBuffer(
+ v8::Isolate* isolate,
+ const uint8_t* data,
+ size_t length)
+ : isolate_(isolate), length_(length) {
+ // We use the BufferPartition() allocator here to allow big enough
+ // allocations, and to do proper accounting of the used memory. If
+ // BufferPartition() will ever not be able to provide big enough allocations,
+ // e.g. because bigger ArrayBuffers get supported, then we have to switch to
+ // another allocator, e.g. the ArrayBuffer allocator.
+ buffer_ = std::unique_ptr<uint8_t[], OnFree>(
+ reinterpret_cast<uint8_t*>(WTF::Partitions::BufferPartition()->Alloc(
+ length, "TCPWritableStreamWrapper")));
+ memcpy(buffer_.get(), data, length);
+ isolate_->AdjustAmountOfExternalAllocatedMemory(static_cast<int64_t>(length));
+}
+
+TCPWritableStreamWrapper::CachedDataBuffer::~CachedDataBuffer() {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int64_t>(length_));
+}
+
+TCPWritableStreamWrapper::TCPWritableStreamWrapper(
+ ScriptState* script_state,
+ base::OnceClosure on_abort,
+ mojo::ScopedDataPipeProducerHandle handle)
+ : script_state_(script_state),
+ on_abort_(std::move(on_abort)),
+ data_pipe_(std::move(handle)),
+ write_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ close_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {
+ write_watcher_.Watch(
+ data_pipe_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ WTF::BindRepeating(&TCPWritableStreamWrapper::OnHandleReady,
+ WrapWeakPersistent(this)));
+ close_watcher_.Watch(
+ data_pipe_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ WTF::BindRepeating(&TCPWritableStreamWrapper::OnPeerClosed,
+ WrapWeakPersistent(this)));
+
+ ScriptState::Scope scope(script_state_);
+ // Set the CountQueueingStrategy's high water mark as 1 to make the logic of
+ // |WriteOrCacheData| much simpler
+ writable_ = WritableStream::CreateWithCountQueueingStrategy(
+ script_state_, MakeGarbageCollected<UnderlyingSink>(this), 1);
+}
+
+TCPWritableStreamWrapper::~TCPWritableStreamWrapper() = default;
+
+void TCPWritableStreamWrapper::Reset() {
+ DVLOG(1) << "TCPWritableStreamWrapper::Reset() this=" << this;
+
+ // We no longer need to call |on_abort_|.
+ on_abort_.Reset();
+
+ ErrorStreamAbortAndReset();
+}
+
+void TCPWritableStreamWrapper::Trace(Visitor* visitor) const {
+ visitor->Trace(script_state_);
+ visitor->Trace(writable_);
+ visitor->Trace(controller_);
+ visitor->Trace(write_promise_resolver_);
+}
+
+void TCPWritableStreamWrapper::OnHandleReady(MojoResult result,
+ const mojo::HandleSignalsState&) {
+ DVLOG(1) << "TCPWritableStreamWrapper::OnHandleReady() this=" << this
+ << " result=" << result;
+
+ switch (result) {
+ case MOJO_RESULT_OK:
+ WriteCachedData();
+ break;
+
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // Will be handled by |close_watcher_|.
+ break;
+
+ default:
+ NOTREACHED();
+ }
+}
+
+void TCPWritableStreamWrapper::OnPeerClosed(MojoResult result,
+ const mojo::HandleSignalsState&) {
+ DVLOG(1) << "TCPWritableStreamWrapper::OnPeerClosed() this=" << this
+ << " result=" << result;
+
+ DCHECK_EQ(result, MOJO_RESULT_OK);
+
+ DCHECK_EQ(state_, State::kOpen);
+ state_ = State::kClosed;
+
+ ErrorStreamAbortAndReset();
+}
+
+ScriptPromise TCPWritableStreamWrapper::SinkWrite(
+ ScriptState* script_state,
+ ScriptValue chunk,
+ ExceptionState& exception_state) {
+ DVLOG(1) << "TCPWritableStreamWrapper::SinkWrite() this=" << this;
+
+ // There can only be one call to write() in progress at a time.
+ DCHECK(!write_promise_resolver_);
+ DCHECK_EQ(0u, offset_);
+
+ if (!data_pipe_) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNetworkError,
+ "The underlying data pipe was disconnected.");
+ return ScriptPromise();
+ }
+
+ auto* isolate = script_state->GetIsolate();
+
+ ArrayBufferOrArrayBufferView buffer_source;
+ V8ArrayBufferOrArrayBufferView::ToImpl(
+ isolate, chunk.V8Value(), buffer_source,
+ UnionTypeConversionMode::kNotNullable, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ DCHECK(!buffer_source.IsNull());
+
+ // |data| will not be valid when this function returns.
+ base::span<const uint8_t> data;
+ if (buffer_source.IsArrayBuffer()) {
+ const auto* array_buffer = buffer_source.GetAsArrayBuffer();
+ data = base::make_span(static_cast<const uint8_t*>(array_buffer->Data()),
+ array_buffer->ByteLength());
+ } else {
+ DCHECK(buffer_source.IsArrayBufferView());
+ const auto* array_buffer_view = buffer_source.GetAsArrayBufferView().Get();
+ data = base::make_span(
+ static_cast<const uint8_t*>(array_buffer_view->BaseAddress()),
+ array_buffer_view->byteLength());
+ }
+
+ return WriteOrCacheData(script_state, data);
+}
+
+// Attempt to write |data|. Cache anything that could not be written
+// synchronously. Arrange for the cached data to be written asynchronously.
+ScriptPromise TCPWritableStreamWrapper::WriteOrCacheData(
+ ScriptState* script_state,
+ base::span<const uint8_t> data) {
+ DVLOG(1) << "TCPWritableStreamWrapper::WriteOrCacheData() this=" << this
+ << " data=(" << data.data() << ", " << data.size() << ")";
+ size_t written = WriteDataSynchronously(data);
+
+ if (written == data.size())
+ return ScriptPromise::CastUndefined(script_state);
+
+ DCHECK_LT(written, data.size());
+
+ if (!data_pipe_) {
+ return ScriptPromise::Reject(script_state, CreateAbortException());
+ }
+
+ DCHECK(!cached_data_);
+ cached_data_ = std::make_unique<CachedDataBuffer>(
+ script_state->GetIsolate(), data.data() + written, data.size() - written);
+ DCHECK_EQ(offset_, 0u);
+ write_watcher_.ArmOrNotify();
+ write_promise_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ return write_promise_resolver_->Promise();
+}
+
+// Write data previously cached. Arrange for any remaining data to be sent
+// asynchronously. Fulfill |write_promise_resolver_| once all data has been
+// written.
+void TCPWritableStreamWrapper::WriteCachedData() {
+ DVLOG(1) << "TCPWritableStreamWrapper::WriteCachedData() this=" << this;
+
+ auto data = base::make_span(static_cast<uint8_t*>(cached_data_->data()),
+ cached_data_->length())
+ .subspan(offset_);
+ size_t written = WriteDataSynchronously(data);
+
+ if (written == data.size()) {
+ cached_data_.reset();
+ offset_ = 0;
+ write_promise_resolver_->Resolve();
+ write_promise_resolver_ = nullptr;
+ return;
+ }
+
+ if (!data_pipe_) {
+ cached_data_.reset();
+ offset_ = 0;
+
+ return;
+ }
+
+ offset_ += written;
+
+ write_watcher_.ArmOrNotify();
+}
+
+// Write as much of |data| as can be written synchronously. Return the number of
+// bytes written. May close |data_pipe_| as a side-effect on error.
+size_t TCPWritableStreamWrapper::WriteDataSynchronously(
+ base::span<const uint8_t> data) {
+ DVLOG(1) << "TCPWritableStreamWrapper::WriteDataSynchronously() this=" << this
+ << " data=(" << data.data() << ", " << data.size() << ")";
+ DCHECK(data_pipe_);
+
+ // This use of saturated cast means that we will fallback to asynchronous
+ // sending if |data| is larger than 4GB. In practice we'd never be able to
+ // send 4GB synchronously anyway.
+ uint32_t num_bytes = base::saturated_cast<uint32_t>(data.size());
+ MojoResult result =
+ data_pipe_->WriteData(data.data(), &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
+ switch (result) {
+ case MOJO_RESULT_OK:
+ case MOJO_RESULT_SHOULD_WAIT:
+ return num_bytes;
+
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // Will be handled by |close_watcher_|.
+ return 0;
+
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+ScriptValue TCPWritableStreamWrapper::CreateAbortException() {
+ DVLOG(1) << "TCPWritableStreamWrapper::CreateAbortException() this=" << this;
+
+ DOMExceptionCode code = DOMExceptionCode::kNetworkError;
+ String message = "The stream was aborted by the remote.";
+
+ return ScriptValue(script_state_->GetIsolate(),
+ V8ThrowDOMException::CreateOrEmpty(
+ script_state_->GetIsolate(), code, message));
+}
+
+void TCPWritableStreamWrapper::ErrorStreamAbortAndReset() {
+ DVLOG(1) << "TCPWritableStreamWrapper::ErrorStreamAbortAndReset() this="
+ << this;
+
+ if (script_state_->ContextIsValid()) {
+ ScriptState::Scope scope(script_state_);
+ ScriptValue exception = CreateAbortException();
+ if (write_promise_resolver_) {
+ write_promise_resolver_->Reject(exception);
+ write_promise_resolver_ = nullptr;
+ } else if (controller_) {
+ controller_->error(script_state_, exception);
+ }
+ }
+
+ controller_ = nullptr;
+ AbortAndReset();
+}
+
+void TCPWritableStreamWrapper::AbortAndReset() {
+ DVLOG(1) << "TCPWritableStreamWrapper::AbortAndReset() this=" << this;
+ state_ = State::kAborted;
+
+ if (on_abort_) {
+ std::move(on_abort_).Run();
+ }
+
+ ResetPipe();
+}
+
+void TCPWritableStreamWrapper::ResetPipe() {
+ DVLOG(1) << "TCPWritableStreamWrapper::ResetPipe() this=" << this;
+
+ write_watcher_.Cancel();
+ close_watcher_.Cancel();
+ data_pipe_.reset();
+ if (cached_data_)
+ cached_data_.reset();
+}
+
+void TCPWritableStreamWrapper::Dispose() {
+ DVLOG(1) << "TCPWritableStreamWrapper::Dispose() this=" << this;
+
+ ResetPipe();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h
new file mode 100644
index 00000000000..25c5f463557
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h
@@ -0,0 +1,151 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_WRITABLE_STREAM_WRAPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_WRITABLE_STREAM_WRAPPER_H_
+
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace v8 {
+class Isolate;
+}
+
+namespace blink {
+
+class ScriptState;
+class WritableStream;
+class WritableStreamDefaultController;
+
+// Helper class to write to a mojo producer handle
+class MODULES_EXPORT TCPWritableStreamWrapper final
+ : public GarbageCollected<TCPWritableStreamWrapper> {
+ USING_PRE_FINALIZER(TCPWritableStreamWrapper, Dispose);
+
+ public:
+ enum class State {
+ kOpen,
+ kAborted,
+ kClosed,
+ };
+
+ TCPWritableStreamWrapper(ScriptState*,
+ base::OnceClosure on_abort,
+ mojo::ScopedDataPipeProducerHandle);
+ ~TCPWritableStreamWrapper();
+
+ WritableStream* Writable() const {
+ DVLOG(1) << "TCPWritableStreamWrapper::writable() called";
+
+ return writable_;
+ }
+
+ ScriptState* GetScriptState() { return script_state_; }
+
+ void Reset();
+
+ State GetState() const { return state_; }
+
+ void Trace(Visitor*) const;
+
+ private:
+ class UnderlyingSink;
+
+ // Called when |data_pipe_| becomes writable or errored.
+ void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
+
+ // Called when |data_pipe_| is closed.
+ void OnPeerClosed(MojoResult, const mojo::HandleSignalsState&);
+
+ // Implements UnderlyingSink::write().
+ ScriptPromise SinkWrite(ScriptState*, ScriptValue chunk, ExceptionState&);
+
+ // Writes |data| to |data_pipe_|, possible saving unwritten data to
+ // |cached_data_|.
+ ScriptPromise WriteOrCacheData(ScriptState*, base::span<const uint8_t> data);
+
+ // Attempts to write some more of |cached_data_| to |data_pipe_|.
+ void WriteCachedData();
+
+ // Writes zero or more bytes of |data| synchronously to |data_pipe_|,
+ // returning the number of bytes that were written.
+ size_t WriteDataSynchronously(base::span<const uint8_t> data);
+
+ // Creates a DOMException indicating that the stream has been aborted.
+ ScriptValue CreateAbortException();
+
+ // Errors |writable_|, resolves |writing_aborted_| and resets |data_pipe_|.
+ void ErrorStreamAbortAndReset();
+
+ // Reset the |data_pipe_|.
+ void AbortAndReset();
+
+ // Resets |data_pipe_| and clears the watchers. Also discards |cached_data_|.
+ void ResetPipe();
+
+ // Prepares the object for destruction.
+ void Dispose();
+
+ class CachedDataBuffer {
+ public:
+ CachedDataBuffer(v8::Isolate* isolate, const uint8_t* data, size_t length);
+
+ ~CachedDataBuffer();
+
+ size_t length() const { return length_; }
+
+ uint8_t* data() { return buffer_.get(); }
+
+ private:
+ // We need the isolate to call |AdjustAmountOfExternalAllocatedMemory| for
+ // the memory stored in |buffer_|.
+ v8::Isolate* isolate_;
+ size_t length_ = 0u;
+
+ struct OnFree {
+ void operator()(void* ptr) const {
+ WTF::Partitions::BufferPartition()->Free(ptr);
+ }
+ };
+ std::unique_ptr<uint8_t[], OnFree> buffer_;
+ };
+
+ const Member<ScriptState> script_state_;
+
+ base::OnceClosure on_abort_;
+
+ mojo::ScopedDataPipeProducerHandle data_pipe_;
+
+ // Only armed when we need to write something.
+ mojo::SimpleWatcher write_watcher_;
+
+ // Always armed to detect close.
+ mojo::SimpleWatcher close_watcher_;
+
+ // Data which has been passed to write() but still needs to be written
+ // asynchronously.
+ // Uses a custom CachedDataBuffer rather than a Vector because
+ // WTF::Vector is currently limited to 2GB.
+ std::unique_ptr<CachedDataBuffer> cached_data_;
+
+ // The offset into |cached_data_| of the first byte that still needs to be
+ // written.
+ size_t offset_ = 0;
+
+ Member<WritableStream> writable_;
+ Member<WritableStreamDefaultController> controller_;
+
+ // 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
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_WRITABLE_STREAM_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper_unittest.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper_unittest.cc
new file mode 100644
index 00000000000..22d9d126aac
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright 2020 The Chromium Authors. 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/tcp_writable_stream_wrapper.h"
+
+#include "base/test/mock_callback.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/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::StrictMock;
+
+// The purpose of this class is to ensure that the data pipe is reset before the
+// V8TestingScope is destroyed, so that the TCPWritableStreamWrapper object
+// doesn't try to create a DOMException after the ScriptState has gone away.
+class StreamCreator {
+ STACK_ALLOCATED();
+
+ public:
+ StreamCreator() = default;
+ ~StreamCreator() {
+ ClosePipe();
+
+ // Let the TCPWritableStreamWrapper object respond to the closure if it
+ // needs to.
+ test::RunPendingTasks();
+ }
+
+ // The default value of |capacity| means some sensible value selected by mojo.
+ TCPWritableStreamWrapper* Create(const V8TestingScope& scope,
+ uint32_t capacity = 0) {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = capacity;
+
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ MojoResult result =
+ mojo::CreateDataPipe(&options, data_pipe_producer, data_pipe_consumer_);
+ if (result != MOJO_RESULT_OK) {
+ ADD_FAILURE() << "CreateDataPipe() returned " << result;
+ }
+
+ auto* script_state = scope.GetScriptState();
+ auto* tcp_writable_stream_wrapper =
+ MakeGarbageCollected<TCPWritableStreamWrapper>(
+ script_state,
+ base::BindOnce(&StreamCreator::OnAbort, base::Unretained(this)),
+ std::move(data_pipe_producer));
+ return tcp_writable_stream_wrapper;
+ }
+
+ void ClosePipe() { data_pipe_consumer_.reset(); }
+
+ // Reads everything from |data_pipe_consumer_| and returns it in a vector.
+ Vector<uint8_t> ReadAllPendingData() {
+ Vector<uint8_t> data;
+ const void* buffer = nullptr;
+ uint32_t buffer_num_bytes = 0;
+ MojoResult result = data_pipe_consumer_->BeginReadData(
+ &buffer, &buffer_num_bytes, MOJO_BEGIN_READ_DATA_FLAG_NONE);
+
+ switch (result) {
+ case MOJO_RESULT_OK:
+ break;
+
+ case MOJO_RESULT_SHOULD_WAIT: // No more data yet.
+ return data;
+
+ default:
+ ADD_FAILURE() << "BeginReadData() failed: " << result;
+ return data;
+ }
+
+ data.Append(static_cast<const uint8_t*>(buffer), buffer_num_bytes);
+ data_pipe_consumer_->EndReadData(buffer_num_bytes);
+ return data;
+ }
+
+ void OnAbort() { on_abort_called_ = true; }
+ bool HasAborted() const { return on_abort_called_; }
+
+ private:
+ bool on_abort_called_ = false;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer_;
+};
+
+TEST(TCPWritableStreamWrapperTest, Create) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ auto* tcp_writable_stream_wrapper = stream_creator.Create(scope);
+ EXPECT_TRUE(tcp_writable_stream_wrapper->Writable());
+}
+
+TEST(TCPWritableStreamWrapperTest, WriteArrayBuffer) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ auto* tcp_writable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* writer = tcp_writable_stream_wrapper->Writable()->getWriter(
+ script_state, ASSERT_NO_EXCEPTION);
+ auto* chunk = DOMArrayBuffer::Create("A", 1);
+ ScriptPromise result =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(scope.GetScriptState(), result);
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsFulfilled());
+ EXPECT_THAT(stream_creator.ReadAllPendingData(), ElementsAre('A'));
+}
+
+TEST(TCPWritableStreamWrapperTest, WriteArrayBufferView) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ auto* tcp_writable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* writer = tcp_writable_stream_wrapper->Writable()->getWriter(
+ script_state, ASSERT_NO_EXCEPTION);
+ auto* buffer = DOMArrayBuffer::Create("*B", 2);
+ // Create a view into the buffer with offset 1, ie. "B".
+ auto* chunk = DOMUint8Array::Create(buffer, 1, 1);
+ ScriptPromise result =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(scope.GetScriptState(), result);
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsFulfilled());
+ EXPECT_THAT(stream_creator.ReadAllPendingData(), ElementsAre('B'));
+}
+
+bool IsAllNulls(base::span<const uint8_t> data) {
+ return std::all_of(data.begin(), data.end(), [](uint8_t c) { return !c; });
+}
+
+TEST(TCPWritableStreamWrapperTest, AsyncWrite) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ // Set a large pipe capacity, so any platform-specific excess is dwarfed in
+ // size.
+ constexpr uint32_t kPipeCapacity = 512u * 1024u;
+ auto* tcp_writable_stream_wrapper =
+ stream_creator.Create(scope, kPipeCapacity);
+
+ auto* script_state = scope.GetScriptState();
+ auto* writer = tcp_writable_stream_wrapper->Writable()->getWriter(
+ script_state, ASSERT_NO_EXCEPTION);
+
+ // Write a chunk that definitely will not fit in the pipe.
+ const size_t kChunkSize = kPipeCapacity * 3;
+ auto* chunk = DOMArrayBuffer::Create(kChunkSize, 1);
+ ScriptPromise result =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester tester(scope.GetScriptState(), result);
+
+ // Let the first pipe write complete.
+ test::RunPendingTasks();
+
+ // Let microtasks run just in case write() returns prematurely.
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ ASSERT_FALSE(tester.IsFulfilled());
+
+ // Read the first part of the data.
+ auto data1 = stream_creator.ReadAllPendingData();
+ EXPECT_LT(data1.size(), kChunkSize);
+
+ // Verify the data wasn't corrupted.
+ EXPECT_TRUE(IsAllNulls(data1));
+
+ // Allow the asynchronous pipe write to happen.
+ test::RunPendingTasks();
+
+ // Read the second part of the data.
+ auto data2 = stream_creator.ReadAllPendingData();
+ EXPECT_TRUE(IsAllNulls(data2));
+
+ test::RunPendingTasks();
+
+ // Read the final part of the data.
+ auto data3 = stream_creator.ReadAllPendingData();
+ EXPECT_TRUE(IsAllNulls(data3));
+ EXPECT_EQ(data1.size() + data2.size() + data3.size(), kChunkSize);
+
+ // Now the write() should settle.
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsFulfilled());
+
+ // Nothing should be left to read.
+ EXPECT_THAT(stream_creator.ReadAllPendingData(), ElementsAre());
+}
+
+// Writing immediately followed by closing should not lose data.
+TEST(TCPWritableStreamWrapperTest, WriteThenClose) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+
+ auto* tcp_writable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* writer = tcp_writable_stream_wrapper->Writable()->getWriter(
+ script_state, ASSERT_NO_EXCEPTION);
+ auto* chunk = DOMArrayBuffer::Create("D", 1);
+ ScriptPromise write_promise =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+
+ ScriptPromise close_promise =
+ writer->close(script_state, ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester write_tester(scope.GetScriptState(), write_promise);
+ ScriptPromiseTester close_tester(scope.GetScriptState(), close_promise);
+
+ // Make sure that write() and close() both run before the event loop is
+ // serviced.
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+ write_tester.WaitUntilSettled();
+ ASSERT_TRUE(write_tester.IsFulfilled());
+ close_tester.WaitUntilSettled();
+ ASSERT_TRUE(close_tester.IsFulfilled());
+
+ EXPECT_THAT(stream_creator.ReadAllPendingData(), ElementsAre('D'));
+}
+
+TEST(TCPWritableStreamWrapperTest, TriggerHasAborted) {
+ V8TestingScope scope;
+ StreamCreator stream_creator;
+ EXPECT_FALSE(stream_creator.HasAborted());
+
+ auto* tcp_writable_stream_wrapper = stream_creator.Create(scope);
+ auto* script_state = scope.GetScriptState();
+ auto* writer = tcp_writable_stream_wrapper->Writable()->getWriter(
+ script_state, ASSERT_NO_EXCEPTION);
+ auto* chunk = DOMArrayBuffer::Create("D", 1);
+ ScriptPromise write_promise =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ ScriptPromiseTester write_tester(scope.GetScriptState(), write_promise);
+ // Trigger onAborted() on purpose.
+ stream_creator.ClosePipe();
+ write_tester.WaitUntilSettled();
+
+ EXPECT_TRUE(stream_creator.HasAborted());
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/udp_socket.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/udp_socket.cc
index 1b3db2906d3..2627a6d2d29 100644
--- a/chromium/third_party/blink/renderer/modules/direct_sockets/udp_socket.cc
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/udp_socket.cc
@@ -21,7 +21,7 @@ UDPSocket::UDPSocket(ScriptPromiseResolver& resolver)
->RegisterFeature(
SchedulingPolicy::Feature::
kOutstandingNetworkRequestDirectSocket,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
DCHECK(resolver_);
}
diff --git a/chromium/third_party/blink/renderer/modules/document_metadata/DIR_METADATA b/chromium/third_party/blink/renderer/modules/document_metadata/DIR_METADATA
new file mode 100644
index 00000000000..3d5ee218827
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/document_metadata/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>Session"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/document_metadata/OWNERS b/chromium/third_party/blink/renderer/modules/document_metadata/OWNERS
index f8798d39411..c48e48ef750 100644
--- a/chromium/third_party/blink/renderer/modules/document_metadata/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/document_metadata/OWNERS
@@ -1,6 +1 @@
-beccahughes@chromium.org
steimel@chromium.org
-sgbowen@google.com
-
-# COMPONENT: Blink>Media>Session
-# TEAM: media-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/encoding/DIR_METADATA b/chromium/third_party/blink/renderer/modules/encoding/DIR_METADATA
new file mode 100644
index 00000000000..fe99f353943
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/encoding/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>TextEncoding"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/encoding/OWNERS b/chromium/third_party/blink/renderer/modules/encoding/OWNERS
index b589432ecf9..0c07f679ffb 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/encoding/OWNERS
@@ -1,5 +1,3 @@
jsbell@chromium.org
ricea@chromium.org
kbr@chromium.org
-
-# COMPONENT: Blink>TextEncoding
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
index 66e4f50846b..430b431bd29 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder.cc
@@ -81,29 +81,25 @@ String TextDecoder::decode(const BufferSource& input,
const TextDecodeOptions* options,
ExceptionState& exception_state) {
DCHECK(options);
- DCHECK(!input.IsNull());
+ // In case of `input` == IDL "missing" special value, default to (nullptr, 0).
+ void* start = nullptr;
+ size_t length = 0;
if (input.IsArrayBufferView()) {
- const char* start = static_cast<const char*>(
- input.GetAsArrayBufferView().View()->BaseAddress());
- size_t length = input.GetAsArrayBufferView().View()->byteLength();
- if (length > std::numeric_limits<uint32_t>::max()) {
- exception_state.ThrowRangeError(
- "Buffer size exceeds maximum heap object size.");
- return String();
- }
- return decode(start, static_cast<uint32_t>(length), options,
- exception_state);
+ start = input.GetAsArrayBufferView()->BaseAddress();
+ length = input.GetAsArrayBufferView()->byteLength();
+ } else if (input.IsArrayBuffer()) {
+ start = input.GetAsArrayBuffer()->Data();
+ length = input.GetAsArrayBuffer()->ByteLength();
}
- DCHECK(input.IsArrayBuffer());
- const char* start =
- static_cast<const char*>(input.GetAsArrayBuffer()->Data());
- size_t length = input.GetAsArrayBuffer()->ByteLength();
+
if (length > std::numeric_limits<uint32_t>::max()) {
exception_state.ThrowRangeError(
"Buffer size exceeds maximum heap object size.");
return String();
}
- return decode(start, static_cast<uint32_t>(length), options, exception_state);
+
+ return decode(static_cast<const char*>(start), static_cast<uint32_t>(length),
+ options, exception_state);
}
String TextDecoder::decode(const char* start,
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
index 9dd6b221c4c..b8bddfc1524 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc
@@ -52,7 +52,7 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
// This implements the "get a copy of the bytes held by the buffer source"
// algorithm (https://heycam.github.io/webidl/#dfn-get-buffer-source-copy).
if (bufferSource.IsArrayBufferView()) {
- const auto* view = bufferSource.GetAsArrayBufferView().View();
+ const auto* view = bufferSource.GetAsArrayBufferView().Get();
const char* start = static_cast<const char*>(view->BaseAddress());
size_t length = view->byteLength();
if (length > std::numeric_limits<uint32_t>::max()) {
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
index 5af8a9488f0..81fb7731bdc 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -17,7 +18,6 @@ class ExceptionState;
class ReadableStream;
class ScriptState;
class TextDecoderOptions;
-class Visitor;
class WritableStream;
// Implements the TextDecoderStream interface as specified at
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc b/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc
index afe8b694585..285f04f02cc 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc
@@ -88,15 +88,15 @@ TextEncoderEncodeIntoResult* TextEncoder::encodeInto(
TextEncoderEncodeIntoResult::Create();
TextCodec::EncodeIntoResult encode_into_result_data;
- unsigned char* destination_buffer = destination.View()->Data();
+ unsigned char* destination_buffer = destination->Data();
if (source.Is8Bit()) {
encode_into_result_data =
codec_->EncodeInto(source.Characters8(), source.length(),
- destination_buffer, destination.View()->length());
+ destination_buffer, destination->length());
} else {
encode_into_result_data =
codec_->EncodeInto(source.Characters16(), source.length(),
- destination_buffer, destination.View()->length());
+ destination_buffer, destination->length());
}
encode_into_result->setRead(encode_into_result_data.code_units_read);
diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
index 4ba6eced9ff..a9c21a49401 100644
--- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
+++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/streams/transform_stream.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -16,7 +17,6 @@ class ExceptionState;
class ReadableStream;
class ScriptState;
class WritableStream;
-class Visitor;
// Implements the TextEncoderStream interface as specified at
// https://encoding.spec.whatwg.org/#interface-textencoderstream.
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/DIR_METADATA b/chromium/third_party/blink/renderer/modules/encryptedmedia/DIR_METADATA
new file mode 100644
index 00000000000..19cd798fea1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Media>Encrypted"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/OWNERS b/chromium/third_party/blink/renderer/modules/encryptedmedia/OWNERS
index 741c7d06a67..f09af455105 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/OWNERS
@@ -1,4 +1,2 @@
jrummell@chromium.org
xhwang@chromium.org
-
-# COMPONENT: Internals>Media>Encrypted
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
index 29a83ff6043..a85678fd957 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/html_media_element_encrypted_media.cc
@@ -55,7 +55,7 @@ class SetMediaKeysHandler : public ScriptPromiseResolver {
Member<HTMLMediaElement> element_;
Member<MediaKeys> new_media_keys_;
bool made_reservation_;
- TaskRunnerTimer<SetMediaKeysHandler> timer_;
+ HeapTaskRunnerTimer<SetMediaKeysHandler> timer_;
DISALLOW_COPY_AND_ASSIGN(SetMediaKeysHandler);
};
@@ -323,6 +323,7 @@ void SetMediaKeysHandler::SetFailed(ExceptionCode code,
void SetMediaKeysHandler::Trace(Visitor* visitor) const {
visitor->Trace(element_);
visitor->Trace(new_media_keys_);
+ visitor->Trace(timer_);
ScriptPromiseResolver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
index 5d98807cbac..44a104a76c4 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
@@ -1039,6 +1039,7 @@ void MediaKeySession::Trace(Visitor* visitor) const {
visitor->Trace(media_keys_);
visitor->Trace(key_statuses_map_);
visitor->Trace(closed_promise_);
+ visitor->Trace(action_timer_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
index 097d0c7f0dd..192e4d43e4e 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_session.h
@@ -161,7 +161,7 @@ class MediaKeySession final
Member<ClosedPromise> closed_promise_;
HeapDeque<Member<PendingAction>> pending_actions_;
- TaskRunnerTimer<MediaKeySession> action_timer_;
+ HeapTaskRunnerTimer<MediaKeySession> action_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
index 61ff322aab2..3ff12c560f6 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.cc
@@ -152,8 +152,7 @@ void ReportMetrics(ExecutionContext* execution_context,
ukm::builders::Media_EME_CreateMediaKeys builder(document->UkmSourceID());
builder.SetKeySystem(KeySystemForUkm::kWidevine);
- builder.SetIsAdFrame(
- static_cast<int>(frame->IsAdRoot() || frame->IsAdSubframe()));
+ builder.SetIsAdFrame(static_cast<int>(frame->IsAdSubframe()));
builder.SetIsCrossOrigin(static_cast<int>(frame->IsCrossOriginToMainFrame()));
builder.SetIsTopFrame(static_cast<int>(frame->IsMainFrame()));
builder.Record(document->UkmRecorder());
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.cc
index 461b77f9566..1bc54329c8d 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.cc
@@ -219,8 +219,7 @@ void MediaKeySystemAccessInitializerBase::GenerateWarningAndReportMetrics()
ukm::builders::Media_EME_RequestMediaKeySystemAccess builder(
DomWindow()->UkmSourceID());
builder.SetKeySystem(KeySystemForUkm::kWidevine);
- builder.SetIsAdFrame(
- static_cast<int>(frame->IsAdRoot() || frame->IsAdSubframe()));
+ builder.SetIsAdFrame(static_cast<int>(frame->IsAdSubframe()));
builder.SetIsCrossOrigin(static_cast<int>(frame->IsCrossOriginToMainFrame()));
builder.SetIsTopFrame(static_cast<int>(frame->IsMainFrame()));
builder.SetVideoCapabilities(static_cast<int>(has_video_capabilities));
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
index 6391504e6c0..92c4cf64abb 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
@@ -460,6 +460,7 @@ WebContentDecryptionModule* MediaKeys::ContentDecryptionModule() {
void MediaKeys::Trace(Visitor* visitor) const {
visitor->Trace(pending_actions_);
visitor->Trace(media_element_);
+ visitor->Trace(timer_);
ScriptWrappable::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.h b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
index 8b82e84aaa3..9819b0fbd41 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
@@ -133,7 +133,7 @@ class MediaKeys : public ScriptWrappable,
bool reserved_for_media_element_;
HeapDeque<Member<PendingAction>> pending_actions_;
- TaskRunnerTimer<MediaKeys> timer_;
+ HeapTaskRunnerTimer<MediaKeys> timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 823ac106e84..d2672bed59b 100644
--- a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -122,7 +122,7 @@ ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess(
mojom::ConsoleMessageLevel::kWarning,
kEncryptedMediaFeaturePolicyConsoleWarning));
exception_state.ThrowSecurityError(
- "requestMediaKeySystemAccess is disabled by feature policy.");
+ "requestMediaKeySystemAccess is disabled by permissions policy.");
return ScriptPromise();
}
diff --git a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
index 95dcae88b4d..2a634aab437 100644
--- a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
+++ b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5
@@ -15,6 +15,8 @@
"BluetoothRemoteGATTCharacteristic",
"CookieStore",
"DelegatedInkTrail",
+ "EyeDropper",
+ "DeviceService",
"MediaKeySession",
"FileWriter",
"GPUDevice",
@@ -33,6 +35,7 @@
"MediaDevices",
"MediaStream",
"MediaStreamTrack",
+ "ModalCloseWatcher",
"RTCDTMFSender",
"RTCDataChannel",
"RTCDtlsTransport",
@@ -54,6 +57,7 @@
"ScreenOrientation",
"Sensor",
"Serial",
+ "SerialPort",
"ServiceWorker",
"ServiceWorkerContainer",
"ServiceWorkerGlobalScope",
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/DIR_METADATA b/chromium/third_party/blink/renderer/modules/eventsource/DIR_METADATA
new file mode 100644
index 00000000000..17e49e6acba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eventsource/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Network"
+}
+team_email: "blink-network-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/OWNERS b/chromium/third_party/blink/renderer/modules/eventsource/OWNERS
index 7115fad815c..acbf93af41e 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/eventsource/OWNERS
@@ -1,4 +1 @@
yhirano@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
index 0ef2d04cafb..1bec360cb18 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
+++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc
@@ -365,6 +365,7 @@ bool EventSource::HasPendingActivity() const {
void EventSource::Trace(Visitor* visitor) const {
visitor->Trace(parser_);
visitor->Trace(loader_);
+ visitor->Trace(connect_timer_);
EventTargetWithInlineData::Trace(visitor);
ThreadableLoaderClient::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source.h b/chromium/third_party/blink/renderer/modules/eventsource/event_source.h
index 914b436a742..68fe6664443 100644
--- a/chromium/third_party/blink/renderer/modules/eventsource/event_source.h
+++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source.h
@@ -131,7 +131,7 @@ class MODULES_EXPORT EventSource final
Member<EventSourceParser> parser_;
Member<ThreadableLoader> loader_;
- TaskRunnerTimer<EventSource> connect_timer_;
+ HeapTaskRunnerTimer<EventSource> connect_timer_;
uint64_t reconnect_delay_;
String event_stream_origin_;
diff --git a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
index b9ffc211d61..e48fb21dc39 100644
--- a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -31,6 +31,7 @@ static_library("test_support") {
deps = [
"//skia",
"//third_party/blink/renderer/bindings/modules/v8:testing",
+ "//third_party/blink/renderer/core",
"//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules:modules_testing",
"//third_party/blink/renderer/platform",
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 cecb6b6eb61..8d0ffc5f10c 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_rect.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_document.h"
@@ -41,7 +40,6 @@
#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"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -60,6 +58,7 @@
#include "third_party/blink/renderer/modules/accessibility/ax_selection.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/skia/include/core/SkMatrix44.h"
+#include "ui/accessibility/ax_action_data.h"
namespace blink {
@@ -86,44 +85,26 @@ mojom::blink::ScrollAlignment::Behavior ToBlinkScrollAlignmentBehavior(
}
} // namespace
-class WebAXSparseAttributeClientAdapter : public AXSparseAttributeClient {
- public:
- explicit WebAXSparseAttributeClientAdapter(
- WebAXSparseAttributeClient& attribute_map)
- : attribute_map_(attribute_map) {}
- virtual ~WebAXSparseAttributeClientAdapter() = default;
-
- private:
- WebAXSparseAttributeClient& attribute_map_;
-
- void AddObjectAttribute(AXObjectAttribute attribute,
- AXObject& value) override {
- attribute_map_.AddObjectAttribute(
- static_cast<WebAXObjectAttribute>(attribute), WebAXObject(&value));
- }
-
- void AddObjectVectorAttribute(AXObjectVectorAttribute attribute,
- HeapVector<Member<AXObject>>* value) override {
- WebVector<WebAXObject> result(value->size());
- std::copy(value->begin(), value->end(), result.begin());
- attribute_map_.AddObjectVectorAttribute(
- static_cast<WebAXObjectVectorAttribute>(attribute), result);
- }
-};
-
// A utility class which uses the lifetime of this object to signify when
// AXObjCache or AXObjectCacheImpl handles programmatic actions.
class ScopedActionAnnotator {
public:
- explicit ScopedActionAnnotator(AXObject* obj)
+ ScopedActionAnnotator(AXObject* obj,
+ ax::mojom::blink::Action event_from_action)
: cache_(&obj->AXObjectCache()) {
- DCHECK_EQ(cache_->active_event_from(), ax::mojom::blink::EventFrom::kNone)
+ std::pair<ax::mojom::blink::EventFrom, ax::mojom::blink::Action>
+ event_from_data = cache_->active_event_from_data();
+ DCHECK_EQ(event_from_data.first, ax::mojom::blink::EventFrom::kNone)
<< "Multiple ScopedActionAnnotator instances cannot be nested.";
- cache_->set_active_event_from(ax::mojom::blink::EventFrom::kAction);
+ DCHECK_EQ(event_from_data.second, ax::mojom::blink::Action::kNone)
+ << "event_from_action must not be set before construction.";
+ cache_->set_active_event_from_data(ax::mojom::blink::EventFrom::kAction,
+ event_from_action);
}
~ScopedActionAnnotator() {
- cache_->set_active_event_from(ax::mojom::blink::EventFrom::kNone);
+ cache_->set_active_event_from_data(ax::mojom::blink::EventFrom::kNone,
+ ax::mojom::blink::Action::kNone);
}
private:
@@ -240,7 +221,6 @@ bool WebAXObject::CanSetValueAttribute() const {
unsigned WebAXObject::ChildCount() const {
if (IsDetached())
return 0;
-
return private_->ChildCountIncludingIgnored();
}
@@ -258,15 +238,6 @@ WebAXObject WebAXObject::ParentObject() const {
return WebAXObject(private_->ParentObjectIncludedInTree());
}
-void WebAXObject::GetSparseAXAttributes(
- WebAXSparseAttributeClient& client) const {
- if (IsDetached())
- return;
-
- WebAXSparseAttributeClientAdapter adapter(client);
- private_->GetSparseAXAttributes(adapter);
-}
-
void WebAXObject::Serialize(ui::AXNodeData* node_data,
ui::AXMode accessibility_mode) const {
if (IsDetached())
@@ -427,20 +398,6 @@ bool WebAXObject::IsEditable() const {
return private_->IsEditable();
}
-int WebAXObject::PosInSet() const {
- if (IsDetached())
- return 0;
-
- return private_->PosInSet();
-}
-
-int WebAXObject::SetSize() const {
- if (IsDetached())
- return 0;
-
- return private_->SetSize();
-}
-
bool WebAXObject::IsInLiveRegion() const {
if (IsDetached())
return false;
@@ -524,11 +481,11 @@ bool WebAXObject::CanvasHasFallbackContent() const {
return private_->CanvasHasFallbackContent();
}
-WebString WebAXObject::ImageDataUrl(const WebSize& max_size) const {
+WebString WebAXObject::ImageDataUrl(const gfx::Size& max_size) const {
if (IsDetached())
return WebString();
- return private_->ImageDataUrl(max_size);
+ return private_->ImageDataUrl(IntSize(max_size));
}
ax::mojom::InvalidState WebAXObject::InvalidState() const {
@@ -568,7 +525,8 @@ WebAXObject WebAXObject::HitTest(const gfx::Point& point) const {
if (IsDetached())
return WebAXObject();
- ScopedActionAnnotator annotater(private_.Get());
+ ScopedActionAnnotator annotater(private_.Get(),
+ ax::mojom::blink::Action::kHitTest);
IntPoint contents_point =
private_->DocumentFrameView()->SoonToBeRemovedUnscaledViewportToContents(
IntPoint(point));
@@ -592,9 +550,9 @@ WebAXObject WebAXObject::HitTest(const gfx::Point& point) const {
return WebAXObject();
}
-WebRect WebAXObject::GetBoundsInFrameCoordinates() const {
+gfx::Rect WebAXObject::GetBoundsInFrameCoordinates() const {
LayoutRect rect = private_->GetBoundsInFrameCoordinates();
- return WebRect(EnclosingIntRect(rect));
+ return EnclosingIntRect(rect);
}
WebString WebAXObject::KeyboardShortcut() const {
@@ -633,35 +591,12 @@ WebString WebAXObject::Language() const {
return private_->Language();
}
-bool WebAXObject::ClearAccessibilityFocus() const {
+bool WebAXObject::PerformAction(const ui::AXActionData& action_data) const {
if (IsDetached())
return false;
- ScopedActionAnnotator annotater(private_.Get());
- return private_->InternalClearAccessibilityFocusAction();
-}
-
-bool WebAXObject::Click() const {
- if (IsDetached())
- return false;
-
- return private_->RequestClickAction();
-}
-
-bool WebAXObject::Increment() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestIncrementAction();
-}
-
-bool WebAXObject::Decrement() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestDecrementAction();
+ ScopedActionAnnotator annotater(private_.Get(), action_data.action);
+ return private_->PerformAction(action_data);
}
WebAXObject WebAXObject::InPageLinkTarget() const {
@@ -775,19 +710,12 @@ void WebAXObject::Selection(bool& is_selection_backward,
}
}
-bool WebAXObject::SetAccessibilityFocus() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->InternalSetAccessibilityFocusAction();
-}
-
bool WebAXObject::SetSelected(bool selected) const {
if (IsDetached())
return false;
- ScopedActionAnnotator annotater(private_.Get());
+ ScopedActionAnnotator annotater(private_.Get(),
+ ax::mojom::blink::Action::kSetSelection);
return private_->RequestSetSelectedAction(selected);
}
@@ -798,7 +726,8 @@ bool WebAXObject::SetSelection(const WebAXObject& anchor_object,
if (IsDetached() || anchor_object.IsDetached() || focus_object.IsDetached())
return false;
- ScopedActionAnnotator annotater(private_.Get());
+ ScopedActionAnnotator annotater(private_.Get(),
+ ax::mojom::blink::Action::kSetSelection);
AXPosition ax_base, ax_extent;
if (static_cast<const AXObject*>(anchor_object)->IsTextObject() ||
static_cast<const AXObject*>(anchor_object)->IsNativeTextControl()) {
@@ -834,38 +763,6 @@ bool WebAXObject::SetSelection(const WebAXObject& anchor_object,
return ax_selection.Select();
}
-bool WebAXObject::Focus() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestFocusAction();
-}
-
-bool WebAXObject::SetSequentialFocusNavigationStartingPoint() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestSetSequentialFocusNavigationStartingPointAction();
-}
-
-bool WebAXObject::SetValue(WebString value) const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestSetValueAction(value);
-}
-
-bool WebAXObject::ShowContextMenu() const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestShowContextMenuAction();
-}
-
WebString WebAXObject::StringValue() const {
if (IsDetached())
return WebString();
@@ -887,24 +784,15 @@ WebURL WebAXObject::Url() const {
return private_->Url();
}
-WebAXObject WebAXObject::ChooserPopup() const {
- if (IsDetached())
- return WebAXObject();
- AXObject* target = private_->ChooserPopup();
- if (!target || target->IsDetached())
- return WebAXObject();
- return WebAXObject(target);
-}
-
WebString WebAXObject::GetName(ax::mojom::NameFrom& out_name_from,
WebVector<WebAXObject>& out_name_objects) const {
+ out_name_from = ax::mojom::blink::NameFrom::kUninitialized;
+
if (IsDetached())
return WebString();
- ax::mojom::NameFrom name_from = ax::mojom::NameFrom::kUninitialized;
HeapVector<Member<AXObject>> name_objects;
- WebString result = private_->GetName(name_from, &name_objects);
- out_name_from = name_from;
+ WebString result = private_->GetName(out_name_from, &name_objects);
out_name_objects.reserve(name_objects.size());
out_name_objects.resize(name_objects.size());
@@ -926,15 +814,14 @@ WebString WebAXObject::Description(
ax::mojom::NameFrom name_from,
ax::mojom::DescriptionFrom& out_description_from,
WebVector<WebAXObject>& out_description_objects) const {
+ out_description_from = ax::mojom::blink::DescriptionFrom::kUninitialized;
+
if (IsDetached())
return WebString();
- ax::mojom::DescriptionFrom description_from =
- ax::mojom::DescriptionFrom::kUninitialized;
HeapVector<Member<AXObject>> description_objects;
- String result =
- private_->Description(name_from, description_from, &description_objects);
- out_description_from = description_from;
+ String result = private_->Description(name_from, out_description_from,
+ &description_objects);
out_description_objects.reserve(description_objects.size());
out_description_objects.resize(description_objects.size());
@@ -1203,53 +1090,6 @@ WebAXObject WebAXObject::PreviousOnLine() const {
return WebAXObject(private_.Get()->PreviousOnLine());
}
-static ax::mojom::MarkerType ToAXMarkerType(
- DocumentMarker::MarkerType marker_type) {
- switch (marker_type) {
- case DocumentMarker::kSpelling:
- return ax::mojom::MarkerType::kSpelling;
- case DocumentMarker::kGrammar:
- return ax::mojom::MarkerType::kGrammar;
- case DocumentMarker::kTextFragment:
- case DocumentMarker::kTextMatch:
- return ax::mojom::MarkerType::kTextMatch;
- case DocumentMarker::kActiveSuggestion:
- return ax::mojom::MarkerType::kActiveSuggestion;
- case DocumentMarker::kSuggestion:
- return ax::mojom::MarkerType::kSuggestion;
- default:
- return ax::mojom::MarkerType::kNone;
- }
-}
-
-void WebAXObject::Markers(WebVector<ax::mojom::MarkerType>& types,
- WebVector<int>& starts,
- WebVector<int>& ends) const {
- if (IsDetached())
- return;
-
- 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());
- WebVector<int> start_offsets(marker_ranges.size());
- WebVector<int> end_offsets(marker_ranges.size());
- for (wtf_size_t i = 0; i < marker_types.size(); ++i) {
- web_marker_types[i] = ToAXMarkerType(marker_types[i]);
- DCHECK(marker_ranges[i].IsValid());
- DCHECK_EQ(marker_ranges[i].Start().ContainerObject(),
- marker_ranges[i].End().ContainerObject());
- start_offsets[i] = marker_ranges[i].Start().TextOffset();
- end_offsets[i] = marker_ranges[i].End().TextOffset();
- }
-
- types.Swap(web_marker_types);
- starts.Swap(start_offsets);
- ends.Swap(end_offsets);
-}
-
void WebAXObject::CharacterOffsets(WebVector<int>& offsets) const {
if (IsDetached())
return;
@@ -1287,12 +1127,6 @@ bool WebAXObject::IsScrollableContainer() const {
return private_->IsScrollableContainer();
}
-bool WebAXObject::IsUserScrollable() const {
- if (IsDetached())
- return false;
-
- return private_->IsUserScrollable();
-}
gfx::Point WebAXObject::GetScrollOffset() const {
if (IsDetached())
return gfx::Point();
@@ -1373,19 +1207,21 @@ bool WebAXObject::ScrollToMakeVisible() const {
if (IsDetached())
return false;
- ScopedActionAnnotator annotater(private_.Get());
+ ScopedActionAnnotator annotater(
+ private_.Get(), ax::mojom::blink::Action::kScrollToMakeVisible);
return private_->RequestScrollToMakeVisibleAction();
}
bool WebAXObject::ScrollToMakeVisibleWithSubFocus(
- const WebRect& subfocus,
+ const gfx::Rect& subfocus,
ax::mojom::ScrollAlignment horizontal_scroll_alignment,
ax::mojom::ScrollAlignment vertical_scroll_alignment,
ax::mojom::ScrollBehavior scroll_behavior) const {
if (IsDetached())
return false;
- ScopedActionAnnotator annotater(private_.Get());
+ ScopedActionAnnotator annotater(
+ private_.Get(), ax::mojom::blink::Action::kScrollToMakeVisible);
auto horizontal_behavior =
ToBlinkScrollAlignmentBehavior(horizontal_scroll_alignment);
auto vertical_behavior =
@@ -1405,18 +1241,10 @@ bool WebAXObject::ScrollToMakeVisibleWithSubFocus(
blink::mojom::blink::ScrollAlignment blink_vertical_scroll_alignment = {
visible_vertical_behavior, vertical_behavior, vertical_behavior};
return private_->RequestScrollToMakeVisibleWithSubFocusAction(
- subfocus, blink_horizontal_scroll_alignment,
+ IntRect(subfocus), blink_horizontal_scroll_alignment,
blink_vertical_scroll_alignment);
}
-bool WebAXObject::ScrollToGlobalPoint(const gfx::Point& point) const {
- if (IsDetached())
- return false;
-
- ScopedActionAnnotator annotater(private_.Get());
- return private_->RequestScrollToGlobalPointAction(IntPoint(point));
-}
-
void WebAXObject::Swap(WebAXObject& other) {
if (IsDetached() || other.IsDetached())
return;
@@ -1436,9 +1264,6 @@ void WebAXObject::HandleAutofillStateChanged(
}
WebString WebAXObject::ToString(bool verbose) const {
- if (IsDetached())
- return WebString();
-
return private_->ToString(verbose);
}
@@ -1499,12 +1324,9 @@ WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) {
}
// static
-WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document,
- bool update_layout_if_necessary) {
- if (update_layout_if_necessary &&
- !MaybeUpdateLayoutAndCheckValidity(web_document)) {
+WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document) {
+ if (!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()))
@@ -1554,8 +1376,7 @@ bool WebAXObject::MaybeUpdateLayoutAndCheckValidity(
return false;
if (document->NeedsLayoutTreeUpdate() || document->View()->NeedsLayout() ||
- document->Lifecycle().GetState() <
- DocumentLifecycle::kCompositingAssignmentsClean) {
+ document->Lifecycle().GetState() < DocumentLifecycle::kPrePaintClean) {
// Note: this always alters the lifecycle, because
// RunAccessibilityLifecyclePhase() will be called.
if (!document->View()->UpdateAllLifecyclePhasesExceptPaint(
@@ -1571,4 +1392,20 @@ bool WebAXObject::MaybeUpdateLayoutAndCheckValidity(
return true;
}
+// static
+void WebAXObject::Freeze(const WebDocument& web_document) {
+ const Document* doc = web_document.ConstUnwrap<Document>();
+ auto* cache = To<AXObjectCacheImpl>(doc->ExistingAXObjectCache());
+ if (cache)
+ cache->Freeze();
+}
+
+// static
+void WebAXObject::Thaw(const WebDocument& web_document) {
+ const Document* doc = web_document.ConstUnwrap<Document>();
+ auto* cache = To<AXObjectCacheImpl>(doc->ExistingAXObjectCache());
+ if (cache)
+ cache->Thaw();
+}
+
} // 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 da9e4d57f17..ba6221fe3fe 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
@@ -214,9 +214,10 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
worker_start_data->script_url, worker_start_data->script_type,
global_scope_name, worker_start_data->user_agent,
worker_start_data->ua_metadata, std::move(web_worker_fetch_context),
- Vector<CSPHeaderAndType>(), network::mojom::ReferrerPolicy::kDefault,
- starter_origin.get(), starter_secure_context, starter_https_state,
- nullptr /* worker_clients */, std::move(content_settings_proxy),
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
+ network::mojom::ReferrerPolicy::kDefault, starter_origin.get(),
+ starter_secure_context, starter_https_state, nullptr /* worker_clients */,
+ std::move(content_settings_proxy),
base::nullopt /* response_address_space */,
nullptr /* OriginTrialTokens */, worker_start_data->devtools_worker_token,
std::move(worker_settings),
@@ -225,14 +226,14 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
nullptr /* worklet_module_respones_map */,
std::move(browser_interface_broker), BeginFrameProviderParams(),
nullptr /* parent_feature_policy */,
- base::UnguessableToken() /* agent_cluster_id */);
+ base::UnguessableToken() /* agent_cluster_id */,
+ worker_start_data->ukm_source_id);
worker_thread_ = std::make_unique<ServiceWorkerThread>(
std::make_unique<ServiceWorkerGlobalScopeProxy>(
*this, *worker_context_client_, initiator_thread_task_runner),
std::move(installed_scripts_manager), std::move(cache_storage_remote),
- initiator_thread_task_runner, worker_start_data->service_worker_token,
- worker_start_data->ukm_source_id);
+ initiator_thread_task_runner, worker_start_data->service_worker_token);
auto devtools_params = std::make_unique<WorkerDevToolsParams>();
devtools_params->devtools_worker_token =
@@ -267,7 +268,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
case mojom::blink::ScriptType::kClassic:
worker_thread_->FetchAndRunClassicScript(
worker_start_data->script_url,
- nullptr /* worker_main_script_load_params */,
+ std::move(worker_start_data->main_script_load_params),
std::move(fetch_client_setting_object_data),
nullptr /* outside_resource_timing_notifier */,
v8_inspector::V8StackTraceId());
@@ -279,7 +280,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
case mojom::blink::ScriptType::kModule:
worker_thread_->FetchAndRunModuleScript(
worker_start_data->script_url,
- nullptr /* worker_main_script_load_params */,
+ std::move(worker_start_data->main_script_load_params),
std::move(fetch_client_setting_object_data),
nullptr /* outside_resource_timing_notifier */,
network::mojom::CredentialsMode::kOmit);
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_testing_support.cc b/chromium/third_party/blink/renderer/modules/exported/web_testing_support.cc
index f31bd370969..b553315feef 100644
--- a/chromium/third_party/blink/renderer/modules/exported/web_testing_support.cc
+++ b/chromium/third_party/blink/renderer/modules/exported/web_testing_support.cc
@@ -25,7 +25,8 @@
#include "third_party/blink/public/web/web_testing_support.h"
-#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h"
#include "third_party/blink/renderer/core/testing/v8/web_core_test_support.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -108,9 +109,14 @@ void WebTestingSupport::InjectInternalsObject(v8::Local<v8::Context> context) {
web_core_test_support::InjectInternalsObject(context);
}
-void WebTestingSupport::ResetInternalsObject(WebLocalFrame* frame) {
+void WebTestingSupport::ResetMainFrame(WebLocalFrame* main_frame) {
+ auto* main_frame_impl = To<WebLocalFrameImpl>(main_frame);
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
- web_core_test_support::ResetInternalsObject(frame->MainWorldScriptContext());
+ web_core_test_support::ResetInternalsObject(
+ main_frame_impl->MainWorldScriptContext());
+ main_frame_impl->GetFrame()
+ ->GetWindowProxyManager()
+ ->ResetIsolatedWorldsForTesting();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/BUILD.gn b/chromium/third_party/blink/renderer/modules/eyedropper/BUILD.gn
new file mode 100644
index 00000000000..9d70bb3d6ae
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("eyedropper") {
+ sources = [
+ "color_select_event.cc",
+ "color_select_event.h",
+ "eye_dropper.cc",
+ "eye_dropper.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/OWNERS b/chromium/third_party/blink/renderer/modules/eyedropper/OWNERS
new file mode 100644
index 00000000000..8a8afda0acb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/OWNERS
@@ -0,0 +1 @@
+iopopesc@microsoft.com
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.cc b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.cc
new file mode 100644
index 00000000000..1e704812b09
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/eyedropper/color_select_event.h"
+
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h"
+
+namespace blink {
+
+ColorSelectEvent::ColorSelectEvent(const AtomicString& type,
+ const ColorSelectEventInit* initializer,
+ base::TimeTicks platform_time_stamp,
+ SyntheticEventType synthetic_event_type,
+ WebMenuSourceType menu_source_type)
+ : PointerEvent(type,
+ initializer,
+ platform_time_stamp,
+ synthetic_event_type,
+ menu_source_type),
+ value_(initializer->value()) {}
+
+ColorSelectEvent* ColorSelectEvent::Create(
+ const AtomicString& type,
+ const ColorSelectEventInit* initializer,
+ base::TimeTicks platform_time_stamp,
+ SyntheticEventType synthetic_event_type,
+ WebMenuSourceType menu_source_type) {
+ return MakeGarbageCollected<ColorSelectEvent>(
+ type, initializer, platform_time_stamp, synthetic_event_type,
+ menu_source_type);
+}
+
+String ColorSelectEvent::value() const {
+ return value_;
+}
+
+void ColorSelectEvent::Trace(Visitor* visitor) const {
+ PointerEvent::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.h b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.h
new file mode 100644
index 00000000000..3b09874450a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.h
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h"
+#include "third_party/blink/renderer/core/events/pointer_event.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class ColorSelectEvent final : public PointerEvent {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit ColorSelectEvent(const AtomicString& type,
+ const ColorSelectEventInit* initializer,
+ base::TimeTicks platform_time_stamp,
+ SyntheticEventType synthetic_event_type,
+ WebMenuSourceType menu_source_type);
+
+ static ColorSelectEvent* Create(
+ const AtomicString& type,
+ const ColorSelectEventInit* initializer,
+ base::TimeTicks platform_time_stamp = base::TimeTicks::Now(),
+ SyntheticEventType synthetic_event_type = kRealOrIndistinguishable,
+ WebMenuSourceType menu_source_type = kMenuSourceNone);
+
+ String value() const;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ String value_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.idl b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.idl
new file mode 100644
index 00000000000..97b2bfb845c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
+
+[Exposed=Window, RuntimeEnabled=EyeDropperAPI]
+interface ColorSelectEvent : PointerEvent {
+ constructor(DOMString type, optional ColorSelectEventInit eventInitDict = {});
+
+ readonly attribute DOMString value;
+};
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl
new file mode 100644
index 00000000000..0285a737641
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
+
+dictionary ColorSelectEventInit : PointerEventInit {
+ DOMString value = "";
+};
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
new file mode 100644
index 00000000000..615ae23a1b2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/eyedropper/eye_dropper.h"
+
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+
+namespace blink {
+
+EyeDropper::EyeDropper(ScriptState* script_state)
+ : ExecutionContextClient(ExecutionContext::From(script_state)),
+ opened_(false) {}
+
+EyeDropper* EyeDropper::Create(ScriptState* script_state) {
+ return MakeGarbageCollected<EyeDropper>(script_state);
+}
+
+ExecutionContext* EyeDropper::GetExecutionContext() const {
+ return ExecutionContextClient::GetExecutionContext();
+}
+
+const AtomicString& EyeDropper::InterfaceName() const {
+ return event_target_names::kEyeDropper;
+}
+
+EyeDropper::~EyeDropper() = default;
+
+bool EyeDropper::opened() const {
+ return opened_;
+}
+
+ScriptPromise EyeDropper::open() {
+ // TODO(iopopesc): Add support for open.
+ return ScriptPromise();
+}
+
+void EyeDropper::close() {
+ // TODO(iopopesc): Add support for close.
+}
+
+void EyeDropper::Trace(Visitor* visitor) const {
+ EventTargetWithInlineData::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.h b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
new file mode 100644
index 00000000000..e131a0b217b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
@@ -0,0 +1,59 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_EYE_DROPPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_EYE_DROPPER_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+// The EyeDropper API enables developers to use a browser-supplied eyedropper
+// in their web applications. This feature is still
+// under development, and is not part of the standard. It can be enabled
+// by passing --enable-blink-features=EyeDropperAPI. See
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
+// for more details.
+class EyeDropper final : public EventTargetWithInlineData,
+ public ExecutionContextClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit EyeDropper(ScriptState*);
+ static EyeDropper* Create(ScriptState*);
+ EyeDropper(const EyeDropper&) = delete;
+ EyeDropper& operator=(const EyeDropper&) = delete;
+ ~EyeDropper() override;
+
+ // EventTarget:
+ ExecutionContext* GetExecutionContext() const override;
+ const AtomicString& InterfaceName() const override;
+
+ // Opens the eyedropper and replaces the cursor with a browser-defined preview
+ // and sets opened boolean to true.
+ ScriptPromise open();
+
+ // Exits the eyedropper mode and the cursor returns to its regular
+ // functionality. Sets opened boolean to false.
+ void close();
+
+ // States if the eyedropper is opened and in use.
+ bool opened() const;
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(colorselect, kColorselect)
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(close, kClose)
+
+ void Trace(Visitor*) const override;
+
+ private:
+ bool opened_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_EYE_DROPPER_H_
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl
new file mode 100644
index 00000000000..75278162d47
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
+
+[Exposed=Window, RuntimeEnabled=EyeDropperAPI]
+interface EyeDropper : EventTarget {
+ [CallWith=ScriptState] constructor();
+
+ Promise<void> open();
+ void close();
+
+ readonly attribute boolean opened;
+
+ // Event handler attributes
+ attribute EventHandler oncolorselect;
+ attribute EventHandler onclose;
+};
diff --git a/chromium/third_party/blink/renderer/modules/eyedropper/idls.gni b/chromium/third_party/blink/renderer/modules/eyedropper/idls.gni
new file mode 100644
index 00000000000..96c64c9aeea
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/eyedropper/idls.gni
@@ -0,0 +1,10 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+modules_idl_files = [
+ "color_select_event.idl",
+ "eye_dropper.idl",
+]
+
+modules_dictionary_idl_files = [ "color_select_event_init.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn b/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn
index 38f13af4bea..6727d5dd0cd 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn
@@ -6,26 +6,26 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("file_system_access") {
sources = [
- "data_transfer_item_native_file_system.cc",
- "data_transfer_item_native_file_system.h",
- "global_native_file_system.cc",
- "global_native_file_system.h",
- "native_file_system_directory_handle.cc",
- "native_file_system_directory_handle.h",
- "native_file_system_directory_iterator.cc",
- "native_file_system_directory_iterator.h",
- "native_file_system_error.cc",
- "native_file_system_error.h",
- "native_file_system_file_handle.cc",
- "native_file_system_file_handle.h",
- "native_file_system_handle.cc",
- "native_file_system_handle.h",
- "native_file_system_underlying_sink.cc",
- "native_file_system_underlying_sink.h",
- "native_file_system_writable_file_stream.cc",
- "native_file_system_writable_file_stream.h",
- "storage_manager_native_file_system.cc",
- "storage_manager_native_file_system.h",
+ "data_transfer_item_file_system_access.cc",
+ "data_transfer_item_file_system_access.h",
+ "file_system_access_error.cc",
+ "file_system_access_error.h",
+ "file_system_directory_handle.cc",
+ "file_system_directory_handle.h",
+ "file_system_directory_iterator.cc",
+ "file_system_directory_iterator.h",
+ "file_system_file_handle.cc",
+ "file_system_file_handle.h",
+ "file_system_handle.cc",
+ "file_system_handle.h",
+ "file_system_underlying_sink.cc",
+ "file_system_underlying_sink.h",
+ "file_system_writable_file_stream.cc",
+ "file_system_writable_file_stream.h",
+ "global_file_system_access.cc",
+ "global_file_system_access.h",
+ "storage_manager_file_system_access.cc",
+ "storage_manager_file_system_access.h",
]
deps = [ "//third_party/blink/renderer/platform" ]
@@ -33,7 +33,7 @@ blink_modules_sources("file_system_access") {
source_set("unit_tests") {
testonly = true
- sources = [ "global_native_file_system_test.cc" ]
+ sources = [ "global_file_system_access_test.cc" ]
configs += [
"//third_party/blink/renderer:config",
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/DIR_METADATA b/chromium/third_party/blink/renderer/modules/file_system_access/DIR_METADATA
new file mode 100644
index 00000000000..9f7250ac158
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>FileSystem"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS b/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS
index 427d68bda9b..44b66138137 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS
@@ -1,4 +1 @@
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/file_system_access/data_transfer_item_file_system_access.cc b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc
new file mode 100644
index 00000000000..48b630de971
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc
@@ -0,0 +1,83 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.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/file_system_access/file_system_access_data_transfer_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/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"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+// static
+ScriptPromise DataTransferItemFileSystemAccess::getAsFileSystemHandle(
+ ScriptState* script_state,
+ DataTransferItem& data_transfer_item) {
+ if (!data_transfer_item.GetDataTransfer()->CanReadData()) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ // If the DataObjectItem doesn't have an associated FileSystemAccessEntry,
+ // return nullptr.
+ if (!data_transfer_item.GetDataObjectItem()->HasFileSystemAccessEntry()) {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ mojo::Remote<mojom::blink::FileSystemAccessManager> nfs_manager;
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ execution_context->GetBrowserInterfaceBroker().GetInterface(
+ nfs_manager.BindNewPipeAndPassReceiver());
+
+ const DataObjectItem& data_object_item =
+ *data_transfer_item.GetDataObjectItem();
+
+ // Since tokens are move-only, we need to create a clone in order
+ // to preserve the state of `data_object_item` for future calls.
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDataTransferToken>
+ token_remote = data_object_item.CloneFileSystemAccessEntryToken();
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ // We need to move `nfs_manager` into GetEntryFromDataTransferToken in order
+ // to keep it in scope long enough for the callback to be executed. To do this
+ // we extract `raw_nfs_manager` from `nfs_manager` and move `nfs_manager` into
+ // the GetEntryFromDataTransferToken callback.
+ auto* raw_nfs_manager = nfs_manager.get();
+ raw_nfs_manager->GetEntryFromDataTransferToken(
+ std::move(token_remote),
+ WTF::Bind(
+ [](mojo::Remote<mojom::blink::FileSystemAccessManager>,
+ ScriptPromiseResolver* resolver,
+ mojom::blink::FileSystemAccessEntryPtr entry) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state)
+ return;
+ resolver->Resolve(FileSystemHandle::CreateFromMojoEntry(
+ std::move(entry), ExecutionContext::From(script_state)));
+ },
+ std::move(nfs_manager), WrapPersistent(resolver)));
+
+ return result;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.h b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.h
new file mode 100644
index 00000000000..6db90140415
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_FILE_SYSTEM_ACCESS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_FILE_SYSTEM_ACCESS_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/file_system_access/file_system_handle.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+namespace blink {
+
+class DataTransferItemFileSystemAccess {
+ STATIC_ONLY(DataTransferItemFileSystemAccess);
+
+ public:
+ static ScriptPromise getAsFileSystemHandle(ScriptState*, DataTransferItem&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_FILE_SYSTEM_ACCESS_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl
new file mode 100644
index 00000000000..867af6cb0a3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl
@@ -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.
+
+// https://wicg.github.io/file-system-access/#drag-and-drop
+[
+ ImplementedAs=DataTransferItemFileSystemAccess,
+ RuntimeEnabled=FileSystemAccess
+] partial interface DataTransferItem {
+ [CallWith=ScriptState, MeasureAs=FileSystemAccessDragAndDrop]
+ Promise<FileSystemHandle?> getAsFileSystemHandle();
+};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc
deleted file mode 100644
index f897c3d15d0..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc
+++ /dev/null
@@ -1,83 +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/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/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/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"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-// static
-ScriptPromise DataTransferItemNativeFileSystem::getAsFileSystemHandle(
- ScriptState* script_state,
- DataTransferItem& data_transfer_item) {
- if (!data_transfer_item.GetDataTransfer()->CanReadData()) {
- return ScriptPromise::CastUndefined(script_state);
- }
-
- // If the DataObjectItem doesn't have an associated NativeFileSystemEntry,
- // return nullptr.
- if (!data_transfer_item.GetDataObjectItem()->HasNativeFileSystemEntry()) {
- return ScriptPromise::CastUndefined(script_state);
- }
-
- mojo::Remote<mojom::blink::NativeFileSystemManager> nfs_manager;
- ExecutionContext* execution_context = ExecutionContext::From(script_state);
- execution_context->GetBrowserInterfaceBroker().GetInterface(
- nfs_manager.BindNewPipeAndPassReceiver());
-
- const DataObjectItem& data_object_item =
- *data_transfer_item.GetDataObjectItem();
-
- // Since tokens are move-only, we need to create a clone in order
- // to preserve the state of `data_object_item` for future calls.
- mojo::PendingRemote<mojom::blink::NativeFileSystemDragDropToken>
- token_remote = data_object_item.CloneNativeFileSystemEntryToken();
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- // We need to move `nfs_manager` into GetEntryFromDragDropToken in order
- // to keep it in scope long enough for the callback to be executed. To do this
- // we extract `raw_nfs_manager` from `nfs_manager` and move `nfs_manager` into
- // the GetEntryFromDragDropToken callback.
- auto* raw_nfs_manager = nfs_manager.get();
- raw_nfs_manager->GetEntryFromDragDropToken(
- std::move(token_remote),
- WTF::Bind(
- [](mojo::Remote<mojom::blink::NativeFileSystemManager>,
- ScriptPromiseResolver* resolver,
- mojom::blink::NativeFileSystemEntryPtr entry) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state)
- return;
- resolver->Resolve(NativeFileSystemHandle::CreateFromMojoEntry(
- std::move(entry), ExecutionContext::From(script_state)));
- },
- std::move(nfs_manager), WrapPersistent(resolver)));
-
- return result;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h
deleted file mode 100644
index e917182897a..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h
+++ /dev/null
@@ -1,24 +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_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/file_system_access/native_file_system_handle.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-
-namespace blink {
-
-class DataTransferItemNativeFileSystem {
- STATIC_ONLY(DataTransferItemNativeFileSystem);
-
- public:
- static ScriptPromise getAsFileSystemHandle(ScriptState*, DataTransferItem&);
-};
-
-} // namespace blink
-
-#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/file_system_access/data_transfer_item_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl
deleted file mode 100644
index 48a9f1d7376..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl
+++ /dev/null
@@ -1,10 +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.
-
-[
- ImplementedAs=DataTransferItemNativeFileSystem,
- RuntimeEnabled=NativeFileSystem
-] partial interface DataTransferItem {
- [CallWith=ScriptState, MeasureAs=NativeFileSystemDragAndDrop] Promise<FileSystemHandle?> getAsFileSystemHandle();
-};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl
index 3ebc626cee2..87d4c4be618 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl
@@ -2,6 +2,8 @@
// 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/#dictdef-directorypickeroptions
+// https://wicg.github.io/file-system-access/#dictdef-directorypickeroptions
dictionary DirectoryPickerOptions {
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] USVString id;
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] (WellKnownDirectory or FileSystemHandle)? startIn;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl
index dc3f82282b7..9dfee44b4bf 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.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://wicg.github.io/native-file-system/#dictdef-filepickeraccepttype
+// https://wicg.github.io/file-system-access/#dictdef-filepickeraccepttype
dictionary FilePickerAcceptType {
USVString description;
record<USVString, (USVString or sequence<USVString>)> accept;
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl
index 7bb6d45d657..37ab8a5941e 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl
@@ -2,8 +2,19 @@
// 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/#dictdef-filepickeroptions
+enum WellKnownDirectory {
+ "desktop",
+ "documents",
+ "downloads",
+ "music",
+ "pictures",
+ "videos",
+};
+
+// https://wicg.github.io/file-system-access/#dictdef-filepickeroptions
dictionary FilePickerOptions {
sequence<FilePickerAcceptType> types;
boolean excludeAcceptAllOption = false;
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] USVString id;
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] (WellKnownDirectory or FileSystemHandle)? startIn;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.cc
new file mode 100644
index 00000000000..541a2355f49
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.cc
@@ -0,0 +1,69 @@
+// 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/file_system_access/file_system_access_error.h"
+
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/core/fileapi/file_error.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+
+namespace blink {
+namespace file_system_access_error {
+
+void Reject(ScriptPromiseResolver* resolver,
+ const mojom::blink::FileSystemAccessError& error) {
+ DCHECK_NE(error.status, mojom::blink::FileSystemAccessStatus::kOk);
+ ResolveOrReject(resolver, error);
+}
+
+void ResolveOrReject(ScriptPromiseResolver* resolver,
+ const mojom::blink::FileSystemAccessError& error) {
+ // Early exit if the resolver's context has been destroyed already.
+ if (!resolver->GetScriptState()->ContextIsValid())
+ return;
+ auto* const isolate = resolver->GetScriptState()->GetIsolate();
+ ScriptState::Scope scope(resolver->GetScriptState());
+
+ // Convert empty message to a null string, to make sure we get the default
+ // error message if no custom error message is provided.
+ const String message = error.message.IsEmpty() ? String() : error.message;
+
+ switch (error.status) {
+ case mojom::blink::FileSystemAccessStatus::kOk:
+ resolver->Resolve();
+ break;
+ case mojom::blink::FileSystemAccessStatus::kPermissionDenied:
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kNotAllowedError, message));
+ break;
+ case mojom::blink::FileSystemAccessStatus::kSecurityError:
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kSecurityError, message));
+ break;
+ case mojom::blink::FileSystemAccessStatus::kInvalidState:
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kInvalidStateError, message));
+ break;
+ case mojom::blink::FileSystemAccessStatus::kInvalidArgument:
+ resolver->Reject(V8ThrowException::CreateTypeError(
+ resolver->GetScriptState()->GetIsolate(), message));
+ break;
+ case mojom::blink::FileSystemAccessStatus::kOperationFailed:
+ case mojom::blink::FileSystemAccessStatus::kOperationAborted:
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kAbortError, message));
+ break;
+ case mojom::blink::FileSystemAccessStatus::kFileError:
+ // TODO(mek): We might want to support custom messages for these cases.
+ resolver->Reject(file_error::CreateDOMException(error.file_error));
+ break;
+ }
+}
+
+} // namespace file_system_access_error
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.h
new file mode 100644
index 00000000000..5165fee2fdf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_access_error.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_ERROR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_ERROR_H_
+
+#include "base/files/file.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink-forward.h"
+
+namespace blink {
+class ScriptPromiseResolver;
+namespace file_system_access_error {
+
+// Rejects |resolver| with an appropriate exception if |status| represents an
+// error. Resolves |resolver| with undefined otherwise.
+void ResolveOrReject(ScriptPromiseResolver* resolver,
+ const mojom::blink::FileSystemAccessError& status);
+
+// Rejects |resolver| with an appropriate exception if |status| represents an
+// error. DCHECKs otherwise.
+void Reject(ScriptPromiseResolver* resolver,
+ const mojom::blink::FileSystemAccessError& error);
+
+} // namespace file_system_access_error
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_ERROR_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writable_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writable_options.idl
new file mode 100644
index 00000000000..d3ab371d6e5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writable_options.idl
@@ -0,0 +1,9 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/file-system-access/#dictdef-filesystemcreatewritableoptions
+dictionary FileSystemCreateWritableOptions {
+ boolean keepExistingData = false;
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] boolean autoClose = false;
+};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl
deleted file mode 100644
index df0834cd8b0..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl
+++ /dev/null
@@ -1,8 +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.
-
-// https://wicg.github.io/native-file-system/#dictdef-filesystemcreatewriteroptions
-dictionary FileSystemCreateWriterOptions {
- boolean keepExistingData = false;
-};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
new file mode 100644
index 00000000000..571df5247cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
@@ -0,0 +1,270 @@
+// 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/file_system_access/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/file_system_access/file_system_access_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_get_directory_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_get_file_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_remove_options.h"
+#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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h"
+#include "third_party/blink/renderer/modules/file_system_access/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 {
+
+using mojom::blink::FileSystemAccessErrorPtr;
+
+FileSystemDirectoryHandle::FileSystemDirectoryHandle(
+ ExecutionContext* context,
+ const String& name,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDirectoryHandle> mojo_ptr)
+ : FileSystemHandle(context, name), mojo_ptr_(context) {
+ mojo_ptr_.Bind(std::move(mojo_ptr),
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI));
+ DCHECK(mojo_ptr_.is_bound());
+}
+
+FileSystemDirectoryIterator* FileSystemDirectoryHandle::entries() {
+ return MakeGarbageCollected<FileSystemDirectoryIterator>(
+ this, FileSystemDirectoryIterator::Mode::kKeyValue,
+ GetExecutionContext());
+}
+
+FileSystemDirectoryIterator* FileSystemDirectoryHandle::keys() {
+ return MakeGarbageCollected<FileSystemDirectoryIterator>(
+ this, FileSystemDirectoryIterator::Mode::kKey, GetExecutionContext());
+}
+
+FileSystemDirectoryIterator* FileSystemDirectoryHandle::values() {
+ return MakeGarbageCollected<FileSystemDirectoryIterator>(
+ this, FileSystemDirectoryIterator::Mode::kValue, GetExecutionContext());
+}
+
+ScriptPromise FileSystemDirectoryHandle::getFileHandle(
+ ScriptState* script_state,
+ const String& name,
+ const FileSystemGetFileOptions* options) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ mojo_ptr_->GetFile(
+ name, options->create(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, const String& name,
+ FileSystemAccessErrorPtr result,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileHandle>
+ handle) {
+ ExecutionContext* context = resolver->GetExecutionContext();
+ if (!context)
+ return;
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(MakeGarbageCollected<FileSystemFileHandle>(
+ context, name, std::move(handle)));
+ },
+ WrapPersistent(resolver), name));
+
+ return result;
+}
+
+ScriptPromise FileSystemDirectoryHandle::getDirectoryHandle(
+ ScriptState* script_state,
+ const String& name,
+ const FileSystemGetDirectoryOptions* options) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ if (!mojo_ptr_.is_bound()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError));
+ return result;
+ }
+
+ mojo_ptr_->GetDirectory(
+ name, options->create(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, const String& name,
+ FileSystemAccessErrorPtr result,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDirectoryHandle>
+ handle) {
+ ExecutionContext* context = resolver->GetExecutionContext();
+ if (!context)
+ return;
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(MakeGarbageCollected<FileSystemDirectoryHandle>(
+ context, name, std::move(handle)));
+ },
+ WrapPersistent(resolver), name));
+
+ return result;
+}
+
+namespace {
+
+void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ V8SetReturnValue(info, info.Data());
+}
+
+} // namespace
+
+ScriptValue FileSystemDirectoryHandle::getEntries(ScriptState* script_state) {
+ auto* iterator = MakeGarbageCollected<FileSystemDirectoryIterator>(
+ this, FileSystemDirectoryIterator::Mode::kValue,
+ ExecutionContext::From(script_state));
+ auto* isolate = script_state->GetIsolate();
+ auto context = script_state->GetContext();
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
+ if (!result
+ ->Set(context, v8::Symbol::GetAsyncIterator(isolate),
+ v8::Function::New(context, &ReturnDataFunction,
+ ToV8(iterator, script_state))
+ .ToLocalChecked())
+ .ToChecked()) {
+ return ScriptValue();
+ }
+ return ScriptValue(script_state->GetIsolate(), result);
+}
+
+ScriptPromise FileSystemDirectoryHandle::removeEntry(
+ ScriptState* script_state,
+ const String& name,
+ const FileSystemRemoveOptions* options) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ if (!mojo_ptr_.is_bound()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError));
+ return result;
+ }
+
+ mojo_ptr_->RemoveEntry(
+ name, options->recursive(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, FileSystemAccessErrorPtr result) {
+ file_system_access_error::ResolveOrReject(resolver, *result);
+ },
+ WrapPersistent(resolver)));
+
+ return result;
+}
+
+ScriptPromise FileSystemDirectoryHandle::resolve(
+ ScriptState* script_state,
+ FileSystemHandle* possible_child) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ if (!mojo_ptr_.is_bound()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError));
+ return result;
+ }
+
+ mojo_ptr_->Resolve(
+ possible_child->Transfer(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, FileSystemAccessErrorPtr result,
+ const base::Optional<Vector<String>>& path) {
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ if (!path.has_value()) {
+ resolver->Resolve(static_cast<ScriptWrappable*>(nullptr));
+ return;
+ }
+ resolver->Resolve(*path);
+ },
+ WrapPersistent(resolver)));
+
+ return result;
+}
+
+mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>
+FileSystemDirectoryHandle::Transfer() {
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> result;
+ if (mojo_ptr_.is_bound())
+ mojo_ptr_->Transfer(result.InitWithNewPipeAndPassReceiver());
+ return result;
+}
+
+void FileSystemDirectoryHandle::Trace(Visitor* visitor) const {
+ visitor->Trace(mojo_ptr_);
+ FileSystemHandle::Trace(visitor);
+}
+
+void FileSystemDirectoryHandle::QueryPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
+ return;
+ }
+ mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
+}
+
+void FileSystemDirectoryHandle::RequestPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ mojom::blink::PermissionStatus)> callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(
+ mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kInvalidState,
+ base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
+ mojom::blink::PermissionStatus::DENIED);
+ return;
+ }
+
+ mojo_ptr_->RequestPermission(writable, std::move(callback));
+}
+
+void FileSystemDirectoryHandle::IsSameEntryImpl(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> other,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr, bool)>
+ callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(
+ mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kInvalidState,
+ base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
+ false);
+ return;
+ }
+
+ mojo_ptr_->Resolve(
+ std::move(other),
+ WTF::Bind(
+ [](base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ bool)> callback,
+ FileSystemAccessErrorPtr result,
+ const base::Optional<Vector<String>>& path) {
+ std::move(callback).Run(std::move(result),
+ path.has_value() && path->IsEmpty());
+ },
+ std::move(callback)));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
new file mode 100644
index 00000000000..0ade0d772fe
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
@@ -0,0 +1,77 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_HANDLE_H_
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+
+namespace blink {
+class FileSystemGetDirectoryOptions;
+class FileSystemGetFileOptions;
+class FileSystemRemoveOptions;
+class FileSystemDirectoryIterator;
+
+class FileSystemDirectoryHandle final : public FileSystemHandle {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ FileSystemDirectoryHandle(
+ ExecutionContext* context,
+ const String& name,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDirectoryHandle>);
+
+ // FileSystemDirectoryHandle IDL interface:
+ FileSystemDirectoryIterator* entries();
+ FileSystemDirectoryIterator* keys();
+ FileSystemDirectoryIterator* values();
+
+ bool isDirectory() const override { return true; }
+
+ ScriptPromise getFileHandle(ScriptState*,
+ const String& name,
+ const FileSystemGetFileOptions*);
+ ScriptPromise getDirectoryHandle(ScriptState*,
+ const String& name,
+ const FileSystemGetDirectoryOptions*);
+ ScriptValue getEntries(ScriptState*);
+ ScriptPromise removeEntry(ScriptState*,
+ const String& name,
+ const FileSystemRemoveOptions*);
+
+ ScriptPromise resolve(ScriptState*, FileSystemHandle* possible_child);
+
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> Transfer()
+ override;
+
+ mojom::blink::FileSystemAccessDirectoryHandle* MojoHandle() {
+ return mojo_ptr_.get();
+ }
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void QueryPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
+ void RequestPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ mojom::blink::PermissionStatus)>) override;
+ // IsSameEntry for directories is implemented in terms of resolve, as resolve
+ // also can be used to figure out if two directories are the same entry.
+ void IsSameEntryImpl(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> other,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr, bool)>)
+ override;
+
+ HeapMojoRemote<mojom::blink::FileSystemAccessDirectoryHandle> mojo_ptr_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl
index c63eac8c403..bf181569941 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl
@@ -2,21 +2,20 @@
// 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/#filesystemdirectoryhandle
+// https://wicg.github.io/file-system-access/#filesystemdirectoryhandle
[
Exposed=(Window,Worker),
SecureContext,
Serializable,
- RuntimeEnabled=NativeFileSystem,
- ImplementedAs=NativeFileSystemDirectoryHandle
+ RuntimeEnabled=FileSystemAccess
] interface FileSystemDirectoryHandle : FileSystemHandle {
// TODO(https://crbug.com/1087157): This interface defines an async
// iterable, however that isn't supported yet by the bindings. So for now
// just explicitly define what an async iterable definition implies.
//async iterable<USVString, FileSystemHandle>;
- NativeFileSystemDirectoryIterator entries();
- NativeFileSystemDirectoryIterator keys();
- NativeFileSystemDirectoryIterator values();
+ FileSystemDirectoryIterator entries();
+ FileSystemDirectoryIterator keys();
+ FileSystemDirectoryIterator values();
[CallWith=ScriptState] Promise<FileSystemFileHandle> getFileHandle(USVString name, optional FileSystemGetFileOptions options = {});
[CallWith=ScriptState] Promise<FileSystemDirectoryHandle> getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.cc
new file mode 100644
index 00000000000..69d89705892
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.cc
@@ -0,0 +1,110 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/file_system_access/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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+FileSystemDirectoryIterator::FileSystemDirectoryIterator(
+ FileSystemDirectoryHandle* directory,
+ Mode mode,
+ ExecutionContext* execution_context)
+ : ExecutionContextClient(execution_context),
+ mode_(mode),
+ directory_(directory),
+ receiver_(this, execution_context) {
+ directory_->MojoHandle()->GetEntries(receiver_.BindNewPipeAndPassRemote(
+ execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+}
+
+ScriptPromise FileSystemDirectoryIterator::next(ScriptState* script_state) {
+ if (error_) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto result = resolver->Promise();
+ file_system_access_error::Reject(resolver, *error_);
+ return result;
+ }
+
+ if (!entries_.IsEmpty()) {
+ FileSystemHandle* handle = entries_.TakeFirst();
+ ScriptValue result;
+ switch (mode_) {
+ case Mode::kKey:
+ result = V8IteratorResult(script_state, handle->name());
+ break;
+ case Mode::kValue:
+ result = V8IteratorResult(script_state, handle);
+ break;
+ case Mode::kKeyValue:
+ HeapVector<ScriptValue, 2> keyvalue;
+ keyvalue.push_back(ScriptValue(script_state->GetIsolate(),
+ ToV8(handle->name(), script_state)));
+ keyvalue.push_back(ScriptValue(script_state->GetIsolate(),
+ ToV8(handle, script_state)));
+ result = V8IteratorResult(script_state, keyvalue);
+ break;
+ }
+ return ScriptPromise::Cast(script_state, result);
+ }
+
+ if (waiting_for_more_entries_) {
+ DCHECK(!pending_next_);
+ pending_next_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ return pending_next_->Promise();
+ }
+
+ return ScriptPromise::Cast(script_state, V8IteratorResultDone(script_state));
+}
+
+bool FileSystemDirectoryIterator::HasPendingActivity() const {
+ return pending_next_;
+}
+
+void FileSystemDirectoryIterator::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+ visitor->Trace(receiver_);
+ visitor->Trace(entries_);
+ visitor->Trace(pending_next_);
+ visitor->Trace(directory_);
+}
+
+void FileSystemDirectoryIterator::DidReadDirectory(
+ mojom::blink::FileSystemAccessErrorPtr result,
+ Vector<mojom::blink::FileSystemAccessEntryPtr> entries,
+ bool has_more_entries) {
+ if (!GetExecutionContext())
+ return;
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ error_ = std::move(result);
+ if (pending_next_) {
+ file_system_access_error::Reject(pending_next_, *error_);
+ pending_next_ = nullptr;
+ }
+ return;
+ }
+ for (auto& e : entries) {
+ entries_.push_back(FileSystemHandle::CreateFromMojoEntry(
+ std::move(e), GetExecutionContext()));
+ }
+ waiting_for_more_entries_ = has_more_entries;
+ if (pending_next_) {
+ ScriptState::Scope scope(pending_next_->GetScriptState());
+ pending_next_->Resolve(
+ next(pending_next_->GetScriptState()).AsScriptValue());
+ pending_next_ = nullptr;
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h
new file mode 100644
index 00000000000..c1dca830f9c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.h
@@ -0,0 +1,65 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
+
+#include "base/files/file.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+
+namespace blink {
+class FileSystemDirectoryHandle;
+class FileSystemHandle;
+class ScriptPromise;
+class ScriptPromiseResolver;
+class ScriptState;
+
+class FileSystemDirectoryIterator final
+ : public ScriptWrappable,
+ public ActiveScriptWrappable<FileSystemDirectoryIterator>,
+ public ExecutionContextClient,
+ public mojom::blink::FileSystemAccessDirectoryEntriesListener {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ // Should this iterator returns keys, values or both?
+ enum Mode { kKey, kValue, kKeyValue };
+
+ FileSystemDirectoryIterator(FileSystemDirectoryHandle* directory,
+ Mode mode,
+ ExecutionContext* execution_context);
+
+ ScriptPromise next(ScriptState*);
+
+ // ScriptWrappable:
+ bool HasPendingActivity() const final;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void DidReadDirectory(mojom::blink::FileSystemAccessErrorPtr result,
+ Vector<mojom::blink::FileSystemAccessEntryPtr> entries,
+ bool has_more_entries) override;
+
+ Mode mode_;
+ mojom::blink::FileSystemAccessErrorPtr error_;
+ bool waiting_for_more_entries_ = true;
+ HeapDeque<Member<FileSystemHandle>> entries_;
+ Member<ScriptPromiseResolver> pending_next_;
+ Member<FileSystemDirectoryHandle> directory_;
+ HeapMojoReceiver<mojom::blink::FileSystemAccessDirectoryEntriesListener,
+ FileSystemDirectoryIterator,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ receiver_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.idl
new file mode 100644
index 00000000000..b9169b2f654
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_iterator.idl
@@ -0,0 +1,14 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Async iterator returned by FileSystemDirectoryHandle.getEntries().
+// https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle-asynciterable
+// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface
+[
+ LegacyNoInterfaceObject,
+ ActiveScriptWrappable,
+ RuntimeEnabled=FileSystemAccess
+] interface FileSystemDirectoryIterator {
+ [CallWith=ScriptState] Promise<any> next();
+};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
new file mode 100644
index 00000000000..0308f9053c2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
@@ -0,0 +1,151 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h"
+
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_writer.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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_writable_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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/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"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+using mojom::blink::FileSystemAccessErrorPtr;
+
+FileSystemFileHandle::FileSystemFileHandle(
+ ExecutionContext* context,
+ const String& name,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileHandle> mojo_ptr)
+ : FileSystemHandle(context, name), mojo_ptr_(context) {
+ mojo_ptr_.Bind(std::move(mojo_ptr),
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI));
+ DCHECK(mojo_ptr_.is_bound());
+}
+
+ScriptPromise FileSystemFileHandle::createWritable(
+ ScriptState* script_state,
+ const FileSystemCreateWritableOptions* options,
+ ExceptionState& exception_state) {
+ if (!mojo_ptr_.is_bound()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "");
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ mojo_ptr_->CreateFileWriter(
+ options->keepExistingData(), options->autoClose(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver,
+ mojom::blink::FileSystemAccessErrorPtr result,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileWriter>
+ writer) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state)
+ return;
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+
+ resolver->Resolve(FileSystemWritableFileStream::Create(
+ script_state, std::move(writer)));
+ },
+ WrapPersistent(resolver)));
+
+ return result;
+}
+
+ScriptPromise FileSystemFileHandle::getFile(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (!mojo_ptr_.is_bound()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "");
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ mojo_ptr_->AsBlob(WTF::Bind(
+ [](ScriptPromiseResolver* resolver, const String& name,
+ FileSystemAccessErrorPtr result, const base::File::Info& info,
+ const scoped_refptr<BlobDataHandle>& blob) {
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(MakeGarbageCollected<File>(
+ name, NullableTimeToOptionalTime(info.last_modified), blob));
+ },
+ WrapPersistent(resolver), name()));
+
+ return result;
+}
+
+mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>
+FileSystemFileHandle::Transfer() {
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> result;
+ if (mojo_ptr_.is_bound())
+ mojo_ptr_->Transfer(result.InitWithNewPipeAndPassReceiver());
+ return result;
+}
+
+void FileSystemFileHandle::Trace(Visitor* visitor) const {
+ visitor->Trace(mojo_ptr_);
+ FileSystemHandle::Trace(visitor);
+}
+
+void FileSystemFileHandle::QueryPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
+ return;
+ }
+ mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
+}
+
+void FileSystemFileHandle::RequestPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ mojom::blink::PermissionStatus)> callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(
+ mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kInvalidState,
+ base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
+ mojom::blink::PermissionStatus::DENIED);
+ return;
+ }
+
+ mojo_ptr_->RequestPermission(writable, std::move(callback));
+}
+
+void FileSystemFileHandle::IsSameEntryImpl(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> other,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr, bool)>
+ callback) {
+ if (!mojo_ptr_.is_bound()) {
+ std::move(callback).Run(
+ mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kInvalidState,
+ base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
+ false);
+ return;
+ }
+
+ mojo_ptr_->IsSameEntry(std::move(other), std::move(callback));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
new file mode 100644
index 00000000000..1c46d619a0f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
@@ -0,0 +1,59 @@
+// 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_FILE_SYSTEM_ACCESS_FILE_SYSTEM_FILE_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_FILE_HANDLE_H_
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+
+namespace blink {
+class FileSystemCreateWritableOptions;
+
+class FileSystemFileHandle final : public FileSystemHandle {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ FileSystemFileHandle(
+ ExecutionContext* context,
+ const String& name,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileHandle>);
+
+ bool isFile() const override { return true; }
+
+ ScriptPromise createWritable(ScriptState*,
+ const FileSystemCreateWritableOptions* options,
+ ExceptionState&);
+ ScriptPromise getFile(ScriptState*, ExceptionState&);
+
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> Transfer()
+ override;
+
+ mojom::blink::FileSystemAccessFileHandle* MojoHandle() {
+ return mojo_ptr_.get();
+ }
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void QueryPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
+ void RequestPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ mojom::blink::PermissionStatus)>) override;
+ void IsSameEntryImpl(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> other,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr, bool)>)
+ override;
+
+ HeapMojoRemote<mojom::blink::FileSystemAccessFileHandle> mojo_ptr_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_FILE_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
index b24362e53ef..f8c4cf50bdc 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
@@ -2,14 +2,15 @@
// 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/#filesystemfilehandle
+// https://wicg.github.io/file-system-access/#filesystemfilehandle
[
Exposed=(Window,Worker),
SecureContext,
Serializable,
- RuntimeEnabled=NativeFileSystem,
- ImplementedAs=NativeFileSystemFileHandle
+ RuntimeEnabled=FileSystemAccess
] interface FileSystemFileHandle : FileSystemHandle {
- [CallWith=ScriptState, RaisesException] Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWriterOptions options = {});
+ [CallWith=ScriptState, RaisesException]
+ Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
+
[CallWith=ScriptState, RaisesException] Promise<File> getFile();
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl
index 529b8dd2e8f..8c45a7f2112 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/native-file-system/#dictdef-filesystemgetdirectoryoptions
+// https://wicg.github.io/file-system-access/#dictdef-filesystemgetdirectoryoptions
dictionary FileSystemGetDirectoryOptions {
boolean create = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl
index 57c5a7d0043..ad7d5a5181a 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/native-file-system/#dictdef-filesystemgetfileoptions
+// https://wicg.github.io/file-system-access/#dictdef-filesystemgetfileoptions
dictionary FileSystemGetFileOptions {
boolean create = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
new file mode 100644
index 00000000000..6ad38845f22
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
@@ -0,0 +1,119 @@
+// 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/file_system_access/file_system_handle.h"
+
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+using mojom::blink::FileSystemAccessEntryPtr;
+using mojom::blink::FileSystemAccessErrorPtr;
+
+FileSystemHandle::FileSystemHandle(ExecutionContext* execution_context,
+ const String& name)
+ : ExecutionContextClient(execution_context), name_(name) {}
+
+// static
+FileSystemHandle* FileSystemHandle::CreateFromMojoEntry(
+ mojom::blink::FileSystemAccessEntryPtr e,
+ ExecutionContext* execution_context) {
+ if (e->entry_handle->is_file()) {
+ return MakeGarbageCollected<FileSystemFileHandle>(
+ execution_context, e->name, std::move(e->entry_handle->get_file()));
+ }
+ return MakeGarbageCollected<FileSystemDirectoryHandle>(
+ execution_context, e->name, std::move(e->entry_handle->get_directory()));
+}
+
+namespace {
+String MojoPermissionStatusToString(mojom::blink::PermissionStatus status) {
+ switch (status) {
+ case mojom::blink::PermissionStatus::GRANTED:
+ return "granted";
+ case mojom::blink::PermissionStatus::DENIED:
+ return "denied";
+ case mojom::blink::PermissionStatus::ASK:
+ return "prompt";
+ }
+ NOTREACHED();
+ return "denied";
+}
+
+} // namespace
+
+ScriptPromise FileSystemHandle::queryPermission(
+ ScriptState* script_state,
+ const FileSystemHandlePermissionDescriptor* descriptor) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ QueryPermissionImpl(
+ descriptor->mode() == "readwrite",
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver,
+ mojom::blink::PermissionStatus result) {
+ resolver->Resolve(MojoPermissionStatusToString(result));
+ },
+ WrapPersistent(resolver)));
+
+ return result;
+}
+
+ScriptPromise FileSystemHandle::requestPermission(
+ ScriptState* script_state,
+ const FileSystemHandlePermissionDescriptor* descriptor) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ RequestPermissionImpl(
+ descriptor->mode() == "readwrite",
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, FileSystemAccessErrorPtr result,
+ mojom::blink::PermissionStatus status) {
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(MojoPermissionStatusToString(status));
+ },
+ WrapPersistent(resolver)));
+
+ return result;
+}
+
+ScriptPromise FileSystemHandle::isSameEntry(ScriptState* script_state,
+ FileSystemHandle* other) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ IsSameEntryImpl(
+ other->Transfer(),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver, FileSystemAccessErrorPtr result,
+ bool same) {
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(same);
+ },
+ WrapPersistent(resolver)));
+ return result;
+}
+
+void FileSystemHandle::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
new file mode 100644
index 00000000000..8ef5fe4ca0e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_HANDLE_H_
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+class ExecutionContext;
+class FileSystemHandlePermissionDescriptor;
+
+class FileSystemHandle : public ScriptWrappable, public ExecutionContextClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ FileSystemHandle(ExecutionContext* execution_context, const String& name);
+ static FileSystemHandle* CreateFromMojoEntry(
+ mojom::blink::FileSystemAccessEntryPtr,
+ ExecutionContext* execution_context);
+
+ virtual bool isFile() const { return false; }
+ virtual bool isDirectory() const { return false; }
+ const String kind() const { return isFile() ? "file" : "directory"; }
+ const String& name() const { return name_; }
+
+ ScriptPromise queryPermission(ScriptState*,
+ const FileSystemHandlePermissionDescriptor*);
+ ScriptPromise requestPermission(ScriptState*,
+ const FileSystemHandlePermissionDescriptor*);
+
+ ScriptPromise isSameEntry(ScriptState*, FileSystemHandle* other);
+
+ // Grab a handle to a transfer token. This may return an invalid PendingRemote
+ // if the context is already destroyed.
+ virtual mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>
+ Transfer() = 0;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ virtual void QueryPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::PermissionStatus)>) = 0;
+ virtual void RequestPermissionImpl(
+ bool writable,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ mojom::blink::PermissionStatus)>) = 0;
+ virtual void IsSameEntryImpl(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> other,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
+ bool)>) = 0;
+
+ String name_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
index 1cab690071b..bff43870a46 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
@@ -2,19 +2,18 @@
// 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-filesystemhandlekind
+// https://wicg.github.io/file-system-access/#enumdef-filesystemhandlekind
enum FileSystemHandleKind {
"file",
"directory",
};
-// https://wicg.github.io/native-file-system/#filesystemhandle
+// https://wicg.github.io/file-system-access/#filesystemhandle
[
Exposed=(Window,Worker),
SecureContext,
Serializable,
- RuntimeEnabled=NativeFileSystem,
- ImplementedAs=NativeFileSystemHandle
+ RuntimeEnabled=FileSystemAccess
] interface FileSystemHandle {
// 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
@@ -28,5 +27,6 @@ enum FileSystemHandleKind {
[CallWith=ScriptState] Promise<PermissionState> requestPermission(
optional FileSystemHandlePermissionDescriptor descriptor = {});
- [CallWith=ScriptState, Measure] Promise<boolean> isSameEntry(FileSystemHandle other);
+ [CallWith=ScriptState, Measure]
+ Promise<boolean> isSameEntry(FileSystemHandle other);
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl
index c4762fc1568..4dd4048a64c 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// http://wicg.github.io/native-file-system/#enumdef-filesystempermissionmode
+// http://wicg.github.io/file-system-access/#enumdef-filesystempermissionmode
enum FileSystemPermissionMode {
"read",
"readwrite"
};
-// http://wicg.github.io/native-file-system/#dictdef-filesystemhandlepermissiondescriptor
+// http://wicg.github.io/file-system-access/#dictdef-filesystemhandlepermissiondescriptor
dictionary FileSystemHandlePermissionDescriptor {
FileSystemPermissionMode mode = "read";
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl
index f3f856600cb..786bc941dd9 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/native-file-system/#dictdef-filesystemremoveoptions
+// https://wicg.github.io/file-system-access/#dictdef-filesystemremoveoptions
dictionary FileSystemRemoveOptions {
boolean recursive = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc
new file mode 100644
index 00000000000..07fbb30aebd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc
@@ -0,0 +1,483 @@
+// 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/file_system_access/file_system_underlying_sink.h"
+
+#include "mojo/public/cpp/system/string_data_source.h"
+#include "third_party/blink/public/common/blob/blob_utils.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"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/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"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
+
+namespace blink {
+
+FileSystemUnderlyingSink::FileSystemUnderlyingSink(
+ ExecutionContext* context,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileWriter> writer_remote)
+ : writer_remote_(context) {
+ writer_remote_.Bind(std::move(writer_remote),
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI));
+ DCHECK(writer_remote_.is_bound());
+}
+
+ScriptPromise FileSystemUnderlyingSink::start(
+ ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise FileSystemUnderlyingSink::write(
+ ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ v8::Local<v8::Value> value = chunk.V8Value();
+
+ ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams input;
+ V8ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams::ToImpl(
+ script_state->GetIsolate(), value, input,
+ UnionTypeConversionMode::kNotNullable, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ if (input.IsNull()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Cannot provide null object");
+ return ScriptPromise();
+ }
+
+ if (input.IsWriteParams()) {
+ return HandleParams(script_state, std::move(*input.GetAsWriteParams()),
+ exception_state);
+ }
+
+ ArrayBufferOrArrayBufferViewOrBlobOrUSVString write_data;
+ V8ArrayBufferOrArrayBufferViewOrBlobOrUSVString::ToImpl(
+ script_state->GetIsolate(), value, write_data,
+ UnionTypeConversionMode::kNotNullable, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ return WriteData(script_state, offset_, std::move(write_data),
+ exception_state);
+}
+
+ScriptPromise FileSystemUnderlyingSink::close(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (!writer_remote_.is_bound() || pending_operation_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Object reached an invalid state");
+ return ScriptPromise();
+ }
+ pending_operation_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = pending_operation_->Promise();
+ writer_remote_->Close(WTF::Bind(&FileSystemUnderlyingSink::CloseComplete,
+ WrapPersistent(this)));
+
+ return result;
+}
+
+ScriptPromise FileSystemUnderlyingSink::abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) {
+ // The specification guarantees that this will only be called after all
+ // pending writes have been aborted. Terminating the remote connection
+ // will ensure that the writes are not closed successfully.
+ if (writer_remote_.is_bound())
+ writer_remote_.reset();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise FileSystemUnderlyingSink::HandleParams(
+ ScriptState* script_state,
+ const WriteParams& params,
+ ExceptionState& exception_state) {
+ if (params.type() == "truncate") {
+ if (!params.hasSizeNonNull()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kSyntaxError,
+ "Invalid params passed. truncate requires a size argument");
+ return ScriptPromise();
+ }
+ return Truncate(script_state, params.sizeNonNull(), exception_state);
+ }
+
+ if (params.type() == "seek") {
+ if (!params.hasPositionNonNull()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kSyntaxError,
+ "Invalid params passed. seek requires a position argument");
+ return ScriptPromise();
+ }
+ return Seek(script_state, params.positionNonNull(), exception_state);
+ }
+
+ if (params.type() == "write") {
+ uint64_t position =
+ params.hasPositionNonNull() ? params.positionNonNull() : offset_;
+ if (!params.hasData()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kSyntaxError,
+ "Invalid params passed. write requires a data argument");
+ return ScriptPromise();
+ }
+ return WriteData(script_state, position, params.data(), exception_state);
+ }
+
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Object reached an invalid state");
+ return ScriptPromise();
+}
+
+namespace {
+// Write operations generally consist of two separate operations, both of which
+// can result in an error:
+// 1) The data producer (be it a Blob or mojo::DataPipeProducer) writes data to
+// a data pipe.
+// 2) The browser side file writer implementation reads data from the data pipe,
+// and writes this to the file.
+//
+// Both operations can report errors in either order, and we have to wait for
+// both to report success before we can consider the combined write call to have
+// succeeded. This helper class listens for both complete events and signals
+// success when both succeeded, or an error when either operation failed.
+//
+// This class deletes itself after calling its callback.
+class WriterHelper : public base::SupportsWeakPtr<WriterHelper> {
+ public:
+ explicit WriterHelper(
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written)> callback)
+ : callback_(std::move(callback)) {}
+ virtual ~WriterHelper() = default;
+
+ // This method is called in response to the mojom Write call. It reports the
+ // result of the write operation from the point of view of the file system API
+ // implementation.
+ void WriteComplete(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written) {
+ DCHECK(!write_result_);
+ write_result_ = std::move(result);
+ bytes_written_ = bytes_written;
+ MaybeCallCallbackAndDeleteThis();
+ }
+
+ // This method is called by renderer side code (in subclasses of this class)
+ // when we've finished producing data to be written.
+ void ProducerComplete(mojom::blink::FileSystemAccessErrorPtr result) {
+ DCHECK(!producer_result_);
+ producer_result_ = std::move(result);
+ MaybeCallCallbackAndDeleteThis();
+ }
+
+ private:
+ void MaybeCallCallbackAndDeleteThis() {
+ DCHECK(callback_);
+
+ if (!producer_result_.is_null() &&
+ producer_result_->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ // Producing data failed, report that error.
+ std::move(callback_).Run(std::move(producer_result_), bytes_written_);
+ delete this;
+ return;
+ }
+
+ if (!write_result_.is_null() &&
+ write_result_->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ // Writing failed, report that error.
+ std::move(callback_).Run(std::move(write_result_), bytes_written_);
+ delete this;
+ return;
+ }
+
+ if (!producer_result_.is_null() && !write_result_.is_null()) {
+ // Both operations succeeded, report success.
+ std::move(callback_).Run(std::move(write_result_), bytes_written_);
+ delete this;
+ return;
+ }
+
+ // Still waiting for the other operation to complete, so don't call the
+ // callback yet.
+ }
+
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written)>
+ callback_;
+
+ mojom::blink::FileSystemAccessErrorPtr producer_result_;
+ mojom::blink::FileSystemAccessErrorPtr write_result_;
+ uint64_t bytes_written_ = 0;
+};
+
+// WriterHelper implementation that is used when data is being produced by a
+// mojo::DataPipeProducer, generally because the data was passed in as an
+// ArrayBuffer or String.
+class StreamWriterHelper : public WriterHelper {
+ public:
+ StreamWriterHelper(
+ std::unique_ptr<mojo::DataPipeProducer> producer,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written)> callback)
+ : WriterHelper(std::move(callback)), producer_(std::move(producer)) {}
+
+ void DataProducerComplete(MojoResult result) {
+ // Reset `producer_` to close the DataPipe. Without this the Write operation
+ // will never complete as it will keep waiting for more data.
+ producer_ = nullptr;
+
+ if (result == MOJO_RESULT_OK) {
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kOk, base::File::FILE_OK, ""));
+ } else {
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kOperationAborted,
+ base::File::FILE_OK, "Failed to write data to data pipe"));
+ }
+ }
+
+ private:
+ std::unique_ptr<mojo::DataPipeProducer> producer_;
+};
+
+// WriterHelper implementation that is used when data is being produced by a
+// Blob.
+class BlobWriterHelper : public mojom::blink::BlobReaderClient,
+ public WriterHelper {
+ public:
+ BlobWriterHelper(
+ mojo::PendingReceiver<mojom::blink::BlobReaderClient> receiver,
+ base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written)> callback)
+ : WriterHelper(std::move(callback)),
+ receiver_(this, std::move(receiver)) {
+ receiver_.set_disconnect_handler(
+ WTF::Bind(&BlobWriterHelper::OnDisconnect, WTF::Unretained(this)));
+ }
+
+ // BlobReaderClient:
+ void OnCalculatedSize(uint64_t total_size,
+ uint64_t expected_content_size) override {}
+ void OnComplete(int32_t status, uint64_t data_length) override {
+ complete_called_ = true;
+ // This error conversion matches what FileReaderLoader does. Failing to read
+ // a blob using FileReader should result in the same exception type as
+ // failing to read a blob here.
+ if (status == net::OK) {
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kOk, base::File::FILE_OK, ""));
+ } else if (status == net::ERR_FILE_NOT_FOUND) {
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kFileError,
+ base::File::FILE_ERROR_NOT_FOUND, ""));
+ } else {
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kFileError,
+ base::File::FILE_ERROR_IO, ""));
+ }
+ }
+
+ private:
+ void OnDisconnect() {
+ if (!complete_called_) {
+ // Disconnected without getting a read result, treat this as read failure.
+ ProducerComplete(mojom::blink::FileSystemAccessError::New(
+ mojom::blink::FileSystemAccessStatus::kOperationAborted,
+ base::File::FILE_OK, "Blob disconnected while reading"));
+ }
+ }
+
+ mojo::Receiver<mojom::blink::BlobReaderClient> receiver_;
+ bool complete_called_ = false;
+};
+
+// Creates a mojo data pipe, where the capacity of the data pipe is derived from
+// the provided `data_size`. Returns false and throws an exception if creating
+// the data pipe failed.
+bool CreateDataPipe(uint64_t data_size,
+ ExceptionState& exception_state,
+ mojo::ScopedDataPipeProducerHandle& producer,
+ mojo::ScopedDataPipeConsumerHandle& consumer) {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = BlobUtils::GetDataPipeCapacity(data_size);
+
+ MojoResult rv = CreateDataPipe(&options, producer, consumer);
+ if (rv != MOJO_RESULT_OK) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Failed to create datapipe");
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+ScriptPromise FileSystemUnderlyingSink::WriteData(
+ ScriptState* script_state,
+ uint64_t position,
+ const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
+ ExceptionState& exception_state) {
+ DCHECK(!data.IsNull());
+
+ if (!writer_remote_.is_bound() || pending_operation_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Object reached an invalid state");
+ return ScriptPromise();
+ }
+
+ std::unique_ptr<mojo::DataPipeProducer::DataSource> data_source;
+ if (data.IsArrayBuffer()) {
+ DOMArrayBuffer* array_buffer = data.GetAsArrayBuffer();
+ data_source = std::make_unique<mojo::StringDataSource>(
+ base::span<const char>(static_cast<const char*>(array_buffer->Data()),
+ array_buffer->ByteLength()),
+ mojo::StringDataSource::AsyncWritingMode::
+ STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
+ } else if (data.IsArrayBufferView()) {
+ DOMArrayBufferView* array_buffer_view = data.GetAsArrayBufferView().Get();
+ data_source = std::make_unique<mojo::StringDataSource>(
+ base::span<const char>(
+ static_cast<const char*>(array_buffer_view->BaseAddress()),
+ array_buffer_view->byteLength()),
+ mojo::StringDataSource::AsyncWritingMode::
+ STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
+ } else if (data.IsUSVString()) {
+ data_source = std::make_unique<mojo::StringDataSource>(
+ StringUTF8Adaptor(data.GetAsUSVString()).AsStringPiece(),
+ mojo::StringDataSource::AsyncWritingMode::
+ STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
+ }
+
+ DCHECK(data_source || data.IsBlob());
+ uint64_t data_size =
+ data_source ? data_source->GetLength() : data.GetAsBlob()->size();
+
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ if (!CreateDataPipe(data_size, exception_state, producer_handle,
+ consumer_handle)) {
+ return ScriptPromise();
+ }
+
+ WriterHelper* helper;
+ if (data.IsBlob()) {
+ mojo::PendingRemote<mojom::blink::BlobReaderClient> reader_client;
+ helper =
+ new BlobWriterHelper(reader_client.InitWithNewPipeAndPassReceiver(),
+ WTF::Bind(&FileSystemUnderlyingSink::WriteComplete,
+ WrapPersistent(this)));
+ data.GetAsBlob()->GetBlobDataHandle()->ReadAll(std::move(producer_handle),
+ std::move(reader_client));
+ } else {
+ auto producer =
+ std::make_unique<mojo::DataPipeProducer>(std::move(producer_handle));
+ auto* producer_ptr = producer.get();
+ helper = new StreamWriterHelper(
+ std::move(producer), WTF::Bind(&FileSystemUnderlyingSink::WriteComplete,
+ WrapPersistent(this)));
+ // Unretained is safe because the producer is owned by `helper`.
+ producer_ptr->Write(
+ std::move(data_source),
+ WTF::Bind(&StreamWriterHelper::DataProducerComplete,
+ WTF::Unretained(static_cast<StreamWriterHelper*>(helper))));
+ }
+
+ writer_remote_->Write(
+ position, std::move(consumer_handle),
+ WTF::Bind(&WriterHelper::WriteComplete, helper->AsWeakPtr()));
+
+ pending_operation_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ return pending_operation_->Promise();
+}
+
+ScriptPromise FileSystemUnderlyingSink::Truncate(
+ ScriptState* script_state,
+ uint64_t size,
+ ExceptionState& exception_state) {
+ if (!writer_remote_.is_bound() || pending_operation_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Object reached an invalid state");
+ return ScriptPromise();
+ }
+ pending_operation_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = pending_operation_->Promise();
+ writer_remote_->Truncate(
+ size, WTF::Bind(&FileSystemUnderlyingSink::TruncateComplete,
+ WrapPersistent(this), size));
+ return result;
+}
+
+ScriptPromise FileSystemUnderlyingSink::Seek(ScriptState* script_state,
+ uint64_t offset,
+ ExceptionState& exception_state) {
+ if (!writer_remote_.is_bound() || pending_operation_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Object reached an invalid state");
+ return ScriptPromise();
+ }
+ offset_ = offset;
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+void FileSystemUnderlyingSink::WriteComplete(
+ mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written) {
+ DCHECK(pending_operation_);
+ file_system_access_error::ResolveOrReject(pending_operation_, *result);
+ pending_operation_ = nullptr;
+
+ if (result->status == mojom::blink::FileSystemAccessStatus::kOk) {
+ // Advance offset.
+ offset_ += bytes_written;
+ }
+}
+
+void FileSystemUnderlyingSink::TruncateComplete(
+ uint64_t to_size,
+ mojom::blink::FileSystemAccessErrorPtr result) {
+ DCHECK(pending_operation_);
+ file_system_access_error::ResolveOrReject(pending_operation_, *result);
+ pending_operation_ = nullptr;
+
+ if (result->status == mojom::blink::FileSystemAccessStatus::kOk) {
+ // Set offset to smallest last set size so that a subsequent write is not
+ // out of bounds.
+ offset_ = to_size < offset_ ? to_size : offset_;
+ }
+}
+
+void FileSystemUnderlyingSink::CloseComplete(
+ mojom::blink::FileSystemAccessErrorPtr result) {
+ DCHECK(pending_operation_);
+ file_system_access_error::ResolveOrReject(pending_operation_, *result);
+ pending_operation_ = nullptr;
+ // We close the mojo pipe because we intend this writable file stream to be
+ // discarded after close. Subsequent operations will fail.
+ writer_remote_.reset();
+}
+
+void FileSystemUnderlyingSink::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ UnderlyingSinkBase::Trace(visitor);
+ visitor->Trace(writer_remote_);
+ visitor->Trace(pending_operation_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.h
new file mode 100644
index 00000000000..87d7eca9405
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.h
@@ -0,0 +1,65 @@
+// 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_FILE_SYSTEM_ACCESS_FILE_SYSTEM_UNDERLYING_SINK_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_UNDERLYING_SINK_H_
+
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+
+namespace blink {
+
+class ExceptionState;
+class ScriptPromiseResolver;
+class WriteParams;
+
+class FileSystemUnderlyingSink final : public UnderlyingSinkBase {
+ public:
+ explicit FileSystemUnderlyingSink(
+ ExecutionContext*,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileWriter>);
+
+ // UnderlyingSinkBase
+ ScriptPromise start(ScriptState*,
+ WritableStreamDefaultController*,
+ ExceptionState&) override;
+ ScriptPromise write(ScriptState*,
+ ScriptValue chunk,
+ WritableStreamDefaultController*,
+ ExceptionState&) override;
+ ScriptPromise close(ScriptState*, ExceptionState&) override;
+ ScriptPromise abort(ScriptState*,
+ ScriptValue reason,
+ ExceptionState&) override;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ ScriptPromise HandleParams(ScriptState*, const WriteParams&, ExceptionState&);
+ ScriptPromise WriteData(
+ ScriptState*,
+ uint64_t position,
+ const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
+ ExceptionState&);
+ ScriptPromise Truncate(ScriptState*, uint64_t size, ExceptionState&);
+ ScriptPromise Seek(ScriptState*, uint64_t offset, ExceptionState&);
+ void WriteComplete(mojom::blink::FileSystemAccessErrorPtr result,
+ uint64_t bytes_written);
+ void TruncateComplete(uint64_t to_size,
+ mojom::blink::FileSystemAccessErrorPtr result);
+ void CloseComplete(mojom::blink::FileSystemAccessErrorPtr result);
+
+ HeapMojoRemote<mojom::blink::FileSystemAccessFileWriter> writer_remote_;
+
+ uint64_t offset_ = 0;
+ Member<ScriptPromiseResolver> pending_operation_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_UNDERLYING_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc
new file mode 100644
index 00000000000..e283056fc1a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.cc
@@ -0,0 +1,117 @@
+// 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/file_system_access/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"
+#include "third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_write_params.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#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/file_system_access/file_system_underlying_sink.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+
+namespace blink {
+
+FileSystemWritableFileStream* FileSystemWritableFileStream::Create(
+ ScriptState* script_state,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileWriter>
+ writer_pending_remote) {
+ DCHECK(writer_pending_remote);
+ ScriptState::Scope scope(script_state);
+
+ ExecutionContext* context = ExecutionContext::From(script_state);
+
+ auto* stream = MakeGarbageCollected<FileSystemWritableFileStream>();
+
+ auto* underlying_sink = MakeGarbageCollected<FileSystemUnderlyingSink>(
+ context, std::move(writer_pending_remote));
+ stream->underlying_sink_ = underlying_sink;
+ auto underlying_sink_value = ScriptValue::From(script_state, underlying_sink);
+
+ auto* init = QueuingStrategyInit::Create();
+ // HighWaterMark set to 1 here. This allows the stream to appear available
+ // without adding additional buffering.
+ init->setHighWaterMark(1);
+ auto* strategy = CountQueuingStrategy::Create(script_state, init);
+ ScriptValue strategy_value = ScriptValue::From(script_state, strategy);
+
+ ExceptionState exception_state(script_state->GetIsolate(),
+ ExceptionState::kConstructionContext,
+ "FileSystemWritableFileStream");
+ stream->InitInternal(script_state, underlying_sink_value, strategy_value,
+ exception_state);
+
+ if (exception_state.HadException())
+ return nullptr;
+
+ return stream;
+}
+
+ScriptPromise FileSystemWritableFileStream::write(
+ ScriptState* script_state,
+ const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams& data,
+ ExceptionState& exception_state) {
+ WritableStreamDefaultWriter* writer =
+ WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ ScriptPromise promise = writer->write(
+ script_state, ScriptValue::From(script_state, data), exception_state);
+
+ WritableStreamDefaultWriter::Release(script_state, writer);
+ return promise;
+}
+
+ScriptPromise FileSystemWritableFileStream::truncate(
+ ScriptState* script_state,
+ uint64_t size,
+ ExceptionState& exception_state) {
+ WritableStreamDefaultWriter* writer =
+ WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ auto* options = WriteParams::Create();
+ options->setType("truncate");
+ options->setSize(size);
+
+ ScriptPromise promise = writer->write(
+ script_state, ScriptValue::From(script_state, options), exception_state);
+
+ WritableStreamDefaultWriter::Release(script_state, writer);
+ return promise;
+}
+
+ScriptPromise FileSystemWritableFileStream::seek(
+ ScriptState* script_state,
+ uint64_t offset,
+ ExceptionState& exception_state) {
+ WritableStreamDefaultWriter* writer =
+ WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ auto* options = WriteParams::Create();
+ options->setType("seek");
+ options->setPosition(offset);
+
+ ScriptPromise promise = writer->write(
+ script_state, ScriptValue::From(script_state, options), exception_state);
+
+ WritableStreamDefaultWriter::Release(script_state, writer);
+ return promise;
+}
+
+void FileSystemWritableFileStream::Trace(Visitor* visitor) const {
+ WritableStream::Trace(visitor);
+ visitor->Trace(underlying_sink_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h
new file mode 100644
index 00000000000..49389f397ff
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
+
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class ScriptPromise;
+class ScriptState;
+class FileSystemUnderlyingSink;
+
+class FileSystemWritableFileStream final : public WritableStream {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static FileSystemWritableFileStream* Create(
+ ScriptState*,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileWriter>);
+
+ void Trace(Visitor* visitor) const override;
+
+ // IDL defined functions specific to FileSystemWritableFileStream.
+ ScriptPromise write(
+ ScriptState*,
+ const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams& data,
+ ExceptionState&);
+ ScriptPromise truncate(ScriptState*, uint64_t size, ExceptionState&);
+ ScriptPromise seek(ScriptState*, uint64_t offset, ExceptionState&);
+
+ private:
+ Member<FileSystemUnderlyingSink> underlying_sink_;
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl
index e09e63d9cfa..2ccd7efd2fb 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl
@@ -2,15 +2,13 @@
// 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/#filesystemwritablefilestream
+// https://wicg.github.io/file-system-access/#filesystemwritablefilestream
[
Exposed=(Window,Worker),
SecureContext,
- ImplementedAs=NativeFileSystemWritableFileStream,
- RuntimeEnabled=NativeFileSystem
+ RuntimeEnabled=FileSystemAccess
] interface FileSystemWritableFileStream : WritableStream {
[CallWith=ScriptState, RaisesException] Promise<void> write((BufferSource or Blob or USVString or WriteParams) data);
[CallWith=ScriptState, RaisesException] Promise<void> truncate(unsigned long long size);
- [CallWith=ScriptState, RaisesException] Promise<void> close();
[CallWith=ScriptState, RaisesException] Promise<void> seek(unsigned long long offset);
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.cc
new file mode 100644
index 00000000000..dcc72223343
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.cc
@@ -0,0 +1,452 @@
+// 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/file_system_access/global_file_system_access.h"
+
+#include <utility>
+
+#include "base/notreached.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/file_system_access/file_system_access_manager.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom-shared.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_directory_picker_options.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"
+#include "third_party/blink/renderer/bindings/modules/v8/well_known_directory_or_file_system_handle.h"
+#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/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/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.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/heap.h"
+#include "third_party/blink/renderer/platform/network/http_parsers.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/text/ascii_ctype.h"
+
+namespace blink {
+
+namespace {
+
+constexpr char kDefaultStartingDirectoryId[] = "";
+
+constexpr bool IsHTTPWhitespace(UChar chr) {
+ return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
+}
+
+bool IsValidSuffixCodePoint(UChar chr) {
+ return IsASCIIAlphanumeric(chr) || chr == '+' || chr == '.';
+}
+
+bool IsValidIdCodePoint(UChar chr) {
+ return IsASCIIAlphanumeric(chr) || chr == '_' || chr == '-';
+}
+
+bool VerifyIsValidExtension(const String& extension,
+ ExceptionState& exception_state) {
+ if (!extension.StartsWith(".")) {
+ exception_state.ThrowTypeError("Extension '" + extension +
+ "' must start with '.'.");
+ return false;
+ }
+ if (!extension.IsAllSpecialCharacters<IsValidSuffixCodePoint>()) {
+ exception_state.ThrowTypeError("Extension '" + extension +
+ "' contains invalid characters.");
+ return false;
+ }
+ if (extension.EndsWith(".")) {
+ exception_state.ThrowTypeError("Extension '" + extension +
+ "' must not end with '.'.");
+ return false;
+ }
+ if (extension.length() > 16) {
+ exception_state.ThrowTypeError("Extension '" + extension +
+ "' cannot be longer than 16 characters.");
+ return false;
+ }
+
+ return true;
+}
+
+String VerifyIsValidId(const String& id, ExceptionState& exception_state) {
+ if (!id.IsAllSpecialCharacters<IsValidIdCodePoint>()) {
+ exception_state.ThrowTypeError("ID '" + id +
+ "' contains invalid characters.");
+ return String();
+ }
+ if (id.length() > 32) {
+ exception_state.ThrowTypeError("ID '" + id +
+ "' cannot be longer than 32 characters.");
+ return String();
+ }
+
+ return std::move(id);
+}
+
+bool AddExtension(const String& extension,
+ Vector<String>& extensions,
+ ExceptionState& exception_state) {
+ if (!VerifyIsValidExtension(extension, exception_state))
+ return false;
+
+ extensions.push_back(extension.Substring(1));
+ return true;
+}
+
+Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts(
+ const HeapVector<Member<FilePickerAcceptType>>& types,
+ ExceptionState& exception_state) {
+ Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> result;
+ result.ReserveInitialCapacity(types.size());
+ for (const auto& t : types) {
+ Vector<String> mimeTypes;
+ mimeTypes.ReserveInitialCapacity(t->accept().size());
+ Vector<String> extensions;
+ for (const auto& a : t->accept()) {
+ String type = a.first.StripWhiteSpace(IsHTTPWhitespace);
+ if (type.IsEmpty()) {
+ exception_state.ThrowTypeError("Invalid type: " + a.first);
+ return {};
+ }
+ Vector<String> parsed_type;
+ type.Split('/', true, parsed_type);
+ if (parsed_type.size() != 2) {
+ exception_state.ThrowTypeError("Invalid type: " + a.first);
+ return {};
+ }
+ if (!IsValidHTTPToken(parsed_type[0])) {
+ exception_state.ThrowTypeError("Invalid type: " + a.first);
+ return {};
+ }
+ if (!IsValidHTTPToken(parsed_type[1])) {
+ exception_state.ThrowTypeError("Invalid type: " + a.first);
+ return {};
+ }
+
+ mimeTypes.push_back(type);
+ if (a.second.IsUSVString()) {
+ if (!AddExtension(a.second.GetAsUSVString(), extensions,
+ exception_state))
+ return {};
+ } else {
+ for (const auto& extension : a.second.GetAsUSVStringSequence()) {
+ if (!AddExtension(extension, extensions, exception_state))
+ return {};
+ }
+ }
+ }
+ result.emplace_back(
+ blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New(
+ t->hasDescription() ? t->description() : g_empty_string,
+ std::move(mimeTypes), std::move(extensions)));
+ }
+ return result;
+}
+
+void VerifyIsAllowedToShowFilePicker(const LocalDOMWindow& window,
+ ExceptionState& exception_state) {
+ if (!window.IsCurrentlyDisplayedInFrame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kAbortError, "");
+ return;
+ }
+
+ if (!window.GetSecurityOrigin()->CanAccessFileSystem()) {
+ if (window.IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
+ exception_state.ThrowSecurityError(
+ "Sandboxed documents aren't allowed to show a file picker.");
+ return;
+ } else {
+ exception_state.ThrowSecurityError(
+ "This document isn't allowed to show a file picker.");
+ return;
+ }
+ }
+
+ LocalFrame* local_frame = window.GetFrame();
+ if (!local_frame || local_frame->IsCrossOriginToMainFrame()) {
+ exception_state.ThrowSecurityError(
+ "Cross origin sub frames aren't allowed to show a file picker.");
+ return;
+ }
+
+ if (!LocalFrame::HasTransientUserActivation(local_frame)) {
+ exception_state.ThrowSecurityError(
+ "Must be handling a user gesture to show a file picker.");
+ return;
+ }
+}
+
+mojom::blink::WellKnownDirectory ConvertWellKnownDirectory(
+ const String& directory,
+ ExceptionState& exception_state) {
+ if (directory == "")
+ return mojom::blink::WellKnownDirectory::kDefault;
+ else if (directory == "desktop")
+ return mojom::blink::WellKnownDirectory::kDirDesktop;
+ else if (directory == "documents")
+ return mojom::blink::WellKnownDirectory::kDirDocuments;
+ else if (directory == "downloads")
+ return mojom::blink::WellKnownDirectory::kDirDownloads;
+ else if (directory == "music")
+ return mojom::blink::WellKnownDirectory::kDirMusic;
+ else if (directory == "pictures")
+ return mojom::blink::WellKnownDirectory::kDirPictures;
+ else if (directory == "videos")
+ return mojom::blink::WellKnownDirectory::kDirVideos;
+
+ NOTREACHED();
+ return mojom::blink::WellKnownDirectory::kDefault;
+}
+
+ScriptPromise ShowFilePickerImpl(
+ ScriptState* script_state,
+ LocalDOMWindow& window,
+ mojom::blink::FilePickerOptionsPtr options,
+ mojom::blink::CommonFilePickerOptionsPtr common_options,
+ bool return_as_sequence) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise resolver_result = resolver->Promise();
+
+ // TODO(mek): Cache mojo::Remote<mojom::blink::FileSystemAccessManager>
+ // 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::FileSystemAccessManager> manager;
+ window.GetBrowserInterfaceBroker().GetInterface(
+ manager.BindNewPipeAndPassReceiver());
+
+ auto* raw_manager = manager.get();
+ raw_manager->ChooseEntries(
+ std::move(options), std::move(common_options),
+ WTF::Bind(
+ [](ScriptPromiseResolver* resolver,
+ mojo::Remote<mojom::blink::FileSystemAccessManager>,
+ bool return_as_sequence, LocalFrame* local_frame,
+ mojom::blink::FileSystemAccessErrorPtr file_operation_result,
+ Vector<mojom::blink::FileSystemAccessEntryPtr> entries) {
+ ExecutionContext* context = resolver->GetExecutionContext();
+ if (!context)
+ return;
+ if (file_operation_result->status !=
+ mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver,
+ *file_operation_result);
+ return;
+ }
+
+ // While it would be better to not trust the renderer process,
+ // we're doing this here to avoid potential mojo message pipe
+ // ordering problems, where the frame activation state
+ // reconciliation messages would compete with concurrent File
+ // System Access messages to the browser.
+ // TODO(https://crbug.com/1017270): Remove this after spec change,
+ // or when activation moves to browser.
+ LocalFrame::NotifyUserActivation(
+ local_frame, mojom::blink::UserActivationNotificationType::
+ kFileSystemAccess);
+
+ if (return_as_sequence) {
+ HeapVector<Member<FileSystemHandle>> results;
+ results.ReserveInitialCapacity(entries.size());
+ for (auto& entry : entries) {
+ results.push_back(FileSystemHandle::CreateFromMojoEntry(
+ std::move(entry), context));
+ }
+ resolver->Resolve(results);
+ } else {
+ DCHECK_EQ(1u, entries.size());
+ resolver->Resolve(FileSystemHandle::CreateFromMojoEntry(
+ std::move(entries[0]), context));
+ }
+ },
+ WrapPersistent(resolver), std::move(manager), return_as_sequence,
+ WrapPersistent(window.GetFrame())));
+ return resolver_result;
+}
+
+} // namespace
+
+// static
+ScriptPromise GlobalFileSystemAccess::showOpenFilePicker(
+ ScriptState* script_state,
+ LocalDOMWindow& window,
+ const OpenFilePickerOptions* options,
+ ExceptionState& exception_state) {
+ UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
+
+ Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
+ if (options->hasTypes())
+ accepts = ConvertAccepts(options->types(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ if (accepts.IsEmpty() && options->excludeAcceptAllOption()) {
+ exception_state.ThrowTypeError("Need at least one accepted type");
+ return ScriptPromise();
+ }
+
+ String starting_directory_id = kDefaultStartingDirectoryId;
+ if (options->hasId()) {
+ starting_directory_id = VerifyIsValidId(options->id(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+
+ auto well_known_starting_directory =
+ mojom::blink::WellKnownDirectory::kDefault;
+ mojo::PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken> token;
+ if (options->hasStartIn()) {
+ auto& start_in = options->startIn();
+ if (start_in.IsWellKnownDirectory()) {
+ well_known_starting_directory = ConvertWellKnownDirectory(
+ start_in.GetAsWellKnownDirectory(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+ if (start_in.IsFileSystemHandle()) {
+ token = start_in.GetAsFileSystemHandle()->Transfer();
+ }
+ }
+
+ VerifyIsAllowedToShowFilePicker(window, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ auto open_file_picker_options = mojom::blink::OpenFilePickerOptions::New(
+ mojom::blink::AcceptsTypesInfo::New(std::move(accepts),
+ !options->excludeAcceptAllOption()),
+ options->multiple());
+
+ return ShowFilePickerImpl(
+ script_state, window,
+ mojom::blink::FilePickerOptions::NewOpenFilePickerOptions(
+ std::move(open_file_picker_options)),
+ mojom::blink::CommonFilePickerOptions::New(
+ std::move(starting_directory_id),
+ std::move(well_known_starting_directory), std::move(token)),
+ /*return_as_sequence=*/true);
+}
+
+// static
+ScriptPromise GlobalFileSystemAccess::showSaveFilePicker(
+ ScriptState* script_state,
+ LocalDOMWindow& window,
+ const SaveFilePickerOptions* options,
+ ExceptionState& exception_state) {
+ UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
+
+ Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
+ if (options->hasTypes())
+ accepts = ConvertAccepts(options->types(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ if (accepts.IsEmpty() && options->excludeAcceptAllOption()) {
+ exception_state.ThrowTypeError("Need at least one accepted type");
+ return ScriptPromise();
+ }
+
+ String starting_directory_id = kDefaultStartingDirectoryId;
+ if (options->hasId()) {
+ starting_directory_id = VerifyIsValidId(options->id(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+
+ auto well_known_starting_directory =
+ mojom::blink::WellKnownDirectory::kDefault;
+ mojo::PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken> token;
+ if (options->hasStartIn()) {
+ auto& start_in = options->startIn();
+ if (start_in.IsWellKnownDirectory()) {
+ well_known_starting_directory = ConvertWellKnownDirectory(
+ start_in.GetAsWellKnownDirectory(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+ if (start_in.IsFileSystemHandle()) {
+ token = start_in.GetAsFileSystemHandle()->Transfer();
+ }
+ }
+
+ VerifyIsAllowedToShowFilePicker(window, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ auto save_file_picker_options = mojom::blink::SaveFilePickerOptions::New(
+ mojom::blink::AcceptsTypesInfo::New(std::move(accepts),
+ !options->excludeAcceptAllOption()),
+ (options->hasSuggestedName() && !options->suggestedName().IsNull())
+ ? options->suggestedName()
+ : g_empty_string);
+ return ShowFilePickerImpl(
+ script_state, window,
+ mojom::blink::FilePickerOptions::NewSaveFilePickerOptions(
+ std::move(save_file_picker_options)),
+ mojom::blink::CommonFilePickerOptions::New(
+ std::move(starting_directory_id),
+ std::move(well_known_starting_directory), std::move(token)),
+ /*return_as_sequence=*/false);
+}
+
+// static
+ScriptPromise GlobalFileSystemAccess::showDirectoryPicker(
+ ScriptState* script_state,
+ LocalDOMWindow& window,
+ const DirectoryPickerOptions* options,
+ ExceptionState& exception_state) {
+ UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
+
+ String starting_directory_id = kDefaultStartingDirectoryId;
+ if (options->hasId()) {
+ starting_directory_id = VerifyIsValidId(options->id(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+
+ auto well_known_starting_directory =
+ mojom::blink::WellKnownDirectory::kDefault;
+ mojo::PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken> token;
+ if (options->hasStartIn()) {
+ auto& start_in = options->startIn();
+ if (start_in.IsWellKnownDirectory()) {
+ well_known_starting_directory = ConvertWellKnownDirectory(
+ start_in.GetAsWellKnownDirectory(), exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+ }
+ if (start_in.IsFileSystemHandle()) {
+ token = start_in.GetAsFileSystemHandle()->Transfer();
+ }
+ }
+
+ VerifyIsAllowedToShowFilePicker(window, exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ auto directory_picker_options = mojom::blink::DirectoryPickerOptions::New();
+ return ShowFilePickerImpl(
+ script_state, window,
+ mojom::blink::FilePickerOptions::NewDirectoryPickerOptions(
+ std::move(directory_picker_options)),
+ mojom::blink::CommonFilePickerOptions::New(
+ std::move(starting_directory_id),
+ std::move(well_known_starting_directory), std::move(token)),
+ /*return_as_sequence=*/false);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.h b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.h
new file mode 100644
index 00000000000..b6190eb3340
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_FILE_SYSTEM_ACCESS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_FILE_SYSTEM_ACCESS_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class OpenFilePickerOptions;
+class SaveFilePickerOptions;
+class DirectoryPickerOptions;
+class ExceptionState;
+class LocalDOMWindow;
+class ScriptPromise;
+class ScriptState;
+
+class GlobalFileSystemAccess {
+ STATIC_ONLY(GlobalFileSystemAccess);
+
+ public:
+ static ScriptPromise showOpenFilePicker(ScriptState*,
+ LocalDOMWindow&,
+ const OpenFilePickerOptions*,
+ ExceptionState&);
+ static ScriptPromise showSaveFilePicker(ScriptState*,
+ LocalDOMWindow&,
+ const SaveFilePickerOptions*,
+ ExceptionState&);
+ static ScriptPromise showDirectoryPicker(ScriptState*,
+ LocalDOMWindow&,
+ const DirectoryPickerOptions*,
+ ExceptionState&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_FILE_SYSTEM_ACCESS_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access_test.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access_test.cc
new file mode 100644
index 00000000000..aedbdd92d8f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_file_system_access_test.cc
@@ -0,0 +1,233 @@
+// 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/file_system_access/global_file_system_access.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/file_system_access/file_system_access_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/script/classic_script.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class MockFileSystemAccessManager
+ : public mojom::blink::FileSystemAccessManager {
+ public:
+ MockFileSystemAccessManager(BrowserInterfaceBrokerProxy& broker,
+ base::OnceClosure reached_callback)
+ : reached_callback_(std::move(reached_callback)), broker_(broker) {
+ broker_.SetBinderForTesting(
+ mojom::blink::FileSystemAccessManager::Name_,
+ WTF::BindRepeating(
+ &MockFileSystemAccessManager::BindFileSystemAccessManager,
+ WTF::Unretained(this)));
+ }
+ MockFileSystemAccessManager(BrowserInterfaceBrokerProxy& broker)
+ : broker_(broker) {
+ broker_.SetBinderForTesting(
+ mojom::blink::FileSystemAccessManager::Name_,
+ WTF::BindRepeating(
+ &MockFileSystemAccessManager::BindFileSystemAccessManager,
+ WTF::Unretained(this)));
+ }
+ ~MockFileSystemAccessManager() override {
+ broker_.SetBinderForTesting(mojom::blink::FileSystemAccessManager::Name_,
+ {});
+ }
+
+ using ChooseEntriesResponseCallback =
+ base::OnceCallback<void(ChooseEntriesCallback callback)>;
+
+ void SetQuitClosure(base::OnceClosure reached_callback) {
+ reached_callback_ = std::move(reached_callback);
+ }
+
+ // Unused for these tests.
+ void GetSandboxedFileSystem(
+ GetSandboxedFileSystemCallback callback) override {}
+
+ void ChooseEntries(mojom::blink::FilePickerOptionsPtr options,
+ mojom::blink::CommonFilePickerOptionsPtr common_options,
+ ChooseEntriesCallback callback) override {
+ if (choose_entries_response_callback_) {
+ std::move(choose_entries_response_callback_).Run(std::move(callback));
+ }
+
+ if (reached_callback_)
+ std::move(reached_callback_).Run();
+ }
+
+ void SetChooseEntriesResponse(ChooseEntriesResponseCallback callback) {
+ choose_entries_response_callback_ = std::move(callback);
+ }
+
+ void GetFileHandleFromToken(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>,
+ mojo::PendingReceiver<mojom::blink::FileSystemAccessFileHandle>)
+ override {}
+
+ void GetDirectoryHandleFromToken(
+ mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>,
+ mojo::PendingReceiver<mojom::blink::FileSystemAccessDirectoryHandle>)
+ override {}
+
+ void GetEntryFromDataTransferToken(
+ mojo::PendingRemote<
+ blink::mojom::blink::FileSystemAccessDataTransferToken> token,
+ GetEntryFromDataTransferTokenCallback callback) override {}
+
+ private:
+ void BindFileSystemAccessManager(mojo::ScopedMessagePipeHandle handle) {
+ receivers_.Add(this,
+ mojo::PendingReceiver<mojom::blink::FileSystemAccessManager>(
+ std::move(handle)));
+ }
+
+ base::OnceClosure reached_callback_;
+ ChooseEntriesResponseCallback choose_entries_response_callback_;
+ mojo::ReceiverSet<mojom::blink::FileSystemAccessManager> receivers_;
+ BrowserInterfaceBrokerProxy& broker_;
+};
+
+class GlobalFileSystemAccessTest : public PageTestBase {
+ public:
+ void SetUp() override {
+ PageTestBase::SetUp();
+ Navigate("http://localhost");
+ GetDocument().GetSettings()->SetScriptEnabled(true);
+ }
+
+ void Navigate(const String& destinationUrl) {
+ const KURL& url = KURL(NullURL(), destinationUrl);
+ auto navigation_params =
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), url);
+ GetDocument().GetFrame()->Loader().CommitNavigation(
+ std::move(navigation_params), /*extra_data=*/nullptr);
+ blink::test::RunPendingTasks();
+ ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
+ }
+};
+
+TEST_F(GlobalFileSystemAccessTest, UserActivationRequiredOtherwiseDenied) {
+ LocalFrame* frame = &GetFrame();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+
+ MockFileSystemAccessManager manager(frame->GetBrowserInterfaceBroker());
+ manager.SetChooseEntriesResponse(WTF::Bind(
+ [](MockFileSystemAccessManager::ChooseEntriesCallback callback) {
+ FAIL();
+ }));
+ ClassicScript::CreateUnspecifiedScript(
+ ScriptSourceCode("window.showOpenFilePicker();"))
+ ->RunScript(GetFrame().DomWindow());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+}
+
+TEST_F(GlobalFileSystemAccessTest, UserActivationChooseEntriesSuccessful) {
+ LocalFrame* frame = &GetFrame();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+
+ LocalFrame::NotifyUserActivation(
+ frame, mojom::UserActivationNotificationType::kTest);
+ EXPECT_TRUE(frame->HasStickyUserActivation());
+
+ base::RunLoop manager_run_loop;
+ MockFileSystemAccessManager manager(frame->GetBrowserInterfaceBroker(),
+ manager_run_loop.QuitClosure());
+ manager.SetChooseEntriesResponse(WTF::Bind(
+ [](MockFileSystemAccessManager::ChooseEntriesCallback callback) {
+ auto error = mojom::blink::FileSystemAccessError::New();
+ error->status = mojom::blink::FileSystemAccessStatus::kOk;
+ error->message = "";
+
+ mojo::PendingRemote<mojom::blink::FileSystemAccessFileHandle>
+ pending_remote;
+ ignore_result(pending_remote.InitWithNewPipeAndPassReceiver());
+ auto handle = mojom::blink::FileSystemAccessHandle::NewFile(
+ std::move(pending_remote));
+ auto entry = mojom::blink::FileSystemAccessEntry::New(std::move(handle),
+ "foo.txt");
+ Vector<mojom::blink::FileSystemAccessEntryPtr> entries;
+ entries.push_back(std::move(entry));
+
+ std::move(callback).Run(std::move(error), std::move(entries));
+ }));
+ ClassicScript::CreateUnspecifiedScript(
+ ScriptSourceCode("window.showOpenFilePicker();"))
+ ->RunScript(GetFrame().DomWindow());
+ manager_run_loop.Run();
+
+ // Mock Manager finished sending data over the mojo pipe.
+ // Clearing the user activation.
+ frame->ClearUserActivation();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+
+ // Let blink-side receiver process the response and set the user activation
+ // again.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(frame->HasStickyUserActivation());
+}
+
+TEST_F(GlobalFileSystemAccessTest, UserActivationChooseEntriesErrors) {
+ LocalFrame* frame = &GetFrame();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+
+ using mojom::blink::FileSystemAccessStatus;
+
+ FileSystemAccessStatus statuses[] = {
+ FileSystemAccessStatus::kPermissionDenied,
+ FileSystemAccessStatus::kInvalidState,
+ FileSystemAccessStatus::kInvalidArgument,
+ FileSystemAccessStatus::kOperationFailed,
+ // kOperationAborted is when the user cancels the file selection.
+ FileSystemAccessStatus::kOperationAborted,
+ };
+ MockFileSystemAccessManager manager(frame->GetBrowserInterfaceBroker());
+
+ for (const FileSystemAccessStatus& status : statuses) {
+ LocalFrame::NotifyUserActivation(
+ frame, mojom::UserActivationNotificationType::kTest);
+ EXPECT_TRUE(frame->HasStickyUserActivation());
+
+ base::RunLoop manager_run_loop;
+ manager.SetQuitClosure(manager_run_loop.QuitClosure());
+ manager.SetChooseEntriesResponse(WTF::Bind(
+ [](mojom::blink::FileSystemAccessStatus status,
+ MockFileSystemAccessManager::ChooseEntriesCallback callback) {
+ auto error = mojom::blink::FileSystemAccessError::New();
+ error->status = status;
+ error->message = "";
+ Vector<mojom::blink::FileSystemAccessEntryPtr> entries;
+
+ std::move(callback).Run(std::move(error), std::move(entries));
+ },
+ status));
+ ClassicScript::CreateUnspecifiedScript(
+ ScriptSourceCode("window.showOpenFilePicker();"))
+ ->RunScript(GetFrame().DomWindow());
+ manager_run_loop.Run();
+
+ // Mock Manager finished sending data over the mojo pipe.
+ // Clearing the user activation.
+ frame->ClearUserActivation();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(frame->HasStickyUserActivation());
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
deleted file mode 100644
index 10f759dca77..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
+++ /dev/null
@@ -1,314 +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/file_system_access/global_native_file_system.h"
-
-#include <utility>
-
-#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/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_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"
-#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/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/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"
-#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/text/ascii_ctype.h"
-
-namespace blink {
-
-namespace {
-
-constexpr bool IsHTTPWhitespace(UChar chr) {
- return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
-}
-
-bool IsValidSuffixCodePoint(UChar chr) {
- return IsASCIIAlphanumeric(chr) || chr == '+' || chr == '.';
-}
-
-bool VerifyIsValidExtension(const String& extension,
- ExceptionState& exception_state) {
- if (!extension.StartsWith(".")) {
- exception_state.ThrowTypeError("Extension '" + extension +
- "' must start with '.'.");
- return false;
- }
- if (!extension.IsAllSpecialCharacters<IsValidSuffixCodePoint>()) {
- exception_state.ThrowTypeError("Extension '" + extension +
- "' contains invalid characters.");
- return false;
- }
- if (extension.EndsWith(".")) {
- exception_state.ThrowTypeError("Extension '" + extension +
- "' must not end with '.'.");
- return false;
- }
- if (extension.length() > 16) {
- exception_state.ThrowTypeError("Extension '" + extension +
- "' cannot be longer than 16 characters.");
- return false;
- }
-
- return true;
-}
-
-bool AddExtension(const String& extension,
- Vector<String>& extensions,
- ExceptionState& exception_state) {
- if (!VerifyIsValidExtension(extension, exception_state))
- return false;
-
- extensions.push_back(extension.Substring(1));
- return true;
-}
-
-Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts(
- const HeapVector<Member<FilePickerAcceptType>>& types,
- ExceptionState& exception_state) {
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> result;
- result.ReserveInitialCapacity(types.size());
- for (const auto& t : types) {
- Vector<String> mimeTypes;
- mimeTypes.ReserveInitialCapacity(t->accept().size());
- Vector<String> extensions;
- for (const auto& a : t->accept()) {
- String type = a.first.StripWhiteSpace(IsHTTPWhitespace);
- if (type.IsEmpty()) {
- exception_state.ThrowTypeError("Invalid type: " + a.first);
- return {};
- }
- Vector<String> parsed_type;
- type.Split('/', true, parsed_type);
- if (parsed_type.size() != 2) {
- exception_state.ThrowTypeError("Invalid type: " + a.first);
- return {};
- }
- if (!IsValidHTTPToken(parsed_type[0])) {
- exception_state.ThrowTypeError("Invalid type: " + a.first);
- return {};
- }
- if (!IsValidHTTPToken(parsed_type[1])) {
- exception_state.ThrowTypeError("Invalid type: " + a.first);
- return {};
- }
-
- mimeTypes.push_back(type);
- if (a.second.IsUSVString()) {
- if (!AddExtension(a.second.GetAsUSVString(), extensions,
- exception_state))
- return {};
- } else {
- for (const auto& extension : a.second.GetAsUSVStringSequence()) {
- if (!AddExtension(extension, extensions, exception_state))
- return {};
- }
- }
- }
- result.emplace_back(
- blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New(
- t->hasDescription() ? t->description() : g_empty_string,
- std::move(mimeTypes), std::move(extensions)));
- }
- return result;
-}
-
-void VerifyIsAllowedToShowFilePicker(const LocalDOMWindow& window,
- ExceptionState& exception_state) {
- if (!window.IsCurrentlyDisplayedInFrame()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kAbortError, "");
- return;
- }
-
- if (!window.GetSecurityOrigin()->CanAccessNativeFileSystem()) {
- if (window.IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
- exception_state.ThrowSecurityError(
- "Sandboxed documents aren't allowed to show a file picker.");
- return;
- } else {
- exception_state.ThrowSecurityError(
- "This document isn't allowed to show a file picker.");
- return;
- }
- }
-
- LocalFrame* local_frame = window.GetFrame();
- if (!local_frame || local_frame->IsCrossOriginToMainFrame()) {
- exception_state.ThrowSecurityError(
- "Cross origin sub frames aren't allowed to show a file picker.");
- return;
- }
-
- if (!LocalFrame::HasTransientUserActivation(local_frame)) {
- exception_state.ThrowSecurityError(
- "Must be handling a user gesture to show a file picker.");
- return;
- }
-}
-
-ScriptPromise ShowFilePickerImpl(
- ScriptState* script_state,
- LocalDOMWindow& window,
- mojom::blink::ChooseFileSystemEntryType chooser_type,
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
- bool accept_all,
- bool return_as_sequence) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise resolver_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;
- window.GetBrowserInterfaceBroker().GetInterface(
- manager.BindNewPipeAndPassReceiver());
-
- auto* raw_manager = manager.get();
- raw_manager->ChooseEntries(
- chooser_type, std::move(accepts), accept_all,
- WTF::Bind(
- [](ScriptPromiseResolver* resolver,
- mojo::Remote<mojom::blink::NativeFileSystemManager>,
- bool return_as_sequence, LocalFrame* local_frame,
- mojom::blink::NativeFileSystemErrorPtr file_operation_result,
- Vector<mojom::blink::NativeFileSystemEntryPtr> entries) {
- ExecutionContext* context = resolver->GetExecutionContext();
- if (!context)
- return;
- if (file_operation_result->status !=
- mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver,
- *file_operation_result);
- return;
- }
-
- // While it would be better to not trust the renderer process,
- // we're doing this here to avoid potential mojo message pipe
- // ordering problems, where the frame activation state
- // reconciliation messages would compete with concurrent Native File
- // System messages to the browser.
- // TODO(https://crbug.com/1017270): Remove this after spec change,
- // or when activation moves to browser.
- LocalFrame::NotifyUserActivation(
- local_frame, mojom::blink::UserActivationNotificationType::
- kNativeFileSystem);
-
- if (return_as_sequence) {
- HeapVector<Member<NativeFileSystemHandle>> results;
- results.ReserveInitialCapacity(entries.size());
- for (auto& entry : entries) {
- results.push_back(NativeFileSystemHandle::CreateFromMojoEntry(
- std::move(entry), context));
- }
- resolver->Resolve(results);
- } else {
- DCHECK_EQ(1u, entries.size());
- resolver->Resolve(NativeFileSystemHandle::CreateFromMojoEntry(
- std::move(entries[0]), context));
- }
- },
- WrapPersistent(resolver), std::move(manager), return_as_sequence,
- WrapPersistent(window.GetFrame())));
- return resolver_result;
-}
-
-} // namespace
-
-// static
-ScriptPromise GlobalNativeFileSystem::showOpenFilePicker(
- ScriptState* script_state,
- LocalDOMWindow& window,
- const OpenFilePickerOptions* options,
- ExceptionState& exception_state) {
- UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
-
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
- if (options->hasTypes())
- accepts = ConvertAccepts(options->types(), exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- if (accepts.IsEmpty() && options->excludeAcceptAllOption()) {
- exception_state.ThrowTypeError("Need at least one accepted type");
- return ScriptPromise();
- }
-
- VerifyIsAllowedToShowFilePicker(window, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- return ShowFilePickerImpl(
- script_state, window,
- options->multiple()
- ? mojom::blink::ChooseFileSystemEntryType::kOpenMultipleFiles
- : mojom::blink::ChooseFileSystemEntryType::kOpenFile,
- std::move(accepts), !options->excludeAcceptAllOption(),
- /*return_as_sequence=*/true);
-}
-
-// static
-ScriptPromise GlobalNativeFileSystem::showSaveFilePicker(
- ScriptState* script_state,
- LocalDOMWindow& window,
- const SaveFilePickerOptions* options,
- ExceptionState& exception_state) {
- UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
-
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
- if (options->hasTypes())
- accepts = ConvertAccepts(options->types(), exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- if (accepts.IsEmpty() && options->excludeAcceptAllOption()) {
- exception_state.ThrowTypeError("Need at least one accepted type");
- return ScriptPromise();
- }
-
- VerifyIsAllowedToShowFilePicker(window, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- return ShowFilePickerImpl(
- script_state, window, mojom::blink::ChooseFileSystemEntryType::kSaveFile,
- std::move(accepts), !options->excludeAcceptAllOption(),
- /*return_as_sequence=*/false);
-}
-
-// static
-ScriptPromise GlobalNativeFileSystem::showDirectoryPicker(
- ScriptState* script_state,
- LocalDOMWindow& window,
- const DirectoryPickerOptions* options,
- ExceptionState& exception_state) {
- UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
-
- VerifyIsAllowedToShowFilePicker(window, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- return ShowFilePickerImpl(
- script_state, window,
- mojom::blink::ChooseFileSystemEntryType::kOpenDirectory, {},
- /*accept_all=*/true,
- /*return_as_sequence=*/false);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h
deleted file mode 100644
index e0ee3bca43e..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h
+++ /dev/null
@@ -1,41 +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_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 OpenFilePickerOptions;
-class SaveFilePickerOptions;
-class DirectoryPickerOptions;
-class ExceptionState;
-class LocalDOMWindow;
-class ScriptPromise;
-class ScriptState;
-
-class GlobalNativeFileSystem {
- STATIC_ONLY(GlobalNativeFileSystem);
-
- public:
- static ScriptPromise showOpenFilePicker(ScriptState*,
- LocalDOMWindow&,
- const OpenFilePickerOptions*,
- ExceptionState&);
- static ScriptPromise showSaveFilePicker(ScriptState*,
- LocalDOMWindow&,
- const SaveFilePickerOptions*,
- ExceptionState&);
- static ScriptPromise showDirectoryPicker(ScriptState*,
- LocalDOMWindow&,
- const DirectoryPickerOptions*,
- ExceptionState&);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_NATIVE_FILE_SYSTEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc
deleted file mode 100644
index b77e4494e37..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc
+++ /dev/null
@@ -1,234 +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/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/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"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/script/classic_script.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-
-namespace blink {
-
-class MockNativeFileSystemManager
- : public mojom::blink::NativeFileSystemManager {
- public:
- MockNativeFileSystemManager(BrowserInterfaceBrokerProxy& broker,
- base::OnceClosure reached_callback)
- : reached_callback_(std::move(reached_callback)), broker_(broker) {
- broker_.SetBinderForTesting(
- mojom::blink::NativeFileSystemManager::Name_,
- WTF::BindRepeating(
- &MockNativeFileSystemManager::BindNativeFileSystemManager,
- WTF::Unretained(this)));
- }
- MockNativeFileSystemManager(BrowserInterfaceBrokerProxy& broker)
- : broker_(broker) {
- broker_.SetBinderForTesting(
- mojom::blink::NativeFileSystemManager::Name_,
- WTF::BindRepeating(
- &MockNativeFileSystemManager::BindNativeFileSystemManager,
- WTF::Unretained(this)));
- }
- ~MockNativeFileSystemManager() override {
- broker_.SetBinderForTesting(mojom::blink::NativeFileSystemManager::Name_,
- {});
- }
-
- using ChooseEntriesResponseCallback =
- base::OnceCallback<void(ChooseEntriesCallback callback)>;
-
- void SetQuitClosure(base::OnceClosure reached_callback) {
- reached_callback_ = std::move(reached_callback);
- }
-
- // Unused for these tests.
- void GetSandboxedFileSystem(
- GetSandboxedFileSystemCallback callback) override {}
-
- void ChooseEntries(
- mojom::ChooseFileSystemEntryType type,
- WTF::Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
- bool include_accepts_all,
- ChooseEntriesCallback callback) override {
- if (choose_entries_response_callback_) {
- std::move(choose_entries_response_callback_).Run(std::move(callback));
- }
-
- if (reached_callback_)
- std::move(reached_callback_).Run();
- }
-
- void SetChooseEntriesResponse(ChooseEntriesResponseCallback callback) {
- choose_entries_response_callback_ = std::move(callback);
- }
-
- void GetFileHandleFromToken(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>,
- mojo::PendingReceiver<mojom::blink::NativeFileSystemFileHandle>)
- override {}
-
- void GetDirectoryHandleFromToken(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>,
- mojo::PendingReceiver<mojom::blink::NativeFileSystemDirectoryHandle>)
- override {}
-
- void GetEntryFromDragDropToken(
- mojo::PendingRemote<blink::mojom::blink::NativeFileSystemDragDropToken>
- token,
- GetEntryFromDragDropTokenCallback callback) override {}
-
- private:
- void BindNativeFileSystemManager(mojo::ScopedMessagePipeHandle handle) {
- receivers_.Add(this,
- mojo::PendingReceiver<mojom::blink::NativeFileSystemManager>(
- std::move(handle)));
- }
-
- base::OnceClosure reached_callback_;
- ChooseEntriesResponseCallback choose_entries_response_callback_;
- mojo::ReceiverSet<mojom::blink::NativeFileSystemManager> receivers_;
- BrowserInterfaceBrokerProxy& broker_;
-};
-
-class GlobalNativeFileSystemTest : public PageTestBase {
- public:
- void SetUp() override {
- PageTestBase::SetUp();
- Navigate("http://localhost");
- GetDocument().GetSettings()->SetScriptEnabled(true);
- }
-
- void Navigate(const String& destinationUrl) {
- const KURL& url = KURL(NullURL(), destinationUrl);
- auto navigation_params =
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(), url);
- GetDocument().GetFrame()->Loader().CommitNavigation(
- std::move(navigation_params), /*extra_data=*/nullptr);
- blink::test::RunPendingTasks();
- ASSERT_EQ(url.GetString(), GetDocument().Url().GetString());
- }
-};
-
-TEST_F(GlobalNativeFileSystemTest, UserActivationRequiredOtherwiseDenied) {
- LocalFrame* frame = &GetFrame();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-
- MockNativeFileSystemManager manager(frame->GetBrowserInterfaceBroker());
- manager.SetChooseEntriesResponse(WTF::Bind(
- [](MockNativeFileSystemManager::ChooseEntriesCallback callback) {
- FAIL();
- }));
- ClassicScript::CreateUnspecifiedScript(
- ScriptSourceCode("window.showOpenFilePicker();"))
- ->RunScript(GetFrame().DomWindow());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-}
-
-TEST_F(GlobalNativeFileSystemTest, UserActivationChooseEntriesSuccessful) {
- LocalFrame* frame = &GetFrame();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-
- LocalFrame::NotifyUserActivation(
- frame, mojom::UserActivationNotificationType::kTest);
- EXPECT_TRUE(frame->HasStickyUserActivation());
-
- base::RunLoop manager_run_loop;
- MockNativeFileSystemManager manager(frame->GetBrowserInterfaceBroker(),
- manager_run_loop.QuitClosure());
- manager.SetChooseEntriesResponse(WTF::Bind(
- [](MockNativeFileSystemManager::ChooseEntriesCallback callback) {
- auto error = mojom::blink::NativeFileSystemError::New();
- error->status = mojom::blink::NativeFileSystemStatus::kOk;
- error->message = "";
-
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle>
- pending_remote;
- ignore_result(pending_remote.InitWithNewPipeAndPassReceiver());
- auto handle = mojom::blink::NativeFileSystemHandle::NewFile(
- std::move(pending_remote));
- auto entry = mojom::blink::NativeFileSystemEntry::New(std::move(handle),
- "foo.txt");
- Vector<mojom::blink::NativeFileSystemEntryPtr> entries;
- entries.push_back(std::move(entry));
-
- std::move(callback).Run(std::move(error), std::move(entries));
- }));
- ClassicScript::CreateUnspecifiedScript(
- ScriptSourceCode("window.showOpenFilePicker();"))
- ->RunScript(GetFrame().DomWindow());
- manager_run_loop.Run();
-
- // Mock Manager finished sending data over the mojo pipe.
- // Clearing the user activation.
- frame->ClearUserActivation();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-
- // Let blink-side receiver process the response and set the user activation
- // again.
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(frame->HasStickyUserActivation());
-}
-
-TEST_F(GlobalNativeFileSystemTest, UserActivationChooseEntriesErrors) {
- LocalFrame* frame = &GetFrame();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-
- using mojom::blink::NativeFileSystemStatus;
-
- NativeFileSystemStatus statuses[] = {
- NativeFileSystemStatus::kPermissionDenied,
- NativeFileSystemStatus::kInvalidState,
- NativeFileSystemStatus::kInvalidArgument,
- NativeFileSystemStatus::kOperationFailed,
- // kOperationAborted is when the user cancels the file selection.
- NativeFileSystemStatus::kOperationAborted,
- };
- MockNativeFileSystemManager manager(frame->GetBrowserInterfaceBroker());
-
- for (const NativeFileSystemStatus& status : statuses) {
- LocalFrame::NotifyUserActivation(
- frame, mojom::UserActivationNotificationType::kTest);
- EXPECT_TRUE(frame->HasStickyUserActivation());
-
- base::RunLoop manager_run_loop;
- manager.SetQuitClosure(manager_run_loop.QuitClosure());
- manager.SetChooseEntriesResponse(WTF::Bind(
- [](mojom::blink::NativeFileSystemStatus status,
- MockNativeFileSystemManager::ChooseEntriesCallback callback) {
- auto error = mojom::blink::NativeFileSystemError::New();
- error->status = status;
- error->message = "";
- Vector<mojom::blink::NativeFileSystemEntryPtr> entries;
-
- std::move(callback).Run(std::move(error), std::move(entries));
- },
- status));
- ClassicScript::CreateUnspecifiedScript(
- ScriptSourceCode("window.showOpenFilePicker();"))
- ->RunScript(GetFrame().DomWindow());
- manager_run_loop.Run();
-
- // Mock Manager finished sending data over the mojo pipe.
- // Clearing the user activation.
- frame->ClearUserActivation();
- EXPECT_FALSE(frame->HasStickyUserActivation());
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(frame->HasStickyUserActivation());
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni b/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni
index a3b719a6670..2d4f3232423 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni
@@ -3,7 +3,7 @@
# found in the LICENSE file.
modules_idl_files = [
- "native_file_system_directory_iterator.idl",
+ "file_system_directory_iterator.idl",
"file_system_directory_handle.idl",
"file_system_file_handle.idl",
"file_system_handle.idl",
@@ -14,7 +14,7 @@ modules_dictionary_idl_files = [
"directory_picker_options.idl",
"file_picker_accept_type.idl",
"file_picker_options.idl",
- "file_system_create_writer_options.idl",
+ "file_system_create_writable_options.idl",
"file_system_get_directory_options.idl",
"file_system_get_file_options.idl",
"file_system_handle_permission_descriptor.idl",
@@ -25,7 +25,7 @@ modules_dictionary_idl_files = [
]
modules_dependency_idl_files = [
- "data_transfer_item_native_file_system.idl",
- "storage_manager_native_file_system.idl",
- "window_native_file_system.idl",
+ "data_transfer_item_file_system_access.idl",
+ "storage_manager_file_system_access.idl",
+ "window_file_system_access.idl",
]
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc
deleted file mode 100644
index 2e008314ac7..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc
+++ /dev/null
@@ -1,274 +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/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/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"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_get_directory_options.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_get_file_options.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_remove_options.h"
-#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/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 {
-
-using mojom::blink::NativeFileSystemErrorPtr;
-
-NativeFileSystemDirectoryHandle::NativeFileSystemDirectoryHandle(
- ExecutionContext* context,
- const String& name,
- mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle> mojo_ptr)
- : NativeFileSystemHandle(context, name), mojo_ptr_(context) {
- mojo_ptr_.Bind(std::move(mojo_ptr),
- context->GetTaskRunner(TaskType::kMiscPlatformAPI));
- DCHECK(mojo_ptr_.is_bound());
-}
-
-NativeFileSystemDirectoryIterator* NativeFileSystemDirectoryHandle::entries() {
- return MakeGarbageCollected<NativeFileSystemDirectoryIterator>(
- this, NativeFileSystemDirectoryIterator::Mode::kKeyValue,
- GetExecutionContext());
-}
-
-NativeFileSystemDirectoryIterator* NativeFileSystemDirectoryHandle::keys() {
- return MakeGarbageCollected<NativeFileSystemDirectoryIterator>(
- this, NativeFileSystemDirectoryIterator::Mode::kKey,
- GetExecutionContext());
-}
-
-NativeFileSystemDirectoryIterator* NativeFileSystemDirectoryHandle::values() {
- return MakeGarbageCollected<NativeFileSystemDirectoryIterator>(
- this, NativeFileSystemDirectoryIterator::Mode::kValue,
- GetExecutionContext());
-}
-
-ScriptPromise NativeFileSystemDirectoryHandle::getFileHandle(
- ScriptState* script_state,
- const String& name,
- const FileSystemGetFileOptions* options) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- mojo_ptr_->GetFile(
- name, options->create(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, const String& name,
- NativeFileSystemErrorPtr result,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle>
- 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<NativeFileSystemFileHandle>(
- context, name, std::move(handle)));
- },
- WrapPersistent(resolver), name));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemDirectoryHandle::getDirectoryHandle(
- ScriptState* script_state,
- const String& name,
- const FileSystemGetDirectoryOptions* options) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- if (!mojo_ptr_.is_bound()) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError));
- return result;
- }
-
- mojo_ptr_->GetDirectory(
- name, options->create(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, const String& name,
- 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, name, std::move(handle)));
- },
- WrapPersistent(resolver), name));
-
- return result;
-}
-
-namespace {
-
-void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
- V8SetReturnValue(info, info.Data());
-}
-
-} // namespace
-
-ScriptValue NativeFileSystemDirectoryHandle::getEntries(
- ScriptState* script_state) {
- auto* iterator = MakeGarbageCollected<NativeFileSystemDirectoryIterator>(
- this, NativeFileSystemDirectoryIterator::Mode::kValue,
- ExecutionContext::From(script_state));
- auto* isolate = script_state->GetIsolate();
- auto context = script_state->GetContext();
- v8::Local<v8::Object> result = v8::Object::New(isolate);
- if (!result
- ->Set(context, v8::Symbol::GetAsyncIterator(isolate),
- v8::Function::New(context, &ReturnDataFunction,
- ToV8(iterator, script_state))
- .ToLocalChecked())
- .ToChecked()) {
- return ScriptValue();
- }
- return ScriptValue(script_state->GetIsolate(), result);
-}
-
-ScriptPromise NativeFileSystemDirectoryHandle::removeEntry(
- ScriptState* script_state,
- const String& name,
- const FileSystemRemoveOptions* options) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- if (!mojo_ptr_.is_bound()) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError));
- return result;
- }
-
- mojo_ptr_->RemoveEntry(
- name, options->recursive(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, NativeFileSystemErrorPtr result) {
- native_file_system_error::ResolveOrReject(resolver, *result);
- },
- WrapPersistent(resolver)));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemDirectoryHandle::resolve(
- ScriptState* script_state,
- NativeFileSystemHandle* possible_child) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- if (!mojo_ptr_.is_bound()) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError));
- return result;
- }
-
- mojo_ptr_->Resolve(
- possible_child->Transfer(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, NativeFileSystemErrorPtr result,
- const base::Optional<Vector<String>>& path) {
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
- if (!path.has_value()) {
- resolver->Resolve(static_cast<ScriptWrappable*>(nullptr));
- return;
- }
- resolver->Resolve(*path);
- },
- WrapPersistent(resolver)));
-
- return result;
-}
-
-mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
-NativeFileSystemDirectoryHandle::Transfer() {
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> result;
- if (mojo_ptr_.is_bound())
- mojo_ptr_->Transfer(result.InitWithNewPipeAndPassReceiver());
- return result;
-}
-
-void NativeFileSystemDirectoryHandle::Trace(Visitor* visitor) const {
- visitor->Trace(mojo_ptr_);
- NativeFileSystemHandle::Trace(visitor);
-}
-
-void NativeFileSystemDirectoryHandle::QueryPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
- return;
- }
- mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
-}
-
-void NativeFileSystemDirectoryHandle::RequestPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- mojom::blink::PermissionStatus)> callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(
- mojom::blink::NativeFileSystemError::New(
- mojom::blink::NativeFileSystemStatus::kInvalidState,
- base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
- mojom::blink::PermissionStatus::DENIED);
- return;
- }
-
- mojo_ptr_->RequestPermission(writable, std::move(callback));
-}
-
-void NativeFileSystemDirectoryHandle::IsSameEntryImpl(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> other,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr, bool)>
- callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(
- mojom::blink::NativeFileSystemError::New(
- mojom::blink::NativeFileSystemStatus::kInvalidState,
- base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
- false);
- return;
- }
-
- mojo_ptr_->Resolve(
- std::move(other),
- WTF::Bind(
- [](base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- bool)> callback,
- NativeFileSystemErrorPtr result,
- const base::Optional<Vector<String>>& path) {
- std::move(callback).Run(std::move(result),
- path.has_value() && path->IsEmpty());
- },
- std::move(callback)));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h
deleted file mode 100644
index d3a18ea1afd..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef 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/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 NativeFileSystemDirectoryIterator;
-
-class NativeFileSystemDirectoryHandle final : public NativeFileSystemHandle {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- NativeFileSystemDirectoryHandle(
- ExecutionContext* context,
- const String& name,
- mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle>);
-
- // FileSystemDirectoryHandle IDL interface:
- NativeFileSystemDirectoryIterator* entries();
- NativeFileSystemDirectoryIterator* keys();
- NativeFileSystemDirectoryIterator* values();
-
- bool isDirectory() const override { return true; }
-
- ScriptPromise getFileHandle(ScriptState*,
- const String& name,
- const FileSystemGetFileOptions*);
- ScriptPromise getDirectoryHandle(ScriptState*,
- const String& name,
- const FileSystemGetDirectoryOptions*);
- ScriptValue getEntries(ScriptState*);
- ScriptPromise removeEntry(ScriptState*,
- const String& name,
- const FileSystemRemoveOptions*);
-
- ScriptPromise resolve(ScriptState*, NativeFileSystemHandle* possible_child);
-
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> Transfer()
- override;
-
- mojom::blink::NativeFileSystemDirectoryHandle* MojoHandle() {
- return mojo_ptr_.get();
- }
-
- void Trace(Visitor*) const override;
-
- private:
- void QueryPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
- void RequestPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- mojom::blink::PermissionStatus)>) override;
- // IsSameEntry for directories is implemented in terms of resolve, as resolve
- // also can be used to figure out if two directories are the same entry.
- void IsSameEntryImpl(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> other,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr, bool)>)
- override;
-
- HeapMojoRemote<mojom::blink::NativeFileSystemDirectoryHandle> mojo_ptr_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc
deleted file mode 100644
index 17b84cc5daa..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/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/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 {
-
-NativeFileSystemDirectoryIterator::NativeFileSystemDirectoryIterator(
- NativeFileSystemDirectoryHandle* directory,
- Mode mode,
- ExecutionContext* execution_context)
- : ExecutionContextClient(execution_context),
- mode_(mode),
- directory_(directory),
- receiver_(this, execution_context) {
- directory_->MojoHandle()->GetEntries(receiver_.BindNewPipeAndPassRemote(
- execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
-}
-
-ScriptPromise NativeFileSystemDirectoryIterator::next(
- ScriptState* script_state) {
- if (error_) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- auto result = resolver->Promise();
- native_file_system_error::Reject(resolver, *error_);
- return result;
- }
-
- if (!entries_.IsEmpty()) {
- NativeFileSystemHandle* handle = entries_.TakeFirst();
- ScriptValue result;
- switch (mode_) {
- case Mode::kKey:
- result = V8IteratorResult(script_state, handle->name());
- break;
- case Mode::kValue:
- result = V8IteratorResult(script_state, handle);
- break;
- case Mode::kKeyValue:
- HeapVector<ScriptValue, 2> keyvalue;
- keyvalue.push_back(ScriptValue(script_state->GetIsolate(),
- ToV8(handle->name(), script_state)));
- keyvalue.push_back(ScriptValue(script_state->GetIsolate(),
- ToV8(handle, script_state)));
- result = V8IteratorResult(script_state, keyvalue);
- break;
- }
- return ScriptPromise::Cast(script_state, result);
- }
-
- if (waiting_for_more_entries_) {
- DCHECK(!pending_next_);
- pending_next_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- return pending_next_->Promise();
- }
-
- return ScriptPromise::Cast(script_state, V8IteratorResultDone(script_state));
-}
-
-bool NativeFileSystemDirectoryIterator::HasPendingActivity() const {
- return pending_next_;
-}
-
-void NativeFileSystemDirectoryIterator::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
- visitor->Trace(receiver_);
- visitor->Trace(entries_);
- visitor->Trace(pending_next_);
- visitor->Trace(directory_);
-}
-
-void NativeFileSystemDirectoryIterator::DidReadDirectory(
- mojom::blink::NativeFileSystemErrorPtr result,
- Vector<mojom::blink::NativeFileSystemEntryPtr> entries,
- bool has_more_entries) {
- if (!GetExecutionContext())
- return;
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- error_ = std::move(result);
- if (pending_next_) {
- native_file_system_error::Reject(pending_next_, *error_);
- pending_next_ = nullptr;
- }
- return;
- }
- for (auto& e : entries) {
- entries_.push_back(NativeFileSystemHandle::CreateFromMojoEntry(
- std::move(e), GetExecutionContext()));
- }
- waiting_for_more_entries_ = has_more_entries;
- if (pending_next_) {
- ScriptState::Scope scope(pending_next_->GetScriptState());
- pending_next_->Resolve(
- next(pending_next_->GetScriptState()).GetScriptValue());
- pending_next_ = nullptr;
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h
deleted file mode 100644
index 256822f4af7..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_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/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"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
-
-namespace blink {
-class NativeFileSystemDirectoryHandle;
-class NativeFileSystemHandle;
-class ScriptPromise;
-class ScriptPromiseResolver;
-class ScriptState;
-
-class NativeFileSystemDirectoryIterator final
- : public ScriptWrappable,
- public ActiveScriptWrappable<NativeFileSystemDirectoryIterator>,
- public ExecutionContextClient,
- public mojom::blink::NativeFileSystemDirectoryEntriesListener {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- // Should this iterator returns keys, values or both?
- enum Mode { kKey, kValue, kKeyValue };
-
- NativeFileSystemDirectoryIterator(NativeFileSystemDirectoryHandle* directory,
- Mode mode,
- ExecutionContext* execution_context);
-
- ScriptPromise next(ScriptState*);
-
- // ScriptWrappable:
- bool HasPendingActivity() const final;
-
- void Trace(Visitor*) const override;
-
- private:
- void DidReadDirectory(mojom::blink::NativeFileSystemErrorPtr result,
- Vector<mojom::blink::NativeFileSystemEntryPtr> entries,
- bool has_more_entries) override;
-
- Mode mode_;
- mojom::blink::NativeFileSystemErrorPtr error_;
- bool waiting_for_more_entries_ = true;
- HeapDeque<Member<NativeFileSystemHandle>> entries_;
- Member<ScriptPromiseResolver> pending_next_;
- Member<NativeFileSystemDirectoryHandle> directory_;
- HeapMojoReceiver<mojom::blink::NativeFileSystemDirectoryEntriesListener,
- NativeFileSystemDirectoryIterator,
- HeapMojoWrapperMode::kWithoutContextObserver>
- receiver_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl
deleted file mode 100644
index 59a4c983865..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl
+++ /dev/null
@@ -1,14 +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.
-
-// Async iterator returned by FileSystemDirectoryHandle.getEntries().
-// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
-// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface
-[
- LegacyNoInterfaceObject,
- ActiveScriptWrappable,
- RuntimeEnabled=NativeFileSystem
-] interface NativeFileSystemDirectoryIterator {
- [CallWith=ScriptState] Promise<any> next();
-};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc
deleted file mode 100644
index 97c366d6f88..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.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/file_system_access/native_file_system_error.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"
-#include "third_party/blink/renderer/core/fileapi/file_error.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-
-namespace blink {
-namespace native_file_system_error {
-
-void Reject(ScriptPromiseResolver* resolver,
- const mojom::blink::NativeFileSystemError& error) {
- DCHECK_NE(error.status, mojom::blink::NativeFileSystemStatus::kOk);
- ResolveOrReject(resolver, error);
-}
-
-void ResolveOrReject(ScriptPromiseResolver* resolver,
- const mojom::blink::NativeFileSystemError& error) {
- // Early exit if the resolver's context has been destroyed already.
- if (!resolver->GetScriptState()->ContextIsValid())
- return;
- auto* const isolate = resolver->GetScriptState()->GetIsolate();
- ScriptState::Scope scope(resolver->GetScriptState());
-
- // Convert empty message to a null string, to make sure we get the default
- // error message if no custom error message is provided.
- const String message = error.message.IsEmpty() ? String() : error.message;
-
- switch (error.status) {
- case mojom::blink::NativeFileSystemStatus::kOk:
- resolver->Resolve();
- break;
- case mojom::blink::NativeFileSystemStatus::kPermissionDenied:
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- isolate, DOMExceptionCode::kNotAllowedError, message));
- break;
- case mojom::blink::NativeFileSystemStatus::kSecurityError:
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- isolate, DOMExceptionCode::kSecurityError, message));
- break;
- case mojom::blink::NativeFileSystemStatus::kInvalidState:
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- isolate, DOMExceptionCode::kInvalidStateError, message));
- break;
- case mojom::blink::NativeFileSystemStatus::kInvalidArgument:
- resolver->Reject(V8ThrowException::CreateTypeError(
- resolver->GetScriptState()->GetIsolate(), message));
- break;
- case mojom::blink::NativeFileSystemStatus::kOperationFailed:
- case mojom::blink::NativeFileSystemStatus::kOperationAborted:
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- isolate, DOMExceptionCode::kAbortError, message));
- break;
- case mojom::blink::NativeFileSystemStatus::kFileError:
- // TODO(mek): We might want to support custom messages for these cases.
- resolver->Reject(file_error::CreateDOMException(error.file_error));
- break;
- }
-}
-
-} // namespace native_file_system_error
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h
deleted file mode 100644
index f7aa988b0c2..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h
+++ /dev/null
@@ -1,28 +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_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/file_system_access/native_file_system_error.mojom-blink-forward.h"
-
-namespace blink {
-class ScriptPromiseResolver;
-namespace native_file_system_error {
-
-// Rejects |resolver| with an appropriate exception if |status| represents an
-// error. Resolves |resolver| with undefined otherwise.
-void ResolveOrReject(ScriptPromiseResolver* resolver,
- const mojom::blink::NativeFileSystemError& status);
-
-// Rejects |resolver| with an appropriate exception if |status| represents an
-// error. DCHECKs otherwise.
-void Reject(ScriptPromiseResolver* resolver,
- const mojom::blink::NativeFileSystemError& error);
-
-} // namespace native_file_system_error
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_ERROR_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc
deleted file mode 100644
index 5ec47c8057a..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc
+++ /dev/null
@@ -1,152 +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/file_system_access/native_file_system_file_handle.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/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"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
-
-namespace blink {
-using mojom::blink::NativeFileSystemErrorPtr;
-
-NativeFileSystemFileHandle::NativeFileSystemFileHandle(
- ExecutionContext* context,
- const String& name,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle> mojo_ptr)
- : NativeFileSystemHandle(context, name), mojo_ptr_(context) {
- mojo_ptr_.Bind(std::move(mojo_ptr),
- context->GetTaskRunner(TaskType::kMiscPlatformAPI));
- DCHECK(mojo_ptr_.is_bound());
-}
-
-ScriptPromise NativeFileSystemFileHandle::createWritable(
- ScriptState* script_state,
- const FileSystemCreateWriterOptions* options,
- ExceptionState& exception_state) {
- if (!mojo_ptr_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "");
- return ScriptPromise();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- mojo_ptr_->CreateFileWriter(
- options->keepExistingData(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver,
- mojom::blink::NativeFileSystemErrorPtr result,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>
- writer) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state)
- return;
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
-
- resolver->Resolve(NativeFileSystemWritableFileStream::Create(
- script_state, std::move(writer)));
- },
- WrapPersistent(resolver)));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemFileHandle::getFile(
- ScriptState* script_state,
- ExceptionState& exception_state) {
- if (!mojo_ptr_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "");
- return ScriptPromise();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- mojo_ptr_->AsBlob(WTF::Bind(
- [](ScriptPromiseResolver* resolver, const String& name,
- NativeFileSystemErrorPtr result, const base::File::Info& info,
- const scoped_refptr<BlobDataHandle>& blob) {
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
- resolver->Resolve(MakeGarbageCollected<File>(
- name, NullableTimeToOptionalTime(info.last_modified), blob));
- },
- WrapPersistent(resolver), name()));
-
- return result;
-}
-
-mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
-NativeFileSystemFileHandle::Transfer() {
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> result;
- if (mojo_ptr_.is_bound())
- mojo_ptr_->Transfer(result.InitWithNewPipeAndPassReceiver());
- return result;
-}
-
-void NativeFileSystemFileHandle::Trace(Visitor* visitor) const {
- visitor->Trace(mojo_ptr_);
- NativeFileSystemHandle::Trace(visitor);
-}
-
-void NativeFileSystemFileHandle::QueryPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
- return;
- }
- mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
-}
-
-void NativeFileSystemFileHandle::RequestPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- mojom::blink::PermissionStatus)> callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(
- mojom::blink::NativeFileSystemError::New(
- mojom::blink::NativeFileSystemStatus::kInvalidState,
- base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
- mojom::blink::PermissionStatus::DENIED);
- return;
- }
-
- mojo_ptr_->RequestPermission(writable, std::move(callback));
-}
-
-void NativeFileSystemFileHandle::IsSameEntryImpl(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> other,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr, bool)>
- callback) {
- if (!mojo_ptr_.is_bound()) {
- std::move(callback).Run(
- mojom::blink::NativeFileSystemError::New(
- mojom::blink::NativeFileSystemStatus::kInvalidState,
- base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"),
- false);
- return;
- }
-
- mojo_ptr_->IsSameEntry(std::move(other), std::move(callback));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h
deleted file mode 100644
index 47ef04abc10..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h
+++ /dev/null
@@ -1,59 +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_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/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 {
-class FileSystemCreateWriterOptions;
-
-class NativeFileSystemFileHandle final : public NativeFileSystemHandle {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- NativeFileSystemFileHandle(
- ExecutionContext* context,
- const String& name,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle>);
-
- bool isFile() const override { return true; }
-
- ScriptPromise createWritable(ScriptState*,
- const FileSystemCreateWriterOptions* options,
- ExceptionState&);
- ScriptPromise getFile(ScriptState*, ExceptionState&);
-
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> Transfer()
- override;
-
- mojom::blink::NativeFileSystemFileHandle* MojoHandle() {
- return mojo_ptr_.get();
- }
-
- void Trace(Visitor*) const override;
-
- private:
- void QueryPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
- void RequestPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- mojom::blink::PermissionStatus)>) override;
- void IsSameEntryImpl(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> other,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr, bool)>)
- override;
-
- HeapMojoRemote<mojom::blink::NativeFileSystemFileHandle> mojo_ptr_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc
deleted file mode 100644
index fc363132f2f..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc
+++ /dev/null
@@ -1,121 +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/file_system_access/native_file_system_handle.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/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 {
-using mojom::blink::NativeFileSystemEntryPtr;
-using mojom::blink::NativeFileSystemErrorPtr;
-
-NativeFileSystemHandle::NativeFileSystemHandle(
- ExecutionContext* execution_context,
- const String& name)
- : ExecutionContextClient(execution_context), name_(name) {}
-
-// static
-NativeFileSystemHandle* NativeFileSystemHandle::CreateFromMojoEntry(
- mojom::blink::NativeFileSystemEntryPtr e,
- ExecutionContext* execution_context) {
- if (e->entry_handle->is_file()) {
- return MakeGarbageCollected<NativeFileSystemFileHandle>(
- execution_context, e->name, std::move(e->entry_handle->get_file()));
- }
- return MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
- execution_context, e->name, std::move(e->entry_handle->get_directory()));
-}
-
-namespace {
-String MojoPermissionStatusToString(mojom::blink::PermissionStatus status) {
- switch (status) {
- case mojom::blink::PermissionStatus::GRANTED:
- return "granted";
- case mojom::blink::PermissionStatus::DENIED:
- return "denied";
- case mojom::blink::PermissionStatus::ASK:
- return "prompt";
- }
- NOTREACHED();
- return "denied";
-}
-
-} // namespace
-
-ScriptPromise NativeFileSystemHandle::queryPermission(
- ScriptState* script_state,
- const FileSystemHandlePermissionDescriptor* descriptor) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- QueryPermissionImpl(
- descriptor->mode() == "readwrite",
- WTF::Bind(
- [](ScriptPromiseResolver* resolver,
- mojom::blink::PermissionStatus result) {
- resolver->Resolve(MojoPermissionStatusToString(result));
- },
- WrapPersistent(resolver)));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemHandle::requestPermission(
- ScriptState* script_state,
- const FileSystemHandlePermissionDescriptor* descriptor) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- RequestPermissionImpl(
- descriptor->mode() == "readwrite",
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, NativeFileSystemErrorPtr result,
- mojom::blink::PermissionStatus status) {
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
- resolver->Resolve(MojoPermissionStatusToString(status));
- },
- WrapPersistent(resolver)));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemHandle::isSameEntry(
- ScriptState* script_state,
- NativeFileSystemHandle* other) {
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- IsSameEntryImpl(
- other->Transfer(),
- WTF::Bind(
- [](ScriptPromiseResolver* resolver, NativeFileSystemErrorPtr result,
- bool same) {
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
- resolver->Resolve(same);
- },
- WrapPersistent(resolver)));
- return result;
-}
-
-void NativeFileSystemHandle::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h
deleted file mode 100644
index 526b941f0a1..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h
+++ /dev/null
@@ -1,72 +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_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/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"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-class ExecutionContext;
-class FileSystemHandlePermissionDescriptor;
-
-class NativeFileSystemHandle : public ScriptWrappable,
- public ExecutionContextClient {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- NativeFileSystemHandle(ExecutionContext* execution_context,
- const String& name);
- static NativeFileSystemHandle* CreateFromMojoEntry(
- mojom::blink::NativeFileSystemEntryPtr,
- ExecutionContext* execution_context);
-
- virtual bool isFile() const { return false; }
- virtual bool isDirectory() const { return false; }
- const String kind() const { return isFile() ? "file" : "directory"; }
- const String& name() const { return name_; }
-
- ScriptPromise queryPermission(ScriptState*,
- const FileSystemHandlePermissionDescriptor*);
- ScriptPromise requestPermission(ScriptState*,
- const FileSystemHandlePermissionDescriptor*);
-
- ScriptPromise isSameEntry(ScriptState*, NativeFileSystemHandle* other);
-
- // Grab a handle to a transfer token. This may return an invalid PendingRemote
- // if the context is already destroyed.
- virtual mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
- Transfer() = 0;
-
- void Trace(Visitor*) const override;
-
- private:
- virtual void QueryPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::PermissionStatus)>) = 0;
- virtual void RequestPermissionImpl(
- bool writable,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- mojom::blink::PermissionStatus)>) = 0;
- virtual void IsSameEntryImpl(
- mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> other,
- base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
- bool)>) = 0;
-
- String name_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc
deleted file mode 100644
index d57e0eac8d0..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc
+++ /dev/null
@@ -1,271 +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/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"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-#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/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"
-
-namespace blink {
-
-NativeFileSystemUnderlyingSink::NativeFileSystemUnderlyingSink(
- ExecutionContext* context,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter> writer_remote)
- : writer_remote_(context) {
- writer_remote_.Bind(std::move(writer_remote),
- context->GetTaskRunner(TaskType::kMiscPlatformAPI));
- DCHECK(writer_remote_.is_bound());
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::start(
- ScriptState* script_state,
- WritableStreamDefaultController* controller,
- ExceptionState& exception_state) {
- return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::write(
- ScriptState* script_state,
- ScriptValue chunk,
- WritableStreamDefaultController* controller,
- ExceptionState& exception_state) {
- v8::Local<v8::Value> value = chunk.V8Value();
-
- ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams input;
- V8ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams::ToImpl(
- script_state->GetIsolate(), value, input,
- UnionTypeConversionMode::kNotNullable, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- if (input.IsNull()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Cannot provide null object");
- return ScriptPromise();
- }
-
- if (input.IsWriteParams()) {
- return HandleParams(script_state, std::move(*input.GetAsWriteParams()),
- exception_state);
- }
-
- ArrayBufferOrArrayBufferViewOrBlobOrUSVString write_data;
- V8ArrayBufferOrArrayBufferViewOrBlobOrUSVString::ToImpl(
- script_state->GetIsolate(), value, write_data,
- UnionTypeConversionMode::kNotNullable, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
- return WriteData(script_state, offset_, std::move(write_data),
- exception_state);
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::close(
- ScriptState* script_state,
- ExceptionState& exception_state) {
- if (!writer_remote_.is_bound() || pending_operation_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Object reached an invalid state");
- return ScriptPromise();
- }
- pending_operation_ =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = pending_operation_->Promise();
- writer_remote_->Close(WTF::Bind(
- &NativeFileSystemUnderlyingSink::CloseComplete, WrapPersistent(this)));
-
- return result;
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::abort(
- ScriptState* script_state,
- ScriptValue reason,
- ExceptionState& exception_state) {
- // The specification guarantees that this will only be called after all
- // pending writes have been aborted. Terminating the remote connection
- // will ensure that the writes are not closed successfully.
- if (writer_remote_.is_bound())
- writer_remote_.reset();
- return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::HandleParams(
- ScriptState* script_state,
- const WriteParams& params,
- ExceptionState& exception_state) {
- if (params.type() == "truncate") {
- if (!params.hasSizeNonNull()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kSyntaxError,
- "Invalid params passed. truncate requires a size argument");
- return ScriptPromise();
- }
- return Truncate(script_state, params.sizeNonNull(), exception_state);
- }
-
- if (params.type() == "seek") {
- if (!params.hasPositionNonNull()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kSyntaxError,
- "Invalid params passed. seek requires a position argument");
- return ScriptPromise();
- }
- return Seek(script_state, params.positionNonNull(), exception_state);
- }
-
- if (params.type() == "write") {
- uint64_t position =
- params.hasPositionNonNull() ? params.positionNonNull() : offset_;
- if (!params.hasData()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kSyntaxError,
- "Invalid params passed. write requires a data argument");
- return ScriptPromise();
- }
- return WriteData(script_state, position, params.data(), exception_state);
- }
-
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Object reached an invalid state");
- return ScriptPromise();
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::WriteData(
- ScriptState* script_state,
- uint64_t position,
- const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
- ExceptionState& exception_state) {
- DCHECK(!data.IsNull());
-
- auto blob_data = std::make_unique<BlobData>();
- Blob* blob = nullptr;
- if (data.IsArrayBuffer()) {
- DOMArrayBuffer* array_buffer = data.GetAsArrayBuffer();
- blob_data->AppendBytes(array_buffer->Data(), array_buffer->ByteLength());
- } else if (data.IsArrayBufferView()) {
- DOMArrayBufferView* array_buffer_view = data.GetAsArrayBufferView().View();
- blob_data->AppendBytes(array_buffer_view->BaseAddress(),
- array_buffer_view->byteLength());
- } else if (data.IsBlob()) {
- blob = data.GetAsBlob();
- } else if (data.IsUSVString()) {
- // Let the developer be explicit about line endings.
- blob_data->AppendText(data.GetAsUSVString(),
- /*normalize_line_endings_to_native=*/false);
- }
-
- if (!blob) {
- uint64_t size = blob_data->length();
- blob = MakeGarbageCollected<Blob>(
- BlobDataHandle::Create(std::move(blob_data), size));
- }
-
- return WriteBlob(script_state, position, blob, exception_state);
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::WriteBlob(
- ScriptState* script_state,
- uint64_t position,
- Blob* blob,
- ExceptionState& exception_state) {
- if (!writer_remote_.is_bound() || pending_operation_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Object reached an invalid state");
- return ScriptPromise();
- }
- pending_operation_ =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = pending_operation_->Promise();
- writer_remote_->Write(
- position, blob->AsMojoBlob(),
- WTF::Bind(&NativeFileSystemUnderlyingSink::WriteComplete,
- WrapPersistent(this)));
- return result;
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::Truncate(
- ScriptState* script_state,
- uint64_t size,
- ExceptionState& exception_state) {
- if (!writer_remote_.is_bound() || pending_operation_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Object reached an invalid state");
- return ScriptPromise();
- }
- pending_operation_ =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = pending_operation_->Promise();
- writer_remote_->Truncate(
- size, WTF::Bind(&NativeFileSystemUnderlyingSink::TruncateComplete,
- WrapPersistent(this), size));
- return result;
-}
-
-ScriptPromise NativeFileSystemUnderlyingSink::Seek(
- ScriptState* script_state,
- uint64_t offset,
- ExceptionState& exception_state) {
- if (!writer_remote_.is_bound() || pending_operation_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Object reached an invalid state");
- return ScriptPromise();
- }
- offset_ = offset;
- return ScriptPromise::CastUndefined(script_state);
-}
-
-void NativeFileSystemUnderlyingSink::WriteComplete(
- mojom::blink::NativeFileSystemErrorPtr result,
- uint64_t bytes_written) {
- DCHECK(pending_operation_);
- native_file_system_error::ResolveOrReject(pending_operation_, *result);
- pending_operation_ = nullptr;
-
- if (result->status == mojom::blink::NativeFileSystemStatus::kOk) {
- // Advance offset.
- offset_ += bytes_written;
- }
-}
-
-void NativeFileSystemUnderlyingSink::TruncateComplete(
- uint64_t to_size,
- mojom::blink::NativeFileSystemErrorPtr result) {
- DCHECK(pending_operation_);
- native_file_system_error::ResolveOrReject(pending_operation_, *result);
- pending_operation_ = nullptr;
-
- if (result->status == mojom::blink::NativeFileSystemStatus::kOk) {
- // Set offset to smallest last set size so that a subsequent write is not
- // out of bounds.
- offset_ = to_size < offset_ ? to_size : offset_;
- }
-}
-
-void NativeFileSystemUnderlyingSink::CloseComplete(
- mojom::blink::NativeFileSystemErrorPtr result) {
- DCHECK(pending_operation_);
- native_file_system_error::ResolveOrReject(pending_operation_, *result);
- pending_operation_ = nullptr;
- // We close the mojo pipe because we intend this writable file stream to be
- // discarded after close. Subsequent operations will fail.
- writer_remote_.reset();
-}
-
-void NativeFileSystemUnderlyingSink::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- UnderlyingSinkBase::Trace(visitor);
- visitor->Trace(writer_remote_);
- visitor->Trace(pending_operation_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h
deleted file mode 100644
index 8d231fc658d..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h
+++ /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.
-
-#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/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"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
-
-namespace blink {
-
-class ExceptionState;
-class ScriptPromiseResolver;
-class WriteParams;
-
-class NativeFileSystemUnderlyingSink final : public UnderlyingSinkBase {
- public:
- explicit NativeFileSystemUnderlyingSink(
- ExecutionContext*,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>);
-
- // UnderlyingSinkBase
- ScriptPromise start(ScriptState*,
- WritableStreamDefaultController*,
- ExceptionState&) override;
- ScriptPromise write(ScriptState*,
- ScriptValue chunk,
- WritableStreamDefaultController*,
- ExceptionState&) override;
- ScriptPromise close(ScriptState*, ExceptionState&) override;
- ScriptPromise abort(ScriptState*,
- ScriptValue reason,
- ExceptionState&) override;
-
- void Trace(Visitor*) const override;
-
- private:
- ScriptPromise HandleParams(ScriptState*, const WriteParams&, ExceptionState&);
- ScriptPromise WriteData(
- ScriptState*,
- uint64_t position,
- const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
- ExceptionState&);
- ScriptPromise WriteBlob(ScriptState*,
- uint64_t position,
- Blob*,
- ExceptionState&);
- ScriptPromise Truncate(ScriptState*, uint64_t size, ExceptionState&);
- ScriptPromise Seek(ScriptState*, uint64_t offset, ExceptionState&);
- void WriteComplete(mojom::blink::NativeFileSystemErrorPtr result,
- uint64_t bytes_written);
- void TruncateComplete(uint64_t to_size,
- mojom::blink::NativeFileSystemErrorPtr result);
- void CloseComplete(mojom::blink::NativeFileSystemErrorPtr result);
-
- HeapMojoRemote<mojom::blink::NativeFileSystemFileWriter> writer_remote_;
-
- uint64_t offset_ = 0;
- Member<ScriptPromiseResolver> pending_operation_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc
deleted file mode 100644
index 64c6c2076f3..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc
+++ /dev/null
@@ -1,130 +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/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"
-#include "third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_write_params.h"
-#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/file_system_access/native_file_system_underlying_sink.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-
-namespace blink {
-
-NativeFileSystemWritableFileStream* NativeFileSystemWritableFileStream::Create(
- ScriptState* script_state,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>
- writer_pending_remote) {
- DCHECK(writer_pending_remote);
- ScriptState::Scope scope(script_state);
-
- ExecutionContext* context = ExecutionContext::From(script_state);
-
- auto* stream = MakeGarbageCollected<NativeFileSystemWritableFileStream>();
-
- auto* underlying_sink = MakeGarbageCollected<NativeFileSystemUnderlyingSink>(
- context, std::move(writer_pending_remote));
- stream->underlying_sink_ = underlying_sink;
- auto underlying_sink_value = ScriptValue::From(script_state, underlying_sink);
-
- auto* init = QueuingStrategyInit::Create();
- // HighWaterMark set to 1 here. This allows the stream to appear available
- // without adding additional buffering.
- init->setHighWaterMark(1);
- auto* strategy = CountQueuingStrategy::Create(script_state, init);
- ScriptValue strategy_value = ScriptValue::From(script_state, strategy);
-
- ExceptionState exception_state(script_state->GetIsolate(),
- ExceptionState::kConstructionContext,
- "NativeFileSystemWritableFileStream");
- stream->InitInternal(script_state, underlying_sink_value, strategy_value,
- exception_state);
-
- if (exception_state.HadException())
- return nullptr;
-
- return stream;
-}
-
-ScriptPromise NativeFileSystemWritableFileStream::write(
- ScriptState* script_state,
- const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams& data,
- ExceptionState& exception_state) {
- WritableStreamDefaultWriter* writer =
- WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- ScriptPromise promise = writer->write(
- script_state, ScriptValue::From(script_state, data), exception_state);
-
- WritableStreamDefaultWriter::Release(script_state, writer);
- return promise;
-}
-
-ScriptPromise NativeFileSystemWritableFileStream::truncate(
- ScriptState* script_state,
- uint64_t size,
- ExceptionState& exception_state) {
- WritableStreamDefaultWriter* writer =
- WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- auto* options = WriteParams::Create();
- options->setType("truncate");
- options->setSize(size);
-
- ScriptPromise promise = writer->write(
- script_state, ScriptValue::From(script_state, options), exception_state);
-
- WritableStreamDefaultWriter::Release(script_state, writer);
- return promise;
-}
-
-ScriptPromise NativeFileSystemWritableFileStream::close(
- ScriptState* script_state,
- ExceptionState& exception_state) {
- WritableStreamDefaultWriter* writer =
- WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- ScriptPromise promise = writer->close(script_state, exception_state);
-
- WritableStreamDefaultWriter::Release(script_state, writer);
- return promise;
-}
-
-ScriptPromise NativeFileSystemWritableFileStream::seek(
- ScriptState* script_state,
- uint64_t offset,
- ExceptionState& exception_state) {
- WritableStreamDefaultWriter* writer =
- WritableStream::AcquireDefaultWriter(script_state, this, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- auto* options = WriteParams::Create();
- options->setType("seek");
- options->setPosition(offset);
-
- ScriptPromise promise = writer->write(
- script_state, ScriptValue::From(script_state, options), exception_state);
-
- WritableStreamDefaultWriter::Release(script_state, writer);
- return promise;
-}
-
-void NativeFileSystemWritableFileStream::Trace(Visitor* visitor) const {
- WritableStream::Trace(visitor);
- visitor->Trace(underlying_sink_);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h
deleted file mode 100644
index fe4ee8c8718..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h
+++ /dev/null
@@ -1,46 +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_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/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"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class ScriptPromise;
-class ScriptState;
-class NativeFileSystemUnderlyingSink;
-
-class NativeFileSystemWritableFileStream final : public WritableStream {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- static NativeFileSystemWritableFileStream* Create(
- ScriptState*,
- mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>);
-
- void Trace(Visitor* visitor) const override;
-
- // IDL defined functions specific to NativeFileSystemWritableFileStream.
- ScriptPromise write(
- ScriptState*,
- const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams& data,
- ExceptionState&);
- ScriptPromise truncate(ScriptState*, uint64_t size, ExceptionState&);
- ScriptPromise close(ScriptState*, ExceptionState&);
- ScriptPromise seek(ScriptState*, uint64_t offset, ExceptionState&);
-
- private:
- Member<NativeFileSystemUnderlyingSink> underlying_sink_;
-};
-} // namespace blink
-
-#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/file_system_access/open_file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl
index 96456f757a8..d74f2c14f06 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/native-file-system/#dictdef-openfilepickeroptions
+// https://wicg.github.io/file-system-access/#dictdef-openfilepickeroptions
dictionary OpenFilePickerOptions : FilePickerOptions {
boolean multiple = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl
index d18f9d01f73..1abe2efea42 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl
@@ -2,6 +2,7 @@
// 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/#dictdef-savefilepickeroptions
+// https://wicg.github.io/file-system-access/#dictdef-savefilepickeroptions
dictionary SaveFilePickerOptions : FilePickerOptions {
+ [RuntimeEnabled=FileSystemAccessAPIExperimental] USVString? suggestedName;
};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc
new file mode 100644
index 00000000000..c21b28d29ed
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.cc
@@ -0,0 +1,122 @@
+// Copyright 2020 The Chromium Authors. 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/file_system_access/storage_manager_file_system_access.h"
+
+#include <utility>
+
+#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/file_system_access/file_system_access_manager.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.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/execution_context/security_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/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_access_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_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/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/casting.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[] = "";
+
+void GetDirectoryImpl(ScriptPromiseResolver* resolver, bool allow_access) {
+ ExecutionContext* context = resolver->GetExecutionContext();
+ if (!resolver->GetScriptState()->ContextIsValid())
+ return;
+
+ if (!allow_access) {
+ auto* const isolate = resolver->GetScriptState()->GetIsolate();
+ ScriptState::Scope scope(resolver->GetScriptState());
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kSecurityError,
+ "Storage directory access is denied."));
+ return;
+ }
+
+ mojo::Remote<mojom::blink::FileSystemAccessManager> manager;
+ context->GetBrowserInterfaceBroker().GetInterface(
+ manager.BindNewPipeAndPassReceiver());
+
+ auto* raw_manager = manager.get();
+ raw_manager->GetSandboxedFileSystem(WTF::Bind(
+ [](ScriptPromiseResolver* resolver,
+ mojo::Remote<mojom::blink::FileSystemAccessManager>,
+ mojom::blink::FileSystemAccessErrorPtr result,
+ mojo::PendingRemote<mojom::blink::FileSystemAccessDirectoryHandle>
+ handle) {
+ ExecutionContext* context = resolver->GetExecutionContext();
+ if (!context)
+ return;
+ if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+ file_system_access_error::Reject(resolver, *result);
+ return;
+ }
+ resolver->Resolve(MakeGarbageCollected<FileSystemDirectoryHandle>(
+ context, kSandboxRootDirectoryName, std::move(handle)));
+ },
+ WrapPersistent(resolver), std::move(manager)));
+}
+
+} // namespace
+
+// static
+ScriptPromise StorageManagerFileSystemAccess::getDirectory(
+ ScriptState* script_state,
+ const StorageManager& storage,
+ ExceptionState& exception_state) {
+ ExecutionContext* context = ExecutionContext::From(script_state);
+
+ if (!context->GetSecurityOrigin()->CanAccessFileSystem()) {
+ if (context->IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
+ exception_state.ThrowSecurityError(
+ "Storage directory access is denied because the context is "
+ "sandboxed and lacks the 'allow-same-origin' flag.");
+ return ScriptPromise();
+ } else {
+ exception_state.ThrowSecurityError("Storage directory access is denied.");
+ return ScriptPromise();
+ }
+ }
+
+ SECURITY_DCHECK(context->IsWindow() || context->IsWorkerGlobalScope());
+ WebContentSettingsClient* content_settings_client = nullptr;
+ if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+ LocalFrame* frame = window->GetFrame();
+ if (!frame) {
+ exception_state.ThrowSecurityError("Storage directory access is denied.");
+ return ScriptPromise();
+ }
+ content_settings_client = frame->GetContentSettingsClient();
+ } else {
+ content_settings_client =
+ To<WorkerGlobalScope>(context)->ContentSettingsClient();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise result = resolver->Promise();
+
+ if (content_settings_client) {
+ content_settings_client->AllowStorageAccess(
+ WebContentSettingsClient::StorageType::kFileSystem,
+ WTF::Bind(&GetDirectoryImpl, WrapPersistent(resolver)));
+ } else {
+ GetDirectoryImpl(resolver, true);
+ }
+
+ return result;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h
new file mode 100644
index 00000000000..2ee916ab1ae
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_FILE_SYSTEM_ACCESS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_FILE_SYSTEM_ACCESS_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class ExceptionState;
+class ScriptPromise;
+class ScriptState;
+class StorageManager;
+
+class StorageManagerFileSystemAccess {
+ STATIC_ONLY(StorageManagerFileSystemAccess);
+
+ public:
+ static ScriptPromise getDirectory(ScriptState*,
+ const StorageManager&,
+ ExceptionState&);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_FILE_SYSTEM_ACCESS_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.idl b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.idl
new file mode 100644
index 00000000000..d73337e3f00
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_file_system_access.idl
@@ -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.
+
+// https://wicg.github.io/file-system-access/#sandboxed-filesystem
+[
+ SecureContext,
+ RuntimeEnabled=FileSystemAccess,
+ ImplementedAs=StorageManagerFileSystemAccess
+] partial interface StorageManager {
+ [CallWith=ScriptState, RaisesException, Measure]
+ Promise<FileSystemDirectoryHandle> getDirectory();
+};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
deleted file mode 100644
index 0b925ca8eed..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
+++ /dev/null
@@ -1,122 +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/file_system_access/storage_manager_native_file_system.h"
-
-#include <utility>
-
-#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/file_system_access/native_file_system_manager.mojom-blink.h"
-#include "third_party/blink/public/platform/web_content_settings_client.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/execution_context/security_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/workers/worker_global_scope.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"
-#include "third_party/blink/renderer/platform/wtf/casting.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[] = "";
-
-void GetDirectoryImpl(ScriptPromiseResolver* resolver, bool allow_access) {
- ExecutionContext* context = resolver->GetExecutionContext();
- if (!resolver->GetScriptState()->ContextIsValid())
- return;
-
- if (!allow_access) {
- auto* const isolate = resolver->GetScriptState()->GetIsolate();
- ScriptState::Scope scope(resolver->GetScriptState());
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- isolate, DOMExceptionCode::kSecurityError,
- "Storage directory access is denied."));
- return;
- }
-
- 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>,
- mojom::blink::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)));
-}
-
-} // namespace
-
-// static
-ScriptPromise StorageManagerNativeFileSystem::getDirectory(
- ScriptState* script_state,
- const StorageManager& storage,
- ExceptionState& exception_state) {
- ExecutionContext* context = ExecutionContext::From(script_state);
-
- if (!context->GetSecurityOrigin()->CanAccessNativeFileSystem()) {
- if (context->IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
- exception_state.ThrowSecurityError(
- "Storage directory access is denied because the context is "
- "sandboxed and lacks the 'allow-same-origin' flag.");
- return ScriptPromise();
- } else {
- exception_state.ThrowSecurityError("Storage directory access is denied.");
- return ScriptPromise();
- }
- }
-
- SECURITY_DCHECK(context->IsWindow() || context->IsWorkerGlobalScope());
- WebContentSettingsClient* content_settings_client = nullptr;
- if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
- LocalFrame* frame = window->GetFrame();
- if (!frame) {
- exception_state.ThrowSecurityError("Storage directory access is denied.");
- return ScriptPromise();
- }
- content_settings_client = frame->GetContentSettingsClient();
- } else {
- content_settings_client =
- To<WorkerGlobalScope>(context)->ContentSettingsClient();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- if (content_settings_client) {
- content_settings_client->AllowStorageAccess(
- WebContentSettingsClient::StorageType::kFileSystem,
- WTF::Bind(&GetDirectoryImpl, WrapPersistent(resolver)));
- } else {
- GetDirectoryImpl(resolver, true);
- }
-
- return result;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h
deleted file mode 100644
index 300eef493de..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h
+++ /dev/null
@@ -1,29 +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_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"
-
-namespace blink {
-
-class ExceptionState;
-class ScriptPromise;
-class ScriptState;
-class StorageManager;
-
-class StorageManagerNativeFileSystem {
- STATIC_ONLY(StorageManagerNativeFileSystem);
-
- public:
- static ScriptPromise getDirectory(ScriptState*,
- const StorageManager&,
- ExceptionState&);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl
deleted file mode 100644
index f3a36d59739..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://wicg.github.io/native-file-system/#sandboxed-filesystem
-[
- SecureContext,
- RuntimeEnabled=NativeFileSystem,
- ImplementedAs=StorageManagerNativeFileSystem
-] partial interface StorageManager {
- [CallWith=ScriptState, RaisesException, Measure]
- Promise<FileSystemDirectoryHandle> getDirectory();
-};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/window_file_system_access.idl b/chromium/third_party/blink/renderer/modules/file_system_access/window_file_system_access.idl
new file mode 100644
index 00000000000..5ea043ca1e7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/window_file_system_access.idl
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/file-system-access/#local-filesystem
+[
+ SecureContext,
+ RuntimeEnabled=FileSystemAccess,
+ ImplementedAs=GlobalFileSystemAccess
+] partial interface Window {
+ [CallWith=ScriptState, RaisesException, Measure]
+ Promise<sequence<FileSystemFileHandle>> showOpenFilePicker(
+ optional OpenFilePickerOptions options = {});
+ [CallWith=ScriptState, RaisesException, Measure]
+ Promise<FileSystemFileHandle> showSaveFilePicker(
+ optional SaveFilePickerOptions options = {});
+ [CallWith=ScriptState, RaisesException, Measure]
+ Promise<FileSystemDirectoryHandle> showDirectoryPicker(
+ optional DirectoryPickerOptions options = {});
+};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl
deleted file mode 100644
index e2d65ef614e..00000000000
--- a/chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl
+++ /dev/null
@@ -1,21 +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.
-
-// https://wicg.github.io/native-file-system/#native-filesystem
-// https://wicg.github.io/native-file-system/#api-getoriginprivatefilesystem
-[
- SecureContext,
- RuntimeEnabled=NativeFileSystem,
- ImplementedAs=GlobalNativeFileSystem
-] partial interface Window {
- [CallWith=ScriptState, RaisesException, Measure]
- Promise<sequence<FileSystemFileHandle>> showOpenFilePicker(
- optional OpenFilePickerOptions options = {});
- [CallWith=ScriptState, RaisesException, Measure]
- Promise<FileSystemFileHandle> showSaveFilePicker(
- optional SaveFilePickerOptions options = {});
- [CallWith=ScriptState, RaisesException, Measure]
- Promise<FileSystemDirectoryHandle> showDirectoryPicker(
- optional DirectoryPickerOptions options = {});
-};
diff --git a/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl b/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl
index 9e6a39c7f52..f62eff5517c 100644
--- a/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://wicg.github.io/native-file-system/#enumdef-writecommandtype
+// https://wicg.github.io/file-system-access/#enumdef-writecommandtype
enum WriteCommandType {
"truncate",
"seek",
"write",
};
-// https://wicg.github.io/native-file-system/#dictdef-writeparams
+// https://wicg.github.io/file-system-access/#dictdef-writeparams
dictionary WriteParams {
required WriteCommandType type;
unsigned long long? size;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/DIR_METADATA b/chromium/third_party/blink/renderer/modules/filesystem/DIR_METADATA
new file mode 100644
index 00000000000..9f7250ac158
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/filesystem/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>FileSystem"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/OWNERS b/chromium/third_party/blink/renderer/modules/filesystem/OWNERS
index e8b67ffb994..b39c0796866 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/filesystem/OWNERS
@@ -3,6 +3,3 @@ jsbell@chromium.org
kinuko@chromium.org
pwnall@chromium.org
nhiroki@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>FileSystem
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc
index d76f7f21a03..442c196fcee 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/data_transfer_item_file_system.cc
@@ -59,10 +59,14 @@ Entry* DataTransferItemFileSystem::webkitGetAsEntry(ScriptState* script_state,
return nullptr;
DCHECK(IsA<File>(file));
+ auto* context = ExecutionContext::From(script_state);
+ if (!context)
+ return nullptr;
+
DOMFileSystem* dom_file_system =
DraggedIsolatedFileSystemImpl::GetDOMFileSystem(
- item.GetDataTransfer()->GetDataObject(),
- ExecutionContext::From(script_state), *item.GetDataObjectItem());
+ item.GetDataTransfer()->GetDataObject(), context,
+ *item.GetDataObjectItem());
if (!dom_file_system) {
// IsolatedFileSystem may not be enabled.
return nullptr;
@@ -75,7 +79,7 @@ Entry* DataTransferItemFileSystem::webkitGetAsEntry(ScriptState* script_state,
// FIXME: This involves synchronous file operation. Consider passing file type
// data when we dispatch drag event.
FileMetadata metadata;
- if (!GetFileMetadata(To<File>(file)->GetPath(), metadata))
+ if (!GetFileMetadata(To<File>(file)->GetPath(), *context, metadata))
return nullptr;
if (metadata.type == FileMetadata::kTypeDirectory)
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
index 2bde1a6b357..541c99427c6 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
#include <memory>
+#include <utility>
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_security_origin.h"
@@ -174,8 +175,7 @@ void DOMFileSystem::ScheduleCallback(ExecutionContext* execution_context,
execution_context->GetTaskRunner(TaskType::kFileReading)
->PostTask(FROM_HERE,
WTF::Bind(&RunCallback, WrapWeakPersistent(execution_context),
- WTF::Passed(std::move(task)),
- WTF::Passed(std::move(identifier))));
+ std::move(task), std::move(identifier)));
}
void DOMFileSystem::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base_test.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base_test.cc
index d8cdbb61ae3..e5ba7d649df 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base_test.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base_test.cc
@@ -7,6 +7,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h"
#include "third_party/blink/renderer/core/fileapi/file.h"
+#include "third_party/blink/renderer/core/testing/null_execution_context.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
@@ -16,11 +18,14 @@ class DOMFileSystemBaseTest : public testing::Test {
DOMFileSystemBaseTest() {
file_path_ = test::BlinkRootDir() +
"/renderer/modules/filesystem/dom_file_system_base_test.cc";
- GetFileMetadata(file_path_, file_metadata_);
+ GetFileMetadata(file_path_, *context_, file_metadata_);
file_metadata_.platform_path = file_path_;
}
+ ~DOMFileSystemBaseTest() override { context_->NotifyContextDestroyed(); }
protected:
+ Persistent<ExecutionContext> context_ =
+ MakeGarbageCollected<NullExecutionContext>();
String file_path_;
FileMetadata file_metadata_;
};
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/html_input_element_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/html_input_element_file_system.cc
index d332dc59c46..139c32095f0 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/html_input_element_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/html_input_element_file_system.cc
@@ -54,8 +54,12 @@ EntryHeapVector HTMLInputElementFileSystem::webkitEntries(
if (!files)
return entries;
+ auto* context = ExecutionContext::From(script_state);
+ if (!context)
+ return entries;
+
DOMFileSystem* filesystem = DOMFileSystem::CreateIsolatedFileSystem(
- ExecutionContext::From(script_state), input.DroppedFileSystemId());
+ context, input.DroppedFileSystemId());
if (!filesystem) {
// Drag-drop isolated filesystem is not available.
return entries;
@@ -66,7 +70,7 @@ EntryHeapVector HTMLInputElementFileSystem::webkitEntries(
// FIXME: This involves synchronous file operation.
FileMetadata metadata;
- if (!GetFileMetadata(file->GetPath(), metadata))
+ if (!GetFileMetadata(file->GetPath(), *context, metadata))
continue;
// The dropped entries are mapped as top-level entries in the isolated
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 c2f6c4812a2..c71d090e22f 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
@@ -85,7 +85,7 @@ void LocalFileSystem::RequestFileSystem(
WrapCrossThreadPersistent(this), type, std::move(callbacks), sync_type));
GetSupplementable()->GetScheduler()->RegisterStickyFeature(
blink::SchedulingPolicy::Feature::kWebFileSystem,
- {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {blink::SchedulingPolicy::DisableBackForwardCache()});
}
void LocalFileSystem::RequestFileSystemCallback(
@@ -130,18 +130,18 @@ void LocalFileSystem::FileSystemNotAllowedInternal(
std::unique_ptr<FileSystemCallbacks> callbacks) {
GetSupplementable()
->GetTaskRunner(TaskType::kFileReading)
- ->PostTask(FROM_HERE, WTF::Bind(&FileSystemCallbacks::DidFail,
- WTF::Passed(std::move(callbacks)),
- base::File::FILE_ERROR_ABORT));
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&FileSystemCallbacks::DidFail, std::move(callbacks),
+ base::File::FILE_ERROR_ABORT));
}
void LocalFileSystem::FileSystemNotAllowedInternal(
std::unique_ptr<ResolveURICallbacks> callbacks) {
GetSupplementable()
->GetTaskRunner(TaskType::kFileReading)
- ->PostTask(FROM_HERE, WTF::Bind(&ResolveURICallbacks::DidFail,
- WTF::Passed(std::move(callbacks)),
- base::File::FILE_ERROR_ABORT));
+ ->PostTask(FROM_HERE,
+ WTF::Bind(&ResolveURICallbacks::DidFail, std::move(callbacks),
+ base::File::FILE_ERROR_ABORT));
}
void LocalFileSystem::FileSystemAllowedInternal(
diff --git a/chromium/third_party/blink/renderer/modules/font_access/BUILD.gn b/chromium/third_party/blink/renderer/modules/font_access/BUILD.gn
index c13fd4ce905..5763d4ef725 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/font_access/BUILD.gn
@@ -6,8 +6,6 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("font_access") {
sources = [
- "font_iterator.cc",
- "font_iterator.h",
"font_manager.cc",
"font_manager.h",
"font_metadata.cc",
diff --git a/chromium/third_party/blink/renderer/modules/font_access/DIR_METADATA b/chromium/third_party/blink/renderer/modules/font_access/DIR_METADATA
new file mode 100644
index 00000000000..2b228dc0a5d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/font_access/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>FontAccess"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/font_access/OWNERS b/chromium/third_party/blink/renderer/modules/font_access/OWNERS
index 7f72f638eb2..21e2d67fb0b 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/font_access/OWNERS
@@ -1,6 +1,3 @@
drott@chromium.org
jsbell@chromium.org
oyiptong@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>FontAccess
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
deleted file mode 100644
index f0b007fb4a7..00000000000
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc
+++ /dev/null
@@ -1,140 +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/font_access/font_iterator.h"
-
-#include "build/build_config.h"
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/common/font_access/font_enumeration_table.pb.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_font_iterator_entry.h"
-#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/wtf/functional.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
-
-namespace blink {
-
-FontIterator::FontIterator(ExecutionContext* context)
- : ExecutionContextLifecycleObserver(context) {
- context->GetBrowserInterfaceBroker().GetInterface(
- remote_manager_.BindNewPipeAndPassReceiver());
- remote_manager_.set_disconnect_handler(
- WTF::Bind(&FontIterator::OnDisconnect, WrapWeakPersistent(this)));
-}
-
-ScriptPromise FontIterator::next(ScriptState* script_state) {
- if (permission_status_ == PermissionStatus::ASK) {
- if (!pending_resolver_) {
- remote_manager_->EnumerateLocalFonts(WTF::Bind(
- &FontIterator::DidGetEnumerationResponse, WrapWeakPersistent(this)));
- pending_resolver_ =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- }
- return pending_resolver_->Promise();
- }
-
- if (permission_status_ == PermissionStatus::DENIED) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotAllowedError,
- "Permission Error"));
- }
-
- return ScriptPromise::Cast(script_state, ToV8(GetNextEntry(), script_state));
-}
-
-void FontIterator::Trace(Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
- ContextLifecycleObserver::Trace(visitor);
- visitor->Trace(entries_);
- visitor->Trace(pending_resolver_);
-}
-
-FontIteratorEntry* FontIterator::GetNextEntry() {
- auto* result = FontIteratorEntry::Create();
- if (entries_.IsEmpty()) {
- result->setDone(true);
- return result;
- }
-
- FontMetadata* entry = entries_.TakeFirst();
- result->setValue(entry);
-
- return result;
-}
-
-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::kNeedsUserActivation:
- pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- 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:
- permission_status_ = PermissionStatus::DENIED;
- pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotAllowedError, "Permission not granted."));
- pending_resolver_.Clear();
- return;
- case FontEnumerationStatus::kUnexpectedError:
- default:
- pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kUnknownError, "An unexpected error occured."));
- pending_resolver_.Clear();
- return;
- }
- permission_status_ = PermissionStatus::GRANTED;
-
- base::ReadOnlySharedMemoryMapping mapping = region.Map();
- FontEnumerationTable table;
-
- if (mapping.size() > INT_MAX) {
- // Cannot deserialize without overflow.
- pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kDataError, "Font data exceeds memory limit."));
- pending_resolver_.Clear();
- return;
- }
-
- table.ParseFromArray(mapping.memory(), static_cast<int>(mapping.size()));
- for (const auto& element : table.fonts()) {
- auto entry = FontEnumerationEntry{
- String::FromUTF8(element.postscript_name().c_str()),
- String::FromUTF8(element.full_name().c_str()),
- String::FromUTF8(element.family().c_str())};
- entries_.push_back(FontMetadata::Create(std::move(entry)));
- }
-
- pending_resolver_->Resolve(GetNextEntry());
- pending_resolver_.Clear();
-}
-
-void FontIterator::ContextDestroyed() {
- remote_manager_.reset();
-}
-
-void FontIterator::OnDisconnect() {
- remote_manager_.reset();
-}
-
-} // namespace blink
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
deleted file mode 100644
index 366951369bd..00000000000
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.h
+++ /dev/null
@@ -1,56 +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_FONT_ACCESS_FONT_ITERATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_FONT_ACCESS_FONT_ITERATOR_H_
-
-#include "base/memory/read_only_shared_memory_region.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/mojom/font_access/font_access.mojom-blink.h"
-#include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-using mojom::blink::FontEnumerationStatus;
-
-class ScriptPromise;
-class ScriptPromiseResolver;
-class ScriptState;
-class FontMetadata;
-class FontIteratorEntry;
-
-class FontIterator final : public ScriptWrappable,
- public ExecutionContextLifecycleObserver {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- using PermissionStatus = mojom::blink::PermissionStatus;
- explicit FontIterator(ExecutionContext* context);
-
- ScriptPromise next(ScriptState*);
-
- void Trace(Visitor*) const override;
-
- private:
- FontIteratorEntry* GetNextEntry();
- void DidGetEnumerationResponse(FontEnumerationStatus,
- base::ReadOnlySharedMemoryRegion);
- void ContextDestroyed() override;
- void OnDisconnect();
-
- HeapDeque<Member<FontMetadata>> entries_;
- Member<ScriptPromiseResolver> pending_resolver_;
- mojo::Remote<mojom::blink::FontAccessManager> remote_manager_;
-
- PermissionStatus permission_status_ = PermissionStatus::ASK;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FONT_ACCESS_FONT_ITERATOR_H_
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
deleted file mode 100644
index 9a8536ab538..00000000000
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl
+++ /dev/null
@@ -1,15 +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.
-
-// TODO(https://crbug.com/1062425): Determine if async iterator performance cost is worthwhile.
-// Async iterator returned by FontManager.query().
-// https://wicg.github.io/local-font-access/
-// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface
-[
- SecureContext,
- LegacyNoInterfaceObject,
- RuntimeEnabled=FontAccess
-] interface FontIterator {
- [CallWith=ScriptState] Promise<any> next();
-};
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_iterator_entry.idl b/chromium/third_party/blink/renderer/modules/font_access/font_iterator_entry.idl
deleted file mode 100644
index 7126de79fcf..00000000000
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator_entry.idl
+++ /dev/null
@@ -1,11 +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.
-
-// Used by FontIterator to represents results of next() calls.
-// https://wicg.github.io/local-font-access/
-// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-iteratorresult-interface
-dictionary FontIteratorEntry {
- FontMetadata value;
- boolean done = false;
-};
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 1f185d5da4d..0e31b8d0086 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
@@ -6,57 +6,167 @@
#include <algorithm>
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/font_access/font_enumeration_table.pb.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_query_options.h"
#include "third_party/blink/renderer/core/dom/dom_exception.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/modules/font_access/font_iterator.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/runtime_enabled_features.h"
namespace blink {
-namespace {
+using mojom::blink::FontEnumerationStatus;
-void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
- V8SetReturnValue(info, info.Data());
+FontManager::FontManager(ExecutionContext* context)
+ : ExecutionContextLifecycleObserver(context) {
+ // Only connect if the feature is enabled. Otherwise, there will
+ // be no service to connect to on the end.
+ if (base::FeatureList::IsEnabled(blink::features::kFontAccess)) {
+ context->GetBrowserInterfaceBroker().GetInterface(
+ remote_manager_.BindNewPipeAndPassReceiver());
+ remote_manager_.set_disconnect_handler(
+ WTF::Bind(&FontManager::OnDisconnect, WrapWeakPersistent(this)));
+ }
}
-} // namespace
+ScriptPromise FontManager::query(ScriptState* script_state,
+ const QueryOptions* options) {
+ DCHECK(options->hasSelect());
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ if (options->persistentAccess() &&
+ RuntimeEnabledFeatures::FontAccessPersistentEnabled()) {
+ remote_manager_->EnumerateLocalFonts(WTF::Bind(
+ &FontManager::DidGetEnumerationResponse, WrapWeakPersistent(this),
+ WrapPersistent(resolver), options->select()));
+ return promise;
+ }
-ScriptValue FontManager::query(ScriptState* script_state,
- ExceptionState& exception_state) {
- if (exception_state.HadException())
- return ScriptValue();
+ remote_manager_->ChooseLocalFonts(
+ options->select(),
+ WTF::Bind(&FontManager::DidShowFontChooser, WrapWeakPersistent(this),
+ WrapPersistent(resolver)));
- auto* iterator =
- MakeGarbageCollected<FontIterator>(ExecutionContext::From(script_state));
- auto* isolate = script_state->GetIsolate();
- auto context = script_state->GetContext();
+ return promise;
+}
- v8::Local<v8::Object> result = v8::Object::New(isolate);
- if (!result
- ->Set(context, v8::Symbol::GetAsyncIterator(isolate),
- v8::Function::New(context, &ReturnDataFunction,
- ToV8(iterator, script_state))
- .ToLocalChecked())
- .ToChecked()) {
- return ScriptValue();
+void FontManager::Trace(blink::Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ ContextLifecycleObserver::Trace(visitor);
+}
+
+void FontManager::DidShowFontChooser(
+ ScriptPromiseResolver* resolver,
+ FontEnumerationStatus status,
+ Vector<mojom::blink::FontMetadataPtr> fonts) {
+ if (RejectPromiseIfNecessary(status, resolver))
+ return;
+
+ auto entries = HeapVector<Member<FontMetadata>>();
+ for (const auto& font : fonts) {
+ auto entry = FontEnumerationEntry{font->postscript_name, font->full_name,
+ font->family};
+ entries.push_back(FontMetadata::Create(std::move(entry)));
}
- return ScriptValue(script_state->GetIsolate(), result);
+ resolver->Resolve(std::move(entries));
}
-ScriptPromise FontManager::showFontChooser(ScriptState* script_state,
- const QueryOptions* options) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
- "Not implemented yet"));
+void FontManager::DidGetEnumerationResponse(
+ ScriptPromiseResolver* resolver,
+ const Vector<String>& selection,
+ FontEnumerationStatus status,
+ base::ReadOnlySharedMemoryRegion region) {
+ if (RejectPromiseIfNecessary(status, resolver))
+ return;
+
+ base::ReadOnlySharedMemoryMapping mapping = region.Map();
+ FontEnumerationTable table;
+
+ if (mapping.size() > INT_MAX) {
+ // Cannot deserialize without overflow.
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kDataError, "Font data exceeds memory limit."));
+ return;
+ }
+
+ // Used to compare with data coming from the browser to avoid conversions.
+ std::set<std::string> selection_utf8;
+ for (const String& postscriptName : selection) {
+ // While postscript names are encoded in a subset of ASCII, we convert the
+ // input into UTF8. This will still allow exact matches to occur.
+ selection_utf8.insert(postscriptName.Utf8());
+ }
+
+ HeapVector<Member<FontMetadata>> entries;
+ table.ParseFromArray(mapping.memory(), static_cast<int>(mapping.size()));
+ for (const auto& element : table.fonts()) {
+ // If the selection list contains items, only allow items that match.
+ if (!selection_utf8.empty() &&
+ selection_utf8.find(element.postscript_name().c_str()) ==
+ selection_utf8.end())
+ continue;
+
+ auto entry = FontEnumerationEntry{
+ String::FromUTF8(element.postscript_name().c_str()),
+ String::FromUTF8(element.full_name().c_str()),
+ String::FromUTF8(element.family().c_str()),
+ String::FromUTF8(element.style().c_str())};
+ entries.push_back(FontMetadata::Create(std::move(entry)));
+ }
+
+ resolver->Resolve(std::move(entries));
}
-void FontManager::Trace(blink::Visitor* visitor) const {
- ScriptWrappable::Trace(visitor);
+bool FontManager::RejectPromiseIfNecessary(const FontEnumerationStatus& status,
+ ScriptPromiseResolver* resolver) {
+ switch (status) {
+ case FontEnumerationStatus::kOk:
+ break;
+ case FontEnumerationStatus::kUnimplemented:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotSupportedError,
+ "Not yet supported on this platform."));
+ return true;
+ case FontEnumerationStatus::kCanceled:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, "The user canceled the operation."));
+ return true;
+ case FontEnumerationStatus::kNeedsUserActivation:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kSecurityError, "User activation is required."));
+ return true;
+ case FontEnumerationStatus::kNotVisible:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kSecurityError, "Page needs to be visible."));
+ return true;
+ case FontEnumerationStatus::kPermissionDenied:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError, "Permission not granted."));
+ return true;
+ case FontEnumerationStatus::kUnexpectedError:
+ default:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError, "An unexpected error occured."));
+ return true;
+ }
+ return false;
+}
+
+void FontManager::ContextDestroyed() {
+ remote_manager_.reset();
+}
+
+void FontManager::OnDisconnect() {
+ remote_manager_.reset();
}
} // 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 bf0b74f2afa..80d5011f10c 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
@@ -5,6 +5,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FONT_ACCESS_FONT_MANAGER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_FONT_ACCESS_FONT_MANAGER_H_
+#include "base/memory/read_only_shared_memory_region.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/font_access/font_access.mojom-blink.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -13,25 +17,42 @@
namespace blink {
class ScriptState;
-class ScriptValue;
class ScriptPromise;
+class ScriptPromiseResolver;
class QueryOptions;
-class FontManager final : public ScriptWrappable {
+class FontManager final : public ScriptWrappable,
+ public ExecutionContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- FontManager() = default;
+ explicit FontManager(ExecutionContext* context);
// Disallow copy and assign.
FontManager(const FontManager&) = delete;
FontManager operator=(const FontManager&) = delete;
// FontManager IDL interface implementation.
- ScriptValue query(ScriptState*, ExceptionState&);
- ScriptPromise showFontChooser(ScriptState*, const QueryOptions* options);
+ ScriptPromise query(ScriptState*, const QueryOptions* options);
void Trace(blink::Visitor*) const override;
+
+ private:
+ void DidShowFontChooser(ScriptPromiseResolver* resolver,
+ mojom::blink::FontEnumerationStatus status,
+ Vector<mojom::blink::FontMetadataPtr> fonts);
+ void DidGetEnumerationResponse(ScriptPromiseResolver* resolver,
+ const Vector<String>& selection,
+ mojom::blink::FontEnumerationStatus,
+ base::ReadOnlySharedMemoryRegion);
+ // Returns whether the resolver has rejected.
+ bool RejectPromiseIfNecessary(
+ const mojom::blink::FontEnumerationStatus& status,
+ ScriptPromiseResolver* resolver);
+ void ContextDestroyed() override;
+ void OnDisconnect();
+
+ mojo::Remote<mojom::blink::FontAccessManager> remote_manager_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_manager.idl b/chromium/third_party/blink/renderer/modules/font_access/font_manager.idl
index 9d0a32933ba..08e5b63a872 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_manager.idl
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_manager.idl
@@ -8,6 +8,5 @@
SecureContext,
RuntimeEnabled=FontAccess
] interface FontManager {
- [CallWith=ScriptState, RaisesException, Measure] object query();
- [CallWith=ScriptState, RuntimeEnabled=FontAccessChooser] Promise<FontIterator> showFontChooser(optional QueryOptions options = {});
+ [CallWith=ScriptState, Measure] Promise<sequence<FontMetadata>> query(optional QueryOptions options = {});
};
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.cc b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.cc
index aae742f1dbc..9dadce30eed 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.cc
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.cc
@@ -42,7 +42,8 @@ void SetUpFontUniqueLookupIfNecessary() {
FontMetadata::FontMetadata(const FontEnumerationEntry& entry)
: postscriptName_(entry.postscript_name),
fullName_(entry.full_name),
- family_(entry.family) {}
+ family_(entry.family),
+ style_(entry.style) {}
FontMetadata* FontMetadata::Create(const FontEnumerationEntry& entry) {
return MakeGarbageCollected<FontMetadata>(entry);
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 aab5474093c..62a46dbf239 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
@@ -19,6 +19,7 @@ struct FontEnumerationEntry {
String postscript_name;
String full_name;
String family;
+ String style;
};
class BLINK_EXPORT FontMetadata final : public ScriptWrappable {
@@ -41,13 +42,15 @@ class BLINK_EXPORT FontMetadata final : public ScriptWrappable {
// | Property | name ID | Localized |
// +----------------+---------+-----------+
// | postscriptName | 6 | No |
+ // | family | 1 | No |
+ // | style | 2 | No |
// | fullName | 4 | Yes |
- // | family | 1 | Yes |
// +----------------+---------+-----------+
String postscriptName() const { return postscriptName_; }
String fullName() const { return fullName_; }
String family() const { return family_; }
+ String style() const { return style_; }
ScriptPromise blob(ScriptState*);
@@ -59,6 +62,7 @@ class BLINK_EXPORT FontMetadata final : public ScriptWrappable {
String postscriptName_;
String fullName_;
String family_;
+ String style_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.idl b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.idl
index 14cde9c1e48..9079fafcbc5 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.idl
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.idl
@@ -11,5 +11,6 @@
readonly attribute USVString postscriptName;
readonly attribute USVString fullName;
readonly attribute USVString family;
+ readonly attribute USVString style;
[CallWith=ScriptState, Measure] Promise<Blob> blob();
};
diff --git a/chromium/third_party/blink/renderer/modules/font_access/idls.gni b/chromium/third_party/blink/renderer/modules/font_access/idls.gni
index b9a24af99be..83654aa295b 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/font_access/idls.gni
@@ -3,15 +3,11 @@
# found in the LICENSE file.
modules_idl_files = [
- "font_iterator.idl",
"font_metadata.idl",
"font_table_map.idl",
"font_manager.idl",
]
-modules_dictionary_idl_files = [
- "font_iterator_entry.idl",
- "query_options.idl",
-]
+modules_dictionary_idl_files = [ "query_options.idl" ]
modules_dependency_idl_files = [ "navigator_fonts.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/font_access/navigator_fonts.cc b/chromium/third_party/blink/renderer/modules/font_access/navigator_fonts.cc
index 777410f73b0..0d5e82cd912 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/navigator_fonts.cc
+++ b/chromium/third_party/blink/renderer/modules/font_access/navigator_fonts.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/font_access/navigator_fonts.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/core/workers/worker_navigator.h"
@@ -36,9 +37,9 @@ class NavigatorFontsImpl final : public GarbageCollected<NavigatorFontsImpl<T>>,
explicit NavigatorFontsImpl(T& navigator) : Supplement<T>(navigator) {}
- FontManager* GetFontManager() const {
+ FontManager* GetFontManager(ExecutionContext* context) const {
if (!font_manager_) {
- font_manager_ = MakeGarbageCollected<FontManager>();
+ font_manager_ = MakeGarbageCollected<FontManager>(context);
}
return font_manager_.Get();
}
@@ -66,7 +67,8 @@ FontManager* NavigatorFonts::fonts(ScriptState* script_state,
Navigator& navigator,
ExceptionState& exception_state) {
DCHECK(ExecutionContext::From(script_state)->IsContextThread());
- return NavigatorFontsImpl<Navigator>::From(navigator).GetFontManager();
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ return NavigatorFontsImpl<Navigator>::From(navigator).GetFontManager(context);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/font_access/query_options.idl b/chromium/third_party/blink/renderer/modules/font_access/query_options.idl
index e8cf81dfa49..8db38c6fff7 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/query_options.idl
+++ b/chromium/third_party/blink/renderer/modules/font_access/query_options.idl
@@ -4,6 +4,6 @@
// https://wicg.github.io/local-font-access/
dictionary QueryOptions {
- boolean all = false;
- sequence<ByteString> fonts;
+ boolean persistentAccess = false;
+ sequence<DOMString> select = [];
};
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/DEPS b/chromium/third_party/blink/renderer/modules/gamepad/DEPS
index a656c0f1875..4d0d96490ad 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/DEPS
+++ b/chromium/third_party/blink/renderer/modules/gamepad/DEPS
@@ -14,6 +14,7 @@ include_rules = [
"+third_party/blink/renderer/modules/event_modules.h",
"+third_party/blink/renderer/modules/gamepad",
"+third_party/blink/renderer/modules/modules_export.h",
+ "+base/i18n/uchar.h",
"+base/macros.h",
# For shared metrics.
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/DIR_METADATA b/chromium/third_party/blink/renderer/modules/gamepad/DIR_METADATA
new file mode 100644
index 00000000000..644b28f1736
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/gamepad/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "IO>Gamepad"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/OWNERS b/chromium/third_party/blink/renderer/modules/gamepad/OWNERS
index 25d985807bd..a53699ce8a8 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/gamepad/OWNERS
@@ -1,6 +1,3 @@
b.kelemen@samsung.com
bajones@chromium.org
mattreynolds@chromium.org
-
-# TEAM: device-dev@chromium.org
-# COMPONENT: IO>Gamepad
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
index 21f6dafa82a..e3fca74d287 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
+#include "base/i18n/uchar.h"
#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h"
@@ -57,9 +58,10 @@ Gamepad::~Gamepad() = default;
void Gamepad::UpdateFromDeviceState(const device::Gamepad& device_gamepad) {
bool newly_connected;
GamepadComparisons::HasGamepadConnectionChanged(
- connected(), // Old connected.
- device_gamepad.connected, // New connected.
- id() != StringView(device_gamepad.id), // ID changed.
+ connected(), // Old connected.
+ device_gamepad.connected, // New connected.
+ id() !=
+ StringView(base::i18n::ToUCharPtr(device_gamepad.id)), // ID changed.
&newly_connected, nullptr);
SetConnected(device_gamepad.connected);
@@ -74,7 +76,7 @@ void Gamepad::UpdateFromDeviceState(const device::Gamepad& device_gamepad) {
// These fields are not expected to change and will only be written when the
// gamepad is newly connected.
if (newly_connected) {
- SetId(device_gamepad.id);
+ SetId(base::i18n::ToUCharPtr(device_gamepad.id));
SetMapping(device_gamepad.mapping);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
index 59b4904ea48..a101a875363 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
@@ -7,8 +7,8 @@
#include "third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h"
#include "device/gamepad/public/cpp/gamepads.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/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h"
#include "third_party/blink/renderer/modules/gamepad/navigator_gamepad.h"
@@ -41,21 +41,23 @@ void GamepadDispatcher::ResetVibrationActuator(
}
GamepadDispatcher::GamepadDispatcher(ExecutionContext& context)
- : // See https://bit.ly/2S0zRAS for task types.
- task_runner_(context.GetTaskRunner(TaskType::kMiscPlatformAPI)),
- gamepad_haptics_manager_remote_(&context) {}
+ : execution_context_(&context), gamepad_haptics_manager_remote_(&context) {}
GamepadDispatcher::~GamepadDispatcher() = default;
void GamepadDispatcher::InitializeHaptics() {
- if (!gamepad_haptics_manager_remote_.is_bound()) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ if (!gamepad_haptics_manager_remote_.is_bound() && execution_context_) {
+ // See https://bit.ly/2S0zRAS for task types.
+ auto task_runner =
+ execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ execution_context_->GetBrowserInterfaceBroker().GetInterface(
gamepad_haptics_manager_remote_.BindNewPipeAndPassReceiver(
- task_runner_));
+ std::move(task_runner)));
}
}
void GamepadDispatcher::Trace(Visitor* visitor) const {
+ visitor->Trace(execution_context_);
visitor->Trace(reader_);
visitor->Trace(gamepad_haptics_manager_remote_);
PlatformEventDispatcher::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
index 84dc5487380..513572170ac 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
@@ -60,7 +60,7 @@ class GamepadDispatcher final : public GarbageCollected<GamepadDispatcher>,
const device::Gamepad&,
bool connected);
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ WeakMember<ExecutionContext> execution_context_;
Member<GamepadSharedMemoryReader> reader_;
HeapMojoRemote<device::mojom::blink::GamepadHapticsManager,
HeapMojoWrapperMode::kWithoutContextObserver>
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 9baa887509a..1defe0ffb89 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -67,7 +67,7 @@ const char NavigatorGamepad::kSupplementName[] = "NavigatorGamepad";
const char kSecureContextBlocked[] =
"Access to the feature \"gamepad\" requires a secure context";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"gamepad\" is disallowed by feature policy.";
+ "Access to the feature \"gamepad\" is disallowed by permissions policy.";
NavigatorGamepad& NavigatorGamepad::From(Navigator& navigator) {
NavigatorGamepad* supplement =
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/DIR_METADATA b/chromium/third_party/blink/renderer/modules/geolocation/DIR_METADATA
new file mode 100644
index 00000000000..7e4fa860c92
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/geolocation/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Geolocation"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/OWNERS b/chromium/third_party/blink/renderer/modules/geolocation/OWNERS
index 2dbeb1a26ff..1ebe75b6510 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/geolocation/OWNERS
@@ -2,6 +2,3 @@ mattreynolds@chromium.org
# Original (legacy) owner.
mcasas@chromium.org
-
-# TEAM: device-dev@chromium.org
-# COMPONENT: Blink>Geolocation
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.cc b/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.cc
index 555fc253dd7..d348531a976 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.cc
+++ b/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.cc
@@ -87,6 +87,7 @@ bool GeoNotifier::IsTimerActive() const {
}
void GeoNotifier::Timer::Trace(Visitor* visitor) const {
+ visitor->Trace(timer_);
visitor->Trace(notifier_);
}
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.h b/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.h
index 4348d707fe3..2ea6c284a2b 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.h
+++ b/chromium/third_party/blink/renderer/modules/geolocation/geo_notifier.h
@@ -69,7 +69,7 @@ class GeoNotifier final : public GarbageCollected<GeoNotifier>,
bool IsActive() const { return timer_.IsActive(); }
private:
- TaskRunnerTimer<GeoNotifier> timer_;
+ HeapTaskRunnerTimer<GeoNotifier> timer_;
Member<GeoNotifier> notifier_;
};
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
index 34c4a23c1f1..3c09d254f70 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -49,10 +49,11 @@ namespace {
const char kPermissionDeniedErrorMessage[] = "User denied Geolocation";
const char kFeaturePolicyErrorMessage[] =
- "Geolocation has been disabled in this document by Feature Policy.";
+ "Geolocation has been disabled in this document by permissions policy.";
const char kFeaturePolicyConsoleWarning[] =
- "Geolocation access has been blocked because of a Feature Policy applied "
- "to the current document. See https://goo.gl/EuHzyv for more details.";
+ "Geolocation access has been blocked because of a permissions policy "
+ "applied to the current document. See https://goo.gl/EuHzyv for more "
+ "details.";
Geoposition* CreateGeoposition(
const device::mojom::blink::Geoposition& position) {
@@ -121,7 +122,9 @@ Geolocation::Geolocation(Navigator& navigator)
: Supplement<Navigator>(navigator),
ExecutionContextLifecycleObserver(navigator.DomWindow()),
PageVisibilityObserver(navigator.DomWindow()->GetFrame()->GetPage()),
+ one_shots_(MakeGarbageCollected<GeoNotifierSet>()),
watchers_(MakeGarbageCollected<GeolocationWatchers>()),
+ one_shots_being_invoked_(MakeGarbageCollected<GeoNotifierSet>()),
geolocation_(navigator.DomWindow()),
geolocation_service_(navigator.DomWindow()) {}
@@ -147,7 +150,7 @@ LocalFrame* Geolocation::GetFrame() const {
void Geolocation::ContextDestroyed() {
StopTimers();
- one_shots_.clear();
+ one_shots_->clear();
watchers_->Clear();
StopUpdating();
@@ -197,7 +200,7 @@ void Geolocation::getCurrentPosition(V8PositionCallback* success_callback,
auto* notifier = MakeGarbageCollected<GeoNotifier>(this, success_callback,
error_callback, options);
- one_shots_.insert(notifier);
+ one_shots_->insert(notifier);
StartRequest(notifier);
}
@@ -259,7 +262,7 @@ void Geolocation::FatalErrorOccurred(GeoNotifier* notifier) {
DCHECK(!notifier->IsTimerActive());
// This request has failed fatally. Remove it from our lists.
- one_shots_.erase(notifier);
+ one_shots_->erase(notifier);
watchers_->Remove(notifier);
if (!HasListeners())
@@ -273,8 +276,8 @@ void Geolocation::RequestUsesCachedPosition(GeoNotifier* notifier) {
// If this is a one-shot request, stop it. Otherwise, if the watch still
// exists, start the service to get updates.
- if (one_shots_.Contains(notifier)) {
- one_shots_.erase(notifier);
+ if (one_shots_->Contains(notifier)) {
+ one_shots_->erase(notifier);
} else if (watchers_->Contains(notifier)) {
StartUpdating(notifier);
}
@@ -287,15 +290,15 @@ void Geolocation::RequestTimedOut(GeoNotifier* notifier) {
DCHECK(!notifier->IsTimerActive());
// If this is a one-shot request, stop it.
- one_shots_.erase(notifier);
+ one_shots_->erase(notifier);
if (!HasListeners())
StopUpdating();
}
bool Geolocation::DoesOwnNotifier(GeoNotifier* notifier) const {
- return one_shots_.Contains(notifier) ||
- one_shots_being_invoked_.Contains(notifier) ||
+ return one_shots_->Contains(notifier) ||
+ one_shots_being_invoked_->Contains(notifier) ||
watchers_->Contains(notifier) ||
watchers_being_invoked_.Contains(notifier);
}
@@ -327,7 +330,7 @@ void Geolocation::clearWatch(int watch_id) {
}
void Geolocation::StopTimers() {
- for (const auto& notifier : one_shots_) {
+ for (const auto& notifier : *one_shots_) {
notifier->StopTimer();
}
@@ -339,7 +342,7 @@ void Geolocation::StopTimers() {
void Geolocation::HandleError(GeolocationPositionError* error) {
DCHECK(error);
- DCHECK(one_shots_being_invoked_.IsEmpty());
+ DCHECK(one_shots_being_invoked_->IsEmpty());
DCHECK(watchers_being_invoked_.IsEmpty());
if (error->IsFatal()) {
@@ -369,7 +372,7 @@ void Geolocation::HandleError(GeolocationPositionError* error) {
// already scheduled must be immediately cancelled according to the spec. But
// the current implementation doesn't support such case.
// TODO(mattreynolds): Support watcher cancellation inside notifier callbacks.
- for (auto& notifier : one_shots_being_invoked_) {
+ for (auto& notifier : *one_shots_being_invoked_) {
if (error->IsFatal() || !notifier->UseCachedPosition())
notifier->RunErrorCallback(error);
}
@@ -386,23 +389,23 @@ void Geolocation::HandleError(GeolocationPositionError* error) {
if (!error->IsFatal()) {
// Keep the notifiers that are okay with a cached position in |one_shots_|.
- for (const auto& notifier : one_shots_being_invoked_) {
+ for (const auto& notifier : *one_shots_being_invoked_) {
if (notifier->UseCachedPosition())
- one_shots_.InsertWithoutTimerCheck(notifier.Get());
+ one_shots_->InsertWithoutTimerCheck(notifier.Get());
else
notifier->StopTimer();
}
- one_shots_being_invoked_.ClearWithoutTimerCheck();
+ one_shots_being_invoked_->ClearWithoutTimerCheck();
}
- one_shots_being_invoked_.clear();
+ one_shots_being_invoked_->clear();
watchers_being_invoked_.clear();
}
void Geolocation::MakeSuccessCallbacks() {
DCHECK(last_position_);
- DCHECK(one_shots_being_invoked_.IsEmpty());
+ DCHECK(one_shots_being_invoked_->IsEmpty());
DCHECK(watchers_being_invoked_.IsEmpty());
// Set |one_shots_being_invoked_| and |watchers_being_invoked_| to the
@@ -419,7 +422,7 @@ void Geolocation::MakeSuccessCallbacks() {
// already scheduled must be immediately cancelled according to the spec. But
// the current implementation doesn't support such case.
// TODO(mattreynolds): Support watcher cancellation inside notifier callbacks.
- for (auto& notifier : one_shots_being_invoked_)
+ for (auto& notifier : *one_shots_being_invoked_)
notifier->RunSuccessCallback(last_position_);
for (auto& notifier : watchers_being_invoked_)
notifier->RunSuccessCallback(last_position_);
@@ -427,7 +430,7 @@ void Geolocation::MakeSuccessCallbacks() {
if (!HasListeners())
StopUpdating();
- one_shots_being_invoked_.clear();
+ one_shots_being_invoked_->clear();
watchers_being_invoked_.clear();
}
@@ -510,7 +513,7 @@ void Geolocation::PageVisibilityChanged() {
}
bool Geolocation::HasPendingActivity() const {
- return !one_shots_.IsEmpty() || !one_shots_being_invoked_.IsEmpty() ||
+ return !one_shots_->IsEmpty() || !one_shots_being_invoked_->IsEmpty() ||
!watchers_->IsEmpty() || !watchers_being_invoked_.IsEmpty();
}
diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.h b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.h
index 86f6281730e..7b86f1d43f9 100644
--- a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.h
+++ b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.h
@@ -120,49 +120,47 @@ class MODULES_EXPORT Geolocation final
private:
// Customized HeapHashSet class that checks notifiers' timers. Notifier's
// timer may be active only when the notifier is owned by the Geolocation.
- class GeoNotifierSet : private HeapHashSet<Member<GeoNotifier>> {
- using BaseClass = HeapHashSet<Member<GeoNotifier>>;
-
+ class GeoNotifierSet final : public GarbageCollected<GeoNotifierSet> {
public:
- using BaseClass::Trace;
-
- using BaseClass::const_iterator;
- using BaseClass::iterator;
+ void Trace(Visitor* visitor) const { visitor->Trace(set_); }
- using BaseClass::begin;
- using BaseClass::end;
- using BaseClass::size;
+ auto begin() const { return set_.begin(); }
+ auto end() const { return set_.end(); }
+ auto size() const { return set_.size(); }
auto insert(GeoNotifier* value) {
DCHECK(!value->IsTimerActive());
- return BaseClass::insert(value);
+ return set_.insert(value);
}
void erase(GeoNotifier* value) {
DCHECK(!value->IsTimerActive());
- return BaseClass::erase(value);
+ return set_.erase(value);
}
void clear() {
#if DCHECK_IS_ON()
- for (const auto& notifier : *this) {
+ for (const auto& notifier : set_) {
DCHECK(!notifier->IsTimerActive());
}
#endif
- BaseClass::clear();
+ set_.clear();
}
- using BaseClass::Contains;
- using BaseClass::IsEmpty;
+ auto Contains(GeoNotifier* value) const { return set_.Contains(value); }
+ auto IsEmpty() const { return set_.IsEmpty(); }
auto InsertWithoutTimerCheck(GeoNotifier* value) {
- return BaseClass::insert(value);
+ return set_.insert(value);
}
- void ClearWithoutTimerCheck() { BaseClass::clear(); }
+ void ClearWithoutTimerCheck() { set_.clear(); }
+
+ private:
+ HeapHashSet<Member<GeoNotifier>> set_;
};
bool HasListeners() const {
- return !one_shots_.IsEmpty() || !watchers_->IsEmpty();
+ return !one_shots_->IsEmpty() || !watchers_->IsEmpty();
}
void StopTimers();
@@ -204,7 +202,7 @@ class MODULES_EXPORT Geolocation final
void OnGeolocationPermissionStatusUpdated(GeoNotifier*,
mojom::PermissionStatus);
- GeoNotifierSet one_shots_;
+ Member<GeoNotifierSet> one_shots_;
Member<GeolocationWatchers> watchers_;
// GeoNotifiers that are in the middle of invocation.
//
@@ -217,7 +215,7 @@ class MODULES_EXPORT Geolocation final
// wrapper-tracing.
// TODO(https://crbug.com/796145): Remove this hack once on-stack objects
// get supported by either of wrapper-tracing or unified GC.
- GeoNotifierSet one_shots_being_invoked_;
+ Member<GeoNotifierSet> one_shots_being_invoked_;
HeapVector<Member<GeoNotifier>> watchers_being_invoked_;
Member<Geoposition> last_position_;
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/BUILD.gn b/chromium/third_party/blink/renderer/modules/handwriting/BUILD.gn
new file mode 100644
index 00000000000..c4ab5d2ea81
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("handwriting") {
+ sources = [
+ "handwriting_drawing.cc",
+ "handwriting_drawing.h",
+ "handwriting_recognition_service.cc",
+ "handwriting_recognition_service.h",
+ "handwriting_recognizer.cc",
+ "handwriting_recognizer.h",
+ "handwriting_stroke.cc",
+ "handwriting_stroke.h",
+ "handwriting_type_converters.cc",
+ "handwriting_type_converters.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/OWNERS b/chromium/third_party/blink/renderer/modules/handwriting/OWNERS
new file mode 100644
index 00000000000..23b8ad4befb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/OWNERS
@@ -0,0 +1,4 @@
+mgiuca@chromium.org
+
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.cc
new file mode 100644
index 00000000000..4c07ad25baa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.cc
@@ -0,0 +1,115 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/handwriting/handwriting_drawing.h"
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_prediction.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_segment.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_stroke.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+
+namespace blink {
+
+namespace {
+// The callback to get the recognition result.
+void OnRecognitionResult(
+ ScriptPromiseResolver* resolver,
+ ScriptState* script_state,
+ base::Optional<Vector<handwriting::mojom::blink::HandwritingPredictionPtr>>
+ predictions) {
+ // If `predictions` does not have value, it means the some error happened in
+ // recognition. Otherwise, if it has value but the vector is empty, it means
+ // the recognition works fine but it can not recognize anything from the
+ // input.
+ if (!predictions.has_value()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError, "Internal error."));
+ return;
+ }
+ HeapVector<Member<HandwritingPrediction>> result;
+ for (const auto& pred_mojo : predictions.value()) {
+ result.push_back(pred_mojo.To<blink::HandwritingPrediction*>());
+ }
+ resolver->Resolve(std::move(result));
+}
+} // namespace
+
+HandwritingDrawing::HandwritingDrawing(ExecutionContext* context,
+ HandwritingRecognizer* recognizer,
+ const HandwritingHints* hints)
+ : hints_(MakeGarbageCollected<HandwritingHints>(*hints)),
+ recognizer_(recognizer) {}
+
+HandwritingDrawing::~HandwritingDrawing() = default;
+
+void HandwritingDrawing::addStroke(HandwritingStroke* stroke) {
+ // It is meaningless to add stroke to an invalidated drawing. However we may
+ // need to remove/clear strokes to save resource.
+ if (IsValid()) {
+ strokes_.push_back(stroke);
+ }
+}
+
+void HandwritingDrawing::removeStroke(const HandwritingStroke* stroke) {
+ wtf_size_t pos = strokes_.ReverseFind(stroke);
+ if (pos != kNotFound) {
+ strokes_.EraseAt(pos);
+ }
+}
+
+void HandwritingDrawing::clear() {
+ strokes_.clear();
+}
+
+const HeapVector<Member<HandwritingStroke>>& HandwritingDrawing::getStrokes() {
+ return strokes_;
+}
+
+ScriptPromise HandwritingDrawing::getPrediction(ScriptState* script_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ if (!IsValid()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError,
+ "The recognizer has been invalidated."));
+ return promise;
+ }
+
+ Vector<handwriting::mojom::blink::HandwritingStrokePtr> strokes;
+ for (const auto& stroke : strokes_) {
+ strokes.push_back(
+ mojo::ConvertTo<handwriting::mojom::blink::HandwritingStrokePtr>(
+ stroke.Get()));
+ }
+
+ recognizer_->GetPrediction(
+ std::move(strokes),
+ mojo::ConvertTo<handwriting::mojom::blink::HandwritingHintsPtr>(
+ hints_.Get()),
+ WTF::Bind(&OnRecognitionResult, WrapPersistent(resolver),
+ WrapPersistent(script_state)));
+
+ return promise;
+}
+
+void HandwritingDrawing::Trace(Visitor* visitor) const {
+ visitor->Trace(hints_);
+ visitor->Trace(strokes_);
+ visitor->Trace(recognizer_);
+ ScriptWrappable::Trace(visitor);
+}
+
+bool HandwritingDrawing::IsValid() const {
+ return recognizer_ != nullptr && recognizer_->IsValid();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.h b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.h
new file mode 100644
index 00000000000..506bddfe5de
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_DRAWING_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_DRAWING_H_
+
+#include "base/macros.h"
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink-forward.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+class ExecutionContext;
+class HandwritingRecognizer;
+class HandwritingStroke;
+class ScriptState;
+
+class HandwritingDrawing final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit HandwritingDrawing(ExecutionContext* context,
+ HandwritingRecognizer* recognizer,
+ const HandwritingHints* hints);
+ ~HandwritingDrawing() override;
+
+ // IDL Interface:
+ void addStroke(HandwritingStroke* stroke);
+ void removeStroke(const HandwritingStroke* stroke);
+ void clear();
+ ScriptPromise getPrediction(ScriptState* script_state);
+ const HeapVector<Member<HandwritingStroke>>& getStrokes();
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ bool IsValid() const;
+
+ Member<HandwritingHints> hints_;
+
+ HeapVector<Member<HandwritingStroke>> strokes_;
+
+ WeakMember<HandwritingRecognizer> recognizer_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandwritingDrawing);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_DRAWING_H_
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl
new file mode 100644
index 00000000000..a4a0e3e47b3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing.idl
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+[
+ SecureContext,
+ RuntimeEnabled=HandwritingRecognition
+] interface HandwritingDrawing {
+ void addStroke(HandwritingStroke stroke);
+ void removeStroke(HandwritingStroke stroke);
+ void clear();
+ sequence<HandwritingStroke> getStrokes();
+
+ [CallWith=ScriptState]
+ Promise<sequence<HandwritingPrediction>> getPrediction();
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing_segment.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing_segment.idl
new file mode 100644
index 00000000000..42e98a93140
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_drawing_segment.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingDrawingSegment {
+ // TODO(crbug.com/1166910): We may use stroke reference rather than index.
+ required unsigned long strokeIndex;
+ required unsigned long beginPointIndex;
+ required unsigned long endPointIndex;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query.idl
new file mode 100644
index 00000000000..358cd065fdb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingFeatureQuery {
+ sequence<DOMString> languages;
+ any alternatives;
+ any segmentationResult;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query_result.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query_result.idl
new file mode 100644
index 00000000000..65697c62a2a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_feature_query_result.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingFeatureQueryResult {
+ boolean languages;
+ boolean alternatives;
+ boolean segmentationResult;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_hints.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_hints.idl
new file mode 100644
index 00000000000..20ba6faa5c0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_hints.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingHints {
+ DOMString recognitionType = "text";
+ DOMString inputType = "mouse";
+ DOMString textContext = "";
+ unsigned long alternatives = 3;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_model_constraint.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_model_constraint.idl
new file mode 100644
index 00000000000..84b555d4939
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_model_constraint.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingModelConstraint {
+ required sequence<DOMString> languages;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_point.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_point.idl
new file mode 100644
index 00000000000..6498c2a9f0c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_point.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingPoint {
+ double x;
+ double y;
+ // Timestamp in ms since the start of the current drawing.
+ DOMTimeStamp t;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_prediction.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_prediction.idl
new file mode 100644
index 00000000000..f21ee8c3573
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_prediction.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingPrediction {
+ required DOMString text;
+ sequence<HandwritingSegment> segmentationResult;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.cc
new file mode 100644
index 00000000000..d7cd3c67bc9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.cc
@@ -0,0 +1,165 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.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_handwriting_feature_query.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_model_constraint.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/modules/handwriting/handwriting_recognizer.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h"
+
+namespace blink {
+
+namespace {
+
+void OnCreateHandwritingRecognizer(
+ ScriptState* script_state,
+ ScriptPromiseResolver* resolver,
+ handwriting::mojom::blink::CreateHandwritingRecognizerResult result,
+ mojo::PendingRemote<handwriting::mojom::blink::HandwritingRecognizer>
+ pending_remote) {
+ if (result !=
+ handwriting::mojom::blink::CreateHandwritingRecognizerResult::kOk) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotSupportedError, "Internal error."));
+ return;
+ }
+
+ auto* handwriting_recognizer = MakeGarbageCollected<HandwritingRecognizer>(
+ ExecutionContext::From(script_state), std::move(pending_remote));
+ resolver->Resolve(handwriting_recognizer);
+}
+
+void OnQueryHandwritingFeature(
+ ScriptState* script_state,
+ ScriptPromiseResolver* resolver,
+ handwriting::mojom::blink::HandwritingFeatureQueryResultPtr query_result) {
+ resolver->Resolve(
+ mojo::ConvertTo<HandwritingFeatureQueryResult*>(std::move(query_result)));
+}
+
+} // namespace
+
+const char HandwritingRecognitionService::kSupplementName[] =
+ "NavigatorHandwritingRecognitionService";
+
+HandwritingRecognitionService::HandwritingRecognitionService(
+ Navigator& navigator)
+ : Supplement<Navigator>(navigator),
+ remote_service_(navigator.GetExecutionContext()) {}
+
+// static
+HandwritingRecognitionService& HandwritingRecognitionService::From(
+ Navigator& navigator) {
+ HandwritingRecognitionService* supplement =
+ Supplement<Navigator>::From<HandwritingRecognitionService>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<HandwritingRecognitionService>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return *supplement;
+}
+
+// static
+ScriptPromise HandwritingRecognitionService::createHandwritingRecognizer(
+ ScriptState* script_state,
+ Navigator& navigator,
+ const HandwritingModelConstraint* constraint,
+ ExceptionState& exception_state) {
+ return HandwritingRecognitionService::From(navigator)
+ .CreateHandwritingRecognizer(script_state, constraint, exception_state);
+}
+
+bool HandwritingRecognitionService::BootstrapMojoConnectionIfNeeded(
+ ScriptState* script_state,
+ ExceptionState& exception_state) {
+ // We need to do the following check because the execution context of this
+ // navigator may be invalid (e.g. the frame is detached).
+ if (!script_state->ContextIsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The execution context is invalid");
+ return false;
+ }
+ // Note that we do not use `ExecutionContext::From(script_state)` because
+ // the ScriptState passed in may not be guaranteed to match the execution
+ // context associated with this navigator, especially with
+ // cross-browsing-context calls.
+ auto* execution_context = GetSupplementable()->GetExecutionContext();
+ if (!remote_service_.is_bound()) {
+ execution_context->GetBrowserInterfaceBroker().GetInterface(
+ remote_service_.BindNewPipeAndPassReceiver(
+ execution_context->GetTaskRunner(TaskType::kInternalDefault)));
+ }
+ return true;
+}
+
+ScriptPromise HandwritingRecognitionService::CreateHandwritingRecognizer(
+ ScriptState* script_state,
+ const HandwritingModelConstraint* blink_model_constraint,
+ ExceptionState& exception_state) {
+ if (!BootstrapMojoConnectionIfNeeded(script_state, exception_state)) {
+ return ScriptPromise();
+ }
+
+ ScriptPromiseResolver* resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+
+ auto mojo_model_constraint =
+ handwriting::mojom::blink::HandwritingModelConstraint::New();
+
+ for (auto const& lang : blink_model_constraint->languages()) {
+ mojo_model_constraint->languages.push_back(lang);
+ }
+
+ remote_service_->CreateHandwritingRecognizer(
+ std::move(mojo_model_constraint),
+ WTF::Bind(OnCreateHandwritingRecognizer, WrapPersistent(script_state),
+ WrapPersistent(resolver)));
+
+ return promise;
+}
+
+// static
+ScriptPromise HandwritingRecognitionService::queryHandwritingRecognizerSupport(
+ ScriptState* script_state,
+ Navigator& navigator,
+ const HandwritingFeatureQuery* query,
+ ExceptionState& exception_state) {
+ return HandwritingRecognitionService::From(navigator)
+ .QueryHandwritingRecognizerSupport(script_state, query, exception_state);
+}
+
+ScriptPromise HandwritingRecognitionService::QueryHandwritingRecognizerSupport(
+ ScriptState* script_state,
+ const HandwritingFeatureQuery* query,
+ ExceptionState& exception_state) {
+ if (!BootstrapMojoConnectionIfNeeded(script_state, exception_state)) {
+ return ScriptPromise();
+ }
+
+ ScriptPromiseResolver* resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+
+ remote_service_->QueryHandwritingRecognizerSupport(
+ mojo::ConvertTo<handwriting::mojom::blink::HandwritingFeatureQueryPtr>(
+ query),
+ WTF::Bind(&OnQueryHandwritingFeature, WrapPersistent(script_state),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+void HandwritingRecognitionService::Trace(Visitor* visitor) const {
+ visitor->Trace(remote_service_);
+ Supplement<Navigator>::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.h b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.h
new file mode 100644
index 00000000000..3296c2eb2ef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNITION_SERVICE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNITION_SERVICE_H_
+
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ExecutionContext;
+class HandwritingModelConstraint;
+class HandwritingFeatureQuery;
+class ScriptState;
+
+class HandwritingRecognitionService final
+ : public GarbageCollected<HandwritingRecognitionService>,
+ public Supplement<Navigator> {
+ public:
+ static const char kSupplementName[];
+
+ explicit HandwritingRecognitionService(Navigator&);
+
+ static HandwritingRecognitionService& From(Navigator&);
+
+ // IDL Interface:
+ static ScriptPromise createHandwritingRecognizer(
+ ScriptState*,
+ Navigator&,
+ const HandwritingModelConstraint*,
+ ExceptionState&);
+ static ScriptPromise queryHandwritingRecognizerSupport(
+ ScriptState*,
+ Navigator&,
+ const HandwritingFeatureQuery*,
+ ExceptionState&);
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ // Bind the Mojo connection to browser process if needed.
+ // Returns false when the execution context is not valid (e.g., the frame is
+ // detached) and an exception will be thrown.
+ // Otherwise returns true.
+ bool BootstrapMojoConnectionIfNeeded(ScriptState*, ExceptionState&);
+ ScriptPromise CreateHandwritingRecognizer(ScriptState*,
+ const HandwritingModelConstraint*,
+ ExceptionState&);
+
+ ScriptPromise QueryHandwritingRecognizerSupport(
+ ScriptState*,
+ const HandwritingFeatureQuery*,
+ ExceptionState&);
+
+ HeapMojoRemote<handwriting::mojom::blink::HandwritingRecognitionService>
+ remote_service_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNITION_SERVICE_H_
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.cc
new file mode 100644
index 00000000000..cca9d7a8d10
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h"
+
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_drawing.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+namespace {
+const char kInvalidErrorMessage[] = "This recognizer has been invalidated.";
+}
+
+HandwritingRecognizer::HandwritingRecognizer(
+ ExecutionContext* context,
+ mojo::PendingRemote<handwriting::mojom::blink::HandwritingRecognizer>
+ pending_remote)
+ : remote_service_(context) {
+ remote_service_.Bind(std::move(pending_remote),
+ context->GetTaskRunner(TaskType::kInternalDefault));
+}
+
+HandwritingRecognizer::~HandwritingRecognizer() = default;
+
+bool HandwritingRecognizer::IsValid() {
+ return remote_service_.is_bound();
+}
+
+void HandwritingRecognizer::GetPrediction(
+ Vector<handwriting::mojom::blink::HandwritingStrokePtr> strokes,
+ handwriting::mojom::blink::HandwritingHintsPtr hints,
+ handwriting::mojom::blink::HandwritingRecognizer::GetPredictionCallback
+ callback) {
+ remote_service_->GetPrediction(std::move(strokes), std::move(hints),
+ std::move(callback));
+}
+
+HandwritingDrawing* HandwritingRecognizer::startDrawing(
+ ScriptState* script_state,
+ const HandwritingHints* hints,
+ ExceptionState& exception_state) {
+ if (!IsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidErrorMessage);
+ return nullptr;
+ }
+
+ auto* handwriting_drawing = MakeGarbageCollected<HandwritingDrawing>(
+ ExecutionContext::From(script_state), this, hints);
+
+ return handwriting_drawing;
+}
+
+void HandwritingRecognizer::finish(ExceptionState& exception_state) {
+ if (!IsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidErrorMessage);
+ return;
+ }
+
+ Invalidate();
+}
+
+void HandwritingRecognizer::Trace(Visitor* visitor) const {
+ visitor->Trace(remote_service_);
+ ScriptWrappable::Trace(visitor);
+}
+
+void HandwritingRecognizer::Invalidate() {
+ remote_service_.reset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h
new file mode 100644
index 00000000000..05a9636cfe9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h
@@ -0,0 +1,62 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNIZER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNIZER_H_
+
+#include "base/macros.h"
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+
+namespace blink {
+
+class ExceptionState;
+class ExecutionContext;
+class HandwritingDrawing;
+class HandwritingHints;
+class ScriptState;
+
+class HandwritingRecognizer final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit HandwritingRecognizer(
+ ExecutionContext* context,
+ mojo::PendingRemote<handwriting::mojom::blink::HandwritingRecognizer>
+ pending_remote);
+ ~HandwritingRecognizer() override;
+
+ // Used by the drawing to see if the recognizer is valid.
+ bool IsValid();
+
+ // Gets prediction, called by `HandwritingDrawing`.
+ void GetPrediction(
+ Vector<handwriting::mojom::blink::HandwritingStrokePtr> strokes,
+ handwriting::mojom::blink::HandwritingHintsPtr hints,
+ handwriting::mojom::blink::HandwritingRecognizer::GetPredictionCallback
+ callback);
+
+ // IDL Interface:
+ HandwritingDrawing* startDrawing(ScriptState* script_state,
+ const HandwritingHints* hints,
+ ExceptionState& exception_state);
+ void finish(ExceptionState& exception_state);
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ // This function will invalidate the recognizer and its drawings;
+ void Invalidate();
+
+ HeapMojoRemote<handwriting::mojom::blink::HandwritingRecognizer>
+ remote_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandwritingRecognizer);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_RECOGNIZER_H_
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl
new file mode 100644
index 00000000000..09bc3d8b49f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_recognizer.idl
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+[
+ SecureContext,
+ RuntimeEnabled=HandwritingRecognition
+] interface HandwritingRecognizer {
+
+ [CallWith=ScriptState, RaisesException]
+ HandwritingDrawing startDrawing(optional HandwritingHints hints = {});
+
+ [RaisesException] void finish();
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_segment.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_segment.idl
new file mode 100644
index 00000000000..ba2d9e11040
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_segment.idl
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+dictionary HandwritingSegment {
+ required DOMString grapheme;
+ required unsigned long beginIndex;
+ required unsigned long endIndex;
+ required sequence<HandwritingDrawingSegment> drawingSegments;
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.cc
new file mode 100644
index 00000000000..a8d10d883de
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/handwriting/handwriting_stroke.h"
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_point.h"
+
+namespace blink {
+
+HandwritingStroke::HandwritingStroke() = default;
+
+HandwritingStroke::~HandwritingStroke() = default;
+
+// static
+HandwritingStroke* HandwritingStroke::Create() {
+ return MakeGarbageCollected<HandwritingStroke>();
+}
+
+void HandwritingStroke::addPoint(const HandwritingPoint* point) {
+ points_.push_back(point);
+}
+
+const HeapVector<Member<const HandwritingPoint>>& HandwritingStroke::getPoints()
+ const {
+ return points_;
+}
+
+void HandwritingStroke::clear() {
+ points_.clear();
+}
+
+void HandwritingStroke::Trace(Visitor* visitor) const {
+ visitor->Trace(points_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.h b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.h
new file mode 100644
index 00000000000..fdac1905d88
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_STROKE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_STROKE_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/remote.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/platform/heap/collection_support/heap_vector.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+class HandwritingPoint;
+
+class MODULES_EXPORT HandwritingStroke final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ HandwritingStroke();
+ ~HandwritingStroke() override;
+
+ static HandwritingStroke* Create();
+
+ // IDL Interface:
+ void addPoint(const HandwritingPoint* point);
+ const HeapVector<Member<const HandwritingPoint>>& getPoints() const;
+ void clear();
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ HeapVector<Member<const HandwritingPoint>> points_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandwritingStroke);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_STROKE_H_
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.idl b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.idl
new file mode 100644
index 00000000000..1db8b0ec98f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_stroke.idl
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=HandwritingRecognition
+] interface HandwritingStroke {
+ constructor();
+ void addPoint(HandwritingPoint point);
+ // Get a copy of the points added to the stroke.
+ // TODO(crbug.com/1166910): Clarify to users that they can't modify the
+ // points using getPoints. According to the comments by @glenrob and @qjw,
+ // this may mislead the user that they can modify the points by modifying the
+ // returned value. We need to figure out to make it more clear that they can't
+ // and either shouldn't modify the points througth the method.
+ sequence<HandwritingPoint> getPoints();
+ void clear();
+};
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.cc
new file mode 100644
index 00000000000..71771bcecd7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.cc
@@ -0,0 +1,204 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h"
+
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_point.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_prediction.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_segment.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_stroke.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace mojo {
+
+using handwriting::mojom::blink::HandwritingDrawingSegmentPtr;
+using handwriting::mojom::blink::HandwritingFeatureQueryPtr;
+using handwriting::mojom::blink::HandwritingFeatureQueryResultPtr;
+using handwriting::mojom::blink::HandwritingFeatureStatus;
+using handwriting::mojom::blink::HandwritingHintsPtr;
+using handwriting::mojom::blink::HandwritingPointPtr;
+using handwriting::mojom::blink::HandwritingPredictionPtr;
+using handwriting::mojom::blink::HandwritingSegmentPtr;
+using handwriting::mojom::blink::HandwritingStrokePtr;
+
+// Converters from IDL to Mojo.
+
+// static
+HandwritingPointPtr
+TypeConverter<HandwritingPointPtr, blink::HandwritingPoint*>::Convert(
+ const blink::HandwritingPoint* input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto output = handwriting::mojom::blink::HandwritingPoint::New();
+ output->location = gfx::PointF(input->x(), input->y());
+ output->t = base::TimeDelta::FromMilliseconds(input->t());
+ return output;
+}
+
+// static
+HandwritingStrokePtr
+TypeConverter<HandwritingStrokePtr, blink::HandwritingStroke*>::Convert(
+ const blink::HandwritingStroke* input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto output = handwriting::mojom::blink::HandwritingStroke::New();
+ for (const auto& point : input->getPoints()) {
+ output->points.push_back(mojo::ConvertTo<HandwritingPointPtr>(point.Get()));
+ }
+ return output;
+}
+
+// static
+HandwritingHintsPtr
+TypeConverter<HandwritingHintsPtr, blink::HandwritingHints*>::Convert(
+ const blink::HandwritingHints* input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto output = handwriting::mojom::blink::HandwritingHints::New();
+ output->recognition_type = input->recognitionType();
+ output->input_type = input->inputType();
+ output->text_context = input->textContext();
+ output->alternatives = input->alternatives();
+ return output;
+}
+
+// static
+HandwritingFeatureQueryPtr
+TypeConverter<HandwritingFeatureQueryPtr, blink::HandwritingFeatureQuery*>::
+ Convert(const blink::HandwritingFeatureQuery* input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto output = handwriting::mojom::blink::HandwritingFeatureQuery::New();
+ if (input->hasLanguages()) {
+ for (const auto& lang : input->languages()) {
+ output->languages.push_back(lang);
+ }
+ }
+ output->alternatives = input->hasAlternatives();
+ output->segmentation_result = input->hasSegmentationResult();
+
+ return output;
+}
+
+// Converters from Mojo to IDL.
+
+// static
+blink::HandwritingPoint*
+TypeConverter<blink::HandwritingPoint*, HandwritingPointPtr>::Convert(
+ const HandwritingPointPtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingPoint::Create();
+ output->setX(input->location.x());
+ output->setY(input->location.y());
+ output->setT(input->t.InMilliseconds());
+ return output;
+}
+
+// static
+blink::HandwritingStroke*
+TypeConverter<blink::HandwritingStroke*, HandwritingStrokePtr>::Convert(
+ const HandwritingStrokePtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingStroke::Create();
+ for (const auto& point : input->points) {
+ output->addPoint(point.To<blink::HandwritingPoint*>());
+ }
+ return output;
+}
+
+// static
+blink::HandwritingFeatureQueryResult*
+TypeConverter<blink::HandwritingFeatureQueryResult*,
+ HandwritingFeatureQueryResultPtr>::
+ Convert(const HandwritingFeatureQueryResultPtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingFeatureQueryResult::Create();
+
+#define HANDWRITING_SET_FEATURE_QUERY_RESULT(feature, setter) \
+ if (input->feature != HandwritingFeatureStatus::kNotQueried) { \
+ if (input->feature == HandwritingFeatureStatus::kNotSupported) { \
+ output->setter(false); \
+ } else { \
+ output->setter(true); \
+ } \
+ }
+
+ HANDWRITING_SET_FEATURE_QUERY_RESULT(languages, setLanguages);
+ HANDWRITING_SET_FEATURE_QUERY_RESULT(alternatives, setAlternatives);
+ HANDWRITING_SET_FEATURE_QUERY_RESULT(segmentation_result,
+ setSegmentationResult);
+#undef HANDWRITING_SET_FEATURE_QUERY_RESULT
+
+ return output;
+}
+
+// static
+blink::HandwritingDrawingSegment*
+TypeConverter<blink::HandwritingDrawingSegment*, HandwritingDrawingSegmentPtr>::
+ Convert(const HandwritingDrawingSegmentPtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingDrawingSegment::Create();
+ output->setStrokeIndex(input->stroke_index);
+ output->setBeginPointIndex(input->begin_point_index);
+ output->setEndPointIndex(input->end_point_index);
+ return output;
+}
+
+// static
+blink::HandwritingSegment*
+TypeConverter<blink::HandwritingSegment*,
+ handwriting::mojom::blink::HandwritingSegmentPtr>::
+ Convert(const handwriting::mojom::blink::HandwritingSegmentPtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingSegment::Create();
+ output->setGrapheme(input->grapheme);
+ output->setBeginIndex(input->begin_index);
+ output->setEndIndex(input->end_index);
+ blink::HeapVector<blink::Member<blink::HandwritingDrawingSegment>>
+ drawing_segments;
+ for (const auto& drw_seg : input->drawing_segments) {
+ drawing_segments.push_back(drw_seg.To<blink::HandwritingDrawingSegment*>());
+ }
+ output->setDrawingSegments(std::move(drawing_segments));
+ return output;
+}
+
+// static
+blink::HandwritingPrediction*
+TypeConverter<blink::HandwritingPrediction*,
+ handwriting::mojom::blink::HandwritingPredictionPtr>::
+ Convert(const handwriting::mojom::blink::HandwritingPredictionPtr& input) {
+ if (!input) {
+ return nullptr;
+ }
+ auto* output = blink::HandwritingPrediction::Create();
+ output->setText(input->text);
+ blink::HeapVector<blink::Member<blink::HandwritingSegment>> segments;
+ for (const auto& seg : input->segmentation_result) {
+ segments.push_back(seg.To<blink::HandwritingSegment*>());
+ }
+ output->setSegmentationResult(std::move(segments));
+ return output;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h
new file mode 100644
index 00000000000..ceeb4533f5b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h
@@ -0,0 +1,113 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_TYPE_CONVERTERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_TYPE_CONVERTERS_H_
+
+#include <string>
+
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink-forward.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+class HandwritingDrawingSegment;
+class HandwritingFeatureQuery;
+class HandwritingFeatureQueryResult;
+class HandwritingHints;
+class HandwritingPoint;
+class HandwritingPrediction;
+class HandwritingSegment;
+class HandwritingStroke;
+} // namespace blink
+
+namespace mojo {
+
+// Converters from IDL to Mojo.
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<handwriting::mojom::blink::HandwritingPointPtr,
+ blink::HandwritingPoint*> {
+ static handwriting::mojom::blink::HandwritingPointPtr Convert(
+ const blink::HandwritingPoint* input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<handwriting::mojom::blink::HandwritingStrokePtr,
+ blink::HandwritingStroke*> {
+ static handwriting::mojom::blink::HandwritingStrokePtr Convert(
+ const blink::HandwritingStroke* input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<handwriting::mojom::blink::HandwritingHintsPtr,
+ blink::HandwritingHints*> {
+ static handwriting::mojom::blink::HandwritingHintsPtr Convert(
+ const blink::HandwritingHints* input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<handwriting::mojom::blink::HandwritingFeatureQueryPtr,
+ blink::HandwritingFeatureQuery*> {
+ static handwriting::mojom::blink::HandwritingFeatureQueryPtr Convert(
+ const blink::HandwritingFeatureQuery* input);
+};
+
+// Converters from Mojo to IDL.
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingPoint*,
+ handwriting::mojom::blink::HandwritingPointPtr> {
+ static blink::HandwritingPoint* Convert(
+ const handwriting::mojom::blink::HandwritingPointPtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingStroke*,
+ handwriting::mojom::blink::HandwritingStrokePtr> {
+ static blink::HandwritingStroke* Convert(
+ const handwriting::mojom::blink::HandwritingStrokePtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingFeatureQueryResult*,
+ handwriting::mojom::blink::HandwritingFeatureQueryResultPtr> {
+ static blink::HandwritingFeatureQueryResult* Convert(
+ const handwriting::mojom::blink::HandwritingFeatureQueryResultPtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingDrawingSegment*,
+ handwriting::mojom::blink::HandwritingDrawingSegmentPtr> {
+ static blink::HandwritingDrawingSegment* Convert(
+ const handwriting::mojom::blink::HandwritingDrawingSegmentPtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingSegment*,
+ handwriting::mojom::blink::HandwritingSegmentPtr> {
+ static blink::HandwritingSegment* Convert(
+ const handwriting::mojom::blink::HandwritingSegmentPtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+ TypeConverter<blink::HandwritingPrediction*,
+ handwriting::mojom::blink::HandwritingPredictionPtr> {
+ static blink::HandwritingPrediction* Convert(
+ const handwriting::mojom::blink::HandwritingPredictionPtr& input);
+};
+
+} // namespace mojo
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HANDWRITING_HANDWRITING_TYPE_CONVERTERS_H_
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters_unittest.cc b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters_unittest.cc
new file mode 100644
index 00000000000..d78ac1f5814
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/handwriting_type_converters_unittest.cc
@@ -0,0 +1,246 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/handwriting/handwriting.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_hints.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_point.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_prediction.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_segment.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_stroke.h"
+#include "third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h"
+
+namespace blink {
+
+using handwriting::mojom::blink::HandwritingDrawingSegmentPtr;
+using handwriting::mojom::blink::HandwritingFeatureQueryPtr;
+using handwriting::mojom::blink::HandwritingFeatureQueryResultPtr;
+using handwriting::mojom::blink::HandwritingFeatureStatus;
+using handwriting::mojom::blink::HandwritingHintsPtr;
+using handwriting::mojom::blink::HandwritingPointPtr;
+using handwriting::mojom::blink::HandwritingPredictionPtr;
+using handwriting::mojom::blink::HandwritingSegmentPtr;
+using handwriting::mojom::blink::HandwritingStrokePtr;
+
+TEST(HandwritingTypeConvertersTest, IdlHandwritingPointToMojo) {
+ auto* idl_point = blink::HandwritingPoint::Create();
+
+ idl_point->setX(1.1);
+ idl_point->setY(2.3);
+ idl_point->setT(345);
+
+ auto mojo_point = mojo::ConvertTo<HandwritingPointPtr>(idl_point);
+ ASSERT_FALSE(mojo_point.is_null());
+ EXPECT_NEAR(mojo_point->location.x(), 1.1, 1e-5);
+ EXPECT_NEAR(mojo_point->location.y(), 2.3, 1e-5);
+ EXPECT_EQ(mojo_point->t.InMilliseconds(), 345);
+}
+
+TEST(HandwritingTypeConvertersTest, IdlHandwritingStrokeToMojo) {
+ auto* idl_stroke = blink::HandwritingStroke::Create();
+ auto* idl_point1 = blink::HandwritingPoint::Create();
+ idl_point1->setX(0.1);
+ idl_point1->setY(0.2);
+ idl_point1->setT(123);
+ auto* idl_point2 = blink::HandwritingPoint::Create();
+ idl_stroke->addPoint(idl_point1);
+ idl_point2->setX(1.1);
+ idl_point2->setY(1.2);
+ idl_point2->setT(456);
+ idl_stroke->addPoint(idl_point2);
+
+ auto mojo_stroke = mojo::ConvertTo<HandwritingStrokePtr>(idl_stroke);
+ ASSERT_FALSE(mojo_stroke.is_null());
+ ASSERT_EQ(mojo_stroke->points.size(), 2u);
+ EXPECT_NEAR(mojo_stroke->points[0]->location.x(), 0.1, 1e-5);
+ EXPECT_NEAR(mojo_stroke->points[0]->location.y(), 0.2, 1e-5);
+ EXPECT_EQ(mojo_stroke->points[0]->t.InMilliseconds(), 123);
+ EXPECT_NEAR(mojo_stroke->points[1]->location.x(), 1.1, 1e-5);
+ EXPECT_NEAR(mojo_stroke->points[1]->location.y(), 1.2, 1e-5);
+ EXPECT_EQ(mojo_stroke->points[1]->t.InMilliseconds(), 456);
+}
+
+TEST(HandwritingTypeConvertersTest, IdlHandwritingHintsToMojo) {
+ auto* idl_hints = blink::HandwritingHints::Create();
+ idl_hints->setRecognitionType("recognition type");
+ idl_hints->setInputType("input type");
+ idl_hints->setTextContext("text context");
+ idl_hints->setAlternatives(10);
+
+ auto mojo_hints = mojo::ConvertTo<HandwritingHintsPtr>(idl_hints);
+ ASSERT_FALSE(mojo_hints.is_null());
+ EXPECT_EQ(mojo_hints->recognition_type, "recognition type");
+ EXPECT_EQ(mojo_hints->input_type, "input type");
+ EXPECT_EQ(mojo_hints->text_context, "text context");
+ EXPECT_EQ(mojo_hints->alternatives, 10u);
+}
+
+TEST(HandwritingTypeConvertersTest, IdlHandwritingFeatureQueryToMojo) {
+ V8TestingScope v8_testing_scope;
+ auto* idl_query = blink::HandwritingFeatureQuery::Create();
+ idl_query->setLanguages({"en", "fr"});
+ idl_query->setAlternatives(
+ blink::ScriptValue::From(v8_testing_scope.GetScriptState(), 10));
+ // Intentionally does not set `segmentationResult`.
+
+ auto mojo_query = mojo::ConvertTo<HandwritingFeatureQueryPtr>(idl_query);
+ ASSERT_FALSE(mojo_query.is_null());
+ ASSERT_EQ(mojo_query->languages.size(), 2u);
+ EXPECT_EQ(mojo_query->languages[0], "en");
+ EXPECT_EQ(mojo_query->languages[1], "fr");
+ EXPECT_EQ(mojo_query->alternatives, true);
+ EXPECT_EQ(mojo_query->segmentation_result, false);
+}
+
+TEST(HandwritingTypeConvertersTest,
+ IdlEmptyLanguageHandwritingFeatureQueryToMojo) {
+ V8TestingScope v8_testing_scope;
+ auto* idl_query = blink::HandwritingFeatureQuery::Create();
+ // Intentionally does not set `languages`.
+ // Intentionally does not set `alternatives`.
+ idl_query->setSegmentationResult(
+ blink::ScriptValue::From(v8_testing_scope.GetScriptState(), "a"));
+
+ auto mojo_query = mojo::ConvertTo<HandwritingFeatureQueryPtr>(idl_query);
+ ASSERT_FALSE(mojo_query.is_null());
+ ASSERT_EQ(mojo_query->languages.size(), 0u);
+ EXPECT_EQ(mojo_query->alternatives, false);
+ EXPECT_EQ(mojo_query->segmentation_result, true);
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingPointToIdl) {
+ auto mojo_point = handwriting::mojom::blink::HandwritingPoint::New();
+ mojo_point->location = gfx::PointF(0.3, 0.4);
+ mojo_point->t = base::TimeDelta::FromMilliseconds(123);
+
+ auto* idl_point = mojo::ConvertTo<blink::HandwritingPoint*>(mojo_point);
+ ASSERT_NE(idl_point, nullptr);
+ EXPECT_NEAR(idl_point->x(), 0.3, 1e-5);
+ EXPECT_NEAR(idl_point->y(), 0.4, 1e-5);
+ EXPECT_EQ(idl_point->t(), 123u);
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingStrokeToIdl) {
+ auto mojo_stroke = handwriting::mojom::blink::HandwritingStroke::New();
+ auto mojo_point1 = handwriting::mojom::blink::HandwritingPoint::New();
+ mojo_point1->location = gfx::PointF(2.1, 2.2);
+ mojo_point1->t = base::TimeDelta::FromMilliseconds(321);
+ mojo_stroke->points.push_back(std::move(mojo_point1));
+ auto mojo_point2 = handwriting::mojom::blink::HandwritingPoint::New();
+ mojo_point2->location = gfx::PointF(3.1, 3.2);
+ mojo_point2->t = base::TimeDelta::FromMilliseconds(456);
+ mojo_stroke->points.push_back(std::move(mojo_point2));
+
+ auto* idl_stroke = mojo::ConvertTo<blink::HandwritingStroke*>(mojo_stroke);
+ ASSERT_NE(idl_stroke, nullptr);
+ ASSERT_EQ(idl_stroke->getPoints().size(), 2u);
+ EXPECT_NEAR(idl_stroke->getPoints()[0]->x(), 2.1, 1e-5);
+ EXPECT_NEAR(idl_stroke->getPoints()[0]->y(), 2.2, 1e-5);
+ EXPECT_EQ(idl_stroke->getPoints()[0]->t(), 321u);
+ EXPECT_NEAR(idl_stroke->getPoints()[1]->x(), 3.1, 1e-5);
+ EXPECT_NEAR(idl_stroke->getPoints()[1]->y(), 3.2, 1e-5);
+ EXPECT_EQ(idl_stroke->getPoints()[1]->t(), 456u);
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingFeatureQueryResultIdl) {
+ auto mojo_query_result =
+ handwriting::mojom::blink::HandwritingFeatureQueryResult::New();
+ mojo_query_result->languages = HandwritingFeatureStatus::kNotQueried;
+ mojo_query_result->alternatives = HandwritingFeatureStatus::kSupported;
+ mojo_query_result->segmentation_result =
+ HandwritingFeatureStatus::kNotSupported;
+
+ auto* idl_query_result =
+ mojo::ConvertTo<blink::HandwritingFeatureQueryResult*>(mojo_query_result);
+ ASSERT_NE(idl_query_result, nullptr);
+ EXPECT_FALSE(idl_query_result->hasLanguages());
+ ASSERT_TRUE(idl_query_result->hasAlternatives());
+ EXPECT_TRUE(idl_query_result->alternatives());
+ ASSERT_TRUE(idl_query_result->hasSegmentationResult());
+ EXPECT_FALSE(idl_query_result->segmentationResult());
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingDrawingSegmentIdl) {
+ auto mojo_drawing_segment =
+ handwriting::mojom::blink::HandwritingDrawingSegment::New();
+ mojo_drawing_segment->stroke_index = 123u;
+ mojo_drawing_segment->begin_point_index = 10u;
+ mojo_drawing_segment->end_point_index = 20u;
+
+ auto* idl_drawing_segment =
+ mojo_drawing_segment.To<blink::HandwritingDrawingSegment*>();
+ EXPECT_EQ(idl_drawing_segment->strokeIndex(), 123u);
+ EXPECT_EQ(idl_drawing_segment->beginPointIndex(), 10u);
+ EXPECT_EQ(idl_drawing_segment->endPointIndex(), 20u);
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingSegmentIdl) {
+ auto mojo_drawing_segment =
+ handwriting::mojom::blink::HandwritingDrawingSegment::New();
+ mojo_drawing_segment->stroke_index = 321u;
+ mojo_drawing_segment->begin_point_index = 30u;
+ mojo_drawing_segment->end_point_index = 40u;
+ auto mojo_segment = handwriting::mojom::blink::HandwritingSegment::New();
+ mojo_segment->grapheme = "The grapheme";
+ mojo_segment->begin_index = 5u;
+ mojo_segment->end_index = 6u;
+ mojo_segment->drawing_segments.push_back(std::move(mojo_drawing_segment));
+
+ auto* idl_segment = mojo_segment.To<blink::HandwritingSegment*>();
+ EXPECT_EQ(idl_segment->grapheme(), "The grapheme");
+ EXPECT_EQ(idl_segment->beginIndex(), 5u);
+ EXPECT_EQ(idl_segment->endIndex(), 6u);
+ ASSERT_EQ(idl_segment->drawingSegments().size(), 1u);
+ EXPECT_EQ(idl_segment->drawingSegments()[0]->strokeIndex(), 321u);
+ EXPECT_EQ(idl_segment->drawingSegments()[0]->beginPointIndex(), 30u);
+ EXPECT_EQ(idl_segment->drawingSegments()[0]->endPointIndex(), 40u);
+}
+
+TEST(HandwritingTypeConvertersTest, MojoHandwritingPredictionIdl) {
+ auto mojo_drawing_segment =
+ handwriting::mojom::blink::HandwritingDrawingSegment::New();
+ mojo_drawing_segment->stroke_index = 456u;
+ mojo_drawing_segment->begin_point_index = 7u;
+ mojo_drawing_segment->end_point_index = 8u;
+ auto mojo_segment = handwriting::mojom::blink::HandwritingSegment::New();
+ mojo_segment->grapheme = "The grapheme";
+ mojo_segment->begin_index = 100u;
+ mojo_segment->end_index = 200u;
+ mojo_segment->drawing_segments.push_back(std::move(mojo_drawing_segment));
+ auto mojo_prediction =
+ handwriting::mojom::blink::HandwritingPrediction::New();
+ mojo_prediction->text = "The prediction";
+ mojo_prediction->segmentation_result.push_back(std::move(mojo_segment));
+
+ auto* idl_prediction = mojo_prediction.To<blink::HandwritingPrediction*>();
+ EXPECT_EQ(idl_prediction->text(), "The prediction");
+ ASSERT_EQ(idl_prediction->segmentationResult().size(), 1u);
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]->grapheme(),
+ "The grapheme");
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]->beginIndex(), 100u);
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]->endIndex(), 200u);
+ ASSERT_EQ(idl_prediction->segmentationResult()[0]->drawingSegments().size(),
+ 1u);
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]
+ ->drawingSegments()[0]
+ ->strokeIndex(),
+ 456u);
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]
+ ->drawingSegments()[0]
+ ->beginPointIndex(),
+ 7u);
+ EXPECT_EQ(idl_prediction->segmentationResult()[0]
+ ->drawingSegments()[0]
+ ->endPointIndex(),
+ 8u);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/idls.gni b/chromium/third_party/blink/renderer/modules/handwriting/idls.gni
new file mode 100644
index 00000000000..c41de06552b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/idls.gni
@@ -0,0 +1,23 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+modules_idl_files = [
+ "handwriting_drawing.idl",
+ "handwriting_recognizer.idl",
+ "handwriting_stroke.idl",
+]
+
+modules_dictionary_idl_files = [
+ "handwriting_feature_query.idl",
+ "handwriting_feature_query_result.idl",
+ "handwriting_hints.idl",
+ "handwriting_model_constraint.idl",
+ "handwriting_point.idl",
+ "handwriting_prediction.idl",
+ "handwriting_drawing_segment.idl",
+ "handwriting_segment.idl",
+]
+
+modules_dependency_idl_files =
+ [ "navigator_handwriting_recognition_service.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl b/chromium/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl
new file mode 100644
index 00000000000..a5e0fc43572
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/handwriting/navigator_handwriting_recognition_service.idl
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
+
+[
+ SecureContext,
+ ImplementedAs=HandwritingRecognitionService,
+ RuntimeEnabled=HandwritingRecognition
+] partial interface Navigator {
+ [CallWith=ScriptState, RaisesException]
+ Promise<HandwritingRecognizer>
+ createHandwritingRecognizer(HandwritingModelConstraint constraint);
+
+ [CallWith=ScriptState, RaisesException]
+ Promise<HandwritingFeatureQueryResult>
+ queryHandwritingRecognizerSupport(HandwritingFeatureQuery query);
+};
diff --git a/chromium/third_party/blink/renderer/modules/hid/DIR_METADATA b/chromium/third_party/blink/renderer/modules/hid/DIR_METADATA
new file mode 100644
index 00000000000..6a05639ab4a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/hid/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>HID"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/hid/OWNERS b/chromium/third_party/blink/renderer/modules/hid/OWNERS
index fd7080c660f..c9710847dd4 100644
--- a/chromium/third_party/blink/renderer/modules/hid/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/hid/OWNERS
@@ -1,5 +1,2 @@
mattreynolds@chromium.org
reillyg@chromium.org
-
-# TEAM: device-dev@chromium.org
-# COMPONENT: Blink>HID
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid.cc b/chromium/third_party/blink/renderer/modules/hid/hid.cc
index f3a47ccee78..ced05f75664 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid.cc
+++ b/chromium/third_party/blink/renderer/modules/hid/hid.cc
@@ -29,7 +29,7 @@ namespace {
const char kContextGone[] = "Script context has shut down.";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"hid\" is disallowed by feature policy.";
+ "Access to the feature \"hid\" is disallowed by permissions policy.";
void RejectWithTypeError(const String& message,
ScriptPromiseResolver* resolver) {
@@ -104,7 +104,7 @@ HID::HID(Navigator& navigator)
feature_handle_for_scheduler_(
navigator.DomWindow()->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kWebHID,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
+ {SchedulingPolicy::DisableBackForwardCache()})) {}
HID::~HID() {
DCHECK(get_devices_promises_.IsEmpty());
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 787d63e64df..1bc289bffea 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
@@ -12,6 +12,9 @@ dictionary HIDCollectionInfo {
// The 16-bit usage value associated with this collection. Zero if not set.
unsigned short usage;
+ // The 8-bit collection type for this collection.
+ octet type;
+
// The subcollections of this collection, in the order they were encountered
// in the report descriptor.
sequence<HIDCollectionInfo> children;
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 8f05aab7277..5ea391d74a9 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_device.cc
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device.cc
@@ -43,10 +43,10 @@ Vector<uint8_t> ConvertBufferSource(
base::checked_cast<wtf_size_t>(
buffer.GetAsArrayBuffer()->ByteLength()));
} else {
- vector.Append(static_cast<uint8_t*>(
- buffer.GetAsArrayBufferView().View()->BaseAddress()),
- base::checked_cast<wtf_size_t>(
- buffer.GetAsArrayBufferView().View()->byteLength()));
+ vector.Append(
+ static_cast<uint8_t*>(buffer.GetAsArrayBufferView()->BaseAddress()),
+ base::checked_cast<wtf_size_t>(
+ buffer.GetAsArrayBufferView()->byteLength()));
}
return vector;
}
@@ -184,6 +184,7 @@ HIDCollectionInfo* ToHIDCollectionInfo(
HIDCollectionInfo* result = HIDCollectionInfo::Create();
result->setUsage(collection.usage->usage);
result->setUsagePage(collection.usage->usage_page);
+ result->setType(collection.collection_type);
HeapVector<Member<HIDReportInfo>> input_reports;
for (const auto& report : collection.input_reports)
@@ -319,7 +320,7 @@ ScriptPromise HIDDevice::sendReport(ScriptState* script_state,
size_t data_size = data.IsArrayBuffer()
? data.GetAsArrayBuffer()->ByteLength()
- : data.GetAsArrayBufferView().View()->byteLength();
+ : data.GetAsArrayBufferView()->byteLength();
if (!base::CheckedNumeric<wtf_size_t>(data_size).IsValid()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -352,7 +353,7 @@ ScriptPromise HIDDevice::sendFeatureReport(
size_t data_size = data.IsArrayBuffer()
? data.GetAsArrayBuffer()->ByteLength()
- : data.GetAsArrayBufferView().View()->byteLength();
+ : data.GetAsArrayBufferView()->byteLength();
if (!base::CheckedNumeric<wtf_size_t>(data_size).IsValid()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -393,6 +394,12 @@ void HIDDevice::ContextDestroyed() {
device_requests_.clear();
}
+bool HIDDevice::HasPendingActivity() const {
+ // The object should be considered active if it is connected and has at least
+ // one event listener.
+ return connection_.is_bound() && HasEventListeners();
+}
+
void HIDDevice::Trace(Visitor* visitor) const {
visitor->Trace(parent_);
visitor->Trace(connection_);
@@ -498,8 +505,14 @@ HIDReportItem* HIDDevice::ToHIDReportItem(
HIDReportItem* result = HIDReportItem::Create();
result->setIsAbsolute(!report_item.is_relative);
result->setIsArray(!report_item.is_variable);
+ result->setIsBufferedBytes(report_item.is_buffered_bytes);
+ result->setIsConstant(report_item.is_constant);
+ result->setIsLinear(!report_item.is_non_linear);
result->setIsRange(report_item.is_range);
+ result->setIsVolatile(report_item.is_volatile);
result->setHasNull(report_item.has_null_position);
+ result->setHasPreferredState(!report_item.no_preferred_state);
+ result->setWrap(report_item.wrap);
result->setReportSize(report_item.report_size);
result->setReportCount(report_item.report_count);
result->setUnitExponent(
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 24b338e9bd2..f118a339ef6 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_device.h
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device.h
@@ -8,6 +8,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/mojom/hid.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/hid/hid.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.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"
@@ -33,6 +34,7 @@ class ScriptState;
class MODULES_EXPORT HIDDevice
: public EventTargetWithInlineData,
public ExecutionContextLifecycleObserver,
+ public ActiveScriptWrappable<HIDDevice>,
public device::mojom::blink::HidConnectionClient {
DEFINE_WRAPPERTYPEINFO();
@@ -71,6 +73,9 @@ class MODULES_EXPORT HIDDevice
// ExecutionContextLifecycleObserver:
void ContextDestroyed() override;
+ // ActiveScriptWrappable:
+ bool HasPendingActivity() const override;
+
static HIDReportItem* ToHIDReportItem(
const device::mojom::blink::HidReportItem& report_item);
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_device.idl b/chromium/third_party/blink/renderer/modules/hid/hid_device.idl
index 9a5e09e0a0d..cfae40d78b7 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_device.idl
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device.idl
@@ -8,6 +8,7 @@
// https://wicg.github.io/webhid/index.html#device-usage
[
+ ActiveScriptWrappable,
Exposed(Window WebHID),
SecureContext
] interface HIDDevice : EventTarget {
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 01ee6d86e96..078c7e04e5c 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
@@ -40,13 +40,39 @@ dictionary HIDReportItem {
// all inputs simultaneously.
boolean isArray;
+ // True if the item emits a fixed-size stream of bytes, or false if the item
+ // is a bit field.
+ boolean isBufferedBytes;
+
+ // True if the item is a read-only constant value, or false if the item is a
+ // report field with modifiable device data.
+ boolean isConstant;
+
+ // True if there is a linear relationship between the measured value and the
+ // raw data from the device, or false if the data has been processed and no
+ // longer represents a linear relationship.
+ boolean isLinear;
+
// True if the usages for this item are defined by |usageMinimum| and
// |usageMaximum| or false if the usages are defined by |usages|.
boolean isRange;
+ // True if the item is a feature or output field that can change without
+ // host interaction, or false if the field should not change without host
+ // interaction.
+ boolean isVolatile;
+
// True if the item uses an out-of-bounds value when there is no input.
boolean hasNull;
+ // True if the item has a preferred state to which it will return when the
+ // user is not physically interacting with the control.
+ boolean hasPreferredState;
+
+ // True if the data rolls over when reaching either the extreme high or low
+ // value.
+ boolean wrap;
+
// 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.
diff --git a/chromium/third_party/blink/renderer/modules/idle/DIR_METADATA b/chromium/third_party/blink/renderer/modules/idle/DIR_METADATA
new file mode 100644
index 00000000000..d78e9e40774
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "fugu-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/idle/OWNERS b/chromium/third_party/blink/renderer/modules/idle/OWNERS
index bb1b52fe961..5a67a3277ca 100644
--- a/chromium/third_party/blink/renderer/modules/idle/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/idle/OWNERS
@@ -1,3 +1 @@
file://content/browser/idle/OWNERS
-
-# TEAM: fugu-dev@chromium.org
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 ecc231cb906..594effa4c1e 100644
--- a/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -28,7 +28,8 @@ using mojom::blink::IdleManagerError;
const char kAbortMessage[] = "Idle detection aborted.";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"idle-detection\" is disallowed by feature policy.";
+ "Access to the feature \"idle-detection\" is disallowed by permissions "
+ "policy.";
constexpr base::TimeDelta kMinimumThreshold = base::TimeDelta::FromSeconds(60);
diff --git a/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc b/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
index c81a25b0d24..1de0bb57e89 100644
--- a/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
@@ -79,7 +79,8 @@ SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) {
// size |max_image_size|. Returns the result if it is not empty. Otherwise,
// find the smallest image in the array and resize it proportionally to fit
// in a box of size |max_image_size|.
-// Sets |original_image_sizes| to the sizes of |images| before resizing.
+// Sets |original_image_sizes| to the sizes of |images| before resizing. Both
+// output vectors are guaranteed to have the same size.
void FilterAndResizeImagesForMaximalSize(
const WTF::Vector<SkBitmap>& unfiltered,
uint32_t max_image_size,
@@ -202,6 +203,8 @@ void ImageDownloaderImpl::DidDownloadImage(
FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images,
&result_original_image_sizes);
+ DCHECK_EQ(result_images.size(), result_original_image_sizes.size());
+
std::move(callback).Run(http_status_code, result_images,
result_original_image_sizes);
}
@@ -218,9 +221,7 @@ void ImageDownloaderImpl::FetchImage(const KURL& image_url,
// Create an image resource fetcher and assign it with a call back object.
image_fetchers_.push_back(
std::make_unique<MultiResolutionImageResourceFetcher>(
- image_url, GetSupplementable(),
- is_favicon ? mojom::blink::RequestContextType::FAVICON
- : mojom::blink::RequestContextType::IMAGE,
+ image_url, GetSupplementable(), is_favicon,
bypass_cache ? blink::mojom::FetchCacheMode::kBypassCache
: blink::mojom::FetchCacheMode::kDefault,
WTF::Bind(&ImageDownloaderImpl::DidFetchImage, WrapPersistent(this),
diff --git a/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.cc b/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.cc
index 72f2aeae228..81c91284c2d 100644
--- a/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.cc
+++ b/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.cc
@@ -107,7 +107,7 @@ class MultiResolutionImageResourceFetcher::ClientImpl
MultiResolutionImageResourceFetcher::MultiResolutionImageResourceFetcher(
const KURL& image_url,
LocalFrame* frame,
- mojom::blink::RequestContextType request_context,
+ bool is_favicon,
mojom::blink::FetchCacheMode cache_mode,
Callback callback)
: callback_(std::move(callback)),
@@ -116,7 +116,7 @@ MultiResolutionImageResourceFetcher::MultiResolutionImageResourceFetcher(
WebAssociatedURLLoaderOptions options;
SetLoaderOptions(options);
- if (request_context == mojom::blink::RequestContextType::FAVICON) {
+ if (is_favicon) {
// To prevent cache tainting, the cross-origin favicon requests have to
// by-pass the service workers. This should ideally not happen. But Chrome’s
// FaviconDatabase is using the icon URL as a key of the "favicons" table.
@@ -130,10 +130,10 @@ MultiResolutionImageResourceFetcher::MultiResolutionImageResourceFetcher(
SetCacheMode(cache_mode);
- Start(frame, request_context, network::mojom::RequestMode::kNoCors,
+ Start(frame, is_favicon, network::mojom::RequestMode::kNoCors,
network::mojom::CredentialsMode::kInclude,
WTF::Bind(&MultiResolutionImageResourceFetcher::OnURLFetchComplete,
- WTF::Unretained(this)));
+ WTF::Unretained(this)));
}
MultiResolutionImageResourceFetcher::~MultiResolutionImageResourceFetcher() {
@@ -193,7 +193,7 @@ void MultiResolutionImageResourceFetcher::SetLoaderOptions(
void MultiResolutionImageResourceFetcher::Start(
LocalFrame* frame,
- mojom::blink::RequestContextType request_context,
+ bool is_favicon,
network::mojom::RequestMode request_mode,
network::mojom::CredentialsMode credentials_mode,
StartCallback callback) {
@@ -203,11 +203,15 @@ void MultiResolutionImageResourceFetcher::Start(
if (!request_.HttpBody().IsNull())
DCHECK_NE("GET", request_.HttpMethod().Utf8()) << "GETs can't have bodies.";
+ mojom::blink::RequestContextType request_context =
+ is_favicon ? mojom::blink::RequestContextType::FAVICON
+ : mojom::blink::RequestContextType::IMAGE;
request_.SetRequestContext(request_context);
request_.SetSiteForCookies(frame->GetDocument()->SiteForCookies());
request_.SetMode(request_mode);
request_.SetCredentialsMode(credentials_mode);
request_.SetRequestDestination(network::mojom::RequestDestination::kImage);
+ request_.SetFavicon(is_favicon);
client_ = std::make_unique<ClientImpl>(std::move(callback));
diff --git a/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.h b/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.h
index aaa3a528e4e..933acb1f475 100644
--- a/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.h
+++ b/chromium/third_party/blink/renderer/modules/image_downloader/multi_resolution_image_resource_fetcher.h
@@ -42,12 +42,11 @@ class MultiResolutionImageResourceFetcher {
using StartCallback = base::OnceCallback<void(const WebURLResponse& response,
const std::string& data)>;
- MultiResolutionImageResourceFetcher(
- const KURL& image_url,
- LocalFrame* frame,
- mojom::blink::RequestContextType request_context,
- mojom::blink::FetchCacheMode cache_mode,
- Callback callback);
+ MultiResolutionImageResourceFetcher(const KURL& image_url,
+ LocalFrame* frame,
+ bool is_favicon,
+ mojom::blink::FetchCacheMode cache_mode,
+ Callback callback);
virtual ~MultiResolutionImageResourceFetcher();
@@ -81,7 +80,7 @@ class MultiResolutionImageResourceFetcher {
// |fetch_credentials_mode| is the credentials mode to use. See
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode
void Start(LocalFrame* frame,
- mojom::blink::RequestContextType request_context,
+ bool is_favicon,
network::mojom::RequestMode request_mode,
network::mojom::CredentialsMode credentials_mode,
StartCallback callback);
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/DIR_METADATA b/chromium/third_party/blink/renderer/modules/imagecapture/DIR_METADATA
new file mode 100644
index 00000000000..da07edd5d66
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>ImageCapture"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/OWNERS b/chromium/third_party/blink/renderer/modules/imagecapture/OWNERS
index ec125cc9337..52977106453 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/OWNERS
@@ -3,6 +3,3 @@ rijubrata.bhaumik@intel.com
# Original (legacy) owner.
mcasas@chromium.org
-
-# COMPONENT: Blink>ImageCapture
-# TEAM: webrtc-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
index 3d312881fdf..613661edcc6 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -43,6 +43,9 @@ namespace {
const char kNoServiceError[] = "ImageCapture service unavailable.";
+const char kInvalidStateTrackError[] =
+ "The associated Track is in an invalid state";
+
bool TrackIsInactive(const MediaStreamTrack& track) {
// Spec instructs to return an exception if the Track's readyState() is not
// "live". Also reject if the track is disabled or muted.
@@ -183,8 +186,7 @@ ScriptPromise ImageCapture::getPhotoCapabilities(ScriptState* script_state) {
if (TrackIsInactive(*stream_track_)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The associated Track is in an invalid state."));
+ DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError));
return promise;
}
@@ -205,7 +207,7 @@ ScriptPromise ImageCapture::getPhotoCapabilities(ScriptState* script_state) {
service_->GetPhotoState(
stream_track_->Component()->Source()->Id(),
WTF::Bind(&ImageCapture::OnMojoGetPhotoState, WrapPersistent(this),
- WrapPersistent(resolver), WTF::Passed(std::move(resolver_cb)),
+ WrapPersistent(resolver), std::move(resolver_cb),
false /* trigger_take_photo */));
return promise;
}
@@ -216,8 +218,7 @@ ScriptPromise ImageCapture::getPhotoSettings(ScriptState* script_state) {
if (TrackIsInactive(*stream_track_)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The associated Track is in an invalid state."));
+ DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError));
return promise;
}
@@ -238,7 +239,7 @@ ScriptPromise ImageCapture::getPhotoSettings(ScriptState* script_state) {
service_->GetPhotoState(
stream_track_->Component()->Source()->Id(),
WTF::Bind(&ImageCapture::OnMojoGetPhotoState, WrapPersistent(this),
- WrapPersistent(resolver), WTF::Passed(std::move(resolver_cb)),
+ WrapPersistent(resolver), std::move(resolver_cb),
false /* trigger_take_photo */));
return promise;
}
@@ -253,8 +254,7 @@ ScriptPromise ImageCapture::setOptions(ScriptState* script_state,
if (TrackIsInactive(*stream_track_)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The associated Track is in an invalid state."));
+ DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError));
return promise;
}
@@ -342,8 +342,7 @@ ScriptPromise ImageCapture::grabFrame(ScriptState* script_state) {
if (TrackIsInactive(*stream_track_)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kInvalidStateError,
- "The associated Track is in an invalid state."));
+ DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError));
return promise;
}
@@ -407,9 +406,8 @@ void ImageCapture::GetMediaTrackCapabilities(
capabilities->setPan(capabilities_->pan());
if (capabilities_->hasTilt())
capabilities->setTilt(capabilities_->tilt());
- }
- if (capabilities_->hasZoom() && HasZoomPermissionGranted()) {
- capabilities->setZoom(capabilities_->zoom());
+ if (capabilities_->hasZoom())
+ capabilities->setZoom(capabilities_->zoom());
}
if (capabilities_->hasTorch())
@@ -487,7 +485,7 @@ void ImageCapture::SetMediaTrackConstraints(
(constraints->hasTilt() &&
!(capabilities_->hasTilt() && HasPanTiltZoomPermissionGranted())) ||
(constraints->hasZoom() &&
- !(capabilities_->hasZoom() && HasZoomPermissionGranted())) ||
+ !(capabilities_->hasZoom() && HasPanTiltZoomPermissionGranted())) ||
(constraints->hasTorch() && !capabilities_->hasTorch())) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError, "Unsupported constraint(s)"));
@@ -886,9 +884,8 @@ void ImageCapture::GetMediaTrackSettings(MediaTrackSettings* settings) const {
settings->setPan(settings_->pan());
if (settings_->hasTilt())
settings->setTilt(settings_->tilt());
- }
- if (settings_->hasZoom() && HasZoomPermissionGranted()) {
- settings->setZoom(settings_->zoom());
+ if (settings_->hasZoom())
+ settings->setZoom(settings_->zoom());
}
if (settings_->hasTorch())
@@ -952,13 +949,6 @@ void ImageCapture::OnPermissionStatusChange(
}
bool ImageCapture::HasPanTiltZoomPermissionGranted() const {
- if (!RuntimeEnabledFeatures::MediaCapturePanTiltEnabled())
- return false;
-
- return pan_tilt_zoom_permission_ == mojom::blink::PermissionStatus::GRANTED;
-}
-
-bool ImageCapture::HasZoomPermissionGranted() const {
return pan_tilt_zoom_permission_ == mojom::blink::PermissionStatus::GRANTED;
}
@@ -978,8 +968,7 @@ void ImageCapture::OnMojoGetPhotoState(
if (TrackIsInactive(*stream_track_)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kOperationError,
- "The associated Track is in an invalid state."));
+ DOMExceptionCode::kOperationError, kInvalidStateTrackError));
service_requests_.erase(resolver);
return;
}
@@ -1049,7 +1038,7 @@ void ImageCapture::OnMojoSetOptions(ScriptPromiseResolver* resolver,
service_->GetPhotoState(
stream_track_->Component()->Source()->Id(),
WTF::Bind(&ImageCapture::OnMojoGetPhotoState, WrapPersistent(this),
- WrapPersistent(resolver), WTF::Passed(std::move(resolver_cb)),
+ WrapPersistent(resolver), std::move(resolver_cb),
trigger_take_photo));
}
@@ -1179,8 +1168,6 @@ void ImageCapture::UpdateMediaTrackCapabilities(
capabilities_->setTilt(ToMediaSettingsRange(*photo_state->tilt));
settings_->setTilt(photo_state->tilt->current);
}
- }
- if (HasZoomPermissionGranted()) {
if (photo_state->zoom->max != photo_state->zoom->min) {
capabilities_->setZoom(ToMediaSettingsRange(*photo_state->zoom));
settings_->setZoom(photo_state->zoom->current);
@@ -1224,6 +1211,156 @@ bool ImageCapture::IsPageVisible() {
return DomWindow() ? DomWindow()->document()->IsPageVisible() : false;
}
+ImageCapture* ImageCapture::Clone() const {
+ ImageCapture* clone = MakeGarbageCollected<ImageCapture>(
+ GetExecutionContext(), stream_track_, HasPanTiltZoomPermissionGranted(),
+ /*callback=*/base::DoNothing());
+
+ // Copy capabilities.
+ if (capabilities_->hasWhiteBalanceMode()) {
+ clone->capabilities_->setWhiteBalanceMode(
+ capabilities_->whiteBalanceMode());
+ }
+ if (capabilities_->hasExposureMode())
+ clone->capabilities_->setExposureMode(capabilities_->exposureMode());
+ if (capabilities_->hasFocusMode())
+ clone->capabilities_->setFocusMode(capabilities_->focusMode());
+ if (capabilities_->hasExposureCompensation()) {
+ clone->capabilities_->setExposureCompensation(
+ capabilities_->exposureCompensation());
+ }
+ if (capabilities_->hasExposureTime())
+ clone->capabilities_->setExposureTime(capabilities_->exposureTime());
+ if (capabilities_->hasColorTemperature()) {
+ clone->capabilities_->setColorTemperature(
+ capabilities_->colorTemperature());
+ }
+ if (capabilities_->hasIso())
+ clone->capabilities_->setIso(capabilities_->iso());
+ if (capabilities_->hasBrightness())
+ clone->capabilities_->setBrightness(capabilities_->brightness());
+ if (capabilities_->hasContrast())
+ clone->capabilities_->setContrast(capabilities_->contrast());
+ if (capabilities_->hasSaturation())
+ clone->capabilities_->setSaturation(capabilities_->saturation());
+ if (capabilities_->hasSharpness())
+ clone->capabilities_->setSharpness(capabilities_->sharpness());
+ if (capabilities_->hasFocusDistance())
+ clone->capabilities_->setFocusDistance(capabilities_->focusDistance());
+ if (capabilities_->hasPan())
+ clone->capabilities_->setPan(capabilities_->pan());
+ if (capabilities_->hasTilt())
+ clone->capabilities_->setTilt(capabilities_->tilt());
+ if (capabilities_->hasZoom())
+ clone->capabilities_->setZoom(capabilities_->zoom());
+ if (capabilities_->hasTorch())
+ clone->capabilities_->setTorch(capabilities_->torch());
+
+ // Copy settings.
+ if (settings_->hasWhiteBalanceMode())
+ clone->settings_->setWhiteBalanceMode(settings_->whiteBalanceMode());
+ if (settings_->hasExposureMode())
+ clone->settings_->setExposureMode(settings_->exposureMode());
+ if (settings_->hasFocusMode())
+ clone->settings_->setFocusMode(settings_->focusMode());
+ if (settings_->hasPointsOfInterest() &&
+ !settings_->pointsOfInterest().IsEmpty()) {
+ clone->settings_->setPointsOfInterest(settings_->pointsOfInterest());
+ }
+ if (settings_->hasExposureCompensation()) {
+ clone->settings_->setExposureCompensation(
+ settings_->exposureCompensation());
+ }
+ if (settings_->hasExposureTime())
+ clone->settings_->setExposureTime(settings_->exposureTime());
+ if (settings_->hasColorTemperature())
+ clone->settings_->setColorTemperature(settings_->colorTemperature());
+ if (settings_->hasIso())
+ clone->settings_->setIso(settings_->iso());
+ if (settings_->hasBrightness())
+ clone->settings_->setBrightness(settings_->brightness());
+ if (settings_->hasContrast())
+ clone->settings_->setContrast(settings_->contrast());
+ if (settings_->hasSaturation())
+ clone->settings_->setSaturation(settings_->saturation());
+ if (settings_->hasSharpness())
+ clone->settings_->setSharpness(settings_->sharpness());
+ if (settings_->hasFocusDistance())
+ clone->settings_->setFocusDistance(settings_->focusDistance());
+ if (settings_->hasPan())
+ clone->settings_->setPan(settings_->pan());
+ if (settings_->hasTilt())
+ clone->settings_->setTilt(settings_->tilt());
+ if (settings_->hasZoom())
+ clone->settings_->setZoom(settings_->zoom());
+ if (settings_->hasTorch())
+ clone->settings_->setTorch(settings_->torch());
+
+ if (!current_constraints_)
+ return clone;
+
+ // Copy current constraints.
+ clone->current_constraints_ = MediaTrackConstraintSet::Create();
+ if (current_constraints_->hasWhiteBalanceMode()) {
+ clone->current_constraints_->setWhiteBalanceMode(
+ current_constraints_->whiteBalanceMode());
+ }
+ if (current_constraints_->hasExposureMode()) {
+ clone->current_constraints_->setExposureMode(
+ current_constraints_->exposureMode());
+ }
+ if (current_constraints_->hasFocusMode()) {
+ clone->current_constraints_->setFocusMode(
+ current_constraints_->focusMode());
+ }
+ if (current_constraints_->hasPointsOfInterest()) {
+ clone->current_constraints_->setPointsOfInterest(
+ current_constraints_->pointsOfInterest());
+ }
+ if (current_constraints_->hasExposureCompensation()) {
+ clone->current_constraints_->setExposureCompensation(
+ current_constraints_->exposureCompensation());
+ }
+ if (current_constraints_->hasExposureTime()) {
+ clone->current_constraints_->setExposureTime(
+ current_constraints_->exposureTime());
+ }
+ if (current_constraints_->hasColorTemperature()) {
+ clone->current_constraints_->setColorTemperature(
+ current_constraints_->colorTemperature());
+ }
+ if (current_constraints_->hasIso())
+ clone->current_constraints_->setIso(current_constraints_->iso());
+ if (current_constraints_->hasBrightness()) {
+ clone->current_constraints_->setBrightness(
+ current_constraints_->brightness());
+ }
+ if (current_constraints_->hasContrast())
+ clone->current_constraints_->setContrast(current_constraints_->contrast());
+ if (current_constraints_->hasSaturation()) {
+ clone->current_constraints_->setSaturation(
+ current_constraints_->saturation());
+ }
+ if (current_constraints_->hasSharpness()) {
+ clone->current_constraints_->setSharpness(
+ current_constraints_->sharpness());
+ }
+ if (current_constraints_->hasFocusDistance()) {
+ clone->current_constraints_->setFocusDistance(
+ current_constraints_->focusDistance());
+ }
+ if (current_constraints_->hasPan())
+ clone->current_constraints_->setPan(current_constraints_->pan());
+ if (current_constraints_->hasTilt())
+ clone->current_constraints_->setTilt(current_constraints_->tilt());
+ if (current_constraints_->hasZoom())
+ clone->current_constraints_->setZoom(current_constraints_->zoom());
+ if (current_constraints_->hasTorch())
+ clone->current_constraints_->setTorch(current_constraints_->torch());
+
+ return clone;
+}
+
void ImageCapture::Trace(Visitor* visitor) const {
visitor->Trace(stream_track_);
visitor->Trace(service_);
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
index ce8ce3844d0..1bc62982bf2 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.h
@@ -84,7 +84,10 @@ class MODULES_EXPORT ImageCapture final
void GetMediaTrackSettings(MediaTrackSettings*) const;
bool HasPanTiltZoomPermissionGranted() const;
- bool HasZoomPermissionGranted() const;
+
+ // Called by MediaStreamTrack::clone() to get a clone with same capabilities,
+ // settings, and constraints.
+ ImageCapture* Clone() const;
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
index f77ee51f6d2..bc91c8d23b2 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.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/functional.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
@@ -58,15 +59,19 @@ void OnError(std::unique_ptr<ImageCaptureGrabFrameCallbacks> callbacks) {
class ImageCaptureFrameGrabber::SingleShotFrameHandler
: public WTF::ThreadSafeRefCounted<SingleShotFrameHandler> {
public:
- SingleShotFrameHandler() : first_frame_received_(false) {}
+ using SkImageDeliverCB = WTF::CrossThreadOnceFunction<void(sk_sp<SkImage>)>;
+
+ explicit SingleShotFrameHandler(SkImageDeliverCB deliver_cb)
+ : deliver_cb_(std::move(deliver_cb)) {
+ DCHECK(deliver_cb_);
+ }
// Receives a |frame| and converts its pixels into a SkImage via an internal
// PaintSurface and SkPixmap. Alpha channel, if any, is copied.
- using SkImageDeliverCB = WTF::CrossThreadFunction<void(sk_sp<SkImage>)>;
void OnVideoFrameOnIOThread(
- SkImageDeliverCB callback,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks current_time);
private:
@@ -76,26 +81,26 @@ class ImageCaptureFrameGrabber::SingleShotFrameHandler
void ConvertAndDeliverFrame(SkImageDeliverCB callback,
scoped_refptr<media::VideoFrame> frame);
- // Flag to indicate that the first frames has been processed, and subsequent
- // ones can be safely discarded.
- bool first_frame_received_;
+ // Null once the initial frame has been queued for delivery.
+ SkImageDeliverCB deliver_cb_;
DISALLOW_COPY_AND_ASSIGN(SingleShotFrameHandler);
};
void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread(
- SkImageDeliverCB callback,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks /* current_time */) {
- if (first_frame_received_)
+ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_frames*/,
+ base::TimeTicks /*current_time*/) {
+ if (!deliver_cb_)
return;
- first_frame_received_ = true;
- task_runner->PostTask(FROM_HERE,
- ConvertToBaseOnceCallback(CrossThreadBindOnce(
- &SingleShotFrameHandler::ConvertAndDeliverFrame,
- scoped_refptr<SingleShotFrameHandler>(this),
- std::move(callback), std::move(frame))));
+
+ // Scaled video frames are not used by ImageCaptureFrameGrabber.
+ PostCrossThreadTask(
+ *task_runner, FROM_HERE,
+ CrossThreadBindOnce(&SingleShotFrameHandler::ConvertAndDeliverFrame,
+ base::WrapRefCounted(this), std::move(deliver_cb_),
+ std::move(frame)));
}
void ImageCaptureFrameGrabber::SingleShotFrameHandler::ConvertAndDeliverFrame(
@@ -250,11 +255,10 @@ void ImageCaptureFrameGrabber::GrabFrame(
WebMediaStreamTrack(component),
ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
&SingleShotFrameHandler::OnVideoFrameOnIOThread,
- base::MakeRefCounted<SingleShotFrameHandler>(),
- WTF::Passed(CrossThreadBindRepeating(
+ base::MakeRefCounted<SingleShotFrameHandler>(CrossThreadBindOnce(
&ImageCaptureFrameGrabber::OnSkImage, weak_factory_.GetWeakPtr(),
- WTF::Passed(std::move(scoped_callbacks)))),
- WTF::Passed(std::move(task_runner)))),
+ std::move(scoped_callbacks))),
+ std::move(task_runner))),
false);
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn b/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
index 5f0498153ca..c5e09703992 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/BUILD.gn
@@ -36,12 +36,6 @@ blink_modules_sources("indexeddb") {
"idb_name_and_version.h",
"idb_object_store.cc",
"idb_object_store.h",
- "idb_observation.cc",
- "idb_observation.h",
- "idb_observer.cc",
- "idb_observer.h",
- "idb_observer_changes.cc",
- "idb_observer_changes.h",
"idb_open_db_request.cc",
"idb_open_db_request.h",
"idb_request.cc",
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/DIR_METADATA b/chromium/third_party/blink/renderer/modules/indexeddb/DIR_METADATA
new file mode 100644
index 00000000000..76f9090976d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>IndexedDB"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/OWNERS b/chromium/third_party/blink/renderer/modules/indexeddb/OWNERS
index 1c17e0230e6..01bf15fa516 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/OWNERS
@@ -2,6 +2,3 @@ file://content/browser/indexed_db/OWNERS
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>IndexedDB
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.cc
index 4104ec54504..7d43685eb23 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
#include <memory>
+#include <utility>
#include "third_party/blink/renderer/core/dom/dom_string_list.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h"
@@ -46,11 +47,6 @@ void IDBAny::ContextWillBeDestroyed() {
idb_cursor_->ContextWillBeDestroyed();
}
-DOMStringList* IDBAny::DomStringList() const {
- DCHECK_EQ(type_, kDOMStringListType);
- return dom_string_list_.Get();
-}
-
IDBCursor* IDBAny::IdbCursor() const {
DCHECK_EQ(type_, kIDBCursorType);
SECURITY_DCHECK(idb_cursor_->IsKeyCursor());
@@ -89,9 +85,6 @@ int64_t IDBAny::Integer() const {
return integer_;
}
-IDBAny::IDBAny(DOMStringList* value)
- : type_(kDOMStringListType), dom_string_list_(value) {}
-
IDBAny::IDBAny(IDBCursor* value)
: type_(IsA<IDBCursorWithValue>(value) ? kIDBCursorWithValueType
: kIDBCursorType),
@@ -112,7 +105,6 @@ IDBAny::IDBAny(std::unique_ptr<IDBKey> key)
IDBAny::IDBAny(int64_t value) : type_(kIntegerType), integer_(value) {}
void IDBAny::Trace(Visitor* visitor) const {
- visitor->Trace(dom_string_list_);
visitor->Trace(idb_cursor_);
visitor->Trace(idb_database_);
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.h
index 47e49e0c7f3..69cab8c48d8 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_any.h
@@ -28,7 +28,6 @@
#include <memory>
-#include "third_party/blink/renderer/core/dom/dom_string_list.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -47,8 +46,8 @@ class IDBObjectStore;
// IDBAny is used for:
// * source of IDBCursor (IDBObjectStore or IDBIndex)
// * source of IDBRequest (IDBObjectStore, IDBIndex, IDBCursor, or null)
-// * result of IDBRequest (IDBDatabase, IDBCursor, DOMStringList, undefined,
-// integer, key or value)
+// * result of IDBRequest (IDBDatabase, IDBCursor, undefined, integer,
+// key or value)
//
// This allows for lazy conversion to script values (via IDBBindingUtilities),
// and avoids the need for many dedicated union types.
@@ -58,7 +57,6 @@ class MODULES_EXPORT IDBAny final : public GarbageCollected<IDBAny> {
enum Type {
kUndefinedType = 0,
kNullType,
- kDOMStringListType,
kIDBCursorType,
kIDBCursorWithValueType,
kIDBDatabaseType,
@@ -69,7 +67,6 @@ class MODULES_EXPORT IDBAny final : public GarbageCollected<IDBAny> {
};
explicit IDBAny(Type);
- explicit IDBAny(DOMStringList*);
explicit IDBAny(IDBCursor*);
explicit IDBAny(IDBDatabase*);
explicit IDBAny(std::unique_ptr<IDBKey>);
@@ -83,7 +80,6 @@ class MODULES_EXPORT IDBAny final : public GarbageCollected<IDBAny> {
Type GetType() const { return type_; }
// Use type() to figure out which one of these you're allowed to call.
- DOMStringList* DomStringList() const;
IDBCursor* IdbCursor() const;
IDBCursorWithValue* IdbCursorWithValue() const;
IDBDatabase* IdbDatabase() const;
@@ -96,7 +92,6 @@ class MODULES_EXPORT IDBAny final : public GarbageCollected<IDBAny> {
const Type type_;
// Only one of the following should ever be in use at any given time.
- const Member<DOMStringList> dom_string_list_;
const Member<IDBCursor> idb_cursor_;
const Member<IDBDatabase> idb_database_;
const std::unique_ptr<IDBKey> idb_key_;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
index 76d204bc33a..6c0070ef8a3 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor.cc
@@ -27,6 +27,8 @@
#include <limits>
#include <memory>
+#include <utility>
+
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_request.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
index 101e265f90c..09bfec8eb3b 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.cc
@@ -26,6 +26,8 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h"
#include <memory>
+#include <utility>
+
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
index c534f7f2b69..283245e594d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc
@@ -27,6 +27,7 @@
#include <limits>
#include <memory>
+#include <utility>
#include "base/atomic_sequence_num.h"
#include "base/optional.h"
@@ -35,7 +36,6 @@
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/indexed_db_names.h"
@@ -43,8 +43,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observer.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
@@ -57,8 +55,6 @@
namespace blink {
-const char IDBDatabase::kCannotObserveVersionChangeTransaction[] =
- "An observer cannot target a version change transaction.";
const char IDBDatabase::kIndexDeletedErrorMessage[] =
"The index or its object store has been deleted.";
const char IDBDatabase::kIndexNameTakenErrorMessage[] =
@@ -98,7 +94,6 @@ IDBDatabase::IDBDatabase(
ExecutionContext* context,
std::unique_ptr<WebIDBDatabase> backend,
IDBDatabaseCallbacks* callbacks,
- v8::Isolate* isolate,
mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime)
: ExecutionContextLifecycleObserver(context),
backend_(std::move(backend)),
@@ -106,12 +101,11 @@ IDBDatabase::IDBDatabase(
event_queue_(
MakeGarbageCollected<EventQueue>(context, TaskType::kDatabaseAccess)),
database_callbacks_(callbacks),
- isolate_(isolate),
feature_handle_for_scheduler_(
context
? context->GetScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kIndexedDBConnection,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})
+ {SchedulingPolicy::DisableBackForwardCache()})
: FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle()) {
database_callbacks_->Connect(this);
}
@@ -124,7 +118,6 @@ IDBDatabase::~IDBDatabase() {
void IDBDatabase::Trace(Visitor* visitor) const {
visitor->Trace(version_change_transaction_);
visitor->Trace(transactions_);
- visitor->Trace(observers_);
visitor->Trace(event_queue_);
visitor->Trace(database_callbacks_);
EventTargetWithInlineData::Trace(visitor);
@@ -139,12 +132,6 @@ int64_t IDBDatabase::NextTransactionId() {
return current_transaction_id.GetNext() + 1;
}
-int32_t IDBDatabase::NextObserverId() {
- // Starts at 1, unlike AtomicSequenceNumber.
- static base::AtomicSequenceNumber current_observer_id;
- return current_observer_id.GetNext() + 1;
-}
-
void IDBDatabase::SetMetadata(const IDBDatabaseMetadata& metadata) {
metadata_ = metadata;
}
@@ -189,36 +176,6 @@ void IDBDatabase::OnComplete(int64_t transaction_id) {
transactions_.at(transaction_id)->OnComplete();
}
-void IDBDatabase::OnChanges(
- const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
- Vector<Persistent<IDBObservation>> observations,
- const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
- for (const auto& observation : observations) {
- observation->SetIsolate(isolate_);
- }
-
- for (const auto& map_entry : observation_index_map) {
- auto observer_lookup_result = observers_.find(map_entry.key);
- if (observer_lookup_result != observers_.end()) {
- IDBObserver* observer = observer_lookup_result->value;
-
- auto transactions_lookup_result = transactions.find(map_entry.key);
- if (transactions_lookup_result != transactions.end()) {
- const std::pair<int64_t, Vector<int64_t>>& obs_txn =
- transactions_lookup_result->value;
- HashSet<String> stores;
- for (int64_t store_id : obs_txn.second) {
- stores.insert(metadata_.object_stores.at(store_id)->name);
- }
- }
-
- observer->Callback()->InvokeAndReportException(
- observer, MakeGarbageCollected<IDBObserverChanges>(
- this, nullptr, observations, map_entry.value));
- }
- }
-}
-
DOMStringList* IDBDatabase::objectStoreNames() const {
auto* object_store_names = MakeGarbageCollected<DOMStringList>();
for (const auto& it : metadata_.object_stores)
@@ -233,25 +190,6 @@ const String& IDBDatabase::GetObjectStoreName(int64_t object_store_id) const {
return it->value->name;
}
-int32_t IDBDatabase::AddObserver(
- IDBObserver* observer,
- int64_t transaction_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<blink::kIDBOperationTypeCount> operation_types) {
- int32_t observer_id = NextObserverId();
- observers_.Set(observer_id, observer);
- Backend()->AddObserver(transaction_id, observer_id, include_transaction,
- no_records, values, operation_types);
- return observer_id;
-}
-
-void IDBDatabase::RemoveObservers(const Vector<int32_t>& observer_ids) {
- observers_.RemoveAll(observer_ids);
- Backend()->RemoveObservers(observer_ids);
-}
-
IDBObjectStore* IDBDatabase::createObjectStore(
const String& name,
const IDBKeyPath& key_path,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
index da5f6a4d085..68c67a8fddf 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h
@@ -49,14 +49,13 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
class DOMException;
class ExceptionState;
class ExecutionContext;
-class IDBObservation;
-class IDBObserver;
class MODULES_EXPORT IDBDatabase final
: public EventTargetWithInlineData,
@@ -69,7 +68,6 @@ class MODULES_EXPORT IDBDatabase final
ExecutionContext*,
std::unique_ptr<WebIDBDatabase>,
IDBDatabaseCallbacks*,
- v8::Isolate*,
mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime);
~IDBDatabase() override;
@@ -85,13 +83,6 @@ class MODULES_EXPORT IDBDatabase final
void TransactionCreated(IDBTransaction*);
void TransactionFinished(const IDBTransaction*);
const String& GetObjectStoreName(int64_t object_store_id) const;
- int32_t AddObserver(IDBObserver*,
- int64_t transaction_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<kIDBOperationTypeCount> operation_types);
- void RemoveObservers(const Vector<int32_t>& observer_ids);
// Implement the IDL
const String& name() const { return metadata_.name; }
@@ -125,9 +116,6 @@ class MODULES_EXPORT IDBDatabase final
void OnVersionChange(int64_t old_version, int64_t new_version);
void OnAbort(int64_t, DOMException*);
void OnComplete(int64_t);
- void OnChanges(const WebIDBDatabaseCallbacks::ObservationIndexMap&,
- Vector<Persistent<IDBObservation>> observations,
- const WebIDBDatabaseCallbacks::TransactionMap& transactions);
// ScriptWrappable
bool HasPendingActivity() const final;
@@ -157,9 +145,7 @@ class MODULES_EXPORT IDBDatabase final
WebIDBDatabase* Backend() const { return backend_.get(); }
static int64_t NextTransactionId();
- static int32_t NextObserverId();
- static const char kCannotObserveVersionChangeTransaction[];
static const char kIndexDeletedErrorMessage[];
static const char kIndexNameTakenErrorMessage[];
static const char kIsKeyCursorErrorMessage[];
@@ -193,7 +179,6 @@ class MODULES_EXPORT IDBDatabase final
std::unique_ptr<WebIDBDatabase> backend_;
Member<IDBTransaction> version_change_transaction_;
HeapHashMap<int64_t, Member<IDBTransaction>> transactions_;
- HeapHashMap<int32_t, Member<IDBObserver>> observers_;
// No interface here, so no need to bind it. This is only for
// lifetime observation of the use of IndexedDB from the browser.
mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime_;
@@ -203,9 +188,6 @@ class MODULES_EXPORT IDBDatabase final
Member<EventQueue> event_queue_;
Member<IDBDatabaseCallbacks> database_callbacks_;
- // Maintain the isolate so that all externally allocated memory can be
- // registered against it.
- v8::Isolate* isolate_;
FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
index cfa159625c1..8d3ea9dff37 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.cc
@@ -25,6 +25,8 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
+#include <utility>
+
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h"
@@ -60,17 +62,6 @@ void IDBDatabaseCallbacks::OnComplete(int64_t transaction_id) {
database_->OnComplete(transaction_id);
}
-void IDBDatabaseCallbacks::OnChanges(
- const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
- Vector<Persistent<IDBObservation>> observations,
- const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
- if (!database_)
- return;
-
- database_->OnChanges(observation_index_map, std::move(observations),
- transactions);
-}
-
void IDBDatabaseCallbacks::Connect(IDBDatabase* database) {
DCHECK(!database_);
DCHECK(database);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
index e7705b02e9f..23377ef7e00 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h
@@ -26,6 +26,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_CALLBACKS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_CALLBACKS_H_
+#include <memory>
+
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -34,7 +36,6 @@ namespace blink {
class DOMException;
class IDBDatabase;
-class IDBObservation;
class MODULES_EXPORT IDBDatabaseCallbacks
: public GarbageCollected<IDBDatabaseCallbacks> {
@@ -49,10 +50,6 @@ class MODULES_EXPORT IDBDatabaseCallbacks
virtual void OnAbort(int64_t transaction_id, DOMException*);
virtual void OnComplete(int64_t transaction_id);
- virtual void OnChanges(
- const WebIDBDatabaseCallbacks::ObservationIndexMap&,
- Vector<Persistent<IDBObservation>> observations,
- const WebIDBDatabaseCallbacks::TransactionMap& transactions);
void Connect(IDBDatabase*);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h
index e7b66443acd..de745c4481c 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database_error.h
@@ -29,6 +29,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_ERROR_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_DATABASE_ERROR_H_
+#include <utility>
+
#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/wtf/text/wtf_string.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
index 4294805e393..1bea8d7f533 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -73,7 +73,8 @@ namespace {
class WebIDBGetDBNamesCallbacksImpl : public WebIDBCallbacks {
public:
- WebIDBGetDBNamesCallbacksImpl(ScriptPromiseResolver* promise_resolver)
+ explicit WebIDBGetDBNamesCallbacksImpl(
+ ScriptPromiseResolver* promise_resolver)
: promise_resolver_(promise_resolver) {
probe::AsyncTaskScheduled(
ExecutionContext::From(promise_resolver_->GetScriptState()),
@@ -137,8 +138,6 @@ class WebIDBGetDBNamesCallbacksImpl : public WebIDBCallbacks {
// completed in the destructor.
}
- void SuccessStringList(const Vector<String>&) override { NOTREACHED(); }
-
void SuccessCursor(
mojo::PendingAssociatedRemote<mojom::blink::IDBCursor> cursor_info,
std::unique_ptr<IDBKey> key,
@@ -282,39 +281,35 @@ ScriptPromise IDBFactory::GetDatabaseInfo(ScriptState* script_state,
return resolver->Promise();
}
-IDBRequest* IDBFactory::GetDatabaseNames(ScriptState* script_state,
- ExceptionState& exception_state) {
- IDB_TRACE("IDBFactory::getDatabaseNamesRequestSetup");
- IDBRequest::AsyncTraceState metrics("IDBFactory::getDatabaseNames");
- IDBRequest* request = IDBRequest::Create(script_state, IDBRequest::Source(),
- nullptr, std::move(metrics));
+void IDBFactory::GetDatabaseInfo(
+ ScriptState* script_state,
+ std::unique_ptr<mojom::blink::IDBCallbacks> callbacks) {
// TODO(jsbell): Used only by inspector; remove unneeded checks/exceptions?
- if (!IsContextValid(ExecutionContext::From(script_state)))
- return nullptr;
+ if (!IsContextValid(ExecutionContext::From(script_state))) {
+ return;
+ }
+
if (!ExecutionContext::From(script_state)
->GetSecurityOrigin()
->CanAccessDatabase()) {
- exception_state.ThrowSecurityError(
- "access to the Indexed Database API is denied in this context.");
- return nullptr;
- }
-
- if (ExecutionContext::From(script_state)->GetSecurityOrigin()->IsLocal()) {
- UseCounter::Count(ExecutionContext::From(script_state),
- WebFeature::kFileAccessedDatabase);
+ callbacks->Error(mojom::blink::IDBException::kAbortError,
+ "Access to the IndexedDB API is denied in this context.");
+ return;
}
if (!AllowIndexedDB(script_state)) {
- request->HandleResponse(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
- return request;
+ callbacks->Error(mojom::blink::IDBException::kUnknownError,
+ kPermissionDeniedErrorMessage);
+ return;
}
- auto callbacks = request->CreateWebCallbacks();
- callbacks->SetState(nullptr, WebIDBCallbacksImpl::kNoTransaction);
+ mojo::PendingAssociatedRemote<mojom::blink::IDBCallbacks> pending_callbacks;
+ mojo::MakeSelfOwnedAssociatedReceiver(
+ std::move(callbacks),
+ pending_callbacks.InitWithNewEndpointAndPassReceiver());
+
GetFactory(ExecutionContext::From(script_state))
- ->GetDatabaseNames(GetCallbacksProxy(std::move(callbacks)));
- return request;
+ ->GetDatabaseInfo(std::move(pending_callbacks));
}
IDBOpenDBRequest* IDBFactory::open(ScriptState* script_state,
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 0299fa661ce..53ac1de2655 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
@@ -29,6 +29,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_FACTORY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_FACTORY_H_
+#include <memory>
+
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -70,12 +72,14 @@ class MODULES_EXPORT IDBFactory final : public ScriptWrappable {
ExceptionState&);
// These are not exposed to the web applications and only used by DevTools.
- IDBRequest* GetDatabaseNames(ScriptState*, ExceptionState&);
IDBOpenDBRequest* CloseConnectionsAndDeleteDatabase(ScriptState*,
const String& name,
ExceptionState&);
ScriptPromise GetDatabaseInfo(ScriptState*, ExceptionState&);
+ // This method is exposed specifically for DevTools.
+ void GetDatabaseInfo(ScriptState*,
+ std::unique_ptr<mojom::blink::IDBCallbacks> callbacks);
void SetFactoryForTesting(mojo::Remote<mojom::blink::IDBFactory> factory);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
index a80377b7fb0..fd5aff9e060 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_factory.h"
#include <memory>
+#include <utility>
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
@@ -91,12 +92,6 @@ class BackendFactoryWithMockedDatabaseInfo : public mojom::blink::IDBFactory {
NOTREACHED();
}
- void GetDatabaseNames(
- mojo::PendingAssociatedRemote<mojom::blink::IDBCallbacks>
- pending_callbacks) override {
- NOTREACHED();
- }
-
void GetDatabaseInfo(mojo::PendingAssociatedRemote<mojom::blink::IDBCallbacks>
pending_callbacks) override {
callbacks_ptr_->Bind(std::move(pending_callbacks));
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
index fd21e6d5f53..7ea637a656d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_index.cc
@@ -25,7 +25,9 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
+#include <limits>
#include <memory>
+#include <utility>
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
index 02f0da3fca8..98e8c1cb943 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.h
@@ -90,6 +90,10 @@ class MODULES_EXPORT IDBKey {
static std::unique_ptr<IDBKey> Clone(const IDBKey* rkey);
+ // Disallow copy and assign.
+ IDBKey(const IDBKey&) = delete;
+ IDBKey& operator=(const IDBKey&) = delete;
+
~IDBKey();
mojom::IDBKeyType GetType() const { return type_; }
@@ -138,10 +142,8 @@ class MODULES_EXPORT IDBKey {
std::unique_ptr<IDBKey> array_key);
private:
- DISALLOW_COPY_AND_ASSIGN(IDBKey);
-
IDBKey();
- IDBKey(mojom::IDBKeyType type);
+ explicit IDBKey(mojom::IDBKeyType type);
IDBKey(mojom::IDBKeyType type, double number);
explicit IDBKey(const String& value);
explicit IDBKey(scoped_refptr<SharedBuffer> value);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
index 803ffe6619e..a00d721aab6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_range.h
@@ -26,6 +26,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_KEY_RANGE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_KEY_RANGE_H_
+#include <memory>
+#include <utility>
+
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
index 6f54902a3e6..e1d008e3bd6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_metadata.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
+#include <utility>
+
namespace blink {
constexpr int64_t IDBIndexMetadata::kInvalidId;
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h
index ac96affd8ba..b6f022f130d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_name_and_version.h
@@ -1,3 +1,7 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_NAME_AND_VERSION_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_NAME_AND_VERSION_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
index 39508a0f3cb..8af6a84e07e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
@@ -25,7 +25,9 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_object_store.h"
+#include <limits>
#include <memory>
+#include <utility>
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
@@ -550,7 +552,7 @@ IDBRequest* IDBObjectStore::DoPutAll(ScriptState* script_state,
auto idb_value = std::make_unique<IDBValue>(
value_wrappers[i].TakeWireBytes(), value_wrappers[i].TakeBlobInfo(),
- value_wrappers[i].TakeNativeFileSystemTransferTokens());
+ value_wrappers[i].TakeFileSystemAccessTransferTokens());
puts[i]->value = std::move(idb_value);
}
@@ -797,7 +799,7 @@ IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state,
auto idb_value = std::make_unique<IDBValue>(
value_wrapper.TakeWireBytes(), value_wrapper.TakeBlobInfo(),
- value_wrapper.TakeNativeFileSystemTransferTokens());
+ value_wrapper.TakeFileSystemAccessTransferTokens());
request->transit_blob_handles() = value_wrapper.TakeBlobDataHandles();
transaction_->transaction_backend()->Put(
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
index 4e79d219730..a2ccd180759 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc
deleted file mode 100644
index 168d6d1ab9f..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
-#include "third_party/blink/renderer/modules/indexed_db_names.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_value.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"
-
-namespace blink {
-
-IDBObservation::~IDBObservation() = default;
-
-ScriptValue IDBObservation::key(ScriptState* script_state) {
- if (!key_range_)
- return ScriptValue::From(script_state,
- v8::Undefined(script_state->GetIsolate()));
-
- return ScriptValue::From(script_state, key_range_);
-}
-
-ScriptValue IDBObservation::value(ScriptState* script_state) {
- return ScriptValue::From(script_state, value_);
-}
-
-mojom::IDBOperationType IDBObservation::StringToOperationType(
- const String& type) {
- if (type == indexed_db_names::kAdd)
- return mojom::IDBOperationType::Add;
- if (type == indexed_db_names::kPut)
- return mojom::IDBOperationType::Put;
- if (type == indexed_db_names::kDelete)
- return mojom::IDBOperationType::Delete;
- if (type == indexed_db_names::kClear)
- return mojom::IDBOperationType::Clear;
-
- NOTREACHED();
- return mojom::IDBOperationType::Add;
-}
-
-const String& IDBObservation::type() const {
- switch (operation_type_) {
- case mojom::IDBOperationType::Add:
- return indexed_db_names::kAdd;
-
- case mojom::IDBOperationType::Put:
- return indexed_db_names::kPut;
-
- case mojom::IDBOperationType::Delete:
- return indexed_db_names::kDelete;
-
- case mojom::IDBOperationType::Clear:
- return indexed_db_names::kClear;
-
- default:
- NOTREACHED();
- return indexed_db_names::kAdd;
- }
-}
-
-IDBObservation::IDBObservation(int64_t object_store_id,
- mojom::IDBOperationType type,
- IDBKeyRange* key_range,
- std::unique_ptr<IDBValue> value)
- : object_store_id_(object_store_id),
- operation_type_(type),
- key_range_(key_range) {
- value_ = MakeGarbageCollected<IDBAny>(std::move(value));
-}
-
-void IDBObservation::SetIsolate(v8::Isolate* isolate) {
- DCHECK(value_ && value_->Value());
- value_->Value()->SetIsolate(isolate);
-}
-
-void IDBObservation::Trace(Visitor* visitor) const {
- visitor->Trace(key_range_);
- visitor->Trace(value_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // 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
deleted file mode 100644
index b44b4989edc..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.+
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVATION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVATION_H_
-
-#include <memory>
-
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink-forward.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class IDBAny;
-class IDBKeyRange;
-class IDBValue;
-class ScriptState;
-
-class IDBObservation final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- static mojom::IDBOperationType StringToOperationType(const String&);
-
- IDBObservation(int64_t object_store_id,
- mojom::IDBOperationType type,
- IDBKeyRange* key_range,
- std::unique_ptr<IDBValue> value);
- ~IDBObservation() override;
-
- void SetIsolate(v8::Isolate* isolate);
- void Trace(Visitor*) const override;
-
- // Implement the IDL
- ScriptValue key(ScriptState*);
- ScriptValue value(ScriptState*);
- const String& type() const;
-
- // Helpers.
- int64_t object_store_id() const { return object_store_id_; }
-
- private:
- int64_t object_store_id_;
- const mojom::IDBOperationType operation_type_;
- Member<IDBKeyRange> key_range_;
- Member<IDBAny> value_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.idl
deleted file mode 100644
index c25bbf57d3d..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/WICG/indexed-db-observers/blob/gh-pages/EXPLAINER.md#records
-
-enum IDBObservationType {
- "add",
- "put",
- "delete",
- "clear"
-};
-[
- Exposed=(Window,Worker),
- RuntimeEnabled=IDBObserver
-]
- interface IDBObservation {
- readonly attribute IDBObservationType type;
- // When the record is a "delete" type, this is an IDBKeyRange.
- [CallWith=ScriptState] readonly attribute any key;
- [CallWith=ScriptState] readonly attribute any value;
-};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.cc
deleted file mode 100644
index f5388f1ce09..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/indexeddb/idb_observer.h"
-
-#include <bitset>
-
-#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_init.h"
-#include "third_party/blink/renderer/modules/indexed_db_names.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
-#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-
-namespace blink {
-
-IDBObserver* IDBObserver::Create(V8IDBObserverCallback* callback) {
- return MakeGarbageCollected<IDBObserver>(callback);
-}
-
-IDBObserver::IDBObserver(V8IDBObserverCallback* callback)
- : callback_(callback) {}
-
-void IDBObserver::observe(IDBDatabase* database,
- IDBTransaction* transaction,
- const IDBObserverInit* options,
- ExceptionState& exception_state) {
- if (!transaction->IsActive()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kTransactionInactiveError,
- transaction->InactiveErrorMessage());
- return;
- }
- if (transaction->IsVersionChange()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kTransactionInactiveError,
- IDBDatabase::kCannotObserveVersionChangeTransaction);
- return;
- }
- if (!database->Backend()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- IDBDatabase::kDatabaseClosedErrorMessage);
- return;
- }
- if (!options->hasOperationTypes()) {
- exception_state.ThrowTypeError(
- "operationTypes not specified in observe options->");
- return;
- }
- if (options->operationTypes().IsEmpty()) {
- exception_state.ThrowTypeError("operationTypes must be populated.");
- return;
- }
-
- std::bitset<kIDBOperationTypeCount> types;
- for (const auto& operation_type : options->operationTypes()) {
- if (operation_type == indexed_db_names::kAdd) {
- types[static_cast<size_t>(mojom::IDBOperationType::Add)] = true;
- } else if (operation_type == indexed_db_names::kPut) {
- types[static_cast<size_t>(mojom::IDBOperationType::Put)] = true;
- } else if (operation_type == indexed_db_names::kDelete) {
- types[static_cast<size_t>(mojom::IDBOperationType::Delete)] = true;
- } else if (operation_type == indexed_db_names::kClear) {
- types[static_cast<size_t>(mojom::IDBOperationType::Clear)] = true;
- } else {
- exception_state.ThrowTypeError(
- "Unknown operation type in observe options: " +
- IDLEnumAsString(operation_type));
- return;
- }
- }
-
- int32_t observer_id =
- database->AddObserver(this, transaction->Id(), options->transaction(),
- options->noRecords(), options->values(), types);
- observer_ids_.insert(observer_id, database);
-}
-
-void IDBObserver::unobserve(IDBDatabase* database,
- ExceptionState& exception_state) {
- if (!database->Backend()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- IDBDatabase::kDatabaseClosedErrorMessage);
- return;
- }
-
- Vector<int32_t> observer_ids_to_remove;
- for (const auto& it : observer_ids_) {
- if (it.value == database)
- observer_ids_to_remove.push_back(it.key);
- }
- observer_ids_.RemoveAll(observer_ids_to_remove);
-
- if (!observer_ids_to_remove.IsEmpty())
- database->RemoveObservers(observer_ids_to_remove);
-}
-
-void IDBObserver::Trace(Visitor* visitor) const {
- visitor->Trace(callback_);
- visitor->Trace(observer_ids_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.h
deleted file mode 100644
index 9fb5b65ac7a..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_H_
-
-#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class ExceptionState;
-class IDBDatabase;
-class IDBObserverInit;
-class IDBTransaction;
-class V8IDBObserverCallback;
-
-class MODULES_EXPORT IDBObserver final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- static IDBObserver* Create(V8IDBObserverCallback*);
-
- V8IDBObserverCallback* Callback() { return callback_; }
-
- explicit IDBObserver(V8IDBObserverCallback*);
-
- // Implement the IDBObserver IDL.
- void observe(IDBDatabase*,
- IDBTransaction*,
- const IDBObserverInit*,
- ExceptionState&);
- void unobserve(IDBDatabase*, ExceptionState&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<V8IDBObserverCallback> callback_;
- HeapHashMap<int32_t, WeakMember<IDBDatabase>> observer_ids_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.idl
deleted file mode 100644
index a56142de3f6..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer.idl
+++ /dev/null
@@ -1,16 +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.
-
-// https://github.com/WICG/indexed-db-observers/issues/24
-
-callback IDBObserverCallback = void (IDBObserverChanges changes);
-
-[
- Exposed=(Window,Worker),
- RuntimeEnabled=IDBObserver
-] interface IDBObserver {
- constructor(IDBObserverCallback callback);
- [RaisesException, Measure] void observe(IDBDatabase db, IDBTransaction tx, IDBObserverInit options);
- [RaisesException, Measure] void unobserve(IDBDatabase db);
-};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc
deleted file mode 100644
index ab409365c77..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-
-namespace blink {
-
-ScriptValue IDBObserverChanges::records(ScriptState* script_state) {
- v8::Local<v8::Context> context(script_state->GetContext());
- v8::Isolate* isolate(script_state->GetIsolate());
- v8::Local<v8::Map> map = v8::Map::New(isolate);
- for (const auto& it : records_) {
- v8::Local<v8::String> key =
- V8String(isolate, database_->GetObjectStoreName(it.key));
- v8::Local<v8::Value> value = ToV8(*it.value, context->Global(), isolate);
- map->Set(context, key, value).ToLocalChecked();
- }
- return ScriptValue::From(script_state, map);
-}
-
-IDBObserverChanges::IDBObserverChanges(
- IDBDatabase* database,
- IDBTransaction* transaction,
- const Vector<Persistent<IDBObservation>>& observations,
- const Vector<int32_t>& observation_indices)
- : database_(database), transaction_(transaction) {
- ExtractChanges(observations, observation_indices);
-}
-
-void IDBObserverChanges::ExtractChanges(
- const Vector<Persistent<IDBObservation>>& observations,
- const Vector<int32_t>& observation_indices) {
- // TODO(dmurph): Avoid getting and setting repeated times.
- for (const auto& idx : observation_indices) {
- records_
- .insert(observations[idx]->object_store_id(),
- MakeGarbageCollected<HeapVector<Member<IDBObservation>>>())
- .stored_value->value->emplace_back(observations[idx]);
- }
-}
-
-void IDBObserverChanges::Trace(Visitor* visitor) const {
- visitor->Trace(database_);
- visitor->Trace(transaction_);
- visitor->Trace(records_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h
deleted file mode 100644
index 8a516e5b3c6..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_CHANGES_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_CHANGES_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class ScriptState;
-
-class IDBObserverChanges final : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- IDBObserverChanges(IDBDatabase*,
- IDBTransaction*,
- const Vector<Persistent<IDBObservation>>& observations,
- const Vector<int32_t>& observation_indices);
-
- void Trace(Visitor*) const override;
-
- // Implement IDL
- IDBTransaction* transaction() const { return transaction_.Get(); }
- IDBDatabase* database() const { return database_.Get(); }
- ScriptValue records(ScriptState*);
-
- private:
- void ExtractChanges(const Vector<Persistent<IDBObservation>>& observations,
- const Vector<int32_t>& observation_indices);
-
- Member<IDBDatabase> database_;
- Member<IDBTransaction> transaction_;
- // Map object_store_id to IDBObservation list.
- HeapHashMap<int64_t, Member<HeapVector<Member<IDBObservation>>>> records_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_OBSERVER_CHANGES_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.idl
deleted file mode 100644
index 80908203103..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_changes.idl
+++ /dev/null
@@ -1,16 +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.
-
-// https://github.com/WICG/indexed-db-observers/blob/gh-pages/EXPLAINER.md#changes-argument
-
-[
- Exposed=(Window, Worker),
- RuntimeEnabled=IDBObserver
-] interface IDBObserverChanges {
- readonly attribute IDBDatabase database;
- // Transaction contains the same object stores as the transaction on which IDBTransaction.observe was called.
- readonly attribute IDBTransaction transaction;
- // Map object from String (object store name) to Array of IDBObservation.
- [CallWith=ScriptState] readonly attribute any records;
-};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_init.idl b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_init.idl
deleted file mode 100644
index d22dfbd4467..00000000000
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observer_init.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://github.com/WICG/indexed-db-observers/blob/gh-pages/EXPLAINER.md#options-argument
-
-dictionary IDBObserverInit {
- boolean transaction = false;
- boolean values = false;
- boolean noRecords = false;
- sequence<IDBObservationType> operationTypes = [];
-};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
index cd6dfe8f930..e80f106881e 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_open_db_request.cc
@@ -107,7 +107,7 @@ void IDBOpenDBRequest::EnqueueUpgradeNeeded(
auto* idb_database = MakeGarbageCollected<IDBDatabase>(
GetExecutionContext(), std::move(backend), database_callbacks_.Release(),
- isolate_, std::move(connection_lifetime_));
+ std::move(connection_lifetime_));
idb_database->SetMetadata(metadata);
if (old_version == IDBDatabaseMetadata::kNoVersion) {
@@ -150,8 +150,7 @@ void IDBOpenDBRequest::EnqueueResponse(std::unique_ptr<WebIDBDatabase> backend,
DCHECK(database_callbacks_);
idb_database = MakeGarbageCollected<IDBDatabase>(
GetExecutionContext(), std::move(backend),
- database_callbacks_.Release(), isolate_,
- std::move(connection_lifetime_));
+ database_callbacks_.Release(), std::move(connection_lifetime_));
SetResult(MakeGarbageCollected<IDBAny>(idb_database));
}
idb_database->SetMetadata(metadata);
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
index e59692356a1..f4c494d94f8 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc
@@ -437,19 +437,6 @@ void IDBRequest::EnqueueResponse(DOMException* error) {
EnqueueEvent(Event::CreateCancelableBubble(event_type_names::kError));
}
-void IDBRequest::EnqueueResponse(const Vector<String>& string_list) {
- IDB_TRACE("IDBRequest::onSuccess(StringList)");
- if (!ShouldEnqueueEvent()) {
- metrics_.RecordAndReset();
- return;
- }
-
- auto* dom_string_list = MakeGarbageCollected<DOMStringList>();
- for (const auto& item : string_list)
- dom_string_list->Append(item);
- EnqueueResultInternal(MakeGarbageCollected<IDBAny>(dom_string_list));
-}
-
void IDBRequest::EnqueueResponse(std::unique_ptr<WebIDBCursor> backend,
std::unique_ptr<IDBKey> key,
std::unique_ptr<IDBKey> primary_key,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
index b7df7ced4bc..65fc0c9ca0f 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.h
@@ -30,6 +30,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_H_
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
@@ -54,7 +55,6 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
@@ -99,7 +99,11 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
// This is used for internal requests that should not show up in an
// application's trace. Examples of internal requests are the requests
// issued by DevTools, and the requests used to populate indexes.
- explicit AsyncTraceState() = default;
+ AsyncTraceState() = default;
+
+ // Disallow copy and assign.
+ AsyncTraceState(const AsyncTraceState&) = delete;
+ AsyncTraceState& operator=(const AsyncTraceState&) = delete;
// Creates an instance that produces begin/end events with the given name.
//
@@ -157,8 +161,6 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
const char* trace_event_name_ = nullptr;
// Uniquely generated ID that ties an async trace's begin and end events.
size_t id_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncTraceState);
};
static IDBRequest* Create(ScriptState*,
@@ -276,10 +278,6 @@ class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData,
mojo::PendingReceiver<mojom::blink::IDBDatabaseGetAllResultSink>
receiver);
- // Only used in webkitGetDatabaseNames(), which is deprecated and hopefully
- // going away soon.
- void EnqueueResponse(const Vector<String>&);
-
// Only IDBOpenDBRequest instances should receive these:
virtual void EnqueueBlocked(int64_t old_version) { NOTREACHED(); }
virtual void EnqueueUpgradeNeeded(int64_t old_version,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
index 1eadb10238c..1055b5049ef 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_request_loader.h"
+#include <algorithm>
+
#include "base/metrics/histogram_functions.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
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 99d9c2f463b..cf911711105 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
@@ -93,13 +93,6 @@ class BackendDatabaseWithMockedClose
mojom::blink::IDBTransactionDurability) override {}
MOCK_METHOD0(Close, void());
void VersionChangeIgnored() override {}
- void AddObserver(int64_t transaction_id,
- int32_t observer_id,
- bool include_transaction,
- bool no_records,
- bool values,
- uint32_t operation_types) override {}
- void RemoveObservers(const WTF::Vector<int32_t>& observers) override {}
void Get(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
@@ -192,8 +185,7 @@ class IDBRequestTest : public testing::Test {
std::unique_ptr<MockWebIDBTransaction> transaction_backend) {
db_ = MakeGarbageCollected<IDBDatabase>(
scope.GetExecutionContext(), std::move(database_backend),
- MakeGarbageCollected<IDBDatabaseCallbacks>(), scope.GetIsolate(),
- mojo::NullRemote());
+ MakeGarbageCollected<IDBDatabaseCallbacks>(), mojo::NullRemote());
HashSet<String> transaction_scope = {"store"};
transaction_ = IDBTransaction::CreateNonVersionChange(
@@ -233,7 +225,6 @@ void EnsureIDBCallbacksDontThrow(IDBRequest* request,
request->HandleResponse();
request->HandleResponse(IDBKey::CreateInvalid(), IDBKey::CreateInvalid(),
CreateNullIDBValueForTesting(scope.GetIsolate()));
- request->EnqueueResponse(Vector<String>());
EXPECT_TRUE(!exception_state.HadException());
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.h
index cade5203d9c..d7e7756a946 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_TEST_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_TEST_HELPER_H_
+#include <memory>
+
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "v8/include/v8.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
index d9403a61087..14f62cc2206 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -97,7 +97,7 @@ IDBTransaction::IDBTransaction(
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::kOutstandingIndexedDBTransaction,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
DCHECK(database_);
DCHECK(!scope_.IsEmpty()) << "Non-versionchange transactions must operate "
"on a well-defined set of stores";
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
index 2ad970b9a93..a58f41d685d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
@@ -44,6 +44,7 @@
#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/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
index 158cad4eeab..29238f7e1fa 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
@@ -96,8 +96,7 @@ class IDBTransactionTest : public testing::Test,
std::unique_ptr<MockWebIDBTransaction> transaction_backend) {
db_ = MakeGarbageCollected<IDBDatabase>(
scope.GetExecutionContext(), std::move(database_backend),
- MakeGarbageCollected<FakeIDBDatabaseCallbacks>(), scope.GetIsolate(),
- mojo::NullRemote());
+ MakeGarbageCollected<FakeIDBDatabaseCallbacks>(), mojo::NullRemote());
HashSet<String> transaction_scope = {"store"};
transaction_ = IDBTransaction::CreateNonVersionChange(
@@ -134,7 +133,6 @@ TEST_F(IDBTransactionTest, ContextDestroyedEarlyDeath) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
@@ -175,7 +173,6 @@ TEST_F(IDBTransactionTest, ContextDestroyedAfterDone) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
@@ -222,7 +219,6 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithQueuedResult) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
@@ -266,7 +262,6 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithTwoQueuedResults) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
@@ -317,7 +312,6 @@ TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
@@ -367,7 +361,6 @@ TEST_F(IDBTransactionTest, TransactionFinish) {
Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions =
MakeGarbageCollected<HeapHashSet<WeakMember<IDBTransaction>>>();
- ;
live_transactions->insert(transaction_);
ThreadState::Current()->CollectAllGarbageForTesting();
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
index e0a30940ccd..99e6a8cbf55 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc
@@ -21,11 +21,11 @@ namespace blink {
IDBValue::IDBValue(
scoped_refptr<SharedBuffer> data,
Vector<WebBlobInfo> blob_info,
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>>
- native_file_system_tokens)
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>
+ file_system_access_tokens)
: data_(std::move(data)),
blob_info_(std::move(blob_info)),
- native_file_system_tokens_(std::move(native_file_system_tokens)) {}
+ file_system_access_tokens_(std::move(file_system_access_tokens)) {}
IDBValue::~IDBValue() {
if (isolate_ && external_allocated_size_)
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 0fafc4435e1..b118a34515a 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
@@ -6,10 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_H_
#include <memory>
+#include <utility>
#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/file_system_access/file_system_access_transfer_token.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.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"
@@ -41,10 +42,14 @@ class MODULES_EXPORT IDBValue final {
IDBValue(
scoped_refptr<SharedBuffer>,
Vector<WebBlobInfo>,
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>> =
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>> =
{});
~IDBValue();
+ // Disallow copy and assign.
+ IDBValue(const IDBValue&) = delete;
+ IDBValue& operator=(const IDBValue&) = delete;
+
size_t DataSize() const { return data_ ? data_->size() : 0; }
bool IsNull() const;
@@ -54,9 +59,9 @@ class MODULES_EXPORT IDBValue final {
const IDBKey* PrimaryKey() const { return primary_key_.get(); }
const IDBKeyPath& KeyPath() const { return key_path_; }
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>>&
- NativeFileSystemTokens() {
- return native_file_system_tokens_;
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>&
+ FileSystemAccessTokens() {
+ return file_system_access_tokens_;
}
// Injects a primary key into a value coming from the backend.
@@ -93,8 +98,6 @@ class MODULES_EXPORT IDBValue final {
const mojom::blink::IDBReturnValuePtr& input);
private:
- DISALLOW_COPY_AND_ASSIGN(IDBValue);
-
friend class IDBValueUnwrapper;
// Keep this private to prevent new refs because we manually bookkeep the
@@ -103,8 +106,8 @@ class MODULES_EXPORT IDBValue final {
Vector<WebBlobInfo> blob_info_;
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>>
- native_file_system_tokens_;
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>
+ file_system_access_tokens_;
std::unique_ptr<IDBKey> primary_key_;
IDBKeyPath key_path_;
@@ -118,4 +121,4 @@ class MODULES_EXPORT IDBValue final {
} // namespace blink
-#endif
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_H_
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
index bd07795b99a..7bb0cae035b 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
@@ -40,7 +40,7 @@ namespace {
// will have to be bumped.
// The SSV format version whose encoding hole is (ab)used for wrapping.
-const static uint8_t kRequiresProcessingSSVPseudoVersion = 17;
+static const uint8_t kRequiresProcessingSSVPseudoVersion = 17;
// SSV processing command replacing the SSV data bytes with a Blob's contents.
//
@@ -50,7 +50,7 @@ const static uint8_t kRequiresProcessingSSVPseudoVersion = 17;
// 4) varint - Blob size
// 5) varint - the offset of the SSV-wrapping Blob in the IDBValue list of Blobs
// (should always be the last Blob)
-const static uint8_t kReplaceWithBlob = 1;
+static const uint8_t kReplaceWithBlob = 1;
} // namespace
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h
index d21e3ecdbc9..133c2760cc6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h
@@ -5,6 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_WRAPPING_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_WRAPPING_H_
+#include <memory>
+#include <utility>
+
#include "base/feature_list.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/platform/web_blob_info.h"
@@ -154,14 +157,14 @@ class MODULES_EXPORT IDBValueWrapper {
return std::move(blob_info_);
}
- Vector<mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>>
- TakeNativeFileSystemTransferTokens() {
+ Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>
+ TakeFileSystemAccessTransferTokens() {
#if DCHECK_IS_ON()
DCHECK(done_cloning_) << __func__ << " called before DoneCloning()";
DCHECK(owns_file_system_handles_) << __func__ << " called twice";
owns_file_system_handles_ = false;
#endif // DCHECK_IS_ON()
- return std::move(serialized_value_->NativeFileSystemTokens());
+ return std::move(serialized_value_->FileSystemAccessTokens());
}
size_t DataLengthBeforeWrapInBytes() { return original_data_length_; }
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idls.gni b/chromium/third_party/blink/renderer/modules/indexeddb/idls.gni
index 9c8b7d8bbef..543974793d5 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idls.gni
@@ -10,9 +10,6 @@ modules_idl_files = [
"idb_index.idl",
"idb_key_range.idl",
"idb_object_store.idl",
- "idb_observation.idl",
- "idb_observer.idl",
- "idb_observer_changes.idl",
"idb_open_db_request.idl",
"idb_request.idl",
"idb_transaction.idl",
@@ -23,7 +20,6 @@ modules_dictionary_idl_files = [
"idb_database_info.idl",
"idb_index_parameters.idl",
"idb_object_store_parameters.idl",
- "idb_observer_init.idl",
"idb_transaction_options.idl",
"idb_version_change_event_init.idl",
]
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 5b60db8bd50..5df392c7ef7 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
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
+#include <utility>
+
#include "base/stl_util.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
@@ -101,7 +103,8 @@ UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
// 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.
+ case blink::mojom::IDBKeyType::Min: // Only used in the browser.
+ break;
}
NOTREACHED();
return blink::mojom::IDBKeyDataView::Tag::OTHER_NONE;
@@ -174,7 +177,7 @@ StructTraits<blink::mojom::IDBValueDataView, std::unique_ptr<blink::IDBValue>>::
external_objects(const std::unique_ptr<blink::IDBValue>& input) {
Vector<blink::mojom::blink::IDBExternalObjectPtr> external_objects;
external_objects.ReserveInitialCapacity(
- input->BlobInfo().size() + input->NativeFileSystemTokens().size());
+ input->BlobInfo().size() + input->FileSystemAccessTokens().size());
for (const blink::WebBlobInfo& info : input->BlobInfo()) {
auto blob_info = blink::mojom::blink::IDBBlobInfo::New();
if (info.IsFile()) {
@@ -198,9 +201,9 @@ StructTraits<blink::mojom::IDBValueDataView, std::unique_ptr<blink::IDBValue>>::
blink::mojom::blink::IDBExternalObject::NewBlobOrFile(
std::move(blob_info)));
}
- for (auto& token : input->NativeFileSystemTokens()) {
+ for (auto& token : input->FileSystemAccessTokens()) {
external_objects.push_back(
- blink::mojom::blink::IDBExternalObject::NewNativeFileSystemToken(
+ blink::mojom::blink::IDBExternalObject::NewFileSystemAccessToken(
std::move(token)));
}
return external_objects;
@@ -230,8 +233,8 @@ bool StructTraits<blink::mojom::IDBValueDataView,
Vector<blink::WebBlobInfo> value_blob_info;
Vector<
- mojo::PendingRemote<blink::mojom::blink::NativeFileSystemTransferToken>>
- native_file_system_tokens;
+ mojo::PendingRemote<blink::mojom::blink::FileSystemAccessTransferToken>>
+ file_system_access_tokens;
for (const auto& object : external_objects) {
switch (object->which()) {
@@ -249,16 +252,16 @@ bool StructTraits<blink::mojom::IDBValueDataView,
break;
}
case blink::mojom::blink::IDBExternalObject::Tag::
- NATIVE_FILE_SYSTEM_TOKEN:
- native_file_system_tokens.push_back(
- std::move(object->get_native_file_system_token()));
+ FILE_SYSTEM_ACCESS_TOKEN:
+ file_system_access_tokens.push_back(
+ std::move(object->get_file_system_access_token()));
break;
}
}
*out = std::make_unique<blink::IDBValue>(
std::move(value_buffer), std::move(value_blob_info),
- std::move(native_file_system_tokens));
+ std::move(file_system_access_tokens));
return true;
}
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 8dcf25fe54c..db0e666beb3 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
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INDEXED_DB_BLINK_MOJOM_TRAITS_H_
#include <stdint.h>
+#include <memory>
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
#include "mojo/public/cpp/bindings/map_traits_wtf_hash_map.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc
index 7f7a02b8a57..3654f6d7534 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
#include <random>
+#include <utility>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
index d9723ec3199..2520fda76ef 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.cc
@@ -6,9 +6,6 @@
#include <utility>
-#include "third_party/blink/public/platform/web_blob_info.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
#include "third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
@@ -42,42 +39,4 @@ void IndexedDBDatabaseCallbacksImpl::Complete(int64_t transaction_id) {
callbacks_->OnComplete(transaction_id);
}
-void IndexedDBDatabaseCallbacksImpl::Changes(
- mojom::blink::IDBObserverChangesPtr changes) {
- Vector<Persistent<IDBObservation>> observations;
- observations.ReserveInitialCapacity(changes->observations.size());
- for (const auto& observation : changes->observations) {
- IDBKeyRange* key_range = observation->key_range.To<IDBKeyRange*>();
- std::unique_ptr<IDBValue> value;
- if (observation->value.has_value())
- value = std::move(observation->value.value());
- if (!value || value->Data()->IsEmpty()) {
- value = std::make_unique<IDBValue>(scoped_refptr<SharedBuffer>(),
- Vector<WebBlobInfo>());
- }
- observations.emplace_back(MakeGarbageCollected<IDBObservation>(
- observation->object_store_id, observation->type, key_range,
- std::move(value)));
- }
-
- HashMap<int32_t, Vector<int32_t>> observation_index_map;
- for (const auto& observation_pair : changes->observation_index_map) {
- observation_index_map.insert(observation_pair.key,
- Vector<int32_t>(observation_pair.value));
- }
-
- HashMap<int32_t, std::pair<int64_t, Vector<int64_t>>> observer_transactions;
- for (const auto& transaction_pair : changes->transaction_map) {
- // Moving an int64_t is rather silly. Sadly, std::make_pair's overloads
- // accept either two rvalue arguments, or none.
- observer_transactions.insert(transaction_pair.key,
- std::make_pair<int64_t, Vector<int64_t>>(
- std::move(transaction_pair.value->id),
- std::move(transaction_pair.value->scope)));
- }
-
- callbacks_->OnChanges(observation_index_map, std::move(observations),
- observer_transactions);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h
index 0a88c407c06..f2d5d697999 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_database_callbacks_impl.h
@@ -22,6 +22,12 @@ class IndexedDBDatabaseCallbacksImpl
std::unique_ptr<WebIDBDatabaseCallbacks> callbacks);
~IndexedDBDatabaseCallbacksImpl() override;
+ // Disallow copy and assign.
+ IndexedDBDatabaseCallbacksImpl(const IndexedDBDatabaseCallbacksImpl&) =
+ delete;
+ IndexedDBDatabaseCallbacksImpl& operator=(
+ const IndexedDBDatabaseCallbacksImpl&) = delete;
+
// mojom::blink::IDBDatabaseCallbacks implementation
void ForcedClose() override;
void VersionChange(int64_t old_version, int64_t new_version) override;
@@ -29,12 +35,9 @@ class IndexedDBDatabaseCallbacksImpl
mojom::blink::IDBException code,
const WTF::String& message) override;
void Complete(int64_t transaction_id) override;
- void Changes(mojom::blink::IDBObserverChangesPtr changes) override;
private:
std::unique_ptr<WebIDBDatabaseCallbacks> callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseCallbacksImpl);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5 b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
index 3aa16b76096..8a89dce3e66 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
@@ -27,12 +27,6 @@
"none",
"total",
- // https://github.com/WICG/indexed-db-observers/blob/gh-pages/EXPLAINER.md//records
- "add",
- "put",
- "delete",
- "clear",
-
// The IDBTransactionDurability enum is still being standardized.
// https://chromestatus.com/feature/5730701489995776
"default",
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
index ac20fbb3435..b034b2383c6 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
@@ -109,40 +109,49 @@ Response AssertIDBFactory(LocalDOMWindow* dom_window, IDBFactory*& result) {
return Response::Success();
}
-class GetDatabaseNamesCallback final : public NativeEventListener {
+class GetDatabaseNamesCallback final : public mojom::blink::IDBCallbacks {
public:
- GetDatabaseNamesCallback(
- std::unique_ptr<RequestDatabaseNamesCallback> request_callback,
- const String& security_origin)
- : request_callback_(std::move(request_callback)),
- security_origin_(security_origin) {}
+ explicit GetDatabaseNamesCallback(
+ std::unique_ptr<RequestDatabaseNamesCallback> request_callback)
+ : request_callback_(std::move(request_callback)) {}
~GetDatabaseNamesCallback() override = default;
- void Invoke(ExecutionContext*, Event* event) override {
- if (event->type() != event_type_names::kSuccess) {
- request_callback_->sendFailure(
- Response::ServerError("Unexpected event type."));
- return;
- }
-
- IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
- IDBAny* request_result = idb_request->ResultAsAny();
- if (request_result->GetType() != IDBAny::kDOMStringListType) {
- request_callback_->sendFailure(
- Response::ServerError("Unexpected result type."));
- return;
- }
+ void Error(mojom::blink::IDBException code, const String& message) override {
+ request_callback_->sendFailure(
+ Response::ServerError("Could not obtain database names."));
+ }
- DOMStringList* database_names_list = request_result->DomStringList();
+ void SuccessNamesAndVersionsList(
+ Vector<mojom::blink::IDBNameAndVersionPtr> names_and_versions) override {
auto database_names = std::make_unique<protocol::Array<String>>();
- for (uint32_t i = 0; i < database_names_list->length(); ++i)
- database_names->emplace_back(database_names_list->item(i));
+ for (const auto& name_and_version : names_and_versions)
+ database_names->emplace_back(name_and_version->name);
request_callback_->sendSuccess(std::move(database_names));
}
+ void SuccessDatabase(
+ mojo::PendingAssociatedRemote<mojom::blink::IDBDatabase> pending_backend,
+ const IDBDatabaseMetadata& metadata) override {
+ NOTREACHED();
+ }
+
+ void SuccessInteger(int64_t value) override { NOTREACHED(); }
+
+ void Success() override { NOTREACHED(); }
+
+ void Blocked(int64_t old_version) override { NOTREACHED(); }
+
+ void UpgradeNeeded(
+ mojo::PendingAssociatedRemote<mojom::blink::IDBDatabase> pending_database,
+ int64_t old_version,
+ mojom::blink::IDBDataLoss data_loss,
+ const String& data_loss_message,
+ const IDBDatabaseMetadata& metadata) override {
+ NOTREACHED();
+ }
+
private:
std::unique_ptr<RequestDatabaseNamesCallback> request_callback_;
- String security_origin_;
};
class DeleteCallback final : public NativeEventListener {
@@ -438,7 +447,8 @@ class DatabaseLoader final
}
private:
- DatabaseLoader(std::unique_ptr<RequestDatabaseCallback> request_callback)
+ explicit DatabaseLoader(
+ std::unique_ptr<RequestDatabaseCallback> request_callback)
: request_callback_(std::move(request_callback)) {}
std::unique_ptr<RequestDatabaseCallback> request_callback_;
};
@@ -760,21 +770,9 @@ void InspectorIndexedDBAgent::requestDatabaseNames(
request_callback->sendFailure(Response::InternalError());
return;
}
- ScriptState::Scope scope(script_state);
- DummyExceptionStateForTesting exception_state;
- IDBRequest* idb_request =
- idb_factory->GetDatabaseNames(script_state, exception_state);
- if (exception_state.HadException()) {
- request_callback->sendFailure(
- Response::ServerError("Could not obtain database names."));
- return;
- }
- idb_request->addEventListener(
- event_type_names::kSuccess,
- MakeGarbageCollected<GetDatabaseNamesCallback>(
- std::move(request_callback),
- frame->DomWindow()->GetSecurityOrigin()->ToRawString()),
- false);
+ idb_factory->GetDatabaseInfo(
+ script_state,
+ std::make_unique<GetDatabaseNamesCallback>(std::move(request_callback)));
}
void InspectorIndexedDBAgent::requestDatabase(
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
index 16d2c8631ce..7e49011008d 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
@@ -31,6 +31,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INSPECTOR_INDEXED_DB_AGENT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_INSPECTOR_INDEXED_DB_AGENT_H_
+#include <memory>
+
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/IndexedDB.h"
#include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
index ccaa58bc826..efa65114794 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_callbacks.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_CALLBACKS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_CALLBACKS_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/optional.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
@@ -24,7 +26,11 @@ class MockWebIDBCallbacks : public WebIDBCallbacks {
MockWebIDBCallbacks();
~MockWebIDBCallbacks() override;
- void SetState(base::WeakPtr<WebIDBCursorImpl>, int64_t);
+ // Disallow copy and assign.
+ MockWebIDBCallbacks(const MockWebIDBCallbacks&) = delete;
+ MockWebIDBCallbacks& operator=(const MockWebIDBCallbacks&) = delete;
+
+ void SetState(base::WeakPtr<WebIDBCursorImpl>, int64_t) override;
MOCK_METHOD2(Error, void(mojom::blink::IDBException, const String&));
@@ -40,8 +46,6 @@ class MockWebIDBCallbacks : public WebIDBCallbacks {
MOCK_METHOD1(SuccessNamesAndVersionsList,
void(Vector<mojom::blink::IDBNameAndVersionPtr>));
- MOCK_METHOD1(SuccessStringList, void(const Vector<String>&));
-
void SuccessCursor(
mojo::PendingAssociatedRemote<mojom::blink::IDBCursor> cursor_info,
std::unique_ptr<IDBKey> key,
@@ -93,9 +97,6 @@ class MockWebIDBCallbacks : public WebIDBCallbacks {
const IDBDatabaseMetadata&));
MOCK_METHOD0(DetachRequestFromCallback, void());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockWebIDBCallbacks);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
index 9dce5f21f24..59a6da0c16c 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h
@@ -50,17 +50,6 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> {
int64_t object_store_id,
int64_t index_id,
const String& new_name));
- MOCK_METHOD6(
- AddObserver,
- void(int64_t transaction_id,
- int32_t observer_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<blink::kIDBOperationTypeCount> operation_types));
- MOCK_CONST_METHOD1(ContainsObserverId, bool(int32_t id));
- MOCK_METHOD1(RemoveObservers,
- void(const Vector<int32_t>& observer_ids_to_remove));
MOCK_METHOD6(Get,
void(int64_t transaction_id,
int64_t object_store_id,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
index d9351c5803d..309e4e683dc 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
@@ -116,20 +116,6 @@ void WebIDBCallbacksImpl::SuccessNamesAndVersionsList(
NOTREACHED();
}
-void WebIDBCallbacksImpl::SuccessStringList(const Vector<String>& string_list) {
- if (!request_)
- return;
-
- probe::AsyncTask async_task(request_->GetExecutionContext(), &async_task_id_,
- "success");
-#if DCHECK_IS_ON()
- DCHECK(!request_->TransactionHasQueuedResults());
-#endif // DCHECK_IS_ON()
- IDBRequest* request = request_.Get();
- Detach();
- request->EnqueueResponse(std::move(string_list));
-}
-
void WebIDBCallbacksImpl::SuccessCursor(
mojo::PendingAssociatedRemote<mojom::blink::IDBCursor> cursor_info,
std::unique_ptr<IDBKey> key,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
index f3460236b8e..e40f90ad627 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
@@ -66,7 +66,6 @@ class WebIDBCallbacksImpl final : public WebIDBCallbacks {
void Error(mojom::blink::IDBException code, const String& message) override;
void SuccessNamesAndVersionsList(
Vector<mojom::blink::IDBNameAndVersionPtr>) override;
- void SuccessStringList(const Vector<String>&) override;
void SuccessCursor(
mojo::PendingAssociatedRemote<mojom::blink::IDBCursor> cursor_info,
std::unique_ptr<IDBKey> key,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
index 1bdee8792b3..d186af62566 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h"
#include <stddef.h>
+#include <utility>
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
index 938b6294130..9b127da6efc 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
@@ -7,6 +7,8 @@
#include <stdint.h>
+#include <memory>
+
#include "base/gtest_prod_util.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
@@ -26,6 +28,10 @@ class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~WebIDBCursorImpl() override;
+ // Disallow copy and assign.
+ WebIDBCursorImpl(const WebIDBCursorImpl&) = delete;
+ WebIDBCursorImpl& operator=(const WebIDBCursorImpl&) = delete;
+
void Advance(uint32_t count, WebIDBCallbacks* callback) override;
void CursorContinue(const IDBKey* key,
@@ -92,8 +98,6 @@ class MODULES_EXPORT WebIDBCursorImpl : public WebIDBCursor {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::WeakPtrFactory<WebIDBCursorImpl> weak_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImpl);
};
} // namespace blink
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 26480f8f0a2..6190d569d79 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
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/macros.h"
@@ -121,14 +122,15 @@ class WebIDBCursorImplTest : public testing::Test {
blink::scheduler::GetSingleThreadTaskRunnerForTesting());
}
+ // Disallow copy and assign.
+ WebIDBCursorImplTest(const WebIDBCursorImplTest&) = delete;
+ WebIDBCursorImplTest& operator=(const WebIDBCursorImplTest&) = delete;
+
protected:
ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
std::unique_ptr<IDBKey> null_key_;
std::unique_ptr<WebIDBCursorImpl> cursor_;
std::unique_ptr<MockCursorImpl> mock_cursor_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest);
};
TEST_F(WebIDBCursorImplTest, PrefetchTest) {
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
index 34ed7bc4886..f2b4872ff11 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database.h
@@ -27,6 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_DATABASE_H_
#include <bitset>
+#include <memory>
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
@@ -76,15 +77,6 @@ class MODULES_EXPORT WebIDBDatabase {
static const int64_t kMinimumIndexId = 30;
- virtual void AddObserver(
- int64_t transaction_id,
- int32_t observer_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<blink::kIDBOperationTypeCount> operation_types) = 0;
- virtual void RemoveObservers(
- const Vector<int32_t>& observer_ids_to_remove) = 0;
virtual void Get(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
index b3973aa5978..d85c6a6c9b9 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h
@@ -31,19 +31,11 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
-class IDBObservation;
-
class WebIDBDatabaseCallbacks {
public:
- using ObservationIndexMap = HashMap<int32_t, Vector<int32_t>>;
-
- // Maps observer to transaction, which needs an id and a scope.
- using TransactionMap = HashMap<int32_t, std::pair<int64_t, Vector<int64_t>>>;
-
virtual ~WebIDBDatabaseCallbacks() = default;
virtual void OnForcedClose() = 0;
@@ -51,9 +43,6 @@ class WebIDBDatabaseCallbacks {
virtual void OnAbort(int64_t transaction_id, const IDBDatabaseError&) = 0;
virtual void OnComplete(int64_t transaction_id) = 0;
- virtual void OnChanges(const ObservationIndexMap&,
- Vector<Persistent<IDBObservation>> observations,
- const TransactionMap& transactions) = 0;
virtual void Detach() = 0;
};
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
index 41a9ffd54eb..fdb4312a56f 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_error.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
-#include "third_party/blink/renderer/modules/indexeddb/idb_observation.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -73,16 +72,6 @@ void WebIDBDatabaseCallbacksImpl::OnComplete(int64_t transaction_id) {
callbacks_->OnComplete(transaction_id);
}
-void WebIDBDatabaseCallbacksImpl::OnChanges(
- const ObservationIndexMap& observation_index_map,
- Vector<Persistent<IDBObservation>> observations,
- const TransactionMap& transactions) {
- if (callbacks_) {
- callbacks_->OnChanges(observation_index_map, std::move(observations),
- transactions);
- }
-}
-
void WebIDBDatabaseCallbacksImpl::Detach() {
callbacks_.Clear();
}
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
index 628240f084f..4b8131c4148 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h
@@ -46,9 +46,6 @@ class WebIDBDatabaseCallbacksImpl final : public WebIDBDatabaseCallbacks {
void OnVersionChange(int64_t old_version, int64_t new_version) override;
void OnAbort(int64_t transaction_id, const IDBDatabaseError&) override;
void OnComplete(int64_t transaction_id) override;
- void OnChanges(const ObservationIndexMap&,
- Vector<Persistent<IDBObservation>> observations,
- const TransactionMap& transactions) override;
void Detach() override;
private:
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
index 7d12bc609a1..d0e7e4a768c 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h"
+#include <utility>
+
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
@@ -52,24 +54,6 @@ void WebIDBDatabaseImpl::VersionChangeIgnored() {
database_->VersionChangeIgnored();
}
-void WebIDBDatabaseImpl::AddObserver(
- int64_t transaction_id,
- int32_t observer_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<blink::kIDBOperationTypeCount> operation_types) {
- static_assert(kIDBOperationTypeCount < sizeof(uint32_t) * CHAR_BIT,
- "IDBOperationTypeCount exceeds size of uint32_t");
- database_->AddObserver(transaction_id, observer_id, include_transaction,
- no_records, values,
- static_cast<uint32_t>(operation_types.to_ulong()));
-}
-
-void WebIDBDatabaseImpl::RemoveObservers(const Vector<int32_t>& observer_ids) {
- database_->RemoveObservers(observer_ids);
-}
-
void WebIDBDatabaseImpl::Get(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
index 59a36e7a38c..a0c1c0af3f0 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_DATABASE_IMPL_H_
#include <stdint.h>
+#include <memory>
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
@@ -41,15 +42,6 @@ class MODULES_EXPORT WebIDBDatabaseImpl : public WebIDBDatabase {
void Close() override;
void VersionChangeIgnored() override;
- void AddObserver(
- int64_t transaction_id,
- int32_t observer_id,
- bool include_transaction,
- bool no_records,
- bool values,
- std::bitset<kIDBOperationTypeCount> operation_types) override;
- void RemoveObservers(const Vector<int32_t>& observer_ids) override;
-
void Get(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h
index d1f23e1bf2b..0e0120e8961 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h
@@ -26,7 +26,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_TRANSACTION_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_WEB_IDB_TRANSACTION_H_
-#include <bitset>
#include <memory>
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc
index c8e62daa474..d2e44d9ad74 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl_unittest.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/BUILD.gn b/chromium/third_party/blink/renderer/modules/installedapp/BUILD.gn
index 749de147711..9eb2ce98f6a 100644
--- a/chromium/third_party/blink/renderer/modules/installedapp/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/installedapp/BUILD.gn
@@ -11,5 +11,8 @@ blink_modules_sources("installedapp") {
"navigator_installed_app.cc",
"navigator_installed_app.h",
]
- deps = [ "//third_party/blink/renderer/modules/manifest" ]
+ deps = [
+ "//services/metrics/public/cpp:ukm_builders",
+ "//third_party/blink/renderer/modules/manifest",
+ ]
}
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/DEPS b/chromium/third_party/blink/renderer/modules/installedapp/DEPS
new file mode 100644
index 00000000000..dc115d0d95b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/installedapp/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+services/metrics/public/cpp",
+] \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/DIR_METADATA b/chromium/third_party/blink/renderer/modules/installedapp/DIR_METADATA
new file mode 100644
index 00000000000..d9e960065a0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/installedapp/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform>Apps>AppLauncher>Install"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/OWNERS b/chromium/third_party/blink/renderer/modules/installedapp/OWNERS
index e3383b0300a..fffca040b69 100644
--- a/chromium/third_party/blink/renderer/modules/installedapp/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/installedapp/OWNERS
@@ -1,4 +1,2 @@
peter@chromium.org
rayankans@chromium.org
-
-# COMPONENT: Platform>Apps>AppLauncher>Install
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
index b9ec220eace..cc979093e31 100644
--- a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/manifest/manifest.h"
#include "third_party/blink/public/mojom/installedapp/related_application.mojom-blink.h"
@@ -87,7 +88,7 @@ void InstalledAppController::OnGetManifestForRelatedApps(
provider_->FilterInstalledApps(
std::move(mojo_related_apps), url,
WTF::Bind(&InstalledAppController::OnFilterInstalledApps,
- WrapPersistent(this), WTF::Passed(std::move(callbacks))));
+ WrapPersistent(this), std::move(callbacks)));
}
void InstalledAppController::OnFilterInstalledApps(
@@ -105,6 +106,12 @@ void InstalledAppController::OnFilterInstalledApps(
app->setVersion(res->version);
applications.push_back(app);
}
+
+ LocalDOMWindow* window = GetSupplementable();
+ ukm::builders::InstalledRelatedApps(window->UkmSourceID())
+ .SetCalled(true)
+ .Record(window->UkmRecorder());
+
callbacks->OnSuccess(applications);
}
diff --git a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
index 05ee0592a25..8e5238b07d5 100644
--- a/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
+++ b/chromium/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
@@ -45,8 +45,8 @@ class InstalledAppControllerTest : public testing::Test {
url_test_helpers::RegisterMockedURLLoad(
KURL("https://example.com/manifest.json"), "", "");
GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("https://example.com")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("https://example.com")),
nullptr /* extra_data */);
test::RunPendingTasks();
diff --git a/chromium/third_party/blink/renderer/modules/launch/DIR_METADATA b/chromium/third_party/blink/renderer/modules/launch/DIR_METADATA
new file mode 100644
index 00000000000..45ae75a7acc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/launch/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/launch/OWNERS b/chromium/third_party/blink/renderer/modules/launch/OWNERS
index acce5878b91..7e253a66445 100644
--- a/chromium/third_party/blink/renderer/modules/launch/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/launch/OWNERS
@@ -1,5 +1,4 @@
+cmp@chromium.org
dmurph@chromium.org
mgiuca@chromium.org
-
-# TEAM: web-apps-platform-team@chromium.org
-# COMPONENT: UI>Browser>WebAppInstalls
+msw@chromium.org
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 66877449367..fa6fa4a83f4 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,10 +5,9 @@
#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/file_system_access/file_system_handle.h"
#include "third_party/blink/renderer/modules/launch/launch_params.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"
namespace blink {
@@ -24,7 +23,7 @@ Member<LaunchQueue> DOMWindowLaunchQueue::launchQueue(LocalDOMWindow& window) {
void DOMWindowLaunchQueue::UpdateLaunchFiles(
LocalDOMWindow* window,
- HeapVector<Member<NativeFileSystemHandle>> files) {
+ HeapVector<Member<FileSystemHandle>> files) {
FromState(window)->launch_queue_->Enqueue(
MakeGarbageCollected<LaunchParams>(std::move(files)));
}
diff --git a/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h b/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
index d1337421c4c..a764f39847f 100644
--- a/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
+++ b/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/heap/handle.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/heap/visitor.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -18,7 +19,6 @@
namespace blink {
class LocalDOMWindow;
-class Visitor;
class DOMWindowLaunchQueue final
: public GarbageCollected<DOMWindowLaunchQueue>,
@@ -32,7 +32,7 @@ class DOMWindowLaunchQueue final
static Member<LaunchQueue> launchQueue(LocalDOMWindow&);
static void UpdateLaunchFiles(LocalDOMWindow*,
- HeapVector<Member<NativeFileSystemHandle>>);
+ HeapVector<Member<FileSystemHandle>>);
void Trace(Visitor*) const override;
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 a33c74dc8c9..6ff868f1d7f 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/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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 02d232563c9..7c9d1fa7649 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_params.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_params.cc
@@ -4,13 +4,12 @@
#include "third_party/blink/renderer/modules/launch/launch_params.h"
-#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
namespace blink {
-LaunchParams::LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files)
- : files_(files) {}
+LaunchParams::LaunchParams(HeapVector<Member<FileSystemHandle>> files)
+ : files_(std::move(files)) {}
LaunchParams::~LaunchParams() = default;
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 e3b60d539c3..29e8b6a6b0e 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_params.h
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_params.h
@@ -5,29 +5,28 @@
#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/file_system_access/native_file_system_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/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"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
-class Visitor;
-
class LaunchParams final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files);
+ explicit LaunchParams(HeapVector<Member<FileSystemHandle>> files);
~LaunchParams() override;
// LaunchParams IDL interface.
- const HeapVector<Member<NativeFileSystemHandle>>& files() { return files_; }
+ const HeapVector<Member<FileSystemHandle>>& files() { return files_; }
void Trace(Visitor*) const override;
private:
- HeapVector<Member<NativeFileSystemHandle>> files_;
+ HeapVector<Member<FileSystemHandle>> files_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/launch/launch_queue.cc b/chromium/third_party/blink/renderer/modules/launch/launch_queue.cc
index 20fe5975b2d..328e00c2f0d 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_queue.cc
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.h"
#include "third_party/blink/renderer/modules/launch/launch_params.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/launch/launch_queue.h b/chromium/third_party/blink/renderer/modules/launch/launch_queue.h
index 7651232b430..bd4086bff7d 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_queue.h
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_queue.h
@@ -9,11 +9,11 @@
#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"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
class V8LaunchConsumer;
-class Visitor;
class LaunchQueue final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
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 37ed2dacbe8..8bd62ab4232 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/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
@@ -33,13 +33,13 @@ WebLaunchServiceImpl::WebLaunchServiceImpl(LocalDOMWindow& window)
WebLaunchServiceImpl::~WebLaunchServiceImpl() = default;
void WebLaunchServiceImpl::SetLaunchFiles(
- WTF::Vector<mojom::blink::NativeFileSystemEntryPtr> entries) {
+ WTF::Vector<mojom::blink::FileSystemAccessEntryPtr> entries) {
if (!window_)
return;
- HeapVector<Member<NativeFileSystemHandle>> files;
+ HeapVector<Member<FileSystemHandle>> files;
for (auto& entry : entries) {
- files.push_back(NativeFileSystemHandle::CreateFromMojoEntry(
+ files.push_back(FileSystemHandle::CreateFromMojoEntry(
std::move(entry), window_->GetExecutionContext()));
}
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 7bcfbb54e50..eaa521e30db 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/file_system_access/native_file_system_directory_handle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_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"
@@ -31,7 +31,7 @@ class MODULES_EXPORT WebLaunchServiceImpl final
// blink::mojom::WebLaunchService:
void SetLaunchFiles(
- WTF::Vector<mojom::blink::NativeFileSystemEntryPtr>) override;
+ WTF::Vector<mojom::blink::FileSystemAccessEntryPtr>) override;
private:
WeakPersistent<LocalDOMWindow> window_;
diff --git a/chromium/third_party/blink/renderer/modules/locks/BUILD.gn b/chromium/third_party/blink/renderer/modules/locks/BUILD.gn
index b8af64f8fd6..74524fa8b01 100644
--- a/chromium/third_party/blink/renderer/modules/locks/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/locks/BUILD.gn
@@ -10,7 +10,5 @@ blink_modules_sources("locks") {
"lock.h",
"lock_manager.cc",
"lock_manager.h",
- "navigator_locks.cc",
- "navigator_locks.h",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/locks/DIR_METADATA b/chromium/third_party/blink/renderer/modules/locks/DIR_METADATA
new file mode 100644
index 00000000000..832447e405b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/locks/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/locks/OWNERS b/chromium/third_party/blink/renderer/modules/locks/OWNERS
index 435d42dc535..c60c1f51b18 100644
--- a/chromium/third_party/blink/renderer/modules/locks/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/locks/OWNERS
@@ -1,4 +1 @@
file://content/browser/locks/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage
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 1bd532ef979..54993e8c4d3 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -202,10 +202,23 @@ class LockManager::LockRequestImpl final
DISALLOW_COPY_AND_ASSIGN(LockRequestImpl);
};
-LockManager::LockManager(ExecutionContext* context)
- : ExecutionContextLifecycleObserver(context),
- service_(context),
- observer_(context) {}
+const char LockManager::kSupplementName[] = "LockManager";
+
+// static
+LockManager* LockManager::locks(NavigatorBase& navigator) {
+ auto* supplement = Supplement<NavigatorBase>::From<LockManager>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<LockManager>(navigator);
+ Supplement<NavigatorBase>::ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+LockManager::LockManager(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()),
+ service_(navigator.GetExecutionContext()),
+ observer_(navigator.GetExecutionContext()) {}
ScriptPromise LockManager::request(ScriptState* script_state,
const String& name,
@@ -229,7 +242,7 @@ ScriptPromise LockManager::request(ScriptState* script_state,
context->GetScheduler()->RegisterStickyFeature(
blink::SchedulingPolicy::Feature::kWebLocks,
- {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {blink::SchedulingPolicy::DisableBackForwardCache()});
// 5. If origin is an opaque origin, then reject promise with a
// "SecurityError" DOMException.
@@ -416,6 +429,7 @@ bool LockManager::IsPendingRequest(LockRequestImpl* request) {
void LockManager::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
visitor->Trace(pending_requests_);
visitor->Trace(held_locks_);
diff --git a/chromium/third_party/blink/renderer/modules/locks/lock_manager.h b/chromium/third_party/blink/renderer/modules/locks/lock_manager.h
index 8353c9ad531..94e3f15b0e7 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock_manager.h
+++ b/chromium/third_party/blink/renderer/modules/locks/lock_manager.h
@@ -17,19 +17,27 @@
#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/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
+class NavigatorBase;
class ScriptPromise;
class ScriptState;
class V8LockGrantedCallback;
class LockManager final : public ScriptWrappable,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit LockManager(ExecutionContext*);
+ static const char kSupplementName[];
+
+ // Web-exposed as navigator.locks
+ static LockManager* locks(NavigatorBase&);
+
+ explicit LockManager(NavigatorBase&);
ScriptPromise request(ScriptState*,
const String& name,
diff --git a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc
deleted file mode 100644
index 802d8829590..00000000000
--- a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/locks/navigator_locks.h"
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/locks/lock_manager.h"
-#include "third_party/blink/renderer/platform/bindings/name_client.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-namespace {
-
-template <typename T>
-class NavigatorLocksImpl final : public GarbageCollected<NavigatorLocksImpl<T>>,
- public Supplement<T>,
- public NameClient {
- public:
- static const char kSupplementName[];
-
- static NavigatorLocksImpl& From(T& navigator) {
- NavigatorLocksImpl* supplement = static_cast<NavigatorLocksImpl*>(
- Supplement<T>::template From<NavigatorLocksImpl>(navigator));
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorLocksImpl>(navigator);
- Supplement<T>::ProvideTo(navigator, supplement);
- }
- return *supplement;
- }
-
- explicit NavigatorLocksImpl(T& navigator) : Supplement<T>(navigator) {}
-
- LockManager* GetLockManager(ExecutionContext* context) const {
- if (!lock_manager_ && context) {
- lock_manager_ = MakeGarbageCollected<LockManager>(context);
- }
- return lock_manager_.Get();
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(lock_manager_);
- Supplement<T>::Trace(visitor);
- }
-
- const char* NameInHeapSnapshot() const override {
- return "NavigatorLocksImpl";
- }
-
- private:
- mutable Member<LockManager> lock_manager_;
-};
-
-// static
-template <typename T>
-const char NavigatorLocksImpl<T>::kSupplementName[] = "NavigatorLocksImpl";
-
-} // namespace
-
-LockManager* NavigatorLocks::locks(ScriptState* script_state,
- Navigator& navigator) {
- return NavigatorLocksImpl<Navigator>::From(navigator).GetLockManager(
- ExecutionContext::From(script_state));
-}
-
-LockManager* NavigatorLocks::locks(ScriptState* script_state,
- WorkerNavigator& navigator) {
- return NavigatorLocksImpl<WorkerNavigator>::From(navigator).GetLockManager(
- ExecutionContext::From(script_state));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.h b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.h
deleted file mode 100644
index 600a0fd6726..00000000000
--- a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class LockManager;
-class Navigator;
-class ScriptState;
-class WorkerNavigator;
-
-class NavigatorLocks final {
- STATIC_ONLY(NavigatorLocks);
-
- public:
- static LockManager* locks(ScriptState*, Navigator&);
- static LockManager* locks(ScriptState*, WorkerNavigator&);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_
diff --git a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.idl b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.idl
index 79d2709cc0c..87389efc5e3 100644
--- a/chromium/third_party/blink/renderer/modules/locks/navigator_locks.idl
+++ b/chromium/third_party/blink/renderer/modules/locks/navigator_locks.idl
@@ -6,7 +6,7 @@
[
SecureContext,
Exposed=Window,
- ImplementedAs=NavigatorLocks
+ ImplementedAs=LockManager
] partial interface Navigator {
- [CallWith=ScriptState] readonly attribute LockManager locks;
+ readonly attribute LockManager locks;
};
diff --git a/chromium/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl b/chromium/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl
index cbbccdf050d..4dfdd5eda88 100644
--- a/chromium/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl
+++ b/chromium/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl
@@ -6,7 +6,7 @@
[
SecureContext,
Exposed=Worker,
- ImplementedAs=NavigatorLocks
+ ImplementedAs=LockManager
] partial interface WorkerNavigator {
- [CallWith=ScriptState] readonly attribute LockManager locks;
+ readonly attribute LockManager locks;
};
diff --git a/chromium/third_party/blink/renderer/modules/manifest/OWNERS b/chromium/third_party/blink/renderer/modules/manifest/OWNERS
index 5275d5cf7ce..d745b3500cf 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/manifest/OWNERS
@@ -1,6 +1,9 @@
+cmp@chromium.org
+dmurph@chromium.org
dominickn@chromium.org
mgiuca@chromium.org
mlamouri@chromium.org
+msw@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.cc b/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.cc
index 58df39c2d5b..1fa3f766978 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -202,9 +203,17 @@ void ManifestManager::OnManifestFetchComplete(const KURL& document_url,
manifest_url_ = response.CurrentRequestUrl();
manifest_ = parser.manifest().Clone();
+ RecordMetrics(*manifest_);
ResolveCallbacks(ResolveStateSuccess);
}
+void ManifestManager::RecordMetrics(const mojom::blink::Manifest& manifest) {
+ if (manifest.capture_links != mojom::blink::CaptureLinks::kUndefined) {
+ UseCounter::Count(GetSupplementable(),
+ WebFeature::kWebAppManifestCaptureLinks);
+ }
+}
+
void ManifestManager::ResolveCallbacks(ResolveState state) {
// Do not reset |manifest_url_| on failure here. If manifest_url_ is
// non-empty, that means the link 404s, we failed to fetch it, or it was
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.h b/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.h
index 141d20d8c0c..b6931bdd2ca 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.h
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_manager.h
@@ -78,6 +78,7 @@ class MODULES_EXPORT ManifestManager
void OnManifestFetchComplete(const KURL& document_url,
const ResourceResponse& response,
const String& data);
+ void RecordMetrics(const mojom::blink::Manifest& manifest);
void ResolveCallbacks(ResolveState state);
void BindReceiver(
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 d464159b167..a14bc6bdd26 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
#include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "third_party/blink/public/common/security/protocol_handler_security_level.h"
#include "third_party/blink/public/platform/web_icon_sizes_parser.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -49,6 +50,10 @@ bool URLIsWithinScope(const KURL& url, const KURL& scope) {
url.GetPath().StartsWith(scope.GetPath());
}
+static bool IsCrLfOrTabChar(UChar c) {
+ return c == '\n' || c == '\r' || c == '\t';
+}
+
} // anonymous namespace
ManifestParser::ManifestParser(const String& data,
@@ -83,7 +88,6 @@ void ManifestParser::Parse() {
manifest_->name = ParseName(root_object.get());
manifest_->short_name = ParseShortName(root_object.get());
manifest_->description = ParseDescription(root_object.get());
- manifest_->categories = ParseCategories(root_object.get());
manifest_->start_url = ParseStartURL(root_object.get());
manifest_->scope = ParseScope(root_object.get(), manifest_->start_url);
manifest_->display = ParseDisplay(root_object.get());
@@ -116,6 +120,7 @@ void ManifestParser::Parse() {
manifest_->gcm_sender_id = ParseGCMSenderID(root_object.get());
manifest_->shortcuts = ParseShortcuts(root_object.get());
+ manifest_->capture_links = ParseCaptureLinks(root_object.get());
ManifestUmaUtil::ParseSucceeded(manifest_);
}
@@ -262,11 +267,21 @@ KURL ManifestParser::ParseURL(const JSONObject* object,
String ManifestParser::ParseName(const JSONObject* object) {
base::Optional<String> name = ParseString(object, "name", Trim);
+ if (name.has_value()) {
+ name = name->RemoveCharacters(IsCrLfOrTabChar);
+ if (name->length() == 0)
+ name = base::nullopt;
+ }
return name.has_value() ? *name : String();
}
String ManifestParser::ParseShortName(const JSONObject* object) {
base::Optional<String> short_name = ParseString(object, "short_name", Trim);
+ if (short_name.has_value()) {
+ short_name = short_name->RemoveCharacters(IsCrLfOrTabChar);
+ if (short_name->length() == 0)
+ short_name = base::nullopt;
+ }
return short_name.has_value() ? *short_name : String();
}
@@ -275,28 +290,6 @@ String ManifestParser::ParseDescription(const JSONObject* object) {
return description.has_value() ? *description : String();
}
-Vector<String> ManifestParser::ParseCategories(const JSONObject* object) {
- Vector<String> categories;
-
- JSONValue* json_value = object->Get("categories");
- if (!json_value)
- return categories;
-
- JSONArray* categories_list = object->GetArray("categories");
- if (!categories_list) {
- AddErrorInfo("property 'categories' ignored, type array expected.");
- return categories;
- }
-
- for (wtf_size_t i = 0; i < categories_list->size(); ++i) {
- String category_string;
- categories_list->at(i)->AsString(&category_string);
- categories.push_back(category_string.StripWhiteSpace().LowerASCII());
- }
-
- return categories;
-}
-
KURL ManifestParser::ParseStartURL(const JSONObject* object) {
return ParseURL(object, "start_url", manifest_url_,
ParseURLRestrictions::kSameOriginOnly);
@@ -455,12 +448,12 @@ ManifestParser::ParseIconPurpose(const JSONObject* icon) {
if (keyword.IsEmpty())
continue;
- if (!CodeUnitCompareIgnoringASCIICase(keyword, "any")) {
+ if (EqualIgnoringASCIICase(keyword, "any")) {
purposes.push_back(mojom::blink::ManifestImageResource::Purpose::ANY);
- } else if (!CodeUnitCompareIgnoringASCIICase(keyword, "monochrome")) {
+ } else if (EqualIgnoringASCIICase(keyword, "monochrome")) {
purposes.push_back(
mojom::blink::ManifestImageResource::Purpose::MONOCHROME);
- } else if (!CodeUnitCompareIgnoringASCIICase(keyword, "maskable")) {
+ } else if (EqualIgnoringASCIICase(keyword, "maskable")) {
purposes.push_back(
mojom::blink::ManifestImageResource::Purpose::MASKABLE);
} else {
@@ -1006,7 +999,8 @@ ManifestParser::ParseProtocolHandler(const JSONObject* object) {
bool is_valid_protocol = protocol.has_value();
if (is_valid_protocol &&
- !VerifyCustomHandlerScheme(protocol.value(), error_message)) {
+ !VerifyCustomHandlerScheme(protocol.value(), error_message,
+ ProtocolHandlerSecurityLevel::kStrict)) {
AddErrorInfo(error_message);
is_valid_protocol = false;
}
@@ -1212,6 +1206,52 @@ String ManifestParser::ParseGCMSenderID(const JSONObject* object) {
return gcm_sender_id.has_value() ? *gcm_sender_id : String();
}
+mojom::blink::CaptureLinks ManifestParser::ParseCaptureLinks(
+ const JSONObject* object) {
+ // Parse if either the command line flag is passed (for about:flags) or the
+ // runtime enabled feature is turned on (for origin trial).
+ if (!base::FeatureList::IsEnabled(features::kWebAppEnableLinkCapturing) &&
+ !RuntimeEnabledFeatures::WebAppLinkCapturingEnabled()) {
+ return mojom::blink::CaptureLinks::kUndefined;
+ }
+
+ String capture_links_string;
+ if (object->GetString("capture_links", &capture_links_string)) {
+ mojom::blink::CaptureLinks capture_links =
+ CaptureLinksFromString(capture_links_string.Utf8());
+ if (capture_links == mojom::blink::CaptureLinks::kUndefined) {
+ AddErrorInfo("capture_links value '" + capture_links_string +
+ "' ignored, unknown value.");
+ }
+ return capture_links;
+ }
+
+ if (JSONArray* list = object->GetArray("capture_links")) {
+ for (wtf_size_t i = 0; i < list->size(); ++i) {
+ const JSONValue* item = list->at(i);
+ if (!item->AsString(&capture_links_string)) {
+ AddErrorInfo("capture_links value '" + item->ToJSONString() +
+ "' ignored, string expected.");
+ continue;
+ }
+
+ mojom::blink::CaptureLinks capture_links =
+ CaptureLinksFromString(capture_links_string.Utf8());
+ if (capture_links != mojom::blink::CaptureLinks::kUndefined)
+ return capture_links;
+
+ AddErrorInfo("capture_links value '" + capture_links_string +
+ "' ignored, unknown value.");
+ }
+ return mojom::blink::CaptureLinks::kUndefined;
+ }
+
+ AddErrorInfo(
+ "property 'capture_links' ignored, type string or array of strings "
+ "expected.");
+ return mojom::blink::CaptureLinks::kUndefined;
+}
+
void ManifestParser::AddErrorInfo(const String& error_msg,
bool critical,
int error_line,
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.h b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.h
index 89a82d8c8b7..0b841593489 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.h
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -119,12 +119,6 @@ class MODULES_EXPORT ManifestParser {
// Returns the parsed string if any, a null string if the parsing failed.
String ParseDescription(const JSONObject* object);
- // Parses the 'categories' field of the manifest, as defined in:
- // https://w3c.github.io/manifest/#dfn-processing-the-categories-member
- // Returns a vector of the parsed strings if any, or empty if the parsing
- // failed.
- Vector<String> ParseCategories(const JSONObject* object);
-
// Parses the 'scope' field of the manifest, as defined in:
// https://w3c.github.io/manifest/#scope-member. Returns the parsed KURL if
// any, or start URL (falling back to document URL) without filename, path,
@@ -387,6 +381,11 @@ class MODULES_EXPORT ManifestParser {
// Returns the parsed string if any, a null string if the parsing failed.
String ParseGCMSenderID(const JSONObject* object);
+ // Parses the 'capture_links' field of the manifest.
+ // This specifies how navigations into the web app's scope should be captured.
+ // https://github.com/WICG/sw-launch/blob/master/declarative_link_capturing.md#proposal
+ mojom::blink::CaptureLinks ParseCaptureLinks(const JSONObject* object);
+
void AddErrorInfo(const String& error_msg,
bool critical = false,
int error_line = 0,
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 e38140ffcc6..2f23170eac2 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
@@ -169,6 +169,14 @@ TEST_F(ManifestParserTest, NameParseRules) {
EXPECT_EQ(1u, GetErrorCount());
EXPECT_EQ("property 'name' ignored, type string expected.", errors()[0]);
}
+
+ // Test stripping out of \t \r and \n.
+ {
+ auto& manifest = ParseManifest("{ \"name\": \"abc\\t\\r\\ndef\" }");
+ ASSERT_EQ(manifest->name, "abcdef");
+ ASSERT_FALSE(IsManifestEmpty(manifest));
+ EXPECT_EQ(0u, GetErrorCount());
+ }
}
TEST_F(ManifestParserTest, DescriptionParseRules) {
@@ -207,53 +215,6 @@ TEST_F(ManifestParserTest, DescriptionParseRules) {
}
}
-TEST_F(ManifestParserTest, CategoriesParseRules) {
- // Smoke test.
- {
- auto& manifest = ParseManifest(R"({ "categories": ["cats", "memes"] })");
- ASSERT_EQ(2u, manifest->categories.size());
- ASSERT_EQ(manifest->categories[0], "cats");
- ASSERT_EQ(manifest->categories[1], "memes");
- ASSERT_FALSE(IsManifestEmpty(manifest));
- EXPECT_EQ(0u, GetErrorCount());
- }
-
- // Trim whitespaces.
- {
- auto& manifest =
- ParseManifest(R"({ "categories": [" cats ", " memes "] })");
- ASSERT_EQ(2u, manifest->categories.size());
- ASSERT_EQ(manifest->categories[0], "cats");
- ASSERT_EQ(manifest->categories[1], "memes");
- EXPECT_EQ(0u, GetErrorCount());
- }
-
- // Categories should be lower-cased.
- {
- auto& manifest = ParseManifest(R"({ "categories": ["CaTs", "Memes"] })");
- ASSERT_EQ(2u, manifest->categories.size());
- ASSERT_EQ(manifest->categories[0], "cats");
- ASSERT_EQ(manifest->categories[1], "memes");
- EXPECT_EQ(0u, GetErrorCount());
- }
-
- // Empty array.
- {
- auto& manifest = ParseManifest(R"({ "categories": [] })");
- ASSERT_EQ(0u, manifest->categories.size());
- EXPECT_EQ(0u, GetErrorCount());
- }
-
- // Detect error if categories isn't an array.
- {
- auto& manifest = ParseManifest(R"({ "categories": {} })");
- ASSERT_EQ(0u, manifest->categories.size());
- ASSERT_EQ(1u, GetErrorCount());
- EXPECT_EQ("property 'categories' ignored, type array expected.",
- errors()[0]);
- }
-}
-
TEST_F(ManifestParserTest, ShortNameParseRules) {
// Smoke test.
{
@@ -287,6 +248,14 @@ TEST_F(ManifestParserTest, ShortNameParseRules) {
EXPECT_EQ("property 'short_name' ignored, type string expected.",
errors()[0]);
}
+
+ // Test stripping out of \t \r and \n.
+ {
+ auto& manifest = ParseManifest("{ \"short_name\": \"abc\\t\\r\\ndef\" }");
+ ASSERT_EQ(manifest->short_name, "abcdef");
+ ASSERT_FALSE(IsManifestEmpty(manifest));
+ EXPECT_EQ(0u, GetErrorCount());
+ }
}
TEST_F(ManifestParserTest, StartURLParseRules) {
@@ -4050,4 +4019,120 @@ TEST_F(ManifestParserTest, GCMSenderIDParseRules) {
}
}
+TEST_F(ManifestParserTest, CaptureLinksParseRules) {
+ // Feature not enabled, should not be parsed.
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": "none" })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+}
+
+class ManifestCaptureLinksParserTest : public ManifestParserTest {
+ public:
+ ManifestCaptureLinksParserTest() {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kWebAppEnableLinkCapturing);
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(ManifestCaptureLinksParserTest, CaptureLinksParseRules) {
+ // Smoke test.
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": "none" })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kNone);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": ["new-client"] })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kNewClient);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Empty array is fine.
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": [] })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+
+ // Unknown single string.
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": "unknown" })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("capture_links value 'unknown' ignored, unknown value.",
+ errors()[0]);
+ }
+
+ // First known value in array is used.
+ {
+ auto& manifest = ParseManifest(
+ R"({ "capture_links": ["none", "existing-client-navigate"] })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kNone);
+ EXPECT_EQ(0u, GetErrorCount());
+ }
+ {
+ auto& manifest = ParseManifest(R"({
+ "capture_links": [
+ "unknown",
+ "existing-client-navigate",
+ "also-unknown",
+ "none"
+ ]
+ })");
+ EXPECT_EQ(manifest->capture_links,
+ mojom::blink::CaptureLinks::kExistingClientNavigate);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("capture_links value 'unknown' ignored, unknown value.",
+ errors()[0]);
+ }
+ {
+ auto& manifest = ParseManifest(R"({
+ "capture_links": [
+ 1234,
+ "new-client",
+ null,
+ "none"
+ ]
+ })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kNewClient);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ("capture_links value '1234' ignored, string expected.",
+ errors()[0]);
+ }
+
+ // Don't parse if the property isn't a string or array of strings.
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": null })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "property 'capture_links' ignored, type string or array of strings "
+ "expected.",
+ errors()[0]);
+ }
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": 1234 })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(1u, GetErrorCount());
+ EXPECT_EQ(
+ "property 'capture_links' ignored, type string or array of strings "
+ "expected.",
+ errors()[0]);
+ }
+ {
+ auto& manifest = ParseManifest(R"({ "capture_links": [12, 34] })");
+ EXPECT_EQ(manifest->capture_links, mojom::blink::CaptureLinks::kUndefined);
+ EXPECT_EQ(2u, GetErrorCount());
+ EXPECT_EQ("capture_links value '12' ignored, string expected.",
+ errors()[0]);
+ EXPECT_EQ("capture_links value '34' ignored, string expected.",
+ errors()[1]);
+ }
+}
+
} // namespace blink
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 73d7d9f42c8..6442377dccc 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
@@ -79,6 +79,8 @@ TypeConverter<blink::Manifest, blink::mojom::blink::ManifestPtr>::Convert(
if (!input->scope.IsEmpty())
output.scope = input->scope;
+ output.capture_links = input->capture_links;
+
return output;
}
@@ -96,15 +98,8 @@ TypeConverter<blink::Manifest::ImageResource,
for (auto& size : input->sizes)
output.sizes.push_back(gfx::Size(size));
- for (auto purpose : input->purpose) {
- blink::mojom::ManifestImageResource_Purpose out_purpose;
- if (!EnumTraits<blink::mojom::ManifestImageResource_Purpose,
- ::blink::mojom::ManifestImageResource_Purpose>::
- FromMojom(purpose, &out_purpose)) {
- NOTREACHED();
- }
- output.purpose.push_back(out_purpose);
- }
+ for (auto purpose : input->purpose)
+ output.purpose.push_back(purpose);
return output;
}
diff --git a/chromium/third_party/blink/renderer/modules/media/DIR_METADATA b/chromium/third_party/blink/renderer/modules/media/DIR_METADATA
new file mode 100644
index 00000000000..0198eda079e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Media"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/media/OWNERS b/chromium/third_party/blink/renderer/modules/media/OWNERS
index 6b9bd7f913b..c841df28163 100644
--- a/chromium/third_party/blink/renderer/modules/media/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/media/OWNERS
@@ -1,11 +1,9 @@
file://media/OWNERS
-miu@chromium.org
mfoltz@chromium.org
+jophba@chromium.org
# WebRTC OWNERS.
hbos@chromium.org
tommi@chromium.org
guidou@chromium.org
olka@chromium.org
-
-# COMPONENT: Internals>Media
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
index fe3a7388fba..a58d78811b6 100644
--- 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
@@ -40,7 +40,7 @@ namespace blink {
//
// There should only be one instance of AudioRendererMixerManager per render
// thread.
-class BLINK_MODULES_EXPORT AudioRendererMixerManager
+class BLINK_MODULES_EXPORT AudioRendererMixerManager final
: public media::AudioRendererMixerPool {
public:
~AudioRendererMixerManager() final;
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
index 0d3e265a099..a29c0fe37ec 100644
--- 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
@@ -39,7 +39,7 @@ class AudioRendererSinkCache::WindowObserver final
explicit WindowObserver(LocalDOMWindow& window)
: Supplement<LocalDOMWindow>(window),
ExecutionContextLifecycleObserver(&window) {}
- ~WindowObserver() = default;
+ ~WindowObserver() override = default;
void Trace(Visitor* visitor) const final {
Supplement<LocalDOMWindow>::Trace(visitor);
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
index 13dda84ccc1..a6b703662ba 100644
--- 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
@@ -34,7 +34,7 @@ WebAudioDeviceFactory* WebAudioDeviceFactory::factory_ = nullptr;
namespace {
#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
- BUILDFLAG(IS_LACROS)
+ BUILDFLAG(IS_CHROMEOS_LACROS)
// 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
diff --git a/chromium/third_party/blink/renderer/modules/media/webmediaplayer_util_unittest.cc b/chromium/third_party/blink/renderer/modules/media/webmediaplayer_util_unittest.cc
index b09746fcded..560f2f50ac6 100644
--- a/chromium/third_party/blink/renderer/modules/media/webmediaplayer_util_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/media/webmediaplayer_util_unittest.cc
@@ -17,22 +17,22 @@ TEST(GetMediaURLScheme, MissingUnknown) {
TEST(GetMediaURLScheme, WebCommon) {
EXPECT_EQ(media::mojom::MediaURLScheme::kFtp,
- GetMediaURLScheme(KURL("ftp://abc.123")));
+ GetMediaURLScheme(KURL("ftp://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kHttp,
- GetMediaURLScheme(KURL("http://abc.123")));
+ GetMediaURLScheme(KURL("http://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kHttps,
- GetMediaURLScheme(KURL("https://abc.123")));
+ GetMediaURLScheme(KURL("https://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kData,
- GetMediaURLScheme(KURL("data://abc.123")));
+ GetMediaURLScheme(KURL("data://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kBlob,
- GetMediaURLScheme(KURL("blob://abc.123")));
+ GetMediaURLScheme(KURL("blob://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kJavascript,
- GetMediaURLScheme(KURL("javascript://abc.123")));
+ GetMediaURLScheme(KURL("javascript://abc.test")));
}
TEST(GetMediaURLScheme, Files) {
EXPECT_EQ(media::mojom::MediaURLScheme::kFile,
- GetMediaURLScheme(KURL("file://abc.123")));
+ GetMediaURLScheme(KURL("file://abc.test")));
EXPECT_EQ(media::mojom::MediaURLScheme::kFileSystem,
GetMediaURLScheme(KURL("filesystem:file://abc/123")));
}
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 958d37191eb..4af36e9fbc5 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
@@ -12,10 +12,6 @@ blink_modules_sources("media_capabilities") {
"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",
- "worker_navigator_media_capabilities.h",
]
deps = [
"//media",
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/DEPS b/chromium/third_party/blink/renderer/modules/media_capabilities/DEPS
index 785ddbfea09..9d0754de6a9 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/DEPS
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/DEPS
@@ -8,7 +8,6 @@ include_rules = [
"+media/mojo/mojom/video_decode_perf_history.mojom-blink.h",
"+media/mojo/mojom/media_metrics_provider.mojom-blink.h",
"+media/video/gpu_video_accelerator_factories.h",
- "+media/video/supported_video_decoder_config.h",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/encryptedmedia",
"+third_party/blink/renderer/modules/media_capabilities",
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA b/chromium/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA
new file mode 100644
index 00000000000..9d49970e664
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>Capabilities"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/OWNERS b/chromium/third_party/blink/renderer/modules/media_capabilities/OWNERS
index b41429325fa..2d282460822 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/OWNERS
@@ -1,4 +1 @@
mlamouri@chromium.org
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media>Capabilities
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 5b1db2b0717..64b2b618d07 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
@@ -16,6 +16,7 @@
#include "media/base/media_util.h"
#include "media/base/mime_util.h"
#include "media/base/supported_types.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_decoder_config.h"
#include "media/filters/stream_parser_factory.h"
#include "media/learning/common/media_learning_tasks.h"
@@ -24,7 +25,6 @@
#include "media/mojo/mojom/media_metrics_provider.mojom-blink.h"
#include "media/mojo/mojom/media_types.mojom-blink.h"
#include "media/video/gpu_video_accelerator_factories.h"
-#include "media/video/supported_video_decoder_config.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/web_feature/web_feature.mojom-blink.h"
@@ -46,6 +46,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_key_system_media_capability.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/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -614,10 +615,25 @@ const char MediaCapabilities::kLearningBadWindowThresholdParamName[] =
const char MediaCapabilities::kLearningNnrThresholdParamName[] =
"nnr_threshold";
-MediaCapabilities::MediaCapabilities(ExecutionContext* context)
- : decode_history_service_(context),
- bad_window_predictor_(context),
- nnr_predictor_(context) {}
+// static
+const char MediaCapabilities::kSupplementName[] = "MediaCapabilities";
+
+MediaCapabilities* MediaCapabilities::mediaCapabilities(
+ NavigatorBase& navigator) {
+ MediaCapabilities* supplement =
+ Supplement<NavigatorBase>::From<MediaCapabilities>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<MediaCapabilities>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+MediaCapabilities::MediaCapabilities(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ decode_history_service_(navigator.GetExecutionContext()),
+ bad_window_predictor_(navigator.GetExecutionContext()),
+ nnr_predictor_(navigator.GetExecutionContext()) {}
void MediaCapabilities::Trace(blink::Visitor* visitor) const {
visitor->Trace(decode_history_service_);
@@ -625,6 +641,7 @@ void MediaCapabilities::Trace(blink::Visitor* visitor) const {
visitor->Trace(nnr_predictor_);
visitor->Trace(pending_cb_map_);
ScriptWrappable::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
}
MediaCapabilities::PendingCallbackState::PendingCallbackState(
@@ -1223,25 +1240,9 @@ void MediaCapabilities::GetGpuFactoriesSupport(
gfx::Rect(natural_size) /* visible_rect */, natural_size,
media::EmptyExtraData(), encryption_scheme);
- static_assert(media::VideoDecoderImplementation::kAlternate ==
- media::VideoDecoderImplementation::kMaxValue,
- "Keep the array below in sync.");
- media::VideoDecoderImplementation decoder_impls[] = {
- media::VideoDecoderImplementation::kDefault,
- media::VideoDecoderImplementation::kAlternate};
- media::GpuVideoAcceleratorFactories::Supported supported =
- media::GpuVideoAcceleratorFactories::Supported::kUnknown;
- for (const auto& impl : decoder_impls) {
- supported = gpu_factories->IsDecoderConfigSupported(impl, config);
- DCHECK_NE(supported,
- media::GpuVideoAcceleratorFactories::Supported::kUnknown);
- if (supported == media::GpuVideoAcceleratorFactories::Supported::kTrue)
- break;
- }
-
OnGpuFactoriesSupport(
- callback_id,
- supported == media::GpuVideoAcceleratorFactories::Supported::kTrue);
+ callback_id, gpu_factories->IsDecoderConfigSupported(config) ==
+ media::GpuVideoAcceleratorFactories::Supported::kTrue);
}
void MediaCapabilities::ResolveCallbackIfReady(int 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 7ed2617a749..833c89968a7 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
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/platform/heap/visitor.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"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
@@ -25,18 +26,26 @@ class ExecutionContext;
class MediaDecodingConfiguration;
class MediaEncodingConfiguration;
class MediaKeySystemAccess;
+class NavigatorBase;
class ScriptPromise;
class ScriptPromiseResolver;
class ScriptState;
-class MODULES_EXPORT MediaCapabilities final : public ScriptWrappable {
+class MODULES_EXPORT MediaCapabilities final
+ : public ScriptWrappable,
+ public Supplement<NavigatorBase> {
DEFINE_WRAPPERTYPEINFO();
public:
static const char kLearningBadWindowThresholdParamName[];
static const char kLearningNnrThresholdParamName[];
- explicit MediaCapabilities(ExecutionContext* context);
+ static const char kSupplementName[];
+
+ // Getter for navigator.mediaCapabilities
+ static MediaCapabilities* mediaCapabilities(NavigatorBase&);
+
+ explicit MediaCapabilities(NavigatorBase&);
void Trace(blink::Visitor* visitor) const override;
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_fuzzer.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_fuzzer.cc
index 922880c3e90..0e4019b3df5 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_fuzzer.cc
@@ -8,7 +8,9 @@
#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_key_system_configuration.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_decoding_configuration.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/core/frame/settings.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/modules/media_capabilities/fuzzer_media_configuration.pb.h"
@@ -142,8 +144,8 @@ DEFINE_TEXT_PROTO_FUZZER(const mc_fuzzer::MediaDecodingConfigProto& proto) {
ToScriptStateForMainWorld(&page_holder->GetFrame());
ScriptState::Scope scope(script_state);
- auto* media_capabilities = MakeGarbageCollected<MediaCapabilities>(
- ExecutionContext::From(script_state));
+ auto* media_capabilities = MediaCapabilities::mediaCapabilities(
+ *page_holder->GetFrame().DomWindow()->navigator());
media_capabilities->decodingInfo(script_state, config,
IGNORE_EXCEPTION_FOR_TESTING);
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
index e98b19c3c88..b7ac9a632b7 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
@@ -27,6 +27,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/web_size.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.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/bindings/modules/v8/v8_audio_configuration.h"
@@ -34,6 +35,8 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_configuration.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_decoding_configuration.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_configuration.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -172,7 +175,8 @@ class FakeMediaMetricsProvider
FAIL();
}
void Initialize(bool is_mse,
- media::mojom::MediaURLScheme url_scheme) override {}
+ media::mojom::MediaURLScheme url_scheme,
+ media::mojom::MediaStreamType media_stream_type) override {}
void OnError(media::mojom::PipelineStatus status) override {}
void SetIsEME() override {}
void SetTimeToMetadata(base::TimeDelta elapsed) override {}
@@ -185,9 +189,9 @@ class FakeMediaMetricsProvider
void SetHasAudio(media::mojom::AudioCodec audio_codec) override {}
void SetHasVideo(media::mojom::VideoCodec video_codec) override {}
void SetVideoPipelineInfo(
- media::mojom::blink::PipelineDecoderInfoPtr info) override {}
+ media::mojom::blink::VideoDecoderInfoPtr info) override {}
void SetAudioPipelineInfo(
- media::mojom::blink::PipelineDecoderInfoPtr info) override {}
+ media::mojom::blink::AudioDecoderInfoPtr info) override {}
private:
mojo::Receiver<media::mojom::blink::MediaMetricsProvider> receiver_{this};
@@ -286,8 +290,8 @@ class MediaCapabilitiesTestContext {
&MockPerfHistoryService::BindRequest,
base::Unretained(perf_history_service_.get()))));
- media_capabilities_ = MakeGarbageCollected<MediaCapabilities>(
- v8_scope_.GetExecutionContext());
+ media_capabilities_ = MediaCapabilities::mediaCapabilities(
+ *v8_scope_.GetWindow().navigator());
}
~MediaCapabilitiesTestContext() {
@@ -630,8 +634,13 @@ TEST(MediaCapabilitiesTests, PredictPowerEfficientWithGpuFactories) {
.WillOnce(Return(false));
EXPECT_CALL(*mock_gpu_factories, NotifyDecoderSupportKnown(_))
.WillOnce(GpuFactoriesNotifyCallback());
+
+ // MediaCapabilities calls IsDecoderSupportKnown() once, and
+ // GpuVideoAcceleratorFactories::IsDecoderConfigSupported() also calls it
+ // once internally.
EXPECT_CALL(*mock_gpu_factories, IsDecoderSupportKnown())
- .WillOnce(Return(true));
+ .Times(2)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(*mock_gpu_factories, IsDecoderConfigSupported(_, _))
.WillOnce(
Return(media::GpuVideoAcceleratorFactories::Supported::kTrue));
@@ -651,7 +660,8 @@ TEST(MediaCapabilitiesTests, PredictPowerEfficientWithGpuFactories) {
.WillOnce(DbCallback(kFeatures, /*smooth*/ false, /*power_eff*/ true));
EXPECT_CALL(context.GetMockPlatform(), GetGpuFactories());
EXPECT_CALL(*mock_gpu_factories, IsDecoderSupportKnown())
- .WillOnce(Return(true));
+ .Times(2)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(*mock_gpu_factories, IsDecoderConfigSupported(_, _))
.WillRepeatedly(
Return(media::GpuVideoAcceleratorFactories::Supported::kFalse));
@@ -923,8 +933,12 @@ void RunCallbackPermutationTest(std::vector<PredictionType> callback_order) {
EXPECT_CALL(*mock_gpu_factories, NotifyDecoderSupportKnown(_))
.WillOnce(
Invoke(&cb_saver, &CallbackSaver::SaveGpuFactoriesNotifyCallback));
+ // MediaCapabilities calls IsDecoderSupportKnown() once, and
+ // GpuVideoAcceleratorFactories::IsDecoderConfigSupported() also calls it
+ // once internally.
EXPECT_CALL(*mock_gpu_factories, IsDecoderSupportKnown())
- .WillOnce(Return(true));
+ .Times(2)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(*mock_gpu_factories, IsDecoderConfigSupported(_, _))
.WillRepeatedly(
Return(media::GpuVideoAcceleratorFactories::Supported::kFalse));
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.cc
deleted file mode 100644
index 8da97e2a083..00000000000
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-// static
-const char NavigatorMediaCapabilities::kSupplementName[] =
- "NavigatorMediaCapabilities";
-
-MediaCapabilities* NavigatorMediaCapabilities::mediaCapabilities(
- Navigator& navigator) {
- NavigatorMediaCapabilities& self =
- NavigatorMediaCapabilities::From(navigator);
- if (!self.capabilities_) {
- self.capabilities_ =
- MakeGarbageCollected<MediaCapabilities>(navigator.DomWindow());
- }
- return self.capabilities_.Get();
-}
-
-void NavigatorMediaCapabilities::Trace(Visitor* visitor) const {
- visitor->Trace(capabilities_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-NavigatorMediaCapabilities::NavigatorMediaCapabilities(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
-
-NavigatorMediaCapabilities& NavigatorMediaCapabilities::From(
- Navigator& navigator) {
- NavigatorMediaCapabilities* supplement =
- Supplement<Navigator>::From<NavigatorMediaCapabilities>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorMediaCapabilities>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.h b/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.h
deleted file mode 100644
index b401f2f6a98..00000000000
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_NAVIGATOR_MEDIA_CAPABILITIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_NAVIGATOR_MEDIA_CAPABILITIES_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class MediaCapabilities;
-class Navigator;
-
-// Provides MediaCapabilities as a supplement of Navigator as an attribute.
-class NavigatorMediaCapabilities final
- : public GarbageCollected<NavigatorMediaCapabilities>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static MediaCapabilities* mediaCapabilities(Navigator&);
-
- explicit NavigatorMediaCapabilities(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- static NavigatorMediaCapabilities& From(Navigator&);
-
- // The MediaCapabilities instance of this Navigator.
- Member<MediaCapabilities> capabilities_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_NAVIGATOR_MEDIA_CAPABILITIES_H_
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.idl b/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.idl
index 6b00ca4c65d..75513498b46 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.idl
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/navigator_media_capabilities.idl
@@ -6,7 +6,7 @@
[
Exposed=Window,
- ImplementedAs=NavigatorMediaCapabilities
+ ImplementedAs=MediaCapabilities
] partial interface Navigator {
[SameObject] readonly attribute MediaCapabilities mediaCapabilities;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.cc
deleted file mode 100644
index 013672b91a6..00000000000
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.cc
+++ /dev/null
@@ -1,50 +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/media_capabilities/worker_navigator_media_capabilities.h"
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-// static
-const char WorkerNavigatorMediaCapabilities::kSupplementName[] =
- "WorkerNavigatorMediaCapabilities";
-
-MediaCapabilities* WorkerNavigatorMediaCapabilities::mediaCapabilities(
- WorkerNavigator& navigator) {
- WorkerNavigatorMediaCapabilities& self =
- WorkerNavigatorMediaCapabilities::From(navigator);
- if (!self.capabilities_) {
- self.capabilities_ = MakeGarbageCollected<MediaCapabilities>(
- navigator.GetExecutionContext());
- }
- return self.capabilities_.Get();
-}
-
-void WorkerNavigatorMediaCapabilities::Trace(Visitor* visitor) const {
- visitor->Trace(capabilities_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-WorkerNavigatorMediaCapabilities::WorkerNavigatorMediaCapabilities(
- WorkerNavigator& navigator)
- : Supplement<WorkerNavigator>(navigator) {}
-
-WorkerNavigatorMediaCapabilities& WorkerNavigatorMediaCapabilities::From(
- WorkerNavigator& navigator) {
- WorkerNavigatorMediaCapabilities* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorMediaCapabilities>(
- navigator);
- if (!supplement) {
- supplement =
- MakeGarbageCollected<WorkerNavigatorMediaCapabilities>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.h b/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.h
deleted file mode 100644
index c0957eee58a..00000000000
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.h
+++ /dev/null
@@ -1,39 +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_MEDIA_CAPABILITIES_WORKER_NAVIGATOR_MEDIA_CAPABILITIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_WORKER_NAVIGATOR_MEDIA_CAPABILITIES_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class MediaCapabilities;
-class WorkerNavigator;
-
-// Provides MediaCapabilities as a supplement of WorkerNavigator as an
-// attribute.
-class WorkerNavigatorMediaCapabilities final
- : public GarbageCollected<WorkerNavigatorMediaCapabilities>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static MediaCapabilities* mediaCapabilities(WorkerNavigator&);
-
- explicit WorkerNavigatorMediaCapabilities(WorkerNavigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- static WorkerNavigatorMediaCapabilities& From(WorkerNavigator&);
-
- // The MediaCapabilities instance of this WorkerNavigator.
- Member<MediaCapabilities> capabilities_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_WORKER_NAVIGATOR_MEDIA_CAPABILITIES_H_
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.idl b/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.idl
index c942782a194..a096c88407a 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.idl
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/worker_navigator_media_capabilities.idl
@@ -6,7 +6,7 @@
[
Exposed=Worker,
- ImplementedAs=WorkerNavigatorMediaCapabilities
+ ImplementedAs=MediaCapabilities
] partial interface WorkerNavigator {
[SameObject] readonly attribute MediaCapabilities mediaCapabilities;
};
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/DIR_METADATA b/chromium/third_party/blink/renderer/modules/media_controls/DIR_METADATA
new file mode 100644
index 00000000000..bac1ed98e03
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_controls/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>Controls"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/OWNERS b/chromium/third_party/blink/renderer/modules/media_controls/OWNERS
index e54edd1a822..b7dd2c37f84 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/media_controls/OWNERS
@@ -1,6 +1,2 @@
-beccahughes@chromium.org
mlamouri@chromium.org
steimel@chromium.org
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media>Controls
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
index 792534a60e0..ba637084a09 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
+#include "third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
@@ -99,6 +100,8 @@ void MediaControlCastButtonElement::DefaultEventHandler(Event& event) {
}
RemotePlayback::From(MediaElement()).PromptInternal();
+ RemotePlaybackMetrics::RecordRemotePlaybackLocation(
+ RemotePlaybackInitiationLocation::HTML_MEDIA_ELEMENT);
}
MediaControlInputElement::DefaultEventHandler(event);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
index 3f0ddf2c58e..1cca200e8e9 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc
@@ -129,12 +129,10 @@ TEST_F(MediaControlDisplayCutoutFullscreenButtonElementTest,
EXPECT_EQ(mojom::ViewportFit::kAuto, CurrentViewportFit());
- display_cutout_fullscreen_button_->DispatchSimulatedClick(
- nullptr, kSendNoEvents, SimulatedClickCreationScope::kFromUserAgent);
+ display_cutout_fullscreen_button_->DispatchSimulatedClick(nullptr);
EXPECT_EQ(mojom::ViewportFit::kCoverForcedByUserAgent, CurrentViewportFit());
- display_cutout_fullscreen_button_->DispatchSimulatedClick(
- nullptr, kSendNoEvents, SimulatedClickCreationScope::kFromUserAgent);
+ display_cutout_fullscreen_button_->DispatchSimulatedClick(nullptr);
EXPECT_EQ(mojom::ViewportFit::kAuto, CurrentViewportFit());
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
index 08be2656f69..006e0cb7601 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element_test.cc
@@ -171,7 +171,7 @@ TEST_F(MediaControlInputElementTest, ClickRecordsInteraction) {
ControlInputElement().MaybeRecordDisplayed();
ControlInputElement().DispatchSimulatedClick(
- Event::CreateBubble(event_type_names::kClick), kSendNoEvents);
+ Event::CreateBubble(event_type_names::kClick));
histogram_tester_.ExpectTotalCount(kControlInputElementHistogramName, 2);
histogram_tester_.ExpectBucketCount(kControlInputElementHistogramName, 0, 1);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 4869190f90e..708b73ca614 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -2130,6 +2130,9 @@ HTMLVideoElement& MediaControlsImpl::VideoElement() {
void MediaControlsImpl::Trace(Visitor* visitor) const {
visitor->Trace(element_mutation_callback_);
+ visitor->Trace(element_size_changed_timer_);
+ visitor->Trace(tap_timer_);
+ visitor->Trace(volume_slider_wanted_timer_);
visitor->Trace(resize_observer_);
visitor->Trace(panel_);
visitor->Trace(overlay_play_button_);
@@ -2156,6 +2159,7 @@ void MediaControlsImpl::Trace(Visitor* visitor) const {
visitor->Trace(orientation_lock_delegate_);
visitor->Trace(rotate_to_fullscreen_delegate_);
visitor->Trace(display_cutout_delegate_);
+ visitor->Trace(hide_media_controls_timer_);
visitor->Trace(media_button_panel_);
visitor->Trace(loading_panel_);
visitor->Trace(display_cutout_fullscreen_button_);
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
index 72d57e76609..42bd5e4588d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -387,7 +387,7 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
rotate_to_fullscreen_delegate_;
Member<MediaControlsDisplayCutoutDelegate> display_cutout_delegate_;
- TaskRunnerTimer<MediaControlsImpl> hide_media_controls_timer_;
+ HeapTaskRunnerTimer<MediaControlsImpl> hide_media_controls_timer_;
unsigned hide_timer_behavior_flags_;
bool is_mouse_over_controls_ : 1;
bool is_paused_for_scrubbing_ : 1;
@@ -401,7 +401,7 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
// as necessary.
Member<MediaElementMutationCallback> element_mutation_callback_;
- TaskRunnerTimer<MediaControlsImpl> element_size_changed_timer_;
+ HeapTaskRunnerTimer<MediaControlsImpl> element_size_changed_timer_;
IntSize size_;
bool keep_showing_until_timer_fires_ : 1;
@@ -415,12 +415,12 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
bool is_touch_interaction_ = false;
// Timer for distinguishing double-taps.
- TaskRunnerTimer<MediaControlsImpl> tap_timer_;
+ HeapTaskRunnerTimer<MediaControlsImpl> tap_timer_;
bool is_paused_for_double_tap_ = false;
// Timer to delay showing the volume slider to avoid accidental triggering
// of the slider
- TaskRunnerTimer<MediaControlsImpl> volume_slider_wanted_timer_;
+ HeapTaskRunnerTimer<MediaControlsImpl> volume_slider_wanted_timer_;
Member<MediaControlsTextTrackManager> text_track_manager_;
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 23acf9e640f..987a0931823 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
@@ -67,13 +67,18 @@ namespace {
class FakeChromeClient : public EmptyChromeClient {
public:
+ FakeChromeClient()
+ : screen_info_({.orientation_type =
+ mojom::blink::ScreenOrientation::kLandscapePrimary}) {
+ }
+
// ChromeClient overrides.
- ScreenInfo GetScreenInfo(LocalFrame&) const override {
- ScreenInfo screen_info;
- screen_info.orientation_type =
- mojom::blink::ScreenOrientation::kLandscapePrimary;
- return screen_info;
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return screen_info_;
}
+
+ private:
+ const ScreenInfo screen_info_;
};
class MockWebMediaPlayerForImpl : public EmptyWebMediaPlayer {
@@ -268,8 +273,7 @@ class MediaControlsImplTest : public PageTestBase,
void ClickOverflowButton() {
MediaControls()
.download_button_->OverflowElementForTests()
- ->DispatchSimulatedClick(nullptr, kSendNoEvents,
- SimulatedClickCreationScope::kFromUserAgent);
+ ->DispatchSimulatedClick(nullptr);
}
void SetReady() {
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 cd37ccb5eda..ffe580ac3b9 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
@@ -39,8 +39,6 @@
#include "ui/gfx/geometry/rect.h"
using testing::_;
-using testing::AtLeast;
-using testing::Return;
namespace blink {
@@ -57,9 +55,16 @@ class DummyScreenOrientationCallback final : public WebLockOrientationCallback {
class MockWebMediaPlayerForOrientationLockDelegate final
: public EmptyWebMediaPlayer {
public:
+ ~MockWebMediaPlayerForOrientationLockDelegate() override = default;
+
+ // EmptyWebMediaPlayer overrides:
bool HasVideo() const override { return true; }
+ gfx::Size NaturalSize() const override { return mock_natural_size_; }
+
+ gfx::Size& MockNaturalSize() { return mock_natural_size_; }
- MOCK_CONST_METHOD0(NaturalSize, gfx::Size());
+ private:
+ gfx::Size mock_natural_size_ = {};
};
class MockScreenOrientation final
@@ -74,6 +79,7 @@ class MockScreenOrientation final
SCREEN_ORIENTATION_LOCK_RESULT_SUCCESS);
LockOrientation(type);
}
+ MOCK_METHOD(void, UnlockOrientation, (), (override));
void BindPendingReceiver(
mojo::PendingAssociatedReceiver<device::mojom::blink::ScreenOrientation>
@@ -83,9 +89,9 @@ class MockScreenOrientation final
void Close() { receiver_.reset(); }
- MOCK_METHOD0(UnlockOrientation, void());
-
- MOCK_METHOD1(LockOrientation, void(device::mojom::ScreenOrientationLockType));
+ MOCK_METHOD(void,
+ LockOrientation,
+ (device::mojom::ScreenOrientationLockType));
private:
mojo::AssociatedReceiver<device::mojom::blink::ScreenOrientation> receiver_{
@@ -133,7 +139,11 @@ class MockChromeClientForOrientationLockDelegate final
WTF::Bind(DidExitFullscreen, WrapPersistent(frame.GetDocument())));
}
- MOCK_CONST_METHOD1(GetScreenInfo, ScreenInfo(LocalFrame&));
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return mock_screen_info_;
+ }
+
+ ScreenInfo& MockScreenInfo() { return mock_screen_info_; }
MockScreenOrientation& ScreenOrientationClient() {
return mock_screen_orientation_;
@@ -141,6 +151,7 @@ class MockChromeClientForOrientationLockDelegate final
private:
MockScreenOrientation mock_screen_orientation_;
+ ScreenInfo mock_screen_info_ = {};
};
class StubLocalFrameClientForOrientationLockDelegate final
@@ -165,7 +176,8 @@ class MediaControlsOrientationLockDelegateTest
: ScopedVideoFullscreenOrientationLockForTest(true),
ScopedVideoRotateToFullscreenForTest(false) {}
- MediaControlsOrientationLockDelegateTest(bool video_rotate_to_fullscreen)
+ explicit MediaControlsOrientationLockDelegateTest(
+ bool video_rotate_to_fullscreen)
: ScopedVideoFullscreenOrientationLockForTest(true),
ScopedVideoRotateToFullscreenForTest(video_rotate_to_fullscreen) {}
@@ -280,12 +292,14 @@ class MediaControlsOrientationLockDelegateTest
Video().GetWebMediaPlayer());
}
+ protected:
+ Persistent<MockChromeClientForOrientationLockDelegate> chrome_client_;
+
private:
friend class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest;
bool previous_orientation_event_value_;
Persistent<HTMLVideoElement> video_;
- Persistent<MockChromeClientForOrientationLockDelegate> chrome_client_;
};
class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
@@ -366,18 +380,14 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
// Calls must be wrapped in ASSERT_NO_FATAL_FAILURE.
void RotateScreenTo(mojom::blink::ScreenOrientation screen_orientation_type,
uint16_t screen_orientation_angle) {
- ScreenInfo screen_info;
- screen_info.orientation_type = screen_orientation_type;
- screen_info.orientation_angle = screen_orientation_angle;
- screen_info.rect = ScreenRectFromAngle(screen_orientation_angle);
- ASSERT_TRUE(screen_info.orientation_type ==
+ ScreenInfo new_screen_info;
+ new_screen_info.orientation_type = screen_orientation_type;
+ new_screen_info.orientation_angle = screen_orientation_angle;
+ new_screen_info.rect = ScreenRectFromAngle(screen_orientation_angle);
+ ASSERT_TRUE(new_screen_info.orientation_type ==
ScreenOrientationController::ComputeOrientation(
- screen_info.rect, screen_info.orientation_angle));
-
- testing::Mock::VerifyAndClearExpectations(&ChromeClient());
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(AtLeast(1))
- .WillRepeatedly(Return(screen_info));
+ new_screen_info.rect, new_screen_info.orientation_angle));
+ ChromeClient().MockScreenInfo() = new_screen_info;
// Screen Orientation API
ScreenOrientationController::From(*GetDocument().domWindow())
@@ -397,8 +407,8 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest
SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
// Set video size.
- EXPECT_CALL(MockWebMediaPlayer(), NaturalSize())
- .WillRepeatedly(Return(gfx::Size(video_width, video_height)));
+ MockWebMediaPlayer().MockNaturalSize() =
+ gfx::Size(video_width, video_height);
// Dispatch an arbitrary Device Orientation event to satisfy
// MediaControlsRotateToFullscreenDelegate's requirement that the device
@@ -572,60 +582,40 @@ TEST_F(MediaControlsOrientationLockDelegateTest, ComputeOrientationLock) {
SimulateVideoNetworkState(HTMLMediaElement::kNetworkIdle);
SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
- EXPECT_CALL(MockWebMediaPlayer(), NaturalSize())
- .Times(14) // Each `computeOrientationLock` calls the method twice.
- .WillOnce(Return(gfx::Size(100, 50)))
- .WillOnce(Return(gfx::Size(100, 50)))
- .WillOnce(Return(gfx::Size(50, 100)))
- .WillOnce(Return(gfx::Size(50, 100)))
- .WillRepeatedly(Return(gfx::Size(100, 100)));
-
// 100x50
+ MockWebMediaPlayer().MockNaturalSize() = gfx::Size(100, 50);
EXPECT_EQ(device::mojom::ScreenOrientationLockType::LANDSCAPE,
ComputeOrientationLock());
// 50x100
+ MockWebMediaPlayer().MockNaturalSize() = gfx::Size(50, 100);
EXPECT_EQ(device::mojom::ScreenOrientationLockType::PORTRAIT,
ComputeOrientationLock());
// 100x100 has more subtilities, it depends on the current screen orientation.
- ScreenInfo screen_info;
- screen_info.orientation_type = mojom::blink::ScreenOrientation::kUndefined;
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(1)
- .WillOnce(Return(screen_info));
+ MockWebMediaPlayer().MockNaturalSize() = gfx::Size(100, 100);
+ ChromeClient().MockScreenInfo().orientation_type =
+ mojom::blink::ScreenOrientation::kUndefined;
EXPECT_EQ(device::mojom::ScreenOrientationLockType::LANDSCAPE,
ComputeOrientationLock());
- screen_info.orientation_type =
+ ChromeClient().MockScreenInfo().orientation_type =
mojom::blink::ScreenOrientation::kPortraitPrimary;
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(1)
- .WillOnce(Return(screen_info));
EXPECT_EQ(device::mojom::ScreenOrientationLockType::PORTRAIT,
ComputeOrientationLock());
- screen_info.orientation_type =
+ ChromeClient().MockScreenInfo().orientation_type =
mojom::blink::ScreenOrientation::kPortraitPrimary;
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(1)
- .WillOnce(Return(screen_info));
EXPECT_EQ(device::mojom::ScreenOrientationLockType::PORTRAIT,
ComputeOrientationLock());
- screen_info.orientation_type =
+ ChromeClient().MockScreenInfo().orientation_type =
mojom::blink::ScreenOrientation::kLandscapePrimary;
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(1)
- .WillOnce(Return(screen_info));
EXPECT_EQ(device::mojom::ScreenOrientationLockType::LANDSCAPE,
ComputeOrientationLock());
- screen_info.orientation_type =
+ ChromeClient().MockScreenInfo().orientation_type =
mojom::blink::ScreenOrientation::kLandscapeSecondary;
- EXPECT_CALL(ChromeClient(), GetScreenInfo(_))
- .Times(1)
- .WillOnce(Return(screen_info));
EXPECT_EQ(device::mojom::ScreenOrientationLockType::LANDSCAPE,
ComputeOrientationLock());
}
@@ -1491,45 +1481,4 @@ TEST_F(MediaControlsOrientationLockAndRotateToFullscreenDelegateTest,
EXPECT_TRUE(DelegateWillUnlockFullscreen());
}
-TEST_F(MediaControlsOrientationLockAndRotateToFullscreenDelegateTest,
- DetachBeforeChangeLockToAnyOrientation) {
- // Naturally portrait device, initially portrait, with landscape video.
- natural_orientation_is_portrait_ = true;
- ASSERT_NO_FATAL_FAILURE(
- RotateScreenTo(mojom::blink::ScreenOrientation::kPortraitPrimary, 0));
- InitVideo(640, 480);
- SetIsAutoRotateEnabledByUser(true);
-
- // Initially inline, unlocked orientation.
- ASSERT_FALSE(Video().IsFullscreen());
- CheckStatePendingFullscreen();
- ASSERT_FALSE(DelegateWillUnlockFullscreen());
-
- // Simulate user clicking on media controls fullscreen button.
- SimulateEnterFullscreen();
- EXPECT_TRUE(Video().IsFullscreen());
-
- // MediaControlsOrientationLockDelegate should lock to landscape.
- CheckStateMaybeLockedFullscreen();
- EXPECT_EQ(device::mojom::ScreenOrientationLockType::LANDSCAPE,
- DelegateOrientationLock());
-
- // This will trigger a screen orientation change to landscape.
- ASSERT_NO_FATAL_FAILURE(
- RotateScreenTo(mojom::blink::ScreenOrientation::kLandscapePrimary, 90));
-
- // Rotate the device to match.
- RotateDeviceTo(90 /* landscape primary */);
-
- // And immediately detach the document by synchronously navigating.
- // One easy way to do this is to replace the document with a JavaScript URL.
- GetFrame().GetSettings()->SetScriptEnabled(true);
- FrameLoadRequest request(GetFrame().DomWindow(),
- ResourceRequest("javascript:'Hello, world!'"));
- GetFrame().Navigate(request, WebFrameLoadType::kStandard);
-
- // We should not crash after the unlock delay.
- test::RunDelayedTasks(GetUnlockDelay());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
index f94b2336e80..3807fe29283 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
@@ -7,7 +7,6 @@
#include "third_party/blink/public/common/widget/screen_info.h"
#include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
@@ -59,14 +58,6 @@ void MediaControlsRotateToFullscreenDelegate::Attach() {
// to receive events for 180 deg rotations).
dom_window->addEventListener(event_type_names::kOrientationchange, this,
false);
-
- // TODO(795286): device orientation now requires a v8::Context in the stack so
- // we are creating one so the event pump starts running.
- LocalFrame* frame = video_element_->GetDocument().GetFrame();
- if (!frame)
- return;
-
- ScriptState::Scope scope(ToScriptStateForMainWorld(frame));
dom_window->addEventListener(event_type_names::kDeviceorientation, this,
false);
}
@@ -275,7 +266,9 @@ MediaControlsRotateToFullscreenDelegate::ComputeScreenOrientation() const {
if (!frame)
return SimpleOrientation::kUnknown;
- switch (frame->GetChromeClient().GetScreenInfo(*frame).orientation_type) {
+ ChromeClient& chrome_client = frame->GetChromeClient();
+ const ScreenInfo& screen_info = chrome_client.GetScreenInfo(*frame);
+ switch (screen_info.orientation_type) {
case mojom::blink::ScreenOrientation::kPortraitPrimary:
case mojom::blink::ScreenOrientation::kPortraitSecondary:
return SimpleOrientation::kPortrait;
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 3f3b2aa2c31..56ca63446cc 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
@@ -6,7 +6,6 @@
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "services/device/public/mojom/screen_orientation.mojom-blink.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
#include "third_party/blink/public/platform/web_size.h"
@@ -22,6 +21,7 @@
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
+#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/modules/device_orientation/device_orientation_controller.h"
#include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h"
@@ -33,20 +33,22 @@
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-using testing::_;
-using testing::AtLeast;
-using testing::Return;
-
namespace blink {
namespace {
class MockVideoWebMediaPlayer : public EmptyWebMediaPlayer {
public:
+ ~MockVideoWebMediaPlayer() override = default;
+
// EmptyWebMediaPlayer overrides:
bool HasVideo() const override { return true; }
+ gfx::Size NaturalSize() const override { return mock_natural_size_; }
+
+ gfx::Size& MockNaturalSize() { return mock_natural_size_; }
- MOCK_CONST_METHOD0(NaturalSize, gfx::Size());
+ private:
+ gfx::Size mock_natural_size_ = {};
};
class MockChromeClient : public EmptyChromeClient {
@@ -71,7 +73,14 @@ class MockChromeClient : public EmptyChromeClient {
Fullscreen::DidExitFullscreen(*frame.GetDocument());
}
- MOCK_CONST_METHOD1(GetScreenInfo, ScreenInfo(LocalFrame&));
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return mock_screen_info_;
+ }
+
+ ScreenInfo& MockScreenInfo() { return mock_screen_info_; }
+
+ private:
+ ScreenInfo mock_screen_info_ = {};
};
class StubLocalFrameClient : public EmptyLocalFrameClient {
@@ -189,11 +198,8 @@ void MediaControlsRotateToFullscreenDelegateTest::InitScreenAndVideo(
gfx::Size video_size,
bool with_device_orientation /* = true */) {
// Set initial screen orientation (called by `Attach` during `AppendChild`).
- ScreenInfo screen_info;
- screen_info.orientation_type = initial_screen_orientation;
- EXPECT_CALL(GetChromeClient(), GetScreenInfo(_))
- .Times(AtLeast(1))
- .WillRepeatedly(Return(screen_info));
+ GetChromeClient().MockScreenInfo().orientation_type =
+ initial_screen_orientation;
// Set up the WebMediaPlayer instance.
GetDocument().body()->AppendChild(&GetVideo());
@@ -202,8 +208,7 @@ void MediaControlsRotateToFullscreenDelegateTest::InitScreenAndVideo(
SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
// Set video size.
- EXPECT_CALL(GetWebMediaPlayer(), NaturalSize())
- .WillRepeatedly(Return(video_size));
+ GetWebMediaPlayer().MockNaturalSize() = video_size;
if (with_device_orientation) {
// Dispatch an arbitrary Device Orientation event to satisfy
@@ -227,12 +232,7 @@ void MediaControlsRotateToFullscreenDelegateTest::PlayVideo() {
void MediaControlsRotateToFullscreenDelegateTest::RotateTo(
mojom::blink::ScreenOrientation new_screen_orientation) {
- ScreenInfo screen_info;
- screen_info.orientation_type = new_screen_orientation;
- testing::Mock::VerifyAndClearExpectations(&GetChromeClient());
- EXPECT_CALL(GetChromeClient(), GetScreenInfo(_))
- .Times(AtLeast(1))
- .WillRepeatedly(Return(screen_info));
+ GetChromeClient().MockScreenInfo().orientation_type = new_screen_orientation;
DispatchEvent(GetWindow(), event_type_names::kOrientationchange);
test::RunPendingTasks();
}
@@ -261,39 +261,28 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, ComputeVideoOrientation) {
GetVideo().SetSrc("https://example.com");
test::RunPendingTasks();
- // Each `ComputeVideoOrientation` calls `NaturalSize` twice, except the first
- // one where the video is not yet ready.
- EXPECT_CALL(GetWebMediaPlayer(), NaturalSize())
- .Times(12)
- .WillOnce(Return(gfx::Size(400, 400)))
- .WillOnce(Return(gfx::Size(400, 400)))
- .WillOnce(Return(gfx::Size(300, 200)))
- .WillOnce(Return(gfx::Size(300, 200)))
- .WillOnce(Return(gfx::Size(200, 300)))
- .WillOnce(Return(gfx::Size(200, 300)))
- .WillOnce(Return(gfx::Size(300, 199)))
- .WillOnce(Return(gfx::Size(300, 199)))
- .WillOnce(Return(gfx::Size(199, 300)))
- .WillOnce(Return(gfx::Size(199, 300)))
- .WillOnce(Return(gfx::Size(0, 0)))
- .WillOnce(Return(gfx::Size(0, 0)));
-
// Video is not yet ready.
EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
SimulateVideoReadyState(HTMLMediaElement::kHaveMetadata);
// 400x400 is square, which is currently treated as landscape.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(400, 400);
EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
// 300x200 is landscape.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(300, 200);
EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
// 200x300 is portrait.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(200, 300);
EXPECT_EQ(SimpleOrientation::kPortrait, ComputeVideoOrientation());
// 300x199 is too small.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(300, 199);
EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
// 199x300 is too small.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(199, 300);
EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
// 0x0 is empty.
+ GetWebMediaPlayer().MockNaturalSize() = gfx::Size(0, 0);
EXPECT_EQ(SimpleOrientation::kUnknown, ComputeVideoOrientation());
}
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_dark.svg b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_dark.svg
new file mode 100644
index 00000000000..764da51d50b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_dark.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#121212">
+ <path fill="none" d="M0 0h24v24H0zm0 0h24v24H0zm21 19c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2"/>
+ <path fill="none" d="M0 0h24v24H0z"/>
+ <path d="M21 5v6.59l-3-3.01-4 4.01-4-4-4 4-3-3.01V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2zm-3 6.42l3 3.01V19c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2v-6.58l3 2.99 4-4 4 4 4-3.99z"/>
+</svg>
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_white.svg b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_white.svg
deleted file mode 100644
index 764cdb175a3..00000000000
--- a/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_no_source_white.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#ffffff">
- <path fill="none" d="M0 0h24v24H0zm0 0h24v24H0zm21 19c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2"/>
- <path fill="none" d="M0 0h24v24H0z"/>
- <path d="M21 5v6.59l-3-3.01-4 4.01-4-4-4 4-3-3.01V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2zm-3 6.42l3 3.01V19c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2v-6.58l3 2.99 4-4 4 4 4-3.99z"/>
-</svg>
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_pause_dark.svg b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_pause_dark.svg
new file mode 100644
index 00000000000..e1a9903c887
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_pause_dark.svg
@@ -0,0 +1,4 @@
+<svg fill="#121212" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
+ <path d="M0 0h24v24H0z" fill="none"/>
+</svg> \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_play_arrow_dark.svg b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_play_arrow_dark.svg
new file mode 100644
index 00000000000..d42d4795b07
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/ic_play_arrow_dark.svg
@@ -0,0 +1,4 @@
+<svg fill="#121212" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M8 5v14l11-7z"/>
+ <path d="M0 0h24v24H0z" fill="none"/>
+</svg> \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
index 1e36d10325d..9b108d3941e 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -2,21 +2,7 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.*/
-/**
- * Used in MediaDocument only.
- * TODO: Move those outside of this file.
- */
-
-video:-webkit-full-page-media {
- margin: auto;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- max-height: 100%;
- max-width: 100%;
-}
+@namespace "http://www.w3.org/1999/xhtml";
/**
* Panel Structure
@@ -565,7 +551,7 @@ input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-co
background-size: 50%;
background-repeat: no-repeat;
background-position: center center;
- background-image: -internal-light-dark(-webkit-image-set(url(ic_play_arrow.svg) 1x), -webkit-image-set(url(ic_play_arrow_white.svg) 1x));
+ background-image: -internal-light-dark(-webkit-image-set(url(ic_play_arrow.svg) 1x), -webkit-image-set(url(ic_play_arrow_dark.svg) 1x));
background-color: rgba(255, 255, 255, .9);
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.10);
@@ -588,6 +574,12 @@ video::-webkit-media-controls.state-buffering input[pseudo="-webkit-media-contro
background-image: -internal-light-dark(-webkit-image-set(url(ic_pause.svg) 1x), -webkit-image-set(url(ic_pause_white.svg) 1x));
}
+video::-webkit-media-controls.state-playing input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal,
+video::-webkit-media-controls.state-loading-metadata-playing input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal,
+video::-webkit-media-controls.state-buffering input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal {
+ background-image: -internal-light-dark(-webkit-image-set(url(ic_pause.svg) 1x), -webkit-image-set(url(ic_pause_dark.svg) 1x));
+}
+
/* For the play button inside the button panel, we want to use a white icon
* instead. */
video::-webkit-media-controls.state-buffering [pseudo="-internal-media-controls-button-panel"] input[pseudo="-webkit-media-controls-play-button" i],
@@ -868,7 +860,7 @@ video::-internal-media-controls-overflow-menu-list {
overflow-y: auto;
white-space: nowrap;
font-size: 12px;
- background: #FFFFFF;
+ background: -internal-light-dark(#ffffff, #3B3B3B);
box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40);
border-radius: 2px;
transition: transform .3s ease-out, opacity .2s linear;
@@ -1072,21 +1064,6 @@ video::-webkit-media-controls-overlay-enclosure {
* Audio Controls
*/
-audio:not([controls]) {
- display: none !important;
-}
-
-/** TODO(crbug.com/985623): Remove these hard-coded audio tag size.
- * This fixed audio tag width/height leads to fail the wpt tests below.
- * crbug.com/955170 external/wpt/css/css-contain/contain-size-replaced-003a.html
- * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003b.html
- * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003c.html
- */
-audio {
- width: 300px;
- height: 54px;
-}
-
audio::-webkit-media-controls-overlay-enclosure,
video::-webkit-media-controls.audio-only [pseudo="-webkit-media-controls-overlay-enclosure"] {
display: none;
@@ -1155,7 +1132,7 @@ video::-webkit-media-controls.audio-only [pseudo="-internal-media-controls-overf
.state-no-source input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal {
opacity: .3;
- background-image: -internal-light-dark(-webkit-image-set(url(ic_no_source.svg) 1x), -webkit-image-set(url(ic_no_source_white.svg) 1x));
+ background-image: -internal-light-dark(-webkit-image-set(url(ic_no_source.svg) 1x), -webkit-image-set(url(ic_no_source_dark.svg) 1x));
}
/**
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls_Android.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls_Android.css
index 1666c976e0d..94b91132f5d 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls_Android.css
+++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/mediaControls_Android.css
@@ -2,6 +2,7 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.*/
+@namespace "http://www.w3.org/1999/xhtml";
/* On Android, we always want the slider thumb to appear. */
video::-webkit-media-controls input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb,
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/DIR_METADATA b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/DIR_METADATA
new file mode 100644
index 00000000000..bcfc2bd394f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>MediaStream>CaptureFromElement"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
index 0a78e513d91..b58e18d5a35 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
@@ -3,6 +3,3 @@ guidou@chromium.org
# Original (legacy) owner.
emircan@chromium.org
mcasas@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>MediaStream>CaptureFromElement
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 7e80f4137dc..b84e03c93d4 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
@@ -31,8 +31,6 @@
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "ui/gfx/color_space.h"
-using media::VideoFrame;
-
namespace blink {
namespace {
@@ -117,10 +115,10 @@ class CanvasCaptureHandler::CanvasCaptureHandlerDelegate {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
}
- void SendNewFrameOnIOThread(scoped_refptr<VideoFrame> video_frame,
+ void SendNewFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame,
base::TimeTicks current_time) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
- new_frame_callback_.Run(std::move(video_frame), current_time);
+ new_frame_callback_.Run(std::move(video_frame), {}, current_time);
}
base::WeakPtr<CanvasCaptureHandlerDelegate> GetWeakPtrForIOThread() {
@@ -269,7 +267,7 @@ void CanvasCaptureHandler::ReadARGBPixelsSync(
PaintImage paint_image = image->PaintImageForCurrentFrame();
const base::TimeTicks timestamp = base::TimeTicks::Now();
const gfx::Size image_size(paint_image.width(), paint_image.height());
- scoped_refptr<VideoFrame> temp_argb_frame = frame_pool_.CreateFrame(
+ scoped_refptr<media::VideoFrame> temp_argb_frame = frame_pool_.CreateFrame(
media::PIXEL_FORMAT_ARGB, image_size, gfx::Rect(image_size), image_size,
base::TimeDelta());
if (!temp_argb_frame) {
@@ -281,8 +279,9 @@ void CanvasCaptureHandler::ReadARGBPixelsSync(
image_size.width(), image_size.height(),
is_opaque ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
if (!paint_image.readPixels(
- image_info, temp_argb_frame->visible_data(VideoFrame::kARGBPlane),
- temp_argb_frame->stride(VideoFrame::kARGBPlane), 0 /*srcX*/,
+ image_info,
+ temp_argb_frame->visible_data(media::VideoFrame::kARGBPlane),
+ temp_argb_frame->stride(media::VideoFrame::kARGBPlane), 0 /*srcX*/,
0 /*srcY*/)) {
DLOG(ERROR) << "Couldn't read pixels from PaintImage";
return;
@@ -290,8 +289,9 @@ void CanvasCaptureHandler::ReadARGBPixelsSync(
SendFrame(
ConvertToYUVFrame(
is_opaque, false /* flip */,
- temp_argb_frame->visible_data(VideoFrame::kARGBPlane), image_size,
- temp_argb_frame->stride(VideoFrame::kARGBPlane), kN32_SkColorType),
+ temp_argb_frame->visible_data(media::VideoFrame::kARGBPlane),
+ image_size, temp_argb_frame->stride(media::VideoFrame::kARGBPlane),
+ kN32_SkColorType),
timestamp, GetImageYUVColorSpace(image));
}
@@ -303,7 +303,7 @@ void CanvasCaptureHandler::ReadARGBPixelsAsync(
const base::TimeTicks timestamp = base::TimeTicks::Now();
const gfx::Size image_size(image->width(), image->height());
- scoped_refptr<VideoFrame> temp_argb_frame = frame_pool_.CreateFrame(
+ scoped_refptr<media::VideoFrame> temp_argb_frame = frame_pool_.CreateFrame(
media::PIXEL_FORMAT_ARGB, image_size, gfx::Rect(image_size), image_size,
base::TimeDelta());
if (!temp_argb_frame) {
@@ -328,7 +328,7 @@ void CanvasCaptureHandler::ReadARGBPixelsAsync(
mailbox_holder.sync_token.GetConstData());
context_provider->RasterInterface()->ReadbackARGBPixelsAsync(
mailbox_holder.mailbox, mailbox_holder.texture_target, image_size,
- temp_argb_frame->visible_data(VideoFrame::kARGBPlane), format,
+ temp_argb_frame->visible_data(media::VideoFrame::kARGBPlane), format,
WTF::Bind(&CanvasCaptureHandler::OnARGBPixelsReadAsync,
weak_ptr_factory_.GetWeakPtr(), image, temp_argb_frame,
timestamp, !image->IsOriginTopLeft()));
@@ -343,7 +343,7 @@ void CanvasCaptureHandler::ReadYUVPixelsAsync(
const base::TimeTicks timestamp = base::TimeTicks::Now();
const gfx::Size image_size(image->width(), image->height());
- scoped_refptr<VideoFrame> output_frame = frame_pool_.CreateFrame(
+ scoped_refptr<media::VideoFrame> output_frame = frame_pool_.CreateFrame(
media::PIXEL_FORMAT_I420, image_size, gfx::Rect(image_size), image_size,
base::TimeDelta());
if (!output_frame) {
@@ -391,13 +391,13 @@ void CanvasCaptureHandler::OnARGBPixelsReadAsync(
const bool is_opaque = image->CurrentFrameKnownToBeOpaque();
const auto color_space = GetImageYUVColorSpace(image);
- SendFrame(
- ConvertToYUVFrame(is_opaque, flip,
- temp_argb_frame->visible_data(VideoFrame::kARGBPlane),
- temp_argb_frame->visible_rect().size(),
- temp_argb_frame->stride(VideoFrame::kARGBPlane),
- kN32_SkColorType),
- this_frame_ticks, color_space);
+ SendFrame(ConvertToYUVFrame(
+ is_opaque, flip,
+ temp_argb_frame->visible_data(media::VideoFrame::kARGBPlane),
+ temp_argb_frame->visible_rect().size(),
+ temp_argb_frame->stride(media::VideoFrame::kARGBPlane),
+ kN32_SkColorType),
+ this_frame_ticks, color_space);
if (num_ongoing_async_pixel_readouts_ == 0 && deferred_request_refresh_frame_)
SendRefreshFrame();
}
@@ -432,7 +432,7 @@ scoped_refptr<media::VideoFrame> CanvasCaptureHandler::ConvertToYUVFrame(
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
TRACE_EVENT0("webrtc", "CanvasCaptureHandler::ConvertToYUVFrame");
- scoped_refptr<VideoFrame> video_frame = frame_pool_.CreateFrame(
+ scoped_refptr<media::VideoFrame> video_frame = frame_pool_.CreateFrame(
is_opaque ? media::PIXEL_FORMAT_I420 : media::PIXEL_FORMAT_I420A,
image_size, gfx::Rect(image_size), image_size, base::TimeDelta());
if (!video_frame) {
@@ -472,17 +472,19 @@ scoped_refptr<media::VideoFrame> CanvasCaptureHandler::ConvertToYUVFrame(
// It is ok to use ARGB function because alpha has the same alignment for
// both ABGR and ARGB.
libyuv::ARGBExtractAlpha(
- source_ptr, stride, video_frame->visible_data(VideoFrame::kAPlane),
- video_frame->stride(VideoFrame::kAPlane), image_size.width(),
+ source_ptr, stride,
+ video_frame->visible_data(media::VideoFrame::kAPlane),
+ video_frame->stride(media::VideoFrame::kAPlane), image_size.width(),
(flip ? -1 : 1) * image_size.height());
}
return video_frame;
}
-void CanvasCaptureHandler::SendFrame(scoped_refptr<VideoFrame> video_frame,
- base::TimeTicks this_frame_ticks,
- const gfx::ColorSpace& color_space) {
+void CanvasCaptureHandler::SendFrame(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks this_frame_ticks,
+ const gfx::ColorSpace& color_space) {
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
// If this function is called asynchronously, |delegate_| might have been
@@ -521,8 +523,7 @@ void CanvasCaptureHandler::AddVideoCapturerSourceToVideoTrack(
track_id, MediaStreamSource::kTypeVideo, track_id, false);
stream_source->SetPlatformSource(std::move(stream_video_source));
stream_source->SetCapabilities(ComputeCapabilitiesForVideoSource(
- track_id, preferred_formats,
- media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE,
+ track_id, preferred_formats, mojom::blink::FacingMode::NONE,
false /* is_device_capture */));
*component = MakeGarbageCollected<MediaStreamComponent>(stream_source);
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
index 3c82aa9a8b3..a7d70291eff 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
@@ -71,8 +71,10 @@ class CanvasCaptureHandlerTest
// Necessary callbacks and MOCK_METHODS for VideoCapturerSource.
MOCK_METHOD2(DoOnDeliverFrame,
void(scoped_refptr<media::VideoFrame>, base::TimeTicks));
- void OnDeliverFrame(scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks estimated_capture_time) {
+ void OnDeliverFrame(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time) {
DoOnDeliverFrame(std::move(video_frame), estimated_capture_time);
}
@@ -93,11 +95,13 @@ class CanvasCaptureHandlerTest
SkImage::MakeFromBitmap(testBitmap));
}
- void OnVerifyDeliveredFrame(bool opaque,
- int expected_width,
- int expected_height,
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks estimated_capture_time) {
+ void OnVerifyDeliveredFrame(
+ bool opaque,
+ int expected_width,
+ int expected_height,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time) {
if (opaque)
EXPECT_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
else
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source_unittest.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source_unittest.cc
index 8fc28f8fc1f..ea62116edf5 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_audio_element_capturer_source_unittest.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
@@ -31,19 +32,6 @@ static const int kAudioTrackSamplesPerBuffer =
kAudioTrackSampleRate * kBufferDurationMs /
base::Time::kMillisecondsPerSecond;
-class MockMediaStreamAudioSink final : public blink::WebMediaStreamAudioSink {
- public:
- MockMediaStreamAudioSink() : blink::WebMediaStreamAudioSink() {}
- ~MockMediaStreamAudioSink() override = default;
-
- MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters& params));
- MOCK_METHOD2(OnData,
- void(const media::AudioBus& audio_bus,
- base::TimeTicks estimated_capture_time));
-
- DISALLOW_COPY_AND_ASSIGN(MockMediaStreamAudioSink);
-};
-
// This test needs to bundle together plenty of objects, namely:
// - a WebAudioSourceProviderImpl, which in turn needs an Audio Sink, in this
// case a NullAudioSink. This is needed to plug HTMLAudioElementCapturerSource
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 ab283282419..46f9ad4c433 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
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.h"
#include "base/memory/ptr_util.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
@@ -63,8 +64,7 @@ bool AddVideoTrackToMediaStream(
track_id, MediaStreamSource::kTypeVideo, track_id, is_remote);
media_stream_source->SetPlatformSource(std::move(media_stream_video_source));
media_stream_source->SetCapabilities(ComputeCapabilitiesForVideoSource(
- track_id, preferred_formats,
- media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE,
+ track_id, preferred_formats, mojom::blink::FacingMode::NONE,
false /* is_device_capture */));
descriptor->AddRemoteTrack(MediaStreamVideoTrack::CreateVideoTrack(
media_stream_video_source_ptr,
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
index b7f3ba53d01..7c0801e25f4 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
@@ -11,7 +11,6 @@
#include "base/trace_event/trace_event.h"
#include "media/base/limits.h"
#include "third_party/blink/public/platform/web_media_player.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
#include "third_party/blink/renderer/platform/mediastream/webrtc_uma_histograms.h"
@@ -132,6 +131,7 @@ void HtmlVideoElementCapturerSource::sendNewFrame() {
PostCrossThreadTask(
*io_task_runner_, FROM_HERE,
CrossThreadBindOnce(new_frame_callback_, std::move(new_frame),
+ std::vector<scoped_refptr<media::VideoFrame>>(),
current_time));
}
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
index 55f576ae536..cb8c482ee72 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
@@ -20,12 +20,12 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_media_player.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
using base::test::RunOnceClosure;
using ::testing::_;
+using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Mock;
using ::testing::SaveArg;
@@ -40,7 +40,10 @@ class MockWebMediaPlayer : public WebMediaPlayer {
MockWebMediaPlayer() {}
~MockWebMediaPlayer() override = default;
- LoadTiming Load(LoadType, const WebMediaPlayerSource&, CorsMode) override {
+ LoadTiming Load(LoadType,
+ const WebMediaPlayerSource&,
+ CorsMode,
+ bool is_cache_disabled) override {
return LoadTiming::kImmediate;
}
void Play() override {}
@@ -50,12 +53,14 @@ class MockWebMediaPlayer : public WebMediaPlayer {
void SetVolume(double) override {}
void SetLatencyHint(double) override {}
void SetPreservesPitch(bool) override {}
+ void SetAutoplayInitiated(bool) override {}
void OnRequestPictureInPicture() override {}
- void OnPictureInPictureAvailabilityChanged(bool available) override {}
WebTimeRanges Buffered() const override { return WebTimeRanges(); }
WebTimeRanges Seekable() const override { return WebTimeRanges(); }
- void SetSinkId(const WebString& sinkId,
- WebSetSinkIdCompleteCallback) override {}
+ bool SetSinkId(const WebString& sinkId,
+ WebSetSinkIdCompleteCallback) override {
+ return false;
+ }
bool HasVideo() const override { return true; }
bool HasAudio() const override { return false; }
gfx::Size NaturalSize() const override { return size_; }
@@ -84,10 +89,8 @@ class MockWebMediaPlayer : public WebMediaPlayer {
void SetWouldTaintOrigin(bool taint) { would_taint_origin_ = taint; }
void Paint(cc::PaintCanvas* canvas,
- const WebRect& rect,
- cc::PaintFlags&,
- int already_uploaded_id,
- VideoFrameUploadMetadata* out_metadata) override {
+ const gfx::Rect& rect,
+ cc::PaintFlags&) override {
return;
}
@@ -127,8 +130,10 @@ class HTMLVideoElementCapturerSourceTest : public testing::TestWithParam<bool> {
// Necessary callbacks and MOCK_METHODS for them.
MOCK_METHOD2(DoOnDeliverFrame,
void(scoped_refptr<media::VideoFrame>, base::TimeTicks));
- void OnDeliverFrame(scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks estimated_capture_time) {
+ void OnDeliverFrame(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time) {
DoOnDeliverFrame(std::move(video_frame), estimated_capture_time);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.cc
index eafd759e225..1588ded5988 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.cc
@@ -43,6 +43,7 @@ void TimedCanvasDrawListener::RequestFrameTimerFired(TimerBase*) {
}
void TimedCanvasDrawListener::Trace(Visitor* visitor) const {
+ visitor->Trace(request_frame_timer_);
OnRequestCanvasDrawListener::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.h b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.h
index f3336d4a05b..0034acad5fc 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.h
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/timed_canvas_draw_listener.h
@@ -33,7 +33,7 @@ class TimedCanvasDrawListener final : public OnRequestCanvasDrawListener {
void RequestFrameTimerFired(TimerBase*);
base::TimeDelta frame_interval_;
- TaskRunnerTimer<TimedCanvasDrawListener> request_frame_timer_;
+ HeapTaskRunnerTimer<TimedCanvasDrawListener> request_frame_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/DIR_METADATA b/chromium/third_party/blink/renderer/modules/mediarecorder/DIR_METADATA
new file mode 100644
index 00000000000..45929028362
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>MediaRecording"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/OWNERS b/chromium/third_party/blink/renderer/modules/mediarecorder/OWNERS
index f320e875e84..f24322a13c0 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/OWNERS
@@ -5,6 +5,3 @@ peter@chromium.org
# Original (legacy) owner.
emircan@chromium.org
mcasas@chromium.org
-
-# COMPONENT: Blink>MediaRecording
-# TEAM: media-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
index 626259cc6aa..18b331507df 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
@@ -65,9 +65,11 @@ namespace blink {
AudioTrackOpusEncoder::AudioTrackOpusEncoder(
OnEncodedAudioCB on_encoded_audio_cb,
- int32_t bits_per_second)
+ int32_t bits_per_second,
+ bool vbr_enabled)
: AudioTrackEncoder(std::move(on_encoded_audio_cb)),
bits_per_second_(bits_per_second),
+ vbr_enabled_(vbr_enabled),
opus_encoder_(nullptr) {}
AudioTrackOpusEncoder::~AudioTrackOpusEncoder() {
@@ -144,6 +146,12 @@ void AudioTrackOpusEncoder::OnSetFormat(
DLOG(ERROR) << "Failed to set Opus bitrate: " << bitrate;
return;
}
+
+ const opus_int32 vbr_enabled = static_cast<opus_int32>(vbr_enabled_);
+ if (opus_encoder_ctl(opus_encoder_, OPUS_SET_VBR(vbr_enabled)) != OPUS_OK) {
+ DLOG(ERROR) << "Failed to set Opus VBR mode: " << vbr_enabled;
+ return;
+ }
}
void AudioTrackOpusEncoder::EncodeAudio(
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.h b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.h
index 3e744819b63..154109260be 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.h
@@ -24,7 +24,8 @@ class AudioTrackOpusEncoder : public AudioTrackEncoder,
public media::AudioConverter::InputCallback {
public:
AudioTrackOpusEncoder(OnEncodedAudioCB on_encoded_audio_cb,
- int32_t bits_per_second);
+ int32_t bits_per_second,
+ bool vbr_enabled = true);
void OnSetFormat(const media::AudioParameters& params) override;
void EncodeAudio(std::unique_ptr<media::AudioBus> input_bus,
@@ -44,6 +45,11 @@ class AudioTrackOpusEncoder : public AudioTrackEncoder,
// Target bitrate for Opus. If 0, Opus provide automatic bitrate is used.
const int32_t bits_per_second_;
+ // Opus operates in VBR or constrained VBR modes even when a fixed bitrate
+ // is specified, unless 'hard' CBR is explicitly enabled by disabling VBR
+ // mode with this flag.
+ const bool vbr_enabled_;
+
// Output parameters after audio conversion. This differs from the input
// parameters only in sample_rate() and frames_per_buffer(): output should be
// 48ksamples/s and 2880, respectively.
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.cc
index f96f4c97800..80af6b90964 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.cc
@@ -48,12 +48,14 @@ AudioTrackRecorder::AudioTrackRecorder(
MediaStreamComponent* track,
OnEncodedAudioCB on_encoded_audio_cb,
base::OnceClosure on_track_source_ended_cb,
- int32_t bits_per_second)
+ int32_t bits_per_second,
+ BitrateMode bitrate_mode)
: TrackRecorder(std::move(on_track_source_ended_cb)),
track_(track),
encoder_(CreateAudioEncoder(codec,
std::move(on_encoded_audio_cb),
- bits_per_second)),
+ bits_per_second,
+ bitrate_mode)),
encoder_thread_(Thread::CreateThread(
ThreadCreationParams(ThreadType::kAudioEncoderThread))),
encoder_task_runner_(encoder_thread_->GetTaskRunner()) {
@@ -75,7 +77,8 @@ AudioTrackRecorder::~AudioTrackRecorder() {
scoped_refptr<AudioTrackEncoder> AudioTrackRecorder::CreateAudioEncoder(
CodecId codec,
OnEncodedAudioCB on_encoded_audio_cb,
- int32_t bits_per_second) {
+ int32_t bits_per_second,
+ BitrateMode bitrate_mode) {
if (codec == CodecId::PCM) {
return base::MakeRefCounted<AudioTrackPcmEncoder>(
media::BindToCurrentLoop(std::move(on_encoded_audio_cb)));
@@ -83,8 +86,8 @@ scoped_refptr<AudioTrackEncoder> AudioTrackRecorder::CreateAudioEncoder(
// All other paths will use the AudioTrackOpusEncoder.
return base::MakeRefCounted<AudioTrackOpusEncoder>(
- media::BindToCurrentLoop(std::move(on_encoded_audio_cb)),
- bits_per_second);
+ media::BindToCurrentLoop(std::move(on_encoded_audio_cb)), bits_per_second,
+ bitrate_mode == BitrateMode::VARIABLE);
}
void AudioTrackRecorder::OnSetFormat(const media::AudioParameters& params) {
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h
index a617ab134cb..2216e1d135e 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h
@@ -41,6 +41,8 @@ class MODULES_EXPORT AudioTrackRecorder
LAST
};
+ enum class BitrateMode { CONSTANT, VARIABLE };
+
using OnEncodedAudioCB =
base::RepeatingCallback<void(const media::AudioParameters& params,
std::string encoded_data,
@@ -52,7 +54,8 @@ class MODULES_EXPORT AudioTrackRecorder
MediaStreamComponent* track,
OnEncodedAudioCB on_encoded_audio_cb,
base::OnceClosure on_track_source_ended_cb,
- int32_t bits_per_second);
+ int32_t bits_per_second,
+ BitrateMode bitrate_mode);
~AudioTrackRecorder() override;
// Implement MediaStreamAudioSink.
@@ -69,7 +72,8 @@ class MODULES_EXPORT AudioTrackRecorder
static scoped_refptr<AudioTrackEncoder> CreateAudioEncoder(
CodecId codec,
OnEncodedAudioCB on_encoded_audio_cb,
- int32_t bits_per_second);
+ int32_t bits_per_second,
+ BitrateMode bitrate_mode);
void ConnectToTrack();
void DisconnectFromTrack();
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
index 9116be7cd0b..851775896be 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
@@ -53,6 +53,7 @@ struct ATRTestParams {
const media::ChannelLayout channel_layout;
const int sample_rate;
const AudioTrackRecorder::CodecId codec;
+ const AudioTrackRecorder::BitrateMode bitrateMode;
};
const ATRTestParams kATRTestParams[] = {
@@ -60,27 +61,45 @@ const ATRTestParams kATRTestParams[] = {
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY, /* input format */
media::CHANNEL_LAYOUT_STEREO, /* channel layout */
kDefaultSampleRate, /* sample rate */
- AudioTrackRecorder::CodecId::OPUS}, /* codec for encoding */
+ AudioTrackRecorder::CodecId::OPUS, /* codec for encoding */
+ AudioTrackRecorder::BitrateMode::VARIABLE}, /* constant/variable rate */
+
// Change to mono:
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
- kDefaultSampleRate, AudioTrackRecorder::CodecId::OPUS},
+ kDefaultSampleRate, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
+
// Different sampling rate as well:
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
- 24000, AudioTrackRecorder::CodecId::OPUS},
+ 24000, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- media::CHANNEL_LAYOUT_STEREO, 8000, AudioTrackRecorder::CodecId::OPUS},
+ media::CHANNEL_LAYOUT_STEREO, 8000, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
+
// Using a non-default Opus sampling rate (48, 24, 16, 12, or 8 kHz).
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
- 22050, AudioTrackRecorder::CodecId::OPUS},
+ 22050, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- media::CHANNEL_LAYOUT_STEREO, 44100, AudioTrackRecorder::CodecId::OPUS},
+ media::CHANNEL_LAYOUT_STEREO, 44100, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- media::CHANNEL_LAYOUT_STEREO, 96000, AudioTrackRecorder::CodecId::OPUS},
+ media::CHANNEL_LAYOUT_STEREO, 96000, AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
- kDefaultSampleRate, AudioTrackRecorder::CodecId::PCM},
+ kDefaultSampleRate, AudioTrackRecorder::CodecId::PCM,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
+ {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate,
+ AudioTrackRecorder::CodecId::PCM,
+ AudioTrackRecorder::BitrateMode::VARIABLE},
+
+ // Use Opus in constatnt bitrate mode:
{media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate,
- AudioTrackRecorder::CodecId::PCM},
+ AudioTrackRecorder::CodecId::OPUS,
+ AudioTrackRecorder::BitrateMode::CONSTANT},
};
class AudioTrackRecorderTest : public testing::TestWithParam<ATRTestParams> {
@@ -112,7 +131,7 @@ class AudioTrackRecorderTest : public testing::TestWithParam<ATRTestParams> {
WTF::BindRepeating(&AudioTrackRecorderTest::OnEncodedAudio,
WTF::Unretained(this)),
ConvertToBaseOnceCallback(CrossThreadBindOnce([] {})),
- 0 /* bits_per_second */);
+ 0 /* bits_per_second */, GetParam().bitrateMode);
}
~AudioTrackRecorderTest() {
@@ -260,9 +279,17 @@ TEST_P(AudioTrackRecorderTest, OnDataOpus) {
// Give ATR initial audio parameters.
audio_track_recorder_->OnSetFormat(first_params_);
+ std::vector<std::size_t> encodedPacketSizes;
// TODO(ajose): consider adding WillOnce(SaveArg...) and inspecting, as done
// in VTR unittests. http://crbug.com/548856
- EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _)).Times(1);
+ EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
+ .Times(1)
+ .WillOnce([&encodedPacketSizes](const media::AudioParameters&,
+ std::string encoded_data,
+ base::TimeTicks) {
+ encodedPacketSizes.push_back(encoded_data.size());
+ });
+
audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
base::TimeTicks::Now());
for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
@@ -273,9 +300,14 @@ TEST_P(AudioTrackRecorderTest, OnDataOpus) {
EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
.Times(1)
// Only reset the decoder once we've heard back:
- .WillOnce(
+ .WillOnce(testing::DoAll(
RunOnceClosure(WTF::Bind(&AudioTrackRecorderTest::ResetDecoder,
- WTF::Unretained(this), second_params_)));
+ WTF::Unretained(this), second_params_)),
+ [&encodedPacketSizes](const media::AudioParameters&,
+ std::string encoded_data, base::TimeTicks) {
+ encodedPacketSizes.push_back(encoded_data.size());
+ }));
+
audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
base::TimeTicks::Now());
for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
@@ -296,7 +328,13 @@ TEST_P(AudioTrackRecorderTest, OnDataOpus) {
// Send audio with different params.
EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
.Times(1)
- .WillOnce(RunOnceClosure(std::move(quit_closure)));
+ .WillOnce(testing::DoAll(
+ RunOnceClosure(std::move(quit_closure)),
+ [&encodedPacketSizes](const media::AudioParameters&,
+ std::string encoded_data, base::TimeTicks) {
+ encodedPacketSizes.push_back(encoded_data.size());
+ }));
+
audio_track_recorder_->OnData(*GetSecondSourceAudioBus(),
base::TimeTicks::Now());
for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
@@ -304,6 +342,14 @@ TEST_P(AudioTrackRecorderTest, OnDataOpus) {
base::TimeTicks::Now());
}
+ // Check that in CBR mode, all the packets are the same size, to confirm it
+ // actually made a CBR recording.
+ if (GetParam().bitrateMode == AudioTrackRecorder::BitrateMode::CONSTANT) {
+ if (!encodedPacketSizes.empty()) {
+ EXPECT_THAT(encodedPacketSizes, testing::Each(encodedPacketSizes[0]));
+ }
+ }
+
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(this);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
index 8cae0a53a58..83375983099 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
@@ -5,6 +5,8 @@
#include "third_party/blink/renderer/modules/mediarecorder/h264_encoder.h"
#include "build/chromeos_buildflags.h"
+#include <utility>
+
#include "media/base/video_frame.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
@@ -55,9 +57,12 @@ void H264Encoder::EncodeOnEncodingTaskRunner(
base::TimeTicks capture_timestamp) {
TRACE_EVENT0("media", "H264Encoder::EncodeOnEncodingTaskRunner");
DCHECK(encoding_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_NV12 ||
+ frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_I420);
- if (frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER)
+ if (frame->format() == media::PIXEL_FORMAT_NV12)
frame = ConvertToI420ForSoftwareEncoder(frame);
+ DCHECK(frame->IsMappable());
const gfx::Size frame_size = frame->visible_rect().size();
if (!openh264_encoder_ || configured_size_ != frame_size) {
@@ -109,11 +114,10 @@ void H264Encoder::EncodeOnEncodingTaskRunner(
const bool is_key_frame = info.eFrameType == videoFrameTypeIDR;
PostCrossThreadTask(
*origin_task_runner_.get(), FROM_HERE,
- CrossThreadBindOnce(
- OnFrameEncodeCompleted,
- WTF::Passed(CrossThreadBindRepeating(on_encoded_video_cb_)),
- video_params, std::move(data), std::string(), capture_timestamp,
- is_key_frame));
+ CrossThreadBindOnce(OnFrameEncodeCompleted,
+ CrossThreadBindRepeating(on_encoded_video_cb_),
+ video_params, std::move(data), std::string(),
+ capture_timestamp, is_key_frame));
}
void H264Encoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) {
@@ -154,7 +158,7 @@ void H264Encoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) {
init_params.iRCMode = RC_OFF_MODE;
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
init_params.iMultipleThreadIdc = 0;
#else
// Threading model: Set to 1 due to https://crbug.com/583348.
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 cf3f588a897..fd04f8e1ed7 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/platform/network/mime/content_type.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -49,6 +50,29 @@ String StateToString(MediaRecorder::State state) {
return String();
}
+String BitrateModeToString(AudioTrackRecorder::BitrateMode bitrateMode) {
+ switch (bitrateMode) {
+ case AudioTrackRecorder::BitrateMode::CONSTANT:
+ return "constant";
+ case AudioTrackRecorder::BitrateMode::VARIABLE:
+ return "variable";
+ }
+
+ NOTREACHED();
+ return String();
+}
+
+AudioTrackRecorder::BitrateMode GetBitrateModeFromOptions(
+ const MediaRecorderOptions* const options) {
+ if (options->hasAudioBitrateMode()) {
+ if (!WTF::CodeUnitCompareIgnoringASCIICase(options->audioBitrateMode(),
+ "constant"))
+ return AudioTrackRecorder::BitrateMode::CONSTANT;
+ }
+
+ return AudioTrackRecorder::BitrateMode::VARIABLE;
+}
+
// Allocates the requested bit rates from |bitrateOptions| into the respective
// |{audio,video}BitsPerSecond| (where a value of zero indicates Platform to use
// whatever it sees fit). If |options.bitsPerSecond()| is specified, it
@@ -190,7 +214,7 @@ MediaRecorder::MediaRecorder(ExecutionContext* context,
if (!recorder_handler_->Initialize(
this, stream->Descriptor(), content_type.GetType(),
content_type.Parameter("codecs"), audio_bits_per_second_,
- video_bits_per_second_)) {
+ video_bits_per_second_, GetBitrateModeFromOptions(options))) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotSupportedError,
"Failed to initialize native MediaRecorder the type provided (" +
@@ -206,6 +230,10 @@ String MediaRecorder::state() const {
return StateToString(state_);
}
+String MediaRecorder::audioBitrateMode() const {
+ return BitrateModeToString(recorder_handler_->AudioBitrateMode());
+}
+
void MediaRecorder::start(ExceptionState& exception_state) {
start(std::numeric_limits<int>::max() /* timeSlice */, exception_state);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
index 889126c0a1c..fec6d5eabf5 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
@@ -49,6 +49,7 @@ class MODULES_EXPORT MediaRecorder
String state() const;
uint32_t videoBitsPerSecond() const { return video_bits_per_second_; }
uint32_t audioBitsPerSecond() const { return audio_bits_per_second_; }
+ String audioBitrateMode() const;
DEFINE_ATTRIBUTE_EVENT_LISTENER(start, kStart)
DEFINE_ATTRIBUTE_EVENT_LISTENER(stop, kStop)
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.idl b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.idl
index 3403191398d..5dbf681ce5f 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.idl
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.idl
@@ -23,6 +23,7 @@ enum RecordingState { "inactive", "recording", "paused" };
attribute EventHandler onerror;
[HighEntropy=Direct, MeasureAs=MediaRecorder_VideoBitsPerSecond] readonly attribute unsigned long videoBitsPerSecond;
[HighEntropy=Direct, MeasureAs=MediaRecorder_AudioBitsPerSecond] readonly attribute unsigned long audioBitsPerSecond;
+ readonly attribute BitrateMode audioBitrateMode;
[RaisesException, Measure] void start(optional long timeslice);
[RaisesException] void stop();
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
index 3c47108257f..138a25176f0 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h"
+#include <memory>
#include <utility>
#include "base/logging.h"
@@ -24,6 +25,7 @@
#include "third_party/blink/renderer/platform/media_capabilities/web_media_configuration.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.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/mediastream/webrtc_uma_histograms.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -159,11 +161,9 @@ bool MediaRecorderHandler::CanSupportMimeType(const String& type,
if (type.IsEmpty())
return true;
- const bool video =
- !CodeUnitCompareIgnoringASCIICase(type, "video/webm") ||
- !CodeUnitCompareIgnoringASCIICase(type, "video/x-matroska");
- const bool audio =
- video ? false : (!CodeUnitCompareIgnoringASCIICase(type, "audio/webm"));
+ const bool video = EqualIgnoringASCIICase(type, "video/webm") ||
+ EqualIgnoringASCIICase(type, "video/x-matroska");
+ const bool audio = !video && EqualIgnoringASCIICase(type, "audio/webm");
if (!video && !audio)
return false;
@@ -193,7 +193,7 @@ bool MediaRecorderHandler::CanSupportMimeType(const String& type,
String codec_string = String::FromUTF8(codec);
auto* const* found = std::find_if(
&codecs[0], &codecs[codecs_count], [&codec_string](const char* name) {
- return !CodeUnitCompareIgnoringASCIICase(codec_string, name);
+ return EqualIgnoringASCIICase(codec_string, name);
});
if (found == &codecs[codecs_count])
return false;
@@ -201,12 +201,14 @@ bool MediaRecorderHandler::CanSupportMimeType(const String& type,
return true;
}
-bool MediaRecorderHandler::Initialize(MediaRecorder* recorder,
- MediaStreamDescriptor* media_stream,
- const String& type,
- const String& codecs,
- int32_t audio_bits_per_second,
- int32_t video_bits_per_second) {
+bool MediaRecorderHandler::Initialize(
+ MediaRecorder* recorder,
+ MediaStreamDescriptor* media_stream,
+ const String& type,
+ const String& codecs,
+ int32_t audio_bits_per_second,
+ int32_t video_bits_per_second,
+ AudioTrackRecorder::BitrateMode audio_bitrate_mode) {
DCHECK(IsMainThread());
// Save histogram data so we can see how much MediaStream Recorder is used.
// The histogram counts the number of calls to the JS API.
@@ -244,9 +246,14 @@ bool MediaRecorderHandler::Initialize(MediaRecorder* recorder,
audio_bits_per_second_ = audio_bits_per_second;
video_bits_per_second_ = video_bits_per_second;
+ audio_bitrate_mode_ = audio_bitrate_mode;
return true;
}
+AudioTrackRecorder::BitrateMode MediaRecorderHandler::AudioBitrateMode() {
+ return audio_bitrate_mode_;
+}
+
bool MediaRecorderHandler::Start(int timeslice) {
DCHECK(IsMainThread());
DCHECK(!recording_);
@@ -280,12 +287,14 @@ bool MediaRecorderHandler::Start(int timeslice) {
return false;
}
- webm_muxer_.reset(
- new media::WebmMuxer(CodecIdToMediaAudioCodec(audio_codec_id_),
- use_video_tracks, use_audio_tracks,
- WTF::BindRepeating(&MediaRecorderHandler::WriteData,
- WrapWeakPersistent(this))));
-
+ webm_muxer_ = std::make_unique<media::WebmMuxer>(
+ CodecIdToMediaAudioCodec(audio_codec_id_), use_video_tracks,
+ use_audio_tracks,
+ WTF::BindRepeating(&MediaRecorderHandler::WriteData,
+ WrapWeakPersistent(this)));
+ if (timeslice > 0) {
+ webm_muxer_->SetMaximumDurationToForceDataOutput(timeslice_);
+ }
if (use_video_tracks) {
// TODO(mcasas): The muxer API supports only one video track. Extend it to
// several video tracks, see http://crbug.com/528523.
@@ -294,6 +303,7 @@ bool MediaRecorderHandler::Start(int timeslice) {
<< "Only recording first video track.";
if (!video_tracks_[0])
return false;
+ UpdateTrackLiveAndEnabled(*video_tracks_[0], /*is_video=*/true);
MediaStreamVideoTrack* const video_track =
static_cast<MediaStreamVideoTrack*>(
@@ -332,6 +342,7 @@ bool MediaRecorderHandler::Start(int timeslice) {
<< " tracks is not implemented. Only recording first audio track.";
if (!audio_tracks_[0])
return false;
+ UpdateTrackLiveAndEnabled(*audio_tracks_[0], /*is_video=*/false);
const AudioTrackRecorder::OnEncodedAudioCB on_encoded_audio_cb =
media::BindToCurrentLoop(WTF::BindRepeating(
@@ -341,7 +352,8 @@ bool MediaRecorderHandler::Start(int timeslice) {
WrapWeakPersistent(this)));
audio_recorders_.emplace_back(std::make_unique<AudioTrackRecorder>(
audio_codec_id_, audio_tracks_[0], std::move(on_encoded_audio_cb),
- std::move(on_track_source_changed_cb), audio_bits_per_second_));
+ std::move(on_track_source_changed_cb), audio_bits_per_second_,
+ audio_bitrate_mode_));
}
recording_ = true;
@@ -652,23 +664,34 @@ bool MediaRecorderHandler::UpdateTracksAndCheckIfChanged() {
if (audio_tracks_changed)
audio_tracks_ = audio_tracks;
+ if (video_tracks_.size())
+ UpdateTrackLiveAndEnabled(*video_tracks_[0], /*is_video=*/true);
+ if (audio_tracks_.size())
+ UpdateTrackLiveAndEnabled(*audio_tracks_[0], /*is_video=*/false);
+
return video_tracks_changed || audio_tracks_changed;
}
+void MediaRecorderHandler::UpdateTrackLiveAndEnabled(
+ const MediaStreamComponent& track,
+ bool is_video) {
+ const bool track_live_and_enabled =
+ track.Source()->GetReadyState() == MediaStreamSource::kReadyStateLive &&
+ track.Enabled();
+ if (webm_muxer_)
+ webm_muxer_->SetLiveAndEnabled(track_live_and_enabled, is_video);
+}
+
void MediaRecorderHandler::OnSourceReadyStateChanged() {
for (const auto& track : video_tracks_) {
DCHECK(track->Source());
- if (track->Source()->GetReadyState() !=
- MediaStreamSource::kReadyStateEnded) {
+ if (track->Source()->GetReadyState() != MediaStreamSource::kReadyStateEnded)
return;
- }
}
for (const auto& track : audio_tracks_) {
DCHECK(track->Source());
- if (track->Source()->GetReadyState() !=
- MediaStreamSource::kReadyStateEnded) {
+ if (track->Source()->GetReadyState() != MediaStreamSource::kReadyStateEnded)
return;
- }
}
// All tracks are ended, so stop the recorder in accordance with
// https://www.w3.org/TR/mediastream-recording/#mediarecorder-methods.
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
index 4cc056b7be7..7eed27d301d 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
@@ -63,7 +63,11 @@ class MODULES_EXPORT MediaRecorderHandler final
const String& type,
const String& codecs,
int32_t audio_bits_per_second,
- int32_t video_bits_per_second);
+ int32_t video_bits_per_second,
+ AudioTrackRecorder::BitrateMode audio_bitrate_mode);
+
+ AudioTrackRecorder::BitrateMode AudioBitrateMode();
+
bool Start(int timeslice);
void Stop();
void Pause();
@@ -119,6 +123,8 @@ class MODULES_EXPORT MediaRecorderHandler final
void OnAudioBusForTesting(const media::AudioBus& audio_bus,
const base::TimeTicks& timestamp);
void SetAudioFormatForTesting(const media::AudioParameters& params);
+ void UpdateTrackLiveAndEnabled(const MediaStreamComponent& track,
+ bool is_video);
// Set to true if there is no MIME type configured upon Initialize()
// and the video track's source supports encoded output, giving
@@ -135,6 +141,9 @@ class MODULES_EXPORT MediaRecorderHandler final
// Audio Codec, OPUS is used by default.
AudioTrackRecorder::CodecId audio_codec_id_;
+ // Audio bitrate mode (constant, variable, etc.), VBR is used by default.
+ AudioTrackRecorder::BitrateMode audio_bitrate_mode_;
+
// |recorder_| has no notion of time, thus may configure us via
// start(timeslice) to notify it after a certain |timeslice_| has passed. We
// use a moving |slice_origin_timestamp_| to track those time chunks.
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
index 046eaa1a11b..34b9ad1ea8e 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
@@ -267,6 +267,28 @@ TEST_P(MediaRecorderHandlerTest, CanSupportMimeType) {
mime_type_audio, example_unsupported_codecs_2));
}
+// Checks that it uses the specified bitrate mode.
+TEST_P(MediaRecorderHandlerTest, SupportsBitrateMode) {
+ AddTracks();
+ V8TestingScope scope;
+ auto* recorder = MakeGarbageCollected<MockMediaRecorder>(scope);
+
+ const String mime_type(GetParam().mime_type);
+ const String codecs(GetParam().codecs);
+
+ EXPECT_TRUE(media_recorder_handler_->Initialize(
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
+ EXPECT_EQ(media_recorder_handler_->AudioBitrateMode(),
+ AudioTrackRecorder::BitrateMode::VARIABLE);
+
+ EXPECT_TRUE(media_recorder_handler_->Initialize(
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::CONSTANT));
+ EXPECT_EQ(media_recorder_handler_->AudioBitrateMode(),
+ AudioTrackRecorder::BitrateMode::CONSTANT);
+}
+
// Checks that the initialization-destruction sequence works fine.
TEST_P(MediaRecorderHandlerTest, InitializeStartStop) {
AddTracks();
@@ -275,7 +297,8 @@ TEST_P(MediaRecorderHandlerTest, InitializeStartStop) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_FALSE(recording());
EXPECT_FALSE(hasVideoRecorders());
EXPECT_FALSE(hasAudioRecorders());
@@ -310,7 +333,8 @@ TEST_P(MediaRecorderHandlerTest, EncodeVideoFrames) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
InSequence s;
@@ -400,7 +424,8 @@ TEST_P(MediaRecorderHandlerTest, OpusEncodeAudioFrames) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
InSequence s;
@@ -466,7 +491,8 @@ TEST_P(MediaRecorderHandlerTest, WebmMuxerErrorWhileEncoding) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
InSequence s;
@@ -513,7 +539,8 @@ TEST_P(MediaRecorderHandlerTest, ActualMimeType) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
StringBuilder actual_mime_type;
actual_mime_type.Append(GetParam().mime_type);
@@ -547,7 +574,8 @@ TEST_P(MediaRecorderHandlerTest, PauseRecorderForVideo) {
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
Mock::VerifyAndClearExpectations(recorder);
@@ -578,7 +606,8 @@ TEST_P(MediaRecorderHandlerTest, StartStopStartRecorderForVideo) {
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
media_recorder_handler_->Stop();
@@ -633,7 +662,8 @@ TEST_P(MediaRecorderHandlerH264ProfileTest, ActualMimeType) {
const String mime_type(GetParam().mime_type);
const String codecs(GetParam().codecs);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), mime_type, codecs, 0, 0));
+ recorder, registry_.test_stream(), mime_type, codecs, 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
String actual_mime_type =
String(GetParam().mime_type) + ";codecs=" + GetParam().codecs;
@@ -703,8 +733,9 @@ TEST_P(MediaRecorderHandlerPassthroughTest, PassesThrough) {
V8TestingScope scope;
auto* recorder = MakeGarbageCollected<MockMediaRecorder>(scope);
- media_recorder_handler_->Initialize(recorder, registry_.test_stream(), "", "",
- 0, 0);
+ media_recorder_handler_->Initialize(
+ recorder, registry_.test_stream(), "", "", 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE);
media_recorder_handler_->Start(0);
const size_t kFrameSize = 42;
@@ -736,7 +767,8 @@ TEST_F(MediaRecorderHandlerPassthroughTest, ErrorsOutOnCodecSwitch) {
V8TestingScope scope;
auto* recorder = MakeGarbageCollected<MockMediaRecorder>(scope);
EXPECT_TRUE(media_recorder_handler_->Initialize(
- recorder, registry_.test_stream(), "", "", 0, 0));
+ recorder, registry_.test_stream(), "", "", 0, 0,
+ AudioTrackRecorder::BitrateMode::VARIABLE));
EXPECT_TRUE(media_recorder_handler_->Start(0));
// NOTE, Asan: the prototype of WriteData which has a const char* as data
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_options.idl b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_options.idl
index 02a0848dbe7..0e1b40ea45f 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_options.idl
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder_options.idl
@@ -4,6 +4,8 @@
// https://w3c.github.io/mediacapture-record/#mediarecorderoptions-section
+enum BitrateMode { "constant", "variable" };
+
dictionary MediaRecorderOptions {
DOMString mimeType = ""; // Encoding mimeType.
@@ -11,4 +13,5 @@ dictionary MediaRecorderOptions {
unsigned long audioBitsPerSecond;
unsigned long videoBitsPerSecond;
unsigned long bitsPerSecond;
+ BitrateMode audioBitrateMode = "variable";
};
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
index cc649fd23b8..eb2ea71ec13 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/vea_encoder.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/mediarecorder/vea_encoder.h"
#include <string>
+#include <utility>
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
@@ -154,11 +155,10 @@ void VEAEncoder::BitstreamBufferReady(
PostCrossThreadTask(
*origin_task_runner_.get(), FROM_HERE,
- CrossThreadBindOnce(
- OnFrameEncodeCompleted,
- WTF::Passed(CrossThreadBindRepeating(on_encoded_video_cb_)),
- front_frame.first, std::move(data), std::string(), front_frame.second,
- metadata.key_frame));
+ CrossThreadBindOnce(OnFrameEncodeCompleted,
+ CrossThreadBindRepeating(on_encoded_video_cb_),
+ front_frame.first, std::move(data), std::string(),
+ front_frame.second, metadata.key_frame));
UseOutputBitstreamBufferId(bitstream_buffer_id);
}
@@ -309,7 +309,8 @@ void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size,
// Currently the VAAPI and V4L2 VEA support only native input mode with NV12
// DMA-buf buffers.
pixel_format = media::PIXEL_FORMAT_NV12;
- storage_type = media::VideoEncodeAccelerator::Config::StorageType::kDmabuf;
+ storage_type =
+ media::VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer;
}
const media::VideoEncodeAccelerator::Config config(
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index a557c58bddb..50f31738869 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -36,7 +36,6 @@
#include "third_party/blink/renderer/modules/mediarecorder/h264_encoder.h"
#endif // #if BUILDFLAG(RTC_USE_H264)
-using media::VideoFrame;
using video_track_recorder::kVEAEncoderMinResolutionHeight;
using video_track_recorder::kVEAEncoderMinResolutionWidth;
@@ -86,6 +85,24 @@ static_assert(base::size(kPreferredCodecIdAndVEAProfiles) ==
// encoder implementation.
const int kMaxNumberOfFramesInEncode = 10;
+void NotifyEncoderSupportKnown(base::OnceClosure callback) {
+ if (!Platform::Current()) {
+ DVLOG(2) << "Couldn't access the render thread";
+ std::move(callback).Run();
+ return;
+ }
+
+ media::GpuVideoAcceleratorFactories* const gpu_factories =
+ Platform::Current()->GetGpuFactories();
+ if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) {
+ DVLOG(2) << "Couldn't initialize GpuVideoAcceleratorFactories";
+ std::move(callback).Run();
+ return;
+ }
+
+ gpu_factories->NotifyEncoderSupportKnown(std::move(callback));
+}
+
// Obtains video encode accelerator's supported profiles.
media::VideoEncodeAccelerator::SupportedProfiles GetVEASupportedProfiles() {
if (!Platform::Current()) {
@@ -254,10 +271,16 @@ VideoTrackRecorderImpl::Encoder::~Encoder() {
origin_task_runner_->DeleteSoon(FROM_HERE,
std::move(num_frames_in_encode_));
}
+ if (encoder_thread_context_ &&
+ !encoding_task_runner_->RunsTasksInCurrentSequence()) {
+ encoding_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(encoder_thread_context_));
+ }
}
void VideoTrackRecorderImpl::Encoder::StartFrameEncode(
- scoped_refptr<VideoFrame> video_frame,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_video_frames*/,
base::TimeTicks capture_timestamp) {
// Cache the thread sending frames on first frame arrival.
if (!origin_task_runner_.get())
@@ -267,23 +290,19 @@ void VideoTrackRecorderImpl::Encoder::StartFrameEncode(
if (paused_)
return;
- const bool is_format_supported =
- video_frame->format() == media::PIXEL_FORMAT_I420 ||
- video_frame->format() == media::PIXEL_FORMAT_ARGB ||
- video_frame->format() == media::PIXEL_FORMAT_ABGR ||
- video_frame->format() == media::PIXEL_FORMAT_I420A ||
- video_frame->format() == media::PIXEL_FORMAT_NV12 ||
- video_frame->format() == media::PIXEL_FORMAT_XRGB;
-
if (num_frames_in_encode_->count() > kMaxNumberOfFramesInEncode) {
DLOG(WARNING) << "Too many frames are queued up. Dropping this one.";
return;
}
- if (!is_format_supported ||
- (video_frame->HasTextures() &&
- video_frame->storage_type() !=
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER)) {
+ // The recorder currently does not consider scaled versions of the frame.
+ const bool is_format_supported =
+ (video_frame->format() == media::PIXEL_FORMAT_NV12 &&
+ video_frame->HasGpuMemoryBuffer()) ||
+ (video_frame->IsMappable() &&
+ (video_frame->format() == media::PIXEL_FORMAT_I420 ||
+ video_frame->format() == media::PIXEL_FORMAT_I420A));
+ if (!is_format_supported) {
PostCrossThreadTask(
*encoding_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&Encoder::RetrieveFrameOnEncodingTaskRunner,
@@ -294,7 +313,7 @@ void VideoTrackRecorderImpl::Encoder::StartFrameEncode(
}
scoped_refptr<media::VideoFrame> frame = video_frame;
- if (frame->storage_type() != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
+ if (!video_frame->HasGpuMemoryBuffer()) {
// Drop alpha channel if the encoder does not support it yet.
if (!CanEncodeAlphaChannel() &&
video_frame->format() == media::PIXEL_FORMAT_I420A) {
@@ -317,7 +336,7 @@ void VideoTrackRecorderImpl::Encoder::StartFrameEncode(
}
void VideoTrackRecorderImpl::Encoder::RetrieveFrameOnEncodingTaskRunner(
- scoped_refptr<VideoFrame> video_frame,
+ scoped_refptr<media::VideoFrame> video_frame,
base::TimeTicks capture_timestamp) {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoding_sequence_checker_);
@@ -360,8 +379,10 @@ void VideoTrackRecorderImpl::Encoder::RetrieveFrameOnEncodingTaskRunner(
const gfx::Size& old_visible_size = video_frame->visible_rect().size();
gfx::Size new_visible_size = old_visible_size;
- media::VideoRotation video_rotation =
- video_frame->metadata()->rotation.value_or(media::VIDEO_ROTATION_0);
+ media::VideoRotation video_rotation = media::VIDEO_ROTATION_0;
+ if (video_frame->metadata().transformation)
+ video_rotation = video_frame->metadata().transformation->rotation;
+
if (video_rotation == media::VIDEO_ROTATION_90 ||
video_rotation == media::VIDEO_ROTATION_270) {
new_visible_size.SetSize(old_visible_size.height(),
@@ -463,20 +484,17 @@ bool VideoTrackRecorderImpl::Encoder::CanEncodeAlphaChannel() {
scoped_refptr<media::VideoFrame>
VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
scoped_refptr<media::VideoFrame> frame) {
- DCHECK_EQ(frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
- // NV12 is currently the only supported pixel format for GpuMemoryBuffer.
DCHECK_EQ(frame->format(), media::VideoPixelFormat::PIXEL_FORMAT_NV12);
- auto* gmb = frame->GetGpuMemoryBuffer();
- if (!gmb->Map())
- return frame;
+ if (frame->GetGpuMemoryBuffer())
+ frame = media::ConvertToMemoryMappedFrame(frame);
+
scoped_refptr<media::VideoFrame> i420_frame = frame_pool_.CreateFrame(
media::VideoPixelFormat::PIXEL_FORMAT_I420, frame->coded_size(),
frame->visible_rect(), frame->natural_size(), frame->timestamp());
auto ret = libyuv::NV12ToI420(
- static_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
- static_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
+ static_cast<const uint8_t*>(frame->data(0)), frame->stride(0),
+ static_cast<const uint8_t*>(frame->data(1)), frame->stride(1),
i420_frame->data(media::VideoFrame::kYPlane),
i420_frame->stride(media::VideoFrame::kYPlane),
i420_frame->data(media::VideoFrame::kUPlane),
@@ -484,57 +502,12 @@ VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
i420_frame->data(media::VideoFrame::kVPlane),
i420_frame->stride(media::VideoFrame::kVPlane),
frame->coded_size().width(), frame->coded_size().height());
- gmb->Unmap();
if (ret)
return frame;
return i420_frame;
}
// static
-scoped_refptr<media::VideoFrame>
-VideoTrackRecorderImpl::Encoder::WrapMappedGpuMemoryBufferVideoFrame(
- scoped_refptr<media::VideoFrame> video_frame) {
- DCHECK(video_frame);
- DCHECK_EQ(video_frame->storage_type(),
- media::VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER);
-
- auto* gmb = video_frame->GetGpuMemoryBuffer();
- DCHECK(gmb);
-
- if (!gmb->Map()) {
- LOG(WARNING) << "Failed to map GpuMemoryBuffer";
- return nullptr;
- }
-
- const size_t num_planes = media::VideoFrame::NumPlanes(video_frame->format());
- uint8_t* plane_addrs[media::VideoFrame::kMaxPlanes] = {};
- for (size_t i = 0; i < num_planes; i++)
- plane_addrs[i] = static_cast<uint8_t*>(gmb->memory(i));
-
- auto mapped_frame = media::VideoFrame::WrapExternalYuvDataWithLayout(
- video_frame->layout(), video_frame->visible_rect(),
- video_frame->natural_size(), plane_addrs[0], plane_addrs[1],
- plane_addrs[2], video_frame->timestamp());
-
- if (!mapped_frame) {
- gmb->Unmap();
- return nullptr;
- }
-
- mapped_frame->set_color_space(video_frame->ColorSpace());
-
- // Pass |video_frame| so that it outlives |mapped_frame| and the mapped buffer
- // is unmapped on destruction.
- mapped_frame->AddDestructionObserver(WTF::Bind(
- [](scoped_refptr<media::VideoFrame> frame) {
- DCHECK(frame->HasGpuMemoryBuffer());
- frame->GetGpuMemoryBuffer()->Unmap();
- },
- std::move(video_frame)));
- return mapped_frame;
-}
-
-// static
VideoTrackRecorderImpl::CodecId VideoTrackRecorderImpl::GetPreferredCodecId() {
return GetCodecEnumerator()->GetPreferredCodecId();
}
@@ -626,10 +599,11 @@ void VideoTrackRecorderImpl::OnVideoFrameForTesting(
if (!encoder_) {
DCHECK(!initialize_encoder_cb_.is_null());
- initialize_encoder_cb_.Run(true /* allow_vea_encoder */, frame, timestamp);
+ initialize_encoder_cb_.Run(/*allow_vea_encoder=*/true, frame, {},
+ timestamp);
}
- encoder_->StartFrameEncode(std::move(frame), timestamp);
+ encoder_->StartFrameEncode(std::move(frame), {}, timestamp);
}
void VideoTrackRecorderImpl::InitializeEncoder(
@@ -637,6 +611,35 @@ void VideoTrackRecorderImpl::InitializeEncoder(
const OnEncodedVideoCB& on_encoded_video_cb,
int32_t bits_per_second,
bool allow_vea_encoder,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_video_frames*/,
+ base::TimeTicks capture_time) {
+ DVLOG(3) << __func__ << video_frame->visible_rect().size().ToString();
+ DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
+
+ // Scaled video frames are currently ignored.
+ auto on_encoder_support_known_cb = WTF::Bind(
+ &VideoTrackRecorderImpl::InitializeEncoderOnEncoderSupportKnown,
+ weak_factory_.GetWeakPtr(), codec_profile, on_encoded_video_cb,
+ bits_per_second, allow_vea_encoder, std::move(video_frame), capture_time);
+
+ if (!allow_vea_encoder) {
+ // If HW encoding is not being used, no need to wait for encoder
+ // enumeration.
+ std::move(on_encoder_support_known_cb).Run();
+ return;
+ }
+
+ // Delay initializing the encoder until HW support is known, so that
+ // CanUseAcceleratedEncoder() can give a reliable and consistent answer.
+ NotifyEncoderSupportKnown(std::move(on_encoder_support_known_cb));
+}
+
+void VideoTrackRecorderImpl::InitializeEncoderOnEncoderSupportKnown(
+ CodecProfile codec_profile,
+ const OnEncodedVideoCB& on_encoded_video_cb,
+ int32_t bits_per_second,
+ bool allow_vea_encoder,
scoped_refptr<media::VideoFrame> frame,
base::TimeTicks capture_time) {
DVLOG(3) << __func__ << frame->visible_rect().size().ToString();
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
index 2a42fc1a8fc..4a3626a68aa 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
@@ -152,8 +152,10 @@ class VideoTrackRecorder : public TrackRecorder<MediaStreamVideoSink> {
// encode the frame. If the |frame|'s data is not directly available (e.g.
// it's a texture) then RetrieveFrameOnEncoderThread() is called, and if
// even that fails, black frames are sent instead.
- void StartFrameEncode(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks capture_timestamp);
+ void StartFrameEncode(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks capture_timestamp);
void RetrieveFrameOnEncodingTaskRunner(
scoped_refptr<media::VideoFrame> video_frame,
base::TimeTicks capture_timestamp);
@@ -203,12 +205,6 @@ class VideoTrackRecorder : public TrackRecorder<MediaStreamVideoSink> {
scoped_refptr<media::VideoFrame> ConvertToI420ForSoftwareEncoder(
scoped_refptr<media::VideoFrame> frame);
- // A helper function to map GpuMemoryBuffer-based VideoFrame. This function
- // maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
- // format. The returned VideoFrame owns the |frame|.
- static scoped_refptr<media::VideoFrame> WrapMappedGpuMemoryBufferVideoFrame(
- scoped_refptr<media::VideoFrame> frame);
-
// Used to shutdown properly on the same thread we were created.
const scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
@@ -335,12 +331,21 @@ class MODULES_EXPORT VideoTrackRecorderImpl : public VideoTrackRecorder {
private:
friend class VideoTrackRecorderTest;
- void InitializeEncoder(CodecProfile codec,
- const OnEncodedVideoCB& on_encoded_video_cb,
- int32_t bits_per_second,
- bool allow_vea_encoder,
- scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks capture_time);
+ void InitializeEncoder(
+ CodecProfile codec,
+ const OnEncodedVideoCB& on_encoded_video_cb,
+ int32_t bits_per_second,
+ bool allow_vea_encoder,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks capture_time);
+ void InitializeEncoderOnEncoderSupportKnown(
+ CodecProfile codec_profile,
+ const OnEncodedVideoCB& on_encoded_video_cb,
+ int32_t bits_per_second,
+ bool allow_vea_encoder,
+ scoped_refptr<media::VideoFrame> frame,
+ base::TimeTicks capture_time);
void OnError();
void ConnectToTrack(const VideoCaptureDeliverFrameCB& callback);
@@ -355,9 +360,11 @@ class MODULES_EXPORT VideoTrackRecorderImpl : public VideoTrackRecorder {
// Inner class to encode using whichever codec is configured.
scoped_refptr<Encoder> encoder_;
- base::RepeatingCallback<void(bool allow_vea_encoder,
- scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks capture_time)>
+ base::RepeatingCallback<void(
+ bool allow_vea_encoder,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks capture_time)>
initialize_encoder_cb_;
bool should_pause_encoder_on_initialization_;
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder_unittest.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder_unittest.cc
index 52c87d28284..c534e793c00 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder_unittest.cc
@@ -8,8 +8,11 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
#include "media/base/video_codecs.h"
#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "media/video/mock_gpu_video_accelerator_factories.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"
@@ -30,7 +33,6 @@
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "ui/gfx/gpu_memory_buffer.h"
-using media::VideoFrame;
using video_track_recorder::kVEAEncoderMinResolutionHeight;
using video_track_recorder::kVEAEncoderMinResolutionWidth;
@@ -44,10 +46,18 @@ using ::testing::TestWithParam;
using ::testing::ValuesIn;
namespace blink {
+namespace {
-ACTION_P(RunClosure, closure) {
- closure.Run();
-}
+// Specifies frame type for test.
+enum class TestFrameType {
+ kNv12GpuMemoryBuffer, // Implies media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER
+ kNv12Software, // Implies media::VideoFrame::STORAGE_OWNED_MEMORY
+ kI420 // Implies media::VideoFrame::STORAGE_OWNED_MEMORY
+};
+
+const TestFrameType kTestFrameTypes[] = {TestFrameType::kNv12GpuMemoryBuffer,
+ TestFrameType::kNv12Software,
+ TestFrameType::kI420};
const VideoTrackRecorder::CodecId kTrackRecorderTestCodec[] = {
VideoTrackRecorder::CodecId::VP8, VideoTrackRecorder::CodecId::VP9
@@ -60,12 +70,10 @@ const gfx::Size kTrackRecorderTestSize[] = {
gfx::Size(kVEAEncoderMinResolutionWidth / 2,
kVEAEncoderMinResolutionHeight / 2),
gfx::Size(kVEAEncoderMinResolutionWidth, kVEAEncoderMinResolutionHeight)};
-const media::VideoFrame::StorageType kStorageTypeToTest[] = {
- media::VideoFrame::STORAGE_OWNED_MEMORY,
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER};
static const int kTrackRecorderTestSizeDiff = 20;
-media::VideoCodec MediaVideoCodecFromCodecId(VideoTrackRecorder::CodecId id) {
+constexpr media::VideoCodec MediaVideoCodecFromCodecId(
+ VideoTrackRecorder::CodecId id) {
switch (id) {
case VideoTrackRecorder::CodecId::VP8:
return media::kCodecVP8;
@@ -82,11 +90,28 @@ media::VideoCodec MediaVideoCodecFromCodecId(VideoTrackRecorder::CodecId id) {
return media::kUnknownVideoCodec;
}
+} // namespace
+
+ACTION_P(RunClosure, closure) {
+ closure.Run();
+}
+
+class MockTestingPlatform : public IOTaskRunnerTestingPlatformSupport {
+ public:
+ MockTestingPlatform() = default;
+ ~MockTestingPlatform() override = default;
+
+ MOCK_METHOD0(GetGpuFactories, media::GpuVideoAcceleratorFactories*());
+};
+
+// TODO(crbug/1177593): refactor the test parameter space to something more
+// reasonable. Many tests below ignore parts of the space leading to too much
+// being tested.
class VideoTrackRecorderTest
: public TestWithParam<testing::tuple<VideoTrackRecorder::CodecId,
gfx::Size,
bool,
- media::VideoFrame::StorageType>> {
+ TestFrameType>> {
public:
VideoTrackRecorderTest() : mock_source_(new MockMediaStreamVideoSource()) {
const String track_id("dummy");
@@ -109,9 +134,11 @@ class VideoTrackRecorderTest
source_->GetPlatformSource());
EXPECT_TRUE(scheduler::GetSingleThreadTaskRunnerForTesting()
->BelongsToCurrentThread());
+
+ ON_CALL(*platform_, GetGpuFactories()).WillByDefault(Return(nullptr));
}
- ~VideoTrackRecorderTest() {
+ ~VideoTrackRecorderTest() override {
component_ = nullptr;
source_ = nullptr;
video_track_recorder_.reset();
@@ -144,7 +171,8 @@ class VideoTrackRecorderTest
base::TimeTicks timestamp,
bool keyframe));
- void Encode(scoped_refptr<VideoFrame> frame, base::TimeTicks capture_time) {
+ void Encode(scoped_refptr<media::VideoFrame> frame,
+ base::TimeTicks capture_time) {
EXPECT_TRUE(scheduler::GetSingleThreadTaskRunnerForTesting()
->BelongsToCurrentThread());
video_track_recorder_->OnVideoFrameForTesting(std::move(frame),
@@ -163,7 +191,7 @@ class VideoTrackRecorderTest
return video_track_recorder_->encoder_->num_frames_in_encode_->count();
}
- ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+ ScopedTestingPlatformSupport<MockTestingPlatform> platform_;
// All members are non-const due to the series of initialize() calls needed.
// |mock_source_| is owned by |source_|, |track_| by |component_|.
@@ -174,6 +202,43 @@ class VideoTrackRecorderTest
std::unique_ptr<VideoTrackRecorderImpl> video_track_recorder_;
+ protected:
+ scoped_refptr<media::VideoFrame> CreateFrameForTest(
+ TestFrameType frame_type,
+ const gfx::Size& frame_size,
+ bool encode_alpha_channel,
+ int padding) {
+ const gfx::Size padded_size(frame_size.width() + padding,
+ frame_size.height());
+ if (frame_type == TestFrameType::kI420) {
+ return media::VideoFrame::CreateZeroInitializedFrame(
+ encode_alpha_channel ? media::PIXEL_FORMAT_I420A
+ : media::PIXEL_FORMAT_I420,
+ padded_size, gfx::Rect(frame_size), frame_size, base::TimeDelta());
+ }
+
+ scoped_refptr<media::VideoFrame> video_frame = blink::CreateTestFrame(
+ padded_size, gfx::Rect(frame_size), frame_size,
+ frame_type == TestFrameType::kNv12Software
+ ? media::VideoFrame::STORAGE_OWNED_MEMORY
+ : media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ scoped_refptr<media::VideoFrame> video_frame2 = video_frame;
+ if (frame_type == TestFrameType::kNv12GpuMemoryBuffer)
+ video_frame2 = media::ConvertToMemoryMappedFrame(video_frame);
+
+ // Fade to black.
+ const uint8_t kBlackY = 0x00;
+ const uint8_t kBlackUV = 0x80;
+ memset(static_cast<uint8_t*>(video_frame2->data(0)), kBlackY,
+ video_frame2->stride(0) * frame_size.height());
+ memset(static_cast<uint8_t*>(video_frame2->data(1)), kBlackUV,
+ video_frame2->stride(1) * (frame_size.height() / 2));
+ if (frame_type == TestFrameType::kNv12GpuMemoryBuffer)
+ return video_frame;
+ return video_frame2;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(VideoTrackRecorderTest);
};
@@ -201,54 +266,20 @@ TEST_P(VideoTrackRecorderTest, VideoEncoding) {
const bool encode_alpha_channel = testing::get<2>(GetParam());
// |frame_size| cannot be arbitrarily small, should be reasonable.
const gfx::Size& frame_size = testing::get<1>(GetParam());
- const media::VideoFrame::StorageType storage_type =
- testing::get<3>(GetParam());
+ const TestFrameType test_frame_type = testing::get<3>(GetParam());
// We don't support alpha channel with GpuMemoryBuffer frames.
- if (storage_type == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER &&
- encode_alpha_channel) {
+ if (test_frame_type != TestFrameType::kI420 && encode_alpha_channel) {
return;
}
- auto create_test_frame =
- [](media::VideoFrame::StorageType storage_type,
- const gfx::Size& frame_size,
- bool encode_alpha_channel) -> scoped_refptr<VideoFrame> {
- scoped_refptr<VideoFrame> video_frame;
- switch (storage_type) {
- case media::VideoFrame::STORAGE_OWNED_MEMORY:
- video_frame = encode_alpha_channel
- ? VideoFrame::CreateTransparentFrame(frame_size)
- : VideoFrame::CreateBlackFrame(frame_size);
- break;
- case media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER: {
- video_frame = CreateTestFrame(frame_size, gfx::Rect(frame_size),
- frame_size, storage_type);
- // Create a black NV12 frame.
- auto* gmb = video_frame->GetGpuMemoryBuffer();
- gmb->Map();
- const uint8_t kBlackY = 0x00;
- const uint8_t kBlackUV = 0x80;
- memset(static_cast<uint8_t*>(gmb->memory(0)), kBlackY,
- gmb->stride(0) * frame_size.height());
- memset(static_cast<uint8_t*>(gmb->memory(1)), kBlackUV,
- gmb->stride(1) * (frame_size.height() / 2));
- gmb->Unmap();
- break;
- }
- default:
- DLOG(ERROR) << "Unexpected storage type";
- }
- return video_frame;
- };
-
- const scoped_refptr<VideoFrame> video_frame =
- create_test_frame(storage_type, frame_size, encode_alpha_channel);
+ const scoped_refptr<media::VideoFrame> video_frame = CreateFrameForTest(
+ test_frame_type, frame_size, encode_alpha_channel, /*padding=*/0);
if (!video_frame)
ASSERT_TRUE(!!video_frame);
const double kFrameRate = 60.0f;
- video_frame->metadata()->frame_rate = kFrameRate;
+ video_frame->metadata().frame_rate = kFrameRate;
InSequence s;
const base::TimeTicks timeticks_now = base::TimeTicks::Now();
@@ -273,8 +304,8 @@ TEST_P(VideoTrackRecorderTest, VideoEncoding) {
// Send another Video Frame and expect only an OnEncodedVideo() callback.
const gfx::Size frame_size2(frame_size.width() + kTrackRecorderTestSizeDiff,
frame_size.height());
- const scoped_refptr<VideoFrame> video_frame2 =
- create_test_frame(storage_type, frame_size2, encode_alpha_channel);
+ const scoped_refptr<media::VideoFrame> video_frame2 = CreateFrameForTest(
+ test_frame_type, frame_size2, encode_alpha_channel, /*padding=*/0);
base::RunLoop run_loop;
@@ -295,8 +326,8 @@ TEST_P(VideoTrackRecorderTest, VideoEncoding) {
EXPECT_GE(third_frame_encoded_data.size(), kEncodedSizeThreshold);
// We only support NV12 with GpuMemoryBuffer video frame.
- if (storage_type != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER &&
- encode_alpha_channel && CanEncodeAlphaChannel()) {
+ if (test_frame_type == TestFrameType::kI420 && encode_alpha_channel &&
+ CanEncodeAlphaChannel()) {
EXPECT_GE(first_frame_encoded_alpha.size(), kEncodedSizeThreshold);
EXPECT_GE(second_frame_encoded_alpha.size(), kEncodedSizeThreshold);
EXPECT_GE(third_frame_encoded_alpha.size(), kEncodedSizeThreshold);
@@ -317,24 +348,46 @@ TEST_P(VideoTrackRecorderTest, EncodeFrameWithPaddedCodedSize) {
const gfx::Size& frame_size = testing::get<1>(GetParam());
const size_t kCodedSizePadding = 16;
- const media::VideoFrame::StorageType storage_type =
- testing::get<3>(GetParam());
- const gfx::Size padded_size(frame_size.width() + kCodedSizePadding,
- frame_size.height());
- scoped_refptr<VideoFrame> video_frame;
- switch (storage_type) {
- case media::VideoFrame::STORAGE_OWNED_MEMORY:
- video_frame = VideoFrame::CreateZeroInitializedFrame(
- media::PIXEL_FORMAT_I420, padded_size, gfx::Rect(frame_size),
- frame_size, base::TimeDelta());
- break;
- case media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER:
- video_frame = CreateTestFrame(padded_size, gfx::Rect(frame_size),
- frame_size, storage_type);
- break;
- default:
- NOTREACHED() << "Unexpected storage type";
- }
+ const TestFrameType test_frame_type = testing::get<3>(GetParam());
+ scoped_refptr<media::VideoFrame> video_frame =
+ CreateFrameForTest(test_frame_type, frame_size,
+ /*encode_alpha_channel=*/false, kCodedSizePadding);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true))
+ .Times(1)
+ .WillOnce(RunClosure(run_loop.QuitClosure()));
+ Encode(video_frame, base::TimeTicks::Now());
+ run_loop.Run();
+
+ Mock::VerifyAndClearExpectations(this);
+}
+
+TEST_P(VideoTrackRecorderTest, EncodeFrameRGB) {
+ InitializeRecorder(testing::get<0>(GetParam()));
+
+ const gfx::Size& frame_size = testing::get<1>(GetParam());
+ // TODO(crbug/1177593): Refactor test harness to use a cleaner parameter
+ // space.
+ if (testing::get<2>(GetParam()))
+ return;
+ // TODO(crbug/1177593): Refactor test harness to use a cleaner parameter
+ // space.
+ // Let kI420 indicate owned memory, and kNv12GpuMemoryBuffer to indicate GMB
+ // storage. Don't test for kNv12Software.
+ const TestFrameType test_frame_type = testing::get<3>(GetParam());
+ if (test_frame_type == TestFrameType::kNv12Software)
+ return;
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ test_frame_type == TestFrameType::kI420
+ ? media::VideoFrame::CreateZeroInitializedFrame(
+ media::PIXEL_FORMAT_XRGB, frame_size, gfx::Rect(frame_size),
+ frame_size, base::TimeDelta())
+ : blink::CreateTestFrame(frame_size, gfx::Rect(frame_size),
+ frame_size,
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
+ media::PIXEL_FORMAT_XRGB);
base::RunLoop run_loop;
EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true))
@@ -352,8 +405,8 @@ TEST_F(VideoTrackRecorderTest, ForceKeyframeOnAlphaSwitch) {
InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
const gfx::Size& frame_size = kTrackRecorderTestSize[0];
- const scoped_refptr<VideoFrame> opaque_frame =
- VideoFrame::CreateBlackFrame(frame_size);
+ const scoped_refptr<media::VideoFrame> opaque_frame =
+ media::VideoFrame::CreateBlackFrame(frame_size);
InSequence s;
base::StringPiece first_frame_encoded_alpha;
@@ -362,8 +415,8 @@ TEST_F(VideoTrackRecorderTest, ForceKeyframeOnAlphaSwitch) {
.WillOnce(SaveArg<2>(&first_frame_encoded_alpha));
Encode(opaque_frame, base::TimeTicks::Now());
- const scoped_refptr<VideoFrame> alpha_frame =
- VideoFrame::CreateTransparentFrame(frame_size);
+ const scoped_refptr<media::VideoFrame> alpha_frame =
+ media::VideoFrame::CreateTransparentFrame(frame_size);
base::StringPiece second_frame_encoded_alpha;
EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true))
.Times(1)
@@ -392,8 +445,8 @@ TEST_F(VideoTrackRecorderTest, HandlesOnError) {
InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
const gfx::Size& frame_size = kTrackRecorderTestSize[0];
- const scoped_refptr<VideoFrame> video_frame =
- VideoFrame::CreateBlackFrame(frame_size);
+ const scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateBlackFrame(frame_size);
InSequence s;
EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true)).Times(1);
@@ -419,8 +472,8 @@ TEST_F(VideoTrackRecorderTest, ReleasesFrame) {
InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
const gfx::Size& frame_size = kTrackRecorderTestSize[0];
- scoped_refptr<VideoFrame> video_frame =
- VideoFrame::CreateBlackFrame(frame_size);
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateBlackFrame(frame_size);
base::RunLoop run_loop;
bool frame_is_destroyed = false;
@@ -439,6 +492,28 @@ TEST_F(VideoTrackRecorderTest, ReleasesFrame) {
Mock::VerifyAndClearExpectations(this);
}
+// Waits for HW encoder support to be enumerated before setting up and
+// performing an encode.
+TEST_F(VideoTrackRecorderTest, WaitForEncoderSupport) {
+ media::MockGpuVideoAcceleratorFactories mock_gpu_factories(nullptr);
+ EXPECT_CALL(*platform_, GetGpuFactories())
+ .WillRepeatedly(Return(&mock_gpu_factories));
+
+ EXPECT_CALL(mock_gpu_factories, NotifyEncoderSupportKnown(_))
+ .WillOnce(base::test::RunOnceClosure<0>());
+ InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
+
+ const gfx::Size& frame_size = kTrackRecorderTestSize[0];
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateBlackFrame(frame_size);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true))
+ .WillOnce(RunClosure(run_loop.QuitWhenIdleClosure()));
+ Encode(video_frame, base::TimeTicks::Now());
+ run_loop.Run();
+}
+
TEST_F(VideoTrackRecorderTest, RequiredRefreshRate) {
// |RequestRefreshFrame| will be called first by |AddSink| and the second time
// by the refresh timer using the required min fps.
@@ -457,7 +532,7 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::Combine(ValuesIn(kTrackRecorderTestCodec),
ValuesIn(kTrackRecorderTestSize),
::testing::Bool(),
- ValuesIn(kStorageTypeToTest)));
+ ValuesIn(kTestFrameTypes)));
class VideoTrackRecorderPassthroughTest
: public TestWithParam<VideoTrackRecorder::CodecId> {
diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/vpx_encoder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/vpx_encoder.cc
index 93c25da07d0..31e1f8cd273 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/vpx_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/vpx_encoder.cc
@@ -5,9 +5,11 @@
#include "third_party/blink/renderer/modules/mediarecorder/vpx_encoder.h"
#include <algorithm>
+#include <utility>
#include "base/system/sys_info.h"
#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
@@ -74,7 +76,7 @@ void VpxEncoder::EncodeOnEncodingTaskRunner(scoped_refptr<VideoFrame> frame,
if (frame->format() == media::PIXEL_FORMAT_NV12 &&
frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER)
- frame = WrapMappedGpuMemoryBufferVideoFrame(frame);
+ frame = media::ConvertToMemoryMappedFrame(frame);
if (!frame) {
LOG(WARNING) << "Invalid video frame to encode";
return;
@@ -173,11 +175,10 @@ void VpxEncoder::EncodeOnEncodingTaskRunner(scoped_refptr<VideoFrame> frame,
PostCrossThreadTask(
*origin_task_runner_.get(), FROM_HERE,
- CrossThreadBindOnce(
- OnFrameEncodeCompleted,
- WTF::Passed(CrossThreadBindRepeating(on_encoded_video_cb_)),
- video_params, std::move(data), std::move(alpha_data),
- capture_timestamp, keyframe));
+ CrossThreadBindOnce(OnFrameEncodeCompleted,
+ CrossThreadBindRepeating(on_encoded_video_cb_),
+ video_params, std::move(data), std::move(alpha_data),
+ capture_timestamp, keyframe));
}
void VpxEncoder::DoEncode(vpx_codec_ctx_t* const encoder,
@@ -344,7 +345,7 @@ base::TimeDelta VpxEncoder::EstimateFrameDuration(const VideoFrame& frame) {
base::TimeDelta predicted_frame_duration =
frame.timestamp() - last_frame_timestamp_;
base::TimeDelta frame_duration =
- frame.metadata()->frame_duration.value_or(predicted_frame_duration);
+ frame.metadata().frame_duration.value_or(predicted_frame_duration);
last_frame_timestamp_ = frame.timestamp();
// Make sure |frame_duration| is in a safe range of values.
const base::TimeDelta kMaxFrameDuration =
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediasession/BUILD.gn
index ba7c6c8eea6..812b1b19d48 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediasession/BUILD.gn
@@ -12,8 +12,6 @@ blink_modules_sources("mediasession") {
"media_metadata_sanitizer.h",
"media_session.cc",
"media_session.h",
- "navigator_media_session.cc",
- "navigator_media_session.h",
"type_converters.cc",
"type_converters.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/DIR_METADATA b/chromium/third_party/blink/renderer/modules/mediasession/DIR_METADATA
new file mode 100644
index 00000000000..3d5ee218827
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasession/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>Session"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/OWNERS b/chromium/third_party/blink/renderer/modules/mediasession/OWNERS
index 12bd2f3d66b..2a73d29485e 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/mediasession/OWNERS
@@ -1,9 +1,5 @@
-beccahughes@chromium.org
foolip@chromium.org
mlamouri@chromium.org
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media>Session
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc
index 918e2ad1d59..2c3e4654b69 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc
@@ -125,6 +125,7 @@ void MediaMetadata::SetArtworkInternal(
void MediaMetadata::Trace(Visitor* visitor) const {
visitor->Trace(artwork_);
visitor->Trace(session_);
+ visitor->Trace(notify_session_timer_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.h b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.h
index 1f7306b8305..925d6bcf3a6 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.h
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.h
@@ -78,7 +78,7 @@ class MODULES_EXPORT MediaMetadata final : public ScriptWrappable {
HeapVector<Member<MediaImage>> artwork_;
Member<MediaSession> session_;
- TaskRunnerTimer<MediaMetadata> notify_session_timer_;
+ HeapTaskRunnerTimer<MediaMetadata> notify_session_timer_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
index d273dfaab50..7cbfdaf9391 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc
@@ -13,9 +13,9 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_session_action_details.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_session_action_handler.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_session_seek_to_action_details.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/core/frame/web_feature.h"
#include "third_party/blink/renderer/modules/mediasession/media_metadata.h"
#include "third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h"
@@ -125,11 +125,23 @@ mojom::blink::MediaSessionPlaybackState StringToMediaSessionPlaybackState(
} // anonymous namespace
-MediaSession::MediaSession(ExecutionContext* execution_context)
- : ExecutionContextClient(execution_context),
+const char MediaSession::kSupplementName[] = "MediaSession";
+
+MediaSession* MediaSession::mediaSession(Navigator& navigator) {
+ MediaSession* supplement =
+ Supplement<Navigator>::From<MediaSession>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<MediaSession>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+MediaSession::MediaSession(Navigator& navigator)
+ : Supplement<Navigator>(navigator),
clock_(base::DefaultTickClock::GetInstance()),
playback_state_(mojom::blink::MediaSessionPlaybackState::NONE),
- client_receiver_(this, execution_context) {}
+ client_receiver_(this, navigator.DomWindow()) {}
void MediaSession::setPlaybackState(const String& playback_state) {
playback_state_ = StringToMediaSessionPlaybackState(playback_state);
@@ -166,21 +178,22 @@ void MediaSession::OnMetadataChanged() {
return;
service->SetMetadata(MediaMetadataSanitizer::SanitizeAndConvertToMojo(
- metadata_, GetExecutionContext()));
+ metadata_, GetSupplementable()->DomWindow()));
}
void MediaSession::setActionHandler(const String& action,
V8MediaSessionActionHandler* handler,
ExceptionState& exception_state) {
if (action == "skipad") {
- if (!RuntimeEnabledFeatures::SkipAdEnabled(GetExecutionContext())) {
+ LocalDOMWindow* window = GetSupplementable()->DomWindow();
+ if (!RuntimeEnabledFeatures::SkipAdEnabled(window)) {
exception_state.ThrowTypeError(
"The provided value 'skipad' is not a valid enum "
"value of type MediaSessionAction.");
return;
}
- UseCounter::Count(GetExecutionContext(), WebFeature::kMediaSessionSkipAd);
+ UseCounter::Count(window, WebFeature::kMediaSessionSkipAd);
}
if (handler) {
@@ -324,13 +337,13 @@ void MediaSession::RecalculatePositionState(bool was_set) {
mojom::blink::MediaSessionService* MediaSession::GetService() {
if (service_)
return service_.get();
- if (!GetExecutionContext())
+ LocalDOMWindow* window = GetSupplementable()->DomWindow();
+ if (!window)
return nullptr;
// See https://bit.ly/2S0zRAS for task types.
- auto task_runner =
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
- GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
+ auto task_runner = window->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ window->GetBrowserInterfaceBroker().GetInterface(
service_.BindNewPipeAndPassReceiver());
if (service_.get())
service_->SetClient(client_receiver_.BindNewPipeAndPassRemote(task_runner));
@@ -341,10 +354,11 @@ mojom::blink::MediaSessionService* MediaSession::GetService() {
void MediaSession::DidReceiveAction(
media_session::mojom::blink::MediaSessionAction action,
mojom::blink::MediaSessionActionDetailsPtr details) {
- if (!GetExecutionContext())
+ LocalDOMWindow* window = GetSupplementable()->DomWindow();
+ if (!window)
return;
LocalFrame::NotifyUserActivation(
- To<LocalDOMWindow>(GetExecutionContext())->GetFrame(),
+ window->GetFrame(),
mojom::blink::UserActivationNotificationType::kInteraction);
auto& name = MojomActionToActionName(action);
@@ -366,7 +380,7 @@ void MediaSession::Trace(Visitor* visitor) const {
visitor->Trace(metadata_);
visitor->Trace(action_handlers_);
ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
+ Supplement<Navigator>::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.h b/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
index cad0af98299..767ebea8a49 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.h
@@ -8,12 +8,12 @@
#include <memory>
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/mediasession/media_session.mojom-blink.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace base {
@@ -22,20 +22,22 @@ class TickClock;
namespace blink {
-class ExecutionContext;
class ExceptionState;
class MediaMetadata;
class MediaPositionState;
+class Navigator;
class V8MediaSessionActionHandler;
class MODULES_EXPORT MediaSession final
: public ScriptWrappable,
- public ExecutionContextClient,
+ public Supplement<Navigator>,
public blink::mojom::blink::MediaSessionClient {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit MediaSession(ExecutionContext*);
+ static const char kSupplementName[];
+ static MediaSession* mediaSession(Navigator&);
+ explicit MediaSession(Navigator&);
void setPlaybackState(const String&);
String playbackState();
@@ -74,7 +76,7 @@ class MODULES_EXPORT MediaSession final
void DidReceiveAction(media_session::mojom::blink::MediaSessionAction,
mojom::blink::MediaSessionActionDetailsPtr) override;
- // Returns null when the ExecutionContext is not document.
+ // Returns null if the associated window is detached.
mojom::blink::MediaSessionService* GetService();
const base::TickClock* clock_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session_test.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_session_test.cc
index bb88e9f897e..2516aa323e5 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/media_session_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session_test.cc
@@ -56,7 +56,8 @@ class MediaSessionTest : public PageTestBase {
mock_service_ = std::make_unique<MockMediaSessionService>();
- media_session_ = MakeGarbageCollected<MediaSession>(GetFrame().DomWindow());
+ media_session_ =
+ MediaSession::mediaSession(*GetFrame().DomWindow()->navigator());
media_session_->service_ = mock_service_->CreateRemoteAndBind();
media_session_->clock_ = &test_clock_;
}
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc b/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc
deleted file mode 100644
index f99065f3d12..00000000000
--- a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc
+++ /dev/null
@@ -1,44 +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/mediasession/navigator_media_session.h"
-
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/modules/mediasession/media_session.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-NavigatorMediaSession::NavigatorMediaSession(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
-
-void NavigatorMediaSession::Trace(Visitor* visitor) const {
- visitor->Trace(session_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-const char NavigatorMediaSession::kSupplementName[] = "NavigatorMediaSession";
-
-NavigatorMediaSession& NavigatorMediaSession::From(Navigator& navigator) {
- NavigatorMediaSession* supplement =
- Supplement<Navigator>::From<NavigatorMediaSession>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorMediaSession>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-MediaSession* NavigatorMediaSession::mediaSession(ScriptState* script_state,
- Navigator& navigator) {
- NavigatorMediaSession& self = NavigatorMediaSession::From(navigator);
- if (!self.session_) {
- self.session_ = MakeGarbageCollected<MediaSession>(
- ExecutionContext::From(script_state));
- }
- return self.session_.Get();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.h b/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.h
deleted file mode 100644
index 7c1fdc2f393..00000000000
--- a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.h
+++ /dev/null
@@ -1,38 +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_MEDIASESSION_NAVIGATOR_MEDIA_SESSION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_NAVIGATOR_MEDIA_SESSION_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/mediasession/media_session.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class ScriptState;
-
-// Provides MediaSession as a supplement of Navigator as an attribute.
-class NavigatorMediaSession final
- : public GarbageCollected<NavigatorMediaSession>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static NavigatorMediaSession& From(Navigator&);
- static MediaSession* mediaSession(ScriptState*, Navigator&);
-
- explicit NavigatorMediaSession(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- // The MediaSession instance of this Navigator.
- Member<MediaSession> session_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_NAVIGATOR_MEDIA_SESSION_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.idl b/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.idl
index 5f6d68d9c6d..795cf4ffb5d 100644
--- a/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.idl
+++ b/chromium/third_party/blink/renderer/modules/mediasession/navigator_media_session.idl
@@ -6,8 +6,8 @@
[
Exposed=(Window),
- ImplementedAs=NavigatorMediaSession,
+ ImplementedAs=MediaSession,
RuntimeEnabled=MediaSession
] partial interface Navigator {
- [CallWith=ScriptState, SameObject] readonly attribute MediaSession mediaSession;
+ [SameObject] readonly attribute MediaSession mediaSession;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
index b3b7d11e4f3..fb64fa7b3b3 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//media/media_options.gni")
import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("mediasource") {
@@ -35,4 +36,10 @@ blink_modules_sources("mediasource") {
"video_playback_quality.cc",
"video_playback_quality.h",
]
+ deps = [
+ "//media",
+
+ # Ensure the generated webcodecs v8 config and chunk bindings are available.
+ "//third_party/blink/renderer/modules/webcodecs:webcodecs",
+ ]
}
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/DEPS b/chromium/third_party/blink/renderer/modules/mediasource/DEPS
index d96729c3994..a7b4b9d51b3 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/DEPS
+++ b/chromium/third_party/blink/renderer/modules/mediasource/DEPS
@@ -1,7 +1,17 @@
include_rules = [
"-third_party/blink/renderer/modules",
+ "+media/base/audio_decoder_config.h",
"+media/base/logging_override_if_enabled.h",
+ "+media/base/mime_util.h",
+ "+media/base/stream_parser.h",
+ "+media/base/stream_parser_buffer.h",
+ "+media/base/supported_types.h",
+ "+media/base/video_decoder_config.h",
+ "+media/filters",
+ "+media/formats/mp4/box_definitions.h",
+ "+media/media_buildflags.h",
"+third_party/blink/renderer/modules/event_modules.h",
"+third_party/blink/renderer/modules/event_target_modules.h",
"+third_party/blink/renderer/modules/mediasource",
+ "+third_party/blink/renderer/modules/webcodecs",
]
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/DIR_METADATA b/chromium/third_party/blink/renderer/modules/mediasource/DIR_METADATA
new file mode 100644
index 00000000000..5c0f9b2807c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Media>Source"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/OWNERS b/chromium/third_party/blink/renderer/modules/mediasource/OWNERS
index c881c588a92..90a1e1915f4 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/mediasource/OWNERS
@@ -1,4 +1,2 @@
chcunningham@chromium.org
wolenetz@chromium.org
-
-# COMPONENT: Internals>Media>Source
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
index 9efe5305731..c322ec1ef92 100644
--- 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
@@ -29,7 +29,7 @@ std::ostream& operator<<(
CrossThreadMediaSourceAttachment::CrossThreadMediaSourceAttachment(
MediaSource* media_source,
- util::PassKey<URLMediaSource> /* passkey */)
+ base::PassKey<URLMediaSource> /* passkey */)
: registered_media_source_(media_source),
// TODO(https://crbug.com/878133): Confirm if kMediaElementEvent remains
// the appropriate task type when standardizing MSE-in-Workers, for
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
index f14ef4a5af5..14a7194512b 100644
--- 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
@@ -8,7 +8,7 @@
#include <memory>
#include "base/thread_annotations.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/public/platform/web_time_range.h"
#include "third_party/blink/renderer/core/html/track/audio_track.h"
#include "third_party/blink/renderer/core/html/track/audio_track_list.h"
@@ -39,7 +39,7 @@ class CrossThreadMediaSourceAttachment final
// 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>);
+ base::PassKey<URLMediaSource>);
// MediaSourceAttachmentSupplement, called by MSE API on worker thread.
// These generally require the MSE implementation to issue these calls from
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/idls.gni b/chromium/third_party/blink/renderer/modules/mediasource/idls.gni
index 5ebc2d32982..5dfa8b3e6db 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/mediasource/idls.gni
@@ -11,6 +11,8 @@ modules_idl_files = [
"video_playback_quality.idl",
]
+modules_dictionary_idl_files = [ "source_buffer_config.idl" ]
+
modules_dependency_idl_files = [
"audio_track_source_buffer.idl",
"html_video_element_media_source.idl",
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
index 3d0d59bcbc3..fbe5daa0c64 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -8,12 +8,20 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
+#include "media/base/audio_decoder_config.h"
#include "media/base/logging_override_if_enabled.h"
+#include "media/base/mime_util.h"
+#include "media/base/supported_types.h"
+#include "media/base/video_decoder_config.h"
+#include "media/media_buildflags.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/platform/web_media_source.h"
#include "third_party/blink/public/platform/web_source_buffer.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_source_buffer_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
@@ -24,6 +32,9 @@
#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.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/modules/webcodecs/audio_decoder.h"
+#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_decoder.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/heap/heap.h"
@@ -36,6 +47,11 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+#include "media/filters/h264_to_annex_b_bitstream_converter.h"
+#include "media/formats/mp4/box_definitions.h"
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
using blink::WebMediaSource;
using blink::WebSourceBuffer;
@@ -178,13 +194,10 @@ SourceBuffer* MediaSource::addSourceBuffer(const String& type,
// 2. If type contains a MIME type that is not supported ..., then throw a
// NotSupportedError exception and abort these steps.
- //
- // TODO(wolenetz): Refactor and use a less-strict version of isTypeSupported
- // here. As part of that, CreateWebSourceBuffer in Chromium should inherit
- // relaxation of impl's StreamParserFactory (since it returns false if a
- // stream parser can't be constructed with |type|). See
- // https://crbug.com/535738.
- if (!isTypeSupported(GetExecutionContext(), type)) {
+ // TODO(crbug.com/535738): Actually relax codec-specificity.
+ if (!IsTypeSupportedInternal(
+ GetExecutionContext(), type,
+ false /* Allow underspecified codecs in |type| */)) {
LogAndThrowDOMException(
exception_state, DOMExceptionCode::kNotSupportedError,
"The type provided ('" + type + "') is unsupported.");
@@ -206,9 +219,127 @@ SourceBuffer* MediaSource::addSourceBuffer(const String& type,
SourceBuffer* source_buffer = nullptr;
// Note, here we must be open, therefore we must have an attachment.
+ if (!RunUnlessElementGoneOrClosingUs(WTF::Bind(
+ &MediaSource::AddSourceBuffer_Locked, WrapPersistent(this), type,
+ nullptr /* audio_config */, nullptr /* video_config */,
+ WTF::Unretained(&exception_state),
+ WTF::Unretained(&source_buffer)))) {
+ // TODO(https://crbug.com/878133): Determine in specification what the
+ // specific, app-visible, exception should be for this case.
+ LogAndThrowDOMException(exception_state,
+ DOMExceptionCode::kInvalidStateError,
+ "Worker MediaSource attachment is closing");
+ }
+
+ return source_buffer;
+}
+
+SourceBuffer* MediaSource::AddSourceBufferUsingConfig(
+ const SourceBufferConfig* config,
+ ExceptionState& exception_state) {
+ DVLOG(2) << __func__ << " this=" << this;
+ DCHECK(config);
+
+ // Precisely one of the multiple keys in SourceBufferConfig must be set.
+ int num_set = 0;
+ if (config->hasAudioConfig())
+ num_set++;
+ if (config->hasVideoConfig())
+ num_set++;
+ if (num_set != 1) {
+ LogAndThrowTypeError(
+ exception_state,
+ "SourceBufferConfig must have precisely one media type");
+ return nullptr;
+ }
+
+ // Determine if the config is valid and supported by creating the necessary
+ // media decoder configs using WebCodecs converters. This implies that codecs
+ // supported by WebCodecs are also supported by MSE, though MSE may require
+ // more precise information in the encoded chunks (such as video chunk
+ // duration).
+ // TODO(crbug.com/1144908): WebCodecs' determination of decoder configuration
+ // support may be changed to be async and thus might also motivate making this
+ // method async.
+ std::unique_ptr<media::AudioDecoderConfig> audio_config;
+ std::unique_ptr<media::VideoDecoderConfig> video_config;
+ String console_message;
+ CodecConfigEval eval;
+
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ // TODO(crbug.com/1144908): The SourceBuffer needs these for converting h264
+ // EncodedVideoChunks. Probably best if these details are put into a new
+ // WebCodecs VideoDecoderHelper abstraction (or similar), since this top-level
+ // MediaSource impl shouldn't need to worry about the details of specific
+ // codec bitstream conversions (nor should the underlying implementation be
+ // depended upon to redo work done already in WebCodecs decoder configuration
+ // validation.) In initial prototype, we do not support h264 buffering, so
+ // will fail if these become populated by MakeMediaVideoDecoderConfig, below.
+ std::unique_ptr<media::H264ToAnnexBBitstreamConverter> h264_converter;
+ std::unique_ptr<media::mp4::AVCDecoderConfigurationRecord> h264_avcc;
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+ if (config->hasAudioConfig()) {
+ audio_config = std::make_unique<media::AudioDecoderConfig>();
+ eval = AudioDecoder::MakeMediaAudioDecoderConfig(*(config->audioConfig()),
+ *audio_config /* out */,
+ console_message /* out */);
+ } else {
+ DCHECK(config->hasVideoConfig());
+ video_config = std::make_unique<media::VideoDecoderConfig>();
+ eval = VideoDecoder::MakeMediaVideoDecoderConfig(
+ *(config->videoConfig()), *video_config /* out */,
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ h264_converter /* out */, h264_avcc /* out */,
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+ console_message /* out */);
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ // TODO(crbug.com/1144908): Initial prototype does not support h264
+ // buffering. See above.
+ if (eval == CodecConfigEval::kSupported && (h264_converter || h264_avcc)) {
+ eval = CodecConfigEval::kUnsupported;
+ console_message =
+ "H.264 EncodedVideoChunk buffering is not yet supported in MSE. See "
+ "https://crbug.com/1144908.";
+ video_config.reset();
+ }
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+ }
+
+ switch (eval) {
+ case CodecConfigEval::kInvalid:
+ LogAndThrowTypeError(exception_state, console_message);
+ return nullptr;
+ case CodecConfigEval::kUnsupported:
+ LogAndThrowDOMException(exception_state,
+ DOMExceptionCode::kNotSupportedError,
+ console_message);
+ return nullptr;
+ case CodecConfigEval::kSupported:
+ // Good, let's proceed.
+ break;
+ }
+
+ // If the readyState attribute is not in the "open" state then throw an
+ // InvalidStateError exception and abort these steps.
+ if (!IsOpen()) {
+ LogAndThrowDOMException(exception_state,
+ DOMExceptionCode::kInvalidStateError,
+ "The MediaSource's readyState is not 'open'.");
+ return nullptr;
+ }
+
+ // Do remainder of steps only if attachment is usable and underlying demuxer
+ // is protected from destruction (applicable especially for MSE-in-Worker
+ // case).
+ SourceBuffer* source_buffer = nullptr;
+ String null_type;
+
+ // Note, here we must be open, therefore we must have an attachment.
if (!RunUnlessElementGoneOrClosingUs(
WTF::Bind(&MediaSource::AddSourceBuffer_Locked, WrapPersistent(this),
- type, WTF::Unretained(&exception_state),
+ null_type, std::move(audio_config), std::move(video_config),
+ WTF::Unretained(&exception_state),
WTF::Unretained(&source_buffer)))) {
// TODO(https://crbug.com/878133): Determine in specification what the
// specific, app-visible, exception should be for this case.
@@ -222,16 +353,23 @@ SourceBuffer* MediaSource::addSourceBuffer(const String& type,
void MediaSource::AddSourceBuffer_Locked(
const String& type,
+ std::unique_ptr<media::AudioDecoderConfig> audio_config,
+ std::unique_ptr<media::VideoDecoderConfig> video_config,
ExceptionState* exception_state,
SourceBuffer** created_buffer,
MediaSourceAttachmentSupplement::ExclusiveKey pass_key) {
AssertAttachmentsMutexHeldIfCrossThreadForDebugging();
// 5. Create a new SourceBuffer object and associated resources.
+ // TODO(crbug.com/1144908): Plumb the configs through into a new logic in
+ // WebSourceBuffer and SourceBufferState such that configs and encoded chunks
+ // can be buffered, with appropriate invocations of the
+ // InitializationSegmentReceived and AppendError methods.
ContentType content_type(type);
String codecs = content_type.Parameter("codecs");
- std::unique_ptr<WebSourceBuffer> web_source_buffer =
- CreateWebSourceBuffer(content_type.GetType(), codecs, *exception_state);
+ std::unique_ptr<WebSourceBuffer> web_source_buffer = CreateWebSourceBuffer(
+ content_type.GetType(), codecs, std::move(audio_config),
+ std::move(video_config), *exception_state);
if (!web_source_buffer) {
DCHECK(exception_state->CodeAs<DOMExceptionCode>() ==
@@ -370,20 +508,33 @@ bool MediaSource::IsUpdating() const {
// static
bool MediaSource::isTypeSupported(ExecutionContext* context,
const String& type) {
+ bool result = IsTypeSupportedInternal(
+ context, type, true /* Require fully specified mime and codecs */);
+ DVLOG(2) << __func__ << "(" << type << ") -> " << (result ? "true" : "false");
+ return result;
+}
+
+// static
+bool MediaSource::IsTypeSupportedInternal(ExecutionContext* context,
+ const String& type,
+ bool enforce_codec_specificity) {
// 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.
if (type.IsEmpty()) {
- DVLOG(1) << __func__ << "(" << type << ") -> false (empty input)";
+ DVLOG(1) << __func__ << "(" << type << ", "
+ << (enforce_codec_specificity ? "true" : "false")
+ << ") -> false (empty input)";
return false;
}
- ContentType content_type(type);
- String codecs = content_type.Parameter("codecs");
-
// 2. If type does not contain a valid MIME type string, then return false.
- if (content_type.GetType().IsEmpty()) {
- DVLOG(1) << __func__ << "(" << type << ") -> false (invalid mime type)";
+ ContentType content_type(type);
+ String mime_type = content_type.GetType();
+ if (mime_type.IsEmpty()) {
+ DVLOG(1) << __func__ << "(" << type << ", "
+ << (enforce_codec_specificity ? "true" : "false")
+ << ") -> false (invalid mime type)";
return false;
}
@@ -391,9 +542,60 @@ bool MediaSource::isTypeSupported(ExecutionContext* context,
// HTMLMediaElement.canPlayType() will return "maybe" or "probably" since it
// does not make sense for a MediaSource to support a type the
// HTMLMediaElement knows it cannot play.
- if (HTMLMediaElement::GetSupportsType(content_type) ==
- MIMETypeRegistry::kIsNotSupported) {
- DVLOG(1) << __func__ << "(" << type
+ String codecs = content_type.Parameter("codecs");
+ MIMETypeRegistry::SupportsType get_supports_type_result;
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC) && BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+ // Here, we special-case for HEVC on ChromeOS, which is only supported if
+ // encrypted. isTypeSupported(fully qualified type with hevc codec) should say
+ // false on such platform (except if kEnableClearHevcForTesting cmdline switch
+ // is used, enabling GetSupportsType success), but addSourceBuffer(same) and
+ // changeType(same) shouldn't fail just due to having HEVC codec. We use
+ // |enforce_codec_specificity| to understand if we are servicing iTS (if true)
+ // versus aSB (if false). If servicing aSB or cT, we'll remove any detected
+ // hevc codec from the codecs we use in the GetSupportsType() query.
+ if (!enforce_codec_specificity) {
+ // Remove any detected HEVC codec from the query to GetSupportsType.
+ std::string filtered_codecs;
+ std::vector<std::string> parsed_codec_ids;
+ media::SplitCodecs(codecs.Ascii(), &parsed_codec_ids);
+ bool first = true;
+ for (const auto& codec_id : parsed_codec_ids) {
+ bool is_codec_ambiguous;
+ media::VideoCodec video_codec = media::kUnknownVideoCodec;
+ media::VideoCodecProfile profile;
+ uint8_t level = 0;
+ media::VideoColorSpace color_space;
+ if (media::ParseVideoCodecString(mime_type.Ascii(), codec_id,
+ &is_codec_ambiguous, &video_codec,
+ &profile, &level, &color_space) &&
+ !is_codec_ambiguous && video_codec == media::VideoCodec::kCodecHEVC) {
+ continue;
+ }
+ if (first)
+ first = false;
+ else
+ filtered_codecs += ",";
+ filtered_codecs += codec_id;
+ }
+
+ std::string filtered_type =
+ mime_type.Ascii() + "; codecs=\"" + filtered_codecs + "\"";
+ DVLOG(1) << __func__ << " filtered_type=" << filtered_type;
+ get_supports_type_result = HTMLMediaElement::GetSupportsType(
+ ContentType(String::FromUTF8(filtered_type.c_str())));
+ } else {
+ // Even on ChromeOS with HEVC support, don't filter out HEVC codec when
+ // servicing isTypeSupported().
+ get_supports_type_result = HTMLMediaElement::GetSupportsType(content_type);
+ }
+#else
+ get_supports_type_result = HTMLMediaElement::GetSupportsType(content_type);
+#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) &&
+ // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+
+ if (get_supports_type_result == MIMETypeRegistry::kIsNotSupported) {
+ DVLOG(1) << __func__ << "(" << type << ", "
+ << (enforce_codec_specificity ? "true" : "false")
<< ") -> false (not supported by HTMLMediaElement)";
RecordIdentifiabilityMetric(context, type, false);
return false;
@@ -407,17 +609,22 @@ bool MediaSource::isTypeSupported(ExecutionContext* context,
// type, media subtype, and codecs then return false.
// 6. Return true.
// For incompletely specified mime-type and codec combinations, we also return
- // false, complying with the non-normative guidance being incubated for the
- // MSE vNext codec switching feature at
- // https://github.com/WICG/media-source/tree/codec-switching.
- // TODO(wolenetz): Relaxed codec specificity following similar non-normative
- // guidance will soon be allowed for addSourceBuffer and changeType methods,
- // but this strict codec specificity is and will be retained for
- // isTypeSupported. See https://crbug.com/535738
- bool result = MIMETypeRegistry::kIsSupported ==
- MIMETypeRegistry::SupportsMediaSourceMIMEType(
- content_type.GetType(), codecs);
- DVLOG(2) << __func__ << "(" << type << ") -> " << (result ? "true" : "false");
+ // false if |enforce_codec_specificity| is true, complying with the
+ // non-normative guidance being incubated for the MSE v2 codec switching
+ // feature at https://github.com/WICG/media-source/tree/codec-switching.
+ // Relaxed codec specificity following similar non-normative guidance is
+ // allowed for addSourceBuffer and changeType methods, but this strict codec
+ // specificity is and will be retained for isTypeSupported.
+ // TODO(crbug.com/535738): Actually relax the codec-specifity for aSB() and
+ // cT() (which is when |enforce_codec_specificity| is false).
+ MIMETypeRegistry::SupportsType supported =
+ MIMETypeRegistry::SupportsMediaSourceMIMEType(mime_type, codecs);
+
+ bool result = supported == MIMETypeRegistry::kIsSupported;
+
+ DVLOG(2) << __func__ << "(" << type << ", "
+ << (enforce_codec_specificity ? "true" : "false") << ") -> "
+ << (result ? "true" : "false");
RecordIdentifiabilityMetric(context, type, result);
return result;
}
@@ -1273,17 +1480,44 @@ void MediaSource::DetachWorkerOnContextDestruction_Locked(
std::unique_ptr<WebSourceBuffer> MediaSource::CreateWebSourceBuffer(
const String& type,
const String& codecs,
+ std::unique_ptr<media::AudioDecoderConfig> audio_config,
+ std::unique_ptr<media::VideoDecoderConfig> video_config,
ExceptionState& exception_state) {
AssertAttachmentsMutexHeldIfCrossThreadForDebugging();
- WebSourceBuffer* web_source_buffer = nullptr;
+ std::unique_ptr<WebSourceBuffer> web_source_buffer;
+ WebMediaSource::AddStatus add_status;
+ if (audio_config) {
+ DCHECK(!video_config);
+ DCHECK(type.IsNull() && codecs.IsNull());
+ web_source_buffer = web_media_source_->AddSourceBuffer(
+ std::move(audio_config), add_status /* out */);
+ DCHECK_NE(add_status, WebMediaSource::kAddStatusNotSupported);
+ } else if (video_config) {
+ DCHECK(type.IsNull() && codecs.IsNull());
+ web_source_buffer = web_media_source_->AddSourceBuffer(
+ std::move(video_config), add_status /* out */);
+ DCHECK_NE(add_status, WebMediaSource::kAddStatusNotSupported);
+ } else {
+ DCHECK(!type.IsNull());
+ web_source_buffer =
+ web_media_source_->AddSourceBuffer(type, codecs, add_status /* out */);
+ }
- switch (
- web_media_source_->AddSourceBuffer(type, codecs, &web_source_buffer)) {
+ switch (add_status) {
case WebMediaSource::kAddStatusOk:
- return base::WrapUnique(web_source_buffer);
+ DCHECK(web_source_buffer);
+ return web_source_buffer;
case WebMediaSource::kAddStatusNotSupported:
+ // DCHECKs, above, ensure this case doesn't occur for the WebCodecs config
+ // overloads of WebMediaSource::AddSourceBuffer(). This case can only
+ // occur for the |type| and |codecs| version of that method.
DCHECK(!web_source_buffer);
+ // TODO(crbug.com/1144908): Are we certain that if we originally had an
+ // audio_config or video_config, above, that it should be supported? In
+ // that case, we could possibly add some DCHECK here if attempt to use
+ // them failed in this case.
+ //
// 2.2
// https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
// Step 2: If type contains a MIME type ... that is not supported with the
@@ -1291,7 +1525,8 @@ std::unique_ptr<WebSourceBuffer> MediaSource::CreateWebSourceBuffer(
// then throw a NotSupportedError exception and abort these steps.
LogAndThrowDOMException(
exception_state, DOMExceptionCode::kNotSupportedError,
- "The type provided ('" + type + "') is not supported.");
+ "The type provided ('" + type +
+ "') is not supported for SourceBuffer creation.");
return nullptr;
case WebMediaSource::kAddStatusReachedIdLimit:
DCHECK(!web_source_buffer);
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
index ccaff0d97fc..cc8c53e035b 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
@@ -24,6 +24,11 @@
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+namespace media {
+class AudioDecoderConfig;
+class VideoDecoderConfig;
+} // namespace media
+
namespace blink {
class EventQueue;
@@ -31,6 +36,7 @@ class ExceptionState;
class HTMLMediaElement;
class CrossThreadMediaSourceAttachment;
class SameThreadMediaSourceAttachment;
+class SourceBufferConfig;
class TrackBase;
class WebSourceBuffer;
@@ -67,6 +73,9 @@ class MediaSource final : public EventTargetWithInlineData,
}
SourceBuffer* addSourceBuffer(const String& type, ExceptionState&)
LOCKS_EXCLUDED(attachment_link_lock_);
+ SourceBuffer* AddSourceBufferUsingConfig(const SourceBufferConfig*,
+ ExceptionState&)
+ LOCKS_EXCLUDED(attachment_link_lock_);
void removeSourceBuffer(SourceBuffer*, ExceptionState&)
LOCKS_EXCLUDED(attachment_link_lock_);
void setDuration(double, ExceptionState&)
@@ -86,6 +95,16 @@ class MediaSource final : public EventTargetWithInlineData,
LOCKS_EXCLUDED(attachment_link_lock_);
static bool isTypeSupported(ExecutionContext* context, const String& type);
+
+ // Helper for isTypeSupported, addSourceBuffer and SourceBuffer changeType.
+ // Set |enforce_codec_specificity| true to require fully specified mime and
+ // codecs, false otherwise.
+ // TODO(https://crbug.com/535738): When |enforce_codec_specificity| is set to
+ // false, then fully relax codec requirements.
+ static bool IsTypeSupportedInternal(ExecutionContext* context,
+ const String& type,
+ bool enforce_codec_specificity);
+
static bool canConstructInDedicatedWorker();
// Methods needed by a MediaSourceAttachmentSupplement to service operations
@@ -168,6 +187,8 @@ class MediaSource final : public EventTargetWithInlineData,
// also require the same, since they can be called from within these methods.
void AddSourceBuffer_Locked(
const String& type /* in */,
+ std::unique_ptr<media::AudioDecoderConfig> audio_config /* in */,
+ std::unique_ptr<media::VideoDecoderConfig> video_config /* in */,
ExceptionState* exception_state /* in/out */,
SourceBuffer** created_buffer /* out */,
MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */)
@@ -190,10 +211,12 @@ class MediaSource final : public EventTargetWithInlineData,
bool IsUpdating() const;
- std::unique_ptr<WebSourceBuffer> CreateWebSourceBuffer(const String& type,
- const String& codecs,
- ExceptionState&)
- LOCKS_EXCLUDED(attachment_link_lock_);
+ std::unique_ptr<WebSourceBuffer> CreateWebSourceBuffer(
+ const String& type,
+ const String& codecs,
+ std::unique_ptr<media::AudioDecoderConfig> audio_config,
+ std::unique_ptr<media::VideoDecoderConfig> video_config,
+ ExceptionState&) LOCKS_EXCLUDED(attachment_link_lock_);
void ScheduleEvent(const AtomicString& event_name);
static void RecordIdentifiabilityMetric(ExecutionContext* context,
const String& type,
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 b09078e877a..161f0b1f951 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl
@@ -50,7 +50,18 @@ enum EndOfStreamError {
attribute EventHandler onsourceopen;
attribute EventHandler onsourceended;
attribute EventHandler onsourceclose;
+
[RaisesException] SourceBuffer addSourceBuffer(DOMString type);
+
+ // For MSE-for-WebCodecs. Explainer:
+ // https://github.com/wolenetz/mse-for-webcodecs/blob/main/explainer.md
+ [
+ RaisesException,
+ RuntimeEnabled=MediaSourceExtensionsForWebCodecs,
+ ImplementedAs=AddSourceBufferUsingConfig,
+ MeasureAs=AddSourceBufferUsingConfig
+ ] SourceBuffer addSourceBuffer(SourceBufferConfig config);
+
[RaisesException] void removeSourceBuffer(SourceBuffer buffer);
readonly attribute DOMString readyState;
[RaisesException] void endOfStream(optional EndOfStreamError error);
@@ -58,7 +69,9 @@ enum EndOfStreamError {
[RaisesException] void setLiveSeekableRange(double start, double end);
[RaisesException] void clearLiveSeekableRange();
- [CallWith=ExecutionContext] static boolean isTypeSupported (DOMString type);
+ // TODO(crbug.com/1144908): Consider adding an overload which is given a
+ // SourceBufferConfig.
+ [CallWith=ExecutionContext] static boolean isTypeSupported(DOMString type);
// Enables proactive feature-detection of MSE-in-Workers support from the
// main thread (or anywhere this interface is exposed.) If the attribute is
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
index 269e7166d40..6c057c91703 100644
--- 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
@@ -5,7 +5,7 @@
#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 "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.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/core/html/track/audio_track.h"
@@ -26,7 +26,7 @@ class VideoTrackList;
// members common to all concrete attachments.
class MediaSourceAttachmentSupplement : public MediaSourceAttachment {
public:
- using ExclusiveKey = util::PassKey<MediaSourceAttachmentSupplement>;
+ using ExclusiveKey = base::PassKey<MediaSourceAttachmentSupplement>;
using RunExclusivelyCB = base::OnceCallback<void(ExclusiveKey)>;
// Communicates a change in the media resource duration to the attached media
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
index 19185b2638c..57322aeb60e 100644
--- 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
@@ -33,7 +33,7 @@ namespace blink {
SameThreadMediaSourceAttachment::SameThreadMediaSourceAttachment(
MediaSource* media_source,
- util::PassKey<URLMediaSource> /* passkey */)
+ base::PassKey<URLMediaSource> /* passkey */)
: registered_media_source_(media_source),
recent_element_time_(0.0),
element_has_error_(false),
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
index 4d6cef7d02f..97045fe67e4 100644
--- 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
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/public/platform/web_time_range.h"
#include "third_party/blink/renderer/core/html/track/audio_track.h"
#include "third_party/blink/renderer/core/html/track/audio_track_list.h"
@@ -29,7 +29,7 @@ class SameThreadMediaSourceAttachment final
// raw pointer is then adopted into a scoped_refptr in
// MediaSourceRegistryImpl::RegisterURL.
SameThreadMediaSourceAttachment(MediaSource* media_source,
- util::PassKey<URLMediaSource>);
+ base::PassKey<URLMediaSource>);
// MediaSourceAttachmentSupplement
void NotifyDurationChanged(MediaSourceTracer* tracer, double duration) final;
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 e370a4ba6ab..d8ef3160786 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -35,10 +35,21 @@
#include <sstream>
#include <utility>
+#include "base/numerics/checked_math.h"
#include "media/base/logging_override_if_enabled.h"
+#include "media/base/stream_parser_buffer.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_source_buffer.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/encoded_audio_chunk_or_encoded_video_chunk.h"
+#include "third_party/blink/renderer/bindings/modules/v8/encoded_av_chunk_sequence_or_encoded_av_chunk.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_source_buffer_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -53,6 +64,8 @@
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.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/modules/webcodecs/encoded_audio_chunk.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.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/heap/heap.h"
@@ -103,6 +116,86 @@ WTF::String WebTimeRangesToString(const WebTimeRanges& ranges) {
return string_builder.ToString();
}
+// These track IDs are used as to differentiate tracks within a SourceBuffer.
+// They can be duplicated across SourceBuffers, since these are not the
+// TrackList identifiers exposed to the web app; these are instead equivalents
+// of bytestream format's in-band track identifiers.
+// TODO(crbug.com/1144908): Consider standardizing these especially if
+// TrackDefaults makes a return to MSE spec, so that apps can provide
+// name/label/kind/etc metadata for tracks originating from appended WebCodecs
+// chunks.
+// TODO(crbug.com/1144908): Since these must be identical to those generated
+// in the underlying WebCodecsEncodedChunkStreamParser, consider moving these
+// to possibly stream_parser.h. Meanwhile, must be kept in sync with similar
+// constexpr in that parser manually.
+constexpr media::StreamParser::TrackId kWebCodecsAudioTrackId = 1;
+constexpr media::StreamParser::TrackId kWebCodecsVideoTrackId = 2;
+
+// TODO(crbug.com/1144908): Move these converters into a WebCodecs decoder
+// helper abstraction. Beyond reuse (instead of copying the various
+// MakeDecoderBuffer methods), that will also help enable buffering h264 where
+// bitstream conversion might be necessary during conversion.
+// Note, caller updates results further as necessary (e.g. duration, DTS, etc).
+scoped_refptr<media::StreamParserBuffer> MakeAudioStreamParserBuffer(
+ const EncodedAudioChunk& audio_chunk) {
+ // TODO(crbug.com/1144908): DecoderBuffer takes size_t size, but
+ // StreamParserBuffer takes int. Fix this. For now, checked_cast is used.
+ auto stream_parser_buffer = media::StreamParserBuffer::CopyFrom(
+ static_cast<uint8_t*>(audio_chunk.data()->Data()),
+ base::checked_cast<int>(audio_chunk.data()->ByteLength()),
+ audio_chunk.type() == "key", media::DemuxerStream::AUDIO,
+ kWebCodecsAudioTrackId);
+
+ // TODO(crbug.com/1144908): Remove or change the following to DCHECK once
+ // StreamParserBuffer::CopyFrom takes size_t, not int.
+ CHECK_EQ(audio_chunk.data()->ByteLength(), stream_parser_buffer->data_size());
+
+ // Currently, we do not populate any side_data in these converters.
+ DCHECK_EQ(0U, stream_parser_buffer->side_data_size());
+ DCHECK_EQ(nullptr, stream_parser_buffer->side_data());
+
+ stream_parser_buffer->set_timestamp(
+ base::TimeDelta::FromMicroseconds(audio_chunk.timestamp()));
+ // TODO(crbug.com/1144908): Get EncodedAudioChunk to have an optional duration
+ // attribute, and require it to be populated for use by MSE-for-WebCodecs,
+ // here. For initial prototype, hard-coded 22ms is used as estimated duration.
+ stream_parser_buffer->set_duration(base::TimeDelta::FromMilliseconds(22));
+ stream_parser_buffer->set_is_duration_estimated(true);
+ return stream_parser_buffer;
+}
+
+// Caller must verify that video_chunk.duration().has_value().
+scoped_refptr<media::StreamParserBuffer> MakeVideoStreamParserBuffer(
+ const EncodedVideoChunk& video_chunk) {
+ // TODO(crbug.com/1144908): DecoderBuffer takes size_t size, but
+ // StreamParserBuffer takes int. Fix this. For now, checked_cast is used.
+ auto stream_parser_buffer = media::StreamParserBuffer::CopyFrom(
+ static_cast<uint8_t*>(video_chunk.data()->Data()),
+ base::checked_cast<int>(video_chunk.data()->ByteLength()),
+ video_chunk.type() == "key", media::DemuxerStream::VIDEO,
+ kWebCodecsVideoTrackId);
+
+ // TODO(crbug.com/1144908): Remove or change the following to DCHECK once
+ // StreamParserBuffer::CopyFrom takes size_t, not int.
+ CHECK_EQ(video_chunk.data()->ByteLength(), stream_parser_buffer->data_size());
+
+ // Currently, we do not populate any side_data in these converters.
+ DCHECK_EQ(0U, stream_parser_buffer->side_data_size());
+ DCHECK_EQ(nullptr, stream_parser_buffer->side_data());
+
+ stream_parser_buffer->set_timestamp(
+ base::TimeDelta::FromMicroseconds(video_chunk.timestamp()));
+ // TODO(crbug.com/1144908): Get EncodedVideoChunk to have an optional decode
+ // timestamp attribute. If it is populated, use it for the DTS of the
+ // StreamParserBuffer, here. For initial prototype, only in-order PTS==DTS
+ // chunks are supported. Out-of-order chunks may result in buffered range gaps
+ // or decode errors.
+ DCHECK(video_chunk.duration().has_value());
+ stream_parser_buffer->set_duration(
+ base::TimeDelta::FromMicroseconds(video_chunk.duration().value()));
+ return stream_parser_buffer;
+}
+
} // namespace
SourceBuffer::SourceBuffer(std::unique_ptr<WebSourceBuffer> web_source_buffer,
@@ -316,8 +409,9 @@ void SourceBuffer::setTimestampOffset(double offset,
// 3. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// Do the remainder of steps only if attachment is usable and underlying
// demuxer is protected from destruction (applicable especially for
@@ -404,8 +498,9 @@ void SourceBuffer::setAppendWindowStart(double start,
// 2. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// 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.
@@ -460,8 +555,9 @@ void SourceBuffer::setAppendWindowEnd(double end,
// 2. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// 3. If the new value equals NaN, then throw a TypeError and abort these
// steps.
@@ -517,13 +613,162 @@ void SourceBuffer::appendBuffer(DOMArrayBuffer* data,
void SourceBuffer::appendBuffer(NotShared<DOMArrayBufferView> data,
ExceptionState& exception_state) {
- DVLOG(3) << __func__ << " this=" << this
- << " size=" << data.View()->byteLength();
+ DVLOG(3) << __func__ << " this=" << this << " size=" << data->byteLength();
// Section 3.2 appendBuffer()
// https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
- AppendBufferInternal(
- static_cast<const unsigned char*>(data.View()->BaseAddress()),
- data.View()->byteLength(), exception_state);
+ AppendBufferInternal(static_cast<const unsigned char*>(data->BaseAddress()),
+ data->byteLength(), exception_state);
+}
+
+// Note that |chunks| may be a sequence of mixed audio and video encoded chunks
+// (which should cause underlying buffering validation to emit error akin to
+// appending video to an audio track or vice-versa). It was impossible to get
+// the bindings generator to disambiguate sequence<audio> vs sequence<video>,
+// hence we could not use simple overloading in the IDL for these two. Neither
+// could the IDL union attempt similar. We must enforce that semantic in
+// implementation. Further note, |chunks| may instead be a single audio or a
+// single video chunk as a helpful additional overload for one-chunk-at-a-time
+// append use-cases.
+ScriptPromise SourceBuffer::appendEncodedChunks(
+ ScriptState* script_state,
+ const EncodedChunks& chunks,
+ ExceptionState& exception_state) {
+ DVLOG(2) << __func__ << " this=" << this;
+
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
+ "media", "SourceBuffer::appendEncodedChunks", TRACE_ID_LOCAL(this));
+
+ if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
+ exception_state)) {
+ TRACE_EVENT_NESTABLE_ASYNC_END0(
+ "media", "SourceBuffer::appendEncodedChunks", TRACE_ID_LOCAL(this));
+ return ScriptPromise();
+ }
+
+ // Convert |chunks| to a StreamParser::BufferQueue.
+ // TODO(crbug.com/1144908): Support out-of-order DTS vs PTS sequences. For
+ // now, PTS is assumed to be DTS (as is common in some formats like WebM).
+ // TODO(crbug.com/1144908): Add optional EncodedAudioChunk duration attribute
+ // and require it to be populated for use with MSE. For now, all audio chunks
+ // are estimated.
+ DCHECK(!pending_chunks_to_buffer_);
+ auto buffer_queue = std::make_unique<media::StreamParser::BufferQueue>();
+ size_t size = 0;
+
+ if (chunks.IsEncodedAudioChunk()) {
+ buffer_queue->emplace_back(
+ MakeAudioStreamParserBuffer(*(chunks.GetAsEncodedAudioChunk())));
+ size += buffer_queue->back()->data_size() +
+ buffer_queue->back()->side_data_size();
+ } else if (chunks.IsEncodedVideoChunk()) {
+ const auto& video_chunk = *(chunks.GetAsEncodedVideoChunk());
+ if (!video_chunk.duration().has_value()) {
+ MediaSource::LogAndThrowTypeError(
+ exception_state,
+ "EncodedVideoChunk is missing duration, required for use with "
+ "SourceBuffer.");
+ return ScriptPromise();
+ ;
+ }
+ buffer_queue->emplace_back(MakeVideoStreamParserBuffer(video_chunk));
+ size += buffer_queue->back()->data_size() +
+ buffer_queue->back()->side_data_size();
+ } else if (chunks.IsEncodedAudioChunkOrEncodedVideoChunkSequence()) {
+ for (const auto& av_chunk :
+ chunks.GetAsEncodedAudioChunkOrEncodedVideoChunkSequence()) {
+ // TODO(crbug.com/1144908): Can null entries occur in the sequence, and
+ // should they be ignored or should they cause exception? Ignoring for
+ // now, if they occur.
+ if (av_chunk.IsNull())
+ continue;
+ if (av_chunk.IsEncodedAudioChunk()) {
+ buffer_queue->emplace_back(
+ MakeAudioStreamParserBuffer(*(av_chunk.GetAsEncodedAudioChunk())));
+ size += buffer_queue->back()->data_size() +
+ buffer_queue->back()->side_data_size();
+ } else if (av_chunk.IsEncodedVideoChunk()) {
+ const auto& video_chunk = *(av_chunk.GetAsEncodedVideoChunk());
+ if (!video_chunk.duration().has_value()) {
+ MediaSource::LogAndThrowTypeError(
+ exception_state,
+ "EncodedVideoChunk is missing duration, required for use with "
+ "SourceBuffer.");
+ return ScriptPromise();
+ ;
+ }
+ buffer_queue->emplace_back(MakeVideoStreamParserBuffer(video_chunk));
+ size += buffer_queue->back()->data_size() +
+ buffer_queue->back()->side_data_size();
+ }
+ }
+ }
+
+ DCHECK(!append_encoded_chunks_resolver_);
+ append_encoded_chunks_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = append_encoded_chunks_resolver_->Promise();
+
+ // Do remainder of steps of analogue of prepare append algorithm and sending
+ // the |buffer_queue| to be buffered by |web_source_buffer_| asynchronously
+ // only if attachment is usable and underlying demuxer is protected from
+ // destruction (applicable especially for MSE-in-Worker case). Note, we must
+ // have |source_| and |source_| must have an attachment because !IsRemoved().
+ if (!source_->RunUnlessElementGoneOrClosingUs(WTF::Bind(
+ &SourceBuffer::AppendEncodedChunks_Locked, WrapPersistent(this),
+ std::move(buffer_queue), size, WTF::Unretained(&exception_state)))) {
+ // TODO(crbug.com/878133): Determine in specification what the specific,
+ // app-visible, exception should be for this case.
+ MediaSource::LogAndThrowDOMException(
+ exception_state, DOMExceptionCode::kInvalidStateError,
+ "Worker MediaSource attachment is closing");
+ append_encoded_chunks_resolver_ = nullptr;
+ return ScriptPromise();
+ }
+
+ return promise;
+}
+
+void SourceBuffer::AppendEncodedChunks_Locked(
+ std::unique_ptr<media::StreamParser::BufferQueue> buffer_queue,
+ size_t size,
+ ExceptionState* exception_state,
+ MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */) {
+ DVLOG(2) << __func__ << " this=" << this << ", size=" << size;
+
+ DCHECK(source_);
+ DCHECK(!updating_);
+ source_->AssertAttachmentsMutexHeldIfCrossThreadForDebugging();
+ DCHECK(append_encoded_chunks_resolver_);
+ DCHECK(buffer_queue);
+ DCHECK(!pending_chunks_to_buffer_);
+
+ double media_time = GetMediaTime();
+ if (!PrepareAppend(media_time, size, *exception_state)) {
+ TRACE_EVENT_NESTABLE_ASYNC_END0(
+ "media", "SourceBuffer::appendEncodedChunks", TRACE_ID_LOCAL(this));
+ append_encoded_chunks_resolver_ = nullptr;
+ return;
+ }
+
+ pending_chunks_to_buffer_ = std::move(buffer_queue);
+ updating_ = true;
+
+ // Note, this promisified API does not queue for dispatch events like
+ // 'updatestart', 'update', 'error', 'abort', nor 'updateend' during the scope
+ // of synchronous and asynchronous operation, because the promise's resolution
+ // or rejection indicates the same information and lets us not wait until
+ // those events are dispatched before resolving them. See verbose reasons in
+ // AbortIfUpdating().
+
+ // Asynchronously run the analogue of the buffer append algorithm.
+ append_encoded_chunks_async_task_handle_ = PostCancellableTask(
+ *GetExecutionContext()->GetTaskRunner(TaskType::kMediaElementEvent),
+ FROM_HERE,
+ WTF::Bind(&SourceBuffer::AppendEncodedChunksAsyncPart,
+ WrapPersistent(this)));
+
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("media", "delay", TRACE_ID_LOCAL(this),
+ "type", "initialDelay");
}
void SourceBuffer::abort(ExceptionState& exception_state) {
@@ -620,8 +865,9 @@ void SourceBuffer::remove(double start,
// 2. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// Do remainder of steps only if attachment is usable and underlying demuxer
// is protected from destruction (applicable especially for MSE-in-Worker
@@ -722,8 +968,9 @@ void SourceBuffer::changeType(const String& type,
// 3. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// Do remainder of steps only if attachment is usable and underlying demuxer
// is protected from destruction (applicable especially for MSE-in-Worker
@@ -740,6 +987,39 @@ void SourceBuffer::changeType(const String& type,
}
}
+void SourceBuffer::ChangeTypeUsingConfig(const SourceBufferConfig* config,
+ ExceptionState& exception_state) {
+ DVLOG(2) << __func__ << " this=" << this;
+
+ // If this object has been removed from the sourceBuffers attribute of the
+ // parent media source, then throw an InvalidStateError exception and abort
+ // these steps.
+ // If the updating attribute equals true, then throw an InvalidStateError
+ // exception and abort these steps.
+ if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
+ exception_state)) {
+ return;
+ }
+
+ // Before this IDL overload was added, changeType(null) yielded a
+ // kNotSupportedError, so preserve that behavior if the bindings resolve us
+ // instead of the original changeType(DOMString) when given a null parameter.
+ // Fortunately, a null or empty SourceBufferConfig here similarly should yield
+ // a kNotSupportedError.
+ if (!config || (!config->hasAudioConfig() && !config->hasVideoConfig())) {
+ MediaSource::LogAndThrowDOMException(
+ exception_state, DOMExceptionCode::kNotSupportedError,
+ "Changing to the type provided ('null' config) is not supported.");
+ return;
+ }
+
+ // TODO(crbug.com/1144908): Further validate allowed in current state (and
+ // take lock at appropriate point), unwrap the config, validate it, update
+ // internals to new config, etc.
+ exception_state.ThrowTypeError(
+ "unimplemented - see https://crbug.com/1144908");
+}
+
void SourceBuffer::ChangeType_Locked(
const String& type,
ExceptionState* exception_state,
@@ -759,7 +1039,9 @@ void SourceBuffer::ChangeType_Locked(
// 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 (!MediaSource::isTypeSupported(GetExecutionContext(), type) ||
+ if (!MediaSource::IsTypeSupportedInternal(
+ GetExecutionContext(), type,
+ false /* allow underspecified codecs in |type| */) ||
!web_source_buffer_->CanChangeType(content_type.GetType(), codecs)) {
MediaSource::LogAndThrowDOMException(
*exception_state, DOMExceptionCode::kNotSupportedError,
@@ -806,8 +1088,9 @@ void SourceBuffer::setTrackDefaults(TrackDefaultList* track_defaults,
// 2. If the updating attribute equals true, then throw an InvalidStateError
// exception and abort these steps.
if (ThrowExceptionIfRemovedOrUpdating(IsRemoved(), updating_,
- exception_state))
+ exception_state)) {
return;
+ }
// 3. Update the attribute to the new value.
track_defaults_ = track_defaults;
@@ -839,17 +1122,41 @@ void SourceBuffer::AbortIfUpdating() {
DCHECK_EQ(pending_remove_start_, -1);
- const char* trace_event_name = "SourceBuffer::appendBuffer";
-
// 4.1. Abort the buffer append and stream append loop algorithms if they are
// running.
- append_buffer_async_task_handle_.Cancel();
- pending_append_data_.clear();
- pending_append_data_offset_ = 0;
-
// 4.2. Set the updating attribute to false.
updating_ = false;
+ if (pending_chunks_to_buffer_) {
+ append_encoded_chunks_async_task_handle_.Cancel();
+ pending_chunks_to_buffer_.reset();
+
+ // For async Promise resolution/rejection, we do not use events to notify
+ // the app, since event dispatch could occur after the promise callback
+ // microtask dispatch and violate the design principle, "Events should fire
+ // before Promises resolve", unless we introduced unnecessary further
+ // latency to enqueue a task to resolve/reject the promise. In this case,
+ // the elision of the "abort" and "updateend" events is synonymous with
+ // rejection with an AbortError DOMException, enabling faster abort
+ // notification. See
+ // https://w3ctag.github.io/design-principles/#promises-and-events
+ // TODO(crbug.com/1144908): Consider moving this verbosity to eventual
+ // specification.
+ DCHECK(append_encoded_chunks_resolver_);
+ append_encoded_chunks_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, "Aborted by explicit abort()"));
+ append_encoded_chunks_resolver_ = nullptr;
+ TRACE_EVENT_NESTABLE_ASYNC_END0(
+ "media", "SourceBuffer::appendEncodedChunks", TRACE_ID_LOCAL(this));
+ return;
+ }
+
+ DCHECK(!append_encoded_chunks_resolver_);
+ append_buffer_async_task_handle_.Cancel();
+ pending_append_data_.clear();
+ pending_append_data_offset_ = 0;
+ // For the regular, non-promisified appendBuffer abort, use events to notify
+ // result.
// 4.3. Queue a task to fire a simple event named abort at this SourceBuffer
// object.
ScheduleEvent(event_type_names::kAbort);
@@ -858,7 +1165,7 @@ void SourceBuffer::AbortIfUpdating() {
// SourceBuffer object.
ScheduleEvent(event_type_names::kUpdateend);
- TRACE_EVENT_NESTABLE_ASYNC_END0("media", trace_event_name,
+ TRACE_EVENT_NESTABLE_ASYNC_END0("media", "SourceBuffer::appendBuffer",
TRACE_ID_LOCAL(this));
}
@@ -1498,8 +1805,6 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
switch (warning) {
case WebSourceBufferClient::kKeyframeTimeGreaterThanDependant:
// Report this problematic GOP structure to help inform follow-up work.
- // Media engine also records RAPPOR for these, up to once per track, at
- // Media.OriginUrl.MSE.KeyframeTimeGreaterThanDependant.
// TODO(wolenetz): Use the data to scope additional work. See
// https://crbug.com/739931.
UseCounter::Count(
@@ -1508,8 +1813,6 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
break;
case WebSourceBufferClient::kMuxedSequenceMode:
// Report this problematic API usage to help inform follow-up work.
- // Media engine also records RAPPOR for these, up to once per
- // SourceBuffer, at Media.OriginUrl.MSE.MuxedSequenceModeSourceBuffer.
// TODO(wolenetz): Use the data to scope additional work. See
// https://crbug.com/737757.
UseCounter::Count(GetExecutionContext(),
@@ -1530,6 +1833,7 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
bool SourceBuffer::HasPendingActivity() const {
return updating_ || append_buffer_async_task_handle_.IsActive() ||
+ append_encoded_chunks_async_task_handle_.IsActive() ||
remove_async_task_handle_.IsActive() ||
(async_event_queue_ && async_event_queue_->HasPendingEvents());
}
@@ -1539,6 +1843,10 @@ void SourceBuffer::ContextDestroyed() {
pending_append_data_.clear();
pending_append_data_offset_ = 0;
+ append_encoded_chunks_async_task_handle_.Cancel();
+ pending_chunks_to_buffer_.reset();
+ append_encoded_chunks_resolver_ = nullptr;
+
remove_async_task_handle_.Cancel();
pending_remove_start_ = -1;
pending_remove_end_ = -1;
@@ -1728,6 +2036,23 @@ void SourceBuffer::AppendBufferInternal_Locked(
"type", "initialDelay");
}
+void SourceBuffer::AppendEncodedChunksAsyncPart() {
+ // Do the async append operation only if attachment is usable and underlying
+ // demuxer is protected from destruction (applicable especially for
+ // MSE-in-Worker case).
+ DCHECK(!IsRemoved()); // So must have |source_| and it must have attachment.
+ if (!source_->RunUnlessElementGoneOrClosingUs(
+ WTF::Bind(&SourceBuffer::AppendEncodedChunksAsyncPart_Locked,
+ WrapPersistent(this)))) {
+ // TODO(crbug.com/878133): Determine in specification what the specific,
+ // app-visible, behavior should be for this case. In this implementation,
+ // the safest thing to do is nothing here now. See more verbose reason in
+ // similar AppendBufferAsyncPart() implementation.
+ DVLOG(1) << __func__ << " this=" << this
+ << ": Worker MediaSource attachment is closing";
+ }
+}
+
void SourceBuffer::AppendBufferAsyncPart() {
// Do the async append operation only if attachment is usable and underlying
// demuxer is protected from destruction (applicable especially for
@@ -1750,6 +2075,51 @@ void SourceBuffer::AppendBufferAsyncPart() {
}
}
+void SourceBuffer::AppendEncodedChunksAsyncPart_Locked(
+ MediaSourceAttachmentSupplement::ExclusiveKey pass_key) {
+ DCHECK(source_);
+ source_->AssertAttachmentsMutexHeldIfCrossThreadForDebugging();
+ DCHECK(updating_);
+ DCHECK(append_encoded_chunks_resolver_);
+ DCHECK(pending_chunks_to_buffer_);
+
+ // Run the analogue to the segment parser loop.
+ // TODO(crbug.com/1144908): Consider buffering |pending_chunks_to_buffer_| in
+ // multiple async iterations if it contains many buffers. It is unclear if
+ // this is necessary when buffering encoded chunks.
+ TRACE_EVENT_NESTABLE_ASYNC_END0("media", "delay", TRACE_ID_LOCAL(this));
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("media", "appending", TRACE_ID_LOCAL(this),
+ "chunkCount",
+ pending_chunks_to_buffer_->size());
+
+ bool append_success = web_source_buffer_->AppendChunks(
+ std::move(pending_chunks_to_buffer_), &timestamp_offset_);
+
+ if (!append_success) {
+ AppendError(pass_key);
+ append_encoded_chunks_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kSyntaxError,
+ "Parsing or frame processing error while buffering encoded chunks."));
+ append_encoded_chunks_resolver_ = nullptr;
+ } else {
+ updating_ = false;
+
+ // Don't schedule 'update' or 'updateend' for this promisified async
+ // method's completion. Promise resolution/rejection will signal same,
+ // faster.
+ append_encoded_chunks_resolver_->Resolve();
+ append_encoded_chunks_resolver_ = nullptr;
+ }
+
+ TRACE_EVENT_NESTABLE_ASYNC_END0("media", "appending", TRACE_ID_LOCAL(this));
+ TRACE_EVENT_NESTABLE_ASYNC_END0("media", "SourceBuffer::appendEncodedChunks",
+ TRACE_ID_LOCAL(this));
+
+ DVLOG(3) << __func__ << " done. this=" << this
+ << " media_time=" << GetMediaTime() << " buffered="
+ << WebTimeRangesToString(web_source_buffer_->Buffered());
+}
+
void SourceBuffer::AppendBufferAsyncPart_Locked(
MediaSourceAttachmentSupplement::ExclusiveKey pass_key) {
DCHECK(source_);
@@ -1769,7 +2139,7 @@ void SourceBuffer::AppendBufferAsyncPart_Locked(
// doesn't block the renderer event loop very long. This value was selected
// by looking at YouTube SourceBuffer usage across a variety of bitrates.
// This value allows relatively large appends while keeping append() call
- // duration in the ~5-15ms range. Note that even in MSE-in-Worker case, we
+ // duration in the ~5-15ms range. Note that even in MSE-in-Worker case, we
// retain this behavior because some synchronous operations done by the main
// thread media element on our attachment block until we are finished and have
// exited the attachment's RunExclusively() callback scope.
@@ -1896,13 +2266,18 @@ void SourceBuffer::AppendError(
// 2. Set the updating attribute to false.
updating_ = false;
- // 3. Queue a task to fire a simple event named error at this SourceBuffer
- // object.
- ScheduleEvent(event_type_names::kError);
+ // Only schedule 'error' and 'updateend' here for the non-promisified regular
+ // appendBuffer asynchronous operation error. The promisified
+ // appendEncodedChunks rejection will be handled by caller.
+ if (!append_encoded_chunks_resolver_) {
+ // 3. Queue a task to fire a simple event named error at this SourceBuffer
+ // object.
+ ScheduleEvent(event_type_names::kError);
- // 4. Queue a task to fire a simple event named updateend at this SourceBuffer
- // object.
- ScheduleEvent(event_type_names::kUpdateend);
+ // 4. Queue a task to fire a simple event named updateend at this
+ // SourceBuffer object.
+ ScheduleEvent(event_type_names::kUpdateend);
+ }
// 5. If decode error is true, then run the end of stream algorithm with the
// error parameter set to "decode".
@@ -1914,6 +2289,7 @@ void SourceBuffer::Trace(Visitor* visitor) const {
visitor->Trace(source_);
visitor->Trace(track_defaults_);
visitor->Trace(async_event_queue_);
+ visitor->Trace(append_encoded_chunks_resolver_);
visitor->Trace(audio_tracks_);
visitor->Trace(video_tracks_);
EventTargetWithInlineData::Trace(visitor);
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 686117d1522..92bc0815e82 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
@@ -34,8 +34,10 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
+#include "media/base/stream_parser.h"
#include "third_party/blink/public/platform/web_source_buffer_client.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -50,11 +52,16 @@ namespace blink {
class AudioTrackList;
class DOMArrayBuffer;
class DOMArrayBufferView;
+class
+ EncodedAudioChunkOrEncodedVideoChunkSequenceOrEncodedAudioChunkOrEncodedVideoChunk;
class EventQueue;
class ExceptionState;
class MediaSource;
class MediaSourceTracer;
class MediaSourceAttachmentSupplement;
+class ScriptPromiseResolver;
+class ScriptState;
+class SourceBufferConfig;
class TimeRanges;
class VideoTrackList;
class WebSourceBuffer;
@@ -70,6 +77,10 @@ class SourceBuffer final : public EventTargetWithInlineData,
static AtomicString SegmentsKeyword();
static AtomicString SequenceKeyword();
+ // Mirror the IDL's typedef for EncodedChunks.
+ using EncodedChunks =
+ EncodedAudioChunkOrEncodedVideoChunkSequenceOrEncodedAudioChunkOrEncodedVideoChunk;
+
SourceBuffer(std::unique_ptr<WebSourceBuffer>, MediaSource*, EventQueue*);
~SourceBuffer() override;
@@ -82,9 +93,13 @@ class SourceBuffer final : public EventTargetWithInlineData,
void setTimestampOffset(double, ExceptionState&);
void appendBuffer(DOMArrayBuffer* data, ExceptionState&);
void appendBuffer(NotShared<DOMArrayBufferView> data, ExceptionState&);
+ ScriptPromise appendEncodedChunks(ScriptState*,
+ const EncodedChunks&,
+ ExceptionState&);
void abort(ExceptionState&);
void remove(double start, double end, ExceptionState&);
void changeType(const String& type, ExceptionState&);
+ void ChangeTypeUsingConfig(const SourceBufferConfig*, ExceptionState&);
double appendWindowStart() const;
void setAppendWindowStart(double, ExceptionState&);
double appendWindowEnd() const;
@@ -140,6 +155,7 @@ class SourceBuffer final : public EventTargetWithInlineData,
bool PrepareAppend(double media_time, size_t new_data_size, ExceptionState&);
bool EvictCodedFrames(double media_time, size_t new_data_size);
void AppendBufferInternal(const unsigned char*, size_t, ExceptionState&);
+ void AppendEncodedChunksAsyncPart();
void AppendBufferAsyncPart();
void AppendError(MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
@@ -175,11 +191,18 @@ class SourceBuffer final : public EventTargetWithInlineData,
const String& type,
ExceptionState*,
MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
+ void AppendEncodedChunks_Locked(
+ std::unique_ptr<media::StreamParser::BufferQueue> buffer_queue,
+ size_t size,
+ ExceptionState* exception_state,
+ MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
void AppendBufferInternal_Locked(
const unsigned char*,
size_t,
ExceptionState*,
MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
+ void AppendEncodedChunksAsyncPart_Locked(
+ MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
void AppendBufferAsyncPart_Locked(
MediaSourceAttachmentSupplement::ExclusiveKey /* passkey */);
void RemoveAsyncPart_Locked(
@@ -225,6 +248,7 @@ class SourceBuffer final : public EventTargetWithInlineData,
AtomicString mode_;
bool updating_;
+
double timestamp_offset_;
Member<AudioTrackList> audio_tracks_;
Member<VideoTrackList> video_tracks_;
@@ -232,10 +256,25 @@ class SourceBuffer final : public EventTargetWithInlineData,
double append_window_end_;
bool first_initialization_segment_received_;
+ // |updating_| logic, per spec, allows at most one of the following async
+ // operations to be exclusively pending for this SourceBuffer: appendBuffer(),
+ // appendEncodedChunks(), or remove(). The following three sections
+ // respectively track the async state for these pending operations:
+
+ // These are valid only during the scope of synchronous and asynchronous
+ // follow-up of appendBuffer().
Vector<unsigned char> pending_append_data_;
wtf_size_t pending_append_data_offset_;
TaskHandle append_buffer_async_task_handle_;
+ // This resolver is set and valid only during the scope of synchronous and
+ // asynchronous follow-up of appendEncodedChunks().
+ std::unique_ptr<media::StreamParser::BufferQueue> pending_chunks_to_buffer_;
+ Member<ScriptPromiseResolver> append_encoded_chunks_resolver_;
+ TaskHandle append_encoded_chunks_async_task_handle_;
+
+ // These are valid only during the scope of synchronous and asynchronous
+ // follow-up of remove().
double pending_remove_start_;
double pending_remove_end_;
TaskHandle remove_async_task_handle_;
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.idl b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.idl
index 04c0634fad0..5bcbbdc247a 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.idl
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.idl
@@ -30,6 +30,10 @@
// https://w3c.github.io/media-source/#idl-def-sourcebuffer
+// This typedef is needed for MSE-for-WebCodecs. Explainer:
+// https://github.com/wolenetz/mse-for-webcodecs/blob/main/explainer.md
+typedef (sequence<(EncodedAudioChunk or EncodedVideoChunk)> or EncodedAudioChunk or EncodedVideoChunk) EncodedChunks;
+
enum AppendMode {
"segments",
"sequence"
@@ -70,6 +74,15 @@ enum AppendMode {
[RaisesException] void appendBuffer(ArrayBuffer data);
[RaisesException] void appendBuffer(ArrayBufferView data);
+ // Append WebCodecs structured, "containerless" media. Explainer:
+ // https://github.com/wolenetz/mse-for-webcodecs/blob/main/explainer.md
+ [
+ CallWith=ScriptState,
+ RaisesException,
+ RuntimeEnabled=MediaSourceExtensionsForWebCodecs,
+ Measure
+ ] Promise<void> appendEncodedChunks(EncodedChunks chunks);
+
// Abort the current segment append sequence.
[RaisesException] void abort();
[RaisesException] void remove(double start, unrestricted double end);
@@ -77,6 +90,15 @@ enum AppendMode {
// Explicitly change the container or codecs
[RaisesException, Measure] void changeType(DOMString type);
+ // For MSE-for-WebCodecs. Explainer:
+ // https://github.com/wolenetz/mse-for-webcodecs/blob/main/explainer.md
+ [
+ RaisesException,
+ RuntimeEnabled=MediaSourceExtensionsForWebCodecs,
+ ImplementedAs=ChangeTypeUsingConfig,
+ MeasureAs=ChangeTypeUsingConfig
+ ] void changeType(SourceBufferConfig config);
+
// Gets or sets the TrackDefaultList this SourceBuffer may consult during
// the initialization segment algorithm.
[RaisesException=Setter, RuntimeEnabled=MediaSourceExperimental] attribute TrackDefaultList trackDefaults;
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_config.idl b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_config.idl
new file mode 100644
index 00000000000..5711e02a692
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer_config.idl
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+// For MSE-for-WebCodecs. Explainer:
+// https://github.com/wolenetz/mse-for-webcodecs/blob/main/explainer.md
+
+dictionary SourceBufferConfig {
+ // Precisely one of these must be populated to signal via addSourceBuffer or
+ // changeType the intent to buffer the corresponding WebCodecs media.
+ // We use this dictionary as the parameter for SourceBuffer's overloads of
+ // addSourceBuffer() and changeType() since sniffing config types introduces
+ // implementation interoperability risk, and specific overloads for each of
+ // AudioDecoderConfig and VideoDecoderConfig dictionaries would not be
+ // differentiable without such sniffing.
+ AudioDecoderConfig audioConfig; // For appending EncodedAudioChunks.
+ VideoDecoderConfig videoConfig; // For appending EncodedVideoChunks.
+};
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.cc b/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.cc
index 4a4bb665659..a1c58cabb91 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.cc
@@ -59,8 +59,6 @@ TrackDefault* TrackDefaultList::item(unsigned index) const {
return track_defaults_[index].Get();
}
-TrackDefaultList::TrackDefaultList() = default;
-
TrackDefaultList::TrackDefaultList(
const HeapVector<Member<TrackDefault>>& track_defaults)
: track_defaults_(track_defaults) {}
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.h b/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.h
index a3d7b4a0a14..e558f6dff4b 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/track_default_list.h
@@ -21,7 +21,7 @@ class TrackDefaultList final : public ScriptWrappable {
static TrackDefaultList* Create(const HeapVector<Member<TrackDefault>>&,
ExceptionState&);
- TrackDefaultList();
+ TrackDefaultList() = default;
explicit TrackDefaultList(const HeapVector<Member<TrackDefault>>&);
unsigned length() const { return track_defaults_.size(); }
@@ -30,7 +30,7 @@ class TrackDefaultList final : public ScriptWrappable {
void Trace(Visitor*) const override;
private:
- const HeapVector<Member<TrackDefault>> track_defaults_;
+ const HeapVector<Member<TrackDefault>> track_defaults_{};
};
} // namespace blink
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 4510b38268c..9b43bd8ecbe 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,7 +31,7 @@
#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 "base/types/pass_key.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -44,7 +44,7 @@ class URLMediaSource {
STATIC_ONLY(URLMediaSource);
public:
- using PassKey = util::PassKey<URLMediaSource>;
+ using PassKey = base::PassKey<URLMediaSource>;
static String createObjectURL(ScriptState*, MediaSource*);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
index 0a6afbd5edd..d8680cb2257 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -31,6 +31,10 @@ blink_modules_sources("mediastream") {
"media_stream.h",
"media_stream_audio_processor.cc",
"media_stream_audio_processor.h",
+ "media_stream_audio_track_underlying_sink.cc",
+ "media_stream_audio_track_underlying_sink.h",
+ "media_stream_audio_track_underlying_source.cc",
+ "media_stream_audio_track_underlying_source.h",
"media_stream_constraints_util.cc",
"media_stream_constraints_util.h",
"media_stream_constraints_util_audio.cc",
@@ -68,6 +72,7 @@ blink_modules_sources("mediastream") {
"media_stream_video_source.cc",
"media_stream_video_track.cc",
"media_stream_video_track.h",
+ "media_stream_video_track_signal_observer.h",
"media_stream_video_track_underlying_sink.cc",
"media_stream_video_track_underlying_sink.h",
"media_stream_video_track_underlying_source.cc",
@@ -78,6 +83,8 @@ blink_modules_sources("mediastream") {
"overconstrained_error.h",
"processed_local_audio_source.cc",
"processed_local_audio_source.h",
+ "pushable_media_stream_audio_source.cc",
+ "pushable_media_stream_audio_source.h",
"pushable_media_stream_video_source.cc",
"pushable_media_stream_video_source.h",
"remote_media_stream_track_adapter.cc",
@@ -98,6 +105,10 @@ blink_modules_sources("mediastream") {
"video_track_adapter.h",
"video_track_adapter_settings.cc",
"video_track_adapter_settings.h",
+ "video_track_signal_underlying_sink.cc",
+ "video_track_signal_underlying_sink.h",
+ "video_track_signal_underlying_source.cc",
+ "video_track_signal_underlying_source.h",
"web_media_stream_device_observer.cc",
"web_media_stream_utils.cc",
"webaudio_media_stream_audio_sink.cc",
@@ -112,6 +123,7 @@ blink_modules_sources("mediastream") {
"//media/capture/mojom:image_capture_blink",
"//media/webrtc",
"//services/viz/public/cpp/gpu:gpu",
+ "//third_party/blink/public/common",
"//third_party/blink/renderer/modules/imagecapture:imagecapture",
"//third_party/libyuv:libyuv",
]
@@ -128,6 +140,8 @@ source_set("test_support") {
"mock_constraint_factory.cc",
"mock_constraint_factory.h",
"mock_encoded_video_frame.h",
+ "mock_media_stream_audio_sink.cc",
+ "mock_media_stream_audio_sink.h",
"mock_media_stream_registry.cc",
"mock_media_stream_registry.h",
"mock_media_stream_video_sink.cc",
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/DEPS b/chromium/third_party/blink/renderer/modules/mediastream/DEPS
index 89ddbdb77f1..f3eb7f78578 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/DEPS
+++ b/chromium/third_party/blink/renderer/modules/mediastream/DEPS
@@ -25,6 +25,7 @@ include_rules = [
"+skia/ext/platform_canvas.h",
"+base/atomicops.h",
+ "+base/bind_post_task.h",
"+base/files/file.h",
"+base/metrics/field_trial.h",
@@ -45,6 +46,8 @@ include_rules = [
"+third_party/blink/renderer/modules/mediastream",
"+third_party/blink/renderer/modules/modules_export.h",
"+third_party/blink/renderer/modules/peerconnection",
+ "+third_party/blink/renderer/modules/webcodecs/audio_frame.h",
+ "+third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h",
"+third_party/blink/renderer/modules/webcodecs/video_frame.h",
"+third_party/blink/renderer/modules/webrtc",
"+ui/gfx/geometry/size.h",
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/DIR_METADATA b/chromium/third_party/blink/renderer/modules/mediastream/DIR_METADATA
new file mode 100644
index 00000000000..02d2785a62c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>GetUserMedia"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/OWNERS b/chromium/third_party/blink/renderer/modules/mediastream/OWNERS
index 0bdfba2d69d..947c899590e 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/mediastream/OWNERS
@@ -3,6 +3,3 @@ hbos@chromium.org
tommi@chromium.org
per-file media_stream_audio_processor*=olka@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
index 38b6d7733d2..c5a4d77a652 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
@@ -249,8 +249,10 @@ blink::VideoCaptureSettings ApplyConstraintsProcessor::SelectVideoSettings(
device_capabilities.device_id = current_request_->Track()->Source()->Id();
device_capabilities.group_id = current_request_->Track()->Source()->GroupId();
device_capabilities.facing_mode =
- GetCurrentVideoSource() ? GetCurrentVideoSource()->device().video_facing
- : media::MEDIA_VIDEO_FACING_NONE;
+ GetCurrentVideoSource()
+ ? static_cast<mojom::blink::FacingMode>(
+ GetCurrentVideoSource()->device().video_facing)
+ : mojom::blink::FacingMode::NONE;
device_capabilities.formats = std::move(formats);
blink::VideoDeviceCaptureCapabilities video_capabilities;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc b/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
index 9e64389f733..9ef3ba43498 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
@@ -15,8 +15,9 @@
#include "third_party/blink/renderer/bindings/modules/v8/long_or_constrain_long_range.h"
#include "third_party/blink/renderer/bindings/modules/v8/point_2d_sequence_or_constrain_point_2d_parameters.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_string_sequence_or_constrain_dom_string_parameters.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_constraints.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_track_constraint_set.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/modules/mediastream/media_track_constraint_set.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.h b/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.h
index a718c58cf84..e2ce4234791 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/identifiability_metrics.h
@@ -7,10 +7,12 @@
#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/modules/mediastream/media_stream_constraints.h"
namespace blink {
+class ExecutionContext;
+class MediaStreamConstraints;
+
IdentifiableToken TokenFromConstraints(
const MediaStreamConstraints* constraints);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/idls.gni b/chromium/third_party/blink/renderer/modules/mediastream/idls.gni
index 0e316f48ec8..e5f1b6f7b60 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/mediastream/idls.gni
@@ -25,6 +25,9 @@ modules_dictionary_idl_files = [
"media_stream_constraints.idl",
"media_stream_event_init.idl",
"media_stream_track_event_init.idl",
+ "media_stream_track_generator_init.idl",
+ "media_stream_track_processor_init.idl",
+ "media_stream_track_signal.idl",
"media_track_capabilities.idl",
"media_track_constraint_set.idl",
"media_track_constraints.idl",
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
index de235d0db4f..308a16fdf7d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
@@ -85,7 +85,7 @@ bool LocalMediaStreamAudioSource::EnsureSourceIsStarted() {
<< GetAudioParameters().AsHumanReadableString() << "}.";
auto* web_frame =
- static_cast<WebLocalFrame*>(WebFrame::FromFrame(consumer_frame_));
+ static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(consumer_frame_));
source_ = Platform::Current()->NewAudioCapturerSource(
web_frame, media::AudioSourceParameters(device().session_id()));
source_->Initialize(GetAudioParameters(), this);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.h b/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.h
index 1dbd78f9069..2e5ae859215 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.h
@@ -22,7 +22,7 @@ class LocalFrame;
// using the parameters and session ID found in MediaStreamDevice, just before
// the first track is connected. Audio data is transported directly to the
// tracks (i.e., there is no audio processing).
-class MODULES_EXPORT LocalMediaStreamAudioSource
+class MODULES_EXPORT LocalMediaStreamAudioSource final
: public MediaStreamAudioSource,
public media::AudioCapturerSource::CaptureCallback {
public:
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm.cc b/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm.cc
index c87f993b9e6..0ee0b6f7a50 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm.cc
@@ -107,7 +107,7 @@ void LowLatencyVideoRendererAlgorithm::Reset() {
void LowLatencyVideoRendererAlgorithm::EnqueueFrame(
scoped_refptr<media::VideoFrame> frame) {
DCHECK(frame);
- DCHECK(!frame->metadata()->end_of_stream);
+ DCHECK(!frame->metadata().end_of_stream);
frame_queue_.push_back(std::move(frame));
++stats_.total_frames;
}
@@ -138,7 +138,7 @@ size_t LowLatencyVideoRendererAlgorithm::DetermineModeAndNumberOfFramesToRender(
int max_remaining_queue_length =
frame_queue_.back()
->metadata()
- ->maximum_composition_delay_in_frames.value_or(
+ .maximum_composition_delay_in_frames.value_or(
kDefaultMaxCompositionDelayInFrames);
// The number of frames in the queue is in the range
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm_unittest.cc b/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm_unittest.cc
index ad9f6de3503..237d7deb49d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/low_latency_video_renderer_algorithm_unittest.cc
@@ -25,7 +25,7 @@ class LowLatencyVideoRendererAlgorithmTest : public testing::Test {
scoped_refptr<media::VideoFrame> frame = frame_pool_.CreateFrame(
media::PIXEL_FORMAT_I420, natural_size, gfx::Rect(natural_size),
natural_size, base::TimeDelta());
- frame->metadata()->maximum_composition_delay_in_frames =
+ frame->metadata().maximum_composition_delay_in_frames =
maximum_composition_delay_in_frames;
return frame;
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
index 3fcfe53cae4..1823a3213e9 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
@@ -368,15 +368,16 @@ static void ParseOldStyleNames(
}
result.enable_dtls_srtp.SetExact(ToBoolean(constraint.value_));
} else if (constraint.name_.Equals(kEnableRtpDataChannels)) {
+ // This constraint does not turn on RTP data channels, but we do not
+ // want it to cause an error, so we parse it and ignore it.
bool value = ToBoolean(constraint.value_);
if (value) {
Deprecation::CountDeprecation(
context, WebFeature::kRTCConstraintEnableRtpDataChannelsTrue);
} else {
- UseCounter::Count(context,
- WebFeature::kRTCConstraintEnableRtpDataChannelsFalse);
+ Deprecation::CountDeprecation(
+ context, WebFeature::kRTCConstraintEnableRtpDataChannelsFalse);
}
- result.enable_rtp_data_channels.SetExact(ToBoolean(constraint.value_));
} else if (constraint.name_.Equals(kEnableDscp)) {
result.enable_dscp.SetExact(ToBoolean(constraint.value_));
} else if (constraint.name_.Equals(kEnableIPv6)) {
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 eff3e1a5a2d..821de11ab6a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -39,6 +39,10 @@ namespace blink {
namespace {
+const char kFeaturePolicyBlocked[] =
+ "Access to the feature \"display-capture\" is disallowed by permission "
+ "policy.";
+
class PromiseResolverCallbacks final : public UserMediaRequest::Callbacks {
public:
explicit PromiseResolverCallbacks(ScriptPromiseResolver* resolver)
@@ -185,6 +189,26 @@ ScriptPromise MediaDevices::getCurrentBrowsingContextMedia(
ScriptState* script_state,
const MediaStreamConstraints* options,
ExceptionState& exception_state) {
+ const ExecutionContext* const context = GetExecutionContext();
+ if (!context) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "The implementation did not support the requested type of object or "
+ "operation.");
+ return ScriptPromise();
+ }
+
+ // This call should not be possible otherwise, as per the RuntimeEnabled
+ // in the IDL.
+ CHECK(RuntimeEnabledFeatures::GetCurrentBrowsingContextMediaEnabled(context));
+
+ if (!context->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kDisplayCapture,
+ ReportOptions::kReportOnFailure)) {
+ exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
+ return ScriptPromise();
+ }
+
return SendUserMediaRequest(
script_state,
UserMediaRequest::MediaType::kGetCurrentBrowsingContextMedia, options,
@@ -297,7 +321,7 @@ namespace {
void RecordEnumeratedDevices(ScriptPromiseResolver* resolver,
const MediaDeviceInfoVector& media_devices) {
if (!IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
- WebFeature::kMediaDevicesEnumerateDevices)) {
+ WebFeature::kIdentifiabilityMediaDevicesEnumerateDevices)) {
return;
}
Document* document = LocalDOMWindow::From(resolver->GetScriptState())
@@ -305,13 +329,13 @@ void RecordEnumeratedDevices(ScriptPromiseResolver* resolver,
->GetDocument();
IdentifiableTokenBuilder builder;
for (const auto& device_info : media_devices) {
- builder.AddToken(IdentifiabilityBenignStringToken(device_info->deviceId()));
+ // Ignore device_id since that varies per-site.
builder.AddToken(IdentifiabilityBenignStringToken(device_info->kind()));
builder.AddToken(IdentifiabilityBenignStringToken(device_info->label()));
- builder.AddToken(IdentifiabilityBenignStringToken(device_info->groupId()));
+ // Ignore group_id since that is varies per-site.
}
IdentifiabilityMetricBuilder(document->UkmSourceID())
- .SetWebfeature(WebFeature::kMediaDevicesEnumerateDevices,
+ .SetWebfeature(WebFeature::kIdentifiabilityMediaDevicesEnumerateDevices,
builder.GetToken())
.Record(document->UkmRecorder());
}
@@ -361,12 +385,15 @@ void MediaDevices::DevicesEnumerated(
mojom::blink::MediaDeviceType device_type =
static_cast<mojom::blink::MediaDeviceType>(i);
WebMediaDeviceInfo device_info = enumeration[i][j];
+ String device_label = String::FromUTF8(device_info.label);
+ if (device_label.Contains("AirPods")) {
+ device_label = "AirPods";
+ }
if (device_type == mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT ||
device_type == mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT) {
InputDeviceInfo* input_device_info =
MakeGarbageCollected<InputDeviceInfo>(
- String::FromUTF8(device_info.device_id),
- String::FromUTF8(device_info.label),
+ String::FromUTF8(device_info.device_id), device_label,
String::FromUTF8(device_info.group_id), device_type);
if (device_type == mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT &&
!video_input_capabilities.IsEmpty()) {
@@ -381,8 +408,7 @@ void MediaDevices::DevicesEnumerated(
media_devices.push_back(input_device_info);
} else {
media_devices.push_back(MakeGarbageCollected<MediaDeviceInfo>(
- String::FromUTF8(device_info.device_id),
- String::FromUTF8(device_info.label),
+ String::FromUTF8(device_info.device_id), device_label,
String::FromUTF8(device_info.group_id), device_type));
}
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
index 2ba40ccfe20..3a997a4e282 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -27,11 +27,14 @@ namespace blink {
const char kFakeAudioInputDeviceId1[] = "fake_audio_input 1";
const char kFakeAudioInputDeviceId2[] = "fake_audio_input 2";
+const char kFakeAudioInputDeviceId3[] = "fake_audio_input 3";
const char kFakeVideoInputDeviceId1[] = "fake_video_input 1";
const char kFakeVideoInputDeviceId2[] = "fake_video_input 2";
const char kFakeCommonGroupId1[] = "fake_group 1";
+const char kFakeCommonGroupId2[] = "fake_group 2";
const char kFakeVideoInputGroupId2[] = "fake_video_input_group 2";
const char kFakeAudioOutputDeviceId1[] = "fake_audio_output 1";
+const char kFakeAudioOutputDeviceId2[] = "fake_audio_output 2";
class MockMediaDevicesDispatcherHost
: public mojom::blink::MediaDevicesDispatcherHost {
@@ -60,8 +63,15 @@ class MockMediaDevicesDispatcherHost
.push_back(device_info);
device_info.device_id = kFakeAudioInputDeviceId2;
- device_info.label = "Fake Audio Input 2";
- device_info.group_id = "fake_group 2";
+ device_info.label = "X's AirPods";
+ device_info.group_id = kFakeCommonGroupId2;
+ enumeration[static_cast<size_t>(
+ blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT)]
+ .push_back(device_info);
+
+ device_info.device_id = kFakeAudioInputDeviceId3;
+ device_info.label = "Fake Audio Input 3";
+ device_info.group_id = "fake_group 3";
enumeration[static_cast<size_t>(
blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT)]
.push_back(device_info);
@@ -89,13 +99,13 @@ class MockMediaDevicesDispatcherHost
mojom::blink::VideoInputDeviceCapabilities::New();
capabilities->device_id = kFakeVideoInputDeviceId1;
capabilities->group_id = kFakeCommonGroupId1;
- capabilities->facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ capabilities->facing_mode = mojom::blink::FacingMode::NONE;
video_input_capabilities.push_back(std::move(capabilities));
capabilities = mojom::blink::VideoInputDeviceCapabilities::New();
capabilities->device_id = kFakeVideoInputDeviceId2;
capabilities->group_id = kFakeVideoInputGroupId2;
- capabilities->facing_mode = media::MEDIA_VIDEO_FACING_USER;
+ capabilities->facing_mode = mojom::blink::FacingMode::USER;
video_input_capabilities.push_back(std::move(capabilities));
}
}
@@ -106,6 +116,13 @@ class MockMediaDevicesDispatcherHost
enumeration[static_cast<size_t>(
blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_OUTPUT)]
.push_back(device_info);
+
+ device_info.device_id = kFakeAudioOutputDeviceId2;
+ device_info.label = "X's AirPods";
+ device_info.group_id = kFakeCommonGroupId2;
+ enumeration[static_cast<size_t>(
+ blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_OUTPUT)]
+ .push_back(device_info);
}
std::move(callback).Run(std::move(enumeration),
std::move(video_input_capabilities),
@@ -261,7 +278,7 @@ TEST_F(MediaDevicesTest, EnumerateDevices) {
ASSERT_FALSE(promise.IsEmpty());
EXPECT_TRUE(devices_enumerated());
- EXPECT_EQ(5u, device_infos().size());
+ EXPECT_EQ(7u, device_infos().size());
// Audio input device with matched output ID.
Member<MediaDeviceInfo> device = device_infos()[0];
@@ -270,37 +287,59 @@ TEST_F(MediaDevicesTest, EnumerateDevices) {
EXPECT_FALSE(device->label().IsEmpty());
EXPECT_FALSE(device->groupId().IsEmpty());
- // Audio input device without matched output ID.
+ // Audio input device with Airpods label.
device = device_infos()[1];
EXPECT_FALSE(device->deviceId().IsEmpty());
EXPECT_EQ("audioinput", device->kind());
EXPECT_FALSE(device->label().IsEmpty());
EXPECT_FALSE(device->groupId().IsEmpty());
- // Video input devices.
+ // Audio input device without matched output ID.
device = device_infos()[2];
EXPECT_FALSE(device->deviceId().IsEmpty());
- EXPECT_EQ("videoinput", device->kind());
+ EXPECT_EQ("audioinput", device->kind());
EXPECT_FALSE(device->label().IsEmpty());
EXPECT_FALSE(device->groupId().IsEmpty());
+ // Video input devices.
device = device_infos()[3];
EXPECT_FALSE(device->deviceId().IsEmpty());
EXPECT_EQ("videoinput", device->kind());
EXPECT_FALSE(device->label().IsEmpty());
EXPECT_FALSE(device->groupId().IsEmpty());
- // Audio output device.
device = device_infos()[4];
EXPECT_FALSE(device->deviceId().IsEmpty());
+ EXPECT_EQ("videoinput", device->kind());
+ EXPECT_FALSE(device->label().IsEmpty());
+ EXPECT_FALSE(device->groupId().IsEmpty());
+
+ // Audio output device.
+ device = device_infos()[5];
+ EXPECT_FALSE(device->deviceId().IsEmpty());
+ EXPECT_EQ("audiooutput", device->kind());
+ EXPECT_FALSE(device->label().IsEmpty());
+ EXPECT_FALSE(device->groupId().IsEmpty());
+
+ // Audio output device with Airpods label.
+ device = device_infos()[6];
+ EXPECT_FALSE(device->deviceId().IsEmpty());
EXPECT_EQ("audiooutput", device->kind());
EXPECT_FALSE(device->label().IsEmpty());
EXPECT_FALSE(device->groupId().IsEmpty());
// Verify group IDs.
- EXPECT_EQ(device_infos()[0]->groupId(), device_infos()[2]->groupId());
- EXPECT_EQ(device_infos()[0]->groupId(), device_infos()[4]->groupId());
- EXPECT_NE(device_infos()[1]->groupId(), device_infos()[4]->groupId());
+ EXPECT_EQ(device_infos()[0]->groupId(), device_infos()[3]->groupId());
+ EXPECT_EQ(device_infos()[0]->groupId(), device_infos()[5]->groupId());
+ EXPECT_NE(device_infos()[2]->groupId(), device_infos()[5]->groupId());
+
+ // Verify device labels do not expose user's information.
+ EXPECT_EQ(device_infos()[1]->label(), "AirPods");
+ EXPECT_EQ(device_infos()[6]->label(), "AirPods");
+
+ // Verify the code does not change non-sensitive device labels.
+ EXPECT_EQ(device_infos()[0]->label(), "Fake Audio Input 1");
+ EXPECT_EQ(device_infos()[3]->label(), "Fake Video Input 1");
}
TEST_F(MediaDevicesTest, EnumerateDevicesAfterConnectionError) {
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 a47adc88820..e010f2b3f75 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc
@@ -556,6 +556,7 @@ void MediaStream::Trace(Visitor* visitor) const {
visitor->Trace(video_tracks_);
visitor->Trace(descriptor_);
visitor->Trace(observers_);
+ visitor->Trace(scheduled_event_timer_);
visitor->Trace(scheduled_events_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextClient::Trace(visitor);
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 d2d601eaf2f..3d673415097 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h
@@ -177,7 +177,7 @@ class MODULES_EXPORT MediaStream final
// including image capture for video tracks.
base::OnceCallback<void(MediaStream*)> media_stream_initialized_callback_;
- TaskRunnerTimer<MediaStream> scheduled_event_timer_;
+ HeapTaskRunnerTimer<MediaStream> scheduled_event_timer_;
HeapVector<Member<Event>> scheduled_events_;
uint32_t number_of_video_tracks_initialized_ = 0;
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 868b1729ac0..4b8b5b3abb8 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
@@ -589,14 +589,14 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
agc2_properties = blink::AdaptiveGainController2Properties{};
agc2_properties->vad_probability_attack =
base::GetFieldTrialParamByFeatureAsDouble(
- features::kWebRtcHybridAgc, "vad_probability_attack", 1.0);
+ features::kWebRtcHybridAgc, "vad_probability_attack", 0.3);
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);
+ "level_estimator_speech_frames_threshold", 6);
agc2_properties->initial_saturation_margin_db =
base::GetFieldTrialParamByFeatureAsInt(
features::kWebRtcHybridAgc, "initial_saturation_margin", 20);
@@ -606,13 +606,19 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
agc2_properties->gain_applier_speech_frames_threshold =
base::GetFieldTrialParamByFeatureAsInt(
features::kWebRtcHybridAgc,
- "gain_applier_speech_frames_threshold", 1);
+ "gain_applier_speech_frames_threshold", 6);
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);
+ features::kWebRtcHybridAgc, "max_output_noise_level_dbfs", -55);
+ agc2_properties->sse2_allowed = base::GetFieldTrialParamByFeatureAsBool(
+ features::kWebRtcHybridAgc, "sse2_allowed", true);
+ agc2_properties->avx2_allowed = base::GetFieldTrialParamByFeatureAsBool(
+ features::kWebRtcHybridAgc, "avx2_allowed", true);
+ agc2_properties->neon_allowed = base::GetFieldTrialParamByFeatureAsBool(
+ features::kWebRtcHybridAgc, "neon_allowed", true);
}
blink::ConfigAutomaticGainControl(
properties.goog_auto_gain_control,
@@ -700,6 +706,10 @@ void MediaStreamAudioProcessor::InitializeCaptureFifo(
output_format_ = media::AudioParameters(
media::AudioParameters::AUDIO_PCM_LOW_LATENCY, output_channel_layout,
output_sample_rate, output_frames);
+ if (output_channel_layout == media::CHANNEL_LAYOUT_DISCRETE) {
+ // Explicitly set number of channels for discrete channel layouts.
+ output_format_.set_channels_for_discrete(input_format.channels());
+ }
capture_fifo_.reset(
new MediaStreamAudioFifo(input_format.channels(), fifo_output_channels,
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
index 81995cd35b0..a82b231feb0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
@@ -11,6 +11,7 @@
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "media/webrtc/audio_delay_stats_reporter.h"
@@ -117,7 +118,11 @@ class MODULES_EXPORT MediaStreamAudioProcessor
friend class MediaStreamAudioProcessorTest;
FRIEND_TEST_ALL_PREFIXES(MediaStreamAudioProcessorTest,
- GetAecDumpMessageFilter);
+ TestAgcEnableDefaultAgc1);
+ FRIEND_TEST_ALL_PREFIXES(MediaStreamAudioProcessorTest,
+ TestAgcEnableHybridAgc);
+ FRIEND_TEST_ALL_PREFIXES(MediaStreamAudioProcessorTest,
+ TestAgcEnableHybridAgcSimdNotAllowed);
// WebRtcPlayoutDataSource::Sink implementation.
void OnPlayoutData(media::AudioBus* audio_bus,
@@ -126,6 +131,14 @@ class MODULES_EXPORT MediaStreamAudioProcessor
void OnPlayoutDataSourceChanged() override;
void OnRenderThreadChanged() override;
+ base::Optional<webrtc::AudioProcessing::Config>
+ GetAudioProcessingModuleConfig() const {
+ if (audio_processing_) {
+ return audio_processing_->GetConfig();
+ }
+ return base::nullopt;
+ }
+
// This method is called on the libjingle thread.
AudioProcessorStatistics GetStats(bool has_remote_tracks) override;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
index a5a812af30e..93f01703a0d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
@@ -14,12 +14,14 @@
#include "base/memory/aligned_memory.h"
#include "base/path_service.h"
#include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_parameters.h"
+#include "media/webrtc/webrtc_switches.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
@@ -392,4 +394,140 @@ TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestWithKeyboardMicChannel) {
audio_processor->Stop();
}
+TEST_F(MediaStreamAudioProcessorTest, TestAgcEnableDefaultAgc1) {
+ ::base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(features::kWebRtcHybridAgc);
+
+ blink::AudioProcessingProperties properties;
+ properties.goog_auto_gain_control = true;
+ properties.goog_experimental_auto_gain_control = false;
+
+ scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
+ new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
+ scoped_refptr<MediaStreamAudioProcessor> audio_processor(
+ new rtc::RefCountedObject<MediaStreamAudioProcessor>(
+ properties, webrtc_audio_device.get()));
+
+ base::Optional<webrtc::AudioProcessing::Config> apm_config =
+ audio_processor->GetAudioProcessingModuleConfig();
+ ASSERT_TRUE(apm_config);
+
+ EXPECT_TRUE(apm_config->gain_controller1.enabled);
+ EXPECT_EQ(
+ apm_config->gain_controller1.mode,
+#if defined(OS_ANDROID)
+ webrtc::AudioProcessing::Config::GainController1::Mode::kFixedDigital);
+#else
+ webrtc::AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog);
+#endif // defined(OS_ANDROID)
+}
+
+TEST_F(MediaStreamAudioProcessorTest, TestAgcEnableHybridAgc) {
+ ::base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeatureWithParameters(
+ features::kWebRtcHybridAgc,
+ {{"vad_probability_attack", "0.2"},
+ {"use_peaks_not_rms", "true"},
+ {"level_estimator_speech_frames_threshold", "3"},
+ {"initial_saturation_margin", "10"},
+ {"extra_saturation_margin", "11"},
+ {"gain_applier_speech_frames_threshold", "5"},
+ {"max_gain_change_db_per_second", "4"},
+ {"max_output_noise_level_dbfs", "-22"},
+ {"sse2_allowed", "true"},
+ {"avx2_allowed", "true"},
+ {"neon_allowed", "true"}});
+
+ blink::AudioProcessingProperties properties;
+ properties.goog_auto_gain_control = true;
+ properties.goog_experimental_auto_gain_control = true;
+
+ scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
+ new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
+ scoped_refptr<MediaStreamAudioProcessor> audio_processor(
+ new rtc::RefCountedObject<MediaStreamAudioProcessor>(
+ properties, webrtc_audio_device.get()));
+
+ base::Optional<webrtc::AudioProcessing::Config> apm_config =
+ audio_processor->GetAudioProcessingModuleConfig();
+ ASSERT_TRUE(apm_config);
+
+ EXPECT_TRUE(apm_config->gain_controller1.enabled);
+ EXPECT_EQ(
+ apm_config->gain_controller1.mode,
+#if defined(OS_ANDROID)
+ webrtc::AudioProcessing::Config::GainController1::Mode::kFixedDigital);
+#else
+ webrtc::AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog);
+#endif // defined(OS_ANDROID)
+ EXPECT_TRUE(apm_config->gain_controller2.enabled);
+ // `compression_gain_db` has no effect when hybrid AGC is active.
+ EXPECT_EQ(apm_config->gain_controller2.fixed_digital.gain_db, 0);
+
+ const auto& adaptive_digital = apm_config->gain_controller2.adaptive_digital;
+ EXPECT_TRUE(adaptive_digital.enabled);
+ EXPECT_FLOAT_EQ(adaptive_digital.vad_probability_attack, 0.2f);
+ EXPECT_EQ(
+ adaptive_digital.level_estimator,
+ webrtc::AudioProcessing::Config::GainController2::LevelEstimator::kPeak);
+ EXPECT_EQ(adaptive_digital.level_estimator_adjacent_speech_frames_threshold,
+ 3);
+ EXPECT_FLOAT_EQ(adaptive_digital.initial_saturation_margin_db, 10);
+ EXPECT_FLOAT_EQ(adaptive_digital.extra_saturation_margin_db, 11);
+ EXPECT_EQ(adaptive_digital.gain_applier_adjacent_speech_frames_threshold, 5);
+ EXPECT_FLOAT_EQ(adaptive_digital.max_gain_change_db_per_second, 4);
+ EXPECT_FLOAT_EQ(adaptive_digital.max_output_noise_level_dbfs, -22);
+ EXPECT_TRUE(adaptive_digital.sse2_allowed);
+ EXPECT_TRUE(adaptive_digital.avx2_allowed);
+ EXPECT_TRUE(adaptive_digital.neon_allowed);
+}
+
+TEST_F(MediaStreamAudioProcessorTest, TestAgcEnableHybridAgcSimdNotAllowed) {
+ ::base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeatureWithParameters(features::kWebRtcHybridAgc,
+ {{"sse2_allowed", "false"},
+ {"avx2_allowed", "false"},
+ {"neon_allowed", "false"}});
+
+ blink::AudioProcessingProperties properties;
+ properties.goog_auto_gain_control = true;
+ properties.goog_experimental_auto_gain_control = true;
+
+ scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
+ new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
+ scoped_refptr<MediaStreamAudioProcessor> audio_processor(
+ new rtc::RefCountedObject<MediaStreamAudioProcessor>(
+ properties, webrtc_audio_device.get()));
+
+ base::Optional<webrtc::AudioProcessing::Config> apm_config =
+ audio_processor->GetAudioProcessingModuleConfig();
+ ASSERT_TRUE(apm_config);
+
+ EXPECT_FALSE(apm_config->gain_controller2.adaptive_digital.sse2_allowed);
+ EXPECT_FALSE(apm_config->gain_controller2.adaptive_digital.avx2_allowed);
+ EXPECT_FALSE(apm_config->gain_controller2.adaptive_digital.neon_allowed);
+}
+
+// Ensure that discrete channel layouts do not crash with audio processing
+// enabled.
+TEST_F(MediaStreamAudioProcessorTest, DiscreteChannelLayout) {
+ blink::AudioProcessingProperties properties;
+ scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
+ new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
+ scoped_refptr<MediaStreamAudioProcessor> audio_processor(
+ new rtc::RefCountedObject<MediaStreamAudioProcessor>(
+ properties, webrtc_audio_device.get()));
+ EXPECT_TRUE(audio_processor->has_audio_processing());
+
+ media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_DISCRETE, 48000, 480);
+ // Test both 1 and 2 discrete channels.
+ for (int channels = 1; channels <= 2; ++channels) {
+ params.set_channels_for_discrete(channels);
+ audio_processor->OnCaptureFormatChanged(params);
+ }
+
+ audio_processor->Stop();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.cc
new file mode 100644
index 00000000000..b4bc610ceb4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h"
+
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.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/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+MediaStreamAudioTrackUnderlyingSink::MediaStreamAudioTrackUnderlyingSink(
+ PushableMediaStreamAudioSource* source)
+ : source_(source->GetWeakPtr()) {}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSink::start(
+ ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSink::write(
+ ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ AudioFrame* audio_frame = V8AudioFrame::ToImplWithTypeCheck(
+ script_state->GetIsolate(), chunk.V8Value());
+ if (!audio_frame) {
+ exception_state.ThrowTypeError("Null audio frame.");
+ return ScriptPromise();
+ }
+
+ if (!audio_frame->buffer()) {
+ exception_state.ThrowTypeError("Empty or closed audio frame.");
+ return ScriptPromise();
+ }
+
+ PushableMediaStreamAudioSource* pushable_source =
+ static_cast<PushableMediaStreamAudioSource*>(source_.get());
+ if (!pushable_source || !pushable_source->running()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Stream closed");
+ return ScriptPromise();
+ }
+
+ pushable_source->PushAudioData(audio_frame->GetSerializationData());
+ audio_frame->close();
+
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSink::abort(
+ ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) {
+ if (source_)
+ source_->StopSource();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSink::close(
+ ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (source_)
+ source_->StopSource();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h
new file mode 100644
index 00000000000..34f201ae25e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SINK_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SINK_H_
+
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+
+namespace blink {
+
+class MediaStreamAudioSource;
+class PushableMediaStreamAudioSource;
+
+class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSink
+ : public UnderlyingSinkBase {
+ public:
+ // |source| must outlive this MediaStreamAudioTrackUnderlyingSink.
+ explicit MediaStreamAudioTrackUnderlyingSink(
+ PushableMediaStreamAudioSource* source);
+
+ // UnderlyingSinkBase overrides.
+ ScriptPromise start(ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override;
+ ScriptPromise write(ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override;
+ ScriptPromise abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) override;
+ ScriptPromise close(ScriptState* script_state,
+ ExceptionState& exception_state) override;
+
+ private:
+ base::WeakPtr<MediaStreamAudioSource> source_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink_test.cc
new file mode 100644
index 00000000000..27c41a70a3b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink_test.cc
@@ -0,0 +1,188 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "base/test/gmock_callback_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+
+using testing::_;
+using testing::StrictMock;
+
+namespace blink {
+
+class MediaStreamAudioTrackUnderlyingSinkTest : public testing::Test {
+ public:
+ MediaStreamAudioTrackUnderlyingSinkTest() {
+ // Use the IO thread for testing purposes, instead of an audio task runner.
+ pushable_audio_source_ = new PushableMediaStreamAudioSource(
+ Thread::MainThread()->GetTaskRunner(),
+ Platform::Current()->GetIOTaskRunner());
+ media_stream_source_ = MakeGarbageCollected<MediaStreamSource>(
+ "dummy_source_id", MediaStreamSource::kTypeAudio, "dummy_source_name",
+ /*remote=*/false);
+ media_stream_source_->SetPlatformSource(
+ base::WrapUnique(pushable_audio_source_));
+ }
+
+ ~MediaStreamAudioTrackUnderlyingSinkTest() override {
+ platform_->RunUntilIdle();
+ WebHeap::CollectAllGarbageForTesting();
+ }
+
+ MediaStreamAudioTrackUnderlyingSink* CreateUnderlyingSink(
+ ScriptState* script_state) {
+ return MakeGarbageCollected<MediaStreamAudioTrackUnderlyingSink>(
+ pushable_audio_source_);
+ }
+
+ void CreateTrackAndConnectToSource() {
+ media_stream_component_ = MakeGarbageCollected<MediaStreamComponent>(
+ media_stream_source_->Id(), media_stream_source_);
+ pushable_audio_source_->ConnectToTrack(media_stream_component_);
+ }
+
+ ScriptValue CreateAudioFrame(ScriptState* script_state,
+ AudioFrame** audio_frame_out = nullptr) {
+ const scoped_refptr<media::AudioBuffer> media_buffer =
+ media::AudioBuffer::CreateEmptyBuffer(
+ media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
+ /*channel_count=*/2,
+ /*sample_rate=*/44100,
+ /*frame_count=*/500, base::TimeDelta());
+ AudioFrame* audio_frame =
+ MakeGarbageCollected<AudioFrame>(std::move(media_buffer));
+ if (audio_frame_out)
+ *audio_frame_out = audio_frame;
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(audio_frame, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+ }
+
+ protected:
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+ Persistent<MediaStreamSource> media_stream_source_;
+ Persistent<MediaStreamComponent> media_stream_component_;
+
+ PushableMediaStreamAudioSource* pushable_audio_source_;
+};
+
+TEST_F(MediaStreamAudioTrackUnderlyingSinkTest,
+ WriteToStreamForwardsToMediaStreamSink) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* underlying_sink = CreateUnderlyingSink(script_state);
+ auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_sink, 1u);
+
+ CreateTrackAndConnectToSource();
+
+ base::RunLoop write_loop;
+ StrictMock<MockMediaStreamAudioSink> mock_sink;
+ EXPECT_CALL(mock_sink, OnSetFormat(_)).Times(::testing::AnyNumber());
+ EXPECT_CALL(mock_sink, OnData(_, _))
+ .WillOnce(base::test::RunOnceClosure(write_loop.QuitClosure()));
+
+ WebMediaStreamAudioSink::AddToAudioTrack(
+ &mock_sink, WebMediaStreamTrack(media_stream_component_.Get()));
+
+ NonThrowableExceptionState exception_state;
+ auto* writer = writable_stream->getWriter(script_state, exception_state);
+
+ AudioFrame* audio_frame = nullptr;
+ auto audio_frame_chunk = CreateAudioFrame(script_state, &audio_frame);
+ EXPECT_NE(audio_frame, nullptr);
+ EXPECT_NE(audio_frame->buffer(), nullptr);
+ ScriptPromiseTester write_tester(
+ script_state,
+ writer->write(script_state, audio_frame_chunk, exception_state));
+ // |audio_frame| should be invalidated after sending it to the sink.
+ write_tester.WaitUntilSettled();
+ EXPECT_EQ(audio_frame->buffer(), nullptr);
+ write_loop.Run();
+
+ writer->releaseLock(script_state);
+ ScriptPromiseTester close_tester(
+ script_state, writable_stream->close(script_state, exception_state));
+ close_tester.WaitUntilSettled();
+
+ // Writing to the sink after the stream closes should fail.
+ DummyExceptionStateForTesting dummy_exception_state;
+ underlying_sink->write(script_state, CreateAudioFrame(script_state), nullptr,
+ dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(
+ &mock_sink, WebMediaStreamTrack(media_stream_component_.Get()));
+}
+
+TEST_F(MediaStreamAudioTrackUnderlyingSinkTest, WriteInvalidDataFails) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* sink = CreateUnderlyingSink(script_state);
+ ScriptValue v8_integer = ScriptValue::From(script_state, 0);
+
+ // Writing something that is not an AudioFrame to the sink should fail.
+ DummyExceptionStateForTesting dummy_exception_state;
+ sink->write(script_state, v8_integer, nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+
+ // Writing a null value to the sink should fail.
+ dummy_exception_state.ClearException();
+ EXPECT_FALSE(dummy_exception_state.HadException());
+ sink->write(script_state, ScriptValue::CreateNull(v8_scope.GetIsolate()),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+
+ // Writing a closed AudioFrame to the sink should fail.
+ dummy_exception_state.ClearException();
+ AudioFrame* audio_frame = nullptr;
+ auto chunk = CreateAudioFrame(script_state, &audio_frame);
+ audio_frame->close();
+ EXPECT_FALSE(dummy_exception_state.HadException());
+ sink->write(script_state, chunk, nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+}
+
+TEST_F(MediaStreamAudioTrackUnderlyingSinkTest, WriteToAbortedSinkFails) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* underlying_sink = CreateUnderlyingSink(script_state);
+ auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_sink, 1u);
+
+ NonThrowableExceptionState exception_state;
+ ScriptPromiseTester abort_tester(
+ script_state, writable_stream->abort(script_state, exception_state));
+ abort_tester.WaitUntilSettled();
+
+ // Writing to the sink after the stream closes should fail.
+ DummyExceptionStateForTesting dummy_exception_state;
+ underlying_sink->write(script_state, CreateAudioFrame(script_state), nullptr,
+ dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc
new file mode 100644
index 00000000000..653aed52c50
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc
@@ -0,0 +1,170 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.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/streams/readable_stream_default_controller_with_script_scope.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.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/mediastream/media_stream_audio_track.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/webrtc/api/frame_transformer_interface.h"
+
+namespace blink {
+
+MediaStreamAudioTrackUnderlyingSource::MediaStreamAudioTrackUnderlyingSource(
+ ScriptState* script_state,
+ MediaStreamComponent* track,
+ wtf_size_t max_queue_size)
+ : UnderlyingSourceBase(script_state),
+ main_task_runner_(ExecutionContext::From(script_state)
+ ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
+ track_(track),
+ max_queue_size_(std::max(1u, max_queue_size)) {
+ DCHECK(track_);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSource::pull(
+ ScriptState* script_state) {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ if (!queue_.empty()) {
+ ProcessPullRequest();
+ } else {
+ is_pending_pull_ = true;
+ }
+
+ DCHECK_LT(queue_.size(), max_queue_size_);
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSource::Start(
+ ScriptState* script_state) {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ MediaStreamAudioTrack* audio_track = MediaStreamAudioTrack::From(track_);
+ if (!audio_track) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ "No input track",
+ DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError)));
+ }
+ WebMediaStreamAudioSink::AddToAudioTrack(this, WebMediaStreamTrack(track_));
+
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise MediaStreamAudioTrackUnderlyingSource::Cancel(
+ ScriptState* script_state,
+ ScriptValue reason) {
+ DisconnectFromTrack();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+void MediaStreamAudioTrackUnderlyingSource::DisconnectFromTrack() {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ if (!track_)
+ return;
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(this,
+ WebMediaStreamTrack(track_));
+
+ track_.Clear();
+}
+
+void MediaStreamAudioTrackUnderlyingSource::Trace(Visitor* visitor) const {
+ visitor->Trace(track_);
+ UnderlyingSourceBase::Trace(visitor);
+}
+
+double MediaStreamAudioTrackUnderlyingSource::DesiredSizeForTesting() const {
+ return Controller()->DesiredSize();
+}
+
+void MediaStreamAudioTrackUnderlyingSource::ContextDestroyed() {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ UnderlyingSourceBase::ContextDestroyed();
+ queue_.clear();
+}
+
+void MediaStreamAudioTrackUnderlyingSource::Close() {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DisconnectFromTrack();
+
+ // Check for Controller(), as the context might have been destroyed.
+ if (Controller())
+ Controller()->Close();
+ queue_.clear();
+}
+
+void MediaStreamAudioTrackUnderlyingSource::OnData(
+ const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) {
+ DCHECK(audio_parameters_.IsValid());
+
+ auto data_copy =
+ media::AudioBus::Create(audio_bus.channels(), audio_bus.frames());
+ audio_bus.CopyTo(data_copy.get());
+
+ auto queue_data = AudioFrameSerializationData::Wrap(
+ std::move(data_copy), audio_parameters_.sample_rate(),
+ estimated_capture_time - base::TimeTicks());
+
+ PostCrossThreadTask(
+ *main_task_runner_, FROM_HERE,
+ CrossThreadBindOnce(
+ &MediaStreamAudioTrackUnderlyingSource::OnDataOnMainThread,
+ WrapCrossThreadPersistent(this), std::move(queue_data)));
+}
+
+void MediaStreamAudioTrackUnderlyingSource::OnDataOnMainThread(
+ std::unique_ptr<AudioFrameSerializationData> queue_data) {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_LE(queue_.size(), max_queue_size_);
+
+ // If the |queue_| is empty and the consumer has signaled a pull, bypass
+ // |queue_| and send the frame directly to the stream controller.
+ if (queue_.empty() && is_pending_pull_) {
+ SendFrameToStream(std::move(queue_data));
+ return;
+ }
+
+ if (queue_.size() == max_queue_size_)
+ queue_.pop_front();
+
+ queue_.emplace_back(std::move(queue_data));
+ if (is_pending_pull_) {
+ ProcessPullRequest();
+ }
+}
+
+void MediaStreamAudioTrackUnderlyingSource::OnSetFormat(
+ const media::AudioParameters& params) {
+ DCHECK(params.IsValid());
+ audio_parameters_ = params;
+}
+
+void MediaStreamAudioTrackUnderlyingSource::ProcessPullRequest() {
+ DCHECK(!queue_.empty());
+ SendFrameToStream(std::move(queue_.front()));
+ queue_.pop_front();
+}
+
+void MediaStreamAudioTrackUnderlyingSource::SendFrameToStream(
+ std::unique_ptr<AudioFrameSerializationData> queue_data) {
+ if (!Controller())
+ return;
+
+ AudioFrame* audio_frame =
+ MakeGarbageCollected<AudioFrame>(std::move(queue_data));
+ Controller()->Enqueue(audio_frame);
+ is_pending_pull_ = false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h
new file mode 100644
index 00000000000..77e9c862789
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h
@@ -0,0 +1,83 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SOURCE_H_
+
+#include "base/threading/thread_checker.h"
+#include "media/base/audio_parameters.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+
+namespace blink {
+
+class AudioFrameSerializationData;
+class MediaStreamComponent;
+
+class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource
+ : public UnderlyingSourceBase,
+ public WebMediaStreamAudioSink {
+ public:
+ explicit MediaStreamAudioTrackUnderlyingSource(ScriptState*,
+ MediaStreamComponent*,
+ wtf_size_t queue_size);
+ MediaStreamAudioTrackUnderlyingSource(
+ const MediaStreamAudioTrackUnderlyingSource&) = delete;
+ MediaStreamAudioTrackUnderlyingSource& operator=(
+ const MediaStreamAudioTrackUnderlyingSource&) = delete;
+
+ // UnderlyingSourceBase
+ ScriptPromise pull(ScriptState*) override;
+ ScriptPromise Start(ScriptState*) override;
+ ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
+
+ // WebMediaStreamAudioSink
+ void OnData(const media::AudioBus& audio_bus,
+ base::TimeTicks estimated_capture_time) override;
+ void OnSetFormat(const media::AudioParameters& params) override;
+
+ // ExecutionLifecycleObserver
+ void ContextDestroyed() override;
+
+ MediaStreamComponent* Track() const { return track_.Get(); }
+ wtf_size_t MaxQueueSize() const { return max_queue_size_; }
+
+ const Deque<std::unique_ptr<AudioFrameSerializationData>>& QueueForTesting()
+ const {
+ return queue_;
+ }
+ bool IsPendingPullForTesting() const { return is_pending_pull_; }
+
+ double DesiredSizeForTesting() const;
+
+ void Close();
+ void Trace(Visitor*) const override;
+
+ private:
+ void ProcessPullRequest();
+ void SendFrameToStream(std::unique_ptr<AudioFrameSerializationData>);
+
+ void DisconnectFromTrack();
+
+ void OnDataOnMainThread(std::unique_ptr<AudioFrameSerializationData> data);
+
+ const scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+ Member<MediaStreamComponent> track_;
+
+ media::AudioParameters audio_parameters_;
+
+ // An internal deque prior to the stream controller's queue. It acts as a ring
+ // buffer and allows dropping old frames instead of new ones in case frames
+ // accumulate due to slow consumption.
+ Deque<std::unique_ptr<AudioFrameSerializationData>> queue_;
+ const wtf_size_t max_queue_size_;
+ bool is_pending_pull_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source_test.cc
new file mode 100644
index 00000000000..16a78179027
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source_test.cc
@@ -0,0 +1,245 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h"
+
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.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/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+using testing::_;
+using testing::AnyNumber;
+
+namespace blink {
+
+class MediaStreamAudioTrackUnderlyingSourceTest : public testing::Test {
+ public:
+ MediaStreamAudioTrackUnderlyingSourceTest()
+ : media_stream_source_(MakeGarbageCollected<MediaStreamSource>(
+ "dummy_source_id",
+ MediaStreamSource::kTypeAudio,
+ "dummy_source_name",
+ false /* remote */)),
+ pushable_audio_source_(new PushableMediaStreamAudioSource(
+ Thread::MainThread()->GetTaskRunner(),
+ Platform::Current()->GetIOTaskRunner())) {
+ media_stream_source_->SetPlatformSource(
+ base::WrapUnique(pushable_audio_source_));
+
+ component_ = MakeGarbageCollected<MediaStreamComponent>(
+ String::FromUTF8("audio_track"), media_stream_source_);
+ pushable_audio_source_->ConnectToTrack(component_);
+ }
+
+ ~MediaStreamAudioTrackUnderlyingSourceTest() override {
+ platform_->RunUntilIdle();
+ component_ = nullptr;
+ media_stream_source_ = nullptr;
+ WebHeap::CollectAllGarbageForTesting();
+ }
+
+ MediaStreamComponent* CreateTrack(ExecutionContext* execution_context) {
+ return MakeGarbageCollected<MediaStreamTrack>(execution_context, component_)
+ ->Component();
+ }
+
+ MediaStreamAudioTrackUnderlyingSource* CreateSource(ScriptState* script_state,
+ wtf_size_t buffer_size) {
+ MediaStreamComponent* track =
+ MakeGarbageCollected<MediaStreamTrack>(
+ ExecutionContext::From(script_state), component_)
+ ->Component();
+ return MakeGarbageCollected<MediaStreamAudioTrackUnderlyingSource>(
+ script_state, track, buffer_size);
+ }
+
+ MediaStreamAudioTrackUnderlyingSource* CreateSource(
+ ScriptState* script_state) {
+ return CreateSource(script_state, 1u);
+ }
+
+ protected:
+ void PushFrame(
+ const base::Optional<base::TimeDelta>& timestamp = base::nullopt) {
+ auto data = AudioFrameSerializationData::Wrap(
+ media::AudioBus::Create(/*channels=*/2, /*frames=*/10),
+ /*sample_rate=*/8000,
+ timestamp.value_or(base::TimeDelta::FromSeconds(1)));
+ pushable_audio_source_->PushAudioData(std::move(data));
+ platform_->RunUntilIdle();
+ }
+
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+ Persistent<MediaStreamSource> media_stream_source_;
+ Persistent<MediaStreamComponent> component_;
+ PushableMediaStreamAudioSource* const pushable_audio_source_;
+};
+
+TEST_F(MediaStreamAudioTrackUnderlyingSourceTest,
+ AudioFrameFlowsThroughStreamAndCloses) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state);
+ auto* stream =
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ NonThrowableExceptionState exception_state;
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, exception_state);
+
+ ScriptPromiseTester read_tester(script_state,
+ reader->read(script_state, exception_state));
+ EXPECT_FALSE(read_tester.IsFulfilled());
+ PushFrame();
+ read_tester.WaitUntilSettled();
+ EXPECT_TRUE(read_tester.IsFulfilled());
+
+ source->Close();
+}
+
+TEST_F(MediaStreamAudioTrackUnderlyingSourceTest,
+ CancelStreamDisconnectsFromTrack) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state);
+ auto* stream =
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ // The stream is connected to a sink.
+ EXPECT_TRUE(source->Track());
+
+ NonThrowableExceptionState exception_state;
+ stream->cancel(script_state, exception_state);
+
+ // Canceling the stream disconnects it from the track.
+ EXPECT_FALSE(source->Track());
+}
+
+// TODO(crbug.com/1174118): Fix and re-enable.
+TEST_F(MediaStreamAudioTrackUnderlyingSourceTest,
+ DISABLED_DropOldFramesWhenQueueIsFull) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ const wtf_size_t buffer_size = 5;
+ auto* source = CreateSource(script_state, buffer_size);
+ EXPECT_EQ(source->MaxQueueSize(), buffer_size);
+ // Create a stream to ensure there is a controller associated to the source.
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ // Add a sink to the track to make it possible to wait until a pushed frame
+ // is delivered to sinks, including |source|, which is a sink of the track.
+ MockMediaStreamAudioSink mock_sink;
+ WebMediaStreamTrack track(source->Track());
+ WebMediaStreamAudioSink::AddToAudioTrack(&mock_sink, track);
+
+ auto push_frame_sync = [&mock_sink, this](const base::TimeDelta timestamp) {
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_sink, OnData(_, _))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ PushFrame(timestamp);
+ sink_loop.Run();
+ };
+
+ const auto& queue = source->QueueForTesting();
+ for (wtf_size_t i = 0; i < buffer_size; ++i) {
+ EXPECT_EQ(queue.size(), i);
+ base::TimeDelta timestamp = base::TimeDelta::FromSeconds(i);
+ push_frame_sync(timestamp);
+ EXPECT_EQ(queue.back()->timestamp(), timestamp);
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta());
+ }
+
+ // Push another frame while the queue is full.
+ EXPECT_EQ(queue.size(), buffer_size);
+ push_frame_sync(base::TimeDelta::FromSeconds(buffer_size));
+
+ // Since the queue was full, the oldest frame from the queue should have been
+ // dropped.
+ EXPECT_EQ(queue.size(), buffer_size);
+ EXPECT_EQ(queue.back()->timestamp(),
+ base::TimeDelta::FromSeconds(buffer_size));
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(1));
+
+ // Pulling with frames in the queue should move the oldest frame in the queue
+ // to the stream's controller.
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ source->pull(script_state);
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ EXPECT_EQ(queue.size(), buffer_size - 1);
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(2));
+
+ source->Close();
+ EXPECT_EQ(queue.size(), 0u);
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(&mock_sink, track);
+}
+
+TEST_F(MediaStreamAudioTrackUnderlyingSourceTest,
+ BypassQueueAfterPullWithEmptyBuffer) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state);
+ // Create a stream to ensure there is a controller associated to the source.
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ MockMediaStreamAudioSink mock_sink;
+ WebMediaStreamTrack track(source->Track());
+ WebMediaStreamAudioSink::AddToAudioTrack(&mock_sink, track);
+
+ auto push_frame_sync = [&mock_sink, this]() {
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_sink, OnData(_, _))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ PushFrame();
+ sink_loop.Run();
+ };
+
+ // At first, the queue is empty and the desired size is empty as well.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+
+ source->pull(script_state);
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_TRUE(source->IsPendingPullForTesting());
+
+ push_frame_sync();
+ // Since a pull was pending, the frame is put directly in the stream
+ // controller, bypassing the source queue.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+
+ source->Close();
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(&mock_sink, track);
+}
+
+TEST_F(MediaStreamAudioTrackUnderlyingSourceTest, QueueSizeCannotBeZero) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state, 0u);
+ // Queue size is always at least 1, even if 0 is requested.
+ EXPECT_EQ(source->MaxQueueSize(), 1u);
+ source->Close();
+}
+
+} // namespace blink
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 9f300df6d9f..a8690e839fe 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
@@ -281,7 +281,7 @@ double StringConstraintFitnessDistance(const WebString& value,
MediaStreamSource::Capabilities ComputeCapabilitiesForVideoSource(
const String& device_id,
const media::VideoCaptureFormats& formats,
- media::VideoFacingMode facing_mode,
+ mojom::blink::FacingMode facing_mode,
bool is_device_capture,
const base::Optional<std::string>& group_id) {
MediaStreamSource::Capabilities capabilities;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
index 5ec959ebf2f..a57535f692a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h
@@ -9,6 +9,7 @@
#include "media/base/video_facing.h"
#include "media/capture/video_capture_types.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.h"
#include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -339,7 +340,7 @@ MODULES_EXPORT MediaStreamSource::Capabilities
ComputeCapabilitiesForVideoSource(
const String& device_id,
const media::VideoCaptureFormats& formats,
- media::VideoFacingMode facing_mode,
+ mojom::blink::FacingMode facing_mode,
bool is_device_capture,
const base::Optional<std::string>& group_id = base::nullopt);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
index 61212b44630..5a7b78b41e8 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
@@ -313,7 +313,7 @@ class EchoCancellationContainer {
device_parameters_(device_parameters),
is_device_capture_(is_device_capture) {
if (!has_active_source) {
-#if defined(OS_MAC) || BUILDFLAG(IS_ASH)
+#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
// If force system echo cancellation feature is enabled, only expose that
// type if available; otherwise expose no type.
if (base::FeatureList::IsEnabled(features::kForceEnableSystemAec)) {
@@ -322,7 +322,7 @@ class EchoCancellationContainer {
{EchoCancellationType::kEchoCancellationSystem,
EchoCancellationType::kEchoCancellationDisabled}));
}
-#endif // defined(OS_MAC) || BUILDFLAG(IS_ASH)
+#endif // defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
return;
}
@@ -441,13 +441,13 @@ class EchoCancellationContainer {
static bool ShouldUseExperimentalSystemEchoCanceller(
const media::AudioParameters& parameters) {
-#if defined(OS_MAC) || BUILDFLAG(IS_ASH)
+#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
if (base::FeatureList::IsEnabled(features::kForceEnableSystemAec) &&
(parameters.effects() &
media::AudioParameters::EXPERIMENTAL_ECHO_CANCELLER)) {
return true;
}
-#endif // defined(OS_MAC) || BUILDFLAG(IS_ASH)
+#endif // defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
return false;
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
index a2e047a3793..00550c48409 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/callback_helpers.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "build/build_config.h"
#include "media/base/audio_parameters.h"
#include "media/webrtc/webrtc_switches.h"
@@ -1925,10 +1925,12 @@ TEST_P(MediaStreamConstraintsUtilAudioTest, LatencyConstraint) {
default_device_max);
CheckLocalMediaStreamAudioSourceLatency(
default_device_, 0.003,
- default_device_min * media::AudioParameters::kAudioCDSampleRate);
+ default_device_min *
+ static_cast<double>(media::AudioParameters::kAudioCDSampleRate));
CheckLocalMediaStreamAudioSourceLatency(
default_device_, 0.015,
- default_device_min * media::AudioParameters::kAudioCDSampleRate);
+ default_device_min *
+ static_cast<double>(media::AudioParameters::kAudioCDSampleRate));
CheckLocalMediaStreamAudioSourceLatency(default_device_, 0.022, 1000);
CheckLocalMediaStreamAudioSourceLatency(default_device_, 0.04, 1000);
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 dcb574f36e0..3a0631f2507 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
@@ -41,11 +41,11 @@ const int kNumDefaultDistanceEntries = 4;
const char kVideoKindColor[] = "color";
const char kVideoKindDepth[] = "depth";
-WebString ToWebString(media::VideoFacingMode facing_mode) {
+WebString ToWebString(mojom::blink::FacingMode facing_mode) {
switch (facing_mode) {
- case media::MEDIA_VIDEO_FACING_USER:
+ case mojom::blink::FacingMode::USER:
return WebString::FromASCII("user");
- case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
+ case mojom::blink::FacingMode::ENVIRONMENT:
return WebString::FromASCII("environment");
default:
return WebString();
@@ -430,7 +430,7 @@ class CandidateFormat {
// Returns true if the facing mode |value| satisfies |constraints|, false
// otherwise.
-bool FacingModeSatisfiesConstraint(media::VideoFacingMode value,
+bool FacingModeSatisfiesConstraint(mojom::blink::FacingMode value,
const StringConstraint& constraint) {
WebString string_value = ToWebString(value);
if (string_value.IsNull())
@@ -693,7 +693,7 @@ VideoInputDeviceCapabilities::VideoInputDeviceCapabilities(
String group_id,
const media::VideoCaptureControlSupport& control_support,
Vector<media::VideoCaptureFormat> formats,
- media::VideoFacingMode facing_mode)
+ mojom::blink::FacingMode facing_mode)
: device_id(std::move(device_id)),
group_id(std::move(group_id)),
control_support(control_support),
@@ -714,13 +714,13 @@ WebString GetVideoKindForFormat(const media::VideoCaptureFormat& format) {
}
MediaStreamTrackPlatform::FacingMode ToPlatformFacingMode(
- media::VideoFacingMode video_facing) {
+ mojom::blink::FacingMode video_facing) {
switch (video_facing) {
- case media::MEDIA_VIDEO_FACING_NONE:
+ case mojom::blink::FacingMode::NONE:
return MediaStreamTrackPlatform::FacingMode::kNone;
- case media::MEDIA_VIDEO_FACING_USER:
+ case mojom::blink::FacingMode::USER:
return MediaStreamTrackPlatform::FacingMode::kUser;
- case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
+ case mojom::blink::FacingMode::ENVIRONMENT:
return MediaStreamTrackPlatform::FacingMode::kEnvironment;
default:
return MediaStreamTrackPlatform::FacingMode::kNone;
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 ac8ffa0c4be..096e15ec59b 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
@@ -7,6 +7,7 @@
#include "base/optional.h"
#include "media/capture/video_capture_types.h"
+#include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -25,7 +26,7 @@ MODULES_EXPORT WebString
GetVideoKindForFormat(const media::VideoCaptureFormat& format);
MODULES_EXPORT MediaStreamTrackPlatform::FacingMode ToPlatformFacingMode(
- media::VideoFacingMode video_facing);
+ mojom::blink::FacingMode video_facing);
// This is a temporary struct to bridge blink and content mojo types.
struct MODULES_EXPORT VideoInputDeviceCapabilities {
@@ -34,7 +35,7 @@ struct MODULES_EXPORT VideoInputDeviceCapabilities {
String group_id,
const media::VideoCaptureControlSupport& control_support,
Vector<media::VideoCaptureFormat> formats,
- media::VideoFacingMode facing_mode);
+ mojom::blink::FacingMode facing_mode);
VideoInputDeviceCapabilities();
VideoInputDeviceCapabilities(VideoInputDeviceCapabilities&& other);
VideoInputDeviceCapabilities& operator=(VideoInputDeviceCapabilities&& other);
@@ -44,7 +45,7 @@ struct MODULES_EXPORT VideoInputDeviceCapabilities {
String group_id;
media::VideoCaptureControlSupport control_support;
Vector<media::VideoCaptureFormat> formats;
- media::VideoFacingMode facing_mode;
+ mojom::blink::FacingMode facing_mode;
};
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 3eabce2fd82..2456068b7f6 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
@@ -82,7 +82,7 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
VideoInputDeviceCapabilities device;
device.device_id = kDeviceID1;
device.group_id = kGroupID1;
- device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ device.facing_mode = mojom::blink::FacingMode::NONE;
device.formats = {
media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f,
media::PIXEL_FORMAT_I420),
@@ -100,7 +100,7 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
// A low-resolution device.
device.device_id = kDeviceID2;
device.group_id = kGroupID2;
- device.facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT;
+ device.facing_mode = mojom::blink::FacingMode::ENVIRONMENT;
device.formats = {
media::VideoCaptureFormat(gfx::Size(40, 30), 20.0f,
media::PIXEL_FORMAT_I420),
@@ -123,7 +123,7 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
// A high-resolution device.
device.device_id = kDeviceID3;
device.group_id = kGroupID3;
- device.facing_mode = media::MEDIA_VIDEO_FACING_USER;
+ device.facing_mode = mojom::blink::FacingMode::USER;
device.formats = {
media::VideoCaptureFormat(gfx::Size(600, 400), 10.0f,
media::PIXEL_FORMAT_I420),
@@ -157,7 +157,7 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
// A depth capture device.
device.device_id = kDeviceID4;
device.group_id = kGroupID4;
- device.facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT;
+ device.facing_mode = mojom::blink::FacingMode::ENVIRONMENT;
device.formats = {media::VideoCaptureFormat(gfx::Size(640, 480), 30.0f,
media::PIXEL_FORMAT_Y16)};
device.control_support.pan = true;
@@ -169,7 +169,7 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
// be supported if no constraints are placed on the frame rate.
device.device_id = kDeviceID5;
device.group_id = kGroupID5;
- device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ device.facing_mode = mojom::blink::FacingMode::NONE;
device.formats = {
media::VideoCaptureFormat(
gfx::Size(MediaStreamVideoSource::kDefaultWidth,
@@ -405,7 +405,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
VideoDeviceCaptureCapabilities capabilities;
VideoInputDeviceCapabilities device;
device.device_id = kDeviceID1;
- device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ device.facing_mode = mojom::blink::FacingMode::NONE;
device.formats = {
media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f,
media::PIXEL_FORMAT_I420),
@@ -505,7 +505,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFacingMode) {
// Only the low-res device supports environment facing mode. Should select
// default settings for everything else.
EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
- EXPECT_EQ(media::MEDIA_VIDEO_FACING_ENVIRONMENT,
+ EXPECT_EQ(mojom::blink::FacingMode::ENVIRONMENT,
low_res_device_->facing_mode);
EXPECT_EQ(*low_res_closest_format_, result.Format());
CheckTrackAdapterSettingsEqualsFormat(result);
@@ -516,7 +516,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFacingMode) {
// Only the high-res device supports user facing mode. Should select default
// settings for everything else.
EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
- EXPECT_EQ(media::MEDIA_VIDEO_FACING_USER, high_res_device_->facing_mode);
+ EXPECT_EQ(mojom::blink::FacingMode::USER, high_res_device_->facing_mode);
EXPECT_EQ(*high_res_closest_format_, result.Format());
CheckTrackAdapterSettingsEqualsFormat(result);
}
@@ -1140,7 +1140,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxFrameRate) {
// MaxFrameRate greater than the maximum allowed.
{
constraint_factory_.Reset();
- const double kMaxFrameRate = media::limits::kMaxFramesPerSecond + 0.1;
+ const double kMaxFrameRate =
+ static_cast<double>(media::limits::kMaxFramesPerSecond) + 0.1;
constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate);
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
@@ -1992,7 +1993,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
VideoDeviceCaptureCapabilities capabilities;
VideoInputDeviceCapabilities device;
device.device_id = kDeviceID1;
- device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ device.facing_mode = mojom::blink::FacingMode::NONE;
device.formats = {
media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f,
media::PIXEL_FORMAT_I420),
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h
index 2390fe107c9..c941ed7014a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h
@@ -27,7 +27,7 @@ class MediaStreamInternalFrameWrapper {
if (!frame_)
return nullptr;
- return static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame()));
+ return static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(frame()));
}
private:
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 34c06b5705a..4c6fd8ac425 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
@@ -89,12 +89,9 @@ bool ConstraintSetHasImageCapture(
constraint_set->hasColorTemperature() || constraint_set->hasIso() ||
constraint_set->hasBrightness() || constraint_set->hasContrast() ||
constraint_set->hasSaturation() || constraint_set->hasSharpness() ||
- constraint_set->hasFocusDistance() ||
- (RuntimeEnabledFeatures::MediaCapturePanTiltEnabled() &&
- constraint_set->hasPan()) ||
- (RuntimeEnabledFeatures::MediaCapturePanTiltEnabled() &&
- constraint_set->hasTilt()) ||
- constraint_set->hasZoom() || constraint_set->hasTorch();
+ constraint_set->hasFocusDistance() || constraint_set->hasPan() ||
+ constraint_set->hasTilt() || constraint_set->hasZoom() ||
+ constraint_set->hasTorch();
}
bool ConstraintSetHasNonImageCapture(
@@ -405,12 +402,27 @@ String MediaStreamTrack::readyState() const {
return String();
}
+void MediaStreamTrack::setReadyState(
+ MediaStreamSource::ReadyState ready_state) {
+ if (ready_state_ != MediaStreamSource::kReadyStateEnded &&
+ ready_state_ != ready_state) {
+ ready_state_ = ready_state;
+
+ // Observers may dispatch events which create and add new Observers;
+ // take a snapshot so as to safely iterate.
+ HeapVector<Member<Observer>> observers;
+ CopyToVector(observers_, observers);
+ for (auto observer : observers)
+ observer->TrackChangedState();
+ }
+}
+
void MediaStreamTrack::stopTrack(ExecutionContext* execution_context) {
SendLogMessage(base::StringPrintf("stopTrack([id=%s])", id().Utf8().c_str()));
if (Ended())
return;
- ready_state_ = MediaStreamSource::kReadyStateEnded;
+ setReadyState(MediaStreamSource::kReadyStateEnded);
feature_handle_for_scheduler_.reset();
UserMediaController* user_media =
UserMediaController::From(To<LocalDOMWindow>(execution_context));
@@ -426,6 +438,9 @@ MediaStreamTrack* MediaStreamTrack::clone(ScriptState* script_state) {
ExecutionContext::From(script_state), cloned_component, ready_state_,
base::DoNothing());
DidCloneMediaStreamTrack(Component(), cloned_component);
+ if (image_capture_) {
+ cloned_track->image_capture_ = image_capture_->Clone();
+ }
return cloned_track;
}
@@ -743,7 +758,7 @@ void MediaStreamTrack::SourceChangedState() {
// 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();
+ setReadyState(component_->Source()->GetReadyState());
switch (ready_state_) {
case MediaStreamSource::kReadyStateLive:
component_->SetMuted(false);
@@ -826,6 +841,7 @@ void MediaStreamTrack::Trace(Visitor* visitor) const {
visitor->Trace(component_);
visitor->Trace(image_capture_);
visitor->Trace(execution_context_);
+ visitor->Trace(observers_);
EventTargetWithInlineData::Trace(visitor);
}
@@ -846,4 +862,8 @@ void MediaStreamTrack::EnsureFeatureHandleForScheduler() {
SchedulingPolicy::DisableAggressiveThrottling());
}
+void MediaStreamTrack::AddObserver(MediaStreamTrack::Observer* observer) {
+ observers_.insert(observer);
+}
+
} // 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 4c46daff82d..72e6d4fb0f4 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
@@ -54,6 +54,12 @@ class MODULES_EXPORT MediaStreamTrack
DEFINE_WRAPPERTYPEINFO();
public:
+ class MODULES_EXPORT Observer : public GarbageCollectedMixin {
+ public:
+ virtual ~Observer() = default;
+ virtual void TrackChangedState() = 0;
+ };
+
MediaStreamTrack(ExecutionContext*, MediaStreamComponent*);
MediaStreamTrack(ExecutionContext*,
MediaStreamComponent*,
@@ -64,37 +70,35 @@ class MODULES_EXPORT MediaStreamTrack
base::OnceClosure callback);
~MediaStreamTrack() override;
+ // MediaStreamTrack.idl
String kind() const;
String id() const;
String label() const;
-
bool enabled() const;
void setEnabled(bool);
-
bool muted() const;
-
String ContentHint() const;
void SetContentHint(const String&);
-
String readyState() const;
-
- void stopTrack(ExecutionContext*);
virtual MediaStreamTrack* clone(ScriptState*);
-
- // This function is called when constrains have been successfully applied.
- // Called from UserMediaRequest when it succeeds. It is not IDL-exposed.
- void SetConstraints(const MediaConstraints&);
-
+ void stopTrack(ExecutionContext*);
MediaTrackCapabilities* getCapabilities() const;
MediaTrackConstraints* getConstraints() const;
MediaTrackSettings* getSettings() const;
ScriptPromise applyConstraints(ScriptState*, const MediaTrackConstraints*);
+ // This function is called when constrains have been successfully applied.
+ // Called from UserMediaRequest when it succeeds. It is not IDL-exposed.
+ void SetConstraints(const MediaConstraints&);
+
DEFINE_ATTRIBUTE_EVENT_LISTENER(mute, kMute)
DEFINE_ATTRIBUTE_EVENT_LISTENER(unmute, kUnmute)
DEFINE_ATTRIBUTE_EVENT_LISTENER(ended, kEnded)
- MediaStreamComponent* Component() { return component_; }
+ // Returns the enum value of the ready state.
+ MediaStreamSource::ReadyState GetReadyState() { return ready_state_; }
+
+ MediaStreamComponent* Component() const { return component_; }
bool Ended() const;
void RegisterMediaStream(MediaStream*);
@@ -112,6 +116,8 @@ class MODULES_EXPORT MediaStreamTrack
ImageCapture* GetImageCapture() { return image_capture_; }
+ void AddObserver(Observer*);
+
void Trace(Visitor*) const override;
private:
@@ -129,6 +135,8 @@ class MODULES_EXPORT MediaStreamTrack
// Ensures that |feature_handle_for_scheduler_| is initialized.
void EnsureFeatureHandleForScheduler();
+ void setReadyState(MediaStreamSource::ReadyState ready_state);
+
// 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.
@@ -141,6 +149,7 @@ class MODULES_EXPORT MediaStreamTrack
Member<MediaStreamComponent> component_;
Member<ImageCapture> image_capture_;
WeakMember<ExecutionContext> execution_context_;
+ HeapHashSet<WeakMember<Observer>> observers_;
};
typedef HeapVector<Member<MediaStreamTrack>> MediaStreamTrackVector;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.cc
index 23c9793e749..edc08f9eb12 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.cc
@@ -5,47 +5,175 @@
#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
+#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_utils.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.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/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
+#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h"
#include "third_party/blink/renderer/platform/wtf/uuid.h"
namespace blink {
+namespace {
+
+const wtf_size_t kDefaultMaxSignalBufferSize = 20u;
+
+class NullUnderlyingSource : public UnderlyingSourceBase {
+ public:
+ explicit NullUnderlyingSource(ScriptState* script_state)
+ : UnderlyingSourceBase(script_state) {}
+};
+
+} // namespace
+
+MediaStreamTrackGenerator* MediaStreamTrackGenerator::Create(
+ ScriptState* script_state,
+ const String& kind,
+ ExceptionState& exception_state) {
+ if (!script_state->ContextIsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Invalid context");
+ return nullptr;
+ }
+
+ MediaStreamSource::StreamType type;
+ if (kind == "video") {
+ type = MediaStreamSource::kTypeVideo;
+ } else if (kind == "audio") {
+ type = MediaStreamSource::kTypeAudio;
+ } else {
+ exception_state.ThrowTypeError("Invalid track generator kind");
+ return nullptr;
+ }
+
+ return MakeGarbageCollected<MediaStreamTrackGenerator>(
+ script_state, type,
+ /*track_id=*/WTF::CreateCanonicalUUIDString(), nullptr,
+ kDefaultMaxSignalBufferSize);
+}
+
+MediaStreamTrackGenerator* MediaStreamTrackGenerator::Create(
+ ScriptState* script_state,
+ MediaStreamTrackGeneratorInit* init,
+ ExceptionState& exception_state) {
+ if (!script_state->ContextIsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Invalid context");
+ return nullptr;
+ }
+
+ if (!init->hasKind()) {
+ exception_state.ThrowTypeError("kind must be specified");
+ return nullptr;
+ }
+
+ if (init->hasSignalTarget() && init->signalTarget()->kind() != init->kind()) {
+ exception_state.ThrowTypeError("kind and signalTarget.kind() do not match");
+ return nullptr;
+ }
+
+ MediaStreamSource::StreamType type;
+ if (init->kind() == "video") {
+ type = MediaStreamSource::kTypeVideo;
+ } else if (init->kind() == "audio") {
+ type = MediaStreamSource::kTypeAudio;
+ } else {
+ exception_state.ThrowTypeError("Invalid track generator kind");
+ return nullptr;
+ }
+
+ wtf_size_t max_signal_buffer_size = kDefaultMaxSignalBufferSize;
+ if (init->hasMaxSignalBufferSize())
+ max_signal_buffer_size = init->maxSignalBufferSize();
+
+ return MakeGarbageCollected<MediaStreamTrackGenerator>(
+ script_state, type,
+ /*track_id=*/WTF::CreateCanonicalUUIDString(), init->signalTarget(),
+ max_signal_buffer_size);
+}
+
MediaStreamTrackGenerator::MediaStreamTrackGenerator(
ScriptState* script_state,
MediaStreamSource::StreamType type,
- const String& track_id)
+ const String& track_id,
+ MediaStreamTrack* signal_target,
+ wtf_size_t max_signal_buffer_size)
: MediaStreamTrack(
ExecutionContext::From(script_state),
MakeGarbageCollected<MediaStreamComponent>(
MakeGarbageCollected<MediaStreamSource>(track_id,
type,
track_id,
- /*remote=*/false))) {
- CreateOutputPlatformTrack();
+ /*remote=*/false))),
+ max_signal_buffer_size_(max_signal_buffer_size) {
+ if (type == MediaStreamSource::kTypeVideo) {
+ CreateVideoOutputPlatformTrack(signal_target);
+ } else {
+ DCHECK_EQ(type, MediaStreamSource::kTypeAudio);
+ CreateAudioOutputPlatformTrack();
+ }
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kMediaStreamTrackGenerator);
}
WritableStream* MediaStreamTrackGenerator::writable(ScriptState* script_state) {
- DCHECK_EQ(kind(), "video");
- if (!writable_)
+ if (writable_)
+ return writable_;
+
+ if (kind() == "video")
CreateVideoStream(script_state);
+ else if (kind() == "audio")
+ CreateAudioStream(script_state);
+
return writable_;
}
-void MediaStreamTrackGenerator::CreateOutputPlatformTrack() {
+ReadableStream* MediaStreamTrackGenerator::readableControl(
+ ScriptState* script_state) {
+ if (readable_control_)
+ return readable_control_;
+
+ if (kind() == "video")
+ CreateVideoControlStream(script_state);
+ else if (kind() == "audio")
+ CreateAudioControlStream(script_state);
+
+ return readable_control_;
+}
+
+PushableMediaStreamVideoSource* MediaStreamTrackGenerator::PushableVideoSource()
+ const {
+ DCHECK_EQ(Component()->Source()->GetType(), MediaStreamSource::kTypeVideo);
+ return static_cast<PushableMediaStreamVideoSource*>(
+ MediaStreamVideoSource::GetVideoSource(Component()->Source()));
+}
+
+void MediaStreamTrackGenerator::CreateVideoOutputPlatformTrack(
+ MediaStreamTrack* signal_target) {
+ base::WeakPtr<MediaStreamVideoSource> signal_target_upstream_source;
+ if (signal_target) {
+ MediaStreamVideoSource* upstream_source =
+ MediaStreamVideoSource::GetVideoSource(
+ signal_target->Component()->Source());
+ signal_target_upstream_source = upstream_source->GetWeakPtr();
+ }
+
std::unique_ptr<PushableMediaStreamVideoSource> platform_source =
- std::make_unique<PushableMediaStreamVideoSource>();
+ std::make_unique<PushableMediaStreamVideoSource>(
+ signal_target_upstream_source);
PushableMediaStreamVideoSource* platform_source_ptr = platform_source.get();
Component()->Source()->SetPlatformSource(std::move(platform_source));
std::unique_ptr<MediaStreamVideoTrack> platform_track =
@@ -56,6 +184,20 @@ void MediaStreamTrackGenerator::CreateOutputPlatformTrack() {
Component()->SetPlatformTrack(std::move(platform_track));
}
+void MediaStreamTrackGenerator::CreateAudioOutputPlatformTrack() {
+ // TODO(https:/crbug.com/1168281): use a different thread than the IO thread
+ // to deliver Audio.
+ std::unique_ptr<PushableMediaStreamAudioSource> platform_source =
+ std::make_unique<PushableMediaStreamAudioSource>(
+ GetExecutionContext()->GetTaskRunner(
+ TaskType::kInternalMediaRealTime),
+ Platform::Current()->GetIOTaskRunner());
+
+ platform_source->ConnectToTrack(Component());
+
+ Component()->Source()->SetPlatformSource(std::move(platform_source));
+}
+
void MediaStreamTrackGenerator::CreateVideoStream(ScriptState* script_state) {
DCHECK(!writable_);
PushableMediaStreamVideoSource* source =
@@ -67,31 +209,47 @@ void MediaStreamTrackGenerator::CreateVideoStream(ScriptState* script_state) {
script_state, video_underlying_sink_, /*high_water_mark=*/1);
}
-MediaStreamTrackGenerator* MediaStreamTrackGenerator::Create(
- ScriptState* script_state,
- const String& kind,
- ExceptionState& exception_state) {
- if (kind != "video") {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Only video tracks are supported");
- return nullptr;
- }
-
- if (!script_state->ContextIsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Invalid context");
+void MediaStreamTrackGenerator::CreateAudioStream(ScriptState* script_state) {
+ DCHECK(!writable_);
+ PushableMediaStreamAudioSource* source =
+ static_cast<PushableMediaStreamAudioSource*>(
+ Component()->Source()->GetPlatformSource());
+ audio_underlying_sink_ =
+ MakeGarbageCollected<MediaStreamAudioTrackUnderlyingSink>(source);
+ writable_ = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, audio_underlying_sink_, /*high_water_mark=*/1);
+}
- return nullptr;
- }
+void MediaStreamTrackGenerator::CreateVideoControlStream(
+ ScriptState* script_state) {
+ DCHECK(!readable_control_);
+ // TODO(crbug.com/1142955): Make the queue size configurable from the
+ // constructor.
+ control_underlying_source_ =
+ MakeGarbageCollected<VideoTrackSignalUnderlyingSource>(
+ script_state, this, max_signal_buffer_size_);
+ readable_control_ = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, control_underlying_source_, /*high_water_mark=*/0);
+}
- return MakeGarbageCollected<MediaStreamTrackGenerator>(
- script_state, MediaStreamSource::kTypeVideo,
- /*track_id=*/WTF::CreateCanonicalUUIDString());
+void MediaStreamTrackGenerator::CreateAudioControlStream(
+ ScriptState* script_state) {
+ DCHECK(!readable_control_);
+ // Since no signals have been defined for audio, use a null source that
+ // does nothing, so that a valid stream can be returned for audio
+ // MediaStreamTrackGenerators.
+ control_underlying_source_ =
+ MakeGarbageCollected<NullUnderlyingSource>(script_state);
+ readable_control_ = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, control_underlying_source_, /*high_water_mark=*/0);
}
void MediaStreamTrackGenerator::Trace(Visitor* visitor) const {
visitor->Trace(video_underlying_sink_);
+ visitor->Trace(audio_underlying_sink_);
visitor->Trace(writable_);
+ visitor->Trace(control_underlying_source_);
+ visitor->Trace(readable_control_);
MediaStreamTrack::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h
index ea9e3af85b6..290a6cf1f38 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h
@@ -11,8 +11,13 @@
namespace blink {
+class MediaStreamAudioTrackUnderlyingSink;
+class MediaStreamTrackGeneratorInit;
class MediaStreamVideoTrackUnderlyingSink;
+class PushableMediaStreamVideoSource;
+class ReadableStream;
class ScriptState;
+class UnderlyingSourceBase;
class WritableStream;
class MODULES_EXPORT MediaStreamTrackGenerator : public MediaStreamTrack {
@@ -22,23 +27,41 @@ class MODULES_EXPORT MediaStreamTrackGenerator : public MediaStreamTrack {
static MediaStreamTrackGenerator* Create(ScriptState*,
const String& kind,
ExceptionState&);
+ static MediaStreamTrackGenerator* Create(ScriptState*,
+ MediaStreamTrackGeneratorInit* init,
+ ExceptionState&);
MediaStreamTrackGenerator(ScriptState*,
MediaStreamSource::StreamType,
- const String& track_id);
+ const String& track_id,
+ MediaStreamTrack* signal_target,
+ wtf_size_t max_signal_buffer_size);
MediaStreamTrackGenerator(const MediaStreamTrackGenerator&) = delete;
MediaStreamTrackGenerator& operator=(const MediaStreamTrackGenerator&) =
delete;
WritableStream* writable(ScriptState* script_state);
+ ReadableStream* readableControl(ScriptState* script_state);
+
+ PushableMediaStreamVideoSource* PushableVideoSource() const;
void Trace(Visitor* visitor) const override;
private:
- void CreateOutputPlatformTrack();
+ void CreateAudioOutputPlatformTrack();
+ void CreateAudioStream(ScriptState* script_state);
+
+ void CreateVideoOutputPlatformTrack(MediaStreamTrack* signal_target);
void CreateVideoStream(ScriptState* script_state);
+ void CreateAudioControlStream(ScriptState* script_state);
+ void CreateVideoControlStream(ScriptState* script_state);
+
+ Member<MediaStreamAudioTrackUnderlyingSink> audio_underlying_sink_;
Member<MediaStreamVideoTrackUnderlyingSink> video_underlying_sink_;
Member<WritableStream> writable_;
+ Member<UnderlyingSourceBase> control_underlying_source_;
+ Member<ReadableStream> readable_control_;
+ const wtf_size_t max_signal_buffer_size_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl
index e66567d7aed..b2cd175e305 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator.idl
@@ -11,10 +11,12 @@
interface MediaStreamTrackGenerator : MediaStreamTrack {
[CallWith=ScriptState, RaisesException, MeasureAs=MediaStreamTrackGenerator]
constructor(DOMString kind);
+ [CallWith=ScriptState, RaisesException, MeasureAs=MediaStreamTrackGenerator]
+ constructor(MediaStreamTrackGeneratorInit init);
- // TODO(crbug.com/1142955): Add |readable| attribute giving control signals.
-
- // This streams takes VideoFrame objects.
- // TODO(crbug.com/1142955): Add support for audio.
+ // This streams takes VideoFrame or AudioFrame objects.
[CallWith=ScriptState] readonly attribute WritableStream writable;
+
+ // This stream returns MediaStreamTrackSignal objects.
+ [CallWith=ScriptState] readonly attribute ReadableStream readableControl;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.idl
new file mode 100644
index 00000000000..bd506749988
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/mediacapture-insertable-streams/#dictdef-mediastreamtrackgeneratorinit
+
+dictionary MediaStreamTrackGeneratorInit {
+ required DOMString kind;
+ MediaStreamTrack signalTarget;
+ [EnforceRange] unsigned short maxSignalBufferSize;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_test.cc
index c8291f7a391..d0f8be15961 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_generator_test.cc
@@ -11,16 +11,24 @@
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/stream_test_utils.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.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/testing/io_task_runner_testing_platform_support.h"
using testing::_;
@@ -32,13 +40,25 @@ namespace {
ScriptValue CreateVideoFrameChunk(ScriptState* script_state) {
const scoped_refptr<media::VideoFrame> media_frame =
media::VideoFrame::CreateBlackFrame(gfx::Size(10, 5));
- VideoFrame* video_frame =
- MakeGarbageCollected<VideoFrame>(std::move(media_frame));
+ VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
+ std::move(media_frame), ExecutionContext::From(script_state));
return ScriptValue(script_state->GetIsolate(),
ToV8(video_frame, script_state->GetContext()->Global(),
script_state->GetIsolate()));
}
+ScriptValue CreateAudioFrameChunk(ScriptState* script_state) {
+ AudioFrame* audio_frame =
+ MakeGarbageCollected<AudioFrame>(media::AudioBuffer::CreateEmptyBuffer(
+ media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
+ /*channel_count=*/2,
+ /*sample_rate=*/44100,
+ /*frame_count=*/500, base::TimeDelta()));
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(audio_frame, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
} // namespace
class MediaStreamTrackGeneratorTest : public testing::Test {
@@ -92,6 +112,73 @@ TEST_F(MediaStreamTrackGeneratorTest, VideoFramesAreWritten) {
EXPECT_TRUE(generator->Ended());
}
+TEST_F(MediaStreamTrackGeneratorTest, AudioFramesAreWritten) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ MediaStreamTrackGenerator* generator = MediaStreamTrackGenerator::Create(
+ script_state, "audio", v8_scope.GetExceptionState());
+
+ MockMediaStreamAudioSink media_stream_audio_sink;
+ WebMediaStreamAudioSink::AddToAudioTrack(
+ &media_stream_audio_sink, WebMediaStreamTrack(generator->Component()));
+
+ base::RunLoop sink_loop;
+ EXPECT_CALL(media_stream_audio_sink, OnData(_, _))
+ .WillOnce(testing::WithArg<0>([&](const media::AudioBus& data) {
+ EXPECT_NE(data.frames(), 0);
+ sink_loop.Quit();
+ }));
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ auto* writer = generator->writable(script_state)
+ ->getWriter(script_state, exception_state);
+ ScriptPromiseTester write_tester(
+ script_state,
+ writer->write(script_state, CreateAudioFrameChunk(script_state),
+ exception_state));
+ EXPECT_FALSE(write_tester.IsFulfilled());
+ write_tester.WaitUntilSettled();
+ sink_loop.Run();
+ EXPECT_TRUE(write_tester.IsFulfilled());
+ EXPECT_FALSE(exception_state.HadException());
+
+ // Closing the writable stream should stop the track.
+ writer->releaseLock(script_state);
+ EXPECT_FALSE(generator->Ended());
+ ScriptPromiseTester close_tester(
+ script_state,
+ generator->writable(script_state)->close(script_state, exception_state));
+ close_tester.WaitUntilSettled();
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_TRUE(generator->Ended());
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(
+ &media_stream_audio_sink, WebMediaStreamTrack(generator->Component()));
+}
+
+TEST_F(MediaStreamTrackGeneratorTest, SignalsAreRead) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ MediaStreamTrackGenerator* generator = MediaStreamTrackGenerator::Create(
+ script_state, "video", ASSERT_NO_EXCEPTION);
+
+ auto* video_source = generator->PushableVideoSource();
+ auto* video_track = MediaStreamVideoTrack::From(generator->Component());
+
+ auto* reader =
+ generator->readableControl(script_state)
+ ->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+ video_source->RequestRefreshFrame();
+ auto* signal = ReadObjectFromStream<MediaStreamTrackSignal>(v8_scope, reader);
+ EXPECT_EQ(signal->signalType(), "request-frame");
+
+ const double min_frame_rate = 3.5;
+ video_track->SetMinimumFrameRate(min_frame_rate);
+ signal = ReadObjectFromStream<MediaStreamTrackSignal>(v8_scope, reader);
+ EXPECT_EQ(signal->signalType(), "set-min-frame-rate");
+ EXPECT_TRUE(signal->hasFrameRate());
+ EXPECT_EQ(signal->frameRate(), min_frame_rate);
+}
+
TEST_F(MediaStreamTrackGeneratorTest, FramesDoNotFlowOnStoppedGenerator) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
@@ -216,16 +303,53 @@ TEST_F(MediaStreamTrackGeneratorTest, CloneStopSource) {
EXPECT_TRUE(clone->Ended());
}
-// TODO(crbug.com/1142955): Add support for audio.
-TEST_F(MediaStreamTrackGeneratorTest, Audio) {
+TEST_F(MediaStreamTrackGeneratorTest, SignalsFlowFromGeneratorToProcessor) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
- MediaStreamTrackGenerator* generator = MediaStreamTrackGenerator::Create(
- script_state, "audio", v8_scope.GetExceptionState());
- EXPECT_EQ(generator, nullptr);
- EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
- EXPECT_EQ(static_cast<DOMExceptionCode>(v8_scope.GetExceptionState().Code()),
- DOMExceptionCode::kNotSupportedError);
+ auto* generator = MediaStreamTrackGenerator::Create(script_state, "video",
+ ASSERT_NO_EXCEPTION);
+
+ // Create a processor connected to a mock source.
+ auto* mock_video_source = CreateMockVideoSource();
+ auto* processor = MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateVideoMediaStreamTrack(v8_scope.GetExecutionContext(),
+ mock_video_source),
+ ASSERT_NO_EXCEPTION);
+ mock_video_source->StartMockedSource();
+
+ // Connect the generator to the processor.
+ generator->readableControl(script_state)
+ ->pipeTo(script_state, processor->writableControl(script_state),
+ ASSERT_NO_EXCEPTION);
+
+ // Push a signal to the generator and verify that it makes it to the mock
+ // source backing the processor at the end of the chain.
+ base::RunLoop loop;
+ EXPECT_CALL(*mock_video_source, OnRequestRefreshFrame())
+ .WillOnce(base::test::RunOnceClosure(loop.QuitClosure()));
+ generator->PushableVideoSource()->RequestRefreshFrame();
+ loop.Run();
+}
+
+TEST_F(MediaStreamTrackGeneratorTest, ImplicitSignalsAreForwarded) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+
+ MockMediaStreamVideoSource* mock_source = CreateMockVideoSource();
+ MediaStreamTrack* signal_target =
+ CreateVideoMediaStreamTrack(v8_scope.GetExecutionContext(), mock_source);
+ mock_source->StartMockedSource();
+
+ auto* init = MediaStreamTrackGeneratorInit::Create();
+ init->setKind("video");
+ init->setSignalTarget(signal_target);
+ auto* generator = MediaStreamTrackGenerator::Create(script_state, init,
+ ASSERT_NO_EXCEPTION);
+ // Send a signal to the generator. It should be forwarded to the source of the
+ // |signal_target| track.
+ EXPECT_CALL(*mock_source, OnRequestRefreshFrame());
+ generator->PushableVideoSource()->RequestRefreshFrame();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
index 2b11a1fb4d5..928e89d4f47 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
@@ -7,9 +7,15 @@
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_utils.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h"
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.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/instrumentation/use_counter.h"
@@ -17,63 +23,226 @@
namespace blink {
+namespace {
+
+// Trivial sink for audio control signals.
+class NullUnderlyingSink : public UnderlyingSinkBase {
+ public:
+ // UnderlyingSinkBase overrides.
+ ScriptPromise start(ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+
+ ScriptPromise write(ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override {
+ exception_state.ThrowTypeError("Invalid audio signal");
+ return ScriptPromise();
+ }
+ ScriptPromise abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) override {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+ ScriptPromise close(ScriptState* script_state,
+ ExceptionState& exception_state) override {
+ return ScriptPromise::CastUndefined(script_state);
+ }
+};
+
+} // namespace
+
+// A MediaStreamTrack Observer which closes the provided
+// UnderlyingSource whenever the provided track is ended.
+class MediaStreamTrackProcessor::UnderlyingSourceCloser
+ : public GarbageCollected<UnderlyingSourceCloser>,
+ public MediaStreamTrack::Observer {
+ public:
+ UnderlyingSourceCloser(
+ MediaStreamTrack* track,
+ MediaStreamAudioTrackUnderlyingSource* audio_underlying_source)
+ : track_(track),
+ audio_underlying_source_(audio_underlying_source),
+ video_underlying_source_() {}
+ UnderlyingSourceCloser(
+ MediaStreamTrack* track,
+ MediaStreamVideoTrackUnderlyingSource* video_underlying_source)
+ : track_(track),
+ audio_underlying_source_(),
+ video_underlying_source_(video_underlying_source) {}
+
+ void TrackChangedState() override {
+ if (track_->GetReadyState() == MediaStreamSource::kReadyStateEnded) {
+ if (audio_underlying_source_ != nullptr) {
+ audio_underlying_source_->Close();
+ }
+ if (video_underlying_source_ != nullptr) {
+ video_underlying_source_->Close();
+ }
+ }
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(track_);
+ visitor->Trace(audio_underlying_source_);
+ visitor->Trace(video_underlying_source_);
+ }
+
+ private:
+ Member<MediaStreamTrack> track_;
+ Member<MediaStreamAudioTrackUnderlyingSource> audio_underlying_source_;
+ Member<MediaStreamVideoTrackUnderlyingSource> video_underlying_source_;
+};
+
MediaStreamTrackProcessor::MediaStreamTrackProcessor(
ScriptState* script_state,
- MediaStreamComponent* input_track)
- : input_track_(input_track) {
+ MediaStreamTrack* input_track,
+ uint16_t buffer_size)
+ : input_track_(input_track), buffer_size_(buffer_size) {
DCHECK(input_track_);
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kMediaStreamTrackProcessor);
}
ReadableStream* MediaStreamTrackProcessor::readable(ScriptState* script_state) {
- DCHECK_EQ(input_track_->Source()->GetType(), MediaStreamSource::kTypeVideo);
- if (!source_stream_)
+ if (source_stream_)
+ return source_stream_;
+
+ if (input_track_->Component()->Source()->GetType() ==
+ MediaStreamSource::kTypeVideo) {
CreateVideoSourceStream(script_state);
+ } else {
+ CreateAudioSourceStream(script_state);
+ }
+
return source_stream_;
}
+WritableStream* MediaStreamTrackProcessor::writableControl(
+ ScriptState* script_state) {
+ if (control_stream_)
+ return control_stream_;
+
+ if (input_track_->Component()->Source()->GetType() ==
+ MediaStreamSource::kTypeVideo) {
+ CreateVideoControlStream(script_state);
+ } else {
+ CreateAudioControlStream(script_state);
+ }
+ return control_stream_;
+}
+
void MediaStreamTrackProcessor::CreateVideoSourceStream(
ScriptState* script_state) {
DCHECK(!source_stream_);
video_underlying_source_ =
- MakeGarbageCollected<MediaStreamVideoTrackUnderlyingSource>(script_state,
- input_track_);
+ MakeGarbageCollected<MediaStreamVideoTrackUnderlyingSource>(
+ script_state, input_track_->Component(), buffer_size_);
+ source_stream_ = ReadableStream::CreateWithCountQueueingStrategy(
+ script_state, video_underlying_source_, /*high_water_mark=*/0,
+ video_underlying_source_->GetStreamTransferOptimizer());
+
+ source_closer_ = MakeGarbageCollected<UnderlyingSourceCloser>(
+ input_track_, video_underlying_source_);
+ input_track_->AddObserver(source_closer_);
+}
+
+void MediaStreamTrackProcessor::CreateAudioSourceStream(
+ ScriptState* script_state) {
+ DCHECK(!source_stream_);
+ audio_underlying_source_ =
+ MakeGarbageCollected<MediaStreamAudioTrackUnderlyingSource>(
+ script_state, input_track_->Component(), buffer_size_);
source_stream_ = ReadableStream::CreateWithCountQueueingStrategy(
- script_state, video_underlying_source_, /*high_water_mark=*/0);
+ script_state, audio_underlying_source_, /*high_water_mark=*/0);
+
+ source_closer_ = MakeGarbageCollected<UnderlyingSourceCloser>(
+ input_track_, audio_underlying_source_);
+ input_track_->AddObserver(source_closer_);
+}
+
+void MediaStreamTrackProcessor::CreateVideoControlStream(
+ ScriptState* script_state) {
+ DCHECK(!control_stream_);
+ signal_underlying_sink_ =
+ MakeGarbageCollected<VideoTrackSignalUnderlyingSink>(input_track_);
+ control_stream_ = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, signal_underlying_sink_, /*high_water_mark=*/1u);
+}
+
+void MediaStreamTrackProcessor::CreateAudioControlStream(
+ ScriptState* script_state) {
+ DCHECK(!control_stream_);
+ signal_underlying_sink_ = MakeGarbageCollected<NullUnderlyingSink>();
+ control_stream_ = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, signal_underlying_sink_, /*high_water_mark=*/1u);
}
MediaStreamTrackProcessor* MediaStreamTrackProcessor::Create(
ScriptState* script_state,
MediaStreamTrack* track,
+ uint16_t buffer_size,
ExceptionState& exception_state) {
if (!track) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "Input track cannot be null");
+ exception_state.ThrowTypeError("Input track cannot be null");
return nullptr;
}
- if (track->kind() != "video") {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Only video tracks are supported");
+ if (track->readyState() == "ended") {
+ exception_state.ThrowTypeError("Input track cannot be ended");
return nullptr;
}
if (!script_state->ContextIsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The context has been destroyed");
return nullptr;
}
- return MakeGarbageCollected<MediaStreamTrackProcessor>(script_state,
- track->Component());
+ return MakeGarbageCollected<MediaStreamTrackProcessor>(script_state, track,
+ buffer_size);
+}
+
+MediaStreamTrackProcessor* MediaStreamTrackProcessor::Create(
+ ScriptState* script_state,
+ MediaStreamTrack* track,
+ ExceptionState& exception_state) {
+ if (!track) {
+ exception_state.ThrowTypeError("Input track cannot be null");
+ return nullptr;
+ }
+ // Using 1 as default buffer size for video since by default we do not want
+ // to buffer, as buffering interferes with MediaStream sources that drop
+ // frames if they start to be buffered (e.g, camera sources).
+ // Using 10 as default for audio, which coincides with the buffer size for
+ // the Web Audio MediaStream sink.
+ uint16_t buffer_size = track->kind() == "video" ? 1u : 10u;
+ return Create(script_state, track, buffer_size, exception_state);
+}
+
+MediaStreamTrackProcessor* MediaStreamTrackProcessor::Create(
+ ScriptState* script_state,
+ MediaStreamTrackProcessorInit* init,
+ ExceptionState& exception_state) {
+ if (init->hasMaxBufferSize()) {
+ return Create(script_state, init->track(), init->maxBufferSize(),
+ exception_state);
+ }
+ return Create(script_state, init->track(), exception_state);
}
void MediaStreamTrackProcessor::Trace(Visitor* visitor) const {
visitor->Trace(input_track_);
+ visitor->Trace(audio_underlying_source_);
visitor->Trace(video_underlying_source_);
+ visitor->Trace(signal_underlying_sink_);
visitor->Trace(source_stream_);
+ visitor->Trace(control_stream_);
+ visitor->Trace(source_closer_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h
index 4a780b1cd56..92057f3df40 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h
@@ -5,43 +5,67 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_TRACK_PROCESSOR_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_TRACK_PROCESSOR_H_
-#include "third_party/blink/renderer/modules/mediastream/media_stream_track.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/impl/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
-class MediaStreamComponent;
+class ExceptionState;
class MediaStreamVideoTrackUnderlyingSource;
-class ScriptState;
+class MediaStreamAudioTrackUnderlyingSource;
+class MediaStreamTrack;
+class MediaStreamTrackProcessorInit;
class ReadableStream;
+class ScriptState;
+class UnderlyingSinkBase;
+class WritableStream;
class MODULES_EXPORT MediaStreamTrackProcessor : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
static MediaStreamTrackProcessor* Create(ScriptState*,
+ MediaStreamTrackProcessorInit*,
+ ExceptionState&);
+ static MediaStreamTrackProcessor* Create(ScriptState*,
MediaStreamTrack*,
+ uint16_t buffer_size,
ExceptionState&);
- MediaStreamTrackProcessor(ScriptState*, MediaStreamComponent*);
+ static MediaStreamTrackProcessor* Create(ScriptState*,
+ MediaStreamTrack*,
+ ExceptionState&);
+ MediaStreamTrackProcessor(ScriptState*,
+ MediaStreamTrack*,
+ uint16_t buffer_size);
MediaStreamTrackProcessor(const MediaStreamTrackProcessor&) = delete;
MediaStreamTrackProcessor& operator=(const MediaStreamTrackProcessor&) =
delete;
// MediaStreamTrackProcessor interface
ReadableStream* readable(ScriptState* script_state);
+ WritableStream* writableControl(ScriptState* script_state);
- MediaStreamComponent* input_track() { return input_track_; }
+ MediaStreamTrack* InputTrack() { return input_track_; }
void Trace(Visitor* visitor) const override;
private:
void CreateVideoSourceStream(ScriptState* script_state);
+ void CreateAudioSourceStream(ScriptState* script_state);
+ void CreateVideoControlStream(ScriptState* script_state);
+ void CreateAudioControlStream(ScriptState* script_state);
+
+ class UnderlyingSourceCloser;
- Member<MediaStreamComponent> input_track_;
+ Member<MediaStreamTrack> input_track_;
Member<MediaStreamVideoTrackUnderlyingSource> video_underlying_source_;
+ Member<MediaStreamAudioTrackUnderlyingSource> audio_underlying_source_;
+ Member<UnderlyingSinkBase> signal_underlying_sink_;
Member<ReadableStream> source_stream_;
+ Member<WritableStream> control_stream_;
+ Member<UnderlyingSourceCloser> source_closer_;
+ uint16_t buffer_size_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl
index bfe28abed2a..a9e7997dd3a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.idl
@@ -10,11 +10,13 @@
]
interface MediaStreamTrackProcessor {
[CallWith=ScriptState, RaisesException, MeasureAs=MediaStreamTrackProcessor]
- constructor(MediaStreamTrack track);
+ constructor(MediaStreamTrack track, optional unsigned short bufferSize);
+ [CallWith=ScriptState, RaisesException, MeasureAs=MediaStreamTrackProcessor]
+ constructor(MediaStreamTrackProcessorInit init);
- // This stream returns VideoFrame objects.
- // TODO(crbug.com/1142955): Add support for audio.
+ // This stream returns VideoFrame or AudioFrame objects.
[CallWith=ScriptState] readonly attribute ReadableStream readable;
- // TODO(crbug.com/1142955): Add |writable| attribute that takes control signals.
+ // This stream accepts MediaStreamTrackSignal objects
+ [CallWith=ScriptState] readonly attribute WritableStream writableControl;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.idl
new file mode 100644
index 00000000000..62c7da4454d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_init.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/mediacapture-insertable-streams/#dictdef-mediastreamtrackprocessorinit
+
+dictionary MediaStreamTrackProcessorInit {
+ required MediaStreamTrack track;
+ [EnforceRange] unsigned short maxBufferSize;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
index 69a54b631ac..94d83150b5d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
@@ -13,14 +13,22 @@
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/stream_test_utils.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
@@ -33,6 +41,13 @@ namespace blink {
namespace {
+std::unique_ptr<PushableMediaStreamAudioSource> CreatePushableAudioSource() {
+ // Use the IO thread for testing purposes.
+ return std::make_unique<PushableMediaStreamAudioSource>(
+ Thread::MainThread()->GetTaskRunner(),
+ Platform::Current()->GetIOTaskRunner());
+}
+
PushableMediaStreamVideoSource* CreatePushableVideoSource() {
PushableMediaStreamVideoSource* pushable_video_source =
new PushableMediaStreamVideoSource();
@@ -45,32 +60,51 @@ PushableMediaStreamVideoSource* CreatePushableVideoSource() {
return pushable_video_source;
}
-MediaStreamTrack* CreateVideoMediaStreamTrack(ExecutionContext* context,
- MediaStreamVideoSource* source) {
- return MakeGarbageCollected<MediaStreamTrack>(
- context, MediaStreamVideoTrack::CreateVideoTrack(
- source, MediaStreamVideoSource::ConstraintsOnceCallback(),
- /*enabled=*/true));
-}
+MediaStreamTrack* CreateAudioMediaStreamTrack(
+ ExecutionContext* context,
+ std::unique_ptr<MediaStreamAudioSource> source) {
+ auto* source_ptr = source.get();
-MediaStreamTrack* CreateAudioMediaStreamTrack(ExecutionContext* context) {
- std::unique_ptr<MediaStreamAudioSource> audio_source =
- std::make_unique<MediaStreamAudioSource>(
- blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
- /*is_local_source=*/false);
MediaStreamSource* media_stream_source =
MakeGarbageCollected<MediaStreamSource>(
"source_id", MediaStreamSource::kTypeAudio, "source_name",
- /*is_remote=*/false);
- media_stream_source->SetPlatformSource(std::move(audio_source));
- std::unique_ptr<MediaStreamAudioTrack> audio_track =
- std::make_unique<MediaStreamAudioTrack>(/*is_local_track=*/false);
+ /*remote=*/false);
+ media_stream_source->SetPlatformSource(std::move(source));
+
MediaStreamComponent* component =
MakeGarbageCollected<MediaStreamComponent>(media_stream_source);
- component->SetPlatformTrack(std::move(audio_track));
+
+ source_ptr->ConnectToTrack(component);
+
return MakeGarbageCollected<MediaStreamTrack>(context, component);
}
+ScriptValue CreateRequestFrameChunk(ScriptState* script_state) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("request-frame");
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
+ScriptValue CreateSetMinFrameRateChunk(ScriptState* script_state,
+ double frame_rate) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ signal->setFrameRate(frame_rate);
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
+ScriptValue CreateInvalidSignalChunk(ScriptState* script_state) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
} // namespace
class MediaStreamTrackProcessorTest : public testing::Test {
@@ -97,12 +131,13 @@ TEST_F(MediaStreamTrackProcessorTest, VideoFramesAreExposed) {
pushable_video_source),
exception_state);
EXPECT_FALSE(exception_state.HadException());
- EXPECT_EQ(track_processor->input_track()->Source()->GetPlatformSource(),
- pushable_video_source);
+ EXPECT_EQ(
+ track_processor->InputTrack()->Component()->Source()->GetPlatformSource(),
+ pushable_video_source);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
- WebMediaStreamTrack(track_processor->input_track()));
+ WebMediaStreamTrack(track_processor->InputTrack()->Component()));
EXPECT_EQ(mock_video_sink.number_of_frames(), 0);
EXPECT_EQ(mock_video_sink.last_frame(), nullptr);
@@ -131,6 +166,127 @@ TEST_F(MediaStreamTrackProcessorTest, VideoFramesAreExposed) {
EXPECT_EQ(mock_video_sink.last_frame(), frame);
}
+TEST_F(MediaStreamTrackProcessorTest, AudioFramesAreExposed) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ auto* pushable_source_ptr = pushable_audio_source.get();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext(),
+ std::move(pushable_audio_source)),
+ exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+ MediaStreamComponent* component = track_processor->InputTrack()->Component();
+ EXPECT_EQ(component->Source()->GetPlatformSource(), pushable_source_ptr);
+
+ MockMediaStreamAudioSink mock_audio_sink;
+ WebMediaStreamAudioSink::AddToAudioTrack(&mock_audio_sink,
+ WebMediaStreamTrack(component));
+
+ auto* reader =
+ track_processor->readable(script_state)
+ ->GetDefaultReaderForTesting(script_state, exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+
+ // Deliver a frame.
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_audio_sink, OnData(_, _))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ pushable_source_ptr->PushAudioData(AudioFrameSerializationData::Wrap(
+ media::AudioBus::Create(/*channels=*/2, /*frames=*/100),
+ /*sample_rate=*/8000, base::TimeDelta::FromSeconds(1)));
+
+ ScriptPromiseTester read_tester(script_state,
+ reader->read(script_state, exception_state));
+ EXPECT_FALSE(read_tester.IsFulfilled());
+ read_tester.WaitUntilSettled();
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_TRUE(read_tester.IsFulfilled());
+ EXPECT_TRUE(read_tester.Value().IsObject());
+ sink_loop.Run();
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(&mock_audio_sink,
+ WebMediaStreamTrack(component));
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoControlSignalsAreForwarded) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MockMediaStreamVideoSource* mock_video_source = CreateMockVideoSource();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateVideoMediaStreamTrack(v8_scope.GetExecutionContext(),
+ mock_video_source),
+ exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_EQ(
+ track_processor->InputTrack()->Component()->Source()->GetPlatformSource(),
+ mock_video_source);
+ mock_video_source->StartMockedSource();
+
+ EXPECT_CALL(*mock_video_source, OnRequestRefreshFrame());
+ auto* writer = track_processor->writableControl(script_state)
+ ->getWriter(script_state, exception_state);
+ ScriptPromiseTester request_frame_tester(
+ script_state,
+ writer->write(script_state, CreateRequestFrameChunk(script_state),
+ exception_state));
+ request_frame_tester.WaitUntilSettled();
+ EXPECT_TRUE(request_frame_tester.IsFulfilled());
+ EXPECT_FALSE(exception_state.HadException());
+
+ MediaStreamVideoTrack* platform_track =
+ MediaStreamVideoTrack::From(track_processor->InputTrack()->Component());
+ EXPECT_FALSE(platform_track->min_frame_rate().has_value());
+ const double min_frame_rate = 15.0;
+ ScriptPromiseTester set_min_frame_rate_tester(
+ script_state,
+ writer->write(script_state,
+ CreateSetMinFrameRateChunk(script_state, min_frame_rate),
+ exception_state));
+ set_min_frame_rate_tester.WaitUntilSettled();
+ EXPECT_TRUE(set_min_frame_rate_tester.IsFulfilled());
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_TRUE(platform_track->min_frame_rate().has_value());
+ EXPECT_EQ(platform_track->min_frame_rate().value(), min_frame_rate);
+
+ ScriptPromiseTester invalid_signal_tester(
+ script_state,
+ writer->write(script_state, CreateInvalidSignalChunk(script_state),
+ exception_state));
+ invalid_signal_tester.WaitUntilSettled();
+ EXPECT_TRUE(invalid_signal_tester.IsRejected());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioControlSignalsAreRejected) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext(),
+ std::make_unique<MediaStreamAudioSource>(
+ Thread::MainThread()->GetTaskRunner(),
+ /*is_local=*/true)),
+ exception_state);
+
+ auto* writer = track_processor->writableControl(script_state)
+ ->getWriter(script_state, exception_state);
+ ScriptPromiseTester tester(
+ script_state,
+ writer->write(script_state, CreateRequestFrameChunk(script_state),
+ exception_state));
+ tester.WaitUntilSettled();
+ EXPECT_TRUE(tester.IsRejected());
+}
+
TEST_F(MediaStreamTrackProcessorTest, CanceledReadableDisconnects) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
@@ -146,12 +302,12 @@ TEST_F(MediaStreamTrackProcessorTest, CanceledReadableDisconnects) {
// Initially the track has no sinks.
MediaStreamVideoTrack* video_track =
- MediaStreamVideoTrack::From(track_processor->input_track());
+ MediaStreamVideoTrack::From(track_processor->InputTrack()->Component());
EXPECT_EQ(video_track->CountSinks(), 0u);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
- WebMediaStreamTrack(track_processor->input_track()));
+ WebMediaStreamTrack(track_processor->InputTrack()->Component()));
EXPECT_EQ(mock_video_sink.number_of_frames(), 0);
EXPECT_EQ(mock_video_sink.last_frame(), nullptr);
EXPECT_EQ(video_track->CountSinks(), 1u);
@@ -196,9 +352,10 @@ TEST_F(MediaStreamTrackProcessorTest, ProcessorConnectsToGenerator) {
exception_state);
// Create generator and connect it to a mock sink.
+ MediaStreamTrackGeneratorInit* init = MediaStreamTrackGeneratorInit::Create();
+ init->setKind("video");
MediaStreamTrackGenerator* track_generator =
- MakeGarbageCollected<MediaStreamTrackGenerator>(
- script_state, MediaStreamSource::kTypeVideo, "track_id");
+ MediaStreamTrackGenerator::Create(script_state, init, exception_state);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
WebMediaStreamTrack(track_generator->Component()));
@@ -228,30 +385,108 @@ TEST_F(MediaStreamTrackProcessorTest, NullInputTrack) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MediaStreamTrack* track = nullptr;
MediaStreamTrackProcessor* track_processor =
- MediaStreamTrackProcessor::Create(script_state, nullptr, exception_state);
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
EXPECT_EQ(track_processor, nullptr);
EXPECT_TRUE(exception_state.HadException());
- EXPECT_EQ(static_cast<DOMExceptionCode>(v8_scope.GetExceptionState().Code()),
- DOMExceptionCode::kOperationError);
+ EXPECT_EQ(static_cast<ESErrorType>(v8_scope.GetExceptionState().Code()),
+ ESErrorType::kTypeError);
}
-// TODO(crbug.com/1142955): Add support for audio.
-TEST_F(MediaStreamTrackProcessorTest, Audio) {
+TEST_F(MediaStreamTrackProcessorTest, EndedTrack) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
ExceptionState& exception_state = v8_scope.GetExceptionState();
- MediaStreamTrack* media_stream_track =
- CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext());
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+ track->stopTrack(v8_scope.GetExecutionContext());
MediaStreamTrackProcessor* track_processor =
- MediaStreamTrackProcessor::Create(script_state, media_stream_track,
- exception_state);
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
EXPECT_EQ(track_processor, nullptr);
EXPECT_TRUE(exception_state.HadException());
- EXPECT_EQ(static_cast<DOMExceptionCode>(v8_scope.GetExceptionState().Code()),
- DOMExceptionCode::kNotSupportedError);
+ EXPECT_EQ(static_cast<ESErrorType>(v8_scope.GetExceptionState().Code()),
+ ESErrorType::kTypeError);
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoCloseOnTrackEnd) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+
+ EXPECT_TRUE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoNoCloseOnTrackDisable) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->setEnabled(false);
+
+ EXPECT_FALSE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioCloseOnTrackEnd) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ MediaStreamTrack* track = CreateAudioMediaStreamTrack(
+ v8_scope.GetExecutionContext(), std::move(pushable_audio_source));
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+
+ EXPECT_TRUE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioNoCloseOnTrackDisable) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ MediaStreamTrack* track = CreateAudioMediaStreamTrack(
+ v8_scope.GetExecutionContext(), std::move(pushable_audio_source));
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->setEnabled(false);
+
+ EXPECT_FALSE(readable->IsClosed());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_signal.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_signal.idl
new file mode 100644
index 00000000000..905c908b840
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_signal.idl
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/mediacapture-insertable-streams/#dictdef-mediastreamtracksignal
+
+enum MediaStreamTrackSignalType {
+ "request-frame",
+ "set-min-frame-rate"
+};
+
+dictionary MediaStreamTrackSignal {
+ required MediaStreamTrackSignalType signalType;
+ double frameRate;
+};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_test.cc
new file mode 100644
index 00000000000..43b5c48c942
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_test.cc
@@ -0,0 +1,75 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_processor.h"
+
+#include <iostream>
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "media/base/video_frame.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/public/web/modules/mediastream/media_stream_video_source.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+
+using testing::_;
+
+namespace blink {
+
+namespace {
+
+class TestObserver : public GarbageCollected<TestObserver>,
+ public MediaStreamTrack::Observer {
+ public:
+ void TrackChangedState() override { observation_count_++; }
+ int ObservationCount() const { return observation_count_; }
+
+ private:
+ int observation_count_ = 0;
+};
+
+} // namespace
+
+class MediaStreamTrackTest : public testing::Test {
+ public:
+ ~MediaStreamTrackTest() override { WebHeap::CollectAllGarbageForTesting(); }
+};
+
+TEST_F(MediaStreamTrackTest, StopTrackTriggersObservers) {
+ V8TestingScope v8_scope;
+
+ MediaStreamSource* source = MakeGarbageCollected<MediaStreamSource>(
+ "id", MediaStreamSource::StreamType::kTypeVideo, "name",
+ false /* remote */);
+ MediaStreamComponent* component =
+ MakeGarbageCollected<MediaStreamComponent>(source);
+ MediaStreamTrack* track = MakeGarbageCollected<MediaStreamTrack>(
+ v8_scope.GetExecutionContext(), component);
+
+ TestObserver* testObserver = MakeGarbageCollected<TestObserver>();
+ track->AddObserver(testObserver);
+
+ source->SetReadyState(MediaStreamSource::kReadyStateMuted);
+ EXPECT_EQ(testObserver->ObservationCount(), 1);
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+ EXPECT_EQ(testObserver->ObservationCount(), 2);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
index 760bd2bda54..5f1faf25381 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
@@ -165,6 +165,11 @@ void MediaStreamVideoCapturerSource::ChangeSourceImpl(
WTF::Unretained(this), capture_params_));
}
+base::WeakPtr<MediaStreamVideoSource>
+MediaStreamVideoCapturerSource::GetWeakPtr() const {
+ return weak_factory_.GetWeakPtr();
+}
+
void MediaStreamVideoCapturerSource::OnRunStateChanged(
const media::VideoCaptureParams& new_capture_params,
bool is_running) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
index cdc70662023..47c46dd4222 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
@@ -81,6 +81,7 @@ class MODULES_EXPORT MediaStreamVideoCapturerSource
base::Optional<media::VideoCaptureParams> GetCurrentCaptureParams()
const override;
void ChangeSourceImpl(const MediaStreamDevice& new_device) override;
+ base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
// Method to bind as RunningCallback in VideoCapturerSource::StartCapture().
void OnRunStateChanged(const media::VideoCaptureParams& new_capture_params,
@@ -108,6 +109,8 @@ class MODULES_EXPORT MediaStreamVideoCapturerSource
VideoCaptureDeliverFrameCB frame_callback_;
DeviceCapturerFactoryCallback device_capturer_factory_callback_;
+ base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoCapturerSource);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
index a09e888df9a..8e3a7b574c3 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
@@ -89,9 +89,10 @@ class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
void DisconnectFromTrack() { MediaStreamVideoSink::DisconnectFromTrack(); }
void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks capture_time) {
*capture_time_ = capture_time;
- *metadata_ = *frame->metadata();
+ *metadata_ = frame->metadata();
std::move(got_frame_cb_).Run();
}
@@ -248,10 +249,12 @@ TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTimeAndMetadataPlumbing) {
fake_sink.ConnectToTrack(track);
const scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2));
- frame->metadata()->frame_rate = 30.0;
+ frame->metadata().frame_rate = 30.0;
PostCrossThreadTask(
*Platform::Current()->GetIOTaskRunner(), FROM_HERE,
- CrossThreadBindOnce(deliver_frame_cb, frame, reference_capture_time));
+ CrossThreadBindOnce(deliver_frame_cb, frame,
+ std::vector<scoped_refptr<media::VideoFrame>>(),
+ reference_capture_time));
run_loop.Run();
fake_sink.DisconnectFromTrack();
EXPECT_EQ(reference_capture_time, capture_time);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
index 8a9f2155257..315f8f16929 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.cc
@@ -47,6 +47,7 @@ class MediaStreamVideoRendererSink::FrameDeliverer {
}
void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks /*current_time*/) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
DCHECK(frame);
@@ -70,6 +71,7 @@ class MediaStreamVideoRendererSink::FrameDeliverer {
}
frame_size_ = frame->natural_size();
+ // Scaled frames are currently ignored.
repaint_cb_.Run(std::move(frame));
}
@@ -87,9 +89,9 @@ class MediaStreamVideoRendererSink::FrameDeliverer {
if (!video_frame)
return;
- video_frame->metadata()->end_of_stream = true;
- video_frame->metadata()->reference_time = base::TimeTicks::Now();
- OnVideoFrame(video_frame, base::TimeTicks());
+ video_frame->metadata().end_of_stream = true;
+ video_frame->metadata().reference_time = base::TimeTicks::Now();
+ OnVideoFrame(video_frame, {}, base::TimeTicks());
}
void Start() {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
index 3f2be7b45fe..b45a5c5538a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
@@ -43,10 +43,7 @@ MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource(
return static_cast<MediaStreamVideoSource*>(source->GetPlatformSource());
}
-MediaStreamVideoSource::MediaStreamVideoSource() : state_(NEW) {
- track_adapter_ = base::MakeRefCounted<VideoTrackAdapter>(
- Platform::Current()->GetIOTaskRunner(), GetWeakPtr());
-}
+MediaStreamVideoSource::MediaStreamVideoSource() : state_(NEW) {}
MediaStreamVideoSource::~MediaStreamVideoSource() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -79,10 +76,10 @@ void MediaStreamVideoSource::AddTrack(
state_ = STARTING;
StartSourceImpl(
ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
- &VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)),
+ &VideoTrackAdapter::DeliverFrameOnIO, GetTrackAdapter())),
ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
&VideoTrackAdapter::DeliverEncodedVideoFrameOnIO,
- track_adapter_)));
+ GetTrackAdapter())));
break;
}
case STARTING:
@@ -127,7 +124,7 @@ void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track,
// Call |frame_adapter_->RemoveTrack| here even if adding the track has
// failed and |frame_adapter_->AddCallback| has not been called.
- track_adapter_->RemoveTrack(video_track);
+ GetTrackAdapter()->RemoveTrack(video_track);
if (tracks_.empty()) {
if (callback) {
@@ -145,8 +142,8 @@ void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track,
// sources created after that StopSource() call, but before the actual
// stop takes place. See https://crbug.com/778039.
remove_last_track_callback_ = std::move(callback);
- StopForRestart(WTF::Bind(&MediaStreamVideoSource::DidStopSource,
- weak_factory_.GetWeakPtr()));
+ StopForRestart(
+ WTF::Bind(&MediaStreamVideoSource::DidStopSource, GetWeakPtr()));
if (state_ == STOPPING_FOR_RESTART || state_ == STOPPED_FOR_RESTART) {
// If the source supports restarting, it is necessary to call
// FinalizeStopSource() to ensure the same behavior as StopSource(),
@@ -191,7 +188,7 @@ void MediaStreamVideoSource::DidStopSource(RestartResult result) {
void MediaStreamVideoSource::ReconfigureTrack(
MediaStreamVideoTrack* track,
const VideoTrackAdapterSettings& adapter_settings) {
- track_adapter_->ReconfigureTrack(track, adapter_settings);
+ GetTrackAdapter()->ReconfigureTrack(track, adapter_settings);
// It's OK to reconfigure settings even if ReconfigureTrack fails, provided
// |track| is not connected to a different source, which is a precondition
// for calling this method.
@@ -209,13 +206,13 @@ void MediaStreamVideoSource::StopForRestart(RestartCallback callback,
}
DCHECK(!restart_callback_);
- track_adapter_->StopFrameMonitoring();
+ GetTrackAdapter()->StopFrameMonitoring();
state_ = STOPPING_FOR_RESTART;
restart_callback_ = std::move(callback);
if (send_black_frame) {
const base::Optional<gfx::Size> source_size =
- track_adapter_->source_frame_size();
+ GetTrackAdapter()->source_frame_size();
scoped_refptr<media::VideoFrame> black_frame =
media::VideoFrame::CreateBlackFrame(
source_size.has_value() ? *source_size
@@ -223,7 +220,8 @@ void MediaStreamVideoSource::StopForRestart(RestartCallback callback,
PostCrossThreadTask(
*io_task_runner(), FROM_HERE,
CrossThreadBindOnce(&VideoTrackAdapter::DeliverFrameOnIO,
- track_adapter_, black_frame,
+ GetTrackAdapter(), black_frame,
+ std::vector<scoped_refptr<media::VideoFrame>>(),
base::TimeTicks::Now()));
}
@@ -336,7 +334,7 @@ void MediaStreamVideoSource::SetDeviceRotationDetection(bool enabled) {
base::SingleThreadTaskRunner* MediaStreamVideoSource::io_task_runner() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return track_adapter_->io_task_runner();
+ return Platform::Current()->GetIOTaskRunner().get();
}
base::Optional<media::VideoCaptureFormat>
@@ -388,7 +386,7 @@ void MediaStreamVideoSource::DoStopSource() {
DVLOG(3) << "DoStopSource()";
if (state_ == ENDED)
return;
- track_adapter_->StopFrameMonitoring();
+ GetTrackAdapter()->StopFrameMonitoring();
StopSourceImpl();
state_ = ENDED;
SetReadyState(WebMediaStreamSource::kReadyStateEnded);
@@ -432,7 +430,7 @@ void MediaStreamVideoSource::FinalizeAddPendingTracks() {
}
if (result == mojom::blink::MediaStreamRequestResult::OK) {
- track_adapter_->AddTrack(
+ GetTrackAdapter()->AddTrack(
track_info.track, track_info.frame_callback,
track_info.encoded_frame_callback, track_info.settings_callback,
track_info.format_callback, *track_info.adapter_settings);
@@ -457,11 +455,11 @@ void MediaStreamVideoSource::StartFrameMonitoring() {
base::Optional<media::VideoCaptureFormat> current_format = GetCurrentFormat();
double frame_rate = current_format ? current_format->frame_rate : 0.0;
if (current_format && enable_device_rotation_detection_) {
- track_adapter_->SetSourceFrameSize(current_format->frame_size);
+ GetTrackAdapter()->SetSourceFrameSize(current_format->frame_size);
}
- track_adapter_->StartFrameMonitoring(
- frame_rate, WTF::BindRepeating(&MediaStreamVideoSource::SetMutedState,
- weak_factory_.GetWeakPtr()));
+ GetTrackAdapter()->StartFrameMonitoring(
+ frame_rate,
+ WTF::BindRepeating(&MediaStreamVideoSource::SetMutedState, GetWeakPtr()));
}
void MediaStreamVideoSource::SetReadyState(
@@ -513,6 +511,15 @@ VideoCaptureFeedbackCB MediaStreamVideoSource::GetFeedbackCallback() const {
return base::DoNothing();
}
+scoped_refptr<VideoTrackAdapter> MediaStreamVideoSource::GetTrackAdapter() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!track_adapter_) {
+ track_adapter_ =
+ base::MakeRefCounted<VideoTrackAdapter>(io_task_runner(), GetWeakPtr());
+ }
+ return track_adapter_;
+}
+
MediaStreamVideoSource::PendingTrackInfo::PendingTrackInfo(
MediaStreamVideoTrack* track,
const VideoCaptureDeliverFrameCB& frame_callback,
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 8dc00f69705..f21c2d4a194 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
@@ -18,6 +18,7 @@
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
@@ -32,9 +33,10 @@ constexpr base::TimeDelta kLowerBoundRefreshInterval =
base::TimeDelta::FromHz(media::limits::kMaxFramesPerSecond);
// This alias mimics the definition of VideoCaptureDeliverFrameCB.
-using VideoCaptureDeliverFrameInternalCallback =
- WTF::CrossThreadFunction<void(scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks estimated_capture_time)>;
+using VideoCaptureDeliverFrameInternalCallback = WTF::CrossThreadFunction<void(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time)>;
// Mimics blink::EncodedVideoFrameCB
using EncodedVideoFrameInternalCallback =
@@ -107,8 +109,10 @@ class MediaStreamVideoTrack::FrameDeliverer
// Triggers all registered callbacks with |frame| and |estimated_capture_time|
// as parameters. Must be called on the IO-thread.
- void DeliverFrameOnIO(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time);
+ void DeliverFrameOnIO(
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time);
// Triggers all encoded callbacks with |frame| and |estimated_capture_time|.
// Must be called on the IO-thread.
@@ -195,10 +199,9 @@ void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
PostCrossThreadTask(
*io_task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &FrameDeliverer::AddCallbackOnIO, WrapRefCounted(this),
- WTF::CrossThreadUnretained(id),
- WTF::Passed(CrossThreadBindRepeating(std::move(callback)))));
+ CrossThreadBindOnce(&FrameDeliverer::AddCallbackOnIO,
+ WrapRefCounted(this), WTF::CrossThreadUnretained(id),
+ CrossThreadBindRepeating(std::move(callback))));
}
void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
@@ -214,10 +217,9 @@ void MediaStreamVideoTrack::FrameDeliverer::AddEncodedCallback(
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
PostCrossThreadTask(
*io_task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &FrameDeliverer::AddEncodedCallbackOnIO, WrapRefCounted(this),
- WTF::CrossThreadUnretained(id),
- WTF::Passed(CrossThreadBindRepeating(std::move(callback)))));
+ CrossThreadBindOnce(&FrameDeliverer::AddEncodedCallbackOnIO,
+ WrapRefCounted(this), WTF::CrossThreadUnretained(id),
+ CrossThreadBindRepeating(std::move(callback))));
}
void MediaStreamVideoTrack::FrameDeliverer::AddEncodedCallbackOnIO(
@@ -323,6 +325,7 @@ void MediaStreamVideoTrack::FrameDeliverer::SetIsRefreshingForMinFrameRateOnIO(
void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
base::TimeTicks estimated_capture_time) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!enabled_ && main_render_task_runner_ && emit_frame_drop_events_) {
@@ -338,9 +341,17 @@ void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
media::VideoCaptureFrameDropReason::
kVideoTrackFrameDelivererNotEnabledReplacingWithBlackFrame));
}
- auto video_frame = enabled_ ? std::move(frame) : GetBlackFrame(*frame);
+ scoped_refptr<media::VideoFrame> video_frame;
+ if (enabled_) {
+ video_frame = std::move(frame);
+ } else {
+ // When disabled, a black video frame is passed along instead. The original
+ // frames are dropped.
+ video_frame = GetBlackFrame(*frame);
+ scaled_video_frames.clear();
+ }
for (const auto& entry : callbacks_)
- entry.second.Run(video_frame, estimated_capture_time);
+ entry.second.Run(video_frame, scaled_video_frames, estimated_capture_time);
// The delay on refresh timer is reset each time a frame is received so that
// it will not fire for at least an additional period. This means refresh
@@ -391,8 +402,8 @@ MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
return nullptr;
wrapped_black_frame->set_timestamp(reference_frame.timestamp());
- wrapped_black_frame->metadata()->reference_time =
- reference_frame.metadata()->reference_time;
+ wrapped_black_frame->metadata().reference_time =
+ reference_frame.metadata().reference_time;
return wrapped_black_frame;
}
@@ -672,7 +683,8 @@ void MediaStreamVideoTrack::GetSettings(
settings.frame_rate = *computed_frame_rate_;
}
- settings.facing_mode = ToPlatformFacingMode(source_->device().video_facing);
+ settings.facing_mode = ToPlatformFacingMode(
+ static_cast<mojom::blink::FacingMode>(source_->device().video_facing));
settings.resize_mode = WebString::FromASCII(std::string(
adapter_settings().target_size() ? WebMediaStreamTrack::kResizeModeRescale
: WebMediaStreamTrack::kResizeModeNone));
@@ -721,6 +733,19 @@ void MediaStreamVideoTrack::OnFrameDropped(
void MediaStreamVideoTrack::SetMinimumFrameRate(double min_frame_rate) {
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
min_frame_rate_ = min_frame_rate;
+ if (signal_observer_)
+ signal_observer_->SetMinimumFrameRate(min_frame_rate);
+}
+
+MediaStreamVideoTrackSignalObserver* MediaStreamVideoTrack::SignalObserver() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+ return signal_observer_.Get();
+}
+
+void MediaStreamVideoTrack::SetSignalObserver(
+ MediaStreamVideoTrackSignalObserver* observer) {
+ DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+ signal_observer_ = observer;
}
void MediaStreamVideoTrack::StartTimerForRequestingFrames() {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
index d9ba4214778..e5fa70e8132 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
@@ -23,6 +23,7 @@
namespace blink {
+class MediaStreamVideoTrackSignalObserver;
class VideoTrackAdapterSettings;
// MediaStreamVideoTrack is a video-specific representation of a
@@ -160,6 +161,9 @@ class MODULES_EXPORT MediaStreamVideoTrack : public MediaStreamTrackPlatform {
void OnFrameDropped(media::VideoCaptureFrameDropReason reason);
+ MediaStreamVideoTrackSignalObserver* SignalObserver();
+ void SetSignalObserver(MediaStreamVideoTrackSignalObserver* observer);
+
bool IsRefreshFrameTimerRunningForTesting() {
return refresh_timer_.IsRunning();
}
@@ -219,6 +223,8 @@ class MODULES_EXPORT MediaStreamVideoTrack : public MediaStreamTrackPlatform {
media::VideoCaptureFormat computed_source_format_;
base::RepeatingTimer refresh_timer_;
+ WeakPersistent<MediaStreamVideoTrackSignalObserver> signal_observer_;
+
base::WeakPtrFactory<MediaStreamVideoTrack> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoTrack);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h
new file mode 100644
index 00000000000..701bb957d96
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_TRACK_SIGNAL_OBSERVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_TRACK_SIGNAL_OBSERVER_H_
+
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+
+namespace blink {
+
+class MediaStreamVideoTrackSignalObserver : public GarbageCollectedMixin {
+ public:
+ virtual ~MediaStreamVideoTrackSignalObserver() = default;
+ virtual void SetMinimumFrameRate(double) = 0;
+ virtual void RequestFrame() = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_TRACK_SIGNAL_OBSERVER_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_test.cc
index a9ea4202a83..a7ea3f5b2cb 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_test.cc
@@ -209,9 +209,11 @@ class CheckThreadHelper {
THREAD_CHECKER(thread_checker_);
};
-void CheckThreadVideoFrameReceiver(CheckThreadHelper* helper,
- scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time) {
+void CheckThreadVideoFrameReceiver(
+ CheckThreadHelper* helper,
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time) {
// Do nothing.
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
index 44cf977b237..bf6f630b1f5 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
@@ -12,7 +12,7 @@ namespace blink {
MediaStreamVideoTrackUnderlyingSink::MediaStreamVideoTrackUnderlyingSink(
PushableMediaStreamVideoSource* source)
- : source_(source) {}
+ : source_(source->GetWeakPtr()) {}
ScriptPromise MediaStreamVideoTrackUnderlyingSink::start(
ScriptState* script_state,
@@ -29,18 +29,29 @@ ScriptPromise MediaStreamVideoTrackUnderlyingSink::write(
VideoFrame* video_frame = V8VideoFrame::ToImplWithTypeCheck(
script_state->GetIsolate(), chunk.V8Value());
if (!video_frame) {
- exception_state.ThrowTypeError("Invalid video frame.");
+ exception_state.ThrowTypeError("Null video frame.");
return ScriptPromise();
}
- if (!source_->running()) {
+ if (!video_frame->frame()) {
+ exception_state.ThrowTypeError("Empty video frame.");
+ return ScriptPromise();
+ }
+
+ PushableMediaStreamVideoSource* pushable_source =
+ static_cast<PushableMediaStreamVideoSource*>(source_.get());
+ if (!pushable_source || !pushable_source->running()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Stream closed");
return ScriptPromise();
}
base::TimeTicks estimated_capture_time = base::TimeTicks::Now();
- source_->PushFrame(video_frame->frame(), estimated_capture_time);
+ pushable_source->PushFrame(video_frame->frame(), estimated_capture_time);
+ // Invalidate the JS |video_frame|. Otherwise, the media frames might not be
+ // released, which would leak resources and also cause some MediaStream
+ // sources such as cameras to drop frames.
+ video_frame->close();
return ScriptPromise::CastUndefined(script_state);
}
@@ -49,14 +60,16 @@ ScriptPromise MediaStreamVideoTrackUnderlyingSink::abort(
ScriptState* script_state,
ScriptValue reason,
ExceptionState& exception_state) {
- source_->StopSource();
+ if (source_)
+ source_->StopSource();
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise MediaStreamVideoTrackUnderlyingSink::close(
ScriptState* script_state,
ExceptionState& exception_state) {
- source_->StopSource();
+ if (source_)
+ source_->StopSource();
return ScriptPromise::CastUndefined(script_state);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
index 6df20efe4f4..115b518c053 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
@@ -10,12 +10,12 @@
namespace blink {
+class MediaStreamVideoSource;
class PushableMediaStreamVideoSource;
class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSink
: public UnderlyingSinkBase {
public:
- // |source| must outlive this MediaStreamVideoTrackUnderlyingSink.
explicit MediaStreamVideoTrackUnderlyingSink(
PushableMediaStreamVideoSource* source);
@@ -34,7 +34,7 @@ class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSink
ExceptionState& exception_state) override;
private:
- PushableMediaStreamVideoSource* source_;
+ base::WeakPtr<MediaStreamVideoSource> source_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
index 915c3541645..0124062b569 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
@@ -53,11 +53,14 @@ class MediaStreamVideoTrackUnderlyingSinkTest : public testing::Test {
/*enabled=*/true);
}
- ScriptValue CreateVideoFrameChunk(ScriptState* script_state) {
+ ScriptValue CreateVideoFrameChunk(ScriptState* script_state,
+ VideoFrame** video_frame_out = nullptr) {
const scoped_refptr<media::VideoFrame> media_frame =
media::VideoFrame::CreateBlackFrame(gfx::Size(100, 50));
- VideoFrame* video_frame =
- MakeGarbageCollected<VideoFrame>(std::move(media_frame));
+ VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
+ std::move(media_frame), ExecutionContext::From(script_state));
+ if (video_frame_out)
+ *video_frame_out = video_frame;
return ScriptValue(script_state->GetIsolate(),
ToV8(video_frame, script_state->GetContext()->Global(),
script_state->GetIsolate()));
@@ -69,8 +72,10 @@ class MediaStreamVideoTrackUnderlyingSinkTest : public testing::Test {
PushableMediaStreamVideoSource* pushable_video_source_;
};
+// TODO(1153092): Test flakes, likely due to completing before background
+// thread has had chance to call OnVideoFrame().
TEST_F(MediaStreamVideoTrackUnderlyingSinkTest,
- WriteToStreamForwardsToMediaStreamSink) {
+ DISABLED_WriteToStreamForwardsToMediaStreamSink) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
auto* underlying_sink = CreateUnderlyingSink(script_state);
@@ -84,12 +89,17 @@ TEST_F(MediaStreamVideoTrackUnderlyingSinkTest,
NonThrowableExceptionState exception_state;
auto* writer = writable_stream->getWriter(script_state, exception_state);
+ VideoFrame* video_frame = nullptr;
+ auto video_frame_chunk = CreateVideoFrameChunk(script_state, &video_frame);
+ EXPECT_NE(video_frame, nullptr);
+ EXPECT_NE(video_frame->frame(), nullptr);
EXPECT_CALL(media_stream_video_sink, OnVideoFrame(_));
ScriptPromiseTester write_tester(
script_state,
- writer->write(script_state, CreateVideoFrameChunk(script_state),
- exception_state));
- EXPECT_FALSE(write_tester.IsFulfilled());
+ writer->write(script_state, video_frame_chunk, exception_state));
+ write_tester.WaitUntilSettled();
+ // |video_frame| should be invalidated after sending it to the sink.
+ EXPECT_EQ(video_frame->frame(), nullptr);
writer->releaseLock(script_state);
ScriptPromiseTester close_tester(
@@ -115,6 +125,22 @@ TEST_F(MediaStreamVideoTrackUnderlyingSinkTest, WriteInvalidDataFails) {
DummyExceptionStateForTesting dummy_exception_state;
sink->write(script_state, v8_integer, nullptr, dummy_exception_state);
EXPECT_TRUE(dummy_exception_state.HadException());
+
+ // Writing a null value to the sink should fail.
+ dummy_exception_state.ClearException();
+ EXPECT_FALSE(dummy_exception_state.HadException());
+ sink->write(script_state, ScriptValue::CreateNull(v8_scope.GetIsolate()),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+
+ // Writing a destroyed VideoFrame to the sink should fail.
+ dummy_exception_state.ClearException();
+ VideoFrame* video_frame = nullptr;
+ auto chunk = CreateVideoFrameChunk(script_state, &video_frame);
+ video_frame->close();
+ EXPECT_FALSE(dummy_exception_state.HadException());
+ sink->write(script_state, chunk, nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
}
TEST_F(MediaStreamVideoTrackUnderlyingSinkTest, WriteToAbortedSinkFails) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
index a4c98fb283d..5c76dc62b7d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
@@ -19,20 +19,60 @@
namespace blink {
+// Temporary workaround for crbug.com/1182497.
+// Doesn't perform any stream optimization, but instead
+// lets MediaStreamVideoTrackUnderlyingSource know that
+// its stream endpoint has been transferred, and that it should mark its video
+// frames for closure when they are cloned().
+class StreamTransferNotifier final
+ : public ReadableStreamTransferringOptimizer {
+ USING_FAST_MALLOC(StreamTransferNotifier);
+ using OptimizerCallback = CrossThreadOnceClosure;
+
+ public:
+ StreamTransferNotifier(
+ scoped_refptr<base::SingleThreadTaskRunner> original_runner,
+ OptimizerCallback callback)
+ : original_runner_(std::move(original_runner)),
+ callback_(std::move(callback)) {}
+
+ UnderlyingSourceBase* PerformInProcessOptimization(
+ ScriptState* script_state) override {
+ // Send a message back to MediaStreamVideoTrackUnderlyingSource.
+ PostCrossThreadTask(*original_runner_, FROM_HERE, std::move(callback_));
+
+ // Return nullptr will mean that no optimization was performed, and streams
+ // will post internally.
+ return nullptr;
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> original_runner_;
+ OptimizerCallback callback_;
+};
+
MediaStreamVideoTrackUnderlyingSource::MediaStreamVideoTrackUnderlyingSource(
ScriptState* script_state,
- MediaStreamComponent* track)
+ MediaStreamComponent* track,
+ wtf_size_t max_queue_size)
: UnderlyingSourceBase(script_state),
main_task_runner_(ExecutionContext::From(script_state)
->GetTaskRunner(TaskType::kInternalMediaRealTime)),
- track_(track) {
+ track_(track),
+ max_queue_size_(std::max(1u, max_queue_size)) {
DCHECK(track_);
}
ScriptPromise MediaStreamVideoTrackUnderlyingSource::pull(
ScriptState* script_state) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- // No backpressure support, so nothing to do here.
+ if (!queue_.empty()) {
+ ProcessPullRequest();
+ } else {
+ is_pending_pull_ = true;
+ }
+
+ DCHECK_LT(queue_.size(), max_queue_size_);
return ScriptPromise::CastUndefined(script_state);
}
@@ -68,17 +108,42 @@ void MediaStreamVideoTrackUnderlyingSource::Trace(Visitor* visitor) const {
UnderlyingSourceBase::Trace(visitor);
}
+double MediaStreamVideoTrackUnderlyingSource::DesiredSizeForTesting() const {
+ return Controller()->DesiredSize();
+}
+
+void MediaStreamVideoTrackUnderlyingSource::ContextDestroyed() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ UnderlyingSourceBase::ContextDestroyed();
+ queue_.clear();
+}
+
void MediaStreamVideoTrackUnderlyingSource::Close() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
DisconnectFromTrack();
-
if (Controller())
Controller()->Close();
+ queue_.clear();
+}
+
+std::unique_ptr<ReadableStreamTransferringOptimizer>
+MediaStreamVideoTrackUnderlyingSource::GetStreamTransferOptimizer() {
+ auto stream_transferred_cb = [](MediaStreamVideoTrackUnderlyingSource* self) {
+ if (self)
+ self->stream_was_transferred_ = true;
+ };
+
+ return std::make_unique<StreamTransferNotifier>(
+ main_task_runner_,
+ CrossThreadBindOnce(stream_transferred_cb,
+ WrapCrossThreadWeakPersistent(this)));
}
void MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrack(
scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/,
base::TimeTicks estimated_capture_time) {
+ // The scaled video frames are currently ignored.
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
CrossThreadBindOnce(
@@ -91,15 +156,44 @@ void MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrackOnMainThread(
scoped_refptr<media::VideoFrame> media_frame,
base::TimeTicks /*estimated_capture_time*/) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- // Drop the frame if there is already a queued frame in the controller.
- // Queueing even a small number of frames can result in significant
- // performance issues, so do not allow queueing more than one frame.
- if (!Controller() || Controller()->DesiredSize() < 0)
+ DCHECK_LE(queue_.size(), max_queue_size_);
+
+ // If the |queue_| is empty and the consumer has signaled a pull, bypass
+ // |queue_| and send the frame directly to the stream controller.
+ if (queue_.empty() && is_pending_pull_) {
+ SendFrameToStream(std::move(media_frame));
+ return;
+ }
+
+ if (queue_.size() == max_queue_size_)
+ queue_.pop_front();
+
+ queue_.push_back(std::move(media_frame));
+ if (is_pending_pull_) {
+ ProcessPullRequest();
+ }
+}
+
+void MediaStreamVideoTrackUnderlyingSource::ProcessPullRequest() {
+ DCHECK(!queue_.empty());
+ SendFrameToStream(std::move(queue_.front()));
+ queue_.pop_front();
+}
+
+void MediaStreamVideoTrackUnderlyingSource::SendFrameToStream(
+ scoped_refptr<media::VideoFrame> media_frame) {
+ DCHECK(media_frame);
+ if (!Controller())
return;
- VideoFrame* video_frame =
- MakeGarbageCollected<VideoFrame>(std::move(media_frame));
+ VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
+ std::move(media_frame), GetExecutionContext());
+
+ if (stream_was_transferred_)
+ video_frame->handle()->SetCloseOnClone();
+
Controller()->Enqueue(video_frame);
+ is_pending_pull_ = false;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
index 2272283cf29..5c0945880bc 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
@@ -7,8 +7,10 @@
#include "base/threading/thread_checker.h"
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
namespace blink {
@@ -19,7 +21,8 @@ class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSource
public MediaStreamVideoSink {
public:
explicit MediaStreamVideoTrackUnderlyingSource(ScriptState*,
- MediaStreamComponent*);
+ MediaStreamComponent*,
+ wtf_size_t queue_size);
MediaStreamVideoTrackUnderlyingSource(
const MediaStreamVideoTrackUnderlyingSource&) = delete;
MediaStreamVideoTrackUnderlyingSource& operator=(
@@ -30,21 +33,48 @@ class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSource
ScriptPromise Start(ScriptState*) override;
ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
+ // ExecutionLifecycleObserver
+ void ContextDestroyed() override;
+
+ MediaStreamComponent* Track() const { return track_.Get(); }
+ wtf_size_t MaxQueueSize() const { return max_queue_size_; }
+
+ bool IsPendingPullForTesting() const { return is_pending_pull_; }
+ const Deque<scoped_refptr<media::VideoFrame>>& QueueForTesting() const {
+ return queue_;
+ }
+ double DesiredSizeForTesting() const;
+
void Close();
void Trace(Visitor*) const override;
- private:
- FRIEND_TEST_ALL_PREFIXES(MediaStreamVideoTrackUnderlyingSourceTest,
- FramesAreDropped);
+ std::unique_ptr<ReadableStreamTransferringOptimizer>
+ GetStreamTransferOptimizer();
- void OnFrameFromTrack(scoped_refptr<media::VideoFrame> media_frame,
- base::TimeTicks estimated_capture_time);
+ private:
+ void OnFrameFromTrack(
+ scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
+ base::TimeTicks estimated_capture_time);
void OnFrameFromTrackOnMainThread(
scoped_refptr<media::VideoFrame> media_frame,
base::TimeTicks estimated_capture_time);
+ void SendFrameToStream(scoped_refptr<media::VideoFrame> media_frame);
+ void ProcessPullRequest();
+
+ // Used when a stream endpoint was transferred to another realm, to
+ // automatically close frames as they are posted to the other stream.
+ bool stream_was_transferred_ = false;
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const Member<MediaStreamComponent> track_;
+
+ // An internal deque prior to the stream controller's queue. It acts as a ring
+ // buffer and allows dropping old frames instead of new ones in case frames
+ // accumulate due to slow consumption.
+ Deque<scoped_refptr<media::VideoFrame>> queue_;
+ const wtf_size_t max_queue_size_;
+ bool is_pending_pull_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
index cb41a5eb563..5d55827be36 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
#include "third_party/blink/public/web/web_heap.h"
@@ -14,11 +16,14 @@
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+using testing::_;
+
namespace blink {
class MediaStreamVideoTrackUnderlyingSourceTest : public testing::Test {
@@ -51,23 +56,37 @@ class MediaStreamVideoTrackUnderlyingSourceTest : public testing::Test {
MediaStreamVideoTrackUnderlyingSource* CreateSource(
ScriptState* script_state,
- MediaStreamComponent* track) {
+ MediaStreamComponent* track,
+ wtf_size_t buffer_size) {
return MakeGarbageCollected<MediaStreamVideoTrackUnderlyingSource>(
- script_state, track);
+ script_state, track, buffer_size);
}
MediaStreamVideoTrackUnderlyingSource* CreateSource(
- ScriptState* script_state) {
+ ScriptState* script_state,
+ MediaStreamComponent* track) {
+ return CreateSource(script_state, track, 1u);
+ }
+
+ MediaStreamVideoTrackUnderlyingSource* CreateSource(ScriptState* script_state,
+ wtf_size_t buffer_size) {
MediaStreamComponent* track =
CreateTrack(ExecutionContext::From(script_state));
- return MakeGarbageCollected<MediaStreamVideoTrackUnderlyingSource>(
- script_state, track);
+ return CreateSource(script_state, track, buffer_size);
+ }
+
+ MediaStreamVideoTrackUnderlyingSource* CreateSource(
+ ScriptState* script_state) {
+ return CreateSource(script_state, 1u);
}
protected:
- void PushFrame() {
+ void PushFrame(
+ const base::Optional<base::TimeDelta>& timestamp = base::nullopt) {
const scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::CreateBlackFrame(gfx::Size(10, 5));
+ if (timestamp)
+ frame->set_timestamp(*timestamp);
pushable_video_source_->PushFrame(frame, base::TimeTicks());
platform_->RunUntilIdle();
}
@@ -121,26 +140,106 @@ TEST_F(MediaStreamVideoTrackUnderlyingSourceTest,
EXPECT_EQ(video_track->CountSinks(), 0u);
}
-TEST_F(MediaStreamVideoTrackUnderlyingSourceTest, FramesAreDropped) {
+TEST_F(MediaStreamVideoTrackUnderlyingSourceTest,
+ DropOldFramesWhenQueueIsFull) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
- auto* source = CreateSource(script_state);
- // Create a stream, to ensure there is a controller associated to the source.
- ReadableStream::CreateWithCountQueueingStrategy(v8_scope.GetScriptState(),
- source, 0);
- // The controller initially has no frames.
- EXPECT_EQ(source->Controller()->DesiredSize(), 0);
+ const wtf_size_t buffer_size = 5;
+ auto* source = CreateSource(script_state, buffer_size);
+ EXPECT_EQ(source->MaxQueueSize(), buffer_size);
+ // Create a stream to ensure there is a controller associated to the source.
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+ // Add a sink to the track to make it possible to wait until a pushed frame
+ // is delivered to sinks, including |source|, which is a sink of the track.
+ MockMediaStreamVideoSink mock_sink;
+ mock_sink.ConnectToTrack(WebMediaStreamTrack(source->Track()));
+ auto push_frame_sync = [&mock_sink, this](const base::TimeDelta timestamp) {
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_sink, OnVideoFrame(_))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ PushFrame(timestamp);
+ sink_loop.Run();
+ };
+
+ const auto& queue = source->QueueForTesting();
+ for (wtf_size_t i = 0; i < buffer_size; ++i) {
+ EXPECT_EQ(queue.size(), i);
+ base::TimeDelta timestamp = base::TimeDelta::FromSeconds(i);
+ push_frame_sync(timestamp);
+ EXPECT_EQ(queue.back()->timestamp(), timestamp);
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(0));
+ }
- // Push a frame. DesiredSize() decreases since the frame is not consumed.
- PushFrame();
- EXPECT_EQ(source->Controller()->DesiredSize(), -1);
+ // Push another frame while the queue is full.
+ EXPECT_EQ(queue.size(), buffer_size);
+ push_frame_sync(base::TimeDelta::FromSeconds(buffer_size));
+
+ // Since the queue was full, the oldest frame from the queue should have been
+ // dropped.
+ EXPECT_EQ(queue.size(), buffer_size);
+ EXPECT_EQ(queue.back()->timestamp(),
+ base::TimeDelta::FromSeconds(buffer_size));
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(1));
+
+ // Pulling with frames in the queue should move the oldest frame in the queue
+ // to the stream's controller.
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ source->pull(script_state);
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ EXPECT_EQ(queue.size(), buffer_size - 1);
+ EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(2));
- // Push an extra frame. DesiredSize() does not change this time because the
- // frame is dropped.
- PushFrame();
- EXPECT_EQ(source->Controller()->DesiredSize(), -1);
+ source->Close();
+ EXPECT_EQ(queue.size(), 0u);
+}
+
+TEST_F(MediaStreamVideoTrackUnderlyingSourceTest,
+ BypassQueueAfterPullWithEmptyBuffer) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state);
+ // Create a stream to ensure there is a controller associated to the source.
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ MockMediaStreamVideoSink mock_sink;
+ mock_sink.ConnectToTrack(WebMediaStreamTrack(source->Track()));
+ auto push_frame_sync = [&mock_sink, this]() {
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_sink, OnVideoFrame(_))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ PushFrame();
+ sink_loop.Run();
+ };
+
+ // At first, the queue is empty and the desired size is empty as well.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+
+ source->pull(script_state);
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_TRUE(source->IsPendingPullForTesting());
+
+ push_frame_sync();
+ // Since a pull was pending, the frame is put directly in the stream
+ // controller, bypassing the source queue.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
source->Close();
}
+TEST_F(MediaStreamVideoTrackUnderlyingSourceTest, QueueSizeCannotBeZero) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* source = CreateSource(script_state, 0u);
+ // Queue size is always at least 1, even if 0 is requested.
+ EXPECT_EQ(source->MaxQueueSize(), 1u);
+ source->Close();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
index 069e6913cfb..84de1cb4c2e 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
@@ -48,8 +48,8 @@ dictionary MediaTrackConstraintSet {
ConstrainDouble saturation;
ConstrainDouble sharpness;
ConstrainDouble focusDistance;
- [RuntimeEnabled=MediaCapturePanTilt] (boolean or ConstrainDouble) pan;
- [RuntimeEnabled=MediaCapturePanTilt] (boolean or ConstrainDouble) tilt;
+ (boolean or ConstrainDouble) pan;
+ (boolean or ConstrainDouble) tilt;
(boolean or ConstrainDouble) zoom;
ConstrainBoolean torch;
// The "mandatory" and "_optional" members are retained for conformance
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
index af933aaa16d..8df714f8e60 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
@@ -43,8 +43,8 @@ dictionary MediaTrackSettings {
double saturation;
double sharpness;
double focusDistance;
- [RuntimeEnabled=MediaCapturePanTilt] double pan;
- [RuntimeEnabled=MediaCapturePanTilt] double tilt;
+ double pan;
+ double tilt;
double zoom;
boolean torch;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
index f1234991ad3..c62076245f6 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
@@ -44,11 +44,11 @@ dictionary MediaTrackSupportedConstraints {
boolean iso = true;
boolean brightness = true;
boolean contrast = true;
- [RuntimeEnabled=MediaCapturePanTilt] boolean pan = true;
+ boolean pan = true;
boolean saturation = true;
boolean sharpness = true;
boolean focusDistance = true;
- [RuntimeEnabled=MediaCapturePanTilt] boolean tilt = true;
+ boolean tilt = true;
boolean zoom = true;
boolean torch = true;
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.cc
new file mode 100644
index 00000000000..a3be50b053b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.cc
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
+
+namespace blink {
+MockMediaStreamAudioSink::MockMediaStreamAudioSink() = default;
+MockMediaStreamAudioSink::~MockMediaStreamAudioSink() = default;
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h
new file mode 100644
index 00000000000..4699b9928e2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MOCK_MEDIA_STREAM_AUDIO_SINK_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MOCK_MEDIA_STREAM_AUDIO_SINK_H_
+
+#include "media/base/audio_bus.h"
+#include "media/base/audio_parameters.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
+
+namespace blink {
+
+class MockMediaStreamAudioSink : public WebMediaStreamAudioSink {
+ public:
+ MockMediaStreamAudioSink();
+ ~MockMediaStreamAudioSink() override;
+
+ MOCK_METHOD2(OnData, void(const media::AudioBus&, base::TimeTicks));
+ MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters&));
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MOCK_MEDIA_STREAM_AUDIO_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.cc
index 36c31d02b23..1094c4700ff 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.cc
@@ -32,6 +32,7 @@ EncodedVideoFrameCB MockMediaStreamVideoSink::GetDeliverEncodedVideoFrameCB() {
void MockMediaStreamVideoSink::DeliverVideoFrame(
scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks estimated_capture_time) {
++number_of_frames_;
format_ = frame->format();
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h
index 9d92deb05e6..cb429fa256e 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h
@@ -61,8 +61,10 @@ class MockMediaStreamVideoSink : public MediaStreamVideoSink {
}
private:
- void DeliverVideoFrame(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time);
+ void DeliverVideoFrame(
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time);
void DeliverEncodedVideoFrame(scoped_refptr<EncodedVideoFrame> frame,
base::TimeTicks estimated_capture_time);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
index f4512922b4b..b7f926bc69f 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
@@ -57,7 +57,9 @@ void MockMediaStreamVideoSource::RequestRefreshFrame() {
base::TimeDelta());
PostCrossThreadTask(
*io_task_runner(), FROM_HERE,
- CrossThreadBindOnce(frame_callback_, frame, base::TimeTicks()));
+ CrossThreadBindOnce(frame_callback_, frame,
+ std::vector<scoped_refptr<media::VideoFrame>>(),
+ base::TimeTicks()));
}
OnRequestRefreshFrame();
}
@@ -66,6 +68,16 @@ void MockMediaStreamVideoSource::OnHasConsumers(bool has_consumers) {
is_suspended_ = !has_consumers;
}
+VideoCaptureFeedbackCB MockMediaStreamVideoSource::GetFeedbackCallback() const {
+ return WTF::BindRepeating(&MockMediaStreamVideoSource::OnFrameFeedback,
+ WTF::Unretained(this));
+}
+
+base::WeakPtr<MediaStreamVideoSource> MockMediaStreamVideoSource::GetWeakPtr()
+ const {
+ return weak_factory_.GetWeakPtr();
+}
+
void MockMediaStreamVideoSource::DoChangeSource(
const MediaStreamDevice& new_device) {
ChangeSourceImpl(new_device);
@@ -100,9 +112,11 @@ void MockMediaStreamVideoSource::DeliverVideoFrame(
scoped_refptr<media::VideoFrame> frame) {
DCHECK(!is_stopped_for_restart_);
DCHECK(!frame_callback_.is_null());
- PostCrossThreadTask(*io_task_runner(), FROM_HERE,
- CrossThreadBindOnce(frame_callback_, std::move(frame),
- base::TimeTicks()));
+ PostCrossThreadTask(
+ *io_task_runner(), FROM_HERE,
+ CrossThreadBindOnce(frame_callback_, std::move(frame),
+ std::vector<scoped_refptr<media::VideoFrame>>(),
+ base::TimeTicks()));
}
void MockMediaStreamVideoSource::DeliverEncodedVideoFrame(
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
index 7b23b1ab953..1ffb2b7f550 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
@@ -27,6 +27,8 @@ class MockMediaStreamVideoSource : public blink::MediaStreamVideoSource {
MOCK_METHOD0(OnRequestRefreshFrame, void());
MOCK_METHOD1(OnCapturingLinkSecured, void(bool));
MOCK_CONST_METHOD0(SupportsEncodedOutput, bool());
+ MOCK_METHOD1(OnFrameDropped, void(media::VideoCaptureFrameDropReason));
+ MOCK_CONST_METHOD1(OnFrameFeedback, void(const media::VideoFrameFeedback&));
// Simulate that the underlying source start successfully.
void StartMockedSource();
@@ -71,6 +73,8 @@ class MockMediaStreamVideoSource : public blink::MediaStreamVideoSource {
base::Optional<media::VideoCaptureParams> GetCurrentCaptureParams()
const override;
void OnHasConsumers(bool has_consumers) override;
+ VideoCaptureFeedbackCB GetFeedbackCallback() const override;
+ base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
protected:
// Implements MediaStreamSource.
@@ -98,6 +102,8 @@ class MockMediaStreamVideoSource : public blink::MediaStreamVideoSource {
blink::VideoCaptureDeliverFrameCB frame_callback_;
EncodedVideoFrameCB encoded_frame_callback_;
+ base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(MockMediaStreamVideoSource);
};
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
index 59e0dea8b55..6cec2256f95 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
@@ -288,7 +288,7 @@ bool ProcessedLocalAudioSource::EnsureSourceIsStarted() {
params.AsHumanReadableString().c_str(),
GetAudioParameters().AsHumanReadableString().c_str()));
auto* web_frame =
- static_cast<WebLocalFrame*>(WebFrame::FromFrame(consumer_frame_));
+ static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(consumer_frame_));
scoped_refptr<media::AudioCapturerSource> new_source =
Platform::Current()->NewAudioCapturerSource(web_frame, source_params);
new_source->Initialize(params, this);
@@ -409,7 +409,7 @@ void ProcessedLocalAudioSource::CaptureUsingProcessor(
bool key_pressed) {
#if defined(OS_WIN) || defined(OS_MAC)
DCHECK_LE(volume, 1.0);
-#elif defined(OS_LINUX) || BUILDFLAG(IS_LACROS) || defined(OS_OPENBSD)
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_OPENBSD)
// We have a special situation on Linux where the microphone volume can be
// "higher than maximum". The input volume slider in the sound preference
// allows the user to set a scaling that is higher than 100%. It means that
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
index 315a8f33327..56caecbe2a3 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
@@ -50,10 +50,10 @@ constexpr int kExpectedSourceBufferSize = kRequestedBufferSize;
// output end of its FIFO.
constexpr int kExpectedOutputBufferSize = kSampleRate / 100;
-class MockMediaStreamAudioSink : public WebMediaStreamAudioSink {
+class FormatCheckingMockAudioSink : public WebMediaStreamAudioSink {
public:
- MockMediaStreamAudioSink() {}
- ~MockMediaStreamAudioSink() override {}
+ FormatCheckingMockAudioSink() = default;
+ ~FormatCheckingMockAudioSink() override = default;
void OnData(const media::AudioBus& audio_bus,
base::TimeTicks estimated_capture_time) override {
@@ -173,8 +173,7 @@ TEST_F(ProcessedLocalAudioSourceTest, VerifyAudioFlowWithoutAudioProcessing) {
CheckOutputFormatMatches(audio_source()->GetAudioParameters());
// Connect a sink to the track.
- std::unique_ptr<MockMediaStreamAudioSink> sink(
- new MockMediaStreamAudioSink());
+ auto sink = std::make_unique<FormatCheckingMockAudioSink>();
EXPECT_CALL(*sink, FormatIsSet(_))
.WillOnce(Invoke(this, &ThisTest::CheckOutputFormatMatches));
MediaStreamAudioTrack::From(audio_track())->AddSink(sink.get());
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc
new file mode 100644
index 00000000000..4de9496af80
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
+
+#include "media/base/audio_timestamp_helper.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.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/functional.h"
+
+namespace blink {
+PushableMediaStreamAudioSource::LivenessBroker::LivenessBroker(
+ PushableMediaStreamAudioSource* source)
+ : source_(source) {}
+
+void PushableMediaStreamAudioSource::LivenessBroker::
+ OnSourceDestroyedOrStopped() {
+ WTF::MutexLocker locker(mutex_);
+ source_ = nullptr;
+}
+
+void PushableMediaStreamAudioSource::LivenessBroker::PushAudioData(
+ std::unique_ptr<AudioFrameSerializationData> data) {
+ WTF::MutexLocker locker(mutex_);
+ if (!source_)
+ return;
+
+ source_->DeliverData(std::move(data));
+}
+
+PushableMediaStreamAudioSource::PushableMediaStreamAudioSource(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> audio_task_runner)
+ : MediaStreamAudioSource(std::move(main_task_runner), /* is_local */ true),
+ audio_task_runner_(std::move(audio_task_runner)),
+ liveness_broker_(
+ base::MakeRefCounted<PushableMediaStreamAudioSource::LivenessBroker>(
+ this)) {}
+
+PushableMediaStreamAudioSource::~PushableMediaStreamAudioSource() {
+ liveness_broker_->OnSourceDestroyedOrStopped();
+}
+
+void PushableMediaStreamAudioSource::PushAudioData(
+ std::unique_ptr<AudioFrameSerializationData> data) {
+ if (audio_task_runner_->RunsTasksInCurrentSequence()) {
+ DeliverData(std::move(data));
+ return;
+ }
+
+ PostCrossThreadTask(
+ *audio_task_runner_, FROM_HERE,
+ CrossThreadBindOnce(
+ &PushableMediaStreamAudioSource::LivenessBroker::PushAudioData,
+ liveness_broker_, std::move(data)));
+}
+
+void PushableMediaStreamAudioSource::DeliverData(
+ std::unique_ptr<AudioFrameSerializationData> data) {
+ DCHECK(audio_task_runner_->RunsTasksInCurrentSequence());
+
+ const media::AudioBus& audio_bus = *data->data();
+ int sample_rate = data->sample_rate();
+
+ media::AudioParameters params = GetAudioParameters();
+ if (!params.IsValid() ||
+ params.format() != media::AudioParameters::AUDIO_PCM_LOW_LATENCY ||
+ last_channels_ != audio_bus.channels() ||
+ last_sample_rate_ != sample_rate || last_frames_ != audio_bus.frames()) {
+ SetFormat(
+ media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::GuessChannelLayout(audio_bus.channels()),
+ sample_rate, audio_bus.frames()));
+ last_channels_ = audio_bus.channels();
+ last_sample_rate_ = sample_rate;
+ last_frames_ = audio_bus.frames();
+ }
+
+ // data->timestamp() is the time at the beginning of the |data| audio piece.
+ // |capture_time| is the time at the end of the |data| audio piece.
+ base::TimeTicks capture_time = base::TimeTicks() + data->timestamp() +
+ media::AudioTimestampHelper::FramesToTime(
+ audio_bus.frames(), sample_rate);
+
+ DeliverDataToTracks(audio_bus, capture_time);
+}
+
+bool PushableMediaStreamAudioSource::EnsureSourceIsStarted() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ is_running_ = true;
+ return true;
+}
+
+void PushableMediaStreamAudioSource::EnsureSourceIsStopped() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ liveness_broker_->OnSourceDestroyedOrStopped();
+ is_running_ = false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h
new file mode 100644
index 00000000000..df8a31217da
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_PUSHABLE_MEDIA_STREAM_AUDIO_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_PUSHABLE_MEDIA_STREAM_AUDIO_SOURCE_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
+#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+class AudioFrameSerializationData;
+
+// Simplifies the creation of audio tracks.
+class MODULES_EXPORT PushableMediaStreamAudioSource
+ : public MediaStreamAudioSource {
+ public:
+ PushableMediaStreamAudioSource(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> audio_task_runner);
+
+ ~PushableMediaStreamAudioSource() override;
+
+ // This can be called from any thread, and will push the data on
+ // |audio_task_runner_|
+ void PushAudioData(std::unique_ptr<AudioFrameSerializationData> data);
+
+ bool running() const {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ return is_running_;
+ }
+
+ private:
+ // Helper class that facilitates the jump to |audio_task_runner_|, by
+ // outliving the given |source| if there is a pending task.
+ class LivenessBroker : public WTF::ThreadSafeRefCounted<LivenessBroker> {
+ public:
+ explicit LivenessBroker(PushableMediaStreamAudioSource* source);
+
+ void OnSourceDestroyedOrStopped();
+ void PushAudioData(std::unique_ptr<AudioFrameSerializationData> data);
+
+ private:
+ WTF::Mutex mutex_;
+ PushableMediaStreamAudioSource* source_ GUARDED_BY(mutex_);
+ };
+
+ // Actually push data to the audio tracks. Only called on
+ // |audio_task_runner_|.
+ void DeliverData(std::unique_ptr<AudioFrameSerializationData> data);
+
+ // MediaStreamAudioSource implementation.
+ bool EnsureSourceIsStarted() final;
+ void EnsureSourceIsStopped() final;
+
+ bool is_running_ = false;
+
+ int last_channels_ = 0;
+ int last_frames_ = 0;
+ int last_sample_rate_ = 0;
+
+ scoped_refptr<base::SequencedTaskRunner> audio_task_runner_;
+ scoped_refptr<LivenessBroker> liveness_broker_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_PUSHABLE_MEDIA_STREAM_AUDIO_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc
new file mode 100644
index 00000000000..f95874f12e8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc
@@ -0,0 +1,211 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
+
+#include "base/run_loop.h"
+#include "media/base/bind_to_current_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+
+namespace blink {
+
+namespace {
+
+class FakeMediaStreamAudioSink : public WebMediaStreamAudioSink {
+ public:
+ FakeMediaStreamAudioSink(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> audio_thread)
+ : main_task_runner_(std::move(main_thread)),
+ audio_task_runner_(std::move(audio_thread)) {}
+ ~FakeMediaStreamAudioSink() override = default;
+
+ void SetupNewAudioParameterExpectations(int channels,
+ int frames,
+ int sample_rate) {
+ expected_channels_ = channels;
+ expected_frames_ = frames;
+ expected_sample_rate_ = sample_rate;
+ }
+
+ void SetDataTimeExpectation(base::TimeTicks time, base::OnceClosure on_data) {
+ DCHECK(!on_data_);
+
+ expected_time_ = time;
+ on_data_ = std::move(on_data);
+ }
+
+ void OnData(const media::AudioBus& data, base::TimeTicks time) override {
+ // Make sure the source delivered audio data on the right thread.
+ EXPECT_TRUE(audio_task_runner_->BelongsToCurrentThread());
+
+ EXPECT_EQ(time, expected_time_);
+ EXPECT_EQ(data.channels(), expected_channels_);
+ EXPECT_EQ(data.frames(), expected_frames_);
+
+ // Call this after all expectations are checked, to prevent test from
+ // setting new expectations on the main thread.
+ std::move(on_data_).Run();
+ }
+
+ void OnSetFormat(const media::AudioParameters& params) override {
+ // Make sure the source changed parameters data on the right thread.
+ EXPECT_TRUE(audio_task_runner_->BelongsToCurrentThread());
+
+ // Also make sure that the audio thread is different from the main
+ // thread (it would be a test error if it wasn't, as it would be
+ // impossible for the check above to fail).
+ ASSERT_TRUE(!main_task_runner_->BelongsToCurrentThread());
+
+ // This should only be called once per format change.
+ EXPECT_FALSE(did_receive_format_change_);
+
+ EXPECT_EQ(params.sample_rate(), expected_sample_rate_);
+ EXPECT_EQ(params.channels(), expected_channels_);
+ EXPECT_EQ(params.frames_per_buffer(), expected_frames_);
+
+ did_receive_format_change_ = true;
+ }
+
+ void ClearDidReceiveFormatChange() { did_receive_format_change_ = false; }
+
+ bool did_receive_format_change() const { return did_receive_format_change_; }
+
+ public:
+ int expected_channels_ = 0;
+ int expected_frames_ = 0;
+ int expected_sample_rate_ = 0;
+ base::TimeTicks expected_time_;
+
+ bool did_receive_format_change_ = false;
+
+ base::OnceClosure on_data_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
+};
+
+} // namespace
+
+class PushableMediaStreamAudioSourceTest : public testing::Test {
+ public:
+ PushableMediaStreamAudioSourceTest() {
+ // Use the IO thread for testing purposes. This is stricter than an audio
+ // sequenced task runner needs to be.
+ audio_task_runner_ = Platform::Current()->GetIOTaskRunner();
+ main_task_runner_ = Thread::MainThread()->GetTaskRunner();
+
+ pushable_audio_source_ = new PushableMediaStreamAudioSource(
+ main_task_runner_, audio_task_runner_);
+ stream_source_ = MakeGarbageCollected<MediaStreamSource>(
+ "dummy_source_id", MediaStreamSource::kTypeAudio, "dummy_source_name",
+ false /* remote */);
+ stream_source_->SetPlatformSource(base::WrapUnique(pushable_audio_source_));
+ stream_component_ = MakeGarbageCollected<MediaStreamComponent>(
+ stream_source_->Id(), stream_source_);
+ }
+
+ void TearDown() override {
+ stream_source_ = nullptr;
+ stream_component_ = nullptr;
+ WebHeap::CollectAllGarbageForTesting();
+ }
+
+ bool ConnectSourceToTrack() {
+ return pushable_audio_source_->ConnectToTrack(stream_component_);
+ }
+
+ void SendAndVerifyAudioData(FakeMediaStreamAudioSink* fake_sink,
+ int channels,
+ int frames,
+ int sample_rate,
+ bool expect_format_change) {
+ fake_sink->ClearDidReceiveFormatChange();
+
+ if (expect_format_change) {
+ fake_sink->SetupNewAudioParameterExpectations(channels, frames,
+ sample_rate);
+ }
+
+ base::RunLoop run_loop;
+ base::TimeTicks timestamp = base::TimeTicks::Now();
+ base::TimeDelta duration =
+ base::TimeDelta::FromSeconds(1) * frames / sample_rate;
+ base::TimeTicks capture_time = timestamp + duration;
+ fake_sink->SetDataTimeExpectation(capture_time, run_loop.QuitClosure());
+
+ pushable_audio_source_->PushAudioData(AudioFrameSerializationData::Wrap(
+ media::AudioBus::Create(channels, frames), sample_rate,
+ timestamp - base::TimeTicks()));
+ run_loop.Run();
+
+ EXPECT_EQ(fake_sink->did_receive_format_change(), expect_format_change);
+ }
+
+ protected:
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+
+ Persistent<MediaStreamSource> stream_source_;
+ Persistent<MediaStreamComponent> stream_component_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
+
+ PushableMediaStreamAudioSource* pushable_audio_source_;
+};
+
+TEST_F(PushableMediaStreamAudioSourceTest, ConnectAndStop) {
+ EXPECT_EQ(MediaStreamSource::kReadyStateLive,
+ stream_source_->GetReadyState());
+ EXPECT_FALSE(pushable_audio_source_->running());
+
+ EXPECT_TRUE(ConnectSourceToTrack());
+ EXPECT_EQ(MediaStreamSource::kReadyStateLive,
+ stream_source_->GetReadyState());
+ EXPECT_TRUE(pushable_audio_source_->running());
+
+ // If the pushable source stops, the MediaStreamSource should stop.
+ pushable_audio_source_->StopSource();
+ EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
+ stream_source_->GetReadyState());
+ EXPECT_FALSE(pushable_audio_source_->running());
+}
+
+TEST_F(PushableMediaStreamAudioSourceTest, FramesPropagateToSink) {
+ EXPECT_TRUE(ConnectSourceToTrack());
+ FakeMediaStreamAudioSink fake_sink(main_task_runner_, audio_task_runner_);
+
+ WebMediaStreamAudioSink::AddToAudioTrack(
+ &fake_sink, WebMediaStreamTrack(stream_component_.Get()));
+
+ constexpr int kChannels = 1;
+ constexpr int kFrames = 256;
+ constexpr int kSampleRate = 8000;
+
+ // The first audio data pushed should trigger a call to OnSetFormat().
+ SendAndVerifyAudioData(&fake_sink, kChannels, kFrames, kSampleRate,
+ /*expect_format_change=*/true);
+
+ // Using the same audio parameters should not trigger OnSetFormat().
+ SendAndVerifyAudioData(&fake_sink, kChannels, kFrames, kSampleRate,
+ /*expect_format_change=*/false);
+
+ // Format changes should trigger OnSetFormat().
+ SendAndVerifyAudioData(&fake_sink, kChannels * 2, kFrames * 4,
+ /*sample_rate=*/44100, /*expect_format_change=*/true);
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(
+ &fake_sink, WebMediaStreamTrack(stream_component_.Get()));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
index 40728707943..c991ad52f86 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.cc
@@ -5,11 +5,16 @@
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.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"
namespace blink {
+PushableMediaStreamVideoSource::PushableMediaStreamVideoSource(
+ const base::WeakPtr<MediaStreamVideoSource>& upstream_source)
+ : upstream_source_(upstream_source) {}
+
void PushableMediaStreamVideoSource::PushFrame(
scoped_refptr<media::VideoFrame> video_frame,
base::TimeTicks estimated_capture_time) {
@@ -30,9 +35,44 @@ void PushableMediaStreamVideoSource::PushFrame(
PostCrossThreadTask(
*io_task_runner(), FROM_HERE,
CrossThreadBindOnce(deliver_frame_cb_, std::move(video_frame),
+ std::vector<scoped_refptr<media::VideoFrame>>(),
estimated_capture_time));
}
+void PushableMediaStreamVideoSource::RequestRefreshFrame() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (upstream_source_)
+ upstream_source_->RequestRefreshFrame();
+ if (signal_observer_)
+ signal_observer_->RequestFrame();
+}
+
+void PushableMediaStreamVideoSource::OnFrameDropped(
+ media::VideoCaptureFrameDropReason reason) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (upstream_source_)
+ upstream_source_->OnFrameDropped(reason);
+}
+
+VideoCaptureFeedbackCB PushableMediaStreamVideoSource::GetFeedbackCallback()
+ const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (upstream_source_) {
+ return WTF::BindRepeating(
+ [](const base::WeakPtr<MediaStreamVideoSource>& source,
+ const media::VideoFrameFeedback& feedback) {
+ if (!source)
+ return;
+
+ PushableMediaStreamVideoSource* pushable_source =
+ static_cast<PushableMediaStreamVideoSource*>(source.get());
+ pushable_source->GetInternalFeedbackCallback().Run(feedback);
+ },
+ GetWeakPtr());
+ }
+ return VideoCaptureFeedbackCB();
+}
+
void PushableMediaStreamVideoSource::StartSourceImpl(
VideoCaptureDeliverFrameCB frame_callback,
EncodedVideoFrameCB encoded_frame_callback) {
@@ -48,4 +88,24 @@ void PushableMediaStreamVideoSource::StopSourceImpl() {
running_ = false;
}
+base::WeakPtr<MediaStreamVideoSource>
+PushableMediaStreamVideoSource::GetWeakPtr() const {
+ return weak_factory_.GetWeakPtr();
+}
+
+VideoCaptureFeedbackCB
+PushableMediaStreamVideoSource::GetInternalFeedbackCallback() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!upstream_source_)
+ return VideoCaptureFeedbackCB();
+
+ return upstream_source_->GetFeedbackCallback();
+}
+
+void PushableMediaStreamVideoSource::SetSignalObserver(
+ MediaStreamVideoTrackSignalObserver* observer) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ signal_observer_ = observer;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
index 8accdc27d86..c8ac5dc4fa6 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h
@@ -11,6 +11,8 @@
namespace blink {
+class MediaStreamVideoTrackSignalObserver;
+
// Simplifies the creation of video tracks. Just do this:
// auto source = std::make_unique<PushableMediaStreamVideoSource>();
// auto* track = CreateVideoTrackFromSource(script_state, source);
@@ -20,6 +22,9 @@ namespace blink {
class MODULES_EXPORT PushableMediaStreamVideoSource
: public MediaStreamVideoSource {
public:
+ PushableMediaStreamVideoSource() = default;
+ explicit PushableMediaStreamVideoSource(
+ const base::WeakPtr<MediaStreamVideoSource>& upstream_source);
// See the definition of VideoCaptureDeliverFrameCB in
// media/capture/video_capturer_source.h for the documentation
// of |estimated_capture_time| and the difference with
@@ -29,14 +34,26 @@ class MODULES_EXPORT PushableMediaStreamVideoSource
bool running() const { return running_; }
// MediaStreamVideoSource
+ void RequestRefreshFrame() override;
+ void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
+ VideoCaptureFeedbackCB GetFeedbackCallback() const override;
void StartSourceImpl(VideoCaptureDeliverFrameCB frame_callback,
EncodedVideoFrameCB encoded_frame_callback) override;
void StopSourceImpl() override;
+ base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
+
+ VideoCaptureFeedbackCB GetInternalFeedbackCallback() const;
+ void SetSignalObserver(MediaStreamVideoTrackSignalObserver*);
private:
bool running_ = false;
VideoCaptureDeliverFrameCB deliver_frame_cb_;
+
+ base::WeakPtr<MediaStreamVideoSource> upstream_source_;
+ WeakPersistent<MediaStreamVideoTrackSignalObserver> signal_observer_;
+
THREAD_CHECKER(thread_checker_);
+ base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
index 4cd633b8f64..8cb1742457a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
#include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
@@ -43,9 +44,10 @@ class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
void DisconnectFromTrack() { MediaStreamVideoSink::DisconnectFromTrack(); }
void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks capture_time) {
*capture_time_ = capture_time;
- *metadata_ = *frame->metadata();
+ *metadata_ = frame->metadata();
*natural_size_ = frame->natural_size();
std::move(got_frame_cb_).Run();
}
@@ -57,16 +59,36 @@ class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
base::OnceClosure got_frame_cb_;
};
+MediaStreamSource* CreateConnectedMediaStreamSource(
+ MediaStreamVideoSource* video_source) {
+ MediaStreamSource* media_stream_source =
+ MakeGarbageCollected<MediaStreamSource>(
+ "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
+ false /* remote */);
+ media_stream_source->SetPlatformSource(base::WrapUnique(video_source));
+ return media_stream_source;
+}
+
+WebMediaStreamTrack StartVideoSource(MediaStreamVideoSource* video_source) {
+ return MediaStreamVideoTrack::CreateVideoTrack(
+ video_source, MediaStreamVideoSource::ConstraintsOnceCallback(),
+ /*enabled=*/true);
+}
+
+MediaStreamSource* CreateAndStartMediaStreamSource(
+ MediaStreamVideoSource* video_source) {
+ MediaStreamSource* source = CreateConnectedMediaStreamSource(video_source);
+ StartVideoSource(video_source);
+ return source;
+}
+
} // namespace
class PushableMediaStreamVideoSourceTest : public testing::Test {
public:
PushableMediaStreamVideoSourceTest() {
pushable_video_source_ = new PushableMediaStreamVideoSource();
- stream_source_ = MakeGarbageCollected<MediaStreamSource>(
- "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
- false /* remote */);
- stream_source_->SetPlatformSource(base::WrapUnique(pushable_video_source_));
+ stream_source_ = CreateConnectedMediaStreamSource(pushable_video_source_);
}
void TearDown() override {
@@ -75,10 +97,7 @@ class PushableMediaStreamVideoSourceTest : public testing::Test {
}
WebMediaStreamTrack StartSource() {
- return MediaStreamVideoTrack::CreateVideoTrack(
- pushable_video_source_,
- MediaStreamVideoSource::ConstraintsOnceCallback(),
- /*enabled=*/true);
+ return StartVideoSource(pushable_video_source_);
}
protected:
@@ -118,7 +137,7 @@ TEST_F(PushableMediaStreamVideoSourceTest, FramesPropagateToSink) {
fake_sink.ConnectToTrack(track);
const scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::CreateBlackFrame(gfx::Size(100, 50));
- frame->metadata()->frame_rate = 30.0;
+ frame->metadata().frame_rate = 30.0;
pushable_video_source_->PushFrame(frame, reference_capture_time);
run_loop.Run();
@@ -130,4 +149,24 @@ TEST_F(PushableMediaStreamVideoSourceTest, FramesPropagateToSink) {
EXPECT_EQ(natural_size.height(), 50);
}
+TEST_F(PushableMediaStreamVideoSourceTest, ForwardToUpstream) {
+ MockMediaStreamVideoSource* mock_source = new MockMediaStreamVideoSource();
+ PushableMediaStreamVideoSource* pushable_video_source =
+ new PushableMediaStreamVideoSource(mock_source->GetWeakPtr());
+ CreateAndStartMediaStreamSource(mock_source);
+ CreateAndStartMediaStreamSource(pushable_video_source);
+
+ EXPECT_CALL(*mock_source, OnRequestRefreshFrame());
+ pushable_video_source->RequestRefreshFrame();
+
+ EXPECT_CALL(*mock_source,
+ OnFrameDropped(media::VideoCaptureFrameDropReason::
+ kResolutionAdapterFrameIsNotValid));
+ pushable_video_source->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kResolutionAdapterFrameIsNotValid);
+
+ EXPECT_CALL(*mock_source, OnFrameFeedback(media::VideoFrameFeedback()));
+ pushable_video_source->GetFeedbackCallback().Run(media::VideoFrameFeedback());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.cc b/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.cc
new file mode 100644
index 00000000000..61387e427bf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "stream_test_utils.h"
+
+#include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+
+namespace blink {
+
+MockMediaStreamVideoSource* CreateMockVideoSource() {
+ MockMediaStreamVideoSource* mock_video_source =
+ new MockMediaStreamVideoSource();
+ MediaStreamSource* media_stream_source =
+ MakeGarbageCollected<MediaStreamSource>(
+ "source_id", MediaStreamSource::kTypeVideo, "source_name",
+ /*remote=*/false);
+ media_stream_source->SetPlatformSource(base::WrapUnique(mock_video_source));
+ return mock_video_source;
+}
+
+MediaStreamTrack* CreateVideoMediaStreamTrack(ExecutionContext* context,
+ MediaStreamVideoSource* source) {
+ return MakeGarbageCollected<MediaStreamTrack>(
+ context, MediaStreamVideoTrack::CreateVideoTrack(
+ source, MediaStreamVideoSource::ConstraintsOnceCallback(),
+ /*enabled=*/true));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.h b/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.h
new file mode 100644
index 00000000000..060d3539ac6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/stream_test_utils.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_STREAM_TEST_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_STREAM_TEST_UTILS_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.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/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+class ExecutionContext;
+class MediaStreamTrack;
+class MediaStreamVideoSource;
+class MockMediaStreamVideoSource;
+
+template <typename T>
+T* ReadObjectFromStream(const V8TestingScope& v8_scope,
+ ReadableStreamDefaultReader* reader) {
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ScriptPromiseTester read_tester(
+ script_state, reader->read(script_state, ASSERT_NO_EXCEPTION));
+ read_tester.WaitUntilSettled();
+ EXPECT_TRUE(read_tester.IsFulfilled());
+
+ v8::Local<v8::Value> result = read_tester.Value().V8Value();
+ EXPECT_TRUE(result->IsObject());
+ v8::Local<v8::Value> v8_signal;
+ bool done = false;
+ EXPECT_TRUE(
+ V8UnpackIteratorResult(script_state, result.As<v8::Object>(), &done)
+ .ToLocal(&v8_signal));
+ EXPECT_FALSE(done);
+ return NativeValueTraits<T>::NativeValue(v8_scope.GetIsolate(), v8_signal,
+ ASSERT_NO_EXCEPTION);
+}
+
+MockMediaStreamVideoSource* CreateMockVideoSource();
+MediaStreamTrack* CreateVideoMediaStreamTrack(ExecutionContext*,
+ MediaStreamVideoSource*);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_STREAM_TEST_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc b/chromium/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
index f5692f995d0..08c383b5c5c 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
@@ -61,7 +61,7 @@ WebLocalFrame* ToWebLocalFrame(LocalFrame* frame) {
if (!frame)
return nullptr;
- return static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame));
+ return static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(frame));
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
index af4af43b675..f47e72a4573 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
@@ -192,7 +192,7 @@ class MockMediaDevicesDispatcherHost
blink::mojom::blink::VideoInputDeviceCapabilities::New();
device->device_id = kFakeVideoInputDeviceId1;
device->group_id = String("dummy");
- device->facing_mode = media::MEDIA_VIDEO_FACING_USER;
+ device->facing_mode = mojom::blink::FacingMode::USER;
if (!video_source_ || !video_source_->IsRunning() ||
!video_source_->GetCurrentFormat()) {
device->formats.push_back(media::VideoCaptureFormat(
@@ -210,7 +210,7 @@ class MockMediaDevicesDispatcherHost
device = blink::mojom::blink::VideoInputDeviceCapabilities::New();
device->device_id = kFakeVideoInputDeviceId2;
device->group_id = String("dummy");
- device->facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT;
+ device->facing_mode = mojom::blink::FacingMode::ENVIRONMENT;
device->formats.push_back(media::VideoCaptureFormat(
gfx::Size(640, 480), 30.0f, media::PIXEL_FORMAT_I420));
result.push_back(std::move(device));
@@ -475,12 +475,16 @@ class UserMediaClientUnderTest : public UserMediaClient {
class UserMediaChromeClient : public EmptyChromeClient {
public:
- ScreenInfo GetScreenInfo(LocalFrame&) const override {
- ScreenInfo info;
- info.rect = gfx::Rect(blink::kDefaultScreenCastWidth,
- blink::kDefaultScreenCastHeight);
- return info;
+ UserMediaChromeClient()
+ : screen_info_({.rect = gfx::Rect(blink::kDefaultScreenCastWidth,
+ blink::kDefaultScreenCastHeight)}) {}
+
+ const ScreenInfo& GetScreenInfo(LocalFrame&) const override {
+ return screen_info_;
}
+
+ private:
+ const ScreenInfo screen_info_;
};
} // namespace
@@ -927,8 +931,9 @@ TEST_F(UserMediaClientTest, DefaultConstraintsPropagate) {
blink::MediaStreamVideoSource::kDefaultWidth);
EXPECT_EQ(video_capture_settings.Height(),
blink::MediaStreamVideoSource::kDefaultHeight);
- EXPECT_EQ(video_capture_settings.FrameRate(),
- blink::MediaStreamVideoSource::kDefaultFrameRate);
+ EXPECT_EQ(
+ video_capture_settings.FrameRate(),
+ static_cast<float>(blink::MediaStreamVideoSource::kDefaultFrameRate));
EXPECT_EQ(video_capture_settings.ResolutionChangePolicy(),
media::ResolutionChangePolicy::FIXED_RESOLUTION);
EXPECT_FALSE(video_capture_settings.noise_reduction());
@@ -937,10 +942,11 @@ TEST_F(UserMediaClientTest, DefaultConstraintsPropagate) {
const blink::VideoTrackAdapterSettings& track_settings =
video_capture_settings.track_adapter_settings();
EXPECT_FALSE(track_settings.target_size().has_value());
- EXPECT_EQ(track_settings.min_aspect_ratio(),
- 1.0 / blink::MediaStreamVideoSource::kDefaultHeight);
+ EXPECT_EQ(
+ track_settings.min_aspect_ratio(),
+ 1.0 / static_cast<double>(blink::MediaStreamVideoSource::kDefaultHeight));
EXPECT_EQ(track_settings.max_aspect_ratio(),
- blink::MediaStreamVideoSource::kDefaultWidth);
+ static_cast<double>(blink::MediaStreamVideoSource::kDefaultWidth));
// 0.0 is the default max_frame_rate and it indicates no frame-rate adjustment
EXPECT_EQ(track_settings.max_frame_rate(), 0.0);
}
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 dc395abdb23..e6ef17c222b 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
@@ -10,10 +10,10 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "media/base/audio_parameters.h"
#include "media/capture/video_capture_types.h"
@@ -47,7 +47,6 @@
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
#include "third_party/blink/renderer/platform/mediastream/webrtc_uma_histograms.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/video_capture/local_video_capturer_source.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -812,9 +811,6 @@ void UserMediaProcessor::SetupVideoInput() {
// static
bool UserMediaProcessor::IsPanTiltZoomPermissionRequested(
const MediaConstraints& constraints) {
- if (!RuntimeEnabledFeatures::MediaCapturePanTiltEnabled())
- return false;
-
if (constraints.Basic().pan.IsPresent() ||
constraints.Basic().tilt.IsPresent() ||
constraints.Basic().zoom.IsPresent()) {
@@ -948,7 +944,8 @@ UserMediaProcessor::GetMediaStreamDeviceObserver() {
auto* media_stream_device_observer =
media_stream_device_observer_for_testing_;
if (frame_) { // Can be null for tests.
- auto* web_frame = static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame_));
+ auto* web_frame =
+ static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(frame_));
if (!web_frame || !web_frame->Client())
return nullptr;
@@ -1063,7 +1060,7 @@ gfx::Size UserMediaProcessor::GetScreenSize() {
gfx::Size screen_size(blink::kDefaultScreenCastWidth,
blink::kDefaultScreenCastHeight);
if (frame_) { // Can be null in tests.
- blink::ScreenInfo info = frame_->GetChromeClient().GetScreenInfo(*frame_);
+ const ScreenInfo& info = frame_->GetChromeClient().GetScreenInfo(*frame_);
screen_size = info.rect.size();
}
return screen_size;
@@ -1277,8 +1274,8 @@ MediaStreamSource* UserMediaProcessor::InitializeVideoSourceObject(
// operate over WTF::Vector.
String::FromUTF8(device.id),
ToStdVector(*current_request_info_->GetNativeVideoFormats(device_id)),
- device.video_facing, current_request_info_->is_video_device_capture(),
- device.group_id));
+ static_cast<mojom::blink::FacingMode>(device.video_facing),
+ current_request_info_->is_video_device_capture(), device.group_id));
local_sources_.push_back(source);
}
return source;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
index 5f90204338c..6e589871f20 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -115,7 +115,7 @@ class MODULES_EXPORT UserMediaRequest final
MediaConstraints video,
Callbacks*,
IdentifiableSurface surface);
- virtual ~UserMediaRequest();
+ ~UserMediaRequest() override;
LocalDOMWindow* GetWindow();
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
index 2fc60c13d23..d51e4e8d396 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_renderer_algorithm_wrapper.cc
@@ -31,7 +31,7 @@ void VideoRendererAlgorithmWrapper::EnqueueFrame(
scoped_refptr<media::VideoFrame> frame) {
DCHECK(frame);
if (renderer_algorithm_ == RendererAlgorithm::Default &&
- frame->metadata()->maximum_composition_delay_in_frames) {
+ frame->metadata().maximum_composition_delay_in_frames) {
default_rendering_frame_buffer_.release();
low_latency_rendering_frame_buffer_ =
std::make_unique<LowLatencyVideoRendererAlgorithm>(media_log_);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
index 4a691e8bc04..c466b90546a 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
@@ -166,9 +166,11 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
// callbacks if |track| was not present in the adapter.
VideoTrackCallbacks RemoveAndGetCallbacks(const MediaStreamVideoTrack* track);
- void DeliverFrame(scoped_refptr<media::VideoFrame> frame,
- const base::TimeTicks& estimated_capture_time,
- bool is_device_rotated);
+ void DeliverFrame(
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ const base::TimeTicks& estimated_capture_time,
+ bool is_device_rotated);
void DeliverEncodedVideoFrame(scoped_refptr<EncodedVideoFrame> frame,
base::TimeTicks estimated_capture_time);
@@ -185,8 +187,10 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
virtual ~VideoFrameResolutionAdapter();
friend class WTF::ThreadSafeRefCounted<VideoFrameResolutionAdapter>;
- void DoDeliverFrame(scoped_refptr<media::VideoFrame> frame,
- const base::TimeTicks& estimated_capture_time);
+ void DoDeliverFrame(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ const base::TimeTicks& estimated_capture_time);
// Returns |true| if the input frame rate is higher that the requested max
// frame rate and |frame| should be dropped. If it returns true, |reason| is
@@ -293,27 +297,29 @@ VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveAndGetCallbacks(
}
void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
- scoped_refptr<media::VideoFrame> frame,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
const base::TimeTicks& estimated_capture_time,
bool is_device_rotated) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
- if (!frame) {
+ if (!video_frame) {
DLOG(ERROR) << "Incoming frame is not valid.";
PostFrameDroppedToMainTaskRunner(
media::VideoCaptureFrameDropReason::kResolutionAdapterFrameIsNotValid);
return;
}
- ComputeFrameRate(frame->timestamp(), &source_format_settings_.frame_rate,
+ ComputeFrameRate(video_frame->timestamp(),
+ &source_format_settings_.frame_rate,
&source_format_settings_.prev_frame_timestamp);
- MaybeUpdateTracksFormat(*frame);
+ MaybeUpdateTracksFormat(*video_frame);
- double frame_rate = frame->metadata()->frame_rate.value_or(
+ double frame_rate = video_frame->metadata().frame_rate.value_or(
MediaStreamVideoSource::kUnknownFrameRate);
auto frame_drop_reason = media::VideoCaptureFrameDropReason::kNone;
- if (MaybeDropFrame(*frame, frame_rate, &frame_drop_reason)) {
+ if (MaybeDropFrame(*video_frame, frame_rate, &frame_drop_reason)) {
PostFrameDroppedToMainTaskRunner(frame_drop_reason);
return;
}
@@ -325,35 +331,45 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
//
// TODO(crbug.com/362521): Allow cropping/scaling of non-GPU memory backed
// textures.
- if (frame->HasTextures() &&
- frame->storage_type() != media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
- DoDeliverFrame(std::move(frame), estimated_capture_time);
+ if (video_frame->HasTextures() &&
+ video_frame->storage_type() !=
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
+ DoDeliverFrame(std::move(video_frame), std::move(scaled_video_frames),
+ estimated_capture_time);
return;
}
- scoped_refptr<media::VideoFrame> video_frame(frame);
+ // The video frame we deliver may or may not get cropping and scaling
+ // soft-applied. Ultimately the listener will decide whether to use the
+ // |delivered_video_frame| or one of the |scaled_video_frames|. When frames
+ // arrive to their final destination, if a scaled frame already has the
+ // destination dimensions there is no need to apply the soft scale calculated
+ // here. But that is not always possible.
+ scoped_refptr<media::VideoFrame> delivered_video_frame = video_frame;
gfx::Size desired_size;
- CalculateDesiredSize(is_device_rotated, frame->natural_size(), settings_,
- &desired_size);
- if (desired_size != frame->natural_size()) {
+ CalculateDesiredSize(is_device_rotated, video_frame->natural_size(),
+ settings_, &desired_size);
+ if (desired_size != video_frame->natural_size()) {
// Get the largest centered rectangle with the same aspect ratio of
- // |desired_size| that fits entirely inside of |frame->visible_rect()|.
- // This will be the rect we need to crop the original frame to.
- // From this rect, the original frame can be scaled down to |desired_size|.
- gfx::Rect region_in_frame =
- media::ComputeLetterboxRegion(frame->visible_rect(), desired_size);
-
- if (frame->HasTextures() || frame->HasGpuMemoryBuffer()) {
+ // |desired_size| that fits entirely inside of
+ // |video_frame->visible_rect()|. This will be the rect we need to crop the
+ // original frame to. From this rect, the original frame can be scaled down
+ // to |desired_size|.
+ gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
+ video_frame->visible_rect(), desired_size);
+
+ if (video_frame->HasTextures() || video_frame->HasGpuMemoryBuffer()) {
// ComputeLetterboxRegion() produces in some cases odd dimensions due to
// internal rounding errors; |region_in_frame| is always smaller or equal
- // to frame->visible_rect(), we can "grow it" if the dimensions are odd.
+ // to video_frame->visible_rect(), we can "grow it" if the dimensions are
+ // odd.
region_in_frame.set_width((region_in_frame.width() + 1) & ~1);
region_in_frame.set_height((region_in_frame.height() + 1) & ~1);
}
- video_frame = media::VideoFrame::WrapVideoFrame(
- frame, frame->format(), region_in_frame, desired_size);
- if (!video_frame) {
+ delivered_video_frame = media::VideoFrame::WrapVideoFrame(
+ video_frame, video_frame->format(), region_in_frame, desired_size);
+ if (!delivered_video_frame) {
PostFrameDroppedToMainTaskRunner(
media::VideoCaptureFrameDropReason::
kResolutionAdapterWrappingFrameForCroppingFailed);
@@ -362,11 +378,12 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
DVLOG(3) << "desired size " << desired_size.ToString()
<< " output natural size "
- << video_frame->natural_size().ToString()
+ << delivered_video_frame->natural_size().ToString()
<< " output visible rect "
- << video_frame->visible_rect().ToString();
+ << delivered_video_frame->visible_rect().ToString();
}
- DoDeliverFrame(std::move(video_frame), estimated_capture_time);
+ DoDeliverFrame(std::move(delivered_video_frame),
+ std::move(scaled_video_frames), estimated_capture_time);
}
void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverEncodedVideoFrame(
@@ -390,7 +407,8 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const {
}
void VideoTrackAdapter::VideoFrameResolutionAdapter::DoDeliverFrame(
- scoped_refptr<media::VideoFrame> frame,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
const base::TimeTicks& estimated_capture_time) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
if (callbacks_.empty()) {
@@ -398,8 +416,9 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DoDeliverFrame(
media::VideoCaptureFrameDropReason::kResolutionAdapterHasNoCallbacks);
}
for (const auto& callback : callbacks_) {
- MaybeUpdateTrackSettings(callback.second.settings_callback, *frame);
- callback.second.frame_callback.Run(frame, estimated_capture_time);
+ MaybeUpdateTrackSettings(callback.second.settings_callback, *video_frame);
+ callback.second.frame_callback.Run(video_frame, scaled_video_frames,
+ estimated_capture_time);
}
}
@@ -542,12 +561,10 @@ void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track,
CrossThreadBindOnce(
&VideoTrackAdapter::AddTrackOnIO, WTF::CrossThreadUnretained(this),
WTF::CrossThreadUnretained(track),
- WTF::Passed(CrossThreadBindRepeating(std::move(frame_callback))),
- WTF::Passed(
- CrossThreadBindRepeating(std::move(encoded_frame_callback))),
- WTF::Passed(CrossThreadBindRepeating(std::move(settings_callback))),
- WTF::Passed(CrossThreadBindRepeating(std::move(format_callback))),
- settings));
+ CrossThreadBindRepeating(std::move(frame_callback)),
+ CrossThreadBindRepeating(std::move(encoded_frame_callback)),
+ CrossThreadBindRepeating(std::move(settings_callback)),
+ CrossThreadBindRepeating(std::move(format_callback)), settings));
}
void VideoTrackAdapter::AddTrackOnIO(
@@ -608,8 +625,7 @@ void VideoTrackAdapter::StartFrameMonitoring(
*io_task_runner_, FROM_HERE,
CrossThreadBindOnce(
&VideoTrackAdapter::StartFrameMonitoringOnIO, WrapRefCounted(this),
- WTF::Passed(
- CrossThreadBindRepeating(std::move(bound_on_muted_callback))),
+ CrossThreadBindRepeating(std::move(bound_on_muted_callback)),
source_frame_rate));
}
@@ -706,9 +722,9 @@ void VideoTrackAdapter::StartFrameMonitoringOnIO(
<< (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s";
PostDelayedCrossThreadTask(
*io_task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this),
- WTF::Passed(std::move(on_muted_callback)), frame_counter_),
+ CrossThreadBindOnce(&VideoTrackAdapter::CheckFramesReceivedOnIO,
+ WrapRefCounted(this), std::move(on_muted_callback),
+ frame_counter_),
base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals /
source_frame_rate_));
}
@@ -763,18 +779,21 @@ void VideoTrackAdapter::ReconfigureTrackOnIO(
}
void VideoTrackAdapter::DeliverFrameOnIO(
- scoped_refptr<media::VideoFrame> frame,
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
base::TimeTicks estimated_capture_time) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0("media", "VideoTrackAdapter::DeliverFrameOnIO");
++frame_counter_;
bool is_device_rotated = false;
+ // It's sufficient to look at |video_frame| since |scaled_video_frames| are
+ // scaled versions of the same image.
// TODO(guidou): Use actual device information instead of this heuristic to
// detect frames from rotated devices. https://crbug.com/722748
if (source_frame_size_ &&
- frame->natural_size().width() == source_frame_size_->height() &&
- frame->natural_size().height() == source_frame_size_->width()) {
+ video_frame->natural_size().width() == source_frame_size_->height() &&
+ video_frame->natural_size().height() == source_frame_size_->width()) {
is_device_rotated = true;
}
if (adapters_.IsEmpty()) {
@@ -785,8 +804,10 @@ void VideoTrackAdapter::DeliverFrameOnIO(
media::VideoCaptureFrameDropReason::
kVideoTrackAdapterHasNoResolutionAdapters));
}
- for (const auto& adapter : adapters_)
- adapter->DeliverFrame(frame, estimated_capture_time, is_device_rotated);
+ for (const auto& adapter : adapters_) {
+ adapter->DeliverFrame(video_frame, scaled_video_frames,
+ estimated_capture_time, is_device_rotated);
+ }
}
void VideoTrackAdapter::DeliverEncodedVideoFrameOnIO(
@@ -821,9 +842,9 @@ void VideoTrackAdapter::CheckFramesReceivedOnIO(
PostDelayedCrossThreadTask(
*io_task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this),
- WTF::Passed(std::move(set_muted_state_callback)), frame_counter_),
+ CrossThreadBindOnce(&VideoTrackAdapter::CheckFramesReceivedOnIO,
+ WrapRefCounted(this),
+ std::move(set_muted_state_callback), frame_counter_),
base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals /
source_frame_rate_));
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.h b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
index b66dd150969..3de75f8c740 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
@@ -62,8 +62,10 @@ class MODULES_EXPORT VideoTrackAdapter
// Delivers |frame| to all tracks that have registered a callback.
// Must be called on the IO-thread.
- void DeliverFrameOnIO(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time);
+ void DeliverFrameOnIO(
+ scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
+ base::TimeTicks estimated_capture_time);
// Delivers |encoded_frame| to all tracks that have registered a callback.
// Must be called on the IO-thread.
@@ -108,6 +110,7 @@ class MODULES_EXPORT VideoTrackAdapter
using VideoCaptureDeliverFrameInternalCallback =
WTF::CrossThreadFunction<void(
scoped_refptr<media::VideoFrame> video_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
base::TimeTicks estimated_capture_time)>;
using DeliverEncodedVideoFrameInternalCallback =
WTF::CrossThreadFunction<void(
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter_unittest.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter_unittest.cc
index 995bc0b5716..45d53378a0b 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_adapter_unittest.cc
@@ -273,8 +273,10 @@ class VideoTrackAdapterFixtureTest : public ::testing::Test {
base::TimeTicks estimated_capture_time) {
auto deliver_frame = [&]() {
platform_support_->GetIOTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&VideoTrackAdapter::DeliverFrameOnIO,
- adapter_, frame, estimated_capture_time));
+ FROM_HERE,
+ base::BindOnce(&VideoTrackAdapter::DeliverFrameOnIO, adapter_, frame,
+ std::vector<scoped_refptr<media::VideoFrame>>(),
+ estimated_capture_time));
};
frame_received_.Reset();
@@ -286,10 +288,12 @@ class VideoTrackAdapterFixtureTest : public ::testing::Test {
frame_received_.Wait();
}
- void OnFrameDelivered(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time) {
+ void OnFrameDelivered(
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time) {
if (frame_validation_callback_) {
- frame_validation_callback_.Run(frame, estimated_capture_time);
+ frame_validation_callback_.Run(frame, {}, estimated_capture_time);
}
frame_received_.Signal();
}
@@ -331,16 +335,18 @@ TEST_F(VideoTrackAdapterFixtureTest, DeliverFrame_GpuMemoryBuffer) {
// Keep the desired size the same as the natural size of the original frame.
VideoTrackAdapterSettings settings_nonscaled(kNaturalSize, kFrameRate);
ConfigureTrack(settings_nonscaled);
- auto check_nonscaled = [&](scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time) {
- // We should get the original frame as-is here.
- EXPECT_EQ(frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
- EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_frame->GetGpuMemoryBuffer());
- EXPECT_EQ(frame->coded_size(), kCodedSize);
- EXPECT_EQ(frame->visible_rect(), kVisibleRect);
- EXPECT_EQ(frame->natural_size(), kNaturalSize);
- };
+ auto check_nonscaled =
+ [&](scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time) {
+ // We should get the original frame as-is here.
+ EXPECT_EQ(frame->storage_type(),
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
+ EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_frame->GetGpuMemoryBuffer());
+ EXPECT_EQ(frame->coded_size(), kCodedSize);
+ EXPECT_EQ(frame->visible_rect(), kVisibleRect);
+ EXPECT_EQ(frame->natural_size(), kNaturalSize);
+ };
SetFrameValidationCallback(base::BindLambdaForTesting(check_nonscaled));
DeliverAndValidateFrame(gmb_frame, base::TimeTicks());
@@ -348,17 +354,19 @@ TEST_F(VideoTrackAdapterFixtureTest, DeliverFrame_GpuMemoryBuffer) {
const gfx::Size kDesiredSize(640, 360);
VideoTrackAdapterSettings settings_scaled(kDesiredSize, kFrameRate);
ConfigureTrack(settings_scaled);
- auto check_scaled = [&](scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time) {
- // The original frame should be wrapped in a new frame, with |kDesiredSize|
- // exposed as natural size of the wrapped frame.
- EXPECT_EQ(frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
- EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_frame->GetGpuMemoryBuffer());
- EXPECT_EQ(frame->coded_size(), kCodedSize);
- EXPECT_EQ(frame->visible_rect(), kVisibleRect);
- EXPECT_EQ(frame->natural_size(), kDesiredSize);
- };
+ auto check_scaled =
+ [&](scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time) {
+ // The original frame should be wrapped in a new frame, with
+ // |kDesiredSize| exposed as natural size of the wrapped frame.
+ EXPECT_EQ(frame->storage_type(),
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
+ EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_frame->GetGpuMemoryBuffer());
+ EXPECT_EQ(frame->coded_size(), kCodedSize);
+ EXPECT_EQ(frame->visible_rect(), kVisibleRect);
+ EXPECT_EQ(frame->natural_size(), kDesiredSize);
+ };
SetFrameValidationCallback(base::BindLambdaForTesting(check_scaled));
DeliverAndValidateFrame(gmb_frame, base::TimeTicks());
}
@@ -417,8 +425,9 @@ class VideoTrackAdapterEncodedTest : public ::testing::Test {
run_loop.Run();
}
- MOCK_METHOD2(OnFrameDelivered,
+ MOCK_METHOD3(OnFrameDelivered,
void(scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks estimated_capture_time));
MOCK_METHOD2(OnEncodedVideoFrameDelivered,
void(scoped_refptr<EncodedVideoFrame>,
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.cc
new file mode 100644
index 00000000000..9fcbbba2bdf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.cc
@@ -0,0 +1,106 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h"
+
+#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal_type.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
+
+namespace blink {
+
+VideoTrackSignalUnderlyingSink::VideoTrackSignalUnderlyingSink(
+ MediaStreamTrack* track) {
+ if (!MediaStreamVideoTrack::From(track->Component()))
+ return;
+ track_ = track;
+ MediaStreamVideoSource* video_source =
+ MediaStreamVideoSource::GetVideoSource(track->Component()->Source());
+ if (video_source)
+ source_ = video_source->GetWeakPtr();
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSink::start(
+ ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSink::write(
+ ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) {
+ MediaStreamTrackSignal* signal =
+ NativeValueTraits<MediaStreamTrackSignal>::NativeValue(
+ script_state->GetIsolate(), chunk.V8Value(), exception_state);
+ if (!signal) {
+ exception_state.ThrowTypeError("Null signal.");
+ return ScriptPromise();
+ }
+
+ if (!track_ || track_->Ended()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "No live track");
+ return ScriptPromise();
+ }
+
+ if (signal->signalType() == "request-frame") {
+ if (!source_ || !source_->IsRunning()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "No active source");
+ return ScriptPromise();
+ }
+ source_->RequestRefreshFrame();
+ return ScriptPromise::CastUndefined(script_state);
+ } else if (signal->signalType() == "set-min-frame-rate") {
+ if (!signal->hasFrameRate()) {
+ exception_state.ThrowTypeError(
+ "A non-negative frameRate is required for set-min-frame-rate.");
+ return ScriptPromise();
+ }
+ if (auto* video_track = MediaStreamVideoTrack::From(track_->Component())) {
+ video_track->SetMinimumFrameRate(signal->frameRate());
+ return ScriptPromise::CastUndefined(script_state);
+ } else {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "No active track");
+ return ScriptPromise();
+ }
+ }
+
+ exception_state.ThrowTypeError("Invalid signal.");
+ return ScriptPromise();
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSink::abort(
+ ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) {
+ track_.Clear();
+ source_.reset();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSink::close(
+ ScriptState* script_state,
+ ExceptionState& exception_state) {
+ track_.Clear();
+ source_.reset();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+void VideoTrackSignalUnderlyingSink::Trace(Visitor* visitor) const {
+ visitor->Trace(track_);
+ UnderlyingSinkBase::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h
new file mode 100644
index 00000000000..6272da1a636
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SINK_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SINK_H_
+
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class MediaStreamTrack;
+class MediaStreamVideoSource;
+
+class MODULES_EXPORT VideoTrackSignalUnderlyingSink
+ : public UnderlyingSinkBase {
+ public:
+ // |source| must outlive this MediaStreamVideoTrackUnderlyingSink.
+ explicit VideoTrackSignalUnderlyingSink(MediaStreamTrack* track);
+
+ // UnderlyingSinkBase overrides.
+ ScriptPromise start(ScriptState* script_state,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override;
+ ScriptPromise write(ScriptState* script_state,
+ ScriptValue chunk,
+ WritableStreamDefaultController* controller,
+ ExceptionState& exception_state) override;
+ ScriptPromise abort(ScriptState* script_state,
+ ScriptValue reason,
+ ExceptionState& exception_state) override;
+ ScriptPromise close(ScriptState* script_state,
+ ExceptionState& exception_state) override;
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ WeakMember<MediaStreamTrack> track_;
+ base::WeakPtr<MediaStreamVideoSource> source_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc
new file mode 100644
index 00000000000..2eb472de7b4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc
@@ -0,0 +1,244 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+
+using testing::_;
+
+namespace blink {
+
+class VideoTrackSignalUnderlyingSinkTest : public testing::Test {
+ public:
+ VideoTrackSignalUnderlyingSinkTest() {
+ mock_video_source_ = new MockMediaStreamVideoSource();
+ media_stream_source_ = MakeGarbageCollected<MediaStreamSource>(
+ "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
+ /*remote=*/false);
+ media_stream_source_->SetPlatformSource(
+ base::WrapUnique(mock_video_source_));
+ web_track_ = MediaStreamVideoTrack::CreateVideoTrack(
+ mock_video_source_, MediaStreamVideoSource::ConstraintsOnceCallback(),
+ true);
+ mock_video_source_->StartMockedSource();
+ }
+
+ ~VideoTrackSignalUnderlyingSinkTest() override {
+ platform_->RunUntilIdle();
+ mock_video_source_->StopSource();
+ base::RunLoop run_loop;
+ platform_->GetIOTaskRunner()->PostTask(FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+ WebHeap::CollectAllGarbageForTesting();
+ }
+
+ MediaStreamTrack* CreateTrack(ExecutionContext* context) const {
+ return MakeGarbageCollected<MediaStreamTrack>(context, web_track_);
+ }
+ VideoTrackSignalUnderlyingSink* CreateUnderlyingSink(
+ MediaStreamTrack* track) {
+ return MakeGarbageCollected<VideoTrackSignalUnderlyingSink>(track);
+ }
+
+ ScriptValue CreateSignalChunk(ScriptState* script_state,
+ const String& signal_name) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType(signal_name);
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+ }
+
+ ScriptValue CreateRequestFrameChunk(ScriptState* script_state) {
+ return CreateSignalChunk(script_state, "request-frame");
+ }
+
+ ScriptValue CreateSetMinFrameRateChunk(
+ ScriptState* script_state,
+ const base::Optional<double>& frame_rate = 10.0) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ if (frame_rate)
+ signal->setFrameRate(*frame_rate);
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+ }
+
+ protected:
+ Persistent<MediaStreamSource> media_stream_source_;
+ WebMediaStreamTrack web_track_;
+ MockMediaStreamVideoSource* mock_video_source_;
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+};
+
+TEST_F(VideoTrackSignalUnderlyingSinkTest,
+ WriteRequestFrameToStreamForwardsToVideoSource) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* track = CreateTrack(v8_scope.GetExecutionContext());
+ auto* underlying_sink = CreateUnderlyingSink(track);
+ auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_sink, 1u);
+
+ NonThrowableExceptionState exception_state;
+ auto* writer = writable_stream->getWriter(script_state, exception_state);
+
+ auto request_frame_chunk = CreateRequestFrameChunk(script_state);
+ EXPECT_CALL(*mock_video_source_, OnRequestRefreshFrame());
+ ScriptPromiseTester write_tester(
+ script_state,
+ writer->write(script_state, request_frame_chunk, exception_state));
+ write_tester.WaitUntilSettled();
+
+ const double frame_rate = 14.8;
+ auto set_min_frame_rate_chunk =
+ CreateSetMinFrameRateChunk(script_state, frame_rate);
+ MediaStreamVideoTrack* video_track =
+ MediaStreamVideoTrack::From(track->Component());
+ EXPECT_FALSE(video_track->min_frame_rate().has_value());
+ ScriptPromiseTester write_tester2(
+ script_state,
+ writer->write(script_state, set_min_frame_rate_chunk, exception_state));
+ write_tester2.WaitUntilSettled();
+ EXPECT_TRUE(video_track->min_frame_rate().has_value());
+ EXPECT_EQ(video_track->min_frame_rate().value(), frame_rate);
+
+ writer->releaseLock(script_state);
+ ScriptPromiseTester close_tester(
+ script_state, writable_stream->close(script_state, exception_state));
+ close_tester.WaitUntilSettled();
+
+ MediaStreamTrack* clone = track->clone(script_state);
+ track->stopTrack(v8_scope.GetExecutionContext());
+
+ // Writing to the sink after the track closes should fail, even if the source
+ // is active.
+ EXPECT_TRUE(mock_video_source_->IsRunning());
+ DummyExceptionStateForTesting dummy_exception_state;
+ underlying_sink->write(script_state, CreateRequestFrameChunk(script_state),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+
+ clone->stopTrack(v8_scope.GetExecutionContext());
+ EXPECT_FALSE(mock_video_source_->IsRunning());
+ // Writing to the sink after the source closes should fail.
+ dummy_exception_state.ClearException();
+ underlying_sink->write(script_state, CreateRequestFrameChunk(script_state),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+}
+
+TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteInvalidDataFails) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* track = CreateTrack(v8_scope.GetExecutionContext());
+ auto* underlying_sink = CreateUnderlyingSink(track);
+
+ MediaStreamVideoTrack* video_track =
+ MediaStreamVideoTrack::From(track->Component());
+ EXPECT_FALSE(video_track->min_frame_rate().has_value());
+
+ DummyExceptionStateForTesting exception_state;
+ auto set_min_frame_rate_chunk =
+ CreateSetMinFrameRateChunk(script_state, base::nullopt);
+ underlying_sink->write(script_state, set_min_frame_rate_chunk, nullptr,
+ exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+ EXPECT_FALSE(video_track->min_frame_rate().has_value());
+
+ exception_state.ClearException();
+ EXPECT_FALSE(exception_state.HadException());
+ underlying_sink->write(script_state,
+ CreateSignalChunk(script_state, "invalid-signal"),
+ nullptr, exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+
+ // Writing null fails
+ exception_state.ClearException();
+ EXPECT_FALSE(exception_state.HadException());
+ underlying_sink->write(script_state,
+ ScriptValue::CreateNull(v8_scope.GetIsolate()),
+ nullptr, exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+
+ // Writing an intenger fails
+ exception_state.ClearException();
+ EXPECT_FALSE(exception_state.HadException());
+ underlying_sink->write(script_state, ScriptValue::From(script_state, 5),
+ nullptr, exception_state);
+ EXPECT_TRUE(exception_state.HadException());
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+}
+
+TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteToClosedSinkFails) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* track = CreateTrack(v8_scope.GetExecutionContext());
+ auto* underlying_sink = CreateUnderlyingSink(track);
+
+ auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_sink, 1u);
+
+ NonThrowableExceptionState exception_state;
+ ScriptPromiseTester abort_tester(
+ script_state, writable_stream->close(script_state, exception_state));
+ abort_tester.WaitUntilSettled();
+
+ // Writing to the sink after the stream closes should fail.
+ DummyExceptionStateForTesting dummy_exception_state;
+ underlying_sink->write(script_state, CreateRequestFrameChunk(script_state),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+}
+
+TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteToAbortedSinkFails) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ auto* track = CreateTrack(v8_scope.GetExecutionContext());
+ auto* underlying_sink = CreateUnderlyingSink(track);
+
+ auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy(
+ script_state, underlying_sink, 1u);
+
+ NonThrowableExceptionState exception_state;
+ ScriptPromiseTester abort_tester(
+ script_state, writable_stream->abort(script_state, exception_state));
+ abort_tester.WaitUntilSettled();
+
+ // Writing to the sink after the stream aborts should fail.
+ DummyExceptionStateForTesting dummy_exception_state;
+ underlying_sink->write(script_state, CreateRequestFrameChunk(script_state),
+ nullptr, dummy_exception_state);
+ EXPECT_TRUE(dummy_exception_state.HadException());
+ EXPECT_EQ(dummy_exception_state.Code(),
+ static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError));
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.cc
new file mode 100644
index 00000000000..cb43b6f91c8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.cc
@@ -0,0 +1,162 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.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/streams/readable_stream_default_controller_with_script_scope.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.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/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/webrtc/api/frame_transformer_interface.h"
+
+namespace blink {
+
+VideoTrackSignalUnderlyingSource::VideoTrackSignalUnderlyingSource(
+ ScriptState* script_state,
+ MediaStreamTrackGenerator* generator,
+ wtf_size_t max_queue_size)
+ : UnderlyingSourceBase(script_state),
+ main_task_runner_(ExecutionContext::From(script_state)
+ ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
+ generator_(generator),
+ max_queue_size_(std::max(1u, max_queue_size)) {
+ DCHECK(generator_);
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSource::pull(
+ ScriptState* script_state) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (!queue_.empty()) {
+ PullFromQueue();
+ } else {
+ is_pending_pull_ = true;
+ }
+
+ DCHECK_LT(queue_.size(), max_queue_size_);
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSource::Start(
+ ScriptState* script_state) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ auto* video_track = MediaStreamVideoTrack::From(generator_->Component());
+ if (!video_track) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state,
+ DOMException::Create(
+ "No input track",
+ DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError)));
+ }
+ video_track->SetSignalObserver(this);
+
+ auto* video_source = generator_->PushableVideoSource();
+ video_source->SetSignalObserver(this);
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+ScriptPromise VideoTrackSignalUnderlyingSource::Cancel(
+ ScriptState* script_state,
+ ScriptValue reason) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ Stop();
+ return ScriptPromise::CastUndefined(script_state);
+}
+
+void VideoTrackSignalUnderlyingSource::Trace(Visitor* visitor) const {
+ visitor->Trace(generator_);
+ visitor->Trace(queue_);
+ UnderlyingSourceBase::Trace(visitor);
+}
+
+double VideoTrackSignalUnderlyingSource::DesiredSizeForTesting() const {
+ return Controller()->DesiredSize();
+}
+
+void VideoTrackSignalUnderlyingSource::ContextDestroyed() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ UnderlyingSourceBase::ContextDestroyed();
+ Stop();
+}
+
+void VideoTrackSignalUnderlyingSource::Close() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ Stop();
+ if (Controller())
+ Controller()->Close();
+}
+
+void VideoTrackSignalUnderlyingSource::SetMinimumFrameRate(double frame_rate) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ signal->setFrameRate(frame_rate);
+ ProcessNewSignal(signal);
+}
+
+void VideoTrackSignalUnderlyingSource::RequestFrame() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("request-frame");
+ ProcessNewSignal(signal);
+}
+
+void VideoTrackSignalUnderlyingSource::ProcessNewSignal(
+ MediaStreamTrackSignal* signal) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ DCHECK_LE(queue_.size(), max_queue_size_);
+ if (!is_active_)
+ return;
+
+ // If the |queue_| is empty and the consumer has signaled a pull, bypass
+ // |queue_| and send the frame directly to the stream controller.
+ if (queue_.empty() && is_pending_pull_) {
+ SendSignalToStream(signal);
+ return;
+ }
+
+ if (queue_.size() == max_queue_size_)
+ queue_.pop_front();
+
+ queue_.push_back(signal);
+ if (is_pending_pull_) {
+ PullFromQueue();
+ }
+}
+
+void VideoTrackSignalUnderlyingSource::PullFromQueue() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ DCHECK(!queue_.empty());
+ DCHECK(is_active_);
+ SendSignalToStream(std::move(queue_.front()));
+ queue_.pop_front();
+}
+
+void VideoTrackSignalUnderlyingSource::SendSignalToStream(
+ MediaStreamTrackSignal* signal) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ DCHECK(signal);
+ DCHECK(is_active_);
+ if (!Controller())
+ return;
+
+ Controller()->Enqueue(signal);
+ is_pending_pull_ = false;
+}
+
+void VideoTrackSignalUnderlyingSource::Stop() {
+ is_active_ = false;
+ queue_.clear();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h
new file mode 100644
index 00000000000..8cf0b97f9dd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h
@@ -0,0 +1,80 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SOURCE_H_
+
+#include "base/threading/thread_checker.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_signal_observer.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+
+namespace blink {
+
+class MediaStreamTrackSignal;
+class MediaStreamTrackGenerator;
+
+// This class serves as the source for the control signals sent to
+// a MediaStreamTrackGenerator and exposed on its readableControl field.
+// This class maintains an internal circular queue to store unconsumed
+// signals. If the queue becomes full and new signals are produced,
+// older signals are dropped to accommodate the new signals.
+class MODULES_EXPORT VideoTrackSignalUnderlyingSource
+ : public UnderlyingSourceBase,
+ public MediaStreamVideoTrackSignalObserver {
+ public:
+ explicit VideoTrackSignalUnderlyingSource(ScriptState*,
+ MediaStreamTrackGenerator*,
+ wtf_size_t queue_size);
+ VideoTrackSignalUnderlyingSource(const VideoTrackSignalUnderlyingSource&) =
+ delete;
+ VideoTrackSignalUnderlyingSource& operator=(
+ const VideoTrackSignalUnderlyingSource&) = delete;
+
+ // UnderlyingSourceBase
+ ScriptPromise pull(ScriptState*) override;
+ ScriptPromise Start(ScriptState*) override;
+ ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
+
+ // ExecutionLifecycleObserver
+ void ContextDestroyed() override;
+
+ MediaStreamTrackGenerator* Generator() const { return generator_.Get(); }
+ wtf_size_t MaxQueueSize() const { return max_queue_size_; }
+
+ bool IsPendingPullForTesting() const { return is_pending_pull_; }
+ const HeapDeque<Member<MediaStreamTrackSignal>>& QueueForTesting() const {
+ return queue_;
+ }
+ double DesiredSizeForTesting() const;
+
+ void Close();
+ void Trace(Visitor*) const override;
+
+ private:
+ // MediaStreamVideoTrackSignalObserver
+ void SetMinimumFrameRate(double) override;
+ void RequestFrame() override;
+
+ void ProcessNewSignal(MediaStreamTrackSignal*);
+ void SendSignalToStream(MediaStreamTrackSignal*);
+ void PullFromQueue();
+ void Stop();
+
+ const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ Member<MediaStreamTrackGenerator> generator_;
+
+ // An internal deque prior to the stream controller's queue. It acts as a ring
+ // buffer and allows dropping old signals instead of new ones in case signals
+ // accumulate due to slow consumption.
+ HeapDeque<Member<MediaStreamTrackSignal>> queue_;
+ const wtf_size_t max_queue_size_;
+ bool is_pending_pull_ = false;
+ bool is_active_ = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_VIDEO_TRACK_SIGNAL_UNDERLYING_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source_test.cc
new file mode 100644
index 00000000000..c3138ee02b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source_test.cc
@@ -0,0 +1,191 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_source.h"
+
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
+#include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.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/modules/mediastream/media_stream_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/stream_test_utils.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+using testing::_;
+
+namespace blink {
+
+class VideoTrackSignalUnderlyingSourceTest : public testing::Test {
+ public:
+ ~VideoTrackSignalUnderlyingSourceTest() override {
+ platform_->RunUntilIdle();
+ WebHeap::CollectAllGarbageForTesting();
+ }
+
+ MediaStreamTrackGenerator* CreateGenerator(ScriptState* script_state) {
+ return MakeGarbageCollected<MediaStreamTrackGenerator>(
+ script_state, MediaStreamSource::kTypeVideo, "test-generator",
+ /*signal_target=*/nullptr, /*max_signal_buffer_size=*/10u);
+ }
+
+ VideoTrackSignalUnderlyingSource* CreateSource(
+ ScriptState* script_state,
+ MediaStreamTrackGenerator* generator,
+ wtf_size_t max_buffer_size) {
+ return MakeGarbageCollected<VideoTrackSignalUnderlyingSource>(
+ script_state, generator, max_buffer_size);
+ }
+
+ VideoTrackSignalUnderlyingSource* CreateSource(
+ ScriptState* script_state,
+ MediaStreamTrackGenerator* generator) {
+ return CreateSource(script_state, generator, 1u);
+ }
+
+ protected:
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
+};
+
+TEST_F(VideoTrackSignalUnderlyingSourceTest, SignalsAreExposed) {
+ V8TestingScope v8_scope;
+ auto* script_state = v8_scope.GetScriptState();
+ auto* generator = CreateGenerator(script_state);
+ auto* video_track = MediaStreamVideoTrack::From(generator->Component());
+ auto* video_source = generator->PushableVideoSource();
+ auto* source = CreateSource(script_state, generator);
+ auto* stream =
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+ auto* reader =
+ stream->GetDefaultReaderForTesting(script_state, ASSERT_NO_EXCEPTION);
+
+ video_source->RequestRefreshFrame();
+ auto* signal = ReadObjectFromStream<MediaStreamTrackSignal>(v8_scope, reader);
+ EXPECT_EQ(signal->signalType(), "request-frame");
+
+ const double min_frame_rate = 3.5;
+ video_track->SetMinimumFrameRate(min_frame_rate);
+ signal = ReadObjectFromStream<MediaStreamTrackSignal>(v8_scope, reader);
+ EXPECT_EQ(signal->signalType(), "set-min-frame-rate");
+ EXPECT_TRUE(signal->hasFrameRate());
+ EXPECT_EQ(signal->frameRate(), min_frame_rate);
+
+ source->Close();
+}
+
+TEST_F(VideoTrackSignalUnderlyingSourceTest, CancelStreamDisconnectsFromTrack) {
+ V8TestingScope v8_scope;
+ auto* script_state = v8_scope.GetScriptState();
+ auto* generator = CreateGenerator(script_state);
+ auto* source = CreateSource(script_state, generator);
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+ auto& queue = source->QueueForTesting();
+
+ generator->PushableVideoSource()->RequestRefreshFrame();
+ EXPECT_EQ(queue.size(), 1u);
+
+ source->Cancel(script_state, ScriptValue());
+ EXPECT_EQ(queue.size(), 0u);
+
+ generator->PushableVideoSource()->RequestRefreshFrame();
+ EXPECT_EQ(queue.size(), 0u);
+
+ source->Close();
+}
+
+TEST_F(VideoTrackSignalUnderlyingSourceTest, DropOldSignalsWhenQueueIsFull) {
+ V8TestingScope v8_scope;
+ auto* script_state = v8_scope.GetScriptState();
+ auto* generator = CreateGenerator(script_state);
+ auto* video_track = MediaStreamVideoTrack::From(generator->Component());
+ const wtf_size_t buffer_size = 3;
+ auto* source = CreateSource(script_state, generator, buffer_size);
+ EXPECT_EQ(source->MaxQueueSize(), buffer_size);
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ const auto& queue = source->QueueForTesting();
+ for (wtf_size_t i = 0; i < buffer_size; ++i) {
+ EXPECT_EQ(queue.size(), i);
+ video_track->SetMinimumFrameRate(i);
+ EXPECT_EQ(queue.back()->frameRate(), i);
+ EXPECT_EQ(queue.front()->frameRate(), 0.0);
+ }
+
+ // Push another signal while the queue is full.
+ EXPECT_EQ(queue.size(), buffer_size);
+ video_track->SetMinimumFrameRate(buffer_size);
+
+ // Since the queue was full, the oldest signal from the queue should have been
+ // dropped.
+ EXPECT_EQ(queue.size(), buffer_size);
+ EXPECT_EQ(queue.back()->frameRate(), buffer_size);
+ EXPECT_EQ(queue.front()->frameRate(), 1.0);
+
+ // Pulling with signals in the queue should move the oldest signal in the
+ // queue to the stream's controller.
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ source->pull(script_state);
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+ EXPECT_EQ(queue.size(), buffer_size - 1);
+ EXPECT_EQ(queue.front()->frameRate(), 2);
+
+ source->Close();
+ EXPECT_EQ(queue.size(), 0u);
+}
+
+TEST_F(VideoTrackSignalUnderlyingSourceTest,
+ BypassQueueAfterPullWithEmptyBuffer) {
+ V8TestingScope v8_scope;
+ auto* script_state = v8_scope.GetScriptState();
+ auto* generator = CreateGenerator(script_state);
+ auto* source = CreateSource(script_state, generator);
+ ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
+
+ // At first, the queue is empty and the desired size is empty as well.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+
+ source->pull(script_state);
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), 0);
+ EXPECT_TRUE(source->IsPendingPullForTesting());
+
+ generator->PushableVideoSource()->RequestRefreshFrame();
+ // Since a pull was pending, the signal is put directly in the stream
+ // controller, bypassing the source queue.
+ EXPECT_TRUE(source->QueueForTesting().empty());
+ EXPECT_EQ(source->DesiredSizeForTesting(), -1);
+ EXPECT_FALSE(source->IsPendingPullForTesting());
+
+ source->Close();
+}
+
+TEST_F(VideoTrackSignalUnderlyingSourceTest, QueueSizeCannotBeZero) {
+ V8TestingScope v8_scope;
+ auto* script_state = v8_scope.GetScriptState();
+ auto* generator = CreateGenerator(script_state);
+ auto* source = CreateSource(script_state, generator, /*max_buffer_size=*/0u);
+
+ // Queue size is always at least 1, even if 0 is requested.
+ EXPECT_EQ(source->MaxQueueSize(), 1u);
+ source->Close();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc b/chromium/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc
index 74bfc6a4b14..c48ee7349d3 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc
@@ -85,8 +85,9 @@ void WebAudioMediaStreamAudioSink::OnData(
base::TimeTicks estimated_capture_time) {
NON_REENTRANT_SCOPE(capture_reentrancy_checker_);
DCHECK(!estimated_capture_time.is_null());
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
- "WebAudioMediaStreamAudioSink::OnData");
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "WebAudioMediaStreamAudioSink::OnData", "this",
+ static_cast<void*>(this), "frames", audio_bus.frames());
base::AutoLock auto_lock(lock_);
if (!is_enabled_)
@@ -121,8 +122,9 @@ void WebAudioMediaStreamAudioSink::ProvideInput(
NON_REENTRANT_SCOPE(provide_input_reentrancy_checker_);
DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
- "WebAudioMediaStreamAudioSink::ProvideInput");
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "WebAudioMediaStreamAudioSink::ProvideInput", "this",
+ static_cast<void*>(this), "frames", number_of_frames);
if (!output_wrapper_ ||
static_cast<size_t>(output_wrapper_->channels()) != audio_data.size()) {
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 a01e1684828..61fa0df65f0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
@@ -22,19 +22,22 @@
#include "media/base/video_frame.h"
#include "media/base/video_transformation.h"
#include "media/base/video_types.h"
+#include "media/mojo/mojom/media_metrics_provider.mojom.h"
#include "media/video/gpu_memory_buffer_video_frame_pool.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_renderer.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_video_renderer.h"
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_media_player_client.h"
#include "third_party/blink/public/platform/web_media_player_source.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
#include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_renderer_factory.h"
#include "third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h"
@@ -253,9 +256,9 @@ class WebMediaPlayerMS::FrameDeliverer {
bool tracing_enabled = false;
TRACE_EVENT_CATEGORY_GROUP_ENABLED("media", &tracing_enabled);
if (tracing_enabled) {
- if (frame->metadata()->reference_time.has_value()) {
+ if (frame->metadata().reference_time.has_value()) {
TRACE_EVENT1("media", "EnqueueFrame", "Ideal Render Instant",
- frame->metadata()->reference_time->ToInternalValue());
+ frame->metadata().reference_time->ToInternalValue());
} else {
TRACE_EVENT0("media", "EnqueueFrame");
}
@@ -397,6 +400,9 @@ WebMediaPlayerMS::~WebMediaPlayerMS() {
void WebMediaPlayerMS::OnAudioRenderErrorCallback() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (watch_time_reporter_)
+ watch_time_reporter_->OnError(media::AUDIO_RENDERER_ERROR);
+
if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
// Any error that occurs before reaching ReadyStateHaveMetadata should
// be considered a format error.
@@ -409,7 +415,8 @@ void WebMediaPlayerMS::OnAudioRenderErrorCallback() {
WebMediaPlayer::LoadTiming WebMediaPlayerMS::Load(
LoadType load_type,
const WebMediaPlayerSource& source,
- CorsMode /*cors_mode*/) {
+ CorsMode /*cors_mode*/,
+ bool is_cache_disabled) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
SendLogMessage(String::Format("%s({load_type=%s})", __func__,
LoadTypeToString(load_type)));
@@ -421,6 +428,8 @@ WebMediaPlayer::LoadTiming WebMediaPlayerMS::Load(
if (!web_stream_.IsNull())
web_stream_.AddObserver(this);
+ watch_time_reporter_.reset();
+
compositor_ = base::MakeRefCounted<WebMediaPlayerMSCompositor>(
compositor_task_runner_, io_task_runner_, web_stream_,
std::move(submitter_), surface_layer_mode_, weak_this_);
@@ -453,7 +462,7 @@ WebMediaPlayer::LoadTiming WebMediaPlayerMS::Load(
if (internal_frame_->web_frame()) {
WebURL url = source.GetAsURL();
- // Report UMA and RAPPOR metrics.
+ // Report UMA metrics.
ReportMetrics(load_type, url, *internal_frame_->web_frame(),
media_log_.get());
}
@@ -530,6 +539,7 @@ WebMediaPlayer::LoadTiming WebMediaPlayerMS::Load(
SendLogMessage(String::Format("%s => (audio only mode)", __func__));
SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
+ MaybeCreateWatchTimeReporter();
}
return WebMediaPlayer::LoadTiming::kImmediate;
@@ -659,12 +669,17 @@ void WebMediaPlayerMS::ReloadVideo() {
}
DCHECK_NE(renderer_action, RendererReloadAction::KEEP_RENDERER);
- if (!paused_)
- delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
+ if (!paused_) {
+ client_->DidPlayerSizeChange(NaturalSize());
+ if (watch_time_reporter_)
+ UpdateWatchTimeReporterSecondaryProperties();
+ }
// TODO(perkj, magjed): We use OneShot focus type here so that it takes
// audio focus once it starts, and then will not respond to further audio
// focus changes. See https://crbug.com/596516 for more details.
+ client_->DidMediaMetadataChange(HasAudio(), HasVideo(),
+ media::MediaContentType::OneShot);
delegate_->DidMediaMetadataChange(delegate_id_, HasAudio(), HasVideo(),
media::MediaContentType::OneShot);
}
@@ -723,6 +738,8 @@ void WebMediaPlayerMS::ReloadAudio() {
// TODO(perkj, magjed): We use OneShot focus type here so that it takes
// audio focus once it starts, and then will not respond to further audio
// focus changes. See https://crbug.com/596516 for more details.
+ client_->DidMediaMetadataChange(HasAudio(), HasVideo(),
+ media::MediaContentType::OneShot);
delegate_->DidMediaMetadataChange(delegate_id_, HasAudio(), HasVideo(),
media::MediaContentType::OneShot);
}
@@ -743,9 +760,18 @@ void WebMediaPlayerMS::Play() {
if (audio_renderer_)
audio_renderer_->Play();
- if (HasVideo())
- delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
+ if (watch_time_reporter_) {
+ watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
+ watch_time_reporter_->OnPlaying();
+ }
+
+ if (HasVideo()) {
+ client_->DidPlayerSizeChange(NaturalSize());
+ if (watch_time_reporter_)
+ UpdateWatchTimeReporterSecondaryProperties();
+ }
+ client_->DidPlayerStartPlaying();
delegate_->DidPlay(delegate_id_);
delegate_->SetIdle(delegate_id_, false);
@@ -770,6 +796,10 @@ void WebMediaPlayerMS::Pause() {
if (audio_renderer_)
audio_renderer_->Pause();
+ client_->DidPlayerPaused(/* stream_ended = */ false);
+ if (watch_time_reporter_)
+ watch_time_reporter_->OnPaused();
+
delegate_->DidPause(delegate_id_, /* reached_end_of_stream = */ false);
delegate_->SetIdle(delegate_id_, true);
@@ -790,7 +820,9 @@ void WebMediaPlayerMS::SetVolume(double volume) {
volume_ = volume;
if (audio_renderer_.get())
audio_renderer_->SetVolume(volume_ * volume_multiplier_);
- delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
+ if (watch_time_reporter_)
+ watch_time_reporter_->OnVolumeChange(volume);
+ client_->DidPlayerMutedStatusChange(volume == 0.0);
}
void WebMediaPlayerMS::SetLatencyHint(double seconds) {
@@ -806,6 +838,8 @@ void WebMediaPlayerMS::SetPreservesPitch(bool preserves_pitch) {
// and thus there should be no pitch-shifting.
}
+void WebMediaPlayerMS::SetAutoplayInitiated(bool autoplay_initiated) {}
+
void WebMediaPlayerMS::OnRequestPictureInPicture() {
if (!bridge_)
ActivateSurfaceLayerForVideo();
@@ -814,31 +848,28 @@ void WebMediaPlayerMS::OnRequestPictureInPicture() {
DCHECK(bridge_->GetSurfaceId().is_valid());
}
-void WebMediaPlayerMS::OnPictureInPictureAvailabilityChanged(bool available) {
- delegate_->DidPictureInPictureAvailabilityChange(delegate_id_, available);
-}
-
-void WebMediaPlayerMS::SetSinkId(
+bool WebMediaPlayerMS::SetSinkId(
const WebString& sink_id,
WebSetSinkIdCompleteCallback completion_callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
SendLogMessage(
String::Format("%s({sink_id=%s})", __func__, sink_id.Utf8().c_str()));
+
+ media::OutputDeviceStatusCB callback =
+ ConvertToOutputDeviceStatusCB(std::move(completion_callback));
+
if (!audio_renderer_) {
SendLogMessage(String::Format(
"%s => (WARNING: failed to instantiate audio renderer)", __func__));
- }
- media::OutputDeviceStatusCB callback =
- ConvertToOutputDeviceStatusCB(std::move(completion_callback));
- if (audio_renderer_) {
- auto sink_id_utf8 = sink_id.Utf8();
- audio_renderer_->SwitchOutputDevice(sink_id_utf8, std::move(callback));
- delegate_->DidAudioOutputSinkChange(delegate_id_, sink_id_utf8);
- } else {
std::move(callback).Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
SendLogMessage(String::Format(
"%s => (ERROR: OUTPUT_DEVICE_STATUS_ERROR_INTERNAL)", __func__));
+ return false;
}
+
+ auto sink_id_utf8 = sink_id.Utf8();
+ audio_renderer_->SwitchOutputDevice(sink_id_utf8, std::move(callback));
+ return true;
}
void WebMediaPlayerMS::SetPreload(WebMediaPlayer::Preload preload) {
@@ -947,10 +978,8 @@ bool WebMediaPlayerMS::DidLoadingProgress() {
}
void WebMediaPlayerMS::Paint(cc::PaintCanvas* canvas,
- const WebRect& rect,
- cc::PaintFlags& flags,
- int already_uploaded_id,
- VideoFrameUploadMetadata* out_metadata) {
+ const gfx::Rect& rect,
+ cc::PaintFlags& flags) {
DVLOG(3) << __func__;
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -963,7 +992,7 @@ void WebMediaPlayerMS::Paint(cc::PaintCanvas* canvas,
if (!provider)
return;
}
- const gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
+ const gfx::RectF dest_rect(rect);
video_renderer_.Paint(frame, canvas, dest_rect, flags, video_transformation_,
provider.get());
}
@@ -1011,6 +1040,10 @@ bool WebMediaPlayerMS::HasAvailableVideoFrame() const {
void WebMediaPlayerMS::OnFrameHidden() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (watch_time_reporter_)
+ watch_time_reporter_->OnHidden();
+
// This method is called when the RenderFrame is sent to background or
// suspended. During undoable tab closures OnHidden() may be called back to
// back, so we can't rely on |render_frame_suspended_| being false here.
@@ -1060,6 +1093,9 @@ void WebMediaPlayerMS::OnFrameClosed() {
void WebMediaPlayerMS::OnFrameShown() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (watch_time_reporter_)
+ watch_time_reporter_->OnShown();
+
if (frame_deliverer_) {
PostCrossThreadTask(
*io_task_runner_, FROM_HERE,
@@ -1083,43 +1119,6 @@ void WebMediaPlayerMS::OnFrameShown() {
void WebMediaPlayerMS::OnIdleTimeout() {}
-void WebMediaPlayerMS::OnPlay() {
- // TODO(perkj, magjed): It's not clear how WebRTC should work with an
- // MediaSession, until these issues are resolved, disable session controls.
- // https://crbug.com/595297.
-}
-
-void WebMediaPlayerMS::OnPause() {
- // TODO(perkj, magjed): See TODO in OnPlay().
-}
-
-void WebMediaPlayerMS::OnMuted(bool muted) {
- SendLogMessage(
- String::Format("%s({muted=%s})", __func__, muted ? "true" : "false"));
- client_->RequestMuted(muted);
-}
-
-void WebMediaPlayerMS::OnSeekForward(double seconds) {
- // TODO(perkj, magjed): See TODO in OnPlay().
-}
-
-void WebMediaPlayerMS::OnSeekBackward(double seconds) {
- // TODO(perkj, magjed): See TODO in OnPlay().
-}
-
-void WebMediaPlayerMS::OnEnterPictureInPicture() {
- client_->RequestEnterPictureInPicture();
-}
-
-void WebMediaPlayerMS::OnExitPictureInPicture() {
- client_->RequestExitPictureInPicture();
-}
-
-void WebMediaPlayerMS::OnSetAudioSink(const std::string& sink_id) {
- SetSinkId(WebString::FromASCII(sink_id),
- base::DoNothing::Once<base::Optional<blink::WebSetSinkIdError>>());
-}
-
void WebMediaPlayerMS::OnVolumeMultiplierUpdate(double multiplier) {
// TODO(perkj, magjed): See TODO in OnPlay().
}
@@ -1128,108 +1127,6 @@ void WebMediaPlayerMS::OnBecamePersistentVideo(bool value) {
get_client()->OnBecamePersistentVideo(value);
}
-bool WebMediaPlayerMS::CopyVideoTextureToPlatformTexture(
- gpu::gles2::GLES2Interface* gl,
- unsigned target,
- unsigned int texture,
- unsigned internal_format,
- unsigned format,
- unsigned type,
- int level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- VideoFrameUploadMetadata* out_metadata) {
- TRACE_EVENT0("media", "copyVideoTextureToPlatformTexture");
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- scoped_refptr<media::VideoFrame> video_frame = compositor_->GetCurrentFrame();
-
- if (!video_frame.get() || !video_frame->HasTextures())
- return false;
-
- auto provider = Platform::Current()->SharedMainThreadContextProvider();
- // GPU Process crashed.
- if (!provider)
- return false;
-
- return video_renderer_.CopyVideoFrameTexturesToGLTexture(
- provider.get(), gl, video_frame.get(), target, texture, internal_format,
- format, type, level, premultiply_alpha, flip_y);
-}
-
-bool WebMediaPlayerMS::CopyVideoYUVDataToPlatformTexture(
- gpu::gles2::GLES2Interface* gl,
- unsigned target,
- unsigned int texture,
- unsigned internal_format,
- unsigned format,
- unsigned type,
- int level,
- bool premultiply_alpha,
- bool flip_y,
- int already_uploaded_id,
- VideoFrameUploadMetadata* out_metadata) {
- TRACE_EVENT0("media", "copyVideoYUVDataToPlatformTexture");
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- scoped_refptr<media::VideoFrame> video_frame = compositor_->GetCurrentFrame();
-
- if (!video_frame)
- return false;
- if (video_frame->HasTextures())
- return false;
-
- auto provider = Platform::Current()->SharedMainThreadContextProvider();
- // GPU Process crashed.
- if (!provider)
- return false;
-
- return video_renderer_.CopyVideoFrameYUVDataToGLTexture(
- provider.get(), gl, *video_frame, target, texture, internal_format,
- format, type, level, premultiply_alpha, flip_y);
-}
-
-bool WebMediaPlayerMS::TexImageImpl(TexImageFunctionID functionID,
- unsigned target,
- gpu::gles2::GLES2Interface* gl,
- unsigned int texture,
- int level,
- int internalformat,
- unsigned format,
- unsigned type,
- int xoffset,
- int yoffset,
- int zoffset,
- bool flip_y,
- bool premultiply_alpha) {
- TRACE_EVENT0("media", "texImageImpl");
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- const scoped_refptr<media::VideoFrame> video_frame =
- compositor_->GetCurrentFrame();
- if (!video_frame || !video_frame->IsMappable() ||
- video_frame->HasTextures() ||
- video_frame->format() != media::PIXEL_FORMAT_Y16) {
- return false;
- }
-
- if (functionID == kTexImage2D) {
- auto provider = Platform::Current()->SharedMainThreadContextProvider();
- // GPU Process crashed.
- if (!provider)
- return false;
- return media::PaintCanvasVideoRenderer::TexImage2D(
- target, texture, gl, provider->ContextCapabilities(), video_frame.get(),
- level, internalformat, format, type, flip_y, premultiply_alpha);
- } else if (functionID == kTexSubImage2D) {
- return media::PaintCanvasVideoRenderer::TexSubImage2D(
- target, gl, video_frame.get(), level, format, type, xoffset, yoffset,
- flip_y, premultiply_alpha);
- }
- return false;
-}
-
void WebMediaPlayerMS::ActivateSurfaceLayerForVideo() {
// Note that we might or might not already be in VideoLayer mode.
DCHECK(!bridge_);
@@ -1280,6 +1177,7 @@ void WebMediaPlayerMS::OnFirstFrameReceived(media::VideoRotation video_rotation,
SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
TriggerResize();
ResetCanvasCache();
+ MaybeCreateWatchTimeReporter();
}
void WebMediaPlayerMS::OnOpacityChanged(bool is_opaque) {
@@ -1356,7 +1254,9 @@ void WebMediaPlayerMS::TriggerResize() {
if (HasVideo())
get_client()->SizeChanged();
- delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
+ client_->DidPlayerSizeChange(NaturalSize());
+ if (watch_time_reporter_)
+ UpdateWatchTimeReporterSecondaryProperties();
}
void WebMediaPlayerMS::SetGpuMemoryBufferVideoForTesting(
@@ -1379,6 +1279,20 @@ void WebMediaPlayerMS::OnDisplayTypeChanged(DisplayType display_type) {
CrossThreadBindOnce(&WebMediaPlayerMSCompositor::SetForceSubmit,
CrossThreadUnretained(compositor_.get()),
display_type == DisplayType::kPictureInPicture));
+
+ if (!watch_time_reporter_)
+ return;
+
+ switch (display_type) {
+ case DisplayType::kInline:
+ watch_time_reporter_->OnDisplayTypeInline();
+ break;
+ case DisplayType::kFullscreen:
+ watch_time_reporter_->OnDisplayTypeFullscreen();
+ break;
+ case DisplayType::kPictureInPicture:
+ watch_time_reporter_->OnDisplayTypePictureInPicture();
+ }
}
void WebMediaPlayerMS::OnNewFramePresentedCallback() {
@@ -1424,4 +1338,183 @@ void WebMediaPlayerMS::StopForceBeginFrames(TimerBase* timer) {
compositor_->SetForceBeginFrames(false);
}
+void WebMediaPlayerMS::MaybeCreateWatchTimeReporter() {
+ if (!internal_frame_->web_frame())
+ return;
+
+ if (!HasAudio() && !HasVideo())
+ return;
+
+ base::Optional<media::mojom::MediaStreamType> media_stream_type =
+ GetMediaStreamType();
+ if (!media_stream_type)
+ return;
+
+ if (watch_time_reporter_)
+ return;
+
+ if (compositor_) {
+ compositor_initial_time_ = compositor_->GetCurrentTime();
+ compositor_last_time_ = compositor_initial_time_;
+ }
+ if (audio_renderer_) {
+ audio_initial_time_ = audio_renderer_->GetCurrentRenderTime();
+ audio_last_time_ = audio_initial_time_;
+ }
+
+ mojo::Remote<media::mojom::MediaMetricsProvider> media_metrics_provider;
+ auto* execution_context =
+ internal_frame_->frame()->DomWindow()->GetExecutionContext();
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ execution_context->GetTaskRunner(TaskType::kMediaElementEvent);
+ execution_context->GetBrowserInterfaceBroker().GetInterface(
+ media_metrics_provider.BindNewPipeAndPassReceiver(task_runner));
+ media_metrics_provider->Initialize(false /* is_mse */,
+ media::mojom::MediaURLScheme::kMissing,
+ *media_stream_type);
+
+ // Create the watch time reporter and synchronize its initial state.
+ // WTF::Unretained() is safe because WebMediaPlayerMS owns the
+ // |watch_time_reporter_|, and therefore outlives it.
+ watch_time_reporter_ = std::make_unique<WatchTimeReporter>(
+ media::mojom::PlaybackProperties::New(
+ HasAudio(), HasVideo(), false /*is_background*/, false /*is_muted*/,
+ false /*is_mse*/, false /*is_eme*/,
+ false /*is_embedded_media_experience*/, *media_stream_type),
+ NaturalSize(),
+ WTF::BindRepeating(&WebMediaPlayerMS::GetCurrentTimeInterval,
+ WTF::Unretained(this)),
+ WTF::BindRepeating(&WebMediaPlayerMS::GetPipelineStatistics,
+ WTF::Unretained(this)),
+ media_metrics_provider.get(),
+ internal_frame_->web_frame()->GetTaskRunner(
+ blink::TaskType::kInternalMedia));
+
+ watch_time_reporter_->OnVolumeChange(volume_);
+
+ if (delegate_->IsFrameHidden())
+ watch_time_reporter_->OnHidden();
+ else
+ watch_time_reporter_->OnShown();
+
+ if (client_) {
+ if (client_->HasNativeControls())
+ watch_time_reporter_->OnNativeControlsEnabled();
+ else
+ watch_time_reporter_->OnNativeControlsDisabled();
+
+ switch (client_->GetDisplayType()) {
+ case DisplayType::kInline:
+ watch_time_reporter_->OnDisplayTypeInline();
+ break;
+ case DisplayType::kFullscreen:
+ watch_time_reporter_->OnDisplayTypeFullscreen();
+ break;
+ case DisplayType::kPictureInPicture:
+ watch_time_reporter_->OnDisplayTypePictureInPicture();
+ break;
+ }
+ }
+
+ UpdateWatchTimeReporterSecondaryProperties();
+
+ // If the WatchTimeReporter was recreated in the middle of playback, we want
+ // to resume playback here too since we won't get another play() call.
+ if (!paused_)
+ watch_time_reporter_->OnPlaying();
+}
+
+void WebMediaPlayerMS::UpdateWatchTimeReporterSecondaryProperties() {
+ // Set only the natural size and use default values for the other secondary
+ // properties. MediaStreams generally operate with raw data, where there is no
+ // codec information. For the MediaStreams where coded information is
+ // available, the coded information is currently not accessible to the media
+ // player.
+ // TODO(https://crbug.com/1147813) Report codec information once accessible.
+ watch_time_reporter_->UpdateSecondaryProperties(
+ media::mojom::SecondaryPlaybackProperties::New(
+ media::kUnknownAudioCodec, media::kUnknownVideoCodec,
+ media::AudioCodecProfile::kUnknown,
+ media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN,
+ media::AudioDecoderType::kUnknown, media::VideoDecoderType::kUnknown,
+ media::EncryptionScheme::kUnencrypted,
+ media::EncryptionScheme::kUnencrypted, NaturalSize()));
+}
+
+base::TimeDelta WebMediaPlayerMS::GetCurrentTimeInterval() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (compositor_) {
+ compositor_last_time_ =
+ std::max(compositor_last_time_, compositor_->GetCurrentTime());
+ }
+ if (audio_renderer_) {
+ audio_last_time_ =
+ std::max(audio_last_time_, audio_renderer_->GetCurrentRenderTime());
+ }
+
+ base::TimeDelta compositor_interval =
+ compositor_last_time_ - compositor_initial_time_;
+ base::TimeDelta audio_interval = audio_last_time_ - audio_initial_time_;
+ return std::max(compositor_interval, audio_interval);
+}
+
+media::PipelineStatistics WebMediaPlayerMS::GetPipelineStatistics() {
+ media::PipelineStatistics stats;
+ stats.video_frames_decoded = DecodedFrameCount();
+ stats.video_frames_dropped = DroppedFrameCount();
+ return stats;
+}
+
+base::Optional<media::mojom::MediaStreamType>
+WebMediaPlayerMS::GetMediaStreamType() {
+ if (web_stream_.IsNull())
+ return base::nullopt;
+
+ // If either the first video or audio source is remote, the media stream is
+ // of remote source.
+ MediaStreamDescriptor& descriptor = *web_stream_;
+ MediaStreamSource* media_source = nullptr;
+ if (HasVideo()) {
+ auto video_components = descriptor.VideoComponents();
+ DCHECK_GT(video_components.size(), 0U);
+ media_source = video_components[0]->Source();
+ } else if (HasAudio()) {
+ auto audio_components = descriptor.AudioComponents();
+ DCHECK_GT(audio_components.size(), 0U);
+ media_source = audio_components[0]->Source();
+ }
+ if (!media_source)
+ return base::nullopt;
+ if (media_source->Remote())
+ return media::mojom::MediaStreamType::kRemote;
+
+ auto* platform_source = media_source->GetPlatformSource();
+ if (!platform_source)
+ return base::nullopt;
+ switch (platform_source->device().type) {
+ case mojom::blink::MediaStreamType::NO_SERVICE:
+ // Element capture uses the default NO_SERVICE value since it does not set
+ // a device.
+ return media::mojom::MediaStreamType::kLocalElementCapture;
+ case mojom::blink::MediaStreamType::DEVICE_AUDIO_CAPTURE:
+ case mojom::blink::MediaStreamType::DEVICE_VIDEO_CAPTURE:
+ return media::mojom::MediaStreamType::kLocalDeviceCapture;
+ case mojom::blink::MediaStreamType::GUM_TAB_AUDIO_CAPTURE:
+ case mojom::blink::MediaStreamType::GUM_TAB_VIDEO_CAPTURE:
+ return media::mojom::MediaStreamType::kLocalTabCapture;
+ case mojom::blink::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE:
+ case mojom::blink::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE:
+ return media::mojom::MediaStreamType::kLocalDesktopCapture;
+ case mojom::blink::MediaStreamType::DISPLAY_AUDIO_CAPTURE:
+ case mojom::blink::MediaStreamType::DISPLAY_VIDEO_CAPTURE:
+ case mojom::blink::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB:
+ return media::mojom::MediaStreamType::kLocalDisplayCapture;
+ case mojom::blink::MediaStreamType::NUM_MEDIA_TYPES:
+ NOTREACHED();
+ return base::nullopt;
+ }
+
+ return base::nullopt;
+}
+
} // namespace blink
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 f5103764921..b9dd7eb74a4 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
@@ -8,6 +8,7 @@
#include <string>
#include <utility>
+#include "base/bind_post_task.h"
#include "base/hash/hash.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
@@ -56,10 +57,6 @@ scoped_refptr<media::VideoFrame> CopyFrame(
frame->format() == media::PIXEL_FORMAT_XRGB ||
frame->format() == media::PIXEL_FORMAT_I420 ||
frame->format() == media::PIXEL_FORMAT_NV12);
- new_frame = media::VideoFrame::CreateFrame(
- media::PIXEL_FORMAT_I420, frame->coded_size(), frame->visible_rect(),
- frame->natural_size(), frame->timestamp());
-
auto provider = Platform::Current()->SharedMainThreadContextProvider();
if (!provider) {
// Return a black frame (yuv = {0, 0x80, 0x80}).
@@ -75,50 +72,53 @@ scoped_refptr<media::VideoFrame> CopyFrame(
DCHECK(provider->RasterInterface());
video_renderer->Copy(frame.get(), &paint_canvas, provider.get());
- SkPixmap pixmap;
- const bool result = bitmap.peekPixels(&pixmap);
- DCHECK(result) << "Error trying to access SkBitmap's pixels";
-
-#if SK_PMCOLOR_BYTE_ORDER(R, G, B, A)
- const uint32_t source_pixel_format = libyuv::FOURCC_ABGR;
-#else
- const uint32_t source_pixel_format = libyuv::FOURCC_ARGB;
-#endif
- libyuv::ConvertToI420(static_cast<const uint8_t*>(pixmap.addr(0, 0)),
- pixmap.computeByteSize(),
- new_frame->visible_data(media::VideoFrame::kYPlane),
- new_frame->stride(media::VideoFrame::kYPlane),
- new_frame->visible_data(media::VideoFrame::kUPlane),
- new_frame->stride(media::VideoFrame::kUPlane),
- new_frame->visible_data(media::VideoFrame::kVPlane),
- new_frame->stride(media::VideoFrame::kVPlane),
- 0 /* crop_x */, 0 /* crop_y */, pixmap.width(),
- pixmap.height(), new_frame->visible_rect().width(),
- new_frame->visible_rect().height(), libyuv::kRotate0,
- source_pixel_format);
+ bitmap.setImmutable();
+ new_frame =
+ media::CreateFromSkImage(bitmap.asImage(), frame->visible_rect(),
+ frame->natural_size(), frame->timestamp());
+ if (!new_frame) {
+ return media::VideoFrame::CreateColorFrame(
+ frame->visible_rect().size(), 0u, 0x80, 0x80, frame->timestamp());
+ }
} else {
DCHECK(frame->IsMappable());
DCHECK(frame->format() == media::PIXEL_FORMAT_I420A ||
- frame->format() == media::PIXEL_FORMAT_I420);
+ frame->format() == media::PIXEL_FORMAT_I420 ||
+ frame->format() == media::PIXEL_FORMAT_NV12);
const gfx::Size& coded_size = frame->coded_size();
new_frame = media::VideoFrame::CreateFrame(
- media::IsOpaque(frame->format()) ? media::PIXEL_FORMAT_I420
- : media::PIXEL_FORMAT_I420A,
- coded_size, frame->visible_rect(), frame->natural_size(),
- frame->timestamp());
- libyuv::I420Copy(frame->data(media::VideoFrame::kYPlane),
- frame->stride(media::VideoFrame::kYPlane),
- frame->data(media::VideoFrame::kUPlane),
- frame->stride(media::VideoFrame::kUPlane),
- frame->data(media::VideoFrame::kVPlane),
- frame->stride(media::VideoFrame::kVPlane),
- new_frame->data(media::VideoFrame::kYPlane),
- new_frame->stride(media::VideoFrame::kYPlane),
- new_frame->data(media::VideoFrame::kUPlane),
- new_frame->stride(media::VideoFrame::kUPlane),
- new_frame->data(media::VideoFrame::kVPlane),
- new_frame->stride(media::VideoFrame::kVPlane),
- coded_size.width(), coded_size.height());
+ frame->format(), coded_size, frame->visible_rect(),
+ frame->natural_size(), frame->timestamp());
+ if (!new_frame) {
+ return media::VideoFrame::CreateColorFrame(
+ frame->visible_rect().size(), 0u, 0x80, 0x80, frame->timestamp());
+ }
+
+ if (frame->format() == media::PIXEL_FORMAT_NV12) {
+ libyuv::NV12Copy(frame->data(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kYPlane),
+ frame->data(media::VideoFrame::kUVPlane),
+ frame->stride(media::VideoFrame::kUVPlane),
+ new_frame->data(media::VideoFrame::kYPlane),
+ new_frame->stride(media::VideoFrame::kYPlane),
+ new_frame->data(media::VideoFrame::kUVPlane),
+ new_frame->stride(media::VideoFrame::kUVPlane),
+ coded_size.width(), coded_size.height());
+ } else {
+ libyuv::I420Copy(frame->data(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kYPlane),
+ frame->data(media::VideoFrame::kUPlane),
+ frame->stride(media::VideoFrame::kUPlane),
+ frame->data(media::VideoFrame::kVPlane),
+ frame->stride(media::VideoFrame::kVPlane),
+ new_frame->data(media::VideoFrame::kYPlane),
+ new_frame->stride(media::VideoFrame::kYPlane),
+ new_frame->data(media::VideoFrame::kUPlane),
+ new_frame->stride(media::VideoFrame::kUPlane),
+ new_frame->data(media::VideoFrame::kVPlane),
+ new_frame->stride(media::VideoFrame::kVPlane),
+ coded_size.width(), coded_size.height());
+ }
if (frame->format() == media::PIXEL_FORMAT_I420A) {
libyuv::CopyPlane(frame->data(media::VideoFrame::kAPlane),
frame->stride(media::VideoFrame::kAPlane),
@@ -129,7 +129,7 @@ scoped_refptr<media::VideoFrame> CopyFrame(
}
// Transfer metadata keys.
- new_frame->metadata()->MergeMetadataFrom(frame->metadata());
+ new_frame->metadata().MergeMetadataFrom(frame->metadata());
return new_frame;
}
@@ -171,7 +171,7 @@ WebMediaPlayerMSCompositor::WebMediaPlayerMSCompositor(
*video_frame_compositor_task_runner_, FROM_HERE,
CrossThreadBindOnce(&WebMediaPlayerMSCompositor::InitializeSubmitter,
weak_ptr_factory_.GetWeakPtr()));
- update_submission_state_callback_ = media::BindToLoop(
+ update_submission_state_callback_ = base::BindPostTask(
video_frame_compositor_task_runner_,
ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
&WebMediaPlayerMSCompositor::SetIsSurfaceVisible,
@@ -346,7 +346,7 @@ void WebMediaPlayerMSCompositor::EnqueueFrame(
}
// This is a signal frame saying that the stream is stopped.
- if (frame->metadata()->end_of_stream) {
+ if (frame->metadata().end_of_stream) {
rendering_frame_buffer_.reset();
RenderWithoutAlgorithm(std::move(frame), is_copy);
return;
@@ -360,8 +360,8 @@ void WebMediaPlayerMSCompositor::EnqueueFrame(
// note that this is an experimental feature that is only active if certain
// experimental parameters are specified in WebRTC. See crbug.com/1138888 for
// more information.
- if (!frame->metadata()->reference_time.has_value() &&
- !frame->metadata()->maximum_composition_delay_in_frames) {
+ if (!frame->metadata().reference_time.has_value() &&
+ !frame->metadata().maximum_composition_delay_in_frames) {
DLOG(WARNING)
<< "Incoming VideoFrames have no reference_time, switching off super "
"sophisticated rendering algorithm";
@@ -369,8 +369,8 @@ void WebMediaPlayerMSCompositor::EnqueueFrame(
RenderWithoutAlgorithm(std::move(frame), is_copy);
return;
}
- base::TimeTicks render_time = frame->metadata()->reference_time
- ? *frame->metadata()->reference_time
+ base::TimeTicks render_time = frame->metadata().reference_time
+ ? *frame->metadata().reference_time
: base::TimeTicks();
// The code below handles the case where UpdateCurrentFrame() callbacks stop.
@@ -419,9 +419,8 @@ bool WebMediaPlayerMSCompositor::UpdateCurrentFrame(
#endif // DCHECK_IS_ON()
if (tracing_or_dcheck_enabled) {
base::TimeTicks render_time =
- current_frame_->metadata()->reference_time.value_or(
- base::TimeTicks());
- DCHECK(current_frame_->metadata()->reference_time.has_value() ||
+ current_frame_->metadata().reference_time.value_or(base::TimeTicks());
+ DCHECK(current_frame_->metadata().reference_time.has_value() ||
!rendering_frame_buffer_ ||
(rendering_frame_buffer_ &&
!rendering_frame_buffer_->NeedsReferenceTime()))
@@ -610,8 +609,9 @@ void WebMediaPlayerMSCompositor::SetCurrentFrame(
bool is_first_frame = true;
bool has_frame_size_changed = false;
- base::Optional<media::VideoRotation> new_rotation =
- frame->metadata()->rotation.value_or(media::VIDEO_ROTATION_0);
+ base::Optional<media::VideoRotation> new_rotation = media::VIDEO_ROTATION_0;
+ if (frame->metadata().transformation)
+ new_rotation = frame->metadata().transformation->rotation;
base::Optional<bool> new_opacity;
new_opacity = media::IsOpaque(frame->format());
@@ -620,17 +620,19 @@ void WebMediaPlayerMSCompositor::SetCurrentFrame(
// We have a current frame, so determine what has changed.
is_first_frame = false;
- media::VideoRotation current_video_rotation =
- current_frame_->metadata()->rotation.value_or(media::VIDEO_ROTATION_0);
+ auto current_video_rotation = media::VIDEO_ROTATION_0;
+ if (current_frame_->metadata().transformation) {
+ current_video_rotation =
+ current_frame_->metadata().transformation->rotation;
+ }
has_frame_size_changed =
RotationAdjustedSize(*new_rotation, frame->natural_size()) !=
RotationAdjustedSize(current_video_rotation,
current_frame_->natural_size());
- if (current_video_rotation == *new_rotation) {
+ if (current_video_rotation == *new_rotation)
new_rotation.reset();
- }
if (*new_opacity == media::IsOpaque(current_frame_->format()))
new_opacity.reset();
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 7ae457d4408..2ad28972cff 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
@@ -17,6 +17,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/layers/layer.h"
+#include "media/base/media_content_type.h"
#include "media/base/media_util.h"
#include "media/base/test_helpers.h"
#include "media/base/video_frame.h"
@@ -110,33 +111,13 @@ class FakeWebMediaPlayerDelegate
void DidPlay(int delegate_id) override {
EXPECT_EQ(delegate_id_, delegate_id);
- EXPECT_FALSE(playing_);
- playing_ = true;
is_gone_ = false;
}
- void DidPlayerMutedStatusChange(int delegate_id, bool muted) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
void DidPause(int delegate_id, bool reached_end_of_stream) override {
EXPECT_EQ(delegate_id_, delegate_id);
EXPECT_FALSE(reached_end_of_stream);
- EXPECT_TRUE(playing_);
EXPECT_FALSE(is_gone_);
- playing_ = false;
- }
-
- void DidPlayerSizeChange(int delegate_id, const gfx::Size& size) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
- void DidBufferUnderflow(int delegate_id) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
- void DidSeek(int delegate_id) override {
- EXPECT_EQ(delegate_id_, delegate_id);
}
void PlayerGone(int delegate_id) override {
@@ -163,12 +144,6 @@ class FakeWebMediaPlayerDelegate
return false;
}
- void SetIsEffectivelyFullscreen(
- int delegate_id,
- WebFullscreenVideoStatus fullscreen_video_status) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
bool IsFrameHidden() override { return is_hidden_; }
bool IsFrameClosed() override { return false; }
@@ -176,30 +151,9 @@ class FakeWebMediaPlayerDelegate
int delegate_id() { return delegate_id_; }
- void DidPlayerMediaPositionStateChange(
- int delegate_id,
- const media_session::MediaPosition& position) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
- void DidPictureInPictureAvailabilityChange(int delegate_id,
- bool available) override {
- EXPECT_EQ(delegate_id_, delegate_id);
- }
-
- void DidAudioOutputSinkChange(int delegate_id,
- const std::string& hashed_device_id) override {
- 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;
- bool playing_ = false;
bool is_hidden_ = false;
bool is_gone_ = true;
bool is_idle_ = false;
@@ -375,9 +329,9 @@ void MockMediaStreamVideoRenderer::QueueFrames(
// MediaStreamRemoteVideoSource does not explicitly set the rotation
// for unrotated frames, so that is not done here either.
if (rotation != media::VIDEO_ROTATION_0)
- frame->metadata()->rotation = rotation;
+ frame->metadata().transformation = rotation;
- frame->metadata()->reference_time =
+ frame->metadata().reference_time =
base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(token);
AddFrame(FrameType::NORMAL_FRAME, frame);
@@ -600,7 +554,6 @@ class WebMediaPlayerMSTest
void AddTextTrack(WebInbandTextTrack*) override {}
void RemoveTextTrack(WebInbandTextTrack*) override {}
void MediaSourceOpened(WebMediaSource*) override {}
- void RequestSeek(double) override {}
void RemotePlaybackCompatibilityChanged(const WebURL& url,
bool is_compatible) override {}
void OnBecamePersistentVideo(bool) override {}
@@ -615,11 +568,23 @@ class WebMediaPlayerMSTest
void MediaRemotingStarted(
const WebString& remote_device_friendly_name) override {}
void MediaRemotingStopped(int error_code) override {}
- void RequestPlay() override {}
- void RequestPause() override {}
- void RequestMuted(bool muted) override {}
- void RequestEnterPictureInPicture() override {}
- void RequestExitPictureInPicture() override {}
+ void ResumePlayback() override {}
+ void PausePlayback() override {}
+ void DidPlayerStartPlaying() override {}
+ void DidPlayerPaused(bool) override {}
+ void DidPlayerMutedStatusChange(bool muted) override {}
+ void DidMediaMetadataChange(
+ bool has_audio,
+ bool has_video,
+ media::MediaContentType media_content_type) override {}
+ void DidPlayerMediaPositionStateChange(double playback_rate,
+ base::TimeDelta duration,
+ base::TimeDelta position) override {}
+ void DidDisableAudioOutputSinkChanges() override {}
+ void DidPlayerSizeChange(const gfx::Size& size) override {}
+ void DidBufferUnderflow() override {}
+ void DidSeek() override {}
+
Features GetFeatures() override { return Features(); }
// Implementation of cc::VideoFrameProvider::Client
@@ -726,7 +691,8 @@ MockMediaStreamVideoRenderer* WebMediaPlayerMSTest::LoadAndGetFrameProvider(
EXPECT_CALL(*this,
DoReadyStateChanged(WebMediaPlayer::kReadyStateHaveNothing));
player_->Load(WebMediaPlayer::kLoadTypeURL, WebMediaPlayerSource(),
- WebMediaPlayer::kCorsModeUnspecified);
+ WebMediaPlayer::kCorsModeUnspecified,
+ /*is_cache_disabled=*/false);
compositor_ = player_->compositor_.get();
EXPECT_TRUE(!!compositor_);
compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled);
@@ -871,7 +837,8 @@ TEST_P(WebMediaPlayerMSTest, NoWaitForFrameForAudio) {
DoReadyStateChanged(WebMediaPlayer::kReadyStateHaveEnoughData));
player_->Load(WebMediaPlayer::kLoadTypeURL, WebMediaPlayerSource(),
- WebMediaPlayer::kCorsModeUnspecified);
+ WebMediaPlayer::kCorsModeUnspecified,
+ /*is_cache_disabled=*/false);
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
@@ -1352,11 +1319,6 @@ TEST_P(WebMediaPlayerMSTest, HiddenPlayerTests) {
player_->Play();
EXPECT_FALSE(player_->Paused());
- // A pause delivered via the delegate should not pause the video since these
- // calls are currently ignored.
- player_->OnPause();
- EXPECT_FALSE(player_->Paused());
-
// A hidden player should start still be playing upon shown.
delegate_.set_hidden(false);
player_->OnFrameShown();
@@ -1403,7 +1365,7 @@ TEST_P(WebMediaPlayerMSTest, RequestVideoFrameCallback) {
Vector<int> timestamps({0, 33, kTestBrake, 66, 100, 133, 166});
provider->QueueFrames(timestamps);
- // Verify a basic call to RAF.
+ // Verify a basic call to rVFC
player_->RequestVideoFrameCallback();
EXPECT_CALL(*this, OnRequestVideoFrameCallback()).Times(1);
message_loop_controller_.RunAndWaitForStatus(
@@ -1415,7 +1377,8 @@ TEST_P(WebMediaPlayerMSTest, RequestVideoFrameCallback) {
EXPECT_GE(metadata->expected_display_time, metadata->presentation_time);
testing::Mock::VerifyAndClearExpectations(this);
- // Make sure multiple calls to RAF only result in one call per frame to OnRAF.
+ // Make sure multiple calls to rVFC only result in one call per frame to
+ // OnRVFC.
player_->RequestVideoFrameCallback();
player_->RequestVideoFrameCallback();
player_->RequestVideoFrameCallback();
@@ -1458,12 +1421,12 @@ TEST_P(WebMediaPlayerMSTest, GetVideoFramePresentationMetadata) {
Vector<int> timestamps({0, kTestBrake, 33, kTestBrake, 66, kTestBrake});
provider->QueueFrames(timestamps);
- // Chain calls to video.rAF.
+ // Chain calls to video.rVFC.
int num_frames = 3;
player_->RequestVideoFrameCallback();
// Verify that the presentation frame counter is monotonically increasing.
- // Queue up a rAF call immediately after each frame.
+ // Queue up a rVFC call immediately after each frame.
int last_frame_counter = -1;
EXPECT_CALL(*this, OnRequestVideoFrameCallback())
.Times(num_frames)
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/BUILD.gn b/chromium/third_party/blink/renderer/modules/modalclosewatcher/BUILD.gn
new file mode 100644
index 00000000000..9f3262a2846
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("modalclosewatcher") {
+ sources = [
+ "modal_close_watcher.cc",
+ "modal_close_watcher.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/OWNERS b/chromium/third_party/blink/renderer/modules/modalclosewatcher/OWNERS
new file mode 100644
index 00000000000..dec8dabe9e3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/OWNERS
@@ -0,0 +1,2 @@
+japhet@chromium.org
+domenic@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/idls.gni b/chromium/third_party/blink/renderer/modules/modalclosewatcher/idls.gni
new file mode 100644
index 00000000000..7f813637ebc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/idls.gni
@@ -0,0 +1,5 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+modules_idl_files = [ "modal_close_watcher.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc
new file mode 100644
index 00000000000..77385084d33
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc
@@ -0,0 +1,125 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h"
+
+#include "third_party/blink/public/platform/interface_registry.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/platform/keyboard_codes.h"
+
+namespace blink {
+
+const char ModalCloseWatcher::WatcherStack::kSupplementName[] =
+ "ModalCloseWatcher::WatcherStack";
+
+ModalCloseWatcher::WatcherStack& ModalCloseWatcher::WatcherStack::From(
+ LocalDOMWindow& window) {
+ auto* stack = Supplement<LocalDOMWindow>::From<WatcherStack>(window);
+ if (!stack) {
+ stack = MakeGarbageCollected<WatcherStack>(window);
+ Supplement<LocalDOMWindow>::ProvideTo(window, stack);
+ }
+ return *stack;
+}
+
+ModalCloseWatcher::WatcherStack::WatcherStack(LocalDOMWindow& window)
+ : Supplement<LocalDOMWindow>(window), receiver_(this, &window) {}
+
+void ModalCloseWatcher::WatcherStack::Add(ModalCloseWatcher* watcher) {
+ if (watchers_.IsEmpty()) {
+ GetSupplementable()->addEventListener(event_type_names::kKeyup, this);
+ auto& host = GetSupplementable()->GetFrame()->GetLocalFrameHostRemote();
+ host.SetModalCloseListener(receiver_.BindNewPipeAndPassRemote(
+ GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ }
+ watchers_.insert(watcher);
+}
+
+void ModalCloseWatcher::WatcherStack::Remove(ModalCloseWatcher* watcher) {
+ watchers_.erase(watcher);
+ if (watchers_.IsEmpty()) {
+ GetSupplementable()->removeEventListener(event_type_names::kKeyup, this);
+ receiver_.reset();
+ }
+}
+
+void ModalCloseWatcher::WatcherStack::Trace(Visitor* visitor) const {
+ NativeEventListener::Trace(visitor);
+ Supplement<LocalDOMWindow>::Trace(visitor);
+ visitor->Trace(watchers_);
+ visitor->Trace(receiver_);
+}
+
+void ModalCloseWatcher::WatcherStack::Invoke(ExecutionContext*, Event* e) {
+ DCHECK(!watchers_.IsEmpty());
+ KeyboardEvent* event = DynamicTo<KeyboardEvent>(e);
+ if (event && event->isTrusted() && event->keyCode() == VKEY_ESCAPE)
+ Signal();
+}
+
+ModalCloseWatcher* ModalCloseWatcher::Create(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+ WatcherStack& stack = WatcherStack::From(*window);
+ if (stack.HasActiveWatcher() &&
+ !LocalFrame::HasTransientUserActivation(window->GetFrame())) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Creating more than one ModalCloseWatcher at a time requires a user "
+ "activation.");
+ return nullptr;
+ }
+
+ ModalCloseWatcher* watcher = MakeGarbageCollected<ModalCloseWatcher>(window);
+ stack.Add(watcher);
+ return watcher;
+}
+
+ModalCloseWatcher::ModalCloseWatcher(LocalDOMWindow* window)
+ : ExecutionContextClient(window) {}
+
+void ModalCloseWatcher::signalClosed() {
+ if (IsClosed() || dispatching_beforeclose_)
+ return;
+ Event& before_close_event =
+ *Event::CreateCancelable(event_type_names::kBeforeclose);
+ {
+ base::AutoReset<bool> scoped_committing(&dispatching_beforeclose_, true);
+ DispatchEvent(before_close_event);
+ }
+ if (before_close_event.defaultPrevented()) {
+ state_ = State::kModal;
+ // TODO(japhet): Make an async dialog here.
+ }
+ Close();
+}
+
+void ModalCloseWatcher::Close() {
+ if (IsClosed())
+ return;
+ WatcherStack::From(*DomWindow()).Remove(this);
+ state_ = State::kClosed;
+ DispatchEvent(*Event::Create(event_type_names::kClose));
+}
+
+void ModalCloseWatcher::destroy() {
+ if (IsClosed())
+ return;
+ WatcherStack::From(*DomWindow()).Remove(this);
+ state_ = State::kClosed;
+}
+
+const AtomicString& ModalCloseWatcher::InterfaceName() const {
+ return event_target_names::kModalCloseWatcher;
+}
+
+void ModalCloseWatcher::Trace(Visitor* visitor) const {
+ EventTargetWithInlineData::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h
new file mode 100644
index 00000000000..f89c146d6c5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h
@@ -0,0 +1,84 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_
+
+#include "third_party/blink/public/mojom/modal_close_watcher/modal_close_listener.mojom-blink.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ModalCloseWatcher final : public EventTargetWithInlineData,
+ public ExecutionContextClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static ModalCloseWatcher* Create(ScriptState*, ExceptionState&);
+ explicit ModalCloseWatcher(LocalDOMWindow*);
+ void Trace(Visitor*) const override;
+
+ bool IsClosed() const { return state_ == State::kClosed; }
+
+ void signalClosed();
+ void destroy();
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeclose, kBeforeclose)
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(close, kClose)
+
+ // EventTargetWithInlineData overrides:
+ const AtomicString& InterfaceName() const final;
+ ExecutionContext* GetExecutionContext() const final {
+ return ExecutionContextClient::GetExecutionContext();
+ }
+
+ private:
+ void Close();
+
+ // If multiple ModalCloseWatchers are active in a given window, they form a
+ // stack, and a close signal will pop the top watcher. If the stack is empty,
+ // the first ModalCloseWatcher is "free", but creating a new
+ // ModalCloseWatcher when the stack is non-empty requires a user activation.
+ class WatcherStack final : public NativeEventListener,
+ public Supplement<LocalDOMWindow>,
+ public mojom::blink::ModalCloseListener {
+ public:
+ static const char kSupplementName[];
+
+ static WatcherStack& From(LocalDOMWindow&);
+ explicit WatcherStack(LocalDOMWindow&);
+
+ void Add(ModalCloseWatcher*);
+ void Remove(ModalCloseWatcher*);
+ bool HasActiveWatcher() { return !watchers_.IsEmpty(); }
+
+ void Trace(Visitor*) const final;
+
+ private:
+ // NativeEventListener override:
+ void Invoke(ExecutionContext*, Event*) final;
+
+ // mojom::blink::ModalCloseListener override:
+ void Signal() final { watchers_.back()->signalClosed(); }
+
+ HeapLinkedHashSet<Member<ModalCloseWatcher>> watchers_;
+
+ // Holds a pipe which the service uses to notify this object
+ // when the idle state has changed.
+ HeapMojoReceiver<mojom::blink::ModalCloseListener, WatcherStack> receiver_;
+ };
+
+ enum class State { kActive, kModal, kClosed };
+ State state_ = State::kActive;
+ bool dispatching_beforeclose_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.idl b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.idl
new file mode 100644
index 00000000000..25c45816b3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.idl
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ Exposed=Window,
+ RuntimeEnabled=ModalCloseWatcher
+] interface ModalCloseWatcher {
+ [CallWith=ScriptState, RaisesException] constructor();
+
+ void signalClosed();
+ void destroy();
+
+ attribute EventHandler onbeforeclose;
+ attribute EventHandler onclose;
+};
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 99696b69b90..2f3b9289edf 100644
--- a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -58,6 +58,7 @@ _idl_imports = [
"//third_party/blink/renderer/modules/beacon/idls.gni",
"//third_party/blink/renderer/modules/bluetooth/idls.gni",
"//third_party/blink/renderer/modules/broadcastchannel/idls.gni",
+ "//third_party/blink/renderer/modules/buckets/idls.gni",
"//third_party/blink/renderer/modules/cache_storage/idls.gni",
"//third_party/blink/renderer/modules/canvas/idls.gni",
"//third_party/blink/renderer/modules/clipboard/idls.gni",
@@ -69,16 +70,19 @@ _idl_imports = [
"//third_party/blink/renderer/modules/crypto/idls.gni",
"//third_party/blink/renderer/modules/csspaint/idls.gni",
"//third_party/blink/renderer/modules/delegated_ink/idls.gni",
+ "//third_party/blink/renderer/modules/device/idls.gni",
"//third_party/blink/renderer/modules/device_orientation/idls.gni",
"//third_party/blink/renderer/modules/donottrack/idls.gni",
"//third_party/blink/renderer/modules/encoding/idls.gni",
"//third_party/blink/renderer/modules/encryptedmedia/idls.gni",
"//third_party/blink/renderer/modules/eventsource/idls.gni",
+ "//third_party/blink/renderer/modules/eyedropper/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",
+ "//third_party/blink/renderer/modules/handwriting/idls.gni",
"//third_party/blink/renderer/modules/hid/idls.gni",
"//third_party/blink/renderer/modules/idle/idls.gni",
"//third_party/blink/renderer/modules/imagecapture/idls.gni",
@@ -94,6 +98,7 @@ _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/modalclosewatcher/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",
@@ -119,6 +124,7 @@ _idl_imports = [
"//third_party/blink/renderer/modules/speech/idls.gni",
"//third_party/blink/renderer/modules/srcobject/idls.gni",
"//third_party/blink/renderer/modules/storage/idls.gni",
+ "//third_party/blink/renderer/modules/url_pattern/idls.gni",
"//third_party/blink/renderer/modules/vibration/idls.gni",
"//third_party/blink/renderer/modules/video_rvfc/idls.gni",
"//third_party/blink/renderer/modules/virtualkeyboard/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 df351874507..b58d89a0e06 100644
--- a/chromium/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/chromium/third_party/blink/renderer/modules/modules_initializer.cc
@@ -16,8 +16,8 @@
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/bindings/modules/v8/module_bindings_initializer.h"
+#include "third_party/blink/renderer/core/css/background_color_paint_image_generator.h"
#include "third_party/blink/renderer/core/css/css_paint_image_generator.h"
-#include "third_party/blink/renderer/core/css/native_paint_image_generator.h"
#include "third_party/blink/renderer/core/dom/context_features_client_impl.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/editing/suggestion/text_suggestion_backend_impl.h"
@@ -42,8 +42,8 @@
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h"
#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.h"
#include "third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h"
+#include "third_party/blink/renderer/modules/csspaint/background_color_paint_image_generator_impl.h"
#include "third_party/blink/renderer/modules/csspaint/css_paint_image_generator_impl.h"
-#include "third_party/blink/renderer/modules/csspaint/native_paint_image_generator_impl.h"
#include "third_party/blink/renderer/modules/device_orientation/device_motion_controller.h"
#include "third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.h"
#include "third_party/blink/renderer/modules/device_orientation/device_orientation_controller.h"
@@ -95,6 +95,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -122,7 +123,8 @@ void ModulesInitializer::Initialize() {
DraggedIsolatedFileSystem::Init(
DraggedIsolatedFileSystemImpl::PrepareForDataObject);
CSSPaintImageGenerator::Init(CSSPaintImageGeneratorImpl::Create);
- NativePaintImageGenerator::Init(NativePaintImageGeneratorImpl::Create);
+ BackgroundColorPaintImageGenerator::Init(
+ BackgroundColorPaintImageGeneratorImpl::Create);
WebDatabaseHost::GetInstance().Init();
MediaSourceRegistryImpl::Init();
@@ -259,9 +261,12 @@ std::unique_ptr<WebMediaPlayer> ModulesInitializer::CreateWebMediaPlayer(
HTMLMediaElementAudioOutputDevice::sinkId(html_media_element));
MediaInspectorContextImpl* context_impl = MediaInspectorContextImpl::From(
*To<LocalDOMWindow>(html_media_element.GetExecutionContext()));
+ FrameWidget* frame_widget =
+ html_media_element.GetDocument().GetFrame()->GetWidgetForLocalRoot();
return base::WrapUnique(web_frame_client->CreateMediaPlayer(
source, media_player_client, context_impl, &encrypted_media,
- encrypted_media.ContentDecryptionModule(), sink_id));
+ encrypted_media.ContentDecryptionModule(), sink_id,
+ frame_widget->GetLayerTreeSettings()));
}
WebRemotePlaybackClient* ModulesInitializer::CreateWebRemotePlaybackClient(
diff --git a/chromium/third_party/blink/renderer/modules/native_io/BUILD.gn b/chromium/third_party/blink/renderer/modules/native_io/BUILD.gn
index 61ed8d843f9..a183cc4813f 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/native_io/BUILD.gn
@@ -8,12 +8,16 @@ blink_modules_sources("native_io") {
sources = [
"global_native_io.cc",
"global_native_io.h",
+ "native_io_capacity_tracker.cc",
+ "native_io_capacity_tracker.h",
+ "native_io_error.cc",
+ "native_io_error.h",
"native_io_file.cc",
"native_io_file.h",
+ "native_io_file_manager.cc",
+ "native_io_file_manager.h",
"native_io_file_sync.cc",
"native_io_file_sync.h",
- "native_io_manager.cc",
- "native_io_manager.h",
]
deps = [ "//third_party/blink/renderer/platform" ]
diff --git a/chromium/third_party/blink/renderer/modules/native_io/DEPS b/chromium/third_party/blink/renderer/modules/native_io/DEPS
index 8c20ba39153..a902edfa2ba 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/DEPS
+++ b/chromium/third_party/blink/renderer/modules/native_io/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+base/files/file.h",
+ "+base/mac/mac_util.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/native_io/DIR_METADATA b/chromium/third_party/blink/renderer/modules/native_io/DIR_METADATA
new file mode 100644
index 00000000000..24413c7c362
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>NativeIO"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/native_io/OWNERS b/chromium/third_party/blink/renderer/modules/native_io/OWNERS
index 271647c4a24..85c9b490aa0 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/native_io/OWNERS
@@ -1,4 +1 @@
file://content/browser/native_io/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>NativeIO
diff --git a/chromium/third_party/blink/renderer/modules/native_io/README.md b/chromium/third_party/blink/renderer/modules/native_io/README.md
index 89abc128180..0c0474407a2 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/README.md
+++ b/chromium/third_party/blink/renderer/modules/native_io/README.md
@@ -57,3 +57,8 @@ The main reason for enforcing locking early in the API design is to avoid
exposing the details of OS-level file descriptor sharing to the Web Platform.
This aspect of the prototype may also change, based on research and developer
feedback.
+
+# Design documents
+
+- [Quota Management](https://docs.google.com/document/d/1wUrtCOsyH3qGwKuqLhV9AJD-bDAjAzfPL5r1GT8H4IY)
+- [Error handling](https://docs.google.com/document/d/1rvs615AU2s8kVsmUlukbmtQNvUWFny0yzAS_gsnYZEs)
diff --git a/chromium/third_party/blink/renderer/modules/native_io/global_native_io.cc b/chromium/third_party/blink/renderer/modules/native_io/global_native_io.cc
index b381fe7b354..5c3ae5bfd2b 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/global_native_io.cc
+++ b/chromium/third_party/blink/renderer/modules/native_io/global_native_io.cc
@@ -13,7 +13,8 @@
#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_io/native_io_manager.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_file_manager.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -41,11 +42,15 @@ class GlobalNativeIOImpl final : public GarbageCollected<GlobalNativeIOImpl<T>>,
explicit GlobalNativeIOImpl(T& supplementable)
: Supplement<T>(supplementable) {}
- NativeIOManager* GetNativeIOManager(T& scope) {
- if (!native_io_manager_) {
+ NativeIOFileManager* GetNativeIOFileManager(T& scope) {
+ if (!native_io_file_manager_) {
ExecutionContext* execution_context = scope.GetExecutionContext();
+ // TODO(rstz): Consider throwing a security error on opaque origins
+ // instead.
if (&execution_context->GetBrowserInterfaceBroker() ==
- &GetEmptyBrowserInterfaceBroker()) {
+ &GetEmptyBrowserInterfaceBroker() ||
+ !execution_context->GetSecurityOrigin()
+ ->CanAccessStorageFoundation()) {
return nullptr;
}
@@ -53,19 +58,20 @@ class GlobalNativeIOImpl final : public GarbageCollected<GlobalNativeIOImpl<T>>,
execution_context->GetBrowserInterfaceBroker().GetInterface(
backend.BindNewPipeAndPassReceiver(
execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
- native_io_manager_ = MakeGarbageCollected<NativeIOManager>(
- execution_context, std::move(backend));
+ native_io_file_manager_ = MakeGarbageCollected<NativeIOFileManager>(
+ execution_context, std::move(backend),
+ MakeGarbageCollected<NativeIOCapacityTracker>());
}
- return native_io_manager_;
+ return native_io_file_manager_;
}
void Trace(Visitor* visitor) const override {
- visitor->Trace(native_io_manager_);
+ visitor->Trace(native_io_file_manager_);
Supplement<T>::Trace(visitor);
}
private:
- Member<NativeIOManager> native_io_manager_;
+ Member<NativeIOFileManager> native_io_file_manager_;
};
// static
@@ -75,15 +81,16 @@ const char GlobalNativeIOImpl<T>::kSupplementName[] = "GlobalNativeIOImpl";
} // namespace
// static
-NativeIOManager* GlobalNativeIO::nativeIO(LocalDOMWindow& window) {
- return GlobalNativeIOImpl<LocalDOMWindow>::From(window).GetNativeIOManager(
- window);
+NativeIOFileManager* GlobalNativeIO::storageFoundation(LocalDOMWindow& window) {
+ return GlobalNativeIOImpl<LocalDOMWindow>::From(window)
+ .GetNativeIOFileManager(window);
}
// static
-NativeIOManager* GlobalNativeIO::nativeIO(WorkerGlobalScope& worker) {
- return GlobalNativeIOImpl<WorkerGlobalScope>::From(worker).GetNativeIOManager(
- worker);
+NativeIOFileManager* GlobalNativeIO::storageFoundation(
+ WorkerGlobalScope& worker) {
+ return GlobalNativeIOImpl<WorkerGlobalScope>::From(worker)
+ .GetNativeIOFileManager(worker);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/global_native_io.h b/chromium/third_party/blink/renderer/modules/native_io/global_native_io.h
index bb9b05b9399..17b17b9c38c 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/global_native_io.h
+++ b/chromium/third_party/blink/renderer/modules/native_io/global_native_io.h
@@ -10,16 +10,17 @@
namespace blink {
class LocalDOMWindow;
-class NativeIOManager;
+class NativeIOFileManager;
class WorkerGlobalScope;
-// The "nativeIO" attribute on the Window global and Worker global scope.
+// The "storageFoundation" attribute on the Window global and Worker global
+// scope.
class GlobalNativeIO {
STATIC_ONLY(GlobalNativeIO);
public:
- static NativeIOManager* nativeIO(LocalDOMWindow&);
- static NativeIOManager* nativeIO(WorkerGlobalScope&);
+ static NativeIOFileManager* storageFoundation(LocalDOMWindow&);
+ static NativeIOFileManager* storageFoundation(WorkerGlobalScope&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/idls.gni b/chromium/third_party/blink/renderer/modules/native_io/idls.gni
index 694bfa928fd..5f9a67aa304 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/native_io/idls.gni
@@ -4,8 +4,8 @@
modules_idl_files = [
"native_io_file.idl",
+ "native_io_file_manager.idl",
"native_io_file_sync.idl",
- "native_io_manager.idl",
]
modules_dependency_idl_files = [
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.cc
new file mode 100644
index 00000000000..87add2ba1c8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.cc
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "base/numerics/checked_math.h"
+#include "base/sequence_checker.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+bool NativeIOCapacityTracker::ChangeAvailableCapacity(int64_t capacity_delta) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ int64_t new_capacity;
+ if (!base::CheckAdd(available_capacity, capacity_delta)
+ .AssignIfValid(&new_capacity)) {
+ return false;
+ }
+
+ if (new_capacity < 0)
+ return false;
+ available_capacity = new_capacity;
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h
new file mode 100644
index 00000000000..f7b2f459999
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_CAPACITY_TRACKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_CAPACITY_TRACKER_H_
+
+#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+// Tracks the capacity allocated to an execution context.
+class NativeIOCapacityTracker final
+ : public GarbageCollected<NativeIOCapacityTracker> {
+ public:
+ NativeIOCapacityTracker() = default;
+
+ NativeIOCapacityTracker(const NativeIOCapacityTracker&) = delete;
+ NativeIOCapacityTracker& operator=(const NativeIOCapacityTracker&) = delete;
+
+ // Changes the available capacity by the specified amount if possible.
+ //
+ // Returns true if and only if the capacity change is successfully applied.
+ // If `capacity_delta` < 0, returns false if the change would bring the
+ // available capacity below 0.
+ bool ChangeAvailableCapacity(int64_t capacity_delta);
+
+ // Returns the available capacity for this capacity tracker.
+ uint64_t GetAvailableCapacity() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return available_capacity;
+ }
+
+ // GarbageCollected
+ void Trace(Visitor*) const {}
+
+ private:
+ int64_t available_capacity GUARDED_BY_CONTEXT(sequence_checker_) = 0;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_CAPACITY_TRACKER_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_error.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_error.cc
new file mode 100644
index 00000000000..10c45f5d53b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_error.cc
@@ -0,0 +1,95 @@
+// Copyright 2020 The Chromium Authors. 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/native_io/native_io_error.h"
+
+#include "base/files/file.h"
+#include "third_party/blink/public/common/native_io/native_io_utils.h"
+#include "third_party/blink/public/mojom/native_io/native_io.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"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+using blink::mojom::blink::NativeIOErrorPtr;
+using blink::mojom::blink::NativeIOErrorType;
+
+namespace blink {
+
+namespace {
+
+DOMExceptionCode NativeIOErrorToDOMExceptionCode(NativeIOErrorType error) {
+ switch (error) {
+ case NativeIOErrorType::kSuccess:
+ // This function should only be called with an error.
+ NOTREACHED();
+ return DOMExceptionCode::kNoError;
+ case NativeIOErrorType::kUnknown:
+ return DOMExceptionCode::kUnknownError;
+ case NativeIOErrorType::kInvalidState:
+ return DOMExceptionCode::kInvalidStateError;
+ case NativeIOErrorType::kNotFound:
+ return DOMExceptionCode::kNotFoundError;
+ case NativeIOErrorType::kNoModificationAllowed:
+ return DOMExceptionCode::kNoModificationAllowedError;
+ case NativeIOErrorType::kNoSpace:
+ return DOMExceptionCode::kQuotaExceededError;
+ }
+ NOTREACHED();
+ return DOMExceptionCode::kUnknownError;
+}
+
+} // namespace
+
+void RejectNativeIOWithError(ScriptPromiseResolver* resolver,
+ NativeIOErrorPtr error) {
+ DCHECK(resolver->GetScriptState()->ContextIsValid())
+ << "The resolver's script state must be valid.";
+ ScriptState* script_state = resolver->GetScriptState();
+ DOMExceptionCode exception_code =
+ NativeIOErrorToDOMExceptionCode(error->type);
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ script_state->GetIsolate(), exception_code, error->message));
+ return;
+}
+
+void RejectNativeIOWithError(ScriptPromiseResolver* resolver,
+ base::File::Error file_error,
+ const String& message) {
+ DCHECK(resolver->GetScriptState()->ContextIsValid())
+ << "The resolver's script state must be valid.";
+ RejectNativeIOWithError(resolver,
+ FileErrorToNativeIOError(file_error, message));
+ return;
+}
+
+void ThrowNativeIOWithError(ExceptionState& exception_state,
+ NativeIOErrorPtr error) {
+ DOMExceptionCode exception_code =
+ NativeIOErrorToDOMExceptionCode(error->type);
+ exception_state.ThrowDOMException(exception_code, error->message);
+ return;
+}
+
+void ThrowNativeIOWithError(ExceptionState& exception_state,
+ base::File::Error file_error,
+ const String& message) {
+ ThrowNativeIOWithError(exception_state,
+ FileErrorToNativeIOError(file_error, message));
+ return;
+}
+
+NativeIOErrorPtr FileErrorToNativeIOError(base::File::Error file_error,
+ const String& message) {
+ NativeIOErrorType native_io_error_type =
+ blink::native_io::FileErrorToNativeIOErrorType(file_error);
+ String final_message =
+ message.IsEmpty() ? String::FromUTF8(blink::native_io::GetDefaultMessage(
+ native_io_error_type)
+ .c_str())
+ : message;
+ return mojom::blink::NativeIOError::New(native_io_error_type, final_message);
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_error.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_error.h
new file mode 100644
index 00000000000..f53a54587e9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_error.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_ERROR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_ERROR_H_
+
+#include "base/files/file.h"
+#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.h"
+
+using blink::mojom::blink::NativeIOErrorPtr;
+using blink::mojom::blink::NativeIOErrorType;
+
+namespace blink {
+
+class ScriptPromiseResolver;
+class ExceptionState;
+
+// Reject the `resolver` with the appropriate DOMException given
+// `error`. The resolver's execution context should be valid.
+void RejectNativeIOWithError(ScriptPromiseResolver* resolver,
+ NativeIOErrorPtr error);
+
+// Reject the `resolver` with the appropriate DOMException given `file_error`.
+// When no `message` is provided, the default one is chosen. The resolver's
+// execution context should be valid.
+void RejectNativeIOWithError(ScriptPromiseResolver* resolver,
+ base::File::Error file_error,
+ const String& message = String());
+
+// Throw with the appropriate DOMException given `error`.
+void ThrowNativeIOWithError(ExceptionState& exception_state,
+ NativeIOErrorPtr error);
+
+// Throw with the appropriate DOMException given `file_error`. When no `message`
+// is provided, the standard one is chosen.
+void ThrowNativeIOWithError(ExceptionState& exception_state,
+ base::File::Error file_error,
+ const String& message = String());
+
+NativeIOErrorPtr FileErrorToNativeIOError(base::File::Error file_error,
+ const String& message);
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_ERROR_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.cc
index 76f50d3fa39..b9e3a3b2aab 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.cc
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.cc
@@ -9,9 +9,12 @@
#include "base/check.h"
#include "base/files/file.h"
#include "base/location.h"
+#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "base/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
+#include "build/build_config.h"
+#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.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"
@@ -21,6 +24,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_error.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/bindings/script_wrappable.h"
@@ -33,6 +37,10 @@
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
+#if defined(OS_MAC)
+#include "base/mac/mac_util.h"
+#endif
+
namespace blink {
namespace {
@@ -74,13 +82,19 @@ struct NativeIOFile::FileState {
NativeIOFile::NativeIOFile(
base::File backing_file,
+ int64_t backing_file_length,
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file,
+ NativeIOCapacityTracker* capacity_tracker,
ExecutionContext* execution_context)
- : file_state_(std::make_unique<FileState>(std::move(backing_file))),
+ : file_length_(backing_file_length),
+ file_state_(std::make_unique<FileState>(std::move(backing_file))),
// TODO(pwnall): Get a dedicated queue when the specification matures.
resolver_task_runner_(
execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)),
- backend_file_(std::move(backend_file)) {
+ backend_file_(std::move(backend_file)),
+ capacity_tracker_(capacity_tracker) {
+ DCHECK_GE(backing_file_length, 0);
+ DCHECK(capacity_tracker);
backend_file_.set_disconnect_handler(
WTF::Bind(&NativeIOFile::OnBackendDisconnect, WrapWeakPersistent(this)));
}
@@ -124,8 +138,10 @@ ScriptPromise NativeIOFile::getLength(ScriptState* script_state,
return ScriptPromise();
}
if (closed_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return ScriptPromise();
}
io_pending_ = true;
@@ -145,9 +161,10 @@ ScriptPromise NativeIOFile::getLength(ScriptState* script_state,
}
ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
- uint64_t length,
+ uint64_t new_length,
ExceptionState& exception_state) {
- if (!base::IsValueInRangeForNumericType<int64_t>(length)) {
+ if (!base::IsValueInRangeForNumericType<int64_t>(new_length)) {
+ // TODO(rstz): Consider throwing QuotaExceededError here.
exception_state.ThrowTypeError("Quota exceeded.");
return ScriptPromise();
}
@@ -158,27 +175,75 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
return ScriptPromise();
}
if (closed_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return ScriptPromise();
}
+ int64_t expected_length = base::as_signed(new_length);
+
+ DCHECK_GE(expected_length, 0);
+ DCHECK_GE(file_length_, 0);
+ static_assert(0 - std::numeric_limits<int32_t>::max() >=
+ std::numeric_limits<int32_t>::min(),
+ "The `length_delta` computation below may overflow");
+ // Since both values are positive, the arithmetic will not overflow.
+ int64_t length_delta = expected_length - file_length_;
+
+ // The available capacity must be reduced before performing an I/O operation
+ // that increases the file length. The available capacity must not be
+ // reduced before performing an I/O operation that decreases the file
+ // length. The capacity tracker then reports at most
+ // the capacity that is actually available to the execution context. This
+ // prevents double-spending by concurrent I/O operations on different files.
+ if (length_delta > 0) {
+ if (!capacity_tracker_->ChangeAvailableCapacity(-length_delta)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return ScriptPromise();
+ }
+ file_length_ = expected_length;
+ }
io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // Calls to base::File::SetLength() are routed through the browser process,
- // see crbug.com/1084565.
- //
- // We keep a single handle per file, so this handle is passed to the browser
- // process and is given back to the renderer afterwards.
- {
- WTF::MutexLocker locker(file_state_->mutex);
- backend_file_->SetLength(
- base::as_signed(length), std::move(file_state_->file),
- WTF::Bind(&NativeIOFile::DidSetLength, WrapPersistent(this),
- WrapPersistent(resolver)));
+#if defined(OS_MAC)
+ // On macOS < 10.15, a sandboxing limitation causes failures in ftruncate()
+ // syscalls issued from renderers. For this reason, base::File::SetLength()
+ // fails in the renderer. We work around this problem by calling ftruncate()
+ // in the browser process. See crbug.com/1084565.
+ if (!base::mac::IsAtLeastOS10_15()) {
+ // Our system has at most one handle to a file, so we can avoid reasoning
+ // through the implications of multiple handles pointing to the same file.
+ //
+ // To preserve this invariant, we pass this file's handle to the browser
+ // process during the SetLength() mojo call, and the browser passes it back
+ // when the call completes.
+ {
+ WTF::MutexLocker locker(file_state_->mutex);
+ backend_file_->SetLength(
+ expected_length, std::move(file_state_->file),
+ WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this),
+ WrapPersistent(resolver)));
+ }
+ return resolver->Promise();
}
+#endif // defined(OS_MAC)
+ // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
+ // instance is owned by this NativeIOFile, which is also passed to the task
+ // via WrapCrossThreadPersistent. Therefore, the FileState instance is
+ // guaranteed to remain alive during the task's execution.
+ worker_pool::PostTask(
+ FROM_HERE, {base::MayBlock(), base::ThreadPool()},
+ CrossThreadBindOnce(&DoSetLength, WrapCrossThreadPersistent(this),
+ WrapCrossThreadPersistent(resolver),
+ CrossThreadUnretained(file_state_.get()),
+ resolver_task_runner_, expected_length));
return resolver->Promise();
}
@@ -186,7 +251,7 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
MaybeShared<DOMArrayBufferView> buffer,
uint64_t file_offset,
ExceptionState& exception_state) {
- if (!buffer.View()->IsShared()) {
+ if (!buffer->IsShared()) {
exception_state.ThrowTypeError(
"The I/O buffer must be backed by a SharedArrayBuffer");
return ScriptPromise();
@@ -199,16 +264,17 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
return ScriptPromise();
}
if (closed_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return ScriptPromise();
}
io_pending_ = true;
- int read_size = OperationSize(*buffer.View());
- char* read_buffer =
- static_cast<char*>(buffer.View()->BaseAddressMaybeShared());
- DOMSharedArrayBuffer* read_buffer_keepalive = buffer.View()->BufferShared();
+ int read_size = OperationSize(*buffer);
+ char* read_buffer = static_cast<char*>(buffer->BaseAddressMaybeShared());
+ DOMSharedArrayBuffer* read_buffer_keepalive = buffer->BufferShared();
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
// The first CrossThreadUnretained() is safe here because the
@@ -236,7 +302,7 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
MaybeShared<DOMArrayBufferView> buffer,
uint64_t file_offset,
ExceptionState& exception_state) {
- if (!buffer.View()->IsShared()) {
+ if (!buffer->IsShared()) {
exception_state.ThrowTypeError(
"The I/O buffer must be backed by a SharedArrayBuffer");
return ScriptPromise();
@@ -249,16 +315,50 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
return ScriptPromise();
}
if (closed_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return ScriptPromise();
}
+
+ int write_size = OperationSize(*buffer);
+ int64_t write_end_offset;
+ if (!base::CheckAdd(file_offset, write_size)
+ .AssignIfValid(&write_end_offset)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return ScriptPromise();
+ }
+
+ DCHECK_GE(write_end_offset, 0);
+ DCHECK_GE(file_length_, 0);
+ static_assert(0 - std::numeric_limits<int32_t>::max() >=
+ std::numeric_limits<int32_t>::min(),
+ "The `length_delta` computation below may overflow");
+ // Since both values are positive, the arithmetic will not overflow.
+ int64_t length_delta = write_end_offset - file_length_;
+ // The available capacity must be reduced before performing an I/O operation
+ // that increases the file length. This prevents double-spending by concurrent
+ // I/O operations on different files.
+ if (length_delta > 0) {
+ if (!capacity_tracker_->ChangeAvailableCapacity(-length_delta)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return ScriptPromise();
+ }
+ file_length_ = write_end_offset;
+ }
+
io_pending_ = true;
- int write_size = OperationSize(*buffer.View());
const char* write_data =
- static_cast<const char*>(buffer.View()->BaseAddressMaybeShared());
- DOMSharedArrayBuffer* read_buffer_keepalive = buffer.View()->BufferShared();
+ static_cast<const char*>(buffer->BaseAddressMaybeShared());
+ DOMSharedArrayBuffer* read_buffer_keepalive = buffer->BufferShared();
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
// The first CrossThreadUnretained() is safe here because the
@@ -294,8 +394,10 @@ ScriptPromise NativeIOFile::flush(ScriptState* script_state,
return ScriptPromise();
}
if (closed_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return ScriptPromise();
}
io_pending_ = true;
@@ -318,6 +420,7 @@ void NativeIOFile::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
visitor->Trace(queued_close_resolver_);
visitor->Trace(backend_file_);
+ visitor->Trace(capacity_tracker_);
}
void NativeIOFile::OnBackendDisconnect() {
@@ -391,16 +494,15 @@ void NativeIOFile::DoGetLength(
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
- base::File::Error get_length_error = base::File::FILE_OK;
+ base::File::Error get_length_error;
int64_t length = -1;
{
WTF::MutexLocker mutex_locker(file_state->mutex);
DCHECK(file_state->file.IsValid())
<< "file I/O operation queued after file closed";
length = file_state->file.GetLength();
- if (length < 0) {
- get_length_error = file_state->file.GetLastFileError();
- }
+ get_length_error = (length < 0) ? file_state->file.GetLastFileError()
+ : base::File::FILE_OK;
}
PostCrossThreadTask(
@@ -420,19 +522,22 @@ void NativeIOFile::DidGetLength(
ScriptState::Scope scope(script_state);
DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
+ if (get_length_error == base::File::FILE_OK) {
+ DCHECK_EQ(file_length_, length)
+ << "`file_length_` is not an upper bound anymore";
+ }
+
io_pending_ = false;
DispatchQueuedClose();
if (length < 0) {
- DCHECK(get_length_error != base::File::FILE_OK)
+ DCHECK_NE(get_length_error, base::File::FILE_OK)
<< "Negative length reported with no error set";
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kOperationError,
- "getLength() failed"));
+ blink::RejectNativeIOWithError(resolver, get_length_error);
return;
}
- DCHECK(get_length_error == base::File::FILE_OK)
+ DCHECK_EQ(get_length_error, base::File::FILE_OK)
<< "File error reported when length is nonnegative";
// getLength returns an unsigned integer, which is different from e.g.,
// base::File and POSIX. The uses for negative integers are error handling,
@@ -441,32 +546,137 @@ void NativeIOFile::DidGetLength(
resolver->Resolve(length);
}
-void NativeIOFile::DidSetLength(ScriptPromiseResolver* resolver,
- bool backend_success,
- base::File backing_file) {
+// static
+void NativeIOFile::DoSetLength(
+ CrossThreadPersistent<NativeIOFile> native_io_file,
+ CrossThreadPersistent<ScriptPromiseResolver> resolver,
+ NativeIOFile::FileState* file_state,
+ scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
+ int64_t expected_length) {
+ DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+
+ base::File::Error set_length_error;
+ int64_t actual_length;
+ {
+ WTF::MutexLocker mutex_locker(file_state->mutex);
+ DCHECK(file_state->file.IsValid())
+ << "file I/O operation queued after file closed";
+ bool success = file_state->file.SetLength(expected_length);
+ set_length_error =
+ success ? base::File::FILE_OK : file_state->file.GetLastFileError();
+ actual_length = success ? expected_length : file_state->file.GetLength();
+ }
+
+ PostCrossThreadTask(
+ *resolver_task_runner, FROM_HERE,
+ CrossThreadBindOnce(&NativeIOFile::DidSetLengthIo,
+ std::move(native_io_file), std::move(resolver),
+ actual_length, set_length_error));
+}
+
+void NativeIOFile::DidSetLengthIo(
+ CrossThreadPersistent<ScriptPromiseResolver> resolver,
+ int64_t actual_length,
+ base::File::Error set_length_error) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
+ io_pending_ = false;
+
+ if (actual_length >= 0) {
+ DCHECK_LE(actual_length, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_length < file_length_) {
+ // For successful length decreases, this logic returns freed up
+ // capacity. For unsuccessful length increases, this logic returns
+ // unused capacity.
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_length);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_length;
+ }
+ } else {
+ DCHECK(set_length_error != base::File::FILE_OK);
+ // base::File::SetLength() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ if (!closed_) {
+ closed_ = true;
+ queued_close_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ }
+ }
+
+ DispatchQueuedClose();
+
+ if (set_length_error != base::File::FILE_OK) {
+ RejectNativeIOWithError(resolver, set_length_error);
+ return;
+ }
+ resolver->Resolve();
+}
+
+#if defined(OS_MAC)
+void NativeIOFile::DidSetLengthIpc(
+ ScriptPromiseResolver* resolver,
+ base::File backing_file,
+ int64_t actual_length,
+ mojom::blink::NativeIOErrorPtr set_length_error) {
DCHECK(backing_file.IsValid()) << "browser returned closed file";
{
WTF::MutexLocker locker(file_state_->mutex);
file_state_->file = std::move(backing_file);
}
+ ScriptState* script_state = resolver->GetScriptState();
DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
io_pending_ = false;
- ScriptState* script_state = resolver->GetScriptState();
+ if (actual_length >= 0) {
+ DCHECK_LE(actual_length, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_length < file_length_) {
+ // For successful length decreases, this logic returns freed up
+ // capacity. For unsuccessful length increases, this logic returns
+ // unused capacity.
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_length);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_length;
+ }
+ } else {
+ DCHECK(set_length_error->type != mojom::blink::NativeIOErrorType::kSuccess);
+ // base::File::SetLength() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ if (!closed_) {
+ closed_ = true;
+ queued_close_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ }
+ }
+
if (!script_state->ContextIsValid())
return;
ScriptState::Scope scope(script_state);
- if (!backend_success) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
- "setLength() failed"));
+ DispatchQueuedClose();
+
+ if (set_length_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ blink::RejectNativeIOWithError(resolver, std::move(set_length_error));
return;
}
resolver->Resolve();
}
+#endif // defined(OS_MAC)
// static
void NativeIOFile::DoRead(
@@ -512,11 +722,13 @@ void NativeIOFile::DidRead(
DispatchQueuedClose();
if (read_bytes < 0) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kOperationError,
- "read() failed"));
+ DCHECK_NE(read_error, base::File::FILE_OK)
+ << "Negative bytes read reported with no error set";
+ blink::RejectNativeIOWithError(resolver, read_error);
return;
}
+ DCHECK_EQ(read_error, base::File::FILE_OK)
+ << "Error set but positive number of bytes read.";
resolver->Resolve(read_bytes);
}
@@ -533,6 +745,7 @@ void NativeIOFile::DoWrite(
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
int written_bytes;
+ int64_t actual_file_length_on_failure = 0;
base::File::Error write_error;
{
WTF::MutexLocker mutex_locker(file_state->mutex);
@@ -541,18 +754,28 @@ void NativeIOFile::DoWrite(
written_bytes = file_state->file.Write(file_offset, write_data, write_size);
write_error = (written_bytes < 0) ? file_state->file.GetLastFileError()
: base::File::FILE_OK;
+ if (written_bytes < write_size || write_error != base::File::FILE_OK) {
+ actual_file_length_on_failure = file_state->file.GetLength();
+ if (actual_file_length_on_failure < 0 &&
+ write_error != base::File::FILE_OK) {
+ write_error = file_state->file.GetLastFileError();
+ }
+ }
}
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
CrossThreadBindOnce(&NativeIOFile::DidWrite, std::move(native_io_file),
- std::move(resolver), written_bytes, write_error));
+ std::move(resolver), written_bytes, write_error,
+ write_size, actual_file_length_on_failure));
}
void NativeIOFile::DidWrite(
CrossThreadPersistent<ScriptPromiseResolver> resolver,
int written_bytes,
- base::File::Error write_error) {
+ base::File::Error write_error,
+ int write_size,
+ int64_t actual_file_length_on_failure) {
ScriptState* script_state = resolver->GetScriptState();
if (!script_state->ContextIsValid())
return;
@@ -561,14 +784,39 @@ void NativeIOFile::DidWrite(
DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
io_pending_ = false;
+ if (write_error != base::File::FILE_OK || written_bytes < write_size) {
+ if (actual_file_length_on_failure >= 0) {
+ DCHECK_LE(actual_file_length_on_failure, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_file_length_on_failure < file_length_) {
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_file_length_on_failure);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_file_length_on_failure;
+ }
+ } else {
+ DCHECK(write_error != base::File::FILE_OK);
+ // base::File::Write() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ if (!closed_) {
+ closed_ = true;
+ queued_close_resolver_ =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ }
+ }
+ }
+
DispatchQueuedClose();
- if (written_bytes < 0) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kOperationError,
- "write() failed"));
+ if (write_error != base::File::FILE_OK) {
+ blink::RejectNativeIOWithError(resolver, write_error);
return;
}
+ DCHECK_EQ(write_error, base::File::FILE_OK);
+
resolver->Resolve(written_bytes);
}
@@ -579,23 +827,25 @@ void NativeIOFile::DoFlush(
NativeIOFile::FileState* file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
- bool success = false;
+ base::File::Error flush_error;
{
WTF::MutexLocker mutex_locker(file_state->mutex);
DCHECK(file_state->file.IsValid())
<< "file I/O operation queued after file closed";
- success = file_state->file.Flush();
+ bool success = file_state->file.Flush();
+ flush_error =
+ success ? base::File::FILE_OK : file_state->file.GetLastFileError();
}
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
CrossThreadBindOnce(&NativeIOFile::DidFlush, std::move(native_io_file),
- std::move(resolver), success));
+ std::move(resolver), flush_error));
}
void NativeIOFile::DidFlush(
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- bool success) {
+ base::File::Error flush_error) {
ScriptState* script_state = resolver->GetScriptState();
if (!script_state->ContextIsValid())
return;
@@ -606,10 +856,8 @@ void NativeIOFile::DidFlush(
DispatchQueuedClose();
- if (!success) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kOperationError,
- "flush() failed"));
+ if (flush_error != base::File::FILE_OK) {
+ blink::RejectNativeIOWithError(resolver, flush_error);
return;
}
resolver->Resolve();
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.h
index 5de248c7223..9cbd2fc0485 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.h
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.h
@@ -9,11 +9,13 @@
#include "base/files/file.h"
#include "base/memory/scoped_refptr.h"
+#include "build/build_config.h"
#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.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"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -37,7 +39,9 @@ class NativeIOFile final : public ScriptWrappable {
public:
NativeIOFile(base::File backing_file,
+ int64_t backing_file_length,
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file,
+ NativeIOCapacityTracker* capacity_tracker,
ExecutionContext*);
NativeIOFile(const NativeIOFile&) = delete;
@@ -48,7 +52,7 @@ class NativeIOFile final : public ScriptWrappable {
ScriptPromise close(ScriptState*);
ScriptPromise getLength(ScriptState*, ExceptionState&);
- ScriptPromise setLength(ScriptState*, uint64_t length, ExceptionState&);
+ ScriptPromise setLength(ScriptState*, uint64_t new_length, ExceptionState&);
ScriptPromise read(ScriptState*,
MaybeShared<DOMArrayBufferView> buffer,
uint64_t file_offset,
@@ -96,10 +100,30 @@ class NativeIOFile final : public ScriptWrappable {
int64_t length,
base::File::Error get_length_error);
+ // Performs the file I/O part of getLength(), off the main thread.
+ static void DoSetLength(
+ CrossThreadPersistent<NativeIOFile> native_io_file,
+ CrossThreadPersistent<ScriptPromiseResolver> resolver,
+ NativeIOFile::FileState* file_state,
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+ int64_t expected_length);
// Performs the post file I/O part of setLength(), on the main thread.
- void DidSetLength(ScriptPromiseResolver* resolver,
- bool backend_success,
- base::File backing_file);
+ //
+ // `actual_length` is negative if the I/O operation was unsuccessful and the
+ // correct length of the file could not be determined.
+ void DidSetLengthIo(CrossThreadPersistent<ScriptPromiseResolver> resolver,
+ int64_t actual_length,
+ base::File::Error set_length_result);
+#if defined(OS_MAC)
+ // Performs the post IPC part of setLength(), on the main thread.
+ //
+ // `actual_length` is negative if the I/O operation was unsuccessful and the
+ // correct length of the file could not be determined.
+ void DidSetLengthIpc(ScriptPromiseResolver* resolver,
+ base::File backing_file,
+ int64_t actual_length,
+ mojom::blink::NativeIOErrorPtr set_length_result);
+#endif // defined(OS_MAC)
// Performs the file I/O part of read(), off the main thread.
static void DoRead(
@@ -122,14 +146,19 @@ class NativeIOFile final : public ScriptWrappable {
CrossThreadPersistent<ScriptPromiseResolver> resolver,
CrossThreadPersistent<DOMSharedArrayBuffer> write_data_keepalive,
NativeIOFile::FileState* file_state,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
const char* write_data,
uint64_t file_offset,
int write_size);
// Performs the post file I/O part of write(), on the main thread.
+ //
+ // `actual_file_length_on_failure` is negative if the I/O operation was
+ // unsuccessful and the correct length of the file could not be determined.
void DidWrite(CrossThreadPersistent<ScriptPromiseResolver> resolver,
int written_bytes,
- base::File::Error write_error);
+ base::File::Error write_error,
+ int write_size,
+ int64_t actual_file_length_on_failure);
// Performs the file I/O part of flush().
static void DoFlush(
@@ -139,7 +168,7 @@ class NativeIOFile final : public ScriptWrappable {
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file-I/O part of flush(), on the main thread.
void DidFlush(CrossThreadPersistent<ScriptPromiseResolver> resolver,
- bool success);
+ base::File::Error flush_error);
// Kicks off closing the file from the main thread.
void CloseBackingFile();
@@ -163,7 +192,26 @@ class NativeIOFile final : public ScriptWrappable {
// Set to true when close() is called, or when the backend goes away.
bool closed_ = false;
- // See NativeIO::FileState, declared above.
+ // The length of the file used in capacity accounting. Most of the time, this
+ // is the file's length. When `io_pending_` is true, `file_length_` may be
+ // larger than the actual length, to reflect capacity allocated for an
+ // in-progress I/O operation, or capacity that will be released by an
+ // in-progress I/O operation.
+ //
+ // Operations that increase the file's length must first allocate capacity,
+ // update `file_length_` to reflect the increased length, and then perform the
+ // I/O. If the I/O fails, GetLength() must be used to obtain the actual file
+ // length. The result must first be compared against `file_length_` to account
+ // for the unused capacity, then used to update `file_length_`.
+ //
+ // Operations that decrease the file's length must first perform the I/O, and
+ // then update `file_length_` and return freed up capacity. I/O failures can
+ // be handled using the same logic as above.
+ //
+ // TODO(rstz): Consider moving this variable into `file_state_`
+ int64_t file_length_ = 0;
+
+ // See NativeIOFile::FileState, declared above.
const std::unique_ptr<FileState> file_state_;
// Schedules resolving Promises with file I/O results.
@@ -171,6 +219,9 @@ class NativeIOFile final : public ScriptWrappable {
// Mojo pipe that holds the renderer's lock on the file.
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file_;
+
+ // Tracks the capacity for this file's execution context.
+ Member<NativeIOCapacityTracker> capacity_tracker_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.idl b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.idl
index 64ba83a4798..b7521f26d88 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file.idl
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file.idl
@@ -6,7 +6,7 @@
[
Exposed=(Window, Worker),
- RuntimeEnabled=NativeIO,
+ RuntimeEnabled=StorageFoundationAPI,
SecureContext
] interface NativeIOFile {
[CallWith=ScriptState] Promise<void> close();
@@ -20,14 +20,14 @@
] Promise<void> setLength(unsigned long long length);
[
- CallWith=ScriptState, RaisesException
+ CallWith=ScriptState, RaisesException, MeasureAs=StorageFoundationRead
] Promise<unsigned long long> read([AllowShared] ArrayBufferView buffer,
unsigned long long file_offset);
[
- CallWith=ScriptState, RaisesException
+ CallWith=ScriptState, RaisesException, MeasureAs=StorageFoundationWrite
] Promise<unsigned long long> write([AllowShared] ArrayBufferView buffer,
unsigned long long file_offset);
[
- CallWith=ScriptState, RaisesException
+ CallWith=ScriptState, RaisesException, MeasureAs=StorageFoundationFlush
] Promise<void> flush();
};
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.cc
new file mode 100644
index 00000000000..06bed3faf12
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.cc
@@ -0,0 +1,755 @@
+// Copyright 2020 The Chromium Authors. 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/native_io/native_io_file_manager.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/files/file.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.h"
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.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/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/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_error.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_file.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_file_sync.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/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+namespace {
+
+bool IsValidNativeIONameCharacter(int name_char) {
+ return (name_char >= 'a' && name_char <= 'z') ||
+ (name_char >= '0' && name_char <= '9') || name_char == '_';
+}
+
+// Maximum allowed filename length, inclusive.
+const int kMaximumFilenameLength = 100;
+
+bool IsValidNativeIOName(const String& name) {
+ if (name.IsEmpty())
+ return false;
+
+ if (name.length() > kMaximumFilenameLength)
+ return false;
+
+ if (name.Is8Bit()) {
+ return std::all_of(name.Span8().begin(), name.Span8().end(),
+ &IsValidNativeIONameCharacter);
+ }
+ return std::all_of(name.Span16().begin(), name.Span16().end(),
+ &IsValidNativeIONameCharacter);
+}
+
+void ThrowStorageAccessError(ExceptionState& exception_state) {
+ // TODO(fivedots): Switch to security error after it's available as a
+ // NativeIOErrorType.
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kUnknown,
+ "Storage access is denied"));
+}
+
+void OnGetAllResult(ScriptPromiseResolver* resolver,
+ bool backend_success,
+ const Vector<String>& file_names) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (!backend_success) {
+ resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
+ script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
+ "getAll() failed"));
+ return;
+ }
+
+ resolver->Resolve(file_names);
+}
+
+void OnRenameResult(ScriptPromiseResolver* resolver,
+ mojom::blink::NativeIOErrorPtr rename_error) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (rename_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ blink::RejectNativeIOWithError(resolver, std::move(rename_error));
+ return;
+ }
+ resolver->Resolve();
+}
+
+} // namespace
+
+NativeIOFileManager::NativeIOFileManager(
+ ExecutionContext* execution_context,
+ HeapMojoRemote<mojom::blink::NativeIOHost> backend,
+ NativeIOCapacityTracker* capacity_tracker)
+ : ExecutionContextClient(execution_context),
+ capacity_tracker_(capacity_tracker),
+ // TODO(pwnall): Get a dedicated queue when the specification matures.
+ receiver_task_runner_(
+ execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)),
+ backend_(std::move(backend)) {
+ backend_.set_disconnect_handler(WTF::Bind(
+ &NativeIOFileManager::OnBackendDisconnect, WrapWeakPersistent(this)));
+}
+
+NativeIOFileManager::~NativeIOFileManager() = default;
+
+ScriptPromise NativeIOFileManager::open(ScriptState* script_state,
+ String name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return ScriptPromise();
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+
+ CheckStorageAccessAllowed(
+ execution_context, resolver,
+ WTF::Bind(&NativeIOFileManager::OpenImpl, WrapWeakPersistent(this), name,
+ WrapPersistent(resolver)));
+
+ return promise;
+}
+
+ScriptPromise NativeIOFileManager::Delete(ScriptState* script_state,
+ String name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return ScriptPromise();
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ CheckStorageAccessAllowed(
+ execution_context, resolver,
+ WTF::Bind(&NativeIOFileManager::DeleteImpl, WrapWeakPersistent(this),
+ name, WrapPersistent(resolver)));
+
+ return promise;
+}
+
+ScriptPromise NativeIOFileManager::getAll(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ CheckStorageAccessAllowed(
+ execution_context, resolver,
+ WTF::Bind(&NativeIOFileManager::GetAllImpl, WrapWeakPersistent(this),
+ WrapPersistent(resolver)));
+
+ return promise;
+}
+
+ScriptPromise NativeIOFileManager::rename(ScriptState* script_state,
+ String old_name,
+ String new_name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(old_name) || !IsValidNativeIOName(new_name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return ScriptPromise();
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ auto promise = resolver->Promise();
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ CheckStorageAccessAllowed(
+ execution_context, resolver,
+ WTF::Bind(&NativeIOFileManager::RenameImpl, WrapWeakPersistent(this),
+ old_name, new_name, WrapPersistent(resolver)));
+
+ return promise;
+}
+
+NativeIOFileSync* NativeIOFileManager::openSync(
+ String name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return nullptr;
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return nullptr;
+ }
+
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ if (!CheckStorageAccessAllowedSync(execution_context)) {
+ ThrowStorageAccessError(exception_state);
+ return nullptr;
+ }
+
+ HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file(
+ execution_context);
+ mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver =
+ backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_);
+
+ base::File backing_file;
+ uint64_t backing_file_length;
+ mojom::blink::NativeIOErrorPtr open_error;
+ bool call_succeeded =
+ backend_->OpenFile(name, std::move(backend_file_receiver), &backing_file,
+ &backing_file_length, &open_error);
+
+ if (open_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ ThrowNativeIOWithError(exception_state, std::move(open_error));
+ return nullptr;
+ }
+ DCHECK(call_succeeded) << "Mojo call failed";
+ DCHECK(backing_file.IsValid()) << "File is invalid but no error set";
+
+ return MakeGarbageCollected<NativeIOFileSync>(
+ std::move(backing_file), base::as_signed(backing_file_length),
+ std::move(backend_file), capacity_tracker_.Get(), execution_context);
+}
+
+void NativeIOFileManager::deleteSync(String name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return;
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return;
+ }
+
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ if (!CheckStorageAccessAllowedSync(execution_context)) {
+ ThrowStorageAccessError(exception_state);
+ return;
+ }
+
+ mojom::blink::NativeIOErrorPtr delete_error;
+ uint64_t deleted_file_size;
+ bool call_succeeded =
+ backend_->DeleteFile(name, &delete_error, &deleted_file_size);
+
+ if (delete_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ ThrowNativeIOWithError(exception_state, std::move(delete_error));
+ return;
+ }
+ DCHECK(call_succeeded) << "Mojo call failed";
+
+ if (deleted_file_size > 0) {
+ capacity_tracker_->ChangeAvailableCapacity(
+ base::as_signed(deleted_file_size));
+ }
+}
+
+Vector<String> NativeIOFileManager::getAllSync(
+ ExceptionState& exception_state) {
+ Vector<String> result;
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return result;
+ }
+
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ if (!CheckStorageAccessAllowedSync(execution_context)) {
+ ThrowStorageAccessError(exception_state);
+ return result;
+ }
+
+ bool backend_success = false;
+ bool call_succeeded = backend_->GetAllFileNames(&backend_success, &result);
+ DCHECK(call_succeeded) << "Mojo call failed";
+
+ if (!backend_success) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
+ "getAllSync() failed");
+ }
+ return result;
+}
+
+void NativeIOFileManager::renameSync(String old_name,
+ String new_name,
+ ExceptionState& exception_state) {
+ if (!IsValidNativeIOName(old_name) || !IsValidNativeIOName(new_name)) {
+ exception_state.ThrowTypeError("Invalid file name");
+ return;
+ }
+
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return;
+ }
+
+ ExecutionContext* execution_context = GetExecutionContext();
+ DCHECK(execution_context);
+
+ if (!CheckStorageAccessAllowedSync(execution_context)) {
+ ThrowStorageAccessError(exception_state);
+ return;
+ }
+
+ mojom::blink::NativeIOErrorPtr backend_success;
+ bool call_succeeded =
+ backend_->RenameFile(old_name, new_name, &backend_success);
+
+ if (backend_success->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ ThrowNativeIOWithError(exception_state, std::move(backend_success));
+ return;
+ }
+ DCHECK(call_succeeded) << "Mojo call failed";
+}
+
+ScriptPromise NativeIOFileManager::requestCapacity(
+ ScriptState* script_state,
+ uint64_t requested_capacity,
+ ExceptionState& exception_state) {
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+ if (!base::IsValueInRangeForNumericType<int64_t>(requested_capacity)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ backend_->RequestCapacityChange(
+ requested_capacity,
+ WTF::Bind(&NativeIOFileManager::OnRequestCapacityChangeResult,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return resolver->Promise();
+}
+
+ScriptPromise NativeIOFileManager::releaseCapacity(
+ ScriptState* script_state,
+ uint64_t requested_release,
+ ExceptionState& exception_state) {
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return ScriptPromise();
+ }
+ if (!base::IsValueInRangeForNumericType<int64_t>(requested_release)) {
+ ThrowNativeIOWithError(
+ exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "Attempted to release more capacity than available"));
+ return ScriptPromise();
+ }
+
+ int64_t requested_difference = -base::as_signed(requested_release);
+
+ // Reducing available capacity must be done before performing the IPC, so
+ // capacity cannot be double-spent by concurrent NativeIO operations.
+ if (!capacity_tracker_->ChangeAvailableCapacity(requested_difference)) {
+ ThrowNativeIOWithError(
+ exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "Attempted to release more capacity than available."));
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ backend_->RequestCapacityChange(
+ -requested_release,
+ WTF::Bind(&NativeIOFileManager::OnRequestCapacityChangeResult,
+ WrapPersistent(this), WrapPersistent(resolver)));
+ return resolver->Promise();
+}
+
+ScriptPromise NativeIOFileManager::getRemainingCapacity(
+ ScriptState* script_state,
+ ExceptionState& exception_state) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ // TODO(rstz): Consider using ScriptPromise::Cast instead.
+ const ScriptPromise promise = resolver->Promise();
+ uint64_t available_capacity =
+ base::as_unsigned(capacity_tracker_->GetAvailableCapacity());
+ resolver->Resolve(available_capacity);
+ return promise;
+}
+
+void NativeIOFileManager::CheckStorageAccessAllowed(
+ ExecutionContext* context,
+ ScriptPromiseResolver* resolver,
+ base::OnceCallback<void()> callback) {
+ DCHECK(context->IsWindow() || context->IsWorkerGlobalScope());
+
+ auto wrapped_callback = WTF::Bind(
+ &NativeIOFileManager::DidCheckStorageAccessAllowed,
+ WrapWeakPersistent(this), WrapPersistent(resolver), std::move(callback));
+
+ // TODO(crbug/1180185): consider removing caching, if the worker
+ // WebContentSettingsClient does it for us.
+ if (storage_access_allowed_.has_value()) {
+ std::move(wrapped_callback).Run(storage_access_allowed_.value());
+ return;
+ }
+
+ WebContentSettingsClient* content_settings_client = nullptr;
+ if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+ LocalFrame* frame = window->GetFrame();
+ if (!frame) {
+ std::move(wrapped_callback).Run(false);
+ return;
+ }
+ content_settings_client = frame->GetContentSettingsClient();
+ } else {
+ content_settings_client =
+ To<WorkerGlobalScope>(context)->ContentSettingsClient();
+ }
+
+ // TODO(fivedots): Switch storage type once we stop aliasing under Filesystem.
+ if (content_settings_client) {
+ content_settings_client->AllowStorageAccess(
+ WebContentSettingsClient::StorageType::kFileSystem,
+ std::move(wrapped_callback));
+ return;
+ }
+ std::move(wrapped_callback).Run(true);
+}
+
+void NativeIOFileManager::DidCheckStorageAccessAllowed(
+ ScriptPromiseResolver* resolver,
+ base::OnceCallback<void()> callback,
+ bool allowed_access) {
+ storage_access_allowed_ = allowed_access;
+
+ if (allowed_access) {
+ std::move(callback).Run();
+ return;
+ }
+
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ blink::RejectNativeIOWithError(resolver,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kUnknown,
+ "Storage access is denied"));
+ return;
+}
+
+bool NativeIOFileManager::CheckStorageAccessAllowedSync(
+ ExecutionContext* context) {
+ DCHECK(context->IsWindow() || context->IsWorkerGlobalScope());
+
+ if (storage_access_allowed_.has_value()) {
+ return storage_access_allowed_.value();
+ }
+
+ WebContentSettingsClient* content_settings_client = nullptr;
+ if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+ LocalFrame* frame = window->GetFrame();
+ if (!frame) {
+ return false;
+ }
+ content_settings_client = frame->GetContentSettingsClient();
+ } else {
+ content_settings_client =
+ To<WorkerGlobalScope>(context)->ContentSettingsClient();
+ }
+
+ if (content_settings_client) {
+ return content_settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kFileSystem);
+ }
+ return true;
+}
+
+uint64_t NativeIOFileManager::requestCapacitySync(
+ uint64_t requested_capacity,
+ ExceptionState& exception_state) {
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return 0;
+ }
+ if (!base::IsValueInRangeForNumericType<int64_t>(requested_capacity)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return 0;
+ }
+
+ int64_t granted_capacity_delta;
+
+ bool call_succeeded = backend_->RequestCapacityChange(
+ requested_capacity, &granted_capacity_delta);
+ DCHECK(call_succeeded) << "Mojo call failed";
+
+ capacity_tracker_->ChangeAvailableCapacity(granted_capacity_delta);
+ return capacity_tracker_->GetAvailableCapacity();
+}
+
+uint64_t NativeIOFileManager::releaseCapacitySync(
+ uint64_t requested_release,
+ ExceptionState& exception_state) {
+ if (!backend_.is_bound()) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return 0;
+ }
+ if (!base::IsValueInRangeForNumericType<int64_t>(requested_release)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return 0;
+ }
+
+ int64_t requested_difference = -base::as_signed(requested_release);
+
+ int64_t granted_capacity_delta;
+ bool call_succeeded = backend_->RequestCapacityChange(
+ requested_difference, &granted_capacity_delta);
+ DCHECK(call_succeeded) << "Mojo call failed";
+
+ capacity_tracker_->ChangeAvailableCapacity(granted_capacity_delta);
+ return capacity_tracker_->GetAvailableCapacity();
+}
+
+uint64_t NativeIOFileManager::getRemainingCapacitySync(
+ ExceptionState& exception_state) {
+ uint64_t available_capacity =
+ base::as_unsigned(capacity_tracker_->GetAvailableCapacity());
+ return available_capacity;
+}
+
+void NativeIOFileManager::OnBackendDisconnect() {
+ backend_.reset();
+}
+
+void NativeIOFileManager::OnOpenResult(
+ ScriptPromiseResolver* resolver,
+ DisallowNewWrapper<HeapMojoRemote<mojom::blink::NativeIOFileHost>>*
+ backend_file_wrapper,
+ base::File backing_file,
+ uint64_t backing_file_length,
+ mojom::blink::NativeIOErrorPtr open_error) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (open_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ blink::RejectNativeIOWithError(resolver, std::move(open_error));
+ return;
+ }
+ DCHECK(backing_file.IsValid()) << "browser returned closed file but no error";
+
+ NativeIOFile* file = MakeGarbageCollected<NativeIOFile>(
+ std::move(backing_file), base::as_signed(backing_file_length),
+ backend_file_wrapper->TakeValue(), capacity_tracker_.Get(),
+ ExecutionContext::From(script_state));
+ resolver->Resolve(file);
+}
+
+void NativeIOFileManager::OnDeleteResult(
+ ScriptPromiseResolver* resolver,
+ mojom::blink::NativeIOErrorPtr delete_error,
+ uint64_t deleted_file_size) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+
+ if (delete_error->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ blink::RejectNativeIOWithError(resolver, std::move(delete_error));
+ return;
+ }
+
+ if (deleted_file_size > 0) {
+ capacity_tracker_->ChangeAvailableCapacity(
+ base::as_signed(deleted_file_size));
+ }
+
+ resolver->Resolve();
+}
+
+void NativeIOFileManager::OnRequestCapacityChangeResult(
+ ScriptPromiseResolver* resolver,
+ int64_t granted_capacity) {
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(script_state);
+ // If `granted_capacity` < 0, the available capacity has already been released
+ // prior to the IPC.
+ if (granted_capacity > 0) {
+ capacity_tracker_->ChangeAvailableCapacity(
+ base::as_signed(granted_capacity));
+ }
+ uint64_t available_capacity = capacity_tracker_->GetAvailableCapacity();
+
+ resolver->Resolve(available_capacity);
+}
+
+void NativeIOFileManager::OpenImpl(String name,
+ ScriptPromiseResolver* resolver) {
+ DCHECK(storage_access_allowed_.has_value())
+ << "called without checking if storage access was allowed";
+ DCHECK(storage_access_allowed_.value())
+ << "called even though storage access was denied";
+
+ ScriptState* script_state = resolver->GetScriptState();
+ if (!script_state->ContextIsValid())
+ return;
+
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file(
+ execution_context);
+
+ mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver =
+ backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_);
+
+ backend_->OpenFile(
+ name, std::move(backend_file_receiver),
+ WTF::Bind(&NativeIOFileManager::OnOpenResult, WrapPersistent(this),
+ WrapPersistent(resolver),
+ WrapPersistent(WrapDisallowNew(std::move(backend_file)))));
+}
+
+void NativeIOFileManager::DeleteImpl(String name,
+ ScriptPromiseResolver* resolver) {
+ DCHECK(storage_access_allowed_.has_value())
+ << "called without checking if storage access was allowed";
+ DCHECK(storage_access_allowed_.value())
+ << "called even though storage access was denied";
+
+ backend_->DeleteFile(
+ name, WTF::Bind(&NativeIOFileManager::OnDeleteResult,
+ WrapPersistent(this), WrapPersistent(resolver)));
+}
+
+void NativeIOFileManager::GetAllImpl(ScriptPromiseResolver* resolver) {
+ DCHECK(storage_access_allowed_.has_value())
+ << "called without checking if storage access was allowed";
+ DCHECK(storage_access_allowed_.value())
+ << "called even though storage access was denied";
+
+ backend_->GetAllFileNames(
+ WTF::Bind(&OnGetAllResult, WrapPersistent(resolver)));
+}
+
+void NativeIOFileManager::RenameImpl(String old_name,
+ String new_name,
+ ScriptPromiseResolver* resolver) {
+ DCHECK(storage_access_allowed_.has_value())
+ << "called without checking if storage access was allowed";
+ DCHECK(storage_access_allowed_.value())
+ << "called even though storage access was denied";
+
+ backend_->RenameFile(old_name, new_name,
+ WTF::Bind(&OnRenameResult, WrapPersistent(resolver)));
+}
+
+void NativeIOFileManager::Trace(Visitor* visitor) const {
+ visitor->Trace(backend_);
+ visitor->Trace(capacity_tracker_);
+ ScriptWrappable::Trace(visitor);
+ ExecutionContextClient::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.h
new file mode 100644
index 00000000000..3bc2bc33299
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.h
@@ -0,0 +1,136 @@
+// Copyright 2020 The Chromium Authors. 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_NATIVE_IO_NATIVE_IO_FILE_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_MANAGER_H_
+
+#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class ExecutionContext;
+class ExceptionState;
+class ScriptPromiseResolver;
+class NativeIOFileSync;
+class ScriptState;
+
+class NativeIOFileManager final : public ScriptWrappable,
+ public ExecutionContextClient {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit NativeIOFileManager(
+ ExecutionContext*,
+ HeapMojoRemote<mojom::blink::NativeIOHost> backend,
+ NativeIOCapacityTracker* capacity_tracker);
+
+ NativeIOFileManager(const NativeIOFileManager&) = delete;
+ NativeIOFileManager& operator=(const NativeIOFileManager&) = delete;
+
+ // Needed because of the
+ // mojo::Remote<blink::mojom::NativeIOHost>
+ ~NativeIOFileManager() override;
+
+ ScriptPromise open(ScriptState*, String name, ExceptionState&);
+ ScriptPromise Delete(ScriptState*, String name, ExceptionState&);
+ ScriptPromise getAll(ScriptState*, ExceptionState&);
+ ScriptPromise rename(ScriptState*,
+ String old_name,
+ String new_name,
+ ExceptionState&);
+ ScriptPromise requestCapacity(ScriptState*,
+ uint64_t requested_capacity,
+ ExceptionState&);
+ ScriptPromise releaseCapacity(ScriptState*,
+ uint64_t released_capacity,
+ ExceptionState&);
+ ScriptPromise getRemainingCapacity(ScriptState*, ExceptionState&);
+
+ NativeIOFileSync* openSync(String name, ExceptionState&);
+ void deleteSync(String name, ExceptionState&);
+ Vector<String> getAllSync(ExceptionState&);
+ void renameSync(String old_name, String new_name, ExceptionState&);
+ uint64_t requestCapacitySync(uint64_t requested_capacity, ExceptionState&);
+ uint64_t releaseCapacitySync(uint64_t released_capacity, ExceptionState&);
+ uint64_t getRemainingCapacitySync(ExceptionState&);
+
+ // GarbageCollected
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ // Checks whether storage access should be allowed in the provided context,
+ // and calls the callback with the result.
+ void CheckStorageAccessAllowed(ExecutionContext* context,
+ ScriptPromiseResolver* resolver,
+ base::OnceCallback<void()> callback);
+
+ // Called after CheckStoraAccessAllowed is done checking access. Calls the
+ // callback if access is allowed, rejects through the resolver if not.
+ void DidCheckStorageAccessAllowed(ScriptPromiseResolver* resolver,
+ base::OnceCallback<void()> callback,
+ bool allowed_access);
+
+ // Checks whether storage access should be allowed in the provided context.
+ bool CheckStorageAccessAllowedSync(ExecutionContext* context);
+
+ // Executes the actual open, after preconditions have been checked.
+ void OpenImpl(String name, ScriptPromiseResolver* resolver);
+
+ // Executes the actual delete, after preconditions have been checked.
+ void DeleteImpl(String name, ScriptPromiseResolver* resolver);
+
+ // Executes the actual getAll, after preconditions have been checked.
+ void GetAllImpl(ScriptPromiseResolver* resolver);
+
+ // Executes the actual rename, after preconditions have been checked.
+ void RenameImpl(String old_name,
+ String new_name,
+ ScriptPromiseResolver* resolver);
+
+ // Called when the mojo backend disconnects.
+ void OnBackendDisconnect();
+
+ // Called after the mojo call to OpenFile completed.
+ void OnOpenResult(
+ ScriptPromiseResolver* resolver,
+ DisallowNewWrapper<HeapMojoRemote<mojom::blink::NativeIOFileHost>>*
+ backend_file_wrapper,
+ base::File backing_file,
+ uint64_t backing_file_length,
+ mojom::blink::NativeIOErrorPtr open_error);
+
+ // Called after the mojo call to DeleteFile completed.
+ void OnDeleteResult(ScriptPromiseResolver* resolver,
+ mojom::blink::NativeIOErrorPtr delete_error,
+ uint64_t deleted_file_size);
+
+ // Called after the mojo call to RequestCapacityChange completed.
+ void OnRequestCapacityChangeResult(ScriptPromiseResolver* resolver,
+ int64_t granted_capacity);
+
+ // Tracks the capacity for this file manager's execution context.
+ Member<NativeIOCapacityTracker> capacity_tracker_;
+
+ // Task runner used by NativeIOFile mojo receivers generated by this API.
+ const scoped_refptr<base::SequencedTaskRunner> receiver_task_runner_;
+
+ // Wraps an always-on Mojo pipe for sending requests to the storage backend.
+ HeapMojoRemote<mojom::blink::NativeIOHost> backend_;
+
+ // Caches results of checking if storage access is allowed.
+ base::Optional<bool> storage_access_allowed_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.idl b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.idl
new file mode 100644
index 00000000000..2cd23c67d69
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_manager.idl
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/fivedots/nativeio-explainer
+
+[Exposed = (Window, Worker),
+ RuntimeEnabled = StorageFoundationAPI,
+ SecureContext] interface NativeIOFileManager {
+ [ CallWith = ScriptState, RaisesException, MeasureAs = StorageFoundationOpen ]
+ Promise<NativeIOFile> open(DOMString name);
+ [ Exposed = DedicatedWorker, RaisesException, MeasureAs = StorageFoundationOpen ]
+ NativeIOFileSync openSync(DOMString name);
+
+ [ CallWith = ScriptState, ImplementedAs = Delete,
+ RaisesException ] Promise<void> delete (DOMString name);
+ [ Exposed = DedicatedWorker, RaisesException ] void deleteSync(
+ DOMString name);
+
+ [ CallWith = ScriptState, RaisesException ] Promise<sequence<DOMString>>
+ getAll();
+ [ Exposed = DedicatedWorker, RaisesException ] sequence<DOMString>
+ getAllSync();
+
+ [ CallWith = ScriptState, RaisesException ] Promise<void> rename(
+ DOMString old_name, DOMString new_name);
+ [ Exposed = DedicatedWorker, RaisesException ] void renameSync(
+ DOMString old_name, DOMString new_name);
+
+ [ CallWith = ScriptState, RaisesException ] Promise<unsigned long long>
+ requestCapacity(unsigned long long requested_capacity);
+ [ Exposed = DedicatedWorker, RaisesException ] unsigned long long
+ requestCapacitySync(unsigned long long released_capacity);
+
+ [ CallWith = ScriptState, RaisesException ] Promise<unsigned long long>
+ releaseCapacity(unsigned long long released_capacity);
+ [ Exposed = DedicatedWorker, RaisesException ] unsigned long long
+ releaseCapacitySync(unsigned long long released_capacity);
+
+ [ CallWith = ScriptState, RaisesException ] Promise<unsigned long long>
+ getRemainingCapacity();
+ [ Exposed = DedicatedWorker, RaisesException ] unsigned long long
+ getRemainingCapacitySync();
+};
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.cc
index fd019bc639f..5e430902694 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.cc
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.cc
@@ -7,10 +7,14 @@
#include <limits>
#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
+#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_error.h"
#include "third_party/blink/renderer/modules/native_io/native_io_file.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -18,6 +22,10 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
+#if defined(OS_MAC)
+#include "base/mac/mac_util.h"
+#endif
+
namespace blink {
// Extracts the read/write operation size from the buffer size.
@@ -28,10 +36,16 @@ int OperationSize(const DOMArrayBufferView& buffer) {
NativeIOFileSync::NativeIOFileSync(
base::File backing_file,
+ int64_t backing_file_length,
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file,
+ NativeIOCapacityTracker* capacity_tracker,
ExecutionContext* execution_context)
: backing_file_(std::move(backing_file)),
- backend_file_(std::move(backend_file)) {
+ file_length_(backing_file_length),
+ backend_file_(std::move(backend_file)),
+ capacity_tracker_(capacity_tracker) {
+ DCHECK_GE(backing_file_length, 0);
+ DCHECK(capacity_tracker);
backend_file_.set_disconnect_handler(WTF::Bind(
&NativeIOFileSync::OnBackendDisconnect, WrapWeakPersistent(this)));
}
@@ -51,16 +65,19 @@ void NativeIOFileSync::close() {
uint64_t NativeIOFileSync::getLength(ExceptionState& exception_state) {
if (!backing_file_.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
return 0;
}
int64_t length = backing_file_.GetLength();
if (length < 0) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "getLength() failed");
+ ThrowNativeIOWithError(exception_state, backing_file_.GetLastFileError());
return 0;
}
+ DCHECK_EQ(file_length_, length)
+ << "The file size should equal the actual length";
// getLength returns an unsigned integer, which is different from e.g.,
// base::File and POSIX. The uses for negative integers are error handling,
// which is done through exceptions, and seeking from an offset without type
@@ -68,48 +85,148 @@ uint64_t NativeIOFileSync::getLength(ExceptionState& exception_state) {
return base::as_unsigned(length);
}
-void NativeIOFileSync::setLength(uint64_t length,
+void NativeIOFileSync::setLength(uint64_t new_length,
ExceptionState& exception_state) {
- if (!base::IsValueInRangeForNumericType<int64_t>(length)) {
+ if (!base::IsValueInRangeForNumericType<int64_t>(new_length)) {
+ // TODO(rstz): Consider throwing QuotaExceededError here.
exception_state.ThrowTypeError("Length out of bounds");
return;
}
if (!backing_file_.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "NativeIOHost backend went away"));
+ return;
+ }
+ int64_t expected_length = base::as_signed(new_length);
+
+ DCHECK_GE(expected_length, 0);
+ DCHECK_GE(file_length_, 0);
+ static_assert(0 - std::numeric_limits<int32_t>::max() >=
+ std::numeric_limits<int32_t>::min(),
+ "The `length_delta` computation below may overflow");
+ // Since both values are non-negative, the arithmetic will not overflow.
+ int64_t length_delta = expected_length - file_length_;
+
+ if (length_delta > 0) {
+ if (!capacity_tracker_->ChangeAvailableCapacity(-length_delta)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return;
+ }
+ file_length_ = expected_length;
+ }
+
+#if defined(OS_MAC)
+ // On macOS < 10.15, a sandboxing limitation causes failures in ftruncate()
+ // syscalls issued from renderers. For this reason, base::File::SetLength()
+ // fails in the renderer. We work around this problem by calling ftruncate()
+ // in the browser process. See crbug.com/1084565.
+ if (!base::mac::IsAtLeastOS10_15()) {
+ // Our system has at most one handle to a file, so we can avoid reasoning
+ // through the implications of multiple handles pointing to the same file.
+ //
+ // To preserve this invariant, we pass this file's handle to the browser
+ // process during the SetLength() mojo call, and the browser passes it back
+ // when the call completes.
+ mojom::blink::NativeIOErrorPtr set_length_result;
+ int64_t actual_length;
+ backend_file_->SetLength(base::as_signed(expected_length),
+ std::move(backing_file_), &backing_file_,
+ &actual_length, &set_length_result);
+ DCHECK(backing_file_.IsValid()) << "browser returned closed file";
+
+ if (actual_length >= 0) {
+ DCHECK_LE(actual_length, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_length < file_length_) {
+ // For successful length decreases, this logic returns freed up
+ // capacity. For unsuccessful length increases, this logic returns
+ // unused capacity.
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_length);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_length;
+ }
+ } else {
+ DCHECK(set_length_result->type !=
+ mojom::blink::NativeIOErrorType::kSuccess);
+ // base::File::SetLength() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ backing_file_.Close();
+ if (backend_file_.is_bound())
+ backend_file_->Close();
+ }
+
+ if (set_length_result->type != mojom::blink::NativeIOErrorType::kSuccess) {
+ ThrowNativeIOWithError(exception_state, std::move(set_length_result));
+ return;
+ }
+ return;
+ }
+#endif // defined(OS_MAC)
+
+ base::File::Error set_length_result = base::File::FILE_OK;
+ int64_t actual_length = expected_length;
+
+ if (!backing_file_.SetLength(expected_length)) {
+ set_length_result = backing_file_.GetLastFileError();
+ actual_length = backing_file_.GetLength();
+ if (actual_length < 0)
+ set_length_result = backing_file_.GetLastFileError();
+ }
+
+ if (actual_length >= 0) {
+ DCHECK_LE(actual_length, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_length < file_length_) {
+ // For successful length decreases, this logic returns freed up
+ // capacity. For unsuccessful length increases, this logic returns
+ // unused capacity.
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_length);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_length;
+ }
+ } else {
+ DCHECK(set_length_result != base::File::FILE_OK);
+ // base::File::SetLength() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ backing_file_.Close();
+ if (backend_file_.is_bound())
+ backend_file_->Close();
+ }
+ if (set_length_result != base::File::FILE_OK) {
+ ThrowNativeIOWithError(exception_state, set_length_result);
return;
}
- bool backend_success = false;
-
- // Calls to setLength are routed through the browser process, see
- // crbug.com/1084565.
- //
- // We keep a single handle per file, so this handle is passed to the backend
- // and is then given back to the renderer afterwards.
- backend_file_->SetLength(base::as_signed(length), std::move(backing_file_),
- &backend_success, &backing_file_);
- DCHECK(backing_file_.IsValid()) << "browser returned closed file";
- if (!backend_success) {
- exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
- "setLength() failed");
- }
- return;
}
uint64_t NativeIOFileSync::read(MaybeShared<DOMArrayBufferView> buffer,
uint64_t file_offset,
ExceptionState& exception_state) {
- int read_size = OperationSize(*buffer.View());
- char* read_data = static_cast<char*>(buffer.View()->BaseAddressMaybeShared());
+ int read_size = OperationSize(*buffer);
+ char* read_data = static_cast<char*>(buffer->BaseAddressMaybeShared());
if (!backing_file_.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return 0;
}
int read_bytes = backing_file_.Read(file_offset, read_data, read_size);
if (read_bytes < 0) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "read() failed");
+ ThrowNativeIOWithError(exception_state, backing_file_.GetLastFileError());
+ return 0;
}
return base::as_unsigned(read_bytes);
}
@@ -117,19 +234,83 @@ uint64_t NativeIOFileSync::read(MaybeShared<DOMArrayBufferView> buffer,
uint64_t NativeIOFileSync::write(MaybeShared<DOMArrayBufferView> buffer,
uint64_t file_offset,
ExceptionState& exception_state) {
- int write_size = OperationSize(*buffer.View());
- char* write_data =
- static_cast<char*>(buffer.View()->BaseAddressMaybeShared());
+ int write_size = OperationSize(*buffer);
+ char* write_data = static_cast<char*>(buffer->BaseAddressMaybeShared());
if (!backing_file_.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
+ return 0;
+ }
+
+ int64_t write_end_offset;
+ if (!base::CheckAdd(file_offset, write_size)
+ .AssignIfValid(&write_end_offset)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
return 0;
}
+
+ DCHECK_GE(write_end_offset, 0);
+ DCHECK_GE(file_length_, 0);
+ static_assert(0 - std::numeric_limits<int32_t>::max() >=
+ std::numeric_limits<int32_t>::min(),
+ "The `length_delta` computation below may overflow");
+ // Since both values are positive, the arithmetic will not overflow.
+ int64_t length_delta = write_end_offset - file_length_;
+ // The available capacity must be reduced before performing an I/O operation
+ // that increases the file length. This prevents double-spending by concurrent
+ // I/O operations on different files.
+ if (length_delta > 0) {
+ if (!capacity_tracker_->ChangeAvailableCapacity(-length_delta)) {
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kNoSpace,
+ "No capacity available for this operation"));
+ return 0;
+ }
+ file_length_ = write_end_offset;
+ }
+
+ base::File::Error write_error = base::File::FILE_OK;
+ int64_t actual_file_length_on_failure = file_length_;
+
int written_bytes = backing_file_.Write(file_offset, write_data, write_size);
if (written_bytes < 0) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "write() failed");
+ write_error = backing_file_.GetLastFileError();
+ actual_file_length_on_failure = backing_file_.GetLength();
+ }
+ if (write_error != base::File::FILE_OK || written_bytes < write_size) {
+ if (actual_file_length_on_failure >= 0) {
+ DCHECK_LE(actual_file_length_on_failure, file_length_)
+ << "file_length_ should be an upper bound during I/O";
+ if (actual_file_length_on_failure < file_length_) {
+ bool change_success = capacity_tracker_->ChangeAvailableCapacity(
+ file_length_ - actual_file_length_on_failure);
+ DCHECK(change_success) << "Capacity increases should always succeed";
+ file_length_ = actual_file_length_on_failure;
+ }
+ } else {
+ DCHECK(write_error != base::File::FILE_OK);
+ // base::File::Write() failed. Then, attempting to File::GetLength()
+ // failed as well. We don't have a reliable measure of the file's length,
+ // and the file descriptor is probably unusable. Force-closing the file
+ // without reclaiming any capacity minimizes the risk of overusing our
+ // allocation.
+ backing_file_.Close();
+ if (backend_file_.is_bound())
+ backend_file_->Close();
+ }
}
+
+ if (write_error != base::File::FILE_OK) {
+ ThrowNativeIOWithError(exception_state, write_error);
+ return 0;
+ }
+
return base::as_unsigned(written_bytes);
}
@@ -137,20 +318,19 @@ void NativeIOFileSync::flush(ExceptionState& exception_state) {
// This implementation of flush attempts to physically store the data it has
// written on disk. This behaviour might change in the future.
if (!backing_file_.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "The file was already closed");
+ ThrowNativeIOWithError(exception_state,
+ mojom::blink::NativeIOError::New(
+ mojom::blink::NativeIOErrorType::kInvalidState,
+ "The file was already closed"));
return;
}
- bool success = backing_file_.Flush();
- if (!success) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "flush() failed");
- }
- return;
+ if (!backing_file_.Flush())
+ ThrowNativeIOWithError(exception_state, backing_file_.GetLastFileError());
}
void NativeIOFileSync::Trace(Visitor* visitor) const {
visitor->Trace(backend_file_);
+ visitor->Trace(capacity_tracker_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.h
index d85dd75b76f..5104a84b697 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.h
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
+#include "third_party/blink/renderer/modules/native_io/native_io_capacity_tracker.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
@@ -28,7 +29,9 @@ class NativeIOFileSync final : public ScriptWrappable {
public:
NativeIOFileSync(base::File backing_file,
+ int64_t backing_file_size,
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file,
+ NativeIOCapacityTracker* capacity_tracker,
ExecutionContext*);
NativeIOFileSync(const NativeIOFileSync&) = delete;
@@ -58,8 +61,27 @@ class NativeIOFileSync final : public ScriptWrappable {
// The file on disk backing this NativeIOFile.
base::File backing_file_;
+ // The length of the file used in capacity accounting. This should equal the
+ // current file's length, unless that length cannot be reliably determined
+ // using base::GetLength(). In the latter case, the file will be force-closed
+ // to prevent further corruption.
+ //
+ // Operations that increase the file's length must first allocate capacity,
+ // update `file_length_` to reflect the increased length, and then perform the
+ // I/O. If the I/O fails, GetLength() must be used to obtain the actual file
+ // length. The result must first be compared against `file_length_` to account
+ // for the unused capacity, then used to update `file_length_`.
+ //
+ // Operations that decrease the file's length must first perform the I/O, and
+ // then update `file_length_` and return freed up capacity. I/O failures can
+ // be handled using the same logic as above.
+ int64_t file_length_ = 0;
+
// Mojo pipe that holds the renderer's lock on the file.
HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file_;
+
+ // Manages the capacity allocation for this file manager's execution context.
+ Member<NativeIOCapacityTracker> capacity_tracker_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.idl b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.idl
index c0932459e82..4f47c992ad1 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/native_io/native_io_file_sync.idl
@@ -6,7 +6,7 @@
[
Exposed=DedicatedWorker,
- RuntimeEnabled=NativeIO,
+ RuntimeEnabled=StorageFoundationAPI,
SecureContext
] interface NativeIOFileSync {
void close();
@@ -20,14 +20,14 @@
] void setLength(unsigned long long length);
[
- RaisesException
+ RaisesException, MeasureAs=StorageFoundationReadSync
] unsigned long long read([AllowShared] ArrayBufferView buffer,
unsigned long long file_offset);
[
- RaisesException
+ RaisesException, MeasureAs=StorageFoundationWriteSync
] unsigned long long write([AllowShared] ArrayBufferView buffer,
unsigned long long file_offset);
[
- RaisesException
+ RaisesException, MeasureAs=StorageFoundationFlushSync
] void flush();
};
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc b/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc
deleted file mode 100644
index 5be455a2bbf..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.cc
+++ /dev/null
@@ -1,331 +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/native_io/native_io_manager.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/files/file.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.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"
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.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/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/native_io/native_io_file.h"
-#include "third_party/blink/renderer/modules/native_io/native_io_file_sync.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/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
-
-namespace blink {
-
-namespace {
-
-bool IsValidNativeIONameCharacter(int name_char) {
- return (name_char >= 'a' && name_char <= 'z') ||
- (name_char >= '0' && name_char <= '9') || name_char == '_';
-}
-
-bool IsValidNativeIOName(const String& name) {
- if (name.IsEmpty())
- return false;
-
- if (name.Is8Bit()) {
- return std::all_of(name.Span8().begin(), name.Span8().end(),
- &IsValidNativeIONameCharacter);
- }
- return std::all_of(name.Span16().begin(), name.Span16().end(),
- &IsValidNativeIONameCharacter);
-}
-
-void OnOpenResult(
- ScriptPromiseResolver* resolver,
- DisallowNewWrapper<HeapMojoRemote<mojom::blink::NativeIOFileHost>>*
- backend_file_wrapper,
- base::File backing_file) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state);
-
- if (!backing_file.IsValid()) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
- "open() failed"));
- return;
- }
-
- NativeIOFile* file = MakeGarbageCollected<NativeIOFile>(
- std::move(backing_file), backend_file_wrapper->TakeValue(),
- ExecutionContext::From(script_state));
- resolver->Resolve(file);
-}
-
-void OnDeleteResult(ScriptPromiseResolver* resolver, bool backend_success) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state);
-
- if (!backend_success) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
- "delete() failed"));
- return;
- }
-
- resolver->Resolve();
-}
-
-void OnGetAllResult(ScriptPromiseResolver* resolver,
- bool backend_success,
- const Vector<String>& file_names) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state);
-
- if (!backend_success) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
- "getAll() failed"));
- return;
- }
-
- resolver->Resolve(file_names);
-}
-
-void OnRenameResult(ScriptPromiseResolver* resolver, bool backend_success) {
- ScriptState* script_state = resolver->GetScriptState();
- if (!script_state->ContextIsValid())
- return;
- ScriptState::Scope scope(script_state);
-
- if (!backend_success) {
- resolver->Reject(V8ThrowDOMException::CreateOrEmpty(
- script_state->GetIsolate(), DOMExceptionCode::kUnknownError,
- "rename() failed"));
- return;
- }
- resolver->Resolve();
-}
-
-} // namespace
-
-NativeIOManager::NativeIOManager(
- ExecutionContext* execution_context,
- HeapMojoRemote<mojom::blink::NativeIOHost> backend)
- : ExecutionContextClient(execution_context),
- // TODO(pwnall): Get a dedicated queue when the specification matures.
- receiver_task_runner_(
- execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)),
- backend_(std::move(backend)) {
- backend_.set_disconnect_handler(WTF::Bind(
- &NativeIOManager::OnBackendDisconnect, WrapWeakPersistent(this)));
-}
-
-NativeIOManager::~NativeIOManager() = default;
-
-ScriptPromise NativeIOManager::open(ScriptState* script_state,
- String name,
- ExceptionState& exception_state) {
- if (!IsValidNativeIOName(name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return ScriptPromise();
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return ScriptPromise();
- }
-
- ExecutionContext* execution_context = GetExecutionContext();
- DCHECK(execution_context);
-
- HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file(
- execution_context);
- mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver =
- backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_);
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- backend_->OpenFile(
- name, std::move(backend_file_receiver),
- WTF::Bind(&OnOpenResult, WrapPersistent(resolver),
- WrapPersistent(WrapDisallowNew(std::move(backend_file)))));
- return resolver->Promise();
-}
-
-ScriptPromise NativeIOManager::Delete(ScriptState* script_state,
- String name,
- ExceptionState& exception_state) {
- if (!IsValidNativeIOName(name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return ScriptPromise();
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return ScriptPromise();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- backend_->DeleteFile(name,
- WTF::Bind(&OnDeleteResult, WrapPersistent(resolver)));
- return resolver->Promise();
-}
-
-ScriptPromise NativeIOManager::getAll(ScriptState* script_state,
- ExceptionState& exception_state) {
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return ScriptPromise();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- backend_->GetAllFileNames(
- WTF::Bind(&OnGetAllResult, WrapPersistent(resolver)));
- return resolver->Promise();
-}
-
-ScriptPromise NativeIOManager::rename(ScriptState* script_state,
- String old_name,
- String new_name,
- ExceptionState& exception_state) {
- if (!IsValidNativeIOName(old_name) || !IsValidNativeIOName(new_name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return ScriptPromise();
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return ScriptPromise();
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- backend_->RenameFile(old_name, new_name,
- WTF::Bind(&OnRenameResult, WrapPersistent(resolver)));
- return resolver->Promise();
-}
-
-NativeIOFileSync* NativeIOManager::openSync(String name,
- ExceptionState& exception_state) {
- if (!IsValidNativeIOName(name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return nullptr;
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return nullptr;
- }
-
- ExecutionContext* execution_context = GetExecutionContext();
- DCHECK(execution_context);
-
- HeapMojoRemote<mojom::blink::NativeIOFileHost> backend_file(
- execution_context);
- mojo::PendingReceiver<mojom::blink::NativeIOFileHost> backend_file_receiver =
- backend_file.BindNewPipeAndPassReceiver(receiver_task_runner_);
-
- base::File backing_file;
- bool call_succeeded =
- backend_->OpenFile(name, std::move(backend_file_receiver), &backing_file);
-
- if (!call_succeeded || !backing_file.IsValid()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
- "openSync() failed");
- return nullptr;
- }
-
- return MakeGarbageCollected<NativeIOFileSync>(
- std::move(backing_file), std::move(backend_file), execution_context);
-}
-
-void NativeIOManager::deleteSync(String name, ExceptionState& exception_state) {
- if (!IsValidNativeIOName(name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return;
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return;
- }
-
- bool backend_success = false;
- bool call_succeeded = backend_->DeleteFile(name, &backend_success);
-
- if (!call_succeeded || !backend_success) {
- exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
- "deleteSync() failed");
- }
-}
-
-Vector<String> NativeIOManager::getAllSync(ExceptionState& exception_state) {
- Vector<String> result;
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return result;
- }
-
- bool backend_success = false;
- bool call_succeeded = backend_->GetAllFileNames(&backend_success, &result);
-
- if (!call_succeeded || !backend_success) {
- exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
- "getAllSync() failed");
- }
- return result;
-}
-
-void NativeIOManager::renameSync(String old_name,
- String new_name,
- ExceptionState& exception_state) {
- if (!IsValidNativeIOName(old_name) || !IsValidNativeIOName(new_name)) {
- exception_state.ThrowTypeError("Invalid file name");
- return;
- }
-
- if (!backend_.is_bound()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "NativeIOHost backend went away");
- return;
- }
-
- bool backend_success = false;
- bool call_succeeded =
- backend_->RenameFile(old_name, new_name, &backend_success);
-
- if (!call_succeeded || !backend_success) {
- exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
- "renameSync() failed");
- }
-}
-
-void NativeIOManager::Trace(Visitor* visitor) const {
- visitor->Trace(backend_);
- ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
-}
-
-void NativeIOManager::OnBackendDisconnect() {
- backend_.reset();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.h b/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.h
deleted file mode 100644
index 52d0771f95b..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.h
+++ /dev/null
@@ -1,68 +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_NATIVE_IO_NATIVE_IO_MANAGER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_MANAGER_H_
-
-#include "third_party/blink/public/mojom/native_io/native_io.mojom-blink.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"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class ExecutionContext;
-class ExceptionState;
-class NativeIOFileSync;
-class ScriptState;
-
-class NativeIOManager final : public ScriptWrappable,
- public ExecutionContextClient {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit NativeIOManager(ExecutionContext*,
- HeapMojoRemote<mojom::blink::NativeIOHost> backend);
-
- NativeIOManager(const NativeIOManager&) = delete;
- NativeIOManager& operator=(const NativeIOManager&) = delete;
-
- // Needed because of the
- // mojo::Remote<blink::mojom::NativeIOHost>
- ~NativeIOManager() override;
-
- ScriptPromise open(ScriptState*, String name, ExceptionState&);
- ScriptPromise Delete(ScriptState*, String name, ExceptionState&);
- ScriptPromise getAll(ScriptState*, ExceptionState&);
- ScriptPromise rename(ScriptState*,
- String old_name,
- String new_name,
- ExceptionState&);
-
- NativeIOFileSync* openSync(String name, ExceptionState&);
- void deleteSync(String name, ExceptionState&);
- Vector<String> getAllSync(ExceptionState&);
- void renameSync(String old_name, String new_name, ExceptionState&);
-
- // GarbageCollected
- void Trace(Visitor* visitor) const override;
-
- private:
- // Called when the mojo backend disconnects.
- void OnBackendDisconnect();
-
- // Task runner used by NativeIOFile mojo receivers generated by this API.
- const scoped_refptr<base::SequencedTaskRunner> receiver_task_runner_;
-
- // Wraps an always-on Mojo pipe for sending requests to the storage backend.
- HeapMojoRemote<mojom::blink::NativeIOHost> backend_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.idl b/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.idl
deleted file mode 100644
index 860eff12c84..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_io/native_io_manager.idl
+++ /dev/null
@@ -1,33 +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.
-
-// https://github.com/fivedots/nativeio-explainer
-
-[
- Exposed=(Window,Worker),
- RuntimeEnabled=NativeIO,
- SecureContext
-] interface NativeIOManager {
- [
- CallWith=ScriptState, RaisesException
- ] Promise<NativeIOFile> open(DOMString name);
- [
- Exposed=DedicatedWorker, RaisesException
- ] NativeIOFileSync openSync(DOMString name);
-
- [
- CallWith=ScriptState, ImplementedAs=Delete, RaisesException
- ] Promise<void> delete(DOMString name);
- [Exposed=DedicatedWorker, RaisesException] void deleteSync(DOMString name);
-
- [
- CallWith=ScriptState, RaisesException
- ] Promise<sequence<DOMString>> getAll();
- [Exposed=DedicatedWorker, RaisesException] sequence<DOMString> getAllSync();
-
- [
- CallWith=ScriptState, RaisesException
- ] Promise<void> rename(DOMString old_name, DOMString new_name);
- [Exposed=DedicatedWorker, RaisesException] void renameSync(DOMString old_name, DOMString new_name);
-};
diff --git a/chromium/third_party/blink/renderer/modules/native_io/window_native_io.idl b/chromium/third_party/blink/renderer/modules/native_io/window_native_io.idl
index 1b78cc42f38..313d1ed2394 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/window_native_io.idl
+++ b/chromium/third_party/blink/renderer/modules/native_io/window_native_io.idl
@@ -6,8 +6,8 @@
[
ImplementedAs=GlobalNativeIO,
- RuntimeEnabled=NativeIO,
+ RuntimeEnabled=StorageFoundationAPI,
SecureContext
] partial interface Window {
- readonly attribute NativeIOManager nativeIO;
+ readonly attribute NativeIOFileManager storageFoundation;
};
diff --git a/chromium/third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl b/chromium/third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl
index aa03a6ca7c5..53b4efeb9c6 100644
--- a/chromium/third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl
+++ b/chromium/third_party/blink/renderer/modules/native_io/worker_global_scope_native_io.idl
@@ -6,8 +6,8 @@
[
ImplementedAs=GlobalNativeIO,
- RuntimeEnabled=NativeIO,
+ RuntimeEnabled=StorageFoundationAPI,
SecureContext
] partial interface WorkerGlobalScope {
- readonly attribute NativeIOManager nativeIO;
+ readonly attribute NativeIOFileManager storageFoundation;
};
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/DIR_METADATA b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/DIR_METADATA
new file mode 100644
index 00000000000..95449b42113
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>HTML>CustomHandlers"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
index 2781695adae..be8260ae3c0 100644
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/OWNERS
@@ -1,3 +1 @@
gyuyoung@igalia.com
-
-# COMPONENT: Blink>HTML>CustomHandlers
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc
index e63682a4a9a..34b84e9ae03 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
@@ -59,10 +59,9 @@ static bool VerifyCustomHandlerURLSecurity(
// https://crbug.com/971917 and it doesn't make a lot of sense to support
// them. We do need to allow extensions to continue using the API.
if (!full_url.ProtocolIsInHTTPFamily() &&
- !full_url.ProtocolIs("chrome-extension")) {
- error_message =
- "The scheme of the url provided must be 'https' or "
- "'chrome-extension'.";
+ (security_level < ProtocolHandlerSecurityLevel::kExtensionFeatures ||
+ !full_url.ProtocolIs("chrome-extension"))) {
+ error_message = "The scheme of the url provided must be 'https'.";
return false;
}
@@ -105,22 +104,26 @@ static bool VerifyCustomHandlerURL(
} // namespace
-bool VerifyCustomHandlerScheme(const String& scheme, String& error_string) {
+bool VerifyCustomHandlerScheme(const String& scheme,
+ String& error_string,
+ ProtocolHandlerSecurityLevel security_level) {
if (!IsValidProtocol(scheme)) {
error_string = "The scheme name '" + scheme +
"' is not allowed by URI syntax (RFC3986).";
return false;
}
+ bool allow_ext_plus_prefix =
+ security_level >= ProtocolHandlerSecurityLevel::kExtensionFeatures;
bool has_custom_scheme_prefix;
StringUTF8Adaptor scheme_adaptor(scheme);
if (!IsValidCustomHandlerScheme(scheme_adaptor.AsStringPiece(),
+ allow_ext_plus_prefix,
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.";
+ error_string = "The scheme name '" + scheme +
+ "' is not allowed. Schemes starting with '" + scheme +
+ "' must be followed by one or more ASCII letters.";
} else {
error_string = "The scheme '" + scheme +
"' doesn't belong to the scheme allowlist. "
@@ -181,17 +184,18 @@ void NavigatorContentUtils::registerProtocolHandler(
if (!window)
return;
+ ProtocolHandlerSecurityLevel security_level =
+ Platform::Current()->GetProtocolHandlerSecurityLevel();
+
// Per the HTML specification, exceptions for arguments must be surfaced in
// the order of the arguments.
String error_message;
- if (!VerifyCustomHandlerScheme(scheme, error_message)) {
+ if (!VerifyCustomHandlerScheme(scheme, error_message, security_level)) {
exception_state.ThrowSecurityError(error_message);
return;
}
- if (!VerifyCustomHandlerURL(
- *window, url, exception_state,
- Platform::Current()->GetProtocolHandlerSecurityLevel()))
+ if (!VerifyCustomHandlerURL(*window, url, exception_state, security_level))
return;
// Count usage; perhaps we can forbid this from cross-origin subframes as
@@ -221,15 +225,16 @@ void NavigatorContentUtils::unregisterProtocolHandler(
if (!window)
return;
+ ProtocolHandlerSecurityLevel security_level =
+ Platform::Current()->GetProtocolHandlerSecurityLevel();
+
String error_message;
- if (!VerifyCustomHandlerScheme(scheme, error_message)) {
+ if (!VerifyCustomHandlerScheme(scheme, error_message, security_level)) {
exception_state.ThrowSecurityError(error_message);
return;
}
- if (!VerifyCustomHandlerURL(
- *window, url, exception_state,
- Platform::Current()->GetProtocolHandlerSecurityLevel()))
+ if (!VerifyCustomHandlerURL(*window, url, exception_state, security_level))
return;
NavigatorContentUtils::From(navigator, *window->GetFrame())
diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h
index 8104f2b78d6..18770b81478 100644
--- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h
+++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h
@@ -36,12 +36,16 @@
namespace blink {
class ExceptionState;
+class LocalFrame;
class NavigatorContentUtilsClient;
+enum class ProtocolHandlerSecurityLevel;
// Verify custom handler schemes for errors as described in
// https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers.
// Callers should surface an error with |error_message| if it returns false.
-bool VerifyCustomHandlerScheme(const String& scheme, String& error_message);
+bool VerifyCustomHandlerScheme(const String& scheme,
+ String& error_message,
+ ProtocolHandlerSecurityLevel security_level);
// Verify custom handler URLs for syntax errors as described in
// https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers.
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/BUILD.gn b/chromium/third_party/blink/renderer/modules/netinfo/BUILD.gn
index 96cfda41674..69bd8c18059 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/netinfo/BUILD.gn
@@ -6,11 +6,7 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("netinfo") {
sources = [
- "navigator_network_information.cc",
- "navigator_network_information.h",
"network_information.cc",
"network_information.h",
- "worker_navigator_network_information.cc",
- "worker_navigator_network_information.h",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/DIR_METADATA b/chromium/third_party/blink/renderer/modules/netinfo/DIR_METADATA
new file mode 100644
index 00000000000..edfc773b685
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/netinfo/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Network>NetInfo"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/OWNERS b/chromium/third_party/blink/renderer/modules/netinfo/OWNERS
index 8137d1b71e5..3498144a1e9 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/netinfo/OWNERS
@@ -1,4 +1,2 @@
jkarlin@chromium.org
tbansal@chromium.org
-
-# COMPONENT: Internals>Network>NetInfo
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc b/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc
deleted file mode 100644
index 6ba6265d15f..00000000000
--- a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/netinfo/navigator_network_information.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/netinfo/network_information.h"
-
-namespace blink {
-
-NavigatorNetworkInformation::NavigatorNetworkInformation(Navigator& navigator)
- : ExecutionContextClient(navigator.DomWindow()) {}
-
-NavigatorNetworkInformation& NavigatorNetworkInformation::From(
- Navigator& navigator) {
- NavigatorNetworkInformation* supplement =
- ToNavigatorNetworkInformation(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorNetworkInformation>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-NavigatorNetworkInformation*
-NavigatorNetworkInformation::ToNavigatorNetworkInformation(
- Navigator& navigator) {
- return Supplement<Navigator>::From<NavigatorNetworkInformation>(navigator);
-}
-
-const char NavigatorNetworkInformation::kSupplementName[] =
- "NavigatorNetworkInformation";
-
-NetworkInformation* NavigatorNetworkInformation::connection(
- Navigator& navigator) {
- return NavigatorNetworkInformation::From(navigator).connection();
-}
-
-NetworkInformation* NavigatorNetworkInformation::connection() {
- if (!connection_ && DomWindow())
- connection_ = MakeGarbageCollected<NetworkInformation>(DomWindow());
- return connection_.Get();
-}
-
-void NavigatorNetworkInformation::Trace(Visitor* visitor) const {
- visitor->Trace(connection_);
- Supplement<Navigator>::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.h b/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.h
deleted file mode 100644
index b21c1a13e5b..00000000000
--- a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_NAVIGATOR_NETWORK_INFORMATION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_NAVIGATOR_NETWORK_INFORMATION_H_
-
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class NetworkInformation;
-
-class NavigatorNetworkInformation final
- : public GarbageCollected<NavigatorNetworkInformation>,
- public Supplement<Navigator>,
- public ExecutionContextClient {
- public:
- static const char kSupplementName[];
-
- static NavigatorNetworkInformation& From(Navigator&);
- static NavigatorNetworkInformation* ToNavigatorNetworkInformation(Navigator&);
- static NetworkInformation* connection(Navigator&);
-
- explicit NavigatorNetworkInformation(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- NetworkInformation* connection();
-
- Member<NetworkInformation> connection_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_NAVIGATOR_NETWORK_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.idl b/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.idl
index b5857d36ba4..71d83478e63 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.idl
+++ b/chromium/third_party/blink/renderer/modules/netinfo/navigator_network_information.idl
@@ -3,7 +3,7 @@
// found in the LICENSE file.
[
- ImplementedAs=NavigatorNetworkInformation
+ ImplementedAs=NetworkInformation
] partial interface Navigator {
[MeasureAs=NetInfo] readonly attribute NetworkInformation connection;
};
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc b/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc
index 44fb0589cb9..fbc40d0c34b 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc
+++ b/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -270,8 +271,23 @@ void NetworkInformation::StopObserving() {
}
}
-NetworkInformation::NetworkInformation(ExecutionContext* context)
- : ExecutionContextLifecycleObserver(context),
+const char NetworkInformation::kSupplementName[] = "NetworkInformation";
+
+NetworkInformation* NetworkInformation::connection(NavigatorBase& navigator) {
+ if (!navigator.GetExecutionContext())
+ return nullptr;
+ NetworkInformation* supplement =
+ Supplement<NavigatorBase>::From<NetworkInformation>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<NetworkInformation>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+NetworkInformation::NetworkInformation(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()),
web_holdback_console_message_shown_(false),
context_stopped_(false) {
base::Optional<base::TimeDelta> http_rtt;
@@ -292,6 +308,7 @@ NetworkInformation::NetworkInformation(ExecutionContext* context)
void NetworkInformation::Trace(Visitor* visitor) const {
EventTargetWithInlineData::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/network_information.h b/chromium/third_party/blink/renderer/modules/netinfo/network_information.h
index daf6449d9d0..1d33cda8470 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/network_information.h
+++ b/chromium/third_party/blink/renderer/modules/netinfo/network_information.h
@@ -12,20 +12,27 @@
#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/platform/network/network_state_notifier.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
-class ExecutionContext;
+class NavigatorBase;
class NetworkInformation final
: public EventTargetWithInlineData,
public ActiveScriptWrappable<NetworkInformation>,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver,
public NetworkStateNotifier::NetworkStateObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit NetworkInformation(ExecutionContext*);
+ static const char kSupplementName[];
+
+ // Web-exposed as navigator.connection.
+ static NetworkInformation* connection(NavigatorBase&);
+
+ explicit NetworkInformation(NavigatorBase&);
~NetworkInformation() override;
String type() const;
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc b/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc
deleted file mode 100644
index abb3bdcc058..00000000000
--- a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.h"
-
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/netinfo/network_information.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-
-namespace blink {
-
-WorkerNavigatorNetworkInformation::WorkerNavigatorNetworkInformation(
- WorkerNavigator& navigator,
- ExecutionContext* context)
- : Supplement<WorkerNavigator>(navigator) {}
-
-WorkerNavigatorNetworkInformation& WorkerNavigatorNetworkInformation::From(
- WorkerNavigator& navigator,
- ExecutionContext* context) {
- WorkerNavigatorNetworkInformation* supplement =
- ToWorkerNavigatorNetworkInformation(navigator, context);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorNetworkInformation>(
- navigator, context);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-WorkerNavigatorNetworkInformation*
-WorkerNavigatorNetworkInformation::ToWorkerNavigatorNetworkInformation(
- WorkerNavigator& navigator,
- ExecutionContext* context) {
- return Supplement<WorkerNavigator>::From<WorkerNavigatorNetworkInformation>(
- navigator);
-}
-
-const char WorkerNavigatorNetworkInformation::kSupplementName[] =
- "WorkerNavigatorNetworkInformation";
-
-NetworkInformation* WorkerNavigatorNetworkInformation::connection(
- ScriptState* script_state,
- WorkerNavigator& navigator) {
- ExecutionContext* context = ExecutionContext::From(script_state);
- return WorkerNavigatorNetworkInformation::From(navigator, context)
- .connection(context);
-}
-
-void WorkerNavigatorNetworkInformation::Trace(Visitor* visitor) const {
- visitor->Trace(connection_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-NetworkInformation* WorkerNavigatorNetworkInformation::connection(
- ExecutionContext* context) {
- DCHECK(context);
- if (!connection_)
- connection_ = MakeGarbageCollected<NetworkInformation>(context);
- return connection_.Get();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.h b/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.h
deleted file mode 100644
index fbf0eb291b1..00000000000
--- a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_WORKER_NAVIGATOR_NETWORK_INFORMATION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_WORKER_NAVIGATOR_NETWORK_INFORMATION_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class ExecutionContext;
-class NetworkInformation;
-class ScriptState;
-class WorkerNavigator;
-
-class WorkerNavigatorNetworkInformation final
- : public GarbageCollected<WorkerNavigatorNetworkInformation>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static WorkerNavigatorNetworkInformation& From(WorkerNavigator&,
- ExecutionContext*);
- static WorkerNavigatorNetworkInformation* ToWorkerNavigatorNetworkInformation(
- WorkerNavigator&,
- ExecutionContext*);
-
- static NetworkInformation* connection(ScriptState*, WorkerNavigator&);
-
- WorkerNavigatorNetworkInformation(WorkerNavigator&, ExecutionContext*);
-
- void Trace(Visitor*) const override;
-
- private:
- NetworkInformation* connection(ExecutionContext*);
-
- Member<NetworkInformation> connection_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NETINFO_WORKER_NAVIGATOR_NETWORK_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.idl b/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.idl
index 888d8dfdc50..fee9325ad80 100644
--- a/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.idl
+++ b/chromium/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.idl
@@ -4,7 +4,7 @@
[
Exposed=Worker,
- ImplementedAs=WorkerNavigatorNetworkInformation
+ ImplementedAs=NetworkInformation
] partial interface WorkerNavigator {
- [CallWith=ScriptState, MeasureAs=NetInfo] readonly attribute NetworkInformation connection;
+ [MeasureAs=NetInfo] readonly attribute NetworkInformation connection;
};
diff --git a/chromium/third_party/blink/renderer/modules/nfc/BUILD.gn b/chromium/third_party/blink/renderer/modules/nfc/BUILD.gn
index 06dcd3e1740..517a0f702d9 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/nfc/BUILD.gn
@@ -14,14 +14,10 @@ blink_modules_sources("nfc") {
"ndef_reading_event.h",
"ndef_record.cc",
"ndef_record.h",
- "ndef_writer.cc",
- "ndef_writer.h",
"nfc_proxy.cc",
"nfc_proxy.h",
"nfc_type_converters.cc",
"nfc_type_converters.h",
- "nfc_utils.cc",
- "nfc_utils.h",
]
deps = [ "//third_party/blink/renderer/modules/permissions" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/nfc/DIR_METADATA b/chromium/third_party/blink/renderer/modules/nfc/DIR_METADATA
new file mode 100644
index 00000000000..b0c98883af1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/nfc/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>NFC"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/nfc/OWNERS b/chromium/third_party/blink/renderer/modules/nfc/OWNERS
index 7cc2ceebc1d..80925a603f5 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/nfc/OWNERS
@@ -1,8 +1,6 @@
rijubrata.bhaumik@intel.com
reillyg@chromium.org
+beaufort.francois@gmail.com
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Blink>NFC
-# TEAM: device-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/nfc/idls.gni b/chromium/third_party/blink/renderer/modules/nfc/idls.gni
index 34266343cc9..87158dc6a63 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/nfc/idls.gni
@@ -7,7 +7,6 @@ modules_idl_files = [
"ndef_record.idl",
"ndef_reader.idl",
"ndef_reading_event.idl",
- "ndef_writer.idl",
]
modules_dictionary_idl_files = [
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_message.cc b/chromium/third_party/blink/renderer/modules/nfc/ndef_message.cc
index 68475bb2745..bceaacb1093 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_message.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_message.cc
@@ -72,7 +72,7 @@ NDEFMessage* NDEFMessage::Create(const ExecutionContext* execution_context,
}
if (source.IsArrayBufferView()) {
- size_t byte_length = source.GetAsArrayBufferView().View()->byteLength();
+ size_t byte_length = source.GetAsArrayBufferView()->byteLength();
if (byte_length > std::numeric_limits<wtf_size_t>::max()) {
exception_state.ThrowRangeError(
"Buffer size exceeds maximum heap object size.");
@@ -80,8 +80,7 @@ NDEFMessage* NDEFMessage::Create(const ExecutionContext* execution_context,
}
WTF::Vector<uint8_t> payload_data;
payload_data.Append(
- static_cast<uint8_t*>(
- source.GetAsArrayBufferView().View()->BaseAddress()),
+ static_cast<uint8_t*>(source.GetAsArrayBufferView()->BaseAddress()),
static_cast<wtf_size_t>(byte_length));
NDEFMessage* message = MakeGarbageCollected<NDEFMessage>();
message->records_.push_back(MakeGarbageCollected<NDEFRecord>(
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 82d73c04232..b13006e5488 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc
@@ -4,27 +4,25 @@
#include "third_party/blink/renderer/modules/nfc/ndef_reader.h"
-#include <utility>
-
#include "services/device/public/mojom/nfc.mojom-blink.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/modules/v8/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.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/core/dom/abort_signal.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/core/events/error_event.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/inspector/console_message.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/ndef_reading_event.h"
#include "third_party/blink/renderer/modules/nfc/nfc_proxy.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
+#include "third_party/blink/renderer/modules/nfc/nfc_type_converters.h"
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
@@ -34,17 +32,50 @@ using mojom::blink::PermissionStatus;
namespace {
+DOMException* NDEFErrorTypeToDOMException(
+ device::mojom::blink::NDEFErrorType error_type,
+ const String& error_message) {
+ switch (error_type) {
+ case device::mojom::blink::NDEFErrorType::NOT_ALLOWED:
+ return MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError, error_message);
+ case device::mojom::blink::NDEFErrorType::NOT_SUPPORTED:
+ return MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotSupportedError, error_message);
+ case device::mojom::blink::NDEFErrorType::NOT_READABLE:
+ return MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotReadableError, error_message);
+ case device::mojom::blink::NDEFErrorType::INVALID_MESSAGE:
+ return MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
+ error_message);
+ case device::mojom::blink::NDEFErrorType::OPERATION_CANCELLED:
+ return MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError,
+ error_message);
+ case device::mojom::blink::NDEFErrorType::IO_ERROR:
+ return MakeGarbageCollected<DOMException>(DOMExceptionCode::kNetworkError,
+ error_message);
+ }
+ NOTREACHED();
+ // Don't need to handle the case after a NOTREACHED().
+ return nullptr;
+}
+
constexpr char kNotSupportedOrPermissionDenied[] =
- "WebNFC feature is unavailable or permission denied.";
+ "Web NFC is unavailable or permission denied.";
-constexpr char kInvalidStateErrorMessage[] = "A scan() operation is ongoing.";
+constexpr char kChildFrameErrorMessage[] =
+ "Web NFC can only be accessed in a top-level browsing context.";
+
+constexpr char kScanAbortMessage[] = "The NFC scan operation was cancelled.";
+
+constexpr char kWriteAbortMessage[] = "The NFC write operation was cancelled.";
} // namespace
// static
NDEFReader* NDEFReader::Create(ExecutionContext* context) {
context->GetScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kWebNfc,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
return MakeGarbageCollected<NDEFReader>(context);
}
@@ -74,15 +105,11 @@ bool NDEFReader::HasPendingActivity() const {
ScriptPromise NDEFReader::scan(ScriptState* script_state,
const NDEFScanOptions* options,
ExceptionState& exception_state) {
- LocalFrame* frame = script_state->ContextIsValid()
- ? LocalDOMWindow::From(script_state)->GetFrame()
- : nullptr;
// https://w3c.github.io/web-nfc/#security-policies
// WebNFC API must be only accessible from top level browsing context.
- if (!frame || !frame->IsMainFrame()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
- "NFC interfaces are only avaliable "
- "in a top-level browsing context");
+ if (!DomWindow() || !DomWindow()->GetFrame()->IsMainFrame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kChildFrameErrorMessage);
return ScriptPromise();
}
@@ -90,104 +117,67 @@ ScriptPromise NDEFReader::scan(ScriptState* script_state,
// "AbortError" DOMException and return p.
if (options->hasSignal() && options->signal()->aborted()) {
exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
- "The NFC operation was cancelled.");
+ kScanAbortMessage);
return ScriptPromise();
}
- if (has_pending_scan_request_) {
+ // Reject promise when there's already an ongoing scan.
+ if (scan_resolver_ || GetNfcProxy()->IsReading(this)) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- kInvalidStateErrorMessage);
+ "A scan() operation is ongoing.");
return ScriptPromise();
}
- has_pending_scan_request_ = true;
-
- // https://github.com/w3c/web-nfc/issues/592
- // reject scan promise when there's already an ongoing scan.
- if (GetNfcProxy()->IsReading(this)) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- kInvalidStateErrorMessage);
- return ScriptPromise();
- }
-
- resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // 8. If reader.[[Signal]] is not null, then add the following abort steps
- // to reader.[[Signal]]:
- if (options->hasSignal()) {
- options->signal()->AddAlgorithm(
- WTF::Bind(&NDEFReader::Abort, WrapPersistent(this)));
- }
+ scan_resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
GetPermissionService()->RequestPermission(
CreatePermissionDescriptor(PermissionName::NFC),
- LocalFrame::HasTransientUserActivation(frame),
- WTF::Bind(&NDEFReader::OnRequestPermission, WrapPersistent(this),
+ LocalFrame::HasTransientUserActivation(DomWindow()->GetFrame()),
+ WTF::Bind(&NDEFReader::ReadOnRequestPermission, WrapPersistent(this),
WrapPersistent(options)));
- return resolver_->Promise();
-}
-
-PermissionService* NDEFReader::GetPermissionService() {
- if (!permission_service_.is_bound()) {
- ConnectToPermissionService(
- GetExecutionContext(),
- permission_service_.BindNewPipeAndPassReceiver(
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
- }
- return permission_service_.get();
+ return scan_resolver_->Promise();
}
-void NDEFReader::OnRequestPermission(const NDEFScanOptions* options,
- PermissionStatus status) {
- if (!resolver_) {
- has_pending_scan_request_ = false;
+void NDEFReader::ReadOnRequestPermission(const NDEFScanOptions* options,
+ PermissionStatus status) {
+ if (!scan_resolver_)
return;
- }
if (status != PermissionStatus::GRANTED) {
- has_pending_scan_request_ = false;
- resolver_->Reject(MakeGarbageCollected<DOMException>(
+ scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "NFC permission request denied."));
- resolver_.Clear();
- return;
- }
- if (options->hasSignal() && options->signal()->aborted()) {
- has_pending_scan_request_ = false;
- resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kAbortError, "The NFC operation was cancelled."));
- resolver_.Clear();
+ scan_resolver_.Clear();
return;
}
- UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcNdefReaderScan);
- // TODO(https://crbug.com/994936) remove when origin trial is complete.
- UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcAPI);
+ if (options->hasSignal()) {
+ if (options->signal()->aborted()) {
+ scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, kScanAbortMessage));
+ scan_resolver_.Clear();
+ return;
+ }
+ options->signal()->AddAlgorithm(
+ WTF::Bind(&NDEFReader::ReadAbort, WrapPersistent(this)));
+ }
GetNfcProxy()->StartReading(
this,
- WTF::Bind(&NDEFReader::OnScanRequestCompleted, WrapPersistent(this)));
+ WTF::Bind(&NDEFReader::ReadOnRequestCompleted, WrapPersistent(this)));
}
-void NDEFReader::OnScanRequestCompleted(
+void NDEFReader::ReadOnRequestCompleted(
device::mojom::blink::NDEFErrorPtr error) {
- has_pending_scan_request_ = false;
- if (!resolver_)
+ if (!scan_resolver_)
return;
if (error) {
- resolver_->Reject(
+ scan_resolver_->Reject(
NDEFErrorTypeToDOMException(error->error_type, error->error_message));
} else {
- resolver_->Resolve();
+ scan_resolver_->Resolve();
}
- resolver_.Clear();
-}
-
-void NDEFReader::Trace(Visitor* visitor) const {
- visitor->Trace(permission_service_);
- visitor->Trace(resolver_);
- EventTargetWithInlineData::Trace(visitor);
- ActiveScriptWrappable::Trace(visitor);
- ExecutionContextLifecycleObserver::Trace(visitor);
+ scan_resolver_.Clear();
}
void NDEFReader::OnReading(const String& serial_number,
@@ -198,49 +188,174 @@ void NDEFReader::OnReading(const String& serial_number,
MakeGarbageCollected<NDEFMessage>(message)));
}
-void NDEFReader::OnError(const String& message) {
- ErrorEvent* event = ErrorEvent::Create(
- message, SourceLocation::Capture(GetExecutionContext()), nullptr);
- DispatchEvent(*event);
+void NDEFReader::OnReadingError(const String& message) {
+ DispatchEvent(*Event::Create(event_type_names::kReadingerror));
+ GetExecutionContext()->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kInfo, message));
}
-void NDEFReader::OnMojoConnectionError() {
- // If |resolver_| has already settled this rejection is silently ignored.
- if (resolver_) {
- resolver_->Reject(NDEFErrorTypeToDOMException(
- device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
- kNotSupportedOrPermissionDenied));
- resolver_.Clear();
+void NDEFReader::ContextDestroyed() {
+ GetNfcProxy()->StopReading(this);
+}
+
+void NDEFReader::ReadAbort() {
+ if (scan_resolver_) {
+ scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, kScanAbortMessage));
+ scan_resolver_.Clear();
}
- // Dispatches an error event.
- OnError(kNotSupportedOrPermissionDenied);
+ GetNfcProxy()->StopReading(this);
}
-void NDEFReader::ContextDestroyed() {
- // If |resolver_| has already settled this rejection is silently ignored.
- if (resolver_) {
- resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kAbortError,
- "The execution context is going to be gone."));
- resolver_.Clear();
+// https://w3c.github.io/web-nfc/#writing-content
+// https://w3c.github.io/web-nfc/#the-write-method
+ScriptPromise NDEFReader::write(ScriptState* script_state,
+ const NDEFMessageSource& write_message,
+ const NDEFWriteOptions* options,
+ ExceptionState& exception_state) {
+ // https://w3c.github.io/web-nfc/#security-policies
+ // WebNFC API must be only accessible from top level browsing context.
+ if (!DomWindow() || !DomWindow()->GetFrame()->IsMainFrame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kChildFrameErrorMessage);
+ return ScriptPromise();
}
- GetNfcProxy()->StopReading(this);
+
+ if (options->hasSignal() && options->signal()->aborted()) {
+ // If signal’s aborted flag is set, then reject p with an "AbortError"
+ // DOMException and return p.
+ exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
+ kWriteAbortMessage);
+ return ScriptPromise();
+ }
+
+ // Step 11.2: Run "create NDEF message", if this throws an exception,
+ // reject p with that exception and abort these steps.
+ NDEFMessage* ndef_message =
+ NDEFMessage::Create(DomWindow(), write_message, exception_state);
+ if (exception_state.HadException()) {
+ return ScriptPromise();
+ }
+
+ auto message = device::mojom::blink::NDEFMessage::From(ndef_message);
+ DCHECK(message);
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ write_requests_.insert(resolver);
+
+ // Add the writer to proxy's writer list for Mojo connection error
+ // notification.
+ GetNfcProxy()->AddWriter(this);
+
+ GetPermissionService()->RequestPermission(
+ CreatePermissionDescriptor(PermissionName::NFC),
+ LocalFrame::HasTransientUserActivation(DomWindow()->GetFrame()),
+ WTF::Bind(&NDEFReader::WriteOnRequestPermission, WrapPersistent(this),
+ WrapPersistent(resolver), WrapPersistent(options),
+ std::move(message)));
+
+ return resolver->Promise();
}
-void NDEFReader::Abort() {
- if (resolver_) {
- resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kAbortError, "The NFC operation was cancelled."));
- resolver_.Clear();
+void NDEFReader::WriteOnRequestPermission(
+ ScriptPromiseResolver* resolver,
+ const NDEFWriteOptions* options,
+ device::mojom::blink::NDEFMessagePtr message,
+ PermissionStatus status) {
+ if (status != PermissionStatus::GRANTED) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError, "NFC permission request denied."));
+ return;
+ }
+
+ if (options->hasSignal()) {
+ if (options->signal()->aborted()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, kWriteAbortMessage));
+ return;
+ }
+ options->signal()->AddAlgorithm(
+ WTF::Bind(&NDEFReader::WriteAbort, WrapPersistent(this)));
}
- GetNfcProxy()->StopReading(this);
+ auto callback = WTF::Bind(&NDEFReader::WriteOnRequestCompleted,
+ WrapPersistent(this), WrapPersistent(resolver));
+ GetNfcProxy()->Push(std::move(message),
+ device::mojom::blink::NDEFWriteOptions::From(options),
+ std::move(callback));
+}
+
+void NDEFReader::WriteOnRequestCompleted(
+ ScriptPromiseResolver* resolver,
+ device::mojom::blink::NDEFErrorPtr error) {
+ DCHECK(write_requests_.Contains(resolver));
+
+ write_requests_.erase(resolver);
+
+ if (error.is_null()) {
+ resolver->Resolve();
+ } else {
+ resolver->Reject(
+ NDEFErrorTypeToDOMException(error->error_type, error->error_message));
+ }
+}
+
+void NDEFReader::WriteAbort() {
+ // WriteOnRequestCompleted() should always be called whether the push
+ // operation is cancelled successfully or not.
+ GetNfcProxy()->CancelPush();
}
NFCProxy* NDEFReader::GetNfcProxy() const {
- DCHECK(GetExecutionContext());
- return NFCProxy::From(*To<LocalDOMWindow>(GetExecutionContext()));
+ DCHECK(DomWindow());
+ return NFCProxy::From(*DomWindow());
+}
+
+void NDEFReader::Trace(Visitor* visitor) const {
+ visitor->Trace(permission_service_);
+ visitor->Trace(scan_resolver_);
+ visitor->Trace(write_requests_);
+ EventTargetWithInlineData::Trace(visitor);
+ ActiveScriptWrappable::Trace(visitor);
+ ExecutionContextLifecycleObserver::Trace(visitor);
+}
+
+PermissionService* NDEFReader::GetPermissionService() {
+ if (!permission_service_.is_bound()) {
+ ConnectToPermissionService(
+ GetExecutionContext(),
+ permission_service_.BindNewPipeAndPassReceiver(
+ GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ }
+ return permission_service_.get();
+}
+
+void NDEFReader::ReadOnMojoConnectionError() {
+ // If |scan_resolver_| has already settled this rejection is silently ignored.
+ if (scan_resolver_) {
+ scan_resolver_->Reject(NDEFErrorTypeToDOMException(
+ device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
+ kNotSupportedOrPermissionDenied));
+ scan_resolver_.Clear();
+ }
+}
+
+void NDEFReader::WriteOnMojoConnectionError() {
+ // If the mojo connection breaks, All push requests will be rejected with a
+ // default error.
+
+ // Script may execute during a call to Resolve(). Swap these sets to prevent
+ // concurrent modification.
+ HeapHashSet<Member<ScriptPromiseResolver>> write_requests;
+ write_requests_.swap(write_requests);
+ write_requests_.clear();
+ for (ScriptPromiseResolver* resolver : write_requests) {
+ resolver->Reject(NDEFErrorTypeToDOMException(
+ device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
+ kNotSupportedOrPermissionDenied));
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.h b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.h
index ee1a93d9d4d..9f18556e21e 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.h
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.h
@@ -18,10 +18,13 @@
namespace blink {
-class ExecutionContext;
-class NFCProxy;
class NDEFScanOptions;
+class NDEFWriteOptions;
+class NFCProxy;
class ScriptPromiseResolver;
+class StringOrArrayBufferOrArrayBufferViewOrNDEFMessageInit;
+
+using NDEFMessageSource = StringOrArrayBufferOrArrayBufferViewOrNDEFMessageInit;
class MODULES_EXPORT NDEFReader : public EventTargetWithInlineData,
public ActiveScriptWrappable<NDEFReader>,
@@ -41,44 +44,70 @@ class MODULES_EXPORT NDEFReader : public EventTargetWithInlineData,
// ActiveScriptWrappable overrides.
bool HasPendingActivity() const override;
- DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError)
DEFINE_ATTRIBUTE_EVENT_LISTENER(reading, kReading)
- ScriptPromise scan(ScriptState*, const NDEFScanOptions*, ExceptionState&);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(readingerror, kReadingerror)
+
+ // Scan from an NFC tag.
+ ScriptPromise scan(ScriptState* script_state,
+ const NDEFScanOptions* options,
+ ExceptionState& exception_state);
+
+ // Write NDEFMessageSource asynchronously to NFC tag.
+ ScriptPromise write(ScriptState* script_state,
+ const NDEFMessageSource& write_message,
+ const NDEFWriteOptions* options,
+ ExceptionState& exception_state);
void Trace(Visitor*) const override;
// Called by NFCProxy for dispatching events.
virtual void OnReading(const String& serial_number,
const device::mojom::blink::NDEFMessage&);
- virtual void OnError(const String& message);
+ virtual void OnReadingError(const String& message);
// Called by NFCProxy for notification about connection error.
- void OnMojoConnectionError();
+ void ReadOnMojoConnectionError();
+ void WriteOnMojoConnectionError();
private:
// ExecutionContextLifecycleObserver overrides.
void ContextDestroyed() override;
- void Abort();
-
NFCProxy* GetNfcProxy() const;
- void OnScanRequestCompleted(device::mojom::blink::NDEFErrorPtr error);
+ void ReadAbort();
+ void ReadOnRequestCompleted(device::mojom::blink::NDEFErrorPtr error);
+
+ void WriteAbort();
+ void WriteOnRequestCompleted(ScriptPromiseResolver* resolver,
+ device::mojom::blink::NDEFErrorPtr error);
+
+ // Read Permission handling
+ void ReadOnRequestPermission(const NDEFScanOptions* options,
+ mojom::blink::PermissionStatus status);
+
+ // Write Permission handling
+ void WriteOnRequestPermission(
+ ScriptPromiseResolver* resolver,
+ const NDEFWriteOptions* options,
+ device::mojom::blink::NDEFMessagePtr ndef_message,
+ mojom::blink::PermissionStatus status);
+
+ // |scan_resolver_| is kept here to handle Mojo connection failures because in
+ // that case the callback passed to Watch() won't be called and
+ // mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
+ Member<ScriptPromiseResolver> scan_resolver_;
- // Permission handling
- void OnRequestPermission(const NDEFScanOptions* options,
- mojom::blink::PermissionStatus status);
- mojom::blink::PermissionService* GetPermissionService();
HeapMojoRemote<mojom::blink::PermissionService,
HeapMojoWrapperMode::kWithoutContextObserver>
permission_service_;
+ mojom::blink::PermissionService* GetPermissionService();
- // |resolver_| is kept here to handle Mojo connection failures because in that
- // case the callback passed to Watch() won't be called and
+ // |write_requests_| are kept here to handle Mojo connection failures because
+ // in that case the callback passed to Push() won't be called and
// mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
- Member<ScriptPromiseResolver> resolver_;
- // To reject if there is already an ongoing scan.
- bool has_pending_scan_request_ = false;
+ // This list will also be used by AbortSignal.
+ HeapHashSet<Member<ScriptPromiseResolver>> write_requests_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.idl b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.idl
index 280ebf5ac6e..63575c5ee08 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.idl
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.idl
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// https://w3c.github.io/web-nfc/#dom-ndefmessagesource
+typedef (DOMString or BufferSource or NDEFMessageInit) NDEFMessageSource;
+
// http://w3c.github.io/web-nfc/#dom-ndefreader
[
@@ -12,8 +15,12 @@
] interface NDEFReader : EventTarget {
[CallWith=ExecutionContext] constructor();
attribute EventHandler onreading;
- attribute EventHandler onerror;
+ attribute EventHandler onreadingerror;
- [CallWith=ScriptState, RaisesException] Promise<void> scan(
+ [CallWith=ScriptState, RaisesException, MeasureAs=WebNfcNdefReaderScan] Promise<void> scan(
optional NDEFScanOptions options={});
+
+ [CallWith=ScriptState, RaisesException, MeasureAs=WebNfcNdefWriterWrite] Promise<void> write(
+ NDEFMessageSource message,
+ optional NDEFWriteOptions options={});
};
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_record.cc b/chromium/third_party/blink/renderer/modules/nfc/ndef_record.cc
index 5fbbab2d837..8b999171868 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_record.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_record.cc
@@ -15,7 +15,6 @@
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -52,7 +51,7 @@ bool GetBytesOfBufferSource(const NDEFRecordDataSource& buffer_source,
data_length = array_buffer->ByteLength();
} else if (buffer_source.IsArrayBufferView()) {
const DOMArrayBufferView* array_buffer_view =
- buffer_source.GetAsArrayBufferView().View();
+ buffer_source.GetAsArrayBufferView().Get();
data = reinterpret_cast<uint8_t*>(array_buffer_view->BaseAddress());
data_length = array_buffer_view->byteLength();
} else {
@@ -528,7 +527,7 @@ DOMDataView* NDEFRecord::data() const {
return DOMDataView::Create(dom_buffer, 0, payload_data_.size());
}
-// https://w3c.github.io/web-nfc/#dfn-convert-ndefrecord-payloaddata-bytes
+// https://w3c.github.io/web-nfc/#dfn-convert-ndefrecord-data-bytes
base::Optional<HeapVector<Member<NDEFRecord>>> NDEFRecord::toRecords(
ExceptionState& exception_state) const {
if (record_type_ != "smart-poster" &&
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.cc b/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.cc
deleted file mode 100644
index 56a731524a1..00000000000
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.cc
+++ /dev/null
@@ -1,197 +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/nfc/ndef_writer.h"
-
-#include <utility>
-
-#include "mojo/public/cpp/bindings/callback_helpers.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ndef_write_options.h"
-#include "third_party/blink/renderer/core/dom/abort_signal.h"
-#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/core/frame/local_frame.h"
-#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_type_converters.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_utils.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/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-
-namespace blink {
-
-using mojom::blink::PermissionName;
-using mojom::blink::PermissionService;
-using mojom::blink::PermissionStatus;
-
-// static
-NDEFWriter* NDEFWriter::Create(ExecutionContext* context) {
- context->GetScheduler()->RegisterStickyFeature(
- blink::SchedulingPolicy::Feature::kWebNfc,
- {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
- return MakeGarbageCollected<NDEFWriter>(context);
-}
-
-NDEFWriter::NDEFWriter(ExecutionContext* context)
- : ExecutionContextClient(context), permission_service_(context) {}
-
-void NDEFWriter::Trace(Visitor* visitor) const {
- visitor->Trace(permission_service_);
- visitor->Trace(requests_);
- visitor->Trace(nfc_proxy_);
- ScriptWrappable::Trace(visitor);
- ExecutionContextClient::Trace(visitor);
-}
-
-// https://w3c.github.io/web-nfc/#writing-content
-// https://w3c.github.io/web-nfc/#the-write-method
-ScriptPromise NDEFWriter::write(ScriptState* script_state,
- const NDEFMessageSource& write_message,
- const NDEFWriteOptions* options,
- ExceptionState& exception_state) {
- LocalDOMWindow* window = script_state->ContextIsValid()
- ? LocalDOMWindow::From(script_state)
- : nullptr;
- // https://w3c.github.io/web-nfc/#security-policies
- // WebNFC API must be only accessible from top level browsing context.
- if (!window || !window->GetFrame()->IsMainFrame()) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
- "NFC interfaces are only avaliable "
- "in a top-level browsing context");
- return ScriptPromise();
- }
-
- if (options->hasSignal() && options->signal()->aborted()) {
- // If signal’s aborted flag is set, then reject p with an "AbortError"
- // DOMException and return p.
- exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
- "The NFC operation was cancelled.");
- return ScriptPromise();
- }
-
- // Step 11.2: Run "create NDEF message", if this throws an exception,
- // reject p with that exception and abort these steps.
- NDEFMessage* ndef_message =
- NDEFMessage::Create(window, write_message, exception_state);
- if (exception_state.HadException()) {
- return ScriptPromise();
- }
-
- auto message = device::mojom::blink::NDEFMessage::From(ndef_message);
- DCHECK(message);
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- requests_.insert(resolver);
- InitNfcProxyIfNeeded();
- GetPermissionService()->RequestPermission(
- CreatePermissionDescriptor(PermissionName::NFC),
- LocalFrame::HasTransientUserActivation(window->GetFrame()),
- WTF::Bind(&NDEFWriter::OnRequestPermission, WrapPersistent(this),
- WrapPersistent(resolver), WrapPersistent(options),
- std::move(message)));
-
- return resolver->Promise();
-}
-
-PermissionService* NDEFWriter::GetPermissionService() {
- if (!permission_service_.is_bound()) {
- ConnectToPermissionService(
- GetExecutionContext(),
- permission_service_.BindNewPipeAndPassReceiver(
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
- }
- return permission_service_.get();
-}
-
-void NDEFWriter::OnRequestPermission(
- ScriptPromiseResolver* resolver,
- const NDEFWriteOptions* options,
- device::mojom::blink::NDEFMessagePtr message,
- PermissionStatus status) {
- if (status != PermissionStatus::GRANTED) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotAllowedError, "NFC permission request denied."));
- return;
- }
-
- if (options->hasSignal() && options->signal()->aborted()) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kAbortError, "The NFC operation was cancelled."));
- return;
- }
-
- // If signal is not null, then add the abort steps to signal.
- if (options->hasSignal() && !options->signal()->aborted()) {
- options->signal()->AddAlgorithm(WTF::Bind(
- &NDEFWriter::Abort, WrapPersistent(this), WrapPersistent(resolver)));
- }
-
- UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcNdefWriterWrite);
- // TODO(https://crbug.com/994936) remove when origin trial is complete.
- UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcAPI);
-
- auto callback = WTF::Bind(&NDEFWriter::OnRequestCompleted,
- WrapPersistent(this), WrapPersistent(resolver));
- nfc_proxy_->Push(std::move(message),
- device::mojom::blink::NDEFWriteOptions::From(options),
- std::move(callback));
-}
-
-void NDEFWriter::OnMojoConnectionError() {
- nfc_proxy_.Clear();
-
- // If the mojo connection breaks, all push requests will be rejected with a
- // default error.
- for (ScriptPromiseResolver* resolver : requests_) {
- resolver->Reject(NDEFErrorTypeToDOMException(
- device::mojom::blink::NDEFErrorType::NOT_SUPPORTED,
- "WebNFC feature is unavailable or permission denied."));
- }
- requests_.clear();
-}
-
-void NDEFWriter::InitNfcProxyIfNeeded() {
- // Init NfcProxy if needed.
- if (nfc_proxy_)
- return;
-
- nfc_proxy_ = NFCProxy::From(*To<LocalDOMWindow>(GetExecutionContext()));
- DCHECK(nfc_proxy_);
-
- // Add the writer to proxy's writer list for mojo connection error
- // notification.
- nfc_proxy_->AddWriter(this);
-}
-
-void NDEFWriter::Abort(ScriptPromiseResolver* resolver) {
- // |nfc_proxy_| could be null on Mojo connection failure, simply ignore the
- // abort request in this case.
- if (!nfc_proxy_)
- return;
-
- // OnRequestCompleted() should always be called whether the push operation is
- // cancelled successfully or not. So do nothing for the cancelled callback.
- nfc_proxy_->CancelPush(device::mojom::blink::NFC::CancelPushCallback());
-}
-
-void NDEFWriter::OnRequestCompleted(ScriptPromiseResolver* resolver,
- device::mojom::blink::NDEFErrorPtr error) {
- DCHECK(requests_.Contains(resolver));
-
- requests_.erase(resolver);
-
- if (error.is_null()) {
- resolver->Resolve();
- } else {
- resolver->Reject(
- NDEFErrorTypeToDOMException(error->error_type, error->error_message));
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.h b/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.h
deleted file mode 100644
index 3e0631cbd36..00000000000
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.h
+++ /dev/null
@@ -1,74 +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_NFC_NDEF_WRITER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NDEF_WRITER_H_
-
-#include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_proxy.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/mojo/heap_mojo_remote.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
-
-namespace blink {
-
-class NDEFWriteOptions;
-class ExceptionState;
-class ExecutionContext;
-class ScriptPromise;
-class StringOrArrayBufferOrArrayBufferViewOrNDEFMessageInit;
-
-using NDEFMessageSource = StringOrArrayBufferOrArrayBufferViewOrNDEFMessageInit;
-
-class NDEFWriter : public ScriptWrappable, public ExecutionContextClient {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- static NDEFWriter* Create(ExecutionContext*);
-
- explicit NDEFWriter(ExecutionContext*);
- ~NDEFWriter() override = default;
-
- void Trace(Visitor*) const override;
-
- // Write NDEFMessageSource asynchronously to NFC tag.
- ScriptPromise write(ScriptState*,
- const NDEFMessageSource&,
- const NDEFWriteOptions*,
- ExceptionState&);
-
- // Called by NFCProxy for notification about connection error.
- void OnMojoConnectionError();
-
- private:
- void InitNfcProxyIfNeeded();
- void Abort(ScriptPromiseResolver* resolver);
- void OnRequestCompleted(ScriptPromiseResolver* resolver,
- device::mojom::blink::NDEFErrorPtr error);
-
- // Permission handling
- void OnRequestPermission(ScriptPromiseResolver* resolver,
- const NDEFWriteOptions* options,
- device::mojom::blink::NDEFMessagePtr ndef_message,
- mojom::blink::PermissionStatus status);
- mojom::blink::PermissionService* GetPermissionService();
-
- HeapMojoRemote<mojom::blink::PermissionService,
- HeapMojoWrapperMode::kWithoutContextObserver>
- permission_service_;
-
- // |requests_| are kept here to handle Mojo connection failures because
- // in that case the callback passed to Push() won't be called and
- // mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
- // This list will also be used by AbortSignal.
- HeapHashSet<Member<ScriptPromiseResolver>> requests_;
- Member<NFCProxy> nfc_proxy_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NDEF_WRITER_H_
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.idl b/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.idl
deleted file mode 100644
index 23e2dcce135..00000000000
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_writer.idl
+++ /dev/null
@@ -1,20 +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.
-
-// https://w3c.github.io/web-nfc/#dom-ndefmessagesource
-
-typedef (DOMString or BufferSource or NDEFMessageInit) NDEFMessageSource;
-
-// https://w3c.github.io/web-nfc/#dom-nfcwriter
-
-[
- RuntimeEnabled=WebNFC,
- SecureContext,
- Exposed=Window
-] interface NDEFWriter {
- [CallWith=ExecutionContext] constructor();
- [CallWith=ScriptState, RaisesException] Promise<void> write(
- NDEFMessageSource message,
- optional NDEFWriteOptions options={});
-};
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 2cf4c852dc3..aa09e8addd7 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -10,9 +10,7 @@
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/modules/nfc/ndef_reader.h"
-#include "third_party/blink/renderer/modules/nfc/ndef_writer.h"
#include "third_party/blink/renderer/modules/nfc/nfc_type_converters.h"
-#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
namespace blink {
@@ -22,10 +20,6 @@ const char NFCProxy::kSupplementName[] = "NFCProxy";
// static
NFCProxy* NFCProxy::From(LocalDOMWindow& window) {
- // https://w3c.github.io/web-nfc/#security-policies
- // WebNFC API must be only accessible from top level browsing context.
- DCHECK(window.GetFrame()->IsMainFrame());
-
NFCProxy* nfc_proxy = Supplement<LocalDOMWindow>::From<NFCProxy>(window);
if (!nfc_proxy) {
nfc_proxy = MakeGarbageCollected<NFCProxy>(window);
@@ -66,11 +60,8 @@ void NFCProxy::StopReading(NDEFReader* reader) {
DCHECK(reader);
auto iter = readers_.find(reader);
if (iter != readers_.end()) {
- if (nfc_remote_) {
- // We do not need to notify |reader| of anything.
- nfc_remote_->CancelWatch(
- iter->value, device::mojom::blink::NFC::CancelWatchCallback());
- }
+ if (nfc_remote_)
+ nfc_remote_->CancelWatch(iter->value);
readers_.erase(iter);
}
}
@@ -80,9 +71,9 @@ bool NFCProxy::IsReading(const NDEFReader* reader) {
return readers_.Contains(const_cast<NDEFReader*>(reader));
}
-void NFCProxy::AddWriter(NDEFWriter* writer) {
- DCHECK(!writers_.Contains(writer));
- writers_.insert(writer);
+void NFCProxy::AddWriter(NDEFReader* writer) {
+ if (!writers_.Contains(writer))
+ writers_.insert(writer);
}
void NFCProxy::Push(device::mojom::blink::NDEFMessagePtr message,
@@ -92,10 +83,10 @@ void NFCProxy::Push(device::mojom::blink::NDEFMessagePtr message,
nfc_remote_->Push(std::move(message), std::move(options), std::move(cb));
}
-void NFCProxy::CancelPush(
- device::mojom::blink::NFC::CancelPushCallback callback) {
- DCHECK(nfc_remote_);
- nfc_remote_->CancelPush(std::move(callback));
+void NFCProxy::CancelPush() {
+ if (!nfc_remote_)
+ return;
+ nfc_remote_->CancelPush();
}
// device::mojom::blink::NFCClient implementation.
@@ -115,11 +106,11 @@ void NFCProxy::OnWatch(const Vector<uint32_t>& watch_ids,
void NFCProxy::OnError(device::mojom::blink::NDEFErrorPtr error) {
// Dispatch the event to all readers. We iterate on a copy of |readers_|
- // because a reader's onerror event handler may remove itself from |readers_|
- // just during the iteration process.
+ // because a reader's onreadingerror event handler may remove itself from
+ // |readers_| just during the iteration process.
ReaderMap copy = readers_;
for (auto& pair : copy) {
- pair.key->OnError(error->error_message);
+ pair.key->OnReadingError(error->error_message);
}
}
@@ -180,21 +171,20 @@ void NFCProxy::OnMojoConnectionError() {
nfc_remote_.reset();
client_receiver_.reset();
- // Notify all active readers about the connection error and clear the list.
+ // Notify all active readers about the connection error.
ReaderMap readers = std::move(readers_);
for (auto& pair : readers) {
- pair.key->OnMojoConnectionError();
+ pair.key->ReadOnMojoConnectionError();
}
// Each connection maintains its own watch ID numbering, so reset to 1 on
// connection error.
next_watch_id_ = 1;
- // Notify all writers about the connection error.
+ // Notify all writers about the connection error and clear the list.
for (auto& writer : writers_) {
- writer->OnMojoConnectionError();
+ writer->WriteOnMojoConnectionError();
}
- // Clear the reader list.
writers_.clear();
}
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 2054198e35c..751dcd9d0dd 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -18,9 +18,8 @@ namespace blink {
class LocalDOMWindow;
class NDEFReader;
-class NDEFWriter;
-// This is a proxy class used by NDEFWriter(s) and NDEFReader(s) to connect
+// This is a proxy class used by NDEFReader(s) to connect
// to implementation of device::mojom::blink::NFC interface.
class MODULES_EXPORT NFCProxy final : public GarbageCollected<NFCProxy>,
public Supplement<LocalDOMWindow>,
@@ -37,7 +36,7 @@ class MODULES_EXPORT NFCProxy final : public GarbageCollected<NFCProxy>,
// There is no matching RemoveWriter() method because writers are
// automatically removed from the weak hash set when they are garbage
// collected.
- void AddWriter(NDEFWriter*);
+ void AddWriter(NDEFReader*);
void StartReading(NDEFReader*,
device::mojom::blink::NFC::WatchCallback);
@@ -46,7 +45,7 @@ class MODULES_EXPORT NFCProxy final : public GarbageCollected<NFCProxy>,
void Push(device::mojom::blink::NDEFMessagePtr,
device::mojom::blink::NDEFWriteOptionsPtr,
device::mojom::blink::NFC::PushCallback);
- void CancelPush(device::mojom::blink::NFC::CancelPushCallback);
+ void CancelPush();
private:
// Implementation of device::mojom::blink::NFCClient.
@@ -74,7 +73,7 @@ class MODULES_EXPORT NFCProxy final : public GarbageCollected<NFCProxy>,
using ReaderMap = HeapHashMap<WeakMember<NDEFReader>, uint32_t>;
ReaderMap readers_;
- using WriterSet = HeapHashSet<WeakMember<NDEFWriter>>;
+ using WriterSet = HeapHashSet<WeakMember<NDEFReader>>;
WriterSet writers_;
mojo::Remote<device::mojom::blink::NFC> nfc_remote_;
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 2f65ec30f94..5f08d0a2823 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
@@ -105,9 +105,7 @@ class FakeNfcService : public device::mojom::blink::NFC {
set_tag_message(std::move(message));
std::move(callback).Run(nullptr);
}
- void CancelPush(CancelPushCallback callback) override {
- std::move(callback).Run(nullptr);
- }
+ void CancelPush() override {}
void Watch(uint32_t id, WatchCallback callback) override {
if (watch_error_) {
std::move(callback).Run(watch_error_.Clone());
@@ -117,19 +115,10 @@ class FakeNfcService : public device::mojom::blink::NFC {
watchIDs_.push_back(id);
std::move(callback).Run(nullptr);
}
- void CancelWatch(uint32_t id, CancelWatchCallback callback) override {
+ void CancelWatch(uint32_t id) override {
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 {
+ if (index != kNotFound)
watchIDs_.EraseAt(index);
- std::move(callback).Run(nullptr);
- }
- }
- void CancelAllWatches(CancelAllWatchesCallback callback) override {
- watchIDs_.clear();
- std::move(callback).Run(nullptr);
}
device::mojom::blink::NDEFErrorPtr watch_error_;
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 b1d727b785c..b9b3be66564 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
@@ -11,7 +11,6 @@
#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"
-#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
using device::mojom::blink::NDEFMessage;
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.cc
deleted file mode 100644
index 9e01de92619..00000000000
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.cc
+++ /dev/null
@@ -1,49 +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/nfc/nfc_utils.h"
-
-#include <limits>
-#include <utility>
-
-#include "services/device/public/mojom/nfc.mojom-blink.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
-
-namespace blink {
-
-DOMException* NDEFErrorTypeToDOMException(
- device::mojom::blink::NDEFErrorType error_type,
- const String& error_message) {
- switch (error_type) {
- case device::mojom::blink::NDEFErrorType::NOT_ALLOWED:
- return MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotAllowedError, error_message);
- case device::mojom::blink::NDEFErrorType::NOT_SUPPORTED:
- return MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotSupportedError, error_message);
- case device::mojom::blink::NDEFErrorType::NOT_READABLE:
- return MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotReadableError, error_message);
- case device::mojom::blink::NDEFErrorType::NOT_FOUND:
- return MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotFoundError, error_message);
- case device::mojom::blink::NDEFErrorType::INVALID_MESSAGE:
- return MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
- error_message);
- case device::mojom::blink::NDEFErrorType::OPERATION_CANCELLED:
- return MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError,
- error_message);
- case device::mojom::blink::NDEFErrorType::CANNOT_CANCEL:
- return MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNoModificationAllowedError, error_message);
- case device::mojom::blink::NDEFErrorType::IO_ERROR:
- return MakeGarbageCollected<DOMException>(DOMExceptionCode::kNetworkError,
- error_message);
- }
- NOTREACHED();
- // Don't need to handle the case after a NOTREACHED().
- return nullptr;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.h b/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.h
deleted file mode 100644
index 36d0f2387f8..00000000000
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_utils.h
+++ /dev/null
@@ -1,21 +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_NFC_NFC_UTILS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_UTILS_H_
-
-#include "services/device/public/mojom/nfc.mojom-blink-forward.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class DOMException;
-
-DOMException* NDEFErrorTypeToDOMException(
- device::mojom::blink::NDEFErrorType error_type,
- const String& error_message);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/notifications/DIR_METADATA b/chromium/third_party/blink/renderer/modules/notifications/DIR_METADATA
new file mode 100644
index 00000000000..72589bbc922
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/notifications/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/notifications/OWNERS b/chromium/third_party/blink/renderer/modules/notifications/OWNERS
index a5683f2d832..a28f3fedb50 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/notifications/OWNERS
@@ -1,5 +1,2 @@
knollr@chromium.org
peter@chromium.org
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: UI>Notifications
diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification.cc b/chromium/third_party/blink/renderer/modules/notifications/notification.cc
index 66bdb8e0623..107955009fc 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/notification.cc
+++ b/chromium/third_party/blink/renderer/modules/notifications/notification.cc
@@ -502,6 +502,7 @@ bool Notification::HasPendingActivity() const {
void Notification::Trace(Visitor* visitor) const {
visitor->Trace(show_trigger_);
+ visitor->Trace(prepare_show_timer_);
visitor->Trace(loader_);
visitor->Trace(listener_receiver_);
EventTargetWithInlineData::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification.h b/chromium/third_party/blink/renderer/modules/notifications/notification.h
index f2b84914d67..2441a876f90 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/notification.h
+++ b/chromium/third_party/blink/renderer/modules/notifications/notification.h
@@ -187,7 +187,7 @@ class MODULES_EXPORT Notification final
String token_;
- TaskRunnerTimer<Notification> prepare_show_timer_;
+ HeapTaskRunnerTimer<Notification> prepare_show_timer_;
Member<NotificationResourcesLoader> loader_;
diff --git a/chromium/third_party/blink/renderer/modules/payments/DEPS b/chromium/third_party/blink/renderer/modules/payments/DEPS
index a7c0a85b25e..62ea8006283 100644
--- a/chromium/third_party/blink/renderer/modules/payments/DEPS
+++ b/chromium/third_party/blink/renderer/modules/payments/DEPS
@@ -1,3 +1,6 @@
include_rules = [
+ "+base/test/scoped_command_line.h",
"+components/payments/mojom",
+ "+services/network/public/cpp/is_potentially_trustworthy.h",
+ "+services/network/public/cpp/network_switches.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/payments/DIR_METADATA b/chromium/third_party/blink/renderer/modules/payments/DIR_METADATA
new file mode 100644
index 00000000000..667a28bf378
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/payments/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Payments"
+}
+team_email: "payments-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/payments/OWNERS b/chromium/third_party/blink/renderer/modules/payments/OWNERS
index 3bc3573d3eb..06b9d2b61e9 100644
--- a/chromium/third_party/blink/renderer/modules/payments/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/payments/OWNERS
@@ -1,5 +1,3 @@
-# TEAM: payments-dev@chromium.org
-# COMPONENT: Blink>Payments
file://components/payments/OWNERS
@@ -10,4 +8,4 @@ per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
# Emeritus
-mathp@chromium.org
+mathp@chromium.org \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/payments/abort_test.cc b/chromium/third_party/blink/renderer/modules/payments/abort_test.cc
index 0e1963d90d8..b9ca0e3978c 100644
--- a/chromium/third_party/blink/renderer/modules/payments/abort_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/abort_test.cc
@@ -6,6 +6,7 @@
#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/testing/mock_function_scope.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"
@@ -45,7 +46,7 @@ TEST(AbortTest, CannotAbortTwiceConcurrently) {
// should not reject with exception.
TEST(AbortTest, CanAbortAfterShow) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -59,7 +60,7 @@ TEST(AbortTest, CanAbortAfterShow) {
// promise should be rejected.
TEST(AbortTest, FailedAbortShouldRejectAbortPromise) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -76,7 +77,7 @@ TEST(AbortTest, FailedAbortShouldRejectAbortPromise) {
// call should not be rejected, as it's not a duplicate request anymore.
TEST(AbortTest, CanAbortAgainAfterFirstAbortRejected) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -93,7 +94,7 @@ TEST(AbortTest, CanAbortAgainAfterFirstAbortRejected) {
// promise should be rejected, and request.abort() promise should be resolved.
TEST(AbortTest, SuccessfulAbortShouldRejectShowPromiseAndResolveAbortPromise) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
index 1959cffb3e5..6204aa137e9 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_can_make_payment_response.h"
diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
index 96b539aee6d..a11161854c8 100644
--- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
@@ -6,6 +6,7 @@
#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/testing/mock_function_scope.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"
@@ -20,7 +21,7 @@ using payments::mojom::blink::PaymentRequestClient;
TEST(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -34,7 +35,7 @@ TEST(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) {
TEST(HasEnrolledInstrumentTest, RejectPromiseOnUnknownError) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -60,7 +61,7 @@ TEST(HasEnrolledInstrumentTest, RejectDuplicateRequest) {
TEST(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -74,7 +75,7 @@ TEST(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) {
TEST(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -91,7 +92,7 @@ TEST(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) {
TEST(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -108,7 +109,7 @@ TEST(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) {
TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -123,7 +124,7 @@ TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -149,7 +150,7 @@ TEST(CanMakePaymentTest, RejectDuplicateRequest) {
TEST(CanMakePaymentTest, ReturnCannotMakePayment) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -166,7 +167,7 @@ TEST(CanMakePaymentTest, ReturnCannotMakePayment) {
TEST(CanMakePaymentTest, ReturnCanMakePayment) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/chromium/third_party/blink/renderer/modules/payments/complete_test.cc b/chromium/third_party/blink/renderer/modules/payments/complete_test.cc
index 112020f7ef5..9624f7536f8 100644
--- a/chromium/third_party/blink/renderer/modules/payments/complete_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/complete_test.cc
@@ -6,6 +6,7 @@
#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/testing/mock_function_scope.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"
@@ -34,7 +35,7 @@ TEST(CompleteTest, CannotCallCompleteTwice) {
TEST(CompleteTest, ResolveCompletePromiseOnUnknownError) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -54,7 +55,7 @@ TEST(CompleteTest, ResolveCompletePromiseOnUnknownError) {
TEST(CompleteTest, ResolveCompletePromiseOnUserClosingUI) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -96,7 +97,7 @@ TEST(CompleteTest, RejectCompletePromiseAfterError) {
TEST(CompleteTest, ResolvePromiseOnComplete) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -116,7 +117,7 @@ TEST(CompleteTest, ResolvePromiseOnComplete) {
TEST(CompleteTest, RejectCompletePromiseOnUpdateDetailsFailure) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -140,7 +141,7 @@ TEST(CompleteTest, RejectCompletePromiseOnUpdateDetailsFailure) {
TEST(CompleteTest, RejectCompletePromiseAfterTimeout) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/DIR_METADATA b/chromium/third_party/blink/renderer/modules/payments/goods/DIR_METADATA
new file mode 100644
index 00000000000..8089f462851
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "UI>Browser>WebAppInstalls>ChromeOS"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/OWNERS b/chromium/third_party/blink/renderer/modules/payments/goods/OWNERS
index b4b867f7536..a3636bd541b 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/OWNERS
@@ -3,5 +3,3 @@ mgiuca@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: UI>Browser>WebAppInstalls>ChromeOS
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 f1a6c0b8276..fd0b44a47ab 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
@@ -8,11 +8,11 @@
#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/heap/visitor.h"
namespace blink {
class ScriptState;
-class Visitor;
class DigitalGoodsService final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
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 c1c276606bf..76b618ed94a 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
@@ -8,13 +8,13 @@
#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/heap/visitor.h"
#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
class LocalDOMWindow;
class ScriptState;
-class Visitor;
class DOMWindowDigitalGoods final
: public GarbageCollected<DOMWindowDigitalGoods>,
diff --git a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
index fd30e364600..c9ba619104e 100644
--- a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_response.h"
+#include "third_party/blink/renderer/core/testing/mock_function_scope.h"
#include "third_party/blink/renderer/modules/payments/payment_address.h"
#include "third_party/blink/renderer/modules/payments/payment_request.h"
#include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
@@ -20,7 +21,7 @@ namespace {
// provide the shipping option, reject the show() promise.
TEST(OnPaymentResponseTest, RejectMissingShippingOption) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -42,7 +43,7 @@ TEST(OnPaymentResponseTest, RejectMissingShippingOption) {
// provide a shipping address, reject the show() promise.
TEST(OnPaymentResponseTest, RejectMissingAddress) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -63,7 +64,7 @@ TEST(OnPaymentResponseTest, RejectMissingAddress) {
// reject the show() promise.
TEST(OnPaymentResponseTest, RejectMissingName) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerName(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -83,7 +84,7 @@ TEST(OnPaymentResponseTest, RejectMissingName) {
// it, reject the show() promise.
TEST(OnPaymentResponseTest, RejectMissingEmail) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerEmail(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -103,7 +104,7 @@ TEST(OnPaymentResponseTest, RejectMissingEmail) {
// reject the show() promise.
TEST(OnPaymentResponseTest, RejectMissingPhone) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerPhone(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -123,7 +124,7 @@ TEST(OnPaymentResponseTest, RejectMissingPhone) {
// empty string for shipping option, reject the show() promise.
TEST(OnPaymentResponseTest, RejectEmptyShippingOption) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -146,7 +147,7 @@ TEST(OnPaymentResponseTest, RejectEmptyShippingOption) {
// empty shipping address, reject the show() promise.
TEST(OnPaymentResponseTest, RejectEmptyAddress) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -168,7 +169,7 @@ TEST(OnPaymentResponseTest, RejectEmptyAddress) {
// string for name, reject the show() promise.
TEST(OnPaymentResponseTest, RejectEmptyName) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerName(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -189,7 +190,7 @@ TEST(OnPaymentResponseTest, RejectEmptyName) {
// for email, reject the show() promise.
TEST(OnPaymentResponseTest, RejectEmptyEmail) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerEmail(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -210,7 +211,7 @@ TEST(OnPaymentResponseTest, RejectEmptyEmail) {
// string for the phone number, reject the show() promise.
TEST(OnPaymentResponseTest, RejectEmptyPhone) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerPhone(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -231,7 +232,7 @@ TEST(OnPaymentResponseTest, RejectEmptyPhone) {
// provides a shipping address, reject the show() promise.
TEST(OnPaymentResponseTest, RejectNotRequestedAddress) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -253,7 +254,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedAddress) {
// provides a shipping option, reject the show() promise.
TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -274,7 +275,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption) {
// reject the show() promise.
TEST(OnPaymentResponseTest, RejectNotRequestedName) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerName(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -295,7 +296,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedName) {
// reject the show() promise.
TEST(OnPaymentResponseTest, RejectNotRequestedEmail) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerEmail(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -316,7 +317,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedEmail) {
// reject the show() promise.
TEST(OnPaymentResponseTest, RejectNotRequestedPhone) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerPhone(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -337,7 +338,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedPhone) {
// invalid shipping address, reject the show() promise.
TEST(OnPaymentResponseTest, RejectInvalidAddress) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -384,7 +385,7 @@ class PaymentResponseFunction : public ScriptFunction {
// should contain a shipping option and an address.
TEST(OnPaymentResponseTest, CanRequestShippingInformation) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -413,7 +414,7 @@ TEST(OnPaymentResponseTest, CanRequestShippingInformation) {
// contain a payer name.
TEST(OnPaymentResponseTest, CanRequestName) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerName(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -441,7 +442,7 @@ TEST(OnPaymentResponseTest, CanRequestName) {
// contain an email address.
TEST(OnPaymentResponseTest, CanRequestEmail) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerEmail(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -468,7 +469,7 @@ TEST(OnPaymentResponseTest, CanRequestEmail) {
// contain a phone number.
TEST(OnPaymentResponseTest, CanRequestPhone) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerPhone(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -496,7 +497,7 @@ TEST(OnPaymentResponseTest, CanRequestPhone) {
// promise should contain null shipping option and address.
TEST(OnPaymentResponseTest, ShippingInformationNotRequired) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -521,7 +522,7 @@ TEST(OnPaymentResponseTest, ShippingInformationNotRequired) {
// should contain null phone number.
TEST(OnPaymentResponseTest, PhoneNotRequred) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerPhone(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -548,7 +549,7 @@ TEST(OnPaymentResponseTest, PhoneNotRequred) {
// should contain null payer name.
TEST(OnPaymentResponseTest, NameNotRequired) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerName(false);
PaymentRequest* request = PaymentRequest::Create(
@@ -575,7 +576,7 @@ TEST(OnPaymentResponseTest, NameNotRequired) {
// promise should contain null email address.
TEST(OnPaymentResponseTest, EmailNotRequired) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestPayerEmail(false);
PaymentRequest* request = PaymentRequest::Create(
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_handler_utils.cc b/chromium/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
index 49b54a10d8f..ac69d2dbc14 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
@@ -48,6 +48,7 @@ void PaymentHandlerUtils::ReportResponseError(
case ServiceWorkerResponseError::kResponseTypeCorsForRequestModeSameOrigin:
case ServiceWorkerResponseError::kResponseBodyBroken:
case ServiceWorkerResponseError::kDisallowedByCorp:
+ case ServiceWorkerResponseError::kRequestBodyUnusable:
NOTREACHED();
error_message = error_message + "an unexpected error occurred.";
break;
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 6a6523f7f3e..247cc7e239d 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_owner.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -60,6 +61,7 @@
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/weborigin/reporting_disposition.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -701,6 +703,15 @@ void ValidateAndConvertPaymentMethodData(
}
}
+ KURL url(payment_method_data->supportedMethod());
+ if (url.IsValid() &&
+ !execution_context.GetContentSecurityPolicy()->AllowConnectToSource(
+ url, url, RedirectStatus::kNoRedirect,
+ ReportingDisposition::kSuppressReporting)) {
+ UseCounter::Count(&execution_context,
+ WebFeature::kPaymentRequestCSPViolation);
+ }
+
method_names.insert(payment_method_data->supportedMethod());
output.push_back(payments::mojom::blink::PaymentMethodData::New());
@@ -808,27 +819,45 @@ ScriptPromise PaymentRequest::show(ScriptState* script_state,
return ScriptPromise();
}
- // TODO(crbug.com/825270): Reject with SecurityError DOMException if triggered
- // without user activation.
- bool is_user_gesture =
- LocalFrame::HasTransientUserActivation(DomWindow()->GetFrame());
- if (!is_user_gesture) {
+ LocalFrame* local_frame = DomWindow()->GetFrame();
+
+ bool payment_request_allowed =
+ LocalFrame::HasTransientUserActivation(local_frame);
+ if (!payment_request_allowed) {
UseCounter::Count(GetExecutionContext(),
WebFeature::kPaymentRequestShowWithoutGesture);
}
- // TODO(crbug.com/825270): Pretend that a user gesture is provided to allow
- // origins that are part of the Secure Payment Confirmation Origin Trial to
- // use skip-the-sheet flow as a hack for secure modal window
- // (crbug.com/1122028). Remove this after user gesture delegation ships.
- if (RuntimeEnabledFeatures::SecurePaymentConfirmationEnabled(
+ if (RuntimeEnabledFeatures::CapabilityDelegationPaymentRequestEnabled(
GetExecutionContext())) {
- is_user_gesture = true;
+ payment_request_allowed |= local_frame->IsPaymentRequestTokenActive();
+ if (!payment_request_allowed) {
+ String message =
+ "PaymentRequest.show() requires either transient user activation or "
+ "delegated payment request capability";
+ GetExecutionContext()->AddConsoleMessage(
+ MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning, message));
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
+ message);
+ return ScriptPromise();
+ }
+ LocalFrame::ConsumeTransientUserActivation(local_frame);
+ local_frame->ConsumePaymentRequestToken();
+
+ } else if (RuntimeEnabledFeatures::SecurePaymentConfirmationEnabled(
+ GetExecutionContext())) {
+ // TODO(crbug.com/825270): Pretend that a user gesture is provided to allow
+ // origins that are part of the Secure Payment Confirmation Origin Trial to
+ // use skip-the-sheet flow as a hack for secure modal window
+ // (crbug.com/1122028). Remove this after user gesture delegation ships.
+ payment_request_allowed = true;
}
// TODO(crbug.com/779126): add support for handling payment requests in
// immersive mode.
- if (DomWindow()->GetFrame()->GetSettings()->GetImmersiveModeEnabled()) {
+ if (local_frame->GetSettings()->GetImmersiveModeEnabled()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Page popups are suppressed");
return ScriptPromise();
@@ -839,7 +868,7 @@ ScriptPromise PaymentRequest::show(ScriptState* script_state,
UseCounter::Count(GetExecutionContext(), WebFeature::kPaymentRequestShow);
is_waiting_for_show_promise_to_resolve_ = !details_promise.IsEmpty();
- payment_provider_->Show(is_user_gesture,
+ payment_provider_->Show(payment_request_allowed,
is_waiting_for_show_promise_to_resolve_);
if (is_waiting_for_show_promise_to_resolve_) {
// If the website does not calculate the final shopping cart contents within
@@ -1170,6 +1199,8 @@ void PaymentRequest::Trace(Visitor* visitor) const {
visitor->Trace(has_enrolled_instrument_resolver_);
visitor->Trace(payment_provider_);
visitor->Trace(client_receiver_);
+ visitor->Trace(complete_timer_);
+ visitor->Trace(update_payment_details_timer_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
@@ -1503,11 +1534,15 @@ void PaymentRequest::OnError(PaymentErrorReason error,
switch (error) {
case PaymentErrorReason::USER_CANCEL:
+ // Intentional fall through.
+ case PaymentErrorReason::INVALID_DATA_FROM_RENDERER:
+ // Intentional fall through.
+ case PaymentErrorReason::ALREADY_SHOWING:
exception_code = DOMExceptionCode::kAbortError;
break;
case PaymentErrorReason::NOT_SUPPORTED:
- exception_code = exception_code = DOMExceptionCode::kNotSupportedError;
+ exception_code = DOMExceptionCode::kNotSupportedError;
break;
case PaymentErrorReason::NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL:
@@ -1515,10 +1550,6 @@ void PaymentRequest::OnError(PaymentErrorReason error,
not_supported_for_invalid_origin_or_ssl_error_ = error_message;
break;
- case PaymentErrorReason::ALREADY_SHOWING:
- exception_code = DOMExceptionCode::kAbortError;
- break;
-
case PaymentErrorReason::UNKNOWN:
break;
}
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 161a776c4ad..d18cc156ede 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.h
@@ -183,8 +183,8 @@ class MODULES_EXPORT PaymentRequest final
HeapMojoRemote<payments::mojom::blink::PaymentRequest> payment_provider_;
HeapMojoReceiver<payments::mojom::blink::PaymentRequestClient, PaymentRequest>
client_receiver_;
- TaskRunnerTimer<PaymentRequest> complete_timer_;
- TaskRunnerTimer<PaymentRequest> update_payment_details_timer_;
+ HeapTaskRunnerTimer<PaymentRequest> complete_timer_;
+ HeapTaskRunnerTimer<PaymentRequest> update_payment_details_timer_;
bool is_waiting_for_show_promise_to_resolve_;
bool ignore_total_;
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 a76e0ea88ff..ec991c8c742 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
@@ -359,8 +359,7 @@ void PaymentRequestEvent::OnChangePaymentRequestDetailsResponse(
"PaymentDetailsModifier");
if (response->modifiers) {
- auto* modifiers =
- MakeGarbageCollected<HeapVector<Member<PaymentDetailsModifier>>>();
+ HeapVector<Member<PaymentDetailsModifier>> modifiers;
for (const auto& response_modifier : *response->modifiers) {
if (!response_modifier)
continue;
@@ -390,15 +389,14 @@ void PaymentRequestEvent::OnChangePaymentRequestDetailsResponse(
return;
}
mod->setData(ScriptValue(script_state->GetIsolate(), parsed_value));
- modifiers->emplace_back(mod);
+ modifiers.emplace_back(mod);
}
}
- dictionary->setModifiers(*modifiers);
+ dictionary->setModifiers(modifiers);
}
if (response->shipping_options) {
- auto* shipping_options =
- MakeGarbageCollected<HeapVector<Member<PaymentShippingOption>>>();
+ HeapVector<Member<PaymentShippingOption>> shipping_options;
for (const auto& response_shipping_option : *response->shipping_options) {
if (!response_shipping_option)
continue;
@@ -411,9 +409,9 @@ void PaymentRequestEvent::OnChangePaymentRequestDetailsResponse(
shipping_option->setId(response_shipping_option->id);
shipping_option->setLabel(response_shipping_option->label);
shipping_option->setSelected(response_shipping_option->selected);
- shipping_options->emplace_back(shipping_option);
+ shipping_options.emplace_back(shipping_option);
}
- dictionary->setShippingOptions(*shipping_options);
+ dictionary->setShippingOptions(shipping_options);
}
if (response->stringified_payment_method_errors &&
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_test.cc
index 740369cac3d..c4ffa0245a6 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_test.cc
@@ -5,12 +5,17 @@
#include "third_party/blink/renderer/modules/payments/payment_request.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-blink-forward.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/testing/mock_function_scope.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/runtime_enabled_features.h"
namespace blink {
namespace {
@@ -242,7 +247,7 @@ TEST(PaymentRequestTest, PickupShippingTypeWhenShippingTypeIsPickup) {
TEST(PaymentRequestTest, RejectShowPromiseOnInvalidShippingAddress) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -256,7 +261,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnInvalidShippingAddress) {
TEST(PaymentRequestTest, OnShippingOptionChange) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -270,7 +275,7 @@ TEST(PaymentRequestTest, OnShippingOptionChange) {
TEST(PaymentRequestTest, CannotCallShowTwice) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -283,7 +288,7 @@ TEST(PaymentRequestTest, CannotCallShowTwice) {
TEST(PaymentRequestTest, CannotShowAfterAborted) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -298,9 +303,37 @@ TEST(PaymentRequestTest, CannotShowAfterAborted) {
;
}
+TEST(PaymentRequestTest, CannotShowWithoutUserActivation) {
+ RuntimeEnabledFeatures::SetCapabilityDelegationPaymentRequestEnabled(true);
+ PaymentRequestV8TestingScope scope;
+ MockFunctionScope funcs(scope.GetScriptState());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
+ request->show(scope.GetScriptState(), scope.GetExceptionState());
+ EXPECT_EQ(scope.GetExceptionState().Code(),
+ ToExceptionCode(DOMExceptionCode::kNotAllowedError));
+ ;
+}
+
+TEST(PaymentRequestTest, ShowConsumesUserActivation) {
+ RuntimeEnabledFeatures::SetCapabilityDelegationPaymentRequestEnabled(true);
+ PaymentRequestV8TestingScope scope;
+ MockFunctionScope funcs(scope.GetScriptState());
+ PaymentRequest* request = PaymentRequest::Create(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
+
+ LocalFrame::NotifyUserActivation(
+ &(scope.GetFrame()), mojom::UserActivationNotificationType::kTest);
+ request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)
+ .Then(funcs.ExpectNoCall(), funcs.ExpectNoCall());
+ EXPECT_FALSE(LocalFrame::HasTransientUserActivation(&(scope.GetFrame())));
+}
+
TEST(PaymentRequestTest, RejectShowPromiseOnErrorPaymentMethodNotSupported) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -320,7 +353,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnErrorPaymentMethodNotSupported) {
TEST(PaymentRequestTest, RejectShowPromiseOnErrorCancelled) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -339,7 +372,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnErrorCancelled) {
TEST(PaymentRequestTest, RejectShowPromiseOnUpdateDetailsFailure) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -358,7 +391,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnUpdateDetailsFailure) {
TEST(PaymentRequestTest, IgnoreUpdatePaymentDetailsAfterShowPromiseResolved) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -373,7 +406,7 @@ TEST(PaymentRequestTest, IgnoreUpdatePaymentDetailsAfterShowPromiseResolved) {
TEST(PaymentRequestTest, RejectShowPromiseOnNonPaymentDetailsUpdate) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -389,7 +422,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnNonPaymentDetailsUpdate) {
TEST(PaymentRequestTest, RejectShowPromiseOnInvalidPaymentDetailsUpdate) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -409,7 +442,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnInvalidPaymentDetailsUpdate) {
TEST(PaymentRequestTest,
ClearShippingOptionOnPaymentDetailsUpdateWithoutShippingOptions) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentDetailsInit* details = PaymentDetailsInit::Create();
details->setTotal(BuildPaymentItemForTest());
PaymentOptions* options = PaymentOptions::Create();
@@ -453,7 +486,7 @@ TEST(
PaymentRequestTest,
ClearShippingOptionOnPaymentDetailsUpdateWithMultipleUnselectedShippingOptions) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -480,7 +513,7 @@ TEST(
TEST(PaymentRequestTest, UseTheSelectedShippingOptionFromPaymentDetailsUpdate) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentOptions* options = PaymentOptions::Create();
options->setRequestShipping(true);
PaymentRequest* request = PaymentRequest::Create(
@@ -509,7 +542,7 @@ TEST(PaymentRequestTest, UseTheSelectedShippingOptionFromPaymentDetailsUpdate) {
TEST(PaymentRequestTest, NoExceptionWithErrorMessageInUpdate) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
@@ -531,7 +564,7 @@ TEST(PaymentRequestTest, NoExceptionWithErrorMessageInUpdate) {
TEST(PaymentRequestTest,
ShouldResolveWithExceptionIfIDsOfShippingOptionsAreDuplicated) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentDetailsInit* details = PaymentDetailsInit::Create();
details->setTotal(BuildPaymentItemForTest());
HeapVector<Member<PaymentShippingOption>> shipping_options(2);
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
index 105d4e2eb84..791252ca350 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/testing/mock_function_scope.h"
#include "third_party/blink/renderer/modules/payments/payment_request.h"
#include "third_party/blink/renderer/modules/payments/payment_request_delegate.h"
#include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
@@ -134,7 +135,7 @@ TEST(PaymentRequestUpdateEventTest, UpdaterNotRequired) {
TEST(PaymentRequestUpdateEventTest, AddressChangeUpdateWithTimeout) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
@@ -171,7 +172,7 @@ TEST(PaymentRequestUpdateEventTest, AddressChangeUpdateWithTimeout) {
TEST(PaymentRequestUpdateEventTest, OptionChangeUpdateWithTimeout) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
@@ -208,7 +209,7 @@ TEST(PaymentRequestUpdateEventTest, OptionChangeUpdateWithTimeout) {
TEST(PaymentRequestUpdateEventTest, AddressChangePromiseTimeout) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
@@ -242,7 +243,7 @@ TEST(PaymentRequestUpdateEventTest, AddressChangePromiseTimeout) {
TEST(PaymentRequestUpdateEventTest, OptionChangePromiseTimeout) {
PaymentRequestV8TestingScope scope;
- PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+ MockFunctionScope funcs(scope.GetScriptState());
PaymentRequest* request = PaymentRequest::Create(
scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc
index 71bb2070138..ab341c9d86e 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc
@@ -8,8 +8,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_details_modifier.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_method_data.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
@@ -216,60 +215,4 @@ payments::mojom::blink::PaymentAddressPtr BuildPaymentAddressForTest() {
PaymentRequestV8TestingScope::PaymentRequestV8TestingScope()
: V8TestingScope(KURL("https://www.example.com/")) {}
-PaymentRequestMockFunctionScope::PaymentRequestMockFunctionScope(
- ScriptState* script_state)
- : script_state_(script_state) {}
-
-PaymentRequestMockFunctionScope::~PaymentRequestMockFunctionScope() {
- v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate());
- for (MockFunction* mock_function : mock_functions_) {
- testing::Mock::VerifyAndClearExpectations(mock_function);
- }
-}
-
-v8::Local<v8::Function> PaymentRequestMockFunctionScope::ExpectCall(
- String* captor) {
- mock_functions_.push_back(
- MakeGarbageCollected<MockFunction>(script_state_, captor));
- EXPECT_CALL(*mock_functions_.back(), Call(testing::_));
- return mock_functions_.back()->Bind();
-}
-
-v8::Local<v8::Function> PaymentRequestMockFunctionScope::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> PaymentRequestMockFunctionScope::ExpectNoCall() {
- mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_));
- EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0);
- return mock_functions_.back()->Bind();
-}
-
-ACTION_P2(SaveValueIn, script_state, captor) {
- *captor = ToCoreString(
- arg0.V8Value()->ToString(script_state->GetContext()).ToLocalChecked());
-}
-
-PaymentRequestMockFunctionScope::MockFunction::MockFunction(
- ScriptState* script_state)
- : ScriptFunction(script_state) {
- ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>());
-}
-
-PaymentRequestMockFunctionScope::MockFunction::MockFunction(
- ScriptState* script_state,
- String* captor)
- : ScriptFunction(script_state), value_(captor) {
- ON_CALL(*this, Call(testing::_))
- .WillByDefault(
- testing::DoAll(SaveValueIn(WrapPersistent(script_state), value_),
- testing::ReturnArg<0>()));
-}
-
-v8::Local<v8::Function> PaymentRequestMockFunctionScope::MockFunction::Bind() {
- return BindToV8Function();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.h b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.h
index 44933b8c6d9..ad09593507e 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.h
@@ -23,8 +23,6 @@
namespace blink {
class PaymentMethodData;
-class ScriptState;
-class ScriptValue;
class V8TestingScope;
enum PaymentTestDetailToChange {
@@ -95,31 +93,6 @@ class PaymentRequestV8TestingScope : public V8TestingScope {
PaymentRequestV8TestingScope();
};
-class PaymentRequestMockFunctionScope {
- STACK_ALLOCATED();
-
- public:
- explicit PaymentRequestMockFunctionScope(ScriptState*);
- ~PaymentRequestMockFunctionScope();
-
- v8::Local<v8::Function> ExpectCall();
- v8::Local<v8::Function> ExpectCall(String* captor);
- v8::Local<v8::Function> ExpectNoCall();
-
- private:
- class MockFunction : public ScriptFunction {
- public:
- explicit MockFunction(ScriptState*);
- MockFunction(ScriptState*, String* captor);
- v8::Local<v8::Function> Bind();
- MOCK_METHOD1(Call, ScriptValue(ScriptValue));
- String* value_;
- };
-
- ScriptState* script_state_;
- Vector<Persistent<MockFunction>> mock_functions_;
-};
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_TEST_HELPER_H_
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 9890e206010..86d43d621df 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc
@@ -26,7 +26,9 @@ static constexpr size_t kMaximumStringLength = 2 * 1024;
bool PaymentsValidators::IsValidCurrencyCodeFormat(
const String& code,
String* optional_error_message) {
- if (ScriptRegexp("^[A-Z]{3}$", kTextCaseUnicodeInsensitive).Match(code) == 0)
+ auto* regexp = MakeGarbageCollected<ScriptRegexp>(
+ "^[A-Z]{3}$", kTextCaseUnicodeInsensitive);
+ if (regexp->Match(code) == 0)
return true;
if (optional_error_message) {
@@ -41,8 +43,9 @@ bool PaymentsValidators::IsValidCurrencyCodeFormat(
bool PaymentsValidators::IsValidAmountFormat(const String& amount,
const String& item_name,
String* optional_error_message) {
- if (ScriptRegexp("^-?[0-9]+(\\.[0-9]+)?$", kTextCaseSensitive)
- .Match(amount) == 0)
+ auto* regexp = MakeGarbageCollected<ScriptRegexp>("^-?[0-9]+(\\.[0-9]+)?$",
+ kTextCaseSensitive);
+ if (regexp->Match(amount) == 0)
return true;
if (optional_error_message) {
@@ -56,7 +59,9 @@ bool PaymentsValidators::IsValidAmountFormat(const String& amount,
bool PaymentsValidators::IsValidCountryCodeFormat(
const String& code,
String* optional_error_message) {
- if (ScriptRegexp("^[A-Z]{2}$", kTextCaseSensitive).Match(code) == 0)
+ auto* regexp =
+ MakeGarbageCollected<ScriptRegexp>("^[A-Z]{2}$", kTextCaseSensitive);
+ if (regexp->Match(code) == 0)
return true;
if (optional_error_message)
@@ -147,9 +152,9 @@ bool PaymentsValidators::IsValidMethodFormat(const String& identifier) {
if (!url.IsValid()) {
// Syntax for a valid standardized PMI:
// https://www.w3.org/TR/payment-method-id/#dfn-syntax-of-a-standardized-payment-method-identifier
- return ScriptRegexp("^[a-z]+[0-9a-z]*(-[a-z]+[0-9a-z]*)*$",
- kTextCaseSensitive)
- .Match(identifier) == 0;
+ auto* regexp = MakeGarbageCollected<ScriptRegexp>(
+ "^[a-z]+[0-9a-z]*(-[a-z]+[0-9a-z]*)*$", kTextCaseSensitive);
+ return regexp->Match(identifier) == 0;
}
// URL PMI validation rules:
@@ -163,16 +168,7 @@ bool PaymentsValidators::IsValidMethodFormat(const String& identifier) {
if (url.Protocol() != "http")
return false;
- // Allow http://localhost for local development.
- if (SecurityOrigin::Create(url)->IsLocalhost())
- return true;
-
- // Allow http:// origins from
- // --unsafely-treat-insecure-origin-as-secure=<origin> for local development.
- if (SecurityPolicy::IsUrlTrustworthySafelisted(url))
- return true;
-
- return false;
+ return SecurityOrigin::Create(url)->IsPotentiallyTrustworthy();
}
void PaymentsValidators::ValidateAndStringifyObject(
diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc b/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc
index 7164cab41a8..8a733287644 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc
@@ -6,6 +6,9 @@
#include <ostream> // NOLINT
+#include "base/test/scoped_command_line.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/network_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_address_errors.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payer_errors.h"
@@ -363,7 +366,12 @@ TEST(PaymentMethodValidatorTest, IsValidPaymentMethodSafelisted) {
EXPECT_FALSE(PaymentsValidators::IsValidMethodFormat("http://alicepay.com"))
<< "http://alicepay.com is not a valid method format by default";
- SecurityPolicy::AddOriginToTrustworthySafelist("http://alicepay.com");
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure,
+ "http://alicepay.com");
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
EXPECT_TRUE(PaymentsValidators::IsValidMethodFormat("http://alicepay.com"))
<< "http://alicepay.com should be valid if safelisted";
diff --git a/chromium/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc b/chromium/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
index 6d6e0de8ae1..1ed7cf0b196 100644
--- a/chromium/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.h"
#include "third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index 48f247fe314..ac8dae244ed 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//third_party/blink/renderer/modules/modules.gni")
+import("//third_party/webrtc/webrtc.gni")
blink_modules_sources("peerconnection") {
sources = [
@@ -156,6 +157,15 @@ blink_modules_sources("peerconnection") {
source_set("test_support") {
testonly = true
+ # TODO(crbug.com/1173961): avoid depending on testonly webrtc targets.
+ if (rtc_include_tests) {
+ # This target uses some webrtc targets that are not part of
+ # "webrtc_component". This target relies on the fact that including a header
+ # that is not tracked by GN works without raising any warning. However it
+ # leads to build errors if rtc_include_tests = true.
+ check_includes = false
+ }
+
sources = [
"fake_rtc_rtp_transceiver_impl.cc",
"fake_rtc_rtp_transceiver_impl.h",
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/DIR_METADATA b/chromium/third_party/blink/renderer/modules/peerconnection/DIR_METADATA
new file mode 100644
index 00000000000..7fdbb5e4bdd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebRTC"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/OWNERS b/chromium/third_party/blink/renderer/modules/peerconnection/OWNERS
index b2a8f2b2cb5..cf2e30ab384 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/OWNERS
@@ -4,5 +4,3 @@ hta@chromium.org
orphis@chromium.org
steveanton@chromium.org
tommi@chromium.org
-
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
index 09da798acdf..afc0d8c1b16 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
@@ -6,7 +6,9 @@
#include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/webrtc/api/dtls_transport_interface.h"
// The DtlsTransportProxy class takes care of thread-jumping when
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
index b235aaa2fb3..41e7cc11171 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
+#include <utility>
+
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
@@ -24,8 +26,7 @@ IceTransportProxy::IceTransportProxy(
delegate_(delegate),
feature_handle_for_scheduler_(frame.GetFrameScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kWebRTC,
- {SchedulingPolicy::DisableAggressiveThrottling(),
- SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableAggressiveThrottling()})) {
DCHECK(host_thread_);
DCHECK(delegate_);
DCHECK(adapter_factory);
@@ -37,11 +38,10 @@ IceTransportProxy::IceTransportProxy(
// (configured above) will ensure it gets deleted on the host thread.
host_.reset(new IceTransportHost(proxy_thread_, host_thread_,
weak_ptr_factory_.GetWeakPtr()));
- PostCrossThreadTask(
- *host_thread_, FROM_HERE,
- CrossThreadBindOnce(&IceTransportHost::Initialize,
- CrossThreadUnretained(host_.get()),
- WTF::Passed(std::move(adapter_factory))));
+ PostCrossThreadTask(*host_thread_, FROM_HERE,
+ CrossThreadBindOnce(&IceTransportHost::Initialize,
+ CrossThreadUnretained(host_.get()),
+ std::move(adapter_factory)));
}
IceTransportProxy::~IceTransportProxy() {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/sctp_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/sctp_transport_proxy.h
index b999131ed61..b0d876054bc 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/sctp_transport_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/sctp_transport_proxy.h
@@ -8,7 +8,9 @@
#include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/webrtc/api/sctp_transport_interface.h"
// The SctpTransportProxy class takes care of thread-jumping when
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
index 4f84dd281ec..d515f5003e0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
@@ -252,4 +252,19 @@ FakeRTCRtpTransceiverImpl::FiredDirection() const {
return base::nullopt;
}
+webrtc::RTCError FakeRTCRtpTransceiverImpl::SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) {
+ return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
+}
+
+Vector<webrtc::RtpHeaderExtensionCapability>
+FakeRTCRtpTransceiverImpl::HeaderExtensionsNegotiated() const {
+ return {};
+}
+
+Vector<webrtc::RtpHeaderExtensionCapability>
+FakeRTCRtpTransceiverImpl::HeaderExtensionsToOffer() const {
+ return {};
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h
index 9c19b3ed405..54fbe8fd967 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h
@@ -111,6 +111,12 @@ class FakeRTCRtpTransceiverImpl : public RTCRtpTransceiverPlatform {
const override;
base::Optional<webrtc::RtpTransceiverDirection> FiredDirection()
const override;
+ webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) override;
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
+ const override;
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const override;
private:
base::Optional<std::string> mid_;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.cc b/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.cc
index 4a3403cd438..b06cc772f03 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_codec_capability.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.h"
+
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_capabilities.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_codec_capability.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_capability.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h b/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h
index 04a63aa27e2..07376aeb544 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/identifiability_metrics.h
@@ -5,11 +5,11 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_IDENTIFIABILITY_METRICS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_IDENTIFIABILITY_METRICS_H_
-#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_capabilities.h"
-
namespace blink {
+class RTCRtpCapabilities;
+class IdentifiableTokenBuilder;
+
void IdentifiabilityAddRTCRtpCapabilitiesToBuilder(
IdentifiableTokenBuilder& builder,
const RTCRtpCapabilities& capabilities);
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 6563f22ec08..976efbd3a05 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
@@ -15,6 +15,7 @@
#include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/webrtc/track_observer.h"
@@ -51,7 +52,7 @@ class WebRtcEncodedVideoFrame : public EncodedVideoFrame {
public:
explicit WebRtcEncodedVideoFrame(const webrtc::RecordableEncodedFrame& frame)
: buffer_(frame.encoded_buffer()),
- codec_(FromWebRtcVideoCodec(frame.codec())),
+ codec_(WebRtcToMediaVideoCodec(frame.codec())),
is_key_frame_(frame.is_key_frame()),
resolution_(frame.resolution().width, frame.resolution().height) {
if (frame.color_space()) {
@@ -74,19 +75,6 @@ class WebRtcEncodedVideoFrame : public EncodedVideoFrame {
gfx::Size Resolution() const override { return resolution_; }
private:
- static media::VideoCodec FromWebRtcVideoCodec(webrtc::VideoCodecType codec) {
- switch (codec) {
- case webrtc::kVideoCodecVP8:
- return media::kCodecVP8;
- case webrtc::kVideoCodecVP9:
- return media::kCodecVP9;
- case webrtc::kVideoCodecH264:
- return media::kCodecH264;
- default:
- return media::kUnknownVideoCodec;
- }
- }
-
rtc::scoped_refptr<const webrtc::EncodedImageBufferInterface> buffer_;
media::VideoCodec codec_;
bool is_key_frame_;
@@ -136,22 +124,17 @@ class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
EncodedVideoFrameCB encoded_frame_callback_;
// Timestamp of the first received frame.
- base::TimeDelta start_timestamp_;
-
- // WebRTC Chromium timestamp diff
- const base::TimeDelta time_diff_;
-
- // Timestamp of the first received encoded frame.
- base::TimeDelta start_timestamp_encoded_;
-
- // WebRTC Chromium timestamp diff
- const base::TimeDelta time_diff_encoded_;
+ base::Optional<base::TimeTicks> start_timestamp_;
// WebRTC real time clock, needed to determine NTP offset.
webrtc::Clock* clock_;
// Offset between NTP clock and WebRTC clock.
const int64_t ntp_offset_;
+
+ // Determined from a feature flag; if set WebRTC won't forward an unspecified
+ // color space.
+ const bool ignore_unspecified_color_space_;
};
MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::
@@ -162,18 +145,11 @@ MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::
: io_task_runner_(io_task_runner),
frame_callback_(std::move(new_frame_callback)),
encoded_frame_callback_(std::move(encoded_frame_callback)),
- start_timestamp_(media::kNoTimestamp),
- // TODO(qiangchen): There can be two differences between clocks: 1)
- // the offset, 2) the rate (i.e., one clock runs faster than the other).
- // See http://crbug/516700
- time_diff_(base::TimeTicks::Now() - base::TimeTicks() -
- base::TimeDelta::FromMicroseconds(rtc::TimeMicros())),
- start_timestamp_encoded_(media::kNoTimestamp),
- time_diff_encoded_(base::TimeTicks::Now() - base::TimeTicks() -
- base::TimeDelta::FromMicroseconds(rtc::TimeMicros())),
clock_(webrtc::Clock::GetRealTimeClock()),
ntp_offset_(clock_->TimeInMilliseconds() -
- clock_->CurrentNtpInMilliseconds()) {}
+ clock_->CurrentNtpInMilliseconds()),
+ ignore_unspecified_color_space_(base::FeatureList::IsEnabled(
+ features::kWebRtcIgnoreUnspecifiedColorSpace)) {}
MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::
~RemoteVideoSourceDelegate() = default;
@@ -182,17 +158,14 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
const webrtc::VideoFrame& incoming_frame) {
const bool render_immediately = incoming_frame.timestamp_us() == 0;
const base::TimeTicks current_time = base::TimeTicks::Now();
- const base::TimeDelta incoming_timestamp =
- render_immediately
- ? current_time - base::TimeTicks()
- : base::TimeDelta::FromMicroseconds(incoming_frame.timestamp_us());
const base::TimeTicks render_time =
- render_immediately ? base::TimeTicks() + incoming_timestamp
- : base::TimeTicks() + incoming_timestamp + time_diff_;
- if (start_timestamp_ == media::kNoTimestamp)
- start_timestamp_ = incoming_timestamp;
- const base::TimeDelta elapsed_timestamp =
- incoming_timestamp - start_timestamp_;
+ render_immediately
+ ? current_time
+ : base::TimeTicks() + base::TimeDelta::FromMicroseconds(
+ incoming_frame.timestamp_us());
+ if (!start_timestamp_)
+ start_timestamp_ = render_time;
+ const base::TimeDelta elapsed_timestamp = render_time - *start_timestamp_;
TRACE_EVENT2("webrtc", "RemoteVideoSourceDelegate::RenderFrame",
"Ideal Render Instant", render_time.ToInternalValue(),
"Timestamp", elapsed_timestamp.InMicroseconds());
@@ -284,11 +257,23 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
// Rotation may be explicitly set sometimes.
if (incoming_frame.rotation() != webrtc::kVideoRotation_0) {
- video_frame->metadata()->rotation =
+ video_frame->metadata().transformation =
WebRtcToMediaVideoRotation(incoming_frame.rotation());
}
- if (incoming_frame.color_space()) {
+ // The second clause of the condition is controlled by the feature flag
+ // WebRtcIgnoreUnspecifiedColorSpace. If the feature is enabled we won't try
+ // to guess a color space if the webrtc::ColorSpace is unspecified. If the
+ // feature is disabled (default), an unspecified color space will get
+ // converted into a gfx::ColorSpace set to BT709.
+ if (incoming_frame.color_space() &&
+ !(ignore_unspecified_color_space_ &&
+ incoming_frame.color_space()->primaries() ==
+ webrtc::ColorSpace::PrimaryID::kUnspecified &&
+ incoming_frame.color_space()->transfer() ==
+ webrtc::ColorSpace::TransferID::kUnspecified &&
+ incoming_frame.color_space()->matrix() ==
+ webrtc::ColorSpace::MatrixID::kUnspecified)) {
video_frame->set_color_space(
WebRtcToMediaVideoColorSpace(*incoming_frame.color_space())
.ToGfxColorSpace());
@@ -297,36 +282,33 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
// Run render smoothness algorithm only when we don't have to render
// immediately.
if (!render_immediately)
- video_frame->metadata()->reference_time = render_time;
+ video_frame->metadata().reference_time = render_time;
if (incoming_frame.max_composition_delay_in_frames()) {
- video_frame->metadata()->maximum_composition_delay_in_frames =
+ video_frame->metadata().maximum_composition_delay_in_frames =
*incoming_frame.max_composition_delay_in_frames();
}
- video_frame->metadata()->decode_end_time = current_time;
+ video_frame->metadata().decode_end_time = current_time;
// RTP_TIMESTAMP, PROCESSING_TIME, and CAPTURE_BEGIN_TIME are all exposed
// through the JavaScript callback mechanism
// video.requestVideoFrameCallback().
- video_frame->metadata()->rtp_timestamp =
+ video_frame->metadata().rtp_timestamp =
static_cast<double>(incoming_frame.timestamp());
if (incoming_frame.processing_time()) {
- video_frame->metadata()->processing_time =
- base::TimeDelta::FromMicroseconds(
- incoming_frame.processing_time()->Elapsed().us());
+ video_frame->metadata().processing_time = base::TimeDelta::FromMicroseconds(
+ incoming_frame.processing_time()->Elapsed().us());
}
// Set capture time to the NTP time, which is the estimated capture time
// converted to the local clock.
if (incoming_frame.ntp_time_ms() > 0) {
const base::TimeTicks capture_time =
- base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(incoming_frame.ntp_time_ms() +
- ntp_offset_) +
- time_diff_;
- video_frame->metadata()->capture_begin_time = capture_time;
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(
+ incoming_frame.ntp_time_ms() + ntp_offset_);
+ video_frame->metadata().capture_begin_time = capture_time;
}
// Set receive time to arrival of last packet.
@@ -341,8 +323,8 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
->receive_time_ms();
const base::TimeTicks receive_time =
base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(last_packet_arrival_ms) + time_diff_;
- video_frame->metadata()->receive_time = receive_time;
+ base::TimeDelta::FromMilliseconds(last_packet_arrival_ms);
+ video_frame->metadata().receive_time = receive_time;
}
// Use our computed render time as estimated capture time. If timestamp_us()
@@ -361,21 +343,18 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::
base::TimeTicks estimated_capture_time) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::DoRenderFrameOnIOThread");
- frame_callback_.Run(std::move(video_frame), estimated_capture_time);
+ frame_callback_.Run(std::move(video_frame), {}, estimated_capture_time);
}
void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
const webrtc::RecordableEncodedFrame& frame) {
const bool render_immediately = frame.render_time().us() == 0;
const base::TimeTicks current_time = base::TimeTicks::Now();
- const base::TimeDelta incoming_timestamp =
- render_immediately
- ? current_time - base::TimeTicks()
- : base::TimeDelta::FromMicroseconds(frame.render_time().us());
const base::TimeTicks render_time =
render_immediately
- ? base::TimeTicks() + incoming_timestamp
- : base::TimeTicks() + incoming_timestamp + time_diff_encoded_;
+ ? current_time
+ : base::TimeTicks() +
+ base::TimeDelta::FromMicroseconds(frame.render_time().us());
// Use our computed render time as estimated capture time. If render_time()
// is set by WebRTC, it's based on the RTP timestamps in the frame's packets,
@@ -494,6 +473,11 @@ void MediaStreamRemoteVideoSource::RequestRefreshFrame() {
}
}
+base::WeakPtr<MediaStreamVideoSource> MediaStreamRemoteVideoSource::GetWeakPtr()
+ const {
+ return weak_factory_.GetWeakPtr();
+}
+
void MediaStreamRemoteVideoSource::OnEncodedSinkEnabled() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!observer_ || !observer_->track()) {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
index 353f59bb0db..c9f27497713 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
@@ -36,6 +36,7 @@ class MODULES_EXPORT MediaStreamRemoteVideoSource
// MediaStreamVideoSource overrides.
bool SupportsEncodedOutput() const override;
void RequestRefreshFrame() override;
+ base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
protected:
// Implements MediaStreamVideoSource.
@@ -60,6 +61,8 @@ class MODULES_EXPORT MediaStreamRemoteVideoSource
scoped_refptr<RemoteVideoSourceDelegate> delegate_;
std::unique_ptr<TrackObserver> observer_;
+ base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(MediaStreamRemoteVideoSource);
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
index c786417779c..70815a0eba5 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
@@ -13,8 +13,10 @@
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/gmock_callback_support.h"
+#include "base/test/scoped_feature_list.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
@@ -36,14 +38,6 @@
namespace blink {
namespace {
-// On Linux the clock in WebRTC and Chromium are more or less the same.
-// On Windows they are not the same and the accuracy of the measured time
-// difference is typically in the range [-1, 1] ms. However, for certain builds
-// such as ASAN it can be in the order of 10-20 ms. Since this is compensated
-// for both here and in MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
-// we need to use the worst case difference between these two measurements.
-float kChromiumWebRtcMaxTimeDiffMs = 40.0f;
-
using base::test::RunOnceClosure;
using ::testing::_;
using ::testing::Gt;
@@ -76,9 +70,8 @@ class MediaStreamRemoteVideoSourceTest : public ::testing::Test {
webrtc_video_source_(blink::MockWebRtcVideoTrackSource::Create(
/*supports_encoded_output=*/true)),
webrtc_video_track_(
- blink::MockWebRtcVideoTrack::Create("test", webrtc_video_source_)),
- time_diff_(base::TimeTicks::Now() - base::TimeTicks() -
- base::TimeDelta::FromMicroseconds(rtc::TimeMicros())) {}
+ blink::MockWebRtcVideoTrack::Create("test", webrtc_video_source_)) {
+ }
void SetUp() override {
scoped_refptr<base::SingleThreadTaskRunner> main_thread =
@@ -286,21 +279,82 @@ TEST_F(MediaStreamRemoteVideoSourceTest, PreservesColorSpace) {
track->RemoveSink(&sink);
}
-// These tests depend on measuring the difference between the internal WebRTC
-// clock and Chromium's clock. Due to this they are performance sensitive and
-// appear to be flaky for builds with ASAN enabled.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_PopulateRequestAnimationFrameMetadata \
- DISABLED_PopulateRequestAnimationFrameMetadata
-#define MAYBE_ReferenceTimeEqualsTimestampUs \
- DISABLED_ReferenceTimeEqualsTimestampUs
-#else
-#define MAYBE_PopulateRequestAnimationFrameMetadata \
- PopulateRequestAnimationFrameMetadata
-#define MAYBE_ReferenceTimeEqualsTimestampUs ReferenceTimeEqualsTimestampUs
-#endif
TEST_F(MediaStreamRemoteVideoSourceTest,
- MAYBE_PopulateRequestAnimationFrameMetadata) {
+ UnspecifiedColorSpaceIsTreatedAsBt709) {
+ std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
+ blink::MockMediaStreamVideoSink sink;
+ track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(sink, OnVideoFrame)
+ .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
+ rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+ new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+ webrtc::ColorSpace kColorSpace(webrtc::ColorSpace::PrimaryID::kUnspecified,
+ webrtc::ColorSpace::TransferID::kUnspecified,
+ webrtc::ColorSpace::MatrixID::kUnspecified,
+ webrtc::ColorSpace::RangeID::kLimited);
+ const webrtc::VideoFrame& input_frame =
+ webrtc::VideoFrame::Builder()
+ .set_video_frame_buffer(buffer)
+ .set_timestamp_ms(0)
+ .set_rotation(webrtc::kVideoRotation_0)
+ .set_color_space(kColorSpace)
+ .build();
+ source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+ run_loop.Run();
+
+ EXPECT_EQ(1, sink.number_of_frames());
+ scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+ EXPECT_TRUE(output_frame);
+ EXPECT_TRUE(output_frame->ColorSpace() ==
+ gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT709,
+ gfx::ColorSpace::TransferID::BT709,
+ gfx::ColorSpace::MatrixID::BT709,
+ gfx::ColorSpace::RangeID::LIMITED));
+ track->RemoveSink(&sink);
+}
+
+TEST_F(MediaStreamRemoteVideoSourceTest, UnspecifiedColorSpaceIsIgnored) {
+ base::test::ScopedFeatureList scoped_feauture_list;
+ scoped_feauture_list.InitAndEnableFeature(
+ blink::features::kWebRtcIgnoreUnspecifiedColorSpace);
+ std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
+ blink::MockMediaStreamVideoSink sink;
+ track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(sink, OnVideoFrame)
+ .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
+ rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+ new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+ webrtc::ColorSpace kColorSpace(webrtc::ColorSpace::PrimaryID::kUnspecified,
+ webrtc::ColorSpace::TransferID::kUnspecified,
+ webrtc::ColorSpace::MatrixID::kUnspecified,
+ webrtc::ColorSpace::RangeID::kLimited);
+ const webrtc::VideoFrame& input_frame =
+ webrtc::VideoFrame::Builder()
+ .set_video_frame_buffer(buffer)
+ .set_timestamp_ms(0)
+ .set_rotation(webrtc::kVideoRotation_0)
+ .set_color_space(kColorSpace)
+ .build();
+ source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+ run_loop.Run();
+
+ EXPECT_EQ(1, sink.number_of_frames());
+ scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+ EXPECT_TRUE(output_frame);
+ EXPECT_TRUE(output_frame->ColorSpace() ==
+ gfx::ColorSpace(gfx::ColorSpace::PrimaryID::INVALID,
+ gfx::ColorSpace::TransferID::INVALID,
+ gfx::ColorSpace::MatrixID::INVALID,
+ gfx::ColorSpace::RangeID::INVALID));
+ track->RemoveSink(&sink);
+}
+
+TEST_F(MediaStreamRemoteVideoSourceTest,
+ PopulateRequestAnimationFrameMetadata) {
std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
blink::MockMediaStreamVideoSink sink;
track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
@@ -327,22 +381,19 @@ TEST_F(MediaStreamRemoteVideoSourceTest,
clock->CurrentNtpInMilliseconds() - clock->TimeInMilliseconds();
const webrtc::Timestamp kCaptureTimeNtp =
kCaptureTime + webrtc::TimeDelta::Millis(ntp_offset);
- // Expected capture time in Chromium epoch.
+ // Expected capture time.
base::TimeTicks kExpectedCaptureTime =
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(kCaptureTime.ms()) +
- time_diff();
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(kCaptureTime.ms());
webrtc::RtpPacketInfos::vector_type packet_infos;
for (int i = 0; i < 4; ++i) {
packet_infos.emplace_back(kSsrc, kCsrcs, kRtpTimestamp, absl::nullopt,
absl::nullopt, kProcessingStart.ms() - 100 + i);
}
- // Expected receive time should be the same as the last arrival time, in
- // Chromium epoch.
+ // Expected receive time should be the same as the last arrival time.
base::TimeTicks kExpectedReceiveTime =
base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(kProcessingStart.ms() - 100 + 3) +
- time_diff();
+ base::TimeDelta::FromMilliseconds(kProcessingStart.ms() - 100 + 3);
webrtc::VideoFrame input_frame =
webrtc::VideoFrame::Builder()
@@ -360,25 +411,32 @@ TEST_F(MediaStreamRemoteVideoSourceTest,
scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
EXPECT_TRUE(output_frame);
- EXPECT_FLOAT_EQ(output_frame->metadata()->processing_time->InSecondsF(),
+ EXPECT_FLOAT_EQ(output_frame->metadata().processing_time->InSecondsF(),
kProcessingTime);
+ // The NTP offset is estimated both here and in the code that is tested.
+ // Therefore, we cannot exactly determine what capture_begin_time will be set
+ // to.
+ // TODO(kron): Find a lower tolerance without causing the test to be flaky or
+ // make the clock injectable so that a fake clock can be used in the test.
+ constexpr float kNtpOffsetToleranceMs = 40.0;
EXPECT_NEAR(
- (*output_frame->metadata()->capture_begin_time - kExpectedCaptureTime)
+ (*output_frame->metadata().capture_begin_time - kExpectedCaptureTime)
.InMillisecondsF(),
- 0.0f, kChromiumWebRtcMaxTimeDiffMs);
+ 0.0f, kNtpOffsetToleranceMs);
- EXPECT_NEAR((*output_frame->metadata()->receive_time - kExpectedReceiveTime)
- .InMillisecondsF(),
- 0.0f, kChromiumWebRtcMaxTimeDiffMs);
+ EXPECT_FLOAT_EQ(
+ (*output_frame->metadata().receive_time - kExpectedReceiveTime)
+ .InMillisecondsF(),
+ 0.0f);
- EXPECT_EQ(static_cast<uint32_t>(*output_frame->metadata()->rtp_timestamp),
+ EXPECT_EQ(static_cast<uint32_t>(*output_frame->metadata().rtp_timestamp),
kRtpTimestamp);
track->RemoveSink(&sink);
}
-TEST_F(MediaStreamRemoteVideoSourceTest, MAYBE_ReferenceTimeEqualsTimestampUs) {
+TEST_F(MediaStreamRemoteVideoSourceTest, ReferenceTimeEqualsTimestampUs) {
std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
blink::MockMediaStreamVideoSink sink;
track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
@@ -402,14 +460,29 @@ TEST_F(MediaStreamRemoteVideoSourceTest, MAYBE_ReferenceTimeEqualsTimestampUs) {
scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
EXPECT_TRUE(output_frame);
- EXPECT_NEAR((*output_frame->metadata()->reference_time -
- (base::TimeTicks() +
- base::TimeDelta::FromMicroseconds(kTimestampUs) + time_diff()))
- .InMillisecondsF(),
- 0.0f, kChromiumWebRtcMaxTimeDiffMs);
+ EXPECT_FLOAT_EQ(
+ (*output_frame->metadata().reference_time -
+ (base::TimeTicks() + base::TimeDelta::FromMicroseconds(kTimestampUs)))
+ .InMillisecondsF(),
+ 0.0f);
track->RemoveSink(&sink);
}
+TEST_F(MediaStreamRemoteVideoSourceTest, BaseTimeTicksAndRtcMicrosAreTheSame) {
+ base::TimeTicks first_chromium_timestamp = base::TimeTicks::Now();
+ base::TimeTicks webrtc_timestamp =
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(rtc::TimeMicros());
+ base::TimeTicks second_chromium_timestamp = base::TimeTicks::Now();
+
+ // Test that the timestamps are correctly ordered, which they can only be if
+ // the clocks are the same (assuming at least one of the clocks is functioning
+ // correctly).
+ EXPECT_GE((webrtc_timestamp - first_chromium_timestamp).InMillisecondsF(),
+ 0.0f);
+ EXPECT_GE((second_chromium_timestamp - webrtc_timestamp).InMillisecondsF(),
+ 0.0f);
+}
+
// This is a special case that is used to signal "render immediately".
TEST_F(MediaStreamRemoteVideoSourceTest, NoTimestampUsMeansNoReferenceTime) {
std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
@@ -432,7 +505,7 @@ TEST_F(MediaStreamRemoteVideoSourceTest, NoTimestampUsMeansNoReferenceTime) {
scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
EXPECT_TRUE(output_frame);
- EXPECT_FALSE(output_frame->metadata()->reference_time.has_value());
+ EXPECT_FALSE(output_frame->metadata().reference_time.has_value());
track->RemoveSink(&sink);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc
index 098a06383df..0fb4c27e624 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_video_webrtc_sink.cc
@@ -77,8 +77,10 @@ class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter
// destroyed.
void ReleaseSourceOnMainThread();
- void OnVideoFrameOnIO(scoped_refptr<media::VideoFrame> frame,
- base::TimeTicks estimated_capture_time);
+ void OnVideoFrameOnIO(
+ scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks estimated_capture_time);
private:
friend class WTF::ThreadSafeRefCounted<WebRtcVideoSourceAdapter>;
@@ -141,8 +143,13 @@ void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
base::TimeTicks estimated_capture_time) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+ // TODO(https://crbug.com/1157072): When WebRTC makes use of
+ // media::VideoFrameFeedback to tell the capturer to deliver |scaled_frames|
+ // in the encoder's desired resolution, pass along these frames and make use
+ // of them inside WebRTC.
PostCrossThreadTask(
*libjingle_worker_thread_.get(), FROM_HERE,
CrossThreadBindOnce(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread,
@@ -176,7 +183,8 @@ MediaStreamVideoWebRtcSink::MediaStreamVideoWebRtcSink(
// by removing the need for and dependency on a cricket::VideoCapturer.
video_source_ = scoped_refptr<WebRtcVideoTrackSource>(
new rtc::RefCountedObject<WebRtcVideoTrackSource>(
- is_screencast, needs_denoising, feedback_cb));
+ is_screencast, needs_denoising, feedback_cb,
+ factory->GetGpuFactories()));
// TODO(pbos): Consolidate the local video track with the source proxy and
// move into PeerConnectionDependencyFactory. This now separately holds on a
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.cc b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.cc
index 509ea0f3846..51f6076a1de 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.cc
@@ -8,6 +8,7 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h"
+#include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
#include "third_party/webrtc/api/media_stream_interface.h"
#include "third_party/webrtc/api/scoped_refptr.h"
@@ -307,51 +308,6 @@ void MockWebRtcVideoTrackSource::AddOrUpdateSink(
void MockWebRtcVideoTrackSource::RemoveSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {}
-class MockSessionDescription : public SessionDescriptionInterface {
- public:
- MockSessionDescription(const std::string& type, const std::string& sdp)
- : type_(type), sdp_(sdp) {}
- ~MockSessionDescription() override {}
- cricket::SessionDescription* description() override {
- NOTIMPLEMENTED();
- return nullptr;
- }
- const cricket::SessionDescription* description() const override {
- NOTIMPLEMENTED();
- return nullptr;
- }
- std::string session_id() const override {
- NOTIMPLEMENTED();
- return std::string();
- }
- std::string session_version() const override {
- NOTIMPLEMENTED();
- return std::string();
- }
- std::string type() const override { return type_; }
- bool AddCandidate(const IceCandidateInterface* candidate) override {
- NOTIMPLEMENTED();
- return false;
- }
- size_t number_of_mediasections() const override {
- NOTIMPLEMENTED();
- return 0;
- }
- const IceCandidateCollection* candidates(
- size_t mediasection_index) const override {
- NOTIMPLEMENTED();
- return nullptr;
- }
-
- bool ToString(std::string* out) const override {
- *out = sdp_;
- return true;
- }
-
- private:
- std::string type_;
- std::string sdp_;
-};
class MockIceCandidate : public IceCandidateInterface {
public:
@@ -392,7 +348,8 @@ scoped_refptr<webrtc::PeerConnectionInterface>
MockPeerConnectionDependencyFactory::CreatePeerConnection(
const webrtc::PeerConnectionInterface::RTCConfiguration& config,
blink::WebLocalFrame* frame,
- webrtc::PeerConnectionObserver* observer) {
+ webrtc::PeerConnectionObserver* observer,
+ ExceptionState& exception_state) {
return new rtc::RefCountedObject<MockPeerConnectionImpl>(this, observer);
}
@@ -416,16 +373,6 @@ MockPeerConnectionDependencyFactory::CreateLocalVideoTrack(
return track;
}
-SessionDescriptionInterface*
-MockPeerConnectionDependencyFactory::CreateSessionDescription(
- const String& type,
- const String& sdp,
- webrtc::SdpParseError* error) {
- if (fail_to_create_session_description_)
- return nullptr;
- return new MockSessionDescription(type.Utf8(), sdp.Utf8());
-}
-
webrtc::IceCandidateInterface*
MockPeerConnectionDependencyFactory::CreateIceCandidate(const String& sdp_mid,
int sdp_mline_index,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h
index 0d583f46883..c904047a342 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h
@@ -171,7 +171,8 @@ class MockPeerConnectionDependencyFactory
scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
const webrtc::PeerConnectionInterface::RTCConfiguration& config,
blink::WebLocalFrame* frame,
- webrtc::PeerConnectionObserver* observer) override;
+ webrtc::PeerConnectionObserver* observer,
+ ExceptionState& exception_state) override;
scoped_refptr<webrtc::VideoTrackSourceInterface> CreateVideoTrackSourceProxy(
webrtc::VideoTrackSourceInterface* source) override;
scoped_refptr<webrtc::MediaStreamInterface> CreateLocalMediaStream(
@@ -179,10 +180,6 @@ class MockPeerConnectionDependencyFactory
scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrack(
const String& id,
webrtc::VideoTrackSourceInterface* source) override;
- webrtc::SessionDescriptionInterface* CreateSessionDescription(
- const String& type,
- const String& sdp,
- webrtc::SdpParseError* error) override;
webrtc::IceCandidateInterface* CreateIceCandidate(const String& sdp_mid,
int sdp_mline_index,
const String& sdp) override;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
index fc9f9eb0d21..5bd05d8b733 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
@@ -10,10 +10,11 @@
#include <vector>
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h"
+#include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
#include "third_party/blink/renderer/platform/peerconnection/webrtc_util.h"
#include "third_party/webrtc/api/rtp_receiver_interface.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
@@ -324,8 +325,7 @@ const char MockPeerConnectionImpl::kDummyAnswer[] = "dummy answer";
MockPeerConnectionImpl::MockPeerConnectionImpl(
MockPeerConnectionDependencyFactory* factory,
webrtc::PeerConnectionObserver* observer)
- : dependency_factory_(factory),
- remote_streams_(new rtc::RefCountedObject<MockStreamCollection>),
+ : remote_streams_(new rtc::RefCountedObject<MockStreamCollection>),
hint_audio_(false),
hint_video_(false),
getstats_result_(true),
@@ -503,18 +503,16 @@ void MockPeerConnectionImpl::CreateOffer(
CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
DCHECK(observer);
- created_sessiondescription_.reset(
- dependency_factory_->CreateSessionDescription("unknown", kDummyOffer,
- nullptr));
+ created_sessiondescription_ =
+ MockParsedSessionDescription("unknown", kDummyAnswer).release();
}
void MockPeerConnectionImpl::CreateAnswer(
CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
DCHECK(observer);
- created_sessiondescription_.reset(
- dependency_factory_->CreateSessionDescription("unknown", kDummyAnswer,
- nullptr));
+ created_sessiondescription_ =
+ MockParsedSessionDescription("unknown", kDummyAnswer).release();
}
void MockPeerConnectionImpl::SetLocalDescriptionWorker(
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h
index 4adc6ce92bb..fcd6afac877 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h
@@ -386,9 +386,6 @@ class MockPeerConnectionImpl : public webrtc::DummyPeerConnection {
~MockPeerConnectionImpl() override;
private:
- // Used for creating MockSessionDescription.
- MockPeerConnectionDependencyFactory* dependency_factory_;
-
std::string stream_label_;
std::vector<std::string> local_stream_ids_;
rtc::scoped_refptr<MockStreamCollection> remote_streams_;
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 da6d4bb9522..c5c9995962c 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
@@ -236,6 +236,18 @@ class MockRTCPeerConnectionHandlerPlatform::DummyRTCRtpTransceiverPlatform
const override {
return base::nullopt;
}
+ webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) override {
+ return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
+ }
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
+ const override {
+ return {};
+ }
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const override {
+ return {};
+ }
private:
scoped_refptr<DummyTransceiverInternal> internal_;
@@ -251,7 +263,8 @@ MockRTCPeerConnectionHandlerPlatform::~MockRTCPeerConnectionHandlerPlatform() =
bool MockRTCPeerConnectionHandlerPlatform::Initialize(
const webrtc::PeerConnectionInterface::RTCConfiguration&,
const MediaConstraints&,
- WebLocalFrame*) {
+ WebLocalFrame*,
+ ExceptionState&) {
return true;
}
@@ -280,11 +293,11 @@ void MockRTCPeerConnectionHandlerPlatform::SetLocalDescription(
void MockRTCPeerConnectionHandlerPlatform::SetLocalDescription(
RTCVoidRequest*,
- RTCSessionDescriptionPlatform*) {}
+ ParsedSessionDescription) {}
void MockRTCPeerConnectionHandlerPlatform::SetRemoteDescription(
RTCVoidRequest*,
- RTCSessionDescriptionPlatform*) {}
+ ParsedSessionDescription) {}
const webrtc::PeerConnectionInterface::RTCConfiguration&
MockRTCPeerConnectionHandlerPlatform::GetConfiguration() const {
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 1a9cb0ff6e0..d82ad3682a5 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
@@ -17,6 +17,65 @@
namespace blink {
+class MockSessionDescription : public webrtc::SessionDescriptionInterface {
+ public:
+ MockSessionDescription(const std::string& type, const std::string& sdp)
+ : type_(type), sdp_(sdp) {}
+ ~MockSessionDescription() override = default;
+ cricket::SessionDescription* description() override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+ const cricket::SessionDescription* description() const override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+ std::string session_id() const override {
+ NOTIMPLEMENTED();
+ return std::string();
+ }
+ std::string session_version() const override {
+ NOTIMPLEMENTED();
+ return std::string();
+ }
+ std::string type() const override { return type_; }
+ bool AddCandidate(const webrtc::IceCandidateInterface* candidate) override {
+ NOTIMPLEMENTED();
+ return false;
+ }
+ size_t number_of_mediasections() const override {
+ NOTIMPLEMENTED();
+ return 0;
+ }
+ const webrtc::IceCandidateCollection* candidates(
+ size_t mediasection_index) const override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+
+ bool ToString(std::string* out) const override {
+ *out = sdp_;
+ return true;
+ }
+
+ private:
+ std::string type_;
+ std::string sdp_;
+};
+
+// Class for creating a ParsedSessionDescription without running the parser.
+// It returns an empty (but non-null) description object.
+class MockParsedSessionDescription : public ParsedSessionDescription {
+ public:
+ MockParsedSessionDescription(const String& type, const String& sdp)
+ : ParsedSessionDescription(type, sdp) {
+ description_ =
+ std::make_unique<MockSessionDescription>(type.Utf8(), sdp.Utf8());
+ }
+ // Constructor for creating an error-returning session description.
+ MockParsedSessionDescription() : ParsedSessionDescription("error", "error") {}
+};
+
// TODO(https://crbug.com/908461): This is currently implemented as NO-OPs or to
// create dummy objects whose methods return default values. Consider renaming
// the class, changing it to be GMOCK friendly or deleting it.
@@ -29,7 +88,8 @@ class MockRTCPeerConnectionHandlerPlatform : public RTCPeerConnectionHandler {
bool Initialize(const webrtc::PeerConnectionInterface::RTCConfiguration&,
const MediaConstraints&,
- WebLocalFrame*) override;
+ WebLocalFrame*,
+ ExceptionState&) override;
void Stop() override;
void StopAndUnregister() override;
@@ -44,10 +104,8 @@ class MockRTCPeerConnectionHandlerPlatform : public RTCPeerConnectionHandler {
void CreateAnswer(RTCSessionDescriptionRequest*,
RTCAnswerOptionsPlatform*) override;
void SetLocalDescription(RTCVoidRequest*) override;
- void SetLocalDescription(RTCVoidRequest*,
- RTCSessionDescriptionPlatform*) override;
- void SetRemoteDescription(RTCVoidRequest*,
- RTCSessionDescriptionPlatform*) override;
+ void SetLocalDescription(RTCVoidRequest*, ParsedSessionDescription) override;
+ void SetRemoteDescription(RTCVoidRequest*, ParsedSessionDescription) override;
const webrtc::PeerConnectionInterface::RTCConfiguration& GetConfiguration()
const override;
webrtc::RTCErrorType SetConfiguration(
@@ -81,7 +139,6 @@ class MockRTCPeerConnectionHandlerPlatform : public RTCPeerConnectionHandler {
void TrackIceConnectionStateChange(
RTCPeerConnectionHandler::IceConnectionStateVersion version,
webrtc::PeerConnectionInterface::IceConnectionState state) override;
-
private:
class DummyRTCRtpTransceiverPlatform;
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 d765ec01b04..91a0720a9c3 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
@@ -19,6 +19,7 @@
#include "build/build_config.h"
#include "crypto/openssl_util.h"
#include "jingle/glue/thread_wrapper.h"
+#include "media/base/decoder_factory.h"
#include "media/base/media_permission.h"
#include "media/media_buildflags.h"
#include "media/video/gpu_video_accelerator_factories.h"
@@ -32,6 +33,7 @@
#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_error_util.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"
@@ -115,6 +117,9 @@ PeerConnectionDependencyFactory::PeerConnectionDependencyFactory(
create_p2p_socket_dispatcher ? new P2PSocketDispatcher() : nullptr),
chrome_signaling_thread_("WebRTC_Signaling"),
chrome_network_thread_("WebRTC_Network") {
+ if (base::FeatureList::IsEnabled(features::kWebRtcDistinctWorkerThread)) {
+ chrome_worker_thread_.emplace("WebRTC_Worker");
+ }
TryScheduleStunProbeTrial();
}
@@ -162,10 +167,12 @@ void PeerConnectionDependencyFactory::WillDestroyCurrentMessageLoop() {
void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
DCHECK(!pc_factory_.get());
DCHECK(!signaling_thread_);
+ DCHECK(!worker_thread_);
DCHECK(!network_thread_);
DCHECK(!network_manager_);
DCHECK(!socket_factory_);
DCHECK(!chrome_signaling_thread_.IsRunning());
+ DCHECK(!chrome_worker_thread_ || !chrome_worker_thread_->IsRunning());
DCHECK(!chrome_network_thread_.IsRunning());
DVLOG(1) << "PeerConnectionDependencyFactory::CreatePeerConnectionFactory()";
@@ -195,6 +202,19 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
return;
}
+ base::WaitableEvent start_worker_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (chrome_worker_thread_) {
+ CHECK(chrome_worker_thread_->Start());
+ PostCrossThreadTask(
+ *chrome_worker_thread_->task_runner().get(), FROM_HERE,
+ CrossThreadBindOnce(
+ &PeerConnectionDependencyFactory::InitializeWorkerThread,
+ CrossThreadUnretained(this), CrossThreadUnretained(&worker_thread_),
+ CrossThreadUnretained(&start_worker_event)));
+ }
+
CHECK(chrome_signaling_thread_.Start());
CHECK(chrome_network_thread_.Start());
@@ -222,6 +242,13 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
create_network_manager_event.Wait();
CHECK(network_thread_);
+ // Wait for the worker thread, since `InitializeSignalingThread` needs to
+ // refer to `worker_thread_`.
+ if (chrome_worker_thread_) {
+ start_worker_event.Wait();
+ CHECK(worker_thread_);
+ }
+
base::WaitableEvent start_signaling_event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
@@ -231,6 +258,7 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
&PeerConnectionDependencyFactory::InitializeSignalingThread,
CrossThreadUnretained(this),
CrossThreadUnretained(Platform::Current()->GetGpuFactories()),
+ CrossThreadUnretained(Platform::Current()->GetMediaDecoderFactory()),
CrossThreadUnretained(&start_signaling_event)));
start_signaling_event.Wait();
@@ -239,6 +267,7 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() {
void PeerConnectionDependencyFactory::InitializeSignalingThread(
media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* media_decoder_factory,
base::WaitableEvent* event) {
DCHECK(chrome_signaling_thread_.task_runner()->BelongsToCurrentThread());
DCHECK(network_thread_);
@@ -287,10 +316,12 @@ void PeerConnectionDependencyFactory::InitializeSignalingThread(
socket_factory_.reset(new IpcPacketSocketFactory(p2p_socket_dispatcher_.get(),
traffic_annotation));
+ gpu_factories_ = gpu_factories;
std::unique_ptr<webrtc::VideoEncoderFactory> webrtc_encoder_factory =
blink::CreateWebrtcVideoEncoderFactory(gpu_factories);
std::unique_ptr<webrtc::VideoDecoderFactory> webrtc_decoder_factory =
- blink::CreateWebrtcVideoDecoderFactory(gpu_factories);
+ blink::CreateWebrtcVideoDecoderFactory(gpu_factories,
+ media_decoder_factory);
// Enable Multiplex codec in SDP optionally.
if (base::FeatureList::IsEnabled(blink::features::kWebRtcMultiplexCodec)) {
@@ -308,7 +339,7 @@ void PeerConnectionDependencyFactory::InitializeSignalingThread(
}
webrtc::PeerConnectionFactoryDependencies pcf_deps;
- pcf_deps.worker_thread = signaling_thread_;
+ pcf_deps.worker_thread = worker_thread_ ? worker_thread_ : signaling_thread_;
pcf_deps.signaling_thread = signaling_thread_;
pcf_deps.network_thread = network_thread_;
pcf_deps.task_queue_factory = CreateWebRtcTaskQueueFactory();
@@ -346,7 +377,8 @@ scoped_refptr<webrtc::PeerConnectionInterface>
PeerConnectionDependencyFactory::CreatePeerConnection(
const webrtc::PeerConnectionInterface::RTCConfiguration& config,
blink::WebLocalFrame* web_frame,
- webrtc::PeerConnectionObserver* observer) {
+ webrtc::PeerConnectionObserver* observer,
+ ExceptionState& exception_state) {
CHECK(web_frame);
CHECK(observer);
if (!GetPcFactory().get())
@@ -357,9 +389,16 @@ PeerConnectionDependencyFactory::CreatePeerConnection(
webrtc::PeerConnectionDependencies dependencies(observer);
dependencies.allocator = CreatePortAllocator(web_frame);
dependencies.async_resolver_factory = CreateAsyncResolverFactory();
- return GetPcFactory()
- ->CreatePeerConnection(config, std::move(dependencies))
- .get();
+ auto pc_or_error = GetPcFactory()->CreatePeerConnectionOrError(
+ config, std::move(dependencies));
+ if (pc_or_error.ok()) {
+ // Convert from rtc::scoped_refptr to scoped_refptr
+ return pc_or_error.value().get();
+ } else {
+ // Convert error
+ ThrowExceptionFromRTCError(pc_or_error.error(), exception_state);
+ return nullptr;
+ }
}
std::unique_ptr<cricket::PortAllocator>
@@ -499,14 +538,6 @@ PeerConnectionDependencyFactory::CreateLocalVideoTrack(
return GetPcFactory()->CreateVideoTrack(id.Utf8(), source).get();
}
-webrtc::SessionDescriptionInterface*
-PeerConnectionDependencyFactory::CreateSessionDescription(
- const String& type,
- const String& sdp,
- webrtc::SdpParseError* error) {
- return webrtc::CreateSessionDescription(type.Utf8(), sdp.Utf8(), error);
-}
-
webrtc::IceCandidateInterface*
PeerConnectionDependencyFactory::CreateIceCandidate(const String& sdp_mid,
int sdp_mline_index,
@@ -522,6 +553,15 @@ PeerConnectionDependencyFactory::GetWebRtcAudioDevice() {
return audio_device_.get();
}
+void PeerConnectionDependencyFactory::InitializeWorkerThread(
+ rtc::Thread** thread,
+ base::WaitableEvent* event) {
+ jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
+ jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
+ *thread = jingle_glue::JingleThreadWrapper::current();
+ event->Signal();
+}
+
void PeerConnectionDependencyFactory::TryScheduleStunProbeTrial() {
base::Optional<WebString> params =
Platform::Current()->WebRtcStunProbeTrialParameter();
@@ -646,4 +686,8 @@ PeerConnectionDependencyFactory::GetReceiverCapabilities(const String& kind) {
return nullptr;
}
+media::GpuVideoAcceleratorFactories*
+PeerConnectionDependencyFactory::GetGpuFactories() {
+ return gpu_factories_;
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
index 7092f910303..7d21b78a8a4 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
@@ -11,6 +11,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/webrtc/api/peer_connection_interface.h"
#include "third_party/webrtc/p2p/stunprober/stun_prober.h"
@@ -24,6 +25,7 @@ class PortAllocator;
}
namespace media {
+class DecoderFactory;
class GpuVideoAcceleratorFactories;
}
@@ -78,7 +80,8 @@ class MODULES_EXPORT PeerConnectionDependencyFactory
virtual scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
const webrtc::PeerConnectionInterface::RTCConfiguration& config,
blink::WebLocalFrame* web_frame,
- webrtc::PeerConnectionObserver* observer);
+ webrtc::PeerConnectionObserver* observer,
+ ExceptionState& exception_state);
// Creates a PortAllocator that uses Chrome IPC sockets and enforces privacy
// controls according to the permissions granted on the page.
@@ -89,13 +92,6 @@ class MODULES_EXPORT PeerConnectionDependencyFactory
virtual std::unique_ptr<webrtc::AsyncResolverFactory>
CreateAsyncResolverFactory();
- // Creates a libjingle representation of a Session description. Used by a
- // RTCPeerConnectionHandler instance.
- virtual webrtc::SessionDescriptionInterface* CreateSessionDescription(
- const String& type,
- const String& sdp,
- webrtc::SdpParseError* error);
-
// Creates a libjingle representation of an ice candidate.
virtual webrtc::IceCandidateInterface* CreateIceCandidate(
const String& sdp_mid,
@@ -120,6 +116,8 @@ class MODULES_EXPORT PeerConnectionDependencyFactory
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetWebRtcSignalingTaskRunner();
+ media::GpuVideoAcceleratorFactories* GetGpuFactories();
+
protected:
PeerConnectionDependencyFactory(bool create_p2p_socket_dispatcher);
@@ -147,8 +145,11 @@ class MODULES_EXPORT PeerConnectionDependencyFactory
void InitializeSignalingThread(
media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* media_decoder_factory,
base::WaitableEvent* event);
+ void InitializeWorkerThread(rtc::Thread** thread, base::WaitableEvent* event);
+
void CreateIpcNetworkManagerOnNetworkThread(
base::WaitableEvent* event,
std::unique_ptr<MdnsResponderAdapter> mdns_responder,
@@ -170,11 +171,15 @@ class MODULES_EXPORT PeerConnectionDependencyFactory
std::unique_ptr<blink::StunProberTrial> stun_trial_;
+ media::GpuVideoAcceleratorFactories* gpu_factories_;
+
// PeerConnection threads. signaling_thread_ is created from the
// "current" chrome thread.
rtc::Thread* signaling_thread_ = nullptr;
+ rtc::Thread* worker_thread_ = nullptr;
rtc::Thread* network_thread_ = nullptr;
base::Thread chrome_signaling_thread_;
+ base::Optional<base::Thread> chrome_worker_thread_;
base::Thread chrome_network_thread_;
THREAD_CHECKER(thread_checker_);
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 aa9ceb39621..6cfa167f8e1 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
@@ -12,11 +12,10 @@
#include <utility>
#include <vector>
-#include "base/power_monitor/power_observer.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.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"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/web/web_document.h"
@@ -726,9 +725,7 @@ void PeerConnectionTracker::OnSuspend() {
void PeerConnectionTracker::OnThermalStateChange(
mojom::blink::DeviceThermalState thermal_state) {
DCHECK_CALLED_ON_VALID_THREAD(main_thread_);
- mojo::EnumTraits<mojom::blink::DeviceThermalState,
- base::PowerObserver::DeviceThermalState>::
- FromMojom(thermal_state, &current_thermal_state_);
+ current_thermal_state_ = thermal_state;
for (auto& entry : peer_connection_local_id_map_) {
entry.key->OnThermalStateChange(current_thermal_state_);
}
@@ -808,8 +805,7 @@ void PeerConnectionTracker::RegisterPeerConnection(
peer_connection_local_id_map_.insert(pc_handler, lid);
- if (current_thermal_state_ !=
- base::PowerObserver::DeviceThermalState::kUnknown) {
+ if (current_thermal_state_ != mojom::blink::DeviceThermalState::kUnknown) {
pc_handler->OnThermalStateChange(current_thermal_state_);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
index 7000bc48ea4..ee047f78b08 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/power_monitor/power_observer.h"
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -282,8 +281,8 @@ class MODULES_EXPORT PeerConnectionTracker
// This map stores the local ID assigned to each RTCPeerConnectionHandler.
typedef WTF::HashMap<RTCPeerConnectionHandler*, int> PeerConnectionLocalIdMap;
PeerConnectionLocalIdMap peer_connection_local_id_map_;
- base::PowerObserver::DeviceThermalState current_thermal_state_ =
- base::PowerObserver::DeviceThermalState::kUnknown;
+ mojom::blink::DeviceThermalState current_thermal_state_ =
+ mojom::blink::DeviceThermalState::kUnknown;
// This keeps track of the next available local ID.
int next_local_id_;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
index 6991518346c..7c7a0c14c7c 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
@@ -127,8 +127,7 @@ class MockPeerConnectionHandler : public RTCPeerConnectionHandler {
/*force_encoded_audio_insertable_streams=*/false,
/*force_encoded_video_insertable_streams=*/false) {}
MOCK_METHOD0(CloseClientPeerConnection, void());
- MOCK_METHOD1(OnThermalStateChange,
- void(base::PowerObserver::DeviceThermalState));
+ MOCK_METHOD1(OnThermalStateChange, void(mojom::blink::DeviceThermalState));
private:
blink::MockPeerConnectionDependencyFactory dependency_factory_;
@@ -195,35 +194,30 @@ TEST_F(PeerConnectionTrackerTest, OnThermalStateChange) {
CreateTrackerWithMocks();
CreateAndRegisterPeerConnectionHandler();
- EXPECT_CALL(
- *mock_handler_,
- OnThermalStateChange(base::PowerObserver::DeviceThermalState::kUnknown))
+ EXPECT_CALL(*mock_handler_,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kUnknown))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kUnknown);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kUnknown);
- EXPECT_CALL(
- *mock_handler_,
- OnThermalStateChange(base::PowerObserver::DeviceThermalState::kNominal))
+ EXPECT_CALL(*mock_handler_,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kNominal);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal);
- EXPECT_CALL(
- *mock_handler_,
- OnThermalStateChange(base::PowerObserver::DeviceThermalState::kFair))
+ EXPECT_CALL(*mock_handler_,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kFair))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kFair);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kFair);
- EXPECT_CALL(
- *mock_handler_,
- OnThermalStateChange(base::PowerObserver::DeviceThermalState::kSerious))
+ EXPECT_CALL(*mock_handler_,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kSerious))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kSerious);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kSerious);
- EXPECT_CALL(
- *mock_handler_,
- OnThermalStateChange(base::PowerObserver::DeviceThermalState::kCritical))
+ EXPECT_CALL(*mock_handler_,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kCritical))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kCritical);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kCritical);
}
TEST_F(PeerConnectionTrackerTest, ReportInitialThermalState) {
@@ -241,14 +235,14 @@ TEST_F(PeerConnectionTrackerTest, ReportInitialThermalState) {
base::RunLoop().RunUntilIdle();
// Report a known thermal state.
- EXPECT_CALL(handler0, OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kNominal))
+ EXPECT_CALL(handler0,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kNominal);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal);
// Handlers registered late will get the event upon registering.
- EXPECT_CALL(handler1, OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kNominal))
+ EXPECT_CALL(handler1,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal))
.Times(1);
EXPECT_CALL(*mock_host_, AddPeerConnection(_)).Times(1);
tracker_->RegisterPeerConnection(
@@ -257,13 +251,13 @@ TEST_F(PeerConnectionTrackerTest, ReportInitialThermalState) {
base::RunLoop().RunUntilIdle();
// Report the unknown thermal state.
- EXPECT_CALL(handler0, OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kUnknown))
+ EXPECT_CALL(handler0,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kUnknown))
.Times(1);
- EXPECT_CALL(handler1, OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kUnknown))
+ EXPECT_CALL(handler1,
+ OnThermalStateChange(mojom::blink::DeviceThermalState::kUnknown))
.Times(1);
- tracker_->OnThermalStateChange(blink::mojom::DeviceThermalState::kUnknown);
+ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kUnknown);
// Handlers registered late get no event.
EXPECT_CALL(handler2, OnThermalStateChange(_)).Times(0);
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 5925cd58e4e..63c40095a65 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
@@ -205,7 +205,7 @@ void RTCDataChannel::Observer::OnMessage(const webrtc::DataBuffer& buffer) {
*main_thread_, FROM_HERE,
CrossThreadBindOnce(&RTCDataChannel::Observer::OnMessageImpl,
scoped_refptr<Observer>(this),
- WTF::Passed(std::move(new_buffer))));
+ std::move(new_buffer)));
}
void RTCDataChannel::Observer::OnStateChangeImpl(
@@ -417,15 +417,14 @@ void RTCDataChannel::send(DOMArrayBuffer* data,
void RTCDataChannel::send(NotShared<DOMArrayBufferView> data,
ExceptionState& exception_state) {
- if (!(base::CheckedNumeric<unsigned>(buffered_amount_) +
- data.View()->byteLength())
+ if (!(base::CheckedNumeric<unsigned>(buffered_amount_) + data->byteLength())
.IsValid()) {
ThrowBufferOverflowException(&exception_state);
return;
}
- buffered_amount_ += data.View()->byteLength();
- if (!SendRawData(static_cast<const char*>(data.View()->BaseAddress()),
- data.View()->byteLength())) {
+ buffered_amount_ += data->byteLength();
+ if (!SendRawData(static_cast<const char*>(data->BaseAddress()),
+ data->byteLength())) {
// TODO(https://crbug.com/937848): Don't throw an exception if data is
// queued.
ThrowCouldNotSendDataException(&exception_state);
@@ -505,6 +504,7 @@ bool RTCDataChannel::HasPendingActivity() const {
void RTCDataChannel::Trace(Visitor* visitor) const {
visitor->Trace(scheduled_events_);
+ visitor->Trace(scheduled_event_timer_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
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 5e068fe2a0d..2a8320dec07 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
@@ -176,7 +176,7 @@ class MODULES_EXPORT RTCDataChannel final
enum BinaryType { kBinaryTypeBlob, kBinaryTypeArrayBuffer };
BinaryType binary_type_;
- TaskRunnerTimer<RTCDataChannel> scheduled_event_timer_;
+ HeapTaskRunnerTimer<RTCDataChannel> scheduled_event_timer_;
HeapVector<Member<Event>> scheduled_events_;
FRIEND_TEST_ALL_PREFIXES(RTCDataChannelTest, Open);
FRIEND_TEST_ALL_PREFIXES(RTCDataChannelTest, Close);
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 bc5de51d17e..be026790138 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
@@ -18,6 +18,7 @@
#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/heap/heap.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"
@@ -44,8 +45,7 @@ void RunSynchronous(base::TestSimpleTaskRunner* thread,
std::move(closure).Run();
event->Signal();
},
- WTF::Passed(std::move(closure)),
- CrossThreadUnretained(&waitable_event)));
+ std::move(closure), CrossThreadUnretained(&waitable_event)));
waitable_event.Wait();
}
@@ -214,11 +214,18 @@ class MockDataChannel : public webrtc::DataChannelInterface {
class RTCDataChannelTest : public ::testing::Test {
public:
RTCDataChannelTest() : signaling_thread_(new base::TestSimpleTaskRunner()) {}
+ ~RTCDataChannelTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
scoped_refptr<base::TestSimpleTaskRunner> signaling_thread() {
return signaling_thread_;
}
+ protected:
+ Persistent<NullExecutionContext> execution_context_ =
+ MakeGarbageCollected<NullExecutionContext>();
+
private:
scoped_refptr<base::TestSimpleTaskRunner> signaling_thread_;
@@ -237,8 +244,7 @@ TEST_F(RTCDataChannelTest, ChangeStateEarly) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
// In RTCDataChannel::Create, the state change update is posted from the
// signaling thread to the main thread. Wait for posted the task to be
@@ -255,8 +261,7 @@ TEST_F(RTCDataChannelTest, BufferedAmount) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
String message(std::string(100, 'A').c_str());
@@ -273,8 +278,7 @@ TEST_F(RTCDataChannelTest, BufferedAmountLow) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
channel->setBufferedAmountLowThreshold(1);
@@ -295,8 +299,7 @@ TEST_F(RTCDataChannelTest, Open) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
channel->OnStateChange(webrtc::DataChannelInterface::kOpen);
EXPECT_EQ("open", channel->readyState());
}
@@ -307,8 +310,7 @@ TEST_F(RTCDataChannelTest, Close) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
channel->OnStateChange(webrtc::DataChannelInterface::kClosed);
EXPECT_EQ("closed", channel->readyState());
}
@@ -319,8 +321,7 @@ TEST_F(RTCDataChannelTest, Message) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
std::unique_ptr<webrtc::DataBuffer> message(new webrtc::DataBuffer("A"));
channel->OnMessage(std::move(message));
@@ -334,8 +335,7 @@ TEST_F(RTCDataChannelTest, SendAfterContextDestroyed) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
channel->ContextDestroyed();
@@ -353,8 +353,7 @@ TEST_F(RTCDataChannelTest, CloseAfterContextDestroyed) {
std::unique_ptr<MockPeerConnectionHandler> pc(
new MockPeerConnectionHandler(signaling_thread()));
auto* channel = MakeGarbageCollected<RTCDataChannel>(
- MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
- pc.get());
+ execution_context_, webrtc_channel.get(), pc.get());
webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
channel->ContextDestroyed();
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_sink_test.cc
index ad703c4bdea..c9e7862d503 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_sink_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_sink_test.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_encoded_audio_frame.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
index c6f30c34756..2caca05c398 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.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/wtf/vector.h"
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc
index 614d16e9a43..3f6d24941ad 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_encoded_video_frame.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
index 63f012e9acd..ade8bb77ed2 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/webrtc/api/frame_transformer_interface.h"
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
index 497509c2467..c8a127df90f 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -77,50 +77,8 @@ class DtlsIceTransportAdapterCrossThreadFactory
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_;
};
-class DefaultIceTransportAdapterCrossThreadFactory
- : public IceTransportAdapterCrossThreadFactory {
- public:
- void InitializeOnMainThread(LocalFrame& frame) override {
- DCHECK(!port_allocator_);
- DCHECK(!async_resolver_factory_);
-
- auto* rtc_dependency_factory =
- blink::PeerConnectionDependencyFactory::GetInstance();
- port_allocator_ = rtc_dependency_factory->CreatePortAllocator(
- frame.Client()->GetWebFrame());
- async_resolver_factory_ =
- rtc_dependency_factory->CreateAsyncResolverFactory();
- }
-
- std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread(
- IceTransportAdapter::Delegate* delegate) override {
- DCHECK(port_allocator_);
- DCHECK(async_resolver_factory_);
- return std::make_unique<IceTransportAdapterImpl>(
- delegate, std::move(port_allocator_),
- std::move(async_resolver_factory_));
- }
-
- private:
- std::unique_ptr<cricket::PortAllocator> port_allocator_;
- std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
-};
-
} // namespace
-RTCIceTransport* RTCIceTransport::Create(ExecutionContext* context) {
- scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
- context->GetTaskRunner(TaskType::kNetworking);
-
- PeerConnectionDependencyFactory::GetInstance()->EnsureInitialized();
- scoped_refptr<base::SingleThreadTaskRunner> host_thread =
- PeerConnectionDependencyFactory::GetInstance()
- ->GetWebRtcNetworkTaskRunner();
- return MakeGarbageCollected<RTCIceTransport>(
- context, std::move(proxy_thread), std::move(host_thread),
- std::make_unique<DefaultIceTransportAdapterCrossThreadFactory>());
-}
-
RTCIceTransport* RTCIceTransport::Create(
ExecutionContext* context,
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
index 884b804e197..8fcceafbb6f 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
@@ -56,7 +56,6 @@ class MODULES_EXPORT RTCIceTransport final
kDisposed,
};
- static RTCIceTransport* Create(ExecutionContext* context);
static RTCIceTransport* Create(
ExecutionContext* context,
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_channel,
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
index 7894ce1bcb2..38989386176 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
@@ -32,8 +32,6 @@ enum RTCIceGatheringState {
Exposed=Window,
SecureContext
] interface RTCIceTransport : EventTarget {
- // Constructor from https://w3c.github.io/webrtc-ice/#rtcicetransport*
- [CallWith=ExecutionContext, Measure] constructor();
// TODO(github.com/w3c/webrtc-ice/issues/4): role is non-null in the
// WebRTC-PC specification.
[Measure] readonly attribute RTCIceRole? role;
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 b38cf32bb33..0d0337a867c 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
@@ -50,12 +50,12 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
#include "third_party/blink/renderer/bindings/modules/v8/media_stream_track_or_string.h"
-#include "third_party/blink/renderer/bindings/modules/v8/rtc_ice_candidate_init_or_rtc_ice_candidate.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_answer_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_certificate.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_configuration.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_data_channel_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_candidate_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_server.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_offer_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_error_callback.h"
@@ -178,17 +178,10 @@ bool CallErrorCallbackIfSignalingStateClosed(
return false;
}
-bool IsIceCandidateMissingSdp(
- const RTCIceCandidateInitOrRTCIceCandidate& candidate) {
- if (candidate.IsRTCIceCandidateInit()) {
- const RTCIceCandidateInit* ice_candidate_init =
- candidate.GetAsRTCIceCandidateInit();
- return ice_candidate_init->sdpMid().IsNull() &&
- !ice_candidate_init->hasSdpMLineIndexNonNull();
- }
-
- DCHECK(candidate.IsRTCIceCandidate());
- return false;
+bool IsIceCandidateMissingSdpMidAndMLineIndex(
+ const RTCIceCandidateInit* candidate) {
+ return (candidate->sdpMid().IsNull() &&
+ !candidate->hasSdpMLineIndexNonNull());
}
RTCOfferOptionsPlatform* ConvertToRTCOfferOptionsPlatform(
@@ -214,26 +207,18 @@ RTCAnswerOptionsPlatform* ConvertToRTCAnswerOptionsPlatform(
RTCIceCandidatePlatform* ConvertToRTCIceCandidatePlatform(
ExecutionContext* context,
- const RTCIceCandidateInitOrRTCIceCandidate& candidate) {
- DCHECK(!candidate.IsNull());
- if (candidate.IsRTCIceCandidateInit()) {
- const RTCIceCandidateInit* ice_candidate_init =
- candidate.GetAsRTCIceCandidateInit();
- // TODO(guidou): Change default value to -1. crbug.com/614958.
- uint16_t sdp_m_line_index = 0;
- if (ice_candidate_init->hasSdpMLineIndexNonNull()) {
- sdp_m_line_index = ice_candidate_init->sdpMLineIndexNonNull();
- } else {
- UseCounter::Count(context,
- WebFeature::kRTCIceCandidateDefaultSdpMLineIndex);
- }
- return MakeGarbageCollected<RTCIceCandidatePlatform>(
- ice_candidate_init->candidate(), ice_candidate_init->sdpMid(),
- sdp_m_line_index, ice_candidate_init->usernameFragment());
+ const RTCIceCandidateInit* candidate) {
+ // TODO(guidou): Change default value to -1. crbug.com/614958.
+ uint16_t sdp_m_line_index = 0;
+ if (candidate->hasSdpMLineIndexNonNull()) {
+ sdp_m_line_index = candidate->sdpMLineIndexNonNull();
+ } else {
+ UseCounter::Count(context,
+ WebFeature::kRTCIceCandidateDefaultSdpMLineIndex);
}
-
- DCHECK(candidate.IsRTCIceCandidate());
- return candidate.GetAsRTCIceCandidate()->PlatformCandidate();
+ return MakeGarbageCollected<RTCIceCandidatePlatform>(
+ candidate->candidate(), candidate->sdpMid(), sdp_m_line_index,
+ candidate->usernameFragment());
}
enum SdpSemanticRequested {
@@ -324,6 +309,22 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration(
if (configuration->hasSdpSemantics()) {
if (configuration->sdpSemantics() == "plan-b") {
web_configuration.sdp_semantics = webrtc::SdpSemantics::kPlanB;
+ if (!RuntimeEnabledFeatures::RTCExtendDeadlineForPlanBRemovalEnabled(
+ context)) {
+ // TODO(https://crbug.com/857004): In M93, replace this deprecation
+ // warning with the throwing of an exception (Reverse Origin Trial is
+ // required to continue to use Plan B).
+ Deprecation::CountDeprecation(
+ context, WebFeature::kRTCPeerConnectionSdpSemanticsPlanB);
+ } else {
+ // TODO(https://crbug.com/857004): In M96, replace this deprecation
+ // warning with the throwing of an exception (Reverse Origin Trial has
+ // ended).
+ Deprecation::CountDeprecation(
+ context,
+ WebFeature::
+ kRTCPeerConnectionSdpSemanticsPlanBWithReverseOriginTrial);
+ }
} else {
DCHECK_EQ(configuration->sdpSemantics(), "unified-plan");
web_configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
@@ -536,17 +537,19 @@ bool ContainsLegacyRtpDataChannel(String sdp) {
return sdp.Find("google-data/90000") != kNotFound;
}
+bool ContainsCandidate(String sdp) {
+ return sdp.Find("a=candidate") != kNotFound;
+}
+
enum class SdpFormat {
kSimple,
kComplexPlanB,
kComplexUnifiedPlan,
};
-base::Optional<SdpFormat> DeduceSdpFormat(const String& type,
- const String& sdp) {
- std::unique_ptr<webrtc::SessionDescriptionInterface> session_description(
- webrtc::CreateSessionDescription(type.Utf8().c_str(), sdp.Utf8().c_str(),
- nullptr));
+base::Optional<SdpFormat> DeduceSdpFormat(
+ const ParsedSessionDescription& parsed_sdp) {
+ auto* session_description = parsed_sdp.description();
if (!session_description)
return base::nullopt;
size_t num_audio_mlines = 0u;
@@ -604,11 +607,11 @@ RTCSetSessionDescriptionOperation GetRTCVoidRequestOperationType(
const char kOnlySupportedInUnifiedPlanMessage[] =
"This operation is only supported in 'unified-plan'.";
-SdpUsageCategory DeduceSdpUsageCategory(const String& sdp_type,
- const String& sdp,
- bool sdp_semantics_specified,
- webrtc::SdpSemantics sdp_semantics) {
- auto sdp_format = DeduceSdpFormat(sdp_type, sdp);
+SdpUsageCategory DeduceSdpUsageCategory(
+ const ParsedSessionDescription& parsed_sdp,
+ bool sdp_semantics_specified,
+ webrtc::SdpSemantics sdp_semantics) {
+ auto sdp_format = DeduceSdpFormat(parsed_sdp);
if (!sdp_format)
return SdpUsageCategory::kUnknown;
switch (*sdp_format) {
@@ -707,9 +710,21 @@ RTCPeerConnection* RTCPeerConnection::Create(
if (exception_state.HadException())
return nullptr;
+ SdpSemanticRequested sdp_semantics_requested =
+ GetSdpSemanticRequested(rtc_configuration);
UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SdpSemanticRequested",
- GetSdpSemanticRequested(rtc_configuration),
- kSdpSemanticRequestedMax);
+ sdp_semantics_requested, kSdpSemanticRequestedMax);
+
+ if (sdp_semantics_requested == kSdpSemanticRequestedPlanB) {
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionConstructedWithPlanB);
+ } else {
+ // Unified Plan is the default.
+ DCHECK(sdp_semantics_requested == kSdpSemanticRequestedDefault ||
+ sdp_semantics_requested == kSdpSemanticRequestedUnifiedPlan);
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionConstructedWithUnifiedPlan);
+ }
UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.OfferExtmapAllowMixed",
GetOfferExtmapAllowMixedSetting(rtc_configuration));
@@ -760,12 +775,8 @@ RTCPeerConnection::RTCPeerConnection(
peer_handler_unregistered_(true),
closed_(true),
suppress_events_(true),
- has_data_channels_(false),
sdp_semantics_(configuration.sdp_semantics),
sdp_semantics_specified_(sdp_semantics_specified),
- blink_webrtc_time_diff_(
- base::TimeTicks::Now() - base::TimeTicks() -
- base::TimeDelta::FromMicroseconds(rtc::TimeMicros())),
force_encoded_audio_insertable_streams_(
force_encoded_audio_insertable_streams),
force_encoded_video_insertable_streams_(
@@ -804,23 +815,16 @@ RTCPeerConnection::RTCPeerConnection(
}
auto* web_frame =
- static_cast<WebLocalFrame*>(WebFrame::FromFrame(window->GetFrame()));
- if (!peer_handler_->Initialize(configuration, constraints, web_frame)) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotSupportedError,
- "Failed to initialize native PeerConnection.");
+ static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(window->GetFrame()));
+ if (!peer_handler_->Initialize(configuration, constraints, web_frame,
+ exception_state)) {
+ DCHECK(exception_state.HadException());
return;
}
// The RTCPeerConnection was successfully constructed.
closed_ = false;
peer_handler_unregistered_ = false;
suppress_events_ = false;
-
- feature_handle_for_scheduler_ =
- window->GetFrame()->GetFrameScheduler()->RegisterFeature(
- SchedulingPolicy::Feature::kWebRTC,
- SchedulingPolicy{
- SchedulingPolicy::RecordMetricsForBackForwardCache()});
}
RTCPeerConnection::~RTCPeerConnection() {
@@ -1072,25 +1076,21 @@ ScriptPromise RTCPeerConnection::CreateAnswer(
DOMException* RTCPeerConnection::checkSdpForStateErrors(
ExecutionContext* context,
- const RTCSessionDescriptionInit* session_description_init,
- String* sdp) {
+ const ParsedSessionDescription& parsed_sdp) {
if (signaling_state_ ==
webrtc::PeerConnectionInterface::SignalingState::kClosed) {
return MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError, kSignalingStateClosedMessage);
}
- *sdp = session_description_init->sdp();
- if (session_description_init->type() == "offer") {
- if (sdp->IsNull() || sdp->IsEmpty()) {
- *sdp = last_offer_;
- } else if (session_description_init->sdp() != last_offer_) {
- if (FingerprintMismatch(last_offer_, *sdp)) {
+ if (parsed_sdp.type() == "offer") {
+ if (parsed_sdp.sdp() != last_offer_) {
+ if (FingerprintMismatch(last_offer_, parsed_sdp.sdp())) {
return MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidModificationError, kModifiedSdpMessage);
} else {
UseCounter::Count(context, WebFeature::kRTCLocalSdpModification);
- if (ContainsLegacySimulcast(*sdp)) {
+ if (ContainsLegacySimulcast(parsed_sdp.sdp())) {
UseCounter::Count(context,
WebFeature::kRTCLocalSdpModificationSimulcast);
}
@@ -1098,17 +1098,14 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors(
// TODO(https://crbug.com/823036): Return failure for all modification.
}
}
- } else if (session_description_init->type() == "answer" ||
- session_description_init->type() == "pranswer") {
- if (sdp->IsNull() || sdp->IsEmpty()) {
- *sdp = last_answer_;
- } else if (session_description_init->sdp() != last_answer_) {
- if (FingerprintMismatch(last_answer_, *sdp)) {
+ } else if (parsed_sdp.type() == "answer" || parsed_sdp.type() == "pranswer") {
+ if (parsed_sdp.sdp() != last_answer_) {
+ if (FingerprintMismatch(last_answer_, parsed_sdp.sdp())) {
return MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidModificationError, kModifiedSdpMessage);
} else {
UseCounter::Count(context, WebFeature::kRTCLocalSdpModification);
- if (ContainsLegacySimulcast(*sdp)) {
+ if (ContainsLegacySimulcast(parsed_sdp.sdp())) {
UseCounter::Count(context,
WebFeature::kRTCLocalSdpModificationSimulcast);
}
@@ -1121,12 +1118,8 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors(
}
base::Optional<ComplexSdpCategory> RTCPeerConnection::CheckForComplexSdp(
- const RTCSessionDescriptionInit* session_description_init) const {
- if (!session_description_init->hasType())
- return base::nullopt;
-
- base::Optional<SdpFormat> sdp_format = DeduceSdpFormat(
- session_description_init->type(), session_description_init->sdp());
+ const ParsedSessionDescription& parsed_sdp) const {
+ base::Optional<SdpFormat> sdp_format = DeduceSdpFormat(parsed_sdp);
if (!sdp_format) {
return sdp_semantics_specified_
? ComplexSdpCategory::kErrorExplicitSemantics
@@ -1146,10 +1139,10 @@ base::Optional<ComplexSdpCategory> RTCPeerConnection::CheckForComplexSdp(
return base::nullopt;
}
-void RTCPeerConnection::MaybeWarnAboutUnsafeSdp(
- const RTCSessionDescriptionInit* session_description_init) const {
+void RTCPeerConnection::RecordSdpCategoryAndMaybeEmitWarnings(
+ const ParsedSessionDescription& parsed_sdp) const {
base::Optional<ComplexSdpCategory> complex_sdp_category =
- CheckForComplexSdp(session_description_init);
+ CheckForComplexSdp(parsed_sdp);
if (!complex_sdp_category || !GetExecutionContext())
return;
@@ -1162,6 +1155,36 @@ void RTCPeerConnection::MaybeWarnAboutUnsafeSdp(
GetExecutionContext(),
WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics);
}
+
+ // kComplexPlanB/kComplexUnifiedPlan or null.
+ base::Optional<SdpFormat> complex_sdp_format;
+ switch (*complex_sdp_category) {
+ case ComplexSdpCategory::kPlanBExplicitSemantics:
+ case ComplexSdpCategory::kPlanBImplicitSemantics:
+ complex_sdp_format = SdpFormat::kComplexPlanB;
+ break;
+ case ComplexSdpCategory::kUnifiedPlanExplicitSemantics:
+ case ComplexSdpCategory::kUnifiedPlanImplicitSemantics:
+ complex_sdp_format = SdpFormat::kComplexUnifiedPlan;
+ break;
+ case ComplexSdpCategory::kErrorImplicitSemantics:
+ case ComplexSdpCategory::kErrorExplicitSemantics:
+ complex_sdp_format = base::nullopt;
+ break;
+ }
+ // Complex SDP use counters go up when complex SDP is used on an
+ // RTCPeerConnection configured for that SDP format.
+ if (complex_sdp_format.has_value()) {
+ if (sdp_semantics_ == webrtc::SdpSemantics::kPlanB &&
+ complex_sdp_format.value() == SdpFormat::kComplexPlanB) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB);
+ } else if (sdp_semantics_ == webrtc::SdpSemantics::kUnifiedPlan &&
+ complex_sdp_format.value() == SdpFormat::kComplexUnifiedPlan) {
+ UseCounter::Count(GetExecutionContext(),
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan);
+ }
+ }
}
HeapHashSet<Member<RTCIceTransport>> RTCPeerConnection::ActiveIceTransports()
@@ -1310,11 +1333,14 @@ void RTCPeerConnection::UpdateIceConnectionState() {
void RTCPeerConnection::ReportSetSdpUsage(
SetSdpOperationType operation_type,
- const RTCSessionDescriptionInit* session_description_init) const {
+ const ParsedSessionDescription& parsed_sdp) const {
+ if (!parsed_sdp.description()) {
+ LOG(ERROR) << "ReportSetSdpUsage called on SDP that failed parsing";
+ return;
+ }
SdpUsageCategory sdp_usage = DeduceSdpUsageCategory(
- session_description_init->type(), session_description_init->sdp(),
- sdp_semantics_specified_, sdp_semantics_);
- if (session_description_init->type() == "offer") {
+ parsed_sdp, sdp_semantics_specified_, sdp_semantics_);
+ if (parsed_sdp.description()->GetType() == webrtc::SdpType::kOffer) {
switch (operation_type) {
case SetSdpOperationType::kSetLocalDescription:
UMA_HISTOGRAM_ENUMERATION(
@@ -1325,8 +1351,9 @@ void RTCPeerConnection::ReportSetSdpUsage(
"WebRTC.PeerConnection.SdpComplexUsage.SetRemoteOffer", sdp_usage);
break;
}
- } else if (session_description_init->type() == "answer" ||
- session_description_init->type() == "pranswer") {
+ } else if (parsed_sdp.description()->GetType() == webrtc::SdpType::kAnswer ||
+ parsed_sdp.description()->GetType() ==
+ webrtc::SdpType::kPrAnswer) {
switch (operation_type) {
case SetSdpOperationType::kSetLocalDescription:
UMA_HISTOGRAM_ENUMERATION(
@@ -1366,14 +1393,25 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
if (!session_description_init->hasType()) {
return setLocalDescription(script_state);
}
- String sdp;
+ String sdp = session_description_init->sdp();
+ // https://w3c.github.io/webrtc-pc/#dom-peerconnection-setlocaldescription
+ // step 4.4 and 4.5: If SDP is empty, return the last created offer or answer.
+ if (sdp.IsNull() || sdp.IsEmpty()) {
+ if (session_description_init->type() == "offer") {
+ sdp = last_offer_;
+ } else if (session_description_init->type() == "answer" ||
+ session_description_init->type() == "pranswer") {
+ sdp = last_answer_;
+ }
+ }
+ ParsedSessionDescription parsed_sdp =
+ ParsedSessionDescription::Parse(session_description_init->type(), sdp);
if (session_description_init->type() != "rollback") {
- MaybeWarnAboutUnsafeSdp(session_description_init);
- ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription,
- session_description_init);
+ RecordSdpCategoryAndMaybeEmitWarnings(parsed_sdp);
+ ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription, parsed_sdp);
DOMException* exception = checkSdpForStateErrors(
- ExecutionContext::From(script_state), session_description_init, &sdp);
+ ExecutionContext::From(script_state), parsed_sdp);
if (exception) {
exception_state.ThrowDOMException(
static_cast<DOMExceptionCode>(exception->code()),
@@ -1394,9 +1432,7 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription,
*session_description_init),
this, resolver, "RTCPeerConnection", "setLocalDescription");
- peer_handler_->SetLocalDescription(
- request, MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- session_description_init->type(), sdp));
+ peer_handler_->SetLocalDescription(request, std::move(parsed_sdp));
return promise;
}
@@ -1411,10 +1447,22 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
}
DCHECK(script_state->ContextIsValid());
+ String sdp = session_description_init->sdp();
+ // https://w3c.github.io/webrtc-pc/#dom-peerconnection-setlocaldescription
+ // step 4.4 and 4.5: If SDP is empty, return the last created offer or answer.
+ if (sdp.IsNull() || sdp.IsEmpty()) {
+ if (session_description_init->type() == "offer") {
+ sdp = last_offer_;
+ } else if (session_description_init->type() == "answer" ||
+ session_description_init->type() == "pranswer") {
+ sdp = last_answer_;
+ }
+ }
+ ParsedSessionDescription parsed_sdp =
+ ParsedSessionDescription::Parse(session_description_init->type(), sdp);
if (session_description_init->type() != "rollback") {
- MaybeWarnAboutUnsafeSdp(session_description_init);
- ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription,
- session_description_init);
+ RecordSdpCategoryAndMaybeEmitWarnings(parsed_sdp);
+ ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription, parsed_sdp);
}
ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(context, WebFeature::kRTCPeerConnectionSetLocalDescription);
@@ -1434,10 +1482,8 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
WebFeature::
kRTCPeerConnectionSetLocalDescriptionLegacyNoFailureCallback);
}
- String sdp;
if (session_description_init->type() != "rollback") {
- DOMException* exception =
- checkSdpForStateErrors(context, session_description_init, &sdp);
+ DOMException* exception = checkSdpForStateErrors(context, parsed_sdp);
if (exception) {
if (error_callback)
AsyncCallErrorCallback(error_callback, exception);
@@ -1451,10 +1497,7 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription,
*session_description_init),
this, success_callback, error_callback);
- peer_handler_->SetLocalDescription(
- request,
- MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- session_description_init->type(), session_description_init->sdp()));
+ peer_handler_->SetLocalDescription(request, std::move(parsed_sdp));
return ScriptPromise::CastUndefined(script_state);
}
@@ -1482,10 +1525,11 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
}
DCHECK(script_state->ContextIsValid());
+ ParsedSessionDescription parsed_sdp =
+ ParsedSessionDescription::Parse(session_description_init);
if (session_description_init->type() != "rollback") {
- MaybeWarnAboutUnsafeSdp(session_description_init);
- ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
- session_description_init);
+ RecordSdpCategoryAndMaybeEmitWarnings(parsed_sdp);
+ ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, parsed_sdp);
}
if (signaling_state_ ==
webrtc::PeerConnectionInterface::SignalingState::kClosed) {
@@ -1506,16 +1550,17 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(context, WebFeature::kRTCLegacyRtpDataChannelNegotiated);
}
+
+ if (ContainsCandidate(session_description_init->sdp()))
+ DisableBackForwardCache(context);
+
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription,
*session_description_init),
this, resolver, "RTCPeerConnection", "setRemoteDescription");
- peer_handler_->SetRemoteDescription(
- request,
- MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- session_description_init->type(), session_description_init->sdp()));
+ peer_handler_->SetRemoteDescription(request, std::move(parsed_sdp));
return promise;
}
@@ -1530,10 +1575,11 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
}
DCHECK(script_state->ContextIsValid());
+ ParsedSessionDescription parsed_sdp =
+ ParsedSessionDescription::Parse(session_description_init);
if (session_description_init->type() != "rollback") {
- MaybeWarnAboutUnsafeSdp(session_description_init);
- ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
- session_description_init);
+ RecordSdpCategoryAndMaybeEmitWarnings(parsed_sdp);
+ ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, parsed_sdp);
}
ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(context,
@@ -1554,10 +1600,14 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
WebFeature::
kRTCPeerConnectionSetRemoteDescriptionLegacyNoFailureCallback);
}
+
if (ContainsLegacyRtpDataChannel(session_description_init->sdp())) {
UseCounter::Count(context, WebFeature::kRTCLegacyRtpDataChannelNegotiated);
}
+ if (ContainsCandidate(session_description_init->sdp()))
+ DisableBackForwardCache(context);
+
if (CallErrorCallbackIfSignalingStateClosed(signaling_state_, error_callback))
return ScriptPromise::CastUndefined(script_state);
@@ -1568,10 +1618,7 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription,
*session_description_init),
this, success_callback, error_callback);
- peer_handler_->SetRemoteDescription(
- request,
- MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- session_description_init->type(), session_description_init->sdp()));
+ peer_handler_->SetRemoteDescription(request, std::move(parsed_sdp));
return ScriptPromise::CastUndefined(script_state);
}
@@ -1855,8 +1902,9 @@ ScriptPromise RTCPeerConnection::generateCertificate(
ScriptPromise RTCPeerConnection::addIceCandidate(
ScriptState* script_state,
- const RTCIceCandidateInitOrRTCIceCandidate& candidate,
+ const RTCIceCandidateInit* candidate,
ExceptionState& exception_state) {
+ DCHECK(script_state->ContextIsValid());
if (signaling_state_ ==
webrtc::PeerConnectionInterface::SignalingState::kClosed) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
@@ -1864,23 +1912,25 @@ ScriptPromise RTCPeerConnection::addIceCandidate(
return ScriptPromise();
}
- if (IsIceCandidateMissingSdp(candidate)) {
- exception_state.ThrowTypeError(
- "Candidate missing values for both sdpMid and sdpMLineIndex");
- return ScriptPromise();
- }
-
RTCIceCandidatePlatform* platform_candidate =
ConvertToRTCIceCandidatePlatform(ExecutionContext::From(script_state),
candidate);
// Temporary mitigation to avoid throwing an exception when candidate is
- // empty.
+ // empty or nothing was passed.
// TODO(crbug.com/978582): Remove this mitigation when the WebRTC layer
- // handles the empty candidate field correctly.
+ // handles the empty candidate field or the null candidate correctly.
if (platform_candidate->Candidate().IsEmpty())
return ScriptPromise::CastUndefined(script_state);
+ if (IsIceCandidateMissingSdpMidAndMLineIndex(candidate)) {
+ exception_state.ThrowTypeError(
+ "Candidate missing values for both sdpMid and sdpMLineIndex");
+ return ScriptPromise();
+ }
+
+ DisableBackForwardCache(GetExecutionContext());
+
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
@@ -1891,17 +1941,18 @@ ScriptPromise RTCPeerConnection::addIceCandidate(
ScriptPromise RTCPeerConnection::addIceCandidate(
ScriptState* script_state,
- const RTCIceCandidateInitOrRTCIceCandidate& candidate,
+ const RTCIceCandidateInit* candidate,
V8VoidFunction* success_callback,
V8RTCPeerConnectionErrorCallback* error_callback,
ExceptionState& exception_state) {
+ DCHECK(script_state->ContextIsValid());
DCHECK(success_callback);
DCHECK(error_callback);
if (CallErrorCallbackIfSignalingStateClosed(signaling_state_, error_callback))
return ScriptPromise::CastUndefined(script_state);
- if (IsIceCandidateMissingSdp(candidate)) {
+ if (IsIceCandidateMissingSdpMidAndMLineIndex(candidate)) {
exception_state.ThrowTypeError(
"Candidate missing values for both sdpMid and sdpMLineIndex");
return ScriptPromise();
@@ -1914,10 +1965,12 @@ ScriptPromise RTCPeerConnection::addIceCandidate(
// Temporary mitigation to avoid throwing an exception when candidate is
// empty.
// TODO(crbug.com/978582): Remove this mitigation when the WebRTC layer
- // handles the empty candidate field correctly.
+ // handles the empty candidate field or the null candidate correctly.
if (platform_candidate->Candidate().IsEmpty())
return ScriptPromise::CastUndefined(script_state);
+ DisableBackForwardCache(GetExecutionContext());
+
auto* request = MakeGarbageCollected<RTCVoidRequestImpl>(
GetExecutionContext(), base::nullopt, this, success_callback,
error_callback);
@@ -2553,7 +2606,6 @@ RTCDataChannel* RTCPeerConnection::createDataChannel(
}
auto* channel = MakeGarbageCollected<RTCDataChannel>(
GetExecutionContext(), std::move(webrtc_channel), peer_handler_.get());
- has_data_channels_ = true;
return channel;
}
@@ -2792,8 +2844,12 @@ void RTCPeerConnection::RegisterTrack(MediaStreamTrack* track) {
}
void RTCPeerConnection::NoteSdpCreated(const RTCSessionDescription& desc) {
+ // TODO(https://bugs.webrtc.org/12215): Don't re-parse the description here,
+ // it's passed in as a parsed structure into
+ // CreateSessionDescriptionRequest::OnSuccess.
SdpUsageCategory sdp_usage = DeduceSdpUsageCategory(
- desc.type(), desc.sdp(), sdp_semantics_specified_, sdp_semantics_);
+ ParsedSessionDescription::Parse(desc.type(), desc.sdp()),
+ sdp_semantics_specified_, sdp_semantics_);
if (desc.type() == "offer") {
last_offer_ = desc.sdp();
UMA_HISTOGRAM_ENUMERATION(
@@ -2808,7 +2864,7 @@ void RTCPeerConnection::NoteSdpCreated(const RTCSessionDescription& desc) {
void RTCPeerConnection::OnStreamAddTrack(MediaStream* stream,
MediaStreamTrack* track) {
ExceptionState exception_state(v8::Isolate::GetCurrent(),
- ExceptionState::kExecutionContext, nullptr,
+ ExceptionState::kUnknownContext, nullptr,
nullptr);
MediaStreamVector streams;
streams.push_back(stream);
@@ -2824,7 +2880,7 @@ void RTCPeerConnection::OnStreamRemoveTrack(MediaStream* stream,
auto* sender = FindSenderForTrackAndStream(track, stream);
if (sender) {
ExceptionState exception_state(v8::Isolate::GetCurrent(),
- ExceptionState::kExecutionContext, nullptr,
+ ExceptionState::kUnknownContext, nullptr,
nullptr);
removeTrack(sender, exception_state);
// If removeTrack() failed most likely the connection is closed. The
@@ -3287,7 +3343,6 @@ void RTCPeerConnection::DidAddRemoteDataChannel(
auto* blink_channel = MakeGarbageCollected<RTCDataChannel>(
GetExecutionContext(), std::move(channel), peer_handler_.get());
- has_data_channels_ = true;
blink_channel->SetStateToOpenWithoutEvent();
MaybeDispatchEvent(MakeGarbageCollected<RTCDataChannelEvent>(
event_type_names::kDatachannel, blink_channel));
@@ -3518,8 +3573,14 @@ void RTCPeerConnection::CloseInternal() {
if (sctp_transport_) {
sctp_transport_->Close();
}
- for (auto& dtls_transport_iter : dtls_transports_by_native_transport_) {
- dtls_transport_iter.value->Close();
+ // Since Close() can trigger JS-level callbacks, iterate over a copy
+ // of the transports list.
+ auto dtls_transports_copy = dtls_transports_by_native_transport_;
+ for (auto& dtls_transport_iter : dtls_transports_copy) {
+ // Since "value" is a WeakPtr, check if it's still valid.
+ if (dtls_transport_iter.value) {
+ dtls_transport_iter.value->Close();
+ }
}
feature_handle_for_scheduler_.reset();
@@ -3616,11 +3677,6 @@ void RTCPeerConnection::Trace(Visitor* visitor) const {
MediaStreamObserver::Trace(visitor);
}
-base::TimeTicks RTCPeerConnection::WebRtcTimestampToBlinkTimestamp(
- base::TimeTicks webrtc_monotonic_time) const {
- return webrtc_monotonic_time + blink_webrtc_time_diff_;
-}
-
// static
void RTCPeerConnection::SetRtcPeerConnectionHandlerFactoryForTesting(
RtcPeerConnectionHandlerFactoryCallback callback) {
@@ -3637,4 +3693,12 @@ int RTCPeerConnection::PeerConnectionCountLimit() {
return kMaxPeerConnections;
}
+void RTCPeerConnection::DisableBackForwardCache(ExecutionContext* context) {
+ LocalDOMWindow* window = To<LocalDOMWindow>(context);
+ feature_handle_for_scheduler_ =
+ window->GetFrame()->GetFrameScheduler()->RegisterFeature(
+ SchedulingPolicy::Feature::kWebRTC,
+ SchedulingPolicy{SchedulingPolicy::DisableBackForwardCache()});
+}
+
} // namespace blink
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 4e9fb847e5f..241dc8e4c62 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
@@ -68,7 +68,7 @@ class RTCDtlsTransport;
class RTCDTMFSender;
class RTCDataChannel;
class RTCDataChannelInit;
-class RTCIceCandidateInitOrRTCIceCandidate;
+class RTCIceCandidateInit;
class RTCIceTransport;
class RTCOfferOptions;
class RTCPeerConnectionTest;
@@ -103,8 +103,7 @@ enum class SdpUsageCategory {
};
MODULES_EXPORT SdpUsageCategory
-DeduceSdpUsageCategory(const String& sdp_type,
- const String& sdp,
+DeduceSdpUsageCategory(const ParsedSessionDescription& parsed_sdp,
bool sdp_semantics_specified,
webrtc::SdpSemantics sdp_semantics);
@@ -212,10 +211,10 @@ class MODULES_EXPORT RTCPeerConnection final
ExceptionState&);
ScriptPromise addIceCandidate(ScriptState*,
- const RTCIceCandidateInitOrRTCIceCandidate&,
+ const RTCIceCandidateInit*,
ExceptionState&);
ScriptPromise addIceCandidate(ScriptState*,
- const RTCIceCandidateInitOrRTCIceCandidate&,
+ const RTCIceCandidateInit*,
V8VoidFunction*,
V8RTCPeerConnectionErrorCallback*,
ExceptionState&);
@@ -319,9 +318,8 @@ class MODULES_EXPORT RTCPeerConnection final
kSetLocalDescription,
kSetRemoteDescription,
};
- void ReportSetSdpUsage(
- SetSdpOperationType operation_type,
- const RTCSessionDescriptionInit* session_description_init) const;
+ void ReportSetSdpUsage(SetSdpOperationType operation_type,
+ const ParsedSessionDescription& parsed_sdp) const;
// MediaStreamObserver
void OnStreamAddTrack(MediaStream*, MediaStreamTrack*) override;
@@ -389,7 +387,7 @@ class MODULES_EXPORT RTCPeerConnection final
// explicitly specifying the SDP format, there may be errors if the
// application assumes a format that differs from the actual default format.
base::Optional<ComplexSdpCategory> CheckForComplexSdp(
- const RTCSessionDescriptionInit* session_description_init) const;
+ const ParsedSessionDescription&) const;
const CallSetupStateTracker& call_setup_state_tracker() const;
void NoteCallSetupStateEventPending(
@@ -568,16 +566,18 @@ class MODULES_EXPORT RTCPeerConnection final
void CloseInternal();
- void RecordRapporMetrics();
-
DOMException* checkSdpForStateErrors(ExecutionContext*,
- const RTCSessionDescriptionInit*,
- String* sdp);
- void MaybeWarnAboutUnsafeSdp(
- const RTCSessionDescriptionInit* session_description_init) const;
+ const ParsedSessionDescription&);
+ void RecordSdpCategoryAndMaybeEmitWarnings(
+ const ParsedSessionDescription&) const;
HeapHashSet<Member<RTCIceTransport>> ActiveIceTransports() const;
+ // Disables the back-forward cache usage. This is called when it becomes
+ // possible for a connection to happen, as a page with connections cannot be
+ // put into the cache so far.
+ void DisableBackForwardCache(ExecutionContext* context);
+
Member<RTCSessionDescription> pending_local_description_;
Member<RTCSessionDescription> current_local_description_;
Member<RTCSessionDescription> pending_remote_description_;
@@ -660,7 +660,7 @@ class MODULES_EXPORT RTCPeerConnection final
String last_answer_;
Member<RTCSctpTransport> sctp_transport_;
- bool has_data_channels_; // For RAPPOR metrics
+
// In Plan B, senders and receivers are added or removed independently of one
// another. In Unified Plan, senders and receivers are created in pairs as
// transceivers. Transceivers may become inactive, but are never removed.
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
index a977ad2ebdf..d88ca64f20b 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
@@ -80,7 +80,7 @@ enum RTCPeerConnectionState {
readonly attribute RTCSessionDescription? remoteDescription;
readonly attribute RTCSessionDescription? currentRemoteDescription;
readonly attribute RTCSessionDescription? pendingRemoteDescription;
- [CallWith=ScriptState, RaisesException, MeasureAs=RTCPeerConnectionAddIceCandidatePromise] Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate);
+ [CallWith=ScriptState, RaisesException, MeasureAs=RTCPeerConnectionAddIceCandidatePromise] Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate = {});
readonly attribute RTCSignalingState signalingState;
readonly attribute RTCIceGatheringState iceGatheringState;
readonly attribute RTCIceConnectionState iceConnectionState;
@@ -109,7 +109,7 @@ enum RTCPeerConnectionState {
// TODO(guidou): The failureCallback argument should be non-optional.
// TODO(crbug.com/841185): |failureCallback| is not nullable in the spec.
[CallWith=ScriptState] Promise<void> setRemoteDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, optional RTCPeerConnectionErrorCallback? failureCallback);
- [CallWith=ScriptState, RaisesException, MeasureAs=RTCPeerConnectionAddIceCandidateLegacy] Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
+ [CallWith=ScriptState, RaisesException, MeasureAs=RTCPeerConnectionAddIceCandidateLegacy] Promise<void> addIceCandidate(RTCIceCandidateInit candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
// getStats() has a standardized version and a legacy non-standard version.
//
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 aaf34b44fac..a48ff12ee49 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
@@ -27,6 +27,7 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_session_description_init.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
#include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h"
@@ -344,8 +345,11 @@ class StatsResponse : public webrtc::StatsObserver {
public:
class MemberIterator : public RTCLegacyStatsMemberIterator {
public:
- MemberIterator(const StatsReport::Values::const_iterator& it,
- const StatsReport::Values::const_iterator& end)
+ MemberIterator(
+ const std::vector<StatsReport::Values::value_type>::const_iterator&
+ it,
+ const std::vector<StatsReport::Values::value_type>::const_iterator&
+ end)
: it_(it), end_(end) {}
// RTCLegacyStatsMemberIterator
@@ -378,8 +382,8 @@ class StatsResponse : public webrtc::StatsObserver {
}
private:
- StatsReport::Values::const_iterator it_;
- StatsReport::Values::const_iterator end_;
+ std::vector<StatsReport::Values::value_type>::const_iterator it_;
+ std::vector<StatsReport::Values::value_type>::const_iterator end_;
};
explicit Report(const StatsReport* report)
@@ -387,7 +391,7 @@ class StatsResponse : public webrtc::StatsObserver {
type_(report->type()),
type_name_(report->TypeToString()),
timestamp_(report->timestamp()),
- values_(report->values()) {}
+ values_(report->values().begin(), report->values().end()) {}
~Report() override {
// Since the values vector holds pointers to const objects that are bound
@@ -411,7 +415,7 @@ class StatsResponse : public webrtc::StatsObserver {
const StatsReport::StatsType type_;
const std::string type_name_;
const double timestamp_;
- const StatsReport::Values values_;
+ const std::vector<StatsReport::Values::value_type> values_;
};
static void DeleteReports(std::vector<Report*>* reports) {
@@ -602,6 +606,42 @@ bool IsHostnameCandidate(const RTCIceCandidatePlatform& candidate) {
} // namespace
+// Implementation of ParsedSessionDescription
+ParsedSessionDescription::ParsedSessionDescription(const String& sdp_type,
+ const String& sdp)
+ : type_(sdp_type), sdp_(sdp) {}
+
+// static
+ParsedSessionDescription ParsedSessionDescription::Parse(
+ const RTCSessionDescriptionInit* session_description_init) {
+ ParsedSessionDescription temp(session_description_init->type(),
+ session_description_init->sdp());
+ temp.DoParse();
+ return temp;
+}
+
+// static
+ParsedSessionDescription ParsedSessionDescription::Parse(
+ const RTCSessionDescriptionPlatform* session_description_platform) {
+ ParsedSessionDescription temp(session_description_platform->GetType(),
+ session_description_platform->Sdp());
+ temp.DoParse();
+ return temp;
+}
+
+// static
+ParsedSessionDescription ParsedSessionDescription::Parse(const String& sdp_type,
+ const String& sdp) {
+ ParsedSessionDescription temp(sdp_type, sdp);
+ temp.DoParse();
+ return temp;
+}
+
+void ParsedSessionDescription::DoParse() {
+ description_.reset(webrtc::CreateSessionDescription(
+ type_.Utf8().c_str(), sdp_.Utf8().c_str(), &error_));
+}
+
// Implementation of LocalRTCStatsRequest.
LocalRTCStatsRequest::LocalRTCStatsRequest(RTCStatsRequest* impl)
: impl_(impl) {}
@@ -1106,7 +1146,8 @@ bool RTCPeerConnectionHandler::Initialize(
const webrtc::PeerConnectionInterface::RTCConfiguration&
server_configuration,
const MediaConstraints& options,
- WebLocalFrame* frame) {
+ WebLocalFrame* frame,
+ ExceptionState& exception_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK(frame);
frame_ = frame;
@@ -1140,7 +1181,7 @@ bool RTCPeerConnectionHandler::Initialize(
peer_connection_observer_ =
MakeGarbageCollected<Observer>(weak_factory_.GetWeakPtr(), task_runner_);
native_peer_connection_ = dependency_factory_->CreatePeerConnection(
- configuration_, frame_, peer_connection_observer_);
+ configuration_, frame_, peer_connection_observer_, exception_state);
if (!native_peer_connection_.get()) {
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
@@ -1159,7 +1200,8 @@ bool RTCPeerConnectionHandler::InitializeForTest(
const webrtc::PeerConnectionInterface::RTCConfiguration&
server_configuration,
const MediaConstraints& options,
- const base::WeakPtr<PeerConnectionTracker>& peer_connection_tracker) {
+ const base::WeakPtr<PeerConnectionTracker>& peer_connection_tracker,
+ ExceptionState& exception_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
CHECK(!initialize_called_);
@@ -1172,7 +1214,7 @@ bool RTCPeerConnectionHandler::InitializeForTest(
CopyConstraintsIntoRtcConfiguration(options, &configuration_);
native_peer_connection_ = dependency_factory_->CreatePeerConnection(
- configuration_, nullptr, peer_connection_observer_);
+ configuration_, nullptr, peer_connection_observer_, exception_state);
if (!native_peer_connection_.get()) {
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
@@ -1341,24 +1383,22 @@ void RTCPeerConnectionHandler::SetLocalDescription(
void RTCPeerConnectionHandler::SetLocalDescription(
blink::RTCVoidRequest* request,
- RTCSessionDescriptionPlatform* description) {
+ ParsedSessionDescription parsed_sdp) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setLocalDescription");
- String sdp = description->Sdp();
- String type = description->GetType();
+ String sdp = parsed_sdp.sdp();
+ String type = parsed_sdp.type();
if (peer_connection_tracker_) {
peer_connection_tracker_->TrackSetSessionDescription(
this, sdp, type, PeerConnectionTracker::SOURCE_LOCAL);
}
- webrtc::SdpParseError error;
- // Since CreateNativeSessionDescription uses the dependency factory, we need
- // to make this call on the current thread to be safe.
- std::unique_ptr<webrtc::SessionDescriptionInterface> native_desc(
- CreateNativeSessionDescription(sdp, type, &error));
+ const webrtc::SessionDescriptionInterface* native_desc =
+ parsed_sdp.description();
if (!native_desc) {
+ webrtc::SdpParseError error(parsed_sdp.error());
StringBuilder reason_str;
reason_str.Append("Failed to parse SessionDescription. ");
reason_str.Append(error.line.c_str());
@@ -1381,9 +1421,9 @@ void RTCPeerConnectionHandler::SetLocalDescription(
return;
}
- if (!first_local_description_ && IsOfferOrAnswer(native_desc.get())) {
+ if (!first_local_description_ && IsOfferOrAnswer(native_desc)) {
first_local_description_ =
- std::make_unique<FirstSessionDescription>(native_desc.get());
+ std::make_unique<FirstSessionDescription>(native_desc);
if (first_remote_description_) {
ReportFirstSessionDescriptions(*first_local_description_,
*first_remote_description_);
@@ -1415,30 +1455,27 @@ void RTCPeerConnectionHandler::SetLocalDescription(
rtc::scoped_refptr<
webrtc::SetLocalDescriptionObserverInterface>)>(
&webrtc::PeerConnectionInterface::SetLocalDescription),
- native_peer_connection_, WTF::Passed(std::move(native_desc)),
- webrtc_observer),
+ native_peer_connection_, parsed_sdp.release(), webrtc_observer),
CrossThreadUnretained("SetLocalDescription")));
}
void RTCPeerConnectionHandler::SetRemoteDescription(
blink::RTCVoidRequest* request,
- RTCSessionDescriptionPlatform* description) {
+ ParsedSessionDescription parsed_sdp) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setRemoteDescription");
- String sdp = description->Sdp();
- String type = description->GetType();
+ String sdp = parsed_sdp.sdp();
+ String type = parsed_sdp.type();
if (peer_connection_tracker_) {
peer_connection_tracker_->TrackSetSessionDescription(
this, sdp, type, PeerConnectionTracker::SOURCE_REMOTE);
}
- webrtc::SdpParseError error;
- // Since CreateNativeSessionDescription uses the dependency factory, we need
- // to make this call on the current thread to be safe.
- std::unique_ptr<webrtc::SessionDescriptionInterface> native_desc(
- CreateNativeSessionDescription(sdp, type, &error));
+ webrtc::SdpParseError error(parsed_sdp.error());
+ const webrtc::SessionDescriptionInterface* native_desc =
+ parsed_sdp.description();
if (!native_desc) {
StringBuilder reason_str;
reason_str.Append("Failed to parse SessionDescription. ");
@@ -1463,9 +1500,9 @@ void RTCPeerConnectionHandler::SetRemoteDescription(
return;
}
- if (!first_remote_description_ && IsOfferOrAnswer(native_desc.get())) {
- first_remote_description_.reset(
- new FirstSessionDescription(native_desc.get()));
+ if (!first_remote_description_ && IsOfferOrAnswer(native_desc)) {
+ first_remote_description_ =
+ std::make_unique<FirstSessionDescription>(native_desc);
if (first_local_description_) {
ReportFirstSessionDescriptions(*first_local_description_,
*first_remote_description_);
@@ -1497,8 +1534,7 @@ void RTCPeerConnectionHandler::SetRemoteDescription(
rtc::scoped_refptr<
webrtc::SetRemoteDescriptionObserverInterface>)>(
&webrtc::PeerConnectionInterface::SetRemoteDescription),
- native_peer_connection_, WTF::Passed(std::move(native_desc)),
- webrtc_observer),
+ native_peer_connection_, parsed_sdp.release(), webrtc_observer),
CrossThreadUnretained("SetRemoteDescription")));
}
@@ -2066,7 +2102,7 @@ ThermalUmaListener* RTCPeerConnectionHandler::thermal_uma_listener() const {
}
void RTCPeerConnectionHandler::OnThermalStateChange(
- base::PowerObserver::DeviceThermalState thermal_state) {
+ mojom::blink::DeviceThermalState thermal_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
if (is_closed_)
return;
@@ -2456,7 +2492,9 @@ void RTCPeerConnectionHandler::OnModifyTransceivers(
previous_state.stopped() != transceiver_states[i].stopped() ||
previous_state.direction() != transceiver_states[i].direction() ||
previous_state.current_direction() !=
- transceiver_states[i].current_direction();
+ transceiver_states[i].current_direction() ||
+ previous_state.header_extensions_negotiated() !=
+ transceiver_states[i].header_extensions_negotiated();
}
// Update the transceiver.
@@ -2564,20 +2602,6 @@ void RTCPeerConnectionHandler::OnInterestingUsage(int usage_pattern) {
client_->DidNoteInterestingUsage(usage_pattern);
}
-webrtc::SessionDescriptionInterface*
-RTCPeerConnectionHandler::CreateNativeSessionDescription(
- const String& sdp,
- const String& type,
- webrtc::SdpParseError* error) {
- webrtc::SessionDescriptionInterface* native_desc =
- dependency_factory_->CreateSessionDescription(type, sdp, error);
-
- LOG_IF(ERROR, !native_desc) << "Failed to create native session description."
- << " Type: " << type << " SDP: " << sdp;
-
- return native_desc;
-}
-
RTCPeerConnectionHandler::FirstSessionDescription::FirstSessionDescription(
const webrtc::SessionDescriptionInterface* sdesc) {
DCHECK(sdesc);
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 13c92ab732f..dd93da030f4 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
@@ -15,8 +15,8 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/power_monitor/power_observer.h"
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/peerconnection/media_stream_track_metrics.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h"
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h"
#include "third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h"
#include "third_party/blink/renderer/modules/peerconnection/webrtc_media_stream_track_adapter_map.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
@@ -52,10 +53,60 @@ class RTCAnswerOptionsPlatform;
class RTCLegacyStats;
class RTCOfferOptionsPlatform;
class RTCPeerConnectionHandlerClient;
+class RTCSessionDescriptionInit;
class RTCVoidRequest;
class SetLocalDescriptionRequest;
class WebLocalFrame;
+// Helper class for passing pre-parsed session descriptions to functions.
+// Create a ParsedSessionDescription by calling one of the Parse functions.
+// The function allows you to access its input SDP string, as well as the
+// parsed form. If parse failed, description() returns null, and error()
+// returns an error description. The class can't be modified or reused,
+// but can be neutered by calling release().
+class MODULES_EXPORT ParsedSessionDescription {
+ public:
+ static ParsedSessionDescription Parse(const RTCSessionDescriptionInit*);
+ static ParsedSessionDescription Parse(const RTCSessionDescriptionPlatform*);
+ static ParsedSessionDescription Parse(const String& type, const String& sdp);
+
+ // Moveable, but not copyable.
+ ParsedSessionDescription(ParsedSessionDescription&& other) = default;
+ ParsedSessionDescription& operator=(ParsedSessionDescription&& other) =
+ default;
+ ParsedSessionDescription(const ParsedSessionDescription&) = delete;
+ ParsedSessionDescription operator=(const ParsedSessionDescription&) = delete;
+
+ const webrtc::SessionDescriptionInterface* description() const {
+ return description_.get();
+ }
+ const webrtc::SdpParseError& error() const { return error_; }
+ const String& type() const { return type_; }
+ const String& sdp() const { return sdp_; }
+
+ std::unique_ptr<webrtc::SessionDescriptionInterface> release() {
+ return std::unique_ptr<webrtc::SessionDescriptionInterface>(
+ description_.release());
+ }
+
+ protected:
+ // The constructor will not parse the SDP.
+ // It is protected, not private, in order to allow it to be used to construct
+ // mock objects.
+ ParsedSessionDescription(const String& type, const String& sdp);
+ // The mock object also needs access to the description.
+ std::unique_ptr<webrtc::SessionDescriptionInterface> description_;
+
+ private:
+ // Does the actual parsing. Only called from the static Parse methods.
+ void DoParse();
+
+ String type_;
+ String sdp_;
+
+ webrtc::SdpParseError error_;
+};
+
// Mockable wrapper for blink::RTCStatsResponseBase
class MODULES_EXPORT LocalRTCStatsResponse : public rtc::RefCountInterface {
public:
@@ -124,14 +175,16 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
const webrtc::PeerConnectionInterface::RTCConfiguration&
server_configuration,
const MediaConstraints& options,
- const base::WeakPtr<PeerConnectionTracker>& peer_connection_tracker);
+ const base::WeakPtr<PeerConnectionTracker>& peer_connection_tracker,
+ ExceptionState& exception_state);
// RTCPeerConnectionHandlerPlatform implementation
virtual bool Initialize(
const webrtc::PeerConnectionInterface::RTCConfiguration&
server_configuration,
const MediaConstraints& options,
- WebLocalFrame* web_frame);
+ WebLocalFrame* web_frame,
+ ExceptionState& exception_state);
virtual void Stop();
virtual void StopAndUnregister();
@@ -149,10 +202,12 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
blink::RTCAnswerOptionsPlatform* options);
virtual void SetLocalDescription(blink::RTCVoidRequest* request);
+ // Set local and remote description.
+ // The parsed_sdp argument must be passed in with std::move.
virtual void SetLocalDescription(blink::RTCVoidRequest* request,
- RTCSessionDescriptionPlatform* description);
+ ParsedSessionDescription parsed_sdp);
virtual void SetRemoteDescription(blink::RTCVoidRequest* request,
- RTCSessionDescriptionPlatform* description);
+ ParsedSessionDescription parsed_sdp);
virtual const webrtc::PeerConnectionInterface::RTCConfiguration&
GetConfiguration() const;
@@ -211,7 +266,7 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
// Invoked when a new thermal state is received from the OS.
// Virtual for testing purposes.
virtual void OnThermalStateChange(
- base::PowerObserver::DeviceThermalState thermal_state);
+ mojom::blink::DeviceThermalState thermal_state);
// Start recording an event log.
void StartEventLog(int output_period_ms);
@@ -317,11 +372,6 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
kFailure,
};
- webrtc::SessionDescriptionInterface* CreateNativeSessionDescription(
- const String& sdp,
- const String& type,
- webrtc::SdpParseError* error);
-
RTCSessionDescriptionPlatform*
GetRTCSessionDescriptionPlatformOnSignalingThread(
CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
@@ -473,8 +523,8 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
scoped_refptr<ThermalResource> thermal_resource_ = nullptr;
// ThermalUmaListener is only tracked on peer connection that add a track.
std::unique_ptr<ThermalUmaListener> thermal_uma_listener_ = nullptr;
- base::PowerObserver::DeviceThermalState last_thermal_state_ =
- base::PowerObserver::DeviceThermalState::kUnknown;
+ mojom::blink::DeviceThermalState last_thermal_state_ =
+ mojom::blink::DeviceThermalState::kUnknown;
// Record info about the first SessionDescription from the local and
// remote side to record UMA stats once both are set. We only check
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 8f05c347ac7..5c821af2657 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
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h"
+#include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
#include "third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h"
#include "third_party/blink/renderer/modules/peerconnection/testing/fake_resource_listener.h"
#include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h"
@@ -295,9 +296,10 @@ class RTCPeerConnectionHandlerTest : public ::testing::Test {
webrtc::PeerConnectionInterface::RTCConfiguration config;
config.sdp_semantics = webrtc::SdpSemantics::kPlanB;
MediaConstraints constraints;
- EXPECT_TRUE(pc_handler_->InitializeForTest(
- config, constraints, mock_tracker_.get()->AsWeakPtr()));
-
+ DummyExceptionStateForTesting exception_state;
+ EXPECT_TRUE(pc_handler_->InitializeForTest(config, constraints,
+ mock_tracker_.get()->AsWeakPtr(),
+ exception_state));
mock_peer_connection_ = pc_handler_->native_peer_connection();
ASSERT_TRUE(mock_peer_connection_);
EXPECT_CALL(*mock_peer_connection_, Close());
@@ -661,8 +663,6 @@ TEST_F(RTCPeerConnectionHandlerTest, CreateAnswer) {
}
TEST_F(RTCPeerConnectionHandlerTest, setLocalDescription) {
- auto* description = MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- kDummySdpType, kDummySdp);
// PeerConnectionTracker::TrackSetSessionDescription is expected to be called
// before |mock_peer_connection| is called.
testing::InSequence sequence;
@@ -672,7 +672,9 @@ TEST_F(RTCPeerConnectionHandlerTest, setLocalDescription) {
PeerConnectionTracker::SOURCE_LOCAL));
EXPECT_CALL(*mock_peer_connection_, SetLocalDescriptionForMock(_, _));
- pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
+ pc_handler_->SetLocalDescription(
+ nullptr /*RTCVoidRequest*/,
+ MockParsedSessionDescription(kDummySdpType, kDummySdp));
RunMessageLoopsUntilIdle();
std::string sdp_string;
@@ -705,14 +707,12 @@ TEST_F(RTCPeerConnectionHandlerTest, setLocalDescriptionParseError) {
// Used to simulate a parse failure.
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
- pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
+ pc_handler_->SetLocalDescription(
+ nullptr /*RTCVoidRequest*/, ParsedSessionDescription::Parse(description));
RunMessageLoopsUntilIdle();
}
TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
- auto* description = MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- kDummySdpType, kDummySdp);
-
// PeerConnectionTracker::TrackSetSessionDescription is expected to be called
// before |mock_peer_connection| is called.
testing::InSequence sequence;
@@ -722,7 +722,9 @@ TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
PeerConnectionTracker::SOURCE_REMOTE));
EXPECT_CALL(*mock_peer_connection_, SetRemoteDescriptionForMock(_, _));
- pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
+ pc_handler_->SetRemoteDescription(
+ nullptr /*RTCVoidRequest*/,
+ MockParsedSessionDescription(kDummySdpType, kDummySdp));
RunMessageLoopsUntilIdle();
std::string sdp_string;
@@ -755,7 +757,8 @@ TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescriptionParseError) {
// Used to simulate a parse failure.
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
- pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
+ pc_handler_->SetRemoteDescription(
+ nullptr /*RTCVoidRequest*/, ParsedSessionDescription::Parse(description));
RunMessageLoopsUntilIdle();
}
@@ -1289,7 +1292,7 @@ TEST_F(RTCPeerConnectionHandlerTest, CheckInsertableStreamsConfig) {
TEST_F(RTCPeerConnectionHandlerTest, ThermalResourceDefaultValue) {
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
pc_handler_->OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kCritical);
+ mojom::blink::DeviceThermalState::kCritical);
#if defined(OS_MAC)
bool expect_disabled = false;
#else
@@ -1308,7 +1311,7 @@ TEST_F(RTCPeerConnectionHandlerTest,
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
pc_handler_->OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kCritical);
+ mojom::blink::DeviceThermalState::kCritical);
// A ThermalResource is created in response to the thermal signal.
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
}
@@ -1322,7 +1325,7 @@ TEST_F(RTCPeerConnectionHandlerTest,
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
// ThermalResource is created and injected on the fly.
pc_handler_->OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kCritical);
+ mojom::blink::DeviceThermalState::kCritical);
auto resources = mock_peer_connection_->adaptation_resources();
ASSERT_EQ(1u, resources.size());
auto thermal_resource = resources[0];
@@ -1334,8 +1337,7 @@ TEST_F(RTCPeerConnectionHandlerTest,
EXPECT_EQ(webrtc::ResourceUsageState::kOveruse,
resource_listener.latest_measurement());
// ThermalResource responds to new measurements.
- pc_handler_->OnThermalStateChange(
- base::PowerObserver::DeviceThermalState::kNominal);
+ pc_handler_->OnThermalStateChange(mojom::blink::DeviceThermalState::kNominal);
EXPECT_EQ(2u, resource_listener.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kUnderuse,
resource_listener.latest_measurement());
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.cc
index 4f44d82f0a0..9034298078c 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.cc
@@ -57,8 +57,8 @@ RTCPeerConnectionIceErrorEvent::RTCPeerConnectionIceErrorEvent(
host_candidate_ = initializer->hostCandidate();
if (initializer->hasUrl())
url_ = initializer->url();
- if (initializer->hasStatusText())
- error_text_ = initializer->statusText();
+ if (initializer->hasErrorText())
+ error_text_ = initializer->errorText();
}
RTCPeerConnectionIceErrorEvent::~RTCPeerConnectionIceErrorEvent() = default;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl
index a0734029421..98344f95bd7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl
@@ -10,5 +10,5 @@ dictionary RTCPeerConnectionIceErrorEventInit : EventInit {
DOMString hostCandidate;
DOMString url;
required unsigned short errorCode;
- USVString statusText;
-}; \ No newline at end of file
+ USVString errorText;
+};
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 1e6208438d5..8b5a528dbd1 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
@@ -43,6 +43,8 @@ namespace blink {
class RTCOfferOptionsPlatform;
+namespace {
+
static const char* kOfferSdpUnifiedPlanSingleAudioSingleVideo =
"v=0\r\n"
"o=- 6676943034916303038 2 IN IP4 127.0.0.1\r\n"
@@ -376,6 +378,15 @@ static const char* kOfferSdpPlanBMultipleAudioTracks =
"a=ssrc:4092260337 mslabel:46f8615e-7599-49f3-9a45-3cf0faf58614\r\n"
"a=ssrc:4092260337 label:6b5f436e-f85d-40a1-83e4-acec63ca4b82\r\n";
+RTCSessionDescriptionInit* CreateSdp(String type, String sdp) {
+ auto* sdp_init = RTCSessionDescriptionInit::Create();
+ sdp_init->setType(type);
+ sdp_init->setSdp(sdp);
+ return sdp_init;
+}
+
+} // namespace
+
class RTCPeerConnectionTest : public testing::Test {
public:
RTCPeerConnection* CreatePC(
@@ -584,22 +595,27 @@ TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsPlanB) {
RTCSessionDescriptionInit* sdp = RTCSessionDescriptionInit::Create();
sdp->setType("offer");
sdp->setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kUnifiedPlanExplicitSemantics);
sdp->setSdp(kOfferSdpPlanBMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kPlanBExplicitSemantics);
sdp->setSdp("invalid sdp");
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kErrorExplicitSemantics);
// No Complex SDP is detected if only a single track per m= section is used.
sdp->setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
sdp->setSdp(kOfferSdpPlanBSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
}
TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsUnifiedPlan) {
@@ -608,22 +624,27 @@ TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsUnifiedPlan) {
RTCSessionDescriptionInit* sdp = RTCSessionDescriptionInit::Create();
sdp->setType("offer");
sdp->setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kUnifiedPlanExplicitSemantics);
sdp->setSdp(kOfferSdpPlanBMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kPlanBExplicitSemantics);
sdp->setSdp("invalid sdp");
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kErrorExplicitSemantics);
// No Complex SDP is detected if only a single track per m= section is used.
sdp->setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
sdp->setSdp(kOfferSdpPlanBSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
}
TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsUnspecified) {
@@ -632,22 +653,27 @@ TEST_F(RTCPeerConnectionTest, CheckForComplexSdpWithSdpSemanticsUnspecified) {
RTCSessionDescriptionInit* sdp = RTCSessionDescriptionInit::Create();
sdp->setType("offer");
sdp->setSdp(kOfferSdpPlanBMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kPlanBImplicitSemantics);
sdp->setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks);
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kUnifiedPlanImplicitSemantics);
sdp->setSdp("invalid sdp");
- ASSERT_TRUE(pc->CheckForComplexSdp(sdp).has_value());
- ASSERT_EQ(pc->CheckForComplexSdp(sdp),
+ ASSERT_TRUE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
+ ASSERT_EQ(pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)),
ComplexSdpCategory::kErrorImplicitSemantics);
// No Complex SDP is detected if only a single track per m= section is used.
sdp->setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
sdp->setSdp(kOfferSdpPlanBSingleAudioSingleVideo);
- ASSERT_FALSE(pc->CheckForComplexSdp(sdp).has_value());
+ ASSERT_FALSE(
+ pc->CheckForComplexSdp(ParsedSessionDescription::Parse(sdp)).has_value());
}
TEST_F(RTCPeerConnectionTest, CheckInsertableStreamsConfig) {
@@ -746,12 +772,12 @@ class FakeRTCPeerConnectionHandlerPlatform
}
void SetLocalDescription(RTCVoidRequest* request,
- RTCSessionDescriptionPlatform*) override {
+ ParsedSessionDescription) override {
PostToCompleteRequest<RTCVoidRequest>(async_operation_action_, request);
}
void SetRemoteDescription(RTCVoidRequest* request,
- RTCSessionDescriptionPlatform*) override {
+ ParsedSessionDescription) override {
PostToCompleteRequest<RTCVoidRequest>(async_operation_action_, request);
}
@@ -1058,22 +1084,26 @@ TEST(DeduceSdpUsageCategory, SimplePlanBIsAlwaysSafe) {
// If the default is Plan B.
EXPECT_EQ(
SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBSingleAudioSingleVideo),
false, webrtc::SdpSemantics::kPlanB));
// If the default is Unified Plan.
EXPECT_EQ(
SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBSingleAudioSingleVideo),
false, webrtc::SdpSemantics::kUnifiedPlan));
// If sdpSemantics is explicitly set to Plan B.
EXPECT_EQ(
SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBSingleAudioSingleVideo),
true, webrtc::SdpSemantics::kPlanB));
// If sdpSemantics is explicitly set to Unified Plan.
EXPECT_EQ(
SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBSingleAudioSingleVideo),
true, webrtc::SdpSemantics::kUnifiedPlan));
}
@@ -1082,72 +1112,175 @@ TEST(DeduceSdpUsageCategory, SimplePlanBIsAlwaysSafe) {
TEST(DeduceSdpUsageCategory, SimpleUnifiedPlanIsAlwaysSafe) {
// If the default is Plan B.
EXPECT_EQ(SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer",
- kOfferSdpUnifiedPlanSingleAudioSingleVideo,
- false, webrtc::SdpSemantics::kPlanB));
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ false, webrtc::SdpSemantics::kPlanB));
// If the default is Unified Plan.
EXPECT_EQ(SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer",
- kOfferSdpUnifiedPlanSingleAudioSingleVideo,
- false, webrtc::SdpSemantics::kUnifiedPlan));
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ false, webrtc::SdpSemantics::kUnifiedPlan));
// If sdpSemantics is explicitly set to Plan B.
EXPECT_EQ(SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer",
- kOfferSdpUnifiedPlanSingleAudioSingleVideo,
- true, webrtc::SdpSemantics::kPlanB));
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ true, webrtc::SdpSemantics::kPlanB));
// If sdpSemantics is explicitly set to Unified Plan.
EXPECT_EQ(SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer",
- kOfferSdpUnifiedPlanSingleAudioSingleVideo,
- true, webrtc::SdpSemantics::kUnifiedPlan));
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ true, webrtc::SdpSemantics::kUnifiedPlan));
}
// Test that complex SDP is always unsafe when relying on default sdpSemantics.
TEST(DeduceSdpUsageCategory, ComplexSdpIsAlwaysUnsafeWithDefaultSdpSemantics) {
// If the default is Plan B and the SDP is complex Plan B.
- EXPECT_EQ(SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
- false, webrtc::SdpSemantics::kPlanB));
- // If the default is Plan B and the SDP is complex Unified Plan.
EXPECT_EQ(
SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBMultipleAudioTracks),
false, webrtc::SdpSemantics::kPlanB));
- // If the default is Unified Plan and the SDP is complex Plan B.
+ // If the default is Plan B and the SDP is complex Unified Plan.
EXPECT_EQ(SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
- false, webrtc::SdpSemantics::kUnifiedPlan));
- // If the default is Unified Plan and the SDP is complex UNified Plan.
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ false, webrtc::SdpSemantics::kPlanB));
+ // If the default is Unified Plan and the SDP is complex Plan B.
EXPECT_EQ(
SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBMultipleAudioTracks),
false, webrtc::SdpSemantics::kUnifiedPlan));
+ // If the default is Unified Plan and the SDP is complex UNified Plan.
+ EXPECT_EQ(SdpUsageCategory::kUnsafe,
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ false, webrtc::SdpSemantics::kUnifiedPlan));
}
// Test that when sdpSemantics is explicitly set, complex SDP is safe if it is
// of the same format and unsafe if the format is different.
TEST(DeduceSdpUsageCategory, ComplexSdpIsSafeIfMatchingExplicitSdpSemantics) {
// If sdpSemantics is explicitly set to Plan B and the SDP is complex Plan B.
- EXPECT_EQ(SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
- true, webrtc::SdpSemantics::kPlanB));
- // If sdpSemantics is explicitly set to Unified Plan and the SDP is complex
- // Unified Plan.
EXPECT_EQ(
SdpUsageCategory::kSafe,
- DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
- true, webrtc::SdpSemantics::kUnifiedPlan));
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBMultipleAudioTracks),
+ true, webrtc::SdpSemantics::kPlanB));
+ // If sdpSemantics is explicitly set to Unified Plan and the SDP is complex
+ // Unified Plan.
+ EXPECT_EQ(SdpUsageCategory::kSafe,
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ true, webrtc::SdpSemantics::kUnifiedPlan));
// If the sdpSemantics is explicitly set to Plan B but the SDP is complex
// Unified Plan.
- EXPECT_EQ(
- SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
- true, webrtc::SdpSemantics::kPlanB));
+ EXPECT_EQ(SdpUsageCategory::kUnsafe,
+ DeduceSdpUsageCategory(
+ ParsedSessionDescription::Parse(
+ "offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ true, webrtc::SdpSemantics::kPlanB));
// If the sdpSemantics is explicitly set to Unified Plan but the SDP is
// complex Plan B.
- EXPECT_EQ(SdpUsageCategory::kUnsafe,
- DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
- true, webrtc::SdpSemantics::kUnifiedPlan));
+ EXPECT_EQ(
+ SdpUsageCategory::kUnsafe,
+ DeduceSdpUsageCategory(ParsedSessionDescription::Parse(
+ "offer", kOfferSdpPlanBMultipleAudioTracks),
+ true, webrtc::SdpSemantics::kUnifiedPlan));
+}
+
+TEST_F(RTCPeerConnectionTest, SdpSemanticsUseCounters) {
+ // Constructor with default sdpSemantics (= Unified Plan).
+ {
+ V8TestingScope scope;
+ RTCPeerConnection* pc = CreatePC(scope, /*sdp_semantics=*/base::nullopt);
+ // Use counters reflect the constructor's sdpSemantics.
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithPlanB));
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithUnifiedPlan));
+ // Setting simple Unified Plan SDP does not affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ scope.GetExceptionState());
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ // Setting complex Unified Plan SDP does affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ scope.GetExceptionState());
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ }
+ // Constructor with {sdpSemantics:"plan-b"}.
+ {
+ V8TestingScope scope;
+ RTCPeerConnection* pc = CreatePC(scope, "plan-b");
+ // Use counters reflect the constructor's sdpSemantics.
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithPlanB));
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithUnifiedPlan));
+ // Setting simple Plan B SDP does not affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpPlanBSingleAudioSingleVideo),
+ scope.GetExceptionState());
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ // Setting complex Plan B SDP does affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpPlanBMultipleAudioTracks),
+ scope.GetExceptionState());
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ }
+ // Constructor with {sdpSemantics:"unified-plan"}.
+ {
+ V8TestingScope scope;
+ RTCPeerConnection* pc = CreatePC(scope, "unified-plan");
+ // Use counters reflect the constructor's sdpSemantics.
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithPlanB));
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionConstructedWithUnifiedPlan));
+ // Setting simple Unified Plan SDP does not affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpUnifiedPlanSingleAudioSingleVideo),
+ scope.GetExceptionState());
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ // Setting complex Unified Plan SDP does affect use counters.
+ pc->setRemoteDescription(
+ scope.GetScriptState(),
+ CreateSdp("offer", kOfferSdpUnifiedPlanMultipleAudioTracks),
+ scope.GetExceptionState());
+ EXPECT_FALSE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexPlanB));
+ EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+ WebFeature::kRTCPeerConnectionUsingComplexUnifiedPlan));
+ }
}
TEST_F(RTCPeerConnectionTest, MediaStreamTrackStopsThrottling) {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.idl
index 388f11b49ac..8d77b3a3e52 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_header_extension_capability.idl
@@ -5,4 +5,5 @@
// https://w3c.github.io/webrtc-pc/#rtcrtpheaderextensioncapability*
dictionary RTCRtpHeaderExtensionCapability {
DOMString uri;
-}; \ No newline at end of file
+ RTCRtpTransceiverDirection direction = "sendrecv";
+};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
index 173e1965cbc..c60eba5d8f7 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
@@ -115,9 +115,7 @@ RTCRtpReceiver::getSynchronizationSources(ScriptState* script_state,
RTCRtpSynchronizationSource* synchronization_source =
MakeGarbageCollected<RTCRtpSynchronizationSource>();
synchronization_source->setTimestamp(
- time_converter
- .MonotonicTimeToPseudoWallTime(
- pc_->WebRtcTimestampToBlinkTimestamp(web_source->Timestamp()))
+ time_converter.MonotonicTimeToPseudoWallTime(web_source->Timestamp())
.InMilliseconds());
synchronization_source->setSource(web_source->Source());
if (web_source->AudioLevel())
@@ -154,9 +152,7 @@ RTCRtpReceiver::getContributingSources(ScriptState* script_state,
RTCRtpContributingSource* contributing_source =
MakeGarbageCollected<RTCRtpContributingSource>();
contributing_source->setTimestamp(
- time_converter
- .MonotonicTimeToPseudoWallTime(
- pc_->WebRtcTimestampToBlinkTimestamp(web_source->Timestamp()))
+ time_converter.MonotonicTimeToPseudoWallTime(web_source->Timestamp())
.InMilliseconds());
contributing_source->setSource(web_source->Source());
if (web_source->AudioLevel())
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h
index d737060220d..5316a5100b1 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h
@@ -151,7 +151,7 @@ class MODULES_EXPORT RTCRtpReceiverImpl : public RTCRtpReceiverPlatform {
};
class MODULES_EXPORT RTCRtpReceiverOnlyTransceiver
- : public RTCRtpTransceiverPlatform {
+ : public RTCRtpPlanBTransceiverPlatform {
public:
RTCRtpReceiverOnlyTransceiver(
std::unique_ptr<RTCRtpReceiverPlatform> receiver);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h
index 42ffd6c1ff4..1ec13b811fd 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h
@@ -170,7 +170,7 @@ class MODULES_EXPORT RTCRtpSenderImpl : public blink::RTCRtpSenderPlatform {
};
class MODULES_EXPORT RTCRtpSenderOnlyTransceiver
- : public RTCRtpTransceiverPlatform {
+ : public RTCRtpPlanBTransceiverPlatform {
public:
explicit RTCRtpSenderOnlyTransceiver(
std::unique_ptr<blink::RTCRtpSenderPlatform> sender);
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 fc46e57ab85..ddc698d1552 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
@@ -4,10 +4,12 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_capability.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h"
+#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
@@ -69,6 +71,21 @@ bool TransceiverDirectionFromString(
return false;
}
+bool OptionalTransceiverDirectionFromStringWithStopped(
+ const String& direction_string,
+ absl::optional<webrtc::RtpTransceiverDirection>* direction_out) {
+ if (direction_string == "stopped") {
+ *direction_out = webrtc::RtpTransceiverDirection::kStopped;
+ return true;
+ }
+ base::Optional<webrtc::RtpTransceiverDirection> base_direction;
+ bool result =
+ TransceiverDirectionFromString(direction_string, &base_direction);
+ if (base_direction)
+ *direction_out = *base_direction;
+ return result;
+}
+
} // namespace
webrtc::RtpTransceiverInit ToRtpTransceiverInit(
@@ -268,6 +285,74 @@ void RTCRtpTransceiver::setCodecPreferences(
}
}
+void RTCRtpTransceiver::setOfferedRtpHeaderExtensions(
+ const HeapVector<Member<RTCRtpHeaderExtensionCapability>>&
+ header_extensions_to_offer,
+ ExceptionState& exception_state) {
+ Vector<webrtc::RtpHeaderExtensionCapability> webrtc_hdr_exts;
+ auto webrtc_offered_exts = platform_transceiver_->HeaderExtensionsToOffer();
+ int id = 1;
+ for (const auto& hdr_ext : header_extensions_to_offer) {
+ // Handle invalid requests for mandatory extensions as per
+ // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
+ // Step 2.1 (not handled on the WebRTC level).
+ if (hdr_ext->uri().IsEmpty()) {
+ exception_state.ThrowTypeError("The extension URL cannot be empty.");
+ return;
+ }
+
+ absl::optional<webrtc::RtpTransceiverDirection> direction;
+ if (!OptionalTransceiverDirectionFromStringWithStopped(hdr_ext->direction(),
+ &direction) ||
+ !direction) {
+ exception_state.ThrowTypeError("Invalid RTCRtpTransceiverDirection.");
+ return;
+ }
+ const int id_to_store = direction ? id++ : 0;
+ webrtc_hdr_exts.emplace_back(hdr_ext->uri().Ascii(), id_to_store,
+ *direction);
+ }
+ webrtc::RTCError status =
+ platform_transceiver_->SetOfferedRtpHeaderExtensions(
+ std::move(webrtc_hdr_exts));
+ if (status.type() == webrtc::RTCErrorType::UNSUPPORTED_PARAMETER) {
+ // TODO(crbug.com/1051821): support DOMExceptionCode::kNotSupportedError in
+ // rtc_error_util.h/cc and get rid of this manually handled case.
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ status.message());
+ return;
+ } else if (status.type() != webrtc::RTCErrorType::NONE) {
+ ThrowExceptionFromRTCError(status, exception_state);
+ return;
+ }
+}
+
+HeapVector<Member<RTCRtpHeaderExtensionCapability>>
+RTCRtpTransceiver::headerExtensionsToOffer() const {
+ auto webrtc_exts = platform_transceiver_->HeaderExtensionsToOffer();
+ HeapVector<Member<RTCRtpHeaderExtensionCapability>> exts;
+ for (const auto& webrtc_ext : webrtc_exts) {
+ auto* ext = MakeGarbageCollected<RTCRtpHeaderExtensionCapability>();
+ ext->setDirection(TransceiverDirectionToString(webrtc_ext.direction));
+ ext->setUri(webrtc_ext.uri.c_str());
+ exts.push_back(ext);
+ }
+ return exts;
+}
+
+HeapVector<Member<RTCRtpHeaderExtensionCapability>>
+RTCRtpTransceiver::headerExtensionsNegotiated() const {
+ auto webrtc_exts = platform_transceiver_->HeaderExtensionsNegotiated();
+ HeapVector<Member<RTCRtpHeaderExtensionCapability>> exts;
+ for (const auto& webrtc_ext : webrtc_exts) {
+ auto* ext = MakeGarbageCollected<RTCRtpHeaderExtensionCapability>();
+ ext->setDirection(TransceiverDirectionToString(webrtc_ext.direction));
+ ext->setUri(webrtc_ext.uri.c_str());
+ exts.push_back(ext);
+ }
+ return exts;
+}
+
void RTCRtpTransceiver::Trace(Visitor* visitor) const {
visitor->Trace(pc_);
visitor->Trace(sender_);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
index ce7a658e6f6..b30e360f41d 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
@@ -22,6 +22,7 @@
namespace blink {
class RTCPeerConnection;
+class RTCRtpHeaderExtensionCapability;
class RTCRtpReceiver;
class RTCRtpSender;
@@ -68,6 +69,15 @@ class RTCRtpTransceiver final : public ScriptWrappable {
bool DirectionHasRecv() const;
bool FiredDirectionHasRecv() const;
+ void setOfferedRtpHeaderExtensions(
+ const HeapVector<Member<RTCRtpHeaderExtensionCapability>>&
+ header_extensions_to_offer,
+ ExceptionState& exception_state);
+ HeapVector<Member<RTCRtpHeaderExtensionCapability>> headerExtensionsToOffer()
+ const;
+ HeapVector<Member<RTCRtpHeaderExtensionCapability>>
+ headerExtensionsNegotiated() const;
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.idl
index d642fd2dd72..f02719c0837 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.idl
@@ -23,4 +23,9 @@ interface RTCRtpTransceiver {
readonly attribute RTCRtpTransceiverDirection? currentDirection;
[Measure, RuntimeEnabled=RTCRtpTransceiverStop, RaisesException] void stop();
[RaisesException] void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
+ [RaisesException, RuntimeEnabled=RTCRtpHeaderExtensionControl] void setOfferedRtpHeaderExtensions(
+ sequence<RTCRtpHeaderExtensionCapability>
+ headerExtensionsToOffer);
+ [RuntimeEnabled=RTCRtpHeaderExtensionControl] readonly attribute FrozenArray<RTCRtpHeaderExtensionCapability> headerExtensionsToOffer;
+ [RuntimeEnabled=RTCRtpHeaderExtensionControl] readonly attribute FrozenArray<RTCRtpHeaderExtensionCapability> headerExtensionsNegotiated;
};
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 f88d1933307..600c9a265f2 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
@@ -21,7 +21,9 @@ RtpTransceiverState::RtpTransceiverState(
bool stopped,
webrtc::RtpTransceiverDirection direction,
base::Optional<webrtc::RtpTransceiverDirection> current_direction,
- base::Optional<webrtc::RtpTransceiverDirection> fired_direction)
+ base::Optional<webrtc::RtpTransceiverDirection> fired_direction,
+ WTF::Vector<webrtc::RtpHeaderExtensionCapability>
+ header_extensions_negotiated)
: main_task_runner_(std::move(main_task_runner)),
signaling_task_runner_(std::move(signaling_task_runner)),
webrtc_transceiver_(std::move(webrtc_transceiver)),
@@ -32,7 +34,8 @@ RtpTransceiverState::RtpTransceiverState(
stopped_(std::move(stopped)),
direction_(std::move(direction)),
current_direction_(std::move(current_direction)),
- fired_direction_(std::move(fired_direction)) {
+ fired_direction_(std::move(fired_direction)),
+ header_extensions_negotiated_(std::move(header_extensions_negotiated)) {
DCHECK(main_task_runner_);
DCHECK(signaling_task_runner_);
DCHECK(webrtc_transceiver_);
@@ -49,7 +52,9 @@ RtpTransceiverState::RtpTransceiverState(RtpTransceiverState&& other)
stopped_(std::move(other.stopped_)),
direction_(std::move(other.direction_)),
current_direction_(std::move(other.current_direction_)),
- fired_direction_(std::move(other.fired_direction_)) {
+ fired_direction_(std::move(other.fired_direction_)),
+ header_extensions_negotiated_(
+ std::move(other.header_extensions_negotiated_)) {
// Explicitly null |other|'s task runners for use in destructor.
other.main_task_runner_ = nullptr;
other.signaling_task_runner_ = nullptr;
@@ -80,6 +85,9 @@ RtpTransceiverState& RtpTransceiverState::operator=(
direction_ = std::move(other.direction_);
current_direction_ = std::move(other.current_direction_);
fired_direction_ = std::move(other.fired_direction_);
+ header_extensions_negotiated_ =
+ std::move(other.header_extensions_negotiated_);
+
return *this;
}
@@ -178,6 +186,11 @@ RtpTransceiverState::fired_direction() const {
return fired_direction_;
}
+const Vector<webrtc::RtpHeaderExtensionCapability>&
+RtpTransceiverState::header_extensions_negotiated() const {
+ return header_extensions_negotiated_;
+}
+
class RTCRtpTransceiverImpl::RTCRtpTransceiverInternal
: public WTF::ThreadSafeRefCounted<
RTCRtpTransceiverImpl::RTCRtpTransceiverInternal,
@@ -268,6 +281,23 @@ class RTCRtpTransceiverImpl::RTCRtpTransceiverInternal
return webrtc_transceiver_->SetCodecPreferences(codec_preferences);
}
+ webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ std::vector<webrtc::RtpHeaderExtensionCapability>
+ header_extensions_to_offer) {
+ return webrtc_transceiver_->SetOfferedRtpHeaderExtensions(
+ header_extensions_to_offer);
+ }
+
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
+ const {
+ return state_.header_extensions_negotiated();
+ }
+
+ std::vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const {
+ return webrtc_transceiver_->HeaderExtensionsToOffer();
+ }
+
private:
friend class WTF::ThreadSafeRefCounted<RTCRtpTransceiverInternal,
RTCRtpTransceiverInternalTraits>;
@@ -420,4 +450,28 @@ webrtc::RTCError RTCRtpTransceiverImpl::SetCodecPreferences(
std_codec_preferences.begin());
return internal_->setCodecPreferences(std_codec_preferences);
}
+
+webrtc::RTCError RTCRtpTransceiverImpl::SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions_to_offer) {
+ std::vector<webrtc::RtpHeaderExtensionCapability> std_header_extensions;
+ std::move(header_extensions_to_offer.begin(),
+ header_extensions_to_offer.end(),
+ std::back_inserter(std_header_extensions));
+ return internal_->SetOfferedRtpHeaderExtensions(std_header_extensions);
+}
+
+Vector<webrtc::RtpHeaderExtensionCapability>
+RTCRtpTransceiverImpl::HeaderExtensionsNegotiated() const {
+ return internal_->HeaderExtensionsNegotiated();
+}
+
+Vector<webrtc::RtpHeaderExtensionCapability>
+RTCRtpTransceiverImpl::HeaderExtensionsToOffer() const {
+ auto std_extensions = internal_->HeaderExtensionsToOffer();
+ Vector<webrtc::RtpHeaderExtensionCapability> extensions;
+ std::move(std_extensions.begin(), std_extensions.end(),
+ std::back_inserter(extensions));
+ return extensions;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h
index 78f26335752..ef125e171f8 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h
@@ -66,7 +66,9 @@ class MODULES_EXPORT RtpTransceiverState {
bool stopped,
webrtc::RtpTransceiverDirection direction,
base::Optional<webrtc::RtpTransceiverDirection> current_direction,
- base::Optional<webrtc::RtpTransceiverDirection> fired_direction);
+ base::Optional<webrtc::RtpTransceiverDirection> fired_direction,
+ Vector<webrtc::RtpHeaderExtensionCapability>
+ header_extensions_negotiated);
RtpTransceiverState(RtpTransceiverState&&);
RtpTransceiverState(const RtpTransceiverState&) = delete;
~RtpTransceiverState();
@@ -94,6 +96,8 @@ class MODULES_EXPORT RtpTransceiverState {
void set_direction(webrtc::RtpTransceiverDirection);
base::Optional<webrtc::RtpTransceiverDirection> current_direction() const;
base::Optional<webrtc::RtpTransceiverDirection> fired_direction() const;
+ const Vector<webrtc::RtpHeaderExtensionCapability>&
+ header_extensions_negotiated() const;
private:
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
@@ -107,6 +111,7 @@ class MODULES_EXPORT RtpTransceiverState {
webrtc::RtpTransceiverDirection direction_;
base::Optional<webrtc::RtpTransceiverDirection> current_direction_;
base::Optional<webrtc::RtpTransceiverDirection> fired_direction_;
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions_negotiated_;
};
// RTCRtpTransceiverImpl::set_state() performs differently depending on the
@@ -185,6 +190,12 @@ class MODULES_EXPORT RTCRtpTransceiverImpl : public RTCRtpTransceiverPlatform {
webrtc::RTCError Stop() override;
webrtc::RTCError SetCodecPreferences(
Vector<webrtc::RtpCodecCapability>) override;
+ webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) override;
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
+ const override;
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const override;
private:
class RTCRtpTransceiverInternal;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc
index 4b9ac9fc495..f9c39fe1f9b 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc
@@ -146,7 +146,7 @@ class RTCRtpTransceiverImplTest : public ::testing::Test {
blink::ToBaseOptional(webrtc_transceiver->mid()),
webrtc_transceiver->stopped(), webrtc_transceiver->direction(),
blink::ToBaseOptional(webrtc_transceiver->current_direction()),
- blink::ToBaseOptional(webrtc_transceiver->fired_direction()));
+ blink::ToBaseOptional(webrtc_transceiver->fired_direction()), {});
}
protected:
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 28a108e0bb8..23f74767657 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc
@@ -35,7 +35,7 @@ ThermalResource::ThermalResource(
: task_runner_(std::move(task_runner)) {}
void ThermalResource::OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState measurement) {
+ mojom::blink::DeviceThermalState measurement) {
base::AutoLock auto_lock(lock_);
measurement_ = measurement;
++measurement_id_;
@@ -50,8 +50,7 @@ void ThermalResource::SetResourceListener(webrtc::ResourceListener* listener) {
base::AutoLock auto_lock(lock_);
DCHECK(!listener_ || !listener) << "Must not overwrite existing listener.";
listener_ = listener;
- if (listener_ &&
- measurement_ != base::PowerObserver::DeviceThermalState::kUnknown) {
+ if (listener_ && measurement_ != mojom::blink::DeviceThermalState::kUnknown) {
ReportMeasurementWhileHoldingLock(measurement_id_);
}
}
@@ -68,16 +67,16 @@ void ThermalResource::ReportMeasurementWhileHoldingLock(size_t measurement_id) {
if (measurement_id != measurement_id_ || !listener_)
return;
switch (measurement_) {
- case base::PowerObserver::DeviceThermalState::kUnknown:
+ case mojom::blink::DeviceThermalState::kUnknown:
// Stop repeating measurements.
return;
- case base::PowerObserver::DeviceThermalState::kNominal:
- case base::PowerObserver::DeviceThermalState::kFair:
+ case mojom::blink::DeviceThermalState::kNominal:
+ case mojom::blink::DeviceThermalState::kFair:
listener_->OnResourceUsageStateMeasured(
this, webrtc::ResourceUsageState::kUnderuse);
break;
- case base::PowerObserver::DeviceThermalState::kSerious:
- case base::PowerObserver::DeviceThermalState::kCritical:
+ case mojom::blink::DeviceThermalState::kSerious:
+ case mojom::blink::DeviceThermalState::kCritical:
listener_->OnResourceUsageStateMeasured(
this, webrtc::ResourceUsageState::kOveruse);
break;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.h b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.h
index 281caaf0a3b..0f0d1c89b63 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.h
@@ -7,10 +7,10 @@
#include "base/feature_list.h"
#include "base/memory/scoped_refptr.h"
-#include "base/power_monitor/power_observer.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/webrtc/api/adaptation/resource.h"
@@ -46,8 +46,7 @@ class MODULES_EXPORT ThermalResource : public webrtc::Resource {
scoped_refptr<base::SequencedTaskRunner> task_runner);
~ThermalResource() override = default;
- void OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState measurement);
+ void OnThermalMeasurement(mojom::blink::DeviceThermalState measurement);
// webrtc::Resource implementation.
std::string Name() const override;
@@ -61,8 +60,8 @@ class MODULES_EXPORT ThermalResource : public webrtc::Resource {
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::Lock lock_;
webrtc::ResourceListener* listener_ GUARDED_BY(&lock_) = nullptr;
- base::PowerObserver::DeviceThermalState measurement_ GUARDED_BY(&lock_) =
- base::PowerObserver::DeviceThermalState::kUnknown;
+ mojom::blink::DeviceThermalState measurement_ GUARDED_BY(&lock_) =
+ mojom::blink::DeviceThermalState::kUnknown;
size_t measurement_id_ GUARDED_BY(&lock_) = 0u;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource_test.cc
index 628a170c583..4e1dd30825b 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource_test.cc
@@ -50,8 +50,7 @@ TEST_F(ThermalResourceTest, NoMeasurementsByDefault) {
TEST_F(ThermalResourceTest, NominalTriggersUnderuse) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kNominal);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kNominal);
EXPECT_EQ(1u, listener_.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kUnderuse,
listener_.latest_measurement());
@@ -59,8 +58,7 @@ TEST_F(ThermalResourceTest, NominalTriggersUnderuse) {
TEST_F(ThermalResourceTest, FairTriggersUnderuse) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kFair);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kFair);
EXPECT_EQ(1u, listener_.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kUnderuse,
listener_.latest_measurement());
@@ -68,8 +66,7 @@ TEST_F(ThermalResourceTest, FairTriggersUnderuse) {
TEST_F(ThermalResourceTest, SeriousTriggersOveruse) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
EXPECT_EQ(1u, listener_.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kOveruse,
listener_.latest_measurement());
@@ -77,8 +74,7 @@ TEST_F(ThermalResourceTest, SeriousTriggersOveruse) {
TEST_F(ThermalResourceTest, CriticalTriggersOveruse) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kCritical);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kCritical);
EXPECT_EQ(1u, listener_.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kOveruse,
listener_.latest_measurement());
@@ -86,15 +82,13 @@ TEST_F(ThermalResourceTest, CriticalTriggersOveruse) {
TEST_F(ThermalResourceTest, UnknownDoesNotTriggerUsage) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kUnknown);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kUnknown);
EXPECT_EQ(0u, listener_.measurement_count());
}
TEST_F(ThermalResourceTest, MeasurementsRepeatEvery10Seconds) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
size_t expected_count = listener_.measurement_count();
// First Interval.
@@ -130,8 +124,7 @@ TEST_F(ThermalResourceTest, MeasurementsRepeatEvery10Seconds) {
TEST_F(ThermalResourceTest, NewMeasurementInvalidatesInFlightRepetition) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(kReportIntervalMs));
@@ -146,8 +139,7 @@ TEST_F(ThermalResourceTest, NewMeasurementInvalidatesInFlightRepetition) {
EXPECT_EQ(webrtc::ResourceUsageState::kOveruse,
listener_.latest_measurement());
// Trigger kUnderuse.
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kNominal);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kNominal);
EXPECT_EQ(3u, listener_.measurement_count());
EXPECT_EQ(webrtc::ResourceUsageState::kUnderuse,
listener_.latest_measurement());
@@ -169,15 +161,13 @@ TEST_F(ThermalResourceTest, NewMeasurementInvalidatesInFlightRepetition) {
TEST_F(ThermalResourceTest, UnknownStopsRepeatedMeasurements) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(kReportIntervalMs));
// The measurement is repeating.
EXPECT_EQ(2u, listener_.measurement_count());
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kUnknown);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kUnknown);
task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(kReportIntervalMs));
// No more measurements.
@@ -186,8 +176,7 @@ TEST_F(ThermalResourceTest, UnknownStopsRepeatedMeasurements) {
TEST_F(ThermalResourceTest, UnregisteringStopsRepeatedMeasurements) {
resource_->SetResourceListener(&listener_);
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(kReportIntervalMs));
// The measurement is repeating.
@@ -201,8 +190,7 @@ TEST_F(ThermalResourceTest, UnregisteringStopsRepeatedMeasurements) {
}
TEST_F(ThermalResourceTest, RegisteringLateTriggersRepeatedMeasurements) {
- resource_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ resource_->OnThermalMeasurement(mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(
base::TimeDelta::FromMilliseconds(kReportIntervalMs));
EXPECT_EQ(0u, listener_.measurement_count());
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.cc b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.cc
index d1e63fac5a5..5bdc0787dd3 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.cc
@@ -10,8 +10,8 @@
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
-#include "base/power_monitor/power_observer.h"
#include "base/sequenced_task_runner.h"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
namespace blink {
@@ -27,16 +27,15 @@ enum class ThermalStateUMA {
kMaxValue = kCritical,
};
-ThermalStateUMA ToThermalStateUMA(
- base::PowerObserver::DeviceThermalState state) {
+ThermalStateUMA ToThermalStateUMA(mojom::blink::DeviceThermalState state) {
switch (state) {
- case base::PowerObserver::DeviceThermalState::kNominal:
+ case mojom::blink::DeviceThermalState::kNominal:
return ThermalStateUMA::kNominal;
- case base::PowerObserver::DeviceThermalState::kFair:
+ case mojom::blink::DeviceThermalState::kFair:
return ThermalStateUMA::kFair;
- case base::PowerObserver::DeviceThermalState::kSerious:
+ case mojom::blink::DeviceThermalState::kSerious:
return ThermalStateUMA::kSerious;
- case base::PowerObserver::DeviceThermalState::kCritical:
+ case mojom::blink::DeviceThermalState::kCritical:
return ThermalStateUMA::kCritical;
default:
NOTREACHED();
@@ -58,13 +57,13 @@ std::unique_ptr<ThermalUmaListener> ThermalUmaListener::Create(
ThermalUmaListener::ThermalUmaListener(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(std::move(task_runner)),
- current_thermal_state_(base::PowerObserver::DeviceThermalState::kUnknown),
+ current_thermal_state_(mojom::blink::DeviceThermalState::kUnknown),
weak_ptr_factor_(this) {
DCHECK(task_runner_);
}
void ThermalUmaListener::OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState measurement) {
+ mojom::blink::DeviceThermalState measurement) {
base::AutoLock crit(lock_);
current_thermal_state_ = measurement;
}
@@ -79,8 +78,7 @@ void ThermalUmaListener::ScheduleReport() {
void ThermalUmaListener::ReportStats() {
{
base::AutoLock crit(lock_);
- if (current_thermal_state_ !=
- base::PowerObserver::DeviceThermalState::kUnknown) {
+ if (current_thermal_state_ != mojom::blink::DeviceThermalState::kUnknown) {
UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.ThermalState",
ToThermalStateUMA(current_thermal_state_));
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h
index a4006a304ca..16e9fd6bcbd 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h
@@ -10,10 +10,10 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "base/power_monitor/power_observer.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -29,8 +29,7 @@ class MODULES_EXPORT ThermalUmaListener {
scoped_refptr<base::SequencedTaskRunner> task_runner);
~ThermalUmaListener() = default;
- void OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState measurement);
+ void OnThermalMeasurement(mojom::blink::DeviceThermalState measurement);
private:
void ReportStats();
@@ -38,8 +37,7 @@ class MODULES_EXPORT ThermalUmaListener {
base::Lock lock_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- base::PowerObserver::DeviceThermalState current_thermal_state_
- GUARDED_BY(&lock_);
+ mojom::blink::DeviceThermalState current_thermal_state_ GUARDED_BY(&lock_);
base::WeakPtrFactory<ThermalUmaListener> weak_ptr_factor_;
};
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener_test.cc
index 4e3bc30cfb2..aa144e98d3f 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_uma_listener_test.cc
@@ -4,10 +4,10 @@
#include <memory>
-#include "base/power_monitor/power_observer.h"
#include "base/test/metrics/histogram_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
#include "third_party/blink/renderer/modules/peerconnection/thermal_uma_listener.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
@@ -48,7 +48,7 @@ TEST_F(ThermalUmaListenerTest, NoMeasurementsHasNoHistograms) {
TEST_F(ThermalUmaListenerTest, HistogramAfterSignal) {
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kFair);
+ mojom::blink::DeviceThermalState::kFair);
task_runner_->FastForwardBy(kStatsReportingPeriod);
EXPECT_THAT(histogram_.GetAllSamples("WebRTC.PeerConnection.ThermalState"),
@@ -57,7 +57,7 @@ TEST_F(ThermalUmaListenerTest, HistogramAfterSignal) {
TEST_F(ThermalUmaListenerTest, DeletionCancelsListener) {
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kFair);
+ mojom::blink::DeviceThermalState::kFair);
task_runner_->FastForwardBy(2 * kStatsReportingPeriod);
EXPECT_THAT(histogram_.GetAllSamples("WebRTC.PeerConnection.ThermalState"),
testing::ElementsAre(Bucket(1, 2)));
@@ -70,10 +70,10 @@ TEST_F(ThermalUmaListenerTest, DeletionCancelsListener) {
TEST_F(ThermalUmaListenerTest, RecordsMostRecentState) {
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kFair);
+ mojom::blink::DeviceThermalState::kFair);
task_runner_->FastForwardBy(kStatsReportingPeriod / 2);
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(kStatsReportingPeriod / 2);
EXPECT_THAT(histogram_.GetAllSamples("WebRTC.PeerConnection.ThermalState"),
@@ -82,16 +82,16 @@ TEST_F(ThermalUmaListenerTest, RecordsMostRecentState) {
TEST_F(ThermalUmaListenerTest, HistogramBucketsIncludesPreviousPeriod) {
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kNominal);
+ mojom::blink::DeviceThermalState::kNominal);
task_runner_->FastForwardBy(kStatsReportingPeriod);
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kFair);
+ mojom::blink::DeviceThermalState::kFair);
task_runner_->FastForwardBy(kStatsReportingPeriod);
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kSerious);
+ mojom::blink::DeviceThermalState::kSerious);
task_runner_->FastForwardBy(kStatsReportingPeriod);
thermal_uma_listener_->OnThermalMeasurement(
- base::PowerObserver::DeviceThermalState::kCritical);
+ mojom::blink::DeviceThermalState::kCritical);
task_runner_->FastForwardBy(kStatsReportingPeriod);
EXPECT_THAT(histogram_.GetAllSamples("WebRTC.PeerConnection.ThermalState"),
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.cc b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.cc
index 254aa55d1e7..c139887b67f 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.cc
@@ -9,6 +9,18 @@
#include "third_party/webrtc/api/sctp_transport_interface.h"
namespace blink {
+namespace {
+
+Vector<webrtc::RtpHeaderExtensionCapability> GetHeaderExtensionsNegotiated(
+ const webrtc::RtpTransceiverInterface* webrtc_transceiver) {
+ auto std_extensions = webrtc_transceiver->HeaderExtensionsNegotiated();
+ Vector<webrtc::RtpHeaderExtensionCapability> extensions;
+ std::move(std_extensions.begin(), std_extensions.end(),
+ std::back_inserter(extensions));
+ return extensions;
+}
+
+} // namespace
TransceiverStateSurfacer::TransceiverStateSurfacer(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
@@ -112,14 +124,16 @@ void TransceiverStateSurfacer::Initialize(
main_task_runner_, signaling_task_runner_, webrtc_receiver.get(),
std::move(receiver_track_ref), std::move(receiver_stream_ids));
}
+
// Create the transceiver state.
- transceiver_states_.push_back(blink::RtpTransceiverState(
+ transceiver_states_.emplace_back(
main_task_runner_, signaling_task_runner_, webrtc_transceiver.get(),
std::move(sender_state), std::move(receiver_state),
blink::ToBaseOptional(webrtc_transceiver->mid()),
webrtc_transceiver->stopped(), webrtc_transceiver->direction(),
blink::ToBaseOptional(webrtc_transceiver->current_direction()),
- blink::ToBaseOptional(webrtc_transceiver->fired_direction())));
+ blink::ToBaseOptional(webrtc_transceiver->fired_direction()),
+ GetHeaderExtensionsNegotiated(webrtc_transceiver));
}
is_initialized_ = true;
}
@@ -147,7 +161,7 @@ SurfaceSenderStateOnly::SurfaceSenderStateOnly(
DCHECK(sender_);
}
-SurfaceSenderStateOnly::~SurfaceSenderStateOnly() {}
+SurfaceSenderStateOnly::~SurfaceSenderStateOnly() = default;
cricket::MediaType SurfaceSenderStateOnly::media_type() const {
return sender_->media_type();
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h
index 5ffde75e8be..0300f2cd57c 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer.h
@@ -51,7 +51,7 @@ class MODULES_EXPORT TransceiverStateSurfacer {
blink::WebRTCSctpTransportSnapshot SctpTransportSnapshot();
std::vector<blink::RtpTransceiverState> ObtainStates();
- protected:
+ private:
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_;
bool is_initialized_;
@@ -66,7 +66,8 @@ class MODULES_EXPORT TransceiverStateSurfacer {
class MODULES_EXPORT SurfaceSenderStateOnly
: public rtc::RefCountedObject<webrtc::RtpTransceiverInterface> {
public:
- SurfaceSenderStateOnly(rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
+ explicit SurfaceSenderStateOnly(
+ rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
~SurfaceSenderStateOnly() override;
cricket::MediaType media_type() const override;
@@ -90,7 +91,7 @@ class MODULES_EXPORT SurfaceSenderStateOnly
class MODULES_EXPORT SurfaceReceiverStateOnly
: public rtc::RefCountedObject<webrtc::RtpTransceiverInterface> {
public:
- SurfaceReceiverStateOnly(
+ explicit SurfaceReceiverStateOnly(
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
~SurfaceReceiverStateOnly() override;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer_test.cc
index adc1f716281..3fa8c413ea6 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/transceiver_state_surfacer_test.cc
@@ -50,8 +50,10 @@ class TransceiverStateSurfacerTest : public ::testing::Test {
dependency_factory_.get(), main_task_runner_);
surfacer_.reset(new TransceiverStateSurfacer(main_task_runner_,
signaling_task_runner()));
+ DummyExceptionStateForTesting exception_state;
peer_connection_ = dependency_factory_->CreatePeerConnection(
- webrtc::PeerConnectionInterface::RTCConfiguration(), nullptr, nullptr);
+ webrtc::PeerConnectionInterface::RTCConfiguration(), nullptr, nullptr,
+ exception_state);
EXPECT_CALL(
*(static_cast<blink::MockPeerConnectionImpl*>(peer_connection_.get())),
GetSctpTransport())
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 319046e8da5..38da10aced9 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
@@ -17,6 +17,7 @@
#include "media/base/mock_audio_renderer_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/audio/web_audio_device_source_type.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_renderer.h"
#include "third_party/blink/public/platform/platform.h"
@@ -34,6 +35,7 @@
#include "third_party/webrtc/api/media_stream_interface.h"
using testing::_;
+using testing::DoAll;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::SaveArg;
@@ -144,12 +146,12 @@ class MAYBE_WebRtcAudioRendererTest : public testing::Test {
/*opener=*/nullptr,
mojo::NullAssociatedReceiver(),
*agent_group_scheduler_)),
- web_local_frame_(blink::WebLocalFrame::CreateMainFrame(
- web_view_,
- &web_local_frame_client_,
- nullptr,
- base::UnguessableToken::Create(),
- /*policy_container=*/nullptr))
+ web_local_frame_(
+ blink::WebLocalFrame::CreateMainFrame(web_view_,
+ &web_local_frame_client_,
+ nullptr,
+ LocalFrameToken(),
+ /*policy_container=*/nullptr))
#endif
{
MediaStreamSourceVector dummy_components;
@@ -207,6 +209,7 @@ class MAYBE_WebRtcAudioRendererTest : public testing::Test {
}
void TearDown() override {
+ base::RunLoop().RunUntilIdle();
renderer_proxy_ = nullptr;
renderer_ = nullptr;
stream_descriptor_ = nullptr;
@@ -231,7 +234,7 @@ class MAYBE_WebRtcAudioRendererTest : public testing::Test {
};
// Verify that the renderer will be stopped if the only proxy is stopped.
-TEST_F(MAYBE_WebRtcAudioRendererTest, StopRenderer) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_StopRenderer) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
@@ -244,7 +247,7 @@ TEST_F(MAYBE_WebRtcAudioRendererTest, StopRenderer) {
// Verify that the renderer will not be stopped unless the last proxy is
// stopped.
-TEST_F(MAYBE_WebRtcAudioRendererTest, MultipleRenderers) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_MultipleRenderers) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
@@ -278,7 +281,7 @@ TEST_F(MAYBE_WebRtcAudioRendererTest, MultipleRenderers) {
// Verify that the sink of the renderer is using the expected sample rate and
// buffer size.
-TEST_F(MAYBE_WebRtcAudioRendererTest, VerifySinkParameters) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_VerifySinkParameters) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
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 77f65fb2915..99819240484 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
@@ -13,10 +13,7 @@ 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));
+ return description->Clone();
}
WebRtcSetDescriptionObserver::States::States()
diff --git a/chromium/third_party/blink/renderer/modules/permissions/BUILD.gn b/chromium/third_party/blink/renderer/modules/permissions/BUILD.gn
index a9afa01a814..2f90b5aeabf 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/permissions/BUILD.gn
@@ -6,15 +6,11 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("permissions") {
sources = [
- "navigator_permissions.cc",
- "navigator_permissions.h",
"permission_status.cc",
"permission_status.h",
"permission_utils.cc",
"permission_utils.h",
"permissions.cc",
"permissions.h",
- "worker_navigator_permissions.cc",
- "worker_navigator_permissions.h",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/permissions/DIR_METADATA b/chromium/third_party/blink/renderer/modules/permissions/DIR_METADATA
new file mode 100644
index 00000000000..0d36a0e38cb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/permissions/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>PermissionsAPI"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/permissions/OWNERS b/chromium/third_party/blink/renderer/modules/permissions/OWNERS
index e9ad8e97edf..2d282460822 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/permissions/OWNERS
@@ -1,3 +1 @@
mlamouri@chromium.org
-
-# COMPONENT: Blink>PermissionsAPI
diff --git a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.cc
deleted file mode 100644
index 7a400ad9db5..00000000000
--- a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/permissions/navigator_permissions.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/permissions/permissions.h"
-
-namespace blink {
-
-NavigatorPermissions::NavigatorPermissions() = default;
-
-// static
-const char NavigatorPermissions::kSupplementName[] = "NavigatorPermissions";
-
-// static
-NavigatorPermissions& NavigatorPermissions::From(Navigator& navigator) {
- NavigatorPermissions* supplement =
- Supplement<Navigator>::From<NavigatorPermissions>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorPermissions>();
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-Permissions* NavigatorPermissions::permissions(Navigator& navigator) {
- NavigatorPermissions& self = NavigatorPermissions::From(navigator);
- if (!self.permissions_) {
- self.permissions_ =
- MakeGarbageCollected<Permissions>(navigator.DomWindow());
- }
- return self.permissions_.Get();
-}
-
-void NavigatorPermissions::Trace(Visitor* visitor) const {
- visitor->Trace(permissions_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.h b/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.h
deleted file mode 100644
index 6163d67e2f1..00000000000
--- a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_NAVIGATOR_PERMISSIONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_NAVIGATOR_PERMISSIONS_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class Permissions;
-
-class NavigatorPermissions final
- : public GarbageCollected<NavigatorPermissions>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static NavigatorPermissions& From(Navigator&);
- static Permissions* permissions(Navigator&);
-
- NavigatorPermissions();
-
- void Trace(Visitor*) const override;
-
- private:
- Member<Permissions> permissions_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_NAVIGATOR_PERMISSIONS_H_
diff --git a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.idl b/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.idl
index 45c5e4fe8e7..97caa963b52 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.idl
+++ b/chromium/third_party/blink/renderer/modules/permissions/navigator_permissions.idl
@@ -7,7 +7,7 @@
[
Exposed=(Window),
- ImplementedAs=NavigatorPermissions,
+ ImplementedAs=Permissions,
RuntimeEnabled=Permissions
] partial interface Navigator {
readonly attribute Permissions permissions;
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
index ee54fab2167..80707769faa 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl
@@ -23,6 +23,7 @@ enum PermissionName {
// "clipboard",
"screen-wake-lock",
"nfc",
+ "display-capture",
// Non-standard:
"accessibility-events",
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_utils.cc b/chromium/third_party/blink/renderer/modules/permissions/permission_utils.cc
index fc7140919ac..a44a6d6d1bb 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permission_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/permissions/permission_utils.cc
@@ -115,12 +115,8 @@ PermissionDescriptorPtr ParsePermissionDescriptor(
if (exception_state.HadException())
return nullptr;
- if (RuntimeEnabledFeatures::MediaCapturePanTiltEnabled()) {
- return CreateVideoCapturePermissionDescriptor(
- camera_device_permission->panTiltZoom());
- }
-
- return CreateVideoCapturePermissionDescriptor(false /* pan_tilt_zoom */);
+ return CreateVideoCapturePermissionDescriptor(
+ camera_device_permission->panTiltZoom());
}
if (name == "microphone")
return CreatePermissionDescriptor(PermissionName::AUDIO_CAPTURE);
@@ -244,6 +240,14 @@ PermissionDescriptorPtr ParsePermissionDescriptor(
}
return CreatePermissionDescriptor(PermissionName::FONT_ACCESS);
}
+ if (name == "display-capture") {
+ if (!RuntimeEnabledFeatures::DisplayCapturePermissionPolicyEnabled(
+ ExecutionContext::From(script_state))) {
+ exception_state.ThrowTypeError("Display Capture is not enabled.");
+ return nullptr;
+ }
+ return CreatePermissionDescriptor(PermissionName::DISPLAY_CAPTURE);
+ }
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
index 3b190d73000..c3f63e7f280 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
+++ b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_permission_descriptor.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/execution_context/navigator_base.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"
@@ -31,8 +32,23 @@ using mojom::blink::PermissionDescriptorPtr;
using mojom::blink::PermissionName;
using mojom::blink::PermissionService;
-Permissions::Permissions(ExecutionContext* execution_context)
- : service_(execution_context) {}
+// static
+const char Permissions::kSupplementName[] = "Permissions";
+
+// static
+Permissions* Permissions::permissions(NavigatorBase& navigator) {
+ Permissions* supplement =
+ Supplement<NavigatorBase>::From<Permissions>(navigator);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<Permissions>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+Permissions::Permissions(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ service_(navigator.GetExecutionContext()) {}
ScriptPromise Permissions::query(ScriptState* script_state,
const ScriptValue& raw_permission,
@@ -51,10 +67,10 @@ ScriptPromise Permissions::query(ScriptState* script_state,
// likely be "prompt".
PermissionDescriptorPtr descriptor_copy = descriptor->Clone();
GetService(ExecutionContext::From(script_state))
- ->HasPermission(std::move(descriptor),
- WTF::Bind(&Permissions::TaskComplete,
- WrapPersistent(this), WrapPersistent(resolver),
- WTF::Passed(std::move(descriptor_copy))));
+ ->HasPermission(
+ std::move(descriptor),
+ WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
+ WrapPersistent(resolver), std::move(descriptor_copy)));
return promise;
}
@@ -77,8 +93,7 @@ ScriptPromise Permissions::request(ScriptState* script_state,
GetService(context)->RequestPermission(
std::move(descriptor), LocalFrame::HasTransientUserActivation(frame),
WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
- WrapPersistent(resolver),
- WTF::Passed(std::move(descriptor_copy))));
+ WrapPersistent(resolver), std::move(descriptor_copy)));
return promise;
}
@@ -98,8 +113,7 @@ ScriptPromise Permissions::revoke(ScriptState* script_state,
->RevokePermission(
std::move(descriptor),
WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this),
- WrapPersistent(resolver),
- WTF::Passed(std::move(descriptor_copy))));
+ WrapPersistent(resolver), std::move(descriptor_copy)));
return promise;
}
@@ -150,15 +164,15 @@ ScriptPromise Permissions::requestAll(
std::move(internal_permissions),
LocalFrame::HasTransientUserActivation(frame),
WTF::Bind(&Permissions::BatchTaskComplete, WrapPersistent(this),
- WrapPersistent(resolver),
- WTF::Passed(std::move(internal_permissions_copy)),
- WTF::Passed(std::move(caller_index_to_internal_index))));
+ WrapPersistent(resolver), std::move(internal_permissions_copy),
+ std::move(caller_index_to_internal_index)));
return promise;
}
void Permissions::Trace(Visitor* visitor) const {
visitor->Trace(service_);
ScriptWrappable::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
}
PermissionService* Permissions::GetService(
diff --git a/chromium/third_party/blink/renderer/modules/permissions/permissions.h b/chromium/third_party/blink/renderer/modules/permissions/permissions.h
index 8f501d972b3..f59c1267772 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/permissions.h
+++ b/chromium/third_party/blink/renderer/modules/permissions/permissions.h
@@ -12,19 +12,28 @@
#include "third_party/blink/renderer/platform/heap/handle.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 ExecutionContext;
+class NavigatorBase;
class ScriptPromiseResolver;
class ScriptState;
class ScriptValue;
-class Permissions final : public ScriptWrappable {
+class Permissions final : public ScriptWrappable,
+ public Supplement<NavigatorBase> {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit Permissions(ExecutionContext* execution_context);
+ static const char kSupplementName[];
+
+ // Getter for navigator.permissions
+ static Permissions* permissions(NavigatorBase&);
+
+ explicit Permissions(NavigatorBase&);
+
ScriptPromise query(ScriptState*, const ScriptValue&, ExceptionState&);
ScriptPromise request(ScriptState*, const ScriptValue&, ExceptionState&);
ScriptPromise revoke(ScriptState*, const ScriptValue&, ExceptionState&);
diff --git a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.cc
deleted file mode 100644
index bfcfb2f6617..00000000000
--- a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/permissions/worker_navigator_permissions.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/permissions/permissions.h"
-
-namespace blink {
-
-WorkerNavigatorPermissions::WorkerNavigatorPermissions() = default;
-
-// static
-const char WorkerNavigatorPermissions::kSupplementName[] =
- "WorkerNavigatorPermissions";
-
-// static
-WorkerNavigatorPermissions& WorkerNavigatorPermissions::From(
- WorkerNavigator& worker_navigator) {
- WorkerNavigatorPermissions* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorPermissions>(
- worker_navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorPermissions>();
- ProvideTo(worker_navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-Permissions* WorkerNavigatorPermissions::permissions(
- WorkerNavigator& worker_navigator) {
- WorkerNavigatorPermissions& self =
- WorkerNavigatorPermissions::From(worker_navigator);
- if (!self.permissions_) {
- self.permissions_ =
- MakeGarbageCollected<Permissions>(worker_navigator.DomWindow());
- }
- return self.permissions_;
-}
-
-void WorkerNavigatorPermissions::Trace(Visitor* visitor) const {
- visitor->Trace(permissions_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.h b/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.h
deleted file mode 100644
index 4c366cd5dc7..00000000000
--- a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_WORKER_NAVIGATOR_PERMISSIONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_WORKER_NAVIGATOR_PERMISSIONS_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class WorkerNavigator;
-class Permissions;
-
-class WorkerNavigatorPermissions final
- : public GarbageCollected<WorkerNavigatorPermissions>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static WorkerNavigatorPermissions& From(WorkerNavigator&);
- static Permissions* permissions(WorkerNavigator&);
-
- WorkerNavigatorPermissions();
-
- void Trace(Visitor*) const override;
-
- private:
- Member<Permissions> permissions_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PERMISSIONS_WORKER_NAVIGATOR_PERMISSIONS_H_
diff --git a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.idl b/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.idl
index f73ad6bb7d1..7c815ab21e1 100644
--- a/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.idl
+++ b/chromium/third_party/blink/renderer/modules/permissions/worker_navigator_permissions.idl
@@ -7,7 +7,7 @@
[
Exposed=(Worker),
- ImplementedAs=WorkerNavigatorPermissions,
+ ImplementedAs=Permissions,
RuntimeEnabled=Permissions
] partial interface WorkerNavigator {
readonly attribute Permissions permissions;
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/DEPS b/chromium/third_party/blink/renderer/modules/picture_in_picture/DEPS
index 9b854a43d60..bd845827e7c 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/DEPS
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+media/mojo/mojom/media_player.mojom-blink.h",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_modules.h",
"+third_party/blink/renderer/modules/event_target_modules.h",
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA b/chromium/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA
new file mode 100644
index 00000000000..c6851fa12c5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>PictureInPicture"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/OWNERS b/chromium/third_party/blink/renderer/modules/picture_in_picture/OWNERS
index b6c67ebc706..e0e44ab2e42 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/OWNERS
@@ -1,5 +1,2 @@
beaufort.francois@gmail.com
mlamouri@chromium.org
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media>PictureInPicture
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
index 25b0a7776a1..e1899516c29 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
@@ -26,7 +26,7 @@ const char kMetadataNotLoadedError[] =
const char kVideoTrackNotAvailableError[] =
"The video element has no video track.";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"picture-in-picture\" is disallowed by feature "
+ "Access to the feature \"picture-in-picture\" is disallowed by permissions "
"policy.";
const char kNotAvailable[] = "Picture-in-Picture is not available.";
const char kUserGestureRequired[] =
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 4fdfc81c138..6b1da5be03b 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
@@ -8,6 +8,7 @@
#include <utility>
#include "base/callback_helpers.h"
+#include "media/mojo/mojom/media_player.mojom-blink.h"
#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/media/display_type.h"
@@ -177,8 +178,14 @@ void PictureInPictureControllerImpl::EnterPictureInPicture(
session_observer_receiver_.Bind(
session_observer.InitWithNewPipeAndPassReceiver(), task_runner);
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>
+ media_player_remote;
+ video_element->BindMediaPlayerReceiver(
+ media_player_remote.InitWithNewEndpointAndPassReceiver());
+
picture_in_picture_service_->StartSession(
video_element->GetWebMediaPlayer()->GetDelegateId(),
+ std::move(media_player_remote),
video_element->GetWebMediaPlayer()->GetSurfaceId(),
video_element->GetWebMediaPlayer()->NaturalSize(),
ShouldShowPlayPauseButton(*video_element), std::move(session_observer),
diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
index d7ac0aafade..2b23396c20d 100644
--- a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
+++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h"
+#include "media/mojo/mojom/media_player.mojom-blink.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -62,7 +64,7 @@ class MockPictureInPictureService
public:
MockPictureInPictureService() {
// Setup default implementations.
- ON_CALL(*this, StartSession(_, _, _, _, _, _))
+ ON_CALL(*this, StartSession(_, _, _, _, _, _, _))
.WillByDefault(testing::Invoke(
this, &MockPictureInPictureService::StartSessionInternal));
}
@@ -76,9 +78,10 @@ class MockPictureInPictureService
session_remote_.InitWithNewPipeAndPassReceiver()));
}
- MOCK_METHOD6(
+ MOCK_METHOD7(
StartSession,
void(uint32_t,
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>,
const base::Optional<viz::SurfaceId>&,
const gfx::Size&,
bool,
@@ -89,6 +92,7 @@ class MockPictureInPictureService
void StartSessionInternal(
uint32_t,
+ mojo::PendingAssociatedRemote<media::mojom::blink::MediaPlayer>,
const base::Optional<viz::SurfaceId>&,
const gfx::Size&,
bool,
@@ -195,7 +199,7 @@ TEST_F(PictureInPictureControllerTest, EnterPictureInPictureFiresEvent) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), true, _, _));
PictureInPictureControllerImpl::From(GetDocument())
@@ -215,7 +219,7 @@ TEST_F(PictureInPictureControllerTest, ExitPictureInPictureFiresEvent) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), true, _, _));
PictureInPictureControllerImpl::From(GetDocument())
@@ -243,7 +247,7 @@ TEST_F(PictureInPictureControllerTest, StartObserving) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), true, _, _));
PictureInPictureControllerImpl::From(GetDocument())
@@ -263,7 +267,7 @@ TEST_F(PictureInPictureControllerTest, StopObserving) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), true, _, _));
PictureInPictureControllerImpl::From(GetDocument())
@@ -292,7 +296,7 @@ TEST_F(PictureInPictureControllerTest, PlayPauseButton_InfiniteDuration) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), false, _, _));
PictureInPictureControllerImpl::From(GetDocument())
@@ -312,7 +316,7 @@ TEST_F(PictureInPictureControllerTest, PlayPauseButton_MediaSource) {
WebMediaPlayer* player = Video()->GetWebMediaPlayer();
EXPECT_CALL(Service(),
- StartSession(player->GetDelegateId(), player->GetSurfaceId(),
+ StartSession(player->GetDelegateId(), _, player->GetSurfaceId(),
player->NaturalSize(), false, _, _));
PictureInPictureControllerImpl::From(GetDocument())
diff --git a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type.cc b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
index 10de41064f1..724d00cf477 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
+++ b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
@@ -65,8 +65,7 @@ DOMPlugin* DOMMimeType::enabledPlugin() const {
// FIXME: allowPlugins is just a client call. We should not need
// to bounce through the loader to get there.
// Something like: frame()->page()->client()->allowPlugins().
- if (!DomWindow() || !DomWindow()->GetFrame()->Loader().AllowPlugins(
- kNotAboutToInstantiatePlugin)) {
+ if (!DomWindow() || !DomWindow()->GetFrame()->Loader().AllowPlugins()) {
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
index d0c5758f264..4bb886485c7 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
+++ b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
@@ -20,8 +20,10 @@
#include "third_party/blink/renderer/modules/plugins/dom_mime_type_array.h"
+#include "third_party/blink/public/common/features.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/settings.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/plugin_data.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
@@ -56,7 +58,26 @@ DOMMimeType* DOMMimeTypeArray::item(unsigned index) {
return dom_mime_types_[index];
}
+bool DOMMimeTypeArray::ShouldReturnEmptyPluginData(Frame* frame) {
+ // See https://crbug.com/1171373 for more context. P/Nacl plugins will
+ // be supported on some platforms through at least June, 2022. Since
+ // some apps need to use feature detection, we need to continue returning
+ // plugin data for those.
+ if (frame && frame->GetSettings()->GetAllowNonEmptyNavigatorPlugins())
+ return false;
+ // Otherwise, depend on the feature flag, which can be disabled via
+ // Finch killswitch.
+ return base::FeatureList::IsEnabled(features::kNavigatorPluginsEmpty);
+}
+
+bool DOMMimeTypeArray::ShouldReturnEmptyPluginData() const {
+ return ShouldReturnEmptyPluginData(DomWindow() ? DomWindow()->GetFrame()
+ : nullptr);
+}
+
DOMMimeType* DOMMimeTypeArray::namedItem(const AtomicString& property_name) {
+ if (ShouldReturnEmptyPluginData())
+ return nullptr;
PluginData* data = GetPluginData();
if (!data)
return nullptr;
@@ -72,6 +93,8 @@ DOMMimeType* DOMMimeTypeArray::namedItem(const AtomicString& property_name) {
void DOMMimeTypeArray::NamedPropertyEnumerator(Vector<String>& property_names,
ExceptionState&) const {
+ if (ShouldReturnEmptyPluginData())
+ return;
PluginData* data = GetPluginData();
if (!data)
return;
@@ -96,6 +119,10 @@ PluginData* DOMMimeTypeArray::GetPluginData() const {
}
void DOMMimeTypeArray::UpdatePluginData() {
+ if (ShouldReturnEmptyPluginData()) {
+ dom_mime_types_.clear();
+ return;
+ }
PluginData* data = GetPluginData();
if (!data) {
dom_mime_types_.clear();
diff --git a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.h b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.h
index d8b01e5a5aa..eef7213b05b 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.h
+++ b/chromium/third_party/blink/renderer/modules/plugins/dom_mime_type_array.h
@@ -31,6 +31,7 @@
namespace blink {
class ExceptionState;
+class Frame;
class LocalDOMWindow;
class PluginData;
@@ -50,6 +51,8 @@ class DOMMimeTypeArray final : public ScriptWrappable,
void NamedPropertyEnumerator(Vector<String>&, ExceptionState&) const;
bool NamedPropertyQuery(const AtomicString&, ExceptionState&) const;
+ static bool ShouldReturnEmptyPluginData(Frame*);
+
// PluginsChangedObserver implementation.
void PluginsChanged() override;
@@ -59,6 +62,8 @@ class DOMMimeTypeArray final : public ScriptWrappable,
PluginData* GetPluginData() const;
void ContextDestroyed() override;
+ bool ShouldReturnEmptyPluginData() const;
+
HeapVector<Member<DOMMimeType>> dom_mime_types_;
};
diff --git a/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc b/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
index 275160e244c..53c24628f1d 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
+++ b/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/modules/plugins/dom_plugin_array.h"
+#include "third_party/blink/public/common/features.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"
@@ -62,7 +63,14 @@ DOMPlugin* DOMPluginArray::item(unsigned index) {
return dom_plugins_[index];
}
+bool DOMPluginArray::ShouldReturnEmptyPluginData() const {
+ return DOMMimeTypeArray::ShouldReturnEmptyPluginData(
+ DomWindow() ? DomWindow()->GetFrame() : nullptr);
+}
+
DOMPlugin* DOMPluginArray::namedItem(const AtomicString& property_name) {
+ if (ShouldReturnEmptyPluginData())
+ return nullptr;
PluginData* data = GetPluginData();
if (!data)
return nullptr;
@@ -79,6 +87,8 @@ DOMPlugin* DOMPluginArray::namedItem(const AtomicString& property_name) {
void DOMPluginArray::NamedPropertyEnumerator(Vector<String>& property_names,
ExceptionState&) const {
+ if (ShouldReturnEmptyPluginData())
+ return;
PluginData* data = GetPluginData();
if (!data)
return;
@@ -96,6 +106,8 @@ bool DOMPluginArray::NamedPropertyQuery(const AtomicString& property_name,
}
void DOMPluginArray::refresh(bool reload) {
+ if (ShouldReturnEmptyPluginData())
+ return;
if (!DomWindow())
return;
@@ -122,6 +134,10 @@ PluginData* DOMPluginArray::GetPluginData() const {
}
void DOMPluginArray::UpdatePluginData() {
+ if (ShouldReturnEmptyPluginData()) {
+ dom_plugins_.clear();
+ return;
+ }
PluginData* data = GetPluginData();
if (!data) {
dom_plugins_.clear();
diff --git a/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.h b/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.h
index c1f31afb19f..32c2ae804a4 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.h
+++ b/chromium/third_party/blink/renderer/modules/plugins/dom_plugin_array.h
@@ -61,6 +61,8 @@ class DOMPluginArray final : public ScriptWrappable,
PluginData* GetPluginData() const;
void ContextDestroyed() override;
+ bool ShouldReturnEmptyPluginData() const;
+
HeapVector<Member<DOMPlugin>> dom_plugins_;
};
diff --git a/chromium/third_party/blink/renderer/modules/presentation/DIR_METADATA b/chromium/third_party/blink/renderer/modules/presentation/DIR_METADATA
new file mode 100644
index 00000000000..8c61a5f953c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/presentation/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>PresentationAPI"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/presentation/OWNERS b/chromium/third_party/blink/renderer/modules/presentation/OWNERS
index 60162ad0a3b..1ec6273e47c 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/presentation/OWNERS
@@ -1,8 +1,2 @@
mfoltz@chromium.org
mlamouri@chromium.org
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>PresentationAPI
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation.cc
index fdb9eea82cd..e8e6238c98f 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation.cc
@@ -63,7 +63,7 @@ void Presentation::setDefaultRequest(PresentationRequest* request) {
void Presentation::MaybeInitReceiver() {
LocalDOMWindow* window = GetSupplementable()->DomWindow();
- if (!receiver_ && window &&
+ if (!receiver_ && window && window->GetFrame()->IsMainFrame() &&
window->GetFrame()->GetSettings()->GetPresentationReceiver()) {
receiver_ = MakeGarbageCollected<PresentationReceiver>(window);
}
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
index 8f8834ae9f7..3ac62c0e613 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc
@@ -477,7 +477,7 @@ void PresentationConnection::send(
DCHECK(array_buffer_view);
if (!CanSendMessage(exception_state))
return;
- if (!base::CheckedNumeric<wtf_size_t>(array_buffer_view.View()->byteLength())
+ if (!base::CheckedNumeric<wtf_size_t>(array_buffer_view->byteLength())
.IsValid()) {
static_assert(
4294967295 == std::numeric_limits<wtf_size_t>::max(),
@@ -488,7 +488,7 @@ void PresentationConnection::send(
}
messages_.push_back(
- MakeGarbageCollected<Message>(array_buffer_view.View()->buffer()));
+ MakeGarbageCollected<Message>(array_buffer_view->buffer()));
HandleMessageQueue();
}
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_available_event.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_available_event.h
index 1b1393d32d6..aff4b23e797 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_available_event.h
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_available_event.h
@@ -50,15 +50,6 @@ class PresentationConnectionAvailableEvent final : public Event {
Member<PresentationConnection> connection_;
};
-DEFINE_TYPE_CASTS(
- PresentationConnectionAvailableEvent,
- Event,
- event,
- event->InterfaceName() ==
- event_interface_names::kPresentationConnectionAvailableEvent,
- event.InterfaceName() ==
- event_interface_names::kPresentationConnectionAvailableEvent);
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONNECTION_AVAILABLE_EVENT_H_
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
index 3f3f49c4e50..5ead7a17cc2 100644
--- 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
@@ -8,21 +8,15 @@
#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/core/testing/mock_function_scope.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";
@@ -39,49 +33,6 @@ 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(),
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
index cbaf735645b..e4249002939 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
@@ -20,6 +20,7 @@ PresentationReceiver::PresentationReceiver(LocalDOMWindow* window)
presentation_receiver_receiver_(this, window),
presentation_service_remote_(window),
window_(window) {
+ DCHECK(window_->GetFrame()->IsMainFrame());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
window->GetTaskRunner(TaskType::kPresentation);
window->GetBrowserInterfaceBroker().GetInterface(
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/DIR_METADATA b/chromium/third_party/blink/renderer/modules/push_messaging/DIR_METADATA
new file mode 100644
index 00000000000..ee3c1ea06ba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>PushAPI"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/OWNERS b/chromium/third_party/blink/renderer/modules/push_messaging/OWNERS
index 2c516368c09..7b47e3bd568 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/OWNERS
@@ -5,6 +5,3 @@ file://content/browser/push_messaging/OWNERS
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>PushAPI
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_event.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_event.cc
index cb8b60bcfd0..e400b35c413 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_event.cc
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_event.cc
@@ -24,7 +24,7 @@ PushEvent::PushEvent(const AtomicString& type,
if (message_data.IsArrayBuffer() || message_data.IsArrayBufferView()) {
DOMArrayBuffer* buffer =
message_data.IsArrayBufferView()
- ? message_data.GetAsArrayBufferView().View()->buffer()
+ ? message_data.GetAsArrayBufferView()->buffer()
: message_data.GetAsArrayBuffer();
if (!base::CheckedNumeric<uint32_t>(buffer->ByteLength()).IsValid()) {
exception_state.ThrowRangeError(
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc
index a726668f26a..9819c86ae4b 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc
@@ -33,10 +33,9 @@ PushMessageData* PushMessageData::Create(const String& message_string) {
PushMessageData* PushMessageData::Create(
const ArrayBufferOrArrayBufferViewOrUSVString& message_data) {
if (message_data.IsArrayBuffer() || message_data.IsArrayBufferView()) {
- DOMArrayBuffer* buffer =
- message_data.IsArrayBufferView()
- ? message_data.GetAsArrayBufferView().View()->buffer()
- : message_data.GetAsArrayBuffer();
+ DOMArrayBuffer* buffer = message_data.IsArrayBufferView()
+ ? message_data.GetAsArrayBufferView()->buffer()
+ : message_data.GetAsArrayBuffer();
return MakeGarbageCollected<PushMessageData>(
static_cast<const char*>(buffer->Data()),
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_provider.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_provider.cc
index 5e5dc5f97bc..51153fea7df 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_provider.cc
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_provider.cc
@@ -6,9 +6,11 @@
#include <utility>
+#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/mojom/push_messaging/push_messaging_status.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/push_messaging/push_error.h"
#include "third_party/blink/renderer/modules/push_messaging/push_messaging_utils.h"
#include "third_party/blink/renderer/modules/push_messaging/push_subscription.h"
@@ -45,8 +47,10 @@ PushProvider* PushProvider::From(ServiceWorkerRegistration* registration) {
// static
mojom::blink::PushMessaging* PushProvider::GetPushMessagingRemote() {
if (!push_messaging_manager_.is_bound()) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- push_messaging_manager_.BindNewPipeAndPassReceiver(
+ GetSupplementable()
+ ->GetExecutionContext()
+ ->GetBrowserInterfaceBroker()
+ .GetInterface(push_messaging_manager_.BindNewPipeAndPassReceiver(
GetSupplementable()->GetExecutionContext()->GetTaskRunner(
TaskType::kMiscPlatformAPI)));
}
@@ -67,7 +71,7 @@ void PushProvider::Subscribe(
GetSupplementable()->RegistrationId(), std::move(content_options_ptr),
user_gesture,
WTF::Bind(&PushProvider::DidSubscribe, WrapPersistent(this),
- WTF::Passed(std::move(callbacks))));
+ std::move(callbacks)));
}
void PushProvider::DidSubscribe(
@@ -99,7 +103,7 @@ void PushProvider::Unsubscribe(
GetPushMessagingRemote()->Unsubscribe(
GetSupplementable()->RegistrationId(),
WTF::Bind(&PushProvider::DidUnsubscribe, WrapPersistent(this),
- WTF::Passed(std::move(callbacks))));
+ std::move(callbacks)));
}
void PushProvider::DidUnsubscribe(
@@ -124,7 +128,7 @@ void PushProvider::GetSubscription(
GetPushMessagingRemote()->GetSubscription(
GetSupplementable()->RegistrationId(),
WTF::Bind(&PushProvider::DidGetSubscription, WrapPersistent(this),
- WTF::Passed(std::move(callbacks))));
+ std::move(callbacks)));
}
void PushProvider::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
index 1e73260079f..ffb0a1eea04 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
@@ -34,11 +34,8 @@ Vector<uint8_t> BufferSourceToVector(
length = application_server_key.GetAsArrayBuffer()->ByteLength();
} else if (application_server_key.IsArrayBufferView()) {
input = static_cast<char*>(
- application_server_key.GetAsArrayBufferView().View()->buffer()->Data());
- length = application_server_key.GetAsArrayBufferView()
- .View()
- ->buffer()
- ->ByteLength();
+ application_server_key.GetAsArrayBufferView()->BaseAddress());
+ length = application_server_key.GetAsArrayBufferView()->byteLength();
} else if (application_server_key.IsString()) {
if (!Base64UnpaddedURLDecode(application_server_key.GetAsString(),
decoded_application_server_key)) {
diff --git a/chromium/third_party/blink/renderer/modules/quota/BUILD.gn b/chromium/third_party/blink/renderer/modules/quota/BUILD.gn
index f4bc0a0b33f..388a9ee3679 100644
--- a/chromium/third_party/blink/renderer/modules/quota/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/quota/BUILD.gn
@@ -20,8 +20,6 @@ blink_modules_sources("quota") {
"quota_utils.h",
"storage_manager.cc",
"storage_manager.h",
- "worker_navigator_storage_quota.cc",
- "worker_navigator_storage_quota.h",
]
deps = [ "//third_party/blink/renderer/modules/permissions" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/quota/DIR_METADATA b/chromium/third_party/blink/renderer/modules/quota/DIR_METADATA
new file mode 100644
index 00000000000..d01bdb5cf86
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/quota/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>Quota"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/quota/OWNERS b/chromium/third_party/blink/renderer/modules/quota/OWNERS
index 84d5cb66e1c..a61a7147e9a 100644
--- a/chromium/third_party/blink/renderer/modules/quota/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/quota/OWNERS
@@ -1,4 +1 @@
file://storage/browser/quota/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>Quota
diff --git a/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc b/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
index fbbe9cb8059..5a66552e6f9 100644
--- a/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
+++ b/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
@@ -38,14 +38,14 @@
namespace blink {
-NavigatorStorageQuota::NavigatorStorageQuota(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
+NavigatorStorageQuota::NavigatorStorageQuota(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator) {}
const char NavigatorStorageQuota::kSupplementName[] = "NavigatorStorageQuota";
-NavigatorStorageQuota& NavigatorStorageQuota::From(Navigator& navigator) {
+NavigatorStorageQuota& NavigatorStorageQuota::From(NavigatorBase& navigator) {
NavigatorStorageQuota* supplement =
- Supplement<Navigator>::From<NavigatorStorageQuota>(navigator);
+ Supplement<NavigatorBase>::From<NavigatorStorageQuota>(navigator);
if (!supplement) {
supplement = MakeGarbageCollected<NavigatorStorageQuota>(navigator);
ProvideTo(navigator, supplement);
@@ -55,59 +55,40 @@ NavigatorStorageQuota& NavigatorStorageQuota::From(Navigator& navigator) {
DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage(
Navigator& navigator) {
- return NavigatorStorageQuota::From(navigator).webkitTemporaryStorage();
+ NavigatorStorageQuota& navigator_storage = From(navigator);
+ if (!navigator_storage.temporary_storage_) {
+ navigator_storage.temporary_storage_ =
+ MakeGarbageCollected<DeprecatedStorageQuota>(
+ DeprecatedStorageQuota::kTemporary, navigator.DomWindow());
+ }
+ return navigator_storage.temporary_storage_.Get();
}
DeprecatedStorageQuota* NavigatorStorageQuota::webkitPersistentStorage(
Navigator& navigator) {
- return NavigatorStorageQuota::From(navigator).webkitPersistentStorage();
-}
-
-StorageManager* NavigatorStorageQuota::storage(Navigator& navigator) {
- return NavigatorStorageQuota::From(navigator).storage();
-}
-
-DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage() const {
- if (!temporary_storage_) {
- temporary_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
- DeprecatedStorageQuota::kTemporary, GetSupplementable()->DomWindow());
+ NavigatorStorageQuota& navigator_storage = From(navigator);
+ if (!navigator_storage.persistent_storage_) {
+ navigator_storage.persistent_storage_ =
+ MakeGarbageCollected<DeprecatedStorageQuota>(
+ DeprecatedStorageQuota::kPersistent, navigator.DomWindow());
}
- return temporary_storage_.Get();
+ return navigator_storage.persistent_storage_.Get();
}
-DeprecatedStorageQuota* NavigatorStorageQuota::webkitPersistentStorage() const {
- if (!persistent_storage_) {
- persistent_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
- DeprecatedStorageQuota::kPersistent, GetSupplementable()->DomWindow());
- }
- return persistent_storage_.Get();
-}
-
-StorageManager* NavigatorStorageQuota::storage() const {
- if (!storage_manager_) {
- mojo::Remote<mojom::blink::QuotaManagerHost> backend;
-
- auto* supplementable = GetSupplementable();
- auto* execution_context =
- supplementable ? supplementable->GetExecutionContext() : nullptr;
- if (execution_context) {
- if (&execution_context->GetBrowserInterfaceBroker() !=
- &GetEmptyBrowserInterfaceBroker()) {
- execution_context->GetBrowserInterfaceBroker().GetInterface(
- backend.BindNewPipeAndPassReceiver());
- }
- }
- storage_manager_ = MakeGarbageCollected<StorageManager>(execution_context,
- std::move(backend));
+StorageManager* NavigatorStorageQuota::storage(NavigatorBase& navigator) {
+ NavigatorStorageQuota& navigator_storage = From(navigator);
+ if (!navigator_storage.storage_manager_) {
+ navigator_storage.storage_manager_ =
+ MakeGarbageCollected<StorageManager>(navigator.GetExecutionContext());
}
- return storage_manager_.Get();
+ return navigator_storage.storage_manager_.Get();
}
void NavigatorStorageQuota::Trace(Visitor* visitor) const {
visitor->Trace(temporary_storage_);
visitor->Trace(persistent_storage_);
visitor->Trace(storage_manager_);
- Supplement<Navigator>::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.h b/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
index 21324f1b200..6693abd4468 100644
--- a/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
+++ b/chromium/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
@@ -31,7 +31,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_NAVIGATOR_STORAGE_QUOTA_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_NAVIGATOR_STORAGE_QUOTA_H_
-#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -39,28 +38,29 @@
namespace blink {
class Navigator;
+class NavigatorBase;
class StorageManager;
class NavigatorStorageQuota final
: public GarbageCollected<NavigatorStorageQuota>,
- public Supplement<Navigator> {
+ public Supplement<NavigatorBase> {
public:
static const char kSupplementName[];
- static NavigatorStorageQuota& From(Navigator&);
+ // Web-exposed on window only.
static DeprecatedStorageQuota* webkitTemporaryStorage(Navigator&);
static DeprecatedStorageQuota* webkitPersistentStorage(Navigator&);
- static StorageManager* storage(Navigator&);
- DeprecatedStorageQuota* webkitTemporaryStorage() const;
- DeprecatedStorageQuota* webkitPersistentStorage() const;
- StorageManager* storage() const;
+ // Web-exposed on both window and worker.
+ static StorageManager* storage(NavigatorBase&);
- explicit NavigatorStorageQuota(Navigator&);
+ explicit NavigatorStorageQuota(NavigatorBase&);
void Trace(Visitor*) const override;
private:
+ static NavigatorStorageQuota& From(NavigatorBase&);
+
mutable Member<DeprecatedStorageQuota> temporary_storage_;
mutable Member<DeprecatedStorageQuota> persistent_storage_;
mutable Member<StorageManager> storage_manager_;
diff --git a/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc b/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc
index c1f055e12d9..1a9533b91fb 100644
--- a/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc
@@ -85,9 +85,7 @@ void QueryStorageUsageAndQuotaCallback(
} // namespace
-StorageManager::StorageManager(
- ExecutionContext* execution_context,
- mojo::Remote<mojom::blink::QuotaManagerHost> backend)
+StorageManager::StorageManager(ExecutionContext* execution_context)
: ExecutionContextClient(execution_context),
permission_service_(execution_context),
quota_host_(execution_context),
@@ -238,7 +236,7 @@ void StorageManager::PermissionRequestComplete(ScriptPromiseResolver* resolver,
}
void StorageManager::StartObserving() {
- if (change_listener_receiver_.is_bound())
+ if (change_listener_receiver_.is_bound() || !quota_host_.is_bound())
return;
ExecutionContext* execution_context = GetExecutionContext();
diff --git a/chromium/third_party/blink/renderer/modules/quota/storage_manager.h b/chromium/third_party/blink/renderer/modules/quota/storage_manager.h
index 51a7fc76801..b0c02c1cc13 100644
--- a/chromium/third_party/blink/renderer/modules/quota/storage_manager.h
+++ b/chromium/third_party/blink/renderer/modules/quota/storage_manager.h
@@ -29,8 +29,7 @@ class StorageManager final : public EventTargetWithInlineData,
DEFINE_WRAPPERTYPEINFO();
public:
- explicit StorageManager(ExecutionContext*,
- mojo::Remote<mojom::blink::QuotaManagerHost> backend);
+ explicit StorageManager(ExecutionContext*);
~StorageManager() override;
ScriptPromise persisted(ScriptState*);
diff --git a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc b/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc
deleted file mode 100644
index 1c6bf14e631..00000000000
--- a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h"
-
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h"
-#include "third_party/blink/renderer/modules/quota/storage_manager.h"
-
-namespace blink {
-
-WorkerNavigatorStorageQuota::WorkerNavigatorStorageQuota() = default;
-
-const char WorkerNavigatorStorageQuota::kSupplementName[] =
- "WorkerNavigatorStorageQuota";
-
-WorkerNavigatorStorageQuota& WorkerNavigatorStorageQuota::From(
- WorkerNavigator& navigator) {
- WorkerNavigatorStorageQuota* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorStorageQuota>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorStorageQuota>();
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-StorageManager* WorkerNavigatorStorageQuota::storage(
- WorkerNavigator& navigator) {
- return WorkerNavigatorStorageQuota::From(navigator).storage();
-}
-
-StorageManager* WorkerNavigatorStorageQuota::storage() const {
- if (!storage_manager_) {
- mojo::Remote<mojom::blink::QuotaManagerHost> backend;
-
- auto* supplementable = GetSupplementable();
- auto* execution_context =
- supplementable ? supplementable->GetExecutionContext() : nullptr;
- if (execution_context) {
- if (&execution_context->GetBrowserInterfaceBroker() !=
- &GetEmptyBrowserInterfaceBroker()) {
- execution_context->GetBrowserInterfaceBroker().GetInterface(
- backend.BindNewPipeAndPassReceiver());
- }
- }
- storage_manager_ = MakeGarbageCollected<StorageManager>(execution_context,
- std::move(backend));
- }
- return storage_manager_.Get();
-}
-
-void WorkerNavigatorStorageQuota::Trace(Visitor* visitor) const {
- visitor->Trace(storage_manager_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h b/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h
deleted file mode 100644
index 84700a9a3c1..00000000000
--- a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class StorageManager;
-
-class WorkerNavigatorStorageQuota final
- : public GarbageCollected<WorkerNavigatorStorageQuota>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static WorkerNavigatorStorageQuota& From(WorkerNavigator&);
-
- static StorageManager* storage(WorkerNavigator&);
-
- StorageManager* storage() const;
-
- explicit WorkerNavigatorStorageQuota();
-
- void Trace(Visitor*) const override;
-
- private:
- mutable Member<StorageManager> storage_manager_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_
diff --git a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl b/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl
index 0acd78e9e3b..88881890ceb 100644
--- a/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl
+++ b/chromium/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl
@@ -18,7 +18,7 @@
*/
[
- ImplementedAs=WorkerNavigatorStorageQuota
+ ImplementedAs=NavigatorStorageQuota
] partial interface WorkerNavigator {
// https://storage.spec.whatwg.org/#api
[SecureContext] readonly attribute StorageManager storage;
diff --git a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.cc b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.cc
index f8832bf62a2..e71b19ed1e0 100644
--- a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.cc
+++ b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.cc
@@ -31,6 +31,8 @@ String RemoteInvocationErrorToString(
return "invoking Object.getClass() is not permitted";
case mojom::blink::RemoteInvocationError::EXCEPTION_THROWN:
return "an exception was thrown";
+ case mojom::blink::RemoteInvocationError::NON_ASSIGNABLE_TYPES:
+ return "an incompatible object type passed to method parameter";
default:
return String::Format("unknown RemoteInvocationError value: %d", value);
}
@@ -130,6 +132,131 @@ mojom::blink::RemoteInvocationArgumentPtr JSValueToMojom(
std::move(nested_arguments));
}
+ if (js_value->IsTypedArray()) {
+ auto typed_array = js_value.As<v8::TypedArray>();
+ mojom::blink::RemoteArrayType array_type;
+ if (typed_array->IsInt8Array()) {
+ array_type = mojom::blink::RemoteArrayType::kInt8Array;
+ } else if (typed_array->IsUint8Array() ||
+ typed_array->IsUint8ClampedArray()) {
+ array_type = mojom::blink::RemoteArrayType::kUint8Array;
+ } else if (typed_array->IsInt16Array()) {
+ array_type = mojom::blink::RemoteArrayType::kInt16Array;
+ } else if (typed_array->IsUint16Array()) {
+ array_type = mojom::blink::RemoteArrayType::kUint16Array;
+ } else if (typed_array->IsInt32Array()) {
+ array_type = mojom::blink::RemoteArrayType::kInt32Array;
+ } else if (typed_array->IsUint32Array()) {
+ array_type = mojom::blink::RemoteArrayType::kUint32Array;
+ } else if (typed_array->IsFloat32Array()) {
+ array_type = mojom::blink::RemoteArrayType::kFloat32Array;
+ } else if (typed_array->IsFloat64Array()) {
+ array_type = mojom::blink::RemoteArrayType::kFloat64Array;
+ } else {
+ return nullptr;
+ }
+
+ auto remote_typed_array = mojom::blink::RemoteTypedArray::New();
+ mojo_base::BigBuffer buffer(typed_array->ByteLength());
+ typed_array->CopyContents(buffer.data(), buffer.size());
+
+ remote_typed_array->buffer = std::move(buffer);
+ remote_typed_array->type = array_type;
+
+ return mojom::blink::RemoteInvocationArgument::NewTypedArrayValue(
+ std::move(remote_typed_array));
+ }
+
+ if (js_value->IsArrayBuffer() || js_value->IsArrayBufferView()) {
+ // If ArrayBuffer or ArrayBufferView is not a TypedArray, we should treat it
+ // as undefined.
+ return mojom::blink::RemoteInvocationArgument::NewSingletonValue(
+ mojom::blink::SingletonJavaScriptValue::kUndefined);
+ }
+
+ if (js_value->IsObject()) {
+ v8::Local<v8::Object> object_val = js_value.As<v8::Object>();
+
+ RemoteObject* remote_object = nullptr;
+ if (gin::ConvertFromV8(isolate, object_val, &remote_object)) {
+ return mojom::blink::RemoteInvocationArgument::NewObjectIdValue(
+ remote_object->object_id());
+ }
+
+ v8::Local<v8::Value> length_value;
+ v8::TryCatch try_catch(isolate);
+ v8::MaybeLocal<v8::Value> maybe_length_value = object_val->Get(
+ isolate->GetCurrentContext(), V8AtomicString(isolate, "length"));
+ if (try_catch.HasCaught() || !maybe_length_value.ToLocal(&length_value)) {
+ length_value = v8::Null(isolate);
+ try_catch.Reset();
+ }
+
+ if (!length_value->IsNumber()) {
+ return mojom::blink::RemoteInvocationArgument::NewSingletonValue(
+ mojom::blink::SingletonJavaScriptValue::kUndefined);
+ }
+
+ double length = length_value.As<v8::Number>()->Value();
+ if (length < 0 || length > std::numeric_limits<int32_t>::max()) {
+ return mojom::blink::RemoteInvocationArgument::NewSingletonValue(
+ mojom::blink::SingletonJavaScriptValue::kNull);
+ }
+
+ v8::Local<v8::Array> property_names;
+ if (!object_val->GetOwnPropertyNames(isolate->GetCurrentContext())
+ .ToLocal(&property_names)) {
+ return mojom::blink::RemoteInvocationArgument::NewSingletonValue(
+ mojom::blink::SingletonJavaScriptValue::kNull);
+ }
+
+ WTF::Vector<mojom::blink::RemoteInvocationArgumentPtr> nested_arguments(
+ SafeCast<wtf_size_t>(length));
+ for (uint32_t i = 0; i < property_names->Length(); ++i) {
+ v8::Local<v8::Value> key;
+ if (!property_names->Get(isolate->GetCurrentContext(), i).ToLocal(&key) ||
+ key->IsString()) {
+ try_catch.Reset();
+ continue;
+ }
+
+ if (!key->IsNumber()) {
+ NOTREACHED() << "Key \"" << *v8::String::Utf8Value(isolate, key)
+ << "\" is not a number";
+ continue;
+ }
+
+ uint32_t key_value;
+ if (!key->Uint32Value(isolate->GetCurrentContext()).To(&key_value))
+ continue;
+
+ v8::Local<v8::Value> value_v8;
+ v8::MaybeLocal<v8::Value> maybe_value =
+ object_val->Get(isolate->GetCurrentContext(), key);
+ if (try_catch.HasCaught() || !maybe_value.ToLocal(&value_v8)) {
+ value_v8 = v8::Null(isolate);
+ try_catch.Reset();
+ }
+
+ auto nested_argument = JSValueToMojom(value_v8, isolate);
+ if (!nested_argument)
+ continue;
+ nested_arguments[key_value] = std::move(nested_argument);
+ }
+
+ // Ensure that the vector has a null value.
+ for (wtf_size_t i = 0; i < nested_arguments.size(); i++) {
+ if (!nested_arguments[i]) {
+ nested_arguments[i] =
+ mojom::blink::RemoteInvocationArgument::NewSingletonValue(
+ mojom::blink::SingletonJavaScriptValue::kNull);
+ }
+ }
+
+ return mojom::blink::RemoteInvocationArgument::NewArrayValue(
+ std::move(nested_arguments));
+ }
+
return nullptr;
}
@@ -167,11 +294,12 @@ RemoteObject::RemoteObject(v8::Isolate* isolate,
object_id_(object_id) {}
RemoteObject::~RemoteObject() {
- // TODO(https://crbug.com/794320): if |this| outlives |gateway_|, the
- // browser (RemoteObjectImpl.java) needs to handle object ID invalidation when
- // the RemoteObject mojo pipe is closed.
- if (gateway_)
+ if (gateway_) {
gateway_->ReleaseObject(object_id_);
+
+ if (object_)
+ object_->NotifyReleasedObject();
+ }
}
gin::ObjectTemplateBuilder RemoteObject::GetObjectTemplateBuilder(
@@ -243,11 +371,8 @@ void RemoteObject::RemoteObjectInvokeCallback(
return;
if (result->value->is_object_id()) {
- // TODO(crbug.com/794320): need to check whether an object with this id has
- // already been injected
- RemoteObject* object_result =
- new RemoteObject(info.GetIsolate(), remote_object->gateway_,
- result->value->get_object_id());
+ RemoteObject* object_result = remote_object->gateway_->GetRemoteObject(
+ info.GetIsolate(), result->value->get_object_id());
gin::Handle<RemoteObject> controller =
gin::CreateHandle(isolate, object_result);
if (controller.IsEmpty())
diff --git a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.h b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.h
index 6c12a5e38f3..72eeb6013f9 100644
--- a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.h
+++ b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object.h
@@ -37,6 +37,8 @@ class RemoteObject : public gin::Wrappable<RemoteObject>,
std::vector<std::string> EnumerateNamedProperties(
v8::Isolate* isolate) override;
+ int32_t object_id() const { return object_id_; }
+
private:
static void RemoteObjectInvokeCallback(
const v8::FunctionCallbackInfo<v8::Value>& info);
diff --git a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc
index 1373bb2ab95..01e68cbc299 100644
--- a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.cc
@@ -32,7 +32,8 @@ void RemoteObjectGatewayImpl::InjectNamed(const WTF::String& object_name,
if (context.IsEmpty())
return;
- RemoteObject* object = new RemoteObject(isolate, this, object_id);
+ remote_objects_.erase(object_id);
+ RemoteObject* object = GetRemoteObject(isolate, object_id);
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> global = context->Global();
@@ -53,19 +54,19 @@ void RemoteObjectGatewayImpl::BindMojoReceiver(
LocalFrame* frame,
mojo::PendingRemote<mojom::blink::RemoteObjectHost> host,
mojo::PendingReceiver<mojom::blink::RemoteObjectGateway> receiver) {
- if (!frame)
+ if (!frame || !frame->IsAttached())
return;
DCHECK(!RemoteObjectGatewayImpl::From(*frame));
auto* self = MakeGarbageCollected<RemoteObjectGatewayImpl>(
- util::PassKey<RemoteObjectGatewayImpl>(), *frame, std::move(receiver),
+ base::PassKey<RemoteObjectGatewayImpl>(), *frame, std::move(receiver),
std::move(host));
Supplement<LocalFrame>::ProvideTo(*frame, self);
}
RemoteObjectGatewayImpl::RemoteObjectGatewayImpl(
- util::PassKey<RemoteObjectGatewayImpl>,
+ base::PassKey<RemoteObjectGatewayImpl>,
LocalFrame& frame,
mojo::PendingReceiver<mojom::blink::RemoteObjectGateway>
object_gateway_receiver,
@@ -112,9 +113,27 @@ void RemoteObjectGatewayImpl::BindRemoteObjectReceiver(
}
void RemoteObjectGatewayImpl::ReleaseObject(int32_t object_id) {
+ auto iter = remote_objects_.find(object_id);
+ DCHECK(iter != remote_objects_.end());
+ remote_objects_.erase(iter);
object_host_->ReleaseObject(object_id);
}
+RemoteObject* RemoteObjectGatewayImpl::GetRemoteObject(v8::Isolate* isolate,
+ int32_t object_id) {
+ auto iter = remote_objects_.find(object_id);
+ if (iter != remote_objects_.end()) {
+ // Decrease a reference count in the browser side when we reuse RemoteObject
+ // getting from the map.
+ object_host_->ReleaseObject(object_id);
+ return iter->value;
+ }
+
+ auto* remote_object = new RemoteObject(isolate, this, object_id);
+ remote_objects_.insert(object_id, remote_object);
+ return remote_object;
+}
+
// static
void RemoteObjectGatewayFactoryImpl::Create(
LocalFrame* frame,
@@ -131,6 +150,8 @@ RemoteObjectGatewayFactoryImpl::RemoteObjectGatewayFactoryImpl(
void RemoteObjectGatewayFactoryImpl::CreateRemoteObjectGateway(
mojo::PendingRemote<mojom::blink::RemoteObjectHost> host,
mojo::PendingReceiver<mojom::blink::RemoteObjectGateway> receiver) {
+ if (!frame_)
+ return;
RemoteObjectGatewayImpl::BindMojoReceiver(frame_, std::move(host),
std::move(receiver));
}
diff --git a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.h b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.h
index b03373d3f0a..4f578746562 100644
--- a/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.h
+++ b/chromium/third_party/blink/renderer/modules/remote_objects/remote_object_gateway_impl.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_REMOTE_OBJECTS_REMOTE_OBJECT_GATEWAY_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_REMOTE_OBJECTS_REMOTE_OBJECT_GATEWAY_IMPL_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
@@ -21,6 +21,7 @@
namespace blink {
class LocalFrame;
+class RemoteObject;
class MODULES_EXPORT RemoteObjectGatewayImpl
: public GarbageCollected<RemoteObjectGatewayImpl>,
@@ -30,7 +31,7 @@ class MODULES_EXPORT RemoteObjectGatewayImpl
static const char kSupplementName[];
RemoteObjectGatewayImpl(
- util::PassKey<RemoteObjectGatewayImpl>,
+ base::PassKey<RemoteObjectGatewayImpl>,
LocalFrame&,
mojo::PendingReceiver<mojom::blink::RemoteObjectGateway>,
mojo::PendingRemote<mojom::blink::RemoteObjectHost>);
@@ -57,6 +58,7 @@ class MODULES_EXPORT RemoteObjectGatewayImpl
int32_t object_id,
mojo::PendingReceiver<mojom::blink::RemoteObject>);
void ReleaseObject(int32_t object_id);
+ RemoteObject* GetRemoteObject(v8::Isolate* isolate, int32_t object_id);
private:
// mojom::blink::RemoteObjectGateway
@@ -66,6 +68,11 @@ class MODULES_EXPORT RemoteObjectGatewayImpl
void InjectNamed(const WTF::String& object_name, int32_t object_id);
HashMap<String, int32_t> named_objects_;
+ HashMap<int32_t,
+ RemoteObject*,
+ WTF::IntHash<int32_t>,
+ WTF::UnsignedWithZeroKeyHashTraits<int32_t>>
+ remote_objects_;
HeapMojoReceiver<mojom::blink::RemoteObjectGateway,
RemoteObjectGatewayImpl,
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/BUILD.gn b/chromium/third_party/blink/renderer/modules/remoteplayback/BUILD.gn
index 72d145140df..a4fb5b94fcb 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/BUILD.gn
@@ -12,6 +12,8 @@ blink_modules_sources("remoteplayback") {
"html_media_element_remote_playback.h",
"remote_playback.cc",
"remote_playback.h",
+ "remote_playback_metrics.cc",
+ "remote_playback_metrics.h",
]
deps = [ "//third_party/blink/renderer/modules/presentation" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA b/chromium/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA
new file mode 100644
index 00000000000..b8c73508592
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Media>RemotePlayback"
+}
+team_email: "media-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/OWNERS b/chromium/third_party/blink/renderer/modules/remoteplayback/OWNERS
index 715308ef34f..5f806783c38 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/OWNERS
@@ -1,5 +1,2 @@
mlamouri@chromium.org
-# TEAM: media-dev@chromium.org
-# COMPONENT: Blink>Media>RemotePlayback
-
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
index 876a5d3cd2d..d2efc0a3222 100644
--- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/modules/presentation/presentation_availability_state.h"
#include "third_party/blink/renderer/modules/presentation/presentation_controller.h"
#include "third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h"
+#include "third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -235,7 +236,8 @@ ScriptPromise RemotePlayback::prompt(ScriptState* script_state) {
prompt_promise_resolver_ = resolver;
PromptInternal();
-
+ RemotePlaybackMetrics::RecordRemotePlaybackLocation(
+ RemotePlaybackInitiationLocation::REMOTE_PLAYBACK_API);
return promise;
}
@@ -275,8 +277,7 @@ void RemotePlayback::PromptInternal() {
->GetTaskRunner(TaskType::kMediaElementEvent)
->PostTask(FROM_HERE, WTF::Bind(RunRemotePlaybackTask,
WrapPersistent(GetExecutionContext()),
- WTF::Passed(std::move(task)),
- WTF::Passed(std::move(task_id))));
+ std::move(task), std::move(task_id)));
}
}
@@ -309,8 +310,7 @@ int RemotePlayback::WatchAvailabilityInternal(
->GetTaskRunner(TaskType::kMediaElementEvent)
->PostTask(FROM_HERE, WTF::Bind(RunRemotePlaybackTask,
WrapPersistent(GetExecutionContext()),
- WTF::Passed(std::move(task)),
- WTF::Passed(std::move(task_id))));
+ std::move(task), std::move(task_id)));
MaybeStartListeningForAvailability();
return id;
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.cc
new file mode 100644
index 00000000000..e5212b18a0b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace blink {
+// static
+void RemotePlaybackMetrics::RecordRemotePlaybackLocation(
+ RemotePlaybackInitiationLocation location) {
+ UMA_HISTOGRAM_ENUMERATION("Cast.Sender.RemotePlayback.InitiationLocation",
+ location,
+ RemotePlaybackInitiationLocation::kMaxValue);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h
new file mode 100644
index 00000000000..46bdbb6ca8e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_metrics.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_REMOTEPLAYBACK_REMOTE_PLAYBACK_METRICS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_REMOTEPLAYBACK_REMOTE_PLAYBACK_METRICS_H_
+
+namespace blink {
+
+// Do not remove or renumber enums as this is used for metrics. When making
+// changes, also update the enum list in tools/metrics/histograms/enums.xml to
+// keep it in sync.
+enum RemotePlaybackInitiationLocation {
+ REMOTE_PLAYBACK_API = 0,
+ HTML_MEDIA_ELEMENT = 1,
+ kMaxValue = HTML_MEDIA_ELEMENT,
+};
+
+class RemotePlaybackMetrics {
+ public:
+ static void RecordRemotePlaybackLocation(
+ RemotePlaybackInitiationLocation location);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_REMOTEPLAYBACK_REMOTE_PLAYBACK_METRICS_H_
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/BUILD.gn b/chromium/third_party/blink/renderer/modules/sanitizer_api/BUILD.gn
index 22320231673..85c11ce6c63 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/BUILD.gn
@@ -3,6 +3,8 @@
# found in the LICENSE file.
import("//third_party/blink/renderer/modules/modules.gni")
+import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
+import("//third_party/protobuf/proto_library.gni")
blink_modules_sources("sanitizer_api") {
sources = [
@@ -10,3 +12,78 @@ blink_modules_sources("sanitizer_api") {
"sanitizer.h",
]
}
+
+if (use_libfuzzer) {
+ corpus_out_dir = "$target_gen_dir/corpus"
+
+ # For our seed corpus, we have several .html files and several proto config
+ # files. We'll assemble a list of all N x M combinations for the corpus.
+
+ corpus_source_config = [ # These match source files: corpus/*.txt
+ "config1",
+ "config2",
+ "default",
+ ]
+ corpus_source_html = [ # These match source files: corpus/*.html
+ "simple1",
+ "simple2",
+ "simple3",
+ "medium1",
+ "medium2",
+ "medium3",
+ ]
+ corpus_sources = []
+ corpus_outputs = []
+ foreach(f, corpus_source_config) {
+ corpus_sources += [ "corpus/$f.txt" ]
+ }
+ foreach(f, corpus_source_html) {
+ corpus_sources += [ "corpus/$f.html" ]
+ }
+ foreach(conf, corpus_source_config) {
+ foreach(html, corpus_source_html) {
+ corpus_outputs += [ "$corpus_out_dir/$html-$conf.txt" ]
+ }
+ }
+
+ # The build_corpus.py script assembles our corpus files.
+ # The $corpus_sources/$corpus_outputs match what the script requires.
+ # It additionally builds a dictionary (of all "words" it finds in the html
+ # inputs.
+ action("generate_sanitizer_fuzzer_corpus") {
+ script = "build_corpus.py"
+ sources = corpus_sources
+ outputs = [ "$target_gen_dir/sanitizer_api.dict" ] + corpus_outputs
+ args = rebase_path(sources, root_build_dir) + [
+ "--outdir",
+ rebase_path("$corpus_out_dir", root_build_dir),
+ "--dict",
+ rebase_path("$target_gen_dir/sanitizer_api.dict", root_build_dir),
+ ]
+ }
+
+ fuzzable_proto_library("sanitizer_config_proto") {
+ sources = [ "sanitizer_config.proto" ]
+ }
+
+ fuzzer_test("sanitizer_api_fuzzer") {
+ sources = [ "sanitizer_api_fuzzer.cc" ]
+ deps = [
+ ":generate_sanitizer_fuzzer_corpus",
+ ":sanitizer_config_proto",
+ "//third_party/blink/renderer/bindings/modules/v8:bindings_modules_impl_generated",
+ "//third_party/blink/renderer/controller:blink_bindings_test_sources",
+ "//third_party/blink/renderer/core:testing",
+ "//third_party/blink/renderer/modules:modules",
+ "//third_party/blink/renderer/platform:blink_fuzzer_test_support",
+ "//third_party/libprotobuf-mutator",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+
+ # The fuzzer_test rule accepts dependencies for seed_corpus
+ # (in seed_corpus_deps), but not for dict. Hence, we just copy that file.
+ dict = "sanitizer_api.dict"
+ seed_corpus = "$corpus_out_dir"
+ seed_corpus_deps = [ ":generate_sanitizer_fuzzer_corpus" ]
+ }
+}
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/DEPS b/chromium/third_party/blink/renderer/modules/sanitizer_api/DEPS
new file mode 100644
index 00000000000..79fef1659b2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+testing/libfuzzer/proto/lpm_interface.h",
+]
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/DIR_METADATA b/chromium/third_party/blink/renderer/modules/sanitizer_api/DIR_METADATA
new file mode 100644
index 00000000000..beb24481bc4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>SecurityFeature>SanitizerAPI"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/OWNERS b/chromium/third_party/blink/renderer/modules/sanitizer_api/OWNERS
index 4e699554b72..56baa1de8ec 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/OWNERS
@@ -1,4 +1,2 @@
lyf@chromium.org
vogelheim@chromium.org
-
-# COMPONENT: Blink>SecurityFeature>SanitizerAPI
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/build_corpus.py b/chromium/third_party/blink/renderer/modules/sanitizer_api/build_corpus.py
new file mode 100755
index 00000000000..a62afe5be00
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/build_corpus.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import os
+import re
+
+
+def basename(path):
+ return os.path.splitext(os.path.basename(path))[0]
+
+
+def char_escape(c):
+ # Escaping suitable for Protobuf text format, which is C-like.
+ if c in "'\"\\":
+ return "\\" + c
+ elif c == "\n":
+ return "\\n"
+ else:
+ return c
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Generate sanitizer_api_fuzzer seed corpus.")
+ parser.add_argument("--outdir", required=True)
+ parser.add_argument("--dictionary")
+ parser.add_argument("inputs", nargs="+")
+ args = parser.parse_args()
+
+ # For simplicity, read all inputs into dictionary.
+ inputs = {}
+ for input_file in args.inputs:
+ with open(input_file, "r") as f:
+ inputs[input_file] = f.read()
+
+ # Use file extensions to distinguish HTML from config inputs.
+ htmls = filter(lambda name: name.endswith(".html"), inputs)
+ configs = filter(lambda name: name.endswith(".txt"), inputs)
+
+ # Generate each combo of html + config, and write it into --outdir.
+ for html in htmls:
+ for config in configs:
+ name = "%s/%s-%s.txt" % (args.outdir, basename(html),
+ basename(config))
+ escaped_html = "".join(map(char_escape, inputs[html]))
+ with open(name, "w") as f:
+ f.write("html_string: \"%s\"\n%s\n" %
+ (escaped_html, inputs[config]))
+
+ # Write a "dictionary" file with the element and attribute names.
+ # Extract element and attribute names with simple regexps. It doesn't matter
+ # if these will always match correctly, as long as the dictionary is mostly
+ # sensible.
+ if args.dictionary:
+ seed_dictionary = set()
+ for html in htmls:
+ seed_dictionary.update(re.findall(r'(?<=<)\w+\b', inputs[html]))
+ seed_dictionary.update(re.findall(r'\b\w+(?==)', inputs[html]))
+ with open(args.dictionary, "w") as f:
+ for word in seed_dictionary:
+ f.write("\"%s\"\n" % word)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config1.txt b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config1.txt
new file mode 100644
index 00000000000..3374a7703ae
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config1.txt
@@ -0,0 +1,17 @@
+allow_elements: "div"
+allow_elements: "p"
+allow_elements: "span"
+allow_elements: "em"
+allow_elements: "strong"
+allow_attributes {
+ key: "class"
+ value {
+ element: "*"
+ }
+}
+allow_attributes {
+ key: "id"
+ value {
+ element: "*"
+ }
+}
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config2.txt b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config2.txt
new file mode 100644
index 00000000000..63d27533610
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/config2.txt
@@ -0,0 +1,9 @@
+block_elements: "script"
+block_elements: "span"
+drop_elements: "iframe"
+drop_attributes {
+ key: "onclick"
+ value {
+ element: "*"
+ }
+}
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/default.txt b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/default.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/default.txt
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium1.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium1.html
new file mode 100644
index 00000000000..704c85dcb52
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium1.html
@@ -0,0 +1,1000 @@
+<acronym onkeyup="val">text</acronym>
+<tfoot onpointerup="val">text</tfoot>
+<portal onabort="val">text</portal>
+<nobr minlength="val">text</nobr>
+<col pattern="val">text</col>
+<label keytype="val">text</label>
+<rtc ondragend="val">text</rtc>
+<tbody bordercolor="val">text</tbody>
+<ins tabindex="val">text</ins>
+<input pattern="val">text</input>
+<form autoplay="val">text</form>
+<tt onended="val">text</tt>
+<style pattern="val">text</style>
+<plaintext onmousedown="val">text</plaintext>
+<th list="val">text</th>
+<button method="val">text</button>
+<plaintext onselectionchange="val">text</plaintext>
+<object oncuechange="val">text</object>
+<audio onloadedmetadata="val">text</audio>
+<b shape="val">text</b>
+<input formaction="val">text</input>
+<br ondragleave="val">text</br>
+<cite onselectionchange="val">text</cite>
+<plaintext high="val">text</plaintext>
+<kbd name="val">text</kbd>
+<main onpageshow="val">text</main>
+<col onchange="val">text</col>
+<code playsinline="val">text</code>
+<nolayer oncopy="val">text</nolayer>
+<video translate="val">text</video>
+<samp onscrollend="val">text</samp>
+<audio onload="val">text</audio>
+<nav onwaiting="val">text</nav>
+<big noshade="val">text</big>
+<legend vspace="val">text</legend>
+<big defer="val">text</big>
+<optgroup onscroll="val">text</optgroup>
+<h5 onfocus="val">text</h5>
+<dd onhashchange="val">text</dd>
+<frameset oncut="val">text</frameset>
+<nav onprobe="val">text</nav>
+<option onvolumechange="val">text</option>
+<applet media="val">text</applet>
+<figure cite="val">text</figure>
+<rt link="val">text</rt>
+<script inputmode="val">text</script>
+<hgroup ondrop="val">text</hgroup>
+<a checked="val">text</a>
+<listing onportalactivate="val">text</listing>
+<listing nohref="val">text</listing>
+<nolayer onfocus="val">text</nolayer>
+<h6 nohref="val">text</h6>
+<tr download="val">text</tr>
+<noframes onscrollend="val">text</noframes>
+<option autocapitalize="val">text</option>
+<del code="val">text</del>
+<time resources="val">text</time>
+<track datetime="val">text</track>
+<ins end="val">text</ins>
+<s onbeforecut="val">text</s>
+<listing oninput="val">text</listing>
+<dl onanimationend="val">text</dl>
+<ol as="val">text</ol>
+<link imagesrcset="val">text</link>
+<basefont color="val">text</basefont>
+<image minlength="val">text</image>
+<tr accept-charset="val">text</tr>
+<main ondragenter="val">text</main>
+<strong onsubmit="val">text</strong>
+<progress incremental="val">text</progress>
+<center onbeforecut="val">text</center>
+<script onbeforeunload="val">text</script>
+<rtc latencyhint="val">text</rtc>
+<dir onfocus="val">text</dir>
+<big lowsrc="val">text</big>
+<ol onanimationiteration="val">text</ol>
+<article scheme="val">text</article>
+<ul part="val">text</ul>
+<eprobe draggable="val">text</eprobe>
+<noscript valign="val">text</noscript>
+<figure hreftranslate="val">text</figure>
+<eprobe onclose="val">text</eprobe>
+<noembed inert="val">text</noembed>
+<hr vlink="val">text</hr>
+<address reversed="val">text</address>
+<basefont imagesizes="val">text</basefont>
+<mark list="val">text</mark>
+<layer oncancel="val">text</layer>
+<style contenteditable="val">text</style>
+<audio onfocusin="val">text</audio>
+<content placeholder="val">text</content>
+<nobr archive="val">text</nobr>
+<dd oncancel="val">text</dd>
+<ol label="val">text</ol>
+<select dirname="val">text</select>
+<dfn charoff="val">text</dfn>
+<layer preload="val">text</layer>
+<col onloadstart="val">text</col>
+<noscript usemap="val">text</noscript>
+<strike abbr="val">text</strike>
+<sub onmousewheel="val">text</sub>
+<abbr low="val">text</abbr>
+<kbd dirname="val">text</kbd>
+<textarea loading="val">text</textarea>
+<sub impressionexpiry="val">text</sub>
+<eprobe onmouseleave="val">text</eprobe>
+<audio noshade="val">text</audio>
+<legend allow="val">text</legend>
+<abbr oncuechange="val">text</abbr>
+<ul ontransitionend="val">text</ul>
+<br ontouchstart="val">text</br>
+<track class="val">text</track>
+<article standby="val">text</article>
+<figure onmouseup="val">text</figure>
+<content form="val">text</content>
+<bdi valign="val">text</bdi>
+<object marginheight="val">text</object>
+<basefont onbeforeprint="val">text</basefont>
+<ol behavior="val">text</ol>
+<abbr onanimationiteration="val">text</abbr>
+<abbr direction="val">text</abbr>
+<xmp onshow="val">text</xmp>
+<tbody csp="val">text</tbody>
+<aside lowsrc="val">text</aside>
+<style frame="val">text</style>
+<hgroup controlslist="val">text</hgroup>
+<nobr decoding="val">text</nobr>
+<shadow enterkeyhint="val">text</shadow>
+<data height="val">text</data>
+<ul role="val">text</ul>
+<main ontimeupdate="val">text</main>
+<abbr resources="val">text</abbr>
+<shadow onfocusin="val">text</shadow>
+<eprobe onmessageerror="val">text</eprobe>
+<td onbeforeprint="val">text</td>
+<plaintext onpointerup="val">text</plaintext>
+<ins truespeed="val">text</ins>
+<hgroup onpointerover="val">text</hgroup>
+<label onoverscroll="val">text</label>
+<em onpointerdown="val">text</em>
+<progress loading="val">text</progress>
+<h6 frame="val">text</h6>
+<xmp onlostpointercapture="val">text</xmp>
+<data hreflang="val">text</data>
+<td onmessageerror="val">text</td>
+<wbr trusttoken="val">text</wbr>
+<dir content="val">text</dir>
+<h1 noshade="val">text</h1>
+<button oninput="val">text</button>
+<applet onstalled="val">text</applet>
+<bdi ondrop="val">text</bdi>
+<optgroup disableremoteplayback="val">text</optgroup>
+<layer charset="val">text</layer>
+<rb face="val">text</rb>
+<bdo onanimationiteration="val">text</bdo>
+<track invisible="val">text</track>
+<datalist value="val">text</datalist>
+<footer pseudo="val">text</footer>
+<thead width="val">text</thead>
+<style archive="val">text</style>
+<big csp="val">text</big>
+<rtc role="val">text</rtc>
+<section policy="val">text</section>
+<ruby list="val">text</ruby>
+<em type="val">text</em>
+<meter formenctype="val">text</meter>
+<sup formmethod="val">text</sup>
+<big compact="val">text</big>
+<s srclang="val">text</s>
+<form alt="val">text</form>
+<command ongotpointercapture="val">text</command>
+<h3 novalidate="val">text</h3>
+<address size="val">text</address>
+<noframes onseeked="val">text</noframes>
+<section onpointerout="val">text</section>
+<h5 conversiondestination="val">text</h5>
+<noscript axis="val">text</noscript>
+<nobr ondragleave="val">text</nobr>
+<track bgcolor="val">text</track>
+<output oninvalid="val">text</output>
+<del for="val">text</del>
+<object id="val">text</object>
+<strong hreftranslate="val">text</strong>
+<style nowrap="val">text</style>
+<picture onlanguagechange="val">text</picture>
+<datalist version="val">text</datalist>
+<select importance="val">text</select>
+<a onunload="val">text</a>
+<aside scheme="val">text</aside>
+<rt controlslist="val">text</rt>
+<address oncanplay="val">text</address>
+<h6 onpointerleave="val">text</h6>
+<hgroup onclick="val">text</hgroup>
+<image vlink="val">text</image>
+<figcaption onload="val">text</figcaption>
+<fieldset object="val">text</fieldset>
+<noframes accesskey="val">text</noframes>
+<bdi ontransitionend="val">text</bdi>
+<ins marginheight="val">text</ins>
+<strong onkeydown="val">text</strong>
+<noscript declare="val">text</noscript>
+<aside decoding="val">text</aside>
+<h3 select="val">text</h3>
+<h5 onlostpointercapture="val">text</h5>
+<dfn onended="val">text</dfn>
+<b scheme="val">text</b>
+<legend onanimationiteration="val">text</legend>
+<tbody disablepictureinpicture="val">text</tbody>
+<datalist onmousemove="val">text</datalist>
+<img ondragover="val">text</img>
+<tr reversed="val">text</tr>
+<meter valuetype="val">text</meter>
+<br axis="val">text</br>
+<hgroup ongotpointercapture="val">text</hgroup>
+<applet onkeydown="val">text</applet>
+<sub direction="val">text</sub>
+<strike autopictureinpicture="val">text</strike>
+<xmp onwebkitanimationend="val">text</xmp>
+<a onstorage="val">text</a>
+<select oninvalid="val">text</select>
+<style topmargin="val">text</style>
+<optgroup importance="val">text</optgroup>
+<ol oncancel="val">text</ol>
+<h6 readonly="val">text</h6>
+<time action="val">text</time>
+<acronym onanimationstart="val">text</acronym>
+<img ondragend="val">text</img>
+<iframe keytype="val">text</iframe>
+<nobr onpointerdown="val">text</nobr>
+<data rel="val">text</data>
+<a shadowrootdelegatesfocus="val">text</a>
+<main headers="val">text</main>
+<dfn autoplay="val">text</dfn>
+<style dirname="val">text</style>
+<plaintext enctype="val">text</plaintext>
+<footer onratechange="val">text</footer>
+<hr label="val">text</hr>
+<h3 onanimationiteration="val">text</h3>
+<u onwebkitfullscreenerror="val">text</u>
+<xmp onplaying="val">text</xmp>
+<abbr id="val">text</abbr>
+<h5 noshade="val">text</h5>
+<track onselectionchange="val">text</track>
+<li onselectionchange="val">text</li>
+<applet onpageshow="val">text</applet>
+<h4 nomodule="val">text</h4>
+<ins scrolldelay="val">text</ins>
+<canvas autopictureinpicture="val">text</canvas>
+<data onabort="val">text</data>
+<meter onfocusout="val">text</meter>
+<main shape="val">text</main>
+<p onbeforecopy="val">text</p>
+<dd decoding="val">text</dd>
+<frameset truespeed="val">text</frameset>
+<audio archive="val">text</audio>
+<summary summary="val">text</summary>
+<hr imagesrcset="val">text</hr>
+<sup standby="val">text</sup>
+<xmp enctype="val">text</xmp>
+<hgroup as="val">text</hgroup>
+<noframes rowspan="val">text</noframes>
+<u formaction="val">text</u>
+<basefont disableremoteplayback="val">text</basefont>
+<h4 href="val">text</h4>
+<br checked="val">text</br>
+<noembed onemptied="val">text</noembed>
+<cite loading="val">text</cite>
+<li allowpaymentrequest="val">text</li>
+<img src="val">text</img>
+<dfn invisible="val">text</dfn>
+<rt hspace="val">text</rt>
+<header max="val">text</header>
+<tt valign="val">text</tt>
+<rtc checked="val">text</rtc>
+<br src="val">text</br>
+<track action="val">text</track>
+<listing conversiondestination="val">text</listing>
+<blockquote onformdata="val">text</blockquote>
+<applet onbeforeprint="val">text</applet>
+<h2 onformdata="val">text</h2>
+<dir start="val">text</dir>
+<datalist compact="val">text</datalist>
+<img onbeforeprint="val">text</img>
+<colgroup onkeypress="val">text</colgroup>
+<u onmouseout="val">text</u>
+<progress mayscript="val">text</progress>
+<script alink="val">text</script>
+<figure onmousedown="val">text</figure>
+<h3 exportparts="val">text</h3>
+<optgroup onpause="val">text</optgroup>
+<meter virtualkeyboardpolicy="val">text</meter>
+<embed ondragenter="val">text</embed>
+<rtc autocomplete="val">text</rtc>
+<wbr onwebkitfullscreenerror="val">text</wbr>
+<rt referrerpolicy="val">text</rt>
+<aside version="val">text</aside>
+<address onpageshow="val">text</address>
+<li onloadstart="val">text</li>
+<rtc onfocusin="val">text</rtc>
+<tt onvolumechange="val">text</tt>
+<colgroup maxlength="val">text</colgroup>
+<style ononline="val">text</style>
+<center onfocusout="val">text</center>
+<audio onscrollend="val">text</audio>
+<dd inputmode="val">text</dd>
+<rtc code="val">text</rtc>
+<b onselectstart="val">text</b>
+<basefont coords="val">text</basefont>
+<header link="val">text</header>
+<acronym content="val">text</acronym>
+<audio alt="val">text</audio>
+<figure onprogress="val">text</figure>
+<script shadowrootdelegatesfocus="val">text</script>
+<nav onmouseleave="val">text</nav>
+<h6 allow="val">text</h6>
+<dfn archive="val">text</dfn>
+<form onwebkitanimationstart="val">text</form>
+<thead onbeforeunload="val">text</thead>
+<shadow manifest="val">text</shadow>
+<textarea cellspacing="val">text</textarea>
+<label onwebkittransitionend="val">text</label>
+<basefont part="val">text</basefont>
+<tbody onhashchange="val">text</tbody>
+<tfoot start="val">text</tfoot>
+<content latencyhint="val">text</content>
+<rp async="val">text</rp>
+<bgsound onblur="val">text</bgsound>
+<content axis="val">text</content>
+<h3 accesskey="val">text</h3>
+<mark inert="val">text</mark>
+<plaintext hreftranslate="val">text</plaintext>
+<nolayer ontouchend="val">text</nolayer>
+<tfoot name="val">text</tfoot>
+<img onloadstart="val">text</img>
+<label onwebkitfullscreenchange="val">text</label>
+<tbody autopictureinpicture="val">text</tbody>
+<summary ondurationchange="val">text</summary>
+<rb alt="val">text</rb>
+<li face="val">text</li>
+<basefont ondragend="val">text</basefont>
+<listing multiple="val">text</listing>
+<style hspace="val">text</style>
+<figcaption headers="val">text</figcaption>
+<tfoot onwheel="val">text</tfoot>
+<progress onmessage="val">text</progress>
+<caption decoding="val">text</caption>
+<slot onhashchange="val">text</slot>
+<dd tabindex="val">text</dd>
+<listing referrerpolicy="val">text</listing>
+<q leftmargin="val">text</q>
+<rp ismap="val">text</rp>
+<h2 imagesrcset="val">text</h2>
+<button onfocus="val">text</button>
+<strike onanimationstart="val">text</strike>
+<frameset width="val">text</frameset>
+<script marginwidth="val">text</script>
+<acronym controlslist="val">text</acronym>
+<track hidden="val">text</track>
+<sup name="val">text</sup>
+<th rules="val">text</th>
+<embed charset="val">text</embed>
+<h1 ontouchend="val">text</h1>
+<u vlink="val">text</u>
+<shadow target="val">text</shadow>
+<em webkitdirectory="val">text</em>
+<q onwebkitanimationiteration="val">text</q>
+<ol ondrop="val">text</ol>
+<em onclose="val">text</em>
+<samp>text</samp>
+<article topmargin="val">text</article>
+<h2 onkeyup="val">text</h2>
+<tbody mayscript="val">text</tbody>
+<th preload="val">text</th>
+<strike class="val">text</strike>
+<section ping="val">text</section>
+<samp bgcolor="val">text</samp>
+<dt onkeypress="val">text</dt>
+<iframe disabled="val">text</iframe>
+<h1 ondragover="val">text</h1>
+<ins onseeked="val">text</ins>
+<abbr enctype="val">text</abbr>
+<nolayer onwebkitanimationstart="val">text</nolayer>
+<strong spellcheck="val">text</strong>
+<meter accept-charset="val">text</meter>
+<td rules="val">text</td>
+<datalist rows="val">text</datalist>
+<strong cite="val">text</strong>
+<li alt="val">text</li>
+<ins accept-charset="val">text</ins>
+<abbr onpopstate="val">text</abbr>
+<col onoffline="val">text</col>
+<portal onseeking="val">text</portal>
+<keygen onunload="val">text</keygen>
+<applet noshade="val">text</applet>
+<form step="val">text</form>
+<nav onwebkitfullscreenerror="val">text</nav>
+<dt frameborder="val">text</dt>
+<content disableremoteplayback="val">text</content>
+<noframes for="val">text</noframes>
+<kbd shape="val">text</kbd>
+<figcaption oninvalid="val">text</figcaption>
+<s start="val">text</s>
+<p ondblclick="val">text</p>
+<layer oncanplaythrough="val">text</layer>
+<big background="val">text</big>
+<noembed formtarget="val">text</noembed>
+<canvas is="val">text</canvas>
+<section onpageshow="val">text</section>
+<i sizes="val">text</i>
+<tr policy="val">text</tr>
+<thead bgcolor="val">text</thead>
+<nav muted="val">text</nav>
+<samp onresize="val">text</samp>
+<frameset preload="val">text</frameset>
+<nolayer form="val">text</nolayer>
+<option method="val">text</option>
+<ul as="val">text</ul>
+<footer codetype="val">text</footer>
+<cite onplay="val">text</cite>
+<ul loop="val">text</ul>
+<cite ontimeupdate="val">text</cite>
+<plaintext onratechange="val">text</plaintext>
+<strong is="val">text</strong>
+<h6 onwebkitfullscreenerror="val">text</h6>
+<applet cellspacing="val">text</applet>
+<hgroup dirname="val">text</hgroup>
+<h2 valign="val">text</h2>
+<output class="val">text</output>
+<q novalidate="val">text</q>
+<datalist select="val">text</datalist>
+<address onfocusout="val">text</address>
+<command hreftranslate="val">text</command>
+<small onstalled="val">text</small>
+<frameset onfocusout="val">text</frameset>
+<legend onmouseover="val">text</legend>
+<strong onorientationchange="val">text</strong>
+<nolayer method="val">text</nolayer>
+<s async="val">text</s>
+<button allowpaymentrequest="val">text</button>
+<basefont role="val">text</basefont>
+<col onmouseup="val">text</col>
+<object scheme="val">text</object>
+<strong onabort="val">text</strong>
+<section onscrollend="val">text</section>
+<figure onpointerleave="val">text</figure>
+<button loop="val">text</button>
+<center ondragend="val">text</center>
+<dfn data="val">text</dfn>
+<output maxlength="val">text</output>
+<small srcset="val">text</small>
+<u manifest="val">text</u>
+<basefont list="val">text</basefont>
+<tfoot onsuspend="val">text</tfoot>
+<kbd style="val">text</kbd>
+<address vspace="val">text</address>
+<acronym onwebkitfullscreenchange="val">text</acronym>
+<blockquote policy="val">text</blockquote>
+<del title="val">text</del>
+<command onpointerup="val">text</command>
+<label onerror="val">text</label>
+<tr frameborder="val">text</tr>
+<center datetime="val">text</center>
+<rp autofocus="val">text</rp>
+<small onselectstart="val">text</small>
+<button kind="val">text</button>
+<address longdesc="val">text</address>
+<main keytype="val">text</main>
+<label accesskey="val">text</label>
+<a onmousemove="val">text</a>
+<rp onload="val">text</rp>
+<h1 scheme="val">text</h1>
+<h4 enterkeyhint="val">text</h4>
+<em scheme="val">text</em>
+<frameset src="val">text</frameset>
+<nolayer onstorage="val">text</nolayer>
+<tfoot imagesrcset="val">text</tfoot>
+<embed wrap="val">text</embed>
+<u onunload="val">text</u>
+<nolayer char="val">text</nolayer>
+<hr onmouseup="val">text</hr>
+<q min="val">text</q>
+<ul translate="val">text</ul>
+<h2 formaction="val">text</h2>
+<u placeholder="val">text</u>
+<button border="val">text</button>
+<portal onpointerover="val">text</portal>
+<mark nowrap="val">text</mark>
+<embed truespeed="val">text</embed>
+<tfoot ontimezonechange="val">text</tfoot>
+<li truespeed="val">text</li>
+<main onmousemove="val">text</main>
+<noembed srcset="val">text</noembed>
+<iframe compact="val">text</iframe>
+<kbd contenteditable="val">text</kbd>
+<img trusttoken="val">text</img>
+<big oncut="val">text</big>
+<tfoot tabindex="val">text</tfoot>
+<figure onkeypress="val">text</figure>
+<rp oninput="val">text</rp>
+<input label="val">text</input>
+<ol codetype="val">text</ol>
+<dt alt="val">text</dt>
+<listing onpointercancel="val">text</listing>
+<ul onscroll="val">text</ul>
+<image noshade="val">text</image>
+<h3 char="val">text</h3>
+<image onabort="val">text</image>
+<link face="val">text</link>
+<h6 onpointermove="val">text</h6>
+<small size="val">text</small>
+<figure marginwidth="val">text</figure>
+<kbd formenctype="val">text</kbd>
+<address marginheight="val">text</address>
+<h4 onload="val">text</h4>
+<abbr oninput="val">text</abbr>
+<bdo draggable="val">text</bdo>
+<nobr onbeforepaste="val">text</nobr>
+<fieldset onhashchange="val">text</fieldset>
+<video archive="val">text</video>
+<rtc accesskey="val">text</rtc>
+<ul multiple="val">text</ul>
+<hr nowrap="val">text</hr>
+<rt spellcheck="val">text</rt>
+<dfn onblur="val">text</dfn>
+<strike pattern="val">text</strike>
+<progress onbeforepaste="val">text</progress>
+<summary onscroll="val">text</summary>
+<label latencyhint="val">text</label>
+<noframes oncanplay="val">text</noframes>
+<cite end="val">text</cite>
+<p reportingorigin="val">text</p>
+<nav cite="val">text</nav>
+<p onmouseout="val">text</p>
+<figure clear="val">text</figure>
+<dt accesskey="val">text</dt>
+<col scrollamount="val">text</col>
+<caption formnovalidate="val">text</caption>
+<tbody standby="val">text</tbody>
+<link rel="val">text</link>
+<bdo disabled="val">text</bdo>
+<bdi shape="val">text</bdi>
+<slot onkeypress="val">text</slot>
+<canvas onload="val">text</canvas>
+<h3 title="val">text</h3>
+<dl onoverscroll="val">text</dl>
+<canvas onwheel="val">text</canvas>
+<h3 valuetype="val">text</h3>
+<hr onformdata="val">text</hr>
+<b reportingorigin="val">text</b>
+<ruby sizes="val">text</ruby>
+<code valuetype="val">text</code>
+<image form="val">text</image>
+<wbr formaction="val">text</wbr>
+<tr formnovalidate="val">text</tr>
+<blockquote version="val">text</blockquote>
+<ul onhashchange="val">text</ul>
+<embed required="val">text</embed>
+<script style="val">text</script>
+<output hreflang="val">text</output>
+<strike bordercolor="val">text</strike>
+<samp onselectstart="val">text</samp>
+<track pseudo="val">text</track>
+<hr data="val">text</hr>
+<var onprogress="val">text</var>
+<caption onpointerleave="val">text</caption>
+<center high="val">text</center>
+<output onkeypress="val">text</output>
+<i oncuechange="val">text</i>
+<u oncanplay="val">text</u>
+<abbr frameborder="val">text</abbr>
+<ul cols="val">text</ul>
+<h2 summary="val">text</h2>
+<em step="val">text</em>
+<kbd onbeforecopy="val">text</kbd>
+<track csp="val">text</track>
+<nav onanimationstart="val">text</nav>
+<meter muted="val">text</meter>
+<bdi ondragenter="val">text</bdi>
+<content ontoggle="val">text</content>
+<thead ononline="val">text</thead>
+<figure onoverscroll="val">text</figure>
+<dt oninvalid="val">text</dt>
+<option optimum="val">text</option>
+<eprobe axis="val">text</eprobe>
+<noscript invisible="val">text</noscript>
+<li high="val">text</li>
+<content inert="val">text</content>
+<button onprobe="val">text</button>
+<video onauxclick="val">text</video>
+<bdo importance="val">text</bdo>
+<th hidden="val">text</th>
+<tr ononline="val">text</tr>
+<nolayer onpagehide="val">text</nolayer>
+<dl style="val">text</dl>
+<input onmouseover="val">text</input>
+<portal ononline="val">text</portal>
+<hgroup onabort="val">text</hgroup>
+<optgroup src="val">text</optgroup>
+<embed onscrollend="val">text</embed>
+<article summary="val">text</article>
+<rp rel="val">text</rp>
+<wbr onauxclick="val">text</wbr>
+<noscript accesskey="val">text</noscript>
+<ol ondragover="val">text</ol>
+<colgroup ontouchstart="val">text</colgroup>
+<fieldset formmethod="val">text</fieldset>
+<blockquote onkeypress="val">text</blockquote>
+<header onsuspend="val">text</header>
+<noscript srcdoc="val">text</noscript>
+<i reportingorigin="val">text</i>
+<h5 open="val">text</h5>
+<strong oncut="val">text</strong>
+<summary formenctype="val">text</summary>
+<script nohref="val">text</script>
+<li accept-charset="val">text</li>
+<shadow dirname="val">text</shadow>
+<style onblur="val">text</style>
+<listing abbr="val">text</listing>
+<dd onplaying="val">text</dd>
+<embed onloadeddata="val">text</embed>
+<ruby async="val">text</ruby>
+<nolayer oncanplaythrough="val">text</nolayer>
+<br onstorage="val">text</br>
+<blockquote onseeking="val">text</blockquote>
+<optgroup valuetype="val">text</optgroup>
+<track as="val">text</track>
+<tt noresize="val">text</tt>
+<s list="val">text</s>
+<rp topmargin="val">text</rp>
+<col hreftranslate="val">text</col>
+<layer coords="val">text</layer>
+<bdi ontimeupdate="val">text</bdi>
+<samp truespeed="val">text</samp>
+<abbr charoff="val">text</abbr>
+<big incremental="val">text</big>
+<strike lang="val">text</strike>
+<td disablepictureinpicture="val">text</td>
+<ins nomodule="val">text</ins>
+<footer rows="val">text</footer>
+<acronym novalidate="val">text</acronym>
+<ins onended="val">text</ins>
+<optgroup shape="val">text</optgroup>
+<script rowspan="val">text</script>
+<data ismap="val">text</data>
+<i selected="val">text</i>
+<em onwebkitanimationstart="val">text</em>
+<main decoding="val">text</main>
+<eprobe rules="val">text</eprobe>
+<eprobe onpointermove="val">text</eprobe>
+<listing webkitdirectory="val">text</listing>
+<footer cellpadding="val">text</footer>
+<rt archive="val">text</rt>
+<form exportparts="val">text</form>
+<thead action="val">text</thead>
+<image class="val">text</image>
+<meter autopictureinpicture="val">text</meter>
+<caption autocorrect="val">text</caption>
+<address cols="val">text</address>
+<nav as="val">text</nav>
+<dd onbeforeunload="val">text</dd>
+<tt resources="val">text</tt>
+<link method="val">text</link>
+<nobr onpageshow="val">text</nobr>
+<listing alt="val">text</listing>
+<form contenteditable="val">text</form>
+<article cellspacing="val">text</article>
+<ol valuetype="val">text</ol>
+<li loop="val">text</li>
+<slot is="val">text</slot>
+<summary target="val">text</summary>
+<nav lang="val">text</nav>
+<canvas formtarget="val">text</canvas>
+<tbody marginwidth="val">text</tbody>
+<caption shadowroot="val">text</caption>
+<blockquote autoplay="val">text</blockquote>
+<mark accept="val">text</mark>
+<link scrolling="val">text</link>
+<hgroup onloadstart="val">text</hgroup>
+<hr onloadeddata="val">text</hr>
+<audio cite="val">text</audio>
+<eprobe readonly="val">text</eprobe>
+<wbr rules="val">text</wbr>
+<h5 oncancel="val">text</h5>
+<tfoot onwebkitanimationstart="val">text</tfoot>
+<article ongotpointercapture="val">text</article>
+<header onwebkitfullscreenerror="val">text</header>
+<ol low="val">text</ol>
+<iframe datetime="val">text</iframe>
+<section ontoggle="val">text</section>
+<slot onpaste="val">text</slot>
+<h5 charset="val">text</h5>
+<i onplaying="val">text</i>
+<summary enterkeyhint="val">text</summary>
+<bgsound min="val">text</bgsound>
+<h4 onwebkitanimationend="val">text</h4>
+<fieldset onpageshow="val">text</fieldset>
+<aside onanimationstart="val">text</aside>
+<data webkitdirectory="val">text</data>
+<section frameborder="val">text</section>
+<nobr class="val">text</nobr>
+<th oncut="val">text</th>
+<small impressiondata="val">text</small>
+<aside bordercolor="val">text</aside>
+<textarea summary="val">text</textarea>
+<ul disablepictureinpicture="val">text</ul>
+<plaintext bordercolor="val">text</plaintext>
+<rtc type="val">text</rtc>
+<slot onvolumechange="val">text</slot>
+<style behavior="val">text</style>
+<nolayer shape="val">text</nolayer>
+<mark formnovalidate="val">text</mark>
+<big crossorigin="val">text</big>
+<nolayer onwebkitfullscreenchange="val">text</nolayer>
+<eprobe role="val">text</eprobe>
+<ruby translate="val">text</ruby>
+<rb marginwidth="val">text</rb>
+<article policy="val">text</article>
+<h5 oncanplay="val">text</h5>
+<xmp noshade="val">text</xmp>
+<bdi onwebkitfullscreenchange="val">text</bdi>
+<noscript oncopy="val">text</noscript>
+<layer value="val">text</layer>
+<col onpointerleave="val">text</col>
+<ins ontoggle="val">text</ins>
+<mark mayscript="val">text</mark>
+<xmp event="val">text</xmp>
+<plaintext for="val">text</plaintext>
+<br topmargin="val">text</br>
+<dl autofocus="val">text</dl>
+<ol rowspan="val">text</ol>
+<portal onanimationstart="val">text</portal>
+<code ondragover="val">text</code>
+<noembed behavior="val">text</noembed>
+<header onpointerout="val">text</header>
+<listing label="val">text</listing>
+<sub imagesrcset="val">text</sub>
+<u select="val">text</u>
+<form onkeydown="val">text</form>
+<b is="val">text</b>
+<small onanimationend="val">text</small>
+<summary allowpaymentrequest="val">text</summary>
+<textarea coords="val">text</textarea>
+<progress onmessageerror="val">text</progress>
+<embed onmousedown="val">text</embed>
+<th imagesizes="val">text</th>
+<dd allow="val">text</dd>
+<s onmouseleave="val">text</s>
+<ins object="val">text</ins>
+<noframes rows="val">text</noframes>
+<q onwebkittransitionend="val">text</q>
+<meter onpaste="val">text</meter>
+<input lowsrc="val">text</input>
+<nobr onpopstate="val">text</nobr>
+<dl onshow="val">text</dl>
+<datalist onmousewheel="val">text</datalist>
+<col onpointerrawupdate="val">text</col>
+<li manifest="val">text</li>
+<kbd marginheight="val">text</kbd>
+<listing virtualkeyboardpolicy="val">text</listing>
+<dir cellspacing="val">text</dir>
+<ins oninvalid="val">text</ins>
+<time onprogress="val">text</time>
+<content manifest="val">text</content>
+<ul style="val">text</ul>
+<figcaption code="val">text</figcaption>
+<del formmethod="val">text</del>
+<thead onselectionchange="val">text</thead>
+<xmp autocapitalize="val">text</xmp>
+<caption poster="val">text</caption>
+<cite nohref="val">text</cite>
+<p onplay="val">text</p>
+<object href="val">text</object>
+<textarea srcdoc="val">text</textarea>
+<i onbeforeunload="val">text</i>
+<fieldset onprogress="val">text</fieldset>
+<tt onmouseup="val">text</tt>
+<main ondragleave="val">text</main>
+<footer topmargin="val">text</footer>
+<td marginheight="val">text</td>
+<xmp trusttoken="val">text</xmp>
+<time onwebkittransitionend="val">text</time>
+<small end="val">text</small>
+<samp type="val">text</samp>
+<ol kind="val">text</ol>
+<b imagesizes="val">text</b>
+<rb inputmode="val">text</rb>
+<audio onvolumechange="val">text</audio>
+<acronym part="val">text</acronym>
+<input onselect="val">text</input>
+<script end="val">text</script>
+<var src="val">text</var>
+<header role="val">text</header>
+<shadow valuetype="val">text</shadow>
+<footer keytype="val">text</footer>
+<h5 shape="val">text</h5>
+<object onmouseout="val">text</object>
+<input onwebkitanimationiteration="val">text</input>
+<ol step="val">text</ol>
+<mark oncanplaythrough="val">text</mark>
+<shadow accept="val">text</shadow>
+<rp imagesizes="val">text</rp>
+<header ononline="val">text</header>
+<h5 bgcolor="val">text</h5>
+<rb summary="val">text</rb>
+<link onmouseleave="val">text</link>
+<summary onblur="val">text</summary>
+<strong onmousemove="val">text</strong>
+<main reversed="val">text</main>
+<bdo inert="val">text</bdo>
+<plaintext onpause="val">text</plaintext>
+<col ongotpointercapture="val">text</col>
+<legend alink="val">text</legend>
+<i scrolling="val">text</i>
+<noframes start="val">text</noframes>
+<slot latencyhint="val">text</slot>
+<dl language="val">text</dl>
+<s controls="val">text</s>
+<br shape="val">text</br>
+<fieldset lowsrc="val">text</fieldset>
+<p colspan="val">text</p>
+<eprobe onblur="val">text</eprobe>
+<h1 value="val">text</h1>
+<th shape="val">text</th>
+<i checked="val">text</i>
+<blockquote onpointerleave="val">text</blockquote>
+<time disableremoteplayback="val">text</time>
+<p disallowdocumentaccess="val">text</p>
+<script onblur="val">text</script>
+<em onselect="val">text</em>
+<th onlostpointercapture="val">text</th>
+<main noshade="val">text</main>
+<abbr disabled="val">text</abbr>
+<tfoot onbeforeunload="val">text</tfoot>
+<acronym valuetype="val">text</acronym>
+<keygen oncut="val">text</keygen>
+<sup onclose="val">text</sup>
+<nolayer width="val">text</nolayer>
+<fieldset onpopstate="val">text</fieldset>
+<select inert="val">text</select>
+<basefont async="val">text</basefont>
+<layer autocapitalize="val">text</layer>
+<samp dirname="val">text</samp>
+<nav onwheel="val">text</nav>
+<thead onfocus="val">text</thead>
+<audio scrolling="val">text</audio>
+<option imagesizes="val">text</option>
+<big select="val">text</big>
+<small onwaiting="val">text</small>
+<audio controls="val">text</audio>
+<optgroup http-equiv="val">text</optgroup>
+<audio background="val">text</audio>
+<dfn onresize="val">text</dfn>
+<nolayer headers="val">text</nolayer>
+<rb onwheel="val">text</rb>
+<style onseeking="val">text</style>
+<dl kind="val">text</dl>
+<applet usemap="val">text</applet>
+<plaintext nonce="val">text</plaintext>
+<h3 ontimeupdate="val">text</h3>
+<optgroup pseudo="val">text</optgroup>
+<keygen width="val">text</keygen>
+<kbd onscroll="val">text</kbd>
+<noscript direction="val">text</noscript>
+<b onbeforeprint="val">text</b>
+<eprobe onformdata="val">text</eprobe>
+<dfn virtualkeyboardpolicy="val">text</dfn>
+<h1 disallowdocumentaccess="val">text</h1>
+<strong onmousewheel="val">text</strong>
+<var preload="val">text</var>
+<applet conversiondestination="val">text</applet>
+<xmp standby="val">text</xmp>
+<noembed pattern="val">text</noembed>
+<style onload="val">text</style>
+<h5 pattern="val">text</h5>
+<col onunload="val">text</col>
+<th low="val">text</th>
+<textarea max="val">text</textarea>
+<listing hreftranslate="val">text</listing>
+<fieldset hreftranslate="val">text</fieldset>
+<command char="val">text</command>
+<code muted="val">text</code>
+<frameset onwebkitfullscreenerror="val">text</frameset>
+<hr onorientationchange="val">text</hr>
+<dir onkeydown="val">text</dir>
+<dl onstalled="val">text</dl>
+<input spellcheck="val">text</input>
+<input onstalled="val">text</input>
+<i oncut="val">text</i>
+<output contenteditable="val">text</output>
+<em declare="val">text</em>
+<h4 part="val">text</h4>
+<noscript onoffline="val">text</noscript>
+<aside wrap="val">text</aside>
+<h6 spellcheck="val">text</h6>
+<sup srcset="val">text</sup>
+<shadow onwebkitanimationend="val">text</shadow>
+<h4 onpointerenter="val">text</h4>
+<tbody frameborder="val">text</tbody>
+<bgsound autocapitalize="val">text</bgsound>
+<samp data="val">text</samp>
+<link onmouseover="val">text</link>
+<tr onkeydown="val">text</tr>
+<dd srclang="val">text</dd>
+<dir required="val">text</dir>
+<colgroup lang="val">text</colgroup>
+<object decoding="val">text</object>
+<shadow onauxclick="val">text</shadow>
+<wbr clear="val">text</wbr>
+<input data="val">text</input>
+<h6 scheme="val">text</h6>
+<h1 onmousedown="val">text</h1>
+<ul rules="val">text</ul>
+<hgroup onreset="val">text</hgroup>
+<footer rel="val">text</footer>
+<plaintext virtualkeyboardpolicy="val">text</plaintext>
+<acronym onpointercancel="val">text</acronym>
+<listing noshade="val">text</listing>
+<tr onbeforeprint="val">text</tr>
+<b title="val">text</b>
+<strong for="val">text</strong>
+<samp language="val">text</samp>
+<colgroup hspace="val">text</colgroup>
+<basefont onmessageerror="val">text</basefont>
+<sub inputmode="val">text</sub>
+<h6 onoverscroll="val">text</h6>
+<portal text="val">text</portal>
+<style alt="val">text</style>
+<option onprogress="val">text</option>
+<code ontimezonechange="val">text</code>
+<ul charoff="val">text</ul>
+<canvas onmouseout="val">text</canvas>
+<output virtualkeyboardpolicy="val">text</output>
+<var onwaiting="val">text</var>
+<noframes oncuechange="val">text</noframes>
+<article oninput="val">text</article>
+<cite oncancel="val">text</cite>
+<figcaption keytype="val">text</figcaption>
+<a onseeking="val">text</a>
+<listing onmousemove="val">text</listing>
+<code onmouseleave="val">text</code>
+<command usemap="val">text</command>
+<acronym onmousedown="val">text</acronym>
+<main method="val">text</main>
+<rb impressionexpiry="val">text</rb>
+<p scrolldelay="val">text</p>
+<i ondragstart="val">text</i>
+<ul onoffline="val">text</ul>
+<audio vlink="val">text</audio>
+<tt onpointercancel="val">text</tt>
+<summary valuetype="val">text</summary>
+<sup impressionexpiry="val">text</sup>
+<del alt="val">text</del>
+<tr cellpadding="val">text</tr>
+<ins part="val">text</ins>
+<ol onpointerover="val">text</ol>
+<section scrolling="val">text</section>
+<portal formenctype="val">text</portal>
+<fieldset archive="val">text</fieldset>
+<i tabindex="val">text</i>
+<legend onplaying="val">text</legend>
+<style onplay="val">text</style>
+<bgsound archive="val">text</bgsound>
+<strong nomodule="val">text</strong>
+<plaintext height="val">text</plaintext>
+<em onratechange="val">text</em>
+<br frame="val">text</br>
+<meter onpointerout="val">text</meter>
+<ruby autocapitalize="val">text</ruby>
+<a disabled="val">text</a>
+<bdo ondrag="val">text</bdo>
+<big onpointercancel="val">text</big>
+<object formaction="val">text</object>
+<iframe data="val">text</iframe>
+<embed ondragover="val">text</embed>
+<time valign="val">text</time>
+<section reversed="val">text</section>
+<tfoot translate="val">text</tfoot>
+<samp onloadedmetadata="val">text</samp>
+<dd aprobe="val">text</dd>
+<content onwaiting="val">text</content>
+<h4 behavior="val">text</h4>
+<q onbeforecopy="val">text</q>
+<link alt="val">text</link>
+<strike onoffline="val">text</strike>
+<meter onwebkitanimationstart="val">text</meter>
+<h1 accesskey="val">text</h1>
+<p usemap="val">text</p>
+<u onfocusin="val">text</u>
+<sup srclang="val">text</sup>
+<textarea onauxclick="val">text</textarea>
+<col checked="val">text</col>
+<h5 onreset="val">text</h5>
+<address oncut="val">text</address>
+<ol enctype="val">text</ol>
+<dd list="val">text</dd>
+<bdo onunload="val">text</bdo>
+<fieldset ontouchend="val">text</fieldset>
+<dt ontimezonechange="val">text</dt>
+<option height="val">text</option>
+<listing scheme="val">text</listing>
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium2.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium2.html
new file mode 100644
index 00000000000..d44be8ddb66
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium2.html
@@ -0,0 +1,1000 @@
+<ol controlslist="val">text</ol>
+<plaintext axis="val">text</plaintext>
+<data hreflang="val">text</data>
+<samp readonly="val">text</samp>
+<script onloadeddata="val">text</script>
+<dl onpointerup="val">text</dl>
+<tfoot accesskey="val">text</tfoot>
+<var sandbox="val">text</var>
+<video end="val">text</video>
+<content headers="val">text</content>
+<h1 onkeydown="val">text</h1>
+<noscript onratechange="val">text</noscript>
+<code async="val">text</code>
+<address scope="val">text</address>
+<tt method="val">text</tt>
+<li onblur="val">text</li>
+<td shadowrootdelegatesfocus="val">text</td>
+<address onabort="val">text</address>
+<dfn download="val">text</dfn>
+<datalist onloadstart="val">text</datalist>
+<shadow onmouseenter="val">text</shadow>
+<canvas onanimationend="val">text</canvas>
+<li step="val">text</li>
+<h5 topmargin="val">text</h5>
+<s disallowdocumentaccess="val">text</s>
+<applet onloadstart="val">text</applet>
+<dt ondrag="val">text</dt>
+<object minlength="val">text</object>
+<cite onclick="val">text</cite>
+<fieldset ongotpointercapture="val">text</fieldset>
+<datalist onpaste="val">text</datalist>
+<iframe autopictureinpicture="val">text</iframe>
+<tfoot vlink="val">text</tfoot>
+<rb exportparts="val">text</rb>
+<big onreset="val">text</big>
+<img virtualkeyboardpolicy="val">text</img>
+<hr onpointermove="val">text</hr>
+<rt marginwidth="val">text</rt>
+<em media="val">text</em>
+<input rows="val">text</input>
+<data invisible="val">text</data>
+<blockquote ondragleave="val">text</blockquote>
+<section sizes="val">text</section>
+<script ondrop="val">text</script>
+<big controls="val">text</big>
+<datalist allow="val">text</datalist>
+<embed alt="val">text</embed>
+<button onbeforecut="val">text</button>
+<ul onplaying="val">text</ul>
+<input valuetype="val">text</input>
+<option formaction="val">text</option>
+<content invisible="val">text</content>
+<li nomodule="val">text</li>
+<code id="val">text</code>
+<track crossorigin="val">text</track>
+<td onseeked="val">text</td>
+<ul ontimezonechange="val">text</ul>
+<td summary="val">text</td>
+<nav target="val">text</nav>
+<tt onpointerup="val">text</tt>
+<li onwebkitanimationiteration="val">text</li>
+<bdi muted="val">text</bdi>
+<keygen onpointerup="val">text</keygen>
+<center class="val">text</center>
+<p onpagehide="val">text</p>
+<progress disablepictureinpicture="val">text</progress>
+<legend webkitdirectory="val">text</legend>
+<tfoot csp="val">text</tfoot>
+<strike oncanplay="val">text</strike>
+<ins onpointerdown="val">text</ins>
+<label usemap="val">text</label>
+<colgroup ondrag="val">text</colgroup>
+<nolayer autoplay="val">text</nolayer>
+<small ontouchstart="val">text</small>
+<h5 onpointerdown="val">text</h5>
+<script onanimationiteration="val">text</script>
+<code onbeforeunload="val">text</code>
+<video valign="val">text</video>
+<sub onoffline="val">text</sub>
+<dl leftmargin="val">text</dl>
+<strong charset="val">text</strong>
+<dt ongotpointercapture="val">text</dt>
+<form charoff="val">text</form>
+<progress autoplay="val">text</progress>
+<input onwebkitfullscreenchange="val">text</input>
+<acronym onwebkitanimationstart="val">text</acronym>
+<object link="val">text</object>
+<image kind="val">text</image>
+<progress conversiondestination="val">text</progress>
+<bdi onloadstart="val">text</bdi>
+<figcaption importance="val">text</figcaption>
+<applet readonly="val">text</applet>
+<header as="val">text</header>
+<progress lang="val">text</progress>
+<rt onmessage="val">text</rt>
+<noframes onlanguagechange="val">text</noframes>
+<frameset oncanplay="val">text</frameset>
+<h1 decoding="val">text</h1>
+<textarea high="val">text</textarea>
+<blockquote onratechange="val">text</blockquote>
+<link incremental="val">text</link>
+<small ontimeupdate="val">text</small>
+<embed compact="val">text</embed>
+<rt onselectstart="val">text</rt>
+<button is="val">text</button>
+<command background="val">text</command>
+<h6 hreftranslate="val">text</h6>
+<tfoot onseeking="val">text</tfoot>
+<dfn onpointerleave="val">text</dfn>
+<ins nomodule="val">text</ins>
+<ruby high="val">text</ruby>
+<rb csp="val">text</rb>
+<code low="val">text</code>
+<dir playsinline="val">text</dir>
+<th onbeforecopy="val">text</th>
+<thead challenge="val">text</thead>
+<layer onsubmit="val">text</layer>
+<th default="val">text</th>
+<dd language="val">text</dd>
+<nav onmessageerror="val">text</nav>
+<abbr src="val">text</abbr>
+<eprobe policy="val">text</eprobe>
+<li pseudo="val">text</li>
+<h6 class="val">text</h6>
+<script behavior="val">text</script>
+<noscript translate="val">text</noscript>
+<q onoffline="val">text</q>
+<big charoff="val">text</big>
+<del nohref="val">text</del>
+<noembed onorientationchange="val">text</noembed>
+<ins vlink="val">text</ins>
+<rb onplaying="val">text</rb>
+<aside exportparts="val">text</aside>
+<image media="val">text</image>
+<canvas background="val">text</canvas>
+<mark type="val">text</mark>
+<strong oncanplay="val">text</strong>
+<applet height="val">text</applet>
+<ins onsuspend="val">text</ins>
+<portal usemap="val">text</portal>
+<image datetime="val">text</image>
+<main onwebkitfullscreenchange="val">text</main>
+<main event="val">text</main>
+<keygen background="val">text</keygen>
+<datalist oncanplaythrough="val">text</datalist>
+<bdi kind="val">text</bdi>
+<applet onwheel="val">text</applet>
+<strike accesskey="val">text</strike>
+<section ondrag="val">text</section>
+<th onwebkitanimationstart="val">text</th>
+<dd target="val">text</dd>
+<em onbeforecut="val">text</em>
+<ol translate="val">text</ol>
+<content onwebkitanimationiteration="val">text</content>
+<audio onshow="val">text</audio>
+<i alt="val">text</i>
+<section onchange="val">text</section>
+<datalist onpointerup="val">text</datalist>
+<xmp enctype="val">text</xmp>
+<rb crossorigin="val">text</rb>
+<style download="val">text</style>
+<keygen autocomplete="val">text</keygen>
+<cite ongotpointercapture="val">text</cite>
+<xmp ismap="val">text</xmp>
+<output impressionexpiry="val">text</output>
+<dfn ontimezonechange="val">text</dfn>
+<big onwebkitanimationiteration="val">text</big>
+<strike event="val">text</strike>
+<p ontouchstart="val">text</p>
+<track cite="val">text</track>
+<noframes onpause="val">text</noframes>
+<style truespeed="val">text</style>
+<cite onpointerup="val">text</cite>
+<sup longdesc="val">text</sup>
+<nolayer onoverscroll="val">text</nolayer>
+<ruby oninput="val">text</ruby>
+<track target="val">text</track>
+<object onmouseup="val">text</object>
+<noembed code="val">text</noembed>
+<image sizes="val">text</image>
+<canvas integrity="val">text</canvas>
+<tt ondragover="val">text</tt>
+<label onpagehide="val">text</label>
+<address frameborder="val">text</address>
+<br onwebkitfullscreenerror="val">text</br>
+<image ondrop="val">text</image>
+<noframes part="val">text</noframes>
+<time download="val">text</time>
+<strong aprobe="val">text</strong>
+<i onoverscroll="val">text</i>
+<rb incremental="val">text</rb>
+<figcaption onmouseout="val">text</figcaption>
+<fieldset onmouseup="val">text</fieldset>
+<main form="val">text</main>
+<img autofocus="val">text</img>
+<tfoot ondurationchange="val">text</tfoot>
+<slot action="val">text</slot>
+<audio behavior="val">text</audio>
+<del onpopstate="val">text</del>
+<layer list="val">text</layer>
+<sub ononline="val">text</sub>
+<a inputmode="val">text</a>
+<kbd enterkeyhint="val">text</kbd>
+<h1 charset="val">text</h1>
+<ul maxlength="val">text</ul>
+<eprobe cols="val">text</eprobe>
+<link onscrollend="val">text</link>
+<p colspan="val">text</p>
+<iframe ondragleave="val">text</iframe>
+<dir name="val">text</dir>
+<li translate="val">text</li>
+<mark impressiondata="val">text</mark>
+<video ondragstart="val">text</video>
+<noframes nomodule="val">text</noframes>
+<noscript classid="val">text</noscript>
+<script loop="val">text</script>
+<figcaption controls="val">text</figcaption>
+<var virtualkeyboardpolicy="val">text</var>
+<h3 shape="val">text</h3>
+<kbd noresize="val">text</kbd>
+<ul onchange="val">text</ul>
+<strong invisible="val">text</strong>
+<form onprogress="val">text</form>
+<xmp capture="val">text</xmp>
+<xmp noresize="val">text</xmp>
+<h1 face="val">text</h1>
+<col ondrag="val">text</col>
+<content imagesrcset="val">text</content>
+<mark datetime="val">text</mark>
+<keygen marginwidth="val">text</keygen>
+<dt sizes="val">text</dt>
+<tbody disableremoteplayback="val">text</tbody>
+<nav onwebkitfullscreenerror="val">text</nav>
+<applet onkeydown="val">text</applet>
+<strike role="val">text</strike>
+<optgroup for="val">text</optgroup>
+<ul hreftranslate="val">text</ul>
+<abbr size="val">text</abbr>
+<legend onbeforecut="val">text</legend>
+<q onscroll="val">text</q>
+<h5 frameborder="val">text</h5>
+<abbr aprobe="val">text</abbr>
+<mark onmousemove="val">text</mark>
+<hgroup reportingorigin="val">text</hgroup>
+<kbd data="val">text</kbd>
+<ul charoff="val">text</ul>
+<col oncanplaythrough="val">text</col>
+<var onmouseup="val">text</var>
+<strong onblur="val">text</strong>
+<var usemap="val">text</var>
+<nolayer oncut="val">text</nolayer>
+<command oncuechange="val">text</command>
+<rt direction="val">text</rt>
+<datalist form="val">text</datalist>
+<rtc headers="val">text</rtc>
+<dfn oninvalid="val">text</dfn>
+<link onafterprint="val">text</link>
+<small code="val">text</small>
+<article start="val">text</article>
+<acronym ongotpointercapture="val">text</acronym>
+<nav ondragover="val">text</nav>
+<command ononline="val">text</command>
+<strike pseudo="val">text</strike>
+<nolayer onorientationchange="val">text</nolayer>
+<rp truespeed="val">text</rp>
+<tbody oninvalid="val">text</tbody>
+<basefont hspace="val">text</basefont>
+<slot sizes="val">text</slot>
+<content onpopstate="val">text</content>
+<noscript onmessageerror="val">text</noscript>
+<slot async="val">text</slot>
+<main code="val">text</main>
+<slot cite="val">text</slot>
+<bdo onmessage="val">text</bdo>
+<s align="val">text</s>
+<article hreftranslate="val">text</article>
+<center onvolumechange="val">text</center>
+<dfn style="val">text</dfn>
+<summary charoff="val">text</summary>
+<strong oncut="val">text</strong>
+<li manifest="val">text</li>
+<s start="val">text</s>
+<legend autoplay="val">text</legend>
+<bdi ismap="val">text</bdi>
+<eprobe onscroll="val">text</eprobe>
+<h6 max="val">text</h6>
+<tbody onhashchange="val">text</tbody>
+<q accept-charset="val">text</q>
+<tr ondrop="val">text</tr>
+<nobr rows="val">text</nobr>
+<embed trusttoken="val">text</embed>
+<sup accesskey="val">text</sup>
+<dt virtualkeyboardpolicy="val">text</dt>
+<script onkeyup="val">text</script>
+<meter onbeforeprint="val">text</meter>
+<output onwebkitanimationstart="val">text</output>
+<bgsound oncuechange="val">text</bgsound>
+<sub onpagehide="val">text</sub>
+<dt autoplay="val">text</dt>
+<aside value="val">text</aside>
+<aside min="val">text</aside>
+<command nonce="val">text</command>
+<data usemap="val">text</data>
+<small preload="val">text</small>
+<sup reversed="val">text</sup>
+<h4 label="val">text</h4>
+<bdi onbeforepaste="val">text</bdi>
+<link onformdata="val">text</link>
+<object onbeforeunload="val">text</object>
+<noframes max="val">text</noframes>
+<h5 onbeforepaste="val">text</h5>
+<button frameborder="val">text</button>
+<ruby valign="val">text</ruby>
+<header style="val">text</header>
+<eprobe headers="val">text</eprobe>
+<layer onpagehide="val">text</layer>
+<embed onbeforeprint="val">text</embed>
+<ins imagesrcset="val">text</ins>
+<image onpause="val">text</image>
+<rt oncanplay="val">text</rt>
+<nobr controls="val">text</nobr>
+<dd onsuspend="val">text</dd>
+<thead as="val">text</thead>
+<address ontimezonechange="val">text</address>
+<tbody trusttoken="val">text</tbody>
+<basefont language="val">text</basefont>
+<meter onpointercancel="val">text</meter>
+<frameset autocomplete="val">text</frameset>
+<rt autoplay="val">text</rt>
+<ul nomodule="val">text</ul>
+<iframe longdesc="val">text</iframe>
+<fieldset onbeforeunload="val">text</fieldset>
+<bdi part="val">text</bdi>
+<meter contenteditable="val">text</meter>
+<samp style="val">text</samp>
+<applet onabort="val">text</applet>
+<header enctype="val">text</header>
+<plaintext onmessage="val">text</plaintext>
+<content onloadeddata="val">text</content>
+<dd summary="val">text</dd>
+<header usemap="val">text</header>
+<caption playsinline="val">text</caption>
+<textarea shadowrootdelegatesfocus="val">text</textarea>
+<acronym onportalactivate="val">text</acronym>
+<cite autocomplete="val">text</cite>
+<canvas border="val">text</canvas>
+<basefont data="val">text</basefont>
+<strike onpointerup="val">text</strike>
+<textarea end="val">text</textarea>
+<nolayer valign="val">text</nolayer>
+<h2 scrolldelay="val">text</h2>
+<big oncontextmenu="val">text</big>
+<input onmouseup="val">text</input>
+<aside onmouseout="val">text</aside>
+<caption datetime="val">text</caption>
+<i oncopy="val">text</i>
+<sub color="val">text</sub>
+<ul onwebkitanimationend="val">text</ul>
+<abbr onprogress="val">text</abbr>
+<footer preload="val">text</footer>
+<noscript onmousewheel="val">text</noscript>
+<acronym translate="val">text</acronym>
+<bdi topmargin="val">text</bdi>
+<tfoot onlanguagechange="val">text</tfoot>
+<thead onpointerdown="val">text</thead>
+<u noresize="val">text</u>
+<noembed kind="val">text</noembed>
+<picture ontouchcancel="val">text</picture>
+<th size="val">text</th>
+<dl onloadstart="val">text</dl>
+<ol minlength="val">text</ol>
+<h4 disabled="val">text</h4>
+<li tabindex="val">text</li>
+<hr inert="val">text</hr>
+<shadow form="val">text</shadow>
+<dl nowrap="val">text</dl>
+<abbr onerror="val">text</abbr>
+<li declare="val">text</li>
+<ins declare="val">text</ins>
+<input novalidate="val">text</input>
+<address ontoggle="val">text</address>
+<time inert="val">text</time>
+<dfn novalidate="val">text</dfn>
+<track onwebkitanimationend="val">text</track>
+<dt hreflang="val">text</dt>
+<rb onpointerdown="val">text</rb>
+<nobr text="val">text</nobr>
+<var onpointercancel="val">text</var>
+<output onmouseup="val">text</output>
+<button open="val">text</button>
+<input onsuspend="val">text</input>
+<cite lang="val">text</cite>
+<audio alt="val">text</audio>
+<article shape="val">text</article>
+<samp colspan="val">text</samp>
+<article muted="val">text</article>
+<script onanimationend="val">text</script>
+<data onfocusin="val">text</data>
+<th importance="val">text</th>
+<listing onpointercancel="val">text</listing>
+<ol onkeydown="val">text</ol>
+<shadow checked="val">text</shadow>
+<progress onvolumechange="val">text</progress>
+<big latencyhint="val">text</big>
+<center onscrollend="val">text</center>
+<em autoplay="val">text</em>
+<figure classid="val">text</figure>
+<rt ontouchstart="val">text</rt>
+<progress ondrag="val">text</progress>
+<img srcdoc="val">text</img>
+<h6 ondragenter="val">text</h6>
+<canvas ontouchmove="val">text</canvas>
+<progress onselect="val">text</progress>
+<col onseeked="val">text</col>
+<bgsound border="val">text</bgsound>
+<aside cite="val">text</aside>
+<audio marginheight="val">text</audio>
+<blockquote allow="val">text</blockquote>
+<hgroup ondblclick="val">text</hgroup>
+<xmp allowfullscreen="val">text</xmp>
+<optgroup accesskey="val">text</optgroup>
+<canvas frame="val">text</canvas>
+<main onpointerover="val">text</main>
+<fieldset leftmargin="val">text</fieldset>
+<object ontimeupdate="val">text</object>
+<layer text="val">text</layer>
+<output>text</output>
+<meter abbr="val">text</meter>
+<label policy="val">text</label>
+<legend onload="val">text</legend>
+<bgsound onloadeddata="val">text</bgsound>
+<progress valuetype="val">text</progress>
+<eprobe id="val">text</eprobe>
+<h4 ontouchstart="val">text</h4>
+<sub role="val">text</sub>
+<ol high="val">text</ol>
+<option onkeydown="val">text</option>
+<fieldset hidden="val">text</fieldset>
+<center inputmode="val">text</center>
+<form ondragend="val">text</form>
+<rt nowrap="val">text</rt>
+<address onauxclick="val">text</address>
+<ruby onpointerenter="val">text</ruby>
+<data ontouchstart="val">text</data>
+<applet onmessageerror="val">text</applet>
+<command onloadeddata="val">text</command>
+<slot http-equiv="val">text</slot>
+<strong reportingorigin="val">text</strong>
+<applet ondragstart="val">text</applet>
+<video onsubmit="val">text</video>
+<embed high="val">text</embed>
+<listing type="val">text</listing>
+<optgroup onratechange="val">text</optgroup>
+<rtc cellpadding="val">text</rtc>
+<form oncuechange="val">text</form>
+<dt onlostpointercapture="val">text</dt>
+<slot autoplay="val">text</slot>
+<big onfocus="val">text</big>
+<caption inert="val">text</caption>
+<rp onoverscroll="val">text</rp>
+<sub incremental="val">text</sub>
+<plaintext controls="val">text</plaintext>
+<figcaption onorientationchange="val">text</figcaption>
+<ins leftmargin="val">text</ins>
+<blockquote onpointerout="val">text</blockquote>
+<strong src="val">text</strong>
+<i char="val">text</i>
+<p onwebkitfullscreenerror="val">text</p>
+<sub cols="val">text</sub>
+<noscript imagesizes="val">text</noscript>
+<command onshow="val">text</command>
+<style onbeforeprint="val">text</style>
+<h3 playsinline="val">text</h3>
+<object axis="val">text</object>
+<label onkeypress="val">text</label>
+<u ondragleave="val">text</u>
+<br archive="val">text</br>
+<colgroup onauxclick="val">text</colgroup>
+<figcaption behavior="val">text</figcaption>
+<slot accept-charset="val">text</slot>
+<rp topmargin="val">text</rp>
+<th scrolldelay="val">text</th>
+<bgsound onwaiting="val">text</bgsound>
+<hr readonly="val">text</hr>
+<basefont coords="val">text</basefont>
+<eprobe onmousemove="val">text</eprobe>
+<image impressionexpiry="val">text</image>
+<fieldset dirname="val">text</fieldset>
+<button hreflang="val">text</button>
+<mark align="val">text</mark>
+<listing onoverscroll="val">text</listing>
+<noscript scope="val">text</noscript>
+<noembed cite="val">text</noembed>
+<summary onchange="val">text</summary>
+<var rel="val">text</var>
+<style challenge="val">text</style>
+<form onerror="val">text</form>
+<sub optimum="val">text</sub>
+<samp wrap="val">text</samp>
+<shadow onkeyup="val">text</shadow>
+<noframes onload="val">text</noframes>
+<center kind="val">text</center>
+<fieldset onkeypress="val">text</fieldset>
+<abbr onorientationchange="val">text</abbr>
+<form label="val">text</form>
+<layer decoding="val">text</layer>
+<ins for="val">text</ins>
+<h2 shape="val">text</h2>
+<data src="val">text</data>
+<address onpopstate="val">text</address>
+<u disabled="val">text</u>
+<label ondblclick="val">text</label>
+<bdo impressiondata="val">text</bdo>
+<portal readonly="val">text</portal>
+<button value="val">text</button>
+<article oncanplaythrough="val">text</article>
+<em oncut="val">text</em>
+<em wrap="val">text</em>
+<hgroup impressiondata="val">text</hgroup>
+<th sandbox="val">text</th>
+<plaintext tabindex="val">text</plaintext>
+<script standby="val">text</script>
+<li archive="val">text</li>
+<figcaption onmouseup="val">text</figcaption>
+<basefont latencyhint="val">text</basefont>
+<embed headers="val">text</embed>
+<h6 language="val">text</h6>
+<code keytype="val">text</code>
+<button nohref="val">text</button>
+<samp valuetype="val">text</samp>
+<img archive="val">text</img>
+<samp marginheight="val">text</samp>
+<figure allow="val">text</figure>
+<datalist ondragend="val">text</datalist>
+<noscript srcset="val">text</noscript>
+<fieldset shape="val">text</fieldset>
+<nav onseeked="val">text</nav>
+<ruby controlslist="val">text</ruby>
+<a style="val">text</a>
+<shadow title="val">text</shadow>
+<image onstorage="val">text</image>
+<address media="val">text</address>
+<address ontimeupdate="val">text</address>
+<option size="val">text</option>
+<xmp multiple="val">text</xmp>
+<command onwheel="val">text</command>
+<h2 onmousemove="val">text</h2>
+<tbody async="val">text</tbody>
+<frameset code="val">text</frameset>
+<sup onpointerout="val">text</sup>
+<object onfocusin="val">text</object>
+<u onwaiting="val">text</u>
+<shadow list="val">text</shadow>
+<blockquote trusttoken="val">text</blockquote>
+<bdi onpageshow="val">text</bdi>
+<form onbeforepaste="val">text</form>
+<h5 target="val">text</h5>
+<layer rel="val">text</layer>
+<summary cellspacing="val">text</summary>
+<audio abbr="val">text</audio>
+<h6 dirname="val">text</h6>
+<br codebase="val">text</br>
+<dd rows="val">text</dd>
+<sup onorientationchange="val">text</sup>
+<sub cellspacing="val">text</sub>
+<data size="val">text</data>
+<h3 invisible="val">text</h3>
+<cite part="val">text</cite>
+<del nonce="val">text</del>
+<code exportparts="val">text</code>
+<slot longdesc="val">text</slot>
+<abbr truespeed="val">text</abbr>
+<link onpagehide="val">text</link>
+<h4 nohref="val">text</h4>
+<applet longdesc="val">text</applet>
+<layer charset="val">text</layer>
+<rp bgcolor="val">text</rp>
+<layer onwebkittransitionend="val">text</layer>
+<figure height="val">text</figure>
+<q high="val">text</q>
+<blockquote onpagehide="val">text</blockquote>
+<object disabled="val">text</object>
+<article vlink="val">text</article>
+<applet keytype="val">text</applet>
+<center onpointerrawupdate="val">text</center>
+<track onafterprint="val">text</track>
+<video char="val">text</video>
+<optgroup ontimeupdate="val">text</optgroup>
+<form csp="val">text</form>
+<tbody end="val">text</tbody>
+<strike href="val">text</strike>
+<select step="val">text</select>
+<shadow longdesc="val">text</shadow>
+<track noshade="val">text</track>
+<code allowpaymentrequest="val">text</code>
+<wbr marginwidth="val">text</wbr>
+<button ondrop="val">text</button>
+<nav compact="val">text</nav>
+<hgroup action="val">text</hgroup>
+<style onstorage="val">text</style>
+<colgroup oncuechange="val">text</colgroup>
+<bgsound href="val">text</bgsound>
+<layer http-equiv="val">text</layer>
+<basefont rules="val">text</basefont>
+<time onmouseover="val">text</time>
+<dd onpaste="val">text</dd>
+<wbr incremental="val">text</wbr>
+<sup lang="val">text</sup>
+<track compact="val">text</track>
+<tfoot onclose="val">text</tfoot>
+<bgsound charset="val">text</bgsound>
+<hr onafterprint="val">text</hr>
+<rtc topmargin="val">text</rtc>
+<h6 lang="val">text</h6>
+<del referrerpolicy="val">text</del>
+<picture frame="val">text</picture>
+<h3 onportalactivate="val">text</h3>
+<embed leftmargin="val">text</embed>
+<sub inputmode="val">text</sub>
+<option required="val">text</option>
+<keygen capture="val">text</keygen>
+<main ondblclick="val">text</main>
+<nobr rules="val">text</nobr>
+<tbody onratechange="val">text</tbody>
+<cite ondurationchange="val">text</cite>
+<portal ontimeupdate="val">text</portal>
+<caption onresize="val">text</caption>
+<applet charoff="val">text</applet>
+<dd webkitdirectory="val">text</dd>
+<legend onwebkitanimationiteration="val">text</legend>
+<colgroup text="val">text</colgroup>
+<slot select="val">text</slot>
+<rt bordercolor="val">text</rt>
+<select onvolumechange="val">text</select>
+<q codetype="val">text</q>
+<fieldset inert="val">text</fieldset>
+<img async="val">text</img>
+<center onpointerleave="val">text</center>
+<embed oncopy="val">text</embed>
+<image conversiondestination="val">text</image>
+<style conversiondestination="val">text</style>
+<kbd allow="val">text</kbd>
+<article rows="val">text</article>
+<bdi axis="val">text</bdi>
+<h2 onabort="val">text</h2>
+<noembed oncanplay="val">text</noembed>
+<nav onclose="val">text</nav>
+<h5 charoff="val">text</h5>
+<listing formnovalidate="val">text</listing>
+<label>text</label>
+<tfoot srclang="val">text</tfoot>
+<main marginwidth="val">text</main>
+<h2 classid="val">text</h2>
+<wbr hspace="val">text</wbr>
+<samp onportalactivate="val">text</samp>
+<wbr truespeed="val">text</wbr>
+<big ontouchmove="val">text</big>
+<acronym elementtiming="val">text</acronym>
+<meter onpopstate="val">text</meter>
+<basefont nomodule="val">text</basefont>
+<aside color="val">text</aside>
+<iframe truespeed="val">text</iframe>
+<iframe onabort="val">text</iframe>
+<dir bordercolor="val">text</dir>
+<meter colspan="val">text</meter>
+<q clear="val">text</q>
+<cite onseeking="val">text</cite>
+<track loading="val">text</track>
+<em onpageshow="val">text</em>
+<br link="val">text</br>
+<th preload="val">text</th>
+<dir onblur="val">text</dir>
+<small accept="val">text</small>
+<summary formnovalidate="val">text</summary>
+<caption onabort="val">text</caption>
+<shadow onunload="val">text</shadow>
+<h5 lowsrc="val">text</h5>
+<optgroup defer="val">text</optgroup>
+<fieldset onmouseover="val">text</fieldset>
+<hgroup oninput="val">text</hgroup>
+<basefont checked="val">text</basefont>
+<header topmargin="val">text</header>
+<b oncancel="val">text</b>
+<listing declare="val">text</listing>
+<a low="val">text</a>
+<tbody abbr="val">text</tbody>
+<command spellcheck="val">text</command>
+<wbr srclang="val">text</wbr>
+<rtc cols="val">text</rtc>
+<mark hreftranslate="val">text</mark>
+<track onwebkittransitionend="val">text</track>
+<bdi bgcolor="val">text</bdi>
+<meter hspace="val">text</meter>
+<i ping="val">text</i>
+<tt defer="val">text</tt>
+<image onmessage="val">text</image>
+<b datetime="val">text</b>
+<layer onpointercancel="val">text</layer>
+<figure defer="val">text</figure>
+<figure onmessageerror="val">text</figure>
+<eprobe invisible="val">text</eprobe>
+<col onfocus="val">text</col>
+<s onselectstart="val">text</s>
+<p download="val">text</p>
+<rtc ontimeupdate="val">text</rtc>
+<audio onbeforecopy="val">text</audio>
+<dd codebase="val">text</dd>
+<noembed scheme="val">text</noembed>
+<nolayer cols="val">text</nolayer>
+<main ontouchstart="val">text</main>
+<h4 defer="val">text</h4>
+<thead src="val">text</thead>
+<style shape="val">text</style>
+<form contenteditable="val">text</form>
+<img integrity="val">text</img>
+<h4 onbeforepaste="val">text</h4>
+<del onabort="val">text</del>
+<abbr keytype="val">text</abbr>
+<noframes onwebkittransitionend="val">text</noframes>
+<th truespeed="val">text</th>
+<xmp onpointercancel="val">text</xmp>
+<rp alt="val">text</rp>
+<basefont onpageshow="val">text</basefont>
+<dt onmousewheel="val">text</dt>
+<samp nohref="val">text</samp>
+<h5 axis="val">text</h5>
+<output formtarget="val">text</output>
+<h3 hidden="val">text</h3>
+<datalist checked="val">text</datalist>
+<dfn direction="val">text</dfn>
+<section border="val">text</section>
+<noframes onsearch="val">text</noframes>
+<p minlength="val">text</p>
+<img standby="val">text</img>
+<big dirname="val">text</big>
+<b onsearch="val">text</b>
+<header conversiondestination="val">text</header>
+<article target="val">text</article>
+<content onhashchange="val">text</content>
+<meter onseeked="val">text</meter>
+<style shadowroot="val">text</style>
+<a onabort="val">text</a>
+<code onbeforepaste="val">text</code>
+<h1 noresize="val">text</h1>
+<listing ontimezonechange="val">text</listing>
+<ul ismap="val">text</ul>
+<caption onafterprint="val">text</caption>
+<br oncanplaythrough="val">text</br>
+<li align="val">text</li>
+<h4 onseeking="val">text</h4>
+<time onfocusin="val">text</time>
+<ul onpagehide="val">text</ul>
+<rb dirname="val">text</rb>
+<bdo onpageshow="val">text</bdo>
+<link onkeypress="val">text</link>
+<plaintext onorientationchange="val">text</plaintext>
+<figcaption required="val">text</figcaption>
+<noembed class="val">text</noembed>
+<samp crossorigin="val">text</samp>
+<i allow="val">text</i>
+<embed max="val">text</embed>
+<h5 trusttoken="val">text</h5>
+<main onemptied="val">text</main>
+<li disableremoteplayback="val">text</li>
+<blockquote inputmode="val">text</blockquote>
+<ins onwebkitanimationend="val">text</ins>
+<layer policy="val">text</layer>
+<input maxlength="val">text</input>
+<ruby onprogress="val">text</ruby>
+<progress action="val">text</progress>
+<ul aprobe="val">text</ul>
+<layer checked="val">text</layer>
+<select for="val">text</select>
+<noframes autocapitalize="val">text</noframes>
+<h6 virtualkeyboardpolicy="val">text</h6>
+<sup onselectstart="val">text</sup>
+<em shape="val">text</em>
+<basefont contenteditable="val">text</basefont>
+<progress ontouchmove="val">text</progress>
+<frameset action="val">text</frameset>
+<keygen elementtiming="val">text</keygen>
+<i onselectstart="val">text</i>
+<wbr clear="val">text</wbr>
+<th onended="val">text</th>
+<li version="val">text</li>
+<style srcdoc="val">text</style>
+<u pattern="val">text</u>
+<legend oncontextmenu="val">text</legend>
+<select ondrop="val">text</select>
+<b onratechange="val">text</b>
+<hgroup ondurationchange="val">text</hgroup>
+<select virtualkeyboardpolicy="val">text</select>
+<nav rows="val">text</nav>
+<output marginheight="val">text</output>
+<content class="val">text</content>
+<basefont ontouchcancel="val">text</basefont>
+<b title="val">text</b>
+<bdi virtualkeyboardpolicy="val">text</bdi>
+<big required="val">text</big>
+<h6 formaction="val">text</h6>
+<figure charoff="val">text</figure>
+<figcaption onplaying="val">text</figcaption>
+<select standby="val">text</select>
+<rtc onbeforecut="val">text</rtc>
+<section tabindex="val">text</section>
+<link onclose="val">text</link>
+<textarea onkeypress="val">text</textarea>
+<tr aprobe="val">text</tr>
+<var onprobe="val">text</var>
+<iframe playsinline="val">text</iframe>
+<center scrolling="val">text</center>
+<main bgcolor="val">text</main>
+<tt rows="val">text</tt>
+<listing slot="val">text</listing>
+<article onkeypress="val">text</article>
+<section onreset="val">text</section>
+<content oncut="val">text</content>
+<hr loading="val">text</hr>
+<dfn language="val">text</dfn>
+<nobr onpaste="val">text</nobr>
+<h4 onwebkitfullscreenerror="val">text</h4>
+<bdi ontimezonechange="val">text</bdi>
+<nolayer onclick="val">text</nolayer>
+<del onmouseout="val">text</del>
+<h4 onscrollend="val">text</h4>
+<noscript nohref="val">text</noscript>
+<bdo hreflang="val">text</bdo>
+<main value="val">text</main>
+<sub http-equiv="val">text</sub>
+<q placeholder="val">text</q>
+<frameset latencyhint="val">text</frameset>
+<h5 bordercolor="val">text</h5>
+<rtc formenctype="val">text</rtc>
+<h3 readonly="val">text</h3>
+<progress style="val">text</progress>
+<h3 formmethod="val">text</h3>
+<layer version="val">text</layer>
+<small onmouseleave="val">text</small>
+<tbody disablepictureinpicture="val">text</tbody>
+<u srclang="val">text</u>
+<style virtualkeyboardpolicy="val">text</style>
+<blockquote target="val">text</blockquote>
+<th onmouseout="val">text</th>
+<noscript onanimationend="val">text</noscript>
+<video onwebkitfullscreenchange="val">text</video>
+<nobr onstalled="val">text</nobr>
+<figcaption onwebkitanimationstart="val">text</figcaption>
+<dt reversed="val">text</dt>
+<code summary="val">text</code>
+<meter onchange="val">text</meter>
+<dd onpointerup="val">text</dd>
+<picture onpaste="val">text</picture>
+<em pattern="val">text</em>
+<em preload="val">text</em>
+<var capture="val">text</var>
+<picture onpointerup="val">text</picture>
+<nav scrollamount="val">text</nav>
+<h5 max="val">text</h5>
+<td onpointerleave="val">text</td>
+<h1 incremental="val">text</h1>
+<s clear="val">text</s>
+<command content="val">text</command>
+<thead onpageshow="val">text</thead>
+<strong onsuspend="val">text</strong>
+<blockquote ontransitionend="val">text</blockquote>
+<content onpointermove="val">text</content>
+<section imagesizes="val">text</section>
+<canvas end="val">text</canvas>
+<figure onportalactivate="val">text</figure>
+<colgroup nohref="val">text</colgroup>
+<big novalidate="val">text</big>
+<hr formenctype="val">text</hr>
+<del onshow="val">text</del>
+<header ondrag="val">text</header>
+<iframe autocorrect="val">text</iframe>
+<caption headers="val">text</caption>
+<figcaption lang="val">text</figcaption>
+<figcaption ontouchmove="val">text</figcaption>
+<object onorientationchange="val">text</object>
+<h6 imagesrcset="val">text</h6>
+<td onbeforepaste="val">text</td>
+<optgroup autofocus="val">text</optgroup>
+<nobr ondragover="val">text</nobr>
+<datalist onfocusout="val">text</datalist>
+<figcaption onloadedmetadata="val">text</figcaption>
+<nolayer onseeked="val">text</nolayer>
+<br object="val">text</br>
+<h1 ontransitionend="val">text</h1>
+<meter vspace="val">text</meter>
+<applet usemap="val">text</applet>
+<rtc colspan="val">text</rtc>
+<canvas controls="val">text</canvas>
+<basefont oncuechange="val">text</basefont>
+<caption name="val">text</caption>
+<p onbeforepaste="val">text</p>
+<li leftmargin="val">text</li>
+<time dirname="val">text</time>
+<picture inert="val">text</picture>
+<br allowfullscreen="val">text</br>
+<q trusttoken="val">text</q>
+<code ondragend="val">text</code>
+<portal oncuechange="val">text</portal>
+<ruby ondragover="val">text</ruby>
+<output keytype="val">text</output>
+<eprobe oncuechange="val">text</eprobe>
+<meter http-equiv="val">text</meter>
+<dir rules="val">text</dir>
+<image ondragend="val">text</image>
+<nav oncancel="val">text</nav>
+<li disablepictureinpicture="val">text</li>
+<ruby required="val">text</ruby>
+<ol webkitdirectory="val">text</ol>
+<dir srcdoc="val">text</dir>
+<bgsound leftmargin="val">text</bgsound>
+<dir onanimationiteration="val">text</dir>
+<canvas scrolling="val">text</canvas>
+<big align="val">text</big>
+<noembed onpointerenter="val">text</noembed>
+<picture autocorrect="val">text</picture>
+<ruby download="val">text</ruby>
+<big autoplay="val">text</big>
+<caption onwebkitfullscreenchange="val">text</caption>
+<audio lowsrc="val">text</audio>
+<col integrity="val">text</col>
+<cite onpointerleave="val">text</cite>
+<canvas onplay="val">text</canvas>
+<form onorientationchange="val">text</form>
+<object compact="val">text</object>
+<input onfocusin="val">text</input>
+<nolayer accept="val">text</nolayer>
+<track ontimezonechange="val">text</track>
+<frameset onoffline="val">text</frameset>
+<textarea accept="val">text</textarea>
+<basefont required="val">text</basefont>
+<tfoot text="val">text</tfoot>
+<caption frame="val">text</caption>
+<h2 onpause="val">text</h2>
+<button char="val">text</button>
+<em exportparts="val">text</em>
+<h5 allow="val">text</h5>
+<em vspace="val">text</em>
+<keygen impressionexpiry="val">text</keygen>
+<ol onpause="val">text</ol>
+<caption conversiondestination="val">text</caption>
+<img onbeforecopy="val">text</img>
+<nav onhashchange="val">text</nav>
+<object allowfullscreen="val">text</object>
+<dfn challenge="val">text</dfn>
+<main spellcheck="val">text</main>
+<h1 onresize="val">text</h1>
+<bgsound incremental="val">text</bgsound>
+<caption archive="val">text</caption>
+<a ondragover="val">text</a>
+<tbody inputmode="val">text</tbody>
+<bgsound lowsrc="val">text</bgsound>
+<tfoot is="val">text</tfoot>
+<video start="val">text</video>
+<progress codetype="val">text</progress>
+<plaintext ondblclick="val">text</plaintext>
+<br lowsrc="val">text</br>
+<nolayer pattern="val">text</nolayer>
+<style disallowdocumentaccess="val">text</style>
+<progress onbeforeprint="val">text</progress>
+<tfoot abbr="val">text</tfoot>
+<h5 controls="val">text</h5>
+<hr version="val">text</hr>
+<strike onselectstart="val">text</strike>
+<h3 clear="val">text</h3>
+<small onplaying="val">text</small>
+<tbody scope="val">text</tbody>
+<td span="val">text</td>
+<shadow ontouchcancel="val">text</shadow>
+<big for="val">text</big>
+<content media="val">text</content>
+<tbody onlanguagechange="val">text</tbody>
+<keygen ondragenter="val">text</keygen>
+<ins onmouseleave="val">text</ins>
+<ruby scope="val">text</ruby>
+<nav src="val">text</nav>
+<shadow part="val">text</shadow>
+<rp latencyhint="val">text</rp>
+<nolayer width="val">text</nolayer>
+<listing default="val">text</listing>
+<nolayer noshade="val">text</nolayer>
+<option charset="val">text</option>
+<ruby mayscript="val">text</ruby>
+<i colspan="val">text</i>
+<b onwebkittransitionend="val">text</b>
+<center onbeforecut="val">text</center>
+<mark onshow="val">text</mark>
+<aside conversiondestination="val">text</aside>
+<del media="val">text</del>
+<samp select="val">text</samp>
+<input colspan="val">text</input>
+<plaintext contenteditable="val">text</plaintext>
+<optgroup select="val">text</optgroup>
+<frameset accept="val">text</frameset>
+<keygen latencyhint="val">text</keygen>
+<h3 reversed="val">text</h3>
+<h6 decoding="val">text</h6>
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium3.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium3.html
new file mode 100644
index 00000000000..766aae878b9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/medium3.html
@@ -0,0 +1,1000 @@
+<rtc placeholder="val">text</rtc>
+<rp onlanguagechange="val">text</rp>
+<data loop="val">text</data>
+<tbody async="val">text</tbody>
+<track onpause="val">text</track>
+<aside onstorage="val">text</aside>
+<canvas part="val">text</canvas>
+<picture as="val">text</picture>
+<code sandbox="val">text</code>
+<textarea onseeking="val">text</textarea>
+<link list="val">text</link>
+<hgroup hidden="val">text</hgroup>
+<style onpointerrawupdate="val">text</style>
+<col alink="val">text</col>
+<option ononline="val">text</option>
+<layer ononline="val">text</layer>
+<dir imagesizes="val">text</dir>
+<xmp onpopstate="val">text</xmp>
+<h6 contenteditable="val">text</h6>
+<col nomodule="val">text</col>
+<bdo href="val">text</bdo>
+<h5 allow="val">text</h5>
+<colgroup colspan="val">text</colgroup>
+<nolayer ondurationchange="val">text</nolayer>
+<applet onmouseup="val">text</applet>
+<content onmessage="val">text</content>
+<kbd rules="val">text</kbd>
+<nolayer sandbox="val">text</nolayer>
+<ol onplaying="val">text</ol>
+<basefont onmouseenter="val">text</basefont>
+<code mayscript="val">text</code>
+<center formnovalidate="val">text</center>
+<listing vspace="val">text</listing>
+<b>text</b>
+<input scrolling="val">text</input>
+<h6 muted="val">text</h6>
+<legend alink="val">text</legend>
+<code importance="val">text</code>
+<a srclang="val">text</a>
+<h1 onplay="val">text</h1>
+<u codetype="val">text</u>
+<li imagesizes="val">text</li>
+<summary srcdoc="val">text</summary>
+<br onauxclick="val">text</br>
+<article autoplay="val">text</article>
+<col ontimeupdate="val">text</col>
+<audio shadowroot="val">text</audio>
+<figure scope="val">text</figure>
+<noscript onprobe="val">text</noscript>
+<figure onprogress="val">text</figure>
+<dl onfocusout="val">text</dl>
+<dt onstorage="val">text</dt>
+<section scrollamount="val">text</section>
+<iframe name="val">text</iframe>
+<basefont color="val">text</basefont>
+<bdo style="val">text</bdo>
+<style rev="val">text</style>
+<caption allowpaymentrequest="val">text</caption>
+<h1 standby="val">text</h1>
+<dd ontimeupdate="val">text</dd>
+<content disablepictureinpicture="val">text</content>
+<nav title="val">text</nav>
+<strike charoff="val">text</strike>
+<dd vlink="val">text</dd>
+<meter onpointerenter="val">text</meter>
+<caption ondblclick="val">text</caption>
+<caption scheme="val">text</caption>
+<abbr step="val">text</abbr>
+<center ontouchstart="val">text</center>
+<nav span="val">text</nav>
+<section dir="val">text</section>
+<label novalidate="val">text</label>
+<acronym oninput="val">text</acronym>
+<dt ondragenter="val">text</dt>
+<section autopictureinpicture="val">text</section>
+<frameset onpopstate="val">text</frameset>
+<q onselectionchange="val">text</q>
+<h2 headers="val">text</h2>
+<rb formaction="val">text</rb>
+<var onload="val">text</var>
+<p kind="val">text</p>
+<blockquote direction="val">text</blockquote>
+<acronym id="val">text</acronym>
+<rb onbeforecopy="val">text</rb>
+<bdi maxlength="val">text</bdi>
+<abbr media="val">text</abbr>
+<figcaption oninput="val">text</figcaption>
+<layer poster="val">text</layer>
+<basefont codebase="val">text</basefont>
+<keygen onpopstate="val">text</keygen>
+<portal onhashchange="val">text</portal>
+<dt reportingorigin="val">text</dt>
+<td impressionexpiry="val">text</td>
+<li cols="val">text</li>
+<canvas value="val">text</canvas>
+<aside hreflang="val">text</aside>
+<textarea onmouseup="val">text</textarea>
+<iframe accept="val">text</iframe>
+<img formenctype="val">text</img>
+<iframe required="val">text</iframe>
+<progress scheme="val">text</progress>
+<kbd challenge="val">text</kbd>
+<portal async="val">text</portal>
+<address onpagehide="val">text</address>
+<th content="val">text</th>
+<hgroup scrollamount="val">text</hgroup>
+<dir size="val">text</dir>
+<bgsound rowspan="val">text</bgsound>
+<form required="val">text</form>
+<datalist disableremoteplayback="val">text</datalist>
+<dir inputmode="val">text</dir>
+<del integrity="val">text</del>
+<big loop="val">text</big>
+<cite part="val">text</cite>
+<command autocorrect="val">text</command>
+<ins hspace="val">text</ins>
+<header onemptied="val">text</header>
+<bgsound kind="val">text</bgsound>
+<hgroup rows="val">text</hgroup>
+<xmp latencyhint="val">text</xmp>
+<canvas conversiondestination="val">text</canvas>
+<tr frame="val">text</tr>
+<q vlink="val">text</q>
+<canvas hspace="val">text</canvas>
+<layer importance="val">text</layer>
+<nolayer onratechange="val">text</nolayer>
+<th oncut="val">text</th>
+<noframes width="val">text</noframes>
+<aside onpointerup="val">text</aside>
+<sup onchange="val">text</sup>
+<iframe cellspacing="val">text</iframe>
+<rp minlength="val">text</rp>
+<figure onmouseenter="val">text</figure>
+<caption ismap="val">text</caption>
+<blockquote hspace="val">text</blockquote>
+<eprobe shadowrootdelegatesfocus="val">text</eprobe>
+<kbd onkeyup="val">text</kbd>
+<object ontransitionend="val">text</object>
+<object onformdata="val">text</object>
+<dl step="val">text</dl>
+<h1 capture="val">text</h1>
+<content defer="val">text</content>
+<dd ondragover="val">text</dd>
+<form rel="val">text</form>
+<input default="val">text</input>
+<acronym onunload="val">text</acronym>
+<s onlostpointercapture="val">text</s>
+<image integrity="val">text</image>
+<track onsearch="val">text</track>
+<rt slot="val">text</rt>
+<noscript select="val">text</noscript>
+<section link="val">text</section>
+<slot max="val">text</slot>
+<bdo span="val">text</bdo>
+<figure onmousewheel="val">text</figure>
+<data step="val">text</data>
+<xmp target="val">text</xmp>
+<bdi autocorrect="val">text</bdi>
+<slot onformdata="val">text</slot>
+<th summary="val">text</th>
+<image title="val">text</image>
+<style allow="val">text</style>
+<blockquote onresize="val">text</blockquote>
+<del role="val">text</del>
+<noframes impressionexpiry="val">text</noframes>
+<tbody webkitdirectory="val">text</tbody>
+<dir ismap="val">text</dir>
+<hr object="val">text</hr>
+<keygen onauxclick="val">text</keygen>
+<mark is="val">text</mark>
+<picture classid="val">text</picture>
+<th scope="val">text</th>
+<audio select="val">text</audio>
+<del bgcolor="val">text</del>
+<cite onpopstate="val">text</cite>
+<style poster="val">text</style>
+<listing exportparts="val">text</listing>
+<img oninvalid="val">text</img>
+<image ondblclick="val">text</image>
+<tt abbr="val">text</tt>
+<nav onwheel="val">text</nav>
+<canvas accept="val">text</canvas>
+<keygen onmousewheel="val">text</keygen>
+<ruby spellcheck="val">text</ruby>
+<portal onprogress="val">text</portal>
+<time onvolumechange="val">text</time>
+<dd noshade="val">text</dd>
+<h1 summary="val">text</h1>
+<dd maxlength="val">text</dd>
+<iframe defer="val">text</iframe>
+<track cite="val">text</track>
+<s allowpaymentrequest="val">text</s>
+<hr onlanguagechange="val">text</hr>
+<br action="val">text</br>
+<summary inert="val">text</summary>
+<q onkeypress="val">text</q>
+<frameset autocomplete="val">text</frameset>
+<main type="val">text</main>
+<var ondragenter="val">text</var>
+<p onwebkitfullscreenerror="val">text</p>
+<form high="val">text</form>
+<image kind="val">text</image>
+<small form="val">text</small>
+<section nohref="val">text</section>
+<content lowsrc="val">text</content>
+<tfoot hidden="val">text</tfoot>
+<frameset ontouchstart="val">text</frameset>
+<h2 width="val">text</h2>
+<kbd accept="val">text</kbd>
+<applet webkitdirectory="val">text</applet>
+<samp onmouseover="val">text</samp>
+<keygen onwaiting="val">text</keygen>
+<output ondblclick="val">text</output>
+<mark declare="val">text</mark>
+<figcaption open="val">text</figcaption>
+<center onanimationiteration="val">text</center>
+<nobr ondragend="val">text</nobr>
+<center onscroll="val">text</center>
+<shadow impressionexpiry="val">text</shadow>
+<address onpointerenter="val">text</address>
+<ol ondrag="val">text</ol>
+<h1 rows="val">text</h1>
+<sub coords="val">text</sub>
+<td formmethod="val">text</td>
+<progress pattern="val">text</progress>
+<listing lowsrc="val">text</listing>
+<caption disabled="val">text</caption>
+<dl onscrollend="val">text</dl>
+<samp rowspan="val">text</samp>
+<section csp="val">text</section>
+<meter alink="val">text</meter>
+<figcaption end="val">text</figcaption>
+<big policy="val">text</big>
+<li lang="val">text</li>
+<bdo slot="val">text</bdo>
+<strike onended="val">text</strike>
+<legend impressiondata="val">text</legend>
+<address onbeforecut="val">text</address>
+<video rel="val">text</video>
+<rtc name="val">text</rtc>
+<command cellspacing="val">text</command>
+<big csp="val">text</big>
+<col ondragenter="val">text</col>
+<meter onbeforecut="val">text</meter>
+<meter onhashchange="val">text</meter>
+<track decoding="val">text</track>
+<input lang="val">text</input>
+<time onmousemove="val">text</time>
+<img onstalled="val">text</img>
+<embed action="val">text</embed>
+<big onabort="val">text</big>
+<q onclick="val">text</q>
+<big ondragleave="val">text</big>
+<kbd axis="val">text</kbd>
+<del ontouchstart="val">text</del>
+<button oncanplaythrough="val">text</button>
+<summary onmouseup="val">text</summary>
+<canvas lowsrc="val">text</canvas>
+<ruby allowpaymentrequest="val">text</ruby>
+<output ontouchstart="val">text</output>
+<audio onerror="val">text</audio>
+<aside playsinline="val">text</aside>
+<td onkeypress="val">text</td>
+<option step="val">text</option>
+<eprobe autofocus="val">text</eprobe>
+<header onmouseup="val">text</header>
+<button oninvalid="val">text</button>
+<u hreftranslate="val">text</u>
+<big label="val">text</big>
+<bdo language="val">text</bdo>
+<aside csp="val">text</aside>
+<q onprobe="val">text</q>
+<noembed csp="val">text</noembed>
+<tt invisible="val">text</tt>
+<object onorientationchange="val">text</object>
+<code onabort="val">text</code>
+<eprobe object="val">text</eprobe>
+<label minlength="val">text</label>
+<link onfocus="val">text</link>
+<tt onsubmit="val">text</tt>
+<em oncancel="val">text</em>
+<shadow reversed="val">text</shadow>
+<basefont onvolumechange="val">text</basefont>
+<u aprobe="val">text</u>
+<output autopictureinpicture="val">text</output>
+<em onfocus="val">text</em>
+<wbr usemap="val">text</wbr>
+<legend onpause="val">text</legend>
+<summary readonly="val">text</summary>
+<h6 loop="val">text</h6>
+<caption elementtiming="val">text</caption>
+<image inputmode="val">text</image>
+<bdo is="val">text</bdo>
+<col invisible="val">text</col>
+<abbr min="val">text</abbr>
+<section readonly="val">text</section>
+<noframes ismap="val">text</noframes>
+<br selected="val">text</br>
+<nolayer download="val">text</nolayer>
+<center valign="val">text</center>
+<form label="val">text</form>
+<time onclick="val">text</time>
+<image onmessage="val">text</image>
+<frameset cols="val">text</frameset>
+<img is="val">text</img>
+<h1 imagesizes="val">text</h1>
+<tr onanimationiteration="val">text</tr>
+<progress onpointermove="val">text</progress>
+<i kind="val">text</i>
+<em coords="val">text</em>
+<figure open="val">text</figure>
+<acronym disabled="val">text</acronym>
+<u integrity="val">text</u>
+<style face="val">text</style>
+<input onselect="val">text</input>
+<cite required="val">text</cite>
+<code onpointermove="val">text</code>
+<main onplay="val">text</main>
+<h5 controlslist="val">text</h5>
+<figure disabled="val">text</figure>
+<mark onsubmit="val">text</mark>
+<track alink="val">text</track>
+<blockquote oncanplay="val">text</blockquote>
+<h3 onlanguagechange="val">text</h3>
+<noembed enctype="val">text</noembed>
+<article charoff="val">text</article>
+<bdo pseudo="val">text</bdo>
+<th sandbox="val">text</th>
+<hgroup playsinline="val">text</hgroup>
+<em onplaying="val">text</em>
+<li defer="val">text</li>
+<hgroup background="val">text</hgroup>
+<label hspace="val">text</label>
+<time onmouseenter="val">text</time>
+<mark onplay="val">text</mark>
+<big placeholder="val">text</big>
+<bdo oninput="val">text</bdo>
+<h1 oninput="val">text</h1>
+<canvas rev="val">text</canvas>
+<h1 onlostpointercapture="val">text</h1>
+<img alink="val">text</img>
+<caption reversed="val">text</caption>
+<rtc onmouseout="val">text</rtc>
+<nobr onprobe="val">text</nobr>
+<data manifest="val">text</data>
+<shadow onunload="val">text</shadow>
+<a onstorage="val">text</a>
+<noframes cols="val">text</noframes>
+<code onmousewheel="val">text</code>
+<caption rev="val">text</caption>
+<link style="val">text</link>
+<button autopictureinpicture="val">text</button>
+<ul onscroll="val">text</ul>
+<tr onloadedmetadata="val">text</tr>
+<bgsound width="val">text</bgsound>
+<address onpopstate="val">text</address>
+<colgroup download="val">text</colgroup>
+<h6 onscrollend="val">text</h6>
+<samp ondragleave="val">text</samp>
+<keygen onsubmit="val">text</keygen>
+<tbody classid="val">text</tbody>
+<progress onlostpointercapture="val">text</progress>
+<hr onfocusin="val">text</hr>
+<section onshow="val">text</section>
+<code charset="val">text</code>
+<ol onmouseout="val">text</ol>
+<big ondrop="val">text</big>
+<applet onblur="val">text</applet>
+<summary webkitdirectory="val">text</summary>
+<h5 invisible="val">text</h5>
+<var frameborder="val">text</var>
+<rb resources="val">text</rb>
+<tt event="val">text</tt>
+<em onwebkittransitionend="val">text</em>
+<datalist accept-charset="val">text</datalist>
+<sup onmousewheel="val">text</sup>
+<object onpointermove="val">text</object>
+<mark name="val">text</mark>
+<script ondragover="val">text</script>
+<th onpause="val">text</th>
+<output autofocus="val">text</output>
+<h2 part="val">text</h2>
+<select onfocusin="val">text</select>
+<small allowpaymentrequest="val">text</small>
+<listing scrolldelay="val">text</listing>
+<noframes inputmode="val">text</noframes>
+<frameset align="val">text</frameset>
+<noframes class="val">text</noframes>
+<br onabort="val">text</br>
+<samp onsuspend="val">text</samp>
+<rt oncancel="val">text</rt>
+<ruby onprogress="val">text</ruby>
+<kbd referrerpolicy="val">text</kbd>
+<dfn min="val">text</dfn>
+<listing nohref="val">text</listing>
+<fieldset method="val">text</fieldset>
+<noembed compact="val">text</noembed>
+<tbody declare="val">text</tbody>
+<nav oncopy="val">text</nav>
+<eprobe reportingorigin="val">text</eprobe>
+<abbr required="val">text</abbr>
+<wbr onclose="val">text</wbr>
+<h6 formnovalidate="val">text</h6>
+<optgroup onended="val">text</optgroup>
+<address bordercolor="val">text</address>
+<ol formaction="val">text</ol>
+<strike oninput="val">text</strike>
+<var size="val">text</var>
+<command onkeypress="val">text</command>
+<h1 oncanplay="val">text</h1>
+<bdo cellpadding="val">text</bdo>
+<object onstorage="val">text</object>
+<dd frameborder="val">text</dd>
+<input marginwidth="val">text</input>
+<caption sandbox="val">text</caption>
+<td scrolling="val">text</td>
+<dd vspace="val">text</dd>
+<basefont content="val">text</basefont>
+<a default="val">text</a>
+<header onlostpointercapture="val">text</header>
+<main oncopy="val">text</main>
+<samp enctype="val">text</samp>
+<tbody abbr="val">text</tbody>
+<bgsound onscrollend="val">text</bgsound>
+<dl ismap="val">text</dl>
+<nobr onkeydown="val">text</nobr>
+<bgsound slot="val">text</bgsound>
+<cite onerror="val">text</cite>
+<sub onunload="val">text</sub>
+<tbody wrap="val">text</tbody>
+<input scrollamount="val">text</input>
+<optgroup valign="val">text</optgroup>
+<img download="val">text</img>
+<s name="val">text</s>
+<mark elementtiming="val">text</mark>
+<th list="val">text</th>
+<strike latencyhint="val">text</strike>
+<embed onbeforeunload="val">text</embed>
+<dir rev="val">text</dir>
+<legend onpointermove="val">text</legend>
+<blockquote bordercolor="val">text</blockquote>
+<a autocapitalize="val">text</a>
+<track rel="val">text</track>
+<iframe compact="val">text</iframe>
+<basefont allow="val">text</basefont>
+<tt ondurationchange="val">text</tt>
+<thead decoding="val">text</thead>
+<hr border="val">text</hr>
+<var accept="val">text</var>
+<portal onanimationstart="val">text</portal>
+<time selected="val">text</time>
+<center headers="val">text</center>
+<ul noshade="val">text</ul>
+<tfoot border="val">text</tfoot>
+<data standby="val">text</data>
+<kbd onanimationiteration="val">text</kbd>
+<a cellspacing="val">text</a>
+<summary onresize="val">text</summary>
+<bdo declare="val">text</bdo>
+<br ontouchend="val">text</br>
+<script color="val">text</script>
+<xmp formnovalidate="val">text</xmp>
+<code onunload="val">text</code>
+<th onpointerout="val">text</th>
+<rtc height="val">text</rtc>
+<noembed codetype="val">text</noembed>
+<wbr value="val">text</wbr>
+<mark onselectstart="val">text</mark>
+<figcaption oncut="val">text</figcaption>
+<rp onpointerup="val">text</rp>
+<aside onscroll="val">text</aside>
+<section scrolling="val">text</section>
+<b required="val">text</b>
+<plaintext summary="val">text</plaintext>
+<embed hreftranslate="val">text</embed>
+<command autoplay="val">text</command>
+<eprobe content="val">text</eprobe>
+<noframes conversiondestination="val">text</noframes>
+<s onwebkitfullscreenchange="val">text</s>
+<section face="val">text</section>
+<s align="val">text</s>
+<applet novalidate="val">text</applet>
+<hr scrolling="val">text</hr>
+<aside list="val">text</aside>
+<option default="val">text</option>
+<h4 allow="val">text</h4>
+<object defer="val">text</object>
+<col onsubmit="val">text</col>
+<tt onloadeddata="val">text</tt>
+<summary onmousemove="val">text</summary>
+<var inputmode="val">text</var>
+<mark virtualkeyboardpolicy="val">text</mark>
+<strike start="val">text</strike>
+<footer onmouseover="val">text</footer>
+<applet nomodule="val">text</applet>
+<abbr decoding="val">text</abbr>
+<section oncontextmenu="val">text</section>
+<h4 onwaiting="val">text</h4>
+<track onwaiting="val">text</track>
+<dd ondragenter="val">text</dd>
+<a srcdoc="val">text</a>
+<applet as="val">text</applet>
+<canvas select="val">text</canvas>
+<frameset conversiondestination="val">text</frameset>
+<ins vspace="val">text</ins>
+<applet impressionexpiry="val">text</applet>
+<applet max="val">text</applet>
+<h2 rel="val">text</h2>
+<main headers="val">text</main>
+<nolayer disableremoteplayback="val">text</nolayer>
+<rtc exportparts="val">text</rtc>
+<address onkeyup="val">text</address>
+<ol rules="val">text</ol>
+<hgroup onwheel="val">text</hgroup>
+<bdi disablepictureinpicture="val">text</bdi>
+<br rules="val">text</br>
+<li ondurationchange="val">text</li>
+<header onload="val">text</header>
+<option object="val">text</option>
+<h1 leftmargin="val">text</h1>
+<noembed char="val">text</noembed>
+<blockquote allowpaymentrequest="val">text</blockquote>
+<ruby onmouseleave="val">text</ruby>
+<h5 integrity="val">text</h5>
+<style keytype="val">text</style>
+<section size="val">text</section>
+<q onoffline="val">text</q>
+<h4 reversed="val">text</h4>
+<dir coords="val">text</dir>
+<h5 ondurationchange="val">text</h5>
+<kbd abbr="val">text</kbd>
+<strike onmouseout="val">text</strike>
+<link language="val">text</link>
+<br readonly="val">text</br>
+<optgroup ondragstart="val">text</optgroup>
+<h6 conversiondestination="val">text</h6>
+<strike onfocusin="val">text</strike>
+<dt defer="val">text</dt>
+<iframe onselect="val">text</iframe>
+<del onselect="val">text</del>
+<keygen onpointerenter="val">text</keygen>
+<sub object="val">text</sub>
+<colgroup onanimationstart="val">text</colgroup>
+<data onerror="val">text</data>
+<keygen manifest="val">text</keygen>
+<object ongotpointercapture="val">text</object>
+<h3 start="val">text</h3>
+<datalist nonce="val">text</datalist>
+<s autofocus="val">text</s>
+<shadow span="val">text</shadow>
+<strong oncuechange="val">text</strong>
+<label open="val">text</label>
+<h3 onlostpointercapture="val">text</h3>
+<image onbeforecut="val">text</image>
+<kbd span="val">text</kbd>
+<data onlostpointercapture="val">text</data>
+<em allowpaymentrequest="val">text</em>
+<center onkeypress="val">text</center>
+<strike onbeforeprint="val">text</strike>
+<button clear="val">text</button>
+<basefont onhashchange="val">text</basefont>
+<noscript nomodule="val">text</noscript>
+<dt onseeked="val">text</dt>
+<noembed onwebkittransitionend="val">text</noembed>
+<bdi color="val">text</bdi>
+<footer enterkeyhint="val">text</footer>
+<command ondragstart="val">text</command>
+<address ondragover="val">text</address>
+<dir onmousedown="val">text</dir>
+<time ondblclick="val">text</time>
+<h4 onwebkitfullscreenchange="val">text</h4>
+<h5 media="val">text</h5>
+<img onportalactivate="val">text</img>
+<figure ondrop="val">text</figure>
+<time onseeking="val">text</time>
+<u dir="val">text</u>
+<footer onplaying="val">text</footer>
+<dir object="val">text</dir>
+<mark marginheight="val">text</mark>
+<audio tabindex="val">text</audio>
+<legend ondurationchange="val">text</legend>
+<listing formnovalidate="val">text</listing>
+<tt style="val">text</tt>
+<footer name="val">text</footer>
+<article type="val">text</article>
+<main ontouchmove="val">text</main>
+<nolayer onwheel="val">text</nolayer>
+<h2 placeholder="val">text</h2>
+<audio loop="val">text</audio>
+<nav nowrap="val">text</nav>
+<nobr onpagehide="val">text</nobr>
+<embed onclose="val">text</embed>
+<button disableremoteplayback="val">text</button>
+<image onfocusout="val">text</image>
+<rtc srcdoc="val">text</rtc>
+<meter rowspan="val">text</meter>
+<canvas ontimezonechange="val">text</canvas>
+<slot dirname="val">text</slot>
+<header>text</header>
+<h2 onplaying="val">text</h2>
+<col disablepictureinpicture="val">text</col>
+<portal axis="val">text</portal>
+<ins>text</ins>
+<tt onresize="val">text</tt>
+<ul onformdata="val">text</ul>
+<cite oncanplaythrough="val">text</cite>
+<wbr autoplay="val">text</wbr>
+<bgsound declare="val">text</bgsound>
+<caption onvolumechange="val">text</caption>
+<picture onmessage="val">text</picture>
+<meter poster="val">text</meter>
+<dfn coords="val">text</dfn>
+<code ontimeupdate="val">text</code>
+<content abbr="val">text</content>
+<h6 onpageshow="val">text</h6>
+<command scheme="val">text</command>
+<sub vlink="val">text</sub>
+<var spellcheck="val">text</var>
+<samp formaction="val">text</samp>
+<fieldset onended="val">text</fieldset>
+<applet ontimezonechange="val">text</applet>
+<link media="val">text</link>
+<i name="val">text</i>
+<abbr disallowdocumentaccess="val">text</abbr>
+<listing srcset="val">text</listing>
+<code onsubmit="val">text</code>
+<a onpointerout="val">text</a>
+<samp ononline="val">text</samp>
+<colgroup char="val">text</colgroup>
+<samp rows="val">text</samp>
+<bgsound mayscript="val">text</bgsound>
+<rb muted="val">text</rb>
+<legend list="val">text</legend>
+<h4 readonly="val">text</h4>
+<command loop="val">text</command>
+<header lang="val">text</header>
+<audio playsinline="val">text</audio>
+<td accesskey="val">text</td>
+<thead align="val">text</thead>
+<noscript lang="val">text</noscript>
+<basefont srclang="val">text</basefont>
+<frameset onresize="val">text</frameset>
+<legend oncuechange="val">text</legend>
+<track impressiondata="val">text</track>
+<portal ondrag="val">text</portal>
+<address controls="val">text</address>
+<footer onorientationchange="val">text</footer>
+<h5 onmouseenter="val">text</h5>
+<tr draggable="val">text</tr>
+<noscript invisible="val">text</noscript>
+<xmp allowpaymentrequest="val">text</xmp>
+<tfoot truespeed="val">text</tfoot>
+<h1 select="val">text</h1>
+<kbd link="val">text</kbd>
+<datalist ping="val">text</datalist>
+<figcaption resources="val">text</figcaption>
+<p size="val">text</p>
+<bdo form="val">text</bdo>
+<center srcset="val">text</center>
+<noscript content="val">text</noscript>
+<h3 content="val">text</h3>
+<ol onpointercancel="val">text</ol>
+<embed contenteditable="val">text</embed>
+<legend sizes="val">text</legend>
+<big disabled="val">text</big>
+<h6 bgcolor="val">text</h6>
+<big crossorigin="val">text</big>
+<q defer="val">text</q>
+<img onkeydown="val">text</img>
+<li onscroll="val">text</li>
+<dir nohref="val">text</dir>
+<ol srclang="val">text</ol>
+<output action="val">text</output>
+<data cite="val">text</data>
+<textarea accesskey="val">text</textarea>
+<u ondragstart="val">text</u>
+<datalist enterkeyhint="val">text</datalist>
+<th allowfullscreen="val">text</th>
+<summary onpointerleave="val">text</summary>
+<canvas resources="val">text</canvas>
+<rt wrap="val">text</rt>
+<form srclang="val">text</form>
+<samp draggable="val">text</samp>
+<small onplaying="val">text</small>
+<rp ismap="val">text</rp>
+<ul onportalactivate="val">text</ul>
+<video colspan="val">text</video>
+<rp frameborder="val">text</rp>
+<script enterkeyhint="val">text</script>
+<samp onemptied="val">text</samp>
+<button onbeforecut="val">text</button>
+<ruby onpointerrawupdate="val">text</ruby>
+<h1 checked="val">text</h1>
+<col onanimationend="val">text</col>
+<h6 impressionexpiry="val">text</h6>
+<bgsound decoding="val">text</bgsound>
+<center oninvalid="val">text</center>
+<button onload="val">text</button>
+<embed onpaste="val">text</embed>
+<canvas datetime="val">text</canvas>
+<blockquote resources="val">text</blockquote>
+<dfn rules="val">text</dfn>
+<h5 max="val">text</h5>
+<section oninvalid="val">text</section>
+<frameset onsubmit="val">text</frameset>
+<figure onlostpointercapture="val">text</figure>
+<bgsound onstorage="val">text</bgsound>
+<progress end="val">text</progress>
+<samp onlostpointercapture="val">text</samp>
+<var char="val">text</var>
+<time align="val">text</time>
+<ul autocomplete="val">text</ul>
+<dl autofocus="val">text</dl>
+<acronym autofocus="val">text</acronym>
+<br onchange="val">text</br>
+<article alt="val">text</article>
+<dfn cellspacing="val">text</dfn>
+<input code="val">text</input>
+<noembed onanimationiteration="val">text</noembed>
+<iframe policy="val">text</iframe>
+<fieldset keytype="val">text</fieldset>
+<select declare="val">text</select>
+<li axis="val">text</li>
+<optgroup webkitdirectory="val">text</optgroup>
+<h6 onclose="val">text</h6>
+<var onunload="val">text</var>
+<h4 ontouchmove="val">text</h4>
+<address draggable="val">text</address>
+<canvas oncontextmenu="val">text</canvas>
+<video onwebkitanimationend="val">text</video>
+<rp virtualkeyboardpolicy="val">text</rp>
+<legend allowfullscreen="val">text</legend>
+<em onanimationstart="val">text</em>
+<acronym async="val">text</acronym>
+<address lang="val">text</address>
+<layer ongotpointercapture="val">text</layer>
+<q onmessage="val">text</q>
+<portal onseeked="val">text</portal>
+<rt onkeypress="val">text</rt>
+<mark poster="val">text</mark>
+<header onbeforeprint="val">text</header>
+<footer accept="val">text</footer>
+<u ontouchmove="val">text</u>
+<progress ontouchcancel="val">text</progress>
+<basefont onbeforeunload="val">text</basefont>
+<em rev="val">text</em>
+<form ontouchstart="val">text</form>
+<col id="val">text</col>
+<aside onabort="val">text</aside>
+<td datetime="val">text</td>
+<layer autofocus="val">text</layer>
+<select aprobe="val">text</select>
+<big reportingorigin="val">text</big>
+<embed char="val">text</embed>
+<small csp="val">text</small>
+<bdo onprobe="val">text</bdo>
+<ins valuetype="val">text</ins>
+<tt ondrop="val">text</tt>
+<main autoplay="val">text</main>
+<s onmousewheel="val">text</s>
+<ul frameborder="val">text</ul>
+<style oncanplay="val">text</style>
+<a media="val">text</a>
+<samp list="val">text</samp>
+<command codetype="val">text</command>
+<code aprobe="val">text</code>
+<eprobe disableremoteplayback="val">text</eprobe>
+<select ontouchend="val">text</select>
+<br controlslist="val">text</br>
+<datalist ondragover="val">text</datalist>
+<output onwebkitfullscreenchange="val">text</output>
+<rb allowpaymentrequest="val">text</rb>
+<br sizes="val">text</br>
+<dir span="val">text</dir>
+<dl for="val">text</dl>
+<layer marginheight="val">text</layer>
+<section target="val">text</section>
+<link form="val">text</link>
+<xmp disabled="val">text</xmp>
+<h4 onsubmit="val">text</h4>
+<fieldset imagesizes="val">text</fieldset>
+<dt onplay="val">text</dt>
+<i id="val">text</i>
+<datalist oncanplay="val">text</datalist>
+<portal hreftranslate="val">text</portal>
+<script onended="val">text</script>
+<b defer="val">text</b>
+<h2 onstorage="val">text</h2>
+<b onlostpointercapture="val">text</b>
+<strong loading="val">text</strong>
+<video ononline="val">text</video>
+<b onunload="val">text</b>
+<colgroup ongotpointercapture="val">text</colgroup>
+<i scrolldelay="val">text</i>
+<keygen border="val">text</keygen>
+<legend onloadstart="val">text</legend>
+<video virtualkeyboardpolicy="val">text</video>
+<label color="val">text</label>
+<command summary="val">text</command>
+<sub nowrap="val">text</sub>
+<blockquote srcdoc="val">text</blockquote>
+<u part="val">text</u>
+<section as="val">text</section>
+<kbd keytype="val">text</kbd>
+<th scrolldelay="val">text</th>
+<nolayer ontoggle="val">text</nolayer>
+<strike ontoggle="val">text</strike>
+<var onwebkitanimationend="val">text</var>
+<h2 onerror="val">text</h2>
+<basefont onkeyup="val">text</basefont>
+<form oncanplay="val">text</form>
+<rp rowspan="val">text</rp>
+<nobr nomodule="val">text</nobr>
+<noframes version="val">text</noframes>
+<var hreftranslate="val">text</var>
+<noembed truespeed="val">text</noembed>
+<i frame="val">text</i>
+<frameset aprobe="val">text</frameset>
+<frameset topmargin="val">text</frameset>
+<command oncanplay="val">text</command>
+<cite truespeed="val">text</cite>
+<hgroup onmousewheel="val">text</hgroup>
+<h4 virtualkeyboardpolicy="val">text</h4>
+<mark src="val">text</mark>
+<colgroup onreset="val">text</colgroup>
+<form csp="val">text</form>
+<ul topmargin="val">text</ul>
+<colgroup onmousemove="val">text</colgroup>
+<bdo accept-charset="val">text</bdo>
+<option trusttoken="val">text</option>
+<big formaction="val">text</big>
+<bdo conversiondestination="val">text</bdo>
+<a onerror="val">text</a>
+<s rows="val">text</s>
+<del sandbox="val">text</del>
+<strike rules="val">text</strike>
+<frameset onwebkitanimationend="val">text</frameset>
+<embed onpageshow="val">text</embed>
+<slot spellcheck="val">text</slot>
+<summary onwheel="val">text</summary>
+<input shadowroot="val">text</input>
+<track>text</track>
+<xmp onsearch="val">text</xmp>
+<li imagesrcset="val">text</li>
+<option onstalled="val">text</option>
+<optgroup onpointerrawupdate="val">text</optgroup>
+<frameset oncopy="val">text</frameset>
+<progress lowsrc="val">text</progress>
+<slot direction="val">text</slot>
+<h3 scrolldelay="val">text</h3>
+<dfn wrap="val">text</dfn>
+<applet default="val">text</applet>
+<cite onchange="val">text</cite>
+<script disablepictureinpicture="val">text</script>
+<data nohref="val">text</data>
+<hr codebase="val">text</hr>
+<datalist content="val">text</datalist>
+<del incremental="val">text</del>
+<portal ononline="val">text</portal>
+<big challenge="val">text</big>
+<col onprobe="val">text</col>
+<td inputmode="val">text</td>
+<select onpointercancel="val">text</select>
+<s onstalled="val">text</s>
+<ruby virtualkeyboardpolicy="val">text</ruby>
+<h6 onplay="val">text</h6>
+<img hspace="val">text</img>
+<thead language="val">text</thead>
+<aside incremental="val">text</aside>
+<plaintext onloadeddata="val">text</plaintext>
+<layer max="val">text</layer>
+<u action="val">text</u>
+<ol onvolumechange="val">text</ol>
+<frameset ping="val">text</frameset>
+<header onpointerrawupdate="val">text</header>
+<rt onanimationiteration="val">text</rt>
+<big content="val">text</big>
+<ul required="val">text</ul>
+<button dirname="val">text</button>
+<dd link="val">text</dd>
+<audio autoplay="val">text</audio>
+<header longdesc="val">text</header>
+<content onmouseout="val">text</content>
+<rt as="val">text</rt>
+<noscript autocapitalize="val">text</noscript>
+<applet rowspan="val">text</applet>
+<embed direction="val">text</embed>
+<textarea onpointerover="val">text</textarea>
+<ruby name="val">text</ruby>
+<nolayer summary="val">text</nolayer>
+<xmp vspace="val">text</xmp>
+<rp border="val">text</rp>
+<h3 dir="val">text</h3>
+<tfoot webkitdirectory="val">text</tfoot>
+<acronym onfocusout="val">text</acronym>
+<h1 elementtiming="val">text</h1>
+<acronym oncanplay="val">text</acronym>
+<layer charoff="val">text</layer>
+<video onpointerenter="val">text</video>
+<sup placeholder="val">text</sup>
+<del ontransitionend="val">text</del>
+<canvas contenteditable="val">text</canvas>
+<aside async="val">text</aside>
+<keygen controls="val">text</keygen>
+<option cellpadding="val">text</option>
+<tfoot scrolldelay="val">text</tfoot>
+<cite datetime="val">text</cite>
+<tbody controls="val">text</tbody>
+<hgroup controls="val">text</hgroup>
+<center ongotpointercapture="val">text</center>
+<output incremental="val">text</output>
+<acronym onpopstate="val">text</acronym>
+<rtc kind="val">text</rtc>
+<main sandbox="val">text</main>
+<q oninvalid="val">text</q>
+<eprobe manifest="val">text</eprobe>
+<small alt="val">text</small>
+<figcaption formmethod="val">text</figcaption>
+<rt rel="val">text</rt>
+<rp required="val">text</rp>
+<var virtualkeyboardpolicy="val">text</var>
+<colgroup onratechange="val">text</colgroup>
+<style onwaiting="val">text</style>
+<noscript value="val">text</noscript>
+<fieldset step="val">text</fieldset>
+<em ondragleave="val">text</em>
+<meter onwebkitanimationstart="val">text</meter>
+<plaintext onmouseenter="val">text</plaintext>
+<footer onpointercancel="val">text</footer>
+<h3 ontouchstart="val">text</h3>
+<noframes imagesrcset="val">text</noframes>
+<ins ondragenter="val">text</ins>
+<center onpointerdown="val">text</center>
+<tt webkitdirectory="val">text</tt>
+<progress high="val">text</progress>
+<h4 rules="val">text</h4>
+<meter onfocus="val">text</meter>
+<keygen rel="val">text</keygen>
+<slot onpointerleave="val">text</slot>
+<i manifest="val">text</i>
+<command background="val">text</command>
+<rb formtarget="val">text</rb>
+<plaintext onresize="val">text</plaintext>
+<caption ondrop="val">text</caption>
+<canvas lang="val">text</canvas>
+<datalist max="val">text</datalist>
+<fieldset dirname="val">text</fieldset>
+<b ping="val">text</b>
+<fieldset onmessage="val">text</fieldset>
+<mark onoverscroll="val">text</mark>
+<progress maxlength="val">text</progress>
+<del srcset="val">text</del>
+<listing trusttoken="val">text</listing>
+<center max="val">text</center>
+<ins onplaying="val">text</ins>
+<center onended="val">text</center>
+<slot onmousedown="val">text</slot>
+<address ontouchcancel="val">text</address>
+<plaintext>text</plaintext>
+<hr onauxclick="val">text</hr>
+<hgroup onbeforeunload="val">text</hgroup>
+<small is="val">text</small>
+<command onended="val">text</command>
+<center slot="val">text</center>
+<embed onended="val">text</embed>
+<tbody bordercolor="val">text</tbody>
+<h3 selected="val">text</h3>
+<mark dirname="val">text</mark>
+<noframes enctype="val">text</noframes>
+<audio height="val">text</audio>
+<h3 code="val">text</h3>
+<object srclang="val">text</object>
+<img onsearch="val">text</img>
+<video ontoggle="val">text</video>
+<blockquote allow="val">text</blockquote>
+<footer coords="val">text</footer>
+<small tabindex="val">text</small>
+<iframe disallowdocumentaccess="val">text</iframe>
+<ul for="val">text</ul>
+<summary nonce="val">text</summary>
+<option accept="val">text</option>
+<rtc playsinline="val">text</rtc>
+<meter draggable="val">text</meter>
+<caption onafterprint="val">text</caption>
+<dd dirname="val">text</dd>
+<br charset="val">text</br>
+<output onreset="val">text</output>
+<tt onmessageerror="val">text</tt>
+<td srcset="val">text</td>
+<tr wrap="val">text</tr>
+<h6 cellpadding="val">text</h6>
+<datalist onbeforecopy="val">text</datalist>
+<ruby codebase="val">text</ruby>
+<datalist onwheel="val">text</datalist>
+<command onplay="val">text</command>
+<hgroup onbeforepaste="val">text</hgroup>
+<canvas direction="val">text</canvas>
+<i onwebkitanimationstart="val">text</i>
+<abbr is="val">text</abbr>
+<center as="val">text</center>
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple1.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple1.html
new file mode 100644
index 00000000000..8af465f9d08
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple1.html
@@ -0,0 +1 @@
+<div><em>bla</em><script>echo</script></div>
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple2.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple2.html
new file mode 100644
index 00000000000..b1f1ceda60b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple2.html
@@ -0,0 +1,3 @@
+<p>text</p>
+<script>console.log(1);</script>
+<p id="para"><em>text</em></p>
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple3.html b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple3.html
new file mode 100644
index 00000000000..a4bdae8a810
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/corpus/simple3.html
@@ -0,0 +1 @@
+<a href=bla.html onclick="console.log(1)">link</a>
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 320636766ff..adcc31578a2 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
@@ -4,61 +4,92 @@
#include "sanitizer.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_node_filter.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_parse_from_string_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_document_fragment_or_document.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_trusted_html_or_document_fragment_or_document.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_fragment.h"
+#include "third_party/blink/renderer/core/dom/document_init.h"
+#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
+#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.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/html/custom/custom_element.h"
+#include "third_party/blink/renderer/core/html/html_collection.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
+#include "third_party/blink/renderer/core/xml/dom_parser.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/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
-Sanitizer* Sanitizer::Create(const SanitizerConfig* config,
+Sanitizer* Sanitizer::Create(ExecutionContext* execution_context,
+ const SanitizerConfig* config,
ExceptionState& exception_state) {
- return MakeGarbageCollected<Sanitizer>(config);
+ return MakeGarbageCollected<Sanitizer>(execution_context, config);
}
-Sanitizer::Sanitizer(const SanitizerConfig* config) {
+Sanitizer::Sanitizer(ExecutionContext* execution_context,
+ const SanitizerConfig* config)
+ : allow_custom_elements_(config->allowCustomElements()) {
+ bool use_default_config = true;
+ if (config->allowCustomElements()) {
+ use_default_config = false;
+ }
+
// Format dropElements to uppercase.
drop_elements_ = default_drop_elements_;
if (config->hasDropElements()) {
ElementFormatter(drop_elements_, config->dropElements());
+ use_default_config = false;
}
// Format blockElements to uppercase.
block_elements_ = default_block_elements_;
if (config->hasBlockElements()) {
ElementFormatter(block_elements_, config->blockElements());
+ use_default_config = false;
}
// Format allowElements to uppercase.
if (config->hasAllowElements()) {
has_allow_elements_ = true;
ElementFormatter(allow_elements_, config->allowElements());
+ use_default_config = false;
}
// Format dropAttributes to lowercase.
drop_attributes_ = default_drop_attributes_;
if (config->hasDropAttributes()) {
AttrFormatter(drop_attributes_, config->dropAttributes());
+ use_default_config = false;
}
// Format allowAttributes to lowercase.
if (config->hasAllowAttributes()) {
has_allow_attributes_ = true;
AttrFormatter(allow_attributes_, config->allowAttributes());
+ use_default_config = false;
+ }
+
+ if (use_default_config) {
+ // TODO(lyf): Add unit tests for counters.
+ UseCounter::Count(execution_context,
+ WebFeature::kSanitizerAPIDefaultConfiguration);
}
}
@@ -74,8 +105,8 @@ void Sanitizer::AttrFormatter(
const Vector<std::pair<String, Vector<String>>>& attrs) {
for (const std::pair<String, Vector<String>>& pair : attrs) {
const String& lower_attr = pair.first.LowerASCII();
- if (pair.second.Contains("*")) {
- attr_map.insert(lower_attr, Vector<String>({"*"}));
+ if (pair.second == kVectorStar || pair.second.Contains("*")) {
+ attr_map.insert(lower_attr, kVectorStar);
} else {
Vector<String> elements;
for (const String& s : pair.second) {
@@ -129,18 +160,37 @@ DocumentFragment* Sanitizer::SanitizeImpl(
DocumentFragment* fragment = nullptr;
LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+ if (!window) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Cannot find current DOM window.");
+ return nullptr;
+ }
if (input.IsDocumentFragment()) {
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIFromFragment);
fragment = input.GetAsDocumentFragment();
- } else if (window) {
- Document* document = window->document();
- if (input.IsString() || input.IsNull()) {
- fragment = document->createDocumentFragment();
- DCHECK(document->QuerySelector("body"));
- fragment->ParseHTML(input.GetAsString(), document->QuerySelector("body"));
- } else {
- fragment = document->createDocumentFragment();
- fragment->appendChild(input.GetAsDocument()->documentElement());
- }
+ } else if (input.IsString() || input.IsNull()) {
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIFromString);
+
+ Document* document =
+ window->document()
+ ? window->document()->implementation().createHTMLDocument()
+ : DOMParser::Create(script_state)
+ ->parseFromString("<!DOCTYPE html><html><body></body></html>",
+ "text/html",
+ ParseFromStringOptions::Create());
+ // TODO(https://crbug.com/1178774): Behavior difference need further
+ // investgate.
+ fragment = document->createRange()->createContextualFragment(
+ input.GetAsString(), exception_state);
+ } else if (input.IsDocument()) {
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIFromDocument);
+
+ fragment = input.GetAsDocument()->createDocumentFragment();
+ fragment->CloneChildNodesFrom(*(input.GetAsDocument()->body()),
+ CloneChildrenFlag::kClone);
} else {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Cannot find current DOM window.");
@@ -157,67 +207,123 @@ DocumentFragment* Sanitizer::SanitizeImpl(
}
// TODO(crbug.com/1126936): Review the sanitising algorithm for non-HTMLs.
- String node_name = node->nodeName().UpperASCII();
- // If the current element is dropped, remove current element entirely and
- // proceed to its next sibling.
- if (drop_elements_.Contains(node_name)) {
- Node* tmp = node;
- node = NodeTraversal::NextSkippingChildren(*node, fragment);
- tmp->remove();
- } else if (block_elements_.Contains(node_name) ||
- (has_allow_elements_ && !allow_elements_.Contains(node_name))) {
- // If the current element is blocked, append its children after current
- // node to parent node, remove current element and proceed to the next
- // node.
- Node* parent = node->parentNode();
- Node* next_sibling = node->nextSibling();
- while (node->hasChildren()) {
- Node* n = node->firstChild();
- if (next_sibling) {
- parent->insertBefore(n, next_sibling, exception_state);
- } else {
- parent->appendChild(n, exception_state);
- }
- if (exception_state.HadException()) {
- return nullptr;
- }
- }
- Node* tmp = node;
- node = NodeTraversal::Next(*node, fragment);
- tmp->remove();
+ // 1. Let |name| be |element|'s tag name.
+ String name = node->nodeName().UpperASCII();
+ // 2. Classify elements into one of three kinds: kCustom, kUnknown, kRegular
+ ElementKind kind = ElementKind::kRegular;
+ if (CustomElement::IsValidName(AtomicString(name.LowerASCII()), false)) {
+ kind = ElementKind::kCustom;
+ } else if (IsA<HTMLElement>(node) &&
+ To<HTMLElement>(node)->IsHTMLUnknownElement()) {
+ kind = ElementKind::kUnknown;
+ }
+
+ // 3. If |kind| is `regular` and if |name| is not contained in the
+ // default element allow list, then 'drop'
+ if (kind == ElementKind::kRegular &&
+ !default_allow_elements_.Contains(name)) {
+ node = DropElement(node, fragment);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ } else if (kind == ElementKind::kCustom && !allow_custom_elements_) {
+ // 4. If |kind| is `custom` and if allow_custom_elements_ is unset or set
+ // to anything other than `true`, then 'drop'.
+ node = DropElement(node, fragment);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ } else if (drop_elements_.Contains(name)) {
+ // 5. If |name| is in |config|'s [=element drop list=] then 'drop'.
+ node = DropElement(node, fragment);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ } else if (block_elements_.Contains(name)) {
+ // 6. If |name| is in |config|'s [=element block list=] then 'block'.
+ node = BlockElement(node, fragment, exception_state);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ } else if (has_allow_elements_ && !allow_elements_.Contains(name)) {
+ // 7. if |config| has a non-empty [=element allow list=] and |name| is
+ // not in |config|'s [=element allow list=] then 'block'.
+ node = BlockElement(node, fragment, exception_state);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
} else {
- // Otherwise, remove any attributes to be dropped from the current
- // element, and proceed to the next node (preorder, depth-first
- // traversal).
- Element* element = To<Element>(node);
- if (has_allow_attributes_ &&
- allow_attributes_.at("*").Contains(node_name)) {
- } else if (drop_attributes_.at("*").Contains(node_name)) {
- for (const auto& name : element->getAttributeNames()) {
- element->removeAttribute(name);
- }
- } else {
- for (const auto& name : element->getAttributeNames()) {
- // Attributes in drop list or not in allow list while allow list
- // exists will be dropped.
- bool drop = (drop_attributes_.Contains(name) &&
- (drop_attributes_.at(name).Contains("*") ||
- drop_attributes_.at(name).Contains(node_name))) ||
- (has_allow_attributes_ &&
- !(allow_attributes_.Contains(name) &&
- (allow_attributes_.at(name).Contains("*") ||
- allow_attributes_.at(name).Contains(node_name))));
- if (drop)
- element->removeAttribute(name);
- }
- }
- node = NodeTraversal::Next(*node, fragment);
+ node = KeepElement(node, fragment, name, window);
}
}
return fragment;
}
+// If the current element needs to be dropped, remove current element entirely
+// and proceed to its next sibling.
+Node* Sanitizer::DropElement(Node* node, DocumentFragment* fragment) {
+ Node* tmp = node;
+ node = NodeTraversal::NextSkippingChildren(*node, fragment);
+ tmp->remove();
+ return node;
+}
+
+// If the current element should be blocked, append its children after current
+// node to parent node, remove current element and proceed to the next node.
+Node* Sanitizer::BlockElement(Node* node,
+ DocumentFragment* fragment,
+ ExceptionState& exception_state) {
+ Node* parent = node->parentNode();
+ Node* next_sibling = node->nextSibling();
+ while (node->hasChildren()) {
+ Node* n = node->firstChild();
+ if (next_sibling) {
+ parent->insertBefore(n, next_sibling, exception_state);
+ } else {
+ parent->appendChild(n, exception_state);
+ }
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+ }
+ Node* tmp = node;
+ node = NodeTraversal::Next(*node, fragment);
+ tmp->remove();
+ return node;
+}
+
+// Remove any attributes to be dropped from the current element, and proceed to
+// the next node (preorder, depth-first traversal).
+Node* Sanitizer::KeepElement(Node* node,
+ DocumentFragment* fragment,
+ String& node_name,
+ LocalDOMWindow* window) {
+ Element* element = To<Element>(node);
+ if (has_allow_attributes_ && allow_attributes_.at("*").Contains(node_name)) {
+ } else if (drop_attributes_.at("*").Contains(node_name)) {
+ for (const auto& name : element->getAttributeNames()) {
+ element->removeAttribute(name);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ }
+ } else {
+ for (const auto& name : element->getAttributeNames()) {
+ // Attributes in drop list or not in allow list while allow list
+ // exists will be dropped.
+ bool drop = (drop_attributes_.Contains(name) &&
+ (drop_attributes_.at(name) == kVectorStar ||
+ drop_attributes_.at(name).Contains(node_name))) ||
+ (has_allow_attributes_ &&
+ !(allow_attributes_.Contains(name) &&
+ (allow_attributes_.at(name) == kVectorStar ||
+ allow_attributes_.at(name).Contains(node_name))));
+ if (drop) {
+ element->removeAttribute(name);
+ UseCounter::Count(window->GetExecutionContext(),
+ WebFeature::kSanitizerAPIActionTaken);
+ }
+ }
+ }
+ node = NodeTraversal::Next(*node, fragment);
+ return node;
+}
+
void Sanitizer::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
}
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 f8d98e7c9a1..3aae120ef7e 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SANITIZER_API_SANITIZER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SANITIZER_API_SANITIZER_H_
+#include "third_party/blink/renderer/core/dom/node.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/wtf/text/wtf_string.h"
@@ -14,17 +15,26 @@ namespace blink {
class Document;
class DocumentFragment;
class ExceptionState;
+class ExecutionContext;
class SanitizerConfig;
class ScriptState;
class StringOrDocumentFragmentOrDocument;
class StringOrTrustedHTMLOrDocumentFragmentOrDocument;
+enum ElementKind {
+ kCustom,
+ kUnknown,
+ kRegular,
+};
+
class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static Sanitizer* Create(const SanitizerConfig*, ExceptionState&);
- explicit Sanitizer(const SanitizerConfig*);
+ static Sanitizer* Create(ExecutionContext*,
+ const SanitizerConfig*,
+ ExceptionState&);
+ explicit Sanitizer(ExecutionContext*, const SanitizerConfig*);
~Sanitizer() override;
String sanitizeToString(ScriptState*,
@@ -37,6 +47,10 @@ class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
void Trace(Visitor*) const override;
private:
+ Node* DropElement(Node*, DocumentFragment*);
+ Node* BlockElement(Node*, DocumentFragment*, ExceptionState&);
+ Node* KeepElement(Node*, DocumentFragment*, String&, LocalDOMWindow*);
+
void ElementFormatter(HashSet<String>&, const Vector<String>&);
void AttrFormatter(HashMap<String, Vector<String>>&,
const Vector<std::pair<String, Vector<String>>>&);
@@ -51,25 +65,153 @@ class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
HashMap<String, Vector<String>> allow_attributes_ = {};
HashMap<String, Vector<String>> drop_attributes_ = {};
+ bool allow_custom_elements_ = false;
+
bool has_allow_elements_ = false;
bool has_allow_attributes_ = false;
+ // TODO(lyf): make it all-ailpan.
const HashSet<String> default_block_elements_ = {};
- const HashSet<String> default_drop_elements_ = {"SCRIPT", "ANNOTATION-XML",
- "AUDIO", "COLGROUP",
- "DESC", "FOREIGNOBJECT",
- "HEAD", "IFRAME",
- "MATH", "MI",
- "MN", "MO",
- "MS", "MTEXT",
- "NOEMBED", "NOFRAMES",
- "PLAINTEXT", "STYLE",
- "SVG", "TEMPLATE",
- "THEAD", "TITLE",
- "VIDEO", "XMP"};
+ const HashSet<String> default_drop_elements_ = {};
+ const HashSet<String> default_allow_elements_ = {
+ "A", "ABBR", "ACRONYM", "ADDRESS", "AREA", "ARTICLE",
+ "ASIDE", "AUDIO", "B", "BDI", "BDO", "BIG",
+ "BLOCKQUOTE", "BODY", "BR", "BUTTON", "CANVAS", "CAPTION",
+ "CENTER", "CITE", "CODE", "COL", "COLGROUP", "DATALIST",
+ "DD", "DEL", "DETAILS", "DIALOG", "DFN", "DIR",
+ "DIV", "DL", "DT", "EM", "FIELDSET", "FIGCAPTION",
+ "FIGURE", "FONT", "FOOTER", "FORM", "H1", "H2",
+ "H3", "H4", "H5", "H6", "HEAD", "HEADER",
+ "HGROUP", "HR", "HTML", "I", "IMG", "INPUT",
+ "INS", "KBD", "KEYGEN", "LABEL", "LEGEND", "LI",
+ "LINK", "LISTING", "MAP", "MARK", "MENU", "META",
+ "METER", "NAV", "NOBR", "NOSCRIPT", "OL", "OPTGROUP",
+ "OPTION", "OUTPUT", "P", "PICTURE", "PRE", "PROGRESS",
+ "Q", "RB", "RP", "RT", "RTC", "RUBY",
+ "S", "SAMP", "SECTION", "SELECT", "SLOT", "SMALL",
+ "SOURCE", "SPAN", "STRIKE", "STRONG", "SUB", "SUMMARY",
+ "SUP", "STYLE", "TABLE", "TBODY", "TD", "TEXTAREA",
+ "TFOOT", "TH", "THEAD", "TIME", "TR", "TRACK",
+ "TT", "U", "UL", "VAR", "VIDEO", "WBR"};
+ const Vector<String> kVectorStar = Vector<String>({"*"});
const HashMap<String, Vector<String>> default_drop_attributes_ = {
- {"onclick", Vector<String>({"*"})},
- {"onsubmit", Vector<String>({"*"})}};
+ {"onabort", kVectorStar},
+ {"onafterprint", kVectorStar},
+ {"onanimationstart", kVectorStar},
+ {"onanimationiteration", kVectorStar},
+ {"onanimationend", kVectorStar},
+ {"onauxclick", kVectorStar},
+ {"onbeforecopy", kVectorStar},
+ {"onbeforecut", kVectorStar},
+ {"onbeforepaste", kVectorStar},
+ {"onbeforeprint", kVectorStar},
+ {"onbeforeunload", kVectorStar},
+ {"onblur", kVectorStar},
+ {"oncancel", kVectorStar},
+ {"oncanplay", kVectorStar},
+ {"oncanplaythrough", kVectorStar},
+ {"onchange", kVectorStar},
+ {"onclick", kVectorStar},
+ {"onclose", kVectorStar},
+ {"oncontextmenu", kVectorStar},
+ {"oncopy", kVectorStar},
+ {"oncuechange", kVectorStar},
+ {"oncut", kVectorStar},
+ {"ondblclick", kVectorStar},
+ {"ondrag", kVectorStar},
+ {"ondragend", kVectorStar},
+ {"ondragenter", kVectorStar},
+ {"ondragleave", kVectorStar},
+ {"ondragover", kVectorStar},
+ {"ondragstart", kVectorStar},
+ {"ondrop", kVectorStar},
+ {"ondurationchange", kVectorStar},
+ {"onemptied", kVectorStar},
+ {"onended", kVectorStar},
+ {"onerror", kVectorStar},
+ {"onfocus", kVectorStar},
+ {"onfocusin", kVectorStar},
+ {"onfocusout", kVectorStar},
+ {"onformdata", kVectorStar},
+ {"ongotpointercapture", kVectorStar},
+ {"onhashchange", kVectorStar},
+ {"oninput", kVectorStar},
+ {"oninvalid", kVectorStar},
+ {"onkeydown", kVectorStar},
+ {"onkeypress", kVectorStar},
+ {"onkeyup", kVectorStar},
+ {"onlanguagechange", kVectorStar},
+ {"onload", kVectorStar},
+ {"onloadeddata", kVectorStar},
+ {"onloadedmetadata", kVectorStar},
+ {"onloadstart", kVectorStar},
+ {"onlostpointercapture", kVectorStar},
+ {"onmessage", kVectorStar},
+ {"onmessageerror", kVectorStar},
+ {"onmousedown", kVectorStar},
+ {"onmouseenter", kVectorStar},
+ {"onmouseleave", kVectorStar},
+ {"onmousemove", kVectorStar},
+ {"onmouseout", kVectorStar},
+ {"onmouseover", kVectorStar},
+ {"onmouseup", kVectorStar},
+ {"onmousewheel", kVectorStar},
+ {"ononline", kVectorStar},
+ {"onoffline", kVectorStar},
+ {"onorientationchange", kVectorStar},
+ {"onoverscroll", kVectorStar},
+ {"onpagehide", kVectorStar},
+ {"onpageshow", kVectorStar},
+ {"onpaste", kVectorStar},
+ {"onpause", kVectorStar},
+ {"onplay", kVectorStar},
+ {"onplaying", kVectorStar},
+ {"onpointercancel", kVectorStar},
+ {"onpointerdown", kVectorStar},
+ {"onpointerenter", kVectorStar},
+ {"onpointerleave", kVectorStar},
+ {"onpointermove", kVectorStar},
+ {"onpointerout", kVectorStar},
+ {"onpointerover", kVectorStar},
+ {"onpointerrawupdate", kVectorStar},
+ {"onpointerup", kVectorStar},
+ {"onpopstate", kVectorStar},
+ {"onportalactivate", kVectorStar},
+ {"onprogress", kVectorStar},
+ {"onratechange", kVectorStar},
+ {"onreset", kVectorStar},
+ {"onresize", kVectorStar},
+ {"onscroll", kVectorStar},
+ {"onscrollend", kVectorStar},
+ {"onsearch", kVectorStar},
+ {"onseeked", kVectorStar},
+ {"onseeking", kVectorStar},
+ {"onselect", kVectorStar},
+ {"onselectstart", kVectorStar},
+ {"onselectionchange", kVectorStar},
+ {"onshow", kVectorStar},
+ {"onstalled", kVectorStar},
+ {"onstorage", kVectorStar},
+ {"onsuspend", kVectorStar},
+ {"onsubmit", kVectorStar},
+ {"ontimeupdate", kVectorStar},
+ {"ontimezonechange", kVectorStar},
+ {"ontoggle", kVectorStar},
+ {"ontouchstart", kVectorStar},
+ {"ontouchmove", kVectorStar},
+ {"ontouchend", kVectorStar},
+ {"ontouchcancel", kVectorStar},
+ {"ontransitionend", kVectorStar},
+ {"onunload", kVectorStar},
+ {"onvolumechange", kVectorStar},
+ {"onwaiting", kVectorStar},
+ {"onwebkitanimationstart", kVectorStar},
+ {"onwebkitanimationiteration", kVectorStar},
+ {"onwebkitanimationend", kVectorStar},
+ {"onwebkitfullscreenchange", kVectorStar},
+ {"onwebkitfullscreenerror", kVectorStar},
+ {"onwebkittransitionend", kVectorStar},
+ {"onwheel", kVectorStar}};
};
} // 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 f7ae2c47666..bcfd65b81a0 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
@@ -11,7 +11,7 @@ typedef (DOMString or TrustedHTML or DocumentFragment or Document) SanitizerInpu
Exposed=Window,
RuntimeEnabled=SanitizerAPI
] interface Sanitizer {
- [RaisesException] constructor(optional SanitizerConfig config = {});
- [CallWith=ScriptState, RaisesException] DOMString sanitizeToString(SanitizerInput input);
- [CallWith=ScriptState, RaisesException] DocumentFragment sanitize(SanitizerInputWithTrustedHTML input);
+ [MeasureAs=SanitizerAPICreated, CallWith=ExecutionContext, RaisesException] constructor(optional SanitizerConfig config = {});
+ [MeasureAs=SanitizerAPIToString, CallWith=ScriptState, RaisesException] DOMString sanitizeToString(SanitizerInput input);
+ [MeasureAs=SanitizerAPIToFragment, CallWith=ScriptState, RaisesException] DocumentFragment sanitize(SanitizerInputWithTrustedHTML input);
};
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api.dict b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api.dict
new file mode 100644
index 00000000000..2dfde8685bd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api.dict
@@ -0,0 +1,435 @@
+"code"
+"onreset"
+"codetype"
+"alt"
+"integrity"
+"compact"
+"spellcheck"
+"tt"
+"tr"
+"onpointerup"
+"tfoot"
+"th"
+"td"
+"resources"
+"onsubmit"
+"fieldset"
+"rel"
+"controls"
+"reportingorigin"
+"nohref"
+"onstalled"
+"onsearch"
+"contenteditable"
+"button"
+"list"
+"p"
+"small"
+"div"
+"dir"
+"hgroup"
+"video"
+"download"
+"hspace"
+"imagesizes"
+"inert"
+"sub"
+"ontimeupdate"
+"bdo"
+"selected"
+"bdi"
+"ondragleave"
+"decoding"
+"onselect"
+"autopictureinpicture"
+"sup"
+"aprobe"
+"charoff"
+"method"
+"alink"
+"codebase"
+"address"
+"onwebkitanimationiteration"
+"onbeforecopy"
+"strong"
+"placeholder"
+"legend"
+"oncancel"
+"onprogress"
+"oncut"
+"onbeforeunload"
+"action"
+"valuetype"
+"onloadeddata"
+"oncuechange"
+"onscroll"
+"href"
+"impressiondata"
+"nowrap"
+"onpointerenter"
+"noframes"
+"truespeed"
+"strike"
+"scope"
+"type"
+"start"
+"webkitdirectory"
+"formaction"
+"onpopstate"
+"ontouchend"
+"challenge"
+"autocomplete"
+"standby"
+"del"
+"iframe"
+"onselectionchange"
+"longdesc"
+"defer"
+"formmethod"
+"figure"
+"accept"
+"hreflang"
+"high"
+"incremental"
+"onpause"
+"oncopy"
+"axis"
+"rowspan"
+"end"
+"minlength"
+"charset"
+"ping"
+"tbody"
+"eprobe"
+"autofocus"
+"oncanplay"
+"csp"
+"max"
+"figcaption"
+"marginheight"
+"data"
+"enctype"
+"a"
+"onloadedmetadata"
+"onshow"
+"footer"
+"ontouchmove"
+"onanimationend"
+"q"
+"sandbox"
+"marginwidth"
+"allow"
+"abbr"
+"onwebkitfullscreenerror"
+"cols"
+"kbd"
+"formenctype"
+"disabled"
+"usemap"
+"equiv"
+"style"
+"img"
+"li"
+"listing"
+"policy"
+"hidden"
+"main"
+"blockquote"
+"ononline"
+"nomodule"
+"conversiondestination"
+"name"
+"cellspacing"
+"imagesrcset"
+"onwebkitanimationstart"
+"onbeforeprint"
+"em"
+"onpointerout"
+"topmargin"
+"onpointerover"
+"dirname"
+"event"
+"rt"
+"canvas"
+"rp"
+"open"
+"rev"
+"content"
+"rb"
+"formtarget"
+"onemptied"
+"onfocus"
+"playsinline"
+"onkeyup"
+"noresize"
+"onoverscroll"
+"language"
+"onprobe"
+"caption"
+"onseeked"
+"tabindex"
+"accesskey"
+"autocapitalize"
+"hreftranslate"
+"onsuspend"
+"size"
+"onpaste"
+"checked"
+"script"
+"dfn"
+"onmouseup"
+"scheme"
+"cite"
+"option"
+"reversed"
+"onpointermove"
+"part"
+"center"
+"kind"
+"b"
+"target"
+"referrerpolicy"
+"headers"
+"applet"
+"onpagehide"
+"declare"
+"plaintext"
+"border"
+"form"
+"min"
+"aside"
+"multiple"
+"track"
+"onmouseleave"
+"object"
+"class"
+"audio"
+"textarea"
+"onauxclick"
+"clear"
+"face"
+"pattern"
+"onplaying"
+"ontouchstart"
+"section"
+"leftmargin"
+"bgsound"
+"rtc"
+"text"
+"datetime"
+"ondurationchange"
+"slot"
+"title"
+"latencyhint"
+"version"
+"xmp"
+"nonce"
+"dl"
+"onplay"
+"dd"
+"elementtiming"
+"nobr"
+"meter"
+"optgroup"
+"dt"
+"scrolling"
+"onseeking"
+"summary"
+"noshade"
+"impressionexpiry"
+"datalist"
+"onfocusout"
+"frame"
+"ismap"
+"optimum"
+"muted"
+"onlanguagechange"
+"label"
+"importance"
+"formnovalidate"
+"progress"
+"onoffline"
+"basefont"
+"onkeydown"
+"onpointerdown"
+"invisible"
+"article"
+"nav"
+"srcdoc"
+"onpointercancel"
+"s"
+"onportalactivate"
+"maxlength"
+"srcset"
+"col"
+"color"
+"colspan"
+"height"
+"header"
+"onbeforepaste"
+"oninvalid"
+"onabort"
+"ontimezonechange"
+"autocorrect"
+"mark"
+"bgcolor"
+"onvolumechange"
+"onwebkitfullscreenchange"
+"thead"
+"onblur"
+"onmouseout"
+"shadowroot"
+"onmousewheel"
+"onmousedown"
+"ruby"
+"char"
+"ontoggle"
+"scrolldelay"
+"align"
+"value"
+"keygen"
+"vspace"
+"behavior"
+"loop"
+"layer"
+"crossorigin"
+"onwebkitanimationend"
+"is"
+"id"
+"onloadstart"
+"capture"
+"media"
+"onbeforecut"
+"onclick"
+"ongotpointercapture"
+"samp"
+"onended"
+"onhashchange"
+"portal"
+"ondragend"
+"novalidate"
+"i"
+"exportparts"
+"allowpaymentrequest"
+"draggable"
+"command"
+"ondblclick"
+"onselectstart"
+"autoplay"
+"keytype"
+"shape"
+"noscript"
+"onload"
+"oninput"
+"loading"
+"onmousemove"
+"valign"
+"input"
+"bordercolor"
+"onanimationstart"
+"onkeypress"
+"rules"
+"big"
+"onscrollend"
+"onmouseover"
+"background"
+"shadow"
+"noembed"
+"disablepictureinpicture"
+"wbr"
+"sizes"
+"virtualkeyboardpolicy"
+"oncanplaythrough"
+"onmouseenter"
+"manifest"
+"coords"
+"async"
+"onwaiting"
+"enterkeyhint"
+"srclang"
+"onchange"
+"onwheel"
+"for"
+"onpointerleave"
+"onresize"
+"disableremoteplayback"
+"select"
+"ondrag"
+"onfocusin"
+"preload"
+"acronym"
+"step"
+"br"
+"output"
+"src"
+"ol"
+"allowfullscreen"
+"inputmode"
+"cellpadding"
+"onmessage"
+"disallowdocumentaccess"
+"h2"
+"h3"
+"image"
+"h1"
+"h6"
+"h4"
+"h5"
+"wrap"
+"vlink"
+"rows"
+"span"
+"onratechange"
+"width"
+"low"
+"var"
+"translate"
+"ondrop"
+"nolayer"
+"hr"
+"poster"
+"link"
+"oncontextmenu"
+"onunload"
+"lowsrc"
+"colgroup"
+"default"
+"ul"
+"mayscript"
+"embed"
+"onstorage"
+"onorientationchange"
+"classid"
+"frameset"
+"onformdata"
+"controlslist"
+"onerror"
+"onmessageerror"
+"ondragenter"
+"onanimationiteration"
+"direction"
+"ins"
+"shadowrootdelegatesfocus"
+"as"
+"onafterprint"
+"archive"
+"ondragover"
+"onclose"
+"readonly"
+"role"
+"onlostpointercapture"
+"trusttoken"
+"picture"
+"ondragstart"
+"onpointerrawupdate"
+"onpageshow"
+"scrollamount"
+"frameborder"
+"lang"
+"onwebkittransitionend"
+"ontransitionend"
+"ontouchcancel"
+"required"
+"pseudo"
+"u"
+"time"
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc
new file mode 100644
index 00000000000..ff141f5a65e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc
@@ -0,0 +1,121 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Fuzzer for the Sanitizer API, intended to be run on ClusterFuzz.
+//
+// To test out locally:
+// - Assuming
+// $OUT is your local build output directory with use_libbfuzzer set.
+// $GEN is the suitable 'gen' directory under $OUT. $GEN is
+// $OUT/gen/third_party_blink/renderer/modules/sanitizer_api.
+// - Build:
+// $ ninja -C $OUT sanitizer_api_fuzzer
+// - Run with:
+// $ $OUT/sanitizer_api_fuzzer --dict=$GEN/sanitizer_api.dict \
+// $(mktemp -d) $GEN/corpus/
+
+#include "sanitizer.h"
+
+#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/string_or_document_fragment_or_document.h"
+#include "third_party/blink/renderer/bindings/modules/v8/string_or_trusted_html_or_document_fragment_or_document.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.pb.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
+#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+ScriptState* Initialization() {
+ static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
+ static DummyPageHolder* g_page_holder = new DummyPageHolder();
+ return ToScriptStateForMainWorld(&g_page_holder->GetFrame());
+}
+
+Vector<String> ToVector(
+ const google::protobuf::RepeatedPtrField<std::string>& inputs) {
+ Vector<String> elements;
+ for (auto i : inputs) {
+ elements.push_back(i.c_str());
+ }
+ return elements;
+}
+
+void MakeConfiguration(SanitizerConfig* sanitizer_config,
+ const SanitizerConfigProto& proto) {
+ if (proto.allow_elements_size()) {
+ sanitizer_config->setAllowElements(ToVector(proto.allow_elements()));
+ }
+ if (proto.block_elements_size()) {
+ sanitizer_config->setBlockElements(ToVector(proto.block_elements()));
+ }
+ if (proto.drop_elements_size()) {
+ sanitizer_config->setDropElements(ToVector(proto.drop_elements()));
+ }
+ if (proto.allow_attributes_size()) {
+ Vector<std::pair<String, Vector<String>>> allow_attributes;
+ for (auto i : proto.allow_attributes()) {
+ allow_attributes.push_back(std::pair<String, Vector<String>>(
+ i.first.c_str(), ToVector(i.second.element())));
+ }
+ sanitizer_config->setAllowAttributes(allow_attributes);
+ }
+ if (proto.drop_attributes_size()) {
+ Vector<std::pair<String, Vector<String>>> drop_attributes;
+ for (auto i : proto.drop_attributes()) {
+ drop_attributes.push_back(std::pair<String, Vector<String>>(
+ i.first.c_str(), ToVector(i.second.element())));
+ }
+ sanitizer_config->setDropAttributes(drop_attributes);
+ }
+ sanitizer_config->setAllowCustomElements(proto.allow_custom_elements());
+}
+
+void TextProtoFuzzer(const SanitizerConfigProto& proto,
+ ScriptState* script_state) {
+ // Create Sanitizer based on proto's config..
+ LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+ auto* sanitizer_config = MakeGarbageCollected<SanitizerConfig>();
+ MakeConfiguration(sanitizer_config, proto);
+ auto* sanitizer = MakeGarbageCollected<Sanitizer>(
+ window->GetExecutionContext(), sanitizer_config);
+
+ // Sanitize string given in proto. Method depends on sanitize_to_string.
+ String str = proto.html_string().c_str();
+ if (proto.sanitize_to_string()) {
+ StringOrTrustedHTMLOrDocumentFragmentOrDocument str1 =
+ StringOrTrustedHTMLOrDocumentFragmentOrDocument::FromString(str);
+ sanitizer->sanitize(script_state, str1, IGNORE_EXCEPTION_FOR_TESTING);
+ } else {
+ StringOrDocumentFragmentOrDocument str2 =
+ StringOrDocumentFragmentOrDocument::FromString(str);
+ sanitizer->sanitizeToString(script_state, str2,
+ IGNORE_EXCEPTION_FOR_TESTING);
+ }
+
+ // The fuzzer will eventually run out of memory. Force the GC to run every
+ // N-th time. This will trigger both V8 + Oilpan GC.
+ static size_t counter = 0;
+ if (counter++ > 1000) {
+ counter = 0;
+ V8PerIsolateData::MainThreadIsolate()->RequestGarbageCollectionForTesting(
+ v8::Isolate::kFullGarbageCollection);
+ }
+}
+
+} // namespace blink
+
+DEFINE_TEXT_PROTO_FUZZER(const SanitizerConfigProto& proto) {
+ static blink::ScriptState* script_state = blink::Initialization();
+ blink::TextProtoFuzzer(proto, script_state);
+}
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
index fe55d9542da..ea0cba3cd22 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl
@@ -10,4 +10,5 @@ dictionary SanitizerConfig {
sequence<DOMString> dropElements;
record<DOMString, sequence<DOMString>> allowAttributes;
record<DOMString, sequence<DOMString>> dropAttributes;
+ boolean allowCustomElements = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto
new file mode 100644
index 00000000000..7f463efa4ed
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+message SanitizerConfigProto {
+ required string html_string = 1;
+
+ repeated string allow_elements = 2;
+ repeated string block_elements = 3;
+ repeated string drop_elements = 4;
+
+ message Elements { repeated string element = 1; }
+ map<string, Elements> allow_attributes = 5;
+ map<string, Elements> drop_attributes = 6;
+
+ optional bool allow_custom_elements = 7;
+ optional bool sanitize_to_string = 8;
+}
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc b/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
index e24b63e95d4..cdcdd0e9b6f 100644
--- a/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
+++ b/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
@@ -63,11 +63,11 @@ void DOMScheduler::Trace(Visitor* visitor) const {
Supplement<LocalDOMWindow>::Trace(visitor);
}
-ScriptPromise DOMScheduler::postTask(ScriptState* script_state,
- V8Function* callback_function,
- SchedulerPostTaskOptions* options,
- const HeapVector<ScriptValue>& args,
- ExceptionState& exception_state) {
+ScriptPromise DOMScheduler::postTask(
+ ScriptState* script_state,
+ V8SchedulerPostTaskCallback* callback_function,
+ SchedulerPostTaskOptions* options,
+ ExceptionState& exception_state) {
if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed())
return RejectPromiseImmediately(exception_state);
if (options->signal() && options->signal()->aborted())
@@ -112,8 +112,8 @@ ScriptPromise DOMScheduler::postTask(ScriptState* script_state,
base::TimeDelta::FromMilliseconds(std::max(0, options->delay()));
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- MakeGarbageCollected<DOMTask>(this, resolver, callback_function, args,
- task_signal, delay);
+ MakeGarbageCollected<DOMTask>(this, resolver, callback_function, task_signal,
+ delay);
return resolver->Promise();
}
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.h b/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.h
index 1cec218a5f9..3014dff32e8 100644
--- a/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.h
+++ b/chromium/third_party/blink/renderer/modules/scheduler/dom_scheduler.h
@@ -21,8 +21,7 @@ class DOMTask;
class DOMTaskSignal;
class ExceptionState;
class SchedulerPostTaskOptions;
-class ScriptValue;
-class V8Function;
+class V8SchedulerPostTaskCallback;
class WebSchedulingTaskQueue;
class MODULES_EXPORT DOMScheduler : public ScriptWrappable,
@@ -44,9 +43,8 @@ class MODULES_EXPORT DOMScheduler : public ScriptWrappable,
// underlying context is destroyed, e.g. for detached windows, this will
// return a rejected promise.
ScriptPromise postTask(ScriptState*,
- V8Function*,
+ V8SchedulerPostTaskCallback*,
SchedulerPostTaskOptions*,
- const HeapVector<ScriptValue>& args,
ExceptionState&);
// Returns a TaskSignal representing the state when the current task was
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/dom_task.cc b/chromium/third_party/blink/renderer/modules/scheduler/dom_task.cc
index b3174c69d2c..856c465a556 100644
--- a/chromium/third_party/blink/renderer/modules/scheduler/dom_task.cc
+++ b/chromium/third_party/blink/renderer/modules/scheduler/dom_task.cc
@@ -9,7 +9,7 @@
#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/modules/scheduler/dom_scheduler.h"
@@ -33,13 +33,11 @@ namespace blink {
DOMTask::DOMTask(DOMScheduler* scheduler,
ScriptPromiseResolver* resolver,
- V8Function* callback,
- const HeapVector<ScriptValue>& args,
+ V8SchedulerPostTaskCallback* callback,
DOMTaskSignal* signal,
base::TimeDelta delay)
: scheduler_(scheduler),
callback_(callback),
- arguments_(args),
resolver_(resolver),
signal_(signal),
// TODO(kdillon): Expose queuing time from base::sequence_manager so we
@@ -65,7 +63,6 @@ DOMTask::DOMTask(DOMScheduler* scheduler,
void DOMTask::Trace(Visitor* visitor) const {
visitor->Trace(scheduler_);
visitor->Trace(callback_);
- visitor->Trace(arguments_);
visitor->Trace(resolver_);
visitor->Trace(signal_);
}
@@ -97,7 +94,7 @@ void DOMTask::InvokeInternal(ScriptState* script_state) {
v8_context->SetContinuationPreservedEmbedderData(
ToV8(signal_.Get(), v8_context->Global(), isolate));
ScriptValue result;
- if (callback_->Invoke(nullptr, arguments_).To(&result))
+ if (callback_->Invoke(nullptr).To(&result))
resolver_->Resolve(result.V8Value());
else if (try_catch.HasCaught())
resolver_->Reject(try_catch.Exception());
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/dom_task.h b/chromium/third_party/blink/renderer/modules/scheduler/dom_task.h
index 7c490b2a427..76c408e8dfb 100644
--- a/chromium/third_party/blink/renderer/modules/scheduler/dom_task.h
+++ b/chromium/third_party/blink/renderer/modules/scheduler/dom_task.h
@@ -15,8 +15,7 @@ namespace blink {
class DOMScheduler;
class DOMTaskSignal;
class ScriptState;
-class ScriptValue;
-class V8Function;
+class V8SchedulerPostTaskCallback;
// DOMTask represents a task scheduled via the web scheduling API. It will
// keep itself alive until DOMTask::Invoke is called, which may be after the
@@ -25,8 +24,7 @@ class DOMTask final : public GarbageCollected<DOMTask> {
public:
DOMTask(DOMScheduler*,
ScriptPromiseResolver*,
- V8Function*,
- const HeapVector<ScriptValue>& args,
+ V8SchedulerPostTaskCallback*,
DOMTaskSignal*,
base::TimeDelta delay);
@@ -44,8 +42,7 @@ class DOMTask final : public GarbageCollected<DOMTask> {
Member<DOMScheduler> scheduler_;
TaskHandle task_handle_;
- Member<V8Function> callback_;
- HeapVector<ScriptValue> arguments_;
+ Member<V8SchedulerPostTaskCallback> callback_;
Member<ScriptPromiseResolver> resolver_;
probe::AsyncTaskId async_task_id_;
Member<DOMTaskSignal> signal_;
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/scheduler.idl b/chromium/third_party/blink/renderer/modules/scheduler/scheduler.idl
index 54791a0ebad..a06f1bc2113 100644
--- a/chromium/third_party/blink/renderer/modules/scheduler/scheduler.idl
+++ b/chromium/third_party/blink/renderer/modules/scheduler/scheduler.idl
@@ -9,6 +9,6 @@
ImplementedAs=DOMScheduler,
RuntimeEnabled=WebScheduler
] interface Scheduler {
- [CallWith=ScriptState, MeasureAs=SchedulerPostTask, RaisesException] Promise<any> postTask(Function callback, optional SchedulerPostTaskOptions options = {}, any... arguments);
+ [CallWith=ScriptState, MeasureAs=SchedulerPostTask, RaisesException] Promise<any> postTask(SchedulerPostTaskCallback callback, optional SchedulerPostTaskOptions options = {});
[CallWith=ScriptState, MeasureAs=SchedulerCurrentTaskSignal] readonly attribute TaskSignal currentTaskSignal;
};
diff --git a/chromium/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl b/chromium/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl
new file mode 100644
index 00000000000..7dc1b251eb7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl
@@ -0,0 +1,7 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Experimental Scheduling API Proposal:
+// https://docs.google.com/document/d/1Apz-SD-pOagGeyWxIpgOi0ARNkrCrELhPdm18eeu9tw
+callback SchedulerPostTaskCallback = any ();
diff --git a/chromium/third_party/blink/renderer/modules/screen_enumeration/DIR_METADATA b/chromium/third_party/blink/renderer/modules/screen_enumeration/DIR_METADATA
new file mode 100644
index 00000000000..832447e405b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/screen_enumeration/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/screen_enumeration/OWNERS b/chromium/third_party/blink/renderer/modules/screen_enumeration/OWNERS
index f5a53536028..d3c2ed3d15d 100644
--- a/chromium/third_party/blink/renderer/modules/screen_enumeration/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/screen_enumeration/OWNERS
@@ -1,4 +1 @@
file://content/browser/screen_enumeration/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA b/chromium/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA
new file mode 100644
index 00000000000..7a3e881841d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>ScreenOrientation"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/OWNERS b/chromium/third_party/blink/renderer/modules/screen_orientation/OWNERS
index e56fb05c831..393b01f11b5 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/OWNERS
@@ -2,5 +2,3 @@ mlamouri@chromium.org
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Blink>ScreenOrientation
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 1d51152f775..74697bb52fd 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
@@ -104,14 +104,14 @@ void ScreenOrientationController::UpdateOrientation() {
DCHECK(GetPage());
ChromeClient& chrome_client = GetPage()->GetChromeClient();
LocalFrame& frame = *DomWindow()->GetFrame();
- ScreenInfo screen_info = chrome_client.GetScreenInfo(frame);
+ const ScreenInfo& screen_info = chrome_client.GetScreenInfo(frame);
mojom::blink::ScreenOrientation orientation_type =
screen_info.orientation_type;
if (orientation_type == mojom::blink::ScreenOrientation::kUndefined) {
// The embedder could not provide us with an orientation, deduce it
// ourselves.
- orientation_type = ComputeOrientation(
- chrome_client.GetScreenInfo(frame).rect, screen_info.orientation_angle);
+ orientation_type =
+ ComputeOrientation(screen_info.rect, screen_info.orientation_angle);
}
DCHECK(orientation_type != mojom::blink::ScreenOrientation::kUndefined);
@@ -147,9 +147,11 @@ void ScreenOrientationController::PageVisibilityChanged() {
}
void ScreenOrientationController::NotifyOrientationChanged() {
- // TODO(dcheng): Remove this and check in the caller.
- if (!DomWindow())
+ // TODO(dcheng): Update this code to better handle instances when v8 memory
+ // is forcibly purged.
+ if (!DomWindow()) {
return;
+ }
// 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
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 d7a24e9e9f8..7adce74b056 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
@@ -32,7 +32,7 @@ class MODULES_EXPORT ScreenOrientationController final
public Supplement<LocalDOMWindow> {
public:
explicit ScreenOrientationController(LocalDOMWindow&);
- ~ScreenOrientationController();
+ ~ScreenOrientationController() override;
void SetOrientation(ScreenOrientation*);
void NotifyOrientationChanged();
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 baa6b021746..9aab24e0f95 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,7 +11,8 @@
#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/frame/web_frame_widget_impl.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.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"
@@ -202,17 +203,18 @@ TEST_F(ScreenOrientationControllerTest, RaceScenario) {
EXPECT_FALSE(callback_results2.failed_);
}
-class ScreenInfoWebWidgetClient
- : public frame_test_helpers::TestWebWidgetClient {
+class ScreenInfoWebFrameWidget : public frame_test_helpers::TestWebFrameWidget {
public:
- ScreenInfoWebWidgetClient() = default;
- ~ScreenInfoWebWidgetClient() override = default;
+ template <typename... Args>
+ explicit ScreenInfoWebFrameWidget(Args&&... args)
+ : frame_test_helpers::TestWebFrameWidget(std::forward<Args>(args)...) {
+ screen_info_.orientation_angle = 1234;
+ }
+ ~ScreenInfoWebFrameWidget() override = default;
- // frame_test_helpers::TestWebWidgetClient:
+ // frame_test_helpers::TestWebFrameWidget overrides.
ScreenInfo GetInitialScreenInfo() override { return screen_info_; }
- void SetAngle(uint16_t angle) { screen_info_.orientation_angle = angle; }
-
private:
ScreenInfo screen_info_;
};
@@ -227,11 +229,12 @@ TEST_F(ScreenOrientationControllerTest, PageVisibilityCrash) {
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);
+ frame_test_helpers::CreateTestWebFrameWidgetCallback create_widget_callback =
+ base::BindRepeating(
+ &frame_test_helpers::WebViewHelper::CreateTestWebFrameWidget<
+ ScreenInfoWebFrameWidget>);
+ frame_test_helpers::WebViewHelper web_view_helper(create_widget_callback);
+ web_view_helper.InitializeAndLoad(base_url + test_url, nullptr, nullptr);
Page* page = web_view_helper.GetWebView()->GetPage();
LocalFrame* frame = To<LocalFrame>(page->MainFrame());
@@ -270,10 +273,7 @@ TEST_F(ScreenOrientationControllerTest,
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);
+ web_view_helper.InitializeAndLoad(base_url + test_url, nullptr, nullptr);
Page* page = web_view_helper.GetWebView()->GetPage();
LocalFrame* frame = To<LocalFrame>(page->MainFrame());
@@ -289,7 +289,7 @@ TEST_F(ScreenOrientationControllerTest,
blink::ScreenInfo screen_info;
screen_info.orientation_angle = 90;
auto* web_frame_widget_base =
- static_cast<WebFrameWidgetBase*>(frame->GetWidgetForLocalRoot());
+ static_cast<WebFrameWidgetImpl*>(frame->GetWidgetForLocalRoot());
web_frame_widget_base->UpdateScreenInfo(screen_info);
EXPECT_EQ(grandchild_orientation->angle(), 90);
diff --git a/chromium/third_party/blink/renderer/modules/sensor/BUILD.gn b/chromium/third_party/blink/renderer/modules/sensor/BUILD.gn
index c9991956ee6..d7e1cfd653e 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/sensor/BUILD.gn
@@ -12,6 +12,8 @@ blink_modules_sources("sensor") {
"accelerometer.h",
"ambient_light_sensor.cc",
"ambient_light_sensor.h",
+ "gravity_sensor.cc",
+ "gravity_sensor.h",
"gyroscope.cc",
"gyroscope.h",
"linear_acceleration_sensor.cc",
diff --git a/chromium/third_party/blink/renderer/modules/sensor/DIR_METADATA b/chromium/third_party/blink/renderer/modules/sensor/DIR_METADATA
new file mode 100644
index 00000000000..e919846ad84
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sensor/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Sensor"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/sensor/OWNERS b/chromium/third_party/blink/renderer/modules/sensor/OWNERS
index 9080c9a50a8..461e969a49b 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/sensor/OWNERS
@@ -2,6 +2,3 @@ raphael.kubo.da.costa@intel.com
reillyg@chromium.org
rijubrata.bhaumik@intel.com
timvolodine@chromium.org
-
-# COMPONENT: Blink>Sensor
-# TEAM: device-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.cc
new file mode 100644
index 00000000000..4024d6bfc31
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.cc
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/sensor/gravity_sensor.h"
+
+#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
+
+using device::mojom::blink::SensorType;
+
+namespace blink {
+
+// static
+GravitySensor* GravitySensor::Create(ExecutionContext* execution_context,
+ const SpatialSensorOptions* options,
+ ExceptionState& exception_state) {
+ return MakeGarbageCollected<GravitySensor>(execution_context, options,
+ exception_state);
+}
+
+// static
+GravitySensor* GravitySensor::Create(ExecutionContext* execution_context,
+ ExceptionState& exception_state) {
+ return Create(execution_context, SpatialSensorOptions::Create(),
+ exception_state);
+}
+
+GravitySensor::GravitySensor(ExecutionContext* execution_context,
+ const SpatialSensorOptions* options,
+ ExceptionState& exception_state)
+ : Accelerometer(execution_context,
+ options,
+ exception_state,
+ SensorType::GRAVITY,
+ {mojom::blink::FeaturePolicyFeature::kAccelerometer}) {}
+
+void GravitySensor::Trace(Visitor* visitor) const {
+ Accelerometer::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.h b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.h
new file mode 100644
index 00000000000..863695e9328
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.h
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SENSOR_GRAVITY_SENSOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SENSOR_GRAVITY_SENSOR_H_
+
+#include "third_party/blink/renderer/modules/sensor/accelerometer.h"
+
+namespace blink {
+
+class GravitySensor final : public Accelerometer {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static GravitySensor* Create(ExecutionContext*,
+ const SpatialSensorOptions*,
+ ExceptionState&);
+ static GravitySensor* Create(ExecutionContext*, ExceptionState&);
+
+ GravitySensor(ExecutionContext*,
+ const SpatialSensorOptions*,
+ ExceptionState&);
+
+ void Trace(Visitor*) const override;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SENSOR_GRAVITY_SENSOR_H_
diff --git a/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.idl b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.idl
new file mode 100644
index 00000000000..dcc1bdabfd6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sensor/gravity_sensor.idl
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/accelerometer/#gravitysensor
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=GravitySensor
+] interface GravitySensor : Accelerometer {
+ [CallWith=ExecutionContext, RaisesException, MeasureAs=GravitySensorConstructor] constructor(optional SpatialSensorOptions sensorOptions = {});
+};
diff --git a/chromium/third_party/blink/renderer/modules/sensor/idls.gni b/chromium/third_party/blink/renderer/modules/sensor/idls.gni
index 07639bd06c7..d6bcf3feec6 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/sensor/idls.gni
@@ -6,6 +6,7 @@ modules_idl_files = [
"absolute_orientation_sensor.idl",
"accelerometer.idl",
"ambient_light_sensor.idl",
+ "gravity_sensor.idl",
"gyroscope.idl",
"linear_acceleration_sensor.idl",
"magnetometer.idl",
diff --git a/chromium/third_party/blink/renderer/modules/sensor/orientation_sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/orientation_sensor.cc
index c05b40594b2..56fce405db1 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/orientation_sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/orientation_sensor.cc
@@ -102,9 +102,9 @@ void OrientationSensor::populateMatrix(
Float32ArrayOrFloat64ArrayOrDOMMatrix& matrix,
ExceptionState& exception_state) {
if (matrix.IsFloat32Array())
- PopulateMatrixInternal(matrix.GetAsFloat32Array().View(), exception_state);
+ PopulateMatrixInternal(matrix.GetAsFloat32Array().Get(), exception_state);
else if (matrix.IsFloat64Array())
- PopulateMatrixInternal(matrix.GetAsFloat64Array().View(), exception_state);
+ PopulateMatrixInternal(matrix.GetAsFloat64Array().Get(), exception_state);
else if (matrix.IsDOMMatrix())
PopulateMatrixInternal(matrix.GetAsDOMMatrix(), exception_state);
else
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
index 3d777b1a894..23b242fa937 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -52,7 +52,7 @@ Sensor::Sensor(ExecutionContext* execution_context,
if (!AreFeaturesEnabled(execution_context, features)) {
exception_state.ThrowSecurityError(
- "Access to sensor features is disallowed by feature policy");
+ "Access to sensor features is disallowed by permissions policy");
return;
}
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 db6b9d3324c..4cd63ded0d4 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
@@ -34,6 +34,7 @@ SensorProxyImpl::~SensorProxyImpl() {}
void SensorProxyImpl::Trace(Visitor* visitor) const {
visitor->Trace(sensor_remote_);
visitor->Trace(client_receiver_);
+ visitor->Trace(polling_timer_);
SensorProxy::Trace(visitor);
}
@@ -138,8 +139,6 @@ void SensorProxyImpl::ReportError(DOMExceptionCode code,
reading_ = device::SensorReading();
UpdatePollingStatus();
- // The m_sensor.reset() will release all callbacks and its bound parameters,
- // therefore, handleSensorError accepts messages by value.
sensor_remote_.reset();
shared_buffer_reader_.reset();
default_frequency_ = 0.0;
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
index 815c7c7bb24..7b1db9785fa 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
@@ -86,7 +86,7 @@ class SensorProxyImpl final : public SensorProxy,
bool suspended_ = false;
WTF::Vector<double> active_frequencies_;
- TaskRunnerTimer<SensorProxyImpl> polling_timer_;
+ HeapTaskRunnerTimer<SensorProxyImpl> polling_timer_;
DISALLOW_COPY_AND_ASSIGN(SensorProxyImpl);
};
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_reading_remapper.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_reading_remapper.cc
index 0949236d31e..b904f1daace 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_reading_remapper.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_reading_remapper.cc
@@ -125,6 +125,7 @@ void SensorReadingRemapper::RemapToScreenCoords(
break;
case SensorType::ACCELEROMETER:
case SensorType::LINEAR_ACCELERATION:
+ case SensorType::GRAVITY:
RemapSensorReadingXYZ(angle, reading->accel);
break;
case SensorType::GYROSCOPE:
diff --git a/chromium/third_party/blink/renderer/modules/serial/BUILD.gn b/chromium/third_party/blink/renderer/modules/serial/BUILD.gn
index db1e96d3167..56e34dbdea2 100644
--- a/chromium/third_party/blink/renderer/modules/serial/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/serial/BUILD.gn
@@ -10,19 +10,13 @@ assert(!is_android)
blink_modules_sources("serial") {
sources = [
- "navigator_serial.cc",
- "navigator_serial.h",
"serial.cc",
"serial.h",
- "serial_connection_event.cc",
- "serial_connection_event.h",
"serial_port.cc",
"serial_port.h",
"serial_port_underlying_sink.cc",
"serial_port_underlying_sink.h",
"serial_port_underlying_source.cc",
"serial_port_underlying_source.h",
- "worker_navigator_serial.cc",
- "worker_navigator_serial.h",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/serial/DIR_METADATA b/chromium/third_party/blink/renderer/modules/serial/DIR_METADATA
new file mode 100644
index 00000000000..9b3d5d83383
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/serial/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Serial"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/serial/OWNERS b/chromium/third_party/blink/renderer/modules/serial/OWNERS
index 4ae83cac16e..737283cc8fa 100644
--- a/chromium/third_party/blink/renderer/modules/serial/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/serial/OWNERS
@@ -1,3 +1 @@
file://content/browser/serial/OWNERS
-
-# COMPONENT: Blink>Serial
diff --git a/chromium/third_party/blink/renderer/modules/serial/idls.gni b/chromium/third_party/blink/renderer/modules/serial/idls.gni
index ad28c9ed62b..b6dcf4009f6 100644
--- a/chromium/third_party/blink/renderer/modules/serial/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/serial/idls.gni
@@ -4,12 +4,10 @@
modules_idl_files = [
"serial.idl",
- "serial_connection_event.idl",
"serial_port.idl",
]
modules_dictionary_idl_files = [
- "serial_connection_event_init.idl",
"serial_input_signals.idl",
"serial_options.idl",
"serial_output_signals.idl",
diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc
deleted file mode 100644
index a290e90aaef..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/serial/navigator_serial.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/modules/serial/serial.h"
-
-namespace blink {
-
-const char NavigatorSerial::kSupplementName[] = "NavigatorSerial";
-
-NavigatorSerial& NavigatorSerial::From(Navigator& navigator) {
- NavigatorSerial* supplement =
- Supplement<Navigator>::From<NavigatorSerial>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorSerial>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-Serial* NavigatorSerial::serial(Navigator& navigator) {
- return NavigatorSerial::From(navigator).serial();
-}
-
-void NavigatorSerial::Trace(Visitor* visitor) const {
- visitor->Trace(serial_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-NavigatorSerial::NavigatorSerial(Navigator& navigator)
- : Supplement<Navigator>(navigator) {
- if (navigator.DomWindow()) {
- serial_ = MakeGarbageCollected<Serial>(*navigator.DomWindow());
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h
deleted file mode 100644
index 14c9d3dc290..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Serial;
-
-class NavigatorSerial final : public GarbageCollected<NavigatorSerial>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static NavigatorSerial& From(Navigator&);
-
- static Serial* serial(Navigator&);
- Serial* serial() { return serial_; }
-
- explicit NavigatorSerial(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<Serial> serial_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl
index 380dbca369c..fc9a5a5a74e 100644
--- a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl
+++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl
@@ -5,7 +5,7 @@
// https://wicg.github.io/serial
[
- ImplementedAs=NavigatorSerial,
+ ImplementedAs=Serial,
RuntimeEnabled=Serial,
SecureContext
] partial interface Navigator {
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.cc b/chromium/third_party/blink/renderer/modules/serial/serial.cc
index 9627755893e..9d985b63072 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/serial.cc
@@ -17,9 +17,9 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/event_target_modules_names.h"
-#include "third_party/blink/renderer/modules/serial/serial_connection_event.h"
#include "third_party/blink/renderer/modules/serial/serial_port.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -29,7 +29,7 @@ namespace {
const char kContextGone[] = "Script context has shut down.";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"serial\" is disallowed by feature policy.";
+ "Access to the feature \"serial\" is disallowed by permissions policy.";
const char kNoPortSelected[] = "No port selected by the user.";
String TokenToString(const base::UnguessableToken& token) {
@@ -41,10 +41,22 @@ String TokenToString(const base::UnguessableToken& token) {
} // namespace
-Serial::Serial(ExecutionContext& execution_context)
- : ExecutionContextLifecycleObserver(&execution_context),
- service_(&execution_context),
- receiver_(this, &execution_context) {}
+const char Serial::kSupplementName[] = "Serial";
+
+Serial* Serial::serial(NavigatorBase& navigator) {
+ Serial* serial = Supplement<NavigatorBase>::From<Serial>(navigator);
+ if (!serial) {
+ serial = MakeGarbageCollected<Serial>(navigator);
+ ProvideTo(navigator, serial);
+ }
+ return serial;
+}
+
+Serial::Serial(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()),
+ service_(navigator.GetExecutionContext()),
+ receiver_(this, navigator.GetExecutionContext()) {}
ExecutionContext* Serial::GetExecutionContext() const {
return ExecutionContextLifecycleObserver::GetExecutionContext();
@@ -60,13 +72,13 @@ void Serial::ContextDestroyed() {
}
void Serial::OnPortAdded(mojom::blink::SerialPortInfoPtr port_info) {
- DispatchEvent(*SerialConnectionEvent::Create(
- event_type_names::kConnect, GetOrCreatePort(std::move(port_info))));
+ SerialPort* port = GetOrCreatePort(std::move(port_info));
+ port->DispatchEvent(*Event::CreateBubble(event_type_names::kConnect));
}
void Serial::OnPortRemoved(mojom::blink::SerialPortInfoPtr port_info) {
- DispatchEvent(*SerialConnectionEvent::Create(
- event_type_names::kDisconnect, GetOrCreatePort(std::move(port_info))));
+ SerialPort* port = GetOrCreatePort(std::move(port_info));
+ port->DispatchEvent(*Event::CreateBubble(event_type_names::kDisconnect));
}
ScriptPromise Serial::getPorts(ScriptState* script_state,
@@ -173,6 +185,7 @@ void Serial::Trace(Visitor* visitor) const {
visitor->Trace(request_port_promises_);
visitor->Trace(port_cache_);
EventTargetWithInlineData::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.h b/chromium/third_party/blink/renderer/modules/serial/serial.h
index ea0032df18c..7eb88968907 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial.h
+++ b/chromium/third_party/blink/renderer/modules/serial/serial.h
@@ -15,23 +15,31 @@
#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/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
class ExecutionContext;
+class NavigatorBase;
class ScriptPromiseResolver;
class ScriptState;
class SerialPort;
class SerialPortRequestOptions;
class Serial final : public EventTargetWithInlineData,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver,
public mojom::blink::SerialServiceClient {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit Serial(ExecutionContext&);
+ static const char kSupplementName[];
+
+ // Web-exposed navigator.serial
+ static Serial* serial(NavigatorBase&);
+
+ explicit Serial(NavigatorBase&);
// EventTarget
ExecutionContext* GetExecutionContext() const override;
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.cc b/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.cc
deleted file mode 100644
index 98fd77de0fb..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.cc
+++ /dev/null
@@ -1,37 +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/serial/serial_connection_event.h"
-
-#include "third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event_init.h"
-#include "third_party/blink/renderer/modules/serial/serial_port.h"
-
-namespace blink {
-
-SerialConnectionEvent* SerialConnectionEvent::Create(
- const AtomicString& type,
- const SerialConnectionEventInit* initializer) {
- return MakeGarbageCollected<SerialConnectionEvent>(type, initializer);
-}
-
-SerialConnectionEvent* SerialConnectionEvent::Create(const AtomicString& type,
- SerialPort* port) {
- return MakeGarbageCollected<SerialConnectionEvent>(type, port);
-}
-
-SerialConnectionEvent::SerialConnectionEvent(
- const AtomicString& type,
- const SerialConnectionEventInit* initializer)
- : Event(type, initializer), port_(initializer->port()) {}
-
-SerialConnectionEvent::SerialConnectionEvent(const AtomicString& type,
- SerialPort* port)
- : Event(type, Bubbles::kNo, Cancelable::kNo), port_(port) {}
-
-void SerialConnectionEvent::Trace(Visitor* visitor) const {
- visitor->Trace(port_);
- Event::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.h b/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.h
deleted file mode 100644
index ad47f6ced9c..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.h
+++ /dev/null
@@ -1,38 +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_SERIAL_SERIAL_CONNECTION_EVENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_CONNECTION_EVENT_H_
-
-#include "third_party/blink/renderer/modules/event_modules.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class SerialConnectionEventInit;
-class SerialPort;
-
-class SerialConnectionEvent final : public Event {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- static SerialConnectionEvent* Create(const AtomicString& type,
- const SerialConnectionEventInit*);
- static SerialConnectionEvent* Create(const AtomicString& type, SerialPort*);
-
- SerialConnectionEvent(const AtomicString& type,
- const SerialConnectionEventInit*);
- SerialConnectionEvent(const AtomicString& type, SerialPort*);
-
- SerialPort* port() const { return port_; }
-
- void Trace(Visitor*) const override;
-
- private:
- Member<SerialPort> port_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_CONNECTION_EVENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.idl b/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.idl
deleted file mode 100644
index 994f85892bb..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event.idl
+++ /dev/null
@@ -1,11 +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.
-
-[
- Exposed(Window Serial, DedicatedWorker Serial),
- SecureContext
-] interface SerialConnectionEvent : Event {
- constructor(DOMString type, SerialConnectionEventInit eventInitDict);
- [SameObject] readonly attribute SerialPort port;
-};
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event_init.idl b/chromium/third_party/blink/renderer/modules/serial/serial_connection_event_init.idl
deleted file mode 100644
index 70c2c0d5d1f..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/serial_connection_event_init.idl
+++ /dev/null
@@ -1,7 +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.
-
-dictionary SerialConnectionEventInit : EventInit {
- required SerialPort port;
-};
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.cc b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
index f17d76398ea..681820acde8 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -12,8 +12,10 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_serial_output_signals.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_serial_port_info.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/modules/event_target_modules_names.h"
#include "third_party/blink/renderer/modules/serial/serial.h"
#include "third_party/blink/renderer/modules/serial/serial_port_underlying_sink.h"
#include "third_party/blink/renderer/modules/serial/serial_port_underlying_source.h"
@@ -122,7 +124,7 @@ class ContinueCloseFunction : public ScriptFunction {
: ScriptFunction(script_state), port_(port) {}
ScriptValue Call(ScriptValue) override {
- return port_->ContinueClose(GetScriptState()).GetScriptValue();
+ return port_->ContinueClose(GetScriptState()).AsScriptValue();
}
void Trace(Visitor* visitor) const override {
@@ -509,10 +511,6 @@ void SerialPort::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
}
-ExecutionContext* SerialPort::GetExecutionContext() const {
- return parent_->GetExecutionContext();
-}
-
bool SerialPort::HasPendingActivity() const {
// There is no need to check if the execution context has been destroyed, this
// is handled by the common tracing logic.
@@ -522,6 +520,40 @@ bool SerialPort::HasPendingActivity() const {
return port_.is_bound();
}
+ExecutionContext* SerialPort::GetExecutionContext() const {
+ return parent_->GetExecutionContext();
+}
+
+const AtomicString& SerialPort::InterfaceName() const {
+ return event_target_names::kSerialPort;
+}
+
+DispatchEventResult SerialPort::DispatchEventInternal(Event& event) {
+ event.SetTarget(this);
+
+ // Events fired on a SerialPort instance bubble to the parent Serial instance.
+ event.SetEventPhase(Event::kCapturingPhase);
+ event.SetCurrentTarget(parent_);
+ parent_->FireEventListeners(event);
+ if (event.PropagationStopped())
+ goto doneDispatching;
+
+ event.SetEventPhase(Event::kAtTarget);
+ event.SetCurrentTarget(this);
+ FireEventListeners(event);
+ if (event.PropagationStopped() || !event.bubbles())
+ goto doneDispatching;
+
+ event.SetEventPhase(Event::kBubblingPhase);
+ event.SetCurrentTarget(parent_);
+ parent_->FireEventListeners(event);
+
+doneDispatching:
+ event.SetCurrentTarget(nullptr);
+ event.SetEventPhase(Event::kNone);
+ return EventTarget::GetDispatchEventResult(event);
+}
+
void SerialPort::OnReadError(device::mojom::blink::SerialReceiveError error) {
if (ReceiveErrorIsFatal(error))
read_fatal_ = true;
@@ -544,7 +576,7 @@ bool SerialPort::CreateDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
options.element_num_bytes = 1;
options.capacity_num_bytes = buffer_size_;
- MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
if (result == MOJO_RESULT_OK)
return true;
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.h b/chromium/third_party/blink/renderer/modules/serial/serial_port.h
index e3b957f8eb1..13fa4983d41 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.h
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.h
@@ -10,6 +10,7 @@
#include "third_party/blink/public/mojom/serial/serial.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -34,7 +35,7 @@ class SerialPortUnderlyingSink;
class SerialPortUnderlyingSource;
class WritableStream;
-class SerialPort final : public ScriptWrappable,
+class SerialPort final : public EventTargetWithInlineData,
public ActiveScriptWrappable<SerialPort>,
public device::mojom::blink::SerialPortClient {
DEFINE_WRAPPERTYPEINFO();
@@ -44,6 +45,8 @@ class SerialPort final : public ScriptWrappable,
~SerialPort() override;
// Web-exposed functions
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(connect, kConnect)
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect, kDisconnect)
SerialPortInfo* getInfo();
ScriptPromise open(ScriptState*,
const SerialOptions* options,
@@ -72,9 +75,13 @@ class SerialPort final : public ScriptWrappable,
void Trace(Visitor*) const override;
// ActiveScriptWrappable
- ExecutionContext* GetExecutionContext() const;
bool HasPendingActivity() const override;
+ // EventTargetWithInlineData
+ ExecutionContext* GetExecutionContext() const override;
+ const AtomicString& InterfaceName() const override;
+ DispatchEventResult DispatchEventInternal(Event& event) override;
+
// SerialPortClient
void OnReadError(device::mojom::blink::SerialReceiveError) override;
void OnSendError(device::mojom::blink::SerialSendError) override;
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.idl b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
index 7181642e7f0..3dd97a32217 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl
@@ -8,7 +8,10 @@
ActiveScriptWrappable,
Exposed(Window Serial,DedicatedWorker Serial),
SecureContext
-] interface SerialPort {
+] interface SerialPort : EventTarget {
+ attribute EventHandler onconnect;
+ attribute EventHandler ondisconnect;
+
[CallWith=ScriptState, RaisesException]
readonly attribute ReadableStream readable;
[CallWith=ScriptState, RaisesException]
diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
index dc273c5fc4e..6e431ccb1d5 100644
--- a/chromium/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/serial/serial_port_underlying_sink.cc
@@ -178,7 +178,7 @@ void SerialPortUnderlyingSink::WriteData() {
byte_size = array->ByteLength();
data = static_cast<const uint8_t*>(array->Data());
} else {
- DOMArrayBufferView* view = buffer_source_.GetAsArrayBufferView().View();
+ DOMArrayBufferView* view = buffer_source_.GetAsArrayBufferView().Get();
byte_size = view->byteLength();
data = static_cast<const uint8_t*>(view->BaseAddress());
}
diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
deleted file mode 100644
index 0ececc63f1d..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/serial/worker_navigator_serial.h"
-
-#include "third_party/blink/renderer/modules/serial/serial.h"
-
-namespace blink {
-
-const char WorkerNavigatorSerial::kSupplementName[] = "WorkerNavigatorSerial";
-
-WorkerNavigatorSerial& WorkerNavigatorSerial::From(WorkerNavigator& navigator) {
- WorkerNavigatorSerial* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorSerial>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorSerial>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-Serial* WorkerNavigatorSerial::serial(ScriptState* script_state,
- WorkerNavigator& navigator) {
- return WorkerNavigatorSerial::From(navigator).serial(script_state);
-}
-
-Serial* WorkerNavigatorSerial::serial(ScriptState* script_state) {
- if (!serial_) {
- auto* execution_context = ExecutionContext::From(script_state);
- DCHECK(execution_context);
-
- // TODO(https://crbug.com/839117): Remove this check once the Exposed
- // attribute is fixed to only expose this property in dedicated workers.
- if (execution_context->IsDedicatedWorkerGlobalScope())
- serial_ = MakeGarbageCollected<Serial>(*execution_context);
- }
- return serial_;
-}
-
-void WorkerNavigatorSerial::Trace(Visitor* visitor) const {
- visitor->Trace(serial_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-WorkerNavigatorSerial::WorkerNavigatorSerial(WorkerNavigator& navigator)
- : Supplement<WorkerNavigator>(navigator) {}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
deleted file mode 100644
index 0a733eb8bfb..00000000000
--- a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class ScriptState;
-class Serial;
-
-class WorkerNavigatorSerial final
- : public GarbageCollected<WorkerNavigatorSerial>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static WorkerNavigatorSerial& From(WorkerNavigator&);
-
- static Serial* serial(ScriptState*, WorkerNavigator&);
- Serial* serial(ScriptState*);
-
- explicit WorkerNavigatorSerial(WorkerNavigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<Serial> serial_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
index 332080e8527..1bb99e1b1c8 100644
--- a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
+++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
@@ -5,13 +5,10 @@
// https://wicg.github.io/serial
[
- // TODO(crbug.com/839117): Enable the following [Exposed] on the partial
- // interface declaration once it's supported.
- //
- // Exposed=DedicatedWorker,
- ImplementedAs=WorkerNavigatorSerial,
+ Exposed=DedicatedWorker,
+ ImplementedAs=Serial,
RuntimeEnabled=Serial,
SecureContext
] partial interface WorkerNavigator {
- [CallWith=ScriptState, SameObject] readonly attribute Serial serial;
+ [SameObject] readonly attribute Serial serial;
};
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/DIR_METADATA b/chromium/third_party/blink/renderer/modules/service_worker/DIR_METADATA
new file mode 100644
index 00000000000..f0962523cd6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/service_worker/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>ServiceWorker"
+}
+team_email: "worker-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/OWNERS b/chromium/third_party/blink/renderer/modules/service_worker/OWNERS
index c4264613708..970e7eac8a1 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/service_worker/OWNERS
@@ -1,5 +1,2 @@
file://content/browser/service_worker/OWNERS
-# TEAM: worker-dev@chromium.org
-# COMPONENT: Blink>ServiceWorker
-
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 04ddb638666..da1d20a9bb8 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
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h"
#include "services/network/public/cpp/cross_origin_resource_policy.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/renderer/core/fetch/response.h"
namespace blink {
@@ -15,11 +16,7 @@ CrossOriginResourcePolicyChecker::CrossOriginResourcePolicyChecker(
network::mojom::blink::CrossOriginEmbedderPolicyReporter> reporter)
: policy_(std::move(policy)) {
if (reporter) {
- mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
- pending_reporter_non_blink{
- reporter.PassPipe(),
- network::mojom::CrossOriginEmbedderPolicyReporter::Version_};
- reporter_.Bind(std::move(pending_reporter_non_blink));
+ reporter_.Bind(ToCrossVariantMojoType(std::move(reporter)));
}
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.cc b/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.cc
index 67aa88f2475..7780d3da3aa 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.cc
@@ -4,6 +4,10 @@
#include "third_party/blink/renderer/modules/service_worker/extendable_message_event.h"
+#include "third_party/blink/renderer/core/messaging/message_port.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_client.h"
+
namespace blink {
ExtendableMessageEvent* ExtendableMessageEvent::Create(
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.h b/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.h
index 8709481d15c..8526303d3de 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/extendable_message_event.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_EXTENDABLE_MESSAGE_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_EXTENDABLE_MESSAGE_EVENT_H_
+#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/serialization/transferables.h"
#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_extendable_message_event_init.h"
#include "third_party/blink/renderer/modules/event_modules.h"
@@ -13,6 +15,10 @@
namespace blink {
+class MessagePort;
+class ServiceWorkerClient;
+class ServiceWorker;
+
class MODULES_EXPORT ExtendableMessageEvent final : public ExtendableEvent {
DEFINE_WRAPPERTYPEINFO();
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
index 28d7ddd6787..00d5d2095da 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
@@ -153,18 +153,24 @@ void FetchEvent::OnNavigationPreloadResponse(
? FetchResponseData::CreateWithBuffer(BodyStreamBuffer::Create(
script_state, bytes_consumer,
MakeGarbageCollected<AbortSignal>(
- ExecutionContext::From(script_state))))
+ ExecutionContext::From(script_state)),
+ /*cached_metadata_handler=*/nullptr))
: FetchResponseData::Create();
Vector<KURL> url_list(1);
url_list[0] = preload_response_->CurrentRequestUrl();
+ auto response_type =
+ network_utils::IsRedirectResponseCode(preload_response_->HttpStatusCode())
+ ? network::mojom::FetchResponseType::kOpaqueRedirect
+ : network::mojom::FetchResponseType::kBasic;
+
response_data->InitFromResourceResponse(
- url_list, http_names::kGET, network::mojom::CredentialsMode::kInclude,
- FetchRequestData::kBasicTainting,
+ ExecutionContext::From(script_state), response_type, url_list,
+ http_names::kGET, network::mojom::CredentialsMode::kInclude,
preload_response_->ToResourceResponse());
FetchResponseData* tainted_response =
- network_utils::IsRedirectResponseCode(preload_response_->HttpStatusCode())
+ response_type == network::mojom::FetchResponseType::kOpaqueRedirect
? response_data->CreateOpaqueRedirectFilteredResponse()
: response_data->CreateBasicFilteredResponse();
preload_response_property_->Resolve(
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 071f55848fa..9cf7326f0bb 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
@@ -7,12 +7,10 @@
#include <memory>
#include <utility>
-#include "base/feature_list.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
@@ -24,6 +22,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h"
#include "third_party/blink/renderer/modules/service_worker/fetch_event.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
@@ -294,28 +293,24 @@ void FetchRespondWithObserver::OnResponseFulfilled(
// If Cross-Origin-Embedder-Policy is set to require-corp,
// Cross-Origin-Resource-Policy verification should happen before passing the
- // response to the client.
- if (base::FeatureList::IsEnabled(
- network::features::kCrossOriginEmbedderPolicy)) {
- // The service worker script must be in the same origin with the requestor,
- // which is a client of the service worker.
- //
- // Here is in the renderer and we don't have a "trustworthy" initiator.
- // Hence we provide |initiator_origin| as |request_initiator_origin_lock|.
- auto initiator_origin =
- url::Origin::Create(GURL(service_worker_global_scope->Url()));
- // |corp_checker_| could be nullptr when the request is for a main resource
- // or the connection to the client which initiated the request is broken.
- // CORP check isn't needed in both cases because a service worker should be
- // in the same origin with the main resource, and the response to the broken
- // connection won't reach to the client.
- if (corp_checker_ &&
- corp_checker_->IsBlocked(
- url::Origin::Create(GURL(service_worker_global_scope->Url())),
- request_mode_, request_destination_, *response)) {
- OnResponseRejected(ServiceWorkerResponseError::kDisallowedByCorp);
- return;
- }
+ // response to the client. The service worker script must be in the same
+ // origin with the requestor, which is a client of the service worker.
+ //
+ // Here is in the renderer and we don't have a "trustworthy" initiator.
+ // Hence we provide |initiator_origin| as |request_initiator_origin_lock|.
+ auto initiator_origin =
+ url::Origin::Create(GURL(service_worker_global_scope->Url()));
+ // |corp_checker_| could be nullptr when the request is for a main resource
+ // or the connection to the client which initiated the request is broken.
+ // CORP check isn't needed in both cases because a service worker should be
+ // in the same origin with the main resource, and the response to the broken
+ // connection won't reach to the client.
+ if (corp_checker_ &&
+ corp_checker_->IsBlocked(
+ url::Origin::Create(GURL(service_worker_global_scope->Url())),
+ request_mode_, request_destination_, *response)) {
+ OnResponseRejected(ServiceWorkerResponseError::kDisallowedByCorp);
+ return;
}
BodyStreamBuffer* buffer = response->InternalBodyBuffer();
@@ -375,6 +370,19 @@ void FetchRespondWithObserver::OnResponseFulfilled(
void FetchRespondWithObserver::OnNoResponse() {
DCHECK(GetExecutionContext());
+ if (request_body_stream_ && (request_body_stream_->IsLocked() ||
+ request_body_stream_->IsDisturbed())) {
+ GetExecutionContext()->CountUse(
+ WebFeature::kFetchRespondWithNoResponseWithUsedRequestBody);
+ if (!request_body_has_source_) {
+ OnResponseRejected(
+ mojom::blink::ServiceWorkerResponseError::kRequestBodyUnusable);
+ return;
+ }
+ }
+ if (request_body_stream_ && !request_body_has_source_) {
+ // TODO(crbug.com/1165690): Cancel `request_body_stream_`.
+ }
ServiceWorkerGlobalScope* service_worker_global_scope =
To<ServiceWorkerGlobalScope>(GetExecutionContext());
service_worker_global_scope->RespondToFetchEventWithNoResponse(
@@ -382,6 +390,17 @@ void FetchRespondWithObserver::OnNoResponse() {
event_->ResolveHandledPromise();
}
+void FetchRespondWithObserver::SetEvent(FetchEvent* event) {
+ DCHECK(!event_);
+ DCHECK(!request_body_stream_);
+ event_ = event;
+ // We don't use Body::body() in order to avoid accidental CountUse calls.
+ BodyStreamBuffer* body_buffer = event_->request()->BodyBuffer();
+ if (body_buffer) {
+ request_body_stream_ = body_buffer->Stream();
+ }
+}
+
FetchRespondWithObserver::FetchRespondWithObserver(
ExecutionContext* context,
int fetch_event_id,
@@ -394,11 +413,13 @@ FetchRespondWithObserver::FetchRespondWithObserver(
redirect_mode_(request.redirect_mode),
frame_type_(request.frame_type),
request_destination_(request.destination),
+ request_body_has_source_(request.body.FormBody()),
corp_checker_(std::move(corp_checker)),
task_runner_(context->GetTaskRunner(TaskType::kNetworking)) {}
void FetchRespondWithObserver::Trace(Visitor* visitor) const {
visitor->Trace(event_);
+ visitor->Trace(request_body_stream_);
RespondWithObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
index 2de78848c9f..6cbcdfe761f 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
@@ -18,6 +18,7 @@ namespace blink {
class CrossOriginResourcePolicyChecker;
class ExecutionContext;
class FetchEvent;
+class ReadableStream;
class ScriptValue;
class WaitUntilObserver;
@@ -47,10 +48,7 @@ class MODULES_EXPORT FetchRespondWithObserver : public RespondWithObserver {
const char* property_name) override;
void OnNoResponse() override;
- void SetEvent(FetchEvent* event) {
- DCHECK(!event_);
- event_ = event;
- }
+ void SetEvent(FetchEvent* event);
void Trace(Visitor*) const override;
@@ -61,6 +59,9 @@ class MODULES_EXPORT FetchRespondWithObserver : public RespondWithObserver {
const mojom::RequestContextFrameType frame_type_;
const network::mojom::RequestDestination request_destination_;
Member<FetchEvent> event_;
+ Member<ReadableStream> request_body_stream_;
+ // https://fetch.spec.whatwg.org/#concept-body-source
+ const bool request_body_has_source_;
base::WeakPtr<CrossOriginResourcePolicyChecker> corp_checker_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
index 21e6bbc7316..bd92d631948 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h"
#include "base/bind.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
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 c5c1ba9fa54..862a8a747c3 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
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
+#include <algorithm>
#include <memory>
#include <utility>
@@ -47,6 +48,7 @@
#include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/timing/worker_timing_container.mojom-blink.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/public/mojom/worker/subresource_loader_updater.mojom.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_fetch_context.h"
@@ -74,6 +76,7 @@
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
#include "third_party/blink/renderer/core/loader/worker_resource_timing_notifier_impl.h"
#include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
+#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
@@ -198,8 +201,7 @@ ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create(
installed_scripts_manager,
mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote,
base::TimeTicks time_origin,
- const ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id) {
+ const ServiceWorkerToken& service_worker_token) {
#if DCHECK_IS_ON()
// If the script is being loaded via script streaming, the script is not yet
// loaded.
@@ -207,7 +209,7 @@ ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create(
creation_params->script_url)) {
// CSP headers, referrer policy, and origin trial tokens will be provided by
// the InstalledScriptsManager in EvaluateClassicScript().
- DCHECK(creation_params->outside_content_security_policy_headers.IsEmpty());
+ DCHECK(creation_params->outside_content_security_policies.IsEmpty());
DCHECK_EQ(network::mojom::ReferrerPolicy::kDefault,
creation_params->referrer_policy);
DCHECK(creation_params->origin_trial_tokens->IsEmpty());
@@ -216,8 +218,7 @@ ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create(
return MakeGarbageCollected<ServiceWorkerGlobalScope>(
std::move(creation_params), thread, std::move(installed_scripts_manager),
- std::move(cache_storage_remote), time_origin, service_worker_token,
- ukm_source_id);
+ std::move(cache_storage_remote), time_origin, service_worker_token);
}
ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
@@ -227,12 +228,8 @@ ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
installed_scripts_manager,
mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote,
base::TimeTicks time_origin,
- const ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id)
- : WorkerGlobalScope(std::move(creation_params),
- thread,
- time_origin,
- ukm_source_id),
+ const ServiceWorkerToken& service_worker_token)
+ : WorkerGlobalScope(std::move(creation_params), thread, time_origin),
installed_scripts_manager_(std::move(installed_scripts_manager)),
cache_storage_remote_(std::move(cache_storage_remote)),
token_(service_worker_token) {
@@ -328,6 +325,10 @@ void ServiceWorkerGlobalScope::FetchAndRunModuleScript(
RejectCoepUnsafeNone reject_coep_unsafe_none) {
DCHECK(IsContextThread());
DCHECK(!reject_coep_unsafe_none);
+ if (worker_main_script_load_params) {
+ SetWorkerMainScriptLoadingParametersForModules(
+ std::move(worker_main_script_load_params));
+ }
ModuleScriptCustomFetchType fetch_type =
installed_scripts_manager_
? ModuleScriptCustomFetchType::kInstalledServiceWorker
@@ -469,8 +470,9 @@ void ServiceWorkerGlobalScope::DidFetchClassicScript(
classic_script_loader->ResponseURL(), referrer_policy,
classic_script_loader->ResponseAddressSpace(),
classic_script_loader->GetContentSecurityPolicy()
- ? classic_script_loader->GetContentSecurityPolicy()->Headers()
- : Vector<CSPHeaderAndType>(),
+ ? mojo::Clone(classic_script_loader->GetContentSecurityPolicy()
+ ->GetParsedPolicies())
+ : Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
classic_script_loader->OriginTrialTokens(),
classic_script_loader->SourceText(),
classic_script_loader->ReleaseCachedMetadata(), stack_id);
@@ -481,7 +483,7 @@ void ServiceWorkerGlobalScope::Initialize(
const KURL& response_url,
network::mojom::ReferrerPolicy response_referrer_policy,
network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
const Vector<String>* response_origin_trial_tokens,
int64_t appcache_id) {
// Step 4.5. "Set workerGlobalScope's url to serviceWorker's script url."
@@ -511,7 +513,7 @@ void ServiceWorkerGlobalScope::Initialize(
//
// These should be called after SetAddressSpace() to correctly override the
// address space by the "treat-as-public-address" CSP directive.
- InitContentSecurityPolicyFromVector(response_csp_headers);
+ InitContentSecurityPolicyFromVector(std::move(response_csp));
BindContentSecurityPolicyToExecutionContext();
OriginTrialContext::AddTokens(this, response_origin_trial_tokens);
@@ -554,16 +556,10 @@ void ServiceWorkerGlobalScope::LoadAndRunInstalledClassicScript(
kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy);
}
- // Construct a ContentSecurityPolicy object to convert
- // ContentSecurityPolicyResponseHeaders to CSPHeaderAndType.
- // TODO(nhiroki): Find an efficient way to do this.
- auto* content_security_policy = MakeGarbageCollected<ContentSecurityPolicy>();
- content_security_policy->DidReceiveHeaders(
- script_data->GetContentSecurityPolicyResponseHeaders());
-
RunClassicScript(
script_url, referrer_policy, script_data->GetResponseAddressSpace(),
- content_security_policy->Headers(),
+ ContentSecurityPolicy::ParseHeaders(
+ script_data->GetContentSecurityPolicyResponseHeaders()),
script_data->CreateOriginTrialTokens().get(),
script_data->TakeSourceText(), script_data->TakeMetaData(), stack_id);
}
@@ -573,14 +569,14 @@ void ServiceWorkerGlobalScope::RunClassicScript(
const KURL& response_url,
network::mojom::ReferrerPolicy response_referrer_policy,
network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType> response_csp_headers,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
const Vector<String>* response_origin_trial_tokens,
const String& source_code,
std::unique_ptr<Vector<uint8_t>> cached_meta_data,
const v8_inspector::V8StackTraceId& stack_id) {
// Step 4.5-4.11 are implemented in Initialize().
Initialize(response_url, response_referrer_policy, response_address_space,
- response_csp_headers, response_origin_trial_tokens,
+ std::move(response_csp), response_origin_trial_tokens,
mojom::blink::kAppCacheNoCacheId);
// Step 4.12. "Let evaluationStatus be the result of running the classic
@@ -672,15 +668,11 @@ void ServiceWorkerGlobalScope::OnNavigationPreloadError(
DCHECK(IsContextThread());
FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id);
DCHECK(fetch_event);
- // Display an error message to the console, preferring the unsanitized one if
- // available.
- const WebString& error_message = error->unsanitized_message.IsEmpty()
- ? error->message
- : error->unsanitized_message;
- if (!error_message.IsEmpty()) {
+ // Display an error message to the console directly.
+ if (error->mode == WebServiceWorkerError::Mode::kShownInConsole) {
AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kWorker,
- mojom::ConsoleMessageLevel::kError, error_message));
+ mojom::ConsoleMessageLevel::kError, error->message));
}
// Reject the preloadResponse promise.
fetch_event->OnNavigationPreloadError(ScriptController()->GetScriptState(),
@@ -2405,6 +2397,18 @@ void ServiceWorkerGlobalScope::StartPaymentRequestEvent(
event_data->payment_options->request_shipping);
}
+ // Count standardized payment method identifiers, such as "basic-card" or
+ // "tokenized-card". Omit counting the URL-based payment method identifiers,
+ // such as "https://bobpay.xyz".
+ if (std::any_of(
+ event_data->method_data.begin(), event_data->method_data.end(),
+ [](const payments::mojom::blink::PaymentMethodDataPtr& datum) {
+ return datum && !datum->supported_method.StartsWith("http");
+ })) {
+ UseCounter::Count(
+ this, WebFeature::kPaymentHandlerStandardizedPaymentMethodIdentifier);
+ }
+
mojo::PendingRemote<payments::mojom::blink::PaymentHandlerHost>
payment_handler_host = std::move(event_data->payment_handler_host);
Event* event = PaymentRequestEvent::Create(
@@ -2412,8 +2416,7 @@ void ServiceWorkerGlobalScope::StartPaymentRequestEvent(
PaymentEventDataConversion::ToPaymentRequestEventInit(
ScriptController()->GetScriptState(), std::move(event_data)),
std::move(payment_handler_host), respond_with_observer,
- wait_until_observer,
- ExecutionContext::From(ScriptController()->GetScriptState()));
+ wait_until_observer, this);
DispatchExtendableEventWithRespondWith(event, wait_until_observer,
respond_with_observer);
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 ae5aea6c984..d345f8338bf 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
@@ -37,7 +37,6 @@
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/network_context.mojom-blink-forward.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink-forward.h"
@@ -98,8 +97,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
std::unique_ptr<ServiceWorkerInstalledScriptsManager>,
mojo::PendingRemote<mojom::blink::CacheStorage>,
base::TimeTicks time_origin,
- const ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id);
+ const ServiceWorkerToken& service_worker_token);
ServiceWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams>,
@@ -107,8 +105,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
std::unique_ptr<ServiceWorkerInstalledScriptsManager>,
mojo::PendingRemote<mojom::blink::CacheStorage>,
base::TimeTicks time_origin,
- const ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id);
+ const ServiceWorkerToken& service_worker_token);
~ServiceWorkerGlobalScope() override;
// ExecutionContext overrides:
@@ -116,12 +113,13 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
bool ShouldInstallV8Extensions() const final;
// Implements WorkerGlobalScope:
- void Initialize(const KURL& response_url,
- network::mojom::ReferrerPolicy response_referrer_policy,
- network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType>& response_csp_headers,
- const Vector<String>* response_origin_trial_tokens,
- int64_t appcache_id) override;
+ void Initialize(
+ const KURL& response_url,
+ network::mojom::ReferrerPolicy response_referrer_policy,
+ network::mojom::IPAddressSpace response_address_space,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
+ const Vector<String>* response_origin_trial_tokens,
+ int64_t appcache_id) override;
// Fetches and runs the top-level classic worker script.
void FetchAndRunClassicScript(
const KURL& script_url,
@@ -357,14 +355,15 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
const v8_inspector::V8StackTraceId& stack_id);
// https://w3c.github.io/ServiceWorker/#run-service-worker-algorithm
- void RunClassicScript(const KURL& response_url,
- network::mojom::ReferrerPolicy response_referrer_policy,
- network::mojom::IPAddressSpace response_address_space,
- const Vector<CSPHeaderAndType> response_csp_headers,
- const Vector<String>* response_origin_trial_tokens,
- const String& source_code,
- std::unique_ptr<Vector<uint8_t>> cached_meta_data,
- const v8_inspector::V8StackTraceId&);
+ void RunClassicScript(
+ const KURL& response_url,
+ network::mojom::ReferrerPolicy response_referrer_policy,
+ network::mojom::IPAddressSpace response_address_space,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr> response_csp,
+ const Vector<String>* response_origin_trial_tokens,
+ const String& source_code,
+ std::unique_ptr<Vector<uint8_t>> cached_meta_data,
+ const v8_inspector::V8StackTraceId&);
// Counts the |script_size| and |cached_metadata_size| for UMA to measure the
// number of scripts and the total bytes of scripts.
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
index e6d85ea4c32..f9f21840ce6 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
@@ -275,8 +275,7 @@ ServiceWorkerInstalledScriptsManager::ServiceWorkerInstalledScriptsManager(
PostCrossThreadTask(
*io_task_runner, FROM_HERE,
CrossThreadBindOnce(&Internal::Create, script_container_,
- WTF::Passed(std::move(manager_receiver)),
- io_task_runner));
+ std::move(manager_receiver), io_task_runner));
}
bool ServiceWorkerInstalledScriptsManager::IsScriptInstalled(
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc
index c7f153f2587..a4ee3147fba 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc
@@ -54,9 +54,9 @@ class BrowserSideSender
script_info->encoding = encoding;
script_info->headers = headers;
EXPECT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(nullptr, &body_handle_, &script_info->body));
- EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(nullptr, &meta_data_handle_,
- &script_info->meta_data));
+ mojo::CreateDataPipe(nullptr, body_handle_, script_info->body));
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(nullptr, meta_data_handle_,
+ script_info->meta_data));
script_info->body_size = body_size;
script_info->meta_data_size = meta_data_size;
manager_->TransferInstalledScript(std::move(script_info));
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
index 5165dfadd60..7c3c6e353f6 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/script/module_script.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
@@ -37,6 +38,19 @@ void ServiceWorkerModuleTreeClient::NotifyModuleTreeLoadFinished(
worker_global_scope->close();
return;
}
+
+ // With top-level await: https://github.com/w3c/ServiceWorker/pull/1444
+ if (!module_script->HasEmptyRecord() &&
+ module_script->V8Module()->IsGraphAsync()) {
+ worker_reporting_proxy.DidFailToFetchModuleScript();
+ worker_global_scope->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kError,
+ "Top-level await is disallowed in service workers."));
+ worker_global_scope->close();
+ return;
+ }
+
worker_reporting_proxy.DidFetchScript();
// (In the update case) Step 9: "Else, continue the rest of these steps after
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
index 2ab749238df..04f1d5d828c 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
@@ -48,8 +48,7 @@ ServiceWorkerThread::ServiceWorkerThread(
mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote,
scoped_refptr<base::SingleThreadTaskRunner>
parent_thread_default_task_runner,
- const blink::ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id)
+ const blink::ServiceWorkerToken& service_worker_token)
: WorkerThread(*global_scope_proxy,
std::move(parent_thread_default_task_runner)),
global_scope_proxy_(std::move(global_scope_proxy)),
@@ -57,8 +56,7 @@ ServiceWorkerThread::ServiceWorkerThread(
ThreadCreationParams(GetThreadType()))),
installed_scripts_manager_(std::move(installed_scripts_manager)),
cache_storage_remote_(std::move(cache_storage_remote)),
- service_worker_token_(service_worker_token),
- ukm_source_id_(ukm_source_id) {}
+ service_worker_token_(service_worker_token) {}
ServiceWorkerThread::~ServiceWorkerThread() {
global_scope_proxy_->Detach();
@@ -77,8 +75,7 @@ WorkerOrWorkletGlobalScope* ServiceWorkerThread::CreateWorkerGlobalScope(
std::unique_ptr<GlobalScopeCreationParams> creation_params) {
return ServiceWorkerGlobalScope::Create(
this, std::move(creation_params), std::move(installed_scripts_manager_),
- std::move(cache_storage_remote_), time_origin_, service_worker_token_,
- ukm_source_id_);
+ std::move(cache_storage_remote_), time_origin_, service_worker_token_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
index 8be9eba85c6..c8ca932c45e 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
@@ -55,8 +55,7 @@ class MODULES_EXPORT ServiceWorkerThread final : public WorkerThread {
mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote,
scoped_refptr<base::SingleThreadTaskRunner>
parent_thread_default_task_runner,
- const ServiceWorkerToken& service_worker_token,
- ukm::SourceId ukm_source_id);
+ const ServiceWorkerToken& service_worker_token);
~ServiceWorkerThread() override;
WorkerBackingThread& GetWorkerBackingThread() override {
@@ -82,8 +81,6 @@ class MODULES_EXPORT ServiceWorkerThread final : public WorkerThread {
mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote_;
const ServiceWorkerToken service_worker_token_;
-
- const ukm::SourceId ukm_source_id_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index a569c99c9c2..e5eea6a814f 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -94,7 +94,7 @@ class WaitUntilObserver::ThenFunction final : public ScriptFunction {
WTF::Bind(&WaitUntilObserver::OnPromiseRejected,
WrapPersistent(observer_.Get())));
observer_ = nullptr;
- return ScriptPromise::Reject(GetScriptState(), value).GetScriptValue();
+ return ScriptPromise::Reject(GetScriptState(), value).AsScriptValue();
}
event_loop->EnqueueMicrotask(
@@ -336,6 +336,7 @@ void WaitUntilObserver::ConsumeWindowInteraction(TimerBase*) {
}
void WaitUntilObserver::Trace(Visitor* visitor) const {
+ visitor->Trace(consume_window_interaction_timer_);
ExecutionContextClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h
index 3eda3a9fcc9..8ac2556a236 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h
@@ -127,7 +127,7 @@ class MODULES_EXPORT WaitUntilObserver final
int pending_promises_ = 0;
EventDispatchState event_dispatch_state_ = EventDispatchState::kInitial;
bool has_rejected_promise_ = false;
- TaskRunnerTimer<WaitUntilObserver> consume_window_interaction_timer_;
+ HeapTaskRunnerTimer<WaitUntilObserver> consume_window_interaction_timer_;
};
} // namespace blink
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 d40d34cf897..9f1dd032146 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
@@ -20,6 +20,7 @@
#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_content_settings_client.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
@@ -100,7 +101,9 @@ class FakeWebURLLoaderFactory final : public WebURLLoaderFactory {
std::unique_ptr<WebURLLoader> CreateURLLoader(
const WebURLRequest&,
std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>,
- std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>) override {
+ std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>,
+ CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>,
+ WebBackForwardCacheLoaderHelper) override {
return std::make_unique<FakeWebURLLoader>();
}
};
@@ -216,11 +219,9 @@ class MockServiceWorkerContextClient final
/*reporting_observer_receiver=*/mojo::NullReceiver());
// To make the other side callable.
- mojo::AssociateWithDisconnectedPipe(host_receiver.PassHandle());
- mojo::AssociateWithDisconnectedPipe(
- registration_object_host_receiver.PassHandle());
- mojo::AssociateWithDisconnectedPipe(
- service_worker_object_host_receiver.PassHandle());
+ host_receiver.EnableUnassociatedUsage();
+ registration_object_host_receiver.EnableUnassociatedUsage();
+ service_worker_object_host_receiver.EnableUnassociatedUsage();
}
void FailedToFetchClassicScript() override {
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/DEPS b/chromium/third_party/blink/renderer/modules/shapedetection/DEPS
index cf22ab4a920..11c67f0efdf 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/DEPS
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/DEPS
@@ -3,9 +3,10 @@ include_rules = [
"+services/service_manager/public/cpp",
"+skia/public/mojom/bitmap.mojom-blink.h",
"+skia/public/mojom/bitmap.mojom-blink-forward.h",
+ "+third_party/blink/renderer/bindings/modules/v8/v8_point_2d.h",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/canvas/canvas2d",
- "+third_party/blink/renderer/bindings/modules/v8/v8_point_2d.h",
+ "+third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h",
"+third_party/blink/renderer/modules/modules_export.h",
"+third_party/blink/renderer/modules/shapedetection",
"+third_party/skia/include/core/SkImage.h",
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/DIR_METADATA b/chromium/third_party/blink/renderer/modules/shapedetection/DIR_METADATA
new file mode 100644
index 00000000000..90eb6f563dd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>ShapeDetection"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/OWNERS b/chromium/third_party/blink/renderer/modules/shapedetection/OWNERS
index f479be27501..d522bc6939e 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/OWNERS
@@ -5,6 +5,3 @@ mcasas@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Blink>ShapeDetection
-# TEAM: device-dev@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
index 4217f8980c9..a1898d939e5 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector.h
@@ -36,12 +36,11 @@ class MODULES_EXPORT BarcodeDetector final : public ShapeDetector {
explicit BarcodeDetector(ExecutionContext*,
const BarcodeDetectorOptions*,
ExceptionState& exception_state);
+ ~BarcodeDetector() override = default;
void Trace(Visitor*) const override;
private:
- ~BarcodeDetector() override = default;
-
ScriptPromise DoDetect(ScriptPromiseResolver*, SkBitmap) override;
void OnDetectBarcodes(
ScriptPromiseResolver*,
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.h b/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.h
index 111471d807b..59385160a29 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.h
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/face_detector.h
@@ -26,12 +26,11 @@ class MODULES_EXPORT FaceDetector final : public ShapeDetector {
static FaceDetector* Create(ExecutionContext*, const FaceDetectorOptions*);
FaceDetector(ExecutionContext*, const FaceDetectorOptions*);
+ ~FaceDetector() override = default;
void Trace(Visitor*) const override;
private:
- ~FaceDetector() override = default;
-
ScriptPromise DoDetect(ScriptPromiseResolver*, SkBitmap) override;
void OnDetectFaces(
ScriptPromiseResolver*,
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 8f99decf706..7bfbf5eaf0a 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/numerics/checked_math.h"
+#include "skia/ext/skia_utils_base.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -90,7 +91,9 @@ ScriptPromise ShapeDetector::detect(
image->PaintImageForCurrentFrame().GetSwSkImage();
SkBitmap sk_bitmap;
- if (!sk_image->asLegacyBitmap(&sk_bitmap)) {
+ SkBitmap n32_bitmap;
+ if (!sk_image->asLegacyBitmap(&sk_bitmap) ||
+ !skia::SkBitmapToN32OpaqueOrPremul(sk_bitmap, &n32_bitmap)) {
// TODO(mcasas): retrieve the pixels from elsewhere.
NOTREACHED();
resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -99,7 +102,7 @@ ScriptPromise ShapeDetector::detect(
return promise;
}
- return DoDetect(resolver, std::move(sk_bitmap));
+ return DoDetect(resolver, std::move(n32_bitmap));
}
ScriptPromise ShapeDetector::DetectShapesOnImageData(
@@ -112,25 +115,29 @@ ScriptPromise ShapeDetector::DetectShapesOnImageData(
return promise;
}
- if (image_data->BufferBase()->IsDetached()) {
+ if (image_data->IsBufferBaseDetached()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
"The image data has been detached."));
return promise;
}
+ SkPixmap image_data_pixmap = image_data->GetSkPixmap();
SkBitmap sk_bitmap;
- SkImageInfo sk_image_info = image_data->GetSkImageInfo();
- if (!sk_bitmap.tryAllocPixels(sk_image_info, sk_image_info.minRowBytes())) {
+ if (!sk_bitmap.tryAllocPixels(
+ image_data_pixmap.info().makeColorType(kN32_SkColorType),
+ image_data_pixmap.rowBytes())) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
"Failed to allocate pixels for current frame."));
return promise;
}
-
- size_t byte_size = sk_bitmap.computeByteSize();
- CHECK_EQ(byte_size, image_data->BufferBase()->ByteLength());
- memcpy(sk_bitmap.getPixels(), image_data->BufferBase()->Data(), byte_size);
+ if (!sk_bitmap.writePixels(image_data_pixmap, 0, 0)) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError,
+ "Failed to copy pixels for current frame."));
+ return promise;
+ }
return DoDetect(resolver, std::move(sk_bitmap));
}
@@ -140,27 +147,28 @@ ScriptPromise ShapeDetector::DetectShapesOnImageElement(
const HTMLImageElement* img) {
ScriptPromise promise = resolver->Promise();
- if (img->BitmapSourceSize().IsZero()) {
- resolver->Resolve(HeapVector<Member<DOMRect>>());
- return promise;
- }
-
ImageResourceContent* const image_content = img->CachedImage();
- if (!image_content || image_content->ErrorOccurred()) {
+ if (!image_content || !image_content->IsLoaded() ||
+ image_content->ErrorOccurred()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
"Failed to load or decode HTMLImageElement."));
return promise;
}
- Image* const blink_image = image_content->GetImage();
- if (!blink_image) {
+ if (!image_content->HasImage()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
"Failed to get image from resource."));
return promise;
}
+ Image* const blink_image = image_content->GetImage();
+ if (blink_image->Size().IsZero()) {
+ resolver->Resolve(HeapVector<Member<DOMRect>>());
+ return promise;
+ }
+
// The call to asLegacyBitmap() below forces a readback so getting SwSkImage
// here doesn't readback unnecessarily
const sk_sp<SkImage> sk_image =
@@ -169,7 +177,6 @@ ScriptPromise ShapeDetector::DetectShapesOnImageElement(
DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(sk_image->height()));
SkBitmap sk_bitmap;
-
if (!sk_image || !sk_image->asLegacyBitmap(&sk_bitmap)) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.h b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.h
index f1ed766b476..181b95bf323 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.h
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.h
@@ -8,8 +8,8 @@
#include "skia/public/mojom/bitmap.mojom-blink-forward.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/window_or_worker_global_scope.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h"
+#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.h b/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.h
index 2bed20a0668..721352873da 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.h
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/text_detector.h
@@ -25,12 +25,11 @@ class MODULES_EXPORT TextDetector final : public ShapeDetector {
static TextDetector* Create(ExecutionContext*);
explicit TextDetector(ExecutionContext*);
+ ~TextDetector() override = default;
void Trace(Visitor*) const override;
private:
- ~TextDetector() override = default;
-
ScriptPromise DoDetect(ScriptPromiseResolver*, SkBitmap) override;
void OnDetectText(
ScriptPromiseResolver*,
diff --git a/chromium/third_party/blink/renderer/modules/speech/DIR_METADATA b/chromium/third_party/blink/renderer/modules/speech/DIR_METADATA
new file mode 100644
index 00000000000..a354eb6349a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/speech/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Speech"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/speech/OWNERS b/chromium/third_party/blink/renderer/modules/speech/OWNERS
index c213a7d3aeb..5ecb2f4da44 100644
--- a/chromium/third_party/blink/renderer/modules/speech/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/speech/OWNERS
@@ -3,6 +3,3 @@ dmazzoni@chromium.org
# Speech recognition - send reviews here first, then to dmazzoni for approval.
tommi@chromium.org
-gshires@chromium.org
-
-# COMPONENT: Blink>Speech
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 812cb323432..63bef19544c 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
@@ -35,6 +35,6 @@
readonly attribute unsigned long resultIndex;
readonly attribute SpeechRecognitionResultList? results;
- [Measure] readonly attribute Document? interpretation;
- [Measure] readonly attribute Document? emma;
+ [DeprecateAs=V8SpeechRecognitionEvent_Interpretation_AttributeGetter] readonly attribute Document? interpretation;
+ [DeprecateAs=V8SpeechRecognitionEvent_Emma_AttributeGetter] readonly attribute Document? emma;
};
diff --git a/chromium/third_party/blink/renderer/modules/srcobject/DIR_METADATA b/chromium/third_party/blink/renderer/modules/srcobject/DIR_METADATA
new file mode 100644
index 00000000000..86fb426a628
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/srcobject/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Media"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/srcobject/OWNERS b/chromium/third_party/blink/renderer/modules/srcobject/OWNERS
index c854623b81a..05cb9bd3c02 100644
--- a/chromium/third_party/blink/renderer/modules/srcobject/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/srcobject/OWNERS
@@ -1,3 +1 @@
guidou@chromium.org
-
-# COMPONENT: Blink>Media
diff --git a/chromium/third_party/blink/renderer/modules/storage/DIR_METADATA b/chromium/third_party/blink/renderer/modules/storage/DIR_METADATA
new file mode 100644
index 00000000000..4c654bcb0ce
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/storage/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>DOMStorage"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/storage/OWNERS b/chromium/third_party/blink/renderer/modules/storage/OWNERS
index 1559acca15e..ec289ebc748 100644
--- a/chromium/third_party/blink/renderer/modules/storage/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/storage/OWNERS
@@ -4,6 +4,3 @@ mek@chromium.org
# Secondary:
jsbell@chromium.org
pwnall@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>DOMStorage
diff --git a/chromium/third_party/blink/renderer/modules/storage/README.md b/chromium/third_party/blink/renderer/modules/storage/README.md
index d5d8a33888f..75d78ff176a 100644
--- a/chromium/third_party/blink/renderer/modules/storage/README.md
+++ b/chromium/third_party/blink/renderer/modules/storage/README.md
@@ -4,11 +4,6 @@ This directory contains the renderer side implementation of the DOM Storage API.
The browser side code for this lives in `content/browser/dom_storage/`.
-*TODO(dmurph): Delete this paragraph after onion-souping is complete.
-https://crbug.com/781870*
-This file describes only the post-onion-souped version of the code, where
-`features::kOnionSoupDOMStorage` is turned on. This is not yet the default.
-
## Class Responsibilities
### [`DOMWindowStorage`](dom_window_storage.h)
This implements the partial `Window` interface in
@@ -47,7 +42,7 @@ This class is responsible for
[`SessionStorageNamespace`](../../../public/mojom/dom_storage/session_storage_namespace.mojom)
mojo interfaces to create `StorageArea` mojo ptrs for the `CachedStorageArea`s
and clone namespaces for SessionStorage.
-* accounting for all storage used in it's cached areas, and
+* accounting for all storage used in its cached areas, and
* cleaning up unused caches areas on demand.
There are two versions of this class - one version is the SessionStorage
@@ -60,7 +55,7 @@ to open the `StorageAreas`, and is owned by the `StorageController`.
### [`StorageController`](storage_controller.h)
This is a singleton that is responsible for keeping track of all
-`StorageNamespace`s and provide access to the functionality of it's single
+`StorageNamespace`s and provide access to the functionality of its single
LocalStorage `StorageNamespace` that it owns. It holds weak references to all
of the SessionStorage `StorageNamespace`s so it can account for the total
amount of memory used by all of DOMStorage. If this gets too high, it can ask
diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc b/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc
index 35af301c6b9..3b59dbe8ddf 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/storage/storage_controller.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
@@ -72,8 +74,7 @@ TEST(StorageControllerTest, CacheLimit) {
mojo::MakeSelfOwnedReceiver(std::make_unique<MockDomStorage>(),
std::move(receiver));
},
- WTF::Passed(
- connection.dom_storage_remote.BindNewPipeAndPassReceiver())));
+ connection.dom_storage_remote.BindNewPipeAndPassReceiver()));
StorageController controller(std::move(connection),
scheduler::GetSingleThreadTaskRunnerForTesting(),
@@ -131,9 +132,8 @@ TEST(StorageControllerTest, CacheLimitSessionStorage) {
mojo::MakeSelfOwnedReceiver(std::move(dom_storage_ptr),
std::move(receiver));
},
- WTF::Passed(std::move(mock_dom_storage)),
- WTF::Passed(
- connection.dom_storage_remote.BindNewPipeAndPassReceiver())));
+ std::move(mock_dom_storage),
+ connection.dom_storage_remote.BindNewPipeAndPassReceiver()));
StorageController controller(std::move(connection), nullptr, kTestCacheLimit);
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/BUILD.gn b/chromium/third_party/blink/renderer/modules/url_pattern/BUILD.gn
new file mode 100644
index 00000000000..6bc2956e0c0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("url_pattern") {
+ sources = [
+ "url_pattern.cc",
+ "url_pattern.h",
+ ]
+
+ public_deps = [
+ "//third_party/blink/renderer/platform",
+ "//third_party/liburlpattern",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/DEPS b/chromium/third_party/blink/renderer/modules/url_pattern/DEPS
new file mode 100644
index 00000000000..f653912b1f6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/DEPS
@@ -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.
+
+include_rules = [
+ "+base/i18n/uchar.h",
+ "+base/strings/string_util.h",
+ "+third_party/liburlpattern",
+]
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/DIR_METADATA b/chromium/third_party/blink/renderer/modules/url_pattern/DIR_METADATA
new file mode 100644
index 00000000000..76f0164c6ee
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>URLPattern"
+}
+team_email: "worker-dev@chromium.org"
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/OWNERS b/chromium/third_party/blink/renderer/modules/url_pattern/OWNERS
new file mode 100644
index 00000000000..ff6df554415
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/OWNERS
@@ -0,0 +1,6 @@
+# primary
+wanderview@chromium.org
+
+# secondary
+shimazu@chromium.org
+jbroman@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/idls.gni b/chromium/third_party/blink/renderer/modules/url_pattern/idls.gni
new file mode 100644
index 00000000000..9f0ad7e912f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/idls.gni
@@ -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.
+
+modules_idl_files = [ "url_pattern.idl" ]
+
+modules_dictionary_idl_files = [
+ "url_pattern_component_result.idl",
+ "url_pattern_init.idl",
+ "url_pattern_result.idl",
+]
+
+modules_dependency_idl_files = []
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.cc b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.cc
new file mode 100644
index 00000000000..3c877810ce6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.cc
@@ -0,0 +1,778 @@
+// Copyright 2020 The Chromium Authors. 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/url_pattern/url_pattern.h"
+
+#include "base/i18n/uchar.h"
+#include "base/strings/string_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_regexp.h"
+#include "third_party/blink/renderer/bindings/modules/v8/usv_string_or_url_pattern_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_component_result.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_url_pattern_result.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/liburlpattern/parse.h"
+#include "third_party/liburlpattern/pattern.h"
+
+namespace blink {
+
+// A struct representing all the information needed to match a particular
+// component of a URL.
+class URLPattern::Component final
+ : public GarbageCollected<URLPattern::Component> {
+ public:
+ bool Match(StringView input, Vector<String>* group_list) const {
+ return regexp->Match(input, /*start_from=*/0, /*match_length=*/nullptr,
+ group_list) == 0;
+ }
+
+ void Trace(Visitor* visitor) const { visitor->Trace(regexp); }
+
+ // The pattern compiled down to a js regular expression.
+ Member<ScriptRegexp> regexp;
+
+ // The names to be applied to the regular expression capture groups. Note,
+ // liburlpattern regular expressions do not use named capture groups directly.
+ Vector<String> name_list;
+
+ Component(ScriptRegexp* r, Vector<String> n)
+ : regexp(r), name_list(std::move(n)) {}
+};
+
+namespace {
+
+// The liburlpattern::Options to use for most component patterns. We
+// default to strict mode and case sensitivity. In addition, most
+// components have no concept of a delimiter or prefix character.
+const liburlpattern::Options& DefaultOptions() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(liburlpattern::Options, options,
+ ({.delimiter_list = "",
+ .prefix_list = "",
+ .sensitive = true,
+ .strict = true}));
+ return options;
+}
+
+// The liburlpattern::Options to use for hostname patterns. This uses a
+// "." delimiter controlling how far a named group like ":bar" will match
+// by default. Note, hostnames are case insensitive but we require case
+// sensitivity here. This assumes that the hostname values have already
+// been normalized to lower case as in URL().
+const liburlpattern::Options& HostnameOptions() {
+ DEFINE_STATIC_LOCAL(liburlpattern::Options, options,
+ ({.delimiter_list = ".",
+ .prefix_list = "",
+ .sensitive = true,
+ .strict = true}));
+ return options;
+}
+
+// The liburlpattern::Options to use for pathname patterns. This uses a
+// "/" delimiter controlling how far a named group like ":bar" will match
+// by default. It also configures "/" to be treated as an automatic
+// prefix before groups.
+const liburlpattern::Options& PathnameOptions() {
+ DEFINE_STATIC_LOCAL(liburlpattern::Options, options,
+ ({.delimiter_list = "/",
+ .prefix_list = "/",
+ .sensitive = true,
+ .strict = true}));
+ return options;
+}
+
+// An enum indicating whether the associated component values be operated
+// on are for patterns or URLs. Validation and canonicalization will
+// do different things depending on the type.
+enum class ValueType {
+ kPattern,
+ kURL,
+};
+
+// Utility function to determine if a pathname is absolute or not. For
+// kURL values this mainly consists of a check for a leading slash. For
+// patterns we do some additional checking for escaped or grouped slashes.
+bool IsAbsolutePathname(const String& pathname, ValueType type) {
+ if (pathname.IsEmpty())
+ return false;
+
+ if (pathname[0] == '/')
+ return true;
+
+ if (type == ValueType::kURL)
+ return false;
+
+ if (pathname.length() < 2)
+ return false;
+
+ // Patterns treat escaped slashes and slashes within an explicit grouping as
+ // valid leading slashes. For example, "\/foo" or "{/foo}". Patterns do
+ // not consider slashes within a custom regexp group as valid for the leading
+ // pathname slash for now. To support that we would need to be able to
+ // detect things like ":name_123(/foo)" as a valid leading group in a pattern,
+ // but that is considered too complex for now.
+ if ((pathname[0] == '\\' || pathname[0] == '{') && pathname[1] == '/') {
+ return true;
+ }
+
+ return false;
+}
+
+// Utility function to validate that a pattern value contains only ASCII.
+void ValidatePatternEncoding(const String& pattern,
+ StringView label,
+ ExceptionState& exception_state) {
+ if (pattern.ContainsOnlyASCIIOrEmpty())
+ return;
+
+ // TODO: Consider if we should canonicalize patterns instead. See:
+ // https://github.com/WICG/urlpattern/issues/33
+ exception_state.ThrowTypeError("Illegal character in " + label +
+ " pattern '" + pattern +
+ "'. Patterns must be URL encoded ASCII.");
+}
+
+String StringFromCanonOutput(const url::CanonOutput& output,
+ url::Component component) {
+ return String::FromUTF8(output.data() + component.begin, component.len);
+}
+
+// Utility function to canonicalize a protocol string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern.
+String CanonicalizeProtocol(const String& input,
+ ValueType type,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "protocol", exception_state);
+ return input;
+ }
+
+ bool result = false;
+ url::RawCanonOutputT<char> canon_output;
+ url::Component component;
+ if (input.Is8Bit()) {
+ StringUTF8Adaptor utf8(input);
+ result = url::CanonicalizeScheme(
+ utf8.data(), url::Component(0, utf8.size()), &canon_output, &component);
+ } else {
+ result = url::CanonicalizeScheme(
+ base::i18n::ToChar16Ptr(input.Characters16()),
+ url::Component(0, input.length()), &canon_output, &component);
+ }
+
+ if (!result) {
+ exception_state.ThrowTypeError("Invalid protocol '" + input + "'.");
+ return String();
+ }
+
+ return StringFromCanonOutput(canon_output, component);
+}
+
+// Utility function to canonicalize username and/or password strings. Throws
+// an exception if either is invalid. The canonicalization and/or validation
+// will differ depending on whether |type| is kURL or kPattern. On success
+// |username_out| and |password_out| will contain the canonical values.
+void CanonicalizeUsernameAndPassword(const String& username,
+ const String& password,
+ ValueType type,
+ String& username_out,
+ String& password_out,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(username, "username", exception_state);
+ if (exception_state.HadException())
+ return;
+ ValidatePatternEncoding(password, "password", exception_state);
+ if (exception_state.HadException())
+ return;
+ username_out = username;
+ password_out = password;
+ return;
+ }
+
+ bool result = false;
+ url::RawCanonOutputT<char> canon_output;
+ url::Component username_component;
+ url::Component password_component;
+
+ if (username && password && username.Is8Bit() && password.Is8Bit()) {
+ StringUTF8Adaptor username_utf8(username);
+ StringUTF8Adaptor password_utf8(password);
+ result = url::CanonicalizeUserInfo(
+ username_utf8.data(), url::Component(0, username_utf8.size()),
+ password_utf8.data(), url::Component(0, password_utf8.size()),
+ &canon_output, &username_component, &password_component);
+
+ } else {
+ String username16(username);
+ String password16(password);
+ username16.Ensure16Bit();
+ password16.Ensure16Bit();
+ result = url::CanonicalizeUserInfo(
+ base::i18n::ToChar16Ptr(username16.Characters16()),
+ url::Component(0, username16.length()),
+ base::i18n::ToChar16Ptr(password16.Characters16()),
+ url::Component(0, password16.length()), &canon_output,
+ &username_component, &password_component);
+ }
+
+ if (!result) {
+ exception_state.ThrowTypeError("Invalid username '" + username +
+ "' and/or password '" + password + "'.");
+ return;
+ }
+
+ if (username_component.len != -1)
+ username_out = StringFromCanonOutput(canon_output, username_component);
+ if (password_component.len != -1)
+ password_out = StringFromCanonOutput(canon_output, password_component);
+}
+
+// Utility function to canonicalize a hostname string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern.
+String CanonicalizeHostname(const String& input,
+ ValueType type,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "hostname", exception_state);
+ return input;
+ }
+
+ bool success = false;
+ String result = SecurityOrigin::CanonicalizeHost(input, &success);
+ if (!success) {
+ exception_state.ThrowTypeError("Invalid hostname '" + input + "'.");
+ return String();
+ }
+
+ return result;
+}
+
+// Utility function to canonicalize a port string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern. The |protocol|
+// must be provided in order to handle default ports correctly.
+String CanonicalizePort(const String& input,
+ ValueType type,
+ const String& protocol,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "port", exception_state);
+ return input;
+ }
+
+ int default_port = url::PORT_UNSPECIFIED;
+ if (!input.IsEmpty()) {
+ StringUTF8Adaptor protocol_utf8(protocol);
+ default_port =
+ url::DefaultPortForScheme(protocol_utf8.data(), protocol_utf8.size());
+ }
+
+ // Since ports only consist of digits there should be no encoding needed.
+ // Therefore we directly use the UTF8 encoding version of CanonicalizePort().
+ StringUTF8Adaptor utf8(input);
+ url::RawCanonOutputT<char> canon_output;
+ url::Component component;
+ if (!url::CanonicalizePort(utf8.data(), url::Component(0, utf8.size()),
+ default_port, &canon_output, &component)) {
+ exception_state.ThrowTypeError("Invalid port '" + input + "'.");
+ return String();
+ }
+
+ return component.len == -1 ? g_empty_string
+ : StringFromCanonOutput(canon_output, component);
+}
+
+// Utility function to canonicalize a pathname string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern.
+String CanonicalizePathname(const String& input,
+ ValueType type,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "pathname", exception_state);
+ return input;
+ }
+
+ if (!IsAbsolutePathname(input, type)) {
+ exception_state.ThrowTypeError("Cannot resolve absolute pathname for '" +
+ input + "'.");
+ return String();
+ }
+
+ bool result = false;
+ url::RawCanonOutputT<char> canon_output;
+ url::Component component;
+ if (input.Is8Bit()) {
+ StringUTF8Adaptor utf8(input);
+ result = url::CanonicalizePath(utf8.data(), url::Component(0, utf8.size()),
+ &canon_output, &component);
+ } else {
+ result = url::CanonicalizePath(
+ base::i18n::ToChar16Ptr(input.Characters16()),
+ url::Component(0, input.length()), &canon_output, &component);
+ }
+
+ if (!result) {
+ exception_state.ThrowTypeError("Invalid pathname '" + input + "'.");
+ return String();
+ }
+
+ return StringFromCanonOutput(canon_output, component);
+}
+
+// Utility function to canonicalize a search string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern.
+String CanonicalizeSearch(const String& input,
+ ValueType type,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "search", exception_state);
+ return input;
+ }
+
+ url::RawCanonOutputT<char> canon_output;
+ url::Component component;
+ if (input.Is8Bit()) {
+ StringUTF8Adaptor utf8(input);
+ url::CanonicalizeQuery(utf8.data(), url::Component(0, utf8.size()),
+ /*converter=*/nullptr, &canon_output, &component);
+ } else {
+ url::CanonicalizeQuery(base::i18n::ToChar16Ptr(input.Characters16()),
+ url::Component(0, input.length()),
+ /*converter=*/nullptr, &canon_output, &component);
+ }
+
+ return StringFromCanonOutput(canon_output, component);
+}
+
+// Utility function to canonicalize a hash string. Throws an exception
+// if the input is invalid. The canonicalization and/or validation will
+// differ depending on whether |type| is kURL or kPattern.
+String CanonicalizeHash(const String& input,
+ ValueType type,
+ ExceptionState& exception_state) {
+ if (type == ValueType::kPattern) {
+ ValidatePatternEncoding(input, "hash", exception_state);
+ return input;
+ }
+
+ url::RawCanonOutputT<char> canon_output;
+ url::Component component;
+ if (input.Is8Bit()) {
+ StringUTF8Adaptor utf8(input);
+ url::CanonicalizeRef(utf8.data(), url::Component(0, utf8.size()),
+ &canon_output, &component);
+ } else {
+ url::CanonicalizeRef(base::i18n::ToChar16Ptr(input.Characters16()),
+ url::Component(0, input.length()), &canon_output,
+ &component);
+ }
+
+ return StringFromCanonOutput(canon_output, component);
+}
+
+// A utility method that takes a URLPatternInit, splits it apart, and applies
+// the individual component values in the given set of strings. The strings
+// are only applied if a value is present in the init structure.
+void ApplyInit(const URLPatternInit* init,
+ ValueType type,
+ String& protocol,
+ String& username,
+ String& password,
+ String& hostname,
+ String& port,
+ String& pathname,
+ String& search,
+ String& hash,
+ ExceptionState& exception_state) {
+ // If there is a baseURL we need to apply its component values first. The
+ // rest of the URLPatternInit structure will then later override these
+ // values. Note, the baseURL will always set either an empty string or
+ // longer value for each considered component. We do not allow null strings
+ // to persist for these components past this phase since they should no
+ // longer be treated as wildcards.
+ KURL base_url;
+ if (init->hasBaseURL()) {
+ base_url = KURL(init->baseURL());
+ if (!base_url.IsValid() || base_url.IsEmpty()) {
+ exception_state.ThrowTypeError("Invalid baseURL '" + init->baseURL() +
+ "'.");
+ return;
+ }
+
+ protocol = base_url.Protocol() ? base_url.Protocol() : g_empty_string;
+ username = base_url.User() ? base_url.User() : g_empty_string;
+ password = base_url.Pass() ? base_url.Pass() : g_empty_string;
+ hostname = base_url.Host() ? base_url.Host() : g_empty_string;
+ port =
+ base_url.Port() > 0 ? String::Number(base_url.Port()) : g_empty_string;
+ pathname = base_url.GetPath() ? base_url.GetPath() : g_empty_string;
+
+ // Do no propagate search or hash from the base URL. This matches the
+ // behavior when resolving a relative URL against a base URL.
+ }
+
+ // Apply the URLPatternInit component values on top of the default and
+ // baseURL values.
+ if (init->hasProtocol()) {
+ protocol = CanonicalizeProtocol(init->protocol(), type, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasUsername() || init->hasPassword()) {
+ CanonicalizeUsernameAndPassword(init->username(), init->password(), type,
+ username, password, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasHostname()) {
+ hostname = CanonicalizeHostname(init->hostname(), type, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasPort()) {
+ port = CanonicalizePort(init->port(), type, protocol, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasPathname()) {
+ pathname = init->pathname();
+ if (base_url.IsValid() && base_url.IsHierarchical() &&
+ !IsAbsolutePathname(pathname, type)) {
+ // Find the last slash in the baseURL pathname. Since the URL is
+ // hierarchical it should have a slash to be valid, but we are cautious
+ // and check. If there is no slash then we cannot use resolve the
+ // relative pathname and just treat the init pathname as an absolute
+ // value.
+ auto slash_index = base_url.GetPath().ReverseFind("/");
+ if (slash_index != kNotFound) {
+ // Extract the baseURL path up to and including the first slash. Append
+ // the relative init pathname to it.
+ pathname = base_url.GetPath().Substring(0, slash_index + 1) + pathname;
+ }
+ }
+ pathname = CanonicalizePathname(pathname, type, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasSearch()) {
+ search = CanonicalizeSearch(init->search(), type, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+ if (init->hasHash()) {
+ hash = CanonicalizeHash(init->hash(), type, exception_state);
+ if (exception_state.HadException())
+ return;
+ }
+}
+
+} // namespace
+
+URLPattern* URLPattern::Create(const URLPatternInit* init,
+ ExceptionState& exception_state) {
+ // Each component defaults to a wildcard matching any input. We use
+ // the null string as a shorthand for the default.
+ String protocol;
+ String username;
+ String password;
+ String hostname;
+ String port;
+ String pathname;
+ String search;
+ String hash;
+
+ // Apply the input URLPatternInit on top of the default values.
+ ApplyInit(init, ValueType::kPattern, protocol, username, password, hostname,
+ port, pathname, search, hash, exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ // Compile each component pattern into a Component structure that can
+ // be used for matching. Components that match any input may have a
+ // nullptr Component struct pointer.
+
+ auto* protocol_component =
+ CompilePattern(protocol, "protocol", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* username_component =
+ CompilePattern(username, "username", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* password_component =
+ CompilePattern(password, "password", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* hostname_component =
+ CompilePattern(hostname, "hostname", HostnameOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* port_component =
+ CompilePattern(port, "port", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* pathname_component =
+ CompilePattern(pathname, "pathname", PathnameOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* search_component =
+ CompilePattern(search, "search", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ auto* hash_component =
+ CompilePattern(hash, "hash", DefaultOptions(), exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ return MakeGarbageCollected<URLPattern>(
+ protocol_component, username_component, password_component,
+ hostname_component, port_component, pathname_component, search_component,
+ hash_component, base::PassKey<URLPattern>());
+}
+
+URLPattern::URLPattern(Component* protocol,
+ Component* username,
+ Component* password,
+ Component* hostname,
+ Component* port,
+ Component* pathname,
+ Component* search,
+ Component* hash,
+ base::PassKey<URLPattern> key)
+ : protocol_(protocol),
+ username_(username),
+ password_(password),
+ hostname_(hostname),
+ port_(port),
+ pathname_(pathname),
+ search_(search),
+ hash_(hash) {}
+
+bool URLPattern::test(const USVStringOrURLPatternInit& input,
+ ExceptionState& exception_state) const {
+ return Match(input, /*result=*/nullptr, exception_state);
+}
+
+URLPatternResult* URLPattern::exec(const USVStringOrURLPatternInit& input,
+ ExceptionState& exception_state) const {
+ URLPatternResult* result = URLPatternResult::Create();
+ if (!Match(input, result, exception_state))
+ return nullptr;
+ return result;
+}
+
+void URLPattern::Trace(Visitor* visitor) const {
+ visitor->Trace(protocol_);
+ visitor->Trace(username_);
+ visitor->Trace(password_);
+ visitor->Trace(hostname_);
+ visitor->Trace(port_);
+ visitor->Trace(pathname_);
+ visitor->Trace(search_);
+ visitor->Trace(hash_);
+ ScriptWrappable::Trace(visitor);
+}
+
+// static
+URLPattern::Component* URLPattern::CompilePattern(
+ const String& pattern,
+ StringView component,
+ const liburlpattern::Options& options,
+ ExceptionState& exception_state) {
+ // If the pattern is null then optimize by not compiling a pattern. Instead,
+ // a nullptr Component is interpreted as matching any input value.
+ if (pattern.IsNull())
+ return nullptr;
+
+ // Parse the pattern.
+ StringUTF8Adaptor utf8(pattern);
+ auto parse_result = liburlpattern::Parse(
+ absl::string_view(utf8.data(), utf8.size()), options);
+ if (!parse_result.ok()) {
+ exception_state.ThrowTypeError("Invalid " + component + " pattern '" +
+ pattern + "'.");
+ return nullptr;
+ }
+
+ // Extract a regular expression string from the parsed pattern.
+ std::vector<std::string> name_list;
+ std::string regexp_string =
+ parse_result.value().GenerateRegexString(&name_list);
+
+ // Compile the regular expression to verify it is valid.
+ auto case_sensitive = options.sensitive ? WTF::kTextCaseSensitive
+ : WTF::kTextCaseASCIIInsensitive;
+ DCHECK(base::IsStringASCII(regexp_string));
+ ScriptRegexp* regexp = MakeGarbageCollected<ScriptRegexp>(
+ String(regexp_string.data(), regexp_string.size()), case_sensitive);
+ if (!regexp->IsValid()) {
+ // TODO: Figure out which embedded regex expression caused the failure
+ // by compiling each pattern kRegex part individually.
+ exception_state.ThrowTypeError("Invalid " + component + " pattern '" +
+ pattern + "'.");
+ return nullptr;
+ }
+
+ Vector<String> wtf_name_list;
+ wtf_name_list.ReserveInitialCapacity(
+ static_cast<wtf_size_t>(name_list.size()));
+ for (const auto& name : name_list) {
+ DCHECK(base::IsStringASCII(name));
+ wtf_name_list.push_back(String(name.data(), name.size()));
+ }
+
+ return MakeGarbageCollected<URLPattern::Component>(std::move(regexp),
+ std::move(wtf_name_list));
+}
+
+bool URLPattern::Match(const USVStringOrURLPatternInit& input,
+ URLPatternResult* result,
+ ExceptionState& exception_state) const {
+ // By default each URL component value starts with an empty string. The
+ // given input is then layered on top of these defaults.
+ String protocol(g_empty_string);
+ String username(g_empty_string);
+ String password(g_empty_string);
+ String hostname(g_empty_string);
+ String port(g_empty_string);
+ String pathname(g_empty_string);
+ String search(g_empty_string);
+ String hash(g_empty_string);
+
+ if (input.IsURLPatternInit()) {
+ // Layer the URLPatternInit values on top of the default empty strings.
+ ApplyInit(input.GetAsURLPatternInit(), ValueType::kURL, protocol, username,
+ password, hostname, port, pathname, search, hash,
+ exception_state);
+ if (exception_state.HadException()) {
+ // Treat exceptions simply as a failure to match.
+ exception_state.ClearException();
+ return false;
+ }
+ } else {
+ DCHECK(input.IsUSVString());
+
+ // The compile the input string as a fully resolved URL.
+ KURL url(input.GetAsUSVString());
+ if (!url.IsValid() || url.IsEmpty()) {
+ // Treat as failure to match, but don't throw an exception.
+ return false;
+ }
+
+ // TODO: Support relative URLs here by taking a string in a second argument.
+
+ // Apply the parsed URL components on top of our defaults.
+ if (url.Protocol())
+ protocol = url.Protocol();
+ if (url.User())
+ username = url.User();
+ if (url.Pass())
+ password = url.Pass();
+ if (url.Host())
+ hostname = url.Host();
+ if (url.Port() > 0)
+ port = String::Number(url.Port());
+ if (url.GetPath())
+ pathname = url.GetPath();
+ if (url.Query())
+ search = url.Query();
+ if (url.FragmentIdentifier())
+ hash = url.FragmentIdentifier();
+ }
+
+ Vector<String> protocol_group_list;
+ Vector<String> username_group_list;
+ Vector<String> password_group_list;
+ Vector<String> hostname_group_list;
+ Vector<String> port_group_list;
+ Vector<String> pathname_group_list;
+ Vector<String> search_group_list;
+ Vector<String> hash_group_list;
+
+ // If we are not generating a full result then we don't need to populate
+ // group lists.
+ auto* protocol_group_list_ref = result ? &protocol_group_list : nullptr;
+ auto* username_group_list_ref = result ? &username_group_list : nullptr;
+ auto* password_group_list_ref = result ? &password_group_list : nullptr;
+ auto* hostname_group_list_ref = result ? &hostname_group_list : nullptr;
+ auto* port_group_list_ref = result ? &port_group_list : nullptr;
+ auto* pathname_group_list_ref = result ? &pathname_group_list : nullptr;
+ auto* search_group_list_ref = result ? &search_group_list : nullptr;
+ auto* hash_group_list_ref = result ? &hash_group_list : nullptr;
+
+ // Each component of the pattern must match the corresponding component of
+ // the input. If a pattern Component is nullptr, then it matches any
+ // input and we can avoid running a real regular expression match.
+ bool matched =
+ (!protocol_ || protocol_->Match(protocol, protocol_group_list_ref)) &&
+ (!username_ || username_->Match(username, username_group_list_ref)) &&
+ (!password_ || password_->Match(password, password_group_list_ref)) &&
+ (!hostname_ || hostname_->Match(hostname, hostname_group_list_ref)) &&
+ (!port_ || port_->Match(port, port_group_list_ref)) &&
+ (!pathname_ || pathname_->Match(pathname, pathname_group_list_ref)) &&
+ (!search_ || search_->Match(search, search_group_list_ref)) &&
+ (!hash_ || hash_->Match(hash, hash_group_list_ref));
+
+ if (!matched || !result)
+ return matched;
+
+ // TODO: The result.input contains the data before canonicalization, but the
+ // component results will contain inputs after canonicalization. Is
+ // this what we want? See: https://github.com/WICG/urlpattern/issues/34
+ result->setInput(input);
+
+ result->setProtocol(
+ MakeComponentResult(protocol_, protocol, protocol_group_list));
+ result->setUsername(
+ MakeComponentResult(username_, username, username_group_list));
+ result->setPassword(
+ MakeComponentResult(password_, password, password_group_list));
+ result->setHostname(
+ MakeComponentResult(hostname_, hostname, hostname_group_list));
+ result->setPort(MakeComponentResult(port_, port, port_group_list));
+ result->setPathname(
+ MakeComponentResult(pathname_, pathname, pathname_group_list));
+ result->setSearch(MakeComponentResult(search_, search, search_group_list));
+ result->setHash(MakeComponentResult(hash_, hash, hash_group_list));
+ return true;
+}
+
+// static
+URLPatternComponentResult* URLPattern::MakeComponentResult(
+ Component* component,
+ const String& input,
+ const Vector<String>& group_list) {
+ Vector<std::pair<String, String>> groups;
+ if (!component) {
+ // When there is not Component we must act as if there was a default
+ // wildcard pattern with a group. The group includes the entire input.
+ groups.emplace_back("0", input);
+ } else {
+ DCHECK_EQ(component->name_list.size(), group_list.size());
+ for (wtf_size_t i = 0; i < group_list.size(); ++i) {
+ groups.emplace_back(component->name_list[i], group_list[i]);
+ }
+ }
+
+ auto* result = URLPatternComponentResult::Create();
+ result->setInput(input);
+ result->setGroups(groups);
+ return result;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.h b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.h
new file mode 100644
index 00000000000..d7292060253
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.h
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. 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_URL_PATTERN_URL_PATTERN_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_URL_PATTERN_URL_PATTERN_H_
+
+#include "base/types/pass_key.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace liburlpattern {
+struct Options;
+} // namespace liburlpattern
+
+namespace blink {
+
+class ExceptionState;
+class URLPatternComponentResult;
+class URLPatternInit;
+class URLPatternResult;
+class USVStringOrURLPatternInit;
+
+class URLPattern : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+ class Component;
+
+ public:
+ static URLPattern* Create(const URLPatternInit* init,
+ ExceptionState& exception_state);
+
+ URLPattern(Component* protocol,
+ Component* username,
+ Component* password,
+ Component* hostname,
+ Component* port,
+ Component* pathname,
+ Component* search,
+ Component* hash,
+ base::PassKey<URLPattern> key);
+
+ bool test(const USVStringOrURLPatternInit& input,
+ ExceptionState& exception_state) const;
+ URLPatternResult* exec(const USVStringOrURLPatternInit& input,
+ ExceptionState& exception_state) const;
+
+ // TODO: define a stringifier
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ // A utility function that takes a given |pattern| and compiles it into a
+ // Component structure. If the |pattern| matches the given |default_pattern|
+ // then nullptr may be returned without throwing an exception. In this case
+ // the Component is not constructed and the nullptr value should be treated as
+ // matching any input value for the component. The |component| string is used
+ // for exception messages. The |options| control how the pattern is compiled.
+ static Component* CompilePattern(const String& pattern,
+ StringView component,
+ const liburlpattern::Options& options,
+ ExceptionState& exception_state);
+
+ // A utility function to determine if a given |input| matches the pattern
+ // or not. Returns |true| if there is a match and |false| otherwise. If
+ // |result| is not nullptr then the URLPatternResult contents will be filled
+ // in as expected by the exec() method.
+ bool Match(const USVStringOrURLPatternInit& input,
+ URLPatternResult* result,
+ ExceptionState& exception_state) const;
+
+ // A utility function that constructs a URLPatternComponentResult for
+ // a given |component|, |input|, and |group_list|. The |component| may
+ // be nullptr.
+ static URLPatternComponentResult* MakeComponentResult(
+ Component* component,
+ const String& input,
+ const Vector<String>& group_list);
+
+ // The compiled patterns for each URL component. If a Component member is
+ // nullptr then it should be treated as a wildcard matching any input.
+ Member<Component> protocol_;
+ Member<Component> username_;
+ Member<Component> password_;
+ Member<Component> hostname_;
+ Member<Component> port_;
+ Member<Component> pathname_;
+ Member<Component> search_;
+ Member<Component> hash_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_URL_PATTERN_URL_PATTERN_H_
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.idl b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.idl
new file mode 100644
index 00000000000..87646316ccc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern.idl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+typedef (USVString or URLPatternInit) URLPatternInput;
+
+// https://wicg.github.io/urlpattern/
+[
+ SecureContext,
+ Exposed=(Window,Worker),
+ RuntimeEnabled=URLPattern
+] interface URLPattern {
+ [RaisesException] constructor(URLPatternInit init);
+ [RaisesException] boolean test(URLPatternInput input);
+ [RaisesException] URLPatternResult exec(URLPatternInput input);
+};
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.idl b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.idl
new file mode 100644
index 00000000000..04c6753ff2f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_component_result.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://wicg.github.io/urlpattern/
+dictionary URLPatternComponentResult {
+ USVString input;
+ record<USVString, USVString> groups;
+};
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl
new file mode 100644
index 00000000000..9f350a21c48
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_init.idl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/urlpattern/
+dictionary URLPatternInit {
+ USVString protocol;
+ USVString username;
+ USVString password;
+ USVString hostname;
+ USVString port;
+ USVString pathname;
+ USVString search;
+ USVString hash;
+ USVString baseURL;
+};
diff --git a/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl
new file mode 100644
index 00000000000..76e037aedf8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/url_pattern/url_pattern_result.idl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/urlpattern/
+dictionary URLPatternResult {
+ URLPatternInput input;
+ URLPatternComponentResult protocol;
+ URLPatternComponentResult username;
+ URLPatternComponentResult password;
+ URLPatternComponentResult hostname;
+ URLPatternComponentResult port;
+ URLPatternComponentResult pathname;
+ URLPatternComponentResult search;
+ URLPatternComponentResult hash;
+};
diff --git a/chromium/third_party/blink/renderer/modules/vibration/DIR_METADATA b/chromium/third_party/blink/renderer/modules/vibration/DIR_METADATA
new file mode 100644
index 00000000000..c9098c78e4d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/vibration/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Vibration"
+}
+team_email: "platform-capabilities@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/vibration/OWNERS b/chromium/third_party/blink/renderer/modules/vibration/OWNERS
index d8c34233a1f..02b971fe8f5 100644
--- a/chromium/third_party/blink/renderer/modules/vibration/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/vibration/OWNERS
@@ -1,4 +1 @@
mvanouwerkerk@chromium.org
-
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>Vibration
diff --git a/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.cc b/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.cc
index a238fd5aa28..07fb22fbad1 100644
--- a/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.cc
@@ -293,6 +293,7 @@ void VibrationController::Trace(Visitor* visitor) const {
ExecutionContextLifecycleObserver::Trace(visitor);
PageVisibilityObserver::Trace(visitor);
visitor->Trace(vibration_manager_);
+ visitor->Trace(timer_do_vibrate_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.h b/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.h
index 452ad8dd505..2e1fbf8c5a6 100644
--- a/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.h
+++ b/chromium/third_party/blink/renderer/modules/vibration/vibration_controller.h
@@ -52,7 +52,7 @@ class MODULES_EXPORT VibrationController final
static bool vibrate(Navigator&, const VibrationPattern&);
explicit VibrationController(Navigator&);
- virtual ~VibrationController();
+ ~VibrationController() override;
static VibrationPattern SanitizeVibrationPattern(
const UnsignedLongOrUnsignedLongSequence&);
@@ -95,7 +95,7 @@ class MODULES_EXPORT VibrationController final
// Timer for calling |doVibrate| after a delay. It is safe to call
// |startOneshot| when the timer is already running: it may affect the time
// at which it fires, but |doVibrate| will still be called only once.
- TaskRunnerTimer<VibrationController> timer_do_vibrate_;
+ HeapTaskRunnerTimer<VibrationController> timer_do_vibrate_;
// Whether a pattern is being processed. The vibration hardware may
// currently be active, or during a pause it may be inactive.
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 9d1f5d2075d..3cbe3f6552e 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
@@ -85,13 +85,19 @@ void VideoFrameCallbackRequesterImpl::OnWebMediaPlayerCreated() {
GetSupplementable()->GetWebMediaPlayer()->RequestVideoFrameCallback();
}
+void VideoFrameCallbackRequesterImpl::OnWebMediaPlayerCleared() {
+ // Clear existing issued weak pointers from the factory, so that
+ // pending ScheduleVideoFrameCallbacksExecution are cancelled.
+ weak_factory_.InvalidateWeakPtrs();
+}
+
void VideoFrameCallbackRequesterImpl::ScheduleWindowRaf() {
GetSupplementable()
->GetDocument()
.GetScriptedAnimationController()
.ScheduleVideoFrameCallbacksExecution(
WTF::Bind(&VideoFrameCallbackRequesterImpl::OnExecution,
- WrapWeakPersistent(this)));
+ weak_factory_.GetWeakPtr()));
}
void VideoFrameCallbackRequesterImpl::ScheduleExecution() {
@@ -161,8 +167,9 @@ bool VideoFrameCallbackRequesterImpl::TryScheduleImmersiveXRSessionRaf() {
if (!in_immersive_session_)
return false;
- session->ScheduleVideoFrameCallbacksExecution(WTF::Bind(
- &VideoFrameCallbackRequesterImpl::OnExecution, WrapWeakPersistent(this)));
+ session->ScheduleVideoFrameCallbacksExecution(
+ WTF::Bind(&VideoFrameCallbackRequesterImpl::OnExecution,
+ weak_factory_.GetWeakPtr()));
return true;
}
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 e380eb893ca..176ae8babac 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
@@ -39,6 +39,7 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
void cancelVideoFrameCallback(int);
void OnWebMediaPlayerCreated() override;
+ void OnWebMediaPlayerCleared() override;
void OnRequestVideoFrameCallback() override;
// Called by ScriptedAnimationController as part of the rendering steps,
@@ -110,6 +111,9 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
Member<VideoFrameRequestCallbackCollection> callback_collection_;
+ // Only used to invalidate pending OnExecution() calls.
+ base::WeakPtrFactory<VideoFrameCallbackRequesterImpl> weak_factory_{this};
+
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 93b74840c4d..a271b80680f 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
@@ -58,8 +58,8 @@ class MockFunction : public ScriptFunction {
// constructor, due to it having a media::VideoFrameMetadata instance.
class MetadataHelper {
public:
- static VideoFramePresentationMetadata* GetDefaultMedatada() {
- return &metadata_;
+ static const VideoFramePresentationMetadata& GetDefaultMedatada() {
+ return metadata_;
}
static std::unique_ptr<VideoFramePresentationMetadata> CopyDefaultMedatada() {
@@ -71,7 +71,7 @@ class MetadataHelper {
copy->width = metadata_.width;
copy->height = metadata_.height;
copy->media_time = metadata_.media_time;
- copy->metadata.MergeMetadataFrom(&(metadata_.metadata));
+ copy->metadata.MergeMetadataFrom(metadata_.metadata);
return copy;
}
@@ -121,28 +121,28 @@ class VfcRequesterParameterVerifierCallback
was_invoked_ = true;
now_ = now;
- auto* expected = MetadataHelper::GetDefaultMedatada();
- EXPECT_EQ(expected->presented_frames, metadata->presentedFrames());
- EXPECT_EQ((unsigned int)expected->width, metadata->width());
- EXPECT_EQ((unsigned int)expected->height, metadata->height());
- EXPECT_EQ(expected->media_time.InSecondsF(), metadata->mediaTime());
+ auto expected = MetadataHelper::GetDefaultMedatada();
+ EXPECT_EQ(expected.presented_frames, metadata->presentedFrames());
+ EXPECT_EQ((unsigned int)expected.width, metadata->width());
+ EXPECT_EQ((unsigned int)expected.height, metadata->height());
+ EXPECT_EQ(expected.media_time.InSecondsF(), metadata->mediaTime());
- EXPECT_EQ(*expected->metadata.rtp_timestamp, metadata->rtpTimestamp());
+ EXPECT_EQ(*expected.metadata.rtp_timestamp, metadata->rtpTimestamp());
// Verify that values were correctly clamped.
- VerifyTicksClamping(expected->presentation_time,
+ VerifyTicksClamping(expected.presentation_time,
metadata->presentationTime(), "presentation_time");
- VerifyTicksClamping(expected->expected_display_time,
+ VerifyTicksClamping(expected.expected_display_time,
metadata->expectedDisplayTime(),
"expected_display_time");
- VerifyTicksClamping(*expected->metadata.capture_begin_time,
+ VerifyTicksClamping(*expected.metadata.capture_begin_time,
metadata->captureTime(), "capture_time");
- VerifyTicksClamping(*expected->metadata.receive_time,
+ VerifyTicksClamping(*expected.metadata.receive_time,
metadata->receiveTime(), "receive_time");
- base::TimeDelta processing_time = *expected->metadata.processing_time;
+ base::TimeDelta processing_time = *expected.metadata.processing_time;
EXPECT_EQ(ClampElapsedProcessingTime(processing_time),
metadata->processingDuration());
EXPECT_NE(processing_time.InSecondsF(), metadata->processingDuration());
@@ -260,7 +260,7 @@ TEST_F(VideoFrameCallbackRequesterImplTest, VerifyRequestVideoFrameCallback) {
auto* function = MockFunction::Create(scope.GetScriptState());
- // Queuing up a video.rAF call should propagate to the WebMediaPlayer.
+ // Queuing up a video.rVFC call should propagate to the WebMediaPlayer.
EXPECT_CALL(*media_player(), RequestVideoFrameCallback()).Times(1);
vfc_requester().requestVideoFrameCallback(GetCallback(function));
@@ -321,6 +321,28 @@ TEST_F(VideoFrameCallbackRequesterImplTest,
testing::Mock::VerifyAndClear(function);
}
+TEST_F(VideoFrameCallbackRequesterImplTest,
+ VerifyClearedMediaPlayerCancelsPendingExecution) {
+ V8TestingScope scope;
+
+ auto* function = MockFunction::Create(scope.GetScriptState());
+
+ // Queue a request.
+ vfc_requester().requestVideoFrameCallback(GetCallback(function));
+ SimulateFramePresented();
+
+ // The callback should be scheduled for execution, but not yet run.
+ EXPECT_CALL(*function, Call(_)).Times(0);
+
+ // Simulate the HTMLVideoElement getting changing its WebMediaPlayer.
+ vfc_requester().OnWebMediaPlayerCleared();
+
+ // This should be a no-op, else we could get metadata for a null frame.
+ SimulateVideoFrameCallback(base::TimeTicks::Now());
+
+ testing::Mock::VerifyAndClear(function);
+}
+
TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters_WindowRaf) {
auto timing = GetDocument().Loader()->GetTiming();
MetadataHelper::ReinitializeFields(timing.ReferenceMonotonicTime());
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl
index 4d21123e47c..3cb930db60e 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_metadata.idl
@@ -47,6 +47,6 @@ dictionary VideoFrameMetadata {
// The RTP timestamp associated with this video frame.
//
- // https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource-rtptimestamp
unsigned long rtpTimestamp;
-}; \ No newline at end of file
+};
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h
index d15874d78e8..6ed659dd780 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h
@@ -27,7 +27,7 @@ class MODULES_EXPORT VideoFrameRequestCallbackCollection final
using CallbackId = int;
- // Abstract class that generalizes a video.rAF callback.
+ // Abstract class that generalizes a video.rVFC callback.
class MODULES_EXPORT VideoFrameCallback
: public GarbageCollected<VideoFrameCallback>,
public NameClient {
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 07be13663d9..d7d32901596 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
@@ -29,6 +29,9 @@ class VideoFrameRequestCallbackCollectionTest : public PageTestBase {
: execution_context_(MakeGarbageCollected<NullExecutionContext>()),
collection_(MakeGarbageCollected<VideoFrameRequestCallbackCollection>(
execution_context_.Get())) {}
+ ~VideoFrameRequestCallbackCollectionTest() override {
+ execution_context_->NotifyContextDestroyed();
+ }
VideoFrameRequestCallbackCollection* collection() {
return collection_.Get();
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/BUILD.gn b/chromium/third_party/blink/renderer/modules/wake_lock/BUILD.gn
index 5a45d1f52af..6fc9c322d34 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/BUILD.gn
@@ -6,8 +6,6 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("wake_lock") {
sources = [
- "navigator_wake_lock.cc",
- "navigator_wake_lock.h",
"wake_lock.cc",
"wake_lock.h",
"wake_lock_manager.cc",
@@ -16,8 +14,6 @@ blink_modules_sources("wake_lock") {
"wake_lock_sentinel.h",
"wake_lock_type.cc",
"wake_lock_type.h",
- "worker_navigator_wake_lock.cc",
- "worker_navigator_wake_lock.h",
]
deps = [
"//mojo/public/cpp/bindings",
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/DIR_METADATA b/chromium/third_party/blink/renderer/modules/wake_lock/DIR_METADATA
new file mode 100644
index 00000000000..c7b3d7e9c3c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>WakeLock"
+}
+team_email: "device-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/OWNERS b/chromium/third_party/blink/renderer/modules/wake_lock/OWNERS
index 857d88e3494..d4ae36cfb53 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/OWNERS
@@ -1,6 +1,3 @@
mlamouri@chromium.org
raphael.kubo.da.costa@intel.com
reillyg@chromium.org
-
-# COMPONENT: Blink>WakeLock
-# TEAM: device-dev@chromium.org
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 94f3543cc89..183d7f11312 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/README.md
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/README.md
@@ -43,7 +43,7 @@ The rest of the implementation is found in the following directories:
### Testing
-Validation, exception types, feature policy integration and general IDL compliance are tested in [web platform tests], while Chromium-specific implementation details (e.g. permission handling) are tested in [web tests].
+Validation, exception types, permissions policy integration and general IDL compliance are tested in [web platform tests], while Chromium-specific implementation details (e.g. permission handling) are tested in [web tests].
Larger parts of the Blink implementation are tested as browser and unit tests:
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc
deleted file mode 100644
index 35c805316ce..00000000000
--- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc
+++ /dev/null
@@ -1,48 +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/wake_lock/navigator_wake_lock.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/wake_lock/wake_lock.h"
-
-namespace blink {
-
-NavigatorWakeLock::NavigatorWakeLock(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
-
-WakeLock* NavigatorWakeLock::GetWakeLock() {
- if (!wake_lock_) {
- if (auto* window = GetSupplementable()->DomWindow())
- wake_lock_ = MakeGarbageCollected<WakeLock>(*window);
- }
- return wake_lock_;
-}
-
-// static
-const char NavigatorWakeLock::kSupplementName[] = "NavigatorWakeLock";
-
-// static
-NavigatorWakeLock& NavigatorWakeLock::From(Navigator& navigator) {
- NavigatorWakeLock* supplement =
- Supplement<Navigator>::From<NavigatorWakeLock>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorWakeLock>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-WakeLock* NavigatorWakeLock::wakeLock(Navigator& navigator) {
- return NavigatorWakeLock::From(navigator).GetWakeLock();
-}
-
-void NavigatorWakeLock::Trace(Visitor* visitor) const {
- visitor->Trace(wake_lock_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h
deleted file mode 100644
index 6a5df685226..00000000000
--- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.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_WAKE_LOCK_NAVIGATOR_WAKE_LOCK_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_NAVIGATOR_WAKE_LOCK_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class WakeLock;
-
-class NavigatorWakeLock final : public GarbageCollected<NavigatorWakeLock>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- static NavigatorWakeLock& From(Navigator&);
-
- static WakeLock* wakeLock(Navigator&);
-
- explicit NavigatorWakeLock(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- WakeLock* GetWakeLock();
-
- Member<WakeLock> wake_lock_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_NAVIGATOR_WAKE_LOCK_H_
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 48ecc6d2b4b..55d3b0fa86e 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
@@ -5,7 +5,7 @@
// https://w3c.github.io/screen-wake-lock/#extensions-to-the-navigator-interface
[
- ImplementedAs=NavigatorWakeLock,
+ ImplementedAs=WakeLock,
RuntimeEnabled=WakeLock,
SecureContext
] partial interface Navigator {
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 8b3983f11ac..4b77850a1dd 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
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.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_feature.h"
@@ -26,24 +27,32 @@ namespace blink {
using mojom::blink::PermissionService;
using mojom::blink::PermissionStatus;
-WakeLock::WakeLock(LocalDOMWindow& window)
- : ExecutionContextLifecycleObserver(&window),
- PageVisibilityObserver(window.GetFrame()->GetPage()),
- permission_service_(&window),
+// static
+const char WakeLock::kSupplementName[] = "WakeLock";
+
+// static
+WakeLock* WakeLock::wakeLock(NavigatorBase& navigator) {
+ WakeLock* supplement = Supplement<NavigatorBase>::From<WakeLock>(navigator);
+ if (!supplement && navigator.GetExecutionContext()) {
+ supplement = MakeGarbageCollected<WakeLock>(navigator);
+ ProvideTo(navigator, supplement);
+ }
+ return supplement;
+}
+
+WakeLock::WakeLock(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()),
+ PageVisibilityObserver(navigator.DomWindow()
+ ? navigator.DomWindow()->GetFrame()->GetPage()
+ : nullptr),
+ permission_service_(navigator.GetExecutionContext()),
managers_{
- MakeGarbageCollected<WakeLockManager>(&window, WakeLockType::kScreen),
- MakeGarbageCollected<WakeLockManager>(&window,
+ MakeGarbageCollected<WakeLockManager>(navigator.GetExecutionContext(),
+ WakeLockType::kScreen),
+ MakeGarbageCollected<WakeLockManager>(navigator.GetExecutionContext(),
WakeLockType::kSystem)} {}
-WakeLock::WakeLock(DedicatedWorkerGlobalScope& worker_scope)
- : ExecutionContextLifecycleObserver(&worker_scope),
- PageVisibilityObserver(nullptr),
- permission_service_(&worker_scope),
- managers_{MakeGarbageCollected<WakeLockManager>(&worker_scope,
- WakeLockType::kScreen),
- MakeGarbageCollected<WakeLockManager>(&worker_scope,
- WakeLockType::kSystem)} {}
-
ScriptPromise WakeLock::request(ScriptState* script_state,
const String& type,
ExceptionState& exception_state) {
@@ -88,9 +97,9 @@ ScriptPromise WakeLock::request(ScriptState* script_state,
!context->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kScreenWakeLock,
ReportOptions::kReportOnFailure)) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNotAllowedError,
- "Access to Screen Wake Lock features is disallowed by feature policy");
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
+ "Access to Screen Wake Lock features is "
+ "disallowed by permissions policy");
return ScriptPromise();
}
@@ -269,7 +278,7 @@ PermissionService* WakeLock::GetPermissionService() {
ConnectToPermissionService(
GetExecutionContext(),
permission_service_.BindNewPipeAndPassReceiver(
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ GetExecutionContext()->GetTaskRunner(TaskType::kWakeLock)));
}
return permission_service_.get();
}
@@ -278,6 +287,7 @@ void WakeLock::Trace(Visitor* visitor) const {
for (const WakeLockManager* manager : managers_)
visitor->Trace(manager);
visitor->Trace(permission_service_);
+ Supplement<NavigatorBase>::Trace(visitor);
PageVisibilityObserver::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
ScriptWrappable::Trace(visitor);
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 0a8d27e540c..f405b0bbad3 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
@@ -18,6 +18,7 @@
#include "third_party/blink/renderer/platform/heap/handle.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 WTF {
@@ -28,18 +29,23 @@ class String;
namespace blink {
class ExceptionState;
-class LocalDOMWindow;
+class NavigatorBase;
class ScriptState;
class WakeLockManager;
class MODULES_EXPORT WakeLock final : public ScriptWrappable,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver,
public PageVisibilityObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit WakeLock(LocalDOMWindow&);
- explicit WakeLock(DedicatedWorkerGlobalScope&);
+ static const char kSupplementName[];
+
+ // Getter for navigator.wakelock
+ static WakeLock* wakeLock(NavigatorBase&);
+
+ explicit WakeLock(NavigatorBase&);
ScriptPromise request(ScriptState*,
const WTF::String& type,
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 324f555d32f..7b8429b0e06 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
@@ -47,15 +47,10 @@ void WakeLockManager::AcquireWakeLock(ScriptPromiseResolver* resolver) {
ToMojomWakeLockType(wake_lock_type_),
device::mojom::blink::WakeLockReason::kOther, "Blink Wake Lock",
wake_lock_.BindNewPipeAndPassReceiver(
- execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ execution_context_->GetTaskRunner(TaskType::kWakeLock)));
wake_lock_.set_disconnect_handler(WTF::Bind(
&WakeLockManager::OnWakeLockConnectionError, WrapWeakPersistent(this)));
wake_lock_->RequestWakeLock();
-
- feature_handle_for_scheduler_ =
- execution_context_->GetScheduler()->RegisterFeature(
- SchedulingPolicy::Feature::kWakeLock,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
}
// https://w3c.github.io/screen-wake-lock/#the-request-method
// 5.2. Let lock be a new WakeLockSentinel object with its type attribute set
@@ -91,9 +86,6 @@ void WakeLockManager::UnregisterSentinel(WakeLockSentinel* sentinel) {
// 5.2. If success is true and type is "screen" run the following:
// 5.2.1. Reset the platform-specific inactivity timer after which the
// screen is actually turned off.
-
- // Make the page bfcache-eligible if there is no WakeLock held.
- feature_handle_for_scheduler_.reset();
}
}
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 d8a5d52f90c..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
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/platform/heap/handle.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/scheduler/public/frame_or_worker_scheduler.h"
namespace blink {
@@ -52,11 +51,6 @@ class MODULES_EXPORT WakeLockManager final
// ExecutionContext from which we will connect to |wake_lock_service_|.
Member<ExecutionContext> execution_context_;
- // Do not put a page into BackForwardCache if a page has acquired WakeLock.
- // The page becomes cache-able when all locks are released.
- FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
- feature_handle_for_scheduler_;
-
FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, AcquireWakeLock);
FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, ReleaseAllWakeLocks);
FRIEND_TEST_ALL_PREFIXES(WakeLockManagerTest, ReleaseOneWakeLock);
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 3c24465d9a7..7592a1135c7 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
@@ -96,7 +96,7 @@ void WakeLockSentinel::DoRelease() {
// 6. Queue a task to run the following steps:
GetExecutionContext()
- ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->GetTaskRunner(TaskType::kWakeLock)
->PostTask(FROM_HERE, WTF::Bind(&WakeLockSentinel::DispatchReleaseEvent,
WrapWeakPersistent(this)));
}
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 daf4cc2e165..6275adc451b 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
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/modules/event_target_modules_names.h"
#include "third_party/blink/renderer/modules/wake_lock/wake_lock.h"
#include "third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h"
@@ -114,7 +115,7 @@ TEST(WakeLockSentinelTest, ContextDestruction) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
ScriptPromise screen_promise = screen_resolver->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver);
WakeLockManager* manager =
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 29706f07f6b..ee35774c502 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
@@ -10,6 +10,7 @@
#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/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -28,7 +29,7 @@ TEST(WakeLockTest, RequestWakeLockGranted) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
ScriptPromise screen_promise = screen_resolver->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver);
MockWakeLock& screen_lock =
@@ -55,7 +56,7 @@ TEST(WakeLockTest, RequestWakeLockDenied) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
ScriptPromise system_promise = system_resolver->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kSystem, system_resolver);
MockWakeLock& system_lock =
@@ -102,7 +103,7 @@ TEST(WakeLockTest, LossOfDocumentActivity) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
system_resolver1->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver1);
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver2);
screen_lock.WaitForRequest();
@@ -143,7 +144,7 @@ TEST(WakeLockTest, PageVisibilityHidden) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
ScriptPromise system_promise = system_resolver->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver);
screen_lock.WaitForRequest();
wake_lock->DoRequest(WakeLockType::kSystem, system_resolver);
@@ -194,7 +195,7 @@ TEST(WakeLockTest, PageVisibilityHiddenBeforeLockAcquisition) {
MakeGarbageCollected<ScriptPromiseResolver>(context.GetScriptState());
ScriptPromise system_promise = system_resolver->Promise();
- auto* wake_lock = MakeGarbageCollected<WakeLock>(*context.DomWindow());
+ auto* wake_lock = WakeLock::wakeLock(*context.DomWindow()->navigator());
wake_lock->DoRequest(WakeLockType::kScreen, screen_resolver);
wake_lock->DoRequest(WakeLockType::kSystem, system_resolver);
context.Frame()->GetPage()->SetVisibilityState(
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 1052269f376..c08629191ec 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
@@ -18,7 +18,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/modules/wake_lock/wake_lock_type.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -30,7 +30,7 @@ using mojom::blink::PermissionStatus;
namespace {
void RunWithStack(base::RunLoop* run_loop) {
- ThreadState::HeapPointersOnStackScope scan_stack(ThreadState::Current());
+ HeapPointersOnStackScope scan_stack(ThreadState::Current());
run_loop->Run();
}
@@ -324,21 +324,21 @@ void WakeLockTestingContext::WaitForPromiseRejection(ScriptPromise promise) {
// static
v8::Promise::PromiseState ScriptPromiseUtils::GetPromiseState(
const ScriptPromise& promise) {
- return promise.V8Value().As<v8::Promise>()->State();
+ return promise.V8Promise()->State();
}
// static
DOMException* ScriptPromiseUtils::GetPromiseResolutionAsDOMException(
const ScriptPromise& promise) {
- return V8DOMException::ToImplWithTypeCheck(
- promise.GetIsolate(), promise.V8Value().As<v8::Promise>()->Result());
+ return V8DOMException::ToImplWithTypeCheck(promise.GetIsolate(),
+ promise.V8Promise()->Result());
}
// static
WakeLockSentinel* ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(
const ScriptPromise& promise) {
- return V8WakeLockSentinel::ToImplWithTypeCheck(
- promise.GetIsolate(), promise.V8Value().As<v8::Promise>()->Result());
+ return V8WakeLockSentinel::ToImplWithTypeCheck(promise.GetIsolate(),
+ promise.V8Promise()->Result());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.cc
deleted file mode 100644
index ecd93b83e5b..00000000000
--- a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.cc
+++ /dev/null
@@ -1,57 +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/wake_lock/worker_navigator_wake_lock.h"
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/wake_lock/wake_lock.h"
-
-namespace blink {
-
-WorkerNavigatorWakeLock::WorkerNavigatorWakeLock(WorkerNavigator& navigator)
- : Supplement<WorkerNavigator>(navigator) {}
-
-// static
-const char WorkerNavigatorWakeLock::kSupplementName[] =
- "WorkerNavigatorWakeLock";
-
-// static
-WorkerNavigatorWakeLock& WorkerNavigatorWakeLock::From(
- WorkerNavigator& navigator) {
- WorkerNavigatorWakeLock* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorWakeLock>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorWakeLock>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-WakeLock* WorkerNavigatorWakeLock::wakeLock(ScriptState* script_state,
- WorkerNavigator& navigator) {
- return WorkerNavigatorWakeLock::From(navigator).GetWakeLock(script_state);
-}
-
-WakeLock* WorkerNavigatorWakeLock::GetWakeLock(ScriptState* script_state) {
- if (!wake_lock_) {
- auto* execution_context = ExecutionContext::From(script_state);
- DCHECK(execution_context);
-
- // TODO(https://crbug.com/839117): Remove this check once the Exposed
- // attribute is fixed to only expose this property in dedicated workers.
- if (execution_context->IsDedicatedWorkerGlobalScope()) {
- wake_lock_ = MakeGarbageCollected<WakeLock>(
- *To<DedicatedWorkerGlobalScope>(execution_context));
- }
- }
- return wake_lock_;
-}
-
-void WorkerNavigatorWakeLock::Trace(Visitor* visitor) const {
- visitor->Trace(wake_lock_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.h b/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.h
deleted file mode 100644
index 031d0545a80..00000000000
--- a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.h
+++ /dev/null
@@ -1,39 +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_WAKE_LOCK_WORKER_NAVIGATOR_WAKE_LOCK_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WORKER_NAVIGATOR_WAKE_LOCK_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class ScriptState;
-class WakeLock;
-class WorkerNavigator;
-
-class WorkerNavigatorWakeLock final
- : public GarbageCollected<WorkerNavigatorWakeLock>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- static WorkerNavigatorWakeLock& From(WorkerNavigator&);
-
- static WakeLock* wakeLock(ScriptState*, WorkerNavigator&);
-
- explicit WorkerNavigatorWakeLock(WorkerNavigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- WakeLock* GetWakeLock(ScriptState*);
-
- Member<WakeLock> wake_lock_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WAKE_LOCK_WORKER_NAVIGATOR_WAKE_LOCK_H_
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 764e8817110..68519317015 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
@@ -7,9 +7,10 @@
// until System Wake Lock API was split from the Screen Wake Lock API.
[
- ImplementedAs=WorkerNavigatorWakeLock,
+ Exposed=DedicatedWorker,
+ ImplementedAs=WakeLock,
RuntimeEnabled=SystemWakeLock,
SecureContext
] partial interface WorkerNavigator {
- [CallWith=ScriptState, SameObject] readonly attribute WakeLock wakeLock;
+ [SameObject] readonly attribute WakeLock wakeLock;
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
index 899b871673f..247c9ff0d36 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
@@ -155,5 +155,6 @@ blink_modules_sources("webaudio") {
deps = [
"//services/metrics/public/cpp:ukm_builders",
"//third_party/blink/renderer/modules/mediastream",
+ "//third_party/fdlibm",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webaudio/DIR_METADATA
new file mode 100644
index 00000000000..cd6016a497e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebAudio"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/OWNERS b/chromium/third_party/blink/renderer/modules/webaudio/OWNERS
index bcc0e71a548..a837fc9b778 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webaudio/OWNERS
@@ -1,4 +1,2 @@
hongchan@chromium.org
rtoy@chromium.org
-
-# COMPONENT: Blink>WebAudio
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
index cb281f5b728..53528e0538b 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc
@@ -274,21 +274,21 @@ double AnalyserNode::smoothingTimeConstant() const {
}
void AnalyserNode::getFloatFrequencyData(NotShared<DOMFloat32Array> array) {
- GetAnalyserHandler().GetFloatFrequencyData(array.View(),
+ GetAnalyserHandler().GetFloatFrequencyData(array.Get(),
context()->currentTime());
}
void AnalyserNode::getByteFrequencyData(NotShared<DOMUint8Array> array) {
- GetAnalyserHandler().GetByteFrequencyData(array.View(),
+ GetAnalyserHandler().GetByteFrequencyData(array.Get(),
context()->currentTime());
}
void AnalyserNode::getFloatTimeDomainData(NotShared<DOMFloat32Array> array) {
- GetAnalyserHandler().GetFloatTimeDomainData(array.View());
+ GetAnalyserHandler().GetFloatTimeDomainData(array.Get());
}
void AnalyserNode::getByteTimeDomainData(NotShared<DOMUint8Array> array) {
- GetAnalyserHandler().GetByteTimeDomainData(array.View());
+ GetAnalyserHandler().GetByteTimeDomainData(array.Get());
}
void AnalyserNode::ReportDidCreate() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
index 4356676b777..111fad79c9d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer.cc
@@ -244,10 +244,10 @@ void AudioBuffer::copyFromChannel(NotShared<DOMFloat32Array> destination,
size_t count = data_length - buffer_offset;
- count = std::min(destination.View()->length(), count);
+ count = std::min(destination->length(), count);
const float* src = channel_data->Data();
- float* dst = destination.View()->Data();
+ float* dst = destination->Data();
DCHECK(src);
DCHECK(dst);
@@ -288,14 +288,14 @@ void AudioBuffer::copyToChannel(NotShared<DOMFloat32Array> source,
size_t count = channel_data->length() - buffer_offset;
- count = std::min(source.View()->length(), count);
- const float* src = source.View()->Data();
+ count = std::min(source->length(), count);
+ const float* src = source->Data();
float* dst = channel_data->Data();
DCHECK(src);
DCHECK(dst);
DCHECK_LE(buffer_offset + count, channel_data->length());
- DCHECK_LE(count, source.View()->length());
+ DCHECK_LE(count, source->length());
memmove(dst + buffer_offset, src, count * sizeof(*dst));
}
@@ -303,7 +303,7 @@ void AudioBuffer::copyToChannel(NotShared<DOMFloat32Array> source,
void AudioBuffer::Zero() {
for (unsigned i = 0; i < channels_.size(); ++i) {
if (NotShared<DOMFloat32Array> array = getChannelData(i)) {
- float* data = array.View()->Data();
+ float* data = array->Data();
memset(data, 0, length() * sizeof(*data));
}
}
@@ -317,7 +317,7 @@ SharedAudioBuffer::SharedAudioBuffer(AudioBuffer* buffer)
: sample_rate_(buffer->sampleRate()), length_(buffer->length()) {
channels_.resize(buffer->numberOfChannels());
for (unsigned int i = 0; i < buffer->numberOfChannels(); ++i) {
- buffer->getChannelData(i).View()->buffer()->ShareNonSharedForInternalUse(
+ buffer->getChannelData(i)->buffer()->ShareNonSharedForInternalUse(
channels_[i]);
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
index 74705fe26f9..159eb7334ba 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc
@@ -33,9 +33,10 @@
#include "third_party/blink/renderer/platform/audio/audio_utilities.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/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -630,7 +631,7 @@ double AudioBufferSourceHandler::ComputePlaybackRate() {
double final_playback_rate = sample_rate_factor * base_playback_rate;
// Take the detune value into account for the final playback rate.
- final_playback_rate *= pow(2, detune_->FinalValue() / 1200);
+ final_playback_rate *= fdlibm::pow(2, detune_->FinalValue() / 1200);
// Sanity check the total rate. It's very important that the resampler not
// get any bad rate values.
@@ -653,7 +654,21 @@ double AudioBufferSourceHandler::GetMinPlaybackRate() {
}
bool AudioBufferSourceHandler::PropagatesSilence() const {
- return !IsPlayingOrScheduled() || HasFinished() || !shared_buffer_.get();
+ DCHECK(Context()->IsAudioThread());
+
+ if (!IsPlayingOrScheduled() || HasFinished())
+ return true;
+
+ // Protect |shared_buffer_| with tryLock because it can be accessed by the
+ // main thread.
+ MutexTryLocker try_locker(process_lock_);
+ if (try_locker.Locked()) {
+ return !shared_buffer_.get();
+ } else {
+ // Can't get lock. Assume |shared_buffer_| exists, so return false to
+ // indicate this node is (or might be) outputting non-zero samples.
+ return false;
+ }
}
void AudioBufferSourceHandler::HandleStoppableSourceNode() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 783ee92eeb0..ce5d7f81c71 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -74,8 +74,16 @@ AudioContext* AudioContext::Create(Document& document,
// into account double buffering (same as baseLatency).
latency_hint =
WebAudioLatencyHint(context_options->latencyHint().GetAsDouble());
+
+ base::UmaHistogramTimes(
+ "WebAudio.AudioContext.latencyHintMilliSeconds",
+ base::TimeDelta::FromSecondsD(latency_hint.Seconds()));
}
+ base::UmaHistogramEnumeration(
+ "WebAudio.AudioContext.latencyHintCategory", latency_hint.Category(),
+ WebAudioLatencyHint::AudioContextLatencyCategory::kLastValue);
+
base::Optional<float> sample_rate;
if (context_options->hasSampleRate()) {
sample_rate = context_options->sampleRate();
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
index e1f1a068d23..0b014b67ff4 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.h"
#include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
@@ -334,6 +335,10 @@ void AudioHandler::ProcessIfNecessary(uint32_t frames_to_process) {
if (!IsInitialized())
return;
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+ "AudioHandler::ProcessIfNecessary", "this",
+ static_cast<void*>(this), "node type", NodeTypeName().Ascii());
+
// Ensure that we only process once per rendering quantum.
// This handles the "fanout" problem where an output is connected to multiple
// inputs. The first time we're called during this time slice we process, but
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
index c5d329479a4..135588f56eb 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
+#include "build/build_config.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
@@ -235,6 +236,49 @@ void AudioParamHandler::CalculateSampleAccurateValues(
CalculateFinalValues(values, number_of_values, IsAudioRate());
}
+// Replace NaN values in |values| with |default_value|.
+static void HandleNaNValues(float* values,
+ unsigned number_of_values,
+ float default_value) {
+ unsigned k = 0;
+#if defined(ARCH_CPU_X86_FAMILY)
+ if (number_of_values >= 4) {
+ __m128 defaults = _mm_set1_ps(default_value);
+ for (k = 0; k < number_of_values; k += 4) {
+ __m128 v = _mm_loadu_ps(values + k);
+ // cmpuord returns all 1's if v is NaN for each elmeent of v.
+ __m128 isnan = _mm_cmpunord_ps(v, v);
+ // Replace NaN parts with default.
+ __m128 result = _mm_and_ps(isnan, defaults);
+ // Merge in the parts that aren't NaN
+ result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
+ _mm_storeu_ps(values + k, result);
+ }
+ }
+#elif defined(CPU_ARM_NEON)
+ if (number_of_values >= 4) {
+ uint32x4_t defaults = static_cast<uint32x4_t>(vdupq_n_f32(default_value));
+ for (k = 0; k < number_of_values; k += 4) {
+ float32x4_t v = vld1q_f32(values + k);
+ // Returns true (all ones) if v is not NaN
+ uint32x4_t is_not_nan = vceqq_f32(v, v);
+ // Get the parts that are not NaN
+ uint32x4_t result = vandq_u32(is_not_nan, v);
+ // Replace the parts that are NaN with the default and merge with previous
+ // result. (Note: vbic_u32(x, y) = x and not y)
+ result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
+ vst1q_f32(values + k, static_cast<float32x4_t>(result));
+ }
+ }
+#endif
+
+ for (; k < number_of_values; ++k) {
+ if (std::isnan(values[k])) {
+ values[k] = default_value;
+ }
+ }
+}
+
void AudioParamHandler::CalculateFinalValues(float* values,
unsigned number_of_values,
bool sample_accurate) {
@@ -297,10 +341,21 @@ void AudioParamHandler::CalculateFinalValues(float* values,
}
}
- // Clamp the values now to the nominal range
float min_value = MinValue();
float max_value = MaxValue();
+ if (NumberOfRenderingConnections() > 0) {
+ // AudioParams by themselves don't produce NaN because of the finite min
+ // and max values. But an input to an AudioParam could have NaNs.
+ //
+ // NaN values in AudioParams must be replaced by the AudioParam's
+ // defaultValue. Then these values must be clamped to lie in the nominal
+ // range between the AudioParam's minValue and maxValue.
+ //
+ // See https://webaudio.github.io/web-audio-api/#computation-of-value.
+ HandleNaNValues(values, number_of_values, DefaultValue());
+ }
+
vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
number_of_values);
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
index c6177422fc2..db3c5c28b90 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -37,6 +37,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/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
#if defined(ARCH_CPU_X86_FAMILY)
#include <emmintrin.h>
@@ -132,7 +133,7 @@ float AudioParamTimeline::ExponentialRampAtTime(double t,
double time1,
float value2,
double time2) {
- return value1 * pow(value2 / value1, (t - time1) / (time2 - time1));
+ return value1 * fdlibm::pow(value2 / value1, (t - time1) / (time2 - time1));
}
// Compute the value of a set target event at time t with the given event
@@ -142,7 +143,7 @@ float AudioParamTimeline::TargetValueAtTime(double t,
double time1,
float value2,
float time_constant) {
- return value2 + (value1 - value2) * exp(-(t - time1) / time_constant);
+ return value2 + (value1 - value2) * fdlibm::exp(-(t - time1) / time_constant);
}
// Compute the value of a set curve event at time t with the given event
@@ -1322,8 +1323,8 @@ void AudioParamTimeline::ProcessSetTargetFollowedByRamp(
// currentFrame.
value = event->Value() +
(value - event->Value()) *
- exp(-(current_frame / sample_rate - event->Time()) /
- event->TimeConstant());
+ fdlibm::exp(-(current_frame / sample_rate - event->Time()) /
+ event->TimeConstant());
} else {
// SetTarget has already started. Update |value| one frame because it's
// the value from the previous frame.
@@ -1555,11 +1556,12 @@ std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessExponentialRamp(
// m = (v2/v1)^(1/(F*(t2-t1)))
// Compute the per-sample multiplier.
- float multiplier = powf(value2 / value1, 1 / num_sample_frames);
+ float multiplier = fdlibm::powf(value2 / value1, 1 / num_sample_frames);
// Set the starting value of the exponential ramp. Do not attempt
// to optimize pow to powf. See crbug.com/771306.
- value = value1 * pow(value2 / static_cast<double>(value1),
- (current_frame / sample_rate - time1) / delta_time);
+ value = value1 *
+ fdlibm::pow(value2 / static_cast<double>(value1),
+ (current_frame / sample_rate - time1) / delta_time);
for (; write_index < fill_to_frame; ++write_index) {
values[write_index] = value;
value *= multiplier;
@@ -1618,9 +1620,9 @@ std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessSetTarget(
// unsigned and could be 0.
if (ramp_start_frame <= current_frame &&
current_frame < ramp_start_frame + 1) {
- value = target +
- (value - target) *
- exp(-(current_frame / sample_rate - time1) / time_constant);
+ value = target + (value - target) *
+ fdlibm::exp(-(current_frame / sample_rate - time1) /
+ time_constant);
} else {
// Otherwise, need to compute a new value bacause |value| is the
// last computed value of SetTarget. Time has progressed by one
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
index 7045f8fbdac..581f6598ab0 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_node.h"
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 b910fa330d7..1e357b4b8da 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
@@ -23,6 +23,7 @@
#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"
#include "third_party/blink/renderer/core/inspector/worker_devtools_params.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
#include "third_party/blink/renderer/core/messaging/message_channel.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
@@ -80,7 +81,8 @@ class AudioWorkletGlobalScopeTest : public PageTestBase,
window->Url(), mojom::blink::ScriptType::kModule, "AudioWorklet",
window->UserAgent(),
window->GetFrame()->Loader().UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(),
nullptr /* worker_clients */, nullptr /* content_settings_client */,
@@ -90,7 +92,8 @@ class AudioWorkletGlobalScopeTest : public PageTestBase,
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken()),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken()),
base::nullopt, std::make_unique<WorkerDevToolsParams>());
return thread;
}
@@ -148,10 +151,8 @@ class AudioWorkletGlobalScopeTest : public PageTestBase,
global_scope->ScriptController()->GetScriptState();
EXPECT_TRUE(script_state);
KURL js_url("https://example.com/worklet.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- script_state->GetIsolate(), source_code, js_url, js_url,
- ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ script_state->GetIsolate(), source_code, js_url);
EXPECT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(script_state, module, js_url);
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 23dcfa97a1d..02846cea5c0 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
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.h"
+#include <utility>
+
#include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
@@ -51,7 +53,7 @@ void AudioWorkletObjectProxy::DidEvaluateTopLevelScript(bool success) {
CrossThreadBindOnce(
&AudioWorkletMessagingProxy::SynchronizeWorkletProcessorInfoList,
GetAudioWorkletMessagingProxyWeakPtr(),
- WTF::Passed(std::move(processor_info_list))));
+ std::move(processor_info_list)));
}
void AudioWorkletObjectProxy::WillDestroyWorkerGlobalScope() {
@@ -60,8 +62,7 @@ void AudioWorkletObjectProxy::WillDestroyWorkerGlobalScope() {
CrossThreadWeakPersistent<AudioWorkletMessagingProxy>
AudioWorkletObjectProxy::GetAudioWorkletMessagingProxyWeakPtr() {
- return CrossThreadWeakPersistent<AudioWorkletMessagingProxy>(
- MessagingProxyWeakPtr());
+ return DownCast<AudioWorkletMessagingProxy>(MessagingProxyWeakPtr());
}
} // namespace blink
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 790008cec81..ee611387c08 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
@@ -99,7 +99,8 @@ class AudioWorkletThreadTestBase : public PageTestBase,
window->Url(), mojom::blink::ScriptType::kModule, "AudioWorklet",
window->UserAgent(),
window->GetFrame()->Loader().UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(),
nullptr /* worker_clients */, nullptr /* content_settings_client */,
@@ -109,7 +110,8 @@ class AudioWorkletThreadTestBase : public PageTestBase,
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken()),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken()),
base::nullopt, std::make_unique<WorkerDevToolsParams>());
}
@@ -120,10 +122,8 @@ class AudioWorkletThreadTestBase : public PageTestBase,
EXPECT_TRUE(script_state);
ScriptState::Scope scope(script_state);
KURL js_url("https://example.com/worklet.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- script_state->GetIsolate(), "var counter = 0; ++counter;", js_url,
- js_url, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ script_state->GetIsolate(), "var counter = 0; ++counter;", js_url);
EXPECT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(script_state, module, js_url);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
index 2c732a101f3..0c6e6623bf7 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/biquad_filter_node.cc
@@ -255,23 +255,23 @@ void BiquadFilterNode::getFrequencyResponse(
NotShared<DOMFloat32Array> mag_response,
NotShared<DOMFloat32Array> phase_response,
ExceptionState& exception_state) {
- size_t frequency_hz_length = frequency_hz.View()->length();
+ size_t frequency_hz_length = frequency_hz->length();
- if (mag_response.View()->length() != frequency_hz_length) {
+ if (mag_response->length() != frequency_hz_length) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
ExceptionMessages::IndexOutsideRange(
- "magResponse length", mag_response.View()->length(),
- frequency_hz_length, ExceptionMessages::kInclusiveBound,
- frequency_hz_length, ExceptionMessages::kInclusiveBound));
+ "magResponse length", mag_response->length(), frequency_hz_length,
+ ExceptionMessages::kInclusiveBound, frequency_hz_length,
+ ExceptionMessages::kInclusiveBound));
return;
}
- if (phase_response.View()->length() != frequency_hz_length) {
+ if (phase_response->length() != frequency_hz_length) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
ExceptionMessages::IndexOutsideRange(
- "phaseResponse length", phase_response.View()->length(),
+ "phaseResponse length", phase_response->length(),
frequency_hz_length, ExceptionMessages::kInclusiveBound,
frequency_hz_length, ExceptionMessages::kInclusiveBound));
return;
@@ -288,8 +288,8 @@ void BiquadFilterNode::getFrequencyResponse(
// If the length is 0, there's nothing to do.
if (frequency_hz_length_as_int > 0) {
GetBiquadProcessor()->GetFrequencyResponse(
- frequency_hz_length_as_int, frequency_hz.View()->Data(),
- mag_response.View()->Data(), phase_response.View()->Data());
+ frequency_hz_length_as_int, frequency_hz->Data(), mag_response->Data(),
+ phase_response->Data());
}
}
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 72a6c9b6a14..0a72a2caca8 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
@@ -178,7 +178,7 @@ void ConvolverHandler::SetBuffer(AudioBuffer* buffer,
}
for (unsigned i = 0; i < number_of_channels; ++i) {
- buffer_bus->SetChannelMemory(i, buffer->getChannelData(i).View()->Data(),
+ buffer_bus->SetChannelMemory(i, buffer->getChannelData(i)->Data(),
buffer_length);
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
index 09f56436125..79baa0b961b 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
@@ -245,25 +245,25 @@ void IIRFilterNode::getFrequencyResponse(
NotShared<DOMFloat32Array> mag_response,
NotShared<DOMFloat32Array> phase_response,
ExceptionState& exception_state) {
- size_t frequency_hz_length = frequency_hz.View()->length();
+ size_t frequency_hz_length = frequency_hz->length();
// All the arrays must have the same length. Just verify that all
// the arrays have the same length as the |frequency_hz| array.
- if (mag_response.View()->length() != frequency_hz_length) {
+ if (mag_response->length() != frequency_hz_length) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
ExceptionMessages::IndexOutsideRange(
- "magResponse length", mag_response.View()->length(),
- frequency_hz_length, ExceptionMessages::kInclusiveBound,
- frequency_hz_length, ExceptionMessages::kInclusiveBound));
+ "magResponse length", mag_response->length(), frequency_hz_length,
+ ExceptionMessages::kInclusiveBound, frequency_hz_length,
+ ExceptionMessages::kInclusiveBound));
return;
}
- if (phase_response.View()->length() != frequency_hz_length) {
+ if (phase_response->length() != frequency_hz_length) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidAccessError,
ExceptionMessages::IndexOutsideRange(
- "phaseResponse length", phase_response.View()->length(),
+ "phaseResponse length", phase_response->length(),
frequency_hz_length, ExceptionMessages::kInclusiveBound,
frequency_hz_length, ExceptionMessages::kInclusiveBound));
return;
@@ -280,8 +280,8 @@ void IIRFilterNode::getFrequencyResponse(
// Nothing to do if the length is 0.
if (frequency_hz_length_as_int > 0) {
GetIIRFilterProcessor()->GetFrequencyResponse(
- frequency_hz_length_as_int, frequency_hz.View()->Data(),
- mag_response.View()->Data(), phase_response.View()->Data());
+ frequency_hz_length_as_int, frequency_hz->Data(), mag_response->Data(),
+ phase_response->Data());
}
}
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 96b646a82d6..017445eeb95 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
@@ -238,7 +238,7 @@ void MediaElementAudioSourceHandler::unlock() {
process_lock_.unlock();
}
-// ----------------------------------------------------------------
+// -----------------------------------------------------------------------------
MediaElementAudioSourceNode::MediaElementAudioSourceNode(
AudioContext& context,
@@ -286,12 +286,6 @@ MediaElementAudioSourceNode* MediaElementAudioSourceNode::Create(
return Create(*context, *options->mediaElement(), exception_state);
}
-void MediaElementAudioSourceNode::Trace(Visitor* visitor) const {
- visitor->Trace(media_element_);
- AudioSourceProviderClient::Trace(visitor);
- AudioNode::Trace(visitor);
-}
-
MediaElementAudioSourceHandler&
MediaElementAudioSourceNode::GetMediaElementAudioSourceHandler() const {
return static_cast<MediaElementAudioSourceHandler&>(Handler());
@@ -323,4 +317,15 @@ void MediaElementAudioSourceNode::ReportWillBeDestroyed() {
GraphTracer().WillDestroyAudioNode(this);
}
+bool MediaElementAudioSourceNode::HasPendingActivity() const {
+ // The node stays alive as long as the context is running.
+ return context()->ContextState() == BaseAudioContext::kRunning;
+}
+
+void MediaElementAudioSourceNode::Trace(Visitor* visitor) const {
+ visitor->Trace(media_element_);
+ AudioSourceProviderClient::Trace(visitor);
+ AudioNode::Trace(visitor);
+}
+
} // namespace blink
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 950368bcd51..b977f3ea6cb 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
@@ -113,8 +113,12 @@ class MediaElementAudioSourceHandler final : public AudioHandler {
bool is_origin_tainted_;
};
-class MediaElementAudioSourceNode final : public AudioNode,
- public AudioSourceProviderClient {
+// -----------------------------------------------------------------------------
+
+class MediaElementAudioSourceNode final
+ : public AudioNode,
+ public AudioSourceProviderClient,
+ public ActiveScriptWrappable<MediaElementAudioSourceNode> {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -126,7 +130,6 @@ class MediaElementAudioSourceNode final : public AudioNode,
MediaElementAudioSourceNode(AudioContext&, HTMLMediaElement&);
- void Trace(Visitor*) const override;
MediaElementAudioSourceHandler& GetMediaElementAudioSourceHandler() const;
HTMLMediaElement* mediaElement() const;
@@ -142,6 +145,10 @@ class MediaElementAudioSourceNode final : public AudioNode,
void ReportDidCreate() final;
void ReportWillBeDestroyed() final;
+ // GC
+ bool HasPendingActivity() const final;
+ void Trace(Visitor*) const override;
+
private:
Member<HTMLMediaElement> media_element_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl
index 1477fe618fc..44ef971c544 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl
+++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl
@@ -25,6 +25,7 @@
// See https://webaudio.github.io/web-audio-api/#mediaelementaudiosourcenode
[
+ ActiveScriptWrappable,
Exposed=Window
] interface MediaElementAudioSourceNode : AudioNode {
[RaisesException, Measure] constructor(AudioContext context, MediaElementAudioSourceOptions options);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc
index 533cf4fef9a..665628a8db8 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc
@@ -102,8 +102,9 @@ void MediaStreamAudioSourceHandler::SetFormat(uint32_t number_of_channels,
}
void MediaStreamAudioSourceHandler::Process(uint32_t number_of_frames) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
- "MediaStreamAudioSourceHandler::Process");
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+ "MediaStreamAudioSourceHandler::Process", "this",
+ static_cast<void*>(this), "number_of_frames", number_of_frames);
AudioBus* output_bus = Output(0).Bus();
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
index 27acf41ef1f..992ea1bfda7 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
@@ -108,21 +108,6 @@ OfflineAudioContext* OfflineAudioContext::Create(
fprintf(stderr, "[%16p]: OfflineAudioContext::OfflineAudioContext()\n",
audio_context);
#endif
- base::UmaHistogramSparse("WebAudio.OfflineAudioContext.ChannelCount",
- number_of_channels);
- // Arbitrarly limit the maximum length to 1 million frames (about 20 sec
- // at 48kHz). The number of buckets is fairly arbitrary.
- base::UmaHistogramCounts1M("WebAudio.OfflineAudioContext.Length",
- number_of_frames);
- // The limits are the min and max AudioBuffer sample rates currently
- // supported. We use explicit values here instead of
- // audio_utilities::minAudioBufferSampleRate() and
- // audio_utilities::maxAudioBufferSampleRate(). The number of buckets is
- // fairly arbitrary.
- base::UmaHistogramCustomCounts(
- "WebAudio.OfflineAudioContext.SampleRate384kHz", sample_rate, 3000,
- 384000, 50);
-
return audio_context;
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_options.idl b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_options.idl
index d9e7ef88ba7..caa24013d09 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_options.idl
+++ b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_options.idl
@@ -7,5 +7,5 @@ dictionary OscillatorOptions : AudioNodeOptions {
OscillatorType type = "sine";
float detune = 0;
float frequency = 440;
- PeriodicWave? periodicWave;
-}; \ No newline at end of file
+ PeriodicWave periodicWave;
+};
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
index d4f8ece81af..8b7afe0fe01 100644
--- 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
@@ -32,8 +32,12 @@ RealtimeAudioWorkletThread::RealtimeAudioWorkletThread(
// TODO(crbug.com/1022888): The worklet thread priority is always NORMAL on
// Linux and Chrome OS regardless of this thread priority setting.
params.thread_priority = base::ThreadPriority::REALTIME_AUDIO;
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "RealtimeAudioWorkletThread() - REALTIME_AUDIO");
} else {
params.thread_priority = base::ThreadPriority::NORMAL;
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "RealtimeAudioWorkletThread() - NORMAL");
}
if (++s_ref_count_ == 1)
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index d46e17440a9..5dd0c899a36 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -30,6 +30,8 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.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/inspector/console_message.h"
#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
@@ -106,6 +108,15 @@ ScriptProcessorHandler::ScriptProcessorHandler(
}
Initialize();
+
+ LocalDOMWindow* window = To<LocalDOMWindow>(Context()->GetExecutionContext());
+ if (window) {
+ window->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kDeprecation,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead."
+ " (https://bit.ly/audio-worklet)"));
+ }
}
scoped_refptr<ScriptProcessorHandler> ScriptProcessorHandler::Create(
@@ -455,19 +466,15 @@ ScriptProcessorNode* ScriptProcessorNode::Create(
case 0:
// Choose an appropriate size. For an AudioContext, we need to
// choose an appropriate size based on the callback buffer size.
- // For OfflineAudioContext, there's no callback buffer size, so
- // just use the minimum valid buffer size.
if (context.HasRealtimeConstraint()) {
- // TODO(crbug.com/854229): Due to the incompatible constructor between
- // AudioDestinationNode and RealtimeAudioDestinationNode, casting
- // directly from |destination()| is impossible. This is a temporary
- // workaround until the refactoring is completed.
RealtimeAudioDestinationHandler& destination_handler =
static_cast<RealtimeAudioDestinationHandler&>(
context.destination()->GetAudioDestinationHandler());
buffer_size =
ChooseBufferSize(destination_handler.GetCallbackBufferSize());
} else {
+ // For OfflineAudioContext, there's no callback buffer size, so
+ // just use the minimum valid buffer size.
buffer_size = 256;
}
break;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/wave_shaper_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/wave_shaper_node.cc
index 6b745816227..40bc3647b68 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/wave_shaper_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/wave_shaper_node.cc
@@ -117,7 +117,7 @@ void WaveShaperNode::setCurve(NotShared<DOMFloat32Array> curve,
DCHECK(IsMainThread());
if (curve) {
- SetCurveImpl(curve.View()->Data(), curve.View()->length(), exception_state);
+ SetCurveImpl(curve->Data(), curve->length(), exception_state);
} else {
SetCurveImpl(nullptr, 0, exception_state);
}
@@ -138,7 +138,7 @@ NotShared<DOMFloat32Array> WaveShaperNode::curve() {
unsigned size = curve->size();
NotShared<DOMFloat32Array> result(DOMFloat32Array::Create(size));
- memcpy(result.View()->Data(), curve->data(), sizeof(float) * size);
+ memcpy(result->Data(), curve->data(), sizeof(float) * size);
return result;
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index b4090bd22c0..d2e14a3d524 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//media/media_options.gni")
import("//third_party/blink/renderer/modules/modules.gni")
import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
import("//third_party/protobuf/proto_library.gni")
@@ -12,9 +13,15 @@ blink_modules_sources("webcodecs") {
"audio_decoder.h",
"audio_decoder_broker.cc",
"audio_decoder_broker.h",
+ "audio_encoder.cc",
+ "audio_encoder.h",
"audio_frame.cc",
"audio_frame.h",
+ "audio_frame_serialization_data.cc",
+ "audio_frame_serialization_data.h",
"codec_config_eval.h",
+ "codec_logger.cc",
+ "codec_logger.h",
"codec_state_helper.cc",
"codec_state_helper.h",
"decoder_selector.cc",
@@ -27,6 +34,10 @@ blink_modules_sources("webcodecs") {
"encoded_video_chunk.cc",
"encoded_video_chunk.h",
"encoded_video_metadata.h",
+ "encoder_base.cc",
+ "encoder_base.h",
+ "hardware_preference.cc",
+ "hardware_preference.h",
"image_decoder_external.cc",
"image_decoder_external.h",
"plane.cc",
@@ -43,6 +54,8 @@ blink_modules_sources("webcodecs") {
"video_frame_attachment.h",
"video_frame_handle.cc",
"video_frame_handle.h",
+ "video_frame_logger.cc",
+ "video_frame_logger.h",
"video_track_reader.cc",
"video_track_reader.h",
"video_track_writer.cc",
@@ -54,7 +67,11 @@ blink_modules_sources("webcodecs") {
"//media/mojo/clients",
"//media/mojo/mojom",
"//third_party/libyuv:libyuv",
+ "//third_party/opus",
]
+ if (media_use_openh264) {
+ deps += [ "//third_party/openh264:encoder" ]
+ }
public_deps = [
"//third_party/blink/renderer/modules/mediastream:mediastream",
"//third_party/blink/renderer/modules/webaudio:webaudio",
@@ -67,6 +84,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"audio_decoder_broker_test.cc",
+ "audio_frame_test.cc",
"decoder_selector_test.cc",
"encoded_video_chunk_test.cc",
"image_decoder_external_test.cc",
@@ -101,5 +119,6 @@ source_set("unit_tests") {
}
fuzzable_proto_library("fuzzer_protos") {
+ generate_python = true
sources = [ "fuzzer_inputs.proto" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/DEPS b/chromium/third_party/blink/renderer/modules/webcodecs/DEPS
index f79eda8dda1..e1eae306c51 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/DEPS
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/DEPS
@@ -5,7 +5,11 @@ include_rules = [
"+components/viz/common/resources/single_release_callback.h",
"+gpu/command_buffer/client/shared_image_interface.h",
+ "+gpu/command_buffer/client/raster_interface.h",
+ "+gpu/config/gpu_feature_info.h",
+ "+gpu/GLES2/gl2extchromium.h",
+ "+media/audio",
"+media/base",
"+media/filters",
"+media/formats/mp4/box_definitions.h",
@@ -15,6 +19,8 @@ include_rules = [
"+media/video",
"+third_party/libyuv",
+ "+third_party/openh264",
+ "+third_party/opus",
"+ui/gfx/color_space.h",
"+ui/gfx/geometry/rect.h",
@@ -35,4 +41,7 @@ specific_include_rules = {
"+base/run_loop.h",
"+base/files/file_util.h",
],
+ "video_frame_test\.cc": [
+ "+components/viz/test/test_context_provider.h",
+ ]
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webcodecs/DIR_METADATA
new file mode 100644
index 00000000000..d0082086ec8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+ component: "Blink>Media>WebCodecs"
+}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
index 601c5d4eae5..45cc35c85dd 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
@@ -14,10 +14,13 @@
#include "media/base/supported_types.h"
#include "media/base/waiting.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_support.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -26,6 +29,43 @@
namespace blink {
+bool IsValidConfig(const AudioDecoderConfig& config,
+ media::AudioType& out_audio_type,
+ String& out_console_message) {
+ media::AudioCodec codec = media::kUnknownAudioCodec;
+ bool is_codec_ambiguous = true;
+ bool parse_succeeded = ParseAudioCodecString("", config.codec().Utf8(),
+ &is_codec_ambiguous, &codec);
+
+ if (!parse_succeeded) {
+ out_console_message = "Failed to parse codec string.";
+ return false;
+ }
+
+ if (is_codec_ambiguous) {
+ out_console_message = "Codec string is ambiguous.";
+ return false;
+ }
+
+ out_audio_type = {codec};
+ return true;
+}
+
+AudioDecoderConfig* CopyConfig(const AudioDecoderConfig& config) {
+ AudioDecoderConfig* copy = AudioDecoderConfig::Create();
+ copy->setCodec(config.codec());
+ copy->setSampleRate(config.sampleRate());
+ copy->setNumberOfChannels(config.numberOfChannels());
+ if (config.hasDescription()) {
+ DOMArrayPiece buffer(config.description());
+ DOMArrayBuffer* buffer_copy =
+ DOMArrayBuffer::Create(buffer.Data(), buffer.ByteLength());
+ copy->setDescription(
+ ArrayBufferOrArrayBufferView::FromArrayBuffer(buffer_copy));
+ }
+ return copy;
+}
+
// static
std::unique_ptr<AudioDecoderTraits::MediaDecoderType>
AudioDecoderTraits::CreateDecoder(
@@ -42,7 +82,7 @@ void AudioDecoderTraits::UpdateDecoderLog(const MediaDecoderType& decoder,
media_log->SetProperty<media::MediaLogProperty::kFrameTitle>(
std::string("AudioDecoder(WebCodecs)"));
media_log->SetProperty<media::MediaLogProperty::kAudioDecoderName>(
- decoder.GetDisplayName());
+ decoder.GetDecoderType());
media_log->SetProperty<media::MediaLogProperty::kIsPlatformAudioDecoder>(
decoder.IsPlatformDecoder());
media_log->SetProperty<media::MediaLogProperty::kAudioTracks>(
@@ -50,6 +90,14 @@ void AudioDecoderTraits::UpdateDecoderLog(const MediaDecoderType& decoder,
}
// static
+AudioDecoderTraits::OutputType* AudioDecoderTraits::MakeOutput(
+ scoped_refptr<MediaOutputType> output,
+ ExecutionContext* context) {
+ return MakeGarbageCollected<AudioDecoderTraits::OutputType>(
+ std::move(output));
+}
+
+// static
void AudioDecoderTraits::InitializeDecoder(
MediaDecoderType& decoder,
const MediaConfigType& media_config,
@@ -68,56 +116,46 @@ int AudioDecoderTraits::GetMaxDecodeRequests(const MediaDecoderType& decoder) {
AudioDecoder* AudioDecoder::Create(ScriptState* script_state,
const AudioDecoderInit* init,
ExceptionState& exception_state) {
- return MakeGarbageCollected<AudioDecoder>(script_state, init,
- exception_state);
+ auto* result =
+ MakeGarbageCollected<AudioDecoder>(script_state, init, exception_state);
+ return exception_state.HadException() ? nullptr : result;
}
-AudioDecoder::AudioDecoder(ScriptState* script_state,
- const AudioDecoderInit* init,
- ExceptionState& exception_state)
- : DecoderTemplate<AudioDecoderTraits>(script_state, init, exception_state) {
- UseCounter::Count(ExecutionContext::From(script_state),
- WebFeature::kWebCodecs);
-}
+// static
+ScriptPromise AudioDecoder::isConfigSupported(ScriptState* script_state,
+ const AudioDecoderConfig* config,
+ ExceptionState& exception_state) {
+ media::AudioType audio_type;
+ String console_message;
+
+ if (!IsValidConfig(*config, audio_type, console_message)) {
+ exception_state.ThrowTypeError(console_message);
+ return ScriptPromise();
+ }
-CodecConfigEval AudioDecoder::MakeMediaConfig(const ConfigType& config,
- MediaConfigType* out_media_config,
- String* out_console_message) {
- media::AudioCodec codec = media::kUnknownAudioCodec;
- bool is_codec_ambiguous = true;
- bool parse_succeeded = ParseAudioCodecString("", config.codec().Utf8(),
- &is_codec_ambiguous, &codec);
+ AudioDecoderSupport* support = AudioDecoderSupport::Create();
+ support->setSupported(media::IsSupportedAudioType(audio_type));
+ support->setConfig(CopyConfig(*config));
- if (!parse_succeeded) {
- *out_console_message = "Failed to parse codec string.";
- return CodecConfigEval::kInvalid;
- }
+ return ScriptPromise::Cast(script_state, ToV8(support, script_state));
+}
- if (is_codec_ambiguous) {
- *out_console_message = "Codec string is ambiguous.";
- return CodecConfigEval::kInvalid;
- }
+// static
+CodecConfigEval AudioDecoder::MakeMediaAudioDecoderConfig(
+ const ConfigType& config,
+ MediaConfigType& out_media_config,
+ String& out_console_message) {
+ media::AudioType audio_type;
- if (!media::IsSupportedAudioType({codec})) {
- *out_console_message = "Configuration is not supported.";
- return CodecConfigEval::kUnsupported;
- }
+ if (!IsValidConfig(config, audio_type, out_console_message))
+ return CodecConfigEval::kInvalid;
std::vector<uint8_t> extra_data;
if (config.hasDescription()) {
- if (config.description().IsArrayBuffer()) {
- DOMArrayBuffer* buffer = config.description().GetAsArrayBuffer();
- uint8_t* start = static_cast<uint8_t*>(buffer->Data());
- size_t size = buffer->ByteLength();
- extra_data.assign(start, start + size);
- } else {
- DCHECK(config.description().IsArrayBufferView());
- DOMArrayBufferView* view =
- config.description().GetAsArrayBufferView().Get();
- uint8_t* start = static_cast<uint8_t*>(view->BaseAddress());
- size_t size = view->byteLength();
- extra_data.assign(start, start + size);
- }
+ DOMArrayPiece buffer(config.description());
+ uint8_t* start = static_cast<uint8_t*>(buffer.Data());
+ size_t size = buffer.ByteLength();
+ extra_data.assign(start, start + size);
}
media::ChannelLayout channel_layout =
@@ -127,14 +165,31 @@ CodecConfigEval AudioDecoder::MakeMediaConfig(const ConfigType& config,
: media::GuessChannelLayout(config.numberOfChannels());
// TODO(chcunningham): Add sample format to IDL.
- out_media_config->Initialize(
- codec, media::kSampleFormatPlanarF32, channel_layout, config.sampleRate(),
- extra_data, media::EncryptionScheme::kUnencrypted,
+ out_media_config.Initialize(
+ audio_type.codec, media::kSampleFormatPlanarF32, channel_layout,
+ config.sampleRate(), extra_data, media::EncryptionScheme::kUnencrypted,
base::TimeDelta() /* seek preroll */, 0 /* codec delay */);
return CodecConfigEval::kSupported;
}
+AudioDecoder::AudioDecoder(ScriptState* script_state,
+ const AudioDecoderInit* init,
+ ExceptionState& exception_state)
+ : DecoderTemplate<AudioDecoderTraits>(script_state, init, exception_state) {
+ UseCounter::Count(ExecutionContext::From(script_state),
+ WebFeature::kWebCodecs);
+}
+
+CodecConfigEval AudioDecoder::MakeMediaConfig(const ConfigType& config,
+ MediaConfigType* out_media_config,
+ String* out_console_message) {
+ DCHECK(out_media_config);
+ DCHECK(out_console_message);
+ return MakeMediaAudioDecoderConfig(config, *out_media_config,
+ *out_console_message);
+}
+
media::StatusOr<scoped_refptr<media::DecoderBuffer>>
AudioDecoder::MakeDecoderBuffer(const InputType& chunk) {
auto decoder_buffer = media::DecoderBuffer::CopyFrom(
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.h b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
index 69289997578..c148d1024ee 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
@@ -12,8 +12,7 @@
#include "media/base/status.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/decoder_template.h"
@@ -33,11 +32,12 @@ class MediaLog;
namespace blink {
+class AudioDecoderConfig;
class AudioFrame;
class EncodedAudioChunk;
-class EncodedAudioConfig;
class ExceptionState;
class AudioDecoderInit;
+class ScriptPromise;
class V8AudioFrameOutputCallback;
class MODULES_EXPORT AudioDecoderTraits {
@@ -47,7 +47,7 @@ class MODULES_EXPORT AudioDecoderTraits {
using MediaOutputType = media::AudioBuffer;
using MediaDecoderType = media::AudioDecoder;
using OutputCallbackType = V8AudioFrameOutputCallback;
- using ConfigType = EncodedAudioConfig;
+ using ConfigType = AudioDecoderConfig;
using MediaConfigType = media::AudioDecoderConfig;
using InputType = EncodedAudioChunk;
@@ -65,6 +65,8 @@ class MODULES_EXPORT AudioDecoderTraits {
static void UpdateDecoderLog(const MediaDecoderType& decoder,
const MediaConfigType& media_config,
media::MediaLog* media_log);
+ static OutputType* MakeOutput(scoped_refptr<MediaOutputType>,
+ ExecutionContext*);
};
class MODULES_EXPORT AudioDecoder : public DecoderTemplate<AudioDecoderTraits> {
@@ -75,6 +77,16 @@ class MODULES_EXPORT AudioDecoder : public DecoderTemplate<AudioDecoderTraits> {
const AudioDecoderInit*,
ExceptionState&);
+ static ScriptPromise isConfigSupported(ScriptState*,
+ const AudioDecoderConfig*,
+ ExceptionState&);
+
+ // For use by MediaSource and by ::MakeMediaConfig.
+ static CodecConfigEval MakeMediaAudioDecoderConfig(
+ const ConfigType& config,
+ MediaConfigType& out_media_config,
+ String& out_console_message);
+
AudioDecoder(ScriptState*, const AudioDecoderInit*, ExceptionState&);
~AudioDecoder() override = default;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl
index 5e3c35709ae..b5c1c6503d8 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl
@@ -23,18 +23,19 @@
// |decodeQueueSize| is greater than a constant.
readonly attribute long decodeQueueSize;
+ // Which state the decoder is in, indicating which methods can be called.
+ readonly attribute CodecState state;
+
// Set the stream configuration for future decode() requests.
//
// The next decode request must be for a keyframe.
//
// TODO(chcunningham): Move the keyframe rule into the bytestream registry.
- [RaisesException] void configure(EncodedAudioConfig config);
+ [RaisesException] void configure(AudioDecoderConfig config);
// Request decoding of an input chunk.
//
// You must call configure() before calling decode() for the first time.
- //
- // TODO(chcunningham): Change to a dictionary type.
[RaisesException] void decode(EncodedAudioChunk chunk);
// Request output from all previous decode requests.
@@ -59,6 +60,7 @@
// Not recoverable: make a new AudioDecoder if needed.
[RaisesException] void close();
- // Which state the decoder is in, indicating which methods can be called.
- readonly attribute CodecState state;
+ // Call prior to configure() to determine whether config will be supported.
+ [CallWith=ScriptState, RaisesException]
+ static Promise<AudioDecoderSupport> isConfigSupported(AudioDecoderConfig config);
};
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 ee9ace1375e..53afaac9f18 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
@@ -73,13 +73,13 @@ class MediaAudioTaskWrapper {
MediaAudioTaskWrapper(
base::WeakPtr<CrossThreadAudioDecoderClient> weak_client,
ExecutionContext& execution_context,
- media::MediaLog* media_log,
+ std::unique_ptr<media::MediaLog> media_log,
scoped_refptr<base::SequencedTaskRunner> media_task_runner,
scoped_refptr<base::SequencedTaskRunner> main_task_runner)
: weak_client_(std::move(weak_client)),
media_task_runner_(std::move(media_task_runner)),
main_task_runner_(std::move(main_task_runner)),
- media_log_(media_log) {
+ media_log_(std::move(media_log)) {
DVLOG(2) << __func__;
DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -178,7 +178,7 @@ class MediaAudioTaskWrapper {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::unique_ptr<media::AudioDecoder>> audio_decoders;
- decoder_factory_->CreateAudioDecoders(media_task_runner_, media_log_,
+ decoder_factory_->CreateAudioDecoders(media_task_runner_, media_log_.get(),
&audio_decoders);
return audio_decoders;
@@ -199,6 +199,7 @@ class MediaAudioTaskWrapper {
if (decoder_) {
status = media::OkStatus();
decoder_details = DecoderDetails({decoder_->GetDisplayName(),
+ decoder_->GetDecoderType(),
decoder_->IsPlatformDecoder(),
decoder_->NeedsBitstreamConversion()});
}
@@ -247,7 +248,7 @@ class MediaAudioTaskWrapper {
std::unique_ptr<media::AudioDecoder> decoder_;
gfx::ColorSpace target_color_space_;
- media::MediaLog* media_log_;
+ std::unique_ptr<media::MediaLog> media_log_;
SEQUENCE_CHECKER(sequence_checker_);
@@ -266,7 +267,7 @@ AudioDecoderBroker::AudioDecoderBroker(media::MediaLog* media_log,
: media_task_runner_(worker_pool::CreateSequencedTaskRunner({})) {
DVLOG(2) << __func__;
media_tasks_ = std::make_unique<MediaAudioTaskWrapper>(
- weak_factory_.GetWeakPtr(), execution_context, media_log,
+ weak_factory_.GetWeakPtr(), execution_context, media_log->Clone(),
media_task_runner_,
execution_context.GetTaskRunner(TaskType::kInternalMedia));
}
@@ -283,6 +284,11 @@ std::string AudioDecoderBroker::GetDisplayName() const {
: AudioDecoderBroker::kDefaultDisplayName;
}
+media::AudioDecoderType AudioDecoderBroker::GetDecoderType() const {
+ return decoder_details_ ? decoder_details_->decoder_id
+ : media::AudioDecoderType::kBroker;
+}
+
bool AudioDecoderBroker::IsPlatformDecoder() const {
return decoder_details_ ? decoder_details_->is_platform_decoder : false;
}
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 6c811fd72a9..cafb1ac84ef 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,6 +41,7 @@ class CrossThreadAudioDecoderClient {
public:
struct DecoderDetails {
std::string display_name;
+ media::AudioDecoderType decoder_id;
bool is_platform_decoder;
bool needs_bitstream_conversion;
};
@@ -80,6 +81,7 @@ class MODULES_EXPORT AudioDecoderBroker : public media::AudioDecoder,
// AudioDecoder implementation.
std::string GetDisplayName() const override;
+ media::AudioDecoderType GetDecoderType() const override;
bool IsPlatformDecoder() const override;
void Initialize(const media::AudioDecoderConfig& config,
media::CdmContext* cdm_context,
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 a10395a9e41..15b079064c4 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
@@ -143,6 +143,12 @@ class FakeInterfaceFactory : public media::mojom::InterfaceFactory {
std::move(callback).Run(mojo::NullRemote(), base::nullopt,
mojo::NullRemote(), "CDM creation not supported");
}
+#if defined(OS_WIN)
+ void CreateMediaFoundationRenderer(
+ mojo::PendingReceiver<media::mojom::Renderer> receiver,
+ mojo::PendingReceiver<media::mojom::MediaFoundationRendererExtension>
+ renderer_extension_receiver) override {}
+#endif // defined(OS_WIN)
private:
media::MojoCdmServiceContext cdm_service_context_;
@@ -325,7 +331,7 @@ TEST_F(AudioDecoderBrokerTest, Decode_WithMojoDecoder) {
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted));
EXPECT_EQ(GetDisplayName(), "MojoAudioDecoder");
- // Using vorbis buffer here because its easy and the fake decoder generates
+ // Using vorbis buffer here because its easy and the fake decoder generates
// output regardless of the input details.
DecodeBuffer(media::ReadTestDataFile("vorbis-packet-0"));
DecodeBuffer(media::DecoderBuffer::CreateEOSBuffer());
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl
new file mode 100644
index 00000000000..994836026d3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+// NOTE: Keep this strucutre in sync with CopyConfig() defined in
+// audio_decoder.cc.
+
+dictionary AudioDecoderConfig {
+ // TODO(chcunningham): reference spec registry.
+ required DOMString codec;
+
+ // Rate of samples per second. 44100, 48000, etc.
+ required unsigned long sampleRate;
+
+ // 1, 2, etc.
+ required unsigned long numberOfChannels;
+
+ // Optional byte data required to initialize audio decoders such as Vorbis
+ // codebooks.
+ BufferSource description;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
index b093c5d5abd..1bbb97b7656 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
@@ -5,10 +5,10 @@
#include "base/run_loop.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.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/testing/dummy_page_holder.h"
@@ -70,36 +70,38 @@ DEFINE_TEXT_PROTO_FUZZER(
Persistent<AudioDecoder> audio_decoder = AudioDecoder::Create(
script_state, audio_decoder_init, IGNORE_EXCEPTION_FOR_TESTING);
- for (auto& invocation : proto.invocations()) {
- switch (invocation.Api_case()) {
- case wc_fuzzer::AudioDecoderApiInvocation::kConfigure:
- audio_decoder->configure(
- MakeAudioDecoderConfig(invocation.configure()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::AudioDecoderApiInvocation::kDecode:
- audio_decoder->decode(
- MakeEncodedAudioChunk(invocation.decode().chunk()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::AudioDecoderApiInvocation::kFlush: {
- // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
- // of the flush promise.
- audio_decoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
- break;
+ if (audio_decoder) {
+ for (auto& invocation : proto.invocations()) {
+ switch (invocation.Api_case()) {
+ case wc_fuzzer::AudioDecoderApiInvocation::kConfigure:
+ audio_decoder->configure(
+ MakeAudioDecoderConfig(invocation.configure()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::AudioDecoderApiInvocation::kDecode:
+ audio_decoder->decode(
+ MakeEncodedAudioChunk(invocation.decode().chunk()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::AudioDecoderApiInvocation::kFlush: {
+ // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
+ // of the flush promise.
+ audio_decoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ }
+ case wc_fuzzer::AudioDecoderApiInvocation::kReset:
+ audio_decoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::AudioDecoderApiInvocation::kClose:
+ audio_decoder->close(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::AudioDecoderApiInvocation::API_NOT_SET:
+ break;
}
- case wc_fuzzer::AudioDecoderApiInvocation::kReset:
- audio_decoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::AudioDecoderApiInvocation::kClose:
- audio_decoder->close(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::AudioDecoderApiInvocation::API_NOT_SET:
- break;
- }
- // Give other tasks a chance to run (e.g. calling our output callback).
- base::RunLoop().RunUntilIdle();
+ // Give other tasks a chance to run (e.g. calling our output callback).
+ base::RunLoop().RunUntilIdle();
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_support.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_support.idl
new file mode 100644
index 00000000000..cee3920becb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_support.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+dictionary AudioDecoderSupport {
+ boolean supported;
+ AudioDecoderConfig config;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
new file mode 100644
index 00000000000..d343dd60cb7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -0,0 +1,269 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/audio_encoder.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "media/audio/audio_opus_encoder.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/audio_timestamp_helper.h"
+#include "media/base/offloading_audio_encoder.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+
+namespace blink {
+
+// static
+const char* AudioEncoderTraits::GetNameForDevTools() {
+ return "AudioEncoder(WebCodecs)";
+}
+
+AudioEncoder* AudioEncoder::Create(ScriptState* script_state,
+ const AudioEncoderInit* init,
+ ExceptionState& exception_state) {
+ auto* result =
+ MakeGarbageCollected<AudioEncoder>(script_state, init, exception_state);
+ return exception_state.HadException() ? nullptr : result;
+}
+
+AudioEncoder::AudioEncoder(ScriptState* script_state,
+ const AudioEncoderInit* init,
+ ExceptionState& exception_state)
+ : Base(script_state, init, exception_state) {
+ UseCounter::Count(ExecutionContext::From(script_state),
+ WebFeature::kWebCodecs);
+}
+
+AudioEncoder::~AudioEncoder() = default;
+
+void AudioEncoder::ProcessConfigure(Request* request) {
+ DCHECK_NE(state_.AsEnum(), V8CodecState::Enum::kClosed);
+ DCHECK_EQ(request->type, Request::Type::kConfigure);
+ DCHECK(active_config_);
+ DCHECK_EQ(active_config_->codec, media::kCodecOpus);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ auto software_encoder = std::make_unique<media::AudioOpusEncoder>();
+ media_encoder_ = std::make_unique<media::OffloadingAudioEncoder>(
+ std::move(software_encoder));
+
+ auto output_cb = ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+ &AudioEncoder::CallOutputCallback, WrapCrossThreadWeakPersistent(this),
+ // We can't use |active_config_| from |this| because it can change by
+ // the time the callback is executed.
+ WrapCrossThreadPersistent(active_config_.Get()), reset_count_));
+
+ auto done_callback = [](AudioEncoder* self, uint32_t reset_count,
+ media::Status status) {
+ if (!self || self->reset_count_ != reset_count)
+ return;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
+ if (!status.is_ok()) {
+ self->HandleError(
+ self->logger_->MakeException("Encoding error.", status));
+ }
+ self->stall_request_processing_ = false;
+ self->ProcessRequests();
+ };
+
+ stall_request_processing_ = true;
+ produced_first_output_ = false;
+ media_encoder_->Initialize(
+ active_config_->options, std::move(output_cb),
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ done_callback, WrapCrossThreadWeakPersistent(this), reset_count_)));
+}
+
+void AudioEncoder::ProcessEncode(Request* request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, V8CodecState::Enum::kConfigured);
+ DCHECK(media_encoder_);
+ DCHECK_EQ(request->type, Request::Type::kEncode);
+ DCHECK_GT(requested_encodes_, 0);
+
+ auto* frame = request->frame.Release();
+ auto* buffer = frame->buffer();
+
+ auto done_callback = [](AudioEncoder* self, uint32_t reset_count,
+ media::Status status) {
+ if (!self || self->reset_count_ != reset_count)
+ return;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
+ if (!status.is_ok()) {
+ self->HandleError(
+ self->logger_->MakeException("Encoding error.", status));
+ }
+ self->ProcessRequests();
+ };
+
+ if (buffer->numberOfChannels() != uint8_t{active_config_->options.channels} ||
+ buffer->sampleRate() != active_config_->options.sample_rate) {
+ media::Status error(media::StatusCode::kEncoderFailedEncode);
+ error.WithData("channels", int{buffer->numberOfChannels()});
+ error.WithData("sampleRate", buffer->sampleRate());
+
+ HandleError(logger_->MakeException(
+ "Input audio buffer is incompatible with codec parameters", error));
+ frame->close();
+ return;
+ }
+
+ // Converting time at the beginning of the frame (aka timestamp) into
+ // time at the end of the frame (aka capture time) that is expected by
+ // media::AudioEncoder.
+ base::TimeTicks capture_time =
+ base::TimeTicks() +
+ base::TimeDelta::FromMicroseconds(frame->timestamp()) +
+ media::AudioTimestampHelper::FramesToTime(
+ buffer->length(), active_config_->options.sample_rate);
+ DCHECK(buffer);
+
+ // TODO(crbug.com/1168418): There are two reasons we need to copy |buffer|
+ // data here:
+ // 1. AudioBus data needs to be 16 bytes aligned and |buffer| data might not
+ // be aligned like that.
+ // 2. The encoder might need to access this data on a different thread, which
+ // is not allowed from blink point of view.
+ //
+ // If we could transfer AudioBuffer's data to another thread, we wouldn't need
+ // to copy it, if alignment happens to be right.
+ auto audio_bus =
+ media::AudioBus::Create(buffer->numberOfChannels(), buffer->length());
+ for (int channel = 0; channel < audio_bus->channels(); channel++) {
+ auto array = buffer->getChannelData(channel);
+ size_t byte_length = array->byteLength();
+ DCHECK_EQ(byte_length, audio_bus->frames() * sizeof(float));
+ memcpy(audio_bus->channel(channel), array->Data(), byte_length);
+ }
+
+ media_encoder_->Encode(
+ std::move(audio_bus), capture_time,
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ done_callback, WrapCrossThreadWeakPersistent(this), reset_count_)));
+
+ frame->close();
+}
+
+void AudioEncoder::ProcessReconfigure(Request* request) {
+ // Audio decoders don't currently support any meaningful reconfiguring
+}
+
+AudioEncoder::ParsedConfig* AudioEncoder::ParseConfig(
+ const AudioEncoderConfig* opts,
+ ExceptionState& exception_state) {
+ auto* result = MakeGarbageCollected<ParsedConfig>();
+ result->codec = opts->codec().Utf8() == "opus" ? media::kCodecOpus
+ : media::kUnknownAudioCodec;
+ result->options.channels = opts->numberOfChannels();
+
+ result->options.sample_rate = opts->sampleRate();
+ result->codec_string = opts->codec();
+ if (opts->hasBitrate()) {
+ if (!base::IsValueInRangeForNumericType<int>(opts->bitrate())) {
+ exception_state.ThrowTypeError("Invalid bitrate.");
+ return nullptr;
+ }
+ result->options.bitrate = static_cast<int>(opts->bitrate());
+ }
+
+ if (result->options.channels == 0) {
+ exception_state.ThrowTypeError("Invalid channel number.");
+ return nullptr;
+ }
+
+ if (result->options.sample_rate == 0) {
+ exception_state.ThrowTypeError("Invalid sample rate.");
+ return nullptr;
+ }
+ return result;
+}
+
+bool AudioEncoder::CanReconfigure(ParsedConfig& original_config,
+ ParsedConfig& new_config) {
+ return original_config.codec == new_config.codec &&
+ original_config.options.channels == new_config.options.channels &&
+ original_config.options.bitrate == new_config.options.bitrate &&
+ original_config.options.sample_rate == new_config.options.sample_rate;
+}
+
+AudioFrame* AudioEncoder::CloneFrame(AudioFrame* frame,
+ ExecutionContext* context) {
+ auto* init = AudioFrameInit::Create();
+ init->setTimestamp(frame->timestamp());
+
+ auto* buffer = frame->buffer();
+ if (!buffer)
+ return nullptr;
+
+ // Validata that buffer's data is consistent
+ for (auto channel = 0u; channel < buffer->numberOfChannels(); channel++) {
+ auto array = buffer->getChannelData(channel);
+ float* data = array->Data();
+ if (!data)
+ return nullptr;
+ if (array->length() != buffer->length())
+ return nullptr;
+ }
+
+ init->setBuffer(buffer);
+ return MakeGarbageCollected<AudioFrame>(init);
+}
+
+bool AudioEncoder::VerifyCodecSupport(ParsedConfig* config,
+ ExceptionState& exception_state) {
+ if (config->codec != media::kCodecOpus) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ "Unsupported codec type.");
+ return false;
+ }
+ return true;
+}
+
+void AudioEncoder::CallOutputCallback(
+ ParsedConfig* active_config,
+ uint32_t reset_count,
+ media::EncodedAudioBuffer encoded_buffer,
+ base::Optional<media::AudioEncoder::CodecDescription> codec_desc) {
+ if (!script_state_->ContextIsValid() || !output_callback_ ||
+ state_.AsEnum() != V8CodecState::Enum::kConfigured ||
+ reset_count != reset_count_)
+ return;
+
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EncodedAudioMetadata metadata;
+ metadata.timestamp = encoded_buffer.timestamp - base::TimeTicks();
+ auto deleter = [](void* data, size_t length, void*) {
+ delete[] static_cast<uint8_t*>(data);
+ };
+ ArrayBufferContents data(encoded_buffer.encoded_data.release(),
+ encoded_buffer.encoded_data_size, deleter);
+ auto* dom_array = MakeGarbageCollected<DOMArrayBuffer>(std::move(data));
+ auto* chunk = MakeGarbageCollected<EncodedAudioChunk>(metadata, dom_array);
+
+ AudioDecoderConfig* decoder_config = nullptr;
+ if (!produced_first_output_ || codec_desc.has_value()) {
+ decoder_config = MakeGarbageCollected<AudioDecoderConfig>();
+ decoder_config->setCodec(active_config->codec_string);
+ decoder_config->setSampleRate(active_config->options.sample_rate);
+ decoder_config->setNumberOfChannels(active_config->options.channels);
+ 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));
+ }
+ produced_first_output_ = true;
+ }
+
+ ScriptState::Scope scope(script_state_);
+ output_callback_->InvokeAndReportException(nullptr, chunk, decoder_config);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.h b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
new file mode 100644
index 00000000000..f7bae002ac4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
@@ -0,0 +1,98 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_ENCODER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_ENCODER_H_
+
+#include <memory>
+
+#include "media/base/audio_codecs.h"
+#include "media/base/audio_encoder.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_codec_state.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoder_base.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class ExceptionState;
+class AudioEncoderConfig;
+class AudioEncoderInit;
+
+class MODULES_EXPORT AudioEncoderTraits {
+ public:
+ struct ParsedConfig final : public GarbageCollected<ParsedConfig> {
+ media::AudioCodec codec = media::kUnknownAudioCodec;
+ media::AudioEncoder::Options options;
+ String codec_string;
+
+ void Trace(Visitor*) const {}
+ };
+
+ struct AudioEncoderEncodeOptions
+ : public GarbageCollected<AudioEncoderEncodeOptions> {
+ void Trace(Visitor*) const {}
+ };
+
+ using Init = AudioEncoderInit;
+ using Config = AudioEncoderConfig;
+ using InternalConfig = ParsedConfig;
+ using Frame = AudioFrame;
+ using EncodeOptions = AudioEncoderEncodeOptions;
+ using OutputChunk = EncodedAudioChunk;
+ using OutputCallback = V8EncodedAudioChunkOutputCallback;
+ using MediaEncoder = media::AudioEncoder;
+
+ // Can't be a virtual method, because it's used from base ctor.
+ static const char* GetNameForDevTools();
+};
+
+class MODULES_EXPORT AudioEncoder final
+ : public EncoderBase<AudioEncoderTraits> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static AudioEncoder* Create(ScriptState*,
+ const AudioEncoderInit*,
+ ExceptionState&);
+ AudioEncoder(ScriptState*, const AudioEncoderInit*, ExceptionState&);
+ ~AudioEncoder() override;
+
+ void encode(AudioFrame* frame, ExceptionState& exception_state) {
+ return Base::encode(frame, nullptr, exception_state);
+ }
+
+ private:
+ using Base = EncoderBase<AudioEncoderTraits>;
+ using ParsedConfig = AudioEncoderTraits::ParsedConfig;
+
+ void ProcessEncode(Request* request) override;
+ void ProcessConfigure(Request* request) override;
+ void ProcessReconfigure(Request* request) override;
+
+ ParsedConfig* ParseConfig(const AudioEncoderConfig* opts,
+ ExceptionState&) override;
+ bool VerifyCodecSupport(ParsedConfig*, ExceptionState&) override;
+ AudioFrame* CloneFrame(AudioFrame*, ExecutionContext*) override;
+
+ bool CanReconfigure(ParsedConfig& original_config,
+ ParsedConfig& new_config) override;
+
+ void CallOutputCallback(
+ ParsedConfig* active_config,
+ uint32_t reset_count,
+ media::EncodedAudioBuffer encoded_buffer,
+ base::Optional<media::AudioEncoder::CodecDescription> codec_desc);
+
+ bool produced_first_output_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_ENCODER_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl
new file mode 100644
index 00000000000..cfec86c32b9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl
@@ -0,0 +1,50 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+[
+ Exposed=(Window,DedicatedWorker),
+ RuntimeEnabled=WebCodecs,
+ ActiveScriptWrappable
+] interface AudioEncoder {
+ [CallWith=ScriptState, RaisesException, MeasureAs=WebCodecsAudioEncoder]
+ constructor(AudioEncoderInit init);
+
+ // The number of pending encode requests. This does not include requests
+ // that have been sent to the underlying codec.
+ readonly attribute long encodeQueueSize;
+
+ // Enqueues a control message to configure the audio encoder for encoding
+ // audio frames as described by config.
+ [RaisesException]
+ void configure(AudioEncoderConfig config);
+
+ // Enqueues a request to encode a frame.
+ // Results of the encoding (EncodedAudioChunk) are returned via
+ // the output callback provided in configure().
+ [RaisesException]
+ void encode(AudioFrame frame);
+
+
+ // Enqueues a request to produce outputs for all already encoded frames.
+ // Resolved after emitting outputs for all previously encoded frames.
+ [RaisesException]
+ Promise<void> flush();
+
+ // Discard all pending work and current encoder configuration.
+ //
+ // Output for earlier encoding requests will not be emitted.
+ // The next encoded frame will be a keyframe.
+ // Requires configure() to be call to set configuration once again.
+ [RaisesException]
+ void reset();
+
+ // Enqueues a request to shut down the encoder and free its resources.
+ [RaisesException]
+ void close();
+
+ // Which state the encoder is in, indicating which methods can be called.
+ readonly attribute CodecState state;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl
new file mode 100644
index 00000000000..5c255790ed2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+dictionary AudioEncoderConfig {
+ // TODO(chcunningham): reference spec registry.
+ required DOMString codec;
+
+ // Rate of samples per second. 44100, 48000, etc.
+ required unsigned long sampleRate;
+
+ // 1, 2, etc.
+ required unsigned short numberOfChannels;
+
+ required unsigned long long bitrate;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl
new file mode 100644
index 00000000000..cc6b93d1b43
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+dictionary AudioEncoderInit {
+ required EncodedAudioChunkOutputCallback output;
+ required WebCodecsErrorCallback error;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.cc
index 6987b60b297..d9ab76dd6be 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+
#include "media/base/audio_buffer.h"
#include "media/base/audio_bus.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
namespace blink {
@@ -25,23 +27,77 @@ AudioFrame::AudioFrame(scoped_refptr<media::AudioBuffer> buffer)
buffer_ = AudioBuffer::CreateUninitialized(
buffer->channel_count(), buffer->frame_count(), buffer->sample_rate());
- // Wrap blink buffer a media::AudioBus so we can interface with
- // media::AudioBuffer to copy the data out.
- auto media_bus_wrapper =
- media::AudioBus::CreateWrapper(buffer->channel_count());
- for (int i = 0; i < media_bus_wrapper->channels(); ++i) {
- DCHECK_EQ(buffer_->getChannelData(i)->byteLength(),
- buffer->frame_count() * sizeof(float));
- float* channel_data = buffer_->getChannelData(i)->Data();
- media_bus_wrapper->SetChannelData(i, channel_data);
- }
- media_bus_wrapper->set_frames(buffer->frame_count());
+ // AudioBuffer::CreateUninitialized() can fail. This can be the result of
+ // running out of memory, or having parameters that exceed some of WebAudio's
+ // limits. Crash here to prevent accessing uninitialized data below.
+ // TODO(crbug.com/1179079): Add upstream checks to prevent initializing
+ // |buffer_| with parameters outside of WebAudio's limits.
+ CHECK(buffer_);
- // Copy the frames.
+ auto converted_data =
+ media::AudioBus::Create(buffer->channel_count(), buffer->frame_count());
+
+ std::vector<float*> wrapped_channels(buffer_->numberOfChannels());
+ for (unsigned ch = 0; ch < buffer_->numberOfChannels(); ++ch)
+ wrapped_channels[ch] = buffer_->getChannelData(ch)->Data();
+
+ // Copy the frames, converting from |buffer|'s internal format to float.
// TODO(chcunningham): Avoid this copy by refactoring blink::AudioBuffer to
// ref a media::AudioBuffer and only copy for calls to copyToChannel().
- buffer->ReadFrames(media_bus_wrapper->frames(), 0 /* source_frame_offset */,
- 0 /* dest_frame_offset */, media_bus_wrapper.get());
+ buffer->ReadAllFrames(wrapped_channels);
+}
+
+std::unique_ptr<AudioFrameSerializationData>
+AudioFrame::GetSerializationData() {
+ DCHECK(buffer_);
+
+ // Copy buffer unaligned memory into media::AudioBus' aligned memory.
+ // TODO(https://crbug.com/1168418): reevaluate if this copy is necessary after
+ // our changes. E.g. If we can ever guarantee AudioBuffer's memory alignment,
+ // we could save this copy here, by using buffer_->GetSharedAudioBuffer() and
+ // wrapping it directly.
+ auto data_copy =
+ media::AudioBus::Create(buffer_->numberOfChannels(), buffer_->length());
+
+ for (int i = 0; i < data_copy->channels(); ++i) {
+ size_t byte_length = buffer_->getChannelData(i)->byteLength();
+ DCHECK_EQ(byte_length, data_copy->frames() * sizeof(float));
+ float* buffer_data_src = buffer_->getChannelData(i)->Data();
+ memcpy(data_copy->channel(i), buffer_data_src, byte_length);
+ }
+
+ return AudioFrameSerializationData::Wrap(
+ std::move(data_copy), buffer_->sampleRate(),
+ base::TimeDelta::FromMicroseconds(timestamp_));
+}
+
+AudioFrame::AudioFrame(std::unique_ptr<AudioFrameSerializationData> data)
+ : timestamp_(data->timestamp().InMicroseconds()) {
+ media::AudioBus* data_bus = data->data();
+
+ buffer_ = AudioBuffer::CreateUninitialized(
+ data_bus->channels(), data_bus->frames(), data->sample_rate());
+
+ // AudioBuffer::CreateUninitialized() can fail. This can be the result of
+ // running out of memory, or having parameters that exceed some of WebAudio's
+ // limits. Crash here to prevent accessing uninitialized data below.
+ // TODO(crbug.com/1179079): Add upstream checks to prevent initializing
+ // |buffer_| with parameters outside of WebAudio's limits.
+ CHECK(buffer_);
+
+ // Copy the frames.
+ // TODO(https://crbug.com/1168418): Avoid this copy by refactoring
+ // blink::AudioBuffer accept a serializable audio data backing object.
+ DCHECK_EQ(static_cast<int>(buffer_->numberOfChannels()),
+ data_bus->channels());
+ DCHECK_EQ(static_cast<int>(buffer_->length()), data_bus->frames());
+
+ for (int i = 0; i < data_bus->channels(); ++i) {
+ size_t byte_length = buffer_->getChannelData(i)->byteLength();
+ DCHECK_EQ(byte_length, data_bus->frames() * sizeof(float));
+ float* buffer_data_dest = buffer_->getChannelData(i)->Data();
+ memcpy(buffer_data_dest, data_bus->channel(i), byte_length);
+ }
}
void AudioFrame::close() {
@@ -51,6 +107,7 @@ void AudioFrame::close() {
uint64_t AudioFrame::timestamp() const {
return timestamp_;
}
+
AudioBuffer* AudioFrame::buffer() const {
return buffer_;
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.h b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.h
index 82c9cd3eb44..ab27cddaf85 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame.h
@@ -14,6 +14,7 @@ namespace blink {
class ExceptionState;
class AudioFrameInit;
+class AudioFrameSerializationData;
class MODULES_EXPORT AudioFrame final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -23,6 +24,7 @@ class MODULES_EXPORT AudioFrame final : public ScriptWrappable {
// Internal constructor for creating from media::AudioDecoder output.
explicit AudioFrame(scoped_refptr<media::AudioBuffer>);
+ explicit AudioFrame(std::unique_ptr<AudioFrameSerializationData> data);
// audio_frame.idl implementation.
explicit AudioFrame(AudioFrameInit*);
@@ -30,6 +32,9 @@ class MODULES_EXPORT AudioFrame final : public ScriptWrappable {
uint64_t timestamp() const;
AudioBuffer* buffer() const;
+ // Returns audio data that will outlive |this| being closed() or destroyed.
+ std::unique_ptr<AudioFrameSerializationData> GetSerializationData();
+
// GarbageCollected override.
void Trace(Visitor*) const override;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl
index 20791eed4ed..8af56fc1fe4 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl
@@ -5,6 +5,6 @@
// https://github.com/WICG/web-codecs
dictionary AudioFrameInit {
- unsigned long long timestamp; // microseconds
- AudioBuffer buffer;
+ required unsigned long long timestamp; // microseconds
+ required AudioBuffer buffer;
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.cc
new file mode 100644
index 00000000000..d0ec790661e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
+
+namespace blink {
+
+namespace {
+class BasicAudioFrameSerializationData final
+ : public AudioFrameSerializationData {
+ public:
+ BasicAudioFrameSerializationData(std::unique_ptr<media::AudioBus> data,
+ int sample_rate,
+ base::TimeDelta timestamp)
+ : AudioFrameSerializationData(sample_rate, timestamp),
+ data_(std::move(data)) {}
+ ~BasicAudioFrameSerializationData() override = default;
+
+ media::AudioBus* data() override { return data_.get(); }
+
+ private:
+ std::unique_ptr<media::AudioBus> data_;
+};
+} // namespace
+
+AudioFrameSerializationData::AudioFrameSerializationData(
+ int sample_rate,
+ base::TimeDelta timestamp)
+ : sample_rate_(sample_rate), timestamp_(timestamp) {}
+
+// static
+std::unique_ptr<AudioFrameSerializationData> AudioFrameSerializationData::Wrap(
+ std::unique_ptr<media::AudioBus> data,
+ int sample_rate,
+ base::TimeDelta timestamp) {
+ return std::make_unique<BasicAudioFrameSerializationData>(
+ std::move(data), sample_rate, timestamp);
+}
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h
new file mode 100644
index 00000000000..2f33c1dbe33
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_SERIALIZATION_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_SERIALIZATION_DATA_H_
+
+#include "base/time/time.h"
+#include "media/base/audio_bus.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+// Wrapper that contains all the necessary information to recreate an
+// AudioFrame. It abstracts how audio data is actually backed, to simplify
+// lifetime guarantees when jumping threads.
+// TODO(https://crbug.com/1168418): add actual serialization support, to allow
+// the use of AudioFrames in workers.
+class MODULES_EXPORT AudioFrameSerializationData {
+ public:
+ virtual ~AudioFrameSerializationData() = default;
+
+ AudioFrameSerializationData(const AudioFrameSerializationData&) = delete;
+ AudioFrameSerializationData& operator=(const AudioFrameSerializationData&) =
+ delete;
+
+ // Helper function that creates a simple media::AudioBus backed wrapper.
+ static std::unique_ptr<AudioFrameSerializationData> Wrap(
+ std::unique_ptr<media::AudioBus> data,
+ int sample_rate,
+ base::TimeDelta timestamp);
+
+ virtual media::AudioBus* data() = 0;
+
+ int sample_rate() const { return sample_rate_; }
+
+ base::TimeDelta timestamp() const { return timestamp_; }
+
+ protected:
+ AudioFrameSerializationData(int sample_rate, base::TimeDelta timestamp);
+
+ private:
+ int sample_rate_;
+ base::TimeDelta timestamp_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_SERIALIZATION_DATA_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc
new file mode 100644
index 00000000000..2ff6a3799e3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc
@@ -0,0 +1,158 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "media/base/test_helpers.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/bindings/modules/v8/v8_audio_frame_init.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace blink {
+
+namespace {
+// Default test values
+constexpr uint64_t kTimestampInMicroSeconds = 1234;
+constexpr int kChannels = 2;
+constexpr int kFrames = 20;
+constexpr int kSampleRate = 8000;
+} // namespace
+
+class AudioFrameTest : public testing::Test {
+ protected:
+ AudioBuffer* CreateDefaultAudioBuffer() {
+ auto* audio_buffer =
+ AudioBuffer::CreateUninitialized(kChannels, kFrames, kSampleRate);
+ for (int ch = 0; ch < kChannels; ++ch) {
+ float* buffer_data = audio_buffer->getChannelData(ch)->Data();
+ for (int i = 0; i < kFrames; ++i) {
+ buffer_data[i] = static_cast<float>((i + ch * kFrames) / 1000.0f);
+ }
+ }
+ return audio_buffer;
+ }
+
+ AudioFrameInit* CreateDefaultAudioFrameInit(AudioBuffer* buffer) {
+ auto* audio_frame_init = AudioFrameInit::Create();
+ audio_frame_init->setBuffer(buffer);
+ audio_frame_init->setTimestamp(kTimestampInMicroSeconds);
+ return audio_frame_init;
+ }
+};
+
+TEST_F(AudioFrameTest, ConstructFromMediaBuffer) {
+ const media::ChannelLayout channel_layout =
+ media::ChannelLayout::CHANNEL_LAYOUT_STEREO;
+ const int channels = ChannelLayoutToChannelCount(channel_layout);
+ constexpr base::TimeDelta timestamp =
+ base::TimeDelta::FromMicroseconds(kTimestampInMicroSeconds);
+ constexpr int kStart = 1;
+ constexpr int kIncrement = 1;
+ scoped_refptr<media::AudioBuffer> media_buffer =
+ media::MakeAudioBuffer<int16_t>(media::SampleFormat::kSampleFormatS16,
+ channel_layout, channels, kSampleRate,
+ kStart, kIncrement, kFrames, timestamp);
+
+ auto* frame = MakeGarbageCollected<AudioFrame>(media_buffer);
+
+ EXPECT_EQ(frame->timestamp(), kTimestampInMicroSeconds);
+
+ EXPECT_TRUE(frame->buffer());
+ EXPECT_EQ(frame->buffer()->numberOfChannels(),
+ static_cast<unsigned>(channels));
+ EXPECT_EQ(frame->buffer()->length(), static_cast<uint32_t>(kFrames));
+
+ // The buffer's internal int16_t value should have been converted to float32.
+ constexpr float kFloatIncrement =
+ static_cast<float>(kIncrement) / std::numeric_limits<int16_t>::max();
+ constexpr float kFloatStart =
+ static_cast<float>(kStart) / std::numeric_limits<int16_t>::max();
+
+ // Verify the data was properly converted.
+ for (int ch = 0; ch < channels; ++ch) {
+ float* internal_channel = frame->buffer()->getChannelData(ch)->Data();
+ float start_value = kFloatStart + ch * kFloatIncrement * kFrames;
+ for (int i = 0; i < kFrames; ++i) {
+ float expected_value = start_value + i * kFloatIncrement;
+ ASSERT_FLOAT_EQ(expected_value, internal_channel[i])
+ << "i=" << i << ", ch=" << ch;
+ }
+ }
+}
+
+TEST_F(AudioFrameTest, ConstructFromAudioFrameInit) {
+ auto* audio_buffer = CreateDefaultAudioBuffer();
+
+ auto* audio_frame_init = CreateDefaultAudioFrameInit(audio_buffer);
+
+ auto* frame = MakeGarbageCollected<AudioFrame>(audio_frame_init);
+
+ EXPECT_EQ(frame->timestamp(), kTimestampInMicroSeconds);
+ EXPECT_EQ(frame->buffer(), audio_buffer);
+}
+
+TEST_F(AudioFrameTest, VerifySerializationData) {
+ auto* audio_buffer = CreateDefaultAudioBuffer();
+
+ // Create a frame from the audio buffer.
+ auto* audio_frame_init = CreateDefaultAudioFrameInit(audio_buffer);
+ auto* frame = MakeGarbageCollected<AudioFrame>(audio_frame_init);
+
+ // Serialize the data from the frame.
+ std::unique_ptr<AudioFrameSerializationData> data =
+ frame->GetSerializationData();
+
+ // Make sure attributes match.
+ EXPECT_EQ(data->timestamp(),
+ base::TimeDelta::FromMicroseconds(kTimestampInMicroSeconds));
+ EXPECT_EQ(data->sample_rate(), kSampleRate);
+ EXPECT_EQ(data->data()->channels(), kChannels);
+ EXPECT_EQ(data->data()->frames(), kFrames);
+
+ // Make sure the data matches.
+ for (int ch = 0; ch < kChannels; ++ch) {
+ float* buffer_data = audio_buffer->getChannelData(ch)->Data();
+ float* serialized_data = data->data()->channel(ch);
+ for (int i = 0; i < kFrames; ++i) {
+ ASSERT_FLOAT_EQ(buffer_data[i], serialized_data[i])
+ << "i=" << i << ", ch=" << ch;
+ }
+ }
+}
+
+TEST_F(AudioFrameTest, ConstructFromSerializationData) {
+ // Create a default frame.
+ auto* audio_buffer = CreateDefaultAudioBuffer();
+ auto* audio_frame_init = CreateDefaultAudioFrameInit(audio_buffer);
+ auto* original_frame = MakeGarbageCollected<AudioFrame>(audio_frame_init);
+
+ // Get a copy of the serialization data, and create a new frame from it.
+ std::unique_ptr<AudioFrameSerializationData> data =
+ original_frame->GetSerializationData();
+
+ auto* new_frame = MakeGarbageCollected<AudioFrame>(std::move(data));
+
+ // Make sure attributes match.
+ EXPECT_EQ(original_frame->timestamp(), new_frame->timestamp());
+ EXPECT_EQ(original_frame->buffer()->sampleRate(),
+ new_frame->buffer()->sampleRate());
+ EXPECT_EQ(original_frame->buffer()->numberOfChannels(),
+ new_frame->buffer()->numberOfChannels());
+ EXPECT_EQ(original_frame->buffer()->length(), new_frame->buffer()->length());
+
+ // Make sure the data matches.
+ for (int ch = 0; ch < kChannels; ++ch) {
+ float* orig_data = original_frame->buffer()->getChannelData(ch)->Data();
+ float* new_data = new_frame->buffer()->getChannelData(ch)->Data();
+ for (int i = 0; i < kFrames; ++i) {
+ ASSERT_FLOAT_EQ(orig_data[i], new_data[i]) << "i=" << i << ", ch=" << ch;
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl
new file mode 100644
index 00000000000..2ace0bf60f3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+enum AvcBitstreamFormat {
+ "annexb",
+ "avc",
+};
+
+dictionary AvcEncoderConfig {
+ AvcBitstreamFormat format = "avc";
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.cc b/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.cc
new file mode 100644
index 00000000000..638a24ca8af
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.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/webcodecs/codec_logger.h"
+
+#include <string>
+
+#include "media/base/media_util.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/inspector/inspector_media_context_impl.h"
+
+namespace blink {
+
+CodecLogger::CodecLogger(
+ ExecutionContext* context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(context);
+
+ // Owners of |this| should be ExecutionLifeCycleObservers, and should call
+ // Neuter() if |context| is destroyed. The MediaInspectorContextImpl must
+ // outlive |parent_media_log_|. If |context| is already destroyed, owners
+ // might never call Neuter(), and MediaInspectorContextImpl* could be garbage
+ // collected before |parent_media_log_| is destroyed.
+ if (!context->IsContextDestroyed()) {
+ parent_media_log_ = Platform::Current()->GetMediaLog(
+ MediaInspectorContextImpl::From(*context), task_runner);
+ }
+
+ // NullMediaLog silently and safely does nothing.
+ if (!parent_media_log_)
+ parent_media_log_ = std::make_unique<media::NullMediaLog>();
+
+ // This allows us to destroy |parent_media_log_| and stop logging,
+ // without causing problems to |media_log_| users.
+ media_log_ = parent_media_log_->Clone();
+}
+
+CodecLogger::CodecLogger()
+ : parent_media_log_(std::make_unique<media::NullMediaLog>()),
+ media_log_(parent_media_log_->Clone()) {}
+
+DOMException* CodecLogger::MakeException(std::string error_msg,
+ media::Status status) {
+ media_log_->NotifyError(status);
+
+ return MakeGarbageCollected<DOMException>(DOMExceptionCode::kOperationError,
+ error_msg.c_str());
+}
+
+DOMException* CodecLogger::MakeException(std::string error_msg,
+ media::StatusCode code,
+ const base::Location& location) {
+ return MakeException(error_msg, media::Status(code, error_msg, location));
+}
+
+CodecLogger::~CodecLogger() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void CodecLogger::Neuter() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ parent_media_log_ = nullptr;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.h b/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.h
new file mode 100644
index 00000000000..6a19b89924d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/codec_logger.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_LOGGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_LOGGER_H_
+
+#include <memory>
+
+#include "media/base/media_log.h"
+#include "media/base/status.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace blink {
+
+class ExecutionContext;
+
+// Simple wrapper around MediaLog instances, to manage the lifetime safety of
+// said MediaLogs. |parent_media_log_| must be destroyed and created on the
+// main thread (or the worker thread if we are in a worker context).
+// |media_log_| is a clone of |parent_media_log_| which can be safely passed to
+// any thread. If the parent log is destroyed, |media_log_| will safely and
+// silently stop logging.
+// Note: Owners of this class should be ExecutionLifeCycleObservers, and should
+// call Neuter() if the ExecutionContext passed to the constructor is destroyed.
+class MODULES_EXPORT CodecLogger final {
+ public:
+ // Creates a CodecLogger backed by a NullMediaLog, which does nothing.
+ CodecLogger();
+
+ // Attempts to create CodecLogger backed by a BatchingMediaLog. Falls back to
+ // a NullMediaLog on failure.
+ CodecLogger(ExecutionContext*,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ ~CodecLogger();
+
+ // Creates an OperationError DOMException with the given |error_msg|, and logs
+ // the given |status| in |media_log_|.
+ // Since |status| can come from platform codecs, its contents won't be
+ // surfaced to JS, since we could leak important information.
+ DOMException* MakeException(std::string error_msg, media::Status status);
+
+ // Convenience wrapper for MakeException(), where |error_msg| is shared for
+ // both the exception message and the status message.
+ DOMException* MakeException(
+ std::string error_msg,
+ media::StatusCode code,
+ const base::Location& location = base::Location::Current());
+
+ // Safe to use on any thread. |this| should still outlive users of log().
+ media::MediaLog* log() { return media_log_.get(); }
+
+ // Destroys |parent_media_log_|, which makes |media_log_| silently stop
+ // logging in a thread safe way.
+ // Must be called if the ExecutionContext passed into the constructor is
+ // destroyed.
+ void Neuter();
+
+ private:
+ // |parent_media_log_| must be destroyed if ever the ExecutionContext is
+ // destroyed, since the blink::MediaInspectorContext* pointer given to
+ // InspectorMediaEventHandler might no longer be valid.
+ // |parent_media_log_| should not be used directly. Use |media_log_| instead.
+ std::unique_ptr<media::MediaLog> parent_media_log_;
+
+ // We might destroy |parent_media_log_| at any point, so keep a clone which
+ // can be safely accessed, and whose raw pointer can be given callbacks.
+ std::unique_ptr<media::MediaLog> media_log_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_LOGGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl
new file mode 100644
index 00000000000..cb43732e632
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+enum ColorSpaceMatrixID {
+ "RGB",
+ "BT709",
+ "FCC",
+ "BT470BG",
+ "SMPTE170M",
+ "SMPTE240M",
+ "YCOCG",
+ "BT2020_NCL",
+ "BT2020_CL",
+ "YDZDX",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/color_space_primary_id.idl b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_primary_id.idl
new file mode 100644
index 00000000000..68ef2e9ed28
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_primary_id.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/web-codecs
+
+enum ColorSpacePrimaryID {
+ "BT709",
+ "BT470M",
+ "BT470BG",
+ "SMPTE170M",
+ "SMPTE240M",
+ "FILM",
+ "BT2020",
+ "SMPTEST428_1",
+ "SMPTEST431_2",
+ "SMPTEST432_1",
+ "EBU_3213_E",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/color_space_range_id.idl b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_range_id.idl
new file mode 100644
index 00000000000..aa29539af67
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_range_id.idl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+enum ColorSpaceRangeID {
+ // Limited Rec.709 color range.
+ "LIMITED",
+
+ // Full RGB color range.
+ "FULL",
+
+ // Range is defined by TransferID/MatrixID.
+ "DERIVED",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/color_space_transfer_id.idl b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_transfer_id.idl
new file mode 100644
index 00000000000..2351ee27181
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/color_space_transfer_id.idl
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+enum ColorSpaceTransferID {
+ "BT709",
+ "GAMMA22",
+ "GAMMA28",
+ "SMPTE170M",
+ "SMPTE240M",
+ "LINEAR",
+ "LOG",
+ "LOG_SQRT",
+ "IEC61966_2_4",
+ "BT1361_ECG",
+ "IEC61966_2_1",
+ "BT2020_10",
+ "BT2020_12",
+ "SMPTEST2084",
+ "SMPTEST428_1",
+};
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 400c0fd80b8..3906b5430d0 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -11,20 +11,19 @@
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
-#include "media/base/media_util.h"
#include "media/media_buildflags.h"
#include "media/video/gpu_video_accelerator_factories.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/v8_audio_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.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/inspector/inspector_media_context_impl.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_decoder.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
@@ -73,20 +72,15 @@ DecoderTemplate<Traits>::DecoderTemplate(ScriptState* script_state,
// TODO(crbug.com/1151005): Use a real MediaLog in worker contexts too.
if (IsMainThread()) {
- parent_media_log_ = Platform::Current()->GetMediaLog(
- MediaInspectorContextImpl::From(*context),
- context->GetTaskRunner(TaskType::kInternalMedia));
+ logger_ = std::make_unique<CodecLogger>(
+ context, context->GetTaskRunner(TaskType::kInternalMedia));
+ } else {
+ // This will create a logger backed by a NullMediaLog, which does nothing.
+ logger_ = std::make_unique<CodecLogger>();
}
- if (!parent_media_log_)
- parent_media_log_ = std::make_unique<media::NullMediaLog>();
-
- // This allows us to destroy |parent_media_log_| and stop logging,
- // without causing problems to |media_log_| users.
- media_log_ = parent_media_log_->Clone();
-
- media_log_->SetProperty<media::MediaLogProperty::kFrameUrl>(
- GetExecutionContext()->Url().GetString().Ascii());
+ logger_->log()->SetProperty<media::MediaLogProperty::kFrameUrl>(
+ context->Url().GetString().Ascii());
output_cb_ = init->output();
error_cb_ = init->error();
@@ -123,6 +117,15 @@ bool DecoderTemplate<Traits>::IsClosed() {
}
template <typename Traits>
+HardwarePreference DecoderTemplate<Traits>::GetHardwarePreference(
+ const ConfigType&) {
+ return HardwarePreference::kAllow;
+}
+
+template <typename Traits>
+void DecoderTemplate<Traits>::SetHardwarePreference(HardwarePreference) {}
+
+template <typename Traits>
void DecoderTemplate<Traits>::configure(const ConfigType* config,
ExceptionState& exception_state) {
DVLOG(1) << __func__;
@@ -153,6 +156,7 @@ void DecoderTemplate<Traits>::configure(const ConfigType* config,
request->type = Request::Type::kConfigure;
request->media_config = std::move(media_config);
request->reset_generation = reset_generation_;
+ request->hw_pref = GetHardwarePreference(*config);
requests_.push_back(request);
ProcessRequests();
}
@@ -173,9 +177,9 @@ void DecoderTemplate<Traits>::decode(const InputType* chunk,
auto status_or_buffer = MakeDecoderBuffer(*chunk);
if (status_or_buffer.has_value()) {
- request->decoder_buffer = std::move(status_or_buffer.value());
+ request->decoder_buffer = std::move(status_or_buffer).value();
} else {
- request->status = std::move(status_or_buffer.error());
+ request->status = std::move(status_or_buffer).error();
}
requests_.push_back(request);
@@ -273,11 +277,11 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) {
if (!decoder_) {
decoder_ = Traits::CreateDecoder(*ExecutionContext::From(script_state_),
- gpu_factories_, media_log_.get());
+ gpu_factories_, logger_->log());
if (!decoder_) {
- HandleError("Configuration error",
- media::Status(media::StatusCode::kDecoderCreationFailed,
- "Could not create decoder."));
+ Shutdown(
+ logger_->MakeException("Internal error: Could not create decoder.",
+ media::StatusCode::kDecoderCreationFailed));
return false;
}
@@ -286,6 +290,9 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) {
// which can happen if InitializeDecoder() calls it synchronously.
pending_request_ = request;
initializing_sync_ = true;
+
+ SetHardwarePreference(pending_request_->hw_pref);
+
Traits::InitializeDecoder(
*decoder_, *pending_request_->media_config,
WTF::Bind(&DecoderTemplate::OnInitializeDone, WrapWeakPersistent(this)),
@@ -318,10 +325,9 @@ bool DecoderTemplate<Traits>::ProcessDecodeRequest(Request* request) {
DCHECK_GT(num_pending_decodes_, 0);
if (!decoder_) {
- HandleError(
- "Decoding error",
- media::Status(media::StatusCode::kDecoderInitializeNeverCompleted,
- "No decoder found."));
+ Shutdown(logger_->MakeException(
+ "Decoding error: no decoder found.",
+ media::StatusCode::kDecoderInitializeNeverCompleted));
return false;
}
@@ -333,13 +339,13 @@ bool DecoderTemplate<Traits>::ProcessDecodeRequest(Request* request) {
// The request may be invalid, if so report that now.
if (!request->decoder_buffer || request->decoder_buffer->data_size() == 0) {
- media::Status error =
- !request->status.is_ok()
- ? request->status
- : media::Status(media::StatusCode::kDecoderFailedDecode,
- "Null or empty decoder buffer.");
+ if (request->status.is_ok()) {
+ Shutdown(logger_->MakeException("Null or empty decoder buffer.",
+ media::StatusCode::kDecoderFailedDecode));
+ } else {
+ Shutdown(logger_->MakeException("Decoder error.", request->status));
+ }
- HandleError("Decoding error", error);
return false;
}
@@ -403,28 +409,10 @@ bool DecoderTemplate<Traits>::ProcessResetRequest(Request* request) {
}
template <typename Traits>
-void DecoderTemplate<Traits>::HandleError(std::string context,
- media::Status status) {
- DVLOG(1) << __func__;
- if (IsClosed())
- return;
-
- media_log_->NotifyError(status);
-
- std::string message =
- context + (status.message().empty() ? "." : ": " + status.message());
-
- // We could have different DOMExceptionCodes, but for the moment, all of our
- // exceptions seem appropriate as operation errors.
- auto* ex = MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kOperationError, message.c_str());
- Shutdown(ex);
-}
-
-template <typename Traits>
void DecoderTemplate<Traits>::Shutdown(DOMException* exception) {
DVLOG(3) << __func__;
- DCHECK(!IsClosed());
+ if (IsClosed())
+ return;
// Abort pending work (otherwise it will never complete)
if (pending_request_) {
@@ -448,6 +436,9 @@ void DecoderTemplate<Traits>::Shutdown(DOMException* exception) {
output_cb_.Release();
error_cb_.Release();
+ // Prevent any further logging from being reported.
+ logger_->Neuter();
+
// Clear decoding and JS-visible queue state.
decoder_.reset();
pending_decodes_.clear();
@@ -490,10 +481,14 @@ void DecoderTemplate<Traits>::OnConfigureFlushDone(media::Status status) {
DCHECK_EQ(pending_request_->type, Request::Type::kConfigure);
if (!status.is_ok()) {
- HandleError("Configuration error", status);
+ Shutdown(logger_->MakeException(
+ "Internal error: failed to flush out frames from previous config.",
+ status));
return;
}
+ SetHardwarePreference(pending_request_->hw_pref);
+
// Processing continues in OnInitializeDone().
Traits::InitializeDecoder(
*decoder_, *pending_request_->media_config,
@@ -512,12 +507,18 @@ void DecoderTemplate<Traits>::OnInitializeDone(media::Status status) {
DCHECK_EQ(pending_request_->type, Request::Type::kConfigure);
if (!status.is_ok()) {
- HandleError("Decoder initialization error", status);
+ std::string error_message = "Decoder initialization error.";
+ if (status.code() == media::StatusCode::kDecoderUnsupportedConfig) {
+ error_message =
+ "Unsupported configuration. Check isConfigSupported() prior to "
+ "calling configure().";
+ }
+ Shutdown(logger_->MakeException(error_message, status));
return;
}
Traits::UpdateDecoderLog(*decoder_, *pending_request_->media_config,
- media_log_.get());
+ logger_->log());
pending_request_.Release();
@@ -532,7 +533,7 @@ void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id, media::Status status) {
return;
if (!status.is_ok() && status.code() != media::StatusCode::kAborted) {
- HandleError("Decoding error", status);
+ Shutdown(logger_->MakeException("Decoding error.", status));
return;
}
@@ -552,7 +553,7 @@ void DecoderTemplate<Traits>::OnFlushDone(media::Status status) {
DCHECK_EQ(pending_request_->type, Request::Type::kFlush);
if (!status.is_ok()) {
- HandleError("Flushing error", status);
+ Shutdown(logger_->MakeException("Flushing error.", status));
return;
}
@@ -585,8 +586,19 @@ void DecoderTemplate<Traits>::OnOutput(uint32_t reset_generation,
if (state_.AsEnum() != V8CodecState::Enum::kConfigured)
return;
+ auto* context = GetExecutionContext();
+ if (!context)
+ return;
+
output_cb_->InvokeAndReportException(
- nullptr, MakeGarbageCollected<OutputType>(output));
+ nullptr, Traits::MakeOutput(std::move(output), context));
+}
+
+template <typename Traits>
+void DecoderTemplate<Traits>::ContextDestroyed() {
+ state_ = V8CodecState(V8CodecState::Enum::kClosed);
+ logger_->Neuter();
+ decoder_.reset();
}
template <typename Traits>
@@ -602,11 +614,6 @@ void DecoderTemplate<Traits>::Trace(Visitor* visitor) const {
}
template <typename Traits>
-void DecoderTemplate<Traits>::ContextDestroyed() {
- parent_media_log_ = nullptr;
-}
-
-template <typename Traits>
bool DecoderTemplate<Traits>::HasPendingActivity() const {
return pending_request_ || !requests_.IsEmpty();
}
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 c760c58a5ec..d12a2d5a0c5 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h
@@ -15,11 +15,13 @@
#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_codec_state.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
+#include "third_party/blink/renderer/modules/webcodecs/codec_logger.h"
+#include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -72,6 +74,18 @@ class MODULES_EXPORT DecoderTemplate
MediaConfigType* out_media_config,
String* out_console_message) = 0;
+ // Gets the AccelerationPreference from a config.
+ // If derived classes do not override this, this will default to kAllow.
+ virtual HardwarePreference GetHardwarePreference(const ConfigType& config);
+
+ // Sets the HardwarePreference on the |decoder_|.
+ // The default implementation does nothing and must be overridden by derived
+ // classes if needed.
+ // Decoder
+ virtual void SetHardwarePreference(HardwarePreference preference);
+
+ MediaDecoderType* decoder() { return decoder_.get(); }
+
// Convert a chunk to a DecoderBuffer. You can assume that the last
// configuration sent to MakeMediaConfig() is the active configuration for
// |chunk|. If there is an error in the conversion process, the resulting
@@ -95,6 +109,7 @@ class MODULES_EXPORT DecoderTemplate
// For kConfigure Requests.
std::unique_ptr<MediaConfigType> media_config;
+ HardwarePreference hw_pref = HardwarePreference::kAllow;
// For kDecode Requests.
scoped_refptr<media::DecoderBuffer> decoder_buffer;
@@ -115,7 +130,6 @@ class MODULES_EXPORT DecoderTemplate
bool ProcessDecodeRequest(Request* request);
bool ProcessFlushRequest(Request* request);
bool ProcessResetRequest(Request* request);
- void HandleError(std::string context, media::Status);
void ResetAlgorithm();
void Shutdown(DOMException* ex = nullptr);
@@ -147,15 +161,7 @@ class MODULES_EXPORT DecoderTemplate
// Could be a configure, flush, or reset. Decodes go in |pending_decodes_|.
Member<Request> pending_request_;
- // |parent_media_log_| must be destroyed if ever the ExecutionContext is
- // destroyed, since the blink::MediaInspectorContext* pointer given to
- // InspectorMediaEventHandler might no longer be valid.
- // |parent_media_log_| should not be used directly. Use |media_log_| instead.
- std::unique_ptr<media::MediaLog> parent_media_log_;
-
- // We might destroy |parent_media_log_| at any point, so keep a clone which
- // can be safely accessed, and whose raw pointer can be given to |decoder_|.
- std::unique_ptr<media::MediaLog> media_log_;
+ std::unique_ptr<CodecLogger> logger_;
media::GpuVideoAcceleratorFactories* gpu_factories_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl
index 54f3cc20829..003a6f17688 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl
@@ -5,7 +5,7 @@
// https://github.com/WICG/web-codecs
dictionary EncodedAudioChunkInit {
- EncodedVideoChunkType type;
- unsigned long long timestamp; // microseconds
- BufferSource data;
+ required EncodedVideoChunkType type;
+ required unsigned long long timestamp; // microseconds
+ required BufferSource data;
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl
new file mode 100644
index 00000000000..719d4db3f73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+[RuntimeEnabled=WebCodecs]
+callback EncodedAudioChunkOutputCallback =
+ void(EncodedAudioChunk output, optional AudioDecoderConfig decoder_config);
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_config.idl
deleted file mode 100644
index f3b1b26f8c7..00000000000
--- a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_audio_config.idl
+++ /dev/null
@@ -1,20 +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.
-
-// https://github.com/WICG/web-codecs
-
-dictionary EncodedAudioConfig {
- // TODO(chcunningham): reference spec registry.
- required DOMString codec;
-
- // Rate of samples per second. 44100, 48000, etc.
- required unsigned long sampleRate;
-
- // 1, 2, etc.
- required unsigned long numberOfChannels;
-
- // Optional byte data required to initialize audio decoders such as Vorbis
- // codebooks.
- BufferSource description;
-};
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 8b93d7fa359..177664c5e77 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,9 +17,8 @@ EncodedVideoChunk* EncodedVideoChunk::Create(EncodedVideoChunkInit* init) {
EncodedVideoMetadata metadata;
metadata.timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
metadata.key_frame = (init->type() == "key");
- if (init->hasDurationNonNull()) {
- metadata.duration =
- base::TimeDelta::FromMicroseconds(init->durationNonNull());
+ if (init->hasDuration()) {
+ metadata.duration = base::TimeDelta::FromMicroseconds(init->duration());
}
DOMArrayPiece piece(init->data());
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl
index 8739c1e25b7..986d321943b 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl
@@ -5,8 +5,8 @@
// https://github.com/WICG/web-codecs
dictionary EncodedVideoChunkInit {
- EncodedVideoChunkType type;
- unsigned long long timestamp; // microseconds
- unsigned long long? duration; // microseconds
- BufferSource data;
+ required EncodedVideoChunkType type;
+ required unsigned long long timestamp; // microseconds
+ unsigned long long duration; // microseconds
+ required BufferSource data;
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
new file mode 100644
index 00000000000..8fddca44ae6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -0,0 +1,331 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/encoder_base.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/macros.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_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_audio_encoder_init.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"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_encoder.h"
+#include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_encoder.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/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+
+namespace blink {
+
+template <typename Traits>
+EncoderBase<Traits>::EncoderBase(ScriptState* script_state,
+ const InitType* init,
+ ExceptionState& exception_state)
+ : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
+ state_(V8CodecState::Enum::kUnconfigured),
+ script_state_(script_state) {
+ // TODO(crbug.com/1151005): Use a real MediaLog in worker contexts too.
+ if (IsMainThread()) {
+ logger_ = std::make_unique<CodecLogger>(
+ GetExecutionContext(), Thread::MainThread()->GetTaskRunner());
+ } else {
+ // This will create a logger backed by a NullMediaLog, which does nothing.
+ logger_ = std::make_unique<CodecLogger>();
+ }
+
+ media::MediaLog* log = logger_->log();
+
+ log->SetProperty<media::MediaLogProperty::kFrameTitle>(
+ std::string(Traits::GetNameForDevTools()));
+ log->SetProperty<media::MediaLogProperty::kFrameUrl>(
+ GetExecutionContext()->Url().GetString().Ascii());
+
+ output_callback_ = init->output();
+ if (init->hasError())
+ error_callback_ = init->error();
+}
+
+template <typename Traits>
+EncoderBase<Traits>::~EncoderBase() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::configure(const ConfigType* config,
+ ExceptionState& exception_state) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (ThrowIfCodecStateClosed(state_, "configure", exception_state))
+ return;
+
+ InternalConfigType* parsed_config = ParseConfig(config, exception_state);
+ if (!parsed_config) {
+ DCHECK(exception_state.HadException());
+ return;
+ }
+
+ if (!VerifyCodecSupport(parsed_config, exception_state)) {
+ DCHECK(exception_state.HadException());
+ return;
+ }
+
+ Request* request = MakeGarbageCollected<Request>();
+ request->reset_count = reset_count_;
+ if (media_encoder_ && active_config_ &&
+ state_.AsEnum() == V8CodecState::Enum::kConfigured &&
+ CanReconfigure(*active_config_, *parsed_config)) {
+ request->type = Request::Type::kReconfigure;
+ } else {
+ state_ = V8CodecState(V8CodecState::Enum::kConfigured);
+ request->type = Request::Type::kConfigure;
+ }
+ active_config_ = parsed_config;
+ EnqueueRequest(request);
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::encode(FrameType* frame,
+ const EncodeOptionsType* opts,
+ ExceptionState& exception_state) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (ThrowIfCodecStateClosed(state_, "encode", exception_state))
+ return;
+
+ if (ThrowIfCodecStateUnconfigured(state_, "encode", exception_state))
+ return;
+
+ DCHECK(active_config_);
+ auto* context = GetExecutionContext();
+ if (!context) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Context is destroyed.");
+ return;
+ }
+
+ // This will fail if |frame| is already closed.
+ auto* internal_frame = CloneFrame(frame, context);
+
+ if (!internal_frame) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Cannot encode closed frame.");
+ return;
+ }
+
+ // At this point, we have "consumed" the frame, and will close the clone in
+ // ProcessEncode().
+ frame->close();
+
+ Request* request = MakeGarbageCollected<Request>();
+ request->reset_count = reset_count_;
+ request->type = Request::Type::kEncode;
+ request->frame = internal_frame;
+ request->encodeOpts = opts;
+ ++requested_encodes_;
+ EnqueueRequest(request);
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::close(ExceptionState& exception_state) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (ThrowIfCodecStateClosed(state_, "close", exception_state))
+ return;
+
+ state_ = V8CodecState(V8CodecState::Enum::kClosed);
+
+ ResetInternal();
+ media_encoder_.reset();
+ output_callback_.Clear();
+ error_callback_.Clear();
+}
+
+template <typename Traits>
+ScriptPromise EncoderBase<Traits>::flush(ExceptionState& exception_state) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (ThrowIfCodecStateClosed(state_, "flush", exception_state))
+ return ScriptPromise();
+
+ if (ThrowIfCodecStateUnconfigured(state_, "flush", exception_state))
+ return ScriptPromise();
+
+ Request* request = MakeGarbageCollected<Request>();
+ request->resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
+ request->reset_count = reset_count_;
+ request->type = Request::Type::kFlush;
+ EnqueueRequest(request);
+ return request->resolver->Promise();
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::reset(ExceptionState& exception_state) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (ThrowIfCodecStateClosed(state_, "reset", exception_state))
+ return;
+
+ state_ = V8CodecState(V8CodecState::Enum::kUnconfigured);
+ ResetInternal();
+ media_encoder_.reset();
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::ResetInternal() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ reset_count_++;
+ while (!requests_.empty()) {
+ Request* pending_req = requests_.TakeFirst();
+ DCHECK(pending_req);
+ if (pending_req->resolver)
+ pending_req->resolver.Release()->Resolve();
+ if (pending_req->frame)
+ pending_req->frame.Release()->close();
+ }
+ stall_request_processing_ = false;
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::HandleError(DOMException* ex) {
+ if (state_.AsEnum() == V8CodecState::Enum::kClosed)
+ return;
+
+ // Save a temp before we clear the callback.
+ V8WebCodecsErrorCallback* error_callback = error_callback_.Get();
+
+ state_ = V8CodecState(V8CodecState::Enum::kClosed);
+
+ ResetInternal();
+
+ // Errors are permanent. Shut everything down.
+ error_callback_.Clear();
+ media_encoder_.reset();
+ output_callback_.Clear();
+
+ // Prevent further logging.
+ logger_->Neuter();
+
+ if (!script_state_->ContextIsValid() || !error_callback)
+ return;
+
+ ScriptState::Scope scope(script_state_);
+ error_callback->InvokeAndReportException(nullptr, ex);
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::EnqueueRequest(Request* request) {
+ requests_.push_back(request);
+ ProcessRequests();
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::ProcessRequests() {
+ while (!requests_.empty() && !stall_request_processing_) {
+ Request* request = requests_.TakeFirst();
+ DCHECK(request);
+ switch (request->type) {
+ case Request::Type::kConfigure:
+ ProcessConfigure(request);
+ break;
+ case Request::Type::kReconfigure:
+ ProcessReconfigure(request);
+ break;
+ case Request::Type::kEncode:
+ ProcessEncode(request);
+ break;
+ case Request::Type::kFlush:
+ ProcessFlush(request);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::ProcessFlush(Request* request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, V8CodecState::Enum::kConfigured);
+ DCHECK(media_encoder_);
+ DCHECK_EQ(request->type, Request::Type::kFlush);
+
+ auto done_callback = [](EncoderBase<Traits>* self, Request* req,
+ media::Status status) {
+ if (!self)
+ return;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
+ DCHECK(req);
+ DCHECK(req->resolver);
+ if (self->reset_count_ != req->reset_count) {
+ req->resolver.Release()->Reject();
+ return;
+ }
+ if (status.is_ok()) {
+ req->resolver.Release()->Resolve();
+ } else {
+ self->HandleError(
+ self->logger_->MakeException("Flushing error.", status));
+ req->resolver.Release()->Reject();
+ }
+ self->stall_request_processing_ = false;
+ self->ProcessRequests();
+ };
+
+ stall_request_processing_ = true;
+ media_encoder_->Flush(ConvertToBaseOnceCallback(
+ CrossThreadBindOnce(done_callback, WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request))));
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::ContextDestroyed() {
+ state_ = V8CodecState(V8CodecState::Enum::kClosed);
+ logger_->Neuter();
+ media_encoder_.reset();
+}
+
+template <typename Traits>
+bool EncoderBase<Traits>::HasPendingActivity() const {
+ return stall_request_processing_ || !requests_.empty();
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::Trace(Visitor* visitor) const {
+ visitor->Trace(active_config_);
+ visitor->Trace(script_state_);
+ visitor->Trace(output_callback_);
+ visitor->Trace(error_callback_);
+ visitor->Trace(requests_);
+ ScriptWrappable::Trace(visitor);
+ ExecutionContextLifecycleObserver::Trace(visitor);
+}
+
+template <typename Traits>
+void EncoderBase<Traits>::Request::Trace(Visitor* visitor) const {
+ visitor->Trace(frame);
+ visitor->Trace(encodeOpts);
+ visitor->Trace(resolver);
+}
+
+template class EncoderBase<VideoEncoderTraits>;
+template class EncoderBase<AudioEncoderTraits>;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.h b/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.h
new file mode 100644
index 00000000000..7c5374ebb68
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoder_base.h
@@ -0,0 +1,136 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODER_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODER_BASE_H_
+
+#include <memory>
+
+#include "media/base/media_log.h"
+#include "media/base/status.h"
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_codec_state.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/codec_logger.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+class ExceptionState;
+enum class DOMExceptionCode;
+
+template <typename Traits>
+class MODULES_EXPORT EncoderBase
+ : public ScriptWrappable,
+ public ActiveScriptWrappable<EncoderBase<Traits>>,
+ public ExecutionContextLifecycleObserver {
+ public:
+ using InitType = typename Traits::Init;
+ using ConfigType = typename Traits::Config;
+ using InternalConfigType = typename Traits::InternalConfig;
+ using FrameType = typename Traits::Frame;
+ using EncodeOptionsType = typename Traits::EncodeOptions;
+ using OutputChunkType = typename Traits::OutputChunk;
+ using OutputCallbackType = typename Traits::OutputCallback;
+ using MediaEncoderType = typename Traits::MediaEncoder;
+
+ EncoderBase(ScriptState*, const InitType*, ExceptionState&);
+ ~EncoderBase() override;
+
+ // *_encoder.idl implementation.
+ int32_t encodeQueueSize() { return requested_encodes_; }
+
+ void configure(const ConfigType*, ExceptionState&);
+
+ void encode(FrameType* frame,
+ const EncodeOptionsType* opts,
+ ExceptionState& exception_state);
+
+ ScriptPromise flush(ExceptionState&);
+
+ void reset(ExceptionState&);
+
+ void close(ExceptionState&);
+
+ String state() { return state_; }
+
+ // ExecutionContextLifecycleObserver override.
+ void ContextDestroyed() override;
+
+ // ScriptWrappable override.
+ bool HasPendingActivity() const override;
+
+ // GarbageCollected override.
+ void Trace(Visitor*) const override;
+
+ protected:
+ struct Request final : public GarbageCollected<Request> {
+ enum class Type {
+ // Configure an encoder from scratch, possibly replacing the existing one.
+ kConfigure,
+ // Adjust options in the already configured encoder.
+ kReconfigure,
+ kEncode,
+ kFlush,
+ };
+
+ void Trace(Visitor*) const;
+
+ Type type;
+ // Current value of EncoderBase.reset_count_ when request was created.
+ uint32_t reset_count = 0;
+ Member<FrameType> frame; // used by kEncode
+ Member<const EncodeOptionsType> encodeOpts; // used by kEncode
+ Member<ScriptPromiseResolver> resolver; // used by kFlush
+ };
+
+ virtual void HandleError(DOMException* ex);
+ virtual void EnqueueRequest(Request* request);
+ virtual void ProcessRequests();
+ virtual void ProcessEncode(Request* request) = 0;
+ virtual void ProcessConfigure(Request* request) = 0;
+ virtual void ProcessReconfigure(Request* request) = 0;
+ virtual void ProcessFlush(Request* request);
+ virtual void ResetInternal();
+
+ virtual bool CanReconfigure(InternalConfigType& original_config,
+ InternalConfigType& new_config) = 0;
+ virtual InternalConfigType* ParseConfig(const ConfigType*,
+ ExceptionState&) = 0;
+ virtual bool VerifyCodecSupport(InternalConfigType*, ExceptionState&) = 0;
+ virtual FrameType* CloneFrame(FrameType*, ExecutionContext*) = 0;
+
+ std::unique_ptr<CodecLogger> logger_;
+
+ std::unique_ptr<MediaEncoderType> media_encoder_;
+
+ V8CodecState state_;
+
+ Member<InternalConfigType> active_config_;
+ Member<ScriptState> script_state_;
+ Member<OutputCallbackType> output_callback_;
+ Member<V8WebCodecsErrorCallback> error_callback_;
+ HeapDeque<Member<Request>> requests_;
+ int32_t requested_encodes_ = 0;
+
+ // How many times reset() was called on the encoder. It's used to decide
+ // when a callback needs to be dismissed because reset() was called between
+ // an operation and its callback.
+ uint32_t reset_count_ = 0;
+
+ // Some kConfigure and kFlush requests can't be executed in parallel with
+ // kEncode. This flag stops processing of new requests in the requests_ queue
+ // till the current requests are finished.
+ bool stall_request_processing_ = false;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODER_BASE_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
index ab059cb35de..15db4fca68f 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
@@ -142,4 +142,64 @@ message VideoEncoderApiInvocation {
message VideoEncoderApiInvocationSequence {
repeated VideoEncoderApiInvocation invocations = 1;
-} \ No newline at end of file
+}
+
+message DecodeImage {
+ optional uint32 frame_index = 1;
+ optional bool complete_frames_only = 2;
+}
+
+message DecodeMetadata {}
+
+message SelectTrack {
+ required uint32 track_id = 1;
+}
+
+message ImageDecoderApiInvocation {
+ oneof Api {
+ DecodeImage decode_image = 1;
+ DecodeMetadata decode_metadata = 2;
+ SelectTrack select_track = 3;
+ }
+}
+
+message ImageBitmapOptions {
+ enum ImageOrientation {
+ ORIENTATION_NONE = 0;
+ FLIPY = 1;
+ }
+ enum PremultiplyAlpha {
+ PREMULTIPLY_NONE = 0;
+ PREMULTIPLY = 1;
+ PREMULTIPLY_DEFAULT = 2;
+ }
+ enum ColorSpaceConversion {
+ CS_NONE = 0;
+ CS_DEFAULT = 1;
+ }
+ enum ResizeQuality {
+ PIXELATED = 0;
+ LOW = 1;
+ MEDIUM = 2;
+ HIGH = 3;
+ }
+
+ optional ImageOrientation image_orientation = 1;
+ optional PremultiplyAlpha premultiply_alpha = 2;
+ optional ColorSpaceConversion color_space_conversion = 3;
+ optional uint32 resize_width = 4;
+ optional uint32 resize_height = 5;
+ optional ResizeQuality resize_quality = 6;
+}
+
+message ConfigureImageDecoder {
+ required bytes data = 1;
+ required string type = 2;
+ optional ImageBitmapOptions options = 3;
+ optional bool prefer_animation = 4;
+}
+
+message ImageDecoderApiInvocationSequence {
+ required ConfigureImageDecoder config = 1;
+ repeated ImageDecoderApiInvocation invocations = 2;
+}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/generate_image_corpus.py b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/generate_image_corpus.py
new file mode 100644
index 00000000000..1fc64747907
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/generate_image_corpus.py
@@ -0,0 +1,81 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+Assembles a binary protobuf from a base ImageDecoder fuzzer protobuf and the
+contents of the web_tests/images/resources/ directory.
+"""
+
+import copy
+import os
+import sys
+
+# go up 6 parent directories to //src/third_party/blink
+path_to_blink = os.path.abspath(
+ os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ *[os.path.pardir] * 4))
+
+# go up 2 parent directories to //src
+path_to_src_root = os.path.join(path_to_blink, *[os.path.pardir] * 2)
+
+# allow importing modules from //src/components/resources/protobufs
+sys.path.insert(
+ 0,
+ os.path.normpath(
+ os.path.join(path_to_src_root, 'components/resources/protobufs')))
+
+from binary_proto_generator import BinaryProtoGenerator
+
+EXTENSIONS_MAP = {
+ "avif": "image/avif",
+ "png": "image/png",
+ "ico": "image/x-icon",
+ "bmp": "image/bmp",
+ "jpg": "image/jpeg",
+ "gif": "image/gif",
+ "cur": "image/x-icon",
+ "webp": "image/webp",
+}
+
+
+class ImageDecoderProtoGenerator(BinaryProtoGenerator):
+ def ImportProtoModule(self):
+ import fuzzer_inputs_pb2
+ globals()['fuzzer_inputs_pb2'] = fuzzer_inputs_pb2
+
+ def EmptyProtoInstance(self):
+ return fuzzer_inputs_pb2.ImageDecoderApiInvocationSequence()
+
+ def ProcessPb(self, opts, pb):
+ self._outdir = opts.outdir
+ self._processed_pb = pb
+ if not os.path.exists(self._outdir):
+ os.makedirs(self._outdir)
+
+ def WritePb(self, image_fn, image_type):
+ pb = copy.deepcopy(self._processed_pb)
+ pb.config.type = image_type
+ with open(image_fn, 'rb') as input_image:
+ pb.config.data = input_image.read()
+
+ out_fn = os.path.basename(image_fn) + '.pb'
+ with open(os.path.join(self._outdir, out_fn), 'wb') as out_file:
+ out_file.write(pb.SerializeToString())
+
+
+def main():
+ generator = ImageDecoderProtoGenerator()
+ generator.Run()
+
+ image_data_dir = os.path.join(path_to_blink, 'web_tests/images/resources/')
+ for root, _, files in os.walk(os.path.join(image_data_dir)):
+ for fn in files:
+ _, ext = os.path.splitext(fn)
+ ext = ext.lower().split('.')[1]
+ if ext.lower() in EXTENSIONS_MAP:
+ generator.WritePb(os.path.join(root, fn),
+ EXTENSIONS_MAP[ext.lower()])
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_h264.textproto b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_h264.textproto
new file mode 100644
index 00000000000..45bfc23f5dc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_h264.textproto
@@ -0,0 +1,76 @@
+# Simulates reasonable usage of VideoEncoder
+# configure(h264)
+# encode(red frame)
+# encode(green frame, key)
+# configure(h264, different bitrate)
+# encode(blue frame)
+# flush()
+# close()
+
+invocations: [
+ {
+ configure {
+ codec: 'avc1.42001E',
+ acceleration: DENY,
+ bitrate: 1500000,
+ framerate: 25,
+ width: 200,
+ height: 50
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 0,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # RED FRAME
+ rgb_bitmap: "\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377",
+ }
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 33333,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # GREEN FRAME
+ rgb_bitmap: "\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377",
+ },
+ options {
+ key_frame: true,
+ }
+ }
+ },
+ {
+ configure {
+ codec: 'avc1.42001E',
+ acceleration: DENY,
+ framerate: 25,
+ bitrate: 1000000,
+ width: 200,
+ height: 50
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 66666,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # BLUE FRAME
+ rgb_bitmap: "\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377",
+ }
+ }
+ },
+ {
+ flush {}
+ },
+ {
+ close {}
+ }
+] \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_vp8.textproto b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_vp8.textproto
new file mode 100644
index 00000000000..7bfde87c752
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_seed_corpus/video_encoder/encode_vp8.textproto
@@ -0,0 +1,76 @@
+# Simulates reasonable usage of VideoEncoder
+# configure(vp8)
+# encode(red frame)
+# encode(green frame, key)
+# configure(vp8, different bitrate)
+# encode(blue frame)
+# flush()
+# close()
+
+invocations: [
+ {
+ configure {
+ codec: 'vp8',
+ acceleration: ALLOW,
+ bitrate: 1500000,
+ framerate: 25,
+ width: 200,
+ height: 50
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 0,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # RED FRAME
+ rgb_bitmap: "\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377\353\000\000\377",
+ }
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 33333,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # GREEN FRAME
+ rgb_bitmap: "\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377\000\276\000\377",
+ },
+ options {
+ key_frame: true,
+ }
+ }
+ },
+ {
+ configure {
+ codec: 'vp8',
+ acceleration: ALLOW,
+ framerate: 25,
+ bitrate: 1000000,
+ width: 200,
+ height: 50
+ }
+ },
+ {
+ encode {
+ frame {
+ timestamp: 66666,
+ duration: 33333,
+ bitmap_width: 200,
+
+ # BLUE FRAME
+ rgb_bitmap: "\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377\000\310\310\377",
+ }
+ }
+ },
+ {
+ flush {}
+ },
+ {
+ close {}
+ }
+] \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
index c259ce9bd4c..cc1733823e4 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
@@ -9,8 +9,8 @@
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.h"
@@ -56,9 +56,9 @@ VideoDecoderConfig* MakeVideoDecoderConfig(
return config;
}
-EncodedAudioConfig* MakeAudioDecoderConfig(
+AudioDecoderConfig* MakeAudioDecoderConfig(
const wc_fuzzer::ConfigureAudioDecoder& proto) {
- EncodedAudioConfig* config = EncodedAudioConfig::Create();
+ AudioDecoderConfig* config = AudioDecoderConfig::Create();
config->setCodec(proto.codec().c_str());
config->setSampleRate(proto.sample_rate());
config->setNumberOfChannels(proto.number_of_channels());
@@ -75,7 +75,7 @@ VideoEncoderConfig* MakeEncoderConfig(
const wc_fuzzer::ConfigureVideoEncoder& proto) {
VideoEncoderConfig* config = VideoEncoderConfig::Create();
config->setCodec(proto.codec().c_str());
- config->setAcceleration(ToAccelerationType(proto.acceleration()));
+ config->setHardwareAcceleration(ToAccelerationType(proto.acceleration()));
config->setFramerate(proto.framerate());
config->setWidth(proto.width());
config->setHeight(proto.height());
@@ -146,7 +146,8 @@ VideoEncoderEncodeOptions* MakeEncodeOptions(
return options;
}
-VideoFrame* MakeVideoFrame(const wc_fuzzer::VideoFrameBitmapInit& proto) {
+VideoFrame* MakeVideoFrame(ScriptState* script_state,
+ const wc_fuzzer::VideoFrameBitmapInit& proto) {
NotShared<DOMUint8ClampedArray> data_u8(DOMUint8ClampedArray::Create(
reinterpret_cast<const unsigned char*>(proto.rgb_bitmap().data()),
proto.rgb_bitmap().size()));
@@ -164,7 +165,10 @@ VideoFrame* MakeVideoFrame(const wc_fuzzer::VideoFrameBitmapInit& proto) {
video_frame_init->setTimestamp(proto.timestamp());
video_frame_init->setDuration(proto.duration());
- return VideoFrame::Create(image_bitmap, video_frame_init,
+ CanvasImageSourceUnion source;
+ source.SetImageBitmap(image_bitmap);
+
+ return VideoFrame::Create(script_state, source, video_frame_init,
IGNORE_EXCEPTION_FOR_TESTING);
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
index 607806399c7..7b71b90e309 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.h"
@@ -40,7 +40,7 @@ class FakeFunction : public ScriptFunction {
VideoDecoderConfig* MakeVideoDecoderConfig(
const wc_fuzzer::ConfigureVideoDecoder& proto);
-EncodedAudioConfig* MakeAudioDecoderConfig(
+AudioDecoderConfig* MakeAudioDecoderConfig(
const wc_fuzzer::ConfigureAudioDecoder& proto);
VideoEncoderConfig* MakeEncoderConfig(
@@ -52,7 +52,8 @@ EncodedVideoChunk* MakeEncodedVideoChunk(
EncodedAudioChunk* MakeEncodedAudioChunk(
const wc_fuzzer::EncodedAudioChunk& proto);
-VideoFrame* MakeVideoFrame(const wc_fuzzer::VideoFrameBitmapInit& proto);
+VideoFrame* MakeVideoFrame(ScriptState* script_state,
+ const wc_fuzzer::VideoFrameBitmapInit& proto);
VideoEncoderEncodeOptions* MakeEncodeOptions(
const wc_fuzzer::EncodeVideo_EncodeOptions& proto);
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.cc b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.cc
new file mode 100644
index 00000000000..1d1fbffc8a5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.cc
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
+
+#include "base/notreached.h"
+
+namespace blink {
+
+HardwarePreference StringToHardwarePreference(const String& value) {
+ if (value == "allow")
+ return HardwarePreference::kAllow;
+
+ if (value == "require")
+ return HardwarePreference::kRequire;
+
+ if (value == "deny")
+ return HardwarePreference::kDeny;
+
+ NOTREACHED();
+ return HardwarePreference::kAllow;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.h b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.h
new file mode 100644
index 00000000000..99ed2f07e54
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.h
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_HARDWARE_PREFERENCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_HARDWARE_PREFERENCE_H_
+
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+enum class HardwarePreference { kAllow, kDeny, kRequire };
+
+HardwarePreference StringToHardwarePreference(const String& value);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_HARDWARE_PREFERENCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.idl b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.idl
new file mode 100644
index 00000000000..c025ae33d39
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/hardware_preference.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+enum HardwarePreference {
+ "allow",
+ "deny",
+ "require"
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni b/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
index 0dbbb215af8..9d7972c6397 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -4,9 +4,10 @@
modules_idl_files = [
"audio_decoder.idl",
+ "audio_encoder.idl",
"audio_frame.idl",
- "encoded_video_chunk.idl",
"encoded_audio_chunk.idl",
+ "encoded_video_chunk.idl",
"image_decoder.idl",
"plane.idl",
"video_decoder.idl",
@@ -17,32 +18,46 @@ modules_idl_files = [
modules_callback_function_idl_files = [
"audio_frame_output_callback.idl",
+ "encoded_audio_chunk_output_callback.idl",
"video_encoder_output_callback.idl",
"video_frame_output_callback.idl",
- "web_codecs_error_callback.idl",
+ "webcodecs_error_callback.idl",
]
modules_dictionary_idl_files = [
+ "audio_decoder_config.idl",
"audio_decoder_init.idl",
- "encoded_video_chunk_init.idl",
- "encoded_audio_config.idl",
+ "audio_decoder_support.idl",
+ "audio_encoder_config.idl",
+ "audio_encoder_init.idl",
+ "audio_frame_init.idl",
+ "avc_encoder_config.idl",
"encoded_audio_chunk_init.idl",
+ "encoded_video_chunk_init.idl",
+ "image_decode_options.idl",
"image_decoder_init.idl",
"image_frame.idl",
"image_track.idl",
"plane_init.idl",
+ "video_color_space.idl",
"video_decoder_config.idl",
"video_decoder_init.idl",
+ "video_decoder_support.idl",
"video_encoder_config.idl",
- "video_encoder_init.idl",
"video_encoder_encode_options.idl",
+ "video_encoder_init.idl",
"video_frame_init.idl",
- "audio_frame_init.idl",
+ "video_frame_plane_init.idl",
"video_track_writer_parameters.idl",
]
modules_typedefs_enums_only_idl_files = [
"codec_state.idl",
+ "color_space_matrix_id.idl",
+ "color_space_primary_id.idl",
+ "color_space_range_id.idl",
+ "color_space_transfer_id.idl",
+ "hardware_preference.idl",
"video_pixel_format.idl",
]
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl b/chromium/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl
new file mode 100644
index 00000000000..a38fdff84e3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium 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
+
+dictionary ImageDecodeOptions {
+ // The index of the frame to decode.
+ unsigned long frameIndex = 0;
+
+ // When |completeFramesOnly| is set to false, partial progressive frames will
+ // be returned. When in this mode, decode() calls will resolve only once per
+ // new partial image at |frameIndex| until the frame is complete.
+ boolean completeFramesOnly = true;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder.idl b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder.idl
index a32837cbaff..b31ea281fec 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder.idl
@@ -16,16 +16,11 @@
// Returns true if ImageDecoder supports decoding of the given mime type.
static boolean canDecodeType(USVString type);
- // Decodes the frame at the given index. If we're still receiving data, this
- // method will wait to resolve the promise until the given |frameIndex| is
- // available or reject the promise if we receive all data or fail before
- // |frameIndex| is available.
- //
- // When |completeFramesOnly| is set to false, partial progressive frames will
- // be returned. When in this mode, decode() calls will resolve only once per
- // new partial image at |frameIndex| until the frame is complete.
- Promise<ImageFrame> decode(optional unsigned long frameIndex = 0,
- optional boolean completeFramesOnly = true);
+ // Decodes a frame using the given |options| or the first frame if no options
+ // are provided. If data is still being received, the promise won't be
+ // resolved or rejected until the given |options.frameIndex| is available,
+ // all data is received, or a decoding error occurs.
+ Promise<ImageFrame> decode(optional ImageDecodeOptions options);
// Decodes only the metadata for an image; resolves the promise when metadata
// can be decoded. Normally this is done automatically at construction time.
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_base.textproto b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_base.textproto
new file mode 100644
index 00000000000..0574663dd73
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_base.textproto
@@ -0,0 +1,27 @@
+config: {
+ data: '$generated',
+ type: '$generated',
+ prefer_animation: false,
+},
+invocations: [
+ {
+ decode_metadata {}
+ },
+ {
+ decode_image {
+ frame_index: 0,
+ complete_frames_only: true
+ }
+ },
+ {
+ select_track {
+ track_id: 0
+ }
+ },
+ {
+ decode_image {
+ frame_index: 0,
+ complete_frames_only: true
+ }
+ }
+]
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 045b2fe0cbf..7a2d69afaae 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
@@ -11,6 +11,7 @@
#include "third_party/blink/public/common/mime_util/mime_util.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decode_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_frame.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_track.h"
@@ -33,8 +34,9 @@ ImageDecoderExternal* ImageDecoderExternal::Create(
ScriptState* script_state,
const ImageDecoderInit* init,
ExceptionState& exception_state) {
- return MakeGarbageCollected<ImageDecoderExternal>(script_state, init,
- exception_state);
+ auto* result = MakeGarbageCollected<ImageDecoderExternal>(script_state, init,
+ exception_state);
+ return exception_state.HadException() ? nullptr : result;
}
ImageDecoderExternal::DecodeRequest::DecodeRequest(
@@ -72,7 +74,7 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
options_ =
init->hasOptions() ? init->options() : ImageBitmapOptions::Create();
- mime_type_ = init->type();
+ mime_type_ = init->type().LowerASCII();
if (!canDecodeType(mime_type_)) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"Unsupported image format");
@@ -109,7 +111,7 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
if (init->data().IsArrayBuffer()) {
buffer = DOMArrayPiece(init->data().GetAsArrayBuffer());
} else if (init->data().IsArrayBufferView()) {
- buffer = DOMArrayPiece(init->data().GetAsArrayBufferView().View());
+ buffer = DOMArrayPiece(init->data().GetAsArrayBufferView().Get());
} else {
NOTREACHED();
return;
@@ -146,14 +148,14 @@ ImageDecoderExternal::~ImageDecoderExternal() {
DVLOG(1) << __func__;
}
-ScriptPromise ImageDecoderExternal::decode(uint32_t frame_index,
- bool complete_frames_only) {
+ScriptPromise ImageDecoderExternal::decode(const ImageDecodeOptions* options) {
DVLOG(1) << __func__;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
auto promise = resolver->Promise();
pending_decodes_.push_back(MakeGarbageCollected<DecodeRequest>(
- resolver, frame_index, complete_frames_only));
+ resolver, options ? options->frameIndex() : 0,
+ options ? options->completeFramesOnly() : true));
MaybeSatisfyPendingDecodes();
return promise;
}
@@ -310,7 +312,7 @@ void ImageDecoderExternal::CreateImageDecoder() {
// CreateByImageType() can't fail if we use a supported image type. Which we
// DCHECK above via canDecodeType().
- DCHECK(decoder_);
+ DCHECK(decoder_) << mime_type_;
}
void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
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 68bc92da7a3..dbb4fa772ac 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
@@ -20,6 +20,7 @@ namespace blink {
class ExceptionState;
class ScriptState;
class ImageBitmapOptions;
+class ImageDecodeOptions;
class ImageDecoder;
class ImageDecoderInit;
class ImageFrameExternal;
@@ -48,7 +49,7 @@ class MODULES_EXPORT ImageDecoderExternal final
using ImageTrackList = HeapVector<Member<ImageTrackExternal>>;
// image_decoder.idl implementation.
- ScriptPromise decode(uint32_t frame_index, bool complete_frames_only);
+ ScriptPromise decode(const ImageDecodeOptions* options = nullptr);
ScriptPromise decodeMetadata();
void selectTrack(uint32_t track_id, ExceptionState&);
uint32_t frameCount() const;
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 2d38acec5c3..fe943479ebb 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
@@ -4,12 +4,12 @@
#include "third_party/blink/renderer/modules/webcodecs/image_decoder_external.h"
-#include "base/feature_list.h"
#include "media/media_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.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/bindings/modules/v8/v8_image_decode_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_frame.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_track.h"
@@ -44,6 +44,14 @@ class ImageDecoderTest : public testing::Test {
v8_scope->GetIsolate(), value.V8Value(), v8_scope->GetExceptionState());
}
+ ImageDecodeOptions* MakeOptions(uint32_t frame_index = 0,
+ bool complete_frames_only = true) {
+ auto* options = MakeGarbageCollected<ImageDecodeOptions>();
+ options->setFrameIndex(frame_index);
+ options->setCompleteFramesOnly(complete_frames_only);
+ return options;
+ }
+
scoped_refptr<SharedBuffer> ReadFile(StringView file_name) {
StringBuilder file_path;
file_path.Append(test::BlinkWebTestsDir());
@@ -72,12 +80,8 @@ TEST_F(ImageDecoderTest, CanDecodeType) {
EXPECT_TRUE(ImageDecoderExternal::canDecodeType("image/bmp"));
EXPECT_TRUE(ImageDecoderExternal::canDecodeType("image/x-xbitmap"));
-#if BUILDFLAG(ENABLE_AV1_DECODER)
EXPECT_EQ(ImageDecoderExternal::canDecodeType("image/avif"),
- base::FeatureList::IsEnabled(features::kAVIF));
-#else
- EXPECT_FALSE(ImageDecoderExternal::canDecodeType("image/avif"));
-#endif
+ BUILDFLAG(ENABLE_AV1_DECODER));
EXPECT_FALSE(ImageDecoderExternal::canDecodeType("image/svg+xml"));
EXPECT_FALSE(ImageDecoderExternal::canDecodeType("image/heif"));
@@ -94,7 +98,7 @@ TEST_F(ImageDecoderTest, DecodeEmpty) {
DOMArrayBuffer::Create(SharedBuffer::Create())));
auto* decoder = ImageDecoderExternal::Create(v8_scope.GetScriptState(), init,
v8_scope.GetExceptionState());
- EXPECT_TRUE(decoder);
+ EXPECT_FALSE(decoder);
EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
}
@@ -113,7 +117,7 @@ TEST_F(ImageDecoderTest, DecodeNeuteredAtConstruction) {
auto* decoder = ImageDecoderExternal::Create(v8_scope.GetScriptState(), init,
v8_scope.GetExceptionState());
- EXPECT_TRUE(decoder);
+ EXPECT_FALSE(decoder);
EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
}
@@ -143,7 +147,7 @@ TEST_F(ImageDecoderTest, DecodeNeuteredAtDecodeTime) {
ArrayBufferContents contents;
ASSERT_TRUE(buffer->Transfer(v8_scope.GetIsolate(), contents));
- auto promise = decoder->decode(0, true);
+ auto promise = decoder->decode(MakeOptions(0, true));
ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
tester.WaitUntilSettled();
ASSERT_TRUE(tester.IsRejected());
@@ -155,10 +159,21 @@ TEST_F(ImageDecoderTest, DecodeUnsupported) {
EXPECT_FALSE(ImageDecoderExternal::canDecodeType(kImageType));
auto* decoder =
CreateDecoder(&v8_scope, "images/resources/test.svg", kImageType);
- EXPECT_TRUE(decoder);
+ EXPECT_FALSE(decoder);
EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
}
+TEST_F(ImageDecoderTest, DecoderCreationMixedCaseMimeType) {
+ V8TestingScope v8_scope;
+ constexpr char kImageType[] = "image/GiF";
+ EXPECT_TRUE(ImageDecoderExternal::canDecodeType(kImageType));
+ auto* decoder =
+ CreateDecoder(&v8_scope, "images/resources/animated.gif", kImageType);
+ ASSERT_TRUE(decoder);
+ ASSERT_FALSE(v8_scope.GetExceptionState().HadException());
+ EXPECT_EQ(decoder->type(), "image/gif");
+}
+
TEST_F(ImageDecoderTest, DecodeGif) {
V8TestingScope v8_scope;
constexpr char kImageType[] = "image/gif";
@@ -186,7 +201,7 @@ TEST_F(ImageDecoderTest, DecodeGif) {
EXPECT_EQ(tracks[0]->animated(), true);
{
- auto promise = decoder->decode(0, true);
+ auto promise = decoder->decode(MakeOptions(0, true));
ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
tester.WaitUntilSettled();
ASSERT_TRUE(tester.IsFulfilled());
@@ -200,7 +215,7 @@ TEST_F(ImageDecoderTest, DecodeGif) {
}
{
- auto promise = decoder->decode(1, true);
+ auto promise = decoder->decode(MakeOptions(1, true));
ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
tester.WaitUntilSettled();
ASSERT_TRUE(tester.IsFulfilled());
@@ -214,7 +229,7 @@ TEST_F(ImageDecoderTest, DecodeGif) {
}
// Decoding past the end should result in a rejected promise.
- auto promise = decoder->decode(3, true);
+ auto promise = decoder->decode(MakeOptions(3, true));
ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
tester.WaitUntilSettled();
ASSERT_TRUE(tester.IsRejected());
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
new file mode 100644
index 00000000000..9fb87fdfb46
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
@@ -0,0 +1,176 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decode_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.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/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.pb.h"
+#include "third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h"
+#include "third_party/blink/renderer/modules/webcodecs/image_decoder_external.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+#include <string>
+
+namespace blink {
+
+namespace {
+
+String ToImageOrientation(wc_fuzzer::ImageBitmapOptions_ImageOrientation type) {
+ switch (type) {
+ case wc_fuzzer::ImageBitmapOptions_ImageOrientation_ORIENTATION_NONE:
+ return "none";
+ case wc_fuzzer::ImageBitmapOptions_ImageOrientation_FLIPY:
+ return "flipY";
+ }
+}
+
+String ToPremultiplyAlpha(wc_fuzzer::ImageBitmapOptions_PremultiplyAlpha type) {
+ switch (type) {
+ case wc_fuzzer::ImageBitmapOptions_PremultiplyAlpha_PREMULTIPLY_NONE:
+ return "none";
+ case wc_fuzzer::ImageBitmapOptions_PremultiplyAlpha_PREMULTIPLY:
+ return "premultiply";
+ case wc_fuzzer::ImageBitmapOptions_PremultiplyAlpha_PREMULTIPLY_DEFAULT:
+ return "default";
+ }
+}
+
+String ToColorSpaceConversion(
+ wc_fuzzer::ImageBitmapOptions_ColorSpaceConversion type) {
+ switch (type) {
+ case wc_fuzzer::ImageBitmapOptions_ColorSpaceConversion_CS_NONE:
+ return "none";
+ case wc_fuzzer::ImageBitmapOptions_ColorSpaceConversion_CS_DEFAULT:
+ return "default";
+ }
+}
+
+String ToResizeQuality(wc_fuzzer::ImageBitmapOptions_ResizeQuality type) {
+ switch (type) {
+ case wc_fuzzer::ImageBitmapOptions_ResizeQuality_PIXELATED:
+ return "pixelated";
+ case wc_fuzzer::ImageBitmapOptions_ResizeQuality_LOW:
+ return "low";
+ case wc_fuzzer::ImageBitmapOptions_ResizeQuality_MEDIUM:
+ return "medium";
+ case wc_fuzzer::ImageBitmapOptions_ResizeQuality_HIGH:
+ return "high";
+ }
+}
+
+} // namespace
+
+DEFINE_BINARY_PROTO_FUZZER(
+ const wc_fuzzer::ImageDecoderApiInvocationSequence& proto) {
+ static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
+ static DummyPageHolder* page_holder = []() {
+ auto page_holder = std::make_unique<DummyPageHolder>();
+ page_holder->GetFrame().GetSettings()->SetScriptEnabled(true);
+ return page_holder.release();
+ }();
+
+ //
+ // NOTE: GC objects that need to survive iterations of the loop below
+ // must be Persistent<>!
+ //
+ // GC may be triggered by the RunLoop().RunUntilIdle() below, which will GC
+ // raw pointers on the stack. This is not required in production code because
+ // GC typically runs at the top of the stack, or is conservative enough to
+ // keep stack pointers alive.
+ //
+
+ // Scoping Persistent<> refs so GC can collect these at the end.
+ {
+ Persistent<ScriptState> script_state =
+ ToScriptStateForMainWorld(&page_holder->GetFrame());
+ ScriptState::Scope scope(script_state);
+
+ Persistent<ImageDecoderInit> image_decoder_init =
+ MakeGarbageCollected<ImageDecoderInit>();
+ image_decoder_init->setType(proto.config().type().c_str());
+ DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(
+ proto.config().data().data(), proto.config().data().size());
+ image_decoder_init->setData(
+ ArrayBufferOrArrayBufferViewOrReadableStream::FromArrayBuffer(
+ data_copy));
+
+ Persistent<ImageBitmapOptions> options = ImageBitmapOptions::Create();
+ options->setImageOrientation(
+ ToImageOrientation(proto.config().options().image_orientation()));
+ options->setPremultiplyAlpha(
+ ToPremultiplyAlpha(proto.config().options().premultiply_alpha()));
+ options->setColorSpaceConversion(ToColorSpaceConversion(
+ proto.config().options().color_space_conversion()));
+
+ // Limit resize support to a reasonable value to prevent fuzzer oom.
+ constexpr uint32_t kMaxDimension = 4096u;
+ options->setResizeWidth(
+ std::min(proto.config().options().resize_width(), kMaxDimension));
+ options->setResizeHeight(
+ std::min(proto.config().options().resize_height(), kMaxDimension));
+ options->setResizeQuality(
+ ToResizeQuality(proto.config().options().resize_quality()));
+ image_decoder_init->setOptions(options);
+
+ image_decoder_init->setPreferAnimation(proto.config().prefer_animation());
+
+ Persistent<ImageDecoderExternal> image_decoder =
+ ImageDecoderExternal::Create(script_state, image_decoder_init,
+ IGNORE_EXCEPTION_FOR_TESTING);
+
+ if (image_decoder) {
+ Persistent<ImageDecodeOptions> options = ImageDecodeOptions::Create();
+ // Promises will be fulfilled synchronously since we're using an array
+ // buffer based source.
+ for (auto& invocation : proto.invocations()) {
+ switch (invocation.Api_case()) {
+ case wc_fuzzer::ImageDecoderApiInvocation::kDecodeImage:
+ options->setFrameIndex(invocation.decode_image().frame_index());
+ options->setCompleteFramesOnly(
+ invocation.decode_image().complete_frames_only());
+ image_decoder->decode(options);
+ break;
+ case wc_fuzzer::ImageDecoderApiInvocation::kDecodeMetadata:
+ image_decoder->decodeMetadata();
+ break;
+ case wc_fuzzer::ImageDecoderApiInvocation::kSelectTrack:
+ image_decoder->selectTrack(invocation.select_track().track_id(),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::ImageDecoderApiInvocation::API_NOT_SET:
+ break;
+ }
+
+ // Give other tasks a chance to run (e.g. calling our output callback).
+ base::RunLoop().RunUntilIdle();
+ }
+ }
+
+ // TODO(crbug.com/1166925): Push the same image data incrementally into
+ // the fuzzer via a ReadableSource.
+ }
+
+ // Request a V8 GC. Oilpan will be invoked by the GC epilogue.
+ //
+ // Multiple GCs may be required to ensure everything is collected (due to
+ // a chain of persistent handles), so some objects may not be collected until
+ // a subsequent iteration. This is slow enough as is, so we compromise on one
+ // major GC, as opposed to the 5 used in V8GCController for unit tests.
+ V8PerIsolateData::MainThreadIsolate()->RequestGarbageCollectionForTesting(
+ v8::Isolate::kFullGarbageCollection);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/plane.cc b/chromium/third_party/blink/renderer/modules/webcodecs/plane.cc
index 7652ddc4670..aa4b37e8360 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/plane.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/plane.cc
@@ -70,7 +70,7 @@ void Plane::readInto(MaybeShared<DOMArrayBufferView> dst,
auto local_frame = handle_->frame();
if (!local_frame) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Cannot read from destroyed VideoFrame.");
+ "Cannot read from closed VideoFrame.");
return;
}
@@ -88,14 +88,13 @@ void Plane::readInto(MaybeShared<DOMArrayBufferView> dst,
size_t copy_size = total_size - trailing_zeros_size;
// Note: byteLength is zero if the buffer is detached.
- DOMArrayBufferView* view = dst.View();
- uint8_t* base = static_cast<uint8_t*>(view->BaseAddressMaybeShared());
+ uint8_t* base = static_cast<uint8_t*>(dst->BaseAddressMaybeShared());
if (!base) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Destination buffer is not valid.");
return;
}
- if (total_size > view->byteLength()) {
+ if (total_size > dst->byteLength()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Destination buffer is not large enough.");
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_color_space.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_color_space.idl
new file mode 100644
index 00000000000..53f3c48cf19
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_color_space.idl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+// Described in ISO 23001-8:2016
+// See also: https://source.chromium.org/chromium/chromium/src/+/master:media/base/video_color_space.h
+dictionary VideoColorSpace {
+ ColorSpacePrimaryID? primaryID;
+ ColorSpaceTransferID? transferID;
+ ColorSpaceMatrixID? matrixID;
+ ColorSpaceRangeID? rangeID;
+
+ // TODO(sandersd): custom primary/matrix support.
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
index eeee5b75223..43f873be55b 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
@@ -16,8 +16,11 @@
#include "media/media_buildflags.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.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"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_support.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
@@ -26,8 +29,11 @@
#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/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -39,6 +45,215 @@
namespace blink {
+namespace {
+
+media::GpuVideoAcceleratorFactories* GetGpuFactoriesOnMainThread() {
+ DCHECK(IsMainThread());
+ return Platform::Current()->GetGpuFactories();
+}
+
+void DecoderSupport_OnKnown(
+ VideoDecoderSupport* support,
+ std::unique_ptr<VideoDecoder::MediaConfigType> media_config,
+ ScriptPromiseResolver* resolver,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ DCHECK(gpu_factories->IsDecoderSupportKnown());
+ support->setSupported(
+ gpu_factories->IsDecoderConfigSupported(*media_config) ==
+ media::GpuVideoAcceleratorFactories::Supported::kTrue);
+ resolver->Resolve(support);
+}
+
+void DecoderSupport_OnGpuFactories(
+ VideoDecoderSupport* support,
+ std::unique_ptr<VideoDecoder::MediaConfigType> media_config,
+ ScriptPromiseResolver* resolver,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) {
+ support->setSupported(false);
+ resolver->Resolve(support);
+ return;
+ }
+
+ if (gpu_factories->IsDecoderSupportKnown()) {
+ DecoderSupport_OnKnown(support, std::move(media_config), resolver,
+ gpu_factories);
+ return;
+ }
+
+ gpu_factories->NotifyDecoderSupportKnown(
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ &DecoderSupport_OnKnown, WrapCrossThreadPersistent(support),
+ std::move(media_config), WrapCrossThreadPersistent(resolver),
+ CrossThreadUnretained(gpu_factories))));
+}
+
+} // namespace
+
+bool ParseCodecString(const String& codec_string,
+ media::VideoType& out_video_type,
+ String& out_console_message) {
+ bool is_codec_ambiguous = true;
+ media::VideoCodec codec = media::kUnknownVideoCodec;
+ media::VideoCodecProfile profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
+ media::VideoColorSpace color_space = media::VideoColorSpace::REC709();
+ uint8_t level = 0;
+ bool parse_succeeded =
+ media::ParseVideoCodecString("", codec_string.Utf8(), &is_codec_ambiguous,
+ &codec, &profile, &level, &color_space);
+
+ if (!parse_succeeded) {
+ out_console_message = "Failed to parse codec string.";
+ return false;
+ }
+
+ if (is_codec_ambiguous) {
+ out_console_message = "Codec string is ambiguous.";
+ return false;
+ }
+
+ out_video_type = {codec, profile, level, color_space};
+ return true;
+}
+
+// TODO(crbug.com/1179970): rename out_console_message.
+// TODO(crbug.com/1181443): Make this a pure virtual in DecoderTemplate, and
+// refactor its uses.
+bool IsValidConfig(const VideoDecoderConfig& config,
+ media::VideoType& out_video_type,
+ String& out_console_message) {
+ if (!ParseCodecString(config.codec(), out_video_type, out_console_message))
+ return false;
+
+ if (config.hasCodedWidth()) {
+ if (config.codedWidth() == 0) {
+ out_console_message =
+ "Invalid codedWidth. Value must be greater than zero.";
+ return false;
+ }
+
+ uint32_t crop_left = config.hasCropLeft() ? config.cropLeft() : 0;
+ uint32_t crop_width =
+ config.hasCropWidth() ? config.cropWidth() : config.codedWidth();
+
+ if (crop_width == 0) {
+ out_console_message =
+ "Invalid cropWidth. Value must be greater than zero.";
+ return false;
+ }
+
+ if (crop_left + crop_width > config.codedWidth()) {
+ out_console_message =
+ "Invalid cropLeft + cropWidth. Sum must not exceed codedWidth.";
+ return false;
+ }
+ } else { // !config.hasCodedWidth()
+ if (config.hasCropLeft()) {
+ out_console_message =
+ "Invalid config. cropLeft specified without codedWidth.";
+ return false;
+ }
+
+ if (config.hasCropWidth()) {
+ out_console_message =
+ "Invalid config. cropWidth specified without codedWidth.";
+ return false;
+ }
+ }
+
+ if (config.hasCodedHeight()) {
+ if (config.codedHeight() == 0) {
+ out_console_message =
+ "Invalid codedHeight. Value must be greater than zero.";
+ return false;
+ }
+
+ uint32_t crop_top = config.hasCropTop() ? config.cropTop() : 0;
+ uint32_t crop_height =
+ config.hasCropHeight() ? config.cropHeight() : config.codedHeight();
+
+ if (crop_height == 0) {
+ out_console_message =
+ "Invalid cropHeight. Value must be greater than zero.";
+ return false;
+ }
+
+ if (crop_top + crop_height > config.codedHeight()) {
+ out_console_message =
+ "Invalid cropTop + cropHeight. Sum must not exceed codedHeight.";
+ return false;
+ }
+ } else { // !config.hasCodedHeight()
+ if (config.hasCropTop()) {
+ out_console_message =
+ "Invalid config. cropTop specified without codedHeight.";
+ return false;
+ }
+
+ if (config.hasCropHeight()) {
+ out_console_message =
+ "Invalid config. cropHeight specified without codedHeight.";
+ return false;
+ }
+ }
+
+ if (config.hasDisplayWidth() && config.displayWidth() == 0) {
+ out_console_message =
+ "Invalid displayWidth. Value must be greater than zero.";
+ return false;
+ }
+
+ if (config.hasDisplayHeight() && config.displayHeight() == 0) {
+ out_console_message =
+ "Invalid displayHeight. Value must be greater than zero.";
+ return false;
+ }
+
+ return true;
+}
+
+VideoDecoderConfig* CopyConfig(const VideoDecoderConfig& config) {
+ VideoDecoderConfig* copy = VideoDecoderConfig::Create();
+ copy->setCodec(config.codec());
+
+ if (config.hasDescription()) {
+ DOMArrayPiece buffer(config.description());
+ DOMArrayBuffer* buffer_copy =
+ DOMArrayBuffer::Create(buffer.Data(), buffer.ByteLength());
+ copy->setDescription(
+ ArrayBufferOrArrayBufferView::FromArrayBuffer(buffer_copy));
+ }
+
+ if (config.hasCodedWidth())
+ copy->setCodedWidth(config.codedWidth());
+
+ if (config.hasCodedHeight())
+ copy->setCodedHeight(config.codedHeight());
+
+ if (config.hasCropLeft())
+ copy->setCropLeft(config.cropLeft());
+
+ if (config.hasCropTop())
+ copy->setCropTop(config.cropTop());
+
+ if (config.hasCropWidth())
+ copy->setCropWidth(config.cropWidth());
+
+ if (config.hasCropHeight())
+ copy->setCropHeight(config.cropHeight());
+
+ if (config.hasDisplayWidth())
+ copy->setDisplayWidth(config.displayWidth());
+
+ if (config.hasDisplayHeight())
+ copy->setDisplayHeight(config.displayHeight());
+
+ if (config.hasHardwareAcceleration())
+ copy->setHardwareAcceleration(config.hardwareAcceleration());
+
+ return copy;
+}
+
// static
std::unique_ptr<VideoDecoderTraits::MediaDecoderType>
VideoDecoderTraits::CreateDecoder(
@@ -50,6 +265,15 @@ VideoDecoderTraits::CreateDecoder(
}
// static
+HardwarePreference VideoDecoder::GetHardwareAccelerationPreference(
+ const ConfigType& config) {
+ // The IDL defines a default value of "allow".
+ DCHECK(config.hasHardwareAcceleration());
+ return StringToHardwarePreference(
+ IDLEnumAsString(config.hardwareAcceleration()));
+}
+
+// static
void VideoDecoderTraits::InitializeDecoder(
MediaDecoderType& decoder,
const MediaConfigType& media_config,
@@ -67,7 +291,7 @@ void VideoDecoderTraits::UpdateDecoderLog(const MediaDecoderType& decoder,
media_log->SetProperty<media::MediaLogProperty::kFrameTitle>(
std::string("VideoDecoder(WebCodecs)"));
media_log->SetProperty<media::MediaLogProperty::kVideoDecoderName>(
- decoder.GetDisplayName());
+ decoder.GetDecoderType());
media_log->SetProperty<media::MediaLogProperty::kIsPlatformVideoDecoder>(
decoder.IsPlatformDecoder());
media_log->SetProperty<media::MediaLogProperty::kVideoTracks>(
@@ -75,6 +299,14 @@ void VideoDecoderTraits::UpdateDecoderLog(const MediaDecoderType& decoder,
}
// static
+VideoDecoderTraits::OutputType* VideoDecoderTraits::MakeOutput(
+ scoped_refptr<MediaOutputType> output,
+ ExecutionContext* context) {
+ return MakeGarbageCollected<VideoDecoderTraits::OutputType>(std::move(output),
+ context);
+}
+
+// static
int VideoDecoderTraits::GetMaxDecodeRequests(const MediaDecoderType& decoder) {
return decoder.GetMaxDecodeRequests();
}
@@ -83,89 +315,136 @@ int VideoDecoderTraits::GetMaxDecodeRequests(const MediaDecoderType& decoder) {
VideoDecoder* VideoDecoder::Create(ScriptState* script_state,
const VideoDecoderInit* init,
ExceptionState& exception_state) {
- return MakeGarbageCollected<VideoDecoder>(script_state, init,
- exception_state);
+ auto* result =
+ MakeGarbageCollected<VideoDecoder>(script_state, init, exception_state);
+ return exception_state.HadException() ? nullptr : result;
}
-VideoDecoder::VideoDecoder(ScriptState* script_state,
- const VideoDecoderInit* init,
- ExceptionState& exception_state)
- : DecoderTemplate<VideoDecoderTraits>(script_state, init, exception_state) {
- UseCounter::Count(ExecutionContext::From(script_state),
- WebFeature::kWebCodecs);
-}
+// static
+ScriptPromise VideoDecoder::isConfigSupported(ScriptState* script_state,
+ const VideoDecoderConfig* config,
+ ExceptionState& exception_state) {
+ HardwarePreference hw_pref = GetHardwareAccelerationPreference(*config);
-CodecConfigEval VideoDecoder::MakeMediaConfig(const ConfigType& config,
- MediaConfigType* out_media_config,
- String* out_console_message) {
- DCHECK(out_media_config);
- DCHECK(out_console_message);
+ if (hw_pref == HardwarePreference::kRequire)
+ return IsAcceleratedConfigSupported(script_state, config, exception_state);
- bool is_codec_ambiguous = true;
- media::VideoCodec codec = media::kUnknownVideoCodec;
- media::VideoCodecProfile profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
- media::VideoColorSpace color_space = media::VideoColorSpace::REC709();
- uint8_t level = 0;
- bool parse_succeeded = media::ParseVideoCodecString(
- "", config.codec().Utf8(), &is_codec_ambiguous, &codec, &profile, &level,
- &color_space);
+ media::VideoType video_type;
+ String console_message;
- if (!parse_succeeded) {
- *out_console_message = "Failed to parse codec string.";
- return CodecConfigEval::kInvalid;
+ if (!IsValidConfig(*config, video_type, console_message)) {
+ exception_state.ThrowTypeError(console_message);
+ return ScriptPromise();
}
- if (is_codec_ambiguous) {
- *out_console_message = "Codec string is ambiguous.";
- return CodecConfigEval::kInvalid;
+ // Accept all supported configs if we are not requiring hardware only.
+ VideoDecoderSupport* support = VideoDecoderSupport::Create();
+ support->setSupported(media::IsSupportedVideoType(video_type));
+ support->setConfig(CopyConfig(*config));
+ return ScriptPromise::Cast(script_state, ToV8(support, script_state));
+}
+
+ScriptPromise VideoDecoder::IsAcceleratedConfigSupported(
+ ScriptState* script_state,
+ const VideoDecoderConfig* config,
+ ExceptionState& exception_state) {
+ String console_message;
+ auto media_config = std::make_unique<MediaConfigType>();
+ CodecConfigEval config_eval;
+
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ std::unique_ptr<media::H264ToAnnexBBitstreamConverter> h264_converter;
+ std::unique_ptr<media::mp4::AVCDecoderConfigurationRecord> h264_avcc;
+ config_eval = MakeMediaVideoDecoderConfig(
+ *config, *media_config, h264_converter, h264_avcc, console_message);
+#else
+ config_eval =
+ MakeMediaVideoDecoderConfig(*config, *media_config, console_message);
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+ if (config_eval != CodecConfigEval::kSupported) {
+ exception_state.ThrowTypeError(console_message);
+ return ScriptPromise();
}
- if (!media::IsSupportedVideoType({codec, profile, level, color_space})) {
- *out_console_message = "Configuration is not supported.";
- return CodecConfigEval::kUnsupported;
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+ VideoDecoderSupport* support = VideoDecoderSupport::Create();
+ support->setConfig(CopyConfig(*config));
+
+ if (IsMainThread()) {
+ media::GpuVideoAcceleratorFactories* gpu_factories =
+ Platform::Current()->GetGpuFactories();
+ DecoderSupport_OnGpuFactories(support, std::move(media_config), resolver,
+ gpu_factories);
+ } else {
+ auto on_gpu_factories_cb = CrossThreadBindOnce(
+ &DecoderSupport_OnGpuFactories, WrapCrossThreadPersistent(support),
+ std::move(media_config), WrapCrossThreadPersistent(resolver));
+
+ Thread::MainThread()->GetTaskRunner()->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ ConvertToBaseOnceCallback(
+ CrossThreadBindOnce(&GetGpuFactoriesOnMainThread)),
+ ConvertToBaseOnceCallback(std::move(on_gpu_factories_cb)));
}
+ return promise;
+}
+
+HardwarePreference VideoDecoder::GetHardwarePreference(
+ const ConfigType& config) {
+ return GetHardwareAccelerationPreference(config);
+}
+
+void VideoDecoder::SetHardwarePreference(HardwarePreference preference) {
+ static_cast<VideoDecoderBroker*>(decoder())->SetHardwarePreference(
+ preference);
+}
+
+// static
+// TODO(crbug.com/1179970): rename out_console_message.
+CodecConfigEval VideoDecoder::MakeMediaVideoDecoderConfig(
+ const ConfigType& config,
+ MediaConfigType& out_media_config,
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ std::unique_ptr<media::H264ToAnnexBBitstreamConverter>& out_h264_converter,
+ std::unique_ptr<media::mp4::AVCDecoderConfigurationRecord>& out_h264_avcc,
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+ String& out_console_message) {
+ media::VideoType video_type;
+
+ if (!IsValidConfig(config, video_type, out_console_message))
+ return CodecConfigEval::kInvalid;
+
// TODO(sandersd): Can we allow shared ArrayBuffers?
std::vector<uint8_t> extra_data;
if (config.hasDescription()) {
- if (config.description().IsArrayBuffer()) {
- DOMArrayBuffer* buffer = config.description().GetAsArrayBuffer();
- uint8_t* start = static_cast<uint8_t*>(buffer->Data());
- size_t size = buffer->ByteLength();
- extra_data.assign(start, start + size);
- } else {
- DCHECK(config.description().IsArrayBufferView());
- DOMArrayBufferView* view =
- config.description().GetAsArrayBufferView().Get();
- uint8_t* start = static_cast<uint8_t*>(view->BaseAddress());
- size_t size = view->byteLength();
- extra_data.assign(start, start + size);
- }
+ DOMArrayPiece buffer(config.description());
+ uint8_t* start = static_cast<uint8_t*>(buffer.Data());
+ size_t size = buffer.ByteLength();
+ extra_data.assign(start, start + size);
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
- if (codec == media::kCodecH264) {
- if (extra_data.empty()) {
- *out_console_message =
- "H.264 configuration must include an avcC description.";
- return CodecConfigEval::kInvalid;
- }
-
- h264_avcc_ = std::make_unique<media::mp4::AVCDecoderConfigurationRecord>();
- h264_converter_ = std::make_unique<media::H264ToAnnexBBitstreamConverter>();
- if (!h264_converter_->ParseConfiguration(
+ if (video_type.codec == media::kCodecH264 && !extra_data.empty()) {
+ out_h264_avcc =
+ std::make_unique<media::mp4::AVCDecoderConfigurationRecord>();
+ out_h264_converter =
+ std::make_unique<media::H264ToAnnexBBitstreamConverter>();
+ if (!out_h264_converter->ParseConfiguration(
extra_data.data(), static_cast<uint32_t>(extra_data.size()),
- h264_avcc_.get())) {
- *out_console_message = "Failed to parse avcC.";
+ out_h264_avcc.get())) {
+ out_console_message = "Failed to parse avcC.";
return CodecConfigEval::kInvalid;
}
} else {
- h264_avcc_.reset();
- h264_converter_.reset();
+ out_h264_avcc.reset();
+ out_h264_converter.reset();
}
#else
- if (codec == media::kCodecH264) {
- *out_console_message = "H.264 decoding is not supported.";
+ if (video_type.codec == media::kCodecH264) {
+ out_console_message = "H.264 decoding is not supported.";
return CodecConfigEval::kUnsupported;
}
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -175,15 +454,36 @@ CodecConfigEval VideoDecoder::MakeMediaConfig(const ConfigType& config,
// match.
gfx::Size size = gfx::Size(1280, 720);
- out_media_config->Initialize(codec, profile,
- media::VideoDecoderConfig::AlphaMode::kIsOpaque,
- color_space, media::kNoTransformation, size,
- gfx::Rect(gfx::Point(), size), size, extra_data,
- media::EncryptionScheme::kUnencrypted);
+ out_media_config.Initialize(
+ video_type.codec, video_type.profile,
+ media::VideoDecoderConfig::AlphaMode::kIsOpaque, video_type.color_space,
+ media::kNoTransformation, size, gfx::Rect(gfx::Point(), size), size,
+ extra_data, media::EncryptionScheme::kUnencrypted);
return CodecConfigEval::kSupported;
}
+VideoDecoder::VideoDecoder(ScriptState* script_state,
+ const VideoDecoderInit* init,
+ ExceptionState& exception_state)
+ : DecoderTemplate<VideoDecoderTraits>(script_state, init, exception_state) {
+ UseCounter::Count(ExecutionContext::From(script_state),
+ WebFeature::kWebCodecs);
+}
+
+CodecConfigEval VideoDecoder::MakeMediaConfig(const ConfigType& config,
+ MediaConfigType* out_media_config,
+ String* out_console_message) {
+ DCHECK(out_media_config);
+ DCHECK(out_console_message);
+ return MakeMediaVideoDecoderConfig(config, *out_media_config,
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ h264_converter_ /* out */,
+ h264_avcc_ /* out */,
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+ *out_console_message);
+}
+
media::StatusOr<scoped_refptr<media::DecoderBuffer>>
VideoDecoder::MakeDecoderBuffer(const InputType& chunk) {
uint8_t* src = static_cast<uint8_t*>(chunk.data()->Data());
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.h
index 45b544e6c7d..55842b31f5b 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.h
@@ -15,7 +15,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/decoder_template.h"
@@ -48,6 +48,7 @@ class VideoDecoderConfig;
class VideoDecoderInit;
class VideoFrame;
class V8VideoFrameOutputCallback;
+class ScriptPromise;
class MODULES_EXPORT VideoDecoderTraits {
public:
@@ -74,6 +75,8 @@ class MODULES_EXPORT VideoDecoderTraits {
static void UpdateDecoderLog(const MediaDecoderType& decoder,
const MediaConfigType& media_config,
media::MediaLog* media_log);
+ static OutputType* MakeOutput(scoped_refptr<MediaOutputType>,
+ ExecutionContext*);
};
class MODULES_EXPORT VideoDecoder : public DecoderTemplate<VideoDecoderTraits> {
@@ -84,6 +87,24 @@ class MODULES_EXPORT VideoDecoder : public DecoderTemplate<VideoDecoderTraits> {
const VideoDecoderInit*,
ExceptionState&);
+ static ScriptPromise isConfigSupported(ScriptState*,
+ const VideoDecoderConfig*,
+ ExceptionState&);
+
+ static HardwarePreference GetHardwareAccelerationPreference(
+ const ConfigType& config);
+
+ // For use by MediaSource and by ::MakeMediaConfig.
+ static CodecConfigEval MakeMediaVideoDecoderConfig(
+ const ConfigType& config,
+ MediaConfigType& out_media_config,
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ std::unique_ptr<media::H264ToAnnexBBitstreamConverter>&
+ out_h264_converter,
+ std::unique_ptr<media::mp4::AVCDecoderConfigurationRecord>& out_h264_avcc,
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+ String& out_console_message);
+
VideoDecoder(ScriptState*, const VideoDecoderInit*, ExceptionState&);
~VideoDecoder() override = default;
@@ -94,10 +115,19 @@ class MODULES_EXPORT VideoDecoder : public DecoderTemplate<VideoDecoderTraits> {
media::StatusOr<scoped_refptr<media::DecoderBuffer>> MakeDecoderBuffer(
const InputType& input) override;
+ static ScriptPromise IsAcceleratedConfigSupported(ScriptState* script_state,
+ const VideoDecoderConfig*,
+ ExceptionState&);
+
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
std::unique_ptr<media::H264ToAnnexBBitstreamConverter> h264_converter_;
std::unique_ptr<media::mp4::AVCDecoderConfigurationRecord> h264_avcc_;
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+ private:
+ // DecoderTemplate implementation.
+ HardwarePreference GetHardwarePreference(const ConfigType& config) override;
+ void SetHardwarePreference(HardwarePreference preference) override;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.idl
index a31120eff3b..34659e49734 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder.idl
@@ -35,6 +35,9 @@
// TODO(sandersd): Consider emitting an event when this number decreases.
readonly attribute long decodeQueueSize;
+ // Which state the decoder is in, indicating which methods can be called.
+ readonly attribute CodecState state;
+
// Set the stream configuration for future decode() requests.
//
// The next decode request must be for a keyframe.
@@ -45,8 +48,6 @@
// Request decoding of an input chunk.
//
// You must call configure() before calling decode() for the first time.
- //
- // TODO(sandersd): Change to a dictionary type.
[RaisesException] void decode(EncodedVideoChunk chunk);
// Request output from all previous decode requests.
@@ -75,6 +76,7 @@
// Not recoverable: make a new VideoDecoder if needed.
[RaisesException] void close();
- // Which state the decoder is in, indicating which methods can be called.
- readonly attribute CodecState state;
+ // Call prior to configure() to determine whether config will be supported.
+ [CallWith=ScriptState, RaisesException]
+ static Promise<VideoDecoderSupport> isConfigSupported(VideoDecoderConfig config);
};
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 f91373858b6..5c979e41b1b 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
@@ -78,14 +78,14 @@ class MediaVideoTaskWrapper {
base::WeakPtr<CrossThreadVideoDecoderClient> weak_client,
ExecutionContext& execution_context,
media::GpuVideoAcceleratorFactories* gpu_factories,
- media::MediaLog* media_log,
+ std::unique_ptr<media::MediaLog> media_log,
scoped_refptr<base::SequencedTaskRunner> media_task_runner,
scoped_refptr<base::SequencedTaskRunner> main_task_runner)
: weak_client_(std::move(weak_client)),
media_task_runner_(std::move(media_task_runner)),
main_task_runner_(std::move(main_task_runner)),
gpu_factories_(gpu_factories),
- media_log_(media_log) {
+ media_log_(std::move(media_log)) {
DVLOG(2) << __func__;
DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -97,7 +97,7 @@ class MediaVideoTaskWrapper {
media_interface_factory.InitWithNewPipeAndPassReceiver());
// Mojo remote must be bound on media thread where it will be used.
- //|Unretained| is safe because |this| must be destroyed on the media task
+ // |Unretained| is safe because |this| must be destroyed on the media task
// runner.
PostCrossThreadTask(
*media_task_runner_, FROM_HERE,
@@ -169,20 +169,44 @@ class MediaVideoTaskWrapper {
weak_factory_.GetWeakPtr(), cb_id));
}
+ void UpdateHardwarePreference(HardwarePreference preference) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (hardware_preference_ != preference) {
+ hardware_preference_ = preference;
+ decoder_factory_needs_update_ = true;
+ }
+ }
+
private:
void BindOnTaskRunner(
mojo::PendingRemote<media::mojom::InterfaceFactory> interface_factory) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
media_interface_factory_.Bind(std::move(interface_factory));
+ }
+
+ void UpdateDecoderFactory() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(decoder_factory_needs_update_);
+
+ decoder_factory_needs_update_ = false;
// Bind the |interface_factory_| above before passing to
// |external_decoder_factory|.
std::unique_ptr<media::DecoderFactory> external_decoder_factory;
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
- external_decoder_factory = std::make_unique<media::MojoDecoderFactory>(
- media_interface_factory_.get());
+ if (hardware_preference_ != HardwarePreference::kDeny) {
+ external_decoder_factory = std::make_unique<media::MojoDecoderFactory>(
+ media_interface_factory_.get());
+ }
#endif
+
+ if (hardware_preference_ == HardwarePreference::kRequire) {
+ decoder_factory_ = std::move(external_decoder_factory);
+ return;
+ }
+
decoder_factory_ = std::make_unique<media::DefaultDecoderFactory>(
std::move(external_decoder_factory));
}
@@ -201,12 +225,20 @@ class MediaVideoTaskWrapper {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (decoder_factory_needs_update_)
+ UpdateDecoderFactory();
+
std::vector<std::unique_ptr<media::VideoDecoder>> video_decoders;
- decoder_factory_->CreateVideoDecoders(
- media_task_runner_, gpu_factories_, media_log_,
- WTF::BindRepeating(&MediaVideoTaskWrapper::OnRequestOverlayInfo,
- weak_factory_.GetWeakPtr()),
- target_color_space_, &video_decoders);
+
+ // We can end up with a null |decoder_factory_| if
+ // |hardware_preference_| filtered out all available factories.
+ if (decoder_factory_) {
+ decoder_factory_->CreateVideoDecoders(
+ media_task_runner_, gpu_factories_, media_log_.get(),
+ WTF::BindRepeating(&MediaVideoTaskWrapper::OnRequestOverlayInfo,
+ weak_factory_.GetWeakPtr()),
+ target_color_space_, &video_decoders);
+ }
return video_decoders;
}
@@ -225,10 +257,10 @@ class MediaVideoTaskWrapper {
base::Optional<DecoderDetails> decoder_details;
if (decoder_) {
status = media::OkStatus();
- decoder_details = DecoderDetails({decoder_->GetDisplayName(),
- decoder_->IsPlatformDecoder(),
- decoder_->NeedsBitstreamConversion(),
- decoder_->GetMaxDecodeRequests()});
+ decoder_details = DecoderDetails(
+ {decoder_->GetDisplayName(), decoder_->GetDecoderType(),
+ decoder_->IsPlatformDecoder(), decoder_->NeedsBitstreamConversion(),
+ decoder_->GetMaxDecodeRequests()});
}
// Fire |init_cb|.
@@ -274,11 +306,13 @@ class MediaVideoTaskWrapper {
media::GpuVideoAcceleratorFactories* gpu_factories_;
mojo::Remote<media::mojom::InterfaceFactory> media_interface_factory_;
std::unique_ptr<WebCodecsVideoDecoderSelector> selector_;
- std::unique_ptr<media::DefaultDecoderFactory> decoder_factory_;
+ std::unique_ptr<media::DecoderFactory> decoder_factory_;
std::unique_ptr<media::VideoDecoder> decoder_;
gfx::ColorSpace target_color_space_;
+ HardwarePreference hardware_preference_ = HardwarePreference::kAllow;
+ bool decoder_factory_needs_update_ = true;
- media::MediaLog* media_log_;
+ std::unique_ptr<media::MediaLog> media_log_;
SEQUENCE_CHECKER(sequence_checker_);
@@ -303,8 +337,8 @@ VideoDecoderBroker::VideoDecoderBroker(
: worker_pool::CreateSequencedTaskRunner({})) {
DVLOG(2) << __func__;
media_tasks_ = std::make_unique<MediaVideoTaskWrapper>(
- weak_factory_.GetWeakPtr(), execution_context, gpu_factories, media_log,
- media_task_runner_,
+ weak_factory_.GetWeakPtr(), execution_context, gpu_factories,
+ media_log->Clone(), media_task_runner_,
execution_context.GetTaskRunner(TaskType::kInternalMedia));
}
@@ -315,6 +349,11 @@ VideoDecoderBroker::~VideoDecoderBroker() {
media_task_runner_->DeleteSoon(FROM_HERE, std::move(media_tasks_));
}
+media::VideoDecoderType VideoDecoderBroker::GetDecoderType() const {
+ return decoder_details_ ? decoder_details_->decoder_id
+ : media::VideoDecoderType::kBroker;
+}
+
std::string VideoDecoderBroker::GetDisplayName() const {
return decoder_details_ ? decoder_details_->display_name
: VideoDecoderBroker::kDefaultDisplayName;
@@ -324,6 +363,15 @@ bool VideoDecoderBroker::IsPlatformDecoder() const {
return decoder_details_ ? decoder_details_->is_platform_decoder : false;
}
+void VideoDecoderBroker::SetHardwarePreference(
+ HardwarePreference hardware_preference) {
+ PostCrossThreadTask(
+ *media_task_runner_, FROM_HERE,
+ WTF::CrossThreadBindOnce(&MediaVideoTaskWrapper::UpdateHardwarePreference,
+ WTF::CrossThreadUnretained(media_tasks_.get()),
+ hardware_preference));
+}
+
void VideoDecoderBroker::Initialize(const media::VideoDecoderConfig& config,
bool low_delay,
media::CdmContext* cdm_context,
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 9cc7863ebd4..733fe10706a 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
@@ -20,6 +20,7 @@
#include "media/video/gpu_video_accelerator_factories.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace base {
@@ -45,6 +46,7 @@ class CrossThreadVideoDecoderClient {
public:
struct DecoderDetails {
std::string display_name;
+ media::VideoDecoderType decoder_id;
bool is_platform_decoder;
bool needs_bitstream_conversion;
int max_decode_requests;
@@ -88,6 +90,7 @@ class MODULES_EXPORT VideoDecoderBroker : public media::VideoDecoder,
VideoDecoderBroker& operator=(const VideoDecoderBroker&) = delete;
// VideoDecoder implementation.
+ media::VideoDecoderType GetDecoderType() const override;
std::string GetDisplayName() const override;
bool IsPlatformDecoder() const override;
void Initialize(const media::VideoDecoderConfig& config,
@@ -103,6 +106,8 @@ class MODULES_EXPORT VideoDecoderBroker : public media::VideoDecoder,
bool CanReadWithoutStalling() const override;
int GetMaxDecodeRequests() const override;
+ void SetHardwarePreference(HardwarePreference hardware_preference);
+
private:
// Creates a new (incremented) callback ID from |last_callback_id_| for
// mapping in |pending_decode_cb_map_|.
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 d675c737088..cf91480dd28 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
@@ -6,11 +6,13 @@
#include <vector>
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/decode_status.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
@@ -32,7 +34,6 @@
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h"
-
using ::testing::_;
using ::testing::Return;
@@ -65,7 +66,7 @@ class FakeGpuVideoDecoder : public media::FakeVideoDecoder {
media::VideoFrame::ReleaseMailboxCB(), current_config_.coded_size(),
current_config_.visible_rect(), current_config_.natural_size(),
buffer.timestamp());
- frame->metadata()->power_efficient = true;
+ frame->metadata().power_efficient = true;
return frame;
}
@@ -149,6 +150,13 @@ class FakeInterfaceFactory : public media::mojom::InterfaceFactory {
mojo::NullRemote(), "CDM creation not supported");
}
+#if defined(OS_WIN)
+ void CreateMediaFoundationRenderer(
+ mojo::PendingReceiver<media::mojom::Renderer> receiver,
+ mojo::PendingReceiver<media::mojom::MediaFoundationRendererExtension>
+ renderer_extension_receiver) override {}
+#endif // defined(OS_WIN)
+
private:
media::MojoCdmServiceContext cdm_service_context_;
FakeMojoMediaClient mojo_media_client_;
@@ -160,10 +168,27 @@ class FakeInterfaceFactory : public media::mojom::InterfaceFactory {
class VideoDecoderBrokerTest : public testing::Test {
public:
- VideoDecoderBrokerTest() = default;
+ VideoDecoderBrokerTest() {
+ // Make sure we have the option of creating HW or SW decoders.
+ std::vector<base::Feature> disabled_features{
+ media::kForceHardwareVideoDecoders};
+
+ // Make it easier to switch between HW and SW decoders, by initializing with
+ // configs with a small height.
+ std::vector<base::Feature> enabled_features{
+ media::kResolutionBasedDecoderPriority};
+
+ feature_list_.InitWithFeatures(enabled_features, disabled_features);
+ }
+
~VideoDecoderBrokerTest() override {
if (media_thread_)
media_thread_->Stop();
+
+ // Clean up this override, or else we we fail or DCHECK in SetupMojo().
+ Platform::Current()->GetBrowserInterfaceBroker()->SetBinderForTesting(
+ media::mojom::InterfaceFactory::Name_,
+ base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)>());
}
void OnInitWithClosure(base::RepeatingClosure done_cb, media::Status status) {
@@ -224,9 +249,15 @@ class VideoDecoderBrokerTest : public testing::Test {
execution_context, gpu_factories_.get(), &null_media_log_);
}
- void InitializeDecoder(media::VideoDecoderConfig config) {
+ void InitializeDecoder(media::VideoDecoderConfig config,
+ bool expect_success = true) {
base::RunLoop run_loop;
- EXPECT_CALL(*this, OnInit(media::SameStatusCode(media::OkStatus())));
+ if (expect_success) {
+ EXPECT_CALL(*this, OnInit(media::SameStatusCode(media::OkStatus())));
+ } else {
+ EXPECT_CALL(*this, OnInit(media::SameStatusCode(media::Status(
+ media::StatusCode::kDecoderUnsupportedConfig))));
+ }
decoder_broker_->Initialize(
config, false /*low_delay*/, nullptr /* cdm_context */,
WTF::Bind(&VideoDecoderBrokerTest::OnInitWithClosure,
@@ -281,6 +312,8 @@ class VideoDecoderBrokerTest : public testing::Test {
std::unique_ptr<media::MockGpuVideoAcceleratorFactories> gpu_factories_;
std::unique_ptr<FakeInterfaceFactory> interface_factory_;
std::unique_ptr<base::Thread> media_thread_;
+
+ base::test::ScopedFeatureList feature_list_;
};
TEST_F(VideoDecoderBrokerTest, Decode_Uninitialized) {
@@ -322,7 +355,85 @@ TEST_F(VideoDecoderBrokerTest, Decode_NoMojoDecoder) {
ResetDecoder();
}
+// Makes sure that no software decoder is returned if we required acceleration,
+// even if this means that no decoder is selected.
+TEST_F(VideoDecoderBrokerTest, Init_RequireAcceleration) {
+ V8TestingScope v8_scope;
+
+ ConstructDecoder(*v8_scope.GetExecutionContext());
+ EXPECT_EQ(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
+
+ decoder_broker_->SetHardwarePreference(HardwarePreference::kRequire);
+
+ InitializeDecoder(media::TestVideoConfig::Normal(), /*expect_success*/ false);
+ EXPECT_EQ(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
+}
+
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
+TEST_F(VideoDecoderBrokerTest, Init_DenyAcceleration) {
+ V8TestingScope v8_scope;
+ ExecutionContext* execution_context = v8_scope.GetExecutionContext();
+
+ SetupMojo(*execution_context);
+ ConstructDecoder(*execution_context);
+ EXPECT_EQ(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
+
+ decoder_broker_->SetHardwarePreference(HardwarePreference::kDeny);
+
+ // Use an extra-large video to push us towards a hardware decoder.
+ media::VideoDecoderConfig config = media::TestVideoConfig::ExtraLarge();
+ InitializeDecoder(config);
+ EXPECT_NE(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
+ EXPECT_FALSE(IsPlatformDecoder());
+}
+
+TEST_F(VideoDecoderBrokerTest, Decode_MultipleAccelerationPreferences) {
+ V8TestingScope v8_scope;
+ ExecutionContext* execution_context = v8_scope.GetExecutionContext();
+
+ SetupMojo(*execution_context);
+ ConstructDecoder(*execution_context);
+ EXPECT_EQ(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
+
+ // Make sure we can decode software only.
+ decoder_broker_->SetHardwarePreference(HardwarePreference::kDeny);
+ InitializeDecoder(media::TestVideoConfig::Normal());
+ DecodeBuffer(media::ReadTestDataFile("vp8-I-frame-320x120"));
+ DecodeBuffer(media::DecoderBuffer::CreateEOSBuffer());
+ ASSERT_EQ(1U, output_frames_.size());
+
+ // Make sure we can decoder with hardware only.
+ decoder_broker_->SetHardwarePreference(HardwarePreference::kRequire);
+
+ // Use an extra-large video to ensure we don't get a software decoder.
+ media::VideoDecoderConfig large_config = media::TestVideoConfig::ExtraLarge();
+ InitializeDecoder(large_config);
+ DecodeBuffer(media::CreateFakeVideoBufferForTest(
+ large_config, base::TimeDelta(), base::TimeDelta::FromMilliseconds(33)));
+ DecodeBuffer(media::DecoderBuffer::CreateEOSBuffer());
+ ASSERT_EQ(2U, output_frames_.size());
+
+ // Make sure we can decode with both HW or SW as appropriate.
+ decoder_broker_->SetHardwarePreference(HardwarePreference::kAllow);
+
+ // Use a large frame to force hardware decode.
+ InitializeDecoder(large_config);
+ DecodeBuffer(media::CreateFakeVideoBufferForTest(
+ large_config, base::TimeDelta(), base::TimeDelta::FromMilliseconds(33)));
+ DecodeBuffer(media::DecoderBuffer::CreateEOSBuffer());
+ ASSERT_EQ(3U, output_frames_.size());
+ EXPECT_TRUE(IsPlatformDecoder());
+
+ // Use a small frame to force software decode, without changing the
+ // acceleration preference.
+ InitializeDecoder(media::TestVideoConfig::Normal());
+ DecodeBuffer(media::ReadTestDataFile("vp8-I-frame-320x120"));
+ DecodeBuffer(media::DecoderBuffer::CreateEOSBuffer());
+ ASSERT_EQ(4U, output_frames_.size());
+
+ ResetDecoder();
+}
+
TEST_F(VideoDecoderBrokerTest, Decode_WithMojoDecoder) {
V8TestingScope v8_scope;
ExecutionContext* execution_context = v8_scope.GetExecutionContext();
@@ -331,7 +442,7 @@ TEST_F(VideoDecoderBrokerTest, Decode_WithMojoDecoder) {
ConstructDecoder(*execution_context);
EXPECT_EQ(GetDisplayName(), "EmptyWebCodecsVideoDecoder");
- // Use an extra-large video to ensure we don't get a software decoder
+ // Use an extra-large video to ensure we don't get a software decoder.
media::VideoDecoderConfig config = media::TestVideoConfig::ExtraLarge();
InitializeDecoder(config);
EXPECT_EQ(GetDisplayName(), "MojoVideoDecoder");
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl
index f770f2d2804..4e02d1e7e1d 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_config.idl
@@ -4,6 +4,9 @@
// https://github.com/WICG/web-codecs
+// NOTE: Keep this strucutre in sync with CopyConfig() defined in
+// video_decoder.cc.
+
dictionary VideoDecoderConfig {
// Codec string, eg. "avc1.42001e" or "vp09.00.10.08".
// TODO(sandersd): Should we accept "avc1" when |description| is provided?
@@ -32,4 +35,6 @@ dictionary VideoDecoderConfig {
// TODO(sandersd): color space.
// TODO(sandersd): Constraints (sequential access) and requirements
// (imagebitmap, colorspace conversion).
+
+ HardwarePreference hardwareAcceleration = "allow";
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_fuzzer.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_fuzzer.cc
index 73f1b31ae9b..5315766a650 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_fuzzer.cc
@@ -8,7 +8,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.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/testing/dummy_page_holder.h"
@@ -70,36 +70,38 @@ DEFINE_TEXT_PROTO_FUZZER(
Persistent<VideoDecoder> video_decoder = VideoDecoder::Create(
script_state, video_decoder_init, IGNORE_EXCEPTION_FOR_TESTING);
- for (auto& invocation : proto.invocations()) {
- switch (invocation.Api_case()) {
- case wc_fuzzer::VideoDecoderApiInvocation::kConfigure:
- video_decoder->configure(
- MakeVideoDecoderConfig(invocation.configure()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoDecoderApiInvocation::kDecode:
- video_decoder->decode(
- MakeEncodedVideoChunk(invocation.decode().chunk()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoDecoderApiInvocation::kFlush: {
- // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
- // of the flush promise.
- video_decoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
- break;
+ if (video_decoder) {
+ for (auto& invocation : proto.invocations()) {
+ switch (invocation.Api_case()) {
+ case wc_fuzzer::VideoDecoderApiInvocation::kConfigure:
+ video_decoder->configure(
+ MakeVideoDecoderConfig(invocation.configure()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoDecoderApiInvocation::kDecode:
+ video_decoder->decode(
+ MakeEncodedVideoChunk(invocation.decode().chunk()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoDecoderApiInvocation::kFlush: {
+ // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
+ // of the flush promise.
+ video_decoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ }
+ case wc_fuzzer::VideoDecoderApiInvocation::kReset:
+ video_decoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoDecoderApiInvocation::kClose:
+ video_decoder->close(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoDecoderApiInvocation::API_NOT_SET:
+ break;
}
- case wc_fuzzer::VideoDecoderApiInvocation::kReset:
- video_decoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoDecoderApiInvocation::kClose:
- video_decoder->close(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoDecoderApiInvocation::API_NOT_SET:
- break;
- }
- // Give other tasks a chance to run (e.g. calling our output callback).
- base::RunLoop().RunUntilIdle();
+ // Give other tasks a chance to run (e.g. calling our output callback).
+ base::RunLoop().RunUntilIdle();
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_support.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_support.idl
new file mode 100644
index 00000000000..993e55e6ba3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_support.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/web-codecs
+
+dictionary VideoDecoderSupport {
+ boolean supported;
+ VideoDecoderConfig config;
+}; \ No newline at end of file
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 c11c864312d..fe54014cd55 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -11,19 +11,16 @@
#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
+#include "components/viz/common/gpu/raster_context_provider.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/raster_interface.h"
#include "media/base/async_destroy_video_encoder.h"
-#include "media/base/media_util.h"
#include "media/base/mime_util.h"
#include "media/base/offloading_video_encoder.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
+#include "media/base/video_util.h"
#include "media/video/gpu_video_accelerator_factories.h"
#include "media/video/video_encode_accelerator_adapter.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
@@ -32,12 +29,12 @@
#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_avc_encoder_config.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"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/core/inspector/inspector_media_context_impl.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h"
@@ -46,17 +43,43 @@
#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/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/libyuv/include/libyuv.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.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
+
+namespace WTF {
+
+template <>
+struct CrossThreadCopier<media::Status>
+ : public CrossThreadCopierPassThrough<media::Status> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+} // namespace WTF
namespace blink {
namespace {
+
+media::GpuVideoAcceleratorFactories* GetGpuFactoriesOnMainThread() {
+ DCHECK(IsMainThread());
+ return Platform::Current()->GetGpuFactories();
+}
+
std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder(
media::VideoCodecProfile profile,
- const media::VideoEncoder::Options& options) {
- auto* gpu_factories = Platform::Current()->GetGpuFactories();
+ const media::VideoEncoder::Options& options,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled())
return nullptr;
@@ -96,7 +119,7 @@ std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder(
if (!found_supported_profile)
return nullptr;
- auto task_runner = Thread::MainThread()->GetTaskRunner();
+ auto task_runner = Thread::Current()->GetTaskRunner();
return std::make_unique<
media::AsyncDestroyVideoEncoder<media::VideoEncodeAcceleratorAdapter>>(
std::make_unique<media::VideoEncodeAcceleratorAdapter>(
@@ -119,88 +142,31 @@ std::unique_ptr<media::VideoEncoder> CreateOpenH264VideoEncoder() {
#endif // BUILDFLAG(ENABLE_OPENH264)
}
-scoped_refptr<media::VideoFrame> ConvertToI420Frame(
- scoped_refptr<media::VideoFrame> frame) {
- DCHECK_EQ(frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
-
- // TODO: Support more pixel formats
- if (frame->format() != media::VideoPixelFormat::PIXEL_FORMAT_NV12)
- return nullptr;
+} // namespace
- auto* gmb = frame->GetGpuMemoryBuffer();
- if (!gmb->Map())
- return nullptr;
- scoped_refptr<media::VideoFrame> i420_frame = media::VideoFrame::CreateFrame(
- media::VideoPixelFormat::PIXEL_FORMAT_I420, frame->coded_size(),
- frame->visible_rect(), frame->natural_size(), frame->timestamp());
- auto ret = libyuv::NV12ToI420(
- static_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
- static_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
- i420_frame->data(media::VideoFrame::kYPlane),
- i420_frame->stride(media::VideoFrame::kYPlane),
- i420_frame->data(media::VideoFrame::kUPlane),
- i420_frame->stride(media::VideoFrame::kUPlane),
- i420_frame->data(media::VideoFrame::kVPlane),
- i420_frame->stride(media::VideoFrame::kVPlane),
- frame->coded_size().width(), frame->coded_size().height());
- gmb->Unmap();
- if (ret)
- return nullptr;
- return i420_frame;
+// static
+const char* VideoEncoderTraits::GetNameForDevTools() {
+ return "VideoEncoder(WebCodecs)";
}
-} // namespace
-
// static
VideoEncoder* VideoEncoder::Create(ScriptState* script_state,
const VideoEncoderInit* init,
ExceptionState& exception_state) {
- return MakeGarbageCollected<VideoEncoder>(script_state, init,
- exception_state);
+ auto* result =
+ MakeGarbageCollected<VideoEncoder>(script_state, init, exception_state);
+ return exception_state.HadException() ? nullptr : result;
}
VideoEncoder::VideoEncoder(ScriptState* script_state,
const VideoEncoderInit* init,
ExceptionState& exception_state)
- : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
- state_(V8CodecState::Enum::kUnconfigured),
- script_state_(script_state) {
+ : Base(script_state, init, exception_state) {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kWebCodecs);
-
- ExecutionContext* context = GetExecutionContext();
-
- DCHECK(context);
-
- parent_media_log_ = Platform::Current()->GetMediaLog(
- MediaInspectorContextImpl::From(*context),
- Thread::MainThread()->GetTaskRunner());
-
- if (!parent_media_log_)
- parent_media_log_ = std::make_unique<media::NullMediaLog>();
-
- // This allows us to destroy |parent_media_log_| and stop logging,
- // without causing problems to |media_log_| users.
- media_log_ = parent_media_log_->Clone();
-
- media_log_->SetProperty<media::MediaLogProperty::kFrameTitle>(
- std::string("VideoEncoder(WebCodecs)"));
- media_log_->SetProperty<media::MediaLogProperty::kFrameUrl>(
- GetExecutionContext()->Url().GetString().Ascii());
-
- output_callback_ = init->output();
- if (init->hasError())
- error_callback_ = init->error();
-}
-
-VideoEncoder::~VideoEncoder() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-int32_t VideoEncoder::encodeQueueSize() {
- return requested_encodes_;
-}
+VideoEncoder::~VideoEncoder() = default;
VideoEncoder::ParsedConfig* VideoEncoder::ParseConfig(
const VideoEncoderConfig* config,
@@ -229,18 +195,10 @@ VideoEncoder::ParsedConfig* VideoEncoder::ParseConfig(
parsed->options.bitrate = config->bitrate();
// The IDL defines a default value of "allow".
- DCHECK(config->hasAcceleration());
-
- std::string preference = IDLEnumAsString(config->acceleration()).Utf8();
- if (preference == "allow") {
- parsed->acc_pref = AccelerationPreference::kAllow;
- } else if (preference == "require") {
- parsed->acc_pref = AccelerationPreference::kRequire;
- } else if (preference == "deny") {
- parsed->acc_pref = AccelerationPreference::kDeny;
- } else {
- NOTREACHED();
- }
+ DCHECK(config->hasHardwareAcceleration());
+
+ parsed->hw_pref = StringToHardwarePreference(
+ IDLEnumAsString(config->hardwareAcceleration()));
bool is_codec_ambiguous = true;
parsed->codec = media::kUnknownVideoCodec;
@@ -263,6 +221,26 @@ VideoEncoder::ParsedConfig* VideoEncoder::ParseConfig(
return nullptr;
}
+ // We are done with the parsing.
+ if (!config->hasAvc())
+ return parsed;
+
+ // We should only get here with H264 codecs.
+ if (parsed->codec != media::VideoCodec::kCodecH264) {
+ exception_state.ThrowTypeError(
+ "'avcOptions' can only be used with AVC codecs");
+ return nullptr;
+ }
+
+ std::string avc_format = IDLEnumAsString(config->avc()->format()).Utf8();
+ if (avc_format == "avc") {
+ parsed->options.avc.produce_annexb = false;
+ } else if (avc_format == "annexb") {
+ parsed->options.avc.produce_annexb = true;
+ } else {
+ NOTREACHED();
+ }
+
return parsed;
}
@@ -270,20 +248,9 @@ bool VideoEncoder::VerifyCodecSupport(ParsedConfig* config,
ExceptionState& exception_state) {
switch (config->codec) {
case media::kCodecVP8:
- if (config->acc_pref == AccelerationPreference::kRequire) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Accelerated vp8 is not supported");
- return false;
- }
break;
case media::kCodecVP9:
- if (config->acc_pref == AccelerationPreference::kRequire) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Accelerated vp9 is not supported");
- return false;
- }
-
// TODO(https://crbug.com/1119636): Implement / call a proper method for
// detecting support of encoder configs.
if (config->profile == media::VideoCodecProfile::VP9PROFILE_PROFILE1 ||
@@ -307,37 +274,93 @@ bool VideoEncoder::VerifyCodecSupport(ParsedConfig* config,
return true;
}
+VideoFrame* VideoEncoder::CloneFrame(VideoFrame* frame,
+ ExecutionContext* context) {
+ return frame->CloneFromNative(context);
+}
+
void VideoEncoder::UpdateEncoderLog(std::string encoder_name,
bool is_hw_accelerated) {
// TODO(https://crbug.com/1139089) : Add encoder properties.
- media_log_->SetProperty<media::MediaLogProperty::kVideoDecoderName>(
- encoder_name);
- media_log_->SetProperty<media::MediaLogProperty::kIsPlatformVideoDecoder>(
+ media::MediaLog* log = logger_->log();
+
+ log->SetProperty<media::MediaLogProperty::kVideoEncoderName>(encoder_name);
+ log->SetProperty<media::MediaLogProperty::kIsPlatformVideoEncoder>(
is_hw_accelerated);
}
+void VideoEncoder::CreateAndInitializeEncoderWithoutAcceleration(
+ Request* request) {
+ CreateAndInitializeEncoderOnEncoderSupportKnown(request, nullptr);
+}
+
+void VideoEncoder::CreateAndInitializeEncoderOnEncoderSupportKnown(
+ Request* request,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ DCHECK(active_config_);
+ DCHECK_EQ(request->type, Request::Type::kConfigure);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ media_encoder_ = CreateMediaVideoEncoder(*active_config_, gpu_factories);
+ if (!media_encoder_) {
+ HandleError(logger_->MakeException(
+ "Encoder creation error.",
+ media::Status(media::StatusCode::kEncoderInitializationError,
+ "Unable to create encoder (most likely unsupported "
+ "codec/acceleration requirement combination)")));
+ return;
+ }
+
+ auto output_cb = ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+ &VideoEncoder::CallOutputCallback, WrapCrossThreadWeakPersistent(this),
+ // We can't use |active_config_| from |this| because it can change by
+ // the time the callback is executed.
+ WrapCrossThreadPersistent(active_config_.Get()), reset_count_));
+
+ auto done_callback = [](VideoEncoder* self, Request* req,
+ media::Status status) {
+ if (!self || self->reset_count_ != req->reset_count)
+ return;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
+ DCHECK(self->active_config_);
+
+ if (!status.is_ok()) {
+ self->HandleError(self->logger_->MakeException(
+ "Encoder initialization error.", status));
+ }
+
+ self->stall_request_processing_ = false;
+ self->ProcessRequests();
+ };
+
+ media_encoder_->Initialize(
+ active_config_->profile, active_config_->options, std::move(output_cb),
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ done_callback, WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request))));
+}
+
std::unique_ptr<media::VideoEncoder> VideoEncoder::CreateMediaVideoEncoder(
- const ParsedConfig& config) {
+ const ParsedConfig& config,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
// TODO(https://crbug.com/1119636): Implement / call a proper method for
// detecting support of encoder configs.
- switch (config.acc_pref) {
- case AccelerationPreference::kRequire: {
- auto result =
- CreateAcceleratedVideoEncoder(config.profile, config.options);
- is_hw_accelerated_ = !!result;
+ switch (config.hw_pref) {
+ case HardwarePreference::kRequire: {
+ auto result = CreateAcceleratedVideoEncoder(
+ config.profile, config.options, gpu_factories);
if (result)
UpdateEncoderLog("AcceleratedVideoEncoder", true);
return result;
}
- case AccelerationPreference::kAllow:
- if (auto result =
- CreateAcceleratedVideoEncoder(config.profile, config.options)) {
- is_hw_accelerated_ = true;
+ case HardwarePreference::kAllow:
+ if (auto result = CreateAcceleratedVideoEncoder(
+ config.profile, config.options, gpu_factories)) {
UpdateEncoderLog("AcceleratedVideoEncoder", true);
return result;
}
FALLTHROUGH;
- case AccelerationPreference::kDeny: {
+ case HardwarePreference::kDeny: {
std::unique_ptr<media::VideoEncoder> result;
switch (config.codec) {
case media::kCodecVP8:
@@ -352,7 +375,6 @@ std::unique_ptr<media::VideoEncoder> VideoEncoder::CreateMediaVideoEncoder(
default:
return nullptr;
}
- is_hw_accelerated_ = false;
if (!result)
return nullptr;
return std::make_unique<media::OffloadingVideoEncoder>(std::move(result));
@@ -367,202 +389,12 @@ std::unique_ptr<media::VideoEncoder> VideoEncoder::CreateMediaVideoEncoder(
bool VideoEncoder::CanReconfigure(ParsedConfig& original_config,
ParsedConfig& new_config) {
// Reconfigure is intended for things that don't require changing underlying
- // codec implementatio and can be changed on the fly.
+ // codec implementation and can be changed on the fly.
return original_config.codec == new_config.codec &&
original_config.profile == new_config.profile &&
original_config.level == new_config.level &&
original_config.color_space == new_config.color_space &&
- original_config.acc_pref == new_config.acc_pref;
-}
-
-void VideoEncoder::configure(const VideoEncoderConfig* config,
- ExceptionState& exception_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (ThrowIfCodecStateClosed(state_, "configure", exception_state))
- return;
-
- auto* parsed_config = ParseConfig(config, exception_state);
- if (!parsed_config) {
- DCHECK(exception_state.HadException());
- return;
- }
-
- if (!VerifyCodecSupport(parsed_config, exception_state)) {
- DCHECK(exception_state.HadException());
- return;
- }
-
- Request* request = MakeGarbageCollected<Request>();
- request->reset_count = reset_count_;
- if (media_encoder_ && active_config_ &&
- state_.AsEnum() == V8CodecState::Enum::kConfigured &&
- CanReconfigure(*active_config_, *parsed_config)) {
- request->type = Request::Type::kReconfigure;
- } else {
- state_ = V8CodecState(V8CodecState::Enum::kConfigured);
- request->type = Request::Type::kConfigure;
- }
- active_config_ = parsed_config;
- EnqueueRequest(request);
-}
-
-void VideoEncoder::encode(VideoFrame* frame,
- const VideoEncoderEncodeOptions* opts,
- ExceptionState& exception_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (ThrowIfCodecStateClosed(state_, "encode", exception_state))
- return;
-
- if (ThrowIfCodecStateUnconfigured(state_, "encode", exception_state))
- return;
-
- // This will fail if |frame| is already destroyed.
- auto* internal_frame = frame->clone(exception_state);
-
- if (!internal_frame) {
- // Set a more helpful exception than the cloning error message.
- exception_state.ClearException();
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "Cannot encode destroyed frame.");
- return;
- }
-
- DCHECK(active_config_);
- if (internal_frame->frame()->coded_size() !=
- active_config_->options.frame_size) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kOperationError,
- "Frame size doesn't match initial encoder parameters.");
-
- // Free the temporary clone.
- internal_frame->destroy();
- return;
- }
-
- // At this point, we have "consumed" the frame, and will destroy the clone
- // in ProcessEncode().
- frame->destroy();
-
- Request* request = MakeGarbageCollected<Request>();
- request->reset_count = reset_count_;
- request->type = Request::Type::kEncode;
- request->frame = internal_frame;
- request->encodeOpts = opts;
- ++requested_encodes_;
- EnqueueRequest(request);
-}
-
-void VideoEncoder::close(ExceptionState& exception_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (ThrowIfCodecStateClosed(state_, "close", exception_state))
- return;
-
- state_ = V8CodecState(V8CodecState::Enum::kClosed);
-
- ResetInternal();
- media_encoder_.reset();
- output_callback_.Clear();
- error_callback_.Clear();
-}
-
-ScriptPromise VideoEncoder::flush(ExceptionState& exception_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (ThrowIfCodecStateClosed(state_, "flush", exception_state))
- return ScriptPromise();
-
- if (ThrowIfCodecStateUnconfigured(state_, "flush", exception_state))
- return ScriptPromise();
-
- Request* request = MakeGarbageCollected<Request>();
- request->resolver =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
- request->reset_count = reset_count_;
- request->type = Request::Type::kFlush;
- EnqueueRequest(request);
- return request->resolver->Promise();
-}
-
-void VideoEncoder::reset(ExceptionState& exception_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (ThrowIfCodecStateClosed(state_, "reset", exception_state))
- return;
-
- state_ = V8CodecState(V8CodecState::Enum::kUnconfigured);
- ResetInternal();
- media_encoder_.reset();
-}
-
-void VideoEncoder::ResetInternal() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- reset_count_++;
- while (!requests_.empty()) {
- Request* pending_req = requests_.TakeFirst();
- DCHECK(pending_req);
- if (pending_req->resolver)
- pending_req->resolver.Release()->Resolve();
- }
- stall_request_processing_ = false;
-}
-
-void VideoEncoder::HandleError(DOMException* ex) {
- // Save a temp before we clear the callback.
- V8WebCodecsErrorCallback* error_callback = error_callback_.Get();
-
- state_ = V8CodecState(V8CodecState::Enum::kClosed);
-
- ResetInternal();
-
- // Errors are permanent. Shut everything down.
- error_callback_.Clear();
- media_encoder_.reset();
- output_callback_.Clear();
-
- if (!script_state_->ContextIsValid() || !error_callback)
- return;
-
- ScriptState::Scope scope(script_state_);
- error_callback->InvokeAndReportException(nullptr, ex);
-}
-
-void VideoEncoder::HandleError(std::string error_message,
- media::Status status) {
- media_log_->NotifyError(status);
-
- // For now, the only uses of this method correspond to kOperationErrors.
- auto* ex = MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kOperationError, error_message.c_str());
- HandleError(ex);
-}
-
-void VideoEncoder::EnqueueRequest(Request* request) {
- requests_.push_back(request);
- ProcessRequests();
-}
-
-void VideoEncoder::ProcessRequests() {
- while (!requests_.empty() && !stall_request_processing_) {
- Request* request = requests_.TakeFirst();
- DCHECK(request);
- switch (request->type) {
- case Request::Type::kConfigure:
- ProcessConfigure(request);
- break;
- case Request::Type::kReconfigure:
- ProcessReconfigure(request);
- break;
- case Request::Type::kEncode:
- ProcessEncode(request);
- break;
- case Request::Type::kFlush:
- ProcessFlush(request);
- break;
- default:
- NOTREACHED();
- }
- }
+ original_config.hw_pref == new_config.hw_pref;
}
void VideoEncoder::ProcessEncode(Request* request) {
@@ -578,33 +410,84 @@ void VideoEncoder::ProcessEncode(Request* request) {
return;
DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
if (!status.is_ok()) {
- self->HandleError("Encoding error.", status);
+ self->HandleError(
+ self->logger_->MakeException("Encoding error.", status));
}
self->ProcessRequests();
};
scoped_refptr<media::VideoFrame> frame = request->frame->frame();
- if (frame->HasGpuMemoryBuffer() && !is_hw_accelerated_) {
- frame = ConvertToI420Frame(frame);
+
+ // Currently underlying encoders can't handle frame backed by textures,
+ // so let's readback pixel data to CPU memory.
+ if (frame->HasTextures() && !frame->HasGpuMemoryBuffer()) {
+ scoped_refptr<viz::RasterContextProvider> raster_provider;
+ auto wrapper = SharedGpuContext::ContextProviderWrapper();
+ if (wrapper && wrapper->ContextProvider())
+ raster_provider = wrapper->ContextProvider()->RasterContextProvider();
+ if (raster_provider) {
+ auto* ri = raster_provider->RasterInterface();
+ auto* gr_context = raster_provider->GrContext();
+
+ frame = ReadbackTextureBackedFrameToMemorySync(*frame, ri, gr_context,
+ &readback_frame_pool_);
+ } else {
+ frame.reset();
+ }
+
if (!frame) {
- HandleError("Unexpected frame format.",
- media::Status(media::StatusCode::kEncoderFailedEncode,
- "Unexpected frame format"));
+ auto status = media::Status(media::StatusCode::kEncoderFailedEncode,
+ "Can't readback frame textures.");
+ auto task_runner = Thread::Current()->GetTaskRunner();
+ task_runner->PostTask(
+ FROM_HERE,
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ done_callback, WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request), std::move(status))));
return;
}
}
+ // Currently underlying encoders can't handle alpha channel, so let's
+ // wrap a frame with an alpha channel into a frame without it.
+ // For example such frames can come from 2D canvas context with alpha = true.
+ if (frame->storage_type() == media::VideoFrame::STORAGE_OWNED_MEMORY &&
+ frame->format() == media::PIXEL_FORMAT_I420A) {
+ frame = media::WrapAsI420VideoFrame(std::move(frame));
+ }
+
bool keyframe = request->encodeOpts->hasKeyFrameNonNull() &&
request->encodeOpts->keyFrameNonNull();
--requested_encodes_;
- media_encoder_->Encode(
- frame, keyframe,
- WTF::Bind(done_callback, WrapCrossThreadWeakPersistent(this),
- WrapCrossThreadPersistent(request)));
-
- // We passed a copy of frame() above, so this should be safe to destroy
- // here.
- request->frame->destroy();
+ media_encoder_->Encode(frame, keyframe,
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ done_callback, WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request))));
+
+ // We passed a copy of frame() above, so this should be safe to close here.
+ request->frame->close();
+}
+
+void VideoEncoder::OnReceivedGpuFactories(
+ Request* request,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) {
+ CreateAndInitializeEncoderWithoutAcceleration(request);
+ return;
+ }
+
+ // Delay create the hw encoder until HW encoder support is known, so that
+ // GetVideoEncodeAcceleratorSupportedProfiles() can give a reliable answer.
+ auto on_encoder_support_known_cb =
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ &VideoEncoder::CreateAndInitializeEncoderOnEncoderSupportKnown,
+ WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request),
+ CrossThreadUnretained(gpu_factories)));
+ gpu_factories->NotifyEncoderSupportKnown(
+ std::move(on_encoder_support_known_cb));
}
void VideoEncoder::ProcessConfigure(Request* request) {
@@ -613,42 +496,27 @@ void VideoEncoder::ProcessConfigure(Request* request) {
DCHECK(active_config_);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- media_encoder_ = CreateMediaVideoEncoder(*active_config_);
- if (!media_encoder_) {
- HandleError(
- "Encoder creation error.",
- media::Status(media::StatusCode::kEncoderInitializationError,
- "Unable to create encoder (most likely unsupported "
- "codec/acceleration requirement combination)"));
+ stall_request_processing_ = true;
+
+ if (active_config_->hw_pref == HardwarePreference::kDeny) {
+ CreateAndInitializeEncoderWithoutAcceleration(request);
return;
}
- auto output_cb = WTF::BindRepeating(
- &VideoEncoder::CallOutputCallback, WrapCrossThreadWeakPersistent(this),
- // We can't use |active_config_| from |this| because it can change by
- // the time the callback is executed.
- WrapCrossThreadPersistent(active_config_.Get()), reset_count_);
-
- auto done_callback = [](VideoEncoder* self, Request* req,
- media::Status status) {
- if (!self || self->reset_count_ != req->reset_count)
- return;
- DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
- DCHECK(self->active_config_);
-
- if (!status.is_ok()) {
- self->HandleError("Encoder initialization error.", status);
- }
+ if (IsMainThread()) {
+ OnReceivedGpuFactories(request, Platform::Current()->GetGpuFactories());
+ return;
+ }
- self->stall_request_processing_ = false;
- self->ProcessRequests();
- };
+ auto on_gpu_factories_cb = CrossThreadBindOnce(
+ &VideoEncoder::OnReceivedGpuFactories,
+ WrapCrossThreadWeakPersistent(this), WrapCrossThreadPersistent(request));
- stall_request_processing_ = true;
- media_encoder_->Initialize(
- active_config_->profile, active_config_->options, std::move(output_cb),
- WTF::Bind(done_callback, WrapCrossThreadWeakPersistent(this),
- WrapCrossThreadPersistent(request)));
+ Thread::MainThread()->GetTaskRunner()->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ ConvertToBaseOnceCallback(
+ CrossThreadBindOnce(&GetGpuFactoriesOnMainThread)),
+ ConvertToBaseOnceCallback(std::move(on_gpu_factories_cb)));
}
void VideoEncoder::ProcessReconfigure(Request* request) {
@@ -684,22 +552,26 @@ void VideoEncoder::ProcessReconfigure(Request* request) {
return;
DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
if (!status.is_ok()) {
- self->HandleError("Encoder reconfiguration error.", status);
+ self->HandleError(self->logger_->MakeException(
+ "Encoder initialization error.", status));
self->stall_request_processing_ = false;
return;
}
- auto output_cb = WTF::BindRepeating(
- &VideoEncoder::CallOutputCallback, WrapCrossThreadWeakPersistent(self),
- // We can't use |active_config_| from |this| because it can change by
- // the time the callback is executed.
- WrapCrossThreadPersistent(self->active_config_.Get()),
- self->reset_count_);
+ auto output_cb =
+ ConvertToBaseRepeatingCallback(WTF::CrossThreadBindRepeating(
+ &VideoEncoder::CallOutputCallback,
+ WrapCrossThreadWeakPersistent(self),
+ // We can't use |active_config_| from |this| because it can change
+ // by the time the callback is executed.
+ WrapCrossThreadPersistent(self->active_config_.Get()),
+ self->reset_count_));
self->media_encoder_->ChangeOptions(
self->active_config_->options, std::move(output_cb),
- WTF::Bind(reconf_callback, WrapCrossThreadWeakPersistent(self),
- WrapCrossThreadPersistent(req)));
+ ConvertToBaseOnceCallback(CrossThreadBindOnce(
+ reconf_callback, WrapCrossThreadWeakPersistent(self),
+ WrapCrossThreadPersistent(req))));
};
stall_request_processing_ = true;
@@ -728,7 +600,8 @@ void VideoEncoder::ProcessFlush(Request* request) {
if (status.is_ok()) {
req->resolver.Release()->Resolve();
} else {
- self->HandleError("Flushing error.", status);
+ self->HandleError(
+ self->logger_->MakeException("Flushing error.", status));
req->resolver.Release()->Reject();
}
self->stall_request_processing_ = false;
@@ -736,9 +609,9 @@ void VideoEncoder::ProcessFlush(Request* request) {
};
stall_request_processing_ = true;
- media_encoder_->Flush(WTF::Bind(done_callback,
- WrapCrossThreadWeakPersistent(this),
- WrapCrossThreadPersistent(request)));
+ media_encoder_->Flush(ConvertToBaseOnceCallback(
+ CrossThreadBindOnce(done_callback, WrapCrossThreadWeakPersistent(this),
+ WrapCrossThreadPersistent(request))));
}
void VideoEncoder::CallOutputCallback(
@@ -777,27 +650,4 @@ void VideoEncoder::CallOutputCallback(
output_callback_->InvokeAndReportException(nullptr, chunk, decoder_config);
}
-void VideoEncoder::ContextDestroyed() {
- parent_media_log_ = nullptr;
-}
-
-bool VideoEncoder::HasPendingActivity() const {
- return stall_request_processing_ || !requests_.empty();
-}
-
-void VideoEncoder::Trace(Visitor* visitor) const {
- visitor->Trace(active_config_);
- visitor->Trace(script_state_);
- visitor->Trace(output_callback_);
- visitor->Trace(error_callback_);
- visitor->Trace(requests_);
- ScriptWrappable::Trace(visitor);
- ExecutionContextLifecycleObserver::Trace(visitor);
-}
-
-void VideoEncoder::Request::Trace(Visitor* visitor) const {
- visitor->Trace(frame);
- visitor->Trace(encodeOpts);
- visitor->Trace(resolver);
-}
} // namespace blink
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 78d73d70463..7e185760c51 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -8,85 +8,36 @@
#include <memory>
#include "base/optional.h"
-#include "media/base/media_log.h"
-#include "media/base/status.h"
#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
#include "media/base/video_encoder.h"
-#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_codec_state.h"
+#include "media/base/video_frame_pool.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/encoder_base.h"
+#include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
namespace media {
+class GpuVideoAcceleratorFactories;
class VideoEncoder;
struct VideoEncoderOutput;
} // namespace media
namespace blink {
-class ExceptionState;
-enum class DOMExceptionCode;
class VideoEncoderConfig;
class VideoEncoderInit;
class VideoEncoderEncodeOptions;
-class Visitor;
-
-class MODULES_EXPORT VideoEncoder final
- : public ScriptWrappable,
- public ActiveScriptWrappable<VideoEncoder>,
- public ExecutionContextLifecycleObserver {
- DEFINE_WRAPPERTYPEINFO();
+class MODULES_EXPORT VideoEncoderTraits {
public:
- static VideoEncoder* Create(ScriptState*,
- const VideoEncoderInit*,
- ExceptionState&);
- VideoEncoder(ScriptState*, const VideoEncoderInit*, ExceptionState&);
- ~VideoEncoder() override;
-
- // video_encoder.idl implementation.
- int32_t encodeQueueSize();
-
- void encode(VideoFrame* frame,
- const VideoEncoderEncodeOptions*,
- ExceptionState&);
-
- void configure(const VideoEncoderConfig*, ExceptionState&);
-
- ScriptPromise flush(ExceptionState&);
-
- void reset(ExceptionState&);
-
- void close(ExceptionState&);
-
- String state() { return state_; }
-
- // ExecutionContextLifecycleObserver override.
- void ContextDestroyed() override;
-
- // ScriptWrappable override.
- bool HasPendingActivity() const override;
-
- // GarbageCollected override.
- void Trace(Visitor*) const override;
-
- private:
- enum class AccelerationPreference { kAllow, kDeny, kRequire };
-
- // TODO(ezemtsov): Replace this with a {Audio|Video}EncoderConfig.
struct ParsedConfig final : public GarbageCollected<ParsedConfig> {
media::VideoCodec codec;
media::VideoCodecProfile profile;
uint8_t level;
media::VideoColorSpace color_space;
- AccelerationPreference acc_pref;
+ HardwarePreference hw_pref;
media::VideoEncoder::Options options;
String codec_string;
@@ -94,83 +45,66 @@ class MODULES_EXPORT VideoEncoder final
void Trace(Visitor*) const {}
};
- struct Request final : public GarbageCollected<Request> {
- enum class Type {
- // Configure an encoder from scratch, possibly replacing the existing one.
- kConfigure,
- // Adjust options in the already configured encoder.
- kReconfigure,
- kEncode,
- kFlush,
- };
-
- void Trace(Visitor*) const;
-
- Type type;
- // Current value of VideoEncoder.reset_count_ when request was created.
- uint32_t reset_count = 0;
- Member<VideoFrame> frame; // used by kEncode
- Member<const VideoEncoderEncodeOptions> encodeOpts; // used by kEncode
- Member<ScriptPromiseResolver> resolver; // used by kFlush
- };
+ using Init = VideoEncoderInit;
+ using Config = VideoEncoderConfig;
+ using InternalConfig = ParsedConfig;
+ using Frame = VideoFrame;
+ using EncodeOptions = VideoEncoderEncodeOptions;
+ using OutputChunk = EncodedVideoChunk;
+ using OutputCallback = V8VideoEncoderOutputCallback;
+ using MediaEncoder = media::VideoEncoder;
+
+ // Can't be a virtual method, because it's used from base ctor.
+ static const char* GetNameForDevTools();
+};
+
+class MODULES_EXPORT VideoEncoder final
+ : public EncoderBase<VideoEncoderTraits> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static VideoEncoder* Create(ScriptState*,
+ const VideoEncoderInit*,
+ ExceptionState&);
+ VideoEncoder(ScriptState*, const VideoEncoderInit*, ExceptionState&);
+ ~VideoEncoder() override;
+
+ private:
+ using Base = EncoderBase<VideoEncoderTraits>;
+ using ParsedConfig = VideoEncoderTraits::ParsedConfig;
void CallOutputCallback(
ParsedConfig* active_config,
uint32_t reset_count,
media::VideoEncoderOutput output,
base::Optional<media::VideoEncoder::CodecDescription> codec_desc);
- void HandleError(DOMException* ex);
- void HandleError(std::string context, media::Status);
- void EnqueueRequest(Request* request);
- void ProcessRequests();
- void ProcessEncode(Request* request);
- void ProcessConfigure(Request* request);
- void ProcessReconfigure(Request* request);
- void ProcessFlush(Request* request);
+ void ProcessEncode(Request* request) override;
+ void ProcessConfigure(Request* request) override;
+ void ProcessReconfigure(Request* request) override;
+ void ProcessFlush(Request* request) override;
void UpdateEncoderLog(std::string encoder_name, bool is_hw_accelerated);
- void ResetInternal();
- ScriptPromiseResolver* MakePromise();
+ void OnReceivedGpuFactories(Request*, media::GpuVideoAcceleratorFactories*);
+
+ ParsedConfig* ParseConfig(const VideoEncoderConfig*,
+ ExceptionState&) override;
+ bool VerifyCodecSupport(ParsedConfig*, ExceptionState&) override;
+ VideoFrame* CloneFrame(VideoFrame*, ExecutionContext*) override;
- ParsedConfig* ParseConfig(const VideoEncoderConfig*, ExceptionState&);
- bool VerifyCodecSupport(ParsedConfig*, ExceptionState&);
+ void CreateAndInitializeEncoderWithoutAcceleration(Request* request);
+ void CreateAndInitializeEncoderOnEncoderSupportKnown(
+ Request* request,
+ media::GpuVideoAcceleratorFactories* gpu_factories);
std::unique_ptr<media::VideoEncoder> CreateMediaVideoEncoder(
- const ParsedConfig& config);
- bool CanReconfigure(ParsedConfig& original_config, ParsedConfig& new_config);
-
- std::unique_ptr<media::VideoEncoder> media_encoder_;
- bool is_hw_accelerated_ = false;
-
- // |parent_media_log_| must be destroyed if ever the ExecutionContext is
- // destroyed, since the blink::MediaInspectorContext* pointer given to
- // InspectorMediaEventHandler might no longer be valid.
- // |parent_media_log_| should not be used directly. Use |media_log_| instead.
- std::unique_ptr<media::MediaLog> parent_media_log_;
-
- // We might destroy |parent_media_log_| at any point, so keep a clone which
- // can be safely accessed, and whose raw pointer can be given callbacks.
- std::unique_ptr<media::MediaLog> media_log_;
-
- V8CodecState state_;
-
- Member<ParsedConfig> active_config_;
- Member<ScriptState> script_state_;
- Member<V8VideoEncoderOutputCallback> output_callback_;
- Member<V8WebCodecsErrorCallback> error_callback_;
- HeapDeque<Member<Request>> requests_;
- int32_t requested_encodes_ = 0;
- // How many times reset() was called on the encoder. It's used to decide
- // when a callback needs to be dismissed because reset() was called between
- // an operation and its callback.
- uint32_t reset_count_ = 0;
-
- // Some kConfigure and kFlush requests can't be executed in parallel with
- // kEncode. This flag stops processing of new requests in the requests_ queue
- // till the current requests are finished.
- bool stall_request_processing_ = false;
-
- SEQUENCE_CHECKER(sequence_checker_);
+ const ParsedConfig& config,
+ media::GpuVideoAcceleratorFactories* gpu_factories);
+ bool CanReconfigure(ParsedConfig& original_config,
+ ParsedConfig& new_config) override;
+ scoped_refptr<media::VideoFrame> ReadbackTextureBackedFrameToMemory(
+ scoped_refptr<media::VideoFrame> txt_frame);
+
+ media::VideoFramePool readback_frame_pool_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.idl
index 6efa78c8d19..94ee06fa6c7 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.idl
@@ -5,33 +5,25 @@
// https://github.com/WICG/web-codecs
[
- Exposed=Window,
+ Exposed=(Window,DedicatedWorker),
RuntimeEnabled=WebCodecs,
ActiveScriptWrappable
] interface VideoEncoder {
[CallWith=ScriptState, RaisesException, MeasureAs=WebCodecsVideoEncoder]
constructor(VideoEncoderInit init);
- // The number of pending encode requests. This does not include requests that
- // have been sent to the underlying codec.
- //
- // Applications can minimize underflow by enqueueing encode requests until
- // |encodeQueueSize| is greater than a constant.
+ // The number of pending encode requests. This does not include requests
+ // that have been sent to the underlying codec.
readonly attribute long encodeQueueSize;
- // Performs original configuration of the encoder.
- // Resolved after configuration is done. It should be called only
- // once per encoder instance, before calling any other methods.
+ // Enqueues a control message to configure the video encoder for encoding
+ // frames as described by config.
[RaisesException]
void configure(VideoEncoderConfig config);
// Enqueues a request to encode a frame.
// Results of the encoding (EncodedVideoChunk) are returned via
// the output callback provided in configure().
- // Resolved when encoded processed the given frame.
- // The output callback can be called before or after the result is resolved.
- // Several encoded requests can be resolved before even a single output
- // is produced.
[RaisesException]
void encode(VideoFrame frame,
optional VideoEncoderEncodeOptions options = {});
@@ -46,13 +38,11 @@
//
// Output for earlier encoding requests will not be emitted.
// The next encoded frame will be a keyframe.
- // Required a configure() to be call to set configuration once again.
+ // Requires configure() to be call to set configuration once again.
[RaisesException]
void reset();
// Enqueues a request to shut down the encoder and free its resources.
- // Resolved after all resources are released and all following requests
- // rejected.
[RaisesException]
void close();
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
index c151cb6bb1d..e849d305f7d 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
@@ -4,16 +4,9 @@
// https://github.com/WICG/web-codecs
-
-enum VideoEncoderAccelerationPreference {
- "allow",
- "deny",
- "require"
-};
-
dictionary VideoEncoderConfig {
required DOMString codec;
- VideoEncoderAccelerationPreference acceleration = "allow";
+ HardwarePreference hardwareAcceleration = "allow";
unsigned long long bitrate;
@@ -21,4 +14,6 @@ dictionary VideoEncoderConfig {
required unsigned long width;
required unsigned long height;
-}; \ No newline at end of file
+
+ AvcEncoderConfig avc;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
index 5b74d84ad8a..1f4737145ad 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.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/testing/dummy_page_holder.h"
@@ -77,44 +77,47 @@ DEFINE_TEXT_PROTO_FUZZER(
Persistent<VideoEncoder> video_encoder = VideoEncoder::Create(
script_state, video_encoder_init, IGNORE_EXCEPTION_FOR_TESTING);
- for (auto& invocation : proto.invocations()) {
- switch (invocation.Api_case()) {
- case wc_fuzzer::VideoEncoderApiInvocation::kConfigure:
- video_encoder->configure(MakeEncoderConfig(invocation.configure()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoEncoderApiInvocation::kEncode: {
- VideoFrame* frame = MakeVideoFrame(invocation.encode().frame());
- // Often the fuzzer input will be too crazy to produce a valid frame
- // (e.g. bitmap width > bitmap length). In these cases, return early
- // to discourage this sort of fuzzer input. WebIDL doesn't allow
- // callers to pass null, so this is not a real concern.
- if (!frame)
- return;
-
- video_encoder->encode(
- frame, MakeEncodeOptions(invocation.encode().options()),
- IGNORE_EXCEPTION_FOR_TESTING);
- break;
+ if (video_encoder) {
+ for (auto& invocation : proto.invocations()) {
+ switch (invocation.Api_case()) {
+ case wc_fuzzer::VideoEncoderApiInvocation::kConfigure:
+ video_encoder->configure(MakeEncoderConfig(invocation.configure()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoEncoderApiInvocation::kEncode: {
+ VideoFrame* frame =
+ MakeVideoFrame(script_state, invocation.encode().frame());
+ // Often the fuzzer input will be too crazy to produce a valid frame
+ // (e.g. bitmap width > bitmap length). In these cases, return early
+ // to discourage this sort of fuzzer input. WebIDL doesn't allow
+ // callers to pass null, so this is not a real concern.
+ if (!frame)
+ return;
+
+ video_encoder->encode(
+ frame, MakeEncodeOptions(invocation.encode().options()),
+ IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ }
+ case wc_fuzzer::VideoEncoderApiInvocation::kFlush: {
+ // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
+ // of the flush promise.
+ video_encoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ }
+ case wc_fuzzer::VideoEncoderApiInvocation::kReset:
+ video_encoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoEncoderApiInvocation::kClose:
+ video_encoder->close(IGNORE_EXCEPTION_FOR_TESTING);
+ break;
+ case wc_fuzzer::VideoEncoderApiInvocation::API_NOT_SET:
+ break;
}
- case wc_fuzzer::VideoEncoderApiInvocation::kFlush: {
- // TODO(https://crbug.com/1119253): Fuzz whether to await resolution
- // of the flush promise.
- video_encoder->flush(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- }
- case wc_fuzzer::VideoEncoderApiInvocation::kReset:
- video_encoder->reset(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoEncoderApiInvocation::kClose:
- video_encoder->close(IGNORE_EXCEPTION_FOR_TESTING);
- break;
- case wc_fuzzer::VideoEncoderApiInvocation::API_NOT_SET:
- break;
- }
- // Give other tasks a chance to run (e.g. calling our output callback).
- base::RunLoop().RunUntilIdle();
+ // Give other tasks a chance to run (e.g. calling our output callback).
+ base::RunLoop().RunUntilIdle();
+ }
}
}
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 9d165889061..8cf3f0a8d7b 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -6,238 +6,540 @@
#include <utility>
-#include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/resources/single_release_callback.h"
-#include "gpu/command_buffer/client/shared_image_interface.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/numerics/checked_math.h"
#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/video_frame_yuv_converter.h"
+#include "media/base/video_frame_pool.h"
+#include "media/base/video_util.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_plane_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_plane_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/html/canvas/canvas_image_source.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
-#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h"
-#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
-#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
+#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
-#include "third_party/libyuv/include/libyuv.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
namespace blink {
namespace {
-bool IsValidSkColorSpace(sk_sp<SkColorSpace> sk_color_space) {
- // Refer to CanvasColorSpaceToGfxColorSpace in CanvasColorParams.
- sk_sp<SkColorSpace> valid_sk_color_spaces[] = {
- gfx::ColorSpace::CreateSRGB().ToSkColorSpace(),
- gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace(),
- gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
- gfx::ColorSpace::TransferID::GAMMA24)
- .ToSkColorSpace()};
- for (auto& valid_sk_color_space : valid_sk_color_spaces) {
- if (SkColorSpace::Equals(sk_color_space.get(),
- valid_sk_color_space.get())) {
- return true;
- }
+struct YUVReadbackContext {
+ gfx::Size coded_size;
+ gfx::Rect visible_rect;
+ gfx::Size natural_size;
+ base::TimeDelta timestamp;
+ scoped_refptr<media::VideoFrame> frame;
+};
+
+void OnYUVReadbackDone(
+ void* raw_ctx,
+ std::unique_ptr<const SkImage::AsyncReadResult> async_result) {
+ if (!async_result)
+ return;
+ auto* context = reinterpret_cast<YUVReadbackContext*>(raw_ctx);
+ context->frame = media::VideoFrame::WrapExternalYuvData(
+ media::PIXEL_FORMAT_I420, context->coded_size, context->visible_rect,
+ context->natural_size, static_cast<int>(async_result->rowBytes(0)),
+ static_cast<int>(async_result->rowBytes(1)),
+ static_cast<int>(async_result->rowBytes(2)),
+ // TODO(crbug.com/1161304): We should be able to wrap readonly memory in
+ // a VideoFrame without resorting to a const_cast.
+ reinterpret_cast<uint8_t*>(const_cast<void*>(async_result->data(0))),
+ reinterpret_cast<uint8_t*>(const_cast<void*>(async_result->data(1))),
+ reinterpret_cast<uint8_t*>(const_cast<void*>(async_result->data(2))),
+ context->timestamp);
+ if (!context->frame)
+ return;
+ context->frame->AddDestructionObserver(
+ ConvertToBaseOnceCallback(WTF::CrossThreadBindOnce(
+ base::DoNothing::Once<
+ std::unique_ptr<const SkImage::AsyncReadResult>>(),
+ std::move(async_result))));
+}
+
+media::VideoPixelFormat ToMediaPixelFormat(V8VideoPixelFormat::Enum fmt) {
+ switch (fmt) {
+ case V8VideoPixelFormat::Enum::kI420:
+ return media::PIXEL_FORMAT_I420;
+ case V8VideoPixelFormat::Enum::kNV12:
+ return media::PIXEL_FORMAT_NV12;
+ case V8VideoPixelFormat::Enum::kABGR:
+ return media::PIXEL_FORMAT_ABGR;
+ case V8VideoPixelFormat::Enum::kXBGR:
+ return media::PIXEL_FORMAT_XBGR;
+ case V8VideoPixelFormat::Enum::kARGB:
+ return media::PIXEL_FORMAT_ARGB;
+ case V8VideoPixelFormat::Enum::kXRGB:
+ return media::PIXEL_FORMAT_XRGB;
}
- return false;
}
-bool IsValidSkColorType(SkColorType sk_color_type) {
- SkColorType valid_sk_color_types[] = {
- kBGRA_8888_SkColorType, kRGBA_8888_SkColorType,
- // TODO(jie.a.chen@intel.com): Add F16 support.
- // kRGBA_F16_SkColorType
- };
- for (auto& valid_sk_color_type : valid_sk_color_types) {
- if (sk_color_type == valid_sk_color_type) {
- return true;
+class CachedVideoFramePool : public GarbageCollected<CachedVideoFramePool>,
+ public Supplement<ExecutionContext> {
+ public:
+ static const char kSupplementName[];
+
+ static CachedVideoFramePool& From(ExecutionContext& context) {
+ CachedVideoFramePool* supplement =
+ Supplement<ExecutionContext>::From<CachedVideoFramePool>(context);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<CachedVideoFramePool>(context);
+ Supplement<ExecutionContext>::ProvideTo(context, supplement);
}
+ return *supplement;
}
- return false;
-}
-void OnYUVReadbackDone(
- void* raw_frame_ptr,
- std::unique_ptr<const SkImage::AsyncReadResult> async_result) {
- scoped_refptr<media::VideoFrame> frame(
- static_cast<media::VideoFrame*>(raw_frame_ptr));
- if (!async_result) {
- LOG(ERROR) << "Failed to read yuv420 back!";
- return;
+ explicit CachedVideoFramePool(ExecutionContext& context)
+ : Supplement<ExecutionContext>(context),
+ task_runner_(Thread::Current()->GetTaskRunner()) {}
+ virtual ~CachedVideoFramePool() = default;
+
+ // Disallow copy and assign.
+ CachedVideoFramePool& operator=(const CachedVideoFramePool&) = delete;
+ CachedVideoFramePool(const CachedVideoFramePool&) = delete;
+
+ scoped_refptr<media::VideoFrame> CreateFrame(media::VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp) {
+ if (!frame_pool_)
+ CreatePoolAndStartIdleObsever();
+
+ last_frame_creation_ = base::TimeTicks::Now();
+ return frame_pool_->CreateFrame(format, coded_size, visible_rect,
+ natural_size, timestamp);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ Supplement<ExecutionContext>::Trace(visitor);
+ }
+
+ private:
+ static const base::TimeDelta kIdleTimeout;
+
+ void PostMonitoringTask() {
+ DCHECK(!task_handle_.IsActive());
+ task_handle_ = PostDelayedCancellableTask(
+ *task_runner_, FROM_HERE,
+ WTF::Bind(&CachedVideoFramePool::PurgeIdleFramePool,
+ WrapWeakPersistent(this)),
+ kIdleTimeout);
+ }
+
+ void CreatePoolAndStartIdleObsever() {
+ DCHECK(!frame_pool_);
+ frame_pool_ = std::make_unique<media::VideoFramePool>();
+ PostMonitoringTask();
+ }
+
+ // We don't want a VideoFramePool to stick around forever wasting memory, so
+ // once we haven't issued any VideoFrames for a while, turn down the pool.
+ void PurgeIdleFramePool() {
+ if (base::TimeTicks::Now() - last_frame_creation_ > kIdleTimeout) {
+ frame_pool_.reset();
+ return;
+ }
+ PostMonitoringTask();
+ }
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ std::unique_ptr<media::VideoFramePool> frame_pool_;
+ base::TimeTicks last_frame_creation_;
+ TaskHandle task_handle_;
+};
+
+// static -- defined out of line to satisfy link time requirements.
+const char CachedVideoFramePool::kSupplementName[] = "CachedVideoFramePool";
+const base::TimeDelta CachedVideoFramePool::kIdleTimeout =
+ base::TimeDelta::FromSeconds(10);
+
+bool IsSupportedPlanarFormat(const media::VideoFrame& frame) {
+ if (!frame.IsMappable() && !frame.HasGpuMemoryBuffer())
+ return false;
+
+ const size_t num_planes = frame.layout().num_planes();
+ switch (frame.format()) {
+ case media::PIXEL_FORMAT_I420:
+ return num_planes == 3;
+ case media::PIXEL_FORMAT_I420A:
+ return num_planes == 4;
+ case media::PIXEL_FORMAT_NV12:
+ return num_planes == 2;
+ case media::PIXEL_FORMAT_XBGR:
+ case media::PIXEL_FORMAT_XRGB:
+ case media::PIXEL_FORMAT_ABGR:
+ case media::PIXEL_FORMAT_ARGB:
+ return num_planes == 1;
+ default:
+ return false;
}
- auto* data0 = static_cast<const uint8_t*>(async_result->data(0));
- DCHECK(data0);
- auto* data1 = static_cast<const uint8_t*>(async_result->data(1));
- DCHECK(data1);
- auto* data2 = static_cast<const uint8_t*>(async_result->data(2));
- DCHECK(data2);
- gfx::Size size = frame->coded_size();
- libyuv::CopyPlane(data0, static_cast<int>(async_result->rowBytes(0)),
- frame->visible_data(media::VideoFrame::kYPlane),
- frame->stride(media::VideoFrame::kYPlane), size.width(),
- size.height());
- libyuv::CopyPlane(data1, static_cast<int>(async_result->rowBytes(1)),
- frame->visible_data(media::VideoFrame::kUPlane),
- frame->stride(media::VideoFrame::kUPlane), size.width() / 2,
- size.height() / 2);
- libyuv::CopyPlane(data2, static_cast<int>(async_result->rowBytes(2)),
- frame->visible_data(media::VideoFrame::kVPlane),
- frame->stride(media::VideoFrame::kVPlane), size.width() / 2,
- size.height() / 2);
}
} // namespace
-VideoFrame::VideoFrame(scoped_refptr<media::VideoFrame> frame)
- : handle_(base::MakeRefCounted<VideoFrameHandle>(std::move(frame))) {
- DCHECK(handle_->frame());
+VideoFrame::VideoFrame(scoped_refptr<media::VideoFrame> frame,
+ ExecutionContext* context) {
+ DCHECK(frame);
+ handle_ = base::MakeRefCounted<VideoFrameHandle>(std::move(frame), context);
}
VideoFrame::VideoFrame(scoped_refptr<VideoFrameHandle> handle)
: handle_(std::move(handle)) {
DCHECK(handle_);
+
+ // Note: The provided |handle| may be invalid if close() has been called while
+ // a frame is in transit to another thread.
}
// static
-VideoFrame* VideoFrame::Create(ImageBitmap* source,
- VideoFrameInit* init,
+VideoFrame* VideoFrame::Create(ScriptState* script_state,
+ const CanvasImageSourceUnion& source,
+ const VideoFrameInit* init,
ExceptionState& exception_state) {
- if (!source) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotFoundError,
- "No source was provided");
+ auto* image_source = ToCanvasImageSource(source, exception_state);
+ if (!image_source) {
+ // ToCanvasImageSource() will throw a source appropriate exception.
return nullptr;
}
- if (!source->BitmapImage()) {
+ if (image_source->WouldTaintOrigin()) {
+ exception_state.ThrowSecurityError(
+ "VideoFrames can't be created from tainted sources.");
+ return nullptr;
+ }
+
+ // Special case <video> and VideoFrame to directly use the underlying frame.
+ if (source.IsVideoFrame() || source.IsHTMLVideoElement()) {
+ scoped_refptr<media::VideoFrame> source_frame;
+ if (source.IsVideoFrame()) {
+ if (!init || (!init->hasTimestamp() && !init->hasDuration()))
+ return source.GetAsVideoFrame()->clone(script_state, exception_state);
+ source_frame = source.GetAsVideoFrame()->frame();
+ } else if (source.IsHTMLVideoElement()) {
+ if (auto* wmp = source.GetAsHTMLVideoElement()->GetWebMediaPlayer())
+ source_frame = wmp->GetCurrentFrame();
+ }
+
+ if (!source_frame) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Invalid source state");
+ return nullptr;
+ }
+
+ // We can't modify the timestamp or duration directly since there may be
+ // other owners accessing these fields concurrently.
+ if (init && (init->hasTimestamp() || init->hasDuration())) {
+ source_frame = media::VideoFrame::WrapVideoFrame(
+ source_frame, source_frame->format(), source_frame->visible_rect(),
+ source_frame->natural_size());
+ if (init->hasTimestamp()) {
+ source_frame->set_timestamp(
+ base::TimeDelta::FromMicroseconds(init->timestamp()));
+ }
+ if (init->hasDuration()) {
+ source_frame->metadata().frame_duration =
+ base::TimeDelta::FromMicroseconds(init->duration());
+ }
+ }
+
+ return MakeGarbageCollected<VideoFrame>(
+ std::move(source_frame), ExecutionContext::From(script_state));
+ }
+
+ SourceImageStatus status = kInvalidSourceImageStatus;
+ auto image = image_source->GetSourceImageForCanvas(&status, FloatSize());
+ if (!image || status != kNormalSourceImageStatus) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Invalid source state");
return nullptr;
}
- gfx::Size size(source->width(), source->height());
- gfx::Rect rect(size);
- base::TimeDelta timestamp =
- base::TimeDelta::FromMicroseconds(init->timestamp());
+ const auto timestamp = base::TimeDelta::FromMicroseconds(
+ (init && init->hasTimestamp()) ? init->timestamp() : 0);
+
+ const auto sk_image = image->PaintImageForCurrentFrame().GetSkImage();
+ const auto sk_image_info = sk_image->imageInfo();
- auto sk_image_info =
- source->BitmapImage()->PaintImageForCurrentFrame().GetSkImageInfo();
auto sk_color_space = sk_image_info.refColorSpace();
- if (!sk_color_space) {
+ if (!sk_color_space)
sk_color_space = SkColorSpace::MakeSRGB();
- }
- if (!IsValidSkColorSpace(sk_color_space)) {
+
+ const auto gfx_color_space = gfx::ColorSpace(*sk_color_space);
+ if (!gfx_color_space.IsValid()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Invalid color space");
return nullptr;
}
- auto frame = media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_I420, size,
- rect, size, timestamp);
- if (!frame) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Frame creation failed");
- return nullptr;
- }
+ const gfx::Size coded_size(sk_image_info.width(), sk_image_info.height());
+ const gfx::Rect visible_rect(coded_size);
+ const gfx::Size natural_size = coded_size;
- bool is_texture =
- source->BitmapImage()->PaintImageForCurrentFrame().IsTextureBacked();
- // Now only SkImage_Gpu implemented the readbackYUV420 method, so for
- // non-texture image, still use libyuv do the csc until SkImage_Base
- // implement asyncRescaleAndReadPixelsYUV420.
- if (is_texture) {
- auto sk_image =
- source->BitmapImage()->PaintImageForCurrentFrame().GetSkImage();
- SkIRect src_rect = SkIRect::MakeWH(source->width(), source->height());
+ scoped_refptr<media::VideoFrame> frame;
+ if (sk_image->isTextureBacked()) {
+ YUVReadbackContext result;
+ result.coded_size = coded_size;
+ result.visible_rect = visible_rect;
+ result.natural_size = natural_size;
+ result.timestamp = timestamp;
+
+ // While this function indicates it's asynchronous, the flushAndSubmit()
+ // call below ensures it completes synchronously.
sk_image->asyncRescaleAndReadPixelsYUV420(
- kRec709_SkYUVColorSpace, sk_color_space, src_rect,
- {source->width(), source->height()}, SkImage::RescaleGamma::kSrc,
- kHigh_SkFilterQuality, &OnYUVReadbackDone, frame.get());
- GrDirectContext* gr_context =
- source->BitmapImage()->ContextProvider()->GetGrContext();
+ kRec709_SkYUVColorSpace, sk_color_space, sk_image_info.bounds(),
+ sk_image_info.dimensions(), SkImage::RescaleGamma::kSrc,
+ SkImage::RescaleMode::kRepeatedCubic, &OnYUVReadbackDone, &result);
+ GrDirectContext* gr_context = image->ContextProvider()->GetGrContext();
DCHECK(gr_context);
gr_context->flushAndSubmit(/*syncCpu=*/true);
- } else {
- auto sk_color_type = sk_image_info.colorType();
- if (!IsValidSkColorType(sk_color_type)) {
- exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Invalid pixel format");
+
+ if (!result.frame) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "YUV conversion error during readback");
return nullptr;
}
- // TODO(jie.a.chen@intel.com): Handle data of float type.
- // Full copy #1
- WTF::Vector<uint8_t> pixel_data = source->CopyBitmapData();
- if (pixel_data.size() <
- media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_ARGB, size)) {
- exception_state.ThrowDOMException(DOMExceptionCode::kBufferOverrunError,
- "Image buffer is too small.");
+ frame = std::move(result.frame);
+ frame->set_color_space(gfx_color_space);
+ if (init && init->hasDuration()) {
+ frame->metadata().frame_duration =
+ base::TimeDelta::FromMicroseconds(init->duration());
+ }
+ return MakeGarbageCollected<VideoFrame>(
+ std::move(frame), ExecutionContext::From(script_state));
+ }
+
+ frame =
+ media::CreateFromSkImage(sk_image, visible_rect, natural_size, timestamp);
+ if (!frame) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Failed to create video frame");
+ return nullptr;
+ }
+ frame->set_color_space(gfx_color_space);
+ if (init && init->hasDuration()) {
+ frame->metadata().frame_duration =
+ base::TimeDelta::FromMicroseconds(init->duration());
+ }
+ return MakeGarbageCollected<VideoFrame>(
+ base::MakeRefCounted<VideoFrameHandle>(
+ std::move(frame), std::move(sk_image),
+ ExecutionContext::From(script_state)));
+}
+
+// static
+VideoFrame* VideoFrame::Create(ScriptState* script_state,
+ const String& format,
+ const HeapVector<Member<PlaneInit>>& planes,
+ const VideoFramePlaneInit* init,
+ ExceptionState& exception_state) {
+ if (!init->hasCodedWidth() || !init->hasCodedHeight()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ "Coded size is required for planar construction");
+ return nullptr;
+ }
+
+ // Type formats are enforced by V8.
+ auto typed_fmt = V8VideoPixelFormat::Create(format);
+ DCHECK(typed_fmt);
+
+ auto media_fmt = ToMediaPixelFormat(typed_fmt->AsEnum());
+
+ // There's no I420A pixel format, so treat I420 + 4 planes as I420A.
+ if (media_fmt == media::PIXEL_FORMAT_I420 && planes.size() == 4u)
+ media_fmt = media::PIXEL_FORMAT_I420A;
+
+ if (media::VideoFrame::NumPlanes(media_fmt) != planes.size()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format("Invalid number of planes for format %s; expected %zu, "
+ "received %u",
+ format.Ascii().c_str(),
+ media::VideoFrame::NumPlanes(media_fmt), planes.size()));
+ return nullptr;
+ }
+
+ // gfx::Size() takes int.
+ if (!base::CheckedNumeric<uint32_t>(init->codedWidth()).IsValid<int>() ||
+ !base::CheckedNumeric<uint32_t>(init->codedHeight()).IsValid<int>() ||
+ init->codedWidth() == 0 || init->codedHeight() == 0) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format("Invalid coded size (%u, %u) provided",
+ init->codedWidth(), init->codedHeight()));
+ return nullptr;
+ }
+ const gfx::Size coded_size(init->codedWidth(), init->codedHeight());
+
+ for (wtf_size_t i = 0; i < planes.size(); ++i) {
+ const auto minimum_size =
+ media::VideoFrame::PlaneSize(media_fmt, i, coded_size);
+ if (!base::CheckedNumeric<uint32_t>(planes[i]->stride()).IsValid<int>()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format("The stride of plane %u is too large", i));
+ return nullptr;
+ }
+ if (planes[i]->stride() < uint32_t{minimum_size.width()}) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format(
+ "The stride of plane %u is too small for the given coded size "
+ "(%s); expected at least %d, received %u",
+ i, coded_size.ToString().c_str(), minimum_size.width(),
+ planes[i]->stride()));
+ return nullptr;
+ }
+ if (planes[i]->rows() != uint32_t{minimum_size.height()}) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format(
+ "The row count for plane %u is incorrect for the given coded "
+ "size (%s); expected %d, received %u",
+ i, coded_size.ToString().c_str(), minimum_size.height(),
+ planes[i]->rows()));
return nullptr;
}
- DCHECK(sk_color_type == kRGBA_8888_SkColorType ||
- sk_color_type == kBGRA_8888_SkColorType);
- auto libyuv_convert_to_i420 = (sk_color_type == kRGBA_8888_SkColorType)
- ? libyuv::ABGRToI420
- : libyuv::ARGBToI420;
-
- // TODO(jie.a.chen@intel.com): Use GPU to do the conversion.
- // Full copy #2
- int error =
- libyuv_convert_to_i420(pixel_data.data(), source->width() * 4,
- frame->visible_data(media::VideoFrame::kYPlane),
- frame->stride(media::VideoFrame::kYPlane),
- frame->visible_data(media::VideoFrame::kUPlane),
- frame->stride(media::VideoFrame::kUPlane),
- frame->visible_data(media::VideoFrame::kVPlane),
- frame->stride(media::VideoFrame::kVPlane),
- source->width(), source->height());
- if (error) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "ARGB to YUV420 conversion error");
+ // This requires the full stride to be provided for every row.
+ gfx::Size provided_size(planes[i]->stride(), planes[i]->rows());
+ const auto required_byte_size = provided_size.GetCheckedArea();
+ if (!required_byte_size.IsValid()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format("The size of plane %u is too large", i));
+ return nullptr;
+ }
+
+ DOMArrayPiece buffer(planes[i]->src());
+ if (buffer.ByteLength() < required_byte_size.ValueOrDie()) {
+ // Note: We use GetArea() below instead of area.ValueOrDie() since the
+ // base::StrictNumeric seems to confuse the printf() format checks.
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format(
+ "The size of plane %u is too small for the given coded "
+ "size (%s); expected at least %d, received %zu",
+ i, coded_size.ToString().c_str(), provided_size.GetArea(),
+ buffer.ByteLength()));
return nullptr;
}
- gfx::ColorSpace gfx_color_space(*sk_color_space);
- // 'libyuv_convert_to_i420' assumes SMPTE170M.
- // Refer to the func below to check the actual conversion:
- // third_party/libyuv/source/row_common.cc -- RGBToY(...)
- gfx_color_space = gfx_color_space.GetWithMatrixAndRange(
- gfx::ColorSpace::MatrixID::SMPTE170M,
- gfx::ColorSpace::RangeID::LIMITED);
- frame->set_color_space(gfx_color_space);
}
- auto* result = MakeGarbageCollected<VideoFrame>(std::move(frame));
- return result;
-}
-// static
-bool VideoFrame::IsSupportedPlanarFormat(media::VideoFrame* frame) {
- // For now only I420 or NV12 in CPU or GPU memory is supported.
- return frame && (frame->IsMappable() || frame->HasGpuMemoryBuffer()) &&
- ((frame->format() == media::PIXEL_FORMAT_I420 &&
- frame->layout().num_planes() == 3) ||
- (frame->format() == media::PIXEL_FORMAT_NV12 &&
- frame->layout().num_planes() == 2));
+ auto visible_rect = gfx::Rect(coded_size);
+ if (init->hasCropLeft() || init->hasCropTop() || init->hasCropWidth() ||
+ init->hasCropHeight()) {
+ const auto crop_left = init->hasCropLeft() ? init->cropLeft() : 0;
+ const auto crop_top = init->hasCropTop() ? init->cropTop() : 0;
+ const auto crop_w =
+ init->hasCropWidth() ? visible_rect.width() - init->cropWidth() : 0;
+ const auto crop_h =
+ init->hasCropHeight() ? visible_rect.height() - init->cropHeight() : 0;
+ if (crop_w < 0 || crop_h < 0 || crop_w > unsigned{visible_rect.width()} ||
+ crop_h > unsigned{visible_rect.height()}) {
+ visible_rect = gfx::Rect();
+ } else {
+ visible_rect.Inset(crop_left, crop_top, crop_w, crop_h);
+ }
+
+ if (visible_rect.IsEmpty()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format(
+ "Invalid visble rect (%s) after crop (%d, %d, %d, %d) applied",
+ visible_rect.ToString().c_str(), crop_left, crop_top, crop_w,
+ crop_h));
+ return nullptr;
+ }
+ }
+
+ auto natural_size = visible_rect.size();
+ if (init->hasDisplayWidth())
+ natural_size.set_width(init->displayWidth());
+ if (init->hasDisplayHeight())
+ natural_size.set_height(init->displayHeight());
+ if (coded_size.IsEmpty()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format("Invalid display size (%s) provided",
+ natural_size.ToString().c_str()));
+ return nullptr;
+ }
+
+ const auto timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
+ auto& frame_pool =
+ CachedVideoFramePool::From(*ExecutionContext::From(script_state));
+ auto frame = frame_pool.CreateFrame(media_fmt, coded_size, visible_rect,
+ natural_size, timestamp);
+ if (!frame) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kConstraintError,
+ String::Format(
+ "Failed to create a video frame with configuration {format:%s, "
+ "coded_size:%s, visible_rect:%s, display_size:%s}",
+ VideoPixelFormatToString(media_fmt).c_str(),
+ coded_size.ToString().c_str(), visible_rect.ToString().c_str(),
+ natural_size.ToString().c_str()));
+ return nullptr;
+ }
+
+ for (wtf_size_t i = 0; i < planes.size(); ++i) {
+ const auto minimum_size =
+ media::VideoFrame::PlaneSize(media_fmt, i, coded_size);
+
+ DOMArrayPiece buffer(planes[i]->src());
+
+ uint8_t* dest_ptr = frame->visible_data(i);
+ const uint8_t* src_ptr = reinterpret_cast<uint8_t*>(buffer.Data());
+ for (size_t r = 0; r < planes[i]->rows(); ++r) {
+ DCHECK_LE(
+ src_ptr + planes[i]->stride(),
+ reinterpret_cast<uint8_t*>(buffer.Data()) + buffer.ByteLength());
+
+ memcpy(dest_ptr, src_ptr, minimum_size.width());
+ src_ptr += planes[i]->stride();
+ dest_ptr += frame->stride(i);
+ }
+ }
+
+ return MakeGarbageCollected<VideoFrame>(std::move(frame),
+ ExecutionContext::From(script_state));
}
String VideoFrame::format() const {
auto local_frame = handle_->frame();
- if (!local_frame || !IsSupportedPlanarFormat(local_frame.get()))
+ if (!local_frame || !IsSupportedPlanarFormat(*local_frame))
return String();
switch (local_frame->format()) {
case media::PIXEL_FORMAT_I420:
+ case media::PIXEL_FORMAT_I420A:
return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kI420);
case media::PIXEL_FORMAT_NV12:
return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kNV12);
-
+ case media::PIXEL_FORMAT_ABGR:
+ return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kABGR);
+ case media::PIXEL_FORMAT_XBGR:
+ return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kXBGR);
+ case media::PIXEL_FORMAT_ARGB:
+ return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kARGB);
+ case media::PIXEL_FORMAT_XRGB:
+ return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kXRGB);
default:
NOTREACHED();
return String();
@@ -248,7 +550,7 @@ base::Optional<HeapVector<Member<Plane>>> VideoFrame::planes() {
// Verify that |this| has not been invalidated, and that the format is
// supported.
auto local_frame = handle_->frame();
- if (!local_frame || !IsSupportedPlanarFormat(local_frame.get()))
+ if (!local_frame || !IsSupportedPlanarFormat(*local_frame))
return base::nullopt;
// Create a Plane for each VideoFrame plane, but only the first time.
@@ -328,45 +630,49 @@ base::Optional<uint64_t> VideoFrame::timestamp() const {
base::Optional<uint64_t> VideoFrame::duration() const {
auto local_frame = handle_->frame();
// TODO(sandersd): Can a duration be kNoTimestamp?
- if (!local_frame || !local_frame->metadata()->frame_duration.has_value())
+ if (!local_frame || !local_frame->metadata().frame_duration.has_value())
return base::nullopt;
- return local_frame->metadata()->frame_duration->InMicroseconds();
+ return local_frame->metadata().frame_duration->InMicroseconds();
}
-void VideoFrame::destroy() {
- // TODO(tguilbert): Add a warning when destroying already destroyed frames?
+void VideoFrame::close() {
handle_->Invalidate();
}
-VideoFrame* VideoFrame::clone(ExceptionState& exception_state) {
- auto frame = handle_->frame();
+void VideoFrame::destroy(ExecutionContext* execution_context) {
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kDeprecation,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "VideoFrame.destroy() is deprecated; use VideoFrame.close()."));
+ close();
+}
+
+VideoFrame* VideoFrame::clone(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ VideoFrame* frame = CloneFromNative(ExecutionContext::From(script_state));
if (!frame) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
- "Cannot clone destroyed VideoFrame.");
+ "Cannot clone closed VideoFrame.");
return nullptr;
}
- return MakeGarbageCollected<VideoFrame>(std::move(frame));
-}
-
-scoped_refptr<VideoFrameHandle> VideoFrame::handle() {
- return handle_;
-}
-
-scoped_refptr<media::VideoFrame> VideoFrame::frame() {
- return handle_->frame();
+ return frame;
}
-scoped_refptr<const media::VideoFrame> VideoFrame::frame() const {
- return handle_->frame();
+VideoFrame* VideoFrame::CloneFromNative(ExecutionContext* context) {
+ // The returned handle will be nullptr if it was already invalidated.
+ auto handle = handle_->Clone();
+ return handle ? MakeGarbageCollected<VideoFrame>(std::move(handle)) : nullptr;
}
ScriptPromise VideoFrame::createImageBitmap(ScriptState* script_state,
const ImageBitmapOptions* options,
ExceptionState& exception_state) {
- base::Optional<IntRect> crop_rect;
+ VideoFrameLogger::From(*ExecutionContext::From(script_state))
+ .LogCreateImageBitmapDeprecationNotice();
+ base::Optional<IntRect> crop_rect;
if (auto local_frame = handle_->frame())
crop_rect = IntRect(local_frame->visible_rect());
@@ -374,138 +680,105 @@ ScriptPromise VideoFrame::createImageBitmap(ScriptState* script_state,
options, exception_state);
}
-IntSize VideoFrame::BitmapSourceSize() const {
- // TODO(crbug.com/1096724): Should be scaled to display size.
- return IntSize(cropWidth(), cropHeight());
+scoped_refptr<Image> VideoFrame::GetSourceImageForCanvas(
+ SourceImageStatus* status,
+ const FloatSize&) {
+ const auto local_handle = handle_->CloneForInternalUse();
+ if (!local_handle) {
+ DLOG(ERROR) << "GetSourceImageForCanvas() called for closed frame.";
+ *status = kInvalidSourceImageStatus;
+ return nullptr;
+ }
+
+ if (auto sk_img = local_handle->sk_image()) {
+ *status = kNormalSourceImageStatus;
+ return UnacceleratedStaticBitmapImage::Create(std::move(sk_img));
+ }
+
+ const auto image = CreateImageFromVideoFrame(local_handle->frame());
+ if (!image) {
+ *status = kInvalidSourceImageStatus;
+ return nullptr;
+ }
+
+ *status = kNormalSourceImageStatus;
+ return image;
+}
+
+bool VideoFrame::WouldTaintOrigin() const {
+ // VideoFrames can't be created from untainted sources currently. If we ever
+ // add that ability we will need a tainting signal on the VideoFrame itself.
+ // One example would be allowing <video> elements to provide a VideoFrame.
+ return false;
+}
+
+FloatSize VideoFrame::ElementSize(
+ const FloatSize& default_object_size,
+ const RespectImageOrientationEnum respect_orientation) const {
+ // TODO(crbug.com/1140137): This will need consideration for orientation.
+ return FloatSize(BitmapSourceSize());
+}
+
+bool VideoFrame::IsVideoFrame() const {
+ return true;
+}
+
+bool VideoFrame::IsOpaque() const {
+ if (auto local_frame = handle_->frame())
+ return media::IsOpaque(local_frame->format());
+ return false;
+}
+
+bool VideoFrame::IsAccelerated() const {
+ if (auto local_handle = handle_->CloneForInternalUse()) {
+ return handle_->sk_image() ? false
+ : WillCreateAcceleratedImagesFromVideoFrame(
+ local_handle->frame().get());
+ }
+ return false;
}
-bool VideoFrame::preferAcceleratedImageBitmap() const {
- auto local_frame = frame();
- return BitmapSourceSize().Area() > kCpuEfficientFrameSize ||
- (local_frame && local_frame->HasTextures());
+IntSize VideoFrame::BitmapSourceSize() const {
+ // TODO(crbug.com/1096724): Should be scaled to display size.
+ if (auto local_frame = handle_->frame())
+ return IntSize(local_frame->visible_rect().size());
+ return IntSize();
}
ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
base::Optional<IntRect> crop_rect,
const ImageBitmapOptions* options,
ExceptionState& exception_state) {
- auto local_frame = frame();
-
- if (!local_frame) {
+ const auto local_handle = handle_->CloneForInternalUse();
+ if (!local_handle) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
- "Cannot create ImageBitmap from destroyed VideoFrame.");
+ "Cannot create ImageBitmap from closed VideoFrame.");
return ScriptPromise();
}
- if ((local_frame->IsMappable() &&
- (local_frame->format() == media::PIXEL_FORMAT_I420)) ||
- (local_frame->HasTextures() &&
- (local_frame->format() == media::PIXEL_FORMAT_I420 ||
- local_frame->format() == media::PIXEL_FORMAT_NV12 ||
- local_frame->format() == media::PIXEL_FORMAT_ABGR ||
- local_frame->format() == media::PIXEL_FORMAT_XRGB))) {
- scoped_refptr<StaticBitmapImage> image;
- gfx::ColorSpace gfx_color_space = local_frame->ColorSpace();
- gfx_color_space = gfx_color_space.GetWithMatrixAndRange(
- gfx::ColorSpace::MatrixID::RGB, gfx::ColorSpace::RangeID::FULL);
- auto sk_color_space = gfx_color_space.ToSkColorSpace();
- if (!sk_color_space) {
- sk_color_space = SkColorSpace::MakeSRGB();
- }
-
- if (!preferAcceleratedImageBitmap()) {
- size_t bytes_per_row = sizeof(SkColor) * cropWidth();
- size_t image_pixels_size = bytes_per_row * cropHeight();
-
- sk_sp<SkData> image_pixels = TryAllocateSkData(image_pixels_size);
- if (!image_pixels) {
- exception_state.ThrowDOMException(DOMExceptionCode::kBufferOverrunError,
- "Out of memory.");
- return ScriptPromise();
- }
- media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
- local_frame.get(), image_pixels->writable_data(), bytes_per_row);
-
- SkImageInfo info =
- SkImageInfo::Make(cropWidth(), cropHeight(), kN32_SkColorType,
- kUnpremul_SkAlphaType, std::move(sk_color_space));
- sk_sp<SkImage> skImage =
- SkImage::MakeRasterData(info, image_pixels, bytes_per_row);
- image = UnacceleratedStaticBitmapImage::Create(std::move(skImage));
- } else {
- scoped_refptr<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;
- if (raster_context_provider->ContextCapabilities().supports_oop_raster) {
- usage |= gpu::SHARED_IMAGE_USAGE_RASTER |
- gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
- }
-
- gpu::MailboxHolder dest_holder;
- // Use coded_size() to comply with media::ConvertFromVideoFrameYUV.
- dest_holder.mailbox = shared_image_interface->CreateSharedImage(
- viz::ResourceFormat::RGBA_8888, local_frame->coded_size(),
- gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
- usage, gpu::kNullSurfaceHandle);
- dest_holder.sync_token = shared_image_interface->GenUnverifiedSyncToken();
- dest_holder.texture_target = GL_TEXTURE_2D;
-
- 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.get(), dest_holder);
- }
-
- gpu::SyncToken sync_token;
- ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
-
- auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
- [](scoped_refptr<viz::RasterContextProvider> provider,
- gpu::Mailbox mailbox, const gpu::SyncToken& sync_token,
- bool is_lost) {
- provider->SharedImageInterface()->DestroySharedImage(sync_token,
- mailbox);
- },
- raster_context_provider, dest_holder.mailbox));
-
- const SkImageInfo sk_image_info =
- SkImageInfo::Make(codedWidth(), codedHeight(), kN32_SkColorType,
- kUnpremul_SkAlphaType, std::move(sk_color_space));
-
- image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
- dest_holder.mailbox, sync_token, 0u, sk_image_info,
- dest_holder.texture_target, true,
- 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 =
- MakeGarbageCollected<ImageBitmap>(image, crop_rect, options);
+ if (auto sk_img = local_handle->sk_image()) {
+ auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(
+ UnacceleratedStaticBitmapImage::Create(std::move(sk_img)), crop_rect,
+ options);
return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap,
exception_state);
}
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Unsupported VideoFrame.");
- return ScriptPromise();
+ const auto image = CreateImageFromVideoFrame(local_handle->frame());
+ if (!image) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ String(("Unsupported VideoFrame: " +
+ local_handle->frame()->AsHumanReadableString())
+ .c_str()));
+ return ScriptPromise();
+ }
+
+ auto* image_bitmap =
+ MakeGarbageCollected<ImageBitmap>(image, crop_rect, options);
+ return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap,
+ exception_state);
}
void VideoFrame::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.h
index 37a74620fb0..396bc2d2cef 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -8,8 +8,9 @@
#include <stdint.h>
#include "base/optional.h"
-#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
+#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/plane.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
@@ -18,29 +19,48 @@
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+// Note: Don't include "media/base/video_frame.h" here without good reason,
+// since it includes a lot of non-blink types which can pollute the namespace.
+
+namespace media {
+class VideoFrame;
+}
+
namespace blink {
-class ImageBitmap;
+class CanvasImageSource;
class ExceptionState;
+class ExecutionContext;
+class PlaneInit;
class ScriptPromise;
class ScriptState;
class VideoFrameInit;
+class VideoFramePlaneInit;
class MODULES_EXPORT VideoFrame final : public ScriptWrappable,
+ public CanvasImageSource,
public ImageBitmapSource {
DEFINE_WRAPPERTYPEINFO();
public:
// Creates a VideoFrame with a new VideoFrameHandle wrapping |frame|.
- explicit VideoFrame(scoped_refptr<media::VideoFrame> frame);
+ VideoFrame(scoped_refptr<media::VideoFrame> frame, ExecutionContext*);
// Creates a VideoFrame from an existing handle.
// All frames sharing |handle| will have their |handle_| invalidated if any of
- // the frames receives a call to destroy().
+ // the frames receives a call to close().
explicit VideoFrame(scoped_refptr<VideoFrameHandle> handle);
// video_frame.idl implementation.
- static VideoFrame* Create(ImageBitmap*, VideoFrameInit*, ExceptionState&);
+ static VideoFrame* Create(ScriptState*,
+ const CanvasImageSourceUnion&,
+ const VideoFrameInit*,
+ ExceptionState&);
+ static VideoFrame* Create(ScriptState*,
+ const String& format,
+ const HeapVector<Member<PlaneInit>>&,
+ const VideoFramePlaneInit*,
+ ExceptionState&);
String format() const;
base::Optional<HeapVector<Member<Plane>>> planes();
@@ -61,33 +81,48 @@ class MODULES_EXPORT VideoFrame final : public ScriptWrappable,
// Invalidates |handle_|, releasing underlying media::VideoFrame references.
// This effectively "destroys" all frames sharing the same Handle.
- void destroy();
+ void close();
+
+ // DEPRECATED. Alias for close().
+ void destroy(ExecutionContext*);
- // Creates a copy of |this|, with a new Handle, referencing the same
- // media::VideoFrame. The cloned frame will not be destroyed when |this| is,
+ // Creates a clone of |this|, with a new Handle, referencing the same
+ // media::VideoFrame. The cloned frame will not be closed when |this| is,
// and its lifetime should be independently managed.
- VideoFrame* clone(ExceptionState&);
+ VideoFrame* clone(ScriptState*, ExceptionState&);
+ // TODO(crbug.com/1179109): Remove this method. Internal callers should only
+ // hold onto scoped_refptr objects instead of blink::VideoFrames. Internal
+ // callers should use VideoFrameHandle::CloneForInternalUse().
+ VideoFrame* CloneFromNative(ExecutionContext*);
+
+ // TODO(crbug.com/1175907): Remove this method. window.createImageBitmap() is
+ // the preferred mechanism.
ScriptPromise createImageBitmap(ScriptState*,
const ImageBitmapOptions*,
ExceptionState&);
- scoped_refptr<VideoFrameHandle> handle();
-
// Convenience functions
- scoped_refptr<media::VideoFrame> frame();
- scoped_refptr<const media::VideoFrame> frame() const;
+ scoped_refptr<VideoFrameHandle> handle() const { return handle_; }
+ scoped_refptr<media::VideoFrame> frame() const { return handle_->frame(); }
// GarbageCollected override
void Trace(Visitor*) const override;
private:
- static bool IsSupportedPlanarFormat(media::VideoFrame*);
+ // CanvasImageSource implementation
+ scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
+ const FloatSize&) override;
+ bool WouldTaintOrigin() const override;
+ FloatSize ElementSize(const FloatSize&,
+ const RespectImageOrientationEnum) const override;
+ bool IsVideoFrame() const override;
+ bool IsOpaque() const override;
+ bool IsAccelerated() const override;
// ImageBitmapSource implementation
static constexpr uint64_t kCpuEfficientFrameSize = 320u * 240u;
IntSize BitmapSourceSize() const override;
- bool preferAcceleratedImageBitmap() const;
ScriptPromise CreateImageBitmap(ScriptState*,
base::Optional<IntRect> crop_rect,
const ImageBitmapOptions*,
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 ce398368e02..f851e498949 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl
@@ -9,7 +9,12 @@
Serializable,
RuntimeEnabled=WebCodecs
] interface VideoFrame {
- [RaisesException] constructor(ImageBitmap source, VideoFrameInit init);
+ [CallWith=ScriptState, RaisesException]
+ constructor(CanvasImageSource source, optional VideoFrameInit init = {});
+ [CallWith=ScriptState, RaisesException]
+ constructor(VideoPixelFormat format,
+ sequence<PlaneInit> planes,
+ VideoFramePlaneInit init);
// TODO(sandersd): Provide a way to find out what pixel formats are supported.
// TODO(sandersd): Provide a way to convert to a specific pixel format, and to
@@ -45,17 +50,20 @@
// TODO(sandersd): color space metadata.
// TODO(sandersd): rotation metadata.
+ // DEPRECATED: use close() instead.
// Release held resources immediately.
- // TODO(sandersd): Describe how a destroyed VideoFrame acts.
- void destroy();
+ [CallWith=ExecutionContext] void destroy();
+
+ // Release held resources.
+ void close();
// Creates of the copy of this VideoFrame, which needs to be independently
// destroyed.
- [RaisesException]
+ [CallWith=ScriptState, RaisesException]
VideoFrame clone();
// Create an ImageBitmap from the crop region, scaled to the display size.
// TODO(sandersd): Should use the global createImageBitmap() instead.
- [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
- optional ImageBitmapOptions options = {});
+ [CallWith=ScriptState, RaisesException] Promise<ImageBitmap>
+ createImageBitmap(optional ImageBitmapOptions options = {});
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc
index 5c8a4c21ae8..e4fcf447412 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc
@@ -4,11 +4,53 @@
#include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
+#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/skia/include/core/SkImage.h"
+
namespace blink {
-VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame)
+VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
+ ExecutionContext* context)
: frame_(std::move(frame)) {
DCHECK(frame_);
+ DCHECK(context);
+
+ close_auditor_ = VideoFrameLogger::From(*context).GetCloseAuditor();
+
+ DCHECK(close_auditor_);
+}
+
+VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
+ sk_sp<SkImage> sk_image,
+ ExecutionContext* context)
+ : VideoFrameHandle(std::move(frame), context) {
+ sk_image_ = std::move(sk_image);
+}
+
+VideoFrameHandle::VideoFrameHandle(
+ scoped_refptr<media::VideoFrame> frame,
+ sk_sp<SkImage> sk_image,
+ scoped_refptr<VideoFrameLogger::VideoFrameCloseAuditor> close_auditor)
+ : sk_image_(std::move(sk_image)),
+ frame_(std::move(frame)),
+ close_auditor_(std::move(close_auditor)) {
+ DCHECK(frame_);
+ DCHECK(close_auditor_);
+}
+
+VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
+ sk_sp<SkImage> sk_image)
+ : sk_image_(std::move(sk_image)), frame_(std::move(frame)) {
+ DCHECK(frame_);
+}
+
+VideoFrameHandle::~VideoFrameHandle() {
+ // If we still have a valid |close_auditor_|, Invalidate() was never
+ // called and corresponding frames never received a call to close() before
+ // being garbage collected.
+ if (close_auditor_)
+ close_auditor_->ReportUnclosedFrame();
}
scoped_refptr<media::VideoFrame> VideoFrameHandle::frame() {
@@ -16,9 +58,45 @@ scoped_refptr<media::VideoFrame> VideoFrameHandle::frame() {
return frame_;
}
+sk_sp<SkImage> VideoFrameHandle::sk_image() {
+ WTF::MutexLocker locker(mutex_);
+ return sk_image_;
+}
+
void VideoFrameHandle::Invalidate() {
WTF::MutexLocker locker(mutex_);
+ InvalidateLocked();
+}
+
+void VideoFrameHandle::SetCloseOnClone() {
+ WTF::MutexLocker locker(mutex_);
+ close_on_clone_ = true;
+}
+
+scoped_refptr<VideoFrameHandle> VideoFrameHandle::Clone() {
+ WTF::MutexLocker locker(mutex_);
+ auto cloned_handle = frame_ ? base::MakeRefCounted<VideoFrameHandle>(
+ frame_, sk_image_, close_auditor_)
+ : nullptr;
+
+ if (close_on_clone_)
+ InvalidateLocked();
+
+ return cloned_handle;
+}
+
+scoped_refptr<VideoFrameHandle> VideoFrameHandle::CloneForInternalUse() {
+ WTF::MutexLocker locker(mutex_);
+ return frame_ ? base::MakeRefCounted<VideoFrameHandle>(frame_, sk_image_)
+ : nullptr;
+}
+
+void VideoFrameHandle::InvalidateLocked() {
+ mutex_.AssertAcquired();
+
frame_.reset();
+ sk_image_.reset();
+ close_auditor_.reset();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h
index 49a2e995251..50b84b84a13 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h
@@ -6,35 +6,86 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_FRAME_HANDLE_H_
#include "base/memory/scoped_refptr.h"
-#include "media/base/video_frame.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame_logger.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+// Note: Don't include "media/base/video_frame.h" here without good reason,
+// since it includes a lot of non-blink types which can pollute the namespace.
+
+class SkImage;
+
+namespace media {
+class VideoFrame;
+}
namespace blink {
+class ExecutionContext;
+
// Wrapper class that allows sharing a single |frame_| reference across
// multiple VideoFrames, which can be invalidated for all frames at once.
+//
+// If Invalidate() is not called before the handle's destructor runs, this means
+// that none of the VideoFrames sharing this handle were closed, and they were
+// all GC'ed instead. This can lead to stalls, since frames are not released
+// fast enough through the GC to keep a pipeline running smoothly. In that case
+// report an unclosed frame through |close_auditor_|.
class MODULES_EXPORT VideoFrameHandle
: public WTF::ThreadSafeRefCounted<VideoFrameHandle> {
public:
- explicit VideoFrameHandle(scoped_refptr<media::VideoFrame>);
+ VideoFrameHandle(scoped_refptr<media::VideoFrame>, ExecutionContext*);
+ VideoFrameHandle(scoped_refptr<media::VideoFrame>,
+ sk_sp<SkImage> sk_image,
+ ExecutionContext*);
+ VideoFrameHandle(scoped_refptr<media::VideoFrame>,
+ sk_sp<SkImage> sk_image,
+ scoped_refptr<VideoFrameLogger::VideoFrameCloseAuditor>);
+ VideoFrameHandle(scoped_refptr<media::VideoFrame>, sk_sp<SkImage> sk_image);
// Returns a copy of |frame_|, which should be re-used throughout the scope
// of a function call, instead of calling frame() multiple times. Otherwise
// the frame could be destroyed between calls.
scoped_refptr<media::VideoFrame> frame();
+ // Returns a copy of |sk_image_| which may be nullptr if this isn't an SkImage
+ // backed VideoFrame.
+ sk_sp<SkImage> sk_image();
+
// Releases the underlying media::VideoFrame reference, affecting all
// blink::VideoFrames and blink::Planes that hold a reference to |this|.
void Invalidate();
+ // Temporary workaround for crbug.com/1182497.
+ // Overrides the next call to Clone() to return |this| without adding a new
+ // reference. This prevents cloning handles when internally posting frames to
+ // a transferred stream, which cannot be cleared.
+ void SetCloseOnClone();
+
+ // Clones this VideoFrameHandle into a new VideoFrameHandle object.
+ scoped_refptr<VideoFrameHandle> Clone();
+
+ // Same as above, but for internal (non-garbage-collected) usage. Drops the
+ // close auditor so warning messages aren't created for unclosed frames.
+ scoped_refptr<VideoFrameHandle> CloneForInternalUse();
+
private:
friend class WTF::ThreadSafeRefCounted<VideoFrameHandle>;
- ~VideoFrameHandle() = default;
+ ~VideoFrameHandle();
+
+ // |mutex_| must be held before calling into this.
+ void InvalidateLocked();
+
+ // Flag that prevents the creation of a new handle during the next Clone()
+ // call. Used as a temporary workaround for crbug.com/1182497.
+ bool close_on_clone_ = false;
WTF::Mutex mutex_;
+ sk_sp<SkImage> sk_image_;
scoped_refptr<media::VideoFrame> frame_;
+ scoped_refptr<VideoFrameLogger::VideoFrameCloseAuditor> close_auditor_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl
index b1c7c21ab8c..cca1c24b169 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl
@@ -5,6 +5,6 @@
// https://github.com/WICG/web-codecs
dictionary VideoFrameInit {
- required unsigned long long timestamp; // microseconds
- unsigned long long duration; // microseconds
-}; \ No newline at end of file
+ unsigned long long timestamp; // microseconds
+ unsigned long long duration; // microseconds
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.cc
new file mode 100644
index 00000000000..119f1c76fbf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.cc
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webcodecs/video_frame_logger.h"
+
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+
+namespace blink {
+
+// How frequently we check for leaks.
+constexpr base::TimeDelta kTimerInterval = base::TimeDelta::FromSeconds(10);
+
+// How long we wait before stopping the timer when there is no activity.
+constexpr base::TimeDelta kTimerShutdownDelay =
+ base::TimeDelta::FromSeconds(60);
+
+void VideoFrameLogger::VideoFrameCloseAuditor::ReportUnclosedFrame() {
+ were_frames_not_closed_ = true;
+}
+
+void VideoFrameLogger::VideoFrameCloseAuditor::Clear() {
+ were_frames_not_closed_ = false;
+}
+
+VideoFrameLogger::VideoFrameLogger(ExecutionContext& context)
+ : Supplement<ExecutionContext>(context),
+ close_auditor_(base::MakeRefCounted<VideoFrameCloseAuditor>()),
+ timer_(context.GetTaskRunner(TaskType::kInternalMedia),
+ this,
+ &VideoFrameLogger::LogCloseErrors) {}
+
+// static
+VideoFrameLogger& VideoFrameLogger::From(ExecutionContext& context) {
+ VideoFrameLogger* supplement =
+ Supplement<ExecutionContext>::From<VideoFrameLogger>(context);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<VideoFrameLogger>(context);
+ Supplement<ExecutionContext>::ProvideTo(context, supplement);
+ }
+
+ return *supplement;
+}
+
+scoped_refptr<VideoFrameLogger::VideoFrameCloseAuditor>
+VideoFrameLogger::GetCloseAuditor() {
+ // We cannot directly log close errors: they are detected during garbage
+ // collection, and it would be unsafe to access GC'ed objects from a GC'ed
+ // object's destructor. Instead, start a timer here to periodically poll for
+ // these errors. The timer should stop itself after a period of inactivity.
+ if (!timer_.IsActive())
+ timer_.StartRepeating(kTimerInterval, FROM_HERE);
+
+ last_auditor_access_ = base::TimeTicks::Now();
+
+ return close_auditor_;
+}
+
+void VideoFrameLogger::LogCreateImageBitmapDeprecationNotice() {
+ if (already_logged_create_image_bitmap_deprecation_)
+ return;
+
+ already_logged_create_image_bitmap_deprecation_ = true;
+ GetSupplementable()->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kDeprecation,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "VideoFrame.createImageBitmap() is deprecated; please use "
+ "createImageBitmap(VideoFrame)."));
+}
+
+void VideoFrameLogger::LogCloseErrors(TimerBase*) {
+ // If it's been a while since this class was used and there are not other
+ // references to |leak_status_|, stop the timer.
+ if (base::TimeTicks::Now() - last_auditor_access_ > kTimerShutdownDelay &&
+ close_auditor_->HasOneRef()) {
+ timer_.Stop();
+ }
+
+ if (!close_auditor_->were_frames_not_closed())
+ return;
+
+ auto* execution_context = GetSupplementable();
+ if (!execution_context->IsContextDestroyed()) {
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kError,
+ "A VideoFrame was garbage collected without being closed. "
+ "Applications should call close() on frames when done with them to "
+ "prevent stalls."));
+ }
+
+ close_auditor_->Clear();
+}
+
+void VideoFrameLogger::Trace(Visitor* visitor) const {
+ visitor->Trace(timer_);
+ Supplement<ExecutionContext>::Trace(visitor);
+}
+
+// static
+const char VideoFrameLogger::kSupplementName[] = "VideoFrameLogger";
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.h
new file mode 100644
index 00000000000..5361c893995
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_logger.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_WEBCODECS_VIDEO_FRAME_LOGGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_FRAME_LOGGER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+#include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+// This class is used to distribute a VideoFrameCloseAuditor flag to
+// VideoFrameHandles. If a handle's destructor is run without having received a
+// call to Invalidate(), it will set |close_auditor_|. The VideoFrameLogger
+// periodically checks whether or not the flag is set, and outputs an error
+// message to the JS console, reminding developers to call close() on their
+// VideoFrames.
+//
+// This class lets us avoid making VideoFrames ExecutionLifeCycleObservers,
+// which could add 1000s of observers per second. It also avoids the use of
+// a pre-finzalizer on VideoFrames, which could have a GC performance impact.
+class MODULES_EXPORT VideoFrameLogger
+ : public GarbageCollected<VideoFrameLogger>,
+ public Supplement<ExecutionContext> {
+ public:
+ // Class that reports when blink::VideoFrames have been garbage collected
+ // without having close() called on them. This is a web page application
+ // error which can cause a web page to stall.
+ class VideoFrameCloseAuditor
+ : public WTF::ThreadSafeRefCounted<VideoFrameCloseAuditor> {
+ public:
+ void ReportUnclosedFrame();
+ void Clear();
+
+ bool were_frames_not_closed() { return were_frames_not_closed_; }
+
+ private:
+ friend class WTF::ThreadSafeRefCounted<VideoFrameCloseAuditor>;
+ ~VideoFrameCloseAuditor() = default;
+
+ bool were_frames_not_closed_ = false;
+ };
+
+ static const char kSupplementName[];
+
+ static VideoFrameLogger& From(ExecutionContext&);
+
+ explicit VideoFrameLogger(ExecutionContext&);
+ virtual ~VideoFrameLogger() = default;
+
+ // Disallow copy and assign.
+ VideoFrameLogger& operator=(const VideoFrameLogger&) = delete;
+ VideoFrameLogger(const VideoFrameLogger&) = delete;
+
+ // Returns |close_auditor_| and starts |timer_| if needed.
+ scoped_refptr<VideoFrameCloseAuditor> GetCloseAuditor();
+
+ void LogCreateImageBitmapDeprecationNotice();
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void LogCloseErrors(TimerBase*);
+
+ base::TimeTicks last_auditor_access_;
+
+ scoped_refptr<VideoFrameCloseAuditor> close_auditor_;
+
+ HeapTaskRunnerTimer<VideoFrameLogger> timer_;
+
+ bool already_logged_create_image_bitmap_deprecation_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_FRAME_LOGGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl
new file mode 100644
index 00000000000..7974353c812
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.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/web-codecs
+
+dictionary VideoFramePlaneInit {
+ required unsigned long long timestamp; // microseconds
+ unsigned long long duration; // microseconds
+
+ unsigned long codedWidth;
+ unsigned long codedHeight;
+ unsigned long cropLeft;
+ unsigned long cropTop;
+ unsigned long cropWidth;
+ unsigned long cropHeight;
+ unsigned long displayWidth;
+ unsigned long displayHeight;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_test.cc
index cf557a54d2e..2e50a847041 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame_test.cc
@@ -3,10 +3,22 @@
// found in the LICENSE file.
#include "media/base/video_frame.h"
+#include "components/viz/test/test_context_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.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/bindings/modules/v8/v8_video_frame_init.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
+#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -14,11 +26,24 @@ namespace blink {
namespace {
+ImageBitmap* ToImageBitmap(V8TestingScope* v8_scope, ScriptValue value) {
+ return NativeValueTraits<ImageBitmap>::NativeValue(
+ v8_scope->GetIsolate(), value.V8Value(), v8_scope->GetExceptionState());
+}
+
class VideoFrameTest : public testing::Test {
public:
+ void SetUp() override {
+ test_context_provider_ = viz::TestContextProvider::Create();
+ InitializeSharedGpuContext(test_context_provider_.get());
+ }
+
+ void TearDown() override { SharedGpuContext::ResetForTesting(); }
+
VideoFrame* CreateBlinkVideoFrame(
- scoped_refptr<media::VideoFrame> media_frame) {
- return MakeGarbageCollected<VideoFrame>(std::move(media_frame));
+ scoped_refptr<media::VideoFrame> media_frame,
+ ExecutionContext* context) {
+ return MakeGarbageCollected<VideoFrame>(std::move(media_frame), context);
}
VideoFrame* CreateBlinkVideoFrameFromHandle(
scoped_refptr<VideoFrameHandle> handle) {
@@ -44,14 +69,20 @@ class VideoFrameTest : public testing::Test {
media_frame->set_timestamp(timestamp);
return media_frame;
}
+
+ private:
+ scoped_refptr<viz::TestContextProvider> test_context_provider_;
};
TEST_F(VideoFrameTest, ConstructorAndAttributes) {
+ V8TestingScope scope;
+
scoped_refptr<media::VideoFrame> media_frame = CreateBlackMediaVideoFrame(
base::TimeDelta::FromMicroseconds(1000), media::PIXEL_FORMAT_I420,
gfx::Size(112, 208) /* coded_size */,
gfx::Size(100, 200) /* visible_size */);
- VideoFrame* blink_frame = CreateBlinkVideoFrame(media_frame);
+ VideoFrame* blink_frame =
+ CreateBlinkVideoFrame(media_frame, scope.GetExecutionContext());
EXPECT_EQ(1000u, blink_frame->timestamp().value());
EXPECT_EQ(112u, blink_frame->codedWidth());
@@ -60,7 +91,7 @@ TEST_F(VideoFrameTest, ConstructorAndAttributes) {
EXPECT_EQ(200u, blink_frame->cropHeight());
EXPECT_EQ(media_frame, blink_frame->frame());
- blink_frame->destroy();
+ blink_frame->close();
EXPECT_FALSE(blink_frame->timestamp().has_value());
EXPECT_EQ(0u, blink_frame->codedWidth());
@@ -70,10 +101,13 @@ TEST_F(VideoFrameTest, ConstructorAndAttributes) {
EXPECT_EQ(nullptr, blink_frame->frame());
}
-TEST_F(VideoFrameTest, FramesSharingHandleDestruction) {
+TEST_F(VideoFrameTest, FramesSharingHandleClose) {
+ V8TestingScope scope;
+
scoped_refptr<media::VideoFrame> media_frame =
CreateDefaultBlackMediaVideoFrame();
- VideoFrame* blink_frame = CreateBlinkVideoFrame(media_frame);
+ VideoFrame* blink_frame =
+ CreateBlinkVideoFrame(media_frame, scope.GetExecutionContext());
VideoFrame* frame_with_shared_handle =
CreateBlinkVideoFrameFromHandle(blink_frame->handle());
@@ -82,18 +116,21 @@ TEST_F(VideoFrameTest, FramesSharingHandleDestruction) {
// media::VideoFrame reference.
EXPECT_EQ(media_frame, frame_with_shared_handle->frame());
- // Destroying a frame should invalidate all frames sharing the same handle.
- blink_frame->destroy();
+ // Closing a frame should invalidate all frames sharing the same handle.
+ blink_frame->close();
EXPECT_EQ(nullptr, frame_with_shared_handle->frame());
}
-TEST_F(VideoFrameTest, FramesNotSharingHandleDestruction) {
+TEST_F(VideoFrameTest, FramesNotSharingHandleClose) {
+ V8TestingScope scope;
+
scoped_refptr<media::VideoFrame> media_frame =
CreateDefaultBlackMediaVideoFrame();
- VideoFrame* blink_frame = CreateBlinkVideoFrame(media_frame);
+ VideoFrame* blink_frame =
+ CreateBlinkVideoFrame(media_frame, scope.GetExecutionContext());
- auto new_handle =
- base::MakeRefCounted<VideoFrameHandle>(blink_frame->frame());
+ auto new_handle = base::MakeRefCounted<VideoFrameHandle>(
+ blink_frame->frame(), scope.GetExecutionContext());
VideoFrame* frame_with_new_handle =
CreateBlinkVideoFrameFromHandle(std::move(new_handle));
@@ -101,8 +138,8 @@ TEST_F(VideoFrameTest, FramesNotSharingHandleDestruction) {
EXPECT_EQ(media_frame, frame_with_new_handle->frame());
// If a frame was created a new handle reference the same media::VideoFrame,
- // one frame's destruction should not affect the other.
- blink_frame->destroy();
+ // one frame's closure should not affect the other.
+ blink_frame->close();
EXPECT_EQ(media_frame, frame_with_new_handle->frame());
}
@@ -111,37 +148,145 @@ TEST_F(VideoFrameTest, ClonedFrame) {
scoped_refptr<media::VideoFrame> media_frame =
CreateDefaultBlackMediaVideoFrame();
- VideoFrame* blink_frame = CreateBlinkVideoFrame(media_frame);
+ VideoFrame* blink_frame =
+ CreateBlinkVideoFrame(media_frame, scope.GetExecutionContext());
- VideoFrame* cloned_frame = blink_frame->clone(scope.GetExceptionState());
+ VideoFrame* cloned_frame =
+ blink_frame->clone(scope.GetScriptState(), scope.GetExceptionState());
// The cloned frame should be referencing the same media::VideoFrame.
EXPECT_EQ(blink_frame->frame(), cloned_frame->frame());
EXPECT_EQ(media_frame, cloned_frame->frame());
EXPECT_FALSE(scope.GetExceptionState().HadException());
- blink_frame->destroy();
+ blink_frame->close();
- // Destroying the original frame should not affect the cloned frame.
+ // Closing the original frame should not affect the cloned frame.
EXPECT_EQ(media_frame, cloned_frame->frame());
}
-TEST_F(VideoFrameTest, CloningDestroyedFrame) {
+TEST_F(VideoFrameTest, CloningClosedFrame) {
V8TestingScope scope;
scoped_refptr<media::VideoFrame> media_frame =
CreateDefaultBlackMediaVideoFrame();
- VideoFrame* blink_frame = CreateBlinkVideoFrame(media_frame);
+ VideoFrame* blink_frame =
+ CreateBlinkVideoFrame(media_frame, scope.GetExecutionContext());
- blink_frame->destroy();
+ blink_frame->close();
- VideoFrame* cloned_frame = blink_frame->clone(scope.GetExceptionState());
+ VideoFrame* cloned_frame =
+ blink_frame->clone(scope.GetScriptState(), scope.GetExceptionState());
// No frame should have been created, and there should be an exception.
EXPECT_EQ(nullptr, cloned_frame);
EXPECT_TRUE(scope.GetExceptionState().HadException());
}
+TEST_F(VideoFrameTest, LeakedHandlesReportLeaks) {
+ V8TestingScope scope;
+
+ // Create a handle directly instead of a video frame, to avoid dealing with
+ // the GarbageCollector.
+ scoped_refptr<media::VideoFrame> media_frame =
+ CreateDefaultBlackMediaVideoFrame();
+ auto handle = base::MakeRefCounted<VideoFrameHandle>(
+ media_frame, scope.GetExecutionContext());
+
+ // Remove the last reference to the handle without calling Invalidate().
+ handle.reset();
+
+ auto& logger = VideoFrameLogger::From(*scope.GetExecutionContext());
+
+ EXPECT_TRUE(logger.GetCloseAuditor()->were_frames_not_closed());
+}
+
+TEST_F(VideoFrameTest, InvalidatedHandlesDontReportLeaks) {
+ V8TestingScope scope;
+
+ // Create a handle directly instead of a video frame, to avoid dealing with
+ // the GarbageCollector.
+ scoped_refptr<media::VideoFrame> media_frame =
+ CreateDefaultBlackMediaVideoFrame();
+ auto handle = base::MakeRefCounted<VideoFrameHandle>(
+ media_frame, scope.GetExecutionContext());
+
+ handle->Invalidate();
+ handle.reset();
+
+ auto& logger = VideoFrameLogger::From(*scope.GetExecutionContext());
+
+ EXPECT_FALSE(logger.GetCloseAuditor()->were_frames_not_closed());
+}
+
+TEST_F(VideoFrameTest, ImageBitmapCreationAndZeroCopyRoundTrip) {
+ V8TestingScope scope;
+
+ auto* init = VideoFrameInit::Create();
+ init->setTimestamp(0);
+
+ sk_sp<SkSurface> surface(SkSurface::MakeRaster(
+ SkImageInfo::MakeN32Premul(5, 5, SkColorSpace::MakeSRGB())));
+ sk_sp<SkImage> original_image = surface->makeImageSnapshot();
+
+ const auto* default_options = ImageBitmapOptions::Create();
+ auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(
+ UnacceleratedStaticBitmapImage::Create(original_image), base::nullopt,
+ default_options);
+ CanvasImageSourceUnion source;
+ source.SetImageBitmap(image_bitmap);
+ auto* video_frame = VideoFrame::Create(scope.GetScriptState(), source, init,
+ scope.GetExceptionState());
+
+ EXPECT_EQ(video_frame->handle()->sk_image(), original_image);
+
+ {
+ auto promise = video_frame->createImageBitmap(
+ scope.GetScriptState(), default_options, scope.GetExceptionState());
+ ScriptPromiseTester tester(scope.GetScriptState(), promise);
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsFulfilled());
+ auto* new_bitmap = ToImageBitmap(&scope, tester.Value());
+ ASSERT_TRUE(new_bitmap);
+
+ auto bitmap_image =
+ new_bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSwSkImage();
+ EXPECT_EQ(bitmap_image, original_image);
+ }
+
+ auto* clone =
+ video_frame->clone(scope.GetScriptState(), scope.GetExceptionState());
+ EXPECT_EQ(clone->handle()->sk_image(), original_image);
+}
+
+TEST_F(VideoFrameTest, VideoFrameFromGPUImageBitmap) {
+ V8TestingScope scope;
+
+ auto context_provider_wrapper = SharedGpuContext::ContextProviderWrapper();
+ CanvasResourceParams resource_params;
+ auto resource_provider = CanvasResourceProvider::CreateSharedImageProvider(
+ IntSize(100, 100), kLow_SkFilterQuality, resource_params,
+ CanvasResourceProvider::ShouldInitialize::kNo, context_provider_wrapper,
+ RasterMode::kGPU, true /*is_origin_top_left*/,
+ 0u /*shared_image_usage_flags*/);
+
+ scoped_refptr<StaticBitmapImage> bitmap = resource_provider->Snapshot();
+ ASSERT_TRUE(bitmap->IsTextureBacked());
+
+ auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(bitmap);
+ EXPECT_TRUE(image_bitmap);
+ EXPECT_TRUE(image_bitmap->BitmapImage()->IsTextureBacked());
+
+ auto* init = VideoFrameInit::Create();
+ init->setTimestamp(0);
+
+ CanvasImageSourceUnion source;
+ source.SetImageBitmap(image_bitmap);
+ auto* video_frame = VideoFrame::Create(scope.GetScriptState(), source, init,
+ scope.GetExceptionState());
+ ASSERT_TRUE(video_frame);
+}
+
} // namespace
} // namespace blink
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
index b35fbefee2a..dec3f3b55ae 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl
@@ -5,9 +5,21 @@
// https://github.com/WICG/web-codecs
enum VideoPixelFormat {
- // 4:2:0 subsampled 3 plane Y,U,V
+ // 4:2:0 subsampled 3 plane Y,U,V or 4 plane Y,U,V,A
"I420",
// 4:2:0 subsampled 2 plane Y,UV
"NV12",
+
+ // 32bpp RGBA (byte-order), 1 plane.
+ "ABGR",
+
+ // 32bpp BGRA (byte-order), 1 plane.
+ "ARGB",
+
+ // 24bpp RGBX (byte-order), 1 plane.
+ "XBGR",
+
+ // 24bpp BGRX (byte-order), 1 plane.
+ "XRGB",
};
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc
index 52edbaa5845..6f459ff15f3 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc
@@ -8,6 +8,7 @@
#include "media/base/video_frame.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -28,6 +29,13 @@ VideoTrackReader::VideoTrackReader(ScriptState* script_state,
track_(track) {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kWebCodecs);
+
+ ExecutionContext::From(script_state)
+ ->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kDeprecation,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "VideoTrackReader is deprecated; use MediaStreamTrackProcessor "
+ "instead."));
}
void VideoTrackReader::start(V8VideoFrameOutputCallback* callback,
@@ -72,6 +80,7 @@ void VideoTrackReader::StopInternal() {
void VideoTrackReader::OnFrameFromVideoTrack(
scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
base::TimeTicks estimated_capture_time) {
// The value of estimated_capture_time here seems to almost always be the
// system clock and most implementations of this callback ignore it.
@@ -81,11 +90,13 @@ void VideoTrackReader::OnFrameFromVideoTrack(
*real_time_media_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&VideoTrackReader::ExecuteCallbackOnMainThread,
WrapCrossThreadPersistent(this),
- std::move(media_frame)));
+ std::move(media_frame),
+ std::move(scaled_media_frames)));
}
void VideoTrackReader::ExecuteCallbackOnMainThread(
- scoped_refptr<media::VideoFrame> media_frame) {
+ scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/) {
DCHECK(real_time_media_task_runner_->BelongsToCurrentThread());
if (!callback_) {
@@ -99,8 +110,14 @@ void VideoTrackReader::ExecuteCallbackOnMainThread(
// We may want to invalidate |media_frames| when constraints change, but it's
// unclear whether this is a problem for now.
+ auto* context = GetExecutionContext();
+ if (!context)
+ return;
+
+ // Scaled media frames are currently ignored.
callback_->InvokeAndReportException(
- nullptr, MakeGarbageCollected<VideoFrame>(std::move(media_frame)));
+ nullptr,
+ MakeGarbageCollected<VideoFrame>(std::move(media_frame), context));
}
void VideoTrackReader::OnReadyStateChanged(
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.h
index f8dd0e02f94..15c22aced5b 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.h
@@ -16,6 +16,8 @@ namespace blink {
class ScriptState;
+// Note: This class is deprecated. Use MediaStreamTrackProcessor instead.
+// TODO(crbug.com/1157610): remove this class.
class MODULES_EXPORT VideoTrackReader final
: public ScriptWrappable,
public ExecutionContextLifecycleObserver,
@@ -47,13 +49,16 @@ class MODULES_EXPORT VideoTrackReader final
void OnReadyStateChanged(WebMediaStreamSource::ReadyState) override;
// Callback For MediaStreamVideoSink::ConnectToTrack.
- void OnFrameFromVideoTrack(scoped_refptr<media::VideoFrame> media_frame,
- base::TimeTicks estimated_capture_time);
+ void OnFrameFromVideoTrack(
+ scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
+ base::TimeTicks estimated_capture_time);
void StopInternal();
void ExecuteCallbackOnMainThread(
- scoped_refptr<media::VideoFrame> media_frame);
+ scoped_refptr<media::VideoFrame> media_frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames);
// Whether we are connected to |track_| and using |callback_| to deliver
// frames.
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl
index b1d83edfa95..fecfe4d0788 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl
@@ -8,6 +8,8 @@
Exposed=Window,
RuntimeEnabled=WebCodecs
] interface VideoTrackReader {
+ // DEPRECATED: use MediaStreamTrackProcessor instead.
+ // TODO(https://crbug.com/1157610): remove this idl.
[CallWith=ScriptState, RaisesException, MeasureAs=WebCodecsVideoTrackReader]
constructor(MediaStreamTrack track);
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc
index c784aa6b4dd..c19ffe65520 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc
@@ -46,9 +46,9 @@ class VideoTrackReaderWriterTest : public testing::Test {
}
protected:
- VideoFrame* CreateBlackVideoFrame() {
+ VideoFrame* CreateBlackVideoFrame(ExecutionContext* context) {
return MakeGarbageCollected<VideoFrame>(
- media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100)));
+ media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100)), context);
}
void RunIOUntilIdle() const {
@@ -84,7 +84,7 @@ TEST_F(VideoTrackReaderWriterTest, WriteAndRead) {
reader->start(GetCallback(read_output_function), ASSERT_NO_EXCEPTION);
- auto* frame = CreateBlackVideoFrame();
+ auto* frame = CreateBlackVideoFrame(scope.GetExecutionContext());
writer->writable()
->getWriter(script_state, ASSERT_NO_EXCEPTION)
->write(script_state,
@@ -125,7 +125,7 @@ TEST_F(VideoTrackReaderWriterTest, AutoRelease) {
auto* writer =
VideoTrackWriter::Create(script_state, &params, ASSERT_NO_EXCEPTION);
- auto* frame = CreateBlackVideoFrame();
+ auto* frame = CreateBlackVideoFrame(scope.GetExecutionContext());
writer->writable()
->getWriter(script_state, ASSERT_NO_EXCEPTION)
->write(script_state,
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
index ca73526be03..eccb736deac 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
@@ -57,7 +57,7 @@ class VideoTrackWritableStreamSink final : public UnderlyingSinkBase {
source_->PushFrame(video_frame->frame(), estimated_capture_time);
if (release_frames_)
- video_frame->destroy();
+ video_frame->close();
return ScriptPromise::CastUndefined(script_state);
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/web_codecs_error_callback.idl b/chromium/third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl
index 4dcaf89f186..4dcaf89f186 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/web_codecs_error_callback.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webdatabase/DIR_METADATA
new file mode 100644
index 00000000000..0a03f2255c7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>WebSQL"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/OWNERS b/chromium/third_party/blink/renderer/modules/webdatabase/OWNERS
index aab38fa2736..8d602dce575 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/OWNERS
@@ -3,6 +3,3 @@ pwnall@chromium.org
# Secondary
jsbell@chromium.org
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>WebSQL
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
index 8c4b50829b0..0949be546e3 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database.cc
@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/modules/webdatabase/database.h"
#include <memory>
+#include <utility>
#include "base/synchronization/waitable_event.h"
#include "base/thread_annotations.h"
@@ -240,7 +241,7 @@ Database::Database(DatabaseContext* database_context,
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::kWebDatabase,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+ {SchedulingPolicy::DisableBackForwardCache()})) {
DCHECK(IsMainThread());
context_thread_security_origin_ =
database_context_->GetSecurityOrigin()->IsolatedCopy();
@@ -849,7 +850,7 @@ void Database::RunTransaction(
GetDatabaseTaskRunner()->PostTask(
FROM_HERE, WTF::Bind(&CallTransactionErrorCallback,
WrapPersistent(transaction_error_callback),
- WTF::Passed(std::move(error))));
+ std::move(error)));
}
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_context.h b/chromium/third_party/blink/renderer/modules/webdatabase/database_context.h
index 3b6dabaf5b6..d3c0caaece8 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database_context.h
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_context.h
@@ -46,7 +46,7 @@ class DatabaseContext final : public GarbageCollected<DatabaseContext>,
static DatabaseContext* Create(ExecutionContext*);
explicit DatabaseContext(ExecutionContext*);
- ~DatabaseContext();
+ ~DatabaseContext() override;
void Trace(Visitor*) const override;
// For life-cycle management (inherited from
diff --git a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
index 7e489e4548e..05f583503aa 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
@@ -156,6 +156,8 @@ blink_modules_sources("webgl") {
"webgl_video_texture.cc",
"webgl_video_texture.h",
"webgl_video_texture_enum.h",
+ "webgl_webcodecs_video_frame.cc",
+ "webgl_webcodecs_video_frame.h",
]
# The modules/webgl/ directly is a larger module, and
@@ -164,6 +166,10 @@ blink_modules_sources("webgl") {
configs += [ "//third_party/blink/renderer/core:blink_core_pch" ]
public_deps = [ "//device/vr/public/mojom:vr_service_blink" ]
- deps = [ "//third_party/blink/renderer/modules/xr:xr" ]
+ deps = [
+ "//build:chromeos_buildflags",
+ "//third_party/blink/renderer/modules/xr:xr"
+ ]
+ deps += [ "//third_party/blink/renderer/modules/webcodecs:webcodecs" ]
allow_circular_includes_from = deps
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/DEPS b/chromium/third_party/blink/renderer/modules/webgl/DEPS
index 0cac6d5da5e..4e7a58fdd72 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/DEPS
+++ b/chromium/third_party/blink/renderer/modules/webgl/DEPS
@@ -6,6 +6,12 @@ include_rules = [
"+gpu/command_buffer/client/raster_interface.h",
"+gpu/command_buffer/common/capabilities.h",
"+gpu/config/gpu_feature_info.h",
+ "+media/base/video_frame.h",
+ "+media/base/wait_and_replace_sync_token_client.h",
+ "+media/renderers/paint_canvas_video_renderer.h",
+ "+media/video/gpu_memory_buffer_video_frame_pool.h",
"+skia/ext",
+ "+third_party/blink/renderer/modules/webcodecs",
"+ui/gl/gpu_preference.h",
+ "+ui/gfx/color_transform.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/webgl/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webgl/DIR_METADATA
new file mode 100644
index 00000000000..ab221ae12bf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebGL"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webgl/OWNERS b/chromium/third_party/blink/renderer/modules/webgl/OWNERS
index 5a7463513ec..2a09b594120 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webgl/OWNERS
@@ -3,5 +3,3 @@ kainino@chromium.org
kbr@chromium.org
zmo@chromium.org
jdarpinian@chromium.org
-
-# COMPONENT: Blink>WebGL
diff --git a/chromium/third_party/blink/renderer/modules/webgl/idls.gni b/chromium/third_party/blink/renderer/modules/webgl/idls.gni
index d9d97dd1f45..8ad7b1cdedc 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webgl/idls.gni
@@ -75,11 +75,14 @@ modules_idl_files = [
"webgl_vertex_array_object.idl",
"webgl_vertex_array_object_oes.idl",
"webgl_video_texture.idl",
+ "webgl_webcodecs_video_frame.idl",
]
modules_dictionary_idl_files = [
"webgl_context_attributes.idl",
"webgl_context_event_init.idl",
+ "webgl_webcodecs_texture_info.idl",
+ "webgl_webcodecs_video_frame_handle.idl",
]
modules_dependency_idl_files = [
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 2afee686cb5..425d81014b5 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
@@ -41,6 +41,7 @@
#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw.h"
#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h"
#include "third_party/blink/renderer/modules/webgl/webgl_video_texture.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
namespace blink {
@@ -172,6 +173,7 @@ void WebGL2RenderingContext::RegisterContextExtensions() {
RegisterExtension(webgl_multi_draw_instanced_base_vertex_base_instance_,
kDraftExtension);
RegisterExtension(webgl_video_texture_, kDraftExtension);
+ RegisterExtension(webgl_webcodecs_video_frame_, kDraftExtension);
RegisterExtension(ovr_multiview2_);
}
@@ -201,6 +203,7 @@ void WebGL2RenderingContext::Trace(Visitor* visitor) const {
visitor->Trace(webgl_multi_draw_);
visitor->Trace(webgl_multi_draw_instanced_base_vertex_base_instance_);
visitor->Trace(webgl_video_texture_);
+ visitor->Trace(webgl_webcodecs_video_frame_);
WebGL2RenderingContextBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
index c325a8dc62e..89440ed0810 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
@@ -31,6 +31,7 @@ class WebGLMultiDraw;
class WebGLMultiDrawInstancedBaseVertexBaseInstance;
class KHRParallelShaderCompile;
class WebGLVideoTexture;
+class WebGLWebCodecsVideoFrame;
class WebGL2RenderingContext : public WebGL2RenderingContextBase {
DEFINE_WRAPPERTYPEINFO();
@@ -98,6 +99,7 @@ class WebGL2RenderingContext : public WebGL2RenderingContextBase {
Member<WebGLMultiDrawInstancedBaseVertexBaseInstance>
webgl_multi_draw_instanced_base_vertex_base_instance_;
Member<WebGLVideoTexture> webgl_video_texture_;
+ Member<WebGLWebCodecsVideoFrame> webgl_webcodecs_video_frame_;
};
} // namespace blink
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 acbe6a4a05c..be9b6fa1cad 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
@@ -246,7 +246,7 @@ void WebGL2RenderingContextBase::bufferData(
return;
void* sub_base_address = nullptr;
int64_t sub_byte_length = 0;
- if (!ValidateSubSourceAndGetData(src_data.View(), src_offset, length,
+ if (!ValidateSubSourceAndGetData(src_data.Get(), src_offset, length,
&sub_base_address, &sub_byte_length)) {
SynthesizeGLError(GL_INVALID_VALUE, "bufferData",
"srcOffset + length too large");
@@ -285,7 +285,7 @@ void WebGL2RenderingContextBase::bufferSubData(
return;
void* sub_base_address = nullptr;
int64_t sub_byte_length = 0;
- if (!ValidateSubSourceAndGetData(src_data.View(), src_offset, length,
+ if (!ValidateSubSourceAndGetData(src_data.Get(), src_offset, length,
&sub_base_address, &sub_byte_length)) {
SynthesizeGLError(GL_INVALID_VALUE, "bufferSubData",
"srcOffset + length too large");
@@ -368,8 +368,8 @@ void WebGL2RenderingContextBase::getBufferSubData(
void* destination_data_ptr = nullptr;
int64_t destination_byte_length = 0;
const char* message = ValidateGetBufferSubData(
- __FUNCTION__, target, src_byte_offset, dst_data.View(), dst_offset,
- length, &source_buffer, &destination_data_ptr, &destination_byte_length);
+ __FUNCTION__, target, src_byte_offset, dst_data.Get(), dst_offset, length,
+ &source_buffer, &destination_data_ptr, &destination_byte_length);
if (message) {
// If there was a GL error, it was already synthesized in
// validateGetBufferSubData, so it's not done here.
@@ -791,7 +791,7 @@ void WebGL2RenderingContextBase::readPixels(
return;
}
- ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), 0);
+ ReadPixelsHelper(x, y, width, height, format, type, pixels.Get(), 0);
}
void WebGL2RenderingContextBase::readPixels(
@@ -811,7 +811,7 @@ void WebGL2RenderingContextBase::readPixels(
return;
}
- ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), offset);
+ ReadPixelsHelper(x, y, width, height, format, type, pixels.Get(), offset);
}
void WebGL2RenderingContextBase::readPixels(GLint x,
@@ -854,7 +854,7 @@ void WebGL2RenderingContextBase::readPixels(GLint x,
size))
return;
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
{
ScopedDrawingBufferBinder binder(GetDrawingBuffer(), framebuffer);
@@ -1158,7 +1158,7 @@ void WebGL2RenderingContextBase::texImage2D(
}
TexImageHelperDOMArrayBufferView(
kTexImage2D, target, level, internalformat, width, height, 1, border,
- format, type, 0, 0, 0, data.View(), kNullNotReachable, src_offset);
+ format, type, 0, 0, 0, data.Get(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texImage2D(GLenum target,
@@ -1258,6 +1258,31 @@ void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
}
+void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ if (isContextLost())
+ return;
+ if (bound_pixel_unpack_buffer_) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
+ "a buffer is bound to PIXEL_UNPACK_BUFFER");
+ return;
+ }
+
+ TexImageHelperVideoFrame(execution_context->GetSecurityOrigin(), kTexImage2D,
+ target, level, internalformat, format, type, 0, 0, 0,
+ frame, GetTextureSourceSubRectangle(width, height),
+ 1, 0, exception_state);
+}
+
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
@@ -1362,6 +1387,27 @@ void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
exception_state);
}
+void WebGL2RenderingContextBase::texImage2D(ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ if (isContextLost())
+ return;
+ if (bound_pixel_unpack_buffer_) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "texImage2D",
+ "a buffer is bound to PIXEL_UNPACK_BUFFER");
+ return;
+ }
+
+ WebGLRenderingContextBase::texImage2D(execution_context, target, level,
+ internalformat, format, type, frame,
+ exception_state);
+}
+
void WebGL2RenderingContextBase::texImage2D(GLenum target,
GLint level,
GLint internalformat,
@@ -1421,7 +1467,7 @@ void WebGL2RenderingContextBase::texSubImage2D(
}
TexImageHelperDOMArrayBufferView(
kTexSubImage2D, target, level, 0, width, height, 1, 0, format, type,
- xoffset, yoffset, 0, pixels.View(), kNullNotReachable, src_offset);
+ xoffset, yoffset, 0, pixels.Get(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texSubImage2D(GLenum target,
@@ -1525,6 +1571,32 @@ void WebGL2RenderingContextBase::texSubImage2D(
}
void WebGL2RenderingContextBase::texSubImage2D(
+ ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ if (isContextLost())
+ return;
+ if (bound_pixel_unpack_buffer_) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage2D",
+ "a buffer is bound to PIXEL_UNPACK_BUFFER");
+ return;
+ }
+
+ TexImageHelperVideoFrame(
+ execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
+ format, type, xoffset, yoffset, 0, frame,
+ GetTextureSourceSubRectangle(width, height), 1, 0, exception_state);
+}
+
+void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
@@ -1629,6 +1701,21 @@ void WebGL2RenderingContextBase::texSubImage2D(
}
void WebGL2RenderingContextBase::texSubImage2D(
+ ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ WebGLRenderingContextBase::texSubImage2D(execution_context, target, level,
+ xoffset, yoffset, format, type,
+ frame, exception_state);
+}
+
+void WebGL2RenderingContextBase::texSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
@@ -1691,7 +1778,7 @@ void WebGL2RenderingContextBase::texImage3D(
}
TexImageHelperDOMArrayBufferView(kTexImage3D, target, level, internalformat,
width, height, depth, border, format, type,
- 0, 0, 0, pixels.View(), kNullAllowed, 0);
+ 0, 0, 0, pixels.Get(), kNullAllowed, 0);
}
void WebGL2RenderingContextBase::texImage3D(
@@ -1722,7 +1809,7 @@ void WebGL2RenderingContextBase::texImage3D(
}
TexImageHelperDOMArrayBufferView(
kTexImage3D, target, level, internalformat, width, height, depth, border,
- format, type, 0, 0, 0, pixels.View(), kNullNotReachable, src_offset);
+ format, type, 0, 0, 0, pixels.Get(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texImage3D(GLenum target,
@@ -1864,6 +1951,32 @@ void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context,
depth, unpack_image_height_, exception_state);
}
+void WebGL2RenderingContextBase::texImage3D(ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ if (isContextLost())
+ return;
+ if (bound_pixel_unpack_buffer_) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "texImage3D",
+ "a buffer is bound to PIXEL_UNPACK_BUFFER");
+ return;
+ }
+
+ TexImageHelperVideoFrame(execution_context->GetSecurityOrigin(), kTexImage3D,
+ target, level, internalformat, format, type, 0, 0, 0,
+ frame, GetTextureSourceSubRectangle(width, height),
+ depth, unpack_image_height_, exception_state);
+}
+
void WebGL2RenderingContextBase::texImage3D(GLenum target,
GLint level,
GLint internalformat,
@@ -1918,7 +2031,7 @@ void WebGL2RenderingContextBase::texSubImage3D(
TexImageHelperDOMArrayBufferView(
kTexSubImage3D, target, level, 0, width, height, depth, 0, format, type,
- xoffset, yoffset, zoffset, pixels.View(), kNullNotReachable, src_offset);
+ xoffset, yoffset, zoffset, pixels.Get(), kNullNotReachable, src_offset);
}
void WebGL2RenderingContextBase::texSubImage3D(GLenum target,
@@ -2072,6 +2185,35 @@ void WebGL2RenderingContextBase::texSubImage3D(
}
void WebGL2RenderingContextBase::texSubImage3D(
+ ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ if (isContextLost())
+ return;
+ if (bound_pixel_unpack_buffer_) {
+ SynthesizeGLError(GL_INVALID_OPERATION, "texSubImage3D",
+ "a buffer is bound to PIXEL_UNPACK_BUFFER");
+ return;
+ }
+
+ TexImageHelperVideoFrame(execution_context->GetSecurityOrigin(),
+ kTexSubImage3D, target, level, 0, format, type,
+ xoffset, yoffset, zoffset, frame,
+ GetTextureSourceSubRectangle(width, height), depth,
+ unpack_image_height_, exception_state);
+}
+
+void WebGL2RenderingContextBase::texSubImage3D(
GLenum target,
GLint level,
GLint xoffset,
@@ -2114,7 +2256,7 @@ void WebGL2RenderingContextBase::copyTexSubImage3D(GLenum target,
if (!ValidateReadBufferAndGetInfo("copyTexSubImage3D",
read_framebuffer_binding))
return;
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
read_framebuffer_binding);
ContextGL()->CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y,
@@ -2178,8 +2320,7 @@ void WebGL2RenderingContextBase::compressedTexImage2D(
}
ContextGL()->CompressedTexImage2D(
target, level, internalformat, width, height, border, src_length_override,
- static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
- src_offset);
+ static_cast<uint8_t*>(data->BaseAddressMaybeShared()) + src_offset);
}
void WebGL2RenderingContextBase::compressedTexImage2D(GLenum target,
@@ -2262,8 +2403,7 @@ void WebGL2RenderingContextBase::compressedTexSubImage2D(
ContextGL()->CompressedTexSubImage2D(
target, level, xoffset, yoffset, width, height, format,
src_length_override,
- static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
- src_offset);
+ static_cast<uint8_t*>(data->BaseAddressMaybeShared()) + src_offset);
}
void WebGL2RenderingContextBase::compressedTexSubImage2D(GLenum target,
@@ -2327,8 +2467,7 @@ void WebGL2RenderingContextBase::compressedTexImage3D(
ContextGL()->CompressedTexImage3D(
target, level, internalformat, width, height, depth, border,
src_length_override,
- static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
- src_offset);
+ static_cast<uint8_t*>(data->BaseAddressMaybeShared()) + src_offset);
}
void WebGL2RenderingContextBase::compressedTexImage3D(GLenum target,
@@ -2394,8 +2533,7 @@ void WebGL2RenderingContextBase::compressedTexSubImage3D(
ContextGL()->CompressedTexSubImage3D(
target, level, xoffset, yoffset, zoffset, width, height, depth, format,
src_length_override,
- static_cast<uint8_t*>(data.View()->BaseAddressMaybeShared()) +
- src_offset);
+ static_cast<uint8_t*>(data->BaseAddressMaybeShared()) + src_offset);
}
void WebGL2RenderingContextBase::compressedTexSubImage3D(GLenum target,
@@ -2895,15 +3033,14 @@ void WebGL2RenderingContextBase::uniformMatrix2fv(
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
- v.View(), 4, src_offset, src_length))
+ v.Get(), 4, src_offset, src_length))
return;
ContextGL()->UniformMatrix2fv(
location->Location(),
- (src_length
- ? src_length
- : (base::checked_cast<GLuint>(v.View()->length()) - src_offset)) >>
+ (src_length ? src_length
+ : (base::checked_cast<GLuint>(v->length()) - src_offset)) >>
2,
- transpose, v.View()->DataMaybeShared() + src_offset);
+ transpose, v->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix2fv(
@@ -2930,15 +3067,14 @@ void WebGL2RenderingContextBase::uniformMatrix3fv(
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
- v.View(), 9, src_offset, src_length))
+ v.Get(), 9, src_offset, src_length))
return;
ContextGL()->UniformMatrix3fv(
location->Location(),
- (src_length
- ? src_length
- : (base::checked_cast<GLuint>(v.View()->length()) - src_offset)) /
+ (src_length ? src_length
+ : (base::checked_cast<GLuint>(v->length()) - src_offset)) /
9,
- transpose, v.View()->DataMaybeShared() + src_offset);
+ transpose, v->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix3fv(
@@ -2965,15 +3101,14 @@ void WebGL2RenderingContextBase::uniformMatrix4fv(
GLuint src_length) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
- v.View(), 16, src_offset, src_length))
+ v.Get(), 16, src_offset, src_length))
return;
ContextGL()->UniformMatrix4fv(
location->Location(),
- (src_length
- ? src_length
- : (base::checked_cast<GLuint>(v.View()->length()) - src_offset)) >>
+ (src_length ? src_length
+ : (base::checked_cast<GLuint>(v->length()) - src_offset)) >>
4,
- transpose, v.View()->DataMaybeShared() + src_offset);
+ transpose, v->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix4fv(
@@ -3000,15 +3135,15 @@ void WebGL2RenderingContextBase::uniformMatrix2x3fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix2x3fv", location, transpose,
- value.View(), 6, src_offset, src_length))
+ value.Get(), 6, src_offset, src_length))
return;
ContextGL()->UniformMatrix2x3fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) /
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) /
6,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix2x3fv(
@@ -3036,15 +3171,15 @@ void WebGL2RenderingContextBase::uniformMatrix3x2fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix3x2fv", location, transpose,
- value.View(), 6, src_offset, src_length))
+ value.Get(), 6, src_offset, src_length))
return;
ContextGL()->UniformMatrix3x2fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) /
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) /
6,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix3x2fv(
@@ -3072,15 +3207,15 @@ void WebGL2RenderingContextBase::uniformMatrix2x4fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix2x4fv", location, transpose,
- value.View(), 8, src_offset, src_length))
+ value.Get(), 8, src_offset, src_length))
return;
ContextGL()->UniformMatrix2x4fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) >>
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) >>
3,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix2x4fv(
@@ -3108,15 +3243,15 @@ void WebGL2RenderingContextBase::uniformMatrix4x2fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix4x2fv", location, transpose,
- value.View(), 8, src_offset, src_length))
+ value.Get(), 8, src_offset, src_length))
return;
ContextGL()->UniformMatrix4x2fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) >>
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) >>
3,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix4x2fv(
@@ -3144,15 +3279,15 @@ void WebGL2RenderingContextBase::uniformMatrix3x4fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix3x4fv", location, transpose,
- value.View(), 12, src_offset, src_length))
+ value.Get(), 12, src_offset, src_length))
return;
ContextGL()->UniformMatrix3x4fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) /
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) /
12,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix3x4fv(
@@ -3180,15 +3315,15 @@ void WebGL2RenderingContextBase::uniformMatrix4x3fv(
GLuint src_length) {
if (isContextLost() || !ValidateUniformMatrixParameters(
"uniformMatrix4x3fv", location, transpose,
- value.View(), 12, src_offset, src_length))
+ value.Get(), 12, src_offset, src_length))
return;
ContextGL()->UniformMatrix4x3fv(
location->Location(),
- (src_length ? src_length
- : (base::checked_cast<GLuint>(value.View()->length()) -
- src_offset)) /
+ (src_length
+ ? src_length
+ : (base::checked_cast<GLuint>(value->length()) - src_offset)) /
12,
- transpose, value.View()->DataMaybeShared() + src_offset);
+ transpose, value->DataMaybeShared() + src_offset);
}
void WebGL2RenderingContextBase::uniformMatrix4x3fv(
@@ -3362,11 +3497,11 @@ void WebGL2RenderingContextBase::vertexAttribI4iv(
MaybeShared<const DOMInt32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 4) {
+ if (!v.Get() || v->length() < 4) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4iv", "invalid array");
return;
}
- ContextGL()->VertexAttribI4iv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttribI4iv(index, v->DataMaybeShared());
SetVertexAttribType(index, kInt32ArrayType);
}
@@ -3398,11 +3533,11 @@ void WebGL2RenderingContextBase::vertexAttribI4uiv(
MaybeShared<const DOMUint32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 4) {
+ if (!v.Get() || v->length() < 4) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4uiv", "invalid array");
return;
}
- ContextGL()->VertexAttribI4uiv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttribI4uiv(index, v->DataMaybeShared());
SetVertexAttribType(index, kUint32ArrayType);
}
@@ -3477,6 +3612,7 @@ void WebGL2RenderingContextBase::drawArraysInstanced(GLenum mode,
drawing_buffer_.get());
OnBeforeDrawCall();
ContextGL()->DrawArraysInstancedANGLE(mode, first, count, instance_count);
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGL2RenderingContextBase::drawElementsInstanced(GLenum mode,
@@ -3499,6 +3635,7 @@ void WebGL2RenderingContextBase::drawElementsInstanced(GLenum mode,
ContextGL()->DrawElementsInstancedANGLE(
mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)),
instance_count);
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGL2RenderingContextBase::drawRangeElements(GLenum mode,
@@ -3522,6 +3659,7 @@ void WebGL2RenderingContextBase::drawRangeElements(GLenum mode,
ContextGL()->DrawRangeElements(
mode, start, end, count, type,
reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGL2RenderingContextBase::drawBuffers(const Vector<GLenum>& buffers) {
@@ -3627,16 +3765,15 @@ void WebGL2RenderingContextBase::clearBufferiv(GLenum buffer,
GLint drawbuffer,
MaybeShared<DOMInt32Array> value,
GLuint src_offset) {
- if (isContextLost() ||
- !ValidateClearBuffer("clearBufferiv", buffer, value.View()->length(),
- src_offset))
+ if (isContextLost() || !ValidateClearBuffer("clearBufferiv", buffer,
+ value->length(), src_offset))
return;
ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
drawing_buffer_.get());
ContextGL()->ClearBufferiv(buffer, drawbuffer,
- value.View()->DataMaybeShared() + src_offset);
+ value->DataMaybeShared() + src_offset);
UpdateBuffersToAutoClear(kClearBufferiv, buffer, drawbuffer);
}
@@ -3660,16 +3797,15 @@ void WebGL2RenderingContextBase::clearBufferuiv(
GLint drawbuffer,
MaybeShared<DOMUint32Array> value,
GLuint src_offset) {
- if (isContextLost() ||
- !ValidateClearBuffer("clearBufferuiv", buffer, value.View()->length(),
- src_offset))
+ if (isContextLost() || !ValidateClearBuffer("clearBufferuiv", buffer,
+ value->length(), src_offset))
return;
ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
drawing_buffer_.get());
ContextGL()->ClearBufferuiv(buffer, drawbuffer,
- value.View()->DataMaybeShared() + src_offset);
+ value->DataMaybeShared() + src_offset);
UpdateBuffersToAutoClear(kClearBufferuiv, buffer, drawbuffer);
}
@@ -3693,9 +3829,8 @@ void WebGL2RenderingContextBase::clearBufferfv(
GLint drawbuffer,
MaybeShared<DOMFloat32Array> value,
GLuint src_offset) {
- if (isContextLost() ||
- !ValidateClearBuffer("clearBufferfv", buffer, value.View()->length(),
- src_offset))
+ if (isContextLost() || !ValidateClearBuffer("clearBufferfv", buffer,
+ value->length(), src_offset))
return;
// As of this writing the default back buffer will always have an
@@ -3708,7 +3843,7 @@ void WebGL2RenderingContextBase::clearBufferfv(
drawing_buffer_.get());
ContextGL()->ClearBufferfv(buffer, drawbuffer,
- value.View()->DataMaybeShared() + src_offset);
+ value->DataMaybeShared() + src_offset);
// clearBufferiv and clearBufferuiv will currently generate an error
// if they're called against the default back buffer. If support for
// extended canvas color spaces is added, this call might need to be
@@ -5524,7 +5659,6 @@ bool WebGL2RenderingContextBase::ValidateReadPixelsFormatAndType(
return false;
}
return true;
- case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
@@ -5535,6 +5669,23 @@ bool WebGL2RenderingContextBase::ValidateReadPixelsFormatAndType(
return false;
}
return true;
+ case GL_UNSIGNED_SHORT:
+ if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeUint16) {
+ SynthesizeGLError(
+ GL_INVALID_OPERATION, "readPixels",
+ "type GL_UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
+ return false;
+ }
+ if (format == GL_RGBA) {
+ if (!ExtensionEnabled(kEXTTextureNorm16Name)) {
+ SynthesizeGLError(
+ GL_INVALID_ENUM, "readPixels",
+ "invalid format/type combination RGBA/UNSIGNED_SHORT without "
+ "EXT_texture_norm16 support");
+ return false;
+ }
+ }
+ return true;
case GL_SHORT:
if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeInt16) {
SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
index 3c2f41ae692..0b3a2b5d6de 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
@@ -140,6 +140,17 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texImage2D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLsizei,
+ GLsizei,
+ GLint,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texImage2D(GLenum,
GLint,
GLint,
@@ -212,6 +223,17 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texSubImage2D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLint,
+ GLsizei,
+ GLsizei,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texSubImage2D(GLenum,
GLint,
GLint,
@@ -261,6 +283,14 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texImage2D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texImage2D(GLenum,
GLint,
GLint,
@@ -296,6 +326,15 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texSubImage2D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLint,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texSubImage2D(GLenum,
GLint,
GLint,
@@ -374,6 +413,18 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texImage3D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLsizei,
+ GLsizei,
+ GLsizei,
+ GLint,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texImage3D(GLenum,
GLint,
GLint,
@@ -468,6 +519,19 @@ class WebGL2RenderingContextBase : public WebGLRenderingContextBase {
GLenum,
HTMLVideoElement*,
ExceptionState&);
+ void texSubImage3D(ExecutionContext*,
+ GLenum,
+ GLint,
+ GLint,
+ GLint,
+ GLint,
+ GLsizei,
+ GLsizei,
+ GLsizei,
+ GLenum,
+ GLenum,
+ VideoFrame*,
+ ExceptionState&);
void texSubImage3D(GLenum,
GLint,
GLint,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
index 830f701b40c..002319f00e1 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
@@ -297,7 +297,8 @@ interface mixin WebGL2RenderingContextBase {
[CallWith=ExecutionContext, RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, HTMLImageElement image);
[CallWith=ExecutionContext, RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, HTMLCanvasElement canvas);
[CallWith=ExecutionContext, RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, OffscreenCanvas offscreenCanvas);
- [CallWith=ExecutionContext,RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, HTMLVideoElement video);
+ [CallWith=ExecutionContext, RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, HTMLVideoElement video);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, VideoFrame frame);
[RaisesException] void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ImageBitmap bitmap);
void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, GLuint srcOffset);
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLintptr offset);
@@ -306,6 +307,7 @@ interface mixin WebGL2RenderingContextBase {
[CallWith=ExecutionContext, RaisesException] void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, HTMLCanvasElement canvas);
[CallWith=ExecutionContext, RaisesException] void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, OffscreenCanvas offscreenCanvas);
[CallWith=ExecutionContext, RaisesException] void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, HTMLVideoElement video);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, VideoFrame frame);
[RaisesException] void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, ImageBitmap bitmap);
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, GLuint srcOffset);
void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
@@ -316,6 +318,7 @@ interface mixin WebGL2RenderingContextBase {
[CallWith=ExecutionContext, RaisesException] void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, HTMLCanvasElement canvas);
[CallWith=ExecutionContext, RaisesException] void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, OffscreenCanvas offscreenCanvas);
[CallWith=ExecutionContext, RaisesException] void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, HTMLVideoElement video);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, VideoFrame frame);
[RaisesException] void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, ImageBitmap bitmap);
void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels);
void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView pixels, GLuint srcOffset);
@@ -325,6 +328,7 @@ interface mixin WebGL2RenderingContextBase {
[CallWith=ExecutionContext, RaisesException] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, HTMLCanvasElement canvas);
[CallWith=ExecutionContext, RaisesException] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, OffscreenCanvas offscreenCanvas);
[CallWith=ExecutionContext, RaisesException] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, HTMLVideoElement video);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, VideoFrame frame);
[RaisesException] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, ImageBitmap bitmap);
void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, [AllowShared] ArrayBufferView pixels, optional GLuint srcOffset = 0);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.cc
index 4bca3959dcd..9a4cc5556f0 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.cc
@@ -65,6 +65,9 @@ void WebGLDrawInstancedBaseVertexBaseInstance::
WebGLExtensionScopedContext scoped(this);
if (scoped.IsLost())
return;
+
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->DrawArraysInstancedBaseInstanceANGLE(
mode, first, count, instance_count, baseinstance);
}
@@ -80,6 +83,9 @@ void WebGLDrawInstancedBaseVertexBaseInstance::
WebGLExtensionScopedContext scoped(this);
if (scoped.IsLost())
return;
+
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()
->ContextGL()
->DrawElementsInstancedBaseVertexBaseInstanceANGLE(
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
index 54b02a1859d..a27a1fab5a6 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h
@@ -53,6 +53,7 @@ enum WebGLExtensionName {
kWebGLMultiDrawInstancedBaseVertexBaseInstanceName,
kWebGLMultiviewName,
kWebGLVideoTextureName,
+ kWebGLWebCodecsVideoFrameName,
kWebGLExtensionNameCount, // Must be the last entry
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc
index d3dcaca00a8..787111f1499 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.cc
@@ -48,6 +48,8 @@ void WebGLMultiDraw::multiDrawArraysImpl(
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->MultiDrawArraysWEBGL(
mode, &firsts[firstsOffset], &counts[countsOffset], drawcount);
}
@@ -72,6 +74,8 @@ void WebGLMultiDraw::multiDrawElementsImpl(
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->MultiDrawElementsWEBGL(
mode, &counts[countsOffset], type, &offsets[offsetsOffset], drawcount);
}
@@ -101,6 +105,8 @@ void WebGLMultiDraw::multiDrawArraysInstancedImpl(
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->MultiDrawArraysInstancedWEBGL(
mode, &firsts[firstsOffset], &counts[countsOffset],
&instanceCounts[instanceCountsOffset], drawcount);
@@ -132,6 +138,8 @@ void WebGLMultiDraw::multiDrawElementsInstancedImpl(
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->MultiDrawElementsInstancedWEBGL(
mode, &counts[countsOffset], type, &offsets[offsetsOffset],
&instanceCounts[instanceCountsOffset], drawcount);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
index 91de853db2b..e0da2d4c898 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc
@@ -41,8 +41,8 @@ bool WebGLMultiDrawCommon::ValidateArray(WebGLExtensionScopedContext* scoped,
base::span<const int32_t> WebGLMultiDrawCommon::MakeSpan(
const Int32ArrayOrLongSequence& array) {
if (array.IsInt32Array()) {
- return base::span<const int32_t>(array.GetAsInt32Array().View()->Data(),
- array.GetAsInt32Array().View()->length());
+ return base::span<const int32_t>(array.GetAsInt32Array()->Data(),
+ array.GetAsInt32Array()->length());
}
return base::span<const int32_t>(array.GetAsLongSequence().data(),
array.GetAsLongSequence().size());
@@ -52,9 +52,8 @@ base::span<const int32_t> WebGLMultiDrawCommon::MakeSpan(
base::span<const uint32_t> WebGLMultiDrawCommon::MakeSpan(
const Uint32ArrayOrUnsignedLongSequence& array) {
if (array.IsUint32Array()) {
- return base::span<const uint32_t>(
- array.GetAsUint32Array().View()->Data(),
- array.GetAsUint32Array().View()->length());
+ return base::span<const uint32_t>(array.GetAsUint32Array()->Data(),
+ array.GetAsUint32Array()->length());
}
return base::span<const uint32_t>(array.GetAsUnsignedLongSequence().data(),
array.GetAsUnsignedLongSequence().size());
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
index 94f2dd14de7..9c81715fe4f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
@@ -84,6 +84,8 @@ void WebGLMultiDrawInstancedBaseVertexBaseInstance::
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()->ContextGL()->MultiDrawArraysInstancedBaseInstanceWEBGL(
mode, &firsts[firsts_offset], &counts[counts_offset],
&instance_counts[instance_counts_offset],
@@ -133,6 +135,8 @@ void WebGLMultiDrawInstancedBaseVertexBaseInstance::
return;
}
+ scoped.Context()->RecordUKMCanvasDrawnToAtFirstDrawCall();
+
scoped.Context()
->ContextGL()
->MultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
index dea00f2bfb1..cf0e83c16af 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
@@ -72,6 +72,7 @@
#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw.h"
#include "third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.h"
#include "third_party/blink/renderer/modules/webgl/webgl_video_texture.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
namespace blink {
@@ -212,6 +213,7 @@ void WebGLRenderingContext::RegisterContextExtensions() {
RegisterExtension(webgl_lose_context_, kApprovedExtension, kBothPrefixes);
RegisterExtension(webgl_multi_draw_);
RegisterExtension(webgl_video_texture_, kDraftExtension);
+ RegisterExtension(webgl_webcodecs_video_frame_, kDraftExtension);
}
void WebGLRenderingContext::Trace(Visitor* visitor) const {
@@ -249,6 +251,7 @@ void WebGLRenderingContext::Trace(Visitor* visitor) const {
visitor->Trace(webgl_lose_context_);
visitor->Trace(webgl_multi_draw_);
visitor->Trace(webgl_video_texture_);
+ visitor->Trace(webgl_webcodecs_video_frame_);
WebGLRenderingContextBase::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
index 6264f9c8d1c..ffa8653144c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
@@ -59,6 +59,7 @@ class WebGLDepthTexture;
class WebGLLoseContext;
class WebGLMultiDraw;
class WebGLVideoTexture;
+class WebGLWebCodecsVideoFrame;
class WebGLRenderingContext final : public WebGLRenderingContextBase {
DEFINE_WRAPPERTYPEINFO();
@@ -134,6 +135,7 @@ class WebGLRenderingContext final : public WebGLRenderingContextBase {
Member<WebGLLoseContext> webgl_lose_context_;
Member<WebGLMultiDraw> webgl_multi_draw_;
Member<WebGLVideoTexture> webgl_video_texture_;
+ Member<WebGLWebCodecsVideoFrame> webgl_webcodecs_video_frame_;
};
} // namespace blink
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 03d950b017d..9dd34d18b00 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
@@ -36,6 +36,8 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/config/gpu_feature_info.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/paint_canvas_video_renderer.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_settings.h"
@@ -47,6 +49,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/dactyloscoper.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -66,6 +69,7 @@
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
#include "third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h"
#include "third_party/blink/renderer/modules/webgl/ext_blend_min_max.h"
#include "third_party/blink/renderer/modules/webgl/ext_frag_depth.h"
@@ -114,6 +118,8 @@
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#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/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
@@ -153,7 +159,7 @@ WebGLRenderingContextBaseSet& ActiveContexts() {
if (!active_contexts_persistent) {
active_contexts_persistent =
MakeGarbageCollected<WebGLRenderingContextBaseSet>();
- active_contexts_persistent.RegisterAsStaticReference();
+ LEAK_SANITIZER_IGNORE_OBJECT(&active_contexts_persistent);
}
return *active_contexts_persistent;
}
@@ -169,7 +175,7 @@ WebGLRenderingContextBaseMap& ForciblyEvictedContexts() {
if (!forcibly_evicted_contexts_persistent) {
forcibly_evicted_contexts_persistent =
MakeGarbageCollected<WebGLRenderingContextBaseMap>();
- forcibly_evicted_contexts_persistent.RegisterAsStaticReference();
+ LEAK_SANITIZER_IGNORE_OBJECT(&forcibly_evicted_contexts_persistent);
}
return *forcibly_evicted_contexts_persistent;
}
@@ -338,174 +344,48 @@ GLint Clamp(GLint value, GLint min, GLint max) {
return value;
}
-// Strips comments from shader text. This allows non-ASCII characters
-// to be used in comments without potentially breaking OpenGL
-// implementations not expecting characters outside the GLSL ES set.
-class StripComments {
+// Replaces non-ASCII characters with a placeholder. Given
+// shaderSource's new rules as of
+// https://github.com/KhronosGroup/WebGL/pull/3206 , the browser must
+// not generate INVALID_VALUE for these out-of-range characters.
+// Shader compilation must fail for invalid constructs farther in the
+// pipeline.
+class ReplaceNonASCII {
public:
- StripComments(const String& str)
- : parse_state_(kBeginningOfLine),
- source_string_(str),
- length_(str.length()),
- position_(0) {
- Parse();
- }
+ ReplaceNonASCII(const String& str) { Parse(str); }
String Result() { return builder_.ToString(); }
private:
- bool HasMoreCharacters() const { return (position_ < length_); }
-
- void Parse() {
- while (HasMoreCharacters()) {
- Process(Current());
- // process() might advance the position.
- if (HasMoreCharacters())
- Advance();
+ void Parse(const String& source_string) {
+ unsigned len = source_string.length();
+ for (unsigned i = 0; i < len; ++i) {
+ UChar current = source_string[i];
+ if (WTF::IsASCII(current))
+ builder_.Append(current);
+ else
+ builder_.Append('?');
}
}
- void Process(UChar);
-
- bool Peek(UChar& character) const {
- if (position_ + 1 >= length_)
- return false;
- character = source_string_[position_ + 1];
- return true;
- }
-
- UChar Current() {
- SECURITY_DCHECK(position_ < length_);
- return source_string_[position_];
- }
-
- void Advance() { ++position_; }
-
- static bool IsNewline(UChar character) {
- // Don't attempt to canonicalize newline related characters.
- return (character == '\n' || character == '\r');
- }
-
- void Emit(UChar character) { builder_.Append(character); }
-
- enum ParseState {
- // Have not seen an ASCII non-whitespace character yet on
- // this line. Possible that we might see a preprocessor
- // directive.
- kBeginningOfLine,
-
- // Have seen at least one ASCII non-whitespace character
- // on this line.
- kMiddleOfLine,
-
- // Handling a preprocessor directive. Passes through all
- // characters up to the end of the line. Disables comment
- // processing.
- kInPreprocessorDirective,
-
- // Handling a single-line comment. The comment text is
- // replaced with a single space.
- kInSingleLineComment,
-
- // Handling a multi-line comment. Newlines are passed
- // through to preserve line numbers.
- kInMultiLineComment
- };
-
- ParseState parse_state_;
- String source_string_;
- unsigned length_;
- unsigned position_;
StringBuilder builder_;
};
-void StripComments::Process(UChar c) {
- if (IsNewline(c)) {
- // No matter what state we are in, pass through newlines
- // so we preserve line numbers.
- Emit(c);
-
- if (parse_state_ != kInMultiLineComment)
- parse_state_ = kBeginningOfLine;
-
- return;
- }
-
- UChar temp = 0;
- switch (parse_state_) {
- case kBeginningOfLine:
- if (WTF::IsASCIISpace(c)) {
- Emit(c);
- break;
- }
-
- if (c == '#') {
- parse_state_ = kInPreprocessorDirective;
- Emit(c);
- break;
- }
-
- // Transition to normal state and re-handle character.
- parse_state_ = kMiddleOfLine;
- Process(c);
- break;
-
- case kMiddleOfLine:
- case kInPreprocessorDirective:
- if (c == '/' && Peek(temp)) {
- if (temp == '/') {
- parse_state_ = kInSingleLineComment;
- Emit(' ');
- Advance();
- break;
- }
-
- if (temp == '*') {
- parse_state_ = kInMultiLineComment;
- // Emit the comment start in case the user has
- // an unclosed comment and we want to later
- // signal an error.
- Emit('/');
- Emit('*');
- Advance();
- break;
- }
- }
-
- Emit(c);
- break;
-
- case kInSingleLineComment:
- // Line-continuation characters are processed before comment processing.
- // Advance string if a new line character is immediately behind
- // line-continuation character.
- if (c == '\\') {
- if (Peek(temp) && IsNewline(temp))
- Advance();
- }
-
- // The newline code at the top of this function takes care
- // of resetting our state when we get out of the
- // single-line comment. Swallow all other characters.
- break;
-
- case kInMultiLineComment:
- if (c == '*' && Peek(temp) && temp == '/') {
- Emit('*');
- Emit('/');
- parse_state_ = kMiddleOfLine;
- Advance();
- break;
- }
+static bool g_should_fail_context_creation_for_testing = false;
- // Swallow all other characters. Unclear whether we may
- // want or need to just emit a space per character to try
- // to preserve column numbers for debugging purposes.
- break;
+static CanvasRenderingContext::CanvasRenderingAPI GetCanvasRenderingAPIType(
+ Platform::ContextType context_type) {
+ switch (context_type) {
+ case Platform::kWebGL1ContextType:
+ return CanvasRenderingContext::CanvasRenderingAPI::kWebgl;
+ case Platform::kWebGL2ContextType:
+ return CanvasRenderingContext::CanvasRenderingAPI::kWebgl2;
+ default:
+ NOTREACHED();
+ return CanvasRenderingContext::CanvasRenderingAPI::kWebgl;
}
}
-static bool g_should_fail_context_creation_for_testing = false;
} // namespace
class ScopedTexture2DRestorer {
@@ -556,6 +436,29 @@ class ScopedUnpackParametersResetRestore {
bool enabled_;
};
+class ScopedDisableRasterizerDiscard {
+ STACK_ALLOCATED();
+
+ public:
+ explicit ScopedDisableRasterizerDiscard(WebGLRenderingContextBase* context,
+ bool was_enabled)
+ : context_(context), was_enabled_(was_enabled) {
+ if (was_enabled_) {
+ context_->disable(GL_RASTERIZER_DISCARD);
+ }
+ }
+
+ ~ScopedDisableRasterizerDiscard() {
+ if (was_enabled_) {
+ context_->enable(GL_RASTERIZER_DISCARD);
+ }
+ }
+
+ private:
+ WebGLRenderingContextBase* context_;
+ bool was_enabled_;
+};
+
static void FormatWebGLStatusString(const StringView& gl_info,
const StringView& info_string,
StringBuilder& builder) {
@@ -727,7 +630,7 @@ scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage() {
// Since we are grabbing a snapshot that is not for compositing, we use a
// custom resource provider. This avoids consuming compositing-specific
// resources (e.g. GpuMemoryBuffer)
- auto color_params = ColorParams();
+ auto color_params = CanvasRenderingContextColorParams().GetAsResourceParams();
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
size, GetDrawingBuffer()->FilterQuality(), color_params,
@@ -769,11 +672,6 @@ ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
if (xr_compatible_)
return ScriptPromise::CastUndefined(script_state);
- if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled()) {
- xr_compatible_ = true;
- return ScriptPromise::CastUndefined(script_state);
- }
-
// If there's a request currently in progress, return the same promise.
if (make_xr_compatible_resolver_)
return make_xr_compatible_resolver_->Promise();
@@ -807,41 +705,47 @@ bool WebGLRenderingContextBase::DidGpuRestart(
kNotCompatibleAfterRestart;
}
-bool WebGLRenderingContextBase::MakeXrCompatibleSync(
+XRSystem* WebGLRenderingContextBase::GetXrSystemFromHost(
CanvasRenderingContextHost* host) {
- if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled())
- return true;
+ XRSystem* xr = nullptr;
+
+ if (host->IsOffscreenCanvas()) {
+ OffscreenCanvas* offscreen_canvas = static_cast<OffscreenCanvas*>(host);
+ if (auto* window = DynamicTo<LocalDOMWindow>(
+ offscreen_canvas->GetExecutionContext())) {
+ if (Document* document = window->document()) {
+ xr = XRSystem::From(*document);
+ }
+ }
+ } else {
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(host);
+ xr = XRSystem::From(canvas->GetDocument());
+ }
+
+ return xr;
+}
+bool WebGLRenderingContextBase::MakeXrCompatibleSync(
+ CanvasRenderingContextHost* host) {
device::mojom::blink::XrCompatibleResult xr_compatible_result =
device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable;
- if (!host->IsOffscreenCanvas()) {
- HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(host);
- if (XRSystem* xr = XRSystem::From(canvas->GetDocument()))
- xr->MakeXrCompatibleSync(&xr_compatible_result);
- }
+ if (XRSystem* xr = GetXrSystemFromHost(host))
+ xr->MakeXrCompatibleSync(&xr_compatible_result);
return IsXrCompatibleFromResult(xr_compatible_result);
}
void WebGLRenderingContextBase::MakeXrCompatibleAsync() {
- if (!canvas()) {
+ if (XRSystem* xr = GetXrSystemFromHost(Host())) {
+ // The promise will be completed on the callback.
+ xr->MakeXrCompatibleAsync(
+ WTF::Bind(&WebGLRenderingContextBase::OnMakeXrCompatibleFinished,
+ WrapWeakPersistent(this)));
+ } else {
xr_compatible_ = false;
CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
- return;
}
-
- XRSystem* xr = XRSystem::From(canvas()->GetDocument());
- if (!xr) {
- xr_compatible_ = false;
- CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
- return;
- }
-
- // The promise will be completed on the callback.
- xr->MakeXrCompatibleAsync(
- WTF::Bind(&WebGLRenderingContextBase::OnMakeXrCompatibleFinished,
- WrapWeakPersistent(this)));
}
void WebGLRenderingContextBase::OnMakeXrCompatibleFinished(
@@ -1198,7 +1102,8 @@ scoped_refptr<DrawingBuffer> WebGLRenderingContextBase::CreateDrawingBuffer(
this, ClampedCanvasSize(), premultiplied_alpha, want_alpha_channel,
want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve,
web_gl_version, chromium_image_usage, Host()->FilterQuality(),
- ColorParams(), PowerPreferenceToGpuPreference(attrs.power_preference));
+ CanvasRenderingContextColorParams(),
+ PowerPreferenceToGpuPreference(attrs.power_preference));
}
void WebGLRenderingContextBase::InitializeNewContext() {
@@ -1227,6 +1132,8 @@ void WebGLRenderingContextBase::InitializeNewContext() {
stencil_func_mask_back_ = 0xFFFFFFFF;
num_gl_errors_to_console_allowed_ = kMaxGLErrorsAllowedToConsole;
+ rasterizer_discard_enabled_ = false;
+
clear_color_[0] = clear_color_[1] = clear_color_[2] = clear_color_[3] = 0;
scissor_enabled_ = false;
clear_depth_ = 1;
@@ -1489,11 +1396,47 @@ void WebGLRenderingContextBase::DidDraw() {
}
bool WebGLRenderingContextBase::PushFrame() {
- int submitted_frame = false;
+ TRACE_EVENT0("blink", "WebGLRenderingContextBase::PushFrame");
+ DCHECK(Host());
+ DCHECK(Host()->IsOffscreenCanvas());
+ if (isContextLost() || !GetDrawingBuffer())
+ return false;
+
+ bool must_clear_now = ClearIfComposited(kClearCallerOther) != kSkipped;
+ if (!must_paint_to_canvas_ && !must_clear_now)
+ return false;
+
+ if (!Host()->LowLatencyEnabled() &&
+ GetDrawingBuffer()->IsUsingGpuCompositing()) {
+ // If LowLatency is not enabled, and it's using Gpu Compositing, it will try
+ // to export the mailbox, synctoken and callback mechanism for the
+ // compositor to present the frame in the offscrencanvas.
+ if (PushFrameNoCopy())
+ return true;
+ }
+
+ return PushFrameWithCopy();
+}
+
+bool WebGLRenderingContextBase::PushFrameNoCopy() {
+ auto canvas_resource = GetDrawingBuffer()->ExportCanvasResource();
+ if (!canvas_resource)
+ return false;
+ const int width = GetDrawingBuffer()->Size().Width();
+ const int height = GetDrawingBuffer()->Size().Height();
+ const bool submitted_frame = Host()->PushFrame(
+ std::move(canvas_resource), SkIRect::MakeWH(width, height));
+
+ MarkLayerComposited();
+ return submitted_frame;
+}
+
+bool WebGLRenderingContextBase::PushFrameWithCopy() {
+ bool submitted_frame = false;
if (PaintRenderingResultsToCanvas(kBackBuffer)) {
if (Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU)) {
- int width = GetDrawingBuffer()->Size().Width();
- int height = GetDrawingBuffer()->Size().Height();
+ const int width = GetDrawingBuffer()->Size().Width();
+ const int height = GetDrawingBuffer()->Size().Height();
submitted_frame =
Host()->PushFrame(Host()->ResourceProvider()->ProduceCanvasResource(),
SkIRect::MakeWH(width, height));
@@ -1520,14 +1463,17 @@ void WebGLRenderingContextBase::OnErrorMessage(const char* message,
}
WebGLRenderingContextBase::HowToClear
-WebGLRenderingContextBase::ClearIfComposited(GLbitfield mask) {
+WebGLRenderingContextBase::ClearIfComposited(
+ WebGLRenderingContextBase::ClearCaller caller,
+ GLbitfield mask) {
if (isContextLost())
return kSkipped;
GLbitfield buffers_needing_clearing =
GetDrawingBuffer()->GetBuffersToAutoClear();
- if (buffers_needing_clearing == 0 || (mask && framebuffer_binding_))
+ if (buffers_needing_clearing == 0 || (mask && framebuffer_binding_) ||
+ (rasterizer_discard_enabled_ && caller == kClearCallerDrawOrClear))
return kSkipped;
if (isContextLost()) {
@@ -1576,10 +1522,15 @@ WebGLRenderingContextBase::ClearIfComposited(GLbitfield mask) {
ContextGL()->ColorMask(
true, true, true,
!GetDrawingBuffer()->DefaultBufferRequiresAlphaChannelToBePreserved());
- // If the WebGL 2.0 clearBuffer APIs already have been used to
- // selectively clear some of the buffers, don't destroy those
- // results.
- GetDrawingBuffer()->ClearFramebuffers(clear_mask & buffers_needing_clearing);
+ {
+ ScopedDisableRasterizerDiscard scoped_disable(this,
+ rasterizer_discard_enabled_);
+ // If the WebGL 2.0 clearBuffer APIs already have been used to
+ // selectively clear some of the buffers, don't destroy those
+ // results.
+ GetDrawingBuffer()->ClearFramebuffers(clear_mask &
+ buffers_needing_clearing);
+ }
// Call the DrawingBufferClient method to restore scissor test, mask, and
// clear values, because we dirtied them above.
@@ -1654,20 +1605,26 @@ void WebGLRenderingContextBase::SetIsInHiddenPage(bool hidden) {
bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
SourceDrawingBuffer source_buffer) {
+ TRACE_EVENT0("blink",
+ "WebGLRenderingContextBase::PaintRenderingResultsToCanvas");
if (isContextLost() || !GetDrawingBuffer())
return false;
- bool must_clear_now = ClearIfComposited() != kSkipped;
- if (!must_paint_to_canvas_ && !must_clear_now)
- return false;
-
- must_paint_to_canvas_ = false;
+ bool must_clear_now = ClearIfComposited(kClearCallerOther) != kSkipped;
if (Host()->ResourceProvider() &&
Host()->ResourceProvider()->Size() != GetDrawingBuffer()->Size()) {
Host()->DiscardResourceProvider();
}
+ // The host's ResourceProvider is purged to save memory when the tab
+ // is backgrounded.
+
+ if (!must_paint_to_canvas_ && !must_clear_now && Host()->ResourceProvider())
+ return false;
+
+ must_paint_to_canvas_ = false;
+
CanvasResourceProvider* resource_provider =
Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU);
if (!resource_provider)
@@ -1682,8 +1639,9 @@ bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
// Single buffered passthrough resource provider doesn't have backing
// texture. We need to export the backbuffer mailbox directly without
// copying.
- if (!resource_provider->ImportResource(GetDrawingBuffer()->AsCanvasResource(
- resource_provider->CreateWeakPtr()))) {
+ if (!resource_provider->ImportResource(
+ GetDrawingBuffer()->ExportLowLatencyCanvasResource(
+ resource_provider->CreateWeakPtr()))) {
// This isn't expected to fail for single buffered resource provider.
NOTREACHED();
return false;
@@ -1746,7 +1704,7 @@ bool WebGLRenderingContextBase::CopyRenderingResultsFromDrawingBuffer(
cc::PaintFlags paint_flags;
paint_flags.setBlendMode(SkBlendMode::kSrc);
resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0,
- 0, &paint_flags);
+ 0, SkSamplingOptions(), &paint_flags);
return true;
}
@@ -1760,7 +1718,7 @@ sk_sp<SkData> WebGLRenderingContextBase::PaintRenderingResultsToDataArray(
SourceDrawingBuffer source_buffer) {
if (isContextLost())
return nullptr;
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
ScopedFramebufferRestorer restorer(this);
return GetDrawingBuffer()->PaintRenderingResultsToDataArray(source_buffer);
@@ -1956,6 +1914,24 @@ void WebGLRenderingContextBase::bindTexture(GLenum target,
return;
}
texture_units_[active_texture_unit_].texture_video_image_binding_ = texture;
+ } else if (target == GL_TEXTURE_EXTERNAL_OES) {
+ if (!ExtensionEnabled(kWebGLWebCodecsVideoFrameName)) {
+ SynthesizeGLError(
+ GL_INVALID_ENUM, "bindTexture",
+ "unhandled type, WEBGL_webcodecs_video_frame extension not enabled");
+ return;
+ }
+ texture_units_[active_texture_unit_].texture_external_oes_binding_ =
+ texture;
+ } else if (target == GL_TEXTURE_RECTANGLE_ARB) {
+ if (!ExtensionEnabled(kWebGLWebCodecsVideoFrameName)) {
+ SynthesizeGLError(
+ GL_INVALID_ENUM, "bindTexture",
+ "unhandled type, WEBGL_webcodecs_video_frame extension not enabled");
+ return;
+ }
+ texture_units_[active_texture_unit_].texture_rectangle_arb_binding_ =
+ texture;
} else {
SynthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target");
return;
@@ -2093,8 +2069,8 @@ void WebGLRenderingContextBase::bufferData(GLenum target,
if (isContextLost())
return;
DCHECK(data);
- BufferDataImpl(target, data.View()->byteLength(),
- data.View()->BaseAddressMaybeShared(), usage);
+ BufferDataImpl(target, data->byteLength(), data->BaseAddressMaybeShared(),
+ usage);
}
void WebGLRenderingContextBase::BufferSubDataImpl(GLenum target,
@@ -2200,7 +2176,7 @@ void WebGLRenderingContextBase::clear(GLbitfield mask) {
ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
drawing_buffer_.get());
- if (ClearIfComposited(mask) != kCombinedClear) {
+ if (ClearIfComposited(kClearCallerDrawOrClear, mask) != kCombinedClear) {
// If clearing the default back buffer's depth buffer, also clear the
// stencil buffer, if one was allocated implicitly. This avoids performance
// problems on some GPUs.
@@ -2289,7 +2265,7 @@ void WebGLRenderingContextBase::compressedTexImage2D(
return;
ContextGL()->CompressedTexImage2D(target, level, internalformat, width,
height, border, data_length,
- data.View()->BaseAddressMaybeShared());
+ data->BaseAddressMaybeShared());
}
void WebGLRenderingContextBase::compressedTexSubImage2D(
@@ -2312,7 +2288,7 @@ void WebGLRenderingContextBase::compressedTexSubImage2D(
return;
ContextGL()->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
height, format, data_length,
- data.View()->BaseAddressMaybeShared());
+ data->BaseAddressMaybeShared());
}
bool WebGLRenderingContextBase::ValidateSettableTexFormat(
@@ -2378,7 +2354,7 @@ void WebGLRenderingContextBase::copyTexImage2D(GLenum target,
WebGLFramebuffer* read_framebuffer_binding = nullptr;
if (!ValidateReadBufferAndGetInfo("copyTexImage2D", read_framebuffer_binding))
return;
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
read_framebuffer_binding);
ContextGL()->CopyTexImage2D(target, level, internalformat, x, y, width,
@@ -2401,7 +2377,7 @@ void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target,
if (!ValidateReadBufferAndGetInfo("copyTexSubImage2D",
read_framebuffer_binding))
return;
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
read_framebuffer_binding);
ContextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width,
@@ -2620,6 +2596,8 @@ void WebGLRenderingContextBase::disable(GLenum cap) {
}
if (cap == GL_SCISSOR_TEST)
scissor_enabled_ = false;
+ if (cap == GL_RASTERIZER_DISCARD)
+ rasterizer_discard_enabled_ = false;
ContextGL()->Disable(cap);
}
@@ -2723,6 +2701,7 @@ void WebGLRenderingContextBase::drawArraysImpl(GLenum mode,
drawing_buffer_.get());
OnBeforeDrawCall();
ContextGL()->DrawArrays(mode, first, count);
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGLRenderingContextBase::drawElementsImpl(GLenum mode,
@@ -2744,6 +2723,7 @@ void WebGLRenderingContextBase::drawElementsImpl(GLenum mode,
ContextGL()->DrawElements(
mode, count, type,
reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGLRenderingContextBase::DrawArraysInstancedANGLE(GLenum mode,
@@ -2763,6 +2743,7 @@ void WebGLRenderingContextBase::DrawArraysInstancedANGLE(GLenum mode,
drawing_buffer_.get());
OnBeforeDrawCall();
ContextGL()->DrawArraysInstancedANGLE(mode, first, count, primcount);
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGLRenderingContextBase::DrawElementsInstancedANGLE(GLenum mode,
@@ -2785,6 +2766,7 @@ void WebGLRenderingContextBase::DrawElementsInstancedANGLE(GLenum mode,
ContextGL()->DrawElementsInstancedANGLE(
mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)),
primcount);
+ RecordUKMCanvasDrawnToAtFirstDrawCall();
}
void WebGLRenderingContextBase::enable(GLenum cap) {
@@ -2797,6 +2779,8 @@ void WebGLRenderingContextBase::enable(GLenum cap) {
}
if (cap == GL_SCISSOR_TEST)
scissor_enabled_ = true;
+ if (cap == GL_RASTERIZER_DISCARD)
+ rasterizer_discard_enabled_ = true;
ContextGL()->Enable(cap);
}
@@ -3326,6 +3310,14 @@ void WebGLRenderingContextBase::RecordShaderPrecisionFormatForStudy(
.Record(ukm_params.ukm_recorder);
}
+void WebGLRenderingContextBase::RecordUKMCanvasDrawnToAtFirstDrawCall() {
+ if (!has_been_drawn_to_) {
+ has_been_drawn_to_ = true;
+ RecordUKMCanvasDrawnToRenderingAPI(
+ GetCanvasRenderingAPIType(context_type_));
+ }
+}
+
ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
GLenum pname) {
if (isContextLost())
@@ -3656,6 +3648,10 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter(
ScriptState* script_state,
WebGLProgram* program,
GLenum pname) {
+ // Completion status queries always return true on a lost context. This is
+ // intended to prevent applications from entering an infinite polling loop.
+ if (isContextLost() && pname == GL_COMPLETION_STATUS_KHR)
+ return WebGLAny(script_state, true);
if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) {
return ScriptValue::CreateNull(script_state->GetIsolate());
}
@@ -3768,6 +3764,10 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter(
ScriptState* script_state,
WebGLShader* shader,
GLenum pname) {
+ // Completion status queries always return true on a lost context. This is
+ // intended to prevent applications from entering an infinite polling loop.
+ if (isContextLost() && pname == GL_COMPLETION_STATUS_KHR)
+ return WebGLAny(script_state, true);
if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) {
return ScriptValue::CreateNull(script_state->GetIsolate());
}
@@ -4598,17 +4598,7 @@ void WebGLRenderingContextBase::readPixels(
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels) {
- 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);
+ ReadPixelsHelper(x, y, width, height, format, type, pixels.Get(), 0);
}
void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,
@@ -4658,7 +4648,7 @@ void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,
buffer_size.ValueOrDie())) {
return;
}
- ClearIfComposited();
+ ClearIfComposited(kClearCallerOther);
uint8_t* data = static_cast<uint8_t*>(pixels->BaseAddressMaybeShared()) +
offset_in_bytes.ValueOrDie();
@@ -4772,18 +4762,12 @@ void WebGLRenderingContextBase::shaderSource(WebGLShader* shader,
const String& string) {
if (!ValidateWebGLProgramOrShader("shaderSource", shader))
return;
- String string_without_comments = StripComments(string).Result();
+ String ascii_string = ReplaceNonASCII(string).Result();
shader->SetSource(string);
- if (!string_without_comments.Is8Bit() ||
- !string_without_comments.ContainsOnlyASCIIOrEmpty()) {
- SynthesizeGLError(
- GL_INVALID_VALUE, "shaderSource",
- "Non ASCII character detected after comments are stripped.");
- return;
- }
+ DCHECK(ascii_string.Is8Bit() && ascii_string.ContainsOnlyASCIIOrEmpty());
const GLchar* shader_data =
- reinterpret_cast<const GLchar*>(string_without_comments.Characters8());
- const GLint shader_length = string_without_comments.length();
+ reinterpret_cast<const GLchar*>(ascii_string.Characters8());
+ const GLint shader_length = ascii_string.length();
ContextGL()->ShaderSource(ObjectOrZero(shader), 1, &shader_data,
&shader_length);
}
@@ -5105,8 +5089,9 @@ scoped_refptr<Image> WebGLRenderingContextBase::DrawImageIntoBuffer(
// TODO(ccameron): WebGL should produce sRGB images.
// https://crbug.com/672299
image->Draw(resource_provider->Canvas(), flags, FloatRect(dest_rect),
- FloatRect(src_rect), kRespectImageOrientation,
- Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
+ FloatRect(src_rect), SkSamplingOptions(),
+ kRespectImageOrientation, Image::kDoNotClampImageToSourceRect,
+ Image::kSyncDecode);
return resource_provider->Snapshot();
}
@@ -5259,7 +5244,7 @@ void WebGLRenderingContextBase::texImage2D(
MaybeShared<DOMArrayBufferView> pixels) {
TexImageHelperDOMArrayBufferView(kTexImage2D, target, level, internalformat,
width, height, 1, border, format, type, 0, 0,
- 0, pixels.View(), kNullAllowed, 0);
+ 0, pixels.Get(), kNullAllowed, 0);
}
void WebGLRenderingContextBase::TexImageHelperImageData(
@@ -5282,7 +5267,7 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
return;
DCHECK(pixels);
DCHECK(!pixels->data().IsNull());
- if (pixels->BufferBase()->IsDetached()) {
+ if (pixels->IsBufferBaseDetached()) {
SynthesizeGLError(GL_INVALID_VALUE, func_name,
"The source data has been detached.");
return;
@@ -5313,15 +5298,34 @@ 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.
+
+ GLenum image_type;
+ WebGLImageConversion::DataFormat data_format;
+ switch (pixels->GetImageDataStorageFormat()) {
+ case kUint8ClampedArrayStorageFormat:
+ image_type = GL_UNSIGNED_BYTE;
+ data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA8;
+ break;
+ case kUint16ArrayStorageFormat:
+ image_type = GL_UNSIGNED_SHORT;
+ data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA16;
+ break;
+ case kFloat32ArrayStorageFormat:
+ image_type = GL_FLOAT;
+ data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA32F;
+ break;
+ default:
+ NOTREACHED();
+ }
+
// No conversion is needed if destination format is RGBA and type is
- // UNSIGNED_BYTE and no Flip or Premultiply operation is required.
+ // same as the source image type and no Flip or Premultiply operation is
+ // required.
if (!unpack_flip_y_ && !unpack_premultiply_alpha_ && format == GL_RGBA &&
- type == GL_UNSIGNED_BYTE && !selecting_sub_rectangle && depth == 1) {
+ type == image_type && !selecting_sub_rectangle && depth == 1 &&
+ data_format == format) {
need_conversion = false;
} else {
if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
@@ -5329,8 +5333,7 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
type = GL_FLOAT;
}
if (!WebGLImageConversion::ExtractImageData(
- pixels->data().GetAsUint8ClampedArray()->Data(),
- WebGLImageConversion::DataFormat::kDataFormatRGBA8, pixels->Size(),
+ pixels->GetSkPixmap().writable_addr(), data_format, pixels->Size(),
adjusted_source_image_rect, depth, unpack_image_height, format,
type, unpack_flip_y_, unpack_premultiply_alpha_, data)) {
SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data");
@@ -5338,9 +5341,8 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
}
}
ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
- const uint8_t* bytes = need_conversion
- ? data.data()
- : pixels->data().GetAsUint8ClampedArray()->Data();
+ const void* bytes =
+ need_conversion ? data.data() : pixels->GetSkPixmap().writable_addr();
if (function_id == kTexImage2D) {
DCHECK_EQ(unpack_image_height, 0);
TexImage2DBase(
@@ -5730,28 +5732,6 @@ void WebGLRenderingContextBase::texImage2D(
GetTextureSourceSize(context_host), 1, 0, exception_state);
}
-scoped_refptr<Image> WebGLRenderingContextBase::VideoFrameToImage(
- HTMLVideoElement* video,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
- const IntSize& visible_size = video->videoVisibleSize();
- if (visible_size.IsEmpty()) {
- SynthesizeGLError(GL_INVALID_VALUE, "tex(Sub)Image2D",
- "video visible size is empty");
- return nullptr;
- }
- CanvasResourceProvider* resource_provider =
- generated_image_cache_.GetCanvasResourceProvider(visible_size);
- if (!resource_provider) {
- SynthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
- return nullptr;
- }
- IntRect dest_rect(0, 0, visible_size.Width(), visible_size.Height());
- video->PaintCurrentFrame(resource_provider->Canvas(), dest_rect, nullptr,
- already_uploaded_id, out_metadata);
- return resource_provider->Snapshot();
-}
-
void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
const SecurityOrigin* security_origin,
TexImageFunctionID function_id,
@@ -5773,12 +5753,15 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
return;
if (!ValidateHTMLVideoElement(security_origin, func_name, video,
- exception_state))
+ exception_state)) {
return;
+ }
+
WebGLTexture* texture =
ValidateTexImageBinding(func_name, function_id, target);
if (!texture)
return;
+
TexImageFunctionType function_type;
if (function_id == kTexImage2D || function_id == kTexImage3D)
function_type = kTexImage;
@@ -5787,19 +5770,69 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
if (!ValidateTexFunc(func_name, function_type, kSourceHTMLVideoElement,
target, level, internalformat, video->videoWidth(),
video->videoHeight(), 1, 0, format, type, xoffset,
- yoffset, zoffset))
+ yoffset, zoffset)) {
return;
+ }
- GLint adjusted_internalformat =
- ConvertTexInternalFormat(internalformat, type);
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+ scoped_refptr<media::VideoFrame> media_video_frame;
+ if (auto* wmp = video->GetWebMediaPlayer()) {
+ media_video_frame = wmp->GetCurrentFrame();
+ video_renderer = wmp->GetPaintCanvasVideoRenderer();
+ }
+
+ if (!media_video_frame || !video_renderer)
+ return;
+
+ // This is enforced by ValidateHTMLVideoElement(), but DCHECK to be sure.
+ DCHECK(!WouldTaintOrigin(video));
+ TexImageHelperMediaVideoFrame(
+ function_id, target, level, internalformat, format, type, xoffset,
+ yoffset, zoffset, source_image_rect, depth, unpack_image_height, texture,
+ std::move(media_video_frame), video_renderer);
+}
+
+void WebGLRenderingContextBase::TexImageHelperVideoFrame(
+ const SecurityOrigin* security_origin,
+ TexImageFunctionID function_id,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ VideoFrame* frame,
+ const IntRect& source_image_rect,
+ GLsizei depth,
+ GLint unpack_image_height,
+ ExceptionState& exception_state) {
+ const char* func_name = GetTexImageFunctionName(function_id);
+ if (isContextLost())
+ return;
- // For WebGL last-uploaded-frame-metadata API. https://crbug.com/639174
- WebMediaPlayer::VideoFrameUploadMetadata frame_metadata = {};
- int already_uploaded_id = -1;
- WebMediaPlayer::VideoFrameUploadMetadata* frame_metadata_ptr = nullptr;
- if (RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled()) {
- already_uploaded_id = texture->GetLastUploadedVideoFrameId();
- frame_metadata_ptr = &frame_metadata;
+ WebGLTexture* texture =
+ ValidateTexImageBinding(func_name, function_id, target);
+ if (!texture)
+ return;
+
+ TexImageFunctionType function_type;
+ if (function_id == kTexImage2D || function_id == kTexImage3D)
+ function_type = kTexImage;
+ else
+ function_type = kTexSubImage;
+
+ auto local_handle = frame->handle()->CloneForInternalUse();
+ if (!local_handle)
+ return;
+
+ const auto natural_size = local_handle->frame()->natural_size();
+ if (!ValidateTexFunc(func_name, function_type, kSourceVideoFrame, target,
+ level, internalformat, natural_size.width(),
+ natural_size.height(), 1, 0, format, type, xoffset,
+ yoffset, zoffset)) {
+ return;
}
if (!source_image_rect.IsValid()) {
@@ -5808,83 +5841,256 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
"parameters is invalid");
return;
}
- bool source_image_rect_is_default =
- source_image_rect == SentinelEmptyRect() ||
- source_image_rect ==
- IntRect(0, 0, video->videoWidth(), video->videoHeight());
+ // Some blink::VideoFrame objects reference a SkImage which can be used
+ // directly instead of making a copy through the VideoFrame.
+ if (auto sk_img = local_handle->sk_image()) {
+ DCHECK(!sk_img->isTextureBacked());
+ const GLint adjusted_internalformat =
+ ConvertTexInternalFormat(internalformat, type);
+
+ // For WebGL last-uploaded-frame-metadata API. https://crbug.com/639174
+ auto metadata = WebGLVideoTexture::CreateVideoFrameUploadMetadata(
+ local_handle->frame().get(), texture->GetLastUploadedVideoFrameId());
+ if (metadata.skipped) {
+ texture->UpdateLastUploadedFrame(metadata);
+ return;
+ }
+ auto image = UnacceleratedStaticBitmapImage::Create(std::move(sk_img));
+ TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset,
+ yoffset, zoffset, format, type, image.get(),
+ // Note: kHtmlDomVideo means alpha won't be unmultiplied.
+ WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_,
+ unpack_premultiply_alpha_, source_image_rect, depth,
+ unpack_image_height);
+ texture->UpdateLastUploadedFrame(metadata);
+ return;
+ }
+
+ TexImageHelperMediaVideoFrame(function_id, target, level, internalformat,
+ format, type, xoffset, yoffset, zoffset,
+ source_image_rect, depth, unpack_image_height,
+ texture, local_handle->frame(), nullptr);
+}
+
+void WebGLRenderingContextBase::TexImageHelperMediaVideoFrame(
+ TexImageFunctionID function_id,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ const IntRect& source_image_rect,
+ GLsizei depth,
+ GLint unpack_image_height,
+ WebGLTexture* texture,
+ scoped_refptr<media::VideoFrame> media_video_frame,
+ media::PaintCanvasVideoRenderer* video_renderer) {
+ DCHECK(!isContextLost());
+ DCHECK(texture);
+ DCHECK(media_video_frame);
+ DCHECK(source_image_rect.IsValid());
+
+ auto metadata = WebGLVideoTexture::CreateVideoFrameUploadMetadata(
+ media_video_frame.get(), texture->GetLastUploadedVideoFrameId());
+ if (metadata.skipped) {
+ texture->UpdateLastUploadedFrame(metadata);
+ return;
+ }
+
+ TexImageFunctionType function_type;
+ if (function_id == kTexImage2D || function_id == kTexImage3D)
+ function_type = kTexImage;
+ else
+ function_type = kTexSubImage;
+
+ // TODO(crbug.com/1175907): Reconcile usage of natural size versus visible
+ // rect. The existing <video> path uses natural size for |source_image_rect|
+ // and visible size centered at zero for actual Paint/Copy operations. So for
+ // now preserve the same behavior for all media::VideoFrame texturing.
+ const GLint adjusted_internalformat =
+ ConvertTexInternalFormat(internalformat, type);
+ const bool source_image_rect_is_default =
+ source_image_rect == SentinelEmptyRect() ||
+ source_image_rect == IntRect(0, 0,
+ media_video_frame->natural_size().width(),
+ media_video_frame->natural_size().height());
const auto& caps = GetDrawingBuffer()->ContextProvider()->GetCapabilities();
const bool may_need_image_external_essl3 =
caps.egl_image_external &&
Extensions3DUtil::CopyTextureCHROMIUMNeedsESSL3(internalformat);
const bool have_image_external_essl3 = caps.egl_image_external_essl3;
- const bool use_copyTextureCHROMIUM =
+ const bool use_copy_texture_chromium =
function_id == kTexImage2D && source_image_rect_is_default &&
depth == 1 && GL_TEXTURE_2D == target &&
(have_image_external_essl3 || !may_need_image_external_essl3) &&
CanUseTexImageViaGPU(format, type);
- // Format of source video may be 16-bit format, e.g. Y16 format.
+ // Callers may chose to provide a renderer which ensures that generated
+ // intermediates will be cached across TexImage calls for the same frame.
+ std::unique_ptr<media::PaintCanvasVideoRenderer> local_video_renderer;
+ if (!video_renderer) {
+ local_video_renderer = std::make_unique<media::PaintCanvasVideoRenderer>();
+ video_renderer = local_video_renderer.get();
+ }
+
+ // Format of source VideoFrame may be 16-bit format, e.g. Y16 format.
// glCopyTextureCHROMIUM requires the source texture to be in 8-bit format.
- // Converting 16-bits formated source texture to 8-bits formated texture will
- // cause precision lost. So, uploading such video texture to half float or
- // float texture can not use GPU-GPU path.
- if (use_copyTextureCHROMIUM) {
+ // Converting 16-bits formatted source texture to 8-bits formatted texture
+ // will cause precision lost. So, uploading such video texture to half float
+ // or float texture can not use GPU-GPU path.
+ if (use_copy_texture_chromium) {
DCHECK(Extensions3DUtil::CanUseCopyTextureCHROMIUM(target));
DCHECK_EQ(xoffset, 0);
DCHECK_EQ(yoffset, 0);
DCHECK_EQ(zoffset, 0);
+
+ viz::RasterContextProvider* raster_context_provider = nullptr;
+ if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
+ if (auto* context_provider = wrapper->ContextProvider())
+ raster_context_provider = context_provider->RasterContextProvider();
+ }
+
// Go through the fast path doing a GPU-GPU textures copy without a readback
// to system memory if possible. Otherwise, it will fall back to the normal
// SW path.
- if (video->CopyVideoTextureToPlatformTexture(
- ContextGL(), target, texture->Object(), adjusted_internalformat,
- format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
- already_uploaded_id, frame_metadata_ptr)) {
- texture->UpdateLastUploadedFrame(frame_metadata);
+ if (media_video_frame->HasTextures() &&
+ video_renderer->CopyVideoFrameTexturesToGLTexture(
+ raster_context_provider, ContextGL(), media_video_frame, target,
+ texture->Object(), adjusted_internalformat, format, type, level,
+ unpack_premultiply_alpha_, unpack_flip_y_)) {
+ texture->UpdateLastUploadedFrame(metadata);
return;
}
// For certain video frame formats (e.g. I420/YUV), if they start on the CPU
// (e.g. video camera frames): upload them to the GPU, do a GPU decode, and
// then copy into the target texture.
- if (video->CopyVideoYUVDataToPlatformTexture(
- ContextGL(), target, texture->Object(), adjusted_internalformat,
- format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
- already_uploaded_id, frame_metadata_ptr)) {
- texture->UpdateLastUploadedFrame(frame_metadata);
+ //
+ // TODO(crbug.com/1180879): I420A should be supported, but currently fails
+ // conformance/textures/misc/texture-video-transparent.html.
+ if (!media_video_frame->HasTextures() &&
+ media::IsOpaque(media_video_frame->format()) &&
+ video_renderer->CopyVideoFrameYUVDataToGLTexture(
+ raster_context_provider, ContextGL(), *media_video_frame, target,
+ texture->Object(), adjusted_internalformat, format, type, level,
+ unpack_premultiply_alpha_, unpack_flip_y_)) {
+ texture->UpdateLastUploadedFrame(metadata);
return;
}
}
- if (source_image_rect_is_default) {
+ if (source_image_rect_is_default && media_video_frame->IsMappable() &&
+ media_video_frame->format() == media::PIXEL_FORMAT_Y16) {
// 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 unpack_params(
this, unpack_flip_y_ || unpack_premultiply_alpha_);
- if (video->TexImageImpl(
- static_cast<WebMediaPlayer::TexImageFunctionID>(function_id),
- target, ContextGL(), texture->Object(), level,
- adjusted_internalformat, format, type, xoffset, yoffset, zoffset,
- unpack_flip_y_,
- unpack_premultiply_alpha_ &&
- unpack_colorspace_conversion_ == GL_NONE)) {
- texture->ClearLastUploadedFrame();
+
+ const bool premultiply_alpha =
+ unpack_premultiply_alpha_ && unpack_colorspace_conversion_ == GL_NONE;
+
+ if (function_id == kTexImage2D &&
+ media::PaintCanvasVideoRenderer::TexImage2D(
+ target, texture->Object(), ContextGL(), caps,
+ media_video_frame.get(), level, adjusted_internalformat, format,
+ type, unpack_flip_y_, premultiply_alpha)) {
+ texture->UpdateLastUploadedFrame(metadata);
+ return;
+ } else if (function_id == kTexSubImage2D &&
+ media::PaintCanvasVideoRenderer::TexSubImage2D(
+ target, ContextGL(), media_video_frame.get(), level, format,
+ type, xoffset, yoffset, unpack_flip_y_, premultiply_alpha)) {
+ texture->UpdateLastUploadedFrame(metadata);
return;
}
}
- scoped_refptr<Image> image =
- VideoFrameToImage(video, already_uploaded_id, frame_metadata_ptr);
+ // TODO(crbug.com/1175907): Double check that the premultiply alpha settings
+ // are all correct below. When we go through the CanvasResourceProvider for
+ // Image creation, CanvasResourceParams { kPremul_SkAlphaType } is used.
+ //
+ // We probably need some stronger checks on the accelerated upload path if
+ // unmultiply has been requested or we need to never premultiply for Image
+ // creation from a VideoFrame.
+
+#if defined(OS_MAC)
+ // TODO(crbug.com/1180726): Sampling from macOS IOSurfaces requires
+ // GL_ARB_texture_rectangle which is not available in the WebGL context.
+ constexpr bool kAllowZeroCopyImages = false;
+#else
+ constexpr bool kAllowZeroCopyImages = true;
+#endif
+
+#if defined(OS_ANDROID)
+ // TODO(crbug.com/1175907): Only TexImage2D seems to work with the GPU path on
+ // Android M -- appears to work fine on R, but to avoid regressions in <video>
+ // limit to TexImage2D only for now. Fails conformance test on Nexus 5X:
+ // conformance/textures/misc/texture-corner-case-videos.html
+ //
+ // TODO(crbug.com/1181993): Even TexImage2D doesn't seem to work reliably with
+ // the GPU path.
+ const bool function_supports_gpu_teximage = false;
+#elif defined(OS_LINUX)
+ // TODO(crbug.com/1181562): TexSubImage2D via the GPU path performs poorly on
+ // Linux when used with ShMem GpuMemoryBuffer backed frames. We don't have a
+ // way to differentiate between true texture backed frames and ShMem GMBs, so
+ // for now limit GPU texturing to TexImage2D.
+ const bool function_supports_gpu_teximage = function_id == kTexImage2D;
+#else
+ const bool function_supports_gpu_teximage =
+ function_id == kTexImage2D || function_id == kTexSubImage2D;
+#endif
+
+ const bool can_upload_via_gpu = function_supports_gpu_teximage &&
+ CanUseTexImageViaGPU(format, type) &&
+ source_image_rect_is_default;
+
+ // If we can upload via GPU, try to to use an accelerated resource provider
+ // configured appropriately for video. Otherwise use the software cache.
+ auto& image_cache =
+ can_upload_via_gpu ? generated_video_cache_ : generated_image_cache_;
+
+ const auto visible_rect = media_video_frame->visible_rect();
+ scoped_refptr<Image> image = CreateImageFromVideoFrame(
+ std::move(media_video_frame), kAllowZeroCopyImages,
+ image_cache.GetCanvasResourceProvider(IntSize(visible_rect.size())),
+ video_renderer);
if (!image)
return;
- TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset,
- yoffset, zoffset, format, type, image.get(),
- WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_,
- unpack_premultiply_alpha_, source_image_rect, depth,
- unpack_image_height);
- texture->UpdateLastUploadedFrame(frame_metadata);
+
+ if (can_upload_via_gpu && image->IsTextureBacked()) {
+ auto adjusted_source_image_rect = source_image_rect;
+ if (adjusted_source_image_rect == SentinelEmptyRect())
+ adjusted_source_image_rect = GetTextureSourceSize(image.get());
+
+ auto* accel_image = static_cast<AcceleratedStaticBitmapImage*>(image.get());
+ if (function_id == kTexImage2D) {
+ TexImage2DBase(
+ target, level, internalformat, adjusted_source_image_rect.Width(),
+ adjusted_source_image_rect.Height(), 0, format, type, nullptr);
+ TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image,
+ nullptr, adjusted_source_image_rect,
+ unpack_premultiply_alpha_, unpack_flip_y_);
+ } else {
+ TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0,
+ accel_image, nullptr, adjusted_source_image_rect,
+ unpack_premultiply_alpha_, unpack_flip_y_);
+ }
+ } else {
+ TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset,
+ yoffset, zoffset, format, type, image.get(),
+ // Note: kHtmlDomVideo means alpha won't be unmultiplied.
+ WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_,
+ unpack_premultiply_alpha_, source_image_rect, depth,
+ unpack_image_height);
+ }
+
+ texture->UpdateLastUploadedFrame(metadata);
}
void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
@@ -5901,6 +6107,19 @@ void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
SentinelEmptyRect(), 1, 0, exception_state);
}
+void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ TexImageHelperVideoFrame(execution_context->GetSecurityOrigin(), kTexImage2D,
+ target, level, internalformat, format, type, 0, 0, 0,
+ frame, SentinelEmptyRect(), 1, 0, exception_state);
+}
+
void WebGLRenderingContextBase::TexImageHelperImageBitmap(
TexImageFunctionID function_id,
GLenum target,
@@ -5998,8 +6217,13 @@ void WebGLRenderingContextBase::TexImageHelperImageBitmap(
if (peek_succeed) {
pixel_data_ptr = static_cast<uint8_t*>(pixmap.writable_addr());
} else {
- pixel_data = bitmap->CopyBitmapData(
- bitmap->IsPremultiplied() ? kPremultiplyAlpha : kUnpremultiplyAlpha);
+ SkImageInfo info = bitmap->GetBitmapSkImageInfo();
+ info =
+ info.makeAlphaType(bitmap->IsPremultiplied() ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType);
+ if (info.colorType() == kN32_SkColorType)
+ info = info.makeColorType(kRGBA_8888_SkColorType);
+ pixel_data = bitmap->CopyBitmapData(info, true);
pixel_data_ptr = pixel_data.data();
}
Vector<uint8_t> data;
@@ -6181,7 +6405,7 @@ void WebGLRenderingContextBase::texSubImage2D(
MaybeShared<DOMArrayBufferView> pixels) {
TexImageHelperDOMArrayBufferView(kTexSubImage2D, target, level, 0, width,
height, 1, 0, format, type, xoffset, yoffset,
- 0, pixels.View(), kNullNotAllowed, 0);
+ 0, pixels.Get(), kNullNotAllowed, 0);
}
void WebGLRenderingContextBase::texSubImage2D(GLenum target,
@@ -6244,6 +6468,22 @@ void WebGLRenderingContextBase::texSubImage2D(
SentinelEmptyRect(), 1, 0, exception_state);
}
+void WebGLRenderingContextBase::texSubImage2D(
+ ExecutionContext* execution_context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLenum format,
+ GLenum type,
+ VideoFrame* frame,
+ ExceptionState& exception_state) {
+ TexImageHelperVideoFrame(execution_context->GetSecurityOrigin(),
+ kTexSubImage2D, target, level, 0, format, type,
+ xoffset, yoffset, 0, frame, SentinelEmptyRect(), 1,
+ 0, exception_state);
+}
+
void WebGLRenderingContextBase::texSubImage2D(GLenum target,
GLint level,
GLint xoffset,
@@ -6555,11 +6795,11 @@ void WebGLRenderingContextBase::uniformMatrix2fv(
MaybeShared<DOMFloat32Array> v) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
- v.View(), 4, 0, v.View()->length()))
+ v.Get(), 4, 0, v->length()))
return;
- ContextGL()->UniformMatrix2fv(
- location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 2,
- transpose, v.View()->DataMaybeShared());
+ ContextGL()->UniformMatrix2fv(location->Location(),
+ base::checked_cast<GLuint>(v->length()) >> 2,
+ transpose, v->DataMaybeShared());
}
void WebGLRenderingContextBase::uniformMatrix2fv(
@@ -6580,11 +6820,11 @@ void WebGLRenderingContextBase::uniformMatrix3fv(
MaybeShared<DOMFloat32Array> v) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
- v.View(), 9, 0, v.View()->length()))
+ v.Get(), 9, 0, v->length()))
return;
- ContextGL()->UniformMatrix3fv(
- location->Location(), base::checked_cast<GLuint>(v.View()->length()) / 9,
- transpose, v.View()->DataMaybeShared());
+ ContextGL()->UniformMatrix3fv(location->Location(),
+ base::checked_cast<GLuint>(v->length()) / 9,
+ transpose, v->DataMaybeShared());
}
void WebGLRenderingContextBase::uniformMatrix3fv(
@@ -6605,11 +6845,11 @@ void WebGLRenderingContextBase::uniformMatrix4fv(
MaybeShared<DOMFloat32Array> v) {
if (isContextLost() ||
!ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
- v.View(), 16, 0, v.View()->length()))
+ v.Get(), 16, 0, v->length()))
return;
- ContextGL()->UniformMatrix4fv(
- location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 4,
- transpose, v.View()->DataMaybeShared());
+ ContextGL()->UniformMatrix4fv(location->Location(),
+ base::checked_cast<GLuint>(v->length()) >> 4,
+ transpose, v->DataMaybeShared());
}
void WebGLRenderingContextBase::uniformMatrix4fv(
@@ -6667,11 +6907,11 @@ void WebGLRenderingContextBase::vertexAttrib1fv(
MaybeShared<const DOMFloat32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 1) {
+ if (!v.Get() || v->length() < 1) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array");
return;
}
- ContextGL()->VertexAttrib1fv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttrib1fv(index, v->DataMaybeShared());
SetVertexAttribType(index, kFloat32ArrayType);
}
@@ -6701,11 +6941,11 @@ void WebGLRenderingContextBase::vertexAttrib2fv(
MaybeShared<const DOMFloat32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 2) {
+ if (!v.Get() || v->length() < 2) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array");
return;
}
- ContextGL()->VertexAttrib2fv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttrib2fv(index, v->DataMaybeShared());
SetVertexAttribType(index, kFloat32ArrayType);
}
@@ -6736,11 +6976,11 @@ void WebGLRenderingContextBase::vertexAttrib3fv(
MaybeShared<const DOMFloat32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 3) {
+ if (!v.Get() || v->length() < 3) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array");
return;
}
- ContextGL()->VertexAttrib3fv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttrib3fv(index, v->DataMaybeShared());
SetVertexAttribType(index, kFloat32ArrayType);
}
@@ -6772,11 +7012,11 @@ void WebGLRenderingContextBase::vertexAttrib4fv(
MaybeShared<const DOMFloat32Array> v) {
if (isContextLost())
return;
- if (!v.View() || v.View()->length() < 4) {
+ if (!v.Get() || v->length() < 4) {
SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array");
return;
}
- ContextGL()->VertexAttrib4fv(index, v.View()->DataMaybeShared());
+ ContextGL()->VertexAttrib4fv(index, v->DataMaybeShared());
SetVertexAttribType(index, kFloat32ArrayType);
}
@@ -7272,6 +7512,24 @@ WebGLTexture* WebGLRenderingContextBase::ValidateTextureBinding(
tex = texture_units_[active_texture_unit_]
.texture_video_image_binding_.Get();
break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ if (!ExtensionEnabled(kWebGLWebCodecsVideoFrameName)) {
+ SynthesizeGLError(GL_INVALID_ENUM, function_name,
+ "invalid texture target");
+ return nullptr;
+ }
+ tex = texture_units_[active_texture_unit_]
+ .texture_external_oes_binding_.Get();
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ if (!ExtensionEnabled(kWebGLWebCodecsVideoFrameName)) {
+ SynthesizeGLError(GL_INVALID_ENUM, function_name,
+ "invalid texture target");
+ return nullptr;
+ }
+ tex = texture_units_[active_texture_unit_]
+ .texture_rectangle_arb_binding_.Get();
+ break;
default:
SynthesizeGLError(GL_INVALID_ENUM, function_name,
"invalid texture target");
@@ -7643,7 +7901,8 @@ bool WebGLRenderingContextBase::ValidateTexFuncParameters(
if (source_type == kSourceHTMLImageElement ||
source_type == kSourceHTMLCanvasElement ||
source_type == kSourceHTMLVideoElement ||
- source_type == kSourceImageData || source_type == kSourceImageBitmap) {
+ source_type == kSourceImageData || source_type == kSourceImageBitmap ||
+ source_type == kSourceVideoFrame) {
if (!ValidateTexImageSourceFormatAndType(function_name, function_type,
internalformat, format, type)) {
return false;
@@ -8211,7 +8470,7 @@ bool WebGLRenderingContextBase::ValidateDrawElements(const char* function_name,
}
void WebGLRenderingContextBase::OnBeforeDrawCall() {
- ClearIfComposited();
+ ClearIfComposited(kClearCallerDrawOrClear);
MarkContextChanged(kCanvasChanged);
}
@@ -8345,8 +8604,8 @@ String WebGLRenderingContextBase::EnsureNotNull(const String& text) const {
}
WebGLRenderingContextBase::LRUCanvasResourceProviderCache::
- LRUCanvasResourceProviderCache(wtf_size_t capacity)
- : resource_providers_(capacity) {}
+ LRUCanvasResourceProviderCache(wtf_size_t capacity, CacheType type)
+ : type_(type), resource_providers_(capacity) {}
CanvasResourceProvider* WebGLRenderingContextBase::
LRUCanvasResourceProviderCache::GetCanvasResourceProvider(
@@ -8362,12 +8621,21 @@ CanvasResourceProvider* WebGLRenderingContextBase::
return resource_provider;
}
- // TODO(fserb): why is this a BITMAP?
- std::unique_ptr<CanvasResourceProvider> temp(
- CanvasResourceProvider::CreateBitmapProvider(
- size, kLow_SkFilterQuality, CanvasColorParams(),
- CanvasResourceProvider::ShouldInitialize::kNo)); // TODO: should this
- // use the canvas's
+ std::unique_ptr<CanvasResourceProvider> temp;
+ if (type_ == CacheType::kVideo) {
+ viz::RasterContextProvider* raster_context_provider = nullptr;
+ if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
+ if (auto* context_provider = wrapper->ContextProvider())
+ raster_context_provider = context_provider->RasterContextProvider();
+ }
+ temp = CreateResourceProviderForVideoFrame(size, raster_context_provider);
+ } else {
+ // TODO(fserb): why is this a BITMAP?
+ temp = CanvasResourceProvider::CreateBitmapProvider(
+ size, kLow_SkFilterQuality, CanvasResourceParams(),
+ CanvasResourceProvider::ShouldInitialize::kNo); // TODO: should this
+ // use the canvas's
+ }
if (!temp)
return nullptr;
@@ -8548,10 +8816,14 @@ void WebGLRenderingContextBase::TextureUnitState::Trace(
visitor->Trace(texture3d_binding_);
visitor->Trace(texture2d_array_binding_);
visitor->Trace(texture_video_image_binding_);
+ visitor->Trace(texture_external_oes_binding_);
+ visitor->Trace(texture_rectangle_arb_binding_);
}
void WebGLRenderingContextBase::Trace(Visitor* visitor) const {
visitor->Trace(context_group_);
+ visitor->Trace(dispatch_context_lost_event_timer_);
+ visitor->Trace(restore_timer_);
visitor->Trace(bound_array_buffer_);
visitor->Trace(default_vertex_array_object_);
visitor->Trace(bound_vertex_array_object_);
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 5adeea1b604..4971c9ada0c 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
@@ -73,6 +73,10 @@ class GLES2Interface;
}
} // namespace gpu
+namespace media {
+class PaintCanvasVideoRenderer;
+}
+
namespace blink {
class AcceleratedStaticBitmapImage;
@@ -87,6 +91,7 @@ class ImageBitmap;
class ImageData;
class IntSize;
class OESVertexArrayObject;
+class VideoFrame;
class WebGLActiveInfo;
class WebGLBuffer;
class WebGLCompressedTextureASTC;
@@ -108,6 +113,7 @@ class WebGLShader;
class WebGLShaderPrecisionFormat;
class WebGLUniformLocation;
class WebGLVertexArrayObjectBase;
+class XRSystem;
using GLenumHashSet = HashSet<GLenum,
WTF::AlreadyHashed,
@@ -427,6 +433,14 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
GLenum type,
HTMLVideoElement*,
ExceptionState&);
+ void texImage2D(ExecutionContext*,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ VideoFrame*,
+ ExceptionState&);
void texImage2D(GLenum target,
GLint level,
GLint internalformat,
@@ -481,6 +495,15 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
GLenum type,
HTMLVideoElement*,
ExceptionState&);
+ void texSubImage2D(ExecutionContext*,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLenum format,
+ GLenum type,
+ VideoFrame*,
+ ExceptionState&);
void texSubImage2D(GLenum target,
GLint level,
GLint xoffset,
@@ -629,6 +652,8 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
Member<WebGLTexture> texture3d_binding_;
Member<WebGLTexture> texture2d_array_binding_;
Member<WebGLTexture> texture_video_image_binding_;
+ Member<WebGLTexture> texture_external_oes_binding_;
+ Member<WebGLTexture> texture_rectangle_arb_binding_;
void Trace(Visitor*) const;
};
@@ -767,11 +792,6 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
int height,
const char* function_name);
- scoped_refptr<Image> VideoFrameToImage(
- HTMLVideoElement*,
- int already_uploaded_id,
- WebMediaPlayer::VideoFrameUploadMetadata* out_metadata);
-
// Structure for rendering to a DrawingBuffer, instead of directly
// to the back-buffer of m_context.
scoped_refptr<DrawingBuffer> drawing_buffer_;
@@ -788,9 +808,10 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
// real ones, it's likely that there's no JavaScript on the stack, but that
// might be dependent on how exactly the platform discovers that the context
// was lost. For better portability we always defer the dispatch of the event.
- TaskRunnerTimer<WebGLRenderingContextBase> dispatch_context_lost_event_timer_;
+ HeapTaskRunnerTimer<WebGLRenderingContextBase>
+ dispatch_context_lost_event_timer_;
bool restore_allowed_ = false;
- TaskRunnerTimer<WebGLRenderingContextBase> restore_timer_;
+ HeapTaskRunnerTimer<WebGLRenderingContextBase> restore_timer_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
bool destruction_in_progress_ = false;
@@ -826,6 +847,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
static bool IsXrCompatibleFromResult(
device::mojom::blink::XrCompatibleResult result);
static bool DidGpuRestart(device::mojom::blink::XrCompatibleResult result);
+ static XRSystem* GetXrSystemFromHost(CanvasRenderingContextHost* host);
void MakeXrCompatibleAsync();
void OnMakeXrCompatibleFinished(
device::mojom::blink::XrCompatibleResult xr_compatible_result);
@@ -838,19 +860,24 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
Vector<GLenum> compressed_texture_formats_;
- // Fixed-size cache of reusable resource providers for video texImage2D calls.
+ // Fixed-size cache of reusable resource providers for image and video
+ // texImage2D calls.
class LRUCanvasResourceProviderCache {
public:
- explicit LRUCanvasResourceProviderCache(wtf_size_t capacity);
+ enum class CacheType { kImage, kVideo };
+ LRUCanvasResourceProviderCache(wtf_size_t capacity, CacheType type);
// The pointer returned is owned by the image buffer map.
CanvasResourceProvider* GetCanvasResourceProvider(const IntSize&);
private:
void BubbleToFront(wtf_size_t idx);
+ const CacheType type_;
Vector<std::unique_ptr<CanvasResourceProvider>> resource_providers_;
};
- LRUCanvasResourceProviderCache generated_image_cache_ =
- LRUCanvasResourceProviderCache(4);
+ LRUCanvasResourceProviderCache generated_image_cache_{
+ 4, LRUCanvasResourceProviderCache::CacheType::kImage};
+ LRUCanvasResourceProviderCache generated_video_cache_{
+ 4, LRUCanvasResourceProviderCache::CacheType::kVideo};
GLint max_texture_size_;
GLint max_cube_map_texture_size_;
@@ -895,6 +922,9 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
// not the internal clamped value.
GLuint stencil_func_mask_, stencil_func_mask_back_;
+ // WebGL 2.0 only, but putting it here saves multiple virtual functions.
+ bool rasterizer_discard_enabled_;
+
bool is_depth_stencil_supported_;
bool synthesized_errors_to_console_ = true;
@@ -1082,7 +1112,15 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
// doesn't have to call glClear() again.
kCombinedClear
};
- HowToClear ClearIfComposited(GLbitfield clear_mask = 0);
+ enum ClearCaller {
+ // Caller of ClearIfComposited is a user-level draw or clear call.
+ kClearCallerDrawOrClear,
+ // Caller of ClearIfComposited is anything else, including
+ // readbacks or copies.
+ kClearCallerOther,
+ };
+
+ HowToClear ClearIfComposited(ClearCaller caller, GLbitfield clear_mask = 0);
// Convert texture internal format.
GLenum ConvertTexInternalFormat(GLenum internalformat, GLenum type);
@@ -1337,6 +1375,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
kSourceHTMLVideoElement,
kSourceImageBitmap,
kSourceUnpackBuffer,
+ kSourceVideoFrame,
};
// Helper function for tex{Sub}Image{2|3}D to check if the input
@@ -1575,7 +1614,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
bool ExtractDataLengthIfValid(const char* function_name,
MaybeShared<DOMArrayBufferView> data,
T* data_length) {
- if (base::CheckedNumeric<T>(data.View()->byteLength())
+ if (base::CheckedNumeric<T>(data->byteLength())
.AssignIfValid(data_length)) {
return true;
}
@@ -1747,6 +1786,23 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
GLsizei,
GLint,
ExceptionState&);
+
+ void TexImageHelperVideoFrame(const SecurityOrigin*,
+ TexImageFunctionID,
+ GLenum,
+ GLint,
+ GLint,
+ GLenum,
+ GLenum,
+ GLint,
+ GLint,
+ GLint,
+ VideoFrame*,
+ const IntRect&,
+ GLsizei,
+ GLint,
+ ExceptionState&);
+
void TexImageHelperImageBitmap(TexImageFunctionID,
GLenum,
GLint,
@@ -1776,6 +1832,10 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
DOMArrayBufferView* pixels,
int64_t offset);
+ // Record Canvas/OffscreenCanvas.RenderingContextDrawnTo at the first draw
+ // call.
+ void RecordUKMCanvasDrawnToAtFirstDrawCall();
+
private:
WebGLRenderingContextBase(CanvasRenderingContextHost*,
scoped_refptr<base::SingleThreadTaskRunner>,
@@ -1789,6 +1849,24 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
const CanvasContextCreationAttributesCore&,
Platform::ContextType context_type,
bool* using_gpu_compositing);
+
+ void TexImageHelperMediaVideoFrame(
+ TexImageFunctionID function_id,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLenum format,
+ GLenum type,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ const IntRect& source_image_rect,
+ GLsizei depth,
+ GLint unpack_image_height,
+ WebGLTexture* texture,
+ scoped_refptr<media::VideoFrame> media_video_frame,
+ media::PaintCanvasVideoRenderer* video_renderer);
+
// Copy from the source directly to the texture via the gpu, without
// a read-back to system memory. Source can be a texture-backed
// Image, or another canvas's WebGLRenderingContext.
@@ -1825,6 +1903,13 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
GLenum precision_type,
WebGLShaderPrecisionFormat* format);
+ // PushFrameWithCopy will make a potential copy if the resource is accelerated
+ // or a drawImage if the resource is non accelerated.
+ bool PushFrameWithCopy();
+ // PushFrameNoCopy will try and export the content of the DrawingBuffer as a
+ // ExtenralCanvasResource.
+ bool PushFrameNoCopy();
+
static bool webgl_context_limits_initialized_;
static unsigned max_active_webgl_contexts_;
static unsigned max_active_webgl_contexts_on_worker_;
@@ -1840,6 +1925,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
friend class WebGLFastCallHelper;
WebGLFastCallHelper fast_call_;
+ bool has_been_drawn_to_ = false;
DISALLOW_COPY_AND_ASSIGN(WebGLRenderingContextBase);
};
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 48867512b27..d14cc765b88 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
@@ -630,6 +630,9 @@ interface mixin WebGLRenderingContextBase {
[RaisesException] void texImage2D(
GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, ImageBitmap bitmap);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texImage2D(
+ GLenum target, GLint level, GLint internalformat,
+ GLenum format, GLenum type, VideoFrame frame);
void texSubImage2D(
GLenum target, GLint level, GLint xoffset, GLint yoffset,
@@ -653,6 +656,9 @@ interface mixin WebGLRenderingContextBase {
[RaisesException] void texSubImage2D(
GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, ImageBitmap bitmap);
+ [CallWith=ExecutionContext, RaisesException, RuntimeEnabled=WebCodecs] void texSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLenum format, GLenum type, VideoFrame frame);
void uniform1f(WebGLUniformLocation? location, GLfloat x);
void uniform1fv(WebGLUniformLocation? location, [AllowShared, FlexibleArrayBufferView] Float32Array v);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_texture.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_texture.h
index 0883232c587..1bb9404ca1f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_texture.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_texture.h
@@ -26,8 +26,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_TEXTURE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_TEXTURE_H_
+#include "base/time/time.h"
#include "third_party/blink/public/platform/web_media_player.h"
#include "third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.h"
+#include "third_party/blink/renderer/platform/geometry/int_rect.h"
namespace blink {
@@ -47,22 +49,30 @@ class WebGLTexture : public WebGLSharedPlatform3DObject {
static GLint ComputeLevelCount(GLsizei width, GLsizei height, GLsizei depth);
+ // For last-uploaded-frame-metadata API. https://crbug.com/639174
+ struct VideoFrameUploadMetadata {
+ int frame_id = -1;
+ IntRect visible_rect = {};
+ base::TimeDelta timestamp = {};
+ base::TimeDelta expected_timestamp = {};
+ bool skipped = false;
+ };
+
int GetLastUploadedVideoFrameId() const {
return last_uploaded_video_frame_metadata_.frame_id;
}
- void UpdateLastUploadedFrame(
- blink::WebMediaPlayer::VideoFrameUploadMetadata frame_metadata) {
+ void UpdateLastUploadedFrame(VideoFrameUploadMetadata frame_metadata) {
last_uploaded_video_frame_metadata_ = frame_metadata;
}
void ClearLastUploadedFrame() { last_uploaded_video_frame_metadata_ = {}; }
unsigned lastUploadedVideoWidth() const {
- return last_uploaded_video_frame_metadata_.visible_rect.width();
+ return last_uploaded_video_frame_metadata_.visible_rect.Width();
}
unsigned lastUploadedVideoHeight() const {
- return last_uploaded_video_frame_metadata_.visible_rect.height();
+ return last_uploaded_video_frame_metadata_.visible_rect.Height();
}
double lastUploadedVideoTimestamp() const {
return last_uploaded_video_frame_metadata_.timestamp.InSecondsF();
@@ -86,8 +96,7 @@ class WebGLTexture : public WebGLSharedPlatform3DObject {
GLenum target_;
- blink::WebMediaPlayer::VideoFrameUploadMetadata
- last_uploaded_video_frame_metadata_ = {};
+ VideoFrameUploadMetadata last_uploaded_video_frame_metadata_ = {};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
index 468ae30e7f6..2f331639d70 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
@@ -5,11 +5,14 @@
#include "third_party/blink/renderer/modules/webgl/webgl_video_texture.h"
#include "build/build_config.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_metadata.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
#include "third_party/blink/renderer/modules/webgl/webgl_video_texture_enum.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
namespace blink {
@@ -79,27 +82,45 @@ VideoFrameMetadata* WebGLVideoTexture::shareVideoImageWEBGL(
NOTIMPLEMENTED();
return nullptr;
#else
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+ scoped_refptr<media::VideoFrame> media_video_frame;
+ if (auto* wmp = video->GetWebMediaPlayer()) {
+ media_video_frame = wmp->GetCurrentFrame();
+ video_renderer = wmp->GetPaintCanvasVideoRenderer();
+ }
+
+ if (!media_video_frame || !video_renderer)
+ return nullptr;
+
// For WebGL last-uploaded-frame-metadata API.
- WebMediaPlayer::VideoFrameUploadMetadata frame_metadata = {};
- auto* frame_metadata_ptr = &frame_metadata;
- int already_uploaded_id = HTMLVideoElement::kNoAlreadyUploadedFrame;
- if (RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled())
- already_uploaded_id = texture->GetLastUploadedVideoFrameId();
+ auto metadata = CreateVideoFrameUploadMetadata(
+ media_video_frame.get(), texture->GetLastUploadedVideoFrameId());
+ if (metadata.skipped) {
+ texture->UpdateLastUploadedFrame(metadata);
+ DCHECK(current_frame_metadata_);
+ return current_frame_metadata_;
+ }
target = GL_TEXTURE_2D;
+ viz::RasterContextProvider* raster_context_provider = nullptr;
+ if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
+ if (auto* context_provider = wrapper->ContextProvider())
+ raster_context_provider = context_provider->RasterContextProvider();
+ }
+
// TODO(shaobo.yan@intel.com) : A fallback path or exception needs to be
// added when video is not using gpu decoder.
- bool success = video->PrepareVideoFrameForWebGL(
- scoped.Context()->ContextGL(), target, texture->Object(),
- already_uploaded_id, frame_metadata_ptr);
+ const bool success = video_renderer->PrepareVideoFrameForWebGL(
+ raster_context_provider, scoped.Context()->ContextGL(),
+ std::move(media_video_frame), target, texture->Object());
if (!success) {
exception_state.ThrowTypeError("Failed to share video to texture.");
return nullptr;
}
if (RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled())
- texture->UpdateLastUploadedFrame(frame_metadata);
+ texture->UpdateLastUploadedFrame(metadata);
if (!current_frame_metadata_)
current_frame_metadata_ = VideoFrameMetadata::Create();
@@ -109,14 +130,13 @@ VideoFrameMetadata* WebGLVideoTexture::shareVideoImageWEBGL(
// not currently saved in VideoFrameCompositor, so VFC::ProcessNewFrame()
// would need to save the current time as well as the presentation time.
current_frame_metadata_->setPresentationTime(
- frame_metadata_ptr->timestamp.InMicrosecondsF());
+ metadata.timestamp.InMicrosecondsF());
current_frame_metadata_->setExpectedDisplayTime(
- frame_metadata_ptr->expected_timestamp.InMicrosecondsF());
+ metadata.expected_timestamp.InMicrosecondsF());
- current_frame_metadata_->setWidth(frame_metadata_ptr->visible_rect.width());
- current_frame_metadata_->setHeight(frame_metadata_ptr->visible_rect.height());
- current_frame_metadata_->setMediaTime(
- frame_metadata_ptr->timestamp.InSecondsF());
+ current_frame_metadata_->setWidth(metadata.visible_rect.Width());
+ current_frame_metadata_->setHeight(metadata.visible_rect.Height());
+ current_frame_metadata_->setMediaTime(metadata.timestamp.InSecondsF());
// This is a required field. It is supposed to be monotonically increasing for
// video.requestVideoFrameCallback, but it isn't used yet for
@@ -135,4 +155,28 @@ bool WebGLVideoTexture::releaseVideoImageWEBGL(
return true;
}
+// static
+WebGLTexture::VideoFrameUploadMetadata
+WebGLVideoTexture::CreateVideoFrameUploadMetadata(
+ const media::VideoFrame* frame,
+ int already_uploaded_id) {
+ DCHECK(frame);
+ WebGLTexture::VideoFrameUploadMetadata metadata = {};
+ if (!RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled())
+ return metadata;
+
+ metadata.frame_id = frame->unique_id();
+ metadata.visible_rect = IntRect(frame->visible_rect());
+ metadata.timestamp = frame->timestamp();
+ if (frame->metadata().frame_duration.has_value()) {
+ metadata.expected_timestamp =
+ frame->timestamp() + *frame->metadata().frame_duration;
+ };
+
+ // Skip uploading frames which have already been uploaded.
+ if (already_uploaded_id == frame->unique_id())
+ metadata.skipped = true;
+ return metadata;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.h
index 2530b5a02ed..4661272ba26 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.h
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.h
@@ -7,6 +7,10 @@
#include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
+namespace media {
+class VideoFrame;
+}
+
namespace blink {
class HTMLVideoElement;
@@ -34,6 +38,12 @@ class WebGLVideoTexture final : public WebGLExtension {
bool releaseVideoImageWEBGL(ExecutionContext*, unsigned, ExceptionState&);
+ // Helper method for filling in VideoFrameUploadMetadata. Will be default
+ // initialized (skipped = false) if the metadata API is disabled.
+ static WebGLTexture::VideoFrameUploadMetadata CreateVideoFrameUploadMetadata(
+ const media::VideoFrame* frame,
+ int already_uploaded_id);
+
private:
Member<VideoFrameMetadata> current_frame_metadata_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_texture_info.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_texture_info.idl
new file mode 100644
index 00000000000..ce0d3f5e039
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_texture_info.idl
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://www.khronos.org/registry/webgl/extensions/proposals/WEBGL_webcodecs_video_frame/
+
+dictionary WebGLWebCodecsTextureInfo {
+ // webgl texture
+ WebGLTexture texture;
+
+ // texture target: { GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES, ...}
+ GLenum target;
+
+ // {"sampler", "samplerExternalOES", ...}
+ DOMString samplerType;
+
+ // {"texture2D", ...}
+ DOMString samplerFunc;
+
+ // {"r", "rg", "rgb", ...}
+ DOMString components;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.cc
new file mode 100644
index 00000000000..5a2fc50ae6b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.cc
@@ -0,0 +1,495 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h"
+
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "media/base/wait_and_replace_sync_token_client.h"
+#include "media/video/gpu_memory_buffer_video_frame_pool.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_space_matrix_id.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_space_primary_id.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_space_range_id.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_space_transfer_id.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_color_space.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_pixel_format.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_texture_info.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_webgl_webcodecs_video_frame_handle.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_unowned_texture.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/worker_pool.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "ui/gfx/color_transform.h"
+
+namespace blink {
+
+namespace {
+
+#if defined(OS_WIN)
+const char kRequiredExtension[] = "GL_NV_EGL_stream_consumer_external";
+#elif defined(OS_MAC)
+const char kRequiredExtension[] = "GL_ANGLE_texture_rectangle";
+#elif defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+const char kRequiredExtension[] = "GL_OES_EGL_image_external";
+#else
+const char kRequiredExtension[] = "";
+#endif
+
+void FillVideoColorSpace(VideoColorSpace* video_color_space,
+ gfx::ColorSpace& gfx_color_space) {
+ gfx::ColorSpace::PrimaryID primaries = gfx_color_space.GetPrimaryID();
+ base::Optional<V8ColorSpacePrimaryID> primary_id;
+ switch (primaries) {
+ case gfx::ColorSpace::PrimaryID::BT709:
+ primary_id = V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kBT709);
+ break;
+ case gfx::ColorSpace::PrimaryID::BT470M:
+ primary_id = V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kBT470M);
+ break;
+ case gfx::ColorSpace::PrimaryID::BT470BG:
+ primary_id = V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kBT470BG);
+ break;
+ case gfx::ColorSpace::PrimaryID::SMPTE170M:
+ primary_id =
+ V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kSMPTE170M);
+ break;
+ case gfx::ColorSpace::PrimaryID::SMPTE240M:
+ primary_id =
+ V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kSMPTE240M);
+ break;
+ case gfx::ColorSpace::PrimaryID::FILM:
+ primary_id = V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kFILM);
+ break;
+ case gfx::ColorSpace::PrimaryID::BT2020:
+ primary_id = V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kBT2020);
+ break;
+ case gfx::ColorSpace::PrimaryID::SMPTEST428_1:
+ primary_id =
+ V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kSmptest4281);
+ break;
+ case gfx::ColorSpace::PrimaryID::SMPTEST431_2:
+ primary_id =
+ V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kSmptest4312);
+ break;
+ case gfx::ColorSpace::PrimaryID::SMPTEST432_1:
+ primary_id =
+ V8ColorSpacePrimaryID(V8ColorSpacePrimaryID::Enum::kSmptest4321);
+ break;
+ // TODO(jie.a.chen@intel.com): Need to check EBU_3213_E.
+ default:;
+ }
+ if (primary_id) {
+ video_color_space->setPrimaryID(*primary_id);
+ }
+
+ gfx::ColorSpace::TransferID transfer = gfx_color_space.GetTransferID();
+ base::Optional<V8ColorSpaceTransferID> transfer_id;
+ switch (transfer) {
+ case gfx::ColorSpace::TransferID::BT709:
+#if defined(OS_MAC)
+ // TODO(jie.a.chen@intel.com): BT709_APPLE is not available in WebCodecs.
+ case gfx::ColorSpace::TransferID::BT709_APPLE:
+#endif
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kBT709);
+ break;
+ case gfx::ColorSpace::TransferID::GAMMA22:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kGAMMA22);
+ break;
+ case gfx::ColorSpace::TransferID::GAMMA28:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kGAMMA28);
+ break;
+ case gfx::ColorSpace::TransferID::SMPTE170M:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kSMPTE170M);
+ break;
+ case gfx::ColorSpace::TransferID::SMPTE240M:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kSMPTE240M);
+ break;
+ case gfx::ColorSpace::TransferID::LINEAR:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kLINEAR);
+ break;
+ case gfx::ColorSpace::TransferID::LOG:
+ transfer_id = V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kLOG);
+ break;
+ case gfx::ColorSpace::TransferID::LOG_SQRT:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kLogSqrt);
+ break;
+ case gfx::ColorSpace::TransferID::IEC61966_2_4:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kIec6196624);
+ break;
+ case gfx::ColorSpace::TransferID::BT1361_ECG:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kBt1361Ecg);
+ break;
+ case gfx::ColorSpace::TransferID::IEC61966_2_1:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kIec6196621);
+ break;
+ case gfx::ColorSpace::TransferID::BT2020_10:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kBt202010);
+ break;
+
+ case gfx::ColorSpace::TransferID::BT2020_12:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kBt202012);
+ break;
+ case gfx::ColorSpace::TransferID::SMPTEST2084:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kSMPTEST2084);
+ break;
+ case gfx::ColorSpace::TransferID::SMPTEST428_1:
+ transfer_id =
+ V8ColorSpaceTransferID(V8ColorSpaceTransferID::Enum::kSmptest4281);
+ break;
+ default:;
+ }
+ if (transfer_id) {
+ video_color_space->setTransferID(*transfer_id);
+ }
+
+ gfx::ColorSpace::MatrixID matrix = gfx_color_space.GetMatrixID();
+ base::Optional<V8ColorSpaceMatrixID> matrix_id;
+ switch (matrix) {
+ case gfx::ColorSpace::MatrixID::RGB:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kRGB);
+ break;
+ case gfx::ColorSpace::MatrixID::BT709:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kBT709);
+ break;
+ case gfx::ColorSpace::MatrixID::FCC:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kFCC);
+ break;
+ case gfx::ColorSpace::MatrixID::BT470BG:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kBT470BG);
+ break;
+ case gfx::ColorSpace::MatrixID::SMPTE170M:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kSMPTE170M);
+ break;
+ case gfx::ColorSpace::MatrixID::SMPTE240M:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kSMPTE240M);
+ break;
+ case gfx::ColorSpace::MatrixID::YCOCG:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kYCOCG);
+ break;
+ case gfx::ColorSpace::MatrixID::BT2020_NCL:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kBt2020Ncl);
+ break;
+ case gfx::ColorSpace::MatrixID::BT2020_CL:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kBt2020Cl);
+ break;
+ case gfx::ColorSpace::MatrixID::YDZDX:
+ matrix_id = V8ColorSpaceMatrixID(V8ColorSpaceMatrixID::Enum::kYDZDX);
+ break;
+ default:;
+ }
+ if (matrix_id) {
+ video_color_space->setMatrixID(*matrix_id);
+ }
+
+ gfx::ColorSpace::RangeID range = gfx_color_space.GetRangeID();
+ base::Optional<V8ColorSpaceRangeID> range_id;
+ switch (range) {
+ case gfx::ColorSpace::RangeID::LIMITED:
+ range_id = V8ColorSpaceRangeID(V8ColorSpaceRangeID::Enum::kLIMITED);
+ break;
+ case gfx::ColorSpace::RangeID::FULL:
+ range_id = V8ColorSpaceRangeID(V8ColorSpaceRangeID::Enum::kFULL);
+ break;
+ case gfx::ColorSpace::RangeID::DERIVED:
+ range_id = V8ColorSpaceRangeID(V8ColorSpaceRangeID::Enum::kDERIVED);
+ break;
+ default:;
+ }
+ if (range_id) {
+ video_color_space->setRangeID(*range_id);
+ }
+}
+
+void GetMediaTaskRunnerAndGpuFactoriesOnMainThread(
+ scoped_refptr<base::SingleThreadTaskRunner>* media_task_runner_out,
+ media::GpuVideoAcceleratorFactories** gpu_factories_out,
+ base::WaitableEvent* waitable_event) {
+ DCHECK(IsMainThread());
+ *media_task_runner_out = Platform::Current()->MediaThreadTaskRunner();
+ *gpu_factories_out = Platform::Current()->GetGpuFactories();
+ waitable_event->Signal();
+}
+
+} // namespace
+
+WebGLWebCodecsVideoFrame::WebGLWebCodecsVideoFrame(
+ WebGLRenderingContextBase* context)
+ : WebGLExtension(context) {
+ context->ContextGL()->RequestExtensionCHROMIUM(kRequiredExtension);
+
+#if defined(OS_MAC)
+ // texture_rectangle needs to be turned on for MAC.
+ context->ContextGL()->Enable(GC3D_TEXTURE_RECTANGLE_ARB);
+#endif
+
+#if defined(OS_WIN)
+ formats_supported[media::PIXEL_FORMAT_NV12] = true;
+ auto& components_nv12 = format_to_components_map_[media::PIXEL_FORMAT_NV12];
+ components_nv12[media::VideoFrame::kYPlane] = "r";
+ components_nv12[media::VideoFrame::kUPlane] = "rg";
+#elif defined(OS_MAC)
+ formats_supported[media::PIXEL_FORMAT_XRGB] = true;
+ auto& components_xrgb = format_to_components_map_[media::PIXEL_FORMAT_XRGB];
+ components_xrgb[media::VideoFrame::kYPlane] = "rgba";
+#elif defined(OS_ANDROID)
+ formats_supported[media::PIXEL_FORMAT_ABGR] = true;
+ auto& components_abgr = format_to_components_map_[media::PIXEL_FORMAT_ABGR];
+ components_abgr[media::VideoFrame::kYPlane] = "rgb";
+
+ // GpuMemoryBufferVideoFramePool
+ formats_supported[media::PIXEL_FORMAT_NV12] = true;
+ auto& components_nv12 = format_to_components_map_[media::PIXEL_FORMAT_NV12];
+ components_nv12[media::VideoFrame::kYPlane] = "r";
+ components_nv12[media::VideoFrame::kUPlane] = "rg";
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
+ formats_supported[media::PIXEL_FORMAT_ABGR] = true;
+ auto& components_abgr = format_to_components_map_[media::PIXEL_FORMAT_ABGR];
+ components_abgr[media::VideoFrame::kYPlane] = "rgb";
+#endif
+}
+
+WebGLWebCodecsVideoFrame::~WebGLWebCodecsVideoFrame() {
+ if (gpu_memory_buffer_pool_) {
+ media_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(gpu_memory_buffer_pool_));
+ }
+}
+
+WebGLExtensionName WebGLWebCodecsVideoFrame::GetName() const {
+ return kWebGLWebCodecsVideoFrameName;
+}
+
+bool WebGLWebCodecsVideoFrame::Supported(WebGLRenderingContextBase* context) {
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_FUCHSIA)
+ // TODO(jie.a.chen@intel.com): Add Linux support.
+ return false;
+#else
+ return true;
+#endif
+}
+
+const char* WebGLWebCodecsVideoFrame::ExtensionName() {
+ return "WEBGL_webcodecs_video_frame";
+}
+
+void WebGLWebCodecsVideoFrame::Trace(Visitor* visitor) const {
+ WebGLExtension::Trace(visitor);
+}
+
+WebGLWebCodecsVideoFrameHandle* WebGLWebCodecsVideoFrame::importVideoFrame(
+ ExecutionContext* execution_context,
+ VideoFrame* video_frame,
+ ExceptionState& exception_state) {
+ WebGLExtensionScopedContext scoped(this);
+ if (!video_frame || scoped.IsLost())
+ return nullptr;
+
+ const char* sampler_type = "sampler2D";
+ const char* sampler_func = "texture2D";
+ gfx::ColorSpace src_color_space = gfx::ColorSpace::CreateREC709();
+ media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN;
+#if defined(OS_WIN)
+ sampler_type = "samplerExternalOES";
+ pixel_format = media::PIXEL_FORMAT_NV12;
+#elif defined(OS_MAC)
+ sampler_type = "sampler2DRect";
+ sampler_func = "texture2DRect";
+ pixel_format = media::PIXEL_FORMAT_XRGB;
+#elif defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+ sampler_type = "samplerExternalOES";
+ pixel_format = media::PIXEL_FORMAT_ABGR;
+ src_color_space = gfx::ColorSpace::CreateSRGB();
+#endif
+
+ scoped_refptr<media::VideoFrame> frame = video_frame->frame();
+ if (!frame->HasTextures()) {
+ InitializeGpuMemoryBufferPool();
+ base::WaitableEvent waitable_event;
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
+ base::Unretained(gpu_memory_buffer_pool_.get()),
+ base::RetainedRef(frame),
+ base::BindOnce(
+ &WebGLWebCodecsVideoFrame::OnHardwareVideoFrameCreated,
+ base::Unretained(this), base::Unretained(&waitable_event))));
+ waitable_event.Wait();
+
+ if (frame == hardware_video_frame_) {
+ exception_state.ThrowTypeError(
+ "Unable to import a software video frame.");
+ return nullptr;
+ }
+ frame = std::move(hardware_video_frame_);
+#if defined(OS_WIN)
+ sampler_type = "sampler2D";
+#elif defined(OS_ANDROID)
+ sampler_type = "sampler2D";
+ pixel_format = frame->format();
+ src_color_space = frame->ColorSpace();
+#endif
+ }
+
+ if (!formats_supported[pixel_format]) {
+ exception_state.ThrowTypeError(
+ String::Format("VideoPixelFormat:%s is not supported yet.",
+ media::VideoPixelFormatToString(pixel_format).c_str()));
+ return nullptr;
+ }
+
+ const auto& components = format_to_components_map_[pixel_format];
+ HeapVector<Member<WebGLWebCodecsTextureInfo>> info_array;
+ for (size_t tex = 0; tex < frame->NumTextures(); ++tex) {
+ WebGLWebCodecsTextureInfo* texture_info =
+ MakeGarbageCollected<WebGLWebCodecsTextureInfo>();
+ info_array.push_back(texture_info);
+ texture_info->setSamplerType(sampler_type);
+ texture_info->setSamplerFunc(sampler_func);
+ texture_info->setComponents(components[tex].c_str());
+
+ auto* gl = scoped.Context()->ContextGL();
+ auto& mailbox_holder = frame->mailbox_holder(tex);
+ gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
+ GLuint texture_id = 0;
+ if (mailbox_holder.mailbox.IsSharedImage()) {
+ texture_id = gl->CreateAndTexStorage2DSharedImageCHROMIUM(
+ mailbox_holder.mailbox.name);
+ gl->BeginSharedImageAccessDirectCHROMIUM(
+ texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
+ } else {
+ texture_id =
+ gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
+ }
+ DCHECK_NE(texture_id, 0u);
+ auto texture_target = frame->mailbox_holder(tex).texture_target;
+ WebGLUnownedTexture* texture = MakeGarbageCollected<WebGLUnownedTexture>(
+ scoped.Context(), texture_id, texture_target);
+ texture_info->setTexture(texture);
+ texture_info->setTarget(texture_target);
+ }
+
+ WebGLWebCodecsVideoFrameHandle* video_frame_handle =
+ MakeGarbageCollected<WebGLWebCodecsVideoFrameHandle>();
+ video_frame_handle->setTextureInfoArray(info_array);
+ if (std::string(kRequiredExtension) != "") {
+ video_frame_handle->setRequiredExtension(kRequiredExtension);
+ }
+ // Remove "PIXEL_FORMAT_" prefix
+ auto&& video_pixel_format =
+ V8VideoPixelFormat::Create(&VideoPixelFormatToString(pixel_format)[13]);
+ DCHECK(video_pixel_format);
+ video_frame_handle->setPixelFormat(*video_pixel_format);
+
+ // TODO(jie.a.chen@intel.com): Is the colorspace/flip-y/pre-alpha of video
+ // frame specific to OS only? For the same OS, does it vary for different
+ // video streams?
+ video_frame_handle->setFlipY(true);
+ video_frame_handle->setPremultipliedAlpha(false);
+#if defined(OS_WIN)
+ DCHECK(frame->format() == media::PIXEL_FORMAT_NV12);
+ src_color_space = frame->ColorSpace();
+#elif defined(OS_MAC)
+ video_frame_handle->setRequiredExtension("GL_ARB_texture_rectangle");
+ video_frame_handle->setPremultipliedAlpha(true);
+ src_color_space = frame->ColorSpace();
+ src_color_space = src_color_space.GetAsFullRangeRGB();
+#endif
+ VideoColorSpace* video_frame_color_space =
+ MakeGarbageCollected<VideoColorSpace>();
+ FillVideoColorSpace(video_frame_color_space, src_color_space);
+ video_frame_handle->setColorSpace(video_frame_color_space);
+
+ gfx::ColorSpace dst_color_space = gfx::ColorSpace::CreateSRGB();
+ std::unique_ptr<gfx::ColorTransform> color_transform(
+ gfx::ColorTransform::NewColorTransform(
+ src_color_space, dst_color_space,
+ gfx::ColorTransform::Intent::INTENT_ABSOLUTE));
+ video_frame_handle->setColorConversionShaderFunc(
+ color_transform->GetShaderSource().c_str());
+
+ // Bookkeeping of imported video frames.
+ GLuint tex0 = info_array[0]->texture()->Object();
+ tex0_to_video_frame_map_.insert(tex0, frame);
+
+ return video_frame_handle;
+}
+
+bool WebGLWebCodecsVideoFrame::releaseVideoFrame(
+ ExecutionContext* execution_context,
+ WebGLWebCodecsVideoFrameHandle* handle,
+ ExceptionState& exception_state) {
+ DCHECK(handle);
+ WebGLExtensionScopedContext scoped(this);
+ auto* gl = scoped.Context()->ContextGL();
+ auto& info_array = handle->textureInfoArray();
+ GLuint tex0 = info_array[0]->texture()->Object();
+ auto frame = tex0_to_video_frame_map_.Take(tex0);
+ for (wtf_size_t i = 0; i < info_array.size(); ++i) {
+ auto mailbox = frame->mailbox_holder(i).mailbox;
+ GLuint texture = info_array[i]->texture()->Object();
+ DCHECK_NE(texture, 0u);
+ if (mailbox.IsSharedImage()) {
+ gl->EndSharedImageAccessDirectCHROMIUM(texture);
+ }
+ gl->DeleteTextures(1, &texture);
+ }
+ media::WaitAndReplaceSyncTokenClient client(gl);
+ frame->UpdateReleaseSyncToken(&client);
+ return true;
+}
+
+void WebGLWebCodecsVideoFrame::OnHardwareVideoFrameCreated(
+ base::WaitableEvent* waitable_event,
+ scoped_refptr<media::VideoFrame> video_frame) {
+ hardware_video_frame_ = std::move(video_frame);
+ waitable_event->Signal();
+}
+
+void WebGLWebCodecsVideoFrame::InitializeGpuMemoryBufferPool() {
+ if (!worker_task_runner_) {
+ worker_task_runner_ = worker_pool::CreateSequencedTaskRunner({});
+ }
+ if (!gpu_memory_buffer_pool_) {
+ media::GpuVideoAcceleratorFactories* gpu_factories = nullptr;
+ if (IsMainThread()) {
+ media_task_runner_ = Platform::Current()->MediaThreadTaskRunner();
+ gpu_factories = Platform::Current()->GetGpuFactories();
+ } else {
+ base::WaitableEvent waitable_event;
+ // TODO(crbug.com/1164152): Lift the main thread restriction.
+ if (PostCrossThreadTask(
+ *Thread::MainThread()->GetTaskRunner(), FROM_HERE,
+ CrossThreadBindOnce(
+ &GetMediaTaskRunnerAndGpuFactoriesOnMainThread,
+ CrossThreadUnretained(&media_task_runner_),
+ CrossThreadUnretained(&gpu_factories),
+ CrossThreadUnretained(&waitable_event)))) {
+ waitable_event.Wait();
+ }
+ }
+ gpu_memory_buffer_pool_ =
+ std::make_unique<media::GpuMemoryBufferVideoFramePool>(
+ media_task_runner_, worker_task_runner_, gpu_factories);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h
new file mode 100644
index 00000000000..644d01c105f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_WEBCODECS_VIDEO_FRAME_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_WEBCODECS_VIDEO_FRAME_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_extension.h"
+
+namespace media {
+class GpuMemoryBufferVideoFramePool;
+} // namespace media
+
+namespace blink {
+
+class WebGLWebCodecsVideoFrameHandle;
+
+class WebGLWebCodecsVideoFrame final : public WebGLExtension {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ ~WebGLWebCodecsVideoFrame() override;
+
+ static bool Supported(WebGLRenderingContextBase*);
+ static const char* ExtensionName();
+
+ explicit WebGLWebCodecsVideoFrame(WebGLRenderingContextBase*);
+
+ WebGLExtensionName GetName() const override;
+
+ void Trace(Visitor*) const override;
+
+ WebGLWebCodecsVideoFrameHandle* importVideoFrame(ExecutionContext*,
+ blink::VideoFrame*,
+ ExceptionState&);
+
+ bool releaseVideoFrame(ExecutionContext*,
+ WebGLWebCodecsVideoFrameHandle*,
+ ExceptionState&);
+
+ private:
+ void OnHardwareVideoFrameCreated(
+ base::WaitableEvent* waitable_event,
+ scoped_refptr<media::VideoFrame> video_frame);
+
+ void InitializeGpuMemoryBufferPool();
+
+ std::bitset<media::PIXEL_FORMAT_MAX + 1> formats_supported;
+ std::array<std::array<std::string, media::VideoFrame::kMaxPlanes>,
+ media::PIXEL_FORMAT_MAX + 1>
+ format_to_components_map_;
+
+ using VideoFrameHandleMap = HashMap<GLuint, scoped_refptr<media::VideoFrame>>;
+ // This holds the reference for all video frames being imported, but not
+ // yet released.
+ VideoFrameHandleMap tex0_to_video_frame_map_;
+
+ std::unique_ptr<media::GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool_;
+ scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ scoped_refptr<media::VideoFrame> hardware_video_frame_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_WEBCODECS_VIDEO_FRAME_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.idl
new file mode 100644
index 00000000000..dfa8b468120
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame.idl
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://www.khronos.org/registry/webgl/extensions/proposals/WEBGL_webcodecs_video_frame/
+
+[
+ RuntimeEnabled=WebGLDraftExtensions,
+ LegacyNoInterfaceObject
+] interface WebGLWebCodecsVideoFrame {
+ // This imports a VideoFrame from WebCodecs, and returns a
+ // VideoFrameHandle which is needed to access this VideoFrame
+ // in WebGL. If the VideoFrame is not backed by GPU, null is
+ // returned. The VideoFrame keeps being locked until
+ // releaseVideoFrame is called.
+ [CallWith=ExecutionContext, RaisesException]
+ WebGLWebCodecsVideoFrameHandle importVideoFrame(VideoFrame videoFrame);
+
+ // Unlocks the VideoFrame.
+ [CallWith=ExecutionContext, RaisesException]
+ boolean releaseVideoFrame(WebGLWebCodecsVideoFrameHandle handle);
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame_handle.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame_handle.idl
new file mode 100644
index 00000000000..a41a2373b8e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_webcodecs_video_frame_handle.idl
@@ -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.
+
+// https://www.khronos.org/registry/webgl/extensions/proposals/WEBGL_webcodecs_video_frame/
+
+dictionary WebGLWebCodecsVideoFrameHandle {
+ required FrozenArray<WebGLWebCodecsTextureInfo> textureInfoArray;
+
+ // The GLSL extension to be enabled in the shader.
+ // {"GL_NV_EGL_stream_consumer_external", "GL_OES_EGL_image_external", ...}
+ DOMString? requiredExtension;
+
+ // {"NV12", "I420", "ABGR", ...}
+ // TODO(jie.a.chen@intel.com): Move this to WebCodecs VideoFrame.
+ VideoPixelFormat? pixelFormat;
+
+ // The color space of texel color fetched from the video frame texture.
+ // With this information, it's possible to accurately interpret and convert
+ // the texels of video frame into the canvas' color space of this WebGL
+ // context, so that developers can write their own GLSL function for color
+ // conversion.
+ // TODO(jie.a.chen@intel.com): Figure out SDR white level, which may be needed
+ // for HDR video.
+ VideoColorSpace colorSpace;
+
+ // This generates an GLSL "vec3 DoColorConversion(vec3 color)" function,
+ // which can be used to convert the video frame from its original color
+ // space to the current WebGL context's canvas color space.
+ // If developers won't bother to write their own color conversion function,
+ // this helper function is for their convenience.
+ // TODO(jie.a.chen@intel.com): Add function name prefix/suffix to avoid
+ // potential name confliction.
+ DOMString colorConversionShaderFunc;
+
+ // Indicates whether the video frame is Y flipped.
+ // TODO(jie.a.chen@intel.com): Move this to WebCodecs VideoFrame.
+ boolean flipY;
+
+ // Indicates whether the video frame is alpha premultiplied.
+ // TODO(jie.a.chen@intel.com): Move this to WebCodecs VideoFrame.
+ boolean premultipliedAlpha;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
index a52893f9a32..4a3aa2e99cf 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -74,10 +74,6 @@ blink_modules_sources("webgpu") {
"gpu_uncaptured_error_event.h",
"gpu_validation_error.cc",
"gpu_validation_error.h",
- "navigator_gpu.cc",
- "navigator_gpu.h",
- "worker_navigator_gpu.cc",
- "worker_navigator_gpu.h",
]
deps = [
"//gpu/command_buffer/client:webgpu_interface",
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/DEPS b/chromium/third_party/blink/renderer/modules/webgpu/DEPS
index 56fc5d0ad54..44323d4ccf6 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/DEPS
+++ b/chromium/third_party/blink/renderer/modules/webgpu/DEPS
@@ -7,5 +7,6 @@ include_rules = [
"+gpu/command_buffer/common/sync_token.h",
"+gpu/command_buffer/client/shared_image_interface.h",
"+gpu/command_buffer/client/webgpu_interface.h",
+ "+media/base/video_frame.h",
"+services/metrics/public/cpp/ukm_builders.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webgpu/DIR_METADATA
new file mode 100644
index 00000000000..5f64887a668
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebGPU"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/OWNERS b/chromium/third_party/blink/renderer/modules/webgpu/OWNERS
index 1a2169f842c..65bf0485c07 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webgpu/OWNERS
@@ -1,5 +1,4 @@
cwallez@chromium.org
kainino@chromium.org
+enga@chromium.org
kbr@chromium.org
-
-# COMPONENT: Blink>WebGPU
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 9c588080c10..541f480cad5 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -9,9 +9,10 @@
#include "third_party/blink/renderer/bindings/modules/v8/double_sequence_or_gpu_color_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/unsigned_long_enforce_range_sequence_or_gpu_extent_3d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/unsigned_long_enforce_range_sequence_or_gpu_origin_3d_dict.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_copy_view.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_data_layout.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_texture.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_data_layout.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_index_format.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_shader_module.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
@@ -53,6 +54,73 @@ WGPUBindingType AsDawnEnum<WGPUBindingType>(const WTF::String& webgpu_enum) {
}
template <>
+WGPUBufferBindingType AsDawnEnum<WGPUBufferBindingType>(
+ const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "uniform") {
+ return WGPUBufferBindingType_Uniform;
+ }
+ if (webgpu_enum == "storage") {
+ return WGPUBufferBindingType_Storage;
+ }
+ if (webgpu_enum == "read-only-storage") {
+ return WGPUBufferBindingType_ReadOnlyStorage;
+ }
+ NOTREACHED();
+ return WGPUBufferBindingType_Force32;
+}
+
+template <>
+WGPUSamplerBindingType AsDawnEnum<WGPUSamplerBindingType>(
+ const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "filtering") {
+ return WGPUSamplerBindingType_Filtering;
+ }
+ if (webgpu_enum == "non-filtering") {
+ return WGPUSamplerBindingType_NonFiltering;
+ }
+ if (webgpu_enum == "comparison") {
+ return WGPUSamplerBindingType_Comparison;
+ }
+ NOTREACHED();
+ return WGPUSamplerBindingType_Force32;
+}
+
+template <>
+WGPUTextureSampleType AsDawnEnum<WGPUTextureSampleType>(
+ const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "float") {
+ return WGPUTextureSampleType_Float;
+ }
+ if (webgpu_enum == "unfilterable-float") {
+ return WGPUTextureSampleType_UnfilterableFloat;
+ }
+ if (webgpu_enum == "depth") {
+ return WGPUTextureSampleType_Depth;
+ }
+ if (webgpu_enum == "sint") {
+ return WGPUTextureSampleType_Sint;
+ }
+ if (webgpu_enum == "uint") {
+ return WGPUTextureSampleType_Uint;
+ }
+ NOTREACHED();
+ return WGPUTextureSampleType_Force32;
+}
+
+template <>
+WGPUStorageTextureAccess AsDawnEnum<WGPUStorageTextureAccess>(
+ const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "read-only") {
+ return WGPUStorageTextureAccess_ReadOnly;
+ }
+ if (webgpu_enum == "write-only") {
+ return WGPUStorageTextureAccess_WriteOnly;
+ }
+ NOTREACHED();
+ return WGPUStorageTextureAccess_Force32;
+}
+
+template <>
WGPUTextureComponentType AsDawnEnum<WGPUTextureComponentType>(
const WTF::String& webgpu_enum) {
if (webgpu_enum == "float") {
@@ -231,10 +299,6 @@ WGPUTextureFormat AsDawnEnum<WGPUTextureFormat>(
if (webgpu_enum == "rgb10a2unorm") {
return WGPUTextureFormat_RGB10A2Unorm;
}
- if (webgpu_enum == "rg11b10float") {
- // Deprecated.
- return WGPUTextureFormat_RG11B10Ufloat;
- }
if (webgpu_enum == "rg11b10ufloat") {
return WGPUTextureFormat_RG11B10Ufloat;
}
@@ -318,10 +382,6 @@ WGPUTextureFormat AsDawnEnum<WGPUTextureFormat>(
if (webgpu_enum == "bc6h-rgb-float") {
return WGPUTextureFormat_BC6HRGBFloat;
}
- if (webgpu_enum == "bc6h-rgb-sfloat") {
- // Deprecated.
- return WGPUTextureFormat_BC6HRGBFloat;
- }
if (webgpu_enum == "bc7-rgba-unorm") {
return WGPUTextureFormat_BC7RGBAUnorm;
}
@@ -443,6 +503,15 @@ WGPUIndexFormat AsDawnEnum<WGPUIndexFormat>(const WTF::String& webgpu_enum) {
return WGPUIndexFormat_Force32;
}
+WGPUIndexFormat AsDawnEnum(const V8GPUIndexFormat& webgpu_enum) {
+ switch (webgpu_enum.AsEnum()) {
+ case V8GPUIndexFormat::Enum::kUint16:
+ return WGPUIndexFormat_Uint16;
+ case V8GPUIndexFormat::Enum::kUint32:
+ return WGPUIndexFormat_Uint32;
+ }
+}
+
template <>
WGPUPrimitiveTopology AsDawnEnum<WGPUPrimitiveTopology>(
const WTF::String& webgpu_enum) {
@@ -764,7 +833,8 @@ WGPUColor AsDawnType(const DoubleSequenceOrGPUColorDict* webgpu_color) {
}
WGPUExtent3D AsDawnType(
- const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict* webgpu_extent) {
+ const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict* webgpu_extent,
+ GPUDevice* device) {
DCHECK(webgpu_extent);
WGPUExtent3D dawn_extent = {1, 1, 1};
@@ -794,7 +864,14 @@ WGPUExtent3D AsDawnType(
webgpu_extent->GetAsGPUExtent3DDict();
dawn_extent.width = webgpu_extent_3d_dict->width();
dawn_extent.height = webgpu_extent_3d_dict->height();
- dawn_extent.depth = webgpu_extent_3d_dict->depth();
+
+ if (webgpu_extent_3d_dict->hasDepth()) {
+ device->AddConsoleWarning(
+ "Specifying an extent depth is deprecated. Use depthOrArrayLayers.");
+ dawn_extent.depth = webgpu_extent_3d_dict->depth();
+ } else {
+ dawn_extent.depth = webgpu_extent_3d_dict->depthOrArrayLayers();
+ }
} else {
NOTREACHED();
@@ -843,7 +920,7 @@ WGPUOrigin3D AsDawnType(
return dawn_origin;
}
-WGPUTextureCopyView AsDawnType(const GPUTextureCopyView* webgpu_view,
+WGPUTextureCopyView AsDawnType(const GPUImageCopyTexture* webgpu_view,
GPUDevice* device) {
DCHECK(webgpu_view);
DCHECK(webgpu_view->texture());
@@ -861,7 +938,7 @@ WGPUTextureCopyView AsDawnType(const GPUTextureCopyView* webgpu_view,
// WGPU_STRIDE_UNDEFINED (0xFFFF'FFFF). Blink must make sure that an actual
// value of 0xFFFF'FFFF coming in from JS is not treated as
// WGPU_STRIDE_UNDEFINED, so it injects an error in that case.
-const char* ValidateTextureDataLayout(const GPUTextureDataLayout* webgpu_layout,
+const char* ValidateTextureDataLayout(const GPUImageDataLayout* webgpu_layout,
WGPUTextureDataLayout* dawn_layout) {
DCHECK(webgpu_layout);
@@ -894,7 +971,7 @@ const char* ValidateTextureDataLayout(const GPUTextureDataLayout* webgpu_layout,
}
OwnedProgrammableStageDescriptor AsDawnType(
- const GPUProgrammableStageDescriptor* webgpu_stage) {
+ const GPUProgrammableStage* webgpu_stage) {
DCHECK(webgpu_stage);
std::string entry_point = webgpu_stage->entryPoint().Ascii();
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.h b/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
index 4d37448c09d..4305f1ff2b4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
@@ -21,11 +21,12 @@ namespace blink {
class DoubleSequenceOrGPUColorDict;
class GPUColorDict;
-class GPUProgrammableStageDescriptor;
-class GPUTextureCopyView;
-class GPUTextureDataLayout;
+class GPUProgrammableStage;
+class GPUImageCopyTexture;
+class GPUImageDataLayout;
class UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict;
class UnsignedLongEnforceRangeSequenceOrGPUOrigin3DDict;
+class V8GPUIndexFormat;
// Convert WebGPU bitfield values to Dawn enums. These have the same value.
template <typename DawnEnum>
@@ -36,6 +37,7 @@ DawnEnum AsDawnEnum(uint32_t webgpu_enum) {
// Convert WebGPU string enums to Dawn enums.
template <typename DawnEnum>
DawnEnum AsDawnEnum(const WTF::String& webgpu_enum);
+WGPUIndexFormat AsDawnEnum(const V8GPUIndexFormat& webgpu_enum);
// These conversions are used multiple times and are declared here. Conversions
// used only once, for example for object construction, are defined
@@ -44,17 +46,17 @@ WGPUColor AsDawnColor(const Vector<double>&);
WGPUColor AsDawnType(const GPUColorDict*);
WGPUColor AsDawnType(const DoubleSequenceOrGPUColorDict*);
WGPUExtent3D AsDawnType(
- const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict*);
+ const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict*,
+ GPUDevice* device);
WGPUOrigin3D AsDawnType(
const UnsignedLongEnforceRangeSequenceOrGPUOrigin3DDict*);
-WGPUTextureCopyView AsDawnType(const GPUTextureCopyView* webgpu_view,
+WGPUTextureCopyView AsDawnType(const GPUImageCopyTexture* webgpu_view,
GPUDevice* device);
-const char* ValidateTextureDataLayout(const GPUTextureDataLayout* webgpu_layout,
+const char* ValidateTextureDataLayout(const GPUImageDataLayout* webgpu_layout,
WGPUTextureDataLayout* layout);
using OwnedProgrammableStageDescriptor =
std::tuple<WGPUProgrammableStageDescriptor, std::unique_ptr<char[]>>;
-OwnedProgrammableStageDescriptor AsDawnType(
- const GPUProgrammableStageDescriptor*);
+OwnedProgrammableStageDescriptor AsDawnType(const GPUProgrammableStage*);
// WebGPU objects are converted to Dawn objects by getting the opaque handle
// which can be passed to Dawn.
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 15fc7d89a8a..c7c7cd7a8df 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc
@@ -19,10 +19,6 @@ DawnObjectBase::GetDawnControlClient() const {
return dawn_control_client_;
}
-bool DawnObjectBase::IsDawnControlClientDestroyed() const {
- return dawn_control_client_->IsDestroyed();
-}
-
gpu::webgpu::WebGPUInterface* DawnObjectBase::GetInterface() const {
return dawn_control_client_->GetInterface();
}
@@ -31,70 +27,40 @@ const DawnProcTable& DawnObjectBase::GetProcs() const {
return dawn_control_client_->GetProcs();
}
-DawnDeviceClientSerializerHolder::DawnDeviceClientSerializerHolder(
- scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id)
- : dawn_control_client_(std::move(dawn_control_client)),
- device_client_id_(device_client_id) {}
-
-DawnDeviceClientSerializerHolder::~DawnDeviceClientSerializerHolder() {
- if (dawn_control_client_->IsDestroyed()) {
- return;
- }
- dawn_control_client_->GetInterface()->RemoveDevice(device_client_id_);
-}
-
-const scoped_refptr<DawnControlClientHolder>&
-DeviceTreeObject::GetDawnControlClient() const {
- return device_client_serializer_holder_->dawn_control_client_;
-}
-
-bool DeviceTreeObject::IsDawnControlClientDestroyed() const {
- return GetDawnControlClient()->IsDestroyed();
-}
-gpu::webgpu::WebGPUInterface* DeviceTreeObject::GetInterface() const {
- return GetDawnControlClient()->GetInterface();
-}
-const DawnProcTable& DeviceTreeObject::GetProcs() const {
- return GetDawnControlClient()->GetProcs();
-}
-
-uint64_t DeviceTreeObject::GetDeviceClientID() const {
- return device_client_serializer_holder_->device_client_id_;
+void DawnObjectBase::setLabel(const String& value) {
+ // TODO: Relay label changes to Dawn
+ label_ = value;
}
-void DeviceTreeObject::EnsureFlush() {
+void DawnObjectBase::EnsureFlush() {
bool needs_flush = false;
- GetInterface()->EnsureAwaitingFlush(
- device_client_serializer_holder_->device_client_id_, &needs_flush);
+ GetInterface()->EnsureAwaitingFlush(&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_);
+ [](scoped_refptr<DawnControlClientHolder> dawn_control_client) {
+ dawn_control_client->GetInterface()->FlushAwaitingCommands();
},
- device_client_serializer_holder_));
+ dawn_control_client_));
}
// Flush commands up until now on this object's parent device immediately.
-void DeviceTreeObject::FlushNow() {
- GetInterface()->FlushCommands(
- device_client_serializer_holder_->device_client_id_);
+void DawnObjectBase::FlushNow() {
+ GetInterface()->FlushCommands();
}
DawnObjectImpl::DawnObjectImpl(GPUDevice* device)
- : DeviceTreeObject(device->GetDeviceClientSerializerHolder()),
- device_(device) {}
+ : DawnObjectBase(device->GetDawnControlClient()), device_(device) {}
DawnObjectImpl::~DawnObjectImpl() = default;
+WGPUDevice DawnObjectImpl::GetDeviceHandle() {
+ return device_->GetHandle();
+}
+
void DawnObjectImpl::Trace(Visitor* visitor) const {
visitor->Trace(device_);
ScriptWrappable::Trace(visitor);
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 63c2d95f9e8..88ad1008e41 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h
@@ -11,6 +11,33 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+#define DAWN_OBJECTS \
+ X(BindGroup, bindGroup) \
+ X(BindGroupLayout, bindGroupLayout) \
+ X(Buffer, buffer) \
+ X(CommandBuffer, commandBuffer) \
+ X(CommandEncoder, commandEncoder) \
+ X(ComputePassEncoder, computePassEncoder) \
+ X(ComputePipeline, computePipeline) \
+ X(Device, device) \
+ X(Fence, fence) \
+ X(Instance, instance) \
+ X(PipelineLayout, pipelineLayout) \
+ X(QuerySet, querySet) \
+ X(Queue, queue) \
+ X(RenderBundle, renderBundle) \
+ X(RenderBundleEncoder, renderBundleEncoder) \
+ X(RenderPassEncoder, renderPassEncoder) \
+ X(RenderPipeline, renderPipeline) \
+ X(Sampler, sampler) \
+ X(ShaderModule, shaderModule) \
+ X(Surface, surface) \
+ X(SwapChain, swapChain) \
+ X(Texture, texture) \
+ X(TextureView, textureView)
namespace gpu {
namespace webgpu {
@@ -22,8 +49,19 @@ class WebGPUInterface;
namespace blink {
+template <typename T>
+struct WGPUReleaseFn;
+
+#define X(Name, name) \
+ template <> \
+ struct WGPUReleaseFn<WGPU##Name> { \
+ static constexpr void (*DawnProcTable::*fn)(WGPU##Name) = \
+ &DawnProcTable::name##Release; \
+ };
+DAWN_OBJECTS
+#undef X
+
class GPUDevice;
-class Visitor;
// This class allows objects to hold onto a DawnControlClientHolder.
// The DawnControlClientHolder is used to hold the WebGPUInterface and keep
@@ -35,59 +73,9 @@ class DawnObjectBase {
scoped_refptr<DawnControlClientHolder> dawn_control_client);
const scoped_refptr<DawnControlClientHolder>& GetDawnControlClient() const;
- bool IsDawnControlClientDestroyed() const;
gpu::webgpu::WebGPUInterface* GetInterface() const;
const DawnProcTable& GetProcs() const;
- private:
- scoped_refptr<DawnControlClientHolder> dawn_control_client_;
-};
-
-// This class allows objects to hold onto a DawnControlClientHolder and a
-// device client id. Now one GPUDevice is related to one WebGPUSerializer in
-// the client side of WebGPU context. When the GPUDevice and all the other
-// WebGPU objects that are created from the GPUDevice are destroyed, this
-// object will be destroyed and in the destructor of this object we will
-// trigger the clean-ups to the corresponding WebGPUSerailzer and other data
-// structures in the GPU process.
-class DawnDeviceClientSerializerHolder
- : public RefCounted<DawnDeviceClientSerializerHolder> {
- public:
- DawnDeviceClientSerializerHolder(
- scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id);
-
- private:
- friend class RefCounted<DawnDeviceClientSerializerHolder>;
- friend class DeviceTreeObject;
- ~DawnDeviceClientSerializerHolder();
-
- scoped_refptr<DawnControlClientHolder> dawn_control_client_;
- uint64_t device_client_id_;
-};
-
-// This class is the parent of GPUDevice and all the WebGPU objects that are
-// created from a GPUDevice, which holds a
-// scoped_refptr<DawnDeviceClientSerializerHolder> and provides functions to
-// access all the members inside it. When a GPUDevice and all the WebGPU
-// objects created from it are destroyed, the refcount of
-// DawnDeviceClientSerializerHolder will become 0 and the clean-ups to the
-// corresponding WebGPUSerailzer and other data structures in the GPU process
-// will be triggered.
-class DeviceTreeObject {
- public:
- explicit DeviceTreeObject(scoped_refptr<DawnDeviceClientSerializerHolder>
- device_client_seralizer_holder)
- : device_client_serializer_holder_(
- std::move(device_client_seralizer_holder)) {}
-
- const scoped_refptr<DawnControlClientHolder>& GetDawnControlClient() const;
- bool IsDawnControlClientDestroyed() const;
- gpu::webgpu::WebGPUInterface* GetInterface() const;
- const DawnProcTable& GetProcs() const;
-
- 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();
@@ -95,16 +83,22 @@ class DeviceTreeObject {
// Flush commands up until now on this object's parent device immediately.
void FlushNow();
- protected:
- scoped_refptr<DawnDeviceClientSerializerHolder>
- device_client_serializer_holder_;
+ // GPUObjectBase mixin implementation
+ const String& label() const { return label_; }
+ void setLabel(const String& value);
+
+ private:
+ scoped_refptr<DawnControlClientHolder> dawn_control_client_;
+ String label_;
};
-class DawnObjectImpl : public ScriptWrappable, public DeviceTreeObject {
+class DawnObjectImpl : public ScriptWrappable, public DawnObjectBase {
public:
explicit DawnObjectImpl(GPUDevice* device);
~DawnObjectImpl() override;
+ WGPUDevice GetDeviceHandle();
+
void Trace(Visitor* visitor) const override;
protected:
@@ -115,37 +109,48 @@ template <typename Handle>
class DawnObject : public DawnObjectImpl {
public:
DawnObject(GPUDevice* device, Handle handle)
- : DawnObjectImpl(device), handle_(handle) {}
- ~DawnObject() override = default;
+ : DawnObjectImpl(device),
+ handle_(handle),
+ device_handle_(GetDeviceHandle()) {
+ // All WebGPU Blink objects created directly or by the Device hold a
+ // Member<GPUDevice> which keeps the device alive. However, this does not
+ // enforce that the GPUDevice is finalized after all objects referencing it.
+ // Add an extra ref in this constructor, and a release in the destructor to
+ // ensure that the Dawn device is destroyed last.
+ // TODO(enga): Investigate removing Member<GPUDevice>.
+ GetProcs().deviceReference(device_handle_);
+ }
+
+ ~DawnObject() override {
+ // Note: The device is released last because all child objects must be
+ // destroyed first.
+ (GetProcs().*WGPUReleaseFn<Handle>::fn)(handle_);
+ GetProcs().deviceRelease(device_handle_);
+ }
Handle GetHandle() const { return handle_; }
private:
Handle const handle_;
+ WGPUDevice device_handle_;
};
template <>
-class DawnObject<WGPUDevice> : public DeviceTreeObject {
+class DawnObject<WGPUDevice> : public DawnObjectBase {
public:
DawnObject(scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id,
WGPUDevice handle)
- : DeviceTreeObject(base::MakeRefCounted<DawnDeviceClientSerializerHolder>(
- std::move(dawn_control_client),
- device_client_id)),
- handle_(handle) {}
+ : DawnObjectBase(dawn_control_client), handle_(handle) {}
+ ~DawnObject() { GetProcs().deviceRelease(handle_); }
WGPUDevice GetHandle() const { return handle_; }
- const scoped_refptr<DawnDeviceClientSerializerHolder>&
- GetDeviceClientSerializerHolder() const {
- return device_client_serializer_holder_;
- }
-
private:
WGPUDevice const handle_;
};
} // namespace blink
+#undef DAWN_OBJECTS
+
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_OBJECT_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
index c74039a344d..1ed933f92c6 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_request_adapter_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/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
@@ -81,17 +82,27 @@ std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProvider(
} // anonymous namespace
// static
-GPU* GPU::Create(ExecutionContext& execution_context) {
- return MakeGarbageCollected<GPU>(execution_context);
+const char GPU::kSupplementName[] = "GPU";
+
+// static
+GPU* GPU::gpu(NavigatorBase& navigator) {
+ GPU* gpu = Supplement<NavigatorBase>::From<GPU>(navigator);
+ if (!gpu) {
+ gpu = MakeGarbageCollected<GPU>(navigator);
+ ProvideTo(navigator, gpu);
+ }
+ return gpu;
}
-GPU::GPU(ExecutionContext& execution_context)
- : ExecutionContextLifecycleObserver(&execution_context) {}
+GPU::GPU(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()) {}
GPU::~GPU() = default;
void GPU::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
@@ -147,8 +158,8 @@ void GPU::RecordAdapterForIdentifiability(
IdentifiableTokenBuilder output_builder;
if (adapter) {
output_builder.AddToken(IdentifiabilityBenignStringToken(adapter->name()));
- for (const auto& extension : adapter->extensions(script_state)) {
- output_builder.AddToken(IdentifiabilityBenignStringToken(extension));
+ for (const auto& feature : adapter->features()) {
+ output_builder.AddToken(IdentifiabilityBenignStringToken(feature));
}
}
@@ -173,8 +184,7 @@ ScriptPromise GPU::requestAdapter(ScriptState* script_state,
// 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"));
+ resolver->Resolve(v8::Null(script_state->GetIsolate()));
return promise;
} else {
// Make a new DawnControlClientHolder with the context provider we just
@@ -193,14 +203,11 @@ ScriptPromise GPU::requestAdapter(ScriptState* script_state,
power_preference = gpu::webgpu::PowerPreference::kLowPower;
}
- if (!dawn_control_client_->GetInterface()->RequestAdapterAsync(
- power_preference,
- WTF::Bind(&GPU::OnRequestAdapterCallback, WrapPersistent(this),
- WrapPersistent(script_state), WrapPersistent(options),
- WrapPersistent(resolver)))) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kOperationError, "Fail to request GPUAdapter"));
- }
+ dawn_control_client_->GetInterface()->RequestAdapterAsync(
+ power_preference,
+ WTF::Bind(&GPU::OnRequestAdapterCallback, WrapPersistent(this),
+ WrapPersistent(script_state), WrapPersistent(options),
+ WrapPersistent(resolver)));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
index 416dd776f14..abdbd28995a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
struct WGPUDeviceProperties;
@@ -17,17 +18,23 @@ namespace blink {
class GPUAdapter;
class GPURequestAdapterOptions;
+class NavigatorBase;
class ScriptPromiseResolver;
class ScriptState;
class DawnControlClientHolder;
class GPU final : public ScriptWrappable,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- static GPU* Create(ExecutionContext& execution_context);
- explicit GPU(ExecutionContext& execution_context);
+ static const char kSupplementName[];
+
+ // Getter for navigator.gpu
+ static GPU* gpu(NavigatorBase&);
+
+ explicit GPU(NavigatorBase&);
~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 c633c5617a5..e2651f30170 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_request_adapter_options.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -19,20 +20,26 @@ namespace {
WGPUDeviceProperties AsDawnType(const GPUDeviceDescriptor* descriptor) {
DCHECK_NE(nullptr, descriptor);
- HashSet<String> extension_set;
- for (auto& extension : descriptor->extensions())
- extension_set.insert(extension);
+ const Vector<String>& feature_names = descriptor->hasExtensions()
+ ? descriptor->extensions()
+ : // Deprecated path
+ descriptor->nonGuaranteedFeatures();
+
+ HashSet<String> feature_set;
+ for (auto& feature : feature_names)
+ feature_set.insert(feature);
WGPUDeviceProperties requested_device_properties = {};
- // TODO(crbug.com/1048603): We should validate that the extension_set is a
- // subset of the adapter's extension set.
+ // TODO(crbug.com/1048603): We should validate that the feature_set is a
+ // subset of the adapter's feature set.
requested_device_properties.textureCompressionBC =
- extension_set.Contains("texture-compression-bc") ||
- extension_set.Contains("textureCompressionBC");
+ feature_set.Contains("texture-compression-bc");
requested_device_properties.shaderFloat16 =
- extension_set.Contains("shader-float16");
+ feature_set.Contains("shader-float16");
+ requested_device_properties.pipelineStatisticsQuery =
+ feature_set.Contains("pipeline-statistics-query");
requested_device_properties.timestampQuery =
- extension_set.Contains("timestamp-query");
+ feature_set.Contains("timestamp-query");
return requested_device_properties;
}
@@ -47,26 +54,53 @@ GPUAdapter::GPUAdapter(
name_(name),
adapter_service_id_(adapter_service_id),
adapter_properties_(properties) {
- InitializeExtensionNameList();
+ InitializeFeatureNameList();
+}
+
+void GPUAdapter::AddConsoleWarning(ExecutionContext* execution_context,
+ const char* message) {
+ if (execution_context && allowed_console_warnings_remaining_ > 0) {
+ auto* console_message = MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kRendering,
+ mojom::blink::ConsoleMessageLevel::kWarning, message);
+ execution_context->AddConsoleMessage(console_message);
+
+ allowed_console_warnings_remaining_--;
+ if (allowed_console_warnings_remaining_ == 0) {
+ auto* final_message = MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kRendering,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "WebGPU: too many warnings, no more warnings will be reported to the "
+ "console for this GPUAdapter.");
+ execution_context->AddConsoleMessage(final_message);
+ }
+ }
}
const String& GPUAdapter::name() const {
return name_;
}
-Vector<String> GPUAdapter::extensions(ScriptState* script_state) const {
- return extension_name_list_;
+Vector<String> GPUAdapter::features() const {
+ return feature_name_list_;
+}
+
+Vector<String> GPUAdapter::extensions(ExecutionContext* execution_context) {
+ AddConsoleWarning(
+ execution_context,
+ "The extensions attribute has been deprecated in favor of the features "
+ "attribute, and will soon be removed.");
+ return feature_name_list_;
}
void GPUAdapter::OnRequestDeviceCallback(ScriptPromiseResolver* resolver,
const GPUDeviceDescriptor* descriptor,
- bool is_request_device_success,
- uint64_t device_client_id) {
- if (is_request_device_success) {
+ WGPUDevice dawn_device) {
+ if (dawn_device) {
ExecutionContext* execution_context = resolver->GetExecutionContext();
- auto* device = MakeGarbageCollected<GPUDevice>(
- execution_context, GetDawnControlClient(), this, device_client_id,
- descriptor);
+ auto* device = MakeGarbageCollected<GPUDevice>(execution_context,
+ GetDawnControlClient(), this,
+ dawn_device, descriptor);
resolver->Resolve(device);
ukm::builders::ClientRenderingAPI(execution_context->UkmSourceID())
.SetGPUDevice(static_cast<int>(true))
@@ -78,34 +112,41 @@ void GPUAdapter::OnRequestDeviceCallback(ScriptPromiseResolver* resolver,
}
}
-void GPUAdapter::InitializeExtensionNameList() {
- DCHECK(extension_name_list_.IsEmpty());
+void GPUAdapter::InitializeFeatureNameList() {
+ DCHECK(feature_name_list_.IsEmpty());
if (adapter_properties_.textureCompressionBC) {
- extension_name_list_.emplace_back("texture-compression-bc");
- extension_name_list_.emplace_back("textureCompressionBC");
+ feature_name_list_.emplace_back("texture-compression-bc");
}
if (adapter_properties_.shaderFloat16) {
- extension_name_list_.emplace_back("shader-float16");
+ feature_name_list_.emplace_back("shader-float16");
+ }
+ if (adapter_properties_.pipelineStatisticsQuery) {
+ feature_name_list_.emplace_back("pipeline-statistics-query");
}
if (adapter_properties_.timestampQuery) {
- extension_name_list_.emplace_back("timestamp-query");
+ feature_name_list_.emplace_back("timestamp-query");
}
}
ScriptPromise GPUAdapter::requestDevice(ScriptState* script_state,
- const GPUDeviceDescriptor* descriptor) {
+ GPUDeviceDescriptor* descriptor) {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
+ if (descriptor->hasExtensions()) {
+ AddConsoleWarning(
+ ExecutionContext::From(script_state),
+ "Specifying extensions when requesting a GPUDevice is deprecated in "
+ "favor of specifying nonGuaranteedFeatures, and will soon be removed.");
+ descriptor->setNonGuaranteedFeatures(descriptor->extensions());
+ }
+
WGPUDeviceProperties requested_device_properties = AsDawnType(descriptor);
- if (!GetInterface()->RequestDeviceAsync(
- adapter_service_id_, requested_device_properties,
- WTF::Bind(&GPUAdapter::OnRequestDeviceCallback, WrapPersistent(this),
- WrapPersistent(resolver), WrapPersistent(descriptor)))) {
- resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kOperationError, "Unknown error creating GPUDevice"));
- }
+ GetInterface()->RequestDeviceAsync(
+ adapter_service_id_, requested_device_properties,
+ WTF::Bind(&GPUAdapter::OnRequestDeviceCallback, WrapPersistent(this),
+ WrapPersistent(resolver), WrapPersistent(descriptor)));
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
index 991e911b572..e6f80f6f7da 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
@@ -28,22 +28,32 @@ class GPUAdapter final : public ScriptWrappable, public DawnObjectBase {
scoped_refptr<DawnControlClientHolder> dawn_control_client);
const String& name() const;
- Vector<String> extensions(ScriptState* script_state) const;
+ Vector<String> features() const;
+ Vector<String> extensions(ExecutionContext* execution_context);
ScriptPromise requestDevice(ScriptState* script_state,
- const GPUDeviceDescriptor* descriptor);
+ GPUDeviceDescriptor* descriptor);
private:
void OnRequestDeviceCallback(ScriptPromiseResolver* resolver,
const GPUDeviceDescriptor* descriptor,
- bool is_request_device_success,
- uint64_t device_client_id);
- void InitializeExtensionNameList();
+ WGPUDevice dawn_device);
+ void InitializeFeatureNameList();
+
+ // Console warnings should generally be attributed to a GPUDevice, but in
+ // cases where there is no device warnings can be surfaced here. It's expected
+ // that very few warning will need to be shown for a given adapter, and as a
+ // result the maximum allowed warnings is lower than the per-device count.
+ void AddConsoleWarning(ExecutionContext* execution_context,
+ const char* message);
String name_;
uint32_t adapter_service_id_;
WGPUDeviceProperties adapter_properties_;
- Vector<String> extension_name_list_;
+ Vector<String> feature_name_list_;
+
+ static constexpr int kMaxAllowedConsoleWarnings = 50;
+ int allowed_console_warnings_remaining_ = kMaxAllowedConsoleWarnings;
DISALLOW_COPY_AND_ASSIGN(GPUAdapter);
};
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 16b2ead0834..d8669fa2de2 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -4,11 +4,10 @@
// https://gpuweb.github.io/gpuweb/
-enum GPUExtensionName {
+enum GPUFeatureName {
+ "pipeline-statistics-query",
"texture-compression-bc",
"timestamp-query",
- // Non-standard extension name string. Remove after a transition period.
- "textureCompressionBC",
"shader-float16"
};
@@ -16,7 +15,9 @@ enum GPUExtensionName {
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUAdapter {
[HighEntropy=Direct, MeasureAs=GPUAdapter_Name] readonly attribute DOMString name;
- [CallWith=ScriptState, SameObject] readonly attribute FrozenArray<GPUExtensionName> extensions;
+ [SameObject] readonly attribute FrozenArray<GPUFeatureName> features;
+ // Deprecated
+ [CallWith=ExecutionContext, SameObject] readonly attribute FrozenArray<GPUFeatureName> extensions;
[CallWith=ScriptState] Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
index 0aa8ed69e6f..c329580b7dd 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
@@ -69,19 +69,14 @@ GPUBindGroup* GPUBindGroup::Create(GPUDevice* device,
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUBindGroup>(
+ GPUBindGroup* bind_group = MakeGarbageCollected<GPUBindGroup>(
device, device->GetProcs().deviceCreateBindGroup(device->GetHandle(),
&dawn_desc));
+ bind_group->setLabel(webgpu_desc->label());
+ return bind_group;
}
GPUBindGroup::GPUBindGroup(GPUDevice* device, WGPUBindGroup bind_group)
: DawnObject<WGPUBindGroup>(device, bind_group) {}
-GPUBindGroup::~GPUBindGroup() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().bindGroupRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.h
index 71cca96ca4f..0032b3fe25b 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.h
@@ -20,7 +20,6 @@ class GPUBindGroup : public DawnObject<WGPUBindGroup> {
const GPUBindGroupDescriptor* webgpu_desc,
ExceptionState& exception_state);
explicit GPUBindGroup(GPUDevice* device, WGPUBindGroup bind_group);
- ~GPUBindGroup() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUBindGroup);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
index dbb19a6528d..8f6ea191fe6 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUBindGroup {
};
+GPUBindGroup includes GPUObjectBase;
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 301029616a4..925b16edba2 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
@@ -6,6 +6,10 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_entry.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_layout.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_layout.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_storage_texture_binding_layout.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_binding_layout.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -20,30 +24,65 @@ WGPUBindGroupLayoutEntry AsDawnType(
dawn_binding.binding = webgpu_binding->binding();
dawn_binding.visibility =
AsDawnEnum<WGPUShaderStage>(webgpu_binding->visibility());
- dawn_binding.type = AsDawnEnum<WGPUBindingType>(webgpu_binding->type());
- dawn_binding.hasDynamicOffset = webgpu_binding->hasDynamicOffset();
+ if (webgpu_binding->hasBuffer()) {
+ dawn_binding.buffer.type =
+ AsDawnEnum<WGPUBufferBindingType>(webgpu_binding->buffer()->type());
+ dawn_binding.buffer.hasDynamicOffset =
+ webgpu_binding->buffer()->hasDynamicOffset();
+ dawn_binding.buffer.minBindingSize =
+ webgpu_binding->buffer()->minBindingSize();
+ }
- dawn_binding.minBufferBindingSize =
- webgpu_binding->hasMinBufferBindingSize()
- ? webgpu_binding->minBufferBindingSize()
- : 0;
+ if (webgpu_binding->hasSampler()) {
+ dawn_binding.sampler.type =
+ AsDawnEnum<WGPUSamplerBindingType>(webgpu_binding->sampler()->type());
+ }
- dawn_binding.viewDimension =
- AsDawnEnum<WGPUTextureViewDimension>(webgpu_binding->viewDimension());
+ if (webgpu_binding->hasTexture()) {
+ dawn_binding.texture.sampleType = AsDawnEnum<WGPUTextureSampleType>(
+ webgpu_binding->texture()->sampleType());
+ dawn_binding.texture.viewDimension = AsDawnEnum<WGPUTextureViewDimension>(
+ webgpu_binding->texture()->viewDimension());
+ dawn_binding.texture.multisampled =
+ webgpu_binding->texture()->multisampled();
+ }
- dawn_binding.textureComponentType = AsDawnEnum<WGPUTextureComponentType>(
- webgpu_binding->textureComponentType());
- dawn_binding.multisampled = webgpu_binding->multisampled();
+ if (webgpu_binding->hasStorageTexture()) {
+ dawn_binding.storageTexture.access = AsDawnEnum<WGPUStorageTextureAccess>(
+ webgpu_binding->storageTexture()->access());
+ dawn_binding.storageTexture.format = AsDawnEnum<WGPUTextureFormat>(
+ webgpu_binding->storageTexture()->format());
+ dawn_binding.storageTexture.viewDimension =
+ AsDawnEnum<WGPUTextureViewDimension>(
+ webgpu_binding->storageTexture()->viewDimension());
+ }
- if (dawn_binding.multisampled) {
+ // Deprecated values
+ if (webgpu_binding->hasType()) {
device->AddConsoleWarning(
- "Creating a GPUBindGroupLayoutEntry with entry.multisampled = true is "
- "deprecated: set entry.type = \"multisampled-texture\" instead.");
- }
+ "The format of GPUBindGroupLayoutEntry has changed, and will soon "
+ "require the buffer, sampler, texture, or storageTexture members be "
+ "set rather than setting type, etc. on the entry directly.");
+
+ dawn_binding.type = AsDawnEnum<WGPUBindingType>(webgpu_binding->type());
+
+ dawn_binding.hasDynamicOffset = webgpu_binding->hasDynamicOffset();
- dawn_binding.storageTextureFormat =
- AsDawnEnum<WGPUTextureFormat>(webgpu_binding->storageTextureFormat());
+ dawn_binding.minBufferBindingSize =
+ webgpu_binding->hasMinBufferBindingSize()
+ ? webgpu_binding->minBufferBindingSize()
+ : 0;
+
+ dawn_binding.viewDimension =
+ AsDawnEnum<WGPUTextureViewDimension>(webgpu_binding->viewDimension());
+
+ dawn_binding.textureComponentType = AsDawnEnum<WGPUTextureComponentType>(
+ webgpu_binding->textureComponentType());
+
+ dawn_binding.storageTextureFormat =
+ AsDawnEnum<WGPUTextureFormat>(webgpu_binding->storageTextureFormat());
+ }
return dawn_binding;
}
@@ -86,20 +125,15 @@ GPUBindGroupLayout* GPUBindGroupLayout::Create(
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUBindGroupLayout>(
+ GPUBindGroupLayout* layout = MakeGarbageCollected<GPUBindGroupLayout>(
device, device->GetProcs().deviceCreateBindGroupLayout(
device->GetHandle(), &dawn_desc));
+ layout->setLabel(webgpu_desc->label());
+ return layout;
}
GPUBindGroupLayout::GPUBindGroupLayout(GPUDevice* device,
WGPUBindGroupLayout bind_group_layout)
: DawnObject<WGPUBindGroupLayout>(device, bind_group_layout) {}
-GPUBindGroupLayout::~GPUBindGroupLayout() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().bindGroupLayoutRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h
index 60982bdc1a1..aeb9b9f0fe7 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h
@@ -22,7 +22,6 @@ class GPUBindGroupLayout : public DawnObject<WGPUBindGroupLayout> {
ExceptionState& exception_state);
explicit GPUBindGroupLayout(GPUDevice* device,
WGPUBindGroupLayout bind_group_layout);
- ~GPUBindGroupLayout() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUBindGroupLayout);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
index 20dafb87e2e..470552ffa87 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUBindGroupLayout {
};
+GPUBindGroupLayout includes GPUObjectBase;
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 cb29531c4e0..1cbd37df7db 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
@@ -1,13 +1,16 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// https://gpuweb.github.io/gpuweb/
dictionary GPUBindGroupLayoutEntry {
required GPUIndex32 binding;
required GPUShaderStageFlags visibility;
- required GPUBindingType type;
+
+ GPUBufferBindingLayout buffer;
+ GPUSamplerBindingLayout sampler;
+ GPUTextureBindingLayout texture;
+ GPUStorageTextureBindingLayout storageTexture;
+
+ // Deprecated BindGroupLayout members.
+ GPUBindingType type;
boolean hasDynamicOffset = false;
@@ -16,7 +19,6 @@ dictionary GPUBindGroupLayoutEntry {
GPUTextureViewDimension viewDimension = "2d";
GPUTextureComponentType textureComponentType = "float";
- boolean multisampled = false;
GPUTextureFormat storageTextureFormat;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.idl
deleted file mode 100644
index fd955ac5082..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.idl
+++ /dev/null
@@ -1,35 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUBlendDescriptor {
- GPUBlendFactor srcFactor = "one";
- GPUBlendFactor dstFactor = "zero";
- GPUBlendOperation operation = "add";
-};
-
-enum GPUBlendFactor {
- "zero",
- "one",
- "src-color",
- "one-minus-src-color",
- "src-alpha",
- "one-minus-src-alpha",
- "dst-color",
- "one-minus-dst-color",
- "dst-alpha",
- "one-minus-dst-alpha",
- "src-alpha-saturated",
- "blend-color",
- "one-minus-blend-color"
-};
-
-enum GPUBlendOperation {
- "add",
- "subtract",
- "reverse-subtract",
- "min",
- "max"
-};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl
new file mode 100644
index 00000000000..787ef912ffb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUBlendState {
+ GPUBlendFactor srcFactor = "one";
+ GPUBlendFactor dstFactor = "zero";
+ GPUBlendOperation operation = "add";
+};
+
+enum GPUBlendFactor {
+ "zero",
+ "one",
+ "src-color",
+ "one-minus-src-color",
+ "src-alpha",
+ "one-minus-src-alpha",
+ "dst-color",
+ "one-minus-dst-color",
+ "dst-alpha",
+ "one-minus-dst-alpha",
+ "src-alpha-saturated",
+ "blend-color",
+ "one-minus-blend-color"
+};
+
+enum GPUBlendOperation {
+ "add",
+ "subtract",
+ "reverse-subtract",
+ "min",
+ "max"
+};
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 0591edd43ef..c73982b6e0b 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -68,9 +68,11 @@ GPUBuffer* GPUBuffer::Create(GPUDevice* device,
dawn_desc.size = std::min(dawn_desc.size, kGuaranteedBufferOOMSize);
}
- return MakeGarbageCollected<GPUBuffer>(
+ GPUBuffer* buffer = MakeGarbageCollected<GPUBuffer>(
device, dawn_desc.size,
device->GetProcs().deviceCreateBuffer(device->GetHandle(), &dawn_desc));
+ buffer->setLabel(webgpu_desc->label());
+ return buffer;
}
GPUBuffer::GPUBuffer(GPUDevice* device,
@@ -79,13 +81,6 @@ GPUBuffer::GPUBuffer(GPUDevice* device,
: DawnObject<WGPUBuffer>(device, buffer), size_(size) {
}
-GPUBuffer::~GPUBuffer() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().bufferRelease(GetHandle());
-}
-
void GPUBuffer::Trace(Visitor* visitor) const {
visitor->Trace(mapped_array_buffers_);
DawnObject<WGPUBuffer>::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
index 23357fc4369..1dd4b86f00a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.h
@@ -27,7 +27,6 @@ class GPUBuffer : public DawnObject<WGPUBuffer> {
explicit GPUBuffer(GPUDevice* device,
uint64_t size,
WGPUBuffer buffer);
- ~GPUBuffer() override;
void Trace(Visitor* visitor) const override;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
index 2880ea35afe..eefd25d7146 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
@@ -16,3 +16,4 @@
[CallWith=ScriptState] void unmap();
[CallWith=ScriptState] void destroy();
};
+GPUBuffer includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_binding_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_binding_layout.idl
new file mode 100644
index 00000000000..b87f2eb2c3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_binding_layout.idl
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUBufferBindingLayout {
+ GPUBufferBindingType type = "uniform";
+ boolean hasDynamicOffset = false;
+ GPUSize64 minBindingSize = 0;
+};
+
+enum GPUBufferBindingType {
+ "uniform",
+ "storage",
+ "read-only-storage",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_copy_view.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_copy_view.idl
deleted file mode 100644
index 94e76c1f3a0..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer_copy_view.idl
+++ /dev/null
@@ -1,9 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUBufferCopyView : GPUTextureDataLayout {
- required GPUBuffer buffer;
-};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index bfacc2148b4..50188762c2f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/rendering_context.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_swap_chain_descriptor.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
namespace blink {
@@ -125,20 +126,38 @@ GPUSwapChain* GPUCanvasContext::configureSwapChain(
swapchain_ = MakeGarbageCollected<GPUSwapChain>(
this, descriptor->device(), usage, format, filter_quality_);
+ swapchain_->CcLayer()->SetContentsOpaque(!CreationAttributes().alpha);
+ swapchain_->setLabel(descriptor->label());
+
+ // If we don't notify the host that something has changed it may never check
+ // for the new cc::Layer.
+ Host()->SetNeedsCompositingUpdate();
+
return swapchain_;
}
ScriptPromise GPUCanvasContext::getSwapChainPreferredFormat(
ScriptState* script_state,
- const GPUDevice* device) {
+ GPUDevice* device) {
ScriptPromiseResolver* resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
+ device->AddConsoleWarning(
+ "Passing a GPUDevice to getSwapChainPreferredFormat is deprecated. "
+ "Pass a GPUAdapter instead, and update the calling code to expect a "
+ "GPUTextureFormat to be retured instead of a Promise.");
+
// TODO(crbug.com/1007166): Return actual preferred format for the swap chain.
resolver->Resolve("bgra8unorm");
return promise;
}
+String GPUCanvasContext::getSwapChainPreferredFormat(
+ const GPUAdapter* adapter) {
+ // TODO(crbug.com/1007166): Return actual preferred format for the swap chain.
+ return "bgra8unorm";
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
index 788635a2aff..c53856e85d1 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -13,6 +13,7 @@
namespace blink {
+class GPUAdapter;
class GPUSwapChain;
class GPUSwapChainDescriptor;
@@ -63,7 +64,8 @@ class GPUCanvasContext : public CanvasRenderingContext {
GPUSwapChain* configureSwapChain(const GPUSwapChainDescriptor* descriptor,
ExceptionState&);
ScriptPromise getSwapChainPreferredFormat(ScriptState* script_state,
- const GPUDevice* device);
+ GPUDevice* device);
+ String getSwapChainPreferredFormat(const GPUAdapter* adapter);
private:
DISALLOW_COPY_AND_ASSIGN(GPUCanvasContext);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
index 431b1efad7c..f28980aaaec 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
@@ -10,4 +10,5 @@
[RaisesException] GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
[CallWith=ScriptState] Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
+ GPUTextureFormat getSwapChainPreferredFormat(GPUAdapter adapter);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl
deleted file mode 100644
index 07e114c7cda..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl
+++ /dev/null
@@ -1,13 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUColorStateDescriptor {
- required GPUTextureFormat format;
-
- GPUBlendDescriptor alphaBlend = {};
- GPUBlendDescriptor colorBlend = {};
- GPUColorWriteFlags writeMask = 15; // GPUColorWrite.ALL
-};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl
new file mode 100644
index 00000000000..7e18301980f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl
@@ -0,0 +1,13 @@
+// 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://gpuweb.github.io/gpuweb/
+
+dictionary GPUColorTargetState {
+ required GPUTextureFormat format;
+
+ GPUBlendState alphaBlend = {};
+ GPUBlendState colorBlend = {};
+ GPUColorWriteFlags writeMask = 15; // GPUColorWrite.ALL
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.cc
index c781a899d5f..d246e3a51c8 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.cc
@@ -12,11 +12,4 @@ GPUCommandBuffer::GPUCommandBuffer(GPUDevice* device,
WGPUCommandBuffer command_buffer)
: DawnObject<WGPUCommandBuffer>(device, command_buffer) {}
-GPUCommandBuffer::~GPUCommandBuffer() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().commandBufferRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h
index efbbfa525cf..2c2df6a1c5b 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h
@@ -15,7 +15,6 @@ class GPUCommandBuffer : public DawnObject<WGPUCommandBuffer> {
public:
explicit GPUCommandBuffer(GPUDevice* device,
WGPUCommandBuffer command_buffer);
- ~GPUCommandBuffer() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUCommandBuffer);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
index 75b5b25e5d6..7de4d14d9c4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUCommandBuffer {
};
+GPUCommandBuffer includes GPUObjectBase;
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 44be1715bef..87c0f977961 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
@@ -7,14 +7,14 @@
#include "third_party/blink/renderer/bindings/modules/v8/double_sequence_or_gpu_color_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/unsigned_long_enforce_range_sequence_or_gpu_extent_3d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/unsigned_long_enforce_range_sequence_or_gpu_origin_3d_dict.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_copy_view.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_buffer_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_encoder_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pass_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_buffer.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_texture.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pass_color_attachment_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pass_depth_stencil_attachment_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pass_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_copy_view.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_buffer.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h"
@@ -109,8 +109,8 @@ WGPURenderPassDepthStencilAttachmentDescriptor AsDawnType(
}
WGPUBufferCopyView ValidateAndConvertBufferCopyView(
- const GPUBufferCopyView* webgpu_view,
- ExceptionState& exception_state) {
+ const GPUImageCopyBuffer* webgpu_view,
+ const char** error) {
DCHECK(webgpu_view);
DCHECK(webgpu_view->buffer());
@@ -118,17 +118,7 @@ WGPUBufferCopyView ValidateAndConvertBufferCopyView(
dawn_view.nextInChain = nullptr;
dawn_view.buffer = webgpu_view->buffer()->GetHandle();
- {
- const char* error =
- ValidateTextureDataLayout(webgpu_view, &dawn_view.layout);
- if (error) {
- // TODO(crbug.com/dawn/566): This error needs to be injected into the
- // encoder, instead of thrown as an exception.
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- error);
- }
- }
-
+ *error = ValidateTextureDataLayout(webgpu_view, &dawn_view.layout);
return dawn_view;
}
@@ -166,22 +156,17 @@ GPUCommandEncoder* GPUCommandEncoder::Create(
dawn_desc_ptr = &dawn_desc;
}
- return MakeGarbageCollected<GPUCommandEncoder>(
+ GPUCommandEncoder* encoder = MakeGarbageCollected<GPUCommandEncoder>(
device, device->GetProcs().deviceCreateCommandEncoder(device->GetHandle(),
dawn_desc_ptr));
+ encoder->setLabel(webgpu_desc->label());
+ return encoder;
}
GPUCommandEncoder::GPUCommandEncoder(GPUDevice* device,
WGPUCommandEncoder command_encoder)
: DawnObject<WGPUCommandEncoder>(device, command_encoder) {}
-GPUCommandEncoder::~GPUCommandEncoder() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().commandEncoderRelease(GetHandle());
-}
-
GPURenderPassEncoder* GPUCommandEncoder::beginRenderPass(
const GPURenderPassDescriptor* descriptor,
ExceptionState& exception_state) {
@@ -228,9 +213,17 @@ GPURenderPassEncoder* GPUCommandEncoder::beginRenderPass(
dawn_desc.depthStencilAttachment = nullptr;
}
- return MakeGarbageCollected<GPURenderPassEncoder>(
+ if (descriptor->hasOcclusionQuerySet()) {
+ dawn_desc.occlusionQuerySet = AsDawnType(descriptor->occlusionQuerySet());
+ } else {
+ dawn_desc.occlusionQuerySet = nullptr;
+ }
+
+ GPURenderPassEncoder* encoder = MakeGarbageCollected<GPURenderPassEncoder>(
device_,
GetProcs().commandEncoderBeginRenderPass(GetHandle(), &dawn_desc));
+ encoder->setLabel(descriptor->label());
+ return encoder;
}
GPUComputePassEncoder* GPUCommandEncoder::beginComputePass(
@@ -242,9 +235,11 @@ GPUComputePassEncoder* GPUCommandEncoder::beginComputePass(
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUComputePassEncoder>(
+ GPUComputePassEncoder* encoder = MakeGarbageCollected<GPUComputePassEncoder>(
device_,
GetProcs().commandEncoderBeginComputePass(GetHandle(), &dawn_desc));
+ encoder->setLabel(descriptor->label());
+ return encoder;
}
void GPUCommandEncoder::copyBufferToBuffer(GPUBuffer* src,
@@ -260,16 +255,17 @@ void GPUCommandEncoder::copyBufferToBuffer(GPUBuffer* src,
}
void GPUCommandEncoder::copyBufferToTexture(
- GPUBufferCopyView* source,
- GPUTextureCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state) {
- WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
+ GPUImageCopyBuffer* source,
+ GPUImageCopyTexture* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
+ WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size, device_);
WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_);
+ const char* error = nullptr;
WGPUBufferCopyView dawn_source =
- ValidateAndConvertBufferCopyView(source, exception_state);
- if (exception_state.HadException()) {
+ ValidateAndConvertBufferCopyView(source, &error);
+ if (error) {
+ GetProcs().commandEncoderInjectValidationError(GetHandle(), error);
return;
}
@@ -278,16 +274,17 @@ void GPUCommandEncoder::copyBufferToTexture(
}
void GPUCommandEncoder::copyTextureToBuffer(
- GPUTextureCopyView* source,
- GPUBufferCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state) {
- WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
+ GPUImageCopyTexture* source,
+ GPUImageCopyBuffer* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
+ WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size, device_);
WGPUTextureCopyView dawn_source = AsDawnType(source, device_);
+ const char* error = nullptr;
WGPUBufferCopyView dawn_destination =
- ValidateAndConvertBufferCopyView(destination, exception_state);
- if (exception_state.HadException()) {
+ ValidateAndConvertBufferCopyView(destination, &error);
+ if (error) {
+ GetProcs().commandEncoderInjectValidationError(GetHandle(), error);
return;
}
@@ -296,13 +293,12 @@ void GPUCommandEncoder::copyTextureToBuffer(
}
void GPUCommandEncoder::copyTextureToTexture(
- GPUTextureCopyView* source,
- GPUTextureCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state) {
+ GPUImageCopyTexture* source,
+ GPUImageCopyTexture* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
WGPUTextureCopyView dawn_source = AsDawnType(source, device_);
WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_);
- WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
+ WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size, device_);
GetProcs().commandEncoderCopyTextureToTexture(
GetHandle(), &dawn_source, &dawn_destination, &dawn_copy_size);
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 92d221ff16b..0cfa00466c3 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
@@ -12,7 +12,7 @@ namespace blink {
class ExceptionState;
class GPUBuffer;
-class GPUBufferCopyView;
+class GPUImageCopyBuffer;
class GPUCommandBuffer;
class GPUCommandBufferDescriptor;
class GPUCommandEncoderDescriptor;
@@ -21,7 +21,7 @@ class GPUComputePassEncoder;
class GPUQuerySet;
class GPURenderPassDescriptor;
class GPURenderPassEncoder;
-class GPUTextureCopyView;
+class GPUImageCopyTexture;
class UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict;
class GPUCommandEncoder : public DawnObject<WGPUCommandEncoder> {
@@ -33,7 +33,6 @@ class GPUCommandEncoder : public DawnObject<WGPUCommandEncoder> {
const GPUCommandEncoderDescriptor* webgpu_desc);
explicit GPUCommandEncoder(GPUDevice* device,
WGPUCommandEncoder command_encoder);
- ~GPUCommandEncoder() override;
// gpu_command_encoder.idl
GPURenderPassEncoder* beginRenderPass(
@@ -47,20 +46,17 @@ class GPUCommandEncoder : public DawnObject<WGPUCommandEncoder> {
uint64_t dst_offset,
uint64_t size);
void copyBufferToTexture(
- GPUBufferCopyView* source,
- GPUTextureCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state);
+ GPUImageCopyBuffer* source,
+ GPUImageCopyTexture* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
void copyTextureToBuffer(
- GPUTextureCopyView* source,
- GPUBufferCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state);
+ GPUImageCopyTexture* source,
+ GPUImageCopyBuffer* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
void copyTextureToTexture(
- GPUTextureCopyView* source,
- GPUTextureCopyView* destination,
- UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
- ExceptionState& exception_state);
+ GPUImageCopyTexture* source,
+ GPUImageCopyTexture* destination,
+ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
void pushDebugGroup(String groupLabel);
void popDebugGroup();
void insertDebugMarker(String markerLabel);
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 d054757ff76..b269ce7de3a 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
@@ -17,19 +17,19 @@
GPUSize64 dstOffset,
GPUSize64 size);
- [RaisesException] void copyBufferToTexture(
- GPUBufferCopyView source,
- GPUTextureCopyView destination,
+ void copyBufferToTexture(
+ GPUImageCopyBuffer source,
+ GPUImageCopyTexture destination,
GPUExtent3D copySize);
- [RaisesException] void copyTextureToBuffer(
- GPUTextureCopyView source,
- GPUBufferCopyView destination,
+ void copyTextureToBuffer(
+ GPUImageCopyTexture source,
+ GPUImageCopyBuffer destination,
GPUExtent3D copySize);
- [RaisesException] void copyTextureToTexture(
- GPUTextureCopyView source,
- GPUTextureCopyView destination,
+ void copyTextureToTexture(
+ GPUImageCopyTexture source,
+ GPUImageCopyTexture destination,
GPUExtent3D copySize);
void pushDebugGroup(USVString groupLabel);
@@ -47,3 +47,4 @@
GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
};
+GPUCommandEncoder includes GPUObjectBase;
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 7e4738d47b2..1b595b0b825 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
@@ -17,11 +17,10 @@ GPUComputePassEncoder::GPUComputePassEncoder(
WGPUComputePassEncoder compute_pass_encoder)
: DawnObject<WGPUComputePassEncoder>(device, compute_pass_encoder) {}
-GPUComputePassEncoder::~GPUComputePassEncoder() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().computePassEncoderRelease(GetHandle());
+void GPUComputePassEncoder::setBindGroup(uint32_t index,
+ GPUBindGroup* bindGroup) {
+ GetProcs().computePassEncoderSetBindGroup(GetHandle(), index,
+ bindGroup->GetHandle(), 0, nullptr);
}
void GPUComputePassEncoder::setBindGroup(
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 26cc4d92c57..31a9843e373 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
@@ -23,9 +23,9 @@ class GPUComputePassEncoder : public DawnObject<WGPUComputePassEncoder>,
public:
explicit GPUComputePassEncoder(GPUDevice* device,
WGPUComputePassEncoder compute_pass_encoder);
- ~GPUComputePassEncoder() override;
// gpu_compute_pass_encoder.idl
+ void setBindGroup(uint32_t index, GPUBindGroup* bindGroup);
void setBindGroup(uint32_t index,
GPUBindGroup* bindGroup,
const Vector<uint32_t>& dynamicOffsets);
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 858b075ae86..4a0d017bfd6 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
@@ -16,4 +16,5 @@
void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
void endPass();
};
+GPUComputePassEncoder includes GPUObjectBase;
GPUComputePassEncoder includes GPUProgrammablePassEncoder;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.cc
index 708ed3673fe..2cf4d015b76 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.cc
@@ -5,8 +5,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage_descriptor.h"
-#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
@@ -14,43 +13,53 @@
namespace blink {
-// static
-GPUComputePipeline* GPUComputePipeline::Create(
- GPUDevice* device,
- const GPUComputePipelineDescriptor* webgpu_desc) {
- DCHECK(device);
+WGPUComputePipelineDescriptor AsDawnType(
+ const GPUComputePipelineDescriptor* webgpu_desc,
+ std::string* label,
+ OwnedProgrammableStageDescriptor* computeStageDescriptor) {
DCHECK(webgpu_desc);
+ DCHECK(label);
+ DCHECK(computeStageDescriptor);
- std::string label;
WGPUComputePipelineDescriptor dawn_desc = {};
dawn_desc.nextInChain = nullptr;
if (webgpu_desc->hasLayout()) {
dawn_desc.layout = AsDawnType(webgpu_desc->layout());
}
if (webgpu_desc->hasLabel()) {
- label = webgpu_desc->label().Utf8();
- dawn_desc.label = label.c_str();
+ *label = webgpu_desc->label().Utf8();
+ dawn_desc.label = label->c_str();
}
- auto compute_stage = AsDawnType(webgpu_desc->computeStage());
- dawn_desc.computeStage = std::get<0>(compute_stage);
+ *computeStageDescriptor = AsDawnType(webgpu_desc->computeStage());
+ dawn_desc.computeStage = std::get<0>(*computeStageDescriptor);
+
+ return dawn_desc;
+}
+
+// static
+GPUComputePipeline* GPUComputePipeline::Create(
+ GPUDevice* device,
+ const GPUComputePipelineDescriptor* webgpu_desc) {
+ DCHECK(device);
+ DCHECK(webgpu_desc);
+
+ std::string label;
+ OwnedProgrammableStageDescriptor computeStageDescriptor;
+ WGPUComputePipelineDescriptor dawn_desc =
+ AsDawnType(webgpu_desc, &label, &computeStageDescriptor);
- return MakeGarbageCollected<GPUComputePipeline>(
+ GPUComputePipeline* pipeline = MakeGarbageCollected<GPUComputePipeline>(
device, device->GetProcs().deviceCreateComputePipeline(
device->GetHandle(), &dawn_desc));
+ pipeline->setLabel(webgpu_desc->label());
+ return pipeline;
}
GPUComputePipeline::GPUComputePipeline(GPUDevice* device,
WGPUComputePipeline compute_pipeline)
: DawnObject<WGPUComputePipeline>(device, compute_pipeline) {}
-GPUComputePipeline::~GPUComputePipeline() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().computePipelineRelease(GetHandle());
-}
-
GPUBindGroupLayout* GPUComputePipeline::getBindGroupLayout(uint32_t index) {
return MakeGarbageCollected<GPUBindGroupLayout>(
device_,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h
index c1fa63269a1..37aaf2c54b9 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_COMPUTE_PIPELINE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_COMPUTE_PIPELINE_H_
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
namespace blink {
@@ -12,6 +13,11 @@ namespace blink {
class GPUBindGroupLayout;
class GPUComputePipelineDescriptor;
+WGPUComputePipelineDescriptor AsDawnType(
+ const GPUComputePipelineDescriptor* webgpu_desc,
+ std::string* label,
+ OwnedProgrammableStageDescriptor* computeStageDescriptor);
+
class GPUComputePipeline : public DawnObject<WGPUComputePipeline> {
DEFINE_WRAPPERTYPEINFO();
@@ -21,7 +27,6 @@ class GPUComputePipeline : public DawnObject<WGPUComputePipeline> {
const GPUComputePipelineDescriptor* webgpu_desc);
explicit GPUComputePipeline(GPUDevice* device,
WGPUComputePipeline compute_pipeline);
- ~GPUComputePipeline() override;
GPUBindGroupLayout* getBindGroupLayout(uint32_t index);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
index 61cd206b786..49f28bc6b8f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
@@ -7,5 +7,6 @@
[
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUComputePipeline {
- GPUBindGroupLayout getBindGroupLayout(GPUIndex32 index);
};
+GPUComputePipeline includes GPUObjectBase;
+GPUComputePipeline includes GPUPipelineBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl
index 6d6d8fd23ea..ce59ee47f7d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl
@@ -5,5 +5,5 @@
// https://gpuweb.github.io/gpuweb/
dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
- required GPUProgrammableStageDescriptor computeStage;
+ required GPUProgrammableStage computeStage;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl
new file mode 100644
index 00000000000..ccd6711343d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl
@@ -0,0 +1,18 @@
+// 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://gpuweb.github.io/gpuweb/
+
+dictionary GPUDepthStencilState {
+ required GPUTextureFormat format;
+
+ boolean depthWriteEnabled = false;
+ GPUCompareFunction depthCompare = "always";
+
+ GPUStencilFaceState stencilFront = {};
+ GPUStencilFaceState stencilBack = {};
+
+ GPUStencilValue stencilReadMask = 0xFFFFFFFF;
+ GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl
deleted file mode 100644
index aedf8eb9157..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl
+++ /dev/null
@@ -1,18 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUDepthStencilStateDescriptor {
- required GPUTextureFormat format;
-
- boolean depthWriteEnabled = false;
- GPUCompareFunction depthCompare = "always";
-
- GPUStencilStateFaceDescriptor stencilFront = {};
- GPUStencilStateFaceDescriptor stencilBack = {};
-
- GPUStencilValue stencilReadMask = 0xFFFFFFFF;
- GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
-};
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 2b1f5d3dcba..315b0a90dca 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -7,8 +7,9 @@
#include "gpu/command_buffer/client/webgpu_interface.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_gpu_compute_pipeline_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_extension_name.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_feature_name.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_uncaptured_error_event_init.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -21,6 +22,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h"
#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_out_of_memory_error.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"
@@ -30,6 +32,8 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_shader_module.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_validation_error.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
@@ -52,17 +56,15 @@ Vector<String> ToStringVector(
GPUDevice::GPUDevice(ExecutionContext* execution_context,
scoped_refptr<DawnControlClientHolder> dawn_control_client,
GPUAdapter* adapter,
- uint64_t client_id,
+ WGPUDevice dawn_device,
const GPUDeviceDescriptor* descriptor)
: ExecutionContextClient(execution_context),
- DawnObject(dawn_control_client,
- client_id,
- dawn_control_client->GetInterface()->GetDevice(client_id)),
+ DawnObject(dawn_control_client, dawn_device),
adapter_(adapter),
#ifdef USE_BLINK_V8_BINDING_NEW_IDL_DICTIONARY
- extension_name_list_(ToStringVector(descriptor->extensions())),
+ feature_name_list_(ToStringVector(descriptor->nonGuaranteedFeatures())),
#else
- extension_name_list_(descriptor->extensions()),
+ feature_name_list_(descriptor->nonGuaranteedFeatures()),
#endif
queue_(MakeGarbageCollected<GPUQueue>(
this,
@@ -72,7 +74,7 @@ GPUDevice::GPUDevice(ExecutionContext* execution_context,
WrapWeakPersistent(this))),
lost_callback_(BindDawnCallback(&GPUDevice::OnDeviceLostError,
WrapWeakPersistent(this))) {
- DCHECK(dawn_control_client->GetInterface()->GetDevice(client_id));
+ DCHECK(dawn_device);
GetProcs().deviceSetUncapturedErrorCallback(
GetHandle(), error_callback_->UnboundRepeatingCallback(),
error_callback_->AsUserdata());
@@ -80,19 +82,7 @@ GPUDevice::GPUDevice(ExecutionContext* execution_context,
lost_callback_->UnboundCallback(),
lost_callback_->AsUserdata());
- if (extension_name_list_.Contains("textureCompressionBC")) {
- AddConsoleWarning(
- "The extension name 'textureCompressionBC' is deprecated: use "
- "'texture-compression-bc' instead");
- }
-}
-
-GPUDevice::~GPUDevice() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- queue_ = nullptr;
- GetProcs().deviceRelease(GetHandle());
+ setLabel(descriptor->label());
}
void GPUDevice::InjectError(WGPUErrorType type, const char* message) {
@@ -144,6 +134,12 @@ void GPUDevice::OnUncapturedError(WGPUErrorType errorType,
}
void GPUDevice::OnDeviceLostError(const char* message) {
+ // This function is called by a callback created by BindDawnCallback.
+ // Release the unique_ptr holding it since BindDawnCallback is self-deleting.
+ // This is stored as a unique_ptr because the lost callback may never be
+ // called.
+ lost_callback_.release();
+
AddConsoleWarning(message);
if (lost_property_->GetState() == LostProperty::kPending) {
@@ -152,19 +148,87 @@ void GPUDevice::OnDeviceLostError(const char* message) {
}
}
+void GPUDevice::OnCreateRenderPipelineAsyncCallback(
+ ScriptPromiseResolver* resolver,
+ WGPUCreatePipelineAsyncStatus status,
+ WGPURenderPipeline render_pipeline,
+ const char* message) {
+ switch (status) {
+ case WGPUCreatePipelineAsyncStatus_Success: {
+ resolver->Resolve(
+ MakeGarbageCollected<GPURenderPipeline>(this, render_pipeline));
+ break;
+ }
+
+ case WGPUCreatePipelineAsyncStatus_Error:
+ case WGPUCreatePipelineAsyncStatus_DeviceLost:
+ case WGPUCreatePipelineAsyncStatus_DeviceDestroyed:
+ case WGPUCreatePipelineAsyncStatus_Unknown: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError, message));
+ break;
+ }
+
+ default: {
+ NOTREACHED();
+ }
+ }
+}
+
+void GPUDevice::OnCreateComputePipelineAsyncCallback(
+ ScriptPromiseResolver* resolver,
+ WGPUCreatePipelineAsyncStatus status,
+ WGPUComputePipeline compute_pipeline,
+ const char* message) {
+ switch (status) {
+ case WGPUCreatePipelineAsyncStatus_Success: {
+ resolver->Resolve(
+ MakeGarbageCollected<GPUComputePipeline>(this, compute_pipeline));
+ break;
+ }
+
+ case WGPUCreatePipelineAsyncStatus_Error:
+ case WGPUCreatePipelineAsyncStatus_DeviceLost:
+ case WGPUCreatePipelineAsyncStatus_DeviceDestroyed:
+ case WGPUCreatePipelineAsyncStatus_Unknown: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError, message));
+ break;
+ }
+
+ default: {
+ NOTREACHED();
+ }
+ }
+}
+
GPUAdapter* GPUDevice::adapter() const {
return adapter_;
}
-Vector<String> GPUDevice::extensions() const {
- return extension_name_list_;
+Vector<String> GPUDevice::features() const {
+ return feature_name_list_;
+}
+
+Vector<String> GPUDevice::extensions() {
+ AddConsoleWarning(
+ "The extensions attribute has been deprecated in favor of the features "
+ "attribute, and will soon be removed.");
+ return feature_name_list_;
}
ScriptPromise GPUDevice::lost(ScriptState* script_state) {
return lost_property_->Promise(script_state->World());
}
+GPUQueue* GPUDevice::queue() {
+ return queue_;
+}
+
GPUQueue* GPUDevice::defaultQueue() {
+ AddConsoleWarning(
+ "The defaultQueue attribute has been deprecated in favor of the queue "
+ "attribute, and will soon be removed.");
return queue_;
}
@@ -177,6 +241,14 @@ GPUTexture* GPUDevice::createTexture(const GPUTextureDescriptor* descriptor,
return GPUTexture::Create(this, descriptor, exception_state);
}
+GPUTexture* GPUDevice::experimentalImportTexture(
+ HTMLVideoElement* video,
+ unsigned int usage_flags,
+ ExceptionState& exception_state) {
+ return GPUTexture::FromVideo(
+ this, video, static_cast<WGPUTextureUsage>(usage_flags), exception_state);
+}
+
GPUSampler* GPUDevice::createSampler(const GPUSamplerDescriptor* descriptor) {
return GPUSampler::Create(this, descriptor);
}
@@ -215,6 +287,77 @@ GPUComputePipeline* GPUDevice::createComputePipeline(
return GPUComputePipeline::Create(this, descriptor);
}
+ScriptPromise GPUDevice::createRenderPipelineAsync(
+ ScriptState* script_state,
+ const GPURenderPipelineDescriptor* descriptor) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ OwnedRenderPipelineDescriptor dawn_desc_info;
+ v8::Isolate* isolate = script_state->GetIsolate();
+ ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
+ "GPUVertexStateDescriptor");
+ ConvertToDawnType(isolate, descriptor, &dawn_desc_info, exception_state);
+ if (exception_state.HadException()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError,
+ "Error in parsing GPURenderPipelineDescriptor"));
+ } else {
+ auto* callback =
+ BindDawnCallback(&GPUDevice::OnCreateRenderPipelineAsyncCallback,
+ WrapPersistent(this), WrapPersistent(resolver));
+ GetProcs().deviceCreateRenderPipelineAsync(
+ GetHandle(), &dawn_desc_info.dawn_desc, callback->UnboundCallback(),
+ callback->AsUserdata());
+ }
+
+ // WebGPU guarantees that promises are resolved in finite time so we need to
+ // ensure commands are flushed.
+ EnsureFlush();
+ return promise;
+}
+
+ScriptPromise GPUDevice::createComputePipelineAsync(
+ ScriptState* script_state,
+ const GPUComputePipelineDescriptor* descriptor) {
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ std::string label;
+ OwnedProgrammableStageDescriptor computeStageDescriptor;
+ WGPUComputePipelineDescriptor dawn_desc =
+ AsDawnType(descriptor, &label, &computeStageDescriptor);
+
+ auto* callback =
+ BindDawnCallback(&GPUDevice::OnCreateComputePipelineAsyncCallback,
+ WrapPersistent(this), WrapPersistent(resolver));
+ GetProcs().deviceCreateComputePipelineAsync(GetHandle(), &dawn_desc,
+ callback->UnboundCallback(),
+ callback->AsUserdata());
+ // WebGPU guarantees that promises are resolved in finite time so we need to
+ // ensure commands are flushed.
+ EnsureFlush();
+ return promise;
+}
+
+ScriptPromise GPUDevice::createReadyRenderPipeline(
+ ScriptState* script_state,
+ const GPURenderPipelineDescriptor* descriptor) {
+ AddConsoleWarning(
+ "createReadyRenderPipeline is deprecated in favor of "
+ "createRenderPipelineAsync");
+ return createRenderPipelineAsync(script_state, descriptor);
+}
+
+ScriptPromise GPUDevice::createReadyComputePipeline(
+ ScriptState* script_state,
+ const GPUComputePipelineDescriptor* descriptor) {
+ AddConsoleWarning(
+ "createReadyComputePipeline is deprecated in favor of "
+ "createComputePipelineAsync");
+ return createComputePipelineAsync(script_state, descriptor);
+}
+
GPUCommandEncoder* GPUDevice::createCommandEncoder(
const GPUCommandEncoderDescriptor* descriptor) {
return GPUCommandEncoder::Create(this, descriptor);
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 904ec51f349..0dd29ab3397 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -17,6 +17,7 @@
namespace blink {
class ExecutionContext;
+class HTMLVideoElement;
class GPUAdapter;
class GPUAdapter;
class GPUBuffer;
@@ -58,22 +59,26 @@ class GPUDevice final : public EventTargetWithInlineData,
explicit GPUDevice(ExecutionContext* execution_context,
scoped_refptr<DawnControlClientHolder> dawn_control_client,
GPUAdapter* adapter,
- uint64_t client_id,
+ WGPUDevice dawn_device,
const GPUDeviceDescriptor* descriptor);
- ~GPUDevice() override;
void Trace(Visitor* visitor) const override;
// gpu_device.idl
GPUAdapter* adapter() const;
- Vector<String> extensions() const;
+ Vector<String> features() const;
+ Vector<String> extensions();
ScriptPromise lost(ScriptState* script_state);
+ GPUQueue* queue();
GPUQueue* defaultQueue();
GPUBuffer* createBuffer(const GPUBufferDescriptor* descriptor);
GPUTexture* createTexture(const GPUTextureDescriptor* descriptor,
ExceptionState& exception_state);
+ GPUTexture* experimentalImportTexture(HTMLVideoElement* video,
+ unsigned int usage_flags,
+ ExceptionState& exception_state);
GPUSampler* createSampler(const GPUSamplerDescriptor* descriptor);
GPUBindGroup* createBindGroup(const GPUBindGroupDescriptor* descriptor,
@@ -92,6 +97,18 @@ class GPUDevice final : public EventTargetWithInlineData,
const GPURenderPipelineDescriptor* descriptor);
GPUComputePipeline* createComputePipeline(
const GPUComputePipelineDescriptor* descriptor);
+ ScriptPromise createRenderPipelineAsync(
+ ScriptState* script_state,
+ const GPURenderPipelineDescriptor* descriptor);
+ ScriptPromise createComputePipelineAsync(
+ ScriptState* script_state,
+ const GPUComputePipelineDescriptor* descriptor);
+ ScriptPromise createReadyRenderPipeline(
+ ScriptState* script_state,
+ const GPURenderPipelineDescriptor* descriptor);
+ ScriptPromise createReadyComputePipeline(
+ ScriptState* script_state,
+ const GPUComputePipelineDescriptor* descriptor);
GPUCommandEncoder* createCommandEncoder(
const GPUCommandEncoderDescriptor* descriptor);
@@ -123,13 +140,27 @@ class GPUDevice final : public EventTargetWithInlineData,
WGPUErrorType type,
const char* message);
+ void OnCreateRenderPipelineAsyncCallback(ScriptPromiseResolver* resolver,
+ WGPUCreatePipelineAsyncStatus status,
+ WGPURenderPipeline render_pipeline,
+ const char* message);
+ void OnCreateComputePipelineAsyncCallback(
+ ScriptPromiseResolver* resolver,
+ WGPUCreatePipelineAsyncStatus status,
+ WGPUComputePipeline compute_pipeline,
+ const char* message);
+
Member<GPUAdapter> adapter_;
- Vector<String> extension_name_list_;
+ Vector<String> feature_name_list_;
Member<GPUQueue> queue_;
Member<LostProperty> lost_property_;
std::unique_ptr<
DawnCallback<base::RepeatingCallback<void(WGPUErrorType, const char*)>>>
error_callback_;
+ // lost_callback_ is stored as a unique_ptr since it may never be called.
+ // We need to be sure to free it on deletion of the device.
+ // Inside OnDeviceLostError we'll release the unique_ptr to avoid a double
+ // free.
std::unique_ptr<DawnCallback<base::OnceCallback<void(const char*)>>>
lost_callback_;
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 aa1da249d33..0533ce43ac8 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -8,13 +8,20 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUDevice : EventTarget {
[SameObject] readonly attribute GPUAdapter adapter;
- readonly attribute FrozenArray<GPUExtensionName> extensions;
+
+ readonly attribute FrozenArray<GPUFeatureName> features;
+ // Deprecated
+ readonly attribute FrozenArray<GPUFeatureName> extensions;
+
[CallWith=ScriptState] readonly attribute Promise<GPUDeviceLostInfo> lost;
+ [SameObject] readonly attribute GPUQueue queue;
+ // Deprecated
[SameObject] readonly attribute GPUQueue defaultQueue;
GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
[RaisesException] GPUTexture createTexture(GPUTextureDescriptor descriptor);
+ [RuntimeEnabled=WebGPUImportTexture, RaisesException] GPUTexture experimentalImportTexture(HTMLVideoElement video, GPUTextureUsageFlags usage);
GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
[RaisesException] GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
@@ -25,6 +32,13 @@
[CallWith=ScriptState] GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
+ [CallWith=ScriptState] Promise<GPURenderPipeline?> createRenderPipelineAsync(GPURenderPipelineDescriptor descriptor);
+ [CallWith=ScriptState] Promise<GPUComputePipeline?> createComputePipelineAsync(GPUComputePipelineDescriptor descriptor);
+
+ // Deprecated
+ [CallWith=ScriptState] Promise<GPURenderPipeline?> createReadyRenderPipeline(GPURenderPipelineDescriptor descriptor);
+ [CallWith=ScriptState] Promise<GPUComputePipeline?> createReadyComputePipeline(GPUComputePipelineDescriptor descriptor);
+
GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
@@ -35,6 +49,7 @@
attribute EventHandler onuncapturederror;
};
+GPUDevice includes GPUObjectBase;
enum GPUErrorFilter {
"none",
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl
index fbfe94db830..b87634955aa 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl
@@ -5,6 +5,9 @@
// https://gpuweb.github.io/gpuweb/
dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
- sequence<GPUExtensionName> extensions = [];
+ sequence<GPUFeatureName> nonGuaranteedFeatures = [];
GPULimits limits = {};
+
+ // Deprecated
+ sequence<GPUFeatureName> extensions;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl
index 6fc1fe24159..7c6793659e9 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl
@@ -7,5 +7,7 @@
dictionary GPUExtent3DDict {
GPUIntegerCoordinate width = 1;
GPUIntegerCoordinate height = 1;
- GPUIntegerCoordinate depth = 1;
+ GPUIntegerCoordinate depthOrArrayLayers = 1;
+ // Deprecated
+ GPUIntegerCoordinate depth;
};
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 8ee1dd5776a..c384d4788e0 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc
@@ -17,13 +17,6 @@ namespace blink {
GPUFence::GPUFence(GPUDevice* device, WGPUFence fence)
: DawnObject<WGPUFence>(device, fence) {}
-GPUFence::~GPUFence() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().fenceRelease(GetHandle());
-}
-
uint64_t GPUFence::getCompletedValue() const {
return GetProcs().fenceGetCompletedValue(GetHandle());
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.h
index 6dd3b505131..80896f7207f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.h
@@ -18,7 +18,6 @@ class GPUFence : public DawnObject<WGPUFence> {
public:
explicit GPUFence(GPUDevice* device, WGPUFence fence);
- ~GPUFence() override;
// gpu_fence.idl
uint64_t getCompletedValue() const;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_bitmap_copy_view.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_bitmap_copy_view.idl
deleted file mode 100644
index e0e29b5113f..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_bitmap_copy_view.idl
+++ /dev/null
@@ -1,12 +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.
-
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUImageBitmapCopyView {
- required ImageBitmap imageBitmap;
- GPUOrigin2D origin = {};
-};
-
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_buffer.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_buffer.idl
new file mode 100644
index 00000000000..45e662aca78
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_buffer.idl
@@ -0,0 +1,9 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUImageCopyBuffer : GPUImageDataLayout {
+ required GPUBuffer buffer;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_image_bitmap.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_image_bitmap.idl
new file mode 100644
index 00000000000..5481e8d9cb9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_image_bitmap.idl
@@ -0,0 +1,12 @@
+// 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://gpuweb.github.io/gpuweb/
+
+dictionary GPUImageCopyImageBitmap {
+ required ImageBitmap imageBitmap;
+ GPUOrigin2D origin = {};
+};
+
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture.idl
new file mode 100644
index 00000000000..7b93247b346
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture.idl
@@ -0,0 +1,12 @@
+// 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://gpuweb.github.io/gpuweb/
+
+dictionary GPUImageCopyTexture {
+ required GPUTexture texture;
+ GPUSize32 mipLevel = 0;
+ GPUOrigin3D origin = {};
+ GPUTextureAspect aspect = "all";
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_data_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_data_layout.idl
new file mode 100644
index 00000000000..6dfe34685dd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_image_data_layout.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/#dictdef-GPUImageDataLayout
+
+dictionary GPUImageDataLayout {
+ GPUSize64 offset = 0;
+ GPUSize32 bytesPerRow;
+ GPUSize32 rowsPerImage;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_object_base.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_object_base.idl
new file mode 100644
index 00000000000..cd9aa2d496e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_object_base.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+interface mixin GPUObjectBase {
+ attribute USVString? label;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_base.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_base.idl
new file mode 100644
index 00000000000..5fe91836425
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_base.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+interface mixin GPUPipelineBase {
+ GPUBindGroupLayout getBindGroupLayout(GPUIndex32 index);
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
index 146e8214a10..dace7846ea9 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.cc
@@ -35,20 +35,15 @@ GPUPipelineLayout* GPUPipelineLayout::Create(
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUPipelineLayout>(
+ GPUPipelineLayout* layout = MakeGarbageCollected<GPUPipelineLayout>(
device, device->GetProcs().deviceCreatePipelineLayout(device->GetHandle(),
&dawn_desc));
+ layout->setLabel(webgpu_desc->label());
+ return layout;
}
GPUPipelineLayout::GPUPipelineLayout(GPUDevice* device,
WGPUPipelineLayout pipeline_layout)
: DawnObject<WGPUPipelineLayout>(device, pipeline_layout) {}
-GPUPipelineLayout::~GPUPipelineLayout() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().pipelineLayoutRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
index 21cc71ca42a..843ef71616f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h
@@ -20,7 +20,6 @@ class GPUPipelineLayout : public DawnObject<WGPUPipelineLayout> {
const GPUPipelineLayoutDescriptor* webgpu_desc);
explicit GPUPipelineLayout(GPUDevice* device,
WGPUPipelineLayout pipeline_layout);
- ~GPUPipelineLayout() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUPipelineLayout);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
index f192dea8d04..a73fcfd88c4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUPipelineLayout {
};
+GPUPipelineLayout includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl
index a3876898701..7562e9a4ec0 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.idl
@@ -7,8 +7,9 @@
[
RuntimeEnabled=WebGPU
] interface mixin GPUProgrammablePassEncoder {
+ void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup);
void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup,
- optional sequence<GPUBufferDynamicOffset> dynamicOffsets = []);
+ sequence<GPUBufferDynamicOffset> dynamicOffsets);
[RaisesException] void setBindGroup(
GPUIndex32 index, GPUBindGroup bindGroup,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage.idl
new file mode 100644
index 00000000000..875cfda20c5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage.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://gpuweb.github.io/gpuweb/
+
+dictionary GPUProgrammableStage {
+ required GPUShaderModule module;
+ required USVString entryPoint;
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage_descriptor.idl
deleted file mode 100644
index 3c645977721..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_programmable_stage_descriptor.idl
+++ /dev/null
@@ -1,10 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUProgrammableStageDescriptor {
- required GPUShaderModule module;
- required USVString entryPoint;
-};
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
index ddd49f65bca..afdd9bf806f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc
@@ -37,21 +37,16 @@ GPUQuerySet* GPUQuerySet::Create(GPUDevice* device,
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUQuerySet>(
+ GPUQuerySet* query_set = MakeGarbageCollected<GPUQuerySet>(
device,
device->GetProcs().deviceCreateQuerySet(device->GetHandle(), &dawn_desc));
+ query_set->setLabel(webgpu_desc->label());
+ return query_set;
}
GPUQuerySet::GPUQuerySet(GPUDevice* device, WGPUQuerySet querySet)
: DawnObject<WGPUQuerySet>(device, querySet) {}
-GPUQuerySet::~GPUQuerySet() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().querySetRelease(GetHandle());
-}
-
void GPUQuerySet::destroy() {
GetProcs().querySetDestroy(GetHandle());
}
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
index c26749382db..4db24db74f8 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h
@@ -19,7 +19,6 @@ class GPUQuerySet : public DawnObject<WGPUQuerySet> {
static GPUQuerySet* Create(GPUDevice* device,
const GPUQuerySetDescriptor* webgpu_desc);
explicit GPUQuerySet(GPUDevice* device, WGPUQuerySet querySet);
- ~GPUQuerySet() override;
// gpu_queryset.idl
void destroy();
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
index d9457806831..97414dd0888 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl
@@ -9,3 +9,4 @@
] interface GPUQuerySet {
void destroy();
};
+GPUQuerySet includes GPUObjectBase;
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 3b8a9181dfe..7f18ffe8091 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -13,8 +13,8 @@
#include "third_party/blink/renderer/bindings/modules/v8/unsigned_long_enforce_range_sequence_or_gpu_origin_3d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_buffer_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_fence_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_bitmap_copy_view.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_copy_view.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_image_bitmap.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_texture.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_fence.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
@@ -34,21 +35,33 @@ WGPUOrigin3D GPUOrigin2DToWGPUOrigin3D(
const UnsignedLongEnforceRangeSequenceOrGPUOrigin2DDict* webgpu_origin) {
DCHECK(webgpu_origin);
- WGPUOrigin3D dawn_origin = {};
+ WGPUOrigin3D dawn_origin = {
+ 0,
+ 0,
+ 0,
+ };
if (webgpu_origin->IsUnsignedLongEnforceRangeSequence()) {
const Vector<uint32_t>& webgpu_origin_sequence =
webgpu_origin->GetAsUnsignedLongEnforceRangeSequence();
- DCHECK_EQ(webgpu_origin_sequence.size(), 3UL);
- dawn_origin.x = webgpu_origin_sequence[0];
- dawn_origin.y = webgpu_origin_sequence[1];
- dawn_origin.z = 0;
+ // The WebGPU spec states that if the sequence isn't big enough then the
+ // default values of 0 are used (which are set above).
+ switch (webgpu_origin_sequence.size()) {
+ default:
+ // This is a 2D origin and the depth should be 0 always.
+ dawn_origin.y = webgpu_origin_sequence[1];
+ FALLTHROUGH;
+ case 1:
+ dawn_origin.x = webgpu_origin_sequence[0];
+ FALLTHROUGH;
+ case 0:
+ break;
+ }
} else if (webgpu_origin->IsGPUOrigin2DDict()) {
const GPUOrigin2DDict* webgpu_origin_2d_dict =
webgpu_origin->GetAsGPUOrigin2DDict();
dawn_origin.x = webgpu_origin_2d_dict->x();
dawn_origin.y = webgpu_origin_2d_dict->y();
- dawn_origin.z = 0;
} else {
NOTREACHED();
}
@@ -128,17 +141,6 @@ bool CanUploadThroughGPU(StaticBitmapImage* image,
GPUQueue::GPUQueue(GPUDevice* device, WGPUQueue queue)
: DawnObject<WGPUQueue>(device, queue) {
- produce_dawn_texture_handler_ = base::AdoptRef(new DawnTextureFromImageBitmap(
- GetDawnControlClient(), GetDeviceClientID()));
-}
-
-GPUQueue::~GPUQueue() {
- produce_dawn_texture_handler_ = nullptr;
-
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().queueRelease(GetHandle());
}
void GPUQueue::submit(const HeapVector<Member<GPUCommandBuffer>>& buffers) {
@@ -171,29 +173,31 @@ GPUFence* GPUQueue::createFence(const GPUFenceDescriptor* descriptor) {
desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUFence>(
+ GPUFence* fence = MakeGarbageCollected<GPUFence>(
device_, GetProcs().queueCreateFence(GetHandle(), &desc));
+ fence->setLabel(descriptor->label());
+ return fence;
}
void GPUQueue::writeBuffer(GPUBuffer* buffer,
uint64_t buffer_offset,
const MaybeShared<DOMArrayBufferView>& data,
- uint64_t data_byte_offset,
+ uint64_t data_element_offset,
ExceptionState& exception_state) {
WriteBufferImpl(buffer, buffer_offset, data->byteLength(),
data->BaseAddressMaybeShared(), data->TypeSize(),
- data_byte_offset, {}, exception_state);
+ data_element_offset, {}, exception_state);
}
void GPUQueue::writeBuffer(GPUBuffer* buffer,
uint64_t buffer_offset,
const MaybeShared<DOMArrayBufferView>& data,
- uint64_t data_byte_offset,
- uint64_t byte_size,
+ uint64_t data_element_offset,
+ uint64_t data_element_count,
ExceptionState& exception_state) {
WriteBufferImpl(buffer, buffer_offset, data->byteLength(),
data->BaseAddressMaybeShared(), data->TypeSize(),
- data_byte_offset, byte_size, exception_state);
+ data_element_offset, data_element_count, exception_state);
}
void GPUQueue::writeBuffer(GPUBuffer* buffer,
@@ -222,41 +226,40 @@ void GPUQueue::WriteBufferImpl(GPUBuffer* buffer,
uint64_t data_byte_length,
const void* data_base_ptr,
unsigned data_bytes_per_element,
- uint64_t data_byte_offset,
- base::Optional<uint64_t> byte_size,
+ uint64_t data_element_offset,
+ base::Optional<uint64_t> data_element_count,
ExceptionState& exception_state) {
if (buffer_offset % 4 != 0) {
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "bufferOffset must be a multiple of 4");
+ "Buffer offset must be a multiple of 4");
return;
}
- if (data_byte_offset % data_bytes_per_element != 0) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kOperationError,
- "dataByteOffset must be a multiple of data.BYTES_PER_ELEMENT");
- return;
- }
+ CHECK_LE(data_bytes_per_element, 8u);
- if (data_byte_offset > data_byte_length) {
+ if (data_element_offset > data_byte_length / data_bytes_per_element) {
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "dataByteOffset is too large");
+ "Data offset is too large");
return;
}
+
+ uint64_t data_byte_offset = data_element_offset * data_bytes_per_element;
uint64_t max_write_size = data_byte_length - data_byte_offset;
uint64_t write_byte_size = max_write_size;
- if (byte_size.has_value()) {
- write_byte_size = byte_size.value();
- if (write_byte_size > max_write_size) {
- exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
- "byteSize is too large");
+ if (data_element_count.has_value()) {
+ if (data_element_count.value() > max_write_size / data_bytes_per_element) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kOperationError,
+ "Number of bytes to write is too large");
return;
}
+ write_byte_size = data_element_count.value() * data_bytes_per_element;
}
- if (write_byte_size % std::max(4u, data_bytes_per_element) != 0) {
- exception_state.ThrowRangeError(
- "byteSize must be a multiple of max(4, data.BYTES_PER_ELEMENT)");
+ if (write_byte_size % 4 != 0) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kOperationError,
+ "Number of bytes to write must be a multiple of 4");
return;
}
@@ -276,9 +279,9 @@ void GPUQueue::WriteBufferImpl(GPUBuffer* buffer,
}
void GPUQueue::writeTexture(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const MaybeShared<DOMArrayBufferView>& data,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state) {
WriteTextureImpl(destination, data->BaseAddressMaybeShared(),
@@ -287,9 +290,9 @@ void GPUQueue::writeTexture(
}
void GPUQueue::writeTexture(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const DOMArrayBufferBase* data,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state) {
WriteTextureImpl(destination, data->DataMaybeShared(), data->ByteLength(),
@@ -297,13 +300,13 @@ void GPUQueue::writeTexture(
}
void GPUQueue::WriteTextureImpl(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const void* data,
size_t data_size,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state) {
- WGPUExtent3D dawn_write_size = AsDawnType(&write_size);
+ WGPUExtent3D dawn_write_size = AsDawnType(&write_size, device_);
WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_);
WGPUTextureDataLayout dawn_data_layout = {};
@@ -323,8 +326,8 @@ void GPUQueue::WriteTextureImpl(
// TODO(shaobo.yan@intel.com): Implement this function
void GPUQueue::copyImageBitmapToTexture(
- GPUImageBitmapCopyView* source,
- GPUTextureCopyView* destination,
+ GPUImageCopyImageBitmap* source,
+ GPUImageCopyTexture* destination,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
ExceptionState& exception_state) {
if (!source->imageBitmap()) {
@@ -346,7 +349,7 @@ void GPUQueue::copyImageBitmapToTexture(
// appropriate format. Now only support texture format exactly the same. The
// compatible formats need to be defined in WebGPU spec.
- WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
+ WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size, device_);
// Extract imageBitmap attributes
WGPUOrigin3D origin_in_image_bitmap =
@@ -482,12 +485,13 @@ bool GPUQueue::CopyContentFromGPU(StaticBitmapImage* image,
const WGPUOrigin3D& origin,
const WGPUExtent3D& copy_size,
const WGPUTextureCopyView& destination) {
- WGPUTexture src_texture =
- produce_dawn_texture_handler_->ProduceDawnTextureFromImageBitmap(image);
- // Failed to produceDawnTexture.
- if (!src_texture) {
- return false;
- }
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture =
+ WebGPUMailboxTexture::FromStaticBitmapImage(
+ GetDawnControlClient(), device_->GetHandle(),
+ WGPUTextureUsage_CopySrc, image);
+
+ WGPUTexture src_texture = mailbox_texture->GetTexture();
+ DCHECK(src_texture != nullptr);
WGPUTextureCopyView src = {};
src.texture = src_texture;
@@ -509,7 +513,6 @@ bool GPUQueue::CopyContentFromGPU(StaticBitmapImage* image,
GetProcs().commandBufferRelease(commands);
GetProcs().commandEncoderRelease(encoder);
- produce_dawn_texture_handler_->FinishDawnTextureFromImageBitmapAccess();
return true;
}
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 7ada7446e4a..b2bc0e48f38 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h
@@ -11,15 +11,14 @@
namespace blink {
-class DawnTextureFromImageBitmap;
class ExceptionState;
class GPUBuffer;
class GPUCommandBuffer;
class GPUFence;
class GPUFenceDescriptor;
-class GPUImageBitmapCopyView;
-class GPUTextureCopyView;
-class GPUTextureDataLayout;
+class GPUImageCopyImageBitmap;
+class GPUImageCopyTexture;
+class GPUImageDataLayout;
class StaticBitmapImage;
class UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict;
@@ -28,7 +27,6 @@ class GPUQueue : public DawnObject<WGPUQueue> {
public:
explicit GPUQueue(GPUDevice* device, WGPUQueue queue);
- ~GPUQueue() override;
// gpu_queue.idl
void submit(const HeapVector<Member<GPUCommandBuffer>>& buffers);
@@ -37,13 +35,13 @@ class GPUQueue : public DawnObject<WGPUQueue> {
void writeBuffer(GPUBuffer* buffer,
uint64_t buffer_offset,
const MaybeShared<DOMArrayBufferView>& data,
- uint64_t data_byte_offset,
+ uint64_t data_element_offset,
ExceptionState& exception_state);
void writeBuffer(GPUBuffer* buffer,
uint64_t buffer_offset,
const MaybeShared<DOMArrayBufferView>& data,
- uint64_t data_byte_offset,
- uint64_t byte_size,
+ uint64_t data_element_offset,
+ uint64_t data_element_count,
ExceptionState& exception_state);
void writeBuffer(GPUBuffer* buffer,
uint64_t buffer_offset,
@@ -57,20 +55,20 @@ class GPUQueue : public DawnObject<WGPUQueue> {
uint64_t byte_size,
ExceptionState& exception_state);
void writeTexture(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const MaybeShared<DOMArrayBufferView>& data,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state);
void writeTexture(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const DOMArrayBufferBase* data,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state);
void copyImageBitmapToTexture(
- GPUImageBitmapCopyView* source,
- GPUTextureCopyView* destination,
+ GPUImageCopyImageBitmap* source,
+ GPUImageCopyTexture* destination,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copySize,
ExceptionState& exception_state);
@@ -93,15 +91,13 @@ class GPUQueue : public DawnObject<WGPUQueue> {
base::Optional<uint64_t> byte_size,
ExceptionState& exception_state);
void WriteTextureImpl(
- GPUTextureCopyView* destination,
+ GPUImageCopyTexture* destination,
const void* data,
size_t dataSize,
- GPUTextureDataLayout* data_layout,
+ GPUImageDataLayout* data_layout,
UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size,
ExceptionState& exception_state);
- scoped_refptr<DawnTextureFromImageBitmap> produce_dawn_texture_handler_;
-
DISALLOW_COPY_AND_ASSIGN(GPUQueue);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
index 26be9a3a385..2174c348741 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
@@ -19,8 +19,8 @@
GPUBuffer buffer,
GPUSize64 bufferOffset,
[AllowShared] ArrayBufferView data,
- optional GPUSize64 dataByteOffset = 0,
- optional GPUSize64 byteSize);
+ optional GPUSize64 dataElementOffset = 0,
+ optional GPUSize64 dataElementCount);
[RaisesException] void writeBuffer(
GPUBuffer buffer,
GPUSize64 bufferOffset,
@@ -29,18 +29,19 @@
optional GPUSize64 byteSize);
[RaisesException] void writeTexture(
- GPUTextureCopyView destination,
+ GPUImageCopyTexture destination,
[AllowShared] ArrayBufferView data,
- GPUTextureDataLayout dataLayout,
+ GPUImageDataLayout dataLayout,
GPUExtent3D size);
[RaisesException] void writeTexture(
- GPUTextureCopyView destination,
+ GPUImageCopyTexture destination,
ArrayBuffer data,
- GPUTextureDataLayout dataLayout,
+ GPUImageDataLayout dataLayout,
GPUExtent3D size);
[RaisesException] void copyImageBitmapToTexture(
- GPUImageBitmapCopyView source,
- GPUTextureCopyView destination,
+ GPUImageCopyImageBitmap source,
+ GPUImageCopyTexture destination,
GPUExtent3D copySize);
};
+GPUQueue includes GPUObjectBase; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.cc
index 266a5b99e87..d20423d52df 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.cc
@@ -12,11 +12,4 @@ GPURenderBundle::GPURenderBundle(GPUDevice* device,
WGPURenderBundle render_bundle)
: DawnObject<WGPURenderBundle>(device, render_bundle) {}
-GPURenderBundle::~GPURenderBundle() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().renderBundleRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h
index b9f06fdac5a..2df2adbb0b2 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h
@@ -16,7 +16,6 @@ class GPURenderBundle : public DawnObject<WGPURenderBundle> {
public:
explicit GPURenderBundle(GPUDevice* device, WGPURenderBundle render_bundle);
- ~GPURenderBundle() override;
DISALLOW_COPY_AND_ASSIGN(GPURenderBundle);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
index ba301eb8be0..9f7a6e17d8d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPURenderBundle {
};
+GPURenderBundle includes GPUObjectBase;
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 3db33d66636..53c04faf29d 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
@@ -44,9 +44,12 @@ GPURenderBundleEncoder* GPURenderBundleEncoder::Create(
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPURenderBundleEncoder>(
- device, device->GetProcs().deviceCreateRenderBundleEncoder(
- device->GetHandle(), &dawn_desc));
+ GPURenderBundleEncoder* encoder =
+ MakeGarbageCollected<GPURenderBundleEncoder>(
+ device, device->GetProcs().deviceCreateRenderBundleEncoder(
+ device->GetHandle(), &dawn_desc));
+ encoder->setLabel(webgpu_desc->label());
+ return encoder;
}
GPURenderBundleEncoder::GPURenderBundleEncoder(
@@ -54,11 +57,10 @@ GPURenderBundleEncoder::GPURenderBundleEncoder(
WGPURenderBundleEncoder render_bundle_encoder)
: DawnObject<WGPURenderBundleEncoder>(device, render_bundle_encoder) {}
-GPURenderBundleEncoder::~GPURenderBundleEncoder() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().renderBundleEncoderRelease(GetHandle());
+void GPURenderBundleEncoder::setBindGroup(uint32_t index,
+ GPUBindGroup* bindGroup) {
+ GetProcs().renderBundleEncoderSetBindGroup(
+ GetHandle(), index, bindGroup->GetHandle(), 0, nullptr);
}
void GPURenderBundleEncoder::setBindGroup(
@@ -110,28 +112,11 @@ void GPURenderBundleEncoder::setPipeline(GPURenderPipeline* pipeline) {
}
void GPURenderBundleEncoder::setIndexBuffer(GPUBuffer* buffer,
+ const V8GPUIndexFormat& format,
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);
+ GetHandle(), buffer->GetHandle(), AsDawnEnum(format), offset, size);
}
void GPURenderBundleEncoder::setVertexBuffer(uint32_t slot,
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 f0bb0546e53..18443d2db82 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
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_RENDER_BUNDLE_ENCODER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_RENDER_BUNDLE_ENCODER_H_
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_index_format.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_programmable_pass_encoder.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -30,9 +31,9 @@ class GPURenderBundleEncoder : public DawnObject<WGPURenderBundleEncoder>,
explicit GPURenderBundleEncoder(
GPUDevice* device,
WGPURenderBundleEncoder render_bundle_encoder);
- ~GPURenderBundleEncoder() override;
// gpu_render_bundle_encoder.idl
+ void setBindGroup(uint32_t index, GPUBindGroup* bindGroup);
void setBindGroup(uint32_t index,
GPUBindGroup* bindGroup,
const Vector<uint32_t>& dynamicOffsets);
@@ -47,12 +48,10 @@ class GPURenderBundleEncoder : public DawnObject<WGPURenderBundleEncoder>,
void insertDebugMarker(String markerLabel);
void setPipeline(GPURenderPipeline* pipeline);
- void setIndexBuffer(GPUBuffer* buffer, uint64_t offset, uint64_t size);
void setIndexBuffer(GPUBuffer* buffer,
- const WTF::String& format,
+ const V8GPUIndexFormat& format,
uint64_t offset,
- uint64_t size,
- ExceptionState& exception_state);
+ uint64_t size);
void setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
uint64_t offset,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
index 98355ab34ab..4fd9caf4baa 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
@@ -9,5 +9,6 @@
] interface GPURenderBundleEncoder {
GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
};
+GPURenderBundleEncoder includes GPUObjectBase;
GPURenderBundleEncoder includes GPUProgrammablePassEncoder;
GPURenderBundleEncoder includes GPURenderEncoderBase;
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 9061bc26e6c..7e9b81e37d1 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
@@ -10,17 +10,7 @@
void setPipeline(GPURenderPipeline pipeline);
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,
+ GPUIndexFormat format,
optional GPUSize64 offset = 0,
optional GPUSize64 size = 0);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_descriptor.idl
index 9589242ac4f..f9fc758b76f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_descriptor.idl
@@ -7,6 +7,7 @@
dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
GPURenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
+ GPUQuerySet occlusionQuerySet;
};
enum GPULoadOp {
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 c8a6ea6a38a..0f9bbc53df4 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
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h"
#include "third_party/blink/renderer/bindings/modules/v8/double_sequence_or_gpu_color_dict.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_index_format.h"
#include "third_party/blink/renderer/core/typed_arrays/typed_flexible_array_buffer_view.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_bind_group.h"
@@ -21,11 +22,10 @@ GPURenderPassEncoder::GPURenderPassEncoder(
WGPURenderPassEncoder render_pass_encoder)
: DawnObject<WGPURenderPassEncoder>(device, render_pass_encoder) {}
-GPURenderPassEncoder::~GPURenderPassEncoder() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().renderPassEncoderRelease(GetHandle());
+void GPURenderPassEncoder::setBindGroup(uint32_t index,
+ GPUBindGroup* bindGroup) {
+ GetProcs().renderPassEncoderSetBindGroup(GetHandle(), index,
+ bindGroup->GetHandle(), 0, nullptr);
}
void GPURenderPassEncoder::setBindGroup(
@@ -109,28 +109,11 @@ void GPURenderPassEncoder::setScissorRect(uint32_t x,
}
void GPURenderPassEncoder::setIndexBuffer(GPUBuffer* buffer,
+ const V8GPUIndexFormat& format,
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);
+ GetHandle(), buffer->GetHandle(), AsDawnEnum(format), offset, size);
}
void GPURenderPassEncoder::setVertexBuffer(uint32_t slot,
@@ -196,6 +179,14 @@ void GPURenderPassEncoder::executeBundles(
dawn_bundles.get());
}
+void GPURenderPassEncoder::beginOcclusionQuery(uint32_t queryIndex) {
+ GetProcs().renderPassEncoderBeginOcclusionQuery(GetHandle(), queryIndex);
+}
+
+void GPURenderPassEncoder::endOcclusionQuery() {
+ GetProcs().renderPassEncoderEndOcclusionQuery(GetHandle());
+}
+
void GPURenderPassEncoder::writeTimestamp(GPUQuerySet* querySet,
uint32_t queryIndex) {
GetProcs().renderPassEncoderWriteTimestamp(GetHandle(), querySet->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 78b9f0268ba..5fbb096d3f1 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
@@ -18,6 +18,7 @@ class DoubleSequenceOrGPUColorDict;
class GPURenderBundle;
class GPURenderPipeline;
class GPUQuerySet;
+class V8GPUIndexFormat;
class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
public GPUProgrammablePassEncoder {
@@ -26,9 +27,9 @@ class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
public:
explicit GPURenderPassEncoder(GPUDevice* device,
WGPURenderPassEncoder render_pass_encoder);
- ~GPURenderPassEncoder() override;
// gpu_render_pass_encoder.idl
+ void setBindGroup(uint32_t index, GPUBindGroup* bindGroup);
void setBindGroup(uint32_t index,
GPUBindGroup* bindGroup,
const Vector<uint32_t>& dynamicOffsets);
@@ -53,12 +54,10 @@ class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
float minDepth,
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,
+ const V8GPUIndexFormat& format,
uint64_t offset,
- uint64_t size,
- ExceptionState& exception_state);
+ uint64_t size);
void setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
const uint64_t offset,
@@ -86,6 +85,8 @@ 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 beginOcclusionQuery(uint32_t queryIndex);
+ void endOcclusionQuery();
void writeTimestamp(GPUQuerySet* querySet, uint32_t queryIndex);
void endPass();
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 6ac8535eca3..d67dacb4522 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,8 +18,11 @@
void setStencilReference(GPUStencilValue reference);
void executeBundles(sequence<GPURenderBundle> bundles);
+ void beginOcclusionQuery(GPUSize32 queryIndex);
+ void endOcclusionQuery();
void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
void endPass();
};
+GPURenderPassEncoder includes GPUObjectBase;
GPURenderPassEncoder includes GPUProgrammablePassEncoder;
GPURenderPassEncoder includes GPURenderEncoderBase;
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 e29a8ee4285..f9032a7dc7f 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
@@ -5,16 +5,15 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_rasterization_state_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_state_face_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_face_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h"
-#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
@@ -25,7 +24,7 @@ namespace blink {
namespace {
-WGPUBlendDescriptor AsDawnType(const GPUBlendDescriptor* webgpu_desc) {
+WGPUBlendDescriptor AsDawnType(const GPUBlendState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUBlendDescriptor dawn_desc = {};
@@ -39,8 +38,7 @@ WGPUBlendDescriptor AsDawnType(const GPUBlendDescriptor* webgpu_desc) {
} // anonymous namespace
-WGPUColorStateDescriptor AsDawnType(
- const GPUColorStateDescriptor* webgpu_desc) {
+WGPUColorStateDescriptor AsDawnType(const GPUColorTargetState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUColorStateDescriptor dawn_desc = {};
@@ -57,7 +55,7 @@ WGPUColorStateDescriptor AsDawnType(
namespace {
WGPUStencilStateFaceDescriptor AsDawnType(
- const GPUStencilStateFaceDescriptor* webgpu_desc) {
+ const GPUStencilFaceState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUStencilStateFaceDescriptor dawn_desc = {};
@@ -71,7 +69,7 @@ WGPUStencilStateFaceDescriptor AsDawnType(
}
WGPUDepthStencilStateDescriptor AsDawnType(
- const GPUDepthStencilStateDescriptor* webgpu_desc) {
+ const GPUDepthStencilState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUDepthStencilStateDescriptor dawn_desc = {};
@@ -88,22 +86,24 @@ WGPUDepthStencilStateDescriptor AsDawnType(
return dawn_desc;
}
-using WGPUVertexStateInfo = std::tuple<WGPUVertexStateDescriptor,
- Vector<WGPUVertexBufferLayoutDescriptor>,
- Vector<WGPUVertexAttributeDescriptor>>;
-
-WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
+void GPUVertexStateAsWGPUVertexState(
v8::Isolate* isolate,
const GPUVertexStateDescriptor* descriptor,
+ WGPUVertexStateDescriptor* dawn_desc,
+ Vector<WGPUVertexBufferLayoutDescriptor>* dawn_vertex_buffers,
+ Vector<WGPUVertexAttributeDescriptor>* dawn_vertex_attributes,
ExceptionState& exception_state) {
- WGPUVertexStateDescriptor dawn_desc = {};
- dawn_desc.indexFormat =
+ DCHECK(isolate);
+ DCHECK(descriptor);
+ DCHECK(dawn_desc);
+ DCHECK(dawn_vertex_buffers);
+ DCHECK(dawn_vertex_attributes);
+
+ *dawn_desc = {};
+ dawn_desc->indexFormat =
AsDawnEnum<WGPUIndexFormat>(descriptor->indexFormat());
- dawn_desc.vertexBufferCount = 0;
- dawn_desc.vertexBuffers = nullptr;
-
- Vector<WGPUVertexBufferLayoutDescriptor> dawn_vertex_buffers;
- Vector<WGPUVertexAttributeDescriptor> dawn_vertex_attributes;
+ dawn_desc->vertexBufferCount = 0;
+ dawn_desc->vertexBuffers = nullptr;
if (descriptor->hasVertexBuffers()) {
// TODO(crbug.com/951629): Use a sequence of nullable descriptors.
@@ -111,9 +111,7 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
descriptor->vertexBuffers().V8Value();
if (!vertex_buffers_value->IsArray()) {
exception_state.ThrowTypeError("vertexBuffers must be an array");
-
- return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
- std::move(dawn_vertex_attributes));
+ return;
}
v8::Local<v8::Context> context = isolate->GetCurrentContext();
@@ -135,7 +133,7 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
dawn_vertex_buffer.attributeCount = 0;
dawn_vertex_buffer.attributes = nullptr;
- dawn_vertex_buffers.push_back(dawn_vertex_buffer);
+ dawn_vertex_buffers->push_back(dawn_vertex_buffer);
continue;
}
@@ -143,8 +141,7 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
NativeValueTraits<GPUVertexBufferLayoutDescriptor>::NativeValue(
isolate, value, exception_state);
if (exception_state.HadException()) {
- return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
- std::move(dawn_vertex_attributes));
+ return;
}
WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
@@ -154,7 +151,7 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
dawn_vertex_buffer.attributeCount =
static_cast<uint32_t>(vertex_buffer->attributes().size());
dawn_vertex_buffer.attributes = nullptr;
- dawn_vertex_buffers.push_back(dawn_vertex_buffer);
+ dawn_vertex_buffers->push_back(dawn_vertex_buffer);
for (wtf_size_t j = 0; j < vertex_buffer->attributes().size(); ++j) {
const GPUVertexAttributeDescriptor* attribute =
@@ -164,7 +161,7 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
dawn_vertex_attribute.offset = attribute->offset();
dawn_vertex_attribute.format =
AsDawnEnum<WGPUVertexFormat>(attribute->format());
- dawn_vertex_attributes.push_back(dawn_vertex_attribute);
+ dawn_vertex_attributes->push_back(dawn_vertex_attribute);
}
}
@@ -172,21 +169,18 @@ WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
// after we stopped appending to the vector so the pointers aren't
// invalidated.
uint32_t attributeIndex = 0;
- for (WGPUVertexBufferLayoutDescriptor& buffer : dawn_vertex_buffers) {
+ for (WGPUVertexBufferLayoutDescriptor& buffer : *dawn_vertex_buffers) {
if (buffer.attributeCount == 0) {
continue;
}
- buffer.attributes = &dawn_vertex_attributes[attributeIndex];
+ buffer.attributes = &(*dawn_vertex_attributes)[attributeIndex];
attributeIndex += buffer.attributeCount;
}
}
- dawn_desc.vertexBufferCount =
- static_cast<uint32_t>(dawn_vertex_buffers.size());
- dawn_desc.vertexBuffers = dawn_vertex_buffers.data();
-
- return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
- std::move(dawn_vertex_attributes));
+ dawn_desc->vertexBufferCount =
+ static_cast<uint32_t>(dawn_vertex_buffers->size());
+ dawn_desc->vertexBuffers = dawn_vertex_buffers->data();
}
WGPURasterizationStateDescriptor AsDawnType(
@@ -206,114 +200,97 @@ WGPURasterizationStateDescriptor AsDawnType(
} // anonymous namespace
-// static
-GPURenderPipeline* GPURenderPipeline::Create(
- ScriptState* script_state,
- GPUDevice* device,
- const GPURenderPipelineDescriptor* webgpu_desc) {
- DCHECK(device);
+void ConvertToDawnType(v8::Isolate* isolate,
+ const GPURenderPipelineDescriptor* webgpu_desc,
+ OwnedRenderPipelineDescriptor* dawn_desc_info,
+ ExceptionState& exception_state) {
+ DCHECK(isolate);
DCHECK(webgpu_desc);
+ DCHECK(dawn_desc_info);
+
+ GPUVertexStateAsWGPUVertexState(
+ isolate, webgpu_desc->vertexState(), &dawn_desc_info->vertex_state,
+ &dawn_desc_info->vertex_buffer_layouts,
+ &dawn_desc_info->vertex_attributes, exception_state);
+ if (exception_state.HadException()) {
+ return;
+ }
+ dawn_desc_info->dawn_desc.vertexState = &dawn_desc_info->vertex_state;
- std::string label;
- WGPURenderPipelineDescriptor dawn_desc = {};
- dawn_desc.nextInChain = nullptr;
if (webgpu_desc->hasLayout()) {
- dawn_desc.layout = AsDawnType(webgpu_desc->layout());
+ dawn_desc_info->dawn_desc.layout = AsDawnType(webgpu_desc->layout());
}
+
if (webgpu_desc->hasLabel()) {
- label = webgpu_desc->label().Utf8();
- dawn_desc.label = label.c_str();
+ dawn_desc_info->label = webgpu_desc->label().Utf8();
+ dawn_desc_info->dawn_desc.label = dawn_desc_info->label.c_str();
}
- OwnedProgrammableStageDescriptor vertex_stage_info =
- AsDawnType(webgpu_desc->vertexStage());
- dawn_desc.vertexStage = std::get<0>(vertex_stage_info);
- OwnedProgrammableStageDescriptor fragment_stage_info;
+ dawn_desc_info->vertex_stage_info = AsDawnType(webgpu_desc->vertexStage());
+ dawn_desc_info->dawn_desc.vertexStage =
+ std::get<0>(dawn_desc_info->vertex_stage_info);
if (webgpu_desc->hasFragmentStage()) {
- fragment_stage_info = AsDawnType(webgpu_desc->fragmentStage());
- dawn_desc.fragmentStage = &std::get<0>(fragment_stage_info);
- } else {
- dawn_desc.fragmentStage = nullptr;
+ dawn_desc_info->fragment_stage_info =
+ AsDawnType(webgpu_desc->fragmentStage());
+ dawn_desc_info->dawn_desc.fragmentStage =
+ &std::get<0>(dawn_desc_info->fragment_stage_info);
}
- dawn_desc.primitiveTopology =
+ dawn_desc_info->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);
- 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_info->rasterization_state =
+ AsDawnType(webgpu_desc->rasterizationState());
+ dawn_desc_info->dawn_desc.rasterizationState =
+ &dawn_desc_info->rasterization_state;
- WGPURasterizationStateDescriptor rasterization_state;
- rasterization_state = AsDawnType(webgpu_desc->rasterizationState());
- dawn_desc.rasterizationState = &rasterization_state;
+ dawn_desc_info->dawn_desc.sampleCount = webgpu_desc->sampleCount();
- dawn_desc.sampleCount = webgpu_desc->sampleCount();
-
- WGPUDepthStencilStateDescriptor depth_stencil_state = {};
if (webgpu_desc->hasDepthStencilState()) {
- depth_stencil_state = AsDawnType(webgpu_desc->depthStencilState());
- dawn_desc.depthStencilState = &depth_stencil_state;
- } else {
- dawn_desc.depthStencilState = nullptr;
+ dawn_desc_info->depth_stencil_state =
+ AsDawnType(webgpu_desc->depthStencilState());
+ dawn_desc_info->dawn_desc.depthStencilState =
+ &dawn_desc_info->depth_stencil_state;
}
- std::unique_ptr<WGPUColorStateDescriptor[]> color_states =
- AsDawnType(webgpu_desc->colorStates());
- dawn_desc.colorStateCount =
+ dawn_desc_info->color_states = AsDawnType(webgpu_desc->colorStates());
+ dawn_desc_info->dawn_desc.colorStateCount =
static_cast<uint32_t>(webgpu_desc->colorStates().size());
+ dawn_desc_info->dawn_desc.colorStates = dawn_desc_info->color_states.get();
- dawn_desc.colorStates = color_states.get();
+ dawn_desc_info->dawn_desc.sampleMask = webgpu_desc->sampleMask();
+ dawn_desc_info->dawn_desc.alphaToCoverageEnabled =
+ webgpu_desc->alphaToCoverageEnabled();
+}
- dawn_desc.sampleMask = webgpu_desc->sampleMask();
- dawn_desc.alphaToCoverageEnabled = webgpu_desc->alphaToCoverageEnabled();
+// static
+GPURenderPipeline* GPURenderPipeline::Create(
+ ScriptState* script_state,
+ GPUDevice* device,
+ const GPURenderPipelineDescriptor* webgpu_desc) {
+ DCHECK(device);
+ DCHECK(webgpu_desc);
- return MakeGarbageCollected<GPURenderPipeline>(
- device, device->GetProcs().deviceCreateRenderPipeline(device->GetHandle(),
- &dawn_desc));
+ OwnedRenderPipelineDescriptor dawn_desc_info;
+ v8::Isolate* isolate = script_state->GetIsolate();
+ ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
+ "GPUVertexStateDescriptor");
+ ConvertToDawnType(isolate, webgpu_desc, &dawn_desc_info, exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+
+ GPURenderPipeline* pipeline = MakeGarbageCollected<GPURenderPipeline>(
+ device, device->GetProcs().deviceCreateRenderPipeline(
+ device->GetHandle(), &dawn_desc_info.dawn_desc));
+ pipeline->setLabel(webgpu_desc->label());
+ return pipeline;
}
GPURenderPipeline::GPURenderPipeline(GPUDevice* device,
WGPURenderPipeline render_pipeline)
: DawnObject<WGPURenderPipeline>(device, render_pipeline) {}
-GPURenderPipeline::~GPURenderPipeline() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().renderPipelineRelease(GetHandle());
-}
-
GPUBindGroupLayout* GPURenderPipeline::getBindGroupLayout(uint32_t index) {
return MakeGarbageCollected<GPUBindGroupLayout>(
device_, GetProcs().renderPipelineGetBindGroupLayout(GetHandle(), index));
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
index 3f9dbb1839f..d613e5b978a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
@@ -5,14 +5,47 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_RENDER_PIPELINE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_RENDER_PIPELINE_H_
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
namespace blink {
class GPUBindGroupLayout;
class GPURenderPipelineDescriptor;
+class ExceptionState;
class ScriptState;
+struct OwnedRenderPipelineDescriptor {
+ public:
+ OwnedRenderPipelineDescriptor() : dawn_desc({}) {}
+
+ // This struct should be non-copyable non-movable because it contains
+ // self-referencing pointers that would be invalidated when moved / copied.
+ OwnedRenderPipelineDescriptor(const OwnedRenderPipelineDescriptor& desc) =
+ delete;
+ OwnedRenderPipelineDescriptor(OwnedRenderPipelineDescriptor&& desc) = delete;
+ OwnedRenderPipelineDescriptor& operator=(
+ const OwnedRenderPipelineDescriptor& desc) = delete;
+ OwnedRenderPipelineDescriptor& operator=(
+ OwnedRenderPipelineDescriptor&& desc) = delete;
+
+ WGPURenderPipelineDescriptor dawn_desc;
+ std::string label;
+ OwnedProgrammableStageDescriptor vertex_stage_info;
+ OwnedProgrammableStageDescriptor fragment_stage_info;
+ WGPUVertexStateDescriptor vertex_state;
+ Vector<WGPUVertexBufferLayoutDescriptor> vertex_buffer_layouts;
+ Vector<WGPUVertexAttributeDescriptor> vertex_attributes;
+ WGPURasterizationStateDescriptor rasterization_state;
+ WGPUDepthStencilStateDescriptor depth_stencil_state;
+ std::unique_ptr<WGPUColorStateDescriptor[]> color_states;
+};
+
+void ConvertToDawnType(v8::Isolate* isolate,
+ const GPURenderPipelineDescriptor* webgpu_desc,
+ OwnedRenderPipelineDescriptor* dawn_desc_info,
+ ExceptionState& exception_state);
+
class GPURenderPipeline : public DawnObject<WGPURenderPipeline> {
DEFINE_WRAPPERTYPEINFO();
@@ -23,7 +56,6 @@ class GPURenderPipeline : public DawnObject<WGPURenderPipeline> {
const GPURenderPipelineDescriptor* webgpu_desc);
explicit GPURenderPipeline(GPUDevice* device,
WGPURenderPipeline render_pipeline);
- ~GPURenderPipeline() override;
GPUBindGroupLayout* getBindGroupLayout(uint32_t index);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
index 7be67ddf655..be42ba1278d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
@@ -7,5 +7,6 @@
[
Exposed(Window WebGPU, Worker WebGPU)
] interface GPURenderPipeline {
- GPUBindGroupLayout getBindGroupLayout(GPUIndex32 index);
};
+GPURenderPipeline includes GPUObjectBase;
+GPURenderPipeline includes GPUPipelineBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
index 04a181c7ea9..84aeb201954 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
@@ -5,13 +5,13 @@
// https://gpuweb.github.io/gpuweb/
dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
- required GPUProgrammableStageDescriptor vertexStage;
- GPUProgrammableStageDescriptor fragmentStage;
+ required GPUProgrammableStage vertexStage;
+ GPUProgrammableStage fragmentStage;
required GPUPrimitiveTopology primitiveTopology;
GPURasterizationStateDescriptor rasterizationState = {};
- required sequence<GPUColorStateDescriptor> colorStates;
- GPUDepthStencilStateDescriptor depthStencilState;
+ required sequence<GPUColorTargetState> colorStates;
+ GPUDepthStencilState depthStencilState;
GPUVertexStateDescriptor vertexState = {};
GPUSize32 sampleCount = 1;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
index 2035143b3b3..aebb8e68015 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.cc
@@ -31,6 +31,7 @@ WGPUSamplerDescriptor AsDawnType(const GPUSamplerDescriptor* webgpu_desc,
AsDawnEnum<WGPUFilterMode>(webgpu_desc->mipmapFilter());
dawn_desc.lodMinClamp = webgpu_desc->lodMinClamp();
dawn_desc.lodMaxClamp = webgpu_desc->lodMaxClamp();
+ dawn_desc.maxAnisotropy = webgpu_desc->maxAnisotropy();
if (webgpu_desc->hasCompare()) {
dawn_desc.compare = AsDawnEnum<WGPUCompareFunction>(webgpu_desc->compare());
}
@@ -51,19 +52,14 @@ GPUSampler* GPUSampler::Create(GPUDevice* device,
DCHECK(webgpu_desc);
std::string label;
WGPUSamplerDescriptor dawn_desc = AsDawnType(webgpu_desc, &label);
- return MakeGarbageCollected<GPUSampler>(
+ GPUSampler* sampler = MakeGarbageCollected<GPUSampler>(
device,
device->GetProcs().deviceCreateSampler(device->GetHandle(), &dawn_desc));
+ sampler->setLabel(webgpu_desc->label());
+ return sampler;
}
GPUSampler::GPUSampler(GPUDevice* device, WGPUSampler sampler)
: DawnObject<WGPUSampler>(device, sampler) {}
-GPUSampler::~GPUSampler() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().samplerRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.h
index a7c9164118e..421039dc679 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.h
@@ -18,7 +18,6 @@ class GPUSampler : public DawnObject<WGPUSampler> {
static GPUSampler* Create(GPUDevice* device,
const GPUSamplerDescriptor* webgpu_desc);
explicit GPUSampler(GPUDevice* device, WGPUSampler sampler);
- ~GPUSampler() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUSampler);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
index afb0b4ec0ba..25036e8e878 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUSampler {
};
+GPUSampler includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_binding_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_binding_layout.idl
new file mode 100644
index 00000000000..38a1515213f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_binding_layout.idl
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUSamplerBindingLayout {
+ GPUSamplerBindingType type = "filtering";
+};
+
+enum GPUSamplerBindingType {
+ "filtering",
+ "non-filtering",
+ "comparison",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
index 42123d22313..36b0705d761 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
@@ -14,6 +14,7 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
float lodMinClamp = 0;
float lodMaxClamp = 0xffffffff;
GPUCompareFunction compare;
+ [Clamp] unsigned short maxAnisotropy = 1;
};
enum GPUAddressMode {
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
index 660209a987c..d76e932c99d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
@@ -36,7 +36,7 @@ GPUShaderModule* GPUShaderModule::Create(
NotShared<DOMUint32Array> code = wgsl_or_spirv.GetAsUint32Array();
uint32_t length_words = 0;
- if (!base::CheckedNumeric<uint32_t>(code.View()->length())
+ if (!base::CheckedNumeric<uint32_t>(code->length())
.AssignIfValid(&length_words)) {
exception_state.ThrowRangeError(
"The provided ArrayBuffer exceeds the maximum supported size "
@@ -45,7 +45,7 @@ GPUShaderModule* GPUShaderModule::Create(
}
spirv_desc.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
- spirv_desc.code = code.View()->Data();
+ spirv_desc.code = code->Data();
spirv_desc.codeSize = length_words;
dawn_desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&spirv_desc);
}
@@ -55,20 +55,15 @@ GPUShaderModule* GPUShaderModule::Create(
dawn_desc.label = label.c_str();
}
- return MakeGarbageCollected<GPUShaderModule>(
+ GPUShaderModule* shader = MakeGarbageCollected<GPUShaderModule>(
device, device->GetProcs().deviceCreateShaderModule(device->GetHandle(),
&dawn_desc));
+ shader->setLabel(webgpu_desc->label());
+ return shader;
}
GPUShaderModule::GPUShaderModule(GPUDevice* device,
WGPUShaderModule shader_module)
: DawnObject<WGPUShaderModule>(device, shader_module) {}
-GPUShaderModule::~GPUShaderModule() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().shaderModuleRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.h
index 90f32a1b2fd..4b2b0ec609d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.h
@@ -20,7 +20,6 @@ class GPUShaderModule : public DawnObject<WGPUShaderModule> {
const GPUShaderModuleDescriptor* webgpu_desc,
ExceptionState& exception_state);
explicit GPUShaderModule(GPUDevice* device, WGPUShaderModule shader_module);
- ~GPUShaderModule() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUShaderModule);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
index e8d42b92efb..d2efe34b4ea 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUShaderModule {
};
+GPUShaderModule includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_face_state.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_face_state.idl
new file mode 100644
index 00000000000..cffaaf763ef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_face_state.idl
@@ -0,0 +1,24 @@
+// 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://gpuweb.github.io/gpuweb/
+
+dictionary GPUStencilFaceState {
+ GPUCompareFunction compare = "always";
+ GPUStencilOperation failOp = "keep";
+ GPUStencilOperation depthFailOp = "keep";
+ GPUStencilOperation passOp = "keep";
+};
+
+enum GPUStencilOperation {
+ "keep",
+ "zero",
+ "replace",
+ "invert",
+ "increment-clamp",
+ "decrement-clamp",
+ "increment-wrap",
+ "decrement-wrap"
+};
+
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_state_face_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_state_face_descriptor.idl
deleted file mode 100644
index bcdca5fc5c7..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_stencil_state_face_descriptor.idl
+++ /dev/null
@@ -1,24 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUStencilStateFaceDescriptor {
- GPUCompareFunction compare = "always";
- GPUStencilOperation failOp = "keep";
- GPUStencilOperation depthFailOp = "keep";
- GPUStencilOperation passOp = "keep";
-};
-
-enum GPUStencilOperation {
- "keep",
- "zero",
- "replace",
- "invert",
- "increment-clamp",
- "decrement-clamp",
- "increment-wrap",
- "decrement-wrap"
-};
-
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl
new file mode 100644
index 00000000000..f9903b3009f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUStorageTextureBindingLayout {
+ required GPUStorageTextureAccess access;
+ required GPUTextureFormat format;
+ GPUTextureViewDimension viewDimension = "2d";
+};
+
+enum GPUStorageTextureAccess {
+ "read-only",
+ "write-only",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
index 3afa50c8458..e29955ffa2d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
@@ -16,14 +17,13 @@ GPUSwapChain::GPUSwapChain(GPUCanvasContext* context,
WGPUTextureUsage usage,
WGPUTextureFormat format,
SkFilterQuality filter_quality)
- : DeviceTreeObject(device->GetDeviceClientSerializerHolder()),
- device_(device),
+ : DawnObjectImpl(device),
context_(context),
usage_(usage),
format_(format) {
// TODO: Use label from GPUObjectDescriptorBase.
swap_buffers_ = base::AdoptRef(new WebGPUSwapBufferProvider(
- this, GetDawnControlClient(), GetDeviceClientID(), usage_, format));
+ this, GetDawnControlClient(), device->GetHandle(), usage_, format));
swap_buffers_->SetFilterQuality(filter_quality);
}
@@ -32,10 +32,9 @@ GPUSwapChain::~GPUSwapChain() {
}
void GPUSwapChain::Trace(Visitor* visitor) const {
- visitor->Trace(device_);
visitor->Trace(context_);
visitor->Trace(texture_);
- ScriptWrappable::Trace(visitor);
+ DawnObjectImpl::Trace(visitor);
}
void GPUSwapChain::Neuter() {
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
index 42f66b8d9d5..91842e005fd 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
@@ -18,8 +18,7 @@ class GPUCanvasContext;
class GPUDevice;
class GPUTexture;
-class GPUSwapChain : public ScriptWrappable,
- public DeviceTreeObject,
+class GPUSwapChain : public DawnObjectImpl,
public WebGPUSwapBufferProvider::Client {
DEFINE_WRAPPERTYPEINFO();
@@ -48,7 +47,6 @@ class GPUSwapChain : public ScriptWrappable,
scoped_refptr<WebGPUSwapBufferProvider> swap_buffers_;
- Member<GPUDevice> device_;
Member<GPUCanvasContext> context_;
WGPUTextureUsage usage_;
WGPUTextureFormat format_;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
index d69ae91cef6..7c688e18316 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
@@ -9,3 +9,4 @@
] interface GPUSwapChain {
GPUTexture getCurrentTexture();
};
+GPUSwapChain includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
index 8c98c6f0eb4..fe282e25f17 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -4,14 +4,24 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
+#include "gpu/command_buffer/client/webgpu_interface.h"
+#include "media/base/video_frame.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture_view.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
namespace blink {
+bool GPUTextureUsage::usedDeprecatedOutputAttachment = false;
+
namespace {
WGPUTextureDescriptor AsDawnType(const GPUTextureDescriptor* webgpu_desc,
@@ -21,20 +31,20 @@ WGPUTextureDescriptor AsDawnType(const GPUTextureDescriptor* webgpu_desc,
DCHECK(label);
DCHECK(device);
+ if (webgpu_desc->usage() & GPUTextureUsage::kRenderAttachment &&
+ GPUTextureUsage::usedDeprecatedOutputAttachment) {
+ GPUTextureUsage::usedDeprecatedOutputAttachment = false;
+ device->AddConsoleWarning(
+ "GPUTextureUsage.OUTPUT_ATTACHMENT has been "
+ "renamed to GPUTextureUsage.RENDER_ATTACHMENT.");
+ }
+
WGPUTextureDescriptor dawn_desc = {};
dawn_desc.nextInChain = nullptr;
dawn_desc.usage = static_cast<WGPUTextureUsage>(webgpu_desc->usage());
dawn_desc.dimension =
AsDawnEnum<WGPUTextureDimension>(webgpu_desc->dimension());
- dawn_desc.size = AsDawnType(&webgpu_desc->size());
- if (webgpu_desc->format() == "rg11b10float") {
- device->AddConsoleWarning(
- "rg11b10float is deprecated. Use rg11b10ufloat instead.");
- }
- if (webgpu_desc->format() == "bc6h-rgb-sfloat") {
- device->AddConsoleWarning(
- "bc6h-rgb-sfloat is deprecated. Use bc6h-rgb-float instead.");
- }
+ dawn_desc.size = AsDawnType(&webgpu_desc->size(), device);
dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
dawn_desc.mipLevelCount = webgpu_desc->mipLevelCount();
dawn_desc.sampleCount = webgpu_desc->sampleCount();
@@ -80,22 +90,131 @@ GPUTexture* GPUTexture::Create(GPUDevice* device,
DCHECK(device);
DCHECK(webgpu_desc);
- // Check size is correctly formatted before further processing.
- const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& size =
- webgpu_desc->size();
- if (size.IsUnsignedLongEnforceRangeSequence() &&
- size.GetAsUnsignedLongEnforceRangeSequence().size() != 3) {
- exception_state.ThrowRangeError("size length must be 3");
- return nullptr;
- }
-
std::string label;
WGPUTextureDescriptor dawn_desc = AsDawnType(webgpu_desc, &label, device);
- return MakeGarbageCollected<GPUTexture>(
+ GPUTexture* texture = MakeGarbageCollected<GPUTexture>(
device,
device->GetProcs().deviceCreateTexture(device->GetHandle(), &dawn_desc),
dawn_desc.format);
+ texture->setLabel(webgpu_desc->label());
+ return texture;
+}
+
+// static
+GPUTexture* GPUTexture::FromVideo(GPUDevice* device,
+ HTMLVideoElement* video,
+ WGPUTextureUsage usage,
+ ExceptionState& exception_state) {
+ if (!video || !video->videoWidth() || !video->videoHeight()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Missing video source");
+ return nullptr;
+ }
+
+ if (video->WouldTaintOrigin()) {
+ exception_state.ThrowSecurityError(
+ "Video element contains cross-origin data and may not be loaded.");
+ return nullptr;
+ }
+
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+ scoped_refptr<media::VideoFrame> media_video_frame;
+ if (auto* wmp = video->GetWebMediaPlayer()) {
+ media_video_frame = wmp->GetCurrentFrame();
+ video_renderer = wmp->GetPaintCanvasVideoRenderer();
+ }
+
+ if (!media_video_frame || !video_renderer) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Failed to import texture from video");
+ return nullptr;
+ }
+
+ // Create a CanvasResourceProvider for producing WebGPU-compatible shared
+ // images.
+ // TODO(crbug.com/1174809): This should recycle resources instead of creating
+ // a new shared image every time.
+ const auto intrinsic_size = IntSize(media_video_frame->natural_size());
+ std::unique_ptr<CanvasResourceProvider> resource_provider =
+ CanvasResourceProvider::CreateWebGPUImageProvider(
+ intrinsic_size, kLow_SkFilterQuality,
+ CanvasResourceParams(CanvasColorSpace::kSRGB, kN32_SkColorType,
+ kPremul_SkAlphaType),
+ CanvasResourceProvider::ShouldInitialize::kNo,
+ SharedGpuContext::ContextProviderWrapper());
+
+ if (!resource_provider) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Failed to import texture from video");
+ return nullptr;
+ }
+
+ viz::RasterContextProvider* raster_context_provider = nullptr;
+ if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
+ if (auto* context_provider = wrapper->ContextProvider())
+ raster_context_provider = context_provider->RasterContextProvider();
+ }
+
+ // TODO(crbug.com/1174809): This isn't efficient for VideoFrames which are
+ // already available as a shared image. A WebGPUMailboxTexture should be
+ // created directly from the VideoFrame instead.
+ const auto dest_rect = gfx::Rect(media_video_frame->natural_size());
+ if (!DrawVideoFrameIntoResourceProvider(
+ std::move(media_video_frame), resource_provider.get(),
+ raster_context_provider, dest_rect, video_renderer)) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+ "Failed to import texture from video");
+ return nullptr;
+ }
+
+ // Acquire the CanvasResource wrapping the shared image.
+ scoped_refptr<CanvasResource> canvas_resource =
+ resource_provider->ProduceCanvasResource();
+ DCHECK(canvas_resource->IsValid());
+ DCHECK(canvas_resource->IsAccelerated());
+
+ // Extract the format. This is only used to validate copyImageBitmapToTexture
+ // right now. We may want to reflect it from this function or validate it
+ // against some input parameters.
+ WGPUTextureFormat format;
+ switch (canvas_resource->CreateSkImageInfo().colorType()) {
+ case SkColorType::kRGBA_8888_SkColorType:
+ format = WGPUTextureFormat_RGBA8Unorm;
+ break;
+ case SkColorType::kBGRA_8888_SkColorType:
+ format = WGPUTextureFormat_BGRA8Unorm;
+ break;
+ case SkColorType::kRGBA_1010102_SkColorType:
+ format = WGPUTextureFormat_RGB10A2Unorm;
+ break;
+ case SkColorType::kRGBA_F16_SkColorType:
+ format = WGPUTextureFormat_RGBA16Float;
+ break;
+ case SkColorType::kRGBA_F32_SkColorType:
+ format = WGPUTextureFormat_RGBA32Float;
+ break;
+ case SkColorType::kR8G8_unorm_SkColorType:
+ format = WGPUTextureFormat_RG8Unorm;
+ break;
+ case SkColorType::kR16G16_float_SkColorType:
+ format = WGPUTextureFormat_RG16Float;
+ break;
+ default:
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kOperationError,
+ "Failed to import texture from video. Unsupported format.");
+ return nullptr;
+ }
+
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture =
+ WebGPUMailboxTexture::FromCanvasResource(device->GetDawnControlClient(),
+ device->GetHandle(), usage,
+ std::move(canvas_resource));
+ DCHECK(mailbox_texture->GetTexture() != nullptr);
+
+ return MakeGarbageCollected<GPUTexture>(device, format,
+ std::move(mailbox_texture));
}
GPUTexture::GPUTexture(GPUDevice* device,
@@ -103,12 +222,12 @@ GPUTexture::GPUTexture(GPUDevice* device,
WGPUTextureFormat format)
: DawnObject<WGPUTexture>(device, texture), format_(format) {}
-GPUTexture::~GPUTexture() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().textureRelease(GetHandle());
-}
+GPUTexture::GPUTexture(GPUDevice* device,
+ WGPUTextureFormat format,
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture)
+ : DawnObject<WGPUTexture>(device, mailbox_texture->GetTexture()),
+ format_(format),
+ mailbox_texture_(std::move(mailbox_texture)) {}
GPUTextureView* GPUTexture::createView(
const GPUTextureViewDescriptor* webgpu_desc) {
@@ -116,12 +235,15 @@ GPUTextureView* GPUTexture::createView(
std::string label;
WGPUTextureViewDescriptor dawn_desc = AsDawnType(webgpu_desc, &label);
- return MakeGarbageCollected<GPUTextureView>(
+ GPUTextureView* view = MakeGarbageCollected<GPUTextureView>(
device_, GetProcs().textureCreateView(GetHandle(), &dawn_desc));
+ view->setLabel(webgpu_desc->label());
+ return view;
}
void GPUTexture::destroy() {
GetProcs().textureDestroy(GetHandle());
+ mailbox_texture_.reset();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.h
index 202a4909b14..faf52d08059 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.h
@@ -6,13 +6,17 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_TEXTURE_H_
#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace blink {
class ExceptionState;
+class HTMLVideoElement;
class GPUTextureDescriptor;
class GPUTextureView;
class GPUTextureViewDescriptor;
+class StaticBitmapImage;
+class WebGPUMailboxTexture;
class GPUTexture : public DawnObject<WGPUTexture> {
DEFINE_WRAPPERTYPEINFO();
@@ -21,10 +25,15 @@ class GPUTexture : public DawnObject<WGPUTexture> {
static GPUTexture* Create(GPUDevice* device,
const GPUTextureDescriptor* webgpu_desc,
ExceptionState& exception_state);
- explicit GPUTexture(GPUDevice* device,
- WGPUTexture texture,
- WGPUTextureFormat format);
- ~GPUTexture() override;
+ static GPUTexture* FromVideo(GPUDevice* device,
+ HTMLVideoElement* video,
+ WGPUTextureUsage usage,
+ ExceptionState& exception_state);
+
+ GPUTexture(GPUDevice* device, WGPUTexture texture, WGPUTextureFormat format);
+ GPUTexture(GPUDevice* device,
+ WGPUTextureFormat format,
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture);
// gpu_texture.idl
GPUTextureView* createView(const GPUTextureViewDescriptor* webgpu_desc);
@@ -34,6 +43,7 @@ class GPUTexture : public DawnObject<WGPUTexture> {
private:
WGPUTextureFormat format_;
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture_;
DISALLOW_COPY_AND_ASSIGN(GPUTexture);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
index 868ea15af32..b4523829f15 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
@@ -10,3 +10,4 @@
GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});
void destroy();
};
+GPUTexture includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_binding_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_binding_layout.idl
new file mode 100644
index 00000000000..e0945872eee
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_binding_layout.idl
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUTextureBindingLayout {
+ GPUTextureSampleType sampleType = "float";
+ GPUTextureViewDimension viewDimension = "2d";
+ boolean multisampled = false;
+};
+
+enum GPUTextureSampleType {
+ "float",
+ "unfilterable-float",
+ "depth",
+ "sint",
+ "uint",
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_copy_view.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_copy_view.idl
deleted file mode 100644
index 474ad13515c..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_copy_view.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://gpuweb.github.io/gpuweb/
-
-dictionary GPUTextureCopyView {
- required GPUTexture texture;
- GPUSize32 mipLevel = 0;
- GPUOrigin3D origin = {};
- GPUTextureAspect aspect = "all";
-};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_data_layout.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_data_layout.idl
deleted file mode 100644
index 7f7a46b165e..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_data_layout.idl
+++ /dev/null
@@ -1,11 +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.
-
-// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedatalayout
-
-dictionary GPUTextureDataLayout {
- GPUSize64 offset = 0;
- GPUSize32 bytesPerRow;
- GPUSize32 rowsPerImage;
-};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
index 820b341f7a5..a64fd53e9d5 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
@@ -50,7 +50,6 @@ enum GPUTextureFormat {
/* Packed 32 bit formats */
"rgb9e5ufloat",
"rgb10a2unorm",
- "rg11b10float",
"rg11b10ufloat",
/* Normal 64 bit formats */
"rg32uint",
@@ -80,7 +79,6 @@ enum GPUTextureFormat {
"bc5-rg-snorm",
"bc6h-rgb-ufloat",
"bc6h-rgb-float",
- "bc6h-rgb-sfloat",
"bc7-rgba-unorm",
"bc7-rgba-unorm-srgb"
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h
index 4455467dafc..f0505b87f7d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h
@@ -18,7 +18,13 @@ class GPUTextureUsage : public ScriptWrappable {
static constexpr uint32_t kCopyDst = 2;
static constexpr uint32_t kSampled = 4;
static constexpr uint32_t kStorage = 8;
- static constexpr uint32_t kOutputAttachment = 16;
+ static constexpr uint32_t kRenderAttachment = 16;
+
+ static bool usedDeprecatedOutputAttachment;
+ static uint32_t OUTPUT_ATTACHMENT() {
+ usedDeprecatedOutputAttachment = true;
+ return kRenderAttachment;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(GPUTextureUsage);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
index e0cd42e225e..1ad2c8c8af8 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
@@ -12,5 +12,8 @@ typedef [EnforceRange] unsigned long GPUTextureUsageFlags;
const unsigned long COPY_DST = 2;
const unsigned long SAMPLED = 4;
const unsigned long STORAGE = 8;
- const unsigned long OUTPUT_ATTACHMENT = 16;
+ const unsigned long RENDER_ATTACHMENT = 16;
+
+ // Deprecated.
+ static readonly attribute unsigned long OUTPUT_ATTACHMENT;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.cc
index 91641b180f0..9b87f22f88b 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.cc
@@ -11,11 +11,4 @@ namespace blink {
GPUTextureView::GPUTextureView(GPUDevice* device, WGPUTextureView texture_view)
: DawnObject<WGPUTextureView>(device, texture_view) {}
-GPUTextureView::~GPUTextureView() {
- if (IsDawnControlClientDestroyed()) {
- return;
- }
- GetProcs().textureViewRelease(GetHandle());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.h
index 3eb00bcb86b..ff00b070f21 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.h
@@ -14,7 +14,6 @@ class GPUTextureView : public DawnObject<WGPUTextureView> {
public:
explicit GPUTextureView(GPUDevice* device, WGPUTextureView texture_view);
- ~GPUTextureView() override;
private:
DISALLOW_COPY_AND_ASSIGN(GPUTextureView);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
index 03d36268dc8..0b9b79db1a4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
@@ -8,3 +8,4 @@
Exposed(Window WebGPU, Worker WebGPU)
] interface GPUTextureView {
};
+GPUTextureView includes GPUObjectBase;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/idls.gni b/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
index 31dad915217..9e713df4b49 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
@@ -43,28 +43,31 @@ modules_dictionary_idl_files = [
"gpu_bind_group_entry.idl",
"gpu_bind_group_layout_descriptor.idl",
"gpu_bind_group_layout_entry.idl",
- "gpu_blend_descriptor.idl",
+ "gpu_blend_state.idl",
"gpu_buffer_binding.idl",
- "gpu_buffer_copy_view.idl",
+ "gpu_buffer_binding_layout.idl",
"gpu_buffer_descriptor.idl",
"gpu_color_dict.idl",
- "gpu_color_state_descriptor.idl",
+ "gpu_color_target_state.idl",
"gpu_command_buffer_descriptor.idl",
"gpu_command_encoder_descriptor.idl",
"gpu_compute_pass_descriptor.idl",
"gpu_compute_pipeline_descriptor.idl",
- "gpu_depth_stencil_state_descriptor.idl",
+ "gpu_depth_stencil_state.idl",
"gpu_device_descriptor.idl",
"gpu_extent_3d_dict.idl",
"gpu_fence_descriptor.idl",
- "gpu_image_bitmap_copy_view.idl",
+ "gpu_image_copy_buffer.idl",
+ "gpu_image_copy_image_bitmap.idl",
+ "gpu_image_copy_texture.idl",
+ "gpu_image_data_layout.idl",
"gpu_limits.idl",
"gpu_object_descriptor_base.idl",
"gpu_origin_2d_dict.idl",
"gpu_origin_3d_dict.idl",
"gpu_pipeline_descriptor_base.idl",
"gpu_pipeline_layout_descriptor.idl",
- "gpu_programmable_stage_descriptor.idl",
+ "gpu_programmable_stage.idl",
"gpu_query_set_descriptor.idl",
"gpu_rasterization_state_descriptor.idl",
"gpu_render_bundle_descriptor.idl",
@@ -74,12 +77,13 @@ modules_dictionary_idl_files = [
"gpu_render_pass_descriptor.idl",
"gpu_render_pipeline_descriptor.idl",
"gpu_request_adapter_options.idl",
+ "gpu_sampler_binding_layout.idl",
"gpu_sampler_descriptor.idl",
"gpu_shader_module_descriptor.idl",
- "gpu_stencil_state_face_descriptor.idl",
+ "gpu_stencil_face_state.idl",
+ "gpu_storage_texture_binding_layout.idl",
"gpu_swap_chain_descriptor.idl",
- "gpu_texture_copy_view.idl",
- "gpu_texture_data_layout.idl",
+ "gpu_texture_binding_layout.idl",
"gpu_texture_descriptor.idl",
"gpu_texture_view_descriptor.idl",
"gpu_uncaptured_error_event_init.idl",
@@ -89,6 +93,8 @@ modules_dictionary_idl_files = [
]
modules_dependency_idl_files = [
+ "gpu_object_base.idl",
+ "gpu_pipeline_base.idl",
"gpu_programmable_pass_encoder.idl",
"gpu_render_encoder_base.idl",
"navigator_gpu.idl",
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc b/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
deleted file mode 100644
index 67659bf4d2a..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
+++ /dev/null
@@ -1,50 +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/webgpu/navigator_gpu.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/webgpu/gpu.h"
-
-namespace blink {
-
-// static
-NavigatorGPU& NavigatorGPU::From(Navigator& navigator) {
- NavigatorGPU* supplement =
- Supplement<Navigator>::From<NavigatorGPU>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorGPU>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-GPU* NavigatorGPU::gpu(ScriptState* script_state, Navigator& navigator) {
- return NavigatorGPU::From(navigator).gpu(script_state);
-}
-
-GPU* NavigatorGPU::gpu(ScriptState* script_state) {
- if (!gpu_) {
- ExecutionContext* context = ExecutionContext::From(script_state);
- DCHECK(context);
-
- gpu_ = GPU::Create(*context);
- }
- return gpu_;
-}
-
-void NavigatorGPU::Trace(Visitor* visitor) const {
- visitor->Trace(gpu_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-NavigatorGPU::NavigatorGPU(Navigator& navigator)
- : Supplement<Navigator>(navigator) {}
-
-const char NavigatorGPU::kSupplementName[] = "NavigatorGPU";
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.h b/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.h
deleted file mode 100644
index 8608e8a56e8..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.h
+++ /dev/null
@@ -1,41 +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_WEBGPU_NAVIGATOR_GPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_NAVIGATOR_GPU_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class GPU;
-
-class NavigatorGPU final : public GarbageCollected<NavigatorGPU>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- // Gets, or creates, NavigatorGPU supplement on Navigator.
- // See platform/Supplementable.h
- static NavigatorGPU& From(Navigator&);
-
- static GPU* gpu(ScriptState* script_state, Navigator&);
- GPU* gpu(ScriptState* script_state);
-
- explicit NavigatorGPU(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<GPU> gpu_;
-
- DISALLOW_COPY_AND_ASSIGN(NavigatorGPU);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_NAVIGATOR_GPU_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl b/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl
index 1ee4f3f6888..29a6f57450f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl
@@ -6,7 +6,7 @@
[
Exposed=Window,
- ImplementedAs=NavigatorGPU
+ ImplementedAs=GPU
] partial interface Navigator {
- [SameObject, RuntimeEnabled=WebGPU, CallWith=ScriptState] readonly attribute GPU gpu;
+ [SameObject, RuntimeEnabled=WebGPU] readonly attribute GPU gpu;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc b/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc
deleted file mode 100644
index 05762efec8f..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc
+++ /dev/null
@@ -1,49 +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/webgpu/worker_navigator_gpu.h"
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/webgpu/gpu.h"
-
-namespace blink {
-
-// static
-WorkerNavigatorGPU& WorkerNavigatorGPU::From(WorkerNavigator& navigator) {
- WorkerNavigatorGPU* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorGPU>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorGPU>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state,
- WorkerNavigator& navigator) {
- return WorkerNavigatorGPU::From(navigator).gpu(script_state);
-}
-
-GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state) {
- if (!gpu_) {
- ExecutionContext* context = ExecutionContext::From(script_state);
- DCHECK(context);
-
- gpu_ = GPU::Create(*context);
- }
- return gpu_;
-}
-
-void WorkerNavigatorGPU::Trace(Visitor* visitor) const {
- visitor->Trace(gpu_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-WorkerNavigatorGPU::WorkerNavigatorGPU(WorkerNavigator& navigator)
- : Supplement<WorkerNavigator>(navigator) {}
-
-const char WorkerNavigatorGPU::kSupplementName[] = "WorkerNavigatorGPU";
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h b/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h
deleted file mode 100644
index c22f5cf3367..00000000000
--- a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h
+++ /dev/null
@@ -1,41 +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_WEBGPU_WORKER_NAVIGATOR_GPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class GPU;
-class WorkerNavigator;
-
-class WorkerNavigatorGPU final : public GarbageCollected<WorkerNavigatorGPU>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- // Gets, or creates, WorkerNavigatorGPU supplement on WorkerNavigator.
- // See platform/Supplementable.h
- static WorkerNavigatorGPU& From(WorkerNavigator&);
-
- static GPU* gpu(ScriptState* script_state, WorkerNavigator&);
- GPU* gpu(ScriptState* script_state);
-
- explicit WorkerNavigatorGPU(WorkerNavigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<GPU> gpu_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerNavigatorGPU);
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl b/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
index e69ee47abfc..28279fc3a04 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
@@ -6,7 +6,7 @@
[
Exposed=Worker,
- ImplementedAs=WorkerNavigatorGPU
+ ImplementedAs=GPU
] partial interface WorkerNavigator {
- [SameObject, RuntimeEnabled=WebGPU, CallWith=ScriptState] readonly attribute GPU gpu;
+ [SameObject, RuntimeEnabled=WebGPU] readonly attribute GPU gpu;
};
diff --git a/chromium/third_party/blink/renderer/modules/webid/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webid/DIR_METADATA
new file mode 100644
index 00000000000..483421308cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webid/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Identity>WebID"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webid/OWNERS b/chromium/third_party/blink/renderer/modules/webid/OWNERS
index 719c8fd4ccc..cfed0af3c46 100644
--- a/chromium/third_party/blink/renderer/modules/webid/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webid/OWNERS
@@ -1,3 +1 @@
file://content/browser/webid/OWNERS
-
-# COMPONENT: Blink>Identity>WebID
diff --git a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.cc b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.cc
index e69acde4e95..485d25d6e00 100644
--- a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.cc
+++ b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.cc
@@ -11,34 +11,34 @@
namespace blink {
-const char NavigatorWebID::kSupplementName[] = "NavigatorWebID";
+const char NavigatorWebId::kSupplementName[] = "NavigatorWebId";
-NavigatorWebID& NavigatorWebID::From(Navigator& navigator) {
- NavigatorWebID* supplement =
- Supplement<Navigator>::From<NavigatorWebID>(navigator);
+NavigatorWebId& NavigatorWebId::From(Navigator& navigator) {
+ NavigatorWebId* supplement =
+ Supplement<Navigator>::From<NavigatorWebId>(navigator);
if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorWebID>(navigator);
- NavigatorWebID::ProvideTo(navigator, supplement);
+ supplement = MakeGarbageCollected<NavigatorWebId>(navigator);
+ NavigatorWebId::ProvideTo(navigator, supplement);
}
return *supplement;
}
-WebID* NavigatorWebID::id(Navigator& navigator) {
- return NavigatorWebID::From(navigator).id();
+WebId* NavigatorWebId::id(Navigator& navigator) {
+ return NavigatorWebId::From(navigator).id();
}
-WebID* NavigatorWebID::id() {
+WebId* NavigatorWebId::id() {
return web_id_;
}
-void NavigatorWebID::Trace(Visitor* visitor) const {
+void NavigatorWebId::Trace(Visitor* visitor) const {
visitor->Trace(web_id_);
Supplement<Navigator>::Trace(visitor);
}
-NavigatorWebID::NavigatorWebID(Navigator& navigator) {
+NavigatorWebId::NavigatorWebId(Navigator& navigator) {
if (navigator.DomWindow()) {
- web_id_ = MakeGarbageCollected<WebID>(*navigator.DomWindow());
+ web_id_ = MakeGarbageCollected<WebId>(*navigator.DomWindow());
}
}
diff --git a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.h b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.h
index 3d0ac457a47..257be8c2387 100644
--- a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.h
+++ b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.h
@@ -12,26 +12,26 @@
namespace blink {
class Navigator;
-class WebID;
+class WebId;
-class NavigatorWebID final : public GarbageCollected<NavigatorWebID>,
+class NavigatorWebId final : public GarbageCollected<NavigatorWebId>,
public Supplement<Navigator> {
public:
static const char kSupplementName[];
// Gets, or creates, NavigatorID supplement on Navigator.
// See platform/Supplementable.h
- static NavigatorWebID& From(Navigator&);
+ static NavigatorWebId& From(Navigator&);
- static WebID* id(Navigator&);
- WebID* id();
+ static WebId* id(Navigator&);
+ WebId* id();
void Trace(Visitor*) const override;
- explicit NavigatorWebID(Navigator&);
+ explicit NavigatorWebId(Navigator&);
private:
- Member<WebID> web_id_;
+ Member<WebId> web_id_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.idl b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.idl
index fbfa1c1cf0b..ed16cf093e2 100644
--- a/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.idl
+++ b/chromium/third_party/blink/renderer/modules/webid/navigator_web_id.idl
@@ -6,8 +6,8 @@
[
SecureContext,
Exposed=Window,
- ImplementedAs=NavigatorWebID,
+ ImplementedAs=NavigatorWebId,
RuntimeEnabled=WebID
] partial interface Navigator {
- [SameObject] readonly attribute WebID id;
+ [SameObject] readonly attribute WebId id;
};
diff --git a/chromium/third_party/blink/renderer/modules/webid/web_id.cc b/chromium/third_party/blink/renderer/modules/webid/web_id.cc
index f69efd73db6..dbffc2d5bec 100644
--- a/chromium/third_party/blink/renderer/modules/webid/web_id.cc
+++ b/chromium/third_party/blink/renderer/modules/webid/web_id.cc
@@ -7,8 +7,8 @@
#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_web_id_request_options.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/modules/webid/web_id_request_options.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -19,22 +19,91 @@ namespace blink {
namespace {
void OnRequestIdToken(ScriptPromiseResolver* resolver,
+ mojom::blink::RequestIdTokenStatus status,
const WTF::String& id_token) {
- resolver->Resolve(id_token);
+ switch (status) {
+ case mojom::blink::RequestIdTokenStatus::kApprovalDeclined: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError, "User declined the sign-in attempt."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kErrorTooManyRequests: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError,
+ "Only one navigator.id.get request may be outstanding at one time."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::
+ kErrorWebIdNotSupportedByProvider: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "The indicated provider does not support WebID."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kErrorFetchingWellKnown: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "Error fetching the provider's .well-known configuration."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kErrorInvalidWellKnown: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "Provider's .well-known configuration is invalid."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kErrorFetchingSignin: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "Error attempting to reach the provider's sign-in endpoint."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kErrorInvalidSigninResponse: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError,
+ "Provider's sign-in response is invalid"));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kError: {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError, "Error retrieving an id token."));
+ return;
+ }
+ case mojom::blink::RequestIdTokenStatus::kSuccess: {
+ resolver->Resolve(id_token);
+ return;
+ }
+ }
+}
+
+void OnProvideIdToken(ScriptPromiseResolver* resolver,
+ mojom::blink::ProvideIdTokenStatus status) {
+ // TODO(kenrb): Provide better messages for different error codes.
+ if (status != mojom::blink::ProvideIdTokenStatus::kSuccess) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNetworkError, "Error providing the id token."));
+ return;
+ }
+ resolver->Resolve();
}
} // namespace
-WebID::WebID(ExecutionContext& context)
- : ExecutionContextClient(&context), auth_request_(&context) {}
+WebId::WebId(ExecutionContext& context)
+ : ExecutionContextClient(&context),
+ auth_request_(&context),
+ auth_response_(&context) {}
-ScriptPromise WebID::get(ScriptState* script_state,
- const WebIDRequestOptions* options,
+ScriptPromise WebId::get(ScriptState* script_state,
+ const WebIdRequestOptions* options,
ExceptionState& exception_state) {
- auto* context = GetExecutionContext();
-
if (!options->hasProvider()) {
- exception_state.ThrowTypeError("Provider is required.");
+ exception_state.ThrowTypeError("Invalid parameters: provider required.");
+ return ScriptPromise();
+ }
+
+ if (!options->hasRequest()) {
+ exception_state.ThrowTypeError("Invalid parameters: request required.");
return ScriptPromise();
}
@@ -48,33 +117,59 @@ ScriptPromise WebID::get(ScriptState* script_state,
return ScriptPromise();
}
- if (!auth_request_.is_bound()) {
- // TODO(kenrb): Work out whether kUserInteraction is the best task type
- // here. It might be appropriate to create a new one.
- context->GetBrowserInterfaceBroker().GetInterface(
- auth_request_.BindNewPipeAndPassReceiver(
- context->GetTaskRunner(TaskType::kUserInteraction)));
- auth_request_.set_disconnect_handler(
- WTF::Bind(&WebID::OnConnectionError, WrapWeakPersistent(this)));
- }
+ BindRemote(auth_request_);
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auth_request_->RequestIdToken(
- provider, WTF::Bind(&OnRequestIdToken, WrapPersistent(resolver)));
+ provider, options->request(),
+ WTF::Bind(&OnRequestIdToken, WrapPersistent(resolver)));
+
+ return promise;
+}
+
+ScriptPromise WebId::provide(ScriptState* script_state, String id_token) {
+ BindRemote(auth_response_);
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ auth_response_->ProvideIdToken(
+ id_token, WTF::Bind(&OnProvideIdToken, WrapPersistent(resolver)));
return promise;
}
-void WebID::Trace(blink::Visitor* visitor) const {
+template <typename Interface>
+void WebId::BindRemote(HeapMojoRemote<Interface>& remote) {
+ auto* context = GetExecutionContext();
+
+ if (remote.is_bound())
+ return;
+
+ // TODO(kenrb): Work out whether kUserInteraction is the best task type
+ // here. It might be appropriate to create a new one.
+ context->GetBrowserInterfaceBroker().GetInterface(
+ remote.BindNewPipeAndPassReceiver(
+ context->GetTaskRunner(TaskType::kUserInteraction)));
+ remote.set_disconnect_handler(
+ WTF::Bind(&WebId::OnConnectionError, WrapWeakPersistent(this)));
+}
+
+void WebId::Trace(blink::Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
ExecutionContextClient::Trace(visitor);
visitor->Trace(auth_request_);
+ visitor->Trace(auth_response_);
}
-void WebID::OnConnectionError() {
+void WebId::OnConnectionError() {
auth_request_.reset();
+ // TODO(majidvp): We should handle connection errors for request and response
+ // separately.
+ auth_response_.reset();
+
// TODO(kenrb): Cache the resolver and resolve the promise with an
// appropriate error message.
}
diff --git a/chromium/third_party/blink/renderer/modules/webid/web_id.h b/chromium/third_party/blink/renderer/modules/webid/web_id.h
index b2c8793c838..276b3fa1e22 100644
--- a/chromium/third_party/blink/renderer/modules/webid/web_id.h
+++ b/chromium/third_party/blink/renderer/modules/webid/web_id.h
@@ -5,8 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBID_WEB_ID_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBID_WEB_ID_H_
-#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/blink/public/mojom/webid/federated_auth_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/webid/federated_auth_response.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -14,27 +14,31 @@
namespace blink {
-class WebIDRequestOptions;
+class WebIdRequestOptions;
class ExceptionState;
class ExecutionContext;
class ScriptPromise;
class ScriptState;
-class WebID final : public ScriptWrappable, public ExecutionContextClient {
+class WebId final : public ScriptWrappable, public ExecutionContextClient {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit WebID(ExecutionContext&);
+ explicit WebId(ExecutionContext&);
// WebID IDL interface.
- ScriptPromise get(ScriptState*, const WebIDRequestOptions*, ExceptionState&);
+ ScriptPromise get(ScriptState*, const WebIdRequestOptions*, ExceptionState&);
+ ScriptPromise provide(ScriptState*, String id_token);
void Trace(blink::Visitor*) const override;
private:
+ template <typename Interface>
+ void BindRemote(HeapMojoRemote<Interface>& remote);
void OnConnectionError();
HeapMojoRemote<mojom::blink::FederatedAuthRequest> auth_request_;
+ HeapMojoRemote<mojom::blink::FederatedAuthResponse> auth_response_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webid/web_id.idl b/chromium/third_party/blink/renderer/modules/webid/web_id.idl
index 4943618168d..111b67da991 100644
--- a/chromium/third_party/blink/renderer/modules/webid/web_id.idl
+++ b/chromium/third_party/blink/renderer/modules/webid/web_id.idl
@@ -8,7 +8,9 @@
SecureContext,
Exposed=(Window),
RuntimeEnabled=WebID
-] interface WebID {
+] interface WebId {
[CallWith=ScriptState, RaisesException]
- Promise<DOMString> get(optional WebIDRequestOptions options = {});
+ Promise<DOMString> get(optional WebIdRequestOptions options = {});
+ [CallWith=ScriptState]
+ Promise<void> provide(optional DOMString id_token = "");
};
diff --git a/chromium/third_party/blink/renderer/modules/webid/web_id_request_options.idl b/chromium/third_party/blink/renderer/modules/webid/web_id_request_options.idl
index b84c01f5707..0da53732eca 100644
--- a/chromium/third_party/blink/renderer/modules/webid/web_id_request_options.idl
+++ b/chromium/third_party/blink/renderer/modules/webid/web_id_request_options.idl
@@ -4,6 +4,9 @@
// https://github.com/WICG/WebID
-dictionary WebIDRequestOptions {
+dictionary WebIdRequestOptions {
+ // URL for the Identity Provider.
USVString provider;
+ // Serialized request parameters.
+ USVString request;
};
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webmidi/DIR_METADATA
new file mode 100644
index 00000000000..0237b65e856
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webmidi/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>WebMIDI"
+}
+team_email: "midi-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/OWNERS b/chromium/third_party/blink/renderer/modules/webmidi/OWNERS
index 1a8a48de571..eed18af1fc9 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webmidi/OWNERS
@@ -1,6 +1,3 @@
kouhei@chromium.org
toyoshim@chromium.org
yhirano@chromium.org
-
-# TEAM: midi-dev@chromium.org
-# COMPONENT: Blink>WebMIDI
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 cbc52a63f97..88ccf042f3f 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
@@ -101,8 +101,13 @@ void MIDIDispatcher::SetOutputPortState(uint32_t port,
void MIDIDispatcher::SessionStarted(midi::mojom::blink::Result result) {
TRACE_EVENT0("midi", "MIDIDispatcher::OnSessionStarted");
+ // We always have a valid instance in `client_` in the production code, but
+ // just in case to be robust for mojo injections and code changes in the
+ // future. Other methods protect accesses to `client_` by `initialized_` flag
+ // that is set below.
+ SECURITY_CHECK(client_);
+
DCHECK(!initialized_);
- DCHECK(client_);
initialized_ = true;
if (result == midi::mojom::blink::Result::OK) {
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_message_event.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_message_event.cc
index 1b5853cece8..1627a376741 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_message_event.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_message_event.cc
@@ -12,7 +12,7 @@ MIDIMessageEvent::MIDIMessageEvent(const AtomicString& type,
const MIDIMessageEventInit* initializer)
: Event(type, initializer) {
if (initializer->hasData())
- data_ = initializer->data().View();
+ data_ = initializer->data().Get();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc
index 2bf69e9a8e5..e16c08488a5 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc
@@ -262,7 +262,7 @@ void MIDIOutput::send(NotShared<DOMUint8Array> array,
timestamp = GetTimeOrigin(context) +
base::TimeDelta::FromMillisecondsD(timestamp_in_milliseconds);
}
- SendInternal(array.View(), timestamp, exception_state);
+ SendInternal(array.Get(), timestamp, exception_state);
}
void MIDIOutput::send(Vector<unsigned> unsigned_data,
@@ -288,7 +288,7 @@ void MIDIOutput::send(NotShared<DOMUint8Array> data,
return;
DCHECK(data);
- SendInternal(data.View(), base::TimeTicks::Now(), exception_state);
+ SendInternal(data.Get(), base::TimeTicks::Now(), exception_state);
}
void MIDIOutput::send(Vector<unsigned> unsigned_data,
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
index 4bbe6d74c77..331c2b03501 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -50,10 +50,10 @@ namespace blink {
namespace {
const char kFeaturePolicyErrorMessage[] =
- "Midi has been disabled in this document by Feature Policy.";
+ "Midi has been disabled in this document by permissions policy.";
const char kFeaturePolicyConsoleWarning[] =
- "Midi access has been blocked because of a Feature Policy applied to the "
- "current document. See https://goo.gl/EuHzyv for more details.";
+ "Midi access has been blocked because of a permissions policy applied to "
+ "the current document. See https://goo.gl/EuHzyv for more details.";
} // namespace
diff --git a/chromium/third_party/blink/renderer/modules/webrtc/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webrtc/DIR_METADATA
new file mode 100644
index 00000000000..5673a4c5f58
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webrtc/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>WebRTC"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webrtc/OWNERS b/chromium/third_party/blink/renderer/modules/webrtc/OWNERS
index c4d5a7de35e..21ecac2ba02 100644
--- a/chromium/third_party/blink/renderer/modules/webrtc/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webrtc/OWNERS
@@ -1,4 +1 @@
file://third_party/blink/renderer/modules/mediastream/OWNERS
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc b/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc
index b36ddd5d535..047145badbc 100644
--- a/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc
@@ -4,9 +4,9 @@
#include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "media/base/audio_bus.h"
@@ -97,7 +97,8 @@ void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
int64_t ntp_time_ms = -1;
int16_t* audio_data = render_buffer_.data();
- TRACE_EVENT_BEGIN0("audio", "VoE::PullRenderData");
+ TRACE_EVENT_BEGIN1("audio", "VoE::PullRenderData", "frames",
+ frames_per_10_ms);
audio_transport_callback_->PullRenderData(
kBytesPerSample * 8, sample_rate, audio_bus->channels(), frames_per_10_ms,
audio_data, &elapsed_time_ms, &ntp_time_ms);
diff --git a/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc b/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
index 0ff5010f749..792de4697c2 100644
--- a/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
+++ b/chromium/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
@@ -212,7 +212,7 @@ class WebRtcAudioRenderer::InternalFrame {
if (!frame_)
return nullptr;
- return static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame()));
+ return static_cast<WebLocalFrame*>(WebFrame::FromCoreFrame(frame()));
}
private:
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 392f849305d..a942771d7b1 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_share_data.h"
@@ -130,7 +131,7 @@ NavigatorShare::ShareClientImpl::ShareClientImpl(
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::kWebShare,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
+ {SchedulingPolicy::DisableBackForwardCache()})) {}
void NavigatorShare::ShareClientImpl::Callback(mojom::blink::ShareError error) {
if (navigator_) {
@@ -207,13 +208,15 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
return ScriptPromise();
}
+ ExecutionContext* const execution_context =
+ ExecutionContext::From(script_state);
+
// The feature policy is currently not enforced.
LocalDOMWindow* const window = LocalDOMWindow::From(script_state);
- window->CountUse(
- ExecutionContext::From(script_state)
- ->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebShare)
- ? WebFeature::kWebSharePolicyAllow
- : WebFeature::kWebSharePolicyDisallow);
+ window->CountUse(execution_context->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kWebShare)
+ ? WebFeature::kWebSharePolicyAllow
+ : WebFeature::kWebSharePolicyDisallow);
if (client_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
@@ -222,6 +225,7 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
}
if (!LocalFrame::ConsumeTransientUserActivation(window->GetFrame())) {
+ VLOG(1) << "Share without transient activation (user gesture)";
exception_state.ThrowDOMException(
DOMExceptionCode::kNotAllowedError,
"Must be handling a user gesture to perform a share request.");
@@ -257,6 +261,9 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
if (files.size() > kMaxSharedFileCount ||
total_bytes > kMaxSharedFileBytes) {
+ execution_context->AddConsoleMessage(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning, "Share too large");
exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
"Permission denied");
return ScriptPromise();
diff --git a/chromium/third_party/blink/renderer/modules/webshare/navigator_share_test.cc b/chromium/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
index 8c442313b6f..f7efe9572f7 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
@@ -99,7 +99,7 @@ class NavigatorShareTest : public testing::Test {
EXPECT_EQ(mock_share_service_.error() == mojom::ShareError::OK
? v8::Promise::kFulfilled
: v8::Promise::kRejected,
- promise.V8Value().As<v8::Promise>()->State());
+ promise.V8Promise()->State());
}
MockShareService& mock_share_service() { return mock_share_service_; }
@@ -107,8 +107,8 @@ class NavigatorShareTest : public testing::Test {
protected:
void SetUp() override {
GetFrame().Loader().CommitNavigation(
- WebNavigationParams::CreateWithHTMLBuffer(SharedBuffer::Create(),
- KURL("https://example.com")),
+ WebNavigationParams::CreateWithHTMLBufferForTesting(
+ SharedBuffer::Create(), KURL("https://example.com")),
nullptr /* extra_data */);
test::RunPendingTasks();
diff --git a/chromium/third_party/blink/renderer/modules/websockets/BUILD.gn b/chromium/third_party/blink/renderer/modules/websockets/BUILD.gn
index 78e5791244b..c806a794adf 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/websockets/BUILD.gn
@@ -26,4 +26,6 @@ blink_modules_sources("websockets") {
"websocket_stream.cc",
"websocket_stream.h",
]
+
+ deps = [ "//services/network/public/mojom:websocket_mojom" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/websockets/DIR_METADATA b/chromium/third_party/blink/renderer/modules/websockets/DIR_METADATA
new file mode 100644
index 00000000000..70f997c2e51
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/websockets/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Network>WebSockets"
+}
+team_email: "blink-network-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/websockets/OWNERS b/chromium/third_party/blink/renderer/modules/websockets/OWNERS
index e765c190805..3dc0bbfbdc1 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/websockets/OWNERS
@@ -1,6 +1,3 @@
ricea@chromium.org
yhirano@chromium.org
yoichio@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>WebSockets
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 e479736ee36..7d16ecdde4a 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -61,7 +61,6 @@
#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/use_counter.h"
-#include "third_party/blink/renderer/platform/network/network_log.h"
#include "third_party/blink/renderer/platform/weborigin/known_ports.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -185,11 +184,11 @@ DOMWebSocket::DOMWebSocket(ExecutionContext* context)
extensions_(""),
event_queue_(MakeGarbageCollected<EventQueue>(this)),
buffered_amount_update_task_pending_(false) {
- NETWORK_DVLOG(1) << "DOMWebSocket " << this << " created";
+ DVLOG(1) << "DOMWebSocket " << this << " created";
}
DOMWebSocket::~DOMWebSocket() {
- NETWORK_DVLOG(1) << "DOMWebSocket " << this << " destroyed";
+ DVLOG(1) << "DOMWebSocket " << this << " destroyed";
DCHECK(!channel_);
}
@@ -246,7 +245,7 @@ void DOMWebSocket::Connect(const String& url,
ExceptionState& exception_state) {
UseCounter::Count(GetExecutionContext(), WebFeature::kWebSocket);
- NETWORK_DVLOG(1) << "WebSocket " << this << " connect() url=" << url;
+ DVLOG(1) << "WebSocket " << this << " connect() url=" << url;
channel_ = CreateChannel(GetExecutionContext(), this);
auto result = common_.Connect(GetExecutionContext(), url, protocols, channel_,
@@ -301,9 +300,9 @@ void DOMWebSocket::ReflectBufferedAmountConsumption() {
if (event_queue_->IsPaused())
return;
DCHECK_GE(buffered_amount_, consumed_buffered_amount_);
- NETWORK_DVLOG(1) << "WebSocket " << this
- << " reflectBufferedAmountConsumption() " << buffered_amount_
- << " => " << (buffered_amount_ - consumed_buffered_amount_);
+ DVLOG(1) << "WebSocket " << this << " reflectBufferedAmountConsumption() "
+ << buffered_amount_ << " => "
+ << (buffered_amount_ - consumed_buffered_amount_);
buffered_amount_ -= consumed_buffered_amount_;
consumed_buffered_amount_ = 0;
@@ -317,8 +316,7 @@ void DOMWebSocket::ReleaseChannel() {
void DOMWebSocket::send(const String& message,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " send() Sending String "
- << message;
+ DVLOG(1) << "WebSocket " << this << " send() Sending String " << message;
if (common_.GetState() == kConnecting) {
SetInvalidStateErrorForSendMethod(exception_state);
return;
@@ -340,8 +338,8 @@ void DOMWebSocket::send(const String& message,
void DOMWebSocket::send(DOMArrayBuffer* binary_data,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " send() Sending ArrayBuffer "
- << binary_data;
+ DVLOG(1) << "WebSocket " << this << " send() Sending ArrayBuffer "
+ << binary_data;
DCHECK(binary_data);
if (common_.GetState() == kConnecting) {
SetInvalidStateErrorForSendMethod(exception_state);
@@ -360,28 +358,27 @@ void DOMWebSocket::send(DOMArrayBuffer* binary_data,
void DOMWebSocket::send(NotShared<DOMArrayBufferView> array_buffer_view,
ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " send() Sending ArrayBufferView "
- << array_buffer_view.View();
+ DVLOG(1) << "WebSocket " << this << " send() Sending ArrayBufferView "
+ << array_buffer_view.Get();
DCHECK(array_buffer_view);
if (common_.GetState() == kConnecting) {
SetInvalidStateErrorForSendMethod(exception_state);
return;
}
if (common_.GetState() == kClosing || common_.GetState() == kClosed) {
- UpdateBufferedAmountAfterClose(array_buffer_view.View()->byteLength());
+ UpdateBufferedAmountAfterClose(array_buffer_view->byteLength());
return;
}
RecordSendTypeHistogram(WebSocketSendType::kArrayBufferView);
DCHECK(channel_);
- buffered_amount_ += array_buffer_view.View()->byteLength();
- channel_->Send(*array_buffer_view.View()->buffer(),
- array_buffer_view.View()->byteOffset(),
- array_buffer_view.View()->byteLength(), base::OnceClosure());
+ buffered_amount_ += array_buffer_view->byteLength();
+ channel_->Send(*array_buffer_view->buffer(), array_buffer_view->byteOffset(),
+ array_buffer_view->byteLength(), base::OnceClosure());
}
void DOMWebSocket::send(Blob* binary_data, ExceptionState& exception_state) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " send() Sending Blob "
- << binary_data->Uuid();
+ DVLOG(1) << "WebSocket " << this << " send() Sending Blob "
+ << binary_data->Uuid();
DCHECK(binary_data);
if (common_.GetState() == kConnecting) {
SetInvalidStateErrorForSendMethod(exception_state);
@@ -481,7 +478,7 @@ ExecutionContext* DOMWebSocket::GetExecutionContext() const {
}
void DOMWebSocket::ContextDestroyed() {
- NETWORK_DVLOG(1) << "WebSocket " << this << " contextDestroyed()";
+ DVLOG(1) << "WebSocket " << this << " contextDestroyed()";
event_queue_->ContextDestroyed();
if (channel_) {
ReleaseChannel();
@@ -511,7 +508,7 @@ void DOMWebSocket::ContextLifecycleStateChanged(
void DOMWebSocket::DidConnect(const String& subprotocol,
const String& extensions) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidConnect()";
+ DVLOG(1) << "WebSocket " << this << " DidConnect()";
if (common_.GetState() != kConnecting)
return;
common_.SetState(kOpen);
@@ -521,8 +518,8 @@ void DOMWebSocket::DidConnect(const String& subprotocol,
}
void DOMWebSocket::DidReceiveTextMessage(const String& msg) {
- NETWORK_DVLOG(1) << "WebSocket " << this
- << " DidReceiveTextMessage() Text message " << msg;
+ DVLOG(1) << "WebSocket " << this << " DidReceiveTextMessage() Text message "
+ << msg;
ReflectBufferedAmountConsumption();
DCHECK_NE(common_.GetState(), kConnecting);
if (common_.GetState() != kOpen)
@@ -538,8 +535,8 @@ void DOMWebSocket::DidReceiveBinaryMessage(
for (const auto& span : data) {
size += span.size();
}
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidReceiveBinaryMessage() "
- << size << " byte binary message";
+ DVLOG(1) << "WebSocket " << this << " DidReceiveBinaryMessage() " << size
+ << " byte binary message";
ReflectBufferedAmountConsumption();
DCHECK(!origin_string_.IsNull());
@@ -568,7 +565,7 @@ void DOMWebSocket::DidReceiveBinaryMessage(
}
void DOMWebSocket::DidError() {
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidError()";
+ DVLOG(1) << "WebSocket " << this << " DidError()";
ReflectBufferedAmountConsumption();
common_.SetState(kClosed);
event_queue_->Dispatch(Event::Create(event_type_names::kError));
@@ -576,8 +573,8 @@ void DOMWebSocket::DidError() {
void DOMWebSocket::DidConsumeBufferedAmount(uint64_t consumed) {
DCHECK_GE(buffered_amount_, consumed + consumed_buffered_amount_);
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidConsumeBufferedAmount("
- << consumed << ")";
+ DVLOG(1) << "WebSocket " << this << " DidConsumeBufferedAmount(" << consumed
+ << ")";
if (common_.GetState() == kClosed)
return;
consumed_buffered_amount_ += consumed;
@@ -585,7 +582,7 @@ void DOMWebSocket::DidConsumeBufferedAmount(uint64_t consumed) {
}
void DOMWebSocket::DidStartClosingHandshake() {
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidStartClosingHandshake()";
+ DVLOG(1) << "WebSocket " << this << " DidStartClosingHandshake()";
ReflectBufferedAmountConsumption();
common_.SetState(kClosing);
}
@@ -594,7 +591,7 @@ void DOMWebSocket::DidClose(
ClosingHandshakeCompletionStatus closing_handshake_completion,
uint16_t code,
const String& reason) {
- NETWORK_DVLOG(1) << "WebSocket " << this << " DidClose()";
+ DVLOG(1) << "WebSocket " << this << " DidClose()";
ReflectBufferedAmountConsumption();
if (!channel_)
return;
diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index e05a0a388ee..e99480df4a4 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -23,7 +23,7 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/impl/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
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 428e796f24e..198acd6322d 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
@@ -38,7 +38,7 @@
#include "base/feature_list.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
@@ -64,7 +64,6 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
-#include "third_party/blink/renderer/platform/network/network_log.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -207,7 +206,7 @@ WebSocketChannelImpl::WebSocketChannelImpl(
WebSocketChannelImpl::~WebSocketChannelImpl() = default;
bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
- NETWORK_DVLOG(1) << this << " Connect()";
+ DVLOG(1) << this << " Connect()";
if (GetBaseFetchContext()->ShouldBlockWebSocketByMixedContentCheck(url)) {
has_initiated_opening_handshake_ = false;
@@ -218,11 +217,9 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
feature_handle_for_scheduler_ = scheduler->RegisterFeature(
SchedulingPolicy::Feature::kWebSocket,
base::FeatureList::IsEnabled(kAllowAggressiveThrottlingWithWebSocket)
- ? SchedulingPolicy{SchedulingPolicy::
- RecordMetricsForBackForwardCache()}
- : SchedulingPolicy{
- SchedulingPolicy::DisableAggressiveThrottling(),
- SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ ? SchedulingPolicy{SchedulingPolicy::DisableBackForwardCache()}
+ : SchedulingPolicy{SchedulingPolicy::DisableAggressiveThrottling(),
+ SchedulingPolicy::DisableBackForwardCache()});
}
if (MixedContentChecker::IsMixedContent(
@@ -294,7 +291,7 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
WebSocketChannel::SendResult WebSocketChannelImpl::Send(
const std::string& message,
base::OnceClosure completion_callback) {
- NETWORK_DVLOG(1) << this << " Send(" << message << ") (std::string argument)";
+ DVLOG(1) << this << " Send(" << message << ") (std::string argument)";
probe::DidSendWebSocketMessage(execution_context_, identifier_,
WebSocketOpCode::kOpCodeText, true,
message.c_str(), message.length());
@@ -326,10 +323,10 @@ WebSocketChannel::SendResult WebSocketChannelImpl::Send(
void WebSocketChannelImpl::Send(
scoped_refptr<BlobDataHandle> blob_data_handle) {
- NETWORK_DVLOG(1) << this << " Send(" << blob_data_handle->Uuid() << ", "
- << blob_data_handle->GetType() << ", "
- << blob_data_handle->size() << ") "
- << "(BlobDataHandle argument)";
+ DVLOG(1) << this << " Send(" << blob_data_handle->Uuid() << ", "
+ << blob_data_handle->GetType() << ", " << blob_data_handle->size()
+ << ") "
+ << "(BlobDataHandle argument)";
// FIXME: We can't access the data here.
// Since Binary data are not displayed in Inspector, this does not
// affect actual behavior.
@@ -344,9 +341,9 @@ WebSocketChannel::SendResult WebSocketChannelImpl::Send(
size_t byte_offset,
size_t byte_length,
base::OnceClosure completion_callback) {
- NETWORK_DVLOG(1) << this << " Send(" << buffer.Data() << ", " << byte_offset
- << ", " << byte_length << ") "
- << "(DOMArrayBuffer argument)";
+ DVLOG(1) << this << " Send(" << buffer.Data() << ", " << byte_offset << ", "
+ << byte_length << ") "
+ << "(DOMArrayBuffer argument)";
probe::DidSendWebSocketMessage(
execution_context_, identifier_, WebSocketOpCode::kOpCodeBinary, true,
static_cast<const char*>(buffer.Data()) + byte_offset, byte_length);
@@ -379,7 +376,7 @@ WebSocketChannel::SendResult WebSocketChannelImpl::Send(
void WebSocketChannelImpl::Close(int code, const String& reason) {
DCHECK_EQ(GetState(), State::kOpen);
DCHECK(!execution_context_->IsContextDestroyed());
- NETWORK_DVLOG(1) << this << " Close(" << code << ", " << reason << ")";
+ DVLOG(1) << this << " Close(" << code << ", " << reason << ")";
uint16_t code_to_send = static_cast<uint16_t>(
code == kCloseEventCodeNotSpecified ? kCloseEventCodeNoStatusRcvd : code);
messages_.push_back(Message(code_to_send, reason));
@@ -389,7 +386,7 @@ void WebSocketChannelImpl::Close(int code, const String& reason) {
void WebSocketChannelImpl::Fail(const String& reason,
mojom::ConsoleMessageLevel level,
std::unique_ptr<SourceLocation> location) {
- NETWORK_DVLOG(1) << this << " Fail(" << reason << ")";
+ DVLOG(1) << this << " Fail(" << reason << ")";
probe::DidReceiveWebSocketMessageError(execution_context_, identifier_,
reason);
const String message =
@@ -415,7 +412,7 @@ void WebSocketChannelImpl::Fail(const String& reason,
}
void WebSocketChannelImpl::Disconnect() {
- NETWORK_DVLOG(1) << this << " disconnect()";
+ DVLOG(1) << this << " disconnect()";
if (identifier_) {
TRACE_EVENT_INSTANT1(
"devtools.timeline", "WebSocketDestroy", TRACE_EVENT_SCOPE_THREAD,
@@ -428,7 +425,7 @@ void WebSocketChannelImpl::Disconnect() {
}
void WebSocketChannelImpl::CancelHandshake() {
- NETWORK_DVLOG(1) << this << " CancelHandshake()";
+ DVLOG(1) << this << " CancelHandshake()";
if (GetState() != State::kConnecting)
return;
@@ -440,12 +437,12 @@ void WebSocketChannelImpl::CancelHandshake() {
}
void WebSocketChannelImpl::ApplyBackpressure() {
- NETWORK_DVLOG(1) << this << " ApplyBackpressure";
+ DVLOG(1) << this << " ApplyBackpressure";
backpressure_ = true;
}
void WebSocketChannelImpl::RemoveBackpressure() {
- NETWORK_DVLOG(1) << this << " RemoveBackpressure";
+ DVLOG(1) << this << " RemoveBackpressure";
if (backpressure_) {
backpressure_ = false;
ConsumePendingDataFrames();
@@ -455,8 +452,8 @@ void WebSocketChannelImpl::RemoveBackpressure() {
void WebSocketChannelImpl::OnOpeningHandshakeStarted(
network::mojom::blink::WebSocketHandshakeRequestPtr request) {
DCHECK_EQ(GetState(), State::kConnecting);
- NETWORK_DVLOG(1) << this << " OnOpeningHandshakeStarted("
- << request->url.GetString() << ")";
+ DVLOG(1) << this << " OnOpeningHandshakeStarted(" << request->url.GetString()
+ << ")";
TRACE_EVENT_INSTANT1(
"devtools.timeline", "WebSocketSendHandshakeRequest",
@@ -469,7 +466,11 @@ void WebSocketChannelImpl::OnOpeningHandshakeStarted(
void WebSocketChannelImpl::OnFailure(const WTF::String& message,
int net_error,
- int response_code) {}
+ int response_code) {
+ DVLOG(1) << this << " OnFailure(" << message << ", " << net_error << ", "
+ << response_code << ")";
+ failure_message_ = message;
+}
void WebSocketChannelImpl::OnConnectionEstablished(
mojo::PendingRemote<network::mojom::blink::WebSocket> websocket,
@@ -481,8 +482,8 @@ void WebSocketChannelImpl::OnConnectionEstablished(
DCHECK_EQ(GetState(), State::kConnecting);
const String& protocol = response->selected_protocol;
const String& extensions = response->extensions;
- NETWORK_DVLOG(1) << this << " OnConnectionEstablished(" << protocol << ", "
- << extensions << ")";
+ DVLOG(1) << this << " OnConnectionEstablished(" << protocol << ", "
+ << extensions << ")";
TRACE_EVENT_INSTANT1(
"devtools.timeline", "WebSocketReceiveHandshakeResponse",
TRACE_EVENT_SCOPE_THREAD, "data",
@@ -537,8 +538,8 @@ void WebSocketChannelImpl::OnDataFrame(
network::mojom::blink::WebSocketMessageType type,
uint64_t data_length) {
DCHECK_EQ(GetState(), State::kOpen);
- NETWORK_DVLOG(1) << this << " OnDataFrame(" << fin << ", " << type << ", "
- << "(data_length = " << data_length << "))";
+ DVLOG(1) << this << " OnDataFrame(" << fin << ", " << type << ", "
+ << "(data_length = " << data_length << "))";
pending_data_frames_.push_back(
DataFrame(fin, type, static_cast<uint32_t>(data_length)));
ConsumePendingDataFrames();
@@ -549,8 +550,8 @@ void WebSocketChannelImpl::OnDropChannel(bool was_clean,
const String& reason) {
// TODO(yhirano): This should be DCHECK_EQ(GetState(), State::kOpen).
DCHECK(GetState() == State::kOpen || GetState() == State::kConnecting);
- NETWORK_DVLOG(1) << this << " OnDropChannel(" << was_clean << ", " << code
- << ", " << reason << ")";
+ DVLOG(1) << this << " OnDropChannel(" << was_clean << ", " << code << ", "
+ << reason << ")";
if (identifier_) {
TRACE_EVENT_INSTANT1(
@@ -565,7 +566,7 @@ void WebSocketChannelImpl::OnDropChannel(bool was_clean,
void WebSocketChannelImpl::OnClosingHandshake() {
DCHECK_EQ(GetState(), State::kOpen);
- NETWORK_DVLOG(1) << this << " OnClosingHandshake()";
+ DVLOG(1) << this << " OnClosingHandshake()";
client_->DidStartClosingHandshake();
}
@@ -860,7 +861,7 @@ BaseFetchContext* WebSocketChannelImpl::GetBaseFetchContext() const {
void WebSocketChannelImpl::OnReadable(MojoResult result,
const mojo::HandleSignalsState& state) {
DCHECK_EQ(GetState(), State::kOpen);
- NETWORK_DVLOG(2) << this << " OnReadable mojo_result=" << result;
+ DVLOG(2) << this << " OnReadable mojo_result=" << result;
if (result != MOJO_RESULT_OK) {
// We don't detect mojo errors on data pipe. Mojo connection errors will
// be detected via |client_receiver_|.
@@ -874,9 +875,9 @@ void WebSocketChannelImpl::ConsumePendingDataFrames() {
while (!pending_data_frames_.empty() && !backpressure_ &&
GetState() == State::kOpen) {
DataFrame& data_frame = pending_data_frames_.front();
- NETWORK_DVLOG(2) << " ConsumePendingDataFrame frame=(" << data_frame.fin
- << ", " << data_frame.type
- << ", (data_length = " << data_frame.data_length << "))";
+ DVLOG(2) << " ConsumePendingDataFrame frame=(" << data_frame.fin << ", "
+ << data_frame.type << ", (data_length = " << data_frame.data_length
+ << "))";
if (data_frame.data_length == 0) {
ConsumeDataFrame(data_frame.fin, data_frame.type, nullptr, 0);
pending_data_frames_.pop_front();
@@ -992,7 +993,7 @@ void WebSocketChannelImpl::ConsumeDataFrame(
void WebSocketChannelImpl::OnWritable(MojoResult result,
const mojo::HandleSignalsState& state) {
DCHECK_EQ(GetState(), State::kOpen);
- NETWORK_DVLOG(2) << this << " OnWritable mojo_result=" << result;
+ DVLOG(2) << this << " OnWritable mojo_result=" << result;
if (result != MOJO_RESULT_OK) {
// We don't detect mojo errors on data pipe. Mojo connection errors will
// be detected via |client_receiver_|.
@@ -1079,12 +1080,14 @@ void WebSocketChannelImpl::OnConnectionError(const base::Location& set_from,
uint32_t custom_reason,
const std::string& description) {
DCHECK_NE(GetState(), State::kDisconnected);
- NETWORK_DVLOG(1) << " OnConnectionError("
- << " reason: " << custom_reason
- << ", description:" << description
- << "), set_from:" << set_from.ToString();
- String message = "Unknown reason";
- if (custom_reason == network::mojom::blink::WebSocket::kInternalFailure) {
+ DVLOG(1) << " OnConnectionError("
+ << ", description:" << description
+ << ", failure_message:" << failure_message_
+ << "), set_from:" << set_from.ToString();
+ String message;
+ if (description.empty()) {
+ message = failure_message_;
+ } else {
message = String::FromUTF8(description.c_str(), description.size());
}
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index e2f1d297873..67b62299786 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -180,7 +180,7 @@ class MODULES_EXPORT WebSocketChannelImpl final
public:
using DidCallSendMessage =
- util::StrongAlias<class DidCallSendMessageTag, bool>;
+ base::StrongAlias<class DidCallSendMessageTag, bool>;
// Initializes message as a string
Message(const std::string&,
@@ -316,6 +316,7 @@ class MODULES_EXPORT WebSocketChannelImpl final
size_t sent_size_of_top_message_ = 0;
FrameScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
+ WTF::String failure_message_;
const std::unique_ptr<const SourceLocation> location_at_construction_;
network::mojom::blink::WebSocketHandshakeRequestPtr handshake_request_;
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
index b1b1c7ec631..76757adb79c 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
@@ -226,7 +226,7 @@ class WebSocketChannelImplTest : public PageTestBase {
const MojoCreateDataPipeOptions data_pipe_options{
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1,
capacity};
- return mojo::CreateDataPipe(&data_pipe_options, writable, readable);
+ return mojo::CreateDataPipe(&data_pipe_options, *writable, *readable);
}
std::unique_ptr<TestWebSocket> EstablishConnection(
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.cc
index fc4976ff1e7..ed584d2412d 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.cc
@@ -33,7 +33,6 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.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/assertions.h"
namespace blink {
@@ -323,9 +322,8 @@ void WebSocketStream::UnderlyingSink::SendAny(ScriptState* script_state,
return;
}
- SendArrayBuffer(script_state, data.View()->buffer(),
- data.View()->byteOffset(), data.View()->byteLength(),
- resolver, std::move(callback));
+ SendArrayBuffer(script_state, data->buffer(), data->byteOffset(),
+ data->byteLength(), resolver, std::move(callback));
return;
}
@@ -437,9 +435,9 @@ WebSocketStream::WebSocketStream(ExecutionContext* execution_context,
closed_resolver_(
MakeGarbageCollected<ScriptPromiseResolver>(script_state)),
connection_(script_state->GetIsolate(),
- connection_resolver_->Promise().V8Value().As<v8::Promise>()),
+ connection_resolver_->Promise().V8Promise()),
closed_(script_state->GetIsolate(),
- closed_resolver_->Promise().V8Value().As<v8::Promise>()) {}
+ closed_resolver_->Promise().V8Promise()) {}
WebSocketStream::~WebSocketStream() = default;
diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.h b/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.h
index a2ec431ad3f..0e8cbae9c55 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_stream.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "v8/include/v8.h"
@@ -24,7 +25,6 @@ class ScriptPromise;
class ScriptPromiseResolver;
class ScriptState;
class ScriptValue;
-class Visitor;
class WebSocketChannel;
class WebSocketCloseInfo;
class WebSocketStreamOptions;
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webtransport/DIR_METADATA
new file mode 100644
index 00000000000..d6e9ab34b76
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webtransport/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Network>WebTransport"
+}
+team_email: "blink-network-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/OWNERS b/chromium/third_party/blink/renderer/modules/webtransport/OWNERS
index e57af91fd03..20ff3c47588 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webtransport/OWNERS
@@ -1,5 +1,2 @@
ricea@chromium.org
yhirano@chromium.org
-
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>WebTransport
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 ef587aa8ac2..cca1abca9a3 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
@@ -154,6 +154,8 @@ class StubQuicTransport : public network::mojom::blink::QuicTransport {
was_abort_stream_called_ = true;
}
+ void SetOutgoingDatagramExpirationDuration(base::TimeDelta) override {}
+
private:
base::OnceCallback<void(uint32_t,
mojo::ScopedDataPipeConsumerHandle,
@@ -264,7 +266,7 @@ class ScopedQuicTransport : public mojom::blink::QuicTransportConnector {
// |browser_interface_broker_| is cached here because we need to use it in the
// destructor. This means ScopedQuicTransport must always be destroyed before
// the V8TestingScope object that owns the BrowserInterfaceBrokerProxy.
- BrowserInterfaceBrokerProxy* browser_interface_broker_;
+ const BrowserInterfaceBrokerProxy* browser_interface_broker_;
QuicTransport* quic_transport_;
std::unique_ptr<StubQuicTransport> stub_;
mojo::Remote<network::mojom::blink::QuicTransportClient> client_remote_;
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 29dba03d427..3b072d4d45c 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc
@@ -28,7 +28,6 @@
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.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/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "v8/include/v8.h"
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 b83a684f761..924fce162f7 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/optional.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -18,6 +18,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
@@ -25,7 +26,6 @@ class ScriptState;
class StreamAbortInfo;
class ReadableStream;
class ReadableStreamDefaultControllerWithScriptScope;
-class Visitor;
// Implementation of the IncomingStream mixin from the standard:
// https://wicg.github.io/web-transport/#incoming-stream. ReceiveStream and
@@ -81,7 +81,7 @@ class MODULES_EXPORT IncomingStream final
private:
class UnderlyingSource;
- using IsLocalAbort = util::StrongAlias<class IsLocalAbortTag, bool>;
+ using IsLocalAbort = base::StrongAlias<class IsLocalAbortTag, bool>;
// Called when |data_pipe_| becomes readable or errored.
void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc
index 2dbc95bbab0..66dd2673755 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc
@@ -41,8 +41,8 @@ class IncomingStreamTest : public ::testing::Test {
options.element_num_bytes = 1;
options.capacity_num_bytes = capacity;
- MojoResult result = mojo::CreateDataPipe(&options, &data_pipe_producer_,
- &data_pipe_consumer_);
+ MojoResult result = mojo::CreateDataPipe(&options, data_pipe_producer_,
+ data_pipe_consumer_);
if (result != MOJO_RESULT_OK) {
ADD_FAILURE() << "CreateDataPipe() returned " << result;
}
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 07f2393be1f..243e1ee369d 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc
@@ -245,7 +245,7 @@ ScriptPromise OutgoingStream::SinkWrite(ScriptState* script_state,
array_buffer->ByteLength());
} else {
DCHECK(buffer_source.IsArrayBufferView());
- const auto* array_buffer_view = buffer_source.GetAsArrayBufferView().View();
+ const auto* array_buffer_view = buffer_source.GetAsArrayBufferView().Get();
data = base::span<const uint8_t>(
static_cast<const uint8_t*>(array_buffer_view->BaseAddress()),
array_buffer_view->byteLength());
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 73ff45a6bf7..47374a83ec8 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h
@@ -9,7 +9,7 @@
#include <stdint.h>
#include "base/containers/span.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -94,7 +94,7 @@ class MODULES_EXPORT OutgoingStream final
private:
class UnderlyingSink;
- using IsLocalAbort = util::StrongAlias<class IsLocalAbortTag, bool>;
+ using IsLocalAbort = base::StrongAlias<class IsLocalAbortTag, bool>;
// Called when |data_pipe_| becomes writable or errored.
void OnHandleReady(MojoResult, const mojo::HandleSignalsState&);
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream_test.cc b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream_test.cc
index fffc49a7ad0..23d824f8559 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream_test.cc
@@ -61,8 +61,8 @@ class StreamCreator {
options.capacity_num_bytes = capacity;
mojo::ScopedDataPipeProducerHandle data_pipe_producer;
- MojoResult result = mojo::CreateDataPipe(&options, &data_pipe_producer,
- &data_pipe_consumer_);
+ MojoResult result =
+ mojo::CreateDataPipe(&options, data_pipe_producer, data_pipe_consumer_);
if (result != MOJO_RESULT_OK) {
ADD_FAILURE() << "CreateDataPipe() returned " << result;
}
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 70ed2ecbebf..940cb50be67 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc
@@ -19,9 +19,11 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_quic_transport_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_dtls_fingerprint.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_web_transport_close_info.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/probe/core_probes.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"
@@ -37,6 +39,7 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -57,7 +60,7 @@ bool CreateStreamDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
// TODO(ricea): Find an appropriate value for capacity_num_bytes.
options.capacity_num_bytes = 0;
- MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
if (result != MOJO_RESULT_OK) {
// Probably out of resources.
exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
@@ -73,8 +76,8 @@ bool CreateStreamDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
// Sends a datagram on write().
class QuicTransport::DatagramUnderlyingSink final : public UnderlyingSinkBase {
public:
- explicit DatagramUnderlyingSink(QuicTransport* quic_transport)
- : quic_transport_(quic_transport) {}
+ DatagramUnderlyingSink(QuicTransport* quic_transport, int high_water_mark)
+ : quic_transport_(quic_transport), high_water_mark_(high_water_mark) {}
ScriptPromise start(ScriptState* script_state,
WritableStreamDefaultController*,
@@ -103,10 +106,9 @@ class QuicTransport::DatagramUnderlyingSink final : public UnderlyingSinkBase {
return ScriptPromise();
}
- return SendDatagram(
- {static_cast<const uint8_t*>(data.View()->buffer()->Data()) +
- data.View()->byteOffset(),
- data.View()->byteLength()});
+ return SendDatagram({static_cast<const uint8_t*>(data->buffer()->Data()) +
+ data->byteOffset(),
+ data->byteLength()});
}
exception_state.ThrowTypeError(
@@ -128,6 +130,7 @@ class QuicTransport::DatagramUnderlyingSink final : public UnderlyingSinkBase {
void Trace(Visitor* visitor) const override {
visitor->Trace(quic_transport_);
+ visitor->Trace(pending_datagrams_);
UnderlyingSinkBase::Trace(visitor);
}
@@ -142,18 +145,31 @@ class QuicTransport::DatagramUnderlyingSink final : public UnderlyingSinkBase {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(
quic_transport_->script_state_);
+ pending_datagrams_.push_back(resolver);
+
quic_transport_->quic_transport_->SendDatagram(
- data, WTF::Bind(&DatagramSent, WrapPersistent(resolver)));
+ data, WTF::Bind(&DatagramUnderlyingSink::OnDatagramProcessed,
+ WrapWeakPersistent(this)));
+ if (pending_datagrams_.size() < static_cast<wtf_size_t>(high_water_mark_)) {
+ // In this case we pretend that the datagram is processed immediately, to
+ // get more requests from the stream.
+ return ScriptPromise::CastUndefined(quic_transport_->script_state_);
+ }
return resolver->Promise();
}
- // |sent| indicates whether the datagram was sent or dropped. Currently we
- // |don't do anything with this information.
- static void DatagramSent(ScriptPromiseResolver* resolver, bool sent) {
+ void OnDatagramProcessed(bool sent) {
+ DCHECK(!pending_datagrams_.empty());
+
+ ScriptPromiseResolver* resolver = pending_datagrams_.front();
+ pending_datagrams_.pop_front();
+
resolver->Resolve();
}
Member<QuicTransport> quic_transport_;
+ const int high_water_mark_;
+ HeapDeque<Member<ScriptPromiseResolver>> pending_datagrams_;
};
// Captures a pointer to the ReadableStreamDefaultControllerWithScriptScope in
@@ -368,7 +384,8 @@ QuicTransport::QuicTransport(ScriptState* script_state,
url_(NullURL(), url),
quic_transport_(context),
handshake_client_receiver_(this, context),
- client_receiver_(this, context) {}
+ client_receiver_(this, context),
+ inspector_transport_id_(CreateUniqueIdentifier()) {}
ScriptPromise QuicTransport::createSendStream(ScriptState* script_state,
ExceptionState& exception_state) {
@@ -507,7 +524,8 @@ void QuicTransport::OnConnectionEstablished(
DVLOG(1) << "QuicTransport::OnConnectionEstablished() this=" << this;
handshake_client_receiver_.reset();
- // TODO(ricea): Report to devtools.
+ probe::WebTransportConnectionEstablished(GetExecutionContext(),
+ inspector_transport_id_);
auto task_runner =
GetExecutionContext()->GetTaskRunner(TaskType::kNetworking);
@@ -603,6 +621,11 @@ void QuicTransport::ForgetStream(uint32_t stream_id) {
stream_map_.erase(stream_id);
}
+void QuicTransport::SetDatagramWritableQueueExpirationDuration(
+ base::TimeDelta duration) {
+ quic_transport_->SetOutgoingDatagramExpirationDuration(duration);
+}
+
void QuicTransport::Trace(Visitor* visitor) const {
visitor->Trace(received_datagrams_);
visitor->Trace(received_datagrams_controller_);
@@ -700,7 +723,7 @@ void QuicTransport::Init(const String& url,
handshake_client_receiver_.set_disconnect_handler(
WTF::Bind(&QuicTransport::OnConnectionError, WrapWeakPersistent(this)));
- // TODO(ricea): Report something to devtools.
+ probe::WebTransportCreated(execution_context, inspector_transport_id_, url_);
// The choice of 1 for the ReadableStream means that it will queue one
// datagram even when read() is not being called. Unfortunately, that datagram
@@ -709,8 +732,25 @@ void QuicTransport::Init(const String& url,
received_datagrams_ = ReadableStream::CreateWithCountQueueingStrategy(
script_state_,
MakeGarbageCollected<DatagramUnderlyingSource>(script_state_, this), 1);
+ int outgoing_datagrams_high_water_mark = 1;
+ if (options.hasDatagramWritableHighWaterMark()) {
+ outgoing_datagrams_high_water_mark =
+ options.datagramWritableHighWaterMark();
+ }
+
+ // We create a WritableStream with high water mark 1 and try to mimic the
+ // given high water mark in the Sink, from two reasons:
+ // 1. This is better because we can hide the RTT between the renderer and the
+ // network service.
+ // 2. Keeping datagrams in the renderer would be confusing for the timer for
+ // the datagram
+ // queue in the network service, because the timestamp is taken when the
+ // datagram is added to the queue.
outgoing_datagrams_ = WritableStream::CreateWithCountQueueingStrategy(
- script_state_, MakeGarbageCollected<DatagramUnderlyingSink>(this), 1);
+ script_state_,
+ MakeGarbageCollected<DatagramUnderlyingSink>(
+ this, outgoing_datagrams_high_water_mark),
+ 1);
received_streams_underlying_source_ =
StreamVendingUnderlyingSource::CreateWithVendor<ReceiveStreamVendor>(
@@ -743,6 +783,7 @@ void QuicTransport::ResetAll() {
void QuicTransport::Dispose() {
DVLOG(1) << "QuicTransport::Dispose() this=" << this;
+ probe::WebTransportClosed(GetExecutionContext(), inspector_transport_id_);
stream_map_.clear();
quic_transport_.reset();
handshake_client_receiver_.reset();
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 2bcfefa32d5..9ecbdb63bd7 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "base/containers/span.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
@@ -49,7 +49,7 @@ class MODULES_EXPORT QuicTransport final
USING_PRE_FINALIZER(QuicTransport, Dispose);
public:
- using PassKey = util::PassKey<QuicTransport>;
+ using PassKey = base::PassKey<QuicTransport>;
static QuicTransport* Create(ScriptState*,
const String& url,
QuicTransportOptions*,
@@ -97,6 +97,8 @@ class MODULES_EXPORT QuicTransport final
// Removes the reference to a stream.
void ForgetStream(uint32_t stream_id);
+ void SetDatagramWritableQueueExpirationDuration(base::TimeDelta duration);
+
// ScriptWrappable implementation
void Trace(Visitor* visitor) const override;
@@ -172,6 +174,8 @@ class MODULES_EXPORT QuicTransport final
Member<ReadableStream> received_bidirectional_streams_;
Member<StreamVendingUnderlyingSource>
received_bidirectional_streams_underlying_source_;
+
+ const uint64_t inspector_transport_id_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_options.idl b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_options.idl
index cb20475e391..4c7daba2d21 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_options.idl
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_options.idl
@@ -6,4 +6,9 @@
dictionary QuicTransportOptions {
sequence<RTCDtlsFingerprint> serverCertificateFingerprints;
+
+ // This is an experimental and non-standard parameter. This controls the high
+ // water mark (https://streams.spec.whatwg.org/#high-water-mark) for the
+ // datagramWritable stream.
+ long datagramWritableHighWaterMark;
};
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_test.cc b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_test.cc
index 650e6681a39..3b88b5961ef 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport_test.cc
@@ -130,6 +130,8 @@ class MockQuicTransport : public network::mojom::blink::QuicTransport {
void(base::OnceCallback<
void(uint32_t, mojo::ScopedDataPipeConsumerHandle)>));
+ MOCK_METHOD1(SetOutgoingDatagramExpirationDuration, void(base::TimeDelta));
+
void SendFin(uint32_t stream_id) override {}
void AbortStream(uint32_t stream_id, uint64_t code) override {}
@@ -160,9 +162,11 @@ class QuicTransportTest : public ::testing::Test {
}
// Creates a QuicTransport object with the given |url|.
- QuicTransport* Create(const V8TestingScope& scope, const String& url) {
+ QuicTransport* Create(const V8TestingScope& scope,
+ const String& url,
+ QuicTransportOptions* options) {
AddBinder(scope);
- return QuicTransport::Create(scope.GetScriptState(), url, EmptyOptions(),
+ return QuicTransport::Create(scope.GetScriptState(), url, options,
ASSERT_NO_EXCEPTION);
}
@@ -212,9 +216,11 @@ class QuicTransportTest : public ::testing::Test {
// Creates, connects and returns a QuicTransport object with the given |url|.
// Runs the event loop.
- QuicTransport* CreateAndConnectSuccessfully(const V8TestingScope& scope,
- const String& url) {
- auto* quic_transport = Create(scope, url);
+ QuicTransport* CreateAndConnectSuccessfully(
+ const V8TestingScope& scope,
+ const String& url,
+ QuicTransportOptions* options = EmptyOptions()) {
+ auto* quic_transport = Create(scope, url, options);
ConnectSuccessfully(quic_transport);
return quic_transport;
}
@@ -282,7 +288,7 @@ class QuicTransportTest : public ::testing::Test {
mojom::blink::QuicTransportConnector::Name_, {});
}
- BrowserInterfaceBrokerProxy* interface_broker_ = nullptr;
+ const BrowserInterfaceBrokerProxy* interface_broker_ = nullptr;
WTF::Deque<AcceptUnidirectionalStreamCallback>
pending_unidirectional_accept_callbacks_;
WTF::Deque<AcceptBidirectionalStreamCallback>
@@ -374,6 +380,7 @@ TEST_F(QuicTransportTest, FailByCSP) {
scope.GetExecutionContext()
->GetContentSecurityPolicyForCurrentWorld()
->DidReceiveHeader("connect-src 'none'",
+ *(scope.GetExecutionContext()->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
QuicTransport::Create(scope.GetScriptState(),
@@ -395,6 +402,7 @@ TEST_F(QuicTransportTest, PassCSP) {
scope.GetExecutionContext()
->GetContentSecurityPolicyForCurrentWorld()
->DidReceiveHeader("connect-src quic-transport://example.com",
+ *(scope.GetExecutionContext()->GetSecurityOrigin()),
network::mojom::ContentSecurityPolicyType::kEnforce,
network::mojom::ContentSecurityPolicySource::kHTTP);
QuicTransport::Create(scope.GetScriptState(),
@@ -617,9 +625,77 @@ TEST_F(QuicTransportTest, SendDatagram) {
EXPECT_TRUE(tester.Value().IsUndefined());
}
+TEST_F(QuicTransportTest, BackpressureForOutgoingDatagrams) {
+ V8TestingScope scope;
+ auto* const options = MakeGarbageCollected<QuicTransportOptions>();
+ options->setDatagramWritableHighWaterMark(3);
+ auto* quic_transport = CreateAndConnectSuccessfully(
+ scope, "quic-transport://example.com", options);
+
+ EXPECT_CALL(*mock_quic_transport_, SendDatagram(_, _))
+ .Times(4)
+ .WillRepeatedly(
+ Invoke([](base::span<const uint8_t>,
+ MockQuicTransport::SendDatagramCallback callback) {
+ std::move(callback).Run(true);
+ }));
+
+ auto* writable = quic_transport->sendDatagrams();
+ auto* script_state = scope.GetScriptState();
+ auto* writer = writable->getWriter(script_state, ASSERT_NO_EXCEPTION);
+
+ ScriptPromise promise1;
+ ScriptPromise promise2;
+ ScriptPromise promise3;
+ ScriptPromise promise4;
+
+ {
+ auto* chunk = DOMUint8Array::Create(1);
+ *chunk->Data() = 'A';
+ promise1 =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ }
+ {
+ auto* chunk = DOMUint8Array::Create(1);
+ *chunk->Data() = 'B';
+ promise2 =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ }
+ {
+ auto* chunk = DOMUint8Array::Create(1);
+ *chunk->Data() = 'C';
+ promise3 =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ }
+ {
+ auto* chunk = DOMUint8Array::Create(1);
+ *chunk->Data() = 'D';
+ promise4 =
+ writer->write(script_state, ScriptValue::From(script_state, chunk),
+ ASSERT_NO_EXCEPTION);
+ }
+
+ // The first two promises are resolved immediately.
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ EXPECT_EQ(promise1.V8Promise()->State(), v8::Promise::kFulfilled);
+ EXPECT_EQ(promise2.V8Promise()->State(), v8::Promise::kFulfilled);
+ EXPECT_EQ(promise3.V8Promise()->State(), v8::Promise::kPending);
+ EXPECT_EQ(promise4.V8Promise()->State(), v8::Promise::kPending);
+
+ // The rest are resolved by the callback.
+ test::RunPendingTasks();
+ v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+ EXPECT_EQ(promise3.V8Promise()->State(), v8::Promise::kFulfilled);
+ EXPECT_EQ(promise4.V8Promise()->State(), v8::Promise::kFulfilled);
+}
+
TEST_F(QuicTransportTest, SendDatagramBeforeConnect) {
V8TestingScope scope;
- auto* quic_transport = Create(scope, "quic-transport://example.com");
+ auto* quic_transport =
+ Create(scope, "quic-transport://example.com", EmptyOptions());
auto* writable = quic_transport->sendDatagrams();
auto* script_state = scope.GetScriptState();
@@ -1268,6 +1344,21 @@ TEST_F(QuicTransportTest, ReceiveBidirectionalStream) {
EXPECT_TRUE(bidirectional_stream);
}
+TEST_F(QuicTransportTest, SetDatagramWritableQueueExpirationDuration) {
+ V8TestingScope scope;
+
+ auto* quic_transport =
+ CreateAndConnectSuccessfully(scope, "quic-transport://example.com");
+
+ constexpr base::TimeDelta duration = base::TimeDelta::FromMilliseconds(40);
+ EXPECT_CALL(*mock_quic_transport_,
+ SetOutgoingDatagramExpirationDuration(duration));
+
+ quic_transport->SetDatagramWritableQueueExpirationDuration(duration);
+
+ test::RunPendingTasks();
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/send_stream.cc b/chromium/third_party/blink/renderer/modules/webtransport/send_stream.cc
index c9f73db59eb..3ee150634ca 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/send_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/send_stream.cc
@@ -9,7 +9,6 @@
#include "base/notreached.h"
#include "third_party/blink/renderer/modules/webtransport/quic_transport.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/send_stream.h b/chromium/third_party/blink/renderer/modules/webtransport/send_stream.h
index d79444d2487..cd48cd75ebf 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/send_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/send_stream.h
@@ -13,12 +13,12 @@
#include "third_party/blink/renderer/modules/webtransport/web_transport_stream.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
class QuicTransport;
class ScriptState;
-class Visitor;
class MODULES_EXPORT SendStream final : public ScriptWrappable,
public WebTransportStream,
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/test_utils.cc b/chromium/third_party/blink/renderer/modules/webtransport/test_utils.cc
index 3c3574d1296..c966d0f1d49 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/test_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/test_utils.cc
@@ -24,7 +24,7 @@ bool CreateDataPipeForWebTransportTests(
options.element_num_bytes = 1;
options.capacity_num_bytes = 0; // 0 means the system default size.
- MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
if (result != MOJO_RESULT_OK) {
ADD_FAILURE() << "CreateDataPipe() returned " << result;
return false;
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h
index 12e0ec0accf..025ffc620bc 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h
@@ -5,7 +5,8 @@
#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 "base/time/time.h"
+#include "base/types/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"
@@ -23,7 +24,7 @@ class MODULES_EXPORT WebTransport final
DEFINE_WRAPPERTYPEINFO();
public:
- using PassKey = util::PassKey<WebTransport>;
+ using PassKey = base::PassKey<WebTransport>;
static WebTransport* Create(ScriptState*,
const String& url,
QuicTransportOptions*,
@@ -74,6 +75,11 @@ class MODULES_EXPORT WebTransport final
return quic_transport_->GetExecutionContext();
}
+ void setDatagramWritableQueueExpirationDuration(double ms) {
+ return quic_transport_->SetDatagramWritableQueueExpirationDuration(
+ base::TimeDelta::FromMillisecondsD(ms));
+ }
+
private:
const Member<QuicTransport> quic_transport_;
};
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl
index 16df63a2e0f..d619d615dd0 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl
@@ -23,4 +23,9 @@
void close(optional WebTransportCloseInfo closeInfo = {});
readonly attribute Promise<void> ready;
readonly attribute Promise<WebTransportCloseInfo> closed;
+
+ // This is an experimental and non-standard function. Sets the duration
+ // which determines whether an outgoing datagram should be discarded due to
+ // being in the queue for too long, in milliseconds.
+ void setDatagramWritableQueueExpirationDuration(double ms);
};
diff --git a/chromium/third_party/blink/renderer/modules/webusb/BUILD.gn b/chromium/third_party/blink/renderer/modules/webusb/BUILD.gn
index 3ed9da2ec52..53551d7935b 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webusb/BUILD.gn
@@ -6,8 +6,6 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("webusb") {
sources = [
- "navigator_usb.cc",
- "navigator_usb.h",
"usb.cc",
"usb.h",
"usb_alternate_interface.cc",
@@ -28,8 +26,6 @@ blink_modules_sources("webusb") {
"usb_isochronous_out_transfer_packet.h",
"usb_isochronous_out_transfer_result.h",
"usb_out_transfer_result.h",
- "worker_navigator_usb.cc",
- "worker_navigator_usb.h",
]
deps = [ "//build:chromeos_buildflags" ]
diff --git a/chromium/third_party/blink/renderer/modules/webusb/DIR_METADATA b/chromium/third_party/blink/renderer/modules/webusb/DIR_METADATA
new file mode 100644
index 00000000000..f6467f94ba0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webusb/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>USB"
+}
+team_email: "webusb@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webusb/OWNERS b/chromium/third_party/blink/renderer/modules/webusb/OWNERS
index 8dc3166e8c9..acf1a9ed553 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webusb/OWNERS
@@ -1,4 +1 @@
file://chrome/browser/usb/OWNERS
-
-# COMPONENT: Blink>USB
-# TEAM: webusb@chromium.org
diff --git a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.cc b/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.cc
deleted file mode 100644
index 164ea22a6e9..00000000000
--- a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webusb/navigator_usb.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/modules/webusb/usb.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-
-namespace blink {
-
-NavigatorUSB& NavigatorUSB::From(Navigator& navigator) {
- NavigatorUSB* supplement =
- Supplement<Navigator>::From<NavigatorUSB>(navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<NavigatorUSB>(navigator);
- ProvideTo(navigator, supplement);
- }
- return *supplement;
-}
-
-USB* NavigatorUSB::usb(Navigator& navigator) {
- return NavigatorUSB::From(navigator).usb();
-}
-
-USB* NavigatorUSB::usb() {
- return usb_;
-}
-
-void NavigatorUSB::Trace(Visitor* visitor) const {
- visitor->Trace(usb_);
- Supplement<Navigator>::Trace(visitor);
-}
-
-NavigatorUSB::NavigatorUSB(Navigator& navigator) {
- if (navigator.DomWindow())
- usb_ = MakeGarbageCollected<USB>(*navigator.DomWindow());
-}
-
-const char NavigatorUSB::kSupplementName[] = "NavigatorUSB";
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.h b/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.h
deleted file mode 100644
index 143a7d03bb5..00000000000
--- a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_NAVIGATOR_USB_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_NAVIGATOR_USB_H_
-
-#include "third_party/blink/renderer/core/frame/navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class Navigator;
-class USB;
-
-class NavigatorUSB final : public GarbageCollected<NavigatorUSB>,
- public Supplement<Navigator> {
- public:
- static const char kSupplementName[];
-
- // Gets, or creates, NavigatorUSB supplement on Navigator.
- // See platform/Supplementable.h
- static NavigatorUSB& From(Navigator&);
-
- static USB* usb(Navigator&);
- USB* usb();
-
- explicit NavigatorUSB(Navigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<USB> usb_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_NAVIGATOR_USB_H_
diff --git a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.idl b/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.idl
index d86d90e26ef..aa49b9256f5 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.idl
+++ b/chromium/third_party/blink/renderer/modules/webusb/navigator_usb.idl
@@ -6,7 +6,7 @@
[
Exposed=Window,
- ImplementedAs=NavigatorUSB,
+ ImplementedAs=USB,
SecureContext
] partial interface Navigator {
[SameObject, RuntimeEnabled=WebUSB] readonly attribute USB usb;
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb.cc b/chromium/third_party/blink/renderer/modules/webusb/usb.cc
index cea4f3c741c..d99d900d500 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb.cc
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_usb_device_request_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/webusb/usb_connection_event.h"
@@ -34,7 +35,7 @@ namespace blink {
namespace {
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"usb\" is disallowed by feature policy.";
+ "Access to the feature \"usb\" is disallowed by permissions policy.";
const char kNoDeviceSelected[] = "No device selected.";
void RejectWithTypeError(const String& error_details,
@@ -91,10 +92,22 @@ UsbDeviceFilterPtr ConvertDeviceFilter(const USBDeviceFilter* filter,
} // namespace
-USB::USB(ExecutionContext& context)
- : ExecutionContextLifecycleObserver(&context),
- service_(&context),
- client_receiver_(this, &context) {}
+const char USB::kSupplementName[] = "USB";
+
+USB* USB::usb(NavigatorBase& navigator) {
+ USB* usb = Supplement<NavigatorBase>::From<USB>(navigator);
+ if (!usb) {
+ usb = MakeGarbageCollected<USB>(navigator);
+ ProvideTo(navigator, usb);
+ }
+ return usb;
+}
+
+USB::USB(NavigatorBase& navigator)
+ : Supplement<NavigatorBase>(navigator),
+ ExecutionContextLifecycleObserver(navigator.GetExecutionContext()),
+ service_(navigator.GetExecutionContext()),
+ client_receiver_(this, navigator.GetExecutionContext()) {}
USB::~USB() {
// |service_| may still be valid but there should be no more outstanding
@@ -327,6 +340,7 @@ void USB::Trace(Visitor* visitor) const {
visitor->Trace(client_receiver_);
visitor->Trace(device_cache_);
EventTargetWithInlineData::Trace(visitor);
+ Supplement<NavigatorBase>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb.h b/chromium/third_party/blink/renderer/modules/webusb/usb.h
index 2180cc34873..181b50c974f 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb.h
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb.h
@@ -18,22 +18,30 @@
#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.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 NavigatorBase;
class ScriptPromiseResolver;
class ScriptState;
class USBDevice;
class USBDeviceRequestOptions;
class USB final : public EventTargetWithInlineData,
+ public Supplement<NavigatorBase>,
public ExecutionContextLifecycleObserver,
public device::mojom::blink::UsbDeviceManagerClient {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit USB(ExecutionContext&);
+ static const char kSupplementName[];
+
+ // Getter for navigator.usb
+ static USB* usb(NavigatorBase&);
+
+ explicit USB(NavigatorBase&);
~USB() override;
// USB.idl
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc
index 26a36efc7d7..bf24edc43e4 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc
@@ -54,7 +54,7 @@ const char kInterfaceStateChangeInProgress[] =
"An operation that changes interface state is in progress.";
const char kOpenRequired[] = "The device must be opened first.";
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kExtensionProtocol[] = "chrome-extension";
// These Imprivata extensions can claim the protected HID interface class (used
@@ -96,7 +96,7 @@ bool IsClassAllowedForExtension(uint8_t class_code, const KURL& url) {
return false;
}
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
DOMException* ConvertFatalTransferStatus(const UsbTransferStatus& status) {
switch (status) {
@@ -161,7 +161,7 @@ bool ConvertBufferSource(const ArrayBufferOrArrayBufferView& buffer_source,
vector->Append(static_cast<uint8_t*>(array_buffer->Data()),
static_cast<wtf_size_t>(array_buffer->ByteLength()));
} else {
- DOMArrayBufferView* view = buffer_source.GetAsArrayBufferView().View();
+ DOMArrayBufferView* view = buffer_source.GetAsArrayBufferView().Get();
if (!view->buffer() || view->buffer()->IsDetached()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError, kDetachedBuffer));
@@ -669,7 +669,7 @@ bool USBDevice::IsProtectedInterfaceClass(wtf_size_t interface_index) const {
if (std::binary_search(std::begin(kProtectedClasses),
std::end(kProtectedClasses),
alternate->class_code)) {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return !IsClassAllowedForExtension(alternate->class_code,
GetExecutionContext()->Url());
#else
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.h b/chromium/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.h
index e34fe6efe33..9d75cf5b0a8 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.h
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.h
@@ -32,7 +32,7 @@ class USBInTransferResult final : public ScriptWrappable {
static USBInTransferResult* Create(const String& status,
NotShared<DOMDataView> data) {
- return MakeGarbageCollected<USBInTransferResult>(status, data.View());
+ return MakeGarbageCollected<USBInTransferResult>(status, data.Get());
}
USBInTransferResult(const String& status, DOMDataView* data)
@@ -41,7 +41,7 @@ class USBInTransferResult final : public ScriptWrappable {
~USBInTransferResult() override = default;
String status() const { return status_; }
- DOMDataView* data() const { return data_; }
+ DOMDataView* data() const { return data_.Get(); }
void Trace(Visitor* visitor) const override {
visitor->Trace(data_);
@@ -50,7 +50,7 @@ class USBInTransferResult final : public ScriptWrappable {
private:
const String status_;
- const Member<DOMDataView> data_;
+ const NotShared<DOMDataView> data_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.h b/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.h
index ae0695f42dc..4eb2d96d084 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.h
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.h
@@ -25,7 +25,7 @@ class USBIsochronousInTransferPacket final : public ScriptWrappable {
static USBIsochronousInTransferPacket* Create(const String& status,
NotShared<DOMDataView> data) {
return MakeGarbageCollected<USBIsochronousInTransferPacket>(status,
- data.View());
+ data.Get());
}
USBIsochronousInTransferPacket(const String& status, DOMDataView* data)
diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.h b/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.h
index 341e411202f..9151d1dc19e 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.h
+++ b/chromium/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.h
@@ -29,7 +29,7 @@ class USBIsochronousInTransferResult final : public ScriptWrappable {
static USBIsochronousInTransferResult* Create(
const HeapVector<Member<USBIsochronousInTransferPacket>>& packets,
NotShared<DOMDataView> data) {
- return MakeGarbageCollected<USBIsochronousInTransferResult>(data.View(),
+ return MakeGarbageCollected<USBIsochronousInTransferResult>(data.Get(),
packets);
}
diff --git a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.cc b/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.cc
deleted file mode 100644
index fceec63319b..00000000000
--- a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webusb/worker_navigator_usb.h"
-
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/modules/webusb/usb.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-
-namespace blink {
-
-WorkerNavigatorUSB& WorkerNavigatorUSB::From(
- WorkerNavigator& worker_navigator) {
- WorkerNavigatorUSB* supplement =
- Supplement<WorkerNavigator>::From<WorkerNavigatorUSB>(worker_navigator);
- if (!supplement) {
- supplement = MakeGarbageCollected<WorkerNavigatorUSB>(worker_navigator);
- ProvideTo(worker_navigator, supplement);
- }
- return *supplement;
-}
-
-// static
-USB* WorkerNavigatorUSB::usb(ScriptState* script_state,
- WorkerNavigator& worker_navigator) {
- return WorkerNavigatorUSB::From(worker_navigator).usb(script_state);
-}
-
-USB* WorkerNavigatorUSB::usb(ScriptState* script_state) {
- // A bug in the WebIDL compiler causes this attribute to be incorrectly
- // exposed in the other worker contexts if one of the RuntimeEnabled flags is
- // enabled. Therefore, we will just return the empty usb_ member if the
- // appropriate flag is not enabled for the current context, or if the
- // current context is a ServiceWorkerGlobalScope.
- // TODO(https://crbug.com/839117): Once this attribute stops being incorrectly
- // exposed to the worker contexts, remove these checks.
- if (!usb_) {
- ExecutionContext* context = ExecutionContext::From(script_state);
- DCHECK(context);
-
- bool isDedicatedWorkerAndEnabled =
- context->IsDedicatedWorkerGlobalScope() &&
- RuntimeEnabledFeatures::WebUSBOnDedicatedWorkersEnabled();
-
- if (isDedicatedWorkerAndEnabled) {
- usb_ = MakeGarbageCollected<USB>(*context);
- }
- }
- return usb_;
-}
-
-void WorkerNavigatorUSB::Trace(Visitor* visitor) const {
- visitor->Trace(usb_);
- Supplement<WorkerNavigator>::Trace(visitor);
-}
-
-WorkerNavigatorUSB::WorkerNavigatorUSB(WorkerNavigator& worker_navigator)
- : Supplement<WorkerNavigator>(worker_navigator) {}
-
-const char WorkerNavigatorUSB::kSupplementName[] = "WorkerNavigatorUSB";
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.h b/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.h
deleted file mode 100644
index 840682ff0ec..00000000000
--- a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_WORKER_NAVIGATOR_USB_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_WORKER_NAVIGATOR_USB_H_
-
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/workers/worker_navigator.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class USB;
-class WorkerNavigator;
-
-class WorkerNavigatorUSB final : public GarbageCollected<WorkerNavigatorUSB>,
- public Supplement<WorkerNavigator> {
- public:
- static const char kSupplementName[];
-
- // Gets, or creates, WorkerNavigatorUSB supplement on WorkerNavigator.
- // See platform/Supplementable.h
- static WorkerNavigatorUSB& From(WorkerNavigator&);
-
- static USB* usb(ScriptState*, WorkerNavigator&);
- USB* usb(ScriptState*);
-
- explicit WorkerNavigatorUSB(WorkerNavigator&);
-
- void Trace(Visitor*) const override;
-
- private:
- Member<USB> usb_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_WORKER_NAVIGATOR_USB_H_
diff --git a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl b/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
index 8b933466ce8..6ff616fd3f9 100644
--- a/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
+++ b/chromium/third_party/blink/renderer/modules/webusb/worker_navigator_usb.idl
@@ -5,12 +5,9 @@
// https://wicg.github.io/webusb/#enumeration
[
- // TODO(crbug.com/839117): Enable the following [Exposed] on the partial
- // interface declaration once it's supported.
- //
- // Exposed(DedicatedWorker WebUSBOnDedicatedWorkers),
- ImplementedAs=WorkerNavigatorUSB,
+ Exposed(DedicatedWorker WebUSBOnDedicatedWorkers),
+ ImplementedAs=USB,
SecureContext
] partial interface WorkerNavigator {
- [CallWith=ScriptState, SameObject] readonly attribute USB usb;
+ [SameObject] readonly attribute USB usb;
};
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 af9515a50eb..928441f2ba5 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
@@ -82,10 +82,8 @@ class AnimationAndPaintWorkletThreadTest : public PageTestBase,
EXPECT_TRUE(script_state);
ScriptState::Scope scope(script_state);
const KURL js_url("https://example.com/foo.js");
- v8::Local<v8::Module> module = ModuleRecord::Compile(
- script_state->GetIsolate(), "var counter = 0; ++counter;", js_url,
- js_url, ScriptFetchOptions(), TextPosition::MinimumPosition(),
- ASSERT_NO_EXCEPTION);
+ v8::Local<v8::Module> module = ModuleTestBase::CompileModule(
+ script_state->GetIsolate(), "var counter = 0; ++counter;", js_url);
EXPECT_FALSE(module.IsEmpty());
ScriptValue exception =
ModuleRecord::Instantiate(script_state, module, js_url);
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 4aa6a6fab8d..4f023d29562 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
@@ -32,7 +32,8 @@ CreateAnimationAndPaintWorkletThread(
std::make_unique<GlobalScopeCreationParams>(
window->Url(), mojom::blink::ScriptType::kModule, "Worklet",
window->UserAgent(), window->GetFrame()->Loader().UserAgentMetadata(),
- nullptr /* web_worker_fetch_context */, Vector<CSPHeaderAndType>(),
+ nullptr /* web_worker_fetch_context */,
+ Vector<network::mojom::blink::ContentSecurityPolicyPtr>(),
window->GetReferrerPolicy(), window->GetSecurityOrigin(),
window->IsSecureContext(), window->GetHttpsState(), clients,
nullptr /* content_settings_client */, window->AddressSpace(),
@@ -42,7 +43,8 @@ CreateAnimationAndPaintWorkletThread(
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken()),
+ window->GetAgentClusterID(), ukm::kInvalidSourceId,
+ window->GetExecutionContextToken()),
base::nullopt, std::make_unique<WorkerDevToolsParams>());
return thread;
}
diff --git a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
index 8ca0b86424d..7f0c302eec1 100644
--- a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -6,7 +6,7 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("xr") {
sources = [
- "element_xr.h",
+ "global_event_handlers_xr.h",
"type_converters.cc",
"type_converters.h",
"xr_anchor.cc",
@@ -17,10 +17,14 @@ blink_modules_sources("xr") {
"xr_bounded_reference_space.h",
"xr_canvas_input_provider.cc",
"xr_canvas_input_provider.h",
+ "xr_cpu_depth_information.cc",
+ "xr_cpu_depth_information.h",
"xr_cube_map.cc",
"xr_cube_map.h",
"xr_depth_information.cc",
"xr_depth_information.h",
+ "xr_depth_manager.cc",
+ "xr_depth_manager.h",
"xr_dom_overlay_state.cc",
"xr_dom_overlay_state.h",
"xr_frame.cc",
@@ -31,6 +35,8 @@ blink_modules_sources("xr") {
"xr_frame_request_callback_collection.h",
"xr_grip_space.cc",
"xr_grip_space.h",
+ "xr_hand.cc",
+ "xr_hand.h",
"xr_hit_test_result.cc",
"xr_hit_test_result.h",
"xr_hit_test_source.cc",
@@ -45,6 +51,10 @@ blink_modules_sources("xr") {
"xr_input_source_event.h",
"xr_input_sources_change_event.cc",
"xr_input_sources_change_event.h",
+ "xr_joint_pose.cc",
+ "xr_joint_pose.h",
+ "xr_joint_space.cc",
+ "xr_joint_space.h",
"xr_layer.cc",
"xr_layer.h",
"xr_light_estimate.cc",
@@ -56,8 +66,8 @@ blink_modules_sources("xr") {
"xr_object_space.h",
"xr_plane.cc",
"xr_plane.h",
- "xr_plane_detection_state.cc",
- "xr_plane_detection_state.h",
+ "xr_plane_manager.cc",
+ "xr_plane_manager.h",
"xr_plane_set.cc",
"xr_plane_set.h",
"xr_pose.cc",
@@ -98,13 +108,11 @@ blink_modules_sources("xr") {
"xr_viewport.h",
"xr_webgl_binding.cc",
"xr_webgl_binding.h",
+ "xr_webgl_depth_information.cc",
+ "xr_webgl_depth_information.h",
"xr_webgl_layer.cc",
"xr_webgl_layer.h",
"xr_webgl_rendering_context.h",
- "xr_world_information.cc",
- "xr_world_information.h",
- "xr_world_tracking_state.cc",
- "xr_world_tracking_state.h",
]
deps = [
diff --git a/chromium/third_party/blink/renderer/modules/xr/DIR_METADATA b/chromium/third_party/blink/renderer/modules/xr/DIR_METADATA
new file mode 100644
index 00000000000..c7172b570b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>WebXR"
+}
+team_email: "xr-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/xr/OWNERS b/chromium/third_party/blink/renderer/modules/xr/OWNERS
index 04300e66ff5..9b95aec2eaa 100644
--- a/chromium/third_party/blink/renderer/modules/xr/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/xr/OWNERS
@@ -1,6 +1,3 @@
alcooper@chromium.org
bajones@chromium.org
klausw@chromium.org
-
-# TEAM: xr-dev@chromium.org
-# COMPONENT: Blink>WebXR
diff --git a/chromium/third_party/blink/renderer/modules/xr/document_xr.idl b/chromium/third_party/blink/renderer/modules/xr/document_xr.idl
new file mode 100644
index 00000000000..912f81e9c51
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/document_xr.idl
@@ -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.
+
+// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
+
+[
+ ImplementedAs=GlobalEventHandlersXR
+]
+partial interface Document {
+ attribute EventHandler onbeforexrselect;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/element_xr.h b/chromium/third_party/blink/renderer/modules/xr/element_xr.h
deleted file mode 100644
index a82293984a2..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/element_xr.h
+++ /dev/null
@@ -1,21 +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_XR_ELEMENT_XR_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_ELEMENT_XR_H_
-
-#include "third_party/blink/renderer/modules/event_target_modules.h"
-
-namespace blink {
-
-class ElementXR {
- STATIC_ONLY(ElementXR);
-
- public:
- DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(beforexrselect, kBeforexrselect)
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_ELEMENT_XR_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/element_xr.idl b/chromium/third_party/blink/renderer/modules/xr/element_xr.idl
deleted file mode 100644
index ba69ad6761a..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/element_xr.idl
+++ /dev/null
@@ -1,12 +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.
-
-// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
-
-[
- ImplementedAs=ElementXR
-]
-partial interface Element {
- attribute EventHandler onbeforexrselect;
-};
diff --git a/chromium/third_party/blink/renderer/modules/xr/global_event_handlers_xr.h b/chromium/third_party/blink/renderer/modules/xr/global_event_handlers_xr.h
new file mode 100644
index 00000000000..bb4a15cdef0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/global_event_handlers_xr.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_GLOBAL_EVENT_HANDLERS_XR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_GLOBAL_EVENT_HANDLERS_XR_H_
+
+#include "third_party/blink/renderer/modules/event_target_modules.h"
+
+namespace blink {
+
+// TODO(https://crbug.com/1109272): This should be changed to a partial
+// interface mixin once that's supported by the IDL generator. Currently,
+// GlobalEventHandlers is an interface mixin with five separate implementing
+// interfaces.
+class GlobalEventHandlersXR {
+ STATIC_ONLY(GlobalEventHandlersXR);
+
+ public:
+ DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(beforexrselect, kBeforexrselect)
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_GLOBAL_EVENT_HANDLERS_XR_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/html_element_xr.idl b/chromium/third_party/blink/renderer/modules/xr/html_element_xr.idl
new file mode 100644
index 00000000000..00f486a2bbd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/html_element_xr.idl
@@ -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.
+
+// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
+
+[
+ ImplementedAs=GlobalEventHandlersXR
+]
+partial interface HTMLElement {
+ attribute EventHandler onbeforexrselect;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/idls.gni b/chromium/third_party/blink/renderer/modules/xr/idls.gni
index 71f42f98a13..e542fe26df7 100644
--- a/chromium/third_party/blink/renderer/modules/xr/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/xr/idls.gni
@@ -8,9 +8,13 @@ modules_idl_files = [
"xr_anchor.idl",
"xr_anchor_set.idl",
"xr_bounded_reference_space.idl",
+ "xr_cpu_depth_information.idl",
"xr_depth_information.idl",
"xr_dom_overlay_state.idl",
"xr_frame.idl",
+ "xr_hand.idl",
+ "xr_joint_pose.idl",
+ "xr_joint_space.idl",
"xr_image_tracking_result.idl",
"xr_input_source.idl",
"xr_input_source_array.idl",
@@ -20,7 +24,6 @@ modules_idl_files = [
"xr_light_estimate.idl",
"xr_light_probe.idl",
"xr_plane.idl",
- "xr_plane_detection_state.idl",
"xr_plane_set.idl",
"xr_pose.idl",
"xr_ray.idl",
@@ -40,14 +43,14 @@ modules_idl_files = [
"xr_viewer_pose.idl",
"xr_viewport.idl",
"xr_webgl_binding.idl",
+ "xr_webgl_depth_information.idl",
"xr_webgl_layer.idl",
- "xr_world_information.idl",
- "xr_world_tracking_state.idl",
]
modules_callback_function_idl_files = [ "xr_frame_request_callback.idl" ]
modules_dictionary_idl_files = [
+ "xr_depth_state_init.idl",
"xr_dom_overlay_init.idl",
"xr_hit_test_options_init.idl",
"xr_input_source_event_init.idl",
@@ -66,6 +69,10 @@ modules_dictionary_idl_files = [
modules_typedefs_enums_only_idl_files = [ "xr_webgl_context.idl" ]
modules_dependency_idl_files = [
- "element_xr.idl",
+ "document_xr.idl",
+ "html_element_xr.idl",
+ "mathml_element_xr.idl",
"navigator_xr.idl",
+ "svg_element_xr.idl",
+ "window_xr.idl",
]
diff --git a/chromium/third_party/blink/renderer/modules/xr/mathml_element_xr.idl b/chromium/third_party/blink/renderer/modules/xr/mathml_element_xr.idl
new file mode 100644
index 00000000000..fabea39fd8a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/mathml_element_xr.idl
@@ -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.
+
+// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
+
+[
+ ImplementedAs=GlobalEventHandlersXR
+]
+partial interface MathMLElement {
+ attribute EventHandler onbeforexrselect;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/svg_element_xr.idl b/chromium/third_party/blink/renderer/modules/xr/svg_element_xr.idl
new file mode 100644
index 00000000000..b3b7280288a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/svg_element_xr.idl
@@ -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.
+
+// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
+
+[
+ ImplementedAs=GlobalEventHandlersXR
+]
+partial interface SVGElement {
+ attribute EventHandler onbeforexrselect;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/window_xr.idl b/chromium/third_party/blink/renderer/modules/xr/window_xr.idl
new file mode 100644
index 00000000000..a0f2986cf97
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/window_xr.idl
@@ -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.
+
+// https://immersive-web.github.io/dom-overlays/#onbeforexrselect
+
+[
+ ImplementedAs=GlobalEventHandlersXR
+]
+partial interface Window {
+ attribute EventHandler onbeforexrselect;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc
index 08590754f2c..6408746a803 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.cc
@@ -71,7 +71,7 @@ base::Optional<TransformationMatrix> XRAnchor::MojoFromObject() const {
return base::nullopt;
}
- return mojo_from_anchor_->ToTransform().matrix();
+ return TransformationMatrix(mojo_from_anchor_->ToTransform().matrix());
}
void XRAnchor::Delete() {
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
new file mode 100644
index 00000000000..d1dd7477ee6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
@@ -0,0 +1,145 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h"
+
+#include <cmath>
+#include <cstdlib>
+
+#include "base/numerics/checked_math.h"
+#include "base/numerics/ranges.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/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "ui/gfx/geometry/point3_f.h"
+
+namespace {
+constexpr char kOutOfBoundsAccess[] =
+ "Attempted to access data that is out-of-bounds.";
+
+size_t GetBytesPerElement(device::mojom::XRDepthDataFormat data_format) {
+ switch (data_format) {
+ case device::mojom::XRDepthDataFormat::kLuminanceAlpha:
+ return 2;
+ case device::mojom::XRDepthDataFormat::kFloat32:
+ return 4;
+ }
+}
+}
+
+namespace blink {
+
+XRCPUDepthInformation::XRCPUDepthInformation(
+ const XRFrame* xr_frame,
+ const gfx::Size& size,
+ const gfx::Transform& norm_texture_from_norm_view,
+ float raw_value_to_meters,
+ device::mojom::XRDepthDataFormat data_format,
+ DOMArrayBuffer* data)
+ : XRDepthInformation(xr_frame,
+ size,
+ norm_texture_from_norm_view,
+ raw_value_to_meters),
+ data_(data),
+ data_format_(data_format),
+ bytes_per_element_(GetBytesPerElement(data_format)) {
+ DVLOG(3) << __func__;
+
+ CHECK_EQ(base::CheckMul(bytes_per_element_, size_.width(), size_.height())
+ .ValueOrDie(),
+ data_->ByteLength());
+}
+
+DOMArrayBuffer* XRCPUDepthInformation::data(
+ ExceptionState& exception_state) const {
+ if (!ValidateFrame(exception_state)) {
+ return nullptr;
+ }
+
+ return data_;
+}
+
+float XRCPUDepthInformation::getDepthInMeters(
+ float x,
+ float y,
+ ExceptionState& exception_state) const {
+ DVLOG(3) << __func__ << ": x=" << x << ", y=" << y;
+
+ if (!ValidateFrame(exception_state)) {
+ return 0.0;
+ }
+
+ if (x > 1.0 || x < 0.0) {
+ exception_state.ThrowRangeError(kOutOfBoundsAccess);
+ return 0.0;
+ }
+
+ if (y > 1.0 || y < 0.0) {
+ exception_state.ThrowRangeError(kOutOfBoundsAccess);
+ return 0.0;
+ }
+
+ // Those coordinates are actually `norm_view_coordinates` before a series of
+ // transforms is applied, but they are modified in-place, so the name's in
+ // anticipation of those transforms.
+ gfx::Point3F depth_coordinates(x, y, 0.0);
+
+ // `norm_view_coordinates` becomes `norm_depth_coordinates`:
+ norm_depth_buffer_from_norm_view_.TransformPoint(&depth_coordinates);
+
+ // `norm_depth_coordinates` becomes `depth_coordinates`:
+ depth_coordinates.Scale(size_.width(), size_.height(), 1.0);
+
+ uint32_t column = base::ClampToRange<uint32_t>(
+ static_cast<uint32_t>(depth_coordinates.x()), 0, size_.width() - 1);
+ uint32_t row = base::ClampToRange<uint32_t>(
+ static_cast<uint32_t>(depth_coordinates.y()), 0, size_.height() - 1);
+
+ auto checked_index =
+ base::CheckAdd(column, base::CheckMul(row, size_.width()));
+ size_t index = checked_index.ValueOrDie();
+
+ // Convert from data's native units to meters when accessing:
+ float result = GetItem(index) * raw_value_to_meters_;
+
+ DVLOG(3) << __func__ << ": x=" << x << ", y=" << y << ", column=" << column
+ << ", row=" << row << ", index=" << index << ", result=" << result;
+
+ return result;
+}
+
+float XRCPUDepthInformation::GetItem(size_t index) const {
+ DVLOG(3) << __func__ << ": index=" << index;
+
+ switch (data_format_) {
+ case device::mojom::XRDepthDataFormat::kLuminanceAlpha: {
+ // Luminance-alpha is 2 bytes per entry & base::make_span expects the
+ // length to be provided in the number of elements. The constructor
+ // enforces that |data_|'s byte length matches the size of the array,
+ // taking into account the number of bytes per element.
+ base::span<const uint16_t> array =
+ base::make_span(reinterpret_cast<const uint16_t*>(data_->Data()),
+ data_->ByteLength() / bytes_per_element_);
+ return array[index];
+ }
+ case device::mojom::XRDepthDataFormat::kFloat32: {
+ // Float32 is 4 bytes per entry & base::make_span expects the length to be
+ // provided in the number of elements. The constructor enforces that
+ // |data_|'s byte length matches the size of the array, taking into
+ // account the number of bytes per element.
+ base::span<const float> array =
+ base::make_span(reinterpret_cast<const float*>(data_->Data()),
+ data_->ByteLength() / bytes_per_element_);
+ return array[index];
+ }
+ }
+}
+
+void XRCPUDepthInformation::Trace(Visitor* visitor) const {
+ visitor->Trace(data_);
+ XRDepthInformation::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h
new file mode 100644
index 00000000000..6032e761ab4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CPU_DEPTH_INFORMATION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CPU_DEPTH_INFORMATION_H_
+
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/modules/xr/xr_depth_information.h"
+
+namespace gfx {
+class Size;
+class Transform;
+} // namespace gfx
+
+namespace blink {
+
+class ExceptionState;
+class XRFrame;
+
+class XRCPUDepthInformation final : public XRDepthInformation {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit XRCPUDepthInformation(
+ const XRFrame* xr_frame,
+ const gfx::Size& size,
+ const gfx::Transform& norm_texture_from_norm_view,
+ float raw_value_to_meters,
+ device::mojom::XRDepthDataFormat data_format,
+ DOMArrayBuffer* data);
+
+ DOMArrayBuffer* data(ExceptionState& exception_state) const;
+
+ float getDepthInMeters(float x,
+ float y,
+ ExceptionState& exception_state) const;
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ const Member<DOMArrayBuffer> data_;
+ const device::mojom::XRDepthDataFormat data_format_;
+ const size_t bytes_per_element_;
+
+ // Helper, returns value at `index` in `data_`. Depending on `data_format_`,
+ // the `data_` will be viewed into via Uint16Array (for luminance-alpha),
+ // or via Float32Array (for float32).
+ float GetItem(size_t index) const;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CPU_DEPTH_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl
new file mode 100644
index 00000000000..bd32a22dd56
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=WebXRDepth
+] interface XRCPUDepthInformation : XRDepthInformation {
+ [
+ RaisesException,
+ SameObject,
+ SaveSameObject,
+ MeasureAs=XRCPUDepthInformationDataAttribute
+ ] readonly attribute ArrayBuffer data;
+
+ [RaisesException, MeasureAs=XRCPUDepthInformationGetDepth]
+ float getDepthInMeters(float x, float y);
+};
+
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc
index 1d8aff905a1..f9c654df547 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.cc
@@ -27,8 +27,8 @@ float HalfFloatToFloat(const uint16_t input) {
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
uint8_t LinearToSrgb(float cl) {
float cs = base::ClampToRange(
- cl < 0.0031308f ? 12.92f * cl : 1.055f * pow(cl, 0.41666f) - 0.055f, 0.0f,
- 1.0f);
+ cl < 0.0031308f ? 12.92f * cl : 1.055f * std::pow(cl, 0.41666f) - 0.055f,
+ 0.0f, 1.0f);
return static_cast<uint8_t>(255.0f * cs + 0.5f);
}
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 64d0e310a59..8b78d8b8800 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
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CUBE_MAP_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CUBE_MAP_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/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
index 35f28c73a87..053b0301b88 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc
@@ -6,87 +6,74 @@
#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_frame.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.";
+
+constexpr char kFrameInactive[] =
+ "XRDepthInformation members are only accessible when their XRFrame's "
+ "`active` boolean is `true`.";
+constexpr char kFrameNotAnimated[] =
+ "XRDepthInformation members are only accessible when their XRFrame's "
+ "`animationFrame` boolean is `true`.";
}
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_;
+ const XRFrame* xr_frame,
+ const gfx::Size& size,
+ const gfx::Transform& norm_depth_buffer_from_norm_view,
+ float raw_value_to_meters)
+ : xr_frame_(xr_frame),
+ size_(size),
+ norm_depth_buffer_from_norm_view_(norm_depth_buffer_from_norm_view),
+ raw_value_to_meters_(raw_value_to_meters) {
+ DVLOG(3) << __func__ << ": size_=" << size_.ToString()
+ << ", norm_depth_buffer_from_norm_view_="
+ << norm_depth_buffer_from_norm_view_.ToString()
+ << ", raw_value_to_meters_=" << raw_value_to_meters_;
}
uint32_t XRDepthInformation::width() const {
- return width_;
+ return size_.width();
}
uint32_t XRDepthInformation::height() const {
- return height_;
+ return size_.height();
}
-float XRDepthInformation::getDepth(uint32_t column,
- uint32_t row,
- ExceptionState& exception_state) const {
- DVLOG(3) << __func__ << ": column=" << column << ", row=" << row;
+float XRDepthInformation::rawValueToMeters() const {
+ return raw_value_to_meters_;
+}
- if (column >= width_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
- kOutOfBoundsAccess);
- return 0.0;
- }
+XRRigidTransform* XRDepthInformation::normDepthBufferFromNormView() const {
+ return MakeGarbageCollected<XRRigidTransform>(
+ TransformationMatrix(norm_depth_buffer_from_norm_view_.matrix()));
+}
- if (row >= height_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
- kOutOfBoundsAccess);
- return 0.0;
+bool XRDepthInformation::ValidateFrame(ExceptionState& exception_state) const {
+ if (!xr_frame_->IsActive()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kFrameInactive);
+ return false;
}
- 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;
-}
+ if (!xr_frame_->IsAnimationFrame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kFrameNotAnimated);
+ return false;
+ }
-XRRigidTransform* XRDepthInformation::normTextureFromNormView() const {
- return MakeGarbageCollected<XRRigidTransform>(
- TransformationMatrix(norm_texture_from_norm_view_.matrix()));
+ return true;
}
void XRDepthInformation::Trace(Visitor* visitor) const {
- visitor->Trace(data_);
+ visitor->Trace(xr_frame_);
ScriptWrappable::Trace(visitor);
}
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
index 0245b1d54f9..e371581e892 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h
@@ -6,43 +6,50 @@
#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/geometry/size.h"
#include "ui/gfx/transform.h"
namespace blink {
class ExceptionState;
+class XRFrame;
class XRRigidTransform;
-class XRDepthInformation final : public ScriptWrappable {
+class XRDepthInformation : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
- public:
+ protected:
explicit XRDepthInformation(
- const device::mojom::blink::XRDepthDataUpdated& depth_data);
+ const XRFrame* xr_frame,
+ const gfx::Size& size,
+ const gfx::Transform& norm_depth_buffer_from_norm_view,
+ float raw_value_to_meters);
- DOMUint16Array* data() const;
+ // Helper to validate whether a frame is in a correct state. Should be invoked
+ // before every member access. If the validation returns `false`, it means the
+ // validation failed & an exception is going to be thrown and the rest of the
+ // member access code should not run.
+ bool ValidateFrame(ExceptionState& exception_state) const;
+ public:
uint32_t width() const;
uint32_t height() const;
- XRRigidTransform* normTextureFromNormView() const;
+ XRRigidTransform* normDepthBufferFromNormView() const;
- float getDepth(uint32_t column,
- uint32_t row,
- ExceptionState& exception_state) const;
+ float rawValueToMeters() const;
void Trace(Visitor* visitor) const override;
- private:
- uint32_t width_;
- uint32_t height_;
+ protected:
+ const Member<const XRFrame> xr_frame_;
+
+ const gfx::Size size_;
- Member<DOMUint16Array> data_;
- gfx::Transform norm_texture_from_norm_view_;
+ const gfx::Transform norm_depth_buffer_from_norm_view_;
+ const float raw_value_to_meters_;
};
} // namespace blink
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
index 0479dcc607a..bdcf618498b 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl
@@ -7,14 +7,10 @@
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);
+ [SameObject, SaveSameObject]
+ readonly attribute XRRigidTransform normDepthBufferFromNormView;
+ readonly attribute float rawValueToMeters;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.cc b/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.cc
new file mode 100644
index 00000000000..86f8e3b3215
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.cc
@@ -0,0 +1,136 @@
+// Copyright 2020 The Chromium Authors. 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_manager.h"
+
+#include "base/trace_event/trace_event.h"
+#include "third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+
+namespace {
+
+constexpr char kInvalidUsageMode[] =
+ "Unable to obtain XRCPUDepthInformation in \"gpu-optimized\" usage mode.";
+
+String UsageToString(device::mojom::XRDepthUsage usage) {
+ switch (usage) {
+ case device::mojom::XRDepthUsage::kCPUOptimized:
+ return "cpu-optimized";
+ case device::mojom::XRDepthUsage::kGPUOptimized:
+ return "gpu-optimized";
+ }
+}
+
+String DataFormatToString(device::mojom::XRDepthDataFormat data_format) {
+ switch (data_format) {
+ case device::mojom::XRDepthDataFormat::kLuminanceAlpha:
+ return "luminance-alpha";
+ case device::mojom::XRDepthDataFormat::kFloat32:
+ return "float32";
+ }
+}
+
+} // namespace
+
+namespace blink {
+
+XRDepthManager::XRDepthManager(
+ base::PassKey<XRSession> pass_key,
+ XRSession* session,
+ const device::mojom::blink::XRDepthConfig& depth_configuration)
+ : session_(session),
+ usage_(depth_configuration.depth_usage),
+ data_format_(depth_configuration.depth_data_format),
+ usage_str_(UsageToString(usage_)),
+ data_format_str_(DataFormatToString(data_format_)) {
+ DVLOG(3) << __func__ << ": usage_=" << usage_
+ << ", data_format_=" << data_format_;
+}
+
+XRDepthManager::~XRDepthManager() = default;
+
+void XRDepthManager::ProcessDepthInformation(
+ device::mojom::blink::XRDepthDataPtr depth_data) {
+ DVLOG(3) << __func__ << ": depth_data valid? " << !!depth_data;
+
+ // Throw away old data, we won't need it anymore because we'll either replace
+ // it with new data, or no new data is available (& we don't want to keep the
+ // old data in that case as well).
+ depth_data_ = nullptr;
+ data_ = nullptr;
+
+ if (depth_data) {
+ DVLOG(3) << __func__ << ": depth_data->which()="
+ << static_cast<uint32_t>(depth_data->which());
+
+ 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 we just discard the data we previously got and will
+ // not set the new one.
+ break;
+ case device::mojom::blink::XRDepthData::Tag::UPDATED_DEPTH_DATA:
+ // We got new depth buffer - store the current depth data as a member.
+ depth_data_ = std::move(depth_data->get_updated_depth_data());
+ break;
+ }
+ }
+}
+
+XRCPUDepthInformation* XRDepthManager::GetCpuDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) {
+ DVLOG(2) << __func__;
+
+ if (usage_ != device::mojom::XRDepthUsage::kCPUOptimized) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidUsageMode);
+ return nullptr;
+ }
+
+ if (!depth_data_) {
+ return nullptr;
+ }
+
+ EnsureData();
+
+ return MakeGarbageCollected<XRCPUDepthInformation>(
+ xr_frame, depth_data_->size, depth_data_->norm_texture_from_norm_view,
+ depth_data_->raw_value_to_meters, data_format_, data_);
+}
+
+XRWebGLDepthInformation* XRDepthManager::GetWebGLDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) {
+ DVLOG(2) << __func__;
+
+ if (usage_ != device::mojom::XRDepthUsage::kGPUOptimized) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidUsageMode);
+ return nullptr;
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
+void XRDepthManager::EnsureData() {
+ DCHECK(depth_data_);
+
+ if (data_) {
+ return;
+ }
+
+ // Copy the pixel data into ArrayBuffer:
+ data_ = DOMArrayBuffer::Create(depth_data_->pixel_data.data(),
+ depth_data_->pixel_data.size());
+}
+
+void XRDepthManager::Trace(Visitor* visitor) const {
+ visitor->Trace(session_);
+ visitor->Trace(data_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.h b/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.h
new file mode 100644
index 00000000000..ded8f77300a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_manager.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_MANAGER_H_
+
+#include "base/types/pass_key.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class ExceptionState;
+class XRCPUDepthInformation;
+class XRWebGLDepthInformation;
+class XRFrame;
+class XRSession;
+
+// Helper class, used to separate the code related to depth buffer processing
+// out of XRSession.
+class XRDepthManager : public GarbageCollected<XRDepthManager> {
+ public:
+ explicit XRDepthManager(
+ base::PassKey<XRSession> pass_key,
+ XRSession* session,
+ const device::mojom::blink::XRDepthConfig& device_configuration);
+ virtual ~XRDepthManager();
+
+ void ProcessDepthInformation(device::mojom::blink::XRDepthDataPtr depth_data);
+
+ const String& depthUsage() const { return usage_str_; }
+ const String& depthDataFormat() const { return data_format_str_; }
+
+ XRCPUDepthInformation* GetCpuDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state);
+
+ XRWebGLDepthInformation* GetWebGLDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state);
+
+ void Trace(Visitor* visitor) const;
+
+ private:
+ Member<XRSession> session_;
+
+ const device::mojom::XRDepthUsage usage_;
+ const device::mojom::XRDepthDataFormat data_format_;
+
+ const String usage_str_;
+ const String data_format_str_;
+
+ // Current depth data buffer.
+ device::mojom::blink::XRDepthDataUpdatedPtr depth_data_;
+
+ // Cached version of the depth buffer data. If not null, contains the same
+ // information as |depth_data_.pixel_data| buffer.
+ Member<DOMArrayBuffer> data_;
+
+ void EnsureData();
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_state_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_depth_state_init.idl
new file mode 100644
index 00000000000..801ed9b6466
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_state_init.idl
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+enum XRDepthUsage {
+ "cpu-optimized",
+ "gpu-optimized"
+};
+
+enum XRDepthDataFormat {
+ "luminance-alpha",
+ "float32",
+};
+
+dictionary XRDepthStateInit {
+ required sequence<XRDepthUsage> usagePreference;
+ required sequence<XRDepthDataFormat> dataFormatPreference;
+};
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 2617193d95a..36b374d36b3 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
@@ -7,30 +7,24 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_joint_space.h"
#include "third_party/blink/renderer/modules/xr/xr_light_estimate.h"
#include "third_party/blink/renderer/modules/xr/xr_light_probe.h"
+#include "third_party/blink/renderer/modules/xr/xr_plane_set.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h"
-#include "third_party/blink/renderer/modules/xr/xr_world_information.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
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.";
-
const char kSessionMismatch[] = "XRSpace and XRFrame sessions do not match.";
const char kCannotReportPoses[] =
@@ -44,14 +38,24 @@ const char kCannotObtainNativeOrigin[] =
"The operation was unable to obtain necessary information and could not be "
"completed.";
+const char kSpacesSequenceTooLarge[] =
+ "Insufficient buffer capacity for pose results.";
+
+const char kMismatchedBufferSizes[] = "Buffer sizes must be equal";
+
} // namespace
-XRFrame::XRFrame(XRSession* session, XRWorldInformation* world_information)
- : world_information_(world_information), session_(session) {}
+constexpr char XRFrame::kInactiveFrame[];
+constexpr char XRFrame::kNonAnimationFrame[];
+
+XRFrame::XRFrame(XRSession* session, bool is_animation_frame)
+ : session_(session), is_animation_frame_(is_animation_frame) {}
XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space,
ExceptionState& exception_state) {
- DVLOG(3) << __func__;
+ DVLOG(3) << __func__ << ": is_active_=" << is_active_
+ << ", is_animation_frame_=" << is_animation_frame_;
+
if (!is_active_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kInactiveFrame);
@@ -102,6 +106,27 @@ XRAnchorSet* XRFrame::trackedAnchors() const {
return session_->TrackedAnchors();
}
+XRPlaneSet* XRFrame::detectedPlanes(ExceptionState& exception_state) const {
+ DVLOG(3) << __func__;
+
+ if (!session_->IsFeatureEnabled(
+ device::mojom::XRSessionFeature::PLANE_DETECTION)) {
+ DVLOG(2) << __func__
+ << ": plane detection feature not enabled on a session";
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ XRSession::kPlanesFeatureNotSupported);
+ return {};
+ }
+
+ if (!is_active_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInactiveFrame);
+ return nullptr;
+ }
+
+ return session_->GetDetectedPlanes();
+}
+
XRLightEstimate* XRFrame::getLightEstimate(
XRLightProbe* light_probe,
ExceptionState& exception_state) const {
@@ -131,24 +156,41 @@ XRLightEstimate* XRFrame::getLightEstimate(
return light_probe->getLightEstimate();
}
-XRDepthInformation* XRFrame::getDepthInformation(
+XRCPUDepthInformation* XRFrame::getDepthInformation(
XRView* view,
ExceptionState& exception_state) const {
DVLOG(2) << __func__;
+ if (!session_->IsFeatureEnabled(device::mojom::XRSessionFeature::DEPTH)) {
+ DVLOG(2) << __func__ << ": depth sensing is not enabled on a session";
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ XRSession::kDepthSensingFeatureNotSupported);
+ return nullptr;
+ }
+
if (!is_active_) {
+ DVLOG(2) << __func__ << ": frame is not active";
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kInactiveFrame);
return nullptr;
}
+ if (!is_animation_frame_) {
+ DVLOG(2) << __func__ << ": frame is not animating";
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kNonAnimationFrame);
+ return nullptr;
+ }
+
if (this != view->frame()) {
+ DVLOG(2) << __func__ << ": view did not originate from the frame";
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kInvalidView);
return nullptr;
}
- return session_->GetDepthInformation();
+ return session_->GetCpuDepthInformation(this, exception_state);
}
// Return an XRPose that has a transform of basespace_from_space, while
@@ -352,9 +394,113 @@ HeapVector<Member<XRImageTrackingResult>> XRFrame::getImageTrackingResults(
return session_->ImageTrackingResults(exception_state);
}
+XRJointPose* XRFrame::getJointPose(XRJointSpace* joint,
+ XRSpace* baseSpace,
+ ExceptionState& exception_state) {
+ if (!is_active_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInactiveFrame);
+ return nullptr;
+ }
+
+ if (session_ != baseSpace->session() || session_ != joint->session()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kSessionMismatch);
+ return nullptr;
+ }
+
+ const XRPose* pose = joint->getPose(baseSpace);
+ if (!pose) {
+ return nullptr;
+ }
+
+ const float radius = joint->radius();
+
+ return MakeGarbageCollected<XRJointPose>(pose->transform()->TransformMatrix(),
+ radius);
+}
+
+bool XRFrame::fillJointRadii(HeapVector<Member<XRJointSpace>>& jointSpaces,
+ NotShared<DOMFloat32Array> radii,
+ ExceptionState& exception_state) {
+ if (!is_active_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInactiveFrame);
+ return false;
+ }
+
+ if (jointSpaces.size() != radii->length()) {
+ exception_state.ThrowTypeError(kMismatchedBufferSizes);
+ return false;
+ }
+
+ for (unsigned offset = 0; offset < jointSpaces.size(); offset++) {
+ const XRJointSpace* jointSpace = jointSpaces[offset];
+ if (session_ != jointSpace->session()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kSessionMismatch);
+ return false;
+ }
+
+ radii->Data()[offset] = jointSpace->radius();
+ }
+
+ return true;
+}
+
+bool XRFrame::fillPoses(HeapVector<Member<XRSpace>>& spaces,
+ XRSpace* baseSpace,
+ NotShared<DOMFloat32Array> transforms,
+ ExceptionState& exception_state) {
+ if (!is_active_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInactiveFrame);
+ return false;
+ }
+
+ const unsigned floats_per_transform = 16;
+
+ if (spaces.size() * floats_per_transform > transforms->length()) {
+ exception_state.ThrowTypeError(kSpacesSequenceTooLarge);
+ return false;
+ }
+
+ if (session_ != baseSpace->session()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kSessionMismatch);
+ return false;
+ }
+
+ bool allValid = true;
+ unsigned offset = 0;
+ for (const auto& space : spaces) {
+ if (session_ != space->session()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kSessionMismatch);
+ return false;
+ }
+
+ const XRPose* pose = space->getPose(baseSpace);
+ if (!pose) {
+ for (unsigned i = 0; i < floats_per_transform; i++) {
+ transforms->Data()[offset + i] = NAN;
+ allValid = false;
+ }
+ } else {
+ const float* const poseMatrix = pose->transform()->matrix()->Data();
+ for (unsigned i = 0; i < floats_per_transform; i++) {
+ transforms->Data()[offset + i] = poseMatrix[i];
+ }
+ }
+
+ offset += floats_per_transform;
+ }
+
+ return allValid;
+}
+
void XRFrame::Trace(Visitor* visitor) const {
visitor->Trace(session_);
- visitor->Trace(world_information_);
ScriptWrappable::Trace(visitor);
}
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 2ec60de9659..3e324421e9b 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
@@ -9,6 +9,8 @@
#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/bindings/core/v8/v8_dom_matrix.h"
+#include "third_party/blink/renderer/modules/xr/xr_joint_pose.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -19,13 +21,16 @@ namespace blink {
class ExceptionState;
class XRAnchorSet;
-class XRDepthInformation;
+class XRCPUDepthInformation;
class XRHitTestResult;
class XRHitTestSource;
class XRImageTrackingResult;
class XRInputSource;
+class XRJointPose;
class XRLightEstimate;
class XRLightProbe;
+class XRJointSpace;
+class XRPlaneSet;
class XRPose;
class XRReferenceSpace;
class XRRigidTransform;
@@ -35,24 +40,29 @@ class XRTransientInputHitTestResult;
class XRTransientInputHitTestSource;
class XRView;
class XRViewerPose;
-class XRWorldInformation;
class XRFrame final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit XRFrame(XRSession* session, XRWorldInformation* world_information);
+ static constexpr char kInactiveFrame[] =
+ "XRFrame access outside the callback that produced it is invalid.";
+ static constexpr char kNonAnimationFrame[] =
+ "This method can only be called on XRFrame objects passed to "
+ "XRSession.requestAnimationFrame callbacks.";
+
+ explicit XRFrame(XRSession* session, bool is_animation_frame = false);
XRSession* session() const { return session_; }
XRViewerPose* getViewerPose(XRReferenceSpace*, ExceptionState&);
XRPose* getPose(XRSpace*, XRSpace*, ExceptionState&);
- XRWorldInformation* worldInformation() const { return world_information_; }
XRAnchorSet* trackedAnchors() const;
XRLightEstimate* getLightEstimate(XRLightProbe*, ExceptionState&) const;
- XRDepthInformation* getDepthInformation(
+ XRCPUDepthInformation* getDepthInformation(
XRView* view,
ExceptionState& exception_state) const;
+ XRPlaneSet* detectedPlanes(ExceptionState& exception_state) const;
void Trace(Visitor*) const override;
@@ -60,9 +70,7 @@ class XRFrame final : public ScriptWrappable {
bool IsActive() const;
- void SetAnimationFrame(bool is_animation_frame) {
- is_animation_frame_ = is_animation_frame;
- }
+ bool IsAnimationFrame() const { return is_animation_frame_; }
HeapVector<Member<XRHitTestResult>> getHitTestResults(
XRHitTestSource* hit_test_source,
@@ -81,11 +89,21 @@ class XRFrame final : public ScriptWrappable {
HeapVector<Member<XRImageTrackingResult>> getImageTrackingResults(
ExceptionState&);
+ XRJointPose* getJointPose(XRJointSpace* joint,
+ XRSpace* baseSpace,
+ ExceptionState& exception_state);
+ bool fillJointRadii(HeapVector<Member<XRJointSpace>>& jointSpaces,
+ NotShared<DOMFloat32Array> radii,
+ ExceptionState& exception_state);
+ bool fillPoses(HeapVector<Member<XRSpace>>& spaces,
+ XRSpace* baseSpace,
+ NotShared<DOMFloat32Array> transforms,
+ ExceptionState& exception_state);
+
private:
std::unique_ptr<TransformationMatrix> GetAdjustedPoseMatrix(XRSpace*) const;
XRPose* GetTargetRayPose(XRInputSource*, XRSpace*) const;
XRPose* GetGripPose(XRInputSource*, XRSpace*) const;
-
// Helper that creates an anchor with the assumption that the conversion from
// passed in space to a stationary space is required.
// |native_origin_from_anchor| is a transform from |space|'s native origin to
@@ -97,8 +115,6 @@ class XRFrame final : public ScriptWrappable {
XRSpace* space,
ExceptionState& exception_state);
- Member<XRWorldInformation> world_information_;
-
const Member<XRSession> session_;
// Frames are only active during callbacks. getPose and getViewerPose should
@@ -108,7 +124,7 @@ class XRFrame final : public ScriptWrappable {
// Only frames created by XRSession.requestAnimationFrame callbacks are
// animation frames. getViewerPose should only be called from JS on active
// animation frames.
- bool is_animation_frame_ = false;
+ bool is_animation_frame_;
};
} // namespace blink
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 9b9e5c54c4a..c6c65b9187e 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
@@ -10,10 +10,6 @@
] interface XRFrame {
[SameObject] readonly attribute XRSession session;
- // More details about the real-world understanding APIs can be found here:
- // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
- [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldInformation worldInformation;
-
[RuntimeEnabled=WebXRAnchors]
readonly attribute XRAnchorSet trackedAnchors;
[RuntimeEnabled=WebXRAnchors, CallWith=ScriptState, RaisesException, MeasureAs=XRFrameCreateAnchor]
@@ -31,8 +27,20 @@
XRLightEstimate? getLightEstimate(XRLightProbe lightProbe);
[RuntimeEnabled=WebXRDepth, RaisesException, MeasureAs=XRFrameGetDepthInformation]
- XRDepthInformation getDepthInformation(XRView view);
+ XRCPUDepthInformation? getDepthInformation(XRView view);
[RuntimeEnabled=WebXRImageTracking, RaisesException]
FrozenArray<XRImageTrackingResult> getImageTrackingResults();
+
+ [RuntimeEnabled=WebXRHandInput, RaisesException]
+ XRJointPose? getJointPose(XRJointSpace joint, XRSpace baseSpace);
+ [RuntimeEnabled=WebXRHandInput, RaisesException]
+ boolean fillJointRadii(sequence<XRJointSpace> jointSpaces, Float32Array radii);
+ [RuntimeEnabled=WebXRHandInput, RaisesException]
+ boolean fillPoses(sequence<XRSpace> spaces, XRSpace baseSpace, Float32Array transforms);
+
+ // More details about the real-world understanding APIs can be found here:
+ // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
+ [RuntimeEnabled=WebXRPlaneDetection, RaisesException]
+ readonly attribute XRPlaneSet? detectedPlanes;
};
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 31524900954..de1b36b546e 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -14,12 +14,10 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/modules/xr/xr_plane_detection_state.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/modules/xr/xr_viewport.h"
#include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
-#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h"
#include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hand.cc b/chromium/third_party/blink/renderer/modules/xr/xr_hand.cc
new file mode 100644
index 00000000000..2e86feedbd6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_hand.cc
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. 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_hand.h"
+#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_joint_pose.h"
+#include "third_party/blink/renderer/modules/xr/xr_joint_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+
+namespace blink {
+
+XRHand::XRHand(const device::mojom::blink::XRHandTrackingData* state,
+ XRInputSource* input_source) {
+ DCHECK_EQ(state->hand_joint_data.size(), kNumJoints);
+
+ for (unsigned i = 0; i < state->hand_joint_data.size(); i++) {
+ device::mojom::blink::XRHandJoint joint = state->hand_joint_data[i]->joint;
+ DCHECK(static_cast<unsigned>(joint) < state->hand_joint_data.size());
+
+ XRJointSpace* joint_space = MakeGarbageCollected<XRJointSpace>(
+ input_source->session(),
+ std::make_unique<TransformationMatrix>(
+ state->hand_joint_data[i]->mojo_from_joint.matrix()),
+ joint, state->hand_joint_data[i]->radius,
+ input_source->xr_handedness());
+
+ joint_spaces_[static_cast<unsigned>(joint)] = {
+ MojomHandJointToString(joint), std::move(joint_space)};
+ }
+}
+
+XRJointSpace* XRHand::get(const String& key) {
+ return std::get<THandJointsMapValue>(
+ joint_spaces_[static_cast<unsigned>(StringToMojomHandJoint(key))]);
+}
+
+XRHand::HandJointIterationSource::HandJointIterationSource(
+ const THandJointCollection& joint_spaces)
+ : joint_spaces_(joint_spaces), current(0) {}
+
+bool XRHand::HandJointIterationSource::Next(ScriptState* script_state,
+ THandJointsMapKey& key,
+ THandJointsMapValue& value,
+ ExceptionState& exception_state) {
+ if (current >= joint_spaces_.size())
+ return false;
+ key = std::get<THandJointsMapKey>(joint_spaces_[current]);
+ value = std::get<THandJointsMapValue>(joint_spaces_[current]);
+ current++;
+ return true;
+}
+
+void XRHand::Trace(Visitor* visitor) const {
+ for (const auto& key_value_pair : joint_spaces_) {
+ visitor->Trace(std::get<THandJointsMapValue>(key_value_pair));
+ }
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hand.h b/chromium/third_party/blink/renderer/modules/xr/xr_hand.h
new file mode 100644
index 00000000000..705cb094386
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_hand.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HAND_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HAND_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/iterable.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class XRInputSource;
+class XRJointSpace;
+
+class XRHand : public ScriptWrappable,
+ public PairIterable<String, Member<XRJointSpace>> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ static const unsigned kNumJoints =
+ static_cast<unsigned>(device::mojom::blink::XRHandJoint::kMaxValue) + 1u;
+
+ using THandJointsMapKey = String;
+ using THandJointsMapValue = Member<XRJointSpace>;
+ using THandJointCollection =
+ std::array<std::tuple<THandJointsMapKey, THandJointsMapValue>,
+ kNumJoints>;
+
+ public:
+ explicit XRHand(const device::mojom::blink::XRHandTrackingData* state,
+ XRInputSource* input_source);
+ ~XRHand() override = default;
+
+ size_t size() const { return joint_spaces_.size(); }
+
+ XRJointSpace* get(const String& key);
+
+ void Trace(Visitor*) const override;
+
+ private:
+ class HandJointIterationSource final
+ : public PairIterable<THandJointsMapKey,
+ THandJointsMapValue>::IterationSource {
+ public:
+ explicit HandJointIterationSource(const THandJointCollection& joint_spaces);
+
+ bool Next(ScriptState* script_state,
+ THandJointsMapKey& key,
+ THandJointsMapValue& value,
+ ExceptionState& exception_state) override;
+
+ private:
+ const THandJointCollection& joint_spaces_;
+
+ uint32_t current;
+ };
+
+ using Iterationsource =
+ PairIterable<String, Member<XRJointSpace>>::IterationSource;
+ IterationSource* StartIteration(ScriptState*, ExceptionState&) override {
+ return MakeGarbageCollected<HandJointIterationSource>(joint_spaces_);
+ }
+
+ THandJointCollection joint_spaces_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_HAND_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hand.idl b/chromium/third_party/blink/renderer/modules/xr/xr_hand.idl
new file mode 100644
index 00000000000..9c09d200f4c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_hand.idl
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//https://immersive-web.github.io/webxr-hand-input/#idl-index
+enum XRHandJoint {
+ "wrist",
+ "thumb-metacarpal",
+ "thumb-phalanx-proximal",
+ "thumb-phalanx-distal",
+ "thumb-tip",
+ "index-finger-metacarpal",
+ "index-finger-phalanx-proximal",
+ "index-finger-phalanx-intermediate",
+ "index-finger-phalanx-distal",
+ "index-finger-tip",
+ "middle-finger-metacarpal",
+ "middle-finger-phalanx-proximal",
+ "middle-finger-phalanx-intermediate",
+ "middle-finger-phalanx-distal",
+ "middle-finger-tip",
+ "ring-finger-metacarpal",
+ "ring-finger-phalanx-proximal",
+ "ring-finger-phalanx-intermediate",
+ "ring-finger-phalanx-distal",
+ "ring-finger-tip",
+ "pinky-finger-metacarpal",
+ "pinky-finger-phalanx-proximal",
+ "pinky-finger-phalanx-intermediate",
+ "pinky-finger-phalanx-distal",
+ "pinky-finger-tip"
+};
+
+//https://immersive-web.github.io/webxr-hand-input/#idl-index
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=WebXRHandInput
+] interface XRHand {
+ iterable<XRHandJoint, XRJointSpace>;
+
+ readonly attribute unsigned long size;
+ XRJointSpace get(XRHandJoint key);
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc
index 0178e27a396..6f091d20fcc 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_hit_test_result.cc
@@ -27,8 +27,8 @@ XRPose* XRHitTestResult::getPose(XRSpace* other) {
auto maybe_other_space_native_from_mojo = other->NativeFromMojo();
DCHECK(maybe_other_space_native_from_mojo);
- blink::TransformationMatrix mojo_from_this =
- mojo_from_this_.ToTransform().matrix();
+ auto mojo_from_this =
+ TransformationMatrix(mojo_from_this_.ToTransform().matrix());
auto other_native_from_mojo = *maybe_other_space_native_from_mojo;
auto other_offset_from_other_native = other->OffsetFromNativeMatrix();
@@ -77,7 +77,8 @@ ScriptPromise XRHitTestResult::createAnchor(ScriptState* script_state,
auto space_from_mojo = mojo_from_space.Inverse();
auto space_from_anchor =
- space_from_mojo * (mojo_from_this_.ToTransform().matrix());
+ space_from_mojo *
+ TransformationMatrix(mojo_from_this_.ToTransform().matrix());
if (plane_id_) {
DVLOG(2) << __func__
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_image_tracking_result.cc b/chromium/third_party/blink/renderer/modules/xr/xr_image_tracking_result.cc
index 5e59609dc1a..982e893b95a 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_image_tracking_result.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_image_tracking_result.cc
@@ -42,7 +42,7 @@ base::Optional<TransformationMatrix> XRImageTrackingResult::MojoFromObject()
return base::nullopt;
}
- return mojo_from_this_->ToTransform().matrix();
+ return TransformationMatrix(mojo_from_this_->ToTransform().matrix());
}
XRSpace* XRImageTrackingResult::imageSpace() const {
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc
index 28b58316ba8..cd7d27d7556 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/input/event_handling_util.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/modules/xr/xr_grip_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_hand.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source_event.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_session_event.h"
@@ -105,6 +106,13 @@ XRInputSource* XRInputSource::CreateOrUpdateFrom(
TryGetTransformationMatrix(state->mojo_from_input);
}
+ if (updated_source->state_.is_visible) {
+ if (state->hand_tracking_data.get()) {
+ updated_source->hand_ = MakeGarbageCollected<XRHand>(
+ state->hand_tracking_data.get(), updated_source);
+ }
+ }
+
updated_source->state_.emulated_position = state->emulated_position;
return updated_source;
@@ -129,6 +137,7 @@ XRInputSource::XRInputSource(const XRInputSource& other)
MakeGarbageCollected<XRTargetRaySpace>(other.session_, this)),
grip_space_(MakeGarbageCollected<XRGripSpace>(other.session_, this)),
gamepad_(other.gamepad_),
+ hand_(other.hand_),
mojo_from_input_(
TryGetTransformationMatrix(other.mojo_from_input_.get())),
input_from_pointer_(
@@ -614,6 +623,7 @@ void XRInputSource::Trace(Visitor* visitor) const {
visitor->Trace(target_ray_space_);
visitor->Trace(grip_space_);
visitor->Trace(gamepad_);
+ visitor->Trace(hand_);
ScriptWrappable::Trace(visitor);
}
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 4340096f7eb..75a7b274008 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
@@ -23,6 +23,7 @@ namespace blink {
class Element;
class XRGripSpace;
+class XRHand;
class XRInputSourceEvent;
class XRSession;
class XRSpace;
@@ -49,12 +50,17 @@ class XRInputSource : public ScriptWrappable, public Gamepad::Client {
XRSession* session() const { return session_; }
+ device::mojom::XRHandedness xr_handedness() const {
+ return state_.handedness;
+ }
+
const String handedness() const;
const String targetRayMode() const;
bool emulatedPosition() const { return state_.emulated_position; }
XRSpace* targetRaySpace() const;
XRSpace* gripSpace() const;
Gamepad* gamepad() const { return gamepad_; }
+ XRHand* hand() const { return hand_; }
Vector<String> profiles() const { return state_.profiles; }
uint32_t source_id() const { return state_.source_id; }
@@ -161,6 +167,7 @@ class XRInputSource : public ScriptWrappable, public Gamepad::Client {
Member<XRTargetRaySpace> target_ray_space_;
Member<XRGripSpace> grip_space_;
Member<Gamepad> gamepad_;
+ Member<XRHand> hand_;
// Input device pose in mojo space. This is the grip pose for
// tracked controllers, and the viewer pose for screen input.
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl
index d1869d2fe85..6adadac1bb0 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -24,5 +24,6 @@ enum XRTargetRayMode {
[SameObject] readonly attribute XRSpace targetRaySpace;
[SameObject] readonly attribute XRSpace? gripSpace;
[SameObject, Measure] readonly attribute Gamepad? gamepad;
+ [SameObject, RuntimeEnabled=WebXRHandInput] readonly attribute XRHand? hand;
[SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> profiles;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.cc b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.cc
new file mode 100644
index 00000000000..a52e8d5ac3a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.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/xr/xr_joint_pose.h"
+#include "third_party/blink/renderer/modules/xr/xr_pose.h"
+
+namespace blink {
+
+XRJointPose::XRJointPose(const TransformationMatrix& transform, float radius)
+ : XRPose(transform, /* emulatedPosition */ false), radius_(radius) {}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.h b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.h
new file mode 100644
index 00000000000..6c9b327850f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_JOINT_POSE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_JOINT_POSE_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_pose.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRJointPose : public XRPose {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRJointPose(const TransformationMatrix& transform,
+ float radius);
+
+ float radius() const { return radius_; }
+
+ private:
+ float radius_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_JOINT_POSE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.idl b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.idl
new file mode 100644
index 00000000000..d73401c3212
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_pose.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.
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=WebXRHandInput
+] interface XRJointPose : XRPose {
+ readonly attribute float radius;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.cc b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.cc
new file mode 100644
index 00000000000..d60163fcfbf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.cc
@@ -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.
+
+#include "third_party/blink/renderer/modules/xr/xr_joint_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_hand.h"
+#include "third_party/blink/renderer/modules/xr/xr_space.h"
+#include "third_party/blink/renderer/modules/xr/xr_utils.h"
+
+namespace blink {
+
+XRJointSpace::XRJointSpace(
+ XRSession* session,
+ std::unique_ptr<TransformationMatrix> mojo_from_joint,
+ device::mojom::blink::XRHandJoint joint,
+ float radius,
+ device::mojom::blink::XRHandedness handedness)
+ : XRSpace(session),
+ mojo_from_joint_space_(std::move(mojo_from_joint)),
+ joint_(joint),
+ radius_(radius),
+ handedness_(handedness) {}
+
+base::Optional<TransformationMatrix> XRJointSpace::MojoFromNative() {
+ return *mojo_from_joint_space_.get();
+}
+
+bool XRJointSpace::EmulatedPosition() const {
+ return false;
+}
+
+base::Optional<device::mojom::blink::XRNativeOriginInformation>
+XRJointSpace::NativeOrigin() const {
+ return XRNativeOriginInformation::Create(this);
+}
+
+bool XRJointSpace::IsStationary() const {
+ return false;
+}
+
+const String XRJointSpace::jointName() const {
+ return MojomHandJointToString(joint_);
+}
+
+std::string XRJointSpace::ToString() const {
+ return "XRJointSpace";
+}
+
+void XRJointSpace::Trace(Visitor* visitor) const {
+ XRSpace::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.h b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.h
new file mode 100644
index 00000000000..86f7bbbd962
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. 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_JOINT_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_JOINT_SPACE_H_
+
+#include "base/optional.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_native_origin_information.h"
+#include "third_party/blink/renderer/modules/xr/xr_space.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace blink {
+
+class XRSession;
+
+class XRJointSpace : public XRSpace {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ XRJointSpace(XRSession* session,
+ std::unique_ptr<TransformationMatrix> mojo_from_joint,
+ device::mojom::blink::XRHandJoint joint,
+ float radius,
+ device::mojom::XRHandedness handedness);
+
+ float radius() const { return radius_; }
+ device::mojom::blink::XRHandJoint joint() const { return joint_; }
+ const String jointName() const;
+ device::mojom::XRHandedness handedness() const { return handedness_; }
+
+ base::Optional<TransformationMatrix> MojoFromNative() override;
+ bool EmulatedPosition() const override;
+
+ base::Optional<device::mojom::blink::XRNativeOriginInformation> NativeOrigin()
+ const final;
+
+ bool IsStationary() const override;
+
+ std::string ToString() const override;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ const std::unique_ptr<TransformationMatrix> mojo_from_joint_space_;
+ const device::mojom::blink::XRHandJoint joint_;
+ const float radius_;
+ const device::mojom::XRHandedness handedness_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_JOINT_SPACE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.idl b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.idl
new file mode 100644
index 00000000000..551ec31f681
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_joint_space.idl
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium 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=WebXRHandInput
+] interface XRJointSpace : XRSpace {
+ readonly attribute XRHandJoint jointName;
+};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc
index ecdb5a7e0e8..12389c6e04b 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_light_probe.cc
@@ -5,12 +5,12 @@
#include "third_party/blink/renderer/modules/xr/xr_light_probe.h"
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_light_probe_init.h"
#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
#include "third_party/blink/renderer/modules/event_modules.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/xr/xr_cube_map.h"
#include "third_party/blink/renderer/modules/xr/xr_light_estimate.h"
-#include "third_party/blink/renderer/modules/xr/xr_light_probe_init.h"
#include "third_party/blink/renderer/modules/xr/xr_object_space.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
@@ -97,7 +97,7 @@ void XRLightProbe::Trace(Visitor* visitor) const {
visitor->Trace(session_);
visitor->Trace(probe_space_);
visitor->Trace(light_estimate_);
- ScriptWrappable::Trace(visitor);
+ EventTargetWithInlineData::Trace(visitor);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc
index a0662f9a068..431f4da3ade 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.cc
@@ -7,6 +7,7 @@
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/modules/xr/xr_anchor.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
+#include "third_party/blink/renderer/modules/xr/xr_joint_space.h"
#include "third_party/blink/renderer/modules/xr/xr_light_probe.h"
#include "third_party/blink/renderer/modules/xr/xr_plane.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
@@ -74,6 +75,21 @@ device::mojom::blink::XRNativeOriginInformation Create(
}
device::mojom::blink::XRNativeOriginInformation Create(
+ const XRJointSpace* joint_space) {
+ DCHECK(joint_space);
+
+ device::mojom::blink::XRHandJointSpaceInfoPtr joint_space_info =
+ device::mojom::blink::XRHandJointSpaceInfo::New();
+ joint_space_info->handedness = joint_space->handedness();
+ joint_space_info->joint = joint_space->joint();
+
+ device::mojom::blink::XRNativeOriginInformation result;
+ result.set_hand_joint_space_info(std::move(joint_space_info));
+
+ return result;
+}
+
+device::mojom::blink::XRNativeOriginInformation Create(
device::mojom::XRReferenceSpaceType reference_space_type) {
device::mojom::blink::XRNativeOriginInformation result;
result.set_reference_space_type(reference_space_type);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.h
index 179424e5091..9273c9292ea 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_native_origin_information.h
@@ -12,6 +12,7 @@ namespace blink {
class XRAnchor;
class XRImageTrackingResult;
class XRInputSource;
+class XRJointSpace;
class XRLightProbe;
class XRPlane;
class XRReferenceSpace;
@@ -28,6 +29,8 @@ device::mojom::blink::XRNativeOriginInformation Create(
const XRLightProbe* light_probe);
device::mojom::blink::XRNativeOriginInformation Create(
const XRReferenceSpace* reference_space);
+device::mojom::blink::XRNativeOriginInformation Create(
+ const XRJointSpace* joint_space);
device::mojom::blink::XRNativeOriginInformation Create(
device::mojom::XRReferenceSpaceType reference_space_type);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc
index 83dc1094b8c..8877cc5623f 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane.cc
@@ -63,7 +63,7 @@ base::Optional<TransformationMatrix> XRPlane::MojoFromObject() const {
return base::nullopt;
}
- return mojo_from_plane_->ToTransform().matrix();
+ return TransformationMatrix(mojo_from_plane_->ToTransform().matrix());
}
String XRPlane::orientation() const {
@@ -127,7 +127,8 @@ ScriptPromise XRPlane::createAnchor(ScriptState* script_state,
auto space_from_mojo = mojo_from_space.Inverse();
// We'll create an anchor located at the current plane's pose:
auto space_from_anchor =
- space_from_mojo * (mojo_from_plane_->ToTransform().matrix());
+ space_from_mojo *
+ TransformationMatrix(mojo_from_plane_->ToTransform().matrix());
return session_->CreatePlaneAnchorHelper(
script_state, space_from_anchor,
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc
deleted file mode 100644
index 5bdbed936c3..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.cc
+++ /dev/null
@@ -1,12 +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/xr/xr_plane_detection_state.h"
-
-namespace blink {
-
-XRPlaneDetectionState::XRPlaneDetectionState(bool enabled)
- : enabled_(enabled) {}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h
deleted file mode 100644
index 1079a81fb76..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.h
+++ /dev/null
@@ -1,28 +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_XR_XR_PLANE_DETECTION_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PLANE_DETECTION_STATE_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class XRPlaneDetectionState : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit XRPlaneDetectionState(bool enabled);
-
- bool enabled() const { return enabled_; }
-
- private:
- bool enabled_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PLANE_DETECTION_STATE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl
deleted file mode 100644
index 9457324459d..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl
+++ /dev/null
@@ -1,15 +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.
-
-// More details about the plane detection API can be found here:
-// https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
-[
- SecureContext,
- Exposed=Window,
- RuntimeEnabled=WebXRPlaneDetection
-]
-interface XRPlaneDetectionState {
- readonly attribute boolean enabled;
-};
-
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.cc b/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.cc
new file mode 100644
index 00000000000..4de5b402430
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.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_plane_manager.h"
+
+#include "base/trace_event/trace_event.h"
+#include "third_party/blink/renderer/modules/xr/xr_plane.h"
+#include "third_party/blink/renderer/modules/xr/xr_plane_set.h"
+
+namespace blink {
+
+XRPlaneManager::XRPlaneManager(base::PassKey<XRSession> pass_key,
+ XRSession* session)
+ : session_(session) {}
+
+void XRPlaneManager::ProcessPlaneInformation(
+ const device::mojom::blink::XRPlaneDetectionData* detected_planes_data,
+ double timestamp) {
+ TRACE_EVENT0("xr", __FUNCTION__);
+
+ if (!detected_planes_data) {
+ DVLOG(3) << __func__ << ": detected_planes_data is null";
+
+ // We have received a nullopt - plane detection is not supported or
+ // disabled. Mark detected_planes as null & clear stored planes.
+ is_detected_planes_null_ = true;
+ plane_ids_to_planes_.clear();
+ return;
+ }
+
+ TRACE_COUNTER2("xr", "Plane statistics", "All planes",
+ detected_planes_data->all_planes_ids.size(), "Updated planes",
+ detected_planes_data->updated_planes_data.size());
+
+ DVLOG(3) << __func__ << ": updated planes size="
+ << detected_planes_data->updated_planes_data.size()
+ << ", all planes size="
+ << detected_planes_data->all_planes_ids.size();
+
+ is_detected_planes_null_ = false;
+
+ HeapHashMap<uint64_t, Member<XRPlane>> updated_planes;
+
+ // First, process all planes that had their information updated (new planes
+ // are also processed here).
+ for (const auto& plane : detected_planes_data->updated_planes_data) {
+ DCHECK(plane);
+
+ auto it = plane_ids_to_planes_.find(plane->id);
+ if (it != plane_ids_to_planes_.end()) {
+ updated_planes.insert(plane->id, it->value);
+ it->value->Update(*plane, timestamp);
+ } else {
+ updated_planes.insert(
+ plane->id, MakeGarbageCollected<XRPlane>(plane->id, session_, *plane,
+ timestamp));
+ }
+ }
+
+ // Then, copy over the planes that were not updated but are still present.
+ for (const auto& plane_id : detected_planes_data->all_planes_ids) {
+ // If the plane was already updated, there is nothing to do as it was
+ // already moved to |updated_planes|. If it's not updated, just copy it over
+ // as-is.
+ if (!base::Contains(updated_planes, plane_id)) {
+ auto it = plane_ids_to_planes_.find(plane_id);
+ DCHECK(it != plane_ids_to_planes_.end());
+ updated_planes.insert(plane_id, it->value);
+ }
+ }
+
+ plane_ids_to_planes_.swap(updated_planes);
+}
+
+XRPlaneSet* XRPlaneManager::GetDetectedPlanes() const {
+ if (is_detected_planes_null_)
+ return nullptr;
+
+ HeapHashSet<Member<XRPlane>> result;
+ for (auto& plane_id_and_plane : plane_ids_to_planes_) {
+ result.insert(plane_id_and_plane.value);
+ }
+
+ return MakeGarbageCollected<XRPlaneSet>(result);
+}
+
+void XRPlaneManager::Trace(Visitor* visitor) const {
+ visitor->Trace(session_);
+ visitor->Trace(plane_ids_to_planes_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.h
new file mode 100644
index 00000000000..5f44b1627ea
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane_manager.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PLANE_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PLANE_MANAGER_H_
+
+#include "base/types/pass_key.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class XRPlaneSet;
+
+// Helper class, used to separate the code related to plane processing out of
+// XRSession.
+class XRPlaneManager : public GarbageCollected<XRPlaneManager> {
+ public:
+ explicit XRPlaneManager(base::PassKey<XRSession> pass_key,
+ XRSession* session);
+
+ void ProcessPlaneInformation(
+ const device::mojom::blink::XRPlaneDetectionData* detected_planes_data,
+ double timestamp);
+
+ XRPlaneSet* GetDetectedPlanes() const;
+
+ void Trace(Visitor* visitor) const;
+
+ private:
+ Member<XRSession> session_;
+
+ bool is_detected_planes_null_ = true;
+ HeapHashMap<uint64_t, Member<XRPlane>> plane_ids_to_planes_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PLANE_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc
index 0691efd672b..9299d921ca5 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_render_state.cc
@@ -63,7 +63,6 @@ base::Optional<double> XRRenderState::inlineVerticalFieldOfView() const {
void XRRenderState::Trace(Visitor* visitor) const {
visitor->Trace(base_layer_);
- visitor->Trace(inline_vertical_fov_);
ScriptWrappable::Trace(visitor);
}
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 e6c691c39dd..5590410583b 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -13,6 +13,7 @@
#include "base/auto_reset.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ranges.h"
+#include "base/types/pass_key.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"
@@ -32,7 +33,9 @@
#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_cube_map.h"
#include "third_party/blink/renderer/modules/xr/xr_depth_information.h"
+#include "third_party/blink/renderer/modules/xr/xr_depth_manager.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"
@@ -40,7 +43,7 @@
#include "third_party/blink/renderer/modules/xr/xr_input_source_event.h"
#include "third_party/blink/renderer/modules/xr/xr_input_sources_change_event.h"
#include "third_party/blink/renderer/modules/xr/xr_light_probe.h"
-#include "third_party/blink/renderer/modules/xr/xr_plane.h"
+#include "third_party/blink/renderer/modules/xr/xr_plane_manager.h"
#include "third_party/blink/renderer/modules/xr/xr_ray.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_render_state.h"
@@ -51,8 +54,6 @@
#include "third_party/blink/renderer/modules/xr/xr_utils.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
-#include "third_party/blink/renderer/modules/xr/xr_world_information.h"
-#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h"
#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
@@ -241,6 +242,8 @@ constexpr char XRSession::kNoRigidTransformSpecified[];
constexpr char XRSession::kUnableToRetrieveMatrix[];
constexpr char XRSession::kNoSpaceSpecified[];
constexpr char XRSession::kAnchorsFeatureNotSupported[];
+constexpr char XRSession::kPlanesFeatureNotSupported[];
+constexpr char XRSession::kDepthSensingFeatureNotSupported[];
class XRSession::XRSessionResizeObserverDelegate final
: public ResizeObserver::Delegate {
@@ -303,11 +306,31 @@ void XRSession::MetricsReporter::ReportFeatureUsed(
case XRSessionFeature::PLANE_DETECTION:
case XRSessionFeature::DEPTH:
case XRSessionFeature::IMAGE_TRACKING:
+ case XRSessionFeature::HAND_INPUT:
// Not recording metrics for these features currently.
break;
}
}
+XRDepthManager* XRSession::CreateDepthManagerIfEnabled(
+ const XRSessionFeatureSet& feature_set,
+ const device::mojom::blink::XRSessionDeviceConfig& device_config) {
+ DVLOG(2) << __func__;
+
+ if (!base::Contains(feature_set, device::mojom::XRSessionFeature::DEPTH)) {
+ return nullptr;
+ }
+
+ if (!device_config.depth_configuration) {
+ DCHECK(false) << "The session reports that depth sensing is supported but "
+ "did not report depth sensing API configuration!";
+ return nullptr;
+ }
+
+ return MakeGarbageCollected<XRDepthManager>(
+ base::PassKey<XRSession>{}, this, *device_config.depth_configuration);
+}
+
XRSession::XRSession(
XRSystem* xr,
mojo::PendingReceiver<device::mojom::blink::XRSessionClient>
@@ -322,8 +345,12 @@ XRSession::XRSession(
mode_(mode),
environment_integration_(
mode == device::mojom::blink::XRSessionMode::kImmersiveAr),
- world_information_(MakeGarbageCollected<XRWorldInformation>(this)),
enabled_features_(std::move(enabled_features)),
+ plane_manager_(
+ MakeGarbageCollected<XRPlaneManager>(base::PassKey<XRSession>{},
+ this)),
+ depth_manager_(
+ CreateDepthManagerIfEnabled(enabled_features_, *device_config)),
input_sources_(MakeGarbageCollected<XRInputSourceArray>()),
client_receiver_(this, xr->GetExecutionContext()),
input_receiver_(this, xr->GetExecutionContext()),
@@ -347,9 +374,6 @@ XRSession::XRSession(
device_config->default_framebuffer_scale, kMinDefaultFramebufferScale,
kMaxDefaultFramebufferScale);
- world_tracking_state_ = MakeGarbageCollected<XRWorldTrackingState>(
- IsFeatureEnabled(device::mojom::XRSessionFeature::PLANE_DETECTION));
-
DVLOG(2) << __func__
<< ": supports_viewport_scaling_=" << supports_viewport_scaling_;
@@ -472,6 +496,26 @@ void XRSession::updateRenderState(XRRenderStateInit* init,
MaybeRequestFrame();
}
+const String& XRSession::depthUsage(ExceptionState& exception_state) {
+ if (!depth_manager_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kDepthSensingFeatureNotSupported);
+ return g_empty_string;
+ }
+
+ return depth_manager_->depthUsage();
+}
+
+const String& XRSession::depthDataFormat(ExceptionState& exception_state) {
+ if (!depth_manager_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kDepthSensingFeatureNotSupported);
+ return g_empty_string;
+ }
+
+ return depth_manager_->depthDataFormat();
+}
+
void XRSession::UpdateEyeParameters(
const device::mojom::blink::VREyeParametersPtr& left_eye,
const device::mojom::blink::VREyeParametersPtr& right_eye) {
@@ -1123,6 +1167,10 @@ void XRSession::ProcessAnchorsData(
<< " anchors that have not been updated";
}
+XRPlaneSet* XRSession::GetDetectedPlanes() const {
+ return plane_manager_->GetDetectedPlanes();
+}
+
void XRSession::CleanUpUnusedHitTestSources() {
auto unused_hit_test_source_ids = GetIdsOfUnusedHitTestSources(
hit_test_source_ids_to_hit_test_sources_, hit_test_source_ids_);
@@ -1208,39 +1256,28 @@ 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;
+XRCPUDepthInformation* XRSession::GetCpuDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) const {
+ if (!depth_manager_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kDepthSensingFeatureNotSupported);
+ return nullptr;
}
-}
-XRDepthInformation* XRSession::GetDepthInformation() const {
- DVLOG(2) << __func__;
+ return depth_manager_->GetCpuDepthInformation(xr_frame, exception_state);
+}
- if (!depth_data_) {
+XRWebGLDepthInformation* XRSession::GetWebGLDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) const {
+ if (!depth_manager_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kDepthSensingFeatureNotSupported);
return nullptr;
}
- return MakeGarbageCollected<XRDepthInformation>(*depth_data_);
+ return depth_manager_->GetWebGLDepthInformation(xr_frame, exception_state);
}
ScriptPromise XRSession::requestLightProbe(ScriptState* script_state,
@@ -1260,10 +1297,11 @@ ScriptPromise XRSession::requestLightProbe(ScriptState* script_state,
if (light_probe_init->reflectionFormat() != "srgba8" &&
light_probe_init->reflectionFormat() != "rgba16f") {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Reflection format \"" +
- light_probe_init->reflectionFormat() +
- "\" not supported.");
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "Reflection format \"" +
+ IDLEnumAsString(light_probe_init->reflectionFormat()) +
+ "\" not supported.");
return ScriptPromise();
}
@@ -1746,11 +1784,16 @@ void XRSession::UpdateWorldUnderstandingStateForFrame(
const device::mojom::blink::XRFrameDataPtr& frame_data) {
// Update objects that might change on per-frame basis.
if (frame_data) {
- world_information_->ProcessPlaneInformation(
+ plane_manager_->ProcessPlaneInformation(
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));
+
+ if (depth_manager_) {
+ depth_manager_->ProcessDepthInformation(
+ std::move(frame_data->depth_data));
+ }
+
ProcessTrackedImagesData(frame_data->tracked_images.get());
const device::mojom::blink::XRLightEstimationData* light_data =
@@ -1759,10 +1802,14 @@ void XRSession::UpdateWorldUnderstandingStateForFrame(
world_light_probe_->ProcessLightEstimationData(light_data, timestamp);
}
} else {
- world_information_->ProcessPlaneInformation(nullptr, timestamp);
+ plane_manager_->ProcessPlaneInformation(nullptr, timestamp);
ProcessAnchorsData(nullptr, timestamp);
ProcessHitTestData(nullptr);
- ProcessDepthData(nullptr);
+
+ if (depth_manager_) {
+ depth_manager_->ProcessDepthInformation(nullptr);
+ }
+
ProcessTrackedImagesData(nullptr);
if (world_light_probe_) {
@@ -1843,8 +1890,7 @@ void XRSession::OnFrame(
return;
}
- XRFrame* presentation_frame = CreatePresentationFrame();
- presentation_frame->SetAnimationFrame(true);
+ XRFrame* presentation_frame = CreatePresentationFrame(true);
// Make sure that any frame-bounded changed to the views array take effect.
if (update_views_next_frame_) {
@@ -1932,11 +1978,11 @@ base::Optional<TransformationMatrix> XRSession::GetMojoFrom(
}
}
-XRFrame* XRSession::CreatePresentationFrame() {
- DVLOG(2) << __func__;
+XRFrame* XRSession::CreatePresentationFrame(bool is_animation_frame) {
+ DVLOG(2) << __func__ << ": is_animation_frame=" << is_animation_frame;
XRFrame* presentation_frame =
- MakeGarbageCollected<XRFrame>(this, world_information_);
+ MakeGarbageCollected<XRFrame>(this, is_animation_frame);
return presentation_frame;
}
@@ -2286,8 +2332,6 @@ bool XRSession::HasPendingActivity() const {
void XRSession::Trace(Visitor* visitor) const {
visitor->Trace(xr_);
visitor->Trace(render_state_);
- visitor->Trace(world_tracking_state_);
- visitor->Trace(world_information_);
visitor->Trace(world_light_probe_);
visitor->Trace(pending_render_state_);
visitor->Trace(end_session_resolver_);
@@ -2302,6 +2346,8 @@ void XRSession::Trace(Visitor* visitor) const {
visitor->Trace(create_anchor_promises_);
visitor->Trace(request_hit_test_source_promises_);
visitor->Trace(reference_spaces_);
+ visitor->Trace(plane_manager_);
+ visitor->Trace(depth_manager_);
visitor->Trace(anchor_ids_to_anchors_);
visitor->Trace(anchor_ids_to_pending_anchor_promises_);
visitor->Trace(prev_base_layer_);
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 caa25da19d3..bb0b058e6f0 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
@@ -42,12 +42,15 @@ class V8XRFrameRequestCallback;
class XRAnchor;
class XRAnchorSet;
class XRCanvasInputProvider;
-class XRDepthInformation;
+class XRCPUDepthInformation;
+class XRDepthManager;
class XRDOMOverlayState;
class XRHitTestOptionsInit;
class XRHitTestSource;
class XRImageTrackingResult;
class XRLightProbe;
+class XRPlaneSet;
+class XRPlaneManager;
class XRReferenceSpace;
class XRRenderState;
class XRRenderStateInit;
@@ -57,9 +60,8 @@ class XRSystem;
class XRTransientInputHitTestOptionsInit;
class XRTransientInputHitTestSource;
class XRViewData;
+class XRWebGLDepthInformation;
class XRWebGLLayer;
-class XRWorldInformation;
-class XRWorldTrackingState;
using XRSessionFeatureSet = HashSet<device::mojom::XRSessionFeature>;
@@ -80,7 +82,10 @@ class XRSession final
static constexpr char kNoSpaceSpecified[] = "No XRSpace specified.";
static constexpr char kAnchorsFeatureNotSupported[] =
"Anchors feature is not supported by the session.";
-
+ static constexpr char kPlanesFeatureNotSupported[] =
+ "Plane detection feature is not supported by the session.";
+ static constexpr char kDepthSensingFeatureNotSupported[] =
+ "Depth sensing 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
@@ -122,7 +127,6 @@ class XRSession final
XRDOMOverlayState* domOverlayState() const { return dom_overlay_state_; }
const String visibilityState() const;
XRRenderState* renderState() const { return render_state_; }
- XRWorldTrackingState* worldTrackingState() { return world_tracking_state_; }
// ARCore by default returns textures in RGBA half-float HDR format and no
// other runtimes support reflection mapping, so just return this until we
@@ -147,6 +151,10 @@ class XRSession final
void updateRenderState(XRRenderStateInit* render_state_init,
ExceptionState& exception_state);
+
+ const String& depthUsage(ExceptionState& exception_state);
+ const String& depthDataFormat(ExceptionState& exception_state);
+
ScriptPromise requestReferenceSpace(ScriptState* script_state,
const String& type,
ExceptionState&);
@@ -335,13 +343,20 @@ class XRSession final
base::Optional<TransformationMatrix> GetMojoFrom(
device::mojom::blink::XRReferenceSpaceType space_type) const;
- XRDepthInformation* GetDepthInformation() const;
+ XRCPUDepthInformation* GetCpuDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) const;
+
+ XRWebGLDepthInformation* GetWebGLDepthInformation(
+ const XRFrame* xr_frame,
+ ExceptionState& exception_state) const;
+
+ XRPlaneSet* GetDetectedPlanes() 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
- // XRSession.
- XRFrame* CreatePresentationFrame();
+ // The created XRFrame will store a reference to this XRSession and use it to
+ // get the latest information out of it.
+ XRFrame* CreatePresentationFrame(bool is_animation_frame = false);
// Updates the internal XRSession state that is relevant to creating
// presentation frames.
@@ -436,8 +451,6 @@ class XRSession final
const device::mojom::blink::XRHitTestSubscriptionResultsData*
hit_test_data);
- void ProcessDepthData(device::mojom::blink::XRDepthDataPtr depth_data);
-
void ProcessTrackedImagesData(
const device::mojom::blink::XRTrackedImagesData*);
HeapVector<Member<XRImageTrackingResult>> frame_tracked_images_;
@@ -449,6 +462,12 @@ class XRSession final
void ExecuteVideoFrameCallbacks(double timestamp);
+ // Helper, creates an instance of depth manager if depth sensing API is
+ // enabled in the session configuration.
+ XRDepthManager* CreateDepthManagerIfEnabled(
+ const XRSessionFeatureSet& feature_set,
+ const device::mojom::blink::XRSessionDeviceConfig& device_config);
+
const Member<XRSystem> xr_;
const device::mojom::blink::XRSessionMode mode_;
const bool environment_integration_;
@@ -458,8 +477,7 @@ class XRSession final
XRVisibilityState visibility_state_ = XRVisibilityState::VISIBLE;
String visibility_state_string_;
Member<XRRenderState> render_state_;
- Member<XRWorldTrackingState> world_tracking_state_;
- Member<XRWorldInformation> world_information_;
+
Member<XRLightProbe> world_light_probe_;
HeapVector<Member<XRRenderStateInit>> pending_render_state_;
@@ -534,6 +552,9 @@ class XRSession final
HashSet<uint64_t> hit_test_source_ids_;
HashSet<uint64_t> hit_test_source_for_transient_input_ids_;
+ Member<XRPlaneManager> plane_manager_;
+ Member<XRDepthManager> depth_manager_;
+
uint32_t view_parameters_id_ = 0;
HeapVector<Member<XRViewData>> views_;
Vector<device::mojom::blink::VREyeParametersPtr> pending_view_parameters_;
@@ -569,9 +590,6 @@ class XRSession final
// 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;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
index 0271055ff2c..9dc54c9091c 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -68,9 +68,6 @@ enum XRReflectionFormat {
long requestAnimationFrame(XRFrameRequestCallback callback);
void cancelAnimationFrame(long handle);
- // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
- [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState;
-
[CallWith=ScriptState, Measure, RaisesException] Promise<void> end();
// https://github.com/immersive-web/hit-test/blob/master/hit-testing-explainer.md
@@ -84,4 +81,9 @@ enum XRReflectionFormat {
[RuntimeEnabled=WebXRImageTracking, CallWith=ScriptState, RaisesException]
Promise<FrozenArray<XRImageTrackingScore>> getTrackedImageScores();
+
+ [RuntimeEnabled=WebXRDepth, RaisesException]
+ readonly attribute XRDepthUsage? depthUsage;
+ [RuntimeEnabled=WebXRDepth, RaisesException]
+ readonly attribute XRDepthDataFormat? depthDataFormat;
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl b/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl
index 2e1b5d7d16a..24076b89d98 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session_init.idl
@@ -8,4 +8,5 @@ dictionary XRSessionInit {
sequence<any> optionalFeatures;
XRDOMOverlayInit domOverlay;
[RuntimeEnabled=WebXRImageTracking] sequence<XRTrackedImageInit> trackedImages;
+ [RuntimeEnabled=WebXRDepth] XRDepthStateInit depthSensing;
};
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 a657120bde3..72bb868b3fd 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_system.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -6,11 +6,13 @@
#include <utility>
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "services/metrics/public/cpp/ukm_builders.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/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_fullscreen_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_depth_state_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_tracked_image_init.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -18,6 +20,7 @@
#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/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/fullscreen/scoped_allow_fullscreen.h"
@@ -30,6 +33,7 @@
#include "third_party/blink/renderer/modules/event_target_modules.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_session_viewport_scaler.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
@@ -47,7 +51,7 @@ const char kNavigatorDetachedError[] =
const char kPageNotVisible[] = "The page is not visible";
const char kFeaturePolicyBlocked[] =
- "Access to the feature \"xr\" is disallowed by feature policy.";
+ "Access to the feature \"xr\" is disallowed by permissions policy.";
const char kActiveImmersiveSession[] =
"There is already an active, immersive XRSession.";
@@ -67,6 +71,10 @@ const char kImmersiveArModeNotValid[] =
const char kTrackedImageWidthInvalid[] =
"trackedImages[%d].widthInMeters invalid, must be a positive number.";
+const char kDepthSensingConfigurationNotSupported[] =
+ "The provided preferences depth sensing usage and format are not "
+ "supported, unable to create the session.";
+
constexpr device::mojom::XRSessionFeature kDefaultImmersiveVrFeatures[] = {
device::mojom::XRSessionFeature::REF_SPACE_VIEWER,
device::mojom::XRSessionFeature::REF_SPACE_LOCAL,
@@ -111,6 +119,94 @@ const char* SessionModeToString(device::mojom::blink::XRSessionMode mode) {
return "";
}
+// TODO(crbug.com/1070871): Drop this #if-else
+#if defined(USE_BLINK_V8_BINDING_NEW_IDL_DICTIONARY)
+
+device::mojom::XRDepthUsage ParseDepthUsage(const V8XRDepthUsage& usage) {
+ switch (usage.AsEnum()) {
+ case V8XRDepthUsage::Enum::kCpuOptimized:
+ return device::mojom::XRDepthUsage::kCPUOptimized;
+ case V8XRDepthUsage::Enum::kGpuOptimized:
+ return device::mojom::XRDepthUsage::kGPUOptimized;
+ }
+}
+
+Vector<device::mojom::XRDepthUsage> ParseDepthUsages(
+ const Vector<V8XRDepthUsage>& usages) {
+ Vector<device::mojom::XRDepthUsage> result;
+
+ std::transform(usages.begin(), usages.end(), std::back_inserter(result),
+ ParseDepthUsage);
+
+ return result;
+}
+
+device::mojom::XRDepthDataFormat ParseDepthFormat(
+ const V8XRDepthDataFormat& format) {
+ switch (format.AsEnum()) {
+ case V8XRDepthDataFormat::Enum::kLuminanceAlpha:
+ return device::mojom::XRDepthDataFormat::kLuminanceAlpha;
+ case V8XRDepthDataFormat::Enum::kFloat32:
+ return device::mojom::XRDepthDataFormat::kFloat32;
+ }
+}
+
+Vector<device::mojom::XRDepthDataFormat> ParseDepthFormats(
+ const Vector<V8XRDepthDataFormat>& formats) {
+ Vector<device::mojom::XRDepthDataFormat> result;
+
+ std::transform(formats.begin(), formats.end(), std::back_inserter(result),
+ ParseDepthFormat);
+
+ return result;
+}
+
+#else
+
+device::mojom::XRDepthUsage ParseDepthUsage(const String& usage) {
+ if (usage == "cpu-optimized") {
+ return device::mojom::XRDepthUsage::kCPUOptimized;
+ } else if (usage == "gpu-optimized") {
+ return device::mojom::XRDepthUsage::kGPUOptimized;
+ }
+
+ NOTREACHED() << "Only strings in the enum are allowed by IDL";
+ return device::mojom::XRDepthUsage::kCPUOptimized;
+}
+
+Vector<device::mojom::XRDepthUsage> ParseDepthUsages(
+ const Vector<String>& usages) {
+ Vector<device::mojom::XRDepthUsage> result;
+
+ std::transform(usages.begin(), usages.end(), std::back_inserter(result),
+ ParseDepthUsage);
+
+ return result;
+}
+
+device::mojom::XRDepthDataFormat ParseDepthFormat(const String& format) {
+ if (format == "luminance-alpha") {
+ return device::mojom::XRDepthDataFormat::kLuminanceAlpha;
+ } else if (format == "float32") {
+ return device::mojom::XRDepthDataFormat::kFloat32;
+ }
+
+ NOTREACHED() << "Only strings in the enum are allowed by IDL";
+ return device::mojom::XRDepthDataFormat::kLuminanceAlpha;
+}
+
+Vector<device::mojom::XRDepthDataFormat> ParseDepthFormats(
+ const Vector<String>& formats) {
+ Vector<device::mojom::XRDepthDataFormat> result;
+
+ std::transform(formats.begin(), formats.end(), std::back_inserter(result),
+ ParseDepthFormat);
+
+ return result;
+}
+
+#endif // USE_BLINK_V8_BINDING_NEW_IDL_DICTIONARY
+
// Converts the given string to an XRSessionFeature. If the string is
// unrecognized, returns nullopt. Based on the spec:
// https://immersive-web.github.io/webxr/#feature-name
@@ -150,6 +246,9 @@ base::Optional<device::mojom::XRSessionFeature> StringToXRSessionFeature(
} else if (RuntimeEnabledFeatures::WebXRImageTrackingEnabled(context) &&
feature_string == "image-tracking") {
return device::mojom::XRSessionFeature::IMAGE_TRACKING;
+ } else if (RuntimeEnabledFeatures::WebXRHandInputEnabled(context) &&
+ feature_string == "hand-tracking") {
+ return device::mojom::XRSessionFeature::HAND_INPUT;
}
return base::nullopt;
@@ -169,6 +268,7 @@ bool IsFeatureValidForMode(device::mojom::XRSessionFeature feature,
case device::mojom::XRSessionFeature::REF_SPACE_UNBOUNDED:
case device::mojom::XRSessionFeature::HIT_TEST:
case device::mojom::XRSessionFeature::ANCHORS:
+ case device::mojom::XRSessionFeature::HAND_INPUT:
return mode == device::mojom::blink::XRSessionMode::kImmersiveVr ||
mode == device::mojom::blink::XRSessionMode::kImmersiveAr;
case device::mojom::XRSessionFeature::DOM_OVERLAY:
@@ -196,9 +296,17 @@ 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 are
+ // all valid only for immersive AR mode for now.
+ return mode == device::mojom::blink::XRSessionMode::kImmersiveAr;
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.
+ if (!session_init->hasDepthSensing()) {
+ execution_context->AddConsoleMessage(
+ MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript, error_level,
+ "Must provide a depthSensing dictionary in XRSessionInit"));
+ return false;
+ }
return mode == device::mojom::blink::XRSessionMode::kImmersiveAr;
}
}
@@ -223,6 +331,7 @@ bool HasRequiredFeaturePolicy(const ExecutionContext* context,
case device::mojom::XRSessionFeature::PLANE_DETECTION:
case device::mojom::XRSessionFeature::DEPTH:
case device::mojom::XRSessionFeature::IMAGE_TRACKING:
+ case device::mojom::XRSessionFeature::HAND_INPUT:
return context->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kWebXr,
ReportOptions::kReportOnFailure);
@@ -287,6 +396,16 @@ bool IsFeatureRequested(
}
}
+bool IsImmersiveArAllowedBySettings(LocalDOMWindow* window) {
+ // If we're unable to get the settings for any reason, we'll treat the AR as
+ // enabled.
+ if (!window->GetFrame()) {
+ return true;
+ }
+
+ return window->GetFrame()->GetSettings()->GetWebXRImmersiveArAllowed();
+}
+
} // namespace
// Ensure that the inline session request is allowed, if not
@@ -783,6 +902,15 @@ device::mojom::blink::XRSessionOptionsPtr XRSystem::XRSessionOptionsFromQuery(
device::mojom::blink::XRTrackedImage::New();
*session_options->tracked_images[i] = query.TrackedImages()[i];
}
+
+ if (query.HasFeature(device::mojom::XRSessionFeature::DEPTH)) {
+ session_options->depth_options =
+ device::mojom::blink::XRDepthOptions::New();
+ session_options->depth_options->usage_preferences = query.PreferredUsage();
+ session_options->depth_options->data_format_preferences =
+ query.PreferredFormat();
+ }
+
return session_options;
}
@@ -796,11 +924,15 @@ XRSystem* XRSystem::FromIfExists(Document& document) {
}
XRSystem* XRSystem::From(Document& document) {
+ DVLOG(2) << __func__;
+
return document.domWindow() ? xr(*document.domWindow()->navigator())
: nullptr;
}
XRSystem* XRSystem::xr(Navigator& navigator) {
+ DVLOG(2) << __func__;
+
LocalDOMWindow* window = navigator.DomWindow();
if (!window)
return nullptr;
@@ -835,7 +967,7 @@ XRSystem::XRSystem(Navigator& navigator)
->GetFrameScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::kWebXR,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
+ {SchedulingPolicy::DisableBackForwardCache()})) {}
void XRSystem::FocusedFrameChanged() {
// Tell all sessions that focus changed.
@@ -972,10 +1104,10 @@ ScriptPromise XRSystem::InternalIsSessionSupported(
throw_on_unsupported);
if (session_mode == device::mojom::blink::XRSessionMode::kImmersiveAr &&
- !RuntimeEnabledFeatures::WebXRARModuleEnabled(GetExecutionContext())) {
+ !IsImmersiveArAllowed()) {
DVLOG(2) << __func__
<< ": Immersive AR session is only supported if WebXRARModule "
- "feature is enabled";
+ "feature is enabled by a runtime feature and web settings";
query->Resolve(false);
return promise;
}
@@ -1207,7 +1339,7 @@ XRSystem::RequestedXRSessionFeatureSet XRSystem::ParseRequestedFeatures(
feature_enum.value())) {
AddConsoleMessage(error_level,
"Feature '" + feature_string +
- "' is not permitted by feature policy");
+ "' is not permitted by permissions policy");
result.invalid_features = true;
} else {
DVLOG(3) << __func__ << ": Adding feature " << feature_string
@@ -1247,7 +1379,7 @@ ScriptPromise XRSystem::requestSession(ScriptState* script_state,
// If the request is for immersive-ar, ensure that feature is enabled.
if (session_mode == device::mojom::blink::XRSessionMode::kImmersiveAr &&
- !RuntimeEnabledFeatures::WebXRARModuleEnabled(GetExecutionContext())) {
+ !IsImmersiveArAllowed()) {
exception_state.ThrowTypeError(
String::Format(kImmersiveArModeNotValid, "requestSession"));
@@ -1348,6 +1480,36 @@ ScriptPromise XRSystem::requestSession(ScriptState* script_state,
query->SetTrackedImages(images);
}
+ if (query->HasFeature(device::mojom::XRSessionFeature::DEPTH)) {
+ // Prerequisites were checked by IsFeatureValidForMode and IDL.
+ DCHECK(session_init);
+ DCHECK(session_init->hasDepthSensing());
+ DCHECK(session_init->depthSensing()->hasUsagePreference())
+ << "required in IDL";
+ DCHECK(session_init->depthSensing()->hasDataFormatPreference())
+ << "required in IDL";
+
+ Vector<device::mojom::XRDepthUsage> preferred_usage =
+ ParseDepthUsages(session_init->depthSensing()->usagePreference());
+ Vector<device::mojom::XRDepthDataFormat> preferred_format =
+ ParseDepthFormats(session_init->depthSensing()->dataFormatPreference());
+
+ // If the depth API is required and either preferred usages or preferred
+ // formats are empty, we already know that the session creation will fail
+ // (as we won't be able to pick a supported usage & format combination), so
+ // let's fail it already:
+ if (query->RequiredFeatures().Contains(
+ device::mojom::XRSessionFeature::DEPTH) &&
+ (preferred_usage.IsEmpty() || preferred_format.IsEmpty())) {
+ query->RejectWithDOMException(DOMExceptionCode::kNotSupportedError,
+ kDepthSensingConfigurationNotSupported,
+ &exception_state);
+ return promise;
+ }
+
+ query->SetDepthSensingConfiguration(preferred_usage, preferred_format);
+ }
+
// The various session request methods may have other checks that would reject
// before needing to create the vr service, so we don't try to create it here.
switch (session_mode) {
@@ -1436,6 +1598,7 @@ void XRSystem::OnRequestSessionSetupForDomOverlay(
void XRSystem::OnRequestSessionReturned(
PendingRequestSessionQuery* query,
device::mojom::blink::RequestSessionResultPtr result) {
+ DVLOG(2) << __func__;
// The session query has returned and we're about to resolve or reject the
// promise, so remove it from our outstanding list.
DCHECK(outstanding_request_queries_.Contains(query));
@@ -1473,13 +1636,8 @@ void XRSystem::OnRequestSessionReturned(
auto session_ptr = std::move(result->get_success()->session);
auto metrics_recorder = std::move(result->get_success()->metrics_recorder);
- bool environment_integration =
- query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr;
-
// immersive sessions must supply display info.
DCHECK(session_ptr->display_info);
- DVLOG(2) << __func__
- << ": environment_integration=" << environment_integration;
XRSessionFeatureSet enabled_features;
for (const auto& feature : session_ptr->enabled_features) {
@@ -1497,6 +1655,11 @@ void XRSystem::OnRequestSessionReturned(
if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr ||
query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) {
+ const bool anchors_enabled = base::Contains(
+ enabled_features, device::mojom::XRSessionFeature::ANCHORS);
+ const bool hit_test_enabled = base::Contains(
+ enabled_features, device::mojom::XRSessionFeature::HIT_TEST);
+ const bool environment_integration = hit_test_enabled || anchors_enabled;
if (environment_integration) {
// See Task Sources spreadsheet for more information:
// https://docs.google.com/spreadsheets/d/1b-dus1Ug3A8y0lX0blkmOjJILisUASdj8x9YN_XMwYc/view
@@ -1511,7 +1674,9 @@ void XRSystem::OnRequestSessionReturned(
WrapWeakPersistent(this)));
session->OnEnvironmentProviderCreated();
+ }
+ if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) {
DCHECK(DomWindow());
if (query->HasFeature(device::mojom::XRSessionFeature::DOM_OVERLAY)) {
DCHECK(query->DOMOverlayElement());
@@ -1679,6 +1844,19 @@ void XRSystem::TryEnsureService() {
DisposeType::kDisconnected));
}
+bool XRSystem::IsImmersiveArAllowed() {
+ const bool ar_allowed_in_settings =
+ IsImmersiveArAllowedBySettings(DomWindow());
+ const bool ar_enabled =
+ ar_allowed_in_settings &&
+ RuntimeEnabledFeatures::WebXRARModuleEnabled(GetExecutionContext());
+
+ DVLOG(2) << __func__ << ": ar_allowed_in_settings=" << ar_allowed_in_settings
+ << ", ar_enabled=" << ar_enabled;
+
+ return ar_enabled;
+}
+
void XRSystem::Trace(Visitor* visitor) const {
visitor->Trace(frame_provider_);
visitor->Trace(sessions_);
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 289801f6120..fb649c82b47 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_system.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.h
@@ -228,6 +228,21 @@ class XRSystem final : public EventTargetWithInlineData,
return tracked_images_;
}
+ void SetDepthSensingConfiguration(
+ const Vector<device::mojom::XRDepthUsage>& preferred_usage,
+ const Vector<device::mojom::XRDepthDataFormat>& preferred_format) {
+ preferred_usage_ = preferred_usage;
+ preferred_format_ = preferred_format;
+ }
+
+ const Vector<device::mojom::XRDepthUsage>& PreferredUsage() const {
+ return preferred_usage_;
+ }
+
+ const Vector<device::mojom::XRDepthDataFormat>& PreferredFormat() const {
+ return preferred_format_;
+ }
+
virtual void Trace(Visitor*) const;
private:
@@ -253,6 +268,9 @@ class XRSystem final : public EventTargetWithInlineData,
Vector<device::mojom::blink::XRTrackedImage> tracked_images_;
+ Vector<device::mojom::XRDepthUsage> preferred_usage_;
+ Vector<device::mojom::XRDepthDataFormat> preferred_format_;
+
DISALLOW_COPY_AND_ASSIGN(PendingRequestSessionQuery);
};
@@ -427,6 +445,11 @@ class XRSystem final : public EventTargetWithInlineData,
void TryEnsureService();
+ // Helper, returns true if immersive AR session creation is supported.
+ // Currently, it checks whether AR is enabled in runtime features, and in web
+ // settings (controlled by enterprise policy).
+ bool IsImmersiveArAllowed();
+
// Indicates whether use of requestDevice has already been logged.
bool did_log_supports_immersive_ = false;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
index d1b6712bfe2..541841ee554 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.cc
@@ -81,4 +81,120 @@ base::Optional<device::Pose> CreatePose(
gfx::Transform(TransformationMatrix::ToSkMatrix44(matrix)));
}
+device::mojom::blink::XRHandJoint StringToMojomHandJoint(
+ const String& hand_joint_string) {
+ if (hand_joint_string == "wrist") {
+ return device::mojom::blink::XRHandJoint::kWrist;
+ } else if (hand_joint_string == "thumb-metacarpal") {
+ return device::mojom::blink::XRHandJoint::kThumbMetacarpal;
+ } else if (hand_joint_string == "thumb-phalanx-proximal") {
+ return device::mojom::blink::XRHandJoint::kThumbPhalanxProximal;
+ } else if (hand_joint_string == "thumb-phalanx-distal") {
+ return device::mojom::blink::XRHandJoint::kThumbPhalanxDistal;
+ } else if (hand_joint_string == "thumb-tip") {
+ return device::mojom::blink::XRHandJoint::kThumbTip;
+ } else if (hand_joint_string == "index-finger-metacarpal") {
+ return device::mojom::blink::XRHandJoint::kIndexFingerMetacarpal;
+ } else if (hand_joint_string == "index-finger-phalanx-proximal") {
+ return device::mojom::blink::XRHandJoint::kIndexFingerPhalanxProximal;
+ } else if (hand_joint_string == "index-finger-phalanx-intermediate") {
+ return device::mojom::blink::XRHandJoint::kIndexFingerPhalanxIntermediate;
+ } else if (hand_joint_string == "index-finger-phalanx-distal") {
+ return device::mojom::blink::XRHandJoint::kIndexFingerPhalanxDistal;
+ } else if (hand_joint_string == "index-finger-tip") {
+ return device::mojom::blink::XRHandJoint::kIndexFingerTip;
+ } else if (hand_joint_string == "middle-finger-metacarpal") {
+ return device::mojom::blink::XRHandJoint::kMiddleFingerMetacarpal;
+ } else if (hand_joint_string == "middle-finger-phalanx-proximal") {
+ return device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxProximal;
+ } else if (hand_joint_string == "middle-finger-phalanx-intermediate") {
+ return device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxIntermediate;
+ } else if (hand_joint_string == "middle-finger-phalanx-distal") {
+ return device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxDistal;
+ } else if (hand_joint_string == "middle-finger-tip") {
+ return device::mojom::blink::XRHandJoint::kMiddleFingerTip;
+ } else if (hand_joint_string == "ring-finger-metacarpal") {
+ return device::mojom::blink::XRHandJoint::kRingFingerMetacarpal;
+ } else if (hand_joint_string == "ring-finger-phalanx-proximal") {
+ return device::mojom::blink::XRHandJoint::kRingFingerPhalanxProximal;
+ } else if (hand_joint_string == "ring-finger-phalanx-intermediate") {
+ return device::mojom::blink::XRHandJoint::kRingFingerPhalanxIntermediate;
+ } else if (hand_joint_string == "ring-finger-phalanx-distal") {
+ return device::mojom::blink::XRHandJoint::kRingFingerPhalanxDistal;
+ } else if (hand_joint_string == "ring-finger-tip") {
+ return device::mojom::blink::XRHandJoint::kRingFingerTip;
+ } else if (hand_joint_string == "pinky-finger-metacarpal") {
+ return device::mojom::blink::XRHandJoint::kPinkyFingerMetacarpal;
+ } else if (hand_joint_string == "pinky-finger-phalanx-proximal") {
+ return device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxProximal;
+ } else if (hand_joint_string == "pinky-finger-phalanx-intermediate") {
+ return device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxIntermediate;
+ } else if (hand_joint_string == "pinky-finger-phalanx-distal") {
+ return device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxDistal;
+ } else if (hand_joint_string == "pinky-finger-tip") {
+ return device::mojom::blink::XRHandJoint::kPinkyFingerTip;
+ }
+
+ NOTREACHED();
+ return device::mojom::blink::XRHandJoint::kMaxValue;
+}
+
+String MojomHandJointToString(device::mojom::blink::XRHandJoint hand_joint) {
+ switch (hand_joint) {
+ case device::mojom::blink::XRHandJoint::kWrist:
+ return "wrist";
+ case device::mojom::blink::XRHandJoint::kThumbMetacarpal:
+ return "thumb-metacarpal";
+ case device::mojom::blink::XRHandJoint::kThumbPhalanxProximal:
+ return "thumb-phalanx-proximal";
+ case device::mojom::blink::XRHandJoint::kThumbPhalanxDistal:
+ return "thumb-phalanx-distal";
+ case device::mojom::blink::XRHandJoint::kThumbTip:
+ return "thumb-tip";
+ case device::mojom::blink::XRHandJoint::kIndexFingerMetacarpal:
+ return "index-finger-metacarpal";
+ case device::mojom::blink::XRHandJoint::kIndexFingerPhalanxProximal:
+ return "index-finger-phalanx-proximal";
+ case device::mojom::blink::XRHandJoint::kIndexFingerPhalanxIntermediate:
+ return "index-finger-phalanx-intermediate";
+ case device::mojom::blink::XRHandJoint::kIndexFingerPhalanxDistal:
+ return "index-finger-phalanx-distal";
+ case device::mojom::blink::XRHandJoint::kIndexFingerTip:
+ return "index-finger-tip";
+ case device::mojom::blink::XRHandJoint::kMiddleFingerMetacarpal:
+ return "middle-finger-metacarpal";
+ case device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxProximal:
+ return "middle-finger-phalanx-proximal";
+ case device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxIntermediate:
+ return "middle-finger-phalanx-intermediate";
+ case device::mojom::blink::XRHandJoint::kMiddleFingerPhalanxDistal:
+ return "middle-finger-phalanx-distal";
+ case device::mojom::blink::XRHandJoint::kMiddleFingerTip:
+ return "middle-finger-tip";
+ case device::mojom::blink::XRHandJoint::kRingFingerMetacarpal:
+ return "ring-finger-metacarpal";
+ case device::mojom::blink::XRHandJoint::kRingFingerPhalanxProximal:
+ return "ring-finger-phalanx-proximal";
+ case device::mojom::blink::XRHandJoint::kRingFingerPhalanxIntermediate:
+ return "ring-finger-phalanx-intermediate";
+ case device::mojom::blink::XRHandJoint::kRingFingerPhalanxDistal:
+ return "ring-finger-phalanx-distal";
+ case device::mojom::blink::XRHandJoint::kRingFingerTip:
+ return "ring-finger-tip";
+ case device::mojom::blink::XRHandJoint::kPinkyFingerMetacarpal:
+ return "pinky-finger-metacarpal";
+ case device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxProximal:
+ return "pinky-finger-phalanx-proximal";
+ case device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxIntermediate:
+ return "pinky-finger-phalanx-intermediate";
+ case device::mojom::blink::XRHandJoint::kPinkyFingerPhalanxDistal:
+ return "pinky-finger-phalanx-distal";
+ case device::mojom::blink::XRHandJoint::kPinkyFingerTip:
+ return "pinky-finger-tip";
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_utils.h b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
index 1962309ec6c..2eea771bc48 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_utils.h
@@ -6,9 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
#include "device/vr/public/mojom/pose.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/modules/xr/xr_webgl_rendering_context.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
@@ -40,6 +42,11 @@ constexpr char kUnableToNormalizeZeroLength[] =
base::Optional<device::Pose> CreatePose(
const blink::TransformationMatrix& matrix);
+// Hand joint conversion methods
+device::mojom::blink::XRHandJoint StringToMojomHandJoint(
+ const String& hand_joint_string);
+String MojomHandJointToString(device::mojom::blink::XRHandJoint hand_joint);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
index 19e4203b99c..b74538ffad8 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
@@ -31,6 +31,13 @@ XRWebGLBinding* XRWebGLBinding::Create(XRSession* session,
return nullptr;
}
+ if (!session->immersive()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Cannot create an XRWebGLBinding for an "
+ "inline XRSession.");
+ return nullptr;
+ }
+
WebGLRenderingContextBase* webgl_context =
webglRenderingContextBaseFromUnion(context);
@@ -41,7 +48,7 @@ XRWebGLBinding* XRWebGLBinding::Create(XRSession* session,
return nullptr;
}
- if (session->immersive() && !webgl_context->IsXRCompatible()) {
+ if (!webgl_context->IsXRCompatible()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"WebGL context must be marked as XR compatible in order to "
@@ -70,10 +77,27 @@ WebGLTexture* XRWebGLBinding::getReflectionCubeMap(
return nullptr;
}
+ if (session_->ended()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "Cannot get a reflection cube map for a session which has ended.");
+ return nullptr;
+ }
+
+ if (session_ != light_probe->session()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
+ "LightProbe comes from a different session than this binding");
+ return nullptr;
+ }
+
// Determine the internal_format, format, and type that will be passed to
// glTexImage2D for each possible light probe reflection format. The formats
// will differ depending on whether we're using WebGL 2 or WebGL 1 with
// extensions.
+ // Note that at this point, since we know we have a valid lightProbe, we also
+ // know that we support whatever reflectionFormat it was created with, as it
+ // would not have been created otherwise.
switch (light_probe->ReflectionFormat()) {
case XRLightProbe::kReflectionFormatRGBA16F:
if (!webgl2_ && !webgl_context_->ExtensionsUtil()->IsExtensionEnabled(
@@ -150,6 +174,38 @@ WebGLTexture* XRWebGLBinding::getCameraImage(XRFrame* frame, XRView* view) {
return texture;
}
+XRWebGLDepthInformation* XRWebGLBinding::getDepthInformation(
+ XRView* view,
+ ExceptionState& exception_state) {
+ DVLOG(1) << __func__;
+
+ if (!session_->IsFeatureEnabled(device::mojom::XRSessionFeature::DEPTH)) {
+ DVLOG(2) << __func__ << ": depth sensing is not enabled on a session";
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ XRSession::kDepthSensingFeatureNotSupported);
+ return nullptr;
+ }
+
+ XRFrame* frame = view->frame();
+
+ if (!frame->IsActive()) {
+ DVLOG(2) << __func__ << ": frame is not active";
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ XRFrame::kInactiveFrame);
+ return nullptr;
+ }
+
+ if (!frame->IsAnimationFrame()) {
+ DVLOG(2) << __func__ << ": frame is not animating";
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ XRFrame::kNonAnimationFrame);
+ return nullptr;
+ }
+
+ return view->session()->GetWebGLDepthInformation(frame, exception_state);
+}
+
void XRWebGLBinding::Trace(Visitor* visitor) const {
visitor->Trace(session_);
visitor->Trace(webgl_context_);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.h b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.h
index 8d2bdce67e4..55f88c33525 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.h
@@ -19,6 +19,7 @@ class XRFrame;
class XRLightProbe;
class XRSession;
class XRView;
+class XRWebGLDepthInformation;
class XRWebGLBinding final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -36,6 +37,9 @@ class XRWebGLBinding final : public ScriptWrappable {
WebGLTexture* getReflectionCubeMap(XRLightProbe*, ExceptionState&);
WebGLTexture* getCameraImage(XRFrame*, XRView*);
+ XRWebGLDepthInformation* getDepthInformation(XRView* view,
+ ExceptionState& exception_state);
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.idl b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.idl
index 5279215180b..a2b0851b609 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_binding.idl
@@ -5,8 +5,7 @@
// https://immersive-web.github.io/layers/#XRWebGLBindingtype
[
SecureContext,
- Exposed=Window,
- RuntimeEnabled=WebXRLightEstimation
+ Exposed=Window
] interface XRWebGLBinding {
[RaisesException] constructor(XRSession session, XRWebGLRenderingContext context);
@@ -15,4 +14,7 @@
WebGLTexture? getReflectionCubeMap(XRLightProbe lightProbe);
[RuntimeEnabled=WebXRCameraAccess] WebGLTexture? getCameraImage(XRFrame frame, XRView view);
+
+ [RuntimeEnabled=WebXRDepth, RaisesException, MeasureAs=XRWebGLBindingGetDepthInformation]
+ XRWebGLDepthInformation? getDepthInformation(XRView view);
};
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.cc
new file mode 100644
index 00000000000..afc2197461e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.cc
@@ -0,0 +1,14 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/xr/xr_webgl_depth_information.h"
+
+namespace blink {
+
+WebGLTexture* XRWebGLDepthInformation::texture(
+ ExceptionState& exception_state) {
+ return nullptr;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.h
new file mode 100644
index 00000000000..4ed0ed6d678
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.h
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DEPTH_INFORMATION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DEPTH_INFORMATION_H_
+
+#include "third_party/blink/renderer/modules/xr/xr_depth_information.h"
+
+namespace blink {
+
+class ExceptionState;
+class WebGLTexture;
+
+class XRWebGLDepthInformation final : public XRDepthInformation {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ WebGLTexture* texture(ExceptionState& exception_state);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DEPTH_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.idl b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.idl
new file mode 100644
index 00000000000..e86904769d4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_depth_information.idl
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=WebXRDepth
+] interface XRWebGLDepthInformation : XRDepthInformation {
+ [RaisesException, SameObject, MeasureAs=XRWebGLDepthInformationTextureAttribute]
+ readonly attribute WebGLTexture texture;
+};
+
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc
deleted file mode 100644
index 05a13a9e50c..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.cc
+++ /dev/null
@@ -1,96 +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/xr/xr_world_information.h"
-
-#include "base/trace_event/trace_event.h"
-#include "third_party/blink/renderer/modules/xr/xr_session.h"
-
-namespace blink {
-
-XRWorldInformation::XRWorldInformation(XRSession* session)
- : session_(session) {}
-
-void XRWorldInformation::Trace(Visitor* visitor) const {
- visitor->Trace(plane_ids_to_planes_);
- visitor->Trace(session_);
- ScriptWrappable::Trace(visitor);
-}
-
-XRPlaneSet* XRWorldInformation::detectedPlanes() const {
- DVLOG(3) << __func__;
-
- HeapHashSet<Member<XRPlane>> result;
-
- if (is_detected_planes_null_)
- return nullptr;
-
- for (auto& plane_id_and_plane : plane_ids_to_planes_) {
- result.insert(plane_id_and_plane.value);
- }
-
- return MakeGarbageCollected<XRPlaneSet>(result);
-}
-
-void XRWorldInformation::ProcessPlaneInformation(
- const device::mojom::blink::XRPlaneDetectionData* detected_planes_data,
- double timestamp) {
- TRACE_EVENT0("xr", __FUNCTION__);
-
- if (!detected_planes_data) {
- DVLOG(3) << __func__ << ": detected_planes_data is null";
-
- // We have received a nullopt - plane detection is not supported or
- // disabled. Mark detected_planes as null & clear stored planes.
- is_detected_planes_null_ = true;
- plane_ids_to_planes_.clear();
- return;
- }
-
- TRACE_COUNTER2("xr", "Plane statistics", "All planes",
- detected_planes_data->all_planes_ids.size(), "Updated planes",
- detected_planes_data->updated_planes_data.size());
-
- DVLOG(3) << __func__ << ": updated planes size="
- << detected_planes_data->updated_planes_data.size()
- << ", all planes size="
- << detected_planes_data->all_planes_ids.size();
-
- is_detected_planes_null_ = false;
-
- HeapHashMap<uint64_t, Member<XRPlane>> updated_planes;
-
- // First, process all planes that had their information updated (new planes
- // are also processed here).
- for (const auto& plane : detected_planes_data->updated_planes_data) {
- DCHECK(plane);
-
- auto it = plane_ids_to_planes_.find(plane->id);
- if (it != plane_ids_to_planes_.end()) {
- updated_planes.insert(plane->id, it->value);
- it->value->Update(*plane, timestamp);
- } else {
- updated_planes.insert(
- plane->id, MakeGarbageCollected<XRPlane>(plane->id, session_, *plane,
- timestamp));
- }
- }
-
- // Then, copy over the planes that were not updated but are still present.
- for (const auto& plane_id : detected_planes_data->all_planes_ids) {
- auto it_updated = updated_planes.find(plane_id);
-
- // If the plane was already updated, there is nothing to do as it was
- // already moved to |updated_planes|. Otherwise just copy it over as-is.
- if (it_updated == updated_planes.end()) {
- auto it = plane_ids_to_planes_.find(plane_id);
- DCHECK(it != plane_ids_to_planes_.end());
- updated_planes.insert(plane_id, it->value);
- }
- }
-
- plane_ids_to_planes_.swap(updated_planes);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.h
deleted file mode 100644
index 4675e7d98fd..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.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_XR_XR_WORLD_INFORMATION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WORLD_INFORMATION_H_
-
-#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
-#include "third_party/blink/renderer/modules/xr/xr_plane.h"
-#include "third_party/blink/renderer/modules/xr/xr_plane_set.h"
-
-namespace blink {
-
-class XRSession;
-
-class XRWorldInformation : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- XRWorldInformation(XRSession* session);
-
- // Returns set of detected planes. Returns null if plane detection is
- // disabled.
- XRPlaneSet* detectedPlanes() const;
-
- void Trace(Visitor* visitor) const override;
-
- // Applies changes to the stored plane information based on the contents of
- // the received frame data. This will update the contents of
- // plane_ids_to_planes_.
- void ProcessPlaneInformation(
- const device::mojom::blink::XRPlaneDetectionData* detected_planes_data,
- double timestamp);
-
- private:
- // Signifies if we should return null from `detectedPlanes()`.
- // This is the case if we have a freshly constructed instance, or if our
- // last `ProcessPlaneInformation()` was called with base::nullopt.
- bool is_detected_planes_null_ = true;
- HeapHashMap<uint64_t, Member<XRPlane>> plane_ids_to_planes_;
-
- Member<XRSession> session_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WORLD_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl b/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl
deleted file mode 100644
index 7aa695098d9..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_information.idl
+++ /dev/null
@@ -1,15 +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.
-
-// More details about the real-world understanding APIs can be found here:
-// https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
-[
- SecureContext,
- Exposed=Window,
- RuntimeEnabled=WebXRPlaneDetection
-]
-interface XRWorldInformation {
- readonly attribute XRPlaneSet? detectedPlanes;
-};
-
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc
deleted file mode 100644
index 249264fa67c..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.cc
+++ /dev/null
@@ -1,20 +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/xr/xr_world_tracking_state.h"
-
-#include "third_party/blink/renderer/modules/xr/xr_plane_detection_state.h"
-
-namespace blink {
-
-XRWorldTrackingState::XRWorldTrackingState(bool plane_detection_enabled)
- : plane_detection_state_(MakeGarbageCollected<XRPlaneDetectionState>(
- plane_detection_enabled)) {}
-
-void XRWorldTrackingState::Trace(Visitor* visitor) const {
- visitor->Trace(plane_detection_state_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h
deleted file mode 100644
index 2cbff13101a..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.h
+++ /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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WORLD_TRACKING_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WORLD_TRACKING_STATE_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class XRPlaneDetectionState;
-
-class XRWorldTrackingState : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit XRWorldTrackingState(bool plane_detection_enabled);
-
- XRPlaneDetectionState* planeDetectionState() const {
- return plane_detection_state_;
- }
-
- void Trace(Visitor* visitor) const override;
-
- private:
- Member<XRPlaneDetectionState> plane_detection_state_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WORLD_TRACKING_STATE_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl b/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl
deleted file mode 100644
index 070ee061f96..00000000000
--- a/chromium/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl
+++ /dev/null
@@ -1,15 +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.
-
-// More details about the real-world understanding APIs can be found here:
-// https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
-[
- SecureContext,
- Exposed=Window,
- RuntimeEnabled=WebXRPlaneDetection
-]
-interface XRWorldTrackingState {
- readonly attribute XRPlaneDetectionState planeDetectionState;
-};
-
diff --git a/chromium/third_party/blink/renderer/platform/BUILD.gn b/chromium/third_party/blink/renderer/platform/BUILD.gn
index 80e96bbedf8..ca52366fe2e 100644
--- a/chromium/third_party/blink/renderer/platform/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/BUILD.gn
@@ -16,11 +16,14 @@ import("//third_party/blink/public/public_features.gni")
import("//third_party/blink/renderer/build/scripts/scripts.gni")
import("//third_party/blink/renderer/config.gni")
import("//third_party/blink/renderer/platform/platform_generated.gni")
+import("//third_party/webrtc/webrtc.gni")
import("//v8/gni/v8.gni")
# Most targets in this file are private actions so use that as the default.
visibility = [
":*",
+ "//:gn_all",
+ "//third_party/blink/public:all_blink",
"//third_party/blink/renderer/platform/heap:test_support",
]
@@ -174,6 +177,7 @@ group("blink_platform_public_deps") {
"//third_party/libpng",
"//third_party/libwebp",
"//third_party/ots",
+ "//ui/gfx/animation/keyframe",
"//url",
"//v8",
]
@@ -397,6 +401,8 @@ component("platform") {
"audio/vector_math.cc",
"audio/vector_math.h",
"audio/vector_math_scalar.h",
+ "back_forward_cache_utils.cc",
+ "back_forward_cache_utils.h",
"bindings/active_script_wrappable_base.cc",
"bindings/active_script_wrappable_base.h",
"bindings/active_script_wrappable_manager.cc",
@@ -417,6 +423,7 @@ component("platform") {
"bindings/dom_wrapper_world.h",
"bindings/enumeration_base.h",
"bindings/exception_code.h",
+ "bindings/exception_context.h",
"bindings/exception_messages.cc",
"bindings/exception_messages.h",
"bindings/exception_state.cc",
@@ -447,9 +454,8 @@ component("platform") {
"bindings/trace_wrapper_v8_reference.h",
"bindings/trace_wrapper_v8_string.cc",
"bindings/trace_wrapper_v8_string.h",
+ "bindings/union_base.cc",
"bindings/union_base.h",
- "bindings/v0_custom_element_binding.cc",
- "bindings/v0_custom_element_binding.h",
"bindings/v8_binding.cc",
"bindings/v8_binding.h",
"bindings/v8_binding_macros.h",
@@ -482,6 +488,7 @@ component("platform") {
"bindings/wrapper_type_info.cc",
"bindings/wrapper_type_info.h",
"content_decryption_module_result.h",
+ "context_lifecycle_notifier.cc",
"context_lifecycle_notifier.h",
"context_lifecycle_observer.cc",
"context_lifecycle_observer.h",
@@ -497,6 +504,7 @@ component("platform") {
"disk_data_allocator.h",
"disk_data_metadata.h",
"exported/file_path_conversion.cc",
+ "exported/impression_conversions.cc",
"exported/interface_registry.cc",
"exported/mediastream/web_media_stream.cc",
"exported/mediastream/web_media_stream_source.cc",
@@ -504,12 +512,12 @@ component("platform") {
"exported/mediastream/web_platform_media_stream_source.cc",
"exported/platform.cc",
"exported/resource_load_info_notifier_wrapper.cc",
- "exported/sync_load_response.cc",
"exported/url_conversion.cc",
"exported/video_capture/web_video_capture_impl_manager.cc",
"exported/weak_wrapper_resource_load_info_notifier.cc",
"exported/web_audio_bus.cc",
"exported/web_audio_device.cc",
+ "exported/web_back_forward_cache_loader_helper.cc",
"exported/web_blob_info.cc",
"exported/web_cache.cc",
"exported/web_content_decryption_module.cc",
@@ -536,7 +544,6 @@ component("platform") {
"exported/web_media_player_source.cc",
"exported/web_media_stream_audio_sink.cc",
"exported/web_memory_pressure_listener.cc",
- "exported/web_mixed_content.cc",
"exported/web_network_state_notifier.cc",
"exported/web_runtime_features.cc",
"exported/web_security_origin.cc",
@@ -659,6 +666,8 @@ component("platform") {
"fonts/shaping/caching_word_shaper.h",
"fonts/shaping/case_mapping_harfbuzz_buffer_filler.cc",
"fonts/shaping/case_mapping_harfbuzz_buffer_filler.h",
+ "fonts/shaping/font_features.cc",
+ "fonts/shaping/font_features.h",
"fonts/shaping/glyph_bounds_accumulator.h",
"fonts/shaping/harfbuzz_face.cc",
"fonts/shaping/harfbuzz_face.h",
@@ -806,6 +815,8 @@ component("platform") {
"graphics/canvas_resource_dispatcher.h",
"graphics/canvas_resource_host.cc",
"graphics/canvas_resource_host.h",
+ "graphics/canvas_resource_params.cc",
+ "graphics/canvas_resource_params.h",
"graphics/canvas_resource_provider.cc",
"graphics/canvas_resource_provider.h",
"graphics/color.cc",
@@ -946,6 +957,8 @@ component("platform") {
"graphics/gpu/webgl_image_conversion.h",
"graphics/gpu/webgpu_image_bitmap_handler.cc",
"graphics/gpu/webgpu_image_bitmap_handler.h",
+ "graphics/gpu/webgpu_mailbox_texture.cc",
+ "graphics/gpu/webgpu_mailbox_texture.h",
"graphics/gpu/webgpu_swap_buffer_provider.cc",
"graphics/gpu/webgpu_swap_buffer_provider.h",
"graphics/gpu/xr_frame_transport.cc",
@@ -1041,6 +1054,7 @@ component("platform") {
"graphics/paint/hit_test_data.h",
"graphics/paint/ignore_paint_timing_scope.cc",
"graphics/paint/ignore_paint_timing_scope.h",
+ "graphics/paint/layer_selection_data.h",
"graphics/paint/paint_artifact.cc",
"graphics/paint/paint_artifact.h",
"graphics/paint/paint_canvas.h",
@@ -1062,6 +1076,7 @@ component("platform") {
"graphics/paint/paint_record_builder.h",
"graphics/paint/paint_recorder.h",
"graphics/paint/paint_shader.h",
+ "graphics/paint/painted_selection_bound.h",
"graphics/paint/property_tree_state.cc",
"graphics/paint/property_tree_state.h",
"graphics/paint/raster_invalidation_tracking.cc",
@@ -1088,6 +1103,10 @@ component("platform") {
"graphics/paint_worklet_paint_dispatcher.cc",
"graphics/paint_worklet_paint_dispatcher.h",
"graphics/paint_worklet_painter.h",
+ "graphics/parkable_image.cc",
+ "graphics/parkable_image.h",
+ "graphics/parkable_image_manager.cc",
+ "graphics/parkable_image_manager.h",
"graphics/path.cc",
"graphics/path.h",
"graphics/path_traversal_state.cc",
@@ -1106,6 +1125,9 @@ component("platform") {
"graphics/raster_dark_mode_filter_impl.h",
"graphics/replaying_canvas.cc",
"graphics/replaying_canvas.h",
+ "graphics/resource_id_traits.h",
+ "graphics/rw_buffer.cc",
+ "graphics/rw_buffer.h",
"graphics/scoped_interpolation_quality.h",
"graphics/scrollbar_theme_settings.cc",
"graphics/scrollbar_theme_settings.h",
@@ -1129,6 +1151,8 @@ component("platform") {
"graphics/touch_action_rect.h",
"graphics/unaccelerated_static_bitmap_image.cc",
"graphics/unaccelerated_static_bitmap_image.h",
+ "graphics/video_frame_image_util.cc",
+ "graphics/video_frame_image_util.h",
"graphics/video_frame_resource_provider.cc",
"graphics/video_frame_resource_provider.h",
"graphics/video_frame_submitter.cc",
@@ -1232,12 +1256,15 @@ component("platform") {
"mojo/heap_mojo_associated_receiver.h",
"mojo/heap_mojo_associated_receiver_set.h",
"mojo/heap_mojo_associated_remote.h",
+ "mojo/heap_mojo_associated_remote_set.h",
"mojo/heap_mojo_receiver.h",
"mojo/heap_mojo_receiver_set.h",
"mojo/heap_mojo_remote.h",
+ "mojo/heap_mojo_remote_set.h",
"mojo/heap_mojo_unique_receiver_set.h",
"mojo/heap_mojo_wrapper_mode.h",
"mojo/kurl_mojom_traits.h",
+ "mojo/mojo_binding_context.h",
"mojo/mojo_helper.h",
"mojo/security_origin_mojom_traits.h",
"mojo/string16_mojom_traits.cc",
@@ -1307,6 +1334,8 @@ component("platform") {
"peerconnection/rtc_video_decoder_adapter.h",
"peerconnection/rtc_video_decoder_factory.cc",
"peerconnection/rtc_video_decoder_factory.h",
+ "peerconnection/rtc_video_decoder_stream_adapter.cc",
+ "peerconnection/rtc_video_decoder_stream_adapter.h",
"peerconnection/rtc_video_encoder.cc",
"peerconnection/rtc_video_encoder.h",
"peerconnection/rtc_video_encoder_factory.cc",
@@ -1487,6 +1516,8 @@ component("platform") {
"widget/input/input_event_prediction.cc",
"widget/input/input_event_prediction.h",
"widget/input/input_handler_proxy.cc",
+ "widget/input/input_metrics.cc",
+ "widget/input/input_metrics.h",
"widget/input/main_thread_event_queue.cc",
"widget/input/main_thread_event_queue.h",
"widget/input/main_thread_event_queue_task.h",
@@ -1611,6 +1642,8 @@ component("platform") {
"//third_party/blink/renderer/platform/loader",
"//third_party/blink/renderer/platform/network",
"//third_party/blink/renderer/platform/scheduler",
+ "//third_party/blink/renderer/platform/wtf:buildflags",
+ "//third_party/fdlibm",
"//third_party/pffft:pffft",
"//ui/gfx",
]
@@ -1621,6 +1654,7 @@ component("platform") {
"//cc/ipc",
"//cc/mojo_embedder",
"//components/paint_preview/common",
+ "//components/power_scheduler",
"//components/search_engines:search_engine_utils",
"//components/viz/client",
"//components/viz/common",
@@ -1873,6 +1907,7 @@ static_library("test_support") {
deps = [
"//base/test:test_support",
+ "//gin",
"//media:test_support",
"//mojo/core/embedder",
"//mojo/public/cpp/bindings",
@@ -1898,6 +1933,15 @@ source_set("blink_platform_unittests_sources") {
visibility = [ "*" ]
testonly = true
+ # TODO(crbug.com/1173961): avoid depending on testonly webrtc targets.
+ if (rtc_include_tests) {
+ # This target uses some webrtc targets that are not part of
+ # "webrtc_component". This target relies on the fact that including a header
+ # that is not tracked by GN works without raising any warning. However it
+ # leads to build errors if rtc_include_tests = true.
+ check_includes = false
+ }
+
sources = [
"animation/animation_translation_util_test.cc",
"animation/compositor_animation_test.cc",
@@ -1931,6 +1975,7 @@ source_set("blink_platform_unittests_sources") {
"fonts/font_test.cc",
"fonts/font_test_utilities.cc",
"fonts/generic_font_family_settings_test.cc",
+ "fonts/opentype/font_format_check_test.cc",
"fonts/opentype/font_settings_test.cc",
"fonts/opentype/open_type_math_support_test.cc",
"fonts/opentype/open_type_vertical_data_test.cc",
@@ -1938,6 +1983,7 @@ source_set("blink_platform_unittests_sources") {
"fonts/orientation_iterator_test.cc",
"fonts/script_run_iterator_test.cc",
"fonts/shaping/caching_word_shaper_test.cc",
+ "fonts/shaping/font_features_test.cc",
"fonts/shaping/harfbuzz_shaper_test.cc",
"fonts/shaping/run_segmenter_test.cc",
"fonts/shaping/shape_result_bloberizer_test.cc",
@@ -1968,6 +2014,7 @@ source_set("blink_platform_unittests_sources") {
"geometry/layout_rect_test.cc",
"geometry/layout_size_test.cc",
"geometry/layout_unit_test.cc",
+ "geometry/length_functions_test.cc",
"geometry/length_test.cc",
"geometry/region_test.cc",
"graphics/accelerated_static_bitmap_image_test.cc",
@@ -2010,10 +2057,12 @@ source_set("blink_platform_unittests_sources") {
"graphics/paint/raster_invalidator_test.cc",
"graphics/paint/scrollbar_display_item_test.cc",
"graphics/paint_invalidation_reason_test.cc",
+ "graphics/parkable_image_test.cc",
"graphics/path_test.cc",
"graphics/placeholder_image_test.cc",
"graphics/raster_dark_mode_filter_impl_test.cc",
- "graphics/static_bitmap_image_test.cc",
+ "graphics/rw_buffer_test.cc",
+ "graphics/video_frame_image_util_test.cc",
"graphics/video_frame_submitter_test.cc",
"heap_observer_set_test.cc",
"image-decoders/bmp/bmp_image_decoder_test.cc",
@@ -2040,9 +2089,11 @@ source_set("blink_platform_unittests_sources") {
"mojo/big_string_mojom_traits_test.cc",
"mojo/heap_mojo_associated_receiver_set_test.cc",
"mojo/heap_mojo_associated_receiver_test.cc",
+ "mojo/heap_mojo_associated_remote_set_test.cc",
"mojo/heap_mojo_associated_remote_test.cc",
"mojo/heap_mojo_receiver_set_test.cc",
"mojo/heap_mojo_receiver_test.cc",
+ "mojo/heap_mojo_remote_set_test.cc",
"mojo/heap_mojo_remote_test.cc",
"mojo/heap_mojo_unique_receiver_set_test.cc",
"mojo/kurl_security_origin_test.cc",
@@ -2051,8 +2102,10 @@ source_set("blink_platform_unittests_sources") {
"p2p/ipc_network_manager_test.cc",
"peerconnection/rtc_encoded_audio_stream_transformer_test.cc",
"peerconnection/rtc_encoded_video_stream_transformer_test.cc",
+ "peerconnection/rtc_rtp_source_test.cc",
"peerconnection/rtc_stats_test.cc",
"peerconnection/rtc_video_decoder_adapter_test.cc",
+ "peerconnection/rtc_video_decoder_stream_adapter_test.cc",
"peerconnection/rtc_video_encoder_test.cc",
"peerconnection/stun_field_trial_test.cc",
"peerconnection/task_queue_factory_test.cc",
@@ -2152,6 +2205,7 @@ source_set("blink_platform_unittests_sources") {
"//mojo/public/cpp/bindings/tests:for_blink_tests",
"//mojo/public/cpp/test_support:test_utils",
"//mojo/public/interfaces/bindings/tests:test_interfaces_blink",
+ "//services/network/public/cpp:test_support",
"//services/viz/public/mojom",
"//skia",
"//skia:skcms",
@@ -2174,10 +2228,12 @@ source_set("blink_platform_unittests_sources") {
"//ui/base:features",
"//ui/base/prediction",
"//ui/gfx",
+ "//ui/gfx:test_support",
"//ui/gfx/geometry",
"//ui/gfx/geometry/mojom:test_interfaces_blink",
"//ui/gfx/mojom:test_interfaces_blink",
"//url",
+ "//url:url_test_support",
"//url/mojom:test_url_mojom_gurl_blink",
]
diff --git a/chromium/third_party/blink/renderer/platform/DEPS b/chromium/third_party/blink/renderer/platform/DEPS
index 731c86db53c..6d3ef8b42f6 100644
--- a/chromium/third_party/blink/renderer/platform/DEPS
+++ b/chromium/third_party/blink/renderer/platform/DEPS
@@ -13,6 +13,7 @@ include_rules = [
"+base/files",
"+base/containers/flat_map.h",
"+base/guid.h",
+ "+base/i18n/uchar.h",
"+base/json",
"+base/location.h",
"+base/logging.h",
@@ -42,6 +43,7 @@ include_rules = [
"+base/task/sequence_manager/task_time_observer.h",
"+base/test",
"+base/test/fuzzed_data_provider.h",
+ "+base/threading/platform_thread.h",
"+base/threading/thread_task_runner_handle.h",
"+base/threading/thread_restrictions.h",
"+base/time",
diff --git a/chromium/third_party/blink/renderer/platform/DIR_METADATA b/chromium/third_party/blink/renderer/platform/DIR_METADATA
new file mode 100644
index 00000000000..d7874ae83c0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/OWNERS b/chromium/third_party/blink/renderer/platform/OWNERS
index c3147cef533..3b41257e30d 100644
--- a/chromium/third_party/blink/renderer/platform/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/OWNERS
@@ -29,5 +29,3 @@ wangxianzhu@chromium.org
# you are changing.
per-file runtime_enabled_features.json5=file://third_party/blink/API_OWNERS
per-file runtime_enabled_features.json5=file://third_party/blink/renderer/core/OWNERS
-
-# COMPONENT: Platform
diff --git a/chromium/third_party/blink/renderer/platform/animation/DIR_METADATA b/chromium/third_party/blink/renderer/platform/animation/DIR_METADATA
new file mode 100644
index 00000000000..8146e6060d4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/animation/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Animation"
+}
+team_email: "animations-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/animation/OWNERS b/chromium/third_party/blink/renderer/platform/animation/OWNERS
index b19b85b5c5a..8a44822b898 100644
--- a/chromium/third_party/blink/renderer/platform/animation/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/animation/OWNERS
@@ -1,6 +1,3 @@
file://third_party/blink/renderer/core/animation/OWNERS
loyso@chromium.org
-
-# TEAM: animations-dev@chromium.org
-# COMPONENT: Blink>Animation
diff --git a/chromium/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc b/chromium/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
index d383ab0eae4..39531f36396 100644
--- a/chromium/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/animation_translation_util_test.cc
@@ -49,24 +49,24 @@ TEST(AnimationTranslationUtilTest, transformsWork) {
50.2, 100, -4, TransformOperation::kScale3D));
ToCompositorTransformOperations(ops, &out_ops, FloatSize());
- EXPECT_EQ(3UL, out_ops.AsCcTransformOperations().size());
+ EXPECT_EQ(3UL, out_ops.AsGfxTransformOperations().size());
const float kErr = 0.0001;
- auto& op0 = out_ops.AsCcTransformOperations().at(0);
- EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
+ auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+ EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
EXPECT_NEAR(op0.translate.x, 2.0f, kErr);
EXPECT_NEAR(op0.translate.y, 0.0f, kErr);
EXPECT_NEAR(op0.translate.z, 0.0f, kErr);
- auto& op1 = out_ops.AsCcTransformOperations().at(1);
- EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_ROTATE, op1.type);
+ auto& op1 = out_ops.AsGfxTransformOperations().at(1);
+ EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_ROTATE, op1.type);
EXPECT_NEAR(op1.rotate.axis.x, 0.1f, kErr);
EXPECT_NEAR(op1.rotate.axis.y, 0.2f, kErr);
EXPECT_NEAR(op1.rotate.axis.z, 0.3f, kErr);
EXPECT_NEAR(op1.rotate.angle, 200000.4f, 0.01f);
- auto& op2 = out_ops.AsCcTransformOperations().at(2);
- EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_SCALE, op2.type);
+ auto& op2 = out_ops.AsGfxTransformOperations().at(2);
+ EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_SCALE, op2.type);
EXPECT_NEAR(op2.scale.x, 50.2f, kErr);
EXPECT_NEAR(op2.scale.y, 100.0f, kErr);
EXPECT_NEAR(op2.scale.z, -4.0f, kErr);
@@ -82,10 +82,10 @@ TEST(AnimationTranslationUtilTest, RelativeTranslate) {
CompositorTransformOperations out_ops;
ToCompositorTransformOperations(ops, &out_ops, FloatSize(200, 100));
- ASSERT_EQ(out_ops.AsCcTransformOperations().size(), 1u);
+ ASSERT_EQ(out_ops.AsGfxTransformOperations().size(), 1u);
- auto& op0 = out_ops.AsCcTransformOperations().at(0);
- EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
+ auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+ EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_TRANSLATE, op0.type);
EXPECT_EQ(op0.translate.x, 100.0f);
EXPECT_EQ(op0.translate.y, 50.0f);
EXPECT_EQ(op0.translate.z, 0.0f);
@@ -104,14 +104,14 @@ TEST(AnimationTranslationUtilTest, RelativeInterpolated) {
CompositorTransformOperations out_ops;
ToCompositorTransformOperations(ops_c, &out_ops, FloatSize(100, 100));
- ASSERT_EQ(out_ops.AsCcTransformOperations().size(), 1u);
+ ASSERT_EQ(out_ops.AsGfxTransformOperations().size(), 1u);
- auto& op0 = out_ops.AsCcTransformOperations().at(0);
- cc::TransformOperations ops_expected;
+ auto& op0 = out_ops.AsGfxTransformOperations().at(0);
+ gfx::TransformOperations ops_expected;
ops_expected.AppendTranslate(25, 0, 0);
- EXPECT_EQ(cc::TransformOperation::TRANSFORM_OPERATION_MATRIX, op0.type);
- cc::ExpectTransformationMatrixNear(op0.matrix, ops_expected.at(0).matrix,
- 1e-6f);
+ EXPECT_EQ(gfx::TransformOperation::TRANSFORM_OPERATION_MATRIX, op0.type);
+ gfx::ExpectTransformationMatrixNear(op0.matrix, ops_expected.at(0).matrix,
+ 1e-6f);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_animation.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_animation.cc
index 1831d202fb2..d3b032e5867 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_animation.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_animation.cc
@@ -120,7 +120,7 @@ void CompositorAnimation::NotifyAnimationTakeover(
base::TimeTicks monotonic_time,
int target_property,
base::TimeTicks animation_start_time,
- std::unique_ptr<cc::AnimationCurve> curve) {
+ std::unique_ptr<gfx::AnimationCurve> curve) {
if (delegate_) {
delegate_->NotifyAnimationTakeover(
(monotonic_time - base::TimeTicks()).InSecondsF(),
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_animation.h b/chromium/third_party/blink/renderer/platform/animation/compositor_animation.h
index eddfe40bcaf..2514643d7ad 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_animation.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_animation.h
@@ -17,7 +17,7 @@
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-namespace cc {
+namespace gfx {
class AnimationCurve;
}
@@ -81,7 +81,7 @@ class PLATFORM_EXPORT CompositorAnimation : public cc::AnimationDelegate {
void NotifyAnimationTakeover(base::TimeTicks monotonic_time,
int target_property,
base::TimeTicks animation_start_time,
- std::unique_ptr<cc::AnimationCurve>) override;
+ std::unique_ptr<gfx::AnimationCurve>) override;
void NotifyLocalTimeUpdated(
base::Optional<base::TimeDelta> local_time) override;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_animation_curve.h
index 2f057e3e23d..9b614f6101c 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_animation_curve.h
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/platform/platform_export.h"
-namespace cc {
+namespace gfx {
class AnimationCurve;
}
@@ -18,7 +18,8 @@ namespace blink {
class PLATFORM_EXPORT CompositorAnimationCurve {
public:
virtual ~CompositorAnimationCurve() = default;
- virtual std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const = 0;
+ virtual std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve()
+ const = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_animation_delegate.h b/chromium/third_party/blink/renderer/platform/animation/compositor_animation_delegate.h
index 5a577c0b285..17defe02b29 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_animation_delegate.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_animation_delegate.h
@@ -7,8 +7,8 @@
#include <memory>
-#include "cc/animation/animation_curve.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
namespace blink {
@@ -26,7 +26,7 @@ class PLATFORM_EXPORT CompositorAnimationDelegate {
virtual void NotifyAnimationTakeover(
double monotonic_time,
double animation_start_time,
- std::unique_ptr<cc::AnimationCurve> curve) {}
+ std::unique_ptr<gfx::AnimationCurve> curve) {}
virtual void NotifyLocalTimeUpdated(
base::Optional<base::TimeDelta> local_time) {}
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.cc
index 5e9b97c40d9..cadf710668a 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.cc
@@ -8,24 +8,24 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "cc/animation/animation_curve.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/timing_function.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace blink {
CompositorColorAnimationCurve::CompositorColorAnimationCurve()
- : curve_(cc::KeyframedColorAnimationCurve::Create()) {}
+ : curve_(gfx::KeyframedColorAnimationCurve::Create()) {}
CompositorColorAnimationCurve::CompositorColorAnimationCurve(
- std::unique_ptr<cc::KeyframedColorAnimationCurve> curve)
+ std::unique_ptr<gfx::KeyframedColorAnimationCurve> curve)
: curve_(std::move(curve)) {}
CompositorColorAnimationCurve::~CompositorColorAnimationCurve() = default;
std::unique_ptr<CompositorColorAnimationCurve>
CompositorColorAnimationCurve::CreateForTesting(
- std::unique_ptr<cc::KeyframedColorAnimationCurve> curve) {
+ std::unique_ptr<gfx::KeyframedColorAnimationCurve> curve) {
return base::WrapUnique(new CompositorColorAnimationCurve(std::move(curve)));
}
@@ -57,7 +57,7 @@ SkColor CompositorColorAnimationCurve::GetValue(double time) const {
return curve_->GetValue(base::TimeDelta::FromSecondsD(time));
}
-std::unique_ptr<cc::AnimationCurve>
+std::unique_ptr<gfx::AnimationCurve>
CompositorColorAnimationCurve::CloneToAnimationCurve() const {
return curve_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h
index bbdbc9f9db3..25b532b4303 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h
@@ -17,7 +17,7 @@
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkColor.h"
-namespace cc {
+namespace gfx {
class KeyframedColorAnimationCurve;
}
@@ -38,19 +38,19 @@ class PLATFORM_EXPORT CompositorColorAnimationCurve
SkColor GetValue(double time) const;
// CompositorAnimationCurve implementation.
- std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
+ std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve() const override;
static std::unique_ptr<CompositorColorAnimationCurve> CreateForTesting(
- std::unique_ptr<cc::KeyframedColorAnimationCurve>);
+ std::unique_ptr<gfx::KeyframedColorAnimationCurve>);
using Keyframes = Vector<std::unique_ptr<CompositorColorKeyframe>>;
Keyframes KeyframesForTesting() const;
private:
CompositorColorAnimationCurve(
- std::unique_ptr<cc::KeyframedColorAnimationCurve>);
+ std::unique_ptr<gfx::KeyframedColorAnimationCurve>);
- std::unique_ptr<cc::KeyframedColorAnimationCurve> curve_;
+ std::unique_ptr<gfx::KeyframedColorAnimationCurve> curve_;
DISALLOW_COPY_AND_ASSIGN(CompositorColorAnimationCurve);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve_test.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve_test.cc
index e0f27cbe25a..c89fc324926 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve_test.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_color_animation_curve_test.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "cc/animation/timing_function.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
using blink::CompositorAnimationCurve;
using blink::CompositorColorAnimationCurve;
@@ -147,8 +147,8 @@ TEST(WebColorAnimationCurveTest, EaseTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -180,8 +180,8 @@ TEST(WebColorAnimationCurveTest, EaseInTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_IN));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -200,8 +200,8 @@ TEST(WebColorAnimationCurveTest, EaseOutTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_OUT));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -220,8 +220,8 @@ TEST(WebColorAnimationCurveTest, EaseInOutTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_IN_OUT));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -243,8 +243,8 @@ TEST(WebColorAnimationCurveTest, CustomBezierTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2));
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::Create(x1, y1, x2, y2));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
EXPECT_EQ((unsigned)round(timing_function->GetValue(time) * 100),
@@ -262,8 +262,8 @@ TEST(WebColorAnimationCurveTest, DefaultTimingFunction) {
curve->AddKeyframe(CompositorColorKeyframe(1, SkColorSetRGB(0, 100, 0),
*LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.cc
index 1f11e4d81a5..c1cdc068631 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.cc
@@ -13,12 +13,12 @@ CompositorColorKeyframe::CompositorColorKeyframe(
SkColor value,
const TimingFunction& timing_function)
: color_keyframe_(
- cc::ColorKeyframe::Create(base::TimeDelta::FromSecondsD(time),
- value,
- timing_function.CloneToCC())) {}
+ gfx::ColorKeyframe::Create(base::TimeDelta::FromSecondsD(time),
+ value,
+ timing_function.CloneToCC())) {}
CompositorColorKeyframe::CompositorColorKeyframe(
- std::unique_ptr<cc::ColorKeyframe> color_keyframe)
+ std::unique_ptr<gfx::ColorKeyframe> color_keyframe)
: color_keyframe_(std::move(color_keyframe)) {}
CompositorColorKeyframe::~CompositorColorKeyframe() = default;
@@ -27,11 +27,11 @@ double CompositorColorKeyframe::Time() const {
return color_keyframe_->Time().InSecondsF();
}
-const cc::TimingFunction* CompositorColorKeyframe::CcTimingFunction() const {
+const gfx::TimingFunction* CompositorColorKeyframe::CcTimingFunction() const {
return color_keyframe_->timing_function();
}
-std::unique_ptr<cc::ColorKeyframe> CompositorColorKeyframe::CloneToCC() const {
+std::unique_ptr<gfx::ColorKeyframe> CompositorColorKeyframe::CloneToCC() const {
return color_keyframe_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.h b/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.h
index beb4fc1ac49..1ef2092846e 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_color_keyframe.h
@@ -6,9 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_COLOR_KEYFRAME_H_
#include "base/macros.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
namespace blink {
@@ -17,18 +17,18 @@ class TimingFunction;
class PLATFORM_EXPORT CompositorColorKeyframe : public CompositorKeyframe {
public:
CompositorColorKeyframe(double time, SkColor value, const TimingFunction&);
- CompositorColorKeyframe(std::unique_ptr<cc::ColorKeyframe>);
+ CompositorColorKeyframe(std::unique_ptr<gfx::ColorKeyframe>);
~CompositorColorKeyframe() override;
// CompositorKeyframe implementation.
double Time() const override;
- const cc::TimingFunction* CcTimingFunction() const override;
+ const gfx::TimingFunction* CcTimingFunction() const override;
SkColor Value() { return color_keyframe_->Value(); }
- std::unique_ptr<cc::ColorKeyframe> CloneToCC() const;
+ std::unique_ptr<gfx::ColorKeyframe> CloneToCC() const;
private:
- std::unique_ptr<cc::ColorKeyframe> color_keyframe_;
+ std::unique_ptr<gfx::ColorKeyframe> color_keyframe_;
DISALLOW_COPY_AND_ASSIGN(CompositorColorKeyframe);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.cc
index eefee742789..a48f220ebc7 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.cc
@@ -4,10 +4,10 @@
#include "third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/timing_function.h"
#include "cc/paint/filter_operations.h"
#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace blink {
@@ -30,7 +30,7 @@ void CompositorFilterAnimationCurve::SetScaledDuration(double scaled_duration) {
curve_->set_scaled_duration(scaled_duration);
}
-std::unique_ptr<cc::AnimationCurve>
+std::unique_ptr<gfx::AnimationCurve>
CompositorFilterAnimationCurve::CloneToAnimationCurve() const {
return curve_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
index 7ed4a5cae1f..a6f6221526e 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_animation_curve.h
@@ -36,7 +36,7 @@ class PLATFORM_EXPORT CompositorFilterAnimationCurve
void SetScaledDuration(double);
// blink::CompositorAnimationCurve implementation.
- std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
+ std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve() const override;
private:
std::unique_ptr<cc::KeyframedFilterAnimationCurve> curve_;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.cc
index 2a7eb269082..981df396262 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.cc
@@ -24,7 +24,7 @@ double CompositorFilterKeyframe::Time() const {
return filter_keyframe_->Time().InSecondsF();
}
-const cc::TimingFunction* CompositorFilterKeyframe::CcTimingFunction() const {
+const gfx::TimingFunction* CompositorFilterKeyframe::CcTimingFunction() const {
return filter_keyframe_->timing_function();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
index a1597aef0d5..08ed28a1623 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_filter_keyframe.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FILTER_KEYFRAME_H_
#include "base/macros.h"
-#include "cc/animation/keyframed_animation_curve.h"
+#include "cc/animation/filter_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -26,7 +26,7 @@ class PLATFORM_EXPORT CompositorFilterKeyframe : public CompositorKeyframe {
// CompositorKeyframe implementation.
double Time() const override;
- const cc::TimingFunction* CcTimingFunction() const override;
+ const gfx::TimingFunction* CcTimingFunction() const override;
private:
std::unique_ptr<cc::FilterKeyframe> filter_keyframe_;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.cc
index 1e405f45c57..0948971069e 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.cc
@@ -8,24 +8,24 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "cc/animation/animation_curve.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/timing_function.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace blink {
CompositorFloatAnimationCurve::CompositorFloatAnimationCurve()
- : curve_(cc::KeyframedFloatAnimationCurve::Create()) {}
+ : curve_(gfx::KeyframedFloatAnimationCurve::Create()) {}
CompositorFloatAnimationCurve::CompositorFloatAnimationCurve(
- std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve)
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve> curve)
: curve_(std::move(curve)) {}
CompositorFloatAnimationCurve::~CompositorFloatAnimationCurve() = default;
std::unique_ptr<CompositorFloatAnimationCurve>
CompositorFloatAnimationCurve::CreateForTesting(
- std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve) {
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve> curve) {
return base::WrapUnique(new CompositorFloatAnimationCurve(std::move(curve)));
}
@@ -63,7 +63,7 @@ float CompositorFloatAnimationCurve::GetValue(double time) const {
return curve_->GetValue(base::TimeDelta::FromSecondsD(time));
}
-std::unique_ptr<cc::AnimationCurve>
+std::unique_ptr<gfx::AnimationCurve>
CompositorFloatAnimationCurve::CloneToAnimationCurve() const {
return curve_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
index 56d801266d4..6a1b6303905 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h
@@ -16,7 +16,7 @@
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
-namespace cc {
+namespace gfx {
class KeyframedFloatAnimationCurve;
}
@@ -39,10 +39,10 @@ class PLATFORM_EXPORT CompositorFloatAnimationCurve
float GetValue(double time) const;
// CompositorAnimationCurve implementation.
- std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
+ std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve() const override;
static std::unique_ptr<CompositorFloatAnimationCurve> CreateForTesting(
- std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve>);
using Keyframes = Vector<std::unique_ptr<CompositorFloatKeyframe>>;
Keyframes KeyframesForTesting() const;
@@ -51,9 +51,9 @@ class PLATFORM_EXPORT CompositorFloatAnimationCurve
private:
CompositorFloatAnimationCurve(
- std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve>);
- std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve_;
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve> curve_;
DISALLOW_COPY_AND_ASSIGN(CompositorFloatAnimationCurve);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve_test.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve_test.cc
index a5f679b5d9b..92d6f11c85a 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve_test.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_float_animation_curve_test.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "cc/animation/timing_function.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
using blink::CompositorAnimationCurve;
using blink::CompositorFloatAnimationCurve;
@@ -131,8 +131,8 @@ TEST(WebFloatAnimationCurveTest, EaseTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -164,8 +164,8 @@ TEST(WebFloatAnimationCurveTest, EaseInTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_IN));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -183,8 +183,8 @@ TEST(WebFloatAnimationCurveTest, EaseOutTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_OUT));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -202,8 +202,8 @@ TEST(WebFloatAnimationCurveTest, EaseInOutTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_IN_OUT));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
@@ -224,8 +224,8 @@ TEST(WebFloatAnimationCurveTest, CustomBezierTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2));
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::Create(x1, y1, x2, y2));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
EXPECT_NEAR(timing_function->GetValue(time), curve->GetValue(time), 1e-7);
@@ -242,8 +242,8 @@ TEST(WebFloatAnimationCurveTest, DefaultTimingFunction) {
curve->AddKeyframe(
CompositorFloatKeyframe(1, 1, *LinearTimingFunction::Shared()));
- std::unique_ptr<cc::TimingFunction> timing_function(
- cc::CubicBezierTimingFunction::CreatePreset(
+ std::unique_ptr<gfx::TimingFunction> timing_function(
+ gfx::CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE));
for (int i = 0; i <= 4; ++i) {
const double time = i * 0.25;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.cc
index 1dabab2d42b..195e6da117a 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.cc
@@ -13,12 +13,12 @@ CompositorFloatKeyframe::CompositorFloatKeyframe(
float value,
const TimingFunction& timing_function)
: float_keyframe_(
- cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(time),
- value,
- timing_function.CloneToCC())) {}
+ gfx::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(time),
+ value,
+ timing_function.CloneToCC())) {}
CompositorFloatKeyframe::CompositorFloatKeyframe(
- std::unique_ptr<cc::FloatKeyframe> float_keyframe)
+ std::unique_ptr<gfx::FloatKeyframe> float_keyframe)
: float_keyframe_(std::move(float_keyframe)) {}
CompositorFloatKeyframe::~CompositorFloatKeyframe() = default;
@@ -27,11 +27,11 @@ double CompositorFloatKeyframe::Time() const {
return float_keyframe_->Time().InSecondsF();
}
-const cc::TimingFunction* CompositorFloatKeyframe::CcTimingFunction() const {
+const gfx::TimingFunction* CompositorFloatKeyframe::CcTimingFunction() const {
return float_keyframe_->timing_function();
}
-std::unique_ptr<cc::FloatKeyframe> CompositorFloatKeyframe::CloneToCC() const {
+std::unique_ptr<gfx::FloatKeyframe> CompositorFloatKeyframe::CloneToCC() const {
return float_keyframe_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h b/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
index 2d38e0367f8..766ab5d7256 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_float_keyframe.h
@@ -6,9 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_FLOAT_KEYFRAME_H_
#include "base/macros.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
namespace blink {
@@ -17,18 +17,18 @@ class TimingFunction;
class PLATFORM_EXPORT CompositorFloatKeyframe : public CompositorKeyframe {
public:
CompositorFloatKeyframe(double time, float value, const TimingFunction&);
- CompositorFloatKeyframe(std::unique_ptr<cc::FloatKeyframe>);
+ CompositorFloatKeyframe(std::unique_ptr<gfx::FloatKeyframe>);
~CompositorFloatKeyframe() override;
// CompositorKeyframe implementation.
double Time() const override;
- const cc::TimingFunction* CcTimingFunction() const override;
+ const gfx::TimingFunction* CcTimingFunction() const override;
float Value() { return float_keyframe_->Value(); }
- std::unique_ptr<cc::FloatKeyframe> CloneToCC() const;
+ std::unique_ptr<gfx::FloatKeyframe> CloneToCC() const;
private:
- std::unique_ptr<cc::FloatKeyframe> float_keyframe_;
+ std::unique_ptr<gfx::FloatKeyframe> float_keyframe_;
DISALLOW_COPY_AND_ASSIGN(CompositorFloatKeyframe);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe.h b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe.h
index 559a0f4218b..5a4d21e10f3 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe.h
@@ -8,7 +8,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/platform_export.h"
-namespace cc {
+namespace gfx {
class TimingFunction;
}
@@ -25,7 +25,7 @@ class PLATFORM_EXPORT CompositorKeyframe {
scoped_refptr<TimingFunction> GetTimingFunctionForTesting() const;
private:
- virtual const cc::TimingFunction* CcTimingFunction() const = 0;
+ virtual const gfx::TimingFunction* CcTimingFunction() const = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
index 8aeb308e331..2e2db63723c 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
@@ -6,12 +6,12 @@
#include <memory>
#include "base/memory/ptr_util.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_id_provider.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
using cc::KeyframeModel;
using cc::AnimationIdProvider;
@@ -25,16 +25,42 @@ CompositorKeyframeModel::CompositorKeyframeModel(
const CompositorAnimationCurve& curve,
compositor_target_property::Type target_property,
int keyframe_model_id,
+ int group_id)
+ : CompositorKeyframeModel(
+ curve,
+ keyframe_model_id,
+ group_id,
+ KeyframeModel::TargetPropertyId(target_property)) {}
+
+CompositorKeyframeModel::CompositorKeyframeModel(
+ const CompositorAnimationCurve& curve,
+ compositor_target_property::Type target_property,
+ int keyframe_model_id,
int group_id,
- const AtomicString& custom_property_name) {
- if (!keyframe_model_id)
- keyframe_model_id = AnimationIdProvider::NextKeyframeModelId();
- if (!group_id)
- group_id = AnimationIdProvider::NextGroupId();
+ const AtomicString& custom_property_name)
+ : CompositorKeyframeModel(
+ curve,
+ keyframe_model_id,
+ group_id,
+ KeyframeModel::TargetPropertyId(target_property,
+ custom_property_name.Utf8().data())) {
+ DCHECK(!custom_property_name.IsEmpty());
+}
- keyframe_model_ = KeyframeModel::Create(
- curve.CloneToAnimationCurve(), keyframe_model_id, group_id,
- target_property, custom_property_name.Utf8().data());
+CompositorKeyframeModel::CompositorKeyframeModel(
+ const CompositorAnimationCurve& curve,
+ compositor_target_property::Type target_property,
+ int keyframe_model_id,
+ int group_id,
+ CompositorPaintWorkletInput::NativePropertyType native_property_type)
+ : CompositorKeyframeModel(
+ curve,
+ keyframe_model_id,
+ group_id,
+ KeyframeModel::TargetPropertyId(target_property,
+ native_property_type)) {
+ DCHECK_NE(native_property_type,
+ CompositorPaintWorkletInput::NativePropertyType::kInvalid);
}
CompositorKeyframeModel::~CompositorKeyframeModel() = default;
@@ -47,10 +73,23 @@ int CompositorKeyframeModel::Group() const {
return keyframe_model_->group();
}
+CompositorKeyframeModel::CompositorKeyframeModel(
+ const CompositorAnimationCurve& curve,
+ int keyframe_model_id,
+ int group_id,
+ const KeyframeModel::TargetPropertyId& id) {
+ if (!keyframe_model_id)
+ keyframe_model_id = AnimationIdProvider::NextKeyframeModelId();
+ if (!group_id)
+ group_id = AnimationIdProvider::NextGroupId();
+ keyframe_model_ = KeyframeModel::Create(curve.CloneToAnimationCurve(),
+ keyframe_model_id, group_id, id);
+}
+
compositor_target_property::Type CompositorKeyframeModel::TargetProperty()
const {
return static_cast<compositor_target_property::Type>(
- keyframe_model_->target_property_id());
+ keyframe_model_->TargetProperty());
}
void CompositorKeyframeModel::SetElementId(CompositorElementId element_id) {
@@ -128,22 +167,24 @@ CompositorKeyframeModel::ReleaseCcKeyframeModel() {
std::unique_ptr<CompositorFloatAnimationCurve>
CompositorKeyframeModel::FloatCurveForTesting() const {
- const cc::AnimationCurve* curve = keyframe_model_->curve();
- DCHECK_EQ(cc::AnimationCurve::FLOAT, curve->Type());
+ const gfx::AnimationCurve* curve = keyframe_model_->curve();
+ DCHECK_EQ(gfx::AnimationCurve::FLOAT, curve->Type());
- auto keyframed_curve = base::WrapUnique(
- static_cast<cc::KeyframedFloatAnimationCurve*>(curve->Clone().release()));
+ auto keyframed_curve =
+ base::WrapUnique(static_cast<gfx::KeyframedFloatAnimationCurve*>(
+ curve->Clone().release()));
return CompositorFloatAnimationCurve::CreateForTesting(
std::move(keyframed_curve));
}
std::unique_ptr<CompositorColorAnimationCurve>
CompositorKeyframeModel::ColorCurveForTesting() const {
- const cc::AnimationCurve* curve = keyframe_model_->curve();
- DCHECK_EQ(cc::AnimationCurve::COLOR, curve->Type());
+ const gfx::AnimationCurve* curve = keyframe_model_->curve();
+ DCHECK_EQ(gfx::AnimationCurve::COLOR, curve->Type());
- auto keyframed_curve = base::WrapUnique(
- static_cast<cc::KeyframedColorAnimationCurve*>(curve->Clone().release()));
+ auto keyframed_curve =
+ base::WrapUnique(static_cast<gfx::KeyframedColorAnimationCurve*>(
+ curve->Clone().release()));
return CompositorColorAnimationCurve::CreateForTesting(
std::move(keyframed_curve));
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
index 7144083160b..41249640af9 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
@@ -12,6 +12,7 @@
#include "cc/animation/keyframe_model.h"
#include "third_party/blink/renderer/platform/animation/compositor_target_property.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+#include "third_party/blink/renderer/platform/graphics/platform_paint_worklet_layer_painter.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
@@ -34,14 +35,22 @@ class PLATFORM_EXPORT CompositorKeyframeModel {
using Direction = cc::KeyframeModel::Direction;
using FillMode = cc::KeyframeModel::FillMode;
- // The |custom_property_name| has a default value of an empty string,
- // indicating that the animated property is a native property. When it is an
- // animated custom property, it should be the property name.
+ CompositorKeyframeModel(const CompositorAnimationCurve&,
+ compositor_target_property::Type,
+ int keyframe_model_id,
+ int group_id);
+ // The |custom_property_name| is the name of animated custom property.
CompositorKeyframeModel(const CompositorAnimationCurve&,
compositor_target_property::Type,
int keyframe_model_id,
int group_id,
- const AtomicString& custom_property_name = "");
+ const AtomicString& custom_property_name);
+ CompositorKeyframeModel(
+ const CompositorAnimationCurve&,
+ compositor_target_property::Type,
+ int keyframe_model_id,
+ int group_id,
+ CompositorPaintWorkletInput::NativePropertyType native_property_type);
~CompositorKeyframeModel();
// An id must be unique.
@@ -87,6 +96,11 @@ class PLATFORM_EXPORT CompositorKeyframeModel {
}
private:
+ CompositorKeyframeModel(const CompositorAnimationCurve& curve,
+ int keyframe_model_id,
+ int group_id,
+ const cc::KeyframeModel::TargetPropertyId& id);
+
std::unique_ptr<cc::KeyframeModel> keyframe_model_;
DISALLOW_COPY_AND_ASSIGN(CompositorKeyframeModel);
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
index 0740006764e..7fd03316069 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
@@ -7,7 +7,7 @@
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
-#include "cc/animation/timing_function.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
using blink::CompositorScrollOffsetAnimationCurve;
@@ -58,7 +58,7 @@ void CompositorScrollOffsetAnimationCurve::UpdateTarget(base::TimeDelta time,
curve_->UpdateTarget(time, gfx::ScrollOffset(new_target.X(), new_target.Y()));
}
-std::unique_ptr<cc::AnimationCurve>
+std::unique_ptr<gfx::AnimationCurve>
CompositorScrollOffsetAnimationCurve::CloneToAnimationCurve() const {
return curve_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
index 87ba98a8908..90e936523b8 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
@@ -39,7 +39,7 @@ class PLATFORM_EXPORT CompositorScrollOffsetAnimationCurve
void UpdateTarget(base::TimeDelta time, FloatPoint new_target);
// CompositorAnimationCurve implementation.
- std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
+ std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve() const override;
private:
std::unique_ptr<cc::ScrollOffsetAnimationCurve> curve_;
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
index a3932b79da8..decab8e1851 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.cc
@@ -4,15 +4,15 @@
#include "third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
#include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
+#include "ui/gfx/transform_operations.h"
namespace blink {
CompositorTransformAnimationCurve::CompositorTransformAnimationCurve()
- : curve_(cc::KeyframedTransformAnimationCurve::Create()) {}
+ : curve_(gfx::KeyframedTransformAnimationCurve::Create()) {}
CompositorTransformAnimationCurve::~CompositorTransformAnimationCurve() =
default;
@@ -32,7 +32,7 @@ void CompositorTransformAnimationCurve::SetScaledDuration(
curve_->set_scaled_duration(scaled_duration);
}
-std::unique_ptr<cc::AnimationCurve>
+std::unique_ptr<gfx::AnimationCurve>
CompositorTransformAnimationCurve::CloneToAnimationCurve() const {
return curve_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
index b6f872ce297..0b0fe6e0ceb 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h
@@ -36,10 +36,10 @@ class PLATFORM_EXPORT CompositorTransformAnimationCurve
void SetScaledDuration(double);
// CompositorAnimationCurve implementation.
- std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
+ std::unique_ptr<gfx::AnimationCurve> CloneToAnimationCurve() const override;
private:
- std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve_;
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve_;
DISALLOW_COPY_AND_ASSIGN(CompositorTransformAnimationCurve);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
index 1c13d89a779..e266dc0f8ba 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.cc
@@ -13,9 +13,9 @@ CompositorTransformKeyframe::CompositorTransformKeyframe(
CompositorTransformOperations value,
const TimingFunction& timing_function)
: transform_keyframe_(
- cc::TransformKeyframe::Create(base::TimeDelta::FromSecondsD(time),
- value.ReleaseCcTransformOperations(),
- timing_function.CloneToCC())) {}
+ gfx::TransformKeyframe::Create(base::TimeDelta::FromSecondsD(time),
+ value.ReleaseGfxTransformOperations(),
+ timing_function.CloneToCC())) {}
CompositorTransformKeyframe::~CompositorTransformKeyframe() = default;
@@ -23,12 +23,12 @@ double CompositorTransformKeyframe::Time() const {
return transform_keyframe_->Time().InSecondsF();
}
-const cc::TimingFunction* CompositorTransformKeyframe::CcTimingFunction()
+const gfx::TimingFunction* CompositorTransformKeyframe::CcTimingFunction()
const {
return transform_keyframe_->timing_function();
}
-std::unique_ptr<cc::TransformKeyframe> CompositorTransformKeyframe::CloneToCC()
+std::unique_ptr<gfx::TransformKeyframe> CompositorTransformKeyframe::CloneToCC()
const {
return transform_keyframe_->Clone();
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
index 48fc1888404..47b85ca323c 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h
@@ -6,11 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_KEYFRAME_H_
#include "base/macros.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "third_party/blink/renderer/platform/animation/compositor_keyframe.h"
#include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
#include "third_party/blink/renderer/platform/animation/timing_function.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
namespace blink {
@@ -21,14 +21,14 @@ class PLATFORM_EXPORT CompositorTransformKeyframe : public CompositorKeyframe {
const TimingFunction&);
~CompositorTransformKeyframe() override;
- std::unique_ptr<cc::TransformKeyframe> CloneToCC() const;
+ std::unique_ptr<gfx::TransformKeyframe> CloneToCC() const;
// CompositorKeyframe implementation.
double Time() const override;
- const cc::TimingFunction* CcTimingFunction() const override;
+ const gfx::TimingFunction* CcTimingFunction() const override;
private:
- std::unique_ptr<cc::TransformKeyframe> transform_keyframe_;
+ std::unique_ptr<gfx::TransformKeyframe> transform_keyframe_;
DISALLOW_COPY_AND_ASSIGN(CompositorTransformKeyframe);
};
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
index fdbf638a318..b5f4dcab315 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.cc
@@ -4,19 +4,19 @@
#include "third_party/blink/renderer/platform/animation/compositor_transform_operations.h"
-#include "cc/animation/transform_operation.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
namespace blink {
-const cc::TransformOperations&
-CompositorTransformOperations::AsCcTransformOperations() const {
+const gfx::TransformOperations&
+CompositorTransformOperations::AsGfxTransformOperations() const {
return transform_operations_;
}
-cc::TransformOperations
-CompositorTransformOperations::ReleaseCcTransformOperations() {
+gfx::TransformOperations
+CompositorTransformOperations::ReleaseGfxTransformOperations() {
return std::move(transform_operations_);
}
diff --git a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.h b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
index 5c6daa4503f..3cc95a12c40 100644
--- a/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
+++ b/chromium/third_party/blink/renderer/platform/animation/compositor_transform_operations.h
@@ -5,9 +5,9 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_OPERATIONS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_ANIMATION_COMPOSITOR_TRANSFORM_OPERATIONS_H_
-#include "cc/animation/transform_operations.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/gfx/transform_operations.h"
class SkMatrix44;
@@ -17,8 +17,8 @@ class PLATFORM_EXPORT CompositorTransformOperations {
STACK_ALLOCATED();
public:
- const cc::TransformOperations& AsCcTransformOperations() const;
- cc::TransformOperations ReleaseCcTransformOperations();
+ const gfx::TransformOperations& AsGfxTransformOperations() const;
+ gfx::TransformOperations ReleaseGfxTransformOperations();
// Returns true if these operations can be blended. It will only return
// false if we must resort to matrix interpolation, and matrix interpolation
@@ -37,7 +37,7 @@ class PLATFORM_EXPORT CompositorTransformOperations {
bool IsIdentity() const;
private:
- cc::TransformOperations transform_operations_;
+ gfx::TransformOperations transform_operations_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/animation/timing_function.cc b/chromium/third_party/blink/renderer/platform/animation/timing_function.cc
index 9922baf0d94..7dcaa58b8af 100644
--- a/chromium/third_party/blink/renderer/platform/animation/timing_function.cc
+++ b/chromium/third_party/blink/renderer/platform/animation/timing_function.cc
@@ -19,7 +19,7 @@ double LinearTimingFunction::Evaluate(double fraction) const {
void LinearTimingFunction::Range(double* min_value, double* max_value) const {}
-std::unique_ptr<cc::TimingFunction> LinearTimingFunction::CloneToCC() const {
+std::unique_ptr<gfx::TimingFunction> LinearTimingFunction::CloneToCC() const {
return nullptr;
}
@@ -95,7 +95,7 @@ void CubicBezierTimingFunction::Range(double* min_value,
*max_value = std::max(std::max(*max_value, solution1), solution2);
}
-std::unique_ptr<cc::TimingFunction> CubicBezierTimingFunction::CloneToCC()
+std::unique_ptr<gfx::TimingFunction> CubicBezierTimingFunction::CloneToCC()
const {
return bezier_->Clone();
}
@@ -154,21 +154,21 @@ double StepsTimingFunction::Evaluate(double fraction) const {
return steps_->GetPreciseValue(fraction, LimitDirection::RIGHT);
}
-std::unique_ptr<cc::TimingFunction> StepsTimingFunction::CloneToCC() const {
+std::unique_ptr<gfx::TimingFunction> StepsTimingFunction::CloneToCC() const {
return steps_->Clone();
}
scoped_refptr<TimingFunction> CreateCompositorTimingFunctionFromCC(
- const cc::TimingFunction* timing_function) {
+ const gfx::TimingFunction* timing_function) {
if (!timing_function)
return LinearTimingFunction::Shared();
switch (timing_function->GetType()) {
- case cc::TimingFunction::Type::CUBIC_BEZIER: {
+ case gfx::TimingFunction::Type::CUBIC_BEZIER: {
auto* cubic_timing_function =
- static_cast<const cc::CubicBezierTimingFunction*>(timing_function);
+ static_cast<const gfx::CubicBezierTimingFunction*>(timing_function);
if (cubic_timing_function->ease_type() !=
- cc::CubicBezierTimingFunction::EaseType::CUSTOM)
+ gfx::CubicBezierTimingFunction::EaseType::CUSTOM)
return CubicBezierTimingFunction::Preset(
cubic_timing_function->ease_type());
@@ -177,9 +177,9 @@ scoped_refptr<TimingFunction> CreateCompositorTimingFunctionFromCC(
bezier.GetX2(), bezier.GetY2());
}
- case cc::TimingFunction::Type::STEPS: {
+ case gfx::TimingFunction::Type::STEPS: {
auto* steps_timing_function =
- static_cast<const cc::StepsTimingFunction*>(timing_function);
+ static_cast<const gfx::StepsTimingFunction*>(timing_function);
return StepsTimingFunction::Create(
steps_timing_function->steps(),
steps_timing_function->step_position());
diff --git a/chromium/third_party/blink/renderer/platform/animation/timing_function.h b/chromium/third_party/blink/renderer/platform/animation/timing_function.h
index bbefc14c106..a7ac1a04103 100644
--- a/chromium/third_party/blink/renderer/platform/animation/timing_function.h
+++ b/chromium/third_party/blink/renderer/platform/animation/timing_function.h
@@ -27,7 +27,6 @@
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
-#include "cc/animation/timing_function.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -35,14 +34,15 @@
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace blink {
class PLATFORM_EXPORT TimingFunction
: public ThreadSafeRefCounted<TimingFunction> {
public:
- using Type = cc::TimingFunction::Type;
- using LimitDirection = cc::TimingFunction::LimitDirection;
+ using Type = gfx::TimingFunction::Type;
+ using LimitDirection = gfx::TimingFunction::LimitDirection;
virtual ~TimingFunction() = default;
@@ -66,7 +66,7 @@ class PLATFORM_EXPORT TimingFunction
virtual void Range(double* min_value, double* max_value) const = 0;
// Create CC instance.
- virtual std::unique_ptr<cc::TimingFunction> CloneToCC() const = 0;
+ virtual std::unique_ptr<gfx::TimingFunction> CloneToCC() const = 0;
protected:
TimingFunction(Type type) : type_(type) {}
@@ -89,7 +89,7 @@ class PLATFORM_EXPORT LinearTimingFunction final : public TimingFunction {
String ToString() const override;
double Evaluate(double fraction) const override;
void Range(double* min_value, double* max_value) const override;
- std::unique_ptr<cc::TimingFunction> CloneToCC() const override;
+ std::unique_ptr<gfx::TimingFunction> CloneToCC() const override;
private:
LinearTimingFunction() : TimingFunction(Type::LINEAR) {}
@@ -97,7 +97,7 @@ class PLATFORM_EXPORT LinearTimingFunction final : public TimingFunction {
class PLATFORM_EXPORT CubicBezierTimingFunction final : public TimingFunction {
public:
- using EaseType = cc::CubicBezierTimingFunction::EaseType;
+ using EaseType = gfx::CubicBezierTimingFunction::EaseType;
static scoped_refptr<CubicBezierTimingFunction> Create(double x1,
double y1,
@@ -114,7 +114,7 @@ class PLATFORM_EXPORT CubicBezierTimingFunction final : public TimingFunction {
String ToString() const override;
double Evaluate(double fraction) const override;
void Range(double* min_value, double* max_value) const override;
- std::unique_ptr<cc::TimingFunction> CloneToCC() const override;
+ std::unique_ptr<gfx::TimingFunction> CloneToCC() const override;
double X1() const {
DCHECK_EQ(GetEaseType(), EaseType::CUSTOM);
@@ -137,7 +137,7 @@ class PLATFORM_EXPORT CubicBezierTimingFunction final : public TimingFunction {
private:
explicit CubicBezierTimingFunction(EaseType ease_type)
: TimingFunction(Type::CUBIC_BEZIER),
- bezier_(cc::CubicBezierTimingFunction::CreatePreset(ease_type)),
+ bezier_(gfx::CubicBezierTimingFunction::CreatePreset(ease_type)),
x1_(),
y1_(),
x2_(),
@@ -145,13 +145,13 @@ class PLATFORM_EXPORT CubicBezierTimingFunction final : public TimingFunction {
CubicBezierTimingFunction(double x1, double y1, double x2, double y2)
: TimingFunction(Type::CUBIC_BEZIER),
- bezier_(cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)),
+ bezier_(gfx::CubicBezierTimingFunction::Create(x1, y1, x2, y2)),
x1_(x1),
y1_(y1),
x2_(x2),
y2_(y2) {}
- std::unique_ptr<cc::CubicBezierTimingFunction> bezier_;
+ std::unique_ptr<gfx::CubicBezierTimingFunction> bezier_;
// TODO(loyso): Get these values from m_bezier->bezier_ (gfx::CubicBezier)
const double x1_;
@@ -162,7 +162,7 @@ class PLATFORM_EXPORT CubicBezierTimingFunction final : public TimingFunction {
class PLATFORM_EXPORT StepsTimingFunction final : public TimingFunction {
public:
- using StepPosition = cc::StepsTimingFunction::StepPosition;
+ using StepPosition = gfx::StepsTimingFunction::StepPosition;
static scoped_refptr<StepsTimingFunction> Create(int steps,
StepPosition step_position) {
@@ -193,7 +193,7 @@ class PLATFORM_EXPORT StepsTimingFunction final : public TimingFunction {
double Evaluate(double fraction) const override;
void Range(double* min_value, double* max_value) const override;
- std::unique_ptr<cc::TimingFunction> CloneToCC() const override;
+ std::unique_ptr<gfx::TimingFunction> CloneToCC() const override;
int NumberOfSteps() const { return steps_->steps(); }
StepPosition GetStepPosition() const { return steps_->step_position(); }
@@ -201,13 +201,13 @@ class PLATFORM_EXPORT StepsTimingFunction final : public TimingFunction {
private:
StepsTimingFunction(int steps, StepPosition step_position)
: TimingFunction(Type::STEPS),
- steps_(cc::StepsTimingFunction::Create(steps, step_position)) {}
+ steps_(gfx::StepsTimingFunction::Create(steps, step_position)) {}
- std::unique_ptr<cc::StepsTimingFunction> steps_;
+ std::unique_ptr<gfx::StepsTimingFunction> steps_;
};
PLATFORM_EXPORT scoped_refptr<TimingFunction>
-CreateCompositorTimingFunctionFromCC(const cc::TimingFunction*);
+CreateCompositorTimingFunctionFromCC(const gfx::TimingFunction*);
PLATFORM_EXPORT bool operator==(const LinearTimingFunction&,
const TimingFunction&);
diff --git a/chromium/third_party/blink/renderer/platform/audio/DIR_METADATA b/chromium/third_party/blink/renderer/platform/audio/DIR_METADATA
new file mode 100644
index 00000000000..cd6016a497e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/audio/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebAudio"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/audio/OWNERS b/chromium/third_party/blink/renderer/platform/audio/OWNERS
index bcc0e71a548..a837fc9b778 100644
--- a/chromium/third_party/blink/renderer/platform/audio/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/audio/OWNERS
@@ -1,4 +1,2 @@
hongchan@chromium.org
rtoy@chromium.org
-
-# COMPONENT: Blink>WebAudio
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc b/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
index e2162d04478..c55185aebc7 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_bus.cc
@@ -34,6 +34,7 @@
#include <memory>
#include <utility>
+#include "base/ranges/algorithm.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_audio_bus.h"
#include "third_party/blink/renderer/platform/audio/audio_file_reader.h"
@@ -65,10 +66,11 @@ AudioBus::AudioBus(unsigned number_of_channels, uint32_t length, bool allocate)
channels_.ReserveInitialCapacity(number_of_channels);
for (unsigned i = 0; i < number_of_channels; ++i) {
- std::unique_ptr<AudioChannel> channel =
- allocate ? std::make_unique<AudioChannel>(length)
- : std::make_unique<AudioChannel>(nullptr, length);
- channels_.push_back(std::move(channel));
+ if (allocate) {
+ channels_.emplace_back(length);
+ } else {
+ channels_.emplace_back(nullptr, length);
+ }
}
layout_ = kLayoutCanonical; // for now this is the only layout we define
@@ -89,13 +91,13 @@ void AudioBus::ResizeSmaller(uint32_t new_length) {
if (new_length <= length_)
length_ = new_length;
- for (unsigned i = 0; i < channels_.size(); ++i)
- channels_[i]->ResizeSmaller(new_length);
+ for (AudioChannel& channel : channels_)
+ channel.ResizeSmaller(new_length);
}
void AudioBus::Zero() {
- for (unsigned i = 0; i < channels_.size(); ++i)
- channels_[i]->Zero();
+ for (AudioChannel& channel : channels_)
+ channel.Zero();
}
AudioChannel* AudioBus::ChannelByType(unsigned channel_type) {
@@ -670,16 +672,12 @@ scoped_refptr<AudioBus> AudioBus::CreateByMixingToMono(
}
bool AudioBus::IsSilent() const {
- for (size_t i = 0; i < channels_.size(); ++i) {
- if (!channels_[i]->IsSilent())
- return false;
- }
- return true;
+ return base::ranges::all_of(channels_, &AudioChannel::IsSilent);
}
void AudioBus::ClearSilentFlag() {
- for (size_t i = 0; i < channels_.size(); ++i)
- channels_[i]->ClearSilentFlag();
+ for (AudioChannel& channel : channels_)
+ channel.ClearSilentFlag();
}
scoped_refptr<AudioBus> DecodeAudioFileData(const char* data, size_t size) {
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_bus.h b/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
index d541a390e8b..3b5aa70db24 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_bus.h
@@ -80,9 +80,9 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
// Channels
unsigned NumberOfChannels() const { return channels_.size(); }
- AudioChannel* Channel(unsigned channel) { return channels_[channel].get(); }
+ AudioChannel* Channel(unsigned channel) { return &channels_[channel]; }
const AudioChannel* Channel(unsigned channel) const {
- return channels_[channel].get();
+ return &channels_[channel];
}
AudioChannel* ChannelByType(unsigned type);
const AudioChannel* ChannelByType(unsigned type) const;
@@ -165,9 +165,7 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
static scoped_refptr<AudioBus> GetDataResource(int resource_id,
float sample_rate);
- protected:
- AudioBus() = default;
-
+ private:
AudioBus(unsigned number_of_channels, uint32_t length, bool allocate);
void DiscreteSumFrom(const AudioBus&);
@@ -178,11 +176,10 @@ class PLATFORM_EXPORT AudioBus : public ThreadSafeRefCounted<AudioBus> {
void SumFromByDownMixing(const AudioBus&);
uint32_t length_;
- Vector<std::unique_ptr<AudioChannel>> channels_;
+ Vector<AudioChannel, 2> channels_;
int layout_;
float sample_rate_; // 0.0 if unknown or N/A
- private:
DISALLOW_COPY_AND_ASSIGN(AudioBus);
};
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_channel.h b/chromium/third_party/blink/renderer/platform/audio/audio_channel.h
index 5adffb5ecf6..a7dbe7e2ef3 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_channel.h
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_channel.h
@@ -34,7 +34,6 @@
#include "base/numerics/checked_math.h"
#include "third_party/blink/renderer/platform/audio/audio_array.h"
#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
@@ -42,8 +41,6 @@ namespace blink {
// samples.
// The PCM samples are normally assumed to be in a nominal range -1.0 -> +1.0
class PLATFORM_EXPORT AudioChannel {
- USING_FAST_MALLOC(AudioChannel);
-
public:
// Memory can be externally referenced, or can be internally allocated with an
// AudioFloatArray.
@@ -130,8 +127,6 @@ class PLATFORM_EXPORT AudioChannel {
float* raw_pointer_;
std::unique_ptr<AudioFloatArray> mem_buffer_;
bool silent_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioChannel);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/audio/audio_utilities.cc b/chromium/third_party/blink/renderer/platform/audio/audio_utilities.cc
index 7fc4153631d..d95cba1dfec 100644
--- a/chromium/third_party/blink/renderer/platform/audio/audio_utilities.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/audio_utilities.cc
@@ -27,19 +27,20 @@
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
namespace audio_utilities {
float DecibelsToLinear(float decibels) {
- return powf(10, 0.05f * decibels);
+ return fdlibm::powf(10, 0.05f * decibels);
}
float LinearToDecibels(float linear) {
DCHECK_GE(linear, 0);
- return 20 * log10f(linear);
+ return 20 * fdlibm::log10f(linear);
}
double DiscreteTimeConstantForSampleRate(double time_constant,
@@ -64,7 +65,7 @@ double DiscreteTimeConstantForSampleRate(double time_constant,
// discrete time constant is
//
// 1 - exp(-1/(Fs*tau)
- return 1 - exp(-1 / (sample_rate * time_constant));
+ return 1 - fdlibm::exp(-1 / (sample_rate * time_constant));
}
size_t TimeToSampleFrame(double time,
diff --git a/chromium/third_party/blink/renderer/platform/audio/biquad.cc b/chromium/third_party/blink/renderer/platform/audio/biquad.cc
index 9dee0b5dc43..a644d4b1880 100644
--- a/chromium/third_party/blink/renderer/platform/audio/biquad.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/biquad.cc
@@ -32,10 +32,11 @@
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
#include "third_party/blink/renderer/platform/audio/denormal_disabler.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
+#include <stdio.h>
#include <algorithm>
#include <complex>
-#include <stdio.h>
#if defined(OS_MAC)
#include <Accelerate/Accelerate.h>
#endif
@@ -48,7 +49,7 @@ const int kBiquadBufferSize = 1024;
// Compute 10^x = exp(x*log(10))
static double pow10(double x) {
- return expf(x * 2.30258509299404568402);
+ return fdlibm::expf(x * 2.30258509299404568402);
}
Biquad::Biquad() : has_sample_accurate_values_(false) {
@@ -277,8 +278,8 @@ void Biquad::SetLowpassParams(int index, double cutoff, double resonance) {
resonance = pow10(resonance / 20);
double theta = kPiDouble * cutoff;
- double alpha = sin(theta) / (2 * resonance);
- double cosw = cos(theta);
+ double alpha = fdlibm::sin(theta) / (2 * resonance);
+ double cosw = fdlibm::cos(theta);
double beta = (1 - cosw) / 2;
double b0 = beta;
@@ -309,8 +310,8 @@ void Biquad::SetHighpassParams(int index, double cutoff, double resonance) {
resonance = pow10(resonance / 20);
double theta = kPiDouble * cutoff;
- double alpha = sin(theta) / (2 * resonance);
- double cosw = cos(theta);
+ double alpha = fdlibm::sin(theta) / (2 * resonance);
+ double cosw = fdlibm::cos(theta);
double beta = (1 + cosw) / 2;
double b0 = beta;
@@ -359,8 +360,8 @@ void Biquad::SetLowShelfParams(int index, double frequency, double db_gain) {
} else if (frequency > 0) {
double w0 = kPiDouble * frequency;
double s = 1; // filter slope (1 is max value)
- double alpha = 0.5 * sin(w0) * sqrt((a + 1 / a) * (1 / s - 1) + 2);
- double k = cos(w0);
+ double alpha = 0.5 * fdlibm::sin(w0) * sqrt((a + 1 / a) * (1 / s - 1) + 2);
+ double k = fdlibm::cos(w0);
double k2 = 2 * sqrt(a) * alpha;
double a_plus_one = a + 1;
double a_minus_one = a - 1;
@@ -391,8 +392,8 @@ void Biquad::SetHighShelfParams(int index, double frequency, double db_gain) {
} else if (frequency > 0) {
double w0 = kPiDouble * frequency;
double s = 1; // filter slope (1 is max value)
- double alpha = 0.5 * sin(w0) * sqrt((a + 1 / a) * (1 / s - 1) + 2);
- double k = cos(w0);
+ double alpha = 0.5 * fdlibm::sin(w0) * sqrt((a + 1 / a) * (1 / s - 1) + 2);
+ double k = fdlibm::cos(w0);
double k2 = 2 * sqrt(a) * alpha;
double a_plus_one = a + 1;
double a_minus_one = a - 1;
@@ -426,8 +427,8 @@ void Biquad::SetPeakingParams(int index,
if (frequency > 0 && frequency < 1) {
if (q > 0) {
double w0 = kPiDouble * frequency;
- double alpha = sin(w0) / (2 * q);
- double k = cos(w0);
+ double alpha = fdlibm::sin(w0) / (2 * q);
+ double k = fdlibm::cos(w0);
double b0 = 1 + alpha * a;
double b1 = -2 * k;
@@ -459,8 +460,8 @@ void Biquad::SetAllpassParams(int index, double frequency, double q) {
if (frequency > 0 && frequency < 1) {
if (q > 0) {
double w0 = kPiDouble * frequency;
- double alpha = sin(w0) / (2 * q);
- double k = cos(w0);
+ double alpha = fdlibm::sin(w0) / (2 * q);
+ double k = fdlibm::cos(w0);
double b0 = 1 - alpha;
double b1 = -2 * k;
@@ -492,8 +493,8 @@ void Biquad::SetNotchParams(int index, double frequency, double q) {
if (frequency > 0 && frequency < 1) {
if (q > 0) {
double w0 = kPiDouble * frequency;
- double alpha = sin(w0) / (2 * q);
- double k = cos(w0);
+ double alpha = fdlibm::sin(w0) / (2 * q);
+ double k = fdlibm::cos(w0);
double b0 = 1;
double b1 = -2 * k;
@@ -525,8 +526,8 @@ void Biquad::SetBandpassParams(int index, double frequency, double q) {
if (frequency > 0 && frequency < 1) {
double w0 = kPiDouble * frequency;
if (q > 0) {
- double alpha = sin(w0) / (2 * q);
- double k = cos(w0);
+ double alpha = fdlibm::sin(w0) / (2 * q);
+ double k = fdlibm::cos(w0);
double b0 = alpha;
double b1 = 0;
@@ -586,14 +587,15 @@ void Biquad::GetFrequencyResponse(int n_frequencies,
phase_response[k] = std::nanf("");
} else {
double omega = -kPiDouble * frequency[k];
- std::complex<double> z = std::complex<double>(cos(omega), sin(omega));
+ std::complex<double> z =
+ std::complex<double>(fdlibm::cos(omega), fdlibm::sin(omega));
std::complex<double> numerator = b0 + (b1 + b2 * z) * z;
std::complex<double> denominator =
std::complex<double>(1, 0) + (a1 + a2 * z) * z;
std::complex<double> response = numerator / denominator;
mag_response[k] = static_cast<float>(abs(response));
phase_response[k] =
- static_cast<float>(atan2(imag(response), real(response)));
+ static_cast<float>(fdlibm::atan2(imag(response), real(response)));
}
}
}
@@ -612,7 +614,8 @@ static double RepeatedRootResponse(double n,
// This helps with finding a nuemrical solution because this
// approximately linearizes the response for large n.
- return (n - 2) * log(r) + log(fabs(c1 * (n + 1) * r * r + c2)) - log_eps;
+ return (n - 2) * fdlibm::log(r) +
+ fdlibm::log(fabs(c1 * (n + 1) * r * r + c2)) - log_eps;
}
// Regula Falsi root finder, Illinois variant
@@ -817,8 +820,10 @@ double Biquad::TailFrame(int coef_index, double max_frame) {
// It's possible for kMaxTailAmplitude to be greater than c1 + c2.
// This may produce a negative tail frame. Just clamp the tail
// frame to 0.
- tail_frame = clampTo(
- 1 + log(kMaxTailAmplitude / (fabs(c1) + fabs(c2))) / log(fabs(r1)), 0);
+ tail_frame =
+ clampTo(1 + fdlibm::log(kMaxTailAmplitude / (fabs(c1) + fabs(c2))) /
+ fdlibm::log(fabs(r1)),
+ 0);
DCHECK(std::isfinite(tail_frame));
} else if (discrim < 0) {
@@ -842,7 +847,8 @@ double Biquad::TailFrame(int coef_index, double max_frame) {
DCHECK(std::isfinite(c1));
DCHECK(std::isfinite(c2));
- tail_frame = 1 + log(kMaxTailAmplitude / (c1 + c2)) / log(r);
+ tail_frame =
+ 1 + fdlibm::log(kMaxTailAmplitude / (c1 + c2)) / fdlibm::log(r);
if (c1 == 0 && c2 == 0) {
// If c1 = c2 = 0, then H(z) = b0. Hence, there's no tail
// because this is just a wire from input to output.
@@ -864,6 +870,12 @@ double Biquad::TailFrame(int coef_index, double max_frame) {
// Double pole at 0. This just delays the signal by 2 frames,
// so set the tail frame to 2.
tail_frame = 2;
+ } else if (std::abs(r) >= 1) {
+ // Double pole at 1 or -1 (or outside the unit circle in general). In any
+ // case, the impulse response grows without bound since the pole is on or
+ // outside the unit circle. Return infinity and let the caller clamp it
+ // to something more reasonable.
+ tail_frame = std::numeric_limits<double>::infinity();
} else {
double c1 = (b0 * r * r + b1 * r + b2) / (r * r);
double c2 = b1 * r + 2 * b2;
@@ -883,14 +895,15 @@ double Biquad::TailFrame(int coef_index, double max_frame) {
// -(1+log(r))/log(r). so we can start our search from that
// point to max_frames.
- double low = clampTo(-(1 + log(r)) / log(r), 1.0,
+ double low = clampTo(-(1 + fdlibm::log(r)) / fdlibm::log(r), 1.0,
static_cast<double>(max_frame - 1));
double high = max_frame;
DCHECK(std::isfinite(low));
DCHECK(std::isfinite(high));
- tail_frame = RootFinder(low, high, log(kMaxTailAmplitude), c1, c2, r);
+ tail_frame =
+ RootFinder(low, high, fdlibm::log(kMaxTailAmplitude), c1, c2, r);
}
}
}
diff --git a/chromium/third_party/blink/renderer/platform/audio/distance_effect.cc b/chromium/third_party/blink/renderer/platform/audio/distance_effect.cc
index 83f3c130905..3fd3ff481b8 100644
--- a/chromium/third_party/blink/renderer/platform/audio/distance_effect.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/distance_effect.cc
@@ -33,6 +33,7 @@
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -88,7 +89,7 @@ double DistanceEffect::ExponentialGain(double distance) {
// Clamp distance according to spec
distance = clampTo(distance, ref_distance_);
- return pow(distance / ref_distance_, -clampTo(rolloff_factor_, 0.0));
+ return fdlibm::pow(distance / ref_distance_, -clampTo(rolloff_factor_, 0.0));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/audio/down_sampler.cc b/chromium/third_party/blink/renderer/platform/audio/down_sampler.cc
index d0fddec485b..f1089317319 100644
--- a/chromium/third_party/blink/renderer/platform/audio/down_sampler.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/down_sampler.cc
@@ -33,6 +33,7 @@
#include <memory>
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -61,13 +62,13 @@ std::unique_ptr<AudioFloatArray> MakeReducedKernel(size_t size) {
for (int i = 1; i < n; i += 2) {
// Compute the sinc() with offset.
double s = sinc_scale_factor * kPiDouble * (i - half_size);
- double sinc = !s ? 1.0 : sin(s) / s;
+ double sinc = !s ? 1.0 : fdlibm::sin(s) / s;
sinc *= sinc_scale_factor;
// Compute Blackman window, matching the offset of the sinc().
double x = static_cast<double>(i) / n;
- double window =
- a0 - a1 * cos(kTwoPiDouble * x) + a2 * cos(kTwoPiDouble * 2.0 * x);
+ double window = a0 - a1 * fdlibm::cos(kTwoPiDouble * x) +
+ a2 * fdlibm::cos(kTwoPiDouble * 2.0 * x);
// Window the sinc() function.
// Then store only the odd terms in the kernel.
diff --git a/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc b/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
index 83b1e63a6c8..dac66e7c9d7 100644
--- a/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
#include "third_party/blink/renderer/platform/audio/denormal_disabler.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -97,16 +98,17 @@ void DynamicsCompressorKernel::SetPreDelayTime(float pre_delay_time) {
// Exponential curve for the knee.
// It is 1st derivative matched at m_linearThreshold and asymptotically
// approaches the value m_linearThreshold + 1 / k.
-float DynamicsCompressorKernel::KneeCurve(float x, float k) {
+float DynamicsCompressorKernel::KneeCurve(float x, float k) const {
// Linear up to threshold.
if (x < linear_threshold_)
return x;
- return linear_threshold_ + (1 - expf(-k * (x - linear_threshold_))) / k;
+ return linear_threshold_ +
+ (1 - fdlibm::expf(-k * (x - linear_threshold_))) / k;
}
// Full compression curve with constant ratio after knee.
-float DynamicsCompressorKernel::Saturate(float x, float k) {
+float DynamicsCompressorKernel::Saturate(float x, float k) const {
float y;
if (x < knee_threshold_)
@@ -125,7 +127,7 @@ float DynamicsCompressorKernel::Saturate(float x, float k) {
// Approximate 1st derivative with input and output expressed in dB.
// This slope is equal to the inverse of the compression "ratio".
// In other words, a compression ratio of 20 would be a slope of 1/20.
-float DynamicsCompressorKernel::SlopeAt(float x, float k) {
+float DynamicsCompressorKernel::SlopeAt(float x, float k) const {
if (x < linear_threshold_)
return 1;
@@ -142,7 +144,7 @@ float DynamicsCompressorKernel::SlopeAt(float x, float k) {
return m;
}
-float DynamicsCompressorKernel::KAtSlope(float desired_slope) {
+float DynamicsCompressorKernel::KAtSlope(float desired_slope) const {
float x_db = db_threshold_ + db_knee_;
float x = audio_utilities::DecibelsToLinear(x_db);
@@ -230,7 +232,7 @@ void DynamicsCompressorKernel::Process(
float full_range_makeup_gain = 1 / full_range_gain;
// Empirical/perceptual tuning.
- full_range_makeup_gain = powf(full_range_makeup_gain, 0.6f);
+ full_range_makeup_gain = fdlibm::powf(full_range_makeup_gain, 0.6f);
float linear_post_gain =
audio_utilities::DecibelsToLinear(db_post_gain) * full_range_makeup_gain;
@@ -297,7 +299,7 @@ void DynamicsCompressorKernel::Process(
float desired_gain = detector_average_;
// Pre-warp so we get desiredGain after sin() warp below.
- float scaled_desired_gain = asinf(desired_gain) / kPiOverTwoFloat;
+ float scaled_desired_gain = fdlibm::asinf(desired_gain) / kPiOverTwoFloat;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Deal with envelopes
@@ -373,7 +375,7 @@ void DynamicsCompressorKernel::Process(
float eff_atten_diff_db = std::max(0.5f, max_attack_compression_diff_db_);
float x = 0.25f / eff_atten_diff_db;
- envelope_rate = 1 - powf(x, 1 / attack_frames);
+ envelope_rate = 1 - fdlibm::powf(x, 1 / attack_frames);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -451,14 +453,14 @@ void DynamicsCompressorKernel::Process(
// Warp pre-compression gain to smooth out sharp exponential transition
// points.
float post_warp_compressor_gain =
- sinf(kPiOverTwoFloat * compressor_gain);
+ fdlibm::sinf(kPiOverTwoFloat * compressor_gain);
// Calculate total gain using the linear post-gain and effect blend.
float total_gain =
dry_mix + wet_mix * linear_post_gain * post_warp_compressor_gain;
// Calculate metering.
- float db_real_gain = 20 * std::log10(post_warp_compressor_gain);
+ float db_real_gain = 20 * fdlibm::log10(post_warp_compressor_gain);
if (db_real_gain < metering_gain_)
metering_gain_ = db_real_gain;
else
diff --git a/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h b/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
index 3d7292052fc..db2d86511c8 100644
--- a/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
+++ b/chromium/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.h
@@ -102,10 +102,10 @@ class PLATFORM_EXPORT DynamicsCompressorKernel {
float max_attack_compression_diff_db_;
// Static compression curve.
- float KneeCurve(float x, float k);
- float Saturate(float x, float k);
- float SlopeAt(float x, float k);
- float KAtSlope(float desired_slope);
+ float KneeCurve(float x, float k) const;
+ float Saturate(float x, float k) const;
+ float SlopeAt(float x, float k) const;
+ float KAtSlope(float desired_slope) const;
float UpdateStaticCurveParameters(float db_threshold,
float db_knee,
diff --git a/chromium/third_party/blink/renderer/platform/audio/equal_power_panner.cc b/chromium/third_party/blink/renderer/platform/audio/equal_power_panner.cc
index 22fb5b2af72..44d882fa36d 100644
--- a/chromium/third_party/blink/renderer/platform/audio/equal_power_panner.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/equal_power_panner.cc
@@ -30,11 +30,11 @@
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
-EqualPowerPanner::EqualPowerPanner(float sample_rate)
- : Panner(PanningModel::kEqualPower) {}
+EqualPowerPanner::EqualPowerPanner(float sample_rate) {}
void EqualPowerPanner::Pan(double azimuth,
double /*elevation*/,
@@ -96,8 +96,8 @@ void EqualPowerPanner::Pan(double azimuth,
}
}
- desired_gain_l = std::cos(kPiOverTwoDouble * desired_pan_position);
- desired_gain_r = std::sin(kPiOverTwoDouble * desired_pan_position);
+ desired_gain_l = fdlibm::cos(kPiOverTwoDouble * desired_pan_position);
+ desired_gain_r = fdlibm::sin(kPiOverTwoDouble * desired_pan_position);
int n = frames_to_process;
@@ -165,8 +165,8 @@ void EqualPowerPanner::CalculateDesiredGain(double& desired_gain_l,
}
}
- desired_gain_l = std::cos(kPiOverTwoDouble * desired_pan_position);
- desired_gain_r = std::sin(kPiOverTwoDouble * desired_pan_position);
+ desired_gain_l = fdlibm::cos(kPiOverTwoDouble * desired_pan_position);
+ desired_gain_r = fdlibm::sin(kPiOverTwoDouble * desired_pan_position);
}
void EqualPowerPanner::PanWithSampleAccurateValues(
diff --git a/chromium/third_party/blink/renderer/platform/audio/fft_frame.cc b/chromium/third_party/blink/renderer/platform/audio/fft_frame.cc
index b10f84b06c2..b53cdefbe0f 100644
--- a/chromium/third_party/blink/renderer/platform/audio/fft_frame.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/fft_frame.cc
@@ -32,6 +32,7 @@
#include <memory>
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
#ifndef NDEBUG
#include <stdio.h>
@@ -125,8 +126,8 @@ void FFTFrame::InterpolateFrequencyComponents(const FFTFrame& frame1,
double mag2 = abs(c2);
// Interpolate magnitudes in decibels
- double mag1db = 20.0 * log10(mag1);
- double mag2db = 20.0 * log10(mag2);
+ double mag1db = 20.0 * fdlibm::log10(mag1);
+ double mag2db = 20.0 * fdlibm::log10(mag2);
double s1 = s1base;
double s2 = s2base;
@@ -137,16 +138,16 @@ void FFTFrame::InterpolateFrequencyComponents(const FFTFrame& frame1,
double threshold = (i > 16) ? 5.0 : 2.0;
if (magdbdiff < -threshold && mag1db < 0.0) {
- s1 = pow(s1, 0.75);
+ s1 = fdlibm::pow(s1, 0.75);
s2 = 1.0 - s1;
} else if (magdbdiff > threshold && mag2db < 0.0) {
- s2 = pow(s2, 0.75);
+ s2 = fdlibm::pow(s2, 0.75);
s1 = 1.0 - s2;
}
// Average magnitude by decibels instead of linearly
double magdb = s1 * mag1db + s2 * mag2db;
- double mag = pow(10.0, 0.05 * magdb);
+ double mag = fdlibm::pow(10.0, 0.05 * magdb);
// Now, deal with phase
double phase1 = arg(c1);
diff --git a/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.cc b/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.cc
index c78343dabeb..ac96ceafe54 100644
--- a/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.cc
@@ -97,18 +97,6 @@ HRTFKernel::HRTFKernel(AudioChannel* channel,
fft_frame_->DoPaddedFFT(impulse_response, truncated_response_length);
}
-std::unique_ptr<AudioChannel> HRTFKernel::CreateImpulseResponse() {
- std::unique_ptr<AudioChannel> channel =
- std::make_unique<AudioChannel>(FftSize());
- FFTFrame fft_frame(*fft_frame_);
-
- // Add leading delay back in.
- fft_frame.AddConstantGroupDelay(frame_delay_);
- fft_frame.DoInverseFFT(channel->MutableData());
-
- return channel;
-}
-
// Interpolates two kernels with x: 0 -> 1 and returns the result.
std::unique_ptr<HRTFKernel> HRTFKernel::CreateInterpolatedKernel(
HRTFKernel* kernel1,
diff --git a/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.h b/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.h
index 001a477b525..d1859ad4887 100644
--- a/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.h
+++ b/chromium/third_party/blink/renderer/platform/audio/hrtf_kernel.h
@@ -78,9 +78,6 @@ class PLATFORM_EXPORT HRTFKernel {
float SampleRate() const { return sample_rate_; }
double Nyquist() const { return 0.5 * SampleRate(); }
- // Converts back into impulse-response form.
- std::unique_ptr<AudioChannel> CreateImpulseResponse();
-
private:
std::unique_ptr<FFTFrame> fft_frame_;
float frame_delay_;
diff --git a/chromium/third_party/blink/renderer/platform/audio/hrtf_panner.cc b/chromium/third_party/blink/renderer/platform/audio/hrtf_panner.cc
index cc12303b7f6..07ffc7e3885 100644
--- a/chromium/third_party/blink/renderer/platform/audio/hrtf_panner.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/hrtf_panner.cc
@@ -42,8 +42,7 @@ const double kMaxDelayTimeSeconds = 0.002;
const int kUninitializedAzimuth = -1;
HRTFPanner::HRTFPanner(float sample_rate, HRTFDatabaseLoader* database_loader)
- : Panner(PanningModel::kHRTF),
- database_loader_(database_loader),
+ : database_loader_(database_loader),
sample_rate_(sample_rate),
crossfade_selection_(kCrossfadeSelection1),
azimuth_index1_(kUninitializedAzimuth),
diff --git a/chromium/third_party/blink/renderer/platform/audio/iir_filter.cc b/chromium/third_party/blink/renderer/platform/audio/iir_filter.cc
index 94370fea82c..e5a5aaf3537 100644
--- a/chromium/third_party/blink/renderer/platform/audio/iir_filter.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/iir_filter.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -137,7 +138,7 @@ void IIRFilter::GetFrequencyResponse(int n_frequencies,
// zRecip = 1/z = exp(-j*frequency)
double omega = -kPiDouble * frequency[k];
std::complex<double> z_recip =
- std::complex<double>(cos(omega), sin(omega));
+ std::complex<double>(fdlibm::cos(omega), fdlibm::sin(omega));
std::complex<double> numerator = EvaluatePolynomial(
feedforward_->Data(), z_recip, feedforward_->size() - 1);
@@ -146,7 +147,7 @@ void IIRFilter::GetFrequencyResponse(int n_frequencies,
std::complex<double> response = numerator / denominator;
mag_response[k] = static_cast<float>(abs(response));
phase_response[k] =
- static_cast<float>(atan2(imag(response), real(response)));
+ static_cast<float>(fdlibm::atan2(imag(response), real(response)));
}
}
}
diff --git a/chromium/third_party/blink/renderer/platform/audio/panner.h b/chromium/third_party/blink/renderer/platform/audio/panner.h
index b2bed74ccb7..a72bd994dda 100644
--- a/chromium/third_party/blink/renderer/platform/audio/panner.h
+++ b/chromium/third_party/blink/renderer/platform/audio/panner.h
@@ -80,9 +80,7 @@ class PLATFORM_EXPORT Panner {
virtual bool RequiresTailProcessing() const = 0;
protected:
- explicit Panner(PanningModel model) : panning_model_(model) {}
-
- PanningModel panning_model_;
+ Panner() = default;
private:
DISALLOW_COPY_AND_ASSIGN(Panner);
diff --git a/chromium/third_party/blink/renderer/platform/audio/push_pull_fifo.cc b/chromium/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
index 0971cf3d1e3..754aaf47480 100644
--- a/chromium/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
@@ -55,8 +55,8 @@ PushPullFIFO::~PushPullFIFO() {
// Push the data from |input_bus| to FIFO. The size of push is determined by
// the length of |input_bus|.
void PushPullFIFO::Push(const AudioBus* input_bus) {
- TRACE_EVENT1("webaudio", "PushPullFIFO::Push",
- "input_bus length", input_bus->length());
+ TRACE_EVENT2("webaudio", "PushPullFIFO::Push", "this",
+ static_cast<void*>(this), "frames", input_bus->length());
MutexLocker locker(lock_);
TRACE_EVENT0("webaudio", "PushPullFIFO::Push under lock");
@@ -110,9 +110,8 @@ void PushPullFIFO::Push(const AudioBus* input_bus) {
// Pull the data out of FIFO to |output_bus|. If remaining frame in the FIFO
// is less than the frames to pull, provides remaining frame plus the silence.
size_t PushPullFIFO::Pull(AudioBus* output_bus, size_t frames_requested) {
- TRACE_EVENT2("webaudio", "PushPullFIFO::Pull",
- "output_bus length", output_bus->length(),
- "frames_requested", frames_requested);
+ TRACE_EVENT2("webaudio", "PushPullFIFO::Pull", "this",
+ static_cast<void*>(this), "frames", frames_requested);
MutexLocker locker(lock_);
TRACE_EVENT0("webaudio", "PushPullFIFO::Pull under lock");
diff --git a/chromium/third_party/blink/renderer/platform/audio/reverb.cc b/chromium/third_party/blink/renderer/platform/audio/reverb.cc
index e7eca7d2093..703fdf863b5 100644
--- a/chromium/third_party/blink/renderer/platform/audio/reverb.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/reverb.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -72,7 +73,7 @@ static float CalculateNormalizationScale(AudioBus* response) {
float scale = 1 / power;
- scale *= powf(
+ scale *= fdlibm::powf(
10, kGainCalibration *
0.05f); // calibrate to make perceived volume same as unprocessed
diff --git a/chromium/third_party/blink/renderer/platform/audio/sinc_resampler.cc b/chromium/third_party/blink/renderer/platform/audio/sinc_resampler.cc
index 5f10d969432..924db3f2927 100644
--- a/chromium/third_party/blink/renderer/platform/audio/sinc_resampler.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/sinc_resampler.cc
@@ -31,6 +31,7 @@
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
#if defined(ARCH_CPU_X86_FAMILY)
#include <emmintrin.h>
@@ -118,13 +119,13 @@ void SincResampler::InitializeKernel() {
// Compute the sinc() with offset.
double s =
sinc_scale_factor * kPiDouble * (i - half_size - subsample_offset);
- double sinc = !s ? 1.0 : std::sin(s) / s;
+ double sinc = !s ? 1.0 : fdlibm::sin(s) / s;
sinc *= sinc_scale_factor;
// Compute Blackman window, matching the offset of the sinc().
double x = (i - subsample_offset) / n;
- double window = a0 - a1 * std::cos(kTwoPiDouble * x) +
- a2 * std::cos(kTwoPiDouble * 2.0 * x);
+ double window = a0 - a1 * fdlibm::cos(kTwoPiDouble * x) +
+ a2 * fdlibm::cos(kTwoPiDouble * 2.0 * x);
// Window the sinc() function and store at the correct offset.
kernel_storage_[i + offset_index * kernel_size_] = sinc * window;
diff --git a/chromium/third_party/blink/renderer/platform/audio/stereo_panner.cc b/chromium/third_party/blink/renderer/platform/audio/stereo_panner.cc
index 2ff13bec392..4d9a9da6d01 100644
--- a/chromium/third_party/blink/renderer/platform/audio/stereo_panner.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/stereo_panner.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -55,8 +56,8 @@ void StereoPanner::PanWithSampleAccurateValues(const AudioBus* input_bus,
double pan = clampTo(*pan_values++, -1.0, 1.0);
// Pan from left to right [-1; 1] will be normalized as [0; 1].
pan_radian = (pan * 0.5 + 0.5) * kPiOverTwoDouble;
- gain_l = std::cos(pan_radian);
- gain_r = std::sin(pan_radian);
+ gain_l = fdlibm::cos(pan_radian);
+ gain_r = fdlibm::sin(pan_radian);
*destination_l++ = static_cast<float>(input_l * gain_l);
*destination_r++ = static_cast<float>(input_l * gain_r);
}
@@ -67,8 +68,8 @@ void StereoPanner::PanWithSampleAccurateValues(const AudioBus* input_bus,
double pan = clampTo(*pan_values++, -1.0, 1.0);
// Normalize [-1; 0] to [0; 1]. Do nothing when [0; 1].
pan_radian = (pan <= 0 ? pan + 1 : pan) * kPiOverTwoDouble;
- gain_l = std::cos(pan_radian);
- gain_r = std::sin(pan_radian);
+ gain_l = fdlibm::cos(pan_radian);
+ gain_r = fdlibm::sin(pan_radian);
if (pan <= 0) {
*destination_l++ = static_cast<float>(input_l + input_r * gain_l);
*destination_r++ = static_cast<float>(input_r * gain_r);
@@ -114,8 +115,8 @@ void StereoPanner::PanToTargetValue(const AudioBus* input_bus,
// Pan from left to right [-1; 1] will be normalized as [0; 1].
double pan_radian = (target_pan * 0.5 + 0.5) * kPiOverTwoDouble;
- double gain_l = std::cos(pan_radian);
- double gain_r = std::sin(pan_radian);
+ double gain_l = fdlibm::cos(pan_radian);
+ double gain_r = fdlibm::sin(pan_radian);
// TODO(rtoy): This can be vectorized using vector_math::Vsmul
while (n--) {
@@ -129,8 +130,8 @@ void StereoPanner::PanToTargetValue(const AudioBus* input_bus,
double pan_radian =
(target_pan <= 0 ? target_pan + 1 : target_pan) * kPiOverTwoDouble;
- double gain_l = std::cos(pan_radian);
- double gain_r = std::sin(pan_radian);
+ double gain_l = fdlibm::cos(pan_radian);
+ double gain_r = fdlibm::sin(pan_radian);
// TODO(rtoy): Consider moving the if statement outside the loop
// since |target_pan| is constant inside the loop.
diff --git a/chromium/third_party/blink/renderer/platform/audio/up_sampler.cc b/chromium/third_party/blink/renderer/platform/audio/up_sampler.cc
index fb70a44e352..df78152fbc2 100644
--- a/chromium/third_party/blink/renderer/platform/audio/up_sampler.cc
+++ b/chromium/third_party/blink/renderer/platform/audio/up_sampler.cc
@@ -33,6 +33,7 @@
#include <memory>
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/fdlibm/ieee754.h"
namespace blink {
@@ -58,12 +59,12 @@ std::unique_ptr<AudioFloatArray> MakeKernel(size_t size) {
for (int i = 0; i < n; ++i) {
// Compute the sinc() with offset.
double s = kPiDouble * (i - half_size - subsample_offset);
- double sinc = !s ? 1.0 : sin(s) / s;
+ double sinc = !s ? 1.0 : fdlibm::sin(s) / s;
// Compute Blackman window, matching the offset of the sinc().
double x = (i - subsample_offset) / n;
- double window =
- a0 - a1 * cos(kTwoPiDouble * x) + a2 * cos(kTwoPiDouble * 2.0 * x);
+ double window = a0 - a1 * fdlibm::cos(kTwoPiDouble * x) +
+ a2 * fdlibm::cos(kTwoPiDouble * 2.0 * x);
// Window the sinc() function.
(*kernel)[i] = sinc * window;
diff --git a/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.cc b/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.cc
new file mode 100644
index 00000000000..c4ece9c7b0d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.cc
@@ -0,0 +1,38 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+bool IsInflightNetworkRequestBackForwardCacheSupportEnabled() {
+ // Note that the call to RuntimeEnabledFeatures::BackForwardCacheEnabled()
+ // must be done first to ensure we will never call
+ // base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable) when
+ // back-forward cache is not enabled. This is important because IsEnabled()
+ // might trigger activation of the current user in BackForwardCache's field
+ // trial group even though it shouldn't (e.g. when BackForwardCache is
+ // disabled due to low RAM), lowering the back-forward cache hit rate.
+ // TODO(rakina): Remove BackForwardCache from RuntimeEnabledFeatures and move
+ // features::kBackForwardCache and BackForwardCacheMemoryControls from
+ // content/ to blink/public, so that we can combine this check with the checks
+ // in content/.
+ return RuntimeEnabledFeatures::BackForwardCacheEnabled() &&
+ base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable);
+}
+
+int GetLoadingTasksUnfreezableParamAsInt(const std::string& param_name,
+ int default_value) {
+ if (!IsInflightNetworkRequestBackForwardCacheSupportEnabled())
+ return default_value;
+ return base::GetFieldTrialParamByFeatureAsInt(
+ blink::features::kLoadingTasksUnfreezable, param_name, default_value);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.h b/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.h
new file mode 100644
index 00000000000..fe0273ce51a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/back_forward_cache_utils.h
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BACK_FORWARD_CACHE_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BACK_FORWARD_CACHE_UTILS_H_
+
+#include <string>
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// Returns true iff back-forward cache and LoadingTasksUnfreezable are enabled.
+PLATFORM_EXPORT bool IsInflightNetworkRequestBackForwardCacheSupportEnabled();
+// Returns the param |param_name| of LoadingTasksUnfreezable as int, or
+// |default_value| if not set.
+PLATFORM_EXPORT int GetLoadingTasksUnfreezableParamAsInt(
+ const std::string& param_name,
+ int default_value);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BACK_FORWARD_CACHE_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/platform/bindings/DIR_METADATA b/chromium/third_party/blink/renderer/platform/bindings/DIR_METADATA
new file mode 100644
index 00000000000..148e0ebf048
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/bindings/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Bindings"
+}
+team_email: "blink-reviews-bindings@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/bindings/OWNERS b/chromium/third_party/blink/renderer/platform/bindings/OWNERS
index 750dcc6a414..74be775b547 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/bindings/OWNERS
@@ -1,5 +1,2 @@
# Bindings OWNERS
file://third_party/blink/renderer/bindings/OWNERS
-
-# TEAM: blink-reviews-bindings@chromium.org
-# COMPONENT: Blink>Bindings
diff --git a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h
index ed8bac6bbad..542b3d2cf47 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h
@@ -24,6 +24,14 @@ class PLATFORM_EXPORT ActiveScriptWrappableBase : public GarbageCollectedMixin {
virtual bool IsContextDestroyed() const = 0;
virtual bool DispatchHasPendingActivity() const = 0;
+ // See trait below.
+ //
+ // Registering the ActiveScriptWrappableBase after construction means that
+ // the garbage collector does not need to deal with objects that are
+ // currently under construction. This is important as checking whether ASW
+ // should be treated as active involves calling virtual functions which may
+ // not work during construction. The objects in construction are kept alive
+ // via conservative stack scanning.
void ActiveScriptWrappableBaseConstructed();
protected:
@@ -33,6 +41,31 @@ class PLATFORM_EXPORT ActiveScriptWrappableBase : public GarbageCollectedMixin {
DISALLOW_COPY_AND_ASSIGN(ActiveScriptWrappableBase);
};
+} // namespace blink
+
+#if BUILDFLAG(USE_V8_OILPAN)
+
+namespace cppgc {
+template <typename T, typename Unused>
+struct PostConstructionCallbackTrait;
+
+template <typename T>
+struct PostConstructionCallbackTrait<
+ T,
+ base::void_t<decltype(
+ std::declval<T>().ActiveScriptWrappableBaseConstructed())>> {
+ static void Call(T* object) {
+ static_assert(std::is_base_of<blink::ActiveScriptWrappableBase, T>::value,
+ "Only ActiveScriptWrappableBase should use the "
+ "post-construction hook.");
+ object->ActiveScriptWrappableBaseConstructed();
+ }
+};
+} // namespace cppgc
+
+#else // !USE_V8_OILPAN
+
+namespace blink {
template <typename T>
struct PostConstructionHookTrait<
T,
@@ -42,16 +75,12 @@ struct PostConstructionHookTrait<
static_assert(std::is_base_of<ActiveScriptWrappableBase, T>::value,
"Only ActiveScriptWrappableBase should use the "
"post-construction hook.");
- // Registering the ActiveScriptWrappableBase after construction means that
- // the garbage collector does not need to deal with objects that are
- // currently under construction. This is imnportant as checking whether ASW
- // should be treated as active involves calling virtual functions which may
- // not work during construction. The objects in construction are kept alive
- // via conservative stack scanning.
object->ActiveScriptWrappableBaseConstructed();
}
};
} // namespace blink
+#endif // !USE_V8_OILPAN
+
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_ACTIVE_SCRIPT_WRAPPABLE_BASE_H_
diff --git a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
index d9ed60fce38..2abc344ec1e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h
@@ -11,8 +11,6 @@
namespace blink {
-class LivenessBroker;
-
// ActiveScriptWrappableManager (ASWM) is integrated into the garbage collector
// and keeps ActiveScriptWrappable alive as long as they have
// HasPendingActivity() returning true and are attached to a live
diff --git a/chromium/third_party/blink/renderer/platform/bindings/dictionary_base.h b/chromium/third_party/blink/renderer/platform/bindings/dictionary_base.h
index 90422c62d7d..97bebe268ba 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/dictionary_base.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/dictionary_base.h
@@ -11,8 +11,6 @@
namespace blink {
-class Visitor;
-
namespace bindings {
// This class is the base class for all IDL dictionary implementations. This is
diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
index 674c1b60bf9..9b26a15281e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
@@ -122,8 +122,13 @@ DOMWrapperWorld::~DOMWrapperWorld() {
}
void DOMWrapperWorld::Dispose() {
- dom_data_store_->Dispose();
- dom_data_store_.Clear();
+ if (dom_data_store_) {
+ // The data_store_ might be cleared on thread termination in the same
+ // garbage collection cycle which prohibits accessing the references from
+ // the dtor.
+ dom_data_store_->Dispose();
+ dom_data_store_.Clear();
+ }
DCHECK(GetWorldMap().Contains(world_id_));
GetWorldMap().erase(world_id_);
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
index d9e7a702195..66c85f20594 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
@@ -35,7 +35,6 @@
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/web_isolated_world_ids.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -54,6 +53,15 @@ class DOMDataStore;
class ScriptWrappable;
class SecurityOrigin;
+enum IsolatedWorldId {
+ // Embedder isolated worlds can use IDs in [1, 1<<29).
+ kEmbedderWorldIdLimit = (1 << 29),
+ kDocumentXMLTreeViewerWorldId,
+ kDevToolsFirstIsolatedWorldId,
+ kDevToolsLastIsolatedWorldId = kDevToolsFirstIsolatedWorldId + (1 << 29),
+ kIsolatedWorldIdLimit,
+};
+
// This class represent a collection of DOM wrappers for a specific world. This
// is identified by a world id that is a per-thread global identifier (see
// WorldId enum).
diff --git a/chromium/third_party/blink/renderer/platform/bindings/exception_context.h b/chromium/third_party/blink/renderer/platform/bindings/exception_context.h
new file mode 100644
index 00000000000..c90845ff456
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/bindings/exception_context.h
@@ -0,0 +1,135 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_EXCEPTION_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_EXCEPTION_CONTEXT_H_
+
+#include "base/macros.h"
+#include "base/notreached.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+// ExceptionContext stores context information about what Web API throws an
+// exception.
+//
+// Note that ExceptionContext accepts only string literals as its string
+// parameters.
+class PLATFORM_EXPORT ExceptionContext final {
+ DISALLOW_NEW();
+
+ public:
+ enum class Context : int16_t {
+ kEmpty,
+ kUnknown, // TODO(crbug.com/270033): Remove this item.
+ // IDL Interface, IDL Namespace
+ kAttributeGet,
+ kAttributeSet,
+ kConstantGet,
+ kConstructorOperationInvoke,
+ kOperationInvoke,
+ kIndexedPropertyGet,
+ kIndexedPropertySet,
+ kIndexedPropertyDefine,
+ kIndexedPropertyDelete,
+ kIndexedPropertyQuery,
+ kIndexedPropertyEnumerate,
+ kNamedPropertyGet,
+ kNamedPropertySet,
+ kNamedPropertyDefine,
+ kNamedPropertyDelete,
+ kNamedPropertyQuery,
+ kNamedPropertyEnumerate,
+ // IDL Dictionary
+ kDictionaryMemberGet,
+ kDictionaryMemberSet,
+ // IDL Callback Function
+ kCallbackFunctionConstruct,
+ kCallbackFunctionInvoke,
+ // IDL Callback Interface
+ kCallbackInterfaceOperationInvoke,
+ // Operating on a function argument
+ kFunctionArgument,
+ };
+
+ ExceptionContext() = default;
+
+ // Note `class_name` and `property_name` accept only string literals.
+ explicit ExceptionContext(Context context,
+ const char* class_name,
+ const char* property_name)
+ : context_(context),
+ class_name_(class_name),
+ property_name_(property_name) {
+#if DCHECK_IS_ON()
+ switch (context) {
+ case Context::kAttributeGet:
+ case Context::kAttributeSet:
+ case Context::kConstantGet:
+ case Context::kOperationInvoke:
+ case Context::kDictionaryMemberGet:
+ case Context::kDictionaryMemberSet:
+ case Context::kCallbackInterfaceOperationInvoke:
+ DCHECK(class_name);
+ DCHECK(property_name);
+ break;
+ case Context::kConstructorOperationInvoke:
+ case Context::kIndexedPropertyGet:
+ case Context::kIndexedPropertySet:
+ case Context::kIndexedPropertyDefine:
+ case Context::kIndexedPropertyDelete:
+ case Context::kIndexedPropertyQuery:
+ case Context::kIndexedPropertyEnumerate:
+ case Context::kNamedPropertyGet:
+ case Context::kNamedPropertySet:
+ case Context::kNamedPropertyDefine:
+ case Context::kNamedPropertyDelete:
+ case Context::kNamedPropertyQuery:
+ case Context::kNamedPropertyEnumerate:
+ case Context::kCallbackFunctionConstruct:
+ case Context::kCallbackFunctionInvoke:
+ DCHECK(class_name);
+ break;
+ case Context::kEmpty:
+ case Context::kFunctionArgument:
+ NOTREACHED();
+ break;
+ case Context::kUnknown:
+ break;
+ }
+#endif // DCHECK_IS_ON()
+ }
+
+ explicit ExceptionContext(Context context, const char* class_name)
+ : ExceptionContext(context, class_name, nullptr) {}
+
+ explicit ExceptionContext(Context context, int16_t argument_index)
+ : context_(context), argument_index_(argument_index) {
+ DCHECK_EQ(Context::kFunctionArgument, context);
+ }
+
+ ExceptionContext(const ExceptionContext&) = default;
+ ExceptionContext(ExceptionContext&&) = default;
+ ExceptionContext& operator=(const ExceptionContext&) = default;
+ ExceptionContext& operator=(ExceptionContext&&) = default;
+
+ ~ExceptionContext() = default;
+
+ Context GetContext() const { return context_; }
+ const char* GetClassName() const { return class_name_; }
+ const char* GetPropertyName() const { return property_name_; }
+ int16_t GetArgumentIndex() const { return argument_index_; }
+
+ private:
+ Context context_ = Context::kEmpty;
+ int16_t argument_index_ = 0;
+ const char* class_name_ = nullptr;
+ const char* property_name_ = nullptr;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_EXCEPTION_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/platform/bindings/exception_messages.cc b/chromium/third_party/blink/renderer/platform/bindings/exception_messages.cc
index 69df3fdde6d..057f8b7d6e8 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/exception_messages.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/exception_messages.cc
@@ -202,6 +202,11 @@ String ExceptionMessages::ReadOnly(const char* detail) {
: read_only;
}
+String ExceptionMessages::ValueNotOfType(const char* expected_type) {
+ return String::Format("The provided value is not of type '%s'.",
+ expected_type);
+}
+
template <>
String ExceptionMessages::FormatNumber<float>(float number) {
return FormatPotentiallyNonFiniteNumber(number);
diff --git a/chromium/third_party/blink/renderer/platform/bindings/exception_messages.h b/chromium/third_party/blink/renderer/platform/bindings/exception_messages.h
index 40ae4e7188f..0d4f4bbb097 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/exception_messages.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/exception_messages.h
@@ -158,6 +158,8 @@ class PLATFORM_EXPORT ExceptionMessages {
static String ReadOnly(const char* detail = nullptr);
+ static String ValueNotOfType(const char* expected_type);
+
private:
template <typename NumType>
static String FormatFiniteNumber(NumType number) {
diff --git a/chromium/third_party/blink/renderer/platform/bindings/exception_state.cc b/chromium/third_party/blink/renderer/platform/bindings/exception_state.cc
index e6ce495a92f..82bbb5840c8 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/exception_state.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/exception_state.cc
@@ -181,80 +181,71 @@ void ExceptionState::SetException(ExceptionCode exception_code,
}
}
-String ExceptionState::AddExceptionContext(const String& message) const {
- if (message.IsEmpty())
- return message;
-
- const char* i = InterfaceName();
- const char* p = PropertyName();
- const auto& m = message;
-
- if (i && p) {
- switch (context_) {
- case kConstructionContext:
- return ExceptionMessages::FailedToConstruct(i, m);
- case kExecutionContext:
- return ExceptionMessages::FailedToExecute(p, i, m);
- case kDeletionContext:
- return ExceptionMessages::FailedToDelete(p, i, m);
- case kGetterContext:
- return ExceptionMessages::FailedToGet(p, i, m);
- case kSetterContext:
- return ExceptionMessages::FailedToSet(p, i, m);
- case kEnumerationContext:
- return ExceptionMessages::FailedToEnumerate(i, m);
- case kQueryContext:
- break;
- case kIndexedGetterContext:
- return ExceptionMessages::FailedToGetIndexed(i, m);
- case kIndexedSetterContext:
- return ExceptionMessages::FailedToSetIndexed(i, m);
- case kIndexedDeletionContext:
- return ExceptionMessages::FailedToDeleteIndexed(i, m);
- case kNamedGetterContext:
- return ExceptionMessages::FailedToGetNamed(i, m);
- case kNamedSetterContext:
- return ExceptionMessages::FailedToSetNamed(i, m);
- case kNamedDeletionContext:
- return ExceptionMessages::FailedToDeleteNamed(i, m);
- case kUnknownContext:
- break;
- }
- }
+void ExceptionState::PushContextScope(ContextScope* scope) {
+ scope->SetParent(context_stack_top_);
+ context_stack_top_ = scope;
+}
+
+void ExceptionState::PopContextScope() {
+ DCHECK(!context_stack_top_);
+ context_stack_top_ = context_stack_top_->GetParent();
+}
- if (i) {
- switch (context_) {
- case kConstructionContext:
- return ExceptionMessages::FailedToConstruct(i, m);
- case kExecutionContext:
- break;
- case kDeletionContext:
- break;
- case kGetterContext:
- break;
- case kSetterContext:
- break;
- case kEnumerationContext:
- return ExceptionMessages::FailedToEnumerate(i, m);
- case kQueryContext:
- break;
- case kIndexedGetterContext:
- return ExceptionMessages::FailedToGetIndexed(i, m);
- case kIndexedSetterContext:
- return ExceptionMessages::FailedToSetIndexed(i, m);
- case kIndexedDeletionContext:
- return ExceptionMessages::FailedToDeleteIndexed(i, m);
- case kNamedGetterContext:
- return ExceptionMessages::FailedToGetNamed(i, m);
- case kNamedSetterContext:
- return ExceptionMessages::FailedToSetNamed(i, m);
- case kNamedDeletionContext:
- return ExceptionMessages::FailedToDeleteNamed(i, m);
- case kUnknownContext:
- break;
- }
+namespace {
+
+String AddContextToMessage(const String& message,
+ const ExceptionContext& context) {
+ const char* c = context.GetClassName();
+ const char* p = context.GetPropertyName();
+ const String& m = message;
+
+ switch (context.GetContext()) {
+ case ExceptionState::kConstructionContext:
+ return ExceptionMessages::FailedToConstruct(c, m);
+ case ExceptionState::kExecutionContext:
+ return ExceptionMessages::FailedToExecute(p, c, m);
+ case ExceptionState::kGetterContext:
+ return ExceptionMessages::FailedToGet(p, c, m);
+ case ExceptionState::kSetterContext:
+ return ExceptionMessages::FailedToSet(p, c, m);
+ case ExceptionState::kEnumerationContext:
+ return ExceptionMessages::FailedToEnumerate(c, m);
+ case ExceptionState::kQueryContext:
+ break;
+ case ExceptionState::kIndexedGetterContext:
+ return ExceptionMessages::FailedToGetIndexed(c, m);
+ case ExceptionState::kIndexedSetterContext:
+ return ExceptionMessages::FailedToSetIndexed(c, m);
+ case ExceptionState::kIndexedDeletionContext:
+ return ExceptionMessages::FailedToDeleteIndexed(c, m);
+ case ExceptionState::kNamedGetterContext:
+ return ExceptionMessages::FailedToGetNamed(c, m);
+ case ExceptionState::kNamedSetterContext:
+ return ExceptionMessages::FailedToSetNamed(c, m);
+ case ExceptionState::kNamedDeletionContext:
+ return ExceptionMessages::FailedToDeleteNamed(c, m);
+ case ExceptionState::kUnknownContext:
+ break;
+ default:
+ NOTREACHED();
+ break;
}
+ return m;
+}
+} // namespace
+
+String ExceptionState::AddExceptionContext(
+ const String& original_message) const {
+ if (original_message.IsEmpty())
+ return original_message;
+
+ String message = original_message;
+ for (const ContextScope* scope = context_stack_top_; scope;
+ scope = scope->GetParent()) {
+ message = AddContextToMessage(message, scope->GetContext());
+ }
+ message = AddContextToMessage(message, main_context_);
return message;
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/exception_state.h b/chromium/third_party/blink/renderer/platform/bindings/exception_state.h
index a48584e40a6..d21a799ded9 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/exception_state.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/exception_state.h
@@ -34,7 +34,8 @@
#include "base/macros.h"
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
+#include "third_party/blink/renderer/platform/bindings/exception_context.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -49,22 +50,64 @@ class PLATFORM_EXPORT ExceptionState {
STACK_ALLOCATED();
public:
- enum ContextType {
- kConstructionContext,
- kExecutionContext,
- kDeletionContext,
- kGetterContext,
- kSetterContext,
- kEnumerationContext,
- kQueryContext,
- kIndexedGetterContext,
- kIndexedSetterContext,
- kIndexedDeletionContext,
- kNamedGetterContext,
- kNamedSetterContext,
- kNamedDeletionContext,
- kUnknownContext, // FIXME: Remove this once we've flipped over to the new
- // API.
+ // TODO(peria): Replace following enum aliases.
+ using ContextType = ExceptionContext::Context;
+ static constexpr ContextType kConstructionContext =
+ ExceptionContext::Context::kConstructorOperationInvoke;
+ static constexpr ContextType kExecutionContext =
+ ExceptionContext::Context::kOperationInvoke;
+ static constexpr ContextType kDeletionContext =
+ ExceptionContext::Context::kNamedPropertyDelete;
+ static constexpr ContextType kGetterContext =
+ ExceptionContext::Context::kAttributeGet;
+ static constexpr ContextType kSetterContext =
+ ExceptionContext::Context::kAttributeSet;
+ static constexpr ContextType kEnumerationContext =
+ ExceptionContext::Context::kNamedPropertyEnumerate;
+ static constexpr ContextType kQueryContext =
+ ExceptionContext::Context::kNamedPropertyQuery;
+ static constexpr ContextType kIndexedGetterContext =
+ ExceptionContext::Context::kIndexedPropertyGet;
+ static constexpr ContextType kIndexedSetterContext =
+ ExceptionContext::Context::kIndexedPropertySet;
+ static constexpr ContextType kIndexedDeletionContext =
+ ExceptionContext::Context::kIndexedPropertyDelete;
+ static constexpr ContextType kNamedGetterContext =
+ ExceptionContext::Context::kNamedPropertyGet;
+ static constexpr ContextType kNamedSetterContext =
+ ExceptionContext::Context::kNamedPropertySet;
+ static constexpr ContextType kNamedDeletionContext =
+ ExceptionContext::Context::kNamedPropertyDelete;
+ static constexpr ContextType kUnknownContext =
+ ExceptionContext::Context::kUnknown;
+
+ // ContextScope represents a stack of ExceptionContext in order to represent
+ // nested exception contexts such like an IDL dictionary in another IDL
+ // dictionary.
+ class ContextScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit ContextScope(const ExceptionContext& context,
+ ExceptionState& exception_state)
+ : exception_state_(exception_state), context_(context) {
+ exception_state_.PushContextScope(this);
+ }
+ ContextScope(const ContextScope&) = delete;
+ ContextScope& operator=(const ContextScope&) = delete;
+
+ ~ContextScope() { exception_state_.PopContextScope(); }
+
+ private:
+ void SetParent(const ContextScope* parent) { parent_ = parent; }
+ const ContextScope* GetParent() const { return parent_; }
+ const ExceptionContext& GetContext() const { return context_; }
+
+ ExceptionState& exception_state_;
+ const ContextScope* parent_ = nullptr;
+ const ExceptionContext context_;
+
+ friend class ExceptionState;
};
// A function pointer type that creates a DOMException.
@@ -77,36 +120,25 @@ class PLATFORM_EXPORT ExceptionState {
// Sets the function to create a DOMException. Must be called only once.
static void SetCreateDOMExceptionFunction(CreateDOMExceptionFunction);
+ ExceptionState(v8::Isolate* isolate, const ExceptionContext& context)
+ : main_context_(context), isolate_(isolate) {}
+
+ ExceptionState(v8::Isolate* isolate, ExceptionContext&& context)
+ : main_context_(std::move(context)), isolate_(isolate) {}
+
ExceptionState(v8::Isolate* isolate,
ContextType context_type,
const char* interface_name,
const char* property_name)
- : code_(0),
- context_(context_type),
- property_name_(property_name),
- interface_name_(interface_name),
- isolate_(isolate) {}
+ : ExceptionState(
+ isolate,
+ ExceptionContext(context_type, interface_name, property_name)) {}
ExceptionState(v8::Isolate* isolate,
ContextType context_type,
const char* interface_name)
- : ExceptionState(isolate, context_type, interface_name, nullptr) {
-#if DCHECK_IS_ON()
- switch (context_) {
- case kConstructionContext:
- case kEnumerationContext:
- case kIndexedGetterContext:
- case kIndexedSetterContext:
- case kIndexedDeletionContext:
- case kNamedGetterContext:
- case kNamedSetterContext:
- case kNamedDeletionContext:
- break;
- default:
- NOTREACHED();
- }
-#endif // DCHECK_IS_ON()
- }
+ : ExceptionState(isolate,
+ ExceptionContext(context_type, interface_name)) {}
~ExceptionState() {
if (!exception_.IsEmpty()) {
@@ -169,30 +201,49 @@ class PLATFORM_EXPORT ExceptionState {
return exception_.NewLocal(isolate_);
}
- ContextType Context() const { return context_; }
- const char* PropertyName() const { return property_name_; }
- const char* InterfaceName() const { return interface_name_; }
+ // Returns the context of what Web API is currently being executed.
+ const ExceptionContext& GetContext() const {
+ DCHECK(!context_stack_top_);
+ return main_context_;
+ }
+
+ // Deprecated APIs to get information about where this ExceptionState has
+ // been created.
+ ContextType Context() const { return GetContext().GetContext(); }
+ const char* PropertyName() const { return GetContext().GetPropertyName(); }
+ const char* InterfaceName() const { return GetContext().GetClassName(); }
protected:
void SetException(ExceptionCode, const String&, v8::Local<v8::Value>);
private:
+ void PushContextScope(ContextScope* scope);
+ void PopContextScope();
+
String AddExceptionContext(const String&) const;
// Since DOMException is defined in core/, we need a dependency injection in
// order to create a DOMException in platform/.
static CreateDOMExceptionFunction s_create_dom_exception_func_;
- ExceptionCode code_;
- ContextType context_;
+ // The main context represents what Web API is currently being executed.
+ // This is embedded without using ContextScope in order to avoid an overhead
+ // of ContextScope.
+ ExceptionContext main_context_;
+
+ // `context_stack_top_` points to the top of the context stack which
+ // represents additional (nested) contexts such as an IDL dictionary in a
+ // member of another IDL dictionary. nullptr means no additional context.
+ const ContextScope* context_stack_top_ = nullptr;
+
+ v8::Isolate* isolate_;
+ ExceptionCode code_ = 0;
String message_;
- const char* property_name_;
- const char* interface_name_;
// The exception is empty when it was thrown through
// DummyExceptionStateForTesting.
- ScopedPersistent<v8::Value> exception_;
- v8::Isolate* isolate_;
+ TraceWrapperV8Reference<v8::Value> exception_;
+ friend class ContextScope;
DISALLOW_COPY_AND_ASSIGN(ExceptionState);
};
diff --git a/chromium/third_party/blink/renderer/platform/bindings/idl_member_installer.cc b/chromium/third_party/blink/renderer/platform/bindings/idl_member_installer.cc
index 520ff5d33ee..81dbc9c59b0 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/idl_member_installer.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/idl_member_installer.cc
@@ -161,10 +161,10 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
V8PrivateProperty::GetCachedAccessor(isolate, v8_cached_accessor)
.GetPrivate(),
v8::Local<v8::Value>(), signature, length, v8_side_effect);
+ function_template->RemovePrototype();
}
function_template->SetClassName(name);
- function_template->RemovePrototype();
function_template->SetAcceptAnyReceiver(
GetConfigCrossOriginCheck<kind>(config) ==
IDLMemberInstaller::FlagCrossOriginCheck::kDoNotCheck);
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index 90e917ebe75..1879d7527fc 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -127,16 +127,6 @@ ParkableStringManager& ParkableStringManager::Instance() {
ParkableStringManager::~ParkableStringManager() = default;
-void ParkableStringManager::SetRendererBackgrounded(bool backgrounded) {
- DCHECK(IsMainThread());
- backgrounded_ = backgrounded;
-}
-
-bool ParkableStringManager::IsRendererBackgrounded() const {
- DCHECK(IsMainThread());
- return backgrounded_;
-}
-
bool ParkableStringManager::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd) {
DCHECK(IsMainThread());
@@ -486,7 +476,6 @@ ParkableStringManager::Statistics ParkableStringManager::ComputeStatistics()
}
void ParkableStringManager::ResetForTesting() {
- backgrounded_ = false;
has_pending_aging_task_ = false;
has_posted_unparking_time_accounting_task_ = false;
did_register_memory_pressure_listener_ = false;
@@ -501,8 +490,7 @@ void ParkableStringManager::ResetForTesting() {
}
ParkableStringManager::ParkableStringManager()
- : backgrounded_(false),
- has_pending_aging_task_(false),
+ : has_pending_aging_task_(false),
has_posted_unparking_time_accounting_task_(false),
did_register_memory_pressure_listener_(false),
allocator_for_testing_(nullptr) {}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
index d62d4ac37f5..d08a67d00e0 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
@@ -56,8 +56,6 @@ class PLATFORM_EXPORT ParkableStringManager {
static ParkableStringManager& Instance();
~ParkableStringManager();
- void SetRendererBackgrounded(bool backgrounded);
- bool IsRendererBackgrounded() const;
void PurgeMemory();
// Number of parked and unparked strings. Public for testing.
size_t Size() const;
@@ -125,7 +123,6 @@ class PLATFORM_EXPORT ParkableStringManager {
void ResetForTesting();
ParkableStringManager();
- bool backgrounded_;
bool has_pending_aging_task_;
bool has_posted_unparking_time_accounting_task_;
bool did_register_memory_pressure_listener_;
diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
index 87b48b9d541..ee745c344d6 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -4,13 +4,15 @@
#include <algorithm>
#include <limits>
-#include <thread>
+#include "base/bind.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/memory_allocator_dump.h"
@@ -43,6 +45,15 @@ String MakeLargeString(char c = 'a') {
return String(data.data(), data.size()).ReleaseImpl();
}
+class LambdaThreadDelegate : public base::PlatformThread::Delegate {
+ public:
+ explicit LambdaThreadDelegate(base::OnceClosure f) : f_(std::move(f)) {}
+ void ThreadMain() override { std::move(f_).Run(); }
+
+ private:
+ base::OnceClosure f_;
+};
+
} // namespace
class ParkableStringTest : public ::testing::Test {
@@ -382,8 +393,13 @@ TEST_F(ParkableStringTest, LockUnlock) {
EXPECT_TRUE(ParkAndWait(parkable));
parkable.ToString();
- std::thread t([&]() { parkable.Lock(); });
- t.join();
+
+ LambdaThreadDelegate delegate(
+ base::BindLambdaForTesting([&]() { parkable.Lock(); }));
+ base::PlatformThreadHandle thread_handle;
+ base::PlatformThread::Create(0, &delegate, &thread_handle);
+ base::PlatformThread::Join(thread_handle);
+
EXPECT_FALSE(ParkAndWait(parkable));
parkable.Unlock();
EXPECT_TRUE(ParkAndWait(parkable));
@@ -504,11 +520,13 @@ TEST_F(ParkableStringTest, ShouldPark) {
String parkable(MakeLargeString().ReleaseImpl());
EXPECT_TRUE(ParkableStringManager::ShouldPark(*parkable.Impl()));
- std::thread t([]() {
+ LambdaThreadDelegate delegate(base::BindLambdaForTesting([]() {
String parkable(MakeLargeString().ReleaseImpl());
EXPECT_FALSE(ParkableStringManager::ShouldPark(*parkable.Impl()));
- });
- t.join();
+ }));
+ base::PlatformThreadHandle thread_handle;
+ base::PlatformThread::Create(0, &delegate, &thread_handle);
+ base::PlatformThread::Join(thread_handle);
}
#if defined(ADDRESS_SANITIZER)
@@ -699,24 +717,7 @@ TEST_F(ParkableStringTest, SynchronousToDisk) {
EXPECT_TRUE(impl->is_on_disk()); // Synchronous writing.
}
-TEST_F(ParkableStringTest, OnPurgeMemoryInBackground) {
- ParkableString parkable = CreateAndParkAll();
- ParkableStringManager::Instance().SetRendererBackgrounded(true);
- EXPECT_TRUE(ParkableStringManager::Instance().IsRendererBackgrounded());
-
- parkable.ToString();
- EXPECT_FALSE(parkable.Impl()->is_parked());
- EXPECT_TRUE(parkable.Impl()->has_compressed_data());
-
- MemoryPressureListenerRegistry::Instance().OnPurgeMemory();
- EXPECT_TRUE(parkable.Impl()->is_parked());
-
- parkable.ToString();
- EXPECT_TRUE(parkable.Impl()->has_compressed_data());
-}
-
-TEST_F(ParkableStringTest, OnPurgeMemoryInForeground) {
- ParkableStringManager::Instance().SetRendererBackgrounded(false);
+TEST_F(ParkableStringTest, OnPurgeMemory) {
ParkableString parkable1 = CreateAndParkAll();
ParkableString parkable2(MakeLargeString('b').ReleaseImpl());
@@ -985,7 +986,8 @@ TEST_F(ParkableStringTest, AgingTicksStopsWithNoProgress) {
CheckOnlyCpuCostTaskRemains();
}
-TEST_F(ParkableStringTest, OnlyOneAgingTask) {
+// Flaky on a few platforms: crbug.com/1168170.
+TEST_F(ParkableStringTest, DISABLED_OnlyOneAgingTask) {
ParkableString parkable1(MakeLargeString('a').ReleaseImpl());
ParkableString parkable2(MakeLargeString('b').ReleaseImpl());
diff --git a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
index 96136b348f6..99a79bb2eb2 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h
@@ -250,7 +250,6 @@ class PLATFORM_EXPORT RuntimeCallStats {
#define CALLBACK_COUNTERS(V) \
BINDINGS_METHOD(V, ElementGetBoundingClientRect) \
BINDINGS_METHOD(V, ElementGetInnerHTML) \
- BINDINGS_METHOD(V, ElementSetInnerHTML) \
BINDINGS_METHOD(V, EventTargetDispatchEvent) \
BINDINGS_METHOD(V, HTMLElementClick) \
BINDINGS_METHOD(V, NodeAppendChild) \
diff --git a/chromium/third_party/blink/renderer/platform/bindings/scoped_persistent.h b/chromium/third_party/blink/renderer/platform/bindings/scoped_persistent.h
index fd3267a78d7..f21756c3b5a 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/scoped_persistent.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/scoped_persistent.h
@@ -51,12 +51,6 @@ class ScopedPersistent {
ScopedPersistent(v8::Isolate* isolate, v8::Local<T> handle)
: handle_(isolate, handle) {}
- ScopedPersistent(v8::Isolate* isolate, v8::MaybeLocal<T> maybe) {
- v8::Local<T> local;
- if (maybe.ToLocal(&local))
- handle_.Reset(isolate, local);
- }
-
~ScopedPersistent() { Clear(); }
ALWAYS_INLINE v8::Local<T> NewLocal(v8::Isolate* isolate) const {
diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_state.cc b/chromium/third_party/blink/renderer/platform/bindings/script_state.cc
index 982aa7654b5..d9a9ad15454 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/script_state.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/script_state.cc
@@ -17,7 +17,7 @@ ScriptState::ScriptState(v8::Local<v8::Context> context,
: isolate_(context->GetIsolate()),
context_(isolate_, context),
world_(std::move(world)),
- per_context_data_(std::make_unique<V8PerContextData>(context)),
+ per_context_data_(MakeGarbageCollected<V8PerContextData>(context)),
reference_from_v8_context_(PERSISTENT_FROM_HERE, this) {
DCHECK(world_);
context_.SetWeak(this, &OnV8ContextCollectedCallback);
@@ -34,12 +34,17 @@ ScriptState::~ScriptState() {
RendererResourceCoordinator::Get()->OnScriptStateDestroyed(this);
}
+void ScriptState::Trace(Visitor* visitor) const {
+ visitor->Trace(per_context_data_);
+}
+
void ScriptState::DetachGlobalObject() {
DCHECK(!context_.IsEmpty());
GetContext()->DetachGlobal();
}
void ScriptState::DisposePerContextData() {
+ per_context_data_->Dispose();
per_context_data_ = nullptr;
InstanceCounters::IncrementCounter(
InstanceCounters::kDetachedScriptStateCounter);
diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_state.h b/chromium/third_party/blink/renderer/platform/bindings/script_state.h
index 2a1897e16b1..738b754b6fb 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/script_state.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/script_state.h
@@ -130,7 +130,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
ExecutionContext* execution_context);
~ScriptState();
- void Trace(Visitor*) const {}
+ void Trace(Visitor*) const;
static ScriptState* Current(v8::Isolate* isolate) { // DEPRECATED
return From(isolate->GetCurrentContext());
@@ -190,7 +190,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
}
void DetachGlobalObject();
- V8PerContextData* PerContextData() const { return per_context_data_.get(); }
+ V8PerContextData* PerContextData() const { return per_context_data_.Get(); }
void DisposePerContextData();
// This method is expected to be called only from
@@ -217,7 +217,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
// So you must explicitly clear the std::unique_ptr by calling
// disposePerContextData() once you no longer need V8PerContextData.
// Otherwise, the v8::Context will leak.
- std::unique_ptr<V8PerContextData> per_context_data_;
+ Member<V8PerContextData> per_context_data_;
// v8::Context has an internal field to this ScriptState* as a raw pointer,
// which is out of scope of Blink GC, but it must be a strong reference. We
diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.cc b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.cc
index f583d76b33b..39364dfec5e 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
@@ -30,6 +31,20 @@ v8::Local<v8::Value> ScriptWrappable::Wrap(
return AssociateWithWrapper(isolate, wrapper_type_info, wrapper);
}
+v8::MaybeLocal<v8::Value> ScriptWrappable::WrapV2(ScriptState* script_state) {
+ const WrapperTypeInfo* wrapper_type_info = this->GetWrapperTypeInfo();
+
+ DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+ v8::Local<v8::Object> wrapper;
+ if (!V8DOMWrapper::CreateWrapperV2(script_state, wrapper_type_info)
+ .ToLocal(&wrapper)) {
+ return v8::MaybeLocal<v8::Value>();
+ }
+ return AssociateWithWrapper(script_state->GetIsolate(), wrapper_type_info,
+ wrapper);
+}
+
v8::Local<v8::Object> ScriptWrappable::AssociateWithWrapper(
v8::Isolate* isolate,
const WrapperTypeInfo* wrapper_type_info,
diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.h b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.h
index 75dfd25a342..fb0fc247fd8 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable.h
@@ -43,6 +43,8 @@
namespace blink {
+class ScriptState;
+
// ScriptWrappable provides a way to map from/to C++ DOM implementation to/from
// JavaScript object (platform object). ToV8() converts a ScriptWrappable to
// a v8::Object and toScriptWrappable() converts a v8::Object back to
@@ -97,6 +99,10 @@ class PLATFORM_EXPORT ScriptWrappable
// Creates and returns a new wrapper object.
virtual v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context);
+ // This is another version of Wrap which returns v8::MaybeLocal value
+ // in order to throw an exception.
+ // TODO(canonmukai): We should replace current Wrap with this WrapV2.
+ virtual v8::MaybeLocal<v8::Value> WrapV2(ScriptState*);
// Associates the instance with the given |wrapper| if this instance is not
// yet associated with any wrapper. Returns the wrapper already associated
diff --git a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
index c3388beb43b..68f112fdee5 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h
@@ -355,15 +355,19 @@ inline v8::Local<v8::Value> ToV8(base::Time date, ScriptState* script_state) {
}
// Only declare ToV8(void*,...) for checking function overload mismatch.
-// This ToV8(void*,...) should be never used. So we will find mismatch
-// because of "unresolved external symbol".
+// This ToV8(void*,...) should be never used.
// Without ToV8(void*, ...), call to toV8 with T* will match with
// ToV8(bool, ...) if T is not a subclass of ScriptWrappable or if T is
// declared but not defined (so it's not clear that T is a subclass of
// ScriptWrappable).
// This hack helps detect such unwanted implicit conversions from T* to bool.
v8::Local<v8::Value> ToV8(void* value,
- v8::Local<v8::Object> creation_context,
+ v8::Local<v8::Object>,
+ v8::Isolate*) = delete;
+// Similarly, this helps detect unwanted implicit conversion from const T* to
+// bool, e.g. ToV8(const Element*).
+v8::Local<v8::Value> ToV8(const void* value,
+ v8::Local<v8::Object>,
v8::Isolate*) = delete;
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
index d68b79f432f..b2937f6b525 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
@@ -7,10 +7,21 @@
#include <utility>
+#include "base/compiler_specific.h"
#include "base/macros.h"
#include "third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
+#include "v8/include/v8-cppgc.h"
#include "v8/include/v8.h"
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "v8/include/cppgc/trace-trait.h"
+#endif // USE_V8_OILPAN
+
namespace blink {
template <typename T>
@@ -67,7 +78,8 @@ class TraceWrapperV8Reference {
}
template <class S>
- TraceWrapperV8Reference(TraceWrapperV8Reference<S>&& other) noexcept {
+ TraceWrapperV8Reference( // NOLINT
+ TraceWrapperV8Reference<S>&& other) noexcept {
*this = std::move(other);
}
@@ -112,21 +124,53 @@ class TraceWrapperV8Reference {
protected:
ALWAYS_INLINE void InternalSet(v8::Isolate* isolate, v8::Local<T> handle) {
handle_.Reset(isolate, handle);
+#if BUILDFLAG(USE_V8_OILPAN)
+ UnifiedHeapMarkingVisitor::WriteBarrier(UnsafeCast<v8::Value>().Get());
+#else // !USE_V8_OILPAN
UnifiedHeapMarkingVisitor::WriteBarrier(UnsafeCast<v8::Value>());
+#endif // !USE_V8_OILPAN
}
ALWAYS_INLINE void WriteBarrier() const {
+#if BUILDFLAG(USE_V8_OILPAN)
+ UnifiedHeapMarkingVisitor::WriteBarrier(UnsafeCast<v8::Value>().Get());
+#else // !USE_V8_OILPAN
UnifiedHeapMarkingVisitor::WriteBarrier(UnsafeCast<v8::Value>());
+#endif // !USE_V8_OILPAN
}
v8::TracedReference<T> handle_;
+
+ friend struct cppgc::TraceTrait<TraceWrapperV8Reference<T>>;
};
+} // namespace blink
+#if BUILDFLAG(USE_V8_OILPAN)
+
+namespace cppgc {
+template <typename T>
+struct TraceTrait<blink::TraceWrapperV8Reference<T>> {
+ STATIC_ONLY(TraceTrait);
+
+ static cppgc::TraceDescriptor GetTraceDescriptor(
+ const blink::TraceWrapperV8Reference<T>* ref) {
+ return {nullptr, Trace};
+ }
+
+ static void Trace(Visitor* visitor, const void* self) {
+ visitor->Trace(
+ static_cast<const blink::TraceWrapperV8Reference<T>*>(self)->handle_);
+ }
+};
+} // namespace cppgc
+
+#else // !USE_V8_OILPAN
+
+namespace blink {
template <typename T>
struct TraceTrait<TraceWrapperV8Reference<T>> {
STATIC_ONLY(TraceTrait);
- public:
static TraceDescriptor GetTraceDescriptor(
const TraceWrapperV8Reference<T>* ref) {
return {ref, TraceTrait<TraceWrapperV8Reference<T>>::Trace};
@@ -136,9 +180,10 @@ struct TraceTrait<TraceWrapperV8Reference<T>> {
visitor->Trace(*static_cast<const TraceWrapperV8Reference<T>*>(ref));
}
};
-
} // namespace blink
+#endif // !USE_V8_OILPAN
+
namespace WTF {
template <typename T>
diff --git a/chromium/third_party/blink/renderer/platform/bindings/union_base.cc b/chromium/third_party/blink/renderer/platform/bindings/union_base.cc
new file mode 100644
index 00000000000..4b37e3b96f0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/bindings/union_base.cc
@@ -0,0 +1,33 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/bindings/union_base.h"
+
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+namespace bindings {
+
+// static
+String UnionBase::ProduceUnionNameInIDL(
+ const base::span<const char* const>& member_names) {
+ DCHECK_GE(member_names.size(), 2u);
+
+ StringBuilder builder;
+
+ builder.Append("(");
+ builder.Append(member_names[0]);
+ for (size_t i = 1; i < member_names.size(); ++i) {
+ builder.Append(" or ");
+ builder.Append(member_names[i]);
+ }
+ builder.Append(")");
+
+ return builder.ToString();
+}
+
+} // namespace bindings
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/union_base.h b/chromium/third_party/blink/renderer/platform/bindings/union_base.h
index 5029291af7a..0e777b7ff49 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/union_base.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/union_base.h
@@ -5,12 +5,16 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
+#include "base/containers/span.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "v8/include/v8.h"
namespace blink {
+class ScriptState;
+
namespace bindings {
// UnionBase is the common base class of all the IDL union classes. Most
@@ -22,9 +26,14 @@ class PLATFORM_EXPORT UnionBase : public GarbageCollected<UnionBase> {
public:
virtual ~UnionBase() = default;
+ virtual v8::MaybeLocal<v8::Value> ToV8Value(ScriptState* script_state) = 0;
+
virtual void Trace(Visitor*) const {}
protected:
+ static String ProduceUnionNameInIDL(
+ const base::span<const char* const>& member_names);
+
UnionBase() = default;
};
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.cc b/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.cc
deleted file mode 100644
index 5413028b65b..00000000000
--- a/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h"
-
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-
-namespace blink {
-
-V0CustomElementBinding::V0CustomElementBinding(v8::Isolate* isolate,
- v8::Local<v8::Object> prototype)
- : prototype_(isolate, prototype) {
- DCHECK(!prototype_.IsEmpty());
-}
-
-V0CustomElementBinding::~V0CustomElementBinding() = default;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h b/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h
deleted file mode 100644
index 401a51a7795..00000000000
--- a/chromium/third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V0_CUSTOM_ELEMENT_BINDING_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V0_CUSTOM_ELEMENT_BINDING_H_
-
-#include <memory>
-
-#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT V0CustomElementBinding {
- USING_FAST_MALLOC(V0CustomElementBinding);
-
- public:
- V0CustomElementBinding(v8::Isolate*, v8::Local<v8::Object> prototype);
- ~V0CustomElementBinding();
-
- private:
- ScopedPersistent<v8::Object> prototype_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V0_CUSTOM_ELEMENT_BINDING_H_
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
index 8c2c5db0d44..05838971936 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
@@ -71,6 +71,41 @@ v8::Local<v8::Object> V8DOMWrapper::CreateWrapper(
return wrapper;
}
+v8::MaybeLocal<v8::Object> V8DOMWrapper::CreateWrapperV2(
+ ScriptState* script_state,
+ const WrapperTypeInfo* type) {
+ RUNTIME_CALL_TIMER_SCOPE(script_state->GetIsolate(),
+ RuntimeCallStats::CounterId::kCreateWrapper);
+
+ V8WrapperInstantiationScope scope(script_state, type);
+ if (scope.AccessCheckFailed()) {
+ // V8WrapperInstantiationScope's ctor throws an exception
+ // if AccessCheckFailed.
+ return v8::MaybeLocal<v8::Object>();
+ }
+
+ V8PerContextData* per_context_data =
+ V8PerContextData::From(scope.GetContext());
+ v8::Local<v8::Object> wrapper;
+ if (per_context_data) {
+ wrapper = per_context_data->CreateWrapperFromCache(type);
+ CHECK(!wrapper.IsEmpty());
+ } else {
+ // The context is detached, but still accessible.
+ // TODO(yukishiino): This code does not create a wrapper with
+ // the correct settings. Should follow the same way as
+ // V8PerContextData::createWrapperFromCache, though there is no need to
+ // cache resulting objects or their constructors.
+ const DOMWrapperWorld& world = DOMWrapperWorld::World(scope.GetContext());
+ wrapper = type->GetV8ClassTemplate(script_state->GetIsolate(), world)
+ .As<v8::FunctionTemplate>()
+ ->InstanceTemplate()
+ ->NewInstance(scope.GetContext())
+ .ToLocalChecked();
+ }
+ return wrapper;
+}
+
bool V8DOMWrapper::IsWrapper(v8::Isolate* isolate, v8::Local<v8::Value> value) {
if (value.IsEmpty() || !value->IsObject())
return false;
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h b/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h
index f9236332b9b..29d047b8988 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h
@@ -57,6 +57,13 @@ class V8DOMWrapper {
v8::Isolate*,
v8::Local<v8::Object> creation_context,
const WrapperTypeInfo*);
+ // This is another version of CreateWrapper which returns
+ // v8::MaybeLocal in order to throw an exception.
+ // TODO(canonmukai): We should replace CreateWrapper with
+ // CreateWrapperV2 soon.
+ PLATFORM_EXPORT static v8::MaybeLocal<v8::Object> CreateWrapperV2(
+ ScriptState*,
+ const WrapperTypeInfo*);
PLATFORM_EXPORT static bool IsWrapper(v8::Isolate*, v8::Local<v8::Value>);
// Associates the given ScriptWrappable with the given |wrapper| if the
@@ -116,7 +123,7 @@ inline void V8DOMWrapper::SetNativeInfoInternal(
// The following write barrier is necessary as V8 might not see the newly
// created object during garbage collection, e.g., when the object is black
// allocated.
- UnifiedHeapMarkingVisitor::WriteBarrier(isolate, wrapper_type_info,
+ UnifiedHeapMarkingVisitor::WriteBarrier(isolate, wrapper, wrapper_type_info,
wrappable);
}
@@ -162,11 +169,9 @@ class V8WrapperInstantiationScope {
V8WrapperInstantiationScope(v8::Local<v8::Object> creation_context,
v8::Isolate* isolate,
const WrapperTypeInfo* type)
- : did_enter_context_(false),
- context_(isolate->GetCurrentContext()),
+ : context_(isolate->GetCurrentContext()),
try_catch_(isolate),
- type_(type),
- access_check_failed_(false) {
+ type_(type) {
// creationContext should not be empty. Because if we have an
// empty creationContext, we will end up creating
// a new object in the context currently entered. This is wrong.
@@ -192,6 +197,33 @@ class V8WrapperInstantiationScope {
context_->Enter();
}
+ // This is an overload of constructor for CreateWrapperV2.
+ V8WrapperInstantiationScope(ScriptState* script_state,
+ const WrapperTypeInfo* type)
+ : context_(script_state->GetIsolate()->GetCurrentContext()),
+ try_catch_(script_state->GetIsolate()),
+ type_(type) {
+ v8::Local<v8::Context> context_for_wrapper = script_state->GetContext();
+
+ // For performance, we enter the context only if the currently running
+ // context is different from the context that we are about to enter.
+ if (context_for_wrapper == context_)
+ return;
+
+ if (!BindingSecurityForPlatform::ShouldAllowWrapperCreationOrThrowException(
+ script_state->GetIsolate()->GetCurrentContext(),
+ context_for_wrapper, type_)) {
+ DCHECK(try_catch_.HasCaught());
+ try_catch_.ReThrow();
+ access_check_failed_ = true;
+ return;
+ }
+
+ did_enter_context_ = true;
+ context_ = context_for_wrapper;
+ context_->Enter();
+ }
+
~V8WrapperInstantiationScope() {
if (!did_enter_context_) {
try_catch_.ReThrow();
@@ -218,11 +250,11 @@ class V8WrapperInstantiationScope {
bool AccessCheckFailed() const { return access_check_failed_; }
private:
- bool did_enter_context_;
+ bool did_enter_context_ = false;
v8::Local<v8::Context> context_;
v8::TryCatch try_catch_;
const WrapperTypeInfo* type_;
- bool access_check_failed_;
+ bool access_check_failed_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
index c1aa7f7127e..8d92ce4398b 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
@@ -37,7 +37,6 @@
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/v0_custom_element_binding.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
@@ -47,21 +46,15 @@ namespace blink {
namespace {
-constexpr char kWrapperBoilerplatesLabel[] =
- "V8PerContextData::wrapper_boilerplates_";
-constexpr char kConstructorMapLabel[] = "V8PerContextData::constructor_map_";
constexpr char kContextLabel[] = "V8PerContextData::context_";
} // namespace
V8PerContextData::V8PerContextData(v8::Local<v8::Context> context)
: isolate_(context->GetIsolate()),
- wrapper_boilerplates_(isolate_, kWrapperBoilerplatesLabel),
- constructor_map_(isolate_, kConstructorMapLabel),
context_holder_(std::make_unique<gin::ContextHolder>(isolate_)),
context_(isolate_, context),
- activity_logger_(nullptr),
- data_map_(MakeGarbageCollected<DataMap>()) {
+ activity_logger_(nullptr) {
context_holder_->SetContext(context);
context_.Get().AnnotateStrongRetainer(kContextLabel);
@@ -78,24 +71,47 @@ V8PerContextData::~V8PerContextData() {
}
}
+void V8PerContextData::Dispose() {
+ // These fields are not traced by the garbage collector and could contain
+ // strong GC roots that prevent `this` from otherwise being collected, so
+ // explicitly break any potential cycles in the ownership graph now.
+ context_holder_ = nullptr;
+ if (!context_.IsEmpty())
+ context_.SetPhantom();
+ if (!private_custom_element_definition_id_.IsEmpty())
+ private_custom_element_definition_id_.SetPhantom();
+}
+
+void V8PerContextData::Trace(Visitor* visitor) const {
+ visitor->Trace(wrapper_boilerplates_);
+ visitor->Trace(constructor_map_);
+ visitor->Trace(data_map_);
+}
+
V8PerContextData* V8PerContextData::From(v8::Local<v8::Context> context) {
return ScriptState::From(context)->PerContextData();
}
v8::Local<v8::Object> V8PerContextData::CreateWrapperFromCacheSlowCase(
const WrapperTypeInfo* type) {
+ DCHECK(!wrapper_boilerplates_.Contains(type));
v8::Context::Scope scope(GetContext());
v8::Local<v8::Function> interface_object = ConstructorForType(type);
CHECK(!interface_object.IsEmpty());
v8::Local<v8::Object> instance_template =
V8ObjectConstructor::NewInstance(isolate_, interface_object)
.ToLocalChecked();
- wrapper_boilerplates_.Set(type, instance_template);
+
+ TraceWrapperV8Reference<v8::Object> traced_wrapper;
+ traced_wrapper.Set(isolate_, instance_template);
+ wrapper_boilerplates_.insert(type, traced_wrapper);
+
return instance_template->Clone();
}
v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase(
const WrapperTypeInfo* type) {
+ DCHECK(!constructor_map_.Contains(type));
v8::Local<v8::Context> context = GetContext();
v8::Context::Scope scope(context);
@@ -110,7 +126,10 @@ v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase(
type, context, world, isolate_, parent_interface_object,
V8ObjectConstructor::CreationMode::kInstallConditionalFeatures);
- constructor_map_.Set(type, interface_object);
+ TraceWrapperV8Reference<v8::Function> traced_wrapper;
+ traced_wrapper.Set(isolate_, interface_object);
+ constructor_map_.insert(type, traced_wrapper);
+
return interface_object;
}
@@ -131,31 +150,28 @@ bool V8PerContextData::GetExistingConstructorAndPrototypeForType(
const WrapperTypeInfo* type,
v8::Local<v8::Object>* prototype_object,
v8::Local<v8::Function>* interface_object) {
- *interface_object = constructor_map_.Get(type);
- if (interface_object->IsEmpty()) {
- *prototype_object = v8::Local<v8::Object>();
+ auto it = constructor_map_.find(type);
+ if (it == constructor_map_.end()) {
+ interface_object->Clear();
+ prototype_object->Clear();
return false;
}
+ *interface_object = it->value.NewLocal(isolate_);
*prototype_object = PrototypeForType(type);
DCHECK(!prototype_object->IsEmpty());
return true;
}
-void V8PerContextData::AddCustomElementBinding(
- std::unique_ptr<V0CustomElementBinding> binding) {
- custom_element_bindings_.push_back(std::move(binding));
-}
-
void V8PerContextData::AddData(const char* key, Data* data) {
- data_map_->Set(key, data);
+ data_map_.Set(key, data);
}
void V8PerContextData::ClearData(const char* key) {
- data_map_->erase(key);
+ data_map_.erase(key);
}
V8PerContextData::Data* V8PerContextData::GetData(const char* key) {
- return data_map_->at(key);
+ return data_map_.at(key);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.h b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
index 9ba1ef38a81..bf10ab6f647 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
@@ -36,11 +36,11 @@
#include "gin/public/context_holder.h"
#include "gin/public/gin_embedders.h"
#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/bindings/v8_global_value_map.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
@@ -49,16 +49,14 @@
namespace blink {
-class V0CustomElementBinding;
class V8DOMActivityLogger;
class V8PerContextData;
struct WrapperTypeInfo;
// Used to hold data that is associated with a single v8::Context object, and
// has a 1:1 relationship with v8::Context.
-class PLATFORM_EXPORT V8PerContextData final {
- USING_FAST_MALLOC(V8PerContextData);
-
+class PLATFORM_EXPORT V8PerContextData final
+ : public GarbageCollected<V8PerContextData> {
public:
explicit V8PerContextData(v8::Local<v8::Context>);
@@ -66,23 +64,27 @@ class PLATFORM_EXPORT V8PerContextData final {
~V8PerContextData();
+ void Trace(Visitor* visitor) const;
+ void Dispose();
+
v8::Local<v8::Context> GetContext() { return context_.NewLocal(isolate_); }
// To create JS Wrapper objects, we create a cache of a 'boiler plate'
// object, and then simply Clone that object each time we need a new one.
// This is faster than going through the full object creation process.
v8::Local<v8::Object> CreateWrapperFromCache(const WrapperTypeInfo* type) {
- v8::Local<v8::Object> boilerplate = wrapper_boilerplates_.Get(type);
- return !boilerplate.IsEmpty() ? boilerplate->Clone()
- : CreateWrapperFromCacheSlowCase(type);
+ auto it = wrapper_boilerplates_.find(type);
+ return it != wrapper_boilerplates_.end()
+ ? it->value.Get()->Clone()
+ : CreateWrapperFromCacheSlowCase(type);
}
// Returns the interface object that is appropriately initialized (e.g.
// context-dependent properties are installed).
v8::Local<v8::Function> ConstructorForType(const WrapperTypeInfo* type) {
- v8::Local<v8::Function> interface_object = constructor_map_.Get(type);
- return (!interface_object.IsEmpty()) ? interface_object
- : ConstructorForTypeSlowCase(type);
+ auto it = constructor_map_.find(type);
+ return it != constructor_map_.end() ? it->value.NewLocal(isolate_)
+ : ConstructorForTypeSlowCase(type);
}
v8::Local<v8::Object> PrototypeForType(const WrapperTypeInfo*);
@@ -96,8 +98,6 @@ class PLATFORM_EXPORT V8PerContextData final {
v8::Local<v8::Object>* prototype_object,
v8::Local<v8::Function>* interface_object);
- void AddCustomElementBinding(std::unique_ptr<V0CustomElementBinding>);
-
// Gets a Private to store custom element definition IDs on a
// constructor that has been registered as a custom element in this
// context. This private has to be per-context because the same
@@ -130,13 +130,15 @@ class PLATFORM_EXPORT V8PerContextData final {
v8::Local<v8::Object> CreateWrapperFromCacheSlowCase(const WrapperTypeInfo*);
v8::Local<v8::Function> ConstructorForTypeSlowCase(const WrapperTypeInfo*);
- v8::Isolate* isolate_;
+ v8::Isolate* const isolate_;
// For each possible type of wrapper, we keep a boilerplate object.
// The boilerplate is used to create additional wrappers of the same type.
- V8GlobalValueMap<const WrapperTypeInfo*, v8::Object> wrapper_boilerplates_;
+ HeapHashMap<const WrapperTypeInfo*, TraceWrapperV8Reference<v8::Object>>
+ wrapper_boilerplates_;
- V8GlobalValueMap<const WrapperTypeInfo*, v8::Function> constructor_map_;
+ HeapHashMap<const WrapperTypeInfo*, TraceWrapperV8Reference<v8::Function>>
+ constructor_map_;
std::unique_ptr<gin::ContextHolder> context_holder_;
@@ -144,15 +146,11 @@ class PLATFORM_EXPORT V8PerContextData final {
ScopedPersistent<v8::Private> private_custom_element_definition_id_;
- typedef Vector<std::unique_ptr<V0CustomElementBinding>>
- V0CustomElementBindingList;
- V0CustomElementBindingList custom_element_bindings_;
-
// This is owned by a static hash map in V8DOMActivityLogger.
V8DOMActivityLogger* activity_logger_;
using DataMap = HeapHashMap<const char*, Member<Data>>;
- Persistent<DataMap> data_map_;
+ DataMap data_map_;
DISALLOW_COPY_AND_ASSIGN(V8PerContextData);
};
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
index 18474fdbc27..1e916c6ea88 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -59,7 +59,7 @@ static void BeforeCallEnteredCallback(v8::Isolate* isolate) {
CHECK(!ScriptForbiddenScope::IsScriptForbidden());
}
-static void MicrotasksCompletedCallback(v8::Isolate* isolate) {
+static void MicrotasksCompletedCallback(v8::Isolate* isolate, void* data) {
V8PerIsolateData::From(isolate)->RunEndOfScopeTasks();
}
@@ -159,16 +159,12 @@ void V8PerIsolateData::WillBeDestroyed(v8::Isolate* isolate) {
data->ClearScriptRegexpContext();
- // Detach V8's garbage collector.
- // Need to finalize an already running garbage collection as otherwise
- // callbacks are missing and state gets out of sync.
- ThreadState* const thread_state = ThreadState::Current();
- thread_state->FinishIncrementalMarkingIfRunning(
- BlinkGC::CollectionType::kMajor, BlinkGC::kHeapPointersOnStack,
- BlinkGC::kAtomicMarking, BlinkGC::kEagerSweeping,
- BlinkGC::GCReason::kThreadTerminationGC);
+ ThreadState::Current()->DetachFromIsolate();
+
data->active_script_wrappable_manager_.Clear();
- thread_state->DetachFromIsolate();
+ // Callbacks can be removed as they only cover single events (e.g. atomic
+ // pause) and they cannot get out of sync.
+ DCHECK_EQ(0u, data->gc_callback_depth_);
isolate->RemoveGCPrologueCallback(data->prologue_callback_);
isolate->RemoveGCEpilogueCallback(data->epilogue_callback_);
}
diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
index 7834d4a444e..2c24a3e5316 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
@@ -207,6 +207,10 @@ class PLATFORM_EXPORT V8PerIsolateData final {
v8::Isolate::GCCallback prologue_callback,
v8::Isolate::GCCallback epilogue_callback);
+ void EnterGC() { gc_callback_depth_++; }
+
+ void LeaveGC() { gc_callback_depth_--; }
+
private:
V8PerIsolateData(scoped_refptr<base::SingleThreadTaskRunner>,
V8ContextSnapshotMode);
@@ -268,6 +272,7 @@ class PLATFORM_EXPORT V8PerIsolateData final {
v8::Isolate::GCCallback prologue_callback_;
v8::Isolate::GCCallback epilogue_callback_;
+ size_t gc_callback_depth_ = 0;
DISALLOW_COPY_AND_ASSIGN(V8PerIsolateData);
};
diff --git a/chromium/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/chromium/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
index e544f774ccd..5ce607cb867 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
+++ b/chromium/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -33,6 +33,7 @@
#include "gin/public/wrapper_info.h"
#include "third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -43,7 +44,6 @@ namespace blink {
class CustomWrappable;
class DOMWrapperWorld;
class ScriptWrappable;
-class Visitor;
static const int kV8DOMWrapperTypeIndex =
static_cast<int>(gin::kWrapperInfoIndex);
diff --git a/chromium/third_party/blink/renderer/platform/blob/DIR_METADATA b/chromium/third_party/blink/renderer/platform/blob/DIR_METADATA
new file mode 100644
index 00000000000..08cf7a5d95c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/blob/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Storage>FileAPI"
+}
+team_email: "storage-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/blob/OWNERS b/chromium/third_party/blink/renderer/platform/blob/OWNERS
index 518ea8c5083..0afd48aa197 100644
--- a/chromium/third_party/blink/renderer/platform/blob/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/blob/OWNERS
@@ -2,6 +2,3 @@ file://storage/browser/blob/OWNERS
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>FileAPI
diff --git a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider.cc b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider.cc
index 084d17eceb6..7aa139649f7 100644
--- a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/platform/blob/blob_bytes_provider.h"
+#include <utility>
+
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
@@ -133,7 +135,7 @@ BlobBytesProvider* BlobBytesProvider::CreateAndBind(
mojo::MakeSelfOwnedReceiver(std::move(provider),
std::move(receiver));
},
- WTF::Passed(std::move(provider)), WTF::Passed(std::move(receiver))));
+ std::move(provider), std::move(receiver)));
return result;
}
diff --git a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
index e1140bbe3eb..abacfde3a7a 100644
--- a/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
+++ b/chromium/third_party/blink/renderer/platform/blob/blob_bytes_provider_test.cc
@@ -327,8 +327,11 @@ TEST_F(BlobBytesProviderTest, RequestAsStream) {
provider->AppendData(test_data2_);
provider->AppendData(test_data3_);
- mojo::DataPipe pipe(7);
- provider->RequestAsStream(std::move(pipe.producer_handle));
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(7, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
+ provider->RequestAsStream(std::move(producer_handle));
Vector<uint8_t> received_data;
base::RunLoop loop;
@@ -336,7 +339,7 @@ TEST_F(BlobBytesProviderTest, RequestAsStream) {
FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC,
blink::scheduler::GetSequencedTaskRunnerForTesting());
watcher.Watch(
- pipe.consumer_handle.get(), MOJO_HANDLE_SIGNAL_READABLE,
+ consumer_handle.get(), MOJO_HANDLE_SIGNAL_READABLE,
MOJO_WATCH_CONDITION_SATISFIED,
base::BindRepeating(
[](mojo::DataPipeConsumerHandle pipe,
@@ -361,7 +364,7 @@ TEST_F(BlobBytesProviderTest, RequestAsStream) {
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
bytes_out->AppendVector(bytes);
},
- pipe.consumer_handle.get(), loop.QuitClosure(), &received_data));
+ consumer_handle.get(), loop.QuitClosure(), &received_data));
loop.Run();
EXPECT_EQ(combined_bytes_, received_data);
diff --git a/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.cc b/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.cc
new file mode 100644
index 00000000000..f20e9cbb9da
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.cc
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
+
+#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
+
+namespace blink {
+
+ContextLifecycleNotifier::~ContextLifecycleNotifier() {
+#if DCHECK_IS_ON()
+ // `NotifyContextDestroyed()` must be called prior to destruction.
+ DCHECK(did_notify_observers_);
+#endif
+}
+
+void ContextLifecycleNotifier::AddContextLifecycleObserver(
+ ContextLifecycleObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ContextLifecycleNotifier::RemoveContextLifecycleObserver(
+ ContextLifecycleObserver* observer) {
+ DCHECK(observers_.HasObserver(observer));
+ observers_.RemoveObserver(observer);
+}
+
+void ContextLifecycleNotifier::NotifyContextDestroyed() {
+ observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
+ observer->NotifyContextDestroyed();
+ });
+ observers_.Clear();
+
+#if DCHECK_IS_ON()
+ did_notify_observers_ = true;
+#endif
+}
+
+void ContextLifecycleNotifier::Trace(Visitor* visitor) const {
+ visitor->Trace(observers_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.h b/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.h
index 6b16cfe76bb..2eb7e4d73a8 100644
--- a/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.h
+++ b/chromium/third_party/blink/renderer/platform/context_lifecycle_notifier.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_CONTEXT_LIFECYCLE_NOTIFIER_H_
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
namespace blink {
@@ -14,8 +15,28 @@ class ContextLifecycleObserver;
// Notifier interface for ContextLifecycleObserver.
class PLATFORM_EXPORT ContextLifecycleNotifier : public GarbageCollectedMixin {
public:
- virtual void AddContextLifecycleObserver(ContextLifecycleObserver*) = 0;
- virtual void RemoveContextLifecycleObserver(ContextLifecycleObserver*) = 0;
+ virtual ~ContextLifecycleNotifier();
+
+ virtual void AddContextLifecycleObserver(ContextLifecycleObserver*);
+ virtual void RemoveContextLifecycleObserver(ContextLifecycleObserver*);
+
+ void Trace(Visitor* visitor) const override;
+
+ protected:
+ // Should be called by implementers to notify observers when the context is
+ // destroyed.
+ void NotifyContextDestroyed();
+
+ const HeapObserverSet<ContextLifecycleObserver>& observers() const {
+ return observers_;
+ }
+ HeapObserverSet<ContextLifecycleObserver>& observers() { return observers_; }
+
+ private:
+ HeapObserverSet<ContextLifecycleObserver> observers_;
+#if DCHECK_IS_ON()
+ bool did_notify_observers_ = false;
+#endif
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.cc b/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.cc
index 9beb1790856..c1f2695b1ea 100644
--- a/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.cc
+++ b/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.cc
@@ -8,8 +8,15 @@
namespace blink {
-void ContextLifecycleObserver::ObserverSetWillBeCleared() {
- notifier_ = nullptr;
+ContextLifecycleObserver::~ContextLifecycleObserver() {
+#if DCHECK_IS_ON()
+ // We want to make sure that if we are still waiting for a notification,
+ // then the context hasn't been GC'ed (or, in other words, if the WeakPtr is
+ // reset then `ContextDestroyed()` has been called).
+ // waiting_for_context_destroyed_ -> notifier_
+ // !waiting_for_context_destroyed_ || notifier_
+ DCHECK(!waiting_for_context_destroyed_ || notifier_);
+#endif
}
void ContextLifecycleObserver::SetContextLifecycleNotifier(
@@ -22,10 +29,24 @@ void ContextLifecycleObserver::SetContextLifecycleNotifier(
notifier_ = notifier;
+#if DCHECK_IS_ON()
+ // If the notifier is not null we expect it to notify us when it is destroyed.
+ waiting_for_context_destroyed_ = !!notifier_;
+#endif
+
if (notifier_)
notifier_->AddContextLifecycleObserver(this);
}
+void ContextLifecycleObserver::NotifyContextDestroyed() {
+#if DCHECK_IS_ON()
+ DCHECK(waiting_for_context_destroyed_);
+ waiting_for_context_destroyed_ = false;
+#endif
+ ContextDestroyed();
+ notifier_ = nullptr;
+}
+
void ContextLifecycleObserver::Trace(Visitor* visitor) const {
visitor->Trace(notifier_);
}
diff --git a/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.h b/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.h
index bc034a9c609..776ccb5cc1b 100644
--- a/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.h
+++ b/chromium/third_party/blink/renderer/platform/context_lifecycle_observer.h
@@ -15,10 +15,8 @@ class ContextLifecycleNotifier;
// ExecutionContext from platform/.
class PLATFORM_EXPORT ContextLifecycleObserver : public GarbageCollectedMixin {
public:
- virtual void ContextDestroyed() = 0;
-
- // Call before clearing an observer list.
- void ObserverSetWillBeCleared();
+ virtual ~ContextLifecycleObserver();
+ void NotifyContextDestroyed();
ContextLifecycleNotifier* GetContextLifecycleNotifier() const {
return notifier_;
@@ -32,8 +30,13 @@ class PLATFORM_EXPORT ContextLifecycleObserver : public GarbageCollectedMixin {
protected:
ContextLifecycleObserver() = default;
+ virtual void ContextDestroyed() = 0;
+
private:
WeakMember<ContextLifecycleNotifier> notifier_;
+#if DCHECK_IS_ON()
+ bool waiting_for_context_destroyed_ = false;
+#endif
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/disk_data_allocator.cc b/chromium/third_party/blink/renderer/platform/disk_data_allocator.cc
index c34e37d4860..ae2a1da085f 100644
--- a/chromium/third_party/blink/renderer/platform/disk_data_allocator.cc
+++ b/chromium/third_party/blink/renderer/platform/disk_data_allocator.cc
@@ -137,8 +137,6 @@ std::unique_ptr<DiskDataMetadata> DiskDataAllocator::Write(const void* data,
}
void DiskDataAllocator::Read(const DiskDataMetadata& metadata, void* data) {
- DCHECK(IsMainThread());
-
// Doesn't need locking as files support concurrent access, and we don't
// update metadata.
char* data_char = reinterpret_cast<char*>(data);
diff --git a/chromium/third_party/blink/renderer/platform/disk_data_allocator.h b/chromium/third_party/blink/renderer/platform/disk_data_allocator.h
index fb80874988e..7b13a5562f3 100644
--- a/chromium/third_party/blink/renderer/platform/disk_data_allocator.h
+++ b/chromium/third_party/blink/renderer/platform/disk_data_allocator.h
@@ -28,8 +28,7 @@ class DiskDataMetadata;
// available.
//
// Threading:
-// - Reads must be done from the main thread
-// - Writes can be done from any thread.
+// - Reads and writes can be done from any thread.
// - public methods are thread-safe, and unless otherwise noted, can be called
// from any thread.
class PLATFORM_EXPORT DiskDataAllocator : public mojom::blink::DiskAllocator {
@@ -47,14 +46,16 @@ class PLATFORM_EXPORT DiskDataAllocator : public mojom::blink::DiskAllocator {
std::unique_ptr<DiskDataMetadata> Write(const void* data, size_t size);
// Reads data. A read failure is fatal.
- // Must be called from the main thread.
+ // Caller must make sure that this is not called at the same time as
+ // |Discard()|.
// Can be called at any time before |Discard()| destroys |metadata|.
//
// |data| must point to an area large enough to fit a |metadata.size|-ed
// array. Note that this performs a blocking disk read.
void Read(const DiskDataMetadata& metadata, void* data);
- // Discards existing data pointed at by |metadata|.
+ // Discards existing data pointed at by |metadata|. Caller must make sure this
+ // is not called while the same file is being read.
void Discard(std::unique_ptr<DiskDataMetadata> metadata);
~DiskDataAllocator() override;
diff --git a/chromium/third_party/blink/renderer/platform/disk_data_metadata.h b/chromium/third_party/blink/renderer/platform/disk_data_metadata.h
index 7c66cff4773..94d62b3f7a5 100644
--- a/chromium/third_party/blink/renderer/platform/disk_data_metadata.h
+++ b/chromium/third_party/blink/renderer/platform/disk_data_metadata.h
@@ -14,12 +14,12 @@ class DiskDataMetadata {
public:
int64_t start_offset() const { return start_offset_; }
size_t size() const { return size_; }
- DiskDataMetadata(DiskDataMetadata&& other) = delete;
private:
DiskDataMetadata(int64_t start_offset, size_t size)
: start_offset_(start_offset), size_(size) {}
DiskDataMetadata(const DiskDataMetadata& other) = default;
+ DiskDataMetadata(DiskDataMetadata&& other) = default;
DiskDataMetadata& operator=(const DiskDataMetadata& other) = default;
int64_t start_offset_;
diff --git a/chromium/third_party/blink/renderer/platform/exported/file_path_conversion.cc b/chromium/third_party/blink/renderer/platform/exported/file_path_conversion.cc
index c4b7999726b..134bb1adc43 100644
--- a/chromium/third_party/blink/renderer/platform/exported/file_path_conversion.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/file_path_conversion.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "base/files/file_path.h"
+#include "base/i18n/uchar.h"
#include "build/build_config.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
@@ -17,8 +18,8 @@ base::FilePath StringToFilePath(const String& str) {
return base::FilePath();
if (!str.Is8Bit()) {
- return base::FilePath::FromUTF16Unsafe(
- base::StringPiece16(str.Characters16(), str.length()));
+ return base::FilePath::FromUTF16Unsafe(base::StringPiece16(
+ base::i18n::ToChar16Ptr(str.Characters16()), str.length()));
}
#if defined(OS_POSIX)
diff --git a/chromium/third_party/blink/renderer/platform/exported/impression_conversions.cc b/chromium/third_party/blink/renderer/platform/exported/impression_conversions.cc
new file mode 100644
index 00000000000..2baa2c64820
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/exported/impression_conversions.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/public/platform/impression_conversions.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_string.h"
+
+namespace blink {
+
+blink::Impression ConvertWebImpressionToImpression(
+ const blink::WebImpression& web_impression) {
+ blink::Impression result;
+
+ result.impression_data = web_impression.impression_data;
+ result.expiry = web_impression.expiry;
+ result.reporting_origin = web_impression.reporting_origin;
+ result.conversion_destination = web_impression.conversion_destination;
+
+ return result;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA b/chromium/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA
new file mode 100644
index 00000000000..02d2785a62c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>GetUserMedia"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/exported/mediastream/OWNERS b/chromium/third_party/blink/renderer/platform/exported/mediastream/OWNERS
index 32889ccc574..b99ae052002 100644
--- a/chromium/third_party/blink/renderer/platform/exported/mediastream/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/exported/mediastream/OWNERS
@@ -1,6 +1,3 @@
file://third_party/blink/common/mediastream/OWNERS
per-file media_stream_audio_processor*=aluebs@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/renderer/platform/exported/platform.cc b/chromium/third_party/blink/renderer/platform/exported/platform.cc
index ff270b6e572..42166716137 100644
--- a/chromium/third_party/blink/renderer/platform/exported/platform.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/platform.cc
@@ -47,6 +47,7 @@
#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
#include "third_party/blink/renderer/platform/fonts/font_cache_memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image_manager.h"
#include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
#include "third_party/blink/renderer/platform/heap/gc_task_runner.h"
#include "third_party/blink/renderer/platform/heap/process_heap.h"
@@ -239,6 +240,9 @@ void Platform::InitializeMainThreadCommon(Platform* platform,
ParkableStringManagerDumpProvider::Instance(), "ParkableStrings",
base::ThreadTaskRunnerHandle::Get());
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ &ParkableImageManager::Instance(), "ParkableImages",
+ base::ThreadTaskRunnerHandle::Get());
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
CanvasMemoryDumpProvider::Instance(), "Canvas",
base::ThreadTaskRunnerHandle::Get());
diff --git a/chromium/third_party/blink/renderer/platform/exported/sync_load_response.cc b/chromium/third_party/blink/renderer/platform/exported/sync_load_response.cc
deleted file mode 100644
index 45e2064f223..00000000000
--- a/chromium/third_party/blink/renderer/platform/exported/sync_load_response.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/public/platform/sync_load_response.h"
-
-namespace blink {
-
-SyncLoadResponse::SyncLoadResponse() = default;
-
-SyncLoadResponse::SyncLoadResponse(SyncLoadResponse&& other) = default;
-
-SyncLoadResponse::~SyncLoadResponse() = default;
-
-SyncLoadResponse& SyncLoadResponse::operator=(SyncLoadResponse&& other) =
- default;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/url_conversion.cc b/chromium/third_party/blink/renderer/platform/exported/url_conversion.cc
index 4b149343d90..b6ab467b8b4 100644
--- a/chromium/third_party/blink/renderer/platform/exported/url_conversion.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/url_conversion.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/public/platform/url_conversion.h"
+#include "base/i18n/uchar.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -23,7 +24,8 @@ GURL WebStringToGURL(const WebString& web_string) {
}
// GURL can consume UTF-16 directly.
- return GURL(base::StringPiece16(str.Characters16(), str.length()));
+ return GURL(base::StringPiece16(base::i18n::ToChar16Ptr(str.Characters16()),
+ str.length()));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc b/chromium/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
index e761ce042ed..d1b878b4a78 100644
--- a/chromium/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
@@ -196,8 +196,9 @@ class VideoCaptureImplManagerTest : public ::testing::Test,
run_loop.Run();
}
- MOCK_METHOD2(OnFrameReady,
+ MOCK_METHOD3(OnFrameReady,
void(scoped_refptr<media::VideoFrame>,
+ std::vector<scoped_refptr<media::VideoFrame>>,
base::TimeTicks estimated_capture_time));
MOCK_METHOD1(OnStarted, void(const media::VideoCaptureSessionId& id));
MOCK_METHOD1(OnStopped, void(const media::VideoCaptureSessionId& id));
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_back_forward_cache_loader_helper.cc b/chromium/third_party/blink/renderer/platform/exported/web_back_forward_cache_loader_helper.cc
new file mode 100644
index 00000000000..fee80d90d02
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/exported/web_back_forward_cache_loader_helper.cc
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
+
+namespace blink {
+
+WebBackForwardCacheLoaderHelper::WebBackForwardCacheLoaderHelper(
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper)
+ : private_(back_forward_cache_loader_helper) {}
+
+void WebBackForwardCacheLoaderHelper::Reset() {
+ private_.Reset();
+}
+
+void WebBackForwardCacheLoaderHelper::Assign(
+ const WebBackForwardCacheLoaderHelper& other) {
+ private_ = other.private_;
+}
+
+BackForwardCacheLoaderHelper*
+WebBackForwardCacheLoaderHelper::GetBackForwardCacheLoaderHelper() const {
+ if (!private_)
+ return nullptr;
+ return private_.Get();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_font.cc b/chromium/third_party/blink/renderer/platform/exported/web_font.cc
index 26382685aa5..9b56a858bb3 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_font.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_font.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/public/platform/web_font.h"
#include "third_party/blink/public/platform/web_font_description.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_text_run.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_memory_pressure_listener.cc b/chromium/third_party/blink/renderer/platform/exported/web_memory_pressure_listener.cc
index a2dac148366..7e39dbf87b7 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_memory_pressure_listener.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_memory_pressure_listener.cc
@@ -9,7 +9,7 @@
namespace blink {
void WebMemoryPressureListener::OnMemoryPressure(
- WebMemoryPressureLevel pressure_level) {
+ base::MemoryPressureListener::MemoryPressureLevel pressure_level) {
MemoryPressureListenerRegistry::Instance().OnMemoryPressure(pressure_level);
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_mixed_content.cc b/chromium/third_party/blink/renderer/platform/exported/web_mixed_content.cc
deleted file mode 100644
index ea0a828186f..00000000000
--- a/chromium/third_party/blink/renderer/platform/exported/web_mixed_content.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 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/public/platform/web_mixed_content.h"
-
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-
-namespace blink {
-
-// static
-WebMixedContentContextType WebMixedContent::ContextTypeFromRequestContext(
- mojom::blink::RequestContextType context,
- WebMixedContent::CheckModeForPlugin check_mode_for_plugin) {
- switch (context) {
- // "Optionally-blockable" mixed content
- case mojom::blink::RequestContextType::AUDIO:
- case mojom::blink::RequestContextType::IMAGE:
- case mojom::blink::RequestContextType::VIDEO:
- return WebMixedContentContextType::kOptionallyBlockable;
-
- // Plugins! Oh how dearly we love plugin-loaded content!
- case mojom::blink::RequestContextType::PLUGIN: {
- return check_mode_for_plugin ==
- WebMixedContent::CheckModeForPlugin::kStrict
- ? WebMixedContentContextType::kBlockable
- : WebMixedContentContextType::kOptionallyBlockable;
- }
-
- // "Blockable" mixed content
- case mojom::blink::RequestContextType::BEACON:
- case mojom::blink::RequestContextType::CSP_REPORT:
- case mojom::blink::RequestContextType::EMBED:
- case mojom::blink::RequestContextType::EVENT_SOURCE:
- case mojom::blink::RequestContextType::FAVICON:
- case mojom::blink::RequestContextType::FETCH:
- case mojom::blink::RequestContextType::FONT:
- case mojom::blink::RequestContextType::FORM:
- case mojom::blink::RequestContextType::FRAME:
- case mojom::blink::RequestContextType::HYPERLINK:
- case mojom::blink::RequestContextType::IFRAME:
- case mojom::blink::RequestContextType::IMAGE_SET:
- case mojom::blink::RequestContextType::IMPORT:
- case mojom::blink::RequestContextType::INTERNAL:
- case mojom::blink::RequestContextType::LOCATION:
- case mojom::blink::RequestContextType::MANIFEST:
- case mojom::blink::RequestContextType::OBJECT:
- case mojom::blink::RequestContextType::PING:
- case mojom::blink::RequestContextType::PREFETCH:
- case mojom::blink::RequestContextType::SCRIPT:
- case mojom::blink::RequestContextType::SERVICE_WORKER:
- case mojom::blink::RequestContextType::SHARED_WORKER:
- case mojom::blink::RequestContextType::STYLE:
- case mojom::blink::RequestContextType::SUBRESOURCE:
- case mojom::blink::RequestContextType::TRACK:
- case mojom::blink::RequestContextType::WORKER:
- case mojom::blink::RequestContextType::XML_HTTP_REQUEST:
- case mojom::blink::RequestContextType::XSLT:
- return WebMixedContentContextType::kBlockable;
-
- // FIXME: Contexts that we should block, but don't currently.
- // https://crbug.com/388650
- case mojom::blink::RequestContextType::DOWNLOAD:
- return WebMixedContentContextType::kShouldBeBlockable;
-
- case mojom::blink::RequestContextType::UNSPECIFIED:
- NOTREACHED();
- }
- NOTREACHED();
- return WebMixedContentContextType::kBlockable;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index a601b843db6..674b14492c0 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -50,6 +50,10 @@ void WebRuntimeFeatures::EnableBrowserVerifiedUserActivationMouse(bool enable) {
RuntimeEnabledFeatures::SetBrowserVerifiedUserActivationMouseEnabled(enable);
}
+void WebRuntimeFeatures::EnableCapabilityDelegationPaymentRequest(bool enable) {
+ RuntimeEnabledFeatures::SetCapabilityDelegationPaymentRequestEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableClickPointerEvent(bool enable) {
RuntimeEnabledFeatures::SetClickPointerEventEnabled(enable);
}
@@ -68,6 +72,14 @@ void WebRuntimeFeatures::EnableWebBluetoothRemoteCharacteristicNewWriteValue(
SetWebBluetoothRemoteCharacteristicNewWriteValueEnabled(enable);
}
+void WebRuntimeFeatures::EnableCompositeBGColorAnimation(bool enable) {
+ RuntimeEnabledFeatures::SetCompositeBGColorAnimationEnabled(enable);
+}
+
+void WebRuntimeFeatures::EnableCompositeRelativeKeyframes(bool enable) {
+ RuntimeEnabledFeatures::SetCompositeRelativeKeyframesEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableWebNfc(bool enable) {
RuntimeEnabledFeatures::SetWebNFCEnabled(enable);
}
@@ -97,10 +109,18 @@ void WebRuntimeFeatures::EnableOriginTrialControlledFeatures(bool enable) {
RuntimeEnabledFeatures::SetOriginTrialControlledFeaturesEnabled(enable);
}
+void WebRuntimeFeatures::EnableAOMAriaRelationshipProperties(bool enable) {
+ RuntimeEnabledFeatures::SetAOMAriaRelationshipPropertiesEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableAccelerated2dCanvas(bool enable) {
RuntimeEnabledFeatures::SetAccelerated2dCanvasEnabled(enable);
}
+void WebRuntimeFeatures::EnableAccessibilityAriaVirtualContent(bool enable) {
+ RuntimeEnabledFeatures::SetAccessibilityAriaVirtualContentEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableAccessibilityExposeDisplayNone(bool enable) {
RuntimeEnabledFeatures::SetAccessibilityExposeDisplayNoneEnabled(enable);
}
@@ -171,6 +191,10 @@ void WebRuntimeFeatures::EnableScrollTopLeftInterop(bool enable) {
RuntimeEnabledFeatures::SetScrollTopLeftInteropEnabled(enable);
}
+void WebRuntimeFeatures::EnableKeyboardAccessibleTooltip(bool enable) {
+ RuntimeEnabledFeatures::SetKeyboardAccessibleTooltipEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableKeyboardFocusableScrollers(bool enable) {
RuntimeEnabledFeatures::SetKeyboardFocusableScrollersEnabled(enable);
}
@@ -187,10 +211,6 @@ void WebRuntimeFeatures::EnableDecodeLossyWebPImagesToYUV(bool enable) {
RuntimeEnabledFeatures::SetDecodeLossyWebPImagesToYUVEnabled(enable);
}
-void WebRuntimeFeatures::EnableFeaturePolicyForSandbox(bool enable) {
- RuntimeEnabledFeatures::SetFeaturePolicyForSandboxEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableFileSystem(bool enable) {
RuntimeEnabledFeatures::SetFileSystemEnabled(enable);
}
@@ -345,6 +365,10 @@ void WebRuntimeFeatures::EnableTextFragmentAnchor(bool enable) {
RuntimeEnabledFeatures::SetTextFragmentIdentifiersEnabled(enable);
}
+void WebRuntimeFeatures::EnableTextFragmentColorChange(bool enable) {
+ RuntimeEnabledFeatures::SetTextFragmentColorChangeEnabled(enable);
+}
+
void WebRuntimeFeatures::EnablePreciseMemoryInfo(bool enable) {
RuntimeEnabledFeatures::SetPreciseMemoryInfoEnabled(enable);
}
@@ -393,6 +417,10 @@ void WebRuntimeFeatures::EnableWebXRDepth(bool enable) {
RuntimeEnabledFeatures::SetWebXRDepthEnabled(enable);
}
+void WebRuntimeFeatures::EnableWebXRHandInput(bool enable) {
+ RuntimeEnabledFeatures::SetWebXRHandInputEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableWebXRHitTest(bool enable) {
RuntimeEnabledFeatures::SetWebXRHitTestEnabled(enable);
}
@@ -485,6 +513,10 @@ void WebRuntimeFeatures::EnableWebAuthenticationGetAssertionFeaturePolicy(
enable);
}
+void WebRuntimeFeatures::EnableWebOTPAssertionFeaturePolicy(bool enable) {
+ RuntimeEnabledFeatures::SetWebOTPAssertionFeaturePolicyEnabled(enable);
+}
+
void WebRuntimeFeatures::EnableLazyInitializeMediaControls(bool enable) {
RuntimeEnabledFeatures::SetLazyInitializeMediaControlsEnabled(enable);
}
@@ -499,10 +531,6 @@ void WebRuntimeFeatures::EnableAutomationControlled(bool enable) {
RuntimeEnabledFeatures::SetAutomationControlledEnabled(enable);
}
-void WebRuntimeFeatures::EnableExperimentalProductivityFeatures(bool enable) {
- RuntimeEnabledFeatures::SetExperimentalProductivityFeaturesEnabled(enable);
-}
-
void WebRuntimeFeatures::EnableDisallowDocumentAccess(bool enable) {
RuntimeEnabledFeatures::SetDisallowDocumentAccessEnabled(enable);
}
@@ -543,14 +571,6 @@ void WebRuntimeFeatures::EnableAllowSyncXHRInPageDismissal(bool enable) {
RuntimeEnabledFeatures::SetAllowSyncXHRInPageDismissalEnabled(enable);
}
-void WebRuntimeFeatures::EnableShadowDOMV0(bool enable) {
- RuntimeEnabledFeatures::SetShadowDOMV0Enabled(enable);
-}
-
-void WebRuntimeFeatures::EnableCustomElementsV0(bool enable) {
- RuntimeEnabledFeatures::SetCustomElementsV0Enabled(enable);
-}
-
void WebRuntimeFeatures::EnableHTMLImports(bool enable) {
RuntimeEnabledFeatures::SetHTMLImportsEnabled(enable);
}
@@ -647,4 +667,8 @@ void WebRuntimeFeatures::EnableTargetBlankImpliesNoOpener(bool enable) {
RuntimeEnabledFeatures::SetTargetBlankImpliesNoOpenerEnabled(enable);
}
+void WebRuntimeFeatures::EnableCSSColorSchemeUARendering(bool enable) {
+ RuntimeEnabledFeatures::SetCSSColorSchemeUARenderingEnabled(enable);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_security_origin.cc b/chromium/third_party/blink/renderer/platform/exported/web_security_origin.cc
index 52e70dcb30d..5f739c17a9f 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_security_origin.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_security_origin.cc
@@ -72,11 +72,6 @@ uint16_t WebSecurityOrigin::Port() const {
return private_->Port();
}
-uint16_t WebSecurityOrigin::EffectivePort() const {
- DCHECK(private_);
- return private_->EffectivePort();
-}
-
bool WebSecurityOrigin::IsOpaque() const {
DCHECK(private_);
return private_->IsOpaque();
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_string.cc b/chromium/third_party/blink/renderer/platform/exported/web_string.cc
index a18a5810de2..d0d721f0f86 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_string.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_string.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/public/platform/web_string.h"
+#include "base/i18n/uchar.h"
#include "base/strings/string_util.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h"
@@ -56,7 +57,8 @@ WebString& WebString::operator=(const WebString&) = default;
WebString& WebString::operator=(WebString&&) = default;
WebString::WebString(const WebUChar* data, size_t len)
- : impl_(StringImpl::Create8BitIfPossible(data, len)) {}
+ : impl_(StringImpl::Create8BitIfPossible(base::i18n::ToUCharPtr(data),
+ len)) {}
void WebString::Reset() {
impl_ = nullptr;
@@ -75,7 +77,8 @@ const WebLChar* WebString::Data8() const {
}
const WebUChar* WebString::Data16() const {
- return impl_ && !Is8Bit() ? impl_->Characters16() : nullptr;
+ return impl_ && !Is8Bit() ? base::i18n::ToChar16Ptr(impl_->Characters16())
+ : nullptr;
}
std::string WebString::Utf8(UTF8ConversionMode mode) const {
@@ -132,6 +135,12 @@ WebString WebString::FromASCII(const std::string& s) {
return FromLatin1(s);
}
+WebString WebString::IsolatedCopy() const {
+ if (!impl_)
+ return WebString();
+ return String(impl_).IsolatedCopy();
+}
+
bool WebString::Equals(const WebString& s) const {
return Equal(impl_.get(), s.impl_.get());
}
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_string_test.cc b/chromium/third_party/blink/renderer/platform/exported/web_string_test.cc
index 6453629b1d4..8404703cc1e 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_string_test.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_string_test.cc
@@ -11,7 +11,7 @@ namespace blink {
TEST(WebStringTest, UTF8ConversionRoundTrip) {
// Valid characters.
- for (UChar uchar = 0; uchar <= 0xD7FF; ++uchar) {
+ for (WebUChar uchar = 0; uchar <= 0xD7FF; ++uchar) {
WebString utf16_string(&uchar, 1);
std::string utf8_string(utf16_string.Utf8());
WebString utf16_new_string =
@@ -21,7 +21,7 @@ TEST(WebStringTest, UTF8ConversionRoundTrip) {
}
// Unpaired surrogates.
- for (UChar uchar = 0xD800; uchar <= 0xDFFF; ++uchar) {
+ for (WebUChar uchar = 0xD800; uchar <= 0xDFFF; ++uchar) {
WebString utf16_string(&uchar, 1);
// Conversion with Strict mode results in an empty string.
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
index 986f0e80cca..3cb65f6dbb9 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_request.cc
@@ -347,6 +347,14 @@ void WebURLRequest::SetMode(network::mojom::RequestMode mode) {
return resource_request_->SetMode(mode);
}
+bool WebURLRequest::GetFavicon() const {
+ return resource_request_->IsFavicon();
+}
+
+void WebURLRequest::SetFavicon(bool) {
+ resource_request_->SetFavicon(true);
+}
+
network::mojom::CredentialsMode WebURLRequest::GetCredentialsMode() const {
return resource_request_->GetCredentialsMode();
}
@@ -548,6 +556,20 @@ network::OptionalTrustTokenParams WebURLRequest::TrustTokenParams() const {
return ConvertTrustTokenParams(resource_request_->TrustTokenParams());
}
+base::Optional<WebURL> WebURLRequest::WebBundleUrl() const {
+ if (resource_request_->GetWebBundleTokenParams()) {
+ return resource_request_->GetWebBundleTokenParams()->bundle_url;
+ }
+ return base::nullopt;
+}
+
+base::Optional<base::UnguessableToken> WebURLRequest::WebBundleToken() const {
+ if (resource_request_->GetWebBundleTokenParams()) {
+ return resource_request_->GetWebBundleTokenParams()->token;
+ }
+ return base::nullopt;
+}
+
WebURLRequest::WebURLRequest(ResourceRequest& r) : resource_request_(&r) {}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
index 3f3efff75b0..cc9704050b9 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -374,6 +374,14 @@ network::mojom::FetchResponseType WebURLResponse::GetType() const {
return resource_response_->GetType();
}
+void WebURLResponse::SetPadding(int64_t padding) {
+ resource_response_->SetPadding(padding);
+}
+
+int64_t WebURLResponse::GetPadding() const {
+ return resource_response_->GetPadding();
+}
+
void WebURLResponse::SetUrlListViaServiceWorker(
const WebVector<WebURL>& url_list_via_service_worker) {
Vector<KURL> url_list(url_list_via_service_worker.size());
@@ -510,6 +518,31 @@ bool WebURLResponse::FromArchive() const {
return resource_response_->FromArchive();
}
+void WebURLResponse::SetDnsAliases(const WebVector<WebString>& aliases) {
+ Vector<String> dns_aliases(aliases.size());
+ std::transform(aliases.begin(), aliases.end(), dns_aliases.begin(),
+ [](const WebString& h) { return WTF::String(h); });
+ resource_response_->SetDnsAliases(std::move(dns_aliases));
+}
+
+WebURL WebURLResponse::WebBundleURL() const {
+ return resource_response_->WebBundleURL();
+}
+
+void WebURLResponse::SetWebBundleURL(const WebURL& url) {
+ resource_response_->SetWebBundleURL(url);
+}
+
+void WebURLResponse::SetAuthChallengeInfo(
+ const base::Optional<net::AuthChallengeInfo>& auth_challenge_info) {
+ resource_response_->SetAuthChallengeInfo(auth_challenge_info);
+}
+
+const base::Optional<net::AuthChallengeInfo>&
+WebURLResponse::AuthChallengeInfo() const {
+ return resource_response_->AuthChallengeInfo();
+}
+
WebURLResponse::WebURLResponse(ResourceResponse& r) : resource_response_(&r) {}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
index 5e2ce559a81..74174df4781 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_response_test.cc
@@ -30,8 +30,10 @@
#include "third_party/blink/public/platform/web_url_response.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
@@ -47,4 +49,15 @@ TEST(WebURLResponseTest, NotNullAfterSetURL) {
EXPECT_FALSE(instance.IsNull());
}
+TEST(WebURLResponseTest, DnsAliasesCanBeAccessed) {
+ WebURLResponse instance;
+ instance.SetCurrentRequestUrl(KURL("http://localhost/"));
+ EXPECT_FALSE(instance.IsNull());
+ EXPECT_TRUE(instance.ToResourceResponse().DnsAliases().IsEmpty());
+ WebVector<WebString> aliases({"alias1", "alias2"});
+ instance.SetDnsAliases(aliases);
+ EXPECT_THAT(instance.ToResourceResponse().DnsAliases(),
+ testing::ElementsAre("alias1", "alias2"));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/file_metadata.cc b/chromium/third_party/blink/renderer/platform/file_metadata.cc
index 51d0190b0b9..3dba7ab98f1 100644
--- a/chromium/third_party/blink/renderer/platform/file_metadata.cc
+++ b/chromium/third_party/blink/renderer/platform/file_metadata.cc
@@ -36,27 +36,16 @@
#include "base/optional.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/filename_util.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/mojom/file/file_utilities.mojom-blink.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
-#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
#include "url/gurl.h"
namespace blink {
-namespace {
-
-mojo::Remote<mojom::blink::FileUtilitiesHost>& GetFileUtilitiesHost() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(
- ThreadSpecific<mojo::Remote<mojom::blink::FileUtilitiesHost>>,
- thread_specific_host, ());
- return *thread_specific_host;
-}
-
-} // namespace
-
// static
FileMetadata FileMetadata::From(const base::File::Info& file_info) {
FileMetadata file_metadata;
@@ -70,38 +59,22 @@ FileMetadata FileMetadata::From(const base::File::Info& file_info) {
return file_metadata;
}
-bool GetFileSize(const String& path, int64_t& result) {
+bool GetFileSize(const String& path,
+ const MojoBindingContext& context,
+ int64_t& result) {
FileMetadata metadata;
- if (!GetFileMetadata(path, metadata))
+ if (!GetFileMetadata(path, context, metadata))
return false;
result = metadata.length;
return true;
}
-bool GetFileModificationTime(const String& path,
- base::Optional<base::Time>& result) {
- FileMetadata metadata;
- if (!GetFileMetadata(path, metadata))
- return false;
- result = metadata.modification_time;
- return true;
-}
-
-void RebindFileUtilitiesForTesting() {
- auto& host = GetFileUtilitiesHost();
- if (host) {
- host.Unbind().reset();
- }
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+bool GetFileMetadata(const String& path,
+ const MojoBindingContext& context,
+ FileMetadata& metadata) {
+ mojo::Remote<mojom::blink::FileUtilitiesHost> host;
+ context.GetBrowserInterfaceBroker().GetInterface(
host.BindNewPipeAndPassReceiver());
-}
-
-bool GetFileMetadata(const String& path, FileMetadata& metadata) {
- auto& host = GetFileUtilitiesHost();
- if (!host) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- host.BindNewPipeAndPassReceiver());
- }
base::Optional<base::File::Info> file_info;
if (!host->GetFileInfo(WebStringToFilePath(path), &file_info) || !file_info)
diff --git a/chromium/third_party/blink/renderer/platform/file_metadata.h b/chromium/third_party/blink/renderer/platform/file_metadata.h
index 08c52dd94ef..0e49d3b3293 100644
--- a/chromium/third_party/blink/renderer/platform/file_metadata.h
+++ b/chromium/third_party/blink/renderer/platform/file_metadata.h
@@ -41,37 +41,37 @@
namespace blink {
+class MojoBindingContext;
+
class FileMetadata {
DISALLOW_NEW();
public:
- FileMetadata()
- : modification_time(base::nullopt), length(-1), type(kTypeUnknown) {}
+ FileMetadata() = default;
PLATFORM_EXPORT static FileMetadata From(const base::File::Info& file_info);
// The last modification time of the file.
- base::Optional<base::Time> modification_time;
+ base::Optional<base::Time> modification_time = base::nullopt;
// The length of the file in bytes.
// The value -1 means that the length is not set.
- int64_t length;
+ int64_t length = -1;
enum Type { kTypeUnknown = 0, kTypeFile, kTypeDirectory };
- Type type;
+ Type type = kTypeUnknown;
String platform_path;
};
-PLATFORM_EXPORT bool GetFileSize(const String&, int64_t& result);
-PLATFORM_EXPORT bool GetFileModificationTime(
- const String&,
- base::Optional<base::Time>& result);
-PLATFORM_EXPORT bool GetFileMetadata(const String&, FileMetadata&);
+PLATFORM_EXPORT bool GetFileSize(const String&,
+ const MojoBindingContext&,
+ int64_t& result);
+PLATFORM_EXPORT bool GetFileMetadata(const String&,
+ const MojoBindingContext&,
+ FileMetadata& result);
PLATFORM_EXPORT KURL FilePathToURL(const String&);
-PLATFORM_EXPORT void RebindFileUtilitiesForTesting();
-
inline base::Optional<base::Time> NullableTimeToOptionalTime(base::Time time) {
if (time.is_null())
return base::nullopt;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/OWNERS b/chromium/third_party/blink/renderer/platform/fonts/OWNERS
new file mode 100644
index 00000000000..c0787f405b1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/OWNERS
@@ -0,0 +1,2 @@
+per-file font_matching_metrics.cc=file://third_party/blink/public/common/privacy_budget/OWNERS
+per-file font_matching_metrics.h=file://third_party/blink/public/common/privacy_budget/OWNERS \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h b/chromium/third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h
index 62d6bb25c3f..d081bc5b6e8 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h
@@ -7,7 +7,23 @@
namespace blink {
-enum class CanvasRotationInVertical : char { kRegular, kRotateCanvasUpright };
+enum class CanvasRotationInVertical : char {
+ kRegular = 0,
+ kRotateCanvasUpright = 1,
+ kOblique = 2,
+ kRotateCanvasUprightOblique = 3,
+};
+
+inline bool IsCanvasRotationInVerticalUpright(CanvasRotationInVertical r) {
+ return static_cast<char>(r) &
+ static_cast<char>(CanvasRotationInVertical::kRotateCanvasUpright);
+}
+
+inline bool IsCanvasRotationOblque(CanvasRotationInVertical r) {
+ return static_cast<char>(r) &
+ static_cast<char>(CanvasRotationInVertical::kOblique);
}
+} // namespace blink
+
#endif
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font.cc b/chromium/third_party/blink/renderer/platform/fonts/font.cc
index 9f59ca8fa1b..e30fba0db66 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font.cc
@@ -60,11 +60,6 @@ FontFallbackMap& GetFontFallbackMap(FontSelector* font_selector) {
scoped_refptr<FontFallbackList> GetOrCreateFontFallbackList(
const FontDescription& font_description,
FontSelector* font_selector) {
- if (!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled()) {
- return FontFallbackList::Create(font_selector);
- }
-
return GetFontFallbackMap(font_selector).Get(font_description);
}
@@ -101,9 +96,8 @@ Font::~Font() {
// should clear the entry from FontFallbackMap.
// Note that we must not persist a FontFallbackList reference outside Font.
void Font::ReleaseFontFallbackListRef() const {
- if (!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled() ||
- !font_fallback_list_ || !font_fallback_list_->IsValid()) {
+ if (!font_fallback_list_ || !font_fallback_list_->IsValid() ||
+ !font_fallback_list_->HasFontFallbackMap()) {
font_fallback_list_.reset();
return;
}
@@ -113,18 +107,13 @@ void Font::ReleaseFontFallbackListRef() const {
CHECK(!list_ref.HasOneRef());
font_fallback_list_.reset();
if (list_ref.HasOneRef())
- GetFontFallbackMap(list_ref.GetFontSelector()).Remove(font_description_);
+ list_ref.GetFontFallbackMap().Remove(font_description_);
}
void Font::RevalidateFontFallbackList() const {
- if (!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled()) {
- font_fallback_list_->RevalidateDeprecated();
- return;
- }
-
+ DCHECK(font_fallback_list_);
font_fallback_list_ =
- GetFontFallbackMap(GetFontSelector()).Get(font_description_);
+ font_fallback_list_->GetFontFallbackMap().Get(font_description_);
}
FontFallbackList* Font::EnsureFontFallbackList() const {
@@ -138,15 +127,12 @@ FontFallbackList* Font::EnsureFontFallbackList() const {
}
bool Font::operator==(const Font& other) const {
- if (RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled()) {
- // When the feature is enabled, two Font objects with the same
- // FontDescription and FontSelector should always hold reference to the same
- // FontFallbackList object, unless invalidated.
- if (font_fallback_list_ && font_fallback_list_->IsValid() &&
- other.font_fallback_list_ && other.font_fallback_list_->IsValid()) {
- return font_fallback_list_ == other.font_fallback_list_;
- }
+ // Two Font objects with the same FontDescription and FontSelector should
+ // always hold reference to the same FontFallbackList object, unless
+ // invalidated.
+ if (font_fallback_list_ && font_fallback_list_->IsValid() &&
+ other.font_fallback_list_ && other.font_fallback_list_->IsValid()) {
+ return font_fallback_list_ == other.font_fallback_list_;
}
FontSelector* first =
@@ -168,12 +154,45 @@ void DrawBlobs(cc::PaintCanvas* canvas,
for (const auto& blob_info : blobs) {
DCHECK(blob_info.blob);
cc::PaintCanvasAutoRestore auto_restore(canvas, false);
- if (blob_info.rotation == CanvasRotationInVertical::kRotateCanvasUpright) {
- canvas->save();
-
- SkMatrix m;
- m.setSinCos(-1, 0, point.X(), point.Y());
- canvas->concat(m);
+ switch (blob_info.rotation) {
+ case CanvasRotationInVertical::kRegular:
+ break;
+ case CanvasRotationInVertical::kRotateCanvasUpright: {
+ canvas->save();
+
+ SkMatrix m;
+ m.setSinCos(-1, 0, point.X(), point.Y());
+ canvas->concat(m);
+ break;
+ }
+ case CanvasRotationInVertical::kRotateCanvasUprightOblique: {
+ canvas->save();
+
+ SkMatrix m;
+ m.setSinCos(-1, 0, point.X(), point.Y());
+ // TODO(yosin): We should use angle specified in CSS instead of
+ // constant value -15deg.
+ // Note: We draw glyph in right-top corner upper.
+ // See CSS "transform: skew(0, -15deg)"
+ SkMatrix skewY;
+ constexpr SkScalar kSkewY = -0.2679491924311227; // tan(-15deg)
+ skewY.setSkew(0, kSkewY, point.X(), point.Y());
+ m.preConcat(skewY);
+ canvas->concat(m);
+ break;
+ }
+ case CanvasRotationInVertical::kOblique: {
+ // TODO(yosin): We should use angle specified in CSS instead of
+ // constant value 15deg.
+ // Note: We draw glyph in right-top corner upper.
+ // See CSS "transform: skew(0, -15deg)"
+ canvas->save();
+ SkMatrix skewX;
+ constexpr SkScalar kSkewX = 0.2679491924311227; // tan(15deg)
+ skewX.setSkew(kSkewX, 0, point.X(), point.Y());
+ canvas->concat(skewX);
+ break;
+ }
}
if (node_id != cc::kInvalidNodeId) {
canvas->drawTextBlob(blob_info.blob, point.X(), point.Y(), node_id,
@@ -372,7 +391,7 @@ unsigned InterceptsFromBlobs(const ShapeResultBloberizer::BlobBuffer& blobs,
// for a change in font. A TextBlob can contain runs with differing fonts
// and the getTextBlobIntercepts method handles multiple fonts for us. For
// upright in vertical blobs we currently have to bail, see crbug.com/655154
- if (blob_info.rotation == CanvasRotationInVertical::kRotateCanvasUpright)
+ if (IsCanvasRotationInVerticalUpright(blob_info.rotation))
continue;
SkScalar* offset_intercepts_buffer = nullptr;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
index 20b35c9ecba..df794d75c13 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc
@@ -416,7 +416,7 @@ void FontCache::AddClient(FontCacheClient* client) {
if (!font_cache_clients_) {
font_cache_clients_ =
MakeGarbageCollected<HeapHashSet<WeakMember<FontCacheClient>>>();
- font_cache_clients_.RegisterAsStaticReference();
+ LEAK_SANITIZER_IGNORE_OBJECT(&font_cache_clients_);
}
DCHECK(!font_cache_clients_->Contains(client));
font_cache_clients_->insert(client);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
index 0bb9538c341..e87551ae409 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -203,11 +203,11 @@ class PLATFORM_EXPORT FontCache {
static void SetLCDTextEnabled(bool enabled) { lcd_text_enabled_ = enabled; }
static void AddSideloadedFontForTesting(sk_sp<SkTypeface>);
// Functions to cache and retrieve the system font metrics.
- static void SetMenuFontMetrics(const wchar_t* family_name,
+ static void SetMenuFontMetrics(const AtomicString& family_name,
int32_t font_height);
- static void SetSmallCaptionFontMetrics(const wchar_t* family_name,
+ static void SetSmallCaptionFontMetrics(const AtomicString& family_name,
int32_t font_height);
- static void SetStatusFontMetrics(const wchar_t* family_name,
+ static void SetStatusFontMetrics(const AtomicString& family_name,
int32_t font_height);
static int32_t MenuFontHeight() { return menu_font_height_; }
static const AtomicString& MenuFontFamily() {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
index 4b2592ef34e..e733fab4702 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc
@@ -372,6 +372,31 @@ unsigned FontDescription::GetHash() const {
return hash;
}
+void FontDescription::SetOrientation(FontOrientation orientation) {
+ fields_.orientation_ = static_cast<unsigned>(orientation);
+ UpdateSyntheticOblique();
+}
+
+void FontDescription::SetStyle(FontSelectionValue value) {
+ font_selection_request_.slope = value;
+ original_slope = value;
+ UpdateSyntheticOblique();
+}
+
+void FontDescription::UpdateSyntheticOblique() {
+ // Doing synthetic oblique for vertical writing mode with upright text
+ // orientation when negative angle parameter of "oblique" keyword, e.g.
+ // "font-style: oblique -15deg" for simulating "tts:fontShear"[1][2], we
+ // need to have normal font style instead of italic/oblique.
+ // [1]
+ // https://www.w3.org/TR/2018/REC-ttml2-20181108/#style-attribute-fontShear
+ // [2] See http://crbug.com/1112923
+ fields_.synthetic_oblique_ =
+ IsVerticalAnyUpright() && original_slope < FontSelectionValue(0);
+ font_selection_request_.slope =
+ fields_.synthetic_oblique_ ? NormalSlopeValue() : original_slope;
+}
+
SkFontStyle FontDescription::SkiaFontStyle() const {
// FIXME(drott): This is a lossy conversion, compare
// https://bugs.chromium.org/p/skia/issues/detail?id=6844
@@ -475,6 +500,18 @@ String FontDescription::ToString(GenericFamilyType familyType) {
return "Unknown";
}
+String FontDescription::ToString(LigaturesState state) {
+ switch (state) {
+ case LigaturesState::kNormalLigaturesState:
+ return "Normal";
+ case LigaturesState::kDisabledLigaturesState:
+ return "Disabled";
+ case LigaturesState::kEnabledLigaturesState:
+ return "Enabled";
+ }
+ return "Unknown";
+}
+
String FontDescription::ToString(Kerning kerning) {
switch (kerning) {
case Kerning::kAutoKerning:
@@ -487,15 +524,26 @@ String FontDescription::ToString(Kerning kerning) {
return "Unknown";
}
-String FontDescription::ToString(LigaturesState state) {
- switch (state) {
- case LigaturesState::kNormalLigaturesState:
- return "Normal";
- case LigaturesState::kDisabledLigaturesState:
- return "Disabled";
- case LigaturesState::kEnabledLigaturesState:
- return "Enabled";
- }
+String FontDescription::ToString(FontSelectionValue selection_value) {
+ if (selection_value == UltraCondensedWidthValue())
+ return "Ultra-Condensed";
+ else if (selection_value == ExtraCondensedWidthValue())
+ return "Extra-Condensed";
+ else if (selection_value == CondensedWidthValue())
+ return "Condensed";
+ else if (selection_value == SemiCondensedWidthValue())
+ return "Semi-Condensed";
+ else if (selection_value == NormalWidthValue())
+ return "Normal";
+ else if (selection_value == SemiExpandedWidthValue())
+ return "Semi-Expanded";
+ else if (selection_value == ExpandedWidthValue())
+ return "Expanded";
+ else if (selection_value == ExtraExpandedWidthValue())
+ return "Extra-Expanded";
+ else if (selection_value == UltraExpandedWidthValue())
+ return "Ultra-Expanded";
+
return "Unknown";
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.h b/chromium/third_party/blink/renderer/platform/fonts/font_description.h
index ffb0d7c8b4a..a0b9c3aed53 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_description.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.h
@@ -73,9 +73,6 @@ class PLATFORM_EXPORT FontDescription {
};
static String ToString(GenericFamilyType);
- enum Kerning { kAutoKerning, kNormalKerning, kNoneKerning };
- static String ToString(Kerning);
-
enum LigaturesState {
kNormalLigaturesState,
kDisabledLigaturesState,
@@ -83,6 +80,11 @@ class PLATFORM_EXPORT FontDescription {
};
static String ToString(LigaturesState);
+ enum Kerning { kAutoKerning, kNormalKerning, kNoneKerning };
+ static String ToString(Kerning);
+
+ static String ToString(FontSelectionValue);
+
enum FontVariantCaps {
kCapsNormal,
kSmallCaps,
@@ -228,6 +230,7 @@ class PLATFORM_EXPORT FontDescription {
UScriptCode GetScript() const { return LocaleOrDefault().GetScript(); }
bool IsSyntheticBold() const { return fields_.synthetic_bold_; }
bool IsSyntheticItalic() const { return fields_.synthetic_italic_; }
+ bool IsSyntheticOblique() const { return fields_.synthetic_oblique_; }
bool UseSubpixelPositioning() const {
return fields_.subpixel_text_position_;
}
@@ -273,7 +276,7 @@ class PLATFORM_EXPORT FontDescription {
void SetAdjustedSize(float s) { adjusted_size_ = clampTo<float>(s); }
void SetSizeAdjust(float aspect) { size_adjust_ = clampTo<float>(aspect); }
- void SetStyle(FontSelectionValue i) { font_selection_request_.slope = i; }
+ void SetStyle(FontSelectionValue i);
void SetWeight(FontSelectionValue w) { font_selection_request_.weight = w; }
void SetStretch(FontSelectionValue s) { font_selection_request_.width = s; }
@@ -301,9 +304,7 @@ class PLATFORM_EXPORT FontDescription {
fields_.text_rendering_ = rendering;
UpdateTypesettingFeatures();
}
- void SetOrientation(FontOrientation orientation) {
- fields_.orientation_ = static_cast<unsigned>(orientation);
- }
+ void SetOrientation(FontOrientation orientation);
void SetWidthVariant(FontWidthVariant width_variant) {
fields_.width_variant_ = width_variant;
}
@@ -383,6 +384,8 @@ class PLATFORM_EXPORT FontDescription {
String ToString() const;
private:
+ void UpdateSyntheticOblique();
+
FontFamily family_list_; // The list of font families to be used.
scoped_refptr<FontFeatureSettings> feature_settings_;
scoped_refptr<FontVariationSettings> variation_settings_;
@@ -409,6 +412,7 @@ class PLATFORM_EXPORT FontDescription {
// Covers stretch, style, weight.
FontSelectionRequest font_selection_request_;
+ FontSelectionValue original_slope;
struct BitFields {
DISALLOW_NEW();
@@ -443,6 +447,7 @@ class PLATFORM_EXPORT FontDescription {
unsigned text_rendering_ : 2; // TextRenderingMode
unsigned synthetic_bold_ : 1;
unsigned synthetic_italic_ : 1;
+ unsigned synthetic_oblique_ : 1;
unsigned subpixel_text_position_ : 1;
unsigned typesetting_features_ : 3;
unsigned variant_numeric_ : 8;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
index c3ead92ddc9..a759bfdc53d 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
@@ -33,16 +33,16 @@
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/font_cache_key.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
+#include "third_party/blink/renderer/platform/fonts/font_fallback_map.h"
#include "third_party/blink/renderer/platform/fonts/font_family.h"
#include "third_party/blink/renderer/platform/fonts/segmented_font_data.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
namespace blink {
-FontFallbackList::FontFallbackList(FontSelector* font_selector)
+FontFallbackList::FontFallbackList(FontFallbackMap& font_fallback_map)
: cached_primary_simple_font_data_(nullptr),
- font_selector_(font_selector),
- font_selector_version_(font_selector ? font_selector->Version() : 0),
+ font_fallback_map_(font_fallback_map),
family_index_(0),
generation_(FontCache::GetFontCache()->Generation()),
has_loading_fallback_(false),
@@ -52,20 +52,15 @@ FontFallbackList::FontFallbackList(FontSelector* font_selector)
can_shape_word_by_word_computed_(false),
is_invalid_(false) {}
-void FontFallbackList::RevalidateDeprecated() {
- DCHECK(!RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled());
+FontFallbackList::~FontFallbackList() {
ReleaseFontData();
- font_list_.clear();
- cached_primary_simple_font_data_ = nullptr;
- family_index_ = 0;
- has_loading_fallback_ = false;
- has_custom_font_ = false;
- has_advance_override_ = false;
- can_shape_word_by_word_ = false;
- can_shape_word_by_word_computed_ = false;
- font_selector_version_ = font_selector_ ? font_selector_->Version() : 0;
- generation_ = FontCache::GetFontCache()->Generation();
+}
+
+FontSelector* FontFallbackList::GetFontSelector() const {
+ // FontFallbackList objects are managed in FontFallbackMap, and should not be
+ // used after FontFallbackMap is destroyed.
+ DCHECK(font_fallback_map_);
+ return font_fallback_map_->GetFontSelector();
}
void FontFallbackList::ReleaseFontData() {
@@ -83,8 +78,7 @@ void FontFallbackList::ReleaseFontData() {
bool FontFallbackList::ShouldSkipDrawing() const {
// The DCHECK hit will be fixed by the runtime enabled feature below, so we
// don't fix it in the legacy code paths.
- DCHECK(IsValid() || !RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled());
+ DCHECK(IsValid());
if (!has_loading_fallback_)
return false;
@@ -159,36 +153,37 @@ scoped_refptr<FontData> FontFallbackList::GetFontData(
family_index_++;
if (curr_family->Family().length()) {
scoped_refptr<FontData> result;
- if (font_selector_)
- result = font_selector_->GetFontData(font_description,
- curr_family->Family());
+ if (GetFontSelector()) {
+ result = GetFontSelector()->GetFontData(font_description,
+ curr_family->Family());
+ }
if (!result) {
result = FontCache::GetFontCache()->GetFontData(font_description,
curr_family->Family());
- if (font_selector_) {
- font_selector_->ReportFontLookupByUniqueOrFamilyName(
+ if (GetFontSelector()) {
+ GetFontSelector()->ReportFontLookupByUniqueOrFamilyName(
curr_family->Family(), font_description,
DynamicTo<SimpleFontData>(result.get()));
}
}
if (result) {
- if (font_selector_) {
- font_selector_->ReportSuccessfulFontFamilyMatch(
+ if (GetFontSelector()) {
+ GetFontSelector()->ReportSuccessfulFontFamilyMatch(
curr_family->Family());
}
return result;
}
- if (font_selector_)
- font_selector_->ReportFailedFontFamilyMatch(curr_family->Family());
+ if (GetFontSelector())
+ GetFontSelector()->ReportFailedFontFamilyMatch(curr_family->Family());
}
}
family_index_ = kCAllFamiliesScanned;
- if (font_selector_) {
+ if (GetFontSelector()) {
// Try the user's preferred standard font.
- if (scoped_refptr<FontData> data = font_selector_->GetFontData(
+ if (scoped_refptr<FontData> data = GetFontSelector()->GetFontData(
font_description, font_family_names::kWebkitStandard))
return data;
}
@@ -196,9 +191,9 @@ scoped_refptr<FontData> FontFallbackList::GetFontData(
// Still no result. Hand back our last resort fallback font.
auto last_resort =
FontCache::GetFontCache()->GetLastResortFallbackFont(font_description);
- if (font_selector_) {
- font_selector_->ReportLastResortFallbackFontLookup(font_description,
- last_resort.get());
+ if (GetFontSelector()) {
+ GetFontSelector()->ReportLastResortFallbackFontLookup(font_description,
+ last_resort.get());
}
return last_resort;
}
@@ -212,9 +207,10 @@ FallbackListCompositeKey FontFallbackList::CompositeKey(
FontFaceCreationParams params(
AdjustFamilyNameToAvoidUnsupportedFonts(current_family->Family()));
scoped_refptr<FontData> result;
- if (font_selector_)
- result = font_selector_->GetFontData(font_description,
- current_family->Family());
+ if (GetFontSelector()) {
+ result = GetFontSelector()->GetFontData(font_description,
+ current_family->Family());
+ }
if (!result) {
if (FontPlatformData* platform_data =
FontCache::GetFontCache()->GetFontPlatformData(font_description,
@@ -291,19 +287,4 @@ bool FontFallbackList::CanShapeWordByWord(
return can_shape_word_by_word_;
}
-bool FontFallbackList::IsValid() const {
- if (RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled()) {
- return !is_invalid_;
- }
-
- // The flag can be set only when the feature above is enabled.
- DCHECK(!is_invalid_);
-
- if (!font_selector_)
- return font_selector_version_ == 0;
-
- return font_selector_->Version() == font_selector_version_;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h
index 4d73745b488..684d089aaba 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h
@@ -36,6 +36,7 @@
namespace blink {
class FontDescription;
+class FontFallbackMap;
const int kCAllFamiliesScanned = -1;
@@ -46,36 +47,32 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> {
USING_FAST_MALLOC(FontFallbackList);
public:
- static scoped_refptr<FontFallbackList> Create(FontSelector* font_selector) {
- return base::AdoptRef(new FontFallbackList(font_selector));
+ static scoped_refptr<FontFallbackList> Create(
+ FontFallbackMap& font_fallback_map) {
+ return base::AdoptRef(new FontFallbackList(font_fallback_map));
}
- ~FontFallbackList() { ReleaseFontData(); }
+ ~FontFallbackList();
// Returns whether the cached data is valid. We can use a FontFallbackList
// only when it's valid.
- bool IsValid() const;
+ bool IsValid() const { return !is_invalid_; }
// Called when font updates (see class comment) have made the cached data
// invalid. Once marked, a Font object cannot reuse |this|, but have to work
// on a new instance obtained from FontFallbackMap.
void MarkInvalid() {
- DCHECK(RuntimeEnabledFeatures::
- CSSReducedFontLoadingLayoutInvalidationsEnabled());
is_invalid_ = true;
}
- // Clears all the stale data, and reset the state for replenishment. Note that
- // this is a deprecated function, and will be removed after we launch feature
- // CSSReducedFontLoadingLayoutInvalidations. With the feature, we'll never
- // revalidate a FontFallbackList, but create a new FontFallbackList instead.
- void RevalidateDeprecated();
-
bool ShouldSkipDrawing() const;
- FontSelector* GetFontSelector() const { return font_selector_.Get(); }
- // FIXME: It should be possible to combine fontSelectorVersion and generation.
- unsigned FontSelectorVersion() const { return font_selector_version_; }
+ // Returns false only after the WeakPersistent to FontFallbackMap is turned to
+ // nullptr due to GC.
+ bool HasFontFallbackMap() const { return font_fallback_map_; }
+ FontFallbackMap& GetFontFallbackMap() const { return *font_fallback_map_; }
+
+ FontSelector* GetFontSelector() const;
uint16_t Generation() const { return generation_; }
ShapeCache* GetShapeCache(const FontDescription& font_description) {
@@ -113,7 +110,7 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> {
bool HasAdvanceOverride() const { return has_advance_override_; }
private:
- explicit FontFallbackList(FontSelector* font_selector);
+ explicit FontFallbackList(FontFallbackMap& font_fallback_map);
scoped_refptr<FontData> GetFontData(const FontDescription&);
@@ -126,8 +123,7 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> {
Vector<scoped_refptr<FontData>, 1> font_list_;
const SimpleFontData* cached_primary_simple_font_data_;
- const Persistent<FontSelector> font_selector_;
- unsigned font_selector_version_;
+ const WeakPersistent<FontFallbackMap> font_fallback_map_;
int family_index_;
uint16_t generation_;
bool has_loading_fallback_ : 1;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.cc b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.cc
index 518f2466d31..624a815e4a5 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.cc
@@ -26,7 +26,7 @@ scoped_refptr<FontFallbackList> FontFallbackMap::Get(
return iter->value;
}
auto add_result = fallback_list_for_description_.insert(
- font_description, FontFallbackList::Create(font_selector_));
+ font_description, FontFallbackList::Create(*this));
return add_result.stored_value->value;
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.h b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.h
index e2186f7e88b..135f1124478 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_map.h
@@ -25,6 +25,8 @@ class PLATFORM_EXPORT FontFallbackMap : public FontCacheClient,
~FontFallbackMap() override;
+ FontSelector* GetFontSelector() const { return font_selector_; }
+
scoped_refptr<FontFallbackList> Get(const FontDescription& font_description);
void Remove(const FontDescription& font_description);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
index 6bbc2dd1bd4..abcc0926686 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/fonts/font_matching_metrics.h"
+#include "base/metrics/histogram_macros.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -307,17 +308,29 @@ void FontMatchingMetrics::PublishUkmMetrics() {
.SetSystemFontFamilyFailures(ukm::GetExponentialBucketMin(
SetIntersection(failed_font_families_, system_font_families_).size(),
kUkmFontLoadCountBucketSpacing))
+ .SetSystemFontFamilyTotal(ukm::GetExponentialBucketMin(
+ system_font_families_.size(), kUkmFontLoadCountBucketSpacing))
.SetWebFontFamilySuccesses(ukm::GetExponentialBucketMin(
SetIntersection(successful_font_families_, web_font_families_).size(),
kUkmFontLoadCountBucketSpacing))
.SetWebFontFamilyFailures(ukm::GetExponentialBucketMin(
SetIntersection(failed_font_families_, web_font_families_).size(),
kUkmFontLoadCountBucketSpacing))
+ .SetWebFontFamilyTotal(ukm::GetExponentialBucketMin(
+ web_font_families_.size(), kUkmFontLoadCountBucketSpacing))
.SetLocalFontFailures(ukm::GetExponentialBucketMin(
local_fonts_failed_.size(), kUkmFontLoadCountBucketSpacing))
.SetLocalFontSuccesses(ukm::GetExponentialBucketMin(
local_fonts_succeeded_.size(), kUkmFontLoadCountBucketSpacing))
+ .SetLocalFontTotal(ukm::GetExponentialBucketMin(
+ local_fonts_succeeded_.size() + local_fonts_failed_.size(),
+ kUkmFontLoadCountBucketSpacing))
.Record(ukm_recorder_);
+ UMA_HISTOGRAM_COUNTS_10000("Blink.Fonts.FontFamilyMatchAttempts.System",
+ system_font_families_.size());
+ UMA_HISTOGRAM_COUNTS_10000(
+ "Blink.Fonts.FontMatchAttempts.System",
+ local_fonts_failed_.size() + local_fonts_succeeded_.size());
}
void FontMatchingMetrics::OnFontLookup() {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_metrics_override.h b/chromium/third_party/blink/renderer/platform/fonts/font_metrics_override.h
index 354603e2c93..4c400119080 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/font_metrics_override.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/font_metrics_override.h
@@ -14,7 +14,7 @@ struct FontMetricsOverride {
base::Optional<float> descent_override;
base::Optional<float> line_gap_override;
base::Optional<float> advance_override;
- base::Optional<float> advance_proportional_override;
+ base::Optional<float> advance_override_vertical_upright;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm
index 1671d612dd0..fb5629f9596 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm
+++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm
@@ -140,16 +140,14 @@ scoped_refptr<SimpleFontData> FontCache::PlatformFallbackFontForCharacter(
font_data_to_substitute->PlatformData();
NSFont* ns_font = base::mac::CFToNSCast(platform_data.CtFont());
- NSString* string =
- [[NSString alloc] initWithCharactersNoCopy:code_units
- length:code_units_length
- freeWhenDone:NO];
+ NSString* string = [[[NSString alloc]
+ initWithCharacters:reinterpret_cast<UniChar*>(code_units)
+ length:code_units_length] autorelease];
NSFont* substitute_font =
[NSFont findFontLike:ns_font
forString:string
withRange:NSMakeRange(0, code_units_length)
inLanguage:nil];
- [string release];
// FIXME: Remove this SPI usage: http://crbug.com/255122
if (!substitute_font && code_units_length == 1)
diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
index aafddac6d3b..7144caba9ef 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
+++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
@@ -33,7 +33,6 @@
#import <Foundation/Foundation.h>
#import <math.h>
-#include "base/bit_cast.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
@@ -42,37 +41,10 @@
#import "third_party/blink/renderer/platform/wtf/hash_set.h"
#import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
-@interface NSFont (YosemiteAdditions)
-+ (NSFont*)systemFontOfSize:(CGFloat)size weight:(CGFloat)weight;
-@end
+namespace blink {
namespace {
-static CGFloat toFontWeight(blink::FontSelectionValue font_weight) {
- static uint64_t ns_font_weights[] = {
- 0xbfe99999a0000000, // NSFontWeightUltraLight
- 0xbfe3333340000000, // NSFontWeightThin
- 0xbfd99999a0000000, // NSFontWeightLight
- 0x0000000000000000, // NSFontWeightRegular
- 0x3fcd70a3e0000000, // NSFontWeightMedium
- 0x3fd3333340000000, // NSFontWeightSemibold
- 0x3fd99999a0000000, // NSFontWeightBold
- 0x3fe1eb8520000000, // NSFontWeightHeavy
- 0x3fe3d70a40000000, // NSFontWeightBlack
- };
- if (font_weight <= 50 || font_weight >= 950)
- return bit_cast<CGFloat>(ns_font_weights[3]);
-
- size_t select_weight = roundf(font_weight / 100) - 1;
- DCHECK_GE(select_weight, 0ul);
- DCHECK_LE(select_weight, base::size(ns_font_weights));
- return bit_cast<CGFloat>(ns_font_weights[select_weight]);
-}
-
-} // namespace
-
-namespace blink {
-
const NSFontTraitMask SYNTHESIZED_FONT_TRAITS =
(NSBoldFontMask | NSItalicFontMask);
@@ -81,18 +53,18 @@ const NSFontTraitMask IMPORTANT_FONT_TRAITS =
NSItalicFontMask | NSNarrowFontMask | NSPosterFontMask |
NSSmallCapsFontMask);
-static BOOL AcceptableChoice(NSFontTraitMask desired_traits,
- NSFontTraitMask candidate_traits) {
+BOOL AcceptableChoice(NSFontTraitMask desired_traits,
+ NSFontTraitMask candidate_traits) {
desired_traits &= ~SYNTHESIZED_FONT_TRAITS;
return (candidate_traits & desired_traits) == desired_traits;
}
-static BOOL BetterChoice(NSFontTraitMask desired_traits,
- int desired_weight,
- NSFontTraitMask chosen_traits,
- int chosen_weight,
- NSFontTraitMask candidate_traits,
- int candidate_weight) {
+BOOL BetterChoice(NSFontTraitMask desired_traits,
+ int desired_weight,
+ NSFontTraitMask chosen_traits,
+ int chosen_weight,
+ NSFontTraitMask candidate_traits,
+ int candidate_weight) {
if (!AcceptableChoice(desired_traits, candidate_traits))
return NO;
@@ -129,6 +101,23 @@ static BOOL BetterChoice(NSFontTraitMask desired_traits,
return candidate_weight_delta_magnitude < chosen_weight_delta_magnitude;
}
+NSFontWeight ToFontWeight(blink::FontSelectionValue font_weight) {
+ if (font_weight <= 50 || font_weight >= 950)
+ return NSFontWeightRegular;
+
+ const NSFontWeight ns_font_weights[] = {
+ NSFontWeightUltraLight, NSFontWeightThin, NSFontWeightLight,
+ NSFontWeightRegular, NSFontWeightMedium, NSFontWeightSemibold,
+ NSFontWeightBold, NSFontWeightHeavy, NSFontWeightBlack,
+ };
+ size_t select_weight = roundf(font_weight / 100) - 1;
+ DCHECK_GE(select_weight, 0ul);
+ DCHECK_LE(select_weight, base::size(ns_font_weights));
+ return ns_font_weights[select_weight];
+}
+
+} // namespace
+
NSFont* MatchUniqueFont(const AtomicString& unique_font_name, float size) {
// Testing with a large list of fonts available on Mac OS shows that matching
// for kCTFontNameAttribute matches postscript name as well as full font name.
@@ -175,16 +164,8 @@ NSFont* MatchNSFontFamily(const AtomicString& desired_family_string,
DCHECK_NE(desired_family_string, FontCache::LegacySystemFontFamily());
if (desired_family_string == font_family_names::kSystemUi) {
- NSFont* font = nil;
-// Normally we'd use an availability macro here, but
-// systemFontOfSize:weight: is available but not visible on macOS 10.10,
-// so it's been forward declared earlier in this file.
-// On OSX 10.10+, the default system font has more weights.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
- font = [NSFont systemFontOfSize:size weight:toFontWeight(desired_weight)];
-#pragma clang diagnostic pop
-
+ NSFont* font = [NSFont systemFontOfSize:size
+ weight:ToFontWeight(desired_weight)];
if (desired_traits & IMPORTANT_FONT_TRAITS)
font = [[NSFontManager sharedFontManager] convertFont:font
toHaveTrait:desired_traits];
diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
index 0636b18ae4b..c3c3e678de9 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
+++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
@@ -6,7 +6,6 @@
#include <AppKit/AppKit.h>
-#include "base/mac/mac_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
@@ -19,21 +18,6 @@ void TestSystemFontContainsString(FontSelectionValue desired_weight,
EXPECT_TRUE([font.description containsString:substring]);
}
-TEST(FontMatcherMacTest, YosemiteFontWeights) {
- if (!base::mac::IsOS10_10())
- return;
-
- TestSystemFontContainsString(FontSelectionValue(100), @"-UltraLight");
- TestSystemFontContainsString(FontSelectionValue(200), @"-Thin");
- TestSystemFontContainsString(FontSelectionValue(300), @"-Light");
- TestSystemFontContainsString(FontSelectionValue(400), @"-Regular");
- TestSystemFontContainsString(FontSelectionValue(500), @"-Medium");
- TestSystemFontContainsString(FontSelectionValue(600), @"-Bold");
- TestSystemFontContainsString(FontSelectionValue(700), @"-Bold");
- TestSystemFontContainsString(FontSelectionValue(800), @"-Heavy");
- TestSystemFontContainsString(FontSelectionValue(900), @"-Heavy");
-}
-
TEST(FontMatcherMacTest, NoUniqueFontMatchOnUnavailableFont) {
NSFont* font = MatchUniqueFont(
"ThisFontNameDoesNotExist07F444B9-4DDF-4A41-8F30-C80D4ED4CCA2", 12);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac_test.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac_test.mm
index 018743cf00d..e8a32bd8bbd 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac_test.mm
+++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac_test.mm
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h"
#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
@@ -33,9 +32,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
// Below the 11.0 axis minimum.
sk_sp<SkTypeface> system_font(MakeSystemFontOfSize(12));
- // TODO(https://crbug.com/1115294, https://crbug.com/1105187): Switch back to
- // @available when it works.
- if (base::mac::IsOS11()) {
+ if (@available(macOS 11.0, *)) {
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -48,7 +45,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 72));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 96));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 97));
- } else if (base::mac::IsOS10_15()) {
+ } else if (@available(macOS 10.15, *)) {
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -78,7 +75,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
// Just smaller than the switch-over size in 10.15, which is 19.9.
system_font = MakeSystemFontOfSize(19);
- if (base::mac::IsOS11()) {
+ if (@available(macOS 11.0, *)) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -91,7 +88,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 72));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 96));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 97));
- } else if (base::mac::IsOS10_15()) {
+ } else if (@available(macOS 10.15, *)) {
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -121,7 +118,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
// Just larger than the switch-over size in 10.15, which is 19.9.
system_font = MakeSystemFontOfSize(20);
- if (base::mac::IsOS11()) {
+ if (@available(macOS 11.0, *)) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -134,7 +131,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 72));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 96));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 97));
- } else if (base::mac::IsOS10_15()) {
+ } else if (@available(macOS 10.15, *)) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -164,7 +161,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
// Above the 11.0 axis maximum.
system_font = MakeSystemFontOfSize(128);
- if (base::mac::IsOS11()) {
+ if (@available(macOS 11.0, *)) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
@@ -177,7 +174,7 @@ TEST(FontPlatformDataMacTest, VariableOpticalSizingThreshold) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 72));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 96));
EXPECT_FALSE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 97));
- } else if (base::mac::IsOS10_15()) {
+ } else if (@available(macOS 10.15, *)) {
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 6));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 12));
EXPECT_TRUE(VariableAxisChangeEffective(system_font.get(), kOpszTag, 17));
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
index 2c11652ffcf..e1710f6bb2a 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
@@ -8,12 +8,48 @@
// having to rely on the platform being able to instantiate this font format.
#include <hb.h>
+#include "base/sys_byteorder.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/harfbuzz-ng/utils/hb_scoped.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace blink {
+namespace {
+
+FontFormatCheck::COLRVersion determineCOLRVersion(
+ const FontFormatCheck::TableTagsVector& table_tags,
+ const hb_face_t* face) {
+ const hb_tag_t kCOLRTag = HB_TAG('C', 'O', 'L', 'R');
+
+ // Only try to read version if header size is sufficient.
+ // https://docs.microsoft.com/en-us/typography/opentype/spec/colr#header
+ const unsigned int kMinCOLRHeaderSize = 14;
+ if (table_tags.size() && table_tags.Contains(kCOLRTag) &&
+ table_tags.Contains(HB_TAG('C', 'P', 'A', 'L'))) {
+ HbScoped<hb_blob_t> table_blob(hb_face_reference_table(face, kCOLRTag));
+ if (hb_blob_get_length(table_blob.get()) < kMinCOLRHeaderSize)
+ return FontFormatCheck::COLRVersion::kNoCOLR;
+
+ unsigned required_bytes_count = 2u;
+ const char* colr_data =
+ hb_blob_get_data(table_blob.get(), &required_bytes_count);
+ if (required_bytes_count < 2u)
+ return FontFormatCheck::COLRVersion::kNoCOLR;
+
+ uint16_t colr_version =
+ base::NetToHost16(*reinterpret_cast<const uint16_t*>(colr_data));
+
+ if (colr_version == 0)
+ return FontFormatCheck::COLRVersion::kCOLRV0;
+ else if (colr_version == 1)
+ return FontFormatCheck::COLRVersion::kCOLRV1;
+ }
+ return FontFormatCheck::COLRVersion::kNoCOLR;
+}
+
+} // namespace
+
FontFormatCheck::FontFormatCheck(sk_sp<SkData> sk_data) {
HbScoped<hb_blob_t> font_blob(hb_blob_create(
reinterpret_cast<const char*>(sk_data->bytes()), sk_data->size(),
@@ -25,6 +61,8 @@ FontFormatCheck::FontFormatCheck(sk_sp<SkData> sk_data) {
table_tags_.resize(table_count);
if (!hb_face_get_table_tags(face.get(), 0, &table_count, table_tags_.data()))
table_tags_.resize(0);
+
+ colr_version_ = determineCOLRVersion(table_tags_, face.get());
}
bool FontFormatCheck::IsVariableFont() {
@@ -37,10 +75,12 @@ bool FontFormatCheck::IsCbdtCblcColorFont() {
table_tags_.Contains(HB_TAG('C', 'B', 'L', 'C'));
}
-bool FontFormatCheck::IsColrCpalColorFont() {
- return table_tags_.size() &&
- table_tags_.Contains(HB_TAG('C', 'O', 'L', 'R')) &&
- table_tags_.Contains(HB_TAG('C', 'P', 'A', 'L'));
+bool FontFormatCheck::IsColrCpalColorFontV0() {
+ return colr_version_ == COLRVersion::kCOLRV0;
+}
+
+bool FontFormatCheck::IsColrCpalColorFontV1() {
+ return colr_version_ == COLRVersion::kCOLRV1;
}
bool FontFormatCheck::IsSbixColorFont() {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.h
index 65671245b66..c4e23a7b02d 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_FONT_FORMAT_CHECK_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_FONT_FORMAT_CHECK_H_
+#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkData.h"
@@ -13,14 +14,18 @@
namespace blink {
-class FontFormatCheck {
+class PLATFORM_EXPORT FontFormatCheck {
STACK_ALLOCATED();
public:
- FontFormatCheck(sk_sp<SkData>);
+ explicit FontFormatCheck(sk_sp<SkData>);
bool IsVariableFont();
bool IsCbdtCblcColorFont();
- bool IsColrCpalColorFont();
+ bool IsColrCpalColorFont() {
+ return IsColrCpalColorFontV0() || IsColrCpalColorFontV1();
+ }
+ bool IsColrCpalColorFontV0();
+ bool IsColrCpalColorFontV1();
bool IsSbixColorFont();
bool IsCff2OutlineFont();
bool IsColorFont();
@@ -34,9 +39,14 @@ class FontFormatCheck {
static VariableFontSubType ProbeVariableFont(sk_sp<SkTypeface>);
- private:
// hb-common.h: typedef uint32_t hb_tag_t;
- Vector<uint32_t> table_tags_;
+ using TableTagsVector = Vector<uint32_t>;
+
+ enum class COLRVersion { kCOLRV0, kCOLRV1, kNoCOLR };
+
+ private:
+ TableTagsVector table_tags_;
+ COLRVersion colr_version_ = COLRVersion::kNoCOLR;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
new file mode 100644
index 00000000000..3f343773477
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class FontFormatCheckTest : public testing::Test {
+ protected:
+ void EnsureFontData(String font_file_name) {
+ sk_sp<SkData> font_file_data(SkData::MakeFromFileName(
+ test::PlatformTestDataPath(font_file_name).Utf8().data()));
+ ASSERT_FALSE(font_file_data->isEmpty());
+ font_data_ = font_file_data;
+ }
+
+ sk_sp<SkData> font_data_;
+};
+
+TEST_F(FontFormatCheckTest, NoCOLR) {
+ EnsureFontData("roboto-a.ttf");
+ FontFormatCheck format_check(font_data_);
+ ASSERT_FALSE(format_check.IsColrCpalColorFontV0());
+ ASSERT_FALSE(format_check.IsColrCpalColorFontV1());
+}
+
+TEST_F(FontFormatCheckTest, COLRV1) {
+ EnsureFontData("colrv1_test.ttf");
+ FontFormatCheck format_check(font_data_);
+ ASSERT_TRUE(format_check.IsColrCpalColorFontV1());
+ ASSERT_FALSE(format_check.IsColrCpalColorFontV0());
+}
+
+TEST_F(FontFormatCheckTest, COLRV0) {
+ EnsureFontData("colrv0_test.ttf");
+ FontFormatCheck format_check(font_data_);
+ ASSERT_TRUE(format_check.IsColrCpalColorFontV0());
+ ASSERT_FALSE(format_check.IsColrCpalColorFontV1());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
index 542975a52ba..84024bbecda 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
@@ -152,9 +152,8 @@ OpenTypeCapsSupport::FontFormat OpenTypeCapsSupport::GetFontFormat() const {
bool has_morx_or_mort = hb_blob_get_length(morx_blob.get()) ||
hb_blob_get_length(mort_blob.get());
bool has_gsub = hb_ot_layout_has_substitution(hb_face);
- font_format_ = has_morx_or_mort&& !has_gsub
- ? font_format_ = FontFormat::kAat
- : font_format_ = FontFormat::kOpenType;
+ font_format_ = has_morx_or_mort && !has_gsub ? FontFormat::kAat
+ : FontFormat::kOpenType;
}
return font_format_;
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
index a3187aea143..1ce5e3d3af3 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
@@ -190,7 +190,11 @@ bool ScriptRunIterator::Consume(unsigned* limit, UScriptCode* script) {
if (!MergeSets()) {
*limit = pos;
*script = ResolveCurrentScript();
- FixupStack(*script);
+ // If the current character is an open bracket, do not assign the resolved
+ // script to it yet because it will belong to the next run.
+ const bool exclude_last =
+ paired_type == PairedBracketType::kBracketTypeOpen;
+ FixupStack(*script, exclude_last);
current_set_ = *next_set_;
return true;
}
@@ -220,8 +224,10 @@ void ScriptRunIterator::CloseBracket(UChar32 ch) {
if (it->ch == target) {
// Have a match, use open paren's resolved script.
UScriptCode script = it->script;
- next_set_->clear();
- next_set_->push_back(script);
+ if (script != USCRIPT_COMMON) {
+ next_set_->clear();
+ next_set_->push_back(script);
+ }
// And pop stack to this point.
int num_popped =
@@ -332,20 +338,27 @@ bool ScriptRunIterator::MergeSets() {
// adjust it if the stack got overfull and open brackets were pushed off
// the bottom. This sets the script of the fixup_depth topmost entries of the
// stack to the resolved script.
-void ScriptRunIterator::FixupStack(UScriptCode resolved_script) {
- if (brackets_fixup_depth_ > 0) {
- if (brackets_fixup_depth_ > brackets_.size()) {
- // Should never happen unless someone breaks the code.
- DLOG(ERROR) << "Brackets fixup depth exceeds size of bracket vector.";
- brackets_fixup_depth_ = brackets_.size();
- }
- auto it = brackets_.rbegin();
- for (wtf_size_t i = 0; i < brackets_fixup_depth_; ++i) {
- it->script = resolved_script;
- ++it;
- }
+void ScriptRunIterator::FixupStack(UScriptCode resolved_script,
+ bool exclude_last) {
+ wtf_size_t count = brackets_fixup_depth_;
+ if (count <= 0)
+ return;
+ if (count > brackets_.size()) {
+ // Should never happen unless someone breaks the code.
+ DLOG(ERROR) << "Brackets fixup depth exceeds size of bracket vector.";
+ count = brackets_.size();
+ }
+ auto it = brackets_.rbegin();
+ // Do not assign the script to the last one if |exclude_last|.
+ if (exclude_last) {
+ ++it;
+ --count;
+ brackets_fixup_depth_ = 1;
+ } else {
brackets_fixup_depth_ = 0;
}
+ for (; count; ++it, --count)
+ it->script = resolved_script;
}
bool ScriptRunIterator::Fetch(wtf_size_t* pos, UChar32* ch) {
diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
index 189e5a62a66..eac28750105 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.h
@@ -43,7 +43,7 @@ class PLATFORM_EXPORT ScriptRunIterator {
void OpenBracket(UChar32);
void CloseBracket(UChar32);
bool MergeSets();
- void FixupStack(UScriptCode resolved_script);
+ void FixupStack(UScriptCode resolved_script, bool exclude_last);
bool Fetch(wtf_size_t* pos, UChar32*);
UScriptCode ResolveCurrentScript() const;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.cc
new file mode 100644
index 00000000000..99ae1df8fa5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.cc
@@ -0,0 +1,227 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/fonts/shaping/font_features.h"
+
+#include "third_party/blink/renderer/platform/fonts/font.h"
+
+namespace blink {
+
+namespace {
+
+constexpr hb_feature_t CreateFeature(hb_tag_t tag, uint32_t value = 0) {
+ return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
+}
+
+constexpr hb_feature_t CreateFeature(char c1,
+ char c2,
+ char c3,
+ char c4,
+ uint32_t value = 0) {
+ return CreateFeature(HB_TAG(c1, c2, c3, c4), value);
+}
+
+} // namespace
+
+base::Optional<unsigned> FontFeatures::FindValueForTesting(hb_tag_t tag) const {
+ for (const hb_feature_t& feature : features_) {
+ if (feature.tag == tag)
+ return feature.value;
+ }
+ return base::nullopt;
+}
+
+void FontFeatures::Initialize(const FontDescription& description) {
+ DCHECK(IsEmpty());
+ const bool is_horizontal = !description.IsVerticalAnyUpright();
+
+ constexpr hb_feature_t no_kern = CreateFeature('k', 'e', 'r', 'n');
+ constexpr hb_feature_t no_vkrn = CreateFeature('v', 'k', 'r', 'n');
+ switch (description.GetKerning()) {
+ case FontDescription::kNormalKerning:
+ // kern/vkrn are enabled by default in HarfBuzz
+ break;
+ case FontDescription::kNoneKerning:
+ Append(is_horizontal ? no_kern : no_vkrn);
+ break;
+ case FontDescription::kAutoKerning:
+ break;
+ }
+
+ {
+ bool default_is_off = description.TextRendering() == blink::kOptimizeSpeed;
+ bool letter_spacing = description.LetterSpacing() != 0;
+ constexpr auto normal = FontDescription::kNormalLigaturesState;
+ constexpr auto enabled = FontDescription::kEnabledLigaturesState;
+ constexpr auto disabled = FontDescription::kDisabledLigaturesState;
+
+ // clig and liga are on by default in HarfBuzz
+ constexpr hb_feature_t no_clig = CreateFeature('c', 'l', 'i', 'g');
+ constexpr hb_feature_t no_liga = CreateFeature('l', 'i', 'g', 'a');
+ auto common = description.CommonLigaturesState();
+ if (letter_spacing ||
+ (common == disabled || (common == normal && default_is_off))) {
+ Append(no_liga);
+ Append(no_clig);
+ }
+ // dlig is off by default in HarfBuzz
+ constexpr hb_feature_t dlig = CreateFeature('d', 'l', 'i', 'g', 1);
+ auto discretionary = description.DiscretionaryLigaturesState();
+ if (!letter_spacing && discretionary == enabled) {
+ Append(dlig);
+ }
+ // hlig is off by default in HarfBuzz
+ constexpr hb_feature_t hlig = CreateFeature('h', 'l', 'i', 'g', 1);
+ auto historical = description.HistoricalLigaturesState();
+ if (!letter_spacing && historical == enabled) {
+ Append(hlig);
+ }
+ // calt is on by default in HarfBuzz
+ constexpr hb_feature_t no_calt = CreateFeature('c', 'a', 'l', 't');
+ auto contextual = description.ContextualLigaturesState();
+ if (letter_spacing ||
+ (contextual == disabled || (contextual == normal && default_is_off))) {
+ Append(no_calt);
+ }
+ }
+
+ static constexpr hb_feature_t hwid = CreateFeature('h', 'w', 'i', 'd', 1);
+ static constexpr hb_feature_t twid = CreateFeature('t', 'w', 'i', 'd', 1);
+ static constexpr hb_feature_t qwid = CreateFeature('q', 'w', 'i', 'd', 1);
+ switch (description.WidthVariant()) {
+ case kHalfWidth:
+ Append(hwid);
+ break;
+ case kThirdWidth:
+ Append(twid);
+ break;
+ case kQuarterWidth:
+ Append(qwid);
+ break;
+ case kRegularWidth:
+ break;
+ }
+
+ // font-variant-east-asian:
+ const FontVariantEastAsian east_asian = description.VariantEastAsian();
+ if (UNLIKELY(!east_asian.IsAllNormal())) {
+ static constexpr hb_feature_t jp78 = CreateFeature('j', 'p', '7', '8', 1);
+ static constexpr hb_feature_t jp83 = CreateFeature('j', 'p', '8', '3', 1);
+ static constexpr hb_feature_t jp90 = CreateFeature('j', 'p', '9', '0', 1);
+ static constexpr hb_feature_t jp04 = CreateFeature('j', 'p', '0', '4', 1);
+ static constexpr hb_feature_t smpl = CreateFeature('s', 'm', 'p', 'l', 1);
+ static constexpr hb_feature_t trad = CreateFeature('t', 'r', 'a', 'd', 1);
+ switch (east_asian.Form()) {
+ case FontVariantEastAsian::kNormalForm:
+ break;
+ case FontVariantEastAsian::kJis78:
+ Append(jp78);
+ break;
+ case FontVariantEastAsian::kJis83:
+ Append(jp83);
+ break;
+ case FontVariantEastAsian::kJis90:
+ Append(jp90);
+ break;
+ case FontVariantEastAsian::kJis04:
+ Append(jp04);
+ break;
+ case FontVariantEastAsian::kSimplified:
+ Append(smpl);
+ break;
+ case FontVariantEastAsian::kTraditional:
+ Append(trad);
+ break;
+ default:
+ NOTREACHED();
+ }
+ static constexpr hb_feature_t fwid = CreateFeature('f', 'w', 'i', 'd', 1);
+ static constexpr hb_feature_t pwid = CreateFeature('p', 'w', 'i', 'd', 1);
+ switch (east_asian.Width()) {
+ case FontVariantEastAsian::kNormalWidth:
+ break;
+ case FontVariantEastAsian::kFullWidth:
+ Append(fwid);
+ break;
+ case FontVariantEastAsian::kProportionalWidth:
+ Append(pwid);
+ break;
+ default:
+ NOTREACHED();
+ }
+ static constexpr hb_feature_t ruby = CreateFeature('r', 'u', 'b', 'y', 1);
+ if (east_asian.Ruby())
+ Append(ruby);
+ }
+
+ // font-variant-numeric:
+ static constexpr hb_feature_t lnum = CreateFeature('l', 'n', 'u', 'm', 1);
+ if (description.VariantNumeric().NumericFigureValue() ==
+ FontVariantNumeric::kLiningNums)
+ Append(lnum);
+
+ static constexpr hb_feature_t onum = CreateFeature('o', 'n', 'u', 'm', 1);
+ if (description.VariantNumeric().NumericFigureValue() ==
+ FontVariantNumeric::kOldstyleNums)
+ Append(onum);
+
+ static constexpr hb_feature_t pnum = CreateFeature('p', 'n', 'u', 'm', 1);
+ if (description.VariantNumeric().NumericSpacingValue() ==
+ FontVariantNumeric::kProportionalNums)
+ Append(pnum);
+ static constexpr hb_feature_t tnum = CreateFeature('t', 'n', 'u', 'm', 1);
+ if (description.VariantNumeric().NumericSpacingValue() ==
+ FontVariantNumeric::kTabularNums)
+ Append(tnum);
+
+ static constexpr hb_feature_t afrc = CreateFeature('a', 'f', 'r', 'c', 1);
+ if (description.VariantNumeric().NumericFractionValue() ==
+ FontVariantNumeric::kStackedFractions)
+ Append(afrc);
+ static constexpr hb_feature_t frac = CreateFeature('f', 'r', 'a', 'c', 1);
+ if (description.VariantNumeric().NumericFractionValue() ==
+ FontVariantNumeric::kDiagonalFractions)
+ Append(frac);
+
+ static constexpr hb_feature_t ordn = CreateFeature('o', 'r', 'd', 'n', 1);
+ if (description.VariantNumeric().OrdinalValue() ==
+ FontVariantNumeric::kOrdinalOn)
+ Append(ordn);
+
+ static constexpr hb_feature_t zero = CreateFeature('z', 'e', 'r', 'o', 1);
+ if (description.VariantNumeric().SlashedZeroValue() ==
+ FontVariantNumeric::kSlashedZeroOn)
+ Append(zero);
+
+ const hb_tag_t chws_or_vchw =
+ is_horizontal ? HB_TAG('c', 'h', 'w', 's') : HB_TAG('v', 'c', 'h', 'w');
+ bool default_enable_chws = true;
+
+ const FontFeatureSettings* settings = description.FeatureSettings();
+ if (UNLIKELY(settings)) {
+ // TODO(drott): crbug.com/450619 Implement feature resolution instead of
+ // just appending the font-feature-settings.
+ const hb_tag_t halt_or_vhal =
+ is_horizontal ? HB_TAG('h', 'a', 'l', 't') : HB_TAG('v', 'h', 'a', 'l');
+ const hb_tag_t palt_or_vpal =
+ is_horizontal ? HB_TAG('p', 'a', 'l', 't') : HB_TAG('v', 'p', 'a', 'l');
+ for (const FontFeature& setting : *settings) {
+ const hb_feature_t feature =
+ CreateFeature(setting.Tag(), setting.Value());
+ Append(feature);
+
+ // `chws` should not be appended if other glyph-width GPOS feature exists.
+ if (default_enable_chws &&
+ (feature.tag == chws_or_vchw ||
+ (feature.value &&
+ (feature.tag == halt_or_vhal || feature.tag == palt_or_vpal))))
+ default_enable_chws = false;
+ }
+ }
+
+ if (default_enable_chws)
+ Append(CreateFeature(chws_or_vchw, 1));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.h
new file mode 100644
index 00000000000..e3411186185
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features.h
@@ -0,0 +1,47 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_FONT_FEATURES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_FONT_FEATURES_H_
+
+#include <hb.h>
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class Font;
+class FontDescription;
+
+// Represents a list of OpenType font feature settings.
+class PLATFORM_EXPORT FontFeatures {
+ STACK_ALLOCATED();
+
+ public:
+ // Initialize the list from |Font|.
+ void Initialize(const FontDescription&);
+
+ wtf_size_t size() const { return features_.size(); }
+ bool IsEmpty() const { return features_.IsEmpty(); }
+
+ const hb_feature_t* data() const { return features_.data(); }
+
+ base::Optional<unsigned> FindValueForTesting(hb_tag_t tag) const;
+
+ void Append(const hb_feature_t& feature) { features_.push_back(feature); }
+ void Insert(const hb_feature_t& feature) { features_.push_front(feature); }
+
+ void EraseAt(wtf_size_t position, wtf_size_t length) {
+ features_.EraseAt(position, length);
+ }
+
+ private:
+ Vector<hb_feature_t, 6> features_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_FONT_FEATURES_H_
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc
new file mode 100644
index 00000000000..200cbb343f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/fonts/shaping/font_features.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/fonts/font_description.h"
+
+namespace blink {
+
+namespace {
+
+class FontFeaturesTest : public testing::Test {};
+
+static const FontOrientation orientations[] = {
+ FontOrientation::kHorizontal,
+ FontOrientation::kVerticalRotated,
+ FontOrientation::kVerticalMixed,
+ FontOrientation::kVerticalUpright,
+};
+
+class FontFeaturesByOrientationTest
+ : public FontFeaturesTest,
+ public testing::WithParamInterface<FontOrientation> {
+ public:
+ FontOrientation GetOrientation() const { return GetParam(); }
+ bool IsHorizontal() const { return !IsVerticalAnyUpright(GetOrientation()); }
+};
+
+INSTANTIATE_TEST_SUITE_P(FontFeaturesTest,
+ FontFeaturesByOrientationTest,
+ testing::ValuesIn(orientations));
+
+// Test 'chws' or 'vchw' is on by default.
+TEST_P(FontFeaturesByOrientationTest, EastAsianContextualSpacingOnByDefault) {
+ constexpr hb_tag_t chws = HB_TAG('c', 'h', 'w', 's');
+ constexpr hb_tag_t vchw = HB_TAG('v', 'c', 'h', 'w');
+ FontDescription font_description;
+ font_description.SetOrientation(GetOrientation());
+ FontFeatures features;
+ features.Initialize(font_description);
+ if (IsHorizontal()) {
+ EXPECT_EQ(features.FindValueForTesting(chws), 1u);
+ EXPECT_EQ(features.FindValueForTesting(vchw), base::nullopt);
+ } else {
+ EXPECT_EQ(features.FindValueForTesting(chws), base::nullopt);
+ EXPECT_EQ(features.FindValueForTesting(vchw), 1u);
+ }
+}
+
+// If author opted-in or opted-out, it should be honored.
+TEST_P(FontFeaturesByOrientationTest,
+ EastAsianContextualSpacingHonorsFontFeatureSettings) {
+ constexpr hb_tag_t chws = HB_TAG('c', 'h', 'w', 's');
+ constexpr hb_tag_t vchw = HB_TAG('v', 'c', 'h', 'w');
+ for (unsigned value = 0; value <= 1; ++value) {
+ scoped_refptr<FontFeatureSettings> settings = FontFeatureSettings::Create();
+ settings->Append({IsHorizontal() ? chws : vchw, value});
+ FontDescription font_description;
+ font_description.SetOrientation(GetOrientation());
+ font_description.SetFeatureSettings(settings);
+ FontFeatures features;
+ features.Initialize(font_description);
+ if (IsHorizontal()) {
+ EXPECT_EQ(features.FindValueForTesting(chws), value);
+ EXPECT_EQ(features.FindValueForTesting(vchw), base::nullopt);
+ } else {
+ EXPECT_EQ(features.FindValueForTesting(chws), base::nullopt);
+ EXPECT_EQ(features.FindValueForTesting(vchw), value);
+ }
+ }
+}
+
+// Test glyph-width GPOS features that should not enable 'chws'/'vchw'.
+TEST_P(FontFeaturesByOrientationTest,
+ EastAsianContextualSpacingOffByFeatureSettings) {
+ constexpr hb_tag_t chws = HB_TAG('c', 'h', 'w', 's');
+ constexpr hb_tag_t vchw = HB_TAG('v', 'c', 'h', 'w');
+ const hb_tag_t tags[] = {
+ IsHorizontal() ? HB_TAG('h', 'a', 'l', 't') : HB_TAG('v', 'h', 'a', 'l'),
+ IsHorizontal() ? HB_TAG('p', 'a', 'l', 't') : HB_TAG('v', 'p', 'a', 'l'),
+ };
+ for (const hb_tag_t tag : tags) {
+ scoped_refptr<FontFeatureSettings> settings = FontFeatureSettings::Create();
+ settings->Append({tag, 1});
+ FontDescription font_description;
+ font_description.SetOrientation(GetOrientation());
+ font_description.SetFeatureSettings(settings);
+ FontFeatures features;
+ features.Initialize(font_description);
+ EXPECT_EQ(features.FindValueForTesting(chws), base::nullopt);
+ EXPECT_EQ(features.FindValueForTesting(vchw), base::nullopt);
+ }
+}
+
+// Test the current behavior when multiple glyph-width GPOS features are set via
+// `FontFeatureSettings`. Current |FontFeatures| does not resolve conflicts,
+// just pass them all as specified to HarfBuzz.
+TEST_P(FontFeaturesByOrientationTest, MultipleGlyphWidthGPOS) {
+ const hb_tag_t tags[] = {
+ HB_TAG('c', 'h', 'w', 's'), HB_TAG('v', 'c', 'h', 'w'),
+ HB_TAG('h', 'a', 'l', 't'), HB_TAG('v', 'h', 'a', 'l'),
+ HB_TAG('p', 'a', 'l', 't'), HB_TAG('v', 'p', 'a', 'l'),
+ };
+ scoped_refptr<FontFeatureSettings> settings = FontFeatureSettings::Create();
+ for (const hb_tag_t tag : tags)
+ settings->Append({tag, 1});
+ FontDescription font_description;
+ font_description.SetOrientation(GetOrientation());
+ font_description.SetFeatureSettings(settings);
+ FontFeatures features;
+ features.Initialize(font_description);
+ // Check all features are enabled.
+ for (const hb_tag_t tag : tags)
+ EXPECT_EQ(features.FindValueForTesting(tag), 1u);
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 3138186ebd6..90d0f6bf1d4 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -45,6 +45,7 @@
#include "third_party/blink/renderer/platform/fonts/font_fallback_iterator.h"
#include "third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h"
#include "third_party/blink/renderer/platform/fonts/shaping/case_mapping_harfbuzz_buffer_filler.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/font_features.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h"
#include "third_party/blink/renderer/platform/fonts/small_caps_iterator.h"
@@ -59,6 +60,15 @@ namespace blink {
namespace {
+constexpr hb_feature_t CreateFeature(char c1,
+ char c2,
+ char c3,
+ char c4,
+ uint32_t value = 0) {
+ return {HB_TAG(c1, c2, c3, c4), value, 0 /* start */,
+ static_cast<unsigned>(-1) /* end */};
+}
+
#if DCHECK_IS_ON()
// Check if the ShapeResult has the specified range.
// |text| and |font| are only for logging.
@@ -148,22 +158,23 @@ class HarfBuzzScopedPtr {
DISALLOW_COPY_AND_ASSIGN(HarfBuzzScopedPtr);
};
-using FeaturesVector = Vector<hb_feature_t, 6>;
struct RangeData {
+ STACK_ALLOCATED();
+
+ public:
hb_buffer_t* buffer;
const Font* font;
TextDirection text_direction;
unsigned start;
unsigned end;
- FeaturesVector font_features;
+ FontFeatures font_features;
Deque<ReshapeQueueItem> reshape_queue;
hb_direction_t HarfBuzzDirection(CanvasRotationInVertical canvas_rotation) {
FontOrientation orientation = font->GetFontDescription().Orientation();
hb_direction_t direction =
IsVerticalAnyUpright(orientation) &&
- (canvas_rotation ==
- CanvasRotationInVertical::kRotateCanvasUpright)
+ IsCanvasRotationInVerticalUpright(canvas_rotation)
? HB_DIRECTION_TTB
: HB_DIRECTION_LTR;
return text_direction == TextDirection::kRtl
@@ -213,7 +224,7 @@ void RoundHarfBuzzBufferPositions(hb_buffer_t* buffer) {
}
inline bool ShapeRange(hb_buffer_t* buffer,
- hb_feature_t* font_features,
+ const hb_feature_t* font_features,
unsigned font_features_size,
const SimpleFontData* current_font,
scoped_refptr<UnicodeRangeSet> current_font_range_set,
@@ -305,11 +316,25 @@ void QueueCharacters(RangeData* range_data,
CanvasRotationInVertical CanvasRotationForRun(
FontOrientation font_orientation,
- OrientationIterator::RenderOrientation render_orientation) {
- if (font_orientation == FontOrientation::kVerticalUpright ||
- (font_orientation == FontOrientation::kVerticalMixed &&
- render_orientation == OrientationIterator::kOrientationKeep))
- return CanvasRotationInVertical::kRotateCanvasUpright;
+ OrientationIterator::RenderOrientation render_orientation,
+ const FontDescription& font_description) {
+ if (font_orientation == FontOrientation::kVerticalUpright) {
+ return font_description.IsSyntheticOblique()
+ ? CanvasRotationInVertical::kRotateCanvasUprightOblique
+ : CanvasRotationInVertical::kRotateCanvasUpright;
+ }
+
+ if (font_orientation == FontOrientation::kVerticalMixed) {
+ if (render_orientation == OrientationIterator::kOrientationKeep) {
+ return font_description.IsSyntheticOblique()
+ ? CanvasRotationInVertical::kRotateCanvasUprightOblique
+ : CanvasRotationInVertical::kRotateCanvasUpright;
+ }
+ return font_description.IsSyntheticOblique()
+ ? CanvasRotationInVertical::kOblique
+ : CanvasRotationInVertical::kRegular;
+ }
+
return CanvasRotationInVertical::kRegular;
}
@@ -553,211 +578,6 @@ void SplitUntilNextCaseChange(
}
}
-constexpr hb_feature_t CreateFeature(hb_tag_t tag, uint32_t value = 0) {
- return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
-}
-
-// TODO(kojii): crbug.com/762493 This list is getting long enough to extract out
-// of HarfBuzzShaper.cpp.
-void SetFontFeatures(const Font* font, FeaturesVector* features) {
- const FontDescription& description = font->GetFontDescription();
-
- constexpr hb_feature_t no_kern = CreateFeature(HB_TAG('k', 'e', 'r', 'n'));
- constexpr hb_feature_t no_vkrn = CreateFeature(HB_TAG('v', 'k', 'r', 'n'));
- switch (description.GetKerning()) {
- case FontDescription::kNormalKerning:
- // kern/vkrn are enabled by default in HarfBuzz
- break;
- case FontDescription::kNoneKerning:
- features->push_back(description.IsVerticalAnyUpright() ? no_vkrn
- : no_kern);
- break;
- case FontDescription::kAutoKerning:
- break;
- }
-
- {
- bool default_is_off = description.TextRendering() == blink::kOptimizeSpeed;
- bool letter_spacing = description.LetterSpacing() != 0;
- constexpr auto normal = FontDescription::kNormalLigaturesState;
- constexpr auto enabled = FontDescription::kEnabledLigaturesState;
- constexpr auto disabled = FontDescription::kDisabledLigaturesState;
-
- // clig and liga are on by default in HarfBuzz
- constexpr hb_feature_t no_clig = CreateFeature(HB_TAG('c', 'l', 'i', 'g'));
- constexpr hb_feature_t no_liga = CreateFeature(HB_TAG('l', 'i', 'g', 'a'));
- auto common = description.CommonLigaturesState();
- if (letter_spacing ||
- (common == disabled || (common == normal && default_is_off))) {
- features->push_back(no_liga);
- features->push_back(no_clig);
- }
- // dlig is off by default in HarfBuzz
- constexpr hb_feature_t dlig = CreateFeature(HB_TAG('d', 'l', 'i', 'g'), 1);
- auto discretionary = description.DiscretionaryLigaturesState();
- if (!letter_spacing && discretionary == enabled) {
- features->push_back(dlig);
- }
- // hlig is off by default in HarfBuzz
- constexpr hb_feature_t hlig = CreateFeature(HB_TAG('h', 'l', 'i', 'g'), 1);
- auto historical = description.HistoricalLigaturesState();
- if (!letter_spacing && historical == enabled) {
- features->push_back(hlig);
- }
- // calt is on by default in HarfBuzz
- constexpr hb_feature_t no_calt = CreateFeature(HB_TAG('c', 'a', 'l', 't'));
- auto contextual = description.ContextualLigaturesState();
- if (letter_spacing ||
- (contextual == disabled || (contextual == normal && default_is_off))) {
- features->push_back(no_calt);
- }
- }
-
- static constexpr hb_feature_t hwid =
- CreateFeature(HB_TAG('h', 'w', 'i', 'd'), 1);
- static constexpr hb_feature_t twid =
- CreateFeature(HB_TAG('t', 'w', 'i', 'd'), 1);
- static constexpr hb_feature_t qwid =
- CreateFeature(HB_TAG('q', 'w', 'i', 'd'), 1);
- switch (description.WidthVariant()) {
- case kHalfWidth:
- features->push_back(hwid);
- break;
- case kThirdWidth:
- features->push_back(twid);
- break;
- case kQuarterWidth:
- features->push_back(qwid);
- break;
- case kRegularWidth:
- break;
- }
-
- // font-variant-east-asian:
- const FontVariantEastAsian east_asian = description.VariantEastAsian();
- if (UNLIKELY(!east_asian.IsAllNormal())) {
- static constexpr hb_feature_t jp78 =
- CreateFeature(HB_TAG('j', 'p', '7', '8'), 1);
- static constexpr hb_feature_t jp83 =
- CreateFeature(HB_TAG('j', 'p', '8', '3'), 1);
- static constexpr hb_feature_t jp90 =
- CreateFeature(HB_TAG('j', 'p', '9', '0'), 1);
- static constexpr hb_feature_t jp04 =
- CreateFeature(HB_TAG('j', 'p', '0', '4'), 1);
- static constexpr hb_feature_t smpl =
- CreateFeature(HB_TAG('s', 'm', 'p', 'l'), 1);
- static constexpr hb_feature_t trad =
- CreateFeature(HB_TAG('t', 'r', 'a', 'd'), 1);
- switch (east_asian.Form()) {
- case FontVariantEastAsian::kNormalForm:
- break;
- case FontVariantEastAsian::kJis78:
- features->push_back(jp78);
- break;
- case FontVariantEastAsian::kJis83:
- features->push_back(jp83);
- break;
- case FontVariantEastAsian::kJis90:
- features->push_back(jp90);
- break;
- case FontVariantEastAsian::kJis04:
- features->push_back(jp04);
- break;
- case FontVariantEastAsian::kSimplified:
- features->push_back(smpl);
- break;
- case FontVariantEastAsian::kTraditional:
- features->push_back(trad);
- break;
- default:
- NOTREACHED();
- }
- static constexpr hb_feature_t fwid =
- CreateFeature(HB_TAG('f', 'w', 'i', 'd'), 1);
- static constexpr hb_feature_t pwid =
- CreateFeature(HB_TAG('p', 'w', 'i', 'd'), 1);
- switch (east_asian.Width()) {
- case FontVariantEastAsian::kNormalWidth:
- break;
- case FontVariantEastAsian::kFullWidth:
- features->push_back(fwid);
- break;
- case FontVariantEastAsian::kProportionalWidth:
- features->push_back(pwid);
- break;
- default:
- NOTREACHED();
- }
- static constexpr hb_feature_t ruby =
- CreateFeature(HB_TAG('r', 'u', 'b', 'y'), 1);
- if (east_asian.Ruby())
- features->push_back(ruby);
- }
-
- // font-variant-numeric:
- static constexpr hb_feature_t lnum =
- CreateFeature(HB_TAG('l', 'n', 'u', 'm'), 1);
- if (description.VariantNumeric().NumericFigureValue() ==
- FontVariantNumeric::kLiningNums)
- features->push_back(lnum);
-
- static constexpr hb_feature_t onum =
- CreateFeature(HB_TAG('o', 'n', 'u', 'm'), 1);
- if (description.VariantNumeric().NumericFigureValue() ==
- FontVariantNumeric::kOldstyleNums)
- features->push_back(onum);
-
- static constexpr hb_feature_t pnum =
- CreateFeature(HB_TAG('p', 'n', 'u', 'm'), 1);
- if (description.VariantNumeric().NumericSpacingValue() ==
- FontVariantNumeric::kProportionalNums)
- features->push_back(pnum);
- static constexpr hb_feature_t tnum =
- CreateFeature(HB_TAG('t', 'n', 'u', 'm'), 1);
- if (description.VariantNumeric().NumericSpacingValue() ==
- FontVariantNumeric::kTabularNums)
- features->push_back(tnum);
-
- static constexpr hb_feature_t afrc =
- CreateFeature(HB_TAG('a', 'f', 'r', 'c'), 1);
- if (description.VariantNumeric().NumericFractionValue() ==
- FontVariantNumeric::kStackedFractions)
- features->push_back(afrc);
- static constexpr hb_feature_t frac =
- CreateFeature(HB_TAG('f', 'r', 'a', 'c'), 1);
- if (description.VariantNumeric().NumericFractionValue() ==
- FontVariantNumeric::kDiagonalFractions)
- features->push_back(frac);
-
- static constexpr hb_feature_t ordn =
- CreateFeature(HB_TAG('o', 'r', 'd', 'n'), 1);
- if (description.VariantNumeric().OrdinalValue() ==
- FontVariantNumeric::kOrdinalOn)
- features->push_back(ordn);
-
- static constexpr hb_feature_t zero =
- CreateFeature(HB_TAG('z', 'e', 'r', 'o'), 1);
- if (description.VariantNumeric().SlashedZeroValue() ==
- FontVariantNumeric::kSlashedZeroOn)
- features->push_back(zero);
-
- FontFeatureSettings* settings = description.FeatureSettings();
- if (!settings)
- return;
-
- // TODO(drott): crbug.com/450619 Implement feature resolution instead of
- // just appending the font-feature-settings.
- unsigned num_features = settings->size();
- for (unsigned i = 0; i < num_features; ++i) {
- hb_feature_t feature;
- feature.tag = settings->at(i).Tag();
- feature.value = settings->at(i).Value();
- feature.start = 0;
- feature.end = static_cast<unsigned>(-1);
- features->push_back(feature);
- }
-}
-
inline RangeData CreateRangeData(const Font* font,
TextDirection direction,
hb_buffer_t* buffer) {
@@ -765,7 +585,7 @@ inline RangeData CreateRangeData(const Font* font,
range_data.buffer = buffer;
range_data.font = font;
range_data.text_direction = direction;
- SetFontFeatures(font, &range_data.font_features);
+ range_data.font_features.Initialize(font->GetFontDescription());
return range_data;
}
@@ -773,7 +593,7 @@ class CapsFeatureSettingsScopedOverlay final {
STACK_ALLOCATED();
public:
- CapsFeatureSettingsScopedOverlay(FeaturesVector*,
+ CapsFeatureSettingsScopedOverlay(FontFeatures*,
FontDescription::FontVariantCaps);
CapsFeatureSettingsScopedOverlay() = delete;
~CapsFeatureSettingsScopedOverlay();
@@ -781,12 +601,12 @@ class CapsFeatureSettingsScopedOverlay final {
private:
void OverlayCapsFeatures(FontDescription::FontVariantCaps);
void PrependCounting(const hb_feature_t&);
- FeaturesVector* features_;
+ FontFeatures* features_;
wtf_size_t count_features_;
};
CapsFeatureSettingsScopedOverlay::CapsFeatureSettingsScopedOverlay(
- FeaturesVector* features,
+ FontFeatures* features,
FontDescription::FontVariantCaps variant_caps)
: features_(features), count_features_(0) {
OverlayCapsFeatures(variant_caps);
@@ -794,18 +614,12 @@ CapsFeatureSettingsScopedOverlay::CapsFeatureSettingsScopedOverlay(
void CapsFeatureSettingsScopedOverlay::OverlayCapsFeatures(
FontDescription::FontVariantCaps variant_caps) {
- static constexpr hb_feature_t smcp =
- CreateFeature(HB_TAG('s', 'm', 'c', 'p'), 1);
- static constexpr hb_feature_t pcap =
- CreateFeature(HB_TAG('p', 'c', 'a', 'p'), 1);
- static constexpr hb_feature_t c2sc =
- CreateFeature(HB_TAG('c', '2', 's', 'c'), 1);
- static constexpr hb_feature_t c2pc =
- CreateFeature(HB_TAG('c', '2', 'p', 'c'), 1);
- static constexpr hb_feature_t unic =
- CreateFeature(HB_TAG('u', 'n', 'i', 'c'), 1);
- static constexpr hb_feature_t titl =
- CreateFeature(HB_TAG('t', 'i', 't', 'l'), 1);
+ static constexpr hb_feature_t smcp = CreateFeature('s', 'm', 'c', 'p', 1);
+ static constexpr hb_feature_t pcap = CreateFeature('p', 'c', 'a', 'p', 1);
+ static constexpr hb_feature_t c2sc = CreateFeature('c', '2', 's', 'c', 1);
+ static constexpr hb_feature_t c2pc = CreateFeature('c', '2', 'p', 'c', 1);
+ static constexpr hb_feature_t unic = CreateFeature('u', 'n', 'i', 'c', 1);
+ static constexpr hb_feature_t titl = CreateFeature('t', 'i', 't', 'l', 1);
if (variant_caps == FontDescription::kSmallCaps ||
variant_caps == FontDescription::kAllSmallCaps) {
PrependCounting(smcp);
@@ -830,7 +644,7 @@ void CapsFeatureSettingsScopedOverlay::OverlayCapsFeatures(
void CapsFeatureSettingsScopedOverlay::PrependCounting(
const hb_feature_t& feature) {
- features_->push_front(feature);
+ features_->Insert(feature);
count_features_++;
}
@@ -940,7 +754,7 @@ void HarfBuzzShaper::ShapeSegment(
CanvasRotationInVertical canvas_rotation =
CanvasRotationForRun(adjusted_font->PlatformData().Orientation(),
- segment.render_orientation);
+ segment.render_orientation, font_description);
CapsFeatureSettingsScopedOverlay caps_overlay(
&range_data->font_features,
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
index 43c6f6df4ff..5b8739912cf 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
@@ -268,4 +268,58 @@ TEST_F(RunSegmenterTest, StartOffset) {
VerifyRuns(&run_segmenter, expect);
}
+TEST_F(RunSegmenterTest, CJKBracketsAfterLatinLetter) {
+ CheckRunsHorizontal(
+ {{"A", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {"\u300C" // CJK LEFT CORNER BRACKET
+ "\u56FD" // CJK UNIFIED IDEOGRAPH
+ "\u300D", // CJK RIGHT CORNER BRACKET
+ USCRIPT_HAN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText}});
+}
+
+TEST_F(RunSegmenterTest, CJKBracketsAfterLatinParenthesis) {
+ CheckRunsHorizontal(
+ {{"A(", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {"\u300C" // CJK LEFT CORNER BRACKET
+ "\u56FD" // CJK UNIFIED IDEOGRAPH
+ "\u300D", // CJK RIGHT CORNER BRACKET
+ USCRIPT_HAN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {")", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText}});
+}
+
+TEST_F(RunSegmenterTest, CJKBracketsWithLatinParenthesisInside) {
+ CheckRunsHorizontal(
+ {{"A", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {"\u300C" // CJK LEFT CORNER BRACKET
+ "\u56FD" // CJK UNIFIED IDEOGRAPH
+ "(",
+ USCRIPT_HAN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {"A", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {")"
+ "\u300D", // CJK RIGHT CORNER BRACKET
+ USCRIPT_HAN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText}});
+}
+
+TEST_F(RunSegmenterTest, CJKBracketsAfterUnmatchingLatinParenthesis) {
+ CheckRunsHorizontal(
+ {{"A((", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {"\u300C" // CJK LEFT CORNER BRACKET
+ "\u56FD" // CJK UNIFIED IDEOGRAPH
+ "\u300D", // CJK RIGHT CORNER BRACKET
+ USCRIPT_HAN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText},
+ {")", USCRIPT_LATIN, OrientationIterator::kOrientationKeep,
+ FontFallbackPriority::kText}});
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 93a50012738..adc10795ccc 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -63,6 +63,18 @@ struct SameSizeAsHarfBuzzRunGlyphData {
ASSERT_SIZE(HarfBuzzRunGlyphData, SameSizeAsHarfBuzzRunGlyphData);
+struct SameSizeAsRunInfo : public RefCounted<SameSizeAsRunInfo> {
+ struct GlyphDataCollection {
+ void* pointers[2];
+ unsigned integer;
+ } glyph_data;
+ void* pointer;
+ Vector<int> vector;
+ int integers[6];
+};
+
+ASSERT_SIZE(ShapeResult::RunInfo, SameSizeAsRunInfo);
+
struct SameSizeAsShapeResult : public RefCounted<SameSizeAsShapeResult> {
float floats[5];
Vector<int> vector;
@@ -75,7 +87,7 @@ ASSERT_SIZE(ShapeResult, SameSizeAsShapeResult);
unsigned ShapeResult::RunInfo::NextSafeToBreakOffset(unsigned offset) const {
DCHECK_LE(offset, num_characters_);
- if (!Rtl()) {
+ if (IsLtr()) {
for (const auto& glyph_data : glyph_data_) {
if (glyph_data.safe_to_break_before &&
glyph_data.character_index >= offset)
@@ -97,7 +109,7 @@ unsigned ShapeResult::RunInfo::PreviousSafeToBreakOffset(
unsigned offset) const {
if (offset >= num_characters_)
return num_characters_;
- if (!Rtl()) {
+ if (IsLtr()) {
for (const auto& glyph_data : base::Reversed(glyph_data_)) {
if (glyph_data.safe_to_break_before &&
glyph_data.character_index <= offset)
@@ -119,7 +131,7 @@ float ShapeResult::RunInfo::XPositionForVisualOffset(
unsigned offset,
AdjustMidCluster adjust_mid_cluster) const {
DCHECK_LT(offset, num_characters_);
- if (Rtl())
+ if (IsRtl())
offset = num_characters_ - offset - 1;
return XPositionForOffset(offset, adjust_mid_cluster);
}
@@ -191,7 +203,7 @@ float ShapeResult::RunInfo::XPositionForOffset(
// the accumulated advance up to the current glyph sequence.
float accumulated_position = 0;
- if (!Rtl()) {
+ if (IsLtr()) {
for (unsigned i = 0; i < num_glyphs; ++i) {
unsigned current_glyph_char_index = glyph_data_[i].character_index;
// If this glyph is still part of the same glyph sequence for the grapheme
@@ -259,7 +271,7 @@ float ShapeResult::RunInfo::XPositionForOffset(
unsigned place = graphemes * pos / size;
pos -= place;
glyph_sequence_advance = glyph_sequence_advance / graphemes;
- if (Rtl()) {
+ if (IsRtl()) {
accumulated_position += glyph_sequence_advance * (graphemes - place - 1);
} else {
accumulated_position += glyph_sequence_advance * place;
@@ -270,14 +282,14 @@ float ShapeResult::RunInfo::XPositionForOffset(
// offset is not at the beginning, we need to jump to the right side of the
// grapheme. On RTL, if we want AdjustToStart and offset is not at the end, we
// need to jump to the left side of the grapheme.
- if (!Rtl() && adjust_mid_cluster == AdjustMidCluster::kToEnd && pos != 0) {
+ if (IsLtr() && adjust_mid_cluster == AdjustMidCluster::kToEnd && pos != 0) {
accumulated_position += glyph_sequence_advance;
- } else if (Rtl() && adjust_mid_cluster == AdjustMidCluster::kToEnd &&
+ } else if (IsRtl() && adjust_mid_cluster == AdjustMidCluster::kToEnd &&
pos != 0) {
accumulated_position -= glyph_sequence_advance;
}
- if (Rtl()) {
+ if (IsRtl()) {
// For RTL, we return the right side.
accumulated_position += glyph_sequence_advance;
}
@@ -303,7 +315,7 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
result->advance = 0.0;
// on RTL, we start on the last index.
- if (Rtl()) {
+ if (IsRtl()) {
glyph_sequence_start = glyph_sequence_end = num_characters_;
}
@@ -319,14 +331,14 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
// Since we are about to move to the next sequence of glyphs, check if
// the target falls inside it, if it does, we found our sequence.
if (result->origin_x + result->advance > target_x) {
- if (!Rtl()) {
+ if (IsLtr()) {
glyph_sequence_end = current_glyph_char_index;
}
break;
}
// Move to the next sequence, update accumulated_x.
- if (Rtl()) {
+ if (IsRtl()) {
// Notice that on RTL, as we move to our next sequence, we already know
// both bounds. Nonetheless, we still need to move forward so we can
// capture all glyphs of this sequence.
@@ -350,7 +362,7 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
unsigned glyph_length = glyph_sequence_end - glyph_sequence_start;
unsigned final_size = floor(glyph_length / graphemes);
result->origin_x += unit_size * step;
- if (!Rtl()) {
+ if (IsLtr()) {
glyph_sequence_start += step;
glyph_sequence_end = glyph_sequence_start + final_size;
} else {
@@ -361,7 +373,7 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition(
}
}
- if (!Rtl()) {
+ if (IsLtr()) {
result->left_character_index = glyph_sequence_start;
result->right_character_index = glyph_sequence_end;
} else {
@@ -414,6 +426,24 @@ size_t ShapeResult::ByteSize() const {
return self_byte_size;
}
+bool ShapeResult::IsStartSafeToBreak() const {
+ // Empty is likely a |SubRange| at the middle of a cluster or a ligature.
+ if (UNLIKELY(runs_.IsEmpty()))
+ return false;
+ const RunInfo* run = nullptr;
+ const HarfBuzzRunGlyphData* glyph_data = nullptr;
+ if (IsLtr()) {
+ run = runs_.front().get();
+ glyph_data = &run->glyph_data_.front();
+ } else {
+ run = runs_.back().get();
+ glyph_data = &run->glyph_data_.back();
+ }
+ return glyph_data->safe_to_break_before &&
+ // If the glyph for the first character is missing, consider not safe.
+ StartIndex() == run->start_index_ + glyph_data->character_index;
+}
+
unsigned ShapeResult::NextSafeToBreakOffset(unsigned index) const {
for (auto* it = runs_.begin(); it != runs_.end(); ++it) {
const auto& run = *it;
@@ -426,13 +456,13 @@ unsigned ShapeResult::NextSafeToBreakOffset(unsigned index) const {
if (offset <= run->num_characters_) {
return run->NextSafeToBreakOffset(offset) + run_start;
}
- if (Rtl()) {
+ if (IsRtl()) {
if (it == runs_.begin())
return run_start + run->num_characters_;
const auto& previous_run = *--it;
return previous_run->start_index_;
}
- } else if (!Rtl()) {
+ } else if (IsLtr()) {
return run_start;
}
}
@@ -452,10 +482,10 @@ unsigned ShapeResult::PreviousSafeToBreakOffset(unsigned index) const {
if (offset <= run->num_characters_) {
return run->PreviousSafeToBreakOffset(offset) + run_start;
}
- if (!Rtl()) {
+ if (IsLtr()) {
return run_start + run->num_characters_;
}
- } else if (Rtl()) {
+ } else if (IsRtl()) {
if (it == runs_.rbegin())
return run->start_index_;
const auto& previous_run = *--it;
@@ -472,21 +502,21 @@ void ShapeResult::OffsetForPosition(float target_x,
BreakGlyphsOption break_glyphs_option,
GlyphIndexResult* result) const {
if (target_x <= 0) {
- if (Rtl()) {
+ if (IsRtl()) {
result->left_character_index = result->right_character_index =
NumCharacters();
}
return;
}
- unsigned characters_so_far = Rtl() ? NumCharacters() : 0;
+ unsigned characters_so_far = IsRtl() ? NumCharacters() : 0;
float current_x = 0;
for (const scoped_refptr<RunInfo>& run_ptr : runs_) {
const RunInfo* run = run_ptr.get();
if (!run)
continue;
- if (Rtl())
+ if (IsRtl())
characters_so_far -= run->num_characters_;
float next_x = current_x + run->width_;
float offset_for_run = target_x - current_x;
@@ -495,7 +525,7 @@ void ShapeResult::OffsetForPosition(float target_x,
run->CharacterIndexForXPosition(offset_for_run, break_glyphs_option,
result);
result->characters_on_left_runs = characters_so_far;
- if (Rtl()) {
+ if (IsRtl()) {
result->left_character_index =
characters_so_far + result->left_character_index;
result->right_character_index =
@@ -511,12 +541,12 @@ void ShapeResult::OffsetForPosition(float target_x,
result->origin_x += current_x;
return;
}
- if (!Rtl())
+ if (IsLtr())
characters_so_far += run->num_characters_;
current_x = next_x;
}
- if (Rtl()) {
+ if (IsRtl()) {
result->left_character_index = 0;
result->right_character_index = 0;
} else {
@@ -537,7 +567,7 @@ unsigned ShapeResult::OffsetForPosition(
OffsetForPosition(x, break_glyphs_option, &result);
// For LTR, the offset is always the left one.
- if (!Rtl())
+ if (IsLtr())
return result.left_character_index;
// For RTL the offset is the right one, except that the interval is open
@@ -567,7 +597,7 @@ unsigned ShapeResult::OffsetToFit(float x, TextDirection line_direction) const {
GlyphIndexResult result;
OffsetForPosition(x, DontBreakGlyphs, &result);
- if (IsLtr(line_direction))
+ if (blink::IsLtr(line_direction))
return result.left_character_index;
if (x == result.origin_x)
@@ -586,7 +616,7 @@ float ShapeResult::PositionForOffset(
// current run.
unsigned offset = absolute_offset;
- if (Rtl()) {
+ if (IsRtl()) {
// Convert logical offsets to visual offsets, because results are in
// logical order while runs are in visual order.
x = width_;
@@ -598,7 +628,7 @@ float ShapeResult::PositionForOffset(
for (unsigned i = 0; i < runs_.size(); i++) {
if (!runs_[i])
continue;
- DCHECK_EQ(Rtl(), runs_[i]->Rtl());
+ DCHECK_EQ(IsRtl(), runs_[i]->IsRtl());
unsigned num_characters = runs_[i]->num_characters_;
if (!offset_x && offset < num_characters) {
@@ -613,7 +643,7 @@ float ShapeResult::PositionForOffset(
// The position in question might be just after the text.
if (!offset_x && absolute_offset == NumCharacters())
- return Rtl() ? 0 : width_;
+ return IsRtl() ? 0 : width_;
return offset_x;
}
@@ -693,7 +723,7 @@ float ShapeResult::ForEachGlyphImpl(float initial_advance,
bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run.direction_);
const SimpleFontData* font_data = run.font_data_.get();
- if (!run.Rtl()) { // Left-to-right
+ if (run.IsLtr()) { // Left-to-right
for (const auto& glyph_data : run.glyph_data_) {
const unsigned character_index = run_start + glyph_data.character_index;
if (character_index >= to)
@@ -862,11 +892,13 @@ void ShapeResult::ApplySpacingImpl(
}
typename ShapeResultSpacing<TextContainerType>::ComputeSpacingParameters
- parameters{.index = run_start_index + glyph_data.character_index,
- .advance_override = run->font_data_->GetAdvanceOverride(),
- .original_advance = glyph_data.advance,
- .advance_proportional_override =
- run->font_data_->GetAdvanceProportionalOverride()};
+ parameters{
+ .index = run_start_index + glyph_data.character_index,
+ .original_advance = glyph_data.advance,
+ .advance_override =
+ IsCanvasRotationInVerticalUpright(run->canvas_rotation_)
+ ? run->font_data_->GetAdvanceOverrideVerticalUpright()
+ : run->font_data_->GetAdvanceOverride()};
space = spacing.ComputeSpacing(parameters, offset);
glyph_data.advance += space;
total_space_for_run += space;
@@ -1175,7 +1207,7 @@ ShapeResult::RunInfo* ShapeResult::InsertRunForTesting(
TextDirection direction,
Vector<uint16_t> safe_break_offsets) {
auto run = RunInfo::Create(
- nullptr, IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL,
+ nullptr, blink::IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL,
CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, start_index,
num_characters, num_characters);
for (unsigned i = 0; i < run->glyph_data_.size(); i++) {
@@ -1184,7 +1216,7 @@ ShapeResult::RunInfo* ShapeResult::InsertRunForTesting(
for (uint16_t offset : safe_break_offsets)
run->glyph_data_[offset].safe_to_break_before = true;
// RTL runs have glyphs in the descending order of character_index.
- if (Rtl())
+ if (IsRtl())
run->glyph_data_.Reverse();
num_glyphs_ += run->NumGlyphs();
RunInfo* run_ptr = run.get();
@@ -1197,7 +1229,7 @@ ShapeResult::RunInfo* ShapeResult::InsertRunForTesting(
// Runs in RTL result are in visual order, and that new runs should be
// prepended. This function adjusts the run order after runs were appended.
void ShapeResult::ReorderRtlRuns(unsigned run_size_before) {
- DCHECK(Rtl());
+ DCHECK(IsRtl());
DCHECK_GT(runs_.size(), run_size_before);
if (runs_.size() == run_size_before + 1) {
if (!run_size_before)
@@ -1235,7 +1267,7 @@ void ShapeResult::CopyRanges(const ShapeRange* ranges,
// Ranges are in logical order so for RTL the ranges are proccessed back to
// front to ensure that they're in a sequential visual order with regards to
// the runs.
- if (Rtl()) {
+ if (IsRtl()) {
unsigned run_index = 0;
unsigned last_range = num_ranges - 1;
for (unsigned i = 0; i < num_ranges; i++) {
@@ -1302,22 +1334,23 @@ unsigned ShapeResult::CopyRangeInternal(unsigned run_index,
unsigned end = std::min(end_offset, run_end) - run_start;
DCHECK(end > start);
- auto sub_run = run->CreateSubRun(start, end);
- sub_run->start_index_ += index_diff;
- target->width_ += sub_run->width_;
- target->num_glyphs_ += sub_run->glyph_data_.size();
- if (auto merged_run =
- should_merge ? target->runs_.back()->MergeIfPossible(*sub_run)
- : scoped_refptr<RunInfo>()) {
- target->runs_.back() = std::move(merged_run);
- } else {
- target->runs_.push_back(std::move(sub_run));
+ if (scoped_refptr<RunInfo> sub_run = run->CreateSubRun(start, end)) {
+ sub_run->start_index_ += index_diff;
+ target->width_ += sub_run->width_;
+ target->num_glyphs_ += sub_run->glyph_data_.size();
+ if (auto merged_run =
+ should_merge ? target->runs_.back()->MergeIfPossible(*sub_run)
+ : scoped_refptr<RunInfo>()) {
+ target->runs_.back() = std::move(merged_run);
+ } else {
+ target->runs_.push_back(std::move(sub_run));
+ }
}
should_merge = false;
// No need to process runs after the end of the range.
- if ((!Rtl() && end_offset <= run_end) ||
- (Rtl() && start_offset >= run_start)) {
+ if ((IsLtr() && end_offset <= run_end) ||
+ (IsRtl() && start_offset >= run_start)) {
break;
}
}
@@ -1329,8 +1362,8 @@ unsigned ShapeResult::CopyRangeInternal(unsigned run_index,
// Runs in RTL result are in visual order, and that new runs should be
// prepended. Reorder appended runs.
- DCHECK_EQ(Rtl(), target->Rtl());
- if (UNLIKELY(Rtl() && target->runs_.size() != target_run_size_before))
+ DCHECK_EQ(IsRtl(), target->IsRtl());
+ if (UNLIKELY(IsRtl() && target->runs_.size() != target_run_size_before))
target->ReorderRtlRuns(target_run_size_before);
target->has_vertical_offsets_ |= has_vertical_offsets_;
@@ -1384,7 +1417,7 @@ void ShapeResult::CheckConsistency() const {
const unsigned start_index = StartIndex();
unsigned index = start_index;
unsigned num_glyphs = 0;
- if (!Rtl()) {
+ if (IsLtr()) {
for (const auto& run : runs_) {
// Characters maybe missing, but must be in increasing order.
DCHECK_GE(run->start_index_, index);
@@ -1436,7 +1469,7 @@ scoped_refptr<ShapeResult> ShapeResult::CreateForTabulationCharacters(
// Tab characters are always LTR or RTL, not TTB, even when
// isVerticalAnyUpright().
hb_direction_t hb_direction =
- IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL;
+ blink::IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL;
// Only the advance of the first tab is affected by |position|.
float advance = font->TabWidth(font_data, tab_size, position);
do {
@@ -1477,7 +1510,7 @@ scoped_refptr<ShapeResult> ShapeResult::CreateForSpaces(const Font* font,
result->has_vertical_offsets_ =
font_data->PlatformData().IsVerticalAnyUpright();
hb_direction_t hb_direction =
- IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL;
+ blink::IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL;
scoped_refptr<ShapeResult::RunInfo> run = RunInfo::Create(
font_data, hb_direction, CanvasRotationInVertical::kRegular,
HB_SCRIPT_COMMON, start_index, length, length);
@@ -1643,7 +1676,7 @@ void ShapeResult::ComputePositionData() const {
// Assumes all runs have the same directionality as the ShapeResult so that
// |x_position| is in ascending order.
- DCHECK_EQ(Rtl(), run->Rtl());
+ DCHECK_EQ(IsRtl(), run->IsRtl());
float total_advance = run_advance;
for (const auto& glyph_data : run->glyph_data_) {
@@ -1714,7 +1747,7 @@ void ShapeResult::DiscardPositionData() const {
unsigned ShapeResult::CachedOffsetForPosition(float x) const {
DCHECK(character_position_);
- unsigned offset = character_position_->OffsetForPosition(x, Rtl());
+ unsigned offset = character_position_->OffsetForPosition(x, IsRtl());
#if 0
// TODO(kojii): This DCHECK fails in ~10 tests. Needs investigations.
DCHECK_EQ(OffsetForPosition(x, BreakGlyphsOption::DontBreakGlyphs), offset) << x;
@@ -1726,7 +1759,7 @@ float ShapeResult::CachedPositionForOffset(unsigned offset) const {
DCHECK_GE(offset, 0u);
DCHECK_LE(offset, num_characters_);
DCHECK(character_position_);
- float position = character_position_->PositionForOffset(offset, Rtl());
+ float position = character_position_->PositionForOffset(offset, IsRtl());
#if 0
// TODO(kojii): This DCHECK fails in several tests. Needs investigations.
DCHECK_EQ(PositionForOffset(offset), position) << offset;
@@ -1735,7 +1768,7 @@ float ShapeResult::CachedPositionForOffset(unsigned offset) const {
}
unsigned ShapeResult::CachedNextSafeToBreakOffset(unsigned offset) const {
- if (Rtl())
+ if (IsRtl())
return NextSafeToBreakOffset(offset);
DCHECK(character_position_);
@@ -1743,7 +1776,7 @@ unsigned ShapeResult::CachedNextSafeToBreakOffset(unsigned offset) const {
}
unsigned ShapeResult::CachedPreviousSafeToBreakOffset(unsigned offset) const {
- if (Rtl())
+ if (IsRtl())
return PreviousSafeToBreakOffset(offset);
DCHECK(character_position_);
@@ -1859,13 +1892,13 @@ void AddRunInfoRanges(const ShapeResult::RunInfo& run_info,
for (const auto& glyph : run_info.glyph_data_)
character_widths[glyph.character_index] += glyph.advance;
- if (run_info.Rtl())
+ if (run_info.IsRtl())
offset += run_info.width_;
for (unsigned character_index = 0; character_index < run_info.num_characters_;
character_index++) {
float start = offset;
- offset += character_widths[character_index] * (run_info.Rtl() ? -1 : 1);
+ offset += character_widths[character_index] * (run_info.IsRtl() ? -1 : 1);
float end = offset;
// To match getCharacterRange we flip ranges to ensure start <= end.
@@ -1883,7 +1916,7 @@ float ShapeResult::IndividualCharacterRanges(Vector<CharacterRange>* ranges,
DCHECK(ranges);
float current_x = start_x;
- if (Rtl()) {
+ if (IsRtl()) {
unsigned run_count = runs_.size();
for (int index = run_count - 1; index >= 0; index--) {
current_x -= runs_[index]->width_;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 327fff59e34..a733598210e 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -173,7 +173,8 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
TextDirection Direction() const {
return static_cast<TextDirection>(direction_);
}
- bool Rtl() const { return Direction() == TextDirection::kRtl; }
+ bool IsLtr() const { return blink::IsLtr(Direction()); }
+ bool IsRtl() const { return blink::IsRtl(Direction()); }
// True if at least one glyph in this result has vertical offsets.
//
@@ -187,6 +188,9 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
// For memory reporting.
size_t ByteSize() const;
+ // True if |StartIndex()| is safe to break.
+ bool IsStartSafeToBreak() const;
+
// Returns the next or previous offsets respectively at which it is safe to
// break without reshaping.
// The |offset| given and the return value is for the original string, between
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
index 0e7076943b2..2d2d0f79064 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
@@ -96,8 +96,7 @@ inline void AddEmphasisMark(ShapeResultBloberizer& bloberizer,
bool is_vertical =
emphasis_font_data->PlatformData().IsVerticalAnyUpright() &&
- emphasis_data.canvas_rotation ==
- CanvasRotationInVertical::kRotateCanvasUpright;
+ IsCanvasRotationInVerticalUpright(emphasis_data.canvas_rotation);
if (!is_vertical) {
bloberizer.Add(emphasis_data.glyph, emphasis_font_data,
@@ -105,8 +104,7 @@ inline void AddEmphasisMark(ShapeResultBloberizer& bloberizer,
mid_glyph_offset - glyph_center.X());
} else {
bloberizer.Add(
- emphasis_data.glyph, emphasis_font_data,
- CanvasRotationInVertical::kRotateCanvasUpright,
+ emphasis_data.glyph, emphasis_font_data, emphasis_data.canvas_rotation,
FloatPoint(-glyph_center.X(), mid_glyph_offset - glyph_center.Y()));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
index 2dc99db0004..f58ce13eae8 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
@@ -57,7 +57,8 @@ class PLATFORM_EXPORT ShapeResultBloberizer {
CommitPendingRun();
pending_font_data_ = font_data;
pending_canvas_rotation_ = canvas_rotation;
- DCHECK_EQ(canvas_rotation, CanvasRotationInVertical::kRegular);
+ DCHECK(!IsCanvasRotationInVerticalUpright(canvas_rotation))
+ << static_cast<int>(canvas_rotation);
}
pending_glyphs_.push_back(glyph);
@@ -77,7 +78,7 @@ class PLATFORM_EXPORT ShapeResultBloberizer {
pending_font_data_ = font_data;
pending_canvas_rotation_ = canvas_rotation;
pending_vertical_baseline_x_offset_ =
- canvas_rotation == CanvasRotationInVertical::kRegular
+ !IsCanvasRotationInVerticalUpright(canvas_rotation)
? 0
: font_data->GetFontMetrics().FloatAscent() -
font_data->GetFontMetrics().FloatAscent(
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
index 758065226be..e51374bf269 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
@@ -69,7 +69,7 @@ CharacterRange ShapeResultBuffer::GetCharacterRange(
for (unsigned i = 0; i < result->runs_.size(); i++) {
if (!result->runs_[i])
continue;
- DCHECK_EQ(direction == TextDirection::kRtl, result->runs_[i]->Rtl());
+ DCHECK_EQ(direction == TextDirection::kRtl, result->runs_[i]->IsRtl());
int num_characters = result->runs_[i]->num_characters_;
if (!found_from_x && from >= 0 && from < num_characters) {
from_x = result->runs_[i]->XPositionForVisualOffset(
@@ -141,14 +141,14 @@ void ShapeResultBuffer::AddRunInfoAdvances(const ShapeResult::RunInfo& run_info,
const unsigned num_glyphs = run_info.glyph_data_.size();
const unsigned num_chars = run_info.num_characters_;
- if (run_info.Rtl())
+ if (run_info.IsRtl())
offset += run_info.width_;
double current_width = 0;
for (unsigned glyph_id = 0; glyph_id < num_glyphs; glyph_id++) {
- unsigned gid = run_info.Rtl() ? num_glyphs - glyph_id - 1 : glyph_id;
+ unsigned gid = run_info.IsRtl() ? num_glyphs - glyph_id - 1 : glyph_id;
unsigned next_gid =
- run_info.Rtl() ? num_glyphs - glyph_id - 2 : glyph_id + 1;
+ run_info.IsRtl() ? num_glyphs - glyph_id - 2 : glyph_id + 1;
const HarfBuzzRunGlyphData& glyph = run_info.glyph_data_[gid];
unsigned char_id = glyph.character_index;
@@ -165,19 +165,19 @@ void ShapeResultBuffer::AddRunInfoAdvances(const ShapeResult::RunInfo& run_info,
unsigned num_graphemes = run_info.NumGraphemes(char_id, next_char_id);
for (unsigned i = char_id; i < next_char_id; i++) {
- if (run_info.Rtl()) {
+ if (run_info.IsRtl()) {
advances.push_back(offset - (current_width / num_graphemes));
} else {
advances.push_back(offset);
}
if (num_graphemes == next_char_id - char_id) {
- offset += (current_width / num_graphemes) * (run_info.Rtl() ? -1 : 1);
+ offset += (current_width / num_graphemes) * (run_info.IsRtl() ? -1 : 1);
}
}
if (num_graphemes != next_char_id - char_id) {
- offset += current_width * (run_info.Rtl() ? -1 : 1);
+ offset += current_width * (run_info.IsRtl() ? -1 : 1);
}
current_width = 0;
@@ -198,7 +198,7 @@ Vector<double> ShapeResultBuffer::IndividualCharacterAdvances(
result->EnsureGraphemes(
StringView(text, character_offset, result->NumCharacters()));
- if (result->Rtl()) {
+ if (result->IsRtl()) {
for (int index = run_count - 1; index >= 0; index--) {
current_x -= result->runs_[index]->width_;
AddRunInfoAdvances(*result->runs_[index], current_x, advances);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
index c13257b8af8..68d3ca9e254 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -98,29 +98,30 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
unsigned start_index,
unsigned num_glyphs,
unsigned num_characters)
- : font_data_(const_cast<SimpleFontData*>(font)),
- direction_(dir),
- canvas_rotation_(canvas_rotation),
- script_(script),
- glyph_data_(
+ : glyph_data_(
std::min(num_glyphs, HarfBuzzRunGlyphData::kMaxCharacterIndex + 1)),
+ font_data_(const_cast<SimpleFontData*>(font)),
start_index_(start_index),
num_characters_(num_characters),
- width_(0.0f) {}
+ width_(0.0f),
+ script_(script),
+ direction_(dir),
+ canvas_rotation_(canvas_rotation) {}
RunInfo(const RunInfo& other)
- : font_data_(other.font_data_),
- direction_(other.direction_),
- canvas_rotation_(other.canvas_rotation_),
- script_(other.script_),
- glyph_data_(other.glyph_data_),
+ : glyph_data_(other.glyph_data_),
+ font_data_(other.font_data_),
graphemes_(other.graphemes_),
start_index_(other.start_index_),
num_characters_(other.num_characters_),
- width_(other.width_) {}
+ width_(other.width_),
+ script_(other.script_),
+ direction_(other.direction_),
+ canvas_rotation_(other.canvas_rotation_) {}
unsigned NumGlyphs() const { return glyph_data_.size(); }
- bool Rtl() const { return HB_DIRECTION_IS_BACKWARD(direction_); }
+ bool IsLtr() const { return HB_DIRECTION_IS_FORWARD(direction_); }
+ bool IsRtl() const { return HB_DIRECTION_IS_BACKWARD(direction_); }
bool IsHorizontal() const { return HB_DIRECTION_IS_HORIZONTAL(direction_); }
CanvasRotationInVertical CanvasRotation() const { return canvas_rotation_; }
unsigned NextSafeToBreakOffset(unsigned) const;
@@ -163,17 +164,20 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
GlyphDataRange FindGlyphDataRange(unsigned start_character_index,
unsigned end_character_index) const {
GlyphDataRange range = GetGlyphDataRange().FindGlyphDataRange(
- Rtl(), start_character_index, end_character_index);
+ IsRtl(), start_character_index, end_character_index);
return range;
}
// Creates a new RunInfo instance representing a subset of the current run.
+ // Returns |nullptr| if there are no glyphs in the specified range.
scoped_refptr<RunInfo> CreateSubRun(unsigned start, unsigned end) {
DCHECK(end > start);
unsigned number_of_characters = std::min(end - start, num_characters_);
auto glyphs = FindGlyphDataRange(start, end);
unsigned number_of_glyphs =
static_cast<unsigned>(std::distance(glyphs.begin, glyphs.end));
+ if (UNLIKELY(!number_of_glyphs))
+ return nullptr;
auto run =
Create(font_data_.get(), direction_, canvas_rotation_, script_,
@@ -205,7 +209,7 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
num_characters_ + other.num_characters_);
// Note: We populate |graphemes_| on demand, e.g. hit testing.
const int index_adjust = other.start_index_ - start_index_;
- if (UNLIKELY(Rtl())) {
+ if (UNLIKELY(IsRtl())) {
run->glyph_data_.CopyFrom(other.glyph_data_, glyph_data_);
auto* const end = run->glyph_data_.begin() + other.glyph_data_.size();
for (auto* it = run->glyph_data_.begin(); it < end; ++it)
@@ -232,7 +236,7 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
}
void ExpandRangeToIncludePartialGlyphs(int offset, int* from, int* to) const {
- int start = !Rtl() ? offset : (offset + num_characters_);
+ int start = IsLtr() ? offset : (offset + num_characters_);
int end = offset + num_characters_;
for (unsigned i = 0; i < glyph_data_.size(); ++i) {
@@ -240,7 +244,7 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
if (start == index)
continue;
- if (!Rtl())
+ if (IsLtr())
end = index;
if (end > *from && start < *to) {
@@ -248,7 +252,7 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
*to = std::max(*to, end);
}
- if (!Rtl())
+ if (IsLtr())
end = offset + num_characters_;
else
end = start;
@@ -493,6 +497,15 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
unsigned size() const { return offsets_.size(); }
bool IsEmpty() const { return size() == 0; }
+ const HarfBuzzRunGlyphData& front() const {
+ CHECK(!IsEmpty());
+ return (*this)[0];
+ }
+ const HarfBuzzRunGlyphData& back() const {
+ CHECK(!IsEmpty());
+ return (*this)[size() - 1];
+ }
+
void Reverse() {
std::reverse(begin(), end());
offsets_.Reverse();
@@ -519,13 +532,8 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
GlyphOffsetArray offsets_;
};
- scoped_refptr<SimpleFontData> font_data_;
- hb_direction_t direction_;
- // For upright-in-vertical we need to tell the ShapeResultBloberizer to rotate
- // the canvas back 90deg for this RunInfo.
- CanvasRotationInVertical canvas_rotation_;
- hb_script_t script_;
GlyphDataCollection glyph_data_;
+ scoped_refptr<SimpleFontData> font_data_;
// graphemes_[i] is the number of graphemes up to (and including) the ith
// character in the run.
@@ -534,6 +542,13 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> {
unsigned start_index_;
unsigned num_characters_;
float width_;
+
+ hb_script_t script_;
+ hb_direction_t direction_;
+
+ // For upright-in-vertical we need to tell the ShapeResultBloberizer to rotate
+ // the canvas back 90deg for this RunInfo.
+ CanvasRotationInVertical canvas_rotation_;
};
// For non-zero glyph offset array
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
index eefbd4ebb02..326648748f7 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
@@ -137,12 +137,12 @@ float ShapeResultSpacing<TextContainerType>::ComputeSpacing(
float spacing = 0;
- bool has_letter_spacing = letter_spacing_ || parameters.advance_override ||
- (parameters.advance_proportional_override != 1.0);
+ bool has_letter_spacing =
+ letter_spacing_ || (parameters.advance_override != 1.0);
if (has_letter_spacing && !Character::TreatAsZeroWidthSpace(character)) {
- spacing += parameters.original_advance *
- (parameters.advance_proportional_override - 1.0) +
- letter_spacing_ + parameters.advance_override;
+ spacing +=
+ parameters.original_advance * (parameters.advance_override - 1.0) +
+ letter_spacing_;
}
if (treat_as_space && (index || character == kNoBreakSpaceCharacter))
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
index 5af754a255f..3e32be02701 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
@@ -64,9 +64,8 @@ class PLATFORM_EXPORT ShapeResultSpacing final {
// keeps states and counts consumed justification opportunities.
struct ComputeSpacingParameters {
unsigned index;
- float advance_override = 0.0;
float original_advance = 0.0;
- float advance_proportional_override = 1.0;
+ float advance_override = 1.0;
};
float ComputeSpacing(unsigned index, float& offset) {
return ComputeSpacing(ComputeSpacingParameters{.index = index}, offset);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
index 8dac0939e7b..dd6b2700ebb 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
@@ -251,6 +251,47 @@ TEST_F(ShapeResultTest, CopyRangeArabicMultiRun) {
TestCopyRangesArabic(result.get());
}
+static struct IsStartSafeToBreakData {
+ bool expected;
+ const char16_t* text;
+ TextDirection direction = TextDirection::kLtr;
+ unsigned start_offset = 0;
+ unsigned end_offset = 0;
+} is_start_safe_to_break_data[] = {
+ {true, u"XX", TextDirection::kLtr},
+ {true, u"XX", TextDirection::kRtl},
+ // SubRange, assuming there is no kerning between "XX".
+ {true, u"XX", TextDirection::kLtr, 1, 2},
+ {true, u"XX", TextDirection::kRtl, 1, 2},
+ // Between "A" and "V" usually have a kerning.
+ {false, u"AV", TextDirection::kLtr, 1, 2},
+ {false, u"AV", TextDirection::kRtl, 1, 2},
+ // SubRange at the middle of a cluster.
+ // U+06D7 ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA
+ {false, u" \u06D7", TextDirection::kLtr, 1, 2},
+ {false, u" \u06D7", TextDirection::kRtl, 1, 2},
+ {false, u" \u06D7.", TextDirection::kLtr, 1, 3},
+ {false, u" \u06D7.", TextDirection::kRtl, 1, 3},
+};
+
+class IsStartSafeToBreakDataTest
+ : public ShapeResultTest,
+ public testing::WithParamInterface<IsStartSafeToBreakData> {};
+
+INSTANTIATE_TEST_SUITE_P(ShapeResultTest,
+ IsStartSafeToBreakDataTest,
+ testing::ValuesIn(is_start_safe_to_break_data));
+
+TEST_P(IsStartSafeToBreakDataTest, IsStartSafeToBreakData) {
+ const IsStartSafeToBreakData data = GetParam();
+ String string(data.text);
+ HarfBuzzShaper shaper(string);
+ scoped_refptr<ShapeResult> result = shaper.Shape(&font, data.direction);
+ if (data.end_offset)
+ result = result->SubRange(data.start_offset, data.end_offset);
+ EXPECT_EQ(result->IsStartSafeToBreak(), data.expected);
+}
+
TEST_F(ShapeResultTest, ComputeInkBoundsWithZeroOffset) {
String string(u"abc");
HarfBuzzShaper shaper(string);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
index 24efa5bf803..c41eeae4d4c 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
@@ -51,13 +51,14 @@ struct ShapeResultView::RunInfoPart {
bool HasGlyphOffsets() const { return range_.offsets; }
// The end character index of |this| without considering offsets in
// |ShapeResultView|. This is analogous to:
- // GlyphAt(Rtl() ? -1 : NumGlyphs()).character_index
+ // GlyphAt(IsRtl() ? -1 : NumGlyphs()).character_index
// if such |HarfBuzzRunGlyphData| is available.
unsigned CharacterIndexOfEndGlyph() const {
return num_characters_ + offset_;
}
- bool Rtl() const { return run_->Rtl(); }
+ bool IsLtr() const { return run_->IsLtr(); }
+ bool IsRtl() const { return run_->IsRtl(); }
bool IsHorizontal() const { return run_->IsHorizontal(); }
unsigned NumCharacters() const { return num_characters_; }
unsigned NumGlyphs() const { return range_.end - range_.begin; }
@@ -73,8 +74,8 @@ struct ShapeResultView::RunInfoPart {
ShapeResult::RunInfo::GlyphDataRange FindGlyphDataRange(
unsigned start_character_index,
unsigned end_character_index) const {
- return GetGlyphDataRange().FindGlyphDataRange(Rtl(), start_character_index,
- end_character_index);
+ return GetGlyphDataRange().FindGlyphDataRange(
+ IsRtl(), start_character_index, end_character_index);
}
unsigned OffsetToRunStartIndex() const { return offset_; }
@@ -109,15 +110,16 @@ unsigned ShapeResultView::RunInfoPart::PreviousSafeToBreakOffset(
unsigned offset) const {
if (offset >= NumCharacters())
return NumCharacters();
- if (!Rtl()) {
+ offset += offset_;
+ if (IsLtr()) {
for (const auto& glyph : base::Reversed(*this)) {
if (glyph.safe_to_break_before && glyph.character_index <= offset)
- return glyph.character_index;
+ return glyph.character_index - offset_;
}
} else {
for (const auto& glyph : *this) {
if (glyph.safe_to_break_before && glyph.character_index <= offset)
- return glyph.character_index;
+ return glyph.character_index - offset_;
}
}
@@ -194,7 +196,7 @@ void ShapeResultView::CreateViewsForResult(const ShapeResultType* other,
continue;
// Compute start/end of the run, or of the part if ShapeResultView.
unsigned part_start = run->start_index_ + other->StartIndexOffsetForRun();
- if (other->Rtl()) {
+ if (other->IsRtl()) {
// Under RTL and multiple parts, A RunInfoPart may have an
// offset_ greater than start_index. In this case, run_start
// would result in an invalid negative value.
@@ -298,7 +300,7 @@ scoped_refptr<ShapeResultView> ShapeResultView::Create(
byte_size, ::WTF::GetStringWithTypeName<ShapeResultView>());
ShapeResultView* out = new (buffer) ShapeResultView(result);
out->char_index_offset_ = result->StartIndex();
- if (!out->Rtl()) {
+ if (out->IsLtr()) {
out->start_index_ = 0;
} else {
out->start_index_ = out->char_index_offset_;
@@ -324,7 +326,7 @@ void ShapeResultView::AddSegments(const Segment* segments,
char_index_offset_ = segments[0].result ? segments[0].result->StartIndex()
: segments[0].view->StartIndex();
char_index_offset_ = std::max(char_index_offset_, segments[0].start_index);
- if (!Rtl()) { // Left-to-right
+ if (IsLtr()) { // Left-to-right
start_index_ = 0;
} else { // Right to left
start_index_ = char_index_offset_;
@@ -332,7 +334,7 @@ void ShapeResultView::AddSegments(const Segment* segments,
}
for (unsigned i = 0; i < segment_count; i++) {
- const Segment& segment = segments[Rtl() ? last_segment_index - i : i];
+ const Segment& segment = segments[IsRtl() ? last_segment_index - i : i];
if (segment.result) {
DCHECK_EQ(segment.result->Direction(), Direction());
CreateViewsForResult(segment.result, segment.start_index,
@@ -358,10 +360,10 @@ unsigned ShapeResultView::PreviousSafeToBreakOffset(unsigned index) const {
if (offset <= part.num_characters_) {
return part.PreviousSafeToBreakOffset(offset) + run_start;
}
- if (!Rtl()) {
+ if (IsLtr()) {
return run_start + part.num_characters_;
}
- } else if (Rtl()) {
+ } else if (IsRtl()) {
if (it == RunsOrParts().rbegin())
return part.start_index_;
const auto& previous_run = *--it;
@@ -446,7 +448,7 @@ float ShapeResultView::ForEachGlyphImpl(float initial_advance,
const SimpleFontData* font_data = run->font_data_.get();
const unsigned character_index_offset_for_glyph_data =
CharacterIndexOffsetForGlyphData(part);
- if (!run->Rtl()) { // Left-to-right
+ if (run->IsLtr()) { // Left-to-right
for (const auto& glyph_data : part) {
unsigned character_index =
glyph_data.character_index + character_index_offset_for_glyph_data;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
index 05c7fa1563d..ea1d1b817d3 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
@@ -114,7 +114,8 @@ class PLATFORM_EXPORT ShapeResultView final
TextDirection Direction() const {
return static_cast<TextDirection>(direction_);
}
- bool Rtl() const { return Direction() == TextDirection::kRtl; }
+ bool IsLtr() const { return blink::IsLtr(Direction()); }
+ bool IsRtl() const { return blink::IsRtl(Direction()); }
bool HasVerticalOffsets() const { return has_vertical_offsets_; }
void FallbackFonts(HashSet<const SimpleFontData*>* fallback) const;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
index 85c46054789..62fbee4b800 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
@@ -125,6 +125,47 @@ TEST_F(ShapeResultViewTest, ArabicSingleView) {
EXPECT_EQ(last_glyphs.size(), 3u);
}
+TEST_F(ShapeResultViewTest, PreviousSafeToBreak) {
+ String string =
+ u"\u0028\u05D1\u0029\u0020\u05D4\u05D1\u05DC\u0020\u05D0\u05DE\u05E8"
+ u"\u0020\u05E2\u05DC\u0020"
+ u"\u05D3\u05D1\u05E8\u05D9\u0020\u05D4\u05D1\u05DC\u05D9\u0020\u05D4"
+ u"\u05E2\u05D5\u05DC\u05DD\u002C"
+ u"\u0020\u05D5\u05E1\u05DE\u05DA\u0020\u05D4\u05B2\u05D1\u05B5\u05DC"
+ u"\u0020\u05D0\u05DC\u0020\u05D4"
+ u"\u05D1\u05DC\u05D9\u05DD\u0020\u05D5\u05D0\u05DD\u0020\u05DC\u05D0"
+ u"\u0020\u05D9\u05DE\u05E6\u05D0"
+ u"\u0020\u05DE\u05D4\u05E9\u05DE\u05D5\u05EA\u0020\u05E9\u05D4\u05DD"
+ u"\u0020\u05E2\u05DC\u0020\u05DE"
+ u"\u05E9\u05E7\u05DC\u0020\u05D0\u05E8\u05E5\u0020\u05E9\u05D9\u05E9"
+ u"\u05EA\u05E0\u05D4\u0020\u05D7"
+ u"\u05D5\u05E5\u0020\u05DE\u05B5\u05D7\u05B2\u05D3\u05B7\u05E8\u0020"
+ u"\u05DE\u05B4\u05E9\u05B0\u05C1"
+ u"\u05DB\u05B8\u05D1\u05B0\u05DA\u05B8\u0020\u0028\u05E9\u05DE\u05D5"
+ u"\u05EA\u0020\u05D6\u05F3\u003A"
+ u"\u05DB\u05F4\u05D7\u0029";
+ TextDirection direction = TextDirection::kRtl;
+ HarfBuzzShaper shaper(string);
+ const RunSegmenter::RunSegmenterRange range = {
+ 51, 131, USCRIPT_HEBREW, blink::OrientationIterator::kOrientationKeep,
+ blink::FontFallbackPriority::kText};
+ scoped_refptr<ShapeResult> shape_result =
+ shaper.Shape(&font, direction, 51, 131, range);
+
+ unsigned start_offset = 59;
+ unsigned end_offset = 118;
+ scoped_refptr<const ShapeResultView> result_view =
+ ShapeResultView::Create(shape_result.get(), start_offset, end_offset);
+ scoped_refptr<ShapeResult> result = result_view->CreateShapeResult();
+
+ unsigned offset = end_offset;
+ do {
+ unsigned safe = result_view->PreviousSafeToBreakOffset(offset);
+ unsigned cached_safe = result->CachedPreviousSafeToBreakOffset(offset);
+ EXPECT_EQ(safe, cached_safe);
+ } while (--offset > start_offset);
+}
+
TEST_F(ShapeResultViewTest, LatinMultiRun) {
TextDirection direction = TextDirection::kLtr;
HarfBuzzShaper shaper_a(To16Bit("hello", 5));
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
index 45d7563b635..d05c94ce466 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
@@ -50,11 +50,18 @@ bool IsAllSpaces(const String& text, unsigned start, unsigned end) {
.IsAllSpecialCharacters<IsBreakableSpace>();
}
-bool ShouldHyphenate(const String& text, unsigned start, unsigned end) {
+bool ShouldHyphenate(const String& text,
+ unsigned word_start,
+ unsigned word_end,
+ unsigned line_start) {
+ // If this is the first word in this line, allow to hyphenate. Otherwise the
+ // word will overflow.
+ if (word_start <= line_start)
+ return true;
// Do not hyphenate the last word in a paragraph, except when it's a single
// word paragraph.
- if (IsAllSpaces(text, end, text.length()))
- return IsAllSpaces(text, 0, start);
+ if (IsAllSpaces(text, word_end, text.length()))
+ return IsAllSpaces(text, 0, word_start);
return true;
}
@@ -125,7 +132,7 @@ ShapingLineBreaker::BreakOpportunity ShapingLineBreaker::Hyphenate(
const String& text = GetText();
unsigned word_end = break_iterator_->NextBreakOpportunity(offset);
if (word_end != offset && IsBreakableSpace(text[word_end - 1]))
- word_end = std::max(start + 1, FindNonHangableEnd(text, word_end - 1));
+ word_end = std::max(offset, FindNonHangableEnd(text, word_end - 1));
if (word_end == offset) {
DCHECK(IsBreakableSpace(text[offset]) ||
offset == break_iterator_->PreviousBreakOpportunity(offset, start));
@@ -141,7 +148,7 @@ ShapingLineBreaker::BreakOpportunity ShapingLineBreaker::Hyphenate(
LazyLineBreakIterator::IsBreakableSpace(text[word_start]))
word_start++;
if (offset >= word_start &&
- ShouldHyphenate(text, previous_break_opportunity, word_end)) {
+ ShouldHyphenate(text, previous_break_opportunity, word_end, start)) {
unsigned prefix_length = Hyphenate(offset, word_start, word_end, backwards);
if (prefix_length)
return {word_start + prefix_length, true};
@@ -157,8 +164,11 @@ ShapingLineBreaker::PreviousBreakOpportunity(unsigned offset,
for (;; offset--) {
offset = break_iterator_->PreviousBreakOpportunity(offset, start);
if (offset <= start || offset >= text.length() ||
- text[offset - 1] != kSoftHyphenCharacter)
+ text[offset - 1] != kSoftHyphenCharacter) {
+ if (IsBreakableSpace(text[offset - 1]))
+ return {offset, FindNonHangableEnd(text, offset - 1), false};
return {offset, false};
+ }
}
}
@@ -183,8 +193,11 @@ ShapingLineBreaker::BreakOpportunity ShapingLineBreaker::NextBreakOpportunity(
if (UNLIKELY(!IsSoftHyphenEnabled())) {
for (;; offset++) {
offset = break_iterator_->NextBreakOpportunity(offset);
- if (offset >= text.length() || text[offset - 1] != kSoftHyphenCharacter)
+ if (offset >= text.length() || text[offset - 1] != kSoftHyphenCharacter) {
+ if (IsBreakableSpace(text[offset - 1]))
+ return {offset, FindNonHangableEnd(text, offset - 1), false};
return {offset, false};
+ }
}
}
@@ -349,6 +362,14 @@ scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeLine(
if (result_out->is_overflow)
return ShapeToEnd(start, first_safe, range_start, range_end);
break_opportunity.offset = range_end;
+ if (break_opportunity.non_hangable_run_end &&
+ range_end < break_opportunity.non_hangable_run_end) {
+ break_opportunity.non_hangable_run_end = base::nullopt;
+ }
+ if (IsBreakableSpace(text[range_end - 1])) {
+ break_opportunity.non_hangable_run_end =
+ FindNonHangableEnd(text, range_end - 1);
+ }
}
CheckBreakOffset(break_opportunity.offset, start, range_end);
@@ -359,6 +380,10 @@ scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeLine(
if (first_safe != start) {
if (first_safe >= break_opportunity.offset) {
// There is no safe-to-break, reshape the whole range.
+ if (!is_break_after_any_space && break_opportunity.non_hangable_run_end) {
+ break_opportunity.offset =
+ std::max(start + 1, *break_opportunity.non_hangable_run_end);
+ }
SetBreakOffset(break_opportunity, text, result_out);
CheckBreakOffset(result_out->break_offset, start, range_end);
return ShapeResultView::Create(
diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
index b0296b7f786..52c122ef5ee 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc
@@ -54,6 +54,21 @@ class ShapingLineBreakerTest : public testing::Test {
font = Font(font_description);
}
+ void SelectLucidaFont() {
+ FontFamily lucida_family;
+ // Windows 10
+ lucida_family.SetFamily("Lucida Grande");
+ // Windows 7
+ lucida_family.AppendFamily("Lucida Grande");
+ // Linux
+ lucida_family.AppendFamily("Lucida Medium");
+ // Mac
+ lucida_family.AppendFamily("Lucida Medium");
+
+ font_description.SetFamily(lucida_family);
+ font = Font(font_description);
+ }
+
void TearDown() override {}
// Compute all break positions by |NextBreakOpportunity|.
@@ -322,6 +337,41 @@ TEST_F(ShapingLineBreakerTest, ShapeLineRangeEndMidWord) {
EXPECT_EQ(result->Width(), line->Width());
}
+TEST_F(ShapingLineBreakerTest, ShapeLineWithLucidaFont) {
+ SelectLucidaFont();
+ FontDescription::VariantLigatures ligatures;
+ ligatures.common = FontDescription::kEnabledLigaturesState;
+
+ // 012345678901234567890123456789012345
+ String string(u"Lorem ipsum, consexx porttitxx. xxx");
+ LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal);
+ // In LayoutNG we use kAfterSpaceRun as TextBreakIterator`s default behavior.
+ break_iterator.SetBreakSpace(BreakSpaceType::kAfterSpaceRun);
+ TextDirection direction = TextDirection::kLtr;
+
+ HarfBuzzShaper shaper(string);
+ scoped_refptr<const ShapeResult> result =
+ shaper.Shape(&font, direction, 0, 35);
+ scoped_refptr<const ShapeResult> segment1 =
+ shaper.Shape(&font, direction, 13, 31);
+ scoped_refptr<const ShapeResult> segment2 =
+ shaper.Shape(&font, direction, 13, 32);
+
+ HarfBuzzShaperCallbackContext context{&shaper, &font, result->Direction()};
+ ShapingLineBreaker breaker(result, &break_iterator, nullptr,
+ HarfBuzzShaperCallback, &context);
+ scoped_refptr<const ShapeResultView> line;
+ unsigned break_offset = 0;
+
+ line = ShapeLine(&breaker, 13, segment1->SnappedWidth(), &break_offset);
+ EXPECT_EQ(31u, break_offset);
+ EXPECT_EQ(segment1->Width(), line->Width());
+
+ line = ShapeLine(&breaker, 13, segment2->SnappedWidth(), &break_offset);
+ EXPECT_EQ(31u, break_offset);
+ EXPECT_EQ(segment1->Width(), line->Width());
+}
+
struct BreakOpportunityTestData {
const char16_t* string;
Vector<unsigned> break_positions;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index e23f1f7fd26..f87d93cb92b 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -179,13 +179,9 @@ void SimpleFontData::PlatformInit(bool subpixel_ascent_descent,
if (int units_per_em = face->getUnitsPerEm())
font_metrics_.SetUnitsPerEm(units_per_em);
- if (metrics_override.advance_override) {
- advance_override_ =
- *metrics_override.advance_override * platform_data_.size();
- }
-
- advance_proportional_override_ =
- metrics_override.advance_proportional_override;
+ advance_override_ = metrics_override.advance_override;
+ advance_override_vertical_upright_ =
+ metrics_override.advance_override_vertical_upright;
}
void SimpleFontData::PlatformGlyphInit() {
@@ -324,7 +320,9 @@ void SimpleFontData::ComputeNormalizedTypoAscentAndDescent() const {
font_metrics.FloatDescent())) {
return;
}
- NOTREACHED();
+
+ // We shouldn't be here unless the height is zero or lower.
+ DCHECK_LE(font_metrics.Height(), 0);
}
bool SimpleFontData::TrySetNormalizedTypoAscentAndDescent(float ascent,
diff --git a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h
index 0abbc23ec1b..4b75aa2fa6f 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -158,13 +158,12 @@ class PLATFORM_EXPORT SimpleFontData : public FontData {
}
bool HasAdvanceOverride() const override {
- return advance_override_.has_value() ||
- advance_proportional_override_.has_value();
+ return advance_override_.has_value();
}
- float GetAdvanceOverride() const { return advance_override_.value_or(0); }
- float GetAdvanceProportionalOverride() const {
- return advance_proportional_override_.value_or(1);
+ float GetAdvanceOverride() const { return advance_override_.value_or(1); }
+ float GetAdvanceOverrideVerticalUpright() const {
+ return advance_override_vertical_upright_.value_or(1);
}
protected:
@@ -217,13 +216,10 @@ class PLATFORM_EXPORT SimpleFontData : public FontData {
unsigned visual_overflow_inflation_for_ascent_;
unsigned visual_overflow_inflation_for_descent_;
- // The additional advance added to each letter as defined by the
+ // The multiplier to the advance of each letter as defined by the
// advance-override value in @font-face.
base::Optional<float> advance_override_;
-
- // The multiplier to the advance of each letter as defined by the
- // advance-proportional-override value in @font-face.
- base::Optional<float> advance_proportional_override_;
+ base::Optional<float> advance_override_vertical_upright_;
mutable FontHeight normalized_typo_ascent_descent_;
diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
index e72f801016a..6e388c9135c 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc
@@ -37,7 +37,7 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
-#include "third_party/ots/include/ots-memory-stream.h"
+#include "third_party/ots/src/include/ots-memory-stream.h"
#include "third_party/skia/include/core/SkStream.h"
#include <hb.h>
diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
index 0624ff11029..bb6ef79ff02 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
@@ -4,9 +4,11 @@
#include "third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
@@ -37,7 +39,8 @@ bool WebFontTypefaceFactory::CreateTypeface(sk_sp<SkData> sk_data,
if (!format_check.IsVariableFont() && !format_check.IsColorFont()) {
typeface = DefaultFontManager()->makeFromStream(std::move(stream));
if (typeface) {
- ReportWebFontInstantiationResult(kSuccessConventionalWebFont);
+ ReportInstantiationResult(
+ InstantiationResult::kSuccessConventionalWebFont);
return true;
}
// Not UMA reporting general decoding errors as these are already recorded
@@ -48,15 +51,29 @@ bool WebFontTypefaceFactory::CreateTypeface(sk_sp<SkData> sk_data,
// We don't expect variable CBDT/CBLC or Sbix variable fonts for now.
if (format_check.IsCbdtCblcColorFont()) {
typeface = FreeTypeFontManager()->makeFromStream(std::move(stream));
- if (typeface)
- ReportWebFontInstantiationResult(kSuccessCbdtCblcColorFont);
+ if (typeface) {
+ ReportInstantiationResult(InstantiationResult::kSuccessCbdtCblcColorFont);
+ }
return typeface.get();
}
+ if (format_check.IsColrCpalColorFontV1()) {
+ if (RuntimeEnabledFeatures::COLRV1FontsEnabled()) {
+ typeface = FreeTypeFontManager()->makeFromStream(std::move(stream));
+ if (typeface) {
+ ReportInstantiationResult(InstantiationResult::kSuccessColrV1Font);
+ }
+ return typeface.get();
+ } else {
+ // Always reject COLRv1 fonts when the feature is off.
+ return false;
+ }
+ }
+
if (format_check.IsSbixColorFont()) {
typeface = FontManagerForSbix()->makeFromStream(std::move(stream));
if (typeface) {
- ReportWebFontInstantiationResult(kSuccessSbixFont);
+ ReportInstantiationResult(InstantiationResult::kSuccessSbixFont);
}
return typeface.get();
}
@@ -66,7 +83,7 @@ bool WebFontTypefaceFactory::CreateTypeface(sk_sp<SkData> sk_data,
if (format_check.IsCff2OutlineFont()) {
typeface = FreeTypeFontManager()->makeFromStream(std::move(stream));
if (typeface)
- ReportWebFontInstantiationResult(kSuccessCff2Font);
+ ReportInstantiationResult(InstantiationResult::kSuccessCff2Font);
return typeface.get();
}
@@ -74,17 +91,20 @@ bool WebFontTypefaceFactory::CreateTypeface(sk_sp<SkData> sk_data,
// FontManager, which is FreeType on Windows.
if (format_check.IsVariableFont()) {
typeface = FontManagerForVariations()->makeFromStream(std::move(stream));
- if (typeface)
- ReportWebFontInstantiationResult(kSuccessVariableWebFont);
- else
- ReportWebFontInstantiationResult(kErrorInstantiatingVariableFont);
+ if (typeface) {
+ ReportInstantiationResult(InstantiationResult::kSuccessVariableWebFont);
+ } else {
+ ReportInstantiationResult(
+ InstantiationResult::kErrorInstantiatingVariableFont);
+ }
return typeface.get();
}
- if (format_check.IsColrCpalColorFont()) {
+ if (format_check.IsColrCpalColorFontV0()) {
typeface = FontManagerForColrCpal()->makeFromStream(std::move(stream));
- if (typeface)
- ReportWebFontInstantiationResult(kSuccessColrCpalFont);
+ if (typeface) {
+ ReportInstantiationResult(InstantiationResult::kSuccessColrCpalFont);
+ }
return typeface.get();
}
@@ -137,17 +157,12 @@ sk_sp<SkFontMgr> WebFontTypefaceFactory::FontManagerForColrCpal() {
if (!CoreTextVersionSupportsColrCpal())
return FreeTypeFontManager();
#endif
- // TODO(https://crbug.com/882844): Check Mac OS version and use the FreeType
- // font manager accordingly.
return DefaultFontManager();
}
-void WebFontTypefaceFactory::ReportWebFontInstantiationResult(
- WebFontInstantiationResult result) {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(
- EnumerationHistogram, web_font_variable_fonts_ratio,
- ("Blink.Fonts.VariableFontsRatio", kMaxWebFontInstantiationResult));
- web_font_variable_fonts_ratio.Count(result);
+void WebFontTypefaceFactory::ReportInstantiationResult(
+ InstantiationResult result) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.Fonts.VariableFontsRatio", result);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h b/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h
index 129865336d8..ee3ea75e48c 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h
+++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h
@@ -35,7 +35,7 @@ class WebFontTypefaceFactory {
private:
// These values are written to logs. New enum values can be added, but
// existing enums must never be renumbered or deleted and reused.
- enum WebFontInstantiationResult {
+ enum class InstantiationResult {
kErrorInstantiatingVariableFont = 0,
kSuccessConventionalWebFont = 1,
kSuccessVariableWebFont = 2,
@@ -43,12 +43,13 @@ class WebFontTypefaceFactory {
kSuccessCff2Font = 4,
kSuccessSbixFont = 5,
kSuccessColrCpalFont = 6,
- kMaxWebFontInstantiationResult = 7
+ kSuccessColrV1Font = 7,
+ kMaxValue = kSuccessColrV1Font
};
static sk_sp<SkFontMgr> DefaultFontManager();
- static void ReportWebFontInstantiationResult(WebFontInstantiationResult);
+ static void ReportInstantiationResult(InstantiationResult);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
index fc75d9543f9..d342281d380 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
@@ -207,21 +207,21 @@ const AtomicString& FontCache::SystemFontFamily() {
}
// static
-void FontCache::SetMenuFontMetrics(const wchar_t* family_name,
+void FontCache::SetMenuFontMetrics(const AtomicString& family_name,
int32_t font_height) {
menu_font_family_name_ = new AtomicString(family_name);
menu_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
}
// static
-void FontCache::SetSmallCaptionFontMetrics(const wchar_t* family_name,
+void FontCache::SetSmallCaptionFontMetrics(const AtomicString& family_name,
int32_t font_height) {
small_caption_font_family_name_ = new AtomicString(family_name);
small_caption_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
}
// static
-void FontCache::SetStatusFontMetrics(const wchar_t* family_name,
+void FontCache::SetStatusFontMetrics(const AtomicString& family_name,
int32_t font_height) {
status_font_family_name_ = new AtomicString(family_name);
status_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc
index 13162712b2e..d8fa9c55ac4 100644
--- a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc
+++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc
@@ -8,11 +8,11 @@
#include <utility>
#include "base/files/file_path.h"
+#include "base/metrics/histogram_macros.h"
#include "mojo/public/mojom/base/shared_memory.mojom-blink.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
@@ -21,11 +21,11 @@ namespace {
// These enum values correspond to the
// "Blink.Fonts.WindowsUniqueLocalFontInstantiationResult" histogram, new values
// can be added, but old values should never be reused.
-enum WindowsUniqueLocalFontInstantiationResult {
+enum class InstantiationResult {
kSuccess = 0,
kErrorOutsideWindowsFontsDirectory = 1,
kErrorOther = 2,
- kMaxWindowsUniqueLocalFontInstantiationResult = 3
+ kMaxValue = kErrorOther,
};
} // namespace
@@ -88,7 +88,7 @@ sk_sp<SkTypeface> FontUniqueNameLookupWin::InstantiateFromPathAndTtcIndex(
sk_sp<SkTypeface> local_typeface = SkTypeface::MakeFromFile(
font_file_path.AsUTF8Unsafe().c_str(), ttc_index);
- WindowsUniqueLocalFontInstantiationResult result = kSuccess;
+ InstantiationResult result = InstantiationResult::kSuccess;
// There is a chance that some systems have managed to register fonts into the
// Windows system font collection outside the C:\Windows\Fonts directory. For
@@ -99,16 +99,13 @@ sk_sp<SkTypeface> FontUniqueNameLookupWin::InstantiateFromPathAndTtcIndex(
if (!local_typeface) {
base::FilePath windows_fonts_path(L"C:\\WINDOWS\\FONTS");
if (!windows_fonts_path.IsParent(font_file_path))
- result = kErrorOutsideWindowsFontsDirectory;
+ result = InstantiationResult::kErrorOutsideWindowsFontsDirectory;
else
- result = kErrorOther;
+ result = InstantiationResult::kErrorOther;
}
- DEFINE_THREAD_SAFE_STATIC_LOCAL(
- EnumerationHistogram, windows_unique_local_font_instantiation_histogram,
- ("Blink.Fonts.WindowsUniqueLocalFontInstantiationResult",
- kMaxWindowsUniqueLocalFontInstantiationResult));
- windows_unique_local_font_instantiation_histogram.Count(result);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Blink.Fonts.WindowsUniqueLocalFontInstantiationResult", result);
return local_typeface;
}
diff --git a/chromium/third_party/blink/renderer/platform/geometry/calculation_value.cc b/chromium/third_party/blink/renderer/platform/geometry/calculation_value.cc
index ed540165fc9..797e34099d8 100644
--- a/chromium/third_party/blink/renderer/platform/geometry/calculation_value.cc
+++ b/chromium/third_party/blink/renderer/platform/geometry/calculation_value.cc
@@ -45,8 +45,9 @@ CalculationValue::~CalculationValue() {
}
float CalculationValue::Evaluate(float max_value) const {
- float value = is_expression_ ? value = data_.expression->Evaluate(max_value)
- : value = Pixels() + Percent() / 100 * max_value;
+ float value =
+ clampTo<float>(is_expression_ ? data_.expression->Evaluate(max_value)
+ : Pixels() + Percent() / 100 * max_value);
return (IsNonNegative() && value < 0) ? 0 : value;
}
diff --git a/chromium/third_party/blink/renderer/platform/geometry/layout_unit.h b/chromium/third_party/blink/renderer/platform/geometry/layout_unit.h
index 19788bffabe..b70b4df9e8b 100644
--- a/chromium/third_party/blink/renderer/platform/geometry/layout_unit.h
+++ b/chromium/third_party/blink/renderer/platform/geometry/layout_unit.h
@@ -88,6 +88,17 @@ ALWAYS_INLINE int GetMinSaturatedSetResultForTesting() {
class PLATFORM_EXPORT LayoutUnit;
constexpr bool operator<(const LayoutUnit&, const LayoutUnit&);
+// kIndefiniteSize is a special value used within layout code. It is typical
+// within layout to have sizes which are only allowed to be non-negative or
+// "indefinite". We use the value of "-1" to represent these indefinite values.
+//
+// It is common to clamp these indefinite values to zero.
+// |LayoutUnit::ClampIndefiniteToZero| provides this functionality, and
+// additionally DCHECKs that it isn't some other negative value.
+//
+// TODO(wangxianzhu): Make it a constexpr when LayoutUnit allows it.
+#define kIndefiniteSize LayoutUnit(-1)
+
class LayoutUnit {
DISALLOW_NEW();
@@ -208,6 +219,15 @@ class LayoutUnit {
return value_ > 0 ? LayoutUnit() : *this;
}
+ LayoutUnit ClampIndefiniteToZero() const {
+ // We compare to |kFixedPointDenominator| here instead of |kIndefiniteSize|
+ // as the operator== for LayoutUnit is inlined below.
+ if (value_ == -kFixedPointDenominator)
+ return LayoutUnit();
+ DCHECK_GE(value_, 0);
+ return *this;
+ }
+
constexpr bool HasFraction() const {
return RawValue() % kFixedPointDenominator;
}
@@ -750,6 +770,10 @@ inline int FloorToInt(LayoutUnit value) {
return value.Floor();
}
+inline int CeilToInt(LayoutUnit value) {
+ return value.Ceil();
+}
+
inline LayoutUnit AbsoluteValue(const LayoutUnit& value) {
return value.Abs();
}
diff --git a/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc b/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
index f07da329692..e1fd678021a 100644
--- a/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
+++ b/chromium/third_party/blink/renderer/platform/geometry/length_functions.cc
@@ -40,7 +40,7 @@ float FloatValueForLength(const Length& length, float maximum_value) {
case Length::kFixed:
return length.GetFloatValue();
case Length::kPercent:
- return static_cast<float>(maximum_value * length.Percent() / 100.0f);
+ return clampTo<float>(maximum_value * length.Percent() / 100.0f);
case Length::kFillAvailable:
case Length::kAuto:
return static_cast<float>(maximum_value);
diff --git a/chromium/third_party/blink/renderer/platform/geometry/length_functions_test.cc b/chromium/third_party/blink/renderer/platform/geometry/length_functions_test.cc
new file mode 100644
index 00000000000..86abeb020c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/geometry/length_functions_test.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/geometry/length_functions.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(LengthFunctionsTest, OutOfRangePercentage) {
+ Length max = Length::Percent(std::numeric_limits<float>::max());
+ float value = FloatValueForLength(max, 800);
+ EXPECT_TRUE(isfinite(value));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/DEPS b/chromium/third_party/blink/renderer/platform/graphics/DEPS
index 2353df9a947..eeafe8b46fd 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/DEPS
+++ b/chromium/third_party/blink/renderer/platform/graphics/DEPS
@@ -14,6 +14,7 @@ include_rules = [
"+base/barrier_closure.h",
"+cc",
"+components/paint_preview/common",
+ "+components/power_scheduler",
"+components/viz/client",
"+components/viz/common",
"+gpu/config",
@@ -33,13 +34,18 @@ include_rules = [
"+media/base/media_switches.h",
"+media/base/video_frame.h",
"+media/base/video_types.h",
+ "+media/base/video_util.h",
"+media/media_buildflags.h",
+ "+media/renderers/paint_canvas_video_renderer.h",
"+media/renderers/video_resource_updater.h",
"+services/viz/public/mojom",
"+services/viz/public/cpp/gpu/context_provider_command_buffer.h",
"+skia",
"+third_party/blink/renderer/platform/context_lifecycle_notifier.h",
"+third_party/blink/renderer/platform/cpu/mips/common_macros_msa.h",
+ "+third_party/blink/renderer/platform/disk_data_metadata.h",
+ "+third_party/blink/renderer/platform/disk_data_allocator.h",
+ "+third_party/blink/renderer/platform/disk_data_allocator_test_utils.h",
"+third_party/blink/renderer/platform/fonts",
"+third_party/blink/renderer/platform/geometry",
"+third_party/blink/renderer/platform/heap",
@@ -48,6 +54,7 @@ include_rules = [
"+third_party/blink/renderer/platform/image-encoders",
"+third_party/blink/renderer/platform/instrumentation",
"+third_party/blink/renderer/platform/json",
+ "+third_party/blink/renderer/platform/mojo/mojo_binding_context.h",
"+third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h",
"+third_party/blink/renderer/platform/mojo/heap_mojo_remote.h",
"+third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h",
@@ -72,9 +79,16 @@ include_rules = [
specific_include_rules = {
".*_test.cc": [
"+components/viz/test",
+ "+ui/gl/buffer_format_utils.h",
],
"(graphics_context|skia_utils)\.cc" : [ "+ui/base/ui_base_features.h" ],
"graphics_context.h": [
"+third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h",
],
+ "rw_buffer_test.cc": [
+ "+base/threading/platform_thread.h",
+ ],
+ "video_frame_image_util_test.cc": [
+ "+media/renderers/shared_image_video_frame_test_utils.h",
+ ],
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/DIR_METADATA b/chromium/third_party/blink/renderer/platform/graphics/DIR_METADATA
new file mode 100644
index 00000000000..739e146e9a8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Paint"
+}
+team_email: "paint-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/graphics/OWNERS b/chromium/third_party/blink/renderer/platform/graphics/OWNERS
index 4b3d9b2d1f8..457035c2c22 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/graphics/OWNERS
@@ -18,12 +18,6 @@ jonross@chromium.org
# lowLatency canvas
mcasas@chromium.org
-# canvas resources and images
-khushalsagar@chromium.org
-
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Paint
-
# Video SurfaceLayer functionality.
per-file video_frame*=file://media/OWNERS
per-file video_frame*=mlamouri@chromium.org
diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index dcfb03e36a9..2e8a9c1d269 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -171,6 +171,7 @@ void AcceleratedStaticBitmapImage::Draw(
const cc::PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum should_respect_image_orientation,
ImageClampingMode image_clamping_mode,
ImageDecodingMode decode_mode) {
@@ -184,7 +185,7 @@ void AcceleratedStaticBitmapImage::Draw(
.set_decoding_mode(paint_image_decoding_mode)
.TakePaintImage();
}
- StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect,
+ StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect, sampling,
image_clamping_mode,
should_respect_image_orientation, paint_image);
}
@@ -266,7 +267,7 @@ void AcceleratedStaticBitmapImage::InitializeTextureBacking(
texture_info.fTarget = texture_target_;
texture_info.fID = shared_context_texture_id;
texture_info.fFormat =
- CanvasColorParams(sk_image_info_).GLSizedInternalFormat();
+ CanvasResourceParams(sk_image_info_).GLSizedInternalFormat();
GrBackendTexture backend_texture(sk_image_info_.width(),
sk_image_info_.height(), GrMipMapped::kNo,
texture_info);
@@ -361,14 +362,17 @@ AcceleratedStaticBitmapImage::ConvertToColorSpace(
->SharedImageInterface()
->UsageForMailbox(mailbox_);
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
- Size(), kLow_SkFilterQuality, CanvasColorParams(image_info),
+ Size(), kLow_SkFilterQuality, CanvasResourceParams(image_info),
CanvasResourceProvider::ShouldInitialize::kNo, ContextProviderWrapper(),
RasterMode::kGPU, IsOriginTopLeft(), usage_flags);
if (!provider) {
return nullptr;
}
- provider->Canvas()->drawImage(PaintImageForCurrentFrame(), 0, 0, nullptr);
+ cc::PaintFlags paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ provider->Canvas()->drawImage(PaintImageForCurrentFrame(), 0, 0,
+ SkSamplingOptions(), &paint);
return provider->Snapshot(orientation_);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
index 8ed9660db5b..533484369e4 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
@@ -81,6 +81,7 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
const cc::PaintFlags&,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
index e34a9cccf59..8666c10c843 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
+#include <utility>
+
#include "base/barrier_closure.h"
#include "base/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
@@ -66,16 +68,10 @@ struct AnimationWorkletMutatorDispatcherImpl::AsyncMutationRequest {
};
AnimationWorkletMutatorDispatcherImpl::AnimationWorkletMutatorDispatcherImpl(
- bool main_thread_task_runner)
- : client_(nullptr), outputs_(OutputVectorRef::Create()) {
- // By default web tests run without threaded compositing. See
- // https://crbug.com/770028. If threaded compositing is disabled or
- // |main_thread_task_runner| is true we run on the main thread's compositor
- // task runner otherwise we run tasks on the compositor thread's default
- // task runner.
- host_queue_ = main_thread_task_runner || !Thread::CompositorThread()
- ? Thread::MainThread()->Scheduler()->CompositorTaskRunner()
- : Thread::CompositorThread()->GetTaskRunner();
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : host_queue_(task_runner),
+ client_(nullptr),
+ outputs_(OutputVectorRef::Create()) {
tick_clock_ = std::make_unique<base::DefaultTickClock>();
}
@@ -85,15 +81,13 @@ AnimationWorkletMutatorDispatcherImpl::
// static
template <typename ClientType>
std::unique_ptr<ClientType> AnimationWorkletMutatorDispatcherImpl::CreateClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* weak_interface,
- scoped_refptr<base::SingleThreadTaskRunner>* queue,
- bool main_thread_client) {
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& weak_interface,
+ scoped_refptr<base::SingleThreadTaskRunner> queue) {
DCHECK(IsMainThread());
- auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(
- main_thread_client);
+ auto mutator =
+ std::make_unique<AnimationWorkletMutatorDispatcherImpl>(std::move(queue));
// This is allowed since we own the class for the duration of creation.
- *weak_interface = mutator->weak_factory_.GetWeakPtr();
- *queue = mutator->GetTaskRunner();
+ weak_interface = mutator->weak_factory_.GetWeakPtr();
return std::make_unique<ClientType>(std::move(mutator));
}
@@ -101,17 +95,19 @@ std::unique_ptr<ClientType> AnimationWorkletMutatorDispatcherImpl::CreateClient(
// static
std::unique_ptr<CompositorMutatorClient>
AnimationWorkletMutatorDispatcherImpl::CreateCompositorThreadClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* weak_interface,
- scoped_refptr<base::SingleThreadTaskRunner>* queue) {
- return CreateClient<CompositorMutatorClient>(weak_interface, queue, false);
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& weak_interface,
+ scoped_refptr<base::SingleThreadTaskRunner> queue) {
+ return CreateClient<CompositorMutatorClient>(weak_interface,
+ std::move(queue));
}
// static
std::unique_ptr<MainThreadMutatorClient>
AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* weak_interface,
- scoped_refptr<base::SingleThreadTaskRunner>* queue) {
- return CreateClient<MainThreadMutatorClient>(weak_interface, queue, true);
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& weak_interface,
+ scoped_refptr<base::SingleThreadTaskRunner> queue) {
+ return CreateClient<MainThreadMutatorClient>(weak_interface,
+ std::move(queue));
}
void AnimationWorkletMutatorDispatcherImpl::MutateSynchronously(
@@ -352,12 +348,11 @@ void AnimationWorkletMutatorDispatcherImpl::RequestMutations(
// The mutator is created and destroyed on the worklet thread.
WrapCrossThreadWeakPersistent(mutator),
// The worklet input is not required after the Mutate call.
- WTF::Passed(std::move(it->value)),
+ std::move(it->value),
// The vector of outputs is wrapped in a scoped_refptr initialized
// on the host thread. It can outlive the dispatcher during shutdown
// of a process with a running animation.
- outputs_, next_request_index++,
- WTF::Passed(std::move(on_done_runner))));
+ outputs_, next_request_index++, std::move(on_done_runner)));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
index 81bdf2dfea7..ed3405db389 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h
@@ -33,19 +33,20 @@ class MainThreadMutatorClient;
class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
: public AnimationWorkletMutatorDispatcher {
public:
- // There are three outputs for the two interface surfaces of the created
+ // There are two outputs for the two interface surfaces of the created
// class blob. The returned owning pointer to the Client, which
- // also owns the rest of the structure. |mutatee| and |mutatee_runner| form a
+ // also owns the rest of the structure. |mutatee| form a
// pair for referencing the AnimationWorkletMutatorDispatcherImpl. i.e. Put
// tasks on the TaskRunner using the WeakPtr to get to the methods.
static std::unique_ptr<CompositorMutatorClient> CreateCompositorThreadClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* mutatee,
- scoped_refptr<base::SingleThreadTaskRunner>* mutatee_runner);
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& mutatee,
+ scoped_refptr<base::SingleThreadTaskRunner> mutatee_runner);
static std::unique_ptr<MainThreadMutatorClient> CreateMainThreadClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* mutatee,
- scoped_refptr<base::SingleThreadTaskRunner>* mutatee_runner);
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& mutatee,
+ scoped_refptr<base::SingleThreadTaskRunner> mutatee_runner);
- explicit AnimationWorkletMutatorDispatcherImpl(bool main_thread_task_runner);
+ explicit AnimationWorkletMutatorDispatcherImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~AnimationWorkletMutatorDispatcherImpl() override;
// AnimationWorkletMutatorDispatcher implementation.
@@ -74,10 +75,6 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
MutatorClient* client() { return client_; }
- scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() {
- return host_queue_;
- }
-
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -129,11 +126,11 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
// dictionary.
AnimationWorkletMutatorToTaskRunnerMap mutator_map_;
+ // |weak_interface| argument will be modified (initialized) by this function.
template <typename ClientType>
static std::unique_ptr<ClientType> CreateClient(
- base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>* weak_interface,
- scoped_refptr<base::SingleThreadTaskRunner>* queue,
- bool create_main_thread_client);
+ base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>& weak_interface,
+ scoped_refptr<base::SingleThreadTaskRunner> queue);
scoped_refptr<base::SingleThreadTaskRunner> host_queue_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
index 08234cde64a..e5ace413e1c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc
@@ -100,7 +100,7 @@ class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test {
public:
void SetUp() override {
auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(
- /*main_thread_task_runner=*/true);
+ base::ThreadTaskRunnerHandle::Get());
mutator_ = mutator.get();
client_ =
std::make_unique<::testing::StrictMock<MockCompositorMutatorClient>>(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc b/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
index 804b84f70e6..dc002e7b58d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -8,9 +8,13 @@
#include "base/bind.h"
#include "base/single_thread_task_runner.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "services/viz/public/mojom/compositing/frame_timing_details.mojom-blink.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/platform/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "ui/gfx/mojom/presentation_feedback.mojom-blink.h"
@@ -27,7 +31,10 @@ BeginFrameProvider::BeginFrameProvider(
frame_sink_id_(begin_frame_provider_params.frame_sink_id),
parent_frame_sink_id_(begin_frame_provider_params.parent_frame_sink_id),
compositor_frame_sink_(context),
- begin_frame_client_(client) {}
+ begin_frame_client_(client),
+ animation_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Animation.Worker")) {}
void BeginFrameProvider::ResetCompositorFrameSink() {
compositor_frame_sink_.reset();
@@ -94,6 +101,7 @@ void BeginFrameProvider::RequestBeginFrame() {
needs_begin_frame_ = true;
compositor_frame_sink_->SetNeedsBeginFrame(true);
+ animation_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kAnimation);
}
void BeginFrameProvider::OnBeginFrame(
@@ -116,6 +124,8 @@ void BeginFrameProvider::OnBeginFrame(
if (!requested_needs_begin_frame_) {
needs_begin_frame_ = false;
compositor_frame_sink_->SetNeedsBeginFrame(false);
+ animation_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kAnimationTimeout);
}
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index 7b6834fca84..73632ced9da 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -7,6 +7,7 @@
#include <string>
+#include "components/power_scheduler/power_mode_voter.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -95,6 +96,8 @@ class PLATFORM_EXPORT BeginFrameProvider
HeapMojoWrapperMode::kWithoutContextObserver>
compositor_frame_sink_;
Member<BeginFrameProviderClient> begin_frame_client_;
+
+ std::unique_ptr<power_scheduler::PowerModeVoter> animation_power_mode_voter_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
index fafc5eb7c00..b4fc597cf76 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc
@@ -157,6 +157,11 @@ IntSize BitmapImage::DensityCorrectedSize() const {
return density_corrected_size_.IsEmpty() ? Size() : density_corrected_size_;
}
+void BitmapImage::RecordDecodedImageType(UseCounter* use_counter) {
+ BitmapImageMetrics::CountDecodedImageType(decoder_->FilenameExtension(),
+ use_counter);
+}
+
IntSize BitmapImage::PreferredDisplaySize() const {
UpdateSize();
if (!density_corrected_size_respecting_orientation_.IsEmpty())
@@ -259,6 +264,7 @@ void BitmapImage::Draw(
const PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum should_respect_image_orientation,
ImageClampingMode clamp_mode,
ImageDecodingMode decode_mode) {
@@ -317,7 +323,7 @@ void BitmapImage::Draw(
uint32_t stable_id = image.stable_id();
bool is_lazy_generated = image.IsLazyGenerated();
canvas->drawImageRect(std::move(image), adjusted_src_rect, adjusted_dst_rect,
- &flags,
+ sampling, &flags,
WebCoreClampingModeToSkiaRectConstraint(clamp_mode));
if (is_lazy_generated) {
@@ -346,14 +352,8 @@ bool BitmapImage::IsSizeAvailable() {
return true;
size_available_ = decoder_ && decoder_->IsSizeAvailable();
- if (size_available_ && HasVisibleImageSize(Size())) {
+ if (size_available_ && HasVisibleImageSize(Size()))
BitmapImageMetrics::CountDecodedImageType(decoder_->FilenameExtension());
- if (decoder_->FilenameExtension() == "jpg") {
- IntSize correctedSize = decoder_->DensityCorrectedSizeAtIndex(0);
- BitmapImageMetrics::CountImageDensityCorrection(
- !correctedSize.IsEmpty() && correctedSize != decoder_->Size());
- }
- }
return size_available_;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.h
index 0084c5998ff..80aac0ea5d3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.h
@@ -45,6 +45,8 @@
namespace blink {
+class UseCounter;
+
class PLATFORM_EXPORT BitmapImage final : public Image {
friend class BitmapImageTest;
friend class CrossfadeGeneratedImage;
@@ -107,6 +109,10 @@ class PLATFORM_EXPORT BitmapImage final : public Image {
IntSize DensityCorrectedSize() const override;
+ // Records the decoded image type in a UseCounter. |use_counter| may be a null
+ // pointer.
+ void RecordDecodedImageType(UseCounter* use_counter);
+
protected:
bool IsSizeAvailable() override;
@@ -131,6 +137,7 @@ class PLATFORM_EXPORT BitmapImage final : public Image {
const cc::PaintFlags&,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
index 06b3801f9b8..d4a0ace613b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
@@ -8,40 +8,57 @@
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "media/media_buildflags.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
#include "third_party/blink/renderer/platform/graphics/color_space_gamut.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
namespace blink {
-void BitmapImageMetrics::CountDecodedImageType(const String& type) {
- DecodedImageType decoded_image_type =
- type == "jpg"
- ? DecodedImageType::kJPEG
- : type == "png"
- ? DecodedImageType::kPNG
- : type == "gif"
- ? DecodedImageType::kGIF
- : type == "webp"
- ? DecodedImageType::kWebP
- : type == "ico"
- ? DecodedImageType::kICO
- : type == "bmp"
- ? DecodedImageType::kBMP
+namespace {
+
+BitmapImageMetrics::DecodedImageType StringToDecodedImageType(
+ const String& type) {
+ if (type == "jpg")
+ return BitmapImageMetrics::DecodedImageType::kJPEG;
+ if (type == "png")
+ return BitmapImageMetrics::DecodedImageType::kPNG;
+ if (type == "gif")
+ return BitmapImageMetrics::DecodedImageType::kGIF;
+ if (type == "webp")
+ return BitmapImageMetrics::DecodedImageType::kWebP;
+ if (type == "ico")
+ return BitmapImageMetrics::DecodedImageType::kICO;
+ if (type == "bmp")
+ return BitmapImageMetrics::DecodedImageType::kBMP;
#if BUILDFLAG(ENABLE_AV1_DECODER)
- : type == "avif"
- ? DecodedImageType::kAVIF
+ if (type == "avif")
+ return BitmapImageMetrics::DecodedImageType::kAVIF;
#endif
- : DecodedImageType::kUnknown;
+ return BitmapImageMetrics::DecodedImageType::kUnknown;
+}
- UMA_HISTOGRAM_ENUMERATION("Blink.DecodedImageType", decoded_image_type);
+} // namespace
+
+void BitmapImageMetrics::CountDecodedImageType(const String& type) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.DecodedImageType",
+ StringToDecodedImageType(type));
}
-void BitmapImageMetrics::CountImageDensityCorrection(bool density_correction_present) {
- UMA_HISTOGRAM_BOOLEAN("Blink.DecodedImage.DensitySizeCorrectionDetected",
- density_correction_present);
+void BitmapImageMetrics::CountDecodedImageType(const String& type,
+ UseCounter* use_counter) {
+ if (use_counter) {
+ if (type == "webp") {
+ use_counter->CountUse(WebFeature::kWebPImage);
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+ } else if (type == "avif") {
+ use_counter->CountUse(WebFeature::kAVIFImage);
+#endif
+ }
+ }
}
void BitmapImageMetrics::CountImageJpegDensity(int image_min_side,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
index efe521853b3..c90dc34def5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
@@ -13,6 +13,7 @@
namespace blink {
class IntSize;
+class UseCounter;
class PLATFORM_EXPORT BitmapImageMetrics {
STATIC_ONLY(BitmapImageMetrics);
@@ -55,7 +56,10 @@ class PLATFORM_EXPORT BitmapImageMetrics {
// |type| is the return value of ImageDecoder::FilenameExtension().
static void CountDecodedImageType(const String& type);
- static void CountImageDensityCorrection(bool densityCorrectionPresent);
+ // |type| is the return value of ImageDecoder::FilenameExtension().
+ // |use_counter| may be a null pointer.
+ static void CountDecodedImageType(const String& type,
+ UseCounter* use_counter);
// Report the JPEG compression density in 0.01 bits per pixel for an image
// with a smallest side (width or length) of |image_min_side| and total size
// in bytes |image_size_bytes|.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
index 3469e4f33fc..3160e012c17 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc
@@ -69,9 +69,9 @@ class FrameSettingImageProvider : public cc::ImageProvider {
DCHECK(!draw_image.paint_image().IsPaintWorklet());
auto sk_image =
draw_image.paint_image().GetSkImageForFrame(frame_index_, client_id_);
- return ScopedResult(
- cc::DecodedDrawImage(sk_image, nullptr, SkSize::MakeEmpty(),
- SkSize::Make(1, 1), draw_image.filter_quality()));
+ return ScopedResult(cc::DecodedDrawImage(
+ sk_image, nullptr, SkSize::MakeEmpty(), SkSize::Make(1, 1),
+ draw_image.filter_quality(), true));
}
private:
@@ -92,7 +92,7 @@ void GenerateBitmapForPaintImage(cc::PaintImage paint_image,
bitmap->eraseColor(SK_AlphaTRANSPARENT);
FrameSettingImageProvider image_provider(frame_index, client_id);
cc::SkiaPaintCanvas canvas(*bitmap, &image_provider);
- canvas.drawImage(paint_image, 0u, 0u, nullptr);
+ canvas.drawImage(paint_image, 0u, 0u);
}
} // namespace
@@ -187,7 +187,7 @@ class BitmapImageTest : public testing::Test {
bitmap.allocPixels(info, image->Size().Width() * 4);
bitmap.eraseColor(SK_AlphaTRANSPARENT);
cc::SkiaPaintCanvas canvas(bitmap);
- canvas.drawImage(paint_image, 0u, 0u, nullptr);
+ canvas.drawImage(paint_image, 0u, 0u);
return bitmap;
}
@@ -276,12 +276,6 @@ TEST_F(BitmapImageTest, isAllDataReceived) {
image->SetData(image_data, true);
EXPECT_TRUE(image->IsAllDataReceived());
-
- image->SetData(SharedBuffer::Create("data", sizeof("data")), false);
- EXPECT_FALSE(image->IsAllDataReceived());
-
- image->SetData(image_data, true);
- EXPECT_TRUE(image->IsAllDataReceived());
}
TEST_F(BitmapImageTest, noColorProfile) {
@@ -834,33 +828,6 @@ TEST_F(BitmapHistogramTest, DecodedImageType) {
#endif // BUILDFLAG(ENABLE_AV1_DECODER)
}
-TEST_F(BitmapHistogramTest, DecodedImageDensitySizeCorrectionDetected) {
- ExpectImageRecordsSample("exif-resolution-none.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- false);
- ExpectImageRecordsSample("exif-resolution-invalid-cm.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- false);
- ExpectImageRecordsSample("exif-resolution-invalid-no-match.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- false);
- ExpectImageRecordsSample("exif-resolution-invalid-partial.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- false);
- ExpectImageRecordsSample("exif-resolution-no-change.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- false);
- ExpectImageRecordsSample("exif-resolution-valid-hires.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- true);
- ExpectImageRecordsSample("exif-resolution-valid-lores.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- true);
- ExpectImageRecordsSample("exif-resolution-valid-non-uniform.jpg",
- "Blink.DecodedImage.DensitySizeCorrectionDetected",
- true);
-}
-
TEST_F(BitmapHistogramTest, DecodedImageDensityKiBWeighted_JpegDensity) {
// Test a 64x64 image, which should be too small to report any metrics.
{
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index bccbecf3501..a6a1b0f958b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -516,6 +516,14 @@ void Canvas2DLayerBridge::FlushRecording() {
base::TimeDelta::FromMilliseconds(100), 100);
}
}
+
+ // Rastering the recording would have locked images, since we've flushed
+ // all recorded ops, we should release all locked images as well.
+ // A new null check on the resource provider is necessary just in case
+ // the playback crashed the context.
+ if (GetOrCreateResourceProvider())
+ ResourceProvider()->ReleaseLockedImages();
+
have_recorded_draw_commands_ = false;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
index 36a47241aee..1179b835460 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -82,34 +82,42 @@ namespace {
class ImageTrackingDecodeCache : public cc::StubDecodeCache {
public:
ImageTrackingDecodeCache() = default;
+ ~ImageTrackingDecodeCache() override { EXPECT_EQ(num_locked_images_, 0); }
cc::DecodedDrawImage GetDecodedImageForDraw(
const cc::DrawImage& image) override {
EXPECT_FALSE(disallow_cache_use_);
+ num_locked_images_++;
decoded_images_.push_back(image);
SkBitmap bitmap;
bitmap.allocPixelsFlags(SkImageInfo::MakeN32Premul(10, 10),
SkBitmap::kZeroPixels_AllocFlag);
sk_sp<SkImage> sk_image = SkImage::MakeFromBitmap(bitmap);
return cc::DecodedDrawImage(sk_image, nullptr, SkSize::Make(0, 0),
- SkSize::Make(1, 1), kLow_SkFilterQuality);
+ SkSize::Make(1, 1), kLow_SkFilterQuality,
+ !budget_exceeded_);
}
+ void set_budget_exceeded(bool exceeded) { budget_exceeded_ = exceeded; }
void set_disallow_cache_use(bool disallow) { disallow_cache_use_ = disallow; }
void DrawWithImageFinished(
const cc::DrawImage& image,
const cc::DecodedDrawImage& decoded_image) override {
EXPECT_FALSE(disallow_cache_use_);
+ num_locked_images_--;
}
const Vector<cc::DrawImage>& decoded_images() const {
return decoded_images_;
}
+ int num_locked_images() const { return num_locked_images_; }
private:
Vector<cc::DrawImage> decoded_images_;
+ int num_locked_images_ = 0;
+ bool budget_exceeded_ = false;
bool disallow_cache_use_ = false;
};
@@ -819,19 +827,18 @@ TEST_F(Canvas2DLayerBridgeTest, EnsureCCImageCacheUse) {
SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
0u, expected_color_space)};
- bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
+ bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u);
bridge->GetPaintCanvas()->drawImageRect(
images[1].paint_image(), SkRect::MakeWH(5u, 5u), SkRect::MakeWH(5u, 5u),
- nullptr, SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
bridge->NewImageSnapshot();
EXPECT_EQ(image_decode_cache_.decoded_images(), images);
}
TEST_F(Canvas2DLayerBridgeTest, EnsureCCImageCacheUseWithColorConversion) {
- auto color_params = CanvasColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kOpaque);
+ auto color_params = CanvasColorParams(CanvasColorSpace::kSRGB,
+ CanvasPixelFormat::kUint8, kOpaque);
std::unique_ptr<Canvas2DLayerBridge> bridge =
MakeBridge(IntSize(300, 300), RasterMode::kGPU, color_params);
Vector<cc::DrawImage> images = {
@@ -842,21 +849,74 @@ TEST_F(Canvas2DLayerBridgeTest, EnsureCCImageCacheUseWithColorConversion) {
SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
0u, color_params.GetStorageGfxColorSpace())};
- bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
+ bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u);
bridge->GetPaintCanvas()->drawImageRect(
images[1].paint_image(), SkRect::MakeWH(5u, 5u), SkRect::MakeWH(5u, 5u),
- nullptr, SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
bridge->NewImageSnapshot();
EXPECT_EQ(image_decode_cache_.decoded_images(), images);
}
+TEST_F(Canvas2DLayerBridgeTest, ImagesLockedUntilCacheLimit) {
+ auto color_params = CanvasColorParams(CanvasColorSpace::kSRGB,
+ CanvasPixelFormat::kF16, kOpaque);
+ std::unique_ptr<Canvas2DLayerBridge> bridge =
+ MakeBridge(IntSize(300, 300), RasterMode::kGPU, color_params);
+
+ Vector<cc::DrawImage> images = {
+ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), false,
+ SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
+ SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()),
+ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)), false,
+ SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
+ 0u, color_params.GetStorageGfxColorSpace()),
+ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)), false,
+ SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
+ 0u, color_params.GetStorageGfxColorSpace())};
+
+ // First 2 images are budgeted, they should remain locked after the op.
+ bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u);
+ bridge->GetPaintCanvas()->drawImage(images[1].paint_image(), 0u, 0u);
+ bridge->GetOrCreateResourceProvider()->FlushCanvas();
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 2);
+
+ // Next image is not budgeted, we should unlock all images other than the last
+ // image.
+ image_decode_cache_.set_budget_exceeded(true);
+ bridge->GetPaintCanvas()->drawImage(images[2].paint_image(), 0u, 0u);
+ bridge->GetOrCreateResourceProvider()->FlushCanvas();
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 1);
+
+ // Ask the provider to release everything, no locked images should remain.
+ bridge->GetOrCreateResourceProvider()->ReleaseLockedImages();
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 0);
+}
+
+TEST_F(Canvas2DLayerBridgeTest, QueuesCleanupTaskForLockedImages) {
+ auto color_params = CanvasColorParams(CanvasColorSpace::kSRGB,
+ CanvasPixelFormat::kF16, kOpaque);
+ std::unique_ptr<Canvas2DLayerBridge> bridge =
+ MakeBridge(IntSize(300, 300), RasterMode::kGPU, color_params);
+
+ auto image =
+ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), false,
+ SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
+ SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace());
+ bridge->GetPaintCanvas()->drawImage(image.paint_image(), 0u, 0u);
+
+ bridge->GetOrCreateResourceProvider()->FlushCanvas();
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 1);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 0);
+}
+
TEST_F(Canvas2DLayerBridgeTest, ImageCacheOnContextLost) {
auto color_params = CanvasColorParams(CanvasColorSpace::kSRGB,
CanvasPixelFormat::kF16, kOpaque);
std::unique_ptr<Canvas2DLayerBridge> bridge =
MakeBridge(IntSize(300, 300), RasterMode::kGPU, color_params);
- PaintFlags flags;
Vector<cc::DrawImage> images = {
cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), false,
SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
@@ -864,12 +924,14 @@ TEST_F(Canvas2DLayerBridgeTest, ImageCacheOnContextLost) {
cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)), false,
SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
0u, color_params.GetStorageGfxColorSpace())};
- bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
+ bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u);
// Lose the context and ensure that the image provider is not used.
bridge->GetOrCreateResourceProvider()->OnContextDestroyed();
+ // We should unref all images on the cache when the context is destroyed.
+ EXPECT_EQ(image_decode_cache_.num_locked_images(), 0);
image_decode_cache_.set_disallow_cache_use(true);
- bridge->GetPaintCanvas()->drawImage(images[1].paint_image(), 0u, 0u, &flags);
+ bridge->GetPaintCanvas()->drawImage(images[1].paint_image(), 0u, 0u);
}
TEST_F(Canvas2DLayerBridgeTest,
@@ -894,7 +956,6 @@ TEST_F(Canvas2DLayerBridgeTest,
&release_callback2));
EXPECT_EQ(release_callback2, nullptr);
}
-
class CustomFakeCanvasResourceHost : public FakeCanvasResourceHost {
public:
explicit CustomFakeCanvasResourceHost(const IntSize& size)
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
index 7dd54738714..9bd98856246 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
@@ -6,7 +6,9 @@
#include "cc/paint/skia_paint_canvas.h"
#include "components/viz/common/resources/resource_format_utils.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_params.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/khronos/GLES3/gl3.h"
@@ -42,6 +44,35 @@ sk_sp<SkColorSpace> CanvasColorSpaceToSkColorSpace(
return CanvasColorSpaceToGfxColorSpace(color_space).ToSkColorSpace();
}
+CanvasColorSpace CanvasColorSpaceFromSkColorSpace(
+ const SkColorSpace* sk_color_space) {
+ // TODO(https://crbug.com/1121448): This function returns sRGB if
+ // |sk_color_space| does not exactly match one of the named color spaces. It
+ // should find the best named match.
+ CanvasColorSpace color_spaces[] = {
+ CanvasColorSpace::kSRGB,
+ CanvasColorSpace::kRec2020,
+ CanvasColorSpace::kP3,
+ };
+ for (const auto& color_space : color_spaces) {
+ if (SkColorSpace::Equals(sk_color_space,
+ CanvasColorSpaceToGfxColorSpace(color_space)
+ .ToSkColorSpace()
+ .get())) {
+ return color_space;
+ }
+ }
+ return CanvasColorSpace::kSRGB;
+}
+
+CanvasColorSpace CanvasColorSpaceFromName(const String& color_space_name) {
+ if (color_space_name == kRec2020CanvasColorSpaceName)
+ return CanvasColorSpace::kRec2020;
+ if (color_space_name == kP3CanvasColorSpaceName)
+ return CanvasColorSpace::kP3;
+ return CanvasColorSpace::kSRGB;
+}
+
CanvasColorParams::CanvasColorParams() = default;
CanvasColorParams::CanvasColorParams(CanvasColorSpace color_space,
@@ -51,44 +82,67 @@ CanvasColorParams::CanvasColorParams(CanvasColorSpace color_space,
pixel_format_(pixel_format),
opacity_mode_(opacity_mode) {}
-CanvasColorParams::CanvasColorParams(const SkImageInfo& info)
- : CanvasColorParams(info.refColorSpace(), info.colorType()) {}
+CanvasColorParams::CanvasColorParams(const WTF::String& color_space,
+ const WTF::String& pixel_format,
+ bool has_alpha) {
+ if (color_space == kRec2020CanvasColorSpaceName)
+ color_space_ = CanvasColorSpace::kRec2020;
+ else if (color_space == kP3CanvasColorSpaceName)
+ color_space_ = CanvasColorSpace::kP3;
+
+ if (pixel_format == kF16CanvasPixelFormatName)
+ pixel_format_ = CanvasPixelFormat::kF16;
+
+ if (!has_alpha)
+ opacity_mode_ = kOpaque;
+}
+
+CanvasResourceParams CanvasColorParams::GetAsResourceParams() const {
+ SkAlphaType alpha_type =
+ opacity_mode_ == kOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+ return CanvasResourceParams(color_space_, GetSkColorType(), alpha_type);
+}
+
+const char* CanvasColorParams::GetColorSpaceAsString() const {
+ switch (color_space_) {
+ case CanvasColorSpace::kSRGB:
+ return kSRGBCanvasColorSpaceName;
+ case CanvasColorSpace::kRec2020:
+ return kRec2020CanvasColorSpaceName;
+ case CanvasColorSpace::kP3:
+ return kP3CanvasColorSpaceName;
+ };
+ CHECK(false);
+ return "";
+}
+
+const char* CanvasColorParams::GetPixelFormatAsString() const {
+ switch (pixel_format_) {
+ case CanvasPixelFormat::kF16:
+ return kF16CanvasPixelFormatName;
+ case CanvasPixelFormat::kUint8:
+ return kUint8CanvasPixelFormatName;
+ };
+ CHECK(false);
+ return "";
+}
SkColorType CanvasColorParams::GetSkColorType() const {
switch (pixel_format_) {
case CanvasPixelFormat::kF16:
return kRGBA_F16_SkColorType;
- case CanvasPixelFormat::kRGBA8:
- return kRGBA_8888_SkColorType;
- case CanvasPixelFormat::kBGRA8:
- return kBGRA_8888_SkColorType;
+ case CanvasPixelFormat::kUint8:
+ return kN32_SkColorType;
}
NOTREACHED();
return kN32_SkColorType;
}
-SkAlphaType CanvasColorParams::GetSkAlphaType() const {
- return opacity_mode_ == kOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-}
-
-const SkSurfaceProps* CanvasColorParams::GetSkSurfaceProps() const {
- static const SkSurfaceProps disable_lcd_props(0, kUnknown_SkPixelGeometry);
- if (opacity_mode_ == kOpaque)
- return nullptr;
- return &disable_lcd_props;
-}
uint8_t CanvasColorParams::BytesPerPixel() const {
return SkColorTypeBytesPerPixel(GetSkColorType());
}
-gfx::ColorSpace CanvasColorParams::GetSamplerGfxColorSpace() const {
- // TODO(ccameron): If we add support for uint8srgb as a pixel format, this
- // will need to take into account whether or not this texture will be sampled
- // in linear or nonlinear space.
- return CanvasColorSpaceToGfxColorSpace(color_space_);
-}
-
gfx::ColorSpace CanvasColorParams::GetStorageGfxColorSpace() const {
return CanvasColorSpaceToGfxColorSpace(color_space_);
}
@@ -100,94 +154,4 @@ sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpace() const {
return CanvasColorSpaceToSkColorSpace(color_space_);
}
-gfx::BufferFormat CanvasColorParams::GetBufferFormat() const {
- switch (GetSkColorType()) {
- case kRGBA_8888_SkColorType:
- return gfx::BufferFormat::RGBA_8888;
- case kBGRA_8888_SkColorType:
- return gfx::BufferFormat::BGRA_8888;
- case kRGBA_F16_SkColorType:
- return gfx::BufferFormat::RGBA_F16;
- default:
- NOTREACHED();
- }
-
- return gfx::BufferFormat::RGBA_8888;
-}
-
-GLenum CanvasColorParams::GLUnsizedInternalFormat() const {
- // TODO(junov): try GL_RGB when opacity_mode_ == kOpaque
- switch (GetSkColorType()) {
- case kRGBA_8888_SkColorType:
- return GL_RGBA;
- case kBGRA_8888_SkColorType:
- return GL_BGRA_EXT;
- case kRGBA_F16_SkColorType:
- return GL_RGBA;
- default:
- NOTREACHED();
- }
-
- return GL_RGBA;
-}
-
-GLenum CanvasColorParams::GLSizedInternalFormat() const {
- switch (GetSkColorType()) {
- case kRGBA_8888_SkColorType:
- return GL_RGBA8;
- case kBGRA_8888_SkColorType:
- return GL_BGRA8_EXT;
- case kRGBA_F16_SkColorType:
- return GL_RGBA16F;
- default:
- NOTREACHED();
- }
-
- return GL_RGBA8;
-}
-
-GLenum CanvasColorParams::GLType() const {
- switch (GetSkColorType()) {
- case kRGBA_8888_SkColorType:
- case kBGRA_8888_SkColorType:
- return GL_UNSIGNED_BYTE;
- case kRGBA_F16_SkColorType:
- return GL_HALF_FLOAT_OES;
- default:
- NOTREACHED();
- }
-
- return GL_UNSIGNED_BYTE;
-}
-
-viz::ResourceFormat CanvasColorParams::TransferableResourceFormat() const {
- return viz::GetResourceFormat(GetBufferFormat());
-}
-
-CanvasColorParams::CanvasColorParams(const sk_sp<SkColorSpace> sk_color_space,
- SkColorType sk_color_type) {
- color_space_ = CanvasColorSpace::kSRGB;
- pixel_format_ = GetNativeCanvasPixelFormat();
-
- CanvasColorSpace color_spaces[] = {
- CanvasColorSpace::kSRGB,
- CanvasColorSpace::kRec2020,
- CanvasColorSpace::kP3,
- };
- for (const auto& color_space : color_spaces) {
- if (SkColorSpace::Equals(sk_color_space.get(),
- CanvasColorSpaceToGfxColorSpace(color_space)
- .ToSkColorSpace()
- .get())) {
- color_space_ = color_space;
- break;
- }
- }
-
- if (sk_color_type == kRGBA_F16_SkColorType)
- pixel_format_ = CanvasPixelFormat::kF16;
- else if (sk_color_type == kRGBA_8888_SkColorType)
- pixel_format_ = CanvasPixelFormat::kRGBA8;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.h
index f08a72255fb..e32f3d9bc1e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.h
@@ -13,14 +13,14 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/buffer_types.h"
-class SkSurfaceProps;
-
namespace gfx {
class ColorSpace;
}
namespace blink {
+class CanvasResourceParams;
+
enum class CanvasColorSpace {
kSRGB,
kRec2020,
@@ -28,14 +28,30 @@ enum class CanvasColorSpace {
};
enum class CanvasPixelFormat {
- kRGBA8,
- kBGRA8,
+ kUint8,
kF16,
};
+constexpr const char* kSRGBCanvasColorSpaceName = "srgb";
+constexpr const char* kRec2020CanvasColorSpaceName = "rec2020";
+constexpr const char* kP3CanvasColorSpaceName = "display-p3";
+
+constexpr const char* kUint8CanvasPixelFormatName = "uint8";
+constexpr const char* kF16CanvasPixelFormatName = "float16";
+
+// Return the CanvasColorSpace for the specified |name|. On invalid inputs,
+// returns CanvasColorSpace::kSRGB.
+CanvasColorSpace PLATFORM_EXPORT
+CanvasColorSpaceFromName(const String& color_space_name);
+
+// Return the SkColorSpace for the specified |color_space|.
sk_sp<SkColorSpace> PLATFORM_EXPORT
CanvasColorSpaceToSkColorSpace(CanvasColorSpace color_space);
+// Return the named CanvasColorSpace that best matches |sk_color_space|.
+CanvasColorSpace PLATFORM_EXPORT
+CanvasColorSpaceFromSkColorSpace(const SkColorSpace* sk_color_space);
+
class PLATFORM_EXPORT CanvasColorParams {
DISALLOW_NEW();
@@ -43,52 +59,32 @@ class PLATFORM_EXPORT CanvasColorParams {
// The default constructor will create an output-blended 8-bit surface.
CanvasColorParams();
CanvasColorParams(CanvasColorSpace, CanvasPixelFormat, OpacityMode);
- explicit CanvasColorParams(const SkImageInfo&);
-
- static CanvasPixelFormat GetNativeCanvasPixelFormat() {
- if (kN32_SkColorType == kRGBA_8888_SkColorType)
- return CanvasPixelFormat::kRGBA8;
- else if (kN32_SkColorType == kBGRA_8888_SkColorType)
- return CanvasPixelFormat::kBGRA8;
- }
+ CanvasColorParams(const WTF::String& color_space,
+ const WTF::String& pixel_format,
+ bool has_alpha);
CanvasColorSpace ColorSpace() const { return color_space_; }
CanvasPixelFormat PixelFormat() const { return pixel_format_; }
OpacityMode GetOpacityMode() const { return opacity_mode_; }
- void SetCanvasColorSpace(CanvasColorSpace c) { color_space_ = c; }
- void SetCanvasPixelFormat(CanvasPixelFormat f) { pixel_format_ = f; }
- void SetOpacityMode(OpacityMode m) { opacity_mode_ = m; }
+ const char* GetColorSpaceAsString() const;
+ const char* GetPixelFormatAsString() const;
+
+ CanvasResourceParams GetAsResourceParams() const;
// The pixel format to use for allocating SkSurfaces.
SkColorType GetSkColorType() const;
- uint8_t BytesPerPixel() const;
-
- // The color space in which pixels read from the canvas via a shader will be
- // returned. Note that for canvases with linear pixel math, these will be
- // converted from their storage space into a linear space.
- gfx::ColorSpace GetSamplerGfxColorSpace() const;
// Return the color space of the underlying data for the canvas.
gfx::ColorSpace GetStorageGfxColorSpace() const;
sk_sp<SkColorSpace> GetSkColorSpace() const;
- SkAlphaType GetSkAlphaType() const;
- const SkSurfaceProps* GetSkSurfaceProps() const;
-
- // Gpu memory buffer parameters
- gfx::BufferFormat GetBufferFormat() const;
- uint32_t GLSizedInternalFormat() const; // For GLES2, use Unsized
- uint32_t GLUnsizedInternalFormat() const;
- uint32_t GLType() const;
- viz::ResourceFormat TransferableResourceFormat() const;
+ uint8_t BytesPerPixel() const;
private:
- CanvasColorParams(const sk_sp<SkColorSpace> color_space,
- SkColorType color_type);
CanvasColorSpace color_space_ = CanvasColorSpace::kSRGB;
- CanvasPixelFormat pixel_format_ = GetNativeCanvasPixelFormat();
+ CanvasPixelFormat pixel_format_ = CanvasPixelFormat::kUint8;
OpacityMode opacity_mode_ = kNonOpaque;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
index a6503d5443f..fe6eb7a3c80 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/platform/graphics/color_correction_test_utils.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "ui/gfx/color_space.h"
+#include "ui/gl/buffer_format_utils.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 43dc33e1751..c2b5fc60f25 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -35,25 +35,16 @@
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/color_space.h"
-#if BUILDFLAG(SKIA_USE_DAWN)
-namespace {
-// TODO(senorblanco): This should be using RequestDeviceAsync(), but
-// those callbacks don't seem to work currently. Assume device 1
-// and use it in all the WebGPUInterface calls. http://crbug.com/1078775
-constexpr uint64_t kWebGPUDeviceClientID = 1;
-} // namespace
-#endif
-
namespace blink {
CanvasResource::CanvasResource(base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params)
+ const CanvasResourceParams& params)
: owning_thread_ref_(base::PlatformThread::CurrentRef()),
owning_thread_task_runner_(Thread::Current()->GetTaskRunner()),
provider_(std::move(provider)),
filter_quality_(filter_quality),
- color_params_(color_params) {}
+ params_(params) {}
CanvasResource::~CanvasResource() {
#if DCHECK_IS_ON()
@@ -134,8 +125,8 @@ bool CanvasResource::PrepareTransferableResource(
DCHECK(IsValid());
DCHECK(out_callback);
- auto func = WTF::Bind(&ReleaseFrameResources, provider_,
- WTF::Passed(base::WrapRefCounted(this)));
+ auto func =
+ WTF::Bind(&ReleaseFrameResources, provider_, base::WrapRefCounted(this));
*out_callback = viz::SingleReleaseCallback::Create(std::move(func));
if (!out_resource)
@@ -162,8 +153,8 @@ bool CanvasResource::PrepareAcceleratedTransferableResource(
mailbox, GLFilter(), TextureTarget(), GetSyncToken(), gfx::Size(Size()),
IsOverlayCandidate());
- out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
- out_resource->format = color_params_.TransferableResourceFormat();
+ out_resource->color_space = params_.GetSamplerGfxColorSpace();
+ out_resource->format = params_.TransferableResourceFormat();
out_resource->read_lock_fences_enabled = NeedsReadLockFences();
return true;
@@ -184,7 +175,7 @@ bool CanvasResource::PrepareUnacceleratedTransferableResource(
*out_resource = viz::TransferableResource::MakeSoftware(
mailbox, gfx::Size(Size()), viz::RGBA_8888);
- out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
+ out_resource->color_space = params_.GetSamplerGfxColorSpace();
return true;
}
@@ -210,11 +201,10 @@ GLenum CanvasResource::GLFilter() const {
CanvasResourceSharedBitmap::CanvasResourceSharedBitmap(
const IntSize& size,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality)
- : CanvasResource(std::move(provider), filter_quality, color_params),
- size_(size) {
+ : CanvasResource(std::move(provider), filter_quality, params), size_(size) {
// Software compositing lazily uses RGBA_8888 as the resource format
// everywhere but the content is expected to be rendered in N32 format.
base::MappedReadOnlyRegion shm = viz::bitmap_allocation::AllocateSharedBitmap(
@@ -272,11 +262,11 @@ scoped_refptr<StaticBitmapImage> CanvasResourceSharedBitmap::Bitmap() {
scoped_refptr<CanvasResourceSharedBitmap> CanvasResourceSharedBitmap::Create(
const IntSize& size,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality) {
auto resource = AdoptRef(new CanvasResourceSharedBitmap(
- size, color_params, std::move(provider), filter_quality));
+ size, params, std::move(provider), filter_quality));
return resource->IsValid() ? resource : nullptr;
}
@@ -323,8 +313,8 @@ void CanvasResourceSharedBitmap::TakeSkImage(sk_sp<SkImage> image) {
CanvasResourceSharedImage::CanvasResourceSharedImage(
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params)
- : CanvasResource(provider, filter_quality, color_params) {}
+ const CanvasResourceParams& params)
+ : CanvasResource(provider, filter_quality, params) {}
// CanvasResourceRasterSharedImage
//==============================================================================
@@ -334,19 +324,28 @@ CanvasResourceRasterSharedImage::CanvasResourceRasterSharedImage(
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
bool is_origin_top_left,
bool is_accelerated,
uint32_t shared_image_usage_flags)
- : CanvasResourceSharedImage(std::move(provider),
- filter_quality,
- color_params),
+ : CanvasResourceSharedImage(std::move(provider), filter_quality, params),
context_provider_wrapper_(std::move(context_provider_wrapper)),
size_(size),
is_origin_top_left_(is_origin_top_left),
is_accelerated_(is_accelerated),
+#if defined(OS_MAC)
+ // On Mac, WebGPU usage is always backed by an IOSurface which should
+ // should also use the GL_TEXTURE_RECTANGLE target instead of
+ // GL_TEXTURE_2D. Setting |is_overlay_candidate_| both allows overlays,
+ // and causes |texture_target_| to take the value returned from
+ // gpu::GetBufferTextureTarget.
+ is_overlay_candidate_(
+ shared_image_usage_flags &
+ (gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_WEBGPU)),
+#else
is_overlay_candidate_(shared_image_usage_flags &
gpu::SHARED_IMAGE_USAGE_SCANOUT),
+#endif
texture_target_(
is_overlay_candidate_
? gpu::GetBufferTextureTarget(
@@ -370,7 +369,7 @@ CanvasResourceRasterSharedImage::CanvasResourceRasterSharedImage(
if (!gpu_memory_buffer_)
return;
- gpu_memory_buffer_->SetColorSpace(color_params.GetStorageGfxColorSpace());
+ gpu_memory_buffer_->SetColorSpace(params.GetStorageGfxColorSpace());
}
auto* shared_image_interface =
@@ -438,14 +437,14 @@ CanvasResourceRasterSharedImage::Create(
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
bool is_origin_top_left,
bool is_accelerated,
uint32_t shared_image_usage_flags) {
TRACE_EVENT0("blink", "CanvasResourceRasterSharedImage::Create");
auto resource = base::AdoptRef(new CanvasResourceRasterSharedImage(
size, std::move(context_provider_wrapper), std::move(provider),
- filter_quality, color_params, is_origin_top_left, is_accelerated,
+ filter_quality, params, is_origin_top_left, is_accelerated,
shared_image_usage_flags));
return resource->IsValid() ? resource : nullptr;
}
@@ -723,12 +722,10 @@ CanvasResourceSkiaDawnSharedImage::CanvasResourceSkiaDawnSharedImage(
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
bool is_origin_top_left,
uint32_t shared_image_usage_flags)
- : CanvasResourceSharedImage(std::move(provider),
- filter_quality,
- color_params),
+ : CanvasResourceSharedImage(std::move(provider), filter_quality, params),
context_provider_wrapper_(std::move(context_provider_wrapper)),
size_(size),
owning_thread_task_runner_(Thread::Current()->GetTaskRunner()),
@@ -774,14 +771,13 @@ CanvasResourceSkiaDawnSharedImage::Create(
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
bool is_origin_top_left,
uint32_t shared_image_usage_flags) {
TRACE_EVENT0("blink", "CanvasResourceSkiaDawnSharedImage::Create");
auto resource = base::AdoptRef(new CanvasResourceSkiaDawnSharedImage(
size, std::move(context_provider_wrapper), std::move(provider),
- filter_quality, color_params, is_origin_top_left,
- shared_image_usage_flags));
+ filter_quality, params, is_origin_top_left, shared_image_usage_flags));
return resource->IsValid() ? resource : nullptr;
}
@@ -834,8 +830,10 @@ void CanvasResourceSkiaDawnSharedImage::WillDraw() {
void CanvasResourceSkiaDawnSharedImage::BeginAccess() {
auto* webgpu = WebGPUInterface();
+ // TODO(senorblanco): create an actual passed-in Device, rather than this
+ // default hacky one. http://crbug.com/1078775
gpu::webgpu::ReservedTexture reservation =
- webgpu->ReserveTexture(kWebGPUDeviceClientID);
+ webgpu->ReserveTexture(webgpu->DeprecatedEnsureDefaultDeviceSync());
DCHECK(reservation.texture);
owning_thread_data().texture = wgpu::Texture(reservation.texture);
@@ -843,8 +841,8 @@ void CanvasResourceSkiaDawnSharedImage::BeginAccess() {
owning_thread_data().generation = reservation.generation;
webgpu->FlushCommands();
webgpu->AssociateMailbox(
- kWebGPUDeviceClientID, 0, owning_thread_data().id,
- owning_thread_data().generation,
+ reservation.deviceId, reservation.deviceGeneration,
+ owning_thread_data().id, owning_thread_data().generation,
WGPUTextureUsage_Sampled | WGPUTextureUsage_OutputAttachment,
reinterpret_cast<GLbyte*>(&owning_thread_data().shared_image_mailbox));
}
@@ -852,7 +850,7 @@ void CanvasResourceSkiaDawnSharedImage::BeginAccess() {
void CanvasResourceSkiaDawnSharedImage::EndAccess() {
auto* webgpu = WebGPUInterface();
webgpu->FlushCommands();
- webgpu->DissociateMailbox(kWebGPUDeviceClientID, owning_thread_data().id,
+ webgpu->DissociateMailbox(owning_thread_data().id,
owning_thread_data().generation);
owning_thread_data().texture = nullptr;
@@ -1031,18 +1029,21 @@ CanvasResourceSkiaDawnSharedImage::ContextProviderWrapper() const {
//==============================================================================
scoped_refptr<ExternalCanvasResource> ExternalCanvasResource::Create(
const gpu::Mailbox& mailbox,
+ std::unique_ptr<viz::SingleReleaseCallback> release_callback,
+ gpu::SyncToken sync_token,
const IntSize& size,
GLenum texture_target,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- bool is_origin_top_left) {
+ bool is_origin_top_left,
+ bool is_overlay_candidate) {
TRACE_EVENT0("blink", "ExternalCanvasResource::Create");
auto resource = AdoptRef(new ExternalCanvasResource(
- mailbox, size, texture_target, color_params,
- std::move(context_provider_wrapper), std::move(provider), filter_quality,
- is_origin_top_left));
+ mailbox, std::move(release_callback), sync_token, size, texture_target,
+ params, std::move(context_provider_wrapper), std::move(provider),
+ filter_quality, is_origin_top_left, is_overlay_candidate));
return resource->IsValid() ? resource : nullptr;
}
@@ -1051,7 +1052,7 @@ ExternalCanvasResource::~ExternalCanvasResource() {
}
bool ExternalCanvasResource::IsValid() const {
- return context_provider_wrapper_ && !mailbox_.IsZero();
+ return context_provider_wrapper_ && HasGpuMailbox();
}
void ExternalCanvasResource::Abandon() {
@@ -1084,6 +1085,8 @@ scoped_refptr<StaticBitmapImage> ExternalCanvasResource::Bitmap() {
}
void ExternalCanvasResource::TearDown() {
+ if (release_callback_)
+ release_callback_->Run(GetSyncToken(), resource_is_lost_);
Abandon();
}
@@ -1104,6 +1107,14 @@ const gpu::SyncToken ExternalCanvasResource::GetSyncToken() {
auto* gl = ContextGL();
if (gl)
gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
+ } else if (!sync_token_.verified_flush()) {
+ // The offscreencanvas usage needs the sync_token to be verified in order to
+ // be able to use it by the compositor.
+ int8_t* token_data = sync_token_.GetData();
+ auto* gl = ContextGL();
+ gl->ShallowFlushCHROMIUM();
+ gl->VerifySyncTokensCHROMIUM(&token_data, 1);
+ sync_token_.SetVerifyFlush();
}
return sync_token_;
}
@@ -1115,32 +1126,40 @@ ExternalCanvasResource::ContextProviderWrapper() const {
ExternalCanvasResource::ExternalCanvasResource(
const gpu::Mailbox& mailbox,
+ std::unique_ptr<viz::SingleReleaseCallback> out_callback,
+ gpu::SyncToken sync_token,
const IntSize& size,
GLenum texture_target,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality,
- bool is_origin_top_left)
- : CanvasResource(std::move(provider), filter_quality, color_params),
+ bool is_origin_top_left,
+ bool is_overlay_candidate)
+ : CanvasResource(std::move(provider), filter_quality, params),
context_provider_wrapper_(std::move(context_provider_wrapper)),
size_(size),
mailbox_(mailbox),
texture_target_(texture_target),
- is_origin_top_left_(is_origin_top_left) {}
+ release_callback_(std::move(out_callback)),
+ sync_token_(sync_token),
+ is_origin_top_left_(is_origin_top_left),
+ is_overlay_candidate_(is_overlay_candidate) {
+ DCHECK(!release_callback_ || sync_token_.HasData());
+}
// CanvasResourceSwapChain
//==============================================================================
scoped_refptr<CanvasResourceSwapChain> CanvasResourceSwapChain::Create(
const IntSize& size,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality) {
TRACE_EVENT0("blink", "CanvasResourceSwapChain::Create");
auto resource = AdoptRef(new CanvasResourceSwapChain(
- size, color_params, std::move(context_provider_wrapper),
- std::move(provider), filter_quality));
+ size, params, std::move(context_provider_wrapper), std::move(provider),
+ filter_quality));
return resource->IsValid() ? resource : nullptr;
}
@@ -1260,11 +1279,11 @@ CanvasResourceSwapChain::ContextProviderWrapper() const {
CanvasResourceSwapChain::CanvasResourceSwapChain(
const IntSize& size,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceProvider> provider,
SkFilterQuality filter_quality)
- : CanvasResource(std::move(provider), filter_quality, color_params),
+ : CanvasResource(std::move(provider), filter_quality, params),
context_provider_wrapper_(std::move(context_provider_wrapper)),
size_(size) {
if (!context_provider_wrapper_)
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.h
index 8f08d72d020..cb836ed76c0 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -13,7 +13,7 @@
#include "gpu/ipc/common/mailbox.mojom-blink.h"
#include "skia/buildflags.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
-#include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_params.h"
#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
@@ -159,7 +159,7 @@ class PLATFORM_EXPORT CanvasResource
protected:
CanvasResource(base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&);
+ const CanvasResourceParams&);
// Called during resource destruction if the resource is destroyed on a thread
// other than where it was created. This implies that no context associated
@@ -198,7 +198,7 @@ class PLATFORM_EXPORT CanvasResource
MailboxSyncMode);
bool PrepareUnacceleratedTransferableResource(
viz::TransferableResource* out_resource);
- const CanvasColorParams& ColorParams() const { return color_params_; }
+ const CanvasResourceParams& ColorParams() const { return params_; }
void OnDestroy();
CanvasResourceProvider* Provider() { return provider_.get(); }
base::WeakPtr<CanvasResourceProvider> WeakProvider() { return provider_; }
@@ -210,8 +210,9 @@ class PLATFORM_EXPORT CanvasResource
// Sync token that was provided when resource was released
gpu::SyncToken sync_token_for_release_;
base::WeakPtr<CanvasResourceProvider> provider_;
+ // TODO(https://crbug.com/1157747): Merge |filter_quality_| into |params_|.
SkFilterQuality filter_quality_;
- CanvasColorParams color_params_;
+ CanvasResourceParams params_;
#if DCHECK_IS_ON()
bool did_call_on_destroy_ = false;
#endif
@@ -222,7 +223,7 @@ class PLATFORM_EXPORT CanvasResourceSharedBitmap final : public CanvasResource {
public:
static scoped_refptr<CanvasResourceSharedBitmap> Create(
const IntSize&,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality);
~CanvasResourceSharedBitmap() override;
@@ -245,7 +246,7 @@ class PLATFORM_EXPORT CanvasResourceSharedBitmap final : public CanvasResource {
bool HasGpuMailbox() const override;
CanvasResourceSharedBitmap(const IntSize&,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality);
@@ -271,7 +272,7 @@ class PLATFORM_EXPORT CanvasResourceSharedImage : public CanvasResource {
protected:
CanvasResourceSharedImage(base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&);
+ const CanvasResourceParams&);
};
// Resource type for Raster-based SharedImage
@@ -283,7 +284,7 @@ class PLATFORM_EXPORT CanvasResourceRasterSharedImage final
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
bool is_origin_top_left,
bool is_accelerated,
uint32_t shared_image_usage_flags);
@@ -370,7 +371,7 @@ class PLATFORM_EXPORT CanvasResourceRasterSharedImage final
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
bool is_origin_top_left,
bool is_accelerated,
uint32_t shared_image_usage_flags);
@@ -428,7 +429,7 @@ class PLATFORM_EXPORT CanvasResourceSkiaDawnSharedImage final
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
bool is_origin_top_left,
uint32_t shared_image_usage_flags);
~CanvasResourceSkiaDawnSharedImage() override;
@@ -501,7 +502,7 @@ class PLATFORM_EXPORT CanvasResourceSkiaDawnSharedImage final
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
bool is_origin_top_left,
uint32_t shared_image_usage_flags);
@@ -550,17 +551,24 @@ class PLATFORM_EXPORT CanvasResourceSkiaDawnSharedImage final
// Resource type for a given opaque external resource described on construction
// via a Mailbox; this CanvasResource IsAccelerated() by definition.
+// This resource can also encapsulate an external mailbox, synctoken and release
+// callback, exported from WebGL. This CanvasResource should only be used with
+// context that support GL.
class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource {
public:
static scoped_refptr<ExternalCanvasResource> Create(
- const gpu::Mailbox&,
+ const gpu::Mailbox& mailbox,
+ std::unique_ptr<viz::SingleReleaseCallback> release_callback,
+ gpu::SyncToken sync_token,
const IntSize&,
GLenum texture_target,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality,
- bool is_origin_top_left);
+ bool is_origin_top_left,
+ bool is_overlay_candidate);
+
~ExternalCanvasResource() override;
bool IsRecycleable() const final { return IsValid(); }
bool IsAccelerated() const final { return true; }
@@ -572,10 +580,7 @@ class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource {
void Abandon() final;
IntSize Size() const final { return size_; }
void TakeSkImage(sk_sp<SkImage> image) final;
- void NotifyResourceLost() override {
- // Used for single buffering mode which doesn't need to care about sync
- // token synchronization.
- }
+ void NotifyResourceLost() override { resource_is_lost_ = true; }
scoped_refptr<StaticBitmapImage> Bitmap() override;
const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override;
@@ -583,38 +588,44 @@ class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource {
private:
void TearDown() override;
GLenum TextureTarget() const final { return texture_target_; }
- bool IsOverlayCandidate() const final { return true; }
+ bool IsOverlayCandidate() const final { return is_overlay_candidate_; }
bool HasGpuMailbox() const override;
const gpu::SyncToken GetSyncToken() override;
base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
const override;
- ExternalCanvasResource(const gpu::Mailbox&,
- const IntSize&,
- GLenum texture_target,
- const CanvasColorParams&,
- base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
- base::WeakPtr<CanvasResourceProvider>,
- SkFilterQuality,
- bool is_origin_top_left);
+ ExternalCanvasResource(
+ const gpu::Mailbox& mailbox,
+ std::unique_ptr<viz::SingleReleaseCallback> out_callback,
+ gpu::SyncToken sync_token,
+ const IntSize&,
+ GLenum texture_target,
+ const CanvasResourceParams&,
+ base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
+ base::WeakPtr<CanvasResourceProvider>,
+ SkFilterQuality,
+ bool is_origin_top_left,
+ bool is_overlay_candidate);
const base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper_;
const IntSize size_;
const gpu::Mailbox mailbox_;
const GLenum texture_target_;
- const bool is_origin_top_left_;
-
+ std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
gpu::SyncToken sync_token_;
+ const bool is_origin_top_left_;
bool is_origin_clean_ = true;
+ bool resource_is_lost_ = false;
+ const bool is_overlay_candidate_;
};
class PLATFORM_EXPORT CanvasResourceSwapChain final : public CanvasResource {
public:
static scoped_refptr<CanvasResourceSwapChain> Create(
const IntSize&,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality);
@@ -652,7 +663,7 @@ class PLATFORM_EXPORT CanvasResourceSwapChain final : public CanvasResource {
const override;
CanvasResourceSwapChain(const IntSize&,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceProvider>,
SkFilterQuality);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index 882843937ed..cd91934b558 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -8,6 +8,9 @@
#include "base/debug/stack_trace.h"
#include "base/single_thread_task_runner.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/resource_format.h"
@@ -21,6 +24,7 @@
#include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h"
+#include "third_party/blink/renderer/platform/graphics/resource_id_traits.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
@@ -51,6 +55,8 @@ struct CanvasResourceDispatcher::FrameResource {
CanvasResourceDispatcher::CanvasResourceDispatcher(
CanvasResourceDispatcherClient* client,
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner,
uint32_t client_id,
uint32_t sink_id,
int canvas_id,
@@ -61,7 +67,12 @@ CanvasResourceDispatcher::CanvasResourceDispatcher(
needs_begin_frame_(false),
placeholder_canvas_id_(canvas_id),
num_unreclaimed_frames_posted_(0),
- client_(client) {
+ client_(client),
+ agent_group_scheduler_compositor_task_runner_(
+ std::move(agent_group_scheduler_compositor_task_runner)),
+ animation_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Animation.Canvas")) {
// Frameless canvas pass an invalid |frame_sink_id_|; don't create mojo
// channel for this special case.
if (!frame_sink_id_.is_valid())
@@ -140,13 +151,11 @@ void CanvasResourceDispatcher::PostImageToPlaceholderIfNotBlocked(
void CanvasResourceDispatcher::PostImageToPlaceholder(
scoped_refptr<CanvasResource> canvas_resource,
viz::ResourceId resource_id) {
- scoped_refptr<base::SingleThreadTaskRunner> dispatcher_task_runner =
- Thread::Current()->GetTaskRunner();
// After this point, |canvas_resource| can only be used on the main thread,
// until it is returned.
canvas_resource->Transfer();
PostCrossThreadTask(
- *Thread::MainThread()->Scheduler()->CompositorTaskRunner(), FROM_HERE,
+ *agent_group_scheduler_compositor_task_runner_, FROM_HERE,
CrossThreadBindOnce(UpdatePlaceholderImage, placeholder_canvas_id_,
std::move(canvas_resource), resource_id));
}
@@ -203,12 +212,12 @@ bool CanvasResourceDispatcher::PrepareFrame(
return false;
}
- next_resource_id_++;
+ auto next_resource_id = id_generator_.GenerateNextId();
// For frameless canvas, we don't get a valid frame_sink_id and should drop.
if (!frame_sink_id_.is_valid()) {
PostImageToPlaceholderIfNotBlocked(std::move(canvas_resource),
- next_resource_id_);
+ next_resource_id);
return false;
}
@@ -248,7 +257,7 @@ bool CanvasResourceDispatcher::PrepareFrame(
canvas_resource->PrepareTransferableResource(
&resource, &frame_resource->release_callback, kVerifiedSyncToken);
- const unsigned resource_id = next_resource_id_;
+ const viz::ResourceId resource_id = next_resource_id;
resource.id = resource_id;
resources_.insert(resource_id, std::move(frame_resource));
@@ -303,8 +312,24 @@ void CanvasResourceDispatcher::DidReceiveCompositorFrameAck(
}
void CanvasResourceDispatcher::SetNeedsBeginFrame(bool needs_begin_frame) {
- if (needs_begin_frame_ == needs_begin_frame)
+ if (needs_begin_frame_ == needs_begin_frame) {
+ // If the offscreencanvas is in the same tread as the canvas, and we are
+ // trying for a second time to request the being frame, and we are in a
+ // capture_stream scenario, we will call a BeginFrame right away. So
+ // Offscreen Canvas can behave in a more synchronous way when it's on the
+ // main thread.
+ if (needs_begin_frame_ && IsMainThread()) {
+ OffscreenCanvasPlaceholder* placeholder_canvas =
+ OffscreenCanvasPlaceholder::GetPlaceholderCanvasById(
+ placeholder_canvas_id_);
+ if (placeholder_canvas &&
+ placeholder_canvas->IsOffscreenCanvasRegistered() &&
+ placeholder_canvas->HasCanvasCapture() && Client()) {
+ Client()->BeginFrame();
+ }
+ }
return;
+ }
needs_begin_frame_ = needs_begin_frame;
if (!suspend_animation_)
SetNeedsBeginFrameInternal();
@@ -319,8 +344,19 @@ void CanvasResourceDispatcher::SetSuspendAnimation(bool suspend_animation) {
}
void CanvasResourceDispatcher::SetNeedsBeginFrameInternal() {
- if (sink_)
- sink_->SetNeedsBeginFrame(needs_begin_frame_ && !suspend_animation_);
+ if (!sink_)
+ return;
+
+ bool needs_begin_frame = needs_begin_frame_ && !suspend_animation_;
+ sink_->SetNeedsBeginFrame(needs_begin_frame);
+
+ if (needs_begin_frame) {
+ animation_power_mode_voter_->VoteFor(
+ power_scheduler::PowerMode::kAnimation);
+ } else {
+ animation_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kAnimationTimeout);
+ }
}
bool CanvasResourceDispatcher::HasTooManyPendingFrames() const {
@@ -379,7 +415,7 @@ void CanvasResourceDispatcher::ReclaimResource(viz::ResourceId resource_id) {
kMaxUnreclaimedPlaceholderFrames - 1);
PostImageToPlaceholderIfNotBlocked(std::move(latest_unposted_image_),
latest_unposted_resource_id_);
- latest_unposted_resource_id_ = 0;
+ latest_unposted_resource_id_ = viz::kInvalidResourceId;
}
}
@@ -425,9 +461,9 @@ void CanvasResourceDispatcher::SetPlaceholderCanvasDispatcher(
placeholder_canvas_id);
} else {
PostCrossThreadTask(
- *Thread::MainThread()->Scheduler()->CompositorTaskRunner(), FROM_HERE,
+ *agent_group_scheduler_compositor_task_runner_, FROM_HERE,
CrossThreadBindOnce(UpdatePlaceholderDispatcher, this->GetWeakPtr(),
- WTF::Passed(std::move(dispatcher_task_runner)),
+ std::move(dispatcher_task_runner),
placeholder_canvas_id));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
index b8549abc864..7c420864406 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/memory/read_only_shared_memory_region.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
@@ -16,6 +17,7 @@
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h"
#include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/graphics/resource_id_traits.h"
#include "third_party/blink/renderer/platform/platform_export.h"
namespace blink {
@@ -42,6 +44,8 @@ class PLATFORM_EXPORT CanvasResourceDispatcher
};
CanvasResourceDispatcher(CanvasResourceDispatcherClient*,
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner,
uint32_t client_id,
uint32_t sink_id,
int placeholder_canvas_id,
@@ -90,7 +94,9 @@ class PLATFORM_EXPORT CanvasResourceDispatcher
private:
friend class CanvasResourceDispatcherTest;
struct FrameResource;
- using ResourceMap = HashMap<unsigned, std::unique_ptr<FrameResource>>;
+
+ using ResourceMap =
+ HashMap<viz::ResourceId, std::unique_ptr<FrameResource>, ResourceIdHash>;
bool PrepareFrame(scoped_refptr<CanvasResource>,
base::TimeTicks commit_start_time,
@@ -127,7 +133,7 @@ class PLATFORM_EXPORT CanvasResourceDispatcher
int placeholder_canvas_id_;
- unsigned next_resource_id_ = 0;
+ viz::ResourceIdGenerator id_generator_;
ResourceMap resources_;
viz::FrameTokenGenerator next_frame_token_;
@@ -142,6 +148,11 @@ class PLATFORM_EXPORT CanvasResourceDispatcher
CanvasResourceDispatcherClient* client_;
+ scoped_refptr<base::SingleThreadTaskRunner>
+ agent_group_scheduler_compositor_task_runner_;
+
+ std::unique_ptr<power_scheduler::PowerModeVoter> animation_power_mode_voter_;
+
base::WeakPtrFactory<CanvasResourceDispatcher> weak_ptr_factory_{this};
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
index 5fa65e92770..5d85dea7213 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
@@ -38,19 +38,26 @@ struct TestParams {
bool context_alpha;
bool vertical_flip;
};
+
+viz::ResourceId NextId(viz::ResourceId id) {
+ return viz::ResourceId(id.GetUnsafeValue() + 1);
+}
+
} // namespace
class MockCanvasResourceDispatcher : public CanvasResourceDispatcher {
public:
MockCanvasResourceDispatcher()
: CanvasResourceDispatcher(nullptr /* client */,
+ base::ThreadTaskRunnerHandle::Get(),
kClientId,
kSinkId,
0 /* placeholder_canvas_id* */,
{kWidth, kHeight} /* canvas_size */) {}
MOCK_METHOD2(PostImageToPlaceholder,
- void(scoped_refptr<CanvasResource>, unsigned resource_id));
+ void(scoped_refptr<CanvasResource>,
+ viz::ResourceId resource_id));
};
class CanvasResourceDispatcherTest
@@ -76,8 +83,8 @@ class CanvasResourceDispatcherTest
return dispatcher_->latest_unposted_resource_id_;
}
- viz::ResourceId GetCurrentResourceId() {
- return dispatcher_->next_resource_id_;
+ viz::ResourceId PeekNextResourceId() {
+ return dispatcher_->id_generator_.PeekNextValueForTesting();
}
const IntSize& GetSize() const { return dispatcher_->size_; }
@@ -88,7 +95,7 @@ class CanvasResourceDispatcherTest
void CreateCanvasResourceDispatcher() {
dispatcher_ = std::make_unique<MockCanvasResourceDispatcher>();
resource_provider_ = CanvasResourceProvider::CreateSharedBitmapProvider(
- IntSize(kWidth, kHeight), kLow_SkFilterQuality, CanvasColorParams(),
+ IntSize(kWidth, kHeight), kLow_SkFilterQuality, CanvasResourceParams(),
CanvasResourceProvider::ShouldInitialize::kCallClear,
dispatcher_->GetWeakPtr());
}
@@ -106,44 +113,44 @@ TEST_F(CanvasResourceDispatcherTest, PlaceholderRunsNormally) {
/* We allow OffscreenCanvas to post up to 3 frames without hearing a response
* from placeholder. */
// Post first frame
- unsigned post_resource_id = 1u;
+ viz::ResourceId post_resource_id(1u);
EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id));
DispatchOneFrame();
EXPECT_EQ(1u, GetNumUnreclaimedFramesPosted());
- EXPECT_EQ(1u, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
Mock::VerifyAndClearExpectations(Dispatcher());
// Post second frame
- post_resource_id++;
+ post_resource_id = NextId(post_resource_id);
EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id));
DispatchOneFrame();
EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted());
- EXPECT_EQ(2u, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
Mock::VerifyAndClearExpectations(Dispatcher());
// Post third frame
- post_resource_id++;
+ post_resource_id = NextId(post_resource_id);
EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id));
DispatchOneFrame();
EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted());
- EXPECT_EQ(3u, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
EXPECT_EQ(nullptr, GetLatestUnpostedImage());
Mock::VerifyAndClearExpectations(Dispatcher());
/* We mock the behavior of placeholder on main thread here, by reclaiming
* the resources in order. */
// Reclaim first frame
- unsigned reclaim_resource_id = 1u;
+ viz::ResourceId reclaim_resource_id(1u);
Dispatcher()->ReclaimResource(reclaim_resource_id);
EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted());
// Reclaim second frame
- reclaim_resource_id++;
+ reclaim_resource_id = NextId(reclaim_resource_id);
Dispatcher()->ReclaimResource(reclaim_resource_id);
EXPECT_EQ(1u, GetNumUnreclaimedFramesPosted());
// Reclaim third frame
- reclaim_resource_id++;
+ reclaim_resource_id = NextId(reclaim_resource_id);
Dispatcher()->ReclaimResource(reclaim_resource_id);
EXPECT_EQ(0u, GetNumUnreclaimedFramesPosted());
}
@@ -160,17 +167,17 @@ TEST_F(CanvasResourceDispatcherTest, PlaceholderBeingBlocked) {
DispatchOneFrame();
DispatchOneFrame();
DispatchOneFrame();
- unsigned post_resource_id = 4u;
+ viz::ResourceId post_resource_id(4u);
EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted());
- EXPECT_EQ(post_resource_id, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
EXPECT_TRUE(GetLatestUnpostedImage());
EXPECT_EQ(post_resource_id, GetLatestUnpostedResourceId());
// Attempt to post the 5th time. The latest unposted image will be replaced.
- post_resource_id++;
+ post_resource_id = NextId(post_resource_id);
DispatchOneFrame();
EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted());
- EXPECT_EQ(post_resource_id, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
EXPECT_TRUE(GetLatestUnpostedImage());
EXPECT_EQ(post_resource_id, GetLatestUnpostedResourceId());
@@ -179,18 +186,18 @@ TEST_F(CanvasResourceDispatcherTest, PlaceholderBeingBlocked) {
/* When main thread becomes unblocked, the first reclaim called by placeholder
* will trigger CanvasResourceDispatcher to post the last saved image.
* Resource reclaim happens in the same order as frame posting. */
- unsigned reclaim_resource_id = 1u;
+ viz::ResourceId reclaim_resource_id(1u);
EXPECT_CALL(*(Dispatcher()), PostImageToPlaceholder(_, post_resource_id));
Dispatcher()->ReclaimResource(reclaim_resource_id);
// Reclaim 1 frame and post 1 frame, so numPostImagesUnresponded remains as 3
EXPECT_EQ(3u, GetNumUnreclaimedFramesPosted());
// Not generating new resource Id
- EXPECT_EQ(post_resource_id, GetCurrentResourceId());
+ EXPECT_EQ(NextId(post_resource_id), PeekNextResourceId());
EXPECT_FALSE(GetLatestUnpostedImage());
- EXPECT_EQ(0u, GetLatestUnpostedResourceId());
+ EXPECT_EQ(viz::kInvalidResourceId, GetLatestUnpostedResourceId());
Mock::VerifyAndClearExpectations(Dispatcher());
- reclaim_resource_id++;
+ reclaim_resource_id = NextId(reclaim_resource_id);
Dispatcher()->ReclaimResource(reclaim_resource_id);
EXPECT_EQ(2u, GetNumUnreclaimedFramesPosted());
}
@@ -218,7 +225,7 @@ TEST_P(CanvasResourceDispatcherTest, DispatchFrame) {
platform->RunUntilIdle();
auto canvas_resource = CanvasResourceSharedBitmap::Create(
- GetSize(), CanvasColorParams(), nullptr /* provider */,
+ GetSize(), CanvasResourceParams(), nullptr /* provider */,
kLow_SkFilterQuality);
EXPECT_TRUE(!!canvas_resource);
EXPECT_EQ(canvas_resource->Size(), GetSize());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.cc
new file mode 100644
index 00000000000..3bec7f3aaf9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_params.h"
+
+#include "cc/paint/skia_paint_canvas.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/khronos/GLES3/gl3.h"
+#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "ui/gfx/color_space.h"
+
+namespace blink {
+
+namespace {
+
+// The CanvasColorSpace value definitions are specified in the CSS Color Level 4
+// specification.
+gfx::ColorSpace CanvasColorSpaceToGfxColorSpace(CanvasColorSpace color_space) {
+ switch (color_space) {
+ case CanvasColorSpace::kSRGB:
+ return gfx::ColorSpace::CreateSRGB();
+ break;
+ case CanvasColorSpace::kRec2020:
+ return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
+ gfx::ColorSpace::TransferID::GAMMA24);
+ break;
+ case CanvasColorSpace::kP3:
+ return gfx::ColorSpace::CreateDisplayP3D65();
+ break;
+ }
+ NOTREACHED();
+}
+
+} // namespace
+
+CanvasResourceParams::CanvasResourceParams() = default;
+
+CanvasResourceParams::CanvasResourceParams(CanvasColorSpace color_space,
+ SkColorType color_type,
+ SkAlphaType alpha_type)
+ : color_space_(color_space),
+ color_type_(color_type),
+ alpha_type_(alpha_type) {}
+
+CanvasResourceParams::CanvasResourceParams(const SkImageInfo& info)
+ : CanvasResourceParams(info.refColorSpace(), info.colorType()) {
+ // TODO(https://crbug.com/1157747): This ignores |info|'s SkAlphaType.
+}
+
+const SkSurfaceProps* CanvasResourceParams::GetSkSurfaceProps() const {
+ static const SkSurfaceProps disable_lcd_props(0, kUnknown_SkPixelGeometry);
+ if (alpha_type_ == kOpaque_SkAlphaType)
+ return nullptr;
+ return &disable_lcd_props;
+}
+
+uint8_t CanvasResourceParams::BytesPerPixel() const {
+ return SkColorTypeBytesPerPixel(color_type_);
+}
+
+gfx::ColorSpace CanvasResourceParams::GetSamplerGfxColorSpace() const {
+ // TODO(ccameron): If we add support for uint8srgb as a pixel format, this
+ // will need to take into account whether or not this texture will be sampled
+ // in linear or nonlinear space.
+ return CanvasColorSpaceToGfxColorSpace(color_space_);
+}
+
+gfx::ColorSpace CanvasResourceParams::GetStorageGfxColorSpace() const {
+ return CanvasColorSpaceToGfxColorSpace(color_space_);
+}
+
+sk_sp<SkColorSpace> CanvasResourceParams::GetSkColorSpace() const {
+ static_assert(kN32_SkColorType == kRGBA_8888_SkColorType ||
+ kN32_SkColorType == kBGRA_8888_SkColorType,
+ "Unexpected kN32_SkColorType value.");
+ return CanvasColorSpaceToSkColorSpace(color_space_);
+}
+
+gfx::BufferFormat CanvasResourceParams::GetBufferFormat() const {
+ switch (color_type_) {
+ case kRGBA_F16_SkColorType:
+ return gfx::BufferFormat::RGBA_F16;
+ case kRGBA_8888_SkColorType:
+ return gfx::BufferFormat::RGBA_8888;
+ case kBGRA_8888_SkColorType:
+ return gfx::BufferFormat::BGRA_8888;
+ case kRGB_888x_SkColorType:
+ return gfx::BufferFormat::RGBX_8888;
+ default:
+ NOTREACHED();
+ }
+
+ return gfx::BufferFormat::RGBA_8888;
+}
+
+GLenum CanvasResourceParams::GLSizedInternalFormat() const {
+ switch (color_type_) {
+ case kRGBA_F16_SkColorType:
+ return GL_RGBA16F;
+ case kRGBA_8888_SkColorType:
+ return GL_RGBA8;
+ case kBGRA_8888_SkColorType:
+ return GL_BGRA8_EXT;
+ case kRGB_888x_SkColorType:
+ return GL_RGB8;
+ default:
+ NOTREACHED();
+ }
+
+ return GL_RGBA8;
+}
+
+GLenum CanvasResourceParams::GLType() const {
+ switch (color_type_) {
+ case kRGBA_F16_SkColorType:
+ return GL_HALF_FLOAT_OES;
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType:
+ case kRGB_888x_SkColorType:
+ return GL_UNSIGNED_BYTE;
+ default:
+ NOTREACHED();
+ }
+
+ return GL_UNSIGNED_BYTE;
+}
+
+viz::ResourceFormat CanvasResourceParams::TransferableResourceFormat() const {
+ return viz::GetResourceFormat(GetBufferFormat());
+}
+
+CanvasResourceParams::CanvasResourceParams(
+ const sk_sp<SkColorSpace> sk_color_space,
+ SkColorType sk_color_type) {
+ color_space_ = CanvasColorSpaceFromSkColorSpace(sk_color_space.get());
+ color_type_ = kN32_SkColorType;
+ if (sk_color_type == kRGBA_F16_SkColorType ||
+ sk_color_type == kRGBA_8888_SkColorType ||
+ sk_color_type == kRGB_888x_SkColorType) {
+ color_type_ = sk_color_type;
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.h
new file mode 100644
index 00000000000..8132dc6b323
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_params.h
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_PARAMS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_PARAMS_H_
+
+#include "components/viz/common/resources/resource_format.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/gfx/buffer_types.h"
+
+class SkSurfaceProps;
+
+namespace gfx {
+class ColorSpace;
+}
+
+namespace blink {
+
+// TODO(https://crbug.com/1157747): This class is a copy-paste of
+// CanvasColorParams. This should be changed to specify a SkColorType,
+// SkAlphaType, SkColorSpace, and SkFilterMode.
+class PLATFORM_EXPORT CanvasResourceParams {
+ DISALLOW_NEW();
+
+ public:
+ // The default constructor will create an output-blended 8-bit surface.
+ CanvasResourceParams();
+ CanvasResourceParams(CanvasColorSpace, SkColorType, SkAlphaType);
+ explicit CanvasResourceParams(const SkImageInfo&);
+
+ CanvasColorSpace ColorSpace() const { return color_space_; }
+
+ void SetCanvasColorSpace(CanvasColorSpace c) { color_space_ = c; }
+ void SetSkColorType(SkColorType color_type) { color_type_ = color_type; }
+
+ // The pixel format to use for allocating SkSurfaces.
+ SkColorType GetSkColorType() const { return color_type_; }
+ uint8_t BytesPerPixel() const;
+
+ // The color space in which pixels read from the canvas via a shader will be
+ // returned. Note that for canvases with linear pixel math, these will be
+ // converted from their storage space into a linear space.
+ gfx::ColorSpace GetSamplerGfxColorSpace() const;
+
+ // Return the color space of the underlying data for the canvas.
+ gfx::ColorSpace GetStorageGfxColorSpace() const;
+ sk_sp<SkColorSpace> GetSkColorSpace() const;
+ SkAlphaType GetSkAlphaType() const { return alpha_type_; }
+ const SkSurfaceProps* GetSkSurfaceProps() const;
+
+ // Gpu memory buffer parameters
+ gfx::BufferFormat GetBufferFormat() const;
+ uint32_t GLSizedInternalFormat() const; // For GLES2, use Unsized
+ uint32_t GLUnsizedInternalFormat() const;
+ uint32_t GLType() const;
+
+ viz::ResourceFormat TransferableResourceFormat() const;
+
+ private:
+ CanvasResourceParams(const sk_sp<SkColorSpace> color_space,
+ SkColorType color_type);
+
+ CanvasColorSpace color_space_ = CanvasColorSpace::kSRGB;
+ SkColorType color_type_ = kN32_SkColorType;
+ SkAlphaType alpha_type_ = kPremul_SkAlphaType;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_PARAMS_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 3cd38bd9cc3..59d81e4f0d2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -71,12 +71,12 @@ static FlushForImageListener* GetFlushForImageListener() {
namespace {
bool IsGMBAllowed(IntSize size,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
const gpu::Capabilities& caps) {
return gpu::IsImageSizeValidForGpuMemoryBufferFormat(
- gfx::Size(size), color_params.GetBufferFormat()) &&
+ gfx::Size(size), params.GetBufferFormat()) &&
gpu::IsImageFromGpuMemoryBufferFormatSupported(
- color_params.GetBufferFormat(), caps);
+ params.GetBufferFormat(), caps);
}
} // namespace
@@ -94,8 +94,16 @@ class CanvasResourceProvider::CanvasImageProvider : public cc::ImageProvider {
cc::ImageProvider::ScopedResult GetRasterContent(
const cc::DrawImage&) override;
+ void ReleaseLockedImages() { locked_images_.clear(); }
+
private:
+ void CanUnlockImage(ScopedResult);
+ void CleanupLockedImages();
+ bool IsHardwareDecodeCache() const;
+
cc::PlaybackImageProvider::RasterMode raster_mode_;
+ bool cleanup_task_pending_ = false;
+ Vector<ScopedResult> locked_images_;
base::Optional<cc::PlaybackImageProvider> playback_image_provider_n32_;
base::Optional<cc::PlaybackImageProvider> playback_image_provider_f16_;
@@ -111,12 +119,12 @@ class CanvasResourceProviderBitmap : public CanvasResourceProvider {
CanvasResourceProviderBitmap(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
: CanvasResourceProvider(kBitmap,
size,
filter_quality,
- color_params,
+ params,
true /*is_origin_top_left*/,
nullptr /*context_provider_wrapper*/,
std::move(resource_dispatcher)) {}
@@ -155,11 +163,11 @@ class CanvasResourceProviderSharedBitmap : public CanvasResourceProviderBitmap {
CanvasResourceProviderSharedBitmap(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
: CanvasResourceProviderBitmap(size,
filter_quality,
- color_params,
+ params,
std::move(resource_dispatcher)) {
DCHECK(ResourceDispatcher());
type_ = kSharedBitmap;
@@ -169,16 +177,15 @@ class CanvasResourceProviderSharedBitmap : public CanvasResourceProviderBitmap {
private:
scoped_refptr<CanvasResource> CreateResource() final {
- CanvasColorParams color_params = ColorParams();
- if (!IsBitmapFormatSupported(color_params.TransferableResourceFormat())) {
+ CanvasResourceParams params = ColorParams();
+ if (!IsBitmapFormatSupported(params.TransferableResourceFormat())) {
// If the rendering format is not supported, downgrate to 8-bits.
// TODO(junov): Should we try 12-12-12-12 and 10-10-10-2?
- color_params.SetCanvasPixelFormat(
- CanvasColorParams::GetNativeCanvasPixelFormat());
+ params.SetSkColorType(kN32_SkColorType);
}
- return CanvasResourceSharedBitmap::Create(Size(), color_params,
- CreateWeakPtr(), FilterQuality());
+ return CanvasResourceSharedBitmap::Create(Size(), params, CreateWeakPtr(),
+ FilterQuality());
}
scoped_refptr<CanvasResource> ProduceCanvasResource() final {
@@ -205,7 +212,7 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
CanvasResourceProviderSharedImage(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper,
bool is_origin_top_left,
@@ -218,12 +225,14 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
filter_quality,
// TODO(khushalsagar): The software path seems to be assuming N32
// somewhere in the later pipeline but for offscreen canvas only.
- CanvasColorParams(color_params.ColorSpace(),
- is_accelerated && color_params.PixelFormat() !=
- CanvasPixelFormat::kF16
- ? CanvasPixelFormat::kRGBA8
- : color_params.PixelFormat(),
- color_params.GetOpacityMode()),
+ // TODO(https://crbug.com/1157747): This is RGBA, but the above
+ // comment suggests N32. See if this can be N32.
+ CanvasResourceParams(params.ColorSpace(),
+ is_accelerated && params.GetSkColorType() !=
+ kRGBA_F16_SkColorType
+ ? kRGBA_8888_SkColorType
+ : params.GetSkColorType(),
+ params.GetSkAlphaType()),
is_origin_top_left,
std::move(context_provider_wrapper),
nullptr /* resource_dispatcher */),
@@ -399,6 +408,12 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
return cached_snapshot_;
}
+ void WillDrawIfNeeded() final {
+ if (cached_snapshot_) {
+ WillDraw();
+ }
+ }
+
void WillDrawInternal(bool write_to_local_texture) {
DCHECK(resource_);
@@ -493,9 +508,10 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
}
WillDrawInternal(true);
gpu::raster::RasterInterface* ri = RasterInterface();
- SkColor background_color = ColorParams().GetOpacityMode() == kOpaque
- ? SK_ColorBLACK
- : SK_ColorTRANSPARENT;
+ SkColor background_color =
+ ColorParams().GetSkAlphaType() == kOpaque_SkAlphaType
+ ? SK_ColorBLACK
+ : SK_ColorTRANSPARENT;
auto list = base::MakeRefCounted<cc::DisplayItemList>(
cc::DisplayItemList::kTopLevelDisplayItemList);
@@ -609,11 +625,10 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
DCHECK(!resource()->is_cross_thread())
<< "Write access is only allowed on the owning thread";
- if (current_resource_has_write_access_ || IsGpuContextLost() ||
- use_oop_rasterization_)
+ if (current_resource_has_write_access_ || IsGpuContextLost())
return;
- if (is_accelerated_) {
+ if (is_accelerated_ && !use_oop_rasterization_) {
resource()->BeginWriteAccess();
}
@@ -629,17 +644,22 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider {
if (!current_resource_has_write_access_ || IsGpuContextLost())
return;
- DCHECK(!use_oop_rasterization_);
-
if (is_accelerated_) {
// We reset |mode_| here since the draw commands which overwrite the
// complete canvas must have been flushed at this point without triggering
// copy-on-write.
mode_ = SkSurface::kRetain_ContentChangeMode;
- // Issue any skia work using this resource before releasing write access.
- FlushGrContext();
- resource()->EndWriteAccess();
+
+ if (!use_oop_rasterization_) {
+ // Issue any skia work using this resource before releasing write
+ // access.
+ FlushGrContext();
+ resource()->EndWriteAccess();
+ }
} else {
+ // Currently we never use OOP raster when the resource is not accelerated
+ // so we check that assumption here.
+ DCHECK(!use_oop_rasterization_);
if (ShouldReplaceTargetBuffer())
resource_ = NewOrRecycledResource();
resource()->CopyRenderingResultsToGpuMemoryBuffer(
@@ -673,7 +693,7 @@ class CanvasResourceProviderPassThrough final : public CanvasResourceProvider {
CanvasResourceProviderPassThrough(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
@@ -681,7 +701,7 @@ class CanvasResourceProviderPassThrough final : public CanvasResourceProvider {
: CanvasResourceProvider(kPassThrough,
size,
filter_quality,
- color_params,
+ params,
is_origin_top_left,
std::move(context_provider_wrapper),
std::move(resource_dispatcher)) {}
@@ -726,14 +746,14 @@ class CanvasResourceProviderSwapChain final : public CanvasResourceProvider {
CanvasResourceProviderSwapChain(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
: CanvasResourceProvider(kSwapChain,
size,
filter_quality,
- color_params,
+ params,
true /*is_origin_top_left*/,
std::move(context_provider_wrapper),
std::move(resource_dispatcher)) {
@@ -842,10 +862,10 @@ std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreateBitmapProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize should_initialize) {
auto provider = std::make_unique<CanvasResourceProviderBitmap>(
- size, filter_quality, color_params, nullptr /*resource_dispatcher*/);
+ size, filter_quality, params, nullptr /*resource_dispatcher*/);
if (provider->IsValid()) {
if (should_initialize ==
CanvasResourceProvider::ShouldInitialize::kCallClear)
@@ -860,7 +880,7 @@ std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreateSharedBitmapProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize should_initialize,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher) {
// SharedBitmapProvider has to have a valid resource_dispatecher to be able to
@@ -869,7 +889,7 @@ CanvasResourceProvider::CreateSharedBitmapProvider(
return nullptr;
auto provider = std::make_unique<CanvasResourceProviderSharedBitmap>(
- size, filter_quality, color_params, std::move(resource_dispatcher));
+ size, filter_quality, params, std::move(resource_dispatcher));
if (provider->IsValid()) {
if (should_initialize ==
CanvasResourceProvider::ShouldInitialize::kCallClear)
@@ -884,7 +904,7 @@ std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreateSharedImageProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize should_initialize,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
RasterMode raster_mode,
@@ -909,14 +929,14 @@ CanvasResourceProvider::CreateSharedImageProvider(
base::FeatureList::IsEnabled(blink::features::kDawn2dCanvas);
// TODO(senorblanco): once Dawn reports maximum texture size, Dawn Canvas
// should respect it. http://crbug.com/1082760
- if (!skia_use_dawn && (size.Width() > capabilities.max_texture_size ||
+ if (!skia_use_dawn && (size.Width() < 1 || size.Height() < 1 ||
+ size.Width() > capabilities.max_texture_size ||
size.Height() > capabilities.max_texture_size)) {
return nullptr;
}
const bool is_gpu_memory_buffer_image_allowed =
- is_gpu_compositing_enabled &&
- IsGMBAllowed(size, color_params, capabilities) &&
+ is_gpu_compositing_enabled && IsGMBAllowed(size, params, capabilities) &&
Platform::Current()->GetGpuMemoryBufferManager();
if (raster_mode == RasterMode::kCPU && !is_gpu_memory_buffer_image_allowed)
@@ -931,7 +951,7 @@ CanvasResourceProvider::CreateSharedImageProvider(
}
auto provider = std::make_unique<CanvasResourceProviderSharedImage>(
- size, filter_quality, color_params, context_provider_wrapper,
+ size, filter_quality, params, context_provider_wrapper,
is_origin_top_left, raster_mode == RasterMode::kGPU, skia_use_dawn,
shared_image_usage_flags);
if (provider->IsValid()) {
@@ -945,10 +965,24 @@ CanvasResourceProvider::CreateSharedImageProvider(
}
std::unique_ptr<CanvasResourceProvider>
+CanvasResourceProvider::CreateWebGPUImageProvider(
+ const IntSize& size,
+ SkFilterQuality filter_quality,
+ const CanvasResourceParams& params,
+ ShouldInitialize initialize_provider,
+ base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+ context_provider_wrapper) {
+ return CreateSharedImageProvider(
+ size, filter_quality, params, initialize_provider,
+ std::move(context_provider_wrapper), RasterMode::kGPU,
+ true /* is_origin_top_left */, gpu::SHARED_IMAGE_USAGE_WEBGPU);
+}
+
+std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreatePassThroughProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
bool is_origin_top_left) {
@@ -967,12 +1001,12 @@ CanvasResourceProvider::CreatePassThroughProvider(
// Either swap_chain or gpu memory buffer should be enabled for this be used
if (!capabilities.shared_image_swap_chain &&
- (!IsGMBAllowed(size, color_params, capabilities) ||
+ (!IsGMBAllowed(size, params, capabilities) ||
!Platform::Current()->GetGpuMemoryBufferManager()))
return nullptr;
auto provider = std::make_unique<CanvasResourceProviderPassThrough>(
- size, filter_quality, color_params, context_provider_wrapper,
+ size, filter_quality, params, context_provider_wrapper,
resource_dispatcher, is_origin_top_left);
if (provider->IsValid()) {
// All the other type of resources are doing a clear here. As a
@@ -989,7 +1023,7 @@ std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreateSwapChainProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize should_initialize,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
@@ -1010,7 +1044,7 @@ CanvasResourceProvider::CreateSwapChainProvider(
}
auto provider = std::make_unique<CanvasResourceProviderSwapChain>(
- size, filter_quality, color_params, context_provider_wrapper,
+ size, filter_quality, params, context_provider_wrapper,
resource_dispatcher);
if (provider->IsValid()) {
if (should_initialize ==
@@ -1057,16 +1091,73 @@ CanvasResourceProvider::CanvasImageProvider::GetRasterContent(
if (playback_image_provider_f16_ &&
draw_image.paint_image().is_high_bit_depth()) {
DCHECK(playback_image_provider_f16_);
- return playback_image_provider_f16_->GetRasterContent(draw_image);
+ scoped_decoded_image =
+ playback_image_provider_f16_->GetRasterContent(draw_image);
+ } else {
+ scoped_decoded_image =
+ playback_image_provider_n32_->GetRasterContent(draw_image);
+ }
+
+ // Holding onto locked images here is a performance optimization for the
+ // gpu image decode cache. For that cache, it is expensive to lock and
+ // unlock gpu discardable, and so it is worth it to hold the lock on
+ // these images across multiple potential decodes. In the software case,
+ // locking in this manner makes it easy to run out of discardable memory
+ // (backed by shared memory sometimes) because each per-colorspace image
+ // decode cache has its own limit. In the software case, just unlock
+ // immediately and let the discardable system manage the cache logic
+ // behind the scenes.
+ if (!scoped_decoded_image.needs_unlock() || !IsHardwareDecodeCache()) {
+ return scoped_decoded_image;
+ }
+
+ constexpr int kMaxLockedImagesCount = 500;
+ if (!scoped_decoded_image.decoded_image().is_budgeted() ||
+ locked_images_.size() > kMaxLockedImagesCount) {
+ // If we have exceeded the budget, ReleaseLockedImages any locked decodes.
+ ReleaseLockedImages();
+ }
+
+ auto decoded_draw_image = scoped_decoded_image.decoded_image();
+ return ScopedResult(decoded_draw_image,
+ base::BindOnce(&CanvasImageProvider::CanUnlockImage,
+ weak_factory_.GetWeakPtr(),
+ std::move(scoped_decoded_image)));
+}
+
+void CanvasResourceProvider::CanvasImageProvider::CanUnlockImage(
+ ScopedResult image) {
+ // We should early out and avoid calling this function for software decodes.
+ DCHECK(IsHardwareDecodeCache());
+
+ // Because these image decodes are being done in javascript calling into
+ // canvas code, there's no obvious time to do the cleanup. To handle this,
+ // post a cleanup task to run after javascript is done running.
+ if (!cleanup_task_pending_) {
+ cleanup_task_pending_ = true;
+ Thread::Current()->GetTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&CanvasImageProvider::CleanupLockedImages,
+ weak_factory_.GetWeakPtr()));
}
- return playback_image_provider_n32_->GetRasterContent(draw_image);
+
+ locked_images_.push_back(std::move(image));
+}
+
+void CanvasResourceProvider::CanvasImageProvider::CleanupLockedImages() {
+ cleanup_task_pending_ = false;
+ ReleaseLockedImages();
+}
+
+bool CanvasResourceProvider::CanvasImageProvider::IsHardwareDecodeCache()
+ const {
+ return raster_mode_ != cc::PlaybackImageProvider::RasterMode::kSoftware;
}
CanvasResourceProvider::CanvasResourceProvider(
const ResourceProviderType& type,
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
bool is_origin_top_left,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
@@ -1075,7 +1166,7 @@ CanvasResourceProvider::CanvasResourceProvider(
resource_dispatcher_(resource_dispatcher),
size_(size),
filter_quality_(filter_quality),
- color_params_(color_params),
+ params_(params),
is_origin_top_left_(is_origin_top_left),
snapshot_paint_image_id_(cc::PaintImage::GetNextId()),
identifiability_paint_op_digest_(size_) {
@@ -1134,13 +1225,16 @@ CanvasResourceProvider::GetOrCreateCanvasImageProvider() {
: cc::PlaybackImageProvider::RasterMode::kGpu;
}
canvas_image_provider_ = std::make_unique<CanvasImageProvider>(
- ImageDecodeCacheRGBA8(), cache_f16, gfx::ColorSpace::CreateSRGB(),
- color_params_.GetSkColorType(), raster_mode);
+ ImageDecodeCacheRGBA8(), cache_f16,
+ ColorParams().GetStorageGfxColorSpace(), params_.GetSkColorType(),
+ raster_mode);
}
return canvas_image_provider_.get();
}
cc::PaintCanvas* CanvasResourceProvider::Canvas() {
+ WillDrawIfNeeded();
+
if (!recorder_) {
// A raw pointer is safe here because the callback is only used by the
// |recorder_|.
@@ -1167,6 +1261,11 @@ void CanvasResourceProvider::OnFlushForImage(PaintImage::ContentId content_id) {
}
}
+void CanvasResourceProvider::ReleaseLockedImages() {
+ if (canvas_image_provider_)
+ canvas_image_provider_->ReleaseLockedImages();
+}
+
scoped_refptr<StaticBitmapImage> CanvasResourceProvider::SnapshotInternal(
const ImageOrientation& orientation) {
if (!IsValid())
@@ -1281,7 +1380,7 @@ void CanvasResourceProvider::Clear() {
// send them directly through to Skia so that they're not replayed for
// printing operations. See crbug.com/1003114
DCHECK(IsValid());
- if (color_params_.GetOpacityMode() == kOpaque)
+ if (params_.GetSkAlphaType() == kOpaque_SkAlphaType)
Canvas()->clear(SK_ColorBLACK);
else
Canvas()->clear(SK_ColorTRANSPARENT);
@@ -1421,7 +1520,7 @@ void CanvasResourceProvider::RestoreBackBuffer(const cc::PaintImage& image) {
EnsureSkiaCanvas();
cc::PaintFlags copy_paint;
copy_paint.setBlendMode(SkBlendMode::kSrc);
- skia_canvas_->drawImage(image, 0, 0, &copy_paint);
+ skia_canvas_->drawImage(image, 0, 0, SkSamplingOptions(), &copy_paint);
}
bool CanvasResourceProvider::HasRecordedDrawOps() const {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 25935dabb48..7d5a91d9537 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -92,30 +92,37 @@ class PLATFORM_EXPORT CanvasResourceProvider
static std::unique_ptr<CanvasResourceProvider> CreateBitmapProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize initialize_provider);
static std::unique_ptr<CanvasResourceProvider> CreateSharedBitmapProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize initialize_provider,
base::WeakPtr<CanvasResourceDispatcher>);
static std::unique_ptr<CanvasResourceProvider> CreateSharedImageProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize initialize_provider,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
RasterMode raster_mode,
bool is_origin_top_left,
uint32_t shared_image_usage_flags);
+ static std::unique_ptr<CanvasResourceProvider> CreateWebGPUImageProvider(
+ const IntSize& size,
+ SkFilterQuality filter_quality,
+ const CanvasResourceParams& params,
+ ShouldInitialize initialize_provider,
+ base::WeakPtr<WebGraphicsContext3DProviderWrapper>);
+
static std::unique_ptr<CanvasResourceProvider> CreatePassThroughProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceDispatcher>,
bool is_origin_top_left);
@@ -123,7 +130,7 @@ class PLATFORM_EXPORT CanvasResourceProvider
static std::unique_ptr<CanvasResourceProvider> CreateSwapChainProvider(
const IntSize& size,
SkFilterQuality filter_quality,
- const CanvasColorParams& color_params,
+ const CanvasResourceParams& params,
ShouldInitialize initialize_provider,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceDispatcher>,
@@ -142,8 +149,9 @@ class PLATFORM_EXPORT CanvasResourceProvider
void OnContextDestroyed() override;
cc::PaintCanvas* Canvas();
+ void ReleaseLockedImages();
sk_sp<cc::PaintRecord> FlushCanvas();
- const CanvasColorParams& ColorParams() const { return color_params_; }
+ const CanvasResourceParams& ColorParams() const { return params_; }
void SetFilterQuality(SkFilterQuality quality) { filter_quality_ = quality; }
const IntSize& Size() const { return size_; }
bool IsOriginTopLeft() const { return is_origin_top_left_; }
@@ -251,7 +259,7 @@ class PLATFORM_EXPORT CanvasResourceProvider
CanvasResourceProvider(const ResourceProviderType&,
const IntSize&,
SkFilterQuality,
- const CanvasColorParams&,
+ const CanvasResourceParams&,
bool is_origin_top_left,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
base::WeakPtr<CanvasResourceDispatcher>);
@@ -266,6 +274,10 @@ class PLATFORM_EXPORT CanvasResourceProvider
CanvasImageProvider* GetOrCreateCanvasImageProvider();
void TearDownSkSurface();
+ // Will only notify a will draw if its needed. This is initially done for the
+ // CanvasResourceProviderSharedImage use case.
+ virtual void WillDrawIfNeeded() {}
+
ResourceProviderType type_;
mutable sk_sp<SkSurface> surface_; // mutable for lazy init
SkSurface::ContentChangeMode mode_ = SkSurface::kRetain_ContentChangeMode;
@@ -298,7 +310,7 @@ class PLATFORM_EXPORT CanvasResourceProvider
base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher_;
const IntSize size_;
SkFilterQuality filter_quality_;
- const CanvasColorParams color_params_;
+ const CanvasResourceParams params_;
const bool is_origin_top_left_;
std::unique_ptr<CanvasImageProvider> canvas_image_provider_;
std::unique_ptr<cc::SkiaPaintCanvas> skia_canvas_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index 967154828e4..8d0b2b9a2c7 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -10,8 +10,8 @@
#include "components/viz/test/test_gpu_memory_buffer_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_params.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
@@ -74,9 +74,8 @@ class CanvasResourceProviderTest : public Test {
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderAcceleratedOverlay) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
@@ -96,9 +95,9 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderAcceleratedOverlay) {
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
- EXPECT_EQ(provider->ColorParams().PixelFormat(), CanvasPixelFormat::kRGBA8);
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
@@ -107,9 +106,8 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderAcceleratedOverlay) {
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderTexture) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kLow_SkFilterQuality, kColorParams,
@@ -125,18 +123,17 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderTexture) {
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
- EXPECT_EQ(provider->ColorParams().PixelFormat(), CanvasPixelFormat::kRGBA8);
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderUnacceleratedOverlay) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
@@ -156,9 +153,10 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderUnacceleratedOverlay) {
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
- EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(),
+ kColorParams.GetSkColorType());
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
@@ -166,9 +164,8 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderUnacceleratedOverlay) {
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageResourceRecycling) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
@@ -187,9 +184,9 @@ TEST_F(CanvasResourceProviderTest,
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
- EXPECT_EQ(provider->ColorParams().PixelFormat(), CanvasPixelFormat::kRGBA8);
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
// Same resource and sync token if we query again without updating.
auto resource = provider->ProduceCanvasResource();
@@ -222,9 +219,8 @@ TEST_F(CanvasResourceProviderTest,
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageStaticBitmapImage) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
@@ -271,9 +267,8 @@ TEST_F(CanvasResourceProviderTest,
fake_context->SetCapabilities(caps);
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
@@ -295,9 +290,8 @@ TEST_F(CanvasResourceProviderTest,
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderBitmap) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateBitmapProvider(
kSize, kLow_SkFilterQuality, kColorParams,
@@ -309,23 +303,23 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderBitmap) {
EXPECT_FALSE(provider->SupportsDirectCompositing());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
- EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(),
+ kColorParams.GetSkColorType());
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderSharedBitmap) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
MockCanvasResourceDispatcherClient client;
CanvasResourceDispatcher resource_dispatcher(
- &client, 1 /* client_id */, 1 /* sink_id */,
- 1 /* placeholder_canvas_id */, kSize);
+ &client, base::ThreadTaskRunnerHandle::Get(), 1 /* client_id */,
+ 1 /* sink_id */, 1 /* placeholder_canvas_id */, kSize);
auto provider = CanvasResourceProvider::CreateSharedBitmapProvider(
kSize, kLow_SkFilterQuality, kColorParams,
@@ -338,9 +332,10 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderSharedBitmap) {
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
- EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(),
+ kColorParams.GetSkColorType());
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
@@ -350,9 +345,8 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderSharedBitmap) {
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderDirect2DGpuMemoryBuffer) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
@@ -372,9 +366,9 @@ TEST_F(CanvasResourceProviderTest,
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
- EXPECT_EQ(provider->ColorParams().PixelFormat(), CanvasPixelFormat::kRGBA8);
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
@@ -384,13 +378,12 @@ TEST_F(CanvasResourceProviderTest,
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderDirect3DGpuMemoryBuffer) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreatePassThroughProvider(
kSize, kLow_SkFilterQuality, kColorParams, context_provider_wrapper_,
- nullptr /* resource_dispatcher */, true /* is_origin_top_left */);
+ nullptr /*resource_dispatcher */, true /*is_origin_top_left*/);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
@@ -398,9 +391,10 @@ TEST_F(CanvasResourceProviderTest,
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
- EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(),
+ kColorParams.GetSkColorType());
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
@@ -409,9 +403,10 @@ TEST_F(CanvasResourceProviderTest,
gpu::Mailbox mailbox = gpu::Mailbox::Generate();
scoped_refptr<ExternalCanvasResource> resource =
ExternalCanvasResource::Create(
- mailbox, kSize, GL_TEXTURE_2D, kColorParams,
- SharedGpuContext::ContextProviderWrapper(), provider->CreateWeakPtr(),
- kMedium_SkFilterQuality, true /*is_origin_top_left*/);
+ mailbox, nullptr, gpu::SyncToken(), kSize, GL_TEXTURE_2D,
+ kColorParams, SharedGpuContext::ContextProviderWrapper(),
+ provider->CreateWeakPtr(), kMedium_SkFilterQuality,
+ true /*is_origin_top_left*/, true /*is_overlay_candidate*/);
// NewOrRecycledResource() would return nullptr before an ImportResource().
EXPECT_TRUE(provider->ImportResource(resource));
@@ -421,9 +416,8 @@ TEST_F(CanvasResourceProviderTest,
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_Bitmap) {
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateBitmapProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
@@ -440,9 +434,8 @@ TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_Bitmap) {
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SharedImage) {
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
@@ -467,9 +460,8 @@ TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SharedImage) {
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SwapChain) {
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSwapChainProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
@@ -494,9 +486,8 @@ TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SwapChain) {
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_PassThrough) {
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreatePassThroughProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, context_provider_wrapper_,
@@ -518,9 +509,8 @@ TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_PassThrough) {
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderDirect2DSwapChain) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSwapChainProvider(
kSize, kLow_SkFilterQuality, kColorParams,
@@ -536,16 +526,16 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderDirect2DSwapChain) {
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_TRUE(provider->IsSingleBuffered());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
- EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
- EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
- kColorParams.GetOpacityMode());
+ EXPECT_EQ(provider->ColorParams().GetSkColorType(),
+ kColorParams.GetSkColorType());
+ EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
+ kColorParams.GetSkAlphaType());
}
TEST_F(CanvasResourceProviderTest, FlushForImage) {
const IntSize kSize(10, 10);
- const CanvasColorParams kColorParams(
- CanvasColorSpace::kSRGB, CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ const CanvasResourceParams kColorParams(
+ CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto src_provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
@@ -568,8 +558,7 @@ TEST_F(CanvasResourceProviderTest, FlushForImage) {
EXPECT_FALSE(dst_canvas->IsCachingImage(src_content_id));
- cc::PaintFlags flags;
- dst_canvas->drawImage(paint_image, 0, 0, &flags);
+ dst_canvas->drawImage(paint_image, 0, 0, SkSamplingOptions(), nullptr);
EXPECT_TRUE(dst_canvas->IsCachingImage(src_content_id));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
index 03156bbb3cb..c0e34a8d121 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
@@ -24,7 +24,8 @@ namespace blink {
TEST(CanvasResourceTest, PrepareTransferableResource_SharedBitmap) {
scoped_refptr<CanvasResource> canvas_resource =
- CanvasResourceSharedBitmap::Create(IntSize(10, 10), CanvasColorParams(),
+ CanvasResourceSharedBitmap::Create(IntSize(10, 10),
+ CanvasResourceParams(),
nullptr, // CanvasResourceProvider
kLow_SkFilterQuality);
EXPECT_TRUE(!!canvas_resource);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
index 652a1b715fb..ca97bde9466 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
@@ -193,7 +193,7 @@ bool ColorCorrectionTestUtils::ConvertPixelsToColorSpaceAndPixelFormatForTest(
src_sk_color_space =
CanvasColorParams(src_color_space,
(src_storage_format == kUint8ClampedArrayStorageFormat)
- ? CanvasPixelFormat::kRGBA8
+ ? CanvasPixelFormat::kUint8
: CanvasPixelFormat::kF16,
kNonOpaque)
.GetSkColorSpace();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
index 9d38804f585..ee9fd786cb8 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h
@@ -30,13 +30,13 @@ class PLATFORM_EXPORT ContentLayerClientImpl : public cc::ContentLayerClient,
~ContentLayerClientImpl() override;
// cc::ContentLayerClient
- gfx::Rect PaintableRegion() override {
+ gfx::Rect PaintableRegion() const final {
return gfx::Rect(raster_invalidator_.LayerBounds().size());
}
- scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() override {
+ scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() final {
return cc_display_item_list_;
}
- bool FillsBoundsCompletely() const override { return false; }
+ bool FillsBoundsCompletely() const final { return false; }
// LayerAsJSONClient implementation
void AppendAdditionalInfoAsJSON(LayerTreeFlags,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index d05e03f7a58..185f538290d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "cc/document_transition/document_transition_request.h"
#include "cc/layers/scrollbar_layer_base.h"
#include "cc/paint/display_item_list.h"
#include "cc/trees/effect_node.h"
@@ -153,8 +154,11 @@ scoped_refptr<cc::Layer> PaintArtifactCompositor::WrappedCcLayerForPendingLayer(
const TransformPaintPropertyNode&
PaintArtifactCompositor::NearestScrollTranslationForLayer(
const PendingLayer& pending_layer) {
- if (const auto* scroll_translation = ScrollTranslationForLayer(pending_layer))
- return *scroll_translation;
+ if (pending_layer.compositing_type != PendingLayer::kPreCompositedLayer) {
+ if (const auto* scroll_translation =
+ ScrollTranslationForLayer(pending_layer))
+ return *scroll_translation;
+ }
const auto& transform = pending_layer.property_tree_state.Transform();
// TODO(pdr): This could be a performance issue because it crawls up the
@@ -166,6 +170,7 @@ PaintArtifactCompositor::NearestScrollTranslationForLayer(
const TransformPaintPropertyNode*
PaintArtifactCompositor::ScrollTranslationForLayer(
const PendingLayer& pending_layer) {
+ DCHECK_NE(pending_layer.compositing_type, PendingLayer::kPreCompositedLayer);
// Not checking PendingLayer::kScrollHitTestLayer because a scroll hit test
// chunk without a direct compositing reasons can still be composited (e.g.
// when it can't be merged into any other layer).
@@ -299,8 +304,13 @@ PaintArtifactCompositor::CompositedLayerForPendingLayer(
// Set properties that foreign layers would normally control for themselves
// here to avoid changing foreign layers. This includes things set by
// GraphicsLayer on the ContentsLayer() or by video clients etc.
- cc_layer->SetContentsOpaque(pending_layer.rect_known_to_be_opaque.Contains(
- FloatRect(cc_combined_bounds)));
+ bool contents_opaque = pending_layer.rect_known_to_be_opaque.Contains(
+ FloatRect(cc_combined_bounds));
+ cc_layer->SetContentsOpaque(contents_opaque);
+ if (!contents_opaque) {
+ cc_layer->SetContentsOpaqueForText(
+ pending_layer.text_known_to_be_on_opaque_background);
+ }
return cc_layer;
}
@@ -315,13 +325,17 @@ bool PaintArtifactCompositor::HasComposited(
element_id);
}
-bool PaintArtifactCompositor::PropertyTreeStateChanged(
- const PropertyTreeState& state) const {
- const auto& root = PropertyTreeState::Root();
+bool PaintArtifactCompositor::PendingLayer::PropertyTreeStateChanged() const {
auto change = PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
- return state.Transform().Changed(change, root.Transform()) ||
- state.Clip().Changed(change, root, &state.Transform()) ||
- state.Effect().Changed(change, root, &state.Transform());
+ if (change_of_decomposited_transforms >= change)
+ return true;
+
+ const auto& root = PropertyTreeState::Root();
+ return property_tree_state.Transform().Changed(change, root.Transform()) ||
+ property_tree_state.Clip().Changed(change, root,
+ &property_tree_state.Transform()) ||
+ property_tree_state.Effect().Changed(change, root,
+ &property_tree_state.Transform());
}
PaintArtifactCompositor::PendingLayer::PendingLayer(
@@ -331,6 +345,8 @@ PaintArtifactCompositor::PendingLayer::PendingLayer(
: bounds(first_chunk->bounds),
rect_known_to_be_opaque(first_chunk->known_to_be_opaque ? bounds
: FloatRect()),
+ text_known_to_be_on_opaque_background(
+ first_chunk->text_known_to_be_on_opaque_background),
chunks(&chunks.GetPaintArtifact(), first_chunk.IndexInPaintArtifact()),
property_tree_state(
first_chunk->properties.GetPropertyTreeState().Unalias()),
@@ -429,14 +445,23 @@ FloatRect PaintArtifactCompositor::PendingLayer::VisualRectForOverlapTesting()
bool PaintArtifactCompositor::PendingLayer::Merge(const PendingLayer& guest) {
PropertyTreeState new_state = PropertyTreeState::Uninitialized();
- if (!CanMerge(guest, guest.property_tree_state, &new_state, &bounds))
+ FloatRect guest_bounds;
+ if (!CanMerge(guest, guest.property_tree_state, &new_state, &guest_bounds,
+ &bounds)) {
return false;
+ }
chunks.Merge(guest.chunks);
rect_known_to_be_opaque =
UniteRectsKnownToBeOpaque(MapRectKnownToBeOpaque(new_state),
guest.MapRectKnownToBeOpaque(new_state));
+ text_known_to_be_on_opaque_background &=
+ (guest.text_known_to_be_on_opaque_background ||
+ rect_known_to_be_opaque.Contains(guest_bounds));
property_tree_state = new_state;
+ change_of_decomposited_transforms =
+ std::max(change_of_decomposited_transforms,
+ guest.change_of_decomposited_transforms);
return true;
}
@@ -552,6 +577,7 @@ bool PaintArtifactCompositor::PendingLayer::CanMerge(
const PendingLayer& guest,
const PropertyTreeState& guest_state,
PropertyTreeState* out_merged_state,
+ FloatRect* out_guest_bounds,
FloatRect* out_merged_bounds) const {
if (&chunks.GetPaintArtifact() != &guest.chunks.GetPaintArtifact())
return false;
@@ -588,6 +614,8 @@ bool PaintArtifactCompositor::PendingLayer::CanMerge(
if (out_merged_state)
*out_merged_state = *merged_state;
+ if (out_guest_bounds)
+ *out_guest_bounds = new_guest_bounds.Rect();
if (out_merged_bounds)
*out_merged_bounds = merged_bounds;
return true;
@@ -916,8 +944,8 @@ SynthesizedClip::PaintContentsToDisplayList() {
const auto& translation = translation_2d_or_matrix_.Translation2D();
cc_list->push<cc::TranslateOp>(translation.Width(), translation.Height());
} else {
- cc_list->push<cc::ConcatOp>(SkMatrix(TransformationMatrix::ToSkMatrix44(
- translation_2d_or_matrix_.Matrix())));
+ cc_list->push<cc::ConcatOp>(
+ TransformationMatrix::ToSkM44(translation_2d_or_matrix_.Matrix()));
}
if (path_) {
cc_list->push<cc::ClipPathOp>(path_->GetSkPath(), SkClipOp::kIntersect,
@@ -1088,6 +1116,9 @@ void PaintArtifactCompositor::DecompositeTransforms() {
while (!transform->IsRoot() && can_be_decomposited.at(transform)) {
pending_layer.offset_of_decomposited_transforms +=
transform->Translation2D();
+ pending_layer.change_of_decomposited_transforms =
+ std::max(pending_layer.change_of_decomposited_transforms,
+ transform->NodeChanged());
transform = &transform->Parent()->Unalias();
}
pending_layer.property_tree_state.SetTransform(*transform);
@@ -1102,38 +1133,45 @@ void PaintArtifactCompositor::DecompositeTransforms() {
void PaintArtifactCompositor::Update(
const Vector<PreCompositedLayerInfo>& pre_composited_layers,
const ViewportProperties& viewport_properties,
- const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes) {
+ const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes,
+ Vector<std::unique_ptr<cc::DocumentTransitionRequest>>
+ transition_requests) {
DCHECK(scroll_translation_nodes.IsEmpty() ||
RuntimeEnabledFeatures::ScrollUnificationEnabled());
DCHECK(root_layer_);
DCHECK(NeedsUpdate());
+ TRACE_EVENT0("blink", "PaintArtifactCompositor::Update");
+
// The tree will be null after detaching and this update can be ignored.
// See: WebViewImpl::detachPaintArtifactCompositor().
cc::LayerTreeHost* host = root_layer_->layer_tree_host();
if (!host)
return;
- TRACE_EVENT0("blink", "PaintArtifactCompositor::Update");
+ for (auto& request : transition_requests)
+ host->AddDocumentTransitionRequest(std::move(request));
host->property_trees()->scroll_tree.SetScrollCallbacks(scroll_callbacks_);
root_layer_->set_property_tree_sequence_number(
g_s_property_tree_sequence_number);
+ // Make compositing decisions, storing the result in |pending_layers_|.
+ CollectPendingLayers(pre_composited_layers);
+ DecompositeTransforms();
+
LayerListBuilder layer_list_builder;
PropertyTreeManager property_tree_manager(*this, *host->property_trees(),
*root_layer_, layer_list_builder,
g_s_property_tree_sequence_number);
- CollectPendingLayers(pre_composited_layers);
UpdateCompositorViewportProperties(viewport_properties, property_tree_manager,
host);
// With ScrollUnification, we ensure a cc::ScrollNode for all
// |scroll_translation_nodes|.
- if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
+ if (RuntimeEnabledFeatures::ScrollUnificationEnabled())
property_tree_manager.EnsureCompositorScrollNodes(scroll_translation_nodes);
- }
Vector<std::unique_ptr<ContentLayerClientImpl>> new_content_layer_clients;
new_content_layer_clients.ReserveCapacity(pending_layers_.size());
@@ -1147,10 +1185,7 @@ void PaintArtifactCompositor::Update(
for (auto& entry : synthesized_clip_cache_)
entry.in_use = false;
- // See if we can de-composite any transforms.
- DecompositeTransforms();
-
- const PendingLayer* previous_pending_layer = nullptr;
+ cc::LayerSelection layer_selection;
for (auto& pending_layer : pending_layers_) {
const auto& property_state = pending_layer.property_tree_state;
const auto& transform = property_state.Transform();
@@ -1171,7 +1206,8 @@ void PaintArtifactCompositor::Update(
pending_layer, new_content_layer_clients, new_scroll_hit_test_layers,
new_scrollbar_layers);
- UpdateLayerProperties(*layer, pending_layer, &property_tree_manager);
+ UpdateLayerProperties(*layer, pending_layer, layer_selection,
+ &property_tree_manager);
layer->SetLayerTreeHost(root_layer_->layer_tree_host());
@@ -1225,14 +1261,15 @@ void PaintArtifactCompositor::Update(
// nodes|^2) and could be optimized by caching the lookup of nodes known
// to be changed/unchanged.
if (layer->subtree_property_changed() ||
- PropertyTreeStateChanged(property_state)) {
+ pending_layer.PropertyTreeStateChanged()) {
layer->SetSubtreePropertyChanged();
root_layer_->SetNeedsCommit();
}
-
- previous_pending_layer = &pending_layer;
}
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ root_layer_->layer_tree_host()->RegisterSelection(layer_selection);
+
property_tree_manager.Finalize();
content_layer_clients_.swap(new_content_layer_clients);
scroll_hit_test_layers_.swap(new_scroll_hit_test_layers);
@@ -1274,6 +1311,7 @@ void PaintArtifactCompositor::Update(
void PaintArtifactCompositor::UpdateLayerProperties(
cc::Layer& layer,
const PendingLayer& pending_layer,
+ cc::LayerSelection& layer_selection,
PropertyTreeManager* property_tree_manager) {
// Properties of foreign layers are managed by their owners.
if (pending_layer.compositing_type == PendingLayer::kForeignLayer)
@@ -1286,7 +1324,8 @@ void PaintArtifactCompositor::UpdateLayerProperties(
.GetPaintArtifactShared());
}
PaintChunksToCcLayer::UpdateLayerProperties(
- layer, pending_layer.property_tree_state, chunks, property_tree_manager);
+ layer, pending_layer.property_tree_state, chunks, layer_selection,
+ property_tree_manager);
}
void PaintArtifactCompositor::UpdateRepaintedLayerProperties() const {
@@ -1299,8 +1338,9 @@ void PaintArtifactCompositor::UpdateRepaintedLayerProperties() const {
continue;
DCHECK(pending_layer.graphics_layer);
if (pending_layer.graphics_layer->Repainted()) {
+ cc::LayerSelection layer_selection;
UpdateLayerProperties(pending_layer.graphics_layer->CcLayer(),
- pending_layer);
+ pending_layer, layer_selection);
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 15a434dbb51..02f9b3948f7 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/layer_collections.h"
#include "cc/layers/picture_layer.h"
@@ -29,6 +30,7 @@
namespace cc {
class ScrollbarLayerBase;
+class DocumentTransitionRequest;
}
namespace blink {
@@ -104,10 +106,11 @@ class SynthesizedClip : private cc::ContentLayerClient {
private:
// ContentLayerClient implementation.
- gfx::Rect PaintableRegion() final { return gfx::Rect(layer_->bounds()); }
- bool FillsBoundsCompletely() const final { return false; }
-
+ gfx::Rect PaintableRegion() const final {
+ return gfx::Rect(layer_->bounds());
+ }
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() final;
+ bool FillsBoundsCompletely() const final { return false; }
private:
scoped_refptr<cc::PictureLayer> layer_;
@@ -153,10 +156,11 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
// noncomposited nodes, and is used for Scroll Unification to generate scroll
// nodes for noncomposited scrollers to complete the compositor's scroll
// property tree.
- void Update(const Vector<PreCompositedLayerInfo>&,
- const ViewportProperties& viewport_properties,
- const Vector<const TransformPaintPropertyNode*>&
- scroll_translation_nodes);
+ void Update(
+ const Vector<PreCompositedLayerInfo>&,
+ const ViewportProperties& viewport_properties,
+ const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes,
+ Vector<std::unique_ptr<cc::DocumentTransitionRequest>> requests);
void UpdateRepaintedLayerProperties() const;
@@ -240,8 +244,9 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
// current state).
bool CanMerge(const PendingLayer& guest,
const PropertyTreeState& guest_state,
- PropertyTreeState* merged_state = nullptr,
- FloatRect* merged_bounds = nullptr) const;
+ PropertyTreeState* out_merged_state = nullptr,
+ FloatRect* out_guest_bounds = nullptr,
+ FloatRect* out_merged_bounds = nullptr) const;
// Mutate this layer's property tree state to a more general (shallower)
// state, thus the name "upcast". The concrete effect of this is to
@@ -268,18 +273,24 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
return compositing_type != kOverlap && compositing_type != kOther;
}
+ bool PropertyTreeStateChanged() const;
+
// The rects are in the space of property_tree_state.
FloatRect bounds;
FloatRect rect_known_to_be_opaque;
+ bool text_known_to_be_on_opaque_background;
PaintChunkSubset chunks;
PropertyTreeState property_tree_state;
FloatPoint offset_of_decomposited_transforms;
+ PaintPropertyChangeType change_of_decomposited_transforms =
+ PaintPropertyChangeType::kUnchanged;
const GraphicsLayer* graphics_layer = nullptr;
CompositingType compositing_type;
};
static void UpdateLayerProperties(cc::Layer&,
const PendingLayer&,
+ cc::LayerSelection& layer_selection,
PropertyTreeManager* = nullptr);
void DecompositeTransforms();
@@ -322,8 +333,6 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
Vector<scoped_refptr<cc::Layer>>& new_scroll_hit_test_layers,
Vector<scoped_refptr<cc::ScrollbarLayerBase>>& new_scrollbar_layers);
- bool PropertyTreeStateChanged(const PropertyTreeState&) const;
-
const TransformPaintPropertyNode& NearestScrollTranslationForLayer(
const PendingLayer&);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 0e4e2515825..68fc4bcb5da 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -10,6 +10,7 @@
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/layers/layer.h"
#include "cc/test/fake_impl_task_runner_provider.h"
@@ -31,6 +32,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "third_party/blink/renderer/platform/testing/fake_display_item_client.h"
+#include "third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h"
#include "third_party/blink/renderer/platform/testing/layer_tree_host_embedder.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
@@ -144,8 +146,9 @@ class PaintArtifactCompositorTest : public testing::Test,
paint_artifact_compositor_->SetNeedsUpdate();
Vector<PreCompositedLayerInfo> pre_composited_layers = {
{PaintChunkSubset(artifact)}};
- paint_artifact_compositor_->Update(
- pre_composited_layers, viewport_properties, scroll_translation_nodes);
+ paint_artifact_compositor_->Update(pre_composited_layers,
+ viewport_properties,
+ scroll_translation_nodes, {});
layer_tree_->layer_tree_host()->LayoutAndUpdateLayers();
}
@@ -155,31 +158,14 @@ class PaintArtifactCompositorTest : public testing::Test,
cc::Layer* RootLayer() { return paint_artifact_compositor_->RootLayer(); }
- // CompositeAfterPaint creates scroll hit test data (which create scroll hit
- // test layers in PaintArtifactCompositor) whereas before CompositeAfterPaint,
- // scrollable foreign layers are created in ScrollingCoordinator and passed
- // to PaintArtifactCompositor.
void CreateScrollableChunk(
TestPaintArtifact& artifact,
const TransformPaintPropertyNode& scroll_translation,
const ClipPaintPropertyNodeOrAlias& clip,
const EffectPaintPropertyNodeOrAlias& effect) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- artifact.Chunk(*scroll_translation.Parent(), clip, effect)
- .ScrollHitTest(&scroll_translation);
- return;
- }
-
- // Create a foreign layer for scrolling, roughly matching the layer
- // created by ScrollingCoordinator.
- const auto* scroll_node = scroll_translation.ScrollNode();
- auto rect = scroll_node->ContainerRect();
- scoped_refptr<cc::Layer> layer = cc::Layer::Create();
- layer->SetBounds(gfx::Size(rect.Size()));
- layer->SetElementId(scroll_node->GetCompositorElementId());
- layer->SetHitTestable(true);
- artifact.Chunk(scroll_translation, clip, effect)
- .ForeignLayer(layer, rect.Location());
+ artifact.Chunk(*scroll_translation.Parent(), clip, effect)
+ .ScrollHitTest(scroll_translation.ScrollNode()->ContainerRect(),
+ &scroll_translation);
}
// Returns the |num|th scrollable layer. In CompositeAfterPaint, this will be
@@ -1175,10 +1161,10 @@ TEST_P(PaintArtifactCompositorTest, OneScrollNodeNonComposited) {
.RectDrawing(IntRect(-110, 12, 170, 19), Color::kWhite);
Update(artifact.Build());
- // Node #0 reserved for null; #1 for root render surface. Blink nodes are all
- // decomposited.
- EXPECT_EQ(2u, GetPropertyTrees().scroll_tree.size());
- EXPECT_EQ(2u, GetPropertyTrees().transform_tree.size());
+ // Node #0 reserved for null; #1 for root render surface; #2 is the blink
+ // scroll translation.
+ EXPECT_EQ(3u, GetPropertyTrees().scroll_tree.size());
+ EXPECT_EQ(3u, GetPropertyTrees().transform_tree.size());
EXPECT_EQ(1u, LayerCount());
}
@@ -5037,4 +5023,37 @@ TEST_P(PaintArtifactCompositorTest, AddNonCompositedScrollNodes) {
EXPECT_FALSE(scroll_node->is_composited);
}
+TEST_P(PaintArtifactCompositorTest, PreCompositedLayerNonCompositedScrolling) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ FakeGraphicsLayerClient client;
+ GraphicsLayer graphics_layer(client);
+ auto parent_scroll_translation = CreateScrollTranslation(
+ t0(), 10, 20, IntRect(0, 0, 100, 100), IntSize(200, 200),
+ CompositingReason::kRootScroller);
+ PropertyTreeState layer_state(*parent_scroll_translation, c0(), e0());
+ graphics_layer.SetLayerState(layer_state, IntPoint());
+ auto scroll_translation = CreateScrollTranslation(
+ *parent_scroll_translation, 10, 20, IntRect(0, 0, 150, 150),
+ IntSize(200, 200), CompositingReason::kNone);
+
+ TestPaintArtifact artifact;
+ CreateScrollableChunk(artifact, *scroll_translation, c0(), e0());
+ Vector<PreCompositedLayerInfo> pre_composited_layers = {
+ {PaintChunkSubset(artifact.Build()), &graphics_layer}};
+ GetPaintArtifactCompositor().SetNeedsUpdate();
+ GetPaintArtifactCompositor().Update(
+ pre_composited_layers, PaintArtifactCompositor::ViewportProperties(), {},
+ {});
+
+ EXPECT_EQ(1u, LayerCount());
+ EXPECT_EQ(&graphics_layer.CcLayer(), LayerAt(0));
+ EXPECT_EQ(gfx::Rect(0, 0, 150, 150),
+ graphics_layer.CcLayer().non_fast_scrollable_region().bounds());
+ EXPECT_EQ(parent_scroll_translation->CcNodeId(
+ graphics_layer.CcLayer().property_tree_sequence_number()),
+ graphics_layer.CcLayer().scroll_tree_index());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
index 9fd095e165c..62c43d9f4b4 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -7,6 +7,7 @@
#include "base/containers/adapters.h"
#include "base/numerics/safe_conversions.h"
#include "cc/base/features.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/layers/layer.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_op_buffer.h"
@@ -150,7 +151,7 @@ class ConversionContext {
translation.Height());
}
} else {
- cc_list_.push<cc::ConcatOp>(translation_2d_or_matrix.ToSkMatrix());
+ cc_list_.push<cc::ConcatOp>(translation_2d_or_matrix.ToSkM44());
}
}
@@ -688,7 +689,7 @@ void ConversionContext::SwitchToTransform(
const auto& translation = translation_2d_or_matrix.Translation2D();
cc_list_.push<cc::TranslateOp>(translation.Width(), translation.Height());
} else {
- cc_list_.push<cc::ConcatOp>(translation_2d_or_matrix.ToSkMatrix());
+ cc_list_.push<cc::ConcatOp>(translation_2d_or_matrix.ToSkM44());
}
cc_list_.EndPaintOfPairedBegin();
previous_transform_ = current_transform_;
@@ -815,8 +816,6 @@ static void UpdateBackgroundColor(cc::Layer& layer,
const EffectPaintPropertyNode& layer_effect,
const PaintChunkSubset& paint_chunks) {
Vector<Color, 4> background_colors;
- Color safe_opaque_background_color;
- float safe_opaque_background_area = 0;
float min_background_area = kMinBackgroundColorCoverageRatio *
layer.bounds().width() * layer.bounds().height();
for (auto it = paint_chunks.end(); it != paint_chunks.begin();) {
@@ -841,20 +840,12 @@ static void UpdateBackgroundColor(cc::Layer& layer,
break;
}
}
- if (chunk.background_color_area > safe_opaque_background_area) {
- // This color will be used only if we don't find proper background_color.
- safe_opaque_background_color = chunk.background_color;
- safe_opaque_background_area = chunk.background_color_area;
- }
}
Color background_color;
for (Color color : base::Reversed(background_colors))
background_color = background_color.Blend(color);
layer.SetBackgroundColor(background_color.Rgb());
- layer.SetSafeOpaqueBackgroundColor(background_color == Color::kTransparent
- ? safe_opaque_background_color.Rgb()
- : background_color.Rgb());
}
static void UpdateTouchActionRegion(
@@ -995,14 +986,75 @@ static void UpdateTouchActionWheelEventHandlerAndNonFastScrollableRegions(
layer.SetNonFastScrollableRegion(std::move(non_fast_scrollable_region));
}
+static gfx::Point MapSelectionBoundPoint(const IntPoint& point,
+ const PropertyTreeState& layer_state,
+ const PropertyTreeState& chunk_state,
+ const FloatPoint& layer_offset) {
+ FloatPoint mapped_point =
+ GeometryMapper::SourceToDestinationProjection(chunk_state.Transform(),
+ layer_state.Transform())
+ .MapPoint(FloatPoint(point));
+
+ mapped_point.MoveBy(-layer_offset);
+ gfx::Point out_point(RoundedIntPoint(mapped_point));
+ return out_point;
+}
+
+static cc::LayerSelectionBound
+ConvertPaintedSelectionBoundToLayerSelectionBound(
+ const PaintedSelectionBound& bound,
+ const PropertyTreeState& layer_state,
+ const PropertyTreeState& chunk_state,
+ const FloatPoint& layer_offset) {
+ cc::LayerSelectionBound layer_bound;
+ layer_bound.type = bound.type;
+ layer_bound.hidden = bound.hidden;
+ layer_bound.edge_start = MapSelectionBoundPoint(bound.edge_start, layer_state,
+ chunk_state, layer_offset);
+ layer_bound.edge_end = MapSelectionBoundPoint(bound.edge_end, layer_state,
+ chunk_state, layer_offset);
+ return layer_bound;
+}
+
+static void UpdateLayerSelection(cc::Layer& layer,
+ const PropertyTreeState& layer_state,
+ const PaintChunkSubset& chunks,
+ cc::LayerSelection& layer_selection) {
+ gfx::Vector2dF cc_layer_offset = layer.offset_to_transform_parent();
+ FloatPoint layer_offset(cc_layer_offset.x(), cc_layer_offset.y());
+ for (const auto& chunk : chunks) {
+ if (!chunk.layer_selection_data)
+ continue;
+
+ auto chunk_state = chunk.properties.GetPropertyTreeState().Unalias();
+ if (chunk.layer_selection_data->start) {
+ const PaintedSelectionBound& bound =
+ chunk.layer_selection_data->start.value();
+ layer_selection.start = ConvertPaintedSelectionBoundToLayerSelectionBound(
+ bound, layer_state, chunk_state, layer_offset);
+ layer_selection.start.layer_id = layer.id();
+ }
+
+ if (chunk.layer_selection_data->end) {
+ const PaintedSelectionBound& bound =
+ chunk.layer_selection_data->end.value();
+ layer_selection.end = ConvertPaintedSelectionBoundToLayerSelectionBound(
+ bound, layer_state, chunk_state, layer_offset);
+ layer_selection.end.layer_id = layer.id();
+ }
+ }
+}
+
void PaintChunksToCcLayer::UpdateLayerProperties(
cc::Layer& layer,
const PropertyTreeState& layer_state,
const PaintChunkSubset& chunks,
+ cc::LayerSelection& layer_selection,
PropertyTreeManager* property_tree_manager) {
UpdateBackgroundColor(layer, layer_state.Effect(), chunks);
UpdateTouchActionWheelEventHandlerAndNonFastScrollableRegions(
layer, layer_state, chunks, property_tree_manager);
+ UpdateLayerSelection(layer, layer_state, chunks, layer_selection);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h
index 5b311bbe60b..4c959697425 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COMPOSITING_PAINT_CHUNKS_TO_CC_LAYER_H_
#include "base/memory/scoped_refptr.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/paint/display_item_list.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -75,6 +76,7 @@ class PLATFORM_EXPORT PaintChunksToCcLayer {
static void UpdateLayerProperties(cc::Layer& layer,
const PropertyTreeState& layer_state,
const PaintChunkSubset&,
+ cc::LayerSelection& layer_selection,
PropertyTreeManager* = nullptr);
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index 689051009ec..682e8b73935 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -121,8 +121,7 @@ class PaintRecordMatcher
do { \
const auto* concat = (op_buffer).GetOpAtForTesting<cc::ConcatOp>(index); \
ASSERT_NE(nullptr, concat); \
- EXPECT_EQ(SkMatrix(TransformationMatrix::ToSkMatrix44(transform)), \
- concat->matrix); \
+ EXPECT_EQ(TransformationMatrix::ToSkM44(transform), concat->matrix); \
} while (false)
#define EXPECT_TRANSLATE(x, y, op_buffer, index) \
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 6787d40240d..97feb8cd1de 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -19,7 +19,6 @@
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkLumaColorFilter.h"
namespace blink {
@@ -440,7 +439,12 @@ int PropertyTreeManager::EnsureCompositorTransformNode(
transform_node.IsInSubtreeOfPageScale();
compositor_node.will_change_transform =
- transform_node.RequiresCompositingForWillChangeTransform();
+ transform_node.RequiresCompositingForWillChangeTransform() &&
+ // cc assumes preference of performance over raster quality for
+ // will-change:transform, but for SVG we still prefer raster quality, so
+ // don't pass will-change:transform to cc for SVG.
+ // TODO(crbug.com/1186020): find a better way to handle this.
+ !transform_node.IsForSVGChild();
if (const auto* sticky_constraint = transform_node.GetStickyConstraint()) {
cc::StickyPositionNodeData& sticky_data =
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index bece7e4d6c9..6aacf5e6f00 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -30,6 +30,7 @@ using CompositingReasons = uint64_t;
V(ActiveOpacityAnimation) \
V(ActiveFilterAnimation) \
V(ActiveBackdropFilterAnimation) \
+ V(AffectedByOuterViewportBoundsDelta) \
V(ScrollDependentPosition) \
V(OverflowScrolling) \
V(OverflowScrollingParent) \
@@ -130,14 +131,15 @@ class PLATFORM_EXPORT CompositingReason {
kComboAllDirectNonStyleDeterminedReasons =
kVideo | kCanvas | kPlugin | kIFrame | kSVGRoot |
kOverflowScrollingParent | kOutOfFlowClipping | kVideoOverlay |
- kXrOverlay | kRoot | kRootScroller | kScrollDependentPosition |
- kBackfaceInvisibility3DAncestor,
+ kXrOverlay | kRoot | kRootScroller | kScrollDependentPosition |
+ kAffectedByOuterViewportBoundsDelta | kBackfaceInvisibility3DAncestor,
kComboAllDirectReasons = kComboAllDirectStyleDeterminedReasons |
kComboAllDirectNonStyleDeterminedReasons,
kComboAllCompositedScrollingDeterminedReasons =
- kScrollDependentPosition | kOverflowScrolling,
+ kScrollDependentPosition | kAffectedByOuterViewportBoundsDelta |
+ kOverflowScrolling,
kComboCompositedDescendants =
kIsolateCompositedDescendants | kOpacityWithCompositedDescendants |
@@ -155,12 +157,11 @@ class PLATFORM_EXPORT CompositingReason {
kComboSquashableReasons =
kOverlap | kAssumedOverlap | kOverflowScrollingParent,
- kPreventingSubpixelAccumulationReasons =
- kWillChangeTransform | kActiveTransformAnimation,
+ kPreventingSubpixelAccumulationReasons = kWillChangeTransform,
kDirectReasonsForPaintOffsetTranslationProperty =
- kScrollDependentPosition | kVideo | kCanvas | kPlugin | kIFrame |
- kSVGRoot,
+ kScrollDependentPosition | kAffectedByOuterViewportBoundsDelta |
+ kVideo | kCanvas | kPlugin | kIFrame | kSVGRoot,
kDirectReasonsForTransformProperty =
k3DTransform | kTrivial3DTransform | kWillChangeTransform |
kWillChangeOther | kPerspectiveWith3DDescendants |
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc b/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
index 9eec39764c9..8217d7561ca 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/geometry/rect.h"
namespace blink {
@@ -53,9 +52,8 @@ void CompositorFilterOperations::AppendOpacityFilter(float amount) {
filter_operations_.Append(cc::FilterOperation::CreateOpacityFilter(amount));
}
-void CompositorFilterOperations::AppendBlurFilter(
- float amount,
- SkBlurImageFilter::TileMode tile_mode) {
+void CompositorFilterOperations::AppendBlurFilter(float amount,
+ SkTileMode tile_mode) {
filter_operations_.Append(
cc::FilterOperation::CreateBlurFilter(amount, tile_mode));
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.h b/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.h
index 4c3a334f655..6265a90eddf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_filter_operations.h
@@ -31,8 +31,7 @@ class PLATFORM_EXPORT CompositorFilterOperations {
void AppendContrastFilter(float amount);
void AppendOpacityFilter(float amount);
void AppendBlurFilter(float amount,
- SkBlurImageFilter::TileMode tile_mode =
- SkBlurImageFilter::kClampToBlack_TileMode);
+ SkTileMode tile_mode = SkTileMode::kDecal);
void AppendDropShadowFilter(IntPoint offset, float std_deviation, Color);
void AppendColorMatrixFilter(const cc::FilterOperation::Matrix&);
void AppendZoomFilter(float amount, int inset);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/contiguous_container.h b/chromium/third_party/blink/renderer/platform/graphics/contiguous_container.h
index 0aa085c6159..12c03b02c5f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/contiguous_container.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/contiguous_container.h
@@ -73,7 +73,7 @@ class PLATFORM_EXPORT ContiguousContainerBase {
public:
Buffer(wtf_size_t buffer_size, const char* type_name)
: capacity_(static_cast<wtf_size_t>(
- WTF::Partitions::BufferActualSize(buffer_size))),
+ WTF::Partitions::BufferPotentialCapacity(buffer_size))),
begin_(static_cast<uint8_t*>(
WTF::Partitions::BufferMalloc(capacity_, type_name))),
end_(begin_) {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
index c1a01c9a1a3..ad7135d0466 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
@@ -45,6 +45,7 @@ CrossfadeGeneratedImage::CrossfadeGeneratedImage(
void CrossfadeGeneratedImage::DrawCrossfade(
cc::PaintCanvas* canvas,
+ const SkSamplingOptions& sampling,
const PaintFlags& flags,
RespectImageOrientationEnum respect_orientation,
ImageClampingMode clamp_mode,
@@ -69,11 +70,11 @@ void CrossfadeGeneratedImage::DrawCrossfade(
// RespectImageOrientationEnum from CrossfadeGeneratedImage::draw(). Code was
// written this way during refactoring to avoid modifying existing behavior,
// but this warrants further investigation. crbug.com/472634
- from_image_->Draw(canvas, image_flags, dest_rect, from_image_rect,
+ from_image_->Draw(canvas, image_flags, dest_rect, from_image_rect, sampling,
kDoNotRespectImageOrientation, clamp_mode, decode_mode);
image_flags.setBlendMode(SkBlendMode::kPlus);
image_flags.setColor(ScaleAlpha(flags.getColor(), percentage_));
- to_image_->Draw(canvas, image_flags, dest_rect, to_image_rect,
+ to_image_->Draw(canvas, image_flags, dest_rect, to_image_rect, sampling,
respect_orientation, clamp_mode, decode_mode);
}
@@ -82,6 +83,7 @@ void CrossfadeGeneratedImage::Draw(
const PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum respect_orientation,
ImageClampingMode clamp_mode,
ImageDecodingMode decode_mode) {
@@ -91,9 +93,9 @@ void CrossfadeGeneratedImage::Draw(
PaintCanvasAutoRestore ar(canvas, true);
canvas->clipRect(dst_rect);
- canvas->concat(
- SkMatrix::MakeRectToRect(src_rect, dst_rect, SkMatrix::kFill_ScaleToFit));
- DrawCrossfade(canvas, flags, respect_orientation, clamp_mode, decode_mode);
+ canvas->concat(SkMatrix::RectToRect(src_rect, dst_rect));
+ DrawCrossfade(canvas, sampling, flags, respect_orientation, clamp_mode,
+ decode_mode);
}
void CrossfadeGeneratedImage::DrawTile(
@@ -107,10 +109,10 @@ void CrossfadeGeneratedImage::DrawTile(
PaintFlags flags = context.FillFlags();
flags.setBlendMode(SkBlendMode::kSrcOver);
FloatRect dest_rect((FloatPoint()), crossfade_size_);
- flags.setFilterQuality(
- context.ComputeFilterQuality(this, dest_rect, src_rect));
- DrawCrossfade(context.Canvas(), flags, respect_orientation,
- kClampImageToSourceRect, kSyncDecode);
+ DrawCrossfade(context.Canvas(),
+ context.ComputeSamplingOptions(this, dest_rect, src_rect),
+ flags, respect_orientation, kClampImageToSourceRect,
+ kSyncDecode);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.h b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.h
index 17fb61c5692..b98d2a5d50f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.h
@@ -56,6 +56,7 @@ class PLATFORM_EXPORT CrossfadeGeneratedImage final : public GeneratedImage {
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
@@ -71,6 +72,7 @@ class PLATFORM_EXPORT CrossfadeGeneratedImage final : public GeneratedImage {
private:
void DrawCrossfade(cc::PaintCanvas*,
+ const SkSamplingOptions&,
const cc::PaintFlags&,
RespectImageOrientationEnum,
ImageClampingMode,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc b/chromium/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
index a22f12f13d1..096239c8f45 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
@@ -211,7 +211,7 @@ bool DecodingImageGenerator::GetPixels(const SkImageInfo& dst_info,
decoded = bitmap.installPixels(target_info, memory, adjusted_row_bytes);
DCHECK(decoded);
- canvas->drawBitmap(bitmap, 0, 0, &paint);
+ canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
}
}
return decoded;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
index 362325664f5..642f5785ca9 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
@@ -30,9 +30,12 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/platform/graphics/decoding_image_generator.h"
#include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
#include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image_manager.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
@@ -45,30 +48,30 @@ namespace {
// Do not rename entries or reuse numeric values to ensure the histogram is
// consistent over time.
-enum IncrementalDecodePerImageType {
+enum class IncrementalDecodePerImageType {
kJpegIncrementalNeeded = 0,
kJpegAllDataReceivedInitially = 1,
kWebPIncrementalNeeded = 2,
kWebPAllDataReceivedInitially = 3,
- kBoundaryValue
+ kMaxValue = kWebPAllDataReceivedInitially,
};
void ReportIncrementalDecodeNeeded(bool all_data_received,
const String& image_type) {
DCHECK(IsMainThread());
- DEFINE_STATIC_LOCAL(EnumerationHistogram, incremental_decode_needed_histogram,
- ("Blink.ImageDecoders.IncrementalDecodeNeeded",
- IncrementalDecodePerImageType::kBoundaryValue));
+ base::Optional<IncrementalDecodePerImageType> status;
if (image_type == "jpg") {
- incremental_decode_needed_histogram.Count(
- all_data_received
- ? IncrementalDecodePerImageType::kJpegAllDataReceivedInitially
- : IncrementalDecodePerImageType::kJpegIncrementalNeeded);
+ status = all_data_received
+ ? IncrementalDecodePerImageType::kJpegAllDataReceivedInitially
+ : IncrementalDecodePerImageType::kJpegIncrementalNeeded;
} else if (image_type == "webp") {
- incremental_decode_needed_histogram.Count(
- all_data_received
- ? IncrementalDecodePerImageType::kWebPAllDataReceivedInitially
- : IncrementalDecodePerImageType::kWebPIncrementalNeeded);
+ status = all_data_received
+ ? IncrementalDecodePerImageType::kWebPAllDataReceivedInitially
+ : IncrementalDecodePerImageType::kWebPIncrementalNeeded;
+ }
+ if (status) {
+ UMA_HISTOGRAM_ENUMERATION("Blink.ImageDecoders.IncrementalDecodeNeeded",
+ *status);
}
}
@@ -167,9 +170,11 @@ DeferredImageDecoder::DeferredImageDecoder(
can_yuv_decode_(false),
has_hot_spot_(false),
image_is_high_bit_depth_(false),
- complete_frame_content_id_(PaintImage::GetNextContentId()) {}
+ complete_frame_content_id_(PaintImage::GetNextContentId()) {
+}
-DeferredImageDecoder::~DeferredImageDecoder() = default;
+DeferredImageDecoder::~DeferredImageDecoder() {
+}
String DeferredImageDecoder::FilenameExtension() const {
return metadata_decoder_ ? metadata_decoder_->FilenameExtension()
@@ -188,9 +193,8 @@ sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator() {
DCHECK_GT(decoded_size.width(), 0);
DCHECK_GT(decoded_size.height(), 0);
- sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
scoped_refptr<SegmentReader> segment_reader =
- SegmentReader::CreateFromSkROBuffer(std::move(ro_buffer));
+ parkable_image_->MakeROSnapshot();
SkImageInfo info =
SkImageInfo::MakeN32(decoded_size.width(), decoded_size.height(),
@@ -247,15 +251,7 @@ sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator() {
}
scoped_refptr<SharedBuffer> DeferredImageDecoder::Data() {
- if (!rw_buffer_)
- return nullptr;
- sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
- scoped_refptr<SharedBuffer> shared_buffer = SharedBuffer::Create();
- SkROBuffer::Iter it(ro_buffer.get());
- do {
- shared_buffer->Append(static_cast<const char*>(it.data()), it.size());
- } while (it.next());
- return shared_buffer;
+ return parkable_image_ ? parkable_image_->Data() : nullptr;
}
void DeferredImageDecoder::SetData(scoped_refptr<SharedBuffer> data,
@@ -266,6 +262,8 @@ void DeferredImageDecoder::SetData(scoped_refptr<SharedBuffer> data,
void DeferredImageDecoder::SetDataInternal(scoped_refptr<SharedBuffer> data,
bool all_data_received,
bool push_data_to_decoder) {
+ // Once all the data has been received, the image should not change.
+ DCHECK(!all_data_received_);
if (metadata_decoder_) {
all_data_received_ = all_data_received;
if (push_data_to_decoder)
@@ -274,16 +272,14 @@ void DeferredImageDecoder::SetDataInternal(scoped_refptr<SharedBuffer> data,
}
if (frame_generator_) {
- if (!rw_buffer_)
- rw_buffer_ = std::make_unique<SkRWBuffer>(data->size());
-
- for (auto it = data->GetIteratorAt(rw_buffer_->size()); it != data->cend();
- ++it) {
- DCHECK_GE(data->size(), rw_buffer_->size() + it->size());
- const size_t remaining = data->size() - rw_buffer_->size() - it->size();
- rw_buffer_->append(it->data(), it->size(), remaining);
- }
+ if (!parkable_image_)
+ parkable_image_ = ParkableImage::Create(data->size());
+
+ parkable_image_->Append(data.get(), parkable_image_->size());
}
+
+ if (all_data_received && parkable_image_)
+ parkable_image_->Freeze();
}
bool DeferredImageDecoder::IsSizeAvailable() {
@@ -374,7 +370,7 @@ IntSize DeferredImageDecoder::DensityCorrectedSizeAtIndex(size_t index) const {
size_t DeferredImageDecoder::ByteSize() const {
- return rw_buffer_ ? rw_buffer_->size() : 0u;
+ return parkable_image_ ? parkable_image_->size() : 0u;
}
void DeferredImageDecoder::ActivateLazyDecoding() {
@@ -438,15 +434,12 @@ void DeferredImageDecoder::PrepareLazyDecodedFrames() {
frame_data_[i].duration_ = metadata_decoder_->FrameDurationAtIndex(i);
frame_data_[i].orientation_ = metadata_decoder_->Orientation();
frame_data_[i].density_corrected_size_ = metadata_decoder_->DensityCorrectedSize();
- frame_data_[i].is_received_ = metadata_decoder_->FrameIsReceivedAtIndex(i);
}
- // The last lazy decoded frame created from previous call might be
- // incomplete so update its state.
- if (previous_size) {
- const size_t last_frame = previous_size - 1;
- frame_data_[last_frame].is_received_ =
- metadata_decoder_->FrameIsReceivedAtIndex(last_frame);
+ // Update the is_received_ state of incomplete frames.
+ while (received_frame_count_ < frame_data_.size() &&
+ metadata_decoder_->FrameIsReceivedAtIndex(received_frame_count_)) {
+ frame_data_[received_frame_count_++].is_received_ = true;
}
can_yuv_decode_ =
diff --git a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
index 86d323705d7..d0d2952bf04 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
@@ -31,13 +31,14 @@
#include "base/macros.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "third_party/skia/include/core/SkRWBuffer.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace blink {
@@ -104,7 +105,7 @@ class PLATFORM_EXPORT DeferredImageDecoder final {
// Copy of the data that is passed in, used by deferred decoding.
// Allows creating readonly snapshots that may be read in another thread.
- std::unique_ptr<SkRWBuffer> rw_buffer_;
+ scoped_refptr<ParkableImage> parkable_image_;
std::unique_ptr<ImageDecoder> metadata_decoder_;
String filename_extension_;
@@ -131,6 +132,9 @@ class PLATFORM_EXPORT DeferredImageDecoder final {
// Caches frame state information.
Vector<DeferredFrameData> frame_data_;
+ // The number of received/complete frames in |frame_data_|. Note: This is also
+ // the index of the first unreceived/incomplete frame in |frame_data_|.
+ size_t received_frame_count_ = 0;
scoped_refptr<ImageFrameGenerator> frame_generator_;
DISALLOW_COPY_AND_ASSIGN(DeferredImageDecoder);
@@ -138,4 +142,4 @@ class PLATFORM_EXPORT DeferredImageDecoder final {
} // namespace blink
-#endif
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DEFERRED_IMAGE_DECODER_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test_wo_platform.cc b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test_wo_platform.cc
index ae2f0fed896..00d20ed258a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test_wo_platform.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test_wo_platform.cc
@@ -6,6 +6,7 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
+#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -45,6 +46,7 @@ sk_sp<SkImage> CreateFrameAtIndex(DeferredImageDecoder* decoder, size_t index) {
static void MixImages(const char* file_name,
size_t bytes_for_first_frame,
size_t later_frame) {
+ base::test::SingleThreadTaskEnvironment task_environment;
const Vector<char> file = ReadFile(file_name)->CopyAs<Vector<char>>();
scoped_refptr<SharedBuffer> partial_file =
@@ -93,6 +95,7 @@ TEST(DeferredImageDecoderTestWoPlatform, mixImagesIco) {
}
TEST(DeferredImageDecoderTestWoPlatform, fragmentedSignature) {
+ base::test::SingleThreadTaskEnvironment task_environment;
const char* test_files[] = {
"/images/resources/animated.gif",
"/images/resources/mu.png",
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_blend.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_blend.cc
index 7b69feefc5d..a261591877b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_blend.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_blend.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkXfermodeImageFilter.h"
namespace blink {
@@ -48,9 +47,10 @@ sk_sp<PaintFilter> FEBlend::CreateImageFilter() {
InputEffect(1), OperatingInterpolationSpace()));
SkBlendMode mode =
WebCoreCompositeToSkiaComposite(kCompositeSourceOver, mode_);
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<XfermodePaintFilter>(mode, std::move(background),
- std::move(foreground), &crop_rect);
+ std::move(foreground),
+ base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEBlend::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_box_reflect.h b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_box_reflect.h
index 3c137e185b9..cc1458201c6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_box_reflect.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_box_reflect.h
@@ -15,14 +15,13 @@ namespace blink {
class PLATFORM_EXPORT FEBoxReflect final : public FilterEffect {
public:
FEBoxReflect(Filter*, const BoxReflection&);
+ ~FEBoxReflect() final;
// FilterEffect implementation
WTF::TextStream& ExternalRepresentation(WTF::TextStream&,
int indentation) const final;
private:
- ~FEBoxReflect() final;
-
FloatRect MapEffect(const FloatRect&) const final;
sk_sp<PaintFilter> CreateImageFilter() final;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_color_matrix.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_color_matrix.cc
index aa24b6a28ab..968e9299cfd 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_color_matrix.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_color_matrix.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
namespace blink {
@@ -146,9 +145,9 @@ sk_sp<PaintFilter> FEColorMatrix::CreateImageFilter() {
sk_sp<PaintFilter> input(paint_filter_builder::Build(
InputEffect(0), OperatingInterpolationSpace()));
sk_sp<SkColorFilter> filter = CreateColorFilter(type_, values_);
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<ColorFilterPaintFilter>(std::move(filter), std::move(input),
- &rect);
+ base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
index a54b3ff2ed4..0c1caba69a2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc
@@ -132,11 +132,12 @@ sk_sp<PaintFilter> FEComponentTransfer::CreateImageFilter() {
unsigned char r_values[256], g_values[256], b_values[256], a_values[256];
GetValues(r_values, g_values, b_values, a_values);
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
sk_sp<SkColorFilter> color_filter =
SkTableColorFilter::MakeARGB(a_values, r_values, g_values, b_values);
return sk_make_sp<ColorFilterPaintFilter>(std::move(color_filter),
- std::move(input), &crop_rect);
+ std::move(input),
+ base::OptionalOrNullptr(crop_rect));
}
void FEComponentTransfer::GetValues(unsigned char r_values[256],
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_composite.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_composite.cc
index 6954edfc4fe..9b75b9a5c3d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_composite.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_composite.cc
@@ -27,8 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkArithmeticImageFilter.h"
-#include "third_party/skia/include/effects/SkXfermodeImageFilter.h"
namespace blink {
@@ -186,18 +184,19 @@ sk_sp<PaintFilter> FEComposite::CreateImageFilterInternal(
sk_sp<PaintFilter> background(
paint_filter_builder::Build(InputEffect(1), OperatingInterpolationSpace(),
!MayProduceInvalidPreMultipliedPixels()));
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
if (type_ == FECOMPOSITE_OPERATOR_ARITHMETIC) {
return sk_make_sp<ArithmeticPaintFilter>(
SkFloatToScalar(k1_), SkFloatToScalar(k2_), SkFloatToScalar(k3_),
SkFloatToScalar(k4_), requires_pm_color_validation,
- std::move(background), std::move(foreground), &crop_rect);
+ std::move(background), std::move(foreground),
+ base::OptionalOrNullptr(crop_rect));
}
- return sk_make_sp<XfermodePaintFilter>(ToBlendMode(type_),
- std::move(background),
- std::move(foreground), &crop_rect);
+ return sk_make_sp<XfermodePaintFilter>(
+ ToBlendMode(type_), std::move(background), std::move(foreground),
+ base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_convolve_matrix.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_convolve_matrix.cc
index 940a79825b3..0eb108c673e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_convolve_matrix.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_convolve_matrix.cc
@@ -29,7 +29,6 @@
#include "base/numerics/checked_math.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkMatrixConvolutionImageFilter.h"
namespace blink {
@@ -94,17 +93,16 @@ bool FEConvolveMatrix::SetPreserveAlpha(bool preserve_alpha) {
return true;
}
-SkMatrixConvolutionImageFilter::TileMode ToSkiaTileMode(
- EdgeModeType edge_mode) {
+static SkTileMode ToSkiaTileMode(EdgeModeType edge_mode) {
switch (edge_mode) {
case EDGEMODE_DUPLICATE:
- return SkMatrixConvolutionImageFilter::kClamp_TileMode;
+ return SkTileMode::kClamp;
case EDGEMODE_WRAP:
- return SkMatrixConvolutionImageFilter::kRepeat_TileMode;
+ return SkTileMode::kRepeat;
case EDGEMODE_NONE:
- return SkMatrixConvolutionImageFilter::kClampToBlack_TileMode;
+ return SkTileMode::kDecal;
default:
- return SkMatrixConvolutionImageFilter::kClamp_TileMode;
+ return SkTileMode::kClamp;
}
}
@@ -138,15 +136,15 @@ sk_sp<PaintFilter> FEConvolveMatrix::CreateImageFilter() {
SkScalar gain = SkFloatToScalar(1.0f / divisor_);
SkScalar bias = SkFloatToScalar(bias_ * 255);
SkIPoint target = SkIPoint::Make(target_offset_.X(), target_offset_.Y());
- MatrixConvolutionPaintFilter::TileMode tile_mode = ToSkiaTileMode(edge_mode_);
+ SkTileMode tile_mode = ToSkiaTileMode(edge_mode_);
bool convolve_alpha = !preserve_alpha_;
auto kernel = std::make_unique<SkScalar[]>(num_elements);
for (int i = 0; i < num_elements; ++i)
kernel[i] = SkFloatToScalar(kernel_matrix_[num_elements - 1 - i]);
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<MatrixConvolutionPaintFilter>(
kernel_size, kernel.get(), gain, bias, target, tile_mode, convolve_alpha,
- std::move(input), &crop_rect);
+ std::move(input), base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_displacement_map.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_displacement_map.cc
index da586678816..f5e13fdde07 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_displacement_map.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_displacement_map.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkDisplacementMapEffect.h"
namespace blink {
@@ -86,20 +85,20 @@ bool FEDisplacementMap::SetScale(float scale) {
return true;
}
-static SkDisplacementMapEffect::ChannelSelectorType ToSkiaMode(
- ChannelSelectorType type) {
+static SkColorChannel ToSkiaMode(ChannelSelectorType type) {
switch (type) {
case CHANNEL_R:
- return SkDisplacementMapEffect::kR_ChannelSelectorType;
+ return SkColorChannel::kR;
case CHANNEL_G:
- return SkDisplacementMapEffect::kG_ChannelSelectorType;
+ return SkColorChannel::kG;
case CHANNEL_B:
- return SkDisplacementMapEffect::kB_ChannelSelectorType;
+ return SkColorChannel::kB;
case CHANNEL_A:
- return SkDisplacementMapEffect::kA_ChannelSelectorType;
+ return SkColorChannel::kA;
case CHANNEL_UNKNOWN:
default:
- return SkDisplacementMapEffect::kUnknown_ChannelSelectorType;
+ // Historically, Skia's raster backend treated unknown as blue.
+ return SkColorChannel::kB;
}
}
@@ -114,18 +113,16 @@ sk_sp<PaintFilter> FEDisplacementMap::CreateImageFilter() {
sk_sp<PaintFilter> displ = paint_filter_builder::Build(
InputEffect(1), OperatingInterpolationSpace());
- SkDisplacementMapEffect::ChannelSelectorType type_x =
- ToSkiaMode(x_channel_selector_);
- SkDisplacementMapEffect::ChannelSelectorType type_y =
- ToSkiaMode(y_channel_selector_);
- PaintFilter::CropRect crop_rect = GetCropRect();
+ SkColorChannel type_x = ToSkiaMode(x_channel_selector_);
+ SkColorChannel type_y = ToSkiaMode(y_channel_selector_);
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
// FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored
// This can be fixed by adding a 2nd scale parameter to
// DisplacementMapEffectPaintFilter.
return sk_make_sp<DisplacementMapEffectPaintFilter>(
type_x, type_y,
SkFloatToScalar(GetFilter()->ApplyHorizontalScale(scale_)),
- std::move(displ), std::move(color), &crop_rect);
+ std::move(displ), std::move(color), base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_drop_shadow.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_drop_shadow.cc
index 1a5fb28eb81..74bae62fd5b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_drop_shadow.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_drop_shadow.cc
@@ -24,7 +24,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
namespace blink {
@@ -72,12 +71,12 @@ sk_sp<PaintFilter> FEDropShadow::CreateImageFilter() {
float std_y = GetFilter()->ApplyVerticalScale(std_y_);
Color color = AdaptColorToOperatingInterpolationSpace(
shadow_color_.CombineWithAlpha(shadow_opacity_));
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<DropShadowPaintFilter>(
SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(std_x),
SkFloatToScalar(std_y), color.Rgb(),
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
- std::move(input), &crop_rect);
+ DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
+ std::move(input), base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEDropShadow::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_flood.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_flood.cc
index 3b38104d1f2..d3373a41082 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_flood.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_flood.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
namespace blink {
@@ -60,9 +59,10 @@ bool FEFlood::SetFloodOpacity(float flood_opacity) {
sk_sp<PaintFilter> FEFlood::CreateImageFilter() {
Color color = FloodColor().CombineWithAlpha(FloodOpacity());
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<ColorFilterPaintFilter>(
- SkColorFilters::Blend(color.Rgb(), SkBlendMode::kSrc), nullptr, &rect);
+ SkColorFilters::Blend(color.Rgb(), SkBlendMode::kSrc), nullptr,
+ base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEFlood::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_gaussian_blur.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_gaussian_blur.cc
index 64d77f92ccd..e2bf85c9c5e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_gaussian_blur.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_gaussian_blur.cc
@@ -28,7 +28,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
namespace blink {
@@ -80,11 +79,10 @@ sk_sp<PaintFilter> FEGaussianBlur::CreateImageFilter() {
InputEffect(0), OperatingInterpolationSpace()));
float std_x = GetFilter()->ApplyHorizontalScale(std_x_);
float std_y = GetFilter()->ApplyVerticalScale(std_y_);
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<BlurPaintFilter>(
- SkFloatToScalar(std_x), SkFloatToScalar(std_y),
- BlurPaintFilter::TileMode::kClampToBlack_TileMode, std::move(input),
- &rect);
+ SkFloatToScalar(std_x), SkFloatToScalar(std_y), SkTileMode::kDecal,
+ std::move(input), base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEGaussianBlur::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_lighting.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_lighting.cc
index 2a0c7ddf992..81a5df87357 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_lighting.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_lighting.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/point_light_source.h"
#include "third_party/blink/renderer/platform/graphics/filters/spot_light_source.h"
#include "third_party/skia/include/core/SkPoint3.h"
-#include "third_party/skia/include/effects/SkLightingImageFilter.h"
namespace blink {
@@ -56,7 +55,8 @@ FELighting::FELighting(Filter* filter,
sk_sp<PaintFilter> FELighting::CreateImageFilter() {
if (!light_source_)
return CreateTransparentBlack();
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
+ const PaintFilter::CropRect* rect = base::OptionalOrNullptr(crop_rect);
Color light_color = AdaptColorToOperatingInterpolationSpace(lighting_color_);
sk_sp<PaintFilter> input(paint_filter_builder::Build(
InputEffect(0), OperatingInterpolationSpace()));
@@ -71,7 +71,7 @@ sk_sp<PaintFilter> FELighting::CreateImageFilter() {
sinf(azimuth_rad) * cosf(elevation_rad), sinf(elevation_rad));
return sk_make_sp<LightingDistantPaintFilter>(
GetLightingType(), direction, light_color.Rgb(), surface_scale_,
- GetFilterConstant(), specular_exponent_, std::move(input), &rect);
+ GetFilterConstant(), specular_exponent_, std::move(input), rect);
}
case LS_POINT: {
PointLightSource* point_light_source =
@@ -81,7 +81,7 @@ sk_sp<PaintFilter> FELighting::CreateImageFilter() {
SkPoint3::Make(position.X(), position.Y(), position.Z());
return sk_make_sp<LightingPointPaintFilter>(
GetLightingType(), sk_position, light_color.Rgb(), surface_scale_,
- GetFilterConstant(), specular_exponent_, std::move(input), &rect);
+ GetFilterConstant(), specular_exponent_, std::move(input), rect);
}
case LS_SPOT: {
SpotLightSource* spot_light_source =
@@ -102,7 +102,7 @@ sk_sp<PaintFilter> FELighting::CreateImageFilter() {
return sk_make_sp<LightingSpotPaintFilter>(
GetLightingType(), location, target, specular_exponent,
limiting_cone_angle, light_color.Rgb(), surface_scale_,
- GetFilterConstant(), specular_exponent_, std::move(input), &rect);
+ GetFilterConstant(), specular_exponent_, std::move(input), rect);
}
default:
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_merge.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_merge.cc
index 6cd3d006913..60b9a9cfb32 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_merge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_merge.cc
@@ -26,7 +26,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkMergeImageFilter.h"
namespace blink {
@@ -40,8 +39,9 @@ sk_sp<PaintFilter> FEMerge::CreateImageFilter() {
input_refs[i] = paint_filter_builder::Build(InputEffect(i),
OperatingInterpolationSpace());
}
- PaintFilter::CropRect rect = GetCropRect();
- return sk_make_sp<MergePaintFilter>(input_refs.get(), size, &rect);
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
+ return sk_make_sp<MergePaintFilter>(input_refs.get(), size,
+ base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEMerge::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_morphology.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_morphology.cc
index e1bcdbc28c3..9bd37164631 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_morphology.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_morphology.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkMorphologyImageFilter.h"
namespace blink {
@@ -87,13 +86,14 @@ sk_sp<PaintFilter> FEMorphology::CreateImageFilter() {
InputEffect(0), OperatingInterpolationSpace()));
float radius_x = GetFilter()->ApplyHorizontalScale(radius_x_);
float radius_y = GetFilter()->ApplyVerticalScale(radius_y_);
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
MorphologyPaintFilter::MorphType morph_type =
type_ == FEMORPHOLOGY_OPERATOR_DILATE
? MorphologyPaintFilter::MorphType::kDilate
: MorphologyPaintFilter::MorphType::kErode;
return sk_make_sp<MorphologyPaintFilter>(morph_type, radius_x, radius_y,
- std::move(input), &rect);
+ std::move(input),
+ base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_offset.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_offset.cc
index 364a6595d23..59924c02b69 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_offset.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_offset.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
namespace blink {
@@ -59,13 +58,13 @@ FloatRect FEOffset::MapEffect(const FloatRect& rect) const {
sk_sp<PaintFilter> FEOffset::CreateImageFilter() {
Filter* filter = this->GetFilter();
- PaintFilter::CropRect crop_rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
return sk_make_sp<OffsetPaintFilter>(
SkFloatToScalar(filter->ApplyHorizontalScale(dx_)),
SkFloatToScalar(filter->ApplyVerticalScale(dy_)),
paint_filter_builder::Build(InputEffect(0),
OperatingInterpolationSpace()),
- &crop_rect);
+ base::OptionalOrNullptr(crop_rect));
}
WTF::TextStream& FEOffset::ExternalRepresentation(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_tile.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_tile.cc
index b2bff044da0..5b4aa835b31 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_tile.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_tile.cc
@@ -24,7 +24,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkTileImageFilter.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_turbulence.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_turbulence.cc
index f3a89fcd103..7684c13d7d4 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_turbulence.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_turbulence.cc
@@ -27,8 +27,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkPaintImageFilter.h"
-#include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
namespace blink {
@@ -123,7 +121,7 @@ sk_sp<PaintFilter> FETurbulence::CreateImageFilter() {
base_frequency_x = base_frequency_y = 0;
}
- PaintFilter::CropRect rect = GetCropRect();
+ base::Optional<PaintFilter::CropRect> crop_rect = GetCropRect();
TurbulencePaintFilter::TurbulenceType type =
GetType() == FETURBULENCE_TYPE_FRACTALNOISE
? TurbulencePaintFilter::TurbulenceType::kFractalNoise
@@ -144,7 +142,8 @@ sk_sp<PaintFilter> FETurbulence::CreateImageFilter() {
return sk_make_sp<TurbulencePaintFilter>(
type, SkFloatToScalar(base_frequency_x),
SkFloatToScalar(base_frequency_y), capped_num_octaves,
- SkFloatToScalar(Seed()), StitchTiles() ? &size : nullptr, &rect);
+ SkFloatToScalar(Seed()), StitchTiles() ? &size : nullptr,
+ base::OptionalOrNullptr(crop_rect));
}
static WTF::TextStream& operator<<(WTF::TextStream& ts,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.cc
index 63733cdf642..4a1b5b02a33 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
namespace blink {
@@ -133,25 +132,23 @@ bool FilterEffect::InputsTaintOrigin() const {
}
sk_sp<PaintFilter> FilterEffect::CreateTransparentBlack() const {
- PaintFilter::CropRect rect = GetCropRect();
sk_sp<SkColorFilter> color_filter =
SkColorFilters::Blend(0, SkBlendMode::kClear);
- return sk_make_sp<ColorFilterPaintFilter>(std::move(color_filter), nullptr,
- &rect);
+ return sk_make_sp<ColorFilterPaintFilter>(
+ std::move(color_filter), nullptr, base::OptionalOrNullptr(GetCropRect()));
}
-PaintFilter::CropRect FilterEffect::GetCropRect() const {
+base::Optional<PaintFilter::CropRect> FilterEffect::GetCropRect() const {
if (!ClipsToBounds())
- return PaintFilter::CropRect(SkRect::MakeEmpty(), 0);
+ return {};
FloatRect computed_bounds = FilterPrimitiveSubregion();
// This and the filter region check is a workaround for crbug.com/512453.
if (computed_bounds.IsEmpty())
- return PaintFilter::CropRect(SkRect::MakeEmpty(), 0);
+ return {};
FloatRect filter_region = GetFilter()->FilterRegion();
if (!filter_region.IsEmpty())
computed_bounds.Intersect(filter_region);
- return PaintFilter::CropRect(
- GetFilter()->MapLocalRectToAbsoluteRect(computed_bounds));
+ return GetFilter()->MapLocalRectToAbsoluteRect(computed_bounds);
}
static int GetImageFilterIndex(InterpolationSpace interpolation_space,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.h b/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
index 15c66cbfcdd..1b402e2a3cb 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/filter_effect.h
@@ -139,7 +139,7 @@ class PLATFORM_EXPORT FilterEffect : public GarbageCollected<FilterEffect> {
Color AdaptColorToOperatingInterpolationSpace(const Color& device_color);
- PaintFilter::CropRect GetCropRect() const;
+ base::Optional<PaintFilter::CropRect> GetCropRect() const;
private:
FilterEffectVector input_effects_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.cc
index 34ce3217d11..1bea3065ec2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.cc
@@ -30,14 +30,8 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
-#include "third_party/skia/include/effects/SkImageSource.h"
-#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
-#include "third_party/skia/include/effects/SkPictureImageFilter.h"
#include "third_party/skia/include/effects/SkTableColorFilter.h"
-#include "third_party/skia/include/effects/SkXfermodeImageFilter.h"
namespace blink {
namespace paint_filter_builder {
@@ -167,9 +161,8 @@ sk_sp<PaintFilter> BuildBoxReflectFilter(const BoxReflection& reflection,
sk_sp<PaintFilter> flip_image_filter = sk_make_sp<MatrixPaintFilter>(
reflection.ReflectionMatrix(), kLow_SkFilterQuality,
std::move(masked_input));
- return sk_make_sp<XfermodePaintFilter>(SkBlendMode::kSrcOver,
- std::move(flip_image_filter),
- std::move(input), nullptr);
+ return sk_make_sp<XfermodePaintFilter>(
+ SkBlendMode::kSrcOver, std::move(flip_image_filter), std::move(input));
}
} // namespace paint_filter_builder
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_effect.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_effect.cc
index 042813ae8c7..9e9b03d9ef7 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_effect.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/paint_filter_effect.cc
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
-#include "third_party/skia/include/effects/SkPaintImageFilter.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/source_alpha.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/source_alpha.cc
index a23b3fdeace..53b757b1c97 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/filters/source_alpha.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/filters/source_alpha.cc
@@ -24,7 +24,6 @@
#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/DIR_METADATA b/chromium/third_party/blink/renderer/platform/graphics/gpu/DIR_METADATA
new file mode 100644
index 00000000000..ab221ae12bf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebGL"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/OWNERS b/chromium/third_party/blink/renderer/platform/graphics/gpu/OWNERS
index c4f33610158..1bac549914b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/OWNERS
@@ -1,7 +1,6 @@
# The bulk of the files in this directory are related to WebGL, though
# there are a couple used by accelerated 2D canvas as well.
-# COMPONENT: Blink>WebGL
# WebGL, WebGPU, Dawn, etc.
kainino@chromium.org
@@ -13,4 +12,4 @@ bajones@chromium.org
klausw@chromium.org
# SharedGpuContext, ImageLayerBridge, etc.
-khushalsagar@chromium.org
+sunnyps@chromium.org
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
index 751629c19a0..4cb708fe301 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
@@ -13,7 +13,8 @@ namespace blink {
DawnControlClientHolder::DawnControlClientHolder(
std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
: context_provider_(std::move(context_provider)),
- interface_(context_provider_->WebGPUInterface()) {}
+ interface_(context_provider_->WebGPUInterface()),
+ procs_(interface_->GetProcs()) {}
void DawnControlClientHolder::SetLostContextCallback() {
context_provider_->SetLostContextCallback(WTF::BindRepeating(
@@ -21,12 +22,8 @@ void DawnControlClientHolder::SetLostContextCallback() {
}
void DawnControlClientHolder::Destroy() {
- interface_ = nullptr;
- context_provider_.reset();
-}
-
-bool DawnControlClientHolder::IsDestroyed() const {
- return !interface_;
+ SetContextLost();
+ interface_->DisconnectContextAndDestroyServer();
}
WebGraphicsContext3DProvider* DawnControlClientHolder::GetContextProvider()
@@ -39,11 +36,6 @@ gpu::webgpu::WebGPUInterface* DawnControlClientHolder::GetInterface() const {
return interface_;
}
-const DawnProcTable& DawnControlClientHolder::GetProcs() const {
- DCHECK(interface_);
- return interface_->GetProcs();
-}
-
void DawnControlClientHolder::SetContextLost() {
lost_ = true;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
index af3c42b82f3..0e4527ec3bf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
@@ -32,11 +32,10 @@ class PLATFORM_EXPORT DawnControlClientHolder
std::unique_ptr<WebGraphicsContext3DProvider> context_provider);
void Destroy();
- bool IsDestroyed() const;
WebGraphicsContext3DProvider* GetContextProvider() const;
gpu::webgpu::WebGPUInterface* GetInterface() const;
- const DawnProcTable& GetProcs() const;
+ const DawnProcTable& GetProcs() const { return procs_; }
void SetContextLost();
bool IsContextLost() const;
void SetLostContextCallback();
@@ -47,6 +46,7 @@ class PLATFORM_EXPORT DawnControlClientHolder
std::unique_ptr<WebGraphicsContext3DProvider> context_provider_;
gpu::webgpu::WebGPUInterface* interface_;
+ DawnProcTable procs_;
bool lost_ = false;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 04b28152719..893abfc4e1d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -210,7 +210,6 @@ DrawingBuffer::DrawingBuffer(
want_depth_(want_depth),
want_stencil_(want_stencil),
storage_color_space_(color_params.GetStorageGfxColorSpace()),
- sampler_color_space_(color_params.GetSamplerGfxColorSpace()),
use_half_float_storage_(color_params.PixelFormat() ==
CanvasPixelFormat::kF16),
filter_quality_(filter_quality),
@@ -421,8 +420,7 @@ bool DrawingBuffer::FinishPrepareTransferableResourceSoftware(
// mailbox is released (and while the release callback is running). It also
// owns the SharedBitmap.
auto func = base::BindOnce(&DrawingBuffer::MailboxReleasedSoftware,
- weak_factory_.GetWeakPtr(),
- WTF::Passed(std::move(registered)));
+ weak_factory_.GetWeakPtr(), std::move(registered));
*out_release_callback = viz::SingleReleaseCallback::Create(std::move(func));
contents_changed_ = false;
@@ -520,7 +518,7 @@ bool DrawingBuffer::FinishPrepareTransferableResourceGpu(
color_buffer_for_mailbox->mailbox, GL_LINEAR, texture_target_,
color_buffer_for_mailbox->produce_sync_token, gfx::Size(size_),
is_overlay_candidate);
- out_resource->color_space = sampler_color_space_;
+ out_resource->color_space = storage_color_space_;
out_resource->format = color_buffer_for_mailbox->format;
// This holds a ref on the DrawingBuffer that will keep it alive until the
// mailbox is released (and while the release callback is running).
@@ -672,7 +670,7 @@ DrawingBuffer::ScopedRGBEmulationForBlitFramebuffer::
}
}
-scoped_refptr<CanvasResource> DrawingBuffer::AsCanvasResource(
+scoped_refptr<CanvasResource> DrawingBuffer::ExportLowLatencyCanvasResource(
base::WeakPtr<CanvasResourceProvider> resource_provider) {
// Swap chain must be presented before resource is exported.
ResolveAndPresentSwapChainIfNeeded();
@@ -680,14 +678,14 @@ scoped_refptr<CanvasResource> DrawingBuffer::AsCanvasResource(
scoped_refptr<ColorBuffer> canvas_resource_buffer =
UsingSwapChain() ? front_color_buffer_ : back_color_buffer_;
- CanvasColorParams color_params;
+ CanvasResourceParams resource_params;
switch (canvas_resource_buffer->format) {
case viz::RGBA_8888:
case viz::RGBX_8888:
- color_params.SetCanvasPixelFormat(CanvasPixelFormat::kRGBA8);
+ resource_params.SetSkColorType(kRGBA_8888_SkColorType);
break;
case viz::RGBA_F16:
- color_params.SetCanvasPixelFormat(CanvasPixelFormat::kF16);
+ resource_params.SetSkColorType(kRGBA_F16_SkColorType);
break;
default:
NOTREACHED();
@@ -695,10 +693,51 @@ scoped_refptr<CanvasResource> DrawingBuffer::AsCanvasResource(
}
return ExternalCanvasResource::Create(
- canvas_resource_buffer->mailbox, canvas_resource_buffer->size,
- texture_target_, color_params, context_provider_->GetWeakPtr(),
- resource_provider, kLow_SkFilterQuality,
- /*is_origin_top_left=*/opengl_flip_y_extension_);
+ canvas_resource_buffer->mailbox, /*release_callback=*/nullptr,
+ gpu::SyncToken(), canvas_resource_buffer->size, texture_target_,
+ resource_params, context_provider_->GetWeakPtr(), resource_provider,
+ kLow_SkFilterQuality,
+ /*is_origin_top_left=*/opengl_flip_y_extension_,
+ /*is_overlay_candidate=*/true);
+}
+
+scoped_refptr<CanvasResource> DrawingBuffer::ExportCanvasResource() {
+ ScopedStateRestorer scoped_state_restorer(this);
+ TRACE_EVENT0("blink", "DrawingBuffer::ExportCanvasResource");
+
+ // Using PrepareTransferableResourceInternal, with force_gpu_result as we
+ // will use this ExportCanvasResource only for gpu_composited content.
+ viz::TransferableResource out_resource;
+ std::unique_ptr<viz::SingleReleaseCallback> out_release_callback;
+ const bool force_gpu_result = true;
+ if (!PrepareTransferableResourceInternal(
+ nullptr, &out_resource, &out_release_callback, force_gpu_result))
+ return nullptr;
+
+ CanvasResourceParams resource_params;
+ switch (out_resource.format) {
+ case viz::RGBA_8888:
+ resource_params.SetSkColorType(kRGBA_8888_SkColorType);
+ break;
+ case viz::RGBX_8888:
+ resource_params.SetSkColorType(kRGB_888x_SkColorType);
+ break;
+ case viz::RGBA_F16:
+ resource_params.SetSkColorType(kRGBA_F16_SkColorType);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ return ExternalCanvasResource::Create(
+ out_resource.mailbox_holder.mailbox, std::move(out_release_callback),
+ out_resource.mailbox_holder.sync_token, IntSize(out_resource.size),
+ out_resource.mailbox_holder.texture_target, resource_params,
+ context_provider_->GetWeakPtr(), /*resource_provider=*/nullptr,
+ kLow_SkFilterQuality,
+ /*is_origin_top_left=*/opengl_flip_y_extension_,
+ out_resource.is_overlay_candidate);
}
DrawingBuffer::ColorBuffer::ColorBuffer(
@@ -1667,10 +1706,17 @@ scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer(
// Create a normal SharedImage if GpuMemoryBuffer is not needed or the
// allocation above failed.
if (!gpu_memory_buffer) {
+ // We want to set the correct SkAlphaType on the new shared image but in
+ // the case of ShouldUseChromiumImage() we instead keep this buffer
+ // premultiplied, draw to |premultiplied_alpha_false_mailbox_|, and
+ // convert during copy.
+ SkAlphaType alpha_type = kPremul_SkAlphaType;
+ if (!ShouldUseChromiumImage() && !premultiplied_alpha_)
+ alpha_type = kUnpremul_SkAlphaType;
+
back_buffer_mailbox = sii->CreateSharedImage(
format, static_cast<gfx::Size>(size), storage_color_space_,
- kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
- gpu::kNullSurfaceHandle);
+ kTopLeft_GrSurfaceOrigin, alpha_type, usage, gpu::kNullSurfaceHandle);
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
index c6fc3a8577c..1343ab3a90d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -159,6 +159,8 @@ class PLATFORM_EXPORT DrawingBuffer : public cc::TextureLayerClient,
bool HasDepthBuffer() const { return !!depth_stencil_buffer_; }
bool HasStencilBuffer() const { return !!depth_stencil_buffer_; }
+ bool IsUsingGpuCompositing() const { return using_gpu_compositing_; }
+
// Given the desired buffer size, provides the largest dimensions that will
// fit in the pixel budget.
static IntSize AdjustSize(const IntSize& desired_size,
@@ -281,7 +283,9 @@ class PLATFORM_EXPORT DrawingBuffer : public cc::TextureLayerClient,
bool doing_work_ = false;
};
- scoped_refptr<CanvasResource> AsCanvasResource(
+ scoped_refptr<CanvasResource> ExportCanvasResource();
+
+ scoped_refptr<CanvasResource> ExportLowLatencyCanvasResource(
base::WeakPtr<CanvasResourceProvider> resource_provider);
static const size_t kDefaultColorBufferCacheLimit;
@@ -595,10 +599,8 @@ class PLATFORM_EXPORT DrawingBuffer : public cc::TextureLayerClient,
const bool want_depth_;
const bool want_stencil_;
- // The color space of this buffer's storage, and the color space in which
- // shader samplers will read this buffer.
+ // The color space of this buffer's storage.
const gfx::ColorSpace storage_color_space_;
- const gfx::ColorSpace sampler_color_space_;
AntialiasingMode anti_aliasing_mode_ = kAntialiasingModeNone;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
index ae96ebec2d3..611c6855be5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
@@ -74,6 +74,9 @@ class WebGraphicsContext3DProviderForTests
void CopyVideoFrame(media::PaintCanvasVideoRenderer* video_render,
media::VideoFrame* video_frame,
cc::PaintCanvas* canvas) override {}
+ viz::RasterContextProvider* RasterContextProvider() const override {
+ return nullptr;
+ }
private:
cc::StubDecodeCache image_decode_cache_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index c0f510a463a..4535a22f806 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -39,14 +39,16 @@ scoped_refptr<StaticBitmapImage> MakeAccelerated(
auto paint_image = source->PaintImageForCurrentFrame();
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
source->Size(), kLow_SkFilterQuality,
- CanvasColorParams(paint_image.GetSkImageInfo()),
+ CanvasResourceParams(paint_image.GetSkImageInfo()),
CanvasResourceProvider::ShouldInitialize::kNo, context_provider_wrapper,
RasterMode::kGPU, source->IsOriginTopLeft(),
gpu::SHARED_IMAGE_USAGE_DISPLAY);
if (!provider || !provider->IsAccelerated())
return nullptr;
- provider->Canvas()->drawImage(paint_image, 0, 0, nullptr);
+ cc::PaintFlags paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ provider->Canvas()->drawImage(paint_image, 0, 0, SkSamplingOptions(), &paint);
return provider->Snapshot();
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context_test.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context_test.cc
index c0d4423b525..3c0219a525c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context_test.cc
@@ -193,7 +193,7 @@ TEST_F(BadSharedGpuContextTest, AccelerateImageBufferSurfaceCreationFails) {
IntSize size(10, 10);
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
- size, kLow_SkFilterQuality, CanvasColorParams(),
+ size, kLow_SkFilterQuality, CanvasResourceParams(),
CanvasResourceProvider::ShouldInitialize::kNo,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
true /*is_origin_top_left*/, 0u /*shared_image_usage_flags*/);
@@ -220,7 +220,7 @@ TEST_F(SharedGpuContextTestViz, AccelerateImageBufferSurfaceAutoRecovery) {
IntSize size(10, 10);
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
- size, kLow_SkFilterQuality, CanvasColorParams(),
+ size, kLow_SkFilterQuality, CanvasResourceParams(),
CanvasResourceProvider::ShouldInitialize::kNo,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
true /*is_origin_top_left*/, 0u /*shared_image_usage_flags*/);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
index 3b42e35efb7..8355cb96cb4 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
@@ -3935,7 +3935,7 @@ bool WebGLImageConversion::PackImageData(
}
bool WebGLImageConversion::ExtractImageData(
- const uint8_t* image_data,
+ const void* image_data,
DataFormat source_data_format,
const IntSize& image_data_size,
const IntRect& source_image_sub_rectangle,
@@ -4014,7 +4014,7 @@ bool WebGLImageConversion::ExtractTextureData(
return true;
}
-bool WebGLImageConversion::PackPixels(const uint8_t* source_data,
+bool WebGLImageConversion::PackPixels(const void* source_data,
DataFormat source_data_format,
unsigned source_data_width,
unsigned source_data_height,
@@ -4038,7 +4038,6 @@ bool WebGLImageConversion::PackPixels(const uint8_t* source_data,
remainder ? (valid_src + source_unpack_alignment - remainder) : valid_src;
int src_row_offset =
source_data_sub_rectangle.X() * TexelBytesForFormat(source_data_format);
-
DataFormat dst_data_format =
GetDataFormat(destination_format, destination_type);
if (dst_data_format == kDataFormatNumFormats)
@@ -4056,10 +4055,10 @@ bool WebGLImageConversion::PackPixels(const uint8_t* source_data,
alpha_op = kAlphaDoNothing;
if (source_data_format == dst_data_format && alpha_op == kAlphaDoNothing) {
- const uint8_t* base_ptr =
- source_data + src_stride * source_data_sub_rectangle.Y();
- const uint8_t* base_end =
- source_data + src_stride * source_data_sub_rectangle.MaxY();
+ const uint8_t* base_ptr = static_cast<const uint8_t*>(source_data) +
+ src_stride * source_data_sub_rectangle.Y();
+ const uint8_t* base_end = static_cast<const uint8_t*>(source_data) +
+ src_stride * source_data_sub_rectangle.MaxY();
// If packing multiple images into a 3D texture, and flipY is true,
// then the sub-rectangle is pointing at the start of the
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h
index 6ac0093ee61..9f9155609da 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h
@@ -232,7 +232,7 @@ class PLATFORM_EXPORT WebGLImageConversion final {
// packing the pixel data according to the given format and type,
// and obeying the flipY and premultiplyAlpha flags. Returns true
// upon success.
- static bool ExtractImageData(const uint8_t* image_data,
+ static bool ExtractImageData(const void* image_data,
DataFormat source_data_format,
const IntSize& image_data_size,
const IntRect& source_image_sub_rectangle,
@@ -269,7 +269,7 @@ class PLATFORM_EXPORT WebGLImageConversion final {
// data is tightly packed. Non-zero values may take a slow path. Destination
// data will have no gaps between rows. Implemented in
// GraphicsContext3DImagePacking.cpp.
- static bool PackPixels(const uint8_t* source_data,
+ static bool PackPixels(const void* source_data,
DataFormat source_data_format,
unsigned source_data_width,
unsigned source_data_height,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc
index 03e2f22cde9..3fe8fd7b071 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc
@@ -133,55 +133,4 @@ uint64_t DawnTextureFormatBytesPerPixel(const WGPUTextureFormat color_type) {
}
}
-DawnTextureFromImageBitmap::DawnTextureFromImageBitmap(
- scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id)
- : dawn_control_client_(dawn_control_client),
- device_client_id_(device_client_id) {}
-
-DawnTextureFromImageBitmap::~DawnTextureFromImageBitmap() {
- // Ensure calls to ProduceDawnTextureFromImageBitmap
- // and FinishDawnTextureFromImageBitmapAccess are matched.
- DCHECK_EQ(wire_texture_id_, 0u);
- DCHECK_EQ(wire_texture_generation_, 0u);
-
- device_client_id_ = 0;
- dawn_control_client_.reset();
-}
-
-WGPUTexture DawnTextureFromImageBitmap::ProduceDawnTextureFromImageBitmap(
- scoped_refptr<StaticBitmapImage> image) {
- DCHECK(!dawn_control_client_->IsDestroyed());
-
- associated_resource_ = image->GetMailboxHolder().mailbox;
-
- // Produce and inject image to WebGPU texture
- gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
- gpu::webgpu::ReservedTexture reservation =
- webgpu->ReserveTexture(device_client_id_);
- DCHECK(reservation.texture);
-
- wire_texture_id_ = reservation.id;
- wire_texture_generation_ = reservation.generation;
-
- // This may fail because gl_backing resource cannot produce dawn
- // representation.
- webgpu->AssociateMailbox(device_client_id_, 0, wire_texture_id_,
- wire_texture_generation_, WGPUTextureUsage_CopySrc,
- reinterpret_cast<GLbyte*>(&associated_resource_));
-
- return reservation.texture;
-}
-
-void DawnTextureFromImageBitmap::FinishDawnTextureFromImageBitmapAccess() {
- DCHECK(!dawn_control_client_->IsDestroyed());
- DCHECK_NE(wire_texture_id_, 0u);
-
- gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
- webgpu->DissociateMailbox(device_client_id_, wire_texture_id_,
- wire_texture_generation_);
- wire_texture_id_ = 0;
- wire_texture_generation_ = 0;
- associated_resource_.SetZero();
-}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h
index a7b6f747a45..d90a8a5acfc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h
@@ -8,8 +8,6 @@
#include <dawn/webgpu.h>
#include "base/containers/span.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -36,29 +34,5 @@ CopyBytesFromImageBitmapForWebGPU(scoped_refptr<StaticBitmapImage> image,
uint64_t PLATFORM_EXPORT
DawnTextureFormatBytesPerPixel(const WGPUTextureFormat color_type);
-class PLATFORM_EXPORT DawnTextureFromImageBitmap
- : public RefCounted<DawnTextureFromImageBitmap> {
- public:
- DawnTextureFromImageBitmap(
- scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id);
-
- ~DawnTextureFromImageBitmap();
- WGPUTexture ProduceDawnTextureFromImageBitmap(
- scoped_refptr<StaticBitmapImage> image);
- void FinishDawnTextureFromImageBitmapAccess();
-
- uint32_t GetTextureIdForTest() { return wire_texture_id_; }
- uint32_t GetTextureGenerationForTest() { return wire_texture_generation_; }
- uint64_t GetDeviceClientIdForTest() { return device_client_id_; }
-
- private:
- scoped_refptr<DawnControlClientHolder> dawn_control_client_;
- gpu::Mailbox associated_resource_;
- uint64_t device_client_id_;
- uint32_t wire_texture_id_ = 0;
- uint32_t wire_texture_generation_ = 0;
-};
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_IMAGE_BITMAP_HANDLER_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
index 3ebea4e79ac..7e32260dc2d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h"
-
#include "base/memory/scoped_refptr.h"
#include "base/test/null_task_runner.h"
#include "base/test/task_environment.h"
@@ -16,6 +15,7 @@
#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
@@ -58,12 +58,21 @@ bool GPUUploadingPathSupported() {
class MockWebGPUInterface : public gpu::webgpu::WebGPUInterfaceStub {
public:
+ MockWebGPUInterface() {
+ procs_ = {};
+
+ // WebGPU functions the tests will call. No-op them since we don't have a
+ // real WebGPU device.
+ procs_.deviceReference = [](WGPUDevice) {};
+ procs_.deviceRelease = [](WGPUDevice) {};
+ }
+
MOCK_METHOD(gpu::webgpu::ReservedTexture,
ReserveTexture,
- (uint64_t device_client_id));
+ (WGPUDevice device));
MOCK_METHOD(void,
AssociateMailbox,
- (GLuint64 device_client_id,
+ (GLuint device_id,
GLuint device_generation,
GLuint id,
GLuint generation,
@@ -71,9 +80,12 @@ class MockWebGPUInterface : public gpu::webgpu::WebGPUInterfaceStub {
const GLbyte* mailbox));
MOCK_METHOD(void,
DissociateMailbox,
- (GLuint64 device_client_id,
- GLuint texture_id,
- GLuint texture_generation));
+ (GLuint texture_id, GLuint texture_generation));
+
+ const DawnProcTable& GetProcs() const override { return procs_; }
+
+ private:
+ DawnProcTable procs_;
};
// The six reference pixels are: red, green, blue, white, black.
@@ -348,7 +360,7 @@ TEST_F(WebGPUImageBitmapHandlerTest, VerifyCopyBytesWithPremultiplyAlpha) {
WGPUTextureFormat_RGBA8Unorm);
}
-class DawnTextureFromImageBitmapTest : public testing::Test {
+class WebGPUMailboxTextureTest : public testing::Test {
protected:
void SetUp() override {
auto webgpu = std::make_unique<MockWebGPUInterface>();
@@ -359,9 +371,6 @@ class DawnTextureFromImageBitmapTest : public testing::Test {
dawn_control_client_ =
base::MakeRefCounted<DawnControlClientHolder>(std::move(provider));
- dawn_texture_provider_ = base::MakeRefCounted<DawnTextureFromImageBitmap>(
- dawn_control_client_, 1 /* device_client_id */);
-
test_context_provider_ = viz::TestContextProvider::Create();
InitializeSharedGpuContext(test_context_provider_.get());
}
@@ -369,12 +378,12 @@ class DawnTextureFromImageBitmapTest : public testing::Test {
void TearDown() override { SharedGpuContext::ResetForTesting(); }
MockWebGPUInterface* webgpu_;
scoped_refptr<DawnControlClientHolder> dawn_control_client_;
- scoped_refptr<DawnTextureFromImageBitmap> dawn_texture_provider_;
scoped_refptr<viz::TestContextProvider> test_context_provider_;
base::test::TaskEnvironment task_environment_;
+ WGPUDevice fake_device_ = reinterpret_cast<WGPUDevice>(this);
};
-TEST_F(DawnTextureFromImageBitmapTest, VerifyAccessTexture) {
+TEST_F(WebGPUMailboxTextureTest, VerifyAccessTexture) {
if (!GPUUploadingPathSupported()) {
LOG(ERROR) << "Test skipped because GPU uploading path not supported.";
return;
@@ -383,38 +392,36 @@ TEST_F(DawnTextureFromImageBitmapTest, VerifyAccessTexture) {
viz::TransferableResource resource;
gpu::webgpu::ReservedTexture reservation = {
- reinterpret_cast<WGPUTexture>(&resource), 1, 1};
+ reinterpret_cast<WGPUTexture>(&resource), 1, 1, /* deviceId */ 2,
+ /* deviceGeneration */ 3};
- // Test that ProduceDawnTextureFromImageBitmap calls ReserveTexture and
+ // Test creating a WebGPUMailboxTexture calls ReserveTexture and
// AssociateMailbox correctly.
- const GLbyte* mailbox_bytes = nullptr;
-
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation));
- EXPECT_CALL(*webgpu_, AssociateMailbox(
- dawn_texture_provider_->GetDeviceClientIdForTest(),
- _, reservation.id, reservation.generation,
- WGPUTextureUsage_CopySrc, _))
- .WillOnce(testing::SaveArg<5>(&mailbox_bytes));
-
- WGPUTexture texture =
- dawn_texture_provider_->ProduceDawnTextureFromImageBitmap(bitmap);
-
- gpu::Mailbox mailbox = gpu::Mailbox::FromVolatile(
- *reinterpret_cast<const volatile gpu::Mailbox*>(mailbox_bytes));
+ gpu::Mailbox mailbox;
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation));
+ EXPECT_CALL(*webgpu_,
+ AssociateMailbox(2, 3, reservation.id, reservation.generation,
+ WGPUTextureUsage_CopySrc, _))
+ .WillOnce(
+ testing::Invoke(testing::WithArg<5>([&](const GLbyte* mailbox_bytes) {
+ mailbox = gpu::Mailbox::FromVolatile(
+ *reinterpret_cast<const volatile gpu::Mailbox*>(mailbox_bytes));
+ })));
+
+ scoped_refptr<WebGPUMailboxTexture> mailbox_texture =
+ WebGPUMailboxTexture::FromStaticBitmapImage(
+ dawn_control_client_, fake_device_, WGPUTextureUsage_CopySrc, bitmap);
EXPECT_TRUE(mailbox == bitmap->GetMailboxHolder().mailbox);
- EXPECT_NE(texture, nullptr);
- EXPECT_EQ(dawn_texture_provider_->GetTextureIdForTest(), 1u);
- EXPECT_EQ(dawn_texture_provider_->GetTextureGenerationForTest(), 1u);
+ EXPECT_NE(mailbox_texture->GetTexture(), nullptr);
+ EXPECT_EQ(mailbox_texture->GetTextureIdForTest(), 1u);
+ EXPECT_EQ(mailbox_texture->GetTextureGenerationForTest(), 1u);
- // Test that FinishDawnTextureFromImageBitmapAccess calls DissociateMailbox
+ // Test that ~WebGPUMailboxTexture calls DissociateMailbox
// correctly.
EXPECT_CALL(*webgpu_, DissociateMailbox(
- dawn_texture_provider_->GetDeviceClientIdForTest(),
reservation.id, reservation.generation));
-
- dawn_texture_provider_->FinishDawnTextureFromImageBitmapAccess();
-
- EXPECT_EQ(dawn_texture_provider_->GetTextureIdForTest(), 0u);
+ mailbox_texture.reset();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
new file mode 100644
index 00000000000..915f3403cc8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
@@ -0,0 +1,93 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
+
+#include "gpu/command_buffer/client/webgpu_interface.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
+
+namespace blink {
+
+// static
+scoped_refptr<WebGPUMailboxTexture> WebGPUMailboxTexture::FromStaticBitmapImage(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ scoped_refptr<StaticBitmapImage> image) {
+ DCHECK(image->IsTextureBacked());
+ auto finished_access_callback =
+ WTF::Bind(&StaticBitmapImage::UpdateSyncToken, WTF::RetainedRef(image));
+
+ return base::AdoptRef(new WebGPUMailboxTexture(
+ std::move(dawn_control_client), device, usage,
+ image->GetMailboxHolder().mailbox, image->GetMailboxHolder().sync_token,
+ std::move(finished_access_callback)));
+}
+
+// static
+scoped_refptr<WebGPUMailboxTexture> WebGPUMailboxTexture::FromCanvasResource(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ scoped_refptr<CanvasResource> canvas_resource) {
+ auto finished_access_callback = WTF::Bind(&CanvasResource::WaitSyncToken,
+ WTF::RetainedRef(canvas_resource));
+
+ const gpu::Mailbox& mailbox =
+ canvas_resource->GetOrCreateGpuMailbox(kUnverifiedSyncToken);
+ gpu::SyncToken sync_token = canvas_resource->GetSyncToken();
+ return base::AdoptRef(new WebGPUMailboxTexture(
+ std::move(dawn_control_client), device, usage, mailbox, sync_token,
+ std::move(finished_access_callback)));
+}
+
+WebGPUMailboxTexture::WebGPUMailboxTexture(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ base::OnceCallback<void(const gpu::SyncToken&)> destroy_callback)
+ : dawn_control_client_(std::move(dawn_control_client)),
+ device_(device),
+ destroy_callback_(std::move(destroy_callback)) {
+ dawn_control_client_->GetProcs().deviceReference(device_);
+
+ gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
+
+ // Wait on any work using the image.
+ webgpu->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+
+ // Produce and inject image to WebGPU texture
+ gpu::webgpu::ReservedTexture reservation = webgpu->ReserveTexture(device_);
+ DCHECK(reservation.texture);
+
+ wire_texture_id_ = reservation.id;
+ wire_texture_generation_ = reservation.generation;
+ texture_ = reservation.texture;
+
+ // This may fail because gl_backing resource cannot produce dawn
+ // representation.
+ webgpu->AssociateMailbox(reservation.deviceId, reservation.deviceGeneration,
+ wire_texture_id_, wire_texture_generation_, usage,
+ reinterpret_cast<const GLbyte*>(&mailbox));
+}
+
+WebGPUMailboxTexture::~WebGPUMailboxTexture() {
+ DCHECK_NE(wire_texture_id_, 0u);
+
+ gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
+ webgpu->DissociateMailbox(wire_texture_id_, wire_texture_generation_);
+
+ if (destroy_callback_) {
+ gpu::SyncToken finished_access_token;
+ webgpu->GenUnverifiedSyncTokenCHROMIUM(finished_access_token.GetData());
+ std::move(destroy_callback_).Run(finished_access_token);
+ }
+
+ dawn_control_client_->GetProcs().deviceRelease(device_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h
new file mode 100644
index 00000000000..73d181cbdcb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h
@@ -0,0 +1,63 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_MAILBOX_TEXTURE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_MAILBOX_TEXTURE_H_
+
+#include <dawn/webgpu.h>
+
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+
+namespace blink {
+
+class CanvasResource;
+class DawnControlClientHolder;
+class StaticBitmapImage;
+
+class PLATFORM_EXPORT WebGPUMailboxTexture
+ : public RefCounted<WebGPUMailboxTexture> {
+ public:
+ static scoped_refptr<WebGPUMailboxTexture> FromStaticBitmapImage(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ scoped_refptr<StaticBitmapImage> image);
+
+ static scoped_refptr<WebGPUMailboxTexture> FromCanvasResource(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ scoped_refptr<CanvasResource> canvas_resource);
+
+ ~WebGPUMailboxTexture();
+
+ WGPUTexture GetTexture() { return texture_; }
+ uint32_t GetTextureIdForTest() { return wire_texture_id_; }
+ uint32_t GetTextureGenerationForTest() { return wire_texture_generation_; }
+ WGPUDevice GetDeviceForTest() { return device_; }
+
+ private:
+ WebGPUMailboxTexture(
+ scoped_refptr<DawnControlClientHolder> dawn_control_client,
+ WGPUDevice device,
+ WGPUTextureUsage usage,
+ const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ base::OnceCallback<void(const gpu::SyncToken&)> destroy_callback);
+
+ scoped_refptr<DawnControlClientHolder> dawn_control_client_;
+ WGPUDevice device_;
+ base::OnceCallback<void(const gpu::SyncToken&)> destroy_callback_;
+ WGPUTexture texture_;
+ uint32_t wire_texture_id_ = 0;
+ uint32_t wire_texture_generation_ = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_MAILBOX_TEXTURE_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
index 36a691b98c7..6f3878ac979 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -29,12 +29,12 @@ viz::ResourceFormat WGPUFormatToViz(WGPUTextureFormat format) {
WebGPUSwapBufferProvider::WebGPUSwapBufferProvider(
Client* client,
scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id,
+ WGPUDevice device,
WGPUTextureUsage usage,
WGPUTextureFormat format)
: dawn_control_client_(dawn_control_client),
client_(client),
- device_client_id_(device_client_id),
+ device_(device),
usage_(usage),
format_(WGPUFormatToViz(format)) {
// Create a layer that will be used by the canvas and will ask for a
@@ -50,10 +50,14 @@ WebGPUSwapBufferProvider::WebGPUSwapBufferProvider(
// paths to keep the rendering correct in that cases.
layer_->SetContentsOpaque(true);
layer_->SetPremultipliedAlpha(true);
+
+ dawn_control_client_->GetProcs().deviceReference(device_);
}
WebGPUSwapBufferProvider::~WebGPUSwapBufferProvider() {
Neuter();
+ dawn_control_client_->GetProcs().deviceRelease(device_);
+ device_ = nullptr;
}
cc::Layer* WebGPUSwapBufferProvider::CcLayer() {
@@ -78,7 +82,7 @@ void WebGPUSwapBufferProvider::Neuter() {
layer_ = nullptr;
}
- if (current_swap_buffer_ && !dawn_control_client_->IsDestroyed()) {
+ if (current_swap_buffer_) {
// Ensure we wait for previous WebGPU commands before destroying the shared
// image.
gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
@@ -92,7 +96,7 @@ void WebGPUSwapBufferProvider::Neuter() {
}
WGPUTexture WebGPUSwapBufferProvider::GetNewTexture(const IntSize& size) {
- DCHECK(!current_swap_buffer_ && !dawn_control_client_->IsDestroyed());
+ DCHECK(!current_swap_buffer_);
gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
gpu::SharedImageInterface* sii =
@@ -117,14 +121,14 @@ WGPUTexture WebGPUSwapBufferProvider::GetNewTexture(const IntSize& size) {
current_swap_buffer_->access_finished_token.GetConstData());
// Associate the mailbox to a dawn_wire client DawnTexture object
- gpu::webgpu::ReservedTexture reservation =
- webgpu->ReserveTexture(device_client_id_);
+ gpu::webgpu::ReservedTexture reservation = webgpu->ReserveTexture(device_);
DCHECK(reservation.texture);
wire_texture_id_ = reservation.id;
wire_texture_generation_ = reservation.generation;
webgpu->AssociateMailbox(
- device_client_id_, 0, reservation.id, reservation.generation, usage_,
+ reservation.deviceId, reservation.deviceGeneration, reservation.id,
+ reservation.generation, usage_,
reinterpret_cast<GLbyte*>(&current_swap_buffer_->mailbox));
// When the page request a texture it means we'll need to present it on the
@@ -138,8 +142,7 @@ bool WebGPUSwapBufferProvider::PrepareTransferableResource(
cc::SharedBitmapIdRegistrar* bitmap_registrar,
viz::TransferableResource* out_resource,
std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) {
- DCHECK(!neutered_ && !dawn_control_client_->IsDestroyed());
-
+ DCHECK(!neutered_);
if (!current_swap_buffer_ || neutered_) {
return false;
}
@@ -152,8 +155,7 @@ bool WebGPUSwapBufferProvider::PrepareTransferableResource(
// to the texture are errors.
gpu::webgpu::WebGPUInterface* webgpu = dawn_control_client_->GetInterface();
DCHECK_NE(wire_texture_id_, 0u);
- webgpu->DissociateMailbox(device_client_id_, wire_texture_id_,
- wire_texture_generation_);
+ webgpu->DissociateMailbox(wire_texture_id_, wire_texture_generation_);
// Make the compositor wait on previous Dawn commands.
webgpu->GenUnverifiedSyncTokenCHROMIUM(
@@ -213,9 +215,6 @@ WebGPUSwapBufferProvider::SwapBuffer::SwapBuffer(
access_finished_token(creation_token) {}
WebGPUSwapBufferProvider::SwapBuffer::~SwapBuffer() {
- if (swap_buffers->dawn_control_client_->IsDestroyed()) {
- return;
- }
gpu::SharedImageInterface* sii =
swap_buffers->dawn_control_client_->GetContextProvider()
->SharedImageInterface();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
index 4927c03ece5..e30ef00dfe3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -35,7 +35,7 @@ class PLATFORM_EXPORT WebGPUSwapBufferProvider
WebGPUSwapBufferProvider(
Client* client,
scoped_refptr<DawnControlClientHolder> dawn_control_client,
- uint64_t device_client_id,
+ WGPUDevice device,
WGPUTextureUsage usage,
WGPUTextureFormat format);
~WebGPUSwapBufferProvider() override;
@@ -83,7 +83,7 @@ class PLATFORM_EXPORT WebGPUSwapBufferProvider
scoped_refptr<DawnControlClientHolder> dawn_control_client_;
Client* client_;
- uint64_t device_client_id_;
+ WGPUDevice device_;
scoped_refptr<cc::TextureLayer> layer_;
bool neutered_ = false;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
index 19100740ef6..48d46ec5f3f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -19,8 +19,16 @@ namespace {
class MockWebGPUInterface : public gpu::webgpu::WebGPUInterfaceStub {
public:
- MOCK_METHOD1(ReserveTexture,
- gpu::webgpu::ReservedTexture(uint64_t device_client_id));
+ MockWebGPUInterface() {
+ procs_ = {};
+
+ // WebGPU functions the tests will call. No-op them since we don't have a
+ // real WebGPU device.
+ procs_.deviceReference = [](WGPUDevice) {};
+ procs_.deviceRelease = [](WGPUDevice) {};
+ }
+
+ MOCK_METHOD1(ReserveTexture, gpu::webgpu::ReservedTexture(WGPUDevice device));
// It is hard to use GMock with SyncTokens represented as GLByte*, instead we
// remember which were the last sync tokens generated or waited upon.
@@ -41,10 +49,14 @@ class MockWebGPUInterface : public gpu::webgpu::WebGPUInterfaceStub {
void WaitSyncTokenCHROMIUM(const GLbyte* sync_token_data) override {
memcpy(&most_recent_waited_token, sync_token_data, sizeof(gpu::SyncToken));
}
+
+ const DawnProcTable& GetProcs() const override { return procs_; }
+
gpu::SyncToken most_recent_generated_token;
gpu::SyncToken most_recent_waited_token;
private:
+ DawnProcTable procs_;
uint64_t token_id_ = 42;
};
@@ -58,13 +70,13 @@ class WebGPUSwapBufferProviderForTests : public WebGPUSwapBufferProvider {
WebGPUSwapBufferProviderForTests(
bool* alive,
Client* client,
- uint64_t client_device_id_,
+ WGPUDevice device,
scoped_refptr<DawnControlClientHolder> dawn_control_client,
WGPUTextureUsage usage,
WGPUTextureFormat format)
: WebGPUSwapBufferProvider(client,
dawn_control_client,
- client_device_id_,
+ device,
usage,
format),
alive_(alive) {}
@@ -89,9 +101,8 @@ class WebGPUSwapBufferProviderTest : public testing::Test {
dawn_control_client_ =
base::MakeRefCounted<DawnControlClientHolder>(std::move(provider));
- static const uint64_t kDeviceClientID = 1;
provider_ = base::MakeRefCounted<WebGPUSwapBufferProviderForTests>(
- &provider_alive_, &client_, kDeviceClientID, dawn_control_client_,
+ &provider_alive_, &client_, fake_device_, dawn_control_client_,
WGPUTextureUsage_OutputAttachment, WGPUTextureFormat_RGBA8Unorm);
}
@@ -101,6 +112,7 @@ class WebGPUSwapBufferProviderTest : public testing::Test {
FakeProviderClient client_;
scoped_refptr<WebGPUSwapBufferProviderForTests> provider_;
bool provider_alive_ = true;
+ WGPUDevice fake_device_ = reinterpret_cast<WGPUDevice>(this);
};
TEST_F(WebGPUSwapBufferProviderTest,
@@ -123,17 +135,20 @@ TEST_F(WebGPUSwapBufferProviderTest,
std::unique_ptr<viz::SingleReleaseCallback> release_callback3;
// Produce resources.
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation1));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation1));
provider_->GetNewTexture(kSize);
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource1,
&release_callback1));
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation2));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation2));
provider_->GetNewTexture(kSize);
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource2,
&release_callback2));
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation3));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation3));
provider_->GetNewTexture(kSize);
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource3,
&release_callback3));
@@ -161,7 +176,8 @@ TEST_F(WebGPUSwapBufferProviderTest, VerifyResizingProperlyAffectsResources) {
std::unique_ptr<viz::SingleReleaseCallback> release_callback;
// Produce one resource of size kSize.
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation));
provider_->GetNewTexture(static_cast<IntSize>(kSize));
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
&release_callback));
@@ -169,7 +185,8 @@ TEST_F(WebGPUSwapBufferProviderTest, VerifyResizingProperlyAffectsResources) {
release_callback->Run(gpu::SyncToken(), false /* lostResource */);
// Produce one resource of size kOtherSize.
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation));
provider_->GetNewTexture(static_cast<IntSize>(kOtherSize));
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
&release_callback));
@@ -177,7 +194,8 @@ TEST_F(WebGPUSwapBufferProviderTest, VerifyResizingProperlyAffectsResources) {
release_callback->Run(gpu::SyncToken(), false /* lostResource */);
// Produce one resource of size kSize again.
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation));
provider_->GetNewTexture(static_cast<IntSize>(kSize));
EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
&release_callback));
@@ -195,7 +213,8 @@ TEST_F(WebGPUSwapBufferProviderTest, VerifyInsertAndWaitSyncTokenCorrectly) {
// Produce the first resource, check that WebGPU will wait for the creation of
// the shared image
- EXPECT_CALL(*webgpu_, ReserveTexture(_)).WillOnce(Return(reservation));
+ EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+ .WillOnce(Return(reservation));
provider_->GetNewTexture(static_cast<IntSize>(kSize));
EXPECT_EQ(sii_->MostRecentGeneratedToken(),
webgpu_->most_recent_waited_token);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
index 761e65b2101..389f524ec71 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
#include "ui/gfx/gpu_fence.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.cc b/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.cc
index dbd7b216fc2..0e44fa9a12e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.cc
@@ -35,6 +35,7 @@ void GradientGeneratedImage::Draw(cc::PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) {
@@ -43,8 +44,7 @@ void GradientGeneratedImage::Draw(cc::PaintCanvas* canvas,
SkRect::MakeWH(size_.Width(), size_.Height())))
return;
- const SkMatrix transform =
- SkMatrix::MakeRectToRect(src_rect, dest_rect, SkMatrix::kFill_ScaleToFit);
+ const SkMatrix transform = SkMatrix::RectToRect(src_rect, dest_rect);
SkRect visible_dest_rect;
transform.mapRect(&visible_dest_rect, visible_src_rect);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.h b/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
index 1467cd0514a..5a5aeb8054f 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
@@ -50,6 +50,7 @@ class PLATFORM_EXPORT GradientGeneratedImage final : public GeneratedImage {
const PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 048a43be1e3..11c70b635b9 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -117,25 +117,8 @@ class GraphicsContext::DarkModeFlags final {
base::Optional<PaintFlags> dark_mode_flags_;
};
-GraphicsContext::GraphicsContext(PaintController& paint_controller,
- printing::MetafileSkia* metafile,
- paint_preview::PaintPreviewTracker* tracker)
- : canvas_(nullptr),
- paint_controller_(paint_controller),
- paint_state_stack_(),
- paint_state_index_(0),
- metafile_(metafile),
- tracker_(tracker),
-#if DCHECK_IS_ON()
- layer_count_(0),
- disable_destruction_checks_(false),
-#endif
- device_scale_factor_(1.0f),
- dark_mode_filter_(nullptr),
- printing_(false),
- is_painting_preview_(false),
- in_drawing_recorder_(false),
- is_dark_mode_enabled_(false) {
+GraphicsContext::GraphicsContext(PaintController& paint_controller)
+ : paint_controller_(paint_controller) {
// FIXME: Do some tests to determine how many states are typically used, and
// allocate several here.
paint_state_stack_.push_back(std::make_unique<GraphicsContextState>());
@@ -153,6 +136,14 @@ GraphicsContext::~GraphicsContext() {
#endif
}
+void GraphicsContext::CopyConfigFrom(GraphicsContext& other) {
+ SetPrintingMetafile(other.printing_metafile_);
+ SetPaintPreviewTracker(other.paint_preview_tracker_);
+ SetDarkModeEnabled(other.is_dark_mode_enabled_);
+ SetDeviceScaleFactor(other.device_scale_factor_);
+ SetPrinting(other.printing_);
+}
+
DarkModeFilter* GraphicsContext::GetDarkModeFilter() {
if (!dark_mode_filter_) {
dark_mode_filter_ =
@@ -221,6 +212,7 @@ void GraphicsContext::SetInDrawingRecorder(bool val) {
}
void GraphicsContext::SetDOMNodeId(DOMNodeId new_node_id) {
+ DCHECK(NeedsDOMNodeId());
if (canvas_)
canvas_->setNodeId(new_node_id);
@@ -228,35 +220,10 @@ void GraphicsContext::SetDOMNodeId(DOMNodeId new_node_id) {
}
DOMNodeId GraphicsContext::GetDOMNodeId() const {
+ DCHECK(NeedsDOMNodeId());
return dom_node_id_;
}
-void GraphicsContext::SetShadow(
- const FloatSize& offset,
- float blur,
- const Color& color,
- DrawLooperBuilder::ShadowTransformMode shadow_transform_mode,
- DrawLooperBuilder::ShadowAlphaMode shadow_alpha_mode,
- ShadowMode shadow_mode) {
- DrawLooperBuilder draw_looper_builder;
- if (!color.Alpha()) {
- // When shadow-only but there is no shadow, we use an empty draw looper
- // to disable rendering of the source primitive. When not shadow-only, we
- // clear the looper.
- SetDrawLooper(shadow_mode != kDrawShadowOnly
- ? nullptr
- : draw_looper_builder.DetachDrawLooper());
- return;
- }
-
- draw_looper_builder.AddShadow(offset, blur, color, shadow_transform_mode,
- shadow_alpha_mode);
- if (shadow_mode == kDrawShadowAndForeground) {
- draw_looper_builder.AddUnmodifiedContent();
- }
- SetDrawLooper(draw_looper_builder.DetachDrawLooper());
-}
-
void GraphicsContext::SetDrawLooper(sk_sp<SkDrawLooper> draw_looper) {
MutableState()->SetDrawLooper(std::move(draw_looper));
}
@@ -315,10 +282,10 @@ void GraphicsContext::EndLayer() {
void GraphicsContext::BeginRecording(const FloatRect& bounds) {
DCHECK(!canvas_);
canvas_ = paint_recorder_.beginRecording(bounds);
- if (metafile_)
- canvas_->SetPrintingMetafile(metafile_);
- if (tracker_)
- canvas_->SetPaintPreviewTracker(tracker_);
+ if (printing_metafile_)
+ canvas_->SetPrintingMetafile(printing_metafile_);
+ if (paint_preview_tracker_)
+ canvas_->SetPaintPreviewTracker(paint_preview_tracker_);
}
sk_sp<PaintRecord> GraphicsContext::EndRecording() {
@@ -346,17 +313,17 @@ void GraphicsContext::CompositeRecord(sk_sp<PaintRecord> record,
PaintFlags flags;
flags.setBlendMode(op);
- flags.setFilterQuality(
- static_cast<SkFilterQuality>(ImageInterpolationQuality()));
+ SkSamplingOptions sampling(
+ static_cast<SkFilterQuality>(ImageInterpolationQuality()),
+ SkSamplingOptions::kMedium_asMipmapLinear);
canvas_->save();
- canvas_->concat(
- SkMatrix::MakeRectToRect(src, dest, SkMatrix::kFill_ScaleToFit));
+ canvas_->concat(SkMatrix::RectToRect(src, dest));
canvas_->drawImage(PaintImageBuilder::WithDefault()
.set_paint_record(record, RoundedIntRect(src),
PaintImage::GetNextContentId())
.set_id(PaintImage::GetNextId())
.TakePaintImage(),
- 0, 0, &flags);
+ 0, 0, sampling, &flags);
canvas_->restore();
}
@@ -462,9 +429,7 @@ void GraphicsContext::DrawFocusRing(const Vector<IntRect>& rects,
const Color& color,
mojom::blink::ColorScheme color_scheme) {
#if defined(OS_MAC)
- const Color& inner_color = color_scheme == mojom::blink::ColorScheme::kDark
- ? SkColorSetRGB(0x99, 0xC8, 0xFF)
- : color;
+ const Color& inner_color = color;
#else
const Color& inner_color =
color_scheme == mojom::blink::ColorScheme::kDark ? SK_ColorWHITE : color;
@@ -494,84 +459,6 @@ void GraphicsContext::DrawFocusRing(const Vector<IntRect>& rects,
}
}
-static inline FloatRect AreaCastingShadowInHole(
- const FloatRect& hole_rect,
- float shadow_blur,
- float shadow_spread,
- const FloatSize& shadow_offset) {
- FloatRect bounds(hole_rect);
-
- bounds.Inflate(shadow_blur);
-
- if (shadow_spread < 0)
- bounds.Inflate(-shadow_spread);
-
- FloatRect offset_bounds = bounds;
- offset_bounds.Move(-shadow_offset);
- return UnionRect(bounds, offset_bounds);
-}
-
-void GraphicsContext::DrawInnerShadow(const FloatRoundedRect& rect,
- const Color& orig_shadow_color,
- const FloatSize& shadow_offset,
- float shadow_blur,
- float shadow_spread,
- Edges clipped_edges) {
- SkColor shadow_color = DarkModeFilterHelper::ApplyToColorIfNeeded(
- this, orig_shadow_color.Rgb(), DarkModeFilter::ElementRole::kBackground);
-
- FloatRect hole_rect(rect.Rect());
- hole_rect.Inflate(-shadow_spread);
-
- if (hole_rect.IsEmpty()) {
- FillRoundedRect(rect, Color(shadow_color));
- return;
- }
-
- if (clipped_edges & kLeftEdge) {
- hole_rect.Move(-std::max(shadow_offset.Width(), 0.0f) - shadow_blur, 0);
- hole_rect.SetWidth(hole_rect.Width() +
- std::max(shadow_offset.Width(), 0.0f) + shadow_blur);
- }
- if (clipped_edges & kTopEdge) {
- hole_rect.Move(0, -std::max(shadow_offset.Height(), 0.0f) - shadow_blur);
- hole_rect.SetHeight(hole_rect.Height() +
- std::max(shadow_offset.Height(), 0.0f) + shadow_blur);
- }
- if (clipped_edges & kRightEdge)
- hole_rect.SetWidth(hole_rect.Width() -
- std::min(shadow_offset.Width(), 0.0f) + shadow_blur);
- if (clipped_edges & kBottomEdge)
- hole_rect.SetHeight(hole_rect.Height() -
- std::min(shadow_offset.Height(), 0.0f) + shadow_blur);
-
- Color fill_color(SkColorGetR(shadow_color), SkColorGetG(shadow_color),
- SkColorGetB(shadow_color), 255);
-
- FloatRect outer_rect = AreaCastingShadowInHole(rect.Rect(), shadow_blur,
- shadow_spread, shadow_offset);
- FloatRoundedRect rounded_hole(hole_rect, rect.GetRadii());
-
- GraphicsContextStateSaver state_saver(*this);
- if (rect.IsRounded()) {
- ClipRoundedRect(rect);
- if (shadow_spread < 0)
- rounded_hole.ExpandRadii(-shadow_spread);
- else
- rounded_hole.ShrinkRadii(shadow_spread);
- } else {
- Clip(rect.Rect());
- }
-
- DrawLooperBuilder draw_looper_builder;
- draw_looper_builder.AddShadow(FloatSize(shadow_offset), shadow_blur,
- shadow_color,
- DrawLooperBuilder::kShadowRespectsTransforms,
- DrawLooperBuilder::kShadowIgnoresAlpha);
- SetDrawLooper(draw_looper_builder.DetachDrawLooper());
- FillRectWithRoundedHole(outer_rect, rounded_hole, fill_color);
-}
-
static void EnforceDotsAtEndpoints(GraphicsContext& context,
FloatPoint& p1,
FloatPoint& p2,
@@ -891,7 +778,6 @@ void GraphicsContext::DrawImage(
PaintFlags image_flags = ImmutableState()->FillFlags();
image_flags.setBlendMode(op);
image_flags.setColor(SK_ColorBLACK);
- image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
// Do not classify the image if the element has any CSS filters.
if (!has_filter_property) {
@@ -899,8 +785,10 @@ void GraphicsContext::DrawImage(
dest);
}
- image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
- Image::kClampImageToSourceRect, decode_mode);
+ image->Draw(canvas_, image_flags, dest, src,
+ ComputeSamplingOptions(image, dest, src),
+ should_respect_image_orientation, Image::kClampImageToSourceRect,
+ decode_mode);
paint_controller_.SetImagePainted();
}
@@ -928,11 +816,11 @@ void GraphicsContext::DrawImageRRect(
if (dest.IsEmpty() || visible_src.IsEmpty())
return;
+ SkSamplingOptions sampling =
+ ComputeSamplingOptions(image, dest.Rect(), src_rect);
PaintFlags image_flags = ImmutableState()->FillFlags();
image_flags.setBlendMode(op);
image_flags.setColor(SK_ColorBLACK);
- image_flags.setFilterQuality(
- ComputeFilterQuality(image, dest.Rect(), src_rect));
DarkModeFilterHelper::ApplyToImageIfNeeded(this, image, &image_flags,
src_rect, dest.Rect());
@@ -941,19 +829,24 @@ void GraphicsContext::DrawImageRRect(
(respect_orientation == kDoNotRespectImageOrientation ||
image->HasDefaultOrientation());
if (use_shader) {
- const SkMatrix local_matrix = SkMatrix::MakeRectToRect(
- visible_src, dest.Rect(), SkMatrix::kFill_ScaleToFit);
+ const SkMatrix local_matrix =
+ SkMatrix::RectToRect(visible_src, dest.Rect());
use_shader = image->ApplyShader(image_flags, local_matrix);
}
if (use_shader) {
+ // Temporarily set filter-quality for the shader. <reed>
+ // Should be replaced with explicit sampling parameter passed to
+ // ApplyShader()
+ image_flags.setFilterQuality(
+ ComputeFilterQuality(image, dest.Rect(), src_rect));
// Shader-based fast path.
canvas_->drawRRect(dest, image_flags);
} else {
// Clip-based fallback.
PaintCanvasAutoRestore auto_restore(canvas_, true);
canvas_->clipRRect(dest, image_flags.isAntiAlias());
- image->Draw(canvas_, image_flags, dest.Rect(), src_rect,
+ image->Draw(canvas_, image_flags, dest.Rect(), src_rect, sampling,
respect_orientation, Image::kClampImageToSourceRect,
decode_mode);
}
@@ -966,7 +859,7 @@ SkFilterQuality GraphicsContext::ComputeFilterQuality(
const FloatRect& dest,
const FloatRect& src) const {
InterpolationQuality resampling;
- if (Printing()) {
+ if (printing_) {
resampling = kInterpolationNone;
} else if (image->CurrentFrameIsLazyDecoded()) {
resampling = kInterpolationDefault;
@@ -1162,6 +1055,16 @@ void GraphicsContext::FillDRRect(const FloatRoundedRect& outer,
canvas_->drawRRect(stroke_r_rect, stroke_flags);
}
+void GraphicsContext::FillRectWithRoundedHole(
+ const FloatRect& rect,
+ const FloatRoundedRect& rounded_hole_rect,
+ const Color& color) {
+ PaintFlags flags(ImmutableState()->FillFlags());
+ flags.setColor(DarkModeFilterHelper::ApplyToColorIfNeeded(
+ this, color.Rgb(), DarkModeFilter::ElementRole::kBackground));
+ canvas_->drawDRRect(SkRRect::MakeRect(rect), rounded_hole_rect, flags);
+}
+
void GraphicsContext::FillEllipse(const FloatRect& ellipse) {
DrawOval(ellipse, ImmutableState()->FillFlags());
}
@@ -1292,7 +1195,7 @@ void GraphicsContext::SetURLDestinationLocation(const String& name,
DCHECK(canvas_);
// Paint previews don't make use of linked destinations.
- if (tracker_)
+ if (paint_preview_tracker_)
return;
SkRect rect = SkRect::MakeXYWH(location.X(), location.Y(), 0, 0);
@@ -1305,16 +1208,6 @@ void GraphicsContext::ConcatCTM(const AffineTransform& affine) {
Concat(AffineTransformToSkMatrix(affine));
}
-void GraphicsContext::FillRectWithRoundedHole(
- const FloatRect& rect,
- const FloatRoundedRect& rounded_hole_rect,
- const Color& color) {
- PaintFlags flags(ImmutableState()->FillFlags());
- flags.setColor(DarkModeFilterHelper::ApplyToColorIfNeeded(
- this, color.Rgb(), DarkModeFilter::ElementRole::kBackground));
- canvas_->drawDRRect(SkRRect::MakeRect(rect), rounded_hole_rect, flags);
-}
-
void GraphicsContext::AdjustLineToPixelBoundaries(FloatPoint& p1,
FloatPoint& p2,
float stroke_width) {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
index 004ea91d3cf..94ab958545a 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -71,12 +71,21 @@ class PLATFORM_EXPORT GraphicsContext {
USING_FAST_MALLOC(GraphicsContext);
public:
- explicit GraphicsContext(PaintController&,
- printing::MetafileSkia* = nullptr,
- paint_preview::PaintPreviewTracker* = nullptr);
-
+ explicit GraphicsContext(PaintController&);
~GraphicsContext();
+ // Copy configs such as printing, dark mode, device scale factor etc. from
+ // another GraphicsContext.
+ void CopyConfigFrom(GraphicsContext&);
+
+ void SetPrintingMetafile(printing::MetafileSkia* metafile) {
+ printing_metafile_ = metafile;
+ }
+
+ void SetPaintPreviewTracker(paint_preview::PaintPreviewTracker* tracker) {
+ paint_preview_tracker_ = tracker;
+ }
+
cc::PaintCanvas* Canvas() { return canvas_; }
const cc::PaintCanvas* Canvas() const { return canvas_; }
@@ -148,30 +157,21 @@ class PLATFORM_EXPORT GraphicsContext {
return ImmutableState()->GetInterpolationQuality();
}
+ SkSamplingOptions ImageSamplingOptions() const {
+ return SkSamplingOptions(
+ static_cast<SkFilterQuality>(ImageInterpolationQuality()),
+ SkSamplingOptions::kMedium_asMipmapLinear);
+ }
+
// Specify the device scale factor which may change the way document markers
// and fonts are rendered.
void SetDeviceScaleFactor(float factor) { device_scale_factor_ = factor; }
float DeviceScaleFactor() const { return device_scale_factor_; }
- // Returns if the context is a printing context instead of a display
- // context. Bitmap shouldn't be resampled when printing to keep the best
- // possible quality.
- bool Printing() const { return printing_; }
+ // Set to true if context is for printing. Bitmaps won't be resampled when
+ // printing to keep the best possible quality.
void SetPrinting(bool printing) { printing_ = printing; }
- // Returns if the context is saving a paint preview instead of displaying.
- // In such cases, clipping should not occur.
- bool IsPaintingPreview() const { return is_painting_preview_; }
- void SetIsPaintingPreview(bool is_painting_preview) {
- is_painting_preview_ = is_painting_preview;
- }
-
- // Returns if the context is printing or painting a preview. Many of the
- // behaviors required for printing and paint previews are shared.
- bool IsPrintingOrPaintingPreview() const {
- return Printing() || IsPaintingPreview();
- }
-
SkColorFilter* GetColorFilter() const;
void SetColorFilter(ColorFilter);
// ---------- End state management methods -----------------
@@ -221,6 +221,9 @@ class PLATFORM_EXPORT GraphicsContext {
void FillDRRect(const FloatRoundedRect&,
const FloatRoundedRect&,
const Color&);
+ void FillRectWithRoundedHole(const FloatRect&,
+ const FloatRoundedRect& rounded_hole_rect,
+ const Color&);
void StrokeRect(const FloatRect&, float line_width);
@@ -351,15 +354,6 @@ class PLATFORM_EXPORT GraphicsContext {
// not necessarily non-empty), even when the context is disabled.
sk_sp<PaintRecord> EndRecording();
- void SetShadow(const FloatSize& offset,
- float blur,
- const Color&,
- DrawLooperBuilder::ShadowTransformMode =
- DrawLooperBuilder::kShadowRespectsTransforms,
- DrawLooperBuilder::ShadowAlphaMode =
- DrawLooperBuilder::kShadowRespectsAlpha,
- ShadowMode = kDrawShadowAndForeground);
-
void SetDrawLooper(sk_sp<SkDrawLooper>);
void DrawFocusRing(const Vector<IntRect>&,
@@ -371,21 +365,6 @@ class PLATFORM_EXPORT GraphicsContext {
mojom::blink::ColorScheme color_scheme);
void DrawFocusRing(const Path&, float width, int offset, const Color&);
- enum Edge {
- kNoEdge = 0,
- kTopEdge = 1 << 1,
- kRightEdge = 1 << 2,
- kBottomEdge = 1 << 3,
- kLeftEdge = 1 << 4
- };
- typedef unsigned Edges;
- void DrawInnerShadow(const FloatRoundedRect&,
- const Color& shadow_color,
- const FloatSize& shadow_offset,
- float shadow_blur,
- float shadow_spread,
- Edges clipped_edges = kNoEdge);
-
const PaintFlags& FillFlags() const { return ImmutableState()->FillFlags(); }
// If the length of the path to be stroked is known, pass it in for correct
// dash or dot placement. Border painting uses a stroke thickness determined
@@ -408,6 +387,13 @@ class PLATFORM_EXPORT GraphicsContext {
const FloatRect& dest,
const FloatRect& src) const;
+ SkSamplingOptions ComputeSamplingOptions(Image* image,
+ const FloatRect& dest,
+ const FloatRect& src) const {
+ return SkSamplingOptions(ComputeFilterQuality(image, dest, src),
+ SkSamplingOptions::kMedium_asMipmapLinear);
+ }
+
// Sets target URL of a clickable area.
void SetURLForRect(const KURL&, const IntRect&);
@@ -440,6 +426,7 @@ class PLATFORM_EXPORT GraphicsContext {
// creating a tagged PDF. Callers are responsible for restoring it.
void SetDOMNodeId(DOMNodeId);
DOMNodeId GetDOMNodeId() const;
+ bool NeedsDOMNodeId() const { return printing_; }
static sk_sp<SkColorFilter> WebCoreColorFilterToSkiaColorFilter(ColorFilter);
@@ -510,16 +497,12 @@ class PLATFORM_EXPORT GraphicsContext {
}
}
- void FillRectWithRoundedHole(const FloatRect&,
- const FloatRoundedRect& rounded_hole_rect,
- const Color&);
-
class DarkModeFlags;
// This is owned by paint_recorder_. Never delete this object.
// Drawing operations are allowed only after the first BeginRecording() which
// initializes this to not null.
- cc::PaintCanvas* canvas_;
+ cc::PaintCanvas* canvas_ = nullptr;
PaintController& paint_controller_;
@@ -529,29 +512,28 @@ class PLATFORM_EXPORT GraphicsContext {
Vector<std::unique_ptr<GraphicsContextState>> paint_state_stack_;
// Current index on the stack. May not be the last thing on the stack.
- unsigned paint_state_index_;
+ wtf_size_t paint_state_index_ = 0;
// Raw pointer to the current state.
- GraphicsContextState* paint_state_;
+ GraphicsContextState* paint_state_ = nullptr;
PaintRecorder paint_recorder_;
- printing::MetafileSkia* metafile_;
- paint_preview::PaintPreviewTracker* tracker_;
+ printing::MetafileSkia* printing_metafile_ = nullptr;
+ paint_preview::PaintPreviewTracker* paint_preview_tracker_ = nullptr;
#if DCHECK_IS_ON()
- int layer_count_;
- bool disable_destruction_checks_;
+ int layer_count_ = 0;
+ bool disable_destruction_checks_ = false;
#endif
- float device_scale_factor_;
+ float device_scale_factor_ = 1.0f;
std::unique_ptr<DarkModeFilter> dark_mode_filter_;
- unsigned printing_ : 1;
- unsigned is_painting_preview_ : 1;
- unsigned in_drawing_recorder_ : 1;
- unsigned is_dark_mode_enabled_ : 1;
+ bool printing_ = false;
+ bool in_drawing_recorder_ = false;
+ bool is_dark_mode_enabled_ = false;
// The current node ID, which is used for marked content in a tagged PDF.
DOMNodeId dom_node_id_ = kInvalidDOMNodeId;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context_test.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_context_test.cc
index 36b606a3f8e..6e29c6f1aed 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context_test.cc
@@ -215,7 +215,7 @@ TEST_F(GraphicsContextDarkModeTest, InvertBrightness) {
EXPECT_EQ(SK_ColorWHITE, bitmap_.getColor(0, 0));
EXPECT_EQ(SK_ColorBLACK, bitmap_.getColor(1, 0));
EXPECT_EQ(SK_ColorCYAN, bitmap_.getColor(2, 0));
- EXPECT_EQ(0xffd8d8d8, bitmap_.getColor(3, 0));
+ EXPECT_EQ(0xffe1e1e1, bitmap_.getColor(3, 0));
}
// Invert lightness (in HSL space).
@@ -230,7 +230,7 @@ TEST_F(GraphicsContextDarkModeTest, InvertLightness) {
EXPECT_EQ(SK_ColorWHITE, bitmap_.getColor(0, 0));
EXPECT_EQ(SK_ColorBLACK, bitmap_.getColor(1, 0));
EXPECT_EQ(SK_ColorRED, bitmap_.getColor(2, 0));
- EXPECT_EQ(0xffd8d8d8, bitmap_.getColor(3, 0));
+ EXPECT_EQ(0xffe1e1e1, bitmap_.getColor(3, 0));
}
// Invert lightness plus grayscale.
@@ -244,8 +244,8 @@ TEST_F(GraphicsContextDarkModeTest, InvertLightnessPlusGrayscale) {
EXPECT_EQ(SK_ColorWHITE, bitmap_.getColor(0, 0));
EXPECT_EQ(SK_ColorBLACK, bitmap_.getColor(1, 0));
- EXPECT_EQ(0xffe2e2e2, bitmap_.getColor(2, 0));
- EXPECT_EQ(0xffd8d8d8, bitmap_.getColor(3, 0));
+ EXPECT_EQ(0xffe6e6e6, bitmap_.getColor(2, 0));
+ EXPECT_EQ(0xffe1e1e1, bitmap_.getColor(3, 0));
}
TEST_F(GraphicsContextDarkModeTest, InvertLightnessPlusContrast) {
@@ -259,7 +259,7 @@ TEST_F(GraphicsContextDarkModeTest, InvertLightnessPlusContrast) {
EXPECT_EQ(SK_ColorWHITE, bitmap_.getColor(0, 0));
EXPECT_EQ(SK_ColorBLACK, bitmap_.getColor(1, 0));
EXPECT_EQ(SK_ColorRED, bitmap_.getColor(2, 0));
- EXPECT_EQ(0xffe7e7e7, bitmap_.getColor(3, 0));
+ EXPECT_EQ(0xfff1f1f1, bitmap_.getColor(3, 0));
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index 29c9b6fb384..db2f311652d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -67,7 +67,6 @@ namespace blink {
GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client)
: client_(client),
- prevent_contents_opaque_changes_(false),
draws_content_(false),
paints_hit_test_(false),
contents_visible_(true),
@@ -264,10 +263,6 @@ void GraphicsLayer::SetOffsetFromLayoutObject(const IntSize& offset) {
Invalidate(PaintInvalidationReason::kFullLayer); // As DisplayItemClient.
}
-IntRect GraphicsLayer::InterestRect() {
- return previous_interest_rect_;
-}
-
void GraphicsLayer::ClearPaintStateRecursively() {
ForAllGraphicsLayers(
*this,
@@ -348,10 +343,12 @@ void GraphicsLayer::Paint(Vector<PreCompositedLayerInfo>& pre_composited_layers,
#endif
DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName();
- IntRect new_interest_rect =
- interest_rect
- ? *interest_rect
- : client_.ComputeInterestRect(this, previous_interest_rect_);
+ IntRect new_interest_rect;
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ new_interest_rect = interest_rect ? *interest_rect
+ : client_.ComputeInterestRect(
+ this, previous_interest_rect_);
+ }
auto& paint_controller = GetPaintController();
PaintController::ScopedBenchmarkMode scoped_benchmark_mode(paint_controller,
@@ -367,6 +364,10 @@ void GraphicsLayer::Paint(Vector<PreCompositedLayerInfo>& pre_composited_layers,
DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName();
paint_controller.UpdateCurrentPaintChunkProperties(
nullptr, layer_state_->state.GetPropertyTreeState());
+ // If this uses pre-CAP compositing, contents_opaque will be calculated by
+ // CompositedLayerMapping; otherwise, it is calculated by PaintChunker.
+ paint_controller.SetShouldComputeContentsOpaque(
+ ShouldCreateLayersAfterPaint());
previous_interest_rect_ = new_interest_rect;
client_.PaintContents(this, context, painting_phase_, new_interest_rect);
paint_controller.CommitNewDisplayItems();
@@ -374,7 +375,7 @@ void GraphicsLayer::Paint(Vector<PreCompositedLayerInfo>& pre_composited_layers,
// when unifying PaintController.
Validate();
DVLOG(2) << "Painted GraphicsLayer: " << DebugName()
- << " interest_rect=" << InterestRect().ToString();
+ << " paintable region: " << PaintableRegion().ToString();
}
PaintChunkSubset chunks(paint_controller.GetPaintArtifactShared());
@@ -399,8 +400,8 @@ void GraphicsLayer::Paint(Vector<PreCompositedLayerInfo>& pre_composited_layers,
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
PaintsContentOrHitTest()) {
raster_under_invalidation_params.emplace(
- EnsureRasterInvalidator().EnsureTracking(), InterestRect(),
- DebugName());
+ EnsureRasterInvalidator().EnsureTracking(),
+ IntRect(PaintableRegion()), DebugName());
}
// If nothing changed in the layer, keep the original display item list.
@@ -463,14 +464,12 @@ void GraphicsLayer::UpdateContentsLayerBounds() {
}
void GraphicsLayer::SetContentsToCcLayer(
- scoped_refptr<cc::Layer> contents_layer,
- bool prevent_contents_opaque_changes) {
+ scoped_refptr<cc::Layer> contents_layer) {
DCHECK_NE(contents_layer, layer_);
- SetContentsTo(std::move(contents_layer), prevent_contents_opaque_changes);
+ SetContentsTo(std::move(contents_layer));
}
-void GraphicsLayer::SetContentsTo(scoped_refptr<cc::Layer> layer,
- bool prevent_contents_opaque_changes) {
+void GraphicsLayer::SetContentsTo(scoped_refptr<cc::Layer> layer) {
if (layer) {
if (contents_layer_ != layer) {
contents_layer_ = std::move(layer);
@@ -482,7 +481,6 @@ void GraphicsLayer::SetContentsTo(scoped_refptr<cc::Layer> layer,
NotifyChildListChange();
}
UpdateContentsLayerBounds();
- prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
} else if (contents_layer_) {
contents_layer_ = nullptr;
NotifyChildListChange();
@@ -595,25 +593,6 @@ void GraphicsLayer::SetContentsVisible(bool contents_visible) {
UpdateLayerIsDrawable();
}
-void GraphicsLayer::SetContentsLayerBackgroundColor(Color color) {
- if (contents_layer_)
- contents_layer_->SetBackgroundColor(color.Rgb());
-}
-
-bool GraphicsLayer::ContentsOpaque() const {
- return CcLayer().contents_opaque();
-}
-
-void GraphicsLayer::SetContentsOpaque(bool opaque) {
- CcLayer().SetContentsOpaque(opaque);
- if (contents_layer_ && !prevent_contents_opaque_changes_)
- contents_layer_->SetContentsOpaque(opaque);
-}
-
-void GraphicsLayer::SetContentsOpaqueForText(bool opaque) {
- CcLayer().SetContentsOpaqueForText(opaque);
-}
-
void GraphicsLayer::SetPaintsHitTest(bool paints_hit_test) {
if (paints_hit_test_ == paints_hit_test)
return;
@@ -711,6 +690,12 @@ void GraphicsLayer::SetContentsLayerState(
client_.GraphicsLayersDidChange();
}
+gfx::Rect GraphicsLayer::PaintableRegion() const {
+ return RuntimeEnabledFeatures::CullRectUpdateEnabled()
+ ? client_.PaintableRegion(this)
+ : previous_interest_rect_;
+}
+
scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList() {
DCHECK(!ShouldCreateLayersAfterPaint());
return cc_display_item_list_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
index 31ccfbd126d..b4a972d9ac6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -139,13 +139,6 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
bool ContentsAreVisible() const { return contents_visible_; }
void SetContentsVisible(bool);
- void SetContentsLayerBackgroundColor(Color color);
-
- // Opaque means that we know the layer contents have no alpha.
- bool ContentsOpaque() const;
- void SetContentsOpaque(bool);
- void SetContentsOpaqueForText(bool);
-
void SetHitTestable(bool);
bool IsHitTestable() const { return hit_testable_; }
@@ -158,12 +151,7 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
// Set that the position/size of the contents (image or video).
void SetContentsRect(const IntRect&);
- // If |prevent_contents_opaque_changes| is set to true, then calls to
- // SetContentsOpaque() will not be passed on to |contents_layer|. Use when
- // the client wants to have control of the opaqueness of |contents_layer|
- // independently of what outcome painting produces.
- void SetContentsToCcLayer(scoped_refptr<cc::Layer> contents_layer,
- bool prevent_contents_opaque_changes);
+ void SetContentsToCcLayer(scoped_refptr<cc::Layer> contents_layer);
bool HasContentsLayer() const { return ContentsLayer(); }
cc::Layer* ContentsLayer() const { return contents_layer_.get(); }
@@ -180,8 +168,6 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
const IntRect&,
PaintInvalidationReason);
- IntRect InterestRect();
-
// Returns true if any layer is repainted.
bool PaintRecursively(GraphicsContext&,
Vector<PreCompositedLayerInfo>&,
@@ -244,9 +230,9 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
friend class GraphicsLayerTest;
// cc::ContentLayerClient implementation.
- gfx::Rect PaintableRegion() final { return InterestRect(); }
+ gfx::Rect PaintableRegion() const final;
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() final;
- bool FillsBoundsCompletely() const override { return false; }
+ bool FillsBoundsCompletely() const final { return false; }
void ClearPaintStateRecursively();
void Paint(Vector<PreCompositedLayerInfo>&,
@@ -266,8 +252,7 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
void UpdateLayerIsDrawable();
void UpdateContentsLayerBounds();
- void SetContentsTo(scoped_refptr<cc::Layer>,
- bool prevent_contents_opaque_changes);
+ void SetContentsTo(scoped_refptr<cc::Layer>);
RasterInvalidator& EnsureRasterInvalidator();
void InvalidateRaster(const IntRect&);
@@ -279,7 +264,6 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
TransformationMatrix transform_;
- bool prevent_contents_opaque_changes_ : 1;
bool draws_content_ : 1;
bool paints_hit_test_ : 1;
bool contents_visible_ : 1;
@@ -308,6 +292,7 @@ class PLATFORM_EXPORT GraphicsLayer : public DisplayItemClient,
mutable std::unique_ptr<PaintController> paint_controller_;
+ // Used only when CullRectUpdate is not enabled.
IntRect previous_interest_rect_;
struct LayerState {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
index d0b4ed92fb4..3a790a921c3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h
@@ -54,9 +54,13 @@ class PLATFORM_EXPORT GraphicsLayerClient {
public:
virtual ~GraphicsLayerClient() = default;
+ // Used only when CullRectUpdate is not enabled.
virtual IntRect ComputeInterestRect(
const GraphicsLayer*,
const IntRect& previous_interest_rect) const = 0;
+ // Used when CullRectUpdate is enabled.
+ virtual IntRect PaintableRegion(const GraphicsLayer*) const = 0;
+
virtual LayoutSize SubpixelAccumulation() const { return LayoutSize(); }
// Returns whether the client needs to be repainted with respect to the given
// graphics layer.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
index bba15d90998..3856e9a977c 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc
@@ -188,10 +188,10 @@ TEST_F(GraphicsLayerTest, ContentsLayer) {
FakeGraphicsLayerClient client;
GraphicsLayer graphics_layer(client);
auto contents_layer = cc::Layer::Create();
- graphics_layer.SetContentsToCcLayer(contents_layer, true);
+ graphics_layer.SetContentsToCcLayer(contents_layer);
EXPECT_TRUE(graphics_layer.HasContentsLayer());
EXPECT_EQ(contents_layer.get(), graphics_layer.ContentsLayer());
- graphics_layer.SetContentsToCcLayer(nullptr, true);
+ graphics_layer.SetContentsToCcLayer(nullptr);
EXPECT_FALSE(graphics_layer.HasContentsLayer());
EXPECT_EQ(nullptr, graphics_layer.ContentsLayer());
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_types.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_types.h
index 3890907eb75..c7258df0853 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/graphics_types.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_types.h
@@ -134,14 +134,6 @@ enum MailboxSyncMode {
kOrderingBarrier,
};
-// TODO(junov): crbug.com/453113 Relocate ShadowMode to
-// CanvasRenderingContext2DState.h once GraphicsContext no longer uses it.
-enum ShadowMode {
- kDrawShadowAndForeground,
- kDrawShadowOnly,
- kDrawForegroundOnly
-};
-
enum AntiAliasingMode { kNotAntiAliased, kAntiAliased };
enum GradientSpreadMethod {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest.cc b/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest.cc
index 843840af4ee..cb820befc74 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest.cc
@@ -49,7 +49,7 @@ IdentifiabilityPaintOpDigest::IdentifiabilityPaintOpDigest(IntSize size,
/*can_use_lcd_text=*/false,
/*content_supports_distance_field_text=*/false,
/*max_texture_size=*/0,
- /*original_ctm=*/SkMatrix::I()) {
+ /*original_ctm=*/SkM44()) {
serialize_options_.for_identifiability_study = true;
constexpr size_t kInitialSize = 16 * 1024;
if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc b/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
index e9262667aa5..e1af0992129 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
@@ -249,7 +249,7 @@ TEST(IdentifiabilityPaintOpDigestTest, BufferLeftoversDontAffectFutureDigests) {
/*num_ops_to_visit=*/1);
identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2,
/*num_ops_to_visit=*/1);
- EXPECT_EQ(INT64_C(-1855817800596177722),
+ EXPECT_EQ(INT64_C(-8958477480441775589),
identifiability_paintop_digest1.GetToken().ToUkmMetricValue());
EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest2.GetToken().ToUkmMetricValue());
@@ -280,7 +280,7 @@ TEST(IdentifiabilityPaintOpDigestTest,
paint_record->push<cc::ScaleOp>(kScaleX, kScaleY);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/2);
- EXPECT_EQ(INT64_C(-2635322358402873102),
+ EXPECT_EQ(INT64_C(4130836803240885894),
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
@@ -425,11 +425,10 @@ TEST(IdentifiabilityPaintOpDigestTest, DigestImageOp) {
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize);
auto paint_record = sk_make_sp<cc::PaintRecord>();
paint_record->push<cc::DrawImageOp>(
- cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), 10.0f, 10.0f,
- nullptr);
+ cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), 10.0f, 10.0f);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1);
- EXPECT_EQ(INT64_C(72317288461381383),
+ EXPECT_EQ(INT64_C(-3447989221783743109),
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image.cc b/chromium/third_party/blink/renderer/platform/graphics/image.cc
index 4281c382acc..c44f061dcf3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/image.cc
@@ -145,13 +145,13 @@ PaintImage Image::ResizeAndOrientImage(
DCHECK_GE(opacity, 0);
DCHECK_LE(opacity, 1);
paint.setAlpha(opacity * 255);
- paint.setFilterQuality(interpolation_quality == kInterpolationNone
- ? kNone_SkFilterQuality
- : kHigh_SkFilterQuality);
+ SkSamplingOptions sampling;
+ if (interpolation_quality != kInterpolationNone)
+ sampling = SkSamplingOptions({1.0f / 3, 1.0f / 3});
SkCanvas* canvas = surface->getCanvas();
canvas->concat(AffineTransformToSkMatrix(transform));
- canvas->drawImage(image.GetSwSkImage(), 0, 0, &paint);
+ canvas->drawImage(image.GetSwSkImage(), 0, 0, sampling, &paint);
return PaintImageBuilder::WithProperties(std::move(image))
.set_image(surface->makeImageSnapshot(), PaintImage::GetNextContentId())
@@ -179,7 +179,7 @@ namespace {
sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
const SkMatrix& shader_matrix,
- SkFilterQuality quality_to_use,
+ const SkSamplingOptions& sampling,
bool should_antialias,
const FloatSize& spacing,
SkTileMode tmx,
@@ -200,13 +200,12 @@ sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
cc::PaintCanvas* canvas = recorder.beginRecording(tile_rect);
PaintFlags flags;
flags.setAntiAlias(should_antialias);
- flags.setFilterQuality(quality_to_use);
canvas->drawImageRect(
image,
SkRect::MakeXYWH(subset_rect.X(), subset_rect.Y(), subset_rect.Width(),
subset_rect.Height()),
- SkRect::MakeWH(subset_rect.Width(), subset_rect.Height()), &flags,
- SkCanvas::kStrict_SrcRectConstraint);
+ SkRect::MakeWH(subset_rect.Width(), subset_rect.Height()), sampling,
+ &flags, SkCanvas::kStrict_SrcRectConstraint);
return PaintShader::MakePaintRecord(recorder.finishRecordingAsPicture(),
tile_rect, tmx, tmy, &shader_matrix);
@@ -279,10 +278,10 @@ void Image::DrawPattern(GraphicsContext& context,
const auto tmy = ComputeTileMode(dest_rect.Y(), dest_rect.MaxY(), adjusted_y,
adjusted_y + tile_size.Height());
- SkFilterQuality quality_to_use =
- context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect));
+ SkSamplingOptions sampling_to_use =
+ context.ComputeSamplingOptions(this, dest_rect, FloatRect(subset_rect));
sk_sp<PaintShader> tile_shader = CreatePatternShader(
- image, local_matrix, quality_to_use, context.ShouldAntialias(),
+ image, local_matrix, sampling_to_use, context.ShouldAntialias(),
FloatSize(repeat_spacing.Width() / oriented_scale.Width(),
repeat_spacing.Height() / oriented_scale.Height()),
tmx, tmy, subset_rect);
@@ -293,7 +292,6 @@ void Image::DrawPattern(GraphicsContext& context,
// Note: we can't simply bail, because of arbitrary blend mode.
flags.setColor(tile_shader ? SK_ColorBLACK : SK_ColorTRANSPARENT);
flags.setBlendMode(composite_op);
- flags.setFilterQuality(quality_to_use);
flags.setShader(std::move(tile_shader));
context.DrawRect(dest_rect, flags);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image.h b/chromium/third_party/blink/renderer/platform/graphics/image.h
index a497b13c6cd..28bfbfb003b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/image.h
@@ -234,6 +234,7 @@ class PLATFORM_EXPORT Image : public ThreadSafeRefCounted<Image> {
const cc::PaintFlags&,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) = 0;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_data_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
index 7cffc615582..aa47d1ce4d2 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
@@ -171,19 +171,21 @@ String ImageDataBuffer::ToDataURL(const ImageEncodingMimeType mime_type,
const double& quality) const {
DCHECK(is_valid_);
- // toDataURL always encodes in sRGB and does not include the color space
- // information.
- sk_sp<SkImage> skia_image = nullptr;
SkPixmap pixmap = pixmap_;
- if (pixmap.colorSpace()) {
- if (!pixmap.colorSpace()->isSRGB()) {
- skia_image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
- skia_image = skia_image->makeColorSpace(SkColorSpace::MakeSRGB());
- if (!skia_image->peekPixels(&pixmap))
- return "data:,";
- MSAN_CHECK_MEM_IS_INITIALIZED(pixmap.addr(), pixmap.computeByteSize());
+ if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
+ // toDataURL always encodes in sRGB and does not include the color space
+ // information.
+ sk_sp<SkImage> skia_image = nullptr;
+ if (pixmap.colorSpace()) {
+ if (!pixmap.colorSpace()->isSRGB()) {
+ skia_image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
+ skia_image = skia_image->makeColorSpace(SkColorSpace::MakeSRGB());
+ if (!skia_image->peekPixels(&pixmap))
+ return "data:,";
+ MSAN_CHECK_MEM_IS_INITIALIZED(pixmap.addr(), pixmap.computeByteSize());
+ }
+ pixmap.setColorSpace(nullptr);
}
- pixmap.setColorSpace(nullptr);
}
Vector<unsigned char> result;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_frame_generator.cc b/chromium/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
index 372482a738d..d7ffcbbf486 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
@@ -34,36 +34,39 @@
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkYUVASizeInfo.h"
namespace blink {
-static bool UpdateYUVAInfoPlanarConfigAndWidthBytes(
- ImageDecoder* decoder,
- SkYUVAInfo::PlanarConfig* config,
- size_t component_width_bytes[SkYUVAInfo::kMaxPlanes]) {
- switch (decoder->GetYUVSubsampling()) {
+SkYUVAInfo::Subsampling SubsamplingToSkiaSubsampling(
+ cc::YUVSubsampling subsampling) {
+ switch (subsampling) {
case cc::YUVSubsampling::k410:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_410;
- break;
+ return SkYUVAInfo::Subsampling::k410;
case cc::YUVSubsampling::k411:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_411;
- break;
+ return SkYUVAInfo::Subsampling::k411;
case cc::YUVSubsampling::k420:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_420;
- break;
+ return SkYUVAInfo::Subsampling::k420;
case cc::YUVSubsampling::k422:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_422;
- break;
+ return SkYUVAInfo::Subsampling::k422;
case cc::YUVSubsampling::k440:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_440;
- break;
+ return SkYUVAInfo::Subsampling::k440;
case cc::YUVSubsampling::k444:
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_444;
- break;
- default:
- return false;
+ return SkYUVAInfo::Subsampling::k444;
+ case cc::YUVSubsampling::kUnknown:
+ return SkYUVAInfo::Subsampling::kUnknown;
}
+}
+
+static bool UpdateYUVAInfoSubsamplingAndWidthBytes(
+ ImageDecoder* decoder,
+ SkYUVAInfo::Subsampling* subsampling,
+ size_t component_width_bytes[SkYUVAInfo::kMaxPlanes]) {
+ SkYUVAInfo::Subsampling tempSubsampling =
+ SubsamplingToSkiaSubsampling(decoder->GetYUVSubsampling());
+ if (tempSubsampling == SkYUVAInfo::Subsampling::kUnknown) {
+ return false;
+ }
+ *subsampling = tempSubsampling;
component_width_bytes[0] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kY);
component_width_bytes[1] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kU);
component_width_bytes[2] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kV);
@@ -112,7 +115,7 @@ bool ImageFrameGenerator::DecodeAndScale(
}
TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "generator",
- this);
+ static_cast<void*>(this));
// This implementation does not support arbitrary scaling so check the
// requested size.
@@ -205,14 +208,20 @@ bool ImageFrameGenerator::DecodeToYUV(
decoder->DecodeToYUV();
}
- if (!decoder->Failed()) {
+ // Display a complete scan if available, even if decoding fails.
+ if (decoder->HasDisplayableYUVData()) {
// TODO(crbug.com/910276): Set this properly for alpha support.
SetHasAlpha(index, false);
return true;
}
- DCHECK(decoder->Failed());
- yuv_decoding_failed_ = true;
+ // Currently if there is no displayable data, the decoder always fails.
+ // This may not be the case once YUV supports incremental decoding
+ // (crbug.com/943519).
+ if (decoder->Failed()) {
+ yuv_decoding_failed_ = true;
+ }
+
return false;
}
@@ -253,26 +262,29 @@ bool ImageFrameGenerator::GetYUVAInfo(
DCHECK(decoder);
DCHECK(decoder->CanDecodeToYUV());
- SkYUVAInfo::PlanarConfig config;
+ SkYUVAInfo::Subsampling subsampling;
size_t width_bytes[SkYUVAInfo::kMaxPlanes];
- if (!UpdateYUVAInfoPlanarConfigAndWidthBytes(decoder.get(), &config,
- width_bytes)) {
+ if (!UpdateYUVAInfoSubsamplingAndWidthBytes(decoder.get(), &subsampling,
+ width_bytes)) {
return false;
}
- SkYUVAInfo yuva_info(full_size_, config, decoder->GetYUVColorSpace());
+ SkYUVAInfo yuva_info(full_size_, SkYUVAInfo::PlaneConfig::kY_U_V, subsampling,
+ decoder->GetYUVColorSpace());
SkYUVAPixmapInfo::DataType dataType;
if (decoder->GetYUVBitDepth() > 8) {
- if (supported_data_types.supported(config,
+ if (supported_data_types.supported(SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAPixmapInfo::DataType::kUnorm16)) {
dataType = SkYUVAPixmapInfo::DataType::kUnorm16;
} else if (supported_data_types.supported(
- config, SkYUVAPixmapInfo::DataType::kFloat16)) {
+ SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAPixmapInfo::DataType::kFloat16)) {
dataType = SkYUVAPixmapInfo::DataType::kFloat16;
} else {
return false;
}
} else if (supported_data_types.supported(
- config, SkYUVAPixmapInfo::DataType::kUnorm8)) {
+ SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAPixmapInfo::DataType::kUnorm8)) {
dataType = SkYUVAPixmapInfo::DataType::kUnorm8;
} else {
return false;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
index 0a2324a681e..732c863f952 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
@@ -88,15 +88,17 @@ class InterceptingCanvasBase : public SkCanvas {
void onDrawOval(const SkRect&, const SkPaint&) override = 0;
void onDrawRRect(const SkRRect&, const SkPaint&) override = 0;
void onDrawPath(const SkPath&, const SkPaint&) override = 0;
- void onDrawImage(const SkImage*,
- SkScalar,
- SkScalar,
- const SkPaint*) override = 0;
- void onDrawImageRect(const SkImage*,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint*,
- SrcRectConstraint) override = 0;
+ void onDrawImage2(const SkImage*,
+ SkScalar,
+ SkScalar,
+ const SkSamplingOptions&,
+ const SkPaint*) override = 0;
+ void onDrawImageRect2(const SkImage*,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions&,
+ const SkPaint*,
+ SrcRectConstraint) override = 0;
void onDrawVerticesObject(const SkVertices*,
SkBlendMode bmode,
const SkPaint&) override = 0;
@@ -115,9 +117,8 @@ class InterceptingCanvasBase : public SkCanvas {
void onDrawPicture(const SkPicture*,
const SkMatrix*,
const SkPaint*) override = 0;
- void didSetMatrix(const SkMatrix&) override = 0;
+ void didSetM44(const SkM44&) override = 0;
void didConcat44(const SkM44&) override = 0;
- void didConcat(const SkMatrix&) override = 0;
void didScale(SkScalar, SkScalar) override = 0;
void didTranslate(SkScalar, SkScalar) override = 0;
void willSave() override = 0;
@@ -179,21 +180,24 @@ class InterceptingCanvas : public InterceptingCanvasBase {
this->SkCanvas::onDrawPath(path, paint);
}
- void onDrawImage(const SkImage* image,
- SkScalar x,
- SkScalar y,
- const SkPaint* paint) override {
+ void onDrawImage2(const SkImage* image,
+ SkScalar x,
+ SkScalar y,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint) override {
Interceptor interceptor(this);
- this->SkCanvas::onDrawImage(image, x, y, paint);
+ this->SkCanvas::onDrawImage2(image, x, y, sampling, paint);
}
- void onDrawImageRect(const SkImage* image,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- SrcRectConstraint constraint) override {
+ void onDrawImageRect2(const SkImage* image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint,
+ SrcRectConstraint constraint) override {
Interceptor interceptor(this);
- this->SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
+ this->SkCanvas::onDrawImageRect2(image, src, dst, sampling, paint,
+ constraint);
}
void onDrawVerticesObject(const SkVertices* vertices,
@@ -250,16 +254,10 @@ class InterceptingCanvas : public InterceptingCanvasBase {
this->UnrollDrawPicture(picture, matrix, paint, nullptr);
}
- void didSetMatrix(const SkMatrix& matrix) override {
- Interceptor interceptor(this);
- }
+ void didSetM44(const SkM44&) override { Interceptor interceptor(this); }
void didConcat44(const SkM44&) override { Interceptor interceptor(this); }
- void didConcat(const SkMatrix& matrix) override {
- Interceptor interceptor(this);
- }
-
void didScale(SkScalar x, SkScalar y) override {
Interceptor interceptor(this);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
index 868f06f99a5..51d3c786688 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc
@@ -234,13 +234,6 @@ std::unique_ptr<JSONObject> ObjectForSkImage(const SkImage* image) {
return image_item;
}
-std::unique_ptr<JSONArray> ArrayForSkMatrix(const SkMatrix& matrix) {
- auto matrix_array = std::make_unique<JSONArray>();
- for (int i = 0; i < 9; ++i)
- matrix_array->PushDouble(matrix[i]);
- return matrix_array;
-}
-
std::unique_ptr<JSONArray> ArrayForSkScalars(size_t count,
const SkScalar array[]) {
auto points_array_item = std::make_unique<JSONArray>();
@@ -452,10 +445,11 @@ void LoggingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
this->SkCanvas::onDrawPath(path, paint);
}
-void LoggingCanvas::onDrawImage(const SkImage* image,
- SkScalar left,
- SkScalar top,
- const SkPaint* paint) {
+void LoggingCanvas::onDrawImage2(const SkImage* image,
+ SkScalar left,
+ SkScalar top,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint) {
AutoLogger logger(this);
JSONObject* params = logger.LogItemWithParams("drawImage");
params->SetDouble("left", left);
@@ -463,23 +457,24 @@ void LoggingCanvas::onDrawImage(const SkImage* image,
params->SetObject("image", ObjectForSkImage(image));
if (paint)
params->SetObject("paint", ObjectForSkPaint(*paint));
- this->SkCanvas::onDrawImage(image, left, top, paint);
+ this->SkCanvas::onDrawImage2(image, left, top, sampling, paint);
}
-void LoggingCanvas::onDrawImageRect(const SkImage* image,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- SrcRectConstraint constraint) {
+void LoggingCanvas::onDrawImageRect2(const SkImage* image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions& sampling,
+ const SkPaint* paint,
+ SrcRectConstraint constraint) {
AutoLogger logger(this);
JSONObject* params = logger.LogItemWithParams("drawImageRect");
params->SetObject("image", ObjectForSkImage(image));
- if (src)
- params->SetObject("src", ObjectForSkRect(*src));
+ params->SetObject("src", ObjectForSkRect(src));
params->SetObject("dst", ObjectForSkRect(dst));
if (paint)
params->SetObject("paint", ObjectForSkPaint(*paint));
- this->SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
+ this->SkCanvas::onDrawImageRect2(image, src, dst, sampling, paint,
+ constraint);
}
void LoggingCanvas::onDrawVerticesObject(const SkVertices* vertices,
@@ -560,10 +555,12 @@ void LoggingCanvas::onDrawPicture(const SkPicture* picture,
this->UnrollDrawPicture(picture, matrix, paint, nullptr);
}
-void LoggingCanvas::didSetMatrix(const SkMatrix& matrix) {
+void LoggingCanvas::didSetM44(const SkM44& matrix) {
+ SkScalar m[16];
+ matrix.getColMajor(m);
AutoLogger logger(this);
JSONObject* params = logger.LogItemWithParams("setMatrix");
- params->SetArray("matrix", ArrayForSkMatrix(matrix));
+ params->SetArray("matrix44", ArrayForSkScalars(16, m));
}
void LoggingCanvas::didConcat44(const SkM44& matrix) {
@@ -574,29 +571,6 @@ void LoggingCanvas::didConcat44(const SkM44& matrix) {
params->SetArray("matrix44", ArrayForSkScalars(16, m));
}
-void LoggingCanvas::didConcat(const SkMatrix& matrix) {
- AutoLogger logger(this);
- JSONObject* params;
-
- switch (matrix.getType()) {
- case SkMatrix::kTranslate_Mask:
- params = logger.LogItemWithParams("translate");
- params->SetDouble("dx", matrix.getTranslateX());
- params->SetDouble("dy", matrix.getTranslateY());
- break;
-
- case SkMatrix::kScale_Mask:
- params = logger.LogItemWithParams("scale");
- params->SetDouble("scaleX", matrix.getScaleX());
- params->SetDouble("scaleY", matrix.getScaleY());
- break;
-
- default:
- params = logger.LogItemWithParams("concat");
- params->SetArray("matrix", ArrayForSkMatrix(matrix));
- }
-}
-
void LoggingCanvas::didScale(SkScalar x, SkScalar y) {
AutoLogger logger(this);
JSONObject* params = logger.LogItemWithParams("scale");
diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
index 96a856d1d21..dfd4021ea61 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h
@@ -53,12 +53,17 @@ class LoggingCanvas : public InterceptingCanvasBase {
void onDrawOval(const SkRect&, const SkPaint&) override;
void onDrawRRect(const SkRRect&, const SkPaint&) override;
void onDrawPath(const SkPath&, const SkPaint&) override;
- void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
- void onDrawImageRect(const SkImage*,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint*,
- SrcRectConstraint) override;
+ void onDrawImage2(const SkImage*,
+ SkScalar,
+ SkScalar,
+ const SkSamplingOptions&,
+ const SkPaint*) override;
+ void onDrawImageRect2(const SkImage*,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions&,
+ const SkPaint*,
+ SrcRectConstraint) override;
void onDrawVerticesObject(const SkVertices*,
SkBlendMode bmode,
const SkPaint&) override;
@@ -77,9 +82,8 @@ class LoggingCanvas : public InterceptingCanvasBase {
void onDrawPicture(const SkPicture*,
const SkMatrix*,
const SkPaint*) override;
- void didSetMatrix(const SkMatrix&) override;
+ void didSetM44(const SkM44&) override;
void didConcat44(const SkM44&) override;
- void didConcat(const SkMatrix&) override;
void didScale(SkScalar, SkScalar) override;
void didTranslate(SkScalar, SkScalar) override;
void willSave() override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.cc b/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.cc
index c926ce1952c..38dbfd515ca 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.cc
@@ -31,9 +31,7 @@ MailboxRef::MailboxRef(
: sync_token_(sync_token),
context_thread_ref_(context_thread_ref),
context_task_runner_(std::move(context_task_runner)),
- release_callback_(std::move(release_callback)) {
- DCHECK(sync_token.HasData());
-}
+ release_callback_(std::move(release_callback)) {}
MailboxRef::~MailboxRef() {
if (context_thread_ref_ == base::PlatformThread::CurrentRef()) {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.h b/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.h
index ef9e2996c97..cd94537c7e6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_ref.h
@@ -32,10 +32,7 @@ class MailboxRef : public ThreadSafeRefCounted<MailboxRef> {
bool is_cross_thread() const {
return base::PlatformThread::CurrentRef() != context_thread_ref_;
}
- void set_sync_token(gpu::SyncToken token) {
- DCHECK(sync_token_.HasData());
- sync_token_ = token;
- }
+ void set_sync_token(gpu::SyncToken token) { sync_token_ = token; }
const gpu::SyncToken& sync_token() const { return sync_token_; }
bool verified_flush() { return sync_token_.verified_flush(); }
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
index e13ebbc68f7..3001841e465 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.cc
@@ -32,6 +32,7 @@ MailboxTextureBacking::MailboxTextureBacking(
context_provider_wrapper_(std::move(context_provider_wrapper)) {}
MailboxTextureBacking::~MailboxTextureBacking() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (context_provider_wrapper_) {
gpu::raster::RasterInterface* ri =
context_provider_wrapper_->ContextProvider()->RasterInterface();
@@ -52,10 +53,13 @@ gpu::Mailbox MailboxTextureBacking::GetMailbox() const {
}
sk_sp<SkImage> MailboxTextureBacking::GetAcceleratedSkImage() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
return sk_image_;
}
sk_sp<SkImage> MailboxTextureBacking::GetSkImageViaReadback() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!mailbox_.IsZero()) {
if (!context_provider_wrapper_)
return nullptr;
@@ -85,6 +89,7 @@ bool MailboxTextureBacking::readPixels(const SkImageInfo& dst_info,
size_t dst_row_bytes,
int src_x,
int src_y) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!mailbox_.IsZero()) {
if (!context_provider_wrapper_)
return false;
@@ -102,6 +107,7 @@ bool MailboxTextureBacking::readPixels(const SkImageInfo& dst_info,
}
void MailboxTextureBacking::FlushPendingSkiaOps() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!context_provider_wrapper_ || !sk_image_)
return;
sk_image_->flushAndSubmit(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
index 7ba3b6d41e8..05f7fe3bcdf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_backing.h
@@ -8,6 +8,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MAILBOX_TEXTURE_BACKING_H_
#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
@@ -47,6 +48,7 @@ class MailboxTextureBacking : public TextureBacking {
scoped_refptr<MailboxRef> mailbox_ref_;
const SkImageInfo sk_image_info_;
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
+ THREAD_CHECKER(thread_checker_);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.cc b/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.cc
index 700112561d9..30a4717def5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.cc
@@ -18,9 +18,10 @@ MemoryManagedPaintCanvas::~MemoryManagedPaintCanvas() = default;
void MemoryManagedPaintCanvas::drawImage(const cc::PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions& sampling,
const cc::PaintFlags* flags) {
DCHECK(!image.IsPaintWorklet());
- RecordPaintCanvas::drawImage(image, left, top, flags);
+ RecordPaintCanvas::drawImage(image, left, top, sampling, flags);
UpdateMemoryUsage(image);
}
@@ -28,9 +29,11 @@ void MemoryManagedPaintCanvas::drawImageRect(
const cc::PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions& sampling,
const cc::PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) {
- RecordPaintCanvas::drawImageRect(image, src, dst, flags, constraint);
+ RecordPaintCanvas::drawImageRect(image, src, dst, sampling, flags,
+ constraint);
UpdateMemoryUsage(image);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h
index 2d2d17a8bd1..2ca460f4e69 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h
@@ -31,10 +31,12 @@ class PLATFORM_EXPORT MemoryManagedPaintCanvas final
void drawImage(const cc::PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions&,
const cc::PaintFlags* flags) override;
void drawImageRect(const cc::PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions&,
const cc::PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc b/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
index 87831e86f1f..3724ce8cea8 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
@@ -7,6 +7,7 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
+#include "third_party/blink/renderer/platform/graphics/resource_id_traits.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/hash_map.h"
diff --git a/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h b/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
index c21fdd436b1..e011ca666e5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
@@ -50,6 +50,8 @@ class PLATFORM_EXPORT OffscreenCanvasPlaceholder {
void UpdateOffscreenCanvasFilterQuality(SkFilterQuality filter_quality);
+ virtual bool HasCanvasCapture() const { return false; }
+
private:
bool PostSetSuspendAnimationToOffscreenCanvasThread(bool suspend);
@@ -57,7 +59,7 @@ class PLATFORM_EXPORT OffscreenCanvasPlaceholder {
scoped_refptr<CanvasResource> placeholder_frame_;
base::WeakPtr<CanvasResourceDispatcher> frame_dispatcher_;
scoped_refptr<base::SingleThreadTaskRunner> frame_dispatcher_task_runner_;
- viz::ResourceId placeholder_frame_resource_id_ = 0;
+ viz::ResourceId placeholder_frame_resource_id_ = viz::kInvalidResourceId;
enum {
kNoPlaceholderId = -1,
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
index d2f5981936f..f3b60e9dd99 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
+#include "base/containers/adapters.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
@@ -14,6 +15,30 @@
namespace blink {
+static constexpr int kReasonablePixelLimit =
+ std::numeric_limits<int>::max() / 2;
+
+// Returns the number of pixels to expand the cull rect for composited scroll
+// and transform.
+static int LocalPixelDistanceToExpand(
+ const TransformPaintPropertyNode& root_transform,
+ const TransformPaintPropertyNode& local_transform) {
+ // Number of pixels to expand in root coordinates for cull rect under
+ // composited scroll translation or other composited transform.
+ static constexpr int kPixelDistanceToExpand = 4000;
+
+ FloatRect rect(0, 0, 1, 1);
+ GeometryMapper::SourceToDestinationRect(root_transform, local_transform,
+ rect);
+ // Now rect.Size() is the size of a screen pixel in local coordinates.
+ float scale = std::max(rect.Width(), rect.Height());
+ // A very big scale may be caused by non-invertable near non-invertable
+ // transforms. Fallback to scale 1. The limit is heuristic.
+ if (scale > kReasonablePixelLimit / kPixelDistanceToExpand)
+ return kPixelDistanceToExpand;
+ return scale * kPixelDistanceToExpand;
+}
+
bool CullRect::Intersects(const IntRect& rect) const {
return IsInfinite() || rect.Intersects(rect_);
}
@@ -50,51 +75,57 @@ void CullRect::Move(const FloatSize& offset) {
rect_ = EnclosingIntRect(float_rect);
}
-static void MapRect(const TransformPaintPropertyNode& transform,
- IntRect& rect) {
- if (transform.IsIdentityOr2DTranslation()) {
- FloatRect float_rect(rect);
- float_rect.Move(-transform.Translation2D());
- rect = EnclosingIntRect(float_rect);
+void CullRect::ApplyTransform(const TransformPaintPropertyNode& transform) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ transform.ScrollNode()) {
+ // TODO(wangxianzhu): Remove this code path for CullRectUpdate.
+ ApplyScrollTranslation(transform, transform);
} else {
- rect = transform.MatrixWithOriginApplied().Inverse().MapRect(rect);
+ ApplyTransformWithoutExpansion(transform);
}
}
-CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
+void CullRect::ApplyTransformWithoutExpansion(
const TransformPaintPropertyNode& transform) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- if (const auto* scroll = transform.ScrollNode()) {
- rect_.Intersect(scroll->ContainerRect());
- if (rect_.IsEmpty())
- return kNotExpanded;
-
- MapRect(transform, rect_);
-
- // Don't expand for non-composited scrolling.
- if (!transform.HasDirectCompositingReasons())
- return kNotExpanded;
-
- // We create scroll node for the root scroller even it's not scrollable.
- // Don't expand in the case.
- if (scroll->ContainerRect().Width() >= scroll->ContentsSize().Width() &&
- scroll->ContainerRect().Height() >= scroll->ContentsSize().Height())
- return kNotExpanded;
-
- // Expand the cull rect for scrolling contents for composited scrolling.
- static const int kPixelDistanceToExpand = 4000;
- rect_.Inflate(kPixelDistanceToExpand);
- // Don't clip the cull rect by contents size to let ChangedEnough() work
- // even if the new cull rect exceeds the bounds of contents rect.
- return rect_.Contains(IntRect(IntPoint(), scroll->ContentsSize()))
- ? kExpandedForWholeScrollingContents
- : kExpandedForPartialScrollingContents;
- }
- }
+ if (IsInfinite())
+ return;
- if (!IsInfinite())
- MapRect(transform, rect_);
- return kNotExpanded;
+ DCHECK(transform.Parent());
+ GeometryMapper::SourceToDestinationRect(*transform.Parent(), transform,
+ rect_);
+}
+
+CullRect::ApplyTransformResult CullRect::ApplyScrollTranslation(
+ const TransformPaintPropertyNode& root_transform,
+ const TransformPaintPropertyNode& scroll_translation) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
+ const auto* scroll = scroll_translation.ScrollNode();
+ DCHECK(scroll);
+
+ rect_.Intersect(scroll->ContainerRect());
+ if (rect_.IsEmpty())
+ return kNotExpanded;
+
+ ApplyTransformWithoutExpansion(scroll_translation);
+
+ // Don't expand for non-composited scrolling.
+ if (!scroll_translation.HasDirectCompositingReasons())
+ return kNotExpanded;
+
+ // We create scroll node for the root scroller even it's not scrollable.
+ // Don't expand in the case.
+ if (scroll->ContainerRect().Width() >= scroll->ContentsSize().Width() &&
+ scroll->ContainerRect().Height() >= scroll->ContentsSize().Height())
+ return kNotExpanded;
+
+ // Expand the cull rect for scrolling contents for composited scrolling.
+ rect_.Inflate(LocalPixelDistanceToExpand(root_transform, scroll_translation));
+ IntRect contents_rect(IntPoint(), scroll->ContentsSize());
+ rect_.Intersect(contents_rect);
+ return rect_ == contents_rect ? kExpandedForWholeScrollingContents
+ : kExpandedForPartialScrollingContents;
}
void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
@@ -125,7 +156,7 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
*last_transform, *scroll_translation->Parent(), rect_);
}
last_scroll_translation_result =
- ApplyTransformInternal(*scroll_translation);
+ ApplyScrollTranslation(source, *scroll_translation);
last_transform = scroll_translation;
}
@@ -135,25 +166,202 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
}
if (last_scroll_translation_result == kExpandedForPartialScrollingContents &&
- old_cull_rect && !ChangedEnough(*old_cull_rect))
+ old_cull_rect &&
+ !ChangedEnough(*old_cull_rect,
+ &last_transform->ScrollNode()->ContentsSize())) {
rect_ = old_cull_rect->Rect();
+ }
}
-bool CullRect::ChangedEnough(const CullRect& old_cull_rect) const {
- DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+void CullRect::ApplyPaintPropertiesWithoutExpansion(
+ const PropertyTreeState& source,
+ const PropertyTreeState& destination) {
+ FloatClipRect clip_rect =
+ GeometryMapper::LocalToAncestorClipRect(destination, source);
+ if (!clip_rect.IsInfinite())
+ rect_.Intersect(EnclosingIntRect(clip_rect.Rect()));
+ if (!IsInfinite()) {
+ GeometryMapper::SourceToDestinationRect(source.Transform(),
+ destination.Transform(), rect_);
+ }
+}
+
+void CullRect::ApplyPaintProperties(
+ const PropertyTreeState& root,
+ const PropertyTreeState& source,
+ const PropertyTreeState& destination,
+ const base::Optional<CullRect>& old_cull_rect) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::CullRectUpdateEnabled());
+
+ Vector<const TransformPaintPropertyNode*, 4> scroll_translations;
+ Vector<const ClipPaintPropertyNode*, 4> clips;
+ bool abnormal_hierarchy = false;
+
+ for (const auto* t = &destination.Transform(); t != &source.Transform();
+ t = t->UnaliasedParent()) {
+ DCHECK(t);
+ if (t == &root.Transform()) {
+ abnormal_hierarchy = true;
+ break;
+ }
+ if (t->ScrollNode())
+ scroll_translations.push_back(t);
+ }
+
+ if (!abnormal_hierarchy) {
+ for (const auto* c = &destination.Clip(); c != &source.Clip();
+ c = c->UnaliasedParent()) {
+ DCHECK(c);
+ if (c == &root.Clip()) {
+ abnormal_hierarchy = true;
+ break;
+ }
+ clips.push_back(c);
+ }
+ }
+
+ if (abnormal_hierarchy) {
+ // Either the transform or the clip of |source| is not an ancestor of
+ // |destination|. Map infinite rect from the root.
+ *this = Infinite();
+ ApplyPaintProperties(root, root, destination, old_cull_rect);
+ return;
+ }
+
+ // These are either the source transform/clip or the last scroll
+ // translation's transform/clip.
+ const auto* last_transform = &source.Transform();
+ const auto* last_clip = &source.Clip();
+ auto last_scroll_translation_result = kNotExpanded;
+
+ // For now effects (especially pixel-moving filters) are not considered in
+ // this class. The client has to use infinite cull rect in the case.
+ // TODO(wangxianzhu): support clip rect expansion for pixel-moving filters.
+ const auto& effect_root = EffectPaintPropertyNode::Root();
+ auto scroll_translation_it = scroll_translations.rbegin();
+ for (const auto* clip : base::Reversed(clips)) {
+ if (scroll_translation_it == scroll_translations.rend())
+ break;
+
+ const auto* scroll_translation = *scroll_translation_it++;
+ if (&clip->LocalTransformSpace() != scroll_translation->Parent())
+ continue;
+
+ ApplyPaintPropertiesWithoutExpansion(
+ PropertyTreeState(*last_transform, *last_clip, effect_root),
+ PropertyTreeState(*scroll_translation->UnaliasedParent(), *clip,
+ effect_root));
+ last_scroll_translation_result =
+ ApplyScrollTranslation(root.Transform(), *scroll_translation);
+
+ last_transform = scroll_translation;
+ last_clip = clip;
+ }
+
+ ApplyPaintPropertiesWithoutExpansion(
+ PropertyTreeState(*last_transform, *last_clip, effect_root), destination);
+
+ // Since the cull rect mapping above can produce extremely large numbers in
+ // cases of perspective, try our best to "normalize" the result by ensuring
+ // that none of the rect dimensions exceed some large, but reasonable, limit.
+ // Note that by clamping X and Y, we are effectively moving the rect right /
+ // down. However, this will at most make us paint more content, which is
+ // better than erroneously deciding that the rect produced here is far
+ // offscreen.
+ if (rect_.X() < -kReasonablePixelLimit)
+ rect_.SetX(-kReasonablePixelLimit);
+ if (rect_.Y() < -kReasonablePixelLimit)
+ rect_.SetY(-kReasonablePixelLimit);
+ if (rect_.MaxX() > kReasonablePixelLimit)
+ rect_.ShiftMaxXEdgeTo(kReasonablePixelLimit);
+ if (rect_.MaxY() > kReasonablePixelLimit)
+ rect_.ShiftMaxYEdgeTo(kReasonablePixelLimit);
+
+ const IntSize* expansion_bounds = nullptr;
+ bool expanded = false;
+ if (last_scroll_translation_result == kExpandedForPartialScrollingContents &&
+ last_clip == &destination.Clip()) {
+ DCHECK(last_transform->ScrollNode());
+ expansion_bounds = &last_transform->ScrollNode()->ContentsSize();
+ expanded = true;
+ } else if (!IsInfinite() && last_transform != &destination.Transform() &&
+ destination.Transform().HasDirectCompositingReasons()) {
+ // Direct compositing reasons such as will-change transform can cause the
+ // content to move arbitrarily, so there is no exact cull rect. Instead of
+ // using an infinite rect, we use a heuristic of expanding by
+ // |pixel_distance_to_expand|. To avoid extreme expansion in the presence
+ // of nested composited transforms, the heuristic is skipped for rects that
+ // are already very large.
+ int pixel_distance_to_expand =
+ LocalPixelDistanceToExpand(root.Transform(), destination.Transform());
+ if (rect_.Width() < pixel_distance_to_expand) {
+ rect_.InflateX(pixel_distance_to_expand);
+ expanded = true;
+ }
+ if (rect_.Height() < pixel_distance_to_expand) {
+ rect_.InflateY(pixel_distance_to_expand);
+ expanded = true;
+ }
+ }
+
+ if (expanded && old_cull_rect &&
+ !ChangedEnough(*old_cull_rect, expansion_bounds))
+ rect_ = old_cull_rect->Rect();
+}
+
+bool CullRect::ChangedEnough(const CullRect& old_cull_rect,
+ const IntSize* expansion_bounds) const {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+ RuntimeEnabledFeatures::CullRectUpdateEnabled());
const auto& new_rect = Rect();
const auto& old_rect = old_cull_rect.Rect();
- if (old_rect == new_rect || (old_rect.IsEmpty() && new_rect.IsEmpty()))
+ if (old_rect.Contains(new_rect))
+ return false;
+ if (old_rect.IsEmpty() && new_rect.IsEmpty())
return false;
if (old_rect.IsEmpty())
return true;
+ static constexpr int kChangedEnoughMinimumDistance = 512;
auto expanded_old_rect = old_rect;
- static const int kChangedEnoughMinimumDistance = 512;
expanded_old_rect.Inflate(kChangedEnoughMinimumDistance);
- return !expanded_old_rect.Contains(new_rect);
+ if (!expanded_old_rect.Contains(new_rect))
+ return true;
+
+ // The following edge checking logic applies only when the bounds (which were
+ // used to clip the cull rect) are known.
+ if (!expansion_bounds)
+ return false;
+
+ // The cull rect must have been clipped by *expansion_bounds.
+ DCHECK(IntRect(IntPoint(), *expansion_bounds).Contains(rect_));
+
+ // Even if the new cull rect doesn't include enough new area to satisfy
+ // the condition above, update anyway if it touches the edge of the scrolling
+ // contents that is not touched by the existing cull rect. Because it's
+ // impossible to expose more area in the direction, update cannot be deferred
+ // until the exposed new area satisfies the condition above.
+ // For example,
+ // scroller contents dimensions: 100x1000
+ // old cull rect: 0,100 100x8000
+ // A new rect of 0,0 100x8000 will not be |kChangedEnoughMinimumDistance|
+ // pixels away from the current rect. Without additional logic for this case,
+ // we will continue using the old cull rect.
+ if (rect_.X() == 0 && old_cull_rect.Rect().X() != 0)
+ return true;
+ if (rect_.Y() == 0 && old_cull_rect.Rect().Y() != 0)
+ return true;
+ if (rect_.MaxX() == expansion_bounds->Width() &&
+ old_cull_rect.Rect().MaxX() != expansion_bounds->Width())
+ return true;
+ if (rect_.MaxY() == expansion_bounds->Height() &&
+ old_cull_rect.Rect().MaxY() != expansion_bounds->Height())
+ return true;
+
+ return false;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
index 522abc7fe4c..6943c79e481 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h
@@ -18,6 +18,7 @@ class AffineTransform;
class FloatRect;
class LayoutRect;
class LayoutUnit;
+class PropertyTreeState;
class TransformPaintPropertyNode;
class PLATFORM_EXPORT CullRect {
@@ -47,9 +48,9 @@ class PLATFORM_EXPORT CullRect {
// 1. it's clipped by the container rect,
// 2. transformed by inverse of the scroll translation,
// 3. expanded by thousands of pixels for composited scrolling.
- void ApplyTransform(const TransformPaintPropertyNode& transform) {
- ApplyTransformInternal(transform);
- }
+ // 4. clipped by the contents rect.
+ // TODO(wangxianzhu): Remove this function for CullRectUpdate.
+ void ApplyTransform(const TransformPaintPropertyNode&);
// For CompositeAfterPaint only. Applies transforms from |source| (not
// included) to |destination| (included). For each scroll translation, the
@@ -58,10 +59,21 @@ class PLATFORM_EXPORT CullRect {
// doesn't cover the whole scrolling contents, and the new cull rect doesn't
// change enough (by hundreds of pixels) from |old_cull_rect|, the cull rect
// will be set to |old_cull_rect| to avoid repaint on each composited scroll.
+ // TODO(wangxianzhu): Remove this function for CullRectUpdate.
void ApplyTransforms(const TransformPaintPropertyNode& source,
const TransformPaintPropertyNode& destination,
const base::Optional<CullRect>& old_cull_rect);
+ // For CullRectUpdate only. Similar to the above but also applies clips and
+ // expands for all directly composited transforms (including scrolling and
+ // non-scrolling ones). |root| is used to calculate the expansion distance in
+ // the local space, to make the expansion distance approximately the same in
+ // the root space.
+ void ApplyPaintProperties(const PropertyTreeState& root,
+ const PropertyTreeState& source,
+ const PropertyTreeState& destination,
+ const base::Optional<CullRect>& old_cull_rect);
+
const IntRect& Rect() const { return rect_; }
String ToString() const { return rect_.ToString(); }
@@ -82,10 +94,17 @@ class PLATFORM_EXPORT CullRect {
// doesn't cover the whole scrolling contents.
kExpandedForPartialScrollingContents,
};
- ApplyTransformResult ApplyTransformInternal(
- const TransformPaintPropertyNode&);
+ ApplyTransformResult ApplyScrollTranslation(
+ const TransformPaintPropertyNode& root_transform,
+ const TransformPaintPropertyNode& scroll_translation);
+
+ void ApplyTransformWithoutExpansion(const TransformPaintPropertyNode&);
+ void ApplyPaintPropertiesWithoutExpansion(
+ const PropertyTreeState& source,
+ const PropertyTreeState& destination);
- bool ChangedEnough(const CullRect& old_cull_rect) const;
+ bool ChangedEnough(const CullRect& old_cull_rect,
+ const IntSize* bounds) const;
IntRect rect_;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
index c381bd3ea5f..be468e895f6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
@@ -21,14 +21,27 @@ class CullRectTest : public testing::Test {
const CullRect::ApplyTransformResult kExpandedForWholeScrollingContents =
CullRect::kExpandedForWholeScrollingContents;
- CullRect::ApplyTransformResult ApplyTransform(
+ // Tests only transforms without clips.
+ void ApplyTransforms(CullRect& cull_rect,
+ const TransformPaintPropertyNode& source,
+ const TransformPaintPropertyNode& destination,
+ const base::Optional<CullRect>& old_cull_rect) {
+ PropertyTreeState source_state(source, c0(), e0());
+ PropertyTreeState destination_state(destination, c0(), e0());
+ cull_rect.ApplyPaintProperties(PropertyTreeState::Root(), source_state,
+ destination_state, old_cull_rect);
+ }
+
+ CullRect::ApplyTransformResult ApplyScrollTranslation(
CullRect& cull_rect,
const TransformPaintPropertyNode& t) {
- return cull_rect.ApplyTransformInternal(t);
+ return cull_rect.ApplyScrollTranslation(t, t);
}
- bool ChangedEnough(const IntRect& old_rect, const IntRect& new_rect) {
- return CullRect(new_rect).ChangedEnough(CullRect(old_rect));
+ bool ChangedEnough(const IntRect& old_rect,
+ const IntRect& new_rect,
+ const IntSize* bounds = nullptr) {
+ return CullRect(new_rect).ChangedEnough(CullRect(old_rect), bounds);
}
};
@@ -91,7 +104,7 @@ TEST_F(CullRectTest, ApplyTransform) {
CullRect cull_rect(IntRect(1, 1, 50, 50));
auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 1));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *transform));
+ cull_rect.ApplyTransform(*transform);
EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect());
}
@@ -100,13 +113,12 @@ TEST_F(CullRectTest, ApplyTransformInfinite) {
CullRect cull_rect = CullRect::Infinite();
auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 1));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *transform));
-
+ cull_rect.ApplyTransform(*transform);
EXPECT_TRUE(cull_rect.IsInfinite());
}
TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -118,24 +130,25 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kExpandedForPartialScrollingContents,
- ApplyTransform(cull_rect, *scroll_translation));
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50)
// Inverse transformed: (3020, 5010, 30, 50)
// Expanded: (-980, 1010, 8030, 8050)
- EXPECT_EQ(IntRect(-980, 1010, 8030, 8050), cull_rect.Rect());
+ // Then clipped by the contents rect.
+ EXPECT_EQ(IntRect(0, 1010, 7050, 6990), cull_rect.Rect());
cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForPartialScrollingContents,
- ApplyTransform(cull_rect, *scroll_translation));
- // This result differs from the above result in height (8040 vs 8030)
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
+ // This result differs from the above result in height (7050 vs 7060)
// because it's not clipped by the infinite input cull rect.
- EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect.Rect());
+ EXPECT_EQ(IntRect(0, 1010, 7060, 6990), cull_rect.Rect());
}
TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationPartialScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -146,21 +159,23 @@ TEST_F(CullRectTest,
CreateScrollTranslation(t0(), -3000, -5000, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50)
// Inverse transformed: (3020, 5010, 30, 50)
EXPECT_EQ(IntRect(3020, 5010, 30, 50), cull_rect.Rect());
cull_rect = CullRect::Infinite();
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (40 vs 30)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(3020, 5010, 40, 50), cull_rect.Rect());
}
TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(200, 100, 40, 50);
@@ -171,13 +186,14 @@ TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
CreateCompositedScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
EXPECT_TRUE(cull_rect.Rect().IsEmpty());
}
TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationNoIntersectionWithContainerRect) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(200, 100, 40, 50);
@@ -187,12 +203,13 @@ TEST_F(CullRectTest,
auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
EXPECT_TRUE(cull_rect.Rect().IsEmpty());
}
TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -204,24 +221,23 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kExpandedForWholeScrollingContents,
- ApplyTransform(cull_rect, *scroll_translation));
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50)
// Inverse transformed: (30, 25, 30, 50)
// Expanded: (-3970, -3975, 8030, 8050)
- EXPECT_EQ(IntRect(-3970, -3975, 8030, 8050), cull_rect.Rect());
+ // Then clipped by the contents rect.
+ EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect.Rect());
cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForWholeScrollingContents,
- ApplyTransform(cull_rect, *scroll_translation));
- // This result differs from the above result in height (8040 vs 8030)
- // because it's not clipped by the infinite input cull rect.
- EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect.Rect());
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
+ EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect.Rect());
}
TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationWholeScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50);
@@ -231,21 +247,23 @@ TEST_F(CullRectTest,
auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100));
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50)
// Inverse transformed: (30, 25, 30, 50)
EXPECT_EQ(IntRect(30, 25, 30, 50), cull_rect.Rect());
cull_rect = CullRect::Infinite();
- EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation));
+ EXPECT_EQ(kNotExpanded,
+ ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (40 vs 30)
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(30, 25, 40, 50), cull_rect.Rect());
}
TEST_F(CullRectTest, ChangedEnoughEmpty) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
EXPECT_FALSE(ChangedEnough(IntRect(), IntRect()));
EXPECT_FALSE(ChangedEnough(IntRect(1, 1, 0, 0), IntRect(2, 2, 0, 0)));
EXPECT_TRUE(ChangedEnough(IntRect(), IntRect(0, 0, 1, 1)));
@@ -253,7 +271,7 @@ TEST_F(CullRectTest, ChangedEnoughEmpty) {
}
TEST_F(CullRectTest, ChangedNotEnough) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
IntRect old_rect(100, 100, 100, 100);
EXPECT_FALSE(ChangedEnough(old_rect, old_rect));
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 90, 90)));
@@ -261,8 +279,8 @@ TEST_F(CullRectTest, ChangedNotEnough) {
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(1, 1, 200, 200)));
}
-TEST_F(CullRectTest, ChangedEnoughScrollScenarios) {
- ScopedCompositeAfterPaintForTest cap(true);
+TEST_F(CullRectTest, ChangedEnoughOnMovement) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
IntRect old_rect(100, 100, 100, 100);
IntRect new_rect(old_rect);
new_rect.Move(500, 0);
@@ -275,241 +293,351 @@ TEST_F(CullRectTest, ChangedEnoughScrollScenarios) {
EXPECT_TRUE(ChangedEnough(old_rect, new_rect));
}
-TEST_F(CullRectTest, ApplyTransformsSameTransform) {
- ScopedCompositeAfterPaintForTest cap(true);
+TEST_F(CullRectTest, ChangedEnoughNewRectTouchingEdge) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+ IntSize bounds(500, 500);
+ IntRect old_rect(100, 100, 100, 100);
+ // Top edge.
+ EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 50, 100, 200), &bounds));
+ EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 0, 100, 200), &bounds));
+ // Left edge.
+ EXPECT_FALSE(ChangedEnough(old_rect, IntRect(50, 100, 200, 100), &bounds));
+ EXPECT_TRUE(ChangedEnough(old_rect, IntRect(0, 100, 200, 100), &bounds));
+ // Bottom edge.
+ EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 100, 350), &bounds));
+ EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 100, 100, 400), &bounds));
+ // Right edge.
+ EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 350, 100), &bounds));
+ EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 100, 400, 100), &bounds));
+}
+
+TEST_F(CullRectTest, ChangedEnoughOldRectTouchingEdge) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+ IntSize bounds(500, 500);
+ IntRect new_rect(100, 100, 300, 300);
+ // Top edge.
+ EXPECT_FALSE(ChangedEnough(IntRect(100, 0, 100, 100), new_rect, &bounds));
+ // Left edge.
+ EXPECT_FALSE(ChangedEnough(IntRect(0, 100, 100, 100), new_rect, &bounds));
+ // Bottom edge.
+ EXPECT_FALSE(ChangedEnough(IntRect(300, 400, 100, 100), new_rect, &bounds));
+ // Right edge.
+ EXPECT_FALSE(ChangedEnough(IntRect(400, 300, 100, 100), new_rect, &bounds));
+}
+
+TEST_F(CullRectTest, ApplyPaintPropertiesSameState) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ auto clip = CreateClip(c0(), t0(), FloatRoundedRect(1, 2, 3, 4));
+ PropertyTreeState root = PropertyTreeState::Root();
+ PropertyTreeState state(*transform, *clip, e0());
+
CullRect cull_rect1(IntRect(1, 1, 50, 50));
- cull_rect1.ApplyTransforms(*transform, *transform, base::nullopt);
+ cull_rect1.ApplyPaintProperties(state, state, state, base::nullopt);
+ EXPECT_EQ(IntRect(1, 1, 50, 50), cull_rect1.Rect());
+ cull_rect1.ApplyPaintProperties(root, state, state, base::nullopt);
EXPECT_EQ(IntRect(1, 1, 50, 50), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(1, 1, 50, 50));
// Should ignore old_cull_rect.
- cull_rect2.ApplyTransforms(*transform, *transform, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(state, state, state, old_cull_rect);
+ EXPECT_EQ(cull_rect1, cull_rect2);
+ cull_rect2.ApplyPaintProperties(root, state, state, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
CullRect infinite = CullRect::Infinite();
- infinite.ApplyTransforms(*transform, *transform, base::nullopt);
+ infinite.ApplyPaintProperties(state, state, state, base::nullopt);
+ EXPECT_TRUE(infinite.IsInfinite());
+ infinite.ApplyPaintProperties(root, state, state, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite());
}
-TEST_F(CullRectTest, ApplyTransformsWithoutScroll) {
- ScopedCompositeAfterPaintForTest cap(true);
+TEST_F(CullRectTest, ApplyPaintPropertiesWithoutClipScroll) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(10, 20));
+ PropertyTreeState root = PropertyTreeState::Root();
+ PropertyTreeState state1(*t1, c0(), e0());
+ PropertyTreeState state2(*t2, c0(), e0());
CullRect cull_rect1(IntRect(1, 1, 50, 50));
- cull_rect1.ApplyTransforms(*t1, *t2, base::nullopt);
+ cull_rect1.ApplyPaintProperties(root, state1, state2, base::nullopt);
EXPECT_EQ(IntRect(-9, -19, 50, 50), cull_rect1.Rect());
CullRect cull_rect2(IntRect(1, 1, 50, 50));
- cull_rect2.ApplyTransforms(t0(), *t2, base::nullopt);
+ cull_rect2.ApplyPaintProperties(root, root, state2, base::nullopt);
EXPECT_EQ(IntRect(-10, -21, 50, 50), cull_rect2.Rect());
CullRect old_cull_rect = cull_rect2;
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect3(IntRect(1, 1, 50, 50));
// Should ignore old_cull_rect.
- cull_rect3.ApplyTransforms(t0(), *t2, old_cull_rect);
+ cull_rect3.ApplyPaintProperties(root, root, state2, old_cull_rect);
EXPECT_EQ(cull_rect2, cull_rect3);
CullRect infinite = CullRect::Infinite();
- infinite.ApplyTransforms(t0(), *t2, base::nullopt);
+ infinite.ApplyPaintProperties(root, root, state2, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite());
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
- auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ ScopedCullRectUpdateForTest cull_rect_update(true);
- ScrollPaintPropertyNode::State scroll_state;
- scroll_state.container_rect = IntRect(20, 10, 40, 50);
- scroll_state.contents_size = IntSize(2000, 2000);
- auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(),
- std::move(scroll_state));
- auto scroll_translation =
- CreateCompositedScrollTranslation(*t1, -10, -15, *scroll);
+ auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ PropertyTreeState state1(*t1, c0(), e0());
+ auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
+ state1, -10, -15, IntRect(20, 10, 40, 50), IntSize(2000, 2000));
+ auto scroll_translation_state =
+ ref_scroll_translation_state.GetPropertyTreeState().Unalias();
// Same as ApplyScrollTranslationWholeScrollingContents.
CullRect cull_rect1(IntRect(0, 0, 50, 100));
- cull_rect1.ApplyTransforms(*t1, *scroll_translation, base::nullopt);
- EXPECT_EQ(IntRect(-3970, -3975, 8030, 8050), cull_rect1.Rect());
+ cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ base::nullopt);
+ EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect.
- cull_rect2.ApplyTransforms(*t1, *scroll_translation, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
CullRect cull_rect3 = CullRect::Infinite();
- cull_rect3.ApplyTransforms(*t1, *scroll_translation, base::nullopt);
- // This result differs from the first result in height (8040 vs 8030)
- // because it's not clipped by the infinite input cull rect.
- EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect3.Rect());
+ cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ base::nullopt);
+ EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect3.Rect());
}
TEST_F(CullRectTest, ApplyTransformsWithOrigin) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto t2 = CreateTransform(*t1, TransformationMatrix().Scale(0.5),
FloatPoint3D(50, 100, 0));
+ PropertyTreeState root = PropertyTreeState::Root();
+ PropertyTreeState state1(*t1, c0(), e0());
+ PropertyTreeState state2(*t2, c0(), e0());
CullRect cull_rect1(IntRect(0, 0, 50, 200));
- cull_rect1.ApplyTransforms(*t1, *t2, base::nullopt);
+ cull_rect1.ApplyPaintProperties(root, state1, state2, base::nullopt);
EXPECT_EQ(IntRect(-50, -100, 100, 400), cull_rect1.Rect());
}
TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ PropertyTreeState state1(*t1, c0(), e0());
- ScrollPaintPropertyNode::State scroll_state;
- scroll_state.container_rect = IntRect(20, 10, 40, 50);
- scroll_state.contents_size = IntSize(8000, 8000);
- auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(),
- std::move(scroll_state));
- auto scroll_translation =
- CreateCompositedScrollTranslation(*t1, -3000, -5000, *scroll);
+ auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
+ state1, -3000, -5000, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
+ auto scroll_translation_state =
+ ref_scroll_translation_state.GetPropertyTreeState().Unalias();
// Same as ApplyScrollTranslationPartialScrollingContents.
CullRect cull_rect1(IntRect(0, 0, 50, 100));
- cull_rect1.ApplyTransforms(*t1, *scroll_translation, base::nullopt);
- EXPECT_EQ(IntRect(-980, 1010, 8030, 8050), cull_rect1.Rect());
+ cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ base::nullopt);
+ EXPECT_EQ(IntRect(0, 1010, 7050, 6990), cull_rect1.Rect());
- CullRect old_cull_rect = cull_rect1;
- old_cull_rect.Move(IntSize(1, 1));
+ CullRect old_cull_rect(IntRect(0, 1100, 7050, 6900));
CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Use old_cull_rect if the new cull rect didn't change enough.
- cull_rect2.ApplyTransforms(*t1, *scroll_translation, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ old_cull_rect);
EXPECT_EQ(old_cull_rect, cull_rect2);
old_cull_rect.Move(IntSize(1000, 1000));
CullRect cull_rect3(IntRect(0, 0, 50, 100));
// Use the new cull rect if it changed enough.
- cull_rect3.ApplyTransforms(*t1, *scroll_translation, old_cull_rect);
+ cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3);
CullRect cull_rect4 = CullRect::Infinite();
- cull_rect4.ApplyTransforms(*t1, *scroll_translation, base::nullopt);
- // This result differs from the first result in height (8040 vs 8030)
+ cull_rect4.ApplyPaintProperties(state1, state1, scroll_translation_state,
+ base::nullopt);
+ // This result differs from the first result in height (7050 vs 7060)
// because it's not clipped by the infinite input cull rect.
- EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect4.Rect());
+ EXPECT_EQ(IntRect(0, 1010, 7060, 6990), cull_rect4.Rect());
}
TEST_F(CullRectTest, ApplyTransformsEscapingScroll) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
+ PropertyTreeState root = PropertyTreeState::Root();
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(111, 222, 333, 444));
+ PropertyTreeState state1(*t1, *c1, e0());
- ScrollPaintPropertyNode::State scroll_state;
- scroll_state.container_rect = IntRect(20, 10, 40, 50);
- scroll_state.contents_size = IntSize(8000, 8000);
- auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(),
- std::move(scroll_state));
- auto scroll_translation =
- CreateCompositedScrollTranslation(*t1, -3000, -5000, *scroll);
- auto t2 = CreateTransform(*scroll_translation,
+ auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
+ state1, -3000, -5000, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
+ auto scroll_translation_state =
+ ref_scroll_translation_state.GetPropertyTreeState().Unalias();
+
+ auto t2 = CreateTransform(scroll_translation_state.Transform(),
TransformationMatrix().Translate(100, 200));
+ PropertyTreeState state2(*t2, scroll_translation_state.Clip(), e0());
CullRect cull_rect1(IntRect(0, 0, 50, 100));
- // Just apply tranforms without clipping and expansion for scroll translation.
- cull_rect1.ApplyTransforms(*t2, *t1, base::nullopt);
- EXPECT_EQ(IntRect(-2900, -4800, 50, 100), cull_rect1.Rect());
+ // Ignore the current cull rect, and apply paint properties from root to
+ // state1 on infinite cull rect instead.
+ cull_rect1.ApplyPaintProperties(root, state2, state1, base::nullopt);
+ EXPECT_EQ(IntRect(110, 220, 333, 444), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect.
- cull_rect2.ApplyTransforms(*t2, *t1, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(root, state2, state1, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
- CullRect infinite = CullRect::Infinite();
- infinite.ApplyTransforms(*t2, *t1, base::nullopt);
- EXPECT_TRUE(infinite.IsInfinite());
+ CullRect cull_rect3 = CullRect::Infinite();
+ cull_rect3.ApplyPaintProperties(root, state2, state1, base::nullopt);
+ EXPECT_EQ(cull_rect1, cull_rect3);
}
TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ PropertyTreeState state1(*t1, c0(), e0());
- ScrollPaintPropertyNode::State scroll_state1;
- scroll_state1.container_rect = IntRect(20, 10, 40, 50);
- scroll_state1.contents_size = IntSize(8000, 8000);
- auto scroll1 = ScrollPaintPropertyNode::Create(
- ScrollPaintPropertyNode::Root(), std::move(scroll_state1));
- auto scroll_translation1 =
- CreateCompositedScrollTranslation(*t1, -10, -15, *scroll1);
+ auto ref_scroll_translation_state1 = CreateCompositedScrollTranslationState(
+ state1, -10, -15, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
+ auto scroll_translation_state1 =
+ ref_scroll_translation_state1.GetPropertyTreeState().Unalias();
- auto t2 = CreateTransform(*scroll_translation1,
+ auto t2 = CreateTransform(scroll_translation_state1.Transform(),
TransformationMatrix().Translate(2000, 3000));
+ PropertyTreeState state2(*t2, scroll_translation_state1.Clip(), e0());
- ScrollPaintPropertyNode::State scroll_state2;
- scroll_state2.container_rect = IntRect(30, 20, 100, 200);
- scroll_state2.contents_size = IntSize(200, 400);
- auto scroll2 = ScrollPaintPropertyNode::Create(
- ScrollPaintPropertyNode::Root(), std::move(scroll_state2));
- auto scroll_translation2 =
- CreateCompositedScrollTranslation(*t2, -10, -15, *scroll2);
+ auto ref_scroll_translation_state2 = CreateCompositedScrollTranslationState(
+ state2, -10, -15, IntRect(30, 20, 100, 200), IntSize(200, 400));
+ auto scroll_translation_state2 =
+ ref_scroll_translation_state2.GetPropertyTreeState().Unalias();
CullRect cull_rect1(IntRect(0, 0, 50, 100));
- cull_rect1.ApplyTransforms(*t1, *scroll_translation2, base::nullopt);
- EXPECT_EQ(IntRect(-3960, -3965, 8100, 8200), cull_rect1.Rect());
+ cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state2,
+ base::nullopt);
+ EXPECT_EQ(IntRect(0, 0, 200, 400), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect.
- cull_rect2.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state2,
+ old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
}
TEST_F(CullRectTest, ApplyTransformsBigScrollContentsAfterSmallScrollContents) {
- ScopedCompositeAfterPaintForTest cap(true);
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
+ PropertyTreeState state1(*t1, c0(), e0());
- ScrollPaintPropertyNode::State scroll_state1;
- scroll_state1.container_rect = IntRect(30, 20, 100, 200);
- scroll_state1.contents_size = IntSize(200, 400);
- auto scroll1 = ScrollPaintPropertyNode::Create(
- ScrollPaintPropertyNode::Root(), std::move(scroll_state1));
- auto scroll_translation1 =
- CreateCompositedScrollTranslation(*t1, -10, -15, *scroll1);
+ auto ref_scroll_translation_state1 = CreateCompositedScrollTranslationState(
+ state1, -10, -15, IntRect(30, 20, 100, 200), IntSize(200, 400));
+ auto scroll_translation_state1 =
+ ref_scroll_translation_state1.GetPropertyTreeState().Unalias();
- auto t2 = CreateTransform(*scroll_translation1,
+ auto t2 = CreateTransform(scroll_translation_state1.Transform(),
TransformationMatrix().Translate(10, 20));
+ PropertyTreeState state2(*t2, scroll_translation_state1.Clip(), e0());
- ScrollPaintPropertyNode::State scroll_state2;
- scroll_state2.container_rect = IntRect(20, 10, 50, 100);
- scroll_state2.contents_size = IntSize(10000, 20000);
- auto scroll2 = ScrollPaintPropertyNode::Create(
- ScrollPaintPropertyNode::Root(), std::move(scroll_state2));
- auto scroll_translation2 =
- CreateCompositedScrollTranslation(*t2, -3000, -5000, *scroll2);
+ auto ref_scroll_translation_state2 = CreateCompositedScrollTranslationState(
+ state2, -3000, -5000, IntRect(20, 10, 50, 100), IntSize(10000, 20000));
+ auto scroll_translation_state2 =
+ ref_scroll_translation_state2.GetPropertyTreeState().Unalias();
CullRect cull_rect1(IntRect(0, 0, 100, 200));
- cull_rect1.ApplyTransforms(*t1, *scroll_translation2, base::nullopt);
+ cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state2,
+ base::nullopt);
// After the first scroll: (-3960, -3965, 8070, 8180)
// After t2: (-3980, -3975, 8070, 8180)
// Clipped by the container rect of the second scroll: (20, 10, 50, 100)
// After the second scroll offset: (3020, 5010, 50, 100)
// Expanded: (-980, 1010, 8050, 8100)
- EXPECT_EQ(IntRect(-980, 1010, 8050, 8100), cull_rect1.Rect());
+ // Then clipped by the contents rect.
+ EXPECT_EQ(IntRect(0, 1010, 7070, 8100), cull_rect1.Rect());
- CullRect old_cull_rect = cull_rect1;
- old_cull_rect.Move(IntSize(1, 1));
+ CullRect old_cull_rect(IntRect(0, 1100, 7070, 8100));
CullRect cull_rect2(IntRect(0, 0, 100, 200));
// Use old_cull_rect if the new cull rect didn't change enough.
- cull_rect2.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect);
+ cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state2,
+ old_cull_rect);
EXPECT_EQ(old_cull_rect, cull_rect2);
old_cull_rect.Move(IntSize(1000, 1000));
CullRect cull_rect3(IntRect(0, 0, 100, 200));
// Use the new cull rect if it changed enough.
- cull_rect3.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect);
+ cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state2,
+ old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3);
}
+TEST_F(CullRectTest, NonCompositedTransformUnderClip) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
+ PropertyTreeState root = PropertyTreeState::Root();
+ auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(100, 200, 300, 400));
+ auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(10, 20));
+ PropertyTreeState state1(*t1, *c1, e0());
+
+ CullRect cull_rect1(IntRect(0, 0, 300, 500));
+ cull_rect1.ApplyPaintProperties(root, root, state1, base::nullopt);
+ // Clip by c1, then transformed by t1.
+ EXPECT_EQ(IntRect(90, 180, 200, 300), cull_rect1.Rect());
+
+ CullRect cull_rect2(IntRect(0, 0, 300, 500));
+ CullRect old_cull_rect(IntRect(133, 244, 333, 444));
+ // Should ignore old_cull_rect.
+ cull_rect2.ApplyPaintProperties(root, root, state1, old_cull_rect);
+ EXPECT_EQ(cull_rect1, cull_rect2);
+
+ CullRect cull_rect3 = CullRect::Infinite();
+ cull_rect3.ApplyPaintProperties(root, root, state1, base::nullopt);
+ EXPECT_EQ(IntRect(90, 180, 300, 400), cull_rect3.Rect());
+}
+
+TEST_F(CullRectTest, CompositedTranslationUnderClip) {
+ ScopedCullRectUpdateForTest cull_rect_update(true);
+
+ PropertyTreeState root = PropertyTreeState::Root();
+ auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(100, 200, 300, 400));
+ auto t1 = CreateTransform(
+ t0(), TransformationMatrix().Translate(10, 20).Scale3d(2, 3, 1),
+ FloatPoint3D(), CompositingReason::kWillChangeTransform);
+ PropertyTreeState state1(*t1, *c1, e0());
+
+ CullRect cull_rect1(IntRect(0, 0, 300, 500));
+ cull_rect1.ApplyPaintProperties(root, root, state1, base::nullopt);
+ // The result in NonCompositedTransformUnderClip expanded by 2000 (scaled by
+ // maximum of 1/2 and 1/3).
+ EXPECT_EQ(IntRect(-1955, -1940, 4100, 4100), cull_rect1.Rect());
+
+ CullRect cull_rect2(IntRect(0, 0, 300, 500));
+ CullRect old_cull_rect = cull_rect1;
+ old_cull_rect.Move(IntSize(200, 200));
+ // Use old_cull_rect if the new cull rect didn't change enough.
+ cull_rect2.ApplyPaintProperties(root, root, state1, old_cull_rect);
+ EXPECT_EQ(old_cull_rect, cull_rect2);
+
+ CullRect cull_rect3(IntRect(0, 0, 300, 500));
+ old_cull_rect.Move(IntSize(1000, 1000));
+ // Use the new cull rect if it changed enough.
+ cull_rect3.ApplyPaintProperties(root, root, state1, old_cull_rect);
+ EXPECT_EQ(cull_rect1, cull_rect3);
+
+ CullRect cull_rect4 = CullRect::Infinite();
+ cull_rect4.ApplyPaintProperties(root, root, state1, base::nullopt);
+ EXPECT_EQ(IntRect(-1955, -1940, 4150, 4134), cull_rect4.Rect());
+}
+
TEST_F(CullRectTest, IntersectsVerticalRange) {
CullRect cull_rect(IntRect(0, 0, 50, 100));
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.cc
index 5560ac3d102..aaa92fbfa92 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.cc
@@ -36,13 +36,14 @@ String DisplayItemClient::SafeDebugName(bool known_to_be_safe) const {
return DebugName();
}
- // If the caller is not sure, we must ensure the client is alive, and it's
- // not a destroyed client at the same address of a new client.
+ // If the caller is not sure, we must ensure the client is alive.
+ if (!IsAlive())
+ return "DEAD";
+
if (IsJustCreated())
return "Just created:" + DebugName();
- if (IsAlive())
- return DebugName();
- return "DEAD";
+
+ return DebugName();
}
#endif // DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.h b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
index a22a27f4c2b..801a06306fa 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
@@ -47,10 +47,8 @@ class PLATFORM_EXPORT DisplayItemClient {
virtual String DebugName() const = 0;
- // Needed for paint chunk clients only. Returns the id of the DOM node
- // associated with this DisplayItemClient, or kInvalidDOMNodeId if there is no
- // associated DOM node or this DisplayItemClient is never used as a paint
- // chunk client.
+ // Returns the id of the DOM node associated with this DisplayItemClient, or
+ // kInvalidDOMNodeId if there is no associated DOM node.
virtual DOMNodeId OwnerNodeId() const { return kInvalidDOMNodeId; }
// The outset will be used to inflate visual rect after the visual rect is
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client_test.cc
index 7cc270bd343..850ec26dee5 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_client_test.cc
@@ -12,12 +12,20 @@ namespace {
#if DCHECK_IS_ON() && !defined(UNDEFINED_SANITIZER)
-TEST(DisplayItemClientTest, IsAlive) {
- EXPECT_FALSE(reinterpret_cast<DisplayItemClient*>(0x12345678)->IsAlive());
+TEST(DisplayItemClientTest, IsAliveAndSafeDebugName) {
+ const auto* invalid_client = reinterpret_cast<DisplayItemClient*>(0x12345678);
+ EXPECT_FALSE(invalid_client->IsAlive());
+ EXPECT_EQ("DEAD", invalid_client->SafeDebugName());
+
FakeDisplayItemClient* test_client = new FakeDisplayItemClient;
EXPECT_TRUE(test_client->IsAlive());
+ EXPECT_EQ("Just created:FakeDisplayItemClient", test_client->SafeDebugName());
+ test_client->Validate();
+ EXPECT_EQ("FakeDisplayItemClient", test_client->SafeDebugName());
+
delete test_client;
EXPECT_FALSE(test_client->IsAlive());
+ EXPECT_EQ("DEAD", test_client->SafeDebugName());
}
#endif
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
index b664b76bbc2..8a36a94e320 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.cc
@@ -31,7 +31,7 @@ DrawingRecorder::DrawingRecorder(GraphicsContext& context,
context.SetInDrawingRecorder(true);
context.BeginRecording(FloatRect());
- if (context.Printing()) {
+ if (context.NeedsDOMNodeId()) {
DOMNodeId dom_node_id = display_item_client.OwnerNodeId();
if (dom_node_id != kInvalidDOMNodeId) {
dom_node_id_to_restore_ = context.GetDOMNodeId();
@@ -41,7 +41,7 @@ DrawingRecorder::DrawingRecorder(GraphicsContext& context,
}
DrawingRecorder::~DrawingRecorder() {
- if (context_.Printing() && dom_node_id_to_restore_)
+ if (dom_node_id_to_restore_)
context_.SetDOMNodeId(dom_node_id_to_restore_.value());
context_.SetInDrawingRecorder(false);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
index 17b90c3122b..cdc290ebb50 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
@@ -106,6 +106,8 @@ class PLATFORM_EXPORT GeometryMapper {
matrix_->PostTranslate(x, y);
}
+ SkM44 ToSkM44() const { return TransformationMatrix::ToSkM44(Matrix()); }
+
SkMatrix ToSkMatrix() const {
if (LIKELY(IsIdentityOr2DTranslation())) {
return SkMatrix::Translate(Translation2D().Width(),
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h b/chromium/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h
new file mode 100644
index 00000000000..7bc878f7755
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_LAYER_SELECTION_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_LAYER_SELECTION_DATA_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/platform/graphics/paint/painted_selection_bound.h"
+
+namespace blink {
+
+// Represents paint-related metadata about the start and end of a selection.
+// The information is stored on a paint chunk - note that the frame's selection
+// can start in one paint chunk and end in another, so it's possible for one
+// or both of the bounds to be set. The start and end can also be set
+// independently by different painters within the same paint chunk.
+// In the common case of no selection (or if the selection completely surrounds
+// a paint chunk), neither would be set.
+struct PLATFORM_EXPORT LayerSelectionData {
+ base::Optional<PaintedSelectionBound> start;
+ base::Optional<PaintedSelectionBound> end;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_LAYER_SELECTION_DATA_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
index 50e86f0f4c2..f2250a89331 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
@@ -28,8 +28,11 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> {
public:
explicit PaintArtifact(
- wtf_size_t initial_display_item_list_capacity_in_bytes = 0)
- : display_item_list_(initial_display_item_list_capacity_in_bytes) {}
+ wtf_size_t initial_display_item_list_capacity_in_bytes = 0,
+ wtf_size_t initial_paint_chunks_capacity_in_elements = 0)
+ : display_item_list_(initial_display_item_list_capacity_in_bytes) {
+ chunks_.ReserveInitialCapacity(initial_paint_chunks_capacity_in_elements);
+ }
PaintArtifact(const PaintArtifact& other) = delete;
PaintArtifact& operator=(const PaintArtifact& other) = delete;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.cc
index ef550343f68..7ad9c06a93e 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.cc
@@ -20,6 +20,7 @@ struct SameSizeAsPaintChunk {
IntRect bounds;
IntRect drawable_bounds;
void* hit_test_data;
+ void* layer_selection;
bool b[2];
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
index d12dddb2274..1da661967a7 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/hit_test_data.h"
+#include "third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h"
#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h"
#include "third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -41,6 +42,7 @@ struct PLATFORM_EXPORT PaintChunk {
id(id),
properties(props),
known_to_be_opaque(false),
+ text_known_to_be_on_opaque_background(false),
is_cacheable(id.client.IsCacheable()),
client_is_just_created(id.client.IsJustCreated()),
is_moved_from_cached_subsequence(false) {}
@@ -54,10 +56,13 @@ struct PLATFORM_EXPORT PaintChunk {
id(other.id),
properties(other.properties),
hit_test_data(std::move(other.hit_test_data)),
+ layer_selection_data(std::move(other.layer_selection_data)),
bounds(other.bounds),
drawable_bounds(other.drawable_bounds),
raster_effect_outset(other.raster_effect_outset),
known_to_be_opaque(other.known_to_be_opaque),
+ text_known_to_be_on_opaque_background(
+ other.text_known_to_be_on_opaque_background),
is_cacheable(other.is_cacheable),
client_is_just_created(false),
is_moved_from_cached_subsequence(true) {
@@ -99,6 +104,12 @@ struct PLATFORM_EXPORT PaintChunk {
return *hit_test_data;
}
+ LayerSelectionData& EnsureLayerSelectionData() {
+ if (!layer_selection_data)
+ layer_selection_data = std::make_unique<LayerSelectionData>();
+ return *layer_selection_data;
+ }
+
size_t MemoryUsageInBytes() const;
String ToString() const;
@@ -126,6 +137,7 @@ struct PLATFORM_EXPORT PaintChunk {
RefCountedPropertyTreeState properties;
std::unique_ptr<HitTestData> hit_test_data;
+ std::unique_ptr<LayerSelectionData> layer_selection_data;
// The following fields depend on the display items in this chunk.
// They are updated when a display item is added into the chunk.
@@ -148,6 +160,8 @@ struct PLATFORM_EXPORT PaintChunk {
// True if the bounds are filled entirely with opaque contents.
bool known_to_be_opaque : 1;
+ // True if all text is known to be on top of an opaque background.
+ bool text_known_to_be_on_opaque_background : 1;
// End of derived data.
// The following fields are put here to avoid memory gap.
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
index 2669abf6819..73e5f1e92df 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
@@ -105,10 +105,23 @@ bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) {
}
constexpr wtf_size_t kMaxRegionComplexity = 10;
- if (item.IsDrawing() &&
- static_cast<const DrawingDisplayItem&>(item).KnownToBeOpaque() &&
- last_chunk_known_to_be_opaque_region_.Complexity() < kMaxRegionComplexity)
- last_chunk_known_to_be_opaque_region_.Unite(item.VisualRect());
+ if (should_compute_contents_opaque_ && item.IsDrawing()) {
+ const DrawingDisplayItem& drawing =
+ static_cast<const DrawingDisplayItem&>(item);
+ if (drawing.KnownToBeOpaque() &&
+ last_chunk_known_to_be_opaque_region_.Complexity() <
+ kMaxRegionComplexity) {
+ last_chunk_known_to_be_opaque_region_.Unite(item.VisualRect());
+ }
+ if (last_chunk_text_known_to_be_on_opaque_background_) {
+ if (const auto* paint_record = drawing.GetPaintRecord().get()) {
+ if (paint_record->has_draw_text_ops()) {
+ last_chunk_text_known_to_be_on_opaque_background_ =
+ last_chunk_known_to_be_opaque_region_.Contains(item.VisualRect());
+ }
+ }
+ }
+ }
chunk.raster_effect_outset =
std::max(chunk.raster_effect_outset, item.GetRasterEffectOutset());
@@ -154,6 +167,39 @@ bool PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
return created_new_chunk;
}
+void PaintChunker::AddSelectionToCurrentChunk(
+ base::Optional<PaintedSelectionBound> start,
+ base::Optional<PaintedSelectionBound> end) {
+ // We should have painted the selection when calling this method.
+ DCHECK(chunks_);
+ DCHECK(!chunks_->IsEmpty());
+
+ auto& chunk = chunks_->back();
+
+#if DCHECK_IS_ON()
+ if (start) {
+ IntRect edge_rect(start->edge_start, start->edge_end - start->edge_start);
+ DCHECK(chunk.bounds.Contains(edge_rect));
+ }
+
+ if (end) {
+ IntRect edge_rect(end->edge_start, end->edge_end - end->edge_start);
+ DCHECK(chunk.bounds.Contains(edge_rect));
+ }
+#endif
+
+ LayerSelectionData& selection_data = chunk.EnsureLayerSelectionData();
+ if (start) {
+ DCHECK(!selection_data.start);
+ selection_data.start = start;
+ }
+
+ if (end) {
+ DCHECK(!selection_data.end);
+ selection_data.end = end;
+ }
+}
+
void PaintChunker::CreateScrollHitTestChunk(
const PaintChunk::Id& id,
const TransformPaintPropertyNode* scroll_translation,
@@ -213,9 +259,14 @@ void PaintChunker::FinalizeLastChunkProperties() {
return;
auto& chunk = chunks_->back();
- chunk.known_to_be_opaque =
- last_chunk_known_to_be_opaque_region_.Contains(chunk.bounds);
- last_chunk_known_to_be_opaque_region_ = Region();
+ if (should_compute_contents_opaque_) {
+ chunk.known_to_be_opaque =
+ last_chunk_known_to_be_opaque_region_.Contains(chunk.bounds);
+ chunk.text_known_to_be_on_opaque_background =
+ last_chunk_text_known_to_be_on_opaque_background_;
+ last_chunk_known_to_be_opaque_region_ = Region();
+ last_chunk_text_known_to_be_on_opaque_background_ = true;
+ }
if (candidate_background_color_ != Color::kTransparent) {
chunk.background_color = candidate_background_color_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
index 08ba2dfc7ea..02cfd2bcb55 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/optional.h"
+#include "cc/input/layer_selection_bound.h"
#include "third_party/blink/renderer/platform/geometry/region.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
@@ -52,6 +53,10 @@ class PLATFORM_EXPORT PaintChunker final {
}
bool WillForceNewChunk() const { return will_force_new_chunk_; }
+ void SetShouldComputeContentsOpaque(bool should_compute_) {
+ should_compute_contents_opaque_ = should_compute_;
+ }
+
void AppendByMoving(PaintChunk&&);
// Returns true if a new chunk is created.
@@ -68,6 +73,11 @@ class PLATFORM_EXPORT PaintChunker final {
const TransformPaintPropertyNode* scroll_translation,
const IntRect&);
+ // The id will be used when we need to create a new current chunk.
+ // Otherwise it's ignored. Returns true if a new chunk is added.
+ void AddSelectionToCurrentChunk(base::Optional<PaintedSelectionBound> start,
+ base::Optional<PaintedSelectionBound> end);
+
// Returns true if a new chunk is created.
bool ProcessBackgroundColorCandidate(const PaintChunk::Id& id,
Color color,
@@ -96,12 +106,15 @@ class PLATFORM_EXPORT PaintChunker final {
PropertyTreeState::Uninitialized();
Region last_chunk_known_to_be_opaque_region_;
+ bool last_chunk_text_known_to_be_on_opaque_background_ = true;
// True when an item forces a new chunk (e.g., foreign display items), and for
// the item following a forced chunk. PaintController also forces new chunks
// before and after subsequences by calling ForceNewChunk().
bool will_force_new_chunk_ = true;
+ bool should_compute_contents_opaque_ = true;
+
Color candidate_background_color_ = Color::kTransparent;
float candidate_background_area_ = 0;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
index f6096784be3..a94e3fa2f94 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -79,6 +79,14 @@ void PaintController::RecordScrollHitTestData(
CheckNewChunk();
}
+void PaintController::RecordSelection(
+ base::Optional<PaintedSelectionBound> start,
+ base::Optional<PaintedSelectionBound> end) {
+ DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ DCHECK(start.has_value() || end.has_value());
+ paint_chunker_.AddSelectionToCurrentChunk(start, end);
+}
+
void PaintController::SetPossibleBackgroundColor(
const DisplayItemClient& client,
Color color,
@@ -548,7 +556,8 @@ void PaintController::CommitNewDisplayItems() {
current_paint_artifact_ = std::move(new_paint_artifact_);
if (usage_ == kMultiplePaints) {
new_paint_artifact_ = base::MakeRefCounted<PaintArtifact>(
- current_paint_artifact_->GetDisplayItemList().UsedCapacityInBytes());
+ current_paint_artifact_->GetDisplayItemList().UsedCapacityInBytes(),
+ current_paint_artifact_->PaintChunks().size());
paint_chunker_.ResetChunks(&new_paint_artifact_->PaintChunks());
} else {
new_paint_artifact_ = nullptr;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
index ce9172be409..415bee2f173 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -10,6 +10,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "cc/input/layer_selection_bound.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/graphics/contiguous_container.h"
@@ -99,6 +101,10 @@ class PLATFORM_EXPORT PaintController {
void EnsureChunk();
+ void SetShouldComputeContentsOpaque(bool should_compute) {
+ paint_chunker_.SetShouldComputeContentsOpaque(should_compute);
+ }
+
void RecordHitTestData(const DisplayItemClient&,
const IntRect&,
TouchAction,
@@ -109,6 +115,10 @@ class PLATFORM_EXPORT PaintController {
DisplayItem::Type,
const TransformPaintPropertyNode* scroll_translation,
const IntRect&);
+
+ void RecordSelection(base::Optional<PaintedSelectionBound> start,
+ base::Optional<PaintedSelectionBound> end);
+
void SetPossibleBackgroundColor(const DisplayItemClient&,
Color,
uint64_t area);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node_test.cc
index d87bfc33633..6d003a297b9 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node_test.cc
@@ -347,6 +347,23 @@ TEST_F(PaintPropertyNodeTest, ChangeTransformDuringCompositedAnimation) {
ExpectUnchangedState();
}
+TEST_F(PaintPropertyNodeTest, ChangeTransformOriginDuringCompositedAnimation) {
+ ResetAllChanged();
+ ExpectUnchangedState();
+ TransformPaintPropertyNode::AnimationState animation_state;
+ animation_state.is_running_animation_on_compositor = true;
+ transform.child1->Update(*transform.ancestor,
+ TransformPaintPropertyNode::State{
+ {TransformationMatrix(), FloatPoint3D(1, 2, 3)}},
+ animation_state);
+
+ EXPECT_TRUE(transform.child1->Changed(
+ PaintPropertyChangeType::kChangedOnlySimpleValues, *transform.root));
+
+ ResetAllChanged();
+ ExpectUnchangedState();
+}
+
TEST_F(PaintPropertyNodeTest, TransformChangeOneChild) {
ResetAllChanged();
ExpectUnchangedState();
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
index d3e4b978b0c..f5f010bf778 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc
@@ -10,33 +10,23 @@
namespace blink {
-PaintRecordBuilder::PaintRecordBuilder(
- printing::MetafileSkia* metafile,
- GraphicsContext* containing_context,
- PaintController* paint_controller,
- paint_preview::PaintPreviewTracker* tracker)
- : paint_controller_(nullptr) {
- if (paint_controller) {
- paint_controller_ = paint_controller;
- } else {
- own_paint_controller_ =
- std::make_unique<PaintController>(PaintController::kTransient);
- paint_controller_ = own_paint_controller_.get();
- }
-
+PaintRecordBuilder::PaintRecordBuilder()
+ : own_paint_controller_(new PaintController(PaintController::kTransient)),
+ paint_controller_(own_paint_controller_.get()),
+ context_(new GraphicsContext(*paint_controller_)) {
paint_controller_->UpdateCurrentPaintChunkProperties(
nullptr, PropertyTreeState::Root());
+}
- context_ =
- std::make_unique<GraphicsContext>(*paint_controller_, metafile, tracker);
- if (containing_context) {
- context_->SetDarkModeEnabled(containing_context->IsDarkModeEnabled());
- context_->SetDeviceScaleFactor(containing_context->DeviceScaleFactor());
- context_->SetPrinting(containing_context->Printing());
- context_->SetIsPaintingPreview(containing_context->IsPaintingPreview());
- }
+PaintRecordBuilder::PaintRecordBuilder(GraphicsContext& containing_context)
+ : PaintRecordBuilder() {
+ context_->CopyConfigFrom(containing_context);
}
+PaintRecordBuilder::PaintRecordBuilder(PaintController& paint_controller)
+ : paint_controller_(&paint_controller),
+ context_(new GraphicsContext(*paint_controller_)) {}
+
PaintRecordBuilder::~PaintRecordBuilder() = default;
sk_sp<PaintRecord> PaintRecordBuilder::EndRecording(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
index 446f8d459c7..2d3bbd88374 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h
@@ -24,21 +24,21 @@ class PaintController;
class PLATFORM_EXPORT PaintRecordBuilder final : public DisplayItemClient {
public:
- // Constructs a new builder for the resulting paint record. If |metadata|
- // is specified, that metadata is propagated to the builder's internal canvas.
- // If |containing_context| is specified, the device scale factor, printing,
- // and disabled state are propagated to the builder's internal context.
- // If a PaintController is passed, it is used as the PaintController for
- // painting the picture (and hence we can use its cache). Otherwise, a new
- // transient PaintController is used for the duration of the picture building,
- // which therefore has no caching. It also resets paint chunk state to
- // PropertyTreeState::Root() before beginning to record.
- // TODO(wangxianzhu): Remove the input PaintController feature for
- // CompositeAfterPaint.
- PaintRecordBuilder(printing::MetafileSkia* metafile = nullptr,
- GraphicsContext* containing_context = nullptr,
- PaintController* = nullptr,
- paint_preview::PaintPreviewTracker* tracker = nullptr);
+ // Constructs a new builder for the resulting paint record. A transient
+ // PaintController is created and will be used for the duration of the picture
+ // building, which therefore has no caching. It also resets paint chunk state
+ // to PropertyTreeState::Root() before beginning to record.
+ PaintRecordBuilder();
+
+ // Same as PaintRecordBulder() except that the properties of
+ // |containing_context| such as device scale factor, printing, etc. are
+ // propagated to this builder's internal context.
+ explicit PaintRecordBuilder(GraphicsContext& containing_context);
+
+ // The input PaintController will be used for painting the picture (and hence
+ // we can use its cache).
+ explicit PaintRecordBuilder(PaintController&);
+
~PaintRecordBuilder() override;
GraphicsContext& Context() { return *context_; }
@@ -59,8 +59,8 @@ class PLATFORM_EXPORT PaintRecordBuilder final : public DisplayItemClient {
String DebugName() const final { return "PaintRecordBuilder"; }
private:
- PaintController* paint_controller_;
std::unique_ptr<PaintController> own_paint_controller_;
+ PaintController* paint_controller_;
std::unique_ptr<GraphicsContext> context_;
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc
index f1f6f76992d..142a7f60cfc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder_test.cc
@@ -37,7 +37,7 @@ TEST_F(PaintRecordBuilderTest, TransientPaintController) {
TEST_F(PaintRecordBuilderTest, LastingPaintController) {
InitRootChunk();
- PaintRecordBuilder builder(nullptr, nullptr, &GetPaintController());
+ PaintRecordBuilder builder(GetPaintController());
auto& context = builder.Context();
EXPECT_EQ(&context.GetPaintController(), &GetPaintController());
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/painted_selection_bound.h b/chromium/third_party/blink/renderer/platform/graphics/paint/painted_selection_bound.h
new file mode 100644
index 00000000000..b881dbb0251
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/painted_selection_bound.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINTED_SELECTION_BOUND_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINTED_SELECTION_BOUND_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+#include "third_party/blink/renderer/platform/geometry/float_point.h"
+#include "ui/gfx/selection_bound.h"
+
+namespace blink {
+
+// Blink's notion of cc::LayerSelectionBound. Note that the points are IntPoints
+// to match the painted selection rect, which is always pixel aligned.
+// There is also no layer_id as that is determined at composition time.
+struct PLATFORM_EXPORT PaintedSelectionBound {
+ gfx::SelectionBound::Type type;
+ IntPoint edge_start;
+ IntPoint edge_end;
+ // Whether this bound is hidden (clipped out/occluded) within the painted
+ // content of the layer (as opposed to being outside of the layer's bounds).
+ bool hidden;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINTED_SELECTION_BOUND_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
index 7d19f7a5fc4..c85b65a2b93 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
@@ -16,7 +16,6 @@ const TransformPaintPropertyNode& TransformPaintPropertyNode::Root() {
State{
FloatSize(), &ScrollPaintPropertyNode::Root(),
State::Flags{false /* flattens_inherited_transform */,
- false /* affected_by_outer_viewport_bounds_delta */,
false /* in_subtree_of_page_scale */}})));
return *root;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h b/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
index 41582a40790..56a76e91a71 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
@@ -161,13 +161,13 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
// Use bitfield packing instead of separate bools to save space.
struct Flags {
bool flattens_inherited_transform : 1;
- bool affected_by_outer_viewport_bounds_delta : 1;
bool in_subtree_of_page_scale : 1;
bool animation_is_axis_aligned : 1;
bool delegates_to_parent_for_backface : 1;
// Set if a frame is rooted at this node.
bool is_frame_paint_offset_translation : 1;
- } flags = {false, false, true, false, false, false};
+ bool is_for_svg_child : 1;
+ } flags = {false, true, false, false, false, false};
BackfaceVisibility backface_visibility = BackfaceVisibility::kInherited;
unsigned rendering_context_id = 0;
CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
@@ -186,14 +186,15 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
if (flags.flattens_inherited_transform !=
other.flags.flattens_inherited_transform ||
- flags.affected_by_outer_viewport_bounds_delta !=
- other.flags.affected_by_outer_viewport_bounds_delta ||
flags.in_subtree_of_page_scale !=
other.flags.in_subtree_of_page_scale ||
flags.animation_is_axis_aligned !=
other.flags.animation_is_axis_aligned ||
flags.delegates_to_parent_for_backface !=
other.flags.delegates_to_parent_for_backface ||
+ flags.is_frame_paint_offset_translation !=
+ other.flags.is_frame_paint_offset_translation ||
+ flags.is_for_svg_child != other.flags.is_for_svg_child ||
backface_visibility != other.backface_visibility ||
rendering_context_id != other.rendering_context_id ||
compositor_element_id != other.compositor_element_id ||
@@ -211,7 +212,11 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
bool transform_has_simple_change = true;
if (!transform_changed) {
transform_has_simple_change = false;
- } else if (animation_state.is_running_animation_on_compositor) {
+ } else if (!origin_changed &&
+ animation_state.is_running_animation_on_compositor) {
+ // |is_running_animation_on_compositor| means a transform animation is
+ // running. Composited transform origin animations are not supported so
+ // origin changes need to be considered as simple changes.
transform_has_simple_change = false;
} else if (matrix_changed &&
!transform_and_origin.ChangePreserves2dAxisAlignment(
@@ -319,7 +324,8 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
// used to keep bottom-fixed elements appear fixed to the bottom of the
// screen in the presence of URL bar movement.
bool IsAffectedByOuterViewportBoundsDelta() const {
- return state_.flags.affected_by_outer_viewport_bounds_delta;
+ return DirectCompositingReasons() &
+ CompositingReason::kAffectedByOuterViewportBoundsDelta;
}
// If true, this node is a descendant of the page scale transform. This is
@@ -406,6 +412,11 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
CompositingReason::kActiveTransformAnimation;
}
+ bool RequiresCompositingForScrollDependentPosition() const {
+ return DirectCompositingReasons() &
+ CompositingReason::kScrollDependentPosition;
+ }
+
CompositingReasons DirectCompositingReasonsForDebugging() const {
return DirectCompositingReasons();
}
@@ -444,6 +455,8 @@ class PLATFORM_EXPORT TransformPaintPropertyNode
unsigned RenderingContextId() const { return state_.rendering_context_id; }
bool HasRenderingContext() const { return state_.rendering_context_id; }
+ bool IsForSVGChild() const { return state_.flags.is_for_svg_child; }
+
std::unique_ptr<JSONObject> ToJSON() const;
private:
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.cc b/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.cc
index 084304ea8cc..34e0fa15dee 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.cc
@@ -15,13 +15,13 @@ void PaintGeneratedImage::Draw(cc::PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) {
PaintCanvasAutoRestore ar(canvas, true);
canvas->clipRect(dest_rect);
- canvas->concat(SkMatrix::MakeRectToRect(src_rect, dest_rect,
- SkMatrix::kFill_ScaleToFit));
+ canvas->concat(SkMatrix::RectToRect(src_rect, dest_rect));
SkRect bounds = src_rect;
canvas->saveLayer(&bounds, &flags);
canvas->drawPicture(record_);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.h b/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.h
index 6978106580e..b5a7b35157b 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint_generated_image.h
@@ -25,6 +25,7 @@ class PLATFORM_EXPORT PaintGeneratedImage : public GeneratedImage {
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc b/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
index c645e61fc7a..57cce025621 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
@@ -101,7 +101,7 @@ void PaintWorkletPaintDispatcher::DispatchWorklets(
CrossThreadBindOnce(&PaintWorkletPaintDispatcher::AsyncPaintDone,
dispatcher));
},
- weak_factory_.GetWeakPtr(), WTF::Passed(std::move(runner)));
+ weak_factory_.GetWeakPtr(), std::move(runner));
// Use a base::RepeatingClosure to make sure that AsyncPaintDone is only
// called once, once all the worklets are done. If there are no inputs
@@ -142,8 +142,8 @@ void PaintWorkletPaintDispatcher::DispatchWorklets(
}
on_done_runner->RunAndReset();
},
- WrapCrossThreadPersistent(painter), WTF::Passed(std::move(jobs)),
- WTF::Passed(std::move(on_done_runner))));
+ WrapCrossThreadPersistent(painter), std::move(jobs),
+ std::move(on_done_runner)));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
index 7236054e7d9..5cd5a3a21e6 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
@@ -69,7 +69,7 @@ class PLATFORM_EXPORT PaintWorkletPaintDispatcher {
// The main thread is given a base::WeakPtr to this class to hand to the
// PaintWorklet thread(s), so that they can register and unregister
- // PaintWorklets. See blink::WebFrameWidgetBase for where this happens.
+ // PaintWorklets. See blink::WebFrameWidgetImpl for where this happens.
base::WeakPtr<PaintWorkletPaintDispatcher> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/parkable_image.cc b/chromium/third_party/blink/renderer/platform/graphics/parkable_image.cc
new file mode 100644
index 00000000000..bde9c9914a2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/parkable_image.cc
@@ -0,0 +1,269 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/parkable_image.h"
+
+#include "base/debug/stack_trace.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/timer/elapsed_timer.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image_manager.h"
+#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+namespace blink {
+
+namespace {
+
+void RecordReadStatistics(size_t size, base::TimeDelta duration) {
+ size_t throughput_mb_s =
+ static_cast<size_t>(size / duration.InSecondsF()) / (1024 * 1024);
+ size_t size_kb = size / 1024; // in KiB
+
+ // Size should be <1MiB in most cases.
+ base::UmaHistogramCounts10000("Memory.ParkableImage.Read.Size", size_kb);
+ // Size is usually >1KiB, and at most ~10MiB, and throughput ranges from
+ // single-digit MB/s to ~1000MiB/s depending on the CPU/disk, hence the
+ // ranges.
+ base::UmaHistogramCustomMicrosecondsTimes(
+ "Memory.ParkableImage.Read.Latency", duration,
+ base::TimeDelta::FromMicroseconds(500), base::TimeDelta::FromSeconds(1),
+ 100);
+ base::UmaHistogramCounts1000("Memory.ParkableImage.Read.Throughput",
+ throughput_mb_s);
+}
+
+void RecordWriteStatistics(size_t size, base::TimeDelta duration) {
+ size_t throughput_mb_s =
+ static_cast<size_t>(size / duration.InSecondsF()) / (1024 * 1024);
+ size_t size_kb = size / 1024;
+
+ // Size should be <1MiB in most cases.
+ base::UmaHistogramCounts10000("Memory.ParkableImage.Write.Size", size_kb);
+ // Size is usually >1KiB, and at most ~10MiB, and throughput ranges from
+ // single-digit MB/s to ~1000MiB/s depending on the CPU/disk, hence the
+ // ranges.
+ base::UmaHistogramCustomMicrosecondsTimes(
+ "Memory.ParkableImage.Write.Latency", duration,
+ base::TimeDelta::FromMicroseconds(500), base::TimeDelta::FromSeconds(1),
+ 100);
+ base::UmaHistogramCounts1000("Memory.ParkableImage.Write.Throughput",
+ throughput_mb_s);
+}
+
+} // namespace
+
+void ParkableImage::Append(WTF::SharedBuffer* buffer, size_t offset) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ MutexLocker lock(lock_);
+ DCHECK(!frozen_);
+ DCHECK(!is_on_disk());
+ DCHECK(rw_buffer_);
+
+ for (auto it = buffer->GetIteratorAt(offset); it != buffer->cend(); ++it) {
+ DCHECK_GE(buffer->size(), rw_buffer_->size() + it->size());
+ const size_t remaining = buffer->size() - rw_buffer_->size() - it->size();
+ rw_buffer_->Append(it->data(), it->size(), remaining);
+ }
+ size_ = rw_buffer_->size();
+}
+
+scoped_refptr<SharedBuffer> ParkableImage::Data() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ MutexLocker lock(lock_);
+ Unpark();
+ DCHECK(rw_buffer_);
+ scoped_refptr<ROBuffer> ro_buffer(rw_buffer_->MakeROBufferSnapshot());
+ scoped_refptr<SharedBuffer> shared_buffer = SharedBuffer::Create();
+ ROBuffer::Iter it(ro_buffer.get());
+ do {
+ shared_buffer->Append(static_cast<const char*>(it.data()), it.size());
+ } while (it.Next());
+ return shared_buffer;
+}
+
+scoped_refptr<SegmentReader> ParkableImage::GetSegmentReader() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ MutexLocker lock(lock_);
+ Unpark();
+ DCHECK(rw_buffer_);
+ scoped_refptr<ROBuffer> ro_buffer(rw_buffer_->MakeROBufferSnapshot());
+ scoped_refptr<SegmentReader> segment_reader =
+ SegmentReader::CreateFromROBuffer(std::move(ro_buffer));
+ return segment_reader;
+}
+
+bool ParkableImage::CanParkNow() const {
+ DCHECK(!is_on_disk());
+ return is_frozen() && rw_buffer_->HasNoSnapshots();
+}
+
+ParkableImage::ParkableImage(size_t initial_capacity)
+ : rw_buffer_(std::make_unique<RWBuffer>(initial_capacity)) {
+ ParkableImageManager::Instance().Add(this);
+}
+
+ParkableImage::~ParkableImage() {
+ auto& manager = ParkableImageManager::Instance();
+ manager.Remove(this);
+ if (on_disk_metadata_)
+ manager.data_allocator().Discard(std::move(on_disk_metadata_));
+}
+
+// static
+scoped_refptr<ParkableImage> ParkableImage::Create(size_t initial_capacity) {
+ return base::MakeRefCounted<ParkableImage>(initial_capacity);
+}
+
+scoped_refptr<SegmentReader> ParkableImage::MakeROSnapshot() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return GetSegmentReader();
+}
+
+void ParkableImage::Freeze() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ MutexLocker lock(lock_);
+
+ DCHECK(!frozen_);
+ frozen_ = true;
+}
+
+// static
+void ParkableImage::WriteToDiskInBackground(
+ scoped_refptr<ParkableImage> parkable_image,
+ scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner) {
+ DCHECK(!IsMainThread());
+ MutexLocker lock(parkable_image->lock_);
+
+ DCHECK(ParkableImageManager::IsParkableImagesToDiskEnabled());
+ DCHECK(parkable_image);
+ DCHECK(!parkable_image->on_disk_metadata_);
+
+ scoped_refptr<ROBuffer> ro_buffer =
+ parkable_image->rw_buffer_->MakeROBufferSnapshot();
+ ROBuffer::Iter it(ro_buffer.get());
+
+ Vector<char> vector;
+ vector.ReserveInitialCapacity(parkable_image->size());
+
+ do {
+ vector.Append(reinterpret_cast<const char*>(it.data()), it.size());
+ } while (it.Next());
+
+ // Release the lock while writing, so we don't block for too long.
+ parkable_image->lock_.unlock();
+
+ base::ElapsedTimer timer;
+ auto metadata = ParkableImageManager::Instance().data_allocator().Write(
+ vector.data(), vector.size());
+ base::TimeDelta elapsed = timer.Elapsed();
+
+ // Acquire the lock again after writing.
+ parkable_image->lock_.lock();
+
+ parkable_image->on_disk_metadata_ = std::move(metadata);
+
+ // Nothing to do if the write failed except return. Notably, we need to
+ // keep around the data for the ParkableImage in this case.
+ if (!parkable_image->on_disk_metadata_) {
+ parkable_image->background_task_in_progress_ = false;
+ } else {
+ RecordWriteStatistics(parkable_image->on_disk_metadata_->size(), elapsed);
+ ParkableImageManager::Instance().RecordDiskWriteTime(elapsed);
+ PostCrossThreadTask(*callback_task_runner, FROM_HERE,
+ CrossThreadBindOnce(&ParkableImage::MaybeDiscardData,
+ std::move(parkable_image)));
+ }
+}
+
+void ParkableImage::MaybeDiscardData() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ MutexLocker lock(lock_);
+ DCHECK(on_disk_metadata_);
+
+ background_task_in_progress_ = false;
+
+ // If the image is now unparkable, we need to keep the data around.
+ // This can happen if, for example, in between the time we posted the task to
+ // discard the data and the time MaybeDiscardData is called, we've created a
+ // SegmentReader from |rw_buffer_|, since discarding the data would leave us
+ // with a dangling pointer in the SegmentReader.
+ if (CanParkNow())
+ DiscardData();
+}
+
+void ParkableImage::DiscardData() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ rw_buffer_ = nullptr;
+ ParkableImageManager::Instance().OnWrittenToDisk(this);
+}
+
+bool ParkableImage::MaybePark() {
+ DCHECK(ParkableImageManager::IsParkableImagesToDiskEnabled());
+
+ MutexLocker lock(lock_);
+
+ if (background_task_in_progress_)
+ return true;
+
+ if (!CanParkNow())
+ return false;
+
+ if (on_disk_metadata_) {
+ DiscardData();
+ return true;
+ }
+
+ background_task_in_progress_ = true;
+
+ // The writing is done on a background thread. We pass a TaskRunner from the
+ // current thread for when we have finished writing.
+ worker_pool::PostTask(
+ FROM_HERE, {base::MayBlock(), base::ThreadPool()},
+ CrossThreadBindOnce(&ParkableImage::WriteToDiskInBackground,
+ scoped_refptr<ParkableImage>(this),
+ Thread::Current()->GetTaskRunner()));
+ return true;
+}
+
+void ParkableImage::Unpark() {
+ if (!is_on_disk())
+ return;
+
+ DCHECK(ParkableImageManager::IsParkableImagesToDiskEnabled());
+
+ TRACE_EVENT1("blink", "ParkableImage::Unpark", "size", size());
+
+ DCHECK(on_disk_metadata_);
+ WTF::Vector<uint8_t> vector(size());
+
+ base::ElapsedTimer timer;
+ ParkableImageManager::Instance().data_allocator().Read(*on_disk_metadata_,
+ vector.data());
+ base::TimeDelta elapsed = timer.Elapsed();
+
+ RecordReadStatistics(on_disk_metadata_->size(), elapsed);
+ ParkableImageManager::Instance().RecordDiskReadTime(elapsed);
+
+ ParkableImageManager::Instance().OnReadFromDisk(this);
+
+ DCHECK(!rw_buffer_);
+
+ rw_buffer_ = std::make_unique<RWBuffer>(size());
+ rw_buffer_->Append(vector.data(), size());
+}
+
+size_t ParkableImage::size() const {
+ return size_;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/parkable_image.h b/chromium/third_party/blink/renderer/platform/graphics/parkable_image.h
new file mode 100644
index 00000000000..bea703c081d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/parkable_image.h
@@ -0,0 +1,120 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_
+
+#include "base/debug/stack_trace.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/renderer/platform/disk_data_metadata.h"
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
+#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
+#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
+
+namespace blink {
+
+class SegmentReader;
+class ParkableImageManager;
+
+// Wraps a RWBuffer containing encoded image data. This buffer can be written
+// to/read from disk when not needed, to improve memory usage.
+class PLATFORM_EXPORT ParkableImage final
+ : public ThreadSafeRefCounted<ParkableImage> {
+ public:
+ // |initial_capacity| reserves space in the internal buffer, if you know how
+ // much data you'll be appending in advance.
+ explicit ParkableImage(size_t initial_capacity = 0);
+
+ ~ParkableImage();
+
+ ParkableImage& operator=(const ParkableImage&) = delete;
+ ParkableImage(const ParkableImage&) = delete;
+
+ // Factory method to construct a ParkableImage.
+ static scoped_refptr<ParkableImage> Create(size_t initial_capacity = 0);
+
+ // Freezes the ParkableImage. This changes the following:
+ // (1) We are no longer allowed to mutate the internal buffer (e.g. via
+ // Append);
+ // (2) The image may now be parked to disk.
+ void Freeze() LOCKS_EXCLUDED(lock_);
+
+ // Adds data to the internal buffer of ParkableImage. Cannot be called after
+ // the ParkableImage has been frozen (see Freeze()). |offset| is the offset
+ // from the start of |buffer| that we want to start copying the data from.
+ void Append(WTF::SharedBuffer* buffer, size_t offset = 0)
+ LOCKS_EXCLUDED(lock_);
+
+ // Make a Read-Only snapshot of the data within ParkableImage. This may be a
+ // view into the internal buffer of ParkableImage, or a copy of the data. It
+ // is guaranteed to be safe to read this data from another thread at any time.
+ scoped_refptr<SegmentReader> MakeROSnapshot();
+
+ // Returns the data in the internal buffer. It should not be modified after
+ // the ParkableImage has been frozen.
+ scoped_refptr<SharedBuffer> Data() LOCKS_EXCLUDED(lock_);
+
+ // Returns the size of the internal buffer. Can be called even when
+ // ParkableImage has been parked.
+ size_t size() const;
+
+ bool is_frozen() const { return frozen_; }
+ bool is_on_disk() const EXCLUSIVE_LOCKS_REQUIRED(lock_) {
+ return !rw_buffer_ && on_disk_metadata_;
+ }
+ bool CanParkNow() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ private:
+ friend class ParkableImageManager;
+ friend class ParkableImageBaseTest;
+
+ scoped_refptr<SegmentReader> GetSegmentReader() LOCKS_EXCLUDED(lock_);
+
+ // Attempt to park to disk. Returns false if it cannot be parked right now for
+ // whatever reason, true if we will _attempt_ to park it to disk.
+ bool MaybePark() LOCKS_EXCLUDED(lock_);
+
+ // Unpark the data from disk. This is blocking, on the same thread (since we
+ // cannot expect to continue with anything that needs the data until we have
+ // unparked it).
+ void Unpark() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ // Tries to write the data from |rw_buffer_| to disk. Then, if the data is
+ // successfully written to disk, posts a task to discard |rw_buffer_|.
+ static void WriteToDiskInBackground(
+ scoped_refptr<ParkableImage>,
+ scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner)
+ LOCKS_EXCLUDED(lock_);
+
+ // Attempt to discard the data. This should only be called after we've written
+ // the data to disk. Fails if the image can not be parked at the time this is
+ // called for whatever reason.
+ void MaybeDiscardData() LOCKS_EXCLUDED(lock_);
+
+ // Discards the data in |rw_buffer_|. Caller is responsible for making sure
+ // this is only called when the image can be parked.
+ void DiscardData() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ mutable Mutex lock_;
+
+ std::unique_ptr<RWBuffer> rw_buffer_ GUARDED_BY(lock_);
+
+ // Non-null iff we have the data from |rw_buffer_| saved to disk.
+ std::unique_ptr<DiskDataMetadata> on_disk_metadata_ GUARDED_BY(lock_) =
+ nullptr;
+ // |size_| is only modified on the main thread.
+ size_t size_ = 0;
+ // |frozen_| is only modified on the main thread.
+ bool frozen_ = false;
+ bool background_task_in_progress_ GUARDED_BY(lock_) = false;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.cc b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.cc
new file mode 100644
index 00000000000..acde65ca904
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.cc
@@ -0,0 +1,223 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/parkable_image_manager.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/single_thread_task_runner.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/wtf.h"
+
+namespace blink {
+
+const base::Feature kParkableImagesToDisk{"ParkableImagesToDisk",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+struct ParkableImageManager::Statistics {
+ size_t unparked_size = 0;
+ size_t on_disk_size = 0;
+ size_t total_size = 0;
+};
+
+constexpr const char* ParkableImageManager::kAllocatorDumpName;
+
+constexpr base::TimeDelta ParkableImageManager::kDelayedParkingInterval;
+
+// static
+ParkableImageManager& ParkableImageManager::Instance() {
+ static base::NoDestructor<ParkableImageManager> instance;
+ return *instance;
+}
+
+bool ParkableImageManager::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs&,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ auto* dump = pmd->CreateAllocatorDump(kAllocatorDumpName);
+
+ MutexLocker lock(lock_);
+ Statistics stats = ComputeStatistics();
+
+ dump->AddScalar("total_size", "bytes", stats.total_size);
+ dump->AddScalar("unparked_size", "bytes", stats.unparked_size);
+ dump->AddScalar("on_disk_size", "bytes", stats.on_disk_size);
+
+ return true;
+}
+
+ParkableImageManager::Statistics ParkableImageManager::ComputeStatistics()
+ const {
+ Statistics stats;
+
+ for (auto* unparked : unparked_images_)
+ stats.unparked_size += unparked->size();
+
+ for (auto* on_disk : on_disk_images_)
+ stats.on_disk_size += on_disk->size();
+
+ stats.total_size = stats.on_disk_size + stats.unparked_size;
+
+ return stats;
+}
+
+size_t ParkableImageManager::Size() const {
+ MutexLocker lock(lock_);
+
+ return on_disk_images_.size() + unparked_images_.size();
+}
+
+DiskDataAllocator& ParkableImageManager::data_allocator() const {
+ if (allocator_for_testing_)
+ return *allocator_for_testing_;
+
+ return DiskDataAllocator::Instance();
+}
+
+void ParkableImageManager::ResetForTesting() {
+ MutexLocker lock(lock_);
+
+ has_pending_parking_task_ = false;
+ has_posted_accounting_task_ = false;
+ unparked_images_.clear();
+ on_disk_images_.clear();
+ allocator_for_testing_ = nullptr;
+ total_disk_read_time_ = base::TimeDelta();
+ total_disk_write_time_ = base::TimeDelta();
+}
+
+void ParkableImageManager::Add(ParkableImage* image) {
+ DCHECK(IsMainThread());
+
+ MutexLocker lock(lock_);
+
+ ScheduleDelayedParkingTaskIfNeeded();
+
+ if (!has_posted_accounting_task_) {
+ auto task_runner = Thread::Current()->GetTaskRunner();
+ DCHECK(task_runner);
+ // |base::Unretained(this)| is fine because |this| is a NoDestructor
+ // singleton.
+ task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ParkableImageManager::RecordStatisticsAfter5Minutes,
+ base::Unretained(this)),
+ base::TimeDelta::FromMinutes(5));
+ has_posted_accounting_task_ = true;
+ }
+
+ unparked_images_.insert(image);
+}
+
+void ParkableImageManager::RecordStatisticsAfter5Minutes() const {
+ DCHECK(IsMainThread());
+
+ MutexLocker lock(lock_);
+
+ Statistics stats = ComputeStatistics();
+
+ base::UmaHistogramCounts100000("Memory.ParkableImage.TotalSize.5min",
+ stats.total_size / 1024); // in KiB
+ base::UmaHistogramCounts100000("Memory.ParkableImage.OnDiskSize.5min",
+ stats.on_disk_size / 1024); // in KiB
+ base::UmaHistogramCounts100000("Memory.ParkableImage.UnparkedSize.5min",
+ stats.unparked_size / 1024); // in KiB
+
+ // Metrics related to parking only should be recorded if the feature is
+ // enabled.
+ if (IsParkableImagesToDiskEnabled()) {
+ base::UmaHistogramBoolean("Memory.ParkableImage.DiskIsUsable.5min",
+ data_allocator().may_write());
+ // These metrics only make sense if the disk allocator is used.
+ if (data_allocator().may_write()) {
+ base::UmaHistogramTimes("Memory.ParkableImage.TotalWriteTime.5min",
+ total_disk_write_time_);
+ base::UmaHistogramTimes("Memory.ParkableImage.TotalReadTime.5min",
+ total_disk_read_time_);
+ }
+ }
+}
+
+void ParkableImageManager::Remove(ParkableImage* image) {
+ DCHECK(IsMainThread());
+
+ MutexLocker lock(lock_);
+
+ // Image could be on disk or unparked. Remove it in either case.
+ unparked_images_.erase(image);
+ on_disk_images_.erase(image);
+}
+
+void ParkableImageManager::MoveImage(ParkableImage* image,
+ WTF::HashSet<ParkableImage*>* from,
+ WTF::HashSet<ParkableImage*>* to) {
+ auto it = from->find(image);
+ CHECK(it != from->end());
+ CHECK(!to->Contains(image));
+ from->erase(it);
+ to->insert(image);
+}
+
+void ParkableImageManager::OnWrittenToDisk(ParkableImage* image) {
+ MutexLocker lock(lock_);
+ MoveImage(image, &unparked_images_, &on_disk_images_);
+}
+
+void ParkableImageManager::OnReadFromDisk(ParkableImage* image) {
+ MutexLocker lock(lock_);
+ MoveImage(image, &on_disk_images_, &unparked_images_);
+ ScheduleDelayedParkingTaskIfNeeded();
+}
+
+void ParkableImageManager::ScheduleDelayedParkingTaskIfNeeded() {
+ if (!ParkableImageManager::IsParkableImagesToDiskEnabled())
+ return;
+
+ if (has_pending_parking_task_)
+ return;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ Thread::Current()->GetTaskRunner();
+ task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ParkableImageManager::MaybeParkImages,
+ base::Unretained(this)),
+ ParkableImageManager::kDelayedParkingInterval);
+ has_pending_parking_task_ = true;
+}
+
+void ParkableImageManager::MaybeParkImages() {
+ DCHECK(ParkableImageManager::IsParkableImagesToDiskEnabled());
+
+ MutexLocker lock(lock_);
+
+ // This makes a copy of the pointers stored in |unparked_images_|. We iterate
+ // over this copy in |MaybeParkImages|, instead of |unparked_images_|
+ // directly, for two reasons:
+ // (1) Avoiding a deadlock when we need to park synchronously (i.e. if we have
+ // already written to disk and don't need to post a background task), as
+ // synchronous parking calls |ParkableImageManager::OnWrittenToDisk()|;
+ // (2) Keeping the images alive until we are done iterating, without locking
+ // (through use of scoped_refptr instead of a raw pointer).
+ WTF::Vector<scoped_refptr<ParkableImage>> unparked_images;
+ for (auto* image : unparked_images_)
+ unparked_images.push_back(scoped_refptr<ParkableImage>(image));
+
+ // We unlock here so that we can avoid a deadlock, since if the data for the
+ // image is already written to disk, we can discard our copy of the data
+ // synchronously, which calls back into the manager.
+ lock_.unlock();
+
+ for (auto image : unparked_images)
+ image->MaybePark();
+
+ lock_.lock();
+
+ has_pending_parking_task_ = false;
+
+ if (unparked_images_.size() > 0)
+ ScheduleDelayedParkingTaskIfNeeded();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.h b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.h
new file mode 100644
index 00000000000..3a1b3aa3e2d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_manager.h
@@ -0,0 +1,122 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_MANAGER_H_
+
+#include "base/trace_event/memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/disk_data_allocator.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+
+namespace blink {
+
+class ParkableImage;
+
+PLATFORM_EXPORT extern const base::Feature kParkableImagesToDisk;
+
+// Manages parkable images, which are used in blink::BitmapImage. Currently,
+// only records metrics for this. In the future we will park eligible images
+// to disk.
+// Main Thread only.
+class PLATFORM_EXPORT ParkableImageManager
+ : public base::trace_event::MemoryDumpProvider {
+ public:
+ static ParkableImageManager& Instance();
+ ~ParkableImageManager() override = default;
+
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
+ base::trace_event::ProcessMemoryDump*) override;
+
+ // Number of parked and unparked images.
+ size_t Size() const LOCKS_EXCLUDED(lock_);
+
+ static bool IsParkableImagesToDiskEnabled() {
+ return base::FeatureList::IsEnabled(kParkableImagesToDisk);
+ }
+
+ private:
+ struct Statistics;
+
+ friend class ParkableImage;
+ friend class base::NoDestructor<ParkableImageManager>;
+ friend class ParkableImageBaseTest;
+
+ ParkableImageManager() = default;
+
+ DiskDataAllocator& data_allocator() const;
+
+ // Register and unregister a ParkableImage with the manager. ParkableImage
+ // should call these when created/destructed.
+ void Add(ParkableImage* image) LOCKS_EXCLUDED(lock_);
+ void Remove(ParkableImage* image) LOCKS_EXCLUDED(lock_);
+
+ void ScheduleDelayedParkingTaskIfNeeded() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+ void MaybeParkImages() LOCKS_EXCLUDED(lock_);
+
+ Statistics ComputeStatistics() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ void RecordStatisticsAfter5Minutes() const LOCKS_EXCLUDED(lock_);
+
+ void MoveImage(ParkableImage* image,
+ WTF::HashSet<ParkableImage*>* from,
+ WTF::HashSet<ParkableImage*>* to)
+ EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ void RecordDiskWriteTime(base::TimeDelta write_time) LOCKS_EXCLUDED(lock_) {
+ MutexLocker lock(lock_);
+ total_disk_write_time_ += write_time;
+ }
+
+ void RecordDiskReadTime(base::TimeDelta read_time) LOCKS_EXCLUDED(lock_) {
+ MutexLocker lock(lock_);
+ total_disk_read_time_ += read_time;
+ }
+
+ // Keeps track of whether the image is unparked or on disk. ParkableImage
+ // should call these when written to or read from disk.
+ void OnWrittenToDisk(ParkableImage* image) LOCKS_EXCLUDED(lock_);
+ void OnReadFromDisk(ParkableImage* image) LOCKS_EXCLUDED(lock_);
+
+ void SetDataAllocatorForTesting(
+ std::unique_ptr<DiskDataAllocator> allocator) {
+ allocator_for_testing_ = std::move(allocator);
+ }
+
+ void ResetForTesting();
+ constexpr static auto kDelayedParkingInterval =
+ base::TimeDelta::FromSeconds(2);
+ constexpr static const char* kAllocatorDumpName = "parkable_images";
+
+ mutable Mutex lock_;
+
+ // The following two sets are used to keep track of all ParkableImages that
+ // have been created. ParkableImages are added to |unparked_images_| upon
+ // creation, and removed from whichever set they are in at the time of their
+ // destruction.
+ //
+ // Parking or Unparking a ParkableImage moves the image to the appropriate
+ // set, using |OnReadFromDisk| and |OnWrittenToDisk|.
+ //
+ // |unparked_images_| keeps track of all images that have a in-memory
+ // representation.
+ //
+ // |on_disk_images_| keeps track of all images that do not have an in-memory
+ // representation. Accessing the data for any image in |on_disk_images_|
+ // involves a read from disk.
+ WTF::HashSet<ParkableImage*> unparked_images_ GUARDED_BY(lock_);
+ WTF::HashSet<ParkableImage*> on_disk_images_ GUARDED_BY(lock_);
+
+ bool has_pending_parking_task_ GUARDED_BY(lock_) = false;
+ bool has_posted_accounting_task_ = false;
+
+ base::TimeDelta total_disk_read_time_ GUARDED_BY(lock_) = base::TimeDelta();
+ base::TimeDelta total_disk_write_time_ GUARDED_BY(lock_) = base::TimeDelta();
+
+ std::unique_ptr<DiskDataAllocator> allocator_for_testing_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/parkable_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_test.cc
new file mode 100644
index 00000000000..618d5f8257c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/parkable_image_test.cc
@@ -0,0 +1,668 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/parkable_image.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/disk_data_allocator_test_utils.h"
+#include "third_party/blink/renderer/platform/graphics/parkable_image_manager.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
+
+using ThreadPoolExecutionMode =
+ base::test::TaskEnvironment::ThreadPoolExecutionMode;
+
+namespace blink {
+
+// Parent for ParkableImageTest and ParkableImageNoParkingTest. The only
+// difference between those two is whether parking is enabled or not.
+class ParkableImageBaseTest : public ::testing::Test {
+ public:
+ ParkableImageBaseTest()
+ : task_env_(base::test::TaskEnvironment::TimeSource::MOCK_TIME,
+ ThreadPoolExecutionMode::DEFAULT) {}
+
+ void SetUp() override {
+ auto& manager = ParkableImageManager::Instance();
+ manager.ResetForTesting();
+ manager.SetDataAllocatorForTesting(
+ std::make_unique<InMemoryDataAllocator>());
+ }
+
+ void TearDown() override {
+ CHECK_EQ(ParkableImageManager::Instance().Size(), 0u);
+ task_env_.FastForwardUntilNoTasksRemain();
+ }
+
+ protected:
+ void WaitForDelayedParking() {
+ task_env_.FastForwardBy(ParkableImageManager::kDelayedParkingInterval);
+ }
+
+ // To aid in testing that the "Memory.ParkableImage.*.5min" metrics are
+ // correctly recorded.
+ void Wait5MinForStatistics() {
+ task_env_.FastForwardBy(base::TimeDelta::FromMinutes(5));
+ }
+
+ void DescribeCurrentTasks() { task_env_.DescribeCurrentTasks(); }
+
+ void RunPostedTasks() { task_env_.RunUntilIdle(); }
+
+ size_t GetPendingMainThreadTaskCount() {
+ return task_env_.GetPendingMainThreadTaskCount();
+ }
+
+ static bool MaybePark(scoped_refptr<ParkableImage> pi) {
+ return pi->MaybePark();
+ }
+ static void Unpark(scoped_refptr<ParkableImage> pi) {
+ MutexLocker lock(pi->lock_);
+ pi->Unpark();
+ }
+ static bool is_on_disk(scoped_refptr<ParkableImage> pi) {
+ MutexLocker lock(pi->lock_);
+ return pi->is_on_disk();
+ }
+
+ scoped_refptr<ParkableImage> MakeParkableImageForTesting(const char* buffer,
+ size_t length) {
+ auto pi = ParkableImage::Create();
+
+ pi->Append(WTF::SharedBuffer::Create(buffer, length).get(), 0);
+
+ return pi;
+ }
+
+ // Checks content matches the ParkableImage returned from
+ // |MakeParkableImageForTesting|.
+ static bool IsSameContent(scoped_refptr<ParkableImage> pi,
+ const char* buffer,
+ size_t length) {
+ if (pi->size() != length) {
+ return false;
+ }
+
+ MutexLocker lock(pi->lock_);
+ auto ro_buffer = pi->rw_buffer_->MakeROBufferSnapshot();
+ ROBuffer::Iter iter(ro_buffer.get());
+ do {
+ if (memcmp(iter.data(), buffer, iter.size()) != 0) {
+ return false;
+ }
+ buffer += iter.size();
+ } while (iter.Next());
+
+ return true;
+ }
+
+ // This checks that the "Memory.ParkableImage.Write.*" statistics from
+ // |RecordReadStatistics()| are recorded correctly, namely
+ // "Memory.ParkableImage.Write.Latency",
+ // "Memory.ParkableImage.Write.Throughput", and
+ // "Memory.ParkableImage.Write.Size".
+ //
+ // Checks the counts for all 3 metrics, but only checks the value for
+ // "Memory.ParkableImage.Write.Size", since the others can't be easily tested.
+ void ExpectWriteStatistics(base::HistogramBase::Sample sample,
+ base::HistogramBase::Count expected_count) {
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.Write.Latency",
+ expected_count);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.Write.Throughput",
+ expected_count);
+ histogram_tester_.ExpectBucketCount("Memory.ParkableImage.Write.Size",
+ sample, expected_count);
+ }
+
+ // This checks that the "Memory.ParkableImage.Read.*" statistics from
+ // |RecordReadStatistics()| are recorded correctly, namely
+ // "Memory.ParkableImage.Read.Latency",
+ // "Memory.ParkableImage.Read.Throughput", and
+ // "Memory.ParkableImage.Read.Size".
+ //
+ // Checks the counts for all 3 metrics, but only checks the value for
+ // "Memory.ParkableImage.Read.Size", since the others can't be easily tested.
+ void ExpectReadStatistics(base::HistogramBase::Sample sample,
+ base::HistogramBase::Count expected_count) {
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.Read.Latency",
+ expected_count);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.Read.Throughput",
+ expected_count);
+ }
+
+ base::HistogramTester histogram_tester_;
+
+ private:
+ base::test::TaskEnvironment task_env_;
+};
+
+// Parking is enabled for these tests.
+class ParkableImageTest : public ParkableImageBaseTest {
+ public:
+ ParkableImageTest() { fl_.InitAndEnableFeature(kParkableImagesToDisk); }
+
+ private:
+ base::test::ScopedFeatureList fl_;
+};
+
+// Parking is disabled for these tests.
+class ParkableImageNoParkingTest : public ParkableImageBaseTest {
+ public:
+ ParkableImageNoParkingTest() {
+ fl_.InitAndDisableFeature(kParkableImagesToDisk);
+ }
+
+ private:
+ base::test::ScopedFeatureList fl_;
+};
+
+// Tests that ParkableImages are constructed with the correct size.
+TEST_F(ParkableImageTest, Size) {
+ auto pi = ParkableImage::Create();
+
+ EXPECT_EQ(pi->size(), 0u);
+
+ // This has capacity 10, not size 10; size should still be 0.
+ pi = ParkableImage::Create(10);
+
+ EXPECT_EQ(pi->size(), 0u);
+}
+
+// Tests that |Freeze|ing a ParkableImage correctly updates its state.
+TEST_F(ParkableImageTest, Frozen) {
+ auto pi = ParkableImage::Create();
+ ASSERT_EQ(pi->size(), 0u);
+
+ // Starts unfrozen.
+ EXPECT_FALSE(pi->is_frozen());
+
+ pi->Freeze();
+
+ EXPECT_TRUE(pi->is_frozen());
+}
+
+// Tests that |Append|ing to a ParkableImage correctly adds data to it.
+TEST_F(ParkableImageTest, Append) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = ParkableImage::Create();
+ ASSERT_EQ(pi->size(), 0u); // Should be empty when created.
+
+ pi->Append(WTF::SharedBuffer::Create(data, kDataSize).get(), 0);
+
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+}
+
+// Tests that multiple |Append|s correctly add data to the end of ParkableImage.
+TEST_F(ParkableImageTest, AppendMultiple) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = ParkableImage::Create();
+ ASSERT_EQ(pi->size(), 0u); // Should be empty when created.
+
+ auto sb = WTF::SharedBuffer::Create(data, kDataSize);
+ ASSERT_EQ(sb->size(), kDataSize);
+
+ pi->Append(sb.get(), 0);
+
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ sb->Append(data, kDataSize);
+ ASSERT_EQ(sb->size(), 2 * kDataSize);
+
+ pi->Append(sb.get(), pi->size());
+
+ EXPECT_EQ(pi->size(), 2 * kDataSize);
+}
+
+// Tests that we can read/write to disk correctly, preserving the data.
+TEST_F(ParkableImageTest, ParkAndUnpark) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ // We have no images currently.
+ ASSERT_EQ(0u, ParkableImageManager::Instance().Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ // We now have 1 image.
+ ASSERT_EQ(1u, ParkableImageManager::Instance().Size());
+
+ // Can't park because it is not frozen.
+ EXPECT_FALSE(MaybePark(pi));
+
+ // Should _not_ be on disk now.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ pi->Freeze();
+
+ // Parkable now that it's frozen.
+ EXPECT_TRUE(MaybePark(pi));
+
+ // Run task to park image.
+ RunPostedTasks();
+
+ // Should be on disk now.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+
+ // Unparking blocks until it is read from disk, so we expect it to no longer
+ // be on disk after unparking.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same after unparking.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+}
+
+// Tests that trying to park multiple times doesn't add any extra tasks.
+TEST_F(ParkableImageTest, ParkTwiceAndUnpark) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ // We have no images currently.
+ ASSERT_EQ(0u, ParkableImageManager::Instance().Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ // We now have 1 image.
+ ASSERT_EQ(1u, ParkableImageManager::Instance().Size());
+ pi->Freeze();
+
+ // Attempt to park the image twice in a row. This should have the same effect
+ // as trying to park it once.
+ EXPECT_TRUE(MaybePark(pi));
+ EXPECT_TRUE(MaybePark(pi));
+
+ // Run task to park image.
+ RunPostedTasks();
+
+ // Should be on disk now.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+
+ // Unparking blocks until it is read from disk, so we expect it to no longer
+ // be on disk after unparking.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same after unparking.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+}
+
+// Tests that we can park to disk synchronously after the data is stored on
+// disk the first time.
+TEST_F(ParkableImageTest, ParkAndUnparkSync) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ // We have no images currently.
+ ASSERT_EQ(0u, ParkableImageManager::Instance().Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ // We now have 1 image.
+ ASSERT_EQ(1u, ParkableImageManager::Instance().Size());
+
+ // Can't park because it is not frozen.
+ EXPECT_FALSE(MaybePark(pi));
+
+ // Should _not_ be on disk now.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ pi->Freeze();
+
+ // Parkable now that it's frozen.
+ EXPECT_TRUE(MaybePark(pi));
+
+ // Should not be on disk yet because we haven't run the tasks to write to disk
+ // yet.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Run task to park image.
+ RunPostedTasks();
+
+ // Should be on disk now.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+
+ // Unparking blocks until it is read from disk, so we expect it to no longer
+ // be on disk after unparking.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same after unparking.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ // Try to park a second time.
+ EXPECT_TRUE(MaybePark(pi));
+
+ // We already have it on disk, so this time we just need to discard the data,
+ // which can be done synchronously.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+
+ // Unparking blocks until it is read from disk, so we expect it to no longer
+ // be on disk after unparking.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same after unparking.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ // One extra read than write. We discard the data twice, but we only need to
+ // write to disk once. Because we've discarded it twice, we need to do two
+ // reads.
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 2);
+}
+
+// Tests that creating a snapshot partway through writing correctly aborts
+// discarding the data.
+TEST_F(ParkableImageTest, ParkAndUnparkAborted) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ // We have no images currently.
+ ASSERT_EQ(0u, ParkableImageManager::Instance().Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ // We now have 1 image.
+ ASSERT_EQ(1u, ParkableImageManager::Instance().Size());
+
+ // Should _not_ be on disk now.
+ ASSERT_FALSE(is_on_disk(pi));
+
+ pi->Freeze();
+
+ // Parkable now that it's frozen.
+ EXPECT_TRUE(MaybePark(pi));
+
+ auto snapshot = pi->MakeROSnapshot();
+
+ // Run task to park image.
+ RunPostedTasks();
+
+ // Should have been aborted, so still not on disk.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Unparking after aborted write is fine.
+ Unpark(pi);
+
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ // We still expect a write to be done in this case, since the only thing
+ // preventing it from being parked is the snapshot. However, the data is not
+ // discarded here, since we need for the snapshot.
+ //
+ // Since the data was never discarded, we expect 0 reads however.
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 0);
+
+ // Since we have a snapshot alive, we can't park.
+ EXPECT_FALSE(MaybePark(pi));
+
+ // kill the old snapshot.
+ snapshot = nullptr;
+
+ // Now that snapshot is gone, we can park.
+ EXPECT_TRUE(MaybePark(pi));
+
+ RunPostedTasks();
+
+ // Now parking can succeed.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ // Unpark after successful write should also work.
+ Unpark(pi);
+
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // Make sure content is the same.
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+}
+
+// Tests that a frozen image will be written to disk by the manager.
+TEST_F(ParkableImageTest, ManagerSimple) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto& manager = ParkableImageManager::Instance();
+ EXPECT_EQ(0u, manager.Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+ pi->Freeze();
+
+ EXPECT_EQ(1u, manager.Size());
+
+ // One of these is the delayed parking task
+ // |ParkableImageManager::MaybeParkImages|, the other is the delayed
+ // accounting task |ParkableImageManager::RecordStatisticsAfter5Minutes|.
+ EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
+
+ WaitForDelayedParking();
+
+ // Image should be on disk now.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+ EXPECT_FALSE(is_on_disk(pi));
+
+ WaitForDelayedParking();
+
+ // Even though we unparked earlier, a new delayed parking task should park the
+ // image still.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+}
+
+// Tests that the manager can correctly handle multiple parking tasks being
+// created at once.
+TEST_F(ParkableImageTest, ManagerTwo) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto& manager = ParkableImageManager::Instance();
+ EXPECT_EQ(0u, manager.Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+ pi->Freeze();
+
+ EXPECT_EQ(1u, manager.Size());
+
+ // One of these is the delayed parking task
+ // |ParkableImageManager::MaybeParkImages|, the other is the delayed
+ // accounting task |ParkableImageManager::RecordStatisticsAfter5Minutes|.
+ EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
+
+ WaitForDelayedParking();
+
+ // Image should be on disk now.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ Unpark(pi);
+ EXPECT_FALSE(is_on_disk(pi));
+
+ WaitForDelayedParking();
+
+ // Even though we unparked earlier, a new delayed parking task should park the
+ // image still.
+ EXPECT_TRUE(is_on_disk(pi));
+
+ ExpectWriteStatistics(kDataSize / 1024, 1);
+ ExpectReadStatistics(kDataSize / 1024, 1);
+}
+
+// Test that a non-frozen image will not be written to disk.
+TEST_F(ParkableImageTest, ManagerNonFrozen) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto& manager = ParkableImageManager::Instance();
+ EXPECT_EQ(0u, manager.Size());
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ EXPECT_EQ(1u, manager.Size());
+
+ // One of these is the delayed parking task
+ // |ParkableImageManager::MaybeParkImages|, the other is the delayed
+ // accounting task |ParkableImageManager::RecordStatisticsAfter5Minutes|.
+ EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
+
+ WaitForDelayedParking();
+
+ // Can't park because it is not frozen.
+ EXPECT_FALSE(is_on_disk(pi));
+
+ // No read or write was done, so we expect no metrics to be recorded for
+ // reading/writing.
+ ExpectWriteStatistics(0, 0);
+ ExpectReadStatistics(0, 0);
+}
+
+// Check that trying to unpark a ParkableImage when parking is disabled has no
+// effect.
+TEST_F(ParkableImageNoParkingTest, Unpark) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ pi->Freeze();
+
+ ASSERT_FALSE(is_on_disk(pi));
+
+ // This is a no-op when parking is disabled.
+ Unpark(pi);
+
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ // No data should be written or read when parking is disabled.
+ ExpectWriteStatistics(kDataSize / 1024, 0);
+ ExpectReadStatistics(kDataSize / 1024, 0);
+}
+
+// Tests that the ParkableImageManager is correctly recording statistics after 5
+// minutes.
+TEST_F(ParkableImageTest, ManagerStatistics5min) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+ pi->Freeze();
+
+ Wait5MinForStatistics();
+
+ // We expect "Memory.ParkableImage.OnDiskFootprintKb.5min" not to be emitted,
+ // since we've mocked the DiskDataAllocator for testing (and therefore cannot
+ // actually write to disk).
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.DiskIsUsable.5min",
+ 1);
+ histogram_tester_.ExpectTotalCount(
+ "Memory.ParkableImage.OnDiskFootprintKb.5min", 0);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.OnDiskSize.5min", 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalReadTime.5min",
+ 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalSize.5min", 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalWriteTime.5min",
+ 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.UnparkedSize.5min",
+ 1);
+}
+
+// Tests that the ParkableImageManager is correctly recording statistics after 5
+// minutes, even when parking is disabled. Only bookkeeping metrics should be
+// recorded in this case, since no reads/writes will happen.
+TEST_F(ParkableImageNoParkingTest, ManagerStatistics5min) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+ pi->Freeze();
+
+ Wait5MinForStatistics();
+
+ // Note that we expect 0 counts of some of these metrics.
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.DiskIsUsable.5min",
+ 0);
+ histogram_tester_.ExpectTotalCount(
+ "Memory.ParkableImage.OnDiskFootprintKb.5min", 0);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.OnDiskSize.5min", 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalReadTime.5min",
+ 0);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalSize.5min", 1);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.TotalWriteTime.5min",
+ 0);
+ histogram_tester_.ExpectTotalCount("Memory.ParkableImage.UnparkedSize.5min",
+ 1);
+}
+
+// Tests that the manager doesn't try to park any images when parking is
+// disabled.
+TEST_F(ParkableImageNoParkingTest, ManagerSimple) {
+ const size_t kDataSize = 3.5 * 4096;
+ char data[kDataSize];
+ PrepareReferenceData(data, kDataSize);
+
+ auto pi = MakeParkableImageForTesting(data, kDataSize);
+
+ auto& manager = ParkableImageManager::Instance();
+ // The manager still keeps track of all images when parking is disabled, but
+ // should not park them.
+ EXPECT_EQ(1u, manager.Size());
+
+ pi->Freeze();
+
+ // This is the delayed
+ // accounting task |ParkableImageManager::RecordStatisticsAfter5Minutes|.
+ EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
+
+ // This should not do anything, since parking is disabled.
+ WaitForDelayedParking();
+
+ EXPECT_FALSE(is_on_disk(pi));
+
+ EXPECT_TRUE(IsSameContent(pi, data, kDataSize));
+
+ // No data should be written or read when parking is disabled.
+ ExpectWriteStatistics(kDataSize / 1024, 0);
+ ExpectReadStatistics(kDataSize / 1024, 0);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.cc b/chromium/third_party/blink/renderer/platform/graphics/path.cc
index 3fa64ff77c0..b3e7bb1a187 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/path.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/path.cc
@@ -109,10 +109,14 @@ bool Path::StrokeContains(const FloatPoint& point,
.contains(SkScalar(point.X()), SkScalar(point.Y()));
}
-FloatRect Path::BoundingRect() const {
+FloatRect Path::TightBoundingRect() const {
return path_.computeTightBounds();
}
+FloatRect Path::BoundingRect() const {
+ return path_.getBounds();
+}
+
FloatRect Path::StrokeBoundingRect(const StrokeData& stroke_data) const {
// Skia stroke resolution scale for reduced-precision requirements.
constexpr float kStrokePrecision = 0.3f;
@@ -201,17 +205,13 @@ float Path::length() const {
}
FloatPoint Path::PointAtLength(float length) const {
- FloatPoint point;
- float normal;
- PointAndNormalAtLength(length, point, normal);
- return point;
+ return PointAndNormalAtLength(length).point;
}
-static bool CalculatePointAndNormalOnPath(SkPathMeasure& measure,
- SkScalar& contour_start,
- SkScalar length,
- FloatPoint& point,
- float& normal_angle) {
+static base::Optional<PointAndTangent> CalculatePointAndNormalOnPath(
+ SkPathMeasure& measure,
+ SkScalar& contour_start,
+ SkScalar length) {
do {
SkScalar contour_end = contour_start + measure.getLength();
if (length <= contour_end) {
@@ -220,31 +220,25 @@ static bool CalculatePointAndNormalOnPath(SkPathMeasure& measure,
SkScalar pos_in_contour = length - contour_start;
if (measure.getPosTan(pos_in_contour, &position, &tangent)) {
- normal_angle =
+ PointAndTangent result;
+ result.point = FloatPoint(position);
+ result.tangent_in_degrees =
rad2deg(SkScalarToFloat(SkScalarATan2(tangent.fY, tangent.fX)));
- point = FloatPoint(SkScalarToFloat(position.fX),
- SkScalarToFloat(position.fY));
- return true;
+ return result;
}
}
contour_start = contour_end;
} while (measure.nextContour());
- return false;
+ return base::nullopt;
}
-void Path::PointAndNormalAtLength(float length,
- FloatPoint& point,
- float& normal) const {
+PointAndTangent Path::PointAndNormalAtLength(float length) const {
SkPathMeasure measure(path_, false);
SkScalar start = 0;
- if (CalculatePointAndNormalOnPath(
- measure, start, WebCoreFloatToSkScalar(length), point, normal))
- return;
-
- SkPoint position = path_.getPoint(0);
- point =
- FloatPoint(SkScalarToFloat(position.fX), SkScalarToFloat(position.fY));
- normal = 0;
+ if (base::Optional<PointAndTangent> result = CalculatePointAndNormalOnPath(
+ measure, start, WebCoreFloatToSkScalar(length)))
+ return *result;
+ return {FloatPoint(path_.getPoint(0)), 0};
}
Path::PositionCalculator::PositionCalculator(const Path& path)
@@ -252,9 +246,7 @@ Path::PositionCalculator::PositionCalculator(const Path& path)
path_measure_(path.GetSkPath(), false),
accumulated_length_(0) {}
-void Path::PositionCalculator::PointAndNormalAtLength(float length,
- FloatPoint& point,
- float& normal_angle) {
+PointAndTangent Path::PositionCalculator::PointAndNormalAtLength(float length) {
SkScalar sk_length = WebCoreFloatToSkScalar(length);
if (sk_length >= 0) {
if (sk_length < accumulated_length_) {
@@ -263,15 +255,12 @@ void Path::PositionCalculator::PointAndNormalAtLength(float length,
accumulated_length_ = 0;
}
- if (CalculatePointAndNormalOnPath(path_measure_, accumulated_length_,
- sk_length, point, normal_angle))
- return;
+ base::Optional<PointAndTangent> result = CalculatePointAndNormalOnPath(
+ path_measure_, accumulated_length_, sk_length);
+ if (result)
+ return *result;
}
-
- SkPoint position = path_.getPoint(0);
- point =
- FloatPoint(SkScalarToFloat(position.fX), SkScalarToFloat(position.fY));
- normal_angle = 0;
+ return {FloatPoint(path_.getPoint(0)), 0};
}
void Path::Clear() {
diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.h b/chromium/third_party/blink/renderer/platform/graphics/path.h
index 6e8f3b5d405..84351f1d8bc 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/path.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/path.h
@@ -65,6 +65,12 @@ struct PathElement {
FloatPoint* points;
};
+// Result structure from Path::PointAndNormalAtLength() (and similar).
+struct PointAndTangent {
+ FloatPoint point;
+ float tangent_in_degrees = 0;
+};
+
typedef void (*PathApplierFunction)(void* info, const PathElement*);
class PLATFORM_EXPORT Path {
@@ -92,12 +98,16 @@ class PLATFORM_EXPORT Path {
const AffineTransform&) const;
SkPath StrokePath(const StrokeData&, const AffineTransform&) const;
+ // Tight Bounding calculation is very expensive, but it guarantees the strict
+ // bounding box. It's always included in BoundingRect. For a logical bounding
+ // box (used for clipping or damage) BoundingRect is recommended.
+ FloatRect TightBoundingRect() const;
FloatRect BoundingRect() const;
FloatRect StrokeBoundingRect(const StrokeData&) const;
float length() const;
FloatPoint PointAtLength(float length) const;
- void PointAndNormalAtLength(float length, FloatPoint&, float&) const;
+ PointAndTangent PointAndNormalAtLength(float length) const;
// Helper for computing a sequence of positions and normals (normal angles) on
// a path. The best possible access pattern will be one where the |length|
@@ -111,7 +121,7 @@ class PLATFORM_EXPORT Path {
public:
explicit PositionCalculator(const Path&);
- void PointAndNormalAtLength(float length, FloatPoint&, float&);
+ PointAndTangent PointAndNormalAtLength(float length);
private:
SkPath path_;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/path_test.cc b/chromium/third_party/blink/renderer/platform/graphics/path_test.cc
index fbf1af623c8..6c0bce00452 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/path_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/path_test.cc
@@ -17,10 +17,9 @@ TEST(PathTest, PointAtEndOfPath) {
path.AddBezierCurveTo(FloatPoint(324, 196), FloatPoint(472, 370),
FloatPoint(460, 470));
- FloatPoint point;
- float angle;
- path.PointAndNormalAtLength(path.length(), point, angle);
- EXPECT_EQ(point, FloatPoint(460, 470));
+ PointAndTangent point_and_tangent =
+ path.PointAndNormalAtLength(path.length());
+ EXPECT_EQ(point_and_tangent.point, FloatPoint(460, 470));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
index 4a7480b5b9f..8b5c78df6e3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc
@@ -53,6 +53,7 @@ void DrawIcon(cc::PaintCanvas* canvas,
const PaintFlags& flags,
float x,
float y,
+ const SkSamplingOptions& sampling,
float scale_factor) {
// Note that |icon_image| will be a 0x0 image when running
// blink_platform_unittests.
@@ -67,18 +68,19 @@ void DrawIcon(cc::PaintCanvas* canvas,
icon_image->PaintImageForCurrentFrame(),
IntRect(IntPoint::Zero(), icon_image->Size()),
FloatRect(x, y, scale_factor * kIconWidth, scale_factor * kIconHeight),
- &flags, SkCanvas::kFast_SrcRectConstraint);
+ sampling, &flags, SkCanvas::kFast_SrcRectConstraint);
}
void DrawCenteredIcon(cc::PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dest_rect,
+ const SkSamplingOptions& sampling,
float scale_factor) {
DrawIcon(
canvas, flags,
dest_rect.X() + (dest_rect.Width() - scale_factor * kIconWidth) / 2.0f,
dest_rect.Y() + (dest_rect.Height() - scale_factor * kIconHeight) / 2.0f,
- scale_factor);
+ sampling, scale_factor);
}
FontDescription CreatePlaceholderFontDescription(float scale_factor) {
@@ -248,8 +250,8 @@ PaintImage PlaceholderImage::PaintImageForCurrentFrame() {
PaintRecorder paint_recorder;
Draw(paint_recorder.beginRecording(FloatRect(dest_rect)), PaintFlags(),
- FloatRect(dest_rect), FloatRect(dest_rect), kRespectImageOrientation,
- kClampImageToSourceRect, kSyncDecode);
+ FloatRect(dest_rect), FloatRect(dest_rect), SkSamplingOptions(),
+ kRespectImageOrientation, kClampImageToSourceRect, kSyncDecode);
paint_record_for_current_frame_ = paint_recorder.finishRecordingAsPicture();
paint_record_content_id_ = PaintImage::GetNextContentId();
@@ -272,6 +274,7 @@ void PlaceholderImage::Draw(cc::PaintCanvas* canvas,
const PaintFlags& base_flags,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum respect_orientation,
ImageClampingMode image_clamping_mode,
ImageDecodingMode decode_mode) {
@@ -294,7 +297,7 @@ void PlaceholderImage::Draw(cc::PaintCanvas* canvas,
}
if (text_.IsEmpty()) {
- DrawCenteredIcon(canvas, base_flags, dest_rect,
+ DrawCenteredIcon(canvas, base_flags, dest_rect, sampling,
icon_and_text_scale_factor_);
return;
}
@@ -313,7 +316,7 @@ void PlaceholderImage::Draw(cc::PaintCanvas* canvas,
(kIconWidth + 2 * kFeaturePaddingX + kPaddingBetweenIconAndText);
if (dest_rect.Width() < icon_and_text_width) {
- DrawCenteredIcon(canvas, base_flags, dest_rect,
+ DrawCenteredIcon(canvas, base_flags, dest_rect, sampling,
icon_and_text_scale_factor_);
return;
}
@@ -340,7 +343,7 @@ void PlaceholderImage::Draw(cc::PaintCanvas* canvas,
}
DrawIcon(canvas, base_flags, icon_x,
- feature_y + icon_and_text_scale_factor_ * kIconPaddingY,
+ feature_y + icon_and_text_scale_factor_ * kIconPaddingY, sampling,
icon_and_text_scale_factor_);
flags.setColor(SkColorSetARGB(0xAB, 0, 0, 0));
@@ -368,7 +371,8 @@ void PlaceholderImage::DrawPattern(
// Ignore the pattern specifications and just draw a single placeholder image
// over the whole |dest_rect|. This is done in order to prevent repeated icons
// from cluttering tiled background images.
- Draw(context.Canvas(), flags, dest_rect, src_rect, respect_orientation,
+ Draw(context.Canvas(), flags, dest_rect, src_rect,
+ context.ImageSamplingOptions(), respect_orientation,
kClampImageToSourceRect, kUnspecifiedDecode);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.h b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.h
index dd3e3f55a19..68819d68ce1 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.h
@@ -46,6 +46,7 @@ class PLATFORM_EXPORT PlaceholderImage final : public Image {
const cc::PaintFlags&,
const FloatRect& dest_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc
index 76e28796f73..42067757770 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc
@@ -71,12 +71,13 @@ void DrawImageExpectingGrayBoxOnly(PlaceholderImage& image,
const FloatRect& dest_rect) {
MockPaintCanvas canvas;
ExpectDrawGrayBox(canvas, dest_rect);
- EXPECT_CALL(canvas, drawImageRect(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(canvas, drawImageRect(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(canvas, drawTextBlob(_, _, _, _)).Times(0);
image.Draw(&canvas, PaintFlags(), dest_rect,
- FloatRect(0.0f, 0.0f, 100.0f, 100.0f), kRespectImageOrientation,
- Image::kClampImageToSourceRect, Image::kUnspecifiedDecode);
+ FloatRect(0.0f, 0.0f, 100.0f, 100.0f), SkSamplingOptions(),
+ kRespectImageOrientation, Image::kClampImageToSourceRect,
+ Image::kUnspecifiedDecode);
}
void DrawImageExpectingIconOnly(PlaceholderImage& image,
@@ -101,13 +102,13 @@ void DrawImageExpectingIconOnly(PlaceholderImage& image,
FloatNear(scale_factor * kBaseIconWidth, 0.01)),
Property(&SkRect::height,
FloatNear(scale_factor * kBaseIconHeight, 0.01))),
- /*flags=*/_, /*constraint=*/_))
+ /*sampling*/ _, /*flags=*/_, /*constraint=*/_))
.Times(1);
EXPECT_CALL(canvas, drawTextBlob(_, _, _, _)).Times(0);
image.Draw(&canvas, PaintFlags(), dest_rect,
- FloatRect(0.0f, 0.0f, 100.0f, 100.0f),
+ FloatRect(0.0f, 0.0f, 100.0f, 100.0f), SkSamplingOptions(),
kDoNotRespectImageOrientation, Image::kClampImageToSourceRect,
Image::kUnspecifiedDecode);
}
@@ -171,7 +172,7 @@ void DrawImageExpectingIconAndTextLTR(PlaceholderImage& image,
FloatNear(scale_factor * kBaseIconWidth, 0.01)),
Property(&SkRect::height,
FloatNear(scale_factor * kBaseIconHeight, 0.01))),
- /*flags=*/_,
+ /*sampling*/ _, /*flags=*/_,
/*constraint=*/_))
.Times(1);
@@ -197,7 +198,7 @@ void DrawImageExpectingIconAndTextLTR(PlaceholderImage& image,
}));
image.Draw(&canvas, PaintFlags(), dest_rect,
- FloatRect(0.0f, 0.0f, 100.0f, 100.0f),
+ FloatRect(0.0f, 0.0f, 100.0f, 100.0f), SkSamplingOptions(),
kDoNotRespectImageOrientation, Image::kClampImageToSourceRect,
Image::kUnspecifiedDecode);
}
@@ -284,14 +285,14 @@ TEST_F(PlaceholderImageTest, FormatPlaceholderText) {
TEST_F(PlaceholderImageTest, DrawNonIntersectingSrcRect) {
MockPaintCanvas canvas;
EXPECT_CALL(canvas, drawRect(_, _)).Times(0);
- EXPECT_CALL(canvas, drawImageRect(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(canvas, drawImageRect(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(canvas, drawTextBlob(_, _, _, _)).Times(0);
PlaceholderImage::Create(nullptr, IntSize(800, 600), 0)
->Draw(&canvas, PaintFlags(), FloatRect(0.0f, 0.0f, 800.0f, 600.0f),
// The source rectangle is outside the 800x600 bounds of the image,
// so nothing should be drawn.
- FloatRect(1000.0f, 0.0f, 800.0f, 600.0f),
+ FloatRect(1000.0f, 0.0f, 800.0f, 600.0f), SkSamplingOptions(),
kDoNotRespectImageOrientation, Image::kClampImageToSourceRect,
Image::kUnspecifiedDecode);
}
@@ -426,7 +427,7 @@ TEST_F(PlaceholderImageTest, DrawWithOriginalResourceSizeRTL) {
FloatNear(kScaleFactor * kBaseIconWidth, 0.01)),
Property(&SkRect::height,
FloatNear(kScaleFactor * kBaseIconHeight, 0.01))),
- /*flags=*/_,
+ /*sampling*/ _, /*flags=*/_,
/*constraint=*/_))
.Times(1);
@@ -450,7 +451,7 @@ TEST_F(PlaceholderImageTest, DrawWithOriginalResourceSizeRTL) {
}));
image->Draw(&canvas, PaintFlags(), dest_rect,
- FloatRect(0.0f, 0.0f, 100.0f, 100.0f),
+ FloatRect(0.0f, 0.0f, 100.0f, 100.0f), SkSamplingOptions(),
kDoNotRespectImageOrientation, Image::kClampImageToSourceRect,
Image::kUnspecifiedDecode);
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/resource_id_traits.h b/chromium/third_party/blink/renderer/platform/graphics/resource_id_traits.h
new file mode 100644
index 00000000000..b370d7c1801
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/resource_id_traits.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RESOURCE_ID_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RESOURCE_ID_TRAITS_H_
+
+#include <limits>
+
+#include "components/viz/common/resources/resource_id.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
+#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+
+namespace WTF {
+
+template <>
+struct WTF::CrossThreadCopier<viz::ResourceId>
+ : public WTF::CrossThreadCopierPassThrough<viz::ResourceId> {};
+
+template <>
+struct HashTraits<viz::ResourceId> : GenericHashTraits<viz::ResourceId> {
+ static const bool kEmptyValueIsZero = false;
+ static viz::ResourceId EmptyValue() {
+ return viz::ResourceId(std::numeric_limits<uint32_t>::max());
+ }
+ static void ConstructDeletedValue(viz::ResourceId& slot, bool) {
+ slot = viz::ResourceId(std::numeric_limits<uint32_t>::max() - 1);
+ }
+ static bool IsDeletedValue(const viz::ResourceId& value) {
+ return value.GetUnsafeValue() == std::numeric_limits<uint32_t>::max() - 1;
+ }
+};
+
+} // namespace WTF
+
+namespace blink {
+
+struct ResourceIdHash {
+ STATIC_ONLY(ResourceIdHash);
+
+ static bool Equal(const viz::ResourceId& a, const viz::ResourceId& b) {
+ return a == b;
+ }
+
+ static uint32_t GetHash(const viz::ResourceId& id) {
+ return WTF::HashInt(id.GetUnsafeValue());
+ }
+
+ static const bool safe_to_compare_to_empty_or_deleted = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RESOURCE_ID_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.cc
new file mode 100644
index 00000000000..4d738359e1c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.cc
@@ -0,0 +1,278 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
+
+#include "base/atomic_ref_count.h"
+#include "base/check.h"
+#include "base/check_op.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
+
+#include <algorithm>
+#include <atomic>
+#include <new>
+
+namespace blink {
+
+namespace {
+
+// Force small chunks to be a page's worth
+static const size_t kMinAllocSize = 4096;
+
+} // namespace
+
+struct RWBuffer::BufferBlock {
+ RWBuffer::BufferBlock* next_; // updated by the writer
+ size_t used_; // updated by the writer
+ const size_t capacity_;
+
+ explicit BufferBlock(size_t capacity)
+ : next_(nullptr), used_(0), capacity_(capacity) {}
+
+ const void* startData() const { return this + 1; }
+
+ size_t avail() const { return capacity_ - used_; }
+ void* avail_data() {
+ return reinterpret_cast<char*>(const_cast<void*>(startData())) + used_;
+ }
+
+ static RWBuffer::BufferBlock* Alloc(size_t length) {
+ size_t capacity = LengthToCapacity(length);
+ void* buffer =
+ WTF::Partitions::BufferMalloc(sizeof(RWBuffer::BufferBlock) + capacity,
+ "blink::RWBuffer::BufferBlock");
+ return new (buffer) RWBuffer::BufferBlock(capacity);
+ }
+
+ // Return number of bytes actually appended. Important that we always
+ // completely fill this block before spilling into the next, since the reader
+ // uses capacity_ to know how many bytes it can read.
+ size_t Append(const void* src, size_t length) {
+ Validate();
+ size_t amount = std::min(avail(), length);
+ memcpy(avail_data(), src, amount);
+ used_ += amount;
+ Validate();
+ return amount;
+ }
+
+ // Do not call in the reader thread, since the writer may be updating used_.
+ // (The assertion is still true, but TSAN still may complain about its
+ // raciness.)
+ void Validate() const {
+ DCHECK_GT(capacity_, 0u);
+ DCHECK_LE(used_, capacity_);
+ }
+
+ private:
+ static size_t LengthToCapacity(size_t length) {
+ const size_t min_size = kMinAllocSize - sizeof(RWBuffer::BufferBlock);
+ return std::max(length, min_size);
+ }
+};
+
+struct RWBuffer::BufferHead {
+ mutable base::AtomicRefCount ref_count_;
+ RWBuffer::BufferBlock block_;
+
+ explicit BufferHead(size_t capacity) : ref_count_(1), block_(capacity) {}
+
+ static size_t LengthToCapacity(size_t length) {
+ const size_t min_size = kMinAllocSize - sizeof(RWBuffer::BufferHead);
+ return std::max(length, min_size);
+ }
+
+ static RWBuffer::BufferHead* Alloc(size_t length) {
+ size_t capacity = LengthToCapacity(length);
+ size_t size = sizeof(RWBuffer::BufferHead) + capacity;
+ void* buffer =
+ WTF::Partitions::BufferMalloc(size, "blink::RWBuffer::BufferHead");
+ return new (buffer) RWBuffer::BufferHead(capacity);
+ }
+
+ void ref() const {
+ auto old_ref_count = ref_count_.Increment();
+ DCHECK_GT(old_ref_count, 0);
+ }
+
+ void unref() const {
+ // A release here acts in place of all releases we "should" have been doing
+ // in ref().
+ if (!ref_count_.Decrement()) {
+ // Like unique(), the acquire is only needed on success.
+ RWBuffer::BufferBlock* block = block_.next_;
+ WTF::Partitions::BufferFree(
+ reinterpret_cast<void*>(const_cast<RWBuffer::BufferHead*>(this)));
+ while (block) {
+ RWBuffer::BufferBlock* next = block->next_;
+ WTF::Partitions::BufferFree(block);
+ block = next;
+ }
+ }
+ }
+
+ void Validate(size_t minUsed,
+ const RWBuffer::BufferBlock* tail = nullptr) const {
+#if DCHECK_IS_ON()
+ DCHECK(!ref_count_.IsZero());
+ size_t totalUsed = 0;
+ const RWBuffer::BufferBlock* block = &block_;
+ const RWBuffer::BufferBlock* lastBlock = block;
+ while (block) {
+ block->Validate();
+ totalUsed += block->used_;
+ lastBlock = block;
+ block = block->next_;
+ }
+ DCHECK(minUsed <= totalUsed);
+ if (tail) {
+ DCHECK(tail == lastBlock);
+ }
+#endif
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// The reader can only access block.capacity_ (which never changes), and cannot
+// access block.used_, which may be updated by the writer.
+//
+ROBuffer::ROBuffer(const RWBuffer::BufferHead* head,
+ size_t available,
+ const RWBuffer::BufferBlock* tail)
+ : head_(head), available_(available), tail_(tail) {
+ if (head) {
+ head_->ref();
+ DCHECK_GT(available, 0u);
+ head->Validate(available, tail);
+ } else {
+ DCHECK_EQ(0u, available);
+ DCHECK(!tail);
+ }
+}
+
+ROBuffer::~ROBuffer() {
+ if (head_) {
+ head_->unref();
+ }
+}
+
+ROBuffer::Iter::Iter(const ROBuffer* buffer) {
+ Reset(buffer);
+}
+
+ROBuffer::Iter::Iter(const scoped_refptr<ROBuffer>& buffer) {
+ Reset(buffer.get());
+}
+
+void ROBuffer::Iter::Reset(const ROBuffer* buffer) {
+ buffer_ = buffer;
+ if (buffer && buffer->head_) {
+ block_ = &buffer->head_->block_;
+ remaining_ = buffer->available_;
+ } else {
+ block_ = nullptr;
+ remaining_ = 0;
+ }
+}
+
+const void* ROBuffer::Iter::data() const {
+ return remaining_ ? block_->startData() : nullptr;
+}
+
+size_t ROBuffer::Iter::size() const {
+ if (!block_) {
+ return 0;
+ }
+ return std::min(block_->capacity_, remaining_);
+}
+
+bool ROBuffer::Iter::Next() {
+ if (remaining_) {
+ remaining_ -= size();
+ if (buffer_->tail_ == block_) {
+ // There are more blocks, but buffer_ does not know about them.
+ DCHECK_EQ(0u, remaining_);
+ block_ = nullptr;
+ } else {
+ block_ = block_->next_;
+ }
+ }
+ return remaining_ != 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+RWBuffer::RWBuffer(size_t initial_capacity) {
+ if (initial_capacity) {
+ head_ = RWBuffer::BufferHead::Alloc(initial_capacity);
+ tail_ = &head_->block_;
+ }
+}
+
+RWBuffer::~RWBuffer() {
+ Validate();
+ if (head_) {
+ head_->unref();
+ }
+}
+
+// It is important that we always completely fill the current block before
+// spilling over to the next, since our reader will be using capacity_ (min'd
+// against its total available) to know how many bytes to read from a given
+// block.
+//
+void RWBuffer::Append(const void* src, size_t length, size_t reserve) {
+ Validate();
+ if (0 == length) {
+ return;
+ }
+
+ total_used_ += length;
+
+ if (!head_) {
+ head_ = RWBuffer::BufferHead::Alloc(length + reserve);
+ tail_ = &head_->block_;
+ }
+
+ size_t written = tail_->Append(src, length);
+ DCHECK(written <= length);
+ src = static_cast<const char*>(src) + written;
+ length -= written;
+
+ if (length) {
+ auto* block = RWBuffer::BufferBlock::Alloc(length + reserve);
+ tail_->next_ = block;
+ tail_ = block;
+ written = tail_->Append(src, length);
+ DCHECK(written == length);
+ }
+ Validate();
+}
+
+scoped_refptr<ROBuffer> RWBuffer::MakeROBufferSnapshot() const {
+ return AdoptRef(new ROBuffer(head_, total_used_, tail_));
+}
+
+bool RWBuffer::HasNoSnapshots() const {
+ // Trivially, there are no other references to the underlying buffer, because
+ // there is no underlying buffer.
+ if (!head_) {
+ return true;
+ }
+
+ return head_->ref_count_.IsOne();
+}
+
+void RWBuffer::Validate() const {
+#if DCHECK_IS_ON()
+ if (head_) {
+ head_->Validate(total_used_, tail_);
+ } else {
+ DCHECK(!tail_);
+ DCHECK_EQ(0u, total_used_);
+ }
+#endif
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.h b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.h
new file mode 100644
index 00000000000..afbd5487a00
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer.h
@@ -0,0 +1,121 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
+
+namespace blink {
+
+class ROBuffer;
+
+/**
+ * Accumulates bytes of memory that are "appended" to it, growing internal
+ * storage as needed. The growth is done such that at any time in the writer's
+ * thread, an ROBuffer or StreamAsset can be snapped off (and safely passed to
+ * another thread). The ROBuffer/StreamAsset snapshot can see the previously
+ * stored bytes, but will be unaware of any future writes.
+ */
+class PLATFORM_EXPORT RWBuffer {
+ public:
+ struct BufferHead;
+ struct BufferBlock;
+
+ explicit RWBuffer(size_t initialCapacity = 0);
+ ~RWBuffer();
+
+ RWBuffer& operator=(const RWBuffer&) = delete;
+ RWBuffer(const RWBuffer&) = delete;
+
+ size_t size() const { return total_used_; }
+
+ /**
+ * Append |length| bytes from |buffer|.
+ *
+ * If the caller knows in advance how much more data they are going to
+ * append, they can pass a |reserve| hint (representing the number of upcoming
+ * bytes *in addition* to the current append), to minimize the number of
+ * internal allocations.
+ */
+ void Append(const void* buffer, size_t length, size_t reserve = 0);
+
+ scoped_refptr<ROBuffer> MakeROBufferSnapshot() const;
+
+ // This should only be called from the same thread that we are creating the
+ // RWBuffer and the snapshots on.
+ // If true is returned, it is guaranteed that |this| has unique ownership of
+ // its underlying buffer.
+ bool HasNoSnapshots() const;
+
+ void Validate() const;
+
+ private:
+ BufferHead* head_ = nullptr;
+ BufferBlock* tail_ = nullptr;
+ size_t total_used_ = 0;
+};
+
+/**
+ * Contains a read-only, thread-sharable block of memory. To access the memory,
+ * the caller must instantiate a local iterator, as the memory is stored in 1 or
+ * more contiguous blocks.
+ */
+class PLATFORM_EXPORT ROBuffer : public WTF::ThreadSafeRefCounted<ROBuffer> {
+ public:
+ /**
+ * Return the logical length of the data owned/shared by this buffer. It may
+ * be stored in multiple contiguous blocks, accessible via the iterator.
+ */
+ size_t size() const { return available_; }
+
+ class PLATFORM_EXPORT Iter {
+ public:
+ explicit Iter(const ROBuffer*);
+ explicit Iter(const scoped_refptr<ROBuffer>&);
+
+ void Reset(const ROBuffer*);
+
+ /**
+ * Return the current continuous block of memory, or nullptr if the
+ * iterator is exhausted
+ */
+ const void* data() const;
+
+ /**
+ * Returns the number of bytes in the current contiguous block of memory,
+ * or 0 if the iterator is exhausted.
+ */
+ size_t size() const;
+
+ /**
+ * Advance to the next contiguous block of memory, returning true if there
+ * is another block, or false if the iterator is exhausted.
+ */
+ bool Next();
+
+ private:
+ const RWBuffer::BufferBlock* block_;
+ size_t remaining_;
+ const ROBuffer* buffer_;
+ };
+
+ private:
+ friend class WTF::ThreadSafeRefCounted<ROBuffer>;
+ ROBuffer(const RWBuffer::BufferHead* head,
+ size_t available,
+ const RWBuffer::BufferBlock* tail);
+ ~ROBuffer();
+
+ const RWBuffer::BufferHead* head_;
+ const size_t available_;
+ const RWBuffer::BufferBlock* tail_;
+
+ friend class RWBuffer;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/rw_buffer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer_test.cc
new file mode 100644
index 00000000000..6143a0156df
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/rw_buffer_test.cc
@@ -0,0 +1,182 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
+
+#include <array>
+
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkStream.h"
+
+namespace blink {
+namespace {
+
+const char gABC[] = "abcdefghijklmnopqrstuvwxyz";
+
+void check_abcs(const char buffer[], size_t size) {
+ ASSERT_EQ(size % 26, 0u);
+ for (size_t offset = 0; offset < size; offset += 26) {
+ EXPECT_TRUE(!memcmp(&buffer[offset], gABC, 26));
+ }
+}
+
+// reader should contains an integral number of copies of gABC.
+void check_alphabet_buffer(const ROBuffer* reader) {
+ size_t size = reader->size();
+ ASSERT_EQ(size % 26, 0u);
+
+ std::vector<char> storage(size);
+ ROBuffer::Iter iter(reader);
+ size_t offset = 0;
+ do {
+ ASSERT_LE(offset + iter.size(), size);
+ memcpy(storage.data() + offset, iter.data(), iter.size());
+ offset += iter.size();
+ } while (iter.Next());
+ ASSERT_EQ(offset, size);
+ check_abcs(storage.data(), size);
+}
+
+class ROBufferTestThread : public base::PlatformThread::Delegate {
+ public:
+ ROBufferTestThread(scoped_refptr<ROBuffer> reader, size_t i)
+ : reader_(reader), i_(i) {}
+ ROBufferTestThread() = default;
+ ROBufferTestThread(const ROBufferTestThread&) = default;
+
+ void ThreadMain() override {
+ EXPECT_EQ((i_ + 1) * 26U, reader_->size());
+ check_alphabet_buffer(reader_.get());
+ }
+
+ scoped_refptr<ROBuffer> reader_;
+ size_t i_;
+};
+
+} // namespace
+
+TEST(RWBufferTest, Append) {
+ // Knowing that the default capacity is 4096, choose N large enough so we
+ // force it to use multiple buffers internally.
+ static constexpr size_t N = 1000;
+ std::array<scoped_refptr<ROBuffer>, N> readers;
+
+ {
+ RWBuffer buffer;
+ for (size_t i = 0; i < N; ++i) {
+ buffer.Append(gABC, 26);
+ readers[i] = buffer.MakeROBufferSnapshot();
+ }
+ EXPECT_EQ(N * 26, buffer.size());
+ }
+
+ // Verify that although the RWBuffer's destructor has run, the readers are
+ // still valid.
+ for (size_t i = 0; i < N; ++i) {
+ EXPECT_EQ((i + 1) * 26U, readers[i]->size());
+ check_alphabet_buffer(readers[i].get());
+ }
+}
+
+TEST(RWBufferTest, Threaded) {
+ // Knowing that the default capacity is 4096, choose N large enough so we
+ // force it to use multiple buffers internally.
+ constexpr size_t N = 1000;
+ RWBuffer buffer;
+ std::array<ROBufferTestThread, N> threads;
+ std::array<base::PlatformThreadHandle, N> handlers;
+
+ for (size_t i = 0; i < N; ++i) {
+ buffer.Append(gABC, 26);
+ scoped_refptr<ROBuffer> reader = buffer.MakeROBufferSnapshot();
+ EXPECT_EQ(reader->size(), buffer.size());
+
+ // reader's copy constructor will ref the ROBuffer, which will be unreffed
+ // when the task ends.
+ // Ownership of stream is passed to the task, which will delete it.
+ threads[i] = ROBufferTestThread(reader, i);
+ ASSERT_TRUE(base::PlatformThread::Create(0, &threads[i], &handlers[i]));
+ }
+ EXPECT_EQ(N * 26, buffer.size());
+ for (size_t i = 0; i < N; ++i) {
+ base::PlatformThread::Join(handlers[i]);
+ }
+}
+
+// Tests that it is safe to call ROBuffer::Iter::size() when exhausted.
+TEST(RWBufferTest, Size) {
+ RWBuffer buffer;
+ buffer.Append(gABC, 26);
+
+ scoped_refptr<ROBuffer> roBuffer(buffer.MakeROBufferSnapshot());
+ ROBuffer::Iter iter(roBuffer.get());
+ EXPECT_TRUE(iter.data());
+ EXPECT_EQ(iter.size(), 26u);
+
+ // There is only one block in this buffer.
+ EXPECT_TRUE(!iter.Next());
+ EXPECT_EQ(0u, iter.size());
+}
+
+// Tests that operations (including the destructor) are safe on an RWBuffer
+// without any data appended.
+TEST(RWBufferTest, Empty) {
+ RWBuffer buffer;
+ ASSERT_EQ(0u, buffer.size());
+
+ scoped_refptr<ROBuffer> roBuffer = buffer.MakeROBufferSnapshot();
+ ASSERT_TRUE(roBuffer);
+ if (roBuffer) {
+ EXPECT_EQ(roBuffer->size(), 0u);
+ ROBuffer::Iter iter(roBuffer.get());
+ EXPECT_EQ(iter.size(), 0u);
+ EXPECT_TRUE(!iter.data());
+ EXPECT_TRUE(!iter.Next());
+ }
+}
+
+// Tests that |HasNoSnapshots| returns the correct value when the buffer is
+// empty.
+// In this case, we can't tell if a snapshot has been created (in general), so
+// we expect to always get back false.
+TEST(RWBufferTest, HasNoSnapshotsEmpty) {
+ RWBuffer buffer;
+ ASSERT_EQ(0u, buffer.size());
+
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+
+ {
+ scoped_refptr<ROBuffer> first = buffer.MakeROBufferSnapshot();
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+
+ scoped_refptr<ROBuffer> second = buffer.MakeROBufferSnapshot();
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+ }
+
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+}
+
+// Tests that |HasNoSnapshots| returns the correct value when the buffer is
+// empty.
+TEST(RWBufferTest, HasNoSnapshots) {
+ RWBuffer buffer;
+ ASSERT_EQ(0u, buffer.size());
+
+ buffer.Append(gABC, 26);
+
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+
+ {
+ scoped_refptr<ROBuffer> first = buffer.MakeROBufferSnapshot();
+ EXPECT_FALSE(buffer.HasNoSnapshots());
+
+ scoped_refptr<ROBuffer> second = buffer.MakeROBufferSnapshot();
+ EXPECT_FALSE(buffer.HasNoSnapshots());
+ }
+
+ EXPECT_TRUE(buffer.HasNoSnapshots());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h b/chromium/third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h
index 933ce6a5b47..de11cfd5b20 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"
diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
index d2ca053713d..71afa00c65d 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
@@ -199,7 +199,13 @@ SkMatrix AffineTransformToSkMatrix(const AffineTransform& source) {
// SkMatrices are 3x3, so they have a concept of "perspective" in the bottom
// row. blink::AffineTransform is a 2x3 matrix that can encode 2d rotations,
// skew and translation, but has no perspective. Those parameters are set to
- // zero here.
+ // zero here. i.e.:
+
+ // INPUT OUTPUT
+ // | a c e | | a c e |
+ // | b d f | ----> | b d f |
+ // | 0 0 1 |
+
SkMatrix result;
result.setScaleX(WebCoreDoubleToSkScalar(source.A()));
@@ -218,8 +224,16 @@ SkMatrix AffineTransformToSkMatrix(const AffineTransform& source) {
}
SkMatrix TransformationMatrixToSkMatrix(const TransformationMatrix& source) {
- // For now this just encodes to a 2x3 transform, like the above function
- // TODO(aaronhk) use the perspective properly crbug.com/1140535
+ // SkMatrix is 3x3, TransformationMatrix is 4x4, this function encodes
+ // assuming that a 2D-transformation with perspective is what's desired,
+ // throwing out the z-dimension values. i.e.:
+
+ // INPUT OUTPUT
+ // | m11 m21 m31 m41 | | m11 m21 m41 |
+ // | m12 m22 m32 m42 | ----> | m12 m22 m42 |
+ // | m13 m23 m33 m43 | | m14 m24 m44 |
+ // | m14 m24 m34 m44 |
+
SkMatrix result;
result.setScaleX(WebCoreDoubleToSkScalar(source.M11()));
@@ -230,9 +244,9 @@ SkMatrix TransformationMatrixToSkMatrix(const TransformationMatrix& source) {
result.setSkewY(WebCoreDoubleToSkScalar(source.M12()));
result.setTranslateY(WebCoreDoubleToSkScalar(source.M42()));
- result.setPerspX(0);
- result.setPerspY(0);
- result.set(SkMatrix::kMPersp2, SK_Scalar1);
+ result.setPerspX(source.M14());
+ result.setPerspY(source.M24());
+ result.set(SkMatrix::kMPersp2, source.M44());
return result;
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
index 93e9bb7fc1b..631a02551cb 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
@@ -47,6 +47,7 @@ void StaticBitmapImage::DrawHelper(
const PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
ImageClampingMode clamp_mode,
RespectImageOrientationEnum respect_orientation,
const PaintImage& image) {
@@ -75,60 +76,9 @@ void StaticBitmapImage::DrawHelper(
}
}
- canvas->drawImageRect(image, adjusted_src_rect, adjusted_dst_rect, &flags,
+ canvas->drawImageRect(image, adjusted_src_rect, adjusted_dst_rect, sampling,
+ &flags,
WebCoreClampingModeToSkiaRectConstraint(clamp_mode));
}
-base::CheckedNumeric<size_t> StaticBitmapImage::GetSizeInBytes(
- const IntRect& rect,
- const CanvasColorParams& color_params) {
- uint8_t bytes_per_pixel = color_params.BytesPerPixel();
- base::CheckedNumeric<size_t> data_size = bytes_per_pixel;
- data_size *= rect.Size().Area();
- return data_size;
-}
-
-bool StaticBitmapImage::MayHaveStrayArea(
- scoped_refptr<StaticBitmapImage> src_image,
- const IntRect& rect) {
- if (!src_image)
- return false;
-
- return rect.X() < 0 || rect.Y() < 0 ||
- rect.MaxX() > src_image->Size().Width() ||
- rect.MaxY() > src_image->Size().Height();
-}
-
-bool StaticBitmapImage::CopyToByteArray(
- scoped_refptr<StaticBitmapImage> src_image,
- base::span<uint8_t> dst,
- const IntRect& rect,
- const CanvasColorParams& color_params) {
- DCHECK_EQ(dst.size(), GetSizeInBytes(rect, color_params).ValueOrDie());
-
- if (!src_image)
- return true;
-
- if (dst.size() == 0)
- return true;
-
- SkColorType color_type =
- (color_params.GetSkColorType() == kRGBA_F16_SkColorType)
- ? kRGBA_F16_SkColorType
- : kRGBA_8888_SkColorType;
- SkImageInfo info =
- SkImageInfo::Make(rect.Width(), rect.Height(), color_type,
- kUnpremul_SkAlphaType, color_params.GetSkColorSpace());
- bool read_pixels_successful =
- src_image->PaintImageForCurrentFrame().readPixels(
- info, dst.data(), info.minRowBytes(), rect.X(), rect.Y());
- DCHECK(read_pixels_successful ||
- !src_image->PaintImageForCurrentFrame()
- .GetSkImageInfo()
- .bounds()
- .intersect(SkIRect::MakeXYWH(rect.X(), rect.Y(), info.width(),
- info.height())));
- return true;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
index e05d58fc355..a01b2c2cecf 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
@@ -96,24 +96,13 @@ class PLATFORM_EXPORT StaticBitmapImage : public Image {
return orientation_ == ImageOrientationEnum::kDefault;
}
- static base::CheckedNumeric<size_t> GetSizeInBytes(
- const IntRect& rect,
- const CanvasColorParams& color_params);
-
- static bool MayHaveStrayArea(scoped_refptr<StaticBitmapImage> src_image,
- const IntRect& rect);
-
- static bool CopyToByteArray(scoped_refptr<StaticBitmapImage> src_image,
- base::span<uint8_t> dst,
- const IntRect&,
- const CanvasColorParams&);
-
protected:
// Helper for sub-classes
void DrawHelper(cc::PaintCanvas*,
const cc::PaintFlags&,
const FloatRect&,
const FloatRect&,
+ const SkSamplingOptions&,
ImageClampingMode,
RespectImageOrientationEnum,
const PaintImage&);
diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image_test.cc
deleted file mode 100644
index 4784533fa9d..00000000000
--- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image_test.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
-#include "third_party/skia/include/core/SkSurface.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class StaticBitmapImageTest : public testing::Test {};
-
-// This test verifies if requesting a large ImageData that cannot be handled by
-// V8 is denied by StaticBitmapImage. This prevents V8 from crashing the
-// renderer if the user asks to get back the ImageData.
-TEST_F(StaticBitmapImageTest,
- ConvertArrayBufferContentsTooBigToAllocateDoesNotCrash) {
- SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
- sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
- EXPECT_TRUE(!!surface);
-
- scoped_refptr<StaticBitmapImage> image =
- UnacceleratedStaticBitmapImage::Create(surface->makeImageSnapshot());
-
- IntRect too_big_rect(IntPoint(0, 0),
- IntSize(1, (v8::TypedArray::kMaxLength / 4) + 1));
- EXPECT_GT(StaticBitmapImage::GetSizeInBytes(too_big_rect, CanvasColorParams())
- .ValueOrDie(),
- v8::TypedArray::kMaxLength);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
index 3406b920e0d..f4a9de25760 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
@@ -82,12 +82,13 @@ void UnacceleratedStaticBitmapImage::Draw(
const cc::PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions& sampling,
RespectImageOrientationEnum should_respect_image_orientation,
ImageClampingMode clamp_mode,
ImageDecodingMode) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect, clamp_mode,
- should_respect_image_orientation,
+ StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect, sampling,
+ clamp_mode, should_respect_image_orientation,
PaintImageForCurrentFrame());
}
diff --git a/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h
index 8496da774ba..061ac1444c3 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h
@@ -36,6 +36,7 @@ class PLATFORM_EXPORT UnacceleratedStaticBitmapImage final
const cc::PaintFlags&,
const FloatRect& dst_rect,
const FloatRect& src_rect,
+ const SkSamplingOptions&,
RespectImageOrientationEnum,
ImageClampingMode,
ImageDecodingMode) override;
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc
new file mode 100644
index 00000000000..49c71dee3d0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc
@@ -0,0 +1,231 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
+
+#include "build/build_config.h"
+#include "components/viz/common/gpu/raster_context_provider.h"
+#include "components/viz/common/resources/single_release_callback.h"
+#include "gpu/config/gpu_feature_info.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_types.h"
+#include "media/base/video_util.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
+#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace blink {
+
+namespace {
+
+scoped_refptr<viz::RasterContextProvider> GetRasterContextProvider() {
+ auto wrapper = SharedGpuContext::ContextProviderWrapper();
+ if (!wrapper)
+ return nullptr;
+
+ if (auto* provider = wrapper->ContextProvider())
+ return base::WrapRefCounted(provider->RasterContextProvider());
+
+ return nullptr;
+}
+
+bool CanUseZeroCopyImages(const media::VideoFrame& frame) {
+ // SharedImage optimization: create AcceleratedStaticBitmapImage directly.
+ // Disabled on Android because the hardware decode implementation may neuter
+ // frames, which would violate ImageBitmap requirements.
+ // TODO(sandersd): Handle YUV pixel formats.
+ // TODO(sandersd): Handle high bit depth formats.
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return frame.NumTextures() == 1 &&
+ frame.mailbox_holder(0).mailbox.IsSharedImage() &&
+ (frame.format() == media::PIXEL_FORMAT_ARGB ||
+ frame.format() == media::PIXEL_FORMAT_XRGB ||
+ frame.format() == media::PIXEL_FORMAT_ABGR ||
+ frame.format() == media::PIXEL_FORMAT_XBGR ||
+ frame.format() == media::PIXEL_FORMAT_BGRA);
+#endif
+}
+
+bool ShouldCreateAcceleratedImages(
+ viz::RasterContextProvider* raster_context_provider) {
+ if (!SharedGpuContext::IsGpuCompositingEnabled())
+ return false;
+
+ if (!raster_context_provider)
+ return false;
+
+ if (raster_context_provider->GetGpuFeatureInfo().IsWorkaroundEnabled(
+ DISABLE_IMAGEBITMAP_FROM_VIDEO_USING_GPU)) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+bool WillCreateAcceleratedImagesFromVideoFrame(const media::VideoFrame* frame) {
+ return CanUseZeroCopyImages(*frame) ||
+ ShouldCreateAcceleratedImages(GetRasterContextProvider().get());
+}
+
+scoped_refptr<StaticBitmapImage> CreateImageFromVideoFrame(
+ scoped_refptr<media::VideoFrame> frame,
+ bool allow_zero_copy_images,
+ CanvasResourceProvider* resource_provider,
+ media::PaintCanvasVideoRenderer* video_renderer,
+ const gfx::Rect& dest_rect) {
+ DCHECK(frame);
+ if (allow_zero_copy_images && dest_rect.IsEmpty() &&
+ CanUseZeroCopyImages(*frame)) {
+ // TODO(sandersd): Do we need to be able to handle limited-range RGB? It
+ // may never happen, and SkColorSpace doesn't know about it.
+ auto sk_color_space =
+ frame->ColorSpace().GetAsFullRangeRGB().ToSkColorSpace();
+ if (!sk_color_space)
+ sk_color_space = SkColorSpace::MakeSRGB();
+
+ const SkImageInfo sk_image_info = SkImageInfo::Make(
+ frame->coded_size().width(), frame->coded_size().height(),
+ kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space));
+
+ // Hold a ref by storing it in the release callback.
+ auto release_callback = viz::SingleReleaseCallback::Create(
+ WTF::Bind([](scoped_refptr<media::VideoFrame> frame,
+ const gpu::SyncToken& sync_token, bool is_lost) {},
+ frame));
+
+ return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
+ frame->mailbox_holder(0).mailbox, frame->mailbox_holder(0).sync_token,
+ 0u, sk_image_info, frame->mailbox_holder(0).texture_target, true,
+ // Pass nullptr for |context_provider_wrapper|, because we don't
+ // know which context the mailbox came from. It is used only to
+ // detect when the mailbox is invalid due to context loss, and is
+ // ignored when |is_cross_thread|.
+ base::WeakPtr<WebGraphicsContext3DProviderWrapper>(),
+ // Pass null |context_thread_ref|, again because we don't know
+ // which context the mailbox came from. This should always trigger
+ // |is_cross_thread|.
+ base::PlatformThreadRef(),
+ // The task runner is only used for |release_callback|.
+ Thread::Current()->GetTaskRunner(), std::move(release_callback));
+ }
+
+ gfx::Rect final_dest_rect = dest_rect;
+ if (final_dest_rect.IsEmpty()) {
+ // Since we're copying, the destination is always aligned with the origin.
+ const auto& visible_rect = frame->visible_rect();
+ final_dest_rect =
+ gfx::Rect(0, 0, visible_rect.width(), visible_rect.height());
+ } else if (!resource_provider) {
+ DLOG(ERROR) << "An external CanvasResourceProvider must be provided when "
+ "providing a custom destination rect.";
+ return nullptr;
+ } else if (!gfx::Rect(gfx::Size(resource_provider->Size()))
+ .Contains(final_dest_rect)) {
+ DLOG(ERROR)
+ << "Provided CanvasResourceProvider is too small. Expected at least "
+ << final_dest_rect.ToString() << " got "
+ << resource_provider->Size().ToString();
+ return nullptr;
+ }
+
+ auto raster_context_provider = GetRasterContextProvider();
+ const auto resource_provider_size = IntSize(final_dest_rect.size());
+ std::unique_ptr<CanvasResourceProvider> local_resource_provider;
+ if (!resource_provider) {
+ local_resource_provider = CreateResourceProviderForVideoFrame(
+ resource_provider_size, raster_context_provider.get());
+ if (!local_resource_provider) {
+ DLOG(ERROR) << "Failed to create CanvasResourceProvider.";
+ return nullptr;
+ }
+
+ resource_provider = local_resource_provider.get();
+ }
+
+ if (!DrawVideoFrameIntoResourceProvider(std::move(frame), resource_provider,
+ raster_context_provider.get(),
+ final_dest_rect, video_renderer)) {
+ return nullptr;
+ }
+ return resource_provider->Snapshot();
+}
+
+bool DrawVideoFrameIntoResourceProvider(
+ scoped_refptr<media::VideoFrame> frame,
+ CanvasResourceProvider* resource_provider,
+ viz::RasterContextProvider* raster_context_provider,
+ const gfx::Rect& dest_rect,
+ media::PaintCanvasVideoRenderer* video_renderer) {
+ DCHECK(frame);
+ DCHECK(resource_provider);
+ DCHECK(gfx::Rect(gfx::Size(resource_provider->Size())).Contains(dest_rect));
+
+ if (frame->HasTextures()) {
+ if (!raster_context_provider) {
+ DLOG(ERROR) << "Unable to process a texture backed VideoFrame w/o a "
+ "RasterContextProvider.";
+ return false; // Unable to get/create a shared main thread context.
+ }
+ if (!raster_context_provider->GrContext() &&
+ !raster_context_provider->ContextCapabilities().supports_oop_raster) {
+ DLOG(ERROR) << "Unable to process a texture backed VideoFrame w/o a "
+ "GrContext or OOP raster support.";
+ return false; // The context has been lost.
+ }
+ }
+
+ cc::PaintFlags media_flags;
+ media_flags.setAlpha(0xFF);
+ media_flags.setFilterQuality(kLow_SkFilterQuality);
+ media_flags.setBlendMode(SkBlendMode::kSrc);
+
+ std::unique_ptr<media::PaintCanvasVideoRenderer> local_video_renderer;
+ if (!video_renderer) {
+ local_video_renderer = std::make_unique<media::PaintCanvasVideoRenderer>();
+ video_renderer = local_video_renderer.get();
+ }
+
+ // If the provider isn't accelerated, avoid GPU round trips to upload frame
+ // data from GpuMemoryBuffer backed frames which aren't mappable.
+ if (frame->HasGpuMemoryBuffer() && !frame->IsMappable() &&
+ !resource_provider->IsAccelerated()) {
+ frame = media::ConvertToMemoryMappedFrame(std::move(frame));
+ }
+
+ video_renderer->Paint(
+ frame.get(), resource_provider->Canvas(), gfx::RectF(dest_rect),
+ media_flags,
+ frame->metadata().transformation.value_or(media::kNoTransformation),
+ raster_context_provider);
+ return true;
+}
+
+std::unique_ptr<CanvasResourceProvider> CreateResourceProviderForVideoFrame(
+ IntSize size,
+ viz::RasterContextProvider* raster_context_provider) {
+ if (!ShouldCreateAcceleratedImages(raster_context_provider)) {
+ return CanvasResourceProvider::CreateBitmapProvider(
+ size, kLow_SkFilterQuality, CanvasResourceParams(),
+ CanvasResourceProvider::ShouldInitialize::kNo);
+ }
+
+ return CanvasResourceProvider::CreateSharedImageProvider(
+ size, kLow_SkFilterQuality, CanvasResourceParams(),
+ CanvasResourceProvider::ShouldInitialize::kNo,
+ SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
+ false, // Origin of GL texture is bottom left on screen
+ gpu::SHARED_IMAGE_USAGE_DISPLAY);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.h b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.h
new file mode 100644
index 00000000000..6db3ed2231a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util.h
@@ -0,0 +1,86 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_VIDEO_FRAME_IMAGE_UTIL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_VIDEO_FRAME_IMAGE_UTIL_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/geometry/rect.h"
+
+// Note: Don't include "media/base/video_frame.h" here without good reason,
+// since it includes a lot of non-blink types which can pollute the namespace.
+
+namespace media {
+class PaintCanvasVideoRenderer;
+class VideoFrame;
+} // namespace media
+
+namespace viz {
+class RasterContextProvider;
+}
+
+namespace blink {
+class CanvasResourceProvider;
+class StaticBitmapImage;
+
+// Returns true if CreateImageFromVideoFrame() expects to create an
+// AcceleratedStaticBitmapImage. Note: This may be overridden if a software
+// |resource_provider| is given to CreateImageFromVideoFrame().
+PLATFORM_EXPORT bool WillCreateAcceleratedImagesFromVideoFrame(
+ const media::VideoFrame* frame);
+
+// Returns a StaticBitmapImage for the given frame. Accelerated images will be
+// preferred if possible. A zero copy mechanism will be preferred if possible
+// unless |allow_zero_copy_images| is false.
+//
+// |video_renderer| may optionally be provided in cases where the same frame may
+// end up repeatedly converted.
+//
+// Likewise |resource_provider| may be provided to prevent thrashing when this
+// method is called with high frequency.
+//
+// The default resource provider size is the frame's visible size. The default
+// |dest_rect| is the visible size aligned to the origin. Callers may choose to
+// provide their own |resource_provider| and |dest_rect| for rendering to the
+// frame's natural size.
+//
+// When an external |resource_provider| is provided a |dest_rect| may also be
+// provided to control where in the canvas the VideoFrame will be drawn. A
+// non-empty |dest_rect| will disable zero copy image support.
+PLATFORM_EXPORT scoped_refptr<StaticBitmapImage> CreateImageFromVideoFrame(
+ scoped_refptr<media::VideoFrame> frame,
+ bool allow_zero_copy_images = true,
+ CanvasResourceProvider* resource_provider = nullptr,
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr,
+ const gfx::Rect& dest_rect = gfx::Rect());
+
+// Similar to the above, but just skips creating the StaticBitmapImage from the
+// CanvasResourceProvider. Returns true if the frame could be drawn or false
+// otherwise. Note: In certain failure modes a black frame will be drawn.
+//
+// |video_renderer| may optionally be provided in cases where the same frame may
+// end up repeatedly drawn.
+//
+// A |raster_context_provider| is required to convert texture backed frames.
+PLATFORM_EXPORT bool DrawVideoFrameIntoResourceProvider(
+ scoped_refptr<media::VideoFrame> frame,
+ CanvasResourceProvider* resource_provider,
+ viz::RasterContextProvider* raster_context_provider,
+ const gfx::Rect& dest_rect,
+ media::PaintCanvasVideoRenderer* video_renderer = nullptr);
+
+// Creates a CanvasResourceProvider which is appropriate for drawing VideoFrame
+// objects into. Some callers to CreateImageFromVideoFrame() may choose to cache
+// their resource providers. If |raster_context_provider| is null a software
+// resource provider will be returned.
+PLATFORM_EXPORT std::unique_ptr<CanvasResourceProvider>
+CreateResourceProviderForVideoFrame(
+ IntSize size,
+ viz::RasterContextProvider* raster_context_provider);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_VIDEO_FRAME_IMAGE_UTIL_H_
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc
new file mode 100644
index 00000000000..125945f8bb4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc
@@ -0,0 +1,313 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
+
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "components/viz/common/gpu/raster_context_provider.h"
+#include "components/viz/test/test_context_provider.h"
+#include "gpu/command_buffer/common/capabilities.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/shared_image_video_frame_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
+#include "third_party/blink/renderer/platform/testing/video_frame_utils.h"
+
+namespace blink {
+
+namespace {
+
+constexpr auto kTestSize = gfx::Size(64, 64);
+
+class ScopedFakeGpuContext {
+ public:
+ explicit ScopedFakeGpuContext(bool disable_imagebitmap) {
+ SharedGpuContext::ResetForTesting();
+ test_context_provider_ = viz::TestContextProvider::Create();
+
+ if (disable_imagebitmap) {
+ // Disable CanvasResourceProvider using GPU.
+ auto& feature_info = test_context_provider_->GetWritableGpuFeatureInfo();
+ feature_info.enabled_gpu_driver_bug_workarounds.push_back(
+ DISABLE_IMAGEBITMAP_FROM_VIDEO_USING_GPU);
+ }
+
+ InitializeSharedGpuContext(test_context_provider_.get());
+ }
+
+ scoped_refptr<viz::ContextProvider> context_provider() const {
+ return test_context_provider_;
+ }
+
+ viz::RasterContextProvider* raster_context_provider() const {
+ return test_context_provider_.get();
+ }
+
+ ~ScopedFakeGpuContext() {
+ task_environment_.RunUntilIdle();
+ SharedGpuContext::ResetForTesting();
+ }
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ scoped_refptr<viz::TestContextProvider> test_context_provider_;
+};
+
+} // namespace
+
+TEST(VideoFrameImageUtilTest, WillCreateAcceleratedImagesFromVideoFrame) {
+ // I420A isn't a supported zero copy format.
+ {
+ auto alpha_frame = media::VideoFrame::CreateTransparentFrame(kTestSize);
+ EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(alpha_frame.get()));
+ }
+
+ // Software RGB frames aren't supported.
+ {
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+ EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(cpu_frame.get()));
+ }
+
+ // GpuMemoryBuffer frames aren't supported.
+ {
+ auto cpu_frame = CreateTestFrame(
+ kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER, media::PIXEL_FORMAT_XRGB);
+ EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(cpu_frame.get()));
+ }
+
+ // Single mailbox shared images should be supported except on Android.
+ {
+ auto shared_image_frame = CreateTestFrame(
+ kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OPAQUE, media::PIXEL_FORMAT_XRGB);
+ EXPECT_EQ(shared_image_frame->NumTextures(), 1u);
+ EXPECT_TRUE(shared_image_frame->mailbox_holder(0).mailbox.IsSharedImage());
+#if defined(OS_ANDROID)
+ EXPECT_FALSE(
+ WillCreateAcceleratedImagesFromVideoFrame(shared_image_frame.get()));
+#else
+ EXPECT_TRUE(
+ WillCreateAcceleratedImagesFromVideoFrame(shared_image_frame.get()));
+#endif
+ }
+}
+
+// Android doesn't support zero copy images.
+#if !defined(OS_ANDROID)
+TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameZeroCopy) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+ auto shared_image_frame = CreateTestFrame(
+ kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OPAQUE, media::PIXEL_FORMAT_XRGB);
+ EXPECT_EQ(shared_image_frame->NumTextures(), 1u);
+ EXPECT_TRUE(shared_image_frame->mailbox_holder(0).mailbox.IsSharedImage());
+
+ auto image = CreateImageFromVideoFrame(shared_image_frame);
+ ASSERT_TRUE(image->IsTextureBacked());
+ EXPECT_EQ(memcmp(image->GetMailboxHolder().mailbox.name,
+ shared_image_frame->mailbox_holder(0).mailbox.name,
+ sizeof(gpu::Mailbox::Name)),
+ 0);
+}
+#endif
+
+TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameSoftwareFrame) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+ auto image = CreateImageFromVideoFrame(cpu_frame);
+ ASSERT_FALSE(image->IsTextureBacked());
+ task_environment_.RunUntilIdle();
+}
+
+TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameGpuMemoryBufferFrame) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
+ media::PIXEL_FORMAT_NV12);
+ auto image = CreateImageFromVideoFrame(cpu_frame);
+ ASSERT_FALSE(image->IsTextureBacked());
+ task_environment_.RunUntilIdle();
+}
+
+TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameTextureFrame) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OPAQUE,
+ media::PIXEL_FORMAT_NV12);
+ auto image = CreateImageFromVideoFrame(cpu_frame);
+
+ // An unaccelerated image can't be created from a texture based VideoFrame
+ // without a viz::RasterContextProvider.
+ ASSERT_FALSE(image);
+ task_environment_.RunUntilIdle();
+}
+
+TEST(VideoFrameImageUtilTest,
+ CreateAcceleratedImageFromVideoFrameBasicSoftwareFrame) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+ auto image = CreateImageFromVideoFrame(cpu_frame);
+ ASSERT_TRUE(image->IsTextureBacked());
+}
+
+TEST(VideoFrameImageUtilTest, CreateAcceleratedImageFromGpuMemoryBufferFrame) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+ auto gmb_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
+ media::PIXEL_FORMAT_NV12);
+ auto image = CreateImageFromVideoFrame(gmb_frame);
+ ASSERT_TRUE(image->IsTextureBacked());
+}
+
+TEST(VideoFrameImageUtilTest, CreateAcceleratedImageFromTextureFrame) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+
+ auto texture_frame = media::CreateSharedImageRGBAFrame(
+ fake_context.context_provider(), kTestSize, gfx::Rect(kTestSize),
+ base::DoNothing::Once());
+ auto image = CreateImageFromVideoFrame(texture_frame,
+ /*allow_zero_copy_images=*/false);
+ ASSERT_TRUE(image->IsTextureBacked());
+}
+
+TEST(VideoFrameImageUtilTest, FlushedAcceleratedImage) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+
+ auto texture_frame = media::CreateSharedImageRGBAFrame(
+ fake_context.context_provider(), kTestSize, gfx::Rect(kTestSize),
+ base::DoNothing::Once());
+
+ auto* raster_context_provider = fake_context.raster_context_provider();
+ ASSERT_TRUE(raster_context_provider);
+
+ auto provider = CreateResourceProviderForVideoFrame(IntSize(kTestSize),
+ raster_context_provider);
+ ASSERT_TRUE(provider);
+ EXPECT_TRUE(provider->IsAccelerated());
+
+ auto image = CreateImageFromVideoFrame(texture_frame,
+ /*allow_zero_copy_images=*/false,
+ provider.get());
+ EXPECT_TRUE(image->IsTextureBacked());
+
+ image = CreateImageFromVideoFrame(texture_frame,
+ /*allow_zero_copy_images=*/false,
+ provider.get());
+ EXPECT_TRUE(image->IsTextureBacked());
+
+ ASSERT_FALSE(provider->needs_flush());
+ ASSERT_FALSE(provider->HasRecordedDrawOps());
+}
+
+TEST(VideoFrameImageUtilTest, SoftwareCreateResourceProviderForVideoFrame) {
+ // Creating a provider with a null viz::RasterContextProvider should result in
+ // a non-accelerated provider being created.
+ auto provider =
+ CreateResourceProviderForVideoFrame(IntSize(kTestSize), nullptr);
+ ASSERT_TRUE(provider);
+ EXPECT_FALSE(provider->IsAccelerated());
+}
+
+TEST(VideoFrameImageUtilTest, AcceleratedCreateResourceProviderForVideoFrame) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
+ ASSERT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
+
+ auto* raster_context_provider = fake_context.raster_context_provider();
+ ASSERT_TRUE(raster_context_provider);
+
+ // Creating a provider with a null viz::RasterContextProvider should result in
+ // a non-accelerated provider being created.
+ {
+ auto provider =
+ CreateResourceProviderForVideoFrame(IntSize(kTestSize), nullptr);
+ ASSERT_TRUE(provider);
+ EXPECT_FALSE(provider->IsAccelerated());
+ }
+
+ // Creating a provider with a real raster context provider should result in
+ // an accelerated provider being created.
+ {
+ auto provider = CreateResourceProviderForVideoFrame(
+ IntSize(kTestSize), raster_context_provider);
+ ASSERT_TRUE(provider);
+ EXPECT_TRUE(provider->IsAccelerated());
+ }
+}
+
+TEST(VideoFrameImageUtilTest, WorkaroundCreateResourceProviderForVideoFrame) {
+ ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/true);
+ ASSERT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
+
+ auto* raster_context_provider = fake_context.raster_context_provider();
+ ASSERT_TRUE(raster_context_provider);
+
+ // Creating a provider with a real raster context provider should result in
+ // an unaccelerated provider being created due to the workaround.
+ {
+ auto provider = CreateResourceProviderForVideoFrame(
+ IntSize(kTestSize), raster_context_provider);
+ ASSERT_TRUE(provider);
+ EXPECT_FALSE(provider->IsAccelerated());
+ }
+}
+
+TEST(VideoFrameImageUtilTest, DestRectWithoutCanvasResourceProvider) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+
+ // A CanvasResourceProvider must be provided with a custom destination rect.
+ auto image = CreateImageFromVideoFrame(cpu_frame, true, nullptr, nullptr,
+ gfx::Rect(0, 0, 10, 10));
+ ASSERT_FALSE(image);
+ task_environment_.RunUntilIdle();
+}
+
+TEST(VideoFrameImageUtilTest, CanvasResourceProviderTooSmallForDestRect) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+
+ auto provider =
+ CreateResourceProviderForVideoFrame(IntSize(gfx::Size(16, 16)), nullptr);
+ ASSERT_TRUE(provider);
+ EXPECT_FALSE(provider->IsAccelerated());
+
+ auto image = CreateImageFromVideoFrame(cpu_frame, true, provider.get(),
+ nullptr, gfx::Rect(kTestSize));
+ ASSERT_FALSE(image);
+ task_environment_.RunUntilIdle();
+}
+
+TEST(VideoFrameImageUtilTest, CanvasResourceProviderDestRect) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::PIXEL_FORMAT_XRGB);
+
+ auto provider = CreateResourceProviderForVideoFrame(
+ IntSize(gfx::Size(128, 128)), nullptr);
+ ASSERT_TRUE(provider);
+ EXPECT_FALSE(provider->IsAccelerated());
+
+ auto image = CreateImageFromVideoFrame(cpu_frame, true, provider.get(),
+ nullptr, gfx::Rect(16, 16, 64, 64));
+ ASSERT_TRUE(image);
+ task_environment_.RunUntilIdle();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 7a51d095305..6ca10257819 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -11,6 +11,9 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "cc/metrics/video_playback_roughness_reporter.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/returned_resource.h"
#include "media/base/video_frame.h"
@@ -37,7 +40,10 @@ VideoFrameSubmitter::VideoFrameSubmitter(
rotation_(media::VIDEO_ROTATION_0),
roughness_reporter_(std::make_unique<cc::VideoPlaybackRoughnessReporter>(
std::move(roughness_reporting_callback))),
- frame_trackers_(false, nullptr) {
+ frame_trackers_(false, nullptr),
+ animation_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Animation.Video")) {
DETACH_FROM_THREAD(thread_checker_);
}
@@ -65,6 +71,8 @@ void VideoFrameSubmitter::StartRendering() {
if (compositor_frame_sink_) {
compositor_frame_sink_->SetNeedsBeginFrame(IsDrivingFrameUpdates());
+ animation_power_mode_voter_->VoteFor(
+ power_scheduler::PowerMode::kAnimation);
}
frame_trackers_.StartSequence(cc::FrameSequenceTrackerType::kVideo);
@@ -374,11 +382,15 @@ void VideoFrameSubmitter::UpdateSubmissionState() {
const auto is_driving_frame_updates = IsDrivingFrameUpdates();
compositor_frame_sink_->SetNeedsBeginFrame(is_driving_frame_updates);
+ animation_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kAnimation);
// If we're not driving frame updates, then we're paused / off-screen / etc.
// Roughness reporting should stop until we resume. Since the current frame
// might be on-screen for a long time, we also discard the current window.
- if (!is_driving_frame_updates)
+ if (!is_driving_frame_updates) {
roughness_reporter_->Reset();
+ animation_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kAnimationTimeout);
+ }
// These two calls are very important; they are responsible for significant
// memory savings when content is off-screen.
@@ -575,8 +587,8 @@ viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame(
? video_frame_provider_->GetPreferredRenderInterval()
: viz::BeginFrameArgs::MinInterval();
- if (video_frame && video_frame->metadata()->decode_end_time.has_value()) {
- base::TimeTicks value = *video_frame->metadata()->decode_end_time;
+ if (video_frame && video_frame->metadata().decode_end_time.has_value()) {
+ base::TimeTicks value = *video_frame->metadata().decode_end_time;
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
"media", "VideoFrameSubmitter", TRACE_ID_LOCAL(frame_token), value);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index 476bb662750..e96e6659227 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -15,6 +15,7 @@
#include "base/timer/timer.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
#include "cc/metrics/video_playback_roughness_reporter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/client/shared_bitmap_reporter.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/resources/shared_bitmap.h"
@@ -195,6 +196,8 @@ class PLATFORM_EXPORT VideoFrameSubmitter
// presented.
base::flat_set<uint32_t> ignorable_submitted_frames_;
+ std::unique_ptr<power_scheduler::PowerModeVoter> animation_power_mode_voter_;
+
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_{this};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index af7d14af6bc..54b5cc6d2da 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -992,7 +992,7 @@ TEST_F(VideoFrameSubmitterTest, ProcessTimingDetails) {
auto frame = media::VideoFrame::CreateFrame(
media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
gfx::Size(8, 8), i * frame_duration);
- frame->metadata()->wallclock_frame_duration = frame_duration;
+ frame->metadata().wallclock_frame_duration = frame_duration;
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillRepeatedly(Return(frame));
diff --git a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
index 52b0679d553..459e411198a 100644
--- a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -16,7 +16,6 @@ buildflag_header("blink_heap_buildflags") {
flags = [
"BLINK_HEAP_VERIFICATION=$enable_blink_heap_verification",
"BLINK_HEAP_YOUNG_GENERATION=$enable_blink_heap_young_generation",
- "BLINK_HEAP_USE_V8_OILPAN=$enable_blink_heap_use_v8_oilpan",
]
}
@@ -55,15 +54,24 @@ blink_platform_sources("heap") {
sources = [
"blink_gc_memory_dump_provider.h",
+ "collection_support/heap_deque.h",
+ "collection_support/heap_hash_counted_set.h",
+ "collection_support/heap_hash_map.h",
+ "collection_support/heap_hash_set.h",
"collection_support/heap_hash_table_backing.h",
+ "collection_support/heap_linked_hash_set.h",
"collection_support/heap_linked_stack.h",
+ "collection_support/heap_list_hash_set.h",
+ "collection_support/heap_vector.h",
"collection_support/heap_vector_backing.h",
+ "custom_spaces.h",
"disallow_new_wrapper.h",
"garbage_collected.h",
"gc_task_runner.h",
"handle.h",
"heap.h",
"heap_allocator.h",
+ "heap_allocator_impl.h",
"heap_stats_collector.h",
"heap_traits.h",
"member.h",
@@ -72,6 +80,7 @@ blink_platform_sources("heap") {
"self_keep_alive.h",
"thread_state.h",
"thread_state_scopes.h",
+ "trace_traits.h",
"unified_heap_controller.h",
"unified_heap_marking_visitor.h",
"visitor.h",
@@ -83,6 +92,7 @@ blink_platform_sources("heap") {
"//third_party/blink/renderer/platform:make_platform_generated",
"//third_party/blink/renderer/platform/heap:heap_unsanitized",
"//third_party/blink/renderer/platform/heap/asm",
+ "//third_party/blink/renderer/platform/wtf:buildflags",
"//third_party/icu",
"//v8",
]
@@ -90,25 +100,36 @@ blink_platform_sources("heap") {
if (enable_blink_heap_use_v8_oilpan) {
sources += [
"v8_wrapper/blink_gc.h",
+ "v8_wrapper/blink_gc_memory_dump_provider.cc",
"v8_wrapper/blink_gc_memory_dump_provider.h",
- "v8_wrapper/disallow_new_wrapper.h",
+ "v8_wrapper/collection_support/heap_hash_table_backing.h",
+ "v8_wrapper/collection_support/heap_vector_backing.h",
+ "v8_wrapper/custom_spaces.cc",
+ "v8_wrapper/custom_spaces.h",
"v8_wrapper/garbage_collected.h",
- "v8_wrapper/gc_task_runner.h",
"v8_wrapper/heap.h",
- "v8_wrapper/heap_allocator.h",
+ "v8_wrapper/heap_allocator_impl.h",
"v8_wrapper/heap_stats_collector.h",
"v8_wrapper/heap_traits.h",
"v8_wrapper/member.h",
"v8_wrapper/persistent.h",
"v8_wrapper/process_heap.h",
+ "v8_wrapper/thread_state.cc",
"v8_wrapper/thread_state.h",
"v8_wrapper/thread_state_scopes.h",
+ "v8_wrapper/trace_traits.h",
"v8_wrapper/unified_heap_controller.h",
"v8_wrapper/unified_heap_marking_visitor.h",
"v8_wrapper/visitor.h",
]
- deps += [ "//v8:cppgc" ]
+ deps += [
+ "//gin:gin",
+
+ # Dependency on V8 which transitively depends on cppgc but exposes
+ # JS-related C++ heap through V8's Isolate.
+ "//v8",
+ ]
} else {
sources += [
"impl/atomic_entry_flag.h",
@@ -116,23 +137,22 @@ blink_platform_sources("heap") {
"impl/blink_gc.h",
"impl/blink_gc_memory_dump_provider.cc",
"impl/blink_gc_memory_dump_provider.h",
- "impl/disallow_new_wrapper.h",
+ "impl/collection_support/heap_hash_table_backing.h",
+ "impl/collection_support/heap_vector_backing.h",
"impl/finalizer_traits.h",
"impl/garbage_collected.h",
"impl/gc_info.cc",
"impl/gc_info.h",
- "impl/gc_task_runner.h",
"impl/heap.cc",
"impl/heap.h",
- "impl/heap_allocator.cc",
- "impl/heap_allocator.h",
+ "impl/heap_allocator_impl.cc",
+ "impl/heap_allocator_impl.h",
"impl/heap_compact.cc",
"impl/heap_compact.h",
"impl/heap_page.cc",
"impl/heap_page.h",
"impl/heap_stats_collector.cc",
"impl/heap_stats_collector.h",
- "impl/heap_traits.h",
"impl/marking_scheduling_oracle.cc",
"impl/marking_scheduling_oracle.h",
"impl/marking_verifier.cc",
@@ -185,10 +205,16 @@ blink_platform_sources("heap") {
source_set("test_support") {
testonly = true
- sources = [
- "heap_test_utilities.cc",
- "heap_test_utilities.h",
- ]
+ sources = [ "heap_test_utilities.h" ]
+
+ if (enable_blink_heap_use_v8_oilpan) {
+ sources += [ "v8_wrapper/heap_test_utilities.h" ]
+ } else {
+ sources += [
+ "impl/heap_test_utilities.cc",
+ "impl/heap_test_utilities.h",
+ ]
+ }
deps = [
":blink_heap_buildflags",
@@ -196,7 +222,13 @@ source_set("test_support") {
"//third_party/blink/public/mojom:mojom_platform_blink_headers",
"//third_party/blink/renderer/platform:bindings_buildflags",
"//third_party/blink/renderer/platform:platform",
+ "//third_party/blink/renderer/platform/wtf:buildflags",
]
+
+ if (enable_blink_heap_use_v8_oilpan) {
+ deps += [ "//v8:v8_for_testing" ]
+ }
+
public_deps = [ "//base/test:test_support" ]
}
@@ -214,32 +246,36 @@ test("blink_heap_unittests") {
source_set("blink_heap_unittests_sources") {
testonly = true
- sources = [
- "../testing/run_all_tests.cc",
- "test/blink_gc_memory_dump_provider_test.cc",
- "test/card_table_test.cc",
- "test/concurrent_marking_test.cc",
- "test/gc_info_test.cc",
- "test/heap_compact_test.cc",
- "test/heap_linked_stack_test.cc",
- "test/heap_stats_collector_test.cc",
- "test/heap_test.cc",
- "test/heap_thread_test.cc",
- "test/heap_traits_test.cc",
- "test/incremental_marking_test.cc",
- "test/marking_scheduling_oracle_test.cc",
- "test/marking_verifier_test.cc",
- "test/name_trait_test.cc",
- "test/object_start_bitmap_test.cc",
- "test/persistent_test.cc",
- "test/thread_state_scheduling_test.cc",
- "test/weakness_marking_test.cc",
- "test/worklist_test.cc",
- "test/write_barrier_perftest.cc",
- ]
- if (enable_blink_heap_young_generation) {
- sources += [ "test/minor_gc_test.cc" ]
+ sources = [ "../testing/run_all_tests.cc" ]
+
+ if (!enable_blink_heap_use_v8_oilpan) {
+ sources += [
+ "test/blink_gc_memory_dump_provider_test.cc",
+ "test/card_table_test.cc",
+ "test/concurrent_marking_test.cc",
+ "test/gc_info_test.cc",
+ "test/heap_compact_test.cc",
+ "test/heap_linked_stack_test.cc",
+ "test/heap_stats_collector_test.cc",
+ "test/heap_test.cc",
+ "test/heap_thread_test.cc",
+ "test/heap_traits_test.cc",
+ "test/incremental_marking_test.cc",
+ "test/marking_scheduling_oracle_test.cc",
+ "test/marking_verifier_test.cc",
+ "test/name_trait_test.cc",
+ "test/object_start_bitmap_test.cc",
+ "test/persistent_test.cc",
+ "test/thread_state_scheduling_test.cc",
+ "test/weakness_marking_test.cc",
+ "test/worklist_test.cc",
+ "test/write_barrier_perftest.cc",
+ ]
+
+ if (enable_blink_heap_young_generation) {
+ sources += [ "test/minor_gc_test.cc" ]
+ }
}
configs += [
diff --git a/chromium/third_party/blink/renderer/platform/heap/DEPS b/chromium/third_party/blink/renderer/platform/heap/DEPS
index 5814f38e1e9..4f4a359ec6f 100644
--- a/chromium/third_party/blink/renderer/platform/heap/DEPS
+++ b/chromium/third_party/blink/renderer/platform/heap/DEPS
@@ -14,6 +14,7 @@ include_rules = [
"+base/task_runner.h",
"+base/task/post_job.h",
"+base/template_util.h",
+ "+gin/public/v8_platform.h",
"+testing/perf/perf_result_reporter.h",
"+third_party/blink/renderer/platform/bindings",
diff --git a/chromium/third_party/blink/renderer/platform/heap/DIR_METADATA b/chromium/third_party/blink/renderer/platform/heap/DIR_METADATA
new file mode 100644
index 00000000000..00600710faf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>MemoryAllocator>GarbageCollection"
+}
+team_email: "oilpan-reviews@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/heap/OWNERS b/chromium/third_party/blink/renderer/platform/heap/OWNERS
index dafb539f11d..132b4d9011e 100644
--- a/chromium/third_party/blink/renderer/platform/heap/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/heap/OWNERS
@@ -3,6 +3,3 @@ haraken@chromium.org
kouhei@chromium.org
mlippautz@chromium.org
omerkatz@chromium.org
-
-# TEAM: oilpan-reviews@chromium.org
-# COMPONENT: Blink>MemoryAllocator>GarbageCollection
diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
index bba521667cf..227089f8002 100644
--- a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
+++ b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/blink_gc.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h b/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
index e3216e12529..3e6f4c2f629 100644
--- a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
+++ b/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_deque.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_deque.h
new file mode 100644
index 00000000000..be2ffec1f46
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_deque.h
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_DEQUE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_DEQUE_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+template <typename T>
+class HeapDeque final : public GarbageCollected<HeapDeque<T>>,
+ public Deque<T, 0, HeapAllocator> {
+ DISALLOW_NEW();
+
+ public:
+ HeapDeque() = default;
+
+ explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) {
+ }
+
+ HeapDeque(wtf_size_t size, const T& val)
+ : Deque<T, 0, HeapAllocator>(size, val) {
+ }
+
+ HeapDeque& operator=(const HeapDeque& other) {
+ HeapDeque<T> copy(other);
+ Deque<T, 0, HeapAllocator>::Swap(copy);
+ return *this;
+ }
+
+ HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {}
+
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ Deque<T, 0, HeapAllocator>::Trace(visitor);
+ }
+
+ private:
+ static constexpr void CheckType() {
+ static_assert(WTF::IsMemberType<T>::value,
+ "HeapDeque supports only Member.");
+ static_assert(std::is_trivially_destructible<HeapDeque>::value,
+ "HeapDeque must be trivially destructible.");
+ static_assert(WTF::IsTraceable<T>::value,
+ "For vectors without traceable elements, use Deque<> instead "
+ "of HeapDeque<>");
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_DEQUE_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h
new file mode 100644
index 00000000000..fa2d44e1e08
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h
@@ -0,0 +1,61 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_COUNTED_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_COUNTED_SET_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
+
+namespace blink {
+
+template <typename Value,
+ typename HashFunctions = typename DefaultHash<Value>::Hash,
+ typename Traits = HashTraits<Value>>
+class HeapHashCountedSet final
+ : public GarbageCollected<HeapHashCountedSet<Value, HashFunctions, Traits>>,
+ public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> {
+ DISALLOW_NEW();
+
+ public:
+ HeapHashCountedSet() = default;
+
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ HashCountedSet<Value, HashFunctions, Traits, HeapAllocator>::Trace(visitor);
+ }
+
+ private:
+ static constexpr void CheckType() {
+ static_assert(WTF::IsMemberOrWeakMemberType<Value>::value,
+ "HeapHashCountedSet supports only Member and WeakMember.");
+ static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
+ "HeapHashCountedSet must be trivially destructible.");
+ static_assert(WTF::IsTraceable<Value>::value,
+ "For counted sets without traceable elements, use "
+ "HashCountedSet<> instead of HeapHashCountedSet<>.");
+ }
+};
+
+} // namespace blink
+
+namespace WTF {
+
+template <typename Value,
+ typename HashFunctions,
+ typename Traits,
+ typename VectorType>
+inline void CopyToVector(
+ const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set,
+ VectorType& vector) {
+ CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits,
+ blink::HeapAllocator>&>(set),
+ vector);
+}
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_COUNTED_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h
new file mode 100644
index 00000000000..740ea72f112
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_
+
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+
+namespace blink {
+
+template <typename KeyArg,
+ typename MappedArg,
+ typename HashArg = typename DefaultHash<KeyArg>::Hash,
+ typename KeyTraitsArg = HashTraits<KeyArg>,
+ typename MappedTraitsArg = HashTraits<MappedArg>>
+class HeapHashMap final : public GarbageCollected<HeapHashMap<KeyArg,
+ MappedArg,
+ HashArg,
+ KeyTraitsArg,
+ MappedTraitsArg>>,
+ public HashMap<KeyArg,
+ MappedArg,
+ HashArg,
+ KeyTraitsArg,
+ MappedTraitsArg,
+ HeapAllocator> {
+ DISALLOW_NEW();
+
+ public:
+ HeapHashMap() = default;
+
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg,
+ HeapAllocator>::Trace(visitor);
+ }
+
+ private:
+ static constexpr void CheckType() {
+ static_assert(std::is_trivially_destructible<HeapHashMap>::value,
+ "HeapHashMap must be trivially destructible.");
+ static_assert(
+ WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
+ "For hash maps without traceable elements, use HashMap<> "
+ "instead of HeapHashMap<>.");
+ static_assert(WTF::IsMemberOrWeakMemberType<KeyArg>::value ||
+ !WTF::IsTraceable<KeyArg>::value,
+ "HeapHashMap supports only Member, WeakMember and "
+ "non-traceable types as keys.");
+ static_assert(WTF::IsMemberOrWeakMemberType<MappedArg>::value ||
+ !WTF::IsTraceable<MappedArg>::value ||
+ WTF::IsSubclassOfTemplate<MappedArg,
+ TraceWrapperV8Reference>::value,
+ "HeapHashMap supports only Member, WeakMember, "
+ "TraceWrapperV8Reference and "
+ "non-traceable types as values.");
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h
new file mode 100644
index 00000000000..47b58a73115
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_SET_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+
+namespace blink {
+
+template <typename ValueArg,
+ typename HashArg = typename DefaultHash<ValueArg>::Hash,
+ typename TraitsArg = HashTraits<ValueArg>>
+class HeapHashSet final
+ : public GarbageCollected<HeapHashSet<ValueArg, HashArg, TraitsArg>>,
+ public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
+ DISALLOW_NEW();
+
+ public:
+ HeapHashSet() = default;
+
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator>::Trace(visitor);
+ }
+
+ private:
+ static constexpr void CheckType() {
+ static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
+ "HeapHashSet supports only Member and WeakMember.");
+ static_assert(std::is_trivially_destructible<HeapHashSet>::value,
+ "HeapHashSet must be trivially destructible.");
+ static_assert(WTF::IsTraceable<ValueArg>::value,
+ "For hash sets without traceable elements, use HashSet<> "
+ "instead of HeapHashSet<>.");
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index 27460c3acca..ec11bf758f6 100644
--- a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -1,282 +1,75 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
-#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
-#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
-#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-namespace blink {
-
-template <typename Table>
-class HeapHashTableBacking final
- : public WTF::ConditionalDestructor<
- HeapHashTableBacking<Table>,
- std::is_trivially_destructible<typename Table::ValueType>::value> {
- DISALLOW_NEW();
- IS_GARBAGE_COLLECTED_TYPE();
-
- public:
- template <typename Backing>
- static void* AllocateObject(size_t size);
-
- void Finalize();
-};
-
-template <typename Table>
-struct ThreadingTrait<HeapHashTableBacking<Table>> {
- STATIC_ONLY(ThreadingTrait);
- using Key = typename Table::KeyType;
- using Value = typename Table::ValueType;
- static const ThreadAffinity kAffinity =
- (ThreadingTrait<Key>::kAffinity == kMainThreadOnly) &&
- (ThreadingTrait<Value>::kAffinity == kMainThreadOnly)
- ? kMainThreadOnly
- : kAnyThread;
-};
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h"
+#else // !USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/collection_support/heap_hash_table_backing.h"
+#endif // !USE_V8_OILPAN
-// static
-template <typename Table>
-template <typename Backing>
-void* HeapHashTableBacking<Table>::AllocateObject(size_t size) {
- ThreadState* state =
- ThreadStateFor<ThreadingTrait<Backing>::kAffinity>::GetState();
- DCHECK(state->IsAllocationAllowed());
- const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(Backing);
- return state->Heap().AllocateOnArenaIndex(
- state, size, BlinkGC::kHashTableArenaIndex, GCInfoTrait<Backing>::Index(),
- type_name);
-}
-
-template <typename Table>
-void HeapHashTableBacking<Table>::Finalize() {
- using Value = typename Table::ValueType;
- static_assert(
- !std::is_trivially_destructible<Value>::value,
- "Finalization of trivially destructible classes should not happen.");
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
- // Use the payload size as recorded by the heap to determine how many
- // elements to finalize.
- size_t length = header->PayloadSize() / sizeof(Value);
- Value* table = reinterpret_cast<Value*>(this);
- for (unsigned i = 0; i < length; ++i) {
- if (!Table::IsEmptyOrDeletedBucket(table[i]))
- table[i].~Value();
- }
-}
+namespace blink {
-template <typename Table>
-struct MakeGarbageCollectedTrait<HeapHashTableBacking<Table>> {
- static HeapHashTableBacking<Table>* Call(size_t num_elements) {
- CHECK_GT(num_elements, 0u);
- void* memory = HeapHashTableBacking<Table>::template AllocateObject<
- HeapHashTableBacking<Table>>(num_elements *
- sizeof(typename Table::ValueType));
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
- // Placement new as regular operator new() is deleted.
- HeapHashTableBacking<Table>* object =
- ::new (memory) HeapHashTableBacking<Table>();
- header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
- return object;
- }
+// Helper for processing ephemerons represented as KeyValuePair. Reorders
+// parameters if needed so that KeyType is always weak.
+template <typename _KeyType,
+ typename _ValueType,
+ typename _KeyTraits,
+ typename _ValueTraits,
+ bool = WTF::IsWeak<_ValueType>::value>
+struct EphemeronKeyValuePair {
+ using KeyType = _KeyType;
+ using ValueType = _ValueType;
+ using KeyTraits = _KeyTraits;
+ using ValueTraits = _ValueTraits;
+
+ // Ephemerons have different weakness for KeyType and ValueType. If weakness
+ // is equal, we either have Strong/Strong, or Weak/Weak, which would indicate
+ // a full strong or fully weak pair.
+ static constexpr bool is_ephemeron =
+ WTF::IsWeak<KeyType>::value != WTF::IsWeak<ValueType>::value;
+
+ static_assert(!WTF::IsWeak<KeyType>::value ||
+ WTF::IsWeakMemberType<KeyType>::value,
+ "Weakness must be encoded using WeakMember.");
+
+ EphemeronKeyValuePair(const KeyType* k, const ValueType* v)
+ : key(k), value(v) {}
+ const KeyType* key;
+ const ValueType* value;
};
-// The trace trait for the heap hashtable backing is used when we find a
-// direct pointer to the backing from the conservative stack scanner. This
-// normally indicates that there is an ongoing iteration over the table, and so
-// we disable weak processing of table entries. When the backing is found
-// through the owning hash table we mark differently, in order to do weak
-// processing.
-template <typename Table>
-struct TraceTrait<HeapHashTableBacking<Table>> {
- STATIC_ONLY(TraceTrait);
- using Backing = HeapHashTableBacking<Table>;
- using ValueType = typename Table::ValueTraits::TraitType;
- using Traits = typename Table::ValueTraits;
-
- public:
- static TraceDescriptor GetTraceDescriptor(const void* self) {
- return {self, Trace<WTF::kNoWeakHandling>};
- }
-
- static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
- return GetWeakTraceDescriptorImpl<ValueType>::GetWeakTraceDescriptor(self);
- }
-
- template <WTF::WeakHandlingFlag WeakHandling = WTF::kNoWeakHandling>
- static void Trace(Visitor* visitor, const void* self) {
- if (!Traits::kCanTraceConcurrently && self) {
- if (visitor->DeferredTraceIfConcurrent({self, &Trace<WeakHandling>},
- GetBackingStoreSize(self)))
- return;
- }
-
- static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
- WTF::IsWeak<ValueType>::value,
- "T should not be traced");
- WTF::TraceInCollectionTrait<WeakHandling, Backing, void>::Trace(visitor,
- self);
- }
-
- private:
- static size_t GetBackingStoreSize(const void* backing_store) {
- const HeapObjectHeader* header =
- HeapObjectHeader::FromPayload(backing_store);
- return header->IsLargeObject<HeapObjectHeader::AccessMode::kAtomic>()
- ? static_cast<LargeObjectPage*>(PageFromObject(header))
- ->ObjectSize()
- : header->size<HeapObjectHeader::AccessMode::kAtomic>();
- }
-
- template <typename ValueType>
- struct GetWeakTraceDescriptorImpl {
- static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
- return {backing, nullptr};
- }
- };
-
- template <typename K, typename V>
- struct GetWeakTraceDescriptorImpl<WTF::KeyValuePair<K, V>> {
- static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
- return GetWeakTraceDescriptorKVPImpl<K, V>::GetWeakTraceDescriptor(
- backing);
- }
-
- template <typename KeyType,
- typename ValueType,
- bool ephemeron_semantics = (WTF::IsWeak<KeyType>::value &&
- !WTF::IsWeak<ValueType>::value &&
- WTF::IsTraceable<ValueType>::value) ||
- (WTF::IsWeak<ValueType>::value &&
- !WTF::IsWeak<KeyType>::value &&
- WTF::IsTraceable<KeyType>::value)>
- struct GetWeakTraceDescriptorKVPImpl {
- static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
- return {backing, nullptr};
- }
- };
-
- template <typename KeyType, typename ValueType>
- struct GetWeakTraceDescriptorKVPImpl<KeyType, ValueType, true> {
- static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
- return {backing, Trace<WTF::kWeakHandling>};
- }
- };
- };
+template <typename _KeyType,
+ typename _ValueType,
+ typename _KeyTraits,
+ typename _ValueTraits>
+struct EphemeronKeyValuePair<_KeyType,
+ _ValueType,
+ _KeyTraits,
+ _ValueTraits,
+ true> : EphemeronKeyValuePair<_ValueType,
+ _KeyType,
+ _ValueTraits,
+ _KeyTraits,
+ false> {
+ EphemeronKeyValuePair(const _KeyType* k, const _ValueType* v)
+ : EphemeronKeyValuePair<_ValueType,
+ _KeyType,
+ _ValueTraits,
+ _KeyTraits,
+ false>(v, k) {}
};
} // namespace blink
namespace WTF {
-namespace internal {
-
-// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking.
-// It is used to provide a snapshot view of the bucket key and guarantee
-// that the same key is used for checking empty/deleted buckets and tracing.
-template <typename T>
-class ConcurrentBucket {
- using KeyExtractionCallback = void (*)(const T&, void*);
-
- public:
- using BucketType = T;
-
- ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) {
- extract_key(t, &buf_);
- }
-
- // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key
- // and the value are the same.
- const T* key() const { return reinterpret_cast<const T*>(&buf_); }
- const T* value() const { return key(); }
- const T* bucket() const { return key(); }
-
- private:
- // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
- // can be accessed the same as objects of type T
- static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t));
- alignas(boundary) char buf_[sizeof(T)];
-};
-
-template <typename Key, typename Value>
-class ConcurrentBucket<KeyValuePair<Key, Value>> {
- using KeyExtractionCallback = void (*)(const KeyValuePair<Key, Value>&,
- void*);
-
- public:
- using BucketType = ConcurrentBucket;
-
- ConcurrentBucket(const KeyValuePair<Key, Value>& pair,
- KeyExtractionCallback extract_key)
- : value_(&pair.value) {
- extract_key(pair, &buf_);
- }
-
- const Key* key() const { return reinterpret_cast<const Key*>(&buf_); }
- const Value* value() const { return value_; }
- const ConcurrentBucket* bucket() const { return this; }
-
- private:
- // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
- // can be accessed the same as objects of type Key
- static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t));
- alignas(boundary) char buf_[sizeof(Key)];
- const Value* value_;
-};
-
-} // namespace internal
-
-// This trace method is for tracing a HashTableBacking either through regular
-// tracing (via the relevant TraceTraits) or when finding a HashTableBacking
-// through conservative stack scanning (which will treat all references in the
-// backing strongly).
-template <WTF::WeakHandlingFlag WeakHandling, typename Table>
-struct TraceHashTableBackingInCollectionTrait {
- using Value = typename Table::ValueType;
- using Traits = typename Table::ValueTraits;
- using Extractor = typename Table::ExtractorType;
-
- static void Trace(blink::Visitor* visitor, const void* self) {
- static_assert(IsTraceableInCollectionTrait<Traits>::value ||
- WTF::IsWeak<Value>::value,
- "Table should not be traced");
- const Value* array = reinterpret_cast<const Value*>(self);
- blink::HeapObjectHeader* header =
- blink::HeapObjectHeader::FromPayload(self);
- // Use the payload size as recorded by the heap to determine how many
- // elements to trace.
- size_t length = header->PayloadSize() / sizeof(Value);
- const bool is_concurrent = visitor->IsConcurrent();
- for (size_t i = 0; i < length; ++i) {
- // If tracing concurrently, use a concurrent-safe version of
- // IsEmptyOrDeletedBucket (check performed on a local copy instead
- // of directly on the bucket).
- if (is_concurrent) {
- internal::ConcurrentBucket<Value> concurrent_bucket(
- array[i], Extractor::ExtractSafe);
- if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
- IsEmptyOrDeletedBucketForKey(*concurrent_bucket.key())) {
- blink::TraceCollectionIfEnabled<
- WeakHandling,
- typename internal::ConcurrentBucket<Value>::BucketType,
- Traits>::Trace(visitor, concurrent_bucket.bucket());
- }
- } else {
- if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
- IsEmptyOrDeletedBucket(array[i])) {
- blink::TraceCollectionIfEnabled<WeakHandling, Value, Traits>::Trace(
- visitor, &array[i]);
- }
- }
- }
- }
-};
-
template <typename Table>
struct TraceInCollectionTrait<kNoWeakHandling,
blink::HeapHashTableBacking<Table>,
@@ -432,6 +225,9 @@ struct TraceInCollectionTrait<
}
};
+template <typename T>
+struct IsWeak<internal::ConcurrentBucket<T>> : IsWeak<T> {};
+
} // namespace WTF
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h
new file mode 100644
index 00000000000..12a46002071
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
+class HeapLinkedHashSet final
+ : public GarbageCollected<HeapLinkedHashSet<ValueArg, TraitsArg>>,
+ public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
+ static void CheckType() {
+ static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
+ "HeapLinkedHashSet supports only Member and WeakMember.");
+ // If not trivially destructible, we have to add a destructor which will
+ // hinder performance.
+ static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
+ "HeapLinkedHashSet must be trivially destructible.");
+ static_assert(WTF::IsTraceable<ValueArg>::value,
+ "For sets without traceable elements, use LinkedHashSet<> "
+ "instead of HeapLinkedHashSet<>.");
+ }
+
+ public:
+ HeapLinkedHashSet() = default;
+
+ void Trace(Visitor* v) const {
+ CheckType();
+ LinkedHashSet<ValueArg, TraitsArg, HeapAllocator>::Trace(v);
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
index 407d705b379..e56c90ef01f 100644
--- a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
@@ -32,9 +32,10 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_STACK_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/heap/heap_allocator_impl.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
namespace blink {
@@ -47,12 +48,7 @@ namespace blink {
template <typename T>
class HeapLinkedStack final : public GarbageCollected<HeapLinkedStack<T>> {
public:
- static void CheckType() {
- static_assert(internal::IsMember<T>,
- "HeapLinkedStack supports only Member.");
- }
-
- HeapLinkedStack() { CheckType(); }
+ HeapLinkedStack() = default;
inline size_t size() const;
inline bool IsEmpty() const;
@@ -61,7 +57,10 @@ class HeapLinkedStack final : public GarbageCollected<HeapLinkedStack<T>> {
inline const T& Peek() const;
inline void Pop();
- void Trace(Visitor* visitor) const { visitor->Trace(head_); }
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ visitor->Trace(head_);
+ }
private:
class Node final : public GarbageCollected<Node> {
@@ -77,6 +76,11 @@ class HeapLinkedStack final : public GarbageCollected<HeapLinkedStack<T>> {
Member<Node> next_;
};
+ static void CheckType() {
+ static_assert(WTF::IsMemberType<T>::value,
+ "HeapLinkedStack supports only Member.");
+ }
+
Member<Node> head_;
size_t size_ = 0;
};
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_list_hash_set.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_list_hash_set.h
new file mode 100644
index 00000000000..ad7914319c7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_list_hash_set.h
@@ -0,0 +1,125 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LIST_HASH_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LIST_HASH_SET_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+class HeapListHashSetAllocator;
+template <typename ValueArg>
+class HeapListHashSetNode;
+
+template <typename ValueArg>
+class HeapListHashSetNode final
+ : public GarbageCollected<HeapListHashSetNode<ValueArg>> {
+ public:
+ using NodeAllocator = HeapListHashSetAllocator;
+ using PointerType = Member<HeapListHashSetNode>;
+ using Value = ValueArg;
+
+ template <typename U>
+ static HeapListHashSetNode* Create(NodeAllocator* allocator, U&& value) {
+ return MakeGarbageCollected<HeapListHashSetNode>(std::forward<U>(value));
+ }
+
+ template <typename U>
+ explicit HeapListHashSetNode(U&& value) noexcept
+ : value_(std::forward<U>(value)) {
+ static_assert(std::is_trivially_destructible<Value>::value,
+ "Garbage collected types used in ListHashSet must be "
+ "trivially destructible");
+ }
+
+ HeapListHashSetNode() = delete;
+ HeapListHashSetNode(const HeapListHashSetNode&) = delete;
+ HeapListHashSetNode& operator=(const HeapListHashSetNode&) = delete;
+
+ void Destroy(NodeAllocator* allocator) {}
+
+ HeapListHashSetNode* Next() const { return next_; }
+ HeapListHashSetNode* Prev() const { return prev_; }
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(prev_);
+ visitor->Trace(next_);
+ visitor->Trace(value_);
+ }
+
+ ValueArg value_;
+ PointerType prev_ = nullptr;
+ PointerType next_ = nullptr;
+};
+
+// Empty allocator as HeapListHashSetNode directly allocates using
+// MakeGarbageCollected().
+class HeapListHashSetAllocator final {
+ DISALLOW_NEW();
+
+ public:
+ using TableAllocator = HeapAllocator;
+
+ static constexpr bool kIsGarbageCollected = true;
+
+ struct AllocatorProvider final {
+ void CreateAllocatorIfNeeded() {}
+ HeapListHashSetAllocator* Get() { return nullptr; }
+ void Swap(AllocatorProvider& other) {}
+ };
+};
+
+template <typename ValueArg,
+ wtf_size_t inlineCapacity = 0, // The inlineCapacity is just a dummy
+ // to match ListHashSet (off-heap).
+ typename HashArg = typename DefaultHash<ValueArg>::Hash>
+class HeapListHashSet final
+ : public GarbageCollected<
+ HeapListHashSet<ValueArg, inlineCapacity, HashArg>>,
+ public ListHashSet<ValueArg,
+ inlineCapacity,
+ HashArg,
+ HeapListHashSetAllocator> {
+ public:
+ HeapListHashSet() = default;
+
+ void Trace(Visitor* v) const {
+ CheckType();
+ ListHashSet<ValueArg, inlineCapacity, HashArg,
+ HeapListHashSetAllocator>::Trace(v);
+ }
+
+ private:
+ static void CheckType() {
+ static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
+ "HeapListHashSet supports only Member and WeakMember.");
+ static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
+ "HeapListHashSet must be trivially destructible.");
+ static_assert(WTF::IsTraceable<ValueArg>::value,
+ "For sets without traceable elements, use ListHashSet<> "
+ "instead of HeapListHashSet<>.");
+ }
+};
+
+} // namespace blink
+
+namespace WTF {
+
+template <typename Value, wtf_size_t inlineCapacity>
+struct ListHashSetTraits<Value, inlineCapacity, blink::HeapListHashSetAllocator>
+ : public HashTraits<blink::Member<blink::HeapListHashSetNode<Value>>> {
+ using Allocator = blink::HeapListHashSetAllocator;
+ using Node = blink::HeapListHashSetNode<Value>;
+
+ static constexpr bool kCanTraceConcurrently =
+ HashTraits<Value>::kCanTraceConcurrently;
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LIST_HASH_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector.h
new file mode 100644
index 00000000000..cf34160771f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector.h
@@ -0,0 +1,148 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+template <typename T, wtf_size_t inlineCapacity = 0>
+class HeapVector final : public GarbageCollected<HeapVector<T, inlineCapacity>>,
+ public Vector<T, inlineCapacity, HeapAllocator> {
+ DISALLOW_NEW();
+
+ public:
+ HeapVector() = default;
+
+ explicit HeapVector(wtf_size_t size)
+ : Vector<T, inlineCapacity, HeapAllocator>(size) {}
+
+ HeapVector(wtf_size_t size, const T& val)
+ : Vector<T, inlineCapacity, HeapAllocator>(size, val) {}
+
+ template <wtf_size_t otherCapacity>
+ HeapVector(const HeapVector<T, otherCapacity>& other) // NOLINT
+ : Vector<T, inlineCapacity, HeapAllocator>(other) {}
+
+ HeapVector(const HeapVector& other)
+ : Vector<T, inlineCapacity, HeapAllocator>(other) {}
+
+ HeapVector& operator=(const HeapVector& other) {
+ Vector<T, inlineCapacity, HeapAllocator>::operator=(other);
+ return *this;
+ }
+
+ HeapVector(HeapVector&& other) noexcept
+ : Vector<T, inlineCapacity, HeapAllocator>(std::move(other)) {}
+
+ HeapVector& operator=(HeapVector&& other) noexcept {
+ Vector<T, inlineCapacity, HeapAllocator>::operator=(std::move(other));
+ return *this;
+ }
+
+ HeapVector(std::initializer_list<T> elements)
+ : Vector<T, inlineCapacity, HeapAllocator>(elements) {}
+
+ void Trace(Visitor* visitor) const {
+ CheckType();
+ Vector<T, inlineCapacity, HeapAllocator>::Trace(visitor);
+ }
+
+ private:
+ static constexpr void CheckType() {
+ static_assert(
+ std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
+ "HeapVector must be trivially destructible.");
+ static_assert(WTF::IsTraceable<T>::value,
+ "For vectors without traceable elements, use Vector<> "
+ "instead of HeapVector<>.");
+ static_assert(!WTF::IsWeak<T>::value,
+ "Weak types are not allowed in HeapVector.");
+ static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value,
+ "Type must be traceable in collection");
+ }
+};
+
+} // namespace blink
+
+namespace WTF {
+
+template <typename T>
+struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = false;
+ static const bool kCanInitializeWithMemset = true;
+ static const bool kCanClearUnusedSlotsWithMemset = true;
+ static const bool kCanCopyWithMemcpy = true;
+ static const bool kCanMoveWithMemcpy = true;
+
+ static constexpr bool kCanTraceConcurrently = true;
+};
+
+// These traits are used in VectorBackedLinkedList to support WeakMember in
+// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned.
+// (See the discussion in https://crrev.com/c/2246014)
+template <typename T>
+struct VectorTraits<blink::WeakMember<T>>
+ : VectorTraitsBase<blink::WeakMember<T>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = false;
+ static const bool kCanInitializeWithMemset = true;
+ static const bool kCanClearUnusedSlotsWithMemset = true;
+ static const bool kCanCopyWithMemcpy = true;
+ static const bool kCanMoveWithMemcpy = true;
+
+ static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::UntracedMember<T>>
+ : VectorTraitsBase<blink::UntracedMember<T>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = false;
+ static const bool kCanInitializeWithMemset = true;
+ static const bool kCanClearUnusedSlotsWithMemset = true;
+ static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::HeapVector<T, 0>>
+ : VectorTraitsBase<blink::HeapVector<T, 0>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = false;
+ static const bool kCanInitializeWithMemset = true;
+ static const bool kCanClearUnusedSlotsWithMemset = true;
+ static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::HeapDeque<T>>
+ : VectorTraitsBase<blink::HeapDeque<T>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = false;
+ static const bool kCanInitializeWithMemset = true;
+ static const bool kCanClearUnusedSlotsWithMemset = true;
+ static const bool kCanMoveWithMemcpy = true;
+};
+
+template <typename T, wtf_size_t inlineCapacity>
+struct VectorTraits<blink::HeapVector<T, inlineCapacity>>
+ : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> {
+ STATIC_ONLY(VectorTraits);
+ static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction;
+ static const bool kCanInitializeWithMemset =
+ VectorTraits<T>::kCanInitializeWithMemset;
+ static const bool kCanClearUnusedSlotsWithMemset =
+ VectorTraits<T>::kCanClearUnusedSlotsWithMemset;
+ static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy;
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
index 12b72b78ee9..0a29da548e4 100644
--- a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
+++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
@@ -1,209 +1,16 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
-#include "base/check_op.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/heap/impl/finalizer_traits.h"
-#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
-#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
-#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-namespace blink {
-
-template <typename T, typename Traits = WTF::VectorTraits<T>>
-class HeapVectorBacking final
- : public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
- !Traits::kNeedsDestruction> {
- DISALLOW_NEW();
- IS_GARBAGE_COLLECTED_TYPE();
-
- public:
- template <typename Backing>
- static void* AllocateObject(size_t size) {
- ThreadState* state =
- ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
- DCHECK(state->IsAllocationAllowed());
- const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(Backing);
- return state->Heap().AllocateOnArenaIndex(
- state, size, BlinkGC::kVectorArenaIndex, GCInfoTrait<Backing>::Index(),
- type_name);
- }
-
- // Conditionally invoked via destructor.
- void Finalize();
-};
-
-template <typename T, typename Traits>
-void HeapVectorBacking<T, Traits>::Finalize() {
- static_assert(Traits::kNeedsDestruction,
- "Only vector buffers with items requiring destruction should "
- "be finalized");
- static_assert(
- Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic<T>::value,
- "HeapVectorBacking doesn't support objects that cannot be cleared as "
- "unused with memset or don't have a vtable");
-
- static_assert(
- !std::is_trivially_destructible<T>::value,
- "Finalization of trivially destructible classes should not happen.");
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
- // Use the payload size as recorded by the heap to determine how many
- // elements to finalize.
- size_t length = header->PayloadSize() / sizeof(T);
- Address payload = header->Payload();
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
- ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
-#endif
- // As commented above, HeapVectorBacking calls finalizers for unused slots
- // (which are already zeroed out).
- if (std::is_polymorphic<T>::value) {
- for (unsigned i = 0; i < length; ++i) {
- Address element = payload + i * sizeof(T);
- if (blink::VTableInitialized(element))
- reinterpret_cast<T*>(element)->~T();
- }
- } else {
- T* buffer = reinterpret_cast<T*>(payload);
- for (unsigned i = 0; i < length; ++i)
- buffer[i].~T();
- }
-}
-
-template <typename T>
-struct MakeGarbageCollectedTrait<HeapVectorBacking<T>> {
- static HeapVectorBacking<T>* Call(size_t num_elements) {
- CHECK_GT(num_elements, 0u);
- void* memory =
- HeapVectorBacking<T>::template AllocateObject<HeapVectorBacking<T>>(
- num_elements * sizeof(T));
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
- // Placement new as regular operator new() is deleted.
- HeapVectorBacking<T>* object = ::new (memory) HeapVectorBacking<T>();
- header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
- return object;
- }
-};
-
-template <typename T, typename Traits>
-struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
- STATIC_ONLY(ThreadingTrait);
- static const ThreadAffinity kAffinity = ThreadingTrait<T>::Affinity;
-};
-
-template <typename T, typename Traits>
-struct TraceTrait<HeapVectorBacking<T, Traits>> {
- STATIC_ONLY(TraceTrait);
- using Backing = HeapVectorBacking<T, Traits>;
-
- public:
- static TraceDescriptor GetTraceDescriptor(const void* self) {
- return {self, TraceTrait<Backing>::Trace};
- }
-
- static void Trace(Visitor* visitor, const void* self) {
- if (!Traits::kCanTraceConcurrently && self) {
- if (visitor->DeferredTraceIfConcurrent({self, &Trace},
- GetBackingStoreSize(self)))
- return;
- }
-
- static_assert(!WTF::IsWeak<T>::value,
- "Weakness is not supported in HeapVector and HeapDeque");
- if (WTF::IsTraceableInCollectionTrait<Traits>::value) {
- WTF::TraceInCollectionTrait<WTF::kNoWeakHandling,
- HeapVectorBacking<T, Traits>,
- void>::Trace(visitor, self);
- }
- }
-
- private:
- static size_t GetBackingStoreSize(const void* backing_store) {
- const HeapObjectHeader* header =
- HeapObjectHeader::FromPayload(backing_store);
- return header->IsLargeObject<HeapObjectHeader::AccessMode::kAtomic>()
- ? static_cast<LargeObjectPage*>(PageFromObject(header))
- ->ObjectSize()
- : header->size<HeapObjectHeader::AccessMode::kAtomic>();
- }
-};
-
-} // namespace blink
-
-namespace WTF {
-
-// This trace method is used only for on-stack HeapVectors found in
-// conservative scanning. On-heap HeapVectors are traced by Vector::trace.
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kNoWeakHandling,
- blink::HeapVectorBacking<T, Traits>,
- void> {
- static void Trace(blink::Visitor* visitor, const void* self) {
- // HeapVectorBacking does not know the exact size of the vector
- // and just knows the capacity of the vector. Due to the constraint,
- // HeapVectorBacking can support only the following objects:
- //
- // - An object that has a vtable. In this case, HeapVectorBacking
- // traces only slots that are not zeroed out. This is because if
- // the object has a vtable, the zeroed slot means that it is
- // an unused slot (Remember that the unused slots are guaranteed
- // to be zeroed out by VectorUnusedSlotClearer).
- //
- // - An object that can be initialized with memset. In this case,
- // HeapVectorBacking traces all slots including unused slots.
- // This is fine because the fact that the object can be initialized
- // with memset indicates that it is safe to treat the zerod slot
- // as a valid object.
- static_assert(!IsTraceableInCollectionTrait<Traits>::value ||
- Traits::kCanClearUnusedSlotsWithMemset ||
- std::is_polymorphic<T>::value,
- "HeapVectorBacking doesn't support objects that cannot be "
- "cleared as unused with memset.");
-
- // This trace method is instantiated for vectors where
- // IsTraceableInCollectionTrait<Traits>::value is false, but the trace
- // method should not be called. Thus we cannot static-assert
- // IsTraceableInCollectionTrait<Traits>::value but should runtime-assert it.
- DCHECK(IsTraceableInCollectionTrait<Traits>::value);
-
- const T* array = reinterpret_cast<const T*>(self);
- blink::HeapObjectHeader* header =
- blink::HeapObjectHeader::FromPayload(self);
- // Use the payload size as recorded by the heap to determine how many
- // elements to trace.
- size_t length = header->PayloadSize() / sizeof(T);
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
- // As commented above, HeapVectorBacking can trace unused slots
- // (which are already zeroed out).
- ANNOTATE_CHANGE_SIZE(array, length, 0, length);
-#endif
- if (std::is_polymorphic<T>::value) {
- const char* pointer = reinterpret_cast<const char*>(array);
- for (unsigned i = 0; i < length; ++i) {
- const char* element = pointer + i * sizeof(T);
- if (blink::VTableInitialized(element)) {
- blink::TraceIfNeeded<
- T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
- array[i]);
- }
- }
- } else {
- for (size_t i = 0; i < length; ++i) {
- blink::TraceIfNeeded<
- T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
- array[i]);
- }
- }
- }
-};
-
-} // namespace WTF
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h"
+#else // !USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/collection_support/heap_vector_backing.h"
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/custom_spaces.h b/chromium/third_party/blink/renderer/platform/heap/custom_spaces.h
new file mode 100644
index 00000000000..0ce834e382e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/custom_spaces.h
@@ -0,0 +1,14 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
+
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+#endif // USE_V8_OILPAN
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
index 9d60caf37f6..52a3c6ba141 100644
--- a/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
+++ b/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h
@@ -1,16 +1,62 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
-#include "third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+namespace blink {
+
+// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class.
+template <typename T>
+class DisallowNewWrapper final
+ : public GarbageCollected<DisallowNewWrapper<T>> {
+ public:
+ explicit DisallowNewWrapper(const T& value) : value_(value) {
+ static_assert(WTF::IsDisallowNew<T>::value,
+ "T needs to be a disallow new type");
+ static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
+ }
+ explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) {
+ static_assert(WTF::IsDisallowNew<T>::value,
+ "T needs to be a disallow new type");
+ static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
+ }
+
+ template <typename... Args>
+ explicit DisallowNewWrapper(Args&&... args)
+ : value_(std::forward<Args>(args)...) {
+ static_assert(WTF::IsDisallowNew<T>::value,
+ "T needs to be a disallow new type");
+ static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
+ }
+
+ const T& Value() const { return value_; }
+ T& Value() { return value_; }
+ T&& TakeValue() { return std::move(value_); }
+
+ void Trace(Visitor* visitor) const { visitor->Trace(value_); }
+
+ private:
+ T value_;
+};
+
+// Wraps a disallow new type in a GarbageCollected class, making it possible to
+// be referenced off heap from a Persistent.
+template <typename T>
+DisallowNewWrapper<T>* WrapDisallowNew(const T& value) {
+ return MakeGarbageCollected<DisallowNewWrapper<T>>(value);
+}
+
+template <typename T>
+DisallowNewWrapper<T>* WrapDisallowNew(T&& value) {
+ return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value));
+}
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
index 93715933385..0226743dee5 100644
--- a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
+++ b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/garbage_collected.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h
index 758506b7e07..cc296a7ce26 100644
--- a/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h
+++ b/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h
@@ -1,16 +1,79 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2014 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_PLATFORM_HEAP_GC_TASK_RUNNER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include <memory>
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
-#include "third_party/blink/renderer/platform/heap/impl/gc_task_runner.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+namespace blink {
+
+class GCTaskObserver final : public Thread::TaskObserver {
+ USING_FAST_MALLOC(GCTaskObserver);
+
+ public:
+ GCTaskObserver() = default;
+ ~GCTaskObserver() final = default;
+
+ void WillProcessTask(const base::PendingTask&, bool) final { nesting_++; }
+
+ void DidProcessTask(const base::PendingTask&) final {
+ CHECK(nesting_);
+ nesting_--;
+ ThreadState::Current()->SafePoint(nesting_
+ ? BlinkGC::kHeapPointersOnStack
+ : BlinkGC::kNoHeapPointersOnStack);
+ }
+
+ private:
+ int nesting_;
+};
+
+class GCTaskRunner final {
+ USING_FAST_MALLOC(GCTaskRunner);
+
+ public:
+ explicit GCTaskRunner(Thread* thread)
+ : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) {
+ thread_->AddTaskObserver(gc_task_observer_.get());
+ }
+
+ ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); }
+
+ private:
+ std::unique_ptr<GCTaskObserver> gc_task_observer_;
+ Thread* thread_;
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/handle.h b/chromium/third_party/blink/renderer/platform/heap/handle.h
index ee07268f578..5f745e766c8 100644
--- a/chromium/third_party/blink/renderer/platform/heap/handle.h
+++ b/chromium/third_party/blink/renderer/platform/heap/handle.h
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/heap_traits.h"
#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap.h b/chromium/third_party/blink/renderer/platform/heap/heap.h
index 7cbe94f71ec..530b1f792e6 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/heap.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
index c90f1fc3535..90fbb023008 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -5,12 +5,15 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
-#include "third_party/blink/renderer/platform/heap/impl/heap_allocator.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+// Legacy: Users including `heap_allocator.h` actually expect it to pull in the
+// containers.
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_list_hash_set.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_allocator_impl.h b/chromium/third_party/blink/renderer/platform/heap/heap_allocator_impl.h
new file mode 100644
index 00000000000..e05ca5d0e31
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_allocator_impl.h
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
+
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h"
+#else // !USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h"
+#endif // !USE_V8_OILPAN
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h
index 1a6a45c023d..0939d5ef4a6 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
index f9214bbf8ed..3c5be39331d 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h
@@ -1,208 +1,16 @@
-/*
- * Copyright 2017 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
-#include "base/callback.h"
-#include "base/test/task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-namespace blink {
-
-class TestSupportingGC : public testing::Test {
- public:
- // Performs a precise garbage collection with eager sweeping.
- static void PreciselyCollectGarbage(
- BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
-
- // Performs a conservative garbage collection.
- static void ConservativelyCollectGarbage(
- BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
-
- ~TestSupportingGC() override;
-
- // Performs multiple rounds of garbage collections until no more memory can be
- // freed. This is useful to avoid other garbage collections having to deal
- // with stale memory.
- void ClearOutOldGarbage();
-
- // Completes sweeping if it is currently running.
- void CompleteSweepingIfNeeded();
-
- protected:
- base::test::TaskEnvironment task_environment_;
-};
-
-template <typename T>
-class ObjectWithCallbackBeforeInitializer
- : public GarbageCollected<ObjectWithCallbackBeforeInitializer<T>> {
- public:
- ObjectWithCallbackBeforeInitializer(
- base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb,
- T* value)
- : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
-
- ObjectWithCallbackBeforeInitializer(
- base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb)
- : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
-
- virtual void Trace(Visitor* visitor) const { visitor->Trace(value_); }
-
- T* value() const { return value_.Get(); }
-
- private:
- static bool ExecuteCallbackReturnTrue(
- ObjectWithCallbackBeforeInitializer* thiz,
- base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb) {
- std::move(cb).Run(thiz);
- return true;
- }
-
- bool bool_;
- Member<T> value_;
-};
-
-template <typename T>
-class MixinWithCallbackBeforeInitializer : public GarbageCollectedMixin {
- public:
- MixinWithCallbackBeforeInitializer(
- base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb,
- T* value)
- : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
-
- MixinWithCallbackBeforeInitializer(
- base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb)
- : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
-
- void Trace(Visitor* visitor) const override { visitor->Trace(value_); }
-
- T* value() const { return value_.Get(); }
-
- private:
- static bool ExecuteCallbackReturnTrue(
- MixinWithCallbackBeforeInitializer* thiz,
- base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb) {
- std::move(cb).Run(thiz);
- return true;
- }
-
- bool bool_;
- Member<T> value_;
-};
-
-class BoolMixin {
- protected:
- bool bool_ = false;
-};
-
-template <typename T>
-class ObjectWithMixinWithCallbackBeforeInitializer
- : public GarbageCollected<ObjectWithMixinWithCallbackBeforeInitializer<T>>,
- public BoolMixin,
- public MixinWithCallbackBeforeInitializer<T> {
- public:
- using Mixin = MixinWithCallbackBeforeInitializer<T>;
-
- ObjectWithMixinWithCallbackBeforeInitializer(
- base::OnceCallback<void(Mixin*)>&& cb,
- T* value)
- : Mixin(std::move(cb), value) {}
-
- ObjectWithMixinWithCallbackBeforeInitializer(
- base::OnceCallback<void(Mixin*)>&& cb)
- : Mixin(std::move(cb)) {}
-
- void Trace(Visitor* visitor) const override { Mixin::Trace(visitor); }
-};
-
-// Simple linked object to be used in tests.
-class LinkedObject : public GarbageCollected<LinkedObject> {
- public:
- LinkedObject() = default;
- explicit LinkedObject(LinkedObject* next) : next_(next) {}
-
- void set_next(LinkedObject* next) { next_ = next; }
- LinkedObject* next() const { return next_; }
- Member<LinkedObject>& next_ref() { return next_; }
-
- virtual void Trace(Visitor* visitor) const { visitor->Trace(next_); }
-
- private:
- Member<LinkedObject> next_;
-};
-
-// Test driver for incremental marking. Assumes that no stack handling is
-// required.
-class IncrementalMarkingTestDriver {
- public:
- explicit IncrementalMarkingTestDriver(ThreadState* thread_state)
- : thread_state_(thread_state) {}
- ~IncrementalMarkingTestDriver();
-
- void Start();
- bool SingleStep(BlinkGC::StackState stack_state =
- BlinkGC::StackState::kNoHeapPointersOnStack);
- void FinishSteps(BlinkGC::StackState stack_state =
- BlinkGC::StackState::kNoHeapPointersOnStack);
- void FinishGC(bool complete_sweep = true);
-
- // Methods for forcing a concurrent marking step without any assistance from
- // mutator thread (i.e. without incremental marking on the mutator thread).
- bool SingleConcurrentStep(BlinkGC::StackState stack_state =
- BlinkGC::StackState::kNoHeapPointersOnStack);
- void FinishConcurrentSteps(BlinkGC::StackState stack_state =
- BlinkGC::StackState::kNoHeapPointersOnStack);
-
- size_t GetHeapCompactLastFixupCount() const;
-
- private:
- ThreadState* const thread_state_;
-};
-
-class IntegerObject : public GarbageCollected<IntegerObject> {
- public:
- static std::atomic_int destructor_calls;
-
- explicit IntegerObject(int x) : x_(x) {}
-
- virtual ~IntegerObject() {
- destructor_calls.fetch_add(1, std::memory_order_relaxed);
- }
-
- virtual void Trace(Visitor* visitor) const {}
-
- int Value() const { return x_; }
-
- bool operator==(const IntegerObject& other) const {
- return other.Value() == Value();
- }
-
- unsigned GetHash() { return IntHash<int>::GetHash(x_); }
-
- private:
- int x_;
-};
-
-struct IntegerObjectHash {
- static unsigned GetHash(const IntegerObject& key) {
- return WTF::HashInt(static_cast<uint32_t>(key.Value()));
- }
-
- static bool Equal(const IntegerObject& a, const IntegerObject& b) {
- return a == b;
- }
-};
-
-} // namespace blink
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h"
+#else // !USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/heap_test_utilities.h"
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_traits.h b/chromium/third_party/blink/renderer/platform/heap/heap_traits.h
index 43245200945..f72489def15 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_traits.h
+++ b/chromium/third_party/blink/renderer/platform/heap/heap_traits.h
@@ -1,16 +1,40 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include <type_traits>
+#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/type_traits.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
-#include "third_party/blink/renderer/platform/heap/impl/heap_traits.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+namespace blink {
+
+// Given a type T, returns a type that is either Member<T> or just T depending
+// on whether T is a garbage-collected type.
+template <typename T>
+using AddMemberIfNeeded =
+ std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>;
+
+// Given a type T, returns a type that is either HeapVector<T>,
+// HeapVector<Member<T>> or Vector<T> depending on T.
+template <typename T>
+using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value,
+ HeapVector<AddMemberIfNeeded<T>>,
+ Vector<T>>;
+
+// Given types T and U, returns a type that is one of the following:
+// - HeapVector<std::pair<V, X>>
+// (where V is either T or Member<T> and X is either U or Member<U>)
+// - Vector<std::pair<T, U>>
+template <typename T, typename U>
+using VectorOfPairs = std::conditional_t<
+ WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value,
+ HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>,
+ Vector<std::pair<T, U>>>;
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_hash_table_backing.h b/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_hash_table_backing.h
new file mode 100644
index 00000000000..1e81ebcd9b1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_hash_table_backing.h
@@ -0,0 +1,283 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
+
+#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+
+namespace blink {
+
+template <typename Table>
+class HeapHashTableBacking final
+ : public GarbageCollected<HeapHashTableBacking<Table>>,
+ public WTF::ConditionalDestructor<
+ HeapHashTableBacking<Table>,
+ std::is_trivially_destructible<typename Table::ValueType>::value> {
+ public:
+ template <typename Backing>
+ static void* AllocateObject(size_t);
+
+ // Conditionally invoked via destructor.
+ void Finalize();
+};
+
+template <typename Table>
+struct ThreadingTrait<HeapHashTableBacking<Table>> {
+ STATIC_ONLY(ThreadingTrait);
+ using Key = typename Table::KeyType;
+ using Value = typename Table::ValueType;
+ static const ThreadAffinity kAffinity =
+ (ThreadingTrait<Key>::kAffinity == kMainThreadOnly) &&
+ (ThreadingTrait<Value>::kAffinity == kMainThreadOnly)
+ ? kMainThreadOnly
+ : kAnyThread;
+};
+
+// static
+template <typename Table>
+template <typename Backing>
+void* HeapHashTableBacking<Table>::AllocateObject(size_t size) {
+ ThreadState* state =
+ ThreadStateFor<ThreadingTrait<Backing>::kAffinity>::GetState();
+ DCHECK(state->IsAllocationAllowed());
+ return state->Heap().AllocateOnArenaIndex(
+ state, size, BlinkGC::kHashTableArenaIndex, GCInfoTrait<Backing>::Index(),
+ WTF_HEAP_PROFILER_TYPE_NAME(Backing));
+}
+
+template <typename Table>
+void HeapHashTableBacking<Table>::Finalize() {
+ using Value = typename Table::ValueType;
+ static_assert(
+ !std::is_trivially_destructible<Value>::value,
+ "Finalization of trivially destructible classes should not happen.");
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
+ // Use the payload size as recorded by the heap to determine how many
+ // elements to finalize.
+ size_t length = header->PayloadSize() / sizeof(Value);
+ Value* table = reinterpret_cast<Value*>(this);
+ for (unsigned i = 0; i < length; ++i) {
+ if (!Table::IsEmptyOrDeletedBucket(table[i]))
+ table[i].~Value();
+ }
+}
+
+template <typename Table>
+struct MakeGarbageCollectedTrait<HeapHashTableBacking<Table>> {
+ static HeapHashTableBacking<Table>* Call(size_t num_elements) {
+ static_assert(!std::is_polymorphic<HeapHashTableBacking<Table>>::value,
+ "HeapHashTableBacking must not be polymorphic as it is "
+ "converted to a raw array of buckets for certain operation");
+ CHECK_GT(num_elements, 0u);
+ void* memory = HeapHashTableBacking<Table>::template AllocateObject<
+ HeapHashTableBacking<Table>>(num_elements *
+ sizeof(typename Table::ValueType));
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
+ // Placement new as regular operator new() is deleted.
+ HeapHashTableBacking<Table>* object =
+ ::new (memory) HeapHashTableBacking<Table>();
+ header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
+ return object;
+ }
+};
+
+// The trace trait for the heap hashtable backing is used when we find a
+// direct pointer to the backing from the conservative stack scanner. This
+// normally indicates that there is an ongoing iteration over the table, and so
+// we disable weak processing of table entries. When the backing is found
+// through the owning hash table we mark differently, in order to do weak
+// processing.
+template <typename Table>
+struct TraceTrait<HeapHashTableBacking<Table>> {
+ STATIC_ONLY(TraceTrait);
+ using Backing = HeapHashTableBacking<Table>;
+ using ValueType = typename Table::ValueTraits::TraitType;
+ using Traits = typename Table::ValueTraits;
+
+ public:
+ static TraceDescriptor GetTraceDescriptor(const void* self) {
+ return {self, Trace<WTF::kNoWeakHandling>};
+ }
+
+ static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
+ return GetWeakTraceDescriptorImpl<ValueType>::GetWeakTraceDescriptor(self);
+ }
+
+ template <WTF::WeakHandlingFlag WeakHandling = WTF::kNoWeakHandling>
+ static void Trace(Visitor* visitor, const void* self) {
+ if (!Traits::kCanTraceConcurrently && self) {
+ if (visitor->DeferredTraceIfConcurrent({self, &Trace<WeakHandling>},
+ GetBackingStoreSize(self)))
+ return;
+ }
+
+ static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
+ WTF::IsWeak<ValueType>::value,
+ "T should not be traced");
+ WTF::TraceInCollectionTrait<WeakHandling, Backing, void>::Trace(visitor,
+ self);
+ }
+
+ private:
+ static size_t GetBackingStoreSize(const void* backing_store) {
+ const HeapObjectHeader* header =
+ HeapObjectHeader::FromPayload(backing_store);
+ return header->IsLargeObject<HeapObjectHeader::AccessMode::kAtomic>()
+ ? static_cast<LargeObjectPage*>(PageFromObject(header))
+ ->ObjectSize()
+ : header->size<HeapObjectHeader::AccessMode::kAtomic>();
+ }
+
+ template <typename ValueType>
+ struct GetWeakTraceDescriptorImpl {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return {backing, nullptr};
+ }
+ };
+
+ template <typename K, typename V>
+ struct GetWeakTraceDescriptorImpl<WTF::KeyValuePair<K, V>> {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return GetWeakTraceDescriptorKVPImpl<K, V>::GetWeakTraceDescriptor(
+ backing);
+ }
+
+ template <typename KeyType,
+ typename ValueType,
+ bool ephemeron_semantics = (WTF::IsWeak<KeyType>::value &&
+ !WTF::IsWeak<ValueType>::value &&
+ WTF::IsTraceable<ValueType>::value) ||
+ (WTF::IsWeak<ValueType>::value &&
+ !WTF::IsWeak<KeyType>::value &&
+ WTF::IsTraceable<KeyType>::value)>
+ struct GetWeakTraceDescriptorKVPImpl {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return {backing, nullptr};
+ }
+ };
+
+ template <typename KeyType, typename ValueType>
+ struct GetWeakTraceDescriptorKVPImpl<KeyType, ValueType, true> {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return {backing, Trace<WTF::kWeakHandling>};
+ }
+ };
+ };
+};
+
+} // namespace blink
+
+namespace WTF {
+
+namespace internal {
+
+// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking.
+// It is used to provide a snapshot view of the bucket key and guarantee
+// that the same key is used for checking empty/deleted buckets and tracing.
+template <typename T>
+class ConcurrentBucket {
+ using KeyExtractionCallback = void (*)(const T&, void*);
+
+ public:
+ using BucketType = T;
+
+ ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) {
+ extract_key(t, &buf_);
+ }
+
+ // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key
+ // and the value are the same.
+ const T* key() const { return reinterpret_cast<const T*>(&buf_); }
+ const T* value() const { return key(); }
+ const T* bucket() const { return key(); }
+
+ private:
+ // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+ // can be accessed the same as objects of type T
+ static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t));
+ alignas(boundary) char buf_[sizeof(T)];
+};
+
+template <typename Key, typename Value>
+class ConcurrentBucket<KeyValuePair<Key, Value>> {
+ using KeyExtractionCallback = void (*)(const KeyValuePair<Key, Value>&,
+ void*);
+
+ public:
+ using BucketType = ConcurrentBucket;
+
+ ConcurrentBucket(const KeyValuePair<Key, Value>& pair,
+ KeyExtractionCallback extract_key)
+ : value_(&pair.value) {
+ extract_key(pair, &buf_);
+ }
+
+ const Key* key() const { return reinterpret_cast<const Key*>(&buf_); }
+ const Value* value() const { return value_; }
+ const ConcurrentBucket* bucket() const { return this; }
+
+ private:
+ // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+ // can be accessed the same as objects of type Key
+ static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t));
+ alignas(boundary) char buf_[sizeof(Key)];
+ const Value* value_;
+};
+
+} // namespace internal
+
+// This trace method is for tracing a HashTableBacking either through regular
+// tracing (via the relevant TraceTraits) or when finding a HashTableBacking
+// through conservative stack scanning (which will treat all references in the
+// backing strongly).
+template <WTF::WeakHandlingFlag WeakHandling, typename Table>
+struct TraceHashTableBackingInCollectionTrait {
+ using Value = typename Table::ValueType;
+ using Traits = typename Table::ValueTraits;
+ using Extractor = typename Table::ExtractorType;
+
+ static void Trace(blink::Visitor* visitor, const void* self) {
+ static_assert(IsTraceableInCollectionTrait<Traits>::value ||
+ WTF::IsWeak<Value>::value,
+ "Table should not be traced");
+ const Value* array = reinterpret_cast<const Value*>(self);
+ blink::HeapObjectHeader* header =
+ blink::HeapObjectHeader::FromPayload(self);
+ // Use the payload size as recorded by the heap to determine how many
+ // elements to trace.
+ size_t length = header->PayloadSize() / sizeof(Value);
+ const bool is_concurrent = visitor->IsConcurrent();
+ for (size_t i = 0; i < length; ++i) {
+ // If tracing concurrently, use a concurrent-safe version of
+ // IsEmptyOrDeletedBucket (check performed on a local copy instead
+ // of directly on the bucket).
+ if (is_concurrent) {
+ internal::ConcurrentBucket<Value> concurrent_bucket(
+ array[i], Extractor::ExtractSafe);
+ if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
+ IsEmptyOrDeletedBucketForKey(*concurrent_bucket.key())) {
+ blink::TraceCollectionIfEnabled<
+ WeakHandling,
+ typename internal::ConcurrentBucket<Value>::BucketType,
+ Traits>::Trace(visitor, concurrent_bucket.bucket());
+ }
+ } else {
+ if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
+ IsEmptyOrDeletedBucket(array[i])) {
+ blink::TraceCollectionIfEnabled<WeakHandling, Value, Traits>::Trace(
+ visitor, &array[i]);
+ }
+ }
+ }
+ }
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_vector_backing.h b/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_vector_backing.h
new file mode 100644
index 00000000000..c7b75baa8c7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/collection_support/heap_vector_backing.h
@@ -0,0 +1,213 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
+
+#include "base/check_op.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h"
+#include "third_party/blink/renderer/platform/heap/impl/gc_info.h"
+#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+template <typename T, typename Traits = WTF::VectorTraits<T>>
+class HeapVectorBacking final
+ : public GarbageCollected<HeapVectorBacking<T, Traits>>,
+ public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
+ !Traits::kNeedsDestruction> {
+ public:
+ template <typename Backing>
+ static void* AllocateObject(size_t);
+
+ // Conditionally invoked via destructor.
+ void Finalize();
+};
+
+// static
+template <typename T, typename Traits>
+template <typename Backing>
+void* HeapVectorBacking<T, Traits>::AllocateObject(size_t size) {
+ ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
+ DCHECK(state->IsAllocationAllowed());
+ return state->Heap().AllocateOnArenaIndex(
+ state, size, BlinkGC::kVectorArenaIndex, GCInfoTrait<Backing>::Index(),
+ WTF_HEAP_PROFILER_TYPE_NAME(Backing));
+}
+
+template <typename T, typename Traits>
+void HeapVectorBacking<T, Traits>::Finalize() {
+ static_assert(Traits::kNeedsDestruction,
+ "Only vector buffers with items requiring destruction should "
+ "be finalized");
+ static_assert(
+ Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic<T>::value,
+ "HeapVectorBacking doesn't support objects that cannot be cleared as "
+ "unused with memset or don't have a vtable");
+
+ static_assert(
+ !std::is_trivially_destructible<T>::value,
+ "Finalization of trivially destructible classes should not happen.");
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(this);
+ // Use the payload size as recorded by the heap to determine how many
+ // elements to finalize.
+ size_t length = header->PayloadSize() / sizeof(T);
+ Address payload = header->Payload();
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+ ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
+#endif
+ // As commented above, HeapVectorBacking calls finalizers for unused slots
+ // (which are already zeroed out).
+ if (std::is_polymorphic<T>::value) {
+ for (unsigned i = 0; i < length; ++i) {
+ Address element = payload + i * sizeof(T);
+ if (blink::VTableInitialized(element))
+ reinterpret_cast<T*>(element)->~T();
+ }
+ } else {
+ T* buffer = reinterpret_cast<T*>(payload);
+ for (unsigned i = 0; i < length; ++i)
+ buffer[i].~T();
+ }
+}
+
+template <typename T>
+struct MakeGarbageCollectedTrait<HeapVectorBacking<T>> {
+ static HeapVectorBacking<T>* Call(size_t num_elements) {
+ static_assert(!std::is_polymorphic<HeapVectorBacking<T>>::value,
+ "HeapVectorBacking must not be polymorphic as it is "
+ "converted to a raw array of buckets for certain operation");
+ CHECK_GT(num_elements, 0u);
+ void* memory =
+ HeapVectorBacking<T>::template AllocateObject<HeapVectorBacking<T>>(
+ num_elements * sizeof(T));
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
+ // Placement new as regular operator new() is deleted.
+ HeapVectorBacking<T>* object = ::new (memory) HeapVectorBacking<T>();
+ header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
+ return object;
+ }
+};
+
+template <typename T, typename Traits>
+struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
+ STATIC_ONLY(ThreadingTrait);
+ static const ThreadAffinity kAffinity = ThreadingTrait<T>::Affinity;
+};
+
+template <typename T, typename Traits>
+struct TraceTrait<HeapVectorBacking<T, Traits>> {
+ STATIC_ONLY(TraceTrait);
+ using Backing = HeapVectorBacking<T, Traits>;
+
+ public:
+ static TraceDescriptor GetTraceDescriptor(const void* self) {
+ return {self, TraceTrait<Backing>::Trace};
+ }
+
+ static void Trace(Visitor* visitor, const void* self) {
+ if (!Traits::kCanTraceConcurrently && self) {
+ if (visitor->DeferredTraceIfConcurrent({self, &Trace},
+ GetBackingStoreSize(self)))
+ return;
+ }
+
+ static_assert(!WTF::IsWeak<T>::value,
+ "Weakness is not supported in HeapVector and HeapDeque");
+ if (WTF::IsTraceableInCollectionTrait<Traits>::value) {
+ WTF::TraceInCollectionTrait<WTF::kNoWeakHandling,
+ HeapVectorBacking<T, Traits>,
+ void>::Trace(visitor, self);
+ }
+ }
+
+ private:
+ static size_t GetBackingStoreSize(const void* backing_store) {
+ const HeapObjectHeader* header =
+ HeapObjectHeader::FromPayload(backing_store);
+ return header->IsLargeObject<HeapObjectHeader::AccessMode::kAtomic>()
+ ? static_cast<LargeObjectPage*>(PageFromObject(header))
+ ->ObjectSize()
+ : header->size<HeapObjectHeader::AccessMode::kAtomic>();
+ }
+};
+
+} // namespace blink
+
+namespace WTF {
+
+// This trace method is used for all HeapVectorBacking objects. On-stack objects
+// are found and dispatched using conservative stack scanning. HeapVector (i.e.
+// Vector) dispatches all regular on-heap backings to this method.
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kNoWeakHandling,
+ blink::HeapVectorBacking<T, Traits>,
+ void> {
+ static void Trace(blink::Visitor* visitor, const void* self) {
+ // HeapVectorBacking does not know the exact size of the vector
+ // and just knows the capacity of the vector. Due to the constraint,
+ // HeapVectorBacking can support only the following objects:
+ //
+ // - An object that has a vtable. In this case, HeapVectorBacking
+ // traces only slots that are not zeroed out. This is because if
+ // the object has a vtable, the zeroed slot means that it is
+ // an unused slot (Remember that the unused slots are guaranteed
+ // to be zeroed out by VectorUnusedSlotClearer).
+ //
+ // - An object that can be initialized with memset. In this case,
+ // HeapVectorBacking traces all slots including unused slots.
+ // This is fine because the fact that the object can be initialized
+ // with memset indicates that it is safe to treat the zerod slot
+ // as a valid object.
+ static_assert(!IsTraceableInCollectionTrait<Traits>::value ||
+ Traits::kCanClearUnusedSlotsWithMemset ||
+ std::is_polymorphic<T>::value,
+ "HeapVectorBacking doesn't support objects that cannot be "
+ "cleared as unused with memset.");
+
+ // This trace method is instantiated for vectors where
+ // IsTraceableInCollectionTrait<Traits>::value is false, but the trace
+ // method should not be called. Thus we cannot static-assert
+ // IsTraceableInCollectionTrait<Traits>::value but should runtime-assert it.
+ DCHECK(IsTraceableInCollectionTrait<Traits>::value);
+
+ const T* array = reinterpret_cast<const T*>(self);
+ blink::HeapObjectHeader* header =
+ blink::HeapObjectHeader::FromPayload(self);
+ // Use the payload size as recorded by the heap to determine how many
+ // elements to trace.
+ size_t length = header->PayloadSize() / sizeof(T);
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+ // As commented above, HeapVectorBacking can trace unused slots
+ // (which are already zeroed out).
+ ANNOTATE_CHANGE_SIZE(array, length, 0, length);
+#endif
+ if (std::is_polymorphic<T>::value) {
+ const char* pointer = reinterpret_cast<const char*>(array);
+ for (unsigned i = 0; i < length; ++i) {
+ const char* element = pointer + i * sizeof(T);
+ if (blink::VTableInitialized(element)) {
+ blink::TraceIfNeeded<
+ T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+ array[i]);
+ }
+ }
+ } else {
+ for (size_t i = 0; i < length; ++i) {
+ blink::TraceIfNeeded<
+ T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+ array[i]);
+ }
+ }
+ }
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h
deleted file mode 100644
index b6562e440e3..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h
+++ /dev/null
@@ -1,53 +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_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
-
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-
-namespace blink {
-
-// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class.
-template <typename T>
-class DisallowNewWrapper final
- : public GarbageCollected<DisallowNewWrapper<T>> {
- public:
- explicit DisallowNewWrapper(const T& value) : value_(value) {
- static_assert(WTF::IsDisallowNew<T>::value,
- "T needs to be a disallow new type");
- static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
- }
- explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) {
- static_assert(WTF::IsDisallowNew<T>::value,
- "T needs to be a disallow new type");
- static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable");
- }
-
- const T& Value() const { return value_; }
- T&& TakeValue() { return std::move(value_); }
-
- void Trace(Visitor* visitor) const { visitor->Trace(value_); }
-
- private:
- T value_;
-};
-
-// Wraps a disallow new type in a GarbageCollected class, making it possible to
-// be referenced off heap from a Persistent.
-template <typename T>
-DisallowNewWrapper<T>* WrapDisallowNew(const T& value) {
- return MakeGarbageCollected<DisallowNewWrapper<T>>(value);
-}
-
-template <typename T>
-DisallowNewWrapper<T>* WrapDisallowNew(T&& value) {
- return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value));
-}
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h
index b7af662ed5d..fb60f06725f 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h
@@ -91,8 +91,7 @@ class NeedsAdjustPointer<T, false> {
static_assert(sizeof(T), "T must be fully defined");
public:
- static const bool value =
- IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value;
+ static const bool value = true;
};
// TODO(sof): migrate to wtf/TypeTraits.h
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc
index 14361c26f3c..2be470ad6b3 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc
@@ -108,13 +108,8 @@ void GCInfoTable::Resize() {
const size_t table_size_delta = new_committed_size - old_committed_size;
// Commit the new size and allow read/write.
- // TODO(ajwong): SetSystemPagesAccess should be part of RecommitSystemPages to
- // avoid having two calls here.
- base::SetSystemPagesAccess(current_table_end, table_size_delta,
- base::PageReadWrite);
- bool ok = base::RecommitSystemPages(current_table_end, table_size_delta,
- base::PageReadWrite);
- CHECK(ok);
+ base::RecommitSystemPages(current_table_end, table_size_delta,
+ base::PageReadWrite, base::PageUpdatePermissions);
#if DCHECK_IS_ON()
// Check that newly-committed memory is zero-initialized.
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h
deleted file mode 100644
index 1e93f7fcac5..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2014 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_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
-
-#include <memory>
-#include "base/location.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-class GCTaskObserver final : public Thread::TaskObserver {
- USING_FAST_MALLOC(GCTaskObserver);
-
- public:
- GCTaskObserver() : nesting_(0) {}
-
- ~GCTaskObserver() override {
- // m_nesting can be 1 if this was unregistered in a task and
- // didProcessTask was not called.
- DCHECK(!nesting_ || nesting_ == 1);
- }
-
- void WillProcessTask(const base::PendingTask&, bool) override { nesting_++; }
-
- void DidProcessTask(const base::PendingTask&) override {
- // In the production code WebKit::initialize is called from inside the
- // message loop so we can get didProcessTask() without corresponding
- // willProcessTask once. This is benign.
- if (nesting_)
- nesting_--;
-
- ThreadState::Current()->SafePoint(nesting_
- ? BlinkGC::kHeapPointersOnStack
- : BlinkGC::kNoHeapPointersOnStack);
- }
-
- private:
- int nesting_;
-};
-
-class GCTaskRunner final {
- USING_FAST_MALLOC(GCTaskRunner);
-
- public:
- explicit GCTaskRunner(Thread* thread)
- : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) {
- thread_->AddTaskObserver(gc_task_observer_.get());
- }
-
- ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); }
-
- private:
- std::unique_ptr<GCTaskObserver> gc_task_observer_;
- Thread* thread_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc
index 2fa56d7d1d9..5a617ff7ed9 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc
@@ -59,9 +59,6 @@
namespace blink {
-HeapAllocHooks::AllocationHook* HeapAllocHooks::allocation_hook_ = nullptr;
-HeapAllocHooks::FreeHook* HeapAllocHooks::free_hook_ = nullptr;
-
class ProcessHeapReporter final : public ThreadHeapStatsObserver {
public:
void IncreaseAllocatedSpace(size_t bytes) final {
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap.h
index f1740aaa3e2..263caacbafb 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap.h
@@ -122,45 +122,6 @@ class WeakContainersWorklist {
std::unordered_set<const HeapObjectHeader*> objects_;
};
-class PLATFORM_EXPORT HeapAllocHooks {
- STATIC_ONLY(HeapAllocHooks);
-
- public:
- // TODO(hajimehoshi): Pass a type name of the allocated object.
- typedef void AllocationHook(Address, size_t, const char*);
- typedef void FreeHook(Address);
-
- // Sets allocation hook. Only one hook is supported.
- static void SetAllocationHook(AllocationHook* hook) {
- CHECK(!allocation_hook_ || !hook);
- allocation_hook_ = hook;
- }
-
- // Sets free hook. Only one hook is supported.
- static void SetFreeHook(FreeHook* hook) {
- CHECK(!free_hook_ || !hook);
- free_hook_ = hook;
- }
-
- static void AllocationHookIfEnabled(Address address,
- size_t size,
- const char* type_name) {
- AllocationHook* allocation_hook = allocation_hook_;
- if (UNLIKELY(!!allocation_hook))
- allocation_hook(address, size, type_name);
- }
-
- static void FreeHookIfEnabled(Address address) {
- FreeHook* free_hook = free_hook_;
- if (UNLIKELY(!!free_hook))
- free_hook(address);
- }
-
- private:
- static AllocationHook* allocation_hook_;
- static FreeHook* free_hook_;
-};
-
class HeapCompact;
template <typename T>
class Member;
@@ -538,8 +499,6 @@ class GarbageCollected {
using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type;
GarbageCollected() = default;
-
- DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
};
// Used for passing custom sizes to MakeGarbageCollected.
@@ -659,7 +618,6 @@ inline Address ThreadHeap::AllocateOnArenaIndex(ThreadState* state,
NormalPageArena* arena = static_cast<NormalPageArena*>(Arena(arena_index));
Address address =
arena->AllocateObject(AllocationSizeFromSize(size), gc_info_index);
- HeapAllocHooks::AllocationHookIfEnabled(address, size, type_name);
return address;
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc
deleted file mode 100644
index f4e2745e671..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-
-namespace blink {
-
-namespace {
-
-struct BackingModifier {
- bool can_modify;
- BasePage* const page;
- HeapObjectHeader* const header;
-};
-
-BackingModifier CanModifyBacking(ThreadState* const state, void* address) {
- // - |SweepForbidden| protects against modifying objects from destructors.
- // - |IsSweepingInProgress| protects against modifying objects while
- // concurrent sweeping is in progress.
- // - |in_atomic_pause| protects against modifying objects from within the GC.
- // This can
- // e.g. happen when hash table buckets that have containers inlined are
- // freed during weakness processing.
- // - |IsMarkingInProgress| protects against incremental marking which may have
- // registered callbacks.
- if (state->SweepForbidden() || state->IsSweepingInProgress() ||
- state->in_atomic_pause() || state->IsMarkingInProgress())
- return {false, nullptr, nullptr};
-
- // - Don't adjust large objects because their page is never reused.
- // - Don't free backings allocated on other threads.
- BasePage* page = PageFromObject(address);
- if (page->IsLargeObjectPage() || page->Arena()->GetThreadState() != state)
- return {false, nullptr, nullptr};
-
- HeapObjectHeader* const header = HeapObjectHeader::FromPayload(address);
- // - Guards against pages that have not been swept. Technically, it should be
- // fine to modify those backings. We bail out to maintain the invariant that
- // no marked backing is modified.
- if (header->IsMarked())
- return {false, nullptr, nullptr};
- return {true, page, header};
-}
-
-} // namespace
-
-void HeapAllocator::BackingFree(void* address) {
- if (!address)
- return;
-
- ThreadState* const state = ThreadState::Current();
- BackingModifier result = CanModifyBacking(state, address);
- if (!result.can_modify)
- return;
-
- static_cast<NormalPage*>(result.page)
- ->ArenaForNormalPage()
- ->PromptlyFreeObject(result.header);
-}
-
-void HeapAllocator::FreeVectorBacking(void* address) {
- BackingFree(address);
-}
-
-void HeapAllocator::FreeHashTableBacking(void* address) {
- BackingFree(address);
-}
-
-bool HeapAllocator::BackingExpand(void* address, size_t new_size) {
- if (!address)
- return false;
-
- ThreadState* state = ThreadState::Current();
-
- BackingModifier result = CanModifyBacking(state, address);
- if (!result.can_modify)
- return false;
- DCHECK(!state->in_atomic_pause());
- DCHECK(state->IsAllocationAllowed());
- DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
-
- // FIXME: Support expand for large objects.
- // Don't expand backings allocated on other threads.
- BasePage* page = PageFromObject(address);
- if (page->IsLargeObjectPage() || page->Arena()->GetThreadState() != state)
- return false;
-
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(address);
- NormalPageArena* arena = static_cast<NormalPage*>(page)->ArenaForNormalPage();
- return arena->ExpandObject(header, new_size);
-}
-
-bool HeapAllocator::ExpandVectorBacking(void* address, size_t new_size) {
- return BackingExpand(address, new_size);
-}
-
-bool HeapAllocator::ExpandHashTableBacking(void* address, size_t new_size) {
- return BackingExpand(address, new_size);
-}
-
-bool HeapAllocator::BackingShrink(void* address,
- size_t quantized_current_size,
- size_t quantized_shrunk_size) {
- if (!address || quantized_shrunk_size == quantized_current_size)
- return true;
-
- DCHECK_LT(quantized_shrunk_size, quantized_current_size);
-
- ThreadState* const state = ThreadState::Current();
- BackingModifier result = CanModifyBacking(state, address);
- if (!result.can_modify)
- return false;
-
- DCHECK(state->IsAllocationAllowed());
- DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
-
- NormalPageArena* arena =
- static_cast<NormalPage*>(result.page)->ArenaForNormalPage();
- // We shrink the object only if the shrinking will make a non-small
- // prompt-free block.
- // FIXME: Optimize the threshold size.
- if (quantized_current_size <= quantized_shrunk_size +
- sizeof(HeapObjectHeader) +
- sizeof(void*) * 32 &&
- !arena->IsObjectAllocatedAtAllocationPoint(result.header))
- return true;
-
- arena->ShrinkObject(result.header, quantized_shrunk_size);
- return true;
-}
-
-bool HeapAllocator::ShrinkVectorBacking(void* address,
- size_t quantized_current_size,
- size_t quantized_shrunk_size) {
- return BackingShrink(address, quantized_current_size, quantized_shrunk_size);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
deleted file mode 100644
index 8fc46cb2a62..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
+++ /dev/null
@@ -1,909 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
-
-#include <type_traits>
-
-#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
-#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
-#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
-#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
-#include "third_party/blink/renderer/platform/wtf/deque.h"
-#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
-#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/hash_table.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-#define DISALLOW_IN_CONTAINER() \
- public: \
- using IsDisallowedInContainerMarker = int; \
- \
- private: \
- friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-
-// IsAllowedInContainer returns true if some type T supports being nested
-// arbitrarily in other containers. This is relevant for collections where some
-// collections assume that they are placed on a non-moving arena.
-template <typename T, typename = int>
-struct IsAllowedInContainer : std::true_type {};
-template <typename T>
-struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker>
- : std::false_type {};
-
-// This is a static-only class used as a trait on collections to make them heap
-// allocated. However see also HeapListHashSetAllocator.
-class PLATFORM_EXPORT HeapAllocator {
- STATIC_ONLY(HeapAllocator);
-
- public:
- using LivenessBroker = blink::LivenessBroker;
- using Visitor = blink::Visitor;
- static constexpr bool kIsGarbageCollected = true;
-
- template <typename T>
- static size_t MaxElementCountInBackingStore() {
- return kMaxHeapObjectSize / sizeof(T);
- }
-
- template <typename T>
- static size_t QuantizedSize(size_t count) {
- CHECK(count <= MaxElementCountInBackingStore<T>());
- return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) -
- sizeof(HeapObjectHeader);
- }
- template <typename T>
- static T* AllocateVectorBacking(size_t size) {
- return reinterpret_cast<T*>(
- MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
- }
- static void FreeVectorBacking(void*);
- static bool ExpandVectorBacking(void*, size_t);
- static bool ShrinkVectorBacking(void* address,
- size_t quantized_current_size,
- size_t quantized_shrunk_size);
-
- template <typename T, typename HashTable>
- static T* AllocateHashTableBacking(size_t size) {
- return reinterpret_cast<T*>(
- MakeGarbageCollected<HeapHashTableBacking<HashTable>>(
- size / sizeof(typename HashTable::ValueType)));
- }
- template <typename T, typename HashTable>
- static T* AllocateZeroedHashTableBacking(size_t size) {
- return AllocateHashTableBacking<T, HashTable>(size);
- }
- static void FreeHashTableBacking(void* address);
- static bool ExpandHashTableBacking(void*, size_t);
-
- static void TraceBackingStoreIfMarked(const void* address) {
- // Trace backing store elements only if backing store was marked. The
- // sweeper may be active on the backing store which requires atomic mark bit
- // access. A precise filter is performed in
- // MarkingVisitor::TraceMarkedBackingStore.
- if (HeapObjectHeader::FromPayload(address)
- ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) {
- MarkingVisitor::TraceMarkedBackingStore(address);
- }
- }
-
- template <typename T>
- static void BackingWriteBarrier(T** slot) {
- MarkingVisitor::WriteBarrier(slot);
- }
-
- template <typename Return, typename Metadata>
- static Return Malloc(size_t size, const char* type_name) {
- return reinterpret_cast<Return>(
- MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size)));
- }
-
- // Compilers sometimes eagerly instantiates the unused 'operator delete', so
- // we provide a version that asserts and fails at run-time if used.
- static void Free(void*) { NOTREACHED(); }
-
- template <typename T>
- static void* NewArray(size_t bytes) {
- NOTREACHED();
- return nullptr;
- }
-
- static void DeleteArray(void* ptr) { NOTREACHED(); }
-
- static bool IsAllocationAllowed() {
- return ThreadState::Current()->IsAllocationAllowed();
- }
-
- static bool IsIncrementalMarking() {
- return ThreadState::IsAnyIncrementalMarking() &&
- ThreadState::Current()->IsIncrementalMarking();
- }
-
- template <typename T, typename Traits>
- static void Trace(Visitor* visitor, const T& t) {
- TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
- Traits>::Trace(visitor, &t);
- }
-
- static void EnterGCForbiddenScope() {
- ThreadState::Current()->EnterGCForbiddenScope();
- }
-
- static void LeaveGCForbiddenScope() {
- ThreadState::Current()->LeaveGCForbiddenScope();
- }
-
- template <typename T, typename Traits>
- static void NotifyNewObject(T* object) {
-#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
- ThreadState* const thread_state = ThreadState::Current();
- if (!thread_state->IsIncrementalMarking()) {
- MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(object),
- thread_state);
- return;
- }
-#else
- if (!ThreadState::IsAnyIncrementalMarking())
- return;
- // The object may have been in-place constructed as part of a large object.
- // It is not safe to retrieve the page from the object here.
- ThreadState* const thread_state = ThreadState::Current();
- if (!thread_state->IsIncrementalMarking()) {
- return;
- }
-#endif // BLINK_HEAP_YOUNG_GENERATION
- // Eagerly trace the object ensuring that the object and all its children
- // are discovered by the marker.
- ThreadState::NoAllocationScope no_allocation_scope(thread_state);
- DCHECK(thread_state->CurrentVisitor());
- // No weak handling for write barriers. Modifying weakly reachable objects
- // strongifies them for the current cycle.
- DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object));
- TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
- thread_state->CurrentVisitor(), object);
- }
-
- template <typename T, typename Traits>
- static void NotifyNewObjects(T* array, size_t len) {
-#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
- ThreadState* const thread_state = ThreadState::Current();
- if (!thread_state->IsIncrementalMarking()) {
- MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(array),
- thread_state);
- return;
- }
-#else
- if (!ThreadState::IsAnyIncrementalMarking())
- return;
- // The object may have been in-place constructed as part of a large object.
- // It is not safe to retrieve the page from the object here.
- ThreadState* const thread_state = ThreadState::Current();
- if (!thread_state->IsIncrementalMarking()) {
- return;
- }
-#endif // BLINK_HEAP_YOUNG_GENERATION
- // See |NotifyNewObject| for details.
- ThreadState::NoAllocationScope no_allocation_scope(thread_state);
- DCHECK(thread_state->CurrentVisitor());
- // No weak handling for write barriers. Modifying weakly reachable objects
- // strongifies them for the current cycle.
- while (len-- > 0) {
- DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array));
- TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace(
- thread_state->CurrentVisitor(), array);
- array++;
- }
- }
-
- template <typename T>
- static void TraceVectorBacking(Visitor* visitor,
- const T* backing,
- const T* const* backing_slot) {
- visitor->TraceMovablePointer(backing_slot);
- visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
- }
-
- template <typename T, typename HashTable>
- static void TraceHashTableBackingStrongly(Visitor* visitor,
- const T* backing,
- const T* const* backing_slot) {
- visitor->TraceMovablePointer(backing_slot);
- visitor->Trace(
- reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
- }
-
- template <typename T, typename HashTable>
- static void TraceHashTableBackingWeakly(Visitor* visitor,
- const T* backing,
- const T* const* backing_slot,
- WeakCallback callback,
- const void* parameter) {
- visitor->TraceMovablePointer(backing_slot);
- visitor->TraceWeakContainer(
- reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
- reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
- backing_slot),
- TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor(
- backing),
- TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor(
- backing),
- callback, parameter);
- }
-
- private:
- static Address MarkAsConstructed(Address address) {
- HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address))
- ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>();
- return address;
- }
-
- static void BackingFree(void*);
- static bool BackingExpand(void*, size_t);
- static bool BackingShrink(void*,
- size_t quantized_current_size,
- size_t quantized_shrunk_size);
-
- template <typename T, wtf_size_t u, typename V>
- friend class WTF::Vector;
- template <typename T, typename U, typename V, typename W>
- friend class WTF::HashSet;
- template <typename T,
- typename U,
- typename V,
- typename W,
- typename X,
- typename Y>
- friend class WTF::HashMap;
-};
-
-template <typename VisitorDispatcher, typename Value>
-static void TraceListHashSetValue(VisitorDispatcher visitor,
- const Value& value) {
- // We use the default hash traits for the value in the node, because
- // ListHashSet does not let you specify any specific ones.
- // We don't allow ListHashSet of WeakMember, so we set that one false
- // (there's an assert elsewhere), but we have to specify some value for the
- // strongify template argument, so we specify WTF::WeakPointersActWeak,
- // arbitrarily.
- TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value,
- WTF::HashTraits<Value>>::Trace(visitor, &value);
-}
-
-// The inline capacity is just a dummy template argument to match the off-heap
-// allocator.
-// This inherits from the static-only HeapAllocator trait class, but we do
-// declare pointers to instances. These pointers are always null, and no
-// objects are instantiated.
-template <typename ValueArg, wtf_size_t inlineCapacity>
-class HeapListHashSetAllocator : public HeapAllocator {
- DISALLOW_NEW();
-
- public:
- using TableAllocator = HeapAllocator;
- using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>;
-
- class AllocatorProvider {
- DISALLOW_NEW();
-
- public:
- // For the heap allocation we don't need an actual allocator object, so
- // we just return null.
- HeapListHashSetAllocator* Get() const { return nullptr; }
-
- // No allocator object is needed.
- void CreateAllocatorIfNeeded() {}
- void ReleaseAllocator() {}
-
- // There is no allocator object in the HeapListHashSet (unlike in the
- // regular ListHashSet) so there is nothing to swap.
- void Swap(AllocatorProvider& other) {}
- };
-
- void Deallocate(void* dummy) {}
-
- // This is not a static method even though it could be, because it needs to
- // match the one that the (off-heap) ListHashSetAllocator has. The 'this'
- // pointer will always be null.
- void* AllocateNode() {
- // Consider using a LinkedHashSet instead if this compile-time assert fails:
- static_assert(!WTF::IsWeak<ValueArg>::value,
- "weak pointers in a ListHashSet will result in null entries "
- "in the set");
-
- return Malloc<void*, Node>(
- sizeof(Node),
- nullptr /* Oilpan does not use the heap profiler at the moment. */);
- }
-
- template <typename VisitorDispatcher>
- static void TraceValue(VisitorDispatcher visitor, const Node* node) {
- TraceListHashSetValue(visitor, node->value_);
- }
-};
-
-namespace internal {
-
-template <typename T>
-constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value;
-
-} // namespace internal
-
-template <typename KeyArg,
- typename MappedArg,
- typename HashArg = typename DefaultHash<KeyArg>::Hash,
- typename KeyTraitsArg = HashTraits<KeyArg>,
- typename MappedTraitsArg = HashTraits<MappedArg>>
-class HeapHashMap : public HashMap<KeyArg,
- MappedArg,
- HashArg,
- KeyTraitsArg,
- MappedTraitsArg,
- HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(std::is_trivially_destructible<HeapHashMap>::value,
- "HeapHashMap must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<KeyArg>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(
- IsAllowedInContainer<MappedArg>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(
- WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
- "For hash maps without traceable elements, use HashMap<> "
- "instead of HeapHashMap<>.");
- static_assert(WTF::IsMemberOrWeakMemberType<KeyArg>::value ||
- !WTF::IsTraceable<KeyArg>::value,
- "HeapHashMap supports only Member, WeakMember and "
- "non-traceable types as keys.");
- static_assert(WTF::IsMemberOrWeakMemberType<MappedArg>::value ||
- !WTF::IsTraceable<MappedArg>::value ||
- WTF::IsSubclassOfTemplate<MappedArg,
- TraceWrapperV8Reference>::value,
- "HeapHashMap supports only Member, WeakMember, "
- "TraceWrapperV8Reference and "
- "non-traceable types as values.");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<
- HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>(
- size);
- }
-
- HeapHashMap() { CheckType(); }
-};
-
-template <typename T, typename U, typename V, typename W, typename X>
-struct GCInfoTrait<HeapHashMap<T, U, V, W, X>>
- : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {};
-
-template <typename ValueArg,
- typename HashArg = typename DefaultHash<ValueArg>::Hash,
- typename TraitsArg = HashTraits<ValueArg>>
-class HeapHashSet
- : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
- "HeapHashSet supports only Member and WeakMember.");
- static_assert(std::is_trivially_destructible<HeapHashSet>::value,
- "HeapHashSet must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<ValueArg>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<ValueArg>::value,
- "For hash sets without traceable elements, use HashSet<> "
- "instead of HeapHashSet<>.");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>(
- size);
- }
-
- HeapHashSet() { CheckType(); }
-};
-
-template <typename T, typename U, typename V>
-struct GCInfoTrait<HeapHashSet<T, U, V>>
- : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
-
-template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
-class HeapLinkedHashSet
- : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
- "HeapLinkedHashSet supports only Member and WeakMember.");
- // If not trivially destructible, we have to add a destructor which will
- // hinder performance.
- static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
- "HeapLinkedHashSet must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<ValueArg>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<ValueArg>::value,
- "For sets without traceable elements, use LinkedHashSet<> "
- "instead of HeapLinkedHashSet<>.");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size);
- }
-
- HeapLinkedHashSet() { CheckType(); }
-};
-
-template <typename T, typename U>
-struct GCInfoTrait<HeapLinkedHashSet<T, U>>
- : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {};
-
-template <typename ValueArg,
- wtf_size_t inlineCapacity = 0, // The inlineCapacity is just a dummy
- // to match ListHashSet (off-heap).
- typename HashArg = typename DefaultHash<ValueArg>::Hash>
-class HeapListHashSet
- : public ListHashSet<ValueArg,
- inlineCapacity,
- HashArg,
- HeapListHashSetAllocator<ValueArg, inlineCapacity>> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
- "HeapListHashSet supports only Member and WeakMember.");
- static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
- "HeapListHashSet must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<ValueArg>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<ValueArg>::value,
- "For sets without traceable elements, use ListHashSet<> "
- "instead of HeapListHashSet<>.");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<
- HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size);
- }
-
- HeapListHashSet() { CheckType(); }
-};
-
-template <typename T, wtf_size_t inlineCapacity, typename U>
-struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>>
- : public GCInfoTrait<
- ListHashSet<T,
- inlineCapacity,
- U,
- HeapListHashSetAllocator<T, inlineCapacity>>> {};
-
-template <typename Value,
- typename HashFunctions = typename DefaultHash<Value>::Hash,
- typename Traits = HashTraits<Value>>
-class HeapHashCountedSet
- : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(WTF::IsMemberOrWeakMemberType<Value>::value,
- "HeapHashCountedSet supports only Member and WeakMember.");
- static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
- "HeapHashCountedSet must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<Value>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<Value>::value,
- "For counted sets without traceable elements, use "
- "HashCountedSet<> instead of HeapHashCountedSet<>.");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<
- HeapHashCountedSet<Value, HashFunctions, Traits>>(size);
- }
-
- HeapHashCountedSet() { CheckType(); }
-};
-
-template <typename T, typename U, typename V>
-struct GCInfoTrait<HeapHashCountedSet<T, U, V>>
- : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {};
-
-template <typename T, wtf_size_t inlineCapacity = 0>
-class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(
- std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
- "HeapVector must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<T>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<T>::value,
- "For vectors without traceable elements, use Vector<> "
- "instead of HeapVector<>.");
- static_assert(!WTF::IsWeak<T>::value,
- "Weak types are not allowed in HeapVector.");
- static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value,
- "Type must be traceable in collection");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- // On-heap HeapVectors generally should not have inline capacity, but it is
- // hard to avoid when using a type alias. Hence we only disallow the
- // VectorTraits<T>::kNeedsDestruction case for now.
- static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
- "on-heap HeapVector<> should not have an inline capacity");
- return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size);
- }
-
- HeapVector() { CheckType(); }
-
- explicit HeapVector(wtf_size_t size)
- : Vector<T, inlineCapacity, HeapAllocator>(size) {
- CheckType();
- }
-
- HeapVector(wtf_size_t size, const T& val)
- : Vector<T, inlineCapacity, HeapAllocator>(size, val) {
- CheckType();
- }
-
- template <wtf_size_t otherCapacity>
- HeapVector(const HeapVector<T, otherCapacity>& other)
- : Vector<T, inlineCapacity, HeapAllocator>(other) {
- CheckType();
- }
-
- HeapVector(std::initializer_list<T> elements)
- : Vector<T, inlineCapacity, HeapAllocator>(elements) {
- CheckType();
- }
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct GCInfoTrait<HeapVector<T, inlineCapacity>>
- : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {};
-
-template <typename T>
-class HeapDeque : public Deque<T, 0, HeapAllocator> {
- IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
- DISALLOW_NEW();
-
- static void CheckType() {
- static_assert(internal::IsMember<T>, "HeapDeque supports only Member.");
- static_assert(std::is_trivially_destructible<HeapDeque>::value,
- "HeapDeque must be trivially destructible.");
- static_assert(
- IsAllowedInContainer<T>::value,
- "Not allowed to directly nest type. Use Member<> indirection instead.");
- static_assert(WTF::IsTraceable<T>::value,
- "For vectors without traceable elements, use Deque<> instead "
- "of HeapDeque<>");
- }
-
- public:
- template <typename>
- static void* AllocateObject(size_t size) {
- return ThreadHeap::Allocate<HeapDeque<T>>(size);
- }
-
- HeapDeque() { CheckType(); }
-
- explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) {
- CheckType();
- }
-
- HeapDeque(wtf_size_t size, const T& val)
- : Deque<T, 0, HeapAllocator>(size, val) {
- CheckType();
- }
-
- HeapDeque& operator=(const HeapDeque& other) {
- HeapDeque<T> copy(other);
- Deque<T, 0, HeapAllocator>::Swap(copy);
- return *this;
- }
-
- HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {}
-};
-
-template <typename T>
-struct GCInfoTrait<HeapDeque<T>>
- : public GCInfoTrait<Deque<T, 0, HeapAllocator>> {};
-
-} // namespace blink
-
-namespace WTF {
-
-template <typename T>
-struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = false;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = true;
- static const bool kCanCopyWithMemcpy = true;
- static const bool kCanMoveWithMemcpy = true;
-
- static constexpr bool kCanTraceConcurrently = true;
-};
-
-// These traits are used in VectorBackedLinkedList to support WeakMember in
-// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned.
-// (See the discussion in https://crrev.com/c/2246014)
-template <typename T>
-struct VectorTraits<blink::WeakMember<T>>
- : VectorTraitsBase<blink::WeakMember<T>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = false;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = true;
- static const bool kCanCopyWithMemcpy = true;
- static const bool kCanMoveWithMemcpy = true;
-
- static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::UntracedMember<T>>
- : VectorTraitsBase<blink::UntracedMember<T>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = false;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = true;
- static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::HeapVector<T, 0>>
- : VectorTraitsBase<blink::HeapVector<T, 0>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = false;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = true;
- static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct VectorTraits<blink::HeapDeque<T>>
- : VectorTraitsBase<blink::HeapDeque<T>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = false;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = true;
- static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct VectorTraits<blink::HeapVector<T, inlineCapacity>>
- : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction;
- static const bool kCanInitializeWithMemset =
- VectorTraits<T>::kCanInitializeWithMemset;
- static const bool kCanClearUnusedSlotsWithMemset =
- VectorTraits<T>::kCanClearUnusedSlotsWithMemset;
- static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy;
-};
-
-template <typename T>
-struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> {
- STATIC_ONLY(HashTraits);
- // FIXME: Implement proper const'ness for iterator types. Requires support
- // in the marking Visitor.
- using PeekInType = T*;
- using IteratorGetType = blink::Member<T>*;
- using IteratorConstGetType = const blink::Member<T>*;
- using IteratorReferenceType = blink::Member<T>&;
- using IteratorConstReferenceType = const blink::Member<T>&;
- static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
- return *x;
- }
- static IteratorConstReferenceType GetToReferenceConstConversion(
- IteratorConstGetType x) {
- return *x;
- }
-
- using PeekOutType = T*;
-
- template <typename U>
- static void Store(const U& value, blink::Member<T>& storage) {
- storage = value;
- }
-
- static PeekOutType Peek(const blink::Member<T>& value) { return value; }
-
- static void ConstructDeletedValue(blink::Member<T>& slot, bool) {
- slot = WTF::kHashTableDeletedValue;
- }
-
- static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct HashTraits<blink::WeakMember<T>>
- : SimpleClassHashTraits<blink::WeakMember<T>> {
- STATIC_ONLY(HashTraits);
- static const bool kNeedsDestruction = false;
- // FIXME: Implement proper const'ness for iterator types. Requires support
- // in the marking Visitor.
- using PeekInType = T*;
- using IteratorGetType = blink::WeakMember<T>*;
- using IteratorConstGetType = const blink::WeakMember<T>*;
- using IteratorReferenceType = blink::WeakMember<T>&;
- using IteratorConstReferenceType = const blink::WeakMember<T>&;
- static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
- return *x;
- }
- static IteratorConstReferenceType GetToReferenceConstConversion(
- IteratorConstGetType x) {
- return *x;
- }
-
- using PeekOutType = T*;
-
- template <typename U>
- static void Store(const U& value, blink::WeakMember<T>& storage) {
- storage = value;
- }
-
- static PeekOutType Peek(const blink::WeakMember<T>& value) { return value; }
-
- static void ConstructDeletedValue(blink::WeakMember<T>& slot, bool) {
- slot = WTF::kHashTableDeletedValue;
- }
-
- static constexpr bool kCanTraceConcurrently = true;
-};
-
-template <typename T>
-struct HashTraits<blink::UntracedMember<T>>
- : SimpleClassHashTraits<blink::UntracedMember<T>> {
- STATIC_ONLY(HashTraits);
- static const bool kNeedsDestruction = false;
- // FIXME: Implement proper const'ness for iterator types.
- using PeekInType = T*;
- using IteratorGetType = blink::UntracedMember<T>*;
- using IteratorConstGetType = const blink::UntracedMember<T>*;
- using IteratorReferenceType = blink::UntracedMember<T>&;
- using IteratorConstReferenceType = const blink::UntracedMember<T>&;
- static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
- return *x;
- }
- static IteratorConstReferenceType GetToReferenceConstConversion(
- IteratorConstGetType x) {
- return *x;
- }
- using PeekOutType = T*;
-
- template <typename U>
- static void Store(const U& value, blink::UntracedMember<T>& storage) {
- storage = value;
- }
-
- static PeekOutType Peek(const blink::UntracedMember<T>& value) {
- return value;
- }
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct IsTraceable<
- ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> {
- STATIC_ONLY(IsTraceable);
- static_assert(sizeof(T), "T must be fully defined");
- // All heap allocated node pointers need visiting to keep the nodes alive,
- // regardless of whether they contain pointers to other heap allocated
- // objects.
- static const bool value = true;
-};
-
-template <typename T, wtf_size_t inlineCapacity>
-struct IsGarbageCollectedType<
- ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> {
- static const bool value = true;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetIterator<Set>> {
- static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> {
- static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> {
- static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename Set>
-struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> {
- static const bool value = IsGarbageCollectedType<Set>::value;
-};
-
-template <typename T, typename H>
-struct HandleHashTraits : SimpleClassHashTraits<H> {
- STATIC_ONLY(HandleHashTraits);
- // TODO: Implement proper const'ness for iterator types. Requires support
- // in the marking Visitor.
- using PeekInType = T*;
- using IteratorGetType = H*;
- using IteratorConstGetType = const H*;
- using IteratorReferenceType = H&;
- using IteratorConstReferenceType = const H&;
- static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
- return *x;
- }
- static IteratorConstReferenceType GetToReferenceConstConversion(
- IteratorConstGetType x) {
- return *x;
- }
-
- using PeekOutType = T*;
-
- template <typename U>
- static void Store(const U& value, H& storage) {
- storage = value;
- }
-
- static PeekOutType Peek(const H& value) { return value; }
-};
-
-template <typename Value,
- typename HashFunctions,
- typename Traits,
- typename VectorType>
-inline void CopyToVector(
- const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set,
- VectorType& vector) {
- CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits,
- blink::HeapAllocator>&>(set),
- vector);
-}
-
-} // namespace WTF
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.cc
new file mode 100644
index 00000000000..8f0efaad933
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.cc
@@ -0,0 +1,139 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h"
+
+namespace blink {
+
+namespace {
+
+struct BackingModifier {
+ bool can_modify;
+ BasePage* const page;
+ HeapObjectHeader* const header;
+};
+
+BackingModifier CanModifyBacking(ThreadState* const state, void* address) {
+ // - |SweepForbidden| protects against modifying objects from destructors.
+ // - |IsSweepingInProgress| protects against modifying objects while
+ // concurrent sweeping is in progress.
+ // - |in_atomic_pause| protects against modifying objects from within the GC.
+ // This can
+ // e.g. happen when hash table buckets that have containers inlined are
+ // freed during weakness processing.
+ // - |IsMarkingInProgress| protects against incremental marking which may have
+ // registered callbacks.
+ if (state->SweepForbidden() || state->IsSweepingInProgress() ||
+ state->in_atomic_pause() || state->IsMarkingInProgress())
+ return {false, nullptr, nullptr};
+
+ // - Don't adjust large objects because their page is never reused.
+ // - Don't free backings allocated on other threads.
+ BasePage* page = PageFromObject(address);
+ if (page->IsLargeObjectPage() || page->Arena()->GetThreadState() != state)
+ return {false, nullptr, nullptr};
+
+ HeapObjectHeader* const header = HeapObjectHeader::FromPayload(address);
+ // - Guards against pages that have not been swept. Technically, it should be
+ // fine to modify those backings. We bail out to maintain the invariant that
+ // no marked backing is modified.
+ if (header->IsMarked())
+ return {false, nullptr, nullptr};
+ return {true, page, header};
+}
+
+} // namespace
+
+void HeapAllocator::BackingFree(void* address) {
+ if (!address)
+ return;
+
+ ThreadState* const state = ThreadState::Current();
+ BackingModifier result = CanModifyBacking(state, address);
+ if (!result.can_modify)
+ return;
+
+ static_cast<NormalPage*>(result.page)
+ ->ArenaForNormalPage()
+ ->PromptlyFreeObject(result.header);
+}
+
+void HeapAllocator::FreeVectorBacking(void* address) {
+ BackingFree(address);
+}
+
+void HeapAllocator::FreeHashTableBacking(void* address) {
+ BackingFree(address);
+}
+
+bool HeapAllocator::BackingExpand(void* address, size_t new_size) {
+ if (!address)
+ return false;
+
+ ThreadState* state = ThreadState::Current();
+
+ BackingModifier result = CanModifyBacking(state, address);
+ if (!result.can_modify)
+ return false;
+ DCHECK(!state->in_atomic_pause());
+ DCHECK(state->IsAllocationAllowed());
+ DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
+
+ // FIXME: Support expand for large objects.
+ // Don't expand backings allocated on other threads.
+ BasePage* page = PageFromObject(address);
+ if (page->IsLargeObjectPage() || page->Arena()->GetThreadState() != state)
+ return false;
+
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(address);
+ NormalPageArena* arena = static_cast<NormalPage*>(page)->ArenaForNormalPage();
+ return arena->ExpandObject(header, new_size);
+}
+
+bool HeapAllocator::ExpandVectorBacking(void* address, size_t new_size) {
+ return BackingExpand(address, new_size);
+}
+
+bool HeapAllocator::ExpandHashTableBacking(void* address, size_t new_size) {
+ return BackingExpand(address, new_size);
+}
+
+bool HeapAllocator::BackingShrink(void* address,
+ size_t quantized_current_size,
+ size_t quantized_shrunk_size) {
+ if (!address || quantized_shrunk_size == quantized_current_size)
+ return true;
+
+ DCHECK_LT(quantized_shrunk_size, quantized_current_size);
+
+ ThreadState* const state = ThreadState::Current();
+ BackingModifier result = CanModifyBacking(state, address);
+ if (!result.can_modify)
+ return false;
+
+ DCHECK(state->IsAllocationAllowed());
+ DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
+
+ NormalPageArena* arena =
+ static_cast<NormalPage*>(result.page)->ArenaForNormalPage();
+ // We shrink the object only if the shrinking will make a non-small
+ // prompt-free block.
+ // FIXME: Optimize the threshold size.
+ if (quantized_current_size <= quantized_shrunk_size +
+ sizeof(HeapObjectHeader) +
+ sizeof(void*) * 32 &&
+ !arena->IsObjectAllocatedAtAllocationPoint(result.header))
+ return true;
+
+ arena->ShrinkObject(result.header, quantized_shrunk_size);
+ return true;
+}
+
+bool HeapAllocator::ShrinkVectorBacking(void* address,
+ size_t quantized_current_size,
+ size_t quantized_shrunk_size) {
+ return BackingShrink(address, quantized_current_size, quantized_shrunk_size);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h
new file mode 100644
index 00000000000..362dc4bdc2e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator_impl.h
@@ -0,0 +1,178 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_IMPL_H_
+
+#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
+#include "third_party/blink/renderer/platform/heap/impl/heap.h"
+#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+// This is a static-only class used as a trait on collections to make them heap
+// allocated.
+class PLATFORM_EXPORT HeapAllocator {
+ STATIC_ONLY(HeapAllocator);
+
+ public:
+ using LivenessBroker = blink::LivenessBroker;
+ using Visitor = blink::Visitor;
+ static constexpr bool kIsGarbageCollected = true;
+
+ // See wtf/size_t.h for details.
+ static constexpr size_t kMaxHeapObjectSizeLog2 = 27;
+ static constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
+
+ template <typename T>
+ static size_t MaxElementCountInBackingStore() {
+ return kMaxHeapObjectSize / sizeof(T);
+ }
+
+ template <typename T>
+ static size_t QuantizedSize(size_t count) {
+ CHECK_LE(count, MaxElementCountInBackingStore<T>());
+ // Oilpan's internal size is independent of MaxElementCountInBackingStore()
+ // and the required size to match capacity needs.
+ return count * sizeof(T);
+ }
+
+ template <typename T>
+ static T* AllocateVectorBacking(size_t size) {
+ return reinterpret_cast<T*>(
+ MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
+ }
+ static void FreeVectorBacking(void*);
+ static bool ExpandVectorBacking(void*, size_t);
+ static bool ShrinkVectorBacking(void* address,
+ size_t quantized_current_size,
+ size_t quantized_shrunk_size);
+
+ template <typename T, typename HashTable>
+ static T* AllocateHashTableBacking(size_t size) {
+ static_assert(sizeof(T) == sizeof(typename HashTable::ValueType),
+ "T must match ValueType.");
+ return reinterpret_cast<T*>(
+ MakeGarbageCollected<HeapHashTableBacking<HashTable>>(size /
+ sizeof(T)));
+ }
+ template <typename T, typename HashTable>
+ static T* AllocateZeroedHashTableBacking(size_t size) {
+ return AllocateHashTableBacking<T, HashTable>(size);
+ }
+ static void FreeHashTableBacking(void* address);
+ static bool ExpandHashTableBacking(void*, size_t);
+
+ template <typename Traits>
+ static bool CanReuseHashTableDeletedBucket() {
+ if (Traits::kEmptyValueIsZero || !Traits::kCanTraceConcurrently)
+ return true;
+ return !ThreadState::Current()->IsMarkingInProgress();
+ }
+
+ static bool IsAllocationAllowed() {
+ return ThreadState::Current()->IsAllocationAllowed();
+ }
+
+ static bool IsIncrementalMarking() {
+ return ThreadState::IsAnyIncrementalMarking() &&
+ ThreadState::Current()->IsIncrementalMarking();
+ }
+
+ static void EnterGCForbiddenScope() {
+ ThreadState::Current()->EnterGCForbiddenScope();
+ }
+
+ static void LeaveGCForbiddenScope() {
+ ThreadState::Current()->LeaveGCForbiddenScope();
+ }
+
+ template <typename T, typename Traits>
+ static void Trace(Visitor* visitor, const T& t) {
+ TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
+ Traits>::Trace(visitor, &t);
+ }
+
+ template <typename T>
+ static void TraceVectorBacking(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot) {
+ visitor->TraceMovablePointer(backing_slot);
+ visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
+ }
+
+ template <typename T, typename HashTable>
+ static void TraceHashTableBackingStrongly(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot) {
+ visitor->TraceMovablePointer(backing_slot);
+ visitor->Trace(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
+ }
+
+ template <typename T, typename HashTable>
+ static void TraceHashTableBackingWeakly(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot,
+ WeakCallback callback,
+ const void* parameter) {
+ visitor->TraceMovablePointer(backing_slot);
+ visitor->TraceWeakContainer(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
+ reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+ backing_slot),
+ TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor(
+ backing),
+ TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor(
+ backing),
+ callback, parameter);
+ }
+
+ template <typename T>
+ static void BackingWriteBarrier(T** slot) {
+ MarkingVisitor::WriteBarrier(reinterpret_cast<void**>(slot));
+ }
+
+ template <typename T>
+ static void TraceBackingStoreIfMarked(T** slot) {
+ MarkingVisitor::RetraceObject(*slot);
+ }
+
+ template <typename T, typename Traits>
+ static void NotifyNewObject(T* object) {
+ MarkingVisitor::WriteBarrier(
+ []() { return ThreadState::Current(); }, object, sizeof(T), 1,
+ TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+ }
+
+ template <typename T, typename Traits>
+ static void NotifyNewObjects(T* array, size_t len) {
+ MarkingVisitor::WriteBarrier(
+ []() { return ThreadState::Current(); }, array, sizeof(T), len,
+ TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+ }
+
+ static bool DeferTraceToMutatorThreadIfConcurrent(Visitor* visitor,
+ const void* object,
+ TraceCallback callback,
+ size_t deferred_size) {
+ return visitor->DeferredTraceIfConcurrent({object, callback},
+ deferred_size);
+ }
+
+ private:
+ static void BackingFree(void*);
+ static bool BackingExpand(void*, size_t);
+ static bool BackingShrink(void*,
+ size_t quantized_current_size,
+ size_t quantized_shrunk_size);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc
index 1949d5c9921..89698c61e97 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc
@@ -89,7 +89,6 @@ namespace blink {
void HeapObjectHeader::Finalize(Address object, size_t object_size) {
DCHECK(!IsInConstruction<HeapObjectHeader::AccessMode::kAtomic>());
- HeapAllocHooks::FreeHookIfEnabled(object);
const GCInfo& gc_info = GCInfo::From(GcInfoIndex());
if (gc_info.finalize)
gc_info.finalize(object);
@@ -149,6 +148,15 @@ void BaseArena::CollectStatistics(std::string name,
stats->arena_stats.emplace_back(std::move(arena_stats));
}
+size_t BaseArena::AllocatedBytes() {
+ DCHECK(unswept_pages_.IsEmpty());
+ size_t result = 0;
+ for (BasePage* page : swept_pages_) {
+ result += page->AllocatedBytes();
+ }
+ return result;
+}
+
void NormalPageArena::CollectFreeListStatistics(
ThreadState::Statistics::FreeListStatistics* stats) {
free_list_.CollectStatistics(stats);
@@ -673,13 +681,12 @@ void NormalPageArena::AllocatePage() {
// Take the first possible page ensuring that this thread actually
// gets a page and add the rest to the page pool.
if (!page_memory) {
- bool result = memory->Commit();
- // If you hit the CHECK, it will mean that you're hitting the limit
- // of the number of mmapped regions the OS can support
+ // If you hit the CHECK in the call to Commit(), it means that you're
+ // hitting the limit of the number of mmapped regions the OS can support
// (e.g., /proc/sys/vm/max_map_count in Linux) or on that Windows you
// have exceeded the max commit charge across all processes for the
// system.
- CHECK(result);
+ memory->Commit();
page_memory = memory;
} else {
GetThreadState()->Heap().GetFreePagePool()->Add(ArenaIndex(), memory);
@@ -762,20 +769,20 @@ void NormalPageArena::PromptlyFreeObjectInFreeList(HeapObjectHeader* header,
size_t size) {
DCHECK(!header->IsMarked());
Address address = reinterpret_cast<Address>(header);
- NormalPage* page = reinterpret_cast<NormalPage*>(PageFromObject(header));
- if (page->HasBeenSwept()) {
- Address payload = header->Payload();
- size_t payload_size = header->PayloadSize();
- // If the page has been swept a promptly freed object may be adjacent
- // to other free list entries. We make the object available for future
- // allocation right away by adding it to the free list and increase the
- // promptly_freed_size_ counter which may result in coalescing later.
- SET_MEMORY_INACCESSIBLE(payload, payload_size);
- CHECK_MEMORY_INACCESSIBLE(payload, payload_size);
- AddToFreeList(address, size);
- promptly_freed_size_ += size;
- }
+ NormalPage* page = static_cast<NormalPage*>(PageFromObject(header));
+ DCHECK(page->HasBeenSwept());
+ Address payload = header->Payload();
+ size_t payload_size = header->PayloadSize();
+ // If the page has been swept a promptly freed object may be adjacent
+ // to other free list entries. We make the object available for future
+ // allocation right away by adding it to the free list and increase the
+ // promptly_freed_size_ counter which may result in coalescing later.
+ SET_MEMORY_INACCESSIBLE(payload, payload_size);
+ CHECK_MEMORY_INACCESSIBLE(payload, payload_size);
+ AddToFreeList(address, size);
+ promptly_freed_size_ += size;
GetThreadState()->Heap().stats_collector()->DecreaseAllocatedObjectSize(size);
+ page->DecreaseAllocatedBytes(size);
}
bool NormalPageArena::ExpandObject(HeapObjectHeader* header, size_t new_size) {
@@ -882,9 +889,12 @@ void NormalPageArena::SetAllocationPoint(Address point, size_t size) {
#endif
// Free and clear the old linear allocation area.
if (HasCurrentAllocationArea()) {
- AddToFreeList(CurrentAllocationPoint(), RemainingAllocationSize());
+ size_t remaining_size = RemainingAllocationSize();
+ AddToFreeList(CurrentAllocationPoint(), remaining_size);
GetThreadState()->Heap().stats_collector()->DecreaseAllocatedObjectSize(
- RemainingAllocationSize());
+ remaining_size);
+ static_cast<NormalPage*>(PageFromObject(CurrentAllocationPoint()))
+ ->DecreaseAllocatedBytes(remaining_size);
}
// Set up a new linear allocation area.
current_allocation_point_ = point;
@@ -898,10 +908,11 @@ void NormalPageArena::SetAllocationPoint(Address point, size_t size) {
// actually set up with a non-null address.
GetThreadState()->Heap().stats_collector()->IncreaseAllocatedObjectSize(
size);
+ NormalPage* page = static_cast<NormalPage*>(PageFromObject(point));
+ page->IncreaseAllocatedBytes(size);
// Current allocation point can never be part of the object bitmap start
// because the area can grow or shrink. Will be added back before a GC when
// clearing the allocation point.
- NormalPage* page = reinterpret_cast<NormalPage*>(PageFromObject(point));
page->object_start_bit_map()
->ClearBit<HeapObjectHeader::AccessMode::kAtomic>(point);
// Mark page as containing young objects.
@@ -981,26 +992,25 @@ Address LargeObjectArena::AllocateLargeObjectPage(size_t allocation_size,
Address LargeObjectArena::DoAllocateLargeObjectPage(size_t allocation_size,
size_t gc_info_index) {
- size_t large_object_size =
- LargeObjectPage::PageHeaderSize() + allocation_size;
+ size_t large_page_size = LargeObjectPage::PageHeaderSize() + allocation_size;
// If ASan is supported we add allocationGranularity bytes to the allocated
// space and poison that to detect overflows
#if defined(ADDRESS_SANITIZER)
- large_object_size += kAllocationGranularity;
+ large_page_size += kAllocationGranularity;
#endif
PageMemory* page_memory = PageMemory::Allocate(
- large_object_size, GetThreadState()->Heap().GetRegionTree());
- Address large_object_address = page_memory->WritableStart();
+ large_page_size, GetThreadState()->Heap().GetRegionTree());
+ Address large_page_address = page_memory->WritableStart();
Address header_address =
- large_object_address + LargeObjectPage::PageHeaderSize();
+ large_page_address + LargeObjectPage::PageHeaderSize();
#if DCHECK_IS_ON()
// Verify that the allocated PageMemory is expectedly zeroed.
- for (size_t i = 0; i < large_object_size; ++i)
- DCHECK(!large_object_address[i]);
+ for (size_t i = 0; i < large_page_size; ++i)
+ DCHECK(!large_page_address[i]);
#endif
DCHECK_GT(gc_info_index, 0u);
- LargeObjectPage* large_object = new (large_object_address)
+ LargeObjectPage* large_page = new (large_page_address)
LargeObjectPage(page_memory, this, allocation_size);
HeapObjectHeader* header = new (NotNull, header_address)
HeapObjectHeader(kLargeObjectSizeInHeader, gc_info_index);
@@ -1009,30 +1019,31 @@ Address LargeObjectArena::DoAllocateLargeObjectPage(size_t allocation_size,
// Poison the object header and allocationGranularity bytes after the object
ASAN_POISON_MEMORY_REGION(header, sizeof(*header));
- ASAN_POISON_MEMORY_REGION(large_object->GetAddress() + large_object->size(),
+ ASAN_POISON_MEMORY_REGION(large_page->GetAddress() + large_page->size(),
kAllocationGranularity);
- swept_pages_.PushLocked(large_object);
+ swept_pages_.PushLocked(large_page);
// Update last allocated region in ThreadHeap.
- GetThreadState()->Heap().SetLastAllocatedRegion(large_object->Payload(),
- large_object->PayloadSize());
+ GetThreadState()->Heap().SetLastAllocatedRegion(large_page->Payload(),
+ large_page->PayloadSize());
// Add all segments of kBlinkPageSize to the bloom filter so that the large
// object can be kept by derived pointers on stack. An alternative might be to
// prohibit derived pointers to large objects, but that is dangerous since the
// compiler is free to optimize on-stack base pointers away.
- for (Address page_begin = RoundToBlinkPageStart(large_object->GetAddress());
- page_begin < large_object->PayloadEnd(); page_begin += kBlinkPageSize) {
+ for (Address page_begin = RoundToBlinkPageStart(large_page->GetAddress());
+ page_begin < large_page->PayloadEnd(); page_begin += kBlinkPageSize) {
GetThreadState()->Heap().page_bloom_filter()->Add(page_begin);
}
GetThreadState()->Heap().stats_collector()->IncreaseAllocatedSpace(
- large_object->size());
+ large_page->size());
GetThreadState()->Heap().stats_collector()->IncreaseAllocatedObjectSize(
- large_object->PayloadSize());
+ large_page->ObjectSize());
+ large_page->IncreaseAllocatedBytes(large_page->ObjectSize());
// Add page to the list of young pages.
- large_object->SetAsYoung(true);
- SynchronizedStore(large_object);
+ large_page->SetAsYoung(true);
+ SynchronizedStore(large_page);
return result;
}
@@ -1215,7 +1226,7 @@ FreeListEntry* FreeList::Allocate(size_t allocation_size) {
#if DCHECK_IS_ON() || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER) || \
defined(MEMORY_SANITIZER)
NO_SANITIZE_MEMORY
-void NOINLINE FreeList::GetAllowedAndForbiddenCounts(Address address,
+NOINLINE void FreeList::GetAllowedAndForbiddenCounts(Address address,
size_t size,
size_t& allowed_count,
size_t& forbidden_count) {
@@ -1231,7 +1242,7 @@ void NOINLINE FreeList::GetAllowedAndForbiddenCounts(Address address,
NO_SANITIZE_ADDRESS
NO_SANITIZE_MEMORY
-void NOINLINE FreeList::ZapFreedMemory(Address address, size_t size) {
+NOINLINE void FreeList::ZapFreedMemory(Address address, size_t size) {
for (size_t i = 0; i < size; i++) {
// See the comment in addToFreeList().
if (address[i] != kReuseAllowedZapValue)
@@ -1239,7 +1250,7 @@ void NOINLINE FreeList::ZapFreedMemory(Address address, size_t size) {
}
}
-void NOINLINE FreeList::CheckFreedMemoryIsZapped(Address address, size_t size) {
+NOINLINE void FreeList::CheckFreedMemoryIsZapped(Address address, size_t size) {
for (size_t i = 0; i < size; i++) {
DCHECK(address[i] == kReuseAllowedZapValue ||
address[i] == kReuseForbiddenZapValue);
@@ -1483,6 +1494,7 @@ bool NormalPage::Sweep(FinalizeType finalize_type) {
cached_freelist_.Clear();
unfinalized_freelist_.clear();
Address start_of_gap = Payload();
+ size_t live_bytes = 0;
bool found_finalizer = false;
for (Address header_address = start_of_gap; header_address < PayloadEnd();) {
HeapObjectHeader* header =
@@ -1528,9 +1540,11 @@ bool NormalPage::Sweep(FinalizeType finalize_type) {
#if !BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
header->Unmark<HeapObjectHeader::AccessMode::kAtomic>();
#endif
+ live_bytes += size;
header_address += size;
start_of_gap = header_address;
}
+ SetAllocatedBytes(live_bytes);
// Only add the memory to the free list if the page is not completely empty
// and we are not at the end of the page. Empty pages are not added to the
// free list as the pages are removed immediately.
@@ -1545,6 +1559,7 @@ void NormalPage::SweepAndCompact(CompactionContext& context) {
object_start_bit_map()->Clear();
NormalPage*& current_page = context.current_page_;
size_t& allocation_point = context.allocation_point_;
+ SetAllocatedBytes(0u);
NormalPageArena* page_arena = ArenaForNormalPage();
#if defined(ADDRESS_SANITIZER)
@@ -1632,6 +1647,7 @@ void NormalPage::SweepAndCompact(CompactionContext& context) {
compact->Relocate(payload, compact_frontier + sizeof(HeapObjectHeader));
}
current_page->object_start_bit_map()->SetBit(compact_frontier);
+ current_page->IncreaseAllocatedBytes(size);
header_address += size;
allocation_point += size;
DCHECK(allocation_point <= current_page->PayloadSize());
@@ -1653,6 +1669,7 @@ void NormalPage::MakeConsistentForMutator() {
object_start_bit_map()->Clear();
Address start_of_gap = Payload();
NormalPageArena* normal_arena = ArenaForNormalPage();
+ size_t live_bytes = 0;
for (Address header_address = Payload(); header_address < PayloadEnd();) {
HeapObjectHeader* header =
reinterpret_cast<HeapObjectHeader*>(header_address);
@@ -1676,10 +1693,12 @@ void NormalPage::MakeConsistentForMutator() {
header->Unmark();
}
object_start_bit_map()->SetBit(header_address);
+ live_bytes += size;
header_address += size;
start_of_gap = header_address;
DCHECK_LE(header_address, PayloadEnd());
}
+ SetAllocatedBytes(live_bytes);
if (start_of_gap != PayloadEnd())
normal_arena->AddToFreeList(start_of_gap, PayloadEnd() - start_of_gap);
@@ -1805,6 +1824,7 @@ void NormalPage::CollectStatistics(
}
}
}
+ DCHECK_EQ(live_size, AllocatedBytes());
arena_stats->committed_size_bytes += kBlinkPageSize;
arena_stats->used_size_bytes += live_size;
arena_stats->page_stats.emplace_back(
@@ -1842,11 +1862,13 @@ void LargeObjectPage::RemoveFromHeap() {
bool LargeObjectPage::Sweep(FinalizeType) {
if (!ObjectHeader()->IsMarked()) {
+ SetAllocatedBytes(0u);
return true;
}
#if !BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
ObjectHeader()->Unmark();
#endif
+ DCHECK_EQ(AllocatedBytes(), ObjectSize());
return false;
}
@@ -1860,6 +1882,7 @@ void LargeObjectPage::Unmark() {
void LargeObjectPage::MakeConsistentForMutator() {
Unmark();
+ DCHECK_EQ(AllocatedBytes(), ObjectSize());
}
void LargeObjectPage::FinalizeSweep(SweepResult action) {
@@ -1883,17 +1906,16 @@ void LargeObjectPage::PoisonUnmarkedObjects() {
void LargeObjectPage::CollectStatistics(
ThreadState::Statistics::ArenaStatistics* arena_stats) {
HeapObjectHeader* header = ObjectHeader();
- size_t live_size = 0;
// All non-free objects, dead or alive, are considered as live for the
// purpose of taking a snapshot.
- live_size += ObjectSize();
+ size_t live_size = ObjectSize();
if (!NameClient::HideInternalName()) {
// Detailed names available.
uint32_t gc_info_index = header->GcInfoIndex();
arena_stats->object_stats.type_count[gc_info_index]++;
- arena_stats->object_stats.type_bytes[gc_info_index] += ObjectSize();
+ arena_stats->object_stats.type_bytes[gc_info_index] += live_size;
}
-
+ DCHECK_EQ(live_size, AllocatedBytes());
arena_stats->committed_size_bytes += size();
arena_stats->used_size_bytes += live_size;
arena_stats->page_stats.emplace_back(
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h
index 1c26d4ffe20..74d6df9e387 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h
@@ -92,8 +92,6 @@ BlinkGuardPageSize() {
static_assert(8 == sizeof(double), "We expect sizeof(double) to be 8");
constexpr size_t kAllocationGranularity = sizeof(double);
constexpr size_t kAllocationMask = kAllocationGranularity - 1;
-constexpr size_t kMaxHeapObjectSizeLog2 = 27;
-constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
constexpr size_t kLargeObjectSizeThreshold = kBlinkPageSize / 2;
// A zap value used for freed memory that is allowed to be added to the free
@@ -505,6 +503,18 @@ class BasePage {
void SetAsYoung(bool young) { is_young_ = young; }
+ // The number of bytes that allocated on the page and are not freed yet.
+ size_t AllocatedBytes() { return allocated_bytes_; }
+
+ void SetAllocatedBytes(size_t bytes) { allocated_bytes_ = bytes; }
+
+ void IncreaseAllocatedBytes(size_t bytes) { allocated_bytes_ += bytes; }
+
+ void DecreaseAllocatedBytes(size_t bytes) {
+ DCHECK_GE(allocated_bytes_, bytes);
+ allocated_bytes_ -= bytes;
+ }
+
virtual void VerifyMarking() = 0;
private:
@@ -524,6 +534,11 @@ class BasePage {
BaseArena* const arena_;
ThreadState* const thread_state_;
+ // The counter is updated by the sweeper and the allocator.
+ // It is the sum of objects marked at the last GC and objects allocated on
+ // the page since the last GC.
+ size_t allocated_bytes_ = 0;
+
// Track the sweeping state of a page. Set to false at the start of a sweep,
// true upon completion of sweeping that page.
bool swept_ = true;
@@ -999,6 +1014,7 @@ class PLATFORM_EXPORT BaseArena {
void CollectStatistics(std::string, ThreadState::Statistics*);
virtual void CollectFreeListStatistics(
ThreadState::Statistics::FreeListStatistics*) {}
+ size_t AllocatedBytes();
#if DCHECK_IS_ON()
BasePage* FindPageFromAddress(ConstAddress) const;
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc
index 97590b912b2..bb4180facac 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc
@@ -123,6 +123,8 @@ void ThreadHeapStatsCollector::NotifyMarkingCompleted(size_t marked_bytes) {
ForAllObservers([marked_bytes](ThreadHeapStatsObserver* observer) {
observer->ResetAllocatedObjectSize(marked_bytes);
});
+
+ is_sweeping_ = true;
}
void ThreadHeapStatsCollector::NotifySweepingCompleted() {
@@ -139,6 +141,7 @@ void ThreadHeapStatsCollector::NotifySweepingCompleted() {
"Event should be trivially copyable");
previous_ = std::move(current_);
current_ = Event();
+ is_sweeping_ = false;
}
void ThreadHeapStatsCollector::UpdateReason(BlinkGC::GCReason reason) {
@@ -146,10 +149,11 @@ void ThreadHeapStatsCollector::UpdateReason(BlinkGC::GCReason reason) {
}
size_t ThreadHeapStatsCollector::object_size_in_bytes() const {
- DCHECK_GE(static_cast<int64_t>(previous().marked_bytes) +
- allocated_bytes_since_prev_gc_,
- 0);
- return static_cast<size_t>(static_cast<int64_t>(previous().marked_bytes) +
+ const Event& event = is_sweeping_ ? current_ : previous_;
+ DCHECK_GE(
+ static_cast<int64_t>(event.marked_bytes) + allocated_bytes_since_prev_gc_,
+ 0);
+ return static_cast<size_t>(static_cast<int64_t>(event.marked_bytes) +
allocated_bytes_since_prev_gc_);
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h
index cbac7c3b8ac..bdbed83b3f9 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h
@@ -384,6 +384,7 @@ class PLATFORM_EXPORT ThreadHeapStatsCollector {
size_t allocated_space_bytes_ = 0;
bool is_started_ = false;
+ bool is_sweeping_ = false;
// base::TimeDelta for RawScope. These don't need to be nested within a
// garbage collection cycle to make them easier to use.
diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.cc
index 3373e840c7c..3373e840c7c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.cc
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.h
new file mode 100644
index 00000000000..c376d67f539
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_test_utilities.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_
+
+#include "base/callback.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+
+namespace blink {
+
+class HeapPointersOnStackScope final {
+ STACK_ALLOCATED();
+
+ public:
+ explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) {
+ DCHECK(!state_->heap_pointers_on_stack_forced_);
+ state_->heap_pointers_on_stack_forced_ = true;
+ }
+ ~HeapPointersOnStackScope() {
+ DCHECK(state_->heap_pointers_on_stack_forced_);
+ state_->heap_pointers_on_stack_forced_ = false;
+ }
+
+ private:
+ ThreadState* const state_;
+};
+
+class TestSupportingGC : public testing::Test {
+ public:
+ // Performs a precise garbage collection with eager sweeping.
+ static void PreciselyCollectGarbage(
+ BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
+
+ // Performs a conservative garbage collection.
+ static void ConservativelyCollectGarbage(
+ BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
+
+ ~TestSupportingGC() override;
+
+ // Performs multiple rounds of garbage collections until no more memory can be
+ // freed. This is useful to avoid other garbage collections having to deal
+ // with stale memory.
+ void ClearOutOldGarbage();
+
+ // Completes sweeping if it is currently running.
+ void CompleteSweepingIfNeeded();
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+};
+
+template <typename T>
+class ObjectWithCallbackBeforeInitializer
+ : public GarbageCollected<ObjectWithCallbackBeforeInitializer<T>> {
+ public:
+ ObjectWithCallbackBeforeInitializer(
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb,
+ T* value)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
+
+ ObjectWithCallbackBeforeInitializer( // NOLINT
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
+
+ virtual void Trace(Visitor* visitor) const { visitor->Trace(value_); }
+
+ T* value() const { return value_.Get(); }
+
+ private:
+ static bool ExecuteCallbackReturnTrue(
+ ObjectWithCallbackBeforeInitializer* thiz,
+ base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb) {
+ std::move(cb).Run(thiz);
+ return true;
+ }
+
+ bool bool_;
+ Member<T> value_;
+};
+
+template <typename T>
+class MixinWithCallbackBeforeInitializer : public GarbageCollectedMixin {
+ public:
+ MixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb,
+ T* value)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
+
+ MixinWithCallbackBeforeInitializer( // NOLINT
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb)
+ : bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
+
+ void Trace(Visitor* visitor) const override { visitor->Trace(value_); }
+
+ T* value() const { return value_.Get(); }
+
+ private:
+ static bool ExecuteCallbackReturnTrue(
+ MixinWithCallbackBeforeInitializer* thiz,
+ base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb) {
+ std::move(cb).Run(thiz);
+ return true;
+ }
+
+ bool bool_;
+ Member<T> value_;
+};
+
+class BoolMixin {
+ protected:
+ bool bool_ = false;
+};
+
+template <typename T>
+class ObjectWithMixinWithCallbackBeforeInitializer
+ : public GarbageCollected<ObjectWithMixinWithCallbackBeforeInitializer<T>>,
+ public BoolMixin,
+ public MixinWithCallbackBeforeInitializer<T> {
+ public:
+ using Mixin = MixinWithCallbackBeforeInitializer<T>;
+
+ ObjectWithMixinWithCallbackBeforeInitializer(
+ base::OnceCallback<void(Mixin*)>&& cb,
+ T* value)
+ : Mixin(std::move(cb), value) {}
+
+ ObjectWithMixinWithCallbackBeforeInitializer( // NOLINT
+ base::OnceCallback<void(Mixin*)>&& cb)
+ : Mixin(std::move(cb)) {}
+
+ void Trace(Visitor* visitor) const override { Mixin::Trace(visitor); }
+};
+
+// Simple linked object to be used in tests.
+class LinkedObject : public GarbageCollected<LinkedObject> {
+ public:
+ LinkedObject() = default;
+ explicit LinkedObject(LinkedObject* next) : next_(next) {}
+
+ void set_next(LinkedObject* next) { next_ = next; }
+ LinkedObject* next() const { return next_; }
+ Member<LinkedObject>& next_ref() { return next_; }
+
+ virtual void Trace(Visitor* visitor) const { visitor->Trace(next_); }
+
+ private:
+ Member<LinkedObject> next_;
+};
+
+// Test driver for incremental marking. Assumes that no stack handling is
+// required.
+class IncrementalMarkingTestDriver {
+ public:
+ explicit IncrementalMarkingTestDriver(ThreadState* thread_state)
+ : thread_state_(thread_state) {}
+ ~IncrementalMarkingTestDriver();
+
+ void Start();
+ bool SingleStep(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack);
+ void FinishSteps(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack);
+ void FinishGC(bool complete_sweep = true);
+
+ // Methods for forcing a concurrent marking step without any assistance from
+ // mutator thread (i.e. without incremental marking on the mutator thread).
+ bool SingleConcurrentStep(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack);
+ void FinishConcurrentSteps(BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack);
+
+ size_t GetHeapCompactLastFixupCount() const;
+
+ private:
+ ThreadState* const thread_state_;
+};
+
+class IntegerObject : public GarbageCollected<IntegerObject> {
+ public:
+ static std::atomic_int destructor_calls;
+
+ explicit IntegerObject(int x) : x_(x) {}
+
+ virtual ~IntegerObject() {
+ destructor_calls.fetch_add(1, std::memory_order_relaxed);
+ }
+
+ virtual void Trace(Visitor* visitor) const {}
+
+ int Value() const { return x_; }
+
+ bool operator==(const IntegerObject& other) const {
+ return other.Value() == Value();
+ }
+
+ unsigned GetHash() { return IntHash<int>::GetHash(x_); }
+
+ private:
+ int x_;
+};
+
+struct IntegerObjectHash {
+ static unsigned GetHash(const IntegerObject& key) {
+ return WTF::HashInt(static_cast<uint32_t>(key.Value()));
+ }
+
+ static bool Equal(const IntegerObject& a, const IntegerObject& b) {
+ return a == b;
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h
deleted file mode 100644
index 36ac20e5710..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
-
-#include <type_traits>
-#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/type_traits.h"
-
-namespace blink {
-
-// Given a type T, returns a type that is either Member<T> or just T depending
-// on whether T is a garbage-collected type.
-template <typename T>
-using AddMemberIfNeeded =
- std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>;
-
-// Given a type T, returns a type that is either HeapVector<T>,
-// HeapVector<Member<T>> or Vector<T> depending on T.
-template <typename T>
-using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value,
- HeapVector<AddMemberIfNeeded<T>>,
- Vector<T>>;
-
-// Given types T and U, returns a type that is one of the following:
-// - HeapVector<std::pair<V, X>>
-// (where V is either T or Member<T> and X is either U or Member<U>)
-// - Vector<std::pair<T, U>>
-template <typename T, typename U>
-using VectorOfPairs = std::conditional_t<
- WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value,
- HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>,
- Vector<std::pair<T, U>>>;
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
index aca7b715e65..91300b48e29 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc
@@ -171,7 +171,7 @@ bool MarkingVisitor::MarkValue(void* value,
// static
bool MarkingVisitor::WriteBarrierSlow(void* value) {
- if (!value || IsHashTableDeleteValue(value))
+ if (!value || internal::IsHashTableDeleteValue(value))
return false;
// It is guaranteed that managed references point to either GarbageCollected
@@ -209,23 +209,31 @@ void MarkingVisitor::GenerationalBarrierSlow(Address slot,
}
}
-void MarkingVisitor::TraceMarkedBackingStoreSlow(const void* value) {
- if (!value)
+void MarkingVisitor::RetraceObjectSlow(const void* object) {
+ if (!object)
return;
+ // Trace object only if it is marked and thus has been traced before. The
+ // marker may be active on the backing store which requires atomic mark bit
+ // access.
+ if (!HeapObjectHeader::FromPayload(object)
+ ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) {
+ return;
+ }
+
ThreadState* const thread_state = ThreadState::Current();
if (!thread_state->IsIncrementalMarking())
return;
// |value| is pointing to the start of a backing store.
- HeapObjectHeader* header = HeapObjectHeader::FromPayload(value);
+ HeapObjectHeader* header = HeapObjectHeader::FromPayload(object);
CHECK(header->IsMarked());
DCHECK(thread_state->CurrentVisitor());
// No weak handling for write barriers. Modifying weakly reachable objects
// strongifies them for the current cycle.
GCInfo::From(header->GcInfoIndex())
- .trace(thread_state->CurrentVisitor(), value);
+ .trace(thread_state->CurrentVisitor(), object);
}
constexpr size_t MarkingVisitor::RecentlyRetracedWeakContainers::kMaxCacheSize;
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h
index df17247076f..afa594b2ec9 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h
@@ -8,20 +8,20 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
+#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
-namespace {
+namespace internal {
ALWAYS_INLINE bool IsHashTableDeleteValue(const void* value) {
return value == reinterpret_cast<void*>(-1);
}
-} // namespace
+} // namespace internal
class BasePage;
-class HeapAllocator;
enum class TracenessMemberConfiguration;
template <typename T, TracenessMemberConfiguration tracenessConfiguration>
class MemberBase;
@@ -142,14 +142,29 @@ ALWAYS_INLINE void MarkingVisitorBase::MarkHeader(HeapObjectHeader* header,
// thread.
class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase {
public:
- static void GenerationalBarrier(Address slot, ThreadState* state);
-
- // Eagerly traces an already marked backing store ensuring that all its
- // children are discovered by the marker. The barrier bails out if marking
- // is off and on individual objects reachable if they are already marked. The
- // barrier uses the callback function through GcInfo, so it will not inline
- // any templated type-specific code.
- static void TraceMarkedBackingStore(const void* value);
+ // Write barrier that adds a value the |slot| refers to to the set of marked
+ // objects. The barrier bails out if marking is off or the object is not yet
+ // marked. Returns true if the value has been marked on this call.
+ ALWAYS_INLINE static bool WriteBarrier(void** slot);
+
+ using ThreadStateCallback = ThreadState*();
+ // Write barrier where for a range of |number_of_elements| elements of size
+ // |element_size| starting at |first_element|. The |callback| will be invoked
+ // for each element if necessary.
+ ALWAYS_INLINE static void WriteBarrier(
+ ThreadStateCallback thread_state_callback,
+ void* first_element,
+ size_t element_size,
+ size_t number_of_elements,
+ TraceCallback callback);
+
+ // Eagerly traces an already marked |object| ensuring that all its children
+ // are discovered by the marker. The barrier bails out if marking is off and
+ // on individual objects reachable if they are already marked. The barrier
+ // uses the callback function through GcInfo.
+ //
+ // Note: |object| must point to the beginning of the heap object.
+ ALWAYS_INLINE static void RetraceObject(const void* object);
MarkingVisitor(ThreadState*, MarkingMode);
~MarkingVisitor() override = default;
@@ -162,17 +177,14 @@ class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase {
void FlushMarkingWorklists();
private:
- // Write barrier that adds a value the |slot| refers to to the set of marked
- // objects. The barrier bails out if marking is off or the object is not yet
- // marked. Returns true if the value has been marked on this call.
- template <typename T>
- static bool WriteBarrier(T** slot);
+ ALWAYS_INLINE static void GenerationalBarrier(Address slot,
+ ThreadState* state);
// Exact version of the marking and generational write barriers.
static bool WriteBarrierSlow(void*);
static void GenerationalBarrierSlow(Address, ThreadState*);
static bool MarkValue(void*, BasePage*, ThreadState*);
- static void TraceMarkedBackingStoreSlow(const void*);
+ static void RetraceObjectSlow(const void*);
// Weak containers are strongly retraced during conservative stack scanning.
// Stack scanning happens once per GC at the start of the atomic pause.
@@ -190,17 +202,15 @@ class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase {
size_t last_used_index_ = -1;
} recently_retraced_weak_containers_;
- friend class HeapAllocator;
template <typename T, TracenessMemberConfiguration tracenessConfiguration>
friend class MemberBase;
};
// static
-template <typename T>
-ALWAYS_INLINE bool MarkingVisitor::WriteBarrier(T** slot) {
+bool MarkingVisitor::WriteBarrier(void** slot) {
#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
void* value = *slot;
- if (!value || IsHashTableDeleteValue(value))
+ if (!value || internal::IsHashTableDeleteValue(value))
return false;
// Dijkstra barrier if concurrent marking is in progress.
@@ -223,8 +233,41 @@ ALWAYS_INLINE bool MarkingVisitor::WriteBarrier(T** slot) {
}
// static
-ALWAYS_INLINE void MarkingVisitor::GenerationalBarrier(Address slot,
- ThreadState* state) {
+void MarkingVisitor::WriteBarrier(ThreadStateCallback thread_state_callback,
+ void* first_element,
+ size_t element_size,
+ size_t number_of_elements,
+ TraceCallback callback) {
+#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION)
+ ThreadState* const thread_state = thread_state_callback();
+ if (!thread_state->IsIncrementalMarking()) {
+ MarkingVisitor::GenerationalBarrier(
+ reinterpret_cast<Address>(first_element), thread_state);
+ return;
+ }
+#else // !BLINK_HEAP_YOUNG_GENERATION
+ if (!ThreadState::IsAnyIncrementalMarking())
+ return;
+ // The object may have been in-place constructed as part of a large object.
+ // It is not safe to retrieve the page from the object here.
+ ThreadState* const thread_state = thread_state_callback();
+ if (!thread_state->IsIncrementalMarking()) {
+ return;
+ }
+#endif // !BLINK_HEAP_YOUNG_GENERATION
+ ThreadState::NoAllocationScope no_allocation_scope(thread_state);
+ DCHECK(thread_state->CurrentVisitor());
+ // No weak handling for write barriers. Modifying weakly reachable objects
+ // strongifies them for the current cycle.
+ char* array = static_cast<char*>(first_element);
+ while (number_of_elements-- > 0) {
+ callback(thread_state->CurrentVisitor(), array);
+ array += element_size;
+ }
+}
+
+// static
+void MarkingVisitor::GenerationalBarrier(Address slot, ThreadState* state) {
// First, check if the source object is in the last allocated region of heap.
if (LIKELY(state->Heap().IsInLastAllocatedRegion(slot)))
return;
@@ -234,13 +277,11 @@ ALWAYS_INLINE void MarkingVisitor::GenerationalBarrier(Address slot,
}
// static
-ALWAYS_INLINE void MarkingVisitor::TraceMarkedBackingStore(const void* value) {
+void MarkingVisitor::RetraceObject(const void* object) {
if (!ThreadState::IsAnyIncrementalMarking())
return;
- // Avoid any further checks and dispatch to a call at this point. Aggressive
- // inlining otherwise pollutes the regular execution paths.
- TraceMarkedBackingStoreSlow(value);
+ RetraceObjectSlow(object);
}
// Visitor used to mark Oilpan objects on concurrent threads.
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/member.h b/chromium/third_party/blink/renderer/platform/heap/impl/member.h
index caf60bf1b23..b3991eafa92 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/member.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/member.h
@@ -10,7 +10,9 @@
#include "third_party/blink/renderer/platform/heap/impl/heap_page.h"
#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+#include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
namespace WTF {
@@ -225,7 +227,8 @@ class MemberBase {
}
void WriteBarrier() const {
- MarkingVisitor::WriteBarrier(const_cast<std::remove_const_t<T>**>(&raw_));
+ MarkingVisitor::WriteBarrier(
+ reinterpret_cast<void**>(const_cast<std::remove_const_t<T>**>(&raw_)));
}
void CheckPointer() {
@@ -347,7 +350,7 @@ class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
// heap allocated objects.
// However instead of creating a strong pointer to the object, the WeakMember
// creates a weak pointer, which does not keep the pointee alive. Hence if all
-// pointers to to a heap allocated object are weak the object will be garbage
+// pointers to a heap allocated object are weak the object will be garbage
// collected. At the time of GC the weak pointers will automatically be set to
// null.
template <typename T>
@@ -482,56 +485,16 @@ struct TraceTrait<Member<T>> : public MemberTraceTraits<Member<T>> {};
template <typename T>
struct TraceTrait<WeakMember<T>> : public MemberTraceTraits<WeakMember<T>> {};
-} // namespace blink
-
-namespace WTF {
-
-// PtrHash is the default hash for hash tables with Member<>-derived elements.
-template <typename T>
-struct MemberHash : PtrHash<T> {
- STATIC_ONLY(MemberHash);
- template <typename U>
- static unsigned GetHash(const U& key) {
- return PtrHash<T>::GetHash(key);
- }
- template <typename U, typename V>
- static bool Equal(const U& a, const V& b) {
- return a == b;
- }
-};
-
-template <typename T>
-struct DefaultHash<blink::Member<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::WeakMember<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
template <typename T>
-struct DefaultHash<blink::UntracedMember<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
+inline bool IsHashTableDeletedValue(const Member<T>& m) {
+ return m.IsHashTableDeletedValue();
+}
-template <typename T>
-struct IsTraceable<blink::Member<T>> {
- STATIC_ONLY(IsTraceable);
- static const bool value = true;
-};
+constexpr auto kMemberDeletedValue = WTF::kHashTableDeletedValue;
-template <typename T>
-struct IsWeak<blink::WeakMember<T>> : std::true_type {};
+} // namespace blink
-template <typename T>
-struct IsTraceable<blink::WeakMember<T>> {
- STATIC_ONLY(IsTraceable);
- static const bool value = true;
-};
+namespace WTF {
template <typename T, typename Traits, typename Allocator>
class MemberConstructTraits {
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc
index 4d3ffc1440d..917fd030049 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc
@@ -16,15 +16,14 @@ void MemoryRegion::Release() {
base::FreePages(base_, size_);
}
-bool MemoryRegion::Commit() {
- CHECK(base::RecommitSystemPages(base_, size_, base::PageReadWrite));
- return base::TrySetSystemPagesAccess(base_, size_, base::PageReadWrite);
+void MemoryRegion::Commit() {
+ base::RecommitSystemPages(base_, size_, base::PageReadWrite,
+ base::PageUpdatePermissions);
}
void MemoryRegion::Decommit() {
ASAN_UNPOISON_MEMORY_REGION(base_, size_);
- base::DecommitSystemPages(base_, size_);
- base::SetSystemPagesAccess(base_, size_, base::PageInaccessible);
+ base::DecommitSystemPages(base_, size_, base::PageUpdatePermissions);
}
PageMemoryRegion::PageMemoryRegion(Address base,
@@ -130,7 +129,7 @@ PageMemory* PageMemory::Allocate(size_t payload_size, RegionTree* region_tree) {
PageMemoryRegion::AllocateLargePage(allocation_size, region_tree);
PageMemory* storage =
SetupPageMemoryInRegion(page_memory_region, 0, payload_size);
- CHECK(storage->Commit());
+ storage->Commit();
return storage;
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h
index ee13b210d59..79a2561e448 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h
@@ -33,7 +33,7 @@ class MemoryRegion {
}
void Release();
- WARN_UNUSED_RESULT bool Commit();
+ void Commit();
void Decommit();
Address Base() const { return base_; }
@@ -144,9 +144,9 @@ class PageMemory {
reserved_->PageDeleted(WritableStart());
}
- WARN_UNUSED_RESULT bool Commit() {
+ void Commit() {
reserved_->MarkPageUsed(WritableStart());
- return writable_.Commit();
+ writable_.Commit();
}
void Decommit() {
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc
index b3c31417cfb..69f0b523f71 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc
@@ -38,16 +38,13 @@ void PagePool::Add(int index, PageMemory* memory) {
}
PageMemory* PagePool::Take(int index) {
- while (PoolEntry* entry = pool_[index]) {
+ if (PoolEntry* entry = pool_[index]) {
pool_[index] = entry->next;
PageMemory* memory = entry->data;
DCHECK(memory);
delete entry;
- if (memory->Commit())
- return memory;
-
- // We got some memory, but failed to commit it, try again.
- delete memory;
+ memory->Commit();
+ return memory;
}
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h b/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h
index 00cff273e2f..f6b89028214 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h
@@ -39,19 +39,11 @@ class PersistentLocation final {
base::Location location_;
};
-#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \
- BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-#if !BUILDFLAG(ENABLE_LOCATION_SOURCE)
-#define PERSISTENT_FROM_HERE \
- PersistentLocation(::base::Location::CreateFromHere(__FILE__))
-#else
-#define PERSISTENT_FROM_HERE \
- PersistentLocation( \
- ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__))
-#endif
-#else
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#define PERSISTENT_FROM_HERE PersistentLocation(base::Location::Current())
+#else // !RAW_HEAP_SNAPSHOTS
#define PERSISTENT_FROM_HERE PersistentLocation()
-#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#endif // !RAW_HEAP_SNAPSHOTS
template <typename T,
WeaknessPersistentConfiguration weaknessConfiguration,
@@ -80,34 +72,11 @@ class PersistentBase {
return raw_;
}
- // TODO(https://crbug.com/653394): Consider returning a thread-safe best
- // guess of validity.
- bool MaybeValid() const { return true; }
-
explicit operator bool() const { return Get(); }
T& operator*() const { return *Get(); }
operator T*() const { return Get(); }
T* operator->() const { return Get(); }
- // Register the persistent node as a 'static reference',
- // belonging to the current thread and a persistent that must
- // be cleared when the ThreadState itself is cleared out and
- // destructed.
- //
- // Static singletons arrange for this to happen, either to ensure
- // clean LSan leak reports or to register a thread-local persistent
- // needing to be cleared out before the thread is terminated.
- PersistentBase* RegisterAsStaticReference() {
- static_assert(weaknessConfiguration == kNonWeakPersistentConfiguration,
- "Can only register non-weak Persistent references as static "
- "references.");
- if (PersistentNode* node = persistent_node_.Get()) {
- ThreadState::Current()->RegisterStaticPersistentNode(node);
- LEAK_SANITIZER_IGNORE_OBJECT(this);
- }
- return this;
- }
-
NO_SANITIZE_ADDRESS
void ClearWithLockHeld() {
static_assert(
@@ -251,7 +220,7 @@ class PersistentBase {
weaknessConfiguration,
crossThreadnessConfiguration>& other) {
PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired();
- AssignUnsafe(other);
+ AssignUnsafe(static_cast<T*>(other.Get()));
return *this;
}
@@ -583,9 +552,6 @@ class WeakPersistent
Parent::operator=(other);
return *this;
}
-
- NO_SANITIZE_ADDRESS
- bool IsClearedUnsafe() const { return this->IsNotNull(); }
};
// CrossThreadPersistent allows for holding onto an object strongly on a
@@ -808,17 +774,6 @@ Persistent<T> WrapPersistentInternal(T* value) {
#define WrapPersistent(value) WrapPersistentInternal(value)
#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-template <typename T,
- typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>>
-Persistent<T> WrapPersistentIfNeeded(T* value) {
- return Persistent<T>(value);
-}
-
-template <typename T>
-T& WrapPersistentIfNeeded(T& value) {
- return value;
-}
-
template <typename T>
WeakPersistent<T> WrapWeakPersistent(T* value) {
return WeakPersistent<T>(value);
@@ -884,88 +839,26 @@ inline bool operator!=(const Persistent<T>& a, const Member<U>& b) {
return a.Get() != b.Get();
}
-} // namespace blink
-
-namespace WTF {
-
-template <
- typename T,
- blink::WeaknessPersistentConfiguration weaknessConfiguration,
- blink::CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
-struct VectorTraits<blink::PersistentBase<T,
- weaknessConfiguration,
- crossThreadnessConfiguration>>
- : VectorTraitsBase<blink::PersistentBase<T,
- weaknessConfiguration,
- crossThreadnessConfiguration>> {
- STATIC_ONLY(VectorTraits);
- static const bool kNeedsDestruction = true;
- static const bool kCanInitializeWithMemset = true;
- static const bool kCanClearUnusedSlotsWithMemset = false;
- static const bool kCanMoveWithMemcpy = true;
-};
-
-template <typename T>
-struct HashTraits<blink::Persistent<T>>
- : HandleHashTraits<T, blink::Persistent<T>> {};
-
-template <typename T>
-struct HashTraits<blink::CrossThreadPersistent<T>>
- : HandleHashTraits<T, blink::CrossThreadPersistent<T>> {};
-
-template <typename T>
-struct DefaultHash<blink::Persistent<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::WeakPersistent<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::CrossThreadPersistent<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct DefaultHash<blink::CrossThreadWeakPersistent<T>> {
- STATIC_ONLY(DefaultHash);
- using Hash = MemberHash<T>;
-};
-
-template <typename T>
-struct CrossThreadCopier<blink::CrossThreadPersistent<T>>
- : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> {
- STATIC_ONLY(CrossThreadCopier);
-};
-
-template <typename T>
-struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>>
- : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> {
- STATIC_ONLY(CrossThreadCopier);
-};
-
-} // namespace WTF
+template <typename U, typename T>
+Persistent<U> DownCast(const Persistent<T>& p) {
+ return Persistent<U>(p);
+}
-namespace base {
+template <typename U, typename T>
+WeakPersistent<U> DownCast(const WeakPersistent<T>& p) {
+ return WeakPersistent<U>(p);
+}
-template <typename T>
-struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {};
+template <typename U, typename T>
+CrossThreadPersistent<U> DownCast(const CrossThreadPersistent<T>& p) {
+ return CrossThreadPersistent<U>(p);
+}
-template <typename T>
-struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {};
+template <typename U, typename T>
+CrossThreadWeakPersistent<U> DownCast(const CrossThreadWeakPersistent<T>& p) {
+ return CrossThreadWeakPersistent<U>(p);
+}
-template <typename T>
-struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> {
- static blink::CrossThreadPersistent<T> Unwrap(
- const blink::CrossThreadWeakPersistent<T>& wrapped) {
- return blink::CrossThreadPersistent<T>(wrapped);
- }
-};
-} // namespace base
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h
index d8c2b08471e..2ddf9ec6129 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h
@@ -341,7 +341,7 @@ void PersistentNodePtr<affinity, weakness_configuration>::Uninitialize() {
weakness_configuration == kWeakPersistentConfiguration
? state->GetWeakPersistentRegion()
: state->GetPersistentRegion();
- state->FreePersistentNode(region, ptr_);
+ region->FreeNode(ptr_);
ptr_ = nullptr;
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc
index 038a7385aad..dd66fe252ce 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc
@@ -13,20 +13,6 @@
namespace blink {
-namespace {
-
-void BlinkGCAllocHook(uint8_t* address, size_t size, const char* context) {
- base::PoissonAllocationSampler::RecordAlloc(
- address, size, base::PoissonAllocationSampler::AllocatorType::kBlinkGC,
- context);
-}
-
-void BlinkGCFreeHook(uint8_t* address) {
- base::PoissonAllocationSampler::RecordFree(address);
-}
-
-} // namespace
-
void ProcessHeap::Init() {
DCHECK(!base::FeatureList::IsEnabled(
blink::features::kBlinkHeapConcurrentMarking) ||
@@ -37,11 +23,6 @@ void ProcessHeap::Init() {
total_allocated_object_size_ = 0;
GCInfoTable::CreateGlobalTable();
-
- base::PoissonAllocationSampler::SetHooksInstallCallback([]() {
- HeapAllocHooks::SetAllocationHook(&BlinkGCAllocHook);
- HeapAllocHooks::SetFreeHook(&BlinkGCFreeHook);
- });
}
void ProcessHeap::ResetHeapCounters() {
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc
index 228902f91f7..b3e547e9a3c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc
@@ -101,8 +101,6 @@ namespace {
constexpr double kMarkingScheduleRatioBeforeConcurrentPriorityIncrease = 0.5;
-constexpr size_t kMaxTerminationGCLoops = 20;
-
// Helper function to convert a byte count to a KB count, capping at
// INT_MAX if the number is larger than that.
constexpr base::Histogram::Sample CappedSizeInKB(size_t size_in_bytes) {
@@ -233,6 +231,10 @@ void ThreadState::AttachToIsolate(
}
void ThreadState::DetachFromIsolate() {
+ FinishIncrementalMarkingIfRunning(
+ BlinkGC::CollectionType::kMajor, BlinkGC::kHeapPointersOnStack,
+ BlinkGC::kAtomicMarking, BlinkGC::kEagerSweeping,
+ BlinkGC::GCReason::kThreadTerminationGC);
if (isolate_) {
isolate_->SetEmbedderHeapTracer(nullptr);
if (v8::HeapProfiler* profiler = isolate_->GetHeapProfiler()) {
@@ -254,54 +256,30 @@ void ThreadState::RunTerminationGC() {
BlinkGC::kIncrementalAndConcurrentMarking,
BlinkGC::kConcurrentAndLazySweeping,
BlinkGC::GCReason::kThreadTerminationGC);
-
// Finish sweeping.
CompleteSweep();
- ReleaseStaticPersistentNodes();
-
- // PrepareForThreadStateTermination removes strong references so no need to
- // call it on CrossThreadWeakPersistentRegion.
- ProcessHeap::GetCrossThreadPersistentRegion()
- .PrepareForThreadStateTermination(this);
-
- // Do thread local GC's as long as the count of thread local Persistents
- // changes and is above zero.
- int old_count = -1;
- int current_count = GetPersistentRegion()->NodesInUse();
- DCHECK_GE(current_count, 0);
- while (current_count != old_count) {
+ // The constant specifies how many rounds of GCs should at most be needed to
+ // clean up the heap. If we crash below this means that there's finalizers
+ // adding more objects and roots than the GC is able to clean up.
+ constexpr size_t kMaxTerminationGCsForHeapCleanup = 20;
+ size_t i = 0;
+ do {
+ CHECK_LT(i++, kMaxTerminationGCsForHeapCleanup);
+ // Remove strong cross-thread roots.
+ ProcessHeap::GetCrossThreadPersistentRegion()
+ .PrepareForThreadStateTermination(this);
+ // Remove regular roots.
+ GetPersistentRegion()->PrepareForThreadStateTermination(this);
+ CHECK_EQ(0, GetPersistentRegion()->NodesInUse());
CollectGarbage(BlinkGC::CollectionType::kMajor,
BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
BlinkGC::kEagerSweeping,
BlinkGC::GCReason::kThreadTerminationGC);
- // Release the thread-local static persistents that were
- // instantiated while running the termination GC.
- ReleaseStaticPersistentNodes();
- old_count = current_count;
- current_count = GetPersistentRegion()->NodesInUse();
- }
-
- // We should not have any persistents left when getting to this point,
- // if we have it is a bug, and we have a reference cycle or a missing
- // RegisterAsStaticReference. Clearing out all the Persistents will avoid
- // stale pointers and gets them reported as nullptr dereferences.
- if (current_count) {
- for (size_t i = 0;
- i < kMaxTerminationGCLoops && GetPersistentRegion()->NodesInUse();
- i++) {
- GetPersistentRegion()->PrepareForThreadStateTermination(this);
- CollectGarbage(BlinkGC::CollectionType::kMajor,
- BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
- BlinkGC::kEagerSweeping,
- BlinkGC::GCReason::kThreadTerminationGC);
- }
- }
-
- CHECK(!GetPersistentRegion()->NodesInUse());
+ } while (GetPersistentRegion()->NodesInUse() != 0);
// All of pre-finalizers should be consumed.
- DCHECK(ordered_pre_finalizers_.empty());
+ CHECK(ordered_pre_finalizers_.empty());
CHECK_EQ(GetGCState(), kNoGCScheduled);
Heap().RemoveAllPages();
@@ -461,6 +439,16 @@ void ThreadState::PerformIdleLazySweep(base::TimeTicks deadline) {
if (SweepForbidden())
return;
+ if (!AdvanceLazySweep(deadline)) {
+ ScheduleIdleLazySweep();
+ }
+}
+
+bool ThreadState::AdvanceLazySweep(base::TimeTicks deadline) {
+ DCHECK(CheckThread());
+ DCHECK(IsSweepingInProgress());
+ DCHECK(!SweepForbidden());
+
RUNTIME_CALL_TIMER_SCOPE_IF_ISOLATE_EXISTS(
GetIsolate(), RuntimeCallStats::CounterId::kPerformIdleLazySweep);
@@ -477,14 +465,13 @@ void ThreadState::PerformIdleLazySweep(base::TimeTicks deadline) {
// We request another idle task for the remaining sweeping.
if (sweep_completed) {
SynchronizeAndFinishConcurrentSweeping();
- } else {
- ScheduleIdleLazySweep();
}
}
if (sweep_completed) {
NotifySweepDone();
}
+ return sweep_completed;
}
void ThreadState::PerformConcurrentSweep(base::JobDelegate* job) {
@@ -780,15 +767,6 @@ void ThreadState::SynchronizeAndFinishConcurrentSweeping() {
Heap().InvokeFinalizersOnSweptPages();
}
-BlinkGCObserver::BlinkGCObserver(ThreadState* thread_state)
- : thread_state_(thread_state) {
- thread_state_->AddObserver(this);
-}
-
-BlinkGCObserver::~BlinkGCObserver() {
- thread_state_->RemoveObserver(this);
-}
-
namespace {
// Update trace counters with statistics from the current and previous garbage
@@ -940,17 +918,14 @@ void ThreadState::NotifySweepDone() {
if (!in_atomic_pause()) {
PostSweep();
}
+
+ ThreadState::StatisticsCollector(this).Verify();
}
void ThreadState::PostSweep() {
DCHECK(!in_atomic_pause());
DCHECK(!IsSweepingInProgress());
- gc_age_++;
-
- for (auto* const observer : observers_)
- observer->OnCompleteSweepDone();
-
Heap().stats_collector()->NotifySweepingCompleted();
if (IsMainThread())
@@ -985,56 +960,6 @@ void ThreadState::PushRegistersAndVisitStack() {
VisitUnsafeStack(static_cast<MarkingVisitor*>(CurrentVisitor()));
}
-void ThreadState::AddObserver(BlinkGCObserver* observer) {
- DCHECK(observer);
- DCHECK(!observers_.Contains(observer));
- observers_.insert(observer);
-}
-
-void ThreadState::RemoveObserver(BlinkGCObserver* observer) {
- DCHECK(observer);
- DCHECK(observers_.Contains(observer));
- observers_.erase(observer);
-}
-
-void ThreadState::EnterStaticReferenceRegistrationDisabledScope() {
- static_persistent_registration_disabled_count_++;
-}
-
-void ThreadState::LeaveStaticReferenceRegistrationDisabledScope() {
- DCHECK(static_persistent_registration_disabled_count_);
- static_persistent_registration_disabled_count_--;
-}
-
-void ThreadState::RegisterStaticPersistentNode(PersistentNode* node) {
- if (static_persistent_registration_disabled_count_)
- return;
-
- DCHECK(!static_persistents_.Contains(node));
- static_persistents_.insert(node);
-}
-
-void ThreadState::ReleaseStaticPersistentNodes() {
- HashSet<PersistentNode*> static_persistents;
- static_persistents.swap(static_persistents_);
-
- PersistentRegion* persistent_region = GetPersistentRegion();
- for (PersistentNode* it : static_persistents)
- persistent_region->ReleaseNode(it);
-}
-
-void ThreadState::FreePersistentNode(PersistentRegion* persistent_region,
- PersistentNode* persistent_node) {
- persistent_region->FreeNode(persistent_node);
- // Do not allow static persistents to be freed before
- // they're all released in releaseStaticPersistentNodes().
- //
- // There's no fundamental reason why this couldn't be supported,
- // but no known use for it.
- if (persistent_region == GetPersistentRegion())
- DCHECK(!static_persistents_.Contains(persistent_node));
-}
-
void ThreadState::InvokePreFinalizers() {
DCHECK(CheckThread());
DCHECK(!SweepForbidden());
@@ -1214,7 +1139,7 @@ bool ThreadState::ConcurrentMarkingStep() {
}
return false;
}
- return marker_handle_.IsCompleted();
+ return !marker_handle_.IsActive();
}
void ThreadState::IncrementalMarkingFinalize() {
@@ -1531,6 +1456,8 @@ void ThreadState::MarkPhasePrologue(BlinkGC::CollectionType collection_type,
BlinkGC::GCReason reason) {
SetGCPhase(GCPhase::kMarking);
+ ThreadState::StatisticsCollector(this).Verify();
+
const bool compaction_enabled =
Heap().Compaction()->ShouldCompact(stack_state, marking_type, reason);
@@ -1751,4 +1678,42 @@ void ThreadState::PerformConcurrentMark(base::JobDelegate* job) {
concurrent_visitor->FlushWorklists();
}
+void ThreadState::NotifyGarbageCollection(v8::GCType type,
+ v8::GCCallbackFlags flags) {
+ if (!IsGCForbidden() && (flags & v8::kGCCallbackFlagForced)) {
+ // Forces a precise GC at the end of the current event loop. This is
+ // required for testing code that cannot use GC internals but rather has
+ // to rely on window.gc(). Only schedule additional GCs if the last GC was
+ // using conservative stack scanning.
+ if (type == v8::kGCTypeScavenge || RequiresForcedGCForTesting()) {
+ ScheduleForcedGCForTesting();
+ }
+ }
+}
+
+void ThreadState::CollectNodeAndCssStatistics(
+ base::OnceCallback<void(size_t allocated_node_bytes,
+ size_t allocated_css_bytes)> callback) {
+ if (IsSweepingInProgress()) {
+ // Help the sweeper to make progress using short-running delayed tasks.
+ // We use delayed tasks to give background threads a chance to sweep
+ // most of the heap.
+ const base::TimeDelta kStepSizeMs = base::TimeDelta::FromMilliseconds(5);
+ const base::TimeDelta kTaskDelayMs = base::TimeDelta::FromMilliseconds(10);
+ if (!AdvanceLazySweep(base::TimeTicks::Now() + kStepSizeMs)) {
+ ThreadScheduler::Current()->V8TaskRunner()->PostDelayedTask(
+ FROM_HERE,
+ WTF::Bind(&ThreadState::CollectNodeAndCssStatistics,
+ WTF::Unretained(this), std::move(callback)),
+ kTaskDelayMs);
+ return;
+ }
+ }
+ size_t allocated_node_bytes =
+ Heap().Arena(BlinkGC::kNodeArenaIndex)->AllocatedBytes();
+ size_t allocated_css_bytes =
+ Heap().Arena(BlinkGC::kCSSValueArenaIndex)->AllocatedBytes();
+ std::move(callback).Run(allocated_node_bytes, allocated_css_bytes);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h
index ee318bd64bf..6b6dc6b401f 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h
@@ -51,6 +51,7 @@
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "v8/include/v8.h"
namespace v8 {
class EmbedderGraph;
@@ -65,7 +66,6 @@ class IncrementalMarkingScope;
class MarkingVisitor;
class MarkingSchedulingOracle;
-class PersistentNode;
class PersistentRegion;
class ThreadHeap;
class ThreadState;
@@ -108,26 +108,6 @@ class Visitor;
ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_{this}; \
using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
-class PLATFORM_EXPORT BlinkGCObserver {
- USING_FAST_MALLOC(BlinkGCObserver);
-
- public:
- // The constructor automatically register this object to ThreadState's
- // observer lists. The argument must not be null.
- explicit BlinkGCObserver(ThreadState*);
-
- // The destructor automatically unregister this object from ThreadState's
- // observer lists.
- virtual ~BlinkGCObserver();
-
- virtual void OnCompleteSweepDone() = 0;
-
- private:
- // As a ThreadState must live when a BlinkGCObserver lives, holding a raw
- // pointer is safe.
- ThreadState* thread_state_;
-};
-
class PLATFORM_EXPORT ThreadState final {
USING_FAST_MALLOC(ThreadState);
@@ -192,7 +172,6 @@ class PLATFORM_EXPORT ThreadState final {
class StatisticsCollector;
struct Statistics;
class SweepForbiddenScope;
- class HeapPointersOnStackScope;
using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
v8::EmbedderGraph*,
@@ -347,10 +326,6 @@ class PLATFORM_EXPORT ThreadState final {
return weak_persistent_region_.get();
}
- void RegisterStaticPersistentNode(PersistentNode*);
- void ReleaseStaticPersistentNodes();
- void FreePersistentNode(PersistentRegion*, PersistentNode*);
-
v8::Isolate* GetIsolate() const { return isolate_; }
// Returns |true| if |object| resides on this thread's heap.
@@ -368,8 +343,6 @@ class PLATFORM_EXPORT ThreadState final {
WTF::GetCurrentStackPosition())));
}
- int GcAge() const { return gc_age_; }
-
MarkingVisitor* CurrentVisitor() const {
return current_gc_data_.visitor.get();
}
@@ -417,6 +390,14 @@ class PLATFORM_EXPORT ThreadState final {
--disable_heap_verification_scope_;
}
+ void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
+
+ // Waits until sweeping is done and invokes the given callback with
+ // the total sizes of live objects in Node and CSS arenas.
+ void CollectNodeAndCssStatistics(
+ base::OnceCallback<void(size_t allocated_node_bytes,
+ size_t allocated_css_bytes)>);
+
private:
class IncrementalMarkingScheduler;
@@ -466,9 +447,6 @@ class PLATFORM_EXPORT ThreadState final {
gc_forbidden_count_--;
}
- void EnterStaticReferenceRegistrationDisabledScope();
- void LeaveStaticReferenceRegistrationDisabledScope();
-
// Performs stand-alone garbage collections considering only C++ objects.
//
// Use the public *ForTesting calls for calling GC in tests.
@@ -561,6 +539,8 @@ class PLATFORM_EXPORT ThreadState final {
// Schedule helpers.
void ScheduleIdleLazySweep();
void ScheduleConcurrentAndLazySweep();
+ // Advances sweeping and returns true if sweeping is complete.
+ bool AdvanceLazySweep(base::TimeTicks deadline);
void NotifySweepDone();
void PostSweep();
@@ -574,16 +554,6 @@ class PLATFORM_EXPORT ThreadState final {
void InvokePreFinalizers();
- // Adds the given observer to the ThreadState's observer list. This doesn't
- // take ownership of the argument. The argument must not be null. The argument
- // must not be registered before calling this.
- void AddObserver(BlinkGCObserver*);
-
- // Removes the given observer from the ThreadState's observer list. This
- // doesn't take ownership of the argument. The argument must not be null.
- // The argument must be registered before calling this.
- void RemoveObserver(BlinkGCObserver*);
-
bool IsForcedGC() const { return IsForcedGC(current_gc_data_.reason); }
// Returns whether stack scanning is forced. This is currently only used in
@@ -619,7 +589,6 @@ class PLATFORM_EXPORT ThreadState final {
bool forced_scheduled_gc_for_testing_ = false;
size_t no_allocation_count_ = 0;
size_t gc_forbidden_count_ = 0;
- size_t static_persistent_registration_disabled_count_ = 0;
GCState gc_state_ = GCState::kNoGCScheduled;
GCPhase gc_phase_ = GCPhase::kNone;
@@ -642,16 +611,6 @@ class PLATFORM_EXPORT ThreadState final {
void* asan_fake_stack_;
#endif
- HashSet<BlinkGCObserver*> observers_;
-
- // PersistentNodes that are stored in static references;
- // references that either have to be cleared upon the thread
- // detaching from Oilpan and shutting down or references we
- // have to clear before initiating LSan's leak detection.
- HashSet<PersistentNode*> static_persistents_;
-
- int gc_age_ = 0;
-
struct GCData {
BlinkGC::CollectionType collection_type;
BlinkGC::StackState stack_state;
@@ -677,8 +636,8 @@ class PLATFORM_EXPORT ThreadState final {
base::TimeTicks last_concurrently_marked_bytes_update_;
bool concurrent_marking_priority_increased_ = false;
- friend class BlinkGCObserver;
friend class incremental_marking_test::IncrementalMarkingScope;
+ friend class HeapPointersOnStackScope;
friend class IncrementalMarkingTestDriver;
friend class HeapAllocator;
template <typename T>
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h
index 07e22c95cae..57a4748b06b 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h
@@ -77,52 +77,6 @@ class ThreadState::AtomicPauseScope final {
GCForbiddenScope gc_forbidden_scope;
};
-class ThreadState::HeapPointersOnStackScope final {
- STACK_ALLOCATED();
-
- public:
- explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) {
- DCHECK(!state_->heap_pointers_on_stack_forced_);
- state_->heap_pointers_on_stack_forced_ = true;
- }
- ~HeapPointersOnStackScope() {
- DCHECK(state_->heap_pointers_on_stack_forced_);
- state_->heap_pointers_on_stack_forced_ = false;
- }
-
- private:
- ThreadState* const state_;
-};
-
-#if defined(LEAK_SANITIZER)
-class ThreadState::LsanDisabledScope final {
- STACK_ALLOCATED();
- DISALLOW_COPY_AND_ASSIGN(LsanDisabledScope);
-
- public:
- explicit LsanDisabledScope(ThreadState* thread_state)
- : thread_state_(thread_state) {
- __lsan_disable();
- if (thread_state_)
- thread_state_->EnterStaticReferenceRegistrationDisabledScope();
- }
-
- ~LsanDisabledScope() {
- __lsan_enable();
- if (thread_state_)
- thread_state_->LeaveStaticReferenceRegistrationDisabledScope();
- }
-
- private:
- ThreadState* const thread_state_;
-};
-
-#define LEAK_SANITIZER_DISABLED_SCOPE \
- ThreadState::LsanDisabledScope lsan_disabled_scope(ThreadState::Current())
-#else
-#define LEAK_SANITIZER_DISABLED_SCOPE
-#endif
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
index d845f85de2e..f561bc3b3fb 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc
@@ -29,4 +29,11 @@ ThreadState::Statistics ThreadState::StatisticsCollector::CollectStatistics(
return stats;
}
+void ThreadState::StatisticsCollector::Verify() const {
+#if BUILDFLAG(BLINK_HEAP_VERIFICATION) && DCHECK_IS_ON()
+ // CollectStatistics checks counter consistency with DCHECKs.
+ CollectStatistics(Statistics::kDetailed);
+#endif // BUILDFLAG(BLINK_HEAP_VERIFICATION) && DCHECK_IS_ON()
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
index 9eb1efa6d87..e68d12f294e 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h
@@ -57,6 +57,7 @@ class PLATFORM_EXPORT ThreadState::StatisticsCollector {
: thread_state_(thread_state) {}
ThreadState::Statistics CollectStatistics(Statistics::DetailLevel) const;
+ void Verify() const;
private:
ThreadState* const thread_state_;
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h
index 668da565219..375fc48b3b8 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h
@@ -22,14 +22,8 @@
namespace blink {
-template <typename Table>
-class HeapHashTableBacking;
-template <typename ValueArg, wtf_size_t inlineCapacity>
-class HeapListHashSetAllocator;
template <typename T>
struct TraceTrait;
-template <typename T>
-class WeakMember;
template <typename T, bool = NeedsAdjustPointer<T>::value>
struct AdjustPointerTrait;
@@ -77,67 +71,6 @@ struct TraceIfNeeded<T, true> {
static void Trace(Visitor* visitor, const T& t) { visitor->Trace(t); }
};
-template <WTF::WeakHandlingFlag weakness,
- typename T,
- typename Traits,
- bool = WTF::IsTraceableInCollectionTrait<Traits>::value,
- WTF::WeakHandlingFlag = WTF::WeakHandlingTrait<T>::value>
-struct TraceCollectionIfEnabled;
-
-template <WTF::WeakHandlingFlag weakness, typename T, typename Traits>
-struct TraceCollectionIfEnabled<weakness,
- T,
- Traits,
- false,
- WTF::kNoWeakHandling> {
- STATIC_ONLY(TraceCollectionIfEnabled);
-
- static bool IsAlive(const blink::LivenessBroker& info, const T&) {
- return true;
- }
-
- static void Trace(Visitor*, const void*) {
- static_assert(!WTF::IsTraceableInCollectionTrait<Traits>::value,
- "T should not be traced");
- }
-};
-
-template <typename T, typename Traits>
-struct TraceCollectionIfEnabled<WTF::kNoWeakHandling,
- T,
- Traits,
- false,
- WTF::kWeakHandling> {
- STATIC_ONLY(TraceCollectionIfEnabled);
-
- static void Trace(Visitor* visitor, const void* t) {
- WTF::TraceInCollectionTrait<WTF::kNoWeakHandling, T, Traits>::Trace(
- visitor, *reinterpret_cast<const T*>(t));
- }
-};
-
-template <WTF::WeakHandlingFlag weakness,
- typename T,
- typename Traits,
- bool,
- WTF::WeakHandlingFlag>
-struct TraceCollectionIfEnabled {
- STATIC_ONLY(TraceCollectionIfEnabled);
-
- static bool IsAlive(const blink::LivenessBroker& info, const T& traceable) {
- return WTF::TraceInCollectionTrait<weakness, T, Traits>::IsAlive(info,
- traceable);
- }
-
- static void Trace(Visitor* visitor, const void* t) {
- static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
- weakness == WTF::kWeakHandling,
- "Traits should be traced");
- WTF::TraceInCollectionTrait<weakness, T, Traits>::Trace(
- visitor, *reinterpret_cast<const T*>(t));
- }
-};
-
// The TraceTrait is used to specify how to trace and object for Oilpan and
// wrapper tracing.
//
@@ -190,192 +123,6 @@ struct TraceTrait<std::pair<T, U>> {
}
};
-// While using base::Optional<T> with garbage-collected types is generally
-// disallowed by the OptionalGarbageCollected check in blink_gc_plugin,
-// garbage-collected containers such as HeapVector are allowed and need to be
-// traced.
-template <typename T>
-struct TraceTrait<base::Optional<T>> {
- STATIC_ONLY(TraceTrait);
-
- public:
- static void Trace(Visitor* visitor, const base::Optional<T>* optional) {
- if (*optional != base::nullopt) {
- TraceIfNeeded<T>::Trace(visitor, optional->value());
- }
- }
-};
-
-// Helper for processing ephemerons represented as KeyValuePair. Reorders
-// parameters if needed so that KeyType is always weak.
-template <typename _KeyType,
- typename _ValueType,
- typename _KeyTraits,
- typename _ValueTraits,
- bool = WTF::IsWeak<_ValueType>::value>
-struct EphemeronKeyValuePair {
- using KeyType = _KeyType;
- using ValueType = _ValueType;
- using KeyTraits = _KeyTraits;
- using ValueTraits = _ValueTraits;
-
- // Ephemerons have different weakness for KeyType and ValueType. If weakness
- // is equal, we either have Strong/Strong, or Weak/Weak, which would indicate
- // a full strong or fully weak pair.
- static constexpr bool is_ephemeron =
- WTF::IsWeak<KeyType>::value != WTF::IsWeak<ValueType>::value;
-
- static_assert(!WTF::IsWeak<KeyType>::value ||
- WTF::IsSubclassOfTemplate<KeyType, WeakMember>::value,
- "Weakness must be encoded using WeakMember.");
-
- EphemeronKeyValuePair(const KeyType* k, const ValueType* v)
- : key(k), value(v) {}
- const KeyType* key;
- const ValueType* value;
-};
-
-template <typename _KeyType,
- typename _ValueType,
- typename _KeyTraits,
- typename _ValueTraits>
-struct EphemeronKeyValuePair<_KeyType,
- _ValueType,
- _KeyTraits,
- _ValueTraits,
- true> : EphemeronKeyValuePair<_ValueType,
- _KeyType,
- _ValueTraits,
- _KeyTraits,
- false> {
- EphemeronKeyValuePair(const _KeyType* k, const _ValueType* v)
- : EphemeronKeyValuePair<_ValueType,
- _KeyType,
- _ValueTraits,
- _KeyTraits,
- false>(v, k) {}
-};
-
} // namespace blink
-namespace WTF {
-
-// Catch-all for types that have a way to trace that don't have special
-// handling for weakness in collections. This means that if this type
-// contains WeakMember fields, they will simply be zeroed, but the entry
-// will not be removed from the collection. This always happens for
-// things in vectors, which don't currently support special handling of
-// weak elements.
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kNoWeakHandling, T, Traits> {
- static bool IsAlive(const blink::LivenessBroker& info, const T& t) {
- return true;
- }
-
- static void Trace(blink::Visitor* visitor, const T& t) {
- static_assert(IsTraceableInCollectionTrait<Traits>::value,
- "T should be traceable");
- visitor->Trace(t);
- }
-};
-
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kNoWeakHandling, blink::WeakMember<T>, Traits> {
- static void Trace(blink::Visitor* visitor, const blink::WeakMember<T>& t) {
- // Extract raw pointer to avoid using the WeakMember<> overload in Visitor.
- visitor->TraceStrongly(t);
- }
-};
-
-// Catch-all for types that have HashTrait support for tracing with weakness.
-// Empty to enforce specialization.
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kWeakHandling, T, Traits> {};
-
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kWeakHandling, blink::WeakMember<T>, Traits> {
- static bool IsAlive(const blink::LivenessBroker& info,
- const blink::WeakMember<T>& value) {
- return info.IsHeapObjectAlive(value);
- }
-};
-
-// This specialization of TraceInCollectionTrait is for the backing of
-// HeapListHashSet. This is for the case that we find a reference to the
-// backing from the stack. That probably means we have a GC while we are in a
-// ListHashSet method since normal API use does not put pointers to the backing
-// on the stack.
-template <typename NodeContents,
- size_t inlineCapacity,
- typename T,
- typename U,
- typename V,
- typename W,
- typename X,
- typename Y>
-struct TraceInCollectionTrait<
- kNoWeakHandling,
- blink::HeapHashTableBacking<HashTable<
- ListHashSetNode<NodeContents,
- blink::HeapListHashSetAllocator<T, inlineCapacity>>*,
- U,
- V,
- W,
- X,
- Y,
- blink::HeapAllocator>>,
- void> {
- using Node =
- ListHashSetNode<NodeContents,
- blink::HeapListHashSetAllocator<T, inlineCapacity>>;
- using Table = HashTable<Node*, U, V, W, X, Y, blink::HeapAllocator>;
-
- static void Trace(blink::Visitor* visitor, const void* self) {
- const Node* const* array = reinterpret_cast<const Node* const*>(self);
- blink::HeapObjectHeader* header =
- blink::HeapObjectHeader::FromPayload(self);
- size_t length = header->PayloadSize() / sizeof(Node*);
- const bool is_concurrent = visitor->IsConcurrent();
- for (size_t i = 0; i < length; ++i) {
- const Node* node;
- if (is_concurrent) {
- // If tracing concurrently, IsEmptyOrDeletedBucket can cause data
- // races. Loading array[i] atomically prevents possible data races.
- // array[i] is of type Node* so can directly loaded atomically.
- node = AsAtomicPtr(&array[i])->load(std::memory_order_relaxed);
- } else {
- node = array[i];
- }
- if (!HashTableHelper<
- const Node*, typename Table::ExtractorType,
- typename Table::KeyTraitsType>::IsEmptyOrDeletedBucket(node)) {
- visitor->Trace(node);
- }
- }
- }
-};
-
-// ListHashSetNode pointers (a ListHashSet is implemented as a hash table of
-// these pointers).
-template <typename Value, size_t inlineCapacity, typename Traits>
-struct TraceInCollectionTrait<
- kNoWeakHandling,
- ListHashSetNode<Value,
- blink::HeapListHashSetAllocator<Value, inlineCapacity>>*,
- Traits> {
- using Node =
- ListHashSetNode<Value,
- blink::HeapListHashSetAllocator<Value, inlineCapacity>>;
-
- static void Trace(blink::Visitor* visitor, const Node* node) {
- static_assert(!IsWeak<Node>::value,
- "ListHashSet does not support weakness");
- static_assert(IsTraceableInCollectionTrait<Traits>::value,
- "T should be traceable");
- visitor->Trace(node);
- }
-};
-
-} // namespace WTF
-
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
index 43a4e292dbf..6e697d3d593 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc
@@ -22,7 +22,8 @@ namespace {
constexpr BlinkGC::StackState ToBlinkGCStackState(
v8::EmbedderHeapTracer::EmbedderStackState stack_state) {
- return stack_state == v8::EmbedderHeapTracer::EmbedderStackState::kEmpty
+ return stack_state ==
+ v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers
? BlinkGC::kNoHeapPointersOnStack
: BlinkGC::kHeapPointersOnStack;
}
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc
index 00a9bc24826..57c2e11df86 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc
@@ -68,6 +68,7 @@ void UnifiedHeapMarkingVisitor::WriteBarrier(
// static
void UnifiedHeapMarkingVisitor::WriteBarrier(
v8::Isolate* isolate,
+ v8::Local<v8::Object>&,
const WrapperTypeInfo* wrapper_type_info,
const void* object) {
// |object| here is either ScriptWrappable or CustomWrappable.
diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h
index 8d589b4e52b..f358b313cc1 100644
--- a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h"
+#include "v8/include/v8.h"
namespace v8 {
class EmbedderHeapTracer;
@@ -49,7 +50,10 @@ class PLATFORM_EXPORT UnifiedHeapMarkingVisitor
public:
// Write barriers for annotating a write during incremental marking.
static void WriteBarrier(const TraceWrapperV8Reference<v8::Value>&);
- static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, const void*);
+ static void WriteBarrier(v8::Isolate*,
+ v8::Local<v8::Object>&,
+ const WrapperTypeInfo*,
+ const void*);
UnifiedHeapMarkingVisitor(ThreadState*, MarkingMode, v8::Isolate*);
~UnifiedHeapMarkingVisitor() override = default;
diff --git a/chromium/third_party/blink/renderer/platform/heap/member.h b/chromium/third_party/blink/renderer/platform/heap/member.h
index 4dbf5fd1c44..68ec7c42e1c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/member.h
+++ b/chromium/third_party/blink/renderer/platform/heap/member.h
@@ -5,12 +5,135 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/member.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/member.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
+
+namespace blink {
+
+template <typename T>
+inline void swap(Member<T>& a, Member<T>& b) {
+ a.Swap(b);
+}
+
+} // namespace blink
+
+namespace WTF {
+
+// PtrHash is the default hash for hash tables with Member<>-derived elements.
+template <typename T>
+struct MemberHash : PtrHash<T> {
+ STATIC_ONLY(MemberHash);
+ template <typename U>
+ static unsigned GetHash(const U& key) {
+ return PtrHash<T>::GetHash(key);
+ }
+ template <typename U, typename V>
+ static bool Equal(const U& a, const V& b) {
+ return a == b;
+ }
+};
+
+template <typename T>
+struct DefaultHash<blink::Member<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::WeakMember<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::UntracedMember<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct IsTraceable<blink::Member<T>> {
+ STATIC_ONLY(IsTraceable);
+ static const bool value = true;
+};
+
+template <typename T>
+struct IsWeak<blink::WeakMember<T>> : std::true_type {};
+
+template <typename T>
+struct IsTraceable<blink::WeakMember<T>> {
+ STATIC_ONLY(IsTraceable);
+ static const bool value = true;
+};
+
+template <typename T, typename MemberType>
+struct BaseMemberHashTraits : SimpleClassHashTraits<MemberType> {
+ STATIC_ONLY(BaseMemberHashTraits);
+
+ using PeekInType = T*;
+ using PeekOutType = T*;
+ using IteratorGetType = MemberType*;
+ using IteratorConstGetType = const MemberType*;
+ using IteratorReferenceType = MemberType&;
+ using IteratorConstReferenceType = const MemberType&;
+
+ static PeekOutType Peek(const MemberType& value) { return value; }
+
+ static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+ return *x;
+ }
+
+ static IteratorConstReferenceType GetToReferenceConstConversion(
+ IteratorConstGetType x) {
+ return *x;
+ }
+
+ template <typename U>
+ static void Store(const U& value, MemberType& storage) {
+ storage = value;
+ }
+
+ static void ConstructDeletedValue(MemberType& slot, bool) {
+#if BUILDFLAG(USE_V8_OILPAN)
+ slot = cppgc::kSentinelPointer;
+#else // !USE_V8_OILPAN
+ slot = WTF::kHashTableDeletedValue;
+#endif // !USE_V8_OILPAN
+ }
+
+ static bool IsDeletedValue(const MemberType& value) {
+#if BUILDFLAG(USE_V8_OILPAN)
+ return value.Get() == cppgc::kSentinelPointer;
+#else // !USE_V8_OILPAN
+ return value.IsHashTableDeletedValue();
+#endif // !USE_V8_OILPAN
+ }
+};
+
+template <typename T>
+struct HashTraits<blink::Member<T>>
+ : BaseMemberHashTraits<T, blink::Member<T>> {
+ static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct HashTraits<blink::WeakMember<T>>
+ : BaseMemberHashTraits<T, blink::WeakMember<T>> {
+ static constexpr bool kCanTraceConcurrently = true;
+};
+
+template <typename T>
+struct HashTraits<blink::UntracedMember<T>>
+ : BaseMemberHashTraits<T, blink::UntracedMember<T>> {};
+
+} // namespace WTF
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent.h b/chromium/third_party/blink/renderer/platform/heap/persistent.h
index 77fd0d5cc7b..b9c9ae9a5d1 100644
--- a/chromium/third_party/blink/renderer/platform/heap/persistent.h
+++ b/chromium/third_party/blink/renderer/platform/heap/persistent.h
@@ -5,12 +5,178 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/persistent.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
+
+namespace blink {
+
+template <typename T,
+ typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>>
+Persistent<T> WrapPersistentIfNeeded(T* value) {
+ return Persistent<T>(value);
+}
+
+template <typename T>
+T& WrapPersistentIfNeeded(T& value) {
+ return value;
+}
+
+} // namespace blink
+
+namespace WTF {
+
+template <typename T>
+struct PersistentVectorTraitsBase : VectorTraitsBase<T> {
+ STATIC_ONLY(PersistentVectorTraitsBase);
+ static const bool kCanInitializeWithMemset = true;
+};
+
+template <typename T>
+struct VectorTraits<blink::Persistent<T>>
+ : PersistentVectorTraitsBase<blink::Persistent<T>> {};
+
+template <typename T>
+struct VectorTraits<blink::WeakPersistent<T>>
+ : PersistentVectorTraitsBase<blink::WeakPersistent<T>> {};
+
+template <typename T>
+struct VectorTraits<blink::CrossThreadPersistent<T>>
+ : PersistentVectorTraitsBase<blink::CrossThreadPersistent<T>> {};
+
+template <typename T>
+struct VectorTraits<blink::CrossThreadWeakPersistent<T>>
+ : PersistentVectorTraitsBase<blink::CrossThreadWeakPersistent<T>> {};
+
+template <typename T, typename PersistentType>
+struct BasePersistentHashTraits : SimpleClassHashTraits<PersistentType> {
+ STATIC_ONLY(BasePersistentHashTraits);
+
+ // TODO: Implement proper const'ness for iterator types. Requires support
+ // in the marking Visitor.
+ using PeekInType = T*;
+ using IteratorGetType = PersistentType*;
+ using IteratorConstGetType = const PersistentType*;
+ using IteratorReferenceType = PersistentType&;
+ using IteratorConstReferenceType = const PersistentType&;
+ static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) {
+ return *x;
+ }
+ static IteratorConstReferenceType GetToReferenceConstConversion(
+ IteratorConstGetType x) {
+ return *x;
+ }
+
+ using PeekOutType = T*;
+
+ template <typename U>
+ static void Store(const U& value, PersistentType& storage) {
+ storage = value;
+ }
+
+ static PeekOutType Peek(const PersistentType& value) { return value; }
+
+ static void ConstructDeletedValue(PersistentType& slot, bool) {
+#if BUILDFLAG(USE_V8_OILPAN)
+ slot = cppgc::kSentinelPointer;
+#else // !USE_V8_OILPAN
+ slot = WTF::kHashTableDeletedValue;
+#endif // !USE_V8_OILPAN
+ }
+
+ static bool IsDeletedValue(const PersistentType& value) {
+#if BUILDFLAG(USE_V8_OILPAN)
+ return value.Get() == cppgc::kSentinelPointer;
+#else // !USE_V8_OILPAN
+ return value.IsHashTableDeletedValue();
+#endif // !USE_V8_OILPAN
+ }
+};
+
+template <typename T>
+struct HashTraits<blink::Persistent<T>>
+ : BasePersistentHashTraits<T, blink::Persistent<T>> {};
+
+template <typename T>
+struct HashTraits<blink::CrossThreadPersistent<T>>
+ : BasePersistentHashTraits<T, blink::CrossThreadPersistent<T>> {};
+
+template <typename T>
+struct DefaultHash<blink::Persistent<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::WeakPersistent<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::CrossThreadPersistent<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct DefaultHash<blink::CrossThreadWeakPersistent<T>> {
+ STATIC_ONLY(DefaultHash);
+ using Hash = MemberHash<T>;
+};
+
+template <typename T>
+struct CrossThreadCopier<blink::CrossThreadPersistent<T>>
+ : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+template <typename T>
+struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>>
+ : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+} // namespace WTF
+
+namespace base {
+
+template <typename T>
+struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {};
+
+template <typename T>
+struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {};
+
+template <typename T>
+struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> {
+ static blink::CrossThreadPersistent<T> Unwrap(
+ const blink::CrossThreadWeakPersistent<T>& wrapped) {
+ return blink::CrossThreadPersistent<T>(wrapped);
+ }
+};
+
+// TODO(https://crbug.com/653394): Consider returning a thread-safe best
+// guess of validity. MaybeValid() can be invoked from an arbitrary thread.
+template <typename T>
+struct MaybeValidTraits<blink::WeakPersistent<T>> {
+ static bool MaybeValid(const blink::WeakPersistent<T>& p) { return true; }
+};
+
+template <typename T>
+struct MaybeValidTraits<blink::CrossThreadWeakPersistent<T>> {
+ static bool MaybeValid(const blink::CrossThreadWeakPersistent<T>& p) {
+ return true;
+ }
+};
+
+} // namespace base
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/process_heap.h b/chromium/third_party/blink/renderer/platform/heap/process_heap.h
index 5f8d21f5c5d..4993d405e29 100644
--- a/chromium/third_party/blink/renderer/platform/heap/process_heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/process_heap.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/process_heap.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/self_keep_alive.h b/chromium/third_party/blink/renderer/platform/heap/self_keep_alive.h
index 3eaff5d5c86..70b36f1c207 100644
--- a/chromium/third_party/blink/renderer/platform/heap/self_keep_alive.h
+++ b/chromium/third_party/blink/renderer/platform/heap/self_keep_alive.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_SELF_KEEP_ALIVE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_SELF_KEEP_ALIVE_H_
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/thread_state.h
index 050bac6b39b..eb763b5be77 100644
--- a/chromium/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/chromium/third_party/blink/renderer/platform/heap/thread_state.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/thread_state.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h
index 5abe13206e6..85e74893225 100644
--- a/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h
+++ b/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h
@@ -5,12 +5,35 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
+
+namespace blink {
+
+#if defined(LEAK_SANITIZER)
+class LsanDisabledScope final {
+ STACK_ALLOCATED();
+
+ public:
+ explicit LsanDisabledScope() { __lsan_disable(); }
+
+ ~LsanDisabledScope() { __lsan_enable(); }
+
+ LsanDisabledScope(const LsanDisabledScope&) = delete;
+ LsanDisabledScope& operator=(const LsanDisabledScope&) = delete;
+};
+
+#define LEAK_SANITIZER_DISABLED_SCOPE LsanDisabledScope lsan_disabled_scope
+#else
+#define LEAK_SANITIZER_DISABLED_SCOPE
+#endif
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/trace_traits.h b/chromium/third_party/blink/renderer/platform/heap/trace_traits.h
new file mode 100644
index 00000000000..76b89917079
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/trace_traits.h
@@ -0,0 +1,129 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/hash_table.h"
+
+#if BUILDFLAG(USE_V8_OILPAN)
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h"
+#else // !USE_V8_OILPAN
+#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
+#endif // !USE_V8_OILPAN
+
+namespace blink {
+
+template <WTF::WeakHandlingFlag weakness,
+ typename T,
+ typename Traits,
+ bool = WTF::IsTraceableInCollectionTrait<Traits>::value,
+ WTF::WeakHandlingFlag = WTF::WeakHandlingTrait<T>::value>
+struct TraceCollectionIfEnabled;
+
+template <WTF::WeakHandlingFlag weakness, typename T, typename Traits>
+struct TraceCollectionIfEnabled<weakness,
+ T,
+ Traits,
+ false,
+ WTF::kNoWeakHandling> {
+ STATIC_ONLY(TraceCollectionIfEnabled);
+
+ static bool IsAlive(const blink::LivenessBroker& info, const T&) {
+ return true;
+ }
+
+ static void Trace(Visitor*, const void*) {
+ static_assert(!WTF::IsTraceableInCollectionTrait<Traits>::value,
+ "T should not be traced");
+ }
+};
+
+template <typename T, typename Traits>
+struct TraceCollectionIfEnabled<WTF::kNoWeakHandling,
+ T,
+ Traits,
+ false,
+ WTF::kWeakHandling> {
+ STATIC_ONLY(TraceCollectionIfEnabled);
+
+ static void Trace(Visitor* visitor, const void* t) {
+ WTF::TraceInCollectionTrait<WTF::kNoWeakHandling, T, Traits>::Trace(
+ visitor, *reinterpret_cast<const T*>(t));
+ }
+};
+
+template <WTF::WeakHandlingFlag weakness,
+ typename T,
+ typename Traits,
+ bool,
+ WTF::WeakHandlingFlag>
+struct TraceCollectionIfEnabled {
+ STATIC_ONLY(TraceCollectionIfEnabled);
+
+ static bool IsAlive(const blink::LivenessBroker& info, const T& traceable) {
+ return WTF::TraceInCollectionTrait<weakness, T, Traits>::IsAlive(info,
+ traceable);
+ }
+
+ static void Trace(Visitor* visitor, const void* t) {
+ static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
+ weakness == WTF::kWeakHandling,
+ "Traits should be traced");
+ WTF::TraceInCollectionTrait<weakness, T, Traits>::Trace(
+ visitor, *reinterpret_cast<const T*>(t));
+ }
+};
+
+} // namespace blink
+
+namespace WTF {
+
+// Catch-all for types that have a way to trace that don't have special
+// handling for weakness in collections. This means that if this type
+// contains WeakMember fields, they will simply be zeroed, but the entry
+// will not be removed from the collection. This always happens for
+// things in vectors, which don't currently support special handling of
+// weak elements.
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kNoWeakHandling, T, Traits> {
+ static bool IsAlive(const blink::LivenessBroker& info, const T& t) {
+ return true;
+ }
+
+ static void Trace(blink::Visitor* visitor, const T& t) {
+ static_assert(IsTraceableInCollectionTrait<Traits>::value,
+ "T should be traceable");
+ visitor->Trace(t);
+ }
+};
+
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kNoWeakHandling, blink::WeakMember<T>, Traits> {
+ static void Trace(blink::Visitor* visitor, const blink::WeakMember<T>& t) {
+ // Extract raw pointer to avoid using the WeakMember<> overload in Visitor.
+ visitor->TraceStrongly(t);
+ }
+};
+
+// Catch-all for types that have HashTrait support for tracing with weakness.
+// Empty to enforce specialization.
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kWeakHandling, T, Traits> {};
+
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kWeakHandling, blink::WeakMember<T>, Traits> {
+ static bool IsAlive(const blink::LivenessBroker& info,
+ const blink::WeakMember<T>& value) {
+ return info.IsHeapObjectAlive(value);
+ }
+};
+
+} // namespace WTF
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h b/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h
index 9d197c495e9..636651ef610 100644
--- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h
+++ b/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
index 4d13146e071..267ee3262bf 100644
--- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
index bf8602168fa..e2d376d9e2c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
@@ -5,6 +5,30 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
-// TODO(chromium:1056170): Implement wrapper.
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/liveness-broker.h"
+#include "v8/include/cppgc/trace-trait.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT BlinkGC final {
+ STATIC_ONLY(BlinkGC);
+
+ public:
+ // When garbage collecting we need to know whether or not there can be
+ // pointers to Oilpan-managed objects on the stack for each thread. When
+ // threads reach a safe point they record whether or not they have pointers on
+ // the stack.
+ enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack };
+};
+
+using Address = uint8_t*;
+using ConstAddress = const uint8_t*;
+
+using TraceCallback = cppgc::TraceCallback;
+using WeakCallback = void (*)(const cppgc::LivenessBroker&, const void*);
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc
new file mode 100644
index 00000000000..dd1edb88b0d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc
@@ -0,0 +1,137 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
+
+#include <inttypes.h>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "v8/include/cppgc/heap-statistics.h"
+
+namespace blink {
+namespace {
+
+constexpr const char* HeapTypeString(
+ BlinkGCMemoryDumpProvider::HeapType heap_type) {
+ switch (heap_type) {
+ case BlinkGCMemoryDumpProvider::HeapType::kBlinkMainThread:
+ return "main";
+ case BlinkGCMemoryDumpProvider::HeapType::kBlinkWorkerThread:
+ return "workers";
+ }
+}
+
+} // namespace
+
+BlinkGCMemoryDumpProvider::BlinkGCMemoryDumpProvider(
+ ThreadState* thread_state,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ BlinkGCMemoryDumpProvider::HeapType heap_type)
+ : thread_state_(thread_state),
+ heap_type_(heap_type),
+ dump_base_name_(
+ "blink_gc/" + std::string(HeapTypeString(heap_type_)) + "/heap" +
+ (heap_type_ == HeapType::kBlinkWorkerThread
+ ? "/" + base::StringPrintf(
+ "worker_0x%" PRIXPTR,
+ reinterpret_cast<uintptr_t>(thread_state_))
+ : "")) {
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, "BlinkGC", task_runner);
+}
+
+BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
+}
+
+bool BlinkGCMemoryDumpProvider::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* process_memory_dump) {
+ ::cppgc::HeapStatistics::DetailLevel detail_level =
+ args.level_of_detail ==
+ base::trace_event::MemoryDumpLevelOfDetail::DETAILED
+ ? ::cppgc::HeapStatistics::kDetailed
+ : ::cppgc::HeapStatistics::kBrief;
+
+ ::cppgc::HeapStatistics stats =
+ ThreadState::Current()->cpp_heap().CollectStatistics(detail_level);
+
+ auto* heap_dump = process_memory_dump->CreateAllocatorDump(dump_base_name_);
+ heap_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ stats.physical_size_bytes);
+ heap_dump->AddScalar("allocated_objects_size",
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ stats.used_size_bytes);
+
+ if (detail_level == ::cppgc::HeapStatistics::kBrief) {
+ return true;
+ }
+
+ // Detailed statistics.
+ for (const ::cppgc::HeapStatistics::SpaceStatistics& space_stats :
+ stats.space_stats) {
+ std::string arena_dump_name = dump_base_name_ + "/" + space_stats.name;
+ auto* arena_dump =
+ process_memory_dump->CreateAllocatorDump(arena_dump_name);
+ arena_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ space_stats.physical_size_bytes);
+ arena_dump->AddScalar("allocated_objects_size",
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ space_stats.used_size_bytes);
+
+ size_t page_count = 0;
+ for (const ::cppgc::HeapStatistics::PageStatistics& page_stats :
+ space_stats.page_stats) {
+ auto* page_dump = process_memory_dump->CreateAllocatorDump(
+ arena_dump_name + "/pages/page_" +
+ base::NumberToString(page_count++));
+ page_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ page_stats.physical_size_bytes);
+ page_dump->AddScalar("allocated_objects_size",
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ page_stats.used_size_bytes);
+ }
+
+ const ::cppgc::HeapStatistics::FreeListStatistics& free_list_stats =
+ space_stats.free_list_stats;
+ for (wtf_size_t i = 0; i < free_list_stats.bucket_size.size(); ++i) {
+ constexpr size_t kDigits = 8;
+ std::string original_bucket_size =
+ base::NumberToString(free_list_stats.bucket_size[i]);
+ std::string padded_bucket_size =
+ std::string(kDigits - original_bucket_size.length(), '0') +
+ original_bucket_size;
+ auto* free_list_bucket_dump = process_memory_dump->CreateAllocatorDump(
+ arena_dump_name + "/freelist/bucket_" + padded_bucket_size);
+ free_list_bucket_dump->AddScalar(
+ "free_size", base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ free_list_stats.free_size[i]);
+ }
+
+ const ::cppgc::HeapStatistics::ObjectStatistics& object_stats =
+ space_stats.object_stats;
+ for (wtf_size_t i = 1; i < object_stats.num_types; i++) {
+ if (object_stats.type_name[i].empty())
+ continue;
+
+ auto* class_dump = process_memory_dump->CreateAllocatorDump(
+ arena_dump_name + "/classes/" + object_stats.type_name[i]);
+ class_dump->AddScalar(
+ "object_count", base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+ object_stats.type_count[i]);
+ class_dump->AddScalar("object_size",
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ object_stats.type_bytes[i]);
+ }
+ }
+ return true;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
index 8773bd7af3d..0bb476f4ede 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
@@ -5,6 +5,40 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
-// TODO(chromium:1056170): Implement wrapper.
+#include "base/trace_event/memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace blink {
+
+class ThreadState;
+
+class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final
+ : public base::trace_event::MemoryDumpProvider {
+ USING_FAST_MALLOC(BlinkGCMemoryDumpProvider);
+
+ public:
+ enum class HeapType { kBlinkMainThread, kBlinkWorkerThread };
+
+ ~BlinkGCMemoryDumpProvider() final;
+ BlinkGCMemoryDumpProvider(ThreadState*,
+ scoped_refptr<base::SingleThreadTaskRunner>,
+ HeapType);
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
+ base::trace_event::ProcessMemoryDump*) final;
+
+ private:
+ ThreadState* const thread_state_;
+ const HeapType heap_type_;
+ const std::string dump_base_name_;
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h
new file mode 100644
index 00000000000..201e6632cb2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h
@@ -0,0 +1,275 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
+
+#include <type_traits>
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/wtf/hash_table.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "v8/include/cppgc/custom-space.h"
+#include "v8/include/cppgc/object-size-trait.h"
+
+namespace blink {
+
+template <typename Table>
+class HeapHashTableBacking final
+ : public GarbageCollected<HeapHashTableBacking<Table>>,
+ public WTF::ConditionalDestructor<
+ HeapHashTableBacking<Table>,
+ std::is_trivially_destructible<typename Table::ValueType>::value> {
+ public:
+ // Conditionally invoked via destructor.
+ void Finalize();
+};
+
+template <typename Table>
+void HeapHashTableBacking<Table>::Finalize() {
+ using Value = typename Table::ValueType;
+ static_assert(
+ !std::is_trivially_destructible<Value>::value,
+ "Finalization of trivially destructible classes should not happen.");
+ const size_t object_size =
+ cppgc::subtle::ObjectSizeTrait<HeapHashTableBacking<Table>>::GetSize(
+ *this);
+ const size_t length = object_size / sizeof(Value);
+ Value* table = reinterpret_cast<Value*>(this);
+ for (unsigned i = 0; i < length; ++i) {
+ if (!Table::IsEmptyOrDeletedBucket(table[i]))
+ table[i].~Value();
+ }
+}
+
+template <typename Table>
+struct ThreadingTrait<HeapHashTableBacking<Table>> {
+ STATIC_ONLY(ThreadingTrait);
+ using Key = typename Table::KeyType;
+ using Value = typename Table::ValueType;
+ static constexpr ThreadAffinity kAffinity =
+ (ThreadingTrait<Key>::kAffinity == kMainThreadOnly) &&
+ (ThreadingTrait<Value>::kAffinity == kMainThreadOnly)
+ ? kMainThreadOnly
+ : kAnyThread;
+};
+
+template <typename First, typename Second>
+struct ThreadingTrait<WTF::KeyValuePair<First, Second>> {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity =
+ (ThreadingTrait<First>::kAffinity == kMainThreadOnly) &&
+ (ThreadingTrait<Second>::kAffinity == kMainThreadOnly)
+ ? kMainThreadOnly
+ : kAnyThread;
+};
+
+} // namespace blink
+
+namespace WTF {
+
+namespace internal {
+
+// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking.
+// It is used to provide a snapshot view of the bucket key and guarantee
+// that the same key is used for checking empty/deleted buckets and tracing.
+template <typename T>
+class ConcurrentBucket {
+ using KeyExtractionCallback = void (*)(const T&, void*);
+
+ public:
+ using BucketType = T;
+
+ ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) {
+ extract_key(t, &buf_);
+ }
+
+ // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key
+ // and the value are the same.
+ const T* key() const { return reinterpret_cast<const T*>(&buf_); }
+ const T* value() const { return key(); }
+ const T* bucket() const { return key(); }
+
+ private:
+ // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+ // can be accessed the same as objects of type T
+ static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t));
+ alignas(boundary) char buf_[sizeof(T)];
+};
+
+template <typename Key, typename Value>
+class ConcurrentBucket<KeyValuePair<Key, Value>> {
+ using KeyExtractionCallback = void (*)(const KeyValuePair<Key, Value>&,
+ void*);
+
+ public:
+ using BucketType = ConcurrentBucket;
+
+ ConcurrentBucket(const KeyValuePair<Key, Value>& pair,
+ KeyExtractionCallback extract_key)
+ : value_(&pair.value) {
+ extract_key(pair, &buf_);
+ }
+
+ const Key* key() const { return reinterpret_cast<const Key*>(&buf_); }
+ const Value* value() const { return value_; }
+ const ConcurrentBucket* bucket() const { return this; }
+
+ private:
+ // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+ // can be accessed the same as objects of type Key
+ static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t));
+ alignas(boundary) char buf_[sizeof(Key)];
+ const Value* value_;
+};
+
+} // namespace internal
+
+template <WTF::WeakHandlingFlag weak_handling, typename Table>
+struct TraceHashTableBackingInCollectionTrait {
+ using Value = typename Table::ValueType;
+ using Traits = typename Table::ValueTraits;
+ using Extractor = typename Table::ExtractorType;
+
+ static void Trace(blink::Visitor* visitor, const void* self) {
+ static_assert(IsTraceableInCollectionTrait<Traits>::value ||
+ WTF::IsWeak<Value>::value,
+ "Table should not be traced");
+ const Value* array = reinterpret_cast<const Value*>(self);
+ const size_t length =
+ cppgc::subtle::
+ ObjectSizeTrait<const blink::HeapHashTableBacking<Table>>::GetSize(
+ *reinterpret_cast<const blink::HeapHashTableBacking<Table>*>(
+ self)) /
+ sizeof(Value);
+ for (size_t i = 0; i < length; ++i) {
+ internal::ConcurrentBucket<Value> concurrent_bucket(
+ array[i], Extractor::ExtractSafe);
+ if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
+ IsEmptyOrDeletedBucketForKey(*concurrent_bucket.key())) {
+ blink::TraceCollectionIfEnabled<
+ weak_handling,
+ typename internal::ConcurrentBucket<Value>::BucketType,
+ Traits>::Trace(visitor, concurrent_bucket.bucket());
+ }
+ }
+ }
+};
+
+} // namespace WTF
+
+namespace cppgc {
+
+// Assign HeapVector to the custom HeapVectorBackingSpace.
+template <typename Table>
+struct SpaceTrait<blink::HeapHashTableBacking<Table>> {
+ using Space = blink::HeapHashTableBackingSpace;
+};
+
+// Custom allocation accounts for inlined storage of the actual elements of the
+// backing table.
+template <typename Table>
+class MakeGarbageCollectedTrait<blink::HeapHashTableBacking<Table>>
+ : public MakeGarbageCollectedTraitBase<blink::HeapHashTableBacking<Table>> {
+ public:
+ using Backing = blink::HeapHashTableBacking<Table>;
+
+ template <typename... Args>
+ static Backing* Call(AllocationHandle& handle, size_t num_elements) {
+ static_assert(
+ !std::is_polymorphic<blink::HeapHashTableBacking<Table>>::value,
+ "HeapHashTableBacking must not be polymorphic as it is converted to a "
+ "raw array of buckets for certain operation");
+ CHECK_GT(num_elements, 0u);
+ // Allocate automatically considers the custom space via SpaceTrait.
+ void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
+ handle, sizeof(typename Table::ValueType) * num_elements);
+ Backing* object = ::new (memory) Backing();
+ MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
+ object);
+ return object;
+ }
+};
+
+template <typename Table>
+struct TraceTrait<blink::HeapHashTableBacking<Table>> {
+ using Backing = blink::HeapHashTableBacking<Table>;
+ using Traits = typename Table::ValueTraits;
+ using ValueType = typename Table::ValueTraits::TraitType;
+
+ static TraceDescriptor GetTraceDescriptor(const void* self) {
+ return {self, Trace<WTF::kNoWeakHandling>};
+ }
+
+ static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
+ return GetWeakTraceDescriptorImpl<ValueType>::GetWeakTraceDescriptor(self);
+ }
+
+ template <WTF::WeakHandlingFlag weak_handling = WTF::kNoWeakHandling>
+ static void Trace(Visitor* visitor, const void* self) {
+ if (!Traits::kCanTraceConcurrently && self) {
+ if (visitor->DeferTraceToMutatorThreadIfConcurrent(
+ self, &Trace<weak_handling>,
+ cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+ *reinterpret_cast<const Backing*>(self)))) {
+ return;
+ }
+ }
+
+ static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
+ WTF::IsWeak<ValueType>::value,
+ "T should not be traced");
+ WTF::TraceInCollectionTrait<weak_handling, Backing, void>::Trace(visitor,
+ self);
+ }
+
+ private:
+ // Default setting for HashTable is without weak trace descriptor.
+ template <typename ValueType>
+ struct GetWeakTraceDescriptorImpl {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
+ return {self, nullptr};
+ }
+ };
+
+ // Specialization for WTF::KeyValuePair, which is default bucket storage type.
+ template <typename K, typename V>
+ struct GetWeakTraceDescriptorImpl<WTF::KeyValuePair<K, V>> {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return GetWeakTraceDescriptorKVPImpl<K, V>::GetWeakTraceDescriptor(
+ backing);
+ }
+
+ // Default setting for KVP without ephemeron semantics.
+ template <typename KeyType,
+ typename ValueType,
+ bool ephemeron_semantics = (WTF::IsWeak<KeyType>::value &&
+ !WTF::IsWeak<ValueType>::value &&
+ WTF::IsTraceable<ValueType>::value) ||
+ (WTF::IsWeak<ValueType>::value &&
+ !WTF::IsWeak<KeyType>::value &&
+ WTF::IsTraceable<KeyType>::value)>
+ struct GetWeakTraceDescriptorKVPImpl {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return {backing, nullptr};
+ }
+ };
+
+ // Specialization for KVP with ephemeron semantics.
+ template <typename KeyType, typename ValueType>
+ struct GetWeakTraceDescriptorKVPImpl<KeyType, ValueType, true> {
+ static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+ return {backing, Trace<WTF::kWeakHandling>};
+ }
+ };
+ };
+};
+
+} // namespace cppgc
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h
new file mode 100644
index 00000000000..679ca4ff3ec
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h
@@ -0,0 +1,214 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
+
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
+#include "v8/include/cppgc/custom-space.h"
+#include "v8/include/cppgc/object-size-trait.h"
+#include "v8/include/cppgc/trace-trait.h"
+#include "v8/include/cppgc/visitor.h"
+
+namespace blink {
+namespace internal {
+
+inline bool VTableInitialized(const void* object_payload) {
+ return !!(*reinterpret_cast<const size_t*>(object_payload));
+}
+
+} // namespace internal
+
+template <typename T, typename Traits = WTF::VectorTraits<T>>
+class HeapVectorBacking final
+ : public GarbageCollected<HeapVectorBacking<T, Traits>>,
+ public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
+ !Traits::kNeedsDestruction> {
+ public:
+ // Conditionally invoked via destructor.
+ void Finalize();
+};
+
+template <typename T, typename Traits>
+void HeapVectorBacking<T, Traits>::Finalize() {
+ static_assert(Traits::kNeedsDestruction,
+ "Only vector buffers with items requiring destruction should "
+ "be finalized");
+ static_assert(
+ Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic<T>::value,
+ "HeapVectorBacking doesn't support objects that cannot be cleared as "
+ "unused with memset or don't have a vtable");
+ static_assert(
+ !std::is_trivially_destructible<T>::value,
+ "Finalization of trivially destructible classes should not happen.");
+ const size_t object_size =
+ cppgc::subtle::ObjectSizeTrait<HeapVectorBacking<T, Traits>>::GetSize(
+ *this);
+ const size_t length = object_size / sizeof(T);
+ Address payload = reinterpret_cast<Address>(this);
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+ ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
+#endif // ANNOTATE_CONTIGUOUS_CONTAINER
+ // HeapVectorBacking calls finalizers for unused slots and expects them to be
+ // no-ops.
+ if (std::is_polymorphic<T>::value) {
+ for (size_t i = 0; i < length; ++i) {
+ Address element = payload + i * sizeof(T);
+ if (internal::VTableInitialized(element))
+ reinterpret_cast<T*>(element)->~T();
+ }
+ } else {
+ T* buffer = reinterpret_cast<T*>(payload);
+ for (size_t i = 0; i < length; ++i)
+ buffer[i].~T();
+ }
+}
+
+template <typename T, typename Traits>
+struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+} // namespace blink
+
+namespace WTF {
+
+// This trace method is used for all HeapVectorBacking objects. On-stack objects
+// are found and dispatched using conservative stack scanning. HeapVector (i.e.
+// Vector) dispatches all regular on-heap backings to this method.
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kNoWeakHandling,
+ blink::HeapVectorBacking<T, Traits>,
+ void> {
+ using Backing = blink::HeapVectorBacking<T, Traits>;
+
+ static void Trace(blink::Visitor* visitor, const void* self) {
+ // HeapVectorBacking does not know the exact size of the vector
+ // and just knows the capacity of the vector. Due to the constraint,
+ // HeapVectorBacking can support only the following objects:
+ //
+ // - An object that has a vtable. In this case, HeapVectorBacking
+ // traces only slots that are not zeroed out. This is because if
+ // the object has a vtable, the zeroed slot means that it is
+ // an unused slot (Remember that the unused slots are guaranteed
+ // to be zeroed out by VectorUnusedSlotClearer).
+ //
+ // - An object that can be initialized with memset. In this case,
+ // HeapVectorBacking traces all slots including unused slots.
+ // This is fine because the fact that the object can be initialized
+ // with memset indicates that it is safe to treat the zerod slot
+ // as a valid object.
+ static_assert(!IsTraceableInCollectionTrait<Traits>::value ||
+ Traits::kCanClearUnusedSlotsWithMemset ||
+ std::is_polymorphic<T>::value,
+ "HeapVectorBacking doesn't support objects that cannot be "
+ "cleared as unused with memset.");
+
+ // This trace method is instantiated for vectors where
+ // IsTraceableInCollectionTrait<Traits>::value is false, but the trace
+ // method should not be called. Thus we cannot static-assert
+ // IsTraceableInCollectionTrait<Traits>::value but should runtime-assert it.
+ DCHECK(IsTraceableInCollectionTrait<Traits>::value);
+
+ const T* array = reinterpret_cast<const T*>(self);
+ const size_t length =
+ cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+ *reinterpret_cast<const Backing*>(self)) /
+ sizeof(T);
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+ // As commented above, HeapVectorBacking can trace unused slots (which are
+ // already zeroed out).
+ ANNOTATE_CHANGE_SIZE(array, length, 0, length);
+#endif // ANNOTATE_CONTIGUOUS_CONTAINER
+ if (std::is_polymorphic<T>::value) {
+ for (unsigned i = 0; i < length; ++i) {
+ if (blink::internal::VTableInitialized(&array[i])) {
+ blink::TraceIfNeeded<
+ T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+ array[i]);
+ }
+ }
+ } else {
+ for (size_t i = 0; i < length; ++i) {
+ blink::TraceIfNeeded<
+ T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+ array[i]);
+ }
+ }
+ }
+};
+
+} // namespace WTF
+
+namespace cppgc {
+
+// Assign HeapVector to the custom HeapVectorBackingSpace.
+template <typename T>
+struct SpaceTrait<blink::HeapVectorBacking<T>> {
+ using Space = blink::HeapVectorBackingSpace;
+};
+
+// Custom allocation accounts for inlined storage of the actual elements of the
+// backing array.
+template <typename T>
+class MakeGarbageCollectedTrait<blink::HeapVectorBacking<T>>
+ : public MakeGarbageCollectedTraitBase<blink::HeapVectorBacking<T>> {
+ using Backing = blink::HeapVectorBacking<T>;
+
+ public:
+ template <typename... Args>
+ static Backing* Call(AllocationHandle& handle, size_t num_elements) {
+ static_assert(!std::is_polymorphic<blink::HeapVectorBacking<T>>::value,
+ "HeapVectorBacking must not be polymorphic as it is "
+ "converted to a raw array of buckets for certain operation");
+ CHECK_GT(num_elements, 0u);
+ // Allocate automatically considers the custom space via SpaceTrait.
+ void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
+ handle, sizeof(T) * num_elements);
+ Backing* object = ::new (memory) Backing();
+ MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
+ object);
+ return object;
+ }
+};
+
+template <typename T, typename Traits>
+struct TraceTrait<blink::HeapVectorBacking<T, Traits>> {
+ using Backing = blink::HeapVectorBacking<T, Traits>;
+
+ static TraceDescriptor GetTraceDescriptor(const void* self) {
+ return {self, Trace};
+ }
+
+ static void Trace(Visitor* visitor, const void* self) {
+ if (!Traits::kCanTraceConcurrently && self) {
+ if (visitor->DeferTraceToMutatorThreadIfConcurrent(
+ self, &Trace,
+ cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+ *reinterpret_cast<const Backing*>(self)))) {
+ return;
+ }
+ }
+
+ static_assert(!WTF::IsWeak<T>::value,
+ "Weakness is not supported in HeapVector and HeapDeque");
+ if (WTF::IsTraceableInCollectionTrait<Traits>::value) {
+ WTF::TraceInCollectionTrait<WTF::kNoWeakHandling,
+ blink::HeapVectorBacking<T, Traits>,
+ void>::Trace(visitor, self);
+ }
+ }
+};
+
+} // namespace cppgc
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc
new file mode 100644
index 00000000000..1832f69f736
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+
+namespace blink {
+
+// static
+constexpr cppgc::CustomSpaceIndex HeapVectorBackingSpace::kSpaceIndex;
+
+// static
+constexpr cppgc::CustomSpaceIndex HeapHashTableBackingSpace::kSpaceIndex;
+
+// static
+constexpr cppgc::CustomSpaceIndex NodeSpace::kSpaceIndex;
+
+// static
+constexpr cppgc::CustomSpaceIndex CSSValueSpace::kSpaceIndex;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h
new file mode 100644
index 00000000000..35437fd83b6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "v8/include/cppgc/custom-space.h"
+
+namespace blink {
+
+// The following defines custom spaces that are used to partition Oilpan's heap.
+// Each custom space is assigned to a type partition using `cppgc::SpaceTrait`.
+// It is expected that `kSpaceIndex` uniquely identifies a space and that the
+// indices of all custom spaces form a sequence starting at 0. See
+// `cppgc::CustomSpace` for details.
+
+class PLATFORM_EXPORT HeapVectorBackingSpace
+ : public cppgc::CustomSpace<HeapVectorBackingSpace> {
+ public:
+ static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 0;
+ static constexpr bool kSupportsCompaction = true;
+};
+
+class PLATFORM_EXPORT HeapHashTableBackingSpace
+ : public cppgc::CustomSpace<HeapHashTableBackingSpace> {
+ public:
+ static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 1;
+ static constexpr bool kSupportsCompaction = true;
+};
+
+class PLATFORM_EXPORT NodeSpace : public cppgc::CustomSpace<NodeSpace> {
+ public:
+ static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 2;
+};
+
+class PLATFORM_EXPORT CSSValueSpace : public cppgc::CustomSpace<CSSValueSpace> {
+ public:
+ static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 3;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h
deleted file mode 100644
index 17471d3fd27..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h
+++ /dev/null
@@ -1,10 +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_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
-
-// TODO(chromium:1056170): Implement wrapper.
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
index 5867016b7a0..a06d0e75a9c 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
@@ -4,6 +4,31 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
-// TODO(chromium:1056170): Implement wrapper.
+
+#include "v8/include/cppgc/garbage-collected.h"
+#include "v8/include/cppgc/type-traits.h"
+
+// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
+// field when checking for proper usage. When using GC_PLUGIN_IGNORE
+// a bug-number should be provided as an argument where the bug describes
+// what needs to happen to remove the GC_PLUGIN_IGNORE again.
+#if defined(__clang__)
+#define GC_PLUGIN_IGNORE(bug) \
+ __attribute__((annotate("blink_gc_plugin_ignore")))
+#else
+#define GC_PLUGIN_IGNORE(bug)
+#endif
+
+namespace blink {
+
+using GarbageCollectedMixin = cppgc::GarbageCollectedMixin;
+
+template <typename T>
+struct IsGarbageCollectedMixin {
+ public:
+ static const bool value = cppgc::IsGarbageCollectedMixinTypeV<T>;
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h
deleted file mode 100644
index 2ef207a7c66..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h
+++ /dev/null
@@ -1,10 +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_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
-
-// TODO(chromium:1056170): Implement wrapper.
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
index 5aecfbbbeda..e81eb2f4d80 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
@@ -5,14 +5,41 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "v8/include/cppgc/allocation.h"
#include "v8/include/cppgc/garbage-collected.h"
+#include "v8/include/cppgc/liveness-broker.h"
namespace blink {
+using LivenessBroker = cppgc::LivenessBroker;
+
template <typename T>
using GarbageCollected = cppgc::GarbageCollected<T>;
-using GarbageCollectedMixin = cppgc::GarbageCollectedMixin;
+// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
+// collected type.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(Args&&... args) {
+ return cppgc::MakeGarbageCollected<T>(
+ ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+ ->allocation_handle(),
+ std::forward<Args>(args)...);
+}
+
+using AdditionalBytes = cppgc::AdditionalBytes;
+
+// Constructs an instance of T, which is a garbage collected type. This special
+// version takes size which enables constructing inline objects.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
+ return cppgc::MakeGarbageCollected<T>(
+ ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+ ->allocation_handle(),
+ std::forward<AdditionalBytes>(additional_bytes),
+ std::forward<Args>(args)...);
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h
deleted file mode 100644
index 7c5cd8d4457..00000000000
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h
+++ /dev/null
@@ -1,10 +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_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
-
-// TODO(chromium:1056170): Implement wrapper.
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h
new file mode 100644
index 00000000000..7056f403f10
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h
@@ -0,0 +1,245 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
+
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/heap-consistency.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT HeapAllocator {
+ STATIC_ONLY(HeapAllocator);
+
+ public:
+ using HeapConsistency = cppgc::subtle::HeapConsistency;
+ using LivenessBroker = blink::LivenessBroker;
+
+ static constexpr bool kIsGarbageCollected = true;
+
+ // See wtf/size_t.h for details.
+ static constexpr size_t kMaxHeapObjectSizeLog2 = 27;
+ static constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
+
+ template <typename T>
+ static size_t MaxElementCountInBackingStore() {
+ return kMaxHeapObjectSize / sizeof(T);
+ }
+
+ template <typename T>
+ static size_t QuantizedSize(size_t count) {
+ CHECK_LE(count, MaxElementCountInBackingStore<T>());
+ // Oilpan's internal size is independent of MaxElementCountInBackingStore()
+ // and the required size to match capacity needs.
+ return count * sizeof(T);
+ }
+
+ template <typename T>
+ static T* AllocateVectorBacking(size_t size) {
+ return reinterpret_cast<T*>(
+ MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
+ }
+
+ static void FreeVectorBacking(void*) {
+ // TODO(1056170): Implement.
+ }
+
+ static bool ExpandVectorBacking(void*, size_t) {
+ // TODO(1056170): Implement.
+ return false;
+ }
+
+ static bool ShrinkVectorBacking(void*, size_t, size_t) {
+ // TODO(1056170): Implement.
+ return false;
+ }
+
+ template <typename T, typename HashTable>
+ static T* AllocateHashTableBacking(size_t size) {
+ static_assert(sizeof(T) == sizeof(typename HashTable::ValueType),
+ "T must match ValueType.");
+ return reinterpret_cast<T*>(
+ MakeGarbageCollected<HeapHashTableBacking<HashTable>>(size /
+ sizeof(T)));
+ }
+
+ template <typename T, typename HashTable>
+ static T* AllocateZeroedHashTableBacking(size_t size) {
+ return AllocateHashTableBacking<T, HashTable>(size);
+ }
+
+ static void FreeHashTableBacking(void*) {
+ // TODO(1056170): Implement.
+ }
+
+ static bool ExpandHashTableBacking(void*, size_t) {
+ // TODO(1056170): Implement.
+ return false;
+ }
+
+ static bool IsAllocationAllowed() {
+ return cppgc::subtle::DisallowGarbageCollectionScope::
+ IsGarbageCollectionAllowed(ThreadState::Current()->heap_handle());
+ }
+
+ static bool IsIncrementalMarking() {
+ auto& heap_handle = ThreadState::Current()->heap_handle();
+ return cppgc::subtle::HeapState::IsMarking(heap_handle) &&
+ !cppgc::subtle::HeapState::IsInAtomicPause(heap_handle);
+ }
+
+ static void EnterGCForbiddenScope() {
+ cppgc::subtle::NoGarbageCollectionScope::Enter(
+ ThreadState::Current()->cpp_heap().GetHeapHandle());
+ }
+
+ static void LeaveGCForbiddenScope() {
+ cppgc::subtle::NoGarbageCollectionScope::Leave(
+ ThreadState::Current()->cpp_heap().GetHeapHandle());
+ }
+
+ template <typename Traits>
+ static bool CanReuseHashTableDeletedBucket() {
+ if (Traits::kEmptyValueIsZero || !Traits::kCanTraceConcurrently)
+ return true;
+ return !IsIncrementalMarking();
+ }
+
+ template <typename T>
+ static void BackingWriteBarrier(T** slot) {
+ HeapConsistency::WriteBarrierParams params;
+ switch (HeapConsistency::GetWriteBarrierType(slot, *slot, params)) {
+ case HeapConsistency::WriteBarrierType::kMarking:
+ HeapConsistency::DijkstraWriteBarrier(params, *slot);
+ break;
+ case HeapConsistency::WriteBarrierType::kGenerational:
+ HeapConsistency::GenerationalBarrier(params, slot);
+ break;
+ case HeapConsistency::WriteBarrierType::kNone:
+ break;
+ default:
+ break; // TODO(1056170): Remove default case when API is stable.
+ }
+ }
+
+ template <typename T>
+ static void TraceBackingStoreIfMarked(T** slot) {
+ HeapConsistency::WriteBarrierParams params;
+ if (HeapConsistency::GetWriteBarrierType(slot, *slot, params) ==
+ HeapConsistency::WriteBarrierType::kMarking) {
+ HeapConsistency::SteeleWriteBarrier(params, *slot);
+ }
+ }
+
+ template <typename T, typename Traits>
+ static void NotifyNewObject(T* slot_in_backing) {
+ HeapConsistency::WriteBarrierParams params;
+ // `slot_in_backing` points into a backing store and T is not necessarily a
+ // garbage collected type but may be kept inline.
+ switch (HeapConsistency::GetWriteBarrierType(
+ slot_in_backing, params, []() -> cppgc::HeapHandle& {
+ return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+ ->heap_handle();
+ })) {
+ case HeapConsistency::WriteBarrierType::kMarking:
+ HeapConsistency::DijkstraWriteBarrierRange(
+ params, slot_in_backing, sizeof(T), 1,
+ TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+ break;
+ case HeapConsistency::WriteBarrierType::kGenerational:
+ HeapConsistency::GenerationalBarrier(params, slot_in_backing);
+ break;
+ case HeapConsistency::WriteBarrierType::kNone:
+ break;
+ default:
+ break; // TODO(1056170): Remove default case when API is stable.
+ }
+ }
+
+ template <typename T, typename Traits>
+ static void NotifyNewObjects(T* first_element, size_t length) {
+ HeapConsistency::WriteBarrierParams params;
+ // `first_element` points into a backing store and T is not necessarily a
+ // garbage collected type but may be kept inline.
+ switch (HeapConsistency::GetWriteBarrierType(
+ first_element, params, []() -> cppgc::HeapHandle& {
+ return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+ ->heap_handle();
+ })) {
+ case HeapConsistency::WriteBarrierType::kMarking:
+ HeapConsistency::DijkstraWriteBarrierRange(
+ params, first_element, sizeof(T), length,
+ TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+ break;
+ case HeapConsistency::WriteBarrierType::kGenerational:
+ HeapConsistency::GenerationalBarrier(params, first_element);
+ break;
+ case HeapConsistency::WriteBarrierType::kNone:
+ break;
+ default:
+ break; // TODO(1056170): Remove default case when API is stable.
+ }
+ }
+
+ template <typename T, typename Traits>
+ static void Trace(Visitor* visitor, const T& t) {
+ TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
+ Traits>::Trace(visitor, &t);
+ }
+
+ template <typename T>
+ static void TraceVectorBacking(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot) {
+ visitor->RegisterMovableReference(const_cast<const HeapVectorBacking<T>**>(
+ reinterpret_cast<const HeapVectorBacking<T>* const*>(backing_slot)));
+ visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
+ }
+
+ template <typename T, typename HashTable>
+ static void TraceHashTableBackingStrongly(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot) {
+ visitor->RegisterMovableReference(
+ const_cast<const HeapHashTableBacking<HashTable>**>(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+ backing_slot)));
+ visitor->Trace(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
+ }
+
+ template <typename T, typename HashTable>
+ static void TraceHashTableBackingWeakly(Visitor* visitor,
+ const T* backing,
+ const T* const* backing_slot,
+ WeakCallback callback,
+ const void* parameter) {
+ visitor->RegisterMovableReference(
+ const_cast<const HeapHashTableBacking<HashTable>**>(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+ backing_slot)));
+ visitor->TraceWeakContainer(
+ reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
+ callback, parameter);
+ }
+
+ static bool DeferTraceToMutatorThreadIfConcurrent(Visitor* visitor,
+ const void* object,
+ TraceCallback callback,
+ size_t deferred_size) {
+ return visitor->DeferTraceToMutatorThreadIfConcurrent(object, callback,
+ deferred_size);
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h
new file mode 100644
index 00000000000..cce9cb8e210
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
+
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/testing.h"
+
+namespace blink {
+
+// Allows for overriding the stack state for the purpose of testing. Any garbage
+// collection calls scoped with `HeapPointersOnStackScope` will perform
+// conservative stack scanning, even if other (more local) hints indicate that
+// there's no need for it.
+class HeapPointersOnStackScope final {
+ STACK_ALLOCATED();
+
+ public:
+ explicit HeapPointersOnStackScope(const ThreadState* state)
+ : embedder_stack_state_(
+ state->cpp_heap().GetHeapHandle(),
+ cppgc::EmbedderStackState::kMayContainHeapPointers) {}
+
+ HeapPointersOnStackScope(const HeapPointersOnStackScope&) = delete;
+ HeapPointersOnStackScope& operator=(const HeapPointersOnStackScope&) = delete;
+
+ private:
+ cppgc::testing::OverrideEmbedderStackStateScope embedder_stack_state_;
+};
+
+class TestSupportingGC : public testing::Test {
+ public:
+ // Performs a precise garbage collection with eager sweeping.
+ static void PreciselyCollectGarbage() {
+ // TODO(1056170): Implement.
+ }
+
+ // Performs a conservative garbage collection with eager sweeping.
+ static void ConservativelyCollectGarbage() {
+ // TODO(1056170): Implement.
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
index 78f61452561..a734b3774ca 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "v8/include/cppgc/member.h"
namespace blink {
@@ -18,6 +19,31 @@ using WeakMember = cppgc::WeakMember<T>;
template <typename T>
using UntracedMember = cppgc::UntracedMember<T>;
+template <typename T>
+inline bool IsHashTableDeletedValue(const Member<T>& m) {
+ return m == cppgc::kSentinelPointer;
+}
+
+constexpr auto kMemberDeletedValue = cppgc::kSentinelPointer;
+
+template <typename T>
+struct ThreadingTrait<blink::Member<T>> {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+template <typename T>
+struct ThreadingTrait<blink::WeakMember<T>> {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+template <typename T>
+struct ThreadingTrait<blink::UntracedMember<T>> {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
index a7d0bc305f9..6ec1e7d7a28 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
@@ -5,7 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
+#include "base/bind.h"
+#include "third_party/blink/renderer/platform/bindings/buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "v8/include/cppgc/cross-thread-persistent.h"
#include "v8/include/cppgc/persistent.h"
+#include "v8/include/cppgc/source-location.h"
namespace blink {
@@ -15,6 +20,60 @@ using Persistent = cppgc::Persistent<T>;
template <typename T>
using WeakPersistent = cppgc::WeakPersistent<T>;
+template <typename T>
+using CrossThreadPersistent = cppgc::subtle::CrossThreadPersistent<T>;
+
+template <typename T>
+using CrossThreadWeakPersistent = cppgc::subtle::WeakCrossThreadPersistent<T>;
+
+using PersistentLocation = cppgc::SourceLocation;
+
+template <typename T>
+Persistent<T> WrapPersistent(
+ T* value,
+ const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+ return Persistent<T>(value, loc);
+}
+
+template <typename T>
+WeakPersistent<T> WrapWeakPersistent(
+ T* value,
+ const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+ return WeakPersistent<T>(value, loc);
+}
+
+template <typename T>
+CrossThreadPersistent<T> WrapCrossThreadPersistent(
+ T* value,
+ const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+ return CrossThreadPersistent<T>(value, loc);
+}
+
+template <typename T>
+CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(
+ T* value,
+ const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+ return CrossThreadWeakPersistent<T>(value, loc);
+}
+
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#define PERSISTENT_FROM_HERE PersistentLocation::Current()
+#else
+#define PERSISTENT_FROM_HERE PersistentLocation()
+#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+template <typename U, typename T, typename weakness>
+cppgc::internal::BasicPersistent<U, weakness> DownCast(
+ const cppgc::internal::BasicPersistent<T, weakness>& p) {
+ return p.template To<U>();
+}
+
+template <typename U, typename T, typename weakness>
+cppgc::internal::BasicCrossThreadPersistent<U, weakness> DownCast(
+ const cppgc::internal::BasicCrossThreadPersistent<T, weakness>& p) {
+ return p.template To<U>();
+}
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
index 254f163b74b..b28c8273f6e 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
@@ -5,6 +5,32 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
-// TODO(chromium:1056170): Implement wrapper.
+#include "gin/public/v8_platform.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/platform.h"
+#include "v8/include/cppgc/process-heap-statistics.h"
+
+namespace blink {
+
+// TODO(1056170): Implement wrapper.
+class PLATFORM_EXPORT ProcessHeap {
+ STATIC_ONLY(ProcessHeap);
+
+ public:
+ static void Init() {
+ cppgc::InitializeProcess(gin::V8Platform::Get()->GetPageAllocator());
+ }
+
+ static size_t TotalAllocatedObjectSize() {
+ return cppgc::ProcessHeapStatistics::TotalAllocatedObjectSize();
+ }
+
+ static size_t TotalAllocatedSpace() {
+ return cppgc::ProcessHeapStatistics::TotalAllocatedSpace();
+ }
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc
new file mode 100644
index 00000000000..d11b0694fe3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc
@@ -0,0 +1,143 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+
+#include "gin/public/v8_platform.h"
+#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "v8.h"
+#include "v8/include/v8-cppgc.h"
+
+namespace blink {
+
+// static
+base::LazyInstance<WTF::ThreadSpecific<ThreadState*>>::Leaky
+ ThreadState::thread_specific_ = LAZY_INSTANCE_INITIALIZER;
+
+// static
+alignas(ThreadState) uint8_t
+ ThreadState::main_thread_state_storage_[sizeof(ThreadState)];
+
+// static
+ThreadState* ThreadState::AttachMainThread() {
+ return new (main_thread_state_storage_) ThreadState();
+}
+
+// static
+ThreadState* ThreadState::AttachCurrentThread() {
+ return new ThreadState();
+}
+
+// static
+void ThreadState::DetachCurrentThread() {
+ auto* state = ThreadState::Current();
+ DCHECK(state);
+ delete state;
+}
+
+void ThreadState::AttachToIsolate(v8::Isolate* isolate,
+ V8BuildEmbedderGraphCallback) {
+ isolate->AttachCppHeap(cpp_heap_.get());
+ CHECK_EQ(cpp_heap_.get(), isolate->GetCppHeap());
+ isolate_ = isolate;
+}
+
+void ThreadState::DetachFromIsolate() {
+ CHECK_EQ(cpp_heap_.get(), isolate_->GetCppHeap());
+ isolate_->DetachCppHeap();
+ isolate_ = nullptr;
+}
+
+namespace {
+
+std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> CreateCustomSpaces() {
+ std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> spaces;
+ spaces.emplace_back(std::make_unique<HeapVectorBackingSpace>());
+ spaces.emplace_back(std::make_unique<HeapHashTableBackingSpace>());
+ spaces.emplace_back(std::make_unique<NodeSpace>());
+ spaces.emplace_back(std::make_unique<CSSValueSpace>());
+ return spaces;
+}
+
+} // namespace
+
+ThreadState::ThreadState()
+ : cpp_heap_(v8::CppHeap::Create(
+ gin::V8Platform::Get(),
+ {CreateCustomSpaces(),
+ v8::WrapperDescriptor(kV8DOMWrapperTypeIndex,
+ kV8DOMWrapperObjectIndex,
+ gin::GinEmbedder::kEmbedderBlink)})),
+ allocation_handle_(cpp_heap_->GetAllocationHandle()),
+ heap_handle_(cpp_heap_->GetHeapHandle()),
+ thread_id_(CurrentThread()) {
+ *(thread_specific_.Get()) = this;
+}
+
+ThreadState::~ThreadState() {
+ DCHECK(!IsMainThread());
+ DCHECK(IsCreationThread());
+ cpp_heap_->Terminate();
+}
+
+void ThreadState::SafePoint(BlinkGC::StackState stack_state) {
+ DCHECK(IsCreationThread());
+ if (stack_state != BlinkGC::kNoHeapPointersOnStack)
+ return;
+
+ if (forced_scheduled_gc_for_testing_) {
+ CollectAllGarbageForTesting(stack_state);
+ forced_scheduled_gc_for_testing_ = false;
+ }
+}
+
+void ThreadState::NotifyGarbageCollection(v8::GCType type,
+ v8::GCCallbackFlags flags) {
+ if (flags & v8::kGCCallbackFlagForced) {
+ // Forces a precise GC at the end of the current event loop. This is
+ // required for testing code that cannot use GC internals but rather has
+ // to rely on window.gc(). Only schedule additional GCs if the last GC was
+ // using conservative stack scanning.
+ if (type == v8::kGCTypeScavenge) {
+ forced_scheduled_gc_for_testing_ = true;
+ } else if (type == v8::kGCTypeMarkSweepCompact) {
+ // TODO(1056170): Only need to schedule a forced GC if stack was scanned
+ // conservatively in previous GC.
+ forced_scheduled_gc_for_testing_ = true;
+ }
+ }
+}
+
+void ThreadState::CollectAllGarbageForTesting(BlinkGC::StackState stack_state) {
+ // Should only be used when attached to V8.
+ CHECK(isolate_);
+ size_t previous_live_bytes = 0;
+ for (size_t i = 0; i < 5; i++) {
+ // CppHeap registers itself as EmbedderHeapTracer internally.
+ isolate_->GetEmbedderHeapTracer()->GarbageCollectionForTesting(
+ stack_state == BlinkGC::kHeapPointersOnStack
+ ? cppgc::EmbedderStackState::kMayContainHeapPointers
+ : cppgc::EmbedderStackState::kNoHeapPointers);
+ const size_t live_bytes =
+ cpp_heap()
+ .CollectStatistics(cppgc::HeapStatistics::kBrief)
+ .used_size_bytes;
+ if (previous_live_bytes == live_bytes) {
+ break;
+ }
+ previous_live_bytes = live_bytes;
+ }
+}
+
+void ThreadState::CollectNodeAndCssStatistics(
+ base::OnceCallback<void(size_t allocated_node_bytes,
+ size_t allocated_css_bytes)> callback) {
+ // TODO(1181269): Implement.
+ std::move(callback).Run(0u, 0u);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
index eea17788057..831531bbee4 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
@@ -5,13 +5,162 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
+#include "third_party/blink/renderer/platform/wtf/threading.h"
+#include "v8-profiler.h"
+#include "v8/include/cppgc/heap-consistency.h"
#include "v8/include/cppgc/prefinalizer.h"
+#include "v8/include/v8-cppgc.h"
+#include "v8/include/v8.h"
+
+namespace v8 {
+class CppHeap;
+} // namespace v8
+
+namespace cppgc {
+class AllocationHandle;
+} // namespace cppgc
+
+namespace v8 {
+class EmbedderGraph;
+} // namespace v8
namespace blink {
#define USING_PRE_FINALIZER(Class, PreFinalizer) \
CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer)
+// ThreadAffinity indicates which threads objects can be used on. We
+// distinguish between objects that can be used on the main thread
+// only and objects that can be used on any thread.
+//
+// For objects that can only be used on the main thread, we avoid going
+// through thread-local storage to get to the thread state. This is
+// important for performance.
+enum ThreadAffinity {
+ kAnyThread,
+ kMainThreadOnly,
+};
+
+template <typename T, typename = void>
+struct ThreadingTrait {
+ STATIC_ONLY(ThreadingTrait);
+ static constexpr ThreadAffinity kAffinity = kAnyThread;
+};
+
+template <ThreadAffinity>
+class ThreadStateFor;
+class ThreadState;
+
+using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
+ v8::EmbedderGraph*,
+ void*);
+
+class PLATFORM_EXPORT ThreadState final {
+ public:
+ class NoAllocationScope;
+
+ static ALWAYS_INLINE ThreadState* Current() {
+ return *(thread_specific_.Get());
+ }
+
+ static ALWAYS_INLINE ThreadState* MainThreadState() {
+ return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
+ }
+
+ // Attaches a ThreadState to the main-thread.
+ static ThreadState* AttachMainThread();
+ // Attaches a ThreadState to the currently running thread. Must not be the
+ // main thread and must be called after AttachMainThread().
+ static ThreadState* AttachCurrentThread();
+ static void DetachCurrentThread();
+
+ void AttachToIsolate(v8::Isolate* isolate, V8BuildEmbedderGraphCallback);
+ void DetachFromIsolate();
+
+ ALWAYS_INLINE cppgc::AllocationHandle& allocation_handle() const {
+ return allocation_handle_;
+ }
+ ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
+ ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }
+ ALWAYS_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
+
+ // Forced garbage collection for testing:
+ //
+ // Collects garbage as long as live memory decreases (capped at 5).
+ void CollectAllGarbageForTesting(
+ BlinkGC::StackState stack_state =
+ BlinkGC::StackState::kNoHeapPointersOnStack);
+
+ void SafePoint(BlinkGC::StackState);
+
+ bool IsMainThread() const { return this == MainThreadState(); }
+ bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
+
+ void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
+
+ bool InAtomicSweepingPause() const {
+ auto& heap_handle = cpp_heap().GetHeapHandle();
+ return cppgc::subtle::HeapState::IsInAtomicPause(heap_handle) &&
+ cppgc::subtle::HeapState::IsSweeping(heap_handle);
+ }
+
+ bool IsAllocationAllowed() const {
+ return cppgc::subtle::DisallowGarbageCollectionScope::
+ IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
+ }
+
+ // Waits until sweeping is done and invokes the given callback with
+ // the total sizes of live objects in Node and CSS arenas.
+ void CollectNodeAndCssStatistics(
+ base::OnceCallback<void(size_t allocated_node_bytes,
+ size_t allocated_css_bytes)>);
+
+ private:
+ // Main-thread ThreadState avoids TLS completely by using a regular global.
+ // The object is manually managed and should not rely on global ctor/dtor.
+ static uint8_t main_thread_state_storage_[];
+ // Storage for all ThreadState objects. This includes the main-thread
+ // ThreadState as well.
+ static base::LazyInstance<WTF::ThreadSpecific<ThreadState*>>::Leaky
+ thread_specific_;
+
+ explicit ThreadState();
+ ~ThreadState();
+
+ std::unique_ptr<v8::CppHeap> cpp_heap_;
+ cppgc::AllocationHandle& allocation_handle_;
+ cppgc::HeapHandle& heap_handle_;
+ v8::Isolate* isolate_ = nullptr;
+ base::PlatformThreadId thread_id_;
+ bool forced_scheduled_gc_for_testing_ = false;
+};
+
+template <>
+class ThreadStateFor<kMainThreadOnly> {
+ STATIC_ONLY(ThreadStateFor);
+
+ public:
+ static ALWAYS_INLINE ThreadState* GetState() {
+ return ThreadState::MainThreadState();
+ }
+};
+
+template <>
+class ThreadStateFor<kAnyThread> {
+ STATIC_ONLY(ThreadStateFor);
+
+ public:
+ static ALWAYS_INLINE ThreadState* GetState() {
+ return ThreadState::Current();
+ }
+};
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
index 8378cf6722f..bec9605a0c6 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
@@ -5,6 +5,27 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
-// TODO(chromium:1056170): Implement wrapper.
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "v8/include/cppgc/heap-consistency.h"
+
+namespace blink {
+
+// The NoAllocationScope class is used in debug mode to catch unwanted
+// allocations. E.g. allocations during GC.
+class ThreadState::NoAllocationScope final {
+ STACK_ALLOCATED();
+
+ public:
+ explicit NoAllocationScope(ThreadState* state)
+ : disallow_gc_(state->cpp_heap().GetHeapHandle()) {}
+
+ NoAllocationScope(const NoAllocationScope&) = delete;
+ NoAllocationScope& operator=(const NoAllocationScope&) = delete;
+
+ private:
+ const cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_;
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h
new file mode 100644
index 00000000000..75037198fb1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
+
+#include <tuple>
+
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "v8/include/cppgc/trace-trait.h"
+
+namespace blink {
+
+template <typename T, bool = WTF::IsTraceable<T>::value>
+struct TraceIfNeeded;
+
+template <typename T>
+struct TraceIfNeeded<T, false> {
+ STATIC_ONLY(TraceIfNeeded);
+ static void Trace(Visitor*, const T&) {}
+};
+
+template <typename T>
+struct TraceIfNeeded<T, true> {
+ STATIC_ONLY(TraceIfNeeded);
+ static void Trace(Visitor* visitor, const T& t) { visitor->Trace(t); }
+};
+
+} // namespace blink
+
+namespace cppgc {
+
+// This trace trait for std::pair will null weak members if their referent is
+// collected. If you have a collection that contain weakness it does not remove
+// entries from the collection that contain nulled weak members.
+template <typename T, typename U>
+struct TraceTrait<std::pair<T, U>> {
+ STATIC_ONLY(TraceTrait);
+
+ public:
+ static TraceDescriptor GetTraceDescriptor(const void* self) {
+ return {self, Trace};
+ }
+
+ static void Trace(Visitor* visitor, const std::pair<T, U>* pair) {
+ blink::TraceIfNeeded<U>::Trace(visitor, pair->second);
+ blink::TraceIfNeeded<T>::Trace(visitor, pair->first);
+ }
+};
+
+} // namespace cppgc
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
index 0a4d66e2fe4..cd2871aef9b 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
@@ -5,6 +5,46 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
-// TODO(chromium:1056170): Implement wrapper.
+#include "base/compiler_specific.h"
+#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
+#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/v8-cppgc.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT UnifiedHeapMarkingVisitor final {
+ STATIC_ONLY(UnifiedHeapMarkingVisitor);
+
+ public:
+ static ALWAYS_INLINE void WriteBarrier(
+ const v8::TracedReference<v8::Value>& ref) {
+ v8::JSHeapConsistency::WriteBarrierParams params;
+ if (v8::JSHeapConsistency::GetWriteBarrierType(
+ ref, params, []() -> cppgc::HeapHandle& {
+ return ThreadState::Current()->heap_handle();
+ }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
+ v8::JSHeapConsistency::DijkstraMarkingBarrier(
+ params, ThreadState::Current()->heap_handle(), ref);
+ }
+ }
+
+ static ALWAYS_INLINE void WriteBarrier(v8::Isolate*,
+ v8::Local<v8::Object>& wrapper,
+ const WrapperTypeInfo*,
+ const void* wrappable) {
+ v8::JSHeapConsistency::WriteBarrierParams params;
+ if (v8::JSHeapConsistency::GetWriteBarrierType(
+ wrapper, kV8DOMWrapperObjectIndex, wrappable, params,
+ []() -> cppgc::HeapHandle& {
+ return ThreadState::Current()->heap_handle();
+ }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
+ v8::JSHeapConsistency::DijkstraMarkingBarrier(
+ params, ThreadState::Current()->heap_handle(), wrappable);
+ }
+ }
+};
+
+} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
index abb9204f467..a7da1cc907f 100644
--- a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "v8/include/cppgc/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/heap/visitor.h b/chromium/third_party/blink/renderer/platform/heap/visitor.h
index 31e342005ae..5ace61daa9e 100644
--- a/chromium/third_party/blink/renderer/platform/heap/visitor.h
+++ b/chromium/third_party/blink/renderer/platform/heap/visitor.h
@@ -5,12 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
-#include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
-#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#if BUILDFLAG(USE_V8_OILPAN)
#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h"
-#else // !BLINK_HEAP_USE_V8_OILPAN
+#else // !USE_V8_OILPAN
#include "third_party/blink/renderer/platform/heap/impl/visitor.h"
-#endif // !BLINK_HEAP_USE_V8_OILPAN
+#endif // !USE_V8_OILPAN
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/DIR_METADATA b/chromium/third_party/blink/renderer/platform/image-decoders/DIR_METADATA
new file mode 100644
index 00000000000..a953732cf09
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Images>Codecs"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/OWNERS b/chromium/third_party/blink/renderer/platform/image-decoders/OWNERS
index f6310a37e22..aa51698e07c 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/OWNERS
@@ -2,5 +2,3 @@ urvang@chromium.org
pkasting@chromium.org
noel@chromium.org
scroggo@google.com
-
-# COMPONENT: Internals>Images>Codecs
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
index e4cee28a769..baa4c877d23 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
@@ -29,7 +29,6 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/libavif/src/include/avif/avif.h"
#include "third_party/libyuv/include/libyuv.h"
-#include "third_party/skia/include/core/SkData.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_transform.h"
#include "ui/gfx/half_float.h"
@@ -41,6 +40,11 @@
namespace {
+// The maximum AVIF file size we are willing to decode. This helps libavif
+// detect invalid sizes and offsets in an AVIF file before the file size is
+// known.
+constexpr uint64_t kMaxAvifFileSize = 0x10000000; // 256 MB
+
// Builds a gfx::ColorSpace from the ITU-T H.273 (CICP) color description in the
// image. This color space is used to create the gfx::ColorTransform for the
// YUV-to-RGB conversion. If the image does not have an ICC profile, this color
@@ -271,11 +275,17 @@ bool AVIFImageDecoder::ImageIsHighBitDepth() {
}
void AVIFImageDecoder::OnSetData(SegmentReader* data) {
- // avifDecoder requires all the data be available before reading and cannot
- // read incrementally as data comes in. See
- // https://github.com/AOMediaCodec/libavif/issues/11.
- if (IsAllDataReceived() && !MaybeCreateDemuxer())
- SetFailed();
+ have_parsed_current_data_ = false;
+ const bool all_data_received = IsAllDataReceived();
+ avif_io_data_.reader = data_.get();
+ avif_io_data_.all_data_received = all_data_received;
+ avif_io_.sizeHint = all_data_received ? data_->size() : kMaxAvifFileSize;
+
+ // ImageFrameGenerator::GetYUVAInfo() and ImageFrameGenerator::DecodeToYUV()
+ // assume that allow_decode_to_yuv_ and other image metadata are available
+ // after calling ImageDecoder::Create() with data_complete=true.
+ if (all_data_received)
+ ParseMetadata();
}
cc::YUVSubsampling AVIFImageDecoder::GetYUVSubsampling() const {
@@ -355,7 +365,7 @@ void AVIFImageDecoder::DecodeToYUV() {
// libavif cannot decode to an external buffer. So we need to copy from
// libavif's internal buffer to |image_planes_|.
// TODO(crbug.com/1099825): Enhance libavif to decode to an external buffer.
- if (!DecodeImage(0)) {
+ if (DecodeImage(0) != AVIF_RESULT_OK) {
SetFailed();
return;
}
@@ -443,12 +453,31 @@ void AVIFImageDecoder::DecodeToYUV() {
height = UVSize(height, chroma_shift_y_);
}
}
+ image_planes_->SetHasCompleteScan();
}
int AVIFImageDecoder::RepetitionCount() const {
return decoded_frame_count_ > 1 ? kAnimationLoopInfinite : kAnimationNone;
}
+bool AVIFImageDecoder::FrameIsReceivedAtIndex(size_t index) const {
+ if (!IsDecodedSizeAvailable())
+ return false;
+ if (decoded_frame_count_ == 1)
+ return ImageDecoder::FrameIsReceivedAtIndex(index);
+ if (index >= frame_buffer_cache_.size())
+ return false;
+ if (IsAllDataReceived())
+ return true;
+ avifExtent dataExtent;
+ if (avifDecoderNthImageMaxExtent(decoder_.get(), index, &dataExtent) !=
+ AVIF_RESULT_OK) {
+ return false;
+ }
+ return dataExtent.size == 0 ||
+ dataExtent.offset + dataExtent.size <= data_->size();
+}
+
base::TimeDelta AVIFImageDecoder::FrameDurationAtIndex(size_t index) const {
return index < frame_buffer_cache_.size()
? frame_buffer_cache_[index].Duration()
@@ -496,15 +525,20 @@ gfx::ColorTransform* AVIFImageDecoder::GetColorTransformForTesting() {
return color_transform_.get();
}
+void AVIFImageDecoder::ParseMetadata() {
+ if (!UpdateDemuxer())
+ SetFailed();
+}
+
void AVIFImageDecoder::DecodeSize() {
- // Because avifDecoder cannot read incrementally as data comes in, we cannot
- // decode the size until all data is received. When all data is received,
- // OnSetData() decodes the size right away. So DecodeSize() doesn't need to do
- // anything.
+ ParseMetadata();
}
size_t AVIFImageDecoder::DecodeFrameCount() {
- return Failed() ? frame_buffer_cache_.size() : decoded_frame_count_;
+ if (!Failed())
+ ParseMetadata();
+ return IsDecodedSizeAvailable() ? decoded_frame_count_
+ : frame_buffer_cache_.size();
}
void AVIFImageDecoder::InitializeNewFrame(size_t index) {
@@ -522,16 +556,15 @@ void AVIFImageDecoder::InitializeNewFrame(size_t index) {
}
void AVIFImageDecoder::Decode(size_t index) {
- // TODO(dalecurtis): For fragmented AVIF image sequence files we probably want
- // to allow partial decoding. Depends on if we see frequent use of multi-track
- // images where there's lots to ignore.
- if (Failed() || !IsAllDataReceived())
+ if (Failed())
return;
UpdateAggressivePurging(index);
- if (!DecodeImage(index)) {
- SetFailed();
+ auto ret = DecodeImage(index);
+ if (ret != AVIF_RESULT_OK) {
+ if (ret != AVIF_RESULT_WAITING_ON_IO)
+ SetFailed();
return;
}
@@ -575,6 +608,7 @@ void AVIFImageDecoder::Decode(size_t index) {
buffer.SetPixelsChanged(true);
buffer.SetHasAlpha(!!image->alphaPlane);
buffer.SetStatus(ImageFrame::kFrameComplete);
+ PostDecodeProcessing(index);
}
bool AVIFImageDecoder::CanReusePreviousFrameBuffer(size_t index) const {
@@ -586,46 +620,102 @@ bool AVIFImageDecoder::CanReusePreviousFrameBuffer(size_t index) const {
return true;
}
-bool AVIFImageDecoder::MaybeCreateDemuxer() {
- if (decoder_)
- return true;
+// static
+avifResult AVIFImageDecoder::ReadFromSegmentReader(avifIO* io,
+ uint32_t read_flags,
+ uint64_t offset,
+ size_t size,
+ avifROData* out) {
+ if (read_flags != 0) {
+ // Unsupported read_flags
+ return AVIF_RESULT_IO_ERROR;
+ }
- decoder_ = std::unique_ptr<avifDecoder, void (*)(avifDecoder*)>(
- avifDecoderCreate(), avifDecoderDestroy);
- if (!decoder_)
- return false;
+ AvifIOData* io_data = static_cast<AvifIOData*>(io->data);
- // TODO(dalecurtis): This may create a second copy of the media data in
- // memory, which is not great. libavif should provide a read() based API:
- // https://github.com/AOMediaCodec/libavif/issues/11
- image_data_ = data_->GetAsSkData();
- if (!image_data_)
- return false;
+ // Sanitize/clamp incoming request
+ if (offset > io_data->reader->size()) {
+ // The offset is past the end of the buffer or available data.
+ return io_data->all_data_received ? AVIF_RESULT_IO_ERROR
+ : AVIF_RESULT_WAITING_ON_IO;
+ }
- // TODO(wtc): Currently libavif always prioritizes the animation, but that's
- // not correct. It should instead select animation or still image based on the
- // preferred and major brands listed in the file.
- if (animation_option_ != AnimationOption::kUnspecified &&
- avifDecoderSetSource(
- decoder_.get(), animation_option_ == AnimationOption::kPreferAnimation
- ? AVIF_DECODER_SOURCE_TRACKS
- : AVIF_DECODER_SOURCE_PRIMARY_ITEM) !=
- AVIF_RESULT_OK) {
- return false;
+ // It is more convenient to work with a variable of the size_t type. Since
+ // offset <= io_data->reader->size() <= SIZE_MAX, this cast is safe.
+ size_t position = static_cast<size_t>(offset);
+ const size_t available_size = io_data->reader->size() - position;
+ if (size > available_size) {
+ if (!io_data->all_data_received)
+ return AVIF_RESULT_WAITING_ON_IO;
+ size = available_size;
}
- // Chrome doesn't use XMP and Exif metadata. Ignoring XMP and Exif will ensure
- // avifDecoderParse() isn't waiting for some tiny Exif payload hiding at the
- // end of a file.
- decoder_->ignoreXMP = AVIF_TRUE;
- decoder_->ignoreExif = AVIF_TRUE;
- auto ret = avifDecoderSetIOMemory(decoder_.get(), image_data_->bytes(),
- image_data_->size());
- if (ret != AVIF_RESULT_OK) {
- DVLOG(1) << "avifDecoderSetIOMemory failed: " << avifResultToString(ret);
- return false;
+ out->size = size;
+ const char* data;
+ size_t data_size = io_data->reader->GetSomeData(data, position);
+ if (data_size >= size) {
+ out->data = reinterpret_cast<const uint8_t*>(data);
+ return AVIF_RESULT_OK;
+ }
+
+ io_data->buffer.clear();
+ io_data->buffer.reserve(size);
+ while (size != 0) {
+ data_size = io_data->reader->GetSomeData(data, position);
+ size_t copy_size = std::min(data_size, size);
+ io_data->buffer.insert(io_data->buffer.end(), data, data + copy_size);
+ position += copy_size;
+ size -= copy_size;
}
- ret = avifDecoderParse(decoder_.get());
+
+ out->data = io_data->buffer.data();
+ return AVIF_RESULT_OK;
+}
+
+bool AVIFImageDecoder::UpdateDemuxer() {
+ DCHECK(!Failed());
+ if (IsDecodedSizeAvailable())
+ return true;
+
+ if (have_parsed_current_data_)
+ return true;
+ have_parsed_current_data_ = true;
+
+ if (!decoder_) {
+ decoder_ = std::unique_ptr<avifDecoder, void (*)(avifDecoder*)>(
+ avifDecoderCreate(), avifDecoderDestroy);
+ if (!decoder_)
+ return false;
+
+ // TODO(wtc): Currently libavif always prioritizes the animation, but that's
+ // not correct. It should instead select animation or still image based on
+ // the preferred and major brands listed in the file.
+ if (animation_option_ != AnimationOption::kUnspecified &&
+ avifDecoderSetSource(
+ decoder_.get(),
+ animation_option_ == AnimationOption::kPreferAnimation
+ ? AVIF_DECODER_SOURCE_TRACKS
+ : AVIF_DECODER_SOURCE_PRIMARY_ITEM) != AVIF_RESULT_OK) {
+ return false;
+ }
+
+ // Chrome doesn't use XMP and Exif metadata. Ignoring XMP and Exif will
+ // ensure avifDecoderParse() isn't waiting for some tiny Exif payload hiding
+ // at the end of a file.
+ decoder_->ignoreXMP = AVIF_TRUE;
+ decoder_->ignoreExif = AVIF_TRUE;
+
+ avif_io_.destroy = nullptr;
+ avif_io_.read = ReadFromSegmentReader;
+ avif_io_.write = nullptr;
+ avif_io_.persistent = AVIF_FALSE;
+ avif_io_.data = &avif_io_data_;
+ avifDecoderSetIO(decoder_.get(), &avif_io_);
+ }
+
+ auto ret = avifDecoderParse(decoder_.get());
+ if (ret == AVIF_RESULT_WAITING_ON_IO)
+ return true;
if (ret != AVIF_RESULT_OK) {
DVLOG(1) << "avifDecoderParse failed: " << avifResultToString(ret);
return false;
@@ -709,6 +799,45 @@ bool AVIFImageDecoder::MaybeCreateDemuxer() {
}
}
+ // |angle| * 90 specifies the angle of anti-clockwise rotation in degrees.
+ // Legal values: [0-3].
+ int angle = 0;
+ if (container->transformFlags & AVIF_TRANSFORM_IROT)
+ angle = container->irot.angle;
+ // |axis| specifies the axis for the mirroring operation.
+ // -1: No mirroring.
+ // 0: Mirror about a vertical axis ("left-to-right").
+ // 1: Mirror about a horizontal axis ("top-to-bottom").
+ int axis = -1;
+ if (container->transformFlags & AVIF_TRANSFORM_IMIR)
+ axis = container->imir.axis;
+ // MIAF Section 7.3.6.7 (Clean aperture, rotation and mirror) says:
+ // These properties, if used, shall be indicated to be applied in the
+ // following order: clean aperture first, then rotation, then mirror.
+ //
+ // In the kAxisAngleToOrientation array, the first dimension is axis (with an
+ // offset of 1). The second dimension is angle.
+ constexpr ImageOrientationEnum kAxisAngleToOrientation[3][4] = {
+ // No mirroring.
+ {ImageOrientationEnum::kOriginTopLeft,
+ ImageOrientationEnum::kOriginLeftBottom,
+ ImageOrientationEnum::kOriginBottomRight,
+ ImageOrientationEnum::kOriginRightTop},
+ // Mirror about a vertical axis ("left-to-right"). Change Left<->Right in
+ // the first row.
+ {ImageOrientationEnum::kOriginTopRight,
+ ImageOrientationEnum::kOriginRightBottom,
+ ImageOrientationEnum::kOriginBottomLeft,
+ ImageOrientationEnum::kOriginLeftTop},
+ // Mirror about a horizontal axis ("top-to-bottom"). Change Top<->Bottom
+ // in the first row.
+ {ImageOrientationEnum::kOriginBottomLeft,
+ ImageOrientationEnum::kOriginLeftTop,
+ ImageOrientationEnum::kOriginTopRight,
+ ImageOrientationEnum::kOriginRightBottom},
+ };
+ orientation_ = kAxisAngleToOrientation[axis + 1][angle];
+
// Determine whether the image can be decoded to YUV.
// * Alpha channel is not supported.
// * Multi-frame images (animations) are not supported. (The DecodeToYUV()
@@ -723,12 +852,12 @@ bool AVIFImageDecoder::MaybeCreateDemuxer() {
return SetSize(container->width, container->height);
}
-bool AVIFImageDecoder::DecodeImage(size_t index) {
+avifResult AVIFImageDecoder::DecodeImage(size_t index) {
const auto ret = avifDecoderNthImage(decoder_.get(), index);
// |index| should be less than what DecodeFrameCount() returns, so we should
// not get the AVIF_RESULT_NO_IMAGES_REMAINING error.
DCHECK_NE(ret, AVIF_RESULT_NO_IMAGES_REMAINING);
- return ret == AVIF_RESULT_OK;
+ return ret;
}
void AVIFImageDecoder::UpdateColorTransform(const gfx::ColorSpace& frame_cs,
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
index b3de5b6c3a8..098f8ba5aea 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
@@ -8,14 +8,11 @@
#include <memory>
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkData.h"
+#include "third_party/libavif/src/include/avif/avif.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_transform.h"
-struct avifDecoder;
-struct avifImage;
-
namespace blink {
class FastSharedBufferReader;
@@ -42,6 +39,7 @@ class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder {
uint8_t GetYUVBitDepth() const override;
void DecodeToYUV() override;
int RepetitionCount() const override;
+ bool FrameIsReceivedAtIndex(size_t) const override;
base::TimeDelta FrameDurationAtIndex(size_t) const override;
bool ImageHasBothStillAndAnimatedSubImages() const override;
@@ -52,6 +50,14 @@ class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder {
gfx::ColorTransform* GetColorTransformForTesting();
private:
+ struct AvifIOData {
+ blink::SegmentReader* reader = nullptr;
+ std::vector<uint8_t> buffer;
+ bool all_data_received = false;
+ };
+
+ void ParseMetadata();
+
// ImageDecoder:
void DecodeSize() override;
size_t DecodeFrameCount() override;
@@ -59,12 +65,19 @@ class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder {
void Decode(size_t) override;
bool CanReusePreviousFrameBuffer(size_t) const override;
- // Creates |decoder_| and decodes the size and frame count.
- bool MaybeCreateDemuxer();
+ // Implements avifIOReadFunc, the |read| function in the avifIO struct.
+ static avifResult ReadFromSegmentReader(avifIO* io,
+ uint32_t read_flags,
+ uint64_t offset,
+ size_t size,
+ avifROData* out);
+
+ // Creates |decoder_| if not yet created and decodes the size and frame count.
+ bool UpdateDemuxer();
// Decodes the frame at index |index|. The decoded frame is available in
- // decoder_->image. Returns whether decoding completed successfully.
- bool DecodeImage(size_t index);
+ // decoder_->image.
+ avifResult DecodeImage(size_t index);
// Updates or creates |color_transform_| for YUV-to-RGB conversion.
void UpdateColorTransform(const gfx::ColorSpace& frame_cs, int bit_depth);
@@ -77,24 +90,24 @@ class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder {
// desired.
void ColorCorrectImage(ImageFrame* buffer);
+ bool have_parsed_current_data_ = false;
// The bit depth from the container.
uint8_t bit_depth_ = 0;
bool decode_to_half_float_ = false;
- // The YUV format from the container. Stores an avifPixelFormat enum value.
- // Declared as uint8_t because we can't forward-declare an enum type in C++.
- uint8_t avif_yuv_format_ = 0; // AVIF_PIXEL_FORMAT_NONE
uint8_t chroma_shift_x_ = 0;
uint8_t chroma_shift_y_ = 0;
+ // The YUV format from the container.
+ avifPixelFormat avif_yuv_format_ = AVIF_PIXEL_FORMAT_NONE;
size_t decoded_frame_count_ = 0;
SkYUVColorSpace yuv_color_space_ = SkYUVColorSpace::kIdentity_SkYUVColorSpace;
std::unique_ptr<avifDecoder, void (*)(avifDecoder*)> decoder_{nullptr,
nullptr};
+ avifIO avif_io_ = {};
+ AvifIOData avif_io_data_;
std::unique_ptr<gfx::ColorTransform> color_transform_;
const AnimationOption animation_option_;
-
- sk_sp<SkData> image_data_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc
index 94b7158a757..fb057acd9dd 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc
@@ -11,11 +11,18 @@
#include "base/bit_cast.h"
#include "base/strings/stringprintf.h"
+#include "media/media_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/libavif/src/include/avif/avif.h"
+// If the AV1 decoder library supports the bit depth 12, define
+// HAVE_AVIF_BIT_DEPTH_12_SUPPORT.
+#if BUILDFLAG(ENABLE_DAV1D_DECODER)
+#define HAVE_AVIF_BIT_DEPTH_12_SUPPORT
+#endif
+
#define FIXME_SUPPORT_ICC_PROFILE_NO_TRANSFORM 0
#define FIXME_SUPPORT_ICC_PROFILE_TRANSFORM 0
#define FIXME_DISTINGUISH_LOSSY_OR_LOSSLESS 0
@@ -59,6 +66,7 @@ struct StaticColorCheckParam {
ImageDecoder::CompressionFormat compression_format;
ImageDecoder::AlphaOption alpha_option;
ColorBehavior color_behavior;
+ ImageOrientation orientation;
int color_threshold;
std::vector<ExpectedColor> colors;
};
@@ -92,11 +100,39 @@ std::ostream& operator<<(std::ostream& os, const StaticColorCheckParam& param) {
DCHECK(param.color_behavior.IsTransformToSRGB());
color_behavior = "TransformToSRGB";
}
+ const char* orientation;
+ switch (param.orientation.Orientation()) {
+ case ImageOrientationEnum::kOriginTopLeft:
+ orientation = "kOriginTopLeft";
+ break;
+ case ImageOrientationEnum::kOriginTopRight:
+ orientation = "kOriginTopRight";
+ break;
+ case ImageOrientationEnum::kOriginBottomRight:
+ orientation = "kOriginBottomRight";
+ break;
+ case ImageOrientationEnum::kOriginBottomLeft:
+ orientation = "kOriginBottomLeft";
+ break;
+ case ImageOrientationEnum::kOriginLeftTop:
+ orientation = "kOriginLeftTop";
+ break;
+ case ImageOrientationEnum::kOriginRightTop:
+ orientation = "kOriginRightTop";
+ break;
+ case ImageOrientationEnum::kOriginRightBottom:
+ orientation = "kOriginRightBottom";
+ break;
+ case ImageOrientationEnum::kOriginLeftBottom:
+ orientation = "kOriginLeftBottom";
+ break;
+ }
return os << "\nStaticColorCheckParam {\n path: \"" << param.path
<< "\",\n bit_depth: " << param.bit_depth
<< ",\n color_type: " << color_type
<< ",\n alpha_option: " << alpha_option
- << ",\n color_behavior: " << color_behavior << "\n}";
+ << ",\n color_behavior: " << color_behavior
+ << ",\n orientation: " << orientation << "\n}";
}
StaticColorCheckParam kTestParams[] = {
@@ -107,6 +143,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLossyFormat,
ImageDecoder::kAlphaNotPremultiplied, // q=60(lossy)
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
0,
{}, // we just check that this image is lossy.
},
@@ -117,6 +154,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLossyFormat,
ImageDecoder::kAlphaNotPremultiplied, // q=60(lossy)
ColorBehavior::Ignore(),
+ ImageOrientationEnum::kOriginTopLeft,
0,
{}, // we just check that the decoder won't crash when
// ColorBehavior::Ignore() is used.
@@ -127,6 +165,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
3,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -139,6 +178,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -151,6 +191,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
3,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
@@ -163,6 +204,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
3,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
@@ -175,6 +217,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 192, 192, 192)},
@@ -187,6 +230,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -199,6 +243,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -211,6 +256,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
3,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)},
@@ -224,6 +270,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Ignore(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)},
@@ -238,6 +285,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
/*
@@ -255,6 +303,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -267,6 +316,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -279,6 +329,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)},
@@ -291,6 +342,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
2,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
@@ -303,6 +355,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -315,6 +368,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -328,6 +382,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Ignore(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)},
@@ -342,6 +397,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
/*
@@ -359,6 +415,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -371,6 +428,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)},
@@ -383,6 +441,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)},
@@ -395,6 +454,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
2,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
@@ -407,6 +467,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -419,6 +480,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)},
@@ -432,6 +494,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::Ignore(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
{gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)},
@@ -446,6 +509,7 @@ StaticColorCheckParam kTestParams[] = {
ImageDecoder::kLosslessFormat,
ImageDecoder::kAlphaNotPremultiplied,
ColorBehavior::TransformToSRGB(),
+ ImageOrientationEnum::kOriginTopLeft,
1,
{
/*
@@ -457,13 +521,78 @@ StaticColorCheckParam kTestParams[] = {
{gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
}},
#endif
+ {"/images/resources/avif/red-full-range-angle-1-420-8bpc.avif",
+ 8,
+ ColorType::kRgb,
+ ImageDecoder::kLosslessFormat,
+ ImageDecoder::kAlphaNotPremultiplied,
+ ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginLeftBottom,
+ 3,
+ {
+ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
+ }},
+ {"/images/resources/avif/red-full-range-axis-0-420-8bpc.avif",
+ 8,
+ ColorType::kRgb,
+ ImageDecoder::kLosslessFormat,
+ ImageDecoder::kAlphaNotPremultiplied,
+ ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginTopRight,
+ 3,
+ {
+ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
+ }},
+ {"/images/resources/avif/red-full-range-axis-1-420-8bpc.avif",
+ 8,
+ ColorType::kRgb,
+ ImageDecoder::kLosslessFormat,
+ ImageDecoder::kAlphaNotPremultiplied,
+ ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginBottomLeft,
+ 3,
+ {
+ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
+ }},
+ {"/images/resources/avif/red-full-range-angle-2-axis-0-420-8bpc.avif",
+ 8,
+ ColorType::kRgb,
+ ImageDecoder::kLosslessFormat,
+ ImageDecoder::kAlphaNotPremultiplied,
+ ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginBottomLeft,
+ 3,
+ {
+ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
+ }},
+ {"/images/resources/avif/red-full-range-angle-3-axis-1-420-8bpc.avif",
+ 8,
+ ColorType::kRgb,
+ ImageDecoder::kLosslessFormat,
+ ImageDecoder::kAlphaNotPremultiplied,
+ ColorBehavior::Tag(),
+ ImageOrientationEnum::kOriginRightBottom,
+ 3,
+ {
+ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)},
+ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)},
+ }},
// TODO(ryoh): Add other color profile images, such as BT2020CL,
- // BT2020NCL, Rec601, SMPTE 274M
+ // SMPTE 274M
// TODO(ryoh): Add images with different combinations of ColorPrimaries,
// TransferFunction and MatrixCoefficients,
// such as:
// sRGB ColorPrimaries, BT.2020 TransferFunction and
- // BT.609 MatrixCoefficients
+ // BT.709 MatrixCoefficients
// TODO(ryoh): Add Mono + Alpha Images.
};
@@ -480,10 +609,12 @@ void TestInvalidStaticImage(const char* avif_file, ErrorPhase error_phase) {
decoder->SetData(data.get(), true);
if (error_phase == ErrorPhase::kParse) {
+ EXPECT_FALSE(decoder->IsSizeAvailable());
EXPECT_TRUE(decoder->Failed());
EXPECT_EQ(0u, decoder->FrameCount());
EXPECT_FALSE(decoder->DecodeFrameBufferAtIndex(0));
} else {
+ EXPECT_TRUE(decoder->IsSizeAvailable());
EXPECT_FALSE(decoder->Failed());
EXPECT_GT(decoder->FrameCount(), 0u);
ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
@@ -512,8 +643,12 @@ void ReadYUV(const char* file_name,
auto decoder = CreateAVIFDecoder();
decoder->SetData(data.get(), true);
- ASSERT_TRUE(decoder->IsSizeAvailable());
+ ASSERT_TRUE(decoder->IsDecodedSizeAvailable());
ASSERT_TRUE(decoder->CanDecodeToYUV());
+ EXPECT_NE(decoder->GetYUVSubsampling(), cc::YUVSubsampling::kUnknown);
+ EXPECT_NE(decoder->GetYUVColorSpace(),
+ SkYUVColorSpace::kIdentity_SkYUVColorSpace);
+ EXPECT_EQ(decoder->GetYUVBitDepth(), bit_depth);
IntSize size = decoder->DecodedSize();
IntSize y_size = decoder->DecodedYUVSize(cc::YUVIndex::kY);
@@ -546,6 +681,7 @@ void ReadYUV(const char* file_name,
decoder->DecodeToYUV();
EXPECT_FALSE(decoder->Failed());
+ EXPECT_TRUE(decoder->HasDisplayableYUVData());
auto metadata = decoder->MakeMetadataForDecodeAcceleration();
EXPECT_EQ(cc::ImageType::kAVIF, metadata.image_type);
@@ -598,6 +734,10 @@ void TestYUVRed(const char* file_name,
const IntSize& expected_uv_size,
SkColorType color_type = kGray_8_SkColorType,
int bit_depth = 8) {
+#if !defined(HAVE_AVIF_BIT_DEPTH_12_SUPPORT)
+ if (bit_depth == 12)
+ return;
+#endif
SCOPED_TRACE(base::StringPrintf("file_name=%s, color_type=%d", file_name,
int{color_type}));
@@ -641,6 +781,7 @@ TEST(AnimatedAVIFTests, ValidImages) {
&CreateAVIFDecoder,
"/images/resources/avif/star-animated-10bpc-with-alpha.avif", 5u,
kAnimationLoopInfinite);
+#if defined(HAVE_AVIF_BIT_DEPTH_12_SUPPORT)
TestByteByByteDecode(&CreateAVIFDecoder,
"/images/resources/avif/star-animated-12bpc.avif", 5u,
kAnimationLoopInfinite);
@@ -648,6 +789,7 @@ TEST(AnimatedAVIFTests, ValidImages) {
&CreateAVIFDecoder,
"/images/resources/avif/star-animated-12bpc-with-alpha.avif", 5u,
kAnimationLoopInfinite);
+#endif
// TODO(ryoh): Add animated avif files with EditListBox.
}
@@ -694,10 +836,12 @@ TEST(StaticAVIFTests, ValidImages) {
&CreateAVIFDecoder,
"/images/resources/avif/red-at-12-oclock-with-color-profile-10bpc.avif",
1, kAnimationNone);
+#if defined(HAVE_AVIF_BIT_DEPTH_12_SUPPORT)
TestByteByByteDecode(
&CreateAVIFDecoder,
"/images/resources/avif/red-at-12-oclock-with-color-profile-12bpc.avif",
1, kAnimationNone);
+#endif
}
TEST(StaticAVIFTests, YUV) {
@@ -752,6 +896,10 @@ INSTANTIATE_TEST_CASE_P(Parameterized,
TEST_P(StaticAVIFColorTests, InspectImage) {
const StaticColorCheckParam& param = GetParam();
+#if !defined(HAVE_AVIF_BIT_DEPTH_12_SUPPORT)
+ if (param.bit_depth == 12)
+ return;
+#endif
// TODO(ryoh): Add tests with ImageDecoder::kHighBitDepthToHalfFloat
std::unique_ptr<ImageDecoder> decoder = CreateAVIFDecoderWithOptions(
param.alpha_option, ImageDecoder::kDefaultBitDepth, param.color_behavior,
@@ -773,9 +921,8 @@ TEST_P(StaticAVIFColorTests, InspectImage) {
ASSERT_TRUE(frame);
EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
EXPECT_FALSE(decoder->Failed());
- // TODO(ryoh): How should we treat imir(mirroring), irot(rotation) and
- // clap(cropping)?
- // EXPECT_EQ(xxxx, decoder->Orientation());
+ // TODO(ryoh): How should we treat clap(cropping)?
+ EXPECT_EQ(param.orientation, decoder->Orientation());
EXPECT_EQ(param.color_type == ColorType::kRgbA ||
param.color_type == ColorType::kMonoA,
frame->HasAlpha());
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.cc
index 0dc767dde67..c2fa20b0988 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.cc
@@ -141,7 +141,7 @@ bool BMPImageDecoder::GetFileType(const FastSharedBufferReader& fast_reader,
return false;
file_header = fast_reader.GetConsecutiveData(decoded_offset_,
kSizeOfFileHeader, buffer);
- file_type = (file_header[0] << 8) | static_cast<uint8_t>(file_header[1]);
+ file_type = (uint16_t{file_header[0]} << 8) | uint8_t{file_header[1]};
return true;
}
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader_test.cc
index 0ad4ac7ed55..ce17eea1185 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader_test.cc
@@ -29,10 +29,10 @@
*/
#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkRWBuffer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -42,14 +42,14 @@ namespace {
scoped_refptr<SegmentReader> CopyToROBufferSegmentReader(
scoped_refptr<SegmentReader> input) {
- SkRWBuffer rw_buffer;
+ RWBuffer rw_buffer;
const char* segment = nullptr;
size_t position = 0;
while (size_t length = input->GetSomeData(segment, position)) {
- rw_buffer.append(segment, length);
+ rw_buffer.Append(segment, length);
position += length;
}
- return SegmentReader::CreateFromSkROBuffer(rw_buffer.makeROBufferSnapshot());
+ return SegmentReader::CreateFromROBuffer(rw_buffer.MakeROBufferSnapshot());
}
scoped_refptr<SegmentReader> CopyToDataSegmentReader(
@@ -60,7 +60,7 @@ scoped_refptr<SegmentReader> CopyToDataSegmentReader(
struct SegmentReaders {
scoped_refptr<SegmentReader> segment_readers[3];
- SegmentReaders(scoped_refptr<SharedBuffer> input) {
+ explicit SegmentReaders(scoped_refptr<SharedBuffer> input) {
segment_readers[0] =
SegmentReader::CreateFromSharedBuffer(std::move(input));
segment_readers[1] = CopyToROBufferSegmentReader(segment_readers[0]);
@@ -201,21 +201,21 @@ TEST(SegmentReaderTest, variableSegments) {
scoped_refptr<SegmentReader> segment_reader;
{
// Create a SegmentReader with difference sized segments, to test that
- // the SkROBuffer implementation works when two consecutive segments
+ // the ROBuffer implementation works when two consecutive segments
// are not the same size. This test relies on knowledge of the
- // internals of SkRWBuffer: it ensures that each segment is at least
+ // internals of RWBuffer: it ensures that each segment is at least
// 4096 (though the actual data may be smaller, if it has not been
// written to yet), but when appending a larger amount it may create a
// larger segment.
- SkRWBuffer rw_buffer;
- rw_buffer.append(reference_data, SharedBuffer::kSegmentSize);
- rw_buffer.append(reference_data + SharedBuffer::kSegmentSize,
+ RWBuffer rw_buffer;
+ rw_buffer.Append(reference_data, SharedBuffer::kSegmentSize);
+ rw_buffer.Append(reference_data + SharedBuffer::kSegmentSize,
2 * SharedBuffer::kSegmentSize);
- rw_buffer.append(reference_data + 3 * SharedBuffer::kSegmentSize,
+ rw_buffer.Append(reference_data + 3 * SharedBuffer::kSegmentSize,
.5 * SharedBuffer::kSegmentSize);
segment_reader =
- SegmentReader::CreateFromSkROBuffer(rw_buffer.makeROBufferSnapshot());
+ SegmentReader::CreateFromROBuffer(rw_buffer.MakeROBufferSnapshot());
}
const char* segment;
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
index 942bd0ba612..15eee951232 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
@@ -289,11 +289,6 @@ TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache) {
&CreateDecoder, kWebTestsResourcesDir, "animated-10color.gif");
}
-TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache) {
- TestResumePartialDecodeAfterClearFrameBufferCache(
- &CreateDecoder, kWebTestsResourcesDir, "animated-10color.gif");
-}
-
// The first LZW codes in the image are invalid values that try to create a loop
// in the dictionary. Decoding should fail, but not infinitely loop or corrupt
// memory.
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index 759dfb8e2fe..ff2f7c235c5 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -26,7 +26,6 @@
#include "base/sys_byteorder.h"
#include "build/build_config.h"
#include "media/media_buildflags.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
@@ -140,10 +139,8 @@ String SniffMimeTypeInternal(scoped_refptr<SegmentReader> reader) {
if (MatchesBMPSignature(contents))
return "image/bmp";
#if BUILDFLAG(ENABLE_AV1_DECODER)
- if (base::FeatureList::IsEnabled(features::kAVIF) &&
- AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) {
+ if (AVIFImageDecoder::MatchesAVIFSignature(fast_reader))
return "image/avif";
- }
#endif
return String();
@@ -184,8 +181,9 @@ std::unique_ptr<ImageDecoder> ImageDecoder::CreateByMimeType(
CalculateMaxDecodedBytes(high_bit_depth_decoding_option, desired_size);
// Note: The mime types below should match those supported by
- // MimeUtil::IsSupportedImageMimeType().
+ // MimeUtil::IsSupportedImageMimeType() (which forces lowercase).
std::unique_ptr<ImageDecoder> decoder;
+ mime_type = mime_type.LowerASCII();
if (mime_type == "image/jpeg" || mime_type == "image/pjpeg" ||
mime_type == "image/jpg") {
decoder = std::make_unique<JPEGImageDecoder>(alpha_option, color_behavior,
@@ -209,8 +207,7 @@ std::unique_ptr<ImageDecoder> ImageDecoder::CreateByMimeType(
decoder = std::make_unique<BMPImageDecoder>(alpha_option, color_behavior,
max_decoded_bytes);
#if BUILDFLAG(ENABLE_AV1_DECODER)
- } else if (base::FeatureList::IsEnabled(features::kAVIF) &&
- mime_type == "image/avif") {
+ } else if (mime_type == "image/avif") {
decoder = std::make_unique<AVIFImageDecoder>(
alpha_option, high_bit_depth_decoding_option, color_behavior,
max_decoded_bytes, animation_option);
@@ -229,7 +226,7 @@ bool ImageDecoder::HasSufficientDataToSniffMimeType(const SharedBuffer& data) {
return false;
#if BUILDFLAG(ENABLE_AV1_DECODER)
- if (base::FeatureList::IsEnabled(features::kAVIF)) {
+ {
// Check for an ISO BMFF File Type Box. Assume that 'largesize' is not used.
// The first eight bytes would be a big-endian 32-bit unsigned integer
// 'size' and a four-byte 'type'.
@@ -248,6 +245,7 @@ bool ImageDecoder::HasSufficientDataToSniffMimeType(const SharedBuffer& data) {
}
}
#endif
+
return true;
}
@@ -323,10 +321,8 @@ ImageDecoder::CompressionFormat ImageDecoder::GetCompressionFormat(
// compression algorithm.
// TODO(wtc): Implement this. Figure out whether to return kUndefinedFormat or
// a new kAVIFAnimationFormat in the case of an animated AVIF image.
- if (base::FeatureList::IsEnabled(features::kAVIF) &&
- EqualIgnoringASCIICase(mime_type, "image/avif")) {
+ if (EqualIgnoringASCIICase(mime_type, "image/avif"))
return kLossyFormat;
- }
#endif
if (MIMETypeRegistry::IsLossyImageMIMEType(mime_type))
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index 75c4836f1f9..6688d323ec2 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -79,11 +79,14 @@ class PLATFORM_EXPORT ImagePlanes final {
void* Plane(cc::YUVIndex);
size_t RowBytes(cc::YUVIndex) const;
SkColorType color_type() const { return color_type_; }
+ void SetHasCompleteScan() { has_complete_scan_ = true; }
+ bool HasCompleteScan() const { return has_complete_scan_; }
private:
void* planes_[cc::kNumYUVPlanes];
size_t row_bytes_[cc::kNumYUVPlanes];
SkColorType color_type_;
+ bool has_complete_scan_ = false;
DISALLOW_COPY_AND_ASSIGN(ImagePlanes);
};
@@ -313,9 +316,12 @@ class PLATFORM_EXPORT ImageDecoder {
return true;
}
- // Calls DecodeFrameCount() to get the frame count (if possible), without
- // decoding the individual frames. Resizes |frame_buffer_cache_| to the
- // correct size and returns its size.
+ // Calls DecodeFrameCount() to get the current frame count (if possible),
+ // without decoding the individual frames. Resizes |frame_buffer_cache_| to
+ // the new size and returns that size.
+ //
+ // Note: FrameCount() returns the return value of DecodeFrameCount(). For more
+ // information on the return value, see the comment for DecodeFrameCount().
size_t FrameCount();
virtual int RepetitionCount() const { return kAnimationNone; }
@@ -420,6 +426,9 @@ class PLATFORM_EXPORT ImageDecoder {
void SetImagePlanes(std::unique_ptr<ImagePlanes> image_planes) {
image_planes_ = std::move(image_planes);
}
+ bool HasDisplayableYUVData() const {
+ return image_planes_ && image_planes_->HasCompleteScan();
+ }
// Indicates if the data contains both an animation and still image.
virtual bool ImageHasBothStillAndAnimatedSubImages() const { return false; }
@@ -466,6 +475,18 @@ class PLATFORM_EXPORT ImageDecoder {
// Decodes the image sufficiently to determine the number of frames and
// returns that number.
+ //
+ // If an image format supports images with multiple frames, the decoder must
+ // override this method. FrameCount() calls this method and resizes
+ // |frame_buffer_cache_| to the return value of this method. Therefore, on
+ // failure this method should return |frame_buffer_cache_.size()| (the
+ // existing number of frames) instead of 0 to leave |frame_buffer_cache_|
+ // unchanged.
+ //
+ // This method may return an increasing frame count as frames are received and
+ // parsed. Alternatively, if the total frame count is available in the image
+ // header, this method may return the total frame count without checking how
+ // many frames are received.
virtual size_t DecodeFrameCount() { return 1; }
// Called to initialize the frame buffer with the given index, based on the
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test.cc
index 2c2e1693a04..9e20b13e25c 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test.cc
@@ -34,7 +34,6 @@
#include "build/build_config.h"
#include "media/media_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/platform/image-decoders/image_frame.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -361,35 +360,33 @@ TEST(ImageDecoderTest, decodedSizeLimitIsIgnored) {
#if BUILDFLAG(ENABLE_AV1_DECODER)
TEST(ImageDecoderTest, hasSufficientDataToSniffMimeTypeAvif) {
- if (base::FeatureList::IsEnabled(features::kAVIF)) {
- // The first 36 bytes of the Netflix AVIF test image
- // Chimera-AV1-10bit-1280x720-2380kbps-100.avif. Since the major_brand is
- // not "avif" or "avis", we must parse the compatible_brands to determine if
- // this is an AVIF image.
- constexpr char kData[] = {
- // A File Type Box.
- 0x00, 0x00, 0x00, 0x1c, // unsigned int(32) size; 0x1c = 28
- 'f', 't', 'y', 'p', // unsigned int(32) type = boxtype;
- 'm', 'i', 'f', '1', // unsigned int(32) major_brand;
- 0x00, 0x00, 0x00, 0x00, // unsigned int(32) minor_version;
- 'm', 'i', 'f', '1', // unsigned int(32) compatible_brands[];
- 'a', 'v', 'i', 'f', //
- 'm', 'i', 'a', 'f', //
- // The beginning of a Media Data Box.
- 0x00, 0x00, 0xa4, 0x3a, // unsigned int(32) size;
- 'm', 'd', 'a', 't' // unsigned int(32) type = boxtype;
- };
-
- scoped_refptr<SharedBuffer> buffer = SharedBuffer::Create<size_t>(kData, 8);
- EXPECT_FALSE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
- EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), String());
- buffer->Append<size_t>(kData + 8, 8);
- EXPECT_FALSE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
- EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), String());
- buffer->Append<size_t>(kData + 16, sizeof(kData) - 16);
- EXPECT_TRUE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
- EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), "image/avif");
- }
+ // The first 36 bytes of the Netflix AVIF test image
+ // Chimera-AV1-10bit-1280x720-2380kbps-100.avif. Since the major_brand is
+ // not "avif" or "avis", we must parse the compatible_brands to determine if
+ // this is an AVIF image.
+ constexpr char kData[] = {
+ // A File Type Box.
+ 0x00, 0x00, 0x00, 0x1c, // unsigned int(32) size; 0x1c = 28
+ 'f', 't', 'y', 'p', // unsigned int(32) type = boxtype;
+ 'm', 'i', 'f', '1', // unsigned int(32) major_brand;
+ 0x00, 0x00, 0x00, 0x00, // unsigned int(32) minor_version;
+ 'm', 'i', 'f', '1', // unsigned int(32) compatible_brands[];
+ 'a', 'v', 'i', 'f', //
+ 'm', 'i', 'a', 'f', //
+ // The beginning of a Media Data Box.
+ 0x00, 0x00, 0xa4, 0x3a, // unsigned int(32) size;
+ 'm', 'd', 'a', 't' // unsigned int(32) type = boxtype;
+ };
+
+ scoped_refptr<SharedBuffer> buffer = SharedBuffer::Create<size_t>(kData, 8);
+ EXPECT_FALSE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
+ EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), String());
+ buffer->Append<size_t>(kData + 8, 8);
+ EXPECT_FALSE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
+ EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), String());
+ buffer->Append<size_t>(kData + 16, sizeof(kData) - 16);
+ EXPECT_TRUE(ImageDecoder::HasSufficientDataToSniffMimeType(*buffer));
+ EXPECT_EQ(ImageDecoder::SniffMimeType(buffer), "image/avif");
}
#endif // BUILDFLAG(ENABLE_AV1_DECODER)
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.cc b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.cc
index 13262959813..49fa158ad92 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.cc
@@ -340,39 +340,6 @@ void TestUpdateRequiredPreviousFrameAfterFirstDecode(
}
}
-void TestResumePartialDecodeAfterClearFrameBufferCache(
- DecoderCreator create_decoder,
- SharedBuffer* full_buffer) {
- const Vector<char> full_data = full_buffer->CopyAs<Vector<char>>();
- Vector<unsigned> baseline_hashes;
- CreateDecodingBaseline(create_decoder, full_buffer, &baseline_hashes);
- size_t frame_count = baseline_hashes.size();
-
- std::unique_ptr<ImageDecoder> decoder = create_decoder();
-
- // Let frame 0 be partially decoded.
- scoped_refptr<SharedBuffer> data = SharedBuffer::Create();
- const char* source = full_data.data();
- do {
- data->Append(source++, 1u);
- decoder->SetData(data.get(), false);
- } while (!decoder->FrameCount() ||
- decoder->DecodeFrameBufferAtIndex(0)->GetStatus() ==
- ImageFrame::kFrameEmpty);
-
- // Skip to the last frame and clear.
- decoder->SetData(full_buffer, true);
- EXPECT_EQ(frame_count, decoder->FrameCount());
- ImageFrame* last_frame = decoder->DecodeFrameBufferAtIndex(frame_count - 1);
- EXPECT_EQ(baseline_hashes[frame_count - 1], HashBitmap(last_frame->Bitmap()));
- decoder->ClearCacheExceptFrame(kNotFound);
-
- // Resume decoding of the first frame.
- ImageFrame* first_frame = decoder->DecodeFrameBufferAtIndex(0);
- EXPECT_EQ(ImageFrame::kFrameComplete, first_frame->GetStatus());
- EXPECT_EQ(baseline_hashes[0], HashBitmap(first_frame->Bitmap()));
-}
-
void TestByteByByteDecode(DecoderCreator create_decoder,
const char* file,
size_t expected_frame_count,
@@ -520,23 +487,6 @@ void TestUpdateRequiredPreviousFrameAfterFirstDecode(
TestUpdateRequiredPreviousFrameAfterFirstDecode(create_decoder, data.get());
}
-void TestResumePartialDecodeAfterClearFrameBufferCache(
- DecoderCreator create_decoder,
- const char* dir,
- const char* file) {
- scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
- ASSERT_TRUE(data.get());
- TestResumePartialDecodeAfterClearFrameBufferCache(create_decoder, data.get());
-}
-
-void TestResumePartialDecodeAfterClearFrameBufferCache(
- DecoderCreator create_decoder,
- const char* file) {
- scoped_refptr<SharedBuffer> data = ReadFile(file);
- ASSERT_TRUE(data.get());
- TestResumePartialDecodeAfterClearFrameBufferCache(create_decoder, data.get());
-}
-
static uint32_t PremultiplyColor(uint32_t c) {
return SkPremultiplyARGBInline(SkGetPackedA32(c), SkGetPackedR32(c),
SkGetPackedG32(c), SkGetPackedB32(c));
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h
index 3450fd1c180..5327d1b9ccc 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h
@@ -108,12 +108,6 @@ void TestUpdateRequiredPreviousFrameAfterFirstDecode(DecoderCreator,
void TestUpdateRequiredPreviousFrameAfterFirstDecode(DecoderCreator,
const char* file);
-void TestResumePartialDecodeAfterClearFrameBufferCache(DecoderCreator,
- const char* dir,
- const char* file);
-void TestResumePartialDecodeAfterClearFrameBufferCache(DecoderCreator,
- const char* file);
-
// Verifies that result of alpha blending is similar for AlphaPremultiplied and
// AlphaNotPremultiplied cases.
void TestAlphaBlending(DecoderCreatorWithAlpha, const char*);
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index 71161bea9a8..a1ee1c7e966 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -1043,6 +1043,9 @@ void JPEGImageDecoder::OnSetData(SegmentReader* data) {
if (reader_)
reader_->SetData(data);
+ if (allow_decode_to_yuv_)
+ return;
+
allow_decode_to_yuv_ =
// Incremental YUV decoding is not currently supported (crbug.com/943519).
IsAllDataReceived() &&
@@ -1052,7 +1055,7 @@ void JPEGImageDecoder::OnSetData(SegmentReader* data) {
// the color profile is known, and the subsampling is known.
IsSizeAvailable() &&
// YUV decoding to a smaller size is not supported.
- reader_->Info()->scale_num == reader_->Info()->scale_denom &&
+ reader_ && reader_->Info()->scale_num == reader_->Info()->scale_denom &&
// TODO(crbug.com/911246): Support color space transformations on planar
// data.
!ColorTransform() &&
@@ -1293,6 +1296,7 @@ static bool OutputRawData(JPEGImageReader* reader, ImagePlanes* image_planes) {
}
info->output_scanline = std::min(info->output_scanline, info->output_height);
+ image_planes->SetHasCompleteScan();
return true;
}
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
index f7a3180ae07..dc5f587a5c1 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -78,7 +78,8 @@ void Downsample(size_t max_decoded_bytes,
void ReadYUV(size_t max_decoded_bytes,
const char* image_file_path,
const IntSize& expected_y_size,
- const IntSize& expected_uv_size) {
+ const IntSize& expected_uv_size,
+ const bool expect_decoding_failure = false) {
scoped_refptr<SharedBuffer> data = ReadFile(image_file_path);
ASSERT_TRUE(data);
@@ -119,7 +120,9 @@ void ReadYUV(size_t max_decoded_bytes,
std::make_unique<ImagePlanes>(planes, row_bytes, kGray_8_SkColorType));
decoder->DecodeToYUV();
- EXPECT_FALSE(decoder->Failed());
+
+ EXPECT_EQ(expect_decoding_failure, decoder->Failed());
+ EXPECT_TRUE(decoder->HasDisplayableYUVData());
}
} // anonymous namespace
@@ -220,6 +223,14 @@ TEST(JPEGImageDecoderTest, yuv) {
ASSERT_FALSE(decoder->CanDecodeToYUV());
}
+// Tests that a progressive image missing an EOI marker causes a YUV decoding
+// failure but also results in displayable YUV data.
+TEST(JPEGImageDecoderTest, missingEoi) {
+ const char* jpeg_file = "/images/resources/missing-eoi.jpg"; // 1599x899
+ ReadYUV((1599 * 899 * 4), jpeg_file, IntSize(1599, 899), IntSize(800, 450),
+ /*expect_decoding_failure=*/true);
+}
+
TEST(JPEGImageDecoderTest,
byteByByteBaselineJPEGWithColorProfileAndRestartMarkers) {
TestByteByByteDecode(&CreateJPEGDecoder,
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.cc b/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
index 3d22cf6fb57..8e25a078c54 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
@@ -9,11 +9,11 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkRWBuffer.h"
namespace blink {
@@ -103,23 +103,23 @@ sk_sp<SkData> DataSegmentReader::GetAsSkData() const {
class ROBufferSegmentReader final : public SegmentReader {
public:
- explicit ROBufferSegmentReader(sk_sp<SkROBuffer>);
+ explicit ROBufferSegmentReader(scoped_refptr<ROBuffer>);
size_t size() const override;
size_t GetSomeData(const char*& data, size_t position) const override;
sk_sp<SkData> GetAsSkData() const override;
private:
- sk_sp<SkROBuffer> ro_buffer_;
+ scoped_refptr<ROBuffer> ro_buffer_;
mutable Mutex read_mutex_;
// Position of the first char in the current block of iter_.
mutable size_t position_of_block_ GUARDED_BY(read_mutex_);
- mutable SkROBuffer::Iter iter_ GUARDED_BY(read_mutex_);
+ mutable ROBuffer::Iter iter_ GUARDED_BY(read_mutex_);
DISALLOW_COPY_AND_ASSIGN(ROBufferSegmentReader);
};
-ROBufferSegmentReader::ROBufferSegmentReader(sk_sp<SkROBuffer> buffer)
+ROBufferSegmentReader::ROBufferSegmentReader(scoped_refptr<ROBuffer> buffer)
: ro_buffer_(std::move(buffer)),
position_of_block_(0),
iter_(ro_buffer_.get()) {}
@@ -136,8 +136,8 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
MutexLocker lock(read_mutex_);
if (position < position_of_block_) {
- // SkROBuffer::Iter only iterates forwards. Start from the beginning.
- iter_.reset(ro_buffer_.get());
+ // ROBuffer::Iter only iterates forwards. Start from the beginning.
+ iter_.Reset(ro_buffer_.get());
position_of_block_ = 0;
}
@@ -153,9 +153,9 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
}
// Move to next block.
- if (!iter_.next()) {
+ if (!iter_.Next()) {
// Reset to the beginning, so future calls can succeed.
- iter_.reset(ro_buffer_.get());
+ iter_.Reset(ro_buffer_.get());
position_of_block_ = 0;
return 0;
}
@@ -165,7 +165,7 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
}
static void UnrefROBuffer(const void* ptr, void* context) {
- static_cast<SkROBuffer*>(context)->unref();
+ static_cast<ROBuffer*>(context)->Release();
}
sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
@@ -173,13 +173,13 @@ sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
return nullptr;
// Check to see if the data is already contiguous.
- SkROBuffer::Iter iter(ro_buffer_.get());
- const bool multiple_blocks = iter.next();
- iter.reset(ro_buffer_.get());
+ ROBuffer::Iter iter(ro_buffer_.get());
+ const bool multiple_blocks = iter.Next();
+ iter.Reset(ro_buffer_.get());
if (!multiple_blocks) {
// Contiguous data. No need to copy.
- ro_buffer_->ref();
+ ro_buffer_->AddRef();
return SkData::MakeWithProc(iter.data(), iter.size(), &UnrefROBuffer,
ro_buffer_.get());
}
@@ -190,7 +190,7 @@ sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
size_t size = iter.size();
memcpy(dst, iter.data(), size);
dst += size;
- } while (iter.next());
+ } while (iter.Next());
return data;
}
@@ -206,8 +206,8 @@ scoped_refptr<SegmentReader> SegmentReader::CreateFromSkData(
return base::AdoptRef(new DataSegmentReader(std::move(data)));
}
-scoped_refptr<SegmentReader> SegmentReader::CreateFromSkROBuffer(
- sk_sp<SkROBuffer> buffer) {
+scoped_refptr<SegmentReader> SegmentReader::CreateFromROBuffer(
+ scoped_refptr<ROBuffer> buffer) {
return base::AdoptRef(new ROBufferSegmentReader(std::move(buffer)));
}
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.h b/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.h
index c986ad8da2f..e61770a053b 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.h
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/segment_reader.h
@@ -12,19 +12,20 @@
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
class SkData;
-class SkROBuffer;
template <typename T>
class sk_sp;
namespace blink {
+class ROBuffer;
+
// Interface that looks like SharedBuffer. Used by ImageDecoders to use various
// sources of input including:
// - SharedBuffer
// - for when the caller already has a SharedBuffer
// - SkData
// - for when the caller already has an SkData
-// - SkROBuffer
+// - ROBuffer
// - for when the caller wants to read/write in different threads
//
// Unlike SharedBuffer, this is a read-only interface. There is no way to
@@ -40,7 +41,8 @@ class PLATFORM_EXPORT SegmentReader
// These versions use thread-safe input, so they are always thread-safe.
static scoped_refptr<SegmentReader> CreateFromSkData(sk_sp<SkData>);
- static scoped_refptr<SegmentReader> CreateFromSkROBuffer(sk_sp<SkROBuffer>);
+ static scoped_refptr<SegmentReader> CreateFromROBuffer(
+ scoped_refptr<ROBuffer>);
SegmentReader() = default;
virtual ~SegmentReader() = default;
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
index 38d57399146..4b75caf10a7 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
@@ -31,8 +31,8 @@
#include <string.h>
#include "base/feature_list.h"
+#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
#include "third_party/skia/include/core/SkData.h"
@@ -113,14 +113,14 @@ void alphaBlendNonPremultiplied(blink::ImageFrame& src,
// Do not rename entries nor reuse numeric values. See the following link for
// descriptions: https://developers.google.com/speed/webp/docs/riff_container.
-enum WebPFileFormat {
- kSimpleLossyFileFormat = 0,
- kSimpleLosslessFileFormat = 1,
- kExtendedAlphaFileFormat = 2,
- kExtendedAnimationFileFormat = 3,
- kExtendedAnimationWithAlphaFileFormat = 4,
- kUnknownFileFormat = 5,
- kCountWebPFileFormats
+enum class WebPFileFormat {
+ kSimpleLossy = 0,
+ kSimpleLossless = 1,
+ kExtendedAlpha = 2,
+ kExtendedAnimation = 3,
+ kExtendedAnimationWithAlpha = 4,
+ kUnknown = 5,
+ kMaxValue = kUnknown,
};
// Validates that |blob| is a simple lossy WebP image. Note that this explicitly
@@ -152,22 +152,19 @@ void UpdateWebPFileFormatUMA(const sk_sp<SkData>& blob) {
constexpr int kLossyFormat = 1;
constexpr int kLosslessFormat = 2;
- WebPFileFormat file_format = kUnknownFileFormat;
+ WebPFileFormat file_format = WebPFileFormat::kUnknown;
if (features.has_alpha && features.has_animation)
- file_format = kExtendedAnimationWithAlphaFileFormat;
+ file_format = WebPFileFormat::kExtendedAnimationWithAlpha;
else if (features.has_animation)
- file_format = kExtendedAnimationFileFormat;
+ file_format = WebPFileFormat::kExtendedAnimation;
else if (features.has_alpha)
- file_format = kExtendedAlphaFileFormat;
+ file_format = WebPFileFormat::kExtendedAlpha;
else if (features.format == kLossyFormat)
- file_format = kSimpleLossyFileFormat;
+ file_format = WebPFileFormat::kSimpleLossy;
else if (features.format == kLosslessFormat)
- file_format = kSimpleLosslessFileFormat;
+ file_format = WebPFileFormat::kSimpleLossless;
- DEFINE_THREAD_SAFE_STATIC_LOCAL(
- blink::EnumerationHistogram, file_format_histogram,
- ("Blink.DecodedImage.WebPFileFormat", kCountWebPFileFormats));
- file_format_histogram.Count(file_format);
+ UMA_HISTOGRAM_ENUMERATION("Blink.DecodedImage.WebPFileFormat", file_format);
}
} // namespace
@@ -186,7 +183,7 @@ WEBPImageDecoder::WEBPImageDecoder(AlphaOption alpha_option,
frame_background_has_alpha_(false),
demux_(nullptr),
demux_state_(WEBP_DEMUX_PARSING_HEADER),
- have_already_parsed_this_data_(false),
+ have_parsed_current_data_(false),
repetition_count_(kAnimationLoopOnce),
decoded_height_(0) {
blend_function_ = (alpha_option == kAlphaPremultiplied)
@@ -259,7 +256,7 @@ bool WEBPImageDecoder::CanAllowYUVDecodingForWebP() {
}
void WEBPImageDecoder::OnSetData(SegmentReader* data) {
- have_already_parsed_this_data_ = false;
+ have_parsed_current_data_ = false;
// TODO(crbug.com/943519): Modify this approach for incremental YUV (when
// we don't require IsAllDataReceived() to be true before decoding).
if (IsAllDataReceived()) {
@@ -302,10 +299,9 @@ bool WEBPImageDecoder::UpdateDemuxer() {
if (data_->size() < kWebpHeaderSize)
return IsAllDataReceived() ? SetFailed() : false;
- if (have_already_parsed_this_data_)
+ if (have_parsed_current_data_)
return true;
-
- have_already_parsed_this_data_ = true;
+ have_parsed_current_data_ = true;
if (consolidated_data_ && consolidated_data_->size() >= data_->size()) {
// Less data provided than last time. |consolidated_data_| is guaranteed
@@ -723,6 +719,7 @@ bool WEBPImageDecoder::DecodeSingleFrameToYUV(const uint8_t* data_bytes,
// TODO(crbug.com/911246): Do post-processing once skcms_Transform
// supports multiplanar formats.
ClearDecoder();
+ image_planes->SetHasCompleteScan();
return true;
}
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
index e529ec39e39..68fdcb02ad1 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
@@ -123,7 +123,7 @@ class PLATFORM_EXPORT WEBPImageDecoder final : public ImageDecoder {
WebPDemuxer* demux_;
WebPDemuxState demux_state_;
- bool have_already_parsed_this_data_;
+ bool have_parsed_current_data_;
int repetition_count_;
int decoded_height_;
diff --git a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
index 50d4bd81a40..e520ac0d03e 100644
--- a/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
@@ -397,12 +397,6 @@ TEST(AnimatedWebPTests, randomDecodeAfterClearFrameBufferCache) {
&CreateWEBPDecoder, "/images/resources/webp-animated-icc-xmp.webp");
}
-TEST(AnimatedWebPTests,
- resumePartialDecodeAfterClearFrameBufferCache) {
- TestResumePartialDecodeAfterClearFrameBufferCache(
- &CreateWEBPDecoder, "/images/resources/webp-animated-large.webp");
-}
-
TEST(AnimatedWebPTests, decodeAfterReallocatingData) {
TestDecodeAfterReallocatingData(&CreateWEBPDecoder,
"/images/resources/webp-animated.webp");
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/BUILD.gn b/chromium/third_party/blink/renderer/platform/instrumentation/BUILD.gn
index 870af665cb1..814c58d21ff 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/BUILD.gn
@@ -37,11 +37,11 @@ blink_platform_sources("instrumentation") {
"use_counter.h",
]
- deps = [
+ deps = [ "//services/service_manager/public/cpp" ]
+ public_deps = [
"//components/performance_manager/public/mojom:mojom_blink",
- "//services/service_manager/public/cpp",
+ "//third_party/blink/renderer/platform/heap:heap",
]
- public_deps = [ "//third_party/blink/renderer/platform/heap:heap" ]
allow_circular_includes_from = public_deps
}
@@ -50,6 +50,7 @@ source_set("unit_tests") {
sources = [
"histogram_test.cc",
+ "partition_alloc_memory_dump_provider_test.cc",
"tracing/traced_value_test.cc",
"tracing/web_process_memory_dump_test.cc",
]
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/DIR_METADATA b/chromium/third_party/blink/renderer/platform/instrumentation/DIR_METADATA
new file mode 100644
index 00000000000..f7ff38f306d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Speed>Tracing"
+}
+team_email: "tracing@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/OWNERS b/chromium/third_party/blink/renderer/platform/instrumentation/OWNERS
index ed174f3561b..32ceaab5fbb 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/OWNERS
@@ -2,6 +2,3 @@ eseckler@chromium.org
oysteine@chromium.org
primiano@chromium.org
skyostil@chromium.org
-
-# TEAM: tracing@chromium.org
-# COMPONENT: Speed>Tracing
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/histogram.cc b/chromium/third_party/blink/renderer/platform/instrumentation/histogram.cc
index 0a8270d1352..2ae0db1ae96 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/histogram.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/histogram.cc
@@ -36,30 +36,4 @@ void CustomCountHistogram::CountMicroseconds(base::TimeDelta delta) {
delta.InMicroseconds()));
}
-void CustomCountHistogram::CountMilliseconds(base::TimeDelta delta) {
- Count(base::saturated_cast<base::HistogramBase::Sample>(
- delta.InMilliseconds()));
-}
-
-EnumerationHistogram::EnumerationHistogram(
- const char* name,
- base::HistogramBase::Sample boundary_value)
- : CustomCountHistogram(base::LinearHistogram::FactoryGet(
- name,
- 1,
- boundary_value,
- boundary_value + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag)) {}
-
-LinearHistogram::LinearHistogram(const char* name,
- base::HistogramBase::Sample min,
- base::HistogramBase::Sample max,
- int32_t bucket_count)
- : CustomCountHistogram(base::LinearHistogram::FactoryGet(
- name,
- min,
- max,
- bucket_count,
- base::HistogramBase::kUmaTargetedHistogramFlag)) {}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/histogram.h b/chromium/third_party/blink/renderer/platform/instrumentation/histogram.h
index 8747d1f326a..487f34085ad 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/histogram.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/histogram.h
@@ -31,7 +31,6 @@ class PLATFORM_EXPORT CustomCountHistogram {
void Count(base::HistogramBase::Sample);
void CountMany(base::HistogramBase::Sample, int count);
void CountMicroseconds(base::TimeDelta);
- void CountMilliseconds(base::TimeDelta);
protected:
explicit CustomCountHistogram(base::HistogramBase*);
@@ -39,21 +38,6 @@ class PLATFORM_EXPORT CustomCountHistogram {
base::HistogramBase* histogram_;
};
-class PLATFORM_EXPORT EnumerationHistogram : public CustomCountHistogram {
- public:
- // |boundaryValue| must be strictly greater than samples passed to |count|.
- EnumerationHistogram(const char* name,
- base::HistogramBase::Sample boundary_value);
-};
-
-class PLATFORM_EXPORT LinearHistogram : public CustomCountHistogram {
- public:
- explicit LinearHistogram(const char* name,
- base::HistogramBase::Sample min,
- base::HistogramBase::Sample max,
- int32_t bucket_count);
-};
-
template <typename Derived>
class ScopedUsHistogramTimerBase {
USING_FAST_MALLOC(ScopedUsHistogramTimerBase);
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc b/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
index 261786c3aaa..75b08a64b6f 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
@@ -29,7 +29,7 @@ namespace blink {
// Function defined in third_party/blink/public/web/blink.h.
void DecommitFreeableMemory() {
CHECK(IsMainThread());
- base::PartitionAllocMemoryReclaimer::Instance()->Reclaim();
+ base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
}
// static
@@ -100,13 +100,13 @@ void MemoryPressureListenerRegistry::UnregisterClient(
}
void MemoryPressureListenerRegistry::OnMemoryPressure(
- WebMemoryPressureLevel level) {
+ base::MemoryPressureListener::MemoryPressureLevel level) {
TRACE_EVENT1("blink", "MemoryPressureListenerRegistry::onMemoryPressure",
"level", level);
CHECK(IsMainThread());
for (auto& client : clients_)
client->OnMemoryPressure(level);
- base::PartitionAllocMemoryReclaimer::Instance()->Reclaim();
+ base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
}
void MemoryPressureListenerRegistry::OnPurgeMemory() {
@@ -114,7 +114,7 @@ void MemoryPressureListenerRegistry::OnPurgeMemory() {
for (auto& client : clients_)
client->OnPurgeMemory();
ImageDecodingStore::Instance().Clear();
- base::PartitionAllocMemoryReclaimer::Instance()->Reclaim();
+ base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
// Thread-specific data never issues a layout, so we are safe here.
MutexLocker lock(threads_mutex_);
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h b/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
index d31890304ee..87c95698569 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTRUMENTATION_MEMORY_PRESSURE_LISTENER_H_
#include "base/macros.h"
-#include "third_party/blink/public/platform/web_memory_pressure_level.h"
+#include "base/memory/memory_pressure_listener.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
@@ -19,7 +19,8 @@ class PLATFORM_EXPORT MemoryPressureListener : public GarbageCollectedMixin {
public:
virtual ~MemoryPressureListener() = default;
- virtual void OnMemoryPressure(WebMemoryPressureLevel) {}
+ virtual void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel) {}
virtual void OnPurgeMemory() {}
};
@@ -55,7 +56,7 @@ class PLATFORM_EXPORT MemoryPressureListenerRegistry final
void RegisterClient(MemoryPressureListener*);
void UnregisterClient(MemoryPressureListener*);
- void OnMemoryPressure(WebMemoryPressureLevel);
+ void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel);
void OnPurgeMemory();
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.cc b/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.cc
index eece1d52517..026b66345af 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.cc
@@ -6,6 +6,7 @@
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/format_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
@@ -84,6 +85,37 @@ void PartitionStatsDumperImpl::PartitionDumpTotals(
memory_dump_->CreateAllocatorDump(dump_name + "/thread_cache");
base::trace_event::ReportPartitionAllocThreadCacheStats(
all_thread_caches_dump, all_thread_caches_stats);
+
+ if (all_thread_caches_stats.alloc_count) {
+ int hit_rate_percent =
+ static_cast<int>((100 * all_thread_caches_stats.alloc_hits) /
+ all_thread_caches_stats.alloc_count);
+ base::UmaHistogramPercentage("Memory.PartitionAlloc.ThreadCache.HitRate",
+ hit_rate_percent);
+
+ int batch_fill_rate_percent =
+ static_cast<int>((100 * all_thread_caches_stats.batch_fill_count) /
+ all_thread_caches_stats.alloc_count);
+ base::UmaHistogramPercentage(
+ "Memory.PartitionAlloc.ThreadCache.BatchFillRate",
+ batch_fill_rate_percent);
+ }
+
+ if (thread_cache_stats.alloc_count) {
+ int hit_rate_percent =
+ static_cast<int>((100 * thread_cache_stats.alloc_hits) /
+ thread_cache_stats.alloc_count);
+ base::UmaHistogramPercentage(
+ "Memory.PartitionAlloc.ThreadCache.HitRate.MainThread",
+ hit_rate_percent);
+
+ int batch_fill_rate_percent =
+ static_cast<int>((100 * thread_cache_stats.batch_fill_count) /
+ thread_cache_stats.alloc_count);
+ base::UmaHistogramPercentage(
+ "Memory.PartitionAlloc.ThreadCache.BatchFillRate.MainThread",
+ batch_fill_rate_percent);
+ }
}
}
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider_test.cc b/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider_test.cc
new file mode 100644
index 00000000000..7010e7b6d75
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider_test.cc
@@ -0,0 +1,52 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/instrumentation/partition_alloc_memory_dump_provider.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
+
+namespace blink {
+
+TEST(PartitionAllocMemoryDumpProviderTest, Simple) {
+ // Make sure there is at least one allocation.
+ // Otherwise the hit rate is not computed.
+ void* data = WTF::Partitions::FastMalloc(12, "");
+ WTF::Partitions::FastFree(data);
+
+ base::HistogramTester histogram_tester;
+ base::trace_event::MemoryDumpArgs args = {
+ base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+ base::trace_event::ProcessMemoryDump pmd(args);
+ PartitionAllocMemoryDumpProvider::Instance()->OnMemoryDump(args, &pmd);
+
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
+ defined(PA_THREAD_CACHE_SUPPORTED) && \
+ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+ histogram_tester.ExpectTotalCount("Memory.PartitionAlloc.ThreadCache.HitRate",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.HitRate.MainThread", 1);
+
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.BatchFillRate", 1);
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.HitRate.MainThread", 1);
+#else
+ histogram_tester.ExpectTotalCount("Memory.PartitionAlloc.ThreadCache.HitRate",
+ 0);
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.HitRate.MainThread", 0);
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.BatchFillRate", 0);
+ histogram_tester.ExpectTotalCount(
+ "Memory.PartitionAlloc.ThreadCache.BatchFillRate.MainThread", 0);
+#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
+ // defined(PA_THREAD_CACHE_SUPPORTED) &&
+ // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
index 2e002e3f369..92acf766b71 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
@@ -12,12 +12,6 @@
namespace blink {
-namespace {
-
-using performance_manager::mojom::InterventionPolicy;
-
-} // namespace
-
// static
std::unique_ptr<DocumentResourceCoordinator>
DocumentResourceCoordinator::MaybeCreate(
@@ -55,11 +49,6 @@ void DocumentResourceCoordinator::SetViewportIntersection(
service_->SetViewportIntersection(viewport_intersection);
}
-void DocumentResourceCoordinator::SetOriginTrialFreezePolicy(
- InterventionPolicy policy) {
- service_->SetOriginTrialFreezePolicy(policy);
-}
-
void DocumentResourceCoordinator::SetIsAdFrame() {
service_->SetIsAdFrame();
}
@@ -82,4 +71,10 @@ void DocumentResourceCoordinator::OnFirstContentfulPaint(
service_->OnFirstContentfulPaint(time_since_navigation_start);
}
+void DocumentResourceCoordinator::OnWebMemoryMeasurementRequested(
+ WebMemoryMeasurementMode mode,
+ OnWebMemoryMeasurementRequestedCallback callback) {
+ service_->OnWebMemoryMeasurementRequested(mode, std::move(callback));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
index 06309a5b73b..f7d4cfc8d50 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
@@ -21,6 +21,11 @@ class PLATFORM_EXPORT DocumentResourceCoordinator final {
USING_FAST_MALLOC(DocumentResourceCoordinator);
public:
+ using WebMemoryMeasurementMode =
+ ::performance_manager::mojom::blink::WebMemoryMeasurement::Mode;
+ using OnWebMemoryMeasurementRequestedCallback = ::performance_manager::mojom::
+ blink::DocumentCoordinationUnit::OnWebMemoryMeasurementRequestedCallback;
+
// Returns nullptr if instrumentation is not enabled.
static std::unique_ptr<DocumentResourceCoordinator> MaybeCreate(
const BrowserInterfaceBrokerProxy&);
@@ -30,13 +35,14 @@ class PLATFORM_EXPORT DocumentResourceCoordinator final {
void SetLifecycleState(performance_manager::mojom::LifecycleState);
void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
void SetViewportIntersection(const gfx::Rect& viewport_intersection);
- void SetOriginTrialFreezePolicy(
- performance_manager::mojom::InterventionPolicy policy);
// A one way switch that marks a frame as being an adframe.
void SetIsAdFrame();
void OnNonPersistentNotificationCreated();
void SetHadFormInteraction();
void OnFirstContentfulPaint(base::TimeDelta time_since_navigation_start);
+ void OnWebMemoryMeasurementRequested(
+ WebMemoryMeasurementMode mode,
+ OnWebMemoryMeasurementRequestedCallback callback);
private:
explicit DocumentResourceCoordinator(const BrowserInterfaceBrokerProxy&);
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
index 012e9c2edab..bf28ded30a2 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
@@ -34,6 +34,10 @@ class DummyRendererResourceCoordinator final
ExecutionContext* execution_context) final {}
void OnScriptStateDetached(ScriptState* script_state) final {}
void OnScriptStateDestroyed(ScriptState* script_state) final {}
+ void OnBeforeContentFrameAttached(const Frame& frame,
+ const HTMLFrameOwnerElement& owner) final {}
+ void OnBeforeContentFrameDetached(const Frame& frame,
+ const HTMLFrameOwnerElement& owner) final {}
};
} // namespace
diff --git a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
index af5e9b5ec09..1986d7a3b9b 100644
--- a/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
+++ b/chromium/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
@@ -11,6 +11,8 @@ namespace blink {
// TODO(chrisha): Remove knowledge of ExecutionContext class from this code!
class ExecutionContext;
+class Frame;
+class HTMLFrameOwnerElement;
class ScriptState;
class PLATFORM_EXPORT RendererResourceCoordinator {
@@ -48,6 +50,15 @@ class PLATFORM_EXPORT RendererResourceCoordinator {
virtual void OnScriptStateDetached(ScriptState* script_state) = 0;
// Called when the |script_state| itself is garbage collected.
virtual void OnScriptStateDestroyed(ScriptState* script_state) = 0;
+
+ // Called when |frame| is about to be set as the ContentFrame of |owner|.
+ virtual void OnBeforeContentFrameAttached(
+ const Frame& frame,
+ const HTMLFrameOwnerElement& owner) = 0;
+ // Called when |frame| is about to be unset as the ContentFrame of |owner|.
+ virtual void OnBeforeContentFrameDetached(
+ const Frame& frame,
+ const HTMLFrameOwnerElement& owner) = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/json/DIR_METADATA b/chromium/third_party/blink/renderer/platform/json/DIR_METADATA
new file mode 100644
index 00000000000..a5d0257cece
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/json/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Internals>WTF"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/json/OWNERS b/chromium/third_party/blink/renderer/platform/json/OWNERS
index 3312268b06e..8973bb94daf 100644
--- a/chromium/third_party/blink/renderer/platform/json/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/json/OWNERS
@@ -1,4 +1,2 @@
pfeldman@chromium.org
iclelland@chromium.org
-
-# COMPONENT: Blink>Internals>WTF
diff --git a/chromium/third_party/blink/renderer/platform/link_hash.cc b/chromium/third_party/blink/renderer/platform/link_hash.cc
index 4a1c915d526..803ebe404c9 100644
--- a/chromium/third_party/blink/renderer/platform/link_hash.cc
+++ b/chromium/third_party/blink/renderer/platform/link_hash.cc
@@ -30,9 +30,11 @@
#include "third_party/blink/renderer/platform/link_hash.h"
+#include "base/i18n/uchar.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
+
#include "url/url_util.h"
namespace blink {
@@ -51,7 +53,8 @@ static bool ResolveRelative(const KURL& base,
relative_utf8.size(), nullptr, buffer, &parsed);
}
return url::ResolveRelative(base_utf8.data(), base_utf8.size(),
- base.GetParsed(), relative.Characters16(),
+ base.GetParsed(),
+ base::i18n::ToChar16Ptr(relative.Characters16()),
relative.length(), nullptr, buffer, &parsed);
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/BUILD.gn b/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
index 4f8c6195b48..fb533c27816 100644
--- a/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/loader/BUILD.gn
@@ -24,6 +24,7 @@ blink_platform_sources("loader") {
"cors/cors.h",
"cors/cors_error_string.cc",
"cors/cors_error_string.h",
+ "fetch/back_forward_cache_loader_helper.h",
"fetch/buffering_bytes_consumer.cc",
"fetch/buffering_bytes_consumer.h",
"fetch/bytes_consumer.cc",
@@ -64,6 +65,7 @@ blink_platform_sources("loader") {
"fetch/preload_key.h",
"fetch/raw_resource.cc",
"fetch/raw_resource.h",
+ "fetch/render_blocking_behavior.h",
"fetch/resource.cc",
"fetch/resource.h",
"fetch/resource_client.cc",
@@ -116,10 +118,17 @@ blink_platform_sources("loader") {
"fetch/trust_token_params_conversion.h",
"fetch/unique_identifier.cc",
"fetch/unique_identifier.h",
+ "fetch/url_loader/mojo_url_loader_client.cc",
+ "fetch/url_loader/mojo_url_loader_client.h",
"fetch/url_loader/request_conversion.cc",
"fetch/url_loader/request_conversion.h",
- "fetch/url_loader/web_bundle_subresource_loader.cc",
- "fetch/url_loader/web_bundle_subresource_loader.h",
+ "fetch/url_loader/sync_load_context.cc",
+ "fetch/url_loader/sync_load_context.h",
+ "fetch/url_loader/sync_load_response.cc",
+ "fetch/url_loader/sync_load_response.h",
+ "fetch/url_loader/web_resource_request_sender.cc",
+ "fetch/url_loader/web_url_loader.cc",
+ "fetch/url_loader/web_url_loader_factory.cc",
"fetch/url_loader/worker_main_script_loader.cc",
"fetch/url_loader/worker_main_script_loader.h",
"fetch/url_loader/worker_main_script_loader_client.h",
@@ -131,6 +140,8 @@ blink_platform_sources("loader") {
"internet_disconnected_web_url_loader.cc",
"link_header.cc",
"link_header.h",
+ "mixed_content.cc",
+ "mixed_content.h",
"mixed_content_autoupgrade_status.h",
"static_data_navigation_body_loader.cc",
"static_data_navigation_body_loader.h",
@@ -147,17 +158,21 @@ blink_platform_sources("loader") {
deps = [
":make_platform_loader_generated_fetch_initiator_type_names",
"//components/link_header_util",
- "//components/web_package",
+ "//components/variations/net:net",
"//net",
"//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
"//services/network/public/mojom:mojom_blink",
+ "//third_party/blink/public/mojom:mojom_platform_blink",
"//third_party/blink/renderer/platform/blob:blob",
"//third_party/blink/renderer/platform/instrumentation:instrumentation",
"//third_party/blink/renderer/platform/network:network",
"//third_party/blink/renderer/platform/scheduler:scheduler",
]
- public_deps = [ "//third_party/blink/renderer/platform/heap:heap" ]
+ public_deps = [
+ "//third_party/blink/public/mojom:mojom_platform_headers",
+ "//third_party/blink/renderer/platform/heap:heap",
+ ]
allow_circular_includes_from =
[ "//third_party/blink/renderer/platform/network:network" ]
}
@@ -174,6 +189,7 @@ source_set("unit_tests") {
"cors/cors_test.cc",
"fetch/buffering_bytes_consumer_test.cc",
"fetch/bytes_consumer_test.cc",
+ "fetch/cached_metadata_handler_test.cc",
"fetch/client_hints_preferences_test.cc",
"fetch/data_pipe_bytes_consumer_test.cc",
"fetch/fetch_api_request_body_mojom_traits_test.cc",
@@ -192,7 +208,10 @@ source_set("unit_tests") {
"fetch/response_body_loader_test.cc",
"fetch/shared_buffer_bytes_consumer_test.cc",
"fetch/source_keyed_cached_metadata_handler_test.cc",
- "fetch/url_loader/web_bundle_subresource_loader_test.cc",
+ "fetch/url_loader/mojo_url_loader_client_unittest.cc",
+ "fetch/url_loader/sync_load_context_unittest.cc",
+ "fetch/url_loader/web_resource_request_sender_unittest.cc",
+ "fetch/url_loader/web_url_loader_unittest.cc",
"fetch/url_loader/worker_main_script_loader_unittest.cc",
"ftp_directory_listing_test.cc",
"link_header_test.cc",
@@ -204,8 +223,8 @@ source_set("unit_tests") {
deps = [
"//base/test:test_support",
- "//components/web_package:test_support",
"//mojo/public/cpp/test_support:test_utils",
+ "//net:test_support",
"//net/traffic_annotation:test_support",
"//services/network:test_support",
"//testing/gmock",
diff --git a/chromium/third_party/blink/renderer/platform/loader/DEPS b/chromium/third_party/blink/renderer/platform/loader/DEPS
index 52019c0ffc9..4d149b6e493 100644
--- a/chromium/third_party/blink/renderer/platform/loader/DEPS
+++ b/chromium/third_party/blink/renderer/platform/loader/DEPS
@@ -11,8 +11,11 @@ include_rules = [
"+components/link_header_util", # for LinkHeader.cpp
"+net/base/load_flags.h",
"+net/base/net_errors.h",
+ "+net/traffic_annotation/network_traffic_annotation_test_helper.h",
+ "+net/url_request/redirect_info.h",
"+services/metrics/public", # for UKM API
"+services/network/public", # for Fetch API and CORS
+ "+third_party/blink/renderer/platform/back_forward_cache_utils.h",
"+third_party/blink/renderer/platform/bindings/dom_wrapper_world.h",
"+third_party/blink/renderer/platform/bindings/parkable_string.h",
"+third_party/blink/renderer/platform/bindings/script_forbidden_scope.h",
@@ -28,6 +31,7 @@ include_rules = [
"+third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h",
"+third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h",
"+third_party/blink/renderer/platform/mhtml",
+ "+third_party/blink/renderer/platform/mojo/mojo_binding_context.h",
"+third_party/blink/renderer/platform/network",
"+third_party/blink/renderer/platform/platform_export.h",
"+third_party/blink/renderer/platform/platform_probe_sink.h",
diff --git a/chromium/third_party/blink/renderer/platform/loader/DIR_METADATA b/chromium/third_party/blink/renderer/platform/loader/DIR_METADATA
new file mode 100644
index 00000000000..a080a748373
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Loader"
+}
+team_email: "loading-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/loader/OWNERS b/chromium/third_party/blink/renderer/platform/loader/OWNERS
index 1c34e1edc6a..b46fa621550 100644
--- a/chromium/third_party/blink/renderer/platform/loader/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/loader/OWNERS
@@ -4,6 +4,3 @@ mkwst@chromium.org
toyoshim@chromium.org
yhirano@chromium.org
yoavweiss@chromium.org
-
-# TEAM: loading-dev@chromium.org
-# COMPONENT: Blink>Loader
diff --git a/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
index 180d4f32735..1d45872564e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
@@ -56,6 +56,16 @@ const WebFeature kTextXmlFeatures[2] = {
WebFeature::kSameOriginTextXml,
};
+const WebFeature kJsonFeatures[2] = {
+ WebFeature::kCrossOriginJsonTypeForScript,
+ WebFeature::kSameOriginJsonTypeForScript,
+};
+
+const WebFeature kUnknownFeatures[2] = {
+ WebFeature::kCrossOriginStrictNosniffWouldBlock,
+ WebFeature::kSameOriginStrictNosniffWouldBlock,
+};
+
// Helper function to decide what to do with with a given mime type. This takes
// - a mime type
// - inputs that affect the decision (is_same_origin, mime_type_check_mode).
@@ -121,6 +131,11 @@ bool AllowMimeTypeAsScript(const String& mime_type,
counter = kTextPlainFeatures[same_origin];
} else if (mime_type.StartsWithIgnoringCase("text/xml")) {
counter = kTextXmlFeatures[same_origin];
+ } else if (mime_type.StartsWithIgnoringCase("text/json") ||
+ mime_type.StartsWithIgnoringCase("application/json")) {
+ counter = kJsonFeatures[same_origin];
+ } else {
+ counter = kUnknownFeatures[same_origin];
}
return true;
diff --git a/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
index 4f47d21a355..f4db8179fc9 100644
--- a/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
@@ -152,6 +152,16 @@ TEST_F(AllowedByNosniffTest, Counters) {
{bla, blubb, "text/plain", kOpaque, WebFeature::kCrossOriginTextPlain},
{bla, bla, "text/plain", kBasic, WebFeature::kSameOriginTextScript},
{bla, bla, "text/plain", kBasic, WebFeature::kSameOriginTextPlain},
+ {bla, bla, "text/json", kBasic, WebFeature::kSameOriginTextScript},
+
+ // JSON
+ {bla, bla, "text/json", kBasic, WebFeature::kSameOriginJsonTypeForScript},
+ {bla, bla, "application/json", kBasic,
+ WebFeature::kSameOriginJsonTypeForScript},
+ {bla, blubb, "text/json", kOpaque,
+ WebFeature::kCrossOriginJsonTypeForScript},
+ {bla, blubb, "application/json", kOpaque,
+ WebFeature::kCrossOriginJsonTypeForScript},
// Test mime type and subtype handling.
{bla, bla, "text/xml", kBasic, WebFeature::kSameOriginTextScript},
@@ -166,6 +176,12 @@ TEST_F(AllowedByNosniffTest, Counters) {
{blubb, blubb, "application/xml", kCors,
WebFeature::kCrossOriginApplicationXml},
{bla, bla, "text/html", kBasic, WebFeature::kSameOriginTextHtml},
+
+ // Unknown
+ {bla, bla, "not/script", kBasic,
+ WebFeature::kSameOriginStrictNosniffWouldBlock},
+ {bla, blubb, "not/script", kOpaque,
+ WebFeature::kCrossOriginStrictNosniffWouldBlock},
};
for (auto& testcase : data) {
diff --git a/chromium/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc b/chromium/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
index c2d4cc78b9b..44ba2e94ed1 100644
--- a/chromium/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
@@ -120,10 +120,29 @@ BoundRemoteMapToPendingRemoteMap(
return output;
}
+// TODO(https://crbug.com/1114822): Remove ScopedRequestCrashKeys (it duplicates
+// a similar class in //services/network/crash_keys.h) once it is no longer used
+// below.
class ScopedRequestCrashKeys {
public:
- explicit ScopedRequestCrashKeys(const network::ResourceRequest& request);
- ~ScopedRequestCrashKeys();
+ static base::debug::CrashKeyString* GetRequestUrlCrashKey() {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "request_url", base::debug::CrashKeySize::Size256);
+ return crash_key;
+ }
+
+ static base::debug::CrashKeyString* GetRequestInitiatorCrashKey() {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "request_initiator", base::debug::CrashKeySize::Size64);
+ return crash_key;
+ }
+
+ explicit ScopedRequestCrashKeys(const network::ResourceRequest& request)
+ : url_(GetRequestUrlCrashKey(), request.url.possibly_invalid_spec()),
+ request_initiator_(GetRequestInitiatorCrashKey(),
+ base::OptionalOrNullptr(request.request_initiator)) {
+ }
+ ~ScopedRequestCrashKeys() = default;
ScopedRequestCrashKeys(const ScopedRequestCrashKeys&) = delete;
ScopedRequestCrashKeys& operator=(const ScopedRequestCrashKeys&) = delete;
@@ -133,26 +152,6 @@ class ScopedRequestCrashKeys {
url::debug::ScopedOriginCrashKey request_initiator_;
};
-base::debug::CrashKeyString* GetRequestUrlCrashKey() {
- static auto* crash_key = base::debug::AllocateCrashKeyString(
- "request_url", base::debug::CrashKeySize::Size256);
- return crash_key;
-}
-
-base::debug::CrashKeyString* GetRequestInitiatorCrashKey() {
- static auto* crash_key = base::debug::AllocateCrashKeyString(
- "request_initiator", base::debug::CrashKeySize::Size64);
- return crash_key;
-}
-
-ScopedRequestCrashKeys::ScopedRequestCrashKeys(
- const network::ResourceRequest& request)
- : url_(GetRequestUrlCrashKey(), request.url.possibly_invalid_spec()),
- request_initiator_(GetRequestInitiatorCrashKey(),
- base::OptionalOrNullptr(request.request_initiator)) {}
-
-ScopedRequestCrashKeys::~ScopedRequestCrashKeys() = default;
-
} // namespace
ChildPendingURLLoaderFactoryBundle::ChildPendingURLLoaderFactoryBundle() =
@@ -238,24 +237,6 @@ network::mojom::URLLoaderFactory* ChildURLLoaderFactoryBundle::GetFactory(
if (base_result)
return base_result;
- // All renderer-initiated requests need to provide a value for
- // |request_initiator| - this is enforced by
- // CorsURLLoaderFactory::IsValidRequest (see the
- // InitiatorLockCompatibility::kNoInitiator case).
- DCHECK(request.request_initiator.has_value());
- if (is_deprecated_process_wide_factory_) {
- // The CHECK condition below (in a Renderer process) is also enforced later
- // (in the NetworkService process) by CorsURLLoaderFactory::IsValidRequest
- // (see the InitiatorLockCompatibility::kNoLock case) - this enforcement may
- // result in a renderer kill when the NetworkService is hosted in a separate
- // process from the Browser process. Despite the redundancy, we want to
- // also have the CHECK below, so that the Renderer process terminates
- // earlier, with a callstack that (unlike the NetworkService
- // mojo::ReportBadMessage) is hopefully useful for tracking down the source
- // of the problem.
- CHECK(request.request_initiator->opaque());
- }
-
InitDirectNetworkFactoryIfNecessary();
DCHECK(direct_network_factory_);
return direct_network_factory_.get();
@@ -293,14 +274,6 @@ void ChildURLLoaderFactoryBundle::CreateLoaderAndStart(
// special prefetch handling.
// TODO(horo): Move this routing logic to network service, when we will have
// the special prefetch handling in network service.
- if ((request.resource_type ==
- static_cast<int>(blink::mojom::ResourceType::kPrefetch)) &&
- prefetch_loader_factory_) {
- prefetch_loader_factory_->CreateLoaderAndStart(
- std::move(loader), routing_id, request_id, options, request,
- std::move(client), traffic_annotation);
- return;
- }
if ((request.load_flags & net::LOAD_PREFETCH) && prefetch_loader_factory_) {
// This is no-state prefetch (see
// WebURLRequest::GetLoadFlagsForWebUrlRequest).
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc b/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
index f759b9a5d3f..919102b97d3 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -4,79 +4,20 @@
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
-#include <memory>
#include <string>
-#include <utility>
#include "net/http/http_util.h"
#include "services/network/public/cpp/cors/cors.h"
-#include "services/network/public/cpp/cors/preflight_cache.h"
-#include "services/network/public/cpp/request_mode.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
-#include "third_party/blink/renderer/platform/network/http_header_map.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
-#include "url/gurl.h"
-#include "url/origin.h"
namespace blink {
namespace {
-base::Optional<std::string> GetHeaderValue(const HTTPHeaderMap& header_map,
- const AtomicString& header_name) {
- if (header_map.Contains(header_name)) {
- return header_map.Get(header_name).Latin1();
- }
- return base::nullopt;
-}
-
-network::cors::PreflightCache& GetPerThreadPreflightCache() {
- DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<network::cors::PreflightCache>,
- cache, ());
- return *cache;
-}
-
-base::Optional<std::string> GetOptionalHeaderValue(
- const HTTPHeaderMap& header_map,
- const AtomicString& header_name) {
- const AtomicString& result = header_map.Get(header_name);
- if (result.IsNull())
- return base::nullopt;
-
- return result.Ascii();
-}
-
-std::unique_ptr<net::HttpRequestHeaders> CreateNetHttpRequestHeaders(
- const HTTPHeaderMap& header_map) {
- std::unique_ptr<net::HttpRequestHeaders> request_headers =
- std::make_unique<net::HttpRequestHeaders>();
- for (HTTPHeaderMap::const_iterator i = header_map.begin(),
- end = header_map.end();
- i != end; ++i) {
- DCHECK(!i->key.IsNull());
- DCHECK(!i->value.IsNull());
- request_headers->SetHeader(i->key.Ascii(), i->value.Ascii());
- }
- return request_headers;
-}
-
-url::Origin AsUrlOrigin(const SecurityOrigin& origin) {
- // "file:" origin is treated like an opaque unique origin when
- // allow-file-access-from-files is not specified. Such origin is not
- // opaque (i.e., IsOpaque() returns false) but still serializes to
- // "null".
- return origin.ToString() == "null" ? url::Origin() : origin.ToUrlOrigin();
-}
-
// A parser for the value of the Access-Control-Expose-Headers header.
class HTTPHeaderNameListParser {
STACK_ALLOCATED();
@@ -159,165 +100,10 @@ class HTTPHeaderNameListParser {
namespace cors {
-base::Optional<network::CorsErrorStatus> CheckAccess(
- const KURL& response_url,
- const HTTPHeaderMap& response_header,
- network::mojom::CredentialsMode credentials_mode,
- const SecurityOrigin& origin) {
- return network::cors::CheckAccess(
- response_url,
- GetHeaderValue(response_header, http_names::kAccessControlAllowOrigin),
- GetHeaderValue(response_header,
- http_names::kAccessControlAllowCredentials),
- credentials_mode, AsUrlOrigin(origin));
-}
-
-base::Optional<network::CorsErrorStatus> CheckPreflightAccess(
- const KURL& response_url,
- const int response_status_code,
- const HTTPHeaderMap& response_header,
- network::mojom::CredentialsMode actual_credentials_mode,
- const SecurityOrigin& origin) {
- return network::cors::CheckPreflightAccess(
- response_url, response_status_code,
- GetHeaderValue(response_header, http_names::kAccessControlAllowOrigin),
- GetHeaderValue(response_header,
- http_names::kAccessControlAllowCredentials),
- actual_credentials_mode, AsUrlOrigin(origin));
-}
-
-base::Optional<network::CorsErrorStatus> CheckRedirectLocation(
- const KURL& url,
- network::mojom::RequestMode request_mode,
- const SecurityOrigin* origin,
- CorsFlag cors_flag) {
- base::Optional<url::Origin> origin_to_pass;
- if (origin)
- origin_to_pass = AsUrlOrigin(*origin);
-
- // Blink-side implementations rewrite the origin instead of setting the
- // tainted flag.
- return network::cors::CheckRedirectLocation(
- url, request_mode, origin_to_pass, cors_flag == CorsFlag::Set, false);
-}
-
-base::Optional<network::CorsErrorStatus> CheckExternalPreflight(
- const HTTPHeaderMap& response_header) {
- return network::cors::CheckExternalPreflight(
- GetHeaderValue(response_header, http_names::kAccessControlAllowExternal));
-}
-
bool IsCorsEnabledRequestMode(network::mojom::RequestMode request_mode) {
return network::cors::IsCorsEnabledRequestMode(request_mode);
}
-base::Optional<network::CorsErrorStatus> EnsurePreflightResultAndCacheOnSuccess(
- const HTTPHeaderMap& response_header_map,
- const String& origin,
- const KURL& request_url,
- const String& request_method,
- const HTTPHeaderMap& request_header_map,
- network::mojom::CredentialsMode request_credentials_mode) {
- DCHECK(!origin.IsNull());
- DCHECK(!request_method.IsNull());
-
- base::Optional<network::mojom::CorsError> error;
-
- std::unique_ptr<network::cors::PreflightResult> result =
- network::cors::PreflightResult::Create(
- request_credentials_mode,
- GetOptionalHeaderValue(response_header_map,
- http_names::kAccessControlAllowMethods),
- GetOptionalHeaderValue(response_header_map,
- http_names::kAccessControlAllowHeaders),
- GetOptionalHeaderValue(response_header_map,
- http_names::kAccessControlMaxAge),
- &error);
- if (error)
- return network::CorsErrorStatus(*error);
-
- base::Optional<network::CorsErrorStatus> status;
- status = result->EnsureAllowedCrossOriginMethod(request_method.Ascii());
- if (status)
- return status;
-
- // |is_revalidating| is not needed for blink-side CORS.
- constexpr bool is_revalidating = false;
- status = result->EnsureAllowedCrossOriginHeaders(
- *CreateNetHttpRequestHeaders(request_header_map), is_revalidating);
- if (status)
- return status;
-
- GetPerThreadPreflightCache().AppendEntry(
- url::Origin::Create(GURL(origin.Ascii())), request_url,
- net::NetworkIsolationKey(), std::move(result));
- return base::nullopt;
-}
-
-bool CheckIfRequestCanSkipPreflight(
- const String& origin,
- const KURL& url,
- network::mojom::CredentialsMode credentials_mode,
- const String& method,
- const HTTPHeaderMap& request_header_map) {
- DCHECK(!origin.IsNull());
- DCHECK(!method.IsNull());
-
- // |is_revalidating| is not needed for blink-side CORS.
- constexpr bool is_revalidating = false;
- return GetPerThreadPreflightCache().CheckIfRequestCanSkipPreflight(
- url::Origin::Create(GURL(origin.Ascii())), url,
- net::NetworkIsolationKey(), credentials_mode, method.Ascii(),
- *CreateNetHttpRequestHeaders(request_header_map), is_revalidating);
-}
-
-// Keep this in sync with the identical function
-// network::cors::CorsURLLoader::CalculateResponseTainting.
-//
-// This is the same as that function except using KURL and SecurityOrigin
-// instead of GURL and url::Origin. We can't combine them because converting
-// SecurityOrigin to url::Origin loses information about origins that are
-// allowed by SecurityPolicy.
-//
-// This function also doesn't use a |tainted_origin| flag because Blink loaders
-// mutate the origin instead of using such a flag.
-network::mojom::FetchResponseType CalculateResponseTainting(
- const KURL& url,
- network::mojom::RequestMode request_mode,
- const SecurityOrigin* origin,
- const SecurityOrigin* isolated_world_origin,
- CorsFlag cors_flag) {
- if (url.ProtocolIsData())
- return network::mojom::FetchResponseType::kBasic;
-
- if (cors_flag == CorsFlag::Set) {
- DCHECK(IsCorsEnabledRequestMode(request_mode));
- return network::mojom::FetchResponseType::kCors;
- }
-
- if (!origin) {
- // This is actually not defined in the fetch spec, but in this case CORS
- // is disabled so no one should care this value.
- return network::mojom::FetchResponseType::kBasic;
- }
-
- if (request_mode == network::mojom::RequestMode::kNoCors) {
- bool can_request = origin->CanRequest(url);
- if (!can_request && isolated_world_origin)
- can_request = isolated_world_origin->CanRequest(url);
- if (!can_request)
- return network::mojom::FetchResponseType::kOpaque;
- }
- return network::mojom::FetchResponseType::kBasic;
-}
-
-bool CalculateCredentialsFlag(
- network::mojom::CredentialsMode credentials_mode,
- network::mojom::FetchResponseType response_tainting) {
- return network::cors::CalculateCredentialsFlag(credentials_mode,
- response_tainting);
-}
-
bool IsCorsSafelistedMethod(const String& method) {
DCHECK(!method.IsNull());
return network::cors::IsCorsSafelistedMethod(method.Latin1());
@@ -327,9 +113,10 @@ bool IsCorsSafelistedContentType(const String& media_type) {
return network::cors::IsCorsSafelistedContentType(media_type.Latin1());
}
-bool IsNoCorsSafelistedHeaderName(const String& name) {
+bool IsNoCorsSafelistedHeader(const String& name, const String& value) {
DCHECK(!name.IsNull());
- return network::cors::IsNoCorsSafelistedHeaderName(name.Latin1());
+ DCHECK(!value.IsNull());
+ return network::cors::IsNoCorsSafelistedHeader(name.Latin1(), value.Latin1());
}
bool IsPrivilegedNoCorsHeaderName(const String& name) {
@@ -337,23 +124,9 @@ bool IsPrivilegedNoCorsHeaderName(const String& name) {
return network::cors::IsPrivilegedNoCorsHeaderName(name.Latin1());
}
-bool IsNoCorsSafelistedHeader(const String& name, const String& value) {
+bool IsNoCorsSafelistedHeaderName(const String& name) {
DCHECK(!name.IsNull());
- DCHECK(!value.IsNull());
- return network::cors::IsNoCorsSafelistedHeader(name.Latin1(), value.Latin1());
-}
-
-Vector<String> CorsUnsafeRequestHeaderNames(const HTTPHeaderMap& headers) {
- net::HttpRequestHeaders::HeaderVector in;
- for (const auto& entry : headers) {
- in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair(
- entry.key.Latin1(), entry.value.Latin1()));
- }
-
- Vector<String> header_names;
- for (const auto& name : network::cors::CorsUnsafeRequestHeaderNames(in))
- header_names.push_back(WebString::FromLatin1(name));
- return header_names;
+ return network::cors::IsNoCorsSafelistedHeaderName(name.Latin1());
}
PLATFORM_EXPORT Vector<String> PrivilegedNoCorsHeaderNames() {
@@ -368,8 +141,13 @@ bool IsForbiddenHeaderName(const String& name) {
}
bool ContainsOnlyCorsSafelistedHeaders(const HTTPHeaderMap& header_map) {
- Vector<String> header_names = CorsUnsafeRequestHeaderNames(header_map);
- return header_names.IsEmpty();
+ net::HttpRequestHeaders::HeaderVector in;
+ for (const auto& entry : header_map) {
+ in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair(
+ entry.key.Latin1(), entry.value.Latin1()));
+ }
+
+ return network::cors::CorsUnsafeRequestHeaderNames(in).empty();
}
bool ContainsOnlyCorsSafelistedOrForbiddenHeaders(
@@ -476,6 +254,7 @@ bool IsNoCorsAllowedContext(mojom::blink::RequestContextType context) {
case mojom::blink::RequestContextType::SHARED_WORKER:
case mojom::blink::RequestContextType::VIDEO:
case mojom::blink::RequestContextType::WORKER:
+ case mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE:
return true;
default:
return false;
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors.h b/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
index e76d68adaa2..f3886e799e6 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -31,78 +31,17 @@ enum class CorsFlag : uint8_t {
namespace cors {
// Thin wrapper functions below are for calling ::network::cors functions from
-// Blink core. Once Out-of-renderer CORS is enabled, following functions will
-// be removed.
-PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckAccess(
- const KURL&,
- const HTTPHeaderMap&,
- network::mojom::CredentialsMode,
- const SecurityOrigin&);
-
-PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckPreflightAccess(
- const KURL&,
- const int response_status_code,
- const HTTPHeaderMap&,
- network::mojom::CredentialsMode,
- const SecurityOrigin&);
-
-PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckRedirectLocation(
- const KURL&,
- network::mojom::RequestMode,
- const SecurityOrigin*,
- CorsFlag);
-
-PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckExternalPreflight(
- const HTTPHeaderMap&);
-
+// Blink core.
PLATFORM_EXPORT bool IsCorsEnabledRequestMode(network::mojom::RequestMode);
-
-PLATFORM_EXPORT base::Optional<network::CorsErrorStatus>
-EnsurePreflightResultAndCacheOnSuccess(
- const HTTPHeaderMap& response_header_map,
- const String& origin,
- const KURL& request_url,
- const String& request_method,
- const HTTPHeaderMap& request_header_map,
- network::mojom::CredentialsMode request_credentials_mode);
-
-PLATFORM_EXPORT bool CheckIfRequestCanSkipPreflight(
- const String& origin,
- const KURL&,
- network::mojom::CredentialsMode,
- const String& method,
- const HTTPHeaderMap& request_header_map);
-
-// Returns the response tainting value
-// (https://fetch.spec.whatwg.org/#concept-request-response-tainting) for a
-// request and the CORS flag, as specified in
-// https://fetch.spec.whatwg.org/#main-fetch.
-PLATFORM_EXPORT network::mojom::FetchResponseType CalculateResponseTainting(
- const KURL& url,
- network::mojom::RequestMode request_mode,
- const SecurityOrigin* origin,
- const SecurityOrigin* isolated_world_origin,
- CorsFlag cors_flag);
-
-PLATFORM_EXPORT bool CalculateCredentialsFlag(
- network::mojom::CredentialsMode credentials_mode,
- network::mojom::FetchResponseType response_tainting);
-
-// Thin wrapper functions that will not be removed even after out-of-renderer
-// CORS is enabled.
PLATFORM_EXPORT bool IsCorsSafelistedMethod(const String& method);
PLATFORM_EXPORT bool IsCorsSafelistedContentType(const String&);
PLATFORM_EXPORT bool IsNoCorsSafelistedHeader(const String& name,
const String& value);
PLATFORM_EXPORT bool IsPrivilegedNoCorsHeaderName(const String& name);
PLATFORM_EXPORT bool IsNoCorsSafelistedHeaderName(const String& name);
-PLATFORM_EXPORT Vector<String> CorsUnsafeRequestHeaderNames(
- const HTTPHeaderMap& headers);
PLATFORM_EXPORT Vector<String> PrivilegedNoCorsHeaderNames();
PLATFORM_EXPORT bool IsForbiddenHeaderName(const String& name);
PLATFORM_EXPORT bool ContainsOnlyCorsSafelistedHeaders(const HTTPHeaderMap&);
-PLATFORM_EXPORT bool ContainsOnlyCorsSafelistedOrForbiddenHeaders(
- const HTTPHeaderMap&);
PLATFORM_EXPORT bool IsOkStatus(int status);
@@ -114,7 +53,6 @@ PLATFORM_EXPORT bool IsOkStatus(int status);
// |kNavigate|.
// This should be identical to CalculateCorsFlag defined in
// //services/network/cors/cors_url_loader.cc.
-// This function will be removed when out-of-renderer CORS is enabled.
PLATFORM_EXPORT bool CalculateCorsFlag(
const KURL& url,
const SecurityOrigin* initiator_origin,
diff --git a/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc b/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
index 173f852a577..33a82641852 100644
--- a/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/cors/cors_test.cc
@@ -7,7 +7,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
@@ -101,87 +100,6 @@ TEST_F(CorsExposedHeadersTest, Asterisk) {
HTTPHeaderSet({"a", "b", "*"}));
}
-// Keep this in sync with the CalculateResponseTainting test in
-// services/network/cors/cors_url_loader_unittest.cc.
-TEST(CorsTest, CalculateResponseTainting) {
- using network::mojom::FetchResponseType;
- using network::mojom::RequestMode;
-
- const KURL same_origin_url("https://example.com/");
- const KURL cross_origin_url("https://example2.com/");
- scoped_refptr<SecurityOrigin> origin_refptr =
- SecurityOrigin::Create(same_origin_url);
- const SecurityOrigin* origin = origin_refptr.get();
- const SecurityOrigin* no_origin = nullptr;
-
- // CORS flag is false, same-origin request
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kSameOrigin,
- origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kNoCors,
- origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kCors,
- origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(FetchResponseType::kBasic,
- cors::CalculateResponseTainting(
- same_origin_url, RequestMode::kCorsWithForcedPreflight, origin,
- nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kNavigate,
- origin, nullptr, CorsFlag::Unset));
-
- // CORS flag is false, cross-origin request
- EXPECT_EQ(
- FetchResponseType::kOpaque,
- cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNoCors,
- origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNavigate,
- origin, nullptr, CorsFlag::Unset));
-
- // CORS flag is true, same-origin request
- EXPECT_EQ(FetchResponseType::kCors,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kCors,
- origin, nullptr, CorsFlag::Set));
- EXPECT_EQ(FetchResponseType::kCors,
- cors::CalculateResponseTainting(
- same_origin_url, RequestMode::kCorsWithForcedPreflight, origin,
- nullptr, CorsFlag::Set));
-
- // CORS flag is true, cross-origin request
- EXPECT_EQ(FetchResponseType::kCors, cors::CalculateResponseTainting(
- cross_origin_url, RequestMode::kCors,
- origin, nullptr, CorsFlag::Set));
- EXPECT_EQ(FetchResponseType::kCors,
- cors::CalculateResponseTainting(
- cross_origin_url, RequestMode::kCorsWithForcedPreflight, origin,
- nullptr, CorsFlag::Set));
-
- // Origin is not provided.
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kNoCors,
- no_origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(same_origin_url, RequestMode::kNavigate,
- no_origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNoCors,
- no_origin, nullptr, CorsFlag::Unset));
- EXPECT_EQ(
- FetchResponseType::kBasic,
- cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNavigate,
- no_origin, nullptr, CorsFlag::Unset));
-}
-
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/DEPS b/chromium/third_party/blink/renderer/platform/loader/fetch/DEPS
index 6b62d911e62..2c306ca7b4d 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/DEPS
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+net/base/ip_endpoint.h",
+ "+net/base/schemeful_site.h",
"+net/dns/public",
"+services/network/public/cpp/fetch_api_utils.h",
"+services/network/public/cpp/optional_trust_token_params.h",
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h b/chromium/third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h
new file mode 100644
index 00000000000..ea87bb15a53
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_BACK_FORWARD_CACHE_LOADER_HELPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_BACK_FORWARD_CACHE_LOADER_HELPER_H_
+
+#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-forward.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// Helper class for in-flight network request support for back-forward cache.
+class PLATFORM_EXPORT BackForwardCacheLoaderHelper
+ : public GarbageCollected<BackForwardCacheLoaderHelper> {
+ public:
+ // Evict the page from BackForwardCache. Should be called when handling an
+ // event which can't proceed if the page is in BackForwardCache and can't be
+ // easily deferred to handle later, for example network redirect handling.
+ virtual void EvictFromBackForwardCache(mojom::RendererEvictionReason reason) {
+ }
+
+ // Called when a network request buffered an additional `num_bytes` while the
+ // in back-forward cache. May be called multiple times.
+ virtual void DidBufferLoadWhileInBackForwardCache(size_t num_bytes) {}
+
+ // Returns true if we can still continue buffering data from in-flight network
+ // requests while in back-forward cache.
+ virtual bool CanContinueBufferingWhileInBackForwardCache() const {
+ return false;
+ }
+
+ virtual void Detach() {}
+
+ virtual void Trace(Visitor*) const {}
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_BACK_FORWARD_CACHE_LOADER_HELPER_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.cc
index b33a8bc2cf0..60743ac1d79 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.cc
@@ -19,7 +19,7 @@ BufferingBytesConsumer* BufferingBytesConsumer::CreateWithDelay(
BytesConsumer* bytes_consumer,
scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner) {
return MakeGarbageCollected<BufferingBytesConsumer>(
- util::PassKey<BufferingBytesConsumer>(), bytes_consumer,
+ base::PassKey<BufferingBytesConsumer>(), bytes_consumer,
std::move(timer_task_runner),
base::TimeDelta::FromMilliseconds(kDelayMilliseconds));
}
@@ -28,12 +28,12 @@ BufferingBytesConsumer* BufferingBytesConsumer::CreateWithDelay(
BufferingBytesConsumer* BufferingBytesConsumer::Create(
BytesConsumer* bytes_consumer) {
return MakeGarbageCollected<BufferingBytesConsumer>(
- util::PassKey<BufferingBytesConsumer>(), bytes_consumer, nullptr,
+ base::PassKey<BufferingBytesConsumer>(), bytes_consumer, nullptr,
base::TimeDelta());
}
BufferingBytesConsumer::BufferingBytesConsumer(
- util::PassKey<BufferingBytesConsumer> key,
+ base::PassKey<BufferingBytesConsumer> key,
BytesConsumer* bytes_consumer,
scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner,
base::TimeDelta buffering_start_delay)
@@ -165,6 +165,7 @@ BytesConsumer::Error BufferingBytesConsumer::GetError() const {
void BufferingBytesConsumer::Trace(Visitor* visitor) const {
visitor->Trace(bytes_consumer_);
visitor->Trace(client_);
+ visitor->Trace(timer_);
BytesConsumer::Trace(visitor);
BytesConsumer::Client::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h
index 8ca2f349ca3..44b8a663a76 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -46,7 +46,7 @@ class PLATFORM_EXPORT BufferingBytesConsumer final
// Use the Create*() factory methods instead of direct instantiation.
BufferingBytesConsumer(
- util::PassKey<BufferingBytesConsumer> key,
+ base::PassKey<BufferingBytesConsumer> key,
BytesConsumer* bytes_consumer,
scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner,
base::TimeDelta buffering_start_delay);
@@ -87,7 +87,7 @@ class PLATFORM_EXPORT BufferingBytesConsumer final
void BufferData();
const Member<BytesConsumer> bytes_consumer_;
- TaskRunnerTimer<BufferingBytesConsumer> timer_;
+ HeapTaskRunnerTimer<BufferingBytesConsumer> timer_;
Deque<Vector<char>> buffer_;
size_t offset_for_first_chunk_ = 0;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer_test.cc
index 037092cf783..d77b39794df 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/buffering_bytes_consumer_test.cc
@@ -32,8 +32,8 @@ class BufferingBytesConsumerTest : public testing::Test {
mojo::ScopedDataPipeConsumerHandle consumer_handle;
mojo::ScopedDataPipeProducerHandle producer_handle;
CHECK_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&data_pipe_options, &producer_handle,
- &consumer_handle));
+ mojo::CreateDataPipe(&data_pipe_options, producer_handle,
+ consumer_handle));
return consumer_handle;
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler_test.cc
new file mode 100644
index 00000000000..d9f2f162d1b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler_test.cc
@@ -0,0 +1,135 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this sink code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+namespace {
+
+class MockPlatform final : public TestingPlatformSupportWithMockScheduler {
+ public:
+ MockPlatform() = default;
+ ~MockPlatform() override = default;
+
+ // From blink::Platform:
+ void CacheMetadata(mojom::blink::CodeCacheType cache_type,
+ const WebURL& url,
+ base::Time,
+ const uint8_t*,
+ size_t) override {
+ cached_urls_.push_back(url);
+ }
+
+ void CacheMetadataInCacheStorage(const WebURL& url,
+ base::Time,
+ const uint8_t*,
+ size_t,
+ const WebSecurityOrigin&,
+ const WebString&) override {
+ cache_storage_cached_urls_.push_back(url);
+ }
+
+ const Vector<WebURL>& CachedURLs() const { return cached_urls_; }
+ const Vector<WebURL>& CacheStorageCachedURLs() const {
+ return cache_storage_cached_urls_;
+ }
+
+ private:
+ Vector<WebURL> cached_urls_;
+ Vector<WebURL> cache_storage_cached_urls_;
+};
+
+ResourceResponse CreateTestResourceResponse() {
+ ResourceResponse response(KURL("https://example.com/"));
+ response.SetHttpStatusCode(200);
+ return response;
+}
+
+void SendDataFor(const ResourceResponse& response) {
+ constexpr uint8_t kTestData[] = {1, 2, 3, 4, 5};
+ std::unique_ptr<CachedMetadataSender> sender = CachedMetadataSender::Create(
+ response, mojom::blink::CodeCacheType::kJavascript,
+ SecurityOrigin::Create(response.CurrentRequestUrl()));
+ sender->Send(kTestData, sizeof(kTestData));
+}
+
+TEST(CachedMetadataHandlerTest, SendsMetadataToPlatform) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+ ResourceResponse response(CreateTestResourceResponse());
+
+ SendDataFor(response);
+ EXPECT_EQ(1u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ CachedMetadataHandlerTest,
+ DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(new Response(...))
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+
+ SendDataFor(response);
+ EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ CachedMetadataHandlerTest,
+ SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(fetch(evt.request.url));
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetUrlListViaServiceWorker({response.CurrentRequestUrl()});
+
+ SendDataFor(response);
+ EXPECT_EQ(1u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(
+ CachedMetadataHandlerTest,
+ DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(fetch(some_different_url))
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetUrlListViaServiceWorker(
+ {KURL("https://example.com/different/url")});
+
+ SendDataFor(response);
+ EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
+}
+
+TEST(CachedMetadataHandlerTest,
+ SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
+ ScopedTestingPlatformSupport<MockPlatform> mock;
+
+ // Equivalent to service worker calling respondWith(cache.match(some_url));
+ ResourceResponse response(CreateTestResourceResponse());
+ response.SetWasFetchedViaServiceWorker(true);
+ response.SetCacheStorageCacheName("dummy");
+
+ SendDataFor(response);
+ EXPECT_EQ(0u, mock->CachedURLs().size());
+ EXPECT_EQ(1u, mock->CacheStorageCachedURLs().size());
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
index 638a7f6b0b6..1ff152ca7af 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
@@ -7,13 +7,14 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "services/network/public/cpp/client_hints.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/blink/public/common/client_hints/client_hints.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "url/origin.h"
namespace blink {
@@ -34,6 +35,18 @@ void ClientHintsPreferences::UpdateFrom(
}
}
+void ClientHintsPreferences::CombineWith(
+ const ClientHintsPreferences& preferences) {
+ for (size_t i = 0;
+ i < static_cast<int>(network::mojom::WebClientHintsType::kMaxValue) + 1;
+ ++i) {
+ network::mojom::WebClientHintsType type =
+ static_cast<network::mojom::WebClientHintsType>(i);
+ if (preferences.ShouldSend(type))
+ SetShouldSend(type);
+ }
+}
+
bool ClientHintsPreferences::UserAgentClientHintEnabled() {
return RuntimeEnabledFeatures::UserAgentClientHintEnabled() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -83,8 +96,7 @@ void ClientHintsPreferences::UpdateFromHttpEquivAcceptCH(
// static
bool ClientHintsPreferences::IsClientHintsAllowed(const KURL& url) {
return (url.ProtocolIs("http") || url.ProtocolIs("https")) &&
- (SecurityOrigin::IsSecure(url) ||
- SecurityOrigin::Create(url)->IsLocalhost());
+ network::IsOriginPotentiallyTrustworthy(url::Origin::Create(url));
}
WebEnabledClientHints ClientHintsPreferences::GetWebEnabledClientHints() const {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
index 0d1a88e2322..7083040b28e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
@@ -31,6 +31,7 @@ class PLATFORM_EXPORT ClientHintsPreferences {
ClientHintsPreferences();
void UpdateFrom(const ClientHintsPreferences&);
+ void CombineWith(const ClientHintsPreferences&);
// Parses <meta http-equiv="accept-ch"> value |header_value|, and updates
// |this| to enable the requested client hints. |url| is the URL of the page.
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
index b1c50f139e5..a0db4ee39df 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
@@ -45,16 +45,18 @@ TEST_F(ClientHintsPreferencesTest, BasicSecure) {
false, false, false},
{"DPRW", false, false, false, false, false, false, false, false, false,
false, false, false},
- {"ua", false, false, false, false, false, false, false, true, false,
- false, false, false},
- {"ua-arch", false, false, false, false, false, false, false, false, true,
- false, false, false},
- {"ua-platform", false, false, false, false, false, false, false, false,
- false, true, false, false},
- {"ua-model", false, false, false, false, false, false, false, false,
- false, false, true, false},
- {"ua, ua-arch, ua-platform, ua-model, ua-full-version", false, false,
- false, false, false, false, false, true, true, true, true, true},
+ {"sec-ch-ua", false, false, false, false, false, false, false, true,
+ false, false, false, false},
+ {"sec-ch-ua-arch", false, false, false, false, false, false, false, false,
+ true, false, false, false},
+ {"sec-ch-ua-platform", false, false, false, false, false, false, false,
+ false, false, true, false, false},
+ {"sec-ch-ua-model", false, false, false, false, false, false, false,
+ false, false, false, true, false},
+ {"sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, "
+ "sec-ch-ua-full-version",
+ false, false, false, false, false, false, false, true, true, true, true,
+ true},
};
for (const auto& test_case : cases) {
@@ -254,8 +256,10 @@ TEST_F(ClientHintsPreferencesTest, ParseHeaders) {
false, false, false, false, false},
{"dpr rtt", false, false, false, false, false, false, false, false, false,
false, false, false, false},
- {"ua, ua-arch, ua-platform, ua-model, ua-full-version", false, false,
- false, false, false, false, false, false, true, true, true, true, true},
+ {"sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, "
+ "sec-ch-ua-full-version",
+ false, false, false, false, false, false, false, false, true, true, true,
+ true, true},
};
for (const auto& test : test_cases) {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h b/chromium/third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h
index 2da56da0848..4093593334a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h
@@ -7,6 +7,8 @@
namespace blink {
+// This corresponds to the CORS settings attributes defined in the HTML spec:
+// https://html.spec.whatwg.org/C/#cors-settings-attributes
enum CrossOriginAttributeValue {
kCrossOriginAttributeNotSet,
kCrossOriginAttributeAnonymous,
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer_test.cc
index ec03ab4e89b..9ae4783e87a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer_test.cc
@@ -22,24 +22,26 @@ class DataPipeBytesConsumerTest : public testing::Test {
};
TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
const std::string kData = "Such hospitality. I'm underwhelmed.";
uint32_t write_size = kData.size();
- MojoResult rv = pipe.producer_handle->WriteData(kData.c_str(), &write_size,
- MOJO_WRITE_DATA_FLAG_NONE);
+ MojoResult rv = producer_handle->WriteData(kData.c_str(), &write_size,
+ MOJO_WRITE_DATA_FLAG_NONE);
ASSERT_EQ(MOJO_RESULT_OK, rv);
ASSERT_EQ(kData.size(), write_size);
// Close the producer so the consumer will reach the kDone state after
// completion is signaled below.
- pipe.producer_handle.reset();
+ producer_handle.reset();
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
notifier->SignalComplete();
auto result = MakeGarbageCollected<BytesConsumerTestReader>(consumer)->Run(
task_runner_.get());
@@ -48,22 +50,24 @@ TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead) {
}
TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead_SignalError) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
const std::string kData = "Such hospitality. I'm underwhelmed.";
uint32_t write_size = kData.size();
- MojoResult rv = pipe.producer_handle->WriteData(kData.c_str(), &write_size,
- MOJO_WRITE_DATA_FLAG_NONE);
+ MojoResult rv = producer_handle->WriteData(kData.c_str(), &write_size,
+ MOJO_WRITE_DATA_FLAG_NONE);
ASSERT_EQ(MOJO_RESULT_OK, rv);
ASSERT_EQ(kData.size(), write_size);
- pipe.producer_handle.reset();
+ producer_handle.reset();
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
// Then explicitly signal an error. This should override the pipe completion
// and result in kError.
@@ -79,12 +83,14 @@ TEST_F(DataPipeBytesConsumerTest, TwoPhaseRead_SignalError) {
// must be called for the DataPipeBytesConsumer to reach the closed
// state.
TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeComplete) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -94,7 +100,7 @@ TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeComplete) {
Result rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kShouldWait, rv);
- pipe.producer_handle.reset();
+ producer_handle.reset();
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kShouldWait, rv);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -107,12 +113,14 @@ TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeComplete) {
}
TEST_F(DataPipeBytesConsumerTest, CompleteBeforeEndOfPipe) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -128,7 +136,7 @@ TEST_F(DataPipeBytesConsumerTest, CompleteBeforeEndOfPipe) {
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kShouldWait, rv);
- pipe.producer_handle.reset();
+ producer_handle.reset();
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kDone, rv);
EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState());
@@ -138,12 +146,14 @@ TEST_F(DataPipeBytesConsumerTest, CompleteBeforeEndOfPipe) {
// errored state immediately without waiting for the end of the
// DataPipe.
TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeError) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -153,7 +163,7 @@ TEST_F(DataPipeBytesConsumerTest, EndOfPipeBeforeError) {
Result rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kShouldWait, rv);
- pipe.producer_handle.reset();
+ producer_handle.reset();
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kShouldWait, rv);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -170,8 +180,7 @@ TEST_F(DataPipeBytesConsumerTest, SignalSizeBeforeRead) {
mojo::ScopedDataPipeProducerHandle writable;
const MojoCreateDataPipeOptions options{
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable, &readable));
+ ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, writable, readable));
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
task_runner_, std::move(readable), &notifier);
@@ -212,8 +221,7 @@ TEST_F(DataPipeBytesConsumerTest, SignalExcessSizeBeforeEndOfData) {
mojo::ScopedDataPipeProducerHandle writable;
const MojoCreateDataPipeOptions options{
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable, &readable));
+ ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, writable, readable));
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
task_runner_, std::move(readable), &notifier);
@@ -240,8 +248,7 @@ TEST_F(DataPipeBytesConsumerTest, SignalExcessSizeAfterEndOfData) {
mojo::ScopedDataPipeProducerHandle writable;
const MojoCreateDataPipeOptions options{
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable, &readable));
+ ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, writable, readable));
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
task_runner_, std::move(readable), &notifier);
@@ -268,8 +275,7 @@ TEST_F(DataPipeBytesConsumerTest, SignalSizeAfterRead) {
mojo::ScopedDataPipeProducerHandle writable;
const MojoCreateDataPipeOptions options{
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable, &readable));
+ ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, writable, readable));
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
@@ -300,12 +306,14 @@ TEST_F(DataPipeBytesConsumerTest, SignalSizeAfterRead) {
}
TEST_F(DataPipeBytesConsumerTest, ErrorBeforeEndOfPipe) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -321,7 +329,7 @@ TEST_F(DataPipeBytesConsumerTest, ErrorBeforeEndOfPipe) {
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kError, rv);
- pipe.producer_handle.reset();
+ producer_handle.reset();
rv = consumer->BeginRead(&buffer, &available);
EXPECT_EQ(Result::kError, rv);
EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState());
@@ -330,12 +338,14 @@ TEST_F(DataPipeBytesConsumerTest, ErrorBeforeEndOfPipe) {
// Verify that draining the DataPipe and SignalComplete() will
// close the DataPipeBytesConsumer.
TEST_F(DataPipeBytesConsumerTest, DrainPipeBeforeComplete) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
@@ -360,12 +370,14 @@ TEST_F(DataPipeBytesConsumerTest, DrainPipeBeforeComplete) {
}
TEST_F(DataPipeBytesConsumerTest, CompleteBeforeDrainPipe) {
- mojo::DataPipe pipe;
- ASSERT_TRUE(pipe.producer_handle.is_valid());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
DataPipeBytesConsumer::CompletionNotifier* notifier = nullptr;
DataPipeBytesConsumer* consumer = MakeGarbageCollected<DataPipeBytesConsumer>(
- task_runner_, std::move(pipe.consumer_handle), &notifier);
+ task_runner_, std::move(consumer_handle), &notifier);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
index 4558e08606d..a12b2b814d8 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.cc
@@ -8,73 +8,40 @@
#include "mojo/public/cpp/base/file_path_mojom_traits.h"
#include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h"
#include "third_party/blink/renderer/platform/network/form_data_encoder.h"
#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h"
namespace mojo {
// static
-WTF::Vector<blink::mojom::blink::FetchAPIDataElementPtr>
+WTF::Vector<network::DataElement>
StructTraits<blink::mojom::FetchAPIRequestBodyDataView,
blink::ResourceRequestBody>::elements(blink::ResourceRequestBody&
mutable_body) {
- WTF::Vector<blink::mojom::blink::FetchAPIDataElementPtr> out_elements;
- const auto& body = mutable_body;
- if (body.IsEmpty()) {
- return out_elements;
+ scoped_refptr<network::ResourceRequestBody> network_body;
+ if (auto form_body = mutable_body.FormBody()) {
+ // Here we need to keep the original body, because other members such as
+ // `identifier` are on the form body.
+ network_body = NetworkResourceRequestBodyFor(
+ blink::ResourceRequestBody(form_body),
+ /*allow_http1_for_streaming_upload=*/false);
+ } else if (mutable_body.StreamBody()) {
+ // Here we don't need to keep the original body (and it's impossible to do
+ // so, because the streaming body is not copyable).
+ network_body = NetworkResourceRequestBodyFor(
+ std::move(mutable_body), /*allow_http1_for_streaming_upload=*/false);
}
-
- if (mutable_body.StreamBody()) {
- auto out = blink::mojom::blink::FetchAPIDataElement::New();
- out->type = network::mojom::DataElementType::kReadOnceStream;
- out->chunked_data_pipe_getter = mutable_body.TakeStreamBody();
- out_elements.push_back(std::move(out));
- return out_elements;
+ if (!network_body) {
+ return WTF::Vector<network::DataElement>();
}
-
- DCHECK(body.FormBody());
- for (const auto& element : body.FormBody()->elements_) {
- auto out = blink::mojom::blink::FetchAPIDataElement::New();
- switch (element.type_) {
- case blink::FormDataElement::kData:
- out->type = network::mojom::DataElementType::kBytes;
- out->buf.ReserveCapacity(element.data_.size());
- for (const char c : element.data_) {
- out->buf.push_back(static_cast<uint8_t>(c));
- }
- break;
- case blink::FormDataElement::kEncodedFile:
- out->type = network::mojom::DataElementType::kFile;
- out->path = base::FilePath::FromUTF8Unsafe(element.filename_.Utf8());
- out->offset = element.file_start_;
- out->length = element.file_length_;
- out->expected_modification_time =
- element.expected_file_modification_time_.value_or(base::Time());
- break;
- case blink::FormDataElement::kEncodedBlob: {
- out->type = network::mojom::DataElementType::kDataPipe;
- out->length = element.optional_blob_data_handle_->size();
-
- mojo::Remote<blink::mojom::blink::Blob> blob_remote(
- mojo::PendingRemote<blink::mojom::blink::Blob>(
- element.optional_blob_data_handle_->CloneBlobRemote()
- .PassPipe(),
- blink::mojom::blink::Blob::Version_));
- blob_remote->AsDataPipeGetter(
- out->data_pipe_getter.InitWithNewPipeAndPassReceiver());
- break;
- }
- case blink::FormDataElement::kDataPipe:
- out->type = network::mojom::DataElementType::kDataPipe;
- if (element.data_pipe_getter_) {
- element.data_pipe_getter_->GetDataPipeGetter()->Clone(
- out->data_pipe_getter.InitWithNewPipeAndPassReceiver());
- }
- break;
- }
- out_elements.push_back(std::move(out));
+ WTF::Vector<network::DataElement> out_elements;
+ DCHECK(network_body->elements_mutable());
+ for (auto& element : *network_body->elements_mutable()) {
+ out_elements.emplace_back(std::move(element));
}
return out_elements;
}
@@ -89,73 +56,58 @@ bool StructTraits<blink::mojom::FetchAPIRequestBodyDataView,
return true;
}
- mojo::ArrayDataView<blink::mojom::FetchAPIDataElementDataView> elements_view;
+ mojo::ArrayDataView<network::mojom::DataElementDataView> elements_view;
in.GetElementsDataView(&elements_view);
if (elements_view.size() == 1) {
- blink::mojom::FetchAPIDataElementDataView view;
+ network::mojom::DataElementDataView view;
elements_view.GetDataView(0, &view);
- network::mojom::DataElementType type;
- if (!view.ReadType(&type)) {
- return false;
- }
- if (type == network::mojom::DataElementType::kReadOnceStream) {
- auto chunked_data_pipe_getter = view.TakeChunkedDataPipeGetter<
- mojo::PendingRemote<network::mojom::blink::ChunkedDataPipeGetter>>();
- *out = blink::ResourceRequestBody(std::move(chunked_data_pipe_getter));
+ DCHECK(!view.is_null());
+ if (view.tag() == network::DataElement::Tag::kChunkedDataPipe) {
+ network::DataElement element;
+ if (!elements_view.Read(0, &element)) {
+ return false;
+ }
+ auto& chunked_data_pipe =
+ element.As<network::DataElementChunkedDataPipe>();
+ *out = blink::ResourceRequestBody(blink::ToCrossVariantMojoType(
+ chunked_data_pipe.ReleaseChunkedDataPipeGetter()));
return true;
}
}
auto form_data = blink::EncodedFormData::Create();
for (size_t i = 0; i < elements_view.size(); ++i) {
- blink::mojom::FetchAPIDataElementDataView view;
- elements_view.GetDataView(i, &view);
-
- network::mojom::DataElementType type;
- if (!view.ReadType(&type)) {
+ network::DataElement element;
+ if (!elements_view.Read(i, &element)) {
return false;
}
- switch (type) {
- case network::mojom::DataElementType::kBytes: {
- // TODO(richard.li): Delete this workaround when type of
- // blink::FormDataElement::data_ is changed to WTF::Vector<uint8_t>
- WTF::Vector<uint8_t> buf;
- if (!view.ReadBuf(&buf)) {
- return false;
- }
- form_data->AppendData(buf.data(), buf.size());
+
+ switch (element.type()) {
+ case network::DataElement::Tag::kBytes: {
+ const auto& bytes = element.As<network::DataElementBytes>();
+ form_data->AppendData(bytes.bytes().data(), bytes.bytes().size());
break;
}
- case network::mojom::DataElementType::kFile: {
- base::FilePath file_path;
- base::Time expected_time;
- if (!view.ReadPath(&file_path) ||
- !view.ReadExpectedModificationTime(&expected_time)) {
- return false;
- }
- base::Optional<base::Time> expected_file_modification_time;
- if (!expected_time.is_null()) {
- expected_file_modification_time = expected_time;
+ case network::DataElement::Tag::kFile: {
+ const auto& file = element.As<network::DataElementFile>();
+ base::Optional<base::Time> expected_modification_time;
+ if (!file.expected_modification_time().is_null()) {
+ expected_modification_time = file.expected_modification_time();
}
- form_data->AppendFileRange(blink::FilePathToString(file_path),
- view.offset(), view.length(),
- expected_file_modification_time);
+ form_data->AppendFileRange(blink::FilePathToString(file.path()),
+ file.offset(), file.length(),
+ expected_modification_time);
break;
}
- case network::mojom::DataElementType::kDataPipe: {
- auto data_pipe_ptr_remote = view.TakeDataPipeGetter<
- mojo::PendingRemote<network::mojom::blink::DataPipeGetter>>();
- DCHECK(data_pipe_ptr_remote.is_valid());
-
+ case network::DataElement::Tag::kDataPipe: {
+ auto& datapipe = element.As<network::DataElementDataPipe>();
form_data->AppendDataPipe(
base::MakeRefCounted<blink::WrappedDataPipeGetter>(
- std::move(data_pipe_ptr_remote)));
-
+ blink::ToCrossVariantMojoType(
+ datapipe.ReleaseDataPipeGetter())));
break;
}
- case network::mojom::DataElementType::kUnknown:
- case network::mojom::DataElementType::kChunkedDataPipe:
- case network::mojom::DataElementType::kReadOnceStream:
+ case network::DataElement::Tag::kChunkedDataPipe:
NOTREACHED();
return false;
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.h
index f85aee270a8..4576e3abe9d 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits.h
@@ -21,7 +21,7 @@ struct PLATFORM_EXPORT StructTraits<blink::mojom::FetchAPIRequestBodyDataView,
static void SetToNull(blink::ResourceRequestBody* out) {
*out = blink::ResourceRequestBody();
}
- static WTF::Vector<blink::mojom::blink::FetchAPIDataElementPtr> elements(
+ static WTF::Vector<network::DataElement> elements(
blink::ResourceRequestBody& mutable_body);
static int64_t identifier(const blink::ResourceRequestBody& body) {
return body.FormBody() ? body.FormBody()->Identifier() : 0;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits_test.cc
index 7f96b51c38f..c6505181f2b 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_api_request_body_mojom_traits_test.cc
@@ -30,7 +30,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripEmpty) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
EXPECT_TRUE(dest.IsEmpty());
}
@@ -43,7 +43,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripBytes) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
ASSERT_TRUE(dest.FormBody());
EXPECT_EQ(dest.FormBody()->Identifier(), 29);
@@ -61,7 +61,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripFile) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
ASSERT_TRUE(dest.FormBody());
ASSERT_EQ(1u, dest.FormBody()->Elements().size());
@@ -79,7 +79,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripFileRange) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
ASSERT_TRUE(dest.FormBody());
ASSERT_EQ(1u, dest.FormBody()->Elements().size());
@@ -102,7 +102,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripBlobWithOpionalHandle) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
ASSERT_TRUE(dest.FormBody());
ASSERT_EQ(1u, dest.FormBody()->Elements().size());
@@ -122,7 +122,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripDataPipeGetter) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
ASSERT_TRUE(dest.FormBody());
ASSERT_EQ(1u, dest.FormBody()->Elements().size());
@@ -139,7 +139,7 @@ TEST_F(FetchApiRequestBodyMojomTraitsTest, RoundTripStreamBody) {
ResourceRequestBody dest;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- blink::mojom::blink::FetchAPIRequestBody>(&src, &dest));
+ blink::mojom::blink::FetchAPIRequestBody>(src, dest));
EXPECT_FALSE(dest.FormBody());
ASSERT_TRUE(dest.StreamBody());
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
index c2405674ddf..f3af4183d5c 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
@@ -65,18 +65,6 @@ class PLATFORM_EXPORT FetchClientSettingsObject
// https://html.spec.whatwg.org/C/#concept-settings-object-referrer-policy
virtual network::mojom::ReferrerPolicy GetReferrerPolicy() const = 0;
- // |GetReferrerPolicyDisregardingMetaTagsContainingLists|
- // returns the policy that would have been set had we been ignoring all <meta
- // name=referrer> tags with values comma-separated lists of policies. This
- // allows histogramming the proportion of requests that would end up with
- // different referrers were these tags ignored, helping interpret the impact
- // of removing support for them (which is inconsistent with the spec and other
- // engines).
- virtual base::Optional<network::mojom::ReferrerPolicy>
- GetReferrerPolicyDisregardingMetaTagsContainingLists() const {
- return base::nullopt;
- }
-
// "referrerURL" used in the "Determine request's Referrer" algorithm:
// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
virtual const String GetOutgoingReferrer() const = 0;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index f4d380bda6e..6eef1738995 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -120,6 +120,19 @@ class PLATFORM_EXPORT FetchContext : public GarbageCollected<FetchContext> {
const {
return ResourceRequestBlockedReason::kOther;
}
+ // In derived classes, performs *only* a SubresourceFilter check for whether
+ // the request can go through or should be blocked.
+ virtual base::Optional<ResourceRequestBlockedReason>
+ CanRequestBasedOnSubresourceFilterOnly(
+ ResourceType,
+ const ResourceRequest&,
+ const KURL&,
+ const ResourceLoaderOptions&,
+ ReportingDisposition,
+ const base::Optional<ResourceRequest::RedirectInfo>& redirect_info)
+ const {
+ return ResourceRequestBlockedReason::kOther;
+ }
virtual base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest(
mojom::blink::RequestContextType,
network::mojom::RequestDestination request_destination,
@@ -151,9 +164,11 @@ class PLATFORM_EXPORT FetchContext : public GarbageCollected<FetchContext> {
virtual const FeaturePolicy* GetFeaturePolicy() const { return nullptr; }
// Determine if the request is on behalf of an advertisement. If so, return
- // true.
+ // true. Checks `resource_request.Url()` unless `alias_url` is non-null, in
+ // which case it checks the latter.
virtual bool CalculateIfAdSubresource(
- const ResourceRequest& resource_request,
+ const ResourceRequestHead& resource_request,
+ const base::Optional<KURL>& alias_url,
ResourceType type,
const FetchInitiatorInfo& initiator_info) {
return false;
@@ -174,6 +189,9 @@ class PLATFORM_EXPORT FetchContext : public GarbageCollected<FetchContext> {
return nullptr;
}
+ // Returns if the request context is for prerendering or not.
+ virtual bool IsPrerendering() const { return false; }
+
private:
DISALLOW_COPY_AND_ASSIGN(FetchContext);
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
index 0a351b55b34..c8995c1284e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
@@ -130,4 +130,9 @@ void FetchParameters::SetLazyImageNonBlocking() {
image_request_behavior_ = kNonBlockingImage;
}
+void FetchParameters::SetModuleScript() {
+ DCHECK_EQ(mojom::blink::ScriptType::kClassic, script_type_);
+ script_type_ = mojom::blink::ScriptType::kModule;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
index c38f4571771..cb95a274740 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
@@ -27,10 +27,13 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_FETCH_PARAMETERS_H_
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/script/script_type.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/script/script_type.mojom-shared.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
#include "third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h"
#include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
+#include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
@@ -66,6 +69,7 @@ class PLATFORM_EXPORT FetchParameters {
kNonBlockingImage // The image load may continue, but must be placed in
// ResourceFetcher::non_blocking_loaders_.
};
+
struct ResourceWidth {
DISALLOW_NEW();
float width;
@@ -192,6 +196,10 @@ class PLATFORM_EXPORT FetchParameters {
void SetLazyImageDeferred();
void SetLazyImageNonBlocking();
+ mojom::blink::ScriptType GetScriptType() const { return script_type_; }
+
+ void SetModuleScript();
+
// See documentation in blink::ResourceRequest.
bool IsFromOriginDirtyStyleSheet() const {
return is_from_origin_dirty_style_sheet_;
@@ -204,6 +212,15 @@ class PLATFORM_EXPORT FetchParameters {
resource_request_.SetSignedExchangePrefetchCacheEnabled(enabled);
}
+ RenderBlockingBehavior GetRenderBlockingBehavior() const {
+ return render_blocking_behavior_;
+ }
+
+ void SetRenderBlockingBehavior(
+ RenderBlockingBehavior render_blocking_behavior) {
+ render_blocking_behavior_ = render_blocking_behavior;
+ }
+
private:
ResourceRequest resource_request_;
// |decoder_options_|'s ContentType is set to |kPlainTextContent| in
@@ -216,8 +233,11 @@ class PLATFORM_EXPORT FetchParameters {
ResourceWidth resource_width_;
ClientHintsPreferences client_hint_preferences_;
ImageRequestBehavior image_request_behavior_;
+ mojom::blink::ScriptType script_type_ = mojom::blink::ScriptType::kClassic;
bool is_stale_revalidation_ = false;
bool is_from_origin_dirty_style_sheet_ = false;
+ RenderBlockingBehavior render_blocking_behavior_ =
+ RenderBlockingBehavior::kUnset;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index 5b5a5363894..c5ca2727e80 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -447,7 +447,8 @@ bool MemoryCache::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
return true;
}
-void MemoryCache::OnMemoryPressure(WebMemoryPressureLevel level) {
+void MemoryCache::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
PruneAll();
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
index 16184a56356..74b17f2e573 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
@@ -151,7 +151,8 @@ class PLATFORM_EXPORT MemoryCache final : public GarbageCollected<MemoryCache>,
// Take memory usage snapshot for tracing.
bool OnMemoryDump(WebMemoryDumpLevelOfDetail, WebProcessMemoryDump*) override;
- void OnMemoryPressure(WebMemoryPressureLevel) override;
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel) override;
private:
enum PruneStrategy {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
index f3e230d965f..e647437fdf6 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
@@ -132,7 +132,8 @@ class MemoryCacheCorrectnessTest : public testing::Test {
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
Resource::SetClockForTesting(platform_->test_task_runner()->GetMockClock());
}
void TearDown() override {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
index 3c928d3a779..a1217b9eb1f 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
@@ -104,12 +104,13 @@ class MemoryCacheTest : public testing::Test {
global_memory_cache_ = ReplaceMemoryCacheForTesting(
MakeGarbageCollected<MemoryCache>(platform_->test_task_runner()));
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ lifecycle_notifier_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
properties->MakeDetachable(), MakeGarbageCollected<MockFetchContext>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
- MakeGarbageCollected<TestLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<TestLoaderFactory>(), lifecycle_notifier_,
+ nullptr /* back_forward_cache_loader_helper */));
}
void TearDown() override {
@@ -118,6 +119,7 @@ class MemoryCacheTest : public testing::Test {
Persistent<MemoryCache> global_memory_cache_;
Persistent<ResourceFetcher> fetcher_;
+ Persistent<MockContextLifecycleNotifier> lifecycle_notifier_;
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
platform_;
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
index 965b76b4a08..c4f1754af79 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -36,8 +36,6 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_client_walker.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/response_body_loader.h"
-#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
-#include "third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
@@ -233,11 +231,6 @@ void RawResource::WillNotFollowRedirect() {
c->RedirectBlocked();
}
-SingleCachedMetadataHandler* RawResource::ScriptCacheHandler() {
- DCHECK_EQ(ResourceType::kRaw, GetType());
- return static_cast<SingleCachedMetadataHandler*>(Resource::CacheHandler());
-}
-
scoped_refptr<BlobDataHandle> RawResource::DownloadedBlob() const {
return downloaded_blob_;
}
@@ -300,33 +293,15 @@ void RawResource::ResponseBodyReceived(
client->ResponseBodyReceived(this, body_loader.DrainAsBytesConsumer());
}
-CachedMetadataHandler* RawResource::CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) {
- if (GetType() == ResourceType::kRaw) {
- // This is a resource of indeterminate type, e.g. a fetched WebAssembly
- // module; create a cache handler that can store a single metadata entry.
- return MakeGarbageCollected<ScriptCachedMetadataHandler>(
- Encoding(), std::move(send_callback));
- }
- return Resource::CreateCachedMetadataHandler(std::move(send_callback));
-}
-
void RawResource::SetSerializedCachedMetadata(mojo_base::BigBuffer data) {
// Resource ignores the cached metadata.
Resource::SetSerializedCachedMetadata(mojo_base::BigBuffer());
- // Notify clients before potentially transferring ownership of the buffer.
ResourceClientWalker<RawResourceClient> w(Clients());
- while (RawResourceClient* c = w.Next()) {
- c->SetSerializedCachedMetadata(this, data.data(), data.size());
- }
-
- if (GetType() == ResourceType::kRaw) {
- ScriptCachedMetadataHandler* cache_handler =
- static_cast<ScriptCachedMetadataHandler*>(Resource::CacheHandler());
- if (cache_handler) {
- cache_handler->SetSerializedCachedMetadata(std::move(data));
- }
+ // We rely on the fact that RawResource cannot have multiple clients.
+ CHECK_LE(Clients().size(), 1u);
+ if (RawResourceClient* c = w.Next()) {
+ c->CachedMetadataReceived(this, std::move(data));
}
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
index 12dd376670b..6846361c04a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
@@ -26,6 +26,7 @@
#include <memory>
#include "base/optional.h"
+#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_client.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
@@ -39,7 +40,6 @@ class BufferingBytesConsumer;
class FetchParameters;
class RawResourceClient;
class ResourceFetcher;
-class SingleCachedMetadataHandler;
class PLATFORM_EXPORT RawResource final : public Resource {
public:
@@ -87,19 +87,10 @@ class PLATFORM_EXPORT RawResource final : public Resource {
void SetSerializedCachedMetadata(mojo_base::BigBuffer data) override;
- // Used for code caching of fetched code resources. Returns a cache handler
- // which can only store a single cache metadata entry. This is valid only if
- // type is kRaw.
- SingleCachedMetadataHandler* ScriptCacheHandler();
-
scoped_refptr<BlobDataHandle> DownloadedBlob() const;
void Trace(Visitor* visitor) const override;
- protected:
- CachedMetadataHandler* CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) override;
-
private:
class RawResourceFactory : public NonTextResourceFactory {
public:
@@ -184,7 +175,7 @@ class PLATFORM_EXPORT RawResourceClient : public ResourceClient {
uint64_t /* totalBytesToBeSent */) {}
virtual void ResponseBodyReceived(Resource*, BytesConsumer&) {}
virtual void ResponseReceived(Resource*, const ResourceResponse&) {}
- virtual void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) {}
+ virtual void CachedMetadataReceived(Resource*, mojo_base::BigBuffer) {}
virtual bool RedirectReceived(Resource*,
const ResourceRequest&,
const ResourceResponse&) {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
index 9ed72a6c757..48f308f59eb 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
@@ -67,7 +67,6 @@ class RawResourceTest : public testing::Test {
void DidFinishLoadingBody() override {}
void DidFailLoadingBody() override {}
void DidCancelLoadingBody() override {}
- void EvictFromBackForwardCache(mojom::RendererEvictionReason) override {}
};
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
@@ -243,7 +242,7 @@ TEST_F(RawResourceTest, PreloadWithAsynchronousAddClient) {
ReplayingBytesConsumer::Command(ReplayingBytesConsumer::Command::kDone));
ResponseBodyLoader* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
*bytes_consumer, *MakeGarbageCollected<NoopResponseBodyLoaderClient>(),
- platform_->test_task_runner().get());
+ platform_->test_task_runner().get(), nullptr);
Persistent<DummyClient> dummy_client = MakeGarbageCollected<DummyClient>();
// Set the response first to make ResourceClient addition asynchronous.
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h b/chromium/third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h
new file mode 100644
index 00000000000..7a7761fa226
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RENDER_BLOCKING_BEHAVIOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RENDER_BLOCKING_BEHAVIOR_H_
+
+namespace blink {
+enum class RenderBlockingBehavior : uint8_t {
+ kUnset, // Render blocking value was not set.
+ kBlocking, // Render Blocking resource.
+ kNonBlocking, // Non-blocking resource.
+ kNonBlockingDynamic, // Dynamically injected non-blocking resource.
+ kPotentiallyBlocking, // Dynamically injected non-blocking resource.
+ kInBodyParserBlocking, // Blocks parser below element declaration.
+};
+} // namespace blink
+
+#endif
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 3265d12e68e..b59317fa3e7 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -41,8 +41,6 @@
#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
-#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
-#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
@@ -71,12 +69,6 @@ void NotifyFinishObservers(
observer->NotifyFinished();
}
-blink::mojom::CodeCacheType ToCodeCacheType(ResourceType resource_type) {
- return resource_type == ResourceType::kRaw
- ? blink::mojom::CodeCacheType::kWebAssembly
- : blink::mojom::CodeCacheType::kJavascript;
-}
-
void GetSharedBufferMemoryDump(SharedBuffer* buffer,
const String& dump_prefix,
WebProcessMemoryDump* memory_dump) {
@@ -136,7 +128,8 @@ static inline bool ShouldUpdateHeaderAfterRevalidation(
namespace {
const base::Clock* g_clock_for_testing = nullptr;
-}
+
+} // namespace
static inline base::Time Now() {
const base::Clock* clock = g_clock_for_testing
@@ -163,6 +156,13 @@ Resource::Resource(const ResourceRequestHead& request,
response_timestamp_(Now()),
resource_request_(request),
overhead_size_(CalculateOverheadSize()) {
+ scoped_refptr<const SecurityOrigin> top_frame_origin =
+ resource_request_.TopFrameOrigin();
+ if (top_frame_origin) {
+ net::SchemefulSite site(top_frame_origin->ToUrlOrigin());
+ existing_top_frame_sites_in_cache_.insert(site);
+ }
+
InstanceCounters::IncrementCounter(InstanceCounters::kResourceCounter);
if (IsMainThread())
@@ -175,7 +175,6 @@ Resource::~Resource() {
void Resource::Trace(Visitor* visitor) const {
visitor->Trace(loader_);
- visitor->Trace(cache_handler_);
visitor->Trace(clients_);
visitor->Trace(clients_awaiting_callback_);
visitor->Trace(finished_clients_);
@@ -507,23 +506,12 @@ bool Resource::WillFollowRedirect(const ResourceRequest& new_request,
void Resource::SetResponse(const ResourceResponse& response) {
response_ = response;
-
- // Currently we support the metadata caching only for HTTP family.
- if (!GetResourceRequest().Url().ProtocolIsInHTTPFamily() ||
- !GetResponse().CurrentRequestUrl().ProtocolIsInHTTPFamily()) {
- cache_handler_.Clear();
- return;
- }
-
- cache_handler_ = CreateCachedMetadataHandler(
- CachedMetadataSender::Create(GetResponse(), ToCodeCacheType(GetType()),
- GetResourceRequest().RequestorOrigin()));
}
void Resource::ResponseReceived(const ResourceResponse& response) {
response_timestamp_ = Now();
if (is_revalidating_) {
- if (response.HttpStatusCode() == 304) {
+ if (IsSuccessfulRevalidationResponse(response)) {
RevalidationSucceeded(response);
return;
}
@@ -538,8 +526,6 @@ void Resource::ResponseReceived(const ResourceResponse& response) {
void Resource::SetSerializedCachedMetadata(mojo_base::BigBuffer data) {
DCHECK(!is_revalidating_);
DCHECK(!GetResponse().IsNull());
- // Actual metadata transferred here will be lost.
- DCHECK(!data.size());
}
String Resource::ReasonNotDeletable() const {
@@ -675,11 +661,9 @@ void Resource::DidRemoveClientOrObserver() {
// from volatile storage as promptly as possible"
// "... History buffers MAY store such responses as part of their normal
// operation."
- // We allow non-secure content to be reused in history, but we do not allow
- // secure content to be reused.
- if (HasCacheControlNoStoreHeader() && Url().ProtocolIs("https") &&
- IsMainThread())
+ if (HasCacheControlNoStoreHeader() && IsMainThread()) {
GetMemoryCache()->Remove(this);
+ }
}
}
@@ -765,13 +749,16 @@ Resource::MatchStatus Resource::CanReuse(const FetchParameters& params) const {
return MatchStatus::kUnknownFailure;
}
+ // Use GetResourceRequest to get the const resource_request_.
+ const ResourceRequestHead& current_request = GetResourceRequest();
+
// If credentials were sent with the previous request and won't be with this
// one, or vice versa, re-fetch the resource.
//
// This helps with the case where the server sends back
// "Access-Control-Allow-Origin: *" all the time, but some of the client's
// requests are made without CORS and some with.
- if (GetResourceRequest().AllowStoredCredentials() !=
+ if (current_request.AllowStoredCredentials() !=
new_request.AllowStoredCredentials()) {
return MatchStatus::kRequestCredentialsModeDoesNotMatch;
}
@@ -818,10 +805,10 @@ Resource::MatchStatus Resource::CanReuse(const FetchParameters& params) const {
return MatchStatus::kSynchronousFlagDoesNotMatch;
}
- if (resource_request_.GetKeepalive() || new_request.GetKeepalive())
+ if (current_request.GetKeepalive() || new_request.GetKeepalive())
return MatchStatus::kKeepaliveSet;
- if (GetResourceRequest().HttpMethod() != http_names::kGET ||
+ if (current_request.HttpMethod() != http_names::kGET ||
new_request.HttpMethod() != http_names::kGET) {
return MatchStatus::kRequestMethodDoesNotMatch;
}
@@ -833,16 +820,13 @@ Resource::MatchStatus Resource::CanReuse(const FetchParameters& params) const {
if (!existing_origin->IsSameOriginWith(new_origin.get()))
return MatchStatus::kUnknownFailure;
- // securityOrigin has more complicated checks which callers are responsible
- // for.
-
if (new_request.GetCredentialsMode() !=
- resource_request_.GetCredentialsMode()) {
+ current_request.GetCredentialsMode()) {
return MatchStatus::kRequestCredentialsModeDoesNotMatch;
}
const auto new_mode = new_request.GetMode();
- const auto existing_mode = resource_request_.GetMode();
+ const auto existing_mode = current_request.GetMode();
if (new_mode != existing_mode)
return MatchStatus::kRequestModeDoesNotMatch;
@@ -856,9 +840,6 @@ void Resource::Prune() {
void Resource::OnPurgeMemory() {
Prune();
- if (!cache_handler_)
- return;
- cache_handler_->ClearCachedMetadata(CachedMetadataHandler::kClearLocally);
}
void Resource::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
@@ -924,10 +905,6 @@ void Resource::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
overhead_dump->AddScalar("size", "bytes", OverheadSize());
memory_dump->AddSuballocation(
overhead_dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName));
-
- const String cache_name = dump_name + "/code_cache";
- if (cache_handler_)
- cache_handler_->OnMemoryDump(memory_dump, cache_name);
}
String Resource::GetMemoryDumpName() const {
@@ -977,7 +954,6 @@ void Resource::RevalidationSucceeded(
void Resource::RevalidationFailed() {
SECURITY_CHECK(redirect_chain_.IsEmpty());
ClearData();
- cache_handler_.Clear();
integrity_disposition_ = ResourceIntegrityDisposition::kNotChecked;
integrity_report_info_.Clear();
DestroyDecodedDataForFailedRevalidation();
@@ -1188,19 +1164,6 @@ const char* Resource::ResourceTypeToString(
return InitiatorTypeNameToString(fetch_initiator_name);
}
-// static
-blink::mojom::CodeCacheType Resource::ResourceTypeToCodeCacheType(
- ResourceType resource_type) {
- DCHECK(
- // Cacheable WebAssembly modules are fetched, so raw resource type.
- resource_type == ResourceType::kRaw ||
- // Cacheable Javascript is a script resource.
- resource_type == ResourceType::kScript ||
- // Also accept mock resources for testing.
- resource_type == ResourceType::kMock);
- return ToCodeCacheType(resource_type);
-}
-
bool Resource::IsLoadEventBlockingResourceType() const {
switch (type_) {
case ResourceType::kImage:
@@ -1229,13 +1192,14 @@ void Resource::SetClockForTesting(const base::Clock* clock) {
g_clock_for_testing = clock;
}
-size_t Resource::CodeCacheSize() const {
- return cache_handler_ ? cache_handler_->GetCodeCacheSize() : 0;
+bool Resource::AppendTopFrameSiteForMetrics(const SecurityOrigin& origin) {
+ net::SchemefulSite site(origin.ToUrlOrigin());
+ auto result = existing_top_frame_sites_in_cache_.insert(site);
+ return !result.second;
}
-CachedMetadataHandler* Resource::CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) {
- return nullptr;
+void Resource::SetIsAdResource() {
+ resource_request_.SetIsAdResource();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
index 5ef043e5352..ffbfd4696ca 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -31,6 +31,7 @@
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "mojo/public/cpp/base/big_buffer.h"
+#include "net/base/schemeful_site.h"
#include "third_party/blink/public/mojom/loader/code_cache.mojom-blink-forward.h"
#include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
@@ -63,8 +64,6 @@ class Clock;
namespace blink {
class BlobDataHandle;
-class CachedMetadataHandler;
-class CachedMetadataSender;
class FetchParameters;
class ResourceClient;
class ResourceFinishObserver;
@@ -142,6 +141,9 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
// Match fails due to different request headers.
kRequestHeadersDoNotMatch,
+
+ // Match fails due to different script types.
+ kScriptTypeDoesNotMatch,
};
~Resource() override;
@@ -228,7 +230,7 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
size_t DecodedSize() const { return decoded_size_; }
size_t OverheadSize() const { return overhead_size_; }
- size_t CodeCacheSize() const;
+ virtual size_t CodeCacheSize() const { return 0; }
bool IsLoaded() const { return status_ > ResourceStatus::kPending; }
@@ -266,8 +268,8 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
const ResourceResponse& GetResponse() const { return response_; }
// Sets the serialized metadata retrieved from the platform's cache.
- // Subclasses of Resource that support cached metadata should override this
- // method with one that fills the current CachedMetadataHandler.
+ // The default implementation does nothing. Subclasses interested in the data
+ // should implement the resource-specific behavior.
virtual void SetSerializedCachedMetadata(mojo_base::BigBuffer data);
AtomicString HttpContentType() const;
@@ -382,8 +384,6 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
ResourceType,
const AtomicString& fetch_initiator_name);
- static blink::mojom::CodeCacheType ResourceTypeToCodeCacheType(ResourceType);
-
class ProhibitAddRemoveClientInScope : public base::AutoReset<bool> {
public:
ProhibitAddRemoveClientInScope(Resource* resource)
@@ -407,6 +407,14 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
return CalculateOverheadSize();
}
+ // Appends the top-frame site derived from |origin| to
+ // |existing_top_frame_sites_in_cache_| and returns true if the same site
+ // already exists.
+ bool AppendTopFrameSiteForMetrics(const SecurityOrigin& origin);
+
+ // Sets the ResourceRequest to be tagged as an ad.
+ void SetIsAdResource();
+
protected:
Resource(const ResourceRequestHead&,
ResourceType,
@@ -440,6 +448,11 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
finished_clients_.Contains(client);
}
+ bool IsSuccessfulRevalidationResponse(
+ const ResourceResponse& response) const {
+ return IsCacheValidator() && response.HttpStatusCode() == 304;
+ }
+
struct RedirectPair {
DISALLOW_NEW();
@@ -471,16 +484,6 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
virtual void SetEncoding(const String&) {}
- // Create a handler for the cached metadata of this resource. Subclasses of
- // Resource that support cached metadata should override this method with one
- // that creates an appropriate CachedMetadataHandler implementation, and
- // override SetSerializedCachedMetadata with an implementation that fills the
- // cache handler.
- virtual CachedMetadataHandler* CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback);
-
- CachedMetadataHandler* CacheHandler() { return cache_handler_.Get(); }
-
private:
friend class ResourceLoader;
@@ -500,8 +503,6 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
ResourceType type_;
ResourceStatus status_;
- Member<CachedMetadataHandler> cache_handler_;
-
base::Optional<ResourceError> error_;
base::TimeTicks load_response_end_;
@@ -552,6 +553,13 @@ class PLATFORM_EXPORT Resource : public GarbageCollected<Resource>,
WebScopedVirtualTimePauser virtual_time_pauser_;
+ // To compute metrics for measuring the efficacy of the
+ // memory cache if it was partitioned by top-frame site (in addition to the
+ // current origin which it is already partitioned by).
+ // TODO(crbug.com/1127971): Remove this once the decision is made to partition
+ // the cache using either Network Isolation Key or scoped to per-document.
+ std::set<net::SchemefulSite> existing_top_frame_sites_in_cache_;
+
DISALLOW_COPY_AND_ASSIGN(Resource);
};
@@ -592,11 +600,6 @@ class NonTextResourceFactory : public ResourceFactory {
}
};
-#define DEFINE_RESOURCE_TYPE_CASTS(typeName) \
- DEFINE_TYPE_CASTS(typeName##Resource, Resource, resource, \
- resource->GetType() == ResourceType::k##typeName, \
- resource.GetType() == ResourceType::k##typeName)
-
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index 784a98d7377..adb87702500 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -180,7 +180,8 @@ bool ResourceError::IsCancellation() const {
}
bool ResourceError::IsTrustTokenCacheHit() const {
- return error_code_ == net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT;
+ return error_code_ ==
+ net::ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST;
}
bool ResourceError::IsUnactionableTrustTokensStatus() const {
@@ -300,9 +301,8 @@ String DescriptionForBlockedByClientOrResponse(int error, int extended_error) {
case ResourceRequestBlockedReason::kCorpNotSameSite:
detail = "NotSameSite";
break;
- case ResourceRequestBlockedReason::
- kBlockedByExtensionCrbug1128174Investigation:
- detail = "BlockedByExtensionCrbug1128174Investigation";
+ case ResourceRequestBlockedReason::kConversionRequest:
+ detail = "ConversionRequest";
break;
}
return WebString::FromASCII(net::ErrorToString(error) + "." + detail);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 7c99713e600..3c445ddaa2b 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -47,6 +47,7 @@
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
@@ -56,6 +57,7 @@
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
#include "third_party/blink/renderer/platform/loader/fetch/detachable_use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
@@ -75,6 +77,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/mhtml/archive_resource.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -242,50 +245,6 @@ ResourceLoadPriority AdjustPriorityWithPriorityHint(
return new_priority;
}
-ResourceLoadPriority AdjustPriorityWithDeferScriptIntervention(
- const FetchContext& fetch_context,
- ResourceLoadPriority priority_so_far,
- ResourceType type,
- const ResourceRequestHead& resource_request,
- FetchParameters::DeferOption defer_option,
- bool is_link_preload) {
- if (!base::FeatureList::IsEnabled(
- blink::features::kLowerJavaScriptPriorityWhenForceDeferred)) {
- return priority_so_far;
- }
-
- PreviewsState context_previews_state = fetch_context.previews_state();
-
- if (type != ResourceType::kScript)
- return priority_so_far;
-
- // If none of the JavaScript resources are render blocking (due to the
- // DeferAllScript intervention), then lower their priority so they do not
- // contend for network resources with higher priority resources that may be
- // render blocking (e.g., html, css). ResourceLoadPriority::kMedium
- // corresponds to a network priority of
- // network::mojom::blink::RequestPriority::kLow which is considered delayable
- // by the resource scheduler on the browser side.
- if (RuntimeEnabledFeatures::ForceDeferScriptInterventionEnabled() ||
- (context_previews_state & PreviewsTypes::kDeferAllScriptOn)) {
- return std::min(priority_so_far, ResourceLoadPriority::kMedium);
- }
- return priority_so_far;
-}
-
-std::unique_ptr<TracedValue> BeginResourceLoadData(
- const blink::ResourceRequest& request) {
- auto value = std::make_unique<TracedValue>();
- value->SetString("url", request.Url().GetString());
- return value;
-}
-
-std::unique_ptr<TracedValue> EndResourceLoadFailData() {
- auto value = std::make_unique<TracedValue>();
- value->SetString("outcome", "Fail");
- return value;
-}
-
std::unique_ptr<TracedValue> ResourcePrioritySetData(
blink::ResourceLoadPriority priority) {
auto value = std::make_unique<TracedValue>();
@@ -295,9 +254,9 @@ std::unique_ptr<TracedValue> ResourcePrioritySetData(
// This function corresponds with step 2 substep 7 of
// https://fetch.spec.whatwg.org/#main-fetch.
-void SetReferrer(ResourceRequest& request,
- const FetchClientSettingsObject& fetch_client_settings_object,
- UseCounter& use_counter) {
+void SetReferrer(
+ ResourceRequest& request,
+ const FetchClientSettingsObject& fetch_client_settings_object) {
String referrer_to_use = request.ReferrerString();
network::mojom::ReferrerPolicy referrer_policy_to_use =
request.GetReferrerPolicy();
@@ -305,42 +264,12 @@ void SetReferrer(ResourceRequest& request,
if (referrer_to_use == Referrer::ClientReferrerString())
referrer_to_use = fetch_client_settings_object.GetOutgoingReferrer();
- bool used_referrer_policy_from_context = false;
- if (referrer_policy_to_use == network::mojom::ReferrerPolicy::kDefault) {
- used_referrer_policy_from_context = true;
+ if (referrer_policy_to_use == network::mojom::ReferrerPolicy::kDefault)
referrer_policy_to_use = fetch_client_settings_object.GetReferrerPolicy();
- }
Referrer generated_referrer = SecurityPolicy::GenerateReferrer(
referrer_policy_to_use, request.Url(), referrer_to_use);
- // The request's referrer would be different in the absence of <meta
- // name=referrer> tags with comma-separated-list values exactly when both
- // 1. the request falls back to its client settings object's policy; and
- // 2. if we recompute the referrer using the value of the client settings
- // object's policy, disregarding any policy that came from a meta tag with a
- // comma-separated value, we obtain a different referrer.
- if (used_referrer_policy_from_context) {
- base::Optional<network::mojom::blink::ReferrerPolicy>
- policy_but_for_meta_tags_with_policy_lists =
- fetch_client_settings_object
- .GetReferrerPolicyDisregardingMetaTagsContainingLists();
-
- bool referrer_would_be_different_absent_meta_tags_with_policy_lists =
- policy_but_for_meta_tags_with_policy_lists.has_value() &&
- (generated_referrer.referrer !=
- SecurityPolicy::GenerateReferrer(
- *policy_but_for_meta_tags_with_policy_lists, request.Url(),
- referrer_to_use)
- .referrer);
-
- if (referrer_would_be_different_absent_meta_tags_with_policy_lists) {
- use_counter.CountUse(
- mojom::WebFeature::
- kHTMLMetaElementReferrerPolicyMultipleTokensAffectingRequest);
- }
- }
-
request.SetReferrerString(generated_referrer.referrer);
request.SetReferrerPolicy(generated_referrer.referrer_policy);
}
@@ -371,13 +300,15 @@ ResourceFetcherInit::ResourceFetcherInit(
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
ResourceFetcher::LoaderFactory* loader_factory,
- ContextLifecycleNotifier* context_lifecycle_notifier)
+ ContextLifecycleNotifier* context_lifecycle_notifier,
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper)
: properties(&properties),
context(context),
freezable_task_runner(std::move(freezable_task_runner)),
unfreezable_task_runner(std::move(unfreezable_task_runner)),
loader_factory(loader_factory),
- context_lifecycle_notifier(context_lifecycle_notifier) {
+ context_lifecycle_notifier(context_lifecycle_notifier),
+ back_forward_cache_loader_helper(back_forward_cache_loader_helper) {
DCHECK(context);
DCHECK(this->freezable_task_runner);
DCHECK(this->unfreezable_task_runner);
@@ -553,10 +484,6 @@ ResourceLoadPriority ResourceFetcher::ComputeLoadPriority(
priority = AdjustPriorityWithPriorityHint(priority, type, resource_request,
defer_option, is_link_preload);
- priority = AdjustPriorityWithDeferScriptIntervention(
- Context(), priority, type, resource_request, defer_option,
- is_link_preload);
-
if (properties_->IsSubframeDeprioritizationEnabled()) {
if (properties_->IsMainFrame()) {
UMA_HISTOGRAM_ENUMERATION(
@@ -601,6 +528,7 @@ ResourceFetcher::ResourceFetcher(const ResourceFetcherInit& init)
init.frame_or_worker_scheduler,
*console_logger_,
init.loading_behavior_observer)),
+ back_forward_cache_loader_helper_(init.back_forward_cache_loader_helper),
archive_(init.archive),
resource_timing_report_timer_(
freezable_task_runner_,
@@ -645,6 +573,11 @@ ResourceFetcher::IsControlledByServiceWorker() const {
bool ResourceFetcher::ResourceNeedsLoad(Resource* resource,
const FetchParameters& params,
RevalidationPolicy policy) {
+ // MHTML documents should not trigger actual loads (i.e. all resource requests
+ // should be fulfilled by the MHTML archive).
+ if (archive_)
+ return false;
+
// Defer a font load until it is actually needed unless this is a link
// preload.
if (resource->GetType() == ResourceType::kFont && !params.IsLinkPreload())
@@ -664,13 +597,15 @@ bool ResourceFetcher::ResourceNeedsLoad(Resource* resource,
void ResourceFetcher::DidLoadResourceFromMemoryCache(
Resource* resource,
const ResourceRequest& request,
- bool is_static_data) {
+ bool is_static_data,
+ RenderBlockingBehavior render_blocking_behavior) {
if (IsDetached() || !resource_load_observer_)
return;
resource_load_observer_->WillSendRequest(
request.InspectorId(), request, ResourceResponse() /* redirects */,
- resource->GetType(), resource->Options().initiator_info);
+ resource->GetType(), resource->Options().initiator_info,
+ render_blocking_behavior);
resource_load_observer_->DidReceiveResponse(
request.InspectorId(), request, resource->GetResponse(), resource,
ResourceLoadObserver::ResponseSource::kFromMemoryCache);
@@ -707,7 +642,7 @@ void ResourceFetcher::DidLoadResourceFromMemoryCache(
}
}
-Resource* ResourceFetcher::ResourceForStaticData(
+Resource* ResourceFetcher::CreateResourceForStaticData(
const FetchParameters& params,
const ResourceFactory& factory) {
const KURL& url = params.GetResourceRequest().Url();
@@ -801,11 +736,13 @@ void ResourceFetcher::MakePreloadedResourceBlockOnloadIfNeeded(
}
}
-void ResourceFetcher::UpdateMemoryCacheStats(Resource* resource,
- RevalidationPolicy policy,
- const FetchParameters& params,
- const ResourceFactory& factory,
- bool is_static_data) const {
+void ResourceFetcher::UpdateMemoryCacheStats(
+ Resource* resource,
+ RevalidationPolicy policy,
+ const FetchParameters& params,
+ const ResourceFactory& factory,
+ bool is_static_data,
+ bool same_top_frame_site_resource_cached) const {
if (is_static_data)
return;
@@ -813,6 +750,11 @@ void ResourceFetcher::UpdateMemoryCacheStats(Resource* resource,
DEFINE_RESOURCE_HISTOGRAM("Preload.");
} else {
DEFINE_RESOURCE_HISTOGRAM("");
+
+ // Log metrics to evaluate effectiveness of the memory cache if it was
+ // partitioned by the top-frame site.
+ if (same_top_frame_site_resource_cached)
+ DEFINE_RESOURCE_HISTOGRAM("PerTopFrameSite.");
}
// Aims to count Resource only referenced from MemoryCache (i.e. what would be
@@ -924,6 +866,8 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
DCHECK_NE(computed_load_priority, ResourceLoadPriority::kUnresolved);
resource_request.SetPriority(computed_load_priority);
+ resource_request.SetRenderBlockingBehavior(
+ params.GetRenderBlockingBehavior());
if (resource_request.GetCacheMode() == mojom::FetchCacheMode::kDefault) {
resource_request.SetCacheMode(Context().ResourceRequestCachePolicy(
@@ -947,8 +891,7 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
http_names::kGET &&
!params.IsStaleRevalidation());
- SetReferrer(resource_request, properties_->GetFetchClientSettingsObject(),
- GetUseCounter());
+ SetReferrer(resource_request, properties_->GetFetchClientSettingsObject());
resource_request.SetExternalRequestStateFromRequestorAddressSpace(
properties_->GetFetchClientSettingsObject().GetAddressSpace());
@@ -959,7 +902,7 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
TRACE_DISABLED_BY_DEFAULT("network"), "ResourcePrioritySet",
TRACE_ID_WITH_SCOPE("BlinkResourceID",
TRACE_ID_LOCAL(resource_request.InspectorId())),
- "data", ResourcePrioritySetData(resource_request.Priority()));
+ "priority", resource_request.Priority());
KURL url = MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url());
base::Optional<ResourceRequestBlockedReason> blocked_reason =
@@ -967,8 +910,9 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
reporting_disposition,
resource_request.GetRedirectInfo());
- if (Context().CalculateIfAdSubresource(resource_request, resource_type,
- options.initiator_info))
+ if (Context().CalculateIfAdSubresource(resource_request,
+ base::nullopt /* alias_url */,
+ resource_type, options.initiator_info))
resource_request.SetIsAdResource();
if (blocked_reason)
@@ -988,9 +932,37 @@ base::Optional<ResourceRequestBlockedReason> ResourceFetcher::PrepareRequest(
resource_request.SetAllowStoredCredentials(false);
}
+ if (resource_request.GetWebBundleTokenParams()) {
+ DCHECK_EQ(resource_request.GetRequestDestination(),
+ network::mojom::RequestDestination::kWebBundle);
+ } else {
+ AttachWebBundleTokenIfNeeded(resource_request);
+ }
+
return base::nullopt;
}
+bool ResourceFetcher::ShouldBeLoadedFromWebBundle(const KURL& url) const {
+ for (auto& bundle : subresource_web_bundles_) {
+ if (bundle->CanHandleRequest(url))
+ return true;
+ }
+ return false;
+}
+
+void ResourceFetcher::AttachWebBundleTokenIfNeeded(
+ ResourceRequest& resource_request) const {
+ for (auto& bundle : subresource_web_bundles_) {
+ if (!bundle->CanHandleRequest(resource_request.Url()))
+ continue;
+ resource_request.SetWebBundleTokenParams(
+ ResourceRequestHead::WebBundleTokenParams(bundle->GetBundleUrl(),
+ bundle->WebBundleToken(),
+ mojo::NullRemote()));
+ return;
+ }
+}
+
Resource* ResourceFetcher::RequestResource(FetchParameters& params,
const ResourceFactory& factory,
ResourceClient* client) {
@@ -1022,8 +994,8 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
params.IsFromOriginDirtyStyleSheet());
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
TRACE_DISABLED_BY_DEFAULT("network"), "ResourceLoad",
- TRACE_ID_WITH_SCOPE("BlinkResourceID", TRACE_ID_LOCAL(identifier)),
- "beginData", BeginResourceLoadData(resource_request));
+ TRACE_ID_WITH_SCOPE("BlinkResourceID", TRACE_ID_LOCAL(identifier)), "url",
+ resource_request.Url());
SCOPED_BLINK_UMA_HISTOGRAM_TIMER_THREAD_SAFE(
"Blink.Fetch.RequestResourceTime");
TRACE_EVENT1("blink", "ResourceFetcher::requestResource", "url",
@@ -1054,7 +1026,7 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
bool is_static_data = is_data_url || archive_;
bool is_stale_revalidation = params.IsStaleRevalidation();
if (!is_stale_revalidation && is_static_data) {
- resource = ResourceForStaticData(params, factory);
+ resource = CreateResourceForStaticData(params, factory);
if (resource) {
policy =
DetermineRevalidationPolicy(resource_type, params, *resource, true);
@@ -1068,6 +1040,10 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
}
}
+ bool same_top_frame_site_resource_cached = false;
+ bool in_cached_resources_map = cached_resources_map_.Contains(
+ MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url()));
+
if (!is_stale_revalidation && !resource) {
resource = MatchPreload(params, resource_type);
if (resource) {
@@ -1076,16 +1052,28 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
// found, we may need to make it block the onload event.
MakePreloadedResourceBlockOnloadIfNeeded(resource, params);
} else if (IsMainThread()) {
- resource = GetMemoryCache()->ResourceForURL(
- params.Url(), GetCacheIdentifier(params.Url()));
+ if (base::FeatureList::IsEnabled(features::kScopeMemoryCachePerContext) &&
+ !in_cached_resources_map) {
+ resource = nullptr;
+ } else {
+ resource = GetMemoryCache()->ResourceForURL(
+ params.Url(), GetCacheIdentifier(params.Url()));
+ }
if (resource) {
policy = DetermineRevalidationPolicy(resource_type, params, *resource,
is_static_data);
+ scoped_refptr<const SecurityOrigin> top_frame_origin =
+ resource_request.TopFrameOrigin();
+ if (top_frame_origin) {
+ same_top_frame_site_resource_cached =
+ resource->AppendTopFrameSiteForMetrics(*top_frame_origin);
+ }
}
}
}
- UpdateMemoryCacheStats(resource, policy, params, factory, is_static_data);
+ UpdateMemoryCacheStats(resource, policy, params, factory, is_static_data,
+ same_top_frame_site_resource_cached);
switch (policy) {
case RevalidationPolicy::kReload:
@@ -1133,10 +1121,10 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
DCHECK(EqualIgnoringFragmentIdentifier(resource->Url(), params.Url()));
if (policy == RevalidationPolicy::kUse &&
resource->GetStatus() == ResourceStatus::kCached &&
- !cached_resources_map_.Contains(
- MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url()))) {
+ !in_cached_resources_map) {
// Loaded from MemoryCache.
- DidLoadResourceFromMemoryCache(resource, resource_request, is_static_data);
+ DidLoadResourceFromMemoryCache(resource, resource_request, is_static_data,
+ params.GetRenderBlockingBehavior());
}
if (!is_stale_revalidation) {
String resource_url =
@@ -1154,13 +1142,14 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
// load-blocking. Lazy loaded images that are eventually fetched, however,
// should always be added to |non_blocking_loaders_|, as they are never
// load-blocking.
- LoadBlockingPolicy load_blocking_policy = LoadBlockingPolicy::kDefault;
+ ImageLoadBlockingPolicy load_blocking_policy =
+ ImageLoadBlockingPolicy::kDefault;
if (resource->GetType() == ResourceType::kImage) {
image_resources_.insert(resource);
not_loaded_image_resources_.insert(resource);
if (params.GetImageRequestBehavior() ==
FetchParameters::kNonBlockingImage) {
- load_blocking_policy = LoadBlockingPolicy::kForceNonBlockingLoad;
+ load_blocking_policy = ImageLoadBlockingPolicy::kForceNonBlockingLoad;
}
}
@@ -1171,7 +1160,7 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
if (ResourceNeedsLoad(resource, params, policy)) {
if (!StartLoad(resource,
std::move(params.MutableResourceRequest().MutableBody()),
- load_blocking_policy)) {
+ load_blocking_policy, params.GetRenderBlockingBehavior())) {
resource->FinishAsError(ResourceError::CancelledError(params.Url()),
freezable_task_runner_.get());
}
@@ -1185,7 +1174,7 @@ Resource* ResourceFetcher::RequestResource(FetchParameters& params,
TRACE_EVENT_NESTABLE_ASYNC_END1(
TRACE_DISABLED_BY_DEFAULT("network"), "ResourceLoad",
TRACE_ID_WITH_SCOPE("BlinkResourceID", TRACE_ID_LOCAL(identifier)),
- "endData", EndResourceLoadFailData());
+ "outcome", "Fail");
}
return resource;
@@ -1250,22 +1239,10 @@ std::unique_ptr<WebURLLoader> ResourceFetcher::CreateURLLoader(
const ResourceLoaderOptions& options) {
DCHECK(!GetProperties().IsDetached());
DCHECK(loader_factory_);
- for (auto& bundle : subresource_web_bundles_) {
- if (!bundle->CanHandleRequest(request.Url()))
- continue;
- ResourceLoaderOptions new_options(options);
- new_options.url_loader_factory = base::MakeRefCounted<base::RefCountedData<
- mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>>>(
- bundle->GetURLLoaderFactory());
- // TODO(yoichio): CreateURLLoader take a ResourceRequestHead instead of
- // ResourceRequest.
- return loader_factory_->CreateURLLoader(ResourceRequest(request),
- new_options, freezable_task_runner_,
- unfreezable_task_runner_);
- }
- return loader_factory_->CreateURLLoader(ResourceRequest(request), options,
- freezable_task_runner_,
- unfreezable_task_runner_);
+ return loader_factory_->CreateURLLoader(
+ ResourceRequest(request), options, freezable_task_runner_,
+ unfreezable_task_runner_,
+ WebBackForwardCacheLoaderHelper(back_forward_cache_loader_helper_));
}
std::unique_ptr<WebCodeCacheLoader> ResourceFetcher::CreateCodeCacheLoader() {
@@ -1287,9 +1264,12 @@ Resource* ResourceFetcher::CreateResourceForLoading(
const ResourceFactory& factory) {
const String cache_identifier =
GetCacheIdentifier(params.GetResourceRequest().Url());
- DCHECK(!IsMainThread() || params.IsStaleRevalidation() ||
- !GetMemoryCache()->ResourceForURL(params.GetResourceRequest().Url(),
- cache_identifier));
+ if (!base::FeatureList::IsEnabled(
+ blink::features::kScopeMemoryCachePerContext)) {
+ DCHECK(!IsMainThread() || params.IsStaleRevalidation() ||
+ !GetMemoryCache()->ResourceForURL(params.GetResourceRequest().Url(),
+ cache_identifier));
+ }
RESOURCE_LOADING_DVLOG(1) << "Loading Resource for "
<< params.GetResourceRequest().Url().ElidedString();
@@ -1426,6 +1406,9 @@ void ResourceFetcher::PrintPreloadWarning(Resource* resource,
case Resource::MatchStatus::kRequestHeadersDoNotMatch:
builder.Append("because the request headers do not match.");
break;
+ case Resource::MatchStatus::kScriptTypeDoesNotMatch:
+ builder.Append("because the script type does not match.");
+ break;
}
console_logger_->AddConsoleMessage(mojom::ConsoleMessageSource::kOther,
mojom::ConsoleMessageLevel::kWarning,
@@ -1519,6 +1502,8 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
bool is_static_data) const {
const ResourceRequest& request = fetch_params.GetResourceRequest();
+ Resource* cached_resource_in_fetcher = CachedResource(request.Url());
+
if (IsDownloadOrStreamRequest(request)) {
return {RevalidationPolicy::kReload,
"It is for download or for streaming."};
@@ -1578,7 +1563,7 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
// If resource was populated from archive or data: url, use it.
// This doesn't necessarily mean that |resource| was just created by using
- // ResourceForStaticData().
+ // CreateResourceForStaticData().
if (is_static_data) {
return {RevalidationPolicy::kUse, "Use the existing static resource."};
}
@@ -1640,7 +1625,7 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
// validation. We restrict this only to images from memory cache which are the
// same as the version in the current document.
if (type == ResourceType::kImage &&
- &existing_resource == CachedResource(request.Url())) {
+ &existing_resource == cached_resource_in_fetcher) {
return {RevalidationPolicy::kUse,
"Images can be reused without cache validation."};
}
@@ -1758,6 +1743,8 @@ void ResourceFetcher::ClearContext() {
resource_load_observer_ = nullptr;
use_counter_->Detach();
console_logger_->Detach();
+ if (back_forward_cache_loader_helper_)
+ back_forward_cache_loader_helper_->Detach();
loader_factory_ = nullptr;
unused_preloads_timer_.Cancel();
@@ -1962,18 +1949,32 @@ void ResourceFetcher::MoveResourceLoaderToNonBlocking(ResourceLoader* loader) {
}
bool ResourceFetcher::StartLoad(Resource* resource) {
+ DCHECK(resource->GetType() == ResourceType::kFont ||
+ resource->GetType() == ResourceType::kImage);
return StartLoad(resource, ResourceRequestBody(),
- LoadBlockingPolicy::kDefault);
+ ImageLoadBlockingPolicy::kDefault,
+ RenderBlockingBehavior::kNonBlocking);
}
-bool ResourceFetcher::StartLoad(Resource* resource,
- ResourceRequestBody request_body,
- LoadBlockingPolicy policy) {
+bool ResourceFetcher::StartLoad(
+ Resource* resource,
+ ResourceRequestBody request_body,
+ ImageLoadBlockingPolicy policy,
+ RenderBlockingBehavior render_blocking_behavior) {
DCHECK(resource);
DCHECK(resource->StillNeedsLoad());
ResourceLoader* loader = nullptr;
+ if (archive_ && resource->Url().ProtocolIsInHTTPFamily()) {
+ // MHTML documents should not trigger HTTP requests.
+ //
+ // TODO(lukasza): https://crbug.com/1151438: Remove the ad-hoc DwoC below,
+ // once the bug is fixed and verified.
+ NOTREACHED();
+ base::debug::DumpWithoutCrashing();
+ }
+
{
// Forbids JavaScript/revalidation until start()
// to prevent unintended state transitions.
@@ -1995,7 +1996,7 @@ bool ResourceFetcher::StartLoad(Resource* resource,
ResourceResponse response;
resource_load_observer_->WillSendRequest(
resource->InspectorId(), request, response, resource->GetType(),
- resource->Options().initiator_info);
+ resource->Options().initiator_info, render_blocking_behavior);
}
using QuotaType = decltype(inflight_keepalive_bytes_);
@@ -2021,7 +2022,7 @@ bool ResourceFetcher::StartLoad(Resource* resource,
// is handled by MakePreloadedResourceBlockOnloadIfNeeded().
if (!resource->IsLinkPreload() &&
resource->IsLoadEventBlockingResourceType() &&
- policy != LoadBlockingPolicy::kForceNonBlockingLoad) {
+ policy != ImageLoadBlockingPolicy::kForceNonBlockingLoad) {
loaders_.insert(loader);
} else {
non_blocking_loaders_.insert(loader);
@@ -2126,6 +2127,11 @@ String ResourceFetcher::GetCacheIdentifier(const KURL& url) const {
if (properties_->WebBundlePhysicalUrl().IsValid())
return properties_->WebBundlePhysicalUrl().GetString();
+ // Requests that can be satisfied via `archive_` (i.e. MHTML) or
+ // `subresource_web_bundles_` should not participate in the global caching,
+ // but should use a bundle/mhtml-specific cache.
+ if (archive_)
+ return archive_->GetCacheIdentifier();
for (auto& bundle : subresource_web_bundles_) {
if (bundle->CanHandleRequest(url))
return bundle->GetCacheIdentifier();
@@ -2181,7 +2187,8 @@ void ResourceFetcher::EmulateLoadStartedForInspector(
}
DCHECK_EQ(resource->GetStatus(), ResourceStatus::kCached);
DidLoadResourceFromMemoryCache(resource, params.GetResourceRequest(),
- false /* is_static_data */);
+ false /* is_static_data */,
+ params.GetRenderBlockingBehavior());
}
void ResourceFetcher::PrepareForLeakDetection() {
@@ -2270,14 +2277,6 @@ void ResourceFetcher::RemoveSubresourceWebBundle(
subresource_web_bundles_.erase(&subresource_web_bundle);
}
-void ResourceFetcher::EvictFromBackForwardCache(
- mojom::RendererEvictionReason reason) {
- if (!resource_load_observer_)
- return;
-
- resource_load_observer_->EvictFromBackForwardCache(reason);
-}
-
void ResourceFetcher::Trace(Visitor* visitor) const {
visitor->Trace(context_);
visitor->Trace(properties_);
@@ -2286,7 +2285,9 @@ void ResourceFetcher::Trace(Visitor* visitor) const {
visitor->Trace(console_logger_);
visitor->Trace(loader_factory_);
visitor->Trace(scheduler_);
+ visitor->Trace(back_forward_cache_loader_helper_);
visitor->Trace(archive_);
+ visitor->Trace(resource_timing_report_timer_);
visitor->Trace(loaders_);
visitor->Trace(non_blocking_loaders_);
visitor->Trace(cached_resources_map_);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index 327e6812aba..7bfb1e03b7a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -43,6 +43,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.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/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -52,6 +53,7 @@
namespace blink {
enum class ResourceType : uint8_t;
+class BackForwardCacheLoaderHelper;
class DetachableConsoleLogger;
class DetachableUseCounter;
class DetachableResourceFetcherProperties;
@@ -64,6 +66,7 @@ class ResourceError;
class ResourceLoadObserver;
class ResourceTimingInfo;
class SubresourceWebBundle;
+class WebBackForwardCacheLoaderHelper;
class WebCodeCacheLoader;
struct ResourceFetcherInit;
struct ResourceLoaderOptions;
@@ -99,8 +102,8 @@ class PLATFORM_EXPORT ResourceFetcher
const ResourceRequest&,
const ResourceLoaderOptions&,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner>
- unfreezable_task_runner) = 0;
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper) = 0;
// Create a code cache loader to fetch data from code caches.
virtual std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() = 0;
@@ -174,11 +177,13 @@ class PLATFORM_EXPORT ResourceFetcher
base::OnceCallback<void(int)>);
using DocumentResourceMap = HeapHashMap<String, WeakMember<Resource>>;
+ // Note: This function is defined for devtools. Do not use this function in
+ // non-inspector/non-tent-only contexts.
const DocumentResourceMap& AllResources() const {
return cached_resources_map_;
}
- enum class LoadBlockingPolicy {
+ enum class ImageLoadBlockingPolicy {
kDefault,
kForceNonBlockingLoad,
};
@@ -189,7 +194,10 @@ class PLATFORM_EXPORT ResourceFetcher
// call this method explicitly on cases such as ResourceNeedsLoad() returning
// false.
bool StartLoad(Resource*);
- bool StartLoad(Resource*, ResourceRequestBody, LoadBlockingPolicy);
+ bool StartLoad(Resource*,
+ ResourceRequestBody,
+ ImageLoadBlockingPolicy,
+ RenderBlockingBehavior);
void SetAutoLoadImages(bool);
void SetImagesEnabled(bool);
@@ -305,8 +313,12 @@ class PLATFORM_EXPORT ResourceFetcher
void AddSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);
void RemoveSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);
+ void AttachWebBundleTokenIfNeeded(ResourceRequest&) const;
+ bool ShouldBeLoadedFromWebBundle(const KURL&) const;
- void EvictFromBackForwardCache(mojom::RendererEvictionReason reason);
+ BackForwardCacheLoaderHelper* GetBackForwardCacheLoaderHelper() {
+ return back_forward_cache_loader_helper_;
+ }
private:
friend class ResourceCacheValidationSuppressor;
@@ -341,8 +353,8 @@ class PLATFORM_EXPORT ResourceFetcher
const ResourceFactory&,
WebScopedVirtualTimePauser& virtual_time_pauser);
- Resource* ResourceForStaticData(const FetchParameters&,
- const ResourceFactory&);
+ Resource* CreateResourceForStaticData(const FetchParameters&,
+ const ResourceFactory&);
Resource* ResourceForBlockedRequest(const FetchParameters&,
const ResourceFactory&,
ResourceRequestBlockedReason,
@@ -394,7 +406,8 @@ class PLATFORM_EXPORT ResourceFetcher
void DidLoadResourceFromMemoryCache(Resource*,
const ResourceRequest&,
- bool is_static_data);
+ bool is_static_data,
+ RenderBlockingBehavior);
bool ResourceNeedsLoad(Resource*, const FetchParameters&, RevalidationPolicy);
@@ -406,7 +419,8 @@ class PLATFORM_EXPORT ResourceFetcher
RevalidationPolicy,
const FetchParameters&,
const ResourceFactory&,
- bool is_static_data) const;
+ bool is_static_data,
+ bool same_top_frame_site_resource_cached) const;
void ScheduleStaleRevalidate(Resource* stale_resource);
void RevalidateStaleResource(Resource* stale_resource);
@@ -422,6 +436,7 @@ class PLATFORM_EXPORT ResourceFetcher
const Member<DetachableConsoleLogger> console_logger_;
Member<LoaderFactory> loader_factory_;
const Member<ResourceLoadScheduler> scheduler_;
+ Member<BackForwardCacheLoaderHelper> back_forward_cache_loader_helper_;
DocumentResourceMap cached_resources_map_;
@@ -437,7 +452,7 @@ class PLATFORM_EXPORT ResourceFetcher
HeapVector<Member<Resource>> matched_preloads_;
Member<MHTMLArchive> archive_;
- TaskRunnerTimer<ResourceFetcher> resource_timing_report_timer_;
+ HeapTaskRunnerTimer<ResourceFetcher> resource_timing_report_timer_;
TaskHandle unused_preloads_timer_;
@@ -529,7 +544,8 @@ struct PLATFORM_EXPORT ResourceFetcherInit final {
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
ResourceFetcher::LoaderFactory* loader_factory,
- ContextLifecycleNotifier* context_lifecycle_notifier);
+ ContextLifecycleNotifier* context_lifecycle_notifier,
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper = nullptr);
DetachableResourceFetcherProperties* const properties;
FetchContext* const context;
@@ -546,6 +562,7 @@ struct PLATFORM_EXPORT ResourceFetcherInit final {
ResourceLoadScheduler::ThrottleOptionOverride throttle_option_override =
ResourceLoadScheduler::ThrottleOptionOverride::kNone;
LoadingBehaviorObserver* loading_behavior_observer = nullptr;
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper = nullptr;
DISALLOW_COPY_AND_ASSIGN(ResourceFetcherInit);
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 1bb89327220..ae66f3e7952 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -32,9 +32,11 @@
#include <memory>
#include "base/optional.h"
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
@@ -65,6 +67,7 @@
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
#include "third_party/blink/renderer/platform/loader/testing/test_loader_factory.h"
#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
+#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/scoped_mocked_url.h"
@@ -127,7 +130,8 @@ class ResourceFetcherTest : public testing::Test {
const ResourceRequest& request,
const ResourceResponse& redirect_response,
ResourceType,
- const FetchInitiatorInfo&) override {
+ const FetchInitiatorInfo&,
+ RenderBlockingBehavior) override {
request_ = PartialResourceRequest(request);
}
void DidChangePriority(uint64_t identifier,
@@ -153,7 +157,6 @@ class ResourceFetcherTest : public testing::Test {
const ResourceError&,
int64_t encoded_data_length,
IsInternalRequest is_internal_request) override {}
- void EvictFromBackForwardCache(mojom::RendererEvictionReason) override {}
const base::Optional<PartialResourceRequest>& GetLastRequest() const {
return request_;
}
@@ -175,7 +178,8 @@ class ResourceFetcherTest : public testing::Test {
CreateTaskRunner(),
MakeGarbageCollected<TestLoaderFactory>(
platform_->GetURLLoaderMockFactory()),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
}
ResourceFetcher* CreateFetcher(
@@ -222,12 +226,14 @@ TEST_F(ResourceFetcherTest, StartLoadAfterFrameDetach) {
EXPECT_FALSE(GetMemoryCache()->ResourceForURL(secure_url));
// Start by calling StartLoad() directly, rather than via RequestResource().
- // This shouldn't crash.
+ // This shouldn't crash. Setting the resource type to image, as StartLoad with
+ // a single argument is only called on images or fonts.
fetcher->StartLoad(RawResource::CreateForTest(
- secure_url, SecurityOrigin::CreateUniqueOpaque(), ResourceType::kRaw));
+ secure_url, SecurityOrigin::CreateUniqueOpaque(), ResourceType::kImage));
}
TEST_F(ResourceFetcherTest, UseExistingResource) {
+ blink::HistogramTester histogram_tester;
auto* fetcher = CreateFetcher();
KURL url("http://127.0.0.1:8000/foo.html");
@@ -248,6 +254,253 @@ TEST_F(ResourceFetcherTest, UseExistingResource) {
Resource* new_resource = MockResource::Fetch(fetch_params, fetcher, nullptr);
EXPECT_EQ(resource, new_resource);
+
+ // Test histograms.
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 2);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+
+ // Create a new fetcher and load the same resource.
+ auto* new_fetcher = CreateFetcher();
+ Resource* new_fetcher_resource =
+ MockResource::Fetch(fetch_params, new_fetcher, nullptr);
+ EXPECT_EQ(resource, new_fetcher_resource);
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 2);
+}
+
+TEST_F(ResourceFetcherTest, MemoryCachePerContextUseExistingResource) {
+ blink::HistogramTester histogram_tester;
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kScopeMemoryCachePerContext);
+
+ KURL url("http://127.0.0.1:8000/foo.html");
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+ response.SetHttpHeaderField(http_names::kCacheControl, "max-age=3600");
+ platform_->GetURLLoaderMockFactory()->RegisterURL(
+ url, WrappedResourceResponse(response),
+ test::PlatformTestDataPath(kTestResourceFilename));
+
+ FetchParameters fetch_params =
+ FetchParameters::CreateForTest(ResourceRequest(url));
+
+ auto* fetcher_a = CreateFetcher();
+ Resource* resource_a = MockResource::Fetch(fetch_params, fetcher_a, nullptr);
+ ASSERT_TRUE(resource_a);
+ platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+ EXPECT_TRUE(resource_a->IsLoaded());
+ EXPECT_TRUE(GetMemoryCache()->Contains(resource_a));
+
+ Resource* resource_a1 = MockResource::Fetch(fetch_params, fetcher_a, nullptr);
+ ASSERT_TRUE(resource_a1);
+ EXPECT_EQ(resource_a, resource_a1);
+
+ // Test histograms.
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 2);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+
+ // Create a new fetcher and load the same resource. It should be loaded again.
+ auto* fetcher_b = CreateFetcher();
+ Resource* resource_b = MockResource::Fetch(fetch_params, fetcher_b, nullptr);
+ EXPECT_NE(resource_a1, resource_b);
+ ASSERT_TRUE(resource_b);
+ platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+ EXPECT_TRUE(resource_b->IsLoaded());
+ EXPECT_TRUE(GetMemoryCache()->Contains(resource_b));
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 2);
+
+ // (TODO: crbug.com/1127971) Using the first fetcher now should reuse the same
+ // resource as was earlier loaded by the same fetcher.
+ // EXPECT_EQ(resource_a1, resource_a2);
+ Resource* resource_a2 = MockResource::Fetch(fetch_params, fetcher_a, nullptr);
+ EXPECT_EQ(resource_b, resource_a2);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 2);
+
+ // Using the second fetcher now should reuse the same resource as was earlier
+ // loaded by the same fetcher.
+ Resource* resource_b1 = MockResource::Fetch(fetch_params, fetcher_b, nullptr);
+ EXPECT_EQ(resource_b, resource_b1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 3);
+}
+
+TEST_F(ResourceFetcherTest, MetricsPerTopFrameSite) {
+ blink::HistogramTester histogram_tester;
+
+ KURL url("http://127.0.0.1:8000/foo.html");
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+ response.SetHttpHeaderField(http_names::kCacheControl, "max-age=3600");
+ platform_->GetURLLoaderMockFactory()->RegisterURL(
+ url, WrappedResourceResponse(response),
+ test::PlatformTestDataPath(kTestResourceFilename));
+
+ ResourceRequestHead request_head(url);
+ scoped_refptr<const SecurityOrigin> origin_a =
+ SecurityOrigin::Create(KURL("https://a.test"));
+ request_head.SetTopFrameOrigin(origin_a);
+ request_head.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params =
+ FetchParameters::CreateForTest(ResourceRequest(request_head));
+ auto* fetcher_1 = CreateFetcher();
+ Resource* resource_1 = MockResource::Fetch(fetch_params, fetcher_1, nullptr);
+ ASSERT_TRUE(resource_1);
+ platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+ EXPECT_TRUE(resource_1->IsLoaded());
+ EXPECT_TRUE(GetMemoryCache()->Contains(resource_1));
+
+ auto* fetcher_2 = CreateFetcher();
+ ResourceRequestHead request_head_2(url);
+ scoped_refptr<const SecurityOrigin> origin_b =
+ SecurityOrigin::Create(KURL("https://b.test"));
+ request_head_2.SetTopFrameOrigin(origin_b);
+ request_head_2.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params_2 =
+ FetchParameters::CreateForTest(ResourceRequest(request_head_2));
+ Resource* resource_2 =
+ MockResource::Fetch(fetch_params_2, fetcher_2, nullptr);
+ EXPECT_EQ(resource_1, resource_2);
+
+ // Test histograms.
+ histogram_tester.ExpectTotalCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock", 0);
+
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 2);
+
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+
+ // Now load the same resource with origin_b as top-frame site. The
+ // PerTopFrameSite histogram should be incremented.
+ auto* fetcher_3 = CreateFetcher();
+ ResourceRequestHead request_head_3(url);
+ scoped_refptr<const SecurityOrigin> foo_origin_b =
+ SecurityOrigin::Create(KURL("https://foo.b.test"));
+ request_head_3.SetTopFrameOrigin(foo_origin_b);
+ request_head_3.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params_3 =
+ FetchParameters::CreateForTest(ResourceRequest(request_head_3));
+ Resource* resource_3 =
+ MockResource::Fetch(fetch_params_2, fetcher_3, nullptr);
+ EXPECT_EQ(resource_1, resource_3);
+ histogram_tester.ExpectTotalCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock", 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 2);
+}
+
+TEST_F(ResourceFetcherTest, MetricsPerTopFrameSiteOpaqueOrigins) {
+ blink::HistogramTester histogram_tester;
+
+ KURL url("http://127.0.0.1:8000/foo.html");
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+ response.SetHttpHeaderField(http_names::kCacheControl, "max-age=3600");
+ platform_->GetURLLoaderMockFactory()->RegisterURL(
+ url, WrappedResourceResponse(response),
+ test::PlatformTestDataPath(kTestResourceFilename));
+
+ ResourceRequestHead request_head(url);
+ scoped_refptr<const SecurityOrigin> origin_a =
+ SecurityOrigin::Create(KURL("https://a.test"));
+ scoped_refptr<const SecurityOrigin> opaque_origin1 =
+ SecurityOrigin::CreateUniqueOpaque();
+ request_head.SetTopFrameOrigin(opaque_origin1);
+ request_head.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params =
+ FetchParameters::CreateForTest(ResourceRequest(request_head));
+ auto* fetcher_1 = CreateFetcher();
+ Resource* resource_1 = MockResource::Fetch(fetch_params, fetcher_1, nullptr);
+ ASSERT_TRUE(resource_1);
+ platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+ EXPECT_TRUE(resource_1->IsLoaded());
+ EXPECT_TRUE(GetMemoryCache()->Contains(resource_1));
+
+ // Create a 2nd opaque top-level origin.
+ auto* fetcher_2 = CreateFetcher();
+ ResourceRequestHead request_head_2(url);
+ scoped_refptr<const SecurityOrigin> opaque_origin2 =
+ SecurityOrigin::CreateUniqueOpaque();
+ request_head_2.SetTopFrameOrigin(opaque_origin2);
+ request_head_2.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params_2 =
+ FetchParameters::CreateForTest(ResourceRequest(request_head_2));
+ Resource* resource_2 =
+ MockResource::Fetch(fetch_params_2, fetcher_2, nullptr);
+ EXPECT_EQ(resource_1, resource_2);
+
+ // Test histograms.
+ histogram_tester.ExpectTotalCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock", 0);
+
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 2);
+
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3 /* RevalidationPolicy::kLoad */, 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+
+ // Now load the same resource with opaque_origin1 as top-frame site. The
+ // PerTopFrameSite histogram should be incremented.
+ auto* fetcher_3 = CreateFetcher();
+ ResourceRequestHead request_head_3(url);
+ request_head_3.SetTopFrameOrigin(opaque_origin2);
+ request_head_3.SetRequestorOrigin(origin_a);
+ FetchParameters fetch_params_3 =
+ FetchParameters::CreateForTest(ResourceRequest(request_head_3));
+ Resource* resource_3 =
+ MockResource::Fetch(fetch_params_2, fetcher_3, nullptr);
+ EXPECT_EQ(resource_1, resource_3);
+ histogram_tester.ExpectTotalCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock", 1);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.PerTopFrameSite.Mock",
+ 0 /* RevalidationPolicy::kUse */, 1);
+ histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock",
+ 3);
+ histogram_tester.ExpectBucketCount(
+ "Blink.MemoryCache.RevalidationPolicy.Mock",
+ 0 /* RevalidationPolicy::kUse */, 2);
}
// Verify that the ad bit is copied to WillSendRequest's request when the
@@ -413,7 +666,8 @@ class RequestSameResourceOnComplete
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>(mock_factory_),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
ResourceRequest resource_request2(GetResource()->Url());
resource_request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
FetchParameters fetch_params2 =
@@ -500,7 +754,7 @@ class ServeRequestsOnCompleteClient final
void ResponseReceived(Resource*, const ResourceResponse&) override {
ASSERT_TRUE(false);
}
- void SetSerializedCachedMetadata(Resource*, const uint8_t*, size_t) override {
+ void CachedMetadataReceived(Resource*, mojo_base::BigBuffer) override {
ASSERT_TRUE(false);
}
void DataReceived(Resource*, const char*, size_t) override {
@@ -581,7 +835,8 @@ class ScopedMockRedirectRequester {
properties->MakeDetachable(), context_, task_runner_,
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>(mock_factory_),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
ResourceRequest resource_request(url);
resource_request.SetRequestContext(
mojom::blink::RequestContextType::INTERNAL);
@@ -1166,13 +1421,13 @@ TEST_F(ResourceFetcherTest, DeprioritizeSubframe) {
TEST_F(ResourceFetcherTest, Detach) {
DetachableResourceFetcherProperties& properties =
MakeGarbageCollected<TestResourceFetcherProperties>()->MakeDetachable();
- auto* const fetcher =
- MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties, MakeGarbageCollected<MockFetchContext>(),
- CreateTaskRunner(), CreateTaskRunner(),
- MakeGarbageCollected<TestLoaderFactory>(
- platform_->GetURLLoaderMockFactory()),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* const fetcher = MakeGarbageCollected<ResourceFetcher>(
+ ResourceFetcherInit(properties, MakeGarbageCollected<MockFetchContext>(),
+ CreateTaskRunner(), CreateTaskRunner(),
+ MakeGarbageCollected<TestLoaderFactory>(
+ platform_->GetURLLoaderMockFactory()),
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
EXPECT_EQ(&properties, &fetcher->GetProperties());
EXPECT_FALSE(properties.IsDetached());
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h
index be55d02976a..3e87f24c44d 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h
@@ -8,7 +8,7 @@
#include <inttypes.h>
#include "base/containers/span.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink-forward.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
@@ -52,7 +52,8 @@ class PLATFORM_EXPORT ResourceLoadObserver
const ResourceRequest&,
const ResourceResponse& redirect_response,
ResourceType,
- const FetchInitiatorInfo&) = 0;
+ const FetchInitiatorInfo&,
+ RenderBlockingBehavior) = 0;
// Called when the priority of the request changes.
virtual void DidChangePriority(uint64_t identifier,
@@ -89,7 +90,7 @@ class PLATFORM_EXPORT ResourceLoadObserver
int64_t decoded_body_length,
bool should_report_corb_blocking) = 0;
- using IsInternalRequest = util::StrongAlias<class IsInternalRequestTag, bool>;
+ using IsInternalRequest = base::StrongAlias<class IsInternalRequestTag, bool>;
// Called when a request fails.
virtual void DidFailLoading(const KURL&,
uint64_t identifier,
@@ -97,11 +98,6 @@ class PLATFORM_EXPORT ResourceLoadObserver
int64_t encoded_data_length,
IsInternalRequest) = 0;
- // Evict the page from BackForwardCache. Should be called when handling an
- // event which can't proceed if the page is in BackForwardCache and can't be
- // easily deferred to handle later, for example network redirect handling.
- virtual void EvictFromBackForwardCache(mojom::RendererEvictionReason) {}
-
virtual void Trace(Visitor*) const {}
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
index e285beac7c2..94af06e1f6e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_load_timing.cc
@@ -83,6 +83,7 @@ network::mojom::blink::LoadTimingInfoPtr ResourceLoadTiming::ToMojo() const {
dns_start_, dns_end_, connect_start_, connect_end_, ssl_start_,
ssl_end_),
send_start_, send_end_, receive_headers_start_, receive_headers_end_,
+ /*receive_non_informational_headers_start=*/base::TimeTicks::Now(),
/*first_early_hints_time=*/base::TimeTicks::Now(), push_start_,
push_end_, worker_start_, worker_ready_, worker_fetch_start_,
worker_respond_with_settled_);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 984f2281a2b..5cf198700d2 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -55,12 +55,14 @@
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
@@ -91,20 +93,15 @@ namespace blink {
namespace {
-enum RequestOutcome { kSuccess, kFail };
+enum class RequestOutcome { kSuccess, kFail };
-std::unique_ptr<TracedValue> EndResourceLoadData(RequestOutcome outcome) {
- auto value = std::make_unique<TracedValue>();
+const char* RequestOutcomeToString(RequestOutcome outcome) {
switch (outcome) {
case RequestOutcome::kSuccess:
- value->SetString("outcome", "Success");
- break;
+ return "Success";
case RequestOutcome::kFail:
- value->SetString("outcome", "Fail");
- break;
+ return "Fail";
}
-
- return value;
}
bool IsThrottlableRequestContext(mojom::blink::RequestContextType context) {
@@ -190,6 +187,28 @@ SchedulingPolicy::Feature GetFeatureFromRequestContextType(
}
}
+void LogCnameAliasMetrics(const CnameAliasMetricInfo& info) {
+ UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.CnameAlias.Renderer.HadAliases",
+ info.has_aliases);
+
+ if (info.has_aliases) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "SubresourceFilter.CnameAlias.Renderer.WasAdTaggedBasedOnAlias",
+ info.was_ad_tagged_based_on_alias);
+ UMA_HISTOGRAM_BOOLEAN(
+ "SubresourceFilter.CnameAlias.Renderer.WasBlockedBasedOnAlias",
+ info.was_blocked_based_on_alias);
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.CnameAlias.Renderer.ListLength", info.list_length);
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.CnameAlias.Renderer.InvalidCount",
+ info.invalid_count);
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.CnameAlias.Renderer.RedundantCount",
+ info.redundant_count);
+ }
+}
+
} // namespace
// CodeCacheRequest handles the requests to fetch data from code cache.
@@ -419,11 +438,11 @@ ResourceLoader::ResourceLoader(ResourceFetcher* fetcher,
// Only when this feature is turned on and the loading tasks keep being
// processed and the data is queued up on the renderer, a page can stay in
// BackForwardCache with network requests.
- if (!base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)) {
+ if (!IsInflightNetworkRequestBackForwardCacheSupportEnabled()) {
feature_handle_for_scheduler_ =
frame_or_worker_scheduler->RegisterFeature(
GetFeatureFromRequestContextType(request_context),
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
}
}
@@ -439,6 +458,7 @@ void ResourceLoader::Trace(Visitor* visitor) const {
visitor->Trace(resource_);
visitor->Trace(response_body_loader_);
visitor->Trace(data_pipe_completion_notifier_);
+ visitor->Trace(cancel_timer_);
ResourceLoadSchedulerClient::Trace(visitor);
}
@@ -525,8 +545,8 @@ void ResourceLoader::DidStartLoadingResponseBodyInternal(
DCHECK(!response_body_loader_);
ResponseBodyLoaderClient& response_body_loader_client = *this;
response_body_loader_ = MakeGarbageCollected<ResponseBodyLoader>(
- bytes_consumer, response_body_loader_client,
- task_runner_for_body_loader_);
+ bytes_consumer, response_body_loader_client, task_runner_for_body_loader_,
+ fetcher_->GetBackForwardCacheLoaderHelper());
resource_->ResponseBodyReceived(*response_body_loader_,
task_runner_for_body_loader_);
if (response_body_loader_->IsDrained()) {
@@ -539,6 +559,8 @@ void ResourceLoader::DidStartLoadingResponseBodyInternal(
}
void ResourceLoader::Run() {
+ // TODO(crbug.com/1169032): Manage cookies' capability control here for the
+ // Prerender2.
StartWith(resource_->GetResourceRequest());
}
@@ -787,8 +809,9 @@ bool ResourceLoader::WillFollowRedirect(
reporting_disposition,
new_request->GetRedirectInfo());
- if (Context().CalculateIfAdSubresource(*new_request, resource_type,
- options.initiator_info))
+ if (Context().CalculateIfAdSubresource(
+ *new_request, base::nullopt /* alias_url */, resource_type,
+ options.initiator_info))
new_request->SetIsAdResource();
if (blocked_reason) {
@@ -823,7 +846,8 @@ bool ResourceLoader::WillFollowRedirect(
if (auto* observer = fetcher_->GetResourceLoadObserver()) {
observer->WillSendRequest(resource_->InspectorId(), *new_request,
redirect_response, resource_->GetType(),
- options.initiator_info);
+ options.initiator_info,
+ initial_request.GetRenderBlockingBehavior());
}
// First-party cookie logic moved from DocumentLoader in Blink to
@@ -858,7 +882,16 @@ void ResourceLoader::DidReceiveCachedMetadata(mojo_base::BigBuffer data) {
}
blink::mojom::CodeCacheType ResourceLoader::GetCodeCacheType() const {
- return Resource::ResourceTypeToCodeCacheType(resource_->GetType());
+ const auto& request = resource_->GetResourceRequest();
+ if (request.GetRequestDestination() ==
+ network::mojom::RequestDestination::kEmpty) {
+ // For requests initiated by the fetch function, we use code cache for
+ // WASM compiled code.
+ return mojom::blink::CodeCacheType::kWebAssembly;
+ } else {
+ // Otherwise, we use code cache for scripting.
+ return mojom::blink::CodeCacheType::kJavascript;
+ }
}
void ResourceLoader::SendCachedCodeToResource(mojo_base::BigBuffer data) {
@@ -949,6 +982,15 @@ void ResourceLoader::DidReceiveResponseInternal(
return;
}
+ // Redirect information for possible post-request checks below.
+ const base::Optional<ResourceRequest::RedirectInfo>& previous_redirect_info =
+ request.GetRedirectInfo();
+ const KURL& original_url = previous_redirect_info
+ ? previous_redirect_info->original_url
+ : request.Url();
+ const ResourceRequest::RedirectInfo redirect_info(original_url,
+ request.Url());
+
if (response.WasFetchedViaServiceWorker()) {
// Run post-request CSP checks. This is the "Should response to request be
// blocked by Content Security Policy?" algorithm in the CSP specification:
@@ -968,16 +1010,10 @@ void ResourceLoader::DidReceiveResponseInternal(
// checks as a first-class concept instead of just reusing the functions for
// pre-request checks, and consider running the checks regardless of service
// worker interception.
- const KURL& response_url = response.ResponseUrl();
- const base::Optional<ResourceRequest::RedirectInfo>&
- previous_redirect_info = request.GetRedirectInfo();
- const KURL& original_url = previous_redirect_info
- ? previous_redirect_info->original_url
- : request.Url();
- const ResourceRequest::RedirectInfo redirect_info(original_url,
- request.Url());
+ //
// CanRequest() below only checks enforced policies: check report-only
// here to ensure violations are sent.
+ const KURL& response_url = response.ResponseUrl();
Context().CheckCSPForRequest(
request_context, request_destination, response_url, options,
ReportingDisposition::kReport, original_url,
@@ -994,6 +1030,18 @@ void ResourceLoader::DidReceiveResponseInternal(
}
}
+ if (base::FeatureList::IsEnabled(
+ features::kSendCnameAliasesToSubresourceFilterFromRenderer)) {
+ CnameAliasMetricInfo info;
+ bool should_block = ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck(
+ response.DnsAliases(), request.Url(), original_url, resource_type,
+ initial_request, options, redirect_info, &info);
+ LogCnameAliasMetrics(info);
+
+ if (should_block)
+ return;
+ }
+
// A response should not serve partial content if it was not requested via a
// Range header: https://fetch.spec.whatwg.org/#main-fetch
if (response.GetType() == network::mojom::FetchResponseType::kOpaque &&
@@ -1029,12 +1077,12 @@ void ResourceLoader::DidReceiveResponseInternal(
if (response.CacheControlContainsNoCache()) {
frame_or_worker_scheduler->RegisterStickyFeature(
SchedulingPolicy::Feature::kSubresourceHasCacheControlNoCache,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
if (response.CacheControlContainsNoStore()) {
frame_or_worker_scheduler->RegisterStickyFeature(
SchedulingPolicy::Feature::kSubresourceHasCacheControlNoStore,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
}
}
@@ -1098,7 +1146,7 @@ void ResourceLoader::DidFinishLoadingFirstPartInMultipart() {
TRACE_DISABLED_BY_DEFAULT("network"), "ResourceLoad",
TRACE_ID_WITH_SCOPE("BlinkResourceID",
TRACE_ID_LOCAL(resource_->InspectorId())),
- "endData", EndResourceLoadData(RequestOutcome::kSuccess));
+ "outcome", RequestOutcomeToString(RequestOutcome::kSuccess));
fetcher_->HandleLoaderFinish(resource_.Get(), base::TimeTicks(),
ResourceFetcher::kDidFinishFirstPartInMultipart,
@@ -1142,7 +1190,7 @@ void ResourceLoader::DidFinishLoading(base::TimeTicks response_end_time,
TRACE_DISABLED_BY_DEFAULT("network"), "ResourceLoad",
TRACE_ID_WITH_SCOPE("BlinkResourceID",
TRACE_ID_LOCAL(resource_->InspectorId())),
- "endData", EndResourceLoadData(RequestOutcome::kSuccess));
+ "outcome", RequestOutcomeToString(RequestOutcome::kSuccess));
fetcher_->HandleLoaderFinish(
resource_.Get(), response_end_time, ResourceFetcher::kDidFinishLoading,
@@ -1209,7 +1257,7 @@ void ResourceLoader::HandleError(const ResourceError& error) {
TRACE_DISABLED_BY_DEFAULT("network"), "ResourceLoad",
TRACE_ID_WITH_SCOPE("BlinkResourceID",
TRACE_ID_LOCAL(resource_->InspectorId())),
- "endData", EndResourceLoadData(RequestOutcome::kFail));
+ "outcome", RequestOutcomeToString(RequestOutcome::kFail));
// Set Now() as the response time, in case a more accurate one wasn't set in
// DidFinishLoading or DidFail. This is important for error cases that don't
@@ -1222,11 +1270,6 @@ void ResourceLoader::HandleError(const ResourceError& error) {
inflight_keepalive_bytes_);
}
-void ResourceLoader::EvictFromBackForwardCache(
- mojom::RendererEvictionReason reason) {
- fetcher_->EvictFromBackForwardCache(reason);
-}
-
void ResourceLoader::RequestSynchronously(const ResourceRequestHead& request) {
DCHECK(loader_);
DCHECK_EQ(request.Priority(), ResourceLoadPriority::kHighest);
@@ -1507,4 +1550,73 @@ void ResourceLoader::HandleDataUrl() {
false /* should_report_corb_blocking */);
}
+bool ResourceLoader::ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck(
+ const Vector<String>& dns_aliases,
+ const KURL& request_url,
+ const KURL& original_url,
+ ResourceType resource_type,
+ const ResourceRequestHead& initial_request,
+ const ResourceLoaderOptions& options,
+ const ResourceRequest::RedirectInfo redirect_info,
+ CnameAliasMetricInfo* out_metric_info) {
+ DCHECK(out_metric_info);
+
+ // Look for CNAME aliases, and if any are found, run SubresourceFilter
+ // checks on them to perform resource-blocking and ad-tagging based on the
+ // aliases: if any one of the aliases is on the denylist, then the
+ // request will be deemed on the denylist and treated accordingly (blocked
+ // and/or tagged).
+ out_metric_info->has_aliases = !dns_aliases.IsEmpty();
+ out_metric_info->list_length = dns_aliases.size();
+
+ // If there are no aliases, we have no reason to block based on them.
+ if (!out_metric_info->has_aliases)
+ return false;
+
+ // CNAME aliases were found, and so the SubresourceFilter must be
+ // consulted for each one.
+ // Create a copy of the request URL. We will swap out the host below.
+ KURL alias_url = request_url;
+
+ for (const String& alias : dns_aliases) {
+ alias_url.SetHost(alias);
+
+ // The SubresourceFilter only performs nontrivial matches for
+ // valid URLs. Skip sending this alias if it's invalid.
+ if (!alias_url.IsValid()) {
+ out_metric_info->invalid_count++;
+ continue;
+ }
+
+ // Do not perform a SubresourceFilter check on an `alias_url` that matches
+ // the requested URL (or, inclusively, the original URL in the case of
+ // redirects).
+ if (alias_url == original_url || alias_url == request_url) {
+ out_metric_info->redundant_count++;
+ continue;
+ }
+
+ base::Optional<ResourceRequestBlockedReason> blocked_reason =
+ Context().CanRequestBasedOnSubresourceFilterOnly(
+ resource_type, ResourceRequest(initial_request), alias_url, options,
+ ReportingDisposition::kReport, redirect_info);
+ if (blocked_reason) {
+ HandleError(ResourceError::CancelledDueToAccessCheckError(
+ alias_url, blocked_reason.value()));
+ out_metric_info->was_blocked_based_on_alias = true;
+ return true;
+ }
+
+ if (!resource_->GetResourceRequest().IsAdResource() &&
+ Context().CalculateIfAdSubresource(resource_->GetResourceRequest(),
+ alias_url, resource_type,
+ options.initiator_info)) {
+ resource_->SetIsAdResource();
+ out_metric_info->was_ad_tagged_based_on_alias = true;
+ }
+ }
+
+ return false;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index d53b0facf20..4498155f5be 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -31,6 +31,7 @@
#include <memory>
#include "base/containers/span.h"
+#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/base/big_buffer.h"
@@ -58,6 +59,17 @@ class ResourceError;
class ResourceFetcher;
class ResponseBodyLoader;
+// Struct for keeping variables used in recording CNAME alias metrics bundled
+// together.
+struct CnameAliasMetricInfo {
+ bool has_aliases = false;
+ bool was_ad_tagged_based_on_alias = false;
+ bool was_blocked_based_on_alias = false;
+ int list_length = 0;
+ int invalid_count = 0;
+ int redundant_count = 0;
+};
+
// A ResourceLoader is created for each Resource by the ResourceFetcher when it
// needs to load the specified resource. A ResourceLoader creates a
// WebURLLoader and loads the resource using it. Any per-load logic should be
@@ -140,7 +152,6 @@ class PLATFORM_EXPORT ResourceLoader final
int64_t encoded_data_length,
int64_t encoded_body_length,
int64_t decoded_body_length) override;
- void EvictFromBackForwardCache(mojom::RendererEvictionReason) override;
blink::mojom::CodeCacheType GetCodeCacheType() const;
void SendCachedCodeToResource(mojo_base::BigBuffer data);
@@ -205,6 +216,19 @@ class PLATFORM_EXPORT ResourceLoader final
// Processes Data URL in ResourceLoader instead of using |loader_|.
void HandleDataUrl();
+ // If enabled, performs SubresourceFilter checks for any DNS aliases found for
+ // the requested URL, which may result in ad-tagging the ResourceRequest.
+ // Returns true if the request should be blocked based on these checks.
+ bool ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck(
+ const Vector<String>& dns_aliases,
+ const KURL& request_url,
+ const KURL& original_url,
+ ResourceType resource_type,
+ const ResourceRequestHead& initial_request,
+ const ResourceLoaderOptions& options,
+ const ResourceRequest::RedirectInfo redirect_info,
+ CnameAliasMetricInfo* out_metric_info);
+
std::unique_ptr<WebURLLoader> loader_;
ResourceLoadScheduler::ClientId scheduler_client_id_;
Member<ResourceFetcher> fetcher_;
@@ -247,7 +271,7 @@ class PLATFORM_EXPORT ResourceLoader final
// HandleDataURL().
bool defers_handling_data_url_ = false;
- TaskRunnerTimer<ResourceLoader> cancel_timer_;
+ HeapTaskRunnerTimer<ResourceLoader> cancel_timer_;
FrameScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
index b3755010517..a4f285a969d 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
@@ -118,7 +118,8 @@ class DeferTestLoaderFactory final : public ResourceFetcher::LoaderFactory {
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
return std::make_unique<TestWebURLLoader>(defers_flag_);
}
@@ -159,7 +160,8 @@ class ResourceLoaderDefersLoadingTest : public testing::Test {
base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<DeferTestLoaderFactory>(
&web_url_loader_defers_, process_code_cache_request_callback_),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
}
void SetCodeCacheProcessFunction(ProcessCodeCacheRequestCallback callback) {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
index e404cafa3ba..4b6952bad01 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
@@ -32,7 +32,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_LOADER_OPTIONS_H_
#include "base/memory/scoped_refptr.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink-forward.h"
@@ -70,7 +70,7 @@ enum CacheAwareLoadingEnabled : uint8_t {
// When true, a response is blocked unless it has
// cross-origin-embedder-policy: require-corp.
using RejectCoepUnsafeNone =
- util::StrongAlias<class RejectCoepUnsafeNoneTag, bool>;
+ base::StrongAlias<class RejectCoepUnsafeNoneTag, bool>;
// This class is thread-bound. Do not copy/pass an instance across threads.
struct PLATFORM_EXPORT ResourceLoaderOptions {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
index 615e434eff9..5458967f87e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
@@ -7,11 +7,15 @@
#include <string>
#include <utility>
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "mojo/public/c/system/data_pipe.h"
#include "services/network/public/mojom/fetch_api.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/public/platform/web_url_request_extra_data.h"
@@ -29,6 +33,19 @@
namespace blink {
+const char kCnameAliasHadAliasesHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.HadAliases";
+const char kCnameAliasIsInvalidCountHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.InvalidCount";
+const char kCnameAliasIsRedundantCountHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.RedundantCount";
+const char kCnameAliasListLengthHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.ListLength";
+const char kCnameAliasWasAdTaggedHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.WasAdTaggedBasedOnAlias";
+const char kCnameAliasWasBlockedHistogram[] =
+ "SubresourceFilter.CnameAlias.Renderer.WasBlockedBasedOnAlias";
+
class ResourceLoaderTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(ResourceLoaderTest);
@@ -64,7 +81,8 @@ class ResourceLoaderTest : public testing::Test {
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
return std::make_unique<NoopWebURLLoader>(
std::move(freezable_task_runner));
@@ -78,6 +96,16 @@ class ResourceLoaderTest : public testing::Test {
return base::MakeRefCounted<scheduler::FakeTaskRunner>();
}
+ ResourceFetcher* MakeResourceFetcher(
+ TestResourceFetcherProperties* properties,
+ FetchContext* context) {
+ return MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
+ properties->MakeDetachable(), context, CreateTaskRunner(),
+ CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
+ MakeGarbageCollected<MockContextLifecycleNotifier>(),
+ nullptr /* back_forward_cache_loader_helper */));
+ }
+
private:
class NoopWebURLLoader final : public WebURLLoader {
public:
@@ -141,10 +169,7 @@ std::ostream& operator<<(std::ostream& o, const ResourceLoaderTest::From& f) {
TEST_F(ResourceLoaderTest, LoadResponseBody) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
KURL url("https://www.example.com/");
ResourceRequest request(url);
@@ -165,7 +190,7 @@ TEST_F(ResourceLoaderTest, LoadResponseBody) {
options.element_num_bytes = 1;
options.capacity_num_bytes = 3;
- MojoResult result = CreateDataPipe(&options, &producer, &consumer);
+ MojoResult result = CreateDataPipe(&options, producer, consumer);
ASSERT_EQ(result, MOJO_RESULT_OK);
loader->DidReceiveResponse(WrappedResourceResponse(response));
@@ -206,10 +231,7 @@ TEST_F(ResourceLoaderTest, LoadResponseBody) {
TEST_F(ResourceLoaderTest, LoadDataURL_AsyncAndNonStream) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
// Fetch a data url.
KURL url("data:text/plain,Hello%20World!");
@@ -260,10 +282,7 @@ class TestRawResourceClient final
TEST_F(ResourceLoaderTest, LoadDataURL_AsyncAndStream) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
scheduler::FakeTaskRunner* task_runner =
static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get());
@@ -300,10 +319,7 @@ TEST_F(ResourceLoaderTest, LoadDataURL_AsyncAndStream) {
TEST_F(ResourceLoaderTest, LoadDataURL_AsyncEmptyData) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
// Fetch an empty data url.
KURL url("data:text/html,");
@@ -324,10 +340,7 @@ TEST_F(ResourceLoaderTest, LoadDataURL_AsyncEmptyData) {
TEST_F(ResourceLoaderTest, LoadDataURL_Sync) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
// Fetch a data url synchronously.
KURL url("data:text/plain,Hello%20World!");
@@ -350,10 +363,7 @@ TEST_F(ResourceLoaderTest, LoadDataURL_Sync) {
TEST_F(ResourceLoaderTest, LoadDataURL_SyncEmptyData) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
// Fetch an empty data url synchronously.
KURL url("data:text/html,");
@@ -372,10 +382,7 @@ TEST_F(ResourceLoaderTest, LoadDataURL_SyncEmptyData) {
TEST_F(ResourceLoaderTest, LoadDataURL_DefersAsyncAndNonStream) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
scheduler::FakeTaskRunner* task_runner =
static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get());
@@ -419,10 +426,7 @@ TEST_F(ResourceLoaderTest, LoadDataURL_DefersAsyncAndNonStream) {
TEST_F(ResourceLoaderTest, LoadDataURL_DefersAsyncAndStream) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
scheduler::FakeTaskRunner* task_runner =
static_cast<scheduler::FakeTaskRunner*>(fetcher->GetTaskRunner().get());
@@ -493,10 +497,7 @@ class ResourceLoaderIsolatedCodeCacheTest : public ResourceLoaderTest {
auto* properties =
MakeGarbageCollected<TestResourceFetcherProperties>(origin);
FetchContext* context = MakeGarbageCollected<MockFetchContext>();
- auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
- properties->MakeDetachable(), context, CreateTaskRunner(),
- CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(),
- MakeGarbageCollected<MockContextLifecycleNotifier>()));
+ auto* fetcher = MakeResourceFetcher(properties, context);
ResourceRequest request;
request.SetUrl(foo_url_);
request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
@@ -554,4 +555,286 @@ TEST_F(ResourceLoaderIsolatedCodeCacheTest, CacheResponseFromServiceWorker) {
EXPECT_EQ(false, LoadAndCheckIsolatedCodeCache(response));
}
+class ResourceLoaderSubresourceFilterCnameAliasTest
+ : public ResourceLoaderTest {
+ public:
+ ResourceLoaderSubresourceFilterCnameAliasTest() = default;
+ ~ResourceLoaderSubresourceFilterCnameAliasTest() override = default;
+
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(
+ features::kSendCnameAliasesToSubresourceFilterFromRenderer);
+ ResourceLoaderTest::SetUp();
+ }
+
+ base::HistogramTester* histogram_tester() { return &histogram_tester_; }
+
+ void SetMockSubresourceFilterBlockLists(Vector<String> blocked_urls,
+ Vector<String> tagged_urls) {
+ blocked_urls_ = blocked_urls;
+ tagged_urls_ = tagged_urls;
+ }
+
+ Resource* CreateResource(ResourceRequest request) {
+ FetchParameters params = FetchParameters::CreateForTest(std::move(request));
+ auto* fetcher = MakeResourceFetcherWithMockSubresourceFilter();
+ return RawResource::Fetch(params, fetcher, nullptr);
+ }
+
+ void GiveResponseToLoader(ResourceResponse response, ResourceLoader* loader) {
+ CreateMojoDataPipe();
+ loader->DidReceiveResponse(WrappedResourceResponse(response));
+ }
+
+ protected:
+ FetchContext* MakeFetchContextWithMockSubresourceFilter(
+ Vector<String> blocked_urls,
+ Vector<String> tagged_urls) {
+ auto* context = MakeGarbageCollected<MockFetchContext>();
+ context->set_blocked_urls(blocked_urls);
+ context->set_tagged_urls(tagged_urls);
+ return context;
+ }
+
+ ResourceFetcher* MakeResourceFetcherWithMockSubresourceFilter() {
+ auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
+ FetchContext* context =
+ MakeFetchContextWithMockSubresourceFilter(blocked_urls_, tagged_urls_);
+ return MakeResourceFetcher(properties, context);
+ }
+
+ void CreateMojoDataPipe() {
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = 3;
+
+ MojoResult result = CreateDataPipe(&options, producer, consumer);
+ ASSERT_EQ(result, MOJO_RESULT_OK);
+ }
+
+ void ExpectHistogramsMatching(CnameAliasMetricInfo info) {
+ histogram_tester()->ExpectUniqueSample(kCnameAliasHadAliasesHistogram,
+ info.has_aliases, 1);
+
+ if (info.has_aliases) {
+ histogram_tester()->ExpectUniqueSample(kCnameAliasWasAdTaggedHistogram,
+ info.was_ad_tagged_based_on_alias,
+ 1);
+ histogram_tester()->ExpectUniqueSample(
+ kCnameAliasWasBlockedHistogram, info.was_blocked_based_on_alias, 1);
+ histogram_tester()->ExpectUniqueSample(kCnameAliasListLengthHistogram,
+ info.list_length, 1);
+ histogram_tester()->ExpectUniqueSample(kCnameAliasIsInvalidCountHistogram,
+ info.invalid_count, 1);
+ histogram_tester()->ExpectUniqueSample(
+ kCnameAliasIsRedundantCountHistogram, info.redundant_count, 1);
+ }
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ base::HistogramTester histogram_tester_;
+ Vector<String> blocked_urls_;
+ Vector<String> tagged_urls_;
+};
+
+TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest,
+ DnsAliasesCheckedBySubresourceFilterDisallowed_TaggedAndBlocked) {
+ // Set the blocklists: the first for blocking, the second for ad-tagging.
+ Vector<String> blocked_urls = {"https://bad-ad.com/some_path.html"};
+ Vector<String> tagged_urls = {"https://ad.com/some_path.html"};
+ SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls);
+
+ // Create the request.
+ KURL url("https://www.example.com/some_path.html");
+ ResourceRequest request(url);
+ request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
+
+ // Create the resource and loader.
+ Resource* resource = CreateResource(std::move(request));
+ ResourceLoader* loader = resource->Loader();
+
+ // Create the response.
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ // Set the CNAME aliases.
+ Vector<String> aliases({"ad.com", "bad-ad.com", "alias3.com"});
+ response.SetDnsAliases(aliases);
+
+ // Give the response to the loader.
+ GiveResponseToLoader(response, loader);
+
+ // Test the histograms to verify that the CNAME aliases were detected.
+ // Expect that the resource was tagged as a ad, due to first alias.
+ // Expect that the resource was blocked, due to second alias.
+ CnameAliasMetricInfo info = {.has_aliases = true,
+ .was_ad_tagged_based_on_alias = true,
+ .was_blocked_based_on_alias = true,
+ .list_length = 3,
+ .invalid_count = 0,
+ .redundant_count = 0};
+
+ ExpectHistogramsMatching(info);
+}
+
+TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest,
+ DnsAliasesCheckedBySubresourceFilterDisallowed_BlockedOnly) {
+ // Set the blocklists: the first for blocking, the second for ad-tagging.
+ Vector<String> blocked_urls = {"https://bad-ad.com/some_path.html"};
+ Vector<String> tagged_urls = {};
+ SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls);
+
+ // Create the request.
+ KURL url("https://www.example.com/some_path.html");
+ ResourceRequest request(url);
+ request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
+
+ // Create the resource and loader.
+ Resource* resource = CreateResource(std::move(request));
+ ResourceLoader* loader = resource->Loader();
+
+ // Create the response.
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ // Set the CNAME aliases.
+ Vector<String> aliases({"ad.com", "bad-ad.com", "alias3.com"});
+ response.SetDnsAliases(aliases);
+
+ // Give the response to the loader.
+ GiveResponseToLoader(response, loader);
+
+ // Test the histograms to verify that the CNAME aliases were detected.
+ // Expect that the resource was blocked, due to second alias.
+ CnameAliasMetricInfo info = {.has_aliases = true,
+ .was_ad_tagged_based_on_alias = false,
+ .was_blocked_based_on_alias = true,
+ .list_length = 3,
+ .invalid_count = 0,
+ .redundant_count = 0};
+
+ ExpectHistogramsMatching(info);
+}
+
+TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest,
+ DnsAliasesCheckedBySubresourceFilterDisallowed_TaggedOnly) {
+ // Set the blocklists: the first for blocking, the second for ad-tagging.
+ Vector<String> blocked_urls = {};
+ Vector<String> tagged_urls = {"https://bad-ad.com/some_path.html"};
+ SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls);
+
+ // Create the request.
+ KURL url("https://www.example.com/some_path.html");
+ ResourceRequest request(url);
+ request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
+
+ // Create the resource and loader.
+ Resource* resource = CreateResource(std::move(request));
+ ResourceLoader* loader = resource->Loader();
+
+ // Create the response.
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ // Set the CNAME aliases.
+ Vector<String> aliases({"ad.com", "", "alias3.com", "bad-ad.com"});
+ response.SetDnsAliases(aliases);
+
+ // Give the response to the loader.
+ GiveResponseToLoader(response, loader);
+
+ // Test the histograms to verify that the CNAME aliases were detected.
+ // Expect that the resource was tagged, due to fourth alias.
+ // Expect that the invalid empty alias is counted as such.
+ CnameAliasMetricInfo info = {.has_aliases = true,
+ .was_ad_tagged_based_on_alias = true,
+ .was_blocked_based_on_alias = false,
+ .list_length = 4,
+ .invalid_count = 1,
+ .redundant_count = 0};
+
+ ExpectHistogramsMatching(info);
+}
+
+TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest,
+ DnsAliasesCheckedBySubresourceFilterAllowed_NotBlockedOrTagged) {
+ // Set the blocklists: the first for blocking, the second for ad-tagging.
+ Vector<String> blocked_urls = {};
+ Vector<String> tagged_urls = {};
+ SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls);
+
+ // Create the request.
+ KURL url("https://www.example.com/some_path.html");
+ ResourceRequest request(url);
+ request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
+
+ // Create the resource and loader.
+ Resource* resource = CreateResource(std::move(request));
+ ResourceLoader* loader = resource->Loader();
+
+ // Create the response.
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ // Set the CNAME aliases.
+ Vector<String> aliases(
+ {"non-ad.com", "?", "alias3.com", "not-an-ad.com", "www.example.com"});
+ response.SetDnsAliases(aliases);
+
+ // Give the response to the loader.
+ GiveResponseToLoader(response, loader);
+
+ // Test the histograms to verify that the CNAME aliases were detected.
+ // Expect that the resource was neither tagged nor blocked.
+ // Expect that the invalid alias is counted as such.
+ // Expect that the redundant (i.e. matching the request URL) fifth alias to be
+ // counted as such.
+ CnameAliasMetricInfo info = {.has_aliases = true,
+ .was_ad_tagged_based_on_alias = false,
+ .was_blocked_based_on_alias = false,
+ .list_length = 5,
+ .invalid_count = 1,
+ .redundant_count = 1};
+
+ ExpectHistogramsMatching(info);
+}
+
+TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest,
+ DnsAliasesCheckedBySubresourceFilterNoAliases_NoneDetected) {
+ // Set the blocklists: the first for blocking, the second for ad-tagging.
+ Vector<String> blocked_urls = {};
+ Vector<String> tagged_urls = {};
+ SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls);
+
+ // Create the request.
+ KURL url("https://www.example.com/some_path.html");
+ ResourceRequest request(url);
+ request.SetRequestContext(mojom::blink::RequestContextType::FETCH);
+
+ // Create the resource and loader.
+ Resource* resource = CreateResource(std::move(request));
+ ResourceLoader* loader = resource->Loader();
+
+ // Create the response.
+ ResourceResponse response(url);
+ response.SetHttpStatusCode(200);
+
+ // Set the CNAME aliases.
+ Vector<String> aliases;
+ response.SetDnsAliases(aliases);
+
+ // Give the response to the loader.
+ GiveResponseToLoader(response, loader);
+
+ // Test the histogram to verify that no aliases were detected.
+ CnameAliasMetricInfo info = {.has_aliases = false};
+
+ ExpectHistogramsMatching(info);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h
index 62435966a4b..1be57a1ab0f 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h
@@ -9,7 +9,7 @@
#if DCHECK_IS_ON()
// We can see logs with |--v=N| or |--vmodule=ResourceLoadingLog=N| where N is a
-// verbose level.
+// verbose level, as well as the |--enable-logging=stderr| CLI argument.
#define RESOURCE_LOADING_DVLOG(verbose_level) \
LAZY_STREAM( \
VLOG_STREAM(verbose_level), \
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index 792cbebbfd1..7a460830b6b 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -30,6 +30,7 @@
#include "base/unguessable_token.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
@@ -40,6 +41,42 @@
namespace blink {
+ResourceRequestHead::WebBundleTokenParams&
+ResourceRequestHead::WebBundleTokenParams::operator=(
+ const WebBundleTokenParams& other) {
+ bundle_url = other.bundle_url;
+ token = other.token;
+ handle = other.CloneHandle();
+ return *this;
+}
+
+ResourceRequestHead::WebBundleTokenParams::WebBundleTokenParams(
+ const WebBundleTokenParams& other) {
+ *this = other;
+}
+
+ResourceRequestHead::WebBundleTokenParams::WebBundleTokenParams(
+ const KURL& bundle_url,
+ const base::UnguessableToken& web_bundle_token,
+ mojo::PendingRemote<network::mojom::WebBundleHandle> web_bundle_handle)
+ : bundle_url(bundle_url),
+ token(web_bundle_token),
+ handle(std::move(web_bundle_handle)) {}
+
+mojo::PendingRemote<network::mojom::WebBundleHandle>
+ResourceRequestHead::WebBundleTokenParams::CloneHandle() const {
+ if (!handle)
+ return mojo::NullRemote();
+ mojo::Remote<network::mojom::WebBundleHandle> remote(std::move(
+ const_cast<mojo::PendingRemote<network::mojom::WebBundleHandle>&>(
+ handle)));
+ mojo::PendingRemote<network::mojom::WebBundleHandle> new_remote;
+ remote->Clone(new_remote.InitWithNewPipeAndPassReceiver());
+ const_cast<mojo::PendingRemote<network::mojom::WebBundleHandle>&>(handle) =
+ remote.Unbind();
+ return new_remote;
+}
+
const base::TimeDelta ResourceRequestHead::default_timeout_interval_ =
base::TimeDelta::Max();
@@ -127,26 +164,12 @@ ResourceRequest::ResourceRequest(const KURL& url) : ResourceRequestHead(url) {}
ResourceRequest::ResourceRequest(const ResourceRequestHead& head)
: ResourceRequestHead(head) {}
-ResourceRequest& ResourceRequest::operator=(const ResourceRequest& src) {
- DCHECK(!body_.StreamBody().is_valid());
- DCHECK(!src.body_.StreamBody().is_valid());
- this->ResourceRequestHead::operator=(src);
- body_.SetFormBody(src.body_.FormBody());
- return *this;
-}
-
ResourceRequest::ResourceRequest(ResourceRequest&&) = default;
ResourceRequest& ResourceRequest::operator=(ResourceRequest&&) = default;
ResourceRequest::~ResourceRequest() = default;
-void ResourceRequest::CopyFrom(const ResourceRequest& src) {
- DCHECK(!body_.StreamBody().is_valid());
- DCHECK(!src.body_.StreamBody().is_valid());
- *this = src;
-}
-
void ResourceRequest::CopyHeadFrom(const ResourceRequestHead& src) {
this->ResourceRequestHead::operator=(src);
}
@@ -197,6 +220,7 @@ std::unique_ptr<ResourceRequest> ResourceRequestHead::CreateRedirectRequest(
IsSignedExchangePrefetchCacheEnabled());
request->SetRecursivePrefetchToken(RecursivePrefetchToken());
request->SetFetchLikeAPI(IsFetchLikeAPI());
+ request->SetFavicon(IsFavicon());
return request;
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
index d55e1fae866..3290fa3a99e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_request.h
@@ -41,9 +41,12 @@
#include "services/network/public/mojom/fetch_api.mojom-blink-forward.h"
#include "services/network/public/mojom/ip_address_space.mojom-blink-forward.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
+#include "services/network/public/mojom/url_loader.mojom-blink.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
#include "third_party/blink/public/platform/web_url_request_extra_data.h"
+#include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/network/http_header_map.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
@@ -80,6 +83,23 @@ class PLATFORM_EXPORT ResourceRequestHead {
: original_url(original_url), previous_url(previous_url) {}
};
+ struct PLATFORM_EXPORT WebBundleTokenParams {
+ WebBundleTokenParams() = delete;
+ WebBundleTokenParams(const WebBundleTokenParams& other);
+ WebBundleTokenParams& operator=(const WebBundleTokenParams& other);
+
+ WebBundleTokenParams(
+ const KURL& bundle_url,
+ const base::UnguessableToken& token,
+ mojo::PendingRemote<network::mojom::WebBundleHandle> handle);
+
+ mojo::PendingRemote<network::mojom::WebBundleHandle> CloneHandle() const;
+
+ KURL bundle_url;
+ base::UnguessableToken token;
+ mojo::PendingRemote<network::mojom::WebBundleHandle> handle;
+ };
+
ResourceRequestHead();
explicit ResourceRequestHead(const KURL&);
@@ -457,6 +477,10 @@ class PLATFORM_EXPORT ResourceRequestHead {
void SetFetchLikeAPI(bool enabled) { is_fetch_like_api_ = enabled; }
+ bool IsFavicon() const { return is_favicon_; }
+
+ void SetFavicon(bool enabled) { is_favicon_ = enabled; }
+
bool PrefetchMaybeForTopLeveNavigation() const {
return prefetch_maybe_for_top_level_navigation_;
}
@@ -486,6 +510,23 @@ class PLATFORM_EXPORT ResourceRequestHead {
return allowHTTP1ForStreamingUpload_;
}
+ const base::Optional<ResourceRequestHead::WebBundleTokenParams>&
+ GetWebBundleTokenParams() const {
+ return web_bundle_token_params_;
+ }
+
+ void SetWebBundleTokenParams(
+ ResourceRequestHead::WebBundleTokenParams params) {
+ web_bundle_token_params_ = params;
+ }
+
+ void SetRenderBlockingBehavior(RenderBlockingBehavior behavior) {
+ render_blocking_behavior_ = behavior;
+ }
+ RenderBlockingBehavior GetRenderBlockingBehavior() const {
+ return render_blocking_behavior_;
+ }
+
private:
const CacheControlHeader& GetCacheControlHeader() const;
@@ -569,6 +610,8 @@ class PLATFORM_EXPORT ResourceRequestHead {
bool is_fetch_like_api_ = false;
+ bool is_favicon_ = false;
+
// Currently this is only used when a prefetch request has `as=document`
// specified. If true, and the request is cross-origin, the browser will cache
// the request under the cross-origin's partition. Furthermore, its reuse from
@@ -581,6 +624,16 @@ class PLATFORM_EXPORT ResourceRequestHead {
// prefetch responses. The browser process uses this token to ensure the
// request is cached correctly.
base::Optional<base::UnguessableToken> recursive_prefetch_token_;
+
+ // This is used when fetching either a WebBundle or a subresrouce in the
+ // WebBundle. The network process uses this token to associate the request to
+ // the bundle.
+ base::Optional<WebBundleTokenParams> web_bundle_token_params_;
+
+ // Render blocking behavior of the resource. Used in maintaining correct
+ // reporting for redirects.
+ RenderBlockingBehavior render_blocking_behavior_ =
+ RenderBlockingBehavior::kUnset;
};
class PLATFORM_EXPORT ResourceRequestBody {
@@ -644,13 +697,11 @@ class PLATFORM_EXPORT ResourceRequest final : public ResourceRequestHead {
ResourceRequest(const ResourceRequest&) = delete;
ResourceRequest(ResourceRequest&&);
+ ResourceRequest& operator=(const ResourceRequest&) = delete;
ResourceRequest& operator=(ResourceRequest&&);
~ResourceRequest();
- // TODO(yoichio): Use move semantics as much as possible.
- // See crbug.com/787704.
- void CopyFrom(const ResourceRequest&);
void CopyHeadFrom(const ResourceRequestHead&);
const scoped_refptr<EncodedFormData>& HttpBody() const;
@@ -659,8 +710,6 @@ class PLATFORM_EXPORT ResourceRequest final : public ResourceRequestHead {
ResourceRequestBody& MutableBody() { return body_; }
private:
- ResourceRequest& operator=(const ResourceRequest&);
-
ResourceRequestBody body_;
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index 5fadb1c34d9..cbec9d25317 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -321,6 +321,9 @@ class PLATFORM_EXPORT ResourceResponse final {
app_cache_manifest_url_ = url;
}
+ const KURL& WebBundleURL() const { return web_bundle_url_; }
+ void SetWebBundleURL(const KURL& url) { web_bundle_url_ = url; }
+
bool WasFetchedViaSPDY() const { return was_fetched_via_spdy_; }
void SetWasFetchedViaSPDY(bool value) { was_fetched_via_spdy_ = value; }
@@ -358,6 +361,9 @@ class PLATFORM_EXPORT ResourceResponse final {
// https://html.spec.whatwg.org/C/#cors-cross-origin
bool IsCorsCrossOrigin() const;
+ int64_t GetPadding() const { return padding_; }
+ void SetPadding(int64_t padding) { padding_ = padding; }
+
// See network::ResourceResponseInfo::url_list_via_service_worker.
const Vector<KURL>& UrlListViaServiceWorker() const {
return url_list_via_service_worker_;
@@ -494,9 +500,23 @@ class PLATFORM_EXPORT ResourceResponse final {
was_cookie_in_request_ = was_cookie_in_request;
}
+ const Vector<String>& DnsAliases() const { return dns_aliases_; }
+
+ void SetDnsAliases(Vector<String> aliases) {
+ dns_aliases_ = std::move(aliases);
+ }
+
network::mojom::CrossOriginEmbedderPolicyValue GetCrossOriginEmbedderPolicy()
const;
+ const base::Optional<net::AuthChallengeInfo>& AuthChallengeInfo() const {
+ return auth_challenge_info_;
+ }
+ void SetAuthChallengeInfo(
+ const base::Optional<net::AuthChallengeInfo>& value) {
+ auth_challenge_info_ = value;
+ }
+
private:
void UpdateHeaderParsedState(const AtomicString& name);
@@ -597,6 +617,11 @@ class PLATFORM_EXPORT ResourceResponse final {
network::mojom::FetchResponseType response_type_ =
network::mojom::FetchResponseType::kDefault;
+ // Pre-computed padding. This should only be non-zero if |response_type| is
+ // set to kOpaque. In addition, it is only set if the response was provided
+ // by a service worker FetchEvent handler.
+ int64_t padding_ = 0;
+
// HTTP version used in the response, if known.
HTTPVersion http_version_ = kHTTPVersionUnknown;
@@ -666,6 +691,17 @@ class PLATFORM_EXPORT ResourceResponse final {
// cross-origin prefetch responses. It is used to pass the token along to
// preload header requests from these responses.
base::Optional<base::UnguessableToken> recursive_prefetch_token_;
+
+ // Any DNS aliases for the requested URL, as read from CNAME records.
+ // The alias chain order is preserved in reverse, from canonical name (i.e.
+ // address record name) through to query name.
+ Vector<String> dns_aliases_;
+
+ // The URL of WebBundle this response was loaded from. This value is only
+ // populated for resources loaded from a WebBundle.
+ KURL web_bundle_url_;
+
+ base::Optional<net::AuthChallengeInfo> auth_challenge_info_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc
index 1e2d9198ec8..ce3b6c5e949 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
@@ -102,4 +103,15 @@ TEST(ResourceResponseTest, AddHttpHeaderFieldWithMultipleValues) {
EXPECT_EQ("a=1, b=2, c=3", response.HttpHeaderField("set-cookie"));
}
+TEST(ResourceResponseTest, DnsAliasesCanBeSetAndAccessed) {
+ ResourceResponse response(CreateTestResponse());
+
+ EXPECT_TRUE(response.DnsAliases().IsEmpty());
+
+ Vector<String> aliases({"alias1", "alias2"});
+ response.SetDnsAliases(aliases);
+
+ EXPECT_THAT(response.DnsAliases(), testing::ElementsAre("alias1", "alias2"));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
index 4353c202b8a..7bbd1ee946e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -12,137 +12,13 @@
#include "third_party/blink/renderer/platform/loader/testing/mock_resource.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
-#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
namespace {
-class MockPlatform final : public TestingPlatformSupportWithMockScheduler {
- public:
- MockPlatform() = default;
- ~MockPlatform() override = default;
-
- // From blink::Platform:
- void CacheMetadata(blink::mojom::CodeCacheType cache_type,
- const WebURL& url,
- base::Time,
- const uint8_t*,
- size_t) override {
- cached_urls_.push_back(url);
- }
-
- void CacheMetadataInCacheStorage(const blink::WebURL& url,
- base::Time,
- const uint8_t*,
- size_t,
- const blink::WebSecurityOrigin&,
- const blink::WebString&) override {
- cache_storage_cached_urls_.push_back(url);
- }
-
- const Vector<WebURL>& CachedURLs() const { return cached_urls_; }
- const Vector<WebURL>& CacheStorageCachedURLs() const {
- return cache_storage_cached_urls_;
- }
-
- private:
- Vector<WebURL> cached_urls_;
- Vector<WebURL> cache_storage_cached_urls_;
-};
-
-ResourceResponse CreateTestResourceResponse() {
- ResourceResponse response(url_test_helpers::ToKURL("https://example.com/"));
- response.SetHttpStatusCode(200);
- return response;
-}
-
-void CreateTestResourceAndSetCachedMetadata(const ResourceResponse& response) {
- const uint8_t kTestData[] = {1, 2, 3, 4, 5};
- ResourceRequest request(response.CurrentRequestUrl());
- request.SetRequestorOrigin(
- SecurityOrigin::Create(response.CurrentRequestUrl()));
- auto* resource = MakeGarbageCollected<MockResource>(request);
- resource->SetResponse(response);
- resource->SendCachedMetadata(kTestData, sizeof(kTestData));
- return;
-}
-
-} // anonymous namespace
-
-TEST(ResourceTest, SetCachedMetadata_SendsMetadataToPlatform) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
- ResourceResponse response(CreateTestResourceResponse());
- CreateTestResourceAndSetCachedMetadata(response);
- EXPECT_EQ(1u, mock->CachedURLs().size());
- EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
-}
-
-TEST(
- ResourceTest,
- SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticResponse) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
-
- // Equivalent to service worker calling respondWith(new Response(...))
- ResourceResponse response(CreateTestResourceResponse());
- response.SetWasFetchedViaServiceWorker(true);
-
- CreateTestResourceAndSetCachedMetadata(response);
- EXPECT_EQ(0u, mock->CachedURLs().size());
- EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
-}
-
-TEST(
- ResourceTest,
- SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
-
- // Equivalent to service worker calling respondWith(fetch(evt.request.url));
- ResourceResponse response(CreateTestResourceResponse());
- response.SetWasFetchedViaServiceWorker(true);
- response.SetUrlListViaServiceWorker(
- Vector<KURL>(1, response.CurrentRequestUrl()));
-
- CreateTestResourceAndSetCachedMetadata(response);
- EXPECT_EQ(1u, mock->CachedURLs().size());
- EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
-}
-
-TEST(
- ResourceTest,
- SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
-
- // Equivalent to service worker calling respondWith(fetch(some_different_url))
- ResourceResponse response(CreateTestResourceResponse());
- response.SetWasFetchedViaServiceWorker(true);
- response.SetUrlListViaServiceWorker(Vector<KURL>(
- 1, url_test_helpers::ToKURL("https://example.com/different/url")));
-
- CreateTestResourceAndSetCachedMetadata(response);
- EXPECT_EQ(0u, mock->CachedURLs().size());
- EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
-}
-
-TEST(
- ResourceTest,
- SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
-
- // Equivalent to service worker calling respondWith(cache.match(some_url));
- ResourceResponse response(CreateTestResourceResponse());
- response.SetWasFetchedViaServiceWorker(true);
- response.SetCacheStorageCacheName("dummy");
-
- CreateTestResourceAndSetCachedMetadata(response);
- EXPECT_EQ(0u, mock->CachedURLs().size());
- EXPECT_EQ(1u, mock->CacheStorageCachedURLs().size());
-}
-
TEST(ResourceTest, RevalidateWithFragment) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
KURL url("http://127.0.0.1:8000/foo.html");
ResourceResponse response(url);
response.SetHttpStatusCode(200);
@@ -160,7 +36,6 @@ TEST(ResourceTest, RevalidateWithFragment) {
}
TEST(ResourceTest, Vary) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
const KURL url("http://127.0.0.1:8000/foo.html");
ResourceResponse response(url);
response.SetHttpStatusCode(200);
@@ -228,14 +103,9 @@ TEST(ResourceTest, RevalidationFailed) {
resource->FinishForTest();
GetMemoryCache()->Add(resource);
- MockCacheHandler* original_cache_handler = resource->CacheHandler();
- EXPECT_TRUE(original_cache_handler);
-
// Simulate revalidation start.
resource->SetRevalidatingRequest(ResourceRequest(url));
- EXPECT_EQ(original_cache_handler, resource->CacheHandler());
-
Persistent<MockResourceClient> client =
MakeGarbageCollected<MockResourceClient>();
resource->AddClient(client, nullptr);
@@ -247,8 +117,6 @@ TEST(ResourceTest, RevalidationFailed) {
EXPECT_FALSE(resource->IsCacheValidator());
EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
EXPECT_FALSE(resource->ResourceBuffer());
- EXPECT_TRUE(resource->CacheHandler());
- EXPECT_NE(original_cache_handler, resource->CacheHandler());
EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
resource->AppendData(kData, 4);
@@ -265,7 +133,7 @@ TEST(ResourceTest, RevalidationFailed) {
TEST(ResourceTest, RevalidationSucceeded) {
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
- platform_;
+ platform;
const KURL url("http://test.example.com/");
auto* resource = MakeGarbageCollected<MockResource>(url);
ResourceResponse response(url);
@@ -276,14 +144,9 @@ TEST(ResourceTest, RevalidationSucceeded) {
resource->FinishForTest();
GetMemoryCache()->Add(resource);
- MockCacheHandler* original_cache_handler = resource->CacheHandler();
- EXPECT_TRUE(original_cache_handler);
-
// Simulate a successful revalidation.
resource->SetRevalidatingRequest(ResourceRequest(url));
- EXPECT_EQ(original_cache_handler, resource->CacheHandler());
-
Persistent<MockResourceClient> client =
MakeGarbageCollected<MockResourceClient>();
resource->AddClient(client, nullptr);
@@ -295,7 +158,6 @@ TEST(ResourceTest, RevalidationSucceeded) {
EXPECT_FALSE(resource->IsCacheValidator());
EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
EXPECT_EQ(4u, resource->ResourceBuffer()->size());
- EXPECT_EQ(original_cache_handler, resource->CacheHandler());
EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
GetMemoryCache()->Remove(resource);
@@ -307,7 +169,7 @@ TEST(ResourceTest, RevalidationSucceeded) {
TEST(ResourceTest, RevalidationSucceededForResourceWithoutBody) {
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
- platform_;
+ platform;
const KURL url("http://test.example.com/");
auto* resource = MakeGarbageCollected<MockResource>(url);
ResourceResponse response(url);
@@ -339,7 +201,7 @@ TEST(ResourceTest, RevalidationSucceededForResourceWithoutBody) {
TEST(ResourceTest, RevalidationSucceededUpdateHeaders) {
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
- platform_;
+ platform;
const KURL url("http://test.example.com/");
auto* resource = MakeGarbageCollected<MockResource>(url);
ResourceResponse response(url);
@@ -415,7 +277,7 @@ TEST(ResourceTest, RevalidationSucceededUpdateHeaders) {
TEST(ResourceTest, RedirectDuringRevalidation) {
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
- platform_;
+ platform;
const KURL url("http://test.example.com/1");
const KURL redirect_target_url("http://test.example.com/2");
@@ -432,15 +294,11 @@ TEST(ResourceTest, RedirectDuringRevalidation) {
EXPECT_EQ(url, resource->GetResourceRequest().Url());
EXPECT_EQ(url, resource->LastResourceRequest().Url());
- MockCacheHandler* original_cache_handler = resource->CacheHandler();
- EXPECT_TRUE(original_cache_handler);
-
// Simulate a revalidation.
resource->SetRevalidatingRequest(ResourceRequest(url));
EXPECT_TRUE(resource->IsCacheValidator());
EXPECT_EQ(url, resource->GetResourceRequest().Url());
EXPECT_EQ(url, resource->LastResourceRequest().Url());
- EXPECT_EQ(original_cache_handler, resource->CacheHandler());
Persistent<MockResourceClient> client =
MakeGarbageCollected<MockResourceClient>();
@@ -457,15 +315,12 @@ TEST(ResourceTest, RedirectDuringRevalidation) {
EXPECT_FALSE(resource->IsCacheValidator());
EXPECT_EQ(url, resource->GetResourceRequest().Url());
EXPECT_EQ(redirect_target_url, resource->LastResourceRequest().Url());
- EXPECT_FALSE(resource->CacheHandler());
// The final response is received.
ResourceResponse revalidating_response(redirect_target_url);
revalidating_response.SetHttpStatusCode(200);
resource->ResponseReceived(revalidating_response);
- EXPECT_TRUE(resource->CacheHandler());
-
const char kData2[4] = "xyz";
resource->AppendData(kData2, 3);
resource->FinishForTest();
@@ -482,13 +337,11 @@ TEST(ResourceTest, RedirectDuringRevalidation) {
// Test the case where a client is added after revalidation is completed.
Persistent<MockResourceClient> client2 =
MakeGarbageCollected<MockResourceClient>();
- auto* platform = static_cast<TestingPlatformSupportWithMockScheduler*>(
- Platform::Current());
resource->AddClient(client2, platform->test_task_runner().get());
// Because the client is added asynchronously,
// |runUntilIdle()| is called to make |client2| to be notified.
- platform_->RunUntilIdle();
+ platform->RunUntilIdle();
EXPECT_TRUE(client2->NotifyFinishedCalled());
@@ -508,7 +361,7 @@ class ScopedResourceMockClock {
};
TEST(ResourceTest, StaleWhileRevalidateCacheControl) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
+ ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> mock;
ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
const KURL url("http://127.0.0.1:8000/foo.html");
ResourceResponse response(url);
@@ -536,7 +389,7 @@ TEST(ResourceTest, StaleWhileRevalidateCacheControl) {
}
TEST(ResourceTest, StaleWhileRevalidateCacheControlWithRedirect) {
- ScopedTestingPlatformSupport<MockPlatform> mock;
+ ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> mock;
ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
const KURL url("http://127.0.0.1:8000/foo.html");
const KURL redirect_target_url("http://127.0.0.1:8000/food.html");
@@ -582,4 +435,13 @@ TEST(ResourceTest, DefaultOverheadSize) {
EXPECT_EQ(resource->CalculateOverheadSizeForTest(), resource->OverheadSize());
}
+TEST(ResourceTest, SetIsAdResource) {
+ const KURL url("http://127.0.0.1:8000/foo.html");
+ auto* resource = MakeGarbageCollected<MockResource>(url);
+ EXPECT_FALSE(resource->GetResourceRequest().IsAdResource());
+ resource->SetIsAdResource();
+ EXPECT_TRUE(resource->GetResourceRequest().IsAdResource());
+}
+
+} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
index 611a1701ad6..1bd85bd0f18 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
@@ -9,6 +9,8 @@
#include "base/auto_reset.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
@@ -18,7 +20,7 @@ namespace blink {
constexpr size_t ResponseBodyLoader::kMaxNumConsumedBytesInTask;
-constexpr size_t kDefaultMaxBufferedBodyBytes = 100 * 1000;
+constexpr size_t kDefaultMaxBufferedBodyBytesPerRequest = 100 * 1000;
class ResponseBodyLoader::DelegatingBytesConsumer final
: public BytesConsumer,
@@ -286,10 +288,9 @@ class ResponseBodyLoader::Buffer final
public:
explicit Buffer(ResponseBodyLoader* owner)
: owner_(owner),
- max_bytes_to_read_(base::GetFieldTrialParamByFeatureAsInt(
- blink::features::kLoadingTasksUnfreezable,
+ max_bytes_to_read_(GetLoadingTasksUnfreezableParamAsInt(
"max_buffered_bytes",
- kDefaultMaxBufferedBodyBytes)) {}
+ kDefaultMaxBufferedBodyBytesPerRequest)) {}
bool IsEmpty() const { return buffered_data_.IsEmpty(); }
@@ -297,6 +298,9 @@ class ResponseBodyLoader::Buffer final
// exceeds |max_bytes_to_read_| bytes.
bool AddChunk(const char* buffer, size_t available) {
total_bytes_read_ += available;
+ TRACE_EVENT2("loading", "ResponseBodyLoader::Buffer::AddChunk",
+ "total_bytes_read", static_cast<int>(total_bytes_read_),
+ "added_bytes", static_cast<int>(available));
if (total_bytes_read_ > max_bytes_to_read_)
return false;
Vector<char> new_chunk;
@@ -344,9 +348,11 @@ class ResponseBodyLoader::Buffer final
ResponseBodyLoader::ResponseBodyLoader(
BytesConsumer& bytes_consumer,
ResponseBodyLoaderClient& client,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper)
: bytes_consumer_(bytes_consumer),
client_(client),
+ back_forward_cache_loader_helper_(back_forward_cache_loader_helper),
task_runner_(std::move(task_runner)) {
bytes_consumer_->SetClient(this);
body_buffer_ = MakeGarbageCollected<Buffer>(this);
@@ -433,10 +439,26 @@ void ResponseBodyLoader::DidCancelLoadingBody() {
client_->DidCancelLoadingBody();
}
-// TODO(yuzus): Remove this and provide the capability to the loader.
void ResponseBodyLoader::EvictFromBackForwardCache(
mojom::blink::RendererEvictionReason reason) {
- client_->EvictFromBackForwardCache(reason);
+ if (!back_forward_cache_loader_helper_)
+ return;
+ back_forward_cache_loader_helper_->EvictFromBackForwardCache(reason);
+}
+
+void ResponseBodyLoader::DidBufferLoadWhileInBackForwardCache(
+ size_t num_bytes) {
+ if (!back_forward_cache_loader_helper_)
+ return;
+ back_forward_cache_loader_helper_->DidBufferLoadWhileInBackForwardCache(
+ num_bytes);
+}
+
+bool ResponseBodyLoader::CanContinueBufferingWhileInBackForwardCache() {
+ if (!back_forward_cache_loader_helper_)
+ return false;
+ return back_forward_cache_loader_helper_
+ ->CanContinueBufferingWhileInBackForwardCache();
}
void ResponseBodyLoader::Start() {
@@ -470,7 +492,7 @@ void ResponseBodyLoader::Suspend(WebURLLoader::DeferType suspended_state) {
suspended_state_ = suspended_state;
if (IsSuspendedForBackForwardCache()) {
- DCHECK(base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable));
+ DCHECK(IsInflightNetworkRequestBackForwardCacheSupportEnabled());
// If we're already suspended (but not for back-forward cache), we might've
// ignored some OnStateChange calls.
if (was_suspended) {
@@ -483,7 +505,7 @@ void ResponseBodyLoader::Suspend(WebURLLoader::DeferType suspended_state) {
void ResponseBodyLoader::EvictFromBackForwardCacheIfDrained() {
if (IsDrained()) {
- client_->EvictFromBackForwardCache(
+ EvictFromBackForwardCache(
mojom::blink::RendererEvictionReason::kNetworkRequestDatapipeDrained);
}
}
@@ -554,7 +576,9 @@ void ResponseBodyLoader::OnStateChange() {
std::min(available, kMaxNumConsumedBytesInTask - num_bytes_consumed);
if (IsSuspendedForBackForwardCache()) {
// Save the read data into |body_buffer_| instead.
- if (!body_buffer_->AddChunk(buffer, available)) {
+ DidBufferLoadWhileInBackForwardCache(available);
+ if (!body_buffer_->AddChunk(buffer, available) ||
+ !CanContinueBufferingWhileInBackForwardCache()) {
// We've read too much data while suspended for back-forward cache.
// Evict the page from the back-forward cache.
result = bytes_consumer_->EndRead(available);
@@ -598,6 +622,7 @@ void ResponseBodyLoader::Trace(Visitor* visitor) const {
visitor->Trace(delegating_bytes_consumer_);
visitor->Trace(client_);
visitor->Trace(body_buffer_);
+ visitor->Trace(back_forward_cache_loader_helper_);
ResponseBodyLoaderDrainableInterface::Trace(visitor);
ResponseBodyLoaderClient::Trace(visitor);
BytesConsumer::Client::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
index 1589dfddbcd..4ca1a94aa88 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_refptr.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink-forward.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
@@ -24,6 +25,7 @@ class SingleThreadTaskRunner;
namespace blink {
+class BackForwardCacheLoaderHelper;
class ResponseBodyLoader;
// See ResponseBodyLoader for details. This is a virtual interface to expose
@@ -74,9 +76,11 @@ class PLATFORM_EXPORT ResponseBodyLoader final
private ResponseBodyLoaderClient,
private BytesConsumer::Client {
public:
- ResponseBodyLoader(BytesConsumer&,
- ResponseBodyLoaderClient&,
- scoped_refptr<base::SingleThreadTaskRunner>);
+ ResponseBodyLoader(
+ BytesConsumer&,
+ ResponseBodyLoaderClient&,
+ scoped_refptr<base::SingleThreadTaskRunner>,
+ BackForwardCacheLoaderHelper* back_forward_cache_loader_helper);
// ResponseBodyLoaderDrainableInterface implementation.
mojo::ScopedDataPipeConsumerHandle DrainAsDataPipe(
@@ -127,17 +131,19 @@ class PLATFORM_EXPORT ResponseBodyLoader final
void DidFinishLoadingBody() override;
void DidFailLoadingBody() override;
void DidCancelLoadingBody() override;
- void EvictFromBackForwardCache(mojom::blink::RendererEvictionReason) override;
+ void EvictFromBackForwardCache(mojom::blink::RendererEvictionReason);
+ void DidBufferLoadWhileInBackForwardCache(size_t num_bytes);
+ bool CanContinueBufferingWhileInBackForwardCache();
// BytesConsumer::Client implementation.
void OnStateChange() override;
String DebugName() const override { return "ResponseBodyLoader"; }
- // When |buffer_data_while_suspended_for_bfcache_| is true, we'll save the
- // response body read when suspended.
+
Member<Buffer> body_buffer_;
Member<BytesConsumer> bytes_consumer_;
Member<DelegatingBytesConsumer> delegating_bytes_consumer_;
const Member<ResponseBodyLoaderClient> client_;
+ WeakMember<BackForwardCacheLoaderHelper> back_forward_cache_loader_helper_;
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
WebURLLoader::DeferType suspended_state_ =
WebURLLoader::DeferType::kNotDeferred;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h
index ef9d2d87ea9..993a92f26e3 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h
@@ -27,10 +27,6 @@ class ResponseBodyLoaderClient : public GarbageCollectedMixin {
// Called when the loader cancelled loading the body.
virtual void DidCancelLoadingBody() = 0;
-
- // Called when the body loader is suspended and the data pipe is drained.
- virtual void EvictFromBackForwardCache(
- mojom::blink::RendererEvictionReason) = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
index 4c22d831f78..0b0d928c738 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
@@ -10,7 +10,9 @@
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
#include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h"
#include "third_party/blink/renderer/platform/loader/testing/bytes_consumer_test_reader.h"
#include "third_party/blink/renderer/platform/loader/testing/replaying_bytes_consumer.h"
@@ -21,6 +23,15 @@ namespace blink {
namespace {
+class TestBackForwardCacheLoaderHelper : public BackForwardCacheLoaderHelper {
+ public:
+ TestBackForwardCacheLoaderHelper() = default;
+
+ bool CanContinueBufferingWhileInBackForwardCache() const override {
+ return true;
+ }
+};
+
class ResponseBodyLoaderTest : public testing::Test {
protected:
using Command = ReplayingBytesConsumer::Command;
@@ -74,7 +85,6 @@ class ResponseBodyLoaderTest : public testing::Test {
DCHECK(!failed_);
cancelled_ = true;
}
- void EvictFromBackForwardCache(mojom::RendererEvictionReason) override {}
void SetLoader(ResponseBodyLoader& loader) { loader_ = loader; }
void Trace(Visitor* visitor) const override { visitor->Trace(loader_); }
@@ -134,6 +144,15 @@ class ResponseBodyLoaderTest : public testing::Test {
const Member<BytesConsumer> bytes_consumer_;
const Member<TestClient> test_response_body_loader_client_;
};
+
+ ResponseBodyLoader* MakeResponseBodyLoader(
+ BytesConsumer& bytes_consumer,
+ ResponseBodyLoaderClient& client,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ return MakeGarbageCollected<ResponseBodyLoader>(
+ bytes_consumer, client, task_runner,
+ MakeGarbageCollected<TestBackForwardCacheLoaderHelper>());
+ }
};
class ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest
@@ -151,8 +170,7 @@ TEST_F(ResponseBodyLoaderTest, Load) {
consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
EXPECT_FALSE(client->LoadingIsFinished());
EXPECT_FALSE(client->LoadingIsFailed());
@@ -180,8 +198,7 @@ TEST_F(ResponseBodyLoaderTest, LoadFailure) {
consumer->Add(Command(Command::kError));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
EXPECT_FALSE(client->LoadingIsFinished());
EXPECT_FALSE(client->LoadingIsFailed());
@@ -208,8 +225,7 @@ TEST_F(ResponseBodyLoaderTest, LoadWithDataAndDone) {
consumer->Add(Command(Command::kDataAndDone, "llo"));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
EXPECT_FALSE(client->LoadingIsFinished());
EXPECT_FALSE(client->LoadingIsFailed());
@@ -238,8 +254,7 @@ TEST_F(ResponseBodyLoaderTest, Abort) {
auto* client = MakeGarbageCollected<TestClient>(
TestClient::Option::kAbortOnDidReceiveData);
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
client->SetLoader(*body_loader);
EXPECT_FALSE(client->LoadingIsFinished());
@@ -270,8 +285,7 @@ TEST_F(ResponseBodyLoaderTest, Suspend) {
auto* client = MakeGarbageCollected<TestClient>(
TestClient::Option::kSuspendOnDidReceiveData);
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
client->SetLoader(*body_loader);
EXPECT_FALSE(client->LoadingIsFinished());
@@ -335,8 +349,7 @@ TEST_F(ResponseBodyLoaderTest, ReadTooBigBuffer) {
consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
EXPECT_FALSE(client->LoadingIsFinished());
EXPECT_FALSE(client->LoadingIsFailed());
@@ -367,8 +380,7 @@ TEST_F(ResponseBodyLoaderTest, NotDrainable) {
consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
ResponseBodyLoaderClient* intermediate_client = nullptr;
auto data_pipe = body_loader->DrainAsDataPipe(&intermediate_client);
@@ -399,7 +411,7 @@ TEST_F(ResponseBodyLoaderTest, NotDrainable) {
TEST_F(ResponseBodyLoaderTest, DrainAsDataPipe) {
mojo::ScopedDataPipeConsumerHandle consumer_end;
mojo::ScopedDataPipeProducerHandle producer_end;
- auto result = mojo::CreateDataPipe(nullptr, &producer_end, &consumer_end);
+ auto result = mojo::CreateDataPipe(nullptr, producer_end, consumer_end);
ASSERT_EQ(result, MOJO_RESULT_OK);
@@ -410,8 +422,7 @@ TEST_F(ResponseBodyLoaderTest, DrainAsDataPipe) {
task_runner, std::move(consumer_end), &completion_notifier);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
ResponseBodyLoaderClient* client_for_draining = nullptr;
auto data_pipe = body_loader->DrainAsDataPipe(&client_for_draining);
@@ -443,6 +454,8 @@ class ResponseBodyLoaderLoadingTasksUnfreezableTest
scoped_feature_list_.InitAndEnableFeature(
features::kLoadingTasksUnfreezable);
}
+ WebRuntimeFeatures::EnableBackForwardCache(
+ DeferWithBackForwardCacheEnabled());
}
bool DeferWithBackForwardCacheEnabled() { return GetParam(); }
@@ -458,8 +471,7 @@ TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
consumer->Add(Command(Command::kData, "he"));
body_loader->Start();
task_runner->RunUntilIdle();
@@ -517,8 +529,7 @@ TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
consumer->Add(Command(Command::kData, "he"));
body_loader->Start();
task_runner->RunUntilIdle();
@@ -571,8 +582,7 @@ TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
consumer->Add(Command(Command::kData, "he"));
body_loader->Start();
task_runner->RunUntilIdle();
@@ -634,8 +644,7 @@ TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
body_loader->Start();
task_runner->RunUntilIdle();
EXPECT_EQ("", client->GetData());
@@ -675,7 +684,7 @@ INSTANTIATE_TEST_SUITE_P(All,
TEST_F(ResponseBodyLoaderTest, DrainAsDataPipeAndReportError) {
mojo::ScopedDataPipeConsumerHandle consumer_end;
mojo::ScopedDataPipeProducerHandle producer_end;
- auto result = mojo::CreateDataPipe(nullptr, &producer_end, &consumer_end);
+ auto result = mojo::CreateDataPipe(nullptr, producer_end, consumer_end);
ASSERT_EQ(result, MOJO_RESULT_OK);
@@ -686,8 +695,7 @@ TEST_F(ResponseBodyLoaderTest, DrainAsDataPipeAndReportError) {
task_runner, std::move(consumer_end), &completion_notifier);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader =
- MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+ auto* body_loader = MakeResponseBodyLoader(*consumer, *client, task_runner);
ResponseBodyLoaderClient* client_for_draining = nullptr;
auto data_pipe = body_loader->DrainAsDataPipe(&client_for_draining);
@@ -721,8 +729,9 @@ TEST_F(ResponseBodyLoaderTest, DrainAsBytesConsumer) {
original_consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
@@ -750,8 +759,9 @@ TEST_F(ResponseBodyLoaderTest, CancelDrainedBytesConsumer) {
original_consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
@@ -786,8 +796,9 @@ TEST_F(ResponseBodyLoaderTest, DrainAsBytesConsumerWithError) {
original_consumer->Add(Command(Command::kError));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
@@ -814,8 +825,9 @@ TEST_F(ResponseBodyLoaderTest, AbortAfterBytesConsumerIsDrained) {
original_consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
auto* bytes_consumer_client =
@@ -844,8 +856,9 @@ TEST_F(ResponseBodyLoaderTest, AbortAfterBytesConsumerIsDrainedIsNotified) {
MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
@@ -873,8 +886,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
original_consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
const char* buffer = nullptr;
@@ -920,8 +934,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
original_consumer->Add(Command(Command::kError));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
const char* buffer = nullptr;
@@ -972,8 +987,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
original_consumer->Add(Command(Command::kDataAndDone, "hello"));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
const char* buffer = nullptr;
@@ -1019,7 +1035,7 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
DrainAsDataPipe) {
mojo::ScopedDataPipeConsumerHandle consumer_end;
mojo::ScopedDataPipeProducerHandle producer_end;
- auto result = mojo::CreateDataPipe(nullptr, &producer_end, &consumer_end);
+ auto result = mojo::CreateDataPipe(nullptr, producer_end, consumer_end);
ASSERT_EQ(result, MOJO_RESULT_OK);
@@ -1030,8 +1046,8 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
task_runner, std::move(consumer_end), &completion_notifier);
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
@@ -1058,8 +1074,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationOutOfOnStateChangeTest,
original_consumer->Add(Command(Command::kWait));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
task_runner->RunUntilIdle();
@@ -1087,8 +1104,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationInOnStateChangeTest,
original_consumer->Add(Command(Command::kDone));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
auto* reading_client = MakeGarbageCollected<ReadingClient>(consumer, *client);
@@ -1127,8 +1145,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationInOnStateChangeTest,
original_consumer->Add(Command(Command::kError));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
auto* reading_client = MakeGarbageCollected<ReadingClient>(consumer, *client);
@@ -1167,8 +1186,9 @@ TEST_F(ResponseBodyLoaderDrainedBytesConsumerNotificationInOnStateChangeTest,
original_consumer->Add(Command(Command::kDataAndDone, "hahaha"));
auto* client = MakeGarbageCollected<TestClient>();
- auto* body_loader = MakeGarbageCollected<ResponseBodyLoader>(
- *original_consumer, *client, task_runner);
+
+ auto* body_loader =
+ MakeResponseBodyLoader(*original_consumer, *client, task_runner);
BytesConsumer& consumer = body_loader->DrainAsBytesConsumer();
auto* reading_client = MakeGarbageCollected<ReadingClient>(consumer, *client);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
index 6f58aa7b447..399d8302dd7 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.cc
@@ -30,6 +30,7 @@ FetchParameters ScriptFetchOptions::CreateFetchParameters(
FetchParameters params(std::move(resource_request), resource_loader_options);
params.SetRequestContext(mojom::blink::RequestContextType::SCRIPT);
params.SetRequestDestination(network::mojom::RequestDestination::kScript);
+ params.SetRenderBlockingBehavior(render_blocking_behavior_);
// Step 1. ... and CORS setting. [spec text]
if (cross_origin != kCrossOriginAttributeNotSet)
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
index 13a4cbd2c6f..74cff0cd404 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
+#include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -47,6 +48,7 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
network::mojom::CredentialsMode credentials_mode,
network::mojom::ReferrerPolicy referrer_policy,
mojom::FetchImportanceMode importance,
+ RenderBlockingBehavior render_blocking_behavior,
RejectCoepUnsafeNone reject_coep_unsafe_none =
RejectCoepUnsafeNone(false))
: nonce_(nonce),
@@ -56,6 +58,7 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
credentials_mode_(credentials_mode),
referrer_policy_(referrer_policy),
importance_(importance),
+ render_blocking_behavior_(render_blocking_behavior),
reject_coep_unsafe_none_(reject_coep_unsafe_none) {}
~ScriptFetchOptions() = default;
@@ -111,6 +114,8 @@ class PLATFORM_EXPORT ScriptFetchOptions final {
// "importance" member to the script fetch options struct.
const mojom::FetchImportanceMode importance_;
+ const RenderBlockingBehavior render_blocking_behavior_ =
+ RenderBlockingBehavior::kUnset;
// True when we should reject a response with COEP: none.
// https://wicg.github.io/cross-origin-embedder-policy/#integration-html
// This is for dedicated workers.
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.cc
index 2d1bb0e5f9b..2a3447539ff 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.cc
@@ -11,7 +11,7 @@ namespace blink {
StaleRevalidationResourceClient::StaleRevalidationResourceClient(
Resource* stale_resource)
- : start_time_(base::TimeTicks::Now()), stale_resource_(stale_resource) {}
+ : stale_resource_(stale_resource) {}
StaleRevalidationResourceClient::~StaleRevalidationResourceClient() = default;
@@ -20,13 +20,6 @@ void StaleRevalidationResourceClient::NotifyFinished(Resource* resource) {
if (stale_resource_ && IsMainThread())
GetMemoryCache()->Remove(stale_resource_);
ClearResource();
-
- base::TimeTicks response_end = resource->LoadResponseEnd();
- if (!response_end.is_null()) {
- UMA_HISTOGRAM_LONG_TIMES(
- "Blink.ResourceFetcher.StaleWhileRevalidateDuration",
- response_end - start_time_);
- }
}
void StaleRevalidationResourceClient::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h b/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h
index 889f68ba8c1..036b13a7bab 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h
@@ -26,7 +26,6 @@ class StaleRevalidationResourceClient
String DebugName() const override;
private:
- base::TimeTicks start_time_;
// |stale_resource_| is the original resource that will be removed from the
// MemoryCache when this revalidation request is completed. Note that it is
// different than the active resource for this resource client which accessed
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h b/chromium/third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h
index 2971478b1b4..e44eaffab65 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h
@@ -10,20 +10,24 @@
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/platform_export.h"
+namespace base {
+class UnguessableToken;
+}
+
namespace blink {
class KURL;
-// SubresourceWebBundle is attached to ResourceFetcher and used to intercept
-// subresource requests for a certain set of URLs and serve responses from a
+// SubresourceWebBundle is attached to ResourceFetcher and used to set
+// WebBundleToken to subresource requests which should be served from a
// WebBundle. This is used for Subresource loading with Web Bundles
// (https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md).
class PLATFORM_EXPORT SubresourceWebBundle : public GarbageCollectedMixin {
public:
void Trace(Visitor* visitor) const override {}
virtual bool CanHandleRequest(const KURL& url) const = 0;
- virtual mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
- GetURLLoaderFactory() = 0;
+ virtual const KURL& GetBundleUrl() const = 0;
+ virtual const base::UnguessableToken& WebBundleToken() const = 0;
virtual String GetCacheIdentifier() const = 0;
};
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/DEPS b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/DEPS
index cb1e4f6caaa..d1edc9d3dec 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/DEPS
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/DEPS
@@ -1,14 +1,31 @@
+include_rules = [
+ "+base/atomic_sequence_num.h",
+ "+net/base/registry_controlled_domains/registry_controlled_domain.h",
+ "+net/base/request_priority.h",
+ "+net/base/host_port_pair.h",
+ "+net/cert/cert_status_flags.h",
+ "+net/cert/ct_sct_to_string.h",
+ "+net/cert/x509_certificate.h",
+ "+net/cert/x509_util.h",
+ "+net/ssl/ssl_cipher_suite_names.h",
+ "+net/ssl/ssl_connection_status_flags.h",
+ "+net/ssl/ssl_info.h",
+ "+net/traffic_annotation/network_traffic_annotation.h",
+ "+net/url_request/referrer_policy.h",
+ "+services/network/public/mojom/url_loader.mojom.h",
+ "+services/network/public/mojom/url_response_head.mojom.h",
+ "+third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
+]
+
specific_include_rules = {
"request_conversion.cc" : [
"+media/media_buildflags.h"
],
- "web_bundle_subresource_loader.cc" : [
- "+components/web_package",
- "+net/http/http_status_code.h",
+ "sync_load_context_unittest.cc": [
+ "+base/threading/thread.h",
+ "+services/network/test/test_url_loader_factory.h"
],
- "web_bundle_subresource_loader_test.cc" : [
- "+components/web_package",
- "+net/traffic_annotation/network_traffic_annotation_test_helper.h",
- "+services/network/test/test_url_loader_client.h",
+ "web_url_loader_unittest.cc": [
+ "+net/test/cert_test_util.h"
],
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
new file mode 100644
index 00000000000..18ae7873f82
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
@@ -0,0 +1,594 @@
+// 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/platform/loader/fetch/url_loader/mojo_url_loader_client.h"
+
+#include <iterator>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/system/data_pipe_drainer.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+namespace {
+
+constexpr size_t kDefaultMaxBufferedBodyBytesPerRequest = 100 * 1000;
+constexpr base::TimeDelta kGracePeriodToFinishLoadingWhileInBackForwardCache =
+ base::TimeDelta::FromSeconds(15);
+
+} // namespace
+
+class MojoURLLoaderClient::DeferredMessage {
+ public:
+ DeferredMessage() = default;
+ virtual void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) = 0;
+ virtual bool IsCompletionMessage() const = 0;
+ virtual ~DeferredMessage() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeferredMessage);
+};
+
+class MojoURLLoaderClient::DeferredOnReceiveResponse final
+ : public DeferredMessage {
+ public:
+ explicit DeferredOnReceiveResponse(
+ network::mojom::URLResponseHeadPtr response_head)
+ : response_head_(std::move(response_head)) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnReceivedResponse(std::move(response_head_));
+ }
+ bool IsCompletionMessage() const override { return false; }
+
+ private:
+ network::mojom::URLResponseHeadPtr response_head_;
+};
+
+class MojoURLLoaderClient::DeferredOnReceiveRedirect final
+ : public DeferredMessage {
+ public:
+ DeferredOnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr response_head,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : redirect_info_(redirect_info),
+ response_head_(std::move(response_head)),
+ task_runner_(std::move(task_runner)) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnReceivedRedirect(
+ redirect_info_, std::move(response_head_), task_runner_);
+ }
+ bool IsCompletionMessage() const override { return false; }
+
+ private:
+ const net::RedirectInfo redirect_info_;
+ network::mojom::URLResponseHeadPtr response_head_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
+class MojoURLLoaderClient::DeferredOnUploadProgress final
+ : public DeferredMessage {
+ public:
+ DeferredOnUploadProgress(int64_t current, int64_t total)
+ : current_(current), total_(total) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnUploadProgress(current_, total_);
+ }
+ bool IsCompletionMessage() const override { return false; }
+
+ private:
+ const int64_t current_;
+ const int64_t total_;
+};
+
+class MojoURLLoaderClient::DeferredOnReceiveCachedMetadata final
+ : public DeferredMessage {
+ public:
+ explicit DeferredOnReceiveCachedMetadata(mojo_base::BigBuffer data)
+ : data_(std::move(data)) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnReceivedCachedMetadata(std::move(data_));
+ }
+ bool IsCompletionMessage() const override { return false; }
+
+ private:
+ mojo_base::BigBuffer data_;
+};
+
+class MojoURLLoaderClient::DeferredOnStartLoadingResponseBody final
+ : public DeferredMessage {
+ public:
+ explicit DeferredOnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body)
+ : body_(std::move(body)) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnStartLoadingResponseBody(std::move(body_));
+ }
+ bool IsCompletionMessage() const override { return false; }
+
+ private:
+ mojo::ScopedDataPipeConsumerHandle body_;
+};
+
+class MojoURLLoaderClient::DeferredOnComplete final : public DeferredMessage {
+ public:
+ explicit DeferredOnComplete(const network::URLLoaderCompletionStatus& status)
+ : status_(status) {}
+
+ void HandleMessage(
+ WebResourceRequestSender* resource_request_sender) override {
+ resource_request_sender->OnRequestComplete(status_);
+ }
+ bool IsCompletionMessage() const override { return true; }
+
+ private:
+ const network::URLLoaderCompletionStatus status_;
+};
+
+class MojoURLLoaderClient::BodyBuffer final
+ : public mojo::DataPipeDrainer::Client {
+ public:
+ BodyBuffer(MojoURLLoaderClient* owner,
+ mojo::ScopedDataPipeConsumerHandle readable,
+ mojo::ScopedDataPipeProducerHandle writable,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : owner_(owner),
+ writable_(std::move(writable)),
+ writable_watcher_(FROM_HERE,
+ mojo::SimpleWatcher::ArmingPolicy::MANUAL,
+ std::move(task_runner)),
+ max_bytes_drained_(GetLoadingTasksUnfreezableParamAsInt(
+ "max_buffered_bytes",
+ kDefaultMaxBufferedBodyBytesPerRequest)) {
+ pipe_drainer_ =
+ std::make_unique<mojo::DataPipeDrainer>(this, std::move(readable));
+ writable_watcher_.Watch(
+ writable_.get(),
+ MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ base::BindRepeating(&BodyBuffer::WriteBufferedBody,
+ base::Unretained(this)));
+ }
+
+ bool active() const { return writable_watcher_.IsWatching(); }
+
+ // mojo::DataPipeDrainer::Client
+ void OnDataAvailable(const void* data, size_t num_bytes) override {
+ DCHECK(draining_);
+ SCOPED_CRASH_KEY_NUMBER("OnDataAvailable", "buffered_body_size",
+ buffered_body_.size());
+ SCOPED_CRASH_KEY_NUMBER("OnDataAvailable", "data_bytes", num_bytes);
+ SCOPED_CRASH_KEY_STRING256("OnDataAvailable", "last_loaded_url",
+ owner_->last_loaded_url().GetString().Utf8());
+
+ total_bytes_drained_ += num_bytes;
+ TRACE_EVENT2("loading", "MojoURLLoaderClient::BodyBuffer::OnDataAvailable",
+ "total_bytes_drained", static_cast<int>(total_bytes_drained_),
+ "added_bytes", static_cast<int>(num_bytes));
+
+ if (owner_->IsDeferredWithBackForwardCache()) {
+ owner_->DidBufferLoadWhileInBackForwardCache(num_bytes);
+ if (total_bytes_drained_ > max_bytes_drained_ ||
+ !owner_->CanContinueBufferingWhileInBackForwardCache()) {
+ owner_->EvictFromBackForwardCache(
+ blink::mojom::RendererEvictionReason::kNetworkExceedsBufferLimit);
+ return;
+ }
+ }
+ buffered_body_.emplace(static_cast<const char*>(data),
+ static_cast<const char*>(data) + num_bytes);
+ WriteBufferedBody(MOJO_RESULT_OK);
+ }
+
+ void OnDataComplete() override {
+ DCHECK(draining_);
+ draining_ = false;
+ WriteBufferedBody(MOJO_RESULT_OK);
+ }
+
+ private:
+ void WriteBufferedBody(MojoResult) {
+ // Try to write all the remaining chunks in |buffered_body_|.
+ while (!buffered_body_.empty()) {
+ // Write the chunk at the front of |buffered_body_|.
+ const std::vector<char>& current_chunk = buffered_body_.front();
+ DCHECK_LE(offset_in_current_chunk_, current_chunk.size());
+ uint32_t bytes_sent = base::saturated_cast<uint32_t>(
+ current_chunk.size() - offset_in_current_chunk_);
+ MojoResult result =
+ writable_->WriteData(current_chunk.data() + offset_in_current_chunk_,
+ &bytes_sent, MOJO_WRITE_DATA_FLAG_NONE);
+ switch (result) {
+ case MOJO_RESULT_OK:
+ break;
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // The pipe is closed unexpectedly, finish writing now.
+ draining_ = false;
+ Finish();
+ return;
+ case MOJO_RESULT_SHOULD_WAIT:
+ writable_watcher_.ArmOrNotify();
+ return;
+ default:
+ NOTREACHED();
+ return;
+ }
+ // We've sent |bytes_sent| bytes, update the current offset in the
+ // frontmost chunk.
+ offset_in_current_chunk_ += bytes_sent;
+ DCHECK_LE(offset_in_current_chunk_, current_chunk.size());
+ if (offset_in_current_chunk_ == current_chunk.size()) {
+ // We've finished writing the chunk at the front of the queue, pop it so
+ // that we'll write the next chunk next time.
+ buffered_body_.pop();
+ offset_in_current_chunk_ = 0;
+ }
+ }
+ // We're finished if we've drained the original pipe and sent all the
+ // buffered body.
+ if (!draining_)
+ Finish();
+ }
+
+ void Finish() {
+ DCHECK(!draining_);
+ // We've read and written all the data from the original pipe.
+ writable_watcher_.Cancel();
+ writable_.reset();
+ // There might be a deferred OnComplete message waiting for us to finish
+ // draining the response body, so flush the deferred messages in
+ // the owner MojoURLLoaderClient.
+ owner_->FlushDeferredMessages();
+ }
+
+ MojoURLLoaderClient* const owner_;
+ mojo::ScopedDataPipeProducerHandle writable_;
+ mojo::SimpleWatcher writable_watcher_;
+ std::unique_ptr<mojo::DataPipeDrainer> pipe_drainer_;
+ // We save the received response body as a queue of chunks so that we can free
+ // memory as soon as we finish sending a chunk completely.
+ base::queue<std::vector<char>> buffered_body_;
+ uint32_t offset_in_current_chunk_ = 0;
+ size_t total_bytes_drained_ = 0;
+ const size_t max_bytes_drained_;
+ bool draining_ = true;
+};
+
+MojoURLLoaderClient::MojoURLLoaderClient(
+ WebResourceRequestSender* resource_request_sender,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ bool bypass_redirect_checks,
+ const GURL& request_url,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
+ : back_forward_cache_timeout_(
+ base::TimeDelta::FromSeconds(GetLoadingTasksUnfreezableParamAsInt(
+ "grace_period_to_finish_loading_in_seconds",
+ static_cast<int>(
+ kGracePeriodToFinishLoadingWhileInBackForwardCache
+ .InSeconds())))),
+ resource_request_sender_(resource_request_sender),
+ task_runner_(std::move(task_runner)),
+ bypass_redirect_checks_(bypass_redirect_checks),
+ last_loaded_url_(request_url),
+ back_forward_cache_loader_helper_(back_forward_cache_loader_helper) {}
+
+MojoURLLoaderClient::~MojoURLLoaderClient() = default;
+
+void MojoURLLoaderClient::SetDefersLoading(WebURLLoader::DeferType value) {
+ deferred_state_ = value;
+ if (value == WebURLLoader::DeferType::kNotDeferred) {
+ StopBackForwardCacheEvictionTimer();
+ task_runner_->PostTask(
+ FROM_HERE, WTF::Bind(&MojoURLLoaderClient::FlushDeferredMessages,
+ weak_factory_.GetWeakPtr()));
+ } else if (IsDeferredWithBackForwardCache() && !has_received_complete_ &&
+ !back_forward_cache_eviction_timer_.IsRunning()) {
+ // We should evict the page associated with this load if the connection
+ // takes too long until it either finished or failed.
+ back_forward_cache_eviction_timer_.SetTaskRunner(task_runner_);
+ back_forward_cache_eviction_timer_.Start(
+ FROM_HERE, back_forward_cache_timeout_,
+ WTF::Bind(&MojoURLLoaderClient::EvictFromBackForwardCacheDueToTimeout,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void MojoURLLoaderClient::OnReceiveResponse(
+ network::mojom::URLResponseHeadPtr response_head) {
+ TRACE_EVENT1("loading", "MojoURLLoaderClient::OnReceiveResponse", "url",
+ last_loaded_url_.GetString().Utf8());
+
+ has_received_response_head_ = true;
+ on_receive_response_time_ = base::TimeTicks::Now();
+
+ if (NeedsStoringMessage()) {
+ StoreAndDispatch(
+ std::make_unique<DeferredOnReceiveResponse>(std::move(response_head)));
+ } else {
+ resource_request_sender_->OnReceivedResponse(std::move(response_head));
+ }
+}
+
+BackForwardCacheLoaderHelper*
+MojoURLLoaderClient::GetBackForwardCacheLoaderHelper() {
+ return back_forward_cache_loader_helper_.GetBackForwardCacheLoaderHelper();
+}
+
+void MojoURLLoaderClient::EvictFromBackForwardCache(
+ blink::mojom::RendererEvictionReason reason) {
+ StopBackForwardCacheEvictionTimer();
+ auto* back_forward_cache_loader_helper = GetBackForwardCacheLoaderHelper();
+ if (!back_forward_cache_loader_helper)
+ return;
+ back_forward_cache_loader_helper->EvictFromBackForwardCache(reason);
+}
+
+void MojoURLLoaderClient::DidBufferLoadWhileInBackForwardCache(
+ size_t num_bytes) {
+ auto* back_forward_cache_loader_helper = GetBackForwardCacheLoaderHelper();
+ if (!back_forward_cache_loader_helper)
+ return;
+ back_forward_cache_loader_helper->DidBufferLoadWhileInBackForwardCache(
+ num_bytes);
+}
+
+bool MojoURLLoaderClient::CanContinueBufferingWhileInBackForwardCache() {
+ auto* back_forward_cache_loader_helper = GetBackForwardCacheLoaderHelper();
+ if (!back_forward_cache_loader_helper)
+ return false;
+ return back_forward_cache_loader_helper
+ ->CanContinueBufferingWhileInBackForwardCache();
+}
+
+void MojoURLLoaderClient::EvictFromBackForwardCacheDueToTimeout() {
+ EvictFromBackForwardCache(
+ blink::mojom::RendererEvictionReason::kNetworkRequestTimeout);
+}
+
+void MojoURLLoaderClient::StopBackForwardCacheEvictionTimer() {
+ back_forward_cache_eviction_timer_.Stop();
+}
+
+void MojoURLLoaderClient::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr response_head) {
+ DCHECK(!has_received_response_head_);
+ if (deferred_state_ ==
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
+ EvictFromBackForwardCache(
+ blink::mojom::RendererEvictionReason::kNetworkRequestRedirected);
+
+ OnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+ return;
+ }
+ if (!bypass_redirect_checks_ &&
+ !Platform::Current()->IsRedirectSafe(last_loaded_url_,
+ redirect_info.new_url)) {
+ OnComplete(network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT));
+ return;
+ }
+
+ last_loaded_url_ = KURL(redirect_info.new_url);
+ if (NeedsStoringMessage()) {
+ StoreAndDispatch(std::make_unique<DeferredOnReceiveRedirect>(
+ redirect_info, std::move(response_head), task_runner_));
+ } else {
+ resource_request_sender_->OnReceivedRedirect(
+ redirect_info, std::move(response_head), task_runner_);
+ }
+}
+
+void MojoURLLoaderClient::OnUploadProgress(
+ int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) {
+ if (NeedsStoringMessage()) {
+ StoreAndDispatch(std::make_unique<DeferredOnUploadProgress>(
+ current_position, total_size));
+ } else {
+ resource_request_sender_->OnUploadProgress(current_position, total_size);
+ }
+ std::move(ack_callback).Run();
+}
+
+void MojoURLLoaderClient::OnReceiveCachedMetadata(mojo_base::BigBuffer data) {
+ if (NeedsStoringMessage()) {
+ StoreAndDispatch(
+ std::make_unique<DeferredOnReceiveCachedMetadata>(std::move(data)));
+ } else {
+ resource_request_sender_->OnReceivedCachedMetadata(std::move(data));
+ }
+}
+
+void MojoURLLoaderClient::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+ if (NeedsStoringMessage()) {
+ accumulated_transfer_size_diff_during_deferred_ += transfer_size_diff;
+ } else {
+ resource_request_sender_->OnTransferSizeUpdated(transfer_size_diff);
+ }
+}
+
+void MojoURLLoaderClient::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ TRACE_EVENT1("loading", "MojoURLLoaderClient::OnStartLoadingResponseBody",
+ "url", last_loaded_url_.GetString().Utf8());
+
+ DCHECK(has_received_response_head_);
+ DCHECK(!has_received_response_body_);
+ has_received_response_body_ = true;
+
+ if (!on_receive_response_time_.is_null()) {
+ UMA_HISTOGRAM_TIMES(
+ "Renderer.OnReceiveResponseToOnStartLoadingResponseBody",
+ base::TimeTicks::Now() - on_receive_response_time_);
+ }
+
+ if (!NeedsStoringMessage()) {
+ // Send the message immediately.
+ resource_request_sender_->OnStartLoadingResponseBody(std::move(body));
+ return;
+ }
+
+ if (deferred_state_ !=
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
+ // Defer the message, storing the original body pipe.
+ StoreAndDispatch(
+ std::make_unique<DeferredOnStartLoadingResponseBody>(std::move(body)));
+ return;
+ }
+
+ DCHECK(IsInflightNetworkRequestBackForwardCacheSupportEnabled());
+ // We want to run loading tasks while deferred (but without dispatching the
+ // messages). Drain the original pipe containing the response body into a
+ // new pipe so that we won't block the network service if we're deferred for
+ // a long time.
+ mojo::ScopedDataPipeProducerHandle new_body_producer;
+ mojo::ScopedDataPipeConsumerHandle new_body_consumer;
+ MojoResult result =
+ mojo::CreateDataPipe(nullptr, new_body_producer, new_body_consumer);
+ if (result != MOJO_RESULT_OK) {
+ OnComplete(
+ network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
+ return;
+ }
+ body_buffer_ = std::make_unique<BodyBuffer>(
+ this, std::move(body), std::move(new_body_producer), task_runner_);
+
+ StoreAndDispatch(std::make_unique<DeferredOnStartLoadingResponseBody>(
+ std::move(new_body_consumer)));
+}
+
+void MojoURLLoaderClient::OnComplete(
+ const network::URLLoaderCompletionStatus& status) {
+ has_received_complete_ = true;
+ StopBackForwardCacheEvictionTimer();
+
+ // Dispatch completion status to the WebResourceRequestSender.
+ // Except for errors, there must always be a response's body.
+ DCHECK(has_received_response_body_ || status.error_code != net::OK);
+ if (NeedsStoringMessage()) {
+ StoreAndDispatch(std::make_unique<DeferredOnComplete>(status));
+ } else {
+ resource_request_sender_->OnRequestComplete(status);
+ }
+}
+
+bool MojoURLLoaderClient::NeedsStoringMessage() const {
+ return deferred_state_ != WebURLLoader::DeferType::kNotDeferred ||
+ deferred_messages_.size() > 0 ||
+ accumulated_transfer_size_diff_during_deferred_ > 0;
+}
+
+void MojoURLLoaderClient::StoreAndDispatch(
+ std::unique_ptr<DeferredMessage> message) {
+ DCHECK(NeedsStoringMessage());
+ if (deferred_state_ != WebURLLoader::DeferType::kNotDeferred) {
+ deferred_messages_.emplace_back(std::move(message));
+ } else if (deferred_messages_.size() > 0 ||
+ accumulated_transfer_size_diff_during_deferred_ > 0) {
+ deferred_messages_.emplace_back(std::move(message));
+ FlushDeferredMessages();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void MojoURLLoaderClient::OnConnectionClosed() {
+ // If the connection aborts before the load completes, mark it as aborted.
+ if (!has_received_complete_) {
+ OnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+ return;
+ }
+}
+
+void MojoURLLoaderClient::FlushDeferredMessages() {
+ if (deferred_state_ != WebURLLoader::DeferType::kNotDeferred)
+ return;
+ WebVector<std::unique_ptr<DeferredMessage>> messages;
+ messages.Swap(deferred_messages_);
+ bool has_completion_message = false;
+ base::WeakPtr<MojoURLLoaderClient> weak_this = weak_factory_.GetWeakPtr();
+ // First, dispatch all messages excluding the followings:
+ // - transfer size change
+ // - completion
+ // These two types of messages are dispatched later.
+ for (size_t index = 0; index < messages.size(); ++index) {
+ if (messages[index]->IsCompletionMessage()) {
+ // The completion message arrives at the end of the message queue.
+ DCHECK(!has_completion_message);
+ DCHECK_EQ(index, messages.size() - 1);
+ has_completion_message = true;
+ break;
+ }
+
+ messages[index]->HandleMessage(resource_request_sender_);
+ if (!weak_this)
+ return;
+ if (deferred_state_ != WebURLLoader::DeferType::kNotDeferred) {
+ deferred_messages_.reserve(messages.size() - index - 1);
+ for (size_t i = index + 1; i < messages.size(); ++i)
+ deferred_messages_.emplace_back(std::move(messages[i]));
+ return;
+ }
+ }
+
+ // Dispatch the transfer size update.
+ if (accumulated_transfer_size_diff_during_deferred_ > 0) {
+ auto transfer_size_diff = accumulated_transfer_size_diff_during_deferred_;
+ accumulated_transfer_size_diff_during_deferred_ = 0;
+ resource_request_sender_->OnTransferSizeUpdated(transfer_size_diff);
+ if (!weak_this)
+ return;
+ if (deferred_state_ != WebURLLoader::DeferType::kNotDeferred) {
+ if (has_completion_message) {
+ DCHECK_GT(messages.size(), 0u);
+ DCHECK(messages.back()->IsCompletionMessage());
+ deferred_messages_.emplace_back(std::move(messages.back()));
+ }
+ return;
+ }
+ }
+
+ // Dispatch the completion message.
+ if (has_completion_message) {
+ DCHECK_GT(messages.size(), 0u);
+ DCHECK(messages.back()->IsCompletionMessage());
+ if (body_buffer_ && body_buffer_->active()) {
+ // If we still have an active body buffer, it means we haven't drained all
+ // of the contents of the response body yet. We shouldn't dispatch the
+ // completion message now, so
+ // put the message back into |deferred_messages_| to be sent later after
+ // the body buffer is no longer active.
+ deferred_messages_.emplace_back(std::move(messages.back()));
+ return;
+ }
+ messages.back()->HandleMessage(resource_request_sender_);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h
new file mode 100644
index 00000000000..d2386cda8c2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h
@@ -0,0 +1,128 @@
+// 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_PLATFORM_LOADER_FETCH_URL_LOADER_MOJO_URL_LOADER_CLIENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_MOJO_URL_LOADER_CLIENT_H_
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-forward.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace net {
+struct RedirectInfo;
+} // namespace net
+
+namespace network {
+struct URLLoaderCompletionStatus;
+} // namespace network
+
+namespace blink {
+class BackForwardCacheLoaderHelper;
+class WebResourceRequestSender;
+
+// MojoURLLoaderClient is an implementation of
+// network::mojom::URLLoaderClient to receive messages from a single URLLoader.
+class BLINK_PLATFORM_EXPORT MojoURLLoaderClient final
+ : public network::mojom::URLLoaderClient {
+ public:
+ MojoURLLoaderClient(
+ WebResourceRequestSender* resource_request_sender,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ bool bypass_redirect_checks,
+ const GURL& request_url,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper);
+ ~MojoURLLoaderClient() override;
+
+ // Set the defer status. If loading is deferred, received messages are not
+ // dispatched to clients until it is set not deferred.
+ void SetDefersLoading(WebURLLoader::DeferType value);
+
+ // network::mojom::URLLoaderClient implementation
+ void OnReceiveResponse(
+ network::mojom::URLResponseHeadPtr response_head) override;
+ void OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr response_head) override;
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) override;
+ void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+ void EvictFromBackForwardCache(blink::mojom::RendererEvictionReason reason);
+ void DidBufferLoadWhileInBackForwardCache(size_t num_bytes);
+ bool CanContinueBufferingWhileInBackForwardCache();
+ bool IsDeferredWithBackForwardCache() {
+ return deferred_state_ ==
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache;
+ }
+
+ private:
+ class BodyBuffer;
+ class DeferredMessage;
+ class DeferredOnReceiveResponse;
+ class DeferredOnReceiveRedirect;
+ class DeferredOnUploadProgress;
+ class DeferredOnReceiveCachedMetadata;
+ class DeferredOnStartLoadingResponseBody;
+ class DeferredOnComplete;
+
+ bool NeedsStoringMessage() const;
+ void StoreAndDispatch(std::unique_ptr<DeferredMessage> message);
+ void OnConnectionClosed();
+ const KURL& last_loaded_url() const { return last_loaded_url_; }
+
+ // Dispatches the messages received after SetDefersLoading is called.
+ void FlushDeferredMessages();
+
+ void EvictFromBackForwardCacheDueToTimeout();
+ void StopBackForwardCacheEvictionTimer();
+ BackForwardCacheLoaderHelper* GetBackForwardCacheLoaderHelper();
+
+ WebVector<std::unique_ptr<DeferredMessage>> deferred_messages_;
+ std::unique_ptr<BodyBuffer> body_buffer_;
+ base::OneShotTimer back_forward_cache_eviction_timer_;
+ base::TimeDelta back_forward_cache_timeout_;
+ bool has_received_response_head_ = false;
+ bool has_received_response_body_ = false;
+ bool has_received_complete_ = false;
+ WebURLLoader::DeferType deferred_state_ =
+ WebURLLoader::DeferType::kNotDeferred;
+ int32_t accumulated_transfer_size_diff_during_deferred_ = 0;
+ WebResourceRequestSender* const resource_request_sender_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ bool bypass_redirect_checks_ = false;
+ KURL last_loaded_url_;
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper_;
+
+ // For UMA.
+ base::TimeTicks on_receive_response_time_;
+
+ base::WeakPtrFactory<MojoURLLoaderClient> weak_factory_{this};
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_MOJO_URL_LOADER_CLIENT_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client_unittest.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client_unittest.cc
new file mode 100644
index 00000000000..caad3c87d67
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client_unittest.cc
@@ -0,0 +1,898 @@
+// 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/platform/loader/fetch/url_loader/mojo_url_loader_client.h"
+
+#include <vector>
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/loader/throttling_url_loader.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+namespace blink {
+
+namespace {
+
+constexpr size_t kDataPipeCapacity = 4096;
+
+class MockWebResourceRequestSender : public WebResourceRequestSender {
+ public:
+ struct Context;
+ MockWebResourceRequestSender() : context_(new Context()) {}
+ ~MockWebResourceRequestSender() override = default;
+
+ void OnUploadProgress(int64_t position, int64_t size) override {
+ EXPECT_FALSE(context_->complete);
+ }
+
+ void OnReceivedRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
+ EXPECT_FALSE(context_->cancelled);
+ EXPECT_FALSE(context_->complete);
+ ++context_->seen_redirects;
+ context_->last_load_timing = head->load_timing;
+ if (context_->defer_on_redirect) {
+ context_->url_laoder_client->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferred);
+ }
+ }
+
+ void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override {
+ EXPECT_FALSE(context_->cancelled);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ context_->received_response = true;
+ context_->last_load_timing = head->load_timing;
+ if (context_->cancel_on_receive_response)
+ context_->cancelled = true;
+ }
+
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override {
+ if (context_->cancelled)
+ return;
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ context_->body_handle = std::move(body);
+ }
+
+ void OnTransferSizeUpdated(int transfer_size_diff) override {
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ if (context_->cancelled)
+ return;
+ context_->total_encoded_data_length += transfer_size_diff;
+ if (context_->defer_on_transfer_size_updated) {
+ context_->url_laoder_client->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferred);
+ }
+ }
+
+ void OnReceivedCachedMetadata(mojo_base::BigBuffer data) override {
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ if (context_->cancelled)
+ return;
+ context_->cached_metadata = std::move(data);
+ }
+
+ void OnRequestComplete(
+ const network::URLLoaderCompletionStatus& status) override {
+ if (context_->cancelled)
+ return;
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ context_->complete = true;
+ context_->completion_status = status;
+ }
+
+ Context* context() { return context_.get(); }
+
+ struct Context final {
+ Context() = default;
+ ~Context() = default;
+ Context(const Context&) = delete;
+ Context& operator=(const Context&) = delete;
+
+ // True if should follow redirects, false if should cancel them.
+ bool follow_redirects = true;
+ // True if the request should be deferred on redirects.
+ bool defer_on_redirect = false;
+
+ // Number of total redirects seen.
+ int seen_redirects = 0;
+
+ bool cancel_on_receive_response = false;
+ bool cancel_on_receive_data = false;
+ bool received_response = false;
+
+ mojo_base::BigBuffer cached_metadata;
+ // Data received. If downloading to file, remains empty.
+ std::string data;
+
+ // Mojo's data pipe passed on OnStartLoadingResponseBody.
+ mojo::ScopedDataPipeConsumerHandle body_handle;
+
+ // Total encoded data length, regardless of whether downloading to a file or
+ // not.
+ int total_encoded_data_length = 0;
+ bool defer_on_transfer_size_updated = false;
+
+ bool complete = false;
+ bool cancelled = false;
+ int request_id = -1;
+
+ net::LoadTimingInfo last_load_timing;
+ network::URLLoaderCompletionStatus completion_status;
+ MojoURLLoaderClient* url_laoder_client;
+ };
+
+ private:
+ std::unique_ptr<Context> context_;
+};
+
+std::string ReadOneChunk(mojo::ScopedDataPipeConsumerHandle* handle) {
+ char buffer[kDataPipeCapacity];
+ uint32_t read_bytes = kDataPipeCapacity;
+ MojoResult result =
+ (*handle)->ReadData(buffer, &read_bytes, MOJO_READ_DATA_FLAG_NONE);
+ if (result != MOJO_RESULT_OK)
+ return "";
+ return std::string(buffer, read_bytes);
+}
+
+std::string GetRequestPeerContextBody(
+ MockWebResourceRequestSender::Context* context) {
+ if (context->body_handle) {
+ context->data += ReadOneChunk(&context->body_handle);
+ }
+ return context->data;
+}
+
+class TestBackForwardCacheLoaderHelper : public BackForwardCacheLoaderHelper {
+ public:
+ TestBackForwardCacheLoaderHelper() = default;
+
+ bool CanContinueBufferingWhileInBackForwardCache() const override {
+ return true;
+ }
+};
+
+} // namespace
+
+class WebMojoURLLoaderClientTest : public ::testing::Test,
+ public network::mojom::URLLoaderFactory,
+ public ::testing::WithParamInterface<bool> {
+ protected:
+ WebMojoURLLoaderClientTest()
+ : resource_request_sender_(new MockWebResourceRequestSender()) {
+ if (DeferWithBackForwardCacheEnabled()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ blink::features::kLoadingTasksUnfreezable);
+ }
+
+ WebRuntimeFeatures::EnableBackForwardCache(
+ DeferWithBackForwardCacheEnabled());
+
+ auto url_loader_factory =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(this);
+ auto request = std::make_unique<network::ResourceRequest>();
+ auto loading_task_runner =
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting();
+
+ client_ = std::make_unique<MojoURLLoaderClient>(
+ resource_request_sender_.get(), loading_task_runner,
+ url_loader_factory->BypassRedirectChecks(), request->url,
+ WebBackForwardCacheLoaderHelper(
+ MakeGarbageCollected<TestBackForwardCacheLoaderHelper>()));
+ context_ = resource_request_sender_->context();
+ context_->url_laoder_client = client_.get();
+ url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
+ std::move(url_loader_factory),
+ std::vector<std::unique_ptr<blink::URLLoaderThrottle>>(),
+ /*routing_id=*/0, request_id_, /*loader_options=0*/ 0, request.get(),
+ client_.get(), TRAFFIC_ANNOTATION_FOR_TESTS,
+ std::move(loading_task_runner),
+ base::make_optional(std::vector<std::string>()));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(url_loader_client_);
+ }
+
+ bool DeferWithBackForwardCacheEnabled() { return GetParam(); }
+
+ void TearDown() override { url_loader_client_.reset(); }
+
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
+ override {
+ url_loader_client_.Bind(std::move(client));
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
+ override {
+ NOTREACHED();
+ }
+
+ static MojoCreateDataPipeOptions DataPipeOptions() {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = kDataPipeCapacity;
+ return options;
+ }
+
+ class TestPlatform final : public TestingPlatformSupport {
+ public:
+ bool IsRedirectSafe(const GURL& from_url, const GURL& to_url) override {
+ return true;
+ }
+ };
+
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ ScopedTestingPlatformSupport<TestPlatform> platform_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ std::unique_ptr<ThrottlingURLLoader> url_loader_;
+ std::unique_ptr<MojoURLLoaderClient> client_;
+ std::unique_ptr<MockWebResourceRequestSender> resource_request_sender_;
+ MockWebResourceRequestSender::Context* context_;
+ int request_id_ = 0;
+ mojo::Remote<network::mojom::URLLoaderClient> url_loader_client_;
+};
+
+TEST_P(WebMojoURLLoaderClientTest, OnReceiveResponse) {
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+
+ EXPECT_FALSE(context_->received_response);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, ResponseBody) {
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+
+ EXPECT_FALSE(context_->received_response);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ uint32_t size = 5;
+ MojoResult result =
+ data_pipe_producer->WriteData("hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_EQ(5u, size);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest, OnReceiveRedirect) {
+ net::RedirectInfo redirect_info;
+
+ url_loader_client_->OnReceiveRedirect(redirect_info,
+ network::mojom::URLResponseHead::New());
+
+ EXPECT_EQ(0, context_->seen_redirects);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, context_->seen_redirects);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, OnReceiveCachedMetadata) {
+ std::vector<uint8_t> data;
+ data.push_back('a');
+ mojo_base::BigBuffer metadata(data);
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ url_loader_client_->OnReceiveCachedMetadata(std::move(metadata));
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_EQ(0u, context_->cached_metadata.size());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ ASSERT_EQ(1u, context_->cached_metadata.size());
+ EXPECT_EQ('a', context_->cached_metadata.data()[0]);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, OnTransferSizeUpdated) {
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ url_loader_client_->OnTransferSizeUpdated(4);
+ url_loader_client_->OnTransferSizeUpdated(4);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_EQ(8, context_->total_encoded_data_length);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, OnCompleteWithResponseBody) {
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ uint32_t size = 5;
+ MojoResult result =
+ data_pipe_producer->WriteData("hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_EQ(5u, size);
+ data_pipe_producer.reset();
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->complete);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+ EXPECT_TRUE(context_->complete);
+}
+
+// Due to the lack of ordering guarantee, it is possible that the response body
+// bytes arrives after the completion message. URLLoaderClientImpl should
+// restore the order.
+TEST_P(WebMojoURLLoaderClientTest, OnCompleteShouldBeTheLastMessage) {
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnComplete(status);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+
+ uint32_t size = 5;
+ MojoResult result =
+ data_pipe_producer->WriteData("hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_EQ(5u, size);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest, CancelOnReceiveResponse) {
+ context_->cancel_on_receive_response = true;
+
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_FALSE(context_->cancelled);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_TRUE(context_->cancelled);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, Defer) {
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ data_pipe_producer.reset(); // Empty body.
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, DeferWithResponseBody) {
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ std::string msg1 = "hello";
+ uint32_t size = msg1.size();
+ ASSERT_EQ(MOJO_RESULT_OK, data_pipe_producer->WriteData(
+ msg1.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg1.size(), size);
+ data_pipe_producer.reset();
+
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest,
+ DeferredAndDeferredWithBackForwardCacheTransitions) {
+ if (!DeferWithBackForwardCacheEnabled())
+ return;
+ // Call OnReceiveResponse and OnStartLoadingResponseBody while
+ // deferred (not for back-forward cache).
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Write data to the response body pipe.
+ std::string msg1 = "he";
+ uint32_t size = msg1.size();
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg1.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg1.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Defer for back-forward cache.
+ client_->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+ std::string msg2 = "ll";
+ size = msg2.size();
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg2.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg2.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Defer not for back-forward cache again.
+ client_->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+ std::string msg3 = "o";
+ size = msg3.size();
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg3.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg3.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Stop deferring.
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+
+ // Write more data to the pipe while not deferred.
+ std::string msg4 = "world";
+ size = msg4.size();
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg4.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg4.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("helloworld", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest,
+ DeferredWithBackForwardCacheStoppedDeferringBeforeClosing) {
+ if (!DeferWithBackForwardCacheEnabled())
+ return;
+ // Call OnReceiveResponse, OnStartLoadingResponseBody, OnComplete while
+ // deferred.
+ client_->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
+ network::URLLoaderCompletionStatus status;
+ url_loader_client_->OnComplete(status);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Write data to the response body pipe, but don't close the connection yet.
+ std::string msg1 = "hello";
+ uint32_t size = msg1.size();
+ // We expect that the other end of the pipe to be ready to read the data
+ // immediately.
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg1.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg1.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Stop deferring. OnComplete message shouldn't be dispatched yet because
+ // we're still waiting for the response body pipe to be closed.
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ // When the body is buffered, we'll wait until the pipe is closed before
+ // sending the OnComplete message.
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+
+ // Write more data to the pipe while not deferred.
+ std::string msg2 = "world";
+ size = msg2.size();
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg2.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg2.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("helloworld", GetRequestPeerContextBody(context_));
+
+ // Close the response body pipe.
+ producer_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+ EXPECT_EQ("helloworld", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest, DeferBodyWithoutOnComplete) {
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ // Call OnStartLoadingResponseBody while deferred.
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Write data to the response body pipe, but don't close the connection yet.
+ std::string msg1 = "hello";
+ uint32_t size = msg1.size();
+ // We expect that the other end of the pipe to be ready to read the data
+ // immediately.
+ ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+ msg1.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(msg1.size(), size);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Stop deferring.
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+
+ // Close the response body pipe.
+ producer_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+}
+
+TEST_P(WebMojoURLLoaderClientTest,
+ DeferredWithBackForwardCacheLongResponseBody) {
+ if (!DeferWithBackForwardCacheEnabled())
+ return;
+ // Call OnReceiveResponse, OnStartLoadingResponseBody, OnComplete while
+ // deferred.
+ client_->SetDefersLoading(
+ blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle));
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
+ network::URLLoaderCompletionStatus status;
+ url_loader_client_->OnComplete(status);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+
+ // Write to the response body pipe. It will take several writes.
+ const uint32_t body_size = 70000;
+ uint32_t bytes_remaining = body_size;
+ std::string body(body_size, '*');
+ while (bytes_remaining > 0) {
+ uint32_t start_position = body_size - bytes_remaining;
+ uint32_t bytes_sent = bytes_remaining;
+ MojoResult result = producer_handle->WriteData(
+ body.c_str() + start_position, &bytes_sent, MOJO_WRITE_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ // When we buffer the body the pipe gets drained asynchronously, so it's
+ // possible to keep writing to the pipe if we wait.
+ base::RunLoop().RunUntilIdle();
+ continue;
+ }
+ EXPECT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_GE(bytes_remaining, bytes_sent);
+ bytes_remaining -= bytes_sent;
+ }
+ // Ensure we've written all that we can write. When buffering is disabled, we
+ // can only write |body_size| - |bytes_remaining| bytes.
+ const uint32_t bytes_written = body_size - bytes_remaining;
+ EXPECT_EQ(body_size, bytes_written);
+ producer_handle.reset();
+
+ // Stop deferring.
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ // When the body is buffered, BodyBuffer shouldn't be finished writing to the
+ // new response body pipe at this point (because nobody is reading it).
+ EXPECT_FALSE(context_->complete);
+
+ // Calling GetRequestPeerContextBody to read data from the new response body
+ // pipe will make BodyBuffer write the rest of the body to the pipe.
+ uint32_t bytes_read = 0;
+ while (bytes_read < bytes_written) {
+ bytes_read = GetRequestPeerContextBody(context_).size();
+ base::RunLoop().RunUntilIdle();
+ }
+ // Ensure that we've read everything we've written.
+ EXPECT_EQ(bytes_written, bytes_read);
+ EXPECT_EQ(body, GetRequestPeerContextBody(context_));
+ EXPECT_TRUE(context_->complete);
+}
+
+// As "transfer size update" message is handled specially in the implementation,
+// we have a separate test.
+TEST_P(WebMojoURLLoaderClientTest, DeferWithTransferSizeUpdated) {
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ uint32_t size = 5;
+ MojoResult result =
+ data_pipe_producer->WriteData("hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_EQ(5u, size);
+ data_pipe_producer.reset();
+
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnTransferSizeUpdated(4);
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(4, context_->total_encoded_data_length);
+}
+
+TEST_P(WebMojoURLLoaderClientTest, SetDeferredDuringFlushingDeferredMessage) {
+ context_->defer_on_redirect = true;
+
+ net::RedirectInfo redirect_info;
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveRedirect(redirect_info,
+ network::mojom::URLResponseHead::New());
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ uint32_t size = 5;
+ MojoResult result =
+ data_pipe_producer->WriteData("hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(MOJO_RESULT_OK, result);
+ EXPECT_EQ(5u, size);
+ data_pipe_producer.reset();
+
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+ url_loader_client_->OnTransferSizeUpdated(4);
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_EQ(0, context_->seen_redirects);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, context_->seen_redirects);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ EXPECT_EQ(0, context_->seen_redirects);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, context_->seen_redirects);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ("", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+ EXPECT_FALSE(context_->cancelled);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, context_->seen_redirects);
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+ EXPECT_EQ("hello", GetRequestPeerContextBody(context_));
+ EXPECT_EQ(4, context_->total_encoded_data_length);
+ EXPECT_FALSE(context_->cancelled);
+}
+
+TEST_P(WebMojoURLLoaderClientTest,
+ SetDeferredDuringFlushingDeferredMessageOnTransferSizeUpdated) {
+ context_->defer_on_transfer_size_updated = true;
+
+ network::URLLoaderCompletionStatus status;
+
+ url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+ MojoCreateDataPipeOptions options = DataPipeOptions();
+ mojo::ScopedDataPipeProducerHandle data_pipe_producer;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&options, data_pipe_producer,
+ data_pipe_consumer));
+ data_pipe_producer.reset(); // Empty body.
+ url_loader_client_->OnStartLoadingResponseBody(std::move(data_pipe_consumer));
+
+ url_loader_client_->OnTransferSizeUpdated(4);
+ url_loader_client_->OnComplete(status);
+
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kDeferred);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ EXPECT_FALSE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ(0, context_->total_encoded_data_length);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_FALSE(context_->complete);
+ EXPECT_EQ(4, context_->total_encoded_data_length);
+ EXPECT_FALSE(context_->cancelled);
+
+ client_->SetDefersLoading(blink::WebURLLoader::DeferType::kNotDeferred);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->received_response);
+ EXPECT_TRUE(context_->complete);
+ EXPECT_EQ(4, context_->total_encoded_data_length);
+ EXPECT_FALSE(context_->cancelled);
+}
+
+INSTANTIATE_TEST_SUITE_P(All, WebMojoURLLoaderClientTest, ::testing::Bool());
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
index fb258384b40..47dae6851d3 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
@@ -8,6 +8,7 @@
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/load_flags.h"
#include "net/base/request_priority.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
@@ -19,10 +20,10 @@
#include "services/network/public/mojom/data_pipe_getter.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -35,19 +36,13 @@
namespace blink {
-const char* ImageAcceptHeader() {
- static constexpr char kImageAcceptHeaderWithAvif[] =
- "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
- static constexpr size_t kOffset = sizeof("image/avif,") - 1;
#if BUILDFLAG(ENABLE_AV1_DECODER)
- static const char* header = base::FeatureList::IsEnabled(features::kAVIF)
- ? kImageAcceptHeaderWithAvif
- : kImageAcceptHeaderWithAvif + kOffset;
+constexpr char kImageAcceptHeader[] =
+ "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
#else
- static const char* header = kImageAcceptHeaderWithAvif + kOffset;
+constexpr char kImageAcceptHeader[] =
+ "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8";
#endif
- return header;
-}
namespace {
@@ -153,6 +148,7 @@ mojom::ResourceType RequestContextToResourceType(
case mojom::blink::RequestContextType::DOWNLOAD:
case mojom::blink::RequestContextType::MANIFEST:
case mojom::blink::RequestContextType::SUBRESOURCE:
+ case mojom::blink::RequestContextType::SUBRESOURCE_WEBBUNDLE:
return mojom::ResourceType::kSubResource;
// TextTrack
@@ -216,26 +212,23 @@ void PopulateResourceRequestBody(const EncodedFormData& src,
break;
case FormDataElement::kEncodedBlob: {
DCHECK(element.optional_blob_data_handle_);
- mojo::Remote<mojom::Blob> blob_remote(mojo::PendingRemote<mojom::Blob>(
- element.optional_blob_data_handle_->CloneBlobRemote().PassPipe(),
- mojom::Blob::Version_));
- mojo::PendingRemote<network::mojom::DataPipeGetter>
+ mojo::Remote<mojom::blink::Blob> blob_remote(
+ element.optional_blob_data_handle_->CloneBlobRemote());
+ mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
data_pipe_getter_remote;
blob_remote->AsDataPipeGetter(
data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
- dest->AppendDataPipe(std::move(data_pipe_getter_remote));
+ dest->AppendDataPipe(
+ ToCrossVariantMojoType(std::move(data_pipe_getter_remote)));
break;
}
case FormDataElement::kDataPipe: {
- // Convert network::mojom::blink::DataPipeGetter to
- // network::mojom::DataPipeGetter through a raw message pipe.
mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
pending_data_pipe_getter;
element.data_pipe_getter_->GetDataPipeGetter()->Clone(
pending_data_pipe_getter.InitWithNewPipeAndPassReceiver());
dest->AppendDataPipe(
- mojo::PendingRemote<network::mojom::DataPipeGetter>(
- pending_data_pipe_getter.PassPipe(), 0u));
+ ToCrossVariantMojoType(std::move(pending_data_pipe_getter)));
break;
}
}
@@ -244,6 +237,27 @@ void PopulateResourceRequestBody(const EncodedFormData& src,
} // namespace
+scoped_refptr<network::ResourceRequestBody> NetworkResourceRequestBodyFor(
+ ResourceRequestBody src_body,
+ bool allow_http1_for_streaming_upload) {
+ scoped_refptr<network::ResourceRequestBody> dest_body;
+ if (const EncodedFormData* form_body = src_body.FormBody().get()) {
+ dest_body = base::MakeRefCounted<network::ResourceRequestBody>();
+
+ PopulateResourceRequestBody(*form_body, dest_body.get());
+ } else if (src_body.StreamBody().is_valid()) {
+ mojo::PendingRemote<network::mojom::blink::ChunkedDataPipeGetter>
+ stream_body = src_body.TakeStreamBody();
+ dest_body = base::MakeRefCounted<network::ResourceRequestBody>();
+ dest_body->SetToChunkedDataPipe(
+ ToCrossVariantMojoType(std::move(stream_body)),
+ network::ResourceRequestBody::ReadOnlyOnce(true));
+ dest_body->SetAllowHTTP1ForStreamingUpload(
+ allow_http1_for_streaming_upload);
+ }
+ return dest_body;
+}
+
void PopulateResourceRequest(const ResourceRequestHead& src,
ResourceRequestBody src_body,
network::ResourceRequest* dest) {
@@ -305,19 +319,24 @@ void PopulateResourceRequest(const ResourceRequestHead& src,
dest->credentials_mode = src.GetCredentialsMode();
dest->redirect_mode = src.GetRedirectMode();
dest->fetch_integrity = src.GetFetchIntegrity().Utf8();
-
- mojom::ResourceType resource_type =
- RequestContextToResourceType(src.GetRequestContext());
+ if (src.GetWebBundleTokenParams().has_value()) {
+ dest->web_bundle_token_params =
+ base::make_optional(network::ResourceRequest::WebBundleTokenParams(
+ src.GetWebBundleTokenParams()->bundle_url,
+ src.GetWebBundleTokenParams()->token,
+ src.GetWebBundleTokenParams()->CloneHandle()));
+ }
// TODO(kinuko): Deprecate this.
- dest->resource_type = static_cast<int>(resource_type);
+ dest->resource_type =
+ static_cast<int>(RequestContextToResourceType(src.GetRequestContext()));
- if (resource_type == mojom::ResourceType::kXhr &&
+ if (src.IsFetchLikeAPI() &&
(dest->url.has_username() || dest->url.has_password())) {
dest->do_not_prompt_for_login = true;
}
- if (resource_type == mojom::ResourceType::kPrefetch ||
- resource_type == mojom::ResourceType::kFavicon) {
+ if (src.GetRequestContext() == mojom::blink::RequestContextType::PREFETCH ||
+ src.IsFavicon()) {
dest->do_not_prompt_for_login = true;
}
@@ -351,32 +370,25 @@ void PopulateResourceRequest(const ResourceRequestHead& src,
dest->is_fetch_like_api = src.IsFetchLikeAPI();
- if (const EncodedFormData* body = src_body.FormBody().get()) {
- DCHECK_NE(dest->method, net::HttpRequestHeaders::kGetMethod);
- DCHECK_NE(dest->method, net::HttpRequestHeaders::kHeadMethod);
- dest->request_body = base::MakeRefCounted<network::ResourceRequestBody>();
+ dest->is_favicon = src.IsFavicon();
- PopulateResourceRequestBody(*body, dest->request_body.get());
- } else if (src_body.StreamBody().is_valid()) {
+ dest->request_body = NetworkResourceRequestBodyFor(
+ std::move(src_body), src.AllowHTTP1ForStreamingUpload());
+ if (dest->request_body) {
DCHECK_NE(dest->method, net::HttpRequestHeaders::kGetMethod);
DCHECK_NE(dest->method, net::HttpRequestHeaders::kHeadMethod);
- mojo::PendingRemote<network::mojom::blink::ChunkedDataPipeGetter>
- stream_body = src_body.TakeStreamBody();
- dest->request_body = base::MakeRefCounted<network::ResourceRequestBody>();
- mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
- network_stream_body(stream_body.PassPipe(), 0u);
- dest->request_body->SetToReadOnceStream(std::move(network_stream_body));
- dest->request_body->SetAllowHTTP1ForStreamingUpload(
- src.AllowHTTP1ForStreamingUpload());
}
- if (resource_type == mojom::ResourceType::kStylesheet) {
+ network::mojom::RequestDestination request_destination =
+ src.GetRequestDestination();
+ if (request_destination == network::mojom::RequestDestination::kStyle ||
+ request_destination == network::mojom::RequestDestination::kXslt) {
dest->headers.SetHeader(net::HttpRequestHeaders::kAccept,
kStylesheetAcceptHeader);
- } else if (resource_type == mojom::ResourceType::kImage ||
- resource_type == mojom::ResourceType::kFavicon) {
+ } else if (request_destination ==
+ network::mojom::RequestDestination::kImage) {
dest->headers.SetHeaderIfMissing(net::HttpRequestHeaders::kAccept,
- ImageAcceptHeader());
+ kImageAcceptHeader);
} else {
// Calling SetHeaderIfMissing() instead of SetHeader() because JS can
// manually set an accept header on an XHR.
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h
index f80cd23c0f2..329b583e5be 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.h
@@ -7,19 +7,25 @@
// This file consists of request conversion functions between blink and network.
+#include "base/memory/ref_counted.h"
#include "third_party/blink/renderer/platform/platform_export.h"
namespace network {
+class ResourceRequestBody;
struct ResourceRequest;
} // namespace network
namespace blink {
-PLATFORM_EXPORT const char* ImageAcceptHeader();
+PLATFORM_EXPORT extern const char kImageAcceptHeader[];
class ResourceRequestHead;
class ResourceRequestBody;
+scoped_refptr<network::ResourceRequestBody> NetworkResourceRequestBodyFor(
+ const ResourceRequestBody src_body,
+ bool allow_http1_for_streaming_upload);
+
void PopulateResourceRequest(const ResourceRequestHead& src,
ResourceRequestBody src_body,
network::ResourceRequest* dest);
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.cc
new file mode 100644
index 00000000000..0cf43dcc510
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.cc
@@ -0,0 +1,335 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/common/client_hints/client_hints.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+// An inner helper class to manage the SyncLoadContext's events and timeouts,
+// so that we can stop or resumse all of them at once.
+class SyncLoadContext::SignalHelper final {
+ public:
+ SignalHelper(SyncLoadContext* context,
+ base::WaitableEvent* redirect_or_response_event,
+ base::WaitableEvent* abort_event,
+ base::TimeDelta timeout)
+ : context_(context),
+ redirect_or_response_event_(redirect_or_response_event),
+ abort_event_(abort_event) {
+ // base::TimeDelta::Max() means no timeout.
+ if (timeout != base::TimeDelta::Max()) {
+ // Instantiate a base::OneShotTimer instance.
+ timeout_timer_.emplace();
+ }
+ Start(timeout);
+ }
+
+ void SignalRedirectOrResponseComplete() {
+ abort_watcher_.StopWatching();
+ if (timeout_timer_)
+ timeout_timer_->AbandonAndStop();
+ redirect_or_response_event_->Signal();
+ }
+
+ bool RestartAfterRedirect() {
+ if (abort_event_ && abort_event_->IsSignaled())
+ return false;
+
+ base::TimeDelta timeout_remainder = base::TimeDelta::Max();
+ if (timeout_timer_) {
+ timeout_remainder =
+ timeout_timer_->desired_run_time() - base::TimeTicks::Now();
+ if (timeout_remainder <= base::TimeDelta())
+ return false;
+ }
+ Start(timeout_remainder);
+ return true;
+ }
+
+ private:
+ void Start(base::TimeDelta timeout) {
+ DCHECK(!redirect_or_response_event_->IsSignaled());
+ if (abort_event_) {
+ abort_watcher_.StartWatching(
+ abort_event_,
+ base::BindOnce(&SyncLoadContext::OnAbort, base::Unretained(context_)),
+ context_->task_runner_);
+ }
+ if (timeout_timer_) {
+ DCHECK_NE(base::TimeDelta::Max(), timeout);
+ timeout_timer_->Start(FROM_HERE, timeout, context_,
+ &SyncLoadContext::OnTimeout);
+ }
+ }
+
+ SyncLoadContext* context_;
+ base::WaitableEvent* redirect_or_response_event_;
+ base::WaitableEvent* abort_event_;
+ base::WaitableEventWatcher abort_watcher_;
+ base::Optional<base::OneShotTimer> timeout_timer_;
+};
+
+// static
+void SyncLoadContext::StartAsyncWithWaitableEvent(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ std::unique_ptr<network::PendingSharedURLLoaderFactory>
+ pending_url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ SyncLoadResponse* response,
+ SyncLoadContext** context_for_redirect,
+ base::WaitableEvent* redirect_or_response_event,
+ base::WaitableEvent* abort_event,
+ base::TimeDelta timeout,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ const WebVector<WebString>& cors_exempt_header_list,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper) {
+ scoped_refptr<SyncLoadContext> context(new SyncLoadContext(
+ request.get(), std::move(pending_url_loader_factory), response,
+ context_for_redirect, redirect_or_response_event, abort_event, timeout,
+ std::move(download_to_blob_registry), loading_task_runner));
+ context->resource_request_sender_->SendAsync(
+ std::move(request), routing_id, std::move(loading_task_runner),
+ traffic_annotation, loader_options, cors_exempt_header_list,
+ context, context->url_loader_factory_, std::move(throttles),
+ std::move(resource_load_info_notifier_wrapper),
+ WebBackForwardCacheLoaderHelper());
+}
+
+SyncLoadContext::SyncLoadContext(
+ network::ResourceRequest* request,
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> url_loader_factory,
+ SyncLoadResponse* response,
+ SyncLoadContext** context_for_redirect,
+ base::WaitableEvent* redirect_or_response_event,
+ base::WaitableEvent* abort_event,
+ base::TimeDelta timeout,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : response_(response),
+ context_for_redirect_(context_for_redirect),
+ body_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ download_to_blob_registry_(std::move(download_to_blob_registry)),
+ task_runner_(std::move(task_runner)),
+ signals_(std::make_unique<SignalHelper>(this,
+ redirect_or_response_event,
+ abort_event,
+ timeout)) {
+ if (download_to_blob_registry_)
+ mode_ = Mode::kBlob;
+
+ url_loader_factory_ =
+ network::SharedURLLoaderFactory::Create(std::move(url_loader_factory));
+
+ // Constructs a new WebResourceRequestSender specifically for this request.
+ resource_request_sender_ = std::make_unique<WebResourceRequestSender>();
+
+ // Initialize the final URL with the original request URL. It will be
+ // overwritten on redirects.
+ response_->url = request->url;
+}
+
+SyncLoadContext::~SyncLoadContext() {}
+
+void SyncLoadContext::OnUploadProgress(uint64_t position, uint64_t size) {}
+
+bool SyncLoadContext::OnReceivedRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>* removed_headers) {
+ DCHECK(!Completed());
+ if (removed_headers) {
+ // TODO(yoav): Get the actual FeaturePolicy here to support selective
+ // removal for sync XHR.
+ FindClientHintsToRemove(nullptr /* feature_policy */, redirect_info.new_url,
+ removed_headers);
+ }
+
+ response_->url = redirect_info.new_url;
+ response_->head = std::move(head);
+ response_->redirect_info = redirect_info;
+ *context_for_redirect_ = this;
+ resource_request_sender_->SetDefersLoading(
+ WebURLLoader::DeferType::kDeferred);
+ signals_->SignalRedirectOrResponseComplete();
+ return true;
+}
+
+void SyncLoadContext::FollowRedirect() {
+ if (!signals_->RestartAfterRedirect()) {
+ CancelRedirect();
+ return;
+ }
+
+ response_->redirect_info = net::RedirectInfo();
+ *context_for_redirect_ = nullptr;
+
+ resource_request_sender_->SetDefersLoading(
+ WebURLLoader::DeferType::kNotDeferred);
+}
+
+void SyncLoadContext::CancelRedirect() {
+ response_->redirect_info = net::RedirectInfo();
+ *context_for_redirect_ = nullptr;
+
+ response_->error_code = net::ERR_ABORTED;
+ CompleteRequest();
+}
+
+void SyncLoadContext::OnReceivedResponse(
+ network::mojom::URLResponseHeadPtr head) {
+ DCHECK(!Completed());
+ response_->head = std::move(head);
+}
+
+void SyncLoadContext::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ if (mode_ == Mode::kBlob) {
+ DCHECK(download_to_blob_registry_);
+ DCHECK(!blob_response_started_);
+
+ blob_response_started_ = true;
+
+ download_to_blob_registry_->RegisterFromStream(
+ response_->head->mime_type, "",
+ std::max<int64_t>(0, response_->head->content_length), std::move(body),
+ mojo::NullAssociatedRemote(),
+ base::BindOnce(&SyncLoadContext::OnFinishCreatingBlob,
+ base::Unretained(this)));
+ return;
+ }
+ DCHECK_EQ(Mode::kInitial, mode_);
+ mode_ = Mode::kDataPipe;
+ // setup datapipe to read.
+ body_handle_ = std::move(body);
+ body_watcher_.Watch(
+ body_handle_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ base::BindRepeating(&SyncLoadContext::OnBodyReadable,
+ base::Unretained(this)));
+ body_watcher_.ArmOrNotify();
+}
+
+void SyncLoadContext::OnTransferSizeUpdated(int transfer_size_diff) {}
+
+void SyncLoadContext::OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) {
+ if (Completed()) {
+ // It means the response has been aborted due to an error before finishing
+ // the response.
+ return;
+ }
+ request_completed_ = true;
+ response_->error_code = status.error_code;
+ response_->extended_error_code = status.extended_error_code;
+ response_->resolve_error_info = status.resolve_error_info;
+ response_->cors_error = status.cors_error_status;
+ response_->head->encoded_data_length = status.encoded_data_length;
+ response_->head->encoded_body_length = status.encoded_body_length;
+ if ((blob_response_started_ && !blob_finished_) || body_handle_.is_valid()) {
+ // The body is still begin downloaded as a Blob, or being read through the
+ // handle. Wait until it's completed.
+ return;
+ }
+ CompleteRequest();
+}
+
+void SyncLoadContext::OnFinishCreatingBlob(mojom::SerializedBlobPtr blob) {
+ DCHECK(!Completed());
+ blob_finished_ = true;
+ response_->downloaded_blob = std::move(blob);
+ if (request_completed_)
+ CompleteRequest();
+}
+
+void SyncLoadContext::OnBodyReadable(MojoResult,
+ const mojo::HandleSignalsState&) {
+ DCHECK_EQ(Mode::kDataPipe, mode_);
+ DCHECK(body_handle_.is_valid());
+ const void* buffer = nullptr;
+ uint32_t read_bytes = 0;
+ MojoResult result = body_handle_->BeginReadData(&buffer, &read_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ body_watcher_.ArmOrNotify();
+ return;
+ }
+ if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+ // Whole body has been read.
+ body_handle_.reset();
+ body_watcher_.Cancel();
+ if (request_completed_)
+ CompleteRequest();
+ return;
+ }
+ if (result != MOJO_RESULT_OK) {
+ // Something went wrong.
+ body_handle_.reset();
+ body_watcher_.Cancel();
+ response_->error_code = net::ERR_FAILED;
+ CompleteRequest();
+ return;
+ }
+
+ response_->data.Append(static_cast<const char*>(buffer), read_bytes);
+ body_handle_->EndReadData(read_bytes);
+ body_watcher_.ArmOrNotify();
+}
+
+void SyncLoadContext::OnAbort(base::WaitableEvent* event) {
+ DCHECK(!Completed());
+ response_->error_code = net::ERR_ABORTED;
+ CompleteRequest();
+}
+
+void SyncLoadContext::OnTimeout() {
+ // OnTimeout() must not be called after CompleteRequest() was called, because
+ // the OneShotTimer must have been stopped.
+ DCHECK(!Completed());
+ response_->error_code = net::ERR_TIMED_OUT;
+ CompleteRequest();
+}
+
+void SyncLoadContext::CompleteRequest() {
+ DCHECK(blob_finished_ || (mode_ != Mode::kBlob));
+ DCHECK(!body_handle_.is_valid());
+ body_watcher_.Cancel();
+ signals_->SignalRedirectOrResponseComplete();
+ signals_ = nullptr;
+ response_ = nullptr;
+
+ // This will indirectly cause this object to be deleted.
+ resource_request_sender_->DeletePendingRequest(task_runner_);
+}
+
+bool SyncLoadContext::Completed() const {
+ DCHECK_EQ(!signals_, !response_);
+ return !response_;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h
new file mode 100644
index 00000000000..7f30c10962e
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h
@@ -0,0 +1,155 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_CONTEXT_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "base/timer/timer.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_request_peer.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace network {
+struct ResourceRequest;
+}
+
+namespace blink {
+class ResourceLoadInfoNotifierWrapper;
+class URLLoaderThrottle;
+struct SyncLoadResponse;
+
+// This class owns the context necessary to perform an asynchronous request
+// while the main thread is blocked so that it appears to be synchronous.
+// There are a couple of modes to load a request:
+// 1) kDataPipe; body is received on a data pipe passed on
+// OnStartLoadingResponseBody(), and the body is set to response_.data.
+// 2) kBlob: body is received on a data pipe passed on
+// OnStartLoadingResponseBody(), and wraps the data pipe with a
+// SerializedBlobPtr.
+class BLINK_PLATFORM_EXPORT SyncLoadContext : public WebRequestPeer {
+ public:
+ // Begins a new asynchronous request on whatever sequence this method is
+ // called on. |completed_event| will be signalled when the request is complete
+ // and |response| will be populated with the response data. |abort_event|
+ // will be signalled from the main thread to abort the sync request on a
+ // worker thread when the worker thread is being terminated.
+ // The pointer whose address is `context_for_redirect` is held by the caller
+ // that is blocked on this method, so it will remain valid until the operation
+ // completes. If there are redirects, `context_for_redirect` will point to the
+ // callee context.
+ // If |download_to_blob_registry| is not null, it is used to
+ // redirect the download to a blob, with the resulting blob populated in
+ // |response|.
+ static void StartAsyncWithWaitableEvent(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ std::unique_ptr<network::PendingSharedURLLoaderFactory>
+ pending_url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ SyncLoadResponse* response,
+ SyncLoadContext** context_for_redirect,
+ base::WaitableEvent* completed_event,
+ base::WaitableEvent* abort_event,
+ base::TimeDelta timeout,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ const WebVector<WebString>& cors_exempt_header_list,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper);
+
+ ~SyncLoadContext() override;
+
+ void FollowRedirect();
+ void CancelRedirect();
+
+ private:
+ friend class SyncLoadContextTest;
+
+ SyncLoadContext(
+ network::ResourceRequest* request,
+ std::unique_ptr<network::PendingSharedURLLoaderFactory>
+ url_loader_factory,
+ SyncLoadResponse* response,
+ SyncLoadContext** context_for_redirect,
+ base::WaitableEvent* completed_event,
+ base::WaitableEvent* abort_event,
+ base::TimeDelta timeout,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ // WebRequestPeer implementation:
+ void OnUploadProgress(uint64_t position, uint64_t size) override;
+ bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>*) override;
+ void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnTransferSizeUpdated(int transfer_size_diff) override;
+ void OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) override;
+ void OnFinishCreatingBlob(mojom::SerializedBlobPtr blob);
+
+ void OnBodyReadable(MojoResult, const mojo::HandleSignalsState&);
+
+ void OnAbort(base::WaitableEvent* event);
+ void OnTimeout();
+
+ void CompleteRequest();
+ bool Completed() const;
+
+ // This raw pointer will remain valid for the lifetime of this object because
+ // it remains on the stack until |event_| is signaled.
+ // Set to null after CompleteRequest() is called.
+ SyncLoadResponse* response_;
+
+ // This raw pointer will be set to `this` when receiving redirects on
+ // independent thread and set to nullptr in `FollowRedirect()` or
+ // `CancelRedirect()` on the same thread after `redirect_or_response_event_`
+ // is signaled, which protects it against race condition.
+ SyncLoadContext** context_for_redirect_;
+
+ enum class Mode { kInitial, kDataPipe, kBlob };
+ Mode mode_ = Mode::kInitial;
+
+ // Used when Mode::kDataPipe.
+ mojo::ScopedDataPipeConsumerHandle body_handle_;
+ mojo::SimpleWatcher body_watcher_;
+
+ // State necessary to run a request on an independent thread.
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender_;
+
+ // State for downloading to a blob.
+ mojo::Remote<mojom::BlobRegistry> download_to_blob_registry_;
+ bool blob_response_started_ = false;
+ bool blob_finished_ = false;
+ bool request_completed_ = false;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ class SignalHelper;
+ std::unique_ptr<SignalHelper> signals_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncLoadContext);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context_unittest.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context_unittest.cc
new file mode 100644
index 00000000000..836fde66b6d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h"
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
+
+namespace blink {
+
+namespace {
+
+class TestSharedURLLoaderFactory : public network::TestURLLoaderFactory,
+ public network::SharedURLLoaderFactory {
+ public:
+ // mojom::URLLoaderFactory implementation.
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
+ override {
+ network::TestURLLoaderFactory::CreateLoaderAndStart(
+ std::move(receiver), routing_id, request_id, options, url_request,
+ std::move(client), traffic_annotation);
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory>) override {
+ NOTREACHED();
+ }
+
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override {
+ NOTREACHED();
+ return nullptr;
+ }
+
+ private:
+ friend class base::RefCounted<TestSharedURLLoaderFactory>;
+ ~TestSharedURLLoaderFactory() override = default;
+};
+
+class MockPendingSharedURLLoaderFactory
+ : public network::PendingSharedURLLoaderFactory {
+ public:
+ explicit MockPendingSharedURLLoaderFactory()
+ : factory_(base::MakeRefCounted<TestSharedURLLoaderFactory>()) {}
+
+ scoped_refptr<TestSharedURLLoaderFactory> factory() const { return factory_; }
+
+ protected:
+ scoped_refptr<network::SharedURLLoaderFactory> CreateFactory() override {
+ return factory_;
+ }
+
+ scoped_refptr<TestSharedURLLoaderFactory> factory_;
+};
+
+class MockResourceRequestSender : public WebResourceRequestSender {
+ public:
+ void CreatePendingRequest(scoped_refptr<WebRequestPeer> peer) {
+ peer_ = std::move(peer);
+ }
+
+ void DeletePendingRequest(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
+ peer_.reset();
+ }
+
+ private:
+ scoped_refptr<WebRequestPeer> peer_;
+};
+
+} // namespace
+
+class SyncLoadContextTest : public testing::Test {
+ public:
+ SyncLoadContextTest() : loading_thread_("loading thread") {}
+
+ void SetUp() override {
+ ASSERT_TRUE(loading_thread_.StartAndWaitForTesting());
+ }
+
+ void StartAsyncWithWaitableEventOnLoadingThread(
+ std::unique_ptr<network::ResourceRequest> request,
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory,
+ SyncLoadResponse* out_response,
+ SyncLoadContext** context_for_redirect,
+ base::WaitableEvent* redirect_or_response_event) {
+ loading_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &SyncLoadContext::StartAsyncWithWaitableEvent, std::move(request),
+ MSG_ROUTING_NONE, loading_thread_.task_runner(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0 /* loader_options */,
+ std::move(pending_factory),
+ WebVector<std::unique_ptr<URLLoaderThrottle>>(), out_response,
+ context_for_redirect, redirect_or_response_event,
+ nullptr /* terminate_sync_load_event */,
+ base::TimeDelta::FromSeconds(60) /* timeout */,
+ mojo::NullRemote() /* download_to_blob_registry */,
+ WebVector<WebString>() /* cors_exempt_header_list */,
+ std::make_unique<ResourceLoadInfoNotifierWrapper>(
+ /*resource_load_info_notifier=*/nullptr,
+ task_environment_.GetMainThreadTaskRunner())));
+ }
+
+ static void RunSyncLoadContextViaDataPipe(
+ network::ResourceRequest* request,
+ SyncLoadResponse* response,
+ SyncLoadContext** context_for_redirect,
+ std::string expected_data,
+ base::WaitableEvent* redirect_or_response_event,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(task_runner->BelongsToCurrentThread());
+ auto* context = new SyncLoadContext(
+ request, std::make_unique<MockPendingSharedURLLoaderFactory>(),
+ response, context_for_redirect, redirect_or_response_event,
+ nullptr /* terminate_sync_load_event */,
+ base::TimeDelta::FromSeconds(60) /* timeout */,
+ mojo::NullRemote() /* download_to_blob_registry */, task_runner);
+
+ auto mock_resource_request_sender =
+ std::make_unique<MockResourceRequestSender>();
+ mock_resource_request_sender->CreatePendingRequest(
+ base::WrapRefCounted(context));
+ context->resource_request_sender_ = std::move(mock_resource_request_sender);
+
+ // Simulate the response.
+ context->OnReceivedResponse(network::mojom::URLResponseHead::New());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ mojo::CreateDataPipe(nullptr /* options */, producer_handle,
+ consumer_handle));
+ context->OnStartLoadingResponseBody(std::move(consumer_handle));
+ context->OnCompletedRequest(network::URLLoaderCompletionStatus(net::OK));
+
+ mojo::BlockingCopyFromString(expected_data, producer_handle);
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ base::Thread loading_thread_;
+};
+
+TEST_F(SyncLoadContextTest, StartAsyncWithWaitableEvent) {
+ GURL expected_url = GURL("https://example.com");
+ std::string expected_data = "foobarbaz";
+
+ // Create and exercise SyncLoadContext on the |loading_thread_|.
+ auto request = std::make_unique<network::ResourceRequest>();
+ request->url = expected_url;
+ auto pending_factory = std::make_unique<MockPendingSharedURLLoaderFactory>();
+ pending_factory->factory()->AddResponse(expected_url.spec(), expected_data);
+ SyncLoadResponse response;
+ SyncLoadContext* context_for_redirect = nullptr;
+ base::WaitableEvent redirect_or_response_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ StartAsyncWithWaitableEventOnLoadingThread(
+ std::move(request), std::move(pending_factory), &response,
+ &context_for_redirect, &redirect_or_response_event);
+
+ // Wait until the response is received.
+ redirect_or_response_event.Wait();
+
+ // Check if |response| is set properly after the WaitableEvent fires.
+ EXPECT_EQ(net::OK, response.error_code);
+ const char* response_data = nullptr;
+ size_t size = response.data.GetSomeData(response_data, 0);
+ EXPECT_EQ(expected_data, std::string(response_data, size));
+}
+
+TEST_F(SyncLoadContextTest, ResponseBodyViaDataPipe) {
+ GURL expected_url = GURL("https://example.com");
+ std::string expected_data = "foobarbaz";
+
+ // Create and exercise SyncLoadContext on the |loading_thread_|.
+ auto request = std::make_unique<network::ResourceRequest>();
+ request->url = expected_url;
+ SyncLoadResponse response;
+ base::WaitableEvent redirect_or_response_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ SyncLoadContext* context_for_redirect = nullptr;
+ loading_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&SyncLoadContextTest::RunSyncLoadContextViaDataPipe,
+ request.get(), &response, &context_for_redirect,
+ expected_data, &redirect_or_response_event,
+ loading_thread_.task_runner()));
+
+ // Wait until the response is received.
+ redirect_or_response_event.Wait();
+
+ // Check if |response| is set properly after the WaitableEvent fires.
+ EXPECT_EQ(net::OK, response.error_code);
+ const char* response_data = nullptr;
+ size_t size = response.data.GetSomeData(response_data, 0);
+ EXPECT_EQ(expected_data, std::string(response_data, size));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.cc
new file mode 100644
index 00000000000..d57646a79e7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
+
+namespace blink {
+
+SyncLoadResponse::SyncLoadResponse() = default;
+
+SyncLoadResponse::SyncLoadResponse(SyncLoadResponse&& other) = default;
+
+SyncLoadResponse::~SyncLoadResponse() = default;
+
+SyncLoadResponse& SyncLoadResponse::operator=(SyncLoadResponse&& other) =
+ default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h
new file mode 100644
index 00000000000..01203eb37f2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_RESPONSE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_RESPONSE_H_
+
+#include "base/optional.h"
+#include "net/dns/public/resolve_error_info.h"
+#include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/mojom/blob/serialized_blob.mojom.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_data.h"
+#include "url/gurl.h"
+
+namespace blink {
+
+// See the SyncLoad method. (The name of this struct is not
+// suffixed with "Info" because it also contains the response data.)
+struct BLINK_PLATFORM_EXPORT SyncLoadResponse {
+ SyncLoadResponse();
+ SyncLoadResponse(SyncLoadResponse&& other);
+ ~SyncLoadResponse();
+
+ SyncLoadResponse& operator=(SyncLoadResponse&& other);
+
+ base::Optional<net::RedirectInfo> redirect_info;
+
+ network::mojom::URLResponseHeadPtr head =
+ network::mojom::URLResponseHead::New();
+
+ // The response error code.
+ int error_code;
+
+ // The response extended error code.
+ int extended_error_code = 0;
+
+ // Detailed host resolution error information.
+ net::ResolveErrorInfo resolve_error_info;
+
+ // Optional CORS error details.
+ base::Optional<network::CorsErrorStatus> cors_error;
+
+ // The final URL of the response. This may differ from the request URL in
+ // the case of a server redirect.
+ // Use GURL to avoid extra conversion between KURL and GURL because non-blink
+ // types are allowed for loader here.
+ GURL url;
+
+ // The response data.
+ WebData data;
+
+ // Used for blob response type XMLHttpRequest.
+ mojom::SerializedBlobPtr downloaded_blob;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_SYNC_LOAD_RESPONSE_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.cc
deleted file mode 100644
index 1c96e428bca..00000000000
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.cc
+++ /dev/null
@@ -1,459 +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/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h"
-
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
-#include "components/web_package/web_bundle_parser.h"
-#include "components/web_package/web_bundle_utils.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/system/data_pipe.h"
-#include "mojo/public/cpp/system/data_pipe_drainer.h"
-#include "mojo/public/cpp/system/data_pipe_producer.h"
-#include "net/http/http_status_code.h"
-#include "services/network/public/mojom/url_loader.mojom.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.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/functional.h"
-#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
-
-namespace blink {
-
-namespace {
-
-class WebBundleSubresourceLoader : public network::mojom::URLLoader {
- public:
- WebBundleSubresourceLoader(
- mojo::PendingReceiver<network::mojom::URLLoader> loader,
- const network::ResourceRequest& request,
- mojo::PendingRemote<network::mojom::URLLoaderClient> client)
- : url_(request.url),
- receiver_(this, std::move(loader)),
- client_(std::move(client)) {
- receiver_.set_disconnect_handler(base::BindOnce(
- &WebBundleSubresourceLoader::OnMojoDisconnect, GetWeakPtr()));
- }
- WebBundleSubresourceLoader(const WebBundleSubresourceLoader&) = delete;
- WebBundleSubresourceLoader& operator=(const WebBundleSubresourceLoader&) =
- delete;
-
- const GURL& Url() const { return url_; }
-
- base::WeakPtr<WebBundleSubresourceLoader> GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
- }
-
- void OnResponse(network::mojom::URLResponseHeadPtr response) {
- client_->OnReceiveResponse(std::move(response));
- }
-
- void OnData(mojo::ScopedDataPipeConsumerHandle consumer) {
- client_->OnStartLoadingResponseBody(std::move(consumer));
- }
-
- void OnFail(net::Error error) {
- client_->OnComplete(network::URLLoaderCompletionStatus(error));
- delete this;
- }
-
- void OnWriteCompleted(MojoResult result) {
- network::URLLoaderCompletionStatus status(
- result == MOJO_RESULT_OK ? net::OK : net::ERR_INVALID_WEB_BUNDLE);
- client_->OnComplete(status);
- delete this;
- }
-
- private:
- // network::mojom::URLLoader
- void FollowRedirect(
- const std::vector<std::string>& removed_headers,
- const net::HttpRequestHeaders& modified_headers,
- const net::HttpRequestHeaders& modified_cors_exempt_headers,
- const base::Optional<GURL>& new_url) override {
- NOTREACHED();
- }
-
- void SetPriority(net::RequestPriority priority,
- int32_t intra_priority_value) override {
- // Not supported (do nothing).
- }
-
- void PauseReadingBodyFromNet() override {}
- void ResumeReadingBodyFromNet() override {}
-
- void OnMojoDisconnect() { delete this; }
-
- const GURL url_;
- mojo::Receiver<network::mojom::URLLoader> receiver_;
- mojo::Remote<network::mojom::URLLoaderClient> client_;
- base::WeakPtrFactory<WebBundleSubresourceLoader> weak_ptr_factory_{this};
-};
-
-class PipeDataSource : public mojo::DataPipeProducer::DataSource {
- public:
- explicit PipeDataSource(std::vector<uint8_t> data) : data_(std::move(data)) {}
- uint64_t GetLength() const override { return data_.size(); }
-
- ReadResult Read(uint64_t uint64_offset, base::span<char> buffer) override {
- ReadResult result;
- if (uint64_offset > data_.size()) {
- result.result = MOJO_RESULT_OUT_OF_RANGE;
- return result;
- }
- size_t offset = base::checked_cast<size_t>(uint64_offset);
- size_t len = std::min(data_.size() - offset, buffer.size());
- if (len > 0) {
- DCHECK_LT(offset, data_.size());
- memcpy(buffer.data(), &data_[offset], len);
- }
- result.bytes_read = len;
- return result;
- }
-
- private:
- // Since mojo::DataPipeProducer runs in its own sequence, we can't just have
- // a reference to the SharedBuffer in LinkWebBundleDataSource.
- std::vector<uint8_t> data_;
-};
-
-void DeleteProducerAndRunCallback(
- std::unique_ptr<mojo::DataPipeProducer> producer,
- base::OnceCallback<void(MojoResult result)> callback,
- MojoResult result) {
- std::move(callback).Run(result);
-}
-
-class LinkWebBundleDataSource : public web_package::mojom::BundleDataSource,
- public mojo::DataPipeDrainer::Client {
- public:
- using ReadToDataPipeCallback = base::OnceCallback<void(MojoResult result)>;
-
- LinkWebBundleDataSource(
- mojo::PendingReceiver<web_package::mojom::BundleDataSource>
- data_source_receiver,
- mojo::ScopedDataPipeConsumerHandle bundle_body)
- : data_source_receiver_(this, std::move(data_source_receiver)),
- data_(SharedBuffer::Create()),
- pipe_drainer_(
- std::make_unique<mojo::DataPipeDrainer>(this,
- std::move(bundle_body))) {}
-
- ~LinkWebBundleDataSource() override {
- // The receiver must be closed before destructing pending callbacks in
- // |pending_reads_| / |pending_reads_to_data_pipe_|.
- data_source_receiver_.reset();
- }
-
- LinkWebBundleDataSource(const LinkWebBundleDataSource&) = delete;
- LinkWebBundleDataSource& operator=(const LinkWebBundleDataSource&) = delete;
-
- void ReadToDataPipe(mojo::ScopedDataPipeProducerHandle producer,
- uint64_t offset,
- uint64_t length,
- ReadToDataPipeCallback callback) {
- TRACE_EVENT0("loading", "LinkWebBundleDataSource::ReadToDataPipe");
- if (!finished_loading_ && offset + length > data_->size()) {
- // Current implementation does not support progressive loading of inner
- // response body.
- PendingReadToDataPipe pending;
- pending.producer = std::move(producer);
- pending.offset = offset;
- pending.length = length;
- pending.callback = std::move(callback);
- pending_reads_to_data_pipe_.push_back(std::move(pending));
- return;
- }
-
- auto writer = std::make_unique<mojo::DataPipeProducer>(std::move(producer));
- mojo::DataPipeProducer* raw_writer = writer.get();
- raw_writer->Write(std::make_unique<PipeDataSource>(GetData(offset, length)),
- base::BindOnce(&DeleteProducerAndRunCallback,
- std::move(writer), std::move(callback)));
- }
-
- // mojom::BundleDataSource
- void Read(uint64_t offset, uint64_t length, ReadCallback callback) override {
- TRACE_EVENT0("loading", "LinkWebBundleDataSource::Read");
- if (!finished_loading_ && offset + length > data_->size()) {
- PendingRead pending;
- pending.offset = offset;
- pending.length = length;
- pending.callback = std::move(callback);
- pending_reads_.push_back(std::move(pending));
- return;
- }
- std::move(callback).Run(GetData(offset, length));
- }
-
- // mojo::DataPipeDrainer::Client
- void OnDataAvailable(const void* data, size_t num_bytes) override {
- DCHECK(!finished_loading_);
- data_->Append(reinterpret_cast<const char*>(data), num_bytes);
- ProcessPendingReads();
- }
-
- void OnDataComplete() override {
- DCHECK(!finished_loading_);
- finished_loading_ = true;
- ProcessPendingReads();
- }
-
- private:
- void ProcessPendingReads() {
- std::vector<PendingRead> pendings;
- pendings.swap(pending_reads_);
- for (auto& pending : pendings)
- Read(pending.offset, pending.length, std::move(pending.callback));
-
- std::vector<PendingReadToDataPipe> pipe_pendings;
- pipe_pendings.swap(pending_reads_to_data_pipe_);
- for (auto& pending : pipe_pendings) {
- ReadToDataPipe(std::move(pending.producer), pending.offset,
- pending.length, std::move(pending.callback));
- }
- }
-
- std::vector<uint8_t> GetData(uint64_t uint64_offset, uint64_t uint64_length) {
- size_t offset = base::checked_cast<size_t>(uint64_offset);
- size_t length = base::checked_cast<size_t>(uint64_length);
- std::vector<uint8_t> output(length);
- size_t bytes_copied = 0;
- for (auto it = data_->GetIteratorAt(offset);
- bytes_copied < length && it != data_->cend(); it++) {
- size_t n = std::min(it->size(), length - bytes_copied);
- memcpy(output.data() + bytes_copied, it->data(), n);
- bytes_copied += n;
- }
- output.resize(bytes_copied);
- return output;
- }
-
- struct PendingRead {
- uint64_t offset;
- uint64_t length;
- ReadCallback callback;
- };
- struct PendingReadToDataPipe {
- mojo::ScopedDataPipeProducerHandle producer;
- uint64_t offset;
- uint64_t length;
- ReadToDataPipeCallback callback;
- };
-
- mojo::Receiver<web_package::mojom::BundleDataSource> data_source_receiver_;
- scoped_refptr<SharedBuffer> data_;
- std::vector<PendingRead> pending_reads_;
- std::vector<PendingReadToDataPipe> pending_reads_to_data_pipe_;
- bool finished_loading_ = false;
- std::unique_ptr<mojo::DataPipeDrainer> pipe_drainer_;
-};
-
-// Self destroys when no more bindings exist.
-class WebBundleSubresourceLoaderFactory
- : public network::mojom::URLLoaderFactory {
- public:
- WebBundleSubresourceLoaderFactory(
- mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
- mojo::ScopedDataPipeConsumerHandle bundle_body,
- scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
- WebBundleErrorCallback error_callback)
- : callback_task_runner_(callback_task_runner),
- error_callback_(error_callback) {
- receivers_.Add(this, std::move(receiver));
- receivers_.set_disconnect_handler(base::BindRepeating(
- &WebBundleSubresourceLoaderFactory::OnMojoDisconnect,
- base::Unretained(this)));
- mojo::PendingRemote<web_package::mojom::BundleDataSource> data_source;
- source_ = std::make_unique<LinkWebBundleDataSource>(
- data_source.InitWithNewPipeAndPassReceiver(), std::move(bundle_body));
- // WebBundleParser will self-destruct on remote mojo ends' disconnection.
- new web_package::WebBundleParser(parser_.BindNewPipeAndPassReceiver(),
- std::move(data_source));
-
- parser_->ParseMetadata(
- WTF::Bind(&WebBundleSubresourceLoaderFactory::OnMetadataParsed,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- ~WebBundleSubresourceLoaderFactory() override {
- for (auto loader : pending_loaders_) {
- if (loader)
- loader->OnFail(net::ERR_FAILED);
- }
- }
-
- WebBundleSubresourceLoaderFactory(const WebBundleSubresourceLoaderFactory&) =
- delete;
- WebBundleSubresourceLoaderFactory& operator=(
- const WebBundleSubresourceLoaderFactory&) = delete;
-
- void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory)
- override {
- receivers_.Add(this, std::move(factory));
- }
-
- void CreateLoaderAndStart(
- mojo::PendingReceiver<network::mojom::URLLoader> pending_receiver,
- int32_t routing_id,
- int32_t request_id,
- uint32_t options,
- const network::ResourceRequest& request,
- mojo::PendingRemote<network::mojom::URLLoaderClient> client,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
- override {
- TRACE_EVENT0("loading",
- "WebBundleSubresourceLoaderFactory::CreateLoaderAndStart");
- WebBundleSubresourceLoader* loader = new WebBundleSubresourceLoader(
- std::move(pending_receiver), request, std::move(client));
- if (metadata_error_) {
- loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
- return;
- }
- if (!metadata_) {
- pending_loaders_.push_back(loader->GetWeakPtr());
- return;
- }
- StartLoad(loader);
- }
-
- private:
- void OnMojoDisconnect() {
- if (!receivers_.empty())
- return;
- delete this;
- }
-
- void StartLoad(WebBundleSubresourceLoader* loader) {
- DCHECK(metadata_);
- if (!loader)
- return;
- auto it = metadata_->requests.find(loader->Url());
- if (it == metadata_->requests.end()) {
- RunErrorCallback(WebBundleErrorType::kResourceNotFound,
- loader->Url().possibly_invalid_spec() +
- " is not found in the WebBundle.");
- loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
- return;
- }
- // Currently, we just return the first response for the URL.
- // TODO(crbug.com/1082020): Support variant matching.
- auto& location = it->second->response_locations[0];
- parser_->ParseResponse(
- location->offset, location->length,
- WTF::Bind(&WebBundleSubresourceLoaderFactory::OnResponseParsed,
- weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr()));
- }
-
- void OnMetadataParsed(web_package::mojom::BundleMetadataPtr metadata,
- web_package::mojom::BundleMetadataParseErrorPtr error) {
- TRACE_EVENT0("loading",
- "WebBundleSubresourceLoaderFactory::OnMetadataParsed");
- if (error) {
- metadata_error_ = std::move(error);
- RunErrorCallback(WebBundleErrorType::kMetadataParseError,
- metadata_error_->message);
- for (auto loader : pending_loaders_) {
- if (loader)
- loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
- }
- pending_loaders_.clear();
- return;
- }
-
- metadata_ = std::move(metadata);
- for (auto loader : pending_loaders_)
- StartLoad(loader.get());
- pending_loaders_.clear();
- }
-
- void OnResponseParsed(base::WeakPtr<WebBundleSubresourceLoader> loader,
- web_package::mojom::BundleResponsePtr response,
- web_package::mojom::BundleResponseParseErrorPtr error) {
- TRACE_EVENT0("loading",
- "WebBundleSubresourceLoaderFactory::OnResponseParsed");
- if (!loader)
- return;
- if (error) {
- RunErrorCallback(WebBundleErrorType::kResponseParseError, error->message);
- loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
- return;
- }
- // Currently we allow only net::HTTP_OK responses in bundles.
- // TODO(crbug.com/990733): Revisit this once
- // https://github.com/WICG/webpackage/issues/478 is resolved.
- if (response->response_code != net::HTTP_OK) {
- RunErrorCallback(WebBundleErrorType::kResponseParseError,
- "Invalid response code " +
- base::NumberToString(response->response_code));
- loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
- return;
- }
-
- loader->OnResponse(web_package::CreateResourceResponse(response));
-
- mojo::ScopedDataPipeProducerHandle producer;
- mojo::ScopedDataPipeConsumerHandle consumer;
- if (CreateDataPipe(nullptr, &producer, &consumer) != MOJO_RESULT_OK) {
- loader->OnFail(net::ERR_INSUFFICIENT_RESOURCES);
- return;
- }
- loader->OnData(std::move(consumer));
- source_->ReadToDataPipe(
- std::move(producer), response->payload_offset, response->payload_length,
- base::BindOnce(&WebBundleSubresourceLoader::OnWriteCompleted,
- loader->GetWeakPtr()));
- }
-
- void RunErrorCallback(WebBundleErrorType type, const std::string& message) {
- PostCrossThreadTask(*callback_task_runner_, FROM_HERE,
- WTF::CrossThreadBindOnce(error_callback_, type,
- String(message.c_str())));
- }
-
- mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
- std::unique_ptr<LinkWebBundleDataSource> source_;
- mojo::Remote<web_package::mojom::WebBundleParser> parser_;
- web_package::mojom::BundleMetadataPtr metadata_;
- web_package::mojom::BundleMetadataParseErrorPtr metadata_error_;
- std::vector<base::WeakPtr<WebBundleSubresourceLoader>> pending_loaders_;
- scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
- WebBundleErrorCallback error_callback_;
-
- base::WeakPtrFactory<WebBundleSubresourceLoaderFactory> weak_ptr_factory_{
- this};
-};
-
-// Runs on a background thread.
-void CreateFactoryOnBackground(
- mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
- mojo::ScopedDataPipeConsumerHandle bundle_body,
- scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
- WebBundleErrorCallback error_callback) {
- new WebBundleSubresourceLoaderFactory(
- std::move(receiver), std::move(bundle_body), callback_task_runner,
- std::move(error_callback));
-}
-
-} // namespace
-
-void CreateWebBundleSubresourceLoaderFactory(
- CrossVariantMojoReceiver<network::mojom::URLLoaderFactoryInterfaceBase>
- factory_receiver,
- mojo::ScopedDataPipeConsumerHandle bundle_body,
- WebBundleErrorCallback error_callback) {
- auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
- {base::TaskPriority::USER_VISIBLE,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
- task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&CreateFactoryOnBackground, std::move(factory_receiver),
- std::move(bundle_body),
- base::ThreadTaskRunnerHandle::Get(),
- std::move(error_callback)));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h
deleted file mode 100644
index 82866299c59..00000000000
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h
+++ /dev/null
@@ -1,39 +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_PLATFORM_LOADER_FETCH_URL_LOADER_WEB_BUNDLE_SUBRESOURCE_LOADER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_WEB_BUNDLE_SUBRESOURCE_LOADER_H_
-
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "services/network/public/mojom/url_loader_factory.mojom-shared.h"
-#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace WTF {
-class String;
-} // namespace WTF
-
-namespace blink {
-
-enum class WebBundleErrorType {
- kMetadataParseError,
- kResponseParseError,
- kResourceNotFound,
-};
-
-using WebBundleErrorCallback =
- base::RepeatingCallback<void(WebBundleErrorType,
- const WTF::String& message)>;
-
-// Creates a network::mojom::URLLoaderFactory that can load resources from a
-// WebBundle, and binds it to |factory_receiver|.
-PLATFORM_EXPORT void CreateWebBundleSubresourceLoaderFactory(
- CrossVariantMojoReceiver<network::mojom::URLLoaderFactoryInterfaceBase>
- factory_receiver,
- mojo::ScopedDataPipeConsumerHandle bundle_body,
- WebBundleErrorCallback error_callback);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_URL_LOADER_WEB_BUNDLE_SUBRESOURCE_LOADER_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader_test.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader_test.cc
deleted file mode 100644
index 545ffebb7ac..00000000000
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader_test.cc
+++ /dev/null
@@ -1,336 +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/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h"
-
-#include "base/test/task_environment.h"
-#include "components/web_package/test_support/web_bundle_builder.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/system/data_pipe_utils.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/mojom/url_loader.mojom.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "services/network/test/test_url_loader_client.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-namespace {
-
-const char kResourceUrl[] = "https://example.com/";
-const char kResourceUrl2[] = "https://example.com/another";
-const char kResourceUrl3[] = "https://example.com/yetanother";
-
-std::vector<uint8_t> CreateSmallBundle() {
- web_package::test::WebBundleBuilder builder(kResourceUrl,
- "" /* manifest_url */);
- builder.AddExchange(kResourceUrl,
- {{":status", "200"}, {"content-type", "text/plain"}},
- "body");
- return builder.CreateBundle();
-}
-
-std::vector<uint8_t> CreateLargeBundle() {
- web_package::test::WebBundleBuilder builder(kResourceUrl,
- "" /* manifest_url */);
- builder.AddExchange(kResourceUrl,
- {{":status", "200"}, {"content-type", "text/plain"}},
- "body");
- builder.AddExchange(kResourceUrl2,
- {{":status", "200"}, {"content-type", "text/plain"}},
- std::string(10000, 'a'));
- builder.AddExchange(kResourceUrl3,
- {{":status", "200"}, {"content-type", "text/plain"}},
- "body");
- return builder.CreateBundle();
-}
-
-} // namespace
-
-class WebBundleSubresourceLoaderFactoryTest : public ::testing::Test {
- public:
- void SetUp() override {
- mojo::ScopedDataPipeConsumerHandle consumer;
- ASSERT_EQ(CreateDataPipe(nullptr, &bundle_data_destination_, &consumer),
- MOJO_RESULT_OK);
- CreateWebBundleSubresourceLoaderFactory(
- loader_factory_.BindNewPipeAndPassReceiver(), std::move(consumer),
- base::BindRepeating(
- &WebBundleSubresourceLoaderFactoryTest::OnWebBundleError,
- base::Unretained(this)));
- }
-
- void WriteBundle(base::span<const uint8_t> data) {
- mojo::BlockingCopyFromString(
- std::string(reinterpret_cast<const char*>(data.data()), data.size()),
- bundle_data_destination_);
- }
-
- void FinishWritingBundle() { bundle_data_destination_.reset(); }
-
- struct StartRequestResult {
- mojo::Remote<network::mojom::URLLoader> loader;
- std::unique_ptr<network::TestURLLoaderClient> client;
- };
-
- StartRequestResult StartRequest(const GURL& url) {
- return StartRequestWithLoaderFactory(loader_factory_, url);
- }
-
- void RunUntilBundleError() {
- if (last_bundle_error_.has_value())
- return;
- base::RunLoop run_loop;
- quit_closure_for_bundle_error_ = run_loop.QuitClosure();
- run_loop.Run();
- }
-
- const base::Optional<std::pair<WebBundleErrorType, WTF::String>>&
- last_bundle_error() const {
- return last_bundle_error_;
- }
-
- protected:
- StartRequestResult StartRequestWithLoaderFactory(
- mojo::Remote<network::mojom::URLLoaderFactory>& factory,
- const GURL& url) {
- network::ResourceRequest request;
- request.url = url;
- request.method = "GET";
- StartRequestResult result;
- result.client = std::make_unique<network::TestURLLoaderClient>();
- factory->CreateLoaderAndStart(
- result.loader.BindNewPipeAndPassReceiver(), 0 /* routing_id */,
- 0 /* request_id */, 0 /* options */, request,
- result.client->CreateRemote(),
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
- return result;
- }
-
- mojo::Remote<network::mojom::URLLoaderFactory> loader_factory_;
-
- private:
- void OnWebBundleError(WebBundleErrorType type, const WTF::String& message) {
- last_bundle_error_ = std::make_pair(type, message);
- if (quit_closure_for_bundle_error_)
- std::move(quit_closure_for_bundle_error_).Run();
- }
-
- mojo::ScopedDataPipeProducerHandle bundle_data_destination_;
- base::test::TaskEnvironment task_environment;
- base::Optional<std::pair<WebBundleErrorType, WTF::String>> last_bundle_error_;
- base::OnceClosure quit_closure_for_bundle_error_;
-};
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, Basic) {
- WriteBundle(CreateSmallBundle());
- FinishWritingBundle();
-
- auto request = StartRequest(GURL(kResourceUrl));
- request.client->RunUntilComplete();
-
- EXPECT_EQ(net::OK, request.client->completion_status().error_code);
- EXPECT_FALSE(last_bundle_error().has_value());
- std::string body;
- EXPECT_TRUE(mojo::BlockingCopyToString(
- request.client->response_body_release(), &body));
- EXPECT_EQ("body", body);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, Clone) {
- mojo::Remote<network::mojom::URLLoaderFactory> cloned_factory_;
- loader_factory_->Clone(cloned_factory_.BindNewPipeAndPassReceiver());
-
- WriteBundle(CreateSmallBundle());
- FinishWritingBundle();
-
- auto request =
- StartRequestWithLoaderFactory(cloned_factory_, GURL(kResourceUrl));
- request.client->RunUntilComplete();
-
- EXPECT_EQ(net::OK, request.client->completion_status().error_code);
- EXPECT_FALSE(last_bundle_error().has_value());
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, MetadataParseError) {
- auto request = StartRequest(GURL(kResourceUrl));
-
- std::vector<uint8_t> bundle = CreateSmallBundle();
- bundle[4] ^= 1; // Mutate magic bytes.
- WriteBundle(bundle);
- FinishWritingBundle();
-
- request.client->RunUntilComplete();
- RunUntilBundleError();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request.client->completion_status().error_code);
- EXPECT_EQ(last_bundle_error()->first,
- WebBundleErrorType::kMetadataParseError);
- EXPECT_EQ(last_bundle_error()->second, "Wrong magic bytes.");
-
- // Requests made after metadata parse error should also fail.
- auto request2 = StartRequest(GURL(kResourceUrl));
- request2.client->RunUntilComplete();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request2.client->completion_status().error_code);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, ResponseParseError) {
- web_package::test::WebBundleBuilder builder(kResourceUrl,
- "" /* manifest_url */);
- // An invalid response.
- builder.AddExchange(kResourceUrl, {{":status", "0"}}, "body");
- WriteBundle(builder.CreateBundle());
- FinishWritingBundle();
-
- auto request = StartRequest(GURL(kResourceUrl));
- request.client->RunUntilComplete();
- RunUntilBundleError();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request.client->completion_status().error_code);
- EXPECT_EQ(last_bundle_error()->first,
- WebBundleErrorType::kResponseParseError);
- EXPECT_EQ(last_bundle_error()->second,
- ":status must be 3 ASCII decimal digits.");
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, ResourceNotFoundInBundle) {
- WriteBundle(CreateSmallBundle());
- FinishWritingBundle();
-
- auto request = StartRequest(GURL("https://example.com/no-such-resource"));
- request.client->RunUntilComplete();
- RunUntilBundleError();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request.client->completion_status().error_code);
- EXPECT_EQ(last_bundle_error()->first, WebBundleErrorType::kResourceNotFound);
- EXPECT_EQ(
- last_bundle_error()->second,
- "https://example.com/no-such-resource is not found in the WebBundle.");
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, RedirectResponseIsNotAllowed) {
- web_package::test::WebBundleBuilder builder(kResourceUrl,
- "" /* manifest_url */);
- builder.AddExchange(kResourceUrl,
- {{":status", "301"}, {"location", kResourceUrl2}}, "");
- builder.AddExchange(kResourceUrl2,
- {{":status", "200"}, {"content-type", "text/plain"}},
- "body");
- WriteBundle(builder.CreateBundle());
- FinishWritingBundle();
-
- auto request = StartRequest(GURL(kResourceUrl));
- request.client->RunUntilComplete();
- RunUntilBundleError();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request.client->completion_status().error_code);
- EXPECT_EQ(last_bundle_error()->first,
- WebBundleErrorType::kResponseParseError);
- EXPECT_EQ(last_bundle_error()->second, "Invalid response code 301");
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, StartRequestBeforeReadingBundle) {
- auto request = StartRequest(GURL(kResourceUrl));
-
- WriteBundle(CreateSmallBundle());
- FinishWritingBundle();
- request.client->RunUntilComplete();
-
- EXPECT_EQ(net::OK, request.client->completion_status().error_code);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, MultipleRequests) {
- auto request1 = StartRequest(GURL(kResourceUrl));
- auto request2 = StartRequest(GURL(kResourceUrl2));
-
- std::vector<uint8_t> bundle = CreateLargeBundle();
- // Write the first 10kB of the bundle in which the bundle's metadata and the
- // response for kResourceUrl are included.
- ASSERT_GT(bundle.size(), 10000U);
- WriteBundle(base::make_span(bundle).subspan(0, 10000));
- request1.client->RunUntilComplete();
-
- EXPECT_EQ(net::OK, request1.client->completion_status().error_code);
- EXPECT_FALSE(request2.client->has_received_completion());
-
- // Write the rest of the data.
- WriteBundle(base::make_span(bundle).subspan(10000));
- FinishWritingBundle();
- request2.client->RunUntilComplete();
-
- EXPECT_EQ(net::OK, request2.client->completion_status().error_code);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, CancelRequest) {
- auto request_to_complete1 = StartRequest(GURL(kResourceUrl));
- auto request_to_complete2 = StartRequest(GURL(kResourceUrl2));
- auto request_to_cancel1 = StartRequest(GURL(kResourceUrl));
- auto request_to_cancel2 = StartRequest(GURL(kResourceUrl2));
- auto request_to_cancel3 = StartRequest(GURL(kResourceUrl3));
-
- // Cancel request before getting metadata.
- request_to_cancel1.loader.reset();
-
- std::vector<uint8_t> bundle = CreateLargeBundle();
- // Write the first 10kB of the bundle in which the bundle's metadata, response
- // for kResourceUrl, and response header for kResourceUrl2 are included.
- ASSERT_GT(bundle.size(), 10000U);
- WriteBundle(base::make_span(bundle).subspan(0, 10000));
-
- // This makes sure the bytes written above are consumed by WebBundle parser.
- request_to_complete1.client->RunUntilComplete();
-
- // Cancel request after reading response header, but before reading body.
- request_to_cancel2.loader.reset();
-
- // Cancel request after getting metadata, but before reading response header.
- request_to_cancel3.loader.reset();
-
- // Write the rest of the data.
- WriteBundle(base::make_span(bundle).subspan(10000));
- FinishWritingBundle();
- request_to_complete2.client->RunUntilComplete();
- EXPECT_EQ(net::OK,
- request_to_complete2.client->completion_status().error_code);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest,
- FactoryDestructionCancelsInflightRequests) {
- auto request = StartRequest(GURL(kResourceUrl));
-
- loader_factory_.reset();
-
- WriteBundle(CreateSmallBundle());
- FinishWritingBundle();
- request.client->RunUntilComplete();
-
- EXPECT_EQ(net::ERR_FAILED, request.client->completion_status().error_code);
-}
-
-TEST_F(WebBundleSubresourceLoaderFactoryTest, TruncatedBundle) {
- std::vector<uint8_t> bundle = CreateSmallBundle();
- // Truncate in the middle of responses section.
- bundle.resize(bundle.size() - 10);
- WriteBundle(std::move(bundle));
- FinishWritingBundle();
-
- auto request = StartRequest(GURL(kResourceUrl));
- request.client->RunUntilComplete();
- RunUntilBundleError();
-
- EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
- request.client->completion_status().error_code);
- EXPECT_EQ(last_bundle_error()->first,
- WebBundleErrorType::kResponseParseError);
- EXPECT_EQ(last_bundle_error()->second, "Error reading response header.");
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
new file mode 100644
index 00000000000..dee858aaca9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
@@ -0,0 +1,630 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+
+#include <utility>
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/referrer_policy.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/common/client_hints/client_hints.h"
+#include "third_party/blink/public/common/loader/inter_process_time_ticks_converter.h"
+#include "third_party/blink/public/common/loader/network_utils.h"
+#include "third_party/blink/public/common/loader/referrer_utils.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/common/loader/throttling_url_loader.h"
+#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_request_peer.h"
+#include "third_party/blink/public/platform/web_resource_request_sender_delegate.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
+#include "third_party/blink/renderer/platform/loader/fetch/back_forward_cache_loader_helper.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_context.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.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"
+
+namespace WTF {
+
+template <>
+struct CrossThreadCopier<
+ blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>>> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>>;
+ static Type Copy(Type&& value) { return std::move(value); }
+};
+
+template <>
+struct CrossThreadCopier<net::NetworkTrafficAnnotationTag>
+ : public CrossThreadCopierPassThrough<net::NetworkTrafficAnnotationTag> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = net::NetworkTrafficAnnotationTag;
+ static const Type& Copy(const Type& traffic_annotation) {
+ return traffic_annotation;
+ }
+};
+
+template <>
+struct CrossThreadCopier<blink::WebVector<blink::WebString>> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = blink::WebVector<blink::WebString>;
+ static Type Copy(const Type& value) {
+ Type result;
+ result.reserve(value.size());
+ for (const auto& element : value)
+ result.emplace_back(element.IsolatedCopy());
+ return result;
+ }
+};
+
+} // namespace WTF
+
+namespace blink {
+
+namespace {
+
+// Converts |time| from a remote to local TimeTicks, overwriting the original
+// value.
+void RemoteToLocalTimeTicks(const InterProcessTimeTicksConverter& converter,
+ base::TimeTicks* time) {
+ RemoteTimeTicks remote_time = RemoteTimeTicks::FromTimeTicks(*time);
+ *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
+}
+
+void CheckSchemeForReferrerPolicy(const network::ResourceRequest& request) {
+ if ((request.referrer_policy ==
+ ReferrerUtils::GetDefaultNetReferrerPolicy() ||
+ request.referrer_policy ==
+ net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE) &&
+ request.referrer.SchemeIsCryptographic() &&
+ !url::Origin::Create(request.url).opaque() &&
+ !network::IsUrlPotentiallyTrustworthy(request.url)) {
+ LOG(FATAL) << "Trying to send secure referrer for insecure request "
+ << "without an appropriate referrer policy.\n"
+ << "URL = " << request.url << "\n"
+ << "URL's Origin = "
+ << url::Origin::Create(request.url).Serialize() << "\n"
+ << "Referrer = " << request.referrer;
+ }
+}
+
+int GetInitialRequestID() {
+ // Starting with a random number speculatively avoids RDH_INVALID_REQUEST_ID
+ // which are assumed to have been caused by restarting RequestID at 0 when
+ // restarting a renderer after a crash - this would cause collisions if
+ // requests from the previously crashed renderer are still active. See
+ // https://crbug.com/614281#c61 for more details about this hypothesis.
+ //
+ // To avoid increasing the likelihood of overflowing the range of available
+ // RequestIDs, kMax is set to a relatively low value of 2^20 (rather than
+ // to something higher like 2^31).
+ const int kMin = 0;
+ const int kMax = 1 << 20;
+ return base::RandInt(kMin, kMax);
+}
+
+// Determines if the loader should be restarted on a redirect using
+// ThrottlingURLLoader::FollowRedirectForcingRestart.
+bool RedirectRequiresLoaderRestart(const GURL& original_url,
+ const GURL& redirect_url) {
+ // Restart is needed if the URL is no longer handled by network service.
+ if (network_utils::IsURLHandledByNetworkService(original_url))
+ return !network_utils::IsURLHandledByNetworkService(redirect_url);
+
+ // If URL wasn't originally handled by network service, restart is needed if
+ // schemes are different.
+ return original_url.scheme_piece() != redirect_url.scheme_piece();
+}
+
+} // namespace
+
+// static
+int WebResourceRequestSender::MakeRequestID() {
+ static const int kInitialRequestID = GetInitialRequestID();
+ static base::AtomicSequenceNumber sequence;
+ return kInitialRequestID + sequence.GetNext();
+}
+
+WebResourceRequestSender::WebResourceRequestSender()
+ : delegate_(Platform::Current()->GetResourceRequestSenderDelegate()) {}
+
+WebResourceRequestSender::~WebResourceRequestSender() = default;
+
+void WebResourceRequestSender::SendSync(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ SyncLoadResponse* response,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ base::TimeDelta timeout,
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ scoped_refptr<WebRequestPeer> peer,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
+ if (IsInflightNetworkRequestBackForwardCacheSupportEnabled()) {
+ // Sync fetches are triggered by script, which should not run when a
+ // document is in back-forward cache. If we somehow made it here, we should
+ // trigger a back-forward cache eviction.
+ auto* helper =
+ back_forward_cache_loader_helper.GetBackForwardCacheLoaderHelper();
+ if (helper) {
+ helper->EvictFromBackForwardCache(
+ mojom::RendererEvictionReason::kJavaScriptExecution);
+ }
+ }
+
+ CheckSchemeForReferrerPolicy(*request);
+
+ DCHECK(loader_options & network::mojom::kURLLoadOptionSynchronous);
+ DCHECK(request->load_flags & net::LOAD_IGNORE_LIMITS);
+
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory =
+ url_loader_factory->Clone();
+ base::WaitableEvent redirect_or_response_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ // Prepare the configured throttles for use on a separate thread.
+ for (const auto& throttle : throttles)
+ throttle->DetachFromCurrentSequence();
+
+ // A task is posted to a separate thread to execute the request so that
+ // this thread may block on a waitable event. It is safe to pass raw
+ // pointers to on-stack objects as this stack frame will
+ // survive until the request is complete.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::ThreadPool::CreateSingleThreadTaskRunner({});
+ SyncLoadContext* context_for_redirect = nullptr;
+ PostCrossThreadTask(
+ *task_runner, FROM_HERE,
+ WTF::CrossThreadBindOnce(
+ &SyncLoadContext::StartAsyncWithWaitableEvent, std::move(request),
+ routing_id, task_runner, traffic_annotation, loader_options,
+ std::move(pending_factory), std::move(throttles),
+ CrossThreadUnretained(response),
+ CrossThreadUnretained(&context_for_redirect),
+ CrossThreadUnretained(&redirect_or_response_event),
+ CrossThreadUnretained(terminate_sync_load_event), timeout,
+ std::move(download_to_blob_registry), cors_exempt_header_list,
+ std::move(resource_load_info_notifier_wrapper)));
+
+ // redirect_or_response_event will signal when each redirect completes, and
+ // when the final response is complete.
+ redirect_or_response_event.Wait();
+
+ while (context_for_redirect) {
+ DCHECK(response->redirect_info);
+ bool follow_redirect = peer->OnReceivedRedirect(
+ *response->redirect_info, response->head.Clone(),
+ nullptr /* removed_headers */);
+ redirect_or_response_event.Reset();
+ if (follow_redirect) {
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&SyncLoadContext::FollowRedirect,
+ base::Unretained(context_for_redirect)));
+ } else {
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&SyncLoadContext::CancelRedirect,
+ base::Unretained(context_for_redirect)));
+ }
+ redirect_or_response_event.Wait();
+ }
+}
+
+int WebResourceRequestSender::SendAsync(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ const WebVector<WebString>& cors_exempt_header_list,
+ scoped_refptr<WebRequestPeer> peer,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
+ auto weak_this = weak_factory_.GetWeakPtr();
+
+ CheckSchemeForReferrerPolicy(*request);
+
+#if defined(OS_ANDROID)
+ // Main frame shouldn't come here.
+ DCHECK(!(request->is_main_frame &&
+ IsRequestDestinationFrame(request->destination)));
+ if (request->has_user_gesture) {
+ resource_load_info_notifier_wrapper->NotifyUpdateUserGestureCarryoverInfo();
+ }
+#endif
+
+ // Compute a unique request_id for this renderer process.
+ int request_id = MakeRequestID();
+ request_info_ = std::make_unique<PendingRequestInfo>(
+ std::move(peer), request->destination, request->render_frame_id,
+ request->url, std::move(resource_load_info_notifier_wrapper));
+
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceLoadInitiated(
+ request_id, request->url, request->method, request->referrer,
+ request_info_->request_destination, request->priority);
+
+ request_info_->previews_state = request->previews_state;
+
+ auto client = std::make_unique<MojoURLLoaderClient>(
+ this, loading_task_runner, url_loader_factory->BypassRedirectChecks(),
+ request->url, back_forward_cache_loader_helper);
+
+ std::vector<std::string> std_cors_exempt_header_list(
+ cors_exempt_header_list.size());
+ std::transform(cors_exempt_header_list.begin(), cors_exempt_header_list.end(),
+ std_cors_exempt_header_list.begin(),
+ [](const WebString& h) { return h.Latin1(); });
+ std::unique_ptr<ThrottlingURLLoader> url_loader =
+ ThrottlingURLLoader::CreateLoaderAndStart(
+ std::move(url_loader_factory), throttles.ReleaseVector(), routing_id,
+ request_id, loader_options, request.get(), client.get(),
+ traffic_annotation, std::move(loading_task_runner),
+ base::make_optional(std_cors_exempt_header_list));
+ // TODO(https://crbug.com/1175286): Remove this mitigation when we understand
+ // why `this` or `request_info_` is being destroyed.
+ if (!weak_this || !request_info_)
+ return request_id;
+
+ request_info_->url_loader = std::move(url_loader);
+ request_info_->url_loader_client = std::move(client);
+
+ return request_id;
+}
+
+void WebResourceRequestSender::Cancel(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ // Cancel the request if it didn't complete, and clean it up so the bridge
+ // will receive no more messages.
+ DeletePendingRequest(std::move(task_runner));
+}
+
+void WebResourceRequestSender::SetDefersLoading(WebURLLoader::DeferType value) {
+ if (!request_info_) {
+ DLOG(ERROR) << "unknown request";
+ return;
+ }
+ if (value != WebURLLoader::DeferType::kNotDeferred) {
+ request_info_->is_deferred = value;
+ request_info_->url_loader_client->SetDefersLoading(value);
+ } else if (request_info_->is_deferred !=
+ WebURLLoader::DeferType::kNotDeferred) {
+ request_info_->is_deferred = WebURLLoader::DeferType::kNotDeferred;
+ request_info_->url_loader_client->SetDefersLoading(
+ WebURLLoader::DeferType::kNotDeferred);
+
+ FollowPendingRedirect(request_info_.get());
+ }
+}
+
+void WebResourceRequestSender::DidChangePriority(
+ net::RequestPriority new_priority,
+ int intra_priority_value) {
+ if (!request_info_) {
+ DLOG(ERROR) << "unknown request";
+ return;
+ }
+
+ request_info_->url_loader->SetPriority(new_priority, intra_priority_value);
+}
+
+void WebResourceRequestSender::DeletePendingRequest(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ if (!request_info_)
+ return;
+
+ if (request_info_->net_error == net::ERR_IO_PENDING) {
+ request_info_->net_error = net::ERR_ABORTED;
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceLoadCanceled(request_info_->net_error);
+ }
+
+ // Cancel loading.
+ request_info_->url_loader.reset();
+
+ // Clear URLLoaderClient to stop receiving further Mojo IPC from the browser
+ // process.
+ request_info_->url_loader_client.reset();
+
+ // Always delete the `request_info_` asyncly so that cancelling the request
+ // doesn't delete the request context which the `request_info_->peer` points
+ // to while its response is still being handled.
+ task_runner->DeleteSoon(FROM_HERE, request_info_.release());
+}
+
+WebResourceRequestSender::PendingRequestInfo::PendingRequestInfo(
+ scoped_refptr<WebRequestPeer> peer,
+ network::mojom::RequestDestination request_destination,
+ int render_frame_id,
+ const GURL& request_url,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper)
+ : peer(std::move(peer)),
+ request_destination(request_destination),
+ render_frame_id(render_frame_id),
+ url(request_url),
+ response_url(request_url),
+ local_request_start(base::TimeTicks::Now()),
+ resource_load_info_notifier_wrapper(
+ std::move(resource_load_info_notifier_wrapper)) {}
+
+WebResourceRequestSender::PendingRequestInfo::~PendingRequestInfo() = default;
+
+void WebResourceRequestSender::FollowPendingRedirect(
+ PendingRequestInfo* request_info) {
+ if (request_info->has_pending_redirect &&
+ request_info->should_follow_redirect) {
+ request_info->has_pending_redirect = false;
+ // net::URLRequest clears its request_start on redirect, so should we.
+ request_info->local_request_start = base::TimeTicks::Now();
+ // Redirect URL may not be handled by the network service, so force a
+ // restart in case another URLLoaderFactory should handle the URL.
+ if (request_info->redirect_requires_loader_restart) {
+ request_info->url_loader->FollowRedirectForcingRestart();
+ } else {
+ std::vector<std::string> removed_headers(
+ request_info_->removed_headers.size());
+ std::transform(request_info_->removed_headers.begin(),
+ request_info_->removed_headers.end(),
+ removed_headers.begin(),
+ [](const WebString& h) { return h.Ascii(); });
+ request_info->url_loader->FollowRedirect(
+ removed_headers, {} /* modified_headers */,
+ {} /* modified_cors_exempt_headers */);
+ }
+ }
+}
+
+void WebResourceRequestSender::OnTransferSizeUpdated(
+ int32_t transfer_size_diff) {
+ DCHECK_GT(transfer_size_diff, 0);
+ if (!request_info_)
+ return;
+
+ // TODO(yhirano): Consider using int64_t in
+ // WebRequestPeer::OnTransferSizeUpdated.
+ request_info_->peer->OnTransferSizeUpdated(transfer_size_diff);
+ if (!request_info_)
+ return;
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceTransferSizeUpdated(transfer_size_diff);
+}
+
+void WebResourceRequestSender::OnUploadProgress(int64_t position,
+ int64_t size) {
+ if (!request_info_)
+ return;
+
+ request_info_->peer->OnUploadProgress(position, size);
+}
+
+void WebResourceRequestSender::OnReceivedResponse(
+ network::mojom::URLResponseHeadPtr response_head) {
+ TRACE_EVENT0("loading", "WebResourceRequestSender::OnReceivedResponse");
+ if (!request_info_)
+ return;
+ request_info_->local_response_start = base::TimeTicks::Now();
+ request_info_->remote_request_start =
+ response_head->load_timing.request_start;
+ // Now that response_start has been set, we can properly set the TimeTicks in
+ // the URLResponseHead.
+ ToLocalURLResponseHead(*request_info_, *response_head);
+ request_info_->load_timing_info = response_head->load_timing;
+ if (delegate_) {
+ scoped_refptr<WebRequestPeer> new_peer = delegate_->OnReceivedResponse(
+ std::move(request_info_->peer),
+ WebString::FromUTF8(response_head->mime_type),
+ KURL(request_info_->url));
+ DCHECK(new_peer);
+ request_info_->peer = std::move(new_peer);
+ }
+
+ request_info_->peer->OnReceivedResponse(response_head.Clone());
+ if (!request_info_)
+ return;
+
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceResponseReceived(std::move(response_head),
+ request_info_->previews_state);
+}
+
+void WebResourceRequestSender::OnReceivedCachedMetadata(
+ mojo_base::BigBuffer data) {
+ if (!request_info_)
+ return;
+
+ if (data.size()) {
+ request_info_->peer->OnReceivedCachedMetadata(std::move(data));
+ }
+}
+
+void WebResourceRequestSender::OnReceivedRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr response_head,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ TRACE_EVENT0("loading", "WebResourceRequestSender::OnReceivedRedirect");
+ if (!request_info_)
+ return;
+ if (!request_info_->url_loader && request_info_->should_follow_redirect) {
+ // This is a redirect that synchronously came as the loader is being
+ // constructed, due to a URLLoaderThrottle that changed the starting
+ // URL. Handle this in a posted task, as we don't have the loader
+ // pointer yet.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&WebResourceRequestSender::OnReceivedRedirect,
+ weak_factory_.GetWeakPtr(), redirect_info,
+ std::move(response_head), task_runner));
+ return;
+ }
+
+ request_info_->local_response_start = base::TimeTicks::Now();
+ request_info_->remote_request_start =
+ response_head->load_timing.request_start;
+ request_info_->redirect_requires_loader_restart =
+ RedirectRequiresLoaderRestart(request_info_->response_url,
+ redirect_info.new_url);
+
+ ToLocalURLResponseHead(*request_info_, *response_head);
+ std::vector<std::string> removed_headers;
+ if (request_info_->peer->OnReceivedRedirect(
+ redirect_info, response_head.Clone(), &removed_headers)) {
+ // Double-check if the request is still around. The call above could
+ // potentially remove it.
+ if (!request_info_)
+ return;
+ // TODO(yoav): If request_info doesn't change above, we could avoid this
+ // copy.
+ WebVector<WebString> vector(removed_headers.size());
+ std::transform(
+ removed_headers.begin(), removed_headers.end(), vector.begin(),
+ [](const std::string& h) { return WebString::FromASCII(h); });
+ request_info_->removed_headers = vector;
+ request_info_->response_url = redirect_info.new_url;
+ request_info_->has_pending_redirect = true;
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceRedirectReceived(redirect_info,
+ std::move(response_head));
+
+ if (request_info_->is_deferred == WebURLLoader::DeferType::kNotDeferred)
+ FollowPendingRedirect(request_info_.get());
+ } else {
+ Cancel(std::move(task_runner));
+ }
+}
+
+void WebResourceRequestSender::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ TRACE_EVENT0("loading",
+ "WebResourceRequestSender::OnStartLoadingResponseBody");
+
+ if (!request_info_)
+ return;
+ request_info_->peer->OnStartLoadingResponseBody(std::move(body));
+}
+
+void WebResourceRequestSender::OnRequestComplete(
+ const network::URLLoaderCompletionStatus& status) {
+ TRACE_EVENT0("loading", "WebResourceRequestSender::OnRequestComplete");
+
+ if (!request_info_)
+ return;
+ request_info_->net_error = status.error_code;
+
+ request_info_->resource_load_info_notifier_wrapper
+ ->NotifyResourceLoadCompleted(status);
+
+ WebRequestPeer* peer = request_info_->peer.get();
+
+ if (delegate_) {
+ delegate_->OnRequestComplete();
+ }
+
+ network::URLLoaderCompletionStatus renderer_status(status);
+ if (status.completion_time.is_null()) {
+ // No completion timestamp is provided, leave it as is.
+ } else if (request_info_->remote_request_start.is_null() ||
+ request_info_->load_timing_info.request_start.is_null()) {
+ // We cannot convert the remote time to a local time, let's use the current
+ // timestamp. This happens when
+ // - We get an error before OnReceivedRedirect or OnReceivedResponse is
+ // called, or
+ // - Somehow such a timestamp was missing in the LoadTimingInfo.
+ renderer_status.completion_time = base::TimeTicks::Now();
+ } else {
+ // We have already converted the request start timestamp, let's use that
+ // conversion information.
+ // Note: We cannot create a InterProcessTimeTicksConverter with
+ // (local_request_start, now, remote_request_start, remote_completion_time)
+ // as that may result in inconsistent timestamps.
+ renderer_status.completion_time =
+ std::min(status.completion_time - request_info_->remote_request_start +
+ request_info_->load_timing_info.request_start,
+ base::TimeTicks::Now());
+ }
+ // The request ID will be removed from our pending list in the destructor.
+ // Normally, dispatching this message causes the reference-counted request to
+ // die immediately.
+ // TODO(kinuko): Revisit here. This probably needs to call request_info_->peer
+ // but the past attempt to change it seems to have caused crashes.
+ // (crbug.com/547047)
+ peer->OnCompletedRequest(renderer_status);
+}
+
+void WebResourceRequestSender::ToLocalURLResponseHead(
+ const PendingRequestInfo& request_info,
+ network::mojom::URLResponseHead& response_head) const {
+ if (base::TimeTicks::IsConsistentAcrossProcesses() ||
+ request_info.local_request_start.is_null() ||
+ request_info.local_response_start.is_null() ||
+ response_head.request_start.is_null() ||
+ response_head.response_start.is_null() ||
+ response_head.load_timing.request_start.is_null()) {
+ return;
+ }
+ InterProcessTimeTicksConverter converter(
+ LocalTimeTicks::FromTimeTicks(request_info.local_request_start),
+ LocalTimeTicks::FromTimeTicks(request_info.local_response_start),
+ RemoteTimeTicks::FromTimeTicks(response_head.request_start),
+ RemoteTimeTicks::FromTimeTicks(response_head.response_start));
+
+ net::LoadTimingInfo* load_timing = &response_head.load_timing;
+ RemoteToLocalTimeTicks(converter, &load_timing->request_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->proxy_resolve_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.dns_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.connect_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->connect_timing.ssl_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->send_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->send_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->push_start);
+ RemoteToLocalTimeTicks(converter, &load_timing->push_end);
+ RemoteToLocalTimeTicks(converter, &load_timing->service_worker_start_time);
+ RemoteToLocalTimeTicks(converter, &load_timing->service_worker_ready_time);
+ RemoteToLocalTimeTicks(converter, &load_timing->service_worker_fetch_start);
+ RemoteToLocalTimeTicks(converter,
+ &load_timing->service_worker_respond_with_settled);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender_unittest.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender_unittest.cc
new file mode 100644
index 00000000000..48e373a8be6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender_unittest.cc
@@ -0,0 +1,561 @@
+// 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/platform/web_resource_request_sender.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_response_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/loader/referrer_utils.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_request_peer.h"
+#include "third_party/blink/public/platform/web_resource_request_sender_delegate.h"
+#include "third_party/blink/public/platform/web_url_request_extra_data.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+#include "url/gurl.h"
+
+namespace blink {
+
+namespace {
+
+static constexpr char kTestPageUrl[] = "http://www.google.com/";
+static constexpr char kTestPageHeaders[] =
+ "HTTP/1.1 200 OK\nContent-Type:text/html\n\n";
+static constexpr char kTestPageMimeType[] = "text/html";
+static constexpr char kTestPageCharset[] = "";
+static constexpr char kTestPageContents[] =
+ "<html><head><title>Google</title></head><body><h1>Google</h1></body></"
+ "html>";
+
+constexpr size_t kDataPipeCapacity = 4096;
+
+std::string ReadOneChunk(mojo::ScopedDataPipeConsumerHandle* handle) {
+ char buffer[kDataPipeCapacity];
+ uint32_t read_bytes = kDataPipeCapacity;
+ MojoResult result =
+ (*handle)->ReadData(buffer, &read_bytes, MOJO_READ_DATA_FLAG_NONE);
+ if (result != MOJO_RESULT_OK)
+ return "";
+ return std::string(buffer, read_bytes);
+}
+
+// Returns a fake TimeTicks based on the given microsecond offset.
+base::TimeTicks TicksFromMicroseconds(int64_t micros) {
+ return base::TimeTicks() + base::TimeDelta::FromMicroseconds(micros);
+}
+
+} // namespace
+
+class TestResourceRequestSenderDelegate
+ : public WebResourceRequestSenderDelegate {
+ public:
+ TestResourceRequestSenderDelegate() = default;
+ ~TestResourceRequestSenderDelegate() override = default;
+
+ void OnRequestComplete() override {}
+
+ scoped_refptr<WebRequestPeer> OnReceivedResponse(
+ scoped_refptr<WebRequestPeer> current_peer,
+ const WebString& mime_type,
+ const WebURL& url) override {
+ return base::MakeRefCounted<WrapperPeer>(std::move(current_peer));
+ }
+
+ class WrapperPeer : public WebRequestPeer {
+ public:
+ explicit WrapperPeer(scoped_refptr<WebRequestPeer> original_peer)
+ : original_peer_(std::move(original_peer)) {}
+
+ // WebRequestPeer overrides:
+ void OnUploadProgress(uint64_t position, uint64_t size) override {}
+ bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>*) override {
+ return false;
+ }
+ void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override {
+ response_head_ = std::move(head);
+ }
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override {
+ body_handle_ = std::move(body);
+ }
+ void OnTransferSizeUpdated(int transfer_size_diff) override {}
+ void OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) override {
+ original_peer_->OnReceivedResponse(std::move(response_head_));
+ original_peer_->OnStartLoadingResponseBody(std::move(body_handle_));
+ original_peer_->OnCompletedRequest(status);
+ }
+
+ private:
+ scoped_refptr<WebRequestPeer> original_peer_;
+ network::mojom::URLResponseHeadPtr response_head_;
+ mojo::ScopedDataPipeConsumerHandle body_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(WrapperPeer);
+ };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestResourceRequestSenderDelegate);
+};
+
+// A mock WebRequestPeer to receive messages from the WebResourceRequestSender.
+class MockRequestPeer : public WebRequestPeer {
+ public:
+ explicit MockRequestPeer(WebResourceRequestSender* resource_request_sender)
+ : resource_request_sender_(resource_request_sender) {}
+
+ // WebRequestPeer overrides:
+ void OnUploadProgress(uint64_t position, uint64_t size) override {}
+ bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>* removed_headers) override {
+ last_load_timing_ = head->load_timing;
+ return true;
+ }
+ void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override {
+ last_load_timing_ = head->load_timing;
+ received_response_ = true;
+ if (cancel_on_receive_response_) {
+ resource_request_sender_->Cancel(
+ scheduler::GetSingleThreadTaskRunnerForTesting());
+ }
+ }
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override {
+ if (cancel_on_receive_response_)
+ return;
+ if (body) {
+ data_ += ReadOneChunk(&body);
+ }
+ }
+ void OnTransferSizeUpdated(int transfer_size_diff) override {}
+ void OnReceivedCachedMetadata(mojo_base::BigBuffer data) override {}
+ void OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) override {
+ if (cancel_on_receive_response_)
+ return;
+ completion_status_ = status;
+ complete_ = true;
+ }
+
+ std::string data() { return data_; }
+ bool received_response() { return received_response_; }
+ bool complete() { return complete_; }
+ net::LoadTimingInfo last_load_timing() { return last_load_timing_; }
+ network::URLLoaderCompletionStatus completion_status() {
+ return completion_status_;
+ }
+
+ void SetCancelOnReceiveResponse(bool cancel_on_receive_response) {
+ cancel_on_receive_response_ = cancel_on_receive_response;
+ }
+
+ private:
+ // Data received. If downloading to file, remains empty.
+ std::string data_;
+
+ bool received_response_ = false;
+ bool complete_ = false;
+ bool cancel_on_receive_response_ = false;
+ net::LoadTimingInfo last_load_timing_;
+ network::URLLoaderCompletionStatus completion_status_;
+ WebResourceRequestSender* resource_request_sender_ = nullptr;
+}; // namespace blink
+
+// Sets up the message sender override for the unit test.
+class WebResourceRequestSenderTest : public testing::Test,
+ public network::mojom::URLLoaderFactory {
+ public:
+ explicit WebResourceRequestSenderTest()
+ : platform_(&delegate_),
+ resource_request_sender_(new WebResourceRequestSender()) {}
+
+ ~WebResourceRequestSenderTest() override {
+ resource_request_sender_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& annotation) override {
+ loader_and_clients_.emplace_back(std::move(receiver), std::move(client));
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
+ override {
+ NOTREACHED();
+ }
+
+ void CallOnReceiveResponse(network::mojom::URLLoaderClient* client) {
+ auto head = network::mojom::URLResponseHead::New();
+ std::string raw_headers(kTestPageHeaders);
+ std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
+ head->headers = new net::HttpResponseHeaders(raw_headers);
+ head->mime_type = kTestPageMimeType;
+ head->charset = kTestPageCharset;
+ client->OnReceiveResponse(std::move(head));
+ }
+
+ std::unique_ptr<network::ResourceRequest> CreateResourceRequest() {
+ std::unique_ptr<network::ResourceRequest> request(
+ new network::ResourceRequest());
+
+ request->method = "GET";
+ request->url = GURL(kTestPageUrl);
+ request->site_for_cookies =
+ net::SiteForCookies::FromUrl(GURL(kTestPageUrl));
+ request->referrer_policy = ReferrerUtils::GetDefaultNetReferrerPolicy();
+ request->resource_type =
+ static_cast<int>(mojom::ResourceType::kSubResource);
+ request->priority = net::LOW;
+ request->mode = network::mojom::RequestMode::kNoCors;
+
+ auto url_request_extra_data =
+ base::MakeRefCounted<WebURLRequestExtraData>();
+ url_request_extra_data->CopyToResourceRequest(request.get());
+
+ return request;
+ }
+
+ WebResourceRequestSender* sender() { return resource_request_sender_.get(); }
+
+ void StartAsync(std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<WebRequestPeer> peer) {
+ sender()->SendAsync(
+ std::move(request), 0, scheduler::GetSingleThreadTaskRunnerForTesting(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, false, WebVector<WebString>(),
+ std::move(peer),
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(this),
+ std::vector<std::unique_ptr<URLLoaderThrottle>>(),
+ std::make_unique<ResourceLoadInfoNotifierWrapper>(
+ /*resource_load_info_notifier=*/nullptr),
+ WebBackForwardCacheLoaderHelper());
+ }
+
+ static MojoCreateDataPipeOptions DataPipeOptions() {
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = kDataPipeCapacity;
+ return options;
+ }
+
+ class TestPlatform final : public TestingPlatformSupport {
+ public:
+ explicit TestPlatform(WebResourceRequestSenderDelegate* delegate)
+ : delegate_(delegate) {}
+ WebResourceRequestSenderDelegate* GetResourceRequestSenderDelegate()
+ override {
+ return delegate_;
+ }
+
+ private:
+ WebResourceRequestSenderDelegate* delegate_;
+ };
+
+ protected:
+ std::vector<std::pair<mojo::PendingReceiver<network::mojom::URLLoader>,
+ mojo::PendingRemote<network::mojom::URLLoaderClient>>>
+ loader_and_clients_;
+ TestResourceRequestSenderDelegate delegate_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ ScopedTestingPlatformSupport<TestPlatform, WebResourceRequestSenderDelegate*>
+ platform_;
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender_;
+
+ scoped_refptr<MockRequestPeer> mock_peer_;
+};
+
+// Tests the generation of unique request ids.
+TEST_F(WebResourceRequestSenderTest, MakeRequestID) {
+ int first_id = WebResourceRequestSender::MakeRequestID();
+ int second_id = WebResourceRequestSender::MakeRequestID();
+
+ // Child process ids are unique (per process) and counting from 0 upwards:
+ EXPECT_GT(second_id, first_id);
+ EXPECT_GE(first_id, 0);
+}
+
+TEST_F(WebResourceRequestSenderTest, DelegateTest) {
+ std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+ mock_peer_ =
+ base::MakeRefCounted<MockRequestPeer>(resource_request_sender_.get());
+ StartAsync(std::move(request), mock_peer_);
+
+ ASSERT_EQ(1u, loader_and_clients_.size());
+ mojo::Remote<network::mojom::URLLoaderClient> client(
+ std::move(loader_and_clients_[0].second));
+ loader_and_clients_.clear();
+
+ // The wrapper eats all messages until RequestComplete message is sent.
+ CallOnReceiveResponse(client.get());
+
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ auto options = DataPipeOptions();
+ ASSERT_EQ(mojo::CreateDataPipe(&options, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
+ client->OnStartLoadingResponseBody(std::move(consumer_handle));
+
+ uint32_t size = strlen(kTestPageContents);
+ auto result = producer_handle->WriteData(kTestPageContents, &size,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(result, MOJO_RESULT_OK);
+ ASSERT_EQ(size, strlen(kTestPageContents));
+
+ producer_handle.reset();
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(mock_peer_->received_response());
+
+ // This lets the wrapper peer pass all the messages to the original
+ // peer at once.
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.exists_in_cache = false;
+ status.encoded_data_length = strlen(kTestPageContents);
+ client->OnComplete(status);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(mock_peer_->received_response());
+ EXPECT_EQ(kTestPageContents, mock_peer_->data());
+ EXPECT_TRUE(mock_peer_->complete());
+}
+
+TEST_F(WebResourceRequestSenderTest, CancelDuringCallbackWithWrapperPeer) {
+ std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+ mock_peer_ =
+ base::MakeRefCounted<MockRequestPeer>(resource_request_sender_.get());
+ mock_peer_->SetCancelOnReceiveResponse(true);
+ StartAsync(std::move(request), mock_peer_);
+
+ ASSERT_EQ(1u, loader_and_clients_.size());
+ mojo::Remote<network::mojom::URLLoaderClient> client(
+ std::move(loader_and_clients_[0].second));
+ loader_and_clients_.clear();
+
+ CallOnReceiveResponse(client.get());
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ auto options = DataPipeOptions();
+ ASSERT_EQ(mojo::CreateDataPipe(&options, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
+ client->OnStartLoadingResponseBody(std::move(consumer_handle));
+ uint32_t size = strlen(kTestPageContents);
+ auto result = producer_handle->WriteData(kTestPageContents, &size,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ ASSERT_EQ(result, MOJO_RESULT_OK);
+ ASSERT_EQ(size, strlen(kTestPageContents));
+ producer_handle.reset();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(mock_peer_->received_response());
+
+ // This lets the wrapper peer pass all the messages to the original
+ // peer at once, but the original peer cancels right after it receives
+ // the response. (This will remove pending request info from
+ // WebResourceRequestSender while the wrapper peer is still running
+ // OnCompletedRequest, but it should not lead to crashes.)
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.exists_in_cache = false;
+ status.encoded_data_length = strlen(kTestPageContents);
+ client->OnComplete(status);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(mock_peer_->received_response());
+ // Request should have been cancelled with no additional messages.
+ // EXPECT_TRUE(peer_context.cancelled);
+ EXPECT_EQ("", mock_peer_->data());
+ EXPECT_FALSE(mock_peer_->complete());
+}
+
+class TimeConversionTest : public WebResourceRequestSenderTest {
+ public:
+ void PerformTest(network::mojom::URLResponseHeadPtr response_head) {
+ std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+ StartAsync(std::move(request), mock_peer_);
+
+ ASSERT_EQ(1u, loader_and_clients_.size());
+ mojo::Remote<network::mojom::URLLoaderClient> client(
+ std::move(loader_and_clients_[0].second));
+ loader_and_clients_.clear();
+ client->OnReceiveResponse(std::move(response_head));
+ }
+
+ const network::mojom::URLResponseHead& response_info() const {
+ return *response_info_;
+ }
+
+ private:
+ network::mojom::URLResponseHeadPtr response_info_ =
+ network::mojom::URLResponseHead::New();
+};
+
+// TODO(simonjam): Enable this when 10829031 lands.
+TEST_F(TimeConversionTest, DISABLED_ProperlyInitialized) {
+ auto response_head = network::mojom::URLResponseHead::New();
+ response_head->request_start = TicksFromMicroseconds(5);
+ response_head->response_start = TicksFromMicroseconds(15);
+ response_head->load_timing.request_start_time = base::Time::Now();
+ response_head->load_timing.request_start = TicksFromMicroseconds(10);
+ response_head->load_timing.connect_timing.connect_start =
+ TicksFromMicroseconds(13);
+
+ auto request_start = response_head->load_timing.request_start;
+ PerformTest(std::move(response_head));
+
+ EXPECT_LT(base::TimeTicks(), response_info().load_timing.request_start);
+ EXPECT_EQ(base::TimeTicks(),
+ response_info().load_timing.connect_timing.dns_start);
+ EXPECT_LE(request_start,
+ response_info().load_timing.connect_timing.connect_start);
+}
+
+TEST_F(TimeConversionTest, PartiallyInitialized) {
+ auto response_head = network::mojom::URLResponseHead::New();
+ response_head->request_start = TicksFromMicroseconds(5);
+ response_head->response_start = TicksFromMicroseconds(15);
+
+ PerformTest(std::move(response_head));
+
+ EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
+ EXPECT_EQ(base::TimeTicks(),
+ response_info().load_timing.connect_timing.dns_start);
+}
+
+TEST_F(TimeConversionTest, NotInitialized) {
+ auto response_head = network::mojom::URLResponseHead::New();
+
+ PerformTest(std::move(response_head));
+
+ EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
+ EXPECT_EQ(base::TimeTicks(),
+ response_info().load_timing.connect_timing.dns_start);
+}
+
+class CompletionTimeConversionTest : public WebResourceRequestSenderTest {
+ public:
+ void PerformTest(base::TimeTicks remote_request_start,
+ base::TimeTicks completion_time,
+ base::TimeDelta delay) {
+ std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+ mock_peer_ =
+ base::MakeRefCounted<MockRequestPeer>(resource_request_sender_.get());
+ StartAsync(std::move(request), mock_peer_);
+
+ ASSERT_EQ(1u, loader_and_clients_.size());
+ mojo::Remote<network::mojom::URLLoaderClient> client(
+ std::move(loader_and_clients_[0].second));
+ auto response_head = network::mojom::URLResponseHead::New();
+ response_head->request_start = remote_request_start;
+ response_head->load_timing.request_start = remote_request_start;
+ response_head->load_timing.receive_headers_end = remote_request_start;
+ // We need to put something non-null time, otherwise no values will be
+ // copied.
+ response_head->load_timing.request_start_time =
+ base::Time() + base::TimeDelta::FromSeconds(99);
+ client->OnReceiveResponse(std::move(response_head));
+
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle),
+ MOJO_RESULT_OK);
+ client->OnStartLoadingResponseBody(std::move(consumer_handle));
+ producer_handle.reset(); // The response is empty.
+
+ network::URLLoaderCompletionStatus status;
+ status.completion_time = completion_time;
+
+ client->OnComplete(status);
+
+ const base::TimeTicks until = base::TimeTicks::Now() + delay;
+ while (base::TimeTicks::Now() < until)
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+ base::RunLoop().RunUntilIdle();
+ loader_and_clients_.clear();
+ }
+
+ base::TimeTicks request_start() const {
+ EXPECT_TRUE(mock_peer_->received_response());
+ return mock_peer_->last_load_timing().request_start;
+ }
+ base::TimeTicks completion_time() const {
+ EXPECT_TRUE(mock_peer_->complete());
+ return mock_peer_->completion_status().completion_time;
+ }
+};
+
+TEST_F(CompletionTimeConversionTest, NullCompletionTimestamp) {
+ const auto remote_request_start =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(4);
+
+ PerformTest(remote_request_start, base::TimeTicks(), base::TimeDelta());
+
+ EXPECT_EQ(base::TimeTicks(), completion_time());
+}
+
+TEST_F(CompletionTimeConversionTest, RemoteRequestStartIsUnavailable) {
+ base::TimeTicks begin = base::TimeTicks::Now();
+
+ const auto remote_completion_time =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(8);
+
+ PerformTest(base::TimeTicks(), remote_completion_time, base::TimeDelta());
+
+ base::TimeTicks end = base::TimeTicks::Now();
+ EXPECT_LE(begin, completion_time());
+ EXPECT_LE(completion_time(), end);
+}
+
+TEST_F(CompletionTimeConversionTest, Convert) {
+ const auto remote_request_start =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(4);
+
+ const auto remote_completion_time =
+ remote_request_start + base::TimeDelta::FromMilliseconds(3);
+
+ PerformTest(remote_request_start, remote_completion_time,
+ base::TimeDelta::FromMilliseconds(15));
+
+ EXPECT_EQ(completion_time(),
+ request_start() + base::TimeDelta::FromMilliseconds(3));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
new file mode 100644
index 00000000000..bfd4e078fef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
@@ -0,0 +1,1172 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_url_loader.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check_op.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "net/base/filename_util.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/ct_sct_to_string.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/ssl/ssl_cipher_suite_names.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_info.h"
+#include "services/network/public/cpp/http_raw_request_response_info.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
+#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/loader/mime_sniffing_throttle.h"
+#include "third_party/blink/public/common/loader/previews_state.h"
+#include "third_party/blink/public/common/loader/referrer_utils.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "third_party/blink/public/common/net/ip_address_space_util.h"
+#include "third_party/blink/public/common/security/security_style.h"
+#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom.h"
+#include "third_party/blink/public/platform/file_path_conversion.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
+#include "third_party/blink/public/platform/url_conversion.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_http_load_info.h"
+#include "third_party/blink/public/platform/web_request_peer.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "third_party/blink/public/platform/web_url_loader_client.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_request_extra_data.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_security_policy.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "url/origin.h"
+
+using base::Time;
+using base::TimeTicks;
+using blink::scheduler::WebResourceLoadingTaskRunnerHandle;
+
+namespace blink {
+
+// Utilities -------------------------------------------------------------------
+
+namespace {
+
+// Converts timing data from |load_timing| to the mojo type.
+network::mojom::LoadTimingInfo ToMojoLoadTiming(
+ const net::LoadTimingInfo& load_timing) {
+ DCHECK(!load_timing.request_start.is_null());
+
+ return network::mojom::LoadTimingInfo(
+ load_timing.socket_reused, load_timing.socket_log_id,
+ load_timing.request_start_time, load_timing.request_start,
+ load_timing.proxy_resolve_start, load_timing.proxy_resolve_end,
+ load_timing.connect_timing, load_timing.send_start, load_timing.send_end,
+ load_timing.receive_headers_start, load_timing.receive_headers_end,
+ load_timing.receive_non_informational_headers_start,
+ load_timing.first_early_hints_time, load_timing.push_start,
+ load_timing.push_end, load_timing.service_worker_start_time,
+ load_timing.service_worker_ready_time,
+ load_timing.service_worker_fetch_start,
+ load_timing.service_worker_respond_with_settled);
+}
+
+// This is complementary to ConvertNetPriorityToWebKitPriority, defined in
+// service_worker_context_client.cc.
+// TODO(yhirano): Move this to blink/platform/loader.
+net::RequestPriority ConvertWebKitPriorityToNetPriority(
+ const WebURLRequest::Priority& priority) {
+ switch (priority) {
+ case WebURLRequest::Priority::kVeryHigh:
+ return net::HIGHEST;
+
+ case WebURLRequest::Priority::kHigh:
+ return net::MEDIUM;
+
+ case WebURLRequest::Priority::kMedium:
+ return net::LOW;
+
+ case WebURLRequest::Priority::kLow:
+ return net::LOWEST;
+
+ case WebURLRequest::Priority::kVeryLow:
+ return net::IDLE;
+
+ case WebURLRequest::Priority::kUnresolved:
+ default:
+ NOTREACHED();
+ return net::LOW;
+ }
+}
+
+// Convert a net::SignedCertificateTimestampAndStatus object to a
+// WebURLResponse::SignedCertificateTimestamp object.
+WebURLResponse::SignedCertificateTimestamp NetSCTToBlinkSCT(
+ const net::SignedCertificateTimestampAndStatus& sct_and_status) {
+ return WebURLResponse::SignedCertificateTimestamp(
+ WebString::FromASCII(net::ct::StatusToString(sct_and_status.status)),
+ WebString::FromASCII(net::ct::OriginToString(sct_and_status.sct->origin)),
+ WebString::FromUTF8(sct_and_status.sct->log_description),
+ WebString::FromASCII(
+ base::HexEncode(sct_and_status.sct->log_id.c_str(),
+ sct_and_status.sct->log_id.length())),
+ sct_and_status.sct->timestamp.ToJavaTime(),
+ WebString::FromASCII(net::ct::HashAlgorithmToString(
+ sct_and_status.sct->signature.hash_algorithm)),
+ WebString::FromASCII(net::ct::SignatureAlgorithmToString(
+ sct_and_status.sct->signature.signature_algorithm)),
+ WebString::FromASCII(base::HexEncode(
+ sct_and_status.sct->signature.signature_data.c_str(),
+ sct_and_status.sct->signature.signature_data.length())));
+}
+
+WebString CryptoBufferAsWebString(const CRYPTO_BUFFER* buffer) {
+ base::StringPiece sp = net::x509_util::CryptoBufferAsStringPiece(buffer);
+ return WebString::FromLatin1(reinterpret_cast<const WebLChar*>(sp.begin()),
+ sp.size());
+}
+
+void SetSecurityStyleAndDetails(const GURL& url,
+ const network::mojom::URLResponseHead& head,
+ WebURLResponse* response,
+ bool report_security_info) {
+ if (!report_security_info) {
+ response->SetSecurityStyle(SecurityStyle::kUnknown);
+ return;
+ }
+ if (!url.SchemeIsCryptographic()) {
+ // Some origins are considered secure even though they're not cryptographic,
+ // so treat them as secure in the UI.
+ if (network::IsUrlPotentiallyTrustworthy(url))
+ response->SetSecurityStyle(SecurityStyle::kSecure);
+ else
+ response->SetSecurityStyle(SecurityStyle::kInsecure);
+ return;
+ }
+
+ // The resource loader does not provide a guarantee that requests always have
+ // security info (such as a certificate) attached. Use SecurityStyleUnknown
+ // in this case where there isn't enough information to be useful.
+ if (!head.ssl_info.has_value()) {
+ response->SetSecurityStyle(SecurityStyle::kUnknown);
+ return;
+ }
+
+ const net::SSLInfo& ssl_info = *head.ssl_info;
+
+ const char* protocol = "";
+ const char* key_exchange = "";
+ const char* cipher = "";
+ const char* mac = "";
+ const char* key_exchange_group = "";
+
+ if (ssl_info.connection_status) {
+ int ssl_version =
+ net::SSLConnectionStatusToVersion(ssl_info.connection_status);
+ net::SSLVersionToString(&protocol, ssl_version);
+
+ bool is_aead;
+ bool is_tls13;
+ uint16_t cipher_suite =
+ net::SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
+ net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
+ &is_tls13, cipher_suite);
+ if (!key_exchange) {
+ DCHECK(is_tls13);
+ key_exchange = "";
+ }
+
+ if (!mac) {
+ DCHECK(is_aead);
+ mac = "";
+ }
+
+ if (ssl_info.key_exchange_group != 0) {
+ // Historically the field was named 'curve' rather than 'group'.
+ key_exchange_group = SSL_get_curve_name(ssl_info.key_exchange_group);
+ if (!key_exchange_group) {
+ NOTREACHED();
+ key_exchange_group = "";
+ }
+ }
+ }
+
+ if (net::IsCertStatusError(head.cert_status)) {
+ response->SetSecurityStyle(SecurityStyle::kInsecure);
+ } else {
+ response->SetSecurityStyle(SecurityStyle::kSecure);
+ }
+
+ WebURLResponse::SignedCertificateTimestampList sct_list(
+ ssl_info.signed_certificate_timestamps.size());
+
+ for (size_t i = 0; i < sct_list.size(); ++i)
+ sct_list[i] = NetSCTToBlinkSCT(ssl_info.signed_certificate_timestamps[i]);
+
+ if (!ssl_info.cert) {
+ NOTREACHED();
+ response->SetSecurityStyle(SecurityStyle::kUnknown);
+ return;
+ }
+
+ std::vector<std::string> san_dns;
+ std::vector<std::string> san_ip;
+ ssl_info.cert->GetSubjectAltName(&san_dns, &san_ip);
+ WebVector<WebString> web_san(san_dns.size() + san_ip.size());
+ std::transform(san_dns.begin(), san_dns.end(), web_san.begin(),
+ [](const std::string& h) { return WebString::FromLatin1(h); });
+ std::transform(san_ip.begin(), san_ip.end(), web_san.begin() + san_dns.size(),
+ [](const std::string& h) {
+ net::IPAddress ip(reinterpret_cast<const uint8_t*>(h.data()),
+ h.size());
+ return WebString::FromLatin1(ip.ToString());
+ });
+
+ WebVector<WebString> web_cert;
+ web_cert.reserve(ssl_info.cert->intermediate_buffers().size() + 1);
+ web_cert.emplace_back(CryptoBufferAsWebString(ssl_info.cert->cert_buffer()));
+ for (const auto& cert : ssl_info.cert->intermediate_buffers())
+ web_cert.emplace_back(CryptoBufferAsWebString(cert.get()));
+
+ WebURLResponse::WebSecurityDetails webSecurityDetails(
+ WebString::FromASCII(protocol), WebString::FromASCII(key_exchange),
+ WebString::FromASCII(key_exchange_group), WebString::FromASCII(cipher),
+ WebString::FromASCII(mac),
+ WebString::FromUTF8(ssl_info.cert->subject().common_name), web_san,
+ WebString::FromUTF8(ssl_info.cert->issuer().common_name),
+ ssl_info.cert->valid_start().ToDoubleT(),
+ ssl_info.cert->valid_expiry().ToDoubleT(), web_cert, sct_list);
+
+ response->SetSecurityDetails(webSecurityDetails);
+}
+
+bool IsBannedCrossSiteAuth(
+ network::ResourceRequest* resource_request,
+ WebURLRequestExtraData* passed_url_request_extra_data) {
+ auto& request_url = resource_request->url;
+ auto& first_party = resource_request->site_for_cookies;
+
+ bool allow_cross_origin_auth_prompt = false;
+ if (passed_url_request_extra_data) {
+ WebURLRequestExtraData* url_request_extra_data =
+ static_cast<WebURLRequestExtraData*>(passed_url_request_extra_data);
+ allow_cross_origin_auth_prompt =
+ url_request_extra_data->allow_cross_origin_auth_prompt();
+ }
+
+ if (first_party.IsFirstPartyWithSchemefulMode(
+ request_url, /*compute_schemefully=*/false)) {
+ // If the first party is secure but the subresource is not, this is
+ // mixed-content. Do not allow the image.
+ if (!allow_cross_origin_auth_prompt &&
+ network::IsUrlPotentiallyTrustworthy(first_party.RepresentativeUrl()) &&
+ !network::IsUrlPotentiallyTrustworthy(request_url)) {
+ return true;
+ }
+ return false;
+ }
+
+ return !allow_cross_origin_auth_prompt;
+}
+
+} // namespace
+
+// This inner class exists since the WebURLLoader may be deleted while inside a
+// call to WebURLLoaderClient. Refcounting is to keep the context from
+// being deleted if it may have work to do after calling into the client.
+class WebURLLoader::Context : public WebRequestPeer {
+ public:
+ Context(WebURLLoader* loader,
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ freezable_task_runner_handle,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ unfreezable_task_runner_handle,
+ scoped_refptr<network::SharedURLLoaderFactory> factory,
+ mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper);
+
+ int request_id() const { return request_id_; }
+ WebURLLoaderClient* client() const { return client_; }
+ void set_client(WebURLLoaderClient* client) { client_ = client; }
+ scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner() {
+ return freezable_task_runner_;
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner() {
+ return unfreezable_task_runner_;
+ }
+
+ void Cancel();
+ void SetDefersLoading(WebURLLoader::DeferType value);
+ void DidChangePriority(WebURLRequest::Priority new_priority,
+ int intra_priority_value);
+ void Start(std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<WebURLRequestExtraData> url_request_extra_data,
+ int requestor_id,
+ bool pass_response_pipe_to_client,
+ bool no_mime_sniffing,
+ base::TimeDelta timeout_interval,
+ SyncLoadResponse* sync_load_response,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper);
+
+ // WebRequestPeer overrides:
+ void OnUploadProgress(uint64_t position, uint64_t size) override;
+ bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>* removed_headers) override;
+ void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnTransferSizeUpdated(int transfer_size_diff) override;
+ void OnReceivedCachedMetadata(mojo_base::BigBuffer data) override;
+ void OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) override;
+
+ void SetResourceRequestSenderForTesting( // IN-TEST
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender);
+
+ private:
+ // The maximal number of bytes consumed in a task. When there are more bytes
+ // in the data pipe, they will be consumed in following tasks. Setting a too
+ // small number will generate ton of tasks but setting a too large number will
+ // lead to thread janks. Also, some clients cannot handle too large chunks
+ // (512k for example).
+ static constexpr uint32_t kMaxNumConsumedBytesInTask = 64 * 1024;
+
+ ~Context() override;
+
+ // Called when the body data stream is detached from the reader side.
+ void CancelBodyStreaming();
+
+ void OnBodyAvailable(MojoResult, const mojo::HandleSignalsState&);
+ void OnBodyHasBeenRead(uint32_t read_bytes);
+
+ static net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag(
+ network::ResourceRequest* request);
+
+ WebURLLoader* loader_;
+
+ KURL url_;
+ // Controls SetSecurityStyleAndDetails() in PopulateURLResponse(). Initially
+ // set to WebURLRequest::ReportRawHeaders() in Start() and gets updated in
+ // WillFollowRedirect() (by the InspectorNetworkAgent) while the new
+ // ReportRawHeaders() value won't be propagated to the browser process.
+ //
+ // TODO(tyoshino): Investigate whether it's worth propagating the new value.
+ bool report_raw_headers_;
+
+ WebURLLoaderClient* client_;
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ freezable_task_runner_handle_;
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ unfreezable_task_runner_handle_;
+ scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner_;
+ mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle_;
+ WebURLLoader::DeferType defers_loading_;
+ const WebVector<WebString> cors_exempt_header_list_;
+ base::WaitableEvent* terminate_sync_load_event_;
+
+ int request_id_;
+ bool in_two_phase_read_ = false;
+ bool is_in_on_body_available_ = false;
+
+ base::Optional<network::URLLoaderCompletionStatus> completion_status_;
+
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender_;
+
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper_;
+};
+
+// WebURLLoader::Context -------------------------------------------------------
+
+// static
+constexpr uint32_t WebURLLoader::Context::kMaxNumConsumedBytesInTask;
+
+WebURLLoader::Context::Context(
+ WebURLLoader* loader,
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ freezable_task_runner_handle,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ unfreezable_task_runner_handle,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
+ : loader_(loader),
+ report_raw_headers_(false),
+ client_(nullptr),
+ freezable_task_runner_handle_(std::move(freezable_task_runner_handle)),
+ unfreezable_task_runner_handle_(
+ std::move(unfreezable_task_runner_handle)),
+ freezable_task_runner_(freezable_task_runner_handle_->GetTaskRunner()),
+ unfreezable_task_runner_(
+ unfreezable_task_runner_handle_->GetTaskRunner()),
+ keep_alive_handle_(std::move(keep_alive_handle)),
+ defers_loading_(WebURLLoader::DeferType::kNotDeferred),
+ cors_exempt_header_list_(cors_exempt_header_list),
+ terminate_sync_load_event_(terminate_sync_load_event),
+ request_id_(-1),
+ resource_request_sender_(std::make_unique<WebResourceRequestSender>()),
+ url_loader_factory_(std::move(url_loader_factory)),
+ back_forward_cache_loader_helper_(back_forward_cache_loader_helper) {
+ DCHECK(url_loader_factory_);
+}
+
+void WebURLLoader::Context::Cancel() {
+ TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::Cancel", this,
+ TRACE_EVENT_FLAG_FLOW_IN);
+ if (request_id_ != -1) {
+ resource_request_sender_->Cancel(freezable_task_runner_);
+ request_id_ = -1;
+ }
+
+ // Do not make any further calls to the client.
+ client_ = nullptr;
+ loader_ = nullptr;
+}
+
+void WebURLLoader::Context::SetDefersLoading(WebURLLoader::DeferType value) {
+ if (request_id_ != -1)
+ resource_request_sender_->SetDefersLoading(value);
+ defers_loading_ = value;
+}
+
+void WebURLLoader::Context::DidChangePriority(
+ WebURLRequest::Priority new_priority,
+ int intra_priority_value) {
+ if (request_id_ != -1) {
+ net::RequestPriority net_priority =
+ ConvertWebKitPriorityToNetPriority(new_priority);
+ resource_request_sender_->DidChangePriority(net_priority,
+ intra_priority_value);
+ freezable_task_runner_handle_->DidChangeRequestPriority(net_priority);
+ }
+}
+
+void WebURLLoader::Context::Start(
+ std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<WebURLRequestExtraData> passed_url_request_extra_data,
+ int requestor_id,
+ bool pass_response_pipe_to_client,
+ bool no_mime_sniffing,
+ base::TimeDelta timeout_interval,
+ SyncLoadResponse* sync_load_response,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper) {
+ DCHECK_EQ(request_id_, -1);
+
+ // Notify Blink's scheduler with the initial resource fetch priority.
+ freezable_task_runner_handle_->DidChangeRequestPriority(request->priority);
+
+ url_ = KURL(request->url);
+ report_raw_headers_ = request->report_raw_headers;
+
+ // TODO(horo): Check credentials flag is unset when credentials mode is omit.
+ // Check credentials flag is set when credentials mode is include.
+
+ const network::mojom::RequestDestination request_destination =
+ request->destination;
+
+ // TODO(yhirano): Move the logic below to blink/platform/loader.
+ if (!request->is_favicon &&
+ request_destination == network::mojom::RequestDestination::kImage &&
+ IsBannedCrossSiteAuth(request.get(),
+ passed_url_request_extra_data.get())) {
+ // Prevent third-party image content from prompting for login, as this
+ // is often a scam to extract credentials for another domain from the
+ // user. Only block image loads, as the attack applies largely to the
+ // "src" property of the <img> tag. It is common for web properties to
+ // allow untrusted values for <img src>; this is considered a fair thing
+ // for an HTML sanitizer to do. Conversely, any HTML sanitizer that didn't
+ // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags
+ // would be considered vulnerable in and of itself.
+ request->do_not_prompt_for_login = true;
+ request->load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
+ }
+
+ scoped_refptr<WebURLRequestExtraData> empty_url_request_extra_data;
+ WebURLRequestExtraData* url_request_extra_data;
+ if (passed_url_request_extra_data) {
+ url_request_extra_data = static_cast<WebURLRequestExtraData*>(
+ passed_url_request_extra_data.get());
+ } else {
+ empty_url_request_extra_data =
+ base::MakeRefCounted<WebURLRequestExtraData>();
+ url_request_extra_data = empty_url_request_extra_data.get();
+ }
+ url_request_extra_data->CopyToResourceRequest(request.get());
+
+ if (request->load_flags & net::LOAD_PREFETCH)
+ request->corb_detachable = true;
+
+ auto throttles =
+ url_request_extra_data->TakeURLLoaderThrottles().ReleaseVector();
+ // The frame request blocker is only for a frame's subresources.
+ if (url_request_extra_data->frame_request_blocker() &&
+ !IsRequestDestinationFrame(request_destination)) {
+ auto throttle = url_request_extra_data->frame_request_blocker()
+ ->GetThrottleIfRequestsBlocked();
+ if (throttle)
+ throttles.push_back(std::move(throttle));
+ }
+
+ // TODO(minggang): Remove the useage of render frame id.
+ Platform::Current()->AppendVariationsThrottles(request->render_frame_id,
+ &throttles);
+
+ uint32_t loader_options = network::mojom::kURLLoadOptionNone;
+ if (!no_mime_sniffing) {
+ loader_options |= network::mojom::kURLLoadOptionSniffMimeType;
+ throttles.push_back(
+ std::make_unique<MimeSniffingThrottle>(unfreezable_task_runner_));
+ }
+
+ if (sync_load_response) {
+ DCHECK(defers_loading_ == WebURLLoader::DeferType::kNotDeferred);
+
+ loader_options |= network::mojom::kURLLoadOptionSynchronous;
+ request->load_flags |= net::LOAD_IGNORE_LIMITS;
+
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry;
+ if (pass_response_pipe_to_client) {
+ Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ download_to_blob_registry.InitWithNewPipeAndPassReceiver());
+ }
+ net::NetworkTrafficAnnotationTag tag =
+ GetTrafficAnnotationTag(request.get());
+ resource_request_sender_->SendSync(
+ std::move(request), requestor_id, tag, loader_options,
+ sync_load_response, url_loader_factory_, std::move(throttles),
+ timeout_interval, cors_exempt_header_list_, terminate_sync_load_event_,
+ std::move(download_to_blob_registry), base::WrapRefCounted(this),
+ std::move(resource_load_info_notifier_wrapper),
+ back_forward_cache_loader_helper_);
+ return;
+ }
+
+ TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::Start", this,
+ TRACE_EVENT_FLAG_FLOW_OUT);
+ net::NetworkTrafficAnnotationTag tag = GetTrafficAnnotationTag(request.get());
+ request_id_ = resource_request_sender_->SendAsync(
+ std::move(request), requestor_id, unfreezable_task_runner_, tag,
+ loader_options, cors_exempt_header_list_, base::WrapRefCounted(this),
+ url_loader_factory_, std::move(throttles),
+ std::move(resource_load_info_notifier_wrapper),
+ back_forward_cache_loader_helper_);
+
+ if (defers_loading_ != WebURLLoader::DeferType::kNotDeferred) {
+ resource_request_sender_->SetDefersLoading(
+ WebURLLoader::DeferType::kDeferred);
+ }
+}
+
+void WebURLLoader::Context::OnUploadProgress(uint64_t position, uint64_t size) {
+ if (client_)
+ client_->DidSendData(position, size);
+}
+
+bool WebURLLoader::Context::OnReceivedRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head,
+ std::vector<std::string>* removed_headers) {
+ if (!client_)
+ return false;
+
+ TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::OnReceivedRedirect",
+ this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+
+ WebURLResponse response;
+ PopulateURLResponse(url_, *head, &response, report_raw_headers_, request_id_);
+
+ url_ = KURL(redirect_info.new_url);
+ return client_->WillFollowRedirect(
+ url_, redirect_info.new_site_for_cookies,
+ WebString::FromUTF8(redirect_info.new_referrer),
+ ReferrerUtils::NetToMojoReferrerPolicy(redirect_info.new_referrer_policy),
+ WebString::FromUTF8(redirect_info.new_method), response,
+ report_raw_headers_, removed_headers);
+}
+
+void WebURLLoader::Context::OnReceivedResponse(
+ network::mojom::URLResponseHeadPtr head) {
+ if (!client_)
+ return;
+
+ TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::Context::OnReceivedResponse",
+ this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+
+ // These headers must be stripped off before entering into the renderer
+ // (see also https://crbug.com/1019732).
+ DCHECK(!head->headers || !head->headers->HasHeader("set-cookie"));
+ DCHECK(!head->headers || !head->headers->HasHeader("set-cookie2"));
+ DCHECK(!head->headers || !head->headers->HasHeader("clear-site-data"));
+
+ WebURLResponse response;
+ PopulateURLResponse(url_, *head, &response, report_raw_headers_, request_id_);
+
+ client_->DidReceiveResponse(response);
+
+ // DidReceiveResponse() may have triggered a cancel, causing the |client_| to
+ // go away.
+ if (!client_)
+ return;
+}
+
+void WebURLLoader::Context::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ if (client_)
+ client_->DidStartLoadingResponseBody(std::move(body));
+
+ TRACE_EVENT_WITH_FLOW0(
+ "loading", "WebURLLoader::Context::OnStartLoadingResponseBody", this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+}
+
+void WebURLLoader::Context::OnTransferSizeUpdated(int transfer_size_diff) {
+ client_->DidReceiveTransferSizeUpdate(transfer_size_diff);
+}
+
+void WebURLLoader::Context::OnReceivedCachedMetadata(
+ mojo_base::BigBuffer data) {
+ if (!client_)
+ return;
+ TRACE_EVENT_WITH_FLOW1(
+ "loading", "WebURLLoader::Context::OnReceivedCachedMetadata", this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "length",
+ data.size());
+ client_->DidReceiveCachedMetadata(std::move(data));
+}
+
+void WebURLLoader::Context::OnCompletedRequest(
+ const network::URLLoaderCompletionStatus& status) {
+ int64_t total_transfer_size = status.encoded_data_length;
+ int64_t encoded_body_size = status.encoded_body_length;
+
+ if (client_) {
+ TRACE_EVENT_WITH_FLOW0("loading",
+ "WebURLLoader::Context::OnCompletedRequest", this,
+ TRACE_EVENT_FLAG_FLOW_IN);
+
+ if (status.error_code != net::OK) {
+ client_->DidFail(PopulateURLError(status, url_), status.completion_time,
+ total_transfer_size, encoded_body_size,
+ status.decoded_body_length);
+ } else {
+ client_->DidFinishLoading(status.completion_time, total_transfer_size,
+ encoded_body_size, status.decoded_body_length,
+ status.should_report_corb_blocking);
+ }
+ }
+}
+
+WebURLLoader::Context::~Context() {
+ // We must be already cancelled at this point.
+ DCHECK_LT(request_id_, 0);
+}
+
+void WebURLLoader::Context::CancelBodyStreaming() {
+ scoped_refptr<Context> protect(this);
+
+ if (client_) {
+ // TODO(yhirano): Set |stale_copy_in_cache| appropriately if possible.
+ client_->DidFail(WebURLError(net::ERR_ABORTED, url_),
+ base::TimeTicks::Now(),
+ WebURLLoaderClient::kUnknownEncodedDataLength, 0, 0);
+ }
+
+ // Notify the browser process that the request is canceled.
+ Cancel();
+}
+
+// WebURLLoader ----------------------------------------------------------------
+
+WebURLLoader::WebURLLoader(
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ freezable_task_runner_handle,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ unfreezable_task_runner_handle,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ mojo::PendingRemote<mojom::KeepAliveHandle> keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
+ : context_(new Context(this,
+ cors_exempt_header_list,
+ terminate_sync_load_event,
+ std::move(freezable_task_runner_handle),
+ std::move(unfreezable_task_runner_handle),
+ std::move(url_loader_factory),
+ std::move(keep_alive_handle),
+ back_forward_cache_loader_helper)) {}
+
+WebURLLoader::WebURLLoader() = default;
+
+WebURLLoader::~WebURLLoader() {
+ Cancel();
+}
+
+void WebURLLoader::PopulateURLResponse(
+ const WebURL& url,
+ const network::mojom::URLResponseHead& head,
+ WebURLResponse* response,
+ bool report_security_info,
+ int request_id) {
+ response->SetCurrentRequestUrl(url);
+ response->SetResponseTime(head.response_time);
+ response->SetMimeType(WebString::FromUTF8(head.mime_type));
+ response->SetTextEncodingName(WebString::FromUTF8(head.charset));
+ response->SetExpectedContentLength(head.content_length);
+ response->SetHasMajorCertificateErrors(
+ net::IsCertStatusError(head.cert_status));
+ response->SetCTPolicyCompliance(head.ct_policy_compliance);
+ response->SetIsLegacyTLSVersion(head.is_legacy_tls_version);
+ response->SetHasRangeRequested(head.has_range_requested);
+ response->SetTimingAllowPassed(head.timing_allow_passed);
+ response->SetAppCacheID(head.appcache_id);
+ response->SetAppCacheManifestURL(KURL(head.appcache_manifest_url));
+ response->SetWasCached(!head.load_timing.request_start_time.is_null() &&
+ head.response_time <
+ head.load_timing.request_start_time);
+ response->SetConnectionID(head.load_timing.socket_log_id);
+ response->SetConnectionReused(head.load_timing.socket_reused);
+ response->SetWasFetchedViaSPDY(head.was_fetched_via_spdy);
+ response->SetWasFetchedViaServiceWorker(head.was_fetched_via_service_worker);
+ response->SetServiceWorkerResponseSource(head.service_worker_response_source);
+ response->SetWasFallbackRequiredByServiceWorker(
+ head.was_fallback_required_by_service_worker);
+ response->SetType(head.response_type);
+ response->SetPadding(head.padding);
+ WebVector<KURL> url_list_via_service_worker(
+ head.url_list_via_service_worker.size());
+ std::transform(head.url_list_via_service_worker.begin(),
+ head.url_list_via_service_worker.end(),
+ url_list_via_service_worker.begin(),
+ [](const GURL& h) { return KURL(h); });
+ response->SetUrlListViaServiceWorker(url_list_via_service_worker);
+ response->SetCacheStorageCacheName(
+ head.service_worker_response_source ==
+ network::mojom::FetchResponseSource::kCacheStorage
+ ? WebString::FromUTF8(head.cache_storage_cache_name)
+ : WebString());
+
+ WebVector<WebString> dns_aliases(head.dns_aliases.size());
+ std::transform(head.dns_aliases.begin(), head.dns_aliases.end(),
+ dns_aliases.begin(),
+ [](const std::string& h) { return WebString::FromASCII(h); });
+ response->SetDnsAliases(dns_aliases);
+ response->SetRemoteIPEndpoint(head.remote_endpoint);
+ // This computation can only be done once SetUrlListViaServiceWorker() has
+ // been called on |response|, so that ResponseUrl() returns the correct
+ // answer.
+ //
+ // Implements: https://wicg.github.io/cors-rfc1918/#integration-html
+ response->SetAddressSpace(CalculateResourceAddressSpace(
+ KURL(response->ResponseUrl()), head.remote_endpoint.address()));
+
+ WebVector<WebString> cors_exposed_header_names(
+ head.cors_exposed_header_names.size());
+ std::transform(head.cors_exposed_header_names.begin(),
+ head.cors_exposed_header_names.end(),
+ cors_exposed_header_names.begin(),
+ [](const std::string& h) { return WebString::FromLatin1(h); });
+ response->SetCorsExposedHeaderNames(cors_exposed_header_names);
+ response->SetDidServiceWorkerNavigationPreload(
+ head.did_service_worker_navigation_preload);
+ response->SetEncodedDataLength(head.encoded_data_length);
+ response->SetEncodedBodyLength(head.encoded_body_length);
+ response->SetWasAlpnNegotiated(head.was_alpn_negotiated);
+ response->SetAlpnNegotiatedProtocol(
+ WebString::FromUTF8(head.alpn_negotiated_protocol));
+ response->SetWasAlternateProtocolAvailable(
+ head.was_alternate_protocol_available);
+ response->SetConnectionInfo(head.connection_info);
+ response->SetAsyncRevalidationRequested(head.async_revalidation_requested);
+ response->SetNetworkAccessed(head.network_accessed);
+ response->SetRequestId(request_id);
+ response->SetIsSignedExchangeInnerResponse(
+ head.is_signed_exchange_inner_response);
+ response->SetWasInPrefetchCache(head.was_in_prefetch_cache);
+ response->SetWasCookieInRequest(head.was_cookie_in_request);
+ response->SetRecursivePrefetchToken(head.recursive_prefetch_token);
+ response->SetWebBundleURL(KURL(head.web_bundle_url));
+
+ SetSecurityStyleAndDetails(KURL(url), head, response, report_security_info);
+
+ // If there's no received headers end time, don't set load timing. This is
+ // the case for non-HTTP requests, requests that don't go over the wire, and
+ // certain error cases.
+ if (!head.load_timing.receive_headers_end.is_null()) {
+ response->SetLoadTiming(ToMojoLoadTiming(head.load_timing));
+ }
+
+ if (head.raw_request_response_info.get()) {
+ WebHTTPLoadInfo load_info;
+
+ load_info.SetHTTPStatusCode(
+ head.raw_request_response_info->http_status_code);
+ load_info.SetHTTPStatusText(WebString::FromLatin1(
+ head.raw_request_response_info->http_status_text));
+
+ load_info.SetRequestHeadersText(WebString::FromLatin1(
+ head.raw_request_response_info->request_headers_text));
+ load_info.SetResponseHeadersText(WebString::FromLatin1(
+ head.raw_request_response_info->response_headers_text));
+ for (auto& header : head.raw_request_response_info->request_headers) {
+ load_info.AddRequestHeader(WebString::FromLatin1(header->key),
+ WebString::FromLatin1(header->value));
+ }
+ for (auto& header : head.raw_request_response_info->response_headers) {
+ load_info.AddResponseHeader(WebString::FromLatin1(header->key),
+ WebString::FromLatin1(header->value));
+ }
+ response->SetHTTPLoadInfo(load_info);
+ }
+
+ response->SetAuthChallengeInfo(head.auth_challenge_info);
+
+ const net::HttpResponseHeaders* headers = head.headers.get();
+ if (!headers)
+ return;
+
+ WebURLResponse::HTTPVersion version = WebURLResponse::kHTTPVersionUnknown;
+ if (headers->GetHttpVersion() == net::HttpVersion(0, 9))
+ version = WebURLResponse::kHTTPVersion_0_9;
+ else if (headers->GetHttpVersion() == net::HttpVersion(1, 0))
+ version = WebURLResponse::kHTTPVersion_1_0;
+ else if (headers->GetHttpVersion() == net::HttpVersion(1, 1))
+ version = WebURLResponse::kHTTPVersion_1_1;
+ else if (headers->GetHttpVersion() == net::HttpVersion(2, 0))
+ version = WebURLResponse::kHTTPVersion_2_0;
+ response->SetHttpVersion(version);
+ response->SetHttpStatusCode(headers->response_code());
+ response->SetHttpStatusText(WebString::FromLatin1(headers->GetStatusText()));
+
+ // Build up the header map.
+ size_t iter = 0;
+ std::string name;
+ std::string value;
+ while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ response->AddHttpHeaderField(WebString::FromLatin1(name),
+ WebString::FromLatin1(value));
+ }
+}
+
+// static
+WebURLError WebURLLoader::PopulateURLError(
+ const network::URLLoaderCompletionStatus& status,
+ const WebURL& url) {
+ DCHECK_NE(net::OK, status.error_code);
+ const WebURLError::HasCopyInCache has_copy_in_cache =
+ status.exists_in_cache ? WebURLError::HasCopyInCache::kTrue
+ : WebURLError::HasCopyInCache::kFalse;
+ if (status.cors_error_status)
+ return WebURLError(*status.cors_error_status, has_copy_in_cache, url);
+ if (status.blocked_by_response_reason) {
+ DCHECK_EQ(net::ERR_BLOCKED_BY_RESPONSE, status.error_code);
+ return WebURLError(*status.blocked_by_response_reason,
+ status.resolve_error_info, has_copy_in_cache, url);
+ }
+
+ if (status.trust_token_operation_status !=
+ network::mojom::TrustTokenOperationStatus::kOk) {
+ DCHECK(status.error_code ==
+ net::ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST ||
+ status.error_code == net::ERR_TRUST_TOKEN_OPERATION_FAILED)
+ << "Unexpected error code on Trust Token operation failure (or cache "
+ "hit): "
+ << status.error_code;
+
+ return WebURLError(status.error_code, status.trust_token_operation_status,
+ url);
+ }
+
+ return WebURLError(status.error_code, status.extended_error_code,
+ status.resolve_error_info, has_copy_in_cache,
+ WebURLError::IsWebSecurityViolation::kFalse, url);
+}
+
+void WebURLLoader::LoadSynchronously(
+ std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<WebURLRequestExtraData> url_request_extra_data,
+ int requestor_id,
+ bool pass_response_pipe_to_client,
+ bool no_mime_sniffing,
+ base::TimeDelta timeout_interval,
+ WebURLLoaderClient* client,
+ WebURLResponse& response,
+ base::Optional<WebURLError>& error,
+ WebData& data,
+ int64_t& encoded_data_length,
+ int64_t& encoded_body_length,
+ WebBlobInfo& downloaded_blob,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper) {
+ if (!context_)
+ return;
+
+ TRACE_EVENT0("loading", "WebURLLoader::loadSynchronously");
+ SyncLoadResponse sync_load_response;
+
+ DCHECK(!context_->client());
+ context_->set_client(client);
+
+ const bool report_raw_headers = request->report_raw_headers;
+ context_->Start(std::move(request), std::move(url_request_extra_data),
+ requestor_id, pass_response_pipe_to_client, no_mime_sniffing,
+ timeout_interval, &sync_load_response,
+ std::move(resource_load_info_notifier_wrapper));
+
+ const KURL final_url(sync_load_response.url);
+
+ // TODO(tc): For file loads, we may want to include a more descriptive
+ // status code or status text.
+ const int error_code = sync_load_response.error_code;
+ if (error_code != net::OK) {
+ if (sync_load_response.cors_error) {
+ error = WebURLError(*sync_load_response.cors_error,
+ WebURLError::HasCopyInCache::kFalse, final_url);
+ } else {
+ // SyncResourceHandler returns ERR_ABORTED for CORS redirect errors,
+ // so we treat the error as a web security violation.
+ const WebURLError::IsWebSecurityViolation is_web_security_violation =
+ error_code == net::ERR_ABORTED
+ ? WebURLError::IsWebSecurityViolation::kTrue
+ : WebURLError::IsWebSecurityViolation::kFalse;
+ error = WebURLError(error_code, sync_load_response.extended_error_code,
+ sync_load_response.resolve_error_info,
+ WebURLError::HasCopyInCache::kFalse,
+ is_web_security_violation, final_url);
+ }
+ return;
+ }
+
+ PopulateURLResponse(final_url, *sync_load_response.head, &response,
+ report_raw_headers, context_->request_id());
+ encoded_data_length = sync_load_response.head->encoded_data_length;
+ encoded_body_length = sync_load_response.head->encoded_body_length;
+ if (sync_load_response.downloaded_blob) {
+ downloaded_blob = WebBlobInfo(
+ WebString::FromLatin1(sync_load_response.downloaded_blob->uuid),
+ WebString::FromLatin1(sync_load_response.downloaded_blob->content_type),
+ sync_load_response.downloaded_blob->size,
+ std::move(sync_load_response.downloaded_blob->blob));
+ }
+
+ data.Assign(sync_load_response.data);
+}
+
+void WebURLLoader::LoadAsynchronously(
+ std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<WebURLRequestExtraData> url_request_extra_data,
+ int requestor_id,
+ bool no_mime_sniffing,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper,
+ WebURLLoaderClient* client) {
+ if (!context_)
+ return;
+
+ TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoader::loadAsynchronously", this,
+ TRACE_EVENT_FLAG_FLOW_OUT);
+ DCHECK(!context_->client());
+
+ context_->set_client(client);
+ context_->Start(std::move(request), std::move(url_request_extra_data),
+ requestor_id,
+ /*pass_response_pipe_to_client=*/false, no_mime_sniffing,
+ base::TimeDelta(), nullptr,
+ std::move(resource_load_info_notifier_wrapper));
+}
+
+void WebURLLoader::Cancel() {
+ if (context_)
+ context_->Cancel();
+}
+
+void WebURLLoader::SetDefersLoading(DeferType value) {
+ if (context_)
+ context_->SetDefersLoading(value);
+}
+
+void WebURLLoader::DidChangePriority(WebURLRequest::Priority new_priority,
+ int intra_priority_value) {
+ if (context_)
+ context_->DidChangePriority(new_priority, intra_priority_value);
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+WebURLLoader::GetTaskRunnerForBodyLoader() {
+ if (!context_)
+ return nullptr;
+ return context_->unfreezable_task_runner();
+}
+
+void WebURLLoader::SetResourceRequestSenderForTesting(
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender) {
+ context_->SetResourceRequestSenderForTesting( // IN-TEST
+ std::move(resource_request_sender));
+}
+
+// static
+// We have this function at the bottom of this file because it confuses
+// syntax highliting.
+// TODO(kinuko): Deprecate this, we basically need to know the destination
+// and if it's for favicon or not.
+net::NetworkTrafficAnnotationTag WebURLLoader::Context::GetTrafficAnnotationTag(
+ network::ResourceRequest* request) {
+ if (request->is_favicon) {
+ return net::DefineNetworkTrafficAnnotation("favicon_loader", R"(
+ semantics {
+ sender: "Blink Resource Loader"
+ description:
+ "Chrome sends a request to download favicon for a URL."
+ trigger:
+ "Navigating to a URL."
+ data: "None."
+ destination: WEBSITE
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting: "These requests cannot be disabled in settings."
+ policy_exception_justification:
+ "Not implemented."
+ })");
+ }
+ switch (request->destination) {
+ case network::mojom::RequestDestination::kDocument:
+ case network::mojom::RequestDestination::kIframe:
+ case network::mojom::RequestDestination::kFrame:
+ NOTREACHED();
+ FALLTHROUGH;
+
+ case network::mojom::RequestDestination::kEmpty:
+ case network::mojom::RequestDestination::kAudio:
+ case network::mojom::RequestDestination::kAudioWorklet:
+ case network::mojom::RequestDestination::kFont:
+ case network::mojom::RequestDestination::kImage:
+ case network::mojom::RequestDestination::kManifest:
+ case network::mojom::RequestDestination::kPaintWorklet:
+ case network::mojom::RequestDestination::kReport:
+ case network::mojom::RequestDestination::kScript:
+ case network::mojom::RequestDestination::kServiceWorker:
+ case network::mojom::RequestDestination::kSharedWorker:
+ case network::mojom::RequestDestination::kStyle:
+ case network::mojom::RequestDestination::kTrack:
+ case network::mojom::RequestDestination::kVideo:
+ case network::mojom::RequestDestination::kWebBundle:
+ case network::mojom::RequestDestination::kWorker:
+ case network::mojom::RequestDestination::kXslt:
+ return net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"(
+ semantics {
+ sender: "Blink Resource Loader"
+ description:
+ "Blink-initiated request, which includes all resources for "
+ "normal page loads, chrome URLs, and downloads."
+ trigger:
+ "The user navigates to a URL or downloads a file. Also when a "
+ "webpage, ServiceWorker, or chrome:// uses any network communication."
+ data: "Anything the initiator wants to send."
+ destination: OTHER
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting: "These requests cannot be disabled in settings."
+ policy_exception_justification:
+ "Not implemented. Without these requests, Chrome will be unable "
+ "to load any webpage."
+ })");
+
+ case network::mojom::RequestDestination::kEmbed:
+ case network::mojom::RequestDestination::kObject:
+ return net::DefineNetworkTrafficAnnotation(
+ "blink_extension_resource_loader", R"(
+ semantics {
+ sender: "Blink Resource Loader"
+ description:
+ "Blink-initiated request for resources required for NaCl instances "
+ "tagged with <embed> or <object>, or installed extensions."
+ trigger:
+ "An extension or NaCl instance may initiate a request at any time, "
+ "even in the background."
+ data: "Anything the initiator wants to send."
+ destination: OTHER
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting:
+ "These requests cannot be disabled in settings, but they are "
+ "sent only if user installs extensions."
+ chrome_policy {
+ ExtensionInstallBlocklist {
+ ExtensionInstallBlocklist: {
+ entries: '*'
+ }
+ }
+ }
+ })");
+ }
+
+ return net::NetworkTrafficAnnotationTag::NotReached();
+}
+
+void WebURLLoader::Context::SetResourceRequestSenderForTesting(
+ std::unique_ptr<blink::WebResourceRequestSender> resource_request_sender) {
+ resource_request_sender_ = std::move(resource_request_sender);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_factory.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_factory.cc
new file mode 100644
index 00000000000..204f81362f7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_factory.cc
@@ -0,0 +1,46 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_url_loader_factory.h"
+
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+
+using blink::scheduler::WebResourceLoadingTaskRunnerHandle;
+
+namespace blink {
+
+WebURLLoaderFactory::WebURLLoaderFactory(
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event)
+ : loader_factory_(std::move(loader_factory)),
+ cors_exempt_header_list_(cors_exempt_header_list),
+ terminate_sync_load_event_(terminate_sync_load_event) {
+ DCHECK(loader_factory_);
+}
+
+WebURLLoaderFactory::WebURLLoaderFactory() = default;
+
+WebURLLoaderFactory::~WebURLLoaderFactory() = default;
+
+std::unique_ptr<WebURLLoader> WebURLLoaderFactory::CreateURLLoader(
+ const WebURLRequest& request,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ freezable_task_runner_handle,
+ std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
+ unfreezable_task_runner_handle,
+ CrossVariantMojoRemote<mojom::KeepAliveHandleInterfaceBase>
+ keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
+ DCHECK(freezable_task_runner_handle);
+ DCHECK(unfreezable_task_runner_handle);
+ return std::make_unique<WebURLLoader>(
+ cors_exempt_header_list_, terminate_sync_load_event_,
+ std::move(freezable_task_runner_handle),
+ std::move(unfreezable_task_runner_handle), loader_factory_,
+ std::move(keep_alive_handle), back_forward_cache_loader_helper);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
new file mode 100644
index 00000000000..6f5e2e2e1d6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
@@ -0,0 +1,715 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/platform/web_url_loader.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/test/task_environment.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/cert/x509_util.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/test/cert_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/platform/web_request_peer.h"
+#include "third_party/blink/public/platform/web_resource_request_sender.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/platform/web_url_loader_client.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_request_extra_data.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/platform/loader/fetch/url_loader/sync_load_response.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace blink {
+namespace {
+
+const char kTestURL[] = "http://foo";
+const char kTestHTTPSURL[] = "https://foo";
+const char kTestData[] = "blah!";
+
+class MockResourceRequestSender : public WebResourceRequestSender {
+ public:
+ MockResourceRequestSender() = default;
+ ~MockResourceRequestSender() override = default;
+
+ // WebResourceRequestSender implementation:
+ void SendSync(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ SyncLoadResponse* response,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ base::TimeDelta timeout,
+ const WebVector<WebString>& cors_exempt_header_list,
+ base::WaitableEvent* terminate_sync_load_event,
+ mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
+ scoped_refptr<WebRequestPeer> peer,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
+ override {
+ *response = std::move(sync_load_response_);
+ }
+
+ int SendAsync(
+ std::unique_ptr<network::ResourceRequest> request,
+ int routing_id,
+ scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t loader_options,
+ const WebVector<WebString>& cors_exempt_header_list,
+ scoped_refptr<WebRequestPeer> peer,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ WebVector<std::unique_ptr<URLLoaderThrottle>> throttles,
+ std::unique_ptr<ResourceLoadInfoNotifierWrapper>
+ resource_load_info_notifier_wrapper,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
+ override {
+ EXPECT_FALSE(peer_);
+ if (sync_load_response_.head->encoded_body_length != -1)
+ EXPECT_TRUE(loader_options & network::mojom::kURLLoadOptionSynchronous);
+ peer_ = std::move(peer);
+ return 1;
+ }
+
+ void Cancel(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
+ EXPECT_FALSE(canceled_);
+ canceled_ = true;
+
+ task_runner->ReleaseSoon(FROM_HERE, std::move(peer_));
+ }
+
+ WebRequestPeer* peer() { return peer_.get(); }
+
+ bool canceled() { return canceled_; }
+
+ void SetDefersLoading(WebURLLoader::DeferType value) override {
+ defers_loading_ = (value != WebURLLoader::DeferType::kNotDeferred);
+ }
+ bool defers_loading() const { return defers_loading_; }
+
+ void set_sync_load_response(SyncLoadResponse&& sync_load_response) {
+ sync_load_response_ = std::move(sync_load_response);
+ }
+
+ private:
+ scoped_refptr<WebRequestPeer> peer_;
+ bool canceled_ = false;
+ bool defers_loading_ = false;
+ SyncLoadResponse sync_load_response_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockResourceRequestSender);
+};
+
+class FakeURLLoaderFactory final : public network::mojom::URLLoaderFactory {
+ public:
+ FakeURLLoaderFactory() = default;
+ ~FakeURLLoaderFactory() override = default;
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
+ override {
+ NOTREACHED();
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
+ override {
+ NOTREACHED();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeURLLoaderFactory);
+};
+
+class TestWebURLLoaderClient : public WebURLLoaderClient {
+ public:
+ TestWebURLLoaderClient()
+ : loader_(new WebURLLoader(
+ /*cors_exempt_header_list=*/WebVector<WebString>(),
+ /*terminate_sync_load_event=*/nullptr,
+ scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
+ scheduler::GetSingleThreadTaskRunnerForTesting()),
+ scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
+ scheduler::GetSingleThreadTaskRunnerForTesting()),
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &fake_url_loader_factory_),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ WebBackForwardCacheLoaderHelper())),
+ delete_on_receive_redirect_(false),
+ delete_on_receive_response_(false),
+ delete_on_receive_data_(false),
+ delete_on_finish_(false),
+ delete_on_fail_(false),
+ did_receive_redirect_(false),
+ did_receive_response_(false),
+ did_finish_(false) {}
+
+ ~TestWebURLLoaderClient() override {
+ // During the deconstruction of the `loader_`, the request context will be
+ // released asynchronously and we must ensure that the request context has
+ // been deleted practically before the test quits, thus, memory leak will
+ // not be reported on the ASAN build. So, we call 'reset()' to trigger the
+ // deconstruction, and then execute `RunUntilIdle()` to empty the task queue
+ // to achieve that.
+ if (loader_)
+ loader_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // WebURLLoaderClient implementation:
+ bool WillFollowRedirect(const WebURL& new_url,
+ const net::SiteForCookies& new_site_for_cookies,
+ const WebString& new_referrer,
+ network::mojom::ReferrerPolicy new_referrer_policy,
+ const WebString& new_method,
+ const WebURLResponse& passed_redirect_response,
+ bool& report_raw_headers,
+ std::vector<std::string>*) override {
+ EXPECT_TRUE(loader_);
+
+ // No test currently simulates mutiple redirects.
+ EXPECT_FALSE(did_receive_redirect_);
+ did_receive_redirect_ = true;
+
+ if (delete_on_receive_redirect_)
+ loader_.reset();
+
+ return true;
+ }
+
+ void DidSendData(uint64_t bytesSent, uint64_t totalBytesToBeSent) override {
+ EXPECT_TRUE(loader_);
+ }
+
+ void DidReceiveResponse(const WebURLResponse& response) override {
+ EXPECT_TRUE(loader_);
+ EXPECT_FALSE(did_receive_response_);
+
+ did_receive_response_ = true;
+ response_ = response;
+ if (delete_on_receive_response_)
+ loader_.reset();
+ }
+
+ void DidStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle response_body) override {
+ DCHECK(!response_body_);
+ DCHECK(response_body);
+ response_body_ = std::move(response_body);
+ }
+
+ void DidReceiveData(const char* data, int dataLength) override {
+ NOTREACHED();
+ }
+
+ void DidFinishLoading(base::TimeTicks finishTime,
+ int64_t totalEncodedDataLength,
+ int64_t totalEncodedBodyLength,
+ int64_t totalDecodedBodyLength,
+ bool should_report_corb_blocking) override {
+ EXPECT_TRUE(loader_);
+ EXPECT_TRUE(did_receive_response_);
+ EXPECT_FALSE(did_finish_);
+ did_finish_ = true;
+
+ if (delete_on_finish_)
+ loader_.reset();
+ }
+
+ void DidFail(const WebURLError& error,
+ base::TimeTicks finishTime,
+ int64_t totalEncodedDataLength,
+ int64_t totalEncodedBodyLength,
+ int64_t totalDecodedBodyLength) override {
+ EXPECT_TRUE(loader_);
+ EXPECT_FALSE(did_finish_);
+ error_ = error;
+
+ if (delete_on_fail_)
+ loader_.reset();
+ }
+
+ WebURLLoader* loader() { return loader_.get(); }
+ void DeleteLoader() { loader_.reset(); }
+
+ void set_delete_on_receive_redirect() { delete_on_receive_redirect_ = true; }
+ void set_delete_on_receive_response() { delete_on_receive_response_ = true; }
+ void set_delete_on_receive_data() { delete_on_receive_data_ = true; }
+ void set_delete_on_finish() { delete_on_finish_ = true; }
+ void set_delete_on_fail() { delete_on_fail_ = true; }
+
+ bool did_receive_redirect() const { return did_receive_redirect_; }
+ bool did_receive_response() const { return did_receive_response_; }
+ bool did_receive_response_body() const { return !!response_body_; }
+ bool did_finish() const { return did_finish_; }
+ const base::Optional<WebURLError>& error() const { return error_; }
+ const WebURLResponse& response() const { return response_; }
+
+ private:
+ FakeURLLoaderFactory fake_url_loader_factory_;
+ std::unique_ptr<WebURLLoader> loader_;
+
+ bool delete_on_receive_redirect_;
+ bool delete_on_receive_response_;
+ bool delete_on_receive_data_;
+ bool delete_on_finish_;
+ bool delete_on_fail_;
+
+ bool did_receive_redirect_;
+ bool did_receive_response_;
+ mojo::ScopedDataPipeConsumerHandle response_body_;
+ bool did_finish_;
+ base::Optional<WebURLError> error_;
+ WebURLResponse response_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient);
+};
+
+class WebURLLoaderTest : public testing::Test {
+ public:
+ WebURLLoaderTest() : client_(std::make_unique<TestWebURLLoaderClient>()) {
+ auto sender = std::make_unique<MockResourceRequestSender>();
+ sender_ = sender.get();
+ client_->loader()->SetResourceRequestSenderForTesting(std::move(sender));
+ }
+
+ ~WebURLLoaderTest() override = default;
+
+ void DoStartAsyncRequest() {
+ auto request = std::make_unique<network::ResourceRequest>();
+ request->url = GURL(kTestURL);
+ request->destination = network::mojom::RequestDestination::kEmpty;
+ request->priority = net::IDLE;
+ client()->loader()->LoadAsynchronously(
+ std::move(request), /*url_request_extra_data=*/nullptr,
+ /*requestor_id=*/0,
+ /*no_mime_sniffing=*/false,
+ std::make_unique<ResourceLoadInfoNotifierWrapper>(
+ /*resource_load_info_notifier=*/nullptr),
+ client());
+ ASSERT_TRUE(peer());
+ }
+
+ void DoReceiveRedirect() {
+ EXPECT_FALSE(client()->did_receive_redirect());
+ net::RedirectInfo redirect_info;
+ redirect_info.status_code = 302;
+ redirect_info.new_method = "GET";
+ redirect_info.new_url = GURL(kTestURL);
+ redirect_info.new_site_for_cookies =
+ net::SiteForCookies::FromUrl(GURL(kTestURL));
+ std::vector<std::string> removed_headers;
+ peer()->OnReceivedRedirect(redirect_info,
+ network::mojom::URLResponseHead::New(),
+ &removed_headers);
+ EXPECT_TRUE(client()->did_receive_redirect());
+ }
+
+ void DoReceiveHTTPSRedirect() {
+ EXPECT_FALSE(client()->did_receive_redirect());
+ net::RedirectInfo redirect_info;
+ redirect_info.status_code = 302;
+ redirect_info.new_method = "GET";
+ redirect_info.new_url = GURL(kTestHTTPSURL);
+ redirect_info.new_site_for_cookies =
+ net::SiteForCookies::FromUrl(GURL(kTestHTTPSURL));
+ peer()->OnReceivedRedirect(redirect_info,
+ network::mojom::URLResponseHead::New(), nullptr);
+ EXPECT_TRUE(client()->did_receive_redirect());
+ }
+
+ void DoReceiveResponse() {
+ EXPECT_FALSE(client()->did_receive_response());
+ peer()->OnReceivedResponse(network::mojom::URLResponseHead::New());
+ EXPECT_TRUE(client()->did_receive_response());
+ }
+
+ void DoStartLoadingResponseBody() {
+ mojo::ScopedDataPipeConsumerHandle handle_to_pass;
+ MojoResult rv = mojo::CreateDataPipe(nullptr, body_handle_, handle_to_pass);
+ ASSERT_EQ(MOJO_RESULT_OK, rv);
+ peer()->OnStartLoadingResponseBody(std::move(handle_to_pass));
+ }
+
+ void DoCompleteRequest() {
+ EXPECT_FALSE(client()->did_finish());
+ DCHECK(body_handle_);
+ body_handle_.reset();
+ base::RunLoop().RunUntilIdle();
+ network::URLLoaderCompletionStatus status(net::OK);
+ status.encoded_data_length = base::size(kTestData);
+ status.encoded_body_length = base::size(kTestData);
+ status.decoded_body_length = base::size(kTestData);
+ peer()->OnCompletedRequest(status);
+ EXPECT_TRUE(client()->did_finish());
+ // There should be no error.
+ EXPECT_FALSE(client()->error());
+ }
+
+ void DoFailRequest() {
+ EXPECT_FALSE(client()->did_finish());
+ DCHECK(body_handle_);
+ body_handle_.reset();
+ base::RunLoop().RunUntilIdle();
+ network::URLLoaderCompletionStatus status(net::ERR_FAILED);
+ status.encoded_data_length = base::size(kTestData);
+ status.encoded_body_length = base::size(kTestData);
+ status.decoded_body_length = base::size(kTestData);
+ peer()->OnCompletedRequest(status);
+ EXPECT_FALSE(client()->did_finish());
+ ASSERT_TRUE(client()->error());
+ EXPECT_EQ(net::ERR_FAILED, client()->error()->reason());
+ }
+
+ TestWebURLLoaderClient* client() { return client_.get(); }
+ MockResourceRequestSender* sender() { return sender_; }
+ WebRequestPeer* peer() { return sender_->peer(); }
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ mojo::ScopedDataPipeProducerHandle body_handle_;
+ std::unique_ptr<TestWebURLLoaderClient> client_;
+ MockResourceRequestSender* sender_ = nullptr;
+};
+
+TEST_F(WebURLLoaderTest, Success) {
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoStartLoadingResponseBody();
+ DoCompleteRequest();
+ EXPECT_FALSE(sender()->canceled());
+ EXPECT_TRUE(client()->did_receive_response_body());
+}
+
+TEST_F(WebURLLoaderTest, Redirect) {
+ DoStartAsyncRequest();
+ DoReceiveRedirect();
+ DoReceiveResponse();
+ DoStartLoadingResponseBody();
+ DoCompleteRequest();
+ EXPECT_FALSE(sender()->canceled());
+ EXPECT_TRUE(client()->did_receive_response_body());
+}
+
+TEST_F(WebURLLoaderTest, Failure) {
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoStartLoadingResponseBody();
+ DoFailRequest();
+ EXPECT_FALSE(sender()->canceled());
+}
+
+// The client may delete the WebURLLoader during any callback from the loader.
+// These tests make sure that doesn't result in a crash.
+TEST_F(WebURLLoaderTest, DeleteOnReceiveRedirect) {
+ client()->set_delete_on_receive_redirect();
+ DoStartAsyncRequest();
+ DoReceiveRedirect();
+}
+
+TEST_F(WebURLLoaderTest, DeleteOnReceiveResponse) {
+ client()->set_delete_on_receive_response();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+}
+
+TEST_F(WebURLLoaderTest, DeleteOnFinish) {
+ client()->set_delete_on_finish();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoStartLoadingResponseBody();
+ DoCompleteRequest();
+}
+
+TEST_F(WebURLLoaderTest, DeleteOnFail) {
+ client()->set_delete_on_fail();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoStartLoadingResponseBody();
+ DoFailRequest();
+}
+
+TEST_F(WebURLLoaderTest, DefersLoadingBeforeStart) {
+ client()->loader()->SetDefersLoading(WebURLLoader::DeferType::kDeferred);
+ EXPECT_FALSE(sender()->defers_loading());
+ DoStartAsyncRequest();
+ EXPECT_TRUE(sender()->defers_loading());
+}
+
+TEST_F(WebURLLoaderTest, ResponseIPEndpoint) {
+ KURL url("http://example.test/");
+
+ struct TestCase {
+ const char* ip;
+ uint16_t port;
+ } cases[] = {
+ {"127.0.0.1", 443},
+ {"123.123.123.123", 80},
+ {"::1", 22},
+ {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", 1337},
+ {"2001:db8:85a3:0:0:8a2e:370:7334", 12345},
+ {"2001:db8:85a3::8a2e:370:7334", 8080},
+ {"::ffff:192.0.2.128", 8443},
+ };
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(test.ip);
+
+ net::IPAddress address;
+ ASSERT_TRUE(address.AssignFromIPLiteral(test.ip));
+
+ network::mojom::URLResponseHead head;
+ head.remote_endpoint = net::IPEndPoint(address, test.port);
+
+ WebURLResponse response;
+ WebURLLoader::PopulateURLResponse(url, head, &response, true, -1);
+ EXPECT_EQ(head.remote_endpoint, response.RemoteIPEndpoint());
+ };
+}
+
+TEST_F(WebURLLoaderTest, ResponseAddressSpace) {
+ using AddressSpace = network::mojom::IPAddressSpace;
+
+ struct TestCase {
+ std::string url;
+ std::string ip;
+ AddressSpace expected;
+ } cases[] = {
+ {"http://localhost", "127.0.0.1", AddressSpace::kLocal},
+ {"http://localhost", "::1", AddressSpace::kLocal},
+ {"file:///a/path", "", AddressSpace::kLocal},
+ {"file:///a/path", "8.8.8.8", AddressSpace::kLocal},
+ {"http://router.local", "10.1.0.1", AddressSpace::kPrivate},
+ {"http://router.local", "::ffff:192.0.2.128", AddressSpace::kPrivate},
+ {"https://bleep.test", "8.8.8.8", AddressSpace::kPublic},
+ {"http://a.test", "2001:db8:85a3::8a2e:370:7334", AddressSpace::kPublic},
+ {"http://invalid", "", AddressSpace::kUnknown},
+ };
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(test.url + ", " + test.ip);
+
+ KURL url(test.url.c_str());
+
+ // We are forced to use the result of AssignFromIPLiteral(), and we cannot
+ // just assign it to an unused variable. Check that all non-empty literals
+ // are correctly parsed.
+ net::IPAddress address;
+ EXPECT_EQ(!test.ip.empty(), address.AssignFromIPLiteral(test.ip));
+
+ network::mojom::URLResponseHead head;
+ head.remote_endpoint = net::IPEndPoint(address, 443);
+
+ WebURLResponse response;
+ WebURLLoader::PopulateURLResponse(url, head, &response, true, -1);
+
+ EXPECT_EQ(test.expected, response.AddressSpace());
+ }
+}
+
+// This test verifies that the IPAddressSpace set on WebURLResponse takes into
+// account WebURLResponse::ResponseUrl() instead of
+// WebURLResponse::CurrentRequestUrl().
+TEST_F(WebURLLoaderTest, ResponseAddressSpaceConsidersResponseUrl) {
+ KURL request_url("http://request.test");
+
+ // The remote endpoint contains a public IP address, but the response was
+ // ultimately fetched by a service worker from a file URL.
+ network::mojom::URLResponseHead head;
+ head.remote_endpoint = net::IPEndPoint(net::IPAddress(8, 8, 8, 8), 80);
+ head.was_fetched_via_service_worker = true;
+ head.url_list_via_service_worker = {
+ GURL("http://redirect.test"),
+ GURL("file:///a/path"),
+ };
+
+ WebURLResponse response;
+ WebURLLoader::PopulateURLResponse(request_url, head, &response, true, -1);
+
+ // The address space of the response reflects the fact the it was fetched
+ // from a file, even though the request was initially to a public website.
+ EXPECT_EQ(KURL("http://request.test"), KURL(response.CurrentRequestUrl()));
+ EXPECT_EQ(KURL("file:///a/path"), KURL(response.ResponseUrl()));
+ EXPECT_EQ(network::mojom::IPAddressSpace::kLocal, response.AddressSpace());
+}
+
+TEST_F(WebURLLoaderTest, ResponseCert) {
+ KURL url("https://test.example/");
+
+ net::CertificateList certs;
+ ASSERT_TRUE(net::LoadCertificateFiles(
+ {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
+ ASSERT_EQ(2U, certs.size());
+
+ base::StringPiece cert0_der =
+ net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
+ base::StringPiece cert1_der =
+ net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
+
+ net::SSLInfo ssl_info;
+ ssl_info.cert =
+ net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &ssl_info.connection_status);
+
+ network::mojom::URLResponseHead head;
+ head.ssl_info = ssl_info;
+ WebURLResponse web_url_response;
+ WebURLLoader::PopulateURLResponse(url, head, &web_url_response, true, -1);
+
+ base::Optional<WebURLResponse::WebSecurityDetails> security_details =
+ web_url_response.SecurityDetailsForTesting();
+ ASSERT_TRUE(security_details.has_value());
+ EXPECT_EQ("TLS 1.2", security_details->protocol);
+ EXPECT_EQ("127.0.0.1", security_details->subject_name);
+ EXPECT_EQ("127.0.0.1", security_details->issuer);
+ ASSERT_EQ(3U, security_details->san_list.size());
+ EXPECT_EQ("test.example", security_details->san_list[0]);
+ EXPECT_EQ("127.0.0.2", security_details->san_list[1]);
+ EXPECT_EQ("fe80::1", security_details->san_list[2]);
+ EXPECT_EQ(certs[0]->valid_start().ToTimeT(), security_details->valid_from);
+ EXPECT_EQ(certs[0]->valid_expiry().ToTimeT(), security_details->valid_to);
+ ASSERT_EQ(2U, security_details->certificate.size());
+ EXPECT_EQ(WebString::FromLatin1(std::string(cert0_der)),
+ security_details->certificate[0]);
+ EXPECT_EQ(WebString::FromLatin1(std::string(cert1_der)),
+ security_details->certificate[1]);
+}
+
+TEST_F(WebURLLoaderTest, ResponseCertWithNoSANs) {
+ KURL url("https://test.example/");
+
+ net::CertificateList certs;
+ ASSERT_TRUE(net::LoadCertificateFiles({"multi-root-B-by-C.pem"}, &certs));
+ ASSERT_EQ(1U, certs.size());
+
+ base::StringPiece cert0_der =
+ net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
+
+ net::SSLInfo ssl_info;
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &ssl_info.connection_status);
+ ssl_info.cert = certs[0];
+ network::mojom::URLResponseHead head;
+ head.ssl_info = ssl_info;
+ WebURLResponse web_url_response;
+ WebURLLoader::PopulateURLResponse(url, head, &web_url_response, true, -1);
+
+ base::Optional<WebURLResponse::WebSecurityDetails> security_details =
+ web_url_response.SecurityDetailsForTesting();
+ ASSERT_TRUE(security_details.has_value());
+ EXPECT_EQ("TLS 1.2", security_details->protocol);
+ EXPECT_EQ("B CA - Multi-root", security_details->subject_name);
+ EXPECT_EQ("C CA - Multi-root", security_details->issuer);
+ EXPECT_EQ(0U, security_details->san_list.size());
+ EXPECT_EQ(certs[0]->valid_start().ToTimeT(), security_details->valid_from);
+ EXPECT_EQ(certs[0]->valid_expiry().ToTimeT(), security_details->valid_to);
+ ASSERT_EQ(1U, security_details->certificate.size());
+ EXPECT_EQ(WebString::FromLatin1(std::string(cert0_der)),
+ security_details->certificate[0]);
+}
+
+// Verifies that the lengths used by the PerformanceResourceTiming API are
+// correctly assigned for sync XHR.
+TEST_F(WebURLLoaderTest, SyncLengths) {
+ static const char kBodyData[] = "Today is Thursday";
+ const int kEncodedBodyLength = 30;
+ const int kEncodedDataLength = 130;
+ const KURL url(kTestURL);
+
+ auto request = std::make_unique<network::ResourceRequest>();
+ request->url = url;
+ request->destination = network::mojom::RequestDestination::kEmpty;
+ request->priority = net::HIGHEST;
+
+ // Prepare a mock response
+ SyncLoadResponse sync_load_response;
+ sync_load_response.error_code = net::OK;
+ sync_load_response.url = url;
+ sync_load_response.data.Assign(WebData(kBodyData));
+ ASSERT_EQ(17u, sync_load_response.data.size());
+ sync_load_response.head->encoded_body_length = kEncodedBodyLength;
+ sync_load_response.head->encoded_data_length = kEncodedDataLength;
+ sender()->set_sync_load_response(std::move(sync_load_response));
+
+ WebURLResponse response;
+ base::Optional<WebURLError> error;
+ WebData data;
+ int64_t encoded_data_length = 0;
+ int64_t encoded_body_length = 0;
+ WebBlobInfo downloaded_blob;
+
+ client()->loader()->LoadSynchronously(
+ std::move(request), /*url_request_extra_data=*/nullptr,
+ /*requestor_id=*/0,
+ /*pass_response_pipe_to_client=*/false, /*no_mime_sniffing=*/false,
+ base::TimeDelta(), nullptr, response, error, data, encoded_data_length,
+ encoded_body_length, downloaded_blob,
+ std::make_unique<ResourceLoadInfoNotifierWrapper>(
+ /*resource_load_info_notifier=*/nullptr));
+
+ EXPECT_EQ(kEncodedBodyLength, encoded_body_length);
+ EXPECT_EQ(kEncodedDataLength, encoded_data_length);
+ EXPECT_TRUE(downloaded_blob.Uuid().IsNull());
+}
+
+// Verifies that PopulateURLResponse() copies AuthChallengeInfo to the response.
+TEST_F(WebURLLoaderTest, AuthChallengeInfo) {
+ network::mojom::URLResponseHead head;
+ net::AuthChallengeInfo auth_challenge_info;
+ auth_challenge_info.is_proxy = true;
+ auth_challenge_info.challenge = "foobar";
+ head.auth_challenge_info = auth_challenge_info;
+
+ blink::WebURLResponse response;
+ WebURLLoader::PopulateURLResponse(KURL(), head, &response, true, -1);
+ ASSERT_TRUE(response.AuthChallengeInfo().has_value());
+ EXPECT_TRUE(response.AuthChallengeInfo()->is_proxy);
+ EXPECT_EQ("foobar", response.AuthChallengeInfo()->challenge);
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
index 3735b99b52a..40ab612c1f8 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
@@ -7,12 +7,14 @@
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/loader/referrer_utils.h"
-#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
@@ -31,7 +33,7 @@ WorkerMainScriptLoader::WorkerMainScriptLoader() = default;
WorkerMainScriptLoader::~WorkerMainScriptLoader() = default;
void WorkerMainScriptLoader::Start(
- FetchParameters& fetch_params,
+ const FetchParameters& fetch_params,
std::unique_ptr<WorkerMainScriptLoadParameters>
worker_main_script_load_params,
FetchContext* fetch_context,
@@ -39,7 +41,7 @@ void WorkerMainScriptLoader::Start(
WorkerMainScriptLoaderClient* client) {
DCHECK(resource_load_observer);
DCHECK(client);
- initial_request_.CopyFrom(fetch_params.GetResourceRequest());
+ initial_request_ = fetch_params.GetResourceRequest();
resource_loader_options_ = fetch_params.Options();
initial_request_url_ = fetch_params.GetResourceRequest().Url();
last_request_url_ = initial_request_url_;
@@ -53,10 +55,12 @@ void WorkerMainScriptLoader::Start(
// TODO(crbug.com/929370): Support CSP check to post violation reports for
// worker top-level scripts, if off-the-main-thread fetch is enabled.
+ ResourceRequest resource_request(initial_request_);
resource_load_observer_->WillSendRequest(
- initial_request_.InspectorId(), initial_request_,
+ initial_request_.InspectorId(), resource_request,
/*redirect_response=*/ResourceResponse(), ResourceType::kScript,
- resource_loader_options_.initiator_info);
+ resource_loader_options_.initiator_info,
+ RenderBlockingBehavior::kNonBlocking);
resource_load_info_notifier_wrapper_->NotifyResourceLoadInitiated(
/*request_id=*/-1, initial_request_url_,
@@ -71,7 +75,7 @@ void WorkerMainScriptLoader::Start(
WebURLResponse response;
auto response_head = std::move(worker_main_script_load_params->response_head);
- Platform::Current()->PopulateURLResponse(
+ WebURLLoader::PopulateURLResponse(
WebURL(last_request_url_), *response_head, &response,
response_head->ssl_info.has_value(), /*request_id=*/-1);
resource_response_ = response.ToResourceResponse();
@@ -79,7 +83,7 @@ void WorkerMainScriptLoader::Start(
std::move(response_head), PreviewsTypes::kPreviewsUnspecified);
resource_load_observer_->DidReceiveResponse(
- initial_request_.InspectorId(), initial_request_, resource_response_,
+ initial_request_.InspectorId(), resource_request, resource_response_,
/*resource=*/nullptr,
ResourceLoadObserver::ResponseSource::kNotFromMemoryCache);
@@ -318,12 +322,13 @@ void WorkerMainScriptLoader::HandleRedirections(
redirect_info.new_referrer_policy),
/*skip_service_worker=*/false);
WebURLResponse response;
- Platform::Current()->PopulateURLResponse(
+ WebURLLoader::PopulateURLResponse(
WebURL(last_request_url_), *redirect_response, &response,
redirect_response->ssl_info.has_value(), /*request_id=*/-1);
resource_load_observer_->WillSendRequest(
new_request->InspectorId(), *new_request, response.ToResourceResponse(),
- ResourceType::kScript, resource_loader_options_.initiator_info);
+ ResourceType::kScript, resource_loader_options_.initiator_info,
+ RenderBlockingBehavior::kNonBlocking);
resource_load_info_notifier_wrapper_->NotifyResourceRedirectReceived(
redirect_info, std::move(redirect_response));
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h
index e6f82c490c1..a9426432965 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h
@@ -36,9 +36,10 @@ class SingleCachedMetadataHandler;
class WorkerMainScriptLoaderClient;
struct ResourceLoaderOptions;
-// For dedicated workers (PlzDedicatedWorker) and shared workers, the main
-// script is pre-requested by the browser process. This class is used for
-// receiving the response in the renderer process.
+// For dedicated workers (PlzDedicatedWorker), service workers
+// (PlzServiceWorker), and shared workers, the main script is pre-requested by
+// the browser process. This class is used for receiving the response in the
+// renderer process.
class PLATFORM_EXPORT WorkerMainScriptLoader final
: public GarbageCollected<WorkerMainScriptLoader>,
public network::mojom::URLLoaderClient {
@@ -47,7 +48,7 @@ class PLATFORM_EXPORT WorkerMainScriptLoader final
~WorkerMainScriptLoader() override;
// Starts to load the main script.
- void Start(FetchParameters& fetch_params,
+ void Start(const FetchParameters& fetch_params,
std::unique_ptr<WorkerMainScriptLoadParameters>
worker_main_script_load_params,
FetchContext* fetch_context,
@@ -98,7 +99,7 @@ class PLATFORM_EXPORT WorkerMainScriptLoader final
Member<WorkerMainScriptLoaderClient> client_;
Member<ResourceLoadObserver> resource_load_observer_;
- ResourceRequest initial_request_;
+ ResourceRequestHead initial_request_;
ResourceLoaderOptions resource_loader_options_{nullptr /* world */};
KURL initial_request_url_;
KURL last_request_url_;
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
index 7a8e62cd882..e5df67c95aa 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
@@ -49,20 +49,6 @@ class WorkerMainScriptLoaderTest : public testing::Test {
}
protected:
- class TestPlatform final : public TestingPlatformSupport {
- public:
- void PopulateURLResponse(const WebURL& url,
- const network::mojom::URLResponseHead& head,
- WebURLResponse* response,
- bool report_security_info,
- int request_id) override {
- response->SetCurrentRequestUrl(url);
- response->SetHttpStatusCode(head.headers.get()->response_code());
- response->SetMimeType(WebString::FromUTF8(head.mime_type));
- response->SetTextEncodingName(WebString::FromUTF8(head.charset));
- }
- };
-
class TestClient final : public GarbageCollected<TestClient>,
public WorkerMainScriptLoaderClient {
@@ -160,12 +146,13 @@ class WorkerMainScriptLoaderTest : public testing::Test {
class MockResourceLoadObserver : public ResourceLoadObserver {
public:
MOCK_METHOD2(DidStartRequest, void(const FetchParameters&, ResourceType));
- MOCK_METHOD5(WillSendRequest,
+ MOCK_METHOD6(WillSendRequest,
void(uint64_t identifier,
const ResourceRequest&,
const ResourceResponse& redirect_response,
ResourceType,
- const FetchInitiatorInfo&));
+ const FetchInitiatorInfo&,
+ RenderBlockingBehavior));
MOCK_METHOD3(DidChangePriority,
void(uint64_t identifier,
ResourceLoadPriority,
@@ -227,7 +214,7 @@ class WorkerMainScriptLoaderTest : public testing::Test {
mojo::ScopedDataPipeConsumerHandle body_consumer;
MojoCreateDataPipeOptions options = CreateDataPipeOptions();
EXPECT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, body_producer, &body_consumer));
+ mojo::CreateDataPipe(&options, *body_producer, body_consumer));
worker_main_script_load_params->response_body = std::move(body_consumer);
return worker_main_script_load_params;
@@ -261,7 +248,6 @@ class WorkerMainScriptLoaderTest : public testing::Test {
protected:
base::test::TaskEnvironment task_environment_;
- ScopedTestingPlatformSupport<TestPlatform> platform_;
mojo::PendingRemote<network::mojom::URLLoader> pending_remote_loader_;
mojo::Remote<network::mojom::URLLoaderClient> loader_client_;
@@ -279,7 +265,7 @@ TEST_F(WorkerMainScriptLoaderTest, ResponseWithSucessThenOnComplete) {
MockResourceLoadObserver* mock_observer =
MakeGarbageCollected<MockResourceLoadObserver>();
FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
- EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
+ EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveData(_, _));
EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _));
@@ -310,7 +296,7 @@ TEST_F(WorkerMainScriptLoaderTest, ResponseWithFailureThenOnComplete) {
MockResourceLoadObserver* mock_observer =
MakeGarbageCollected<MockResourceLoadObserver>();
FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
- EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
+ EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
EXPECT_CALL(*mock_observer, DidFailLoading(_, _, _, _, _));
@@ -334,7 +320,7 @@ TEST_F(WorkerMainScriptLoaderTest, DisconnectBeforeOnComplete) {
MockResourceLoadObserver* mock_observer =
MakeGarbageCollected<MockResourceLoadObserver>();
FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
- EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
+ EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
EXPECT_CALL(*mock_observer, DidFailLoading(_, _, _, _, _));
@@ -358,7 +344,7 @@ TEST_F(WorkerMainScriptLoaderTest, OnCompleteWithError) {
MockResourceLoadObserver* mock_observer =
MakeGarbageCollected<MockResourceLoadObserver>();
FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
- EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
+ EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
EXPECT_CALL(*mock_observer, DidReceiveData(_, _));
EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
diff --git a/chromium/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc b/chromium/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
index 496c0178ab4..635edb5b2c3 100644
--- a/chromium/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
#include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_loader_client.h"
#include "third_party/blink/public/platform/web_url_request.h"
@@ -21,7 +22,10 @@ InternetDisconnectedWebURLLoaderFactory::CreateURLLoader(
std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
freezable_task_runner_handle,
std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>
- unfreezable_task_runner_handle) {
+ unfreezable_task_runner_handle,
+ CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>
+ keep_alive_handle,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
DCHECK(freezable_task_runner_handle);
return std::make_unique<InternetDisconnectedWebURLLoader>(
std::move(freezable_task_runner_handle));
diff --git a/chromium/third_party/blink/renderer/platform/loader/mixed_content.cc b/chromium/third_party/blink/renderer/platform/loader/mixed_content.cc
new file mode 100644
index 00000000000..5ab3cfd6032
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/mixed_content.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 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/platform/loader/mixed_content.h"
+
+#include "base/notreached.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
+
+namespace blink {
+
+// static
+mojom::blink::MixedContentContextType
+MixedContent::ContextTypeFromRequestContext(
+ mojom::blink::RequestContextType context,
+ MixedContent::CheckModeForPlugin check_mode_for_plugin) {
+ switch (context) {
+ // "Optionally-blockable" mixed content
+ case mojom::RequestContextType::AUDIO:
+ case mojom::RequestContextType::IMAGE:
+ case mojom::RequestContextType::VIDEO:
+ return mojom::blink::MixedContentContextType::kOptionallyBlockable;
+
+ // Plugins! Oh how dearly we love plugin-loaded content!
+ case mojom::RequestContextType::PLUGIN: {
+ return check_mode_for_plugin == MixedContent::CheckModeForPlugin::kStrict
+ ? mojom::blink::MixedContentContextType::kBlockable
+ : mojom::blink::MixedContentContextType::kOptionallyBlockable;
+ }
+
+ // "Blockable" mixed content
+ case mojom::RequestContextType::BEACON:
+ case mojom::RequestContextType::CSP_REPORT:
+ case mojom::RequestContextType::EMBED:
+ case mojom::RequestContextType::EVENT_SOURCE:
+ case mojom::RequestContextType::FAVICON:
+ case mojom::RequestContextType::FETCH:
+ case mojom::RequestContextType::FONT:
+ case mojom::RequestContextType::FORM:
+ case mojom::RequestContextType::FRAME:
+ case mojom::RequestContextType::HYPERLINK:
+ case mojom::RequestContextType::IFRAME:
+ case mojom::RequestContextType::IMAGE_SET:
+ case mojom::RequestContextType::IMPORT:
+ case mojom::RequestContextType::INTERNAL:
+ case mojom::RequestContextType::LOCATION:
+ case mojom::RequestContextType::MANIFEST:
+ case mojom::RequestContextType::OBJECT:
+ case mojom::RequestContextType::PING:
+ case mojom::RequestContextType::PREFETCH:
+ case mojom::RequestContextType::SCRIPT:
+ case mojom::RequestContextType::SERVICE_WORKER:
+ case mojom::RequestContextType::SHARED_WORKER:
+ case mojom::RequestContextType::STYLE:
+ case mojom::RequestContextType::SUBRESOURCE:
+ case mojom::RequestContextType::SUBRESOURCE_WEBBUNDLE:
+ case mojom::RequestContextType::TRACK:
+ case mojom::RequestContextType::WORKER:
+ case mojom::RequestContextType::XML_HTTP_REQUEST:
+ case mojom::RequestContextType::XSLT:
+ return mojom::blink::MixedContentContextType::kBlockable;
+
+ // FIXME: Contexts that we should block, but don't currently.
+ // https://crbug.com/388650
+ case mojom::RequestContextType::DOWNLOAD:
+ return mojom::blink::MixedContentContextType::kShouldBeBlockable;
+
+ case mojom::RequestContextType::UNSPECIFIED:
+ NOTREACHED();
+ }
+ NOTREACHED();
+ return mojom::blink::MixedContentContextType::kBlockable;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/mixed_content.h b/chromium/third_party/blink/renderer/platform/loader/mixed_content.h
new file mode 100644
index 00000000000..c27703e154a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/loader/mixed_content.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 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_PLATFORM_LOADER_MIXED_CONTENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_MIXED_CONTENT_H_
+
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink-forward.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// Helper functions related to mixed content checks.
+class MixedContent {
+ public:
+ enum class CheckModeForPlugin { kStrict, kLax };
+
+ PLATFORM_EXPORT static mojom::blink::MixedContentContextType
+ ContextTypeFromRequestContext(mojom::RequestContextType,
+ CheckModeForPlugin);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_MIXED_CONTENT_H_
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h b/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
index 217da2c4bd9..4d5e3fd4841 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
@@ -38,6 +38,13 @@ class MockFetchContext : public FetchContext {
uint64_t GetTransferSize() const { return transfer_size_; }
+ void set_blocked_urls(Vector<String> blocked_urls) {
+ blocked_urls_ = std::move(blocked_urls);
+ }
+ void set_tagged_urls(Vector<String> tagged_urls) {
+ tagged_urls_ = std::move(tagged_urls);
+ }
+
bool AllowImage(bool images_enabled, const KURL&) const override {
return true;
}
@@ -51,6 +58,21 @@ class MockFetchContext : public FetchContext {
const override {
return base::nullopt;
}
+ base::Optional<ResourceRequestBlockedReason>
+ CanRequestBasedOnSubresourceFilterOnly(
+ ResourceType type,
+ const ResourceRequest& resource_request,
+ const KURL& url,
+ const ResourceLoaderOptions& options,
+ ReportingDisposition reporting_disposition,
+ const base::Optional<ResourceRequest::RedirectInfo>& redirect_info)
+ const override {
+ if (blocked_urls_.Contains(url.GetString())) {
+ return ResourceRequestBlockedReason::kSubresourceFilter;
+ }
+
+ return base::nullopt;
+ }
base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest(
mojom::blink::RequestContextType,
network::mojom::RequestDestination request_destination,
@@ -79,6 +101,15 @@ class MockFetchContext : public FetchContext {
weak_wrapper_resource_load_info_notifier_->AsWeakPtr());
}
+ bool CalculateIfAdSubresource(
+ const ResourceRequestHead& resource_request,
+ const base::Optional<KURL>& alias_url,
+ ResourceType type,
+ const FetchInitiatorInfo& initiator_info) override {
+ const KURL url = alias_url ? alias_url.value() : resource_request.Url();
+ return tagged_urls_.Contains(url.GetString());
+ }
+
void SetResourceLoadInfoNotifier(
mojom::ResourceLoadInfoNotifier* resource_load_info_notifier) {
resource_load_info_notifier_ = resource_load_info_notifier;
@@ -89,6 +120,8 @@ class MockFetchContext : public FetchContext {
mojom::ResourceLoadInfoNotifier* resource_load_info_notifier_ = nullptr;
std::unique_ptr<WeakWrapperResourceLoadInfoNotifier>
weak_wrapper_resource_load_info_notifier_;
+ Vector<String> blocked_urls_;
+ Vector<String> tagged_urls_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
index 0931e9c4fe7..3a20dfa3286 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
@@ -43,57 +43,4 @@ MockResource::MockResource(const ResourceRequest& request,
const ResourceLoaderOptions& options)
: Resource(request, ResourceType::kMock, options) {}
-CachedMetadataHandler* MockResource::CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) {
- return MakeGarbageCollected<MockCacheHandler>(std::move(send_callback));
-}
-
-void MockResource::SetSerializedCachedMetadata(mojo_base::BigBuffer data) {
- // Resource ignores the cached metadata.
- Resource::SetSerializedCachedMetadata(mojo_base::BigBuffer());
- MockCacheHandler* cache_handler =
- static_cast<MockCacheHandler*>(Resource::CacheHandler());
- if (cache_handler) {
- cache_handler->Set(data.data(), data.size());
- }
-}
-
-void MockResource::SendCachedMetadata(const uint8_t* data, size_t size) {
- MockCacheHandler* cache_handler =
- static_cast<MockCacheHandler*>(Resource::CacheHandler());
- if (cache_handler) {
- cache_handler->Set(data, size);
- cache_handler->Send();
- }
-}
-
-MockCacheHandler* MockResource::CacheHandler() {
- return static_cast<MockCacheHandler*>(Resource::CacheHandler());
-}
-
-MockCacheHandler::MockCacheHandler(
- std::unique_ptr<CachedMetadataSender> send_callback)
- : send_callback_(std::move(send_callback)) {}
-
-void MockCacheHandler::Set(const uint8_t* data, size_t size) {
- data_.emplace();
- data_->Append(data, SafeCast<wtf_size_t>(size));
-}
-
-void MockCacheHandler::ClearCachedMetadata(
- CachedMetadataHandler::ClearCacheType cache_type) {
- if (cache_type == CachedMetadataHandler::kClearPersistentStorage) {
- Send();
- }
- data_.reset();
-}
-
-void MockCacheHandler::Send() {
- if (data_) {
- send_callback_->Send(data_->data(), data_->size());
- } else {
- send_callback_->Send(nullptr, 0);
- }
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
index 991860b1079..2e522f8c0dc 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/mock_resource.h
@@ -6,9 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_TESTING_MOCK_RESOURCE_H_
#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace blink {
@@ -16,27 +14,6 @@ class FetchParameters;
class ResourceFetcher;
struct ResourceLoaderOptions;
-// Mocked cache handler class used by MockResource to test the caching behaviour
-// of Resource.
-class MockCacheHandler : public CachedMetadataHandler {
- public:
- MockCacheHandler(std::unique_ptr<CachedMetadataSender> send_callback);
-
- void Set(const uint8_t* data, size_t);
- void ClearCachedMetadata(CachedMetadataHandler::ClearCacheType) override;
- void Send();
-
- String Encoding() const override { return "mock encoding"; }
- bool IsServedFromCacheStorage() const override { return false; }
- void OnMemoryDump(WebProcessMemoryDump* pmd,
- const String& dump_prefix) const override {}
- size_t GetCodeCacheSize() const override { return 0; }
-
- private:
- std::unique_ptr<CachedMetadataSender> send_callback_;
- base::Optional<Vector<uint8_t>> data_;
-};
-
// Mocked Resource sub-class for testing. MockResource class can pretend a type
// of Resource sub-class in a simple way. You should not expect anything
// complicated to emulate actual sub-resources, but you may be able to use this
@@ -49,14 +26,6 @@ class MockResource final : public Resource {
explicit MockResource(const KURL&);
explicit MockResource(const ResourceRequest&);
MockResource(const ResourceRequest&, const ResourceLoaderOptions&);
-
- CachedMetadataHandler* CreateCachedMetadataHandler(
- std::unique_ptr<CachedMetadataSender> send_callback) override;
- void SetSerializedCachedMetadata(mojo_base::BigBuffer data) override;
-
- MockCacheHandler* CacheHandler();
-
- void SendCachedMetadata(const uint8_t*, size_t);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/test_loader_factory.h b/chromium/third_party/blink/renderer/platform/loader/testing/test_loader_factory.h
index e361dceaf2c..806f9847b9e 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/test_loader_factory.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/test_loader_factory.h
@@ -9,6 +9,7 @@
#include <utility>
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
@@ -32,7 +33,8 @@ class TestLoaderFactory : public ResourceFetcher::LoaderFactory {
const ResourceRequest& request,
const ResourceLoaderOptions& options,
scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner,
+ WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
override {
WrappedResourceRequest wrapped(request);
return url_loader_factory_->CreateURLLoader(
@@ -40,7 +42,9 @@ class TestLoaderFactory : public ResourceFetcher::LoaderFactory {
scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
std::move(freezable_task_runner)),
scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
- std::move(unfreezable_task_runner)));
+ std::move(unfreezable_task_runner)),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ back_forward_cache_loader_helper);
}
std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override {
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc b/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
index f4b9ec2c790..2b3c3aa0411 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
@@ -18,7 +19,9 @@ WebURLLoaderFactoryWithMock::~WebURLLoaderFactoryWithMock() = default;
std::unique_ptr<WebURLLoader> WebURLLoaderFactoryWithMock::CreateURLLoader(
const WebURLRequest& request,
std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>,
- std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>) {
+ std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>,
+ CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>,
+ WebBackForwardCacheLoaderHelper) {
return mock_factory_->CreateURLLoader();
}
diff --git a/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h b/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h
index 2a7ad5f5c3e..769ae0dd84a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h
+++ b/chromium/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h
@@ -22,8 +22,9 @@ class WebURLLoaderFactoryWithMock : public WebURLLoaderFactory {
std::unique_ptr<WebURLLoader> CreateURLLoader(
const WebURLRequest&,
std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>,
- std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>)
- override;
+ std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>,
+ CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>,
+ WebBackForwardCacheLoaderHelper) override;
private:
// Not owned. The mock factory should outlive |this|.
diff --git a/chromium/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc b/chromium/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
index dffa242e974..9a341b2a439 100644
--- a/chromium/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
@@ -19,7 +19,6 @@ void WebURLRequestExtraData::CopyToResourceRequest(
request->is_main_frame = is_main_frame_;
request->transition_type = transition_type_;
request->originated_from_service_worker = originated_from_service_worker_;
- request->force_ignore_site_for_cookies = force_ignore_site_for_cookies_;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/loader/web_url_request_util.cc b/chromium/third_party/blink/renderer/platform/loader/web_url_request_util.cc
index d89f39a78f8..f6f6459b6a8 100644
--- a/chromium/third_party/blink/renderer/platform/loader/web_url_request_util.cc
+++ b/chromium/third_party/blink/renderer/platform/loader/web_url_request_util.cc
@@ -15,15 +15,17 @@
#include "services/network/public/mojom/data_pipe_getter.mojom-blink.h"
#include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-blink.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_http_body.h"
#include "third_party/blink/public/platform/web_http_header_visitor.h"
-#include "third_party/blink/public/platform/web_mixed_content.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/renderer/platform/loader/mixed_content.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/wtf_string.h"
@@ -75,29 +77,31 @@ WebHTTPBody GetWebHTTPBodyForRequestBody(
http_body.SetContainsPasswordData(input.contains_sensitive_info());
for (auto& element : *input.elements()) {
switch (element.type()) {
- case network::mojom::blink::DataElementType::kBytes:
+ case network::DataElement::Tag::kBytes: {
+ const auto& bytes = element.As<network::DataElementBytes>().bytes();
http_body.AppendData(
- WebData(element.bytes(), SafeCast<size_t>(element.length())));
+ WebData(reinterpret_cast<const char*>(bytes.data()), bytes.size()));
break;
- case network::mojom::blink::DataElementType::kFile: {
+ }
+ case network::DataElement::Tag::kFile: {
+ const auto& file = element.As<network::DataElementFile>();
base::Optional<base::Time> modification_time;
- if (!element.expected_modification_time().is_null())
- modification_time = element.expected_modification_time();
+ if (!file.expected_modification_time().is_null())
+ modification_time = file.expected_modification_time();
http_body.AppendFileRange(
- FilePathToWebString(element.path()), element.offset(),
- (element.length() != std::numeric_limits<uint64_t>::max())
- ? element.length()
+ FilePathToWebString(file.path()), file.offset(),
+ (file.length() != std::numeric_limits<uint64_t>::max())
+ ? file.length()
: -1,
modification_time);
break;
}
- case network::mojom::blink::DataElementType::kDataPipe: {
- http_body.AppendDataPipe(element.CloneDataPipeGetter());
+ case network::DataElement::Tag::kDataPipe: {
+ http_body.AppendDataPipe(
+ element.As<network::DataElementDataPipe>().CloneDataPipeGetter());
break;
}
- case network::mojom::blink::DataElementType::kUnknown:
- case network::mojom::blink::DataElementType::kChunkedDataPipe:
- case network::mojom::blink::DataElementType::kReadOnceStream:
+ case network::DataElement::Tag::kChunkedDataPipe:
NOTREACHED();
break;
}
@@ -148,24 +152,19 @@ scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebHTTPBody(
case HTTPBodyElementType::kTypeBlob: {
DCHECK(element.optional_blob);
mojo::Remote<mojom::blink::Blob> blob_remote(
- mojo::PendingRemote<mojom::blink::Blob>(
- std::move(element.optional_blob)));
+ std::move(element.optional_blob));
mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
data_pipe_getter_remote;
blob_remote->AsDataPipeGetter(
data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
request_body->AppendDataPipe(
- mojo::PendingRemote<network::mojom::DataPipeGetter>(
- data_pipe_getter_remote.PassPipe(), 0u));
+ ToCrossVariantMojoType(std::move(data_pipe_getter_remote)));
break;
}
case HTTPBodyElementType::kTypeDataPipe: {
- // Convert the raw message pipe to
- // mojo::Remote<network::mojom::DataPipeGetter> data_pipe_getter.
mojo::Remote<network::mojom::blink::DataPipeGetter> data_pipe_getter(
- mojo::PendingRemote<network::mojom::blink::DataPipeGetter>(
- std::move(element.data_pipe_getter)));
+ std::move(element.data_pipe_getter));
// Set the cloned DataPipeGetter to the output |request_body|, while
// keeping the original message pipe back in the input |httpBody|. This
@@ -175,8 +174,7 @@ scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebHTTPBody(
cloned_getter;
data_pipe_getter->Clone(cloned_getter.InitWithNewPipeAndPassReceiver());
request_body->AppendDataPipe(
- mojo::PendingRemote<network::mojom::DataPipeGetter>(
- cloned_getter.PassPipe(), 0u));
+ ToCrossVariantMojoType(std::move(cloned_getter)));
element.data_pipe_getter = data_pipe_getter.Unbind();
break;
}
@@ -199,10 +197,10 @@ network::mojom::blink::RequestDestination GetRequestDestinationForWebURLRequest(
request.GetRequestDestination());
}
-WebMixedContentContextType GetMixedContentContextTypeForWebURLRequest(
- const WebURLRequest& request) {
- return WebMixedContent::ContextTypeFromRequestContext(
- request.GetRequestContext(), WebMixedContent::CheckModeForPlugin::kLax);
+mojom::blink::MixedContentContextType
+GetMixedContentContextTypeForWebURLRequest(const WebURLRequest& request) {
+ return MixedContent::ContextTypeFromRequestContext(
+ request.GetRequestContext(), MixedContent::CheckModeForPlugin::kLax);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/DIR_METADATA b/chromium/third_party/blink/renderer/platform/mediastream/DIR_METADATA
new file mode 100644
index 00000000000..02d2785a62c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mediastream/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>GetUserMedia"
+}
+team_email: "webrtc-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/OWNERS b/chromium/third_party/blink/renderer/platform/mediastream/OWNERS
index 0b7d1c5bb07..5a7e4be05d7 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/mediastream/OWNERS
@@ -1,6 +1,3 @@
file://third_party/blink/common/mediastream/OWNERS
per-file media_stream_audio_processor*=olka@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>GetUserMedia
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.cc b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.cc
index d4aaea555e5..92b97b09154 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.cc
@@ -246,6 +246,10 @@ void ConfigAutomaticGainControl(
adaptive_digital.max_output_noise_level_dbfs =
agc2_properties->max_output_noise_level_dbfs;
+
+ adaptive_digital.sse2_allowed = agc2_properties->sse2_allowed;
+ adaptive_digital.avx2_allowed = agc2_properties->avx2_allowed;
+ adaptive_digital.neon_allowed = agc2_properties->neon_allowed;
}
} else if (use_fixed_digital_agc2) {
// Experimental AGC is disabled, thus hybrid AGC is disabled. Config AGC2
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h
index a5c2b19d8f9..53f5718d9d4 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h
@@ -125,6 +125,9 @@ struct PLATFORM_EXPORT AdaptiveGainController2Properties {
int gain_applier_speech_frames_threshold;
int max_gain_change_db_per_second;
int max_output_noise_level_dbfs;
+ bool sse2_allowed;
+ bool avx2_allowed;
+ bool neon_allowed;
};
// Configures automatic gain control in `apm_config`. If `agc_enabled` is true
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options_test.cc b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options_test.cc
index 5075bba6711..e2ce2e3b139 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options_test.cc
@@ -51,6 +51,9 @@ TEST(ConfigAutomaticGainControlTest, EnableHybridAGC) {
agc2_properties.gain_applier_speech_frames_threshold = 5;
agc2_properties.max_gain_change_db_per_second = 4;
agc2_properties.max_output_noise_level_dbfs = -22;
+ agc2_properties.sse2_allowed = true;
+ agc2_properties.avx2_allowed = true;
+ agc2_properties.neon_allowed = true;
const double compression_gain_db = 10.0;
ConfigAutomaticGainControl(
@@ -88,6 +91,9 @@ TEST(ConfigAutomaticGainControlTest, EnableHybridAGC) {
agc2_properties.max_gain_change_db_per_second);
EXPECT_FLOAT_EQ(adaptive_digital.max_output_noise_level_dbfs,
agc2_properties.max_output_noise_level_dbfs);
+ EXPECT_TRUE(adaptive_digital.sse2_allowed);
+ EXPECT_TRUE(adaptive_digital.avx2_allowed);
+ EXPECT_TRUE(adaptive_digital.neon_allowed);
}
TEST(PopulateApmConfigTest, DefaultWithoutConfigJson) {
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
index 047afec8d88..7e8c6da0177 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
@@ -28,11 +28,6 @@ void SendLogMessage(const std::string& message) {
} // namespace
-const int kMaxAudioLatencyMs = 5000;
-static_assert(std::numeric_limits<int>::max() / media::limits::kMaxSampleRate >
- kMaxAudioLatencyMs,
- "The maxium audio latency can cause overflow.");
-
// TODO(https://crbug.com/638081):
// Like in ProcessedLocalAudioSource::GetBufferSize(), we should re-evaluate
// whether Android needs special treatment here.
@@ -45,7 +40,7 @@ const int kFallbackAudioLatencyMs =
static_assert(kFallbackAudioLatencyMs >= 0,
"Audio latency has to be non-negative.");
-static_assert(kFallbackAudioLatencyMs <= kMaxAudioLatencyMs,
+static_assert(kFallbackAudioLatencyMs <= 5000,
"Fallback audio latency exceeds maximum.");
MediaStreamAudioSource::MediaStreamAudioSource(
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
index cabcd97c986..065241800e1 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
@@ -139,8 +139,9 @@ void MediaStreamAudioTrack::OnSetFormat(const media::AudioParameters& params) {
void MediaStreamAudioTrack::OnData(const media::AudioBus& audio_bus,
base::TimeTicks reference_time) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
- "MediaStreamAudioTrack::OnData");
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "MediaStreamAudioTrack::OnData", "this",
+ static_cast<void*>(this), "frame", audio_bus.frames());
if (!received_audio_callback_) {
// Add log message with unique this pointer id to mark the audio track as
diff --git a/chromium/third_party/blink/renderer/platform/mediastream/webaudio_media_stream_source.cc b/chromium/third_party/blink/renderer/platform/mediastream/webaudio_media_stream_source.cc
index 1f936de9087..30800b44aa0 100644
--- a/chromium/third_party/blink/renderer/platform/mediastream/webaudio_media_stream_source.cc
+++ b/chromium/third_party/blink/renderer/platform/mediastream/webaudio_media_stream_source.cc
@@ -86,8 +86,9 @@ void WebAudioMediaStreamSource::EnsureSourceIsStopped() {
void WebAudioMediaStreamSource::ConsumeAudio(
const Vector<const float*>& audio_data,
size_t number_of_frames) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
- "WebAudioMediaStreamSource::ConsumeAudio");
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "WebAudioMediaStreamSource::ConsumeAudio", "frames",
+ number_of_frames);
// TODO(miu): Plumbing is needed to determine the actual capture timestamp
// of the audio, instead of just snapshotting base::TimeTicks::Now(), for
@@ -107,8 +108,9 @@ void WebAudioMediaStreamSource::ConsumeAudio(
void WebAudioMediaStreamSource::DeliverRebufferedAudio(
const media::AudioBus& audio_bus,
int frame_delay) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
- "WebAudioMediaStreamSource::DeliverRebufferedAudio");
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "WebAudioMediaStreamSource::DeliverRebufferedAudio", "frames",
+ audio_bus.frames());
const base::TimeTicks reference_time =
current_reference_time_ +
base::TimeDelta::FromMicroseconds(
diff --git a/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc b/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
index f185bd0b9b8..c02c3241f0e 100644
--- a/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
+++ b/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
@@ -33,6 +33,7 @@
#include <stddef.h>
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-blink.h"
#include "third_party/blink/renderer/platform/mhtml/archive_resource.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_parser.h"
@@ -220,6 +221,7 @@ MHTMLArchive* MHTMLArchive::CreateArchive(
const KURL& url,
scoped_refptr<const SharedBuffer> data) {
MHTMLArchive* archive = MakeGarbageCollected<MHTMLArchive>();
+ archive->archive_url_ = url;
// |data| may be null if archive file is empty.
if (!data || data->IsEmpty()) {
@@ -284,7 +286,7 @@ bool MHTMLArchive::CanLoadArchive(const KURL& url) {
// MHTML pages can only be loaded from local URLs, http/https URLs, and
// content URLs(Android specific). The latter is now allowed due to full
// sandboxing enforcement on MHTML pages.
- if (SchemeRegistry::ShouldTreatURLSchemeAsLocal(url.Protocol()))
+ if (base::Contains(url::GetLocalSchemes(), url.Protocol().Ascii()))
return true;
if (url.ProtocolIsInHTTPFamily())
return true;
@@ -440,6 +442,10 @@ ArchiveResource* MHTMLArchive::SubresourceForURL(const KURL& url) const {
return subresources_.at(url.GetString());
}
+String MHTMLArchive::GetCacheIdentifier() const {
+ return archive_url_.GetString();
+}
+
void MHTMLArchive::Trace(Visitor* visitor) const {
visitor->Trace(main_resource_);
visitor->Trace(subresources_);
diff --git a/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.h b/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
index 032ed9ff483..d2c3244dbc6 100644
--- a/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
+++ b/chromium/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
@@ -33,9 +33,9 @@
#include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-blink-forward.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
-
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -102,6 +102,8 @@ class PLATFORM_EXPORT MHTMLArchive final
ArchiveResource* MainResource() const { return main_resource_.Get(); }
ArchiveResource* SubresourceForURL(const KURL&) const;
+ String GetCacheIdentifier() const;
+
// The purported creation date (as expressed by the Date: header).
base::Time Date() const { return date_; }
@@ -117,6 +119,9 @@ class PLATFORM_EXPORT MHTMLArchive final
void AddSubresource(ArchiveResource*);
static bool CanLoadArchive(const KURL&);
+ // URL of the MHTML resource (e.g. file:///foo/bar.mhtml).
+ KURL archive_url_;
+
base::Time date_;
Member<ArchiveResource> main_resource_;
SubArchiveResources subresources_;
diff --git a/chromium/third_party/blink/renderer/platform/mojo/DEPS b/chromium/third_party/blink/renderer/platform/mojo/DEPS
index 5a7db27e6b8..f9176306dfd 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/DEPS
+++ b/chromium/third_party/blink/renderer/platform/mojo/DEPS
@@ -24,6 +24,7 @@ include_rules = [
"+third_party/blink/renderer/platform/context_lifecycle_notifier.h",
"+third_party/blink/renderer/platform/heap_observer_set.h",
"+third_party/blink/renderer/platform/heap",
+ "+third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h",
]
specific_include_rules = {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/big_string_mojom_traits_test.cc b/chromium/third_party/blink/renderer/platform/mojo/big_string_mojom_traits_test.cc
index 6548da748c0..8c586854b3e 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/big_string_mojom_traits_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/big_string_mojom_traits_test.cc
@@ -18,7 +18,7 @@ TEST(BigStringMojomTraitsTest, BigString_Null) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -28,7 +28,7 @@ TEST(BigStringMojomTraitsTest, BigString_Empty) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -39,7 +39,7 @@ TEST(BigStringMojomTraitsTest, BigString_Short) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
// Replace the "o"s in "hello world" with "o"s with acute, so that |str| is
@@ -49,7 +49,7 @@ TEST(BigStringMojomTraitsTest, BigString_Short) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -62,7 +62,7 @@ TEST(BigStringMojomTraitsTest, BigString_Long) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
diff --git a/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc b/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
index bae9ffb051d..f55dcfa9534 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.cc
@@ -14,7 +14,7 @@
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.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/file_system_access_data_transfer_token.mojom-blink.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -76,22 +76,22 @@ bool StructTraits<
// static
base::FilePath StructTraits<
- blink::mojom::DragItemFileDataView,
+ blink::mojom::DataTransferFileDataView,
blink::WebDragData::Item>::path(const blink::WebDragData::Item& item) {
return WebStringToFilePath(item.filename_data);
}
// static
base::FilePath
-StructTraits<blink::mojom::DragItemFileDataView, blink::WebDragData::Item>::
+StructTraits<blink::mojom::DataTransferFileDataView, blink::WebDragData::Item>::
display_name(const blink::WebDragData::Item& item) {
return WebStringToFilePath(item.display_name_data);
}
// static
bool StructTraits<
- blink::mojom::DragItemFileDataView,
- blink::WebDragData::Item>::Read(blink::mojom::DragItemFileDataView data,
+ blink::mojom::DataTransferFileDataView,
+ blink::WebDragData::Item>::Read(blink::mojom::DataTransferFileDataView data,
blink::WebDragData::Item* out) {
blink::WebDragData::Item item;
base::FilePath filename_data, display_name_data;
@@ -102,13 +102,13 @@ bool StructTraits<
item.storage_type = blink::WebDragData::Item::kStorageTypeFilename;
item.filename_data = blink::FilePathToWebString(filename_data);
item.display_name_data = blink::FilePathToWebString(display_name_data);
- mojo::PendingRemote<::blink::mojom::blink::NativeFileSystemDragDropToken>
- native_file_system_token(
- data.TakeNativeFileSystemToken<mojo::PendingRemote<
- ::blink::mojom::blink::NativeFileSystemDragDropToken>>());
- item.native_file_system_entry =
- base::MakeRefCounted<::blink::NativeFileSystemDropData>(
- std::move(native_file_system_token));
+ mojo::PendingRemote<::blink::mojom::blink::FileSystemAccessDataTransferToken>
+ file_system_access_token(
+ data.TakeFileSystemAccessToken<mojo::PendingRemote<
+ ::blink::mojom::blink::FileSystemAccessDataTransferToken>>());
+ item.file_system_access_entry =
+ base::MakeRefCounted<::blink::FileSystemAccessDropData>(
+ std::move(file_system_access_token));
*out = std::move(item);
return true;
@@ -182,12 +182,12 @@ WTF::String StructTraits<blink::mojom::DragItemFileSystemFileDataView,
}
// static
-mojo::PendingRemote<blink::mojom::blink::NativeFileSystemDragDropToken>
-StructTraits<blink::mojom::DragItemFileDataView, blink::WebDragData::Item>::
- native_file_system_token(const blink::WebDragData::Item& item) {
+mojo::PendingRemote<blink::mojom::blink::FileSystemAccessDataTransferToken>
+StructTraits<blink::mojom::DataTransferFileDataView, blink::WebDragData::Item>::
+ file_system_access_token(const blink::WebDragData::Item& item) {
// Should never have to send a transfer token information from the renderer
// to the browser.
- DCHECK(!item.native_file_system_entry);
+ DCHECK(!item.file_system_access_entry);
return mojo::NullRemote();
}
diff --git a/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h b/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
index de0f8318612..969107730c1 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/drag_mojom_traits.h
@@ -16,7 +16,8 @@
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "mojo/public/cpp/bindings/union_traits.h"
#include "services/network/public/mojom/referrer_policy.mojom-forward.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/data_transfer/data_transfer.mojom-shared.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_data_transfer_token.mojom-blink.h"
#include "third_party/blink/public/mojom/page/drag.mojom-shared.h"
#include "third_party/blink/public/platform/web_drag_data.h"
#include "third_party/blink/renderer/platform/mojo/kurl_mojom_traits.h"
@@ -49,13 +50,14 @@ struct StructTraits<blink::mojom::DragItemStringDataView,
};
template <>
-struct StructTraits<blink::mojom::DragItemFileDataView,
+struct StructTraits<blink::mojom::DataTransferFileDataView,
blink::WebDragData::Item> {
static base::FilePath path(const blink::WebDragData::Item& item);
static base::FilePath display_name(const blink::WebDragData::Item& item);
- static mojo::PendingRemote<blink::mojom::blink::NativeFileSystemDragDropToken>
- native_file_system_token(const blink::WebDragData::Item& item);
- static bool Read(blink::mojom::DragItemFileDataView data,
+ static mojo::PendingRemote<
+ blink::mojom::blink::FileSystemAccessDataTransferToken>
+ file_system_access_token(const blink::WebDragData::Item& item);
+ static bool Read(blink::mojom::DataTransferFileDataView data,
blink::WebDragData::Item* out);
};
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h
index c4e77cad341..0fd2f4abc6f 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h
index 5f92e73e5b4..80bb91330c4 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set.h
@@ -7,11 +7,13 @@
#include <utility>
+#include "base/callback.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
@@ -42,6 +44,11 @@ class HeapMojoAssociatedReceiverSet {
const HeapMojoAssociatedReceiverSet&) = delete;
// Methods to redirect to mojo::AssociatedReceiverSet:
+ void set_disconnect_handler(base::RepeatingClosure handler) {
+ wrapper_->associated_receiver_set().set_disconnect_handler(
+ std::move(handler));
+ }
+
mojo::ReceiverId Add(
mojo::PendingAssociatedReceiver<Interface> associated_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
index d9bb1100e0b..643a46d6ac5 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
@@ -17,48 +17,20 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
-class FakeContextNotifier final : public GarbageCollected<FakeContextNotifier>,
- public ContextLifecycleNotifier {
- public:
- FakeContextNotifier() = default;
-
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
-
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
template <HeapMojoWrapperMode Mode>
class GCOwner;
template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedReceiverSetGCBaseTest : public TestSupportingGC {
public:
- FakeContextNotifier* context() { return context_; }
+ MockContextLifecycleNotifier* context() { return context_; }
scoped_refptr<base::NullTaskRunner> task_runner() {
return null_task_runner_;
}
@@ -69,7 +41,7 @@ class HeapMojoAssociatedReceiverSetGCBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<FakeContextNotifier>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
}
void TearDown() override {
@@ -77,7 +49,7 @@ class HeapMojoAssociatedReceiverSetGCBaseTest : public TestSupportingGC {
PreciselyCollectGarbage();
}
- Persistent<FakeContextNotifier> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<GCOwner<Mode>> owner_;
bool is_owner_alive_ = false;
scoped_refptr<base::NullTaskRunner> null_task_runner_ =
@@ -88,7 +60,7 @@ template <HeapMojoWrapperMode Mode>
class GCOwner : public GarbageCollected<GCOwner<Mode>>,
public sample::blink::Service {
public:
- explicit GCOwner(FakeContextNotifier* context,
+ explicit GCOwner(MockContextLifecycleNotifier* context,
HeapMojoAssociatedReceiverSetGCBaseTest<Mode>* test)
: associated_receiver_set_(this, context), test_(test) {
test_->set_is_owner_alive(true);
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
index 95811f150c0..0e9b08d9dce 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
@@ -12,38 +12,14 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
namespace blink {
namespace {
-class MockContext final : public GarbageCollected<MockContext>,
- public ContextLifecycleNotifier {
- public:
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedReceiverGCBaseTest;
@@ -55,7 +31,7 @@ class AssociatedReceiverOwner
public:
explicit AssociatedReceiverOwner(
- MockContext* context,
+ MockContextLifecycleNotifier* context,
HeapMojoAssociatedReceiverGCBaseTest<Mode>* test = nullptr)
: associated_receiver_(this, context), test_(test) {
if (test_)
@@ -103,7 +79,7 @@ class HeapMojoAssociatedReceiverGCBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
disconnected_ = false;
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ =
MakeGarbageCollected<AssociatedReceiverOwner<Mode>>(context_, this);
scoped_refptr<base::NullTaskRunner> null_task_runner =
@@ -123,7 +99,7 @@ class HeapMojoAssociatedReceiverGCBaseTest : public TestSupportingGC {
PreciselyCollectGarbage();
}
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<AssociatedReceiverOwner<Mode>> owner_;
bool is_owner_alive_ = false;
base::RunLoop run_loop_;
@@ -136,7 +112,7 @@ class HeapMojoAssociatedReceiverDestroyContextBaseTest
: public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<AssociatedReceiverOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -145,7 +121,7 @@ class HeapMojoAssociatedReceiverDestroyContextBaseTest
null_task_runner));
}
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<AssociatedReceiverOwner<Mode>> owner_;
mojo::AssociatedRemote<sample::blink::Service> associated_remote_;
};
@@ -167,6 +143,8 @@ class HeapMojoAssociatedReceiverDestroyContextWithoutContextObserverTest
// Make HeapMojoAssociatedReceiver with context observer garbage collected and
// check that the connection is disconnected right after the marking phase.
+// TODO(1056170): Re-enable test.
+#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoAssociatedReceiverGCWithContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
@@ -175,6 +153,7 @@ TEST_F(HeapMojoAssociatedReceiverGCWithContextObserverTest, ResetsOnGC) {
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
+#endif // !USE_V8_OILPAN
// Check that the owner
TEST_F(HeapMojoAssociatedReceiverGCWithContextObserverTest,
@@ -191,6 +170,8 @@ TEST_F(HeapMojoAssociatedReceiverGCWithContextObserverTest,
// Make HeapMojoAssociatedReceiver without context observer garbage collected
// and check that the connection is disconnected right after the marking phase.
+// TODO(1056170): Re-enable test.
+#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoAssociatedReceiverGCWithoutContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
@@ -199,6 +180,7 @@ TEST_F(HeapMojoAssociatedReceiverGCWithoutContextObserverTest, ResetsOnGC) {
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
+#endif // !USE_V8_OILPAN
// Destroy the context with context observer and check that the connection is
// disconnected.
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h
index 4a3760ee900..ed70fb988fc 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h
new file mode 100644
index 00000000000..6ab53683b9a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h
@@ -0,0 +1,119 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_ASSOCIATED_REMOTE_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_ASSOCIATED_REMOTE_SET_H_
+
+#include <utility>
+
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mojo/features.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+
+namespace blink {
+
+// HeapMojoAssociatedRemoteSet is a wrapper for mojo::AssociatedRemoteSet to be
+// owned by a garbage-collected object. Blink is expected to use
+// HeapMojoAssociatedRemoteSet by default. HeapMojoAssociatedRemoteSet must be
+// associated with an ExecutionContext. It resets the mojo connection when the
+// ExecutionContext is detached.
+template <typename Interface,
+ HeapMojoWrapperMode Mode = HeapMojoWrapperMode::kWithContextObserver>
+class HeapMojoAssociatedRemoteSet {
+ DISALLOW_NEW();
+
+ public:
+ using DisconnectHandler =
+ typename mojo::AssociatedRemoteSet<Interface>::DisconnectHandler;
+ using Iterator = typename mojo::AssociatedRemoteSet<Interface>::Iterator;
+
+ explicit HeapMojoAssociatedRemoteSet(ContextLifecycleNotifier* notifier)
+ : wrapper_(MakeGarbageCollected<Wrapper>(notifier)) {}
+
+ HeapMojoAssociatedRemoteSet(const HeapMojoAssociatedRemoteSet&) = delete;
+ HeapMojoAssociatedRemoteSet& operator=(const HeapMojoAssociatedRemoteSet&) =
+ delete;
+ HeapMojoAssociatedRemoteSet(HeapMojoAssociatedRemoteSet&&) = default;
+ HeapMojoAssociatedRemoteSet& operator=(HeapMojoAssociatedRemoteSet&&) =
+ default;
+
+ // Methods to redirect to mojo::AssociatedRemoteSet:
+ mojo::RemoteSetElementId Add(
+ mojo::PendingAssociatedRemote<Interface> associated_remote,
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ DCHECK(task_runner);
+ return wrapper_->associated_remote_set().Add(std::move(associated_remote),
+ task_runner);
+ }
+
+ void Remove(mojo::RemoteSetElementId id) {
+ wrapper_->associated_remote_set().Remove(id);
+ }
+
+ bool Contains(mojo::RemoteSetElementId id) {
+ return wrapper_->associated_remote_set().Contains(id);
+ }
+
+ void set_disconnect_handler(DisconnectHandler handler) {
+ wrapper_->associated_remote_set().set_disconnect_handler(
+ std::move(handler));
+ }
+
+ void Clear() { wrapper_->associated_remote_set().Clear(); }
+
+ bool empty() const { return wrapper_->associated_remote_set().empty(); }
+ size_t size() const { return wrapper_->associated_remote_set().size(); }
+
+ Iterator begin() { return wrapper_->associated_remote_set().begin(); }
+ Iterator begin() const { return wrapper_->associated_remote_set().begin(); }
+ Iterator end() { return wrapper_->associated_remote_set().end(); }
+ Iterator end() const { return wrapper_->associated_remote_set().end(); }
+
+ void Trace(Visitor* visitor) const { visitor->Trace(wrapper_); }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
+ NoClearOnConservativeGC);
+
+ // Garbage collected wrapper class to add a prefinalizer.
+ class Wrapper final : public GarbageCollected<Wrapper>,
+ public ContextLifecycleObserver {
+ USING_PRE_FINALIZER(Wrapper, Dispose);
+
+ public:
+ explicit Wrapper(ContextLifecycleNotifier* notifier) {
+ SetContextLifecycleNotifier(notifier);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ ContextLifecycleObserver::Trace(visitor);
+ }
+
+ void Dispose() { associated_remote_set_.Clear(); }
+
+ mojo::AssociatedRemoteSet<Interface>& associated_remote_set() {
+ return associated_remote_set_;
+ }
+
+ // ContextLifecycleObserver methods
+ void ContextDestroyed() override {
+ if (Mode == HeapMojoWrapperMode::kWithContextObserver ||
+ (Mode == HeapMojoWrapperMode::kWithoutContextObserver &&
+ base::FeatureList::IsEnabled(kHeapMojoUseContextObserver)))
+ associated_remote_set_.Clear();
+ }
+
+ private:
+ mojo::AssociatedRemoteSet<Interface> associated_remote_set_;
+ };
+
+ Member<Wrapper> wrapper_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_ASSOCIATED_REMOTE_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set_test.cc
new file mode 100644
index 00000000000..300b7bec109
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set_test.cc
@@ -0,0 +1,214 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h"
+
+#include <utility>
+
+#include <string>
+#include "base/macros.h"
+#include "base/test/null_task_runner.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "mojo/public/interfaces/bindings/tests/sample_service.mojom-blink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
+
+namespace blink {
+
+namespace {
+
+template <HeapMojoWrapperMode Mode>
+class HeapMojoAssociatedRemoteSetGCBaseTest;
+
+template <HeapMojoWrapperMode Mode>
+class GCOwner : public GarbageCollected<GCOwner<Mode>> {
+ public:
+ explicit GCOwner(MockContextLifecycleNotifier* context,
+ HeapMojoAssociatedRemoteSetGCBaseTest<Mode>* test)
+ : remote_set_(context), test_(test) {
+ test_->set_is_owner_alive(true);
+ }
+ void Dispose() { test_->set_is_owner_alive(false); }
+ void Trace(Visitor* visitor) const { visitor->Trace(remote_set_); }
+
+ HeapMojoAssociatedRemoteSet<sample::blink::Service, Mode>&
+ associated_remote_set() {
+ return remote_set_;
+ }
+
+ private:
+ HeapMojoAssociatedRemoteSet<sample::blink::Service, Mode> remote_set_;
+ HeapMojoAssociatedRemoteSetGCBaseTest<Mode>* test_;
+};
+
+template <HeapMojoWrapperMode Mode>
+class HeapMojoAssociatedRemoteSetGCBaseTest : public TestSupportingGC {
+ public:
+ MockContextLifecycleNotifier* context() { return context_; }
+ scoped_refptr<base::NullTaskRunner> task_runner() {
+ return null_task_runner_;
+ }
+ GCOwner<Mode>* owner() { return owner_; }
+ void set_is_owner_alive(bool alive) { is_owner_alive_ = alive; }
+
+ void ClearOwner() { owner_ = nullptr; }
+
+ protected:
+ void SetUp() override {
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
+ owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
+ }
+ void TearDown() override {
+ owner_ = nullptr;
+ PreciselyCollectGarbage();
+ }
+
+ Persistent<MockContextLifecycleNotifier> context_;
+ Persistent<GCOwner<Mode>> owner_;
+ bool is_owner_alive_ = false;
+ scoped_refptr<base::NullTaskRunner> null_task_runner_ =
+ base::MakeRefCounted<base::NullTaskRunner>();
+};
+
+} // namespace
+
+class HeapMojoAssociatedRemoteSetGCWithContextObserverTest
+ : public HeapMojoAssociatedRemoteSetGCBaseTest<
+ HeapMojoWrapperMode::kWithContextObserver> {};
+class HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest
+ : public HeapMojoAssociatedRemoteSetGCBaseTest<
+ HeapMojoWrapperMode::kForceWithoutContextObserver> {};
+
+// GC the HeapMojoAssociatedRemoteSet with context observer and verify that the
+// remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest, RemovesRemote) {
+ auto& remote_set = owner()->associated_remote_set();
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote;
+ ignore_result(remote.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Remove(rid);
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// Check that the wrapper does not outlive the owner when ConservativeGC finds
+// the wrapper.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
+ NoClearOnConservativeGC) {
+ auto* wrapper = owner_->associated_remote_set().wrapper_.Get();
+
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote;
+ ignore_result(remote.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid =
+ owner()->associated_remote_set().Add(std::move(remote), task_runner());
+ EXPECT_TRUE(wrapper->associated_remote_set().Contains(rid));
+
+ ClearOwner();
+ EXPECT_TRUE(is_owner_alive_);
+
+ ConservativelyCollectGarbage();
+
+ EXPECT_TRUE(wrapper->associated_remote_set().Contains(rid));
+ EXPECT_TRUE(is_owner_alive_);
+}
+
+// GC the HeapMojoAssociatedRemoteSet without context observer and verify that
+// the remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest, RemovesRemote) {
+ auto& remote_set = owner()->associated_remote_set();
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote;
+ ignore_result(remote.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Remove(rid);
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// GC the HeapMojoAssociatedRemoteSet with context observer and verify that the
+// remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
+ ClearLeavesSetEmpty) {
+ auto& remote_set = owner()->associated_remote_set();
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote;
+ ignore_result(remote.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// GC the HeapMojoAssociatedRemoteSet without context observer and verify that
+// the remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest,
+ ClearLeavesSetEmpty) {
+ auto& remote_set = owner()->associated_remote_set();
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote;
+ ignore_result(remote.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// Add several remote and confirm that remote_set holds properly.
+TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
+ AddSeveralRemoteSet) {
+ auto& remote_set = owner()->associated_remote_set();
+
+ EXPECT_TRUE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 0u);
+
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote_1;
+ ignore_result(remote_1.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid_1 =
+ remote_set.Add(std::move(remote_1), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid_1));
+ EXPECT_FALSE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 1u);
+
+ mojo::PendingAssociatedRemote<sample::blink::Service> remote_2;
+ ignore_result(remote_2.InitWithNewEndpointAndPassReceiver());
+
+ mojo::RemoteSetElementId rid_2 =
+ remote_set.Add(std::move(remote_2), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid_1));
+ EXPECT_TRUE(remote_set.Contains(rid_2));
+ EXPECT_FALSE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 2u);
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid_1));
+ EXPECT_FALSE(remote_set.Contains(rid_2));
+ EXPECT_TRUE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 0u);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
index f8b016de3fa..3baa809832c 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
@@ -12,38 +12,13 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
-class MockContext final : public GarbageCollected<MockContext>,
- public ContextLifecycleNotifier {
- public:
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
class ServiceImpl : public sample::blink::Service {
public:
mojo::AssociatedReceiver<sample::blink::Service>& associated_receiver() {
@@ -65,7 +40,7 @@ template <HeapMojoWrapperMode Mode>
class AssociatedRemoteOwner
: public GarbageCollected<AssociatedRemoteOwner<Mode>> {
public:
- explicit AssociatedRemoteOwner(MockContext* context)
+ explicit AssociatedRemoteOwner(MockContextLifecycleNotifier* context)
: associated_remote_(context) {}
explicit AssociatedRemoteOwner(
HeapMojoAssociatedRemote<sample::blink::Service, Mode> associated_remote)
@@ -84,7 +59,7 @@ template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedRemoteDestroyContextBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<AssociatedRemoteOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -94,7 +69,7 @@ class HeapMojoAssociatedRemoteDestroyContextBaseTest : public TestSupportingGC {
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<AssociatedRemoteOwner<Mode>> owner_;
};
@@ -108,7 +83,7 @@ class HeapMojoAssociatedRemoteDisconnectWithReasonHandlerBaseTest
protected:
void SetUp() override {
CHECK(!disconnected_with_reason_);
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<AssociatedRemoteOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -126,7 +101,7 @@ class HeapMojoAssociatedRemoteDisconnectWithReasonHandlerBaseTest
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<AssociatedRemoteOwner<Mode>> owner_;
base::RunLoop run_loop_;
bool disconnected_with_reason_ = false;
@@ -136,7 +111,7 @@ template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedRemoteMoveBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
HeapMojoAssociatedRemote<sample::blink::Service, Mode> associated_remote(
context_);
owner_ = MakeGarbageCollected<AssociatedRemoteOwner<Mode>>(
@@ -149,7 +124,7 @@ class HeapMojoAssociatedRemoteMoveBaseTest : public TestSupportingGC {
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<AssociatedRemoteOwner<Mode>> owner_;
};
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
index f11a4052644..58978f281c9 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
index 8cb14a27d91..385192f86c6 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
@@ -44,6 +45,16 @@ class HeapMojoReceiverSet {
HeapMojoReceiverSet& operator=(const HeapMojoReceiverSet&) = delete;
// Methods to redirect to mojo::ReceiverSet:
+ void set_disconnect_handler(base::RepeatingClosure handler) {
+ wrapper_->receiver_set().set_disconnect_handler(std::move(handler));
+ }
+
+ void set_disconnect_with_reason_handler(
+ mojo::RepeatingConnectionErrorWithReasonCallback handler) {
+ wrapper_->receiver_set().set_disconnect_with_reason_handler(
+ std::move(handler));
+ }
+
mojo::ReceiverId Add(mojo::PendingReceiver<Interface> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
DCHECK(task_runner);
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
index c7fb431a4b0..2683da597c1 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
@@ -17,40 +17,13 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
-class FakeContextNotifier final : public GarbageCollected<FakeContextNotifier>,
- public ContextLifecycleNotifier {
- public:
- FakeContextNotifier() = default;
-
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
template <HeapMojoWrapperMode Mode, typename ContextType>
class HeapMojoReceiverSetGCBaseTest;
@@ -58,7 +31,7 @@ template <HeapMojoWrapperMode Mode, typename ContextType>
class GCOwner : public GarbageCollected<GCOwner<Mode, ContextType>>,
public sample::blink::Service {
public:
- explicit GCOwner(FakeContextNotifier* context,
+ explicit GCOwner(MockContextLifecycleNotifier* context,
HeapMojoReceiverSetGCBaseTest<Mode, ContextType>* test)
: receiver_set_(this, context), test_(test) {
test_->set_is_owner_alive(true);
@@ -86,7 +59,7 @@ class GCOwner : public GarbageCollected<GCOwner<Mode, ContextType>>,
template <HeapMojoWrapperMode Mode, typename ContextType>
class HeapMojoReceiverSetGCBaseTest : public TestSupportingGC {
public:
- FakeContextNotifier* context() { return context_; }
+ MockContextLifecycleNotifier* context() { return context_; }
scoped_refptr<base::NullTaskRunner> task_runner() {
return null_task_runner_;
}
@@ -97,7 +70,7 @@ class HeapMojoReceiverSetGCBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<FakeContextNotifier>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<GCOwner<Mode, ContextType>>(context(), this);
}
void TearDown() override {
@@ -105,7 +78,7 @@ class HeapMojoReceiverSetGCBaseTest : public TestSupportingGC {
PreciselyCollectGarbage();
}
- Persistent<FakeContextNotifier> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<GCOwner<Mode, ContextType>> owner_;
bool is_owner_alive_ = false;
scoped_refptr<base::NullTaskRunner> null_task_runner_ =
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
index 94390beae56..af03c51ae02 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
@@ -14,40 +14,14 @@
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
namespace blink {
namespace {
-class MockContext final : public GarbageCollected<MockContext>,
- public ContextLifecycleNotifier {
- public:
- MockContext() = default;
-
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverGCBaseTest;
@@ -57,7 +31,7 @@ class ReceiverOwner : public GarbageCollected<ReceiverOwner<Mode>>,
USING_PRE_FINALIZER(ReceiverOwner, Dispose);
public:
- explicit ReceiverOwner(MockContext* context,
+ explicit ReceiverOwner(MockContextLifecycleNotifier* context,
HeapMojoReceiverGCBaseTest<Mode>* test = nullptr)
: receiver_(this, context), test_(test) {
if (test_)
@@ -99,7 +73,7 @@ class HeapMojoReceiverGCBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
disconnected_ = false;
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<ReceiverOwner<Mode>>(context_, this);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -117,7 +91,7 @@ class HeapMojoReceiverGCBaseTest : public TestSupportingGC {
PreciselyCollectGarbage();
}
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<ReceiverOwner<Mode>> owner_;
bool is_owner_alive_ = false;
base::RunLoop run_loop_;
@@ -135,7 +109,7 @@ class HeapMojoReceiverDisconnectWithReasonHandlerBaseTest
void SetUp() override {
CHECK(disconnected_reason_.empty());
this->disconnected_ = false;
- this->context_ = MakeGarbageCollected<MockContext>();
+ this->context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
this->owner_ =
MakeGarbageCollected<ReceiverOwner<Mode>>(this->context_, this);
scoped_refptr<base::NullTaskRunner> null_task_runner =
@@ -158,7 +132,7 @@ template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverDestroyContextBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<ReceiverOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -166,7 +140,7 @@ class HeapMojoReceiverDestroyContextBaseTest : public TestSupportingGC {
owner_->receiver().BindNewPipeAndPassRemote(null_task_runner));
}
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<ReceiverOwner<Mode>> owner_;
mojo::Remote<sample::blink::Service> remote_;
};
@@ -197,6 +171,8 @@ class HeapMojoReceiverDisconnectWithReasonHandlerWithoutContextObserverTest
// Make HeapMojoReceiver with context observer garbage collected and check that
// the connection is disconnected right after the marking phase.
+// TODO(1056170): Re-enable test.
+#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoReceiverGCWithContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
@@ -205,6 +181,7 @@ TEST_F(HeapMojoReceiverGCWithContextObserverTest, ResetsOnGC) {
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
+#endif // !USE_V8_OILPAN
// Check that the owner
TEST_F(HeapMojoReceiverGCWithContextObserverTest, NoResetOnConservativeGC) {
@@ -220,6 +197,8 @@ TEST_F(HeapMojoReceiverGCWithContextObserverTest, NoResetOnConservativeGC) {
// Make HeapMojoReceiver without context observer garbage collected and check
// that the connection is disconnected right after the marking phase.
+// TODO(1056170): Re-enable test.
+#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoReceiverGCWithoutContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
@@ -228,6 +207,7 @@ TEST_F(HeapMojoReceiverGCWithoutContextObserverTest, ResetsOnGC) {
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
+#endif // !USE_V8_OILPAN
// Destroy the context with context observer and check that the connection is
// disconnected.
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
index c539d72756b..cae3ed995a4 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set.h
new file mode 100644
index 00000000000..41894b49d70
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set.h
@@ -0,0 +1,123 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_SET_H_
+
+#include <utility>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mojo/features.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+
+namespace blink {
+
+// HeapMojoRemoteSet is a wrapper for mojo::RemoteSet to be owned by a
+// garbage-collected object. Blink is expected to use HeapMojoRemoteSet by
+// default. HeapMojoRemoteSet must be associated with context.
+// HeapMojoRemoteSet's constructor takes context as a mandatory parameter.
+// HeapMojoRemoteSet resets the mojo connection when the associated
+// ExecutionContext is detached.
+
+// TODO(crbug.com/1058076) HeapMojoWrapperMode should be removed once we ensure
+// that the interface is not used after ContextDestroyed().
+template <typename Interface,
+ HeapMojoWrapperMode Mode = HeapMojoWrapperMode::kWithContextObserver>
+class HeapMojoRemoteSet {
+ DISALLOW_NEW();
+
+ public:
+ using DisconnectHandler =
+ typename mojo::RemoteSet<Interface>::DisconnectHandler;
+ using Iterator = typename mojo::RemoteSet<Interface>::Iterator;
+
+ explicit HeapMojoRemoteSet(ContextLifecycleNotifier* notifier)
+ : wrapper_(MakeGarbageCollected<Wrapper>(notifier)) {}
+ HeapMojoRemoteSet(const HeapMojoRemoteSet&) = delete;
+ HeapMojoRemoteSet& operator=(const HeapMojoRemoteSet&) = delete;
+ HeapMojoRemoteSet(HeapMojoRemoteSet&&) = default;
+ HeapMojoRemoteSet& operator=(HeapMojoRemoteSet&&) = default;
+
+ // Methods to redirect to mojo::RemoteSet:
+ void set_disconnect_handler(DisconnectHandler handler) {
+ wrapper_->remote_set().set_disconnect_handler(std::move(handler));
+ }
+
+ mojo::RemoteSetElementId Add(mojo::Remote<Interface> remote) {
+ return wrapper_->remote_set().Add(std::move(remote));
+ }
+
+ mojo::RemoteSetElementId Add(
+ mojo::PendingRemote<Interface> remote,
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ DCHECK(task_runner);
+ return wrapper_->remote_set().Add(std::move(remote), task_runner);
+ }
+
+ void Remove(mojo::RemoteSetElementId id) {
+ wrapper_->remote_set().Remove(id);
+ }
+
+ bool Contains(mojo::RemoteSetElementId id) {
+ return wrapper_->remote_set().Contains(id);
+ }
+
+ void Clear() { wrapper_->remote_set().Clear(); }
+
+ bool empty() const { return wrapper_->remote_set().empty(); }
+ size_t size() const { return wrapper_->remote_set().size(); }
+
+ Iterator begin() { return wrapper_->remote_set().begin(); }
+ Iterator begin() const { return wrapper_->remote_set().begin(); }
+ Iterator end() { return wrapper_->remote_set().end(); }
+ Iterator end() const { return wrapper_->remote_set().end(); }
+
+ void Trace(Visitor* visitor) const { visitor->Trace(wrapper_); }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(HeapMojoRemoteSetGCWithContextObserverTest,
+ NoClearOnConservativeGC);
+
+ // Garbage collected wrapper class to add ContextLifecycleObserver.
+ class Wrapper final : public GarbageCollected<Wrapper>,
+ public ContextLifecycleObserver {
+ public:
+ explicit Wrapper(ContextLifecycleNotifier* notifier) {
+ SetContextLifecycleNotifier(notifier);
+ }
+ Wrapper(const Wrapper&) = delete;
+ Wrapper& operator=(const Wrapper&) = delete;
+ Wrapper(Wrapper&&) = default;
+ Wrapper& operator=(Wrapper&&) = default;
+
+ void Trace(Visitor* visitor) const override {
+ ContextLifecycleObserver::Trace(visitor);
+ }
+
+ mojo::RemoteSet<Interface>& remote_set() { return remote_set_; }
+
+ // ContextLifecycleObserver methods
+ void ContextDestroyed() override {
+ if (Mode == HeapMojoWrapperMode::kWithContextObserver ||
+ (Mode == HeapMojoWrapperMode::kWithoutContextObserver &&
+ base::FeatureList::IsEnabled(kHeapMojoUseContextObserver)))
+ remote_set_.Clear();
+ }
+
+ private:
+ mojo::RemoteSet<Interface> remote_set_;
+ };
+
+ Member<Wrapper> wrapper_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_HEAP_MOJO_REMOTE_SET_H_
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set_test.cc
new file mode 100644
index 00000000000..8628a94975a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_set_test.cc
@@ -0,0 +1,205 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote_set.h"
+
+#include <utility>
+
+#include <string>
+#include "base/test/null_task_runner.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "mojo/public/interfaces/bindings/tests/sample_service.mojom-blink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/heap_observer_set.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
+
+namespace blink {
+
+namespace {
+
+template <HeapMojoWrapperMode Mode>
+class HeapMojoRemoteSetGCBaseTest;
+
+template <HeapMojoWrapperMode Mode>
+class GCOwner : public GarbageCollected<GCOwner<Mode>> {
+ public:
+ explicit GCOwner(MockContextLifecycleNotifier* context,
+ HeapMojoRemoteSetGCBaseTest<Mode>* test)
+ : remote_set_(context), test_(test) {
+ test_->set_is_owner_alive(true);
+ }
+ void Dispose() { test_->set_is_owner_alive(false); }
+ void Trace(Visitor* visitor) const { visitor->Trace(remote_set_); }
+
+ HeapMojoRemoteSet<sample::blink::Service, Mode>& remote_set() {
+ return remote_set_;
+ }
+
+ private:
+ HeapMojoRemoteSet<sample::blink::Service, Mode> remote_set_;
+ HeapMojoRemoteSetGCBaseTest<Mode>* test_;
+};
+
+template <HeapMojoWrapperMode Mode>
+class HeapMojoRemoteSetGCBaseTest : public TestSupportingGC {
+ public:
+ MockContextLifecycleNotifier* context() { return context_; }
+ scoped_refptr<base::NullTaskRunner> task_runner() {
+ return null_task_runner_;
+ }
+ GCOwner<Mode>* owner() { return owner_; }
+ void set_is_owner_alive(bool alive) { is_owner_alive_ = alive; }
+
+ void ClearOwner() { owner_ = nullptr; }
+
+ protected:
+ void SetUp() override {
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
+ owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
+ }
+ void TearDown() override {
+ owner_ = nullptr;
+ PreciselyCollectGarbage();
+ }
+
+ Persistent<MockContextLifecycleNotifier> context_;
+ Persistent<GCOwner<Mode>> owner_;
+ bool is_owner_alive_ = false;
+ scoped_refptr<base::NullTaskRunner> null_task_runner_ =
+ base::MakeRefCounted<base::NullTaskRunner>();
+};
+
+} // namespace
+
+class HeapMojoRemoteSetGCWithContextObserverTest
+ : public HeapMojoRemoteSetGCBaseTest<
+ HeapMojoWrapperMode::kWithContextObserver> {};
+class HeapMojoRemoteSetGCWithoutContextObserverTest
+ : public HeapMojoRemoteSetGCBaseTest<
+ HeapMojoWrapperMode::kForceWithoutContextObserver> {};
+
+// GC the HeapMojoRemoteSet with context observer and verify that the remote
+// is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, RemovesRemote) {
+ auto& remote_set = owner()->remote_set();
+ auto remote = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Remove(rid);
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// Check that the wrapper does not outlive the owner when ConservativeGC finds
+// the wrapper.
+TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, NoClearOnConservativeGC) {
+ auto* wrapper = owner_->remote_set().wrapper_.Get();
+
+ auto remote = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+
+ mojo::RemoteSetElementId rid =
+ owner()->remote_set().Add(std::move(remote), task_runner());
+ EXPECT_TRUE(wrapper->remote_set().Contains(rid));
+
+ ClearOwner();
+ EXPECT_TRUE(is_owner_alive_);
+
+ ConservativelyCollectGarbage();
+
+ EXPECT_TRUE(wrapper->remote_set().Contains(rid));
+ EXPECT_TRUE(is_owner_alive_);
+}
+
+// GC the HeapMojoRemoteSet without context observer and verify that the
+// remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoRemoteSetGCWithoutContextObserverTest, RemovesRemote) {
+ auto& remote_set = owner()->remote_set();
+ auto remote = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Remove(rid);
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// GC the HeapMojoRemoteSet with context observer and verify that the remote
+// is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, ClearLeavesSetEmpty) {
+ auto& remote_set = owner()->remote_set();
+ auto remote = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// GC the HeapMojoRemoteSet without context observer and verify that the
+// remote is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoRemoteSetGCWithoutContextObserverTest, ClearLeavesSetEmpty) {
+ auto& remote_set = owner()->remote_set();
+ auto remote = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+
+ mojo::RemoteSetElementId rid =
+ remote_set.Add(std::move(remote), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid));
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid));
+}
+
+// Add several remote and confirm that remote_set holds properly.
+TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, AddSeveralRemoteSet) {
+ auto& remote_set = owner()->remote_set();
+
+ EXPECT_TRUE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 0u);
+
+ auto remote_1 = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+ mojo::RemoteSetElementId rid_1 =
+ remote_set.Add(std::move(remote_1), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid_1));
+ EXPECT_FALSE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 1u);
+
+ auto remote_2 = mojo::PendingRemote<sample::blink::Service>(
+ mojo::MessagePipe().handle0, 0);
+ mojo::RemoteSetElementId rid_2 =
+ remote_set.Add(std::move(remote_2), task_runner());
+ EXPECT_TRUE(remote_set.Contains(rid_1));
+ EXPECT_TRUE(remote_set.Contains(rid_2));
+ EXPECT_FALSE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 2u);
+
+ remote_set.Clear();
+
+ EXPECT_FALSE(remote_set.Contains(rid_1));
+ EXPECT_FALSE(remote_set.Contains(rid_2));
+ EXPECT_TRUE(remote_set.empty());
+ EXPECT_EQ(remote_set.size(), 0u);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
index 97b764b5ed8..ac3bc721847 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
@@ -14,40 +14,13 @@
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
-class MockContext final : public GarbageCollected<MockContext>,
- public ContextLifecycleNotifier {
- public:
- MockContext() = default;
-
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
class ServiceImpl : public sample::blink::Service {
public:
explicit ServiceImpl() = default;
@@ -68,7 +41,8 @@ class ServiceImpl : public sample::blink::Service {
template <HeapMojoWrapperMode Mode>
class RemoteOwner : public GarbageCollected<RemoteOwner<Mode>> {
public:
- explicit RemoteOwner(MockContext* context) : remote_(context) {}
+ explicit RemoteOwner(MockContextLifecycleNotifier* context)
+ : remote_(context) {}
explicit RemoteOwner(HeapMojoRemote<sample::blink::Service, Mode> remote)
: remote_(std::move(remote)) {}
@@ -83,7 +57,7 @@ template <HeapMojoWrapperMode Mode>
class HeapMojoRemoteDestroyContextBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<RemoteOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -92,7 +66,7 @@ class HeapMojoRemoteDestroyContextBaseTest : public TestSupportingGC {
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<RemoteOwner<Mode>> owner_;
};
@@ -106,7 +80,7 @@ class HeapMojoRemoteDisconnectWithReasonHandlerBaseTest
protected:
void SetUp() override {
CHECK(!disconnected_with_reason_);
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<RemoteOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
@@ -122,7 +96,7 @@ class HeapMojoRemoteDisconnectWithReasonHandlerBaseTest
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<RemoteOwner<Mode>> owner_;
base::RunLoop run_loop_;
bool disconnected_with_reason_ = false;
@@ -132,7 +106,7 @@ template <HeapMojoWrapperMode Mode>
class HeapMojoRemoteMoveBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<MockContext>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
HeapMojoRemote<sample::blink::Service, Mode> remote(context_);
owner_ = MakeGarbageCollected<RemoteOwner<Mode>>(std::move(remote));
scoped_refptr<base::NullTaskRunner> null_task_runner =
@@ -142,7 +116,7 @@ class HeapMojoRemoteMoveBaseTest : public TestSupportingGC {
}
ServiceImpl impl_;
- Persistent<MockContext> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<RemoteOwner<Mode>> owner_;
};
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
index 6ef8d0ae309..ae6158a83da 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mojo/features.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
index f3fe302f517..6267e5e36d3 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
@@ -12,44 +12,18 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
+#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
-class FakeContextNotifier final : public GarbageCollected<FakeContextNotifier>,
- public ContextLifecycleNotifier {
- public:
- FakeContextNotifier() = default;
-
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
- }
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
- ContextLifecycleNotifier::Trace(visitor);
- }
-
- private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
-};
-
template <HeapMojoWrapperMode Mode>
class GCOwner : public GarbageCollected<GCOwner<Mode>> {
public:
- explicit GCOwner(FakeContextNotifier* context) : receiver_set_(context) {}
+ explicit GCOwner(MockContextLifecycleNotifier* context)
+ : receiver_set_(context) {}
void Trace(Visitor* visitor) const { visitor->Trace(receiver_set_); }
HeapMojoUniqueReceiverSet<sample::blink::Service,
@@ -69,7 +43,7 @@ class GCOwner : public GarbageCollected<GCOwner<Mode>> {
template <HeapMojoWrapperMode Mode>
class HeapMojoUniqueReceiverSetBaseTest : public TestSupportingGC {
public:
- FakeContextNotifier* context() { return context_; }
+ MockContextLifecycleNotifier* context() { return context_; }
scoped_refptr<base::NullTaskRunner> task_runner() {
return null_task_runner_;
}
@@ -81,12 +55,12 @@ class HeapMojoUniqueReceiverSetBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
- context_ = MakeGarbageCollected<FakeContextNotifier>();
+ context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<GCOwner<Mode>>(context());
}
void TearDown() override {}
- Persistent<FakeContextNotifier> context_;
+ Persistent<MockContextLifecycleNotifier> context_;
Persistent<GCOwner<Mode>> owner_;
scoped_refptr<base::NullTaskRunner> null_task_runner_ =
base::MakeRefCounted<base::NullTaskRunner>();
diff --git a/chromium/third_party/blink/renderer/platform/mojo/mojo_binding_context.h b/chromium/third_party/blink/renderer/platform/mojo/mojo_binding_context.h
new file mode 100644
index 00000000000..164999454f4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/mojo/mojo_binding_context.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_MOJO_BINDING_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_MOJO_BINDING_CONTEXT_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace blink {
+
+class BrowserInterfaceBrokerProxy;
+
+// This class encapsulates the necessary information for binding Mojo
+// interfaces, to enable interfaces provided by the platform to be aware of the
+// context in which they are intended to be used.
+class PLATFORM_EXPORT MojoBindingContext : public ContextLifecycleNotifier {
+ public:
+ virtual const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker()
+ const = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
+ TaskType) = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MOJO_MOJO_BINDING_CONTEXT_H_
diff --git a/chromium/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h b/chromium/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
index b4a5af9bcb4..e354027625b 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
+++ b/chromium/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
@@ -56,8 +56,7 @@ struct StructTraits<url::mojom::OriginDataView,
}
static uint16_t port(
const scoped_refptr<const ::blink::SecurityOrigin>& origin) {
- return UrlOriginAdapter::GetOriginOrPrecursorOriginIfOpaque(origin)
- ->EffectivePort();
+ return UrlOriginAdapter::GetOriginOrPrecursorOriginIfOpaque(origin)->Port();
}
static base::Optional<base::UnguessableToken> nonce_if_opaque(
const scoped_refptr<const ::blink::SecurityOrigin>& origin) {
diff --git a/chromium/third_party/blink/renderer/platform/mojo/string16_mojom_traits_test.cc b/chromium/third_party/blink/renderer/platform/mojo/string16_mojom_traits_test.cc
index 9efcde17184..0848346070c 100644
--- a/chromium/third_party/blink/renderer/platform/mojo/string16_mojom_traits_test.cc
+++ b/chromium/third_party/blink/renderer/platform/mojo/string16_mojom_traits_test.cc
@@ -23,7 +23,7 @@ TEST(String16MojomTraitsTest, String16) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::String16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
// Replace the "o"s in "hello world" with "o"s with acute, so that |str| is
@@ -32,7 +32,7 @@ TEST(String16MojomTraitsTest, String16) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::String16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -42,7 +42,7 @@ TEST(String16MojomTraitsTest, EmptyString16) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::String16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -52,7 +52,7 @@ TEST(String16MojomTraitsTest, BigString16_Empty) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -63,7 +63,7 @@ TEST(String16MojomTraitsTest, BigString16_Short) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
// Replace the "o"s in "hello world" with "o"s with acute, so that |str| is
@@ -72,7 +72,7 @@ TEST(String16MojomTraitsTest, BigString16_Short) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
@@ -85,7 +85,7 @@ TEST(String16MojomTraitsTest, BigString16_Long) {
ASSERT_TRUE(
mojo::test::SerializeAndDeserialize<mojo_base::mojom::blink::BigString16>(
- &str, &output));
+ str, output));
ASSERT_EQ(str, output);
}
diff --git a/chromium/third_party/blink/renderer/platform/network/BUILD.gn b/chromium/third_party/blink/renderer/platform/network/BUILD.gn
index 3b500f12c6d..163d86a9bb9 100644
--- a/chromium/third_party/blink/renderer/platform/network/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/network/BUILD.gn
@@ -48,7 +48,6 @@ blink_platform_sources("network") {
"mime/mime_type_from_url.h",
"mime/mime_type_registry.cc",
"mime/mime_type_registry.h",
- "network_log.h",
"network_state_notifier.cc",
"network_state_notifier.h",
"network_utils.cc",
@@ -78,6 +77,7 @@ source_set("unit_tests") {
testonly = true
sources = [
+ "content_security_policy_parsers_test.cc",
"encoded_form_data_test.cc",
"http_parsers_test.cc",
"mime/mime_type_registry_test.cc",
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
index 212c2b97594..4148687dcaf 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.cc
@@ -7,6 +7,8 @@
#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
+#include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
+#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
@@ -16,7 +18,7 @@ bool IsCSPDirectiveNameCharacter(UChar c) {
}
bool IsCSPDirectiveValueCharacter(UChar c) {
- return IsASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR
+ return IsASCIISpace(c) || (IsASCIIPrintable(c) && c != ',' && c != ';');
}
// Only checks for general Base64(url) encoded chars, not '=' chars since '=' is
@@ -57,4 +59,51 @@ bool IsMediaTypeCharacter(UChar c) {
return !IsASCIISpace(c) && c != '/';
}
+bool MatchesTheSerializedCSPGrammar(const String& value) {
+ return WTF::VisitCharacters(value, [](const auto* chars, unsigned len) {
+ const auto* it = chars;
+ const auto* end = chars + len;
+
+ while (it < end) {
+ // Consume any whitespaces.
+ while (it < end && IsASCIISpace(*it))
+ it++;
+
+ // Consume a directive name.
+ bool directive_name_found = false;
+ while (it < end && IsCSPDirectiveNameCharacter(*it)) {
+ it++;
+ directive_name_found = true;
+ }
+
+ // Consume the directive value (if any), but only if there is a directive
+ // name followed by at least one whitespace.
+ if (directive_name_found) {
+ bool space_found = false;
+ while (it < end && IsASCIISpace(*it)) {
+ it++;
+ space_found = true;
+ }
+ if (space_found) {
+ while (it < end && IsCSPDirectiveValueCharacter(*it))
+ it++;
+ }
+ }
+
+ if (it == end)
+ return true;
+
+ // There should be at least one ';'.
+ bool semicolon_found = false;
+ while (it < end && *it == ';') {
+ it++;
+ semicolon_found = true;
+ }
+ if (!semicolon_found)
+ return false;
+ }
+ return true;
+ });
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.h b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
index 248f54f9bad..957b5579a88 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers.h
@@ -35,6 +35,12 @@ PLATFORM_EXPORT bool IsMediaTypeCharacter(UChar);
// positional and may only appear at the end of a Base64 encoded string.
PLATFORM_EXPORT bool IsBase64EncodedCharacter(UChar);
+// Check if value matches
+// https://w3c.github.io/webappsec-csp/#grammardef-serialized-policy. We also
+// allow a trailing ';', repeated ';'s, and a trailing ';' followed by spaces.
+PLATFORM_EXPORT
+bool MatchesTheSerializedCSPGrammar(const String& value);
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers_test.cc b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers_test.cc
new file mode 100644
index 00000000000..adbc99d9b9c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_parsers_test.cc
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(ContentSecurityPolicyParsers, MatchesTheSerializedCSPGrammar) {
+ struct {
+ String value;
+ bool expected;
+ } testCases[]{
+ {"script-src 'none'; invalid-directive ", true},
+ {"script-src 'none'; invalid-directive;", true},
+ {" script-src 'none' https://www.example.org ; ;invalid-directive; ;",
+ true},
+ {"script-src 'none', media-src 'none'", false},
+ {"script-src 'none'; /invalid-directive-name", false},
+ };
+
+ for (const auto& testCase : testCases) {
+ EXPECT_EQ(MatchesTheSerializedCSPGrammar(testCase.value),
+ testCase.expected);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
index bea1c2b60cf..e9b29f26372 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.cc
@@ -36,23 +36,17 @@ ContentSecurityPolicyResponseHeaders::ContentSecurityPolicyResponseHeaders(
const ResourceResponse& response)
: ContentSecurityPolicyResponseHeaders(
response.HttpHeaderFields(),
+ response.CurrentRequestUrl(),
SchemeRegistry::SchemeSupportsWasmEvalCSP(
response.CurrentRequestUrl().Protocol())) {}
ContentSecurityPolicyResponseHeaders::ContentSecurityPolicyResponseHeaders(
const HTTPHeaderMap& headers,
+ const KURL& response_url,
bool should_parse_wasm_eval)
: content_security_policy_(headers.Get(http_names::kContentSecurityPolicy)),
content_security_policy_report_only_(
headers.Get(http_names::kContentSecurityPolicyReportOnly)),
+ response_url_(response_url),
should_parse_wasm_eval_(should_parse_wasm_eval) {}
-
-ContentSecurityPolicyResponseHeaders
-ContentSecurityPolicyResponseHeaders::IsolatedCopy() const {
- ContentSecurityPolicyResponseHeaders headers;
- headers.content_security_policy_ = content_security_policy_.IsolatedCopy();
- headers.content_security_policy_report_only_ =
- content_security_policy_report_only_.IsolatedCopy();
- return headers;
-}
}
diff --git a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.h b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.h
index 71d4639b70c..0373a709999 100644
--- a/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.h
+++ b/chromium/third_party/blink/renderer/platform/network/content_security_policy_response_headers.h
@@ -27,6 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_CONTENT_SECURITY_POLICY_RESPONSE_HEADERS_H_
#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -44,6 +45,7 @@ class PLATFORM_EXPORT ContentSecurityPolicyResponseHeaders final {
explicit ContentSecurityPolicyResponseHeaders(const ResourceResponse&);
explicit ContentSecurityPolicyResponseHeaders(
const HTTPHeaderMap&,
+ const KURL& response_url,
bool should_parse_wasm_eval = false);
const String& ContentSecurityPolicy() const {
@@ -52,32 +54,18 @@ class PLATFORM_EXPORT ContentSecurityPolicyResponseHeaders final {
const String& ContentSecurityPolicyReportOnly() const {
return content_security_policy_report_only_;
}
-
- ContentSecurityPolicyResponseHeaders IsolatedCopy() const;
+ const KURL& ResponseUrl() const { return response_url_; }
bool ShouldParseWasmEval() const { return should_parse_wasm_eval_; }
private:
String content_security_policy_;
String content_security_policy_report_only_;
+ KURL response_url_;
const bool should_parse_wasm_eval_ = false;
};
} // namespace blink
-namespace WTF {
-
-template <>
-struct CrossThreadCopier<blink::ContentSecurityPolicyResponseHeaders> {
- STATIC_ONLY(CrossThreadCopier);
- using Type = blink::ContentSecurityPolicyResponseHeaders;
- PLATFORM_EXPORT static Type Copy(
- const blink::ContentSecurityPolicyResponseHeaders& headers) {
- return headers.IsolatedCopy();
- }
-};
-
-} // namespace WTF
-
#endif
diff --git a/chromium/third_party/blink/renderer/platform/network/http_names.json5 b/chromium/third_party/blink/renderer/platform/network/http_names.json5
index 345bf464553..087a389b0e9 100644
--- a/chromium/third_party/blink/renderer/platform/network/http_names.json5
+++ b/chromium/third_party/blink/renderer/platform/network/http_names.json5
@@ -62,7 +62,6 @@
"Require-Document-Policy",
"Save-Data",
"Sec-CH-Lang",
- "Sec-Required-CSP",
"Server-Timing",
"SourceMap",
"Timing-Allow-Origin",
diff --git a/chromium/third_party/blink/renderer/platform/network/http_parsers.cc b/chromium/third_party/blink/renderer/platform/network/http_parsers.cc
index 0f46524563e..da9f32b0b67 100644
--- a/chromium/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/chromium/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -66,8 +66,11 @@ blink::CSPSourcePtr ConvertToBlink(CSPSourcePtr source) {
}
blink::CSPHashSourcePtr ConvertToBlink(CSPHashSourcePtr hash) {
- return blink::CSPHashSource::New(hash->algorithm,
- String::FromUTF8(hash->value));
+ WTF::Vector<uint8_t> hash_value;
+ for (uint8_t el : hash->value)
+ hash_value.push_back(el);
+
+ return blink::CSPHashSource::New(hash->algorithm, hash_value);
}
blink::CSPSourceListPtr ConvertToBlink(CSPSourceListPtr source_list) {
@@ -114,6 +117,18 @@ WTF::HashMap<blink::CSPDirectiveName, blink::CSPSourceListPtr> ConvertToBlink(
return out;
}
+WTF::HashMap<blink::CSPDirectiveName, String> ConvertToBlink(
+ base::flat_map<CSPDirectiveName, std::string> directives) {
+ WTF::HashMap<blink::CSPDirectiveName, String> out;
+
+ for (auto& list : directives) {
+ out.insert(ConvertToBlink(list.first),
+ String::FromUTF8(std::move(list.second)));
+ }
+
+ return out;
+}
+
WTF::Vector<WTF::String> ConvertToBlink(std::vector<std::string> in) {
WTF::Vector<WTF::String> out;
for (auto& el : in)
@@ -121,18 +136,27 @@ WTF::Vector<WTF::String> ConvertToBlink(std::vector<std::string> in) {
return out;
}
+blink::CSPTrustedTypesPtr ConvertToBlink(CSPTrustedTypesPtr trusted_types) {
+ if (!trusted_types)
+ return nullptr;
+ return blink::CSPTrustedTypes::New(ConvertToBlink(trusted_types->list),
+ trusted_types->allow_any,
+ trusted_types->allow_duplicates);
+}
+
blink::ContentSecurityPolicyPtr ConvertToBlink(
ContentSecurityPolicyPtr policy_in) {
return blink::ContentSecurityPolicy::New(
+ ConvertToBlink(std::move(policy_in->self_origin)),
+ ConvertToBlink(std::move(policy_in->raw_directives)),
ConvertToBlink(std::move(policy_in->directives)),
policy_in->upgrade_insecure_requests, policy_in->treat_as_public_address,
- policy_in->sandbox, ConvertToBlink(std::move(policy_in->header)),
+ policy_in->block_all_mixed_content, policy_in->sandbox,
+ ConvertToBlink(std::move(policy_in->header)),
policy_in->use_reporting_api,
ConvertToBlink(std::move(policy_in->report_endpoints)),
- policy_in->plugin_types.has_value()
- ? base::Optional<WTF::Vector<WTF::String>>(
- ConvertToBlink(std::move(policy_in->plugin_types.value())))
- : base::nullopt,
+ policy_in->require_trusted_types_for,
+ ConvertToBlink(std::move(policy_in->trusted_types)),
ConvertToBlink(std::move(policy_in->parsing_errors)));
}
@@ -176,7 +200,7 @@ blink::ParsedHeadersPtr ConvertToBlink(ParsedHeadersPtr parsed_headers) {
ConvertToBlink(std::move(parsed_headers->allow_csp_from)),
std::move(parsed_headers->cross_origin_embedder_policy),
std::move(parsed_headers->cross_origin_opener_policy),
- parsed_headers->origin_isolation,
+ parsed_headers->origin_agent_cluster,
parsed_headers->accept_ch.has_value()
? base::make_optional(
ConvertToBlink(parsed_headers->accept_ch.value()))
@@ -185,7 +209,8 @@ blink::ParsedHeadersPtr ConvertToBlink(ParsedHeadersPtr parsed_headers) {
parsed_headers->critical_ch.has_value()
? base::make_optional(
ConvertToBlink(parsed_headers->critical_ch.value()))
- : base::nullopt);
+ : base::nullopt,
+ parsed_headers->xfo);
}
} // namespace mojom
diff --git a/chromium/third_party/blink/renderer/platform/network/network_log.h b/chromium/third_party/blink/renderer/platform/network/network_log.h
deleted file mode 100644
index 1c0399991fd..00000000000
--- a/chromium/third_party/blink/renderer/platform/network/network_log.h
+++ /dev/null
@@ -1,20 +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_PLATFORM_NETWORK_NETWORK_LOG_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_NETWORK_LOG_H_
-
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-
-#if DCHECK_IS_ON()
-// We can see logs with |--v=N| or |--vmodule=NetworkLog=N| where N is a
-// verbose level.
-#define NETWORK_DVLOG(verbose_level) \
- LAZY_STREAM(VLOG_STREAM(verbose_level), \
- ((verbose_level) <= ::logging::GetVlogLevel("NetworkLog.h")))
-#else
-#define NETWORK_DVLOG(verbose_level) EAT_STREAM_PARAMETERS
-#endif
-
-#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_NETWORK_LOG_H_
diff --git a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
index 32328e88187..86171e23af8 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
+++ b/chromium/third_party/blink/renderer/platform/network/network_state_notifier.cc
@@ -30,6 +30,7 @@
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator_params.h"
#include "third_party/blink/public/common/client_hints/client_hints.h"
+#include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-blink.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -41,6 +42,8 @@
namespace blink {
+using mojom::blink::EffectiveConnectionType;
+
namespace {
// Typical HTTP RTT value corresponding to a given WebEffectiveConnectionType
@@ -224,14 +227,19 @@ void NetworkStateNotifier::SetNetworkConnectionInfoOverride(
base::TimeDelta::FromMilliseconds(http_rtt_msec));
// Threshold values taken from
// net/nqe/network_quality_estimator_params.cc.
- if (http_rtt >= net::kHttpRttEffectiveConnectionTypeThresholds
- [net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G]) {
+ if (http_rtt >=
+ net::kHttpRttEffectiveConnectionTypeThresholds[static_cast<int>(
+ EffectiveConnectionType::kEffectiveConnectionSlow2GType)]) {
effective_type = WebEffectiveConnectionType::kTypeSlow2G;
- } else if (http_rtt >= net::kHttpRttEffectiveConnectionTypeThresholds
- [net::EFFECTIVE_CONNECTION_TYPE_2G]) {
+ } else if (http_rtt >=
+ net::kHttpRttEffectiveConnectionTypeThresholds[static_cast<
+ int>(
+ EffectiveConnectionType::kEffectiveConnection2GType)]) {
effective_type = WebEffectiveConnectionType::kType2G;
- } else if (http_rtt >= net::kHttpRttEffectiveConnectionTypeThresholds
- [net::EFFECTIVE_CONNECTION_TYPE_3G]) {
+ } else if (http_rtt >=
+ net::kHttpRttEffectiveConnectionTypeThresholds[static_cast<
+ int>(
+ EffectiveConnectionType::kEffectiveConnection3GType)]) {
effective_type = WebEffectiveConnectionType::kType3G;
} else {
effective_type = WebEffectiveConnectionType::kType4G;
@@ -395,8 +403,14 @@ void NetworkStateNotifier::CollectZeroedObservers(
// If any observers were removed during the iteration they will have
// 0 values, clean them up.
- for (wtf_size_t i = 0; i < list->zeroed_observers.size(); ++i)
- list->observers.EraseAt(list->zeroed_observers[i]);
+ std::sort(list->zeroed_observers.begin(), list->zeroed_observers.end());
+ int removed = 0;
+ for (wtf_size_t i = 0; i < list->zeroed_observers.size(); ++i) {
+ int index_to_remove = list->zeroed_observers[i] - removed;
+ DCHECK_EQ(nullptr, list->observers[index_to_remove]);
+ list->observers.EraseAt(index_to_remove);
+ removed += 1;
+ }
list->zeroed_observers.clear();
diff --git a/chromium/third_party/blink/renderer/platform/network/network_state_notifier_test.cc b/chromium/third_party/blink/renderer/platform/network/network_state_notifier_test.cc
index eb2bd791529..f7c359235a8 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_state_notifier_test.cc
+++ b/chromium/third_party/blink/renderer/platform/network/network_state_notifier_test.cc
@@ -528,6 +528,53 @@ TEST_F(NetworkStateNotifierTest, RemoveFutureObserverWhileNotifying) {
kUnknownThroughputMbps, SaveData::kOff));
}
+// It should be safe to remove multiple observers in one iteration.
+TEST_F(NetworkStateNotifierTest, RemoveMultipleObserversWhileNotifying) {
+ StateObserver observer1, observer2, observer3;
+ std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle> handle1 =
+ notifier_.AddConnectionObserver(&observer1, GetTaskRunner());
+ std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle> handle2 =
+ notifier_.AddConnectionObserver(&observer2, GetTaskRunner());
+ std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle> handle3 =
+ notifier_.AddConnectionObserver(&observer3, GetTaskRunner());
+ observer1.RemoveObserverOnNotification(std::move(handle1));
+ observer3.RemoveObserverOnNotification(std::move(handle3));
+
+ // Running the first time should delete observers 1 and 3.
+ SetConnection(kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
+ kUnknownRtt, kUnknownThroughputMbps, SaveData::kOff);
+ EXPECT_TRUE(VerifyObservations(
+ observer1, kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+ EXPECT_TRUE(VerifyObservations(
+ observer2, kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+ EXPECT_TRUE(VerifyObservations(
+ observer3, kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+
+ // Run again and only observer 2 should have been updated.
+ SetConnection(kWebConnectionTypeEthernet, kEthernetMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
+ kUnknownRtt, kUnknownThroughputMbps, SaveData::kOff);
+ EXPECT_TRUE(VerifyObservations(
+ observer1, kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+ EXPECT_TRUE(VerifyObservations(
+ observer2, kWebConnectionTypeEthernet, kEthernetMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+ EXPECT_TRUE(VerifyObservations(
+ observer3, kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
+ WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
+ kUnknownThroughputMbps, SaveData::kOff));
+}
+
TEST_F(NetworkStateNotifierTest, MultipleContextsAddObserver) {
StateObserver observer1, observer2;
std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle> handle1 =
diff --git a/chromium/third_party/blink/renderer/platform/network/network_utils.cc b/chromium/third_party/blink/renderer/platform/network/network_utils.cc
index 7cd2d356989..81745b38d39 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/network/network_utils.cc
@@ -52,11 +52,6 @@ bool IsReservedIPAddress(const String& host) {
return !address.IsPubliclyRoutable();
}
-bool IsLocalHostname(const String& host, bool* is_local6) {
- StringUTF8Adaptor utf8(host);
- return net::IsLocalHostname(utf8.AsStringPiece(), is_local6);
-}
-
String GetDomainAndRegistry(const String& host, PrivateRegistryFilter filter) {
StringUTF8Adaptor host_utf8(host);
std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
diff --git a/chromium/third_party/blink/renderer/platform/network/network_utils.h b/chromium/third_party/blink/renderer/platform/network/network_utils.h
index 23220caec85..236796a618f 100644
--- a/chromium/third_party/blink/renderer/platform/network/network_utils.h
+++ b/chromium/third_party/blink/renderer/platform/network/network_utils.h
@@ -25,8 +25,6 @@ enum PrivateRegistryFilter {
PLATFORM_EXPORT bool IsReservedIPAddress(const String& host);
-PLATFORM_EXPORT bool IsLocalHostname(const String& host, bool* is_local6);
-
PLATFORM_EXPORT String GetDomainAndRegistry(const String& host,
PrivateRegistryFilter);
diff --git a/chromium/third_party/blink/renderer/platform/p2p/DIR_METADATA b/chromium/third_party/blink/renderer/platform/p2p/DIR_METADATA
new file mode 100644
index 00000000000..7fdbb5e4bdd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/p2p/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebRTC"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/p2p/OWNERS b/chromium/third_party/blink/renderer/platform/p2p/OWNERS
index eabc2b276ea..f73d253f31a 100644
--- a/chromium/third_party/blink/renderer/platform/p2p/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/p2p/OWNERS
@@ -1,5 +1,3 @@
guidou@chromium.org
sergeyu@chromium.org
steveanton@chromium.org
-
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc b/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
index 29884a255f2..72ec477f578 100644
--- a/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
@@ -36,7 +36,7 @@ void P2PSocketDispatcher::RemoveNetworkListObserver(
network_list_observers_->RemoveObserver(network_list_observer);
}
-network::mojom::blink::P2PSocketManager*
+mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
P2PSocketDispatcher::GetP2PSocketManager() {
base::AutoLock lock(p2p_socket_manager_lock_);
if (!p2p_socket_manager_) {
@@ -56,7 +56,7 @@ P2PSocketDispatcher::GetP2PSocketManager() {
*main_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&P2PSocketDispatcher::RequestInterfaceIfNecessary,
scoped_refptr<P2PSocketDispatcher>(this)));
- return p2p_socket_manager_.get();
+ return p2p_socket_manager_;
}
void P2PSocketDispatcher::NetworkListChanged(
diff --git a/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.h b/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
index b6268562b1b..7d75ef814e1 100644
--- a/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
+++ b/chromium/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
@@ -65,7 +65,8 @@ class PLATFORM_EXPORT P2PSocketDispatcher
void RemoveNetworkListObserver(
blink::NetworkListObserver* network_list_observer) override;
- network::mojom::blink::P2PSocketManager* GetP2PSocketManager();
+ mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
+ GetP2PSocketManager();
private:
friend class base::RefCountedThreadSafe<P2PSocketDispatcher>;
@@ -94,7 +95,7 @@ class PLATFORM_EXPORT P2PSocketDispatcher
mojo::PendingReceiver<network::mojom::blink::P2PSocketManager>
p2p_socket_manager_receiver_;
mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
- p2p_socket_manager_;
+ p2p_socket_manager_ GUARDED_BY(p2p_socket_manager_lock_);
base::Lock p2p_socket_manager_lock_;
// Cached from last |NetworkListChanged| call.
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/DEPS b/chromium/third_party/blink/renderer/platform/peerconnection/DEPS
index 3328b8a2a0e..a4dc7f34b1f 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/DEPS
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/DEPS
@@ -10,17 +10,20 @@ include_rules = [
"+third_party/blink/renderer/platform/webrtc",
# Dependencies.
+ "+base/containers/circular_deque.h",
"+base/strings/string_number_conversions.h",
"+base/strings/string_split.h",
"+base/task/task_traits.h",
"+base/threading/thread_restrictions.h",
"+media/base",
"+media/capture/capture_switches.h",
+ "+media/filters/decoder_stream.h",
"+media/media_buildflags.h",
+ # This is only needed for a cast to DecoderFactory.
+ "+media/renderers/default_decoder_factory.h",
"+media/video/gpu_video_accelerator_factories.h",
"+media/video/video_decode_accelerator.h",
"+media/video/h264_parser.h",
- "+media/video/supported_video_decoder_config.h",
"+media/video/video_encode_accelerator.h",
"+third_party/blink/renderer/platform/bindings/script_wrappable.h",
"+third_party/blink/renderer/platform/heap",
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/DIR_METADATA b/chromium/third_party/blink/renderer/platform/peerconnection/DIR_METADATA
new file mode 100644
index 00000000000..7fdbb5e4bdd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebRTC"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/OWNERS b/chromium/third_party/blink/renderer/platform/peerconnection/OWNERS
index b30d5fd6d29..5e71c359a85 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/OWNERS
@@ -1,5 +1,3 @@
file://third_party/blink/renderer/modules/peerconnection/OWNERS
per-file rtc_video_*=file://media/gpu/OWNERS
-
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink_proxy.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink_proxy.cc
index 095479bf02b..8a586afa9fb 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink_proxy.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink_proxy.cc
@@ -6,6 +6,7 @@
#include "base/check.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_event_log_output_sink.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source_test.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source_test.cc
new file mode 100644
index 00000000000..fec33b6b634
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source_test.cc
@@ -0,0 +1,42 @@
+#include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/api/transport/rtp/rtp_source.h"
+#include "third_party/webrtc/rtc_base/time_utils.h"
+
+namespace blink {
+
+TEST(RtcRtpSource, BasicPropertiesAreSetAndReturned) {
+ int64_t kTimestampMs = 12345678;
+ uint32_t kSourceId = 5;
+ webrtc::RtpSourceType kSourceType = webrtc::RtpSourceType::SSRC;
+ uint32_t kRtpTimestamp = 112233;
+ webrtc::RtpSource rtp_source(kTimestampMs, kSourceId, kSourceType,
+ kRtpTimestamp, webrtc::RtpSource::Extensions());
+
+ RTCRtpSource rtc_rtp_source(rtp_source);
+
+ EXPECT_EQ((rtc_rtp_source.Timestamp() - base::TimeTicks()).InMilliseconds(),
+ kTimestampMs);
+ EXPECT_EQ(rtc_rtp_source.Source(), kSourceId);
+ EXPECT_EQ(rtc_rtp_source.SourceType(), RTCRtpSource::Type::kSSRC);
+ EXPECT_EQ(rtc_rtp_source.RtpTimestamp(), kRtpTimestamp);
+}
+
+// The Timestamp() function relies on the fact that Base::TimeTicks() and
+// rtc::TimeMicros() share the same implementation.
+TEST(RtcRtpSource, BaseTimeTicksAndRtcMicrosAreTheSame) {
+ base::TimeTicks first_chromium_timestamp = base::TimeTicks::Now();
+ base::TimeTicks webrtc_timestamp =
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(rtc::TimeMicros());
+ base::TimeTicks second_chromium_timestamp = base::TimeTicks::Now();
+
+ // Test that the timestamps are correctly ordered, which they can only be if
+ // the clocks are the same (assuming at least one of the clocks is functioning
+ // correctly).
+ EXPECT_GE((webrtc_timestamp - first_chromium_timestamp).InMillisecondsF(),
+ 0.0f);
+ EXPECT_GE((second_chromium_timestamp - webrtc_timestamp).InMillisecondsF(),
+ 0.0f);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h
index eba22db96a8..c11e06db152 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h
@@ -71,6 +71,30 @@ class PLATFORM_EXPORT RTCRtpTransceiverPlatform {
Vector<webrtc::RtpCodecCapability>) {
return {};
}
+ virtual webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) = 0;
+ virtual Vector<webrtc::RtpHeaderExtensionCapability>
+ HeaderExtensionsNegotiated() const = 0;
+ virtual Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const = 0;
+};
+
+// This class contains dummy implementations for functions that are not
+// supported in Plan B mode.
+class RTCRtpPlanBTransceiverPlatform : public RTCRtpTransceiverPlatform {
+ public:
+ webrtc::RTCError SetOfferedRtpHeaderExtensions(
+ Vector<webrtc::RtpHeaderExtensionCapability> header_extensions) override {
+ return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
+ }
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
+ const override {
+ return {};
+ }
+ Vector<webrtc::RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
+ const override {
+ return {};
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h
index cac5d13028c..1a2e67b4ff4 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h
@@ -17,10 +17,10 @@ class PLATFORM_EXPORT RTCSessionDescriptionPlatform final
public:
RTCSessionDescriptionPlatform(const String& type, const String& sdp);
- String GetType() { return type_; }
+ String GetType() const { return type_; }
void SetType(const String& type) { type_ = type; }
- String Sdp() { return sdp_; }
+ String Sdp() const { return sdp_; }
void SetSdp(const String& sdp) { sdp_ = sdp; }
void Trace(Visitor* visitor) const {}
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
index 36354051826..93deb4da446 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
@@ -16,7 +17,6 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
-#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
@@ -37,7 +37,6 @@
#include "third_party/webrtc/api/video/video_frame.h"
#include "third_party/webrtc/media/base/vp9_profile.h"
#include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h"
-#include "third_party/webrtc/rtc_base/bind.h"
#include "third_party/webrtc/rtc_base/ref_count.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
#include "ui/gfx/color_space.h"
@@ -71,20 +70,6 @@ const int32_t kMaxDecodeHistory = 32;
// requesting fallback to software decode.
const int32_t kMaxConsecutiveErrors = 5;
-// Map webrtc::VideoCodecType to media::VideoCodec.
-media::VideoCodec ToVideoCodec(webrtc::VideoCodecType video_codec_type) {
- switch (video_codec_type) {
- case webrtc::kVideoCodecVP8:
- return media::kCodecVP8;
- case webrtc::kVideoCodecVP9:
- return media::kCodecVP9;
- case webrtc::kVideoCodecH264:
- return media::kCodecH264;
- default:
- return media::kUnknownVideoCodec;
- }
-}
-
// Map webrtc::SdpVideoFormat to a guess for media::VideoCodecProfile.
media::VideoCodecProfile GuessVideoCodecProfile(
const webrtc::SdpVideoFormat& format) {
@@ -198,13 +183,13 @@ std::unique_ptr<RTCVideoDecoderAdapter> RTCVideoDecoderAdapter::Create(
return nullptr;
// Bail early for unknown codecs.
- if (ToVideoCodec(video_codec_type) == media::kUnknownVideoCodec)
+ if (WebRtcToMediaVideoCodec(video_codec_type) == media::kUnknownVideoCodec)
return nullptr;
// Avoid the thread hop if the decoder is known not to support the config.
// TODO(sandersd): Predict size from level.
media::VideoDecoderConfig config(
- ToVideoCodec(webrtc::PayloadStringToCodecType(format.name)),
+ WebRtcToMediaVideoCodec(webrtc::PayloadStringToCodecType(format.name)),
GuessVideoCodecProfile(format),
media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
media::kNoTransformation, kDefaultSize, gfx::Rect(kDefaultSize),
@@ -311,7 +296,7 @@ int32_t RTCVideoDecoderAdapter::Decode(const webrtc::EncodedImage& input_image,
// to software decoding. See https://crbug.com/webrtc/9304.
if (video_codec_type_ == webrtc::kVideoCodecVP9 &&
input_image.SpatialIndex().value_or(0) > 0) {
-#if defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_ASH)
+#if defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS_ASH)
if (!base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding)) {
RecordFallbackReason(config_.codec(), FallbackReason::kSpatialLayers);
return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
@@ -319,7 +304,7 @@ int32_t RTCVideoDecoderAdapter::Decode(const webrtc::EncodedImage& input_image,
#else
RecordFallbackReason(config_.codec(), FallbackReason::kSpatialLayers);
return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
-#endif // defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_ASH)
+#endif // defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS_ASH)
}
if (missing_frames) {
@@ -440,8 +425,12 @@ int32_t RTCVideoDecoderAdapter::Release() {
: WEBRTC_VIDEO_CODEC_OK;
}
-const char* RTCVideoDecoderAdapter::ImplementationName() const {
- return "ExternalDecoder";
+webrtc::VideoDecoder::DecoderInfo RTCVideoDecoderAdapter::GetDecoderInfo()
+ const {
+ DecoderInfo info;
+ info.implementation_name = "ExternalDecoder";
+ info.is_hardware_accelerated = true;
+ return info;
}
void RTCVideoDecoderAdapter::InitializeOnMediaThread(
@@ -627,7 +616,7 @@ void RTCVideoDecoderAdapter::FlushOnMediaThread(FlushDoneCB flush_success_cb,
// Send EOS frame for flush.
video_decoder_->Decode(
media::DecoderBuffer::CreateEOSBuffer(),
- WTF::BindRepeating(
+ WTF::Bind(
[](FlushDoneCB flush_success, FlushDoneCB flush_fail,
media::Status status) {
if (status.is_ok())
@@ -635,7 +624,7 @@ void RTCVideoDecoderAdapter::FlushOnMediaThread(FlushDoneCB flush_success_cb,
else
std::move(flush_fail).Run();
},
- base::Passed(&flush_success_cb), base::Passed(&flush_fail_cb)));
+ std::move(flush_success_cb), std::move(flush_fail_cb)));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
index f6738cb9b23..19fe3c03e96 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
@@ -16,10 +16,10 @@
#include "base/synchronization/lock.h"
#include "media/base/decode_status.h"
#include "media/base/status.h"
+#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
-#include "media/video/supported_video_decoder_config.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -83,7 +83,7 @@ class PLATFORM_EXPORT RTCVideoDecoderAdapter : public webrtc::VideoDecoder {
// Called on the worker thread and on the DecodingThread.
int32_t Release() override;
// Called on the worker thread and on the DecodingThread.
- const char* ImplementationName() const override;
+ DecoderInfo GetDecoderInfo() const override;
private:
using CreateVideoDecoderCB =
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc
index bcdf93b8685..68a51811a63 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc
@@ -50,6 +50,9 @@ namespace {
class MockVideoDecoder : public media::VideoDecoder {
public:
std::string GetDisplayName() const override { return "MockVideoDecoder"; }
+ media::VideoDecoderType GetDecoderType() const override {
+ return media::VideoDecoderType::kUnknown;
+ }
void Initialize(const media::VideoDecoderConfig& config,
bool low_delay,
media::CdmContext* cdm_context,
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
index 3c780f267bf..9cf41f4ea7a 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
@@ -7,14 +7,17 @@
#include <array>
#include <memory>
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "build/build_config.h"
+#include "media/base/decoder_factory.h"
#include "media/base/media_util.h"
#include "media/base/video_codecs.h"
#include "media/video/gpu_video_accelerator_factories.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h"
#include "third_party/webrtc/media/base/h264_profile_level_id.h"
#include "third_party/webrtc/media/base/media_constants.h"
#include "third_party/webrtc/media/base/vp9_profile.h"
@@ -33,7 +36,7 @@ struct CodecConfig {
media::VideoCodecProfile profile;
};
-constexpr std::array<CodecConfig, 7> kCodecConfigs = {{
+constexpr std::array<CodecConfig, 8> kCodecConfigs = {{
{media::kCodecVP8, media::VP8PROFILE_ANY},
{media::kCodecVP9, media::VP9PROFILE_PROFILE0},
{media::kCodecVP9, media::VP9PROFILE_PROFILE1},
@@ -41,6 +44,7 @@ constexpr std::array<CodecConfig, 7> kCodecConfigs = {{
{media::kCodecH264, media::H264PROFILE_BASELINE},
{media::kCodecH264, media::H264PROFILE_MAIN},
{media::kCodecH264, media::H264PROFILE_HIGH},
+ {media::kCodecAV1, media::AV1PROFILE_PROFILE_MAIN},
}};
// Translate from media::VideoDecoderConfig to webrtc::SdpVideoFormat, or return
@@ -154,11 +158,9 @@ class ScopedVideoDecoder : public webrtc::VideoDecoder {
int64_t render_time_ms) override {
return decoder_->Decode(input_image, missing_frames, render_time_ms);
}
- bool PrefersLateDecoding() const override {
- return decoder_->PrefersLateDecoding();
- }
- const char* ImplementationName() const override {
- return decoder_->ImplementationName();
+
+ DecoderInfo GetDecoderInfo() const override {
+ return decoder_->GetDecoderInfo();
}
// Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
@@ -175,8 +177,11 @@ class ScopedVideoDecoder : public webrtc::VideoDecoder {
} // namespace
RTCVideoDecoderFactory::RTCVideoDecoderFactory(
- media::GpuVideoAcceleratorFactories* gpu_factories)
- : gpu_factories_(gpu_factories), gpu_codec_support_waiter_(gpu_factories) {
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory)
+ : gpu_factories_(gpu_factories),
+ decoder_factory_(decoder_factory),
+ gpu_codec_support_waiter_(gpu_factories) {
DVLOG(2) << __func__;
}
@@ -194,6 +199,12 @@ std::vector<webrtc::SdpVideoFormat>
RTCVideoDecoderFactory::GetSupportedFormats() const {
CheckAndWaitDecoderSupportStatusIfNeeded();
+ media::SupportedVideoDecoderConfigs supported_decoder_factory_configs =
+ decoder_factory_->GetSupportedVideoDecoderConfigsForWebRTC();
+
+ // For now, ignore `kUseDecoderStreamForWebRTC`, and advertise support only
+ // for hardware-accelerated formats. For some codecs, like AV1, which don't
+ // have an equivalent in rtc, we might want to include them anyway.
std::vector<webrtc::SdpVideoFormat> supported_formats;
for (auto& codec_config : kCodecConfigs) {
media::VideoDecoderConfig config(
@@ -202,18 +213,29 @@ RTCVideoDecoderFactory::GetSupportedFormats() const {
media::VideoColorSpace(), media::kNoTransformation, kDefaultSize,
gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
media::EncryptionScheme::kUnencrypted);
+ base::Optional<webrtc::SdpVideoFormat> format;
for (auto impl : RTCVideoDecoderAdapter::SupportedImplementations()) {
if (gpu_factories_->IsDecoderConfigSupported(impl, config) ==
media::GpuVideoAcceleratorFactories::Supported::kTrue) {
- base::Optional<webrtc::SdpVideoFormat> format =
- VdcToWebRtcFormat(config);
- if (format) {
- supported_formats.push_back(*format);
- }
+ format = VdcToWebRtcFormat(config);
break;
}
}
+
+ if (base::FeatureList::IsEnabled(media::kUseDecoderStreamForWebRTC) &&
+ !format.has_value()) {
+ for (auto& supported_config : supported_decoder_factory_configs) {
+ if (supported_config.Matches(config)) {
+ format = VdcToWebRtcFormat(config);
+ break;
+ }
+ }
+ }
+
+ if (format)
+ supported_formats.push_back(*format);
}
+
MapBaselineProfile(&supported_formats);
return supported_formats;
}
@@ -228,8 +250,13 @@ RTCVideoDecoderFactory::CreateVideoDecoder(
DVLOG(2) << __func__;
CheckAndWaitDecoderSupportStatusIfNeeded();
- std::unique_ptr<webrtc::VideoDecoder> decoder =
- RTCVideoDecoderAdapter::Create(gpu_factories_, format);
+ std::unique_ptr<webrtc::VideoDecoder> decoder;
+ if (base::FeatureList::IsEnabled(media::kUseDecoderStreamForWebRTC)) {
+ decoder = RTCVideoDecoderStreamAdapter::Create(gpu_factories_,
+ decoder_factory_, format);
+ } else {
+ decoder = RTCVideoDecoderAdapter::Create(gpu_factories_, format);
+ }
// ScopedVideoDecoder uses the task runner to make sure the decoder is
// destructed on the correct thread.
return decoder ? std::make_unique<ScopedVideoDecoder>(
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
index 09cf9bbe33d..6e0c4eb4767 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h
@@ -15,6 +15,7 @@ class VideoDecoder;
} // namespace webrtc
namespace media {
+class DecoderFactory;
class GpuVideoAcceleratorFactories;
} // namespace media
@@ -24,7 +25,8 @@ namespace blink {
class RTCVideoDecoderFactory : public webrtc::VideoDecoderFactory {
public:
explicit RTCVideoDecoderFactory(
- media::GpuVideoAcceleratorFactories* gpu_factories);
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory);
~RTCVideoDecoderFactory() override;
// Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
@@ -38,6 +40,7 @@ class RTCVideoDecoderFactory : public webrtc::VideoDecoderFactory {
void CheckAndWaitDecoderSupportStatusIfNeeded() const;
media::GpuVideoAcceleratorFactories* gpu_factories_;
+ media::DecoderFactory* decoder_factory_;
GpuCodecSupportWaiter gpu_codec_support_waiter_;
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
new file mode 100644
index 00000000000..7881d263db9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -0,0 +1,805 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h"
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "base/containers/circular_deque.h"
+#include "base/feature_list.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/sequenced_task_runner.h"
+#include "base/stl_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "media/base/media_log.h"
+#include "media/base/media_switches.h"
+#include "media/base/media_util.h"
+#include "media/base/overlay_info.h"
+#include "media/base/video_types.h"
+#include "media/renderers/default_decoder_factory.h"
+#include "media/video/gpu_video_accelerator_factories.h"
+#include "media/video/video_decode_accelerator.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/webrtc/api/video/video_frame.h"
+#include "third_party/webrtc/media/base/vp9_profile.h"
+#include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h"
+#include "third_party/webrtc/rtc_base/ref_count.h"
+#include "third_party/webrtc/rtc_base/ref_counted_object.h"
+#include "ui/gfx/color_space.h"
+
+namespace WTF {
+
+template <>
+struct CrossThreadCopier<media::VideoDecoderConfig>
+ : public CrossThreadCopierPassThrough<media::VideoDecoderConfig> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
+} // namespace WTF
+
+namespace blink {
+
+namespace {
+
+// Any reasonable size, will be overridden by the decoder anyway.
+constexpr gfx::Size kDefaultSize(640, 480);
+
+// Maximum number of buffers that we will queue in the decoder stream during
+// normal operation. It includes all buffers that we have not gotten an output
+// for. "Normal operation" means that we believe that the decoder is trying to
+// drain the queue. During init and reset, for example, we don't expect it.
+constexpr int32_t kMaxPendingBuffers = 8;
+
+// Absolute maximum number of pending buffers, whether we think the decoder is
+// draining them or not. If, at any time, we believe that there are this many
+// decodes in-flight when a new decode request arrives, we will fall back to
+// software decoding. It indicates that (a) reset never completed, (b) init
+// never completed, or (c) we're hopelessly behind.
+constexpr int32_t kAbsoluteMaxPendingBuffers = 32;
+
+// Map webrtc::VideoCodecType to media::VideoCodec.
+media::VideoCodec ToVideoCodec(webrtc::VideoCodecType video_codec_type) {
+ switch (video_codec_type) {
+ case webrtc::kVideoCodecVP8:
+ return media::kCodecVP8;
+ case webrtc::kVideoCodecVP9:
+ return media::kCodecVP9;
+ case webrtc::kVideoCodecH264:
+ return media::kCodecH264;
+ default:
+ return media::kUnknownVideoCodec;
+ }
+}
+
+// Map webrtc::SdpVideoFormat to a guess for media::VideoCodecProfile.
+media::VideoCodecProfile GuessVideoCodecProfile(
+ const webrtc::SdpVideoFormat& format) {
+ const webrtc::VideoCodecType video_codec_type =
+ webrtc::PayloadStringToCodecType(format.name);
+ switch (video_codec_type) {
+ case webrtc::kVideoCodecVP8:
+ return media::VP8PROFILE_ANY;
+ case webrtc::kVideoCodecVP9: {
+ const webrtc::VP9Profile vp9_profile =
+ webrtc::ParseSdpForVP9Profile(format.parameters)
+ .value_or(webrtc::VP9Profile::kProfile0);
+ switch (vp9_profile) {
+ case webrtc::VP9Profile::kProfile2:
+ return media::VP9PROFILE_PROFILE2;
+ case webrtc::VP9Profile::kProfile1:
+ return media::VP9PROFILE_PROFILE1;
+ case webrtc::VP9Profile::kProfile0:
+ default:
+ return media::VP9PROFILE_PROFILE0;
+ }
+ return media::VP9PROFILE_PROFILE0;
+ }
+ case webrtc::kVideoCodecH264:
+ return media::H264PROFILE_BASELINE;
+ default:
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+ }
+}
+
+void RecordInitializationLatency(base::TimeDelta latency) {
+ base::UmaHistogramTimes("Media.RTCVideoDecoderInitializationLatencyMs",
+ latency);
+}
+
+} // namespace
+
+// DemuxerStream implementation that forwards DecoderBuffer from some other
+// source (i.e., VideoDecoder::Decode).
+class RTCVideoDecoderStreamAdapter::InternalDemuxerStream
+ : public media::DemuxerStream {
+ public:
+ explicit InternalDemuxerStream(const media::VideoDecoderConfig& config)
+ : config_(config) {}
+
+ ~InternalDemuxerStream() override = default;
+
+ // DemuxerStream
+ void Read(ReadCB read_cb) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!pending_read_);
+ pending_read_ = std::move(read_cb);
+ MaybeSatisfyPendingRead();
+ }
+
+ media::AudioDecoderConfig audio_decoder_config() override {
+ NOTREACHED();
+ return media::AudioDecoderConfig();
+ }
+
+ media::VideoDecoderConfig video_decoder_config() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return config_;
+ }
+
+ Type type() const override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return DemuxerStream::VIDEO;
+ }
+
+ Liveness liveness() const override {
+ // Select low-delay mode.
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return Liveness::LIVENESS_LIVE;
+ }
+
+ void EnableBitstreamConverter() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ }
+
+ bool SupportsConfigChanges() override {
+ // The decoder can signal a config change to us, and we'll relay it to the
+ // DecoderStream that's reading from us.
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return true;
+ }
+
+ // We've been given a new DecoderBuffer for the DecoderStream to consume.
+ // Queue it, and maybe send it along immediately if there's a read pending.
+ void EnqueueBuffer(std::unique_ptr<PendingBuffer> pending_buffer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ buffers_.emplace_back(std::move(pending_buffer));
+ MaybeSatisfyPendingRead();
+ }
+
+ // Start a reset -- drop all buffers and abort any pending read request.
+ void Reset() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ buffers_.clear();
+ if (pending_read_)
+ std::move(pending_read_).Run(DemuxerStream::Status::kAborted, nullptr);
+ }
+
+ private:
+ // Send more DecoderBuffers to the reader, if we can.
+ void MaybeSatisfyPendingRead() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // If there aren't any queued decoder buffers, then nothing to do.
+ if (buffers_.empty())
+ return;
+
+ // If the decoder stream isn't trying to read, then also nothing to do.
+ if (!pending_read_)
+ return;
+
+ // See if this buffer should cause a config change. If so, send the config
+ // change first, and keep the buffer for the next call.
+ if (buffers_.front()->new_config) {
+ config_ = std::move(*(buffers_.front()->new_config));
+ std::move(pending_read_)
+ .Run(DemuxerStream::Status::kConfigChanged, nullptr);
+ return;
+ }
+
+ auto pending_buffer = std::move(buffers_.front());
+ buffers_.pop_front();
+
+ std::move(pending_read_)
+ .Run(DemuxerStream::Status::kOk, std::move(pending_buffer->buffer));
+ }
+
+ media::VideoDecoderConfig config_;
+
+ // Buffers that have been sent to us, but we haven't forwarded yet.
+ // These are only ptrs because CrossThread* binding seems to work that way.
+ base::circular_deque<std::unique_ptr<PendingBuffer>> buffers_;
+
+ // Read request from the stream that we haven't been able to fulfill, if any.
+ ReadCB pending_read_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+// static
+std::unique_ptr<RTCVideoDecoderStreamAdapter>
+RTCVideoDecoderStreamAdapter::Create(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory,
+ const webrtc::SdpVideoFormat& format) {
+ DVLOG(1) << __func__ << "(" << format.name << ")";
+
+ const webrtc::VideoCodecType video_codec_type =
+ webrtc::PayloadStringToCodecType(format.name);
+
+ if (!Platform::Current()->IsWebRtcHWH264DecodingEnabled(video_codec_type))
+ return nullptr;
+
+ // Bail early for unknown codecs.
+ if (ToVideoCodec(video_codec_type) == media::kUnknownVideoCodec)
+ return nullptr;
+
+ // Avoid the thread hop if the decoder is known not to support the config.
+ // TODO(sandersd): Predict size from level.
+ media::VideoDecoderConfig config(
+ ToVideoCodec(webrtc::PayloadStringToCodecType(format.name)),
+ GuessVideoCodecProfile(format),
+ media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
+ media::kNoTransformation, kDefaultSize, gfx::Rect(kDefaultSize),
+ kDefaultSize, media::EmptyExtraData(),
+ media::EncryptionScheme::kUnencrypted);
+
+ config.set_is_rtc(true);
+
+ // InitializeSync doesn't really initialize anything; it just posts the work
+ // to the media thread. If init fails, then we'll fall back on the first
+ // decode after we notice.
+ auto rtc_video_decoder_adapter =
+ base::WrapUnique(new RTCVideoDecoderStreamAdapter(
+ gpu_factories, decoder_factory, config, format));
+ rtc_video_decoder_adapter->InitializeSync(config);
+ return rtc_video_decoder_adapter;
+}
+
+RTCVideoDecoderStreamAdapter::RTCVideoDecoderStreamAdapter(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory,
+ const media::VideoDecoderConfig& config,
+ const webrtc::SdpVideoFormat& format)
+ : media_task_runner_(gpu_factories->GetTaskRunner()),
+ gpu_factories_(gpu_factories),
+ decoder_factory_(decoder_factory),
+ format_(format),
+ config_(config),
+ max_pending_buffer_count_(kAbsoluteMaxPendingBuffers) {
+ DVLOG(1) << __func__;
+ decoder_info_.implementation_name = "unknown";
+ decoder_info_.is_hardware_accelerated = false;
+ DETACH_FROM_SEQUENCE(decoding_sequence_checker_);
+ weak_this_ = weak_this_factory_.GetWeakPtr();
+}
+
+RTCVideoDecoderStreamAdapter::~RTCVideoDecoderStreamAdapter() {
+ DVLOG(1) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+}
+
+void RTCVideoDecoderStreamAdapter::InitializeSync(
+ const media::VideoDecoderConfig& config) {
+ DVLOG(3) << __func__;
+
+ // Can be called on |worker_thread_| or |decoding_thread_|.
+ DCHECK(!media_task_runner_->RunsTasksInCurrentSequence());
+ const auto start_time = base::TimeTicks::Now();
+
+ // Allow init to complete asynchronously, since we'll probably succeed.
+ // Trying to do it synchronously can block the mojo pipe, and deadlock.
+ auto init_cb = CrossThreadBindOnce(
+ &RTCVideoDecoderStreamAdapter::OnInitializeDone, weak_this_, start_time);
+
+ PostCrossThreadTask(
+ *media_task_runner_.get(), FROM_HERE,
+ CrossThreadBindOnce(
+ &RTCVideoDecoderStreamAdapter::InitializeOnMediaThread,
+ CrossThreadUnretained(this), config, std::move(init_cb)));
+}
+
+int32_t RTCVideoDecoderStreamAdapter::InitDecode(
+ const webrtc::VideoCodec* codec_settings,
+ int32_t number_of_cores) {
+ DVLOG(1) << __func__;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
+
+ video_codec_type_ = codec_settings->codecType;
+ DCHECK_EQ(webrtc::PayloadStringToCodecType(format_.name), video_codec_type_);
+
+ base::AutoLock auto_lock(lock_);
+ init_decode_complete_ = true;
+ AttemptLogInitializationState_Locked();
+ return has_error_ ? WEBRTC_VIDEO_CODEC_UNINITIALIZED : WEBRTC_VIDEO_CODEC_OK;
+}
+
+void RTCVideoDecoderStreamAdapter::AttemptLogInitializationState_Locked() {
+ lock_.AssertAcquired();
+
+ // Don't log more than once.
+ if (logged_init_status_)
+ return;
+
+ // Don't log anything until both InitDecode and Initialize have completed,
+ // unless we failed. Log failures immediately, since both steps might not
+ // ever complete.
+ if (!has_error_ && (!init_complete_ || !init_decode_complete_))
+ return;
+
+ logged_init_status_ = true;
+
+ UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", !has_error_);
+ if (!has_error_) {
+ UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderProfile",
+ GuessVideoCodecProfile(format_),
+ media::VIDEO_CODEC_PROFILE_MAX + 1);
+ }
+}
+
+int32_t RTCVideoDecoderStreamAdapter::Decode(
+ const webrtc::EncodedImage& input_image,
+ bool missing_frames,
+ int64_t render_time_ms) {
+ DVLOG(2) << __func__;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
+
+ // Hardware VP9 decoders don't handle more than one spatial layer. Fall back
+ // to software decoding. See https://crbug.com/webrtc/9304.
+ if (video_codec_type_ == webrtc::kVideoCodecVP9 &&
+ input_image.SpatialIndex().value_or(0) > 0) {
+#if defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS_ASH)
+ if (!base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding)) {
+ DLOG(ERROR) << __func__ << " multiple spatial layers.";
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
+#else
+ DLOG(ERROR) << __func__ << " multiple spatial layers.";
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+#endif // defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS_ASH)
+ }
+
+ if (missing_frames) {
+ DVLOG(2) << "Missing frames";
+ // We probably can't handle broken frames. Request a key frame.
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ }
+
+ if (key_frame_required_) {
+ // We discarded previous frame because we have too many pending buffers (see
+ // logic) below. Now we need to wait for the key frame and discard
+ // everything else.
+ if (input_image._frameType != webrtc::VideoFrameType::kVideoFrameKey) {
+ DVLOG(2) << "Discard non-key frame";
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ }
+ DVLOG(2) << "Key frame received, resume decoding";
+ // ok, we got key frame and can continue decoding.
+ key_frame_required_ = false;
+ }
+
+ std::vector<uint32_t> spatial_layer_frame_size;
+ size_t max_sl_index = input_image.SpatialIndex().value_or(0);
+ for (size_t i = 0; i <= max_sl_index; i++) {
+ auto frame_size = input_image.SpatialLayerFrameSize(i);
+ if (!frame_size)
+ continue;
+ spatial_layer_frame_size.push_back(*frame_size);
+ }
+
+ // Convert to media::DecoderBuffer.
+ // TODO(sandersd): What is |render_time_ms|?
+ auto pending_buffer = std::make_unique<PendingBuffer>();
+ if (spatial_layer_frame_size.size() > 1) {
+ const uint8_t* side_data =
+ reinterpret_cast<const uint8_t*>(spatial_layer_frame_size.data());
+ size_t side_data_size =
+ spatial_layer_frame_size.size() * sizeof(uint32_t) / sizeof(uint8_t);
+ pending_buffer->buffer = media::DecoderBuffer::CopyFrom(
+ input_image.data(), input_image.size(), side_data, side_data_size);
+ } else {
+ pending_buffer->buffer =
+ media::DecoderBuffer::CopyFrom(input_image.data(), input_image.size());
+ }
+ pending_buffer->buffer->set_timestamp(
+ base::TimeDelta::FromMicroseconds(input_image.Timestamp()));
+ pending_buffer->buffer->set_is_key_frame(
+ input_image._frameType == webrtc::VideoFrameType::kVideoFrameKey);
+
+ // Detect config changes, and include the new config if needed.
+ if (ShouldReinitializeForSettingHDRColorSpace(input_image)) {
+ pending_buffer->new_config = config_;
+ pending_buffer->new_config->set_color_space_info(
+ blink::WebRtcToMediaVideoColorSpace(*input_image.ColorSpace()));
+ }
+
+ // Queue for decoding.
+ {
+ base::AutoLock auto_lock(lock_);
+ // TODO(crbug.com/1150098): We could destroy and re-create `decoder_stream_`
+ // here, to reset the decoder state. For now, just fail.
+ if (has_error_) {
+ DLOG(ERROR) << __func__ << " decoding failed.";
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
+
+ if (pending_buffer_count_ >= max_pending_buffer_count_) {
+ // We are severely behind. Drop pending buffers and request a keyframe to
+ // catch up as quickly as possible.
+ DVLOG(2) << "Pending buffers overflow";
+ // Actually we just discarded a frame. We must wait for the key frame and
+ // drop any other non-key frame.
+ key_frame_required_ = true;
+
+ // If we hit the absolute limit, then give up.
+ if (pending_buffer_count_ >= kAbsoluteMaxPendingBuffers) {
+ has_error_ = true;
+ PostCrossThreadTask(
+ *media_task_runner_.get(), FROM_HERE,
+ CrossThreadBindOnce(
+ &RTCVideoDecoderStreamAdapter::ShutdownOnMediaThread,
+ weak_this_));
+ DLOG(ERROR) << __func__ << " too many errors / pending buffers.";
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
+
+ // Note that this is approximate, since there might be decodes in flight.
+ // If they complete, then this might get decremented (clamped to 0), so
+ // we'll underestimate the queue length a bit until it stabilizes.
+ pending_buffer_count_ = 0;
+ // Increase to the absolute max while decoding is paused. It'll be
+ // lowered as we drain the queue.
+ max_pending_buffer_count_ = kAbsoluteMaxPendingBuffers;
+
+ PostCrossThreadTask(
+ *media_task_runner_.get(), FROM_HERE,
+ CrossThreadBindOnce(&RTCVideoDecoderStreamAdapter::ResetOnMediaThread,
+ weak_this_));
+
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ }
+
+ pending_buffer_count_++;
+ }
+
+ // It would be nice to do this on the current thread, but we'd have to hop to
+ // the media thread anyway if we needed to do any work. So just hop to keep
+ // it simpler.
+ PostCrossThreadTask(
+ *media_task_runner_.get(), FROM_HERE,
+ CrossThreadBindOnce(&RTCVideoDecoderStreamAdapter::DecodeOnMediaThread,
+ weak_this_, std::move(pending_buffer)));
+
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoDecoderStreamAdapter::RegisterDecodeCompleteCallback(
+ webrtc::DecodedImageCallback* callback) {
+ DVLOG(2) << __func__;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
+ DCHECK(callback);
+
+ base::AutoLock auto_lock(lock_);
+ decode_complete_callback_ = callback;
+ return has_error_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE
+ : WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoDecoderStreamAdapter::Release() {
+ DVLOG(1) << __func__;
+
+ base::AutoLock auto_lock(lock_);
+
+ PostCrossThreadTask(
+ *media_task_runner_.get(), FROM_HERE,
+ CrossThreadBindOnce(&RTCVideoDecoderStreamAdapter::ShutdownOnMediaThread,
+ weak_this_));
+
+ return has_error_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE
+ : WEBRTC_VIDEO_CODEC_OK;
+}
+
+webrtc::VideoDecoder::DecoderInfo RTCVideoDecoderStreamAdapter::GetDecoderInfo()
+ const {
+ base::AutoLock auto_lock(lock_);
+ return decoder_info_;
+}
+
+void RTCVideoDecoderStreamAdapter::InitializeOnMediaThread(
+ const media::VideoDecoderConfig& config,
+ InitCB init_cb) {
+ DVLOG(3) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+ // There's no re-init these days. If we ever need to re-init, such as to
+ // clear an error, then `decoder_stream_` and `demuxer_stream_` should be
+ // recreated rather than re-used.
+ DCHECK(!decoder_stream_);
+
+ // TODO(sandersd): Plumb a real log sink here so that we can contribute to
+ // the media-internals UI. The current log just discards all messages.
+ media_log_ = std::make_unique<media::NullMediaLog>();
+
+ // Encryption is not supported.
+ media::CdmContext* cdm_context = nullptr;
+
+ // First init. Set everything up.
+ demuxer_stream_ = std::make_unique<InternalDemuxerStream>(config);
+
+ auto traits =
+ std::make_unique<media::DecoderStreamTraits<media::DemuxerStream::VIDEO>>(
+ media_log_.get());
+
+ media::RequestOverlayInfoCB request_overlay_cb = base::DoNothing();
+ auto create_decoders_cb = base::BindRepeating(
+ [](scoped_refptr<base::SequencedTaskRunner> task_runner,
+ media::DecoderFactory* decoder_factory,
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::MediaLog* media_log,
+ const media::RequestOverlayInfoCB& request_overlay_cb) {
+ std::vector<std::unique_ptr<media::VideoDecoder>> video_decoders;
+ decoder_factory->CreateVideoDecoders(
+ std::move(task_runner), gpu_factories, media_log,
+ request_overlay_cb, gpu_factories->GetRenderingColorSpace(),
+ &video_decoders);
+ return video_decoders;
+ },
+ media_task_runner_, base::Unretained(decoder_factory_),
+ base::Unretained(gpu_factories_), media_log_.get(),
+ std::move(request_overlay_cb));
+
+ decoder_stream_ = std::make_unique<media::VideoDecoderStream>(
+ std::move(traits), media_task_runner_, std::move(create_decoders_cb),
+ media_log_.get());
+ decoder_stream_->set_decoder_change_observer(base::BindRepeating(
+ &RTCVideoDecoderStreamAdapter::OnDecoderChanged, weak_this_));
+ decoder_stream_->Initialize(
+ demuxer_stream_.get(), ConvertToBaseOnceCallback(std::move(init_cb)),
+ cdm_context, base::DoNothing() /* statistics_cb */,
+ base::DoNothing() /* waiting_cb */);
+}
+
+void RTCVideoDecoderStreamAdapter::OnInitializeDone(base::TimeTicks start_time,
+ bool success) {
+ RecordInitializationLatency(base::TimeTicks::Now() - start_time);
+ base::AutoLock auto_lock(lock_);
+ init_complete_ = true;
+
+ if (!success) {
+ has_error_ = true;
+ // TODO(crbug.com/1150103): Is it guaranteed that there will be a next
+ // decode call to signal the error? If not, then we should use the decode
+ // callback if we have one yet.
+ } else {
+ AdjustQueueLength_Locked();
+ AttemptRead_Locked();
+ }
+
+ AttemptLogInitializationState_Locked();
+}
+
+void RTCVideoDecoderStreamAdapter::DecodeOnMediaThread(
+ std::unique_ptr<PendingBuffer> pending_buffer) {
+ DVLOG(4) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+ base::AutoLock auto_lock(lock_);
+
+ // If we're in the error state, then do nothing. `Decode()` will notify about
+ // the error.
+ if (has_error_)
+ return;
+
+ // Remember that this timestamp has already been added to the list.
+ demuxer_stream_->EnqueueBuffer(std::move(pending_buffer));
+
+ // Kickstart reading output, if we're not already.
+ AttemptRead_Locked();
+}
+
+void RTCVideoDecoderStreamAdapter::OnFrameReady(
+ media::VideoDecoderStream::ReadResult result) {
+ DVLOG(3) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+ pending_read_ = false;
+
+ switch (result.code()) {
+ case media::StatusCode::kOk:
+ break;
+ case media::StatusCode::kAborted:
+ // We're doing a Reset(), so just ignore it and keep going.
+ return;
+ default:
+ DVLOG(2) << "Entering permanent error state";
+ UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError",
+ media::VideoDecodeAccelerator::PLATFORM_FAILURE,
+ media::VideoDecodeAccelerator::ERROR_MAX + 1);
+ {
+ base::AutoLock auto_lock(lock_);
+ has_error_ = true;
+ pending_buffer_count_ = 0;
+ }
+ return;
+ }
+
+ scoped_refptr<media::VideoFrame> frame = std::move(result).value();
+ DCHECK(frame);
+
+ const base::TimeDelta timestamp = frame->timestamp();
+ webrtc::VideoFrame rtc_frame =
+ webrtc::VideoFrame::Builder()
+ .set_video_frame_buffer(
+ new rtc::RefCountedObject<blink::WebRtcVideoFrameAdapter>(
+ std::move(frame)))
+ .set_timestamp_rtp(static_cast<uint32_t>(timestamp.InMicroseconds()))
+ .set_timestamp_us(0)
+ .set_rotation(webrtc::kVideoRotation_0)
+ .build();
+
+ base::AutoLock auto_lock(lock_);
+
+ // Try to read the next output, if any, regardless if this succeeded.
+ AttemptRead_Locked();
+
+ // Assumes that Decoded() can be safely called with the lock held, which
+ // apparently it can be because RTCVideoDecoder does the same.
+ DCHECK(decode_complete_callback_);
+ // Since we can reset the queue length while things are in flight, just clamp
+ // to zero. We could choose to discard this frame, too, since it was before a
+ // reset was issued.
+ if (pending_buffer_count_ > 0)
+ pending_buffer_count_--;
+ decode_complete_callback_->Decoded(rtc_frame);
+ AdjustQueueLength_Locked();
+}
+
+void RTCVideoDecoderStreamAdapter::AttemptRead_Locked() {
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+ lock_.AssertAcquired();
+
+ // Only one read may be in-flight at once. We'll try again once the previous
+ // read completes. If a reset is in progress, a read is not allowed to start.
+ // We also may not read until DecoderStream init completes.
+ if (pending_read_ || pending_reset_ || !init_complete_ || has_error_)
+ return;
+
+ // We don't care if there are any pending decodes; keep a read running even if
+ // there aren't any. This way, we don't have to count correctly.
+
+ decoder_stream_->Read(
+ base::BindOnce(&RTCVideoDecoderStreamAdapter::OnFrameReady, weak_this_));
+ pending_read_ = true;
+}
+
+bool RTCVideoDecoderStreamAdapter::ShouldReinitializeForSettingHDRColorSpace(
+ const webrtc::EncodedImage& input_image) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
+
+ if (config_.profile() == media::VP9PROFILE_PROFILE2 &&
+ input_image.ColorSpace()) {
+ const media::VideoColorSpace& new_color_space =
+ blink::WebRtcToMediaVideoColorSpace(*input_image.ColorSpace());
+ if (!config_.color_space_info().IsSpecified() ||
+ new_color_space != config_.color_space_info()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void RTCVideoDecoderStreamAdapter::ResetOnMediaThread() {
+ DVLOG(3) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(!pending_reset_);
+ // A pending read is okay. We may decide to reset at any time, even if a read
+ // is in progress. It'll be aborted when we reset `decoder_stream_`, and no
+ // new read will be issued until the reset completes.
+
+ pending_reset_ = true;
+ demuxer_stream_->Reset();
+ decoder_stream_->Reset(base::BindOnce(
+ &RTCVideoDecoderStreamAdapter::OnResetCompleteOnMediaThread, weak_this_));
+}
+
+void RTCVideoDecoderStreamAdapter::OnResetCompleteOnMediaThread() {
+ DVLOG(3) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(pending_reset_);
+ DCHECK(!pending_read_);
+
+ base::AutoLock auto_lock(lock_);
+
+ pending_reset_ = false;
+
+ AdjustQueueLength_Locked();
+ AttemptRead_Locked();
+}
+
+void RTCVideoDecoderStreamAdapter::AdjustQueueLength_Locked() {
+ // After an init or reset, we can have a larger backlog of queued
+ // DecoderBuffers than we'd normally allow. Since decoding is effectively
+ // paused, we let the backlog grow since it doesn't indicate that we're
+ // running behind in any meaningful sense; hopefully we'll catch up once we
+ // turn the decoder on. Once decoding un-pauses, we need to get back to a
+ // sane upper limit, without spuriously tripping the queue length check in the
+ // process. New decodes will still arrive, and decoding only has to be fast
+ // enough on average. So, the queue might get longer as we (on average) work
+ // through the backlog. `kMaxPendingBuffers` is what we believe is the
+ // maximum backlog we will see, if decoding is "fast enough".
+
+ // So, we lower the max allowable limit as we drain buffers, but allow that
+ // the queue can grow by up to `kMaxPendingBuffers` at any time from the
+ // lowest limit we've observed. This has the side-effect of resetting the
+ // limit to `kMaxPendingBuffers` if we ever do work through the backlog.
+ lock_.AssertAcquired();
+ if (pending_buffer_count_ + kMaxPendingBuffers < max_pending_buffer_count_)
+ max_pending_buffer_count_ = pending_buffer_count_ + kMaxPendingBuffers;
+}
+
+void RTCVideoDecoderStreamAdapter::ShutdownOnMediaThread() {
+ DVLOG(3) << __func__;
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+ weak_this_factory_.InvalidateWeakPtrs();
+ decoder_stream_.reset();
+ demuxer_stream_.reset();
+
+ base::AutoLock auto_lock(lock_);
+ pending_reset_ = false;
+ pending_read_ = false;
+ init_complete_ = false;
+ init_decode_complete_ = false;
+ logged_init_status_ = false;
+ pending_buffer_count_ = 0;
+ // `has_error_` might or might not be set.
+}
+
+void RTCVideoDecoderStreamAdapter::OnDecoderChanged(
+ media::VideoDecoder* decoder) {
+ DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+ if (!decoder)
+ return;
+
+ base::AutoLock auto_lock(lock_);
+
+ if (decoder->IsPlatformDecoder()) {
+ decoder_info_.implementation_name = "ExternalDecoder";
+ decoder_info_.is_hardware_accelerated = true;
+ return;
+ }
+
+ // Translate software decoders to look like rtc-provided ones, to make it
+ // easier for clients to detect.
+ switch (demuxer_stream_->video_decoder_config().codec()) {
+ case media::VideoCodec::kCodecVP8:
+ case media::VideoCodec::kCodecVP9:
+ decoder_info_.implementation_name = "libvpx (DecoderStream)";
+ break;
+ case media::VideoCodec::kCodecAV1:
+ decoder_info_.implementation_name = "libaom (DecoderStream)";
+ break;
+ case media::VideoCodec::kCodecH264:
+ decoder_info_.implementation_name = "FFmpeg (DecoderStream)";
+ break;
+ default:
+ decoder_info_.implementation_name = "unknown";
+ }
+ decoder_info_.is_hardware_accelerated = false;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h
new file mode 100644
index 00000000000..80f91ad93a7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h
@@ -0,0 +1,199 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/synchronization/lock.h"
+#include "media/base/decode_status.h"
+#include "media/base/media_switches.h"
+#include "media/base/overlay_info.h"
+#include "media/base/status.h"
+#include "media/base/supported_video_decoder_config.h"
+#include "media/base/video_codecs.h"
+#include "media/base/video_decoder.h"
+#include "media/base/video_decoder_config.h"
+#include "media/filters/decoder_stream.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
+#include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace base {
+class SequencedThreadTaskRunner;
+} // namespace base
+
+namespace media {
+class DecoderBuffer;
+class DecoderFactory;
+class GpuVideoAcceleratorFactories;
+class MediaLog;
+} // namespace media
+
+namespace blink {
+
+// This class decodes video for WebRTC using a media::VideoDecoderStream.
+//
+// VideoDecoderStream is used by almost all non-WebRTC video decoding in
+// chromium. It handles selecting the decoder implementation, including between
+// hardware and software implementations. It also provides fallback / fall-
+// forward between implementations if needed for config changes.
+//
+// Lifecycle methods are called on the WebRTC worker thread. Decoding happens on
+// a WebRTC DecodingThread, which is an rtc::PlatformThread owend by WebRTC; it
+// does not have a TaskRunner.
+//
+// To stop decoding, WebRTC stops the DecodingThread and then calls Release() on
+// the worker. Calling the DecodedImageCallback after the DecodingThread is
+// stopped is illegal but, because we decode on the media thread, there is no
+// way to synchronize this correctly.
+class PLATFORM_EXPORT RTCVideoDecoderStreamAdapter
+ : public webrtc::VideoDecoder {
+ public:
+ // Creates and initializes an RTCVideoDecoderStreamAdapter. Returns nullptr if
+ // |format| cannot be supported.
+ // Called on the worker thread.
+ static std::unique_ptr<RTCVideoDecoderStreamAdapter> Create(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory,
+ const webrtc::SdpVideoFormat& format);
+
+ // Called on |media_task_runner_|.
+ ~RTCVideoDecoderStreamAdapter() override;
+
+ // webrtc::VideoDecoder implementation.
+ // Called on the DecodingThread.
+ int32_t InitDecode(const webrtc::VideoCodec* codec_settings,
+ int32_t number_of_cores) override;
+ // Called on the DecodingThread.
+ int32_t RegisterDecodeCompleteCallback(
+ webrtc::DecodedImageCallback* callback) override;
+ // Called on the DecodingThread.
+ int32_t Decode(const webrtc::EncodedImage& input_image,
+ bool missing_frames,
+ int64_t render_time_ms) override;
+ // Called on the worker thread and on the DecodingThread.
+ int32_t Release() override;
+ // Called on the worker thread and on the DecodingThread.
+ DecoderInfo GetDecoderInfo() const override;
+
+ private:
+ class InternalDemuxerStream;
+
+ using InitCB = CrossThreadOnceFunction<void(bool)>;
+ using FlushDoneCB = CrossThreadOnceFunction<void()>;
+
+ struct PendingBuffer {
+ scoped_refptr<media::DecoderBuffer> buffer;
+ base::Optional<media::VideoDecoderConfig> new_config;
+ };
+
+ // Called on the worker thread.
+ RTCVideoDecoderStreamAdapter(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* decoder_factory,
+ const media::VideoDecoderConfig& config,
+ const webrtc::SdpVideoFormat& format);
+
+ void InitializeSync(const media::VideoDecoderConfig& config);
+ void InitializeOnMediaThread(const media::VideoDecoderConfig& config,
+ InitCB init_cb);
+ void OnInitializeDone(base::TimeTicks start_time, bool success);
+ void DecodeOnMediaThread(std::unique_ptr<PendingBuffer>);
+ void OnFrameReady(media::VideoDecoderStream::ReadResult result);
+
+ bool ShouldReinitializeForSettingHDRColorSpace(
+ const webrtc::EncodedImage& input_image) const;
+
+ // If no read is in progress with `decoder_stream_`, and there is undecoded
+ // input buffers, then start a read. Otherwise, do nothing.
+ void AttemptRead_Locked();
+
+ // Start a `DecoderStream::Reset`.
+ void ResetOnMediaThread();
+
+ // Notification when `DecoderStream::Reset` completes.
+ void OnResetCompleteOnMediaThread();
+
+ // Adjust `allowable_decoder_queue_length_` if needed.
+ void AdjustQueueLength_Locked();
+
+ // Clear as much memory as we can, cancel outstanding callbacks, etc.
+ void ShutdownOnMediaThread();
+
+ // Log the init state, if we know what it is. Will do nothing if Initialize
+ // has not completed, and also InitDecode() has not been called.
+ void AttemptLogInitializationState_Locked();
+
+ // Called on the media thread when `decoder_stream_` changes the decoder.
+ void OnDecoderChanged(media::VideoDecoder* decoder);
+
+ // Construction parameters.
+ const scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
+ media::GpuVideoAcceleratorFactories* const gpu_factories_;
+ media::DecoderFactory* const decoder_factory_;
+ const webrtc::SdpVideoFormat format_;
+ media::VideoDecoderConfig config_;
+
+ // Media thread members.
+ // |media_log_| must outlive |video_decoder_| because it is passed as a raw
+ // pointer.
+ std::unique_ptr<media::MediaLog> media_log_;
+
+ // Decoding thread members.
+ bool key_frame_required_ = true;
+ webrtc::VideoCodecType video_codec_type_ = webrtc::kVideoCodecGeneric;
+ webrtc::DecodedImageCallback* decode_complete_callback_ = nullptr;
+
+ // Shared members.
+ mutable base::Lock lock_;
+ bool has_error_ GUARDED_BY(lock_) = false;
+ // Current maximum number of in-flight undecoded frames.
+ size_t max_pending_buffer_count_ GUARDED_BY(lock_);
+ // Current number of in-flight decodes.
+ size_t pending_buffer_count_ GUARDED_BY(lock_) = 0;
+ // Has DecoderStream initialization completed? This does not imply that it
+ // completed successfully.
+ bool init_complete_ GUARDED_BY(lock_) = false;
+ // Has InitDecode() been called?
+ bool init_decode_complete_ GUARDED_BY(lock_) = false;
+ // Have we logged init status yet?
+ bool logged_init_status_ GUARDED_BY(lock_) = false;
+ // Current decoder info, as reported by GetDecoderInfo().
+ webrtc::VideoDecoder::DecoderInfo decoder_info_ GUARDED_BY(lock_);
+
+ // Do we have an outstanding `DecoderStream::Read()`?
+ // Media thread only.
+ bool pending_read_ = false;
+
+ // Do we have an in-flight `DecoderStream::Reset()`?
+ // Media thread only.
+ bool pending_reset_ = false;
+
+ // Media thread only.
+ std::unique_ptr<InternalDemuxerStream> demuxer_stream_;
+ std::unique_ptr<media::VideoDecoderStream> decoder_stream_;
+
+ // Thread management.
+ SEQUENCE_CHECKER(decoding_sequence_checker_);
+
+ base::WeakPtr<RTCVideoDecoderStreamAdapter> weak_this_;
+ base::WeakPtrFactory<RTCVideoDecoderStreamAdapter> weak_this_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderStreamAdapter);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc
new file mode 100644
index 00000000000..bc437b5d09a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter_test.cc
@@ -0,0 +1,409 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/check.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "media/base/decode_status.h"
+#include "media/base/decoder_factory.h"
+#include "media/base/media_util.h"
+#include "media/base/video_decoder.h"
+#include "media/base/video_decoder_config.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_types.h"
+#include "media/video/mock_gpu_video_accelerator_factories.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h"
+#include "third_party/webrtc/api/video_codecs/video_codec.h"
+#include "third_party/webrtc/media/base/vp9_profile.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::DoAll;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::ReturnRef;
+using ::testing::SaveArg;
+using ::testing::StrictMock;
+
+namespace blink {
+
+namespace {
+
+class MockVideoDecoder : public media::VideoDecoder {
+ public:
+ std::string GetDisplayName() const override { return "MockVideoDecoder"; }
+ media::VideoDecoderType GetDecoderType() const override {
+ return media::VideoDecoderType::kUnknown;
+ }
+ void Initialize(const media::VideoDecoderConfig& config,
+ bool low_delay,
+ media::CdmContext* cdm_context,
+ InitCB init_cb,
+ const OutputCB& output_cb,
+ const media::WaitingCB& waiting_cb) override {
+ Initialize_(config, low_delay, cdm_context, init_cb, output_cb, waiting_cb);
+ }
+ MOCK_METHOD6(Initialize_,
+ void(const media::VideoDecoderConfig& config,
+ bool low_delay,
+ media::CdmContext* cdm_context,
+ InitCB& init_cb,
+ const OutputCB& output_cb,
+ const media::WaitingCB& waiting_cb));
+ void Decode(scoped_refptr<media::DecoderBuffer> buffer,
+ DecodeCB cb) override {
+ Decode_(std::move(buffer), cb);
+ }
+ MOCK_METHOD2(Decode_,
+ void(scoped_refptr<media::DecoderBuffer> buffer, DecodeCB&));
+ void Reset(base::OnceClosure cb) override { Reset_(cb); }
+ MOCK_METHOD1(Reset_, void(base::OnceClosure&));
+ bool NeedsBitstreamConversion() const override { return false; }
+ bool CanReadWithoutStalling() const override { return true; }
+ int GetMaxDecodeRequests() const override { return 1; }
+ bool IsOptimizedForRTC() const override { return true; }
+};
+
+class MockDecoderFactory : public media::DecoderFactory {
+ public:
+ ~MockDecoderFactory() override = default;
+
+ MOCK_METHOD3(
+ CreateAudioDecoders,
+ void(scoped_refptr<base::SequencedTaskRunner> task_runner,
+ media::MediaLog* media_log,
+ std::vector<std::unique_ptr<media::AudioDecoder>>* audio_decoders));
+
+ void CreateVideoDecoders(scoped_refptr<base::SequencedTaskRunner> task_runner,
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::MediaLog* media_log,
+ media::RequestOverlayInfoCB request_overlay_info_cb,
+ const gfx::ColorSpace& target_color_space,
+ std::vector<std::unique_ptr<media::VideoDecoder>>*
+ video_decoders) override {
+ video_decoders->push_back(std::move(decoder_));
+ }
+
+ MockVideoDecoder* decoder() const { return decoder_.get(); }
+
+ private:
+ // `decoder_` will be null once we're asked to create video decoders.
+ std::unique_ptr<MockVideoDecoder> decoder_ =
+ std::make_unique<MockVideoDecoder>();
+};
+
+// Wraps a callback as a webrtc::DecodedImageCallback.
+class DecodedImageCallback : public webrtc::DecodedImageCallback {
+ public:
+ explicit DecodedImageCallback(
+ base::RepeatingCallback<void(const webrtc::VideoFrame&)> callback)
+ : callback_(callback) {}
+
+ int32_t Decoded(webrtc::VideoFrame& decodedImage) override {
+ callback_.Run(decodedImage);
+ // TODO(sandersd): Does the return value matter? RTCVideoDecoder
+ // ignores it.
+ return 0;
+ }
+
+ private:
+ base::RepeatingCallback<void(const webrtc::VideoFrame&)> callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DecodedImageCallback);
+};
+
+} // namespace
+
+class RTCVideoDecoderStreamAdapterTest : public ::testing::Test {
+ public:
+ RTCVideoDecoderStreamAdapterTest()
+ : task_environment_(
+ base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED),
+ media_thread_task_runner_(
+ base::ThreadPool::CreateSequencedTaskRunner({})),
+ decoded_image_callback_(decoded_cb_.Get()),
+ sdp_format_(webrtc::SdpVideoFormat(
+ webrtc::CodecTypeToPayloadString(webrtc::kVideoCodecVP9))) {
+ decoder_factory_ = std::make_unique<MockDecoderFactory>();
+
+ ON_CALL(gpu_factories_, GetTaskRunner())
+ .WillByDefault(Return(media_thread_task_runner_));
+ EXPECT_CALL(gpu_factories_, GetTaskRunner()).Times(AtLeast(0));
+ EXPECT_CALL(gpu_factories_, GetRenderingColorSpace())
+ .Times(AtLeast(0))
+ .WillRepeatedly(ReturnRef(rendering_colorspace_));
+ }
+
+ ~RTCVideoDecoderStreamAdapterTest() override {
+ if (!adapter_)
+ return;
+
+ media_thread_task_runner_->DeleteSoon(FROM_HERE, std::move(adapter_));
+ task_environment_.RunUntilIdle();
+ }
+
+ protected:
+ bool BasicSetup() {
+ if (!CreateAndInitialize())
+ return false;
+ if (InitDecode() != WEBRTC_VIDEO_CODEC_OK)
+ return false;
+ if (RegisterDecodeCompleteCallback() != WEBRTC_VIDEO_CODEC_OK)
+ return false;
+ task_environment_.RunUntilIdle();
+ return true;
+ }
+
+ bool BasicTeardown() {
+ if (Release() != WEBRTC_VIDEO_CODEC_OK)
+ return false;
+ return true;
+ }
+
+ bool CreateAndInitialize(bool init_cb_result = true) {
+ auto* decoder = decoder_factory_->decoder();
+ EXPECT_CALL(*decoder, Initialize_(_, _, _, _, _, _))
+ .WillOnce(DoAll(
+ SaveArg<0>(&vda_config_), SaveArg<4>(&output_cb_),
+ base::test::RunOnceCallback<3>(
+ init_cb_result
+ ? media::OkStatus()
+ : media::Status(media::StatusCode::kCodeOnlyForTesting))));
+ adapter_ = RTCVideoDecoderStreamAdapter::Create(
+ &gpu_factories_, decoder_factory_.get(), sdp_format_);
+ return !!adapter_;
+ }
+
+ int32_t InitDecode() {
+ webrtc::VideoCodec codec_settings;
+ codec_settings.codecType = webrtc::kVideoCodecVP9;
+ return adapter_->InitDecode(&codec_settings, 1);
+ }
+
+ int32_t RegisterDecodeCompleteCallback() {
+ return adapter_->RegisterDecodeCompleteCallback(&decoded_image_callback_);
+ }
+
+ int32_t Decode(uint32_t timestamp, bool missing_frames = false) {
+ webrtc::EncodedImage input_image;
+ static const uint8_t data[1] = {0};
+ input_image.SetEncodedData(
+ webrtc::EncodedImageBuffer::Create(data, sizeof(data)));
+ input_image._frameType = webrtc::VideoFrameType::kVideoFrameKey;
+ input_image.SetTimestamp(timestamp);
+ return adapter_->Decode(input_image, missing_frames, 0);
+ }
+
+ void FinishDecode(uint32_t timestamp) {
+ media_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &RTCVideoDecoderStreamAdapterTest::FinishDecodeOnMediaThread,
+ base::Unretained(this), timestamp));
+ }
+
+ void FinishDecodeOnMediaThread(uint32_t timestamp) {
+ DCHECK(media_thread_task_runner_->RunsTasksInCurrentSequence());
+ gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes];
+ mailbox_holders[0].mailbox = gpu::Mailbox::Generate();
+ scoped_refptr<media::VideoFrame> frame =
+ media::VideoFrame::WrapNativeTextures(
+ media::PIXEL_FORMAT_ARGB, mailbox_holders,
+ media::VideoFrame::ReleaseMailboxCB(), gfx::Size(640, 360),
+ gfx::Rect(640, 360), gfx::Size(640, 360),
+ base::TimeDelta::FromMicroseconds(timestamp));
+ output_cb_.Run(std::move(frame));
+ }
+
+ int32_t Release() { return adapter_->Release(); }
+
+ webrtc::EncodedImage GetEncodedImageWithColorSpace(uint32_t timestamp) {
+ webrtc::EncodedImage input_image;
+ static const uint8_t data[1] = {0};
+ input_image.SetEncodedData(
+ webrtc::EncodedImageBuffer::Create(data, sizeof(data)));
+ input_image._frameType = webrtc::VideoFrameType::kVideoFrameKey;
+ input_image.SetTimestamp(timestamp);
+ webrtc::ColorSpace webrtc_color_space;
+ webrtc_color_space.set_primaries_from_uint8(1);
+ webrtc_color_space.set_transfer_from_uint8(1);
+ webrtc_color_space.set_matrix_from_uint8(1);
+ webrtc_color_space.set_range_from_uint8(1);
+ input_image.SetColorSpace(webrtc_color_space);
+ return input_image;
+ }
+
+ base::test::TaskEnvironment task_environment_;
+ scoped_refptr<base::SequencedTaskRunner> media_thread_task_runner_;
+
+ StrictMock<media::MockGpuVideoAcceleratorFactories> gpu_factories_{
+ nullptr /* SharedImageInterface* */};
+ std::unique_ptr<MockDecoderFactory> decoder_factory_;
+ StrictMock<base::MockCallback<
+ base::RepeatingCallback<void(const webrtc::VideoFrame&)>>>
+ decoded_cb_;
+ DecodedImageCallback decoded_image_callback_;
+ std::unique_ptr<RTCVideoDecoderStreamAdapter> adapter_;
+ media::VideoDecoder::OutputCB output_cb_;
+
+ const gfx::ColorSpace rendering_colorspace_{gfx::ColorSpace::CreateSRGB()};
+
+ private:
+ webrtc::SdpVideoFormat sdp_format_;
+
+ media::VideoDecoderConfig vda_config_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderStreamAdapterTest);
+};
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, Create_UnknownFormat) {
+ auto adapter = RTCVideoDecoderAdapter::Create(
+ &gpu_factories_, webrtc::SdpVideoFormat(webrtc::CodecTypeToPayloadString(
+ webrtc::kVideoCodecGeneric)));
+ ASSERT_FALSE(adapter);
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, FailInit_InitDecodeFails) {
+ // If initialization fails before InitDecode runs, then InitDecode should too.
+ EXPECT_TRUE(CreateAndInitialize(false));
+ task_environment_.RunUntilIdle();
+ EXPECT_EQ(InitDecode(), WEBRTC_VIDEO_CODEC_UNINITIALIZED);
+ EXPECT_FALSE(BasicTeardown());
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, FailInit_DecodeFails) {
+ // If initialization fails after InitDecode runs, then the first Decode should
+ // fail instead.
+ EXPECT_TRUE(CreateAndInitialize(false));
+ EXPECT_EQ(InitDecode(), WEBRTC_VIDEO_CODEC_OK);
+ task_environment_.RunUntilIdle();
+ EXPECT_EQ(Decode(0), WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
+ EXPECT_FALSE(BasicTeardown());
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, MissingFramesRequestsKeyframe) {
+ EXPECT_TRUE(BasicSetup());
+ EXPECT_EQ(Decode(0, true), WEBRTC_VIDEO_CODEC_ERROR);
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, DecodeOneFrame) {
+ auto* decoder = decoder_factory_->decoder();
+ EXPECT_TRUE(BasicSetup());
+ EXPECT_CALL(*decoder, Decode_(_, _))
+ .WillOnce(base::test::RunOnceCallback<1>(media::DecodeStatus::OK));
+ EXPECT_EQ(Decode(0), WEBRTC_VIDEO_CODEC_OK);
+ task_environment_.RunUntilIdle();
+ EXPECT_CALL(decoded_cb_, Run(_));
+ FinishDecode(0);
+ EXPECT_TRUE(BasicTeardown());
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, SlowDecodingCausesReset) {
+ // If we send enough(tm) decodes without returning any decoded frames, then
+ // the decoder should try a flush + reset.
+ auto* decoder = decoder_factory_->decoder();
+ EXPECT_TRUE(BasicSetup());
+
+ // All Decodes succeed immediately. The backup will come from the fact that
+ // we won't run the media thread while sending decode requests in.
+ EXPECT_CALL(*decoder, Decode_(_, _))
+ .WillRepeatedly(base::test::RunOnceCallback<1>(media::DecodeStatus::OK));
+ // At some point, `adapter_` should trigger a reset.
+ EXPECT_CALL(*decoder, Reset_(_)).WillOnce(base::test::RunOnceCallback<0>());
+
+ // Add decodes without calling FinishDecode.
+ int limit = -1;
+ for (int i = 0; i < 100 && limit < 0; i++) {
+ switch (auto result = Decode(i)) {
+ case WEBRTC_VIDEO_CODEC_OK:
+ // Keep going -- it's still happy.
+ break;
+ case WEBRTC_VIDEO_CODEC_ERROR:
+ // Yay -- it now believes that it's hopelessly behind, and has requested
+ // a keyframe.
+ limit = i;
+ break;
+ default:
+ EXPECT_TRUE(false) << result;
+ }
+ }
+
+ // We should have found a limit at some point.
+ EXPECT_GT(limit, -1);
+
+ // Let the decodes / reset complete.
+ task_environment_.RunUntilIdle();
+
+ // Everything should be reset, so one more decode should succeed. Push a
+ // frame through to make sure.
+ // Should we consider pushing some non-keyframes as well, which should be
+ // rejected since it reset?
+ EXPECT_EQ(Decode(1000), WEBRTC_VIDEO_CODEC_OK);
+ task_environment_.RunUntilIdle();
+ EXPECT_CALL(decoded_cb_, Run(_));
+ FinishDecode(1000);
+ EXPECT_TRUE(BasicTeardown());
+}
+
+TEST_F(RTCVideoDecoderStreamAdapterTest, ReallySlowDecodingCausesFallback) {
+ // If we send really enough(tm) decodes without returning any decoded frames,
+ // then the decoder should fall back to software.
+ auto* decoder = decoder_factory_->decoder();
+ EXPECT_TRUE(BasicSetup());
+
+ // All Decodes succeed immediately. The backup will come from the fact that
+ // we won't run the media thread while sending decode requests in.
+ EXPECT_CALL(*decoder, Decode_(_, _))
+ .WillRepeatedly(base::test::RunOnceCallback<1>(media::DecodeStatus::OK));
+ // At some point, `adapter_` should trigger a reset, before it falls back. It
+ // should not do so more than once, since we won't complete the reset.
+ EXPECT_CALL(*decoder, Reset_(_)).WillOnce(base::test::RunOnceCallback<0>());
+
+ // Add decodes without calling FinishDecode.
+ int limit = -1;
+ for (int i = 0; i < 100 && limit < 0; i++) {
+ switch (auto result = Decode(i)) {
+ case WEBRTC_VIDEO_CODEC_OK:
+ case WEBRTC_VIDEO_CODEC_ERROR:
+ // Keep going -- it's still happy, or not sufficiretrvg.
+ break;
+ case WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE:
+ // Yay -- it now believes that it's hopelessly behind, and has requested
+ // a keyframe.
+ limit = i;
+ break;
+ default:
+ EXPECT_TRUE(false) << result;
+ }
+ }
+
+ // We should have found a limit at some point.
+ EXPECT_GT(limit, -1);
+
+ // Let the decodes / reset complete.
+ task_environment_.RunUntilIdle();
+ EXPECT_FALSE(BasicTeardown());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index 99a34c33dbf..13248d718fb 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -266,7 +266,6 @@ bool CreateSpatialLayersConfig(
sl.height = base::checked_cast<int32_t>(rtc_sl.height);
if (!ConvertKbpsToBps(rtc_sl.targetBitrate, &sl.bitrate_bps))
return false;
- sl.bitrate_bps = rtc_sl.targetBitrate * 1000;
sl.framerate = base::saturated_cast<int32_t>(rtc_sl.maxFramerate);
sl.max_qp = base::saturated_cast<uint8_t>(rtc_sl.qpMax);
sl.num_of_temporal_layers =
@@ -622,7 +621,8 @@ void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
// Use import mode for camera when GpuMemoryBuffer-based video capture is
// enabled.
pixel_format = media::PIXEL_FORMAT_NV12;
- storage_type = media::VideoEncodeAccelerator::Config::StorageType::kDmabuf;
+ storage_type =
+ media::VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer;
use_native_input_ = true;
}
const media::VideoEncodeAccelerator::Config config(
@@ -804,26 +804,30 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
input_frame_coded_size_ = input_coded_size;
- for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
- base::UnsafeSharedMemoryRegion shm = base::UnsafeSharedMemoryRegion::Create(
- media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
- input_coded_size));
- if (!shm.IsValid()) {
- LogAndNotifyError(FROM_HERE, "failed to create input buffer ",
- media::VideoEncodeAccelerator::kPlatformFailureError);
- return;
- }
- base::WritableSharedMemoryMapping mapping = shm.Map();
- if (!mapping.IsValid()) {
- LogAndNotifyError(FROM_HERE, "failed to create input buffer ",
- media::VideoEncodeAccelerator::kPlatformFailureError);
- return;
+ // |input_buffers_| is only needed in non import mode.
+ if (!use_native_input_) {
+ for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
+ base::UnsafeSharedMemoryRegion shm =
+ base::UnsafeSharedMemoryRegion::Create(
+ media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
+ input_coded_size));
+ if (!shm.IsValid()) {
+ LogAndNotifyError(FROM_HERE, "failed to create input buffer ",
+ media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+ base::WritableSharedMemoryMapping mapping = shm.Map();
+ if (!mapping.IsValid()) {
+ LogAndNotifyError(FROM_HERE, "failed to create input buffer ",
+ media::VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+ input_buffers_.push_back(
+ std::make_unique<std::pair<base::UnsafeSharedMemoryRegion,
+ base::WritableSharedMemoryMapping>>(
+ std::move(shm), std::move(mapping)));
+ input_buffers_free_.push_back(i);
}
- input_buffers_.push_back(
- std::make_unique<std::pair<base::UnsafeSharedMemoryRegion,
- base::WritableSharedMemoryMapping>>(
- std::move(shm), std::move(mapping)));
- input_buffers_free_.push_back(i);
}
for (int i = 0; i < kOutputBufferCount; ++i) {
@@ -928,6 +932,7 @@ void RTCVideoEncoder::Impl::BitstreamBufferReady(
bool key_frame =
image._frameType == webrtc::VideoFrameType::kVideoFrameKey;
webrtc::CodecSpecificInfoVP9& vp9 = info.codecSpecific.VP9;
+ info.end_of_picture = true;
if (metadata.vp9) {
// Temporal layer stream.
vp9.first_frame_in_picture = true;
@@ -941,7 +946,6 @@ void RTCVideoEncoder::Impl::BitstreamBufferReady(
vp9.num_ref_pics = metadata.vp9->p_diffs.size();
for (size_t i = 0; i < metadata.vp9->p_diffs.size(); ++i)
vp9.p_diff[i] = metadata.vp9->p_diffs[i];
- vp9.end_of_picture = true;
vp9.ss_data_available = key_frame;
vp9.first_active_layer = 0u;
vp9.spatial_layer_resolution_present = true;
@@ -957,7 +961,6 @@ void RTCVideoEncoder::Impl::BitstreamBufferReady(
vp9.gof_idx = 0;
vp9.num_spatial_layers = 1;
vp9.first_frame_in_picture = true;
- vp9.end_of_picture = true;
vp9.spatial_layer_resolution_present = false;
vp9.inter_pic_predicted = !key_frame;
vp9.ss_data_available = key_frame;
@@ -1127,6 +1130,7 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() {
void RTCVideoEncoder::Impl::EncodeOneFrameWithNativeInput() {
DVLOG(3) << "Impl::EncodeOneFrameWithNativeInput()";
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(input_buffers_.IsEmpty() && input_buffers_free_.IsEmpty());
DCHECK(input_next_frame_);
// EncodeOneFrameWithNativeInput() may re-enter EncodeFrameFinished() if
@@ -1198,7 +1202,7 @@ bool RTCVideoEncoder::Impl::CreateBlackGpuMemoryBufferFrame(
auto gmb = gpu_factories_->CreateGpuMemoryBuffer(
natural_size, gfx::BufferFormat::YUV_420_BIPLANAR,
- gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE);
+ gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE);
if (!gmb || !gmb->Map()) {
black_gmb_frame_ = nullptr;
@@ -1300,9 +1304,9 @@ RTCVideoEncoder::~RTCVideoEncoder() {
DCHECK(!impl_.get());
}
-int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
- int32_t number_of_cores,
- size_t max_payload_size) {
+int32_t RTCVideoEncoder::InitEncode(
+ const webrtc::VideoCodec* codec_settings,
+ const webrtc::VideoEncoder::Settings& settings) {
DVLOG(1) << __func__ << " codecType=" << codec_settings->codecType
<< ", width=" << codec_settings->width
<< ", height=" << codec_settings->height
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
index eb400d95a9a..d4855b2dc2e 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
@@ -52,9 +52,8 @@ class PLATFORM_EXPORT RTCVideoEncoder : public webrtc::VideoEncoder {
// webrtc::VideoEncoder implementation. Tasks are posted to |impl_| using the
// appropriate VEA methods.
- int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
- int32_t number_of_cores,
- size_t max_payload_size) override;
+ int InitEncode(const webrtc::VideoCodec* codec_settings,
+ const webrtc::VideoEncoder::Settings& settings) override;
int32_t Encode(
const webrtc::VideoFrame& input_image,
const std::vector<webrtc::VideoFrameType>* frame_types) override;
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
index edeaaed446c..ddc064ea5c5 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
@@ -38,6 +38,11 @@ const uint16_t kInputFrameHeight = 234;
const uint16_t kInputFrameWidth = 345;
const uint16_t kStartBitrate = 100;
+const webrtc::VideoEncoder::Capabilities kVideoEncoderCapabilities(
+ /* loss_notification= */ false);
+const webrtc::VideoEncoder::Settings
+ kVideoEncoderSettings(kVideoEncoderCapabilities, 1, 12345);
+
class EncodedImageCallbackWrapper : public webrtc::EncodedImageCallback {
public:
using EncodedCallback = base::OnceCallback<void(
@@ -281,7 +286,8 @@ TEST_P(RTCVideoEncoderTest, CreateAndInitSucceeds) {
CreateEncoder(codec_type);
webrtc::VideoCodec codec = GetDefaultCodec();
codec.codecType = codec_type;
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
}
TEST_P(RTCVideoEncoderTest, RepeatedInitSucceeds) {
@@ -289,10 +295,12 @@ TEST_P(RTCVideoEncoderTest, RepeatedInitSucceeds) {
CreateEncoder(codec_type);
webrtc::VideoCodec codec = GetDefaultCodec();
codec.codecType = codec_type;
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
ExpectCreateInitAndDestroyVEA();
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
}
INSTANTIATE_TEST_SUITE_P(CodecProfiles,
@@ -304,7 +312,7 @@ TEST_F(RTCVideoEncoderTest, CreateAndInitSucceedsForTemporalLayer) {
webrtc::VideoCodec tl_codec = GetDefaultTemporalLayerCodec();
CreateEncoder(tl_codec.codecType);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
- rtc_encoder_->InitEncode(&tl_codec, 1, 12345));
+ rtc_encoder_->InitEncode(&tl_codec, kVideoEncoderSettings));
}
// Checks that WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE is returned when there is
@@ -314,7 +322,8 @@ TEST_F(RTCVideoEncoderTest, SoftwareFallbackAfterError) {
CreateEncoder(codec_type);
webrtc::VideoCodec codec = GetDefaultCodec();
codec.codecType = codec_type;
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
EXPECT_CALL(*mock_vea_, Encode(_, _))
.WillOnce(Invoke([this](scoped_refptr<media::VideoFrame>, bool) {
@@ -355,7 +364,8 @@ TEST_F(RTCVideoEncoderTest, EncodeScaledFrame) {
const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
CreateEncoder(codec_type);
webrtc::VideoCodec codec = GetDefaultCodec();
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
EXPECT_CALL(*mock_vea_, Encode(_, _))
.Times(2)
@@ -392,7 +402,8 @@ TEST_F(RTCVideoEncoderTest, PreserveTimestamps) {
const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
CreateEncoder(codec_type);
webrtc::VideoCodec codec = GetDefaultCodec();
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, 1, 12345));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
const uint32_t rtp_timestamp = 1234567;
const uint32_t capture_time_ms = 3456789;
@@ -424,7 +435,7 @@ TEST_F(RTCVideoEncoderTest, EncodeTemporalLayer) {
webrtc::VideoCodec tl_codec = GetDefaultTemporalLayerCodec();
CreateEncoder(tl_codec.codecType);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
- rtc_encoder_->InitEncode(&tl_codec, 1, 12345));
+ rtc_encoder_->InitEncode(&tl_codec, kVideoEncoderSettings));
size_t kNumEncodeFrames = 5u;
EXPECT_CALL(*mock_vea_, Encode(_, _))
.Times(kNumEncodeFrames)
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc b/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc
index 940a35a5f15..cf22786f6e6 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc
@@ -211,12 +211,14 @@ std::unique_ptr<webrtc::VideoEncoderFactory> CreateWebrtcVideoEncoderFactory(
}
std::unique_ptr<webrtc::VideoDecoderFactory> CreateWebrtcVideoDecoderFactory(
- media::GpuVideoAcceleratorFactories* gpu_factories) {
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* media_decoder_factory) {
std::unique_ptr<webrtc::VideoDecoderFactory> decoder_factory;
if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled() &&
Platform::Current()->IsWebRtcHWDecodingEnabled()) {
- decoder_factory = std::make_unique<RTCVideoDecoderFactory>(gpu_factories);
+ decoder_factory = std::make_unique<RTCVideoDecoderFactory>(
+ gpu_factories, media_decoder_factory);
}
return std::make_unique<DecoderAdapter>(std::move(decoder_factory));
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.h b/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.h
index 81d55b86ad9..3bf14c85b9a 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/video_codec_factory.h
@@ -10,6 +10,7 @@
#include "third_party/webrtc/api/video_codecs/video_encoder_factory.h"
namespace media {
+class DecoderFactory;
class GpuVideoAcceleratorFactories;
}
@@ -24,7 +25,8 @@ CreateWebrtcVideoEncoderFactory(
media::GpuVideoAcceleratorFactories* gpu_factories);
PLATFORM_EXPORT std::unique_ptr<webrtc::VideoDecoderFactory>
CreateWebrtcVideoDecoderFactory(
- media::GpuVideoAcceleratorFactories* gpu_factories);
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::DecoderFactory* media_decoder_factory);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
index 544ead652e4..84a9e477501 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
@@ -9,9 +9,10 @@
#include "base/callback_helpers.h"
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/location.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
#include "media/base/audio_timestamp_helper.h"
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
@@ -99,6 +100,9 @@ void WebRtcAudioSink::OnData(const media::AudioBus& audio_bus,
base::TimeTicks estimated_capture_time) {
// No thread check: OnData might be called on different threads (but not
// concurrently).
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("mediastream"),
+ "WebRtcAudioSink::OnData", "this", static_cast<void*>(this),
+ "frames", audio_bus.frames());
// TODO(crbug.com/1054769): Better to let |fifo_| handle the estimated capture
// time and let it return a corrected interpolated capture time to
@@ -131,6 +135,8 @@ void WebRtcAudioSink::OnSetFormat(const media::AudioParameters& params) {
void WebRtcAudioSink::DeliverRebufferedAudio(const media::AudioBus& audio_bus,
int frame_delay) {
DCHECK(params_.IsValid());
+ TRACE_EVENT1("audio", "WebRtcAudioSink::DeliverRebufferedAudio", "frames",
+ audio_bus.frames());
// TODO(miu): Why doesn't a WebRTC sink care about reference time passed to
// OnData(), and the |frame_delay| here? How is AV sync achieved otherwise?
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
index 8ecb8f9a1ae..d5e9f9baf54 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
@@ -64,10 +64,10 @@ gfx::Rect ScaleRectangle(const gfx::Rect& input_rect,
}
webrtc::VideoRotation GetFrameRotation(const media::VideoFrame* frame) {
- if (!frame->metadata()->rotation) {
+ if (!frame->metadata().transformation) {
return webrtc::kVideoRotation_0;
}
- switch (*frame->metadata()->rotation) {
+ switch (frame->metadata().transformation->rotation) {
case media::VIDEO_ROTATION_0:
return webrtc::kVideoRotation_0;
case media::VIDEO_ROTATION_90:
@@ -88,9 +88,11 @@ namespace blink {
WebRtcVideoTrackSource::WebRtcVideoTrackSource(
bool is_screencast,
absl::optional<bool> needs_denoising,
- media::VideoCaptureFeedbackCB callback)
+ media::VideoCaptureFeedbackCB callback,
+ media::GpuVideoAcceleratorFactories* gpu_factories)
: AdaptedVideoTrackSource(/*required_alignment=*/1),
- scaled_frame_pool_(new WebRtcVideoFrameAdapter::BufferPoolOwner()),
+ adapter_resources_(
+ new WebRtcVideoFrameAdapter::SharedResources(gpu_factories)),
is_screencast_(is_screencast),
needs_denoising_(needs_denoising),
callback_(callback) {
@@ -141,12 +143,7 @@ void WebRtcVideoTrackSource::OnFrameCaptured(
scoped_refptr<media::VideoFrame> frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
TRACE_EVENT0("media", "WebRtcVideoSource::OnFrameCaptured");
- if (!(frame->IsMappable() && (frame->format() == media::PIXEL_FORMAT_I420 ||
- frame->format() == media::PIXEL_FORMAT_I420A ||
- frame->format() == media::PIXEL_FORMAT_NV12)) &&
- !(frame->storage_type() ==
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) &&
- !frame->HasTextures()) {
+ if (!WebRtcVideoFrameAdapter::IsFrameAdaptable(frame.get())) {
// Since connecting sources and sinks do not check the format, we need to
// just ignore formats that we can not handle.
LOG(ERROR) << "We cannot send frame with storage type: "
@@ -162,9 +159,8 @@ void WebRtcVideoTrackSource::OnFrameCaptured(
// rtc::AdaptedVideoTrackSource::OnFrame(). This region is going to be
// relative to the coded frame data, i.e.
// [0, 0, frame->coded_size().width(), frame->coded_size().height()].
- base::Optional<int> capture_counter = frame->metadata()->capture_counter;
- base::Optional<gfx::Rect> update_rect =
- frame->metadata()->capture_update_rect;
+ base::Optional<int> capture_counter = frame->metadata().capture_counter;
+ base::Optional<gfx::Rect> update_rect = frame->metadata().capture_update_rect;
const bool has_valid_update_rect =
update_rect.has_value() && capture_counter.has_value() &&
@@ -321,7 +317,7 @@ void WebRtcVideoTrackSource::DeliverFrame(
webrtc::VideoFrame::Builder()
.set_video_frame_buffer(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- frame, scaled_frame_pool_))
+ frame, adapter_resources_))
.set_rotation(GetFrameRotation(frame.get()))
.set_timestamp_us(timestamp_us);
if (update_rect) {
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
index a0ca10b1bc3..dc61867b28b 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
@@ -15,6 +15,10 @@
#include "third_party/webrtc/media/base/adapted_video_track_source.h"
#include "third_party/webrtc/rtc_base/timestamp_aligner.h"
+namespace media {
+class GpuVideoAcceleratorFactories;
+}
+
namespace blink {
// This class implements webrtc's VideoTrackSourceInterface. To pass frames down
@@ -36,7 +40,8 @@ class PLATFORM_EXPORT WebRtcVideoTrackSource
WebRtcVideoTrackSource(bool is_screencast,
absl::optional<bool> needs_denoising,
- media::VideoCaptureFeedbackCB callback);
+ media::VideoCaptureFeedbackCB callback,
+ media::GpuVideoAcceleratorFactories* gpu_factories);
~WebRtcVideoTrackSource() override;
void SetCustomFrameAdaptationParamsForTesting(
@@ -71,7 +76,7 @@ class PLATFORM_EXPORT WebRtcVideoTrackSource
// |thread_checker_| is bound to the libjingle worker thread.
THREAD_CHECKER(thread_checker_);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> scaled_frame_pool_;
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> adapter_resources_;
// State for the timestamp translation.
rtc::TimestampAligner timestamp_aligner_;
diff --git a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
index f8586e9189f..f2f8c6542f1 100644
--- a/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
+++ b/chromium/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
@@ -6,6 +6,7 @@
#include "base/callback_helpers.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/strcat.h"
#include "base/test/task_environment.h"
#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -35,14 +36,16 @@ class MockVideoSink : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
};
class WebRtcVideoTrackSourceTest
- : public ::testing::TestWithParam<media::VideoFrame::StorageType> {
+ : public ::testing::TestWithParam<
+ std::tuple<media::VideoFrame::StorageType, media::VideoPixelFormat>> {
public:
WebRtcVideoTrackSourceTest()
: track_source_(new rtc::RefCountedObject<WebRtcVideoTrackSource>(
/*is_screencast=*/false,
/*needs_denoising=*/absl::nullopt,
base::BindRepeating(&WebRtcVideoTrackSourceTest::ProcessFeedback,
- base::Unretained(this)))) {
+ base::Unretained(this)),
+ /*gpu_factories=*/nullptr)) {
track_source_->AddOrUpdateSink(&mock_sink_, rtc::VideoSinkWants());
}
@@ -57,9 +60,10 @@ class WebRtcVideoTrackSourceTest
void SendTestFrame(const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
- media::VideoFrame::StorageType storage_type) {
- scoped_refptr<media::VideoFrame> frame =
- CreateTestFrame(coded_size, visible_rect, natural_size, storage_type);
+ media::VideoFrame::StorageType storage_type,
+ media::VideoPixelFormat pixel_format) {
+ scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
+ coded_size, visible_rect, natural_size, storage_type, pixel_format);
track_source_->OnFrameCaptured(frame);
}
@@ -68,26 +72,27 @@ class WebRtcVideoTrackSourceTest
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
media::VideoFrame::StorageType storage_type,
+ media::VideoPixelFormat pixel_format,
int max_pixels,
float max_framerate) {
- scoped_refptr<media::VideoFrame> frame =
- CreateTestFrame(coded_size, visible_rect, natural_size, storage_type);
+ scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
+ coded_size, visible_rect, natural_size, storage_type, pixel_format);
track_source_->OnFrameCaptured(frame);
EXPECT_EQ(feedback_.max_pixels, max_pixels);
EXPECT_EQ(feedback_.max_framerate_fps, max_framerate);
}
- void SendTestFrameWithUpdateRect(
- const gfx::Size& coded_size,
- const gfx::Rect& visible_rect,
- const gfx::Size& natural_size,
- int capture_counter,
- const gfx::Rect& update_rect,
- media::VideoFrame::StorageType storage_type) {
- scoped_refptr<media::VideoFrame> frame =
- CreateTestFrame(coded_size, visible_rect, natural_size, storage_type);
- frame->metadata()->capture_counter = capture_counter;
- frame->metadata()->capture_update_rect = update_rect;
+ void SendTestFrameWithUpdateRect(const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ int capture_counter,
+ const gfx::Rect& update_rect,
+ media::VideoFrame::StorageType storage_type,
+ media::VideoPixelFormat pixel_format) {
+ scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
+ coded_size, visible_rect, natural_size, storage_type, pixel_format);
+ frame->metadata().capture_counter = capture_counter;
+ frame->metadata().capture_update_rect = update_rect;
track_source_->OnFrameCaptured(frame);
}
@@ -136,11 +141,30 @@ class WebRtcVideoTrackSourceTest
media::VideoFrameFeedback feedback_;
};
+namespace {
+std::vector<WebRtcVideoTrackSourceTest::ParamType> TestParams() {
+ std::vector<WebRtcVideoTrackSourceTest::ParamType> test_params;
+ // All formats for owned memory.
+ for (media::VideoPixelFormat format :
+ WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
+ test_params.emplace_back(
+ media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY, format);
+ }
+ test_params.emplace_back(
+ media::VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ test_params.emplace_back(media::VideoFrame::STORAGE_OPAQUE,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ return test_params;
+}
+} // namespace
+
TEST_P(WebRtcVideoTrackSourceTest, CropFrameTo640360) {
const gfx::Size kCodedSize(640, 480);
const gfx::Rect kVisibleRect(0, 60, 640, 360);
const gfx::Size kNaturalSize(640, 360);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_KeepAsIs(kNaturalSize));
@@ -149,7 +173,8 @@ TEST_P(WebRtcVideoTrackSourceTest, CropFrameTo640360) {
EXPECT_EQ(kNaturalSize.width(), frame.width());
EXPECT_EQ(kNaturalSize.height(), frame.height());
}));
- SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type);
+ SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type,
+ pixel_format);
}
TEST_P(WebRtcVideoTrackSourceTest, SetsFeedback) {
@@ -158,7 +183,8 @@ TEST_P(WebRtcVideoTrackSourceTest, SetsFeedback) {
const gfx::Size kNaturalSize(640, 360);
const gfx::Size kScaleToSize = gfx::Size(320, 180);
const float k5Fps = 5.0;
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
rtc::VideoSinkWants sink_wants;
sink_wants.max_pixel_count = kScaleToSize.GetArea();
@@ -167,14 +193,16 @@ TEST_P(WebRtcVideoTrackSourceTest, SetsFeedback) {
EXPECT_CALL(mock_sink_, OnFrame(_));
SendTestFrameAndVerifyFeedback(kCodedSize, kVisibleRect, kNaturalSize,
- storage_type, kScaleToSize.GetArea(), k5Fps);
+ storage_type, pixel_format,
+ kScaleToSize.GetArea(), k5Fps);
}
TEST_P(WebRtcVideoTrackSourceTest, CropFrameTo320320) {
const gfx::Size kCodedSize(640, 480);
const gfx::Rect kVisibleRect(80, 0, 480, 480);
const gfx::Size kNaturalSize(320, 320);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_KeepAsIs(kNaturalSize));
@@ -183,14 +211,16 @@ TEST_P(WebRtcVideoTrackSourceTest, CropFrameTo320320) {
EXPECT_EQ(kNaturalSize.width(), frame.width());
EXPECT_EQ(kNaturalSize.height(), frame.height());
}));
- SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type);
+ SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type,
+ pixel_format);
}
TEST_P(WebRtcVideoTrackSourceTest, Scale720To640360) {
const gfx::Size kCodedSize(1280, 720);
const gfx::Rect kVisibleRect(0, 0, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_KeepAsIs(kNaturalSize));
@@ -199,14 +229,16 @@ TEST_P(WebRtcVideoTrackSourceTest, Scale720To640360) {
EXPECT_EQ(kNaturalSize.width(), frame.width());
EXPECT_EQ(kNaturalSize.height(), frame.height());
}));
- SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type);
+ SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type,
+ pixel_format);
}
TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
const gfx::Size kCodedSize(640, 480);
const gfx::Rect kVisibleRect(0, 0, 640, 480);
const gfx::Size kNaturalSize(640, 480);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_KeepAsIs(kNaturalSize));
@@ -220,7 +252,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
}));
int capture_counter = 101; // arbitrary absolute value
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- capture_counter, kUpdateRect1, storage_type);
+ capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Update rect for second frame should get passed along.
@@ -229,7 +262,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
ExpectUpdateRectEquals(kUpdateRect1, frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect1, storage_type);
+ ++capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Simulate the next frame getting dropped
@@ -238,7 +272,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
const gfx::Rect kUpdateRect2(2, 3, 4, 5);
EXPECT_CALL(mock_sink_, OnFrame(_)).Times(0);
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect2, storage_type);
+ ++capture_counter, kUpdateRect2, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// The |update_rect| for the next frame is expected to contain the union
@@ -254,7 +289,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
ExpectUpdateRectEquals(expected_update_rect, frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect3, storage_type);
+ ++capture_counter, kUpdateRect3, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Simulate a gap in |capture_counter|. This is expected to cause the whole
@@ -266,7 +302,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
ExpectUpdateRectEquals(kVisibleRect, frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect4, storage_type);
+ ++capture_counter, kUpdateRect4, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Important edge case (expected to be fairly common): An empty update rect
@@ -278,7 +315,7 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
++capture_counter, kEmptyRectWithZeroOrigin,
- storage_type);
+ storage_type, pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
const gfx::Rect kEmptyRectWithNonZeroOrigin(10, 20, 0, 0);
@@ -288,7 +325,7 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
++capture_counter, kEmptyRectWithNonZeroOrigin,
- storage_type);
+ storage_type, pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// A frame without a CAPTURE_COUNTER and CAPTURE_UPDATE_RECT is treated as the
@@ -297,7 +334,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithNoTransform) {
.WillOnce(Invoke([kVisibleRect](const webrtc::VideoFrame& frame) {
ExpectUpdateRectEquals(kVisibleRect, frame.update_rect());
}));
- SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type);
+ SendTestFrame(kCodedSize, kVisibleRect, kNaturalSize, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
}
@@ -305,7 +343,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
const gfx::Size kCodedSize(640, 480);
const gfx::Rect kVisibleRect(100, 50, 200, 80);
const gfx::Size kNaturalSize = gfx::Size(200, 80);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_KeepAsIs(kNaturalSize));
@@ -319,7 +358,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
}));
int capture_counter = 101; // arbitrary absolute value
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- capture_counter, kUpdateRect1, storage_type);
+ capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Update rect for second frame should get passed along.
@@ -332,7 +372,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
ExpectUpdateRectEquals(expected_update_rect, frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect1, storage_type);
+ ++capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Update rect outside crop region.
@@ -342,7 +383,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
EXPECT_TRUE(frame.update_rect().IsEmpty());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect2, storage_type);
+ ++capture_counter, kUpdateRect2, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// Update rect partly overlapping crop region.
@@ -355,7 +397,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect3, storage_type);
+ ++capture_counter, kUpdateRect3, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// When crop origin changes, the whole frame is expected to be marked as
@@ -368,7 +411,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect2, kNaturalSize,
- ++capture_counter, kUpdateRect1, storage_type);
+ ++capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// When crop size changes, the whole frame is expected to be marked as
@@ -382,7 +426,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithCropFromUpstream) {
frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect3, kNaturalSize,
- ++capture_counter, kUpdateRect1, storage_type);
+ ++capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
}
@@ -391,7 +436,12 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
const gfx::Rect kVisibleRect(100, 50, 200, 80);
const gfx::Size kNaturalSize = gfx::Size(200, 80);
const gfx::Size kScaleToSize = gfx::Size(120, 50);
- const media::VideoFrame::StorageType storage_type = GetParam();
+ const media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ const media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
+ if (storage_type == media::VideoFrame::STORAGE_OPAQUE) {
+ // Texture has no cropping support yet http://crbug/503653.
+ return;
+ }
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_Scale(kNaturalSize, kScaleToSize));
@@ -404,7 +454,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
}));
int capture_counter = 101; // arbitrary absolute value
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- capture_counter, kUpdateRect1, storage_type);
+ capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
// When scaling is applied and UPDATE_RECT is not empty, we scale the
@@ -415,7 +466,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
ExpectUpdateRectEquals(gfx::Rect(10, 10, 100, 30), frame.update_rect());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, kUpdateRect1, storage_type);
+ ++capture_counter, kUpdateRect1, storage_type,
+ pixel_format);
// When UPDATE_RECT is empty, we expect to deliver an empty UpdateRect even if
// scaling is applied.
@@ -424,7 +476,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
EXPECT_TRUE(frame.update_rect().IsEmpty());
}));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, gfx::Rect(), storage_type);
+ ++capture_counter, gfx::Rect(), storage_type,
+ pixel_format);
// When UPDATE_RECT is empty, but the scaling has changed, we expect to
// deliver no known update_rect.
@@ -436,7 +489,8 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
track_source_->SetCustomFrameAdaptationParamsForTesting(
FrameAdaptation_Scale(kNaturalSize, kScaleToSize2));
SendTestFrameWithUpdateRect(kCodedSize, kVisibleRect, kNaturalSize,
- ++capture_counter, gfx::Rect(), storage_type);
+ ++capture_counter, gfx::Rect(), storage_type,
+ pixel_format);
Mock::VerifyAndClearExpectations(&mock_sink_);
}
@@ -444,7 +498,11 @@ TEST_P(WebRtcVideoTrackSourceTest, UpdateRectWithScaling) {
INSTANTIATE_TEST_SUITE_P(
WebRtcVideoTrackSourceTest,
WebRtcVideoTrackSourceTest,
- testing::Values(media::VideoFrame::STORAGE_OWNED_MEMORY,
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER));
+ testing::ValuesIn(TestParams()),
+ [](const auto& info) {
+ return base::StrCat(
+ {media::VideoFrame::StorageTypeToString(std::get<0>(info.param)), "_",
+ media::VideoPixelFormatToString(std::get<1>(info.param))});
+ });
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA b/chromium/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA
new file mode 100644
index 00000000000..0644197c4db
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Privacy>Fingerprinting"
+}
+team_email: "privacy-sandbox-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/privacy_budget/OWNERS b/chromium/third_party/blink/renderer/platform/privacy_budget/OWNERS
index 4c6c22d92dc..dc548692bc4 100644
--- a/chromium/third_party/blink/renderer/platform/privacy_budget/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/privacy_budget/OWNERS
@@ -1,4 +1 @@
file://third_party/blink/public/common/privacy_budget/OWNERS
-
-# TEAM: privacy-sandbox-dev@chromium.org
-# COMPONENT: Privacy>Fingerprinting \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0b89a514c3a..c455ee74204 100644
--- a/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/chromium/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -116,6 +116,10 @@
status: "stable",
},
{
+ name: "AccessibilityAriaVirtualContent",
+ status: "experimental",
+ },
+ {
name: "AccessibilityExposeDisplayNone",
status: "test",
},
@@ -135,7 +139,7 @@
},
{
name: "AddEventListenerAbortSignal",
- status: "experimental",
+ status: "stable",
},
{
name: "AddressSpace",
@@ -183,6 +187,10 @@
origin_trial_feature_name: "AppCache",
},
{
+ name: "AriaTouchPassthrough",
+ status: "experimental",
+ },
+ {
name: "AudioOutputDevices",
// Android does not yet support switching of audio output devices
status: {"Android": "", "default": "stable"},
@@ -225,10 +233,6 @@
settable_from_internals: true,
},
{
- name: "AzimuthAltitude",
- status: "stable",
- },
- {
name: "BackForwardCache",
},
{
@@ -322,6 +326,10 @@
status: "experimental",
},
{
+ name: "CanvasFormattedText",
+ status: "experimental",
+ },
+ {
name: "CanvasHitRegion",
status: "experimental",
},
@@ -330,6 +338,13 @@
status: "experimental",
},
{
+ name: "CapabilityDelegation",
+ implied_by: ["CapabilityDelegationPaymentRequest"],
+ },
+ {
+ name: "CapabilityDelegationPaymentRequest",
+ },
+ {
name: "CaptureTimeInCsrc",
status: "stable",
},
@@ -338,6 +353,9 @@
status: "experimental",
},
{
+ name: "ClickPointerEventIntegerCoordinates",
+ },
+ {
name: "ClickRetargetting",
status: "experimental",
},
@@ -346,6 +364,10 @@
status: "experimental",
},
{
+ name: "COLRV1Fonts",
+ status: "experimental",
+ },
+ {
name: "CompositeAfterPaint",
},
{
@@ -357,21 +379,27 @@
},
{
name: "CompositeRelativeKeyframes",
- status: "experimental",
+ // Controlled by base::Feature::kCompositeRelativeKeyframes.
},
{
name: "CompositeSVG",
- status: "test"
+ status: "stable"
},
{
name: "CompositingOptimizations",
- status: "experimental"
+ status: "stable"
},
{
name: "ComputedAccessibilityInfo",
status: "experimental",
},
{
+ name: "ComputePressure",
+ // No status because this blink runtime feature doesn't work by itself.
+ // It's controlled by the corresponding Chromium feature which needs to
+ // be enabled to make the whole feature work.
+ },
+ {
name: "ConsolidatedMovementXY",
},
{
@@ -407,14 +435,6 @@
status: "experimental",
},
{
- name: "CookieStoreDocument",
- status: "stable",
- },
- {
- name: "CookieStoreWorker",
- status: "stable",
- },
- {
name: "CookiesWithoutSameSiteMustBeSecure",
status: "test",
},
@@ -439,24 +459,61 @@
status: "experimental",
},
{
+ name: "CSSAspectRatioInterpolation",
+ status: "stable",
+ },
+ {
name: "CSSAspectRatioProperty",
status: "stable",
},
{
// https://drafts.csswg.org/css-counter-styles-3
name: "CSSAtRuleCounterStyle",
+ status: "test",
+ },
+ {
+ // Whether <image> values are allowed as counter style <symbol>
+ name: "CSSAtRuleCounterStyleImageSymbols",
+ depends_on: ["CSSAtRuleCounterStyle"]
+ },
+ {
+ // https://github.com/w3c/csswg-drafts/issues/5693
+ // Experimental support of @counter-style rules in shadow DOM.
+ name: "CSSAtRuleCounterStyleInShadowDOM",
+ depends_on: ["CSSAtRuleCounterStyle"],
+ status: "test",
},
{
name: "CSSCalcAsInt",
status: "test",
},
{
+ // https://github.com/DevSDK/calc-infinity-and-NaN/blob/master/explainer.md
+ name: "CSSCalcInfinityAndNaN",
+ status: "test",
+ },
+ {
+ // Support case-sensitive attribute selector modifier
+ // https://drafts.csswg.org/selectors-4/#attribute-case
+ name: "CSSCaseSensitiveSelector",
+ status: "test",
+ },
+ {
// When the color-scheme is supported via the CSS color-scheme property
// (CSSColorScheme) or the meta tag (MetaColorScheme), the only UA
// rendering change is for the canvas background and the :root element
// color property. Enabling this runtime flag will enable dark UA
// rendering for form controls, scrollbars, etc.
name: "CSSColorSchemeUARendering",
+ status: "stable",
+ },
+ {
+ name: "CSSContainerQueries",
+ },
+ {
+ // Support for contain:inline-size and contain:block-size
+ name: "CSSContainSize1D",
+ implied_by: ["CSSContainerQueries"]
},
{
// The main content-visibility feature.
@@ -482,20 +539,13 @@
status: "experimental",
},
{
- // Experimental @font-face descriptor advance-override.
- // Not standardized yet, and subject to changes.
+ // @font-face descriptor advance-override.
+ // https://drafts.csswg.org/css-fonts-5/#descdef-font-face-advance-override
name: "CSSFontFaceAdvanceOverride",
status: "test",
depends_on: ["CSSFontMetricsOverride"],
},
{
- // Experimental @font-face descriptor advance-proportional-override.
- // Not standardized yet, and subject to changes.
- name: "CSSFontFaceAdvanceProportionalOverride",
- status: "test",
- depends_on: ["CSSFontMetricsOverride"],
- },
- {
// @font-face descriptors ascent-override, descent-override and
// line-gap-override.
// https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc
@@ -518,14 +568,6 @@
status: "experimental",
},
{
- // Change ScopedStyleResolve and StyleEngine to use the already stored
- // StyleSheetCollection to find @keyframes rules instead of creating their
- // own hashmaps, so that we can save memory when there are web components
- // with @keyframes rules in their stylesheets.
- name: "CSSKeyframesMemoryReduction",
- status: "test",
- },
- {
name: "CSSLayoutAPI",
status: "experimental",
},
@@ -542,15 +584,6 @@
status: "experimental",
},
{
- name: "CSSMarkerPseudoElement",
- status: "stable",
- implied_by: ["CSSMarkerNestedPseudoElement"],
- },
- // Enables dependency support for the MatchedPropertiesCache.
- {
- name: "CSSMatchedPropertiesCacheDependencies",
- },
- {
name: "CSSMathDepth",
status: "experimental",
implied_by: ["MathMLCore"],
@@ -596,17 +629,15 @@
depends_on: ["PictureInPictureAPI"],
},
{
- name: "CSSPseudoIs",
- status: "stable",
+ name: "CSSPseudoDir",
+ status: "experimental",
},
{
- name: "CSSPseudoWhere",
+ name: "CSSPseudoIs",
status: "stable",
},
{
- // Perform partial layout invalidation on web font loading.
- // See https://crbug.com/441925 and https://bit.ly/35JjPmq for details.
- name: "CSSReducedFontLoadingLayoutInvalidations",
+ name: "CSSPseudoWhere",
status: "stable",
},
// Scrollbar styling.
@@ -628,6 +659,17 @@
name: "CSSSnapSize",
status: "experimental",
},
+ {
+ // Support for CSS ::spelling-error, ::grammar-error, and the
+ // spelling-error and grammar-error values in text-decoration-line.
+ //
+ // https://drafts.csswg.org/css-pseudo-4/#selectordef-spelling-error
+ // https://drafts.csswg.org/css-pseudo-4/#selectordef-grammar-error
+ // https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error
+ // https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error
+ name: "CSSSpellingGrammarErrors",
+ status: "test",
+ },
// Make system color keywords compute to themselves.
// https://github.com/w3c/csswg-drafts/issues/3847
{
@@ -638,7 +680,7 @@
// Support for ::target-text pseudo element as specified in
// https://drafts.csswg.org/css-pseudo/#selectordef-target-text
name: "CSSTargetTextPseudoElement",
- status: "test",
+ status: "stable",
},
// Support for @property rules.
{
@@ -657,6 +699,9 @@
status: "test",
},
{
+ name: "CullRectUpdate",
+ },
+ {
name: "CustomElementDefaultStyle",
status: "experimental",
},
@@ -668,7 +713,7 @@
},
{
name: "CustomStatePseudoClass",
- status: "experimental",
+ status: "stable",
},
{
name: "Database",
@@ -681,11 +726,11 @@
},
{
name: "DecodeJpeg420ImagesToYUV",
- status: "test",
+ status: "stable",
},
{
name: "DecodeLossyWebPImagesToYUV",
- status: "test",
+ status: "stable",
},
{
name: "DelayAsyncScriptExecutionUntilFinishedParsing",
@@ -702,9 +747,13 @@
status: "experimental",
},
{
+ name: "DeviceInterface",
+ status: "experimental",
+ },
+ {
name: "DigitalGoods",
origin_trial_feature_name: "DigitalGoods",
- origin_trial_os: ["android"],
+ origin_trial_os: ["android", "chromeos"],
status: {
"Android": "experimental",
"ChromeOS": "experimental",
@@ -732,6 +781,13 @@
status: "experimental",
},
{
+ name: "DisplayCapturePermissionPolicy",
+ origin_trial_feature_name: "GetCurrentBrowsingContextMedia",
+ // TODO(crbug.com/1150788): Implement for Android when this is applied
+ // to getDisplayMedia.
+ status: {"Android": "", "default": "experimental"},
+ },
+ {
name: "DisplayCutoutAPI",
settable_from_internals: true,
},
@@ -743,15 +799,33 @@
},
{
name: "DocumentPolicy",
- origin_trial_feature_name: "DocumentPolicy",
status: "stable",
},
+ // Enables the ability to use Document Policy header to control feature
+ // DocumentDomain.
+ {
+ name: "DocumentPolicyDocumentDomain",
+ status: "experimental",
+ depends_on: ["DocumentPolicy"],
+ },
{
name: "DocumentPolicyNegotiation",
origin_trial_feature_name: "DocumentPolicyNegotiation",
status: "experimental",
depends_on: ['DocumentPolicy']
},
+ // Enables the ability to use Document Policy header to control feature
+ // SyncXHR.
+ {
+ name: "DocumentPolicySyncXHR",
+ status: "experimental",
+ depends_on: ["DocumentPolicy"],
+ },
+ {
+ // Document transitions, including shared element transitions.
+ // See https://github.com/WICG/proposals/issues/12.
+ name: "DocumentTransition"
+ },
{
name: "DocumentWrite",
},
@@ -763,7 +837,7 @@
{
// http://crbug.com/707656 content editable in LayoutNG.
name: "EditingNG",
- status: "experimental",
+ status: "stable",
},
{
name: "EncryptedMediaEncryptionSchemeQuery",
@@ -817,12 +891,9 @@
origin_trial_feature_name: "ExperimentalJSProfiler",
status: "experimental"
},
- // Enables a set of features intended to help improve web developer
- // productivity, by restricting the use of potentially problematic web-
- // platform behaviors, as well as adding new high-level APIs for common
- // development patterns.
{
- name: "ExperimentalProductivityFeatures",
+ name: "ExperimentalPolicies",
+ depends_on: ["DocumentPolicy"],
status: "experimental"
},
{
@@ -833,6 +904,10 @@
name: "ExtraWebGLVideoTextureMetadata",
},
{
+ name: "EyeDropperAPI",
+ status: "test",
+ },
+ {
name: "FaceDetector",
status: "experimental",
},
@@ -841,13 +916,7 @@
status: "stable",
},
{
- name: "FeaturePolicyForSandbox",
- status: "experimental",
- },
- {
name: "FeaturePolicyReporting",
- implied_by: ["ExperimentalProductivityFeatures"],
- origin_trial_feature_name: "FeaturePolicyReporting",
status: "experimental"
},
{
@@ -856,13 +925,14 @@
{
name: "FetchUploadStreaming",
origin_trial_feature_name: "FetchUploadStreaming",
+ origin_trial_allows_third_party: true,
status: "experimental",
},
{
// Also enabled when blink::features::kFileHandlingAPI is overridden
// on the command line (or via chrome://flags).
name: "FileHandling",
- depends_on: ["NativeFileSystem"],
+ depends_on: ["FileSystemAccess"],
status: {"Android": "test", "default": "experimental"},
origin_trial_feature_name: "FileHandling",
origin_trial_os: ["win", "mac", "linux", "chromeos"],
@@ -872,8 +942,13 @@
status: "stable",
},
{
- name: "FlexAspectRatio",
- status: "stable",
+ name: "FileSystemAccess",
+ status: {"Android": "test", "default": "stable"},
+ },
+ {
+ // In-development features for the File System Access API.
+ name: "FileSystemAccessAPIExperimental",
+ status: "experimental",
},
{
name: "FocuslessSpatialNavigation",
@@ -887,10 +962,12 @@
// be enabled to make the whole feature work.
},
{
- name: "FontAccessChooser",
+ name: "FontAccessPersistent",
// TODO(crbug.com/1000486): Add when the Origin Trial dependency bug is fixed.
// depends_on: ["FontAccess"],
- status: "experimental",
+ // No status because this blink runtime feature doesn't work by itself.
+ // It's controlled by the corresponding Chromium feature which needs to
+ // be enabled to make the whole feature work.
},
{
name: "FontSrcLocalMatching",
@@ -900,9 +977,7 @@
// For simulating Android's overlay fullscreen video in web tests on Linux.
{
name: "ForcedColors",
- // No status because this blink runtime feature doesn't work by itself.
- // It's controlled by the corresponding Chromium feature which needs to
- // be enabled to make the whole feature work.
+ status: "stable",
},
{
name: "ForceDeferScriptIntervention",
@@ -913,10 +988,6 @@
name:"ForceEagerMeasureMemory",
},
{
- name: "ForceLoadAtTop",
- origin_trial_feature_name: "ForceLoadAtTop",
- },
- {
name: "ForceOverlayFullscreenVideo",
},
{
@@ -928,6 +999,7 @@
},
{
name: "FractionalScrollOffsets",
+ status: "experimental",
},
{
name: "FreezeFramesOnVisibility",
@@ -939,8 +1011,9 @@
},
{
name: "GetCurrentBrowsingContextMedia",
+ origin_trial_feature_name: "GetCurrentBrowsingContextMedia",
depends_on: ["GetDisplayMedia"],
- status: {"Android": "", "default": "test"},
+ status: {"Android": "", "default": "experimental"},
},
{
name: "GetDisplayMedia",
@@ -950,10 +1023,18 @@
},
},
{
+ name: "GravitySensor",
+ status: "experimental",
+ },
+ {
name: "GroupEffect",
status: "test",
},
{
+ name: "HandwritingRecognition",
+ status: "experimental",
+ },
+ {
name: "HrefTranslate",
depends_on: ["TranslateService"],
origin_trial_feature_name: "HrefTranslate",
@@ -966,7 +1047,12 @@
status: "test",
},
{
- name: "IDBObserver",
+ name: "HTMLPopupElement",
+ status: "experimental",
+ implied_by: ["HTMLSelectMenuElement"],
+ },
+ {
+ name: "HTMLSelectMenuElement",
status: "experimental",
},
{
@@ -987,16 +1073,13 @@
status: "experimental",
},
{
- name: "ImageOrientation",
- status: "stable",
- },
- {
name: "ImplicitRootScroller",
settable_from_internals: true,
+ status: {"Android": "stable"},
},
{
name: "ImportMaps",
- implied_by: ["ExperimentalProductivityFeatures"],
+ status: "stable"
},
{
name: "InertAttribute",
@@ -1014,6 +1097,11 @@
{
name: "InterestCohortAPI",
origin_trial_feature_name: "InterestCohortAPI",
+ origin_trial_allows_third_party: true,
+ },
+ {
+ name: "InterestCohortFeaturePolicy",
+ status: "experimental",
},
{
name: "IntersectionObserverDocumentScrollingElementRoot",
@@ -1026,6 +1114,10 @@
status: "stable",
},
{
+ name: "KeyboardAccessibleTooltip",
+ status: "experimental",
+ },
+ {
name: "KeyboardFocusableScrollers",
status: "experimental",
},
@@ -1043,7 +1135,7 @@
// provides a convenient way for testing legacy layout code path in blink
// unit tests.
name: "LayoutNG",
- implied_by: ["LayoutNGGrid", "BidiCaretAffinity", "LayoutNGTable"],
+ implied_by: ["LayoutNGGrid", "BidiCaretAffinity", "CSSContainerQueries"],
status: "stable",
},
{
@@ -1051,48 +1143,42 @@
implied_by: ["LayoutNGPrinting"],
},
{
- name: "LayoutNGFieldset",
- depends_on: ["LayoutNG"],
- status: "stable",
- },
- {
- name: "LayoutNGForControls",
- depends_on: ["LayoutNG"],
- status: "stable",
- },
- {
- name: "LayoutNGFragmentItem",
- implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFragmentTraversal", "EditingNG"],
- status: "stable",
- },
- {
// Traverse the fragment tree when painting and hit-testing, instead of
// the layout object tree.
name: "LayoutNGFragmentTraversal",
implied_by: ["LayoutNGBlockFragmentation"],
},
{
+ // Full support for PositionForPoint in NGPhysicalFragment. Without this
+ // enabled, we'll typically fall back to legacy code for block children.
+ name: "LayoutNGFullPositionForPoint",
+ implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFragmentTraversal"],
+ },
+ {
name: "LayoutNGGrid",
},
{
name: "LayoutNGLayoutOverflow",
- depends_on: ["LayoutNG", "LayoutNGFragmentItem"],
+ depends_on: ["LayoutNG"],
status: "stable",
},
{
name: "LayoutNGPrinting",
},
{
+ name: "LayoutNGReplaced",
+ depends_on: ["LayoutNG"]
+ },
+ {
name: "LayoutNGTable",
+ depends_on: ["LayoutNG"],
+ status: "test"
},
{
name: "LayoutNGTextControl",
depends_on: ["EditingNG"],
- status: "experimental",
- },
- {
- name: "LayoutNGWebkitBox",
- status: "stable",
+ // In Chrome, the flag is managed by Finch.
+ status: "test",
},
{
name: "LazyFrameLoading",
@@ -1133,8 +1219,7 @@
},
{
name:"MeasureMemory",
- origin_trial_feature_name: "MeasureMemory",
- status:"experimental",
+ status:"stable",
},
{
name: "MediaCapabilitiesDynamicRange",
@@ -1160,10 +1245,6 @@
name: "MediaCaptureDepthVideoKind",
status: "experimental",
},
- {
- name: "MediaCapturePanTilt",
- status: "stable",
- },
// Set to reflect the MediaCastOverlayButton feature.
{
name: "MediaCastOverlayButton",
@@ -1220,6 +1301,10 @@
status: "experimental",
},
{
+ name: "MediaSourceExtensionsForWebCodecs",
+ status: "experimental",
+ },
+ {
name: "MediaSourceInWorkers",
status: "experimental",
},
@@ -1238,6 +1323,7 @@
{
name: "MediaStreamInsertableStreams",
status: "experimental",
+ origin_trial_feature_name: "WebCodecs"
},
// This is enabled by default on Windows only. The only part that's
// "experimental" is the support on other platforms.
@@ -1250,6 +1336,10 @@
name: "MobileLayoutTheme",
},
{
+ name: "ModalCloseWatcher",
+ status: "experimental",
+ },
+ {
name: "ModuleServiceWorker",
status: "test",
},
@@ -1277,19 +1367,6 @@
status: "stable",
},
{
- // Also enabled when blink::features::kNativeFileSystemAPI is overridden
- // on the command line (or via chrome://flags).
- name: "NativeFileSystem",
- status: {"Android": "test", "default": "stable"},
- // TODO(mek): Remove origin trial integration.
- origin_trial_feature_name: "NativeFileSystem2",
- origin_trial_os: ["win", "mac", "linux", "chromeos"],
- },
- {
- name: "NativeIO",
- status: "experimental",
- },
- {
name: "NavigatorContentUtils",
// Android does not yet support NavigatorContentUtils.
status: {"Android": "", "default": "stable"},
@@ -1362,8 +1439,7 @@
},
{
name: "OriginIsolationHeader",
- origin_trial_feature_name: "OriginIsolationHeader",
- status: "experimental",
+ status: "stable",
},
{
name: "OriginPolicy",
@@ -1422,7 +1498,7 @@
},
{
name: "OverflowClip",
- status: "test",
+ status: "stable",
},
{
name: "OverscrollCustomization",
@@ -1450,10 +1526,6 @@
settable_from_internals: true,
},
{
- name: "ParentNodeReplaceChildren",
- status: "stable",
- },
- {
// This flag enables the Manifest parser to handle URL Protocols.
name: "ParseUrlProtocolHandler",
status: "test",
@@ -1626,9 +1698,6 @@
name: "RawClipboard",
},
{
- name: "ReadableByteStream",
- },
- {
name: "RemotePlayback",
status: "stable",
},
@@ -1644,10 +1713,6 @@
status: "stable",
},
{
- name: "ResizeObserverUpdates",
- status: "stable",
- },
- {
name: "RestrictAutomaticLazyFrameLoadingToDataSaver",
depends_on: ["AutomaticLazyFrameLoading"],
status: "stable",
@@ -1676,6 +1741,13 @@
origin_trial_feature_name: "RtcAudioJitterBufferRtxHandling",
status: "experimental",
},
+ // Reverse Origin Trial for Plan B. When enabled through the Origin Trial,
+ // Plan B is available beyond the initial removal date of Plan B (M93).
+ {
+ name: "RTCExtendDeadlineForPlanBRemoval",
+ origin_trial_feature_name: "RTCExtendDeadlineForPlanBRemoval",
+ status: "test",
+ },
// Enables the use of the RTCIceTransport with extensions.
{
name: "RTCIceTransportExtension",
@@ -1695,6 +1767,13 @@
origin_trial_feature_name: "RTCQuicTransport",
status: "experimental",
},
+ // Enables the use of |RTCRtpTransceiver::setOfferedRtpHeaderExtensions|,
+ // |RTCRtpTransceiver::headerExtensionsToOffer|, and
+ // |RTCRtpTransceiver::headerExtensionsNegotiated|.
+ {
+ name: "RTCRtpHeaderExtensionControl",
+ status: "experimental",
+ },
// Enables the use of |RTCRtpTransceiver::stop()|
{
name: "RTCRtpTransceiverStop",
@@ -1731,6 +1810,10 @@
status: "test",
},
{
+ name: "ScreenFold",
+ status: "experimental",
+ },
+ {
name: "ScreenWakeLock",
status: "stable",
},
@@ -1776,7 +1859,7 @@
{
name: "SecurePaymentConfirmation",
origin_trial_feature_name: "SecurePaymentConfirmation",
- origin_trial_os: ["mac"],
+ origin_trial_os: ["mac", "win"],
status: "experimental",
},
{
@@ -1796,8 +1879,7 @@
},
{
name: "Serial",
- origin_trial_feature_name: "Serial",
- status: {"Android": "", "default": "experimental"},
+ status: {"Android": "", "default": "stable"},
},
{
name: "ServiceWorkerClientLifecycleState",
@@ -1813,7 +1895,7 @@
name: "ShadowDOMV0",
status: "test",
},
- {
+ {
name: "SharedArrayBuffer",
status: "stable",
},
@@ -1862,6 +1944,15 @@
status: "test",
},
{
+ name: "StorageBuckets",
+ status: "experimental",
+ },
+ {
+ name: "StorageFoundationAPI",
+ origin_trial_feature_name: "StorageFoundationAPI",
+ status: "experimental",
+ },
+ {
name: "StrictMimeTypesForWorkers",
status: "experimental"
},
@@ -1869,7 +1960,11 @@
name: "SubresourceWebBundles",
origin_trial_feature_name: "SubresourceWebBundles",
origin_trial_allows_third_party: true,
- status: "test"
+ status: "experimental"
+ },
+ {
+ name: "SummaryListItem",
+ status: "stable",
},
{
name: "SurfaceEmbeddingFeatures",
@@ -1880,11 +1975,6 @@
status: "experimental",
},
{
- name: "TableCellNewPercents",
- depends_on: ["LayoutNG"],
- status: "stable",
- },
- {
// TODO(crbug.com/898942): Remove this in Chrome 95.
name: "TargetBlankImpliesNoOpener",
status: "stable",
@@ -1908,6 +1998,10 @@
status: "experimental",
},
{
+ name: "TextFragmentColorChange",
+ status: "test",
+ },
+ {
name: "TextFragmentIdentifiers",
origin_trial_feature_name: "TextFragmentIdentifiers",
status: "stable",
@@ -1987,24 +2081,23 @@
name: "UnderlineOffsetThickness",
status: "stable",
},
+ // This is a reverse OT used for a phased deprecation, on desktop
+ // https://crbug.com/1071424
{
- name: "UnoptimizedImagePolicies",
- status: "experimental",
- origin_trial_feature_name: "UnoptimizedImagePolicies",
- implied_by: ["ExperimentalProductivityFeatures"]
+ name: "UnrestrictedSharedArrayBuffer",
+ origin_trial_feature_name: "UnrestrictedSharedArrayBuffer",
+ origin_trial_os: ["win", "mac", "linux", "chromeos"],
},
{
- name: "UnsizedMediaPolicy",
+ name: "URLPattern",
status: "experimental",
- origin_trial_feature_name: "UnsizedMediaPolicy",
- implied_by: ["ExperimentalProductivityFeatures"]
},
{
name: "UserActivationSameOriginVisibility",
},
{
name: "UserAgentClientHint",
- status: "experimental",
+ status: "stable",
},
{
name: "V8IdleTasks",
@@ -2055,20 +2148,23 @@
status: "experimental",
},
{
+ name: "WebAppLinkCapturing",
+ },
+ {
name: "WebAppManifestDisplayOverride",
},
{
name: "WebAppWindowControlsOverlay",
},
{
- name: "WebAssemblySimd",
- origin_trial_feature_name: "WebAssemblySimd",
- status: "experimental",
+ name: "WebAssemblyExceptions",
+ origin_trial_feature_name: "WebAssemblyExceptions",
+ status: "test",
},
{
- name: "WebAssemblyThreads",
- origin_trial_feature_name: "WebAssemblyThreads",
- status: "experimental",
+ name: "WebAssemblySimd",
+ origin_trial_feature_name: "WebAssemblySimd",
+ status: "test",
},
// WebAuth is disabled on Android versions prior to N (7.0) due to lack of
// supporting APIs, see runtime_features.cc.
@@ -2076,6 +2172,12 @@
name: "WebAuth",
status: "stable",
},
+ // A more subtle UI for WebAuthn that is web exposed. Under development.
+ // It's controlled by the corresponding Chromium feature which needs to
+ // be enabled to make the whole feature work.
+ {
+ name: "WebAuthenticationConditionalUI",
+ },
{
name: "WebAuthenticationGetAssertionFeaturePolicy",
status: "experimental",
@@ -2086,7 +2188,7 @@
},
{
name: "WebAuthenticationResidentKeyRequirement",
- status: "experimental",
+ status: "stable",
},
// WebBluetooth is enabled by default on Android, ChromeOS and Mac.
// It is also supported in Windows 10 which is handled in runtime_features.cc
@@ -2145,24 +2247,32 @@
name: "WebGPU",
},
{
+ // Requires both WebGPU and --enable-experimental-web-platform-features
+ name: "WebGPUImportTexture",
+ status: "experimental",
+ },
+ {
name: "WebHID",
- origin_trial_feature_name: "WebHID",
- status: {"Android": "", "default": "experimental"},
+ status: {"Android": "", "default": "stable"},
},
{
name: "WebID",
+ status: "experimental"
},
{
name: "WebNFC",
- origin_trial_feature_name: "WebNFC",
- origin_trial_os: ["android"],
- status: "experimental",
+ status: {"Android": "stable", "default": "test"},
},
{
name: "WebOTP",
status: {"default": "experimental", "Android": "stable"},
},
{
+ name: "WebOTPAssertionFeaturePolicy",
+ status: "experimental",
+ depends_on: ["WebOTP"],
+ },
+ {
name: "WebScheduler",
origin_trial_feature_name: "WebScheduler",
status: "experimental",
@@ -2212,7 +2322,12 @@
name: "WebXRDepth",
origin_trial_feature_name: "WebXRDepth",
depends_on: ["WebXRARModule"],
- status: "experimental",
+ status: "stable",
+ },
+ {
+ name: "WebXRHandInput",
+ depends_on: ["WebXRARModule"],
+ status: "experimental"
},
{
name: "WebXRHitTest",
@@ -2231,14 +2346,7 @@
},
{
name: "WebXRLightEstimation",
- origin_trial_feature_name: "WebXRLightEstimation",
depends_on: ["WebXRARModule"],
- status: "experimental",
- },
- {
- name: "WebXRMultiGpu",
- depends_on: ["WebXR"],
- // Enabled when blink::features::kWebXrMultiGpu is enabled.
status: "stable",
},
{
@@ -2249,7 +2357,7 @@
{
name: "WebXRViewportScale",
depends_on: ["WebXRARModule"],
- status: "experimental",
+ status: "stable",
},
{
name: "WheelEventRegions",
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn b/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
index 7fbc5f3e713..dec935a222f 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -168,6 +168,7 @@ blink_platform_sources("scheduler") {
deps = [
"//base",
"//cc",
+ "//components/power_scheduler",
"//components/scheduling_metrics",
"//device/base/synchronization",
"//services/metrics/public/cpp:ukm_builders",
@@ -189,6 +190,7 @@ source_set("test_support") {
testonly = true
sources = [
+ "test/fake_agent_group_scheduler_scheduler.h",
"test/fake_frame_scheduler.h",
"test/fake_page_scheduler.h",
"test/fake_task_runner.cc",
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/DEPS b/chromium/third_party/blink/renderer/platform/scheduler/DEPS
index b6650d87efb..94505c5f400 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/DEPS
+++ b/chromium/third_party/blink/renderer/platform/scheduler/DEPS
@@ -53,6 +53,7 @@ include_rules = [
"+components/scheduling_metrics",
"+services/metrics",
+ "+third_party/blink/renderer/platform/back_forward_cache_utils.h",
"+third_party/blink/renderer/platform/bindings/parkable_string_manager.h",
"+third_party/blink/renderer/platform/instrumentation",
"+third_party/blink/renderer/platform/platform_export.h",
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/DIR_METADATA b/chromium/third_party/blink/renderer/platform/scheduler/DIR_METADATA
new file mode 100644
index 00000000000..bba4e8725bb
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/scheduler/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Scheduling"
+}
+team_email: "scheduler-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/OWNERS b/chromium/third_party/blink/renderer/platform/scheduler/OWNERS
index 60296e85372..a3f384b76b0 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/scheduler/OWNERS
@@ -9,6 +9,3 @@ shaseley@chromium.org
# TOK scheduling team
kouhei@chromium.org
-
-# TEAM: scheduler-dev@chromium.org
-# COMPONENT: Blink>Scheduling
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md b/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
index d01926e7ba2..d5dfc529f1f 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
+++ b/chromium/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
@@ -18,7 +18,7 @@ to find out how to schedule this type of work.
## Tasks
-The main scheduling unit in Blink is a task. A task is a base::Closure posted via
+The main scheduling unit in Blink is a task. A task is a base::OnceClosure posted via
TaskRunner::PostTask or TaskRunner::PostDelayedTask interface. The regular method of
creating closures (base::BindOnce/Repeating) [is banned](#binding-tasks).
Blink should use WTF::Bind (for tasks which are posted to the same thread) and
@@ -175,4 +175,3 @@ on a different thread.
## TODO(altimin): Document idle tasks
-
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
index afc339c56f1..05ba47d97a5 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
@@ -21,9 +22,8 @@ namespace {
class DummyFrameScheduler : public FrameScheduler {
public:
- explicit DummyFrameScheduler(PageScheduler* page_scheduler)
- : page_scheduler_(page_scheduler) {}
- ~DummyFrameScheduler() override {}
+ DummyFrameScheduler() : page_scheduler_(CreateDummyPageScheduler()) {}
+ ~DummyFrameScheduler() override = default;
DummyFrameScheduler(const DummyFrameScheduler&) = delete;
DummyFrameScheduler& operator=(const DummyFrameScheduler&) = delete;
@@ -33,8 +33,12 @@ class DummyFrameScheduler : public FrameScheduler {
return base::ThreadTaskRunnerHandle::Get();
}
- PageScheduler* GetPageScheduler() const override { return page_scheduler_; }
- AgentGroupScheduler* GetAgentGroupScheduler() override { return nullptr; }
+ PageScheduler* GetPageScheduler() const override {
+ return page_scheduler_.get();
+ }
+ WebAgentGroupScheduler* GetAgentGroupScheduler() override {
+ return &page_scheduler_->GetAgentGroupScheduler();
+ }
void SetPreemptedForCooperativeScheduling(Preempted) override {}
void SetFrameVisible(bool) override {}
@@ -94,32 +98,14 @@ class DummyFrameScheduler : public FrameScheduler {
void ReportActiveSchedulerTrackedFeatures() override {}
private:
- PageScheduler* page_scheduler_;
+ std::unique_ptr<PageScheduler> page_scheduler_;
base::WeakPtrFactory<FrameScheduler> weak_ptr_factory_{this};
};
-class DummyAgentGroupScheduler : public AgentGroupScheduler {
- public:
- DummyAgentGroupScheduler() = default;
- ~DummyAgentGroupScheduler() override = default;
-
- DummyAgentGroupScheduler(const DummyAgentGroupScheduler&) = delete;
- DummyAgentGroupScheduler& operator=(const DummyAgentGroupScheduler&) = delete;
-
- AgentGroupScheduler& AsAgentGroupScheduler() override { return *this; }
- std::unique_ptr<PageScheduler> CreatePageScheduler(
- PageScheduler::Delegate*) override {
- return CreateDummyPageScheduler();
- }
- scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override {
- return base::ThreadTaskRunnerHandle::Get();
- }
-};
-
class DummyPageScheduler : public PageScheduler {
public:
DummyPageScheduler()
- : agent_group_scheduler_(std::make_unique<DummyAgentGroupScheduler>()) {}
+ : agent_group_scheduler_(CreateDummyAgentGroupScheduler()) {}
~DummyPageScheduler() override = default;
DummyPageScheduler(const DummyPageScheduler&) = delete;
@@ -129,13 +115,14 @@ class DummyPageScheduler : public PageScheduler {
FrameScheduler::Delegate* delegate,
BlameContext*,
FrameScheduler::FrameType) override {
- return std::make_unique<DummyFrameScheduler>(this);
+ return CreateDummyFrameScheduler();
}
void OnTitleOrFaviconUpdated() override {}
void SetPageVisible(bool) override {}
void SetPageFrozen(bool) override {}
void SetPageBackForwardCached(bool) override {}
+ void OnFocusChanged(bool focused) override {}
void SetKeepActive(bool) override {}
bool IsMainFrameLocal() const override { return true; }
void SetIsMainFrameLocal(bool) override {}
@@ -161,12 +148,46 @@ class DummyPageScheduler : public PageScheduler {
WebScopedVirtualTimePauser::VirtualTaskDuration) override {
return WebScopedVirtualTimePauser();
}
- scheduler::WebAgentGroupScheduler& GetAgentGroupScheduler() override {
+ WebAgentGroupScheduler& GetAgentGroupScheduler() override {
return *agent_group_scheduler_;
}
private:
- std::unique_ptr<DummyAgentGroupScheduler> agent_group_scheduler_;
+ std::unique_ptr<WebAgentGroupScheduler> agent_group_scheduler_;
+};
+
+class DummyAgentGroupScheduler : public AgentGroupScheduler {
+ public:
+ DummyAgentGroupScheduler()
+ : main_thread_scheduler_(CreateDummyWebThreadScheduler()) {}
+ ~DummyAgentGroupScheduler() override = default;
+
+ DummyAgentGroupScheduler(const DummyAgentGroupScheduler&) = delete;
+ DummyAgentGroupScheduler& operator=(const DummyAgentGroupScheduler&) = delete;
+
+ AgentGroupScheduler& AsAgentGroupScheduler() override { return *this; }
+ std::unique_ptr<PageScheduler> CreatePageScheduler(
+ PageScheduler::Delegate*) override {
+ return CreateDummyPageScheduler();
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override {
+ return base::ThreadTaskRunnerHandle::Get();
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override {
+ return base::ThreadTaskRunnerHandle::Get();
+ }
+ WebThreadScheduler& GetMainThreadScheduler() override {
+ return *main_thread_scheduler_;
+ }
+ void BindInterfaceBroker(
+ mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker> remote_broker)
+ override {}
+ BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() override {
+ return GetEmptyBrowserInterfaceBroker();
+ }
+
+ private:
+ std::unique_ptr<WebThreadScheduler> main_thread_scheduler_;
};
// TODO(altimin,yutak): Merge with SimpleThread in platform.cc.
@@ -215,7 +236,7 @@ class DummyThreadScheduler : public ThreadScheduler {
}
std::unique_ptr<WebAgentGroupScheduler> CreateAgentGroupScheduler() override {
- return std::make_unique<DummyAgentGroupScheduler>();
+ return CreateDummyAgentGroupScheduler();
}
WebAgentGroupScheduler* GetCurrentAgentGroupScheduler() override {
@@ -283,7 +304,7 @@ class DummyWebThreadScheduler : public WebThreadScheduler,
}
std::unique_ptr<WebAgentGroupScheduler> CreateAgentGroupScheduler() override {
- return std::make_unique<DummyAgentGroupScheduler>();
+ return CreateDummyAgentGroupScheduler();
}
WebAgentGroupScheduler* GetCurrentAgentGroupScheduler() override {
@@ -294,7 +315,7 @@ class DummyWebThreadScheduler : public WebThreadScheduler,
} // namespace
std::unique_ptr<FrameScheduler> CreateDummyFrameScheduler() {
- return std::make_unique<DummyFrameScheduler>(nullptr);
+ return std::make_unique<DummyFrameScheduler>();
}
std::unique_ptr<PageScheduler> CreateDummyPageScheduler() {
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/features.h b/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
index 183cc4e836b..46ba7541b74 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -301,6 +301,21 @@ constexpr base::FeatureParam<PerAgentSignal> kPerAgentSignal{
&kPerAgentSchedulingExperiments, "signal",
PerAgentSignal::kFirstMeaningfulPaint, &kPerAgentSignalOptions};
+// If enabled, base::ThreadTaskRunnerHandle::Get() and
+// base::SequencedTaskRunnerHandle::Get() returns the current active
+// per-ASG task runner instead of the per-thread task runner.
+const base::Feature kMbiOverrideTaskRunnerHandle{
+ "MbiOverrideTaskRunnerHandle", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, per-AgentGroupScheduler CompositorTaskRunner will be used instead
+// of per-MainThreadScheduler CompositorTaskRunner.
+const base::Feature kMbiCompositorTaskRunnerPerAgentSchedulingGroup{
+ "MbiCompositorTaskRunnerPerAgentSchedulingGroup",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kThrottleVisibleNotFocusedTimers{
+ "ThrottleVisibleNotFocusedTimers", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
index 5110c90ee31..2017943ad50 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
@@ -180,6 +180,7 @@ class BaseIdleHelperTest : public testing::Test {
nullptr, test_task_runner_, test_task_runner_->GetMockTickClock());
scheduler_helper_ = std::make_unique<NonMainThreadSchedulerHelper>(
sequence_manager_.get(), nullptr, TaskType::kInternalTest);
+ scheduler_helper_->AttachToCurrentThread();
idle_helper_ = std::make_unique<IdleHelperForTest>(
scheduler_helper_.get(),
required_quiescence_duration_before_long_idle_period,
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
index e0751e3be0c..815d5058e18 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -29,6 +29,14 @@ SchedulerHelper::SchedulerHelper(SequenceManager* sequence_manager)
sequence_manager_->SetWorkBatchSize(4);
}
+void SchedulerHelper::AttachToCurrentThread() {
+ DETACH_FROM_THREAD(thread_checker_);
+ CheckOnValidThread();
+ DCHECK(default_task_runner_) << "Must be invoked after InitDefaultQueues.";
+ DCHECK(!simple_task_executor_.has_value());
+ simple_task_executor_.emplace(default_task_runner_);
+}
+
void SchedulerHelper::InitDefaultQueues(
scoped_refptr<TaskQueue> default_task_queue,
scoped_refptr<TaskQueue> control_task_queue,
@@ -38,10 +46,11 @@ void SchedulerHelper::InitDefaultQueues(
default_task_runner_ =
default_task_queue->CreateTaskRunner(static_cast<int>(default_task_type));
+ // Invoking SequenceManager::SetDefaultTaskRunner() before attaching the
+ // SchedulerHelper to a thread is fine. The default TaskRunner will be stored
+ // in TLS by the ThreadController before tasks are executed.
DCHECK(sequence_manager_);
sequence_manager_->SetDefaultTaskRunner(default_task_runner_);
-
- simple_task_executor_.emplace(default_task_runner_);
}
SchedulerHelper::~SchedulerHelper() {
@@ -50,6 +59,8 @@ SchedulerHelper::~SchedulerHelper() {
void SchedulerHelper::Shutdown() {
CheckOnValidThread();
+ DCHECK(simple_task_executor_.has_value())
+ << "AttachToCurrentThread() was not invoked.";
if (!sequence_manager_)
return;
ShutdownAllQueues();
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
index b12d21eef9f..948d925989b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
@@ -8,9 +8,11 @@
#include <stddef.h>
#include <memory>
+#include "base/logging.h"
#include "base/macros.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/task/simple_task_executor.h"
+#include "base/threading/thread_checker.h"
#include "base/time/tick_clock.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@@ -34,6 +36,10 @@ class PLATFORM_EXPORT SchedulerHelper
base::sequence_manager::SequenceManager* sequence_manager);
~SchedulerHelper() override;
+ // Must be invoked before running any task from the scheduler, on the thread
+ // that will run these tasks. Setups the ThreadChecker and the TaskExecutor.
+ void AttachToCurrentThread();
+
// SequenceManager::Observer implementation:
void OnBeginNestedRunLoop() override;
void OnExitNestedRunLoop() override;
@@ -72,7 +78,7 @@ class PLATFORM_EXPORT SchedulerHelper
bool IsShutdown() const { return !sequence_manager_; }
inline void CheckOnValidThread() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
class PLATFORM_EXPORT Observer {
@@ -121,7 +127,11 @@ class PLATFORM_EXPORT SchedulerHelper
virtual void ShutdownAllQueues() {}
- base::ThreadChecker thread_checker_;
+ const scoped_refptr<base::SingleThreadTaskRunner>& default_task_runner() {
+ return default_task_runner_;
+ }
+
+ THREAD_CHECKER(thread_checker_);
base::sequence_manager::SequenceManager* sequence_manager_; // NOT OWNED
private:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
index bbc84ed3f64..bb6c5f7f8cd 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
@@ -59,6 +59,7 @@ class SchedulerHelperTest : public testing::Test {
task_environment_.GetMockTickClock());
scheduler_helper_ = std::make_unique<NonMainThreadSchedulerHelper>(
sequence_manager_.get(), nullptr, TaskType::kInternalTest);
+ scheduler_helper_->AttachToCurrentThread();
default_task_runner_ = scheduler_helper_->DefaultTaskRunner();
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
index f693f387c58..c17e32eca01 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
@@ -49,7 +49,6 @@ bool SchedulingPolicy::IsFeatureSticky(SchedulingPolicy::Feature feature) {
case Feature::kRequestedBackForwardCacheBlockedSensors:
case Feature::kRequestedBackgroundWorkPermission:
case Feature::kWebLocks:
- case Feature::kWakeLock:
case Feature::kRequestedStorageAccessGrant:
case Feature::kWebNfc:
case Feature::kWebFileSystem:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
index c575af6f0b6..5e24f116536 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
@@ -18,8 +18,6 @@ SingleThreadIdleTaskRunner::SingleThreadIdleTaskRunner(
: idle_priority_task_runner_(idle_priority_task_runner),
delegate_(delegate),
blame_context_(nullptr) {
- DCHECK(!idle_priority_task_runner_ ||
- idle_priority_task_runner_->RunsTasksInCurrentSequence());
weak_scheduler_ptr_ = weak_factory_.GetWeakPtr();
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/thread.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/thread.cc
index 013326b9a51..61bd6f9da2e 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/thread.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/thread.cc
@@ -7,6 +7,7 @@
#include "base/feature_list.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
@@ -94,16 +95,22 @@ void Thread::CreateAndSetCompositorThread() {
auto compositor_thread =
std::make_unique<scheduler::CompositorThread>(params);
compositor_thread->Init();
- GetCompositorThread() = std::move(compositor_thread);
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
if (base::FeatureList::IsEnabled(
features::kBlinkCompositorUseDisplayThreadPriority)) {
- // Chrome OS moves tasks between control groups on thread priority changes.
- // This is not possible inside the sandbox, so ask the browser to do it.
- // TODO(spang): Check if we can remove this on non-Chrome OS builds.
- Platform::Current()->SetDisplayThreadPriority(
- GetCompositorThread()->ThreadId());
+ compositor_thread->GetTaskRunner()->PostTaskAndReplyWithResult(
+ FROM_HERE, base::BindOnce(&base::PlatformThread::CurrentId),
+ base::BindOnce([](base::PlatformThreadId compositor_thread_id) {
+ // Chrome OS moves tasks between control groups on thread priority
+ // changes. This is not possible inside the sandbox, so ask the
+ // browser to do it.
+ Platform::Current()->SetDisplayThreadPriority(compositor_thread_id);
+ }));
}
+#endif
+
+ GetCompositorThread() = std::move(compositor_thread);
}
Thread* Thread::Current() {
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h
index 400b07f0f01..7add339b4d5 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h
@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace sequence_manager {
@@ -74,9 +75,9 @@ class PLATFORM_EXPORT BudgetPool {
// Specify how this budget pool should block affected queues.
virtual QueueBlockType GetBlockType() const = 0;
- // Returns state for tracing.
- virtual void AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const = 0;
+ // Records state for tracing.
+ virtual void WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const = 0;
// Adds |queue| to given pool. If the pool restriction does not allow
// a task to be run immediately and |queue| is throttled, |queue| becomes
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
index dc9519b3661..9743e5d841c 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
@@ -31,10 +31,10 @@ class BudgetPoolTest : public testing::Test {
void SetUp() override {
clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
null_task_runner_ = base::MakeRefCounted<base::NullTaskRunner>();
- scheduler_.reset(new MainThreadSchedulerImpl(
+ scheduler_ = std::make_unique<MainThreadSchedulerImpl>(
base::sequence_manager::SequenceManagerForTest::Create(
nullptr, null_task_runner_, &clock_),
- base::nullopt));
+ base::nullopt);
task_queue_throttler_ = scheduler_->task_queue_throttler();
start_time_ = clock_.NowTicks();
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.cc
index 8934d5fd344..8272b7a59b2 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.cc
@@ -127,35 +127,26 @@ void CPUTimeBudgetPool::OnQueueNextWakeUpChanged(
void CPUTimeBudgetPool::OnWakeUp(base::TimeTicks now) {}
-void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const {
- current_budget_level_.Trace();
- auto dictionary_scope = state->BeginDictionaryScoped(name_);
-
- state->SetString("name", name_);
- state->SetDouble("time_budget", cpu_percentage_);
- state->SetDouble("time_budget_level_in_seconds",
- current_budget_level_->InSecondsF());
- state->SetDouble("last_checkpoint_seconds_ago",
- (now - last_checkpoint_).InSecondsF());
- state->SetBoolean("is_enabled", is_enabled_);
- state->SetDouble("min_budget_level_to_run_in_seconds",
- min_budget_level_to_run_.InSecondsF());
+void CPUTimeBudgetPool::WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const {
+ auto dict = std::move(context).WriteDictionary();
+
+ dict.Add("name", name_);
+ dict.Add("time_budget", cpu_percentage_);
+ dict.Add("time_budget_level_in_seconds", current_budget_level_->InSecondsF());
+ dict.Add("last_checkpoint_seconds_ago",
+ (now - last_checkpoint_).InSecondsF());
+ dict.Add("is_enabled", is_enabled_);
+ dict.Add("min_budget_level_to_run_in_seconds",
+ min_budget_level_to_run_.InSecondsF());
if (max_throttling_delay_) {
- state->SetDouble("max_throttling_delay_in_seconds",
- max_throttling_delay_.value().InSecondsF());
+ dict.Add("max_throttling_delay_in_seconds",
+ max_throttling_delay_.value().InSecondsF());
}
if (max_budget_level_) {
- state->SetDouble("max_budget_level_in_seconds",
- max_budget_level_.value().InSecondsF());
- }
-
- {
- auto array_scope = state->BeginArrayScoped("task_queues");
- for (TaskQueue* queue : associated_task_queues_) {
- state->AppendString(PointerToString(queue));
- }
+ dict.Add("max_budget_level_in_seconds",
+ max_budget_level_.value().InSecondsF());
}
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
index 485b41045e7..bba2320eeb8 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
@@ -82,8 +82,8 @@ class PLATFORM_EXPORT CPUTimeBudgetPool : public BudgetPool {
base::TimeTicks now,
base::TimeTicks desired_run_time) final;
void OnWakeUp(base::TimeTicks now) final;
- void AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const final;
+ void WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks) const final;
protected:
QueueBlockType GetBlockType() const final;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
index f15057e6ac6..673fba6171a 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.cc
@@ -76,7 +76,7 @@ void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) {
// Task queue is newly throttled.
TRACE_EVENT1("renderer.scheduler", "TaskQueueThrottler_TaskQueueThrottled",
- "task_queue", task_queue);
+ "task_queue", static_cast<void*>(task_queue));
if (!allow_throttling_)
return;
@@ -105,7 +105,7 @@ void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) {
return;
TRACE_EVENT1("renderer.scheduler", "TaskQueueThrottler_TaskQueueUnthrottled",
- "task_queue", task_queue);
+ "task_queue", static_cast<void*>(task_queue));
MaybeDeleteQueueMetadata(iter);
@@ -411,32 +411,31 @@ base::Optional<QueueBlockType> TaskQueueThrottler::GetQueueBlockType(
return base::nullopt;
}
-void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const {
+void TaskQueueThrottler::WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const {
+ auto dict = std::move(context).WriteDictionary();
if (pending_pump_throttled_tasks_runtime_) {
- state->SetDouble(
+ dict.Add(
"next_throttled_tasks_pump_in_seconds",
(pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF());
}
- state->SetBoolean("allow_throttling", allow_throttling_);
+ dict.Add("allow_throttling", allow_throttling_);
{
- auto dictionary_scope = state->BeginDictionaryScoped("time_budget_pools");
- for (const auto& map_entry : budget_pools_) {
- BudgetPool* pool = map_entry.key;
- pool->AsValueInto(state, now);
+ auto time_budget_pools = dict.AddArray("time_budget_pools");
+ for (const auto& budget_pool : budget_pools_) {
+ budget_pool.key->WriteIntoTracedValue(time_budget_pools.AppendItem(),
+ now);
}
}
{
- auto dictionary_scope = state->BeginDictionaryScoped("queue_details");
- for (const auto& map_entry : queue_details_) {
- auto inner_scope = state->BeginDictionaryScopedWithCopiedName(
- PointerToString(map_entry.key));
- state->SetInteger(
- "throttling_ref_count",
- static_cast<int>(map_entry.value->throttling_ref_count()));
+ auto queue_details_array = dict.AddArray("queue_details");
+ for (const auto& queue_details : queue_details_) {
+ auto details_dict = queue_details_array.AppendDictionary();
+ details_dict.Add("queue_name", queue_details.key->GetName());
+ details_dict.Add("metadata", queue_details.value);
}
}
}
@@ -609,5 +608,12 @@ void TaskQueueThrottler::Metadata::OnQueueNextWakeUpChanged(
throttler_->OnQueueNextWakeUpChanged(queue_, wake_up);
}
+void TaskQueueThrottler::Metadata::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("throttling_ref_count", throttling_ref_count_);
+ dict.Add("next_granted_run_time", next_granted_run_time_);
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
index 26ae54958ff..886a74bee18 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace trace_event {
@@ -125,8 +126,12 @@ class PLATFORM_EXPORT TaskQueueThrottler : public BudgetPoolController {
base::TimeTicks start_time,
base::TimeTicks end_time);
- void AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const;
+ void WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const;
+
+ base::WeakPtr<TaskQueueThrottler> AsWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
private:
class Metadata : public base::sequence_manager::TaskQueue::Observer {
@@ -158,6 +163,8 @@ class PLATFORM_EXPORT TaskQueueThrottler : public BudgetPoolController {
next_granted_run_time_ = next_granted_run_time;
}
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
private:
base::sequence_manager::TaskQueue* const queue_;
TaskQueueThrottler* const throttler_;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
index 5ccf80d1ebe..ca36958663c 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
@@ -91,13 +91,13 @@ class TaskQueueThrottlerTest : public testing::Test {
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
wake_up_budget_pool_->AddQueue(base::TimeTicks(),
- timer_queue_->GetTaskQueue());
+ timer_queue_->GetTaskQueueForTest());
timer_task_runner_ = timer_queue_->GetTaskRunnerWithDefaultTaskType();
}
void TearDown() override {
wake_up_budget_pool_->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
+ timer_queue_->GetTaskQueueForTest());
wake_up_budget_pool_->Close();
scheduler_->Shutdown();
scheduler_.reset();
@@ -140,6 +140,10 @@ class TaskQueueThrottlerTest : public testing::Test {
test_task_runner_->NowTicks());
}
+ TaskQueue* GetTaskQueue(MainThreadTaskQueue* queue) {
+ return queue->GetTaskQueueForTest();
+ }
+
protected:
virtual const base::TickClock* GetTickClock() const {
return test_task_runner_->GetMockTickClock();
@@ -212,18 +216,19 @@ INSTANTIATE_TEST_SUITE_P(All,
testing::Bool());
TEST_F(TaskQueueThrottlerTest, ThrottledTasksReportRealTime) {
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain()->Now(),
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain()->Now(),
test_task_runner_->NowTicks());
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain()->Now(),
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain()->Now(),
test_task_runner_->NowTicks());
test_task_runner_->AdvanceMockTickClock(
base::TimeDelta::FromMilliseconds(250));
// Make sure the throttled time domain's Now() reports the same as the
// underlying clock.
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain()->Now(),
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain()->Now(),
test_task_runner_->NowTicks());
}
@@ -319,7 +324,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TimerAlignment) {
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMilliseconds(8300.0));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
test_task_runner_->FastForwardUntilNoTasksRemain();
@@ -353,8 +359,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMilliseconds(8300.0));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
test_task_runner_->FastForwardUntilNoTasksRemain();
@@ -372,53 +380,60 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, Refcount) {
- ExpectUnthrottled(timer_queue_->GetTaskQueue());
+ ExpectUnthrottled(GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectThrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectThrottled(GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectThrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectThrottled(GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectThrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectThrottled(GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectUnthrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectUnthrottled(GetTaskQueue(timer_queue_.get()));
// Should be a NOP.
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectUnthrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectUnthrottled(GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- ExpectThrottled(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ ExpectThrottled(GetTaskQueue(timer_queue_.get()));
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) {
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
- EXPECT_TRUE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ EXPECT_TRUE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
OnTimeDomainHasImmediateWork_EnabledQueue) {
- task_queue_throttler_->OnQueueNextWakeUpChanged(timer_queue_->GetTaskQueue(),
- base::TimeTicks());
+ task_queue_throttler_->OnQueueNextWakeUpChanged(
+ GetTaskQueue(timer_queue_.get()), base::TimeTicks());
// Check PostPumpThrottledTasksLocked was called.
- EXPECT_FALSE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ EXPECT_FALSE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
OnTimeDomainHasImmediateWork_DisabledQueue) {
std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
- timer_queue_->GetTaskQueue()->CreateQueueEnabledVoter();
+ GetTaskQueue(timer_queue_.get())->CreateQueueEnabledVoter();
voter->SetVoteToEnable(false);
- task_queue_throttler_->OnQueueNextWakeUpChanged(timer_queue_->GetTaskQueue(),
- base::TimeTicks());
+ task_queue_throttler_->OnQueueNextWakeUpChanged(
+ GetTaskQueue(timer_queue_.get()), base::TimeTicks());
// Check PostPumpThrottledTasksLocked was not called.
- EXPECT_TRUE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ EXPECT_TRUE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
@@ -426,15 +441,16 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
timer_task_runner_->PostTask(FROM_HERE, base::BindOnce(&NopTask));
std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
- timer_queue_->GetTaskQueue()->CreateQueueEnabledVoter();
+ GetTaskQueue(timer_queue_.get())->CreateQueueEnabledVoter();
voter->SetVoteToEnable(false);
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_TRUE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_TRUE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
// Enabling it should trigger a call to PostPumpThrottledTasksLocked.
voter->SetVoteToEnable(true);
- EXPECT_FALSE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ EXPECT_FALSE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
@@ -443,22 +459,24 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(1));
std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
- timer_queue_->GetTaskQueue()->CreateQueueEnabledVoter();
+ GetTaskQueue(timer_queue_.get())->CreateQueueEnabledVoter();
voter->SetVoteToEnable(false);
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_TRUE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_TRUE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
// Enabling it should trigger a call to PostPumpThrottledTasksLocked.
voter->SetVoteToEnable(true);
- EXPECT_FALSE(scheduler_->ControlTaskQueue()->GetTaskQueue()->IsEmpty());
+ EXPECT_FALSE(GetTaskQueue(scheduler_->ControlTaskQueue().get())->IsEmpty());
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, WakeUpForNonDelayedTask) {
Vector<base::TimeTicks> run_times;
// Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Posting a task should trigger the pump.
timer_task_runner_->PostTask(
@@ -474,7 +492,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, WakeUpForDelayedTask) {
Vector<base::TimeTicks> run_times;
// Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Posting a task should trigger the pump.
timer_task_runner_->PostDelayedTask(
@@ -489,7 +508,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, WakeUpForDelayedTask) {
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
timer_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NopTask),
@@ -499,7 +519,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
timer_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NopTask),
@@ -509,7 +530,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
Vector<base::TimeTicks> run_times;
base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
@@ -538,7 +560,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
TaskDelayIsBasedOnRealTime) {
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post an initial task that should run at the first aligned time period.
timer_task_runner_->PostDelayedTask(
@@ -570,9 +593,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TaskQueueDisabledTillPump) {
size_t count = 0;
timer_task_runner_->PostTask(FROM_HERE, base::BindOnce(&AddOneTask, &count));
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_TRUE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_TRUE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
test_task_runner_->FastForwardUntilNoTasksRemain(); // Wait until the pump.
EXPECT_EQ(1u, count); // The task got run.
@@ -582,13 +606,17 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
DoubleIncrementDoubleDecrement) {
timer_task_runner_->PostTask(FROM_HERE, base::BindOnce(&NopTask));
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_TRUE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_TRUE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
}
TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
@@ -597,13 +625,14 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
scheduler_->EnableVirtualTime(
MainThreadSchedulerImpl::BaseTimeOverridePolicy::DO_NOT_OVERRIDE);
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain(),
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain(),
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
}
@@ -611,14 +640,15 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
IncrementThenEnableVirtualTime) {
timer_task_runner_->PostTask(FROM_HERE, base::BindOnce(&NopTask));
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- EXPECT_TRUE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ EXPECT_TRUE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
scheduler_->EnableVirtualTime(
MainThreadSchedulerImpl::BaseTimeOverridePolicy::DO_NOT_OVERRIDE);
- EXPECT_FALSE(IsQueueBlocked(timer_queue_->GetTaskQueue()));
- EXPECT_EQ(timer_queue_->GetTaskQueue()->GetTimeDomain(),
+ EXPECT_FALSE(IsQueueBlocked(GetTaskQueue(timer_queue_.get())));
+ EXPECT_EQ(GetTaskQueue(timer_queue_.get())->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
}
@@ -629,9 +659,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TimeBasedThrottling) {
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Submit two tasks. They should be aligned, and second one should be
// throttled.
@@ -651,7 +682,7 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TimeBasedThrottling) {
base::TimeTicks() + base::TimeDelta::FromSeconds(3)));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
run_times.clear();
// Queue was removed from CPUTimeBudgetPool, only timer alignment should be
@@ -672,7 +703,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TimeBasedThrottling) {
ElementsAre(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4000),
base::TimeTicks() + base::TimeDelta::FromMilliseconds(4250)));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
pool->Close();
}
@@ -685,9 +717,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
EXPECT_TRUE(pool->IsThrottlingEnabled());
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post an expensive task. Pool is now throttled.
timer_task_runner_->PostDelayedTask(
@@ -734,10 +767,11 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(4000)));
run_times.clear();
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
pool->Close();
}
@@ -749,9 +783,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Submit two tasks. They should be aligned, and second one should be
// throttled.
@@ -769,7 +804,7 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeTicks() + base::TimeDelta::FromSeconds(3)));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
run_times.clear();
// Queue was removed from CPUTimeBudgetPool, only timer alignment should be
@@ -788,7 +823,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4000),
base::TimeTicks() + base::TimeDelta::FromMilliseconds(4250)));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
pool->Close();
}
@@ -805,13 +841,15 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
- pool->AddQueue(base::TimeTicks(), second_queue->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(second_queue.get()));
wake_up_budget_pool_->AddQueue(base::TimeTicks(),
- second_queue->GetTaskQueue());
+ GetTaskQueue(second_queue.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->IncreaseThrottleRefCount(second_queue->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(second_queue.get()));
timer_task_runner_->PostTask(
FROM_HERE,
@@ -826,15 +864,17 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(1),
base::TimeTicks() + base::TimeDelta::FromSeconds(3)));
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->DecreaseThrottleRefCount(second_queue->GetTaskQueue());
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(second_queue.get()));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- second_queue->GetTaskQueue());
+ GetTaskQueue(second_queue.get()));
wake_up_budget_pool_->RemoveQueue(test_task_runner_->NowTicks(),
- second_queue->GetTaskQueue());
+ GetTaskQueue(second_queue.get()));
pool->Close();
}
@@ -849,9 +889,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
pool->SetTimeBudgetRecoveryRate(lazy_now.Now(), 0.1);
pool->DisableThrottling(&lazy_now);
- pool->AddQueue(lazy_now.Now(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(lazy_now.Now(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -881,7 +922,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
LazyNow lazy_now(test_task_runner_->GetMockTickClock());
pool->DisableThrottling(&lazy_now);
- pool->AddQueue(test_task_runner_->NowTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(test_task_runner_->NowTicks(),
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -910,9 +952,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, MaxThrottlingDelay) {
base::TimeDelta::FromMinutes(1));
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.001);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
for (int i = 0; i < 5; ++i) {
timer_task_runner_->PostDelayedTask(
@@ -936,7 +979,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
EnableAndDisableThrottling) {
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
@@ -999,12 +1043,13 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, ReportThrottling) {
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
pool->SetReportingCallback(
base::BindRepeating(&RecordThrottling, &reported_throttling_times));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
@@ -1030,8 +1075,9 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, ReportThrottling) {
base::TimeDelta::FromMilliseconds(1755)));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
pool->Close();
}
@@ -1042,11 +1088,12 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, GrantAdditionalBudget) {
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
pool->GrantAdditionalBudget(base::TimeTicks(),
base::TimeDelta::FromMilliseconds(500));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Submit five tasks. First three will not be throttled because they have
// budget to run.
@@ -1068,8 +1115,9 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, GrantAdditionalBudget) {
base::TimeTicks() + base::TimeDelta::FromSeconds(6)));
pool->RemoveQueue(test_task_runner_->NowTicks(),
- timer_queue_->GetTaskQueue());
- task_queue_throttler_->DecreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->DecreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
pool->Close();
}
@@ -1083,12 +1131,13 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
CPUTimeBudgetPool* pool =
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
LazyNow lazy_now_1(test_task_runner_->GetMockTickClock());
pool->DisableThrottling(&lazy_now_1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(95));
@@ -1115,7 +1164,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
CPUTimeBudgetPool* pool =
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
test_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(95));
@@ -1123,7 +1173,7 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMilliseconds(200));
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
test_task_runner_->FastForwardUntilNoTasksRemain();
@@ -1140,8 +1190,10 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->IncreaseThrottleRefCount(second_queue->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(second_queue.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
@@ -1151,7 +1203,7 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(200));
std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
- timer_queue_->GetTaskQueue()->CreateQueueEnabledVoter();
+ GetTaskQueue(timer_queue_.get())->CreateQueueEnabledVoter();
voter->SetVoteToEnable(false);
test_task_runner_->AdvanceMockTickClock(
@@ -1185,21 +1237,23 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TwoBudgetPools) {
.SetCanBeThrottled(true));
wake_up_budget_pool_->AddQueue(base::TimeTicks(),
- second_queue->GetTaskQueue());
+ GetTaskQueue(second_queue.get()));
CPUTimeBudgetPool* pool1 =
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool1->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool1->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
- pool1->AddQueue(base::TimeTicks(), second_queue->GetTaskQueue());
+ pool1->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
+ pool1->AddQueue(base::TimeTicks(), GetTaskQueue(second_queue.get()));
CPUTimeBudgetPool* pool2 =
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool2->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.01);
- pool2->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool2->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
- task_queue_throttler_->IncreaseThrottleRefCount(second_queue->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(second_queue.get()));
timer_task_runner_->PostTask(
FROM_HERE,
@@ -1225,7 +1279,7 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest, TwoBudgetPools) {
base::TimeTicks() + base::TimeDelta::FromMilliseconds(26000)));
wake_up_budget_pool_->RemoveQueue(test_task_runner_->NowTicks(),
- second_queue->GetTaskQueue());
+ GetTaskQueue(second_queue.get()));
}
namespace {
@@ -1258,7 +1312,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -1288,7 +1343,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -1321,7 +1377,8 @@ TEST_P(TaskQueueThrottlerWithAutoAdvancingTimeTest,
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -1352,7 +1409,8 @@ TEST_F(TaskQueueThrottlerTest,
// of one-minute.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
WakeUpBudgetPool* one_minute_pool = wake_up_budget_pool_;
scoped_refptr<base::SingleThreadTaskRunner> one_minute_task_runner =
timer_task_runner_;
@@ -1371,11 +1429,11 @@ TEST_F(TaskQueueThrottlerTest,
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
two_minutes_pool->AddQueue(base::TimeTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
scoped_refptr<base::SingleThreadTaskRunner> two_minutes_task_runner =
two_minutes_queue->GetTaskRunnerWithDefaultTaskType();
task_queue_throttler_->IncreaseThrottleRefCount(
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
// Post a task with a short delay to the first queue.
constexpr base::TimeDelta kShortDelay = base::TimeDelta::FromSeconds(1);
@@ -1418,7 +1476,7 @@ TEST_F(TaskQueueThrottlerTest,
// Clean up.
two_minutes_pool->RemoveQueue(test_task_runner_->NowTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
two_minutes_pool->Close();
}
@@ -1426,7 +1484,8 @@ TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_MultiplePoolsWithDifferentIntervals) {
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
WakeUpBudgetPool* one_minute_pool = wake_up_budget_pool_;
scoped_refptr<base::SingleThreadTaskRunner> one_minute_task_runner =
timer_task_runner_;
@@ -1444,11 +1503,11 @@ TEST_F(TaskQueueThrottlerTest,
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
two_minutes_pool->AddQueue(base::TimeTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
scoped_refptr<base::SingleThreadTaskRunner> two_minutes_task_runner =
two_minutes_queue->GetTaskRunnerWithDefaultTaskType();
task_queue_throttler_->IncreaseThrottleRefCount(
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
// Post tasks with a short delay to both queues.
constexpr base::TimeDelta kShortDelay = base::TimeDelta::FromSeconds(1);
@@ -1492,7 +1551,7 @@ TEST_F(TaskQueueThrottlerTest,
// Clean up.
two_minutes_pool->RemoveQueue(test_task_runner_->NowTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
two_minutes_pool->Close();
}
@@ -1505,7 +1564,8 @@ TEST_F(TaskQueueThrottlerTest,
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
wake_up_budget_pool_->AllowUnalignedWakeUpIfNoRecentWakeUp();
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
WakeUpBudgetPool* one_minute_pool = wake_up_budget_pool_;
scoped_refptr<base::SingleThreadTaskRunner> one_minute_task_runner =
timer_task_runner_;
@@ -1524,11 +1584,11 @@ TEST_F(TaskQueueThrottlerTest,
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
two_minutes_pool->AddQueue(base::TimeTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
scoped_refptr<base::SingleThreadTaskRunner> two_minutes_task_runner =
two_minutes_queue->GetTaskRunnerWithDefaultTaskType();
task_queue_throttler_->IncreaseThrottleRefCount(
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
// Post tasks with short delays to both queues. They should run unaligned. The
// wake up in |one_minute_pool| should not be taken into account when
@@ -1601,7 +1661,7 @@ TEST_F(TaskQueueThrottlerTest,
// Clean up.
two_minutes_pool->RemoveQueue(test_task_runner_->NowTicks(),
- two_minutes_queue->GetTaskQueue());
+ GetTaskQueue(two_minutes_queue.get()));
two_minutes_pool->Close();
}
@@ -1614,7 +1674,8 @@ TEST_F(TaskQueueThrottlerTest,
// The 1st WakeUpBudgetPool doesn't allow unaligned wake ups.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
WakeUpBudgetPool* aligned_pool = wake_up_budget_pool_;
scoped_refptr<base::SingleThreadTaskRunner> aligned_task_runner =
timer_task_runner_;
@@ -1632,11 +1693,12 @@ TEST_F(TaskQueueThrottlerTest,
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true));
- unaligned_pool->AddQueue(base::TimeTicks(), unaligned_queue->GetTaskQueue());
+ unaligned_pool->AddQueue(base::TimeTicks(),
+ GetTaskQueue(unaligned_queue.get()));
scoped_refptr<base::SingleThreadTaskRunner> unaligned_task_runner =
unaligned_queue->GetTaskRunnerWithDefaultTaskType();
task_queue_throttler_->IncreaseThrottleRefCount(
- unaligned_queue->GetTaskQueue());
+ GetTaskQueue(unaligned_queue.get()));
// Post tasks with short delays to both queues. The 1st task should run
// aligned, while the 2nd task should run unaligned.
@@ -1711,7 +1773,7 @@ TEST_F(TaskQueueThrottlerTest,
// Clean up.
unaligned_pool->RemoveQueue(test_task_runner_->NowTicks(),
- unaligned_queue->GetTaskQueue());
+ GetTaskQueue(unaligned_queue.get()));
unaligned_pool->Close();
}
@@ -1724,7 +1786,8 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_EnableDisableThrottling) {
wake_up_budget_pool_->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(1));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
@@ -1774,7 +1837,8 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_UnalignedWakeUps) {
const base::TimeTicks start_time = test_task_runner_->NowTicks();
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
@@ -1799,7 +1863,8 @@ TEST_F(TaskQueueThrottlerTest,
base::TimeDelta::FromMinutes(1));
wake_up_budget_pool_->AllowUnalignedWakeUpIfNoRecentWakeUp();
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Task delay: Expected run time: Reason:
// 30 seconds 30 seconds >= 60 seconds after last wake up
// 80 seconds 90 seconds >= 60 seconds after last wake up
@@ -1838,7 +1903,8 @@ TEST_F(TaskQueueThrottlerTest,
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_IncreaseWakeUpIntervalBeforeWakeUp) {
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post 2 delayed tasks when the wake up interval is 1 minute. The delay of
// the 2nd task is such that it won't be ready when the 1st task completes.
@@ -1865,7 +1931,8 @@ TEST_F(TaskQueueThrottlerTest,
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_DecreaseWakeUpIntervalBeforeWakeUp) {
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post a delayed task when the wake up interval is 1 hour.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
@@ -1891,7 +1958,8 @@ TEST_F(TaskQueueThrottlerTest,
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post a 1st delayed task when the wake up interval is 1 minute.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
@@ -1930,7 +1998,8 @@ TEST_F(TaskQueueThrottlerTest,
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
// Post a 1st delayed task when the wake up interval is 1 hour.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
@@ -1973,11 +2042,12 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottlingWithCPUBudgetThrottling) {
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
Deque<base::TimeDelta> task_durations =
MakeTaskDurations(9, base::TimeDelta());
@@ -2015,7 +2085,7 @@ TEST_F(TaskQueueThrottlerTest,
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.1);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
Vector<base::TimeTicks> run_times;
@@ -2032,11 +2102,11 @@ TEST_F(TaskQueueThrottlerTest,
if (is_throttled) {
task_queue_throttler_->DecreaseThrottleRefCount(
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
is_throttled = false;
} else {
task_queue_throttler_->IncreaseThrottleRefCount(
- timer_queue_->GetTaskQueue());
+ GetTaskQueue(timer_queue_.get()));
is_throttled = true;
}
@@ -2074,11 +2144,12 @@ TEST_F(TaskQueueThrottlerTest,
task_queue_throttler_->CreateCPUTimeBudgetPool("test");
pool->SetTimeBudgetRecoveryRate(base::TimeTicks(), 0.01);
- pool->AddQueue(base::TimeTicks(), timer_queue_->GetTaskQueue());
+ pool->AddQueue(base::TimeTicks(), GetTaskQueue(timer_queue_.get()));
Vector<base::TimeTicks> run_times;
- task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_->GetTaskQueue());
+ task_queue_throttler_->IncreaseThrottleRefCount(
+ GetTaskQueue(timer_queue_.get()));
timer_task_runner_->PostDelayedTask(
FROM_HERE,
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
index fd01c578696..e21746fd9b9 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
@@ -122,27 +122,19 @@ void WakeUpBudgetPool::OnWakeUp(base::TimeTicks now) {
last_wake_up_ = now;
}
-void WakeUpBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const {
- auto dictionary_scope = state->BeginDictionaryScoped(name_);
-
- state->SetString("name", name_);
- state->SetDouble("wake_up_interval_in_seconds",
- wake_up_interval_.InSecondsF());
- state->SetDouble("wake_up_duration_in_seconds",
- wake_up_duration_.InSecondsF());
- if (last_wake_up_) {
- state->SetDouble("last_wake_up_seconds_ago",
- (now - last_wake_up_.value()).InSecondsF());
- }
- state->SetBoolean("is_enabled", is_enabled_);
+void WakeUpBudgetPool::WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const {
+ auto dict = std::move(context).WriteDictionary();
- {
- auto array_scope = state->BeginArrayScoped("task_queues");
- for (TaskQueue* queue : associated_task_queues_) {
- state->AppendString(PointerToString(queue));
- }
+ dict.Add("name", name_);
+ dict.Add("wake_up_interval_in_seconds", wake_up_interval_.InSecondsF());
+ dict.Add("wake_up_duration_in_seconds", wake_up_duration_.InSecondsF());
+ if (last_wake_up_) {
+ dict.Add("last_wake_up_seconds_ago",
+ (now - last_wake_up_.value()).InSecondsF());
}
+ dict.Add("is_enabled", is_enabled_);
+ dict.Add("task_queues", associated_task_queues_);
}
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h
index 276ffa349b8..a99046a43a1 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h
@@ -51,8 +51,8 @@ class PLATFORM_EXPORT WakeUpBudgetPool : public BudgetPool {
base::TimeTicks now,
base::TimeTicks desired_run_time) final;
void OnWakeUp(base::TimeTicks now) final;
- void AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const final;
+ void WriteIntoTracedValue(perfetto::TracedValue context,
+ base::TimeTicks now) const final;
base::Optional<base::TimeTicks> last_wake_up_for_testing() const {
return last_wake_up_;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
index 0f018531bd6..893a918e724 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
namespace blink {
namespace scheduler {
@@ -30,12 +29,6 @@ void ValidateTracingCategory(const char* category) {
} // namespace internal
-std::string PointerToString(const void* pointer) {
- return base::StringPrintf(
- "0x%" PRIx64,
- static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer)));
-}
-
double TimeDeltaToMilliseconds(const base::TimeDelta& value) {
return value.InMillisecondsF();
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
index 7ddc548946f..ba5136874ef 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/perfetto/include/perfetto/tracing/event_context.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
@@ -43,8 +44,6 @@ PLATFORM_EXPORT void ValidateTracingCategory(const char* category);
} // namespace internal
-PLATFORM_EXPORT std::string PointerToString(const void* pointer);
-
PLATFORM_EXPORT double TimeDeltaToMilliseconds(const base::TimeDelta& value);
PLATFORM_EXPORT const char* YesNoStateToString(bool is_yes);
@@ -186,6 +185,13 @@ class TraceableState : public TraceableVariable, private StateTracer<category> {
void OnTraceLogEnabled() final { Trace(); }
+ // TraceableState<T> is serialisable into trace iff T is serialisable.
+ template <typename V = T>
+ typename perfetto::check_traced_value_support<V>::type WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ perfetto::WriteIntoTracedValue(std::move(context), get());
+ }
+
protected:
void Assign(T new_state) {
if (state_ != new_state) {
@@ -248,7 +254,7 @@ class ProtoStateTracer {
if (!is_enabled())
return;
- TRACE_EVENT_BEGIN(category, name_, trace_track,
+ TRACE_EVENT_BEGIN(category, perfetto::StaticString{name_}, trace_track,
[value](perfetto::EventContext ctx) {
value->AsProtozeroInto(ctx.event());
});
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
index f3e25b200bf..ca8b165293b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
@@ -39,10 +39,8 @@ WebThreadScheduler::CreateMainThreadScheduler(
std::move(message_pump), std::move(settings))
: base::sequence_manager::CreateSequenceManagerOnCurrentThread(
std::move(settings));
- std::unique_ptr<MainThreadSchedulerImpl> scheduler(
- new MainThreadSchedulerImpl(std::move(sequence_manager),
- initial_virtual_time));
- return std::move(scheduler);
+ return std::make_unique<MainThreadSchedulerImpl>(std::move(sequence_manager),
+ initial_virtual_time);
}
// static
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc
index 0aacf6d7ce6..5acdacb3058 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.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/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h"
@@ -25,19 +26,34 @@ MainThreadTaskQueue::QueueCreationParams DefaultTaskQueueCreationParams(
.SetAgentGroupScheduler(agent_group_scheduler_impl);
}
+MainThreadTaskQueue::QueueCreationParams CompositorTaskRunnerCreationParams(
+ AgentGroupSchedulerImpl* agent_group_scheduler_impl) {
+ return MainThreadTaskQueue::QueueCreationParams(
+ MainThreadTaskQueue::QueueType::kCompositor)
+ .SetShouldMonitorQuiescence(true)
+ .SetPrioritisationType(
+ MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor)
+ .SetAgentGroupScheduler(agent_group_scheduler_impl);
+}
+
AgentGroupSchedulerImpl::AgentGroupSchedulerImpl(
MainThreadSchedulerImpl& main_thread_scheduler)
: default_task_queue_(main_thread_scheduler.NewTaskQueue(
DefaultTaskQueueCreationParams(this))),
default_task_runner_(default_task_queue_->CreateTaskRunner(
TaskType::kMainThreadTaskQueueDefault)),
+ compositor_task_queue_(main_thread_scheduler.NewTaskQueue(
+ CompositorTaskRunnerCreationParams(this))),
+ compositor_task_runner_(compositor_task_queue_->CreateTaskRunner(
+ TaskType::kMainThreadTaskQueueCompositor)),
main_thread_scheduler_(main_thread_scheduler) {
DCHECK(!default_task_queue_->GetFrameScheduler());
DCHECK_EQ(default_task_queue_->GetAgentGroupScheduler(), this);
}
AgentGroupSchedulerImpl::~AgentGroupSchedulerImpl() {
- default_task_queue_->ShutdownTaskQueue();
+ default_task_queue_->DetachFromMainThreadScheduler();
+ compositor_task_queue_->DetachFromMainThreadScheduler();
main_thread_scheduler_.RemoveAgentGroupScheduler(this);
}
@@ -48,9 +64,46 @@ std::unique_ptr<PageScheduler> AgentGroupSchedulerImpl::CreatePageScheduler(
return page_scheduler;
}
+scoped_refptr<base::SingleThreadTaskRunner>
+AgentGroupSchedulerImpl::DefaultTaskRunner() {
+ return default_task_runner_;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AgentGroupSchedulerImpl::CompositorTaskRunner() {
+ if (main_thread_scheduler_.scheduling_settings()
+ .mbi_compositor_task_runner_per_agent_scheduling_group) {
+ return compositor_task_runner_;
+ }
+ // We temporarily redirect the per-AGS compositor task runner to the main
+ // thread's compositor task runner.
+ return main_thread_scheduler_.CompositorTaskRunner();
+}
+
+scoped_refptr<MainThreadTaskQueue>
+AgentGroupSchedulerImpl::CompositorTaskQueue() {
+ return compositor_task_queue_;
+}
+
+WebThreadScheduler& AgentGroupSchedulerImpl::GetMainThreadScheduler() {
+ return main_thread_scheduler_;
+}
+
AgentGroupScheduler& AgentGroupSchedulerImpl::AsAgentGroupScheduler() {
return *this;
}
+void AgentGroupSchedulerImpl::BindInterfaceBroker(
+ mojo::PendingRemote<mojom::BrowserInterfaceBroker> remote_broker) {
+ DCHECK(!broker_.is_bound());
+ broker_.Bind(std::move(remote_broker), default_task_runner_);
+}
+
+BrowserInterfaceBrokerProxy&
+AgentGroupSchedulerImpl::GetBrowserInterfaceBroker() {
+ DCHECK(broker_.is_bound());
+ return broker_;
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h
index 01dbd8588ba..7ea89714fdb 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h
@@ -6,6 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_AGENT_GROUP_SCHEDULER_IMPL_H_
#include "base/memory/scoped_refptr.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h"
@@ -17,6 +20,7 @@ namespace blink {
namespace scheduler {
class MainThreadSchedulerImpl;
class MainThreadTaskQueue;
+class WebThreadScheduler;
// AgentGroupScheduler implementation which schedules per-AgentSchedulingGroup
// tasks.
@@ -30,18 +34,25 @@ class PLATFORM_EXPORT AgentGroupSchedulerImpl : public AgentGroupScheduler {
std::unique_ptr<PageScheduler> CreatePageScheduler(
PageScheduler::Delegate*) override;
- scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override {
- return default_task_runner_;
- }
- MainThreadSchedulerImpl& GetMainThreadScheduler() {
- return main_thread_scheduler_;
- }
+ scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override;
+ scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
+ scoped_refptr<MainThreadTaskQueue> CompositorTaskQueue();
+ WebThreadScheduler& GetMainThreadScheduler() override;
AgentGroupScheduler& AsAgentGroupScheduler() override;
+ void BindInterfaceBroker(
+ mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker> remote_broker)
+ override;
+ BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() override;
+
private:
scoped_refptr<MainThreadTaskQueue> default_task_queue_;
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
MainThreadSchedulerImpl& main_thread_scheduler_; // Not owned.
+
+ BrowserInterfaceBrokerProxy broker_;
};
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
index 9a4538263ee..d41bc4ea90e 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
@@ -36,6 +36,7 @@ class AutoAdvancingVirtualTimeDomainTest : public testing::Test {
nullptr, test_task_runner_, test_task_runner_->GetMockTickClock());
scheduler_helper_.reset(new NonMainThreadSchedulerHelper(
sequence_manager_.get(), nullptr, TaskType::kInternalTest));
+ scheduler_helper_->AttachToCurrentThread();
scheduler_helper_->AddTaskTimeObserver(&test_task_time_observer_);
task_queue_ = scheduler_helper_->DefaultNonMainThreadTaskQueue();
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
index 0a455119137..1954d462f81 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
@@ -182,7 +182,7 @@ CompositorPriorityExperiments::CompositorBudgetPoolController::
"CompositorBudgetPool", this, tracing_controller, now));
compositor_budget_pool_->SetMinBudgetLevelToRun(now, min_budget);
compositor_budget_pool_->SetTimeBudgetRecoveryRate(now, budget_recovery_rate);
- compositor_budget_pool_->AddQueue(now, compositor_queue->GetTaskQueue());
+ compositor_queue->AddToBudgetPool(now, compositor_budget_pool_.get());
}
CompositorPriorityExperiments::CompositorBudgetPoolController::
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index ff5aeb81906..1c15019931b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -14,10 +14,14 @@
#include "base/task/sequence_manager/lazy_now.h"
#include "base/time/time.h"
#include "base/trace_event/blame_context.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
#include "third_party/blink/public/platform/blame_context.h"
#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/common/features.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
@@ -31,6 +35,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/web_scheduling_task_queue_impl.h"
#include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
@@ -189,7 +194,10 @@ FrameSchedulerImpl::FrameSchedulerImpl(
waiting_for_meaningful_paint_(true,
"FrameScheduler.WaitingForMeaningfulPaint",
&tracing_controller_,
- YesNoStateToString) {
+ YesNoStateToString),
+ loading_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Loading")) {
frame_task_queue_controller_.reset(
new FrameTaskQueueController(main_thread_scheduler_, this, this));
}
@@ -384,18 +392,16 @@ QueueTraits FrameSchedulerImpl::CreateQueueTraitsForTaskType(TaskType type) {
QueueTraits::PrioritisationType::kJavaScriptTimer)
.SetCanBeIntensivelyThrottled(IsIntensiveWakeUpThrottlingEnabled());
case TaskType::kJavascriptTimerImmediate: {
- return DeferrableTaskQueueTraits()
- .SetPrioritisationType(
- QueueTraits::PrioritisationType::kJavaScriptTimer)
- .SetCanBeThrottled(!base::FeatureList::IsEnabled(
- features::kOptOutZeroTimeoutTimersFromThrottling));
+ // Immediate timers are not throttled.
+ return DeferrableTaskQueueTraits().SetPrioritisationType(
+ QueueTraits::PrioritisationType::kJavaScriptTimer);
}
case TaskType::kInternalLoading:
case TaskType::kNetworking:
case TaskType::kNetworkingWithURLLoaderAnnotation:
return LoadingTaskQueueTraits();
case TaskType::kNetworkingUnfreezable:
- return base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)
+ return IsInflightNetworkRequestBackForwardCacheSupportEnabled()
? UnfreezableLoadingTaskQueueTraits()
: LoadingTaskQueueTraits();
case TaskType::kNetworkingControl:
@@ -425,6 +431,7 @@ QueueTraits FrameSchedulerImpl::CreateQueueTraitsForTaskType(TaskType type) {
case TaskType::kApplicationLifeCycle:
case TaskType::kBackgroundFetch:
case TaskType::kPermission:
+ case TaskType::kWakeLock:
// TODO(altimin): Move appropriate tasks to throttleable task queue.
return DeferrableTaskQueueTraits();
// PostedMessage can be used for navigation, so we shouldn't defer it
@@ -612,9 +619,14 @@ void FrameSchedulerImpl::DidCommitProvisionalLoad(
bool is_same_document = navigation_type == NavigationType::kSameDocument;
if (!is_same_document) {
+ loading_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kLoading);
+ loading_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kLoadingTimeout);
+
waiting_for_contentful_paint_ = true;
waiting_for_meaningful_paint_ = true;
}
+
if (is_main_frame && !is_same_document) {
task_time_ = base::TimeDelta();
// Ignore result here, based on the assumption that
@@ -670,7 +682,7 @@ void FrameSchedulerImpl::OnStartedUsingFeature(
"renderer.scheduler", "ActiveSchedulerTrackedFeature",
TRACE_ID_LOCAL(reinterpret_cast<intptr_t>(this) ^
static_cast<int>(feature)),
- "feature", FeatureToString(feature));
+ "feature", FeatureToHumanReadableString(feature));
}
}
@@ -773,32 +785,22 @@ void FrameSchedulerImpl::OnRemovedBackForwardCacheOptOut(
!back_forward_cache_opt_out_counts_.empty();
}
-void FrameSchedulerImpl::AsValueInto(
- base::trace_event::TracedValue* state) const {
- state->SetBoolean("frame_visible", frame_visible_);
- state->SetBoolean("page_visible", parent_page_scheduler_->IsPageVisible());
- state->SetBoolean("cross_origin_to_main_frame", IsCrossOriginToMainFrame());
- state->SetString("frame_type",
- frame_type_ == FrameScheduler::FrameType::kMainFrame
- ? "MainFrame"
- : "Subframe");
- state->SetBoolean(
- "disable_background_timer_throttling",
- !RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled());
-
- {
- auto dictionary_scope =
- state->BeginDictionaryScoped("frame_task_queue_controller");
- frame_task_queue_controller_->AsValueInto(state);
- }
+void FrameSchedulerImpl::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("frame_visible", frame_visible_);
+ dict.Add("page_visible", parent_page_scheduler_->IsPageVisible());
+ dict.Add("cross_origin_to_main_frame", IsCrossOriginToMainFrame());
+ dict.Add("frame_type", frame_type_ == FrameScheduler::FrameType::kMainFrame
+ ? "MainFrame"
+ : "Subframe");
+ dict.Add("disable_background_timer_throttling",
+ !RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled());
- if (blame_context_) {
- auto dictionary_scope = state->BeginDictionaryScoped("blame_context");
- state->SetString(
- "id_ref",
- PointerToString(reinterpret_cast<void*>(blame_context_->id())));
- state->SetString("scope", blame_context_->scope());
- }
+ dict.Add("frame_task_queue_controller", frame_task_queue_controller_);
+
+ if (blame_context_)
+ dict.Add("blame_context", blame_context_);
}
void FrameSchedulerImpl::SetPageVisibilityForTracing(
@@ -845,12 +847,17 @@ void FrameSchedulerImpl::UpdatePolicy() {
bool task_queues_were_throttled = task_queues_throttled_;
task_queues_throttled_ = ShouldThrottleTaskQueues();
+ if (!task_queues_throttled_)
+ throttled_task_queue_handles_.clear();
+
for (const auto& task_queue_and_voter :
frame_task_queue_controller_->GetAllTaskQueuesAndVoters()) {
UpdateQueuePolicy(task_queue_and_voter.first, task_queue_and_voter.second);
- if (task_queues_were_throttled != task_queues_throttled_) {
- UpdateTaskQueueThrottling(task_queue_and_voter.first,
- task_queues_throttled_);
+ if (task_queues_throttled_ && !task_queues_were_throttled &&
+ task_queue_and_voter.first->CanBeThrottled()) {
+ MainThreadTaskQueue::ThrottleHandle handle =
+ task_queue_and_voter.first->Throttle();
+ throttled_task_queue_handles_.push_back(std::move(handle));
}
}
@@ -937,6 +944,8 @@ void FrameSchedulerImpl::OnLoad() {
// update.
main_thread_scheduler_->OnMainFrameLoad(*this);
}
+
+ loading_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kIdle);
}
bool FrameSchedulerImpl::IsWaitingForContentfulPaint() const {
@@ -962,24 +971,14 @@ bool FrameSchedulerImpl::ShouldThrottleTaskQueues() const {
return false;
if (!parent_page_scheduler_->IsPageVisible())
return true;
+ if (base::FeatureList::IsEnabled(kThrottleVisibleNotFocusedTimers) &&
+ !parent_page_scheduler_->IsPageFocused()) {
+ return true;
+ }
return RuntimeEnabledFeatures::TimerThrottlingForHiddenFramesEnabled() &&
!frame_visible_ && IsCrossOriginToMainFrame();
}
-void FrameSchedulerImpl::UpdateTaskQueueThrottling(
- MainThreadTaskQueue* task_queue,
- bool should_throttle) {
- if (!task_queue->CanBeThrottled())
- return;
- if (should_throttle) {
- main_thread_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
- task_queue->GetTaskQueue());
- } else {
- main_thread_scheduler_->task_queue_throttler()->DecreaseThrottleRefCount(
- task_queue->GetTaskQueue());
- }
-}
-
bool FrameSchedulerImpl::IsExemptFromBudgetBasedThrottling() const {
return opted_out_from_aggressive_throttling();
}
@@ -1214,7 +1213,8 @@ void FrameSchedulerImpl::OnTaskQueueCreated(
task_queue, frame_origin_type_, &lazy_now);
if (task_queues_throttled_) {
- UpdateTaskQueueThrottling(task_queue, true);
+ MainThreadTaskQueue::ThrottleHandle handle = task_queue->Throttle();
+ throttled_task_queue_handles_.push_back(std::move(handle));
}
}
}
@@ -1349,8 +1349,7 @@ MainThreadTaskQueue::QueueTraits
FrameSchedulerImpl::DeferrableTaskQueueTraits() {
return QueueTraits()
.SetCanBeDeferred(true)
- .SetCanBeFrozen(base::FeatureList::IsEnabled(
- blink::features::kStopNonTimersInBackground))
+ .SetCanBeFrozen(true)
.SetCanBePaused(true)
.SetCanRunWhenVirtualTimePaused(false)
.SetCanBePausedForAndroidWebview(true);
@@ -1359,8 +1358,7 @@ FrameSchedulerImpl::DeferrableTaskQueueTraits() {
// static
MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::PausableTaskQueueTraits() {
return QueueTraits()
- .SetCanBeFrozen(base::FeatureList::IsEnabled(
- blink::features::kStopNonTimersInBackground))
+ .SetCanBeFrozen(true)
.SetCanBePaused(true)
.SetCanRunWhenVirtualTimePaused(false)
.SetCanBePausedForAndroidWebview(true);
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 66abb4e0dc5..f9d874d1b9d 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -18,6 +18,7 @@
#include "base/single_thread_task_runner.h"
#include "base/task/sequence_manager/task_queue.h"
#include "base/trace_event/trace_event.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "net/base/request_priority.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -32,6 +33,7 @@
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
#include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace sequence_manager {
@@ -39,7 +41,6 @@ class TaskQueue;
} // namespace sequence_manager
namespace trace_event {
class BlameContext;
-class TracedValue;
} // namespace trace_event
} // namespace base
@@ -132,7 +133,6 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler,
// created by an SVGImage). Virtual for testing.
virtual bool IsOrdinary() const;
- void AsValueInto(base::trace_event::TracedValue* state) const;
bool IsExemptFromBudgetBasedThrottling() const override;
std::unique_ptr<blink::mojom::blink::PauseSubresourceLoadingHandle>
GetPauseSubresourceLoadingHandle() override;
@@ -203,6 +203,8 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler,
const base::UnguessableToken& GetAgentClusterId() const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
protected:
FrameSchedulerImpl(MainThreadSchedulerImpl* main_thread_scheduler,
PageSchedulerImpl* parent_page_scheduler,
@@ -258,11 +260,6 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler,
void UpdateQueuePolicy(
MainThreadTaskQueue* queue,
base::sequence_manager::TaskQueue::QueueEnabledVoter* voter);
- // Update throttling for |task_queue|. This changes the throttling ref counts
- // and should only be called for new queues if throttling is enabled, or if
- // the throttling state changes.
- void UpdateTaskQueueThrottling(MainThreadTaskQueue* task_queue,
- bool should_throttle);
void AddPauseSubresourceLoadingHandle();
void RemovePauseSubresourceLoadingHandle();
@@ -341,6 +338,7 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler,
TraceableState<bool, TracingCategoryName::kInfo> subresource_loading_paused_;
StateTracer<TracingCategoryName::kInfo> url_tracer_;
TraceableState<bool, TracingCategoryName::kInfo> task_queues_throttled_;
+ Vector<MainThreadTaskQueue::ThrottleHandle> throttled_task_queue_handles_;
TraceableState<bool, TracingCategoryName::kInfo>
preempted_for_cooperative_scheduling_;
// TODO(https://crbug.com/827113): Trace the count of opt-outs.
@@ -376,6 +374,8 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler,
TraceableState<bool, TracingCategoryName::kInfo>
waiting_for_meaningful_paint_;
+ std::unique_ptr<power_scheduler::PowerModeVoter> loading_power_mode_voter_;
+
// TODO(altimin): Remove after we have have 1:1 relationship between frames
// and documents.
base::WeakPtrFactory<FrameSchedulerImpl> document_bound_weak_factory_{this};
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index e076b0a5b53..6338f29ec7f 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/renderer/platform/scheduler/common/features.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
@@ -143,10 +144,11 @@ constexpr TaskType kAllFrameTaskTypes[] = {
TaskType::kInternalTranslation,
TaskType::kInternalInspector,
TaskType::kInternalNavigationAssociatedUnfreezable,
- TaskType::kInternalHighPriorityLocalFrame};
+ TaskType::kInternalHighPriorityLocalFrame,
+ TaskType::kWakeLock};
static_assert(
- static_cast<int>(TaskType::kCount) == 76,
+ static_cast<int>(TaskType::kCount) == 77,
"When adding a TaskType, make sure that kAllFrameTaskTypes is updated.");
void AppendToVectorTestTask(Vector<String>* vector, String value) {
@@ -288,6 +290,52 @@ class FrameSchedulerImplTest : public testing::Test {
}
}
+ // Helper for posting several tasks to specific queues. |task_descriptor| is a
+ // string with space delimited task identifiers. The first letter of each task
+ // identifier specifies the task queue:
+ // - 'L': Loading task queue
+ // - 'T': Throttleable task queue
+ // - 'P': Pausable task queue
+ // - 'U': Unpausable task queue
+ // - 'D': Deferrable task queue
+ void PostTestTasksToQueuesWithTrait(Vector<String>* run_order,
+ const String& task_descriptor) {
+ std::istringstream stream(task_descriptor.Utf8());
+ while (!stream.eof()) {
+ std::string task;
+ stream >> task;
+ switch (task[0]) {
+ case 'L':
+ LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
+ FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+ String::FromUTF8(task)));
+ break;
+ case 'T':
+ ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
+ FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+ String::FromUTF8(task)));
+ break;
+ case 'P':
+ PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
+ FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+ String::FromUTF8(task)));
+ break;
+ case 'U':
+ UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
+ FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+ String::FromUTF8(task)));
+ break;
+ case 'D':
+ DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
+ FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+ String::FromUTF8(task)));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ }
+
static void ResetForNavigation(FrameSchedulerImpl* frame_scheduler) {
frame_scheduler->ResetForNavigation();
}
@@ -390,14 +438,12 @@ class FrameSchedulerImplTest : public testing::Test {
bool IsThrottled() {
EXPECT_TRUE(throttleable_task_queue());
- return scheduler_->task_queue_throttler()->IsThrottled(
- throttleable_task_queue()->GetTaskQueue());
+ return throttleable_task_queue()->IsThrottled();
}
bool IsTaskTypeThrottled(TaskType task_type) {
scoped_refptr<MainThreadTaskQueue> task_queue = GetTaskQueue(task_type);
- return scheduler_->task_queue_throttler()->IsThrottled(
- task_queue->GetTaskQueue());
+ return task_queue->IsThrottled();
}
SchedulingLifecycleState CalculateLifecycleState(
@@ -430,22 +476,6 @@ class FrameSchedulerImplTest : public testing::Test {
scoped_refptr<MainThreadTaskQueue> throttleable_task_queue_;
};
-class FrameSchedulerImplStopNonTimersInBackgroundEnabledTest
- : public FrameSchedulerImplTest {
- public:
- FrameSchedulerImplStopNonTimersInBackgroundEnabledTest()
- : FrameSchedulerImplTest({blink::features::kStopNonTimersInBackground},
- {}) {}
-};
-
-class FrameSchedulerImplStopNonTimersInBackgroundDisabledTest
- : public FrameSchedulerImplTest {
- public:
- FrameSchedulerImplStopNonTimersInBackgroundDisabledTest()
- : FrameSchedulerImplTest({},
- {blink::features::kStopNonTimersInBackground}) {}
-};
-
class FrameSchedulerImplStopInBackgroundDisabledTest
: public FrameSchedulerImplTest,
public ::testing::WithParamInterface<TaskType> {
@@ -505,10 +535,6 @@ void IncrementCounter(int* counter) {
++*counter;
}
-void RecordQueueName(String name, Vector<String>* tasks) {
- tasks->push_back(std::move(name));
-}
-
// Simulate running a task of a particular length by fast forwarding the task
// environment clock, which is used to determine the wall time of a task.
void RunTaskOfLength(base::test::TaskEnvironment* task_environment,
@@ -857,8 +883,7 @@ TEST_F(FrameSchedulerImplTest, FreezeForegroundOnlyTasks) {
EXPECT_EQ(1, counter);
}
-TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest,
- PageFreezeAndUnfreezeFlagEnabled) {
+TEST_F(FrameSchedulerImplTest, PageFreezeAndUnfreeze) {
int counter = 0;
LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
@@ -882,13 +907,13 @@ TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest,
page_scheduler_->SetPageFrozen(false);
EXPECT_EQ(1, counter);
- // Same as RunUntilIdle but also advances the clock if necessary.
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(5, counter);
}
-TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest,
- PageFreezeAndUnfreezeFlagDisabled) {
+// Similar to PageFreezeAndUnfreeze, but unfreezes task queues by making the
+// page visible instead of by invoking SetPageFrozen(false).
+TEST_F(FrameSchedulerImplTest, PageFreezeAndPageVisible) {
int counter = 0;
LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
@@ -906,13 +931,13 @@ TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest,
EXPECT_EQ(0, counter);
base::RunLoop().RunUntilIdle();
- // throttleable tasks and loading tasks are frozen, others continue to run.
- EXPECT_EQ(3, counter);
+ // unpausable tasks continue to run.
+ EXPECT_EQ(1, counter);
- page_scheduler_->SetPageFrozen(false);
+ // Making the page visible should cause frozen queues to resume.
+ page_scheduler_->SetPageVisible(true);
- EXPECT_EQ(3, counter);
- // Same as RunUntilIdle but also advances the clock if necessary.
+ EXPECT_EQ(1, counter);
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(5, counter);
}
@@ -980,27 +1005,7 @@ TEST_F(FrameSchedulerImplTest, FramePostsCpuTasksThroughReloadRenavigate) {
TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) {
Vector<String> tasks;
- LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks));
- ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- ThrottleableTaskQueue()->GetTaskQueue()->GetName(),
- &tasks));
- DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- DeferrableTaskQueue()->GetTaskQueue()->GetName(), &tasks));
- PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- PausableTaskQueue()->GetTaskQueue()->GetName(), &tasks));
- UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- UnpausableTaskQueue()->GetTaskQueue()->GetName(), &tasks));
+ PostTestTasksToQueuesWithTrait(&tasks, "L1 T1 D1 P1 U1");
page_scheduler_->SetKeepActive(true); // say we have a Service Worker
page_scheduler_->SetPageVisible(false);
@@ -1009,30 +1014,19 @@ TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) {
EXPECT_THAT(tasks, UnorderedElementsAre());
base::RunLoop().RunUntilIdle();
// Everything runs except throttleable tasks (timers)
- EXPECT_THAT(tasks,
- UnorderedElementsAre(
- String(LoadingTaskQueue()->GetTaskQueue()->GetName()),
- String(DeferrableTaskQueue()->GetTaskQueue()->GetName()),
- String(PausableTaskQueue()->GetTaskQueue()->GetName()),
- String(UnpausableTaskQueue()->GetTaskQueue()->GetName())));
+ EXPECT_THAT(tasks, UnorderedElementsAre("L1", "D1", "P1", "U1"));
tasks.clear();
- LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks));
+ PostTestTasksToQueuesWithTrait(&tasks, "L1");
EXPECT_THAT(tasks, UnorderedElementsAre());
base::RunLoop().RunUntilIdle();
// loading task runs
- EXPECT_THAT(tasks, UnorderedElementsAre(String(
- LoadingTaskQueue()->GetTaskQueue()->GetName())));
+ EXPECT_THAT(tasks, UnorderedElementsAre("L1"));
tasks.clear();
- LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE,
- base::BindOnce(&RecordQueueName,
- LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks));
+ PostTestTasksToQueuesWithTrait(&tasks, "L1");
+
// KeepActive is false when Service Worker stops.
page_scheduler_->SetKeepActive(false);
EXPECT_THAT(tasks, UnorderedElementsAre());
@@ -1044,37 +1038,7 @@ TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) {
EXPECT_THAT(tasks, UnorderedElementsAre());
base::RunLoop().RunUntilIdle();
// loading task runs
- EXPECT_THAT(tasks, UnorderedElementsAre(String(
- LoadingTaskQueue()->GetTaskQueue()->GetName())));
-}
-
-TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest,
- PageFreezeAndPageVisible) {
- int counter = 0;
- LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
- ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
- DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
- PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
- UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
- FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
-
- page_scheduler_->SetPageVisible(false);
- page_scheduler_->SetPageFrozen(true);
-
- EXPECT_EQ(0, counter);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, counter);
-
- // Making the page visible should cause frozen queues to resume.
- page_scheduler_->SetPageVisible(true);
-
- EXPECT_EQ(1, counter);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(5, counter);
+ EXPECT_THAT(tasks, UnorderedElementsAre("L1"));
}
class FrameSchedulerImplTestWithUnfreezableLoading
@@ -1082,7 +1046,9 @@ class FrameSchedulerImplTestWithUnfreezableLoading
public:
FrameSchedulerImplTestWithUnfreezableLoading()
: FrameSchedulerImplTest({blink::features::kLoadingTasksUnfreezable},
- {}) {}
+ {}) {
+ WebRuntimeFeatures::EnableBackForwardCache(true);
+ }
};
TEST_F(FrameSchedulerImplTestWithUnfreezableLoading,
@@ -2478,7 +2444,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut) {
auto feature_handle1 = frame_scheduler_->RegisterFeature(
SchedulingPolicy::Feature::kWebSocket,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
EXPECT_THAT(
frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(),
@@ -2489,7 +2455,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut) {
auto feature_handle2 = frame_scheduler_->RegisterFeature(
SchedulingPolicy::Feature::kWebRTC,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
EXPECT_THAT(
frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(),
@@ -2528,7 +2494,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut_FrameNavigated) {
auto feature_handle = frame_scheduler_->RegisterFeature(
SchedulingPolicy::Feature::kWebSocket,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
EXPECT_THAT(
frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(),
@@ -2539,7 +2505,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut_FrameNavigated) {
frame_scheduler_->RegisterStickyFeature(
SchedulingPolicy::Feature::kMainResourceHasCacheControlNoStore,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
EXPECT_THAT(
frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(),
@@ -2596,11 +2562,11 @@ TEST_F(FrameSchedulerImplTest, FeatureUpload) {
frame_scheduler->RegisterStickyFeature(
SchedulingPolicy::Feature::
kMainResourceHasCacheControlNoStore,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
frame_scheduler->RegisterStickyFeature(
SchedulingPolicy::Feature::
kMainResourceHasCacheControlNoCache,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
// Ensure that the feature upload is delayed.
testing::Mock::VerifyAndClearExpectations(delegate);
EXPECT_CALL(
@@ -2635,7 +2601,7 @@ TEST_F(FrameSchedulerImplTest, FeatureUpload_FrameDestruction) {
FeatureHandle* feature_handle) {
*feature_handle = frame_scheduler->RegisterFeature(
SchedulingPolicy::Feature::kWebSocket,
- {SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ {SchedulingPolicy::DisableBackForwardCache()});
// Ensure that the feature upload is delayed.
testing::Mock::VerifyAndClearExpectations(delegate);
EXPECT_CALL(*delegate,
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
index ced5549aa9f..6f161891430 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
@@ -17,6 +17,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/web_scheduling_task_queue_impl.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
namespace scheduler {
@@ -159,21 +160,11 @@ bool FrameTaskQueueController::RemoveResourceLoadingTaskQueue(
return true;
}
-void FrameTaskQueueController::AsValueInto(
- base::trace_event::TracedValue* state) const {
- {
- auto array_scope = state->BeginArrayScoped("task_queues");
- for (const auto& it : task_queues_) {
- state->AppendString(PointerToString(it.value.get()));
- }
- }
-
- {
- auto array_scope = state->BeginArrayScoped("resource_loading_task_queues");
- for (const auto& queue : resource_loading_task_queues_) {
- state->AppendString(PointerToString(queue.get()));
- }
- }
+void FrameTaskQueueController::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("task_queues", task_queues_.Values());
+ dict.Add("resource_loading_task_queues", resource_loading_task_queues_);
}
// static
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h
index 956a65b5967..163434b51b7 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h
@@ -18,6 +18,7 @@
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace sequence_manager {
@@ -95,7 +96,7 @@ class PLATFORM_EXPORT FrameTaskQueueController {
bool RemoveResourceLoadingTaskQueue(
const scoped_refptr<MainThreadTaskQueue>&);
- void AsValueInto(base::trace_event::TracedValue* state) const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
private:
friend class FrameTaskQueueControllerTest;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc
index ad03fa3f884..59211b1c5ad 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc
@@ -9,23 +9,16 @@
namespace blink {
namespace scheduler {
-IdleTimeEstimator::IdleTimeEstimator(
- const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
- const base::TickClock* time_source,
- int sample_count,
- double estimation_percentile)
- : compositor_task_queue_(compositor_task_runner),
- per_frame_compositor_task_runtime_(sample_count),
+IdleTimeEstimator::IdleTimeEstimator(const base::TickClock* time_source,
+ int sample_count,
+ double estimation_percentile)
+ : per_frame_compositor_task_runtime_(sample_count),
time_source_(time_source),
estimation_percentile_(estimation_percentile),
nesting_level_(0),
- did_commit_(false) {
- compositor_task_queue_->GetTaskQueue()->AddTaskObserver(this);
-}
+ did_commit_(false) {}
-IdleTimeEstimator::~IdleTimeEstimator() {
- compositor_task_queue_->GetTaskQueue()->RemoveTaskObserver(this);
-}
+IdleTimeEstimator::~IdleTimeEstimator() = default;
base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration(
base::TimeDelta compositor_frame_interval) const {
@@ -73,5 +66,15 @@ void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) {
}
}
+void IdleTimeEstimator::AddCompositorTaskQueue(
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue) {
+ compositor_task_queue->GetTaskQueue()->AddTaskObserver(this);
+}
+
+void IdleTimeEstimator::RemoveCompositorTaskQueue(
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue) {
+ compositor_task_queue->GetTaskQueue()->RemoveTaskObserver(this);
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
index db4b01b4edc..f6a962a4ca9 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
@@ -19,7 +19,6 @@ namespace scheduler {
class PLATFORM_EXPORT IdleTimeEstimator : public base::TaskObserver {
public:
IdleTimeEstimator(
- const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
const base::TickClock* time_source,
int sample_count,
double estimation_percentile);
@@ -40,8 +39,12 @@ class PLATFORM_EXPORT IdleTimeEstimator : public base::TaskObserver {
bool was_blocked_or_low_priority) override;
void DidProcessTask(const base::PendingTask& pending_task) override;
+ void AddCompositorTaskQueue(
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue);
+ void RemoveCompositorTaskQueue(
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue);
+
private:
- scoped_refptr<MainThreadTaskQueue> compositor_task_queue_;
cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_;
const base::TickClock* time_source_; // NOT OWNED
double estimation_percentile_;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
index 47d40f37d25..1023113f744 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
@@ -19,19 +19,6 @@
namespace blink {
namespace scheduler {
-class IdleTimeEstimatorForTest : public IdleTimeEstimator {
- public:
- IdleTimeEstimatorForTest(
- const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
- const base::TickClock* clock,
- int sample_count,
- double estimation_percentile)
- : IdleTimeEstimator(compositor_task_runner,
- clock,
- sample_count,
- estimation_percentile) {}
-};
-
class IdleTimeEstimatorTest : public testing::Test {
public:
IdleTimeEstimatorTest()
@@ -46,24 +33,30 @@ class IdleTimeEstimatorTest : public testing::Test {
manager_ = base::sequence_manager::SequenceManagerForTest::Create(
nullptr, task_environment_.GetMainThreadTaskRunner(),
task_environment_.GetMockTickClock());
- compositor_task_queue_ =
- manager_->CreateTaskQueueWithType<MainThreadTaskQueue>(
- base::sequence_manager::TaskQueue::Spec("test_tq"),
- MainThreadTaskQueue::QueueCreationParams(
- MainThreadTaskQueue::QueueType::kCompositor),
- nullptr);
- estimator_.reset(new IdleTimeEstimatorForTest(
- compositor_task_queue_, task_environment_.GetMockTickClock(), 10, 50));
+ estimator_ = std::make_unique<IdleTimeEstimator>(
+ task_environment_.GetMockTickClock(), 10, 50);
+ compositor_task_queue_1_ = NewTaskQueue();
+ compositor_task_queue_2_ = NewTaskQueue();
+ compositor_task_runner_1_ = compositor_task_queue_1_->CreateTaskRunner(
+ TaskType::kMainThreadTaskQueueCompositor);
+ compositor_task_runner_2_ = compositor_task_queue_2_->CreateTaskRunner(
+ TaskType::kMainThreadTaskQueueCompositor);
+ estimator_->AddCompositorTaskQueue(compositor_task_queue_1_);
+ estimator_->AddCompositorTaskQueue(compositor_task_queue_2_);
+ }
+
+ scoped_refptr<MainThreadTaskQueue> NewTaskQueue() {
+ return manager_->CreateTaskQueueWithType<MainThreadTaskQueue>(
+ base::sequence_manager::TaskQueue::Spec("test_tq"),
+ MainThreadTaskQueue::QueueCreationParams(
+ MainThreadTaskQueue::QueueType::kCompositor),
+ nullptr);
}
void SimulateFrameWithOneCompositorTask(int compositor_time) {
base::TimeDelta non_idle_time =
base::TimeDelta::FromMilliseconds(compositor_time);
- base::PendingTask task(FROM_HERE, base::OnceClosure());
- estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false);
- task_environment_.FastForwardBy(non_idle_time);
- estimator_->DidCommitFrameToCompositor();
- estimator_->DidProcessTask(task);
+ PostTask(compositor_task_runner_1_, compositor_time, /*commit=*/true);
if (non_idle_time < frame_length_)
task_environment_.FastForwardBy(frame_length_ - non_idle_time);
}
@@ -74,24 +67,37 @@ class IdleTimeEstimatorTest : public testing::Test {
base::TimeDelta::FromMilliseconds(compositor_time1);
base::TimeDelta non_idle_time2 =
base::TimeDelta::FromMilliseconds(compositor_time2);
- base::PendingTask task(FROM_HERE, base::OnceClosure());
- estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false);
- task_environment_.FastForwardBy(non_idle_time1);
- estimator_->DidProcessTask(task);
-
- estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false);
- task_environment_.FastForwardBy(non_idle_time2);
- estimator_->DidCommitFrameToCompositor();
- estimator_->DidProcessTask(task);
-
+ PostTask(compositor_task_runner_1_, compositor_time1, /*commit=*/false);
+ PostTask(compositor_task_runner_2_, compositor_time2, /*commit=*/true);
base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2;
task_environment_.FastForwardBy(idle_time);
}
+ void PostTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ int compositor_time,
+ bool commit) {
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ [](base::test::TaskEnvironment* task_environment,
+ IdleTimeEstimator* estimator, int compositor_time, bool commit) {
+ base::TimeDelta non_idle_time =
+ base::TimeDelta::FromMilliseconds(compositor_time);
+ task_environment->FastForwardBy(non_idle_time);
+ if (commit)
+ estimator->DidCommitFrameToCompositor();
+ },
+ &task_environment_, estimator_.get(), compositor_time, commit));
+ task_environment_.RunUntilIdle();
+ }
+
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::sequence_manager::SequenceManager> manager_;
- scoped_refptr<MainThreadTaskQueue> compositor_task_queue_;
- std::unique_ptr<IdleTimeEstimatorForTest> estimator_;
+ std::unique_ptr<IdleTimeEstimator> estimator_;
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue_1_;
+ scoped_refptr<MainThreadTaskQueue> compositor_task_queue_2_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_1_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_2_;
const base::TimeDelta frame_length_;
base::sequence_manager::TestTaskTimeObserver test_task_time_observer_;
};
@@ -148,6 +154,16 @@ TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) {
estimator_->GetExpectedIdleDuration(frame_length_));
}
+TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks_WithSingleObserver) {
+ // Observe only |compositor_task_queue_2_|
+ estimator_->RemoveCompositorTaskQueue(compositor_task_queue_1_);
+ SimulateFrameWithTwoCompositorTasks(1, 4);
+ SimulateFrameWithTwoCompositorTasks(1, 4);
+
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(12),
+ estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
TEST_F(IdleTimeEstimatorTest, IgnoresNestedTasks) {
SimulateFrameWithOneCompositorTask(5);
SimulateFrameWithOneCompositorTask(5);
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc
index 39602a63139..be2f8281775 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc
@@ -12,16 +12,10 @@ namespace blink {
namespace scheduler {
MainThread::MainThread(MainThreadSchedulerImpl* scheduler)
- : task_runner_(scheduler->DefaultTaskRunner()),
- scheduler_(scheduler),
- thread_id_(base::PlatformThread::CurrentId()) {}
+ : task_runner_(scheduler->DefaultTaskRunner()), scheduler_(scheduler) {}
MainThread::~MainThread() = default;
-blink::PlatformThreadId MainThread::ThreadId() const {
- return thread_id_;
-}
-
blink::ThreadScheduler* MainThread::Scheduler() {
return scheduler_;
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
index 6a382c287f8..a9054728a56 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
@@ -25,7 +25,6 @@ class PLATFORM_EXPORT MainThread : public Thread {
// Thread implementation.
ThreadScheduler* Scheduler() override;
- PlatformThreadId ThreadId() const override;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override;
void AddTaskTimeObserver(base::sequence_manager::TaskTimeObserver*) override;
@@ -35,7 +34,6 @@ class PLATFORM_EXPORT MainThread : public Thread {
private:
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
MainThreadSchedulerImpl* scheduler_; // Not owned.
- PlatformThreadId thread_id_;
};
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
index a15e2a43d85..0a84c72edce 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
@@ -42,7 +42,7 @@ MainThreadSchedulerHelper::DefaultMainThreadTaskQueue() {
const scoped_refptr<base::SingleThreadTaskRunner>&
MainThreadSchedulerHelper::DefaultTaskRunner() {
- return default_task_queue_->GetTaskRunnerWithDefaultTaskType();
+ return default_task_runner();
}
scoped_refptr<MainThreadTaskQueue>
@@ -59,25 +59,11 @@ scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerHelper::DeprecatedDefaultTaskRunner() {
// TODO(hajimehoshi): Introduce a different task queue from the default task
// queue and return the task runner created from it.
- return DefaultTaskRunner();
+ return default_task_runner();
}
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerHelper::NewTaskQueue(
const MainThreadTaskQueue::QueueCreationParams& params) {
-#if DCHECK_IS_ON()
- // This check is to ensure that we only create one queue with kCompositor
- // prioritisation type, ie one compositor task queue, since elsewhere we
- // assume there is only one when making priority decisions.
- if (params.queue_traits.prioritisation_type ==
- MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) {
- DCHECK(
- !created_compositor_task_queue_ ||
- params.queue_traits.prioritisation_type !=
- MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor);
- created_compositor_task_queue_ = true;
- }
-#endif // DCHECK_IS_ON()
-
scoped_refptr<MainThreadTaskQueue> task_queue =
sequence_manager_->CreateTaskQueueWithType<MainThreadTaskQueue>(
params.spec, params, main_thread_scheduler_);
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h
index dca77b6a301..9d1c2990a54 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h
@@ -46,10 +46,6 @@ class PLATFORM_EXPORT MainThreadSchedulerHelper : public SchedulerHelper {
const scoped_refptr<MainThreadTaskQueue> default_task_queue_;
const scoped_refptr<MainThreadTaskQueue> control_task_queue_;
-#if DCHECK_IS_ON()
- bool created_compositor_task_queue_ = false;
-#endif // DCHECK_IS_ON()
-
DISALLOW_COPY_AND_ASSIGN(MainThreadSchedulerHelper);
};
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 7089d80e317..cf1ea90760b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -25,6 +25,9 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "build/build_config.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/input/web_input_event_attribution.h"
@@ -33,7 +36,6 @@
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
-#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/common/features.h"
@@ -236,8 +238,6 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl(
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kIPCTrackingForCachedPages)
.SetShouldNotifyObservers(false))),
- compositor_task_queue_enabled_voter_(
- compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter()),
memory_purge_task_queue_(helper_.NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kIdle)
@@ -252,18 +252,21 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl(
helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
TaskType::kMainThreadTaskQueueControl)),
main_thread_only_(this,
- compositor_task_queue_,
helper_.GetClock(),
helper_.NowTicks()),
any_thread_(this),
policy_may_need_update_(&any_thread_lock_),
notify_agent_strategy_task_posted_(&any_thread_lock_) {
+ helper_.AttachToCurrentThread();
+
// Compositor task queue and default task queue should be managed by
// WebThreadScheduler. Control task queue should not.
task_runners_.emplace(helper_.DefaultMainThreadTaskQueue(), nullptr);
task_runners_.emplace(
compositor_task_queue_,
compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter());
+ main_thread_only().idle_time_estimator.AddCompositorTaskQueue(
+ compositor_task_queue_);
back_forward_cache_ipc_tracking_task_runner_ =
back_forward_cache_ipc_tracking_task_queue_->CreateTaskRunner(
@@ -347,7 +350,7 @@ MainThreadSchedulerImpl::~MainThreadSchedulerImpl() {
TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler",
this);
- for (auto& pair : task_runners_) {
+ for (const auto& pair : task_runners_) {
pair.first->ShutdownTaskQueue();
}
@@ -377,11 +380,9 @@ WebThreadScheduler* WebThreadScheduler::MainThreadScheduler() {
MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
MainThreadSchedulerImpl* main_thread_scheduler_impl,
- const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
const base::TickClock* time_source,
base::TimeTicks now)
- : idle_time_estimator(compositor_task_runner,
- time_source,
+ : idle_time_estimator(time_source,
kShortIdlePeriodDurationSampleCount,
kShortIdlePeriodDurationPercentile),
current_use_case(UseCase::kNone,
@@ -494,7 +495,10 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
compositor_priority(TaskQueue::QueuePriority::kNormalPriority,
"Scheduler.CompositorPriority",
&main_thread_scheduler_impl->tracing_controller_,
- TaskQueue::PriorityToString) {}
+ TaskQueue::PriorityToString),
+ audible_power_mode_voter(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Audible")) {}
MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
@@ -605,6 +609,13 @@ MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() {
}
}
}
+
+ mbi_override_task_runner_handle =
+ base::FeatureList::IsEnabled(kMbiOverrideTaskRunnerHandle);
+
+ mbi_compositor_task_runner_per_agent_scheduling_group =
+ base::FeatureList::IsEnabled(
+ kMbiCompositorTaskRunnerPerAgentSchedulingGroup);
}
MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
@@ -742,6 +753,13 @@ scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
voter = task_queue->GetTaskQueue()->CreateQueueEnabledVoter();
}
+ if (task_queue->GetPrioritisationType() ==
+ MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) {
+ DCHECK(!voter);
+ voter = task_queue->GetTaskQueue()->CreateQueueEnabledVoter();
+ main_thread_only().idle_time_estimator.AddCompositorTaskQueue(task_queue);
+ }
+
auto insert_result = task_runners_.emplace(task_queue, std::move(voter));
UpdateTaskQueueState(task_queue.get(), insert_result.first->second.get(),
@@ -888,9 +906,6 @@ void MainThreadSchedulerImpl::OnShutdownTaskQueue(
if (was_shutdown_)
return;
- if (task_queue_throttler_)
- task_queue_throttler_->ShutdownTaskQueue(task_queue->GetTaskQueue());
-
task_queue.get()->DetachOnIPCTaskPostedWhileInBackForwardCache();
task_runners_.erase(task_queue.get());
}
@@ -1083,7 +1098,6 @@ void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) {
main_thread_only().metrics_helper.OnRendererForegrounded(now);
}
- ParkableStringManager::Instance().SetRendererBackgrounded(backgrounded);
memory_purge_manager_.SetRendererBackgrounded(backgrounded);
}
@@ -1125,6 +1139,10 @@ void MainThreadSchedulerImpl::OnAudioStateChanged() {
return;
main_thread_only().is_audio_playing = is_audio_playing;
+
+ main_thread_only().audible_power_mode_voter->VoteFor(
+ is_audio_playing ? power_scheduler::PowerMode::kAudible
+ : power_scheduler::PowerMode::kIdle);
}
std::unique_ptr<ThreadScheduler::RendererPauseHandle>
@@ -1454,9 +1472,14 @@ bool MainThreadSchedulerImpl::ShouldYieldForHighPriorityWork() {
case UseCase::kMainThreadGesture:
case UseCase::kMainThreadCustomInputHandling:
case UseCase::kSynchronizedGesture:
- return compositor_task_queue_->GetTaskQueue()
- ->HasTaskToRunImmediately() ||
- main_thread_only().blocking_input_expected_soon;
+ for (const auto& pair : task_runners_) {
+ if (pair.first->GetPrioritisationType() ==
+ MainThreadTaskQueue::QueueTraits::PrioritisationType::
+ kCompositor &&
+ pair.first->GetTaskQueue()->HasTaskToRunImmediately())
+ return true;
+ }
+ return main_thread_only().blocking_input_expected_soon;
case UseCase::kTouchstart:
return true;
@@ -1706,8 +1729,6 @@ void MainThreadSchedulerImpl::UpdateStateForAllTaskQueues(
UpdateTaskQueueState(pair.first.get(), pair.second.get(), old_policy,
current_policy, should_update_priorities);
}
- compositor_task_queue_enabled_voter_->SetVoteToEnable(
- !current_policy.should_freeze_compositor_task_queue());
}
void MainThreadSchedulerImpl::UpdateTaskQueueState(
@@ -1741,6 +1762,12 @@ void MainThreadSchedulerImpl::UpdateTaskQueueState(
task_queue->GetTaskQueue()->SetTimeDomain(real_time_domain());
}
}
+
+ if (task_queue->GetPrioritisationType() ==
+ MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) {
+ task_queue_enabled_voter->SetVoteToEnable(
+ !new_policy.should_freeze_compositor_task_queue());
+ }
}
UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
@@ -1947,7 +1974,7 @@ void MainThreadSchedulerImpl::VirtualTimePaused() {
for (const auto& pair : task_runners_) {
if (pair.first->CanRunWhenVirtualTimePaused())
continue;
- DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue()));
+ DCHECK(!pair.first->IsThrottled());
pair.first->GetTaskQueue()->InsertFence(
TaskQueue::InsertFencePosition::kNow);
}
@@ -1957,7 +1984,7 @@ void MainThreadSchedulerImpl::VirtualTimeResumed() {
for (const auto& pair : task_runners_) {
if (pair.first->CanRunWhenVirtualTimePaused())
continue;
- DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue()));
+ DCHECK(!pair.first->IsThrottled());
DCHECK(pair.first->GetTaskQueue()->HasActiveFence());
pair.first->GetTaskQueue()->RemoveFence();
}
@@ -2046,138 +2073,104 @@ void MainThreadSchedulerImpl::SetMaxVirtualTimeTaskStarvationCount(
ApplyVirtualTimePolicy();
}
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-MainThreadSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
- base::AutoLock lock(any_thread_lock_);
- return AsValueLocked(optional_now);
-}
-
void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshot() const {
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
- "MainThreadScheduler", this, AsValue(helper_.NowTicks()));
+ "MainThreadScheduler", this, [&](perfetto::TracedValue context) {
+ base::AutoLock lock(any_thread_lock_);
+ WriteIntoTracedValueLocked(std::move(context), helper_.NowTicks());
+ });
}
void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const {
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
- "MainThreadScheduler", this, AsValueLocked(helper_.NowTicks()));
-}
-
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
- auto state = std::make_unique<base::trace_event::TracedValue>();
- AsValueIntoLocked(state.get(), optional_now);
- return std::move(state);
+ "MainThreadScheduler", this, [&](perfetto::TracedValue context) {
+ WriteIntoTracedValueLocked(std::move(context), helper_.NowTicks());
+ });
}
-std::string MainThreadSchedulerImpl::ToString() const {
- base::AutoLock lock(any_thread_lock_);
- base::trace_event::TracedValueJSON value;
- AsValueIntoLocked(&value, base::TimeTicks());
- return value.ToJSON();
-}
-
-void MainThreadSchedulerImpl::AsValueIntoLocked(
- base::trace_event::TracedValue* state,
+void MainThreadSchedulerImpl::WriteIntoTracedValueLocked(
+ perfetto::TracedValue context,
base::TimeTicks optional_now) const {
helper_.CheckOnValidThread();
any_thread_lock_.AssertAcquired();
+ auto dict = std::move(context).WriteDictionary();
+
if (optional_now.is_null())
optional_now = helper_.NowTicks();
- state->SetBoolean(
- "has_visible_render_widget_with_touch_handler",
- main_thread_only().has_visible_render_widget_with_touch_handler);
- state->SetString("current_use_case",
- UseCaseToString(main_thread_only().current_use_case));
- state->SetBoolean(
- "compositor_will_send_main_frame_not_expected",
- main_thread_only().compositor_will_send_main_frame_not_expected);
- state->SetBoolean("blocking_input_expected_soon",
- main_thread_only().blocking_input_expected_soon);
- state->SetString("idle_period_state",
- IdleHelper::IdlePeriodStateToString(
- idle_helper_.SchedulerIdlePeriodState()));
- state->SetBoolean("renderer_hidden", main_thread_only().renderer_hidden);
- state->SetBoolean("waiting_for_any_main_frame_contentful_paint",
- any_thread().waiting_for_any_main_frame_contentful_paint);
- state->SetBoolean("waiting_for_any_main_frame_meaningful_paint",
- any_thread().waiting_for_any_main_frame_meaningful_paint);
- state->SetBoolean("have_seen_input_since_navigation",
- any_thread().have_seen_input_since_navigation);
- state->SetBoolean(
+ dict.Add("has_visible_render_widget_with_touch_handler",
+ main_thread_only().has_visible_render_widget_with_touch_handler);
+ dict.Add("current_use_case",
+ UseCaseToString(main_thread_only().current_use_case));
+ dict.Add("compositor_will_send_main_frame_not_expected",
+ main_thread_only().compositor_will_send_main_frame_not_expected);
+ dict.Add("blocking_input_expected_soon",
+ main_thread_only().blocking_input_expected_soon);
+ dict.Add("idle_period_state", IdleHelper::IdlePeriodStateToString(
+ idle_helper_.SchedulerIdlePeriodState()));
+ dict.Add("renderer_hidden", main_thread_only().renderer_hidden);
+ dict.Add("waiting_for_any_main_frame_contentful_paint",
+ any_thread().waiting_for_any_main_frame_contentful_paint);
+ dict.Add("waiting_for_any_main_frame_meaningful_paint",
+ any_thread().waiting_for_any_main_frame_meaningful_paint);
+ dict.Add("have_seen_input_since_navigation",
+ any_thread().have_seen_input_since_navigation);
+ dict.Add(
"have_reported_blocking_intervention_in_current_policy",
main_thread_only().have_reported_blocking_intervention_in_current_policy);
- state->SetBoolean(
+ dict.Add(
"have_reported_blocking_intervention_since_navigation",
main_thread_only().have_reported_blocking_intervention_since_navigation);
- state->SetBoolean("renderer_backgrounded",
- main_thread_only().renderer_backgrounded);
- state->SetBoolean("keep_active_fetch_or_worker",
- main_thread_only().keep_active_fetch_or_worker);
- state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
+ dict.Add("renderer_backgrounded", main_thread_only().renderer_backgrounded);
+ dict.Add("keep_active_fetch_or_worker",
+ main_thread_only().keep_active_fetch_or_worker);
+ dict.Add("now", (optional_now - base::TimeTicks()).InMillisecondsF());
+ dict.Add(
"fling_compositor_escalation_deadline",
(any_thread().fling_compositor_escalation_deadline - base::TimeTicks())
.InMillisecondsF());
- state->SetDouble("last_idle_period_end_time",
- (any_thread().last_idle_period_end_time - base::TimeTicks())
- .InMillisecondsF());
- state->SetBoolean("awaiting_touch_start_response",
- any_thread().awaiting_touch_start_response);
- state->SetBoolean("begin_main_frame_on_critical_path",
- any_thread().begin_main_frame_on_critical_path);
- state->SetBoolean("last_gesture_was_compositor_driven",
- any_thread().last_gesture_was_compositor_driven);
- state->SetBoolean("default_gesture_prevented",
- any_thread().default_gesture_prevented);
- state->SetBoolean("is_audio_playing", main_thread_only().is_audio_playing);
- state->SetBoolean("virtual_time_stopped",
- main_thread_only().virtual_time_stopped);
- state->SetDouble("virtual_time_pause_count",
- main_thread_only().virtual_time_pause_count);
- state->SetString(
- "virtual_time_policy",
- VirtualTimePolicyToString(main_thread_only().virtual_time_policy));
- state->SetBoolean("virtual_time", main_thread_only().use_virtual_time);
-
- {
- auto dictionary_scope = state->BeginDictionaryScoped("page_schedulers");
- for (PageSchedulerImpl* page_scheduler :
- main_thread_only().page_schedulers) {
- auto inner_dictionary = state->BeginDictionaryScopedWithCopiedName(
- PointerToString(page_scheduler));
- page_scheduler->AsValueInto(state);
- }
- }
-
- {
- auto dictionary_scope = state->BeginDictionaryScoped("policy");
- main_thread_only().current_policy.AsValueInto(state);
- }
+ dict.Add("last_idle_period_end_time",
+ (any_thread().last_idle_period_end_time - base::TimeTicks())
+ .InMillisecondsF());
+ dict.Add("awaiting_touch_start_response",
+ any_thread().awaiting_touch_start_response);
+ dict.Add("begin_main_frame_on_critical_path",
+ any_thread().begin_main_frame_on_critical_path);
+ dict.Add("last_gesture_was_compositor_driven",
+ any_thread().last_gesture_was_compositor_driven);
+ dict.Add("default_gesture_prevented", any_thread().default_gesture_prevented);
+ dict.Add("is_audio_playing", main_thread_only().is_audio_playing);
+ dict.Add("virtual_time_stopped", main_thread_only().virtual_time_stopped);
+ dict.Add("virtual_time_pause_count",
+ main_thread_only().virtual_time_pause_count);
+ dict.Add("virtual_time_policy",
+ VirtualTimePolicyToString(main_thread_only().virtual_time_policy));
+ dict.Add("virtual_time", main_thread_only().use_virtual_time);
+
+ dict.Add("page_schedulers", main_thread_only().page_schedulers);
+
+ dict.Add("policy", main_thread_only().current_policy);
// TODO(skyostil): Can we somehow trace how accurate these estimates were?
- state->SetDouble(
+ dict.Add(
"longest_jank_free_task_duration",
main_thread_only().longest_jank_free_task_duration->InMillisecondsF());
- state->SetDouble(
- "compositor_frame_interval",
- main_thread_only().compositor_frame_interval.InMillisecondsF());
- state->SetDouble(
- "estimated_next_frame_begin",
- (main_thread_only().estimated_next_frame_begin - base::TimeTicks())
- .InMillisecondsF());
- state->SetBoolean("in_idle_period", any_thread().in_idle_period);
+ dict.Add("compositor_frame_interval",
+ main_thread_only().compositor_frame_interval.InMillisecondsF());
+ dict.Add("estimated_next_frame_begin",
+ (main_thread_only().estimated_next_frame_begin - base::TimeTicks())
+ .InMillisecondsF());
+ dict.Add("in_idle_period", any_thread().in_idle_period);
- any_thread().user_model.AsValueInto(state);
- render_widget_scheduler_signals_.AsValueInto(state);
+ dict.Add("user_model", any_thread().user_model);
+ dict.Add("render_widget_scheduler_signals", render_widget_scheduler_signals_);
- {
- auto dictionary_scope =
- state->BeginDictionaryScoped("task_queue_throttler");
- task_queue_throttler_->AsValueInto(state, optional_now);
- }
+ dict.Add("task_queue_throttler", [&](perfetto::TracedValue context) {
+ task_queue_throttler_->WriteIntoTracedValue(std::move(context),
+ optional_now);
+ });
}
bool MainThreadSchedulerImpl::Policy::IsQueueEnabled(
@@ -2199,17 +2192,18 @@ MainThreadSchedulerImpl::Policy::GetTimeDomainType() const {
return TimeDomainType::kReal;
}
-void MainThreadSchedulerImpl::Policy::AsValueInto(
- base::trace_event::TracedValue* state) const {
- state->SetString("rail_mode", RAILModeToString(rail_mode()));
- state->SetString("use_case", UseCaseToString(use_case()));
+void MainThreadSchedulerImpl::Policy::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("rail_mode", RAILModeToString(rail_mode()));
+ dict.Add("use_case", UseCaseToString(use_case()));
- state->SetBoolean("should_disable_throttling", should_disable_throttling());
- state->SetBoolean("should_defer_task_queues", should_defer_task_queues());
- state->SetBoolean("should_pause_task_queues", should_pause_task_queues());
- state->SetBoolean("should_pause_task_queues_for_android_webview",
- should_pause_task_queues_for_android_webview());
- state->SetBoolean("use_virtual_time", use_virtual_time());
+ dict.Add("should_disable_throttling", should_disable_throttling());
+ dict.Add("should_defer_task_queues", should_defer_task_queues());
+ dict.Add("should_pause_task_queues", should_pause_task_queues());
+ dict.Add("should_pause_task_queues_for_android_webview",
+ should_pause_task_queues_for_android_webview());
+ dict.Add("use_virtual_time", use_virtual_time());
}
void MainThreadSchedulerImpl::OnIdlePeriodStarted() {
@@ -2440,6 +2434,14 @@ MainThreadSchedulerImpl::V8TaskRunner() {
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::CompositorTaskRunner() {
+ if (scheduling_settings()
+ .mbi_compositor_task_runner_per_agent_scheduling_group) {
+ NOTREACHED() << "When MbiPerAGSCompositorTaskRunner is enabled, "
+ "MainThreadSchedulerImpl::CompositorTaskRunner() shouldn't "
+ "be used. We are planning to remove "
+ "MainThreadSchedulerImpl::CompositorTaskRunner() in the "
+ "near future.";
+ }
return compositor_task_runner_;
}
@@ -2467,30 +2469,92 @@ MainThreadSchedulerImpl::GetCurrentAgentGroupScheduler() {
return current_agent_group_scheduler_;
}
-void MainThreadSchedulerImpl::SetCurrentAgentGroupScheduler(
- WebAgentGroupScheduler* agent_group_scheduler) {
- helper_.CheckOnValidThread();
- if (current_agent_group_scheduler_) {
- TRACE_EVENT_NESTABLE_ASYNC_END1(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "scheduler.agent_scope", current_agent_group_scheduler_,
- "agent_group_scheduler", current_agent_group_scheduler_);
- } else {
- TRACE_EVENT_NESTABLE_ASYNC_END0(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "scheduler.thread_scope", this);
- }
- current_agent_group_scheduler_ = agent_group_scheduler;
- if (current_agent_group_scheduler_) {
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "scheduler.agent_scope", current_agent_group_scheduler_,
- "agent_group_scheduler", current_agent_group_scheduler_);
+void MainThreadSchedulerImpl::BeginAgentGroupSchedulerScope(
+ WebAgentGroupScheduler* next_agent_group_scheduler) {
+ scoped_refptr<base::SingleThreadTaskRunner> next_task_runner;
+ const char* trace_event_scope_name;
+ void* trace_event_scope_id;
+
+ if (next_agent_group_scheduler) {
+ // If the |next_agent_group_scheduler| is not null, it means that a
+ // per-AgentSchedulingGroup task is about to start. In this case, a
+ // per-AgentGroupScheduler scope starts.
+ next_task_runner = next_agent_group_scheduler->DefaultTaskRunner(),
+ trace_event_scope_name = "scheduler.agent_scope";
+ trace_event_scope_id = next_agent_group_scheduler;
} else {
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "scheduler.thread_scope", this);
- }
+ // If the |next_agent_group_scheduler| is null, it means that a
+ // per-thread task is about to start. In this case, a per-thread scope
+ // starts.
+ next_task_runner = helper_.DefaultTaskRunner();
+ trace_event_scope_name = "scheduler.thread_scope";
+ trace_event_scope_id = this;
+ }
+
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
+ TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), trace_event_scope_name,
+ trace_event_scope_id, "agent_group_scheduler",
+ static_cast<void*>(next_agent_group_scheduler));
+
+ WebAgentGroupScheduler* previous_agent_group_scheduler =
+ current_agent_group_scheduler_;
+ current_agent_group_scheduler_ = next_agent_group_scheduler;
+
+ scoped_refptr<base::SingleThreadTaskRunner> previous_task_runner =
+ base::ThreadTaskRunnerHandle::Get();
+ std::unique_ptr<base::ThreadTaskRunnerHandleOverride>
+ thread_task_runner_handle_override;
+ if (scheduling_settings().mbi_override_task_runner_handle &&
+ next_task_runner != previous_task_runner) {
+ // per-thread and per-AgentSchedulingGroup task runner allows nested
+ // runloop. |MainThreadSchedulerImpl| guarantees that
+ // |ThreadTaskRunnerHandle::Get()| and |SequencedTaskRunnerHandle::Get()|
+ // return a proper task runner even when a nested runloop is used. Because
+ // |MainThreadSchedulerImpl::OnTaskStarted()| always overrides
+ // TTRH/STRH::Get() properly. So there is no concern about returning an
+ // unexpected task runner from TTRH/STRH::Get() in this specific case.
+ thread_task_runner_handle_override =
+ std::unique_ptr<base::ThreadTaskRunnerHandleOverride>(
+ new base::ThreadTaskRunnerHandleOverride(
+ next_task_runner,
+ /*allow_nested_runloop=*/true));
+ }
+
+ main_thread_only().agent_group_scheduler_scope_stack.emplace_back(
+ AgentGroupSchedulerScope{
+ std::move(thread_task_runner_handle_override),
+ previous_agent_group_scheduler, next_agent_group_scheduler,
+ std::move(previous_task_runner), std::move(next_task_runner),
+ trace_event_scope_name, trace_event_scope_id});
+}
+
+void MainThreadSchedulerImpl::EndAgentGroupSchedulerScope() {
+ AgentGroupSchedulerScope& agent_group_scheduler_scope =
+ main_thread_only().agent_group_scheduler_scope_stack.back();
+
+ if (scheduling_settings().mbi_override_task_runner_handle) {
+ DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(),
+ agent_group_scheduler_scope.current_task_runner);
+ DCHECK_EQ(base::SequencedTaskRunnerHandle::Get(),
+ agent_group_scheduler_scope.current_task_runner);
+ }
+ agent_group_scheduler_scope.thread_task_runner_handle_override = nullptr;
+ DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(),
+ agent_group_scheduler_scope.previous_task_runner);
+ DCHECK_EQ(base::SequencedTaskRunnerHandle::Get(),
+ agent_group_scheduler_scope.previous_task_runner);
+
+ current_agent_group_scheduler_ =
+ agent_group_scheduler_scope.previous_agent_group_scheduler;
+
+ TRACE_EVENT_NESTABLE_ASYNC_END1(
+ TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+ agent_group_scheduler_scope.trace_event_scope_name,
+ agent_group_scheduler_scope.trace_event_scope_id, "agent_group_scheduler",
+ static_cast<void*>(
+ agent_group_scheduler_scope.current_agent_group_scheduler));
+
+ main_thread_only().agent_group_scheduler_scope_stack.pop_back();
}
std::unique_ptr<ThreadScheduler::RendererPauseHandle>
@@ -2561,6 +2625,11 @@ void MainThreadSchedulerImpl::RemovePageScheduler(
SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded();
}
+ if (main_thread_only().is_audio_playing && page_scheduler->IsAudioPlaying()) {
+ // This page may have been the only one playing audio.
+ OnAudioStateChanged();
+ }
+
base::AutoLock lock(any_thread_lock_);
any_thread().waiting_for_any_main_frame_contentful_paint =
IsAnyMainFrameWaitingForFirstContentfulPaint();
@@ -2605,8 +2674,10 @@ void MainThreadSchedulerImpl::OnTaskStarted(
MainThreadTaskQueue* queue,
const base::sequence_manager::Task& task,
const TaskQueue::TaskTiming& task_timing) {
- SetCurrentAgentGroupScheduler(queue ? queue->GetAgentGroupScheduler()
- : nullptr);
+ if (scheduling_settings().mbi_override_task_runner_handle) {
+ BeginAgentGroupSchedulerScope(queue ? queue->GetAgentGroupScheduler()
+ : nullptr);
+ }
main_thread_only().running_queues.push(queue);
if (main_thread_only().nested_runloop)
@@ -2642,16 +2713,18 @@ void MainThreadSchedulerImpl::OnTaskCompleted(
if (task_timing->has_wall_time() && queue && queue->GetFrameScheduler())
queue->GetFrameScheduler()->AddTaskTime(task_timing->wall_duration());
main_thread_only().running_queues.pop();
+
+ // The overriding TaskRunnerHandle scope ends here.
+ if (scheduling_settings().mbi_override_task_runner_handle)
+ EndAgentGroupSchedulerScope();
+
if (main_thread_only().nested_runloop)
return;
DispatchOnTaskCompletionCallbacks();
- if (queue) {
- task_queue_throttler()->OnTaskRunTimeReported(queue->GetTaskQueue(),
- task_timing->start_time(),
- task_timing->end_time());
- }
+ if (queue)
+ queue->OnTaskRunTimeReported(task_timing);
// TODO(altimin): Per-page metrics should also be considered.
main_thread_only().metrics_helper.RecordTaskMetrics(queue.get(), task,
@@ -2668,10 +2741,6 @@ void MainThreadSchedulerImpl::OnTaskCompleted(
find_in_page_budget_pool_controller_->OnTaskCompleted(queue.get(),
task_timing);
-
- // GetCurrentAgentGroupScheduler() should return nullptr when
- // it's running thread global task runners.
- SetCurrentAgentGroupScheduler(nullptr);
}
void MainThreadSchedulerImpl::RecordTaskUkm(
@@ -2900,8 +2969,13 @@ TaskQueue::QueuePriority MainThreadSchedulerImpl::ComputeCompositorPriority()
void MainThreadSchedulerImpl::UpdateCompositorTaskQueuePriority() {
main_thread_only().compositor_priority = ComputeCompositorPriority();
- CompositorTaskQueue()->GetTaskQueue()->SetQueuePriority(
- ComputePriority(CompositorTaskQueue().get()));
+ for (const auto& pair : task_runners_) {
+ if (pair.first->GetPrioritisationType() !=
+ MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor)
+ continue;
+ pair.first->GetTaskQueue()->SetQueuePriority(
+ ComputePriority(pair.first.get()));
+ }
}
base::Optional<TaskQueue::QueuePriority>
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 2ef822df859..89ea3cb1ef9 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -23,6 +23,7 @@
#include "base/task/sequence_manager/task_time_observer.h"
#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
@@ -50,14 +51,10 @@
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
-
class TaskObserver;
-
-namespace trace_event {
-class ConvertableToTraceFormat;
-}
} // namespace base
namespace blink {
@@ -143,6 +140,15 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
std::array<base::sequence_manager::TaskQueue::QueuePriority,
net::RequestPrioritySize::NUM_PRIORITIES>
net_to_blink_priority;
+
+ // If enabled, base::ThreadTaskRunnerHandle::Get() and
+ // base::SequencedTaskRunnerHandle::Get() returns the current active
+ // per-ASG task runner instead of the per-thread task runner.
+ bool mbi_override_task_runner_handle;
+
+ // If enabled, per-AgentGroupScheduler CompositorTaskRunner will be used
+ // instead of per-MainThreadScheduler CompositorTaskRunner.
+ bool mbi_compositor_task_runner_per_agent_scheduling_group;
};
static const char* UseCaseToString(UseCase use_case);
@@ -223,8 +229,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
std::unique_ptr<WebAgentGroupScheduler> CreateAgentGroupScheduler() override;
WebAgentGroupScheduler* GetCurrentAgentGroupScheduler() override;
- void SetCurrentAgentGroupScheduler(
- WebAgentGroupScheduler* agent_group_scheduler);
std::unique_ptr<ThreadScheduler::RendererPauseHandle> PauseScheduler()
override;
base::TimeTicks MonotonicallyIncreasingVirtualTime() override;
@@ -494,6 +498,21 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
void AddAgentGroupScheduler(AgentGroupSchedulerImpl*);
+ struct AgentGroupSchedulerScope {
+ std::unique_ptr<base::ThreadTaskRunnerHandleOverride>
+ thread_task_runner_handle_override;
+ WebAgentGroupScheduler* previous_agent_group_scheduler;
+ WebAgentGroupScheduler* current_agent_group_scheduler;
+ scoped_refptr<base::SingleThreadTaskRunner> previous_task_runner;
+ scoped_refptr<base::SingleThreadTaskRunner> current_task_runner;
+ const char* trace_event_scope_name;
+ void* trace_event_scope_id;
+ };
+
+ void BeginAgentGroupSchedulerScope(
+ WebAgentGroupScheduler* next_agent_group_scheduler);
+ void EndAgentGroupSchedulerScope();
+
bool IsAnyMainFrameWaitingForFirstContentfulPaint() const;
bool IsAnyMainFrameWaitingForFirstMeaningfulPaint() const;
@@ -573,12 +592,12 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
use_case_ == other.use_case_;
}
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
bool IsQueueEnabled(MainThreadTaskQueue* task_queue) const;
TimeDomainType GetTimeDomainType() const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
private:
RAILMode rail_mode_{RAILMode::kAnimation};
bool should_disable_throttling_{false};
@@ -632,14 +651,10 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
MainThreadTaskQueue* queue);
// Returns the serialized scheduler state for tracing.
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue(
- base::TimeTicks optional_now) const;
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked(
- base::TimeTicks optional_now) const;
+ void WriteIntoTracedValueLocked(perfetto::TracedValue context,
+ base::TimeTicks optional_now) const;
void CreateTraceEventObjectSnapshotLocked() const;
- std::string ToString() const;
-
static bool ShouldPrioritizeInputEvent(const WebInputEvent& web_input_event);
// The amount of time which idle periods can continue being scheduled when the
@@ -780,9 +795,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
// task.
void DispatchOnTaskCompletionCallbacks();
- void AsValueIntoLocked(base::trace_event::TracedValue*,
- base::TimeTicks optional_now) const;
-
bool AllPagesFrozen() const;
// Indicates that scheduler has been shutdown.
@@ -821,8 +833,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
scoped_refptr<MainThreadTaskQueue> virtual_time_control_task_queue_;
scoped_refptr<MainThreadTaskQueue>
back_forward_cache_ipc_tracking_task_queue_;
- std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter>
- compositor_task_queue_enabled_voter_;
using TaskQueueVoterMap = std::map<
scoped_refptr<MainThreadTaskQueue>,
@@ -862,7 +872,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
struct MainThreadOnly {
MainThreadOnly(
MainThreadSchedulerImpl* main_thread_scheduler_impl,
- const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
const base::TickClock* time_source,
base::TimeTicks now);
~MainThreadOnly();
@@ -965,6 +974,10 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
// kNormalPriority and is updated via UpdateCompositorTaskQueuePriority().
TraceableState<TaskQueue::QueuePriority, TracingCategoryName::kDefault>
compositor_priority;
+
+ WTF::Vector<AgentGroupSchedulerScope> agent_group_scheduler_scope_stack;
+
+ std::unique_ptr<power_scheduler::PowerModeVoter> audible_power_mode_voter;
};
struct AnyThread {
@@ -1036,7 +1049,8 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
return any_thread_;
}
- // Don't access compositor_thread_only_, instead use CompositorThreadOnly().
+ // Don't access compositor_thread_only_, instead use
+ // |GetCompositorThreadOnly()|.
CompositorThreadOnly compositor_thread_only_;
CompositorThreadOnly& GetCompositorThreadOnly() {
compositor_thread_only_.CheckOnValidThread();
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 006a901f95a..56a4eb6f6e9 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -444,13 +444,23 @@ class MainThreadSchedulerImplTest : public testing::Test {
default_task_runner_ =
scheduler_->DefaultTaskQueue()->GetTaskRunnerWithDefaultTaskType();
- compositor_task_runner_ =
- scheduler_->CompositorTaskQueue()->GetTaskRunnerWithDefaultTaskType();
+ if (!scheduler_->scheduling_settings()
+ .mbi_compositor_task_runner_per_agent_scheduling_group) {
+ compositor_task_runner_ =
+ scheduler_->CompositorTaskQueue()->GetTaskRunnerWithDefaultTaskType();
+ }
idle_task_runner_ = scheduler_->IdleTaskRunner();
v8_task_runner_ =
scheduler_->V8TaskQueue()->GetTaskRunnerWithDefaultTaskType();
- agent_group_scheduler_ = scheduler_->CreateAgentGroupScheduler();
+ agent_group_scheduler_ = std::unique_ptr<AgentGroupSchedulerImpl>(
+ static_cast<AgentGroupSchedulerImpl*>(
+ scheduler_->CreateAgentGroupScheduler().release()));
+ if (scheduler_->scheduling_settings()
+ .mbi_compositor_task_runner_per_agent_scheduling_group) {
+ compositor_task_runner_ = agent_group_scheduler_->CompositorTaskQueue()
+ ->GetTaskRunnerWithDefaultTaskType();
+ }
page_scheduler_ = std::make_unique<NiceMock<MockPageSchedulerImpl>>(
scheduler_.get(),
static_cast<AgentGroupSchedulerImpl&>(*agent_group_scheduler_));
@@ -474,6 +484,15 @@ class MainThreadSchedulerImplTest : public testing::Test {
blink::TaskType::kInternalHighPriorityLocalFrame);
}
+ MainThreadTaskQueue* compositor_task_queue() {
+ if (scheduler_->scheduling_settings()
+ .mbi_compositor_task_runner_per_agent_scheduling_group) {
+ return agent_group_scheduler_->CompositorTaskQueue().get();
+ } else {
+ return scheduler_->CompositorTaskQueue().get();
+ }
+ }
+
MainThreadTaskQueue* loading_task_queue() {
auto queue_traits = FrameSchedulerImpl::LoadingTaskQueueTraits();
return main_frame_scheduler_->FrameTaskQueueControllerForTest()
@@ -946,7 +965,7 @@ class MainThreadSchedulerImplTest : public testing::Test {
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
std::unique_ptr<MainThreadSchedulerImplForTest> scheduler_;
- std::unique_ptr<WebAgentGroupScheduler> agent_group_scheduler_;
+ std::unique_ptr<AgentGroupSchedulerImpl> agent_group_scheduler_;
std::unique_ptr<MockPageSchedulerImpl> page_scheduler_;
std::unique_ptr<FrameSchedulerImpl> main_frame_scheduler_;
std::unique_ptr<WebWidgetScheduler> widget_scheduler_;
@@ -2485,8 +2504,8 @@ TEST_F(MainThreadSchedulerImplTest, StopAndThrottleThrottleableQueue) {
auto pause_handle = scheduler_->PauseRenderer();
base::RunLoop().RunUntilIdle();
- scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
- throttleable_task_queue()->GetTaskQueue());
+ MainThreadTaskQueue::ThrottleHandle handle =
+ throttleable_task_queue()->Throttle();
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre());
}
@@ -2495,8 +2514,8 @@ TEST_F(MainThreadSchedulerImplTest, ThrottleAndPauseRenderer) {
Vector<String> run_order;
PostTestTasks(&run_order, "T1 T2");
- scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
- throttleable_task_queue()->GetTaskQueue());
+ MainThreadTaskQueue::ThrottleHandle handle =
+ throttleable_task_queue()->Throttle();
base::RunLoop().RunUntilIdle();
auto pause_handle = scheduler_->PauseRenderer();
base::RunLoop().RunUntilIdle();
@@ -2883,9 +2902,8 @@ TEST_F(MainThreadSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) {
// Throttleable tasks should not have been starved by the expensive compositor
// tasks.
- EXPECT_EQ(
- TaskQueue::kNormalPriority,
- scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority());
+ EXPECT_EQ(TaskQueue::kNormalPriority,
+ compositor_task_queue()->GetTaskQueue()->GetQueuePriority());
EXPECT_EQ(1000u, run_order.size());
}
@@ -2926,9 +2944,8 @@ TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) {
// Throttleable tasks should not have been starved by the expensive compositor
// tasks.
- EXPECT_EQ(
- TaskQueue::kNormalPriority,
- scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority());
+ EXPECT_EQ(TaskQueue::kNormalPriority,
+ compositor_task_queue()->GetTaskQueue()->GetQueuePriority());
EXPECT_EQ(1000u, run_order.size());
}
@@ -2967,9 +2984,8 @@ TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_GESTURE) {
EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase()) << "i = " << i;
}
- EXPECT_EQ(
- TaskQueue::kHighestPriority,
- scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority());
+ EXPECT_EQ(TaskQueue::kHighestPriority,
+ compositor_task_queue()->GetTaskQueue()->GetQueuePriority());
EXPECT_EQ(279u, run_order.size());
}
@@ -3140,7 +3156,7 @@ TEST_F(MainThreadSchedulerImplTest, EnableVirtualTime) {
EXPECT_EQ(scheduler_->DefaultTaskQueue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
- EXPECT_EQ(scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetTimeDomain(),
+ EXPECT_EQ(compositor_task_queue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
EXPECT_EQ(loading_task_queue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
@@ -3199,15 +3215,13 @@ TEST_F(MainThreadSchedulerImplTest, EnableVirtualTimeAfterThrottling) {
frame_scheduler->SetCrossOriginToMainFrame(true);
frame_scheduler->SetFrameVisible(false);
- EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled(
- throttleable_tq->GetTaskQueue()));
+ EXPECT_TRUE(throttleable_tq->IsThrottled());
scheduler_->EnableVirtualTime(
MainThreadSchedulerImpl::BaseTimeOverridePolicy::DO_NOT_OVERRIDE);
EXPECT_EQ(throttleable_tq->GetTaskQueue()->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
- EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled(
- throttleable_tq->GetTaskQueue()));
+ EXPECT_FALSE(throttleable_tq->IsThrottled());
}
TEST_F(MainThreadSchedulerImplTest, DisableVirtualTimeForTesting) {
@@ -3216,7 +3230,7 @@ TEST_F(MainThreadSchedulerImplTest, DisableVirtualTimeForTesting) {
scheduler_->DisableVirtualTimeForTesting();
EXPECT_EQ(scheduler_->DefaultTaskQueue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->real_time_domain());
- EXPECT_EQ(scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetTimeDomain(),
+ EXPECT_EQ(compositor_task_queue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->real_time_domain());
EXPECT_EQ(loading_task_queue()->GetTaskQueue()->GetTimeDomain(),
scheduler_->real_time_domain());
@@ -3342,7 +3356,7 @@ TEST_F(MainThreadSchedulerImplTest, Tracing) {
FROM_HERE, base::BindOnce(NullTask),
base::TimeDelta::FromMilliseconds(10));
- EXPECT_FALSE(scheduler_->ToString().empty());
+ scheduler_->CreateTraceEventObjectSnapshot();
}
TEST_F(MainThreadSchedulerImplTest,
@@ -4130,6 +4144,22 @@ TEST_F(BestEffortNonMainQueuesUntilOnFMPTimeoutTest,
TaskQueue::QueuePriority::kNormalPriority);
}
+TEST_F(MainThreadSchedulerImplTest, ThrottleHandleThrottlesQueue) {
+ EXPECT_FALSE(throttleable_task_queue()->IsThrottled());
+ {
+ MainThreadTaskQueue::ThrottleHandle handle =
+ throttleable_task_queue()->Throttle();
+ EXPECT_TRUE(throttleable_task_queue()->IsThrottled());
+ {
+ MainThreadTaskQueue::ThrottleHandle handle_2 =
+ throttleable_task_queue()->Throttle();
+ EXPECT_TRUE(throttleable_task_queue()->IsThrottled());
+ }
+ EXPECT_TRUE(throttleable_task_queue()->IsThrottled());
+ }
+ EXPECT_FALSE(throttleable_task_queue()->IsThrottled());
+}
+
} // namespace main_thread_scheduler_impl_unittest
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
index d2f53467c0e..0fba96bd10b 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
namespace scheduler {
@@ -146,6 +147,12 @@ void MainThreadTaskQueue::OnTaskCompleted(
}
}
+void MainThreadTaskQueue::OnTaskRunTimeReported(
+ TaskQueue::TaskTiming* task_timing) {
+ main_thread_scheduler_->task_queue_throttler()->OnTaskRunTimeReported(
+ task_queue_.get(), task_timing->start_time(), task_timing->end_time());
+}
+
void MainThreadTaskQueue::DetachFromMainThreadScheduler() {
weak_ptr_factory_.InvalidateWeakPtrs();
@@ -203,8 +210,14 @@ WebAgentGroupScheduler* MainThreadTaskQueue::GetAgentGroupScheduler() {
}
void MainThreadTaskQueue::ClearReferencesToSchedulers() {
- if (main_thread_scheduler_)
+ if (main_thread_scheduler_) {
main_thread_scheduler_->OnShutdownTaskQueue(this);
+
+ if (main_thread_scheduler_->task_queue_throttler()) {
+ main_thread_scheduler_->task_queue_throttler()->ShutdownTaskQueue(
+ task_queue_.get());
+ }
+ }
main_thread_scheduler_ = nullptr;
agent_group_scheduler_ = nullptr;
frame_scheduler_ = nullptr;
@@ -243,5 +256,62 @@ MainThreadTaskQueue::web_scheduling_priority() const {
return web_scheduling_priority_;
}
+bool MainThreadTaskQueue::IsThrottled() const {
+ if (main_thread_scheduler_) {
+ return main_thread_scheduler_->task_queue_throttler()->IsThrottled(
+ task_queue_.get());
+ } else {
+ // When the frame detaches the task queue is removed from the throttler.
+ return false;
+ }
+}
+
+MainThreadTaskQueue::ThrottleHandle MainThreadTaskQueue::Throttle() {
+ DCHECK(CanBeThrottled());
+ return ThrottleHandle(
+ task_queue_.get()->AsWeakPtr(),
+ main_thread_scheduler_->task_queue_throttler()->AsWeakPtr());
+}
+
+void MainThreadTaskQueue::AddToBudgetPool(base::TimeTicks now,
+ BudgetPool* pool) {
+ pool->AddQueue(now, task_queue_.get());
+}
+
+void MainThreadTaskQueue::RemoveFromBudgetPool(base::TimeTicks now,
+ BudgetPool* pool) {
+ pool->RemoveQueue(now, task_queue_.get());
+}
+
+void MainThreadTaskQueue::SetImmediateWakeUpForTest() {
+ if (main_thread_scheduler_) {
+ main_thread_scheduler_->task_queue_throttler()->OnQueueNextWakeUpChanged(
+ task_queue_.get(), base::TimeTicks());
+ }
+}
+
+void MainThreadTaskQueue::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("type", queue_type_);
+ dict.Add("traits", queue_traits_);
+}
+
+void MainThreadTaskQueue::QueueTraits::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("can_be_deferred", can_be_deferred);
+ dict.Add("can_be_throttled", can_be_throttled);
+ dict.Add("can_be_intensively_throttled", can_be_intensively_throttled);
+ dict.Add("can_be_paused", can_be_paused);
+ dict.Add("can_be_frozen", can_be_frozen);
+ dict.Add("can_run_in_background", can_run_in_background);
+ dict.Add("can_run_when_virtual_time_paused",
+ can_run_when_virtual_time_paused);
+ dict.Add("can_be_paused_for_android_webview",
+ can_be_paused_for_android_webview);
+ dict.Add("prioritisation_type", prioritisation_type);
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index b9248e18703..7aa393f6e1d 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -13,9 +13,12 @@
#include "base/task/sequence_manager/task_queue_impl.h"
#include "base/task/sequence_manager/time_domain.h"
#include "net/base/request_priority.h"
+#include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
+#include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace sequence_manager {
@@ -36,6 +39,10 @@ namespace agent_interference_recorder_test {
class AgentInterferenceRecorderTest;
}
+namespace task_queue_throttler_unittest {
+class TaskQueueThrottlerTest;
+}
+
class FrameSchedulerImpl;
class MainThreadSchedulerImpl;
@@ -92,6 +99,36 @@ class PLATFORM_EXPORT MainThreadTaskQueue
kCount = 27
};
+ // The ThrottleHandle controls throttling and unthrottling the queue. When
+ // a caller requests a queue to be throttled, this handle is returned and
+ // the queue will remain throttled as long as the handle is alive.
+ class ThrottleHandle {
+ public:
+ ThrottleHandle(base::WeakPtr<TaskQueue> task_queue,
+ base::WeakPtr<TaskQueueThrottler> throttler)
+ : task_queue_(std::move(task_queue)), throttler_(std::move(throttler)) {
+ if (task_queue_ && throttler_)
+ throttler_->IncreaseThrottleRefCount(task_queue_.get());
+ }
+ ~ThrottleHandle() {
+ if (task_queue_ && throttler_)
+ throttler_->DecreaseThrottleRefCount(task_queue_.get());
+ }
+
+ // Move-only.
+ ThrottleHandle(ThrottleHandle&& other)
+ : task_queue_(std::move(other.task_queue_)),
+ throttler_(std::move(other.throttler_)) {
+ other.task_queue_ = nullptr;
+ other.throttler_ = nullptr;
+ }
+ ThrottleHandle& operator=(ThrottleHandle&&);
+
+ private:
+ base::WeakPtr<TaskQueue> task_queue_;
+ base::WeakPtr<TaskQueueThrottler> throttler_;
+ };
+
// Returns name of the given queue type. Returned string has application
// lifetime.
static const char* NameForQueueType(QueueType queue_type);
@@ -228,6 +265,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue
return key;
}
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
bool can_be_deferred : 1;
bool can_be_throttled : 1;
bool can_be_intensively_throttled : 1;
@@ -258,6 +297,17 @@ class PLATFORM_EXPORT MainThreadTaskQueue
return *this;
}
+ QueueCreationParams SetAgentGroupScheduler(
+ AgentGroupSchedulerImpl* scheduler) {
+ agent_group_scheduler = scheduler;
+ return *this;
+ }
+
+ QueueCreationParams SetFrameScheduler(FrameSchedulerImpl* scheduler) {
+ frame_scheduler = scheduler;
+ return *this;
+ }
+
// Forwarded calls to |queue_traits|
QueueCreationParams SetCanBeDeferred(bool value) {
@@ -311,17 +361,6 @@ class PLATFORM_EXPORT MainThreadTaskQueue
// Forwarded calls to |spec|.
- QueueCreationParams SetAgentGroupScheduler(
- AgentGroupSchedulerImpl* scheduler) {
- agent_group_scheduler = scheduler;
- return *this;
- }
-
- QueueCreationParams SetFrameScheduler(FrameSchedulerImpl* scheduler) {
- frame_scheduler = scheduler;
- return *this;
- }
-
QueueCreationParams SetShouldMonitorQuiescence(bool should_monitor) {
spec = spec.SetShouldMonitorQuiescence(should_monitor);
return *this;
@@ -440,13 +479,38 @@ class PLATFORM_EXPORT MainThreadTaskQueue
return task_queue_->task_runner();
}
+ bool IsThrottled() const;
+
+ // Throttles the task queue as long as the handle is kept alive.
+ MainThreadTaskQueue::ThrottleHandle Throttle();
+
+ // Called when a task finished running to update cpu-based throttling.
+ void OnTaskRunTimeReported(TaskQueue::TaskTiming* task_timing);
+
+ // Methods for setting and resetting budget pools for this task queue.
+ // Note that a task queue can be in multiple budget pools so a pool must
+ // be specified when resetting.
+ void AddToBudgetPool(base::TimeTicks now, BudgetPool* pool);
+ void RemoveFromBudgetPool(base::TimeTicks now, BudgetPool* pool);
+
+ // This method is only used for tests. If this queue is throttled it will
+ // notify the throttler that this queue should wake immediately.
+ void SetImmediateWakeUpForTest();
+
base::WeakPtr<MainThreadTaskQueue> AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
protected:
void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler);
+ // Returns the underlying task queue. Only to be used for tests that need to
+ // test functionality of the task queue specifically without the wrapping
+ // MainThreadTaskQueue (ex TaskQueueThrottlerTest).
+ TaskQueue* GetTaskQueueForTest() { return task_queue_.get(); }
+
// TODO(kdillon): Remove references to TaskQueueImpl once TaskQueueImpl
// inherits from TaskQueue.
MainThreadTaskQueue(
@@ -463,6 +527,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue
friend class blink::scheduler::main_thread_scheduler_impl_unittest::
MainThreadSchedulerImplTest;
friend class agent_interference_recorder_test::AgentInterferenceRecorderTest;
+ friend class blink::scheduler::task_queue_throttler_unittest::
+ TaskQueueThrottlerTest;
// Clear references to main thread scheduler and frame scheduler and dispatch
// appropriate notifications. This is the common part of ShutdownTaskQueue and
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc
index 992fe514fdb..559600ee9f0 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc
@@ -51,13 +51,13 @@ class MainThreadTest : public testing::Test {
void SetUp() override {
clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
- scheduler_.reset(new MainThreadSchedulerImpl(
+ scheduler_ = std::make_unique<MainThreadSchedulerImpl>(
base::sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
base::MessagePump::Create(base::MessagePumpType::DEFAULT),
base::sequence_manager::SequenceManager::Settings::Builder()
.SetTickClock(&clock_)
.Build()),
- base::nullopt));
+ base::nullopt);
scheduler_overrider_ =
std::make_unique<ScopedSchedulerOverrider>(scheduler_.get());
thread_ = Thread::Current();
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index c1b6afdf5ac..5955efb7baf 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
namespace scheduler {
@@ -170,13 +171,12 @@ constexpr base::TimeDelta PageSchedulerImpl::kDefaultThrottledWakeUpInterval;
PageSchedulerImpl::PageSchedulerImpl(
PageScheduler::Delegate* delegate,
AgentGroupSchedulerImpl& agent_group_scheduler)
- : main_thread_scheduler_(&agent_group_scheduler.GetMainThreadScheduler()),
+ : main_thread_scheduler_(static_cast<MainThreadSchedulerImpl*>(
+ &agent_group_scheduler.GetMainThreadScheduler())),
agent_group_scheduler_(agent_group_scheduler),
page_visibility_(kDefaultPageVisibility),
page_visibility_changed_time_(
- agent_group_scheduler.GetMainThreadScheduler()
- .GetTickClock()
- ->NowTicks()),
+ main_thread_scheduler_->GetTickClock()->NowTicks()),
audio_state_(AudioState::kSilent),
is_frozen_(false),
reported_background_throttling_since_navigation_(false),
@@ -185,9 +185,9 @@ PageSchedulerImpl::PageSchedulerImpl(
is_main_frame_local_(false),
is_cpu_time_throttled_(false),
are_wake_ups_intensively_throttled_(false),
- keep_active_(
- agent_group_scheduler.GetMainThreadScheduler().SchedulerKeepActive()),
+ keep_active_(main_thread_scheduler_->SchedulerKeepActive()),
had_recent_title_or_favicon_update_(false),
+ focused_(delegate ? delegate->IsFocused() : true),
delegate_(delegate),
delay_for_background_tab_freezing_(GetDelayForBackgroundTabFreezing()),
freeze_on_network_idle_enabled_(base::FeatureList::IsEnabled(
@@ -362,6 +362,13 @@ void PageSchedulerImpl::SetPageBackForwardCached(
}
}
+void PageSchedulerImpl::OnFocusChanged(bool focused) {
+ DCHECK_NE(focused_, focused);
+
+ focused_ = focused;
+ NotifyFrames();
+}
+
void PageSchedulerImpl::SetUpIPCTaskDetection() {
DCHECK(is_stored_in_back_forward_cache_);
has_ipc_detection_enabled_ = true;
@@ -581,6 +588,10 @@ void PageSchedulerImpl::OnTraceLogEnabled() {
}
}
+bool PageSchedulerImpl::IsPageFocused() const {
+ return focused_;
+}
+
bool PageSchedulerImpl::IsWaitingForMainFrameContentfulPaint() const {
return std::any_of(frame_schedulers_.begin(), frame_schedulers_.end(),
[](const FrameSchedulerImpl* fs) {
@@ -599,40 +610,33 @@ bool PageSchedulerImpl::IsWaitingForMainFrameMeaningfulPaint() const {
});
}
-void PageSchedulerImpl::AsValueInto(
- base::trace_event::TracedValue* state) const {
- state->SetBoolean("page_visible",
- page_visibility_ == PageVisibilityState::kVisible);
- state->SetBoolean("is_audio_playing", IsAudioPlaying());
- state->SetBoolean("is_frozen", is_frozen_);
- state->SetBoolean("reported_background_throttling_since_navigation",
- reported_background_throttling_since_navigation_);
- state->SetBoolean("is_page_freezable", IsBackgrounded());
+void PageSchedulerImpl::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("page_visible", page_visibility_ == PageVisibilityState::kVisible);
+ dict.Add("is_audio_playing", IsAudioPlaying());
+ dict.Add("is_frozen", is_frozen_);
+ dict.Add("reported_background_throttling_since_navigation",
+ reported_background_throttling_since_navigation_);
+ dict.Add("is_page_freezable", IsBackgrounded());
- {
- auto dictionary_scope = state->BeginDictionaryScoped("frame_schedulers");
- for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
- auto inner_dictionary = state->BeginDictionaryScopedWithCopiedName(
- PointerToString(frame_scheduler));
- frame_scheduler->AsValueInto(state);
- }
- }
+ dict.Add("frame_schedulers", frame_schedulers_);
}
void PageSchedulerImpl::AddQueueToWakeUpBudgetPool(
MainThreadTaskQueue* task_queue,
FrameOriginType frame_origin_type,
base::sequence_manager::LazyNow* lazy_now) {
- GetWakeUpBudgetPool(task_queue, frame_origin_type)
- ->AddQueue(lazy_now->Now(), task_queue->GetTaskQueue());
+ task_queue->AddToBudgetPool(
+ lazy_now->Now(), GetWakeUpBudgetPool(task_queue, frame_origin_type));
}
void PageSchedulerImpl::RemoveQueueFromWakeUpBudgetPool(
MainThreadTaskQueue* task_queue,
FrameOriginType frame_origin_type,
base::sequence_manager::LazyNow* lazy_now) {
- GetWakeUpBudgetPool(task_queue, frame_origin_type)
- ->RemoveQueue(lazy_now->Now(), task_queue->GetTaskQueue());
+ task_queue->RemoveFromBudgetPool(
+ lazy_now->Now(), GetWakeUpBudgetPool(task_queue, frame_origin_type));
}
WakeUpBudgetPool* PageSchedulerImpl::GetWakeUpBudgetPool(
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index 27dfaabae38..5aee3226986 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -25,11 +25,11 @@
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace base {
namespace trace_event {
class BlameContext;
-class TracedValue;
} // namespace trace_event
} // namespace base
@@ -63,6 +63,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler {
void SetPageVisible(bool page_visible) override;
void SetPageFrozen(bool) override;
void SetPageBackForwardCached(bool) override;
+ void OnFocusChanged(bool focused) override;
void SetKeepActive(bool) override;
bool IsMainFrameLocal() const override;
void SetIsMainFrameLocal(bool is_local) override;
@@ -126,6 +127,8 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler {
void OnTraceLogEnabled();
+ bool IsPageFocused() const;
+
// Virtual for testing.
virtual bool IsWaitingForMainFrameContentfulPaint() const;
virtual bool IsWaitingForMainFrameMeaningfulPaint() const;
@@ -148,7 +151,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler {
// frame it not a local one.
FrameSchedulerImpl* SelectFrameForUkmAttribution();
- void AsValueInto(base::trace_event::TracedValue* state) const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
base::WeakPtr<PageSchedulerImpl> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
@@ -316,6 +319,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler {
bool are_wake_ups_intensively_throttled_;
bool keep_active_;
bool had_recent_title_or_favicon_update_;
+ bool focused_;
CPUTimeBudgetPool* cpu_time_budget_pool_ = nullptr;
// Wake up budget pools for each throttling scenario:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
index 508f17c8cb5..534a809e6d3 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
@@ -21,6 +21,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
@@ -82,6 +83,7 @@ class MockPageSchedulerDelegate : public PageScheduler::Delegate {
void SetLocalMainFrameNetworkIsAlmostIdle(bool idle) { idle_ = idle; }
bool LocalMainFrameNetworkIsAlmostIdle() const override { return idle_; }
+ bool IsFocused() const override { return true; }
private:
void ReportIntervention(const WTF::String&) override {}
@@ -285,17 +287,6 @@ class PageSchedulerImplTest : public testing::Test {
base::test::ScopedFeatureList feature_list_;
};
-class PageSchedulerImplStopNonTimersInBackgroundEnabledTest
- : public PageSchedulerImplTest {
- public:
- PageSchedulerImplStopNonTimersInBackgroundEnabledTest()
- : PageSchedulerImplTest({blink::features::kStopInBackground,
- blink::features::kStopNonTimersInBackground},
- {}) {}
-
- ~PageSchedulerImplStopNonTimersInBackgroundEnabledTest() override = default;
-};
-
TEST_F(PageSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) {
std::unique_ptr<blink::FrameScheduler> frame1(
page_scheduler_->CreateFrameScheduler(
@@ -1318,15 +1309,13 @@ TEST_F(PageSchedulerImplTest, OpenWebSocketExemptsFromBudgetThrottling) {
// Verify that freezing a page prevents tasks in its task queues from running.
// Then, verify that making the page visible unfreezes it and allows tasks in
// its task queues to run.
-TEST_F(PageSchedulerImplStopNonTimersInBackgroundEnabledTest,
- PageFreezeAndSetVisible) {
+TEST_F(PageSchedulerImplTest, PageFreezeAndSetVisible) {
TestFreeze(true);
}
// Same as before, but unfreeze the page explicitly instead of making it
// visible.
-TEST_F(PageSchedulerImplStopNonTimersInBackgroundEnabledTest,
- PageFreezeAndUnfreeze) {
+TEST_F(PageSchedulerImplTest, PageFreezeAndUnfreeze) {
TestFreeze(false);
}
@@ -1363,23 +1352,19 @@ TEST_F(PageSchedulerImplTest, PageSchedulerDestroyedWhileAudioChangePending) {
TEST_F(PageSchedulerImplTest, AudiblePagesAreNotThrottled) {
page_scheduler_->SetPageVisible(false);
- EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled(
- ThrottleableTaskQueue()->GetTaskQueue()));
+ EXPECT_TRUE(ThrottleableTaskQueue()->IsThrottled());
// No throttling when the page is audible.
page_scheduler_->AudioStateChanged(true);
- EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled(
- ThrottleableTaskQueue()->GetTaskQueue()));
+ EXPECT_FALSE(ThrottleableTaskQueue()->IsThrottled());
// No throttling for some time after audio signal disappears.
page_scheduler_->AudioStateChanged(false);
- EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled(
- ThrottleableTaskQueue()->GetTaskQueue()));
+ EXPECT_FALSE(ThrottleableTaskQueue()->IsThrottled());
// Eventually throttling is reenabled again.
test_task_runner_->FastForwardUntilNoTasksRemain();
- EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled(
- ThrottleableTaskQueue()->GetTaskQueue()));
+ EXPECT_TRUE(ThrottleableTaskQueue()->IsThrottled());
}
TEST_F(PageSchedulerImplTest, BudgetBasedThrottlingForPageScheduler) {
@@ -1762,6 +1747,88 @@ TEST_F(PageSchedulerImplPageTransitionTest,
UnorderedElementsAreArray(GetExpectedBuckets()));
}
+class PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest
+ : public PageSchedulerImplTest {
+ public:
+ PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest()
+ : PageSchedulerImplTest(
+ {blink::features::kStopInBackground,
+ blink::scheduler::kThrottleVisibleNotFocusedTimers},
+ {}) {}
+};
+
+TEST_F(PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest,
+ PageVisibleWithFocus) {
+ page_scheduler_->SetPageVisible(true);
+ if (!page_scheduler_->IsPageFocused())
+ page_scheduler_->OnFocusChanged(true);
+
+ int run_count = 0;
+ ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostDelayedTask(
+ FROM_HERE,
+ MakeRepeatingTask(
+ ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType(),
+ &run_count, base::TimeDelta::FromMilliseconds(20)),
+ base::TimeDelta::FromMilliseconds(20));
+
+ test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(50, run_count);
+
+ // Create a new frame when the page has focus
+ int frame_run_count = 0;
+ std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 =
+ CreateFrameScheduler(page_scheduler_.get(), nullptr, nullptr,
+ FrameScheduler::FrameType::kSubframe);
+ ThrottleableTaskQueueForScheduler(frame_scheduler2.get())
+ ->GetTaskRunnerWithDefaultTaskType()
+ ->PostDelayedTask(
+ FROM_HERE,
+ MakeRepeatingTask(
+ ThrottleableTaskQueueForScheduler(frame_scheduler2.get())
+ ->GetTaskRunnerWithDefaultTaskType(),
+ &frame_run_count, base::TimeDelta::FromMilliseconds(20)),
+ base::TimeDelta::FromMilliseconds(20));
+
+ test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(50, frame_run_count);
+}
+
+TEST_F(PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest,
+ PageVisibleWithoutFocus) {
+ page_scheduler_->SetPageVisible(true);
+ if (page_scheduler_->IsPageFocused())
+ page_scheduler_->OnFocusChanged(false);
+
+ int run_count = 0;
+ ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostDelayedTask(
+ FROM_HERE,
+ MakeRepeatingTask(
+ ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType(),
+ &run_count, base::TimeDelta::FromMilliseconds(20)),
+ base::TimeDelta::FromMilliseconds(20));
+
+ test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, run_count);
+
+ // Create a new frame when the page doesn't have focus
+ int frame_run_count = 0;
+ std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 =
+ CreateFrameScheduler(page_scheduler_.get(), nullptr, nullptr,
+ FrameScheduler::FrameType::kSubframe);
+ ThrottleableTaskQueueForScheduler(frame_scheduler2.get())
+ ->GetTaskRunnerWithDefaultTaskType()
+ ->PostDelayedTask(
+ FROM_HERE,
+ MakeRepeatingTask(
+ ThrottleableTaskQueueForScheduler(frame_scheduler2.get())
+ ->GetTaskRunnerWithDefaultTaskType(),
+ &frame_run_count, base::TimeDelta::FromMilliseconds(20)),
+ base::TimeDelta::FromMilliseconds(20));
+
+ test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, frame_run_count);
+}
+
} // namespace page_scheduler_impl_unittest
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc
index 4d13b8ad29b..1441803981e 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc
@@ -7,6 +7,7 @@
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "third_party/blink/public/platform/scheduler/web_render_widget_scheduling_state.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
namespace scheduler {
@@ -51,13 +52,12 @@ void RenderWidgetSignals::DecNumVisibleRenderWidgetsWithTouchHandlers() {
observer_->SetHasVisibleRenderWidgetWithTouchHandler(false);
}
-void RenderWidgetSignals::AsValueInto(
- base::trace_event::TracedValue* state) const {
- auto dictionary_scope =
- state->BeginDictionaryScoped("renderer_widget_signals");
- state->SetInteger("num_visible_render_widgets", num_visible_render_widgets_);
- state->SetInteger("num_visible_render_widgets_with_touch_handlers",
- num_visible_render_widgets_with_touch_handlers_);
+void RenderWidgetSignals::WriteIntoTracedValue(
+ perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("num_visible_render_widgets", num_visible_render_widgets_);
+ dict.Add("num_visible_render_widgets_with_touch_handlers",
+ num_visible_render_widgets_with_touch_handlers_);
}
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h
index f484d89c8f2..81a2d411ed9 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h
@@ -11,6 +11,7 @@
#include "base/trace_event/traced_value.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace blink {
namespace scheduler {
@@ -43,7 +44,7 @@ class PLATFORM_EXPORT RenderWidgetSignals {
std::unique_ptr<WebRenderWidgetSchedulingState>
NewRenderWidgetSchedulingState();
- void AsValueInto(base::trace_event::TracedValue* state) const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
private:
friend class WebRenderWidgetSchedulingState;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
index 6084494be0a..a1a5df6aa69 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
@@ -145,6 +145,8 @@ const char* TaskTypeNames::TaskTypeToString(TaskType task_type) {
return "InternalHighPriorityLocalFrame";
case TaskType::kMainThreadTaskQueueIPCTracking:
return "MainThreadTaskQueueIPCTracking";
+ case TaskType::kWakeLock:
+ return "WakeLock";
case TaskType::kCount:
return "Count";
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc
index 14ed5d50e33..e955335dc93 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/scheduler/main_thread/user_model.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace blink {
namespace scheduler {
@@ -140,25 +141,17 @@ void UserModel::Reset(base::TimeTicks now) {
pending_input_event_count_ = 0;
}
-void UserModel::AsValueInto(base::trace_event::TracedValue* state) const {
- auto dictionary_scope = state->BeginDictionaryScoped("user_model");
- state->SetInteger("pending_input_event_count", pending_input_event_count_);
- state->SetDouble(
- "last_input_signal_time",
- (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
- "last_gesture_start_time",
- (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
- "last_continuous_gesture_time",
- (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble("last_gesture_expected_start_time",
- (last_gesture_expected_start_time_ - base::TimeTicks())
- .InMillisecondsF());
- state->SetDouble("last_reset_time",
- (last_reset_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetBoolean("is_gesture_expected", is_gesture_expected_);
- state->SetBoolean("is_gesture_active", is_gesture_active_);
+void UserModel::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("pending_input_event_count", pending_input_event_count_);
+ dict.Add("last_input_signal_time", last_input_signal_time_);
+ dict.Add("last_gesture_start_time", last_gesture_start_time_);
+ dict.Add("last_continuous_gesture_time", last_continuous_gesture_time_);
+ dict.Add("last_gesture_expected_start_time",
+ last_gesture_expected_start_time_);
+ dict.Add("last_reset_time", last_reset_time_);
+ dict.Add("is_gesture_expected", is_gesture_expected_);
+ dict.Add("is_gesture_active", is_gesture_active_);
}
} // namespace scheduler
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h
index fb7d2b79468..7affc23ce28 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h
@@ -12,6 +12,7 @@
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace blink {
namespace scheduler {
@@ -48,7 +49,7 @@ class PLATFORM_EXPORT UserModel {
const base::TimeTicks now,
base::TimeDelta* prediction_valid_duration) const;
- void AsValueInto(base::trace_event::TracedValue* state) const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
// The time we should stay in a priority-escalated mode after an input event.
static const int kGestureEstimationLimitMillis = 100;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h
index a8c17ebd73e..89b472e1e68 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_AGENT_GROUP_SCHEDULER_H_
#include "base/single_thread_task_runner.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
@@ -21,6 +22,8 @@ class BLINK_PLATFORM_EXPORT AgentGroupScheduler
// associated WebThread.
virtual std::unique_ptr<PageScheduler> CreatePageScheduler(
PageScheduler::Delegate*) = 0;
+
+ virtual BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
index 0e90edae0b4..8b7cf123371 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_FRAME_OR_WORKER_SCHEDULER_H_
#include "base/memory/weak_ptr.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_lifecycle_state.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
@@ -87,7 +87,7 @@ class PLATFORM_EXPORT FrameOrWorkerScheduler {
virtual ~FrameOrWorkerScheduler();
- using Preempted = util::StrongAlias<class PreemptedTag, bool>;
+ using Preempted = base::StrongAlias<class PreemptedTag, bool>;
// Stops any tasks from running while we yield and run a nested loop.
virtual void SetPreemptedForCooperativeScheduling(Preempted) = 0;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
index db5544facc5..795ed1f870a 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
@@ -38,6 +38,8 @@ class PLATFORM_EXPORT PageScheduler {
// Returns true iff the network is idle for the local main frame.
// Always returns false if the main frame is remote.
virtual bool LocalMainFrameNetworkIsAlmostIdle() const { return true; }
+ // Returns if the page has focus.
+ virtual bool IsFocused() const = 0;
};
virtual ~PageScheduler() = default;
@@ -51,6 +53,8 @@ class PLATFORM_EXPORT PageScheduler {
virtual void SetPageFrozen(bool) = 0;
// Handles operations required for storing the page in the back-forward cache.
virtual void SetPageBackForwardCached(bool) = 0;
+ // Handle page focus changed.
+ virtual void OnFocusChanged(bool focused) = 0;
// Tells the scheduler about "keep-alive" state which can be due to:
// service workers, shared workers, or fetch keep-alive.
// If true, then the scheduler should not freeze relevant task queues.
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h b/chromium/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h
index e51068ebb2f..70e3bdbd8ee 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h
@@ -19,11 +19,11 @@ struct PLATFORM_EXPORT SchedulingPolicy {
// List of opt-outs which form a policy.
struct DisableAggressiveThrottling {};
- struct RecordMetricsForBackForwardCache {};
+ struct DisableBackForwardCache {};
struct ValidPolicies {
ValidPolicies(DisableAggressiveThrottling);
- ValidPolicies(RecordMetricsForBackForwardCache);
+ ValidPolicies(DisableBackForwardCache);
};
template <class... ArgTypes,
@@ -35,7 +35,7 @@ struct PLATFORM_EXPORT SchedulingPolicy {
base::trait_helpers::HasTrait<DisableAggressiveThrottling,
ArgTypes...>()),
disable_back_forward_cache(
- base::trait_helpers::HasTrait<RecordMetricsForBackForwardCache,
+ base::trait_helpers::HasTrait<DisableBackForwardCache,
ArgTypes...>()) {}
SchedulingPolicy() {}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/public/thread.h b/chromium/third_party/blink/renderer/platform/scheduler/public/thread.h
index 6f6b57e5eef..7512cc93e53 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/public/thread.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/public/thread.h
@@ -126,7 +126,6 @@ class PLATFORM_EXPORT Thread {
}
bool IsCurrentThread() const;
- virtual PlatformThreadId ThreadId() const { return 0; }
// TaskObserver is an object that receives task notifications from the
// MessageLoop.
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
index bc4b59fd1aa..0779cb5c427 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
@@ -48,8 +48,6 @@ CompositorThreadScheduler::DefaultTaskQueue() {
return helper()->DefaultNonMainThreadTaskQueue();
}
-void CompositorThreadScheduler::InitImpl() {}
-
void CompositorThreadScheduler::OnTaskCompleted(
NonMainThreadTaskQueue* worker_task_queue,
const base::sequence_manager::Task& task,
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
index cb324d6addb..61c35b52d82 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
@@ -61,10 +61,6 @@ class PLATFORM_EXPORT CompositorThreadScheduler
void DidProcessIdleTask() override;
base::TimeTicks NowTicks() override;
- protected:
- // NonMainThreadScheduler:
- void InitImpl() override;
-
private:
CompositorMetricsHelper compositor_metrics_helper_;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
index 4fd8354c949..1471095a229 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
@@ -29,10 +29,6 @@ std::unique_ptr<NonMainThreadSchedulerImpl> NonMainThreadSchedulerImpl::Create(
proxy);
}
-void NonMainThreadSchedulerImpl::Init() {
- InitImpl();
-}
-
scoped_refptr<NonMainThreadTaskQueue>
NonMainThreadSchedulerImpl::CreateTaskQueue(const char* name) {
helper_.CheckOnValidThread();
@@ -122,5 +118,9 @@ NonMainThreadSchedulerImpl::DeprecatedDefaultTaskRunner() {
return DefaultTaskRunner();
}
+void NonMainThreadSchedulerImpl::AttachToCurrentThread() {
+ helper_.AttachToCurrentThread();
+}
+
} // namespace scheduler
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
index 9822d33782d..901003735df 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
@@ -37,13 +37,17 @@ class PLATFORM_EXPORT NonMainThreadSchedulerImpl : public ThreadSchedulerImpl {
base::sequence_manager::SequenceManager* sequence_manager,
WorkerSchedulerProxy* proxy);
- // Blink should use NonMainThreadSchedulerImpl::DefaultTaskQueue instead of
- // WebThreadScheduler::DefaultTaskRunner.
- virtual scoped_refptr<NonMainThreadTaskQueue> DefaultTaskQueue() = 0;
+ // Performs initialization that must occur after the constructor of all
+ // subclasses has run. Must be invoked before any other method. Must be
+ // invoked on the same sequence as the constructor.
+ virtual void Init() {}
+
+ // Attaches the scheduler to the current thread. Must be invoked on the thread
+ // that runs tasks from this scheduler, before running tasks from this
+ // scheduler.
+ void AttachToCurrentThread();
- // Must be called before the scheduler can be used. Does any post construction
- // initialization needed such as initializing idle period detection.
- void Init();
+ virtual scoped_refptr<NonMainThreadTaskQueue> DefaultTaskQueue() = 0;
virtual void OnTaskCompleted(
NonMainThreadTaskQueue* worker_task_queue,
@@ -108,9 +112,6 @@ class PLATFORM_EXPORT NonMainThreadSchedulerImpl : public ThreadSchedulerImpl {
friend class WorkerScheduler;
- // Called during Init() for delayed initialization for subclasses.
- virtual void InitImpl() = 0;
-
NonMainThreadSchedulerHelper* helper() { return &helper_; }
private:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index 3ad29aac8d1..6bbe09cb041 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/platform/back_forward_cache_utils.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h"
#include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
@@ -174,6 +175,7 @@ scoped_refptr<base::SingleThreadTaskRunner> WorkerScheduler::GetTaskRunner(
case TaskType::kInternalIntersectionObserver:
case TaskType::kInternalNavigationAssociated:
case TaskType::kInternalContinueScriptLoading:
+ case TaskType::kWakeLock:
// UnthrottledTaskRunner is generally discouraged in future.
// TODO(nhiroki): Identify which tasks can be throttled / suspendable and
// move them into other task runners. See also comments in
@@ -192,7 +194,7 @@ scoped_refptr<base::SingleThreadTaskRunner> WorkerScheduler::GetTaskRunner(
// Get(LocalFrame). (https://crbug.com/670534)
return unpausable_task_queue_->CreateTaskRunner(type);
case TaskType::kNetworkingUnfreezable:
- return base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)
+ return IsInflightNetworkRequestBackForwardCacheSupportEnabled()
? unpausable_task_queue_->CreateTaskRunner(type)
: pausable_task_queue_->CreateTaskRunner(type);
case TaskType::kMainThreadTaskQueueV8:
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
index 2ce24161bde..56c124474d8 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
@@ -8,6 +8,7 @@
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequence_manager/test/sequence_manager_for_test.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -76,9 +77,14 @@ class WorkerThreadForTest : public WorkerThread {
auto scheduler = std::make_unique<WorkerThreadSchedulerForTest>(
manager, worker_scheduler_proxy(), throtting_state_changed_);
scheduler_ = scheduler.get();
+ return scheduler;
+ }
+
+ void CreateWorkerScheduler() {
+ DCHECK(scheduler_);
+ DCHECK(!worker_scheduler_);
worker_scheduler_ = std::make_unique<scheduler::WorkerScheduler>(
scheduler_, worker_scheduler_proxy());
- return scheduler;
}
WorkerThreadSchedulerForTest* GetWorkerScheduler() { return scheduler_; }
@@ -86,7 +92,7 @@ class WorkerThreadForTest : public WorkerThread {
private:
base::WaitableEvent* throtting_state_changed_; // NOT OWNED
WorkerThreadSchedulerForTest* scheduler_ = nullptr; // NOT OWNED
- std::unique_ptr<WorkerScheduler> worker_scheduler_ = nullptr;
+ std::unique_ptr<WorkerScheduler> worker_scheduler_;
};
std::unique_ptr<WorkerThreadForTest> CreateWorkerThread(
@@ -95,6 +101,17 @@ std::unique_ptr<WorkerThreadForTest> CreateWorkerThread(
auto thread = std::make_unique<WorkerThreadForTest>(frame_scheduler,
throtting_state_changed);
thread->Init();
+
+ base::RunLoop run_loop;
+ thread->GetTaskRunner()->PostTask(FROM_HERE,
+ base::BindLambdaForTesting([&]() {
+ // The WorkerScheduler must be created on
+ // the worker thread.
+ thread->CreateWorkerScheduler();
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
return thread;
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
index 6e59cb0a07e..932a3418b26 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_unittest.cc
@@ -105,6 +105,7 @@ class WorkerSchedulerTest : public testing::Test {
void SetUp() override {
scheduler_->Init();
+ scheduler_->AttachToCurrentThread();
worker_scheduler_ =
std::make_unique<WorkerSchedulerForTest>(scheduler_.get());
}
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.cc
index 8d3ea5f1d9c..c4d20ba6c45 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.cc
@@ -33,13 +33,10 @@ WorkerThread::WorkerThread(const ThreadCreationParams& params)
params.frame_or_worker_scheduler)
: nullptr),
supports_gc_(params.supports_gc) {
- auto non_main_thread_scheduler_factory = base::BindOnce(
- &WorkerThread::CreateNonMainThreadScheduler, base::Unretained(this));
base::SimpleThread::Options options;
options.priority = params.thread_priority;
thread_ = std::make_unique<SimpleThreadImpl>(
- params.name ? params.name : String(), options,
- std::move(non_main_thread_scheduler_factory), supports_gc_,
+ params.name ? params.name : String(), options, supports_gc_,
const_cast<scheduler::WorkerThread*>(this));
if (supports_gc_) {
MemoryPressureListenerRegistry::Instance().RegisterThread(
@@ -58,11 +55,8 @@ WorkerThread::~WorkerThread() {
}
void WorkerThread::Init() {
+ thread_->CreateScheduler();
thread_->StartAsync();
- // TODO(carlscab): We could get rid of this if the NonMainThreadSchedulerImpl
- // and the default_task_runner could be created on the main thread and then
- // bound in the worker thread (similar to what happens with SequenceManager)
- thread_->WaitForInit();
}
std::unique_ptr<NonMainThreadSchedulerImpl>
@@ -72,10 +66,6 @@ WorkerThread::CreateNonMainThreadScheduler(
worker_scheduler_proxy_.get());
}
-blink::PlatformThreadId WorkerThread::ThreadId() const {
- return thread_->tid();
-}
-
blink::ThreadScheduler* WorkerThread::Scheduler() {
return thread_->GetNonMainThreadScheduler();
}
@@ -91,14 +81,12 @@ void WorkerThread::ShutdownOnThread() {
}
WorkerThread::SimpleThreadImpl::SimpleThreadImpl(
- const String& name_prefix,
+ const WTF::String& name_prefix,
const base::SimpleThread ::Options& options,
- NonMainThreadSchedulerFactory factory,
bool supports_gc,
WorkerThread* worker_thread)
: SimpleThread(name_prefix.Utf8(), options),
thread_(worker_thread),
- scheduler_factory_(std::move(factory)),
supports_gc_(supports_gc) {
// TODO(alexclarke): Do we need to unify virtual time for workers and the main
// thread?
@@ -113,15 +101,17 @@ WorkerThread::SimpleThreadImpl::SimpleThreadImpl(
base::sequence_manager::kTaskTypeNone);
}
-void WorkerThread::SimpleThreadImpl::WaitForInit() {
- if (is_initialized_.IsSet())
- return;
- base::WaitableEvent initialized;
- internal_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
- base::Unretained(&initialized)));
- base::ScopedAllowBaseSyncPrimitives allow_wait;
- initialized.Wait();
+void WorkerThread::SimpleThreadImpl::CreateScheduler() {
+ DCHECK(!non_main_thread_scheduler_);
+ DCHECK(!default_task_runner_);
+ DCHECK(sequence_manager_);
+
+ non_main_thread_scheduler_ =
+ thread_->CreateNonMainThreadScheduler(sequence_manager_.get());
+ non_main_thread_scheduler_->Init();
+ default_task_runner_ =
+ non_main_thread_scheduler_->DefaultTaskQueue()->CreateTaskRunner(
+ TaskType::kWorkerThreadTaskQueueDefault);
}
WorkerThread::GCSupport::GCSupport(WorkerThread* thread) {
@@ -133,9 +123,6 @@ WorkerThread::GCSupport::GCSupport(WorkerThread* thread) {
}
WorkerThread::GCSupport::~GCSupport() {
-#if defined(LEAK_SANITIZER)
- ThreadState::Current()->ReleaseStaticPersistentNodes();
-#endif
// Ensure no posted tasks will run from this point on.
gc_task_runner_.reset();
blink_gc_memory_dump_provider_.reset();
@@ -148,20 +135,17 @@ void WorkerThread::SimpleThreadImpl::ShutdownOnThread() {
}
void WorkerThread::SimpleThreadImpl::Run() {
+ DCHECK(non_main_thread_scheduler_)
+ << "CreateScheduler() should be called before starting the thread.";
+ non_main_thread_scheduler_->AttachToCurrentThread();
+
auto scoped_sequence_manager = std::move(sequence_manager_);
auto scoped_internal_task_queue = std::move(internal_task_queue_);
scoped_sequence_manager->BindToMessagePump(
base::MessagePump::Create(base::MessagePumpType::DEFAULT));
- non_main_thread_scheduler_ =
- std::move(scheduler_factory_).Run(scoped_sequence_manager.get());
- non_main_thread_scheduler_->Init();
- default_task_runner_ =
- non_main_thread_scheduler_->DefaultTaskQueue()->CreateTaskRunner(
- TaskType::kWorkerThreadTaskQueueDefault);
+
base::RunLoop run_loop;
run_loop_ = &run_loop;
- is_initialized_.Set();
- // UpdateThreadTLS requires |default_task_runner_| and |is_initialized| set.
Thread::UpdateThreadTLS(thread_);
if (supports_gc_)
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.h
index f2ede1326b2..21e4d074371 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread.h
@@ -8,13 +8,14 @@
#include "base/callback_forward.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/synchronization/atomic_flag.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
#include "third_party/blink/public/platform/web_private_ptr.h"
#include "third_party/blink/renderer/platform/heap/gc_task_runner.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
class BlinkGCMemoryDumpProvider;
@@ -41,7 +42,6 @@ class PLATFORM_EXPORT WorkerThread : public Thread {
// Thread implementation.
void Init() override;
ThreadScheduler* Scheduler() override;
- PlatformThreadId ThreadId() const override;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override;
scheduler::NonMainThreadSchedulerImpl* GetNonMainThreadScheduler() {
@@ -70,17 +70,18 @@ class PLATFORM_EXPORT WorkerThread : public Thread {
std::unique_ptr<scheduler::NonMainThreadSchedulerImpl>(
base::sequence_manager::SequenceManager*)>;
- explicit SimpleThreadImpl(const String& name_prefix,
+ explicit SimpleThreadImpl(const WTF::String& name_prefix,
const base::SimpleThread::Options& options,
- NonMainThreadSchedulerFactory factory,
bool supports_gc,
WorkerThread* worker_thread);
- // Attention: Can only be called after the worker thread has initialized
- // the internal state. The best way to be sure that is the case is to call
- // WaitForInit().
+ // Creates the thread's scheduler. Must be invoked before starting the
+ // thread or accessing the default TaskRunner.
+ void CreateScheduler();
+
+ // Attention: Can only be called after CreateScheduler().
scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() const {
- DCHECK(is_initialized_.IsSet());
+ DCHECK(default_task_runner_);
return default_task_runner_;
}
@@ -95,10 +96,6 @@ class PLATFORM_EXPORT WorkerThread : public Thread {
// WorkerThread::ShutdownOnThread().
void ShutdownOnThread();
- // Blocks until the worker thread is ready to enter the run loop and the
- // default task runner has been initialized.
- void WaitForInit();
-
// Makes sure that Run will eventually finish and thus the thread can be
// joined.
// Can be called from any thread.
@@ -108,7 +105,6 @@ class PLATFORM_EXPORT WorkerThread : public Thread {
private:
void Run() override;
- base::AtomicFlag is_initialized_;
// Internal queue not exposed externally nor to the scheduler used for
// internal operations such as posting the task that will stop the run
// loop.
@@ -117,7 +113,6 @@ class PLATFORM_EXPORT WorkerThread : public Thread {
WorkerThread* thread_;
// The following variables are "owned" by the worker thread
- NonMainThreadSchedulerFactory scheduler_factory_;
std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager_;
scoped_refptr<base::sequence_manager::TaskQueue> internal_task_queue_;
std::unique_ptr<scheduler::NonMainThreadSchedulerImpl>
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
index ae9b778f4b6..d57f9a89568 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
@@ -85,6 +85,13 @@ base::Optional<base::TimeDelta> GetMaxThrottlingDelay() {
return base::TimeDelta::FromMilliseconds(max_throttling_delay_ms);
}
+std::unique_ptr<ukm::MojoUkmRecorder> CreateMojoUkmRecorder() {
+ mojo::PendingRemote<ukm::mojom::UkmRecorderInterface> recorder;
+ Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ recorder.InitWithNewPipeAndPassReceiver());
+ return std::make_unique<ukm::MojoUkmRecorder>(std::move(recorder));
+}
+
} // namespace
WorkerThreadScheduler::WorkerThreadScheduler(
@@ -105,13 +112,6 @@ WorkerThreadScheduler::WorkerThreadScheduler(
initial_frame_status_(proxy ? proxy->initial_frame_status()
: FrameStatus::kNone),
ukm_source_id_(proxy ? proxy->ukm_source_id() : ukm::kInvalidSourceId) {
- if (base::SequencedTaskRunnerHandle::IsSet()) {
- mojo::PendingRemote<ukm::mojom::UkmRecorderInterface> recorder;
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- recorder.InitWithNewPipeAndPassReceiver());
- ukm_recorder_ = std::make_unique<ukm::MojoUkmRecorder>(std::move(recorder));
- }
-
if (proxy && proxy->parent_frame_type())
worker_metrics_helper_.SetParentFrameType(*proxy->parent_frame_type());
@@ -189,7 +189,7 @@ WorkerThreadScheduler::DefaultTaskQueue() {
return helper()->DefaultNonMainThreadTaskQueue();
}
-void WorkerThreadScheduler::InitImpl() {
+void WorkerThreadScheduler::Init() {
initialized_ = true;
idle_helper_.EnableLongIdlePeriod();
@@ -281,6 +281,10 @@ void WorkerThreadScheduler::RecordTaskUkm(
const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
if (!helper()->ShouldRecordTaskUkm(task_timing.has_thread_time()))
return;
+
+ if (!ukm_recorder_)
+ ukm_recorder_ = CreateMojoUkmRecorder();
+
ukm::builders::RendererSchedulerTask builder(ukm_source_id_);
builder.SetVersion(kUkmMetricVersion);
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
index 190f25ffa08..de6debae895 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
@@ -62,6 +62,7 @@ class PLATFORM_EXPORT WorkerThreadScheduler : public NonMainThreadSchedulerImpl,
scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
// NonMainThreadSchedulerImpl implementation:
+ void Init() override;
scoped_refptr<NonMainThreadTaskQueue> DefaultTaskQueue() override;
void OnTaskCompleted(
NonMainThreadTaskQueue* worker_task_queue,
@@ -99,9 +100,6 @@ class PLATFORM_EXPORT WorkerThreadScheduler : public NonMainThreadSchedulerImpl,
}
protected:
- // NonMainThreadScheduler implementation:
- void InitImpl() override;
-
// IdleHelper::Delegate implementation:
bool CanEnterLongIdlePeriod(
base::TimeTicks now,
@@ -132,7 +130,7 @@ class PLATFORM_EXPORT WorkerThreadScheduler : public NonMainThreadSchedulerImpl,
const ThreadType thread_type_;
IdleHelper idle_helper_;
- bool initialized_;
+ bool initialized_ = false;
scoped_refptr<NonMainThreadTaskQueue> control_task_queue_;
scoped_refptr<base::SingleThreadTaskRunner> v8_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
index 3b941bd4c72..2f9f37b427a 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
@@ -152,6 +152,7 @@ class WorkerThreadSchedulerTest : public testing::Test {
task_environment_.GetMockTickClock(),
&timeline_)) {
scheduler_->Init();
+ scheduler_->AttachToCurrentThread();
default_task_queue_ = scheduler_->CreateTaskQueue("test_tq");
default_task_runner_ = default_task_queue_->CreateTaskRunner(0);
idle_task_runner_ = scheduler_->IdleTaskRunner();
@@ -505,6 +506,7 @@ class WorkerThreadSchedulerWithProxyTest : public testing::Test {
task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
scheduler_->Init();
+ scheduler_->AttachToCurrentThread();
}
~WorkerThreadSchedulerWithProxyTest() override = default;
diff --git a/chromium/third_party/blink/renderer/platform/supplementable.h b/chromium/third_party/blink/renderer/platform/supplementable.h
index 7c309d32fd7..1ff7c9962ae 100644
--- a/chromium/third_party/blink/renderer/platform/supplementable.h
+++ b/chromium/third_party/blink/renderer/platform/supplementable.h
@@ -77,7 +77,7 @@ namespace blink {
// public:
// static const char kSupplementName[];
//
-// NavigatorFoo& From(Navigator&);
+// static NavigatorFoo& From(Navigator&);
// }
//
// // static
diff --git a/chromium/third_party/blink/renderer/platform/testing/DEPS b/chromium/third_party/blink/renderer/platform/testing/DEPS
index 84b32220cbb..70871e2fb77 100644
--- a/chromium/third_party/blink/renderer/platform/testing/DEPS
+++ b/chromium/third_party/blink/renderer/platform/testing/DEPS
@@ -35,6 +35,7 @@ include_rules = [
"+third_party/blink/renderer/platform/instrumentation/histogram.h",
"+third_party/blink/renderer/platform/language.h",
"+third_party/blink/renderer/platform/loader",
+ "+third_party/blink/renderer/platform/mojo/mojo_binding_context.h",
"+third_party/blink/renderer/platform/network",
"+third_party/blink/renderer/platform/peerconnection",
"+third_party/blink/renderer/platform/platform_export.h",
@@ -61,6 +62,7 @@ specific_include_rules = {
],
"video_frame_utils\.cc": [
"+media/video/fake_gpu_memory_buffer.h",
+ "+media/base/format_utils.h",
],
"video_frame_utils\.h": [
"+media/base/video_frame.h",
diff --git a/chromium/third_party/blink/renderer/platform/testing/data/colrv0_test.ttf b/chromium/third_party/blink/renderer/platform/testing/data/colrv0_test.ttf
new file mode 100644
index 00000000000..ee970563177
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/testing/data/colrv0_test.ttf
Binary files differ
diff --git a/chromium/third_party/blink/renderer/platform/testing/data/colrv1_test.ttf b/chromium/third_party/blink/renderer/platform/testing/data/colrv1_test.ttf
new file mode 100644
index 00000000000..693bd1c3620
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/testing/data/colrv1_test.ttf
Binary files differ
diff --git a/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.cc b/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
index 6b943b268a6..a0373a93497 100644
--- a/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
@@ -10,8 +10,11 @@
namespace blink {
-WebMediaPlayer::LoadTiming
-EmptyWebMediaPlayer::Load(LoadType, const WebMediaPlayerSource&, CorsMode) {
+WebMediaPlayer::LoadTiming EmptyWebMediaPlayer::Load(
+ LoadType,
+ const WebMediaPlayerSource&,
+ CorsMode,
+ bool is_cache_disabled) {
return LoadTiming::kImmediate;
}
diff --git a/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.h
index 90d8b3e4498..848d324ae71 100644
--- a/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.h
+++ b/chromium/third_party/blink/renderer/platform/testing/empty_web_media_player.h
@@ -22,7 +22,10 @@ class EmptyWebMediaPlayer : public WebMediaPlayer {
public:
~EmptyWebMediaPlayer() override = default;
- LoadTiming Load(LoadType, const WebMediaPlayerSource&, CorsMode) override;
+ LoadTiming Load(LoadType,
+ const WebMediaPlayerSource&,
+ CorsMode,
+ bool is_cache_disabled) override;
void Play() override {}
void Pause() override {}
void Seek(double seconds) override {}
@@ -30,15 +33,17 @@ class EmptyWebMediaPlayer : public WebMediaPlayer {
void SetVolume(double) override {}
void SetLatencyHint(double) override {}
void SetPreservesPitch(bool) override {}
+ void SetAutoplayInitiated(bool) override {}
void OnRequestPictureInPicture() override {}
- void OnPictureInPictureAvailabilityChanged(bool available) override {}
SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
return SurfaceLayerMode::kNever;
}
WebTimeRanges Buffered() const override;
WebTimeRanges Seekable() const override;
- void SetSinkId(const WebString& sink_id,
- WebSetSinkIdCompleteCallback) override {}
+ bool SetSinkId(const WebString& sink_id,
+ WebSetSinkIdCompleteCallback) override {
+ return false;
+ }
bool HasVideo() const override { return false; }
bool HasAudio() const override { return false; }
gfx::Size NaturalSize() const override;
@@ -60,11 +65,7 @@ class EmptyWebMediaPlayer : public WebMediaPlayer {
unsigned DroppedFrameCount() const override { return 0; }
uint64_t AudioDecodedByteCount() const override { return 0; }
uint64_t VideoDecodedByteCount() const override { return 0; }
- void Paint(cc::PaintCanvas*,
- const WebRect&,
- cc::PaintFlags&,
- int already_uploaded_id,
- VideoFrameUploadMetadata*) override {}
+ void Paint(cc::PaintCanvas*, const gfx::Rect&, cc::PaintFlags&) override {}
scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
bool HasAvailableVideoFrame() const override { return false; }
base::WeakPtr<WebMediaPlayer> AsWeakPtr() override { return nullptr; }
diff --git a/chromium/third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h b/chromium/third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h
index 38ce668a97e..f58ad1b87c1 100644
--- a/chromium/third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h
+++ b/chromium/third_party/blink/renderer/platform/testing/fake_graphics_layer_client.h
@@ -18,6 +18,9 @@ class FakeGraphicsLayerClient : public GraphicsLayerClient {
const IntRect&) const override {
return IntRect();
}
+ IntRect PaintableRegion(const GraphicsLayer*) const override {
+ return IntRect();
+ }
String DebugName(const GraphicsLayer*) const override { return String(); }
bool IsTrackingRasterInvalidations() const override {
return is_tracking_raster_invalidations_;
diff --git a/chromium/third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h b/chromium/third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h
index 9328ff3d0b4..77694f34e54 100644
--- a/chromium/third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h
+++ b/chromium/third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h
@@ -7,38 +7,34 @@
#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/platform/heap_observer_set.h"
namespace blink {
class MockContextLifecycleNotifier final
: public GarbageCollected<MockContextLifecycleNotifier>,
public ContextLifecycleNotifier {
+ USING_PRE_FINALIZER(MockContextLifecycleNotifier, Dispose);
+
public:
MockContextLifecycleNotifier() = default;
- void AddContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.AddObserver(observer);
- }
- void RemoveContextLifecycleObserver(
- ContextLifecycleObserver* observer) override {
- observers_.RemoveObserver(observer);
+ void Dispose() {
+ if (!notified_destruction_) {
+ NotifyContextDestroyed();
+ }
}
void NotifyContextDestroyed() {
- observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
- observer->ContextDestroyed();
- });
+ ContextLifecycleNotifier::NotifyContextDestroyed();
+ notified_destruction_ = true;
}
void Trace(Visitor* visitor) const override {
- visitor->Trace(observers_);
ContextLifecycleNotifier::Trace(visitor);
}
private:
- HeapObserverSet<ContextLifecycleObserver> observers_;
+ bool notified_destruction_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h b/chromium/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
index ac01958869c..e1cebcfd2a1 100644
--- a/chromium/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
+++ b/chromium/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
+#include "third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
@@ -23,6 +24,9 @@ inline const ClipPaintPropertyNode& c0() {
inline const EffectPaintPropertyNode& e0() {
return EffectPaintPropertyNode::Root();
}
+inline const ScrollPaintPropertyNode& s0() {
+ return ScrollPaintPropertyNode::Root();
+}
constexpr int c0_id = 1;
constexpr int e0_id = 1;
@@ -217,6 +221,28 @@ inline scoped_refptr<TransformPaintPropertyNode> CreateScrollTranslation(
return TransformPaintPropertyNode::Create(parent, std::move(state));
}
+inline scoped_refptr<TransformPaintPropertyNode> CreateScrollTranslation(
+ const TransformPaintPropertyNodeOrAlias& parent,
+ float offset_x,
+ float offset_y,
+ const IntRect& container_rect,
+ const IntSize& contents_size,
+ CompositingReasons compositing_reasons = CompositingReason::kNone) {
+ const auto* parent_scroll_translation = &parent.Unalias();
+ while (!parent_scroll_translation->ScrollNode())
+ parent_scroll_translation = parent_scroll_translation->UnaliasedParent();
+ ScrollPaintPropertyNode::State scroll_state;
+ scroll_state.container_rect = container_rect;
+ scroll_state.contents_size = contents_size;
+ TransformPaintPropertyNode::State translation_state{
+ FloatSize(offset_x, offset_y)};
+ translation_state.direct_compositing_reasons = compositing_reasons;
+ translation_state.scroll = ScrollPaintPropertyNode::Create(
+ *parent_scroll_translation->ScrollNode(), std::move(scroll_state));
+ return TransformPaintPropertyNode::Create(parent,
+ std::move(translation_state));
+}
+
inline scoped_refptr<TransformPaintPropertyNode>
CreateCompositedScrollTranslation(
const TransformPaintPropertyNodeOrAlias& parent,
@@ -227,6 +253,46 @@ CreateCompositedScrollTranslation(
CompositingReason::kOverflowScrolling);
}
+inline scoped_refptr<TransformPaintPropertyNode>
+CreateCompositedScrollTranslation(
+ const TransformPaintPropertyNodeOrAlias& parent,
+ float offset_x,
+ float offset_y,
+ const IntRect& container_rect,
+ const IntSize& contents_size) {
+ return CreateScrollTranslation(parent, offset_x, offset_y, container_rect,
+ contents_size,
+ CompositingReason::kOverflowScrolling);
+}
+
+inline RefCountedPropertyTreeState CreateScrollTranslationState(
+ const PropertyTreeState& parent_state,
+ float offset_x,
+ float offset_y,
+ const IntRect& container_rect,
+ const IntSize& contents_size,
+ CompositingReasons compositing_reasons = CompositingReason::kNone) {
+ return RefCountedPropertyTreeState(PropertyTreeState(
+ *CreateScrollTranslation(parent_state.Transform(), offset_x, offset_y,
+ container_rect, contents_size,
+ compositing_reasons),
+ *CreateClip(parent_state.Clip(), parent_state.Transform(),
+ FloatRoundedRect(container_rect)),
+ e0()));
+}
+
+inline RefCountedPropertyTreeState CreateCompositedScrollTranslationState(
+ const PropertyTreeState& parent_state,
+ float offset_x,
+ float offset_y,
+ const IntRect& container_rect,
+ const IntSize& contents_size,
+ CompositingReasons compositing_reasons = CompositingReason::kNone) {
+ return CreateScrollTranslationState(parent_state, offset_x, offset_y,
+ container_rect, contents_size,
+ CompositingReason::kOverflowScrolling);
+}
+
inline PropertyTreeState DefaultPaintChunkProperties() {
return PropertyTreeState::Root();
}
diff --git a/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h b/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
index f5b9d63ee7b..5bc3af7502c 100644
--- a/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
+++ b/chromium/third_party/blink/renderer/platform/testing/paint_test_configurations.h
@@ -11,15 +11,21 @@
namespace blink {
-enum { kCompositeAfterPaint = 1 << 0, kUnderInvalidationChecking = 1 << 1 };
+enum {
+ kCullRectUpdate = 1 << 0,
+ kCompositeAfterPaint = 1 << 1,
+ kUnderInvalidationChecking = 1 << 2
+};
class PaintTestConfigurations
: public testing::WithParamInterface<unsigned>,
+ private ScopedCullRectUpdateForTest,
private ScopedCompositeAfterPaintForTest,
private ScopedPaintUnderInvalidationCheckingForTest {
public:
PaintTestConfigurations()
- : ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
+ : ScopedCullRectUpdateForTest(GetParam() & kCullRectUpdate),
+ ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
ScopedPaintUnderInvalidationCheckingForTest(
GetParam() & kUnderInvalidationChecking) {}
~PaintTestConfigurations() {
@@ -29,8 +35,13 @@ class PaintTestConfigurations
};
#define INSTANTIATE_PAINT_TEST_SUITE_P(test_class) \
- INSTANTIATE_TEST_SUITE_P(All, test_class, \
- ::testing::Values(0, kCompositeAfterPaint))
+ INSTANTIATE_TEST_SUITE_P( \
+ All, test_class, \
+ ::testing::Values(0, kCullRectUpdate, kCompositeAfterPaint))
+
+#define INSTANTIATE_PRE_CAP_TEST_SUITE_P(test_class) \
+ INSTANTIATE_TEST_SUITE_P(All, test_class, \
+ ::testing::Values(0, kCullRectUpdate))
#define INSTANTIATE_CAP_TEST_SUITE_P(test_class) \
INSTANTIATE_TEST_SUITE_P(All, test_class, \
diff --git a/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.cc b/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
index fa56cfea162..998abad19e4 100644
--- a/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
@@ -59,8 +59,9 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(const IntRect& bounds,
}
TestPaintArtifact& TestPaintArtifact::ScrollHitTest(
+ const IntRect& rect,
const TransformPaintPropertyNode* scroll_translation) {
- return ScrollHitTest(NewClient(), scroll_translation);
+ return ScrollHitTest(NewClient(), rect, scroll_translation);
}
TestPaintArtifact& TestPaintArtifact::ForeignLayer(
@@ -94,9 +95,12 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client,
TestPaintArtifact& TestPaintArtifact::ScrollHitTest(
DisplayItemClient& client,
+ const IntRect& rect,
const TransformPaintPropertyNode* scroll_translation) {
- paint_artifact_->PaintChunks().back().EnsureHitTestData().scroll_translation =
- scroll_translation;
+ auto& hit_test_data =
+ paint_artifact_->PaintChunks().back().EnsureHitTestData();
+ hit_test_data.scroll_hit_test_rect = rect;
+ hit_test_data.scroll_translation = scroll_translation;
return *this;
}
diff --git a/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.h b/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.h
index ce0b03f088e..4c9044ca2fc 100644
--- a/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.h
+++ b/chromium/third_party/blink/renderer/platform/testing/test_paint_artifact.h
@@ -94,6 +94,7 @@ class TestPaintArtifact {
// automatically created client.
TestPaintArtifact& RectDrawing(const IntRect& bounds, Color color);
TestPaintArtifact& ScrollHitTest(
+ const IntRect&,
const TransformPaintPropertyNode* scroll_translation);
TestPaintArtifact& ForeignLayer(scoped_refptr<cc::Layer> layer,
@@ -105,6 +106,7 @@ class TestPaintArtifact {
Color color);
TestPaintArtifact& ScrollHitTest(
DisplayItemClient&,
+ const IntRect&,
const TransformPaintPropertyNode* scroll_translation);
// Sets fake bounds for the last paint chunk. Note that the bounds will be
diff --git a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support.cc b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support.cc
index 71a457c4f32..57508ee9e10 100644
--- a/chromium/third_party/blink/renderer/platform/testing/testing_platform_support.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/testing_platform_support.cc
@@ -43,6 +43,7 @@
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
@@ -124,7 +125,7 @@ TestingPlatformSupport::GetBrowserInterfaceBroker() {
}
void TestingPlatformSupport::RunUntilIdle() {
- ThreadState::HeapPointersOnStackScope scan_stack(ThreadState::Current());
+ HeapPointersOnStackScope scan_stack(ThreadState::Current());
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/third_party/blink/renderer/platform/testing/unit_test_helpers.cc b/chromium/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
index 89d874901d9..156a07b6d00 100644
--- a/chromium/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -66,7 +67,7 @@ void RunPendingTasks() {
// The following runloop can execute non-nested tasks with heap pointers
// living on stack, so we force both Oilpan and Unified GC to visit the stack.
- ThreadState::HeapPointersOnStackScope scan_stack(ThreadState::Current());
+ HeapPointersOnStackScope scan_stack(ThreadState::Current());
EnterRunLoop();
}
diff --git a/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.cc b/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.cc
index 6f8306d0dcd..3edc25506e0 100644
--- a/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/platform/testing/video_frame_utils.h"
#include "base/callback_helpers.h"
+#include "media/base/format_utils.h"
#include "media/video/fake_gpu_memory_buffer.h"
namespace blink {
@@ -14,28 +15,59 @@ scoped_refptr<media::VideoFrame> CreateTestFrame(
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
media::VideoFrame::StorageType storage_type) {
- scoped_refptr<media::VideoFrame> frame;
+ return CreateTestFrame(coded_size, visible_rect, natural_size, storage_type,
+ storage_type == media::VideoFrame::STORAGE_OWNED_MEMORY
+ ? media::PIXEL_FORMAT_I420
+ : media::PIXEL_FORMAT_NV12);
+}
+
+scoped_refptr<media::VideoFrame> CreateTestFrame(
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ media::VideoFrame::StorageType storage_type,
+ media::VideoPixelFormat pixel_format) {
switch (storage_type) {
case media::VideoFrame::STORAGE_OWNED_MEMORY:
- frame = media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_I420,
- coded_size, visible_rect,
- natural_size, base::TimeDelta());
- break;
-
+ return media::VideoFrame::CreateZeroInitializedFrame(
+ pixel_format, coded_size, visible_rect, natural_size,
+ base::TimeDelta());
case media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER: {
+ base::Optional<gfx::BufferFormat> buffer_format =
+ media::VideoPixelFormatToGfxBufferFormat(pixel_format);
+ CHECK(buffer_format) << "Pixel format "
+ << media::VideoPixelFormatToString(pixel_format)
+ << " has no corresponding gfx::BufferFormat";
auto gmb = std::make_unique<media::FakeGpuMemoryBuffer>(
- coded_size, gfx::BufferFormat::YUV_420_BIPLANAR);
+ coded_size, buffer_format.value());
const gpu::MailboxHolder empty_mailboxes[media::VideoFrame::kMaxPlanes];
- frame = media::VideoFrame::WrapExternalGpuMemoryBuffer(
+ return media::VideoFrame::WrapExternalGpuMemoryBuffer(
visible_rect, natural_size, std::move(gmb), empty_mailboxes,
base::NullCallback(), base::TimeDelta());
- break;
}
+ case media::VideoFrame::STORAGE_OPAQUE: {
+ base::Optional<gfx::BufferFormat> buffer_format =
+ media::VideoPixelFormatToGfxBufferFormat(pixel_format);
+ CHECK(buffer_format) << "Pixel format "
+ << media::VideoPixelFormatToString(pixel_format)
+ << " has no corresponding gfx::BufferFormat";
+ auto gmb = std::make_unique<media::FakeGpuMemoryBuffer>(
+ coded_size, buffer_format.value());
+ gpu::MailboxHolder mailboxes[media::VideoFrame::kMaxPlanes];
+ // Set mailbox names so this registers as a texture.
+ mailboxes[0].mailbox = gpu::Mailbox::GenerateForSharedImage();
+ for (size_t i = 0; i < media::VideoFrame::NumPlanes(pixel_format); ++i) {
+ mailboxes[i].mailbox.name[0] = 1;
+ }
+ return media::VideoFrame::WrapNativeTextures(
+ pixel_format, mailboxes, base::NullCallback(), coded_size,
+ visible_rect, natural_size, base::TimeDelta());
+ }
default:
- NOTREACHED() << "Unexpected storage type";
+ NOTREACHED() << "Unsupported storage type or pixel format";
}
- return frame;
+ return nullptr;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.h b/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.h
index 9052e73e48f..f2374b8f7db 100644
--- a/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.h
+++ b/chromium/third_party/blink/renderer/platform/testing/video_frame_utils.h
@@ -15,6 +15,13 @@ scoped_refptr<media::VideoFrame> CreateTestFrame(
const gfx::Size& natural_size,
media::VideoFrame::StorageType storage_type);
+scoped_refptr<media::VideoFrame> CreateTestFrame(
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ media::VideoFrame::StorageType storage_type,
+ media::VideoPixelFormat pixel_format);
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_VIDEO_FRAME_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc b/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
index b9fbc7db02d..17cd34e2a83 100644
--- a/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
+++ b/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.cc
@@ -24,26 +24,21 @@ namespace blink {
namespace {
-template <typename CharType>
-StringView SkipLeadingSpaces(const CharType* text,
- unsigned length,
- unsigned* num_leading_spaces_out) {
- const CharType* begin = text;
- const CharType* end = text + length;
- while (text != end && Character::TreatAsSpace(*text))
- text++;
- *num_leading_spaces_out = text - begin;
- return StringView(text, static_cast<unsigned>(end - text));
+inline bool ShouldSkipLeadingChar(UChar32 c) {
+ if (Character::TreatAsSpace(c))
+ return true;
+ // Strip leading punctuation, defined as OP and QU line breaking classes,
+ // see UAX #14.
+ const int32_t lb = u_getIntPropertyValue(c, UCHAR_LINE_BREAK);
+ if (lb == U_LB_OPEN_PUNCTUATION || lb == U_LB_QUOTATION)
+ return true;
+ return false;
}
-StringView SkipLeadingSpaces(const StringView& text,
- unsigned* num_leading_spaces_out) {
- if (text.Is8Bit()) {
- return SkipLeadingSpaces(text.Characters8(), text.length(),
- num_leading_spaces_out);
- }
- return SkipLeadingSpaces(text.Characters16(), text.length(),
- num_leading_spaces_out);
+inline bool ShouldSkipTrailingChar(UChar32 c) {
+ // Strip trailing spaces, punctuation and control characters.
+ const int32_t gc_mask = U_GET_GC_MASK(c);
+ return gc_mask & (U_GC_ZS_MASK | U_GC_P_MASK | U_GC_CC_MASK);
}
} // namespace
@@ -86,6 +81,44 @@ bool HyphenationMinikin::OpenDictionary(base::File file) {
return true;
}
+StringView HyphenationMinikin::WordToHyphenate(
+ const StringView& text,
+ unsigned* num_leading_chars_out) {
+ if (text.Is8Bit()) {
+ const LChar* begin = text.Characters8();
+ const LChar* end = begin + text.length();
+ while (begin != end && ShouldSkipLeadingChar(*begin))
+ ++begin;
+ while (begin != end && ShouldSkipTrailingChar(end[-1]))
+ --end;
+ *num_leading_chars_out = begin - text.Characters8();
+ CHECK_GE(end, begin);
+ return StringView(begin, end - begin);
+ }
+ const UChar* begin = text.Characters16();
+ int index = 0;
+ int len = text.length();
+ while (index < len) {
+ int next_index = index;
+ UChar32 c;
+ U16_NEXT(begin, next_index, len, c);
+ if (!ShouldSkipLeadingChar(c))
+ break;
+ index = next_index;
+ }
+ while (index < len) {
+ int prev_len = len;
+ UChar32 c;
+ U16_PREV(begin, index, prev_len, c);
+ if (!ShouldSkipTrailingChar(c))
+ break;
+ len = prev_len;
+ }
+ *num_leading_chars_out = index;
+ CHECK_GE(len, index);
+ return StringView(begin + index, len - index);
+}
+
Vector<uint8_t> HyphenationMinikin::Hyphenate(const StringView& text) const {
Vector<uint8_t> result;
if (text.Is8Bit()) {
@@ -105,11 +138,11 @@ Vector<uint8_t> HyphenationMinikin::Hyphenate(const StringView& text) const {
wtf_size_t HyphenationMinikin::LastHyphenLocation(
const StringView& text,
wtf_size_t before_index) const {
- unsigned num_leading_spaces;
- StringView word = SkipLeadingSpaces(text, &num_leading_spaces);
- if (before_index <= num_leading_spaces)
+ unsigned num_leading_chars;
+ StringView word = WordToHyphenate(text, &num_leading_chars);
+ if (before_index <= num_leading_chars)
return 0;
- before_index = std::min<wtf_size_t>(before_index - num_leading_spaces,
+ before_index = std::min<wtf_size_t>(before_index - num_leading_chars,
word.length() - kMinimumSuffixLength);
if (word.length() < kMinimumPrefixLength + kMinimumSuffixLength ||
@@ -122,15 +155,15 @@ wtf_size_t HyphenationMinikin::LastHyphenLocation(
static_assert(kMinimumPrefixLength >= 1, "|beforeIndex - 1| can underflow");
for (wtf_size_t i = before_index - 1; i >= kMinimumPrefixLength; i--) {
if (result[i])
- return i + num_leading_spaces;
+ return i + num_leading_chars;
}
return 0;
}
Vector<wtf_size_t, 8> HyphenationMinikin::HyphenLocations(
const StringView& text) const {
- unsigned num_leading_spaces;
- StringView word = SkipLeadingSpaces(text, &num_leading_spaces);
+ unsigned num_leading_chars;
+ StringView word = WordToHyphenate(text, &num_leading_chars);
Vector<wtf_size_t, 8> hyphen_locations;
if (word.length() < kMinimumPrefixLength + kMinimumSuffixLength)
@@ -142,7 +175,7 @@ Vector<wtf_size_t, 8> HyphenationMinikin::HyphenLocations(
for (wtf_size_t i = word.length() - kMinimumSuffixLength - 1;
i >= kMinimumPrefixLength; i--) {
if (result[i])
- hyphen_locations.push_back(i + num_leading_spaces);
+ hyphen_locations.push_back(i + num_leading_chars);
}
return hyphen_locations;
}
diff --git a/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.h b/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.h
index e3c39c14958..4f7bfcfe3b3 100644
--- a/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.h
+++ b/chromium/third_party/blink/renderer/platform/text/hyphenation/hyphenation_minikin.h
@@ -28,6 +28,11 @@ class PLATFORM_EXPORT HyphenationMinikin final : public Hyphenation {
wtf_size_t before_index) const override;
Vector<wtf_size_t, 8> HyphenLocations(const StringView&) const override;
+ // Extract the word to hyphenate by skipping leading and trailing spaces and
+ // punctuations.
+ static StringView WordToHyphenate(const StringView& text,
+ unsigned* num_leading_chars_out);
+
static AtomicString MapLocale(const AtomicString& locale);
static scoped_refptr<HyphenationMinikin> FromFileForTesting(base::File);
diff --git a/chromium/third_party/blink/renderer/platform/text/hyphenation_test.cc b/chromium/third_party/blink/renderer/platform/text/hyphenation_test.cc
index 1b608fa475a..3905814bc3a 100644
--- a/chromium/third_party/blink/renderer/platform/text/hyphenation_test.cc
+++ b/chromium/third_party/blink/renderer/platform/text/hyphenation_test.cc
@@ -61,6 +61,33 @@ class HyphenationTest : public testing::Test {
return nullptr;
}
#endif
+
+#if defined(USE_MINIKIN_HYPHENATION)
+ void TestWordToHyphenate(StringView text,
+ StringView expected,
+ unsigned expected_num_leading_chars) {
+ unsigned num_leading_chars;
+ const StringView result =
+ HyphenationMinikin::WordToHyphenate(text, &num_leading_chars);
+ EXPECT_EQ(result, expected);
+ EXPECT_EQ(num_leading_chars, expected_num_leading_chars);
+
+ // |WordToHyphenate| has separate codepaths for 8 and 16 bits. Make sure
+ // both codepaths return the same results. When a paragraph has at least one
+ // 16 bits character (e.g., Emoji), there will be 8 bits words in 16 bits
+ // string.
+ if (!text.Is8Bit()) {
+ // If |text| is 16 bits, 16 bits codepath is already tested.
+ return;
+ }
+ String text16 = text.ToString();
+ text16.Ensure16Bit();
+ const StringView result16 =
+ HyphenationMinikin::WordToHyphenate(text16, &num_leading_chars);
+ EXPECT_EQ(result16, expected);
+ EXPECT_EQ(num_leading_chars, expected_num_leading_chars);
+ }
+#endif
};
TEST_F(HyphenationTest, Get) {
@@ -141,6 +168,18 @@ TEST_F(HyphenationTest, HyphenLocations) {
EXPECT_THAT(actual, ElementsAreArray(locations));
}
+#if defined(USE_MINIKIN_HYPHENATION)
+TEST_F(HyphenationTest, WordToHyphenate) {
+ TestWordToHyphenate("word", "word", 0);
+ TestWordToHyphenate(" word", "word", 1);
+ TestWordToHyphenate(" word", "word", 2);
+ TestWordToHyphenate(" word..", "word", 2);
+ TestWordToHyphenate(" ( word. ).", "word", 3);
+ TestWordToHyphenate(u" ( \u3042. ).", u"\u3042", 3);
+ TestWordToHyphenate(u" ( \U00020B9F. ).", u"\U00020B9F", 3);
+}
+#endif
+
TEST_F(HyphenationTest, LeadingSpaces) {
scoped_refptr<Hyphenation> hyphenation = GetHyphenation("en-us");
#if defined(OS_ANDROID)
@@ -163,12 +202,6 @@ TEST_F(HyphenationTest, LeadingSpaces) {
String only_spaces(" ");
EXPECT_THAT(hyphenation->HyphenLocations(only_spaces), ElementsAre());
EXPECT_EQ(0u, hyphenation->LastHyphenLocation(only_spaces, 3));
-
- // Line breaker is not supposed to pass with trailing spaces.
- String trailing_space("principle ");
- EXPECT_THAT(hyphenation->HyphenLocations(trailing_space),
- testing::AnyOf(ElementsAre(), ElementsAre(6, 4)));
- EXPECT_EQ(0u, hyphenation->LastHyphenLocation(trailing_space, 10));
}
TEST_F(HyphenationTest, English) {
diff --git a/chromium/third_party/blink/renderer/platform/text/locale_to_script_mapping.cc b/chromium/third_party/blink/renderer/platform/text/locale_to_script_mapping.cc
index b940c8fd54d..289f26c34c8 100644
--- a/chromium/third_party/blink/renderer/platform/text/locale_to_script_mapping.cc
+++ b/chromium/third_party/blink/renderer/platform/text/locale_to_script_mapping.cc
@@ -155,7 +155,7 @@ UScriptCode ScriptNameToCode(const String& script_name) {
{"zxxx", USCRIPT_UNWRITTEN_LANGUAGES},
{"zzzz", USCRIPT_UNKNOWN}};
for (const auto& kv : kScriptNameCodeList) {
- if (CodeUnitCompareIgnoringASCIICase(script_name, kv.subtag) == 0)
+ if (EqualIgnoringASCIICase(script_name, kv.subtag))
return kv.script;
}
return USCRIPT_INVALID_CODE;
@@ -447,7 +447,7 @@ UScriptCode LocaleToScriptCodeForFontSelection(const String& locale) {
while (!canonical_locale.IsEmpty()) {
for (const auto& kv : kLocaleScriptList) {
- if (CodeUnitCompareIgnoringASCIICase(canonical_locale, kv.subtag) == 0)
+ if (EqualIgnoringASCIICase(canonical_locale, kv.subtag))
return kv.script;
}
@@ -472,7 +472,7 @@ static UScriptCode ScriptCodeForHanFromRegion(const String& region) {
{"tw", USCRIPT_TRADITIONAL_HAN},
};
for (const auto& kv : kRegionScriptList) {
- if (CodeUnitCompareIgnoringASCIICase(region, kv.subtag) == 0)
+ if (EqualIgnoringASCIICase(region, kv.subtag))
return kv.script;
}
return USCRIPT_COMMON;
diff --git a/chromium/third_party/blink/renderer/platform/text/platform_locale.cc b/chromium/third_party/blink/renderer/platform/text/platform_locale.cc
index 13270d659a8..01140e220a9 100644
--- a/chromium/third_party/blink/renderer/platform/text/platform_locale.cc
+++ b/chromium/third_party/blink/renderer/platform/text/platform_locale.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/platform/text/date_time_format.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -495,17 +496,21 @@ bool Locale::IsSignPrefix(UChar ch) {
}
bool Locale::HasTwoSignChars(const String& str) {
- auto pos =
- str.Find(WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Passed(this)));
+ // Unretained is safe because callback executes synchronously in Find().
+ auto pos = str.Find(
+ WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Unretained(this)));
if (pos == kNotFound)
return false;
- return str.Find(WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Passed(this)),
- pos + 1) != kNotFound;
+ // Unretained is safe because callback executes synchronously in Find().
+ return str.Find(
+ WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Unretained(this)),
+ pos + 1) != kNotFound;
}
bool Locale::HasSignNotAfterE(const String& str) {
- auto pos =
- str.Find(WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Passed(this)));
+ // Unretained is safe because callback executes synchronously in Find().
+ auto pos = str.Find(
+ WTF::BindRepeating(&Locale::IsSignPrefix, WTF::Unretained(this)));
if (pos == kNotFound)
return false;
return pos == 0 || !IsE(str[pos - 1]);
@@ -533,8 +538,9 @@ bool Locale::IsDecimalSeparator(UChar ch) {
// Is there a decimal separator in a string?
bool Locale::HasDecimalSeparator(const String& str) {
+ // Unretained is safe because callback executes synchronously in Find().
return str.Find(WTF::BindRepeating(&Locale::IsDecimalSeparator,
- WTF::Passed(this))) != kNotFound;
+ WTF::Unretained(this))) != kNotFound;
}
String Locale::FormatDateTime(const DateComponents& date,
diff --git a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
index d791ae7210b..4cca10b64d5 100644
--- a/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
+++ b/chromium/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -340,10 +340,11 @@ inline int LazyLineBreakIterator::NextBreakablePosition(
return i;
break;
case BreakSpaceType::kAfterEverySpace:
- if (is_last_space)
+ if (is_last_space || IsOtherSpaceSeparator<CharacterType>(last_ch))
return i;
- if (is_space)
- continue;
+ if ((is_space || IsOtherSpaceSeparator<CharacterType>(ch)) &&
+ i + 1 < len)
+ return i + 1;
break;
}
diff --git a/chromium/third_party/blink/renderer/platform/timer.cc b/chromium/third_party/blink/renderer/platform/timer.cc
index a4ece579d68..2e9a8cbf080 100644
--- a/chromium/third_party/blink/renderer/platform/timer.cc
+++ b/chromium/third_party/blink/renderer/platform/timer.cc
@@ -117,17 +117,12 @@ void TimerBase::SetNextFireTime(base::TimeTicks now, base::TimeDelta delay) {
weak_ptr_factory_.InvalidateWeakPtrs();
web_task_runner_->PostDelayedTask(
- location_,
- WTF::Bind(&TimerBase::RunInternal, weak_ptr_factory_.GetWeakPtr()),
- delay);
+ location_, BindTimerClosure(weak_ptr_factory_.GetWeakPtr()), delay);
}
}
NO_SANITIZE_ADDRESS
void TimerBase::RunInternal() {
- if (!CanFire())
- return;
-
weak_ptr_factory_.InvalidateWeakPtrs();
TRACE_EVENT0("blink", "TimerBase::run");
diff --git a/chromium/third_party/blink/renderer/platform/timer.h b/chromium/third_party/blink/renderer/platform/timer.h
index fd81a09959c..e2a9e5cadfa 100644
--- a/chromium/third_party/blink/renderer/platform/timer.h
+++ b/chromium/third_party/blink/renderer/platform/timer.h
@@ -82,18 +82,21 @@ class PLATFORM_EXPORT TimerBase {
bool operator()(const TimerBase* a, const TimerBase* b) const;
};
- private:
+ protected:
virtual void Fired() = 0;
- NO_SANITIZE_ADDRESS
- virtual bool CanFire() const { return true; }
+ virtual base::OnceClosure BindTimerClosure(
+ base::WeakPtr<TimerBase> weak_ptr) {
+ return WTF::Bind(&TimerBase::RunInternal, std::move(weak_ptr));
+ }
+
+ void RunInternal();
+ private:
base::TimeTicks TimerCurrentTimeTicks() const;
void SetNextFireTime(base::TimeTicks now, base::TimeDelta delay);
- void RunInternal();
-
base::TimeTicks next_fire_time_; // 0 if inactive
base::TimeDelta repeat_interval_; // 0 if not repeating
base::Location location_;
@@ -102,63 +105,83 @@ class PLATFORM_EXPORT TimerBase {
#if DCHECK_IS_ON()
base::PlatformThreadId thread_;
#endif
+ // Used for invalidating tasks at arbitrary times and after the timer has been
+ // destructed.
base::WeakPtrFactory<TimerBase> weak_ptr_factory_{this};
- friend class ThreadTimers;
- friend class TimerHeapLessThanFunction;
- friend class TimerHeapReference;
-
DISALLOW_COPY_AND_ASSIGN(TimerBase);
};
-template <typename TimerFiredClass,
- bool = WTF::IsGarbageCollectedTypeInternal<TimerFiredClass>::value>
-class TaskRunnerTimer;
-
template <typename TimerFiredClass>
-class TaskRunnerTimer<TimerFiredClass, false> : public TimerBase {
+class TaskRunnerTimer : public TimerBase {
public:
using TimerFiredFunction = void (TimerFiredClass::*)(TimerBase*);
TaskRunnerTimer(scoped_refptr<base::SingleThreadTaskRunner> web_task_runner,
TimerFiredClass* o,
TimerFiredFunction f)
- : TimerBase(std::move(web_task_runner)), object_(o), function_(f) {}
+ : TimerBase(std::move(web_task_runner)), object_(o), function_(f) {
+ static_assert(!WTF::IsGarbageCollectedType<TimerFiredClass>::value,
+ "Use HeapTaskRunnerTimer with garbage-collected types.");
+ }
~TaskRunnerTimer() override = default;
protected:
void Fired() override { (object_->*function_)(this); }
- NO_SANITIZE_ADDRESS
- bool CanFire() const override { return true; }
-
private:
TimerFiredClass* object_;
TimerFiredFunction function_;
};
template <typename TimerFiredClass>
-class TaskRunnerTimer<TimerFiredClass, true> : public TimerBase {
+class HeapTaskRunnerTimer final : public TimerBase {
+ DISALLOW_NEW();
+
public:
using TimerFiredFunction = void (TimerFiredClass::*)(TimerBase*);
- TaskRunnerTimer(scoped_refptr<base::SingleThreadTaskRunner> web_task_runner,
- TimerFiredClass* o,
- TimerFiredFunction f)
- : TimerBase(std::move(web_task_runner)), object_(o), function_(f) {}
+ HeapTaskRunnerTimer(
+ scoped_refptr<base::SingleThreadTaskRunner> web_task_runner,
+ TimerFiredClass* object,
+ TimerFiredFunction function)
+ : TimerBase(std::move(web_task_runner)),
+ object_(object),
+ function_(function) {
+ static_assert(
+ WTF::IsGarbageCollectedType<TimerFiredClass>::value,
+ "HeapTaskRunnerTimer can only be used with garbage-collected types.");
+ }
- ~TaskRunnerTimer() override = default;
+ ~HeapTaskRunnerTimer() final = default;
+
+ void Trace(Visitor* visitor) const { visitor->Trace(object_); }
protected:
- void Fired() override { (object_->*function_)(this); }
+ void Fired() final { (object_->*function_)(this); }
- NO_SANITIZE_ADDRESS
- bool CanFire() const override { return object_.IsClearedUnsafe(); }
+ base::OnceClosure BindTimerClosure(base::WeakPtr<TimerBase> weak_ptr) final {
+ return WTF::Bind(&HeapTaskRunnerTimer::RunInternalTrampoline,
+ std::move(weak_ptr), WrapWeakPersistent(object_.Get()));
+ }
private:
- GC_PLUGIN_IGNORE("363031")
- WeakPersistent<TimerFiredClass> object_;
+ // Trampoline used for garbage-collected timer version also checks whether the
+ // object has been deemed as dead by the GC but not yet reclaimed. Dead
+ // objects that have not been reclaimed yet must not be touched (which is
+ // enforced by ASAN poisoning).
+ static void RunInternalTrampoline(base::WeakPtr<TimerBase> weak_ptr,
+ TimerFiredClass* object) {
+ // - {weak_ptr} is invalidated upon request and when the timer is destroyed.
+ // - {object} is null when the garbage collector deemed the timer as
+ // unreachable.
+ if (weak_ptr && object) {
+ static_cast<HeapTaskRunnerTimer*>(weak_ptr.get())->RunInternal();
+ }
+ }
+
+ WeakMember<TimerFiredClass> object_;
TimerFiredFunction function_;
};
diff --git a/chromium/third_party/blink/renderer/platform/timer_test.cc b/chromium/third_party/blink/renderer/platform/timer_test.cc
index 527a2e2ec0d..432a5b04581 100644
--- a/chromium/third_party/blink/renderer/platform/timer_test.cc
+++ b/chromium/third_party/blink/renderer/platform/timer_test.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
+#include "third_party/blink/renderer/platform/wtf/buildflags.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
using base::sequence_manager::TaskQueue;
@@ -119,7 +120,7 @@ class OnHeapTimerOwner final : public GarbageCollected<OnHeapTimerOwner> {
timer_.StartOneShot(interval, caller);
}
- void Trace(Visitor* visitor) const {}
+ void Trace(Visitor* visitor) const { visitor->Trace(timer_); }
private:
void Fired(TimerBase*) {
@@ -127,7 +128,7 @@ class OnHeapTimerOwner final : public GarbageCollected<OnHeapTimerOwner> {
record_->SetTimerHasFired();
}
- TaskRunnerTimer<OnHeapTimerOwner> timer_;
+ HeapTaskRunnerTimer<OnHeapTimerOwner> timer_;
scoped_refptr<Record> record_;
};
@@ -642,6 +643,8 @@ TEST_F(TimerTest, DestructOnHeapTimer) {
EXPECT_FALSE(record->TimerHasFired());
}
+// TODO(1056170): Re-enable test.
+#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(TimerTest, MarkOnHeapTimerAsUnreachable) {
scoped_refptr<OnHeapTimerOwner::Record> record =
OnHeapTimerOwner::Record::Create();
@@ -669,6 +672,7 @@ TEST_F(TimerTest, MarkOnHeapTimerAsUnreachable) {
ThreadState::Current()->CompleteSweep();
}
}
+#endif // !USE_V8_OILPAN
namespace {
diff --git a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
index ffaad5f5e18..41938b8c015 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
@@ -75,6 +75,9 @@ class PLATFORM_EXPORT InterpolatedTransformOperation final
bool PreservesAxisAlignment() const final {
return from_.PreservesAxisAlignment() && to_.PreservesAxisAlignment();
}
+ bool IsIdentityOrTranslation() const final {
+ return from_.IsIdentityOrTranslation() && to_.IsIdentityOrTranslation();
+ }
BoxSizeDependency BoxSizeDependencies() const override {
return CombineDependencies(from_.BoxSizeDependencies(starting_index_),
diff --git a/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
index f33c3f22fb8..192a8e09f83 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
@@ -72,6 +72,9 @@ class PLATFORM_EXPORT Matrix3DTransformOperation final
bool PreservesAxisAlignment() const final {
return matrix_.Preserves2dAxisAlignment();
}
+ bool IsIdentityOrTranslation() const final {
+ return matrix_.IsIdentityOrTranslation();
+ }
Matrix3DTransformOperation(const TransformationMatrix& mat) { matrix_ = mat; }
diff --git a/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
index 688c0c080ce..746ea9621e2 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
@@ -86,6 +86,9 @@ class PLATFORM_EXPORT MatrixTransformOperation final
bool PreservesAxisAlignment() const final {
return Matrix().Preserves2dAxisAlignment();
}
+ bool IsIdentityOrTranslation() const final {
+ return Matrix().IsIdentityOr2DTranslation();
+ }
MatrixTransformOperation(double a,
double b,
diff --git a/chromium/third_party/blink/renderer/platform/transforms/scale_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
index c6352c03062..b4480c6c5ea 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
@@ -86,6 +86,9 @@ class PLATFORM_EXPORT ScaleTransformOperation final
scoped_refptr<TransformOperation> Zoom(double factor) final { return this; }
bool PreservesAxisAlignment() const final { return true; }
+ bool IsIdentityOrTranslation() const final {
+ return x_ == 1.0 && y_ == 1.0 && z_ == 1.0;
+ }
ScaleTransformOperation(double sx, double sy, double sz, OperationType type)
: x_(sx), y_(sy), z_(sz), type_(type) {
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/transform_operation.h
index 98fcab8f149..191c7a42efa 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operation.h
@@ -97,6 +97,7 @@ class PLATFORM_EXPORT TransformOperation
}
virtual bool PreservesAxisAlignment() const { return false; }
+ virtual bool IsIdentityOrTranslation() const { return false; }
bool Is3DOperation() const {
OperationType op_type = GetType();
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
index c60647516ad..9d9229c058b 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operations.h
@@ -91,6 +91,14 @@ class PLATFORM_EXPORT TransformOperations {
return true;
}
+ bool IsIdentityOrTranslation() const {
+ for (auto& operation : operations_) {
+ if (!operation->IsIdentityOrTranslation())
+ return false;
+ }
+ return true;
+ }
+
// Returns true if any operation has a non-trivial component in the Z axis.
bool HasNonTrivial3DComponent() const {
for (auto& operation : operations_) {
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc b/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
index b8f56c66e7a..2fbbe01c65e 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
@@ -736,4 +736,33 @@ TEST(TransformOperationsTest, SizeDependenciesCombineTest) {
EXPECT_EQ(ops.BoxSizeDependencies(), TransformOperation::kDependsBoth);
}
+// https://crbug.com/1155018
+TEST(TransformOperationsTest, OutOfRangePercentage) {
+ TransformOperations ops;
+ ops.Operations().push_back(TranslateTransformOperation::Create(
+ Length::Percent(std::numeric_limits<float>::max()), Length::Percent(50),
+ TransformOperation::kTranslate));
+
+ TransformationMatrix mat;
+ ops.Apply(FloatSize(800, 600), mat);
+
+ // There should not be inf or nan in the transformation result.
+ EXPECT_TRUE(isfinite(mat.M11()));
+ EXPECT_TRUE(isfinite(mat.M12()));
+ EXPECT_TRUE(isfinite(mat.M13()));
+ EXPECT_TRUE(isfinite(mat.M14()));
+ EXPECT_TRUE(isfinite(mat.M21()));
+ EXPECT_TRUE(isfinite(mat.M22()));
+ EXPECT_TRUE(isfinite(mat.M23()));
+ EXPECT_TRUE(isfinite(mat.M24()));
+ EXPECT_TRUE(isfinite(mat.M31()));
+ EXPECT_TRUE(isfinite(mat.M32()));
+ EXPECT_TRUE(isfinite(mat.M33()));
+ EXPECT_TRUE(isfinite(mat.M34()));
+ EXPECT_TRUE(isfinite(mat.M41()));
+ EXPECT_TRUE(isfinite(mat.M42()));
+ EXPECT_TRUE(isfinite(mat.M43()));
+ EXPECT_TRUE(isfinite(mat.M44()));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
index 3551de76e86..2e051fbf7b6 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
@@ -2095,6 +2095,13 @@ SkMatrix44 TransformationMatrix::ToSkMatrix44(
return ret;
}
+SkM44 TransformationMatrix::ToSkM44(const TransformationMatrix& matrix) {
+ return SkM44(matrix.M11(), matrix.M21(), matrix.M31(), matrix.M41(),
+ matrix.M12(), matrix.M22(), matrix.M32(), matrix.M42(),
+ matrix.M13(), matrix.M23(), matrix.M33(), matrix.M43(),
+ matrix.M14(), matrix.M24(), matrix.M34(), matrix.M44());
+}
+
gfx::Transform TransformationMatrix::ToTransform(
const TransformationMatrix& matrix) {
return gfx::Transform(matrix.M11(), matrix.M21(), matrix.M31(), matrix.M41(),
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
index 46cd52a835f..1f803c0f727 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix.h
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/platform/geometry/float_point.h"
#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/skia/include/core/SkM44.h"
#include "third_party/skia/include/core/SkMatrix44.h"
namespace gfx {
@@ -83,7 +84,7 @@ class PLATFORM_EXPORT TransformationMatrix {
TransformationMatrix() {
MakeIdentity();
}
- TransformationMatrix(const AffineTransform&);
+ explicit TransformationMatrix(const AffineTransform&);
TransformationMatrix(const TransformationMatrix& t) {
*this = t;
}
@@ -114,7 +115,7 @@ class PLATFORM_EXPORT TransformationMatrix {
SetMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41,
m42, m43, m44);
}
- TransformationMatrix(const SkMatrix44& matrix) {
+ explicit TransformationMatrix(const SkMatrix44& matrix) {
SetMatrix(
matrix.get(0, 0), matrix.get(1, 0), matrix.get(2, 0), matrix.get(3, 0),
matrix.get(0, 1), matrix.get(1, 1), matrix.get(2, 1), matrix.get(3, 1),
@@ -458,6 +459,7 @@ class PLATFORM_EXPORT TransformationMatrix {
void ToColumnMajorFloatArray(FloatMatrix4& result) const;
static SkMatrix44 ToSkMatrix44(const TransformationMatrix&);
+ static SkM44 ToSkM44(const TransformationMatrix&);
static gfx::Transform ToTransform(const TransformationMatrix&);
// If |asMatrix|, return the matrix in row-major order. Otherwise, return
diff --git a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
index 11503ae1808..a9a70c44de6 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/transformation_matrix_test_helpers.h
@@ -5,8 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TRANSFORMS_TRANSFORMATION_MATRIX_TEST_HELPERS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TRANSFORMS_TRANSFORMATION_MATRIX_TEST_HELPERS_H_
-#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
#include "ui/gfx/transform.h"
namespace blink {
@@ -18,7 +18,7 @@ constexpr double kFloatingPointErrorTolerance = 1e-6;
#define EXPECT_TRANSFORMATION_MATRIX(expected, actual) \
do { \
SCOPED_TRACE(""); \
- cc::ExpectTransformationMatrixNear( \
+ gfx::ExpectTransformationMatrixNear( \
TransformationMatrix::ToTransform(expected), \
TransformationMatrix::ToTransform(actual), \
kFloatingPointErrorTolerance); \
diff --git a/chromium/third_party/blink/renderer/platform/transforms/translate_transform_operation.h b/chromium/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
index 35eda88e662..a83d4630b6d 100644
--- a/chromium/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
+++ b/chromium/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
@@ -104,6 +104,7 @@ class PLATFORM_EXPORT TranslateTransformOperation final
}
bool PreservesAxisAlignment() const final { return true; }
+ bool IsIdentityOrTranslation() const final { return true; }
TranslateTransformOperation(const Length& tx,
const Length& ty,
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/DEPS b/chromium/third_party/blink/renderer/platform/video_capture/DEPS
index ab4b0ea49e6..608fe8686b5 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/DEPS
+++ b/chromium/third_party/blink/renderer/platform/video_capture/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+third_party/blink/renderer/platform/video_capture",
# Dependencies.
+ "+base/bind_post_task.h",
"+media/base",
"+media/capture",
"+third_party/blink/renderer/platform/wtf",
@@ -21,6 +22,7 @@ include_rules = [
specific_include_rules = {
"video_capture_impl_test.cc": [
"+third_party/blink/renderer/platform/testing/gpu_memory_buffer_test_support.h",
+ "+third_party/blink/renderer/platform/testing/histogram_tester.h",
],
"gpu_memory_buffer_test_support.cc": [
"+components/viz/test/test_context_provider.h",
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/DIR_METADATA b/chromium/third_party/blink/renderer/platform/video_capture/DIR_METADATA
new file mode 100644
index 00000000000..84de928a05d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/video_capture/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>GetUserMedia>Webcam"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/OWNERS b/chromium/third_party/blink/renderer/platform/video_capture/OWNERS
index 0a6f62e7be4..be3ed76d1c1 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/video_capture/OWNERS
@@ -1,4 +1,2 @@
chfremer@chromium.org
guidou@chromium.org
-
-# COMPONENT: Blink>GetUserMedia>Webcam
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/local_video_capturer_source.cc b/chromium/third_party/blink/renderer/platform/video_capture/local_video_capturer_source.cc
index 0b50485c6fd..31abe9a8f43 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/local_video_capturer_source.cc
+++ b/chromium/third_party/blink/renderer/platform/video_capture/local_video_capturer_source.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "media/base/bind_to_current_loop.h"
+#include "base/bind_post_task.h"
#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -42,8 +42,8 @@ void LocalVideoCapturerSource::StartCapture(
stop_capture_cb_ = manager_->StartCapture(
session_id_, params,
- media::BindToLoop(task_runner_,
- ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+ base::BindPostTask(
+ task_runner_, ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
&LocalVideoCapturerSource::OnStateUpdate,
weak_factory_.GetWeakPtr()))),
new_frame_callback);
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
index fe10a7a0895..f9d2ecf1a5f 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -17,8 +17,10 @@
#include <utility>
#include "base/bind.h"
+#include "base/bind_post_task.h"
#include "base/callback_helpers.h"
#include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
@@ -104,6 +106,15 @@ struct VideoCaptureImpl::BufferContext
const Vector<gpu::MailboxHolder>& mailbox_holders() const {
return mailbox_holders_;
}
+ media::GpuVideoAcceleratorFactories* gpu_factories() const {
+ return gpu_factories_;
+ }
+ void SetGpuFactories(media::GpuVideoAcceleratorFactories* gpu_factories) {
+ gpu_factories_ = gpu_factories;
+ }
+ GpuMemoryBufferResources* gmb_resources() const {
+ return gmb_resources_.get();
+ }
gfx::GpuMemoryBufferHandle TakeGpuMemoryBufferHandle() {
#if defined(OS_MAC)
@@ -125,84 +136,6 @@ struct VideoCaptureImpl::BufferContext
return gmb_resources_->gpu_memory_buffer.get();
}
- // Creates SharedImage mailboxes for |gpu_memory_buffer_handle_| and wraps the
- // mailboxes with the buffer handles in a DMA-buf VideoFrame. The consumer of
- // the VideoFrame can access the data either through mailboxes (e.g. display)
- // or through the DMA-buf FDs (e.g. video encoder).
- static void BindBufferToTextureOnMediaThread(
- media::GpuVideoAcceleratorFactories* gpu_factories,
- scoped_refptr<BufferContext> buffer_context,
- media::mojom::blink::VideoFrameInfoPtr info,
- std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
- scoped_refptr<media::VideoFrame> frame,
- base::OnceCallback<void(media::mojom::blink::VideoFrameInfoPtr,
- scoped_refptr<media::VideoFrame>,
- scoped_refptr<BufferContext>)> on_texture_bound,
- base::OnceCallback<void()> on_gpu_context_lost) {
- DCHECK(gpu_factories);
- DCHECK(buffer_context->media_task_runner_->RunsTasksInCurrentSequence());
- DCHECK_EQ(info->pixel_format, media::PIXEL_FORMAT_NV12);
-
- bool should_recreate_shared_image = false;
- if (gpu_factories != buffer_context->gpu_factories_) {
- DVLOG(1) << "GPU context changed; re-creating SharedImage objects";
- buffer_context->gpu_factories_ = gpu_factories;
- should_recreate_shared_image = true;
- }
-
- // Create GPU texture and bind GpuMemoryBuffer to the texture.
- auto* sii = buffer_context->gpu_factories_->SharedImageInterface();
- if (!sii) {
- DVLOG(1) << "GPU context lost";
- std::move(on_gpu_context_lost).Run();
- std::move(on_texture_bound)
- .Run(std::move(info), std::move(frame), std::move(buffer_context));
- return;
- }
- // Don't check VideoFrameOutputFormat until we ensure the context has not
- // been lost (if it is lost, then the format will be UNKNOWN).
- DCHECK_EQ(
- buffer_context->gpu_factories_->VideoFrameOutputFormat(
- info->pixel_format),
- media::GpuVideoAcceleratorFactories::OutputFormat::NV12_SINGLE_GMB);
- unsigned texture_target =
- buffer_context->gpu_factories_->ImageTextureTarget(
- gpu_memory_buffer->GetFormat());
- if (should_recreate_shared_image ||
- buffer_context->gmb_resources_->mailbox.IsZero()) {
- uint32_t usage =
- gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER |
- gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
- gpu::SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX;
- buffer_context->gmb_resources_->mailbox = sii->CreateSharedImage(
- gpu_memory_buffer.get(),
- buffer_context->gpu_factories_->GpuMemoryBufferManager(),
- *(info->color_space), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
- usage);
- } else {
- sii->UpdateSharedImage(buffer_context->gmb_resources_->release_sync_token,
- buffer_context->gmb_resources_->mailbox);
- }
- gpu::SyncToken sync_token = sii->GenUnverifiedSyncToken();
- CHECK(!buffer_context->gmb_resources_->mailbox.IsZero());
- CHECK(buffer_context->gmb_resources_->mailbox.IsSharedImage());
- gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
- mailbox_holder_array[0] = gpu::MailboxHolder(
- buffer_context->gmb_resources_->mailbox, sync_token, texture_target);
-
- const auto gmb_size = gpu_memory_buffer->GetSize();
- frame = media::VideoFrame::WrapExternalGpuMemoryBuffer(
- gfx::Rect(info->visible_rect), gmb_size, std::move(gpu_memory_buffer),
- mailbox_holder_array,
- base::BindOnce(&BufferContext::MailboxHolderReleased, buffer_context),
- info->timestamp);
- frame->metadata()->allow_overlay = true;
- frame->metadata()->read_lock_fences_enabled = true;
-
- std::move(on_texture_bound)
- .Run(std::move(info), std::move(frame), std::move(buffer_context));
- }
-
static void MailboxHolderReleased(scoped_refptr<BufferContext> buffer_context,
const gpu::SyncToken& release_sync_token) {
if (!buffer_context->media_task_runner_->RunsTasksInCurrentSequence()) {
@@ -304,6 +237,240 @@ struct VideoCaptureImpl::BufferContext
DISALLOW_COPY_AND_ASSIGN(BufferContext);
};
+VideoCaptureImpl::VideoFrameBufferPreparer::VideoFrameBufferPreparer(
+ VideoCaptureImpl& video_capture_impl,
+ media::mojom::blink::ReadyBufferPtr ready_buffer)
+ : video_capture_impl_(video_capture_impl),
+ buffer_id_(ready_buffer->buffer_id),
+ frame_info_(std::move(ready_buffer->info)) {}
+
+int32_t VideoCaptureImpl::VideoFrameBufferPreparer::buffer_id() const {
+ return buffer_id_;
+}
+
+const media::mojom::blink::VideoFrameInfoPtr&
+VideoCaptureImpl::VideoFrameBufferPreparer::frame_info() const {
+ return frame_info_;
+}
+
+scoped_refptr<media::VideoFrame>
+VideoCaptureImpl::VideoFrameBufferPreparer::frame() const {
+ return frame_;
+}
+
+scoped_refptr<VideoCaptureImpl::BufferContext>
+VideoCaptureImpl::VideoFrameBufferPreparer::buffer_context() const {
+ return buffer_context_;
+}
+
+bool VideoCaptureImpl::VideoFrameBufferPreparer::Initialize() {
+ // Prior to initializing, |frame_| and |gpu_memory_buffer_| are null.
+ DCHECK(!frame_ && !gpu_memory_buffer_);
+ const auto& iter = video_capture_impl_.client_buffers_.find(buffer_id_);
+ DCHECK(iter != video_capture_impl_.client_buffers_.end());
+ buffer_context_ = iter->second;
+ switch (buffer_context_->buffer_type()) {
+ case VideoFrameBufferHandleType::SHARED_BUFFER_HANDLE:
+ // The frame is backed by a writable (unsafe) shared memory handle, but as
+ // it is not sent cross-process the region does not need to be attached to
+ // the frame. See also the case for READ_ONLY_SHMEM_REGION.
+ if (frame_info_->strides) {
+ CHECK(IsYuvPlanar(frame_info_->pixel_format) &&
+ (media::VideoFrame::NumPlanes(frame_info_->pixel_format) == 3))
+ << "Currently, only YUV formats support custom strides.";
+ uint8_t* y_data = const_cast<uint8_t*>(buffer_context_->data());
+ uint8_t* u_data =
+ y_data + (media::VideoFrame::Rows(
+ media::VideoFrame::kYPlane, frame_info_->pixel_format,
+ frame_info_->coded_size.height()) *
+ frame_info_->strides->stride_by_plane[0]);
+ uint8_t* v_data =
+ u_data + (media::VideoFrame::Rows(
+ media::VideoFrame::kUPlane, frame_info_->pixel_format,
+ frame_info_->coded_size.height()) *
+ frame_info_->strides->stride_by_plane[1]);
+ frame_ = media::VideoFrame::WrapExternalYuvData(
+ frame_info_->pixel_format, gfx::Size(frame_info_->coded_size),
+ gfx::Rect(frame_info_->visible_rect),
+ frame_info_->visible_rect.size(),
+ frame_info_->strides->stride_by_plane[0],
+ frame_info_->strides->stride_by_plane[1],
+ frame_info_->strides->stride_by_plane[2], y_data, u_data, v_data,
+ frame_info_->timestamp);
+ } else {
+ frame_ = media::VideoFrame::WrapExternalData(
+ frame_info_->pixel_format, gfx::Size(frame_info_->coded_size),
+ gfx::Rect(frame_info_->visible_rect),
+ frame_info_->visible_rect.size(),
+ const_cast<uint8_t*>(buffer_context_->data()),
+ buffer_context_->data_size(), frame_info_->timestamp);
+ }
+ break;
+ case VideoFrameBufferHandleType::READ_ONLY_SHMEM_REGION:
+ // As with the SHARED_BUFFER_HANDLE type, it is sufficient to just wrap
+ // the data without attaching the shared region to the frame.
+ frame_ = media::VideoFrame::WrapExternalData(
+ frame_info_->pixel_format, gfx::Size(frame_info_->coded_size),
+ gfx::Rect(frame_info_->visible_rect),
+ frame_info_->visible_rect.size(),
+ const_cast<uint8_t*>(buffer_context_->data()),
+ buffer_context_->data_size(), frame_info_->timestamp);
+ break;
+ case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
+ NOTREACHED();
+ break;
+ case VideoFrameBufferHandleType::MAILBOX_HANDLES: {
+ gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
+ CHECK_EQ(media::VideoFrame::kMaxPlanes,
+ buffer_context_->mailbox_holders().size());
+ for (int i = 0; i < media::VideoFrame::kMaxPlanes; i++) {
+ mailbox_holder_array[i] = buffer_context_->mailbox_holders()[i];
+ }
+ frame_ = media::VideoFrame::WrapNativeTextures(
+ frame_info_->pixel_format, mailbox_holder_array,
+ media::VideoFrame::ReleaseMailboxCB(),
+ gfx::Size(frame_info_->coded_size),
+ gfx::Rect(frame_info_->visible_rect),
+ frame_info_->visible_rect.size(), frame_info_->timestamp);
+ break;
+ }
+ case VideoFrameBufferHandleType::GPU_MEMORY_BUFFER_HANDLE: {
+#if defined(OS_MAC)
+ // On macOS, an IOSurfaces passed as a GpuMemoryBufferHandle can be
+ // used by both hardware and software paths.
+ // https://crbug.com/1125879
+ if (!video_capture_impl_.gpu_factories_ ||
+ !video_capture_impl_.media_task_runner_) {
+ frame_ = media::VideoFrame::WrapUnacceleratedIOSurface(
+ buffer_context_->TakeGpuMemoryBufferHandle(),
+ gfx::Rect(frame_info_->visible_rect), frame_info_->timestamp);
+ break;
+ }
+#endif
+ CHECK(video_capture_impl_.gpu_factories_);
+ CHECK(video_capture_impl_.media_task_runner_);
+ // Create GpuMemoryBuffer from handle.
+ if (!buffer_context_->GetGpuMemoryBuffer()) {
+ gfx::BufferFormat gfx_format;
+ switch (frame_info_->pixel_format) {
+ case media::VideoPixelFormat::PIXEL_FORMAT_NV12:
+ gfx_format = gfx::BufferFormat::YUV_420_BIPLANAR;
+ break;
+ default:
+ LOG(FATAL) << "Unsupported pixel format";
+ return false;
+ }
+ // The GpuMemoryBuffer is allocated and owned by the video capture
+ // buffer pool from the video capture service process, so we don't need
+ // to destroy the GpuMemoryBuffer here.
+ auto gmb =
+ video_capture_impl_.gpu_memory_buffer_support_
+ ->CreateGpuMemoryBufferImplFromHandle(
+ buffer_context_->TakeGpuMemoryBufferHandle(),
+ gfx::Size(frame_info_->coded_size), gfx_format,
+ gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing());
+ buffer_context_->SetGpuMemoryBuffer(std::move(gmb));
+ }
+ CHECK(buffer_context_->GetGpuMemoryBuffer());
+
+ // Clone the GpuMemoryBuffer and wrap it in a VideoFrame.
+ gpu_memory_buffer_ =
+ video_capture_impl_.gpu_memory_buffer_support_
+ ->CreateGpuMemoryBufferImplFromHandle(
+ buffer_context_->GetGpuMemoryBuffer()->CloneHandle(),
+ buffer_context_->GetGpuMemoryBuffer()->GetSize(),
+ buffer_context_->GetGpuMemoryBuffer()->GetFormat(),
+ gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing());
+ }
+ }
+ // After initializing, either |frame_| or |gpu_memory_buffer_| has been set.
+ DCHECK(frame_ || gpu_memory_buffer_);
+ return true;
+}
+
+bool VideoCaptureImpl::VideoFrameBufferPreparer::IsVideoFrameBound() const {
+ return frame_.get();
+}
+
+// Creates SharedImage mailboxes for |gpu_memory_buffer_handle_| and wraps the
+// mailboxes with the buffer handles in a DMA-buf VideoFrame. The consumer of
+// the VideoFrame can access the data either through mailboxes (e.g. display)
+// or through the DMA-buf FDs (e.g. video encoder).
+bool VideoCaptureImpl::VideoFrameBufferPreparer::BindVideoFrameOnMediaThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ DCHECK(gpu_factories);
+ DCHECK(!IsVideoFrameBound());
+ DCHECK_EQ(frame_info_->pixel_format, media::PIXEL_FORMAT_NV12);
+
+ bool should_recreate_shared_image = false;
+ if (gpu_factories != buffer_context_->gpu_factories()) {
+ DVLOG(1) << "GPU context changed; re-creating SharedImage objects";
+ buffer_context_->SetGpuFactories(gpu_factories);
+ should_recreate_shared_image = true;
+ }
+
+ // Create GPU texture and bind GpuMemoryBuffer to the texture.
+ auto* sii = buffer_context_->gpu_factories()->SharedImageInterface();
+ if (!sii) {
+ DVLOG(1) << "GPU context lost";
+ return false;
+ }
+ // Don't check VideoFrameOutputFormat until we ensure the context has not
+ // been lost (if it is lost, then the format will be UNKNOWN).
+ DCHECK_EQ(buffer_context_->gpu_factories()->VideoFrameOutputFormat(
+ frame_info_->pixel_format),
+ media::GpuVideoAcceleratorFactories::OutputFormat::NV12_SINGLE_GMB);
+ unsigned texture_target =
+ buffer_context_->gpu_factories()->ImageTextureTarget(
+ gpu_memory_buffer_->GetFormat());
+ if (should_recreate_shared_image ||
+ buffer_context_->gmb_resources()->mailbox.IsZero()) {
+ uint32_t usage =
+ gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER |
+ gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
+ gpu::SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX;
+ buffer_context_->gmb_resources()->mailbox = sii->CreateSharedImage(
+ gpu_memory_buffer_.get(),
+ buffer_context_->gpu_factories()->GpuMemoryBufferManager(),
+ *(frame_info_->color_space), kTopLeft_GrSurfaceOrigin,
+ kPremul_SkAlphaType, usage);
+ } else {
+ sii->UpdateSharedImage(buffer_context_->gmb_resources()->release_sync_token,
+ buffer_context_->gmb_resources()->mailbox);
+ }
+ gpu::SyncToken sync_token = sii->GenVerifiedSyncToken();
+ CHECK(!buffer_context_->gmb_resources()->mailbox.IsZero());
+ CHECK(buffer_context_->gmb_resources()->mailbox.IsSharedImage());
+ gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
+ mailbox_holder_array[0] = gpu::MailboxHolder(
+ buffer_context_->gmb_resources()->mailbox, sync_token, texture_target);
+
+ const auto gmb_size = gpu_memory_buffer_->GetSize();
+ frame_ = media::VideoFrame::WrapExternalGpuMemoryBuffer(
+ gfx::Rect(frame_info_->visible_rect), gmb_size,
+ std::move(gpu_memory_buffer_), mailbox_holder_array,
+ base::BindOnce(&BufferContext::MailboxHolderReleased, buffer_context_),
+ frame_info_->timestamp);
+ frame_->metadata().allow_overlay = true;
+ frame_->metadata().read_lock_fences_enabled = true;
+ return true;
+}
+
+void VideoCaptureImpl::VideoFrameBufferPreparer::Finalize() {
+ DCHECK(frame_);
+ frame_->AddDestructionObserver(
+ base::BindOnce(&VideoCaptureImpl::DidFinishConsumingFrame,
+ media::BindToCurrentLoop(base::BindOnce(
+ &VideoCaptureImpl::OnAllClientsFinishedConsumingFrame,
+ video_capture_impl_.weak_factory_.GetWeakPtr(),
+ buffer_id_, buffer_context_))));
+ if (frame_info_->color_space.has_value() &&
+ frame_info_->color_space->IsValid()) {
+ frame_->set_color_space(frame_info_->color_space.value());
+ }
+ frame_->metadata().MergeMetadataFrom(frame_info_->metadata);
+}
+
// Information about a video capture client of ours.
struct VideoCaptureImpl::ClientInfo {
ClientInfo() = default;
@@ -502,6 +669,7 @@ void VideoCaptureImpl::OnStateChanged(media::mojom::VideoCaptureState state) {
// a frame refresh to start the video call with.
// Capture device will make a decision if it should refresh a frame.
RequestRefreshFrame();
+ RecordStartOutcomeUMA(VideoCaptureStartOutcome::kStarted);
break;
case media::mojom::VideoCaptureState::STOPPED:
OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPED");
@@ -527,6 +695,10 @@ void VideoCaptureImpl::OnStateChanged(media::mojom::VideoCaptureState state) {
client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
clients_.clear();
state_ = VIDEO_CAPTURE_STATE_ERROR;
+
+ RecordStartOutcomeUMA(start_timedout_
+ ? VideoCaptureStartOutcome::kTimedout
+ : VideoCaptureStartOutcome::kFailed);
break;
case media::mojom::VideoCaptureState::ENDED:
OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_ENDED");
@@ -554,21 +726,25 @@ void VideoCaptureImpl::OnNewBuffer(
}
void VideoCaptureImpl::OnBufferReady(
- int32_t buffer_id,
- media::mojom::blink::VideoFrameInfoPtr info) {
- DVLOG(1) << __func__ << " buffer_id: " << buffer_id;
+ media::mojom::blink::ReadyBufferPtr buffer,
+ Vector<media::mojom::blink::ReadyBufferPtr> scaled_buffers) {
+ DVLOG(1) << __func__ << " buffer_id: " << buffer->buffer_id;
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
bool consume_buffer = state_ == VIDEO_CAPTURE_STATE_STARTED;
if (!consume_buffer) {
OnFrameDropped(
media::VideoCaptureFrameDropReason::kVideoCaptureImplNotInStartedState);
- GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id,
+ GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer->buffer_id,
media::VideoFrameFeedback());
+ for (auto& scaled_buffer : scaled_buffers) {
+ GetVideoCaptureHost()->ReleaseBuffer(device_id_, scaled_buffer->buffer_id,
+ media::VideoFrameFeedback());
+ }
return;
}
- base::TimeTicks reference_time = *info->metadata.reference_time;
+ base::TimeTicks reference_time = *buffer->info->metadata.reference_time;
if (first_frame_ref_time_.is_null()) {
first_frame_ref_time_ = reference_time;
@@ -587,8 +763,14 @@ void VideoCaptureImpl::OnBufferReady(
// estimate. e.g. ThreadSafeCaptureOracle::DidCaptureFrame().
// TODO(miu): Fix upstream capturers to always set timestamp and reference
// time. See http://crbug/618407/ for tracking.
- if (info->timestamp.is_zero())
- info->timestamp = reference_time - first_frame_ref_time_;
+ if (buffer->info->timestamp.is_zero())
+ buffer->info->timestamp = reference_time - first_frame_ref_time_;
+
+ // If the capture_begin_time was not set use the reference time. This ensures
+ // there is a captureTime available for local sources for
+ // requestVideoFrameCallback.
+ if (!buffer->info->metadata.capture_begin_time)
+ buffer->info->metadata.capture_begin_time = reference_time;
// TODO(qiangchen): Change the metric name to "reference_time" and
// "timestamp", so that we have consistent naming everywhere.
@@ -596,169 +778,122 @@ void VideoCaptureImpl::OnBufferReady(
TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived",
TRACE_EVENT_SCOPE_THREAD, "timestamp",
(reference_time - base::TimeTicks()).InMicroseconds(),
- "time_delta", info->timestamp.InMicroseconds());
-
- const auto& iter = client_buffers_.find(buffer_id);
- DCHECK(iter != client_buffers_.end());
- scoped_refptr<BufferContext> buffer_context = iter->second;
- scoped_refptr<media::VideoFrame> frame;
- switch (buffer_context->buffer_type()) {
- case VideoFrameBufferHandleType::SHARED_BUFFER_HANDLE:
- // The frame is backed by a writable (unsafe) shared memory handle, but as
- // it is not sent cross-process the region does not need to be attached to
- // the frame. See also the case for READ_ONLY_SHMEM_REGION.
- if (info->strides) {
- CHECK(IsYuvPlanar(info->pixel_format) &&
- (media::VideoFrame::NumPlanes(info->pixel_format) == 3))
- << "Currently, only YUV formats support custom strides.";
- uint8_t* y_data = const_cast<uint8_t*>(buffer_context->data());
- uint8_t* u_data =
- y_data + (media::VideoFrame::Rows(media::VideoFrame::kYPlane,
- info->pixel_format,
- info->coded_size.height()) *
- info->strides->stride_by_plane[0]);
- uint8_t* v_data =
- u_data + (media::VideoFrame::Rows(media::VideoFrame::kUPlane,
- info->pixel_format,
- info->coded_size.height()) *
- info->strides->stride_by_plane[1]);
- frame = media::VideoFrame::WrapExternalYuvData(
- info->pixel_format, gfx::Size(info->coded_size),
- gfx::Rect(info->visible_rect), info->visible_rect.size(),
- info->strides->stride_by_plane[0],
- info->strides->stride_by_plane[1],
- info->strides->stride_by_plane[2], y_data, u_data, v_data,
- info->timestamp);
- } else {
- frame = media::VideoFrame::WrapExternalData(
- info->pixel_format, gfx::Size(info->coded_size),
- gfx::Rect(info->visible_rect), info->visible_rect.size(),
- const_cast<uint8_t*>(buffer_context->data()),
- buffer_context->data_size(), info->timestamp);
- }
- break;
- case VideoFrameBufferHandleType::READ_ONLY_SHMEM_REGION:
- // As with the SHARED_BUFFER_HANDLE type, it is sufficient to just wrap
- // the data without attaching the shared region to the frame.
- frame = media::VideoFrame::WrapExternalData(
- info->pixel_format, gfx::Size(info->coded_size),
- gfx::Rect(info->visible_rect), info->visible_rect.size(),
- const_cast<uint8_t*>(buffer_context->data()),
- buffer_context->data_size(), info->timestamp);
- break;
- case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
- NOTREACHED();
- break;
- case VideoFrameBufferHandleType::MAILBOX_HANDLES: {
- gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
- CHECK_EQ(media::VideoFrame::kMaxPlanes,
- buffer_context->mailbox_holders().size());
- for (int i = 0; i < media::VideoFrame::kMaxPlanes; i++) {
- mailbox_holder_array[i] = buffer_context->mailbox_holders()[i];
- }
- frame = media::VideoFrame::WrapNativeTextures(
- info->pixel_format, mailbox_holder_array,
- media::VideoFrame::ReleaseMailboxCB(), gfx::Size(info->coded_size),
- gfx::Rect(info->visible_rect), info->visible_rect.size(),
- info->timestamp);
- break;
- }
- case VideoFrameBufferHandleType::GPU_MEMORY_BUFFER_HANDLE: {
-#if defined(OS_MAC)
- // On macOS, an IOSurfaces passed as a GpuMemoryBufferHandle can be
- // used by both hardware and software paths.
- // https://crbug.com/1125879
- if (!gpu_factories_ || !media_task_runner_) {
- frame = media::VideoFrame::WrapUnacceleratedIOSurface(
- buffer_context->TakeGpuMemoryBufferHandle(),
- gfx::Rect(info->visible_rect), info->timestamp);
- break;
- }
-#endif
- CHECK(gpu_factories_);
- CHECK(media_task_runner_);
- // Create GpuMemoryBuffer from handle.
- if (!buffer_context->GetGpuMemoryBuffer()) {
- gfx::BufferFormat gfx_format;
- switch (info->pixel_format) {
- case media::VideoPixelFormat::PIXEL_FORMAT_NV12:
- gfx_format = gfx::BufferFormat::YUV_420_BIPLANAR;
- break;
- default:
- LOG(FATAL) << "Unsupported pixel format";
- return;
- }
- // The GpuMemoryBuffer is allocated and owned by the video capture
- // buffer pool from the video capture service process, so we don't need
- // to destroy the GpuMemoryBuffer here.
- auto gmb =
- gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
- buffer_context->TakeGpuMemoryBufferHandle(),
- gfx::Size(info->coded_size), gfx_format,
- gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing());
- buffer_context->SetGpuMemoryBuffer(std::move(gmb));
- }
- CHECK(buffer_context->GetGpuMemoryBuffer());
+ "time_delta", buffer->info->timestamp.InMicroseconds());
+
+ // Create and initialize frame preparers for the non-scaled and the scaled
+ // frames.
+ auto frame_preparer =
+ std::make_unique<VideoFrameBufferPreparer>(*this, std::move(buffer));
+ bool init_successful = frame_preparer->Initialize();
+ bool need_binding_on_media_thread = !frame_preparer->IsVideoFrameBound();
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>> scaled_frame_preparers;
+ scaled_frame_preparers.reserve(scaled_buffers.size());
+ for (media::mojom::blink::ReadyBufferPtr& scaled_buffer : scaled_buffers) {
+ auto scaled_frame_preparer = std::make_unique<VideoFrameBufferPreparer>(
+ *this, std::move(scaled_buffer));
+ init_successful &= scaled_frame_preparer->Initialize();
+ need_binding_on_media_thread |= !scaled_frame_preparer->IsVideoFrameBound();
+ scaled_frame_preparers.push_back(std::move(scaled_frame_preparer));
+ }
+ if (!init_successful) {
+ return;
+ }
- // Clone the GpuMemoryBuffer and wrap it in a VideoFrame.
- std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
- gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
- buffer_context->GetGpuMemoryBuffer()->CloneHandle(),
- buffer_context->GetGpuMemoryBuffer()->GetSize(),
- buffer_context->GetGpuMemoryBuffer()->GetFormat(),
- gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing());
+ // If any of the video frames needs to be bound we do a round-trip time to the
+ // media thread, otherwise we'll go directly to OnVideoFrameReady().
+ if (need_binding_on_media_thread) {
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&VideoCaptureImpl::BindVideoFramesOnMediaThread,
+ gpu_factories_, std::move(frame_preparer),
+ std::move(scaled_frame_preparers),
+ media::BindToCurrentLoop(base::BindOnce(
+ &VideoCaptureImpl::OnVideoFrameReady,
+ weak_factory_.GetWeakPtr(), reference_time)),
+ base::BindPostTask(
+ main_task_runner_,
+ base::BindOnce(&VideoCaptureImpl::OnGpuContextLost,
+ weak_factory_.GetWeakPtr()))));
+ return;
+ }
+ OnVideoFrameReady(reference_time, std::move(frame_preparer),
+ std::move(scaled_frame_preparers));
+}
- media_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &BufferContext::BindBufferToTextureOnMediaThread, gpu_factories_,
- std::move(buffer_context), std::move(info), std::move(gmb), frame,
- media::BindToCurrentLoop(base::BindOnce(
- &VideoCaptureImpl::OnVideoFrameReady,
- weak_factory_.GetWeakPtr(), buffer_id, reference_time)),
- media::BindToLoop(
- main_task_runner_,
- base::BindOnce(&VideoCaptureImpl::OnGpuContextLost,
- weak_factory_.GetWeakPtr()))));
- return;
+// static
+void VideoCaptureImpl::BindVideoFramesOnMediaThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ std::unique_ptr<VideoFrameBufferPreparer> frame_preparer,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>
+ scaled_frame_preparers,
+ base::OnceCallback<
+ void(std::unique_ptr<VideoFrameBufferPreparer>,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>)>
+ on_frame_ready_callback,
+ base::OnceCallback<void()> on_gpu_context_lost) {
+ // Bind all frames that needs binding, i.e. the GPU frames. Software frames
+ // already bound are not touched, allowing mixing software and hardware
+ // frames.
+ bool bind_failed = false;
+ if (!frame_preparer->IsVideoFrameBound()) {
+ bind_failed |= !frame_preparer->BindVideoFrameOnMediaThread(gpu_factories);
+ }
+ for (auto& scaled_frame_preparer : scaled_frame_preparers) {
+ if (!scaled_frame_preparer->IsVideoFrameBound()) {
+ bind_failed |=
+ !scaled_frame_preparer->BindVideoFrameOnMediaThread(gpu_factories);
}
}
- OnVideoFrameReady(buffer_id, reference_time, std::move(info),
- std::move(frame), std::move(buffer_context));
+ if (bind_failed) {
+ std::move(on_gpu_context_lost).Run();
+ // Proceed to invoke |on_frame_ready_callback| even though we failed. It
+ // takes care of dropping the frames.
+ }
+ std::move(on_frame_ready_callback)
+ .Run(std::move(frame_preparer), std::move(scaled_frame_preparers));
}
void VideoCaptureImpl::OnVideoFrameReady(
- int32_t buffer_id,
base::TimeTicks reference_time,
- media::mojom::blink::VideoFrameInfoPtr info,
- scoped_refptr<media::VideoFrame> frame,
- scoped_refptr<BufferContext> buffer_context) {
+ std::unique_ptr<VideoFrameBufferPreparer> frame_preparer,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>
+ scaled_frame_preparers) {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
- if (!frame) {
+ // If any of the frames are not bound and ready we drop all of them.
+ bool is_any_frame_not_bound = !frame_preparer->IsVideoFrameBound();
+ for (const auto& scaled_frame_preparer : scaled_frame_preparers) {
+ is_any_frame_not_bound |= !scaled_frame_preparer->IsVideoFrameBound();
+ }
+ if (is_any_frame_not_bound) {
OnFrameDropped(media::VideoCaptureFrameDropReason::
kVideoCaptureImplFailedToWrapDataAsMediaVideoFrame);
- GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id,
- media::VideoFrameFeedback());
+ // Release all buffers.
+ GetVideoCaptureHost()->ReleaseBuffer(
+ device_id_, frame_preparer->buffer_id(), media::VideoFrameFeedback());
+ for (const auto& scaled_frame_preparer : scaled_frame_preparers) {
+ GetVideoCaptureHost()->ReleaseBuffer(device_id_,
+ scaled_frame_preparer->buffer_id(),
+ media::VideoFrameFeedback());
+ }
return;
}
- frame->AddDestructionObserver(base::BindOnce(
- &VideoCaptureImpl::DidFinishConsumingFrame,
- media::BindToCurrentLoop(base::BindOnce(
- &VideoCaptureImpl::OnAllClientsFinishedConsumingFrame,
- weak_factory_.GetWeakPtr(), buffer_id, std::move(buffer_context)))));
-
- if (info->color_space.has_value() && info->color_space->IsValid())
- frame->set_color_space(info->color_space.value());
-
- media::VideoFrameMetadata metadata = info->metadata;
- frame->metadata()->MergeMetadataFrom(&metadata);
+ // The buffers will be used. Finaize them.
+ frame_preparer->Finalize();
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames;
+ scaled_video_frames.reserve(scaled_frame_preparers.size());
+ for (const auto& scaled_frame_preparer : scaled_frame_preparers) {
+ scaled_frame_preparer->Finalize();
+ scaled_video_frames.push_back(scaled_frame_preparer->frame());
+ }
// TODO(qiangchen): Dive into the full code path to let frame metadata hold
// reference time rather than using an extra parameter.
- for (const auto& client : clients_)
- client.second.deliver_frame_cb.Run(frame, reference_time);
+ for (const auto& client : clients_) {
+ client.second.deliver_frame_cb.Run(frame_preparer->frame(),
+ scaled_video_frames, reference_time);
+ }
}
void VideoCaptureImpl::OnBufferDestroyed(int32_t buffer_id) {
@@ -849,6 +984,9 @@ void VideoCaptureImpl::StartCaptureInternal() {
base::BindOnce(&VideoCaptureImpl::OnStartTimedout,
base::Unretained(this)));
}
+ start_timedout_ = false;
+ start_outcome_reported_ = false;
+ base::UmaHistogramBoolean("Media.VideoCapture.Start", true);
GetVideoCaptureHost()->Start(device_id_, session_id_, params_,
observer_receiver_.BindNewPipeAndPassRemote());
@@ -857,6 +995,9 @@ void VideoCaptureImpl::StartCaptureInternal() {
void VideoCaptureImpl::OnStartTimedout() {
DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
OnLog("VideoCaptureImpl timed out during starting");
+
+ start_timedout_ = true;
+
OnStateChanged(media::mojom::VideoCaptureState::FAILED);
}
@@ -896,6 +1037,15 @@ media::mojom::blink::VideoCaptureHost* VideoCaptureImpl::GetVideoCaptureHost() {
return video_capture_host_.get();
}
+void VideoCaptureImpl::RecordStartOutcomeUMA(VideoCaptureStartOutcome outcome) {
+ // Record the success or failure of starting only the first time we transition
+ // into such a state, not eg when resuming after pausing.
+ if (!start_outcome_reported_) {
+ base::UmaHistogramEnumeration("Media.VideoCapture.StartOutcome", outcome);
+ start_outcome_reported_ = true;
+ }
+}
+
// static
void VideoCaptureImpl::DidFinishConsumingFrame(
BufferFinishedCallback callback_to_io_thread) {
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.h b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
index 16a3dd38fad..de4e6bfadf8 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
+++ b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/thread_annotations.h"
#include "base/threading/thread_checker.h"
#include "media/base/video_frame.h"
#include "media/capture/mojom/video_capture.mojom-blink.h"
@@ -36,6 +37,15 @@ namespace blink {
extern const PLATFORM_EXPORT base::Feature kTimeoutHangingVideoCaptureStarts;
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class VideoCaptureStartOutcome {
+ kStarted = 0,
+ kTimedout = 1,
+ kFailed = 2,
+ kMaxValue = kFailed,
+};
+
// VideoCaptureImpl represents a capture device in renderer process. It provides
// an interface for clients to command the capture (Start, Stop, etc), and
// communicates back to these clients e.g. the capture state or incoming
@@ -96,8 +106,9 @@ class PLATFORM_EXPORT VideoCaptureImpl
void OnNewBuffer(
int32_t buffer_id,
media::mojom::blink::VideoBufferHandlePtr buffer_handle) override;
- void OnBufferReady(int32_t buffer_id,
- media::mojom::blink::VideoFrameInfoPtr info) override;
+ void OnBufferReady(
+ media::mojom::blink::ReadyBufferPtr buffer,
+ Vector<media::mojom::blink::ReadyBufferPtr> scaled_buffers) override;
void OnBufferDestroyed(int32_t buffer_id) override;
void ProcessFeedback(const media::VideoFrameFeedback& feedback);
@@ -111,6 +122,44 @@ class PLATFORM_EXPORT VideoCaptureImpl
struct BufferContext;
+ // Responsible for constructing a media::VideoFrame from a
+ // media::mojom::blink::ReadyBufferPtr. If a gfx::GpuMemoryBuffer is involved,
+ // this requires a round-trip to the media thread.
+ class VideoFrameBufferPreparer {
+ public:
+ VideoFrameBufferPreparer(VideoCaptureImpl& video_capture_impl,
+ media::mojom::blink::ReadyBufferPtr ready_buffer);
+
+ int32_t buffer_id() const;
+ const media::mojom::blink::VideoFrameInfoPtr& frame_info() const;
+ scoped_refptr<media::VideoFrame> frame() const;
+ scoped_refptr<BufferContext> buffer_context() const;
+
+ // If initialization is successful, the video frame is either already bound
+ // or it needs to be bound on the media thread, see IsVideoFrameBound() and
+ // BindVideoFrameOnMediaThread().
+ bool Initialize();
+ bool IsVideoFrameBound() const;
+ // Returns false if the video frame could not be bound because the GPU
+ // context was lost.
+ bool BindVideoFrameOnMediaThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories);
+ // Adds destruction observers and finalizes the color spaces.
+ // Called from OnVideoFrameReady() prior to frame delivery after deciding to
+ // use the media::VideoFrame.
+ void Finalize();
+
+ private:
+ // Set by constructor.
+ VideoCaptureImpl& video_capture_impl_;
+ int32_t buffer_id_;
+ media::mojom::blink::VideoFrameInfoPtr frame_info_;
+ // Set by Initialize().
+ scoped_refptr<BufferContext> buffer_context_;
+ scoped_refptr<media::VideoFrame> frame_;
+ std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
+ };
+
// Contains information about a video capture client, including capture
// parameters callbacks to the client.
struct ClientInfo;
@@ -118,11 +167,21 @@ class PLATFORM_EXPORT VideoCaptureImpl
using BufferFinishedCallback = base::OnceClosure;
- void OnVideoFrameReady(int32_t buffer_id,
- base::TimeTicks reference_time,
- media::mojom::blink::VideoFrameInfoPtr info,
- scoped_refptr<media::VideoFrame> frame,
- scoped_refptr<BufferContext> buffer_context);
+ static void BindVideoFramesOnMediaThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ std::unique_ptr<VideoFrameBufferPreparer> frame_preparer,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>
+ scaled_frame_preparers,
+ base::OnceCallback<
+ void(std::unique_ptr<VideoFrameBufferPreparer>,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>)>
+ on_frame_ready_callback,
+ base::OnceCallback<void()> on_gpu_context_lost);
+ void OnVideoFrameReady(
+ base::TimeTicks reference_time,
+ std::unique_ptr<VideoFrameBufferPreparer> frame_preparer,
+ std::vector<std::unique_ptr<VideoFrameBufferPreparer>>
+ scaled_frame_preparers);
void OnAllClientsFinishedConsumingFrame(
int buffer_id,
@@ -154,6 +213,8 @@ class PLATFORM_EXPORT VideoCaptureImpl
void OnStartTimedout();
+ void RecordStartOutcomeUMA(VideoCaptureStartOutcome outcome);
+
// Callback for when GPU context lost is detected. The method fetches the new
// GPU factories handle on |main_task_runner_| and sets |gpu_factories_| to
// the new handle.
@@ -193,6 +254,8 @@ class PLATFORM_EXPORT VideoCaptureImpl
base::TimeTicks first_frame_ref_time_;
VideoCaptureState state_;
+ bool start_timedout_ = false;
+ bool start_outcome_reported_ = false;
int num_first_frame_logs_ = 0;
diff --git a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
index c7076a10d07..f8c89060a5b 100644
--- a/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
+++ b/chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
@@ -11,6 +11,7 @@
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "media/capture/mojom/video_capture.mojom-blink.h"
@@ -19,11 +20,13 @@
#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/renderer/platform/testing/histogram_tester.h"
#include "third_party/blink/renderer/platform/video_capture/gpu_memory_buffer_test_support.h"
#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
using ::testing::_;
+using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
@@ -120,6 +123,35 @@ class MockMojoVideoCaptureHost : public media::mojom::blink::VideoCaptureHost {
// and on which we set expectations.
class VideoCaptureImplTest : public ::testing::Test {
public:
+ struct BufferDescription {
+ BufferDescription(
+ int buffer_id,
+ gfx::Size size,
+ media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_I420)
+ : buffer_id(buffer_id),
+ size(std::move(size)),
+ pixel_format(pixel_format) {}
+
+ media::mojom::blink::ReadyBufferPtr ToReadyBuffer(
+ const base::TimeTicks now) const {
+ media::mojom::blink::VideoFrameInfoPtr info =
+ media::mojom::blink::VideoFrameInfo::New();
+ media::VideoFrameMetadata metadata;
+ metadata.reference_time = now;
+ info->timestamp = now - base::TimeTicks();
+ info->pixel_format = pixel_format;
+ info->coded_size = size;
+ info->visible_rect = gfx::Rect(size);
+ info->color_space = gfx::ColorSpace();
+ info->metadata = metadata;
+ return media::mojom::blink::ReadyBuffer::New(buffer_id, std::move(info));
+ }
+
+ int buffer_id;
+ gfx::Size size;
+ media::VideoPixelFormat pixel_format;
+ };
+
VideoCaptureImplTest()
: video_capture_impl_(
new VideoCaptureImpl(session_id_,
@@ -144,8 +176,10 @@ class VideoCaptureImplTest : public ::testing::Test {
protected:
// These four mocks are used to create callbacks for the different oeprations.
- MOCK_METHOD2(OnFrameReady,
- void(scoped_refptr<media::VideoFrame>, base::TimeTicks));
+ MOCK_METHOD3(OnFrameReady,
+ void(scoped_refptr<media::VideoFrame>,
+ std::vector<scoped_refptr<media::VideoFrame>>,
+ base::TimeTicks));
MOCK_METHOD1(OnStateUpdate, void(VideoCaptureState));
MOCK_METHOD1(OnDeviceFormatsInUse,
void(const Vector<media::VideoCaptureFormat>&));
@@ -191,23 +225,16 @@ class VideoCaptureImplTest : public ::testing::Test {
}
void SimulateBufferReceived(
- int buffer_id,
- const gfx::Size& size,
- media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_I420) {
- media::mojom::blink::VideoFrameInfoPtr info =
- media::mojom::blink::VideoFrameInfo::New();
-
+ BufferDescription buffer_description,
+ std::vector<BufferDescription> scaled_buffer_descriptions = {}) {
const base::TimeTicks now = base::TimeTicks::Now();
- media::VideoFrameMetadata metadata;
- metadata.reference_time = now;
- info->timestamp = now - base::TimeTicks();
- info->pixel_format = pixel_format;
- info->coded_size = size;
- info->visible_rect = gfx::Rect(size);
- info->color_space = gfx::ColorSpace();
- info->metadata = metadata;
-
- video_capture_impl_->OnBufferReady(buffer_id, std::move(info));
+ Vector<media::mojom::blink::ReadyBufferPtr> scaled_ready_buffers;
+ for (const auto& scaled_buffer_description : scaled_buffer_descriptions) {
+ scaled_ready_buffers.push_back(
+ scaled_buffer_description.ToReadyBuffer(now));
+ }
+ video_capture_impl_->OnBufferReady(buffer_description.ToReadyBuffer(now),
+ std::move(scaled_ready_buffers));
}
void SimulateBufferDestroyed(int buffer_id) {
@@ -245,6 +272,7 @@ class VideoCaptureImplTest : public ::testing::Test {
};
TEST_F(VideoCaptureImplTest, Simple) {
+ base::HistogramTester histogram_tester;
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
@@ -252,6 +280,9 @@ TEST_F(VideoCaptureImplTest, Simple) {
StartCapture(0, params_small_);
StopCapture(0);
+
+ histogram_tester.ExpectUniqueSample("Media.VideoCapture.StartOutcome",
+ VideoCaptureStartOutcome::kStarted, 1);
}
TEST_F(VideoCaptureImplTest, TwoClientsInSequence) {
@@ -336,7 +367,7 @@ TEST_F(VideoCaptureImplTest, BufferReceived) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _));
+ EXPECT_CALL(*this, OnFrameReady(_, _, _));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
@@ -344,8 +375,8 @@ TEST_F(VideoCaptureImplTest, BufferReceived) {
StartCapture(0, params_small_);
SimulateOnBufferCreated(kArbitraryBufferId, region);
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size));
StopCapture(0);
SimulateBufferDestroyed(kArbitraryBufferId);
@@ -363,7 +394,7 @@ TEST_F(VideoCaptureImplTest, BufferReceived_ReadOnlyShmemRegion) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _));
+ EXPECT_CALL(*this, OnFrameReady(_, _, _));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
@@ -371,8 +402,8 @@ TEST_F(VideoCaptureImplTest, BufferReceived_ReadOnlyShmemRegion) {
StartCapture(0, params_small_);
SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size));
StopCapture(0);
SimulateBufferDestroyed(kArbitraryBufferId);
@@ -393,14 +424,15 @@ TEST_F(VideoCaptureImplTest, BufferReceived_GpuMemoryBufferHandle) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _))
- .WillOnce(
- Invoke([&](scoped_refptr<media::VideoFrame> f, base::TimeTicks t) {
- // Hold on a reference to the video frame to emulate that we're
- // actively using the buffer.
- frame = f;
- frame_ready_event.Signal();
- }));
+ EXPECT_CALL(*this, OnFrameReady(_, _, _))
+ .WillOnce(Invoke([&](scoped_refptr<media::VideoFrame> f,
+ std::vector<scoped_refptr<media::VideoFrame>>,
+ base::TimeTicks t) {
+ // Hold on a reference to the video frame to emulate that we're
+ // actively using the buffer.
+ frame = f;
+ frame_ready_event.Signal();
+ }));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
@@ -418,9 +450,9 @@ TEST_F(VideoCaptureImplTest, BufferReceived_GpuMemoryBufferHandle) {
StartCapture(0, params_small_);
SimulateGpuMemoryBufferCreated(kArbitraryBufferId, std::move(gmb_handle));
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size,
- media::PIXEL_FORMAT_NV12);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size,
+ media::PIXEL_FORMAT_NV12));
};
// The second half of the test: Stop capture and destroy the buffer.
@@ -447,6 +479,142 @@ TEST_F(VideoCaptureImplTest, BufferReceived_GpuMemoryBufferHandle) {
EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 0);
}
+TEST_F(VideoCaptureImplTest, ScaledBufferReceived_SoftwareOnly) {
+ const int kLargeBufferId = 11;
+ const int kSmallBufferId = 12;
+
+ const size_t large_frame_size = media::VideoFrame::AllocationSize(
+ media::PIXEL_FORMAT_I420, params_large_.requested_format.frame_size);
+ base::UnsafeSharedMemoryRegion large_region =
+ base::UnsafeSharedMemoryRegion::Create(large_frame_size);
+ ASSERT_TRUE(large_region.IsValid());
+
+ const size_t small_frame_size = media::VideoFrame::AllocationSize(
+ media::PIXEL_FORMAT_I420, params_small_.requested_format.frame_size);
+ base::UnsafeSharedMemoryRegion small_region =
+ base::UnsafeSharedMemoryRegion::Create(small_frame_size);
+ ASSERT_TRUE(small_region.IsValid());
+
+ base::WaitableEvent frame_ready_event;
+ scoped_refptr<media::VideoFrame> ready_frame;
+ std::vector<scoped_refptr<media::VideoFrame>> ready_scaled_frames;
+
+ EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
+ EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
+ EXPECT_CALL(*this, OnFrameReady(_, _, _))
+ .WillOnce(Invoke(
+ [&](scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks timestamp) {
+ ready_frame = frame;
+ ready_scaled_frames = scaled_frames;
+ frame_ready_event.Signal();
+ }));
+ EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_large_));
+ EXPECT_CALL(mock_video_capture_host_, Stop(_));
+ EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kLargeBufferId, _))
+ .Times(0);
+ EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kSmallBufferId, _))
+ .Times(0);
+
+ StartCapture(0, params_large_);
+ SimulateOnBufferCreated(kLargeBufferId, large_region);
+ SimulateOnBufferCreated(kSmallBufferId, small_region);
+ SimulateBufferReceived(
+ BufferDescription(kLargeBufferId,
+ params_large_.requested_format.frame_size),
+ {BufferDescription(kSmallBufferId,
+ params_small_.requested_format.frame_size)});
+ StopCapture(0);
+ SimulateBufferDestroyed(kLargeBufferId);
+ SimulateBufferDestroyed(kSmallBufferId);
+
+ frame_ready_event.Wait();
+ EXPECT_TRUE(ready_frame);
+ EXPECT_EQ(ready_scaled_frames.size(), 1u);
+}
+
+// Any combination of hardware and software frames works, but having the large
+// one be software and the small one be hardware is the most interesting one to
+// test since it would fail if the implementation would assume that the scaled
+// frames have the same type as the original frame.
+TEST_F(VideoCaptureImplTest, ScaledBufferReceived_SoftwareAndHardware) {
+ const int kLargeSoftwareBufferId = 11;
+ const int kSmallHardwareBufferId = 12;
+
+ const size_t large_frame_size = media::VideoFrame::AllocationSize(
+ media::PIXEL_FORMAT_NV12, params_large_.requested_format.frame_size);
+ base::UnsafeSharedMemoryRegion large_region =
+ base::UnsafeSharedMemoryRegion::Create(large_frame_size);
+ ASSERT_TRUE(large_region.IsValid());
+
+ // Buffes are received on IO thread but hardware buffers require a round-trip
+ // to the media thread.
+ base::Thread testing_io_thread("TestingIOThread");
+ base::WaitableEvent frame_ready_event;
+ scoped_refptr<media::VideoFrame> ready_frame;
+ std::vector<scoped_refptr<media::VideoFrame>> ready_scaled_frames;
+
+ EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
+ EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
+ EXPECT_CALL(*this, OnFrameReady(_, _, _))
+ .WillOnce(Invoke(
+ [&](scoped_refptr<media::VideoFrame> frame,
+ std::vector<scoped_refptr<media::VideoFrame>> scaled_frames,
+ base::TimeTicks timestamp) {
+ ready_frame = frame;
+ ready_scaled_frames = scaled_frames;
+ frame_ready_event.Signal();
+ }));
+ EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_large_));
+ EXPECT_CALL(mock_video_capture_host_, Stop(_));
+ EXPECT_CALL(mock_video_capture_host_,
+ ReleaseBuffer(_, kLargeSoftwareBufferId, _))
+ .Times(0);
+ EXPECT_CALL(mock_video_capture_host_,
+ ReleaseBuffer(_, kSmallHardwareBufferId, _))
+ .Times(0);
+
+ auto start_and_receive_buffers = [&]() {
+ gfx::GpuMemoryBufferHandle gmb_handle;
+ gmb_handle.type = gfx::NATIVE_PIXMAP;
+ gmb_handle.id = gfx::GpuMemoryBufferId(kSmallHardwareBufferId);
+ StartCapture(0, params_large_);
+ // Create both buffers.
+ SimulateOnBufferCreated(kLargeSoftwareBufferId, large_region);
+ SimulateGpuMemoryBufferCreated(kSmallHardwareBufferId,
+ std::move(gmb_handle));
+ // Receive buffers.
+ SimulateBufferReceived(
+ BufferDescription(kLargeSoftwareBufferId,
+ params_large_.requested_format.frame_size,
+ media::PIXEL_FORMAT_NV12),
+ {BufferDescription(kSmallHardwareBufferId,
+ params_small_.requested_format.frame_size,
+ media::PIXEL_FORMAT_NV12)});
+ };
+ auto stop_and_destroy_buffers = [&]() {
+ StopCapture(0);
+ SimulateBufferDestroyed(kLargeSoftwareBufferId);
+ SimulateBufferDestroyed(kSmallHardwareBufferId);
+ // Explicitly destroy |video_capture_impl_| to make sure it's destroyed on
+ // the right thread.
+ video_capture_impl_.reset();
+ };
+
+ testing_io_thread.Start();
+ testing_io_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindLambdaForTesting(start_and_receive_buffers));
+
+ frame_ready_event.Wait();
+ EXPECT_TRUE(ready_frame);
+ EXPECT_EQ(ready_scaled_frames.size(), 1u);
+
+ testing_io_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindLambdaForTesting(stop_and_destroy_buffers));
+ testing_io_thread.Stop();
+}
+
TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {
const int kArbitraryBufferId = 12;
@@ -458,7 +626,7 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _)).Times(0);
+ EXPECT_CALL(*this, OnFrameReady(_, _, _)).Times(0);
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_large_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_,
@@ -468,8 +636,8 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {
SimulateOnBufferCreated(kArbitraryBufferId, region);
StopCapture(0);
// A buffer received after StopCapture() triggers an instant ReleaseBuffer().
- SimulateBufferReceived(kArbitraryBufferId,
- params_large_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_large_.requested_format.frame_size));
SimulateBufferDestroyed(kArbitraryBufferId);
EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 1);
@@ -486,7 +654,7 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_ReadOnlyShmemRegion) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _)).Times(0);
+ EXPECT_CALL(*this, OnFrameReady(_, _, _)).Times(0);
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_large_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_,
@@ -496,8 +664,8 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_ReadOnlyShmemRegion) {
SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
StopCapture(0);
// A buffer received after StopCapture() triggers an instant ReleaseBuffer().
- SimulateBufferReceived(kArbitraryBufferId,
- params_large_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_large_.requested_format.frame_size));
SimulateBufferDestroyed(kArbitraryBufferId);
EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 1);
@@ -512,7 +680,7 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_GpuMemoryBufferHandle) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
- EXPECT_CALL(*this, OnFrameReady(_, _)).Times(0);
+ EXPECT_CALL(*this, OnFrameReady(_, _, _)).Times(0);
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_large_));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
EXPECT_CALL(mock_video_capture_host_,
@@ -522,15 +690,17 @@ TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_GpuMemoryBufferHandle) {
SimulateGpuMemoryBufferCreated(kArbitraryBufferId, std::move(gmb_handle));
StopCapture(0);
// A buffer received after StopCapture() triggers an instant ReleaseBuffer().
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size,
- media::PIXEL_FORMAT_NV12);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size,
+ media::PIXEL_FORMAT_NV12));
SimulateBufferDestroyed(kArbitraryBufferId);
EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 1);
}
TEST_F(VideoCaptureImplTest, AlreadyStarted) {
+ base::HistogramTester histogram_tester;
+
media::VideoCaptureParams params = {};
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED))
@@ -548,6 +718,9 @@ TEST_F(VideoCaptureImplTest, AlreadyStarted) {
StopCapture(0);
StopCapture(1);
DCHECK(params.requested_format == params_small_.requested_format);
+
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.Start", 1);
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.StartOutcome", 1);
}
TEST_F(VideoCaptureImplTest, EndedBeforeStop) {
@@ -563,6 +736,8 @@ TEST_F(VideoCaptureImplTest, EndedBeforeStop) {
}
TEST_F(VideoCaptureImplTest, ErrorBeforeStop) {
+ base::HistogramTester histogram_tester;
+
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_ERROR));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
@@ -572,6 +747,11 @@ TEST_F(VideoCaptureImplTest, ErrorBeforeStop) {
OnStateChanged(media::mojom::VideoCaptureState::FAILED);
StopCapture(0);
+
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.Start", 1);
+ // Successful start before the error, so StartOutcome is kStarted.
+ histogram_tester.ExpectUniqueSample("Media.VideoCapture.StartOutcome",
+ VideoCaptureStartOutcome::kStarted, 1);
}
TEST_F(VideoCaptureImplTest, BufferReceivedBeforeOnStarted) {
@@ -590,8 +770,8 @@ TEST_F(VideoCaptureImplTest, BufferReceivedBeforeOnStarted) {
ReleaseBuffer(_, kArbitraryBufferId, _));
StartCapture(0, params_small_);
SimulateOnBufferCreated(kArbitraryBufferId, region);
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
@@ -628,8 +808,8 @@ TEST_F(VideoCaptureImplTest,
ReleaseBuffer(_, kArbitraryBufferId, _));
StartCapture(0, params_small_);
SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
@@ -664,9 +844,9 @@ TEST_F(VideoCaptureImplTest,
ReleaseBuffer(_, kArbitraryBufferId, _));
StartCapture(0, params_small_);
SimulateGpuMemoryBufferCreated(kArbitraryBufferId, std::move(gmb_handle));
- SimulateBufferReceived(kArbitraryBufferId,
- params_small_.requested_format.frame_size,
- media::PIXEL_FORMAT_NV12);
+ SimulateBufferReceived(BufferDescription(
+ kArbitraryBufferId, params_small_.requested_format.frame_size,
+ media::PIXEL_FORMAT_NV12));
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
@@ -687,6 +867,8 @@ TEST_F(VideoCaptureImplTest,
}
TEST_F(VideoCaptureImplTest, StartTimeout) {
+ base::HistogramTester histogram_tester;
+
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_ERROR));
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
@@ -697,9 +879,14 @@ TEST_F(VideoCaptureImplTest, StartTimeout) {
StartCapture(0, params_small_);
task_environment_.FastForwardBy(VideoCaptureImpl::kCaptureStartTimeout);
+
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.Start", 1);
+ histogram_tester.ExpectUniqueSample("Media.VideoCapture.StartOutcome",
+ VideoCaptureStartOutcome::kTimedout, 1);
}
TEST_F(VideoCaptureImplTest, StartTimeout_FeatureDisabled) {
+ base::HistogramTester histogram_tester;
feature_list_.InitAndDisableFeature(kTimeoutHangingVideoCaptureStarts);
EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
@@ -719,6 +906,29 @@ TEST_F(VideoCaptureImplTest, StartTimeout_FeatureDisabled) {
EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
EXPECT_CALL(mock_video_capture_host_, Stop(_));
StopCapture(0);
+
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.Start", 1);
+ histogram_tester.ExpectUniqueSample("Media.VideoCapture.StartOutcome",
+ VideoCaptureStartOutcome::kStarted, 1);
+}
+
+TEST_F(VideoCaptureImplTest, ErrorBeforeStart) {
+ base::HistogramTester histogram_tester;
+
+ EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_ERROR));
+ EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
+ ON_CALL(mock_video_capture_host_, DoStart(_, _, _))
+ .WillByDefault(InvokeWithoutArgs([this]() {
+ // Go straight to Failed. Do not pass Go. Do not collect £200.
+ video_capture_impl_->OnStateChanged(
+ media::mojom::VideoCaptureState::FAILED);
+ }));
+
+ StartCapture(0, params_small_);
+
+ histogram_tester.ExpectTotalCount("Media.VideoCapture.Start", 1);
+ histogram_tester.ExpectUniqueSample("Media.VideoCapture.StartOutcome",
+ VideoCaptureStartOutcome::kFailed, 1);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/DIR_METADATA b/chromium/third_party/blink/renderer/platform/weborigin/DIR_METADATA
new file mode 100644
index 00000000000..1d65edbd311
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/weborigin/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>SecurityFeature"
+}
+team_email: "platform-architecture-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/OWNERS b/chromium/third_party/blink/renderer/platform/weborigin/OWNERS
index 719f4fcb268..c761b3f02aa 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/weborigin/OWNERS
@@ -1,6 +1,3 @@
tsepez@chromium.org
per-file origin_access_entry.*=toyoshim@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>SecurityFeature
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc b/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
index 154e4e18946..978ad7c400f 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl.cc
@@ -29,6 +29,8 @@
#include <algorithm>
+#include "base/i18n/uchar.h"
+#include "base/numerics/checked_math.h"
#include "third_party/blink/renderer/platform/weborigin/known_ports.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -38,6 +40,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
#include "url/gurl.h"
#include "url/url_util.h"
#ifndef NDEBUG
@@ -102,8 +105,9 @@ class KURLCharsetConverter final : public url::CharsetConverter {
void ConvertFromUTF16(const base::char16* input,
int input_length,
url::CanonOutput* output) override {
- std::string encoded = encoding_->Encode(
- String(input, input_length), WTF::kURLEncodedEntitiesForUnencodables);
+ std::string encoded =
+ encoding_->Encode(String(base::i18n::ToUCharPtr(input), input_length),
+ WTF::kURLEncodedEntitiesForUnencodables);
output->Append(encoded.c_str(), static_cast<int>(encoded.length()));
}
@@ -174,10 +178,6 @@ const KURL& BlankURL() {
return blank_url;
}
-bool KURL::IsAboutBlankURL() const {
- return *this == BlankURL();
-}
-
const KURL& SrcdocURL() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<KURL>, static_srcdoc_url, ());
KURL& srcdoc_url = *static_srcdoc_url;
@@ -186,8 +186,29 @@ const KURL& SrcdocURL() {
return srcdoc_url;
}
+bool KURL::IsAboutURL(const char* allowed_path) const {
+ if (!ProtocolIsAbout())
+ return false;
+
+ // Using `is_nonempty` for `host` and `is_valid` for `username` and `password`
+ // to replicate how GURL::IsAboutURL (and GURL::has_host vs
+ // GURL::has_username) works.
+ if (parsed_.host.is_nonempty() || parsed_.username.is_valid() ||
+ parsed_.password.is_valid() || HasPort()) {
+ return false;
+ }
+
+ String path = GetPath();
+ StringUTF8Adaptor path_utf8(path);
+ return GURL::IsAboutPath(path_utf8.AsStringPiece(), allowed_path);
+}
+
+bool KURL::IsAboutBlankURL() const {
+ return IsAboutURL(url::kAboutBlankPath);
+}
+
bool KURL::IsAboutSrcdocURL() const {
- return *this == SrcdocURL();
+ return IsAboutURL(url::kAboutSrcdocPath);
}
const KURL& NullURL() {
@@ -338,10 +359,12 @@ String KURL::LastPathComponent() const {
path.len--;
url::Component file;
- if (string_.Is8Bit())
+ if (string_.Is8Bit()) {
url::ExtractFileName(AsURLChar8Subtle(string_), path, &file);
- else
- url::ExtractFileName(string_.Characters16(), path, &file);
+ } else {
+ url::ExtractFileName(base::i18n::ToChar16Ptr(string_.Characters16()), path,
+ &file);
+ }
// Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns
// a null string when the path is empty, which we duplicate here.
@@ -363,9 +386,11 @@ uint16_t KURL::Port() const {
if (!is_valid_ || parsed_.port.len <= 0)
return 0;
DCHECK(!string_.IsNull());
- int port = string_.Is8Bit()
- ? url::ParsePort(AsURLChar8Subtle(string_), parsed_.port)
- : url::ParsePort(string_.Characters16(), parsed_.port);
+ int port =
+ string_.Is8Bit()
+ ? url::ParsePort(AsURLChar8Subtle(string_), parsed_.port)
+ : url::ParsePort(base::i18n::ToChar16Ptr(string_.Characters16()),
+ parsed_.port);
DCHECK_NE(port, url::PORT_UNSPECIFIED); // Checked port.len <= 0 already.
DCHECK_NE(port, url::PORT_INVALID); // Checked is_valid_ already.
@@ -439,6 +464,44 @@ bool KURL::SetProtocol(const String& protocol) {
!protocol_component.is_nonempty())
return false;
+ DCHECK_EQ(protocol_component.begin, 0);
+ const size_t protocol_length =
+ base::checked_cast<size_t>(protocol_component.len);
+ const String new_protocol_canon =
+ String(canon_protocol.data(), protocol_length);
+
+ // We don't currently perform the check from
+ // https://url.spec.whatwg.org/#scheme-state that special schemes are not
+ // converted to non-special schemes and vice-versa, but the following logic
+ // should only be applied to special schemes.
+ // TODO(ricea): Maybe disallow switching between special and non-special
+ // schemes, to match the standard, if we can develop confidence that it won't
+ // break pages.
+ if (SchemeRegistry::IsSpecialScheme(Protocol()) &&
+ SchemeRegistry::IsSpecialScheme(new_protocol_canon)) {
+ // The protocol is lower-cased during canonicalization.
+ const bool new_protocol_is_file = new_protocol_canon == "file";
+ const bool old_protocol_is_file = ProtocolIs("file");
+
+ // https://url.spec.whatwg.org/#scheme-state
+ // 3. If url includes credentials or has a non-null port, and buffer is
+ // "file", then return.
+ if (new_protocol_is_file && !old_protocol_is_file &&
+ (HasPort() || parsed_.username.len > 0 || parsed_.password.len > 0)) {
+ // This fails silently, which is weird, but necessary to give the expected
+ // behaviour when setting location.protocol. See
+ // https://html.spec.whatwg.org/multipage/history.html#dom-location-protocol.
+ return true;
+ }
+
+ // 4. If url’s scheme is "file" and its host is an empty host, then return.
+ if (!new_protocol_is_file && old_protocol_is_file &&
+ parsed_.host.len <= 0) {
+ // This fails silently as above.
+ return true;
+ }
+ }
+
url::Replacements<char> replacements;
replacements.SetScheme(CharactersOrEmpty(new_protocol_utf8),
url::Component(0, new_protocol_utf8.size()));
@@ -666,7 +729,8 @@ bool KURL::IsHierarchical() const {
return false;
return string_.Is8Bit()
? url::IsStandard(AsURLChar8Subtle(string_), parsed_.scheme)
- : url::IsStandard(string_.Characters16(), parsed_.scheme);
+ : url::IsStandard(base::i18n::ToChar16Ptr(string_.Characters16()),
+ parsed_.scheme);
}
bool EqualIgnoringFragmentIdentifier(const KURL& a, const KURL& b) {
@@ -716,10 +780,12 @@ unsigned KURL::PathAfterLastSlash() const {
if (!is_valid_ || !parsed_.path.is_valid())
return parsed_.CountCharactersBefore(url::Parsed::PATH, false);
url::Component filename;
- if (string_.Is8Bit())
+ if (string_.Is8Bit()) {
url::ExtractFileName(AsURLChar8Subtle(string_), parsed_.path, &filename);
- else
- url::ExtractFileName(string_.Characters16(), parsed_.path, &filename);
+ } else {
+ url::ExtractFileName(base::i18n::ToChar16Ptr(string_.Characters16()),
+ parsed_.path, &filename);
+ }
return filename.begin;
}
@@ -733,8 +799,8 @@ bool ProtocolIs(const String& url, const char* protocol) {
return url::FindAndCompareScheme(AsURLChar8Subtle(url), url.length(),
protocol, nullptr);
}
- return url::FindAndCompareScheme(url.Characters16(), url.length(), protocol,
- nullptr);
+ return url::FindAndCompareScheme(base::i18n::ToChar16Ptr(url.Characters16()),
+ url.length(), protocol, nullptr);
}
void KURL::Init(const KURL& base,
@@ -765,10 +831,10 @@ void KURL::Init(const KURL& base,
clampTo<int>(relative_utf8.size()),
charset_converter, &output, &parsed_);
} else {
- is_valid_ = url::ResolveRelative(base_utf8.data(), base_utf8.size(),
- base.parsed_, relative.Characters16(),
- clampTo<int>(relative.length()),
- charset_converter, &output, &parsed_);
+ is_valid_ = url::ResolveRelative(
+ base_utf8.data(), base_utf8.size(), base.parsed_,
+ base::i18n::ToChar16Ptr(relative.Characters16()),
+ clampTo<int>(relative.length()), charset_converter, &output, &parsed_);
}
// AtomicString::fromUTF8 will re-hash the raw output and check the
@@ -887,6 +953,10 @@ bool KURL::IsSafeToSendToAnotherThread() const {
(!inner_url_ || inner_url_->IsSafeToSendToAnotherThread());
}
+void KURL::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ return perfetto::WriteIntoTracedValue(std::move(context), GetString());
+}
+
KURL::operator GURL() const {
StringUTF8Adaptor utf8(string_);
return GURL(utf8.data(), utf8.size(), parsed_, is_valid_);
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl.h b/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
index 4e944bc2c4b..c7575637d57 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl.h
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_canon.h"
#include "url/url_util.h"
@@ -238,6 +239,8 @@ class PLATFORM_EXPORT KURL {
// TODO(crbug.com/862940): Make this conversion explicit.
operator GURL() const;
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
private:
friend struct WTF::HashTraits<blink::KURL>;
@@ -245,6 +248,8 @@ class PLATFORM_EXPORT KURL {
const String& relative,
const WTF::TextEncoding* query_encoding);
+ bool IsAboutURL(const char* allowed_path) const;
+
StringView ComponentStringView(const url::Component&) const;
String ComponentString(const url::Component&) const;
StringView StringViewForInvalidComponent() const;
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc b/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
index 1fa4f3c22be..56be0c870fc 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/kurl_test.cc
@@ -41,6 +41,8 @@
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "url/gurl.h"
+#include "url/gurl_abstract_tests.h"
#include "url/url_util.h"
namespace blink {
@@ -772,10 +774,12 @@ TEST(KURLTest, DeepCopyInnerURL) {
TEST(KURLTest, LastPathComponent) {
const KURL url1("http://host/path/to/file.txt");
+ EXPECT_TRUE(url1.IsValid());
EXPECT_EQ("file.txt", url1.LastPathComponent());
const KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
- EXPECT_EQ(String(), invalid_utf8.LastPathComponent());
+ EXPECT_FALSE(invalid_utf8.IsValid());
+ EXPECT_EQ("", invalid_utf8.LastPathComponent());
}
TEST(KURLTest, IsHierarchical) {
@@ -784,6 +788,7 @@ TEST(KURLTest, IsHierarchical) {
// url never has a valid hostname (the inner URL does)."
const char* standard_urls[] = {
"http://host/path/to/file.txt",
+ "http://a@9%aa%:/path/to/file.txt", // Invalid, but hierarchical.
"ftp://andrew.cmu.edu/foo",
"file:///path/to/resource",
"file://hostname/etc/",
@@ -802,7 +807,6 @@ TEST(KURLTest, IsHierarchical) {
const char* nonstandard_urls[] = {
"blob:null/guid-goes-here",
"blob:http://example.com/guid-goes-here",
- "http://a@9%aa%:/path/to/file.txt",
"about:blank://hostname",
"about:blank",
"javascript:void(0);",
@@ -823,7 +827,7 @@ TEST(KURLTest, PathAfterLastSlash) {
EXPECT_EQ(20u, url1.PathAfterLastSlash());
KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
- EXPECT_EQ(0u, invalid_utf8.PathAfterLastSlash());
+ EXPECT_EQ(22u, invalid_utf8.PathAfterLastSlash());
}
TEST(KURLTest, ProtocolIsInHTTPFamily) {
@@ -948,6 +952,141 @@ TEST(KURLTest, ThreadSafesStaticKurlGetters) {
#endif
}
+// Setting protocol to "file" should not work if the URL has credentials or a
+// port.
+TEST(KURLTest, FailToSetProtocolToFile) {
+ constexpr const char* kShouldNotChange[] = {
+ "http://foo@localhost/",
+ "http://:bar@localhost/",
+ "http://localhost:8000/",
+ };
+
+ for (const char* url_string : kShouldNotChange) {
+ KURL url(url_string);
+ auto port_before = url.Port();
+ auto user_before = url.User();
+ auto pass_before = url.Pass();
+ EXPECT_TRUE(url.SetProtocol("file")) << "with url " << url_string;
+ EXPECT_EQ(url.Protocol(), "http") << "with url " << url_string;
+
+ EXPECT_EQ(url.Port(), port_before) << "with url " << url_string;
+ EXPECT_EQ(url.User(), user_before) << "with url " << url_string;
+ EXPECT_EQ(url.Pass(), pass_before) << "with url " << url_string;
+ }
+}
+
+// If the source URL is invalid, then it behaves like it has an empty
+// protocol, so the conversion to a file URL can go ahead.
+TEST(KURL, SetProtocolToFileFromInvalidURL) {
+ enum ValidAfterwards {
+ kValid,
+ kInvalid,
+ };
+ struct URLAndExpectedValidity {
+ const char* const url;
+ const ValidAfterwards validity;
+ };
+
+ // The URLs are reparsed when the protocol is changed, and most of
+ // them are converted to a form which is valid. The second argument
+ // reflects the validity after the transformation. All the URLs are
+ // invalid before it.
+ constexpr URLAndExpectedValidity kInvalidURLs[] = {
+ {"http://@/", kValid}, {"http://@@/", kValid},
+ {"http://::/", kInvalid}, {"http://:/", kValid},
+ {"http://:@/", kValid}, {"http://@:/", kValid},
+ {"http://:@:/", kValid}, {"http://foo@/", kValid},
+ {"http://localhost:/", kValid},
+ };
+
+ for (const auto& invalid_url : kInvalidURLs) {
+ KURL url(invalid_url.url);
+
+ EXPECT_TRUE(url.SetProtocol("file")) << "with url " << invalid_url.url;
+
+ EXPECT_EQ(url.Protocol(), invalid_url.validity == kValid ? "file" : "")
+ << "with url " << invalid_url.url;
+
+ EXPECT_EQ(url.IsValid() ? kValid : kInvalid, invalid_url.validity)
+ << "with url " << invalid_url.url;
+ }
+}
+
+TEST(KURLTest, SetProtocolToFromFile) {
+ struct Case {
+ const char* const url;
+ const char* const new_protocol;
+ };
+ constexpr Case kCases[] = {
+ {"http://localhost/path", "file"},
+ {"file://example.com/path", "http"},
+ };
+
+ for (const auto& test_case : kCases) {
+ KURL url(test_case.url);
+ EXPECT_TRUE(url.SetProtocol(test_case.new_protocol));
+ EXPECT_EQ(url.Protocol(), test_case.new_protocol);
+
+ EXPECT_EQ(url.GetPath(), "/path");
+ }
+}
+
+TEST(KURLTest, FailToSetProtocolFromFile) {
+ KURL url("file:///path");
+ EXPECT_TRUE(url.SetProtocol("http"));
+ EXPECT_EQ(url.Protocol(), "file");
+
+ EXPECT_EQ(url.GetPath(), "/path");
+}
+
+// According to the URL standard https://url.spec.whatwg.org/#scheme-state
+// switching between special and non-special schemes shouldn't work, but for now
+// we are retaining it for backwards-compatibility.
+// TODO(ricea): Change these tests if we change the behaviour.
+TEST(KURLTest, SetFileProtocolFromNonSpecial) {
+ KURL url("non-special-scheme://foo:bar@example.com:8000/path");
+ EXPECT_TRUE(url.SetProtocol("file"));
+
+ // The URL is now invalid, so the protocol is empty. This is different from
+ // what happens in the case with special schemes.
+ EXPECT_EQ(url.Protocol(), "");
+ EXPECT_EQ(url.User(), "");
+ EXPECT_TRUE(url.Pass().IsNull());
+ EXPECT_EQ(url.Host(), "");
+ EXPECT_EQ(url.Port(), 0);
+ EXPECT_EQ(url.GetPath(), "");
+}
+
+TEST(KURLTest, SetFileProtocolToNonSpecial) {
+ KURL url("file:///path");
+ EXPECT_TRUE(url.SetProtocol("non-special-scheme"));
+ EXPECT_EQ(url.Protocol(), "non-special-scheme");
+ EXPECT_EQ(url.GetPath(), "///path");
+}
+
+TEST(KURLTest, InvalidKURLToGURL) {
+ // This contains an invalid percent escape (%T%) and also a valid
+ // percent escape that's not 7-bit ascii (%ae), so that the unescaped
+ // host contains both an invalid percent escape and invalid UTF-8.
+ KURL kurl("http://%T%Ae");
+ EXPECT_FALSE(kurl.IsValid());
+
+ // KURL returns empty strings for components on invalid urls.
+ EXPECT_EQ(kurl.Protocol(), "");
+ EXPECT_EQ(kurl.Host(), "");
+
+ // This passes the original internal url to GURL, check that it arrives
+ // in an internally self-consistent state.
+ GURL gurl = kurl;
+ EXPECT_FALSE(gurl.is_valid());
+ EXPECT_TRUE(gurl.SchemeIs(url::kHttpScheme));
+
+ // GURL exposes host for invalid hosts. The invalid percent escape
+ // becomes an escaped percent sign (%25), and the invalid UTF-8
+ // character becomes REPLACEMENT CHARACTER' (U+FFFD) encoded as UTF-8.
+ EXPECT_EQ(gurl.host_piece(), "%25t%EF%BF%BD");
+}
+
enum class PortIsValid {
// The constructor does strict checking. Ports which are considered valid by
// the constructor are kAlways valid.
@@ -1067,3 +1206,29 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(port_test_cases));
} // namespace blink
+
+// Apparently INSTANTIATE_TYPED_TEST_SUITE_P needs to be used in the same
+// namespace as where the typed test suite was defined.
+namespace url {
+
+class KURLTestTraits {
+ public:
+ using UrlType = blink::KURL;
+
+ static UrlType CreateUrlFromString(base::StringPiece s) {
+ return blink::KURL(String::FromUTF8(s));
+ }
+
+ static bool IsAboutBlank(const UrlType& url) { return url.IsAboutBlankURL(); }
+
+ static bool IsAboutSrcdoc(const UrlType& url) {
+ return url.IsAboutSrcdocURL();
+ }
+
+ // Only static members.
+ KURLTestTraits() = delete;
+};
+
+INSTANTIATE_TYPED_TEST_SUITE_P(KURL, AbstractUrlTest, KURLTestTraits);
+
+} // namespace url
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc b/chromium/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
index c9d777e7160..bafe05719c8 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/origin_access_entry.cc
@@ -43,7 +43,7 @@ OriginAccessEntry::OriginAccessEntry(
network::mojom::CorsOriginAccessMatchPriority priority)
: private_(origin.Protocol().Ascii(),
origin.Domain().Ascii(),
- origin.EffectivePort(),
+ origin.Port(),
match_mode,
network::mojom::CorsPortMatchMode::kAllowOnlySpecifiedPort,
priority) {}
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.cc b/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
index 66634ce43ef..473b91706d9 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
@@ -69,12 +69,6 @@ class URLSchemesRegistry final {
service_worker_schemes({"http", "https"}),
fetch_api_schemes({"http", "https"}),
allowed_in_referrer_schemes({"http", "https"}) {
- for (auto& scheme : url::GetLocalSchemes())
- local_schemes.insert(scheme.c_str());
- for (auto& scheme : url::GetSecureSchemes())
- secure_schemes.insert(scheme.c_str());
- for (auto& scheme : url::GetNoAccessSchemes())
- schemes_with_unique_origins.insert(scheme.c_str());
for (auto& scheme : url::GetCorsEnabledSchemes())
cors_enabled_schemes.insert(scheme.c_str());
for (auto& scheme : url::GetCSPBypassingSchemes()) {
@@ -86,10 +80,15 @@ class URLSchemesRegistry final {
}
~URLSchemesRegistry() = default;
- URLSchemesSet local_schemes;
+ // As URLSchemesRegistry is accessed from multiple threads, be very careful to
+ // ensure that
+ // - URLSchemesRegistry is initialized/modified through
+ // GetMutableURLSchemesRegistry() before threads can be created, and
+ // - The URLSchemesRegistry members below aren't modified when accessed after
+ // initialization.
+ // Particularly, Strings inside them shouldn't be copied, as it modifies
+ // reference counts of StringImpls (IsolatedCopy() should be taken instead).
URLSchemesSet display_isolated_url_schemes;
- URLSchemesSet secure_schemes;
- URLSchemesSet schemes_with_unique_origins;
URLSchemesSet empty_document_schemes;
URLSchemesSet schemes_forbidden_from_domain_relaxation;
URLSchemesSet not_allowing_javascript_urls_schemes;
@@ -102,6 +101,7 @@ class URLSchemesRegistry final {
content_security_policy_bypassing_schemes;
URLSchemesSet secure_context_bypassing_schemes;
URLSchemesSet allowed_in_referrer_schemes;
+ URLSchemesSet error_schemes;
URLSchemesSet wasm_eval_csp_schemes;
private:
@@ -127,25 +127,6 @@ URLSchemesRegistry& GetMutableURLSchemesRegistry() {
} // namespace
-void SchemeRegistry::RegisterURLSchemeAsLocal(const String& scheme) {
- DCHECK_EQ(scheme, scheme.LowerASCII());
- GetMutableURLSchemesRegistry().local_schemes.insert(scheme);
-}
-
-bool SchemeRegistry::ShouldTreatURLSchemeAsLocal(const String& scheme) {
- DCHECK_EQ(scheme, scheme.LowerASCII());
- if (scheme.IsEmpty())
- return false;
- return GetURLSchemesRegistry().local_schemes.Contains(scheme);
-}
-
-bool SchemeRegistry::ShouldTreatURLSchemeAsNoAccess(const String& scheme) {
- DCHECK_EQ(scheme, scheme.LowerASCII());
- if (scheme.IsEmpty())
- return false;
- return GetURLSchemesRegistry().schemes_with_unique_origins.Contains(scheme);
-}
-
void SchemeRegistry::RegisterURLSchemeAsDisplayIsolated(const String& scheme) {
DCHECK_EQ(scheme, scheme.LowerASCII());
GetMutableURLSchemesRegistry().display_isolated_url_schemes.insert(scheme);
@@ -165,18 +146,6 @@ bool SchemeRegistry::ShouldTreatURLSchemeAsRestrictingMixedContent(
return scheme == "https";
}
-void SchemeRegistry::RegisterURLSchemeAsSecure(const String& scheme) {
- DCHECK_EQ(scheme, scheme.LowerASCII());
- GetMutableURLSchemesRegistry().secure_schemes.insert(scheme);
-}
-
-bool SchemeRegistry::ShouldTreatURLSchemeAsSecure(const String& scheme) {
- DCHECK_EQ(scheme, scheme.LowerASCII());
- if (scheme.IsEmpty())
- return false;
- return GetURLSchemesRegistry().secure_schemes.Contains(scheme);
-}
-
bool SchemeRegistry::ShouldLoadURLSchemeAsEmptyDocument(const String& scheme) {
DCHECK_EQ(scheme, scheme.LowerASCII());
if (scheme.IsEmpty())
@@ -257,7 +226,10 @@ String SchemeRegistry::ListOfCorsEnabledURLSchemes() {
else
add_separator = true;
- builder.Append(scheme);
+ // As |cors_enabled_schemes| can be accessed from multiple threads, we need
+ // IsolatedCopy() here before passing it to |StringBuilder| that can
+ // ref/deref Strings.
+ builder.Append(scheme.IsolatedCopy());
}
return builder.ToString();
}
@@ -310,14 +282,11 @@ bool SchemeRegistry::ShouldTreatURLSchemeAsSupportingFetchAPI(
return GetURLSchemesRegistry().fetch_api_schemes.Contains(scheme);
}
-// https://fetch.spec.whatwg.org/#fetch-scheme
-bool SchemeRegistry::IsFetchScheme(const String& scheme) {
+// https://url.spec.whatwg.org/#special-scheme
+bool SchemeRegistry::IsSpecialScheme(const String& scheme) {
DCHECK_EQ(scheme, scheme.LowerASCII());
- // "A fetch scheme is a scheme that is "about", "blob", "data", "file",
- // "filesystem", or a network scheme." [spec text]
- return scheme == "about" || scheme == "blob" || scheme == "data" ||
- scheme == "file" || scheme == "filesystem" || scheme == "ftp" ||
- scheme == "http" || scheme == "https";
+ return scheme == "ftp" || scheme == "file" || scheme == "http" ||
+ scheme == "https" || scheme == "ws" || scheme == "wss";
}
void SchemeRegistry::RegisterURLSchemeAsFirstPartyWhenTopLevel(
@@ -385,6 +354,18 @@ bool SchemeRegistry::ShouldTreatURLSchemeAsAllowedForReferrer(
return GetURLSchemesRegistry().allowed_in_referrer_schemes.Contains(scheme);
}
+void SchemeRegistry::RegisterURLSchemeAsError(const String& scheme) {
+ DCHECK_EQ(scheme, scheme.LowerASCII());
+ GetMutableURLSchemesRegistry().error_schemes.insert(scheme);
+}
+
+bool SchemeRegistry::ShouldTreatURLSchemeAsError(const String& scheme) {
+ DCHECK_EQ(scheme, scheme.LowerASCII());
+ if (scheme.IsEmpty())
+ return false;
+ return GetURLSchemesRegistry().error_schemes.Contains(scheme);
+}
+
void SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
const String& scheme,
PolicyAreas policy_areas) {
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.h b/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.h
index be4da093715..279f0b0629b 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.h
+++ b/chromium/third_party/blink/renderer/platform/weborigin/scheme_registry.h
@@ -49,19 +49,8 @@ class PLATFORM_EXPORT SchemeRegistry {
STATIC_ONLY(SchemeRegistry);
public:
- static void RegisterURLSchemeAsLocal(const String&);
- static bool ShouldTreatURLSchemeAsLocal(const String&);
-
static bool ShouldTreatURLSchemeAsRestrictingMixedContent(const String&);
- // Subresources transported by secure schemes do not trigger mixed content
- // warnings. For example, https and data are secure schemes because they
- // cannot be corrupted by active network attackers.
- static void RegisterURLSchemeAsSecure(const String&);
- static bool ShouldTreatURLSchemeAsSecure(const String&);
-
- static bool ShouldTreatURLSchemeAsNoAccess(const String&);
-
// Display-isolated schemes can only be displayed (in the sense of
// SecurityOrigin::canDisplay) by documents from the same scheme.
static void RegisterURLSchemeAsDisplayIsolated(const String&);
@@ -107,8 +96,8 @@ class PLATFORM_EXPORT SchemeRegistry {
static void RegisterURLSchemeAsSupportingFetchAPI(const String& scheme);
static bool ShouldTreatURLSchemeAsSupportingFetchAPI(const String& scheme);
- // https://fetch.spec.whatwg.org/#fetch-scheme
- static bool IsFetchScheme(const String& scheme);
+ // https://url.spec.whatwg.org/#special-scheme
+ static bool IsSpecialScheme(const String& scheme);
// Schemes which override the first-/third-party checks on a Document.
static void RegisterURLSchemeAsFirstPartyWhenTopLevel(const String& scheme);
@@ -129,6 +118,10 @@ class PLATFORM_EXPORT SchemeRegistry {
static void RemoveURLSchemeAsAllowedForReferrer(const String& scheme);
static bool ShouldTreatURLSchemeAsAllowedForReferrer(const String& scheme);
+ // Schemes used for internal error pages, for failed navigations.
+ static void RegisterURLSchemeAsError(const String&);
+ static bool ShouldTreatURLSchemeAsError(const String& scheme);
+
// Allow resources from some schemes to load on a page, regardless of its
// Content Security Policy.
enum PolicyAreas : uint32_t {
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
index 6aca0e2c3ad..c705e272c99 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -34,7 +34,9 @@
#include <string>
#include <utility>
+#include "base/i18n/uchar.h"
#include "net/base/url_util.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/blink/renderer/platform/blob/blob_url.h"
#include "third_party/blink/renderer/platform/blob/blob_url_null_origin_map.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -86,6 +88,10 @@ KURL SecurityOrigin::ExtractInnerURL(const KURL& url) {
return KURL(url.GetPath());
}
+// Note: When changing ShouldTreatAsOpaqueOrigin, consider also updating
+// IsValidInput in //url/scheme_host_port.cc (there might be existing
+// differences in behavior between these 2 layers, but we should avoid
+// introducing new differences).
static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
if (!url.IsValid())
return true;
@@ -109,7 +115,8 @@ static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
relevant_url.ProtocolIs("ftp")) &&
relevant_url.Host().IsEmpty()));
- if (SchemeRegistry::ShouldTreatURLSchemeAsNoAccess(relevant_url.Protocol()))
+ if (base::Contains(url::GetNoAccessSchemes(),
+ relevant_url.Protocol().Ascii()))
return true;
// Nonstandard schemes and unregistered schemes aren't known to contain hosts
@@ -118,7 +125,7 @@ static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
// A temporary exception is made for non-standard local schemes.
// TODO: Migrate "content:" and "externalfile:" to be standard schemes, and
// remove the local scheme exception.
- if (SchemeRegistry::ShouldTreatURLSchemeAsLocal(relevant_url.Protocol()))
+ if (base::Contains(url::GetLocalSchemes(), relevant_url.Protocol().Ascii()))
return false;
// Otherwise, treat non-standard origins as opaque, unless the Android
@@ -133,29 +140,25 @@ static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
}
SecurityOrigin::SecurityOrigin(const KURL& url)
- : protocol_(EnsureNonNull(url.Protocol())),
- host_(EnsureNonNull(url.Host())),
- domain_(host_),
- port_(IsDefaultPortForProtocol(url.Port(), protocol_) ? kInvalidPort
- : url.Port()),
- effective_port_(port_ ? port_ : DefaultPortForProtocol(protocol_)) {
- DCHECK(!ShouldTreatAsOpaqueOrigin(url));
- // By default, only local SecurityOrigins can load local resources.
- can_load_local_resources_ = IsLocal();
-}
+ : SecurityOrigin(
+ EnsureNonNull(url.Protocol()),
+ EnsureNonNull(url.Host()),
+ // This mimics the logic in url::SchemeHostPort(const GURL&). In
+ // particular, it ensures a URL with a port of 0 will translate into
+ // an origin with an effective port of 0.
+ (url.HasPort() || !url.IsValid() || !url.IsHierarchical())
+ ? url.Port()
+ : DefaultPortForProtocol(url.Protocol())) {}
SecurityOrigin::SecurityOrigin(const String& protocol,
const String& host,
uint16_t port)
- : protocol_(protocol),
- host_(host),
- domain_(host_),
- port_(IsDefaultPortForProtocol(port, protocol_) ? kInvalidPort : port),
- effective_port_(port_ ? port_ : DefaultPortForProtocol(protocol_)) {
+ : protocol_(protocol), host_(host), domain_(host_), port_(port) {
DCHECK(url::SchemeHostPort(protocol.Utf8(), host.Utf8(), port,
url::SchemeHostPort::CHECK_CANONICALIZATION)
.IsValid());
DCHECK(!IsOpaque());
+ // By default, only local SecurityOrigins can load local resources.
can_load_local_resources_ = IsLocal();
}
@@ -169,7 +172,6 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other,
host_(other->host_.IsolatedCopy()),
domain_(other->domain_.IsolatedCopy()),
port_(other->port_),
- effective_port_(other->effective_port_),
nonce_if_opaque_(other->nonce_if_opaque_),
universal_access_(other->universal_access_),
domain_was_set_in_dom_(other->domain_was_set_in_dom_),
@@ -190,7 +192,6 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other,
host_(other->host_),
domain_(other->domain_),
port_(other->port_),
- effective_port_(other->effective_port_),
nonce_if_opaque_(other->nonce_if_opaque_),
universal_access_(other->universal_access_),
domain_was_set_in_dom_(other->domain_was_set_in_dom_),
@@ -212,6 +213,12 @@ scoped_refptr<SecurityOrigin> SecurityOrigin::CreateWithReferenceOrigin(
return origin;
}
+ if (url.IsAboutBlankURL()) {
+ if (!reference_origin)
+ return CreateUniqueOpaque();
+ return reference_origin->IsolatedCopy();
+ }
+
if (ShouldTreatAsOpaqueOrigin(url)) {
if (!reference_origin)
return CreateUniqueOpaque();
@@ -272,7 +279,7 @@ url::Origin SecurityOrigin::ToUrlOrigin() const {
const SecurityOrigin* unmasked = GetOriginOrPrecursorOriginIfOpaque();
std::string scheme = unmasked->protocol_.Utf8();
std::string host = unmasked->host_.Utf8();
- uint16_t port = unmasked->effective_port_;
+ uint16_t port = unmasked->port_;
if (nonce_if_opaque_) {
url::Origin result = url::Origin::CreateOpaqueFromNormalizedPrecursorTuple(
std::move(scheme), std::move(host), port, *nonce_if_opaque_);
@@ -305,18 +312,60 @@ String SecurityOrigin::RegistrableDomain() const {
return domain.IsEmpty() ? String() : domain;
}
+// TODO(crbug.com/1153336): Remove this method and make existing call sites rely
+// on network::IsUrlPotentiallyTrustworthy() instead.
bool SecurityOrigin::IsSecure(const KURL& url) {
- if (SchemeRegistry::ShouldTreatURLSchemeAsSecure(url.Protocol()))
+ GURL gurl = GURL(url);
+
+ // 1. If url is "about:blank" or "about:srcdoc", return "Potentially
+ // Trustworthy".
+ if (gurl.IsAboutBlank() || gurl.IsAboutSrcdoc())
return true;
- // URLs that wrap inner URLs are secure if those inner URLs are secure.
- if (ShouldUseInnerURL(url) && SchemeRegistry::ShouldTreatURLSchemeAsSecure(
- ExtractInnerURL(url).Protocol()))
+ // 2. If url’s scheme is "data", return "Potentially Trustworthy".
+ if (gurl.SchemeIs(url::kDataScheme))
return true;
- if (SecurityPolicy::IsUrlTrustworthySafelisted(url))
+ // 3. Return the result of executing §3.2 Is origin potentially trustworthy?
+ // on url’s origin.
+ // Note: The origin of blob: and filesystem: URLs is the origin of the
+ // context in which they were created. Therefore, blobs created in a
+ // trustworthy origin will themselves be potentially trustworthy.
+ url::Origin origin = url::Origin::Create(gurl);
+ if (origin.opaque() &&
+ base::Contains(url::GetSecureSchemes(), gurl.scheme_piece())) {
+ // Authenticated schemes should be treated as trustworthy, even if they
+ // translate into an opaque origin (e.g. because some of them might also be
+ // registered as a no-access, like the //content-layer chrome-error:// or
+ // the //chrome-layer chrome-native://).
return true;
+ }
+
+ // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-origin
+ // 1. If origin is an opaque origin, return "Not Trustworthy".
+ if (origin.opaque())
+ return false;
+
+ // 2. Assert: origin is a tuple origin.
+ DCHECK(!origin.opaque());
+
+ // 3. If origin’s scheme is either "https" or "wss", return "Potentially
+ // Trustworthy".
+ // This is handled by the url::GetSecureSchemes() call below.
+ // 7. If origin’s scheme component is one which the user agent considers to be
+ // authenticated, return "Potentially Trustworthy".
+ // Note: See §7.1 Packaged Applications for detail here.
+ if (base::Contains(url::GetSecureSchemes(), origin.scheme()))
+ return true;
+
+ // 8. If origin has been configured as a trustworthy origin, return
+ // "Potentially Trustworthy".
+ // Note: See §7.2 Development Environments for detail here.
+ if (network::SecureOriginAllowlist::GetInstance().IsOriginAllowlisted(origin))
+ return true;
+
+ // 9. Return "Not Trustworthy".
return false;
}
@@ -423,7 +472,7 @@ bool SecurityOrigin::CanDisplay(const KURL& url) const {
SecurityPolicy::IsOriginAccessToURLAllowed(this, url);
}
- if (SchemeRegistry::ShouldTreatURLSchemeAsLocal(protocol)) {
+ if (base::Contains(url::GetLocalSchemes(), protocol.Ascii())) {
return CanLoadLocalResources() ||
SecurityPolicy::IsOriginAccessToURLAllowed(this, url);
}
@@ -432,24 +481,14 @@ bool SecurityOrigin::CanDisplay(const KURL& url) const {
}
bool SecurityOrigin::IsPotentiallyTrustworthy() const {
- // TODO(lukasza): The code below can hopefully be eventually deleted and
- // IsOriginPotentiallyTrustworthy can be used instead (from
+ // TODO(https://crbug.com/1153336): The code below can hopefully be eventually
+ // deleted and IsOriginPotentiallyTrustworthy can be used instead (from
// //services/network/public/cpp/is_potentially_trustworthy.h).
DCHECK_NE(protocol_, "data");
-
if (IsOpaque())
return is_opaque_origin_potentially_trustworthy_;
-
- if (SchemeRegistry::ShouldTreatURLSchemeAsSecure(protocol_) || IsLocal() ||
- IsLocalhost()) {
- return true;
- }
-
- if (SecurityPolicy::IsOriginTrustworthySafelisted(*this))
- return true;
-
- return false;
+ return network::IsOriginPotentiallyTrustworthy(ToUrlOrigin());
}
// static
@@ -479,7 +518,7 @@ void SecurityOrigin::BlockLocalAccessFromLocalOrigin() {
}
bool SecurityOrigin::IsLocal() const {
- return SchemeRegistry::ShouldTreatURLSchemeAsLocal(protocol_);
+ return base::Contains(url::GetLocalSchemes(), protocol_.Ascii());
}
bool SecurityOrigin::IsLocalhost() const {
@@ -521,7 +560,8 @@ void SecurityOrigin::BuildRawString(StringBuilder& builder) const {
builder.Append("://");
builder.Append(host_);
- if (port_) {
+ if (DefaultPortForProtocol(protocol_) &&
+ port_ != DefaultPortForProtocol(protocol_)) {
builder.Append(':');
builder.AppendNumber(port_);
}
@@ -698,9 +738,9 @@ String SecurityOrigin::CanonicalizeHost(const String& host, bool* success) {
*success = url::CanonicalizeHost(
utf8.data(), url::Component(0, utf8.size()), &canon_output, &out_host);
} else {
- *success = url::CanonicalizeHost(host.Characters16(),
- url::Component(0, host.length()),
- &canon_output, &out_host);
+ *success = url::CanonicalizeHost(
+ base::i18n::ToChar16Ptr(host.Characters16()),
+ url::Component(0, host.length()), &canon_output, &out_host);
}
return String::FromUTF8(canon_output.data(), canon_output.length());
}
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.h b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.h
index 992ee12c823..b8da2bb2d30 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin.h
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin.h
@@ -74,7 +74,10 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
// contains a standard (scheme, host, port) tuple, |reference_origin| is
// ignored. If |reference_origin| is provided and an opaque origin is returned
// (for example, if |url| has the "data:" scheme), the opaque origin will be
- // derived from |reference_origin|, retaining the precursor information.
+ // derived from |reference_origin|, retaining the precursor information. If
+ // |url| is "about:blank", a copy of |reference_origin| is returned. If no
+ // |reference_origin| has been provided, then "data:" and "about:blank" URLs
+ // will resolve into an opaque, unique origin.
static scoped_refptr<SecurityOrigin> CreateWithReferenceOrigin(
const KURL& url,
const SecurityOrigin* reference_origin);
@@ -134,16 +137,17 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
// null string. https://url.spec.whatwg.org/#host-registrable-domain
String RegistrableDomain() const;
- // Returns 0 if the effective port of this origin is the default for its
- // scheme.
- uint16_t Port() const { return port_; }
// Returns the effective port, even if it is the default port for the
// scheme (e.g. "http" => 80).
- uint16_t EffectivePort() const { return effective_port_; }
+ uint16_t Port() const { return port_; }
// Returns true if a given URL is secure, based either directly on its
// own protocol, or, when relevant, on the protocol of its "inner URL"
// Protocols like blob: and filesystem: fall into this latter category.
+ // This method is a stricter alternative to "potentially trustworthy url":
+ // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-url
+ // TODO(crbug.com/1153336): Deprecated, to be removed. Please use
+ // network::IsUrlPotentiallyTrustworthy() instead.
static bool IsSecure(const KURL&);
// Returns true if this SecurityOrigin can script objects in the given
@@ -233,14 +237,10 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
bool CanAccessCookies() const { return !IsOpaque(); }
bool CanAccessPasswordManager() const { return !IsOpaque(); }
bool CanAccessFileSystem() const { return !IsOpaque(); }
- bool CanAccessNativeFileSystem() const { return !IsOpaque(); }
bool CanAccessCacheStorage() const { return !IsOpaque(); }
bool CanAccessLocks() const { return !IsOpaque(); }
-
- // Technically, we should always allow access to sessionStorage, but we
- // currently don't handle creating a sessionStorage area for opaque
- // origins.
bool CanAccessSessionStorage() const { return !IsOpaque(); }
+ bool CanAccessStorageFoundation() const { return !IsOpaque(); }
// The local SecurityOrigin is the most privileged SecurityOrigin.
// The local SecurityOrigin can script any document, navigate to local
@@ -372,8 +372,6 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
bool SerializesAsNull() const;
private:
- constexpr static const uint16_t kInvalidPort = 0;
-
friend struct mojo::UrlOriginAdapter;
friend struct blink::SecurityOriginHash;
@@ -417,8 +415,7 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
const String protocol_ = g_empty_string;
const String host_ = g_empty_string;
String domain_ = g_empty_string;
- const uint16_t port_ = kInvalidPort;
- const uint16_t effective_port_ = kInvalidPort;
+ const uint16_t port_ = 0;
const base::Optional<url::Origin::Nonce> nonce_if_opaque_;
bool universal_access_ = false;
bool domain_was_set_in_dom_ = false;
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_fuzzer.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_fuzzer.cc
index 02428a03724..9a9275ddf2e 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_fuzzer.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_fuzzer.cc
@@ -32,28 +32,6 @@ void RoundTripFromContent(const GURL& input) {
WebSecurityOrigin web_security_origin_2 = security_origin;
url::Origin origin_2 = web_security_origin_2;
- // The notion of unspecified port and port zero doesn't match in between
- // url::Origin and blink::SecurityOrigin. This cause some conversion problems
- // when the scheme is a standard one and the unspecified port can be converted
- // to the default one.
- // ┌──────────────────┬───────────┐
- // │ port unspecified │ port zero │
- // ┌─────────────────────┼──────────────────┼───────────┤
- // │url::Origin │ -1 │ 0 │
- // ├─────────────────────┼──────────────────┼───────────┤
- // │blink::SecurityOrigin│ 0 │ 0 │
- // └─────────────────────┴──────────────────┴───────────┘
- // TODO(https://crbug.com/1136678): Remove this, once fixed.
- if (!origin_1.opaque() && origin_1.port() == 0 &&
- url::DefaultPortForScheme(origin_1.scheme().data(),
- origin_1.scheme().size()) != -1) {
- CHECK_NE(origin_1, origin_2);
- CHECK_EQ(url::DefaultPortForScheme(origin_2.scheme().data(),
- origin_2.scheme().size()),
- origin_2.port());
- return;
- }
-
CHECK_EQ(origin_1, origin_2);
}
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
index 1294f9ba561..eed20be45a9 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -33,7 +33,10 @@
#include <stdint.h>
#include "base/stl_util.h"
+#include "base/test/scoped_command_line.h"
#include "net/base/url_util.h"
+#include "services/network/public/cpp/is_potentially_trustworthy_unittest.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/cors.mojom-blink.h"
#include "services/network/public/mojom/cors_origin_pattern.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,6 +50,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_operators.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "url/gurl.h"
+#include "url/origin_abstract_tests.h"
#include "url/url_util.h"
namespace blink {
@@ -95,130 +99,23 @@ TEST_F(SecurityOriginTest, LocalAccess) {
EXPECT_FALSE(file2->CanAccess(file1.get()));
}
-TEST_F(SecurityOriginTest, IsPotentiallyTrustworthy) {
- struct TestCase {
- bool is_potentially_trustworthy;
- bool is_localhost;
- const char* url;
- };
-
- TestCase inputs[] = {
- // Access is granted to webservers running on localhost.
- {true, true, "http://localhost"},
- {true, true, "http://localhost."},
- {true, true, "http://LOCALHOST"},
- {true, true, "http://localhost:100"},
- {true, true, "http://a.localhost"},
- {true, true, "http://a.b.localhost"},
- {true, true, "http://127.0.0.1"},
- {true, true, "http://127.0.0.2"},
- {true, true, "http://127.1.0.2"},
- {true, true, "http://0177.00.00.01"},
- {true, true, "http://[::1]"},
- {true, true, "http://[0:0::1]"},
- {true, true, "http://[0:0:0:0:0:0:0:1]"},
- {true, true, "http://[::1]:21"},
- {true, true, "http://127.0.0.1:8080"},
- {true, true, "ftp://127.0.0.1"},
- {true, true, "ftp://127.0.0.1:443"},
- {true, true, "ws://127.0.0.1"},
-
- // Non-localhost over HTTP
- {false, false, "http://[1::]"},
- {false, false, "http://[::2]"},
- {false, false, "http://[1::1]"},
- {false, false, "http://[1:2::3]"},
- {false, false, "http://[::127.0.0.1]"},
- {false, false, "http://a.127.0.0.1"},
- {false, false, "http://127.0.0.1.b"},
- {false, false, "http://localhost.a"},
-
- // loopback resolves to localhost on Windows, but not
- // recognized generically here.
- {false, false, "http://loopback"},
-
- // IPv4 mapped IPv6 literals for 127.0.0.1.
- {false, false, "http://[::ffff:127.0.0.1]"},
- {false, false, "http://[::ffff:7f00:1]"},
-
- // IPv4 compatible IPv6 literal for 127.0.0.1.
- {false, false, "http://[::127.0.0.1]"},
-
- // TODO(eroman): Not documented why these are recognized.
- {true, true, "http://localhost6"},
- {true, true, "ftp://localhost6.localdomain6"},
- {true, true, "http://localhost.localdomain"},
-
- // Secure transports are considered trustworthy.
- {true, false, "https://foobar.com"},
- {true, false, "wss://foobar.com"},
-
- // Insecure transports are not considered trustworthy.
- {false, false, "ftp://foobar.com"},
- {false, false, "http://foobar.com"},
- {false, false, "http://foobar.com:443"},
- {false, false, "ws://foobar.com"},
-
- // Local files are considered trustworthy.
- {true, false, "file:///home/foobar/index.html"},
-
- // blob: URLs must look to the inner URL's origin, and apply the same
- // rules as above. Spot check some of them
- {true, true,
- "blob:http://localhost:1000/578223a1-8c13-17b3-84d5-eca045ae384a"},
- {true, false,
- "blob:https://foopy:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
- {false, false, "blob:http://baz:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
- {false, false, "blob:ftp://evil:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
-
- // filesystem: URLs work the same as blob: URLs, and look to the inner
- // URL for security origin.
- {true, true, "filesystem:http://localhost:1000/foo"},
- {true, false, "filesystem:https://foopy:99/foo"},
- {false, false, "filesystem:http://baz:99/foo"},
- {false, false, "filesystem:ftp://evil:99/foo"},
- };
-
- for (size_t i = 0; i < base::size(inputs); ++i) {
- SCOPED_TRACE(inputs[i].url);
- scoped_refptr<const SecurityOrigin> origin =
- SecurityOrigin::CreateFromString(inputs[i].url);
- String error_message;
- EXPECT_EQ(inputs[i].is_potentially_trustworthy,
- origin->IsPotentiallyTrustworthy());
- EXPECT_EQ(inputs[i].is_localhost, origin->IsLocalhost());
-
- GURL test_gurl(inputs[i].url);
- if (!(test_gurl.SchemeIsBlob() || test_gurl.SchemeIsFileSystem())) {
- // Check that the origin's notion of localhost matches //net's notion of
- // localhost. This is skipped for blob: and filesystem: URLs since
- // SecurityOrigin uses their inner URL's origin.
- EXPECT_EQ(net::IsLocalhost(GURL(inputs[i].url)), origin->IsLocalhost());
- }
- }
-
- // Anonymous opaque origins are not considered secure.
- scoped_refptr<SecurityOrigin> opaque_origin =
- SecurityOrigin::CreateUniqueOpaque();
- EXPECT_FALSE(opaque_origin->IsPotentiallyTrustworthy());
-}
-
TEST_F(SecurityOriginTest, IsSecure) {
struct TestCase {
bool is_secure;
const char* url;
} inputs[] = {
- {false, "blob:ftp://evil:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
- {false, "blob:http://example.com/578223a1-8c13-17b3-84d5-eca045ae384a"},
+ // https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy
+ // TODO(crbug.com/1153336 and crbug.com/1164416): Fix product behavior, so
+ // that blink::SecurityOrigin::IsSecure(const KURL&) is compatible with
+ // network::IsUrlPotentiallyTrustworthy(const GURL&) and then move the
+ // tests below to the AbstractTrustworthinessTest.UrlFromString test case
+ // in //services/network/public/cpp/is_potentially_trustworthy_unittest.
+ // See also IsPotentiallyTrustworthy.Url test.
{false, "file:///etc/passwd"},
- {false, "ftp://example.com/"},
- {false, "http://example.com/"},
- {false, "ws://example.com/"},
- {true, "blob:https://example.com/578223a1-8c13-17b3-84d5-eca045ae384a"},
- {true, "https://example.com/"},
- {true, "wss://example.com/"},
-
- {true, "about:blank"},
+ {false, "blob:data:text/html,Hello"},
+ {false, "blob:about:blank"},
+ {false, "filesystem:data:text/html,Hello"},
+ {false, "filesystem:about:blank"},
{false, ""},
{false, "\0"},
};
@@ -231,23 +128,36 @@ TEST_F(SecurityOriginTest, IsSecure) {
}
TEST_F(SecurityOriginTest, IsSecureViaTrustworthy) {
+ // TODO(crbug.com/1153336): Should SecurityOrigin::IsSecure be aligned with
+ // network::IsURLPotentiallyTrustworthy?
+ // https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy
const char* urls[] = {"http://localhost/", "http://localhost:8080/",
"http://127.0.0.1/", "http://127.0.0.1:8080/",
- "http://[::1]/"};
+ "http://[::1]/", "http://vhost.localhost/"};
for (const char* test : urls) {
KURL url(test);
EXPECT_FALSE(SecurityOrigin::IsSecure(url));
- SecurityPolicy::AddOriginToTrustworthySafelist(
- SecurityOrigin::CreateFromString(url)->ToRawString());
- EXPECT_TRUE(SecurityOrigin::IsSecure(url));
+ {
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line =
+ scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure, test);
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
+ EXPECT_TRUE(SecurityOrigin::IsSecure(url));
+ }
}
}
TEST_F(SecurityOriginTest, IsSecureViaTrustworthyHostnamePattern) {
KURL url("http://bar.foo.com");
EXPECT_FALSE(SecurityOrigin::IsSecure(url));
- SecurityPolicy::AddOriginToTrustworthySafelist("*.foo.com");
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure, "*.foo.com");
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
EXPECT_TRUE(SecurityOrigin::IsSecure(url));
}
@@ -255,7 +165,11 @@ TEST_F(SecurityOriginTest, IsSecureViaTrustworthyHostnamePattern) {
TEST_F(SecurityOriginTest, IsSecureViaTrustworthyHostnamePatternEmptyHostname) {
KURL url("file://foo");
EXPECT_FALSE(SecurityOrigin::IsSecure(url));
- SecurityPolicy::AddOriginToTrustworthySafelist("*.foo.com");
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure, "*.foo.com");
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
EXPECT_FALSE(SecurityOrigin::IsSecure(url));
}
@@ -545,28 +459,6 @@ TEST_F(SecurityOriginTest, PunycodeNotUnicode) {
EXPECT_FALSE(origin->CanRequest(unicode_url));
}
-TEST_F(SecurityOriginTest, PortAndEffectivePortMethod) {
- struct TestCase {
- uint16_t port;
- uint16_t effective_port;
- const char* origin;
- } cases[] = {
- {0, 80, "http://example.com"},
- {0, 80, "http://example.com:80"},
- {81, 81, "http://example.com:81"},
- {0, 443, "https://example.com"},
- {0, 443, "https://example.com:443"},
- {444, 444, "https://example.com:444"},
- };
-
- for (const auto& test : cases) {
- scoped_refptr<const SecurityOrigin> origin =
- SecurityOrigin::CreateFromString(test.origin);
- EXPECT_EQ(test.port, origin->Port());
- EXPECT_EQ(test.effective_port, origin->EffectivePort());
- }
-}
-
TEST_F(SecurityOriginTest, CreateFromTuple) {
struct TestCase {
const char* scheme;
@@ -575,6 +467,7 @@ TEST_F(SecurityOriginTest, CreateFromTuple) {
const char* origin;
} cases[] = {
{"http", "example.com", 80, "http://example.com"},
+ {"http", "example.com", 0, "http://example.com:0"},
{"http", "example.com", 81, "http://example.com:81"},
{"https", "example.com", 443, "https://example.com"},
{"https", "example.com", 444, "https://example.com:444"},
@@ -663,8 +556,8 @@ TEST_F(SecurityOriginTest, CanonicalizeHost) {
TEST_F(SecurityOriginTest, UrlOriginConversions) {
url::ScopedSchemeRegistryForTests scoped_registry;
+ url::AddNoAccessScheme("no-access");
url::AddLocalScheme("nonstandard-but-local");
- SchemeRegistry::RegisterURLSchemeAsLocal("nonstandard-but-local");
struct TestCases {
const char* const url;
const char* const scheme;
@@ -692,12 +585,16 @@ TEST_F(SecurityOriginTest, UrlOriginConversions) {
{"http://example.com:123/?query", "http", "example.com", 123},
{"https://example.com/#1234", "https", "example.com", 443},
{"https://u:p@example.com:123/?query#1234", "https", "example.com", 123},
+ {"https://example.com:0/", "https", "example.com", 0},
// Nonstandard schemes.
{"unrecognized-scheme://localhost/", "", "", 0, true},
{"mailto:localhost/", "", "", 0, true},
{"about:blank", "", "", 0, true},
+ // Custom no-access scheme.
+ {"no-access:blah", "", "", 0, true},
+
// Registered URLs
{"ftp://example.com/", "ftp", "example.com", 21},
{"ws://example.com/", "ws", "example.com", 80},
@@ -739,10 +636,8 @@ TEST_F(SecurityOriginTest, UrlOriginConversions) {
EXPECT_EQ(test_case.scheme, security_origin_via_kurl->Protocol());
EXPECT_EQ(test_case.host, security_origin_via_gurl->Host());
EXPECT_EQ(test_case.host, security_origin_via_kurl->Host());
- EXPECT_EQ(security_origin_via_gurl->Port(),
- security_origin_via_kurl->Port());
- EXPECT_EQ(test_case.port, security_origin_via_gurl->EffectivePort());
- EXPECT_EQ(test_case.port, security_origin_via_kurl->EffectivePort());
+ EXPECT_EQ(test_case.port, security_origin_via_gurl->Port());
+ EXPECT_EQ(test_case.port, security_origin_via_kurl->Port());
EXPECT_EQ(test_case.opaque, security_origin_via_gurl->IsOpaque());
EXPECT_EQ(test_case.opaque, security_origin_via_kurl->IsOpaque());
EXPECT_EQ(!test_case.opaque, security_origin_via_kurl->IsSameOriginWith(
@@ -878,23 +773,6 @@ TEST_F(SecurityOriginTest, ToTokenForFastCheck) {
}
}
-TEST_F(SecurityOriginTest, NonStandardScheme) {
- scoped_refptr<const SecurityOrigin> origin =
- SecurityOrigin::CreateFromString("cow://");
- EXPECT_TRUE(origin->IsOpaque());
-}
-
-TEST_F(SecurityOriginTest, NonStandardSchemeWithAndroidWebViewHack) {
- url::ScopedSchemeRegistryForTests scoped_registry;
- url::EnableNonStandardSchemesForAndroidWebView();
- scoped_refptr<const SecurityOrigin> origin =
- SecurityOrigin::CreateFromString("cow://");
- EXPECT_FALSE(origin->IsOpaque());
- EXPECT_EQ("cow", origin->Protocol());
- EXPECT_EQ("", origin->Host());
- EXPECT_EQ(0, origin->Port());
-}
-
TEST_F(SecurityOriginTest, OpaqueIsolatedCopy) {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateUniqueOpaque();
@@ -1182,3 +1060,98 @@ TEST_F(SecurityOriginTest, PercentEncodesHost) {
}
} // namespace blink
+
+// Apparently INSTANTIATE_TYPED_TEST_SUITE_P needs to be used in the same
+// namespace as where the typed test suite was defined.
+namespace url {
+
+class BlinkSecurityOriginTestTraits {
+ public:
+ using OriginType = scoped_refptr<blink::SecurityOrigin>;
+
+ static OriginType CreateOriginFromString(base::StringPiece s) {
+ return blink::SecurityOrigin::CreateFromString(String::FromUTF8(s));
+ }
+
+ static OriginType CreateUniqueOpaqueOrigin() {
+ return blink::SecurityOrigin::CreateUniqueOpaque();
+ }
+
+ static OriginType CreateWithReferenceOrigin(
+ base::StringPiece url,
+ const OriginType& reference_origin) {
+ return blink::SecurityOrigin::CreateWithReferenceOrigin(
+ blink::KURL(String::FromUTF8(url)), reference_origin.get());
+ }
+
+ static OriginType DeriveNewOpaqueOrigin(const OriginType& reference_origin) {
+ return reference_origin->DeriveNewOpaqueOrigin();
+ }
+
+ static bool IsOpaque(const OriginType& origin) { return origin->IsOpaque(); }
+
+ static std::string GetScheme(const OriginType& origin) {
+ return origin->Protocol().Utf8();
+ }
+
+ static std::string GetHost(const OriginType& origin) {
+ return origin->Host().Utf8();
+ }
+
+ static uint16_t GetPort(const OriginType& origin) { return origin->Port(); }
+
+ static SchemeHostPort GetTupleOrPrecursorTupleIfOpaque(
+ const OriginType& origin) {
+ const blink::SecurityOrigin* precursor =
+ origin->GetOriginOrPrecursorOriginIfOpaque();
+ if (!precursor)
+ return SchemeHostPort();
+ return SchemeHostPort(precursor->Protocol().Utf8(),
+ precursor->Host().Utf8(), precursor->Port());
+ }
+
+ static bool IsSameOrigin(const OriginType& a, const OriginType& b) {
+ return a->IsSameOriginWith(b.get());
+ }
+
+ static std::string Serialize(const OriginType& origin) {
+ return origin->ToString().Utf8();
+ }
+
+ static bool IsValidUrl(base::StringPiece str) {
+ return blink::KURL(String::FromUTF8(str)).IsValid();
+ }
+
+ static bool IsOriginPotentiallyTrustworthy(const OriginType& origin) {
+ return origin->IsPotentiallyTrustworthy();
+ }
+
+ static bool IsUrlPotentiallyTrustworthy(base::StringPiece str) {
+ return blink::SecurityOrigin::IsSecure(blink::KURL(String::FromUTF8(str)));
+ }
+
+ static bool IsOriginOfLocalhost(const OriginType& origin) {
+ return origin->IsLocalhost();
+ }
+
+ // Only static members = no constructors are needed.
+ BlinkSecurityOriginTestTraits() = delete;
+};
+
+INSTANTIATE_TYPED_TEST_SUITE_P(BlinkSecurityOrigin,
+ AbstractOriginTest,
+ BlinkSecurityOriginTestTraits);
+
+} // namespace url
+
+// Apparently INSTANTIATE_TYPED_TEST_SUITE_P needs to be used in the same
+// namespace as where the typed test suite was defined.
+namespace network {
+namespace test {
+
+INSTANTIATE_TYPED_TEST_SUITE_P(BlinkSecurityOrigin,
+ AbstractTrustworthinessTest,
+ url::BlinkSecurityOriginTestTraits);
+
+} // namespace test
+} // namespace network
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_policy.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_policy.cc
index 6c28ac26832..f57e30a4d3c 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_policy.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_policy.cc
@@ -62,17 +62,6 @@ static network::cors::OriginAccessList& GetOriginAccessList() {
return origin_access_list;
}
-using OriginSet = HashSet<String>;
-
-static OriginSet& TrustworthyOriginSafelist() {
- DEFINE_STATIC_LOCAL(OriginSet, safelist, ());
- return safelist;
-}
-
-void SecurityPolicy::Init() {
- TrustworthyOriginSafelist();
-}
-
bool SecurityPolicy::ShouldHideReferrer(const KURL& url, const KURL& referrer) {
bool referrer_is_secure_url = referrer.ProtocolIs("https");
bool scheme_is_allowed =
@@ -166,49 +155,6 @@ Referrer SecurityPolicy::GenerateReferrer(
referrer_policy_no_default);
}
-void SecurityPolicy::AddOriginToTrustworthySafelist(
- const String& origin_or_pattern) {
-#if DCHECK_IS_ON()
- // Must be called before we start other threads.
- DCHECK(WTF::IsBeforeThreadCreated());
-#endif
- // Origins and hostname patterns must be canonicalized (including
- // canonicalization to 8-bit strings) before being inserted into
- // TrustworthyOriginSafelist().
- CHECK(origin_or_pattern.Is8Bit());
- TrustworthyOriginSafelist().insert(origin_or_pattern);
-}
-
-bool SecurityPolicy::IsOriginTrustworthySafelisted(
- const SecurityOrigin& origin) {
- // Early return if |origin| cannot possibly be matched.
- if (origin.IsOpaque() || TrustworthyOriginSafelist().IsEmpty())
- return false;
-
- if (TrustworthyOriginSafelist().Contains(origin.ToRawString()))
- return true;
-
- // KURL and SecurityOrigin hosts should be canonicalized to 8-bit strings.
- CHECK(origin.Host().Is8Bit());
- StringUTF8Adaptor host_adaptor(origin.Host());
- for (const auto& origin_or_pattern : TrustworthyOriginSafelist()) {
- StringUTF8Adaptor origin_or_pattern_adaptor(origin_or_pattern);
- if (base::MatchPattern(host_adaptor.AsStringPiece(),
- origin_or_pattern_adaptor.AsStringPiece())) {
- return true;
- }
- }
-
- return false;
-}
-
-bool SecurityPolicy::IsUrlTrustworthySafelisted(const KURL& url) {
- // Early return to avoid initializing the SecurityOrigin.
- if (TrustworthyOriginSafelist().IsEmpty())
- return false;
- return IsOriginTrustworthySafelisted(*SecurityOrigin::Create(url).get());
-}
-
bool SecurityPolicy::IsOriginAccessAllowed(
const SecurityOrigin* active_origin,
const SecurityOrigin* target_origin) {
@@ -310,11 +256,15 @@ bool SecurityPolicy::ReferrerPolicyFromString(
*result = network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin;
return true;
}
- if (EqualIgnoringASCIICase(policy, "no-referrer-when-downgrade") ||
- (support_legacy_keywords && EqualIgnoringASCIICase(policy, "default"))) {
+ if (EqualIgnoringASCIICase(policy, "no-referrer-when-downgrade")) {
*result = network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
return true;
}
+ if (support_legacy_keywords && EqualIgnoringASCIICase(policy, "default")) {
+ *result = ReferrerUtils::NetToMojoReferrerPolicy(
+ ReferrerUtils::GetDefaultNetReferrerPolicy());
+ return true;
+ }
return false;
}
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_policy.h b/chromium/third_party/blink/renderer/platform/weborigin/security_policy.h
index 94198be5280..66a9ffa22fc 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_policy.h
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_policy.h
@@ -50,10 +50,6 @@ class PLATFORM_EXPORT SecurityPolicy {
STATIC_ONLY(SecurityPolicy);
public:
- // This must be called during initialization (before we create
- // other threads).
- static void Init();
-
// True if the referrer should be omitted according to the
// ReferrerPolicyNoReferrerWhenDowngrade. If you intend to send a
// referrer header, you should use generateReferrer instead.
@@ -91,10 +87,6 @@ class PLATFORM_EXPORT SecurityPolicy {
static bool IsOriginAccessToURLAllowed(const SecurityOrigin* active_origin,
const KURL&);
- static void AddOriginToTrustworthySafelist(const String&);
- static bool IsOriginTrustworthySafelisted(const SecurityOrigin&);
- static bool IsUrlTrustworthySafelisted(const KURL&);
-
static bool ReferrerPolicyFromString(const String& policy,
ReferrerPolicyLegacyKeywordsSupport,
network::mojom::ReferrerPolicy* result);
diff --git a/chromium/third_party/blink/renderer/platform/weborigin/security_policy_test.cc b/chromium/third_party/blink/renderer/platform/weborigin/security_policy_test.cc
index 9eee9697d8f..a7a9b4fc553 100644
--- a/chromium/third_party/blink/renderer/platform/weborigin/security_policy_test.cc
+++ b/chromium/third_party/blink/renderer/platform/weborigin/security_policy_test.cc
@@ -30,7 +30,10 @@
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
+#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/cors.mojom-blink.h"
#include "services/network/public/mojom/cors_origin_pattern.mojom-blink.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
@@ -358,8 +361,17 @@ TEST(SecurityPolicyTest, TrustworthySafelist) {
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(url);
EXPECT_FALSE(origin->IsPotentiallyTrustworthy());
- SecurityPolicy::AddOriginToTrustworthySafelist(origin->ToString());
- EXPECT_TRUE(origin->IsPotentiallyTrustworthy());
+
+ {
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line =
+ scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure,
+ origin->ToString().Latin1());
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
+ EXPECT_TRUE(origin->IsPotentiallyTrustworthy());
+ }
}
// Tests that adding URLs that have inner-urls to the safelist
@@ -385,9 +397,17 @@ TEST(SecurityPolicyTest, TrustworthySafelist) {
EXPECT_FALSE(origin1->IsPotentiallyTrustworthy());
EXPECT_FALSE(origin2->IsPotentiallyTrustworthy());
- SecurityPolicy::AddOriginToTrustworthySafelist(origin1->ToString());
- EXPECT_TRUE(origin1->IsPotentiallyTrustworthy());
- EXPECT_TRUE(origin2->IsPotentiallyTrustworthy());
+ {
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line =
+ scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure,
+ origin1->ToString().Latin1());
+ network::SecureOriginAllowlist::GetInstance().ResetForTesting();
+ EXPECT_TRUE(origin1->IsPotentiallyTrustworthy());
+ EXPECT_TRUE(origin2->IsPotentiallyTrustworthy());
+ }
}
}
@@ -616,35 +636,20 @@ TEST(SecurityPolicyTest, ReferrerForCustomScheme) {
String kFullReferrer = "my-new-scheme://com.foo.me/this-should-be-truncated";
String kTruncatedReferrer = "my-new-scheme://com.foo.me/";
- {
- // With the feature off, the old default policy of
- // no-referrer-when-downgrade should preserve the entire URL.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kReducedReferrerGranularity);
-
- EXPECT_EQ(SecurityPolicy::GenerateReferrer(
- network::mojom::ReferrerPolicy::kDefault,
- KURL("https://www.example.com/"), kFullReferrer)
- .referrer,
- kFullReferrer);
- }
-
- {
- // With the feature on, the new default policy of
- // strict-origin-when-cross-origin should truncate the referrer.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kReducedReferrerGranularity);
-
- ASSERT_TRUE(ReferrerUtils::IsReducedReferrerGranularityEnabled());
+ // The default policy of strict-origin-when-cross-origin should truncate the
+ // referrer.
+ EXPECT_EQ(SecurityPolicy::GenerateReferrer(
+ network::mojom::ReferrerPolicy::kDefault,
+ KURL("https://www.example.com/"), kFullReferrer)
+ .referrer,
+ kTruncatedReferrer);
- EXPECT_EQ(SecurityPolicy::GenerateReferrer(
- network::mojom::ReferrerPolicy::kDefault,
- KURL("https://www.example.com/"), kFullReferrer)
- .referrer,
- kTruncatedReferrer);
- }
+ // no-referrer-when-downgrade shouldn't truncate the referrer.
+ EXPECT_EQ(SecurityPolicy::GenerateReferrer(
+ network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade,
+ KURL("https://www.example.com/"), kFullReferrer)
+ .referrer,
+ kFullReferrer);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/DEPS b/chromium/third_party/blink/renderer/platform/webrtc/DEPS
index 4ca2134e95d..ab27fab8964 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/DEPS
+++ b/chromium/third_party/blink/renderer/platform/webrtc/DEPS
@@ -1,3 +1,13 @@
include_rules = [
"+media/base",
]
+
+specific_include_rules = {
+ "webrtc_video_frame_adapter\.cc": [
+ "+media/video/gpu_video_accelerator_factories.h",
+ "+gpu/command_buffer/client/raster_interface.h",
+ ],
+ "webrtc_video_frame_adapter\.h": [
+ "+components/viz/common/gpu/raster_context_provider.h",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/DIR_METADATA b/chromium/third_party/blink/renderer/platform/webrtc/DIR_METADATA
new file mode 100644
index 00000000000..7fdbb5e4bdd
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/webrtc/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>WebRTC"
+} \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/OWNERS b/chromium/third_party/blink/renderer/platform/webrtc/OWNERS
index 48b19446ad8..a1293787554 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/webrtc/OWNERS
@@ -1,3 +1 @@
file://third_party/blink/public/platform/modules/webrtc/OWNERS
-
-# COMPONENT: Blink>WebRTC
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.cc b/chromium/third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.cc
index 285de6bf45a..b968981cf1b 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.cc
+++ b/chromium/third_party/blink/renderer/platform/webrtc/peer_connection_remote_audio_source.cc
@@ -146,8 +146,11 @@ void PeerConnectionRemoteAudioSource::OnData(const void* audio_data,
audio_bus_ = media::AudioBus::Create(number_of_channels, number_of_frames);
}
- audio_bus_->FromInterleaved(audio_data, number_of_frames,
- bits_per_sample / 8);
+ // Only 16 bits per sample is ever used. The FromInterleaved() call should
+ // be updated if that is no longer the case.
+ DCHECK_EQ(bits_per_sample, 16);
+ audio_bus_->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+ reinterpret_cast<const int16_t*>(audio_data), number_of_frames);
media::AudioParameters params = MediaStreamAudioSource::GetAudioParameters();
if (!params.IsValid() ||
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
index dda85c73994..d00ca964339 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
+++ b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
@@ -5,13 +5,21 @@
#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
#include "base/callback_helpers.h"
+#include "base/containers/span.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "gpu/command_buffer/client/raster_interface.h"
+#include "media/base/video_util.h"
+#include "media/video/gpu_video_accelerator_factories.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/convert_from_argb.h"
#include "third_party/libyuv/include/libyuv/scale.h"
#include "third_party/webrtc/api/video/i420_buffer.h"
#include "third_party/webrtc/common_video/include/video_frame_buffer.h"
@@ -167,136 +175,144 @@ rtc::scoped_refptr<webrtc::VideoFrameBuffer> MakeFrameAdapter(
}
}
-void IsValidFrame(const media::VideoFrame& frame) {
- // Paranoia checks.
- DCHECK(media::VideoFrame::IsValidConfig(
- frame.format(), frame.storage_type(), frame.coded_size(),
- frame.visible_rect(), frame.natural_size()));
- DCHECK(media::PIXEL_FORMAT_I420 == frame.format() ||
- media::PIXEL_FORMAT_I420A == frame.format() ||
- media::PIXEL_FORMAT_NV12 == frame.format());
- if (media::PIXEL_FORMAT_NV12 == frame.format()) {
- CHECK(
- reinterpret_cast<const void*>(frame.data(media::VideoFrame::kYPlane)));
- CHECK(
- reinterpret_cast<const void*>(frame.data(media::VideoFrame::kUVPlane)));
- CHECK(frame.stride(media::VideoFrame::kYPlane));
- CHECK(frame.stride(media::VideoFrame::kUVPlane));
- } else {
- CHECK(
- reinterpret_cast<const void*>(frame.data(media::VideoFrame::kYPlane)));
- CHECK(
- reinterpret_cast<const void*>(frame.data(media::VideoFrame::kUPlane)));
- CHECK(
- reinterpret_cast<const void*>(frame.data(media::VideoFrame::kVPlane)));
- CHECK(frame.stride(media::VideoFrame::kYPlane));
- CHECK(frame.stride(media::VideoFrame::kUPlane));
- CHECK(frame.stride(media::VideoFrame::kVPlane));
- }
-}
-
-scoped_refptr<media::VideoFrame> WrapGmbVideoFrameForMappedMemoryAccess(
- scoped_refptr<media::VideoFrame> source_frame) {
- DCHECK_EQ(source_frame->natural_size(), source_frame->visible_rect().size());
- gfx::GpuMemoryBuffer* gmb = source_frame->GetGpuMemoryBuffer();
- if (!gmb || !gmb->Map()) {
- return nullptr;
- }
- // Y and UV planes from the gmb.
- uint8_t* plane_addresses[2] = {static_cast<uint8_t*>(gmb->memory(0)),
- static_cast<uint8_t*>(gmb->memory(1))};
- scoped_refptr<media::VideoFrame> destination_frame =
- media::VideoFrame::WrapExternalYuvData(
- media::VideoPixelFormat::PIXEL_FORMAT_NV12,
- source_frame->coded_size(), source_frame->visible_rect(),
- source_frame->natural_size(), gmb->stride(0), gmb->stride(1),
- plane_addresses[0], plane_addresses[1], source_frame->timestamp());
- if (!destination_frame) {
- gmb->Unmap();
- LOG(ERROR) << "Failed to wrap gmb buffer";
- return nullptr;
- }
- destination_frame->set_color_space(source_frame->ColorSpace());
- destination_frame->metadata()->MergeMetadataFrom(source_frame->metadata());
- destination_frame->AddDestructionObserver(WTF::Bind(
- [](scoped_refptr<media::VideoFrame> frame) {
- CHECK(frame->HasGpuMemoryBuffer());
- frame->GetGpuMemoryBuffer()->Unmap();
- },
- std::move(source_frame)));
- return destination_frame;
-}
-
scoped_refptr<media::VideoFrame> MakeScaledI420VideoFrame(
scoped_refptr<media::VideoFrame> source_frame,
- scoped_refptr<blink::WebRtcVideoFrameAdapter::BufferPoolOwner>
- scaled_frame_pool) {
- gfx::GpuMemoryBuffer* gmb = source_frame->GetGpuMemoryBuffer();
- if (!gmb || !gmb->Map()) {
- return nullptr;
- }
- // Crop to the visible rectangle specified in |source_frame|.
- const uint8_t* src_y = (reinterpret_cast<const uint8_t*>(gmb->memory(0)) +
- source_frame->visible_rect().x() +
- (source_frame->visible_rect().y() * gmb->stride(0)));
- const uint8_t* src_uv =
- (reinterpret_cast<const uint8_t*>(gmb->memory(1)) +
- ((source_frame->visible_rect().x() / 2) * 2) +
- ((source_frame->visible_rect().y() / 2) * gmb->stride(1)));
-
+ scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+ shared_resources) {
+ // ARGB pixel format may be produced by readback of texture backed frames.
+ DCHECK(source_frame->format() == media::PIXEL_FORMAT_NV12 ||
+ source_frame->format() == media::PIXEL_FORMAT_I420 ||
+ source_frame->format() == media::PIXEL_FORMAT_I420A ||
+ source_frame->format() == media::PIXEL_FORMAT_ARGB);
+ const bool has_alpha = source_frame->format() == media::PIXEL_FORMAT_I420A;
// Convert to I420 and scale to the natural size specified in
// |source_frame|.
- auto dst_frame = scaled_frame_pool->CreateFrame(
- media::PIXEL_FORMAT_I420, source_frame->natural_size(),
- gfx::Rect(source_frame->natural_size()), source_frame->natural_size(),
- source_frame->timestamp());
+ auto dst_frame = shared_resources->CreateFrame(
+ has_alpha ? media::PIXEL_FORMAT_I420A : media::PIXEL_FORMAT_I420,
+ source_frame->natural_size(), gfx::Rect(source_frame->natural_size()),
+ source_frame->natural_size(), source_frame->timestamp());
if (!dst_frame) {
- gmb->Unmap();
LOG(ERROR) << "Failed to create I420 frame from pool.";
return nullptr;
}
- dst_frame->metadata()->MergeMetadataFrom(source_frame->metadata());
- const auto& i420_planes = dst_frame->layout().planes();
- webrtc::NV12ToI420Scaler scaler;
- scaler.NV12ToI420Scale(src_y, gmb->stride(0), src_uv, gmb->stride(1),
+ dst_frame->metadata().MergeMetadataFrom(source_frame->metadata());
+
+ switch (source_frame->format()) {
+ case media::PIXEL_FORMAT_I420A:
+ libyuv::ScalePlane(source_frame->visible_data(media::VideoFrame::kAPlane),
+ source_frame->stride(media::VideoFrame::kAPlane),
source_frame->visible_rect().width(),
source_frame->visible_rect().height(),
- dst_frame->data(media::VideoFrame::kYPlane),
- i420_planes[media::VideoFrame::kYPlane].stride,
- dst_frame->data(media::VideoFrame::kUPlane),
- i420_planes[media::VideoFrame::kUPlane].stride,
- dst_frame->data(media::VideoFrame::kVPlane),
- i420_planes[media::VideoFrame::kVPlane].stride,
+ dst_frame->data(media::VideoFrame::kAPlane),
+ dst_frame->stride(media::VideoFrame::kAPlane),
dst_frame->coded_size().width(),
- dst_frame->coded_size().height());
- gmb->Unmap();
+ dst_frame->coded_size().height(),
+ libyuv::kFilterBilinear);
+ // Fallthrough to I420 in order to scale the YUV planes as well.
+ ABSL_FALLTHROUGH_INTENDED;
+ case media::PIXEL_FORMAT_I420:
+ libyuv::I420Scale(source_frame->visible_data(media::VideoFrame::kYPlane),
+ source_frame->stride(media::VideoFrame::kYPlane),
+ source_frame->visible_data(media::VideoFrame::kUPlane),
+ source_frame->stride(media::VideoFrame::kUPlane),
+ source_frame->visible_data(media::VideoFrame::kVPlane),
+ source_frame->stride(media::VideoFrame::kVPlane),
+ source_frame->visible_rect().width(),
+ source_frame->visible_rect().height(),
+ dst_frame->data(media::VideoFrame::kYPlane),
+ dst_frame->stride(media::VideoFrame::kYPlane),
+ dst_frame->data(media::VideoFrame::kUPlane),
+ dst_frame->stride(media::VideoFrame::kUPlane),
+ dst_frame->data(media::VideoFrame::kVPlane),
+ dst_frame->stride(media::VideoFrame::kVPlane),
+ dst_frame->coded_size().width(),
+ dst_frame->coded_size().height(),
+ libyuv::kFilterBilinear);
+ break;
+ case media::PIXEL_FORMAT_NV12: {
+ webrtc::NV12ToI420Scaler scaler;
+ scaler.NV12ToI420Scale(
+ source_frame->visible_data(media::VideoFrame::kYPlane),
+ source_frame->stride(media::VideoFrame::kYPlane),
+ source_frame->visible_data(media::VideoFrame::kUVPlane),
+ source_frame->stride(media::VideoFrame::kUVPlane),
+ source_frame->visible_rect().width(),
+ source_frame->visible_rect().height(),
+ dst_frame->data(media::VideoFrame::kYPlane),
+ dst_frame->stride(media::VideoFrame::kYPlane),
+ dst_frame->data(media::VideoFrame::kUPlane),
+ dst_frame->stride(media::VideoFrame::kUPlane),
+ dst_frame->data(media::VideoFrame::kVPlane),
+ dst_frame->stride(media::VideoFrame::kVPlane),
+ dst_frame->coded_size().width(), dst_frame->coded_size().height());
+ } break;
+ case media::PIXEL_FORMAT_ARGB: {
+ auto visible_size = source_frame->visible_rect().size();
+ if (visible_size == dst_frame->coded_size()) {
+ // Direct conversion to dst_frame with no scaling.
+ libyuv::ARGBToI420(
+ source_frame->visible_data(media::VideoFrame::kARGBPlane),
+ source_frame->stride(media::VideoFrame::kARGBPlane),
+ dst_frame->data(media::VideoFrame::kYPlane),
+ dst_frame->stride(media::VideoFrame::kYPlane),
+ dst_frame->data(media::VideoFrame::kUPlane),
+ dst_frame->stride(media::VideoFrame::kUPlane),
+ dst_frame->data(media::VideoFrame::kVPlane),
+ dst_frame->stride(media::VideoFrame::kVPlane), visible_size.width(),
+ visible_size.height());
+ } else {
+ // Convert to I420 tmp image and then scale to the dst_frame.
+ auto tmp_frame = shared_resources->CreateTemporaryFrame(
+ media::PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size),
+ visible_size, source_frame->timestamp());
+ libyuv::ARGBToI420(
+ source_frame->visible_data(media::VideoFrame::kARGBPlane),
+ source_frame->stride(media::VideoFrame::kARGBPlane),
+ tmp_frame->data(media::VideoFrame::kYPlane),
+ tmp_frame->stride(media::VideoFrame::kYPlane),
+ tmp_frame->data(media::VideoFrame::kUPlane),
+ tmp_frame->stride(media::VideoFrame::kUPlane),
+ tmp_frame->data(media::VideoFrame::kVPlane),
+ tmp_frame->stride(media::VideoFrame::kVPlane), visible_size.width(),
+ visible_size.height());
+ libyuv::I420Scale(
+ tmp_frame->data(media::VideoFrame::kYPlane),
+ tmp_frame->stride(media::VideoFrame::kYPlane),
+ tmp_frame->data(media::VideoFrame::kUPlane),
+ tmp_frame->stride(media::VideoFrame::kUPlane),
+ tmp_frame->data(media::VideoFrame::kVPlane),
+ tmp_frame->stride(media::VideoFrame::kVPlane), visible_size.width(),
+ visible_size.height(), dst_frame->data(media::VideoFrame::kYPlane),
+ dst_frame->stride(media::VideoFrame::kYPlane),
+ dst_frame->data(media::VideoFrame::kUPlane),
+ dst_frame->stride(media::VideoFrame::kUPlane),
+ dst_frame->data(media::VideoFrame::kVPlane),
+ dst_frame->stride(media::VideoFrame::kVPlane),
+ dst_frame->coded_size().width(), dst_frame->coded_size().height(),
+ libyuv::kFilterBilinear);
+ }
+ } break;
+ default:
+ NOTREACHED();
+ }
return dst_frame;
}
scoped_refptr<media::VideoFrame> MakeScaledNV12VideoFrame(
scoped_refptr<media::VideoFrame> source_frame,
- scoped_refptr<blink::WebRtcVideoFrameAdapter::BufferPoolOwner>
- scaled_frame_pool) {
- gfx::GpuMemoryBuffer* gmb = source_frame->GetGpuMemoryBuffer();
- if (!gmb || !gmb->Map()) {
- return nullptr;
- }
- // Crop to the visible rectangle specified in |source_frame|.
- const uint8_t* src_y = (reinterpret_cast<const uint8_t*>(gmb->memory(0)) +
- source_frame->visible_rect().x() +
- (source_frame->visible_rect().y() * gmb->stride(0)));
- const uint8_t* src_uv =
- (reinterpret_cast<const uint8_t*>(gmb->memory(1)) +
- ((source_frame->visible_rect().x() / 2) * 2) +
- ((source_frame->visible_rect().y() / 2) * gmb->stride(1)));
-
- auto dst_frame = scaled_frame_pool->CreateFrame(
+ scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+ shared_resources) {
+ DCHECK_EQ(source_frame->format(), media::PIXEL_FORMAT_NV12);
+ auto dst_frame = shared_resources->CreateFrame(
media::PIXEL_FORMAT_NV12, source_frame->natural_size(),
gfx::Rect(source_frame->natural_size()), source_frame->natural_size(),
source_frame->timestamp());
- dst_frame->metadata()->MergeMetadataFrom(source_frame->metadata());
+ dst_frame->metadata().MergeMetadataFrom(source_frame->metadata());
const auto& nv12_planes = dst_frame->layout().planes();
- libyuv::NV12Scale(src_y, gmb->stride(0), src_uv, gmb->stride(1),
+ libyuv::NV12Scale(source_frame->visible_data(media::VideoFrame::kYPlane),
+ source_frame->stride(media::VideoFrame::kYPlane),
+ source_frame->visible_data(media::VideoFrame::kUVPlane),
+ source_frame->stride(media::VideoFrame::kUVPlane),
source_frame->visible_rect().width(),
source_frame->visible_rect().height(),
dst_frame->data(media::VideoFrame::kYPlane),
@@ -305,42 +321,59 @@ scoped_refptr<media::VideoFrame> MakeScaledNV12VideoFrame(
nv12_planes[media::VideoFrame::kUVPlane].stride,
dst_frame->coded_size().width(),
dst_frame->coded_size().height(), libyuv::kFilterBox);
- gmb->Unmap();
return dst_frame;
}
-scoped_refptr<media::VideoFrame> ConstructVideoFrameFromGpu(
+scoped_refptr<media::VideoFrame> MaybeConvertAndScaleFrame(
scoped_refptr<media::VideoFrame> source_frame,
- scoped_refptr<blink::WebRtcVideoFrameAdapter::BufferPoolOwner>
- scaled_frame_pool) {
- CHECK(source_frame);
- CHECK(scaled_frame_pool);
- // NV12 is the only supported format.
- DCHECK_EQ(source_frame->format(), media::PIXEL_FORMAT_NV12);
- DCHECK_EQ(source_frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
-
- // Convert to I420 and scale to the natural size specified in |source_frame|.
- const bool dont_convert_nv12_image =
+ scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+ shared_resources) {
+ if (!source_frame)
+ return nullptr;
+ // Texture frames may be readback in ARGB format.
+ RTC_DCHECK(source_frame->format() == media::PIXEL_FORMAT_I420 ||
+ source_frame->format() == media::PIXEL_FORMAT_I420A ||
+ source_frame->format() == media::PIXEL_FORMAT_NV12 ||
+ source_frame->format() == media::PIXEL_FORMAT_ARGB);
+ RTC_DCHECK(shared_resources);
+
+ const bool allow_nv12_output =
base::FeatureList::IsEnabled(blink::features::kWebRtcLibvpxEncodeNV12);
- if (!dont_convert_nv12_image) {
- return MakeScaledI420VideoFrame(std::move(source_frame),
- std::move(scaled_frame_pool));
- } else if (source_frame->natural_size() ==
- source_frame->visible_rect().size()) {
- return WrapGmbVideoFrameForMappedMemoryAccess(std::move(source_frame));
- } else {
+ const bool source_is_i420 =
+ source_frame->format() == media::PIXEL_FORMAT_I420 ||
+ source_frame->format() == media::PIXEL_FORMAT_I420A;
+ const bool source_is_nv12 =
+ source_frame->format() == media::PIXEL_FORMAT_NV12;
+ const bool no_scaling_needed =
+ source_frame->natural_size() == source_frame->visible_rect().size();
+
+ if (((source_is_nv12 && allow_nv12_output) || source_is_i420) &&
+ no_scaling_needed) {
+ // |source_frame| already has correct pixel format and resolution.
+ return source_frame;
+ } else if (source_is_nv12 && allow_nv12_output) {
+ // Output NV12 only if it is allowed and no conversion is needed.
return MakeScaledNV12VideoFrame(std::move(source_frame),
- std::move(scaled_frame_pool));
+ std::move(shared_resources));
+ } else {
+ return MakeScaledI420VideoFrame(std::move(source_frame),
+ std::move(shared_resources));
}
}
+static void CreateContextProviderOnMainThread(
+ scoped_refptr<viz::RasterContextProvider>* result,
+ base::WaitableEvent* waitable_event) {
+ *result = blink::Platform::Current()->SharedCompositorWorkerContextProvider();
+ waitable_event->Signal();
+}
+
} // anonymous namespace
namespace blink {
scoped_refptr<media::VideoFrame>
-WebRtcVideoFrameAdapter::BufferPoolOwner::CreateFrame(
+WebRtcVideoFrameAdapter::SharedResources::CreateFrame(
media::VideoPixelFormat format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
@@ -350,9 +383,85 @@ WebRtcVideoFrameAdapter::BufferPoolOwner::CreateFrame(
timestamp);
}
-WebRtcVideoFrameAdapter::BufferPoolOwner::BufferPoolOwner() = default;
+scoped_refptr<media::VideoFrame>
+WebRtcVideoFrameAdapter::SharedResources::CreateTemporaryFrame(
+ media::VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp) {
+ return pool_for_tmp_frames_.CreateFrame(format, coded_size, visible_rect,
+ natural_size, timestamp);
+}
+
+scoped_refptr<viz::RasterContextProvider>
+WebRtcVideoFrameAdapter::SharedResources::GetRasterContextProvider() {
+ base::AutoLock auto_lock(context_provider_lock_);
+ if (raster_context_provider_) {
+ // Reuse created context provider if it's alive.
+ viz::RasterContextProvider::ScopedRasterContextLock lock(
+ raster_context_provider_.get());
+ if (lock.RasterInterface()->GetGraphicsResetStatusKHR() == GL_NO_ERROR)
+ return raster_context_provider_;
+ }
+
+ // Recreate the context provider.
+ base::WaitableEvent waitable_event;
+ PostCrossThreadTask(
+ *Thread::MainThread()->GetTaskRunner(), FROM_HERE,
+ CrossThreadBindOnce(&CreateContextProviderOnMainThread,
+ CrossThreadUnretained(&raster_context_provider_),
+ CrossThreadUnretained(&waitable_event)));
+
+ // This wait is necessary because this task is completed via main thread
+ // asynchronously but WebRTC API is synchronous.
+ base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
+ waitable_event.Wait();
+
+ return raster_context_provider_;
+}
+
+scoped_refptr<media::VideoFrame>
+WebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromTexture(
+ scoped_refptr<media::VideoFrame> source_frame) {
+ RTC_DCHECK(source_frame->HasTextures());
+
+ scoped_refptr<viz::RasterContextProvider> raster_context_provider =
+ GetRasterContextProvider();
+ if (!raster_context_provider) {
+ return nullptr;
+ }
+ viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
+ raster_context_provider.get());
-WebRtcVideoFrameAdapter::BufferPoolOwner::~BufferPoolOwner() = default;
+ auto* ri = scoped_context.RasterInterface();
+ auto* gr_context = raster_context_provider->GrContext();
+
+ if (!ri) {
+ return nullptr;
+ }
+
+ return media::ReadbackTextureBackedFrameToMemorySync(
+ *source_frame, ri, gr_context, &pool_for_mapped_frames_);
+}
+
+scoped_refptr<media::VideoFrame>
+WebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromGpu(
+ scoped_refptr<media::VideoFrame> source_frame) {
+ CHECK(source_frame);
+ // NV12 is the only supported format.
+ DCHECK_EQ(source_frame->format(), media::PIXEL_FORMAT_NV12);
+ DCHECK_EQ(source_frame->storage_type(),
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
+
+ return media::ConvertToMemoryMappedFrame(std::move(source_frame));
+}
+
+WebRtcVideoFrameAdapter::SharedResources::SharedResources(
+ media::GpuVideoAcceleratorFactories* gpu_factories)
+ : gpu_factories_(gpu_factories) {}
+
+WebRtcVideoFrameAdapter::SharedResources::~SharedResources() = default;
WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
scoped_refptr<media::VideoFrame> frame)
@@ -360,8 +469,8 @@ WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
scoped_refptr<media::VideoFrame> frame,
- scoped_refptr<BufferPoolOwner> scaled_frame_pool)
- : frame_(std::move(frame)), scaled_frame_pool_(scaled_frame_pool) {}
+ scoped_refptr<SharedResources> shared_resources)
+ : frame_(std::move(frame)), shared_resources_(shared_resources) {}
WebRtcVideoFrameAdapter::~WebRtcVideoFrameAdapter() {}
@@ -377,97 +486,63 @@ int WebRtcVideoFrameAdapter::height() const {
return frame_->natural_size().height();
}
+// static
+bool WebRtcVideoFrameAdapter::IsFrameAdaptable(const media::VideoFrame* frame) {
+ // Currently accept I420, I420A, NV12 formats in a mapped frame,
+ // or a texture or GPU memory buffer frame.
+ return (frame->IsMappable() &&
+ base::Contains(AdaptableMappablePixelFormats(), frame->format())) ||
+ frame->storage_type() ==
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER ||
+ frame->HasTextures();
+}
+
+// static
+const base::span<const media::VideoPixelFormat>
+WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats() {
+ static constexpr const media::VideoPixelFormat
+ kAdaptableMappablePixelFormats[] = {media::PIXEL_FORMAT_I420,
+ media::PIXEL_FORMAT_I420A,
+ media::PIXEL_FORMAT_NV12};
+ return base::make_span(kAdaptableMappablePixelFormats);
+}
+
rtc::scoped_refptr<webrtc::VideoFrameBuffer>
WebRtcVideoFrameAdapter::CreateFrameAdapter() const {
+ DCHECK(IsFrameAdaptable(frame_.get()))
+ << "Can not create WebRTC frame adapter for frame "
+ << frame_->AsHumanReadableString();
+
if (frame_->storage_type() ==
media::VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER) {
- auto video_frame = ConstructVideoFrameFromGpu(frame_, scaled_frame_pool_);
+ auto video_frame =
+ shared_resources_
+ ? shared_resources_->ConstructVideoFrameFromGpu(frame_)
+ : nullptr;
+ video_frame = MaybeConvertAndScaleFrame(video_frame, shared_resources_);
if (!video_frame) {
return MakeFrameAdapter(media::VideoFrame::CreateColorFrame(
frame_->natural_size(), 0u, 0x80, 0x80, frame_->timestamp()));
}
- // Keep |frame_| alive until |video_frame| is destroyed.
- video_frame->AddDestructionObserver(
- ConvertToBaseOnceCallback(CrossThreadBindOnce(
- base::DoNothing::Once<scoped_refptr<media::VideoFrame>>(),
- frame_)));
-
- IsValidFrame(*video_frame);
return MakeFrameAdapter(std::move(video_frame));
} else if (frame_->HasTextures()) {
- // We cant convert texture synchronously due to threading issues, see
- // https://crbug.com/663452. Instead, return a black frame (yuv = {0, 0x80,
- // 0x80}).
- DLOG(ERROR) << "Texture backed frame cannot be accessed.";
- return MakeFrameAdapter(media::VideoFrame::CreateColorFrame(
- frame_->natural_size(), 0u, 0x80, 0x80, frame_->timestamp()));
- }
- IsValidFrame(*frame_);
-
- // If the frame is a software frame then it can be in I420, I420A or NV12.
- // TODO(https://crbug.com/1169727): Move this check to somewhere else, and add
- // tests for all pixel formats.
- DCHECK(frame_->format() == media::PIXEL_FORMAT_NV12 ||
- frame_->format() == media::PIXEL_FORMAT_I420 ||
- frame_->format() == media::PIXEL_FORMAT_I420A)
- << "Can not scale software frame of format "
- << media::VideoPixelFormatToString(frame_->format());
+ auto video_frame =
+ shared_resources_
+ ? shared_resources_->ConstructVideoFrameFromTexture(frame_)
+ : nullptr;
+ video_frame = MaybeConvertAndScaleFrame(video_frame, shared_resources_);
+ if (!video_frame) {
+ DLOG(ERROR) << "Texture backed frame cannot be accessed.";
+ return MakeFrameAdapter(media::VideoFrame::CreateColorFrame(
+ frame_->natural_size(), 0u, 0x80, 0x80, frame_->timestamp()));
+ }
+ return MakeFrameAdapter(std::move(video_frame));
+ }
// Since scaling is required, hard-apply both the cropping and scaling
// before we hand the frame over to WebRTC.
- gfx::Size scaled_size = frame_->natural_size();
- scoped_refptr<media::VideoFrame> scaled_frame = frame_;
- if (scaled_size != frame_->visible_rect().size()) {
- CHECK(scaled_frame_pool_);
- scaled_frame = scaled_frame_pool_->CreateFrame(
- frame_->format(), scaled_size, gfx::Rect(scaled_size), scaled_size,
- frame_->timestamp());
-
- switch (frame_->format()) {
- case media::PIXEL_FORMAT_I420A:
- libyuv::ScalePlane(
- frame_->visible_data(media::VideoFrame::kAPlane),
- frame_->stride(media::VideoFrame::kAPlane),
- frame_->visible_rect().width(), frame_->visible_rect().height(),
- scaled_frame->data(media::VideoFrame::kAPlane),
- scaled_frame->stride(media::VideoFrame::kAPlane),
- scaled_size.width(), scaled_size.height(), libyuv::kFilterBilinear);
- // Fallthrough to I420 in order to scale the YUV planes as well.
- ABSL_FALLTHROUGH_INTENDED;
- case media::PIXEL_FORMAT_I420:
- libyuv::I420Scale(
- frame_->visible_data(media::VideoFrame::kYPlane),
- frame_->stride(media::VideoFrame::kYPlane),
- frame_->visible_data(media::VideoFrame::kUPlane),
- frame_->stride(media::VideoFrame::kUPlane),
- frame_->visible_data(media::VideoFrame::kVPlane),
- frame_->stride(media::VideoFrame::kVPlane),
- frame_->visible_rect().width(), frame_->visible_rect().height(),
- scaled_frame->data(media::VideoFrame::kYPlane),
- scaled_frame->stride(media::VideoFrame::kYPlane),
- scaled_frame->data(media::VideoFrame::kUPlane),
- scaled_frame->stride(media::VideoFrame::kUPlane),
- scaled_frame->data(media::VideoFrame::kVPlane),
- scaled_frame->stride(media::VideoFrame::kVPlane),
- scaled_size.width(), scaled_size.height(), libyuv::kFilterBilinear);
- break;
- case media::PIXEL_FORMAT_NV12:
- libyuv::NV12Scale(
- frame_->visible_data(media::VideoFrame::kYPlane),
- frame_->stride(media::VideoFrame::kYPlane),
- frame_->visible_data(media::VideoFrame::kUVPlane),
- frame_->stride(media::VideoFrame::kUVPlane),
- frame_->visible_rect().width(), frame_->visible_rect().height(),
- scaled_frame->data(media::VideoFrame::kYPlane),
- scaled_frame->stride(media::VideoFrame::kYPlane),
- scaled_frame->data(media::VideoFrame::kUVPlane),
- scaled_frame->stride(media::VideoFrame::kUVPlane),
- scaled_size.width(), scaled_size.height(), libyuv::kFilterBilinear);
- break;
- default:
- NOTREACHED();
- }
- }
+ scoped_refptr<media::VideoFrame> scaled_frame =
+ MaybeConvertAndScaleFrame(frame_, shared_resources_);
return MakeFrameAdapter(std::move(scaled_frame));
}
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h
index 954d4cbc353..c6cc8aa13f5 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h
+++ b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h
@@ -6,46 +6,104 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
#include <stdint.h>
+#include <map>
+#include "base/containers/span.h"
#include "base/memory/ref_counted.h"
-
#include "base/optional.h"
#include "base/synchronization/lock.h"
+#include "components/viz/common/gpu/raster_context_provider.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_pool.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/webrtc/api/video/video_frame_buffer.h"
+namespace media {
+class GpuVideoAcceleratorFactories;
+}
+
namespace blink {
// Thin adapter from media::VideoFrame to webrtc::VideoFrameBuffer. This
// implementation is read-only and will return null if trying to get a
// non-const pointer to the pixel data. This object will be accessed from
// different threads, but that's safe since it's read-only.
+//
+// 3 types of frames can be adapted, either,
+// - The frame is mappable in either I420, I420A or NV12 pixel formats.
+// - Or, the frame is on a GPU Memory Buffer in NV12.
+// - Or, the frame has textures.
+// Creators of WebRtcVideoFrameAdapter can ensure the frame is convertible by
+// calling |IsFrameAdaptable| before constructing this object.
class PLATFORM_EXPORT WebRtcVideoFrameAdapter
: public webrtc::VideoFrameBuffer {
public:
- class PLATFORM_EXPORT BufferPoolOwner
- : public base::RefCountedThreadSafe<BufferPoolOwner> {
+ class PLATFORM_EXPORT SharedResources
+ : public base::RefCountedThreadSafe<SharedResources> {
public:
- BufferPoolOwner();
+ explicit SharedResources(
+ media::GpuVideoAcceleratorFactories* gpu_factories);
+ // Create frames for requested output format and resolution.
scoped_refptr<media::VideoFrame> CreateFrame(media::VideoPixelFormat format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp);
+ // Temporary frames may have a different format or size than scaled frames.
+ // However, VideoFramePool doesn't work nicely if the requested frame size
+ // or format changes on the fly. Therefore a separate pool is used for
+ // temporary frames.
+ scoped_refptr<media::VideoFrame> CreateTemporaryFrame(
+ media::VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp);
+
+ scoped_refptr<viz::RasterContextProvider> GetRasterContextProvider();
+
+ // Constructs a VideoFrame from a texture by invoking RasterInterface,
+ // which would perform a blocking call to a GPU process.
+ // The pixel data is copied and may be in ARGB pixel format in some cases,
+ // So additional conversion to I420 would be needed.
+ virtual scoped_refptr<media::VideoFrame> ConstructVideoFrameFromTexture(
+ scoped_refptr<media::VideoFrame> source_frame);
+
+ // Constructs a VideoFrame from a GMB. Unless it's a Windows DXGI GMB,
+ // the buffer is mapped to the memory and wrapped by a VideoFrame with no
+ // copies. For DXGI buffers a blocking call to GPU process is made to
+ // copy pixel data.
+ virtual scoped_refptr<media::VideoFrame> ConstructVideoFrameFromGpu(
+ scoped_refptr<media::VideoFrame> source_frame);
+
+ protected:
+ friend class base::RefCountedThreadSafe<SharedResources>;
+ virtual ~SharedResources();
+
private:
- friend class base::RefCountedThreadSafe<BufferPoolOwner>;
- ~BufferPoolOwner();
media::VideoFramePool pool_;
+ media::VideoFramePool pool_for_mapped_frames_;
+ media::VideoFramePool pool_for_tmp_frames_;
+
+ scoped_refptr<viz::RasterContextProvider> raster_context_provider_
+ GUARDED_BY(context_provider_lock_);
+
+ media::GpuVideoAcceleratorFactories* gpu_factories_;
+
+ mutable base::Lock context_provider_lock_;
};
+ // Returns true if |frame| is adaptable to a webrtc::VideoFrameBuffer.
+ static bool IsFrameAdaptable(const media::VideoFrame* frame);
+ static const base::span<const media::VideoPixelFormat>
+ AdaptableMappablePixelFormats();
+
explicit WebRtcVideoFrameAdapter(scoped_refptr<media::VideoFrame> frame);
WebRtcVideoFrameAdapter(scoped_refptr<media::VideoFrame> frame,
- scoped_refptr<BufferPoolOwner> scaled_buffer_pool);
+ scoped_refptr<SharedResources> shared_resources);
scoped_refptr<media::VideoFrame> getMediaVideoFrame() const { return frame_; }
@@ -73,7 +131,9 @@ class PLATFORM_EXPORT WebRtcVideoFrameAdapter
scoped_refptr<media::VideoFrame> frame_;
- mutable scoped_refptr<BufferPoolOwner> scaled_frame_pool_;
+ mutable scoped_refptr<SharedResources> shared_resources_;
+
+ media::GpuVideoAcceleratorFactories* gpu_factories_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc
index 54b50eeac52..5dbc1e143b9 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc
+++ b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc
@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "base/strings/strcat.h"
#include "base/test/scoped_feature_list.h"
#include "media/base/video_frame.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/platform/testing/video_frame_utils.h"
@@ -13,75 +15,119 @@
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
#include "ui/gfx/gpu_memory_buffer.h"
+using ::testing::_;
+using ::testing::Return;
+
namespace blink {
-namespace {
+class MockSharedResources : public WebRtcVideoFrameAdapter::SharedResources {
+ public:
+ MockSharedResources() : WebRtcVideoFrameAdapter::SharedResources(nullptr) {}
+
+ MOCK_METHOD(scoped_refptr<media::VideoFrame>,
+ CreateFrame,
+ (media::VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp));
+
+ MOCK_METHOD(scoped_refptr<media::VideoFrame>,
+ CreateTemporaryFrame,
+ (media::VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp));
+
+ MOCK_METHOD(scoped_refptr<viz::RasterContextProvider>,
+ GetRasterContextProvider,
+ ());
+
+ MOCK_METHOD(scoped_refptr<media::VideoFrame>,
+ ConstructVideoFrameFromTexture,
+ (scoped_refptr<media::VideoFrame> source_frame));
+
+ MOCK_METHOD(scoped_refptr<media::VideoFrame>,
+ ConstructVideoFrameFromGpu,
+ (scoped_refptr<media::VideoFrame> source_frame));
+
+ private:
+ friend class base::RefCountedThreadSafe<MockSharedResources>;
+};
+
+class WebRtcVideoFrameAdapterParamTest
+ : public ::testing::TestWithParam<
+ std::tuple<media::VideoFrame::StorageType, media::VideoPixelFormat>> {
+ public:
+ WebRtcVideoFrameAdapterParamTest()
+ : resources_(new WebRtcVideoFrameAdapter::SharedResources(nullptr)) {}
+
+ protected:
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources_;
+};
-scoped_refptr<media::VideoFrame> CreateTestMemoryFrame(
- const gfx::Size& coded_size,
- const gfx::Rect& visible_rect,
- const gfx::Size& natural_size,
- media::VideoPixelFormat pixel_format) {
- return media::VideoFrame::CreateFrame(pixel_format, coded_size, visible_rect,
- natural_size, base::TimeDelta());
+namespace {
+std::vector<WebRtcVideoFrameAdapterParamTest::ParamType> TestParams() {
+ std::vector<WebRtcVideoFrameAdapterParamTest::ParamType> test_params;
+ // All formats for owned memory.
+ for (media::VideoPixelFormat format :
+ WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
+ test_params.emplace_back(
+ media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY, format);
+ }
+ test_params.emplace_back(
+ media::VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ return test_params;
}
-
} // namespace
-TEST(WebRtcVideoFrameAdapterTest, WidthAndHeight) {
+TEST_P(WebRtcVideoFrameAdapterParamTest, WidthAndHeight) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
-
- // The adapter should report width and height from the natural size for
- // VideoFrame backed by owned memory.
- auto owned_memory_frame =
- CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoFrame::STORAGE_OWNED_MEMORY);
- rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- std::move(owned_memory_frame), pool));
- EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
- EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
- // The adapter should report width and height from the natural size for
- // VideoFrame backed by GpuMemoryBuffer.
- auto gmb_frame =
- CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
- rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(gmb_frame),
- pool));
- EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
- EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
+ media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
+ scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
+ kCodedSize, kVisibleRect, kNaturalSize, storage_type, pixel_format);
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter =
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(frame),
+ resources_);
+ EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
+ EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
}
-TEST(WebRtcVideoFrameAdapterTest, ToI420DownScale) {
+TEST_P(WebRtcVideoFrameAdapterParamTest, ToI420) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
- // The adapter should report width and height from the natural size for
- // VideoFrame backed by owned memory.
- auto owned_memory_frame =
- CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoFrame::STORAGE_OWNED_MEMORY);
- rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- std::move(owned_memory_frame), pool));
- EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
- EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
+ media::VideoFrame::StorageType storage_type = std::get<0>(GetParam());
+ media::VideoPixelFormat pixel_format = std::get<1>(GetParam());
+ scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
+ kCodedSize, kVisibleRect, kNaturalSize, storage_type, pixel_format);
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter =
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(frame),
+ resources_);
- // The I420 frame should have the same size as the natural size
- auto i420_frame = owned_memory_frame_adapter->ToI420();
+ // The I420 frame should have the same size as the natural size.
+ auto i420_frame = frame_adapter->ToI420();
EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
}
+INSTANTIATE_TEST_CASE_P(
+ WebRtcVideoFrameAdapterParamTest,
+ WebRtcVideoFrameAdapterParamTest,
+ ::testing::ValuesIn(TestParams()),
+ [](const auto& info) {
+ return base::StrCat(
+ {media::VideoFrame::StorageTypeToString(std::get<0>(info.param)), "_",
+ media::VideoPixelFormatToString(std::get<1>(info.param))});
+ });
+
TEST(WebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
base::test::ScopedFeatureList scoped_feautre_list;
scoped_feautre_list.InitAndDisableFeature(
@@ -89,8 +135,8 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
auto gmb_frame =
CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
@@ -99,7 +145,7 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
// VideoFrame backed by GpuMemoryBuffer.
rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(gmb_frame),
- pool));
+ resources));
EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
@@ -118,17 +164,18 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420ADownScale) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
// The adapter should report width and height from the natural size for
// VideoFrame backed by owned memory.
auto owned_memory_frame =
- CreateTestMemoryFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoPixelFormat::PIXEL_FORMAT_I420A);
+ CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::VideoPixelFormat::PIXEL_FORMAT_I420A);
rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- std::move(owned_memory_frame), pool));
+ std::move(owned_memory_frame), resources));
EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -148,8 +195,8 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12WrapsGmbWhenNoScalingNeeededWithFeature) {
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
// Same size as visible rect so no scaling.
const gfx::Size kNaturalSize = kVisibleRect.size();
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
auto gmb_frame =
CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
@@ -158,7 +205,7 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12WrapsGmbWhenNoScalingNeeededWithFeature) {
// The adapter should report width and height from the natural size for
// VideoFrame backed by GpuMemoryBuffer.
rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, pool));
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, resources));
EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
@@ -189,8 +236,8 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12ScalesGmbWithFeature) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
auto gmb_frame =
CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
@@ -199,7 +246,7 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12ScalesGmbWithFeature) {
// The adapter should report width and height from the natural size for
// VideoFrame backed by GpuMemoryBuffer.
rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, pool));
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, resources));
EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
@@ -227,17 +274,18 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12OwnedMemoryFrame) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize = kVisibleRect.size();
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
// The adapter should report width and height from the natural size for
// VideoFrame backed by owned memory.
auto owned_memory_frame =
- CreateTestMemoryFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- std::move(owned_memory_frame), pool));
+ std::move(owned_memory_frame), resources));
EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -255,17 +303,18 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12ScaleOwnedMemoryFrame) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
- scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
- new WebRtcVideoFrameAdapter::BufferPoolOwner();
+ scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
+ new WebRtcVideoFrameAdapter::SharedResources(nullptr);
// The adapter should report width and height from the natural size for
// VideoFrame backed by owned memory.
auto owned_memory_frame =
- CreateTestMemoryFrame(kCodedSize, kVisibleRect, kNaturalSize,
- media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
- std::move(owned_memory_frame), pool));
+ std::move(owned_memory_frame), resources));
EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -279,4 +328,71 @@ TEST(WebRtcVideoFrameAdapterTest, Nv12ScaleOwnedMemoryFrame) {
EXPECT_EQ(nv12_frame->height(), kNaturalSize.height());
}
+TEST(WebRtcVideoFrameAdapterTest, TextureFrameIsBlackWithNoSharedResources) {
+ const gfx::Size kCodedSize(1280, 960);
+ const gfx::Rect kVisibleRect(0, 120, 1280, 720);
+ const gfx::Size kNaturalSize(640, 360);
+
+ // The adapter should report width and height from the natural size for
+ // VideoFrame backed by owned memory.
+ auto owned_memory_frame = CreateTestFrame(
+ kCodedSize, kVisibleRect, kNaturalSize, media::VideoFrame::STORAGE_OPAQUE,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter(
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+ std::move(owned_memory_frame), nullptr));
+ EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
+ EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
+
+ // The NV12 frame should have the same size as the natural size, but be black
+ // since we can't handle the texture with no shared resources.
+ auto i420_frame = frame_adapter->ToI420();
+ ASSERT_TRUE(i420_frame);
+ EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
+ EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
+ EXPECT_EQ(0x0, i420_frame->DataY()[0]);
+ EXPECT_EQ(0x80, i420_frame->DataU()[0]);
+ EXPECT_EQ(0x80, i420_frame->DataV()[0]);
+}
+
+TEST(WebRtcVideoFrameAdapterTest, ConvertsTextureFrameWithSharedResources) {
+ const gfx::Size kCodedSize(1280, 960);
+ const gfx::Rect kVisibleRect(0, 120, 1280, 720);
+ const gfx::Size kNaturalSize(640, 360);
+
+ scoped_refptr<MockSharedResources> resources =
+ base::MakeRefCounted<MockSharedResources>();
+
+ // The adapter should report width and height from the natural size for
+ // VideoFrame backed by owned memory.
+ auto owned_memory_frame = CreateTestFrame(
+ kCodedSize, kVisibleRect, kNaturalSize, media::VideoFrame::STORAGE_OPAQUE,
+ media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter(
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+ std::move(owned_memory_frame), resources));
+ EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
+ EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
+
+ scoped_refptr<media::VideoFrame> memory_frame =
+ CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
+ media::VideoFrame::STORAGE_OWNED_MEMORY,
+ media::VideoPixelFormat::PIXEL_FORMAT_ARGB);
+ // fill mock image with whilte color.
+ memset(memory_frame->data(media::VideoFrame::kARGBPlane), 0xFF,
+ kCodedSize.GetArea() * 4);
+
+ // Should call texture conversion.
+ EXPECT_CALL(*resources, ConstructVideoFrameFromTexture(_))
+ .WillOnce(Return(memory_frame));
+
+ // The NV12 frame should have the same size as the natural size, but be black
+ // since we can't handle the texture with no shared resources.
+ auto i420_frame = frame_adapter->ToI420();
+ ASSERT_TRUE(i420_frame);
+ EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
+ EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
+ // Returned memory frame should not be replaced by a black frame.
+ EXPECT_NE(0x0, i420_frame->DataY()[0]);
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.cc b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.cc
index 64a9fbbfc7b..46396ecf4ed 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.cc
+++ b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.cc
@@ -21,6 +21,19 @@ media::VideoRotation WebRtcToMediaVideoRotation(
return media::VIDEO_ROTATION_0;
}
+media::VideoCodec WebRtcToMediaVideoCodec(webrtc::VideoCodecType codec) {
+ switch (codec) {
+ case webrtc::kVideoCodecVP8:
+ return media::kCodecVP8;
+ case webrtc::kVideoCodecVP9:
+ return media::kCodecVP9;
+ case webrtc::kVideoCodecH264:
+ return media::kCodecH264;
+ default:
+ return media::kUnknownVideoCodec;
+ }
+}
+
media::VideoColorSpace WebRtcToMediaVideoColorSpace(
const webrtc::ColorSpace& color_space) {
media::VideoColorSpace::PrimaryID primaries =
diff --git a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h
index 758293439a4..ba5c3552ae1 100644
--- a/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h
+++ b/chromium/third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h
@@ -5,10 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_UTILS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_UTILS_H_
+#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
#include "media/base/video_transformation.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/webrtc/api/video/color_space.h"
+#include "third_party/webrtc/api/video/video_codec_type.h"
#include "third_party/webrtc/api/video/video_rotation.h"
namespace blink {
@@ -19,6 +21,9 @@ namespace blink {
media::VideoRotation PLATFORM_EXPORT
WebRtcToMediaVideoRotation(webrtc::VideoRotation rotation);
+media::VideoCodec PLATFORM_EXPORT
+WebRtcToMediaVideoCodec(webrtc::VideoCodecType codec);
+
media::VideoColorSpace PLATFORM_EXPORT
WebRtcToMediaVideoColorSpace(const webrtc::ColorSpace& color_space);
diff --git a/chromium/third_party/blink/renderer/platform/widget/DEPS b/chromium/third_party/blink/renderer/platform/widget/DEPS
index 1a5525e003e..9c7456d526f 100644
--- a/chromium/third_party/blink/renderer/platform/widget/DEPS
+++ b/chromium/third_party/blink/renderer/platform/widget/DEPS
@@ -1,16 +1,15 @@
include_rules = [
- "+cc/mojo_embedder/async_layer_tree_frame_sink.h",
- "+cc/paint/element_id.h",
- "+cc/trees/browser_controls_params.h",
- "+cc/trees/latency_info_swap_promise_monitor.h",
- "+cc/trees/layer_tree_host.h",
- "+cc/trees/layer_tree_settings.h",
- "+cc/trees/ukm_manager.h",
+ "+cc",
+ "-cc/ipc",
+ "-cc/mojom",
+ "-cc/test",
"+components/viz/common",
"+gpu/command_buffer/client/shared_memory_limits.h",
"+gpu/command_buffer/common/context_creation_attribs.h",
"+gpu/ipc/client/gpu_channel_host.h",
"+services/viz/public/cpp/gpu/context_provider_command_buffer.h",
+ "+services/viz/public/mojom/compositing/delegated_ink_metadata.mojom-blink.h",
+ "+services/viz/public/mojom/compositing/frame_sink_id.mojom-blink.h",
"+ui/base/ime/text_input_mode.h",
"+ui/base/ime/text_input_type.h",
"+ui/base/ime/mojom/text_input_state.mojom-blink.h",
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/BUILD.gn b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/BUILD.gn
index 1acdc30c0ef..1fec93fab74 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/BUILD.gn
@@ -11,6 +11,10 @@ blink_platform_sources("android_webview") {
"synchronous_layer_tree_frame_sink.h",
]
- # TODO(crbug.com/805739): This should not be depended on from the renderer.
- deps = [ "//components/viz/service" ]
+ deps = [
+ "//components/power_scheduler",
+
+ # TODO(crbug.com/805739): This should not be depended on from the renderer.
+ "//components/viz/service",
+ ]
}
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/DEPS b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/DEPS
index 4d7eaf7c1c0..88159ae2666 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/DEPS
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+base/cancelable_callback.h",
+ "+components/power_scheduler",
"+components/viz/service/display",
"+components/viz/service/display_embedder",
"+components/viz/service/frame_sinks",
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
index 52c9b962da8..64c247e52e3 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
@@ -16,6 +16,9 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/features.h"
#include "components/viz/common/gpu/context_provider.h"
@@ -159,7 +162,10 @@ SynchronousLayerTreeFrameSink::SynchronousLayerTreeFrameSink(
features::IsUsingVizFrameSubmissionForWebView()),
use_zero_copy_sw_draw_(
Platform::Current()
- ->IsZeroCopySynchronousSwDrawEnabledForAndroidWebView()) {
+ ->IsZeroCopySynchronousSwDrawEnabledForAndroidWebView()),
+ animation_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Animation")) {
DCHECK(registry_);
DETACH_FROM_THREAD(thread_checker_);
memory_policy_.priority_cutoff_when_visible =
@@ -392,9 +398,14 @@ void SynchronousLayerTreeFrameSink::SubmitCompositorFrame(
}
// NOTE: submit_frame will be empty if viz_frame_submission_enabled_ enabled,
// but it won't be used upstream
- sync_client_->SubmitCompositorFrame(layer_tree_frame_sink_id_,
- std::move(submit_frame),
- client_->BuildHitTestData());
+ // Because OnDraw can synchronously override the viewport without going
+ // through commit and activation, we generate our own LocalSurfaceId by
+ // checking the submitted frame instead of using the one set here.
+ sync_client_->SubmitCompositorFrame(
+ layer_tree_frame_sink_id_,
+ viz_frame_submission_enabled_ ? local_surface_id_
+ : child_local_surface_id_,
+ std::move(submit_frame), client_->BuildHitTestData());
did_submit_frame_ = true;
}
@@ -429,11 +440,16 @@ void SynchronousLayerTreeFrameSink::Invalidate(bool needs_draw) {
void SynchronousLayerTreeFrameSink::DemandDrawHw(
const gfx::Size& viewport_size,
const gfx::Rect& viewport_rect_for_tile_priority,
- const gfx::Transform& transform_for_tile_priority) {
+ const gfx::Transform& transform_for_tile_priority,
+ bool need_new_local_surface_id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(HasClient());
DCHECK(context_provider_.get());
+ if (need_new_local_surface_id) {
+ child_local_surface_id_ = viz::LocalSurfaceId();
+ }
+
client_->SetExternalTilePriorityConstraints(viewport_rect_for_tile_priority,
transform_for_tile_priority);
InvokeComposite(gfx::Transform(), gfx::Rect(viewport_size));
@@ -577,6 +593,18 @@ void SynchronousLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
void SynchronousLayerTreeFrameSink::OnNeedsBeginFrames(
bool needs_begin_frames) {
+ if (needs_begin_frames_ != needs_begin_frames) {
+ if (needs_begin_frames) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames",
+ this);
+ animation_power_mode_voter_->VoteFor(
+ power_scheduler::PowerMode::kAnimation);
+ } else {
+ TRACE_EVENT_NESTABLE_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
+ animation_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kAnimationTimeout);
+ }
+ }
needs_begin_frames_ = needs_begin_frames;
if (sync_client_) {
sync_client_->SetNeedsBeginFrames(needs_begin_frames);
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h
index 8a5436649c7..e47177e3349 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h
@@ -19,6 +19,7 @@
#include "base/threading/thread_checker.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/managed_memory_policy.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_timing_details_map.h"
@@ -56,6 +57,7 @@ class SynchronousLayerTreeFrameSinkClient {
virtual void Invalidate(bool needs_draw) = 0;
virtual void SubmitCompositorFrame(
uint32_t layer_tree_frame_sink_id,
+ const viz::LocalSurfaceId& local_surface_id,
base::Optional<viz::CompositorFrame> frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) = 0;
virtual void SetNeedsBeginFrames(bool needs_begin_frames) = 0;
@@ -128,7 +130,8 @@ class SynchronousLayerTreeFrameSink
const Vector<viz::ReturnedResource>& resources);
void DemandDrawHw(const gfx::Size& viewport_size,
const gfx::Rect& viewport_rect_for_tile_priority,
- const gfx::Transform& transform_for_tile_priority);
+ const gfx::Transform& transform_for_tile_priority,
+ bool need_new_local_surface_id);
void DemandDrawSw(SkCanvas* canvas);
void DemandDrawSwZeroCopy();
void WillSkipDraw();
@@ -221,6 +224,8 @@ class SynchronousLayerTreeFrameSink
bool needs_begin_frames_ = false;
const bool use_zero_copy_sw_draw_;
+ std::unique_ptr<power_scheduler::PowerModeVoter> animation_power_mode_voter_;
+
DISALLOW_COPY_AND_ASSIGN(SynchronousLayerTreeFrameSink);
};
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
index 151ecd87db4..2c8e7445e92 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
@@ -158,8 +158,6 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
const base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess();
cc::LayerTreeSettings settings;
- settings.force_preferred_interval_for_video =
- ::features::IsForcePreferredIntervalForVideoEnabled();
settings.enable_synchronized_scrolling =
base::FeatureList::IsEnabled(::features::kSynchronizedScrolling);
Platform* platform = Platform::Current();
@@ -236,7 +234,7 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
default_tile_size += 32;
if (default_tile_size == 384 && std::abs(portrait_width - 1200) < tolerance)
default_tile_size += 32;
-#elif BUILDFLAG(IS_ASH) || defined(OS_MAC)
+#elif BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC)
// Use 512 for high DPI (dsf=2.0f) devices.
if (initial_device_scale_factor >= 2.0f)
default_tile_size = 512;
@@ -358,6 +356,14 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
cmd.HasSwitch(cc::switches::kShowScreenSpaceRects);
settings.initial_debug_state.highlight_non_lcd_text_layers =
cmd.HasSwitch(cc::switches::kHighlightNonLCDTextLayers);
+ settings.initial_debug_state.show_web_vital_metrics =
+ base::FeatureList::IsEnabled(
+ ::features::kHudDisplayForPerformanceMetrics) &&
+ !for_child_local_root_frame;
+ settings.initial_debug_state.show_smoothness_metrics =
+ base::FeatureList::IsEnabled(
+ ::features::kHudDisplayForPerformanceMetrics) &&
+ !for_child_local_root_frame;
settings.initial_debug_state.SetRecordRenderingStats(
cmd.HasSwitch(cc::switches::kEnableGpuBenchmarking));
@@ -437,8 +443,7 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
settings.scrollbar_fade_duration = ui::kOverlayScrollbarFadeDuration;
settings.scrollbar_thinning_duration =
ui::kOverlayScrollbarThinningDuration;
- settings.scrollbar_flash_after_any_scroll_update =
- ui::OverlayScrollbarFlashAfterAnyScrollUpdate();
+ settings.scrollbar_flash_after_any_scroll_update = true;
}
// If there's over 4GB of RAM, increase the working set size to 256MB for both
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
index 02136f9294c..2e2d744e031 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
@@ -28,6 +28,7 @@
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/input/layer_selection_bound.h"
#include "cc/layers/layer.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_mutator.h"
#include "cc/trees/render_frame_metadata_observer.h"
@@ -205,26 +206,11 @@ void LayerTreeView::ApplyViewportChanges(
delegate_->ApplyViewportChanges(args);
}
-void LayerTreeView::RecordManipulationTypeCounts(cc::ManipulationInfo info) {
+void LayerTreeView::UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) {
if (!delegate_)
return;
- delegate_->RecordManipulationTypeCounts(info);
-}
-
-void LayerTreeView::SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) {
- if (!delegate_)
- return;
- delegate_->SendOverscrollEventFromImplSide(overscroll_delta,
- scroll_latched_element_id);
-}
-
-void LayerTreeView::SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) {
- if (!delegate_)
- return;
- delegate_->SendScrollEndEventFromImplSide(scroll_latched_element_id);
+ delegate_->UpdateCompositorScrollState(commit_data);
}
void LayerTreeView::RequestNewLayerTreeFrameSink() {
@@ -327,6 +313,12 @@ LayerTreeView::GetBeginMainFrameMetrics() {
return delegate_->GetBeginMainFrameMetrics();
}
+std::unique_ptr<cc::WebVitalMetrics> LayerTreeView::GetWebVitalMetrics() {
+ if (!delegate_)
+ return nullptr;
+ return delegate_->GetWebVitalMetrics();
+}
+
void LayerTreeView::NotifyThroughputTrackerResults(
cc::CustomTrackerResults results) {
NOTREACHED();
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
index d8c20a962eb..53d47b2e536 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
@@ -79,12 +79,8 @@ class PLATFORM_EXPORT LayerTreeView
void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override;
void UpdateLayerTreeHost() override;
void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override;
- void RecordManipulationTypeCounts(cc::ManipulationInfo info) override;
- void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) override;
- void SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) override;
+ void UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) override;
void RequestNewLayerTreeFrameSink() override;
void DidInitializeLayerTreeFrameSink() override;
void DidFailToInitializeLayerTreeFrameSink() override;
@@ -102,6 +98,7 @@ class PLATFORM_EXPORT LayerTreeView
cc::ActiveFrameSequenceTrackers trackers) override;
std::unique_ptr<cc::BeginMainFrameMetrics> GetBeginMainFrameMetrics()
override;
+ std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() override;
void NotifyThroughputTrackerResults(
cc::CustomTrackerResults results) override;
void DidObserveFirstScrollDelay(
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
index 52e3cdb0172..d21c055aa9e 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
@@ -14,7 +14,7 @@
namespace cc {
class LayerTreeFrameSink;
struct BeginMainFrameMetrics;
-struct ElementId;
+struct WebVitalMetrics;
class RenderFrameMetadataObserver;
} // namespace cc
@@ -33,20 +33,8 @@ class LayerTreeViewDelegate {
virtual void ApplyViewportChanges(
const cc::ApplyViewportChangesArgs& args) = 0;
- // Record use counts of different methods of scrolling (e.g. wheel, touch,
- // precision touchpad, etc.).
- virtual void RecordManipulationTypeCounts(cc::ManipulationInfo info) = 0;
-
- // Send overscroll DOM event when overscrolling has happened on the compositor
- // thread.
- virtual void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) = 0;
-
- // Send scrollend DOM event when gesture scrolling on the compositor thread
- // has finished.
- virtual void SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) = 0;
+ virtual void UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) = 0;
// Notifies that the compositor has issued a BeginMainFrame.
virtual void BeginMainFrame(base::TimeTicks frame_time) = 0;
@@ -101,6 +89,8 @@ class LayerTreeViewDelegate {
virtual std::unique_ptr<cc::BeginMainFrameMetrics>
GetBeginMainFrameMetrics() = 0;
+ virtual std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() = 0;
+
// Notification of the beginning and end of LayerTreeHost::UpdateLayers, for
// metrics collection.
virtual void BeginUpdateLayers() = 0;
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.cc
index 46091976b36..bc762f8bec1 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.cc
@@ -54,6 +54,8 @@ cc::SwapPromise::DidNotSwapAction QueueReportTimeSwapPromise::DidNotSwap(
std::move(drain_callback_).Run(source_frame_number_);
if (swap_callback_)
std::move(swap_callback_).Run();
+ } else if (reason == cc::SwapPromise::COMMIT_FAILS) {
+ return DidNotSwapAction::KEEP_ACTIVE;
}
return DidNotSwapAction::BREAK_PROMISE;
}
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/render_frame_metadata_observer_impl.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/render_frame_metadata_observer_impl.cc
index 101e6e5cbfa..775bafa7151 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/render_frame_metadata_observer_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/render_frame_metadata_observer_impl.cc
@@ -161,7 +161,7 @@ bool RenderFrameMetadataObserverImpl::ShouldSendRenderFrameMetadata(
rfm1.page_scale_factor != rfm2.page_scale_factor ||
rfm1.external_page_scale_factor != rfm2.external_page_scale_factor ||
rfm1.is_mobile_optimized != rfm2.is_mobile_optimized ||
- rfm1.has_delegated_ink_metadata != rfm2.has_delegated_ink_metadata ||
+ rfm1.delegated_ink_metadata != rfm2.delegated_ink_metadata ||
rfm1.device_scale_factor != rfm2.device_scale_factor ||
rfm1.viewport_size_in_pixels != rfm2.viewport_size_in_pixels ||
rfm1.top_controls_height != rfm2.top_controls_height ||
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc
index 96e364f5f16..86b891d6c81 100644
--- a/chromium/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc
@@ -77,8 +77,8 @@ class WidgetCompositorTest : public cc::LayerTreeTest {
ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
widget_base_ = std::make_unique<WidgetBase>(
- &client_, widget_host_remote.Unbind(), std::move(widget_receiver),
- base::ThreadTaskRunnerHandle::Get(),
+ /*widget_base_client=*/&client_, widget_host_remote.Unbind(),
+ std::move(widget_receiver), base::ThreadTaskRunnerHandle::Get(),
/*is_hidden=*/false,
/*never_composited=*/false,
/*is_for_child_local_root=*/false);
diff --git a/chromium/third_party/blink/renderer/platform/widget/frame_widget.h b/chromium/third_party/blink/renderer/platform/widget/frame_widget.h
index d854f641622..914d2847bd2 100644
--- a/chromium/third_party/blink/renderer/platform/widget/frame_widget.h
+++ b/chromium/third_party/blink/renderer/platform/widget/frame_widget.h
@@ -5,25 +5,37 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_FRAME_WIDGET_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_FRAME_WIDGET_H_
+#include "cc/input/layer_selection_bound.h"
#include "mojo/public/mojom/base/text_direction.mojom-blink.h"
+#include "services/viz/public/mojom/compositing/delegated_ink_metadata.mojom-blink.h"
+#include "services/viz/public/mojom/compositing/frame_sink_id.mojom-blink.h"
#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom-blink.h"
#include "third_party/blink/public/platform/web_text_input_info.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_swap_result.h"
-#include "third_party/blink/public/web/web_widget_client.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "ui/base/ime/mojom/text_input_state.mojom-blink.h"
#include "ui/base/ime/mojom/virtual_keyboard_types.mojom-blink.h"
namespace cc {
class AnimationHost;
+enum class EventListenerClass;
+enum class EventListenerProperties;
class Layer;
+class LayerTreeSettings;
+class LayerTreeDebugState;
class PaintImage;
+struct ElementId;
} // namespace cc
+namespace ui {
+class Cursor;
+} // namespace ui
+
namespace blink {
+struct ScreenInfo;
// In interface exposed within Blink from local root frames that provides
// local-root specific things related to compositing and input. This
@@ -31,13 +43,9 @@ namespace blink {
// on this class occur on the main thread. input/FrameWidgetInputHandlerImpl
// which also implements the FrameWidgetInputHandler interface runs on the
// compositor thread and proxies calls to this class.
-class PLATFORM_EXPORT FrameWidget
- : public mojom::blink::FrameWidgetInputHandler {
+class PLATFORM_EXPORT FrameWidget {
public:
- ~FrameWidget() override;
-
- // Returns the WebWidgetClient, which is implemented outside of blink.
- virtual WebWidgetClient* Client() const = 0;
+ virtual ~FrameWidget();
// Returns the compositors's AnimationHost for the widget.
virtual cc::AnimationHost* AnimationHost() const = 0;
@@ -47,8 +55,8 @@ class PLATFORM_EXPORT FrameWidget
virtual void SetOverscrollBehavior(
const cc::OverscrollBehavior& overscroll_behavior) = 0;
- // Posts a task with the given delay, then calls ScheduleAnimation() on the
- // Client().
+ // Posts a task with the given delay, then requests an animation frame from
+ // the compositor (ie LayerTreeHost::SetNeedsAnimate()).
virtual void RequestAnimationAfterDelay(const base::TimeDelta&) = 0;
// Sets the root layer. The |layer| can be null when detaching the root layer.
@@ -66,8 +74,7 @@ class PLATFORM_EXPORT FrameWidget
// The |callback| will be fired when the corresponding renderer frame is
// submitted (still called "swapped") to the display compositor (either with
// DidSwap or DidNotSwap).
- virtual void NotifySwapAndPresentationTimeInBlink(
- WebReportTimeCallback swap_callback,
+ virtual void NotifyPresentationTimeInBlink(
WebReportTimeCallback presentation_callback) = 0;
// Enable or disable BeginMainFrameNotExpected signals from the compositor,
@@ -78,6 +85,15 @@ class PLATFORM_EXPORT FrameWidget
// purposes.
virtual int GetLayerTreeId() = 0;
+ // Return the LayerTreeSettings from the compositor. These are constant from
+ // the time the compositor is created.
+ virtual const cc::LayerTreeSettings& GetLayerTreeSettings() = 0;
+
+ // Sets the state of the browser controls. (Used for URL bar animations.)
+ virtual void UpdateBrowserControlsState(cc::BrowserControlsState constraints,
+ cc::BrowserControlsState current,
+ bool animate) = 0;
+
// Set or get what event handlers exist in the document contained in the
// WebWidget in order to inform the compositor thread if it is able to handle
// an input event, or it needs to pass it to the main thread to be handled.
@@ -110,7 +126,7 @@ class PLATFORM_EXPORT FrameWidget
// ScrollableArea identified by |scrollable_area_element_id| by the given
// delta + granularity.
virtual void InjectGestureScrollEvent(
- WebGestureDevice device,
+ mojom::blink::GestureDevice device,
const gfx::Vector2dF& delta,
ui::ScrollGranularity granularity,
cc::ElementId scrollable_area_element_id,
@@ -240,6 +256,15 @@ class PLATFORM_EXPORT FrameWidget
// Returns the FrameSinkId for this widget which is used for identifying
// frames submitted from the compositor.
virtual const viz::FrameSinkId& GetFrameSinkId() = 0;
+
+ // Returns the raster scale factor for the local root frame associated with
+ // this widget, taking into account its transform to main frame space.
+ virtual float GetCompositingScaleFactor() = 0;
+
+ // Get and set the configuration for the debugging overlay managed by the
+ // underlaying LayerTreeHost.
+ virtual const cc::LayerTreeDebugState& GetLayerTreeDebugState() = 0;
+ virtual void SetLayerTreeDebugState(const cc::LayerTreeDebugState& state) = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/DIR_METADATA b/chromium/third_party/blink/renderer/platform/widget/input/DIR_METADATA
new file mode 100644
index 00000000000..09bb17b7022
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/widget/input/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/OWNERS b/chromium/third_party/blink/renderer/platform/widget/input/OWNERS
index 5f2c07858ca..9468b22325f 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/widget/input/OWNERS
@@ -1,8 +1,3 @@
dtapuska@chromium.org
-tdresser@chromium.org
bokan@chromium.org
-nzolghadr@chromium.org
flackr@chromium.org
-
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.cc b/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.cc
index 0d258def6b6..18babfb6a0e 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.cc
@@ -33,7 +33,7 @@ EventWithCallback::EventWithCallback(
creation_timestamp_(creation_timestamp),
last_coalesced_timestamp_(last_coalesced_timestamp) {}
-EventWithCallback::~EventWithCallback() {}
+EventWithCallback::~EventWithCallback() = default;
bool EventWithCallback::CanCoalesceWith(const EventWithCallback& other) const {
return event().CanCoalesce(other.event());
@@ -60,7 +60,7 @@ static bool HandledOnCompositorThread(
return (disposition != InputHandlerProxy::DID_NOT_HANDLE &&
disposition !=
InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING &&
- disposition != InputHandlerProxy::DID_HANDLE_NON_BLOCKING);
+ disposition != InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING);
}
void EventWithCallback::RunCallbacks(
@@ -135,6 +135,26 @@ std::unique_ptr<cc::EventMetrics> EventWithCallback::TakeMetrics() {
return std::move(first->metrics_);
}
+void EventWithCallback::WillStartProcessingForMetrics() {
+ DCHECK(metrics());
+ for (auto& original_event : original_events_) {
+ if (original_event.metrics_) {
+ original_event.metrics_->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererCompositorStarted);
+ }
+ }
+}
+
+void EventWithCallback::DidCompleteProcessingForMetrics() {
+ DCHECK(metrics());
+ for (auto& original_event : original_events_) {
+ if (original_event.metrics_) {
+ original_event.metrics_->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererCompositorFinished);
+ }
+ }
+}
+
EventWithCallback::OriginalEventWithCallback::OriginalEventWithCallback(
std::unique_ptr<WebCoalescedInputEvent> event,
std::unique_ptr<cc::EventMetrics> metrics,
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.h b/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.h
index 6c45125257c..9d694c62fc7 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/event_with_callback.h
@@ -86,6 +86,12 @@ class PLATFORM_EXPORT EventWithCallback {
// for latency reporting purposes.
std::unique_ptr<cc::EventMetrics> TakeMetrics();
+ // Called when the compositor thread starts/finishes processing the event so
+ // that the metrics can be updated with the appropriate timestamp. These are
+ // only called if the event has metrics.
+ void WillStartProcessingForMetrics();
+ void DidCompleteProcessingForMetrics();
+
private:
friend class test::InputHandlerProxyEventQueueTest;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.cc b/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.cc
index 9dc22d678a3..77eb8546301 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/check.h"
+#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
@@ -21,9 +22,13 @@ namespace blink {
FrameWidgetInputHandlerImpl::FrameWidgetInputHandlerImpl(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
scoped_refptr<MainThreadEventQueue> input_event_queue)
- : widget_(widget),
+ : widget_(std::move(widget)),
+ main_thread_frame_widget_input_handler_(
+ std::move(frame_widget_input_handler)),
input_event_queue_(input_event_queue),
main_thread_task_runner_(main_thread_task_runner) {}
@@ -42,16 +47,18 @@ void FrameWidgetInputHandlerImpl::AddImeTextSpansToExistingText(
uint32_t end,
const Vector<ui::ImeTextSpan>& ui_ime_text_spans) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, uint32_t start, uint32_t end,
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ uint32_t start, uint32_t end,
const Vector<ui::ImeTextSpan>& ui_ime_text_spans) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
ImeEventGuard guard(widget);
- widget->client()->FrameWidget()->AddImeTextSpansToExistingText(
- start, end, ui_ime_text_spans);
+ handler->AddImeTextSpansToExistingText(start, end, ui_ime_text_spans);
},
- widget_, start, end, ui_ime_text_spans));
+ widget_, main_thread_frame_widget_input_handler_, start, end,
+ ui_ime_text_spans));
}
void FrameWidgetInputHandlerImpl::ClearImeTextSpansByType(
@@ -59,16 +66,16 @@ void FrameWidgetInputHandlerImpl::ClearImeTextSpansByType(
uint32_t end,
ui::ImeTextSpan::Type type) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, uint32_t start, uint32_t end,
- ui::ImeTextSpan::Type type) {
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ uint32_t start, uint32_t end, ui::ImeTextSpan::Type type) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
ImeEventGuard guard(widget);
- widget->client()->FrameWidget()->ClearImeTextSpansByType(start, end,
- type);
+ handler->ClearImeTextSpansByType(start, end, type);
},
- widget_, start, end, type));
+ widget_, main_thread_frame_widget_input_handler_, start, end, type));
}
void FrameWidgetInputHandlerImpl::SetCompositionFromExistingText(
@@ -76,177 +83,174 @@ void FrameWidgetInputHandlerImpl::SetCompositionFromExistingText(
int32_t end,
const Vector<ui::ImeTextSpan>& ui_ime_text_spans) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t start, int32_t end,
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t start, int32_t end,
const Vector<ui::ImeTextSpan>& ui_ime_text_spans) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
ImeEventGuard guard(widget);
-
- widget->client()->FrameWidget()->SetCompositionFromExistingText(
- start, end, ui_ime_text_spans);
+ handler->SetCompositionFromExistingText(start, end, ui_ime_text_spans);
},
- widget_, start, end, ui_ime_text_spans));
+ widget_, main_thread_frame_widget_input_handler_, start, end,
+ ui_ime_text_spans));
}
void FrameWidgetInputHandlerImpl::ExtendSelectionAndDelete(int32_t before,
int32_t after) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t before, int32_t after) {
- if (!widget)
- return;
- widget->client()->FrameWidget()->ExtendSelectionAndDelete(before,
- after);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t before, int32_t after) {
+ if (handler)
+ handler->ExtendSelectionAndDelete(before, after);
},
- widget_, before, after));
+ main_thread_frame_widget_input_handler_, before, after));
}
void FrameWidgetInputHandlerImpl::DeleteSurroundingText(int32_t before,
int32_t after) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t before, int32_t after) {
- if (!widget)
- return;
-
- if (!widget)
- return;
- widget->client()->FrameWidget()->DeleteSurroundingText(before, after);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t before, int32_t after) {
+ if (handler)
+ handler->DeleteSurroundingText(before, after);
},
- widget_, before, after));
+ main_thread_frame_widget_input_handler_, before, after));
}
void FrameWidgetInputHandlerImpl::DeleteSurroundingTextInCodePoints(
int32_t before,
int32_t after) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t before, int32_t after) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->DeleteSurroundingTextInCodePoints(
- before, after);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t before, int32_t after) {
+ if (handler)
+ handler->DeleteSurroundingTextInCodePoints(before, after);
},
- widget_, before, after));
+ main_thread_frame_widget_input_handler_, before, after));
}
void FrameWidgetInputHandlerImpl::SetEditableSelectionOffsets(int32_t start,
int32_t end) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t start, int32_t end) {
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t start, int32_t end) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, UpdateState::kIsSelectingRange);
- widget->client()->FrameWidget()->SetEditableSelectionOffsets(start,
- end);
+ handler->SetEditableSelectionOffsets(start, end);
},
- widget_, start, end));
+ widget_, main_thread_frame_widget_input_handler_, start, end));
}
void FrameWidgetInputHandlerImpl::ExecuteEditCommand(const String& command,
const String& value) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const String& command,
- const String& value) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->ExecuteEditCommand(command, value);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const String& command, const String& value) {
+ if (handler)
+ handler->ExecuteEditCommand(command, value);
},
- widget_, command.IsolatedCopy(), value.IsolatedCopy()));
+ main_thread_frame_widget_input_handler_, command.IsolatedCopy(),
+ value.IsolatedCopy()));
}
void FrameWidgetInputHandlerImpl::Undo() {
- RunOnMainThread(
- base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Undo", UpdateState::kNone));
+ RunOnMainThread(base::BindOnce(
+ &FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread, widget_,
+ main_thread_frame_widget_input_handler_, "Undo", UpdateState::kNone));
}
void FrameWidgetInputHandlerImpl::Redo() {
- RunOnMainThread(
- base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Redo", UpdateState::kNone));
+ RunOnMainThread(base::BindOnce(
+ &FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread, widget_,
+ main_thread_frame_widget_input_handler_, "Redo", UpdateState::kNone));
}
void FrameWidgetInputHandlerImpl::Cut() {
RunOnMainThread(
base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Cut", UpdateState::kIsSelectingRange));
+ widget_, main_thread_frame_widget_input_handler_, "Cut",
+ UpdateState::kIsSelectingRange));
}
void FrameWidgetInputHandlerImpl::Copy() {
RunOnMainThread(
base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Copy", UpdateState::kIsSelectingRange));
+ widget_, main_thread_frame_widget_input_handler_, "Copy",
+ UpdateState::kIsSelectingRange));
}
void FrameWidgetInputHandlerImpl::CopyToFindPboard() {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->CopyToFindPboard();
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler) {
+ if (handler)
+ handler->CopyToFindPboard();
},
- widget_));
+ main_thread_frame_widget_input_handler_));
}
void FrameWidgetInputHandlerImpl::Paste() {
RunOnMainThread(
base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Paste", UpdateState::kIsPasting));
+ widget_, main_thread_frame_widget_input_handler_, "Paste",
+ UpdateState::kIsPasting));
}
void FrameWidgetInputHandlerImpl::PasteAndMatchStyle() {
RunOnMainThread(
base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "PasteAndMatchStyle", UpdateState::kIsPasting));
+ widget_, main_thread_frame_widget_input_handler_,
+ "PasteAndMatchStyle", UpdateState::kIsPasting));
}
void FrameWidgetInputHandlerImpl::Replace(const String& word) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const String& word) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->Replace(word);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const String& word) {
+ if (handler)
+ handler->Replace(word);
},
- widget_, word.IsolatedCopy()));
+ main_thread_frame_widget_input_handler_, word.IsolatedCopy()));
}
void FrameWidgetInputHandlerImpl::ReplaceMisspelling(const String& word) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const String& word) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->ReplaceMisspelling(word);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const String& word) {
+ if (handler)
+ handler->ReplaceMisspelling(word);
},
- widget_, word.IsolatedCopy()));
+ main_thread_frame_widget_input_handler_, word.IsolatedCopy()));
}
void FrameWidgetInputHandlerImpl::Delete() {
- RunOnMainThread(
- base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "Delete", UpdateState::kNone));
+ RunOnMainThread(base::BindOnce(
+ &FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread, widget_,
+ main_thread_frame_widget_input_handler_, "Delete", UpdateState::kNone));
}
void FrameWidgetInputHandlerImpl::SelectAll() {
RunOnMainThread(
base::BindOnce(&FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread,
- widget_, "SelectAll", UpdateState::kIsSelectingRange));
+ widget_, main_thread_frame_widget_input_handler_,
+ "SelectAll", UpdateState::kIsSelectingRange));
}
void FrameWidgetInputHandlerImpl::CollapseSelection() {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget) {
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, UpdateState::kIsSelectingRange);
- widget->client()->FrameWidget()->CollapseSelection();
+ handler->CollapseSelection();
},
- widget_));
+ widget_, main_thread_frame_widget_input_handler_));
}
void FrameWidgetInputHandlerImpl::SelectRange(const gfx::Point& base,
@@ -255,15 +259,16 @@ void FrameWidgetInputHandlerImpl::SelectRange(const gfx::Point& base,
// one outstanding event and an ACK to handle coalescing on the browser
// side. We should be able to clobber them in the main thread event queue.
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const gfx::Point& base,
- const gfx::Point& extent) {
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const gfx::Point& base, const gfx::Point& extent) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, UpdateState::kIsSelectingRange);
- widget->client()->FrameWidget()->SelectRange(base, extent);
+ handler->SelectRange(base, extent);
},
- widget_, base, extent));
+ widget_, main_thread_frame_widget_input_handler_, base, extent));
}
#if defined(OS_ANDROID)
@@ -286,17 +291,15 @@ void FrameWidgetInputHandlerImpl::SelectWordAroundCaret(
}
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget,
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
SelectWordAroundCaretCallback callback) {
- if (widget) {
- FrameWidget* frame_widget = widget->client()->FrameWidget();
- if (frame_widget)
- frame_widget->SelectWordAroundCaret(std::move(callback));
- }
- if (callback)
+ if (handler) {
+ handler->SelectWordAroundCaret(std::move(callback));
+ } else {
std::move(callback).Run(false, 0, 0);
+ }
},
- widget_, std::move(callback)));
+ main_thread_frame_widget_input_handler_, std::move(callback)));
}
#endif // defined(OS_ANDROID)
@@ -305,16 +308,19 @@ void FrameWidgetInputHandlerImpl::AdjustSelectionByCharacterOffset(
int32_t end,
blink::mojom::SelectionMenuBehavior selection_menu_behavior) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, int32_t start, int32_t end,
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ int32_t start, int32_t end,
blink::mojom::SelectionMenuBehavior selection_menu_behavior) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, UpdateState::kIsSelectingRange);
- widget->client()->FrameWidget()->AdjustSelectionByCharacterOffset(
- start, end, selection_menu_behavior);
+ handler->AdjustSelectionByCharacterOffset(start, end,
+ selection_menu_behavior);
},
- widget_, start, end, selection_menu_behavior));
+ widget_, main_thread_frame_widget_input_handler_, start, end,
+ selection_menu_behavior));
}
void FrameWidgetInputHandlerImpl::MoveRangeSelectionExtent(
@@ -323,49 +329,49 @@ void FrameWidgetInputHandlerImpl::MoveRangeSelectionExtent(
// one outstanding event and an ACK to handle coalescing on the browser
// side. We should be able to clobber them in the main thread event queue.
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const gfx::Point& extent) {
+ [](base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const gfx::Point& extent) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, UpdateState::kIsSelectingRange);
- widget->client()->FrameWidget()->MoveRangeSelectionExtent(extent);
+ handler->MoveRangeSelectionExtent(extent);
},
- widget_, extent));
+ widget_, main_thread_frame_widget_input_handler_, extent));
}
void FrameWidgetInputHandlerImpl::ScrollFocusedEditableNodeIntoRect(
const gfx::Rect& rect) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const gfx::Rect& rect) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->ScrollFocusedEditableNodeIntoRect(
- rect);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const gfx::Rect& rect) {
+ if (handler)
+ handler->ScrollFocusedEditableNodeIntoRect(rect);
},
- widget_, rect));
+ main_thread_frame_widget_input_handler_, rect));
}
void FrameWidgetInputHandlerImpl::MoveCaret(const gfx::Point& point) {
RunOnMainThread(base::BindOnce(
- [](base::WeakPtr<WidgetBase> widget, const gfx::Point& point) {
- if (!widget)
- return;
-
- widget->client()->FrameWidget()->MoveCaret(point);
+ [](base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const gfx::Point& point) {
+ if (handler)
+ handler->MoveCaret(point);
},
- widget_, point));
+ main_thread_frame_widget_input_handler_, point));
}
void FrameWidgetInputHandlerImpl::ExecuteCommandOnMainThread(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
const char* command,
UpdateState update_state) {
+ DCHECK_EQ(!!widget, !!handler);
if (!widget)
return;
-
HandlingState handling_state(widget, update_state);
- widget->client()->FrameWidget()->ExecuteEditCommand(command, String());
+ handler->ExecuteEditCommand(command, String());
}
FrameWidgetInputHandlerImpl::HandlingState::HandlingState(
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.h b/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.h
index fa0f315ea01..05d50eb434a 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/frame_widget_input_handler_impl.h
@@ -40,8 +40,12 @@ class WidgetBase;
class PLATFORM_EXPORT FrameWidgetInputHandlerImpl
: public mojom::blink::FrameWidgetInputHandler {
public:
+ // The `widget` and `frame_widget_input_handler` should be invalidated
+ // at the same time.
FrameWidgetInputHandlerImpl(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
scoped_refptr<MainThreadEventQueue> input_event_queue);
~FrameWidgetInputHandlerImpl() override;
@@ -112,12 +116,16 @@ class PLATFORM_EXPORT FrameWidgetInputHandlerImpl
};
void RunOnMainThread(base::OnceClosure closure);
- static void ExecuteCommandOnMainThread(base::WeakPtr<WidgetBase> widget,
- const char* command,
- UpdateState state);
+ static void ExecuteCommandOnMainThread(
+ base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler> handler,
+ const char* command,
+ UpdateState state);
- // |widget_| should only be accessed on the main thread.
+ // These should only be accessed on the main thread.
base::WeakPtr<WidgetBase> widget_;
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ main_thread_frame_widget_input_handler_;
scoped_refptr<MainThreadEventQueue> input_event_queue_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc b/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
index cf5a4e2b3de..15b4f7dce2e 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/platform/widget/input/cursor_control_handler.h"
#include "third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.h"
#include "third_party/blink/renderer/platform/widget/input/event_with_callback.h"
+#include "third_party/blink/renderer/platform/widget/input/input_metrics.h"
#include "third_party/blink/renderer/platform/widget/input/momentum_scroll_jank_tracker.h"
#include "third_party/blink/renderer/platform/widget/input/scroll_predictor.h"
#include "ui/events/types/scroll_input_type.h"
@@ -402,6 +403,12 @@ void InputHandlerProxy::ContinueScrollBeginAfterMainThreadHitTest(
hit_test_result;
gesture_event->data.scroll_begin.main_thread_hit_tested = true;
+ if (metrics) {
+ // The event is going to be re-processed on the compositor thread; so,
+ // reset timstamps of following dispatch stages.
+ metrics->ResetToDispatchStage(
+ cc::EventMetrics::DispatchStage::kArrivedInRendererCompositor);
+ }
auto event_with_callback = std::make_unique<EventWithCallback>(
std::move(event), tick_clock_->NowTicks(), std::move(callback),
std::move(metrics));
@@ -454,8 +461,8 @@ void InputHandlerProxy::DispatchSingleInputEvent(
case WebGestureEvent::Type::kGestureScrollBegin:
case WebGestureEvent::Type::kGesturePinchBegin:
if (disposition == DID_HANDLE ||
- disposition == DID_HANDLE_SHOULD_BUBBLE ||
- disposition == REQUIRES_MAIN_THREAD_HIT_TEST) {
+ disposition == REQUIRES_MAIN_THREAD_HIT_TEST ||
+ (disposition == DROP_EVENT && handling_gesture_on_impl_thread_)) {
// REQUIRES_MAIN_THREAD_HIT_TEST means the scroll will be handled by
// the compositor but needs to block until a hit test is performed by
// Blink. We need to set this to indicate we're in a scroll so that
@@ -464,6 +471,9 @@ void InputHandlerProxy::DispatchSingleInputEvent(
// |handling_gesture_on_impl_thread_|. Ideally these two bits would be
// merged. The queueing behavior is currently just determined by having
// an active gesture device.
+ //
+ // DROP_EVENT and handling_gesture_on_impl_thread_ means that the
+ // gesture was handled but the scroll was not consumed.
currently_active_gesture_device_ =
static_cast<const WebGestureEvent&>(event).SourceDevice();
}
@@ -578,12 +588,12 @@ void InputHandlerProxy::InjectScrollbarGestureScroll(
last_injected_gesture_was_begin_ = false;
}
- base::TimeTicks metrics_time_stamp =
- original_metrics ? original_metrics->time_stamp()
- : synthetic_gesture_event->TimeStamp();
- std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
- synthetic_gesture_event->GetTypeAsUiEventType(), scroll_update_type,
- metrics_time_stamp, synthetic_gesture_event->GetScrollInputType());
+ std::unique_ptr<cc::EventMetrics> metrics =
+ cc::EventMetrics::CreateFromExisting(
+ synthetic_gesture_event->GetTypeAsUiEventType(), scroll_update_type,
+ synthetic_gesture_event->GetScrollInputType(),
+ cc::EventMetrics::DispatchStage::kArrivedInRendererCompositor,
+ original_metrics);
auto gesture_event_with_callback_update = std::make_unique<EventWithCallback>(
std::make_unique<WebCoalescedInputEvent>(
std::move(synthetic_gesture_event), scrollbar_latency_info),
@@ -614,8 +624,10 @@ InputHandlerProxy::RouteToTypeSpecificHandler(
cc::EventsMetricsManager::ScopedMonitor::DoneCallback done_callback;
if (event_with_callback->metrics()) {
+ event_with_callback->WillStartProcessingForMetrics();
done_callback = base::BindOnce(
[](EventWithCallback* event, bool handled) {
+ event->DidCompleteProcessingForMetrics();
std::unique_ptr<cc::EventMetrics> result =
handled ? event->TakeMetrics() : nullptr;
return result;
@@ -791,11 +803,6 @@ WebInputEventAttribution InputHandlerProxy::PerformEventAttribution(
void InputHandlerProxy::RecordMainThreadScrollingReasons(
WebGestureDevice device,
uint32_t reasons) {
- static const char* kGestureHistogramName =
- "Renderer4.MainThreadGestureScrollReason";
- static const char* kWheelHistogramName =
- "Renderer4.MainThreadWheelScrollReason";
-
if (device != WebGestureDevice::kTouchpad &&
device != WebGestureDevice::kScrollbar &&
device != WebGestureDevice::kTouchscreen) {
@@ -835,56 +842,7 @@ void InputHandlerProxy::RecordMainThreadScrollingReasons(
: cc::MainThreadScrollingReason::kTouchEventHandlerRegion);
}
- // Note: This is slightly different from |is_compositor_scroll| above because
- // at this point, we've also included wheel handler region reasons which will
- // scroll on the compositor but require blocking on the main thread. The
- // histograms below don't consider this "not scrolling on main".
- const bool is_unblocked_compositor_scroll =
- reasons == cc::MainThreadScrollingReason::kNotScrollingOnMain;
-
- // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly
- // greater than the sample value. kMainThreadScrollingReasonCount doesn't
- // include the NotScrollingOnMain enum but the histograms do so adding
- // the +1 is necessary.
- // TODO(dcheng): Fix https://crbug.com/705169 so this isn't needed.
- constexpr uint32_t kMainThreadScrollingReasonEnumMax =
- cc::MainThreadScrollingReason::kMainThreadScrollingReasonCount + 1;
- if (is_unblocked_compositor_scroll) {
- if (device == WebGestureDevice::kTouchscreen) {
- UMA_HISTOGRAM_ENUMERATION(
- kGestureHistogramName,
- cc::MainThreadScrollingReason::kNotScrollingOnMain,
- kMainThreadScrollingReasonEnumMax);
- } else {
- UMA_HISTOGRAM_ENUMERATION(
- kWheelHistogramName,
- cc::MainThreadScrollingReason::kNotScrollingOnMain,
- kMainThreadScrollingReasonEnumMax);
- }
- }
-
- for (uint32_t i = 0;
- i < cc::MainThreadScrollingReason::kMainThreadScrollingReasonCount;
- ++i) {
- unsigned val = 1 << i;
- if (reasons & val) {
- if (val == cc::MainThreadScrollingReason::kHandlingScrollFromMainThread) {
- // We only want to record "Handling scroll from main thread" reason if
- // it's the only reason. If it's not the only reason, the "real" reason
- // for scrolling on main is something else, and we only want to pay
- // attention to that reason.
- if (reasons & ~val)
- continue;
- }
- if (device == WebGestureDevice::kTouchscreen) {
- UMA_HISTOGRAM_ENUMERATION(kGestureHistogramName, i + 1,
- kMainThreadScrollingReasonEnumMax);
- } else {
- UMA_HISTOGRAM_ENUMERATION(kWheelHistogramName, i + 1,
- kMainThreadScrollingReasonEnumMax);
- }
- }
- }
+ RecordScrollReasonsMetric(device, reasons);
}
InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel(
@@ -899,7 +857,6 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel(
DCHECK(wheel_event.phase != WebMouseWheelEvent::kPhaseNone ||
wheel_event.momentum_phase != WebMouseWheelEvent::kPhaseNone);
- DCHECK(mouse_wheel_result_.has_value());
// TODO(bokan): This should never happen but after changing
// mouse_event_result_ to a base::Optional, crashes indicate that it does
// so |if| maintains prior behavior. https://crbug.com/1069760.
@@ -927,7 +884,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel(
switch (properties) {
case cc::EventListenerProperties::kBlockingAndPassive:
case cc::EventListenerProperties::kPassive:
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
break;
case cc::EventListenerProperties::kNone:
result = DROP_EVENT;
@@ -992,13 +949,13 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
handling_gesture_on_impl_thread_ = true;
if (input_handler_->IsCurrentlyScrollingViewport())
client_->DidStartScrollingViewport();
-
- if (scroll_status.bubble)
- result = DID_HANDLE_SHOULD_BUBBLE;
+ // if the viewport cannot scroll, the scroll cannot be consumed so we
+ // drop the event
+ if (scroll_status.viewport_cannot_scroll)
+ result = DROP_EVENT;
else
result = DID_HANDLE;
break;
- case ScrollThread::SCROLL_UNKNOWN:
case ScrollThread::SCROLL_ON_MAIN_THREAD:
TRACE_EVENT_INSTANT0("input", "Handle On Main", TRACE_EVENT_SCOPE_THREAD);
result = DID_NOT_HANDLE;
@@ -1008,6 +965,9 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
scroll_sequence_ignored_ = true;
result = DROP_EVENT;
break;
+ default:
+ NOTREACHED();
+ break;
}
// TODO(bokan): Should we really be calling this in cases like DROP_EVENT and
@@ -1183,7 +1143,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HitTestTouchEvent(
*allowed_touch_action != cc::TouchAction::kNone) {
TRACE_EVENT_INSTANT0("input", "NonBlocking due to allowed touchaction",
TRACE_EVENT_SCOPE_THREAD);
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
} else {
TRACE_EVENT_INSTANT0("input", "DidNotHandle due to no touchaction",
TRACE_EVENT_SCOPE_THREAD);
@@ -1201,7 +1161,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HitTestTouchEvent(
"listener", event_listener_class);
switch (event_listener_class) {
case cc::EventListenerProperties::kPassive:
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
break;
case cc::EventListenerProperties::kBlocking:
// The touch area rects above already have checked whether it hits
@@ -1211,7 +1171,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HitTestTouchEvent(
case cc::EventListenerProperties::kBlockingAndPassive:
// There is at least one passive listener that needs to possibly
// be notified so it can't be dropped.
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
break;
case cc::EventListenerProperties::kNone:
result = DROP_EVENT;
@@ -1231,12 +1191,12 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HitTestTouchEvent(
touch_event.GetType() == WebInputEvent::Type::kTouchStart))) {
TRACE_EVENT_INSTANT0("input", "Non blocking due to skip filter",
TRACE_EVENT_SCOPE_THREAD);
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
}
// Merge |touch_result_| and |result| so the result has the highest
// priority value according to the sequence; (DROP_EVENT,
- // DID_HANDLE_NON_BLOCKING, DID_NOT_HANDLE).
+ // DID_NOT_HANDLE_NON_BLOCKING, DID_NOT_HANDLE).
if (!touch_result_.has_value() || touch_result_ == DROP_EVENT ||
result == DID_NOT_HANDLE) {
TRACE_EVENT_INSTANT2(
@@ -1283,7 +1243,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchStart(
cc::EventListenerProperties::kNone) {
TRACE_EVENT_INSTANT0("input", "NonBlocking due to TouchEnd handler",
TRACE_EVENT_SCOPE_THREAD);
- result = DID_HANDLE_NON_BLOCKING;
+ result = DID_NOT_HANDLE_NON_BLOCKING;
}
bool is_in_inertial_scrolling_on_impl =
@@ -1410,7 +1370,7 @@ void InputHandlerProxy::DeliverInputForBeginFrame(
while (!compositor_event_queue_->empty()) {
std::unique_ptr<EventWithCallback> event_with_callback =
scroll_predictor_->ResampleScrollEvents(compositor_event_queue_->Pop(),
- args.frame_time);
+ args.frame_time, args.interval);
DispatchSingleInputEvent(std::move(event_with_callback), args.frame_time);
}
@@ -1513,54 +1473,53 @@ const cc::InputHandlerPointerResult InputHandlerProxy::HandlePointerDown(
EventWithCallback* event_with_callback,
const gfx::PointF& position) {
CHECK(input_handler_);
- // TODO(arakeri): Pass in the modifier instead of a bool once the
- // refactor (crbug.com/1022097) is done. For details, see
- // crbug.com/1016955.
- cc::InputHandlerPointerResult pointer_result = input_handler_->MouseDown(
- position, HasScrollbarJumpKeyModifier(event_with_callback->event()));
- if (pointer_result.type == cc::PointerResultType::kScrollbarScroll) {
- // Since a kScrollbarScroll is about to commence, ensure that any
- // existing ongoing scroll is ended.
- if (currently_active_gesture_device_.has_value()) {
- DCHECK_NE(*currently_active_gesture_device_,
- WebGestureDevice::kUninitialized);
- if (gesture_pinch_in_progress_) {
- input_handler_->PinchGestureEnd(gfx::ToFlooredPoint(position), true);
- }
- if (handling_gesture_on_impl_thread_) {
- input_handler_->RecordScrollEnd(
- GestureScrollInputType(*currently_active_gesture_device_));
- InputHandlerScrollEnd();
- }
+ if (input_handler_->HitTest(position) !=
+ cc::PointerResultType::kScrollbarScroll)
+ return cc::InputHandlerPointerResult();
+
+ // Since a kScrollbarScroll is about to commence, ensure that any existing
+ // ongoing scroll is ended.
+ if (currently_active_gesture_device_.has_value()) {
+ DCHECK_NE(*currently_active_gesture_device_,
+ WebGestureDevice::kUninitialized);
+ if (gesture_pinch_in_progress_) {
+ input_handler_->PinchGestureEnd(gfx::ToFlooredPoint(position), true);
+ }
+ if (handling_gesture_on_impl_thread_) {
+ input_handler_->RecordScrollEnd(
+ GestureScrollInputType(*currently_active_gesture_device_));
+ InputHandlerScrollEnd();
}
+ }
- // Generate GSB and GSU events and add them to the
- // CompositorThreadEventQueue.
- // Note that the latency info passed in to
- // InjectScrollbarGestureScroll is the original LatencyInfo, not the
- // one that may be currently monitored. The currently monitored one
- // may be modified by the call to InjectScrollbarGestureScroll, as
- // it will SetNeedsAnimateInput if the CompositorThreadEventQueue is
- // currently empty.
- InjectScrollbarGestureScroll(WebInputEvent::Type::kGestureScrollBegin,
+ // Generate GSB and GSU events and add them to the CompositorThreadEventQueue.
+ // Note that the latency info passed in to InjectScrollbarGestureScroll is the
+ // original LatencyInfo, not the one that may be currently monitored. The
+ // currently monitored one may be modified by the call to
+ // InjectScrollbarGestureScroll, as it will SetNeedsAnimateInput if the
+ // CompositorThreadEventQueue is currently empty.
+ // TODO(arakeri): Pass in the modifier instead of a bool once the refactor
+ // (crbug.com/1022097) is done. For details, see crbug.com/1016955.
+ const cc::InputHandlerPointerResult pointer_result =
+ input_handler_->MouseDown(
+ position, HasScrollbarJumpKeyModifier(event_with_callback->event()));
+ InjectScrollbarGestureScroll(
+ WebInputEvent::Type::kGestureScrollBegin, position, pointer_result,
+ event_with_callback->latency_info(),
+ event_with_callback->event().TimeStamp(), event_with_callback->metrics());
+
+ // Don't need to inject GSU if the scroll offset is zero (this can be the case
+ // where mouse down occurs on the thumb).
+ if (!pointer_result.scroll_offset.IsZero()) {
+ InjectScrollbarGestureScroll(WebInputEvent::Type::kGestureScrollUpdate,
position, pointer_result,
event_with_callback->latency_info(),
event_with_callback->event().TimeStamp(),
event_with_callback->metrics());
+ }
- // Don't need to inject GSU if the scroll offset is zero (this can
- // be the case where mouse down occurs on the thumb).
- if (!pointer_result.scroll_offset.IsZero()) {
- InjectScrollbarGestureScroll(WebInputEvent::Type::kGestureScrollUpdate,
- position, pointer_result,
- event_with_callback->latency_info(),
- event_with_callback->event().TimeStamp(),
- event_with_callback->metrics());
- }
-
- if (event_with_callback) {
- event_with_callback->SetScrollbarManipulationHandledOnCompositorThread();
- }
+ if (event_with_callback) {
+ event_with_callback->SetScrollbarManipulationHandledOnCompositorThread();
}
return pointer_result;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc b/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
index 1598191b4d9..c355ef625f5 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
@@ -112,6 +112,8 @@ class MockInputHandler : public cc::InputHandler {
cc::ScrollBeginThreadState state));
MOCK_METHOD1(RecordScrollEnd, void(ui::ScrollInputType type));
MOCK_METHOD0(ScrollingShouldSwitchtoMainThread, bool());
+ MOCK_METHOD1(HitTest,
+ cc::PointerResultType(const gfx::PointF& mouse_position));
MOCK_METHOD2(MouseDown,
cc::InputHandlerPointerResult(const gfx::PointF& mouse_position,
const bool shift_modifier));
@@ -260,9 +262,11 @@ const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState(
cc::MainThreadScrollingReason::kNotScrollingOnMain,
/*needs_main_thread_hit_test=*/true);
+constexpr auto kSampleMainThreadScrollingReason =
+ cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
const cc::InputHandler::ScrollStatus kMainThreadScrollState(
cc::InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD,
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
+ kSampleMainThreadScrollingReason);
const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState(
cc::InputHandler::ScrollThread::SCROLL_IGNORED,
@@ -609,6 +613,8 @@ TEST_P(InputHandlerProxyTest, NestedGestureBasedScrollsDifferentSourceDevice) {
cc::InputHandlerPointerResult pointer_down_result;
pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
@@ -663,7 +669,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelNoListener) {
}
TEST_P(InputHandlerProxyTest, MouseWheelPassiveListener) {
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
.WillRepeatedly(testing::Return(false));
EXPECT_CALL(mock_input_handler_,
@@ -731,7 +737,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelEventOutsideBlockingListener) {
TEST_P(InputHandlerProxyTest,
MouseWheelEventOutsideBlockingListenerWithPassiveListener) {
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_CALL(mock_input_handler_,
HasBlockingWheelEventHandlerAt(
testing::Property(&gfx::Point::y, testing::Gt(10))))
@@ -780,6 +786,8 @@ TEST_P(InputHandlerProxyTest, ScrollbarScrollEndOnDeviceChange) {
cc::InputHandlerPointerResult pointer_down_result;
pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
@@ -1399,7 +1407,7 @@ TEST_P(InputHandlerProxyTest,
TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
// One of the touch points is on a touch-region. So the event should be sent
// to the main thread.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_,
@@ -1460,6 +1468,8 @@ TEST_F(InputHandlerProxyEventQueueTest,
cc::InputHandlerPointerResult pointer_down_result;
pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
@@ -1506,6 +1516,8 @@ TEST_F(InputHandlerProxyEventQueueTest,
EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
// A mousedown occurs on the scrollbar *before* the GSE is dispatched.
@@ -1754,7 +1766,7 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) {
TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
// One of the touch points is on a touch-region. So the event should be sent
// to the main thread.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_,
@@ -1802,7 +1814,7 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPassivePositive) {
// One of the touch points is not on a touch-region. So the event should be
// sent to the impl thread.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(
@@ -1821,9 +1833,9 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPassivePositive) {
*touch_action = cc::TouchAction::kPanX;
return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
}));
- EXPECT_CALL(mock_client_,
- SetAllowedTouchAction(cc::TouchAction::kPanRight, 1,
- InputHandlerProxy::DID_HANDLE_NON_BLOCKING))
+ EXPECT_CALL(mock_client_, SetAllowedTouchAction(
+ cc::TouchAction::kPanRight, 1,
+ InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING))
.WillOnce(testing::Return());
WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
@@ -1849,7 +1861,7 @@ TEST_P(InputHandlerProxyTest, TouchStartPassiveAndTouchEndBlocking) {
// The touch start is not in a touch-region but there is a touch end handler
// so to maintain targeting we need to dispatch the touch start as
// non-blocking but drop all touch moves.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(
@@ -1866,9 +1878,9 @@ TEST_P(InputHandlerProxyTest, TouchStartPassiveAndTouchEndBlocking) {
*touch_action = cc::TouchAction::kNone;
return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
}));
- EXPECT_CALL(mock_client_,
- SetAllowedTouchAction(cc::TouchAction::kNone, 1,
- InputHandlerProxy::DID_HANDLE_NON_BLOCKING))
+ EXPECT_CALL(mock_client_, SetAllowedTouchAction(
+ cc::TouchAction::kNone, 1,
+ InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING))
.WillOnce(testing::Return());
WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
@@ -1907,11 +1919,8 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
.WillOnce(testing::Return());
-
- cc::InputHandlerPointerResult pointer_down_result;
- pointer_down_result.type = cc::PointerResultType::kUnhandled;
- EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
- .WillOnce(testing::Return(pointer_down_result));
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(cc::PointerResultType::kUnhandled));
WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
WebInputEvent::kNoModifiers,
@@ -1920,7 +1929,7 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
touch.touch_start_or_first_touch_move = true;
touch.touches[0] =
CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
- EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
+ EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING,
HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
@@ -1934,7 +1943,7 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
touch.touch_start_or_first_touch_move = true;
touch.touches[0] =
CreateWebTouchPoint(WebTouchPoint::State::kStateMoved, 10, 10);
- EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
+ EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING,
HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
VERIFY_AND_RESET_MOCKS();
}
@@ -2498,7 +2507,8 @@ TEST_F(InputHandlerProxyEventQueueTest,
cc::InputHandlerPointerResult pointer_down_result;
pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
-
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
HandleMouseEvent(WebInputEvent::Type::kMouseDown);
@@ -3382,9 +3392,10 @@ class InputHandlerProxyMainThreadScrollingReasonTest
if (reason == cc::MainThreadScrollingReason::kNotScrollingOnMain)
return 0;
- uint32_t bucket = 1;
- while ((reason = reason >> 1))
+ uint32_t bucket = 0;
+ while (reason >>= 1)
bucket++;
+ DCHECK_NE(bucket, 0u);
return bucket;
}
@@ -3396,6 +3407,19 @@ class InputHandlerProxyMainThreadScrollingReasonTest
WebGestureEvent gesture_scroll_end_;
};
+// Tests GetBucketSample() returns the corresponding values defined in
+// enums.xml, to ensure correctness of the tests using the function.
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, ReasonToBucket) {
+ EXPECT_EQ(
+ 0, GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain));
+ EXPECT_EQ(
+ 1,
+ GetBucketSample(
+ cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects));
+ EXPECT_EQ(25, GetBucketSample(
+ cc::MainThreadScrollingReason::kTouchEventHandlerRegion));
+}
+
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
GestureScrollNotScrollOnMain) {
// Touch start with passive event listener.
@@ -3412,13 +3436,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
.WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
.WillOnce(testing::Return());
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(cc::PointerResultType::kUnhandled));
- cc::InputHandlerPointerResult pointer_down_result;
- pointer_down_result.type = cc::PointerResultType::kUnhandled;
- EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
- .WillOnce(testing::Return(pointer_down_result));
-
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_EQ(expected_disposition_,
HandleInputEventAndFlushEventQueue(
mock_input_handler_, input_handler_.get(), touch_start_));
@@ -3464,13 +3485,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
HANDLER_ON_SCROLLING_LAYER));
EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
.WillOnce(testing::Return());
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(cc::PointerResultType::kUnhandled));
- cc::InputHandlerPointerResult pointer_down_result;
- pointer_down_result.type = cc::PointerResultType::kUnhandled;
- EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
- .WillOnce(testing::Return(pointer_down_result));
-
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_EQ(expected_disposition_,
HandleInputEventAndFlushEventQueue(
mock_input_handler_, input_handler_.get(), touch_start_));
@@ -3521,13 +3539,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
HANDLER_ON_SCROLLING_LAYER));
EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
.WillOnce(testing::Return());
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(cc::PointerResultType::kUnhandled));
- cc::InputHandlerPointerResult pointer_down_result;
- pointer_down_result.type = cc::PointerResultType::kUnhandled;
- EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
- .WillOnce(testing::Return(pointer_down_result));
-
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
input_handler_.get(), touch_start_));
@@ -3542,13 +3557,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
HandleInputEventWithLatencyInfo(input_handler_.get(),
gesture_scroll_begin_));
- EXPECT_THAT(
- histogram_tester().GetAllSamples(
- "Renderer4.MainThreadGestureScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
- 1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "Renderer4.MainThreadGestureScrollReason"),
+ testing::ElementsAre(base::Bucket(
+ GetBucketSample(kSampleMainThreadScrollingReason), 1)));
// Handle touch end event so that input handler proxy is out of the state of
// DID_NOT_HANDLE.
@@ -3580,13 +3592,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
.WillOnce(testing::Return());
EXPECT_CALL(mock_input_handler_, GetEventListenerProperties(_))
.WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive));
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(cc::PointerResultType::kUnhandled));
- cc::InputHandlerPointerResult pointer_down_result;
- pointer_down_result.type = cc::PointerResultType::kUnhandled;
- EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
- .WillOnce(testing::Return(pointer_down_result));
-
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
input_handler_.get(), touch_start_));
@@ -3601,13 +3610,10 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
HandleInputEventWithLatencyInfo(input_handler_.get(),
gesture_scroll_begin_));
- EXPECT_THAT(
- histogram_tester().GetAllSamples(
- "Renderer4.MainThreadGestureScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
- 1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "Renderer4.MainThreadGestureScrollReason"),
+ testing::ElementsAre(base::Bucket(
+ GetBucketSample(kSampleMainThreadScrollingReason), 1)));
expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
@@ -3626,37 +3632,7 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
input_handler_->RecordMainThreadScrollingReasonsForTest(
WebGestureDevice::kTouchpad,
cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects |
- cc::MainThreadScrollingReason::kThreadedScrollingDisabled |
- cc::MainThreadScrollingReason::kFrameOverlay |
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
-
- EXPECT_THAT(
- histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
- testing::ElementsAre(
- base::Bucket(
- GetBucketSample(cc::MainThreadScrollingReason::
- kHasBackgroundAttachmentFixedObjects),
- 1),
- base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
- 1),
- base::Bucket(
- GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay),
- 1)));
-
- // We only want to record "Handling scroll from main thread" reason if it's
- // the only reason. If it's not the only reason, the "real" reason for
- // scrolling on main is something else, and we only want to pay attention to
- // that reason. So we should only include this reason in the histogram when
- // its on its own.
- EXPECT_CALL(
- mock_input_handler_,
- RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
- .Times(1);
- input_handler_->RecordMainThreadScrollingReasonsForTest(
- WebGestureDevice::kTouchpad,
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
+ cc::MainThreadScrollingReason::kThreadedScrollingDisabled);
EXPECT_THAT(
histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
@@ -3668,12 +3644,6 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
base::Bucket(
GetBucketSample(
cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
- 1),
- base::Bucket(
- GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay), 1),
- base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
1)));
}
@@ -3689,7 +3659,7 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
EXPECT_CALL(mock_input_handler_,
GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
.WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
- expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+ expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING;
EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
input_handler_.get(), wheel_event_));
@@ -3781,10 +3751,12 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
EXPECT_THAT(
histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
- 1)));
+ testing::ElementsAre(
+ base::Bucket(GetBucketSample(kSampleMainThreadScrollingReason), 1),
+ base::Bucket(
+ GetBucketSample(
+ cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
+ 1)));
expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
@@ -3820,10 +3792,8 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
EXPECT_THAT(
histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
- 1)));
+ testing::ElementsAre(
+ base::Bucket(GetBucketSample(kSampleMainThreadScrollingReason), 1)));
expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
@@ -3881,6 +3851,8 @@ TEST_P(InputHandlerProxyTouchScrollbarTest,
EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
.WillOnce(testing::Return());
+ EXPECT_CALL(mock_input_handler_, HitTest(_))
+ .WillOnce(testing::Return(pointer_down_result.type));
EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
.WillOnce(testing::Return(pointer_down_result));
cc::InputHandlerScrollResult scroll_result_did_scroll;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.cc b/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.cc
new file mode 100644
index 00000000000..6eca912735f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.cc
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/widget/input/input_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "cc/input/main_thread_scrolling_reason.h"
+#include "third_party/blink/public/common/input/web_gesture_device.h"
+
+namespace blink {
+
+namespace {
+
+constexpr uint32_t kMax =
+ cc::MainThreadScrollingReason::kMainThreadScrollingReasonLast;
+
+static void RecordOneScrollReasonMetric(WebGestureDevice device,
+ uint32_t reason_index) {
+ if (device == WebGestureDevice::kTouchscreen) {
+ UMA_HISTOGRAM_EXACT_LINEAR("Renderer4.MainThreadGestureScrollReason",
+ reason_index, kMax + 1);
+ } else {
+ UMA_HISTOGRAM_EXACT_LINEAR("Renderer4.MainThreadWheelScrollReason",
+ reason_index, kMax + 1);
+ }
+}
+
+} // anonymous namespace
+
+void RecordScrollReasonsMetric(WebGestureDevice device, uint32_t reasons) {
+ if (!reasons) {
+ RecordOneScrollReasonMetric(device, 0);
+ return;
+ }
+
+ // The enum in cc::MainThreadScrollingReason simultaneously defines actual
+ // bitmask values and indices into the bitmask, but kNotScrollingMain is
+ // recorded in the histograms as value 0, so the 0th bit should never be used.
+ DCHECK(!(reasons & (1 << 0)));
+
+ for (uint32_t i = 1; i <= kMax; ++i) {
+ if (reasons & (1 << i))
+ RecordOneScrollReasonMetric(device, i);
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.h b/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.h
new file mode 100644
index 00000000000..6d11c56d9e6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/widget/input/input_metrics.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_METRICS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_METRICS_H_
+
+#include "cc/input/main_thread_scrolling_reason.h"
+#include "third_party/blink/public/common/input/web_gesture_device.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// |reasons| is a combination of bits defined in
+// |cc::MainThreadScrollingReason|.
+PLATFORM_EXPORT void RecordScrollReasonsMetric(WebGestureDevice device,
+ uint32_t reasons);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_METRICS_H_
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc b/chromium/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc
index b40f99f89c0..3b0ef487af7 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc
@@ -71,12 +71,12 @@ class QueuedWebInputEvent : public MainThreadEventQueueTask {
const cc::EventMetrics* original_metrics) {
DCHECK_EQ(raw_event->Event().GetType(),
WebInputEvent::Type::kPointerRawUpdate);
- base::TimeTicks original_time_stamp = original_metrics
- ? original_metrics->time_stamp()
- : raw_event->Event().TimeStamp();
- std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
- raw_event->Event().GetTypeAsUiEventType(), base::nullopt,
- original_time_stamp, raw_event->Event().GetScrollInputType());
+ std::unique_ptr<cc::EventMetrics> metrics =
+ cc::EventMetrics::CreateFromExisting(
+ raw_event->Event().GetTypeAsUiEventType(), base::nullopt,
+ raw_event->Event().GetScrollInputType(),
+ cc::EventMetrics::DispatchStage::kRendererCompositorFinished,
+ original_metrics);
return std::make_unique<QueuedWebInputEvent>(
std::move(raw_event), false, HandledEventCallback(), false, attribution,
std::move(metrics));
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
index 95e5f3f3c7d..9fa43f8144b 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
@@ -58,7 +58,8 @@ void ScrollPredictor::ResetOnGestureScrollBegin(const WebGestureEvent& event) {
std::unique_ptr<EventWithCallback> ScrollPredictor::ResampleScrollEvents(
std::unique_ptr<EventWithCallback> event_with_callback,
- base::TimeTicks frame_time) {
+ base::TimeTicks frame_time,
+ base::TimeDelta frame_interval) {
if (!should_resample_scroll_events_)
return event_with_callback;
@@ -79,7 +80,8 @@ std::unique_ptr<EventWithCallback> ScrollPredictor::ResampleScrollEvents(
UpdatePrediction(coalesced_event.event_->Event(), frame_time);
if (should_resample_scroll_events_) {
- ResampleEvent(frame_time, event_with_callback->event_pointer(),
+ ResampleEvent(frame_time, frame_interval,
+ event_with_callback->event_pointer(),
&event_with_callback->latency_info());
}
@@ -128,6 +130,7 @@ void ScrollPredictor::UpdatePrediction(const WebInputEvent& event,
}
void ScrollPredictor::ResampleEvent(base::TimeTicks frame_time,
+ base::TimeDelta frame_interval,
WebInputEvent* event,
ui::LatencyInfo* latency_info) {
DCHECK(event->GetType() == WebInputEvent::Type::kGestureScrollUpdate);
@@ -151,7 +154,7 @@ void ScrollPredictor::ResampleEvent(base::TimeTicks frame_time,
base::TimeTicks prediction_time =
gesture_event->TimeStamp() + prediction_delta;
- auto result = predictor_->GeneratePrediction(prediction_time);
+ auto result = predictor_->GeneratePrediction(prediction_time, frame_interval);
if (result) {
predicted_accumulated_delta = result->pos;
gesture_event->SetTimeStamp(result->time_stamp);
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.h b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.h
index aff434f4d2a..7957d77e9a2 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor.h
@@ -37,7 +37,8 @@ class PLATFORM_EXPORT ScrollPredictor {
// event if enable_resampling is true.
std::unique_ptr<EventWithCallback> ResampleScrollEvents(
std::unique_ptr<EventWithCallback> event_with_callback,
- base::TimeTicks frame_time);
+ base::TimeTicks frame_time,
+ base::TimeDelta frame_interval);
private:
friend class test::InputHandlerProxyEventQueueTest;
@@ -52,6 +53,7 @@ class PLATFORM_EXPORT ScrollPredictor {
// Apply resampled deltaX/deltaY to gesture events
void ResampleEvent(base::TimeTicks frame_time,
+ base::TimeDelta frame_interval,
WebInputEvent* event,
ui::LatencyInfo* latency_info);
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
index 88725b7d085..b34f9df154f 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
@@ -77,26 +77,32 @@ class ScrollPredictorTest : public testing::Test {
}
void HandleResampleScrollEvents(std::unique_ptr<WebInputEvent>& event,
- double time_delta_in_milliseconds = 0) {
+ double time_delta_in_milliseconds = 0,
+ double display_refresh_rate = 30) {
auto event_with_callback = std::make_unique<EventWithCallback>(
std::make_unique<WebCoalescedInputEvent>(std::move(event),
ui::LatencyInfo()),
base::TimeTicks(), base::NullCallback(), nullptr);
event_with_callback->original_events() = std::move(original_events_);
+ base::TimeDelta frame_interval =
+ base::TimeDelta::FromSecondsD(1.0f / display_refresh_rate);
event_with_callback = scroll_predictor_->ResampleScrollEvents(
std::move(event_with_callback),
WebInputEvent::GetStaticTimeStampForTests() +
- base::TimeDelta::FromMillisecondsD(time_delta_in_milliseconds));
+ base::TimeDelta::FromMillisecondsD(time_delta_in_milliseconds),
+ frame_interval);
event = event_with_callback->event().Clone();
}
std::unique_ptr<ui::InputPredictor::InputData> PredictionAvailable(
double time_delta_in_milliseconds = 0) {
- return scroll_predictor_->predictor_->GeneratePrediction(
+ base::TimeTicks frame_time =
WebInputEvent::GetStaticTimeStampForTests() +
- base::TimeDelta::FromMillisecondsD(time_delta_in_milliseconds));
+ base::TimeDelta::FromMillisecondsD(time_delta_in_milliseconds);
+ // Tests with 60Hz.
+ return scroll_predictor_->predictor_->GeneratePrediction(frame_time);
}
gfx::PointF GetLastAccumulatedDelta() {
@@ -168,6 +174,30 @@ class ScrollPredictorTest : public testing::Test {
EXPECT_EQ(expected_type, scroll_predictor_->filter_->GetName());
}
+ void InitLinearResamplingTest(bool use_frames_based_experimental_prediction) {
+ base::FieldTrialParams params;
+ params["filter"] = ::features::kPredictorNameLinearResampling;
+ base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
+ features::kResamplingScrollEvents, params};
+
+ base::FieldTrialParams prediction_type_params;
+ prediction_type_params["mode"] =
+ use_frames_based_experimental_prediction
+ ? ::features::kPredictionTypeFramesBased
+ : ::features::kPredictionTypeTimeBased;
+ base::test::ScopedFeatureList::FeatureAndParams
+ experimental_prediction_params = {
+ ::features::kResamplingScrollEventsExperimentalPrediction,
+ prediction_type_params};
+
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {prediction_params, experimental_prediction_params}, {});
+ scroll_predictor_ = std::make_unique<ScrollPredictor>();
+
+ VerifyPredictorType(::features::kPredictorNameLinearResampling);
+ }
+
protected:
EventWithCallback::OriginalEventList original_events_;
std::unique_ptr<ScrollPredictor> scroll_predictor_;
@@ -372,6 +402,60 @@ TEST_F(ScrollPredictorTest, LSQPredictorTest) {
EXPECT_EQ(-150, result->pos.y());
}
+TEST_F(ScrollPredictorTest, LinearResamplingPredictorTest) {
+ // Test kResamplingScrollEventsExperimentalLatencyFixed
+ InitLinearResamplingTest(false);
+ SendGestureScrollBegin();
+
+ // Send 1st GSU, no prediction available.
+ std::unique_ptr<WebInputEvent> gesture_update =
+ CreateGestureScrollUpdate(0, 10, 10 /* ms */);
+ HandleResampleScrollEvents(gesture_update, 10 /* ms */, 30 /* Hz */);
+ EXPECT_EQ(10, static_cast<const WebGestureEvent*>(gesture_update.get())
+ ->data.scroll_update.delta_y);
+ EXPECT_EQ(
+ WebInputEvent::GetStaticTimeStampForTests() +
+ base::TimeDelta::FromMillisecondsD(10 /* ms */),
+ static_cast<const WebGestureEvent*>(gesture_update.get())->TimeStamp());
+
+ // Prediction using fixed +3.3ms latency.
+ gesture_update = CreateGestureScrollUpdate(0, 10, 20 /* ms */);
+ HandleResampleScrollEvents(gesture_update, 20 /* ms */, 30 /* Hz */);
+ ASSERT_FLOAT_EQ(10 + 3.3,
+ static_cast<const WebGestureEvent*>(gesture_update.get())
+ ->data.scroll_update.delta_y);
+ EXPECT_EQ(
+ WebInputEvent::GetStaticTimeStampForTests() +
+ base::TimeDelta::FromMillisecondsD(23.3 /* ms */),
+ static_cast<const WebGestureEvent*>(gesture_update.get())->TimeStamp());
+
+ // Test kResamplingScrollEventsExperimentalLatencyVariable
+ InitLinearResamplingTest(true);
+ SendGestureScrollBegin();
+
+ // Send 1st GSU, no prediction available.
+ gesture_update = CreateGestureScrollUpdate(0, 10, 10 /* ms */);
+ HandleResampleScrollEvents(gesture_update, 10 /* ms */, 60 /* Hz */);
+ EXPECT_EQ(10, static_cast<const WebGestureEvent*>(gesture_update.get())
+ ->data.scroll_update.delta_y);
+ EXPECT_EQ(
+ WebInputEvent::GetStaticTimeStampForTests() +
+ base::TimeDelta::FromMillisecondsD(10 /* ms */),
+ static_cast<const WebGestureEvent*>(gesture_update.get())->TimeStamp());
+
+ // Prediction at 60Hz: uses experimental latency of 0.5 * 1/60 seconds.
+ // Remember linear resampling has its -5 built-in latency.
+ gesture_update = CreateGestureScrollUpdate(0, 10, 20 /* ms */);
+ HandleResampleScrollEvents(gesture_update, 20 /* ms */, 60 /* Hz */);
+ ASSERT_FLOAT_EQ(10 - 5 + 8.333,
+ static_cast<const WebGestureEvent*>(gesture_update.get())
+ ->data.scroll_update.delta_y);
+ EXPECT_EQ(
+ WebInputEvent::GetStaticTimeStampForTests() +
+ base::TimeDelta::FromMillisecondsD(10 + 10 - 5 + 8.333 /* ms */),
+ static_cast<const WebGestureEvent*>(gesture_update.get())->TimeStamp());
+}
+
TEST_F(ScrollPredictorTest, ScrollPredictorNotChangeScrollDirection) {
SetUpLSQPredictor();
SendGestureScrollBegin();
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc b/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc
index f7dc6576c03..5f3115613c4 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc
@@ -125,7 +125,7 @@ void SynchronousCompositorProxy::DemandDrawHw(
if (layer_tree_frame_sink_) {
layer_tree_frame_sink_->DemandDrawHw(
params->viewport_size, params->viewport_rect_for_tile_priority,
- params->transform_for_tile_priority);
+ params->transform_for_tile_priority, params->need_new_local_surface_id);
}
// Ensure that a response is always sent even if the reply hasn't
@@ -133,7 +133,8 @@ void SynchronousCompositorProxy::DemandDrawHw(
if (hardware_draw_reply_) {
// Did not swap.
std::move(hardware_draw_reply_)
- .Run(PopulateNewCommonParams(), 0u, 0u, base::nullopt, base::nullopt);
+ .Run(PopulateNewCommonParams(), 0u, 0u, base::nullopt, base::nullopt,
+ base::nullopt);
}
}
@@ -215,6 +216,7 @@ void SynchronousCompositorProxy::DoDemandDrawSw(
void SynchronousCompositorProxy::SubmitCompositorFrame(
uint32_t layer_tree_frame_sink_id,
+ const viz::LocalSurfaceId& local_surface_id,
base::Optional<viz::CompositorFrame> frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
// Verify that exactly one of these is true.
@@ -225,9 +227,10 @@ void SynchronousCompositorProxy::SubmitCompositorFrame(
if (hardware_draw_reply_) {
// For viz the CF was submitted directly via CompositorFrameSink
DCHECK(frame || viz_frame_submission_enabled_);
+ DCHECK(local_surface_id.is_valid());
std::move(hardware_draw_reply_)
.Run(std::move(common_renderer_params), layer_tree_frame_sink_id,
- NextMetadataVersion(), std::move(frame),
+ NextMetadataVersion(), local_surface_id, std::move(frame),
std::move(hit_test_region_list));
} else if (software_draw_reply_) {
DCHECK(frame);
@@ -332,10 +335,12 @@ void SynchronousCompositorProxy::SendDemandDrawHwAsyncReply(
mojom::blink::SyncCompositorCommonRendererParamsPtr,
uint32_t layer_tree_frame_sink_id,
uint32_t metadata_version,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id,
base::Optional<viz::CompositorFrame> frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
control_host_->ReturnFrame(layer_tree_frame_sink_id, metadata_version,
- std::move(frame), std::move(hit_test_region_list));
+ local_surface_id, std::move(frame),
+ std::move(hit_test_region_list));
}
void SynchronousCompositorProxy::SendBeginFrameResponse(
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h b/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h
index 846bbd1dad3..19cfb5cb2de 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h
@@ -59,6 +59,7 @@ class SynchronousCompositorProxy : public blink::SynchronousInputHandler,
void Invalidate(bool needs_draw) final;
void SubmitCompositorFrame(
uint32_t layer_tree_frame_sink_id,
+ const viz::LocalSurfaceId& local_surface_id,
base::Optional<viz::CompositorFrame> frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) final;
void SetNeedsBeginFrames(bool needs_begin_frames) final;
@@ -99,6 +100,7 @@ class SynchronousCompositorProxy : public blink::SynchronousInputHandler,
mojom::blink::SyncCompositorCommonRendererParamsPtr,
uint32_t layer_tree_frame_sink_id,
uint32_t metadata_version,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id,
base::Optional<viz::CompositorFrame>,
base::Optional<viz::HitTestRegionList> hit_test_region_list);
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc b/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
index c6628c6acc2..71396e624f2 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
@@ -339,15 +339,19 @@ void WidgetBaseInputHandler::HandleInputEvent(
ui::LatencyComponentType::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT);
cc::LatencyInfoSwapPromiseMonitor swap_promise_monitor(
&swap_latency_info, widget_->LayerTreeHost()->GetSwapPromiseManager());
- base::Optional<base::TimeTicks> metrics_timestamp;
+ std::unique_ptr<cc::EventMetrics> cloned_metrics;
cc::EventsMetricsManager::ScopedMonitor::DoneCallback done_callback;
if (metrics) {
- // Get the timestamp of `metrics` before moving it to the following
- // callback. This timestamp would later be useful in creating
- // `cc::EventMetrics` objects for injected scroll events.
- metrics_timestamp = metrics->time_stamp();
+ // Create a clone of `metrics` before moving it to the following callback.
+ // This would later be useful in creating `cc::EventMetrics` objects for
+ // injected scroll events.
+ cloned_metrics = metrics->Clone();
+ metrics->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererMainStarted);
done_callback = base::BindOnce(
[](std::unique_ptr<cc::EventMetrics> metrics, bool handled) {
+ metrics->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererMainFinished);
std::unique_ptr<cc::EventMetrics> result =
handled ? std::move(metrics) : nullptr;
return result;
@@ -465,7 +469,7 @@ void WidgetBaseInputHandler::HandleInputEvent(
if (handling_state.injected_scroll_params().size()) {
HandleInjectedScrollGestures(
std::move(handling_state.injected_scroll_params()), input_event,
- coalesced_event.latency_info(), metrics_timestamp);
+ coalesced_event.latency_info(), cloned_metrics.get());
}
// Send gesture scroll events and their dispositions to the compositor thread,
@@ -595,7 +599,7 @@ void WidgetBaseInputHandler::HandleInjectedScrollGestures(
std::vector<InjectScrollGestureParams> injected_scroll_params,
const WebInputEvent& input_event,
const ui::LatencyInfo& original_latency_info,
- base::Optional<base::TimeTicks> original_metrics_timestamp) {
+ const cc::EventMetrics* original_metrics) {
DCHECK(injected_scroll_params.size());
base::TimeTicks original_timestamp;
@@ -665,28 +669,24 @@ void WidgetBaseInputHandler::HandleInjectedScrollGestures(
cc::LatencyInfoSwapPromiseMonitor swap_promise_monitor(
&scrollbar_latency_info,
widget_->LayerTreeHost()->GetSwapPromiseManager());
- // For latency metrics, we need the original timestamp of the
- // `input_event` as its current timestamp might have changed due to
- // coalescing in the pipeline. `original_metrics_timestamp` which is the
- // timestamp from the metrics object for the `input_event` contains this
- // original timestamp. We could have used `original_timestamp` for this
- // purpose, but we don't do that as `original_timestamp` is extracted from
- // `ui::LatencyInfo` of `input_event` which we hope to be able to get rid
- // of. Moreover, we plan to add more breakdown timestamps to
- // `EventMetrcis` which are not available in `ui::LatencyInfo`.
- base::TimeTicks time_stamp =
- original_metrics_timestamp.value_or(gesture_event->TimeStamp());
- std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
- gesture_event->GetTypeAsUiEventType(), scroll_update_type, time_stamp,
- gesture_event->GetScrollInputType());
+ std::unique_ptr<cc::EventMetrics> metrics =
+ cc::EventMetrics::CreateFromExisting(
+ gesture_event->GetTypeAsUiEventType(), scroll_update_type,
+ gesture_event->GetScrollInputType(),
+ cc::EventMetrics::DispatchStage::kRendererCompositorFinished,
+ original_metrics);
cc::EventsMetricsManager::ScopedMonitor::DoneCallback done_callback;
if (metrics) {
+ metrics->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererMainStarted);
// Since we don't need `metrics` for this event beyond this point (i.e.
// we don't intend to add further breakdowns to the metrics while
// processing the event, at least for now), it is safe to move the
// metrics object to the callback.
done_callback = base::BindOnce(
[](std::unique_ptr<cc::EventMetrics> metrics, bool handled) {
+ metrics->SetDispatchStageTimestamp(
+ cc::EventMetrics::DispatchStage::kRendererMainFinished);
std::unique_ptr<cc::EventMetrics> result =
handled ? std::move(metrics) : nullptr;
return result;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h b/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h
index 7f10b523e0e..12bfc002351 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h
@@ -105,14 +105,14 @@ class PLATFORM_EXPORT WidgetBaseInputHandler {
// Creates and handles scroll gestures based on parameters from
// `injected_scroll_params`. `input_event`, `original_latency_info`, and
- // `original_metrics_timestamp` are the original event causing gesture
- // scrolls, its latency info, and its metrics timestamp, respectively, used in
- // generating new gestures along with their latency and metrics info.
+ // `original_metrics` are the original event causing gesture scrolls, its
+ // latency info, and its metrics, respectively, used in generating new
+ // gestures along with their latency info and metrics.
void HandleInjectedScrollGestures(
std::vector<InjectScrollGestureParams> injected_scroll_params,
const WebInputEvent& input_event,
const ui::LatencyInfo& original_latency_info,
- base::Optional<base::TimeTicks> original_metrics_timestamp);
+ const cc::EventMetrics* original_metrics);
WidgetBase* widget_;
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc
index cbd43b587b9..add9bfb248c 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc
@@ -38,13 +38,16 @@ WidgetInputHandlerImpl::WidgetInputHandlerImpl(
scoped_refptr<WidgetInputHandlerManager> manager,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
scoped_refptr<MainThreadEventQueue> input_event_queue,
- base::WeakPtr<WidgetBase> widget)
+ base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler)
: main_thread_task_runner_(main_thread_task_runner),
input_handler_manager_(manager),
input_event_queue_(input_event_queue),
- widget_(widget) {}
+ widget_(std::move(widget)),
+ frame_widget_input_handler_(std::move(frame_widget_input_handler)) {}
-WidgetInputHandlerImpl::~WidgetInputHandlerImpl() {}
+WidgetInputHandlerImpl::~WidgetInputHandlerImpl() = default;
void WidgetInputHandlerImpl::SetReceiver(
mojo::PendingReceiver<mojom::blink::WidgetInputHandler>
@@ -158,6 +161,7 @@ void WidgetInputHandlerImpl::InputWasProcessed() {
std::move(input_processed_ack_).Run();
}
+#if defined(OS_ANDROID)
void WidgetInputHandlerImpl::AttachSynchronousCompositor(
mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
control_host,
@@ -167,13 +171,15 @@ void WidgetInputHandlerImpl::AttachSynchronousCompositor(
input_handler_manager_->AttachSynchronousCompositor(
std::move(control_host), std::move(host), std::move(compositor_receiver));
}
+#endif
void WidgetInputHandlerImpl::GetFrameWidgetInputHandler(
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetInputHandler>
frame_receiver) {
mojo::MakeSelfOwnedAssociatedReceiver(
std::make_unique<FrameWidgetInputHandlerImpl>(
- widget_, main_thread_task_runner_, input_event_queue_),
+ widget_, frame_widget_input_handler_, main_thread_task_runner_,
+ input_event_queue_),
std::move(frame_receiver));
}
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h
index 4e15b45769a..dfd96239ada 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h
@@ -23,11 +23,15 @@ class WidgetInputHandlerManager;
// is done so that events stay in order relative to other events.
class WidgetInputHandlerImpl : public mojom::blink::WidgetInputHandler {
public:
+ // The `widget` and `frame_widget_input_handler` should be invalidated
+ // at the same time.
WidgetInputHandlerImpl(
scoped_refptr<WidgetInputHandlerManager> manager,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
scoped_refptr<MainThreadEventQueue> input_event_queue,
- base::WeakPtr<WidgetBase> widget);
+ base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler);
~WidgetInputHandlerImpl() override;
void SetReceiver(mojo::PendingReceiver<mojom::blink::WidgetInputHandler>
@@ -57,6 +61,7 @@ class WidgetInputHandlerImpl : public mojom::blink::WidgetInputHandler {
void DispatchNonBlockingEvent(
std::unique_ptr<WebCoalescedInputEvent>) override;
void WaitForInputProcessed(WaitForInputProcessedCallback callback) override;
+#if defined(OS_ANDROID)
void AttachSynchronousCompositor(
mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
control_host,
@@ -64,6 +69,7 @@ class WidgetInputHandlerImpl : public mojom::blink::WidgetInputHandler {
host,
mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor>
compositor_receiver) override;
+#endif
void GetFrameWidgetInputHandler(
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetInputHandler>
interface_request) override;
@@ -78,6 +84,8 @@ class WidgetInputHandlerImpl : public mojom::blink::WidgetInputHandler {
scoped_refptr<WidgetInputHandlerManager> input_handler_manager_;
scoped_refptr<MainThreadEventQueue> input_event_queue_;
base::WeakPtr<WidgetBase> widget_;
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler_;
// This callback is used to respond to the WaitForInputProcessed Mojo
// message. We keep it around so that we can respond even if the renderer is
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
index 73cac4d137d..bd6cf5fd3d1 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -14,6 +14,9 @@
#include "cc/base/features.h"
#include "cc/metrics/event_metrics.h"
#include "cc/trees/layer_tree_host.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_input_event_attribution.h"
@@ -79,10 +82,8 @@ mojom::blink::InputEventResultState InputEventDispositionToAck(
return mojom::blink::InputEventResultState::kSetNonBlockingDueToFling;
case InputHandlerProxy::DROP_EVENT:
return mojom::blink::InputEventResultState::kNoConsumerExists;
- case InputHandlerProxy::DID_HANDLE_NON_BLOCKING:
+ case InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING:
return mojom::blink::InputEventResultState::kSetNonBlocking;
- case InputHandlerProxy::DID_HANDLE_SHOULD_BUBBLE:
- return mojom::blink::InputEventResultState::kConsumedShouldBubble;
case InputHandlerProxy::REQUIRES_MAIN_THREAD_HIT_TEST:
default:
NOTREACHED();
@@ -171,14 +172,17 @@ class SynchronousCompositorProxyRegistry
scoped_refptr<WidgetInputHandlerManager> WidgetInputHandlerManager::Create(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
bool never_composited,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
scheduler::WebThreadScheduler* main_thread_scheduler,
bool uses_input_handler) {
scoped_refptr<WidgetInputHandlerManager> manager =
- new WidgetInputHandlerManager(std::move(widget), never_composited,
- std::move(compositor_task_runner),
- main_thread_scheduler);
+ new WidgetInputHandlerManager(
+ std::move(widget), std::move(frame_widget_input_handler),
+ never_composited, std::move(compositor_task_runner),
+ main_thread_scheduler);
if (uses_input_handler)
manager->InitInputHandler();
@@ -193,10 +197,14 @@ scoped_refptr<WidgetInputHandlerManager> WidgetInputHandlerManager::Create(
WidgetInputHandlerManager::WidgetInputHandlerManager(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
bool never_composited,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
scheduler::WebThreadScheduler* main_thread_scheduler)
- : widget_(widget),
+ : widget_(std::move(widget)),
+ frame_widget_input_handler_(std::move(frame_widget_input_handler)),
+
widget_scheduler_(main_thread_scheduler->CreateWidgetScheduler()),
main_thread_scheduler_(main_thread_scheduler),
input_event_queue_(base::MakeRefCounted<MainThreadEventQueue>(
@@ -205,7 +213,10 @@ WidgetInputHandlerManager::WidgetInputHandlerManager(
main_thread_scheduler,
/*allow_raf_aligned_input=*/!never_composited)),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- compositor_task_runner_(std::move(compositor_task_runner)) {
+ compositor_task_runner_(std::move(compositor_task_runner)),
+ response_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Response")) {
#if defined(OS_ANDROID)
if (compositor_task_runner_) {
synchronous_compositor_registry_ =
@@ -272,7 +283,7 @@ bool WidgetInputHandlerManager::HandleInputEvent(
}
void WidgetInputHandlerManager::SetNeedsMainFrame() {
- widget_->client()->ScheduleAnimation();
+ widget_->RequestAnimationAfterDelay(base::TimeDelta());
}
void WidgetInputHandlerManager::WillShutdown() {
@@ -328,12 +339,12 @@ void WidgetInputHandlerManager::GenerateScrollBeginAndSendToMainThread(
DCHECK_EQ(update_event.GetType(), WebInputEvent::Type::kGestureScrollUpdate);
auto event = std::make_unique<WebCoalescedInputEvent>(
ScrollBeginFromScrollUpdate(update_event), ui::LatencyInfo());
- base::TimeTicks metrics_time_stamp = update_metrics
- ? update_metrics->time_stamp()
- : event->Event().TimeStamp();
- std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
- event->Event().GetTypeAsUiEventType(), base::nullopt, metrics_time_stamp,
- event->Event().GetScrollInputType());
+ std::unique_ptr<cc::EventMetrics> metrics =
+ cc::EventMetrics::CreateFromExisting(
+ event->Event().GetTypeAsUiEventType(), base::nullopt,
+ event->Event().GetScrollInputType(),
+ cc::EventMetrics::DispatchStage::kRendererCompositorFinished,
+ update_metrics);
DispatchNonBlockingEventToMainThread(std::move(event), attribution,
std::move(metrics));
@@ -359,21 +370,21 @@ WidgetInputHandlerManager::GetWidgetInputHandlerHost() {
return nullptr;
}
+#if defined(OS_ANDROID)
void WidgetInputHandlerManager::AttachSynchronousCompositor(
mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
control_host,
mojo::PendingAssociatedRemote<mojom::blink::SynchronousCompositorHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor>
compositor_request) {
-#if defined(OS_ANDROID)
DCHECK(synchronous_compositor_registry_);
if (synchronous_compositor_registry_->proxy()) {
synchronous_compositor_registry_->proxy()->BindChannel(
std::move(control_host), std::move(host),
std::move(compositor_request));
}
-#endif
}
+#endif
void WidgetInputHandlerManager::ObserveGestureEventOnMainThread(
const WebGestureEvent& gesture_event,
@@ -428,6 +439,13 @@ void WidgetInputHandlerManager::
void WidgetInputHandlerManager::DispatchEvent(
std::unique_ptr<WebCoalescedInputEvent> event,
mojom::blink::WidgetInputHandler::DispatchEventCallback callback) {
+ // Since we can't easily track the end of processing for a non-blocking input
+ // event from here, we just temporarily bump kResponse mode for every
+ // dispatched event.
+ response_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kResponse);
+ response_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kResponseTimeout);
+
bool event_is_move =
event->Event().GetType() == WebInputEvent::Type::kMouseMove ||
event->Event().GetType() == WebInputEvent::Type::kPointerMove;
@@ -473,7 +491,7 @@ void WidgetInputHandlerManager::DispatchEvent(
}
std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
event->Event().GetTypeAsUiEventType(), scroll_update_type,
- event->Event().TimeStamp(), event->Event().GetScrollInputType());
+ event->Event().GetScrollInputType(), event->Event().TimeStamp());
if (uses_input_handler_) {
// If the input_handler_proxy has disappeared ensure we just ack event.
@@ -635,7 +653,8 @@ void WidgetInputHandlerManager::BindChannel(
// |compositor_task_runner_| as events might get out of order.
WidgetInputHandlerImpl* handler = new WidgetInputHandlerImpl(
this, main_thread_task_runner_,
- compositor_task_runner_ ? input_event_queue_ : nullptr, widget_);
+ compositor_task_runner_ ? input_event_queue_ : nullptr, widget_,
+ frame_widget_input_handler_);
handler->SetReceiver(std::move(receiver));
}
diff --git a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
index 124f0b80443..9348dc6fe00 100644
--- a/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
+++ b/chromium/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
@@ -10,6 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
@@ -68,8 +69,12 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
};
public:
+ // The `widget` and `frame_widget_input_handler` should be invalidated
+ // at the same time.
static scoped_refptr<WidgetInputHandlerManager> Create(
base::WeakPtr<WidgetBase> widget_base,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
bool never_composited,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
scheduler::WebThreadScheduler* main_thread_scheduler,
@@ -117,6 +122,7 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
mojom::blink::WidgetInputHandlerHost* GetWidgetInputHandlerHost();
+#if defined(OS_ANDROID)
void AttachSynchronousCompositor(
mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
control_host,
@@ -125,7 +131,6 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor>
compositor_request);
-#if defined(OS_ANDROID)
SynchronousCompositorRegistry* GetSynchronousCompositorRegistry();
#endif
@@ -168,6 +173,8 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
private:
WidgetInputHandlerManager(
base::WeakPtr<WidgetBase> widget,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler,
bool never_composited,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
scheduler::WebThreadScheduler* main_thread_scheduler);
@@ -251,6 +258,8 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
// Only valid to be called on the main thread.
base::WeakPtr<WidgetBase> widget_;
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler_;
std::unique_ptr<scheduler::WebWidgetScheduler> widget_scheduler_;
scheduler::WebThreadScheduler* main_thread_scheduler_;
@@ -313,6 +322,8 @@ class PLATFORM_EXPORT WidgetInputHandlerManager final
// the input handling thread (i.e. on the compositor thread if it exists).
bool has_seen_first_gesture_scroll_update_after_begin_ = false;
+ std::unique_ptr<power_scheduler::PowerModeVoter> response_power_mode_voter_;
+
#if defined(OS_ANDROID)
std::unique_ptr<SynchronousCompositorProxyRegistry>
synchronous_compositor_registry_;
diff --git a/chromium/third_party/blink/renderer/platform/widget/widget_base.cc b/chromium/third_party/blink/renderer/platform/widget/widget_base.cc
index 9cd69720a13..2d7ae9bbb5b 100644
--- a/chromium/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/chromium/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -145,18 +145,23 @@ WidgetBase::WidgetBase(
bool hidden,
bool never_composited,
bool is_for_child_local_root)
- : client_(client),
+ : never_composited_(never_composited),
+ is_for_child_local_root_(is_for_child_local_root),
+ use_zoom_for_dsf_(Platform::Current()->IsUseZoomForDSFEnabled()),
+ client_(client),
widget_host_(std::move(widget_host), task_runner),
receiver_(this, std::move(widget), task_runner),
next_previous_flags_(kInvalidNextPreviousFlagsValue),
- use_zoom_for_dsf_(Platform::Current()->IsUseZoomForDSFEnabled()),
is_hidden_(hidden),
- never_composited_(never_composited),
- is_for_child_local_root_(is_for_child_local_root) {
+ request_animation_after_delay_timer_(
+ std::move(task_runner),
+ this,
+ &WidgetBase::RequestAnimationAfterDelayTimerFired) {
if (auto* main_thread_scheduler =
scheduler::WebThreadScheduler::MainThreadScheduler()) {
render_widget_scheduling_state_ =
main_thread_scheduler->NewRenderWidgetSchedulingState();
+ render_widget_scheduling_state_->SetHidden(is_hidden_);
}
}
@@ -166,14 +171,18 @@ WidgetBase::~WidgetBase() {
}
void WidgetBase::InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
cc::TaskGraphRunner* task_graph_runner,
bool for_child_local_root_frame,
const ScreenInfo& screen_info,
std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
- const cc::LayerTreeSettings* settings) {
+ const cc::LayerTreeSettings* settings,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler) {
+ scheduler::WebThreadScheduler* main_thread_scheduler =
+ &agent_group_scheduler.GetMainThreadScheduler();
main_thread_compositor_task_runner_ =
- main_thread_scheduler->CompositorTaskRunner();
+ agent_group_scheduler.CompositorTaskRunner();
auto* compositing_thread_scheduler =
scheduler::WebThreadScheduler::CompositorThreadScheduler();
@@ -214,9 +223,9 @@ void WidgetBase::InitializeCompositing(
// WidgetBaseInputHandler.
bool uses_input_handler = frame_widget;
widget_input_handler_manager_ = WidgetInputHandlerManager::Create(
- weak_ptr_factory_.GetWeakPtr(), never_composited_,
- std::move(compositor_input_task_runner), main_thread_scheduler,
- uses_input_handler);
+ weak_ptr_factory_.GetWeakPtr(), std::move(frame_widget_input_handler),
+ never_composited_, std::move(compositor_input_task_runner),
+ main_thread_scheduler, uses_input_handler);
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -224,13 +233,19 @@ void WidgetBase::InitializeCompositing(
widget_input_handler_manager_->AllowPreCommitInput();
UpdateScreenInfo(screen_info);
-}
-void WidgetBase::Shutdown(
- scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner) {
- if (!cleanup_runner)
- cleanup_runner = base::ThreadTaskRunnerHandle::Get();
+ // If the widget is hidden, delay starting the compositor until the user
+ // shows it. Otherwise start the compositor immediately. If the widget is
+ // for a provisional frame, this importantly starts the compositor before
+ // the frame is inserted into the frame tree, which impacts first paint
+ // metrics.
+ if (!is_hidden_)
+ SetCompositorVisible(true);
+}
+void WidgetBase::Shutdown() {
+ scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner =
+ base::ThreadTaskRunnerHandle::Get();
// The |input_event_queue_| is refcounted and will live while an event is
// being handled. This drops the connection back to this WidgetBase which
// is being destroyed.
@@ -267,6 +282,10 @@ cc::LayerTreeHost* WidgetBase::LayerTreeHost() const {
return layer_tree_view_->layer_tree_host();
}
+bool WidgetBase::IsComposited() const {
+ return !!layer_tree_view_;
+}
+
cc::AnimationHost* WidgetBase::AnimationHost() const {
return layer_tree_view_->animation_host();
}
@@ -282,9 +301,10 @@ void WidgetBase::ForceRedraw(
base::BindOnce(&OnDidPresentForceDrawFrame, std::move(callback)));
LayerTreeHost()->SetNeedsCommitWithForcedRedraw();
- // ScheduleAnimationForWebTests() which is implemented by WebWidgetTestProxy,
- // providing the additional control over the lifecycle of compositing required
- // by web tests. This will be a no-op on production.
+ // ScheduleAnimationForWebTests() which is implemented by
+ // WebTestWebFrameWidgetImpl, providing the additional control over the
+ // lifecycle of compositing required by web tests. This will be a no-op on
+ // production.
client_->ScheduleAnimationForWebTests();
}
@@ -312,34 +332,34 @@ void WidgetBase::UpdateVisualProperties(
// properties are usually the same for every WidgetBase, except when
// device emulation changes them in the main frame WidgetBase only.
// Example: screen_info.
- // 3. Computed in the renderer of the main frame WebFrameWidgetBase (in blink
+ // 3. Computed in the renderer of the main frame WebFrameWidgetImpl (in blink
// usually). Passed down through the waterfall dance to child frame
- // WebFrameWidgetBase. Here that step is performed by passing the value
- // along to all RemoteFrame objects that are below this WebFrameWidgetBase
- // in the frame tree. The main frame (top level) WebFrameWidgetBase ignores
+ // WebFrameWidgetImpl. Here that step is performed by passing the value
+ // along to all RemoteFrame objects that are below this WebFrameWidgetImpl
+ // in the frame tree. The main frame (top level) WebFrameWidgetImpl ignores
// this value from its RenderWidgetHost since it is controlled in the
- // renderer. Child frame WebFrameWidgetBases consume the value from their
+ // renderer. Child frame WebFrameWidgetImpls consume the value from their
// RenderWidgetHost. Example: page_scale_factor.
// 4. Computed independently in the renderer for each WidgetBase (in blink
// usually). Passed down from the parent to the child WidgetBases through
// the waterfall dance, but the value only travels one step - the child
- // frame WebFrameWidgetBase would compute values for grandchild
- // WebFrameWidgetBases independently. Here the value is passed to child
+ // frame WebFrameWidgetImpl would compute values for grandchild
+ // WebFrameWidgetImpls independently. Here the value is passed to child
// frame RenderWidgets by passing the value along to all RemoteFrame
- // objects that are below this WebFrameWidgetBase in the frame tree. Each
+ // objects that are below this WebFrameWidgetImpl in the frame tree. Each
// WidgetBase consumes this value when it is received from its
// RenderWidgetHost. Example: compositor_viewport_pixel_rect.
// For each of these properties:
- // If the WebView also knows these properties, each WebFrameWidgetBase
+ // If the WebView also knows these properties, each WebFrameWidgetImpl
// will pass them along to the WebView as it receives it, even if there
- // are multiple WebFrameWidgetBases related to the same WebView.
+ // are multiple WebFrameWidgetImpls related to the same WebView.
// However when the main frame in the renderer is the source of truth,
// then child widgets must not clobber that value! In all cases child frames
// do not need to update state in the WebView when a local main frame is
// present as it always sets the value first.
// TODO(danakj): This does create a race if there are multiple
- // UpdateVisualProperties updates flowing through the WebFrameWidgetBase
- // tree at the same time, and it seems that only one WebFrameWidgetBase for
+ // UpdateVisualProperties updates flowing through the WebFrameWidgetImpl
+ // tree at the same time, and it seems that only one WebFrameWidgetImpl for
// each WebView should be responsible for this update.
//
// TODO(danakj): A more explicit API to give values from here to RenderView
@@ -353,7 +373,7 @@ void WidgetBase::UpdateVisualProperties(
blink::VisualProperties visual_properties = visual_properties_from_browser;
// Web tests can override the device scale factor in the renderer.
- if (auto scale_factor = client_->GetDeviceScaleFactorForTesting()) {
+ if (auto scale_factor = client_->GetTestingDeviceScaleFactorOverride()) {
visual_properties.screen_info.device_scale_factor = scale_factor;
visual_properties.compositor_viewport_pixel_rect =
gfx::Rect(gfx::ScaleToCeiledSize(
@@ -374,14 +394,11 @@ void WidgetBase::UpdateVisualProperties(
LayerTreeHost()->SetBrowserControlsParams(
visual_properties.browser_controls_params);
- client_->UpdateVisualProperties(visual_properties);
+ LayerTreeHost()->SetVisualDeviceViewportSize(gfx::ScaleToCeiledSize(
+ visual_properties.visible_viewport_size,
+ visual_properties.screen_info.device_scale_factor));
- // FrameWidgets have custom code for external page scale factor.
- if (!client_->FrameWidget()) {
- LayerTreeHost()->SetExternalPageScaleFactor(
- visual_properties.page_scale_factor,
- visual_properties.is_pinch_gesture_active);
- }
+ client_->UpdateVisualProperties(visual_properties);
}
void WidgetBase::UpdateScreenRects(const gfx::Rect& widget_screen_rect,
@@ -442,20 +459,9 @@ void WidgetBase::ApplyViewportChanges(
client_->ApplyViewportChanges(args);
}
-void WidgetBase::RecordManipulationTypeCounts(cc::ManipulationInfo info) {
- client_->RecordManipulationTypeCounts(info);
-}
-
-void WidgetBase::SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) {
- client_->SendOverscrollEventFromImplSide(overscroll_delta,
- scroll_latched_element_id);
-}
-
-void WidgetBase::SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) {
- client_->SendScrollEndEventFromImplSide(scroll_latched_element_id);
+void WidgetBase::UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) {
+ client_->UpdateCompositorScrollState(commit_data);
}
void WidgetBase::OnDeferMainFrameUpdatesChanged(bool defer) {
@@ -717,6 +723,10 @@ WidgetBase::GetBeginMainFrameMetrics() {
return client_->GetBeginMainFrameMetrics();
}
+std::unique_ptr<cc::WebVitalMetrics> WidgetBase::GetWebVitalMetrics() {
+ return client_->GetWebVitalMetrics();
+}
+
void WidgetBase::BeginUpdateLayers() {
client_->BeginUpdateLayers();
}
@@ -832,6 +842,8 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
ui::mojom::VirtualKeyboardVisibilityRequest last_vk_visibility_request =
ui::mojom::VirtualKeyboardVisibilityRequest::NONE;
bool always_hide_ime = false;
+ base::Optional<gfx::Rect> control_bounds;
+ base::Optional<gfx::Rect> selection_bounds;
if (frame_widget) {
new_info = frame_widget->TextInputInfo();
// This will be used to decide whether or not to show VK when VK policy is
@@ -842,6 +854,8 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
// Check whether the keyboard should always be hidden for the currently
// focused element.
always_hide_ime = frame_widget->ShouldSuppressKeyboardForFocusedElement();
+ frame_widget->GetEditContextBoundsInWindow(&control_bounds,
+ &selection_bounds);
}
const ui::TextInputMode new_mode =
ConvertWebTextInputMode(new_info.input_mode);
@@ -858,7 +872,9 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
always_hide_ime_ != always_hide_ime || vk_policy_ != new_vk_policy ||
(new_vk_policy == ui::mojom::VirtualKeyboardPolicy::MANUAL &&
(last_vk_visibility_request !=
- ui::mojom::VirtualKeyboardVisibilityRequest::NONE))) {
+ ui::mojom::VirtualKeyboardVisibilityRequest::NONE)) ||
+ (control_bounds && frame_control_bounds_ != control_bounds) ||
+ (selection_bounds && frame_selection_bounds_ != selection_bounds)) {
ui::mojom::blink::TextInputStatePtr params =
ui::mojom::blink::TextInputState::New();
params->type = new_type;
@@ -867,15 +883,13 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
params->flags = new_info.flags;
params->vk_policy = new_vk_policy;
params->last_vk_visibility_request = last_vk_visibility_request;
+ params->edit_context_control_bounds = control_bounds;
+ params->edit_context_selection_bounds = selection_bounds;
+
if (!new_info.ime_text_spans.empty()) {
params->ime_text_spans_info =
frame_widget->GetImeTextSpansInfo(new_info.ime_text_spans);
}
- if (frame_widget) {
- frame_widget->GetEditContextBoundsInWindow(
- &params->edit_context_control_bounds,
- &params->edit_context_selection_bounds);
- }
#if defined(OS_ANDROID)
if (next_previous_flags_ == kInvalidNextPreviousFlagsValue) {
// Due to a focus change, values will be reset by the frame.
@@ -917,6 +931,10 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
can_compose_inline_ = new_can_compose_inline;
always_hide_ime_ = always_hide_ime;
text_input_flags_ = new_info.flags;
+ frame_control_bounds_ = control_bounds.value_or(gfx::Rect());
+ // Selection bounds are not populated in non-EditContext scenarios.
+ // It is communicated to IMEs via |WidgetBase::UpdateSelectionBounds|.
+ frame_selection_bounds_ = selection_bounds.value_or(gfx::Rect());
// Reset the show/hide state in the InputMethodController.
if (frame_widget) {
if (last_vk_visibility_request !=
@@ -931,7 +949,10 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
// new RenderFrameMetadata, as the IME will need this info to be updated.
// TODO(ericrk): Consider folding the above IPC into RenderFrameMetadata.
// https://crbug.com/912309
- LayerTreeHost()->RequestForceSendMetadata();
+ // Compositing might not be initialized but input can still be dispatched
+ // to non-composited widgets so LayerTreeHost may be null.
+ if (IsComposited())
+ LayerTreeHost()->RequestForceSendMetadata();
#endif
}
}
@@ -946,7 +967,7 @@ void WidgetBase::ClearTextInputState() {
}
void WidgetBase::ShowVirtualKeyboardOnElementFocus() {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// On ChromeOS, virtual keyboard is triggered only when users leave the
// mouse button or the finger and a text input element is focused at that
// time. Focus event itself shouldn't trigger virtual keyboard.
@@ -1232,9 +1253,7 @@ void WidgetBase::ImeFinishComposingText(bool keep_selection) {
void WidgetBase::QueueSyntheticEvent(
std::unique_ptr<WebCoalescedInputEvent> event) {
- FrameWidget* frame_widget = client_->FrameWidget();
- if (frame_widget)
- frame_widget->Client()->WillQueueSyntheticEvent(*event);
+ client_->WillQueueSyntheticEvent(*event);
// TODO(acomminos): If/when we add support for gesture event attribution on
// the impl thread, have the caller provide attribution.
@@ -1302,6 +1321,27 @@ void WidgetBase::OnImeEventGuardFinish(ImeEventGuard* guard) {
#endif
}
+void WidgetBase::RequestAnimationAfterDelay(const base::TimeDelta& delay) {
+ if (delay.is_zero()) {
+ client_->ScheduleAnimation();
+ return;
+ }
+
+ // Consolidate delayed animation frame requests to keep only the longest
+ // delay.
+ if (request_animation_after_delay_timer_.IsActive() &&
+ request_animation_after_delay_timer_.NextFireInterval() > delay) {
+ request_animation_after_delay_timer_.Stop();
+ }
+ if (!request_animation_after_delay_timer_.IsActive()) {
+ request_animation_after_delay_timer_.StartOneShot(delay, FROM_HERE);
+ }
+}
+
+void WidgetBase::RequestAnimationAfterDelayTimerFired(TimerBase*) {
+ client_->ScheduleAnimation();
+}
+
void WidgetBase::UpdateSurfaceAndScreenInfo(
const viz::LocalSurfaceId& new_local_surface_id,
const gfx::Rect& compositor_viewport_pixel_rect,
@@ -1331,9 +1371,10 @@ void WidgetBase::UpdateSurfaceAndScreenInfo(
compositor_viewport_pixel_rect,
client_->GetOriginalScreenInfo().device_scale_factor,
local_surface_id_from_parent_);
- // The ViewportVisibleRect derives from the LayerTreeView's viewport size,
- // which is set above.
- LayerTreeHost()->SetViewportVisibleRect(client_->ViewportVisibleRect());
+ // The VisualDeviceViewportIntersectionRect derives from the LayerTreeView's
+ // viewport size, which is set above.
+ LayerTreeHost()->SetVisualDeviceViewportIntersectionRect(
+ client_->ViewportVisibleRect());
LayerTreeHost()->SetDisplayColorSpaces(screen_info_.display_color_spaces);
if (orientation_changed)
@@ -1426,7 +1467,7 @@ bool WidgetBase::ComputePreferCompositingToLCDText() {
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kDisablePreferCompositingToLCDText))
return false;
-#if defined(OS_ANDROID) || BUILDFLAG(IS_ASH)
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// On Android, we never have subpixel antialiasing. On Chrome OS we prefer to
// composite all scrollers for better scrolling performance.
return true;
diff --git a/chromium/third_party/blink/renderer/platform/widget/widget_base.h b/chromium/third_party/blink/renderer/platform/widget/widget_base.h
index 53a539f143f..45c1ee5c53d 100644
--- a/chromium/third_party/blink/renderer/platform/widget/widget_base.h
+++ b/chromium/third_party/blink/renderer/platform/widget/widget_base.h
@@ -20,6 +20,7 @@
#include "third_party/blink/public/platform/web_text_input_info.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h"
#include "third_party/blink/renderer/platform/widget/input/widget_base_input_handler.h"
@@ -46,12 +47,12 @@ class WidgetInputHandlerManager;
class WidgetCompositor;
namespace scheduler {
+class WebAgentGroupScheduler;
class WebRenderWidgetSchedulingState;
-class WebThreadScheduler;
}
// This class is the foundational class for all widgets that blink creates.
-// (WebPagePopupImpl, WebFrameWidgetBase) will contain an instance of this
+// (WebPagePopupImpl, WebFrameWidgetImpl) will contain an instance of this
// class. For simplicity purposes this class will be a member of those classes.
//
// Co-orindates handled in this class can be in the "blink coordinate space"
@@ -74,16 +75,25 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
// Initialize the compositor. |settings| is typically null. When |settings| is
// null the default settings will be used, tests may provide a |settings|
// object to override the defaults.
+ //
+ // TODO(dtapuska): The WebFrameWidgetImpl should be responsible for making
+ // the FrameWidgetInputHandlerImpl, but currently it is done in the general
+ // widget input handler classes directly, so we have to plumb through the
+ // main-thread mojom implementation.
+ // The `frame_widget_input_handler` must be invalidated when the WidgetBase is
+ // destroyed/invalidated.
void InitializeCompositing(
- scheduler::WebThreadScheduler* main_thread_scheduler,
+ scheduler::WebAgentGroupScheduler& agent_group_scheduler,
cc::TaskGraphRunner* task_graph_runner,
bool for_child_local_root_frame,
const ScreenInfo& screen_info,
std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory,
- const cc::LayerTreeSettings* settings);
+ const cc::LayerTreeSettings* settings,
+ base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
+ frame_widget_input_handler);
// Shutdown the compositor.
- void Shutdown(scoped_refptr<base::SingleThreadTaskRunner> cleanup_runner);
+ void Shutdown();
// Set the compositor as visible. If |visible| is true, then the compositor
// will request a new layer frame sink, begin producing frames from the
@@ -114,12 +124,8 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
// Applies viewport related properties during a commit from the compositor
// thread.
void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override;
- void RecordManipulationTypeCounts(cc::ManipulationInfo info) override;
- void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) override;
- void SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) override;
+ void UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) override;
void BeginMainFrame(base::TimeTicks frame_time) override;
void OnDeferMainFrameUpdatesChanged(bool) override;
void OnDeferCommitsChanged(bool) override;
@@ -139,6 +145,7 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
cc::ActiveFrameSequenceTrackers trackers) override;
std::unique_ptr<cc::BeginMainFrameMetrics> GetBeginMainFrameMetrics()
override;
+ std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() override;
void BeginUpdateLayers() override;
void EndUpdateLayers() override;
void UpdateVisualState() override;
@@ -148,6 +155,7 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
cc::AnimationHost* AnimationHost() const;
cc::LayerTreeHost* LayerTreeHost() const;
+ bool IsComposited() const;
scheduler::WebRenderWidgetSchedulingState* RendererWidgetSchedulingState()
const;
@@ -178,6 +186,10 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
void SetToolTipText(const String& tooltip_text, TextDirection dir);
+ // Posts a task with the given delay, then calls ScheduleAnimation() on the
+ // WidgetBaseClient.
+ void RequestAnimationAfterDelay(const base::TimeDelta& delay);
+
void ShowVirtualKeyboard();
void UpdateSelectionBounds();
void UpdateTextInputState();
@@ -340,11 +352,24 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
// our state.
void SetHidden(bool hidden);
- std::unique_ptr<LayerTreeView> layer_tree_view_;
- scoped_refptr<WidgetInputHandlerManager> widget_input_handler_manager_;
- WidgetBaseClient* client_;
+ // Called after the delay given in `RequestAnimationAfterDelay()`.
+ void RequestAnimationAfterDelayTimerFired(TimerBase*);
+
+ // Indicates that we are never visible, so never produce graphical output.
+ const bool never_composited_;
+ // Indicates this is for a child local root.
+ const bool is_for_child_local_root_;
+ // When true, the device scale factor is a part of blink coordinates.
+ const bool use_zoom_for_dsf_;
+
+ // The client which handles behaviour specific to the type of widget.
+ WidgetBaseClient* const client_;
+
mojo::AssociatedRemote<mojom::blink::WidgetHost> widget_host_;
mojo::AssociatedReceiver<mojom::blink::Widget> receiver_;
+
+ std::unique_ptr<LayerTreeView> layer_tree_view_;
+ scoped_refptr<WidgetInputHandlerManager> widget_input_handler_manager_;
std::unique_ptr<scheduler::WebRenderWidgetSchedulingState>
render_widget_scheduling_state_;
bool has_focus_ = false;
@@ -377,6 +402,13 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
ui::mojom::VirtualKeyboardPolicy vk_policy_ =
ui::mojom::VirtualKeyboardPolicy::AUTO;
+ // Stores the current control and selection bounds of |webwidget_|
+ // that are used to position the candidate window during IME composition.
+ // These are stored in DIPs if use-zoom-for-dsf is disabled and are relative
+ // to the widget
+ gfx::Rect frame_control_bounds_;
+ gfx::Rect frame_selection_bounds_;
+
// Stores the current text input flags of |webwidget_|.
int text_input_flags_ = 0;
@@ -430,16 +462,12 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
// See https://crbug.com/1131389
gfx::Size visible_viewport_size_in_dips_;
- const bool use_zoom_for_dsf_;
-
// Indicates that we shouldn't bother generated paint events.
bool is_hidden_;
- // Indicates that we are never visible, so never produce graphical output.
- const bool never_composited_;
-
- // Indicates this is for a child local root.
- const bool is_for_child_local_root_;
+ // Delayed callback to ensure we have only one delayed ScheduleAnimation()
+ // call going at a time.
+ TaskRunnerTimer<WidgetBase> request_animation_after_delay_timer_;
// The task runner on the main thread used for compositor tasks.
scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/chromium/third_party/blink/renderer/platform/widget/widget_base_client.h b/chromium/third_party/blink/renderer/platform/widget/widget_base_client.h
index 1012eb159c7..4adff33fa0d 100644
--- a/chromium/third_party/blink/renderer/platform/widget/widget_base_client.h
+++ b/chromium/third_party/blink/renderer/platform/widget/widget_base_client.h
@@ -8,17 +8,23 @@
#include <vector>
#include "base/time/time.h"
+#include "cc/metrics/begin_main_frame_metrics.h"
+#include "cc/metrics/frame_sequence_tracker_collection.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "cc/paint/element_id.h"
+#include "cc/trees/layer_tree_host_client.h"
#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
#include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
#include "third_party/blink/public/platform/input/input_handler_proxy.h"
+#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/public/platform/web_text_input_type.h"
#include "third_party/blink/public/web/web_lifecycle_update.h"
namespace cc {
class LayerTreeFrameSink;
struct BeginMainFrameMetrics;
+struct WebVitalMetrics;
} // namespace cc
namespace blink {
@@ -69,6 +75,10 @@ class WidgetBaseClient {
return nullptr;
}
+ virtual std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() {
+ return nullptr;
+ }
+
// Methods called to mark the beginning and end of the
// LayerTreeHost::UpdateLayers method. Only called when gathering main frame
// UMA and UKM. That is, when RecordStartOfFrameMetrics has been called, and
@@ -87,14 +97,11 @@ class WidgetBaseClient {
// thread.
virtual void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) {}
- virtual void RecordManipulationTypeCounts(cc::ManipulationInfo info) {}
-
- virtual void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- cc::ElementId scroll_latched_element_id) {}
- virtual void SendScrollEndEventFromImplSide(
- cc::ElementId scroll_latched_element_id) {}
+ virtual void UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) {}
+ // Notifies that the layer tree host has completed a call to
+ // RequestMainFrameUpdate in response to a BeginMainFrame.
virtual void DidBeginMainFrame() {}
virtual void DidCommitAndDrawCompositorFrame() {}
@@ -105,6 +112,10 @@ class WidgetBaseClient {
virtual void WillBeginMainFrame() {}
virtual void DidCompletePageScaleAnimation() {}
+ // Allocates a LayerTreeFrameSink to submit CompositorFrames to. Only
+ // override this method if you wish to provide your own implementation
+ // of LayerTreeFrameSinks (usually for tests). If this method returns null
+ // a frame sink will be requested from the browser process (ie. default flow)
virtual std::unique_ptr<cc::LayerTreeFrameSink>
AllocateNewLayerTreeFrameSink() = 0;
@@ -137,7 +148,7 @@ class WidgetBaseClient {
// Called to inform the Widget that it has gained or lost keyboard focus.
virtual void FocusChanged(bool) {}
- // Call to schedule an animation.
+ // Call to request an animation frame from the compositor.
virtual void ScheduleAnimation() {}
// TODO(bokan): Temporary to unblock synthetic gesture events running under
@@ -182,7 +193,7 @@ class WidgetBaseClient {
}
// Return the overridden device scale factor for testing.
- virtual float GetDeviceScaleFactorForTesting() { return 0.f; }
+ virtual float GetTestingDeviceScaleFactorOverride() { return 0.f; }
// Test-specific methods below this point.
virtual void ScheduleAnimationForWebTests() {}
@@ -196,6 +207,9 @@ class WidgetBaseClient {
virtual void RunPaintBenchmark(int repeat_count,
cc::PaintBenchmarkResult& result) {}
+ // Called to indicate a synthetic event was queued.
+ virtual void WillQueueSyntheticEvent(const WebCoalescedInputEvent& event) {}
+
// When the WebWidget is part of a frame tree, returns the active url for
// main frame of that tree, if the main frame is local in that tree. When
// the WebWidget is of a different kind (e.g. a popup) it returns the active
diff --git a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
index 661dd85c715..458b8646e8b 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -19,6 +19,7 @@ buildflag_header("buildflags") {
visibility = [
":*",
+ "//:gn_all",
"//mojo/public/cpp/bindings/*",
"//third_party/blink/*",
]
@@ -212,6 +213,7 @@ component("wtf") {
deps = [
":buildflags",
+ "//build:chromeos_buildflags",
# TODO(tkent): WTF should not depend on it.
"//third_party/blink/public/common:headers",
diff --git a/chromium/third_party/blink/renderer/platform/wtf/DEPS b/chromium/third_party/blink/renderer/platform/wtf/DEPS
index 962b2909012..0b8fe9a712c 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/DEPS
+++ b/chromium/third_party/blink/renderer/platform/wtf/DEPS
@@ -1,6 +1,7 @@
include_rules = [
# To only allow a subset of base/ in Blink, we explicitly list all
# directories and files instead of writing 'base/'.
+ "+base/allocator/buildflags.h",
"+base/allocator/partition_allocator",
"+base/atomic_ref_count.h",
"+base/auto_reset.h",
@@ -14,6 +15,7 @@ include_rules = [
"+base/memory/ref_counted.h",
"+base/memory/weak_ptr.h",
"+base/metrics/histogram_macros.h",
+ "+base/no_destructor.h",
"+base/numerics",
"+base/optional.h",
"+base/process/process_metrics.h",
diff --git a/chromium/third_party/blink/renderer/platform/wtf/DIR_METADATA b/chromium/third_party/blink/renderer/platform/wtf/DIR_METADATA
new file mode 100644
index 00000000000..23763da8568
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/wtf/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Internals>WTF"
+}
+team_email: "platform-architecture-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/wtf/OWNERS b/chromium/third_party/blink/renderer/platform/wtf/OWNERS
index 52eda6933ad..024e0c837f5 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/wtf/OWNERS
@@ -4,6 +4,3 @@ jochen@chromium.org
thakis@chromium.org
tkent@chromium.org
yutak@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/allocator.h b/chromium/third_party/blink/renderer/platform/wtf/allocator/allocator.h
index b135f379ddf..13f4753f78f 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/allocator.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/allocator.h
@@ -7,6 +7,7 @@
#include <atomic>
+#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/check_op.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
@@ -27,10 +28,7 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
// non-garbage-collected objects to avoid unintended allocations.
//
// STACK_ALLOCATED(): Use if the object is only stack allocated.
-// Garbage-collected objects should be in Members but you do not need the
-// trace method as they are on the stack. (Down the line these might turn
-// in to raw pointers, but for now Members indicate that we have thought
-// about them and explicitly taken care of them.)
+// Garbage-collected objects should be in raw pointers.
//
// DISALLOW_NEW(): Cannot be allocated with new operators but can be a
// part of object, a value object in collections or stack allocated. If it has
@@ -64,15 +62,6 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-#define IS_GARBAGE_COLLECTED_CONTAINER_TYPE() \
- IS_GARBAGE_COLLECTED_TYPE(); \
- \
- public: \
- using IsGarbageCollectedCollectionTypeMarker = int; \
- \
- private: \
- friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-
#if defined(__clang__)
#define ANNOTATE_STACK_ALLOCATED \
__attribute__((annotate("blink_stack_allocated")))
@@ -108,6 +97,58 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
// };
//
+// In official builds, do not include type info string literals to avoid
+// bloating the binary.
+#if defined(OFFICIAL_BUILD)
+#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr
+#else
+#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>()
+#endif
+
+// Both of these macros enable fast malloc and provide type info to the heap
+// profiler. The regular macro does not provide type info in official builds,
+// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME|
+// variant provides type info unconditionally, so it should be used sparingly.
+// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a
+// template argument; |USING_FAST_MALLOC| does.
+#define USING_FAST_MALLOC(type) \
+ USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type))
+#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
+ USING_FAST_MALLOC_INTERNAL(type, #type)
+
+// FastMalloc doesn't provide isolation, only a (hopefully fast) malloc(). When
+// PartitionAlloc is already the malloc() implementation, there is nothing to
+// do.
+//
+// Note that we could keep the two heaps separate, but each PartitionAlloc's
+// root has a cost, both in used memory and in virtual address space. Don't pay
+// it when we don't have to.
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+
+// Still using operator overaloading to be closer to the other case, and not
+// require code changes to DISALLOW_NEW() objects.
+#define USING_FAST_MALLOC_INTERNAL(type, typeName) \
+ public: \
+ void* operator new(size_t, void* p) { return p; } \
+ void* operator new[](size_t, void* p) { return p; } \
+ \
+ void* operator new(size_t size) { return malloc(size); } \
+ \
+ void operator delete(void* p) { free(p); } \
+ \
+ void* operator new[](size_t size) { return malloc(size); } \
+ \
+ void operator delete[](void* p) { free(p); } \
+ void* operator new(size_t, NotNullTag, void* location) { \
+ DCHECK(location); \
+ return location; \
+ } \
+ \
+ private: \
+ friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
+
+#else
+
#define USING_FAST_MALLOC_INTERNAL(type, typeName) \
public: \
void* operator new(size_t, void* p) { return p; } \
@@ -132,24 +173,7 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-// In official builds, do not include type info string literals to avoid
-// bloating the binary.
-#if defined(OFFICIAL_BUILD)
-#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr
-#else
-#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>()
-#endif
-
-// Both of these macros enable fast malloc and provide type info to the heap
-// profiler. The regular macro does not provide type info in official builds,
-// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME|
-// variant provides type info unconditionally, so it should be used sparingly.
-// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a
-// template argument; |USING_FAST_MALLOC| does.
-#define USING_FAST_MALLOC(type) \
- USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type))
-#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
- USING_FAST_MALLOC_INTERNAL(type, #type)
+#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// TOOD(omerkatz): replace these casts with std::atomic_ref (C++20) once it
// becomes available
@@ -359,4 +383,4 @@ inline void* operator new(size_t, NotNullTag, void* location) {
return location;
}
-#endif /* WTF_Allocator_h */
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ALLOCATOR_ALLOCATOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h b/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
index bc94e562003..f43947d0747 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
@@ -30,7 +30,7 @@ class WTF_EXPORT PartitionAllocator {
template <typename T>
static size_t QuantizedSize(size_t count) {
CHECK_LE(count, MaxElementCountInBackingStore<T>());
- return WTF::Partitions::BufferActualSize(count * sizeof(T));
+ return WTF::Partitions::BufferPotentialCapacity(count * sizeof(T));
}
template <typename T>
static T* AllocateVectorBacking(size_t size) {
@@ -67,6 +67,11 @@ class WTF_EXPORT PartitionAllocator {
}
static inline bool ExpandHashTableBacking(void*, size_t) { return false; }
+ template <typename Traits>
+ static inline bool CanReuseHashTableDeletedBucket() {
+ return true;
+ }
+
static void Free(void* address) { WTF::Partitions::FastFree(address); }
template <typename T>
static void* NewArray(size_t bytes) {
@@ -76,7 +81,8 @@ class WTF_EXPORT PartitionAllocator {
Free(ptr); // Not the system free, the one from this class.
}
- static void TraceBackingStoreIfMarked(const void*) {}
+ template <typename T>
+ static void TraceBackingStoreIfMarked(T**) {}
template <typename T>
static void BackingWriteBarrier(T**) {}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index e6c60b06bd2..8621cb4d6b5 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -35,6 +35,7 @@
#include "base/allocator/partition_allocator/page_allocator.h"
#include "base/allocator/partition_allocator/partition_alloc_features.h"
#include "base/debug/alias.h"
+#include "base/no_destructor.h"
#include "base/strings/safe_sprintf.h"
#include "base/thread_annotations.h"
#include "components/crash/core/common/crash_key.h"
@@ -46,11 +47,19 @@ namespace WTF {
const char* const Partitions::kAllocatedObjectPoolName =
"partition_alloc/allocated_objects";
+#if PA_ALLOW_PCSCAN
+// Runs PCScan on WTF partitions.
+const base::Feature kPCScanBlinkPartitions{"PCScanBlinkPartitions",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
bool Partitions::initialized_ = false;
// These statics are inlined, so cannot be LazyInstances. We create the values,
// and then set the pointers correctly in Initialize().
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
base::ThreadSafePartitionRoot* Partitions::fast_malloc_root_ = nullptr;
+#endif
base::ThreadSafePartitionRoot* Partitions::array_buffer_root_ = nullptr;
base::ThreadSafePartitionRoot* Partitions::buffer_root_ = nullptr;
base::ThreadUnsafePartitionRoot* Partitions::layout_root_ = nullptr;
@@ -63,50 +72,52 @@ void Partitions::Initialize() {
// static
bool Partitions::InitializeOnce() {
- static base::PartitionAllocator fast_malloc_allocator{};
- static base::PartitionAllocator array_buffer_allocator{};
- static base::PartitionAllocator buffer_allocator{};
- static base::ThreadUnsafePartitionAllocator layout_allocator{};
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+ static base::NoDestructor<base::PartitionAllocator> fast_malloc_allocator{};
+ fast_malloc_allocator->init({base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kEnabled,
+ base::PartitionOptions::Quarantine::kAllowed,
+ base::PartitionOptions::RefCount::kDisabled});
+
+ fast_malloc_root_ = fast_malloc_allocator->root();
+#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+
+ static base::NoDestructor<base::PartitionAllocator> array_buffer_allocator{};
+ static base::NoDestructor<base::PartitionAllocator> buffer_allocator{};
+ static base::NoDestructor<base::ThreadUnsafePartitionAllocator>
+ layout_allocator{};
base::PartitionAllocGlobalInit(&Partitions::HandleOutOfMemory);
- // Restrictions:
- // - DCHECK_IS_ON(): Memory usage of the thread cache is not optimized yet,
- // don't ship this.
- // - BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC): Only one thread cache at a time
- // is supported, in this case it is already claimed by malloc().
-#if DCHECK_IS_ON() && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
- fast_malloc_allocator.init(
- {base::PartitionOptions::Alignment::kRegular,
- base::PartitionOptions::ThreadCache::kEnabled,
- base::PartitionOptions::PCScan::kDisabledByDefault});
-#else
- fast_malloc_allocator.init(
- {base::PartitionOptions::Alignment::kRegular,
- base::PartitionOptions::ThreadCache::kDisabled,
- base::PartitionOptions::PCScan::kDisabledByDefault});
+ array_buffer_allocator->init({base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::Quarantine::kAllowed,
+ base::PartitionOptions::RefCount::kDisabled});
+ buffer_allocator->init({base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::Quarantine::kAllowed,
+ base::PartitionOptions::RefCount::kDisabled});
+ layout_allocator->init({base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::Quarantine::kAllowed,
+ base::PartitionOptions::RefCount::kDisabled});
+
+ array_buffer_root_ = array_buffer_allocator->root();
+ buffer_root_ = buffer_allocator->root();
+ layout_root_ = layout_allocator->root();
+
+#if PA_ALLOW_PCSCAN
+ if (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan) ||
+ base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) {
+ auto& pcscan =
+ base::internal::PCScan<base::internal::ThreadSafe>::Instance();
+ pcscan.RegisterNonScannableRoot(array_buffer_root_);
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+ pcscan.RegisterScannableRoot(fast_malloc_root_);
#endif
- array_buffer_allocator.init(
- {base::PartitionOptions::Alignment::kRegular,
- base::PartitionOptions::ThreadCache::kDisabled,
- base::PartitionOptions::PCScan::kAlwaysDisabled});
- buffer_allocator.init({base::PartitionOptions::Alignment::kRegular,
- base::PartitionOptions::ThreadCache::kDisabled,
- base::PartitionOptions::PCScan::kDisabledByDefault});
- layout_allocator.init({base::PartitionOptions::Alignment::kRegular,
- base::PartitionOptions::ThreadCache::kDisabled,
- base::PartitionOptions::PCScan::kDisabledByDefault});
-
- fast_malloc_root_ = fast_malloc_allocator.root();
- array_buffer_root_ = array_buffer_allocator.root();
- buffer_root_ = buffer_allocator.root();
- layout_root_ = layout_allocator.root();
-
- if (base::features::IsPartitionAllocPCScanEnabled()) {
- fast_malloc_root_->EnablePCScan();
- buffer_root_->EnablePCScan();
- layout_root_->EnablePCScan();
+ pcscan.RegisterScannableRoot(buffer_root_);
}
+#endif
initialized_ = true;
return initialized_;
@@ -129,8 +140,10 @@ void Partitions::DumpMemoryStats(
// accessed only on the main thread.
DCHECK(IsMainThread());
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
FastMallocPartition()->DumpStats("fast_malloc", is_light_dump,
partition_stats_dumper);
+#endif
ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump,
partition_stats_dumper);
BufferPartition()->DumpStats("buffer", is_light_dump, partition_stats_dumper);
@@ -166,8 +179,10 @@ size_t Partitions::TotalSizeOfCommittedPages() {
DCHECK(initialized_);
size_t total_size = 0;
// Racy reads below: this is fine to collect statistics.
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
total_size +=
TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages);
+#endif
total_size +=
TS_UNCHECKED_READ(ArrayBufferPartition()->total_size_of_committed_pages);
total_size +=
@@ -256,24 +271,40 @@ void Partitions::BufferFree(void* p) {
}
// static
-size_t Partitions::BufferActualSize(size_t n) {
- return BufferPartition()->ActualSize(n);
+size_t Partitions::BufferPotentialCapacity(size_t n) {
+ return BufferPartition()->AllocationCapacityFromRequestedSize(n);
}
+// Ideally this would be removed when PartitionAlloc is malloc(), but there are
+// quite a few callers. Just forward to the C functions instead. Most of the
+// usual callers will never reach here though, as USING_FAST_MALLOC() becomes a
+// no-op.
// static
void* Partitions::FastMalloc(size_t n, const char* type_name) {
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
return FastMallocPartition()->Alloc(n, type_name);
+#else
+ return malloc(n);
+#endif
}
// static
void* Partitions::FastZeroedMalloc(size_t n, const char* type_name) {
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
return FastMallocPartition()->AllocFlags(base::PartitionAllocZeroFill, n,
type_name);
+#else
+ return calloc(n, 1);
+#endif
}
// static
void Partitions::FastFree(void* p) {
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
FastMallocPartition()->Free(p);
+#else
+ free(p);
+#endif
}
// static
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.h b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.h
index b8b89b1f7ec..9da09e149ea 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions.h
@@ -80,7 +80,7 @@ class WTF_EXPORT Partitions {
static void* BufferMalloc(size_t n, const char* type_name);
static void* BufferTryRealloc(void* p, size_t n, const char* type_name);
static void BufferFree(void* p);
- static size_t BufferActualSize(size_t n);
+ static size_t BufferPotentialCapacity(size_t n);
static void* FastMalloc(size_t n, const char* type_name);
static void* FastZeroedMalloc(size_t n, const char* type_name);
@@ -89,16 +89,20 @@ class WTF_EXPORT Partitions {
static void HandleOutOfMemory(size_t size);
private:
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
ALWAYS_INLINE static base::ThreadSafePartitionRoot* FastMallocPartition() {
DCHECK(initialized_);
return fast_malloc_root_;
}
+#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static bool InitializeOnce();
static bool initialized_;
// See Allocator.md for a description of these partitions.
+#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static base::ThreadSafePartitionRoot* fast_malloc_root_;
+#endif
static base::ThreadSafePartitionRoot* array_buffer_root_;
static base::ThreadSafePartitionRoot* buffer_root_;
static base::ThreadUnsafePartitionRoot* layout_root_;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions_test.cc b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions_test.cc
index 3f6867cfa45..13ba1c8bdbb 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/allocator/partitions_test.cc
@@ -19,7 +19,7 @@ namespace WTF {
class PartitionsTest : public ::testing::Test {
protected:
void TearDown() override {
- base::PartitionAllocMemoryReclaimer::Instance()->Reclaim();
+ base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
}
};
@@ -68,7 +68,7 @@ TEST_F(PartitionsTest, Decommit) {
// Decommit is not triggered by deallocation.
EXPECT_GT(committed_after, committed_before);
// Decommit works.
- base::PartitionAllocMemoryReclaimer::Instance()->Reclaim();
+ base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
EXPECT_LT(Partitions::TotalSizeOfCommittedPages(), committed_after);
}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/assertions.h b/chromium/third_party/blink/renderer/platform/wtf/assertions.h
index 41ace57cd6c..8830e38199d 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/assertions.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/assertions.h
@@ -77,83 +77,6 @@ void vprintf_stderr_common(const char* format, va_list args);
inline bool operator!=(const Type& a, const Type* b) { return !(a == b); } \
inline bool operator!=(const Type* a, const Type& b) { return !(a == b); }
-// DEFINE_TYPE_CASTS
-//
-// ToType() functions are static_cast<> wrappers with SECURITY_DCHECK. It's
-// helpful to find bad casts.
-//
-// ToTypeOrNull() functions are similar to dynamic_cast<>. They return
-// type-casted values if the specified predicate is true, and return
-// nullptr otherwise.
-//
-// ToTypeOrDie() has a runtime type check, and it crashes if the specified
-// object is not an instance of the destination type. It is used if
-// * it's hard to prevent from passing unexpected objects,
-// * proceeding with the following code doesn't make sense, and
-// * cost of runtime type check is acceptable.
-#define DEFINE_TYPE_CASTS(Type, ArgType, argument, pointerPredicate, \
- referencePredicate) \
- inline Type* To##Type(ArgType* argument) { \
- SECURITY_DCHECK(!argument || (pointerPredicate)); \
- return static_cast<Type*>(argument); \
- } \
- inline const Type* To##Type(const ArgType* argument) { \
- SECURITY_DCHECK(!argument || (pointerPredicate)); \
- return static_cast<const Type*>(argument); \
- } \
- inline Type& To##Type(ArgType& argument) { \
- SECURITY_DCHECK(referencePredicate); \
- return static_cast<Type&>(argument); \
- } \
- inline const Type& To##Type(const ArgType& argument) { \
- SECURITY_DCHECK(referencePredicate); \
- return static_cast<const Type&>(argument); \
- } \
- void To##Type(const Type*); \
- void To##Type(const Type&); \
- \
- inline Type* To##Type##OrNull(ArgType* argument) { \
- if (!(argument) || !(pointerPredicate)) \
- return nullptr; \
- return static_cast<Type*>(argument); \
- } \
- inline const Type* To##Type##OrNull(const ArgType* argument) { \
- if (!(argument) || !(pointerPredicate)) \
- return nullptr; \
- return static_cast<const Type*>(argument); \
- } \
- inline Type* To##Type##OrNull(ArgType& argument) { \
- if (!(referencePredicate)) \
- return nullptr; \
- return static_cast<Type*>(&argument); \
- } \
- inline const Type* To##Type##OrNull(const ArgType& argument) { \
- if (!(referencePredicate)) \
- return nullptr; \
- return static_cast<const Type*>(&argument); \
- } \
- void To##Type##OrNull(const Type*); \
- void To##Type##OrNull(const Type&); \
- \
- inline Type* To##Type##OrDie(ArgType* argument) { \
- CHECK(!argument || (pointerPredicate)); \
- return static_cast<Type*>(argument); \
- } \
- inline const Type* To##Type##OrDie(const ArgType* argument) { \
- CHECK(!argument || (pointerPredicate)); \
- return static_cast<const Type*>(argument); \
- } \
- inline Type& To##Type##OrDie(ArgType& argument) { \
- CHECK(referencePredicate); \
- return static_cast<Type&>(argument); \
- } \
- inline const Type& To##Type##OrDie(const ArgType& argument) { \
- CHECK(referencePredicate); \
- return static_cast<const Type&>(argument); \
- } \
- void To##Type##OrDie(const Type*); \
- void To##Type##OrDie(const Type&)
-
// Check at compile time that related enums stay in sync.
#define STATIC_ASSERT_ENUM(a, b) \
static_assert(static_cast<int>(a) == static_cast<int>(b), \
diff --git a/chromium/third_party/blink/renderer/platform/wtf/container_annotations.h b/chromium/third_party/blink/renderer/platform/wtf/container_annotations.h
index 584b905747f..2cf3d44d984 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/container_annotations.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/container_annotations.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CONTAINER_ANNOTATIONS_H_
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
// TODO(ochang): Remove the ARCH_CPU_X86_64 condition to enable this for X86
@@ -36,13 +37,15 @@
ANNOTATE_NEW_BUFFER(buffer, newCapacity, bufferSize);
// Annotations require buffers to begin on an 8-byte boundary.
-#else // ADDRESS_SANITIZER && (OS_LINUX || OS_CHROMEOS) && ARCH_CPU_X86_64
+#else // ADDRESS_SANITIZER && (OS_LINUX || IS_CHROMEOS_ASH) &&
+ // ARCH_CPU_X86_64
#define ANNOTATE_NEW_BUFFER(buffer, capacity, newSize)
#define ANNOTATE_DELETE_BUFFER(buffer, capacity, oldSize)
#define ANNOTATE_CHANGE_SIZE(buffer, capacity, oldSize, newSize)
#define ANNOTATE_CHANGE_CAPACITY(buffer, oldCapacity, bufferSize, newCapacity)
-#endif // ADDRESS_SANITIZER && (OS_LINUX || OS_CHROMEOS) && ARCH_CPU_X86_64
+#endif // ADDRESS_SANITIZER && (OS_LINUX || IS_CHROMEOS_ASH) &&
+ // ARCH_CPU_X86_64
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CONTAINER_ANNOTATIONS_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/cross_thread_copier.h b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
index b1806482b2d..602a62538ea 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
@@ -67,6 +67,7 @@ struct SyncToken;
}
namespace media {
+class VideoFrame;
struct VideoFrameFeedback;
}
@@ -261,15 +262,6 @@ struct CrossThreadCopier<base::WeakPtr<T>>
STATIC_ONLY(CrossThreadCopier);
};
-template <typename T>
-struct CrossThreadCopier<PassedWrapper<T>> {
- STATIC_ONLY(CrossThreadCopier);
- using Type = PassedWrapper<typename CrossThreadCopier<T>::Type>;
- static Type Copy(PassedWrapper<T>&& value) {
- return WTF::Passed(CrossThreadCopier<T>::Copy(value.MoveOut()));
- }
-};
-
template <typename Signature>
struct CrossThreadCopier<CrossThreadFunction<Signature>> {
STATIC_ONLY(CrossThreadCopier);
@@ -350,6 +342,13 @@ struct CrossThreadCopier<media::VideoFrameFeedback>
STATIC_ONLY(CrossThreadCopier);
};
+template <>
+struct CrossThreadCopier<std::vector<scoped_refptr<media::VideoFrame>>>
+ : public CrossThreadCopierPassThrough<
+ std::vector<scoped_refptr<media::VideoFrame>>> {
+ STATIC_ONLY(CrossThreadCopier);
+};
+
} // namespace WTF
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CROSS_THREAD_COPIER_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/deque.h b/chromium/third_party/blink/renderer/platform/wtf/deque.h
index 4bd0d2e501a..d79fd509716 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/deque.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/deque.h
@@ -264,12 +264,23 @@ class DequeIterator : public DequeIteratorBase<T, inlineCapacity, Allocator> {
Base::Increment();
return *this;
}
- // postfix ++ intentionally omitted
+
+ Iterator operator++(int) {
+ Iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
Iterator& operator--() {
Base::Decrement();
return *this;
}
- // postfix -- intentionally omitted
+
+ Iterator operator--(int) {
+ Iterator tmp = *this;
+ --*this;
+ return tmp;
+ }
};
template <typename T,
@@ -314,12 +325,23 @@ class DequeConstIterator
Base::Increment();
return *this;
}
- // postfix ++ intentionally omitted
+
+ Iterator operator++(int) {
+ Iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
Iterator& operator--() {
Base::Decrement();
return *this;
}
- // postfix -- intentionally omitted
+
+ Iterator operator--(int) {
+ Iterator tmp = *this;
+ --*this;
+ return tmp;
+ }
};
template <typename T, wtf_size_t inlineCapacity, typename Allocator>
diff --git a/chromium/third_party/blink/renderer/platform/wtf/deque_test.cc b/chromium/third_party/blink/renderer/platform/wtf/deque_test.cc
index 6dac66778cc..bd6e0407093 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/deque_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/deque_test.cc
@@ -40,6 +40,42 @@ TEST(DequeTest, Basic) {
EXPECT_EQ(0ul, int_deque.size());
}
+TEST(DequeTest, Iterators) {
+ Deque<int, 2> deque;
+ deque.push_back(0);
+ deque.push_back(1);
+
+ {
+ auto it = deque.begin();
+ EXPECT_EQ(*it, 0);
+ EXPECT_EQ(*++it, 1);
+ EXPECT_EQ(++it, deque.end());
+ }
+
+ {
+ auto it = deque.begin();
+ EXPECT_EQ(*it++, 0);
+ EXPECT_EQ(*it++, 1);
+ EXPECT_EQ(it, deque.end());
+ }
+
+ {
+ const Deque<int, 2>& c_deque = deque;
+ auto c_it = c_deque.begin();
+ EXPECT_EQ(*c_it, 0);
+ EXPECT_EQ(*++c_it, 1);
+ EXPECT_EQ(++c_it, c_deque.end());
+ }
+
+ {
+ const Deque<int, 2>& c_deque = deque;
+ auto c_it = c_deque.begin();
+ EXPECT_EQ(*c_it++, 0);
+ EXPECT_EQ(*c_it++, 1);
+ EXPECT_EQ(c_it, c_deque.end());
+ }
+}
+
template <wtf_size_t inlineCapacity>
void CheckNumberSequence(Deque<int, inlineCapacity>& deque,
int from,
diff --git a/chromium/third_party/blink/renderer/platform/wtf/functional.h b/chromium/third_party/blink/renderer/platform/wtf/functional.h
index 1dfdf40f1a3..4c12c3f9ca9 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/functional.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/functional.h
@@ -81,53 +81,18 @@ namespace WTF {
// argument of type "Argument" (i.e. passed by value). The former case does not
// require any move constructions inbetween.
//
-// For bound parameters (arguments supplied on the creation of a functor), you
-// can move your argument into the internal storage of the functor by supplying
-// an rvalue to that argument (this is done in wrap() of ParamStorageTraits).
-// However, to make the functor be able to get called multiple times, the
-// stored object does not get moved out automatically when the underlying
-// function is actually invoked. If you want to make an argument "auto-passed",
-// you can do so by wrapping your bound argument with WTF::Passed() function, as
-// shown below:
+// Move-only types can be bound to the created callback by using `std::move()`.
+// Note that a parameter bound by `std::move()` is *always* moved-from when
+// invoking a `base::OnceCallback`, and *never* moved-from when invoking a
+// base::RepeatingCallback.
//
-// void YourFunction(Argument argument)
-// {
-// // |argument| is passed from the internal storage of functor.
-// ...
-// }
-//
-// ...
-// base::OnceClosure functor = Bind(&YourFunction, WTF::Passed(Argument()));
-// ...
-// std::move(functor).Run();
-//
-// The underlying function must receive the argument wrapped by WTF::Passed() by
-// rvalue reference or by value.
-//
-// Obviously, if you create a functor this way, you shouldn't call the functor
-// twice or more; after the second call, the passed argument may be invalid.
-
-template <typename T>
-class PassedWrapper final {
- public:
- explicit PassedWrapper(T&& scoper) : scoper_(std::move(scoper)) {}
- PassedWrapper(PassedWrapper&& other) : scoper_(std::move(other.scoper_)) {}
- T MoveOut() const { return std::move(scoper_); }
-
- private:
- mutable T scoper_;
-};
-
-template <typename T>
-PassedWrapper<T> Passed(T&& value) {
- static_assert(
- !std::is_reference<T>::value,
- "You must pass an rvalue to WTF::passed() so it can be moved. Add "
- "std::move() if necessary.");
- static_assert(!std::is_const<T>::value,
- "|value| must not be const so it can be moved.");
- return PassedWrapper<T>(std::move(value));
-}
+// Note: Legacy callback supported transferring move-only arguments to the bound
+// functor of a base::RepeatingCallback using the `Passed()` helper; however,
+// once the bound arguments are moved-from after the first invocation, the bound
+// arguments are (for most movable types) in an undefined but valid state for
+// subsequent invocations of the bound functor. This is generally undesirable
+// and thus no longer allowed. Callbacks that want to transfer move-only
+// arguments to the bound functor *must* be a base::OnceCallback.
template <typename T>
class RetainedRefWrapper final {
@@ -432,13 +397,6 @@ struct BindUnwrapTraits<WTF::RetainedRefWrapper<T>> {
};
template <typename T>
-struct BindUnwrapTraits<WTF::PassedWrapper<T>> {
- static T Unwrap(const WTF::PassedWrapper<T>& wrapped) {
- return wrapped.MoveOut();
- }
-};
-
-template <typename T>
struct BindUnwrapTraits<WTF::UnretainedWrapper<T>> {
static T* Unwrap(const WTF::UnretainedWrapper<T>& wrapped) {
return wrapped.Value();
diff --git a/chromium/third_party/blink/renderer/platform/wtf/hash_iterators.h b/chromium/third_party/blink/renderer/platform/wtf/hash_iterators.h
index 6003d02c509..b050fd9d208 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/hash_iterators.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/hash_iterators.h
@@ -54,10 +54,10 @@ struct HashTableConstIteratorAdapter<HashTableType,
ValuesIterator;
using iterator_category = std::bidirectional_iterator_tag;
- using value_type = HashTableType;
+ using value_type = ValueType;
using difference_type = ptrdiff_t;
- using pointer = value_type*;
- using reference = value_type&;
+ using pointer = const ValueType*;
+ using reference = const ValueType&;
HashTableConstIteratorAdapter() = default;
HashTableConstIteratorAdapter(
@@ -72,13 +72,21 @@ struct HashTableConstIteratorAdapter<HashTableType,
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableConstIteratorAdapter operator++(int) {
+ HashTableConstIteratorAdapter copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableConstIteratorAdapter& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableConstIteratorAdapter operator--(int) {
+ HashTableConstIteratorAdapter copy(*this);
+ --*this;
+ return copy;
+ }
KeysIterator Keys() { return KeysIterator(*this); }
ValuesIterator Values() { return ValuesIterator(*this); }
@@ -101,10 +109,10 @@ struct HashTableIteratorAdapter<HashTableType,
ValuesIterator;
using iterator_category = std::bidirectional_iterator_tag;
- using value_type = HashTableType;
+ using value_type = ValueType;
using difference_type = ptrdiff_t;
- using pointer = value_type*;
- using reference = value_type&;
+ using pointer = ValueType*;
+ using reference = ValueType&;
HashTableIteratorAdapter() = default;
HashTableIteratorAdapter(const typename HashTableType::iterator& impl)
@@ -118,13 +126,21 @@ struct HashTableIteratorAdapter<HashTableType,
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableIteratorAdapter operator++(int) {
+ HashTableIteratorAdapter copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableIteratorAdapter& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableIteratorAdapter operator--(int) {
+ HashTableIteratorAdapter copy(*this);
+ --*this;
+ return copy;
+ }
operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
typename HashTableType::const_iterator i = impl_;
@@ -147,6 +163,12 @@ struct HashTableConstKeysIterator {
ConstIterator;
public:
+ using iterator_category = typename ConstIterator::iterator_category;
+ using value_type = KeyType;
+ using difference_type = typename ConstIterator::difference_type;
+ using pointer = const KeyType*;
+ using reference = const KeyType&;
+
HashTableConstKeysIterator(const ConstIterator& impl) : impl_(impl) {}
const KeyType* Get() const { return &(impl_.Get()->key); }
@@ -157,13 +179,21 @@ struct HashTableConstKeysIterator {
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableConstKeysIterator operator++(int) {
+ HashTableConstKeysIterator copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableConstKeysIterator& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableConstKeysIterator operator--(int) {
+ HashTableConstKeysIterator copy(*this);
+ --*this;
+ return copy;
+ }
ConstIterator impl_;
};
@@ -178,6 +208,12 @@ struct HashTableConstValuesIterator {
ConstIterator;
public:
+ using iterator_category = typename ConstIterator::iterator_category;
+ using value_type = MappedType;
+ using difference_type = typename ConstIterator::difference_type;
+ using pointer = const MappedType*;
+ using reference = const MappedType&;
+
HashTableConstValuesIterator(const ConstIterator& impl) : impl_(impl) {}
const MappedType* Get() const { return &(impl_.Get()->value); }
@@ -188,13 +224,21 @@ struct HashTableConstValuesIterator {
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableConstValuesIterator operator++(int) {
+ HashTableConstValuesIterator copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableConstValuesIterator& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableConstValuesIterator operator--(int) {
+ HashTableConstValuesIterator copy(*this);
+ --*this;
+ return copy;
+ }
ConstIterator impl_;
};
@@ -212,6 +256,12 @@ struct HashTableKeysIterator {
ConstIterator;
public:
+ using iterator_category = typename Iterator::iterator_category;
+ using value_type = KeyType;
+ using difference_type = typename Iterator::difference_type;
+ using pointer = KeyType*;
+ using reference = KeyType&;
+
HashTableKeysIterator(const Iterator& impl) : impl_(impl) {}
KeyType* Get() const { return &(impl_.Get()->key); }
@@ -222,13 +272,21 @@ struct HashTableKeysIterator {
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableKeysIterator operator++(int) {
+ HashTableKeysIterator copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableKeysIterator& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableKeysIterator operator--(int) {
+ HashTableKeysIterator copy(*this);
+ --*this;
+ return copy;
+ }
operator HashTableConstKeysIterator<HashTableType, KeyType, MappedType>() {
ConstIterator i = impl_;
@@ -251,6 +309,12 @@ struct HashTableValuesIterator {
ConstIterator;
public:
+ using iterator_category = typename Iterator::iterator_category;
+ using value_type = MappedType;
+ using difference_type = typename Iterator::difference_type;
+ using pointer = MappedType*;
+ using reference = MappedType&;
+
HashTableValuesIterator(const Iterator& impl) : impl_(impl) {}
MappedType* Get() const { return &(impl_.Get()->value); }
@@ -261,13 +325,21 @@ struct HashTableValuesIterator {
++impl_;
return *this;
}
- // postfix ++ intentionally omitted
+ HashTableValuesIterator operator++(int) {
+ HashTableValuesIterator copy(*this);
+ ++*this;
+ return copy;
+ }
HashTableValuesIterator& operator--() {
--impl_;
return *this;
}
- // postfix -- intentionally omitted
+ HashTableValuesIterator operator--(int) {
+ HashTableValuesIterator copy(*this);
+ --*this;
+ return copy;
+ }
operator HashTableConstValuesIterator<HashTableType, KeyType, MappedType>() {
ConstIterator i = impl_;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc b/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
index 53fb5db27d6..737bb05a30b 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/hash_map_test.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include <iterator>
#include <memory>
#include "base/memory/ptr_util.h"
@@ -640,6 +641,77 @@ TEST(HashMapTest, IsValidKey) {
static_assert(!IsTraceable<HashMap<int, int>>::value,
"HashMap<int, int> must not be traceable.");
+static_assert(
+ std::is_convertible<
+ std::iterator_traits<HashMap<int, int>::iterator>::iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map iterators should be bidirectional");
+static_assert(
+ std::is_same<std::iterator_traits<HashMap<int, int>::iterator>::value_type,
+ KeyValuePair<int, int>>(),
+ "hash map iterators should be over key-value pairs");
+
+static_assert(std::is_convertible<
+ std::iterator_traits<
+ HashMap<int, int>::const_iterator>::iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map const iterators should be bidirectional");
+static_assert(
+ std::is_same<
+ std::iterator_traits<HashMap<int, int>::const_iterator>::value_type,
+ KeyValuePair<int, int>>(),
+ "hash map const iterators should be over key-value pairs");
+
+static_assert(
+ std::is_convertible<
+ std::iterator_traits<
+ HashMap<int, unsigned>::iterator::KeysIterator>::iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map key iterators should be bidirectional");
+static_assert(
+ std::is_same<
+ std::iterator_traits<
+ HashMap<int, unsigned>::iterator::KeysIterator>::value_type,
+ int>(),
+ "hash map key iterators should be over keys");
+
+static_assert(std::is_convertible<
+ std::iterator_traits<HashMap<int, unsigned>::const_iterator::
+ KeysIterator>::iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map const key iterators should be bidirectional");
+static_assert(
+ std::is_same<
+ std::iterator_traits<
+ HashMap<int, unsigned>::const_iterator::KeysIterator>::value_type,
+ int>(),
+ "hash map const key iterators should be over keys");
+
+static_assert(
+ std::is_convertible<
+ std::iterator_traits<HashMap<int, unsigned>::iterator::ValuesIterator>::
+ iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map value iterators should be bidirectional");
+static_assert(
+ std::is_same<
+ std::iterator_traits<
+ HashMap<int, unsigned>::iterator::ValuesIterator>::value_type,
+ unsigned>(),
+ "hash map value iterators should be over values");
+
+static_assert(std::is_convertible<
+ std::iterator_traits<HashMap<int, unsigned>::const_iterator::
+ ValuesIterator>::iterator_category,
+ std::bidirectional_iterator_tag>(),
+ "hash map const value iterators should be bidirectional");
+static_assert(
+ std::is_same<
+ std::iterator_traits<
+ HashMap<int, unsigned>::const_iterator::ValuesIterator>::value_type,
+ unsigned>(),
+ "hash map const value iterators should be over values");
+
} // anonymous namespace
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/hash_table.h b/chromium/third_party/blink/renderer/platform/wtf/hash_table.h
index 9289763b271..46568c25b84 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/hash_table.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -922,6 +922,7 @@ class HashTable final
ValueType* Reinsert(ValueType&&);
static void InitializeBucket(ValueType& bucket);
+ static void ReinitializeBucket(ValueType& bucket);
static void DeleteBucket(const ValueType& bucket) {
bucket.~ValueType();
Traits::ConstructDeletedValue(const_cast<ValueType&>(bucket),
@@ -1283,6 +1284,15 @@ struct HashTableBucketInitializer<false> {
ConstructTraits<Value, Traits, Allocator>::ConstructAndNotifyElement(
&bucket, Traits::EmptyValue());
}
+
+ template <typename Traits, typename Allocator, typename Value>
+ static void Reinitialize(Value& bucket) {
+ // Reinitialize is used when recycling a deleted bucket. For buckets for
+ // which empty value is non-zero, this is forbidden during marking. Thus if
+ // we get here, marking is not active and we can reuse Initialize.
+ DCHECK(Allocator::template CanReuseHashTableDeletedBucket<Traits>());
+ Initialize<Traits, Allocator, Value>(bucket);
+ }
};
template <>
@@ -1296,6 +1306,19 @@ struct HashTableBucketInitializer<true> {
// compilers.
memset(&bucket, 0, sizeof(bucket));
}
+
+ template <typename Traits, typename Allocator, typename Value>
+ static void Reinitialize(Value& bucket) {
+ // This initializes the bucket without copying the empty value. That
+ // makes it possible to use this with types that don't support copying.
+ // The memset to 0 looks like a slow operation but is optimized by the
+ // compilers.
+ if (!Allocator::kIsGarbageCollected) {
+ memset(&bucket, 0, sizeof(bucket));
+ return;
+ }
+ AtomicMemzero(&bucket, sizeof(bucket));
+ }
};
template <typename Key,
@@ -1319,6 +1342,20 @@ template <typename Key,
typename Traits,
typename KeyTraits,
typename Allocator>
+inline void
+HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
+ ReinitializeBucket(ValueType& bucket) {
+ HashTableBucketInitializer<Traits::kEmptyValueIsZero>::template Reinitialize<
+ Traits, Allocator>(bucket);
+}
+
+template <typename Key,
+ typename Value,
+ typename Extractor,
+ typename HashFunctions,
+ typename Traits,
+ typename KeyTraits,
+ typename Allocator>
template <typename HashTranslator, typename T, typename Extra>
typename HashTable<Key,
Value,
@@ -1344,6 +1381,9 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
UPDATE_ACCESS_COUNTS();
+ bool can_reuse_deleted_entry =
+ Allocator::template CanReuseHashTableDeletedBucket<Traits>();
+
ValueType* deleted_entry = nullptr;
ValueType* entry;
while (1) {
@@ -1356,10 +1396,10 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
if (HashTranslator::Equal(Extractor::Extract(*entry), key))
return AddResult(this, entry, false);
- if (IsDeletedBucket(*entry))
+ if (IsDeletedBucket(*entry) && can_reuse_deleted_entry)
deleted_entry = entry;
} else {
- if (IsDeletedBucket(*entry))
+ if (IsDeletedBucket(*entry) && can_reuse_deleted_entry)
deleted_entry = entry;
else if (HashTranslator::Equal(Extractor::Extract(*entry), key))
return AddResult(this, entry, false);
@@ -1373,9 +1413,10 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
RegisterModification();
if (deleted_entry) {
+ DCHECK(can_reuse_deleted_entry);
// Overwrite any data left over from last use, using placement new or
// memset.
- InitializeBucket(*deleted_entry);
+ ReinitializeBucket(*deleted_entry);
entry = deleted_entry;
--deleted_count_;
}
@@ -1444,7 +1485,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
RegisterModification();
if (IsDeletedBucket(*entry)) {
- InitializeBucket(*entry);
+ ReinitializeBucket(*entry);
--deleted_count_;
}
@@ -1836,7 +1877,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
}
}
- Allocator::TraceBackingStoreIfMarked(new_hash_table.table_);
+ Allocator::TraceBackingStoreIfMarked(&new_hash_table.table_);
ValueType* old_table = table_;
unsigned old_table_size = table_size_;
@@ -2018,9 +2059,9 @@ void HashTable<Key,
// Weak processing is omitted when no backing store is present. In case such
// an empty table is later on used it needs to be strongified.
if (table_)
- Allocator::TraceBackingStoreIfMarked(table_);
+ Allocator::TraceBackingStoreIfMarked(&table_);
if (other.table_)
- Allocator::TraceBackingStoreIfMarked(other.table_);
+ Allocator::TraceBackingStoreIfMarked(&other.table_);
}
std::swap(table_size_, other.table_size_);
std::swap(key_count_, other.key_count_);
diff --git a/chromium/third_party/blink/renderer/platform/wtf/leak_annotations.h b/chromium/third_party/blink/renderer/platform/wtf/leak_annotations.h
index 4a9cabc33a1..79f132cc869 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/leak_annotations.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/leak_annotations.h
@@ -73,68 +73,9 @@ class LeakSanitizerDisabler {
// those embedded pointers be reachable by some other path, they will be
// reported as leaking.
#define LEAK_SANITIZER_IGNORE_OBJECT(X) __lsan_ignore_object(X)
-
-// If the object pointed to by the static local is on the Oilpan heap, a strong
-// Persistent<> is created to keep the pointed-to heap object alive. This makes
-// both the Persistent<> and the heap object _reachable_ by LeakSanitizer's leak
-// detection pass. We do not want these intentional leaks to be reported by
-// LSan, hence the static local is registered with Oilpan
-// (see RegisterStaticLocalReference<> below.)
-//
-// Upon Blink shutdown, all the registered statics are released and a final
-// round of GCs are performed to sweep out their now-unreachable object graphs.
-// The end result being a tidied heap that the LeakSanitizer can then scan to
-// report real leaks.
-//
-// The CanRegisterStaticLocalReference<> and RegisterStaticLocalReference<>
-// templates arrange for this -- for a class type T, a registerStatic()
-// implementation is provided if "T* T::registerAsStaticReference(T*)" is a
-// method on T (inherited or otherwise.)
-//
-// An empty, trivial registerStatic() method is provided for all other class
-// types T.
-template <typename T>
-class CanRegisterStaticLocalReference {
- typedef char YesType;
- typedef struct NoType { char padding[8]; } NoType;
-
- // Check if class T has public method "T* registerAsStaticReference()".
- template <typename V>
- static YesType checkHasRegisterAsStaticReferenceMethod(
- V* p,
- typename std::enable_if<IsSubclass<
- V,
- typename std::remove_pointer<decltype(
- p->registerAsStaticReference())>::type>::value>::type* = 0);
- template <typename V>
- static NoType checkHasRegisterAsStaticReferenceMethod(...);
-
- public:
- static const bool value =
- sizeof(YesType) + sizeof(T) ==
- sizeof(checkHasRegisterAsStaticReferenceMethod<T>(nullptr)) + sizeof(T);
-};
-
-template <typename T, bool = CanRegisterStaticLocalReference<T>::value>
-class RegisterStaticLocalReference {
- public:
- static T* registerStatic(T* ptr) { return ptr; }
-};
-
-template <typename T>
-class RegisterStaticLocalReference<T, true> {
- public:
- static T* registerStatic(T* ptr) {
- return static_cast<T*>(ptr->registerAsStaticReference());
- }
-};
-
-#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) \
- WTF::RegisterStaticLocalReference<Type>::registerStatic(Object)
#else
#define WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE
#define LEAK_SANITIZER_IGNORE_OBJECT(X) ((void)0)
-#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) Object
#endif // defined(LEAK_SANITIZER)
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/list_hash_set.h b/chromium/third_party/blink/renderer/platform/wtf/list_hash_set.h
index bfa0975dab0..42d62de5354 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/list_hash_set.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/list_hash_set.h
@@ -59,30 +59,171 @@ class ListHashSetReverseIterator;
template <typename Set>
class ListHashSetConstReverseIterator;
-template <typename ValueArg>
-class ListHashSetNodeBase;
template <typename ValueArg, typename Allocator>
-class ListHashSetNode;
-template <typename ValueArg, size_t inlineCapacity>
-struct ListHashSetAllocator;
+class MallocedListHashSetNode;
+template <typename ValueArg, wtf_size_t inlineCapacity>
+struct MallocedListHashSetAllocator;
template <typename HashArg>
struct ListHashSetNodeHashFunctions;
-template <typename HashArg>
+template <typename HashArg, typename NodeArg>
struct ListHashSetTranslator;
+template <typename Value, wtf_size_t inlineCapacity, typename Allocator>
+struct ListHashSetTraits;
+
+template <typename Value, wtf_size_t inlineCapacity>
+struct ListHashSetTraits<Value,
+ inlineCapacity,
+ MallocedListHashSetAllocator<Value, inlineCapacity>>
+ : public HashTraits<MallocedListHashSetNode<
+ Value,
+ MallocedListHashSetAllocator<Value, inlineCapacity>>*> {
+ using Allocator = MallocedListHashSetAllocator<Value, inlineCapacity>;
+ using Node = MallocedListHashSetNode<Value, Allocator>;
+};
+
+template <typename ValueArg, typename AllocatorArg>
+class MallocedListHashSetNode {
+ DISALLOW_NEW();
+
+ public:
+ using NodeAllocator = AllocatorArg;
+ using PointerType = MallocedListHashSetNode*;
+ using Value = ValueArg;
+
+ template <typename U>
+ static MallocedListHashSetNode* Create(NodeAllocator* allocator, U&& value) {
+ return new (allocator->AllocateNode())
+ MallocedListHashSetNode(std::forward<U>(value));
+ }
+
+ template <typename U>
+ explicit MallocedListHashSetNode(U&& value)
+ : value_(std::forward<U>(value)) {}
+
+ MallocedListHashSetNode() = delete;
+ MallocedListHashSetNode(const MallocedListHashSetNode&) = delete;
+ MallocedListHashSetNode& operator=(const MallocedListHashSetNode&) = delete;
+
+ void Destroy(NodeAllocator* allocator) {
+ this->~MallocedListHashSetNode();
+ allocator->Deallocate(this);
+ }
+
+ MallocedListHashSetNode* Next() const { return next_; }
+ MallocedListHashSetNode* Prev() const { return prev_; }
+
+ ValueArg value_;
+ PointerType prev_ = nullptr;
+ PointerType next_ = nullptr;
+#if DCHECK_IS_ON()
+ bool is_allocated_ = true;
+#endif
+};
+
+// This allocator is only used for non-Heap ListHashSets.
+template <typename ValueArg, wtf_size_t inlineCapacity>
+struct MallocedListHashSetAllocator : public PartitionAllocator {
+ using TableAllocator = PartitionAllocator;
+ using Node = MallocedListHashSetNode<ValueArg, MallocedListHashSetAllocator>;
+
+ class AllocatorProvider {
+ DISALLOW_NEW();
+
+ public:
+ AllocatorProvider() = default;
+ void CreateAllocatorIfNeeded() {
+ if (!allocator_)
+ allocator_ = new MallocedListHashSetAllocator;
+ }
+
+ void ReleaseAllocator() {
+ delete allocator_;
+ allocator_ = nullptr;
+ }
+
+ void Swap(AllocatorProvider& other) {
+ std::swap(allocator_, other.allocator_);
+ }
+
+ MallocedListHashSetAllocator* Get() const {
+ DCHECK(allocator_);
+ return allocator_;
+ }
+
+ private:
+ // Not using std::unique_ptr as this pointer should be deleted at
+ // releaseAllocator() method rather than at destructor.
+ MallocedListHashSetAllocator* allocator_ = nullptr;
+ };
+
+ MallocedListHashSetAllocator() : free_list_(Pool()) {
+ memset(pool_, 0, sizeof(pool_));
+ }
+
+ Node* AllocateNode() {
+ Node* result = free_list_;
+
+ if (!result) {
+ return static_cast<Node*>(WTF::Partitions::FastMalloc(
+ sizeof(Node), WTF_HEAP_PROFILER_TYPE_NAME(Node)));
+ }
+
+#if DCHECK_IS_ON()
+ DCHECK(!result->is_allocated_);
+#endif
-template <typename Value, typename Allocator>
-struct ListHashSetTraits
- : public HashTraits<ListHashSetNode<Value, Allocator>*> {
- using Node = ListHashSetNode<Value, Allocator>;
+ Node* next = result->Next();
+#if DCHECK_IS_ON()
+ DCHECK(!next || !next->is_allocated_);
+#endif
+ if (!next && !is_done_with_initial_free_list_) {
+ next = result + 1;
+ if (next == PastPool()) {
+ is_done_with_initial_free_list_ = true;
+ next = nullptr;
+ } else {
+ DCHECK(InPool(next));
+#if DCHECK_IS_ON()
+ DCHECK(!next->is_allocated_);
+#endif
+ }
+ }
+ free_list_ = next;
+
+ return result;
+ }
+
+ void Deallocate(Node* node) {
+ if (InPool(node)) {
+#if DCHECK_IS_ON()
+ node->is_allocated_ = false;
+#endif
+ node->next_ = free_list_;
+ free_list_ = node;
+ return;
+ }
- static void ConstructDeletedValue(Node*& slot, bool) {
- AsAtomicPtr(&slot)->store(reinterpret_cast<Node*>(-1),
- std::memory_order_relaxed);
+ WTF::Partitions::FastFree(node);
}
- static constexpr bool kCanTraceConcurrently =
- HashTraits<Value>::kCanTraceConcurrently;
+ bool InPool(Node* node) { return node >= Pool() && node < PastPool(); }
+
+ private:
+ Node* Pool() { return reinterpret_cast_ptr<Node*>(pool_); }
+ Node* PastPool() { return Pool() + kPoolSize; }
+
+ Node* free_list_;
+ bool is_done_with_initial_free_list_ = false;
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+ // The allocation pool for nodes is one big chunk that ASAN has no insight
+ // into, so it can cloak errors. Make it as small as possible to force nodes
+ // to be allocated individually where ASAN can see them.
+ static const size_t kPoolSize = 1;
+#else
+ static const size_t kPoolSize = inlineCapacity;
+#endif
+ alignas(Node) char pool_[sizeof(Node) * kPoolSize];
};
// Note that for a ListHashSet you cannot specify the HashTraits as a template
@@ -91,37 +232,37 @@ template <typename ValueArg,
size_t inlineCapacity = 256,
typename HashArg = typename DefaultHash<ValueArg>::Hash,
typename AllocatorArg =
- ListHashSetAllocator<ValueArg, inlineCapacity>>
+ MallocedListHashSetAllocator<ValueArg, inlineCapacity>>
class ListHashSet
: public ConditionalDestructor<
ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>,
AllocatorArg::kIsGarbageCollected> {
- typedef AllocatorArg Allocator;
+ using Allocator = AllocatorArg;
USE_ALLOCATOR(ListHashSet, Allocator);
- typedef ListHashSetNode<ValueArg, Allocator> Node;
- typedef ListHashSetTraits<ValueArg, Allocator> NodeTraits;
- typedef ListHashSetNodeHashFunctions<HashArg> NodeHash;
- typedef ListHashSetTranslator<HashArg> BaseTranslator;
+ using NodeTraits = ListHashSetTraits<ValueArg, inlineCapacity, Allocator>;
+ using Node = typename NodeTraits::Node;
+ using NodeHash = ListHashSetNodeHashFunctions<HashArg>;
+ using BaseTranslator = ListHashSetTranslator<HashArg, Node>;
- typedef HashTable<Node*,
- Node*,
+ typedef HashTable<typename Node::PointerType,
+ typename Node::PointerType,
IdentityExtractor,
NodeHash,
NodeTraits,
NodeTraits,
typename Allocator::TableAllocator>
ImplType;
- typedef HashTableIterator<Node*,
- Node*,
+ typedef HashTableIterator<typename Node::PointerType,
+ typename Node::PointerType,
IdentityExtractor,
NodeHash,
NodeTraits,
NodeTraits,
typename Allocator::TableAllocator>
ImplTypeIterator;
- typedef HashTableConstIterator<Node*,
- Node*,
+ typedef HashTableConstIterator<typename Node::PointerType,
+ typename Node::PointerType,
IdentityExtractor,
NodeHash,
NodeTraits,
@@ -254,7 +395,7 @@ class ListHashSet
void PrependNode(Node*);
void InsertNodeBefore(Node* before_node, Node* new_node);
void DeleteAllNodes();
- Allocator* GetAllocator() const { return allocator_provider_.Get(); }
+ Allocator* GetAllocator() { return allocator_provider_.Get(); }
void CreateAllocatorIfNeeded() {
allocator_provider_.CreateAllocatorIfNeeded();
}
@@ -271,190 +412,11 @@ class ListHashSet
}
ImplType impl_;
- Node* head_;
- Node* tail_;
+ typename Node::PointerType head_;
+ typename Node::PointerType tail_;
typename Allocator::AllocatorProvider allocator_provider_;
};
-// ListHashSetNode has this base class to hold the members because the MSVC
-// compiler otherwise gets into circular template dependencies when trying to do
-// sizeof on a node.
-template <typename ValueArg>
-class ListHashSetNodeBase {
- DISALLOW_NEW();
-
- protected:
- template <typename U>
- explicit ListHashSetNodeBase(U&& value) : value_(std::forward<U>(value)) {}
-
- public:
- ValueArg value_;
- ListHashSetNodeBase* prev_ = nullptr;
- ListHashSetNodeBase* next_ = nullptr;
-#if DCHECK_IS_ON()
- bool is_allocated_ = true;
-#endif
-};
-
-// This allocator is only used for non-Heap ListHashSets.
-template <typename ValueArg, size_t inlineCapacity>
-struct ListHashSetAllocator : public PartitionAllocator {
- typedef PartitionAllocator TableAllocator;
- typedef ListHashSetNode<ValueArg, ListHashSetAllocator> Node;
- typedef ListHashSetNodeBase<ValueArg> NodeBase;
-
- class AllocatorProvider {
- DISALLOW_NEW();
-
- public:
- AllocatorProvider() : allocator_(nullptr) {}
- void CreateAllocatorIfNeeded() {
- if (!allocator_)
- allocator_ = new ListHashSetAllocator;
- }
-
- void ReleaseAllocator() {
- delete allocator_;
- allocator_ = nullptr;
- }
-
- void Swap(AllocatorProvider& other) {
- std::swap(allocator_, other.allocator_);
- }
-
- ListHashSetAllocator* Get() const {
- DCHECK(allocator_);
- return allocator_;
- }
-
- private:
- // Not using std::unique_ptr as this pointer should be deleted at
- // releaseAllocator() method rather than at destructor.
- ListHashSetAllocator* allocator_;
- };
-
- ListHashSetAllocator()
- : free_list_(Pool()), is_done_with_initial_free_list_(false) {
- memset(pool_, 0, sizeof(pool_));
- }
-
- Node* AllocateNode() {
- Node* result = free_list_;
-
- if (!result)
- return static_cast<Node*>(WTF::Partitions::FastMalloc(
- sizeof(NodeBase), WTF_HEAP_PROFILER_TYPE_NAME(Node)));
-
-#if DCHECK_IS_ON()
- DCHECK(!result->is_allocated_);
-#endif
-
- Node* next = result->Next();
-#if DCHECK_IS_ON()
- DCHECK(!next || !next->is_allocated_);
-#endif
- if (!next && !is_done_with_initial_free_list_) {
- next = result + 1;
- if (next == PastPool()) {
- is_done_with_initial_free_list_ = true;
- next = nullptr;
- } else {
- DCHECK(InPool(next));
-#if DCHECK_IS_ON()
- DCHECK(!next->is_allocated_);
-#endif
- }
- }
- free_list_ = next;
-
- return result;
- }
-
- void Deallocate(Node* node) {
- if (InPool(node)) {
-#if DCHECK_IS_ON()
- node->is_allocated_ = false;
-#endif
- node->next_ = free_list_;
- free_list_ = node;
- return;
- }
-
- WTF::Partitions::FastFree(node);
- }
-
- bool InPool(Node* node) { return node >= Pool() && node < PastPool(); }
-
- template <typename VisitorDispatcher>
- static void TraceValue(VisitorDispatcher, const Node*) {}
-
- private:
- Node* Pool() { return reinterpret_cast_ptr<Node*>(pool_); }
- Node* PastPool() { return Pool() + kPoolSize; }
-
- Node* free_list_;
- bool is_done_with_initial_free_list_;
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- // The allocation pool for nodes is one big chunk that ASAN has no insight
- // into, so it can cloak errors. Make it as small as possible to force nodes
- // to be allocated individually where ASAN can see them.
- static const size_t kPoolSize = 1;
-#else
- static const size_t kPoolSize = inlineCapacity;
-#endif
- alignas(NodeBase) char pool_[sizeof(NodeBase) * kPoolSize];
-};
-
-template <typename ValueArg, typename AllocatorArg>
-class ListHashSetNode : public ListHashSetNodeBase<ValueArg> {
- public:
- typedef AllocatorArg NodeAllocator;
- typedef ValueArg Value;
-
- template <typename U>
- explicit ListHashSetNode(U&& value)
- : ListHashSetNodeBase<ValueArg>(std::forward<U>(value)) {
- static_assert(!NodeAllocator::kIsGarbageCollected ||
- std::is_trivially_destructible<Value>::value,
- "Garbage collected types used in ListHashSet should be "
- "trivially destructible");
- }
-
- void* operator new(size_t, NodeAllocator* allocator) {
- static_assert(
- sizeof(ListHashSetNode) == sizeof(ListHashSetNodeBase<ValueArg>),
- "please add any fields to the base");
- return allocator->AllocateNode();
- }
-
- void Destroy(NodeAllocator* allocator) {
- if (NodeAllocator::kIsGarbageCollected)
- return;
- this->~ListHashSetNode();
- allocator->Deallocate(this);
- }
-
- template <typename VisitorDispatcher, typename A = NodeAllocator>
- std::enable_if_t<A::kIsGarbageCollected> Trace(
- VisitorDispatcher visitor) const {
- NodeAllocator::TraceValue(visitor, this);
- }
-
- ListHashSetNode* Next() const {
- return reinterpret_cast<ListHashSetNode*>(this->next_);
- }
- ListHashSetNode* Prev() const {
- return reinterpret_cast<ListHashSetNode*>(this->prev_);
- }
-
- // Don't add fields here, the ListHashSetNodeBase and this should have the
- // same size.
-
- static constexpr ListHashSetNode* UnlinkedNodePointer() {
- return reinterpret_cast<ListHashSetNode*>(-1);
- }
-};
-
template <typename HashArg>
struct ListHashSetNodeHashFunctions {
STATIC_ONLY(ListHashSetNodeHashFunctions);
@@ -462,8 +424,8 @@ struct ListHashSetNodeHashFunctions {
static unsigned GetHash(const T& key) {
return HashArg::GetHash(key->value_);
}
- template <typename T>
- static bool Equal(const T& a, const T& b) {
+ template <typename U, typename V>
+ static bool Equal(const U& a, const V& b) {
return HashArg::Equal(a->value_, b->value_);
}
static const bool safe_to_compare_to_empty_or_deleted = false;
@@ -513,11 +475,6 @@ class ListHashSetIterator {
operator const_iterator() const { return iterator_; }
- template <typename VisitorDispatcher>
- void Trace(VisitorDispatcher visitor) const {
- iterator_.Trace(visitor);
- }
-
private:
Node* GetNode() { return iterator_.GetNode(); }
@@ -575,12 +532,6 @@ class ListHashSetConstIterator {
return position_ != other.position_;
}
- template <typename VisitorDispatcher>
- void Trace(VisitorDispatcher visitor) const {
- visitor->Trace(*set_);
- visitor->Trace(position_);
- }
-
private:
Node* GetNode() { return position_; }
@@ -635,11 +586,6 @@ class ListHashSetReverseIterator {
operator const_reverse_iterator() const { return iterator_; }
- template <typename VisitorDispatcher>
- void Trace(VisitorDispatcher visitor) const {
- iterator_.trace(visitor);
- }
-
private:
Node* GetNode() { return iterator_.node(); }
@@ -697,12 +643,6 @@ class ListHashSetConstReverseIterator {
return position_ != other.position_;
}
- template <typename VisitorDispatcher>
- void Trace(VisitorDispatcher visitor) const {
- visitor->Trace(*set_);
- visitor->Trace(position_);
- }
-
private:
Node* GetNode() { return position_; }
@@ -713,9 +653,12 @@ class ListHashSetConstReverseIterator {
friend class ListHashSet;
};
-template <typename HashFunctions>
+template <typename HashFunctions, typename NodeArg>
struct ListHashSetTranslator {
STATIC_ONLY(ListHashSetTranslator);
+
+ using Node = NodeArg;
+
template <typename T>
static unsigned GetHash(const T& key) {
return HashFunctions::GetHash(key);
@@ -724,11 +667,15 @@ struct ListHashSetTranslator {
static bool Equal(const T& a, const U& b) {
return HashFunctions::Equal(a->value_, b);
}
- template <typename T, typename U, typename V>
- static void Translate(T*& location, U&& key, const V& allocator) {
- AsAtomicPtr(&location)->store(new (const_cast<V*>(&allocator))
- T(std::forward<U>(key)),
- std::memory_order_relaxed);
+ template <typename Key, typename Allocator>
+ static void Translate(typename Node::PointerType& location,
+ Key&& key,
+ Allocator& allocator) {
+ // PointerType is
+ // - Member<Node> for the Heap version, supporting concurrency using
+ // atomics;
+ // - Node* for the PA version;
+ location = Node::Create(&allocator, std::forward<Key>(key));
}
};
@@ -1095,10 +1042,9 @@ ListHashSet<T, inlineCapacity, U, V>::Trace(VisitorDispatcher visitor) const {
static_assert(!IsWeak<T>::value,
"HeapListHashSet does not support weakness, consider using "
"HeapLinkedHashSet instead.");
- // This marks all the nodes and their contents live that can be accessed
- // through the HashTable. That includes m_head and m_tail so we do not have
- // to explicitly trace them here.
impl_.Trace(visitor);
+ visitor->Trace(head_);
+ visitor->Trace(tail_);
}
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/std_lib_extras.h b/chromium/third_party/blink/renderer/platform/wtf/std_lib_extras.h
index b931442417c..1ae8ac111b7 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/std_lib_extras.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/std_lib_extras.h
@@ -80,13 +80,6 @@ class StaticSingleton final {
using WrapperType = typename Wrapper<Type>::type;
- // To cooperate with leak detection(LSan) for Blink garbage collected objects,
- // the objects owned by persistent local statics will in some cases have to be
- // finalized prior to leak checking. This only applies to static references to
- // Blink heap objects and what they transitively hold on to. Hence the
- // LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy
- // details.
-
template <typename HeapNew, typename PlacementNew>
StaticSingleton(const HeapNew& heap_new, const PlacementNew& placement_new)
: instance_(heap_new, placement_new)
@@ -98,7 +91,7 @@ class StaticSingleton final {
{
static_assert(!WTF::IsGarbageCollectedType<Type>::value,
"Garbage collected objects must be wrapped in a Persistent");
- LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance_.Get());
+ LEAK_SANITIZER_IGNORE_OBJECT(instance_.Get());
}
Type& Get(bool allow_cross_thread_use) {
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/DIR_METADATA b/chromium/third_party/blink/renderer/platform/wtf/text/DIR_METADATA
new file mode 100644
index 00000000000..23763da8568
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+ component: "Blink>Internals>WTF"
+}
+team_email: "platform-architecture-dev@chromium.org" \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/OWNERS b/chromium/third_party/blink/renderer/platform/wtf/text/OWNERS
index fbe28ba841c..b33128712b0 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/OWNERS
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/OWNERS
@@ -3,6 +3,3 @@ per-file text_codec*.*=jsbell@chromium.org
per-file text_codec*.*=jshin@chromium.org
per-file text_encoding*.*=jshin@chromium.org
per-file text_encoding*.*=jshin@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h b/chromium/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
index 24a6bee6107..ae9c7809b05 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
@@ -75,38 +75,31 @@ inline bool IsAllASCII(MachineWord word) {
return !(word & NonASCIIMask<sizeof(MachineWord), CharacterType>::Value());
}
-// Note: This function assume the input is likely all ASCII, and
+struct ASCIIStringAttributes {
+ ASCIIStringAttributes(bool contains_only_ascii, bool is_lower_ascii)
+ : contains_only_ascii(contains_only_ascii),
+ is_lower_ascii(is_lower_ascii) {}
+ unsigned contains_only_ascii : 1;
+ unsigned is_lower_ascii : 1;
+};
+
+// Note: This function assumes the input is likely all ASCII, and
// does not leave early if it is not the case.
template <typename CharacterType>
-ALWAYS_INLINE bool CharactersAreAllASCII(const CharacterType* characters,
- size_t length) {
+ALWAYS_INLINE ASCIIStringAttributes
+CharacterAttributes(const CharacterType* characters, size_t length) {
DCHECK_GT(length, 0u);
- MachineWord all_char_bits = 0;
- const CharacterType* end = characters + length;
-
- // Prologue: align the input.
- while (!IsAlignedToMachineWord(characters) && characters != end) {
- all_char_bits |= *characters;
- ++characters;
- }
- // Compare the values of CPU word size.
- const CharacterType* word_end = AlignToMachineWord(end);
- const size_t kLoopIncrement = sizeof(MachineWord) / sizeof(CharacterType);
- while (characters < word_end) {
- all_char_bits |= *(reinterpret_cast_ptr<const MachineWord*>(characters));
- characters += kLoopIncrement;
- }
-
- // Process the remaining bytes.
- while (characters != end) {
- all_char_bits |= *characters;
- ++characters;
+ // Performance note: This loop will not vectorize properly in -Oz. Ensure
+ // the calling code is built with -O2.
+ CharacterType all_char_bits = 0;
+ bool contains_upper_case = false;
+ for (size_t i = 0; i < length; i++) {
+ all_char_bits |= characters[i];
+ contains_upper_case |= IsASCIIUpper(characters[i]);
}
- MachineWord non_ascii_bit_mask =
- NonASCIIMask<sizeof(MachineWord), CharacterType>::Value();
- return !(all_char_bits & non_ascii_bit_mask);
+ return ASCIIStringAttributes(IsASCII(all_char_bits), !contains_upper_case);
}
template <typename CharacterType>
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.cc b/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
index 9f8d7cb4c09..00ef11200a6 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
#include "third_party/blink/renderer/platform/wtf/text/case_map.h"
#include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace WTF {
@@ -97,6 +98,10 @@ std::ostream& operator<<(std::ostream& out, const AtomicString& s) {
return out << s.GetString();
}
+void AtomicString::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ perfetto::WriteIntoTracedValue(std::move(context), GetString());
+}
+
#ifndef NDEBUG
void AtomicString::Show() const {
string_.Show();
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.h b/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.h
index 3dec4f739e5..ab3c0456e98 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/atomic_string.h
@@ -23,6 +23,7 @@
#include <cstring>
#include <iosfwd>
+#include <type_traits>
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -32,6 +33,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/wtf_export.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
namespace WTF {
@@ -74,6 +76,10 @@ class WTF_EXPORT AtomicString {
AtomicString(const LChar* chars, unsigned length);
AtomicString(const UChar* chars, unsigned length);
AtomicString(const UChar* chars);
+ // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t`
+ // on all platforms.
+ template <typename UCharT = UChar,
+ typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>>
AtomicString(const char16_t* chars)
: AtomicString(reinterpret_cast<const UChar*>(chars)) {}
@@ -179,6 +185,8 @@ class WTF_EXPORT AtomicString {
AtomicString LowerASCII() const;
AtomicString UpperASCII() const;
+ bool IsLowerASCII() const { return string_.IsLowerASCII(); }
+
// See comments in WTFString.h.
int ToInt(bool* ok = nullptr) const { return string_.ToInt(ok); }
double ToDouble(bool* ok = nullptr) const { return string_.ToDouble(ok); }
@@ -219,6 +227,8 @@ class WTF_EXPORT AtomicString {
return string_.IsSafeToSendToAnotherThread();
}
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
#ifndef NDEBUG
void Show() const;
#endif
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/character_names.h b/chromium/third_party/blink/renderer/platform/wtf/text/character_names.h
index 8868cd56c34..2e5df9172b4 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/character_names.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/character_names.h
@@ -44,6 +44,8 @@ const UChar kArabicLetterMarkCharacter = 0x061C;
const UChar32 kArabicMathematicalOperatorMeemWithHahWithTatweel = 0x1EEF0;
const UChar32 kArabicMathematicalOperatorHahWithDal = 0x1EEF1;
const UChar kBlackCircleCharacter = 0x25CF;
+const UChar kBlackDownPointingSmallTriangle = 0x25BE;
+const UChar kBlackRightPointingSmallTriangle = 0x25B8;
const UChar kBlackSquareCharacter = 0x25A0;
const UChar kBlackUpPointingTriangleCharacter = 0x25B2;
const UChar kBulletCharacter = 0x2022;
@@ -61,6 +63,8 @@ const UChar kDeleteCharacter = 0x007F;
const UChar kDoubleStruckItalicCapitalDCharacter = 0x2145;
const UChar kDoubleStruckItalicSmallDCharacter = 0x2146;
const UChar kEnQuadCharacter = 0x2000;
+const UChar kEthiopicNumberHundredCharacter = 0x137B;
+const UChar kEthiopicNumberTenThousandCharacter = 0x137C;
const UChar kEthiopicPrefaceColonCharacter = 0x1366;
const UChar kEthiopicWordspaceCharacter = 0x1361;
const UChar kHeavyBlackHeartCharacter = 0x2764;
@@ -200,6 +204,8 @@ using WTF::unicode::kArabicLetterMarkCharacter;
using WTF::unicode::kArabicMathematicalOperatorHahWithDal;
using WTF::unicode::kArabicMathematicalOperatorMeemWithHahWithTatweel;
using WTF::unicode::kBlackCircleCharacter;
+using WTF::unicode::kBlackDownPointingSmallTriangle;
+using WTF::unicode::kBlackRightPointingSmallTriangle;
using WTF::unicode::kBlackSquareCharacter;
using WTF::unicode::kBlackUpPointingTriangleCharacter;
using WTF::unicode::kBulletCharacter;
@@ -216,6 +222,8 @@ using WTF::unicode::kComma;
using WTF::unicode::kDoubleStruckItalicCapitalDCharacter;
using WTF::unicode::kDoubleStruckItalicSmallDCharacter;
using WTF::unicode::kEnQuadCharacter;
+using WTF::unicode::kEthiopicNumberHundredCharacter;
+using WTF::unicode::kEthiopicNumberTenThousandCharacter;
using WTF::unicode::kEthiopicPrefaceColonCharacter;
using WTF::unicode::kEthiopicWordspaceCharacter;
using WTF::unicode::kEyeCharacter;
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder.cc b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder.cc
index 37a3de36b68..43372316e2e 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder.cc
@@ -179,16 +179,19 @@ void StringBuilder::CreateBuffer16(unsigned added_size) {
DCHECK(is_8bit_ || !HasBuffer());
Buffer8 buffer8;
unsigned length = length_;
+ wtf_size_t capacity = 0;
if (has_buffer_) {
buffer8 = std::move(buffer8_);
buffer8_.~Buffer8();
+ capacity = buffer8.capacity();
}
new (&buffer16_) Buffer16;
has_buffer_ = true;
- // See createBuffer8's call to reserveInitialCapacity for why we do this.
- buffer16_.ReserveInitialCapacity(
- length_ +
- std::max<unsigned>(added_size, InitialBufferSize() / sizeof(UChar)));
+ capacity = std::max<wtf_size_t>(
+ capacity, length_ + std::max<unsigned>(
+ added_size, InitialBufferSize() / sizeof(UChar)));
+ // See CreateBuffer8's call to ReserveInitialCapacity for why we do this.
+ buffer16_.ReserveInitialCapacity(capacity);
is_8bit_ = false;
length_ = 0;
if (!buffer8.IsEmpty()) {
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
index e3f6b1b31b4..0190e5c9d30 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
@@ -367,4 +367,14 @@ TEST(StringBuilderTest, AppendNumberDoubleUChar) {
EXPECT_EQ(reference, test);
}
+TEST(StringBuilderTest, ReserveCapacity) {
+ StringBuilder builder;
+ builder.ReserveCapacity(100);
+ EXPECT_LE(100u, builder.Capacity());
+
+ builder.Append(0x202B);
+ ASSERT_FALSE(builder.Is8Bit());
+ EXPECT_LE(100u, builder.Capacity());
+}
+
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.cc b/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.cc
index c57c34113ae..e199f32423d 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.cc
@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
+#include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
#include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
#include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
@@ -79,18 +80,17 @@ void StringImpl::DestroyIfNotStatic() const {
delete this;
}
-bool StringImpl::ContainsOnlyASCIIOrEmptySlowCase() const {
- bool contains_only_ascii =
- Is8Bit() ? CharactersAreAllASCII(Characters8(), length())
- : CharactersAreAllASCII(Characters16(), length());
- uint32_t new_flags = kAsciiCheckDone;
- if (contains_only_ascii)
- new_flags |= kContainsOnlyAscii;
+unsigned StringImpl::ComputeASCIIFlags() const {
+ ASCIIStringAttributes ascii_attributes =
+ Is8Bit() ? CharacterAttributes(Characters8(), length())
+ : CharacterAttributes(Characters16(), length());
+ uint32_t new_flags = ASCIIStringAttributesToFlags(ascii_attributes);
const uint32_t previous_flags =
hash_and_flags_.fetch_or(new_flags, std::memory_order_relaxed);
- static constexpr uint32_t mask = kAsciiCheckDone | kContainsOnlyAscii;
+ static constexpr uint32_t mask =
+ kAsciiPropertyCheckDone | kContainsOnlyAscii | kIsLowerAscii;
DCHECK((previous_flags & mask) == 0 || (previous_flags & mask) == new_flags);
- return contains_only_ascii;
+ return new_flags;
}
bool StringImpl::IsSafeToSendToAnotherThread() const {
@@ -259,6 +259,21 @@ scoped_refptr<StringImpl> StringImpl::Create(const LChar* characters,
return string;
}
+scoped_refptr<StringImpl> StringImpl::Create(
+ const LChar* characters,
+ wtf_size_t length,
+ ASCIIStringAttributes ascii_attributes) {
+ scoped_refptr<StringImpl> ret = Create(characters, length);
+ if (length) {
+ // If length is 0 then `ret` is empty_ and should not have its
+ // attributes calculated or changed.
+ uint32_t new_flags = ASCIIStringAttributesToFlags(ascii_attributes);
+ ret->hash_and_flags_.fetch_or(new_flags, std::memory_order_relaxed);
+ }
+
+ return ret;
+}
+
scoped_refptr<StringImpl> StringImpl::Create8BitIfPossible(
const UChar* characters,
wtf_size_t length) {
@@ -1684,15 +1699,14 @@ int CodeUnitCompareIgnoringASCIICase(wtf_size_t l1,
return (l1 > l2) ? 1 : -1;
}
+template <typename CharacterType>
int CodeUnitCompareIgnoringASCIICase(const StringImpl* string1,
- const LChar* string2) {
- wtf_size_t length1 = string1 ? string1->length() : 0;
- wtf_size_t length2 = SafeCast<wtf_size_t>(
- string2 ? strlen(reinterpret_cast<const char*>(string2)) : 0);
-
+ const CharacterType* string2,
+ wtf_size_t length2) {
if (!string1)
return length2 > 0 ? -1 : 0;
+ wtf_size_t length1 = string1->length();
if (!string2)
return length1 > 0 ? 1 : 0;
@@ -1704,4 +1718,21 @@ int CodeUnitCompareIgnoringASCIICase(const StringImpl* string1,
string1->Characters16(), string2);
}
+int CodeUnitCompareIgnoringASCIICase(const StringImpl* string1,
+ const LChar* string2) {
+ return CodeUnitCompareIgnoringASCIICase(
+ string1, string2,
+ string2 ? strlen(reinterpret_cast<const char*>(string2)) : 0);
+}
+
+int CodeUnitCompareIgnoringASCIICase(const StringImpl* string1,
+ const StringImpl* string2) {
+ if (!string2)
+ return string1 && string1->length() > 0 ? 1 : 0;
+ return VisitCharacters(
+ *string2, [string1](const auto* chars, wtf_size_t length) {
+ return CodeUnitCompareIgnoringASCIICase(string1, chars, length);
+ });
+}
+
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.h b/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.h
index 1a8aeba61f9..4f879d6c699 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_impl.h
@@ -95,8 +95,8 @@ class WTF_EXPORT StringImpl {
enum ConstructEmptyStringTag { kConstructEmptyString };
explicit StringImpl(ConstructEmptyStringTag)
: length_(0),
- hash_and_flags_(kAsciiCheckDone | kContainsOnlyAscii | kIs8Bit |
- kIsStatic) {
+ hash_and_flags_(kAsciiPropertyCheckDone | kContainsOnlyAscii |
+ kIsLowerAscii | kIs8Bit | kIsStatic) {
// Ensure that the hash is computed so that AtomicStringHash can call
// existingHash() with impunity. The empty string is special because it
// is never entered into AtomicString's HashKey, but still needs to
@@ -107,7 +107,8 @@ class WTF_EXPORT StringImpl {
enum ConstructEmptyString16BitTag { kConstructEmptyString16Bit };
explicit StringImpl(ConstructEmptyString16BitTag)
: length_(0),
- hash_and_flags_(kAsciiCheckDone | kContainsOnlyAscii | kIsStatic) {
+ hash_and_flags_(kAsciiPropertyCheckDone | kContainsOnlyAscii |
+ kIsLowerAscii | kIsStatic) {
GetHash();
}
@@ -150,6 +151,10 @@ class WTF_EXPORT StringImpl {
static scoped_refptr<StringImpl> Create(const UChar*, wtf_size_t length);
static scoped_refptr<StringImpl> Create(const LChar*, wtf_size_t length);
+ static scoped_refptr<StringImpl> Create(
+ const LChar*,
+ wtf_size_t length,
+ ASCIIStringAttributes ascii_attributes);
static scoped_refptr<StringImpl> Create8BitIfPossible(const UChar*,
wtf_size_t length);
template <wtf_size_t inlineCapacity>
@@ -222,6 +227,8 @@ class WTF_EXPORT StringImpl {
bool ContainsOnlyASCIIOrEmpty() const;
+ bool IsLowerASCII() const;
+
bool IsSafeToSendToAnotherThread() const;
// The high bits of 'hash' are always empty, but we prefer to store our
@@ -457,13 +464,17 @@ class WTF_EXPORT StringImpl {
// (post-unification). Thus these accesses can also be relaxed.
kIsAtomic = 1 << 2,
- // These two bits are set atomically together. They are initially both
+ // These bits are set atomically together. They are initially all
// zero, and like the hash computation below, become non-zero only as part
// of a single atomic bitwise or. Thus concurrent loads will always observe
- // either a state where the ASCII check has not been completed and both
- // bits are zero, or a state where the state is fully populated.
- kAsciiCheckDone = 1 << 3,
+ // either a state where the ASCII property check has not been completed and
+ // all bits are zero, or a state where the state is fully populated.
+ //
+ // The reason kIsLowerAscii is cached but upper ascii is not is that
+ // DOM attributes APIs require a lowercasing check making it fairly hot.
+ kAsciiPropertyCheckDone = 1 << 3,
kContainsOnlyAscii = 1 << 4,
+ kIsLowerAscii = 1 << 5,
// The last 24 bits (past kHashShift) are reserved for the hash.
// These bits are all zero if the hash is uncomputed, and the hash is
@@ -480,7 +491,19 @@ class WTF_EXPORT StringImpl {
constexpr static int kHashShift = (sizeof(unsigned) * 8) - 24;
static inline constexpr uint32_t LengthToAsciiFlags(int length) {
- return length ? 0 : kAsciiCheckDone | kContainsOnlyAscii;
+ return length
+ ? 0
+ : kAsciiPropertyCheckDone | kContainsOnlyAscii | kIsLowerAscii;
+ }
+
+ static inline uint32_t ASCIIStringAttributesToFlags(
+ ASCIIStringAttributes ascii_attributes) {
+ uint32_t flags = kAsciiPropertyCheckDone;
+ if (ascii_attributes.contains_only_ascii)
+ flags |= kContainsOnlyAscii;
+ if (ascii_attributes.is_lower_ascii)
+ flags |= kIsLowerAscii;
+ return flags;
}
void SetHashRaw(unsigned hash_val) const {
@@ -522,7 +545,10 @@ class WTF_EXPORT StringImpl {
NOINLINE wtf_size_t HashSlowCase() const;
void DestroyIfNotStatic() const;
- bool ContainsOnlyASCIIOrEmptySlowCase() const;
+
+ // Calculates the kContainsOnlyAscii and kIsLowerAscii flags. Returns
+ // a bitfield with those 2 values.
+ unsigned ComputeASCIIFlags() const;
#if DCHECK_IS_ON()
std::string AsciiForDebugging() const;
@@ -586,9 +612,16 @@ WTF_EXPORT bool EqualNonNull(const StringImpl* a, const StringImpl* b);
ALWAYS_INLINE bool StringImpl::ContainsOnlyASCIIOrEmpty() const {
uint32_t flags = hash_and_flags_.load(std::memory_order_relaxed);
- if (flags & kAsciiCheckDone)
+ if (flags & kAsciiPropertyCheckDone)
return flags & kContainsOnlyAscii;
- return ContainsOnlyASCIIOrEmptySlowCase();
+ return ComputeASCIIFlags() & kContainsOnlyAscii;
+}
+
+ALWAYS_INLINE bool StringImpl::IsLowerASCII() const {
+ uint32_t flags = hash_and_flags_.load(std::memory_order_relaxed);
+ if (flags & kAsciiPropertyCheckDone)
+ return flags & kIsLowerAscii;
+ return ComputeASCIIFlags() & kIsLowerAscii;
}
template <typename CharType>
@@ -644,6 +677,8 @@ inline bool EqualIgnoringASCIICase(const CharacterTypeA* a,
}
WTF_EXPORT int CodeUnitCompareIgnoringASCIICase(const StringImpl*,
+ const StringImpl*);
+WTF_EXPORT int CodeUnitCompareIgnoringASCIICase(const StringImpl*,
const LChar*);
inline wtf_size_t Find(const LChar* characters,
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_mac.mm b/chromium/third_party/blink/renderer/platform/wtf/text/string_mac.mm
index d1690b69299..eda6594e0de 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_mac.mm
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_mac.mm
@@ -45,7 +45,8 @@ String::String(NSString* str) {
Vector<UChar, 1024> uchar_buffer(size);
CFStringGetCharacters(reinterpret_cast<CFStringRef>(str),
- CFRangeMake(0, size), uchar_buffer.data());
+ CFRangeMake(0, size),
+ reinterpret_cast<UniChar*>(uchar_buffer.data()));
impl_ = StringImpl::Create(uchar_buffer.data(), size);
}
}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
index 0178c7b0c59..5627859efe1 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/string_view.h
@@ -11,6 +11,8 @@
#include "base/memory/scoped_refptr.h"
#endif
#include <cstring>
+#include <type_traits>
+
#include "base/containers/span.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
@@ -126,6 +128,10 @@ class WTF_EXPORT StringView {
StringView(const UChar* chars, unsigned length)
: impl_(StringImpl::empty16_bit_), bytes_(chars), length_(length) {}
StringView(const UChar* chars);
+ // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t`
+ // on all platforms.
+ template <typename UCharT = UChar,
+ typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>>
StringView(const char16_t* chars)
: StringView(reinterpret_cast<const UChar*>(chars)) {}
@@ -146,9 +152,10 @@ class WTF_EXPORT StringView {
bool IsAtomic() const { return SharedImpl() && SharedImpl()->IsAtomic(); }
bool IsLowerASCII() const {
- if (Is8Bit()) {
+ if (StringImpl* impl = SharedImpl())
+ return impl->IsLowerASCII();
+ if (Is8Bit())
return WTF::IsLowerASCII(Characters8(), length());
- }
return WTF::IsLowerASCII(Characters16(), length());
}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc b/chromium/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
index fb8ab0530c5..5d4ea13e753 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
@@ -432,7 +432,7 @@ String TextCodecICU::Decode(const char* bytes,
// ICU decodes it as U+E5E5.
if (!strcmp(encoding_.GetName(), "GBK")) {
if (EqualIgnoringASCIICase(encoding_.GetName(), "gb18030"))
- resultString.Replace(0xE5E5, ideographicSpaceCharacter);
+ resultString.Replace(0xE5E5, kIdeographicSpaceCharacter);
// Make GBK compliant to the encoding spec and align with GB18030
resultString.Replace(0x01F9, 0xE7C8);
// FIXME: Once https://www.w3.org/Bugs/Public/show_bug.cgi?id=28740#c3
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.cc b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
index b3ba2c2d1d5..0305428c243 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
@@ -35,9 +35,11 @@
#include "third_party/blink/renderer/platform/wtf/text/case_map.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
#include "third_party/blink/renderer/platform/wtf/text/utf8.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
namespace WTF {
@@ -592,8 +594,9 @@ String String::FromUTF8(const LChar* string_start, size_t string_length) {
if (!length)
return g_empty_string;
- if (CharactersAreAllASCII(string_start, length))
- return StringImpl::Create(string_start, length);
+ ASCIIStringAttributes attributes = CharacterAttributes(string_start, length);
+ if (attributes.contains_only_ascii)
+ return StringImpl::Create(string_start, length, attributes);
Vector<UChar, 1024> buffer(length);
UChar* buffer_start = buffer.data();
@@ -639,4 +642,9 @@ void String::Show() const {
}
#endif
+void String::WriteIntoTracedValue(perfetto::TracedValue context) const {
+ StringUTF8Adaptor adaptor(*this);
+ std::move(context).WriteString(adaptor.data(), adaptor.size());
+}
+
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.h b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.h
index e7fea2ac15b..b22da08375a 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string.h
@@ -27,6 +27,8 @@
// on systems without case-sensitive file systems.
#include <iosfwd>
+#include <type_traits>
+
#include "base/containers/span.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -35,6 +37,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
#include "third_party/blink/renderer/platform/wtf/wtf_export.h"
#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#ifdef __OBJC__
#include <objc/objc.h>
@@ -80,6 +83,10 @@ class WTF_EXPORT String {
// Construct a string with UTF-16 data, from a null-terminated source.
String(const UChar*);
+ // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t`
+ // on all platforms.
+ template <typename UCharT = UChar,
+ typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>>
String(const char16_t* chars)
: String(reinterpret_cast<const UChar*>(chars)) {}
@@ -532,6 +539,8 @@ class WTF_EXPORT String {
length);
}
+ bool IsLowerASCII() const { return !impl_ || impl_->IsLowerASCII(); }
+
bool ContainsOnlyASCIIOrEmpty() const {
return !impl_ || impl_->ContainsOnlyASCIIOrEmpty();
}
@@ -549,6 +558,8 @@ class WTF_EXPORT String {
void Show() const;
#endif
+ void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
private:
friend struct HashTraits<String>;
@@ -645,6 +656,11 @@ inline bool CodeUnitCompareLessThan(const String& a, const String& b) {
WTF_EXPORT int CodeUnitCompareIgnoringASCIICase(const String&, const char*);
+inline bool CodeUnitCompareIgnoringASCIICaseLessThan(const String& a,
+ const String& b) {
+ return CodeUnitCompareIgnoringASCIICase(a.Impl(), b.Impl()) < 0;
+}
+
template <bool isSpecialCharacter(UChar)>
inline bool String::IsAllSpecialCharacters() const {
return StringView(*this).IsAllSpecialCharacters<isSpecialCharacter>();
diff --git a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
index 1be1108989c..ff1cbf21e64 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
@@ -346,8 +346,9 @@ TEST(StringTest, FindWithCallback) {
// An instance method.
TestMatcher matcher('t');
+ // Unretained is safe because callback executes synchronously in Find().
auto callback =
- WTF::BindRepeating(&TestMatcher::IsTarget, WTF::Passed(&matcher));
+ WTF::BindRepeating(&TestMatcher::IsTarget, WTF::Unretained(&matcher));
EXPECT_EQ(WTF::kNotFound, test_string1.Find(callback));
EXPECT_EQ(1U, test_string2.Find(callback));
}
diff --git a/chromium/third_party/blink/renderer/platform/wtf/threading.cc b/chromium/third_party/blink/renderer/platform/wtf/threading.cc
index d6636df7991..397ea919a30 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/threading.cc
+++ b/chromium/third_party/blink/renderer/platform/wtf/threading.cc
@@ -12,10 +12,12 @@
namespace WTF {
+#if !defined(OS_ANDROID)
base::PlatformThreadId CurrentThread() {
thread_local base::PlatformThreadId g_id = base::PlatformThread::CurrentId();
return g_id;
}
+#endif // !defined(OS_ANDROID)
// For debugging only -- whether a non-main thread has been created.
diff --git a/chromium/third_party/blink/renderer/platform/wtf/threading.h b/chromium/third_party/blink/renderer/platform/wtf/threading.h
index 0943e791cf5..e103de3ac6f 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/threading.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/threading.h
@@ -43,7 +43,14 @@
namespace WTF {
+#if !defined(OS_ANDROID)
WTF_EXPORT base::PlatformThreadId CurrentThread();
+#else
+// On Android gettid(3) uses a faster TLS model than thread_local.
+inline base::PlatformThreadId CurrentThread() {
+ return base::PlatformThread::CurrentId();
+}
+#endif // !defined(OS_ANDROID)
#if DCHECK_IS_ON()
WTF_EXPORT bool IsBeforeThreadCreated();
diff --git a/chromium/third_party/blink/renderer/platform/wtf/type_traits.h b/chromium/third_party/blink/renderer/platform/wtf/type_traits.h
index b8729c768da..562628a92f0 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/type_traits.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/type_traits.h
@@ -32,7 +32,7 @@
#if BUILDFLAG(USE_V8_OILPAN)
#include "v8/include/cppgc/type-traits.h" // nogncheck
-#else
+#else // !BUILDFLAG(USE_V8_OILPAN)
namespace blink {
template <typename T>
class Member;
@@ -40,7 +40,7 @@ class Visitor;
template <typename T>
class WeakMember;
} // namespace blink
-#endif // BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN)
+#endif // !BUILDFLAG(USE_V8_OILPAN)
namespace WTF {
@@ -123,12 +123,20 @@ template <typename T>
struct IsTraceable : cppgc::internal::IsTraceable<T> {};
template <typename T>
-struct IsGarbageCollectedType : cppgc::internal::IsGarbageCollectedType<T> {};
+struct IsGarbageCollectedType
+ : cppgc::internal::IsGarbageCollectedOrMixinType<T> {};
template <typename T>
struct IsWeak : cppgc::internal::IsWeak<T> {};
template <typename T>
+struct IsMemberType : std::integral_constant<bool, cppgc::IsMemberTypeV<T>> {};
+
+template <typename T>
+struct IsWeakMemberType
+ : std::integral_constant<bool, cppgc::IsWeakMemberTypeV<T>> {};
+
+template <typename T>
struct IsMemberOrWeakMemberType
: std::integral_constant<bool,
cppgc::IsMemberTypeV<T> ||
@@ -167,11 +175,6 @@ struct IsTraceable<T,
"Trace methods should be marked as const.");
};
-template <typename T, typename U>
-struct IsTraceable<std::pair<T, U>>
- : std::integral_constant<bool,
- IsTraceable<T>::value || IsTraceable<U>::value> {};
-
template <typename T>
class IsGarbageCollectedTypeInternal {
typedef char YesType;
@@ -220,14 +223,30 @@ template <typename T>
struct IsWeak : std::false_type {};
template <typename T>
-struct IsMemberOrWeakMemberType
+struct IsMemberType : std::integral_constant<
+ bool,
+ WTF::IsSubclassOfTemplate<T, blink::Member>::value> {
+};
+
+template <typename T>
+struct IsWeakMemberType
: std::integral_constant<
bool,
- WTF::IsSubclassOfTemplate<T, blink::Member>::value ||
- WTF::IsSubclassOfTemplate<T, blink::WeakMember>::value> {};
+ WTF::IsSubclassOfTemplate<T, blink::WeakMember>::value> {};
+
+template <typename T>
+struct IsMemberOrWeakMemberType
+ : std::integral_constant<bool,
+ IsMemberType<T>::value ||
+ IsWeakMemberType<T>::value> {};
#endif // !USE_V8_OILPAN
+template <typename T, typename U>
+struct IsTraceable<std::pair<T, U>>
+ : std::integral_constant<bool,
+ IsTraceable<T>::value || IsTraceable<U>::value> {};
+
// Convenience template wrapping the IsTraceableInCollection template in
// Collection Traits. It helps make the code more readable.
template <typename Traits>
diff --git a/chromium/third_party/blink/renderer/platform/wtf/vector.h b/chromium/third_party/blink/renderer/platform/wtf/vector.h
index 6b6eb4215cb..4f18eacecce 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/vector.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/vector.h
@@ -2178,11 +2178,13 @@ Vector<T, inlineCapacity, Allocator>::Trace(VisitorDispatcher visitor) const {
// Bail out for concurrent marking.
if (!VectorTraits<T>::kCanTraceConcurrently) {
- if (visitor->DeferredTraceIfConcurrent(
- {buffer, internal::DeferredTraceImpl<Allocator, VisitorDispatcher,
- T, inlineCapacity>},
- inlineCapacity * sizeof(T)))
+ if (Allocator::DeferTraceToMutatorThreadIfConcurrent(
+ visitor, buffer,
+ internal::DeferredTraceImpl<Allocator, VisitorDispatcher, T,
+ inlineCapacity>,
+ inlineCapacity * sizeof(T))) {
return;
+ }
}
// Inline buffer requires tracing immediately.